muffin-5.2.1/0000775000175000017500000000000014211404421013134 5ustar jpeisachjpeisachmuffin-5.2.1/Makefile.am0000664000175000017500000000040314211404421015165 0ustar jpeisachjpeisach SUBDIRS=cogl clutter src src/compositor/plugins po doc data EXTRA_DIST = HACKING MAINTAINERS rationales.txt DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache muffin-5.2.1/NEWS0000664000175000017500000040240514211404421013640 0ustar jpeisachjpeisach3.2.1 ===== * Allow keyboard window switching (alt-Tab) during drag-and-drop [Matthias, #660457] * Don't add invisible resize borders to fullscreen windows [Jasper, Owen; #659854] * Fix crash when toplevel windows were set to unexpected window types [Owen; #599988] * Correct problems with windows moving when restarting or switching window managers [Jasper; #660848] * Fix interaction of tiled windows with multiple monitors [Rui; #642580, #657519] * Make meta_display_unmanage_screen() public [Jasper; #660848] * Fix problem with turning off window decorations on the fly [Rui; #660773] * Fix spurious assertion failures with themes such as Nodoka [Sandro; #661286] * Misc bug fixes [Adel, Jasper, Rui; #660464, #660854, #662053] Contributors: Matthias Clasen, Sandro Mani, Rui Matos, Jasper St. Pierre, Owen Taylor Translations: Tommi Vainikainen [fi], Miroslav Nikolić [sr, sr@latin], Muhammet Kara [tr] 3.2.0 ===== * Fix _NET_WM_FRAME_EXTENTS not to include invisible borders [Jasper; #659848] * Fix application-specified window placement (-geometry) for invisible borders [Jasper; #659848] Contributors: Jasper St. Pierre Translations: Nilamdyuti Goswami [as], Carles Ferrando [ca@valencia], Petr Kovar [cz], Mario Blättermann [de], Inaki Larranaga [eu], Gabor Kelemen [hu], Takayoshi Okano [ja], Changwoo Ryu [ko], Djavan Fagundes [pt_BR] 3.1.92 ====== * Fix bug with unredirecting full-screen windows on multi-monitor - notably affected gnome-screensaver [Adel; #657869] * Disable top resizing of attached dialogs [Jasper; #657795] * Code cleanup [Jasper, Rui] * Misc bug fixes [Adel, Florian, Jasper, Rui; #658069, #659266, #659523, #659477] Contributors: Adel Gadllah, Rui Matos, Florian Müllner, Jasper St. Pierre Translations: Joan Duran [ca], Joe Hansen [dk], Jiro Matsuzawa [ja], Daniel Korostil [uk] 3.1.91.1 ======== * Fix problem where certain application updates would get lost [#657071, Owen] * Fix a problem where after resuming from the screensaver, things got slow [#658228, Jasper, Adel] * When a monitor is plugged or unplugged, keep existing windows on their current monitor [#645408, Alex] * Remove 'Muffin' title from alerts such as "The widow '%s' is not responding" [Matthias] * Remove pointless warning: Received a _NET_WM_MOVERESIZE message for %s; these messages lack timestamps and therefore suck. [Rui] * Misc bug fixes [Jasper] * Build fixes [Javier] Contributors: Matthias Clasen, Adel Gadllah, Javier Jardón, Alex Larsson, Rui Matos, Jasper St. Pierre, Owen Taylor Translations: Ihar Hrachyshka [be], Bruce Cowan [en_FB], Daniel Mustieles [es], Claude Paroz [fr], Andika Triwidada [id], Luca Ferretti [it], Rudolfs Mazurs [lt], Piotr Drąg [pl], Duarte Loreto [pt], Matej Urbančič [sl], Tirumurti Vasudevan [ta], Chao-Hsiung Liao [zh_KH, TW] 3.1.90.1 ======== * Fix crash when no windows are open [Adel; #657692] * Fix annotations for new strictness in gobject-introspection [Jasper, Owen] * Fix some errors with rounded frame drawing [Jasper; #657661] Contributors: Adel Gadllah, Jasper St. Pierre, Owen Taylor 3.1.90 ====== * Extend the draggable portion of window borders outside the visible frame for easy resizing with thin borders. (New draggable_border_width GConf key controls the total width of visible and invisible borders.) [Jasper; #644930] * Draw rounded window corners with antialising [Jasper; #628195] * Unredirect override-redirect fullscreen windows, such as full-screen 3D games to avoid any performance impact [Adel; #597014] * Add :resizable and :above properties to MetaWindow. [Tim; #653858] * Add MUFFIN_DISABLE_FALLBACK_COLOR environment variable to allow visualizing places where a color is missing for gtk:custom() colors [Florian; #656112] * Don't attach modal dialogs to special windows like the desktop; add meta_window_is_attached_dialog() [Dan, #646761] * Make MetaBackgroundActor public, allow creating multiple instances (sharing a common texture), and add a :dim-factor property [Rui, Owen; #656433] * Fix attached dialogs to not be resizable from the top and to be position correctly [Jasper; #656619] * Misc bug fixes [Jasper, Rui; #656335, #657583] Contributors: Tim Cuthbertson, Adel Gadllah, Rui Matos, Florian Müllner, Jasper St. Pierre, Owen Taylor, Dan Winship Translations: Alexander Shopov [bg], Jorge González [es], Fran Dieguez [gl], Yaron Shahrabani [he], Takeshi Aihana [ja], Aurimas Černius [lt], Kjartan Maraas [nb], A S Alam [pa], Yuri Kozlov [ru], Daniel Nylander [se], Theppitak Karoonboonyanan [th], Abduxukur Abdurixit [ug], Aron Xu [zh_CN] 3.1.4 ===== * Use better, much more subtle shadow definitions [Jakub; #649374] * Add the ability to use named GTK+ colors in theme files as gtk:custom(name,fallback) [Florian; #648709] * Port from GdkColor to GdkRGBA and from GtkStyle to GtkStyleContext [Florian; #650586] * Try to fix window bindings using the Super key [Owen; #624869] * Update to using more modern Cogl and Clutter APIs [Adel, Emmanuele, Neil; #654551 #654729 #654730 #655064] * Fix for srcdir != builddir builds [Thierry; #624910] * Make handling of focus appearance for attached dialogs more robust [Dan; #647712] * Misc bug fixes [Dan, Florian, Jasper, Owen, Rui; #642957 #649374 #650661 #654489 #654539] Contributors: Emmanuele Bassi, Adel Gadllah, Rui Matos, Florian Müllner, Neil Roberts, Jasper St. Pierre, Jakub Steiner, Owen Taylor Translations: Ihar Hrachyshka [be], Jorge González, Daniel Mustieles [es], Fran Dieguez [gl], Yaron Shahrabani [he], Takeshi Aihana [ja], Kjartan Maraas [nb], Rudolfs Mazurs [lv], Matej Urbančič [sl], Abduxukur Abdurixit [ug], Nguyễn Thái Ngọc Duy [vi] 3.1.3.1 ======= * Back API version down to "3.0" - the change to Meta-3.1.gir was unintentional [Owen] Translations: Yaron Shahrabani [he], Kjartan Maraas [nb], Muhammet Kara [tr] 3.1.3 ===== * Support dark window theme variants for windows with a dark widget theme; this is selected by the _GTK_THEME_VARIANT property [Florian, #645355] * Don't draw a shadow under windows with an alpha-channel - this fixes transparency for GNOME Terminal [Owen, Jasper; #635268] * Add a MetaWindow:wm-class property for notification [Jasper; #649315] * Add a MetaWindow:minimized property for notification [Florian] * Fix handing of unusual window shapes that Wine was setting causing some applications to draw wrong [Jasper; #627880] * Improve replacing another compositor and being replaced: release compositor selection in the right order and wait for compositors that get it wrong. [Colin, Owen; #653121] * Remove behavior where left clicking on a window border with the titlebar offscreen gave the window menu [Florian; #652369] * Don't set the global default textdomain, since Muffin is a library as well as an application [Dan; #649202] * Exit with the right (success or failure) exit status [Dan] * Code cleanup [Florian] * Miscellaneous bug fixes [Owen; #649114, #652507] Contributors: Florian Müllner, Jasper St. Pierre, Owen Taylor, Colin Walters, Dan Winship Translations: Ihar Hrachyshka [be], Daniel Mustieles [es], Yaron Shahrabani [he], Carles Ferrando [ca@valencia], Takeshi Aihana [ja], Fran Diéguez [gl], Matej Urbančič [sl], Miroslav Nikolic [sr], Muhammet Kara [tr], Daniel Korostil [uk] 3.0.2.1 ======= * When saving the session, use the "program name" rather than harcoding muffin, fixing session saving for gnome-shell [Matthias] https://bugzilla.gnome.org/show_bug.cgi?id=648828 Contributors: Matthias Clasen 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, 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 Muffin 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 MuffinWindow 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 Muffin; 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 * Muffin namespace prefix is removed, in favor of consistent meta_ namespace prefixing [Owen]. Naming changes: MuffinWindow => MetaWindowActor muffin_get_windows => meta_get_window_actors muffin_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 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] - libmuffin-private is now only installed for GTK+ 3 builds - Theme parts of libmuffin-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 [muffin-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 muffin-message.c when building Muffin for GNOME Shell dependencies 629350 [muffin-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 muffin code for GTK3 rendering-cleanup 630671 prepare muffin for the demise of GtkObject 630843 gtk_window_set_visual was replaced by gtk_widget_set_visua 631147 Adapt to GTK API changes 631175 Muffin 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 muffin 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 MuffinPlugin 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 - MuffinPluginManager 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 _MUFFIN_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 muffin error: dereferencing pointer ‘p’ does break strict-aliasing rules 616050 - alt-tab infrastructure patches 616274 - muffin 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 muffin 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 muffin_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 Muffin to crash 600068 notifications for window urgency hint 601228 rdesktop does not get keypress signals 602349 [PATCH] trivial - fix compilation warning in muffin 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 muffin 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 Muffin 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 MuffinShapedTexture 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] MuffinScreen::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 '' 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,Muffin on the _NET_SUPPORTING_WM_CHECK window so that gnome-keybinding-properties can figure out to show the Metacity keybindings when Muffin 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 MUFFIN_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. - muffin_plugin_begin_modal() and muffin_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 - muffin 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 MUFFIN_DEBUG_XINERAMA override active Xinerama 593407 - Add 'skip-taskbar' accessor to MetaWindow. ----------------------------- Older Metacity News ----------------------------- 2.26.0 ====== Thanks to Luca Ferretti, Matt Kraai, and Neil Jagdish Patel for improvements in this version. - queue frame resize on window undecorate (Neil) - fix description of desktop background (Luca) (#569649) - wrap g_error calls in braces (Matt) Translations Amitakhya Phukan (as), Mikel González (ast), Ihar Hrachyshka (be@latin), Runa Bhattacharjee (bn_IN), David Planella (ca), Petr Kovar (cs), Ask Hjorth Larsen (da), Christian Kirbach (de), Jennie Petoumenou (el), David Lodge (en_GB), Jorge González (es), Mattias Põldaru (et), Iñaki Larrañaga Murgoitio (eu), Ilkka Tuohela (fi), Claude Paroz (fr), Ankit Patel (gu), Mark Krapivner (he), Rajesh Ranjan (hi), Gabor Kelemen (hu), Luca Ferretti (it), Takeshi AIHANA (ja), Changwoo Ryu (ko), Gintautas Miliauskas (lt), Sangeeta Kumari (mai), Sandeep Shedmake (mr), Wouter Bolsterlee (nl), Manoj Kumar Giri (or), Duarte Loreto (pt), Leonardo Ferreira Fontenelle (pt_BR), Adi Roiban (ro), Yuriy Penkin (ru), Daniel Nylander (sv), I. Felix (ta), Krishna Babu K (te), Theppitak Karoonboonyanan (th), Clytie Siddall (vi), Chao-Hsiung Liao (zh_HK), Chao-Hsiung Liao (zh_TW) 2.25.144 ======== Thanks to Matthias Claesen, Matt Kraai, Elijah Newren, Owen Taylor, and Thomas Thurman for improvements in this version. - Optimise window property lookup (Thomas) (#549886) - Fix slip in the above (Matt) - Several memory leaks fixed (Matthias) (#552303, #552973, #552307) - Fix longstanding crasher about colourmaps (Owen) (#568365) - Alt+middle/right buttons can be switched (Thomas) (#437910) - Support _NET_WM_MOVERESIZE_CANCEL (Elijah) - minor fix paving the way for a theme editor (Thomas) Translations David Planella (ca), Jorge González (es), Mattias Põldaru (et), saudat mohammed (ha), Yuval Tanny\n (he), Gabor Kelemen (hu), Onye, Sylvester (ig), Changwoo Ryu (ko), Raivis Dejus (lv), Kjartan Maraas (nb), Daniel Nylander (sv), Fajuyitan, Sunday Ayo (yo), 甘露 (Gan Lu) (zh_CN) 2.25.89 ======= Thanks to Yanko Kaneti, Frederic Peters, Thomas Thurman, and Colin Walters for improvements in this version. - The maximisation key is a toggle. (Thomas) (#343824) - "Unmaximise" is now called "restore". (Thomas) (#343824) - New thread handling call for gconf (Frederic) (#565517) - Add screenshot commands back which had been removed (Yanko) (#565343) - move_to_corner_se keybinding fixed (Thomas) - Windows on other workspaces which attempt to present themselves are marked as needing attention (Colin) (#482354) - End the grab op when the user clicks the titlebar (Thomas) (#401028) Translations Jorge González (es) 2.25.55 ======= Thanks to Erwann Chenede for improvements in this version. - Fix build on Solaris (Erwann) (#564123) Translations Mattias Põldaru (et), Luca Ferretti (it) 2.25.34 ======= Thanks to Matt Kraai for improvements in this version. - Fixes to Thomas's earlier fixes (Matt) (#562939) Translations None 2.25.21 ======= Thanks to Thomas Thurman for improvements in this version. - Fixes to allow building without compositor again (Thomas) - Fixes for -Wall problems (Thomas) - Various tool updates (Thomas) Translations: none 2.25.13 ======= Thanks to Thomas Thurman for improvements in this version. - Add casts to fix failure to build from source on 64bit hosts (Thomas) (#562106) - Added script to produce annoucements (Thomas) Translations Jorge González (es) 2.25.8 ====== Thanks to Brian Cameron, Maxim Ermilov, Daniel Macks, Elijah Newren, Frederic Peters, Thomas Thurman, David Trowbridge, and Olav Vitters for improvements in this version. - Reorder compiler flags (Daniel) (#562033) - Fix compositor switch (Daniel) (#560990) - Remove spurious warnings about operations on window "none" (Thomas) - Fix _POSIX_C_SOURCE which was breaking OS X builds (Thomas) (#561962) - -Werror -Wall and -ansi are now standard compile flags (Thomas) - Merge screen and window keybindings files; fix minor alt-tab bug in the process (Thomas) (#528337) - Support _NET_WM_FULLSCREEN_MONITORS (David) - Remove some deprecated calls (Thomas) (#560445) - Clean up #includes (Maxim) (#560449) - Update description of raise_on_click (Elijah) - First dialogue delegated to zenity (Thomas) - fix theme-parser typo (Olav) - double-quote variable names in messages (Thomas) (#558309) - fix accidental renaming of run_command_terminal (Thomas) (#557943) - some null checks; problems exposed by new GDM (Brian) (#558058) - ignore mouse button modifier if it's missing (Thomas) (Launchpad 258054, Launchpad 266929) - fix docbook markup (Frederic) Translations Astur (ast), Jorge González (es), Thomas Thurman (la), Leonardo Ferreira Fontenelle (pt_BR), Daniel Nylander (sv) 2.25.5 ====== Thanks to Thomas Thurman for improvements in this version. - Allow third-party apps to decide whether a window appears on all workspaces (Thomas) (#557536) - Fixed keybindings script (again) (Thomas) Translations David Planella (ca), Robert Millan (ca@valencia) 2.25.3 ====== Brown paper bag release which fixes numerous build problems from last night's release of 2.25.2. Apologies. Thanks to Murray Cumming, Thomas Thurman, and Götz Waschk for improvements in this version. - Fix distcheck (Thomas) (#557356) - add libm reference (Götz) (#557357) - fix docbook tags (Murray) (#557337) Translations Yavor Doganov (bg), David Planella (ca), Robert Millan (ca@valencia), Kenneth Nielsen (da), Hendrik Richter (de), Ivar Smolin (et), Claude Paroz (fr), Seán de Búrca (ga), Launchpad Translations Administrators (hr), Gabor Kelemen (hu), Thomas Thurman (la), Žygimantas Beručka (lt), Kjartan Maraas (nb), Duarte Loreto (pt), Djavan Fagundes (pt_BR), Mugurel Tudor (ro), Pavol Šimo (sk), Laurent Dhima (sq), Горан Ракић (sr), Theppitak Karoonboonyanan (th), Funda Wang (zh_CN) 2.25.2 ====== Thanks to Joe Marcus Clarke, Murray Cumming, Tomas Frydrych, William Lachance, Matthew Martin, Christian Persch, Thomas Thurman, and Vincent Untz for improvements in this version. - Add handler for SIGTERM (Joe) (#553980) - Minimised windows are necessarily obscured (Matthew) (#528927) - Build fixes with the above (Christian, Tomas, Thomas) (#557335) (#557201) (#469361) - Changed keybindings to be in a single place (Thomas) (#469361) - Add new document about themes (Murray) - Remove obsolete support for fallback icons (Thomas) - Pass modified mouse events to panels (William) (#554428) - Change where desktop files should go (Vincent) (#549479) Translations Yavor Doganov (bg), David Planella (ca), Kenneth Nielsen (da), Hendrik Richter (de), Ivar Smolin (et), Claude Paroz (fr), Seán de Búrca (ga), Launchpad Translations Administrators (hr), Gabor Kelemen (hu), Thomas Thurman (la), Žygimantas Beručka (lt), Kjartan Maraas (nb), Duarte Loreto (pt), Djavan Fagundes (pt_BR), Mugurel Tudor (ro), Pavol Šimo (sk), Laurent Dhima (sq), Горан Ракић (sr), Theppitak Karoonboonyanan (th), Funda Wang (zh_CN) 2.25.1 ====== Thanks to Thomas Thurman for improvements in this version. - Fix small memory leak, found by Matthias Clasen (Thomas) (#549952) - Added move_to_center keybinding suggested by Khanh-Dang Nguyen Thu Lam (Thomas) (#549979) - Compositor can be turned on and off from the command line (#545323) (Thomas) Translations Khaled Hosny (ar), Petr Kovar (cs), Iñaki Larrañaga Murgoitio (eu), Ilkka Tuohela (fi), Žygimantas Beručka (lt), Duarte Loreto (pt), Djavan Fagundes (pt_BR), Laurent Dhima (sq) 2.25.0 ====== Thanks to Patrick Niklaus, Ted Percival, Eric Piel, Akira TAGOH, and Thomas Thurman for improvements in this version. - Fix memory allocation problem in struts (Eric) (probably #468075) - Ensure windows which start maximised know where to jump back to, so they don't warp to other screens (Ted) (#504692) - Added header comments to some files (Thomas) - Icons for windows which are uncooperative enough not to provide an icon are taken from the theme, not built in (Patrick) (#524343) - Added manual page for metacity-message (Akira, from Debian downstream) Translations Khaled Hosny (ar), Petr Kovar (cs), Ilkka Tuohela (fi), Duarte Loreto (pt), Djavan Fagundes (pt_BR) 2.23.89 ======= Thanks to Thomas Thurman for improvements in this version. - Added DOAP file. (Thomas) Translations Khaled Hosny (ar), Luca Ferretti (it), Takeshi AIHANA (ja), Wouter Bolsterlee (nl), Vladimir Melo (pt_BR), Daniel Nylander (sv) 2.23.55 ======= Thanks to Elijah Newren and Thomas Thurman for improvements in this version. Contrary to rumour, this release does not add tabbing to everything. - Display theme name in title bar of theme viewer (Thomas) (#430198) - Allow toggling of non-compositor effects (Thomas) (#92867) - Add some extra null checks (Thomas) (#422242) - Check for double-freeing at the time of workspace freeing (Elijah) (#361804) - Don't generate log messages unless we're logging (Thomas) - Two windows which don't belong to any application can't be considered to belong to the same application (Thomas) - Various tidyings (Thomas) Translations Yavor Doganov (bg), Gabor Kelemen (hu), Kjartan Maraas (nb), Matej Urbančič (sl), Daniel Nylander (sv), Theppitak Karoonboonyanan (th) 2.23.34 ======= Thanks to Thomas Thurman for improvements in this version. - Commenting and tidying (Thomas) - Fix possible compositor crash (Thomas) (#530702) Translations Khaled Hosny (ar), Yavor Doganov (bg), Jorge González (es), Kjartan Maraas (nb), Yannig Marchegay (Kokoyaya) (oc), Theppitak Karoonboonyanan (th), Clytie Siddall (vi) 2.23.34 ======= Thanks to Thomas Thurman for improvements in this version. - Commenting and tidying (Thomas) - Fix possible compositor crash (Thomas) (#530702) Translations Khaled Hosny (ar), Yavor Doganov (bg), Jorge González (es), Kjartan Maraas (nb), Yannig Marchegay (Kokoyaya) (oc), Theppitak Karoonboonyanan (th), Clytie Siddall (vi) 2.23.34 ======= Thanks to Thomas Thurman for improvements in this version. - Various commenting (Thomas) - Ensure you can turn off compositor with "configure" (Thomas) - Ensure you can turn off gconf with "configure" (Thomas) (#530870) Translations Clytie Siddall (vi) 2.23.21 ======= Thanks to Robert Escriva, Iain Holmes, Matt Krai, Thomas Thurman, and Chris Wang for improvements in this version. - Add shadow ability for menus and tooltips (Iain) (#517442) (#517524) - Fix possible crashes in compositor (Iain) (#534569) (#528787) - Major reorganisation of compositor code (Iain) - Initial version of XRender backend for the compositor (Iain) - New basic public API for compositor (Iain) - Window decoration updates colour when GTK theme changes (Robert) (#511826) - Minor code cleanup for pedantic compilers (Thomas) - Further code cleanup for pedantic compilers (Matt) (#526049) - The atom list appears only once in the code (Thomas) (#530843) - Don't attempt to read attributes of invalid windows (Chris) (#530485) Translations Khaled Hosny (ar), Gabor Kelemen (hu), Kjartan Maraas (nb), Tino Meinen (nl), Theppitak Karoonboonyanan (th) 2.23.13 ======= Thanks to Erwann Chenede and Carlos Garnacho for improvements in this version. - Re-enable cascading (Erwann) (#529925) - Propagate opacity to frame windows (spec compliance!) (Carlos) Translations - None this time! 2.23.8 ====== Thanks to Lucas Rocha, Iain Holmes, and Jens Granseuer for improvements in this version. * No need to symlink to .desktop files (Lucas) * Fixes to compositor's dealings with overlay windows (Iain) * C89 fixes (Jens) Translators: Khaled Hosny (ar), Amitakhya Phukan (as), Ihar Hrachyshka (be@latin), Petr Kovar (cs), Rhys Jones (cy), Kenneth Nielsen (da), Andre Klapper (de), Jorge González (es), Iñaki Larrañaga Murgoitio (eu), Ilkka Tuohela (fi), Claude Paroz (fr), Seán de Búrca (ga), Ignacio Casal Quinteiro (gl), Yuval Tanny (he), Gabor Kelemen (hu), Luca Ferretti (it), Takeshi AIHANA (ja), Shankar Prasad (kn), Changwoo Ryu (ko), Arangel Angov (mk), sandeep shedmake (mr), Kjartan Maraas (nb), Nabin Gautam (ne), Wouter Bolsterlee (nl), Eskild Hustvedt (nn), Yannig Marchegay (Kokoyaya) (oc), Tomasz Dominikowski (pl), Duarte Loreto (pt), Vasiliy Faronov (ru), Daniel Nylander (sv), Theppitak Karoonboonyanan (th), Baris Cicek (tr), Maxim Dziumanenko (uk), Clytie Siddall (vi), Woodman Tuen (zh_HK), Woodman Tuen (zh_TW) 2.23.5 ====== Thanks to Lucas Rocha, Owen Taylor, and Thomas Thurman for improvements in this version. - Updates of useless preferences don't crash (Thomas) (#526016) - Compliance with new gnome-session (Lucas) (#525051) - Preview widget doesn't crash on broken themes (Thomas) (Launchpad 199402) - Initially iconic windows don't unminimise (Owen) (#491090) - Move ~/.metacity to ~/.config/metacity (Thomas) (#518596) - Metacity doesn't stay around when replaced (Thomas) - Extra check for null return in a function (Thomas) - Displays are singletons, simplifying code (Thomas) (#499301) Translations Jorge González (es), Eskild Hustvedt (nn), Baris Cicek (tr), Clytie Siddall (vi) 2.23.3 ====== Thanks to Marco Pesenti Gritti, Iain Holmes, Josh Lee, Thomas Thurman, and Matthew Wilson for improvements in this version. - Workspaces whose name is the same as the standard name, plus some string, are not cut off. (Thomas) (#453678) - Improve compositor performance (Iain) (#522166) - Draw wallpaper correctly when we start up with compositor (Iain) (#522599) - Several other smaller compositor fixes (Iain) - Don't draw shadows on shaped windows unless they have frames (Iain) (#505333) - Newly-created keep-above windows get focus (Marco) (#519188) - Allow moving workspace when dragging with modifier key (Matthew) (#474195) Translations Kenneth Nielsen (da), Gabor Kelemen (hu), Vasiliy Faronov (ru), Daniel Nylander (sv), Maxim Dziumanenko (uk), Woodman Tuen (zh_HK) 2.23.2 ====== Removed some debug statements introduced in 2.23.1. Brown paper bag release. 2.23.1 ====== Thanks to Cosimo Cecchi, Jens Granseuer, Jim Huang, Andrea Del Signore, and Thomas Thurman for improvements in this version. (Cosimo's patch was very similar to another received from Jason Ribero.) - Allow horizontal and vertical maximisation using the mouse (Cosimo/Jason) (#358674) - Allow "spacer" as a value for buttons, for blank space (Andrea) (#509165) - Remove unused code (Jim) - refactor preferences handling (Thomas) - make sure we're valid C89 (Jens) (#518917) - some messing with tool scripts (Thomas) Translations Jorge González (es), Claude Paroz (fr), Woodman Tuen (zh_HK), Woodman Tuen (zh_TW) 2.23.0 ====== Thanks to Matthias Clasen, Mikkel Kamstrup Erlandsen, Jim Huang, Thomas Thurman, and Thomas Wood for improvements in this version. - the preview widget can draw shaped windows properly! (Thomas W, #460018) - refactored handling of boolean and enumerated gconf preferences; refactoring of string and integer preferences will follow shortly (Thomas T) - Applications asking to move and resize windows at the same time have both their requests granted (Mikkel) (#448183) - Windows marked "skip taskbar" don't appear in the ctrl-alt-tab list (Matthias) (#106249) - fix session management detection (Thomas T) (#328210) - when resizing with the keyboard, the cursor stays on a window edge if you escape, whichever direction you were going (Thomas T) (#436257) - fix major breakage when gconf was turned off in configure (Jim) (#515019) - fix major breakage when verbose was turned off in configure (Jim) (#515152) - fix name of verbose option in help (Thomas T) - various bits of messing around with release scripts (Thomas T) Translations Ihar Hrachyshka (be@latin), Ilkka Tuohela (fi), Ignacio Casal Quinteiro (gl), Shankar Prasad (kn), Changwoo Ryu (ko), Nabin Gautam (ne), Wouter Bolsterlee (nl) 2.21.13 ======= Thanks to Michael Meeks and Thomas Thurman for improvements in this version. - Only use compositor version if we have a compositor (Thomas) (#514453) - Remove workaround for a problem in an ancient GTK version (Thomas) (#513737) - Compositor efficiency fixes (Michael) - Various tools added (Thomas) Translations Amitakhya Phukan (as), Rhys Jones (cy), Andre Klapper (de), Takeshi AIHANA (ja), Arangel Angov (mk), Tomasz Dominikowski (pl), Duarte Loreto (pt) 2.21.8 ====== Thanks to Paolo Borelli, Iain Holmes, Havoc Pennington, Christian Persch, Thomas Thurman, and Alex R.M. Turner for improvements in this version. - Windows on other workspaces which need attention appear in the alt-tab list too (Alex) (#333548) - Remove deprecated function call (Christian) (#512561) - New release script (Thomas) - Made a start at improving the general number of comments (Thomas) - Updated copyright year to 2008, and some other tiny fixes (Thomas) - Don't do anything unusual when the compositor frees a window (Iain) - Mapping windows doesn't mark them as damaged (Iain) - Compositor uses the overlay window and not the root window (Iain) - Fixed several list leaks (Paolo) - Fixed warnings about printf formats (Havoc) - Move source files into subdirectories of the src directory (Havoc) Translations Khaled Hosny (ar), Ihar Hrachyshka (be@latin), Petr Kovar (cs), Andre Klapper (de), Jorge González (es), Iñaki Larrañaga Murgoitio (eu), Seán de Búrca (ga), Yuval Tanny (he), Luca Ferretti (it), Takeshi AIHANA (ja), Arangel Angov (mk), sandeep shedmake (mr), Kjartan Maraas (nb), Yannig Marchegay (Kokoyaya) (oc), Daniel Nylander (sv), Theppitak Karoonboonyanan (th), Baris Cicek (tr), Clytie Siddall (vi) 2.21.5 ====== Thanks to Iain Holmes and Thomas Thurman for improvements in this version. This contains the new compositor; downstream maintainers should note that its GConf key is initially turned off in src/metacity.schemas.in and consider whether to turn it on by default in their packages. - merge compositor branch! (Iain) (499081) - print "Subversion" and not "CVS" when building (Thomas) Translations Jorge González (es), Kjartan Maraas (nb), Daniel Nylander (sv) 2.21.3 ====== Thanks to Matthias Clasen, Martin Meyer, Kjartan Maraas, Thomas Thurman, and Lucas Rocha for improvements in this version. - remove dead code (pointed out by Kjartan) (501365) - rewrote long key binding description for the sake of the translators (Thomas) (474889) - check for null before adding menu (Matthias) (496054) - let keys which end a grab also begin a grab (Thomas) (112560) - check the right variable in theme sanity check (Martin) (501362) - get session ID from environment if it's not passed in on the command line (Lucas) (498033) Translations Ihar Hrachyshka (be@latin), Petr Kovar (cs), Jorge González (es), Ignacio Casal Quinteiro (gl), Rodrigo Flores (pt_BR), Pavol Šimo (sk), Matej Urbančič (sl) 2.21.2 ====== Thanks to Benjamin Gramlich, Thomas Thurman, and Peter Bloomfield for improvements in this release. - Theme parser is compliant to XDG Base Directory Specification in searching for theme files. (Benjamin) (#480026) - Some source files which didn't get used were removed (Thomas) (#496947) - Fullscreen and maximise windows don't try to save their position (Peter) (#461927) Translations Matej Urbančič (sl) 2.21.1 ====== Thanks to Elijah Newren, Alex R.M. Turner, Peter Bloomfield, Iain Holmes, Jans Granseuer, Federico Mena Quintero and Thomas Thurman for improvements in this release. - Add --sync option, like all other GTK apps (Iain) - Don't save window's position if it's maximised (Peter) (#461927) - Memory leak fix in preview (Jans) (#469682) - Truncate tab popup string correctly, and refactor function (Alex) - Windows which pop up under always-on-top windows don't get the focus, but do get the "needs attention" hint (Thomas) (#486445) - Fix error in function call which caused focus problems (Federico) (partial fix of #488468) Translations Djihed Afifi (ar), Metin Amiroff (az), Alexander Shopov (bg), Jordi Mallach (ca), David Lodge (en_GB), Jorge González (es), Iñaki Larrañaga Murgoitio (eu), Vincent Untz (fr), Alastair McKinstry (ga), Ankit Patel (gu), Rajesh Ranjan (hi), auto (hr), Changwoo Ryu (ko), Raivis Dejus (lv), Wouter Bolsterlee (nl), Gora Mohanty (or), ASB (pa), wadim dziedzic (pl), Duarte Loreto (pt), Og Maciel (pt_BR), Peter Tuhársky (sk), Matej Urbančič (sl), Daniel Nylander (sv), Maxim Dziumanenko (uk), Funda Wang (zh_CN) 2.20.0 ====== Thanks to Alexey Rusakov for the fix in this release. - prevent a crash on logout with metacity subsequently not being restored in future sessions (Alexey) [#433253] Translations Khaled Hosny (ar), Ihar Hrachyshka (be@latin), Ask Hjorth Larsen (da), Adam Weinberger (en_CA), Iñaki Larrañaga Murgoitio (eu), Ilkka Tuohela (fi), Vincent Untz (fr), Ankit Patel (gu), Gabor Kelemen (hu), Luca Ferretti (it), Takeshi AIHANA (ja), Žygimantas Beručka (lt), Jovan Naumovski (mk), Ani Peter (ml), Og Maciel (pt_BR), Duarte Loreto (pt), Mugurel Tudor (ro), Nickolay V. Shmyrev (ru), Peter Tuhársky (sk), Горан Ракић (sr), Daniel Nylander (sv), Dr.T.Vasudevan (ta), Maxim Dziumanenko (uk), Clytie Siddall (vi) 2.19.55 ======= Thanks to Frederic Crozat, Matthias Clasen, and Thomas Thurman for improvements in this release. - Noninteger auto-raise delay is not assumed to be zero (Thomas) (#377491) - Fix mangled window title in "Force Quit" (Frederic) (#462734) - "Close" can appear at any point in the window menu, and now appears at the bottom (Thomas) (#104026) - Windows which are always on top have "stick" insensitive (Thomas) (#460997) - All bitfields in window structure are together for optimisation (Thomas) (#450271) - Use the correct directory when installing keybindings (Matthias) (#454055) Translations Alexander Shopov (bg), Jorge González (es), Iñaki Larrañaga Murgoitio (eu), Ilkka Tuohela (fi), Theppitak Karoonboonyanan (th) 2.19.34 ======= Thanks to Rob Bradford, Cosimo Cecchi, Yair Hershkovitz and Thomas Thurman for improvements in this release. - Fix a bug where the window can be focused without being raised if the maximize is aborted. (Rob) [#459027] - Unset fullscreen is an allowed action where relevant. (Cosimo) [#449427] - Reverse window buttons and align them to the left for RTL locales. (Yair) [#92212] - Put all bitfields in window data together to help with optimisation. (Thomas) [#450271] Translations Jorge Gonzalez (es), Ilkka Tyohela (fi), Gabor Kelemen (hu), Takeshi AIHANA (ja), Kjartan Maraas (nb), Vincent van Adrighem (nl), Daniel Nylander (sv), Theppitak Karoonbooyana (th), Nguyễn Thái Ngọc Duy (vi) 2.19.21 ======= Thanks to Damien Carbery and Thomas Thurman for improvements in this release. - Fixed build on Solaris (Damien) [#397296, #446535] - Only activate windows which change their startup ID if the new ID differs from the old. (This fixes the bug where KDE apps gained the attention hint when switching workspaces.) (Thomas) [#400167] - Open new windows on the current xinerama. (Thomas) [#145503]. Translations Tshewang Norbu (dz), Jorge González (es), Funda Wang (zh_CN) 2.19.13 ======= Thanks to Elijah Newren and Thomas Thurman for improvements in this release. - Updated the description of raise_on_click (Elijah) [#445447, #389923] - Refactor queueing code in window.c (Thomas) [#376760] - Added switch_group to the keybindings file (Thomas) [#444879] - New window information accessor function (Thomas) [#377495] 2.19.8 ====== Thanks to Linus Torvalds, Yair Hershkovitz and Thomas Thurman for improvements in this release. - Lots of fixups for various alignments in RTL locales (Yair) [#387893] - Add code to configure what happens on right or middle click of titlebar (Linus) [#408904] - Fix layout for titlebars with mixed LTR/RTL scripts (Thomas) [#433400] - Fix window menu layout for RTL scripts (Thomas) [#433400] Translations Khaled Hosny (ar), Ihar Hrachyshka (be@latin), Jovan Naumovski (mk), Theppitak Karoonboonyanan (th) [ Apologies to these translators who didn't get credited in the version of 2.19.8 that shipped. ] 2.19.5 ====== - Prevent metacity from "forgetting" which machine a window is on (Elijah) [#418552] - Prevent nasty flickering an placement problem introduced in metacity 2.19.2 (Elijah) [fix side-effect of change in #426519] - Fix some uninitialized memory usage errors (Elijah) [#427385] Translations David Lodge (en_GB), Jorge González (es), Ignacio Casal Quinteiro (gl), Daniel Nylander (sv) 2.19.3 ====== Thanks to Magnus Therning, Elijah Newren, Thomas Thurman, and Bruno Boaventura for improvements in this release. - Add support for _NET_MOVERESIZE_WINDOW (Magnus, Elijah) [#344521] - EWMH compliance: set _NET_WM_ALLOWED_ACTIONS so that pagers know which actions we support (Elijah) [#115247] - Fix crash with apps trying to open an insanely huge window (Thomas) [#399529] - Fix temporary hang/pause with libXt by making sure apps get a ConfigureNotify on unmap (Elijah) [#399552] - do not auto-maximize windows larger than the workarea in only a single direction (Elijah) [#419810] - Don't show the current workspace as a possible workspace to switch to (Bruno) [#426791] - Preserve stacking order across restarts (Elijah) Translations Khaled Hosny (ar), Kjartan Maraas (nb) 2.19.2 ====== Thanks to Bastien Nocera, Thomas Thurman, and Elijah Newren for improvements in this release. - Add new control-center key bindings definitions (Bastien) [#420145] - Prevent metacity from crashing when trying to use invalid themes (Thomas) [#423855] - Fix invalid free causing crash on metacity close introduced in 2.19.1 (Elijah) [#427385] - Add special keybinding just for debugging spew marks, unbound and not even listed in schemas (Elijah) - Fix move/resize events in relation to combinations of ConfigureRequest and WM_NORMAL_HINTS change notifications (Elijah) [#426519] - Remove what we believe to be an ancient attempt at working around sloppy/mouse focus bugs that we believe have since been correctly fixed. May fix some ugly race conditions. May also cause nasty bugs in sloppy/mouse focus modes. Only one way to find out... (Elijah) [#304430] Translations Raivis Dejus (lv) 2.19.1 ====== Thanks to Jaap Haitsma, Linus Torvalds, Charlie Brej, Kjartan Maraas, Arthur Taylor, Elijah Newren, Josselin Mouette, Havoc Pennington, Benjamin Berg, and Carlo Wood for improvements in this release. - new icon for the force-quit dialog (Jaap) [#396655] - add configureable mouse click action abilities, and clean up lots of related code (Linus) [#408899, #408902, others] - add schemeas for middle and right click titlebar actions (Charlie) [#408903] - remove pango/pangox.h include since it's not needed and not installed anymore (Kjartan) - adjust rounded corners so that they fit nicely with the arcs around them (Arthur) [#399373] - fix session hang when metacity .sm file is missing (Josselin) [#407981] - add support for _NET_WM_USER_TIME_WINDOW in order to cut down on context switches (Elijah, Havoc) [#354213] - prevent nasty metacity/gdk interactions causing hangs with gtk trunk (Elijah) [offshoots of #354213] - fix button middle fallback and the prelight state (Benjamin) [#419043] - Lots of code cleanup for the strut lists (Elijah) - fix handling of unidirectional maximization and partial struts + some miscellaneous cleanups (Carlo) [#358311] - avoid some crashes when dragging windows partially offscreen (Elijah) [#353513] - avoid mousenav vs. keynav focus problems with the run application dialog in mouse/sloppy focus modes (Elijah) [#374752] - _NET_ACTIVE_WINDOW property on the root window should be a single xwindow id, not two (Elijah) - Fix unidirection unmaximization causing jumps (Elijah) [#355497] - fix unfullscreening and unmaximizing with size increment/size constraint windows (such as gnome-terminal) possibly not returning to their "original position" (Elijah) [#329152] - fix some issues with min/max and size increment constraints (Elijah) [#418395] - send synthetic configure notify events in response to appropriate MapRequest events too (Elijah) [#322840] Translations Ihar Hrachyshka (be@latin), Jordi Mallach (ca), Jakub Friedl (cs), norbu (dz), David Lodge (en_GB), Ivar Smolin (et), Gabor Kelemen (hu), Luca Ferretti (it), Takeshi AIHANA (ja), Erdal Ronahi (ku), Gintautas Miliauskas (lt), Jovan Naumovski (mk), Kjartan Maraas (nb), Reinout van Schouwen (nl), wadim dziedzic (pl), raulpereira (pt_BR), Nickolay V. Shmyrev (ru), Горан Ракић (sr), Woodman Tuen (zh_HK), Woodman Tuen (zh_TW) 2.17.5 ====== Thanks to Bruno Boaventura, Mad Alex, and Thomas Thurman for improvements in this release. - make window menu arrangement more sensible. (Bruno) [#382962] - unmaximise button keeps pressed appearance when moved off and back. (Alex) [#395560] - fix a couple of compositor crashes (Thomas) [#387761] - new environment variables checked if the compositor is enabled; see the new file doc/compositor-control.txt for details. (Thomas) Translations Djihed Afifi (ar), Ales Nyakhaychyk (be), Jordi Mallach (ca), Jakub Friedl (cs), David Lodge (en_GB), Raivis Dejus (lv), Kjartan Maraas (nb), Mugurel Tudor (ro), Daniel Nylander (sv), Theppitak Karoonboonyanan (th) 2.17.3 ====== Thanks to Christof Krüger, Federico Mena Quintero, Bruno Boaventura, and Björn Lindqvist for improvements in this release. - fix longstanding problem about windows flickering in and out of maximised state when dragging between xineramas (Christof) [#358715] - grab server when switching workspaces (Federico) [#381127] - replace changing text on window menu with pairs of radio buttons and checkboxes (Bruno, Björn) [#343108] Translations Kjartan Maraas (nb), Jakub Friedl (cs), Yuval Tanny (he), Ivar Smolin (et), Duarte Loreto (pt), Francisco Javier F. Serrador (es) 2.17.2 ====== Thanks to Priit Laes, Bruno Boaventura, Kjartan Maraas, Justin Mason, Elijah Newren and Dan Mick for improvements in this release. - implement handle_move_to_{side|corner}_* to allow the user to flip a window to the side or corner of the screen. (Justin) [#317884] - fix strict focus mode by picking up on res_class (Dan) [#361054] - remove deprecated gtk stuff (Priit, Bruno) - string fixes (Kjartan) [#363354, #363355] Translations Jakub Friedl (cs), Francisco Javier F. Serrador (es), Ilkka Tuohela (fi), Christophe Merlet (RedFox) (fr), Kjartan Maraas (nb) 2.17.1 ====== Thanks to Bruno Boaventura and Carlo Wood for improvements in this release. - sync metacity workspace previous with libwnck (Bruno) [#341893] - fix cases when titlebar is allowed offscreen and shouldn't be, and vice-versa (Carlo) [#333995] Translations Ilkka Tuohela (fi) 2.17.0 ====== Thanks to Elijah Newren, Jens Granseuer, Bruno Boaventura, Carlo Wood, and Thomas Thurman for changes in this release. - version 2 of theme format: stick, shade and above buttons on titlebar, variable rounding on corners, variable transparency on window backgrounds, stock icons in themes, can remove all titlebar buttons from certain classes of window, and more (Thomas) [#102547 and dependencies] - improve "Force Quit" dialog (Bruno) [#121936] - ignore edge resistance when resizing with keyboard (Elijah) [#346782] - maintain window size and placement across restarts (Carlo) [#358042] - prevent crash when closing certain remote apps (Elijah) [#358514] - longstanding mouse-focus bug fixed which affected firefox's autocompletion (Elijah) [#357695] - ignore maximum size constraints when maximising (Elijah) [#327543] - warn translators to keep translations in sync with libwnck (Bruno) [#355620] - fixes for compilation warnings, etc (Elijah, Jens) [#348067, #356631] Translators Ivar Smolin (et), Gabor Kelemen (hu), Luca Ferretti (it), Runa Bhattacharjee (bn_IN) 2.16.2 ====== Thanks to Eljah Newren, Maik Beckmann, Christian Hamar, Thomas Andersen, and Bruno Boaventura de Oliveira for changes in this release. - partial audit to fix timestamp usage (Elijah) [part of #355180] - remove compilation warnings (Maik) [#355876]; (Bruno) [#355490, #355489] - automatic detection of stable/unstable in configure script (Christian/Elijah) [#356122] - make windows be stacked correctly before showing them (Thomas) [#332385] - use guint32 for timestamps (Elijah) [#348305] Translators Wouter Bolsterlee (nl), Matic Žgur (sl), Francisco Javier F. Serrador (es), Vladimir Petkov (bg), Jordi Mallach (ca), Ilkka Tuohela (fi), Rajesh Ranjan (hi), Woodman Tuen (zh_HK, zh_TW), Ani Peter (ml), Felix (ta), Ankit Patel (gu), Mohammad DAMT (id) 2.16.1 ====== Thanks to Elijah Newren, Colin Watson, and Bruno Boaventura de Oliveira Lacerda for changes in this release. - fix stuck grab, letting focus be transferred between windows (Elijah) [#354422 partial] - windows returning from fullscreen are constrained to be onscreen (Elijah) [#353699] - Clear the transient_for flag of a window after emitting a warning (Colin) - Replace copy_of_gdk_x11_window_set_user_time() with the real thing (Bruno) [#352293] Translators David Lodge (en_GB), Ivar Smolin (et), Matic Žgur (sl), Vasiliy Faronov (ru) 2.16.0 == Thanks to Jens Granseuer for changes in this release. - Fix the build with c89/gcc 2.95. Translators Rahul Bhalerao (mr), Runa Bhattacharjee (bn_IN), Woodman Tuen (zh_HK, zh_TW), Kostas Papadimas (el), Ani Peter (ml), Jonathan Ernst (fr), Горан Ракић (sr, Gabor Kelemen (hu), Maxim Dziumanenko (uk), Duarte Loreto (pt), Jordi Mallach (ca), Gintautas Miliauskas (lt) 2.15.34 == Thanks to Stéphane Rosi, Vytautus Liuolia, Will Walker, Baptiste Mille-Mathias, Elijah Newren, Ed Catmur, and Thomas Andersen for fixes in this release. - allow moving maximized windows between xineramas again (Stéphane) [#338660] - fix an uninitialized-usage bug with net_wm_user_time that breaks focus with new windows (Vytautus) - re-fix accessibility events for the alt-tab popup (Will) [#350624] - update the close pixmap to fit better with the other pixmaps of the menu (Baptiste) [#345498] - fix several fullscreen handling bugs I introduced, causing fullscreen windows to not actually be shown fullscreen (Elijah) [#343115] - fix keybindings with hex-values, coming from special extended keyboard keys (Ed) [#140448] - fix metacity-dialog handling of arguments (Thomas) [#340690] Translators Vladimir Petkov (bg), Jordi Mallach (ca), Gabor Kelemen (hu), Mohammad DAMT (id), Wouter Bolsterlee (nl), Daniel Nylander (sv), Funda Wang (zh_CN) 2.15.21 == Thanks to Vincent Untz, Jens Granseuer, Björn Lindqvist, Dmitry Timoshkov, Thomas Thurman, Vytautas Liuolia, Thomas Andersen, Chris Ball, and Elijah Newren for fixes in this release. - kill usage of libegg (Vincent) [#348633] - fix another C89 vs. C99 issue (Jens) [#347621] - make it so maximized windows do not have rounded corners (Björn) [#336850] - fix the heuristic for determining if windows can be made fullscreen, needed for WINE and possible also some legacy applications (Dmitry) [#346927] - make sure window features get recalculated when the screen is resized via XRandR (Dmitry) [#346927] - fitts' law fixes for titlebar buttons on maximized windows (Thomas Thurman) [#97703] - react to _NET_STARTUP_ID changes, as proposed for the new startup-notification/EWMH spec (Vytautas) [#347515] - return the window to maximized state if the window was "shaken loose" from maximized state during a resize but the resize is later aborted (Thomas Andersen) [#346719] - fix button lighting with dragged clicks (Björn) [#321474] - don't minimize in response to double clicks on the titlebar when minimiziation should not be allowed (Chris) [#347377] - fix some titlebar-not-on-screen constraint issues (Elijah) [#333328, #345522] Translators Mahay Alam Khan (bn_IN), Jakub Friedl (cs), Iñaki Larrañaga Murgoitio (eu), Yuval Tanny (he), Rajesh Ranjan (hi), Jovan Naumovski (mk) Kjartan Maraas (nb), Leonid Kanter (ru) 2.15.13 == Thanks to Björn Lindqvist and Thomas Thurman for improvements in this release. - grab alt+shift+button1 when trying to snap-move windows (Björn) - avoid a case where memory is written after it's freed (Thomas) Translators Hendrik Richter (de), Kostas Papadimas (el), Jonathan Ernst (fr), Satoru SATOH (ja) 2.15.8 == Known as the "Elijah sucks for not reviewing a couple dozen patches" release. And for not getting on IRC soon enough to catch Marnanel and show him how to do the release. So, just translations this time. Translations Mahay Alam Khan (bn_IN), Rhys Jones (cy), Francisco Javier F. Serrador (es), Ilkka Tuohela (fi), Rajesh Ranjan (hi), Changwoo Ryu (ko), Fano Rajaonarisoa (mg), Sanlig Badral (mn), Слободан Д. Средојевић (sr), Funda Wang (zh_CN) 2.15.5 == Thanks to Björn Lindqvist, Søren Sandmann, Adam Jackson, Elijah Newren, and Aidan Delaney for improvements in this release. - code cleanup in resizepopup.c (Björn) [#341648] - fix a logic bug so that the whole titlebar becomes sensitive to mouse clicks (Björn) [#336320] - make mouse cursor when moving windows become a hand (Björn) [#337376] - lots and lots of compositor improvements -- beginning of a new layer to abstract transition effects, shrinking and minimizing and exploding effects, fading in and out, unminimize animation that reverses minimize one, translucent menus, bounce on window focus, and all kinds of stuff I don't understand and can't summarize well (Søren, Adam) - Fix a crash on exit/logout from assuming a compositor would always exist (Elijah) [#342166] - code cleanup in tabpopup.c (Aidan Delaney) [#166890] Translations Pema Geyleg (dz), Iñaki Larrañaga Murgoitio (eu), Theppitak Karoonboonyanan (th), Clytie Siddall (vi) 2.15.3 == Thanks to Søren Sandmann, Elijah Newren, Paolo Borelli, Björn Lindqvist, jylefort at FreeBSD org, - various code cleanups (Søren) - prevent long titles from "sticking" in the tasklist (Elijah) [#330671] - handle sync counter notifications in the compositor (Søren) - notes/documentation updates (Elijah) - plug a small leak (Paolo) - remove a lot of dead code obsoleted by the new edge-resistance stuff (Björn) [#341561] - prevent a crash when changing resolution (jylefort) [#340847] - revert an accessibility module loading workaround from Gnome 2.6 that has long since been fixed for us in gtk+ (Elijah) [#123372] Translations Francisco Javier F. Serrador (es), Ignacio Casal Quinteiro (gl), Raivis Dejus (lv), Kjartan Maraas (nb), Funda Wang (zh_CN), Woodman Tuen (zh_HK), Woodman Tuen (zh_TW) 2.15.2 == Here's hoping that "third time's a charm." ;-) This release just fixes the translations-not-included issue. See http://mail.gnome.org/archives/desktop-devel-list/2006-April/msg00483.html for more details. - Use gnome-autogen.sh like most other modules (Rodney) 2.15.1 == This release just fixes the control-center build (which depends upon libmetacity-private). Thanks to Vincent for catching the problem. - Include boxes.h in the includes dir (Elijah) [#339708] 2.15.0 == Thanks to Thomas Thurman, Elijah Newren, Havoc Pennington, Björn Lindqvist, Gora Mohanty, Alejandro Andres, Andy Morum, Dan Sanders, Thomas Andersen, Brian Pepple, and Søren Sandmann for improvements in this release. (Note that "Thomas" below refers to Thomas Thurman if last name isn't specified) - An endless array of compositor updates, not all of which are well explained in the ChangeLog. ;-) Includes an ability to enable and disable the compositor at runtime, fixed up wobbling effect and new explosion effect, special magnification handling, different opacity for different window types like menus, a way of scaling windows, handling of foreign displays, improved handling of window moving/resizing, various code restructuring, special runtime checks for correct extensions and other compositors, lots of bug fixes, and possibly other stuff I'm missing or not understanding (Søren) - Removed "move to another workspace" menu when there are exactly two workspaces (Thomas) [#151183] - fix type for compositing_manager schema entry (Elijah) [#335901] - Port more properties to our async system for code cleanliness and speed improvements (Havoc, Thomas) - Lots of code cleanup, even more code cleanup, wow our code was messy (Björn) [#335177, #337507, #336890, #338359] - Abstract out the functions for setting/unsetting demands attention hint and avoid doing it when the window isn't obscured (Thomas) [#305882] - Change strings to make them more readable, and more translatable (Gora) [#335720] - Reduce compiling warnings -- add a number of casts and change signedness on a number of variables (Björn) [#336032] - Fixed broken links in README (Alejandro) [#333303] - Add a tabbing function, bound to alt-f6 by default, to cycle through the windows of the current application (Thomas) [#94682] - Fix the build with --disable-xsync (Andy) [#336605] - Raise windows on maximize/unmaximize (Dan) [#335076] - Don't have confirmation windows make applications appear to be locked when closing via the window list (Dan) [#334899] - Allow any keybinding pref to be specified either with , a string, or _list, a list of strings, or both (Thomas) [#164831] - warn and ignore if transient_for is set to a non-top-level window (Thomas Andersen) [#335524] - Use po/LINGUAS for listing supported languages (Brian) [#337951] Translations Vladimir Petkov (bg), Jordi Mallach (ca), Miloslav Trmac (cs), Rhys Jones (cy), Lasse Bang Mikkelsen (da), Frank Arnold (de), Kostas Papadimas (el), Francisco Javier F. Serrador (es), Ivar Smolin (et), Iñaki Larrañaga (eu), Farzaneh Sarafraz (fa), Ilkka Tuohela (fi), Ignacio Casal Quinteiro (gl), Ankit Patel (gu), Rajesh Ranjan (hi), Gabor Kelemen (hu), Satoru SATOH (ja), Alexander Didebulidze (ka), Žygimantas Beručka (lt), Kjartan Maraas (nb), Michiel Sikkes (nl), Åsmund Skjæveland (nn), Gora Mohanty (or), Raphael Higino (pt_BR), Duarte Loreto (pt), Mugurel Tudor (ro), Leonid Kanter (ru), Steve Murphy (rw), Laurent Dhima (sq), Слободан Д. Средојевић (sr), Daniel Nylander (sv), Theppitak Karoonboonyanan (th), Maxim Dziumanenko (uk), Clytie Siddall (vi), Funda Wang (zh_CN) 2.14.3 == This release just reverts the widely hated new focus behavior of Metacity 2.14.x to the behavior found in 2.12.x. Patch came from Ron Yorston. See http://blogs.gnome.org/view/newren/2006/04/13/0 and http://mail.gnome.org/archives/release-team/2006-April/msg00025.html for more details. - Add a focus_new_windows gconf key, change the default to 'smart' (2.12 behavior) and add a 'strict' option to get 2.14 behavior. (Ron) [#326159] Translations Vladimir Petkov (bg), Miloslav Trmac (cs), Frank Arnold (de), Francisco Javier F. Serrador (es), Ilkka Tuohela (fi), Tino Meinen (nl), Åsmund Skjæveland (nn), Raphael Higino (pt_BR), Daniel Nylander (sv) 2.14.2 == Thanks to Thomas Thurman, Paolo Borelli, Björn Lindqvist, and Elijah Newren for fixes in this release. - Fix constraints bug causing negative width windows and crashes (Elijah) [#336651] - Fix window grouping with parent/child windows (Björn) [#336184] - use g_str_has_prefix instead of a local copy of the function (Paolo) [#334643] - Make sure pager can refresh when window is minimized on a different workspace (Thomas) [#315142] - Add debugging information for edge resistance (Elijah) Translations Vladimir Petkov (bg), tangi.bzh (br), Jordi Mallach (ca), Miloslav Trmac (cs), Rhys Jones (cy), Lasse Bang Mikkelsen (da), Frank Arnold (de), Mindu Dorji (dz), Kostas Papadimas (el), Francisco Javier F. Serrador (es), Ivar Smolin (et), Iñaki Larrañaga Murgoitio (eu), Elnaz Sarbar (fa), Ilkka Tuohela (fi), Ignacio Casal Quinteiro (gl), Ankit Patel (gu), Rajesh Ranjan (hi) Gabor Kelemen (hu), Luca Ferretti (it), Satoru SATOH (ja), Vladimer Sichinava (ka), Žygimantas Beručka (lt), Kjartan Maraas (nb), Tino Meinen (nl), Kjartan Maraas (no), Gora Mohanty (or), Gnome PL Team (pl), Evandro Fernandes Giovanini (pt_BR), Duarte Loreto (pt), Mugurel Tudor (ro), Leonid Kanter (ru), Laurent Dhima (sq), Слободан Д. Средојевић (sr), Daniel Nylander (sv), Theppitak Karoonboonyanan (th), Maxim Dziumanenko (uk), Clytie Siddall (vi), Funda Wang (zh_CN) 2.14.1 == The only change since 2.14.0 is to remove the "This is the UNSTABLE branch" warning from configure for those compiling Metacity from source. 2.14.0 == Thanks to Ryan Lortie and Thomas Thurman for fixes in this release. - Mark the app-running-remotely-window-title string for translation (Thomas) [#334332] - Only unmaximise window before freeing if the window is actually maximised (Ryan) [#333563] Translations Jordi Mallach (ca), Frank Arnold (de), Luca Ferretti (it), Evandro Fernandes Giovanini (pt_BR), Theppitak Karoonboonyanan (th) 2.13.144 == Thanks to Jens Granseuer, Kristian, Søren Sandmann, Sylvain Bertrand, and Thomas Thurman for improvements in this release. - Fix build with gcc 2.95 (Jens) [#331166] - Compositor improvements [remember, still off by default]: add unused wobbly (un)minimize animation (Kristian), add support for turning updates on and off (Søren), use sync counter to make composited resizing tear free (Søren), add ability to unmanage the screen (Søren), - Fix build issue with library search order (Sylvain) [#330695] - Work around buggy application grouping with transient windows (Thomas) [#328211] - Prevent setting cycle_windows to keybindings that won't work. (Thomas) [#329676] 2.13.89 == Thanks to Søren Sandmann, Thomas Thurman, Thom May, Akira Tagoh, Luke Morton, and Philip O'Brien for improvements in this release. - Compositor improvements [remember that the compositor is still disabled by default]: New fancy minimize animation that fades in and out, new debug stuff, various bug fixes (Søren) - When buggy apps create synthetic button or keypresses without a timestamp, produce a warning instead of failing an assertion (Thomas) [#313490] - Avoid a memory leak when checking which workspace(s) a window is on (Thomas) [#322059] - Add a man page for metacity (Thom, Akira, Luke, Philip) [#321279] - Disable alt-f7 if a window can't be moved, and alt-f8 if it can't be resized (Thomas) [#328920] - Allow alt-escape to cancel alt-tabbing, and vice versa (Thomas) [#141425] Translations Miloslav Trmac (cs), Kjartan Maraas (nb), Tino Meinen (nl), Kjartan Maraas (no), Слободан Д. Средојевић (sr), Funda Wang (zh_CN) 2.13.55 == Thanks to Dick Marinus, Christian Kirbach, and Elijah Newren for improvements in this release. - Add a minimize and none double-click-titlebar-action (Dick) [#300210] - Prevent a critical warning crasher when switching themes (Christian) [#327847] - Fix some uninitialized value problems (Elijah) - If the mouse enters a window on a different screen, activate the default window on the new screen (Elijah) [#319348] Translations Jordi Mallach (ca), Adam Weinberger (en_CA), Francisco Javier F. Serrador (es), Ilkka Tuohela (fi), Ignacio Casal Quinteiro (gl), Ankit Patel (gu), Kjartan Maraas (nb), Kjartan Maraas (no), Evandro Fernandes Giovanini (pt_BR), Theppitak Karoonboonyanan (th), Clytie Siddall (vi), Funda Wang (zh_CN) 2.13.34 == Thanks to Damien Carbery, Havoc Pennington, Søren Sandmann, Björn Lindqvist, Kjartan Maraas, Elijah Newren for improvements in this release. - manually define HOST_NAME_MAX if not already defined to fix Solaris compilation issue (Damien, Havoc) [#326745] - compositor improvements: port to changes in libcm, do it again, fix unrefing, make minimize animation update again (all done by Søren) - make sure an outline border is shown even if a window decoration's width is 0 (Björn) [#98340] - correctly handle window alt-tab outlines in showing desktop mode (Björn) [#98340] - fix lots of tiny issues spotted by the intel compiler (Kjartan) [#321439] - prevent rapidly repeated visual bells from hanging metacity (Elijah) [#322032] - more careful error handling of values returned by GConf (Elijah) [#326615] - fix various initialization and default issues, especially for running with --disable-gconf. Make --disable-gconf actually work. (Elijah) [#326661] - fix some reading-from-free'd-data errors (Søren) [#327575] - fix an unitialized value problem when in raise-on-click mode (Søren) [#327572] - avoid flashing original-sized window when closing a maximized window (Elijah) [#317254] - prevent windows from sometimes getting shoved and smashed by sliding (and possibly auto-hiding) panels (Elijah) [#327822] Translations Ilkka Tuohela (fi), Ignacio Casal Quinteiro (gl), Tino Meinen (nl), Funda Wang (zh_CN) 2.13.21 == Thanks to Damien Carbery, Ray Strode, Søren Sandmann, Elijah Newren, Jens Granseuer, and Kyle Ambroff for improvements in this release. - Fix Solaris compilation issues (Ray, Damien) [#326281, #326746] - Merge compositor work from branches to get the beginnings of an openGL based compositor. Still not ready and thus disabled by default. (Søren) - Composite fixes: Only update composite on damage events (Søren), get non-composite compilation working again (Elijah), Really turn off draw-in-a-loop (Søren) - Don't dereference a NULL string (Elijah) [#327013] - GCC 2.95 fix; remove more C99 style variable initiailizations (Jens) [#327050] - Fix accidental overzealous focus holding by the terminal (introduced in last release) so that windows launched from panel icons, the panel menu, or global keybindings should get focus now. (Elijah) [#326159] - If no valid window is found in the MRU list, then set focus to the desktop window. (Kyle) [#317405] Translations Adam Weinberger (en_CA), Francisco Javier F. Serrador (es), Ankit Patel (gu), Takeshi AIHANA (ja), Theppitak Karoonboonyanan (th), Clytie Siddall (vi) 2.13.13 == Thanks to Jens Granseuer, Björn Lindqvist, and Elijah Newren for improvements in this release. - Remove C99 style variable initiailization (Jens) [#322622] - Fix a logic error (Björn) [#322149] - Plug a few leaks (Elijah) [#309178] - Allow edge resistance at both sides of a window and also when edges don't overlap but are a single pixel away from doing so (Elijah) [part of #321905] - Remove the timeout resistance at screen/xinerama edges (Elijah) [part of #321905] - Revert to the old edge resistance behavior for keyboard movement/resizing based resistance (Elijah) [part of #321905] - Remove the "pull-away" edge resistance (Elijah) [part of #321905] - Avoid crashing when visual bell is in use and focus window is closed (Elijah) [#322031] - Be more strict about what is considered a valid region with partial struts (Elijah) [#322070] - Fix reduced resources resize handling for windows with sizing or resizing constraints (Elijah) [#325774] - Fix window outline for minimized windows when using alt-esc (Elijah) [#325092] - Make the taskbar less flash happy and fix up some related stacking issues (Elijah) [#326035] - More thorough handling of source indication (Elijah) [part of #326041] - Don't "steal" focus from terminal windows for new window mappings as the difference in usage between terminals and other apps seems to suggest this difference in treatment. See bug #326159 for details, feedback welcome (Elijah) [#326159] - Add a raise on click option, basically only because all the major distros are patching it in anyway (though each and every one of them has bugs in their implementations). (Elijah) [#326156] Translations Kjartan Maraas (nb), Kjartan Maraas (no) 2.13.8 == Thanks to Kang Jeong-Hee and Elijah Newren for improvements in this release. - Fix some compilation warnings and issues (Kang) - Escape the title since it is going to be treated as Markup (Elijah) [#324846] - Make the workspace switcher work with dual-head (non-xinerama) setups (Elijah) [#319423] Translations Ilkka Tuohela (fi), Ankit Patel (gu), Kang Joeng-Hee (ko) 2.13.5 == Thanks to Davyd Madeley, Kjartan Maraas, and Björn Lindqvist for improvements in this release. - Make a debugging message actually correspond to the code (Björn) [#322051] - Make the wireframe a bit slimmer (Kjartan) [#320051] - Display hostname in titlebar for remote X clients (Davyd) [#322202] Translations Miloslav Trmac (cs), Adam Weinberger (en_CA), Ankit Patel (gu), Kjartan Maraas (nb), Kjartan Maraas (no), Marcel Telka (sk) 2.13.3 == This is a special edition release just for gicmo, code-named 'elijah, please do a release so magic seb can bring it to me'. It fixes a number of issues due to the major constraints changes found since the last release. Thanks to Davyd Madeley and Elijah Newren for improvements in this release. - Differentiate between movement towards an edge and movement away from one for edge-resistance. Pick smaller constants for movement away from an edge (Elijah) - Use GPOINTER_TO_INT() macro instead of cast to allow compilation on 64-bit architectures without warning (Davyd) - compute the frame geometry due to maximization only after actually maximizing (Elijah) [#321902] - add some developer documentation on updating struts, workareas, regions, and edges (Elijah) - When updating the xinerama due to placement, update which maximal/spanning rect set to use as well (Elijah) [#322068] - Relax the partially onscreen constraint to allow the titlebar to touch the bottom panel in order to make the new constraints code function the same as the old version (Elijah) [#322071] - Don't allow removing a window from maximized or fullscreened state to place the titlebar under the top panel (Elijah) [#322075] Translations Vladimir Petkov (bg), Francisco Javier F. Serrador (es), Ignacio Casal Quinteiro (gl), Takeshi AIHANA (ja), Theppitak Karoonboonyanan (th) 2.13.2 == This release just contains a merge of all the changes on the constraints_experiments branch. Thanks to Havoc Pennington for reviewing the gargantuan patch and suggesting lots of little fixes for making it better, to Rob Adams and Soeren Sandmann for grilling me on how some of the difficult internals work -- allowing me to improve the documentation, to Olav Vitters for finding an easy-to-fix crasher bug in early testing and for repeatedly extending my deadline for switching from working on Metacity to Bugzilla, to Ray Strode for finding two crashers and fixing one of them in early testing, to Bryan Clark for usability advice, to Davyd Madeley and Christian Kellner for testing Xinerama stuff, to Sebastien Bacher for packaging an early version and finding some obscure bugs (that I unfortunately still can't duplicate and will probably still need to fix once I can), Bugs fixed: unfiled - constraints.c is overly complicated[1] unfiled - constraints.c is not robust when all constraints cannot simultaneously be met (constraints need to be prioritized) unfiled - keep-titlebar-onscreen constraint is decoration unaware (since get_outermost_onscreen_positions() forgets to include decorations) unfiled - keyboard snap-moving and snap-resizing snap to hidden edges 86644 - resize should have a shift option like move does 109553 - gravity w/ simultaneous move & resize doesn't work 113601 - maximize vertical and horizontal should toggle and be constrained 122196 - windows show up under vertical panels 122670 - jerky/random resizing of window via keyboard[2] 124582 - keyboard and mouse snap-resizing and snap-moving erroneously moves the window multidimensionally 136307 - don't allow apps to resize themselves off the screen (*cough* filechooser *cough*) 142016, 143784 - windows should not span multiple xineramas unless placed there by the user 143145 - clamp new windows to screensize and force them onscreen, if they'll fit 144126 - Handle pathological strut lists sanely[3] 149867 - fixed aspect ratio windows are difficult to resize[4] 152898 - make screen edges consistent; allow easy slamming of windows into the left, right, and bottom edges of the screen too. 154706 - bouncing weirdness at screen edge with keyboard moving or resizing 156699 - avoid struts when placing windows, if possible (nasty a11y blocker) 302456 - dragging offscreen too restrictive 304857 - wireframe moving off the top of the screen is misleading 308521 - make uni-directional resizing easier with alt-middle-drag and prevent the occasional super annoying resize-the-wrong-side(s) behavior 312007 - snap-resize moves windows with a minimum size constraint 312104 - resizing the top of a window can cause the bottom to grow 319351 - don't instantly snap on mouse-move-snapping, remove braindeadedness of having order of releasing shift and releasing button press matter so much [1] fixed in my opinion, anyway. [2] Actually, it's not totally fixed--it's just annoying instead of almost completely unusable. Matthias had a suggestion that may fix the remainder of the problems (see http://tinyurl.com/bwzuu). [3] This bug was originally about not-quite-so-pathological cases but was left open for the worse cases. The code from the branch handles the remainder of the cases mentioned in this bug. [4] Actually, although it's far better there's still some minor issues left: a slight drift that's only noticeable after lots of resizing, and potential problems with partially onscreen constraints due to not clearing any fixed_directions flags (aspect ratio windows get resized in both directions and thus aren't fixed in one of them) New feature: 81704 - edge resistance for user move and resize operations; in particular 3 different kinds of resistance are implemented: Pixel-Distance: window movement is resisted when it aligns with an edge unless the movement is greater than a threshold number of pixels Timeout: window movement past an edge is prevented until a certain amount of time has elapsed during the operation since the first request to move it past that edge Keyboard-Buildup: when moving or resizing with the keyboard, once a window is aligned with a certain edge it cannot move past until the correct direction has been pressed enough times (e.g. 2 or 3 times) Major code changes: - constraints.c has been rewritten; very few lines of code from the old version remain. There is a comment near the top of the function explaining the basics of how the new framework works. A more detailed explanation can be found in doc/how-constraints-works.txt - edge-resistance.[ch] are new files implementing edge-resistance. - boxes.[ch] are new files containing low-level error-prone functions used heavily in constraints.c and edge-resistance.c, among various places throughout the code. testboxes.c contains a thorough testsuite for the boxes.[ch] functions compiled into a program, testboxes. - meta_window_move_resize_internal() *must* be told the gravity of the associated operation (if it's just a move operation, the gravity will be ignored, but for resize and move+resize the correct value is needed) - the craziness of different values that meta_window_move_resize_internal() accepts has been documented in a large comment at the beginning of the function. It may be possible to clean this up some, but until then things will remain as they were before--caller beware. - screen and xinerama usable areas (i.e. places not covered by e.g. panels) are cached in the workspace now, as are the screen and xinerama edges. These get updated with the workarea in src/workspace.c:ensure_work_areas_validated() Translation Michiel Sikkes (nl) 2.13.1 == Thanks to Philip O'Brien, Kjartan Maraas, and Aidan Delaney for improvements in this release. - add handling for META_PREF_CURSOR_THEME and META_PREF_CURSOR_SIZE for more complete debug info (Philip) [#318976] - Remove possible g_source leak in #ifdef'd out code, in case anyone uses it in the future (Kjartan) [#320050] - Changed the 'minimized' field of the MetaTabEntry struct to 'hidden' (Aidan) [#168455] Translations Miloslav Trmac (cs), Francisco Javier F. Serrador (es), Takeshi AIHANA (ja), Erdal Ronahi (ku), Theppitak Karoonboonyanan (th) 2.13.0 == Thanks to Björn Lindqvist, Kjartan Maraas, Søren Sandmann, Elijah Newren, Ross Cohen, and Muktha for improvements in this release since 2.12.1. - Mave ancestors come along with the transient when moving the window from one workspace to another (Björn) [#314977] - Fix the workspace switcher tabpopup to display the right windows and to fix the pick-a-new-window-to-focus algorithm in order to not select windows that aren't showing (Björn) [#170475] - Fix a couple memory leaks (Kjartan, Søren, Elijah) [#313030] - Make alt-esc (the "switch between windows immediately" keybinding) actually show minimized windows too (Ross) [#107072] - Make alt-esc consistent with alt-tab by leaving stacking of unselected windows unchanged (Ross) [#314285] - Clarify the meaning of the auto_raise preference (Elijah) [#312421] - Fix a crash that occurs when removing some virtual desktops and windows happen to be on those desktops (Elijah) [#318306] - Make the unfocussed Simple window border visible with high contrast inverse theme (Muktha) [#121361] - Fix edge snapping for multi-screen (non-xinerama) setups (Elijah) [#319425] Translations Vladimir Petkov (bg), Kostas Papadimas (el), Adam Weinberger (en_CA), Ivar Smolin (et), Michiel Sikkes (nl), Marcel Telka (sk), Funda Wang (zh_CN) 2.12.1 == Thanks to Ray Strode, Havoc Pennington, and Elijah Newren for improvements in this release. - Truncate ridiculously long titles to avoid crashing or letting the pager crash (Ray, Havoc, Elijah) [#315070] - Get the tabbing window outline to work with gtk+ 2.8.4 again (Elijah) [#317528] Translations Mahay Alam Khan (bn), Francisco Javier F. Serrador (es), Ivar Smolin (et), Iñaki Larrañaga Murgoitio (eu), Luca Ferretti (it), Christian Rose (sv), Clytie Siddall (vi), Funda Wang (zh_CN) 2.12.0 == Thanks to Brent Smith for finding the crasher in the release candidate! - Fix an uninitialized variable problem causing crashes (Brent) [#315000] Translations Bryn Salisbury (cy), Hendrik Richter (de), Christophe Merlet (RedFox) (fr), Ignacio Casal Quinteiro (gl), Norayr Chilingaryan (hy), Young-Ho Cha (ko), Žygimantas Berucka (lt), Michiel Sikkes (nl), Leonid Kanter (ru), Danilo Šegan (sr), Baris Cicek (tr) 2.11.3 == Thanks to Björn Lindqvist and Elijah Newren for improvements in this release. - Check for the right versions of glib and gtk+ (Björn) [#314116] - Avoid obscuring centered-on-desktop windows which are denied focus (Elijah) [#313234] Translations Vladimir Petkov (bg), Jordi Mallach (ca), Kostas Papadimas (el), Ivar Smolin (et), Gabor Kelemen (hu), Mohammad DAMT (id), Duarte Loreto (pt), Mugurel Tudor (ro), Laurent Dhima (sq), Maxim Dziumanenko (uk) 2.11.2 == Thanks to Elijah Newren, Jaap Haitsma, Ray Strode, and Brent Smith for improvements in this release. - Fix an easy to trigger crasher in 2.11.1 caused by unneeded debugging spew (Elijah) [#311819] - Make sure that Metacity dialogs have icons (Jaap) [#309876] - Fix an infinite restacking flicker loop in sloppy and mouse focus with fullscreen windows (Elijah) [#311400] - Change default theme from Simple to Clearlooks (Elijah) - Vastly improve the behavior of keyboard move/resize and edge snapping (Ray) [#310888] - Remove a duplicate string (Brent) [#309774] Translations Yuval Tanny (he), Gnome PL Team (pl), Raphael Higino (pt_BR), Chao-Hsiung Liao (zh_TW) 2.11.1 == Thanks to Elijah Newren, Ken Harris, Matthias Clasen, Christian Persch, and Billy Biggs for improvements in this release. - Fix a miscoloring of parts of the titlebar introduced in the last unstable release (Elijah) [follow-up to #169982] - Provide a more lenient threshold for drawing rounded corners (Ken) [#122065] - Make the Xcursor changes in the last unstable release effective (Matthias) [follow-up to #308106] - Revert the _NET_ACTIVE_WINDOW behavior change made in the 2.9.x unstable series; activation includes changing a window to the current workspace again (Elijah) [reversion of #128380] - Restore original window size if the window was maximized upon withdrawing it (Elijah, Christian) [#137185] - Fix a raising bug with a window that has more than one child window (Elijah, Billy) [part of #307875] - Try to place windows denied focus near the focus window and fix a xinerama bug with the placement (Elijah) [part of #307875] - Avoid modal dialogs being obscured in somewhat pathologically strange circumstances that Eclipse seems to be good at triggering (Elijah) [part of #307875] Translations Miloslav Trmac (cs), Kostas Papadimas (el), Adam Weinberger (en_CA), Francisco Javier F. Serrador (es), Ilkka Tuohela (fi), Christophe Merlet (RedFox) (fr), Ignacio Casal Quinteiro (gl), Ankit Patel (gu), Yair Hershkovitz (he), Takeshi AIHANA (ja), Kjartan Maraas (nb), Kjartan Maraas (no), Marcel Telka (sk), Theppitak Karoonboonyanan (th), Clytie Siddall (vi), Funda Wang (zh_CN) 2.11.0 == This release contains all fixes up to Metacity 2.10.2 plus some new goodies. Thanks to Matthias Clasen, Aivars Kalvans, Björn Lindqvist, and Andrew Johnson for improvements in this release. - React to cursor theme changes (Matthias) [#308106] - Plug a small leak with xinerama information (Aivars) [#307884] - Split up main() into more manageable chunks and make use of GOpt (Björn) [#305331] - Speed up vertical gradients (Andrew) [#169982] Translations Hendrik Richter (de), Ivar Smolin (et), Ignacio Casal Quinteiro (gl), Clytie Siddall (vi) 2.10.2 == Thanks to Billy Biggs, Greg Hudson, Elijah Newren, Ray Strode, Ryan Lortie, and Soeren Sandmann for improvements in this release. - Makes metacity a bit faster when dragging windows around (Soeren) [#141813] - Fix simple memory error, using the address of a local variable as a hash key (Ryan) [#307209] - Fix a small leak in the case of a SYNC_COUNTER property value and HAVE_XSYNC not defined (Ryan) [#307214] - Cleanup font data when done with it (Ray) [#306720] - If the window has a modal transient which is being unmanaged, don't focus it (Elijah) [#305362] - Make sure window position is calculated correctly for reconfigure requests when part of the XWindowChanges structure is uninitialized (Greg) [#305257] - Add a resize popup when resizing constrained windows (Ray) [#305564] - Don't accidentally treat maximize vertically as maximize in both directions (Elijah) [#302204] - Put all transients of the new window, if any exist, in the calc_showing queue (Elijah, Billy) [#303284] Translations Kostas Papadimas (el), Priit Laes (et), Pauli Virtanen (fi), Ignacio Casal Quinteiro (gl), Theppitak Karoonboonyanan (th), Canonical Ltd (xh), Woodman Tuen (zh_TW) 2.10.1 == This is a stable release to coincide with the release of Gnome 2.10.0. Thanks to Dan Winship and Lex Hider for fixes in this release. - Make sure the "Close" button has the focus in the buggy-session-management-applications-warning dialog instead of the table (Dan) [#172703] - add doc/code-overview.txt and doc/how-to-get-focus-right.txt to the distributed files (Lex) [#170519] Translations Adam Weinberger (en_CA), Christopher Orr (en_GB), Elnaz Sarbar (fa), Gabor Kelemen (hu), Jyotsna Shrestha (ne), Steve Murphy (rw), Baris Cicek (tr), Canonical Ltd (xh) 2.10.0 == This is a stable release to coincide with the release of Gnome 2.10.0. The only difference between this version and 2.9.34 is some translation updates. Translations Vladimir Petkov (bg), Gabor Kelemen (hu), Žygimantas Berucka (lt), Reinout van Schouwen (nl), Mugurel Tudor (ro), Danilo Šegan (sr), Woodman Tuen (zh_TW) 2.9.34 == This is an unstable release to coincide with the release of Gnome 2.10.0 release candidate 1 (2.9.92). Thanks to Aidan Delaney, Elijah Newren, and Joe Marcus Clarke for fixes in this release. - Fix crash that occurs when stupid apps claim that a window is its own parent (Elijah, Joe) [#168207] - Prevent the visual bell from changing the focus window (Elijah) [#123366] - Make sure that icons in the alt-tab popup are dimmed for all hidden windows, not just minimized ones (Aidan) [#168455] Translations Elnaz Sarbar (fa), Ankit Patel (gu), Luca Ferretti (it), Reinout van Schouwen (nl), Gnome PL Team (pl), Alexandre Folle de Menezes (pt_BR) 2.9.21 == This is an unstable release heading towards Gnome 2.10. Since there have been an awful lot of fixes since Gnome 2.10 Beta 2, we are hoping to get an extra week of wider testing of all these changes before hard code freeze. Thanks to Aidan Delaney, Crispin Flowerday, Elijah Newren, and Joe Marcus Clarke for fixes in this release. - Make sure we get a valid timestamp if one doesn't come with the _NET_ACTIVE_WINDOW message (Elijah, Crispin) [#166728] - Avoid sending CurrentTime to our XSetInputFocus wrappers, but handle it better in case we miss any cases (Elijah) [#166732] - Remove useless function call (Aidan) [#166730] - Avoid new windows being obscured by the focus window and thus possibly lost (Elijah) [#166524] - Don't unconditionally place not-to-be-focused windows, such as splashscreens, below the focus window (Elijah) [#167042] - Raise the ancestor of a window instead of the window itself (Elijah) [#166894] - Cover half a dozen issues needed to fix a variety of rare timestamp bugs (Elijah) [#167358] - Fix a possible crash on logout (Joe) [#167935] - Fix an obscure xinerama placement bug with windows that are too large to fit in the workarea in both dimensions (Elijah) [#166757] - Ignore all focus and focus-stealing-prevention code in meta_window_show when not showing the window for the first time (Elijah) [#167199] - when receiving a _NET_ACTIVE_WINDOW message, switch to the desktop where the window is located before activating instead of moving the window to the current desktop (Elijah) [#128380] - Handle _NET_CURRENT_DESKTOP messages that come with timestamps (Elijah) [#161361] - Handle keynav vs. mousenav in mouse and sloppy focus modes (Elijah) [#167545] Translations Jordi Mallach (ca), Martin Willemoes Hansen (da), Kostas Papadimas (el), David Lodge (en_GB), Francisco Javier F. Serrador (es), Tõivo Leedjärv (et), Christophe Merlet (RedFox) (fr), Takeshi AIHANA (ja), Young-Ho, Cha (ko), Kjartan Maraas (nb), Michiel Sikkes (nl), Kjartan Maraas (no), Duarte Loreto (pt), Leonid Kanter (ru), Marcel Telka (sk), Laurent Dhima (sq), Maxim Dziumanenko (uk) 2.9.13 == This is an unstable release to coincide with the release of Gnome 2.10.0 Beta 2 (2.9.91). Thanks to Elijah Newren, Balamurali Viswanathan, Stephane Loeuillet, Benjamin Kahn, Garrett (LeSage?), Jose Moya, Dave Ahlswede, Arvind Samptur, John Paul Wallington, Tim Herold, Muktha Narayan, Sinisa Segvic, Owen Taylor, Crispin Flowerday, "RHEL-3", KWin, and Google for improvements in this release. - Refuse to focus a window with a modal transient, and focus the transient instead (Elijah) [#164716] - Make sure we get gconf notifications about the terminal command changing (Balamurali) [#160934] - Specify encoding of src/metacity.desktop.in (Stephane) [#151850] - New 48x48 default icon (Benjamin, Garrett) [#160660] - Add man pages for metacity-window-demo and metacity-theme-viewer (Jose, Dave) [#143513] - Fix minimized window display in workspace switcher after relogin with a saved session (Elijah) [#164677] - Ignore sticky windows for non-active workspaces (Elijah) [#165259] - Don't wireframe when accessibility is on, it apparently causes a desktop wide freeze. (Arvind) [#159538] - Keep tooltip on screen horizontally for xinerama (John) [#165261] - Stick and unstick transients with their parent automatically (Elijah) [#152283] - Shaded windows should not show up in pagers (Elijah) [#165377] - Treat splashscreens same as other windows for stacking (Elijah) [#165243] - Plug a pair of leaks (Elijah) [#165378] - Take into account the appropriate list of windows when placing a new one (Elijah) [#165381] - Correct misleading and inaccurate wording (Elijah) [#165380] - Handle xcomposite pkgconfig version regression (Tim) [#149368] - Make the warn-about-buggy-session-management-apps dialog be sticky (Elijah) [#164745] - Fix the problem with fullscreen windows on a different xinerama monitor not staying on top ("RHEL-3") [#156511] - Make the unfocussed title bar distinguishable in cases where it otherwise isn't for the Atlanta, Simple, and Bright themes (Muktha) [#125291] - Correct the stacking when returning from fullscreen mode (Elijah) [#165718] - Focus parents of dismissed transient windows in preference to the window that most recently had keyboard focus (Elijah) [#157360] - Make sure window->border_only is initialized so we don't get random windows without decorations (Elijah, Sinisa, Owen) [#145131] - Add period to the end of reduced_resources' description (Dave) [#165780] - If activation requests are too old, set the demands_attention hint instead of actually activating (Elijah, Crispin) [#166395] - Ignore xconfigurerequest events for stacking when it should be safe to do so (Elijah, Crispin, KWin, Google) [#166395] - Set a _METACITY_VERSION property (a utf8 string) on the WM check window (Elijah) [#165350] Translations Vladimir Petkov (bg), Miloslav Trmac (cs), Frank Arnold (de), Adam Weinberger (en_CA), David Lodge (en_GB), Francisco Javier F. Serrador (es), Pauli Virtanen (fi), Young-Ho, Changwoo Ryu (ko), Žygimantas Berucka (lt), Kjartan Maraas (nb), Kjartan Maraas (no), Duarte Loreto (pt), Marcel Telka (sk), Christian Rose (sv), Theppitak Karoonboonyanan (th) 2.9.8 == This is a brown paper bag release to cover up the crash I introduced in version 2.9.5. Thanks to Sebastien Bacher and the bleeding edge Ubuntu users for quickly catching the occasional crash that my fix in #123576 could cause, and for verifying that the patch I made fixed this issue (I couldn't duplicate). - Don't forget to initialize display->grab_old_window_stacking [#165093] 2.9.5 == This is an unstable release to coincide with the release of Gnome 2.10.0 Beta 1 (2.9.90). Thanks to Vincent Noel, Elijah Newren, and John Paul Wallington for fixes in this release. - Restore original stacking when aborting an alt-esc window switch operation (Elijah) [#123576] - Fix vertical maximization for second screen (John) [#163420] - Show labels in bold for windows that demand attention (Vincent) [#164590] - In the tab task switcher popup, dim the window icon and put its name between brackets when the window is minimized (Vincent) [#136666] - Correct highlighting of windows in workspace switcher popup (Elijah) [#163450] Translations zh_CN (Funda Wang), nb (Kjartan Maraas), nn (Kjartan Maraas), de (Frank Arnold) 2.9.3 == This is an unstable release to coincide with the release of Gnome 2.9.4. Thanks to Leena Gunda, Thomas Fitzsimmons, and mild7 users sourceforge net, and Elijah Newren for fixes in this release. - Don't focus the panel on click (Elijah) [#160470, and others] - Make sure the save session dialog appears focused (Elijah) [#162983] - Correctly restore size of window when double clicking the titlebar to unmaximize (Leena) [#161236] - Install schema data from builddir not srcdir (Thomas) [#161417] - Provide more documentation to make it easier for people to contribute to Metacity (Elijah) [#162646] - Allow users to move the window around immediately after double-clicking to shade (Elijah) [#90290] - Focus windows that manually position themselves too (Elijah) [#107347] - Don't show window menu if all options are invalid (Elijah) [#148915] - Exclude windows with skip_taskbar hint set from the alt-tab list; they'll appear in the ctrl-alt-tab list instead. (mild7 users sourceforge net) [#106249] - Wrap XSetInputFocus to make display->expected_focus_window more reliable (Elijah) [#154598] - Remove conflict between windows on multiple workspaces and hidden being a global quantity (Elijah) [#156182] Translations es (Francisco Javier F. Serrador), sv (Christian Rose), cs (Miloslav Trmac), ja (Takeshi AIHANA) 2.9.2 == This is an unstable release to coincide with the release of Gnome 2.9.3. Thanks to Alex Duggan, ash AT contact bg, Elijah Newren, and Baptiste Mille-Mathias for fixes in this release. - Add a missing period at the end of a sentence (Baptiste) [#158210] - When snap-moving don't snap to hidden windows, such as transients of minimized windows (Elijah) [#157180] - Focus the desktop when showing it (Elijah) [#159257] - Remove deprecated capplet (Alex, ash) [#160753] Translations da (Martin Willemoes Hansen), bg (Alexander Shopov), en_CA (Adam Weinberger) 2.9.1 == This is an unstable release heading towards Gnome 2.10, released a little late for Gnome 2.9.2 but there weren't many changes anyway this time... Thanks to Benjamin Kahn, Marco Pesenti Gritti, James Henstridge, and Vincent Untz for fixes/features in this release. - gnome-panel-screenshot was renamed to gnome-screenshot (Vincent) [#157529] - Update build stuff (use newer automake, etc.) (James) - Fix build out of src directory (Marco) [#158325] - Use a better default application icon (Benjamin) [#160373] Translations da (Martin Willemoes Hansen), fr(Christophe Merlet, Baptiste Mille-Mathias), lt(Žygimantas Berucka), ja(Takeshi AIHANA) 2.9.0 == This is an unstable release heading towards Gnome 2.10. Thanks to Rob Adams, Anders Carlsson, Elijah Newren, Soeren Sandmann, and Vincent Untz for fixes and features in this release. - Add a keybinding to launch a terminal (Vincent) [#154232] - Correct the requested number of keycodes (Rob) [#155247] - Add tracker bugs to rationales.txt file - Make the "showing desktop" mode be per-workspace instead of per-screen. (Elijah) [#142198] - Don't try to use an ARGB visual at all if the depth isn't 32-bit. This caused major slowdowns with Composite enabled. (Anders) - Fix the modifier key breakage introduced by an Xorg change. (Soeren) [#151554] - Update _NET_WM_STATE_HIDDEN so the pager on the panel will know whether to display windows as visible or hidden (Elijah) [#105665] - Fix the alt-tab order--if the most recently used window is not focused, start alt tabbing with that window instead of the one after it (Elijah) [#156251] - Don't lower newly mapped windows when they're denied focus if they are transients of the focused window. Instead, defocus the currently focused window (Elijah) [#151996] - Re-enable focus stealing prevention (Elijah) Translations es(Francisco Javier F. Serrador), sq(Laurent Dhima), sr(Danilo Šegan), cs(Miloslav Trmac), en_CA(Adam Weinberger), en_GB(David Lodge) 2.8.6 == This is a stable release for Gnome 2.8.1. Thanks to the Ken Harris, Kjartan Maraas, and the tireless efforts of Elijah Newren for fixes in this release. Fixes * Ensure the correct window is focused when minimizing (Elijah) * Fix keynav with mouse focus (Elijah) * Fix several race conditions in window focusing (Elijah) * Focus the top window when lowering by frame click (Ken) * Fix some compiler warnings (Kjartan) * Fix some valgrind-reported errors (Elijah) * Fix some potential issues with autoraising windows (Elijah) Translations * en_CA(Adam Weinberger), it(Luca Ferretti) 2.8.5 == This is a stable release for Gnome 2.8. Only translations and some new developer documentation were added since the last unstable release. This release boasts improved standards-compliance and a number of bug fixes since the last stable release. Translations * ar(Abdulaziz Al-Arfaj), cs(Miloslav Trmac), cy(Dafydd Harries), en_GB(David Lodge), fr(Christophe Merlet (RedFox)), nn(Åsmund Skjæveland), or(Gora Mohanty), pr_BR(Gustavo Noronha Silva), ro(Mugurel Tudor), th(Paisa Seeluangsawat), tr(Baris Cicek), zh_TW(Woodman Tuen) 2.8.4 == This release features a number of bug fixes, and also the disabling of the focus-stealing-prevention code (we're entering hard code freeze in Gnome so it's too late to fix the remaining issues, especially since it requires several patches to modules other than Metacity). Thanks to Havoc Pennington, Soeren Sandmann, Elijah Newren, and Rich Wareham for fixes in this release Fixes * track the last_xor_rect, for wireframe painting (Havoc) * Move wireframe code before grab is released to prevent endless loops with fullscreen windows. (Soeren) * Make dialogs that Metacity shows follow focus-stealing-prevention conventions. (Elijah; part of #149028) * add render extension check to the display, don't build the compositing manager by default, use an ARGB visual when available for the window frame (Rich Wareham; various tweaks added later by Havoc) * move the have_xrender variable initialization up in the file since it can be set as part of composite check (Havoc) * make argb stuff compile, add some code from xcompmgr (Havoc) * fix an assertion failure that would occur after increasing the number of workspaces; fix stacking order when a window is denied focus (Elijah; #150615) * disable some compositor code that wasn't working, don't grab the server during repaint, various set_background fixes and refactoring (Havoc) Translations * az(Metin Amiroff), bs(Kemal Sanjta), ca(Jordi Mallach), el(Kostas Papadimas), es(Francisco Javier F. Serrador), eu(Iñaki Larrañaga Murgoitio), fi(Pauli Virtanen), nb(Kjartan Maraas), sq(Laurent Dhima), uk(Maxim Dziumanenko) 2.8.3 == Some important bug fixes in this release, including somy a11y bugs, and a compile issue on Solaris. Thanks to Rob Adams, Bill Haneman, Peter O'Shea, Mike Castle, Soeren Sandman, Elijah Newren, and Havoc Pennington for fixes in this release. Fixes * Adjust the MRU list when preventing focus stealing (Elijah) * Ensure that we maintain a focus window when switching workspaces in mouse focus mode (Elijah) * Some improvements in the showing desktop mode, and window activation (Elijah) * Make sure cursors changes are handled correctly (Havoc, Soeren) * Some fixes to the window menu (Rob) * Fix a compile issue on Solaris (Peter, Mike) * Allow struts to go past the middle of the screen, provided there's a gap between them, fixing an issue with gnome magnifier (Bill) Translations * fi (Pauli Virtanen), ja (Takeshi AIHANA), ko (Young-Ho, Cha), pl (Gnome PL Team), ru (Dmitry G. Mastrukov), sr (Danilo Šegan), tk (Gurban M. Tewekgeli), zh_CN (Funda Wang) 2.8.2 === Many bugfixes and better support for the freedesktop.org EWMH spec. Thanks to Rob Adams, Anders Carlsson, Elijah Newren, Soeren Sandmann, Emil Soleyman-Zomalan, Michael Terry, and Jeff Waugh for fixes in this release. - set titlebar_uses_system_font = false (it was ugly) - make naming for "move a window"/"move the window"/"move window" more consistent (fixes #142235) - Add trailing quotes to keybinding explanation text. - support for EWMH update counter spec & add compensation events when events are ignored. (fixes #143333 and #109362) - Fix focus bugs: remove race condition on window close/minimize (#131582), make focus choice consistent for each focus mode (#135810), choose correct focus window when "un-showing the desktop (#144900), make sure correct window is focused when using the workspace switcher (#120100). - Use meta_topic instead of meta_warning when failing to connect to a session manager; reduces metacity verbosity. (fixes #136218) - Make meta_window_delete take a timestamp, and be sure to pass it one. - Add support for EWMH _NET_WM_USER_TIME spec. This enables part of preventing focus stealing. (bug #118372) Also fix bug with windows not being focused on unminimizing caused by original patch. (also bug #118372) - Fix some support for EWMH hints, and fix USER_TIME support to include the DEMANDS_ATTENTION hint. Also includes some code for implementing _NET_RESTACK_WINDOW and _NET_MOVERESIZE_WINDOW, but this is disabled pending feature thaw. 2.8.1 === Thanks to Olivier Crete, Jarrod Johnson, Neil Muller, Elijah Newren, Mark McLoughlin, Rob Adams, and foser AT gentoo.org for fixes in this release. - make the --enable-xinerama switch work properly - prevent unwanted grab op from occurring - don't down-size nitems from a gulong to an int - add a value type check for the visual/audible bell gconf settings - make the no sm support warning resizable - more translations 2.8.0 === No code changes in this release, but some new translations. 2.7.1 === Thanks to Rob Adams for fixes in this release. - bug #122016 - fix a focus race - Change move_to_workspace_left/right/up/down keybindings to arrow to avoid conflicting with new keybindings in spacial nautilus. - fix dialog stacking order issues so e.g. panel properties dialog is above the panel 2.7.0 === First unstable release tarball for GNOME 2.6. Thanks to Anders Carlsson, Elijah Newren, Rob Adams, James Cape, Thomas Fitzimmons, Calum Benson for fixes in this release. 2.6.2 === Thanks to Yukihiro Nakai, Rached Ben Mustapha, Gwenole Beauchesne, Padraig O'Briain, Laurent Vivier, Rob Adams for contributions to this release. - fix to repaint after resize always, so on maximize and theme changes we get things drawn properly - fix a compile issue on HPUX - fix translations of metacity-message output - fix to update window icons when they change - put a limit on number of characters displayed in window titles during Alt+tab - fix configure check for Xrandr - fix 64-bit bug in property reading that broke things badly on 64-bit - don't move focus when clicking close button on a window - fix a crash in getting pixmap icons - spawn dialogs and child processes on the proper screen in multihead situations - if the focus gets set to None, set it back to something sane - load accessibility modules and set accessibility roles - fix hang after displaying warning dialogs - fix a memory corruption when sticking/unsticking windows that lead to a frequent crash and windows appearing in Alt+tab improperly - fix some handling of partial-width panel struts - more translations 2.6.1 === - rebuild with fixed glib-gettext.m4 2.6.0 === - some additional translations 2.5.5 === Thanks to Rob Adams, Arvind Samptur, Andreas Volz, Ray Strode, John Paul Wallington, Soeren Sandmann for contributions to this release. And as always thanks to the translators. - fix aspect ratio handling - fix "shake loose" functionality for maximized windows - handle Xrandr size changes properly again - fix fullscreen window detection - fix workspace name handling - don't steal button press events on root window - nuke metacity.spec due to nonmaintenance - allow too-large-for-screen windows to move their titlebar offscreen - keep an MRU list of windows per-workspace and use it to focus the next window when the focused window disappears - fix cursor when moving - improve appearance of opaque resize - make BELOW window state work - fix a crash when gdk_pixmap_foreign_new() returned NULL 2.5.3 === Thanks to Jordi Mallach, Padraig O'Briain, Rob Adams, Julio Merino, Ben Jansens, Jurg Billeter, Ray Strode, marcus@freebsd.org, James Laska, for contributions to this release. Thanks also to all the tireless translators. - fixups to .desktop file - activate window prior to grab end, avoiding extra focus events - add support for partial-width panels (fixes corner panel and xinerama window position constraints) - added keybinding to toggle window as "always on top" - support --disable-schemas-install option to configure - destroy support for legacy GNOME 1.x hints; metacity no longer works with GNOME 1.x - disable raise-on-click for mouse focus modes - fix bug that broke many Javascript popup menus with mozilla - allow "shaking loose" maximized windows, to move them between Xinerama heads or whatever - honor desktop-wide double click timeout - handle window placement properly for windows that start out maximized - integrate Ximian patch to go ahead and log out after 4 minutes even if a dialog is open - fix a segfault - fix bug where window groups weren't always kept up to date - fix bug where focus got confused when switching workspaces with mouse focus mode - fix 64-bit crash on s390x - chdir to user's homedir on startup - keep window in fullscreen layer when its transients are focused - fix keybindings bug when you had ScrollLock enabled - many translation updates 2.5.2 === Thanks to David Santiago, Julien Olivier, Anders Carlsson, Rob Adams for fixes in this release. - improved wording/UI for some dialogs - while clicking a window button, if you move the mouse outside the button such that releasing the mouse button won't activate the window button, visually indicate by "popping out" the button. - fix some valgrind errors - change "show desktop mode" to convert to "everything is minimized mode" if you open a new window while showing desktop, rather than previous behavior of simply leaving show desktop mode. - fix a trivial memory leak - change "move to workspace N" so it doesn't switch workspaces, just moves the window. - translation updates 2.5.1 === Thanks to Rob Adams, Peter O'Shea, Dafydd Harries, Masahiro Sakai, Soeren Sandmann for fixes in this release. - fix bug where fullscreen windows were below top panels - build fix for Solaris - support diagonal window movement with numeric keypad - multihead fix - build fix for Cygwin - place on xinerama containing the pointer - fix totally hosed window placement/movement for frameless windows - improvement to smoothness of window move/resize 2.5.0 === Thanks to Rob Adams, Owen Taylor, Frederic Crozat, Arvind Samptur, Bill Haneman, Akira Tagoh for help with fixes in this release. - many new translations - fix an infinite loop while holding a server grab triggered by some recent Qt versions doing weird stuff - fix bug where Alt+rightclick repeatedly on titlebar resulted in zillions of menus - fix Alt+Tab to *actually* put minimized windows at the end, though this was always intended - rewrite size/positions constraint code (currently known to be quite buggy, e.g. xmms is hosed) - enforce size of at least 1x1 on windows - reduce latency of managing new windows still further by using async properties code in more places - don't grab keybindings on docks, so gnome-panel can handle them - suck in the panel's screenshot and run dialog global bindings - lots of improvements to window placement - sync max number of workspaces with pager applet - fix to keep focus when inside window frame in strict mouse focus mode - make it possible to start a reverse tab with shift+alt+tab (vs. alt+tab then shift) - fix a multihead issue with constraints between two windows on different heads - require GTK+ 2.2.0 and fontconfig - default theme is now Simple - add visual bell feature - incorporate many fixes from 2.4.34 - other stuff 2.4.13 === - we were making all dialogs skip the taskbar, even non-transient ones, though this was supposedly fixed a while ago. Now really fixed. - change back to Alt+click by default for the window drag feature. - assign Alt+F12 to shade window - fix not deleting enough workspaces when the number was reduced via the pager config dialog (readams@hmc.edu) - don't allow windows under the top panel ever, even if they are tall windows (Arvind) - fix up the window layout for directional workspace nav, so you always stop at the edges and always end up where you expect (hp, with tweaks from readams@hmc.edu) - focus new windows in mouse focus mode (readams@hmc.edu) - support xeyes, oclock, etc. by applying shape mask to the window manager frame (yeah it resizes slow, deal) - fix vertical/horizontal maximize - handle crossing events resizing for more opaque resize goodness (Soeren) - add wacky _METACITY_UPDATE_COUNTER experimental extension to do nice opaque resizing (does nothing without a GTK patch) - fix a crash setting workspace names - fix internationalized WM_NAME reading muffin-5.2.1/doc/0000775000175000017500000000000014211404421013701 5ustar jpeisachjpeisachmuffin-5.2.1/doc/code-overview.txt0000664000175000017500000001712014211404421017221 0ustar jpeisachjpeisachThis is not meant to be comprehensive by any means. Rather it is meant as just a brief overview of some of the bigger structures and files, with guides for a variety of task categories providing places to start looking in the code and things to look for. Overview Jobs of various files Major data structures and their relationships Getting started -- where to look Jobs of various files src/window.c is where all the guts of the window manager live. This is basically the only remotely scary file. src/frames.c is the GtkWidget that handles drawing window frames. src/core.h defines the interface used by the GTK portion of the window manager to talk to the other portions. There's some cruft in here that's unused, since nearly all window operations have moved out of this file so frameless apps can have window operations. src/ui.h defines the interface the plain Xlib portion of the window manager uses to talk to the GTK portion. src/theme.c and src/theme-parser.c have the theme system; this is well-modularized from the rest of the code, since the theme viewer app links to these files in addition to the WM itself. Major data structures and their relationships Major structs have a "Meta" prefix, thus MetaDisplay, MetaScreen, MetaWindow, etc. This serves as a way of namespacing in C. It also has the side effect of avoiding conflicts with common names that X already uses such as Display, Screen, Window, etc. Note that when I refer to a display below, I'm meaning a MetaDisplay and not a Display. Don't confuse displays and screens. While Metacity can run with multiple displays, it is kind of useless since you might as well just run two copies of Metacity. However, having multiple screens per display is useful and increasingly common (known as "multiscreen" and "xinerama" setups, where users make use of more than one monitor). You should basically think of a display as a combination of one or more monitors with a single keyboard (...and usually only one mouse). There is also a significant difference between multiscreen and xinerama as well. Basically, each MetaScreen is a root window (root node in the tree of windows). With Xinerama, a single root window appears to span multiple monitors, whereas with multiscreen a root window is confined to a single monitor. To re-emphasize the distinction between a display and a screen, the pointer and keyboard are shared between all root windows for a given display. The display keeps track of a lot of various global quantities, but in particular has a compositor and a list (GList) of screens. A compositor is an opaque structure (only defined in compositor.c), meaning that you'll only reference the API for it. It handles (or will handle) cool stuff with the new X extensions, such as smooth resizing and alpha transparency. A screen keeps track of a number of quantities as well, in particular a stack and a list of workspaces. A stack is basically a list of windows, and the depth order they have relative to each other (which thus determines which windows are on top and which are obscured). A workspace mostly contains a list of windows for the workspace, but also has a few other quantities as well (a list of struts which are areas where windows should not be placed and an mru_list or "most recently used window list"). A window has a huge list of quantities for keeping track of things about a window on the screen. (We want to avoid making this list larger because the memory for all these quantities is per window.) One item in particular that a window has, though, is a frame. A frame is the decorations that surround the window (i.e. the titlebar and the minimize and close buttons and the part that you can use to resize), and contains a handful of variables related to that, but no other major structures. Getting started -- where to look Getting started on developing free software projects can often be like being dropped off in a town that is unknown to you and being told to make a map, when various road and building signs are missing or fading. To try to alleviate that initial difficulty in orientation, below I list a variety of general task categories with file, function, variable, and x property names that may be useful to fixing bugs or writing features that fall within that category. First, though, it's useful to note that most event and message passing goes through display.c:event_callback(), so that's often a good place to start reading for general familiarity with the code (actually, I'd suggest skipping down to the first switch statement within that function). Of course, not all events go through that function, as there are a few other places that handle events too such as frames.c. Anyway, without further ado, here are the categories and (hopefully) useful things to look at for each: Focus issues (i.e. issues with which window is active): doc/how-to-get-focus-right.txt meta_workspace_focus_default_window _NET_ACTIVE_WINDOW _NET_WM_USER_TIME meta_window_focus meta_display_(set_input|focus_the_no)_focus_window XSetInputFocus (only for purposes of understanding how X focus/input works) CurrentTime (mostly, you should just think "Bad; don't use it") Compositor stuff (X extension for eye candy like transparency): compositor.c The luminocity module in CVS Window depth (i.e. stacking or lowering/raising) issues: stack.c _NET_CLIENT_LIST_STACKING transient_for WM_TRANSIENT_FOR meta_window_(raise|lower) _NET_WM_WINDOW_TYPE _NET_WM_MOUSE_ACTION/_NET_WM_TAKE_ACTIVITY? (aren't yet in EWMH) Window placement issues: place.c constraints.c _NET_WM_STRUT WM_SIZE_HINTS Moving and resizing issues: constraints.c update_move update_resize meta_window_handle_mouse_grab_op_event _NET_MOVERESIZE_WINDOW _NET_WM_STRUT Drag and drop issues: the XDND protocol (see http://www.newplanetsoftware.com/xdnd/ and http://freedesktop.org/Standards/XDND) _NET_WM_MOUSE_ACTION/_NET_WM_TAKE_ACTIVITY (aren't yet in EWMH) A general pointer: what causes the difficulty here is that when the application receives a mouse click to start a drag, it does a grab so that the window manager doesn't get any further events; thus correcting things require standards so that applications and window managers can collaborate correctly Theme issues: ??? doc/theme-format.txt theme.c theme-parser.c (ui.c, core.c, frames.c, frame.c? I dunno...) Session management issues: ??? session.c http://www.x.org/X11R6.8.1/doc/SM/xsmp.pdf ? http://www.x.org/X11R6.8.1/doc/SM/SMlib.pdf ? meta_window_apply_session_info Tasklist and Workspace switcher issues: window-props.c various functions in screen.c (especially ones using XChangeProperty) xprops.c The libwnck module in cvs meta_window_client_message Lots of the EWMH Window and workspace selection/changing issues: tabpopup.c keybindings.c, functions: *_workspace*, *_tab_* meta_screen_ensure_*_popup display.c, functions: *_tab* Key and mouse binding actions: keybindings.c meta_frames_button_(press|release)_event display.c: event_callback, but only the (Key|Button)_(Press|Release) cases Xinerama and multiscreen: ??? In general, just search for Xinerama, but in particular see screen.c window.c place.c constraints.c muffin-5.2.1/doc/Makefile.am0000664000175000017500000000016114211404421015733 0ustar jpeisachjpeisachSUBDIRS = man reference EXTRA_DIST=theme-format.txt dialogs.txt code-overview.txt \ how-to-get-focus-right.txt muffin-5.2.1/doc/theme-format.txt0000664000175000017500000003724714211404421017047 0ustar jpeisachjpeisachThemes are in a simple XML-subset format. There are multiple versions 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. As you might expect, older versions of metacity will not understand newer theme formats. However, newer versions will use old themes. Metacity will always use the newest theme format it understands that the X server supports. Some format versions are only supported if you have the right X server features. Each format *requires* the corresponding filename. If you put version 2 format features in the metacity-1/metacity-theme-1.xml file, then metacity will get angry. 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.4 ======================================== An additional color type is added to pick up custom colors defined in the GTK+ theme's CSS: gtk:custom(name,fallback) where refers to a custom color defined with @define-color in the GTK+ theme, and provides an alternative color definition in case the color referenced by is not found. 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 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 < and >). 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 ====================================== The optional attributes rounded_top_left, rounded_top_right, rounded_bottom_left and rounded_bottom_right on <frame_geometry> should now be the radius of the corner in pixels. You may still use the values "false" for 0 and "true" for 5, which means v1 values will still work just fine. <frame_geometry> has a new optional attribute, hide_buttons. If this is true, no buttons will be displayed on the titlebar. Anywhere you can use a positive integer, you can use an integer constant. As well as constant integers and reals, you may define constant colours, thus: <constant name="RevoltingPink" value="#FF00FF"/> <constant name="Background" value="gtk:bg[NORMAL]"/> <frame_style> has two new optional attributes, background and alpha. If you specify alpha, you must specify background. background is a colour used for the background of the frame. alpha is the transparency as a real between 0.0 and 1.0. If the current X server does not support alpha channels, the value is ignored. The filename attribute of <image> may begin with "theme:". If so, the rest of the string is the name of a theme icon. The 64x64 version of the icon is used, except for fallback mini_icons, which use the 16x16 version. This does not affect ordinary resizing. For example: <button function="close" state="normal"> <draw_ops> <include name="active_button"/> <image filename="theme:gnome-logout" x="2" y="2" width="width-4" height="height-4"/> <!-- Note: not "theme:gnome-logout.png" or similar. --> </draw_ops> </button> <menu_icon>s are parsed but ignored. Fallback icons can be specified using <fallback>. There are two optional arguments, icon and mini_icon. The values of these arguments are identical to that of the filename attribute of <image>. Fallback icons are used when a window does not supply its own icon. If a fallback icon is not specified with <fallback>, Metacity will use a built-in icon, as in metacity-theme-1. The <arc> element, as well as the original start_angle and end_angle attributes, may be given from and to attributes. The values of these attributes are given in degrees clockwise, with 0 being straight up. For example: <arc from="0.0" to="90.0" filled="true" color="#FF00FF" x="0" y="5" width="15" height="15"/> <frame state="shaded"> may now take an optional resize attribute, with the same interpretation as the resize attribute on <frame state="normal">. If this attribute is omitted for state="shaded", it defaults to "both". (If it is omitted for state="normal", it remains an error.) In addition to the four <button> functions which are required in metacity-theme-1, there are six new functions in metacity-theme-2: shade, unshade, above, unabove, stick and unstick. Overview of Theme Format Version 1 ================================== <?xml version="1.0"?> <metacity_theme> <!-- Only one info section is allowed --> <info> <name>Foo</name> <author>Foo P. Bar</author> <copyright>whoever, 2002</copyright> <date>Jan 31 2005</date> <description>A sentence about the theme.</description> </info> <!-- define a frame geometry to be referenced later --> <!-- frame_geometry has an optional has_title attribute which determines whether the title text height is included in the height calculation. if not specified, defaults to true. It also has an optional text_size="medium" attribute (same sizes as with Pango markup, xx-small thru medium thru xx-large) Finally it has optional args rounded_top_left=true, rounded_top_right=true, rounded_bottom_left=true, rounded_bottom_right=true. --> <frame_geometry name="normal" has_title="true" title_scale="medium"> <distance name="left_width" value="6"/> <distance name="right_width" value="6"/> <distance name="bottom_height" value="7"/> <distance name="left_titlebar_edge" value="6"/> <distance name="right_titlebar_edge" value="6"/> <distance name="button_width" value="17"/> <distance name="button_height" value="17"/> <!-- alternative to button_width button_height distances --> <aspect_ratio name="button" value="1.0"/> <distance name="title_vertical_pad" value="4"/> <border name="title_border" left="3" right="12" top="4" bottom="3"/> <border name="button_border" left="0" right="0" top="1" bottom="1"/> </frame_geometry> <!-- inheritance is allowed; simply overwrites values from parent --> <frame_geometry name="borderless" parent="normal"> <distance name="left_width" value="0"/> <distance name="right_width" value="0"/> <distance name="bottom_height" value="0"/> <distance name="left_titlebar_edge" value="0"/> <distance name="right_titlebar_edge" value="0"/> </frame_geometry> <!-- define a constant to use in positions/sizes of draw operations; constant names must start with a capital letter. --> <constant name="LineOffset" value="3"/> <!-- define drawing operations to be referenced later; these draw-op lists can also be placed inline. Positions/lengths are given as expressions. Operators are: +,-,*,/,%,`max`,`min` All operators are infix including `max` and `min`, i.e. "2 `max` 5" Some variables are predefined, and constants can also be used. Variables are: width - width of target area height - height of target area object_width - natural width of object being drawn object_height - natural height of object being drawn left_width - distance from left of frame to client window right_width - distance from right of frame to client window top_height - distance from top of frame to client window bottom_height - distance from bottom of frame to client window mini_icon_width - width of mini icon for window mini_icon_height - height of mini icon icon_width - width of large icon icon_height - height of large icon title_width - width of title text title_height - height of title text All these are always defined, except object_width/object_height which only exists for <image> right now. --> <draw_ops name="demo_all_ops"> <line color="#00FF00" x1="LineOffset" y1="0" x2="0" y2="height"/> <line color="gtk:fg[NORMAL]" x1="width - 1" y1="0" x2="width - 1" y2="height" width="3" dash_on_length="2" dash_off_length="3"/> <rectangle color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL]/0.7" x="0" y="0" width="width - 1" height="height - 1" filled="true"/> <arc color="dark gray" x="0" y="0" width="width - 1" height="height - 1" filled="false" start_angle="30" extent_angle="180"/> <tint color="orange" alpha="0.5" x="0" y="0" width="width" height="height"/> <!-- may be vertical, horizontal, diagonal --> <gradient type="diagonal" x="10" y="30" width="width / 3" height="height / 4"> <!-- any number of colors allowed here. A color can be a color name like "blue" (look at gcolorsel), a hex color as in HTML (#FFBB99), or a color from the gtk theme given as "gtk:base[NORMAL]", "gtk:fg[ACTIVE]", etc. --> <color value="gtk:fg[SELECTED]"/> <!-- color obtained by a 0.5 alpha composite of the second color onto the first --> <color value="blend/gtk:bg[SELECTED]/gtk:fg[SELECTED]/0.5"/> </gradient> <!-- image has an optional colorize="#color" attribute to give the image a certain color --> <image filename="foo.png" alpha="0.7" x="10" y="30" width="width / 3" height="height / 4"/> <gtk_arrow state="normal" shadow="in" arrow="up" filled="true" x="2" y="2" width="width - 4" height="height - 4"/> <gtk_box state="normal" shadow="out" x="2" y="2" width="width - 4" height="height - 4"/> <gtk_vline state="normal" x="2" y1="0" y2="height"/> <!-- window's icon --> <icon alpha="0.7" x="10" y="30" width="width / 3" height="height / 4"/> <!-- window's title --> <title color="gtk:text[NORMAL]" x="20" y="30"/> <!-- include another draw ops list; has optional x/y/width/height attrs --> <include name="some_other_draw_ops"/> <!-- tile another draw ops list; has optional x/y/width/height/tile_xoffset/tile_yoffset --> <tile name="some_other_draw_ops" tile_width="10" tile_height="10"/> </draw_ops> <frame_style name="normal" geometry="normal"> <!-- How to draw each piece of the frame. For each piece, a draw_ops can be given inline or referenced by name. If a piece is omitted, then nothing will be drawn for that piece. For each piece, the "width" and "height" variables in coordinate expressions refers to the dimensions of the piece, the origin is at the top left of the piece. So <rectangle x="0" y="0" width="width-1" height="height-1"/> will outline a piece. --> <piece position="entire_background" draw_ops="demo_all_ops"/> <piece position="left_titlebar_edge"> <draw_ops> <line color="#00FF00" x1="0" y1="0" x2="0" y2="height"/> </draw_ops> </piece> <!-- The complete list of frame pieces: entire_background: whole frame titlebar: entire area above the app's window titlebar_middle: area of titlebar_background not considered part of an edge left_titlebar_edge: left side of titlebar background right_titlebar_edge: right side of titlebar background top_titlebar_edge: top side of titlebar background bottom_titlebar_edge: bottom side of titlebar background title: the title area (doesn't include buttons) left_edge: left edge of the frame right_edge: right edge of the frame bottom_edge: bottom edge of the frame overlay: same area as entire_background, but drawn after drawing all sub-pieces instead of before --> <!-- For buttons, drawing methods have to be provided for each of three states: normal, pressed, prelight and the button function or position must be provided: close, maximize, minimize, menu, left_left_background, left_middle_background, left_right_background, right_left_background, right_middle_background, right_right_background So a working theme needs 3*4 = 12 button declarations and a theme may have up to 3*10 = 30 button declarations in order to handle button-rearrangement preferences. (The name "function" for the attribute is from before the background values existed.) --> <button function="close" state="normal" draw_ops="previously_named"/> <button function="menu" state="normal"> <draw_ops> <icon alpha="0.7" x="0" y="0" width="object_width" height="object_height"/> </draw_ops> </button> </frame_style> <!-- styles can inherit from each other with the parent="" attribute. In a subclass anything can be re-specified to override the parent style. --> <frame_style name="focused" parent="normal"> <piece position="title"> <draw_ops> <rectangle color="gtk:bg[SELECTED]" x="0" y="0" width="width-1" height="height-1"/> <title color="gtk:fg[SELECTED]" x="(width - title_width) / 2" y="(height - title_height) / 2"/> </draw_ops> </piece> </frame_style> <!-- Maps styles to states of frame. Focus: yes (focused), no (not focused) Window states: normal, maximized, shaded, maximized_and_shaded Window resizability: none, vertical, horizontal, both Everything unspecified just does the same as unfocused/normal/both. only state="normal" needs a resize="" attribute. --> <frame_style_set name="normal"> <frame focus="yes" state="normal" resize="both" style="focused"/> <frame focus="no" state="normal" resize="both" style="normal"/> </frame_style_set> <!-- Each window type needs a style set Types: normal, dialog, modal_dialog, menu, utility, border --> <window type="normal" style_set="normal"/> <!-- For menu icons, drawing methods are needed for the same four types as the buttons, and GTK states (insensitive,prelight,normal,etc.) --> <menu_icon function="close" state="normal" draw_ops="previously_named"/> </metacity_theme> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/doc/dialogs.txt������������������������������������������������������������������������0000664�0001750�0001750�00000001526�14211404421�016070� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Dialogs which have no transient parent or root window being their tranisent parent are the ones which will be visible in the tasklist. All such dialogs will be *always* on top of the window group i.e they would transients for the whole group. 1) Modal dialogs * If you wish to open another window from a modal dialog open *only* a modal dialog and set it's transient parent. 2) Normal dialog without transient parent * If you wish to open another window from a normal dialog open either a normal dialog or a modal dialog only. Set the transient parent for the child dialog if you do not want them to be transient for all the other windows in the group. with transient parent * If you wish to open another window from a normal dialog you could open any type of window. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/doc/how-to-get-focus-right.txt���������������������������������������������������������0000664�0001750�0001750�00000034140�14211404421�020666� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������To make choice of focus window consistent for each focus method, a number of guidelines should be followed. (For purposes of discussion here, I'm excluding things like the panel and the desktop from "windows". It is technically incorrect to do this, but I'm lazy and "windows" is shorter than something like "normal windows". See the end of the discussion for how these special cases are handled.) The basics are easy: Focus method Behavior click When a user clicks on a window, focus it sloppy When an EnterNotify is received, focus the window mouse Same as sloppy, but also defocus when mouse enters DESKTOP window Note that these choices (along with the choice that clicking on a window raises it for the click focus method) introduces the following invariants for focus from mouse activity: Focus method Invariant click The window on top is focused sloppy If the mouse is in a window, then it is focused; if the mouse is not in a window, then the most recently used window is focused. mouse If the mouse is in a non-DESKTOP window, then it is focused; otherwise, the designated "no_focus_window" is focused However, there are a number of cases where the current focus window becomes invalid and another should be chosen. Some examples are when a focused window is closed or minimized, or when the user changes workspaces. In these cases, there needs to be a rule consistent with the above about the new window to choose. Focus method Behavior click Focus the window on top sloppy Focus the window containing the pointer if there is such a window, otherwise focus the most recently used window. mouse Focus the non-DESKTOP window containing the pointer if there is one, otherwise focus the designated "no_focus_window". Note that "most recently used window", as used here, has a slightly different connotation than "most recent to have keyboard focus". This is because when a user activates a window that is a transient, its ancestor(s) should be considered to be more recently used than other windows that have had the keyboard focus more recently. (See bug 157360; this may mean that the alt-tab order should also change simultaneously, although the current implementation does not do that.) Also, sometimes a new window will be mapped (e.g. unminimizing a window or launching a new application). Most users want to interact with new windows right away, so these should typically be focused. This does conflict with the invariants for sloppy and mouse focus modes, so this wouldn't be true for a strict-pointer-focus mode. For all other modes (non-strict-pointer-focus modes), there are only two cases in which a new window shouldn't be focused: 1) If the window takes a while to launch and the user starts interacting with a different application, the new window should not take focus. 2) If the window that will appear was not launched by the user (error dialogs, instant messaging windows, etc.), then the window should not take focus when it appears. To handle these cases, Metacity compares timestamps of the event that caused the launch and the timestamp of the last interaction with the focused window. (Case 2 is handled by the application providing a special timestamp of 0 for the launch time, which ensures that the window that appears doesn't get focus) If the newly launched window isn't focused, some things should be done to alert the user that there is a window to work with: 1) The _NET_WM_DEMANDS_ATTENTION hint should be set 2) If the new window isn't modal for the focused window, it should appear below the focused window so that it doesn't obscure the focused window that the user is interacting with. 3) If the new window is modal to the focused window, the currently focused window should lose focus but the modal window should appear on top. Additionally, the user may decide to use the keyboard instead of the mouse to navigate between windows (referred to as "keynav"). This poses no problems for click-to-focus (because the same invariant can be maintained), but for sloppy and mouse focus it requires extra work to attempt to handle the INHERENTLY CONFLICTING CONSTRAINTS. Metacity does this by having a mouse_mode boolean used to determine which of the two sets of invariants holds. This mode is set according to which method was most recently used to choose a focus window: 1) When receiving EnterNotify events from mouse movement, set mouse_mode to TRUE. 2) When using keynav to choose a focus window (e.g. alt-tab, alt-esc, alt-f2, move-window-to-workspace keybindings), set mouse_mode to FALSE. 3) When handling events that don't choose a focus window but rather need a focus_window chosen for them (e.g. switch-to-workspace keybindings), don't change the mouse_mode and just use the current value. Note that grabs present a special case since they can generate EnterNotify and LeaveNotify events without using the mouse, thus these events should be ignored when the crossing mode is NotifyGrab or NotifyUngrab. THIS MOUSENAV/KEYNAV MODERATION METHOD IS NOT PERFECT--there are corner cases when trying to mix-and-match between mousenav and keynav simultaneously that cause problems; but it appears to be the most reasonable tradeoff and works well in most cases, especially if the user sticks to just mousenav for a long time or just keynav for a long time. Finally, windows of type WM_DOCK or WM_DESKTOP (e.g. the desktop and the panel) present a special case, at least partially due to the lack of decorations. For WM_DESKTOP windows, we only focus them if the user explicitly requests it (e.g. clicks on the window, uses Ctrl-Alt-Tab to navigate to it, uses a keybinding to show the desktop, etc.). For WM_DOCK windows, we do not focus unless we receive a very explicit request (e.g. Ctrl-Alt-Tab or a _NET_ACTIVE_WINDOW message; not normal clicks). To read more about the bugs that inspired these choices: - When a focused window becomes invalid and another should be chosen http://bugzilla.gnome.org/show_bug.cgi?id=135810 - When a new window is mapped http://bugzilla.gnome.org/show_bug.cgi?id=118372 Also, the EWMH spec, especially the parts relating to _NET_WM_USER_TIME - Modal vs. non-modal dialogs that get denied focus when mapped http://bugzilla.gnome.org/show_bug.cgi?id=151996 - Mousenav vs. Keynav in mouse and sloppy focus modes http://bugzilla.gnome.org/show_bug.cgi?id=167545 http://bugzilla.gnome.org/show_bug.cgi?id=101190 http://bugzilla.gnome.org/show_bug.cgi?id=357695 - Not focusing panels http://bugzilla.gnome.org/show_bug.cgi?id=160470 http://bugzilla.gnome.org/show_bug.cgi?id=120100 There were many bugs which had to be fixed to get all the above working; they helped form these policies and/or show the difficulties in implementing this policy (my apologies in advance for producing a list heavily lopsided to what I've done; it's just that these bugs are the ones I'm the most familiar with): bug 72314 ignore LeaveNotify events from grabs bug 82921 focus windows on map bug 87531 only show focus for sticky windows on active workspace (pager) bug 94545 focus window on workspace switch is non-deterministic bug 95747 should ignore EnterNotify events with NotifyInferior detail set bug 97635 sticky windows always keep focus when switching workspaces bug 102665 a window unminimized from the tasklist should be focused bug 107347 focus windows that manually position themselves too bug 108643 focus in MRU order instead of stack order bug 110970 moving a window to another workspace loses focus bug 112031 closing a dialog can result in a strange focus window bug 115650 add _NET_WM_USER_TIME support to gtk+ (see also 150502) bug 120100 panel shouldn't be focused after workspace applet usage bug 123803 need final EnterNotify after workspace switch (see also 124798) bug 124981 focus clicked window in pager only if on current workspace bug 125492 catch the xserver unfocusing everything and fix its braindeadedness bug 128200 focus correct window on libwnck window minimize (see 107681 too) bug 131582 fix race condition on window minimize/close bug 133120 wrong window focused when changing workspaces bug 135024 _NET_ACTIVE_WINDOW messages need timestamps bug 135786 middle-clicking on focused window to lower it should defocus too bug 136581 window minimization vs. activation for mouse focus bug 144900 fix focus choice on "un-showing" the desktop bug 147475 don't lock keyboard on workspace change bug 148364 DEMANDS_ATTENTION support for metacity & libwnck (and other stuff) bug 149028 focus-stealing-prevention for metacity-dialog (and other stuff) bug 149366 windows denied focus on map occur in wrong order in alt-tab list bug 149543 consistent focus window when unshowing desktop bug 149589 race in focus choice from libwnck messages bug 150271 make sure "run application" dialog gets focused bug 150668 update gtk+ _NET_ACTIVE_WINDOW support bug 151245 application startup notification forwarding (partially rejected) bug 151984 Soeren's idea--backup timestamp when startup notification not used bug 151990 prevent focus inconsistencies by only providing one focus method bug 151996 modal dialogs denied focus should not be lowered bug 152000 fix race on window close followed by rapid mouse movement bug 152004 ways to handle new window versus mouse invariants bug 153220 catch the root window getting focus and reset to default window bug 157360 focus parents of dismissed transient windows in preference to the window that most recently had focus bug 159257 focus the desktop when showing it bug 160470 don't focus panels on click bug 163450 correct highlighting in workspace switcher popup bug 164716 refuse to focus a window with a modal transient, and focus the transient instead bug 166524 avoid new windows being obscured by the focus window bug 167545 mousenav vs. keynav in mouse and sloppy focus modes <a massive heap of bugs relating to focus stealing prevention...> Addendum on sloppy and mouse focus You may occasionally hear people refer to sloppy or mouse focus modes as inherently buggy. This is what they mean by that: 1) Keynav doesn't maintain the same invariants as mouse navigation for these focus modes; switching back and forth between navigation methods, therefore, may have or appear to have inconsistencies. Examples: a) If the user uses Alt-Tab to change the window with focus, then starts to move the mouse, at that moment the window where the mouse is does not have focus. b) Users expect that a workspace they previously used will not change when the return to it. This means things like window position and stacking order, but also the focus window. Unfortunately, using the original focus window (which would be the most recently used window on that workspace) will sometimes conflict with the invariants for mouse and sloppy focus modes. Users are much more surprised by the invariant being broken than by having the focus window changed (see bug 94545 and probably others), so we maintain the invariant. This only matters when using Ctrl-Alt-Arrow to switch workspaces instead of clicking in the workspace switcher, so this really is a keynav vs mouse issue. Either that, or a windows-are-being-mapped exception. ;-) c) Opening a menu, then moving the mouse to a different window, and then pressing escape to dismiss the menu will result in the window containing the mouse not being focused. This is actually correct behavior (because pressing escape shows that the user is using key navigation to interact with the window containing the menu) but is one of those hard-to-get-right keynav and mouse focus mixture cases. (See bug 101190 for more details) d) Similar to (c), moving the mouse off the menu doesn't immediately focus the window that the mouse goes over, due to an application grab (we couldn't change this and wouldn't want to, but technically it does break the invariant). e) If mouse_mode is off and the user does something to cause focus to change (e.g. switch workspaces, close or minimize a window, etc.) and simultaneously tries to move the mouse, the choice of which window to focus is inherently race-y. (You probably can't satisfy both keynav and mousenav invariants simultaneously...) 2) The sloppy/mouse invariants are often not strictly maintained; for example, we provide an exception to the invariant for newly mapped windows. (Most find that not allowing this exception is confusing) 3) There are an awful lot of little cases to handle to get any focus mode right, even for click-to-focus. Since mouse and sloppy focus have sometimes been hard to even determine what correct behavior is, it is much harder to get them completely right. Plus mouse and sloppy focus users are a minority, decreasing the motivation of window manager implementors to get those focus modes right. 4) Because of -1-, -2-, and -3-, implementations are often buggy or inconsistent and people form their opinions from usage of these implementations. 5) Sloppy focus suffers from a bit of a discoverability problem (for example, I have seen a scientist sit down to a computer for which sloppy focus was in use and take a few minutes before figuring out how window activation worked; granted the layout of the windows in that situation was a bit unusual but it still illustrates that sloppy focus is harder than it should be to figure out). Mouse focus solves this problem; however, people that have experience with other computing environments are accustomed to being able to move their mouse outside the window they are working with and still continue interacting with that window, which conflicts with mouse focus. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/doc/reference/�������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�015637� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/doc/reference/Makefile.am��������������������������������������������������������������0000664�0001750�0001750�00000000071�14211404421�017671� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SUBDIRS = muffin if CLUTTER_DOC SUBDIRS += clutter endif�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/doc/reference/muffin-docs.sgml���������������������������������������������������������0000664�0001750�0001750�00000003642�14211404421�020742� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [ <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'"> <!ENTITY version "3.8.2"> ]> <book id="index"> <bookinfo> <title>Muffin Reference Manual This document is for Muffin &version;. Muffin Core Reference Object Hierarchy API Index Index of deprecated API muffin-5.2.1/doc/reference/running-muffin.xml0000664000175000017500000000660114211404421021326 0ustar jpeisachjpeisach Running Muffin
Environment Variables Muffin automatically checks environment variables during its initialization. These environment variables are meant as debug tools or overrides for default behaviours: MUFFIN_VERBOSE Enable verbose mode, in which more information is printed to the console. Muffin needs to be built with the --enable-verbose-mode option (enabled by default). For more fine-grained control of the output, see meta_add_verbose_topic(). MUFFIN_DEBUG Traps and prints X errors to the console. MUFFIN_G_FATAL_WARNINGS Causes any logging from the domains Muffin, Gtk, Gdk, Pango or GLib to terminate the process (only when using the log functions in GLib). MUFFIN_USE_LOGFILE Log all messages to a temporary file. MUFFIN_DEBUG_XINERAMA Log extra information about support of the XINERAMA extension. MUFFIN_DEBUG_SM Log extra information about session management. MUFFIN_DEBUG_BUTTON_GRABS Log extra information about button grabs. MUFFIN_SYNC Call XSync after each X call. MUFFIN_DISPLAY Name of the X11 display to use. META_DISABLE_MIPMAPS Disable use of mipmaps for the textures that back window pixmaps. MUFFIN_USE_STATIC_GRAVITY Enable support for clients with static bit-gravity. MUFFIN_WM_CLASS_FILTER Comma-separated list of WM_CLASS names to which to restrict Muffin to. MUFFIN_DISABLE_FALLBACK_COLOR Disable fallback for themed colors, for easier detection of typographical errors.
muffin-5.2.1/doc/reference/muffin-overview.xml0000664000175000017500000000114014211404421021505 0ustar jpeisachjpeisach Overview Muffin is a GObject-based library for creating compositing window managers. Compositors that wish to use Mutter must implement a subclass of #MetaPlugin and register it with meta_plugin_manager_set_plugin_type() before calling meta_init() but after g_type_init(). #MetaPlugin provides virtual functions that allow to override default behavior in the window management code, such as the effect to perform when a window is created or when switching workspaces. muffin-5.2.1/doc/reference/muffin-docs.sgml.in0000664000175000017500000000364614211404421021353 0ustar jpeisachjpeisach ]> Muffin Reference Manual This document is for Muffin &version;. Muffin Core Reference Object Hierarchy API Index Index of deprecated API muffin-5.2.1/doc/reference/clutter/0000775000175000017500000000000014211404421017321 5ustar jpeisachjpeisachmuffin-5.2.1/doc/reference/clutter/running-clutter.xml0000664000175000017500000003724114211404421023212 0ustar jpeisachjpeisach Emmanuele Bassi
ebassi@linux.intel.com
Running Clutter
Environment Variables Clutter automatically checks environment variables during its initialization. These environment variables are meant as debug tools, overrides for default behaviours or to address known hardware issues: CLUTTER_BACKEND Changes the windowing system backend used by Clutter. The allowed values for this environment variable depend on the configuration options used when compiling Clutter. The available values are: x11, for the X11 backend wayland, for the Wayland backend win32, for the Windows backend osx, for the MacOS X backend gdk, for the GDK backend eglnative, for the EGL/KMS backend cex100, for the CEx100 backend All of the above options except for the eglnative and cex100 backends also have an input backend. CLUTTER_INPUT_BACKEND Changes the input backend used by Clutter. The allowed values for this environment variable depend on the configuration options used when compiling Clutter. The available values are: tslib evdev null This environment variable is only useful for setting the input backend when using a windowing system backend that does not have an input API, like the eglnative or the cex100 windowing system backends. CLUTTER_DRIVER Changes the GL driver used when initializing Clutter. The allowed values for this environment variable are: gl3, for the GL driver using a 3.2+ core profile gl, for the GL driver using a legacy profile gles2, for the GLES 2.0 driver any, for the default chosen by Cogl The special '*' value can be used to ask Clutter to use the default list of drivers, e.g. 'CLUTTER_DRIVER=gles2,*' will ask Clutter to try the GLES 2.0 driver first, and then fall back to the default list of Cogl drivers. CLUTTER_SCALE Forces the window scaling factor to that value inside Clutter instead of relying on what backends detect. CLUTTER_TEXT_DIRECTION Forces the text direction of every Pango layout inside Clutter. Valid values are: ltr or rtl CLUTTER_SHOW_FPS Prints out the frames per second achieved by Clutter. CLUTTER_DEFAULT_FPS Sets the default framerate. CLUTTER_DISABLE_MIPMAPPED_TEXT Disables mipmapping when rendering text. CLUTTER_FUZZY_PICK Enables "fuzzy picking". CLUTTER_DEBUG Enables debugging modes for Clutter; debugging modes are used to print debugging messages on the console. Clutter must be compiled with the --enable-debug configuration switch for these messages to be printed out. Multiple debugging modes can be enabled by separating them using a colon (":") or a comma (","). CLUTTER_PAINT Enables paint debugging modes for Clutter; the modes change the way Clutter paints a scene and are useful for debugging the behaviour of the paint cycle. CLUTTER_ENABLE_DIAGNOSTIC When set to 1, enables diagnostic messages for run-time deprecations, similarly to G_ENABLE_DIAGNOSTIC in GLib. On the GLX backend there is also: CLUTTER_VBLANK Selects the sync-to-vblank mode to be used. Valid values are: none, dri or glx
Command Line Arguments Similarly to the environment variables, Clutter also installs command line switches that are parsed during initialization: --clutter-show-fps Equivalent of CLUTTER_SHOW_FPS. Prints the current rendering speed in frames per second. --clutter-default-fps=FPS Equivalent of CLUTTER_DEFAULT_FPS. Sets the default framerate. --clutter-text-direction=DIRECTION Equivalent of CLUTTER_TEXT_DIRECTION. Sets the direction for the text. --clutter-disable-mipmapped-text Equivalent of CLUTTER_DISABLE_MIPMAPPED_TEXT. Disables mipmapping when rendering text. --clutter-use-fuzzy-picking Equivalent of CLUTTER_FUZZY_PICK. Enables "fuzzy" picking. --clutter-debug=FLAGS Equivalent of CLUTTER_DEBUG. Sets FLAGS as the Clutter debugging flags. --clutter-no-debug=FLAGS Unsets FLAGS from the Clutter debugging flags. --cogl-debug=FLAGS Equivalent of COGL_DEBUG. Sets FLAGS as the Cogl debugging flags. --cogl-no-debug=FLAGS Unsets FLAGS from the Cogl debugging flags. --clutter-enable-accessibility Enables accessibility support. The X11 backends also have the following command line options: --display=DISPLAY Sets the X11 display to use. --screen=SCREEN Sets the X11 screen number to use. --synch Make X11 calls synchronous.
The GLX backend also has the following command line option: --vblank=METHOD Equivalent of CLUTTER_VBLANK. Sets the sync-to-vblank method to be used.
Debug flags for Clutter The debugging flags can be used for the CLUTTER_DEBUG environment variable and the --clutter-debug command line switch. Multiple flags can be separated by a colon (:) or a comma (,). actor Generic actor-related notes animation #ClutterAnimation notes backend Backend-related notes, including initialization of the backend features and GL context creation event Event handling notes layout #ClutterLayoutManager notes misc Miscellaneous notes scheduler Notes related to timelines and the master clock script Notes related to #ClutterScript It is possible to get all the debugging notes using the special "all" flag.
Configuration File Clutter will look for files named settings.ini located in the /etc/clutter-1.0 and $XDG_CONFIG_HOME/clutter-1.0 directories. These files must be valid key files (see #GKeyFile in the GLib documentation) and may have three sections: Environment The keys in this section map the environment variables honoured by Clutter. Debug The keys in this section related to the debugging notes that Clutter exposes when compiled with debugging support; similarly to the environment variables and command line arguments related to the debugging notes, Clutter must be compiled with support for these notes in order to use them. Settings The keys in this section strictly map to the #GObject properties exposed by the #ClutterSettings type; if Clutter is running on an X11 platform, the XSettings manager will take precedence over the values specified in the settings.ini file.
Keys available for the Environment group ShowFps A boolean value, equivalent to setting CLUTTER_SHOW_FPS. DisableMipmappedText A boolean value, equivalent to setting CLUTTER_DISABLE_MIPMAPPED_TEXT. UseFuzzyPicking A boolean value, equivalent to setting CLUTTER_FUZZY_PICK. EnableAccessibility A boolean value, equivalent to setting CLUTTER_ENABLE_ACCESSIBILITY. DefaultFps An integer value, equivalent to setting CLUTTER_DEFAULT_FPS. TextDirection A string value, equivalent to setting CLUTTER_TEXT_DIRECTION.
Keys available for the Debug group Debug A string containing the debugging flags, in the same format that should be used with the CLUTTER_DEBUG environment variable. PaintDebug A string containing the paint debugging flags, in the same format that should be used with the CLUTTER_PAINT environment variable. PickDebug A string containing the pick debugging flags, in the same format that should be used with the CLUTTER_PICK environment variable.
muffin-5.2.1/doc/reference/clutter/flow-layout.png0000664000175000017500000000347214211404421022317 0ustar jpeisachjpeisachPNG  IHDRAassBIT|dtEXtSoftwaregnome-screenshot>IDATx?n\Uob[&lE$,ѱH*T.@tYDhR h\D<;y3H(~f\ϯx3L{4kR"?>d9͹O߇sw2m\ߓwqO ~~n]M<&U5'UU}AYd\Ug3M(+;jr:}RU# ج&kUuRˏL(,bdlB`![L'1Y#/M(ڬ19ߥPXfw19m׍jCcB`oŘT.(w6^# !|or!&!(D @!(D @!(D @!(D @!(D @!(D @!(D @!(D @!(D @!(D }<^9whYdI݇=Ȓg{13MU#%;+Iz:u eXqh9@8G pG pG pG #@8#@8#@8#pG pG pG p@8#@8@G +dE:jytq:1vUwhVUpG pG pG p@8#@8#@8#@8 pG pG pG #@8#p9j'l6vlX8|8uNpG pG #@8#@8#@8#T@8#@8#@8#G pG pG pcfF5= C`2vFpZ #ő81coV9^ckسg$iڴirGY3ӀWyBBBr#Gc]Vo{RRRTXXu$+VOqq>Sy޽{<˗/Wvv)55Ulp-X@ɊPDDFOn|?TVV1}UUw.qv&S]]gyF7tյkW*++K֭S}}[9nV< ϟW||Z}WVi4~IH$ {>i$󶺒lҤIοg1117x6IxMk$7'|b.˺vj999K/ٲe{]O>gbVXXh6k,֭EGG۱cܦL{&9r,((ȦLbK,[ptM&ɞx HCY.]Ά{5IVTTQGy$ƍ;>%8o߾쳁\N&M9s${7ff3IaΜ9cݻwCzMM7ߘ$2e oQQQn%%%eV]]gqFdsubC _W8{-W^{y-sqqM53grY~ӍwewݡM ׯӅ_mQQQluuu~U ɓCee۴G5q,33c>˗/7IsϵzM}I3gpmsϙ$W^y$N8n߾}&ɞ}Y+++3ql>˳jժ6@}74q,//Ν;g}ZUUUg4ZNff-h_Cxx֥K;~4 azq{7,))ɺtb{!`̘1HC؅رc)?#d>`㸇zm{7n\.vCyzafff2Im۶ƿNUitup~ .4[ѩccիW${ꩧ:t$w ޽{ۛoIQtt5,&&֭[-11тwmܶ-Oñ,::q 6h:b:e8\$ŋv ?!!q\~~ϋ۷oUV5^GH6 '6;-b~o6mj2fCynG3ݻw$s\vRmtuN999:t|IUUUlݺu]wݥ#GhݪSaa\.Əe\s5?~nf檸XzcAϞ=uDFFzOMMՎ;cڵK:zL8MAA_*--_| &W__V.F%IJJJRDDeK >?E_ Ǡ -ZHUUUz':K<:q^OuvUK.$=$\p :xjkk}NS[[jȐ!>\Ǐט1c4h x*..Vee8/Qmm?.^xUgG4hĉK> |)%%Eׯ׋/(q׮2bvm*))SNչsfӬ^Z՚:ujb ^~emذcHHH鳳uY[lдJgؠi>}:6 eee^WR|[:4t7n[ٳ6p@x֫Wslp@RRi,Xv@C?h{g׮]kQjIIIm-l>}zo8p@999>[?c … ,Ck:ydm޼Y{Ujj*MЖ-[4qD鮻RZZ޽{zj]wuڼyZ4۷?oMvv,X1Baaaںu2335j(g?ѣճgOUTThڵk|ɫ>/^#G>)--~;=c ƩSl޼ydaaafC y(\+o7IG5[dd?ޭOۨQ,22҂kL[n[+^yw6yPQQjBZ$pĉfӧONxArB.W8Nht0aۧ3g*99YZtTRR4ۺ=z*++裏*..NEEE5Җ-[tmT.]w^護"-_ٹsK5@^_皣8nqwYdiߛ8;︍/++nݺYnnne/i{]Kk]kjjc'd˖-gK\8qizɓn5r#""4l0_rn͚5:tUYY8SÆ ͛շo_eggInFiŋUUUJ7N{]fLL$髯Nۃ8m{ǸpxԨw/lr=c_1.˓z-YD+WÇUWWS.Dwm95|p=SRiZ^~~,Y,=cӧBCCef0a[f plڿ񪬬lӣQ Cym%?"aذaڼyG+ixuu/2oܛ{ZЙ5DZcԩS*--zz,IΝkrf̘cǎ>'ؗ,}ڸqxo u lϞ=?w]S{$c{ּyv{mĈZ~fϞ'rGӧOor̙"͜9SEEEPhhUTTC_nrs՚5ki_jy4m4\RR]]6m34{leff*77WǏ+D>|د޷mۦZ]-77עږn+O[JJuBBBl6c ۽{_e=zeeeYxxEFFwa^Ғ*mk~a;}eٯk[nv7ڞ={ZԕzAU\\ 9]UXXGѤ@g!?v;yd;wNߩ+XEEtRQ! p/$ՓIENDB`muffin-5.2.1/doc/reference/clutter/Makefile.am0000664000175000017500000001013714211404421021357 0ustar jpeisachjpeisachDOC_MODULE = clutter DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml DOC_SOURCE_DIR = $(top_srcdir)/clutter/clutter SCANGOBJ_OPTIONS = SCAN_OPTIONS = MKDB_OPTIONS = --xml-mode --output-format=xml --name-space=muffin-clutter MKTMPL_OPTIONS = FIXXREF_OPTIONS = \ --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \ --extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo \ --extra-dir=$(PANGO_PREFIX)/share/gtk-doc/html/pango \ --extra-dir=$(GDK_PREFIX)/share/gtk-doc/html/gdk \ --extra-dir=$(ATK_PREFIX)/share/gtk-doc/html/atk \ --extra-dir=../cogl/html BUILT_HFILES = \ clutter-enum-types.h \ clutter-version.h \ clutter-marshal.h HFILE_GLOB = \ $(top_srcdir)/clutter/clutter/*.h \ $(top_builddir)/clutter/clutter/*.h \ $(top_srcdir)/clutter/clutter/deprecated/*.h \ $(top_srcdir)/clutter/clutter/x11/clutter-x11.h \ $(top_srcdir)/clutter/clutter/x11/clutter-x11-texture-pixmap.h \ $(top_srcdir)/clutter/clutter/egl/clutter-egl.h \ $(top_srcdir)/clutter/clutter/wayland/clutter-wayland-compositor.h \ $(top_srcdir)/clutter/clutter/cally/*.h CFILE_GLOB = \ $(top_srcdir)/clutter/clutter/*.c \ $(top_srcdir)/clutter/clutter/cally/*.c \ $(top_srcdir)/clutter/clutter/cogl/*.c \ $(top_srcdir)/clutter/clutter/x11/*.c \ $(top_srcdir)/clutter/clutter/egl/*.c \ $(top_srcdir)/clutter/clutter/wayland/*.c \ $(top_srcdir)/clutter/clutter/deprecated/*.c IGNORE_HFILES = \ config.h \ clutter.h \ clutter-actor-meta-private.h \ clutter-actor-private.h \ clutter-backend-private.h \ clutter-bezier.h \ clutter-cogl-compat.h \ clutter-color-static.h \ clutter-config.h \ clutter-constraint-private.h \ clutter-debug.h \ clutter-deprecated.h \ clutter-device-manager-private.h \ clutter-easing.h \ clutter-enum-types.h \ clutter-event-translator.h \ clutter-flatten-effect.h \ clutter-gesture-action-private.h \ clutter-id-pool.h \ clutter-keysyms.h \ clutter-keysyms-compat.h \ clutter-keysyms-table.h \ clutter-marshal.h \ clutter-master-clock-default.h \ clutter-master-clock.h \ clutter-model-private.h \ clutter-paint-node-private.h \ clutter-paint-volume-private.h \ clutter-private.h \ clutter-script-private.h \ clutter-settings-private.h \ clutter-stage-manager-private.h \ clutter-stage-private.h \ clutter-stage-window.h \ clutter-timeout-interval.h \ cally-actor-private.h \ cogl \ egl \ evdev \ tslib \ x11 \ wayland EXTRA_HFILES = \ $(top_srcdir)/clutter/clutter/x11/clutter-x11.h \ $(top_srcdir)/clutter/clutter/x11/clutter-x11-texture-pixmap.h \ $(top_srcdir)/clutter/clutter/egl/clutter-egl.h \ $(top_srcdir)/clutter/clutter/wayland/clutter-wayland-compositor.h HTML_IMAGES = \ actor-box.png \ actor-example.png \ animator-key-frames.png \ bin-layout.png \ box-layout.png \ constraints-example.png \ easing-modes.png \ event-flow.png \ flow-layout.png \ path-alpha-func.png \ offscreen-redirect.png \ table-layout.png SVG_IMAGES = \ animator-key-frames.svg \ easing-modes.svg content_files = \ glossary.xml \ clutter-overview.xml \ building-clutter.xml \ running-clutter.xml \ migrating-ClutterAnimation.xml \ migrating-ClutterBehaviour.xml \ migrating-ClutterEffect.xml \ migrating-ClutterPath.xml expand_content_files = \ glossary.xml \ clutter-overview.xml \ building-clutter.xml \ running-clutter.xml \ migrating-ClutterAnimation.xml \ migrating-ClutterBehaviour.xml \ migrating-ClutterEffect.xml \ migrating-ClutterPath.xml GTKDOC_CFLAGS = -I$(top_srcdir) \ -I$(top_builddir) \ -DCLUTTER_DISABLE_DEPRECATION_WARNINGS \ -DCLUTTER_ENABLE_COMPOSITOR_API \ -DCLUTTER_ENABLE_EXPERIMENTAL_API \ $(CLUTTER_CFLAGS) GTKDOC_LIBS = $(top_builddir)/clutter/clutter/libmuffin-clutter-0.la $(CLUTTER_LIBS) include $(top_srcdir)/gtk-doc.make EXTRA_DIST += clutter.types EXTRA_DIST += $(HTML_IMAGES) $(SVG_IMAGES) DISTCLEANFILES = $(DOC_MODULE).types $(DOC_MODULE)-sections.txt if ENABLE_GTK_DOC TESTS_ENVIRONMENT = \ DOC_MODULE=$(DOC_MODULE) \ DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ SRCDIR=$(abs_srcdir) \ BUILDDIR=$(abs_builddir) #TESTS = $(GTKDOC_CHECK) endif muffin-5.2.1/doc/reference/clutter/bin-layout.png0000664000175000017500000003216014211404421022114 0ustar jpeisachjpeisachPNG  IHDR'sBIT|dtEXtSoftwaregnome-screenshot> IDATxyxUSvFLD tA[O9mmsnhc{zmoUV[#=U LB !&ΰ; w'Y{''!k//$C} wpvuZS*($$*J-)uG[[q0V*>ZI++II^I }5++ }<_IpU!/a u`4t๎8@R:19h0(Yq$hL({nnCJ/*>h/!0B8##0B8##0B8##0B8##0B8##0B8##0B8##0}c+R*T7P*YMpCىdy W,K,~0@r[rqJ&E()RayM#h,@ey$+듯Pvq"$q[0$'_(A9)/pdLID0;3H"yr<>W ҧ/@ fa<}JAoGd8'>N:IsOO6MMMM#Gtu׍h0"v*JeTJ@~;8$NƳ>dM_[e @E+@[~u^SiiiNР>d*(IJj Ԫi9tT2II>HO<ǖaU/WUU{9}?^z%g?S4է?}+uuuujmmӧI˗/Woo֯_/I[|r-\P ,P[[twjO477k_nݪ};駟}'%I˗/WYY|#nwn@.YvBs XqC}mM**k`K1"ǢѨ,Y_]on=Ӈ|gzH3gT4U0$֪MzWd۶?|=:䓵rJp zU[[;w@wx <`?t+Ѕ^7xC7x0߿jXXEGͬ8Np8ˆ{7b xu9( jҥܬӧ{ntM:3ޕ;Nŋ%I'Ҳ=+B?O}}z饗}ݲw:v&sƄ.C3!yj^WRY裏꥗^ү~}_{o}czKw}^}U}xHc!ñDk׮=0}d0VS I^rjooƍ֦NuvvO}у޿er)[r}_9x߳uV.}|Mzdٲe~d2)I BO]];^raqXqȹ\W^y }NSii|MqoTccѝwyȕC}_vi***҅^~5hɒ%;u_N8F>ꪫthѢEzG$n0Vo\ښ8B9 eee ù0u'w&.V n #y?Gpy"/E\O#0B8pFG$GpFXjFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG!`pFG 9@,+'V`xG MeG *5X `b"[|*;aX-?xgJdɼy|b"I8`2Ɩ{_--(::?IӔ$B!JuZQ4JR2֮'7ߜ Evo׮R88J O6oxd6{*ex:}5߲%`$G` 1_זRcڶX֧c%UWi`ǎ週ItJ[=_vjBƛٱk>BZs5 {)@2YmijpXWFwR)m>u׮'TI@Ҟ_׎~4?qj~amq.#Vǫ{Z:mۦNv"16o֮vؾ]/DWאME"~イcQIxK_5aè-I{Nk֌HG C!ux37ٹs>6G/dtػs*u^=zcK oؠ_}Ѷ6Rj~QY=@45o&)sM 46yHOk(5J+~{E[[ջq!.ߏjIG^lϞ]M|$VG۱l$#ciۊةXLvW #<ŻYvW!`! '_Y*N;MG_{*N?=ѝ%SAu~j2VԶ+~]%$!p@rzUP[ŋO3ϔ(:Tt:^~Y-׬QcLBr@rW\Re++ Tqij'ԵzpYA8>GN-#K45iѢͺ!Uɜ9 64h)hOɡkU@4Y  ՍUT|>M>dx>xTyY:Tx,_v}9p ߯et*=\O',Kgy.M?&|>\pqGV;Ȳ4S4禛T~ꩮxd `TY;O|*lhtrn…w-pkcp;B8=O7̝;ɋnSɼy `ԔsZ|r. ,K姞yUUjY@825?f2,WKk}p0bϧӌ&[\K/ՔQҚsd `Jo|C\Oe+6MӯBe 9\U [G#)(ЬW̙멌NSg>#IK ;G#2SR]1x]r&/Z+` Oo~S`0pR)C!oۦHsJ)J%o0(_Yuu*:Uųf)PQN_׮U+gLŲ,xLqkڳrnUSd'rR)ɲdy[T@EJ=VU瞫OMDZ9G\fDGB8 Tsᅲ謌Rco[W_H6cj{ysJ6>ZS.hs@2R8}*/ xgx@[T98۴IC͏k]ۿT%g[T ##ޢ"-Xcmmj۽۵1F*P*ugRA:w#D80TiqԽfzKm3hpuZc.pjB8edlyWvսz4%:;K[P]\U [GC,̙--|MW/<-XLCHK+[p ,IE3fsQtnnG(|-WJy 3p04RХSz7nTϕ! o&jgn# VW_;Qͮ-ɾ>Ee'WV&OA9@]ٯ~(٩DW+v!`H#_I+ ]ٷᰒ+xd `H'tcJc1b1Wm|]U͡jB8*d+c-;wo.Ihy 1pd곣-+9X^kZtl;9T G Y^,n]=,#6{@ Xd2G/r;B8yz3[mݙ߯JW&_Ik Q9:8C@@`0mݮŭƲpEqy'p'$pe.`PųgoxAչv=vm CBy7pEZZ\'TܹRR%ѕ陈wu)8C'Mh;\p4͜PP[]ٷcۊٓQ8@@?yQߖ-ͧA'G'P*1Õ'a::ܽ !_Y\8߼ٵ{**4S2\񕕩sqP(I@@ 6sb΄<z&UǒYTlk*{k {L:z 4Yw)V@*pur`@=ބ<M"zjFOɦSET$ەqm  S3f(P]m~;Qxz%ܛӴi/``ѱmEvtjI9W}r{B+W*zMEvH k`PEGOW9u" ء:& @ӮBMftb \lV|TVKUt6(n׬Q %;;Ɩ%O Uvhʎ;N%楟pl[;|P톫d @sPNj/ocbڶbj/WZJUKST(٩Xk"--47++HJߋ1P^`CS*X[@Eruv92E8iu)K]dѷyu.,Kޢ"pT9''Lls -K+Kd_Vt\O'1a'32hPkL*C#O oQ|%%򕖦_%%hgQכo+c'(h$On[oU<rifwz۸ov<p I^z*:+miۊJ0% i~5fVi #} U TVf]*ծ'geƫT$vw\O2F83TtiڴսzumuY=4jv<pp`}>iΘvm+{ڶb6mL۶iMr=6,WU眣B;W״{~z_W5qp1RMҗTr1okbzݜ')۫_:Wr;\U GT2g_u&eJik]w)50Q<o|CVH2aMUOIùi{ц~W:DRۺU~9n `k΍7ofuY3}47J hWs̓[$ _mޫ矗?h*x(ƌ6|>y +-2GGױݦu_nx{'gUOG}+X8n ;WhJԞ/ىDVMm++S^%sh… 64z])p0SNnު0Ahb bmm~啚r:wr,Qxa5?6n,x\=֩gݺam TP[ T{r򕖎,L#Yj?IEwևw߭d__ƻ [?z7nw]lEvԦ;Tt2f45)ҢVk[nQ!S0L쓍_I}svۉ(֦_Jo^~_|q\FƎŴ'檫32`ۊk5W_a`b# TWW E*Uw _кWi\]uض6oֺ~UnAߗI&zT<t!#t̍7fٲ#8jy _hQhtFd*@cZ/jדONܛ;~[[Ӊ{1q34eY^xAN299-7Qer͚%_QQo8JhlԞE-=~єDzUu.[Ks@xlͻVYj{Y$y=?@e4餓T:ouu#:4>v\PP]~CͿΟ/oaaO$/WT%ϧN~!MU ׫3%Iv"doᰒ}}J (Ȏ\x^Da򕔨Vzs=%c` TT(PQ@^0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0Ic0,I;6ws#0B8##0B8##0B8##0B8##0B8##0B8##r=8Gȶ\O#Gp=czcG!A8##Gp8b 1l"#0B8B)`9#GGF8bpőps98rsGF8BH\ @8)qdYc)ۖE8!H8Z#?lWJr6X0| 1OvJ~o@ݗ Vqcﰉ,-'cyN&ӿ<ˎwt0!¬*ec "󔝌K*k듷BҊM &*OSg0"<] {yr=F"/C!9PXqK@v"=m+;DaY{Ӂ+4pᘇ ˫))S2&Gx,Y@8%򨰼&z0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8##0B8IJHJR3u| $%qݝ;$!)&): }ta΄$> MgJcLR\>]yt.Gڃx7?Sޅ¸a}{WS:t4 J{ok%CEcB\X0Qa80Q콂zo1ǽ{u`4l?{{oWxK@wbʕ#F,_r`ovvش)юdncw~ѣwnߎ3f8`bi:~JLMMBYYZ`AGr EVVظW|5Bhu'Eqy<$?EY,CC#_z1Bh?OogcNgw:!3SSKH&qV\99e@_B{ر};{6F344/BF/q޽l6{43P(}<ّheddYMqqxKVv6BhرJ};wf2?o4lP*jh`8{?Էo߳N᳦:[xDB۵k55տ]#/Dc5_}'S_| lv#}mܓ'Wx۶p!޺vMbĤY>>Y;3gw$>=%9y̙Mo>%5u֭W/_~)^>{vjZڡSOGE}㏪**N\lw~}>xpI|B=$ ðm۷~i&KGEsٝ8zg@k˗gjjT,3@T nncF;R+Ы$e2>lp'''nR+{))*85beW qu# vDd Rzc\T*@g%EO|;99 J5b؈V4*c`jb8QÇ0p H@OWEE ''gx߄ i40Ç¢'!8d+Ћ 0Է2L&6<}L999D"89s!"XTCV8|DDQ++h4ۑ#YZhL7o?7XrՠA ' $k;d+ OMUen>AKۏ݊ 'OBцYYX`dk;dW_T*&Etbgb4b dii-+Koxh``p)Jn v 0*NNO0L"B@b jc➰XB6̖222ìhSԯL5ʦ맷"xUt7)o\^e_=QIqIM-d%C ݻhoUU{wƌqЄWz^j5Pb 2r(~[|VqIqAAMl\>^vbFbK)DW`YX *,,sNff`rrҫW/qustt+zXj_p+K*h#lvı]O\. D256<ȌD" >s4Nfkc_HS‹jSԚO6XShhhyy!LLL8)OLLLSRtxHZcc=D"̝yUhE "FY?IxJdeeGIѦyz >}wEK/&''8اgft-%5 !z%K***ںubIa{@:ZmG!fϚ3p@Ñ}tthkiEs=XW'm-M+EWdddf͜={AmGva$p8t:}ƌD"N>ͥ_%PH4]GxDG$.)iĦ˲&S ZhT;> 8h֬9BX'&Xddg3e .FzxLP$en5Urpph#-ɒ4DjjL!:djjw"$Y Bm3JUEx|)UUUjjjUUUfffqqq$_UQQ־t8d%027%`CMr\B&9Fqu_(ɕ* 2_rn#T(g%N>TRRӓm )D9BKSo}!|Af:}EtGff& 60 //|^@9c2Ś0nJM .=*2N  wxee]\\eh4QC-H~̟p222ONt,m1l$i}u55|}rDG,--Bt:!DP$pJ(Gq[ZZ4AIQ'2 }V.⨬dllrjcQp !D&'OAAi4ckJPvv6!Hނ_pf" 5$"feOWMU? :/gϞ+V-&LX~}uuuaay9W^^ݻwf'9EAH$ԩwnX` :wQ b=jaT*}/I:}aw211]r#ee7WW\***._Ç3Ɂ l^xg?H:!)))55UGG;Ąr~%%%K$w _ %%%%%%xˑ#Guuu'ONo+V2dD9ĉ66uuusfxɵ78h;n(//{~'._OII)1nbzaׯ[N#ǍuQjn^HMMMiiijs͛7wmVz*j΃D"}jBH>g^EtiBTq𷂂?5BJwпTjAA`ŋ9x֭[nu"F"ߪD"?{"m.\k׮ׯO4Ix)S`F"lذ ,AkG^z}??t]zv/@y5kM6oncnvE0z/nll|T6uڦ,ꔠwtdjjJ>}B#XlL&OZf +!r]Ǝ-A ?PQQUQQVVVUU}h͞0~S7 mܸsN7:lhh8lfV&MyveaaL&!D&d2"$$\lϭ\vmÆ /_O=vںu벳\.D') f0W^M4)//0CC7n Fcc#H9mMNNx'$Ns\6.y󦇇р3$^߷QYYmDX|E?~Z 0з2F-^ yU@&̞{̬Ѷ6O9- ?WVVgN* ْ|SSN$ݻwozzzTsSQQAQ(5U~ N") x<x "4*lllK`*G[7 0a<GɊ4hH*ɓ'رɓ??q1L%%O_8avS?L>Eu L`@Z;|%BY`QP~ǠR/<лc888yO&40`ð¢ꚚꚚZ뚚ZM #u0qGUVV>Y\Rb%&(+"Ph3y 5Jh'vv'}UŨnI.m6k,L&`0̍7u'o߈ ihhX~}dd)mD' uuuW\5mĤVI@(6h࠼wV:fe OyZV^>rqΝ'IxݳW/F1g---x{yyxٳBV+-6Sܾ}'aWhjj<==##GM>ۉN m,--$H2K3׊B&oD V^x}1J}𨢲h9sMڶjƁÇCUF PW=²ˁ '3B~,ðE̩quwz >jn*,(<}˃犽͘1cxO^TUUD'֑I> 9_x)Bg2 OW^^$FRR{JKK?}SR;p8:u㙛 rV~$AKK۴RjYp7@C7_s#O'/a/_f..ؑ_PҵQewĔW~=I]{XΝpb?k[Ga2SNmg芏B͉ JOeX:K%! Hw&n[!Uifٳgh4Axxx>ۯ1ccc###ckkFYAAɓǹ\nEş=cvv]\d>~6d;6*<>*&JKۿ'))QӌlInnZILLLKKсm2įEjni9}.JIIgo\#:LJJh0:ujʕx ^y #P```XXXSSSLLL|||[ 8H&xXPP{]][PPSIIɱc,uJjn^~OxqqGbE~ɑ3={>}SYYEtDԔ'm@+P iE|jjlj|EAAw!:cMMMk(##⒗7nذ`xyyjYfժUF Tllڵktubbbm/mʎF54櫷RQYuAL釲=x1-Ϝx)fNI{\:t.;g( ٳ e@cDVߔݿ/&۹sgSSS]]miݻw;wtͭ* ወt;566f䦥gt?b?{bE_:{$Lc*..޻oׯeDjJ*bs>DRR+PMmݍ;weddn޺p%Bt[T*uٲe;vv?5۩1ݪGGǐ&k.'''N }_:%`Zy aO<݇1U5D#BUߗF& IDAT1X @IPj B\rYBւTUU9ɉN/^8쿋rn7od0w9ph_ihh *,*N~H>ރchnn<+l6l6T.N؈X'YB"S2|!|JjJ]MꚚ~?Y'##c̙O!uV'$$x|B/'Ve%'n,6/ߤX+W.Gۮ^PPgԴԆ1q9aXZZ6f33ST !Ç' BgΜ̔)>:v<}IYyEDͫrr566ٳ7PW0,&#kjj =ESQaQmmsŧX>@$V<ȓm$1p8'N/(ȯz*ØÇ>_Fxı79ė%&K6M)0] ܦm MByɯ߰'(pS'srkjqzsN‹lWO<${n K%Ȕ&:6;RKѨFD ZGG舤;wLzz՛9.f{3@$=c;wnc_P:]/-;+dh!Ct@  wZZ!3TшDG$0 x1'#{tںcZY#v}xgg.}[__ܙos%HXV߾}Ո .Z!RҩTAЯWtիH|yBK 8HzY^^1?7srsf͜-Xdgg=w.ER}Ch4ӈz6ɝk%zÑ*s8q%qO"J~aѽGuuYY{x}r럛][WGt8bώz"ܻ7hX]^izzU}STB z\+>ln4''gq)1gΞ*((`ϓ^/@TzZ!8N쓄V^(/lnueeeDIE$7cǖKGOdjUWW,^H %%eIzzzoߦ iEB!#\сAj%z ! AׁJ>V0j:ZLAx\@wirPRRBihhNt,3"FX[02":zt@={P[[E|qj%'/6f엞 iii&: !Ç :z$99y[zzS+\Vvvѣ;W 04\"1\TѱϘ=pXXNn.ѱГm[TTVnOc@,͙ceiى;Z_rsJKr߽Hٌ9:...3c'P(۶lillt@Z:9u.il6сAj%z4*!@]+ׁJ` =` G zHD@/Qa;[Aj%z0:Y2Bӣϝp8eL2eijj ^h=l(Q|LF8;K=à{@j%---cb>DPTUCvhẔt#D5(DhRV"SQY}Ϝ9G!*$@EP剎BJI0t+.ɓn(_~Ц&@7JĎx~v_hQOKYYYqqDGzaVV m{qISjjn?Y;0Ś;y UUT>[^^)a1xϷIDjշ-Ù2ѣ bB6qOb'"N : лqqq=UcqIÇ/^puAQe0=kdGD7goKCCc9DDxxh{{@HJ;vyDQPP_h``XVVH$Re-%%?l4v„QQ H_UEEE[[bYYY g{RSSPWWBʚ >F"=HxqU]So'H˃ziЫZ菲N"f͚3z$ti}DG@x aه }EtGLm/Z%X0pD|`shAD:J:tXUuL/O%E!o5uU6m;q"Q! q#+++##(###KKKðb<÷DE0+ ĤVC| |2:jjjK`㿢ONt6VFVƍkNqOKJ?|24VJ.2 D]4 @GGD"`ĪR+*bg3RKSCKKkhfs\k׮]v,XѣG?ǜuuu:4e~IaB }D"/;w=|i:ҧ`</::wZT$lٲzL| 33,55_E9:8\|i/n'6*E߿q:QH9u(4M/!@tGjEQGێRWS۷z^teddIII^^^>>>W^_zz:~P%66vSL0L^Y?iy5kM>&%%Q(%a$̧^He##+s9#T7'//ob% B Ǻ(JCCF7 ȿ u$ êmMnuuo}ӅOFFFEY}žt\mM^^XpMDf1F~;ڵk֭rF4HY|B%Ht:h)*'v$I&afhhx 1n8&tg}˴|,~gΜYג0m-O 27p:a9ĜJ}ΝB貲V^wqSgD]j1BϬee 2;JwرyfI^O%$$a!&`0LƍG%U ?uV} >_~p޹O7|Ӊ8wɱͨTڛT^$Y۷\!: [ϫ𤪥ԙ3UUj*pk`̚>j|qU>x@NNNz*۷o(XR*,E}FEEy{{w:֒k}}@Sí,$4c0lii p7n۟VVUx **jee/ktw^b%QQV:٣viӼdq%pO>l׶ B( O?K=>?[?޶w :h>J}-,@}| HU]0&y??n] ‰>QSUK܂7MMMJՅ}\'jl‡ٿ5k`ooJ-p.z'QV:ZclĉE3AG[KΆF#TO](H$|XXXXX޲cMMMqllڵktubbbB> ݾ}{ѢEt:BYfժUU 60 //+V^M׮]+7@~';;YjE&FpE- BjFDxի?ovm'Xq87o-Kj{/a^oܽ{sLMM7o#R5 Oܸ1+l.Yjac++|PאUϠ)*.ڿ/B(]~F=p!$//BOqtt a2vrrrB ܰX,1xayፁT*uٲe;vvЖvٳdŵ&TQT6}$4ۮ(o644VWW_'-#ΤiRZ^޻Цo$S$GbRғ$*:p͛7 Ɲ;w8ZɉN/^ض{=wZuu+K*EEOcojj>yNzzL&SBTyOb #3+hD8ْ6M[]"|)\ݓ`;UqBB͎0`X* Ԕ;{l???ddd̜9m tjSSS?tPѿ*" ` 0Ït9x( 칤~&55~ٹΰufq_r>fx5o輼q ir&&&'OGjjn-DKN߿O_QL/O%e%c##_hEEEEEEzq-gs8&؍F =/@YYYTV߿Ͽ+cyѯtMbݼysܹ~mAA[V^=uTNܲeKpp[^ ϮZtz?GN:u˖-'N "s5kִz9%2$yQqh;:oO_xU~``իW޿/\p^[HSSãgӧ]t/x ݿN:bz#V,[f=bSB cƏ#*<Ў{nŗ!aV]]m{G'O.X,d2zx>:Kw- n(//_RRR]]ݯ_F6~ˉPnnnhɯw{ym{>͗neˑOFFbĞ;='Uio"TU\,-t Rlm&XڳoA:XF\AA%$Uj`1E ݱ.aIdf666bmK----jjj.]ڻw/޲se˖ VX1dZBk[Ǐ1c?斗׉+4_NavRDZ nSUUݕD$}jn߾SOO?{ߪO>=xwwH$`p<"!޹V 231h&##3Bc/=]1r/{ꥒr+ _tZNVHsM{uvN{`ȵk)vrt+.!=qUn6#ZY >q9>惻@$8Ωӑoߦ>DtDї.DDwFn uıoӴ"Ϝ h[Gp 8sβQl? --ǎG^yT}wQ+\aq' 勱c |ưʪ꘸xȫ•~x,&m,QϪ ?VVrMMM9 bß[Z!+n{8aܘ;wo0[<&N%*<<}釄\BVxٳg?uaٳVL_*;;+;;KhIDP7УZ!*ߺդ 1,&sdW,hXmmmaqɋd͛ "6o.^hooOt 'a؈sO}!TZZ.++kffÁc2zzz^AA2+{.999666222%wU~ݻdrVV*T Lb@RgϞ533hWڭ`y :9:ZZXK{Ldh`3ۛX& B($$a͛7 Y~]GGG~d2 ܸqxgwرyfŋ=<oo;vl}<8gΜm۶,B;w bX| \kkk''b##v NY` PZ!<^Uu QtEܗ <<ߪVG ӧ-ӧO>}:?3 #[ Y v 'iWmp0pz( .5 `"x)"Hrrr:u1\ؖ,Ԑ R+ѣ!X. 0 p8-":Ȫ܅ qqT?daص7kjZKWRAAj%z0j ֬3ZZZ"w7C,IP(A_ݸ1qʔq\ þ]~IxWJ` @>>Ϟu7nO%|'Xd2+ RSSS t:]KKjRRR+VWW ֎Åjii_M3n)00ť900pTTT|f*a2MMMgΜٻwPCBB\}7VDjr %ɜwtt())!hzөf222d} yv֭{@V޽_CCcﯪbX8 ܸq#Za{jjjDDeu222_N&߯9FA?NP>*odƍG u! 111肨!M-uvvrpeeey9$VG;}̙='zYvWg ㏈ߖ-[Fnݺ%++kbbbff6bUcA&!ؐPpg̘1x7ZZZy  ?ZxkN'v,SVp8==me%16,,СC'Om۾曝;wΛ7oŊvvvC N~!((HYY9,,l??p WvvvۏqbDCEDVVVOOAWWC:tի?? @.\!l&(-}_B<)"" R+j%sFFN_ǐ MΜ?_YU%Ocӧ׭[w'NY[[777\|HTTTo߾=dcǎyxxp8={[);wfh=ٳ>>>?3wHt7Uhxs.^O?ox^,`$a|GjЦ`'U;qaa!ѣӢrQC@0L]]xu]]!wfggmčVU sP9rȑ#GǪC.: ٰaw}7K@ym$E `:sꔩ QH HxO>1a܌u> ` =JƵx,= @x@j{xbIgUw%̕* 9VVf,6bUԼ~cb d#RRSܻuf Ã@;}0hmnp7JJKS҆o/(HIMx8V>[**eNU50>(Ж#0  RԘA57!Dⲥ.-FGGgdh;ďǦƆ:ZE%ͯ `Cl6{9e%%R+KMKQ谴@@j5V KTUUA,-V\0 U܃؂{!HVx{L&s7nLJIA(++#2dSPPQB(//Sd2D"@jiRRRfƆz8N]]}Nf]t|pCEUMYE%|ΞMKOkOj5c/0iklL?xu8ROԠ2#I$e I0$xOVVf#m-< ՝`op_~ O iogy&'<-0Fa)C)**n: 1TZZucbof[7KAjQ VTs)Sr*yyy^@ [XX>xzv^AQW7 qqׯ'۷ e|Q 999C499 6 hf6+$xw䵈{Z@ZJ@_M>}Z]]]~\HAAa&o;w ɡYdT$ An^`0~'"yoUuRG{Ba|s^`hwȞ1U(E-qrp L65l&D$e\Οo<{4!1@_KSÐ&cʕʊ# Ҳ66|1 IYYZ"bAb#bblHZ޽{$<l2$<\__?zTO DVJT)*8zJ!/ZJx0Zuvuaڸnfldu|ghhbsrttrt: Am}g99ZaYWWo2'144 }FTUU%XZfp8 ZZX5Bٰ~w hW][WRVd X6fUA**ʱGijjQԊ M+))>N 155]ﵑ'uyyy_&?~f'B%qҜ=k&H]:01,>>P_OKC '3 : koo~ߡ}$Y[ϣRu >sͣD wu]agkÏ0Y_Oڵ.5AZ)+)ZRUq8ܼy]:O ,ζxϭXjut8))-y@7{iEWW/8xq~')(=k ZZ*׺٠KjKJs'za#Y֭%ˌ'= jk$eeeW'#(ƌ&uh*^ioo/,*|ց ۪ .p8޵nz0bZ(+YR͕p8.˗ʈxssε@;d\J@ȀIjkk:1jhUF1eʔ͛}5fhAoݾY\\$4MD6 korrr^޶+BJje=murJ245`DT Ou$Y𗖑YV\\,%nzƎuu\:hvl)fy]^rrr:˝h\P IDATp'@D"qM^^d+V}VKYYLER&y -Z80pה)SA[jdoke1H$.\hEzfXp8ǒhXYI ӧ ݂65ӛ@ج]vŕ?籎HdMU۵3xO,`+34B,X"'"s,++) BEVFv箝*JKlXRD"qQ66 vM:uvhj&~|}}NJ"8_}y}tKYYٳ<ݭŅD"dffbrf\]ձHdooϵ뤠ljCj t/]`}ێg`444vlnR'ty >}zx~3oWc[ZZ^z޽=Bpnp8,+"""$$nݺViii}||R>AZZZUUu!o\A8!ϟokgT5R"ZMQQ^`gI5'-޿9sJr2ᬭDl'{[eBSC38hOihh;d{_uiiԩS۷w!;ƚDGGǺ:tcff={d}{&$$|d2yʕ{ cd2֭̽8Ӄvϙ3񜺺.+"\#HgDDWWC]}:A wwy߽ NuE%t6Db+V1OP~8-ijjj:::'Ool2:0y8Nss;.$ϖYfjI$fok=yWئMvޞA9s D/Rhg1{HۿH>͙3w-&T%ST`( P:::!{fM hS3SFfǎ~փnܸ Hpp9رcZZZï_Νrtn 777L^lvV1B\.8hѧƵ544wSs:-..n8ԩj;w͟oÏ"Q$Igikj o}4!oB2kVϟ7;uuv KJt:֡1\-oj8hj&VZjժ!9rq@@@@@G3ӧO[ZZUUU ٘}[Wqbu5gP/.-O6ndll«BS3IdX2JJJt:N3{z4255566~8Ȭ0}wى| jyjss3_/$D :Œj /m9;/s8nx2Ɖj2p833ljYY_* oiS'ID"F/\hΜo,(,PUUC^^+)*})Sw슊,,*PVd2jn1AC5kԦɳHdUYϻsNmmƦRWqOp%NK8{wzá9/F̙>~|RV^ H[[W/05}f747 ZIHS+<g7D@PTP\嶚:Up>qj4myqqqZ3W@bom`` Mttt##r|áh4j𼪪*3IYY)[=~AMu >Y|l|=?*))ɉDrxTUեgD}5211_?5bF>?Tjee%l7رJ ?&!p8K 9D YK}0##=ȫ6NNK? <v*_. 9+O5*ƺrBbUV22d9S v]Ẓo۶}}}Ϟ=Ԉmx%drkk{PPG9$HzAr!{ )rrȘXPYYLE'I x+~GP|ihj&ZM`2g˖-'Itt'&&[o吮K/&''/)wSYUy*]H]vŕ?籎H4(**owttsa.22ܜD"X us_~}>g,r8_ yf?_J%pV ɩo޾8w_]աׯ_766|||r~~~'Nc'$Ķ?~¹yyRS[ǧk __ߩSH$84W@|}8p|4#†_.{x:ZYU]CggSRap0Jz,Im۶IIIܹ׈m?CXXN?y򤝝(G`kksd2N7Y+Ir{}ێ>G8qWUVRDmX ǎ;H400߹O 62܈SX__okk+%%5>{t(gɓIΚ_ eeCjD]jzmbRjIY9HH?zOײ'_~˗?5b!F@TTTbbbG8bdžӧO߾}[EEeHK~  oRc:Q\Zv%_]ZZ7u}ݻw#8pk,u 65#b#66vUUU,k,;TCCcSSS#""|uvvWXN|ՊjOnXTZgG^hll:%U+޾ٹrz{JKKN7qX8L&_tipI1G'C[^^iWh4ZGGǕ+WHVV#8+=|}s^^soT*u];\:#&g'NjjYǕѺEEC!VSK FR㓡---̥ 66ӻ)) ,1%X%Dv*))iii=xƍGqx^rŪΑRc?PA'رcGff&ɬ޺u+}o# :Ǐ2YbG]t)h"*##7{իh4l#~; 8.lhjBʟY>eC >|wNEe MCjUVZj#G9r}<|񈣽Be\ >} VkzVNCL2eeehUUU:::FF8Ξ={F9Q>٨ :]]ݧOލ{-[lٲuHhWpU+:n~~^tm:̎V'41JNIzj50\aaAlNURVQUS+7"]E,#Gc'e\-ZY֐jjj>}MSwh4٬ݑ"`IOf5{{ rL&98 A6]^YL57C䯫Y!6VUU"%l*s\ʕlmSrrzZTVN| %tMK _7>ss: K^ݻo߶*bITS+TvکTʊаvvK%|@If+(z6:+*+x<I]^Eeʉ@  qע"Vv7/߹{d|zW0hVw?v8Nf϶]$C|hm}n;$##=//oժUTQz 3*AlOOs`*U*=ٽ{7L޷o߸?~Bbbb1GH3Pq# D)(,hjn;[n ,0!U+.SU]8+*ڥEq7o\t)50jTjFF~~~'NۋB>*ܼ A܌`M|YQqց&<< * Zϝ?c HP4:=e^ꓬήښSaX5gNutvdd>/:p;233Lfuu֭[t:BosXXN?y򤝝EVVVtttoocFCZEhS-El6;)_.vuwa XbXc]琦'-=E(#-)-C_OgL'OVtz{{LfQiYm]TxˋFWUU>|~1g4MEEE__`ss>?lj' ƁFŋ444'>8pSQtwwGEEK).)n HooQX%$.BT55m6SG[l5X z^~}^L}}= uE%t%__>8zѣGvȑ#GpBF&@8utt\x~rWMMQנ+ZtWyTgN-Xe ,uh q8μ¶v(%ffR lÇBHnjjmkON{m>sfVVfAA וsp|<ѣ &F1(:;;"E r"?== (DKFS+A8NMm}ss:Z7ov_vƌ; 71`75Eii[7}!aQ|WPPh:&RyR̩6 ]\h|/>QNn6ik+(l̥-YUuZO>udX=xd3H;ZOWXAjw?673},0ʹs:>prss=z`0 KJa W^655N(ۮEF465saEE䔤>`Ps3S=[oZ{޽pjK &?.MV^c3YXTxMM4V2g\eeA89C .HF`0^5XR9s6||]eedyuG?p8mm ::aYuULb?{WǖVP RѴwtfdjk~VXXrIGt68Cm죩93|!27yܒ x< W@tAj 8]7fhGGpԚ ލi~pjK˙L⯭+WZhx彊3\BA .HƄ`/k0G3-_BNNn'AGimk+(UqATZ?Ʊu&yޝ `kp + Ԍ,-MY3srs ]7o>.l6;;Y|B}U[y ݻܸy!0NPƦ--f&zw|lGm9#@h~"р˖8::f/@ 89-IOO{`̙3AW^6 W@@jL@~aq]}%\,𨷯ּnT[ةPCps;;;ɳOѤjSpl3YiD tvu=RS~`g> 1Zhց*--IH&XWutt"-kuuu{{QQ\+j4Ҳ^Z.kAܜ=wR+ x)B: BRMS: a ʹi 0H7 )Q)STxR+MCSsΜXG@Aj%$|z?0fXݻZtvv} YV؊{ ($  ة wV"ɾ{hkXXXb OPRR***x<--I$< L\+>3$xϛ7S޿?|==Kuvtܸy]I8 (D]]]mlgg|@}޼W߽{I`R+>ᤤ$y{XXZ%$qB*}6}2 (xrWIœZnXtv6M}{<\IHgejjjVVs,-޿ ҥ˸#^}NWW{D/ 1w `b(05Op8IIc6 An^f@p8̫ >}:_LZ0&%+(֭_-_:;iN30fXZ0& WA !Ð=FF;\JJj;d2I2H WP`-[+yyI:ɓVPPPd)ӛ2eǎlR+aH JV316 ޣnk>򹌌 o,i `d0<b/*''ǧK ޣçKHn JVARRRھm#;8B R+-\A Hffwkk D V11"CKJ'%vvvDL&G VXhbאMB\>BR+ \LWsrI$Q|F:: ʔ͛}0\AAA)I0D V@u⠠ ?ZQ׺ 9?N?^/-s׏~`D̵` ǯ\ϾP(KMA^.FX" `FYYy@{;~Hcclct~sSUBJxwؘ5<8hrrr_~uJ-/ss @Ą՜ӧcp8튊X"/@š5>[>3sppCIIIqw^TT{{{э8TRR6mZLL VJJ[jiiqqq!H&&&ƨ(iii]]_~ámllD jkk C[ae5j@6lܰH$00~ cj:@V2eJ`E ?}'Npn3Y L@LLŋg͚ekkd2Μ9w^tˎ;lmm)tuumv徾gϞ;s8A``KWWs`` r/_dC̛*++]__ttpӦ ;ך񃬬}jd R+XP-B4fhqY-v[ӟeAl2xLoP(_1 _|L^reEEq֭{ݽ{wyySFFƾ}dӹۏ?>uOWIɏ]]W<􍻻7oAjjxZ6mڅ qr;[Ux~r@<=}H/ݱc .o޼IJJڸq#۴iSRRׯѧF5HpъF7^~~c$ e2ʳgO?~@(M\`Ѿ>MID<0߿GDKS+$8|6/ T];ϛ?3hjh=è$EDD|EFF~lgǏ3 WWC766m&%%sǏ""++˝VeggFO|HPϞ=;*G"TUU޼y3d M>p{…w}w٣dpAS Hp_;g\fNd`hoon>ӧOﯪ:x;#G9r}lhh=~8Y>ԌH$1)**,[.CyB KBxxxYY`J>}ɌcY@Bd魨΢-ZB]}fSx~ӧ܉~%OXQL&Nb2t:d0tee#ݨ(a{{; ==='Z.{ŋmW7 999 XCj= Vif. D"qMwa2>yt..~cSL&֭Uk=<`r^Չ HNNv~~XRPP  /(ؾs'(HD"yzQ\km-Ȉo[p9F>ۜ:x譵EE;ϫW/7o_a 5p8)y2L&9cA& Vؼw]QMmڮAE;[OJJ|)ޟ=wmyUOO**w Q IIIK.wqqP-ZxU}OZZzALt4A`XYO;wbyzKꪨk==X"t GOĒYێ4VZ׮rW†cɜMx>zm"[M}45xoI))@HV@R@Y> N;v-\@$Ndd9D244?x<>6~D_˫Pmmm/|")KWW_.%'' s؂ H #+))cߤ=|}Ш>|绻Ұl6maXcוɟ+O`P H #[rrr_~r*!lman>;8xЏcǎ?ΎH$ܧ"?vTjee(%޿occ.5.6`AJKKøV@j$-==&&XQ**۷a bEDD|p24ʁk466._~ؼy32̛Χ ø[GGKSD4@j$dW7c2ªUKYYYcDD"ѱc޽L&۷/##cגqvv޷oߊ+E<~mTxXCЄV@"@,BwY|btfHn]]][T* wĉq]F}}}5556mB7 oذA#GG}dLg\b__\`p+Qch`ȏ`й5ӦMpOqɈ`8cǎL&Y]]uVt;NP(t:opnqnגYzѣG.]VE<]];!AZZ_8)+ X ɥ)%%%yǖ˖8::/5Aϟ;::n߾˗_K2///_UUsatc<<<8Ξ={F9F߾}{ϝ;?_Q֯_OќJpss&`p8jj7m,//ߎEU+$`/oSTP ùr"1OM0?s&Aѣ;}e˖]]]+P]Sv*`211ё" 0Z ,,,]-L2_JIIi㒔ttF999wegg'&&*~[JIM~8QAAmCv :88c""#ZZR+D2ef]]]7R(iӦ4.##^VVx M"HTUU}9xᤦzoڬīӾ|ݘ!@j8}3S_88ǁܜԔNƴںޛzWW}Of!`0}Ј JBTxz 3gMT ;/^ͫO2.\8>99gΆC^[Z%me^9?%,3g[ZVL&3:ֵH:x⩱1<>>]]]aaa~~~<~1B"#D3Lc/>m ց Ϟ==ẇ>y4ܹ3@PﯪbXZOuq >NHH/џ󬾡gԩjX22s'իX~Sk==--<"LPmeq8:{pSn^ innF ]l'--oN ܥ336ΠGE]}rccC0ȫR+ VvxYYYY),JKK+::رc#^СC퍍|{Y`0߈yP1߿:0uĉ@q/wŀ uu~/Np^x;m:h[5zmة0]]ݚjc PmmeDȑ#޽{{H3Zjttt___MMͦM wτc{^SsSݽ,ȫ VU]]vD9NVV惇q:@@jAG1knj1cQNF_߭[7KJs9p``vZxCsθZp"~_>ZDGG/$lDZVcXwݹzO{OIKOp#܋0 C ]._\iݩ+*_7'n e=:%%IrZpS<?Eu>!I l6;>QMMƍރW~HbbBjZ  -\EG*$Xq!L V ;i{vvv^0"~CJV(I+\ &++ G֐i/^TRRZΝ6FTooo +V?k|6Ï|K qwFD^AҲ'O:::)EZXPG h==ݿziRe?VQee7n^pl@PV JKKoܴ~= R]O%&$m5FTB|Y3{7<|?o,'dY;&'pS6!t:!9_*|>Fഫ׬祍]+!tɥKӦsv'ݹ}w[3l9郛/˗\{wwDlG&[VG5n$$&%nszzZgg˰Uggg~muuuBÇ'ff>Ynq̬,CCþLLR.\hcrL妦\6^8;;LcXYn 9QQGd)KINIŋTDSSS#ƆsJLJ =UEV2223fN#Lw-pړZN{ʮJJ~~=clW~g>qss6=zfkhO ڟ !I9%`vrt.+/Z`Pɯ;w `чoYOuemcmmYGd飑0{N_ec;::8::=]Ǿra'zZZW\ԫO_i0^7`D @dD @dD @dnlO[dRtU6!مfS] K D+XAuuu***^ǎX ƴiөB\||Q@j Z Θ>mH6v#pd0B,{+(a IDATD 9e$C#CBA·+UQQMu emmsBkD+ҋUFFF'O.^laaNˮ[&=ոw$W{o"EEEBHܕ3˗b[nK<&' U^y{MMM7n98ؿr-JV0Y Iuuu|>_JvT~L&Sp\Z/ǏV:ڏMOoee4?kTB*蔗?155~RA&&\.whNa0W ^RYYGy닋YSܾ;oH: w'Oy<^}}Kv.d0\njua[\nfV`47;>|Xp2nfirRJ[[[c#…=;\W=˻'Cqvv bH%Zm;W<= D%|*U]]-xv9 r.7uWvTRV3=U=f54ԧMZ bclmtktttptt{y{ }QXX[X {#䠐9}eKtAxܳ<G{GZ zF***ZZTWA!u\.* #.a|-UBH̙,UHD+ pu؝BOoS]!P]ATS]9vı'B Dl] nV"0|};ÆlOB6D+D+ &MASQ] Zx튌TUU rTUU?^edf^OKno[[YJJ8tJ_ŋTCץXK!JoĈ>...gϞ%L<񫯿ˣL׃{ (*(BF rՍ4*DV@N݈;QA6|~vlYB6g–H.D+Rύ+lYDC*ܸ–H4D+[V b]?*-$KBz^h{@{{;YqY[)**P])UKRrRzz#Յͧ7d2ݜF>7RN9VN޳T (#C7R;::$Z:.J[KYA^^WW74$L[[J\lJJx;xQQV15%RvH=W'Gnll`~TRRZhIΎ::ڹy9@Z!ZH<-L !~'Oh4iԱ uQ epB@)+)xY*)*-],(h8nIed4jڏl픕|MMDt34wqteMMQUUZ aab.^pp$h deeښh' Ɖ=GGE Ofº'$r(-4i*}uk988**(xY Cv$(#C3,-,[<5/bnnq_vctur:::Vj<1coLL`OC ee]ݜ Ɣ)S.}\%f:]]|4),`@W={WQQQCC?9>|Ã2PMMO ROOo͚u..G(hVVV#''wEB`2ƍ+--cUxLѶondd$##cooo:.|'OqF[ZZΟ? .477 M"Sp„5$^ƣ&(+،^c+?L&<999=. 2O M69::Μ9sÆ UVM<100pժU}PXXV\󄆆666/[gzyyz{{GGG M"Sp„5;2t=>mE)**R]T/]֮Y7RWG{R6P ^>ettt> 6BRSS?yy7=Ö-[ttt!III9{O6C-\pB9t„5Hu5@_#} WʧtttWZ>NNNs\-/˗/766޶m[h4˕mmm.ںZ>S}}UTT͛7"##3}}7MovعoϕWWc0g18shkKm[mmT0xk6cƌ䶶?S|||۷m+iddܼy^۲eKOO:/+// ѣ/ϲeˢzDQQQxYU & LcX;1kVpXB*i#Fسghg&؏_#m-z#tEhroF]]ҥK'O$ڵW^ݵk֭[W^m``@){Daػw/6001cF·^heXX`I֭[ggg'xkaCK*))MSC#0WUkǏG1zō7c~-Mb2^ڎApB^mӧOhaaѭqܹs_X'w->/}}}-='º@fco׭;}#Gʟ@!ZiӦ;8󓲢 F}?һ^___\beMs' ­MG)U*++ʪ:;;-9vRIhz\=-|>oMMMMlmׁOl=ո nf\x^ κ@x='NO;?455u|,-MMM{qp[H=yZ[_b>oK f &tv&;|{ŬR.0 Z  y0߃o|MMM.{:::<">I)lL퀿_ItrP'ODEmniʮorCkegg'''gaaP]ܜ~欷zӦ^s˽}fV6ILJطOC>]OU' Wh_GFF+W$''S]ظh҇=ث*%?z(|=z_6\^^f֬Yk׮cʕ+]-^^^>eʔ.$$bŊ|k wnAZFIMMٳ7z󓓓o/{4>9(@,bbb6nX\\rx&G}$//'10))ѣL&M6 ^.]tÆ ұk%Tjb!$""|wl.O<^X޾(]+{{Ԟ˖-ۺukKKKcck}ׁ[~%%%۷o?qℕw}_ʐښ|=aQq[[ۑ#Ν%w|%%%;>ldS`COW\y b.]*hoooWVVnooo޾m6>mٲ-!3g駟&NXZZJYbN_z-[bbbDu|>ni#wVWWS[Nj^6㲄&jK ܹs˗+))M:Oоy`### >ijj={6""wNLLTPP};|=ruu_dE/%&WU<{,<*a;pZ33;7;п`Z+n|| 8޴irn?S !&&&] 'Yp… !˗/_|h=5hkcǣYo͜wĭc Y9M̓:Ph y|55.YYeee!#aiwJrrg>} º'$UUu͵Uq+Wlh߷ORR"ùw.r@7ص`7nfZYێ>}$U<;xNT'Olmmϼ"U$dkj<\sssCCF)%\nl멄"V݂جx5uגR*WVWWkFG_[Wg'f.vDG'-#vٿY9sdλw>s6#;UTH+D+R*ps}OBB `΋coBQU].j *yͥ^Ď џ?W֭,-Ic u!ZHT'"LQ/^T:RYY֞SU]3HD+)ٙ[UU0K,k޻󕔔u+8N勪t`XxTVf> ߱DqgNutt-f&r@` `hd;316ڷĉllF;U]]ښq+$0r򫪫^z5yevn^G{YZ ґ?ʞ611PWk?r VGEY9XYYyٲ'Msjjj,_0`x89A A 3ay )8qXSC#VvSSW0 Auurtsvd0S&O]}Jru[[Neh@a1CdPSUcF+?\7N{-4A8:8  Çwݳ475###cgk(((HQh~&&&hjgde74R]W_%^SSӞ}|}>|W<1qv c[aaDh4F1bĞ={D;3!d(>cmfj,%,D+!`\M|JHXdσ&*Q'NTTTBs_I:M #WZ3~h|>ŋ7n aaޚ9`8ُ`0ıPh0tٷ`<@OO3gΈLO#L|#vڶe˗CϗKQAqubS?4?FZrȉbZ `@UT&0իW?}0?=IDAT_~9z<|ÇE5T:{\Iii#C6￯d2ƹۍa0s]0?DNN^%}QQQb]`},ĺ=q8@֦M"##̙*//Mh۷o722>Np ÿ %%%{{n3?.\hn9'?*½+d2ǍWZZk%NG=Zvϱ.A$Ǐ[[[3 ^ޒQQgO+/&ť&&HNY[[{ 2Ro↏7HDDD;wNMMuY믪:k9f{E b1bk++)q-!!hK:`޼s朎1'VaaaNN%xK,9sQ^^\vmlllgϞ򲵵^p!!dʕ L&S0'FQV--O7~x2V&.^S] S^ɆO詨X]]H\$H. gioo{2*韑_ G!ZZ :!!arIbwvvZY,]47/ݻTfb`ȑ=~, wl:-(hef:CCZXYyy|b"UTkk۵E:;;Ϟ;!ӏ ĝO.NifٲeۤIUUU_9mEEE|||\\ܼy!222Ϟ={}pϩ^Wڭ[~GǏ733#l߾b|wGW׿x[[\r{–k)"ޚ9㵾-C[[[twn;2 !NݾJĮ%$\KH 222Ξ*.{ܹ{>ys+o/_{yy^+++7]ÿm۶tm?zŋ<(xDEEmܸo˖-}𬖢biiॏpN__>*9ˊgٽ!d̙mmm'N755]bW_}zj777)׵brqn^̞:::nfY} U}jnni>^^¢m.bzIHHX r|>?-ƥ\gyN'!YEų /\k0t JpgZ}󾯵!*;/;m۱s^`0\ GN>c8O=XKkӧ x;JAk`e $JfV'}Z9ͬlϟ?b' =:vO `N9P%lcx8QMm{w={`~QDX+Wby<^ٓw^7JHD+!J[[{ҥ TԫohOJuvKٳwԩA>޾C`ssɓ>xywz Bz~z5v.]dX3OII!F6;#+ͦ"*A7㲄T6;"KPۿUVa =˰샿z5ٙr)`H A Q]06.JIIɼw竨 f EE'Nkjjoh̸1v$RYԆۋg]wJohjj*)}r +D+InjJL^qSS]HLCCþ{ʽ}+$NH0.!!1Qɂ!jX'Nhmmϼ"U${򬢮Յ>6"^B)b-x 1ɅҠ%)F1?~<Y$3p2n-@v˿{1%%ѣC5442{wO>VS[q+UTH+ZHg+%֕wy_Gjkk{XT|= ?MKkkʍEG?u\]];rgʹw PucRR-_U]┖~q٣aZZZw&tGGGUuMfvN[[&TZPXt|Qu51ӧ?9}i7^`Zyyz̛ࠩ񪪫YW f9f+BCG[[[jV6Vǎegx`EѨ3skZ) hW_- ;uLO>UWSsuq Y@ɪ?|~U5NeeCvs+ֹsg9N勪vlV!Fٳf- 7Zkjbbzv ta·zruv^z=(,*w+W=oޢE6 v^Y+mnjr`gd7s0Ȫ%9;B~ݹcvggBHGGٿsss| Yb` B, ~P?1=Sw? 9_Dlٗ_=wNEҞk]{oegN·n=w+,@T婮HrKK{{֖clO:QT\4~NVWWfʩF'heeeE),~k+?'/+iMJJJޠ5+WeKUU!d/9yrʕ]U_Y ʾEu |⪚ZWܜBH[yv;;;BH_umed$<.flf1c! /v36+GTWP@u PSS{-1aΝŬR+VEEEcZYZ޹ڷ}u=!$d|ajj-|bnfֵ#"8Η}fcm-++?rG ڝ<O>'<oWddDbϒԢw=1񛯾pzXrgHKxݺ_~y·!6&zməZT\|:vskx~Ʋ+ FB\\ҵkrL~X Hϯy9@KKӍ/^LPe֭ӂvY^^!k֬340R @dD @dD @dD @dD @do6p-`07oFmXH׎VMMgO!uvjoo|Q.cD+AD+AD+AD+AD+AD+AD+AD+Ax TW TTTt:S] }ŧT %?dz xIENDB`muffin-5.2.1/doc/reference/clutter/constraints-example.png0000664000175000017500000001406714211404421024037 0ustar jpeisachjpeisachPNG  IHDR|sRGBbKGD pHYs  tIMEzrIDATxW S0Fmmv\.jW}&Ԏvu'pu4cd{6QT@`!J8UN`_RIm\wsgEIfc$IFGc6OǓA B!@ta657&x`V B!@ A B!@ A B!@ B!@ A B!@ A B!@ A!h B!@ A B!@ A B%?yk?)<%UVTfC]]6ԥ>EEE& X+ݸy#w>jB%ÊCz%I&&&іs9|øzôehh(3ө́-]$x)).{T~P(N$}}\GrTJ}}}x}䩓xzݔsuDKƢ;5|ׇr+yf2887$IՊlڸ)B::{ 47Eo/) ΩSyЯ2==}9stFGGlMNN-IP,nEpÆ Ӽ7+3<2ӭy+/%Iۓsi4733sIMIޞtLYYY=/kVMEEEzTFFFrN^}K㖭o|Hiii۟;sDKƢ[W5פ,֮Iks֮g歛tޞܸq#kVk$>^5s u^Y"7o;300'gTjjjS:Odbb2^Lwww/z1߾};׆IՎ*@>Ƽw=v$GIl߶# _TTsfs}'`44l̞9}5ݿX'x"--U|P;wLR.dff&us%];?9V=$)+-m;gi㦜m;ѱ\~=yjSYv]4>SYY^MqTKBQG'=s9~xvڝ L"ߘTW>ڻI򙫁,dkoȊ+|C&Illx\B_{?cccy凯366׮UO'EE6t-vDKƢ[^5S'zu ¼?[.^kC?П }43}dʕmGCI_񡏆222G D$Illؘ噘|}&mm)+wm^ӮSS[պsCH^OuIXD6=_n0lYy-+GCim=mK(ټy˼}vnߙ?q|Rms$ExBfffR>ZZ)UNe }ٴqSζh_<].[>öoLYȶ?ПBX̎.kK:;ٽkw|U3ߟkviDwO\ `a%Ku≺VXxB0I-[g7m={}h_#<\\\#<% ՗dX+_[7355y͌%IVTeM)LywwP(a.?~+}}LPpNʛ~^wș3::$IooOd"`Y+6lȞ潩^Yᴞn@ζK_y)IԜޞtvKtH4n)++˾e굩@ZOHΞ={8o{.gҸek*+E]fX׿Y&eeeYv]L ]ۧvU?>7o̥˗ƍYzMV^$9_ϥ&O>d6?9/|!Ir+csy\&dd`I[t+L\O#lrr޾{?Пlmܚ$ihOj`&I=#G/mkoog||JUUU?˙ٿIrje /t'IZdcTV.D ܼ'o7ikoKYiiiWS@^ٺu_5 {7^0,Y{mlYy-+GC'uR:}қl޼e>;L?q @y$bxA B!@ A B!@ A B!@  B!@ A B!@ A B!@ BA B!@ A B!@ A B!@  B!@ A B!@ A B!@ B!@ ,mEIfGGc֊ JA B!@ ,rEIfM<ÿIENDB`muffin-5.2.1/doc/reference/clutter/animator-key-frames.png0000664000175000017500000002724014211404421023707 0ustar jpeisachjpeisachPNG  IHDRsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxip[}6 v}$RWQD-NNlKJ:vY&кNۙwin8Ԏڲ7J6$J v0)@I¹]sϑ8N<6ͶbdNS @'тrJ$nW*rUm,yBL?z^uuuI{zz`p"""zL&CLL ))))))fZmoxM&ӯFя?XۻdEEGGȑ##Z L9kj\[YYYX"""T*EqqSRQK'70L;}4ȇ9>}Z]QQg2~5d?R^^>"""r;Wkf}Q #ቈ8N|G!f)m---ʾ>k#""9CKK6fڪ("""Vf$X,;O .b)d9===BCDDDL#u:J&t=DDD4O6 NSnw"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u""" ]͎T*EDDl6.dB.Z+Hzj!88###ECC&&&ba8V#..2#k6Ԅ3g@G>u7|6mίO'==r ˗qڵynXXo"44ԣ-''ׯ_|ίpZ uRqF"** cccFCC+V@zz: ja1<<\v Fq -0 jlhnnRDll,gju% jZ,iiixg!Hp444b -- 6m֭[!JQQQ1ו@Ǖ+WӉlݺ:>,}Ezu1j#<<`2 |Ÿ'ARaX~=8qu% Q[[^ B*")) ;wDHH<{###.ibcc g8{,8,n U*-(\^YY 6@Tbըk@488~DEE!**8]@))) nǧ~>r455 f|>444vO`٠T*Fnn.MMMRDFFRGK,33`0000p82mٲX,0wqRtڶz oکj~]Պ' tttR2-XpgZ9mJ3Ixǀ>ۓmsz햖8N!11ѣ=&&}|vXV( nm |S`` WL^: ׿P(!!!`ÇqU6c&L&sqEر>,_N8NƺWTTx'PZvwgyJ>FEEM@@P%ɠT*,A|T*uz@@UVׯ_›MO"JhtKee%o>Mk3 =|{f֭P(Z4aN;SٰluݻX,rEEEĶmZZrf``IB1P Պ8DDD $$'>7A.B=55֭\pccc 򺴰ގ4msׇO{b@ף/"""g[szmZFAAAoT*|pQd2TWWܽd2lڴ 6l />=|>2AI 1)** %%%FO d2;tWv \t kp\i0=7?X,9}۲e d2zzzpܹi_*v;.]^T[R` d Cu8|0J%M\Ait)Xצ|hkkg}ƕDcc#|.!$$dڶ eʓ"޽ LTvV랯`._݁m&_Iwo` t~MKKMBBz\phZtttرcJԏܾ}v9997n:+rV~~>6l؀$pZ-o5 g Vwٳp<3\_¼MPs!wɹ2RSSў}6~Pmm-RSS3=>Hvv6׵ǧ J {`=zZ]]]O~l6(..\.ǃP(իWtƍ^qF֭[?D[[uҐb䠧NcMww7.q u577cddַcǎatt2 k׮u\]]\B_|pԩi#5;M&nܸv}i'IX.\ĺucر6112ܿί+H_(¹s0888iL&|طoݽ|(++cǎaڵX~{5I6 7o͛79IFo{V}m`0 ((2 NgϞEMMT*~ =ztV~x'8XVtuuO|www{h$$$ &&* 0 ݻwyqRꉓJND"0?_}g3 yf!""& zO~p8S6NIQt?|SkkUTVV>9ñ("SxNDD$(GCH$DDD"P'"" ~cf3PR~5#/F@`?cV+ tu6 SV&ant}@ @&]Ҹ8`j`aHĚ6׾JWq \TV?N23b~BP6pCnw|g> Xu0ǁ? sdzbzO!1i )}o>H##y۷/tlolҍֺc0 l:fGڇ3@x=3;Wu5GI?_Hg-'9@EpEKl6LP*0PV66O?]]&&O?uMrr0>Hx9Ntb:}@Z-_Flߞ( PUՋwީzϝV,D""#5ބ㐙QTUW5׿HJr'U^򸤤`~lߞ8p VlWxׄ♺-YWW7A!!AgYO>y/!N$kl$'ڵ2!8|8g_xؘk&/|իq<pg_hkiqLdru%Wq҈Iׯwƍn@^6QIc~*166}J'/_ oWf|nMCny3?|}P\c=1m~?V@o7ر{3>}7<e3 8uJݿ?vK7RkB"O uj_~z]؎MESӐGۖ-Q% //j+羳ybTIKg<v'`;PSWu{wsmۼI 1#o|L{;y_YU07֭^ܹuۤ$癘Ը&"BdgGu=hi>SAo.bd1CgT*\. q|zGN%&Π\l6?6k6]|\3y[߄'ZpDˌ̥6d^֌\$g Ê]лw\xYI g\ˮvx^~H#!X5X4a,< ?s-mm) C݇dwֺ4fTz' ] WV{Ҳ{52hGȓ3c4<)p_ k]'=o}Dl#P>q [K$@X~=ܗ x!L{a؈*$ ϣsH 'VըGFATn|R$%'/%Cqq ynbtu~ tAYEWԩPN.h 8;w܏9 DAp& .^Wbhddfxځ @;0!HgyoW(0w;xaL8xq sd{.LˀnGƕ+,/GcknJv[I*$T*ؼ7Á@ACe:eV+<@ rW!P]?$n u"?{G!!!9p]_qJsaaYrZ`@dk+"zD>7B͆fD57p|WFrrлbh1ԉ@G{&d24nۆm0![1$!!h}4zd𑭭}͆z$êVc?)?Cȇlȸt /#nh@́p 0Sp0rsі P"QGbdB͛HyFmhڰfcL D>*]?Ǘ0=}IE{NsrAHCRmadcՕ+h-[0D>&h`eeijhq[] a,<w;ىZ$44@56NL )]6oFozU'8*-2}vά,N'@u c0>ٿaUE"Z[MMnj!6?9YjC$44 Ih=^@:{uJDWf&B;; o' wA{v6j탉7W CH@}}/+s5];p&Q6k`kאvz޻EEy\r  ?!DY,Ⱥp+]վP!!ٿ7mBΩSH,} RP3KMR"P'ZbIuu9ycf6BUI RR0apaAEѣJ"P'Z,N'kjs쩆cbpII_, .ΟA(ƭo|=e-rP'Z!((-Ex{GMB}q1׭cW8%4څl(L&lX{Z匡N&֜=7!q:7J$nX)PzVę^?!==Ӊu}Z-%&-na7<}(.gC7 `<4=\҉ l#=#D Ck Doϡ4Y5zя0 PdUQ ZntWF$:<)F~~aڜ ׭ͅpEajQɄ߇zdDʈP'#Ӊ7׿FjeGW`Bμn}U|߅MFG_V&pUD@99ooGAi)B=,۳|v w }eN4 q:3 Rv gz޺((-ɟ\D38HqkΝlhONFUI Wg܁dB2Ѱke-:DhjVڽ{9቏j4۳_|ȸ| 2P'zjtN!֣)ƍs'foiYUUnGٳze- :#+^Eօ Y,}*)HdѬI$*)/a,0ԉD }}m`ۇl*pL t==K%,0iYS $44x9pfپvBh_@b}=C:-K҉ @ŋY>xTG =;gP'QwyǏ#hpУm<4{**` S*rl N)ױ"b( ! yM帻mmyE)$N'ԣ0tBEhxD#Q ِy2._nhD0P ^_]=2P'IDATQch߹'1DbP'@~Y< nߎ{7 @u$a1oɬVd^UNLxwYa :)sJѣ}0>Ua(.NHlVC&nGhW0*tYD NK.kKKfhPgZ v+IOG\c#?l*P%4}4RǻڥR4VZ I:֬qzBCCDNNt"M9{ ɣ} 1U#@u\tgd:;$: uZT((-EHwG9(u{57]lJ%zl}˨.)*PECH޴anR)P]7RXh"Z8 uZP+_G}))*)HTrוtD?xÁq{,PڊRz{=LZ-jC{N}Atb--Hhh@ǚ5BE GGs$<iB!@uDӍFDiFr{$W„\.peD_CM:1׮!,ii*)$¨ӡ~n+#z4'a<6G@mق;۷+|^[n."z޺,/)8֯2cӬH'&dCfz\0.@uDs߀zt1` FWF͏T45aߛo"@ ŕ|^zN~)#$6ok2a 6!Ν8ӟ+3S >BK/^-f5qa;yۑq22.]Bޕt%%0.vwP#nO?EHOjS u&Ǐ#phȣm,, gJ*#Z\c8k VVT@ۋGp@ u "q޻6!nQlC]˨~uG)E57co=$+$\͆rd\ޙD%-r9 11>}CC;n^X.+2N`h@MO2"5n Ct46Ba2N'R؈b4['g#P_/+CmvwvM:"ѻbN;q0PHBUI + eDfbŋXYQĄG{{v6j)8X|9(^x-((-ՅT4n^- e"'OB=26,}aD~aZN#edojiATK 11hܶ YYP>"ţͦT]hڰ!YphAfy9kjܽ^!==?";4֯G[n.AAWLˍh4Z %Xu?|hT[y8BhW2._# xT $$pF79d9O}D1t[TEED;niAHw/҉ D! pr9їXFD‰nhV~*kamVweZ|P|}jW zz7H$` UяUv}6r)" gR)##>[+PeD4YYFG# }}C56N' zY3?tA u?Ts!a Dݞ=j'{fm99hq?&7O)eŏpw6(L&4{^DΦRa0>eK A=< &c uc;w ] )b4<BB>CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :H0ԉDNDD$ u"""`CH$DDD"P'"" :HH%E. ]͓\.D"Hv{]LL Emmanuele Bassi
ebassi@gnome.org
Migrating from ClutterAnimation The #ClutterAnimation class, along with the #ClutterActor wrappers clutter_actor_animate(), clutter_actor_animate_with_timeline() and clutter_actor_animate_with_alpha(), has been deprecated in Clutter 1.12, and should not be used in newly written code. The direct replacement for a #ClutterAnimation is the #ClutterPropertyTransition class, which allows the transition of a single #GObject property from an initial value to a final value over a user-defined time using a user-defined easing curve. The #ClutterPropertyTransition class inherits from #ClutterTransition, which allows setting the transition interval, as well as the animatable instance to be transitioned; and from #ClutterTimeline, which allows setting the duration and easing curve of the transition. For instance, the following #ClutterAnimation set up: Can be replaced by #ClutterPropertyTransition: It is important to note that only #ClutterAnimatable implementations can be used directly with #ClutterTransition. A #ClutterPropertyTransition can only animate a single property; if more than one property transition is required, you can use the #ClutterTransitionGroup class to group the transitions together.
Migrating clutter_actor_animate() #ClutterActor animatable properties can use implicit transitions through their setter functions. The duration and easing curve of the animation is controlled by clutter_actor_set_easing_duration() and by clutter_actor_set_easing_mode(), respectively; for instance, the equivalent of the following clutter_actor_animate() call: Can be replaced by the following: The default easing duration for the 1.0 API series is set to 0, which means no transition at all. It is possible to set the easing state of a #ClutterActor to its default values by using clutter_actor_save_easing_state(), and return to the previous values by calling clutter_actor_restore_easing_state() instead. The easing state affects all the animatable properties that are modified after changing it; so, for instance: The animation above will implicitly transition the opacity from its current value to 255 in 500 milliseconds using the default easing curve; at the same time, the size of the actor will be transitioned in 500 milliseconds after a delay of 500 milliseconds to the new size stored in the variables width and height.
muffin-5.2.1/doc/reference/clutter/event-flow.dia0000664000175000017500000001067714211404421022101 0ustar jpeisachjpeisach]s_Q^ta&mg2mfE"4 $[}eA8$L!bA`{.-V| |:J|Xߞߝ0[$Er=XӫӧO(_%e^lqV,Kά黓fIgO,e:Z&ӋdǼoJj-7ͳ%RZӳa67<(Cc2ˡoҢ~|"3OdR++=:vJ뤘/kU"M)Cm<\] .V]1&/"YU^y&JkYܦIfo]fyXq(|_&٪_Cy~p7$i1+?\nZ\d鶳_,뿎ޏ_5#%w8-ևӣ8OB~tZ9?M}?>6Xޞo^Eh=@7]4-~/~qQ?vaO?Yγ:>FFXDL8CBDaa,>yHЏANύz"ӿJ T7ey1KGsy^t,6*6#TO[}d6گeʑ~G95D |Q ~o>,<j#ʐDž"(EP*$AAFL0ڃqmPkStS8dC9dҘC1d Ȑ(ȼHP(TT e*=TLlVT LAtEv" vD#F(bLE~M$,-ǽa(1@'XiQ 4)OoutY(CX52f\ϵwq,.9Fvk]iSCrN HV1-˴\ x8p+¯w(#6IA,)ش\@2hkT!a-Vi*bu1)o4&]~= u B؀k Wx 0)bPĠ0_e2O# ? 'ĢS$ERZقC"<Œ`ȓM,I3&QamH\vB+҄h){bˌ]N<`re-TT2AZwN4`K[5 s_CC>F\{7Wyl_q p/+iTذx9K)~gK0azhŕ,dP-rLmk>v\_y9{:YETT٧`zS?m):u0 <)S31#gr;*FO-5ea]]GtWeeͶde7͟ڨR A걫,lBT1ɜHQ4|lZo]<@.IIA@ļ=[+ncҴ8..84[Lx38 fT1 g4*qReC" ֠I& @P 4p6Ʀ{o6ѵ$ĐZC{IbZ8< ;Ϻ5F:Q &,Up­BP8# #:G?{JXai AXruT{XJƭ׵2zA jGK{e\nH3G?$CS tXlބnC&6o-gKs(=V؛ۂVcԛIi O}QLkܾNʾcIk^>fH*/|奁KT#rCg+J{-#&1 ^dFDܣ4ZfTɄ JʕKHT`P"_,"ߑbDƱ*!40Cyw'~_AaPk*"0A?vB0DiJZq{|ߋq@O1 A=azZ;޺ICobz{0`9D EZk CHP2G:{#:oѩaw(SZҽc W!NtNtxMn%~^FD5޽c |4x9ͰӻeOGnWưYUM\&#*vEdM4y >7#r81![=&2qm&L LRP}C+GD7r1F^B݌eu-86p47GzSZtylOd+lEj=gTc8H֒y Pťap`T,CSB Hʊ#%e b%IYMqt`rj( Ja[Q|6ΊźA~[G_X?vƒǰx~!'|3p`Ib$:dNӿ 6oפ?|g6StHL8vBy@pEEy"xZ+}L#cC$qDZ}ˑg  ;N`;2 vrؐZb)C5.nܺ;ԉmŬjr1oy 6/oqd?hJS HasrR5٘fP\;M_, R-wl eNdR)Fٷcv[i1 y>C'$x  lHΝRMVzE}춦`ZtPaاF}h46l߃KQ5%Yu]]@z#5i6˚TӉ7N6 ޝ/qyi5l 82U!ܔE:JVi JB%ocX"$CoQtU4 ܝWiɹrykE^p{qE5TT=}ԫQxmII?08.Z(k7/"-ڎ4b0aym4 jA߷}CA0e5 L(bc:4-us nfFU m» ]vބ/ ΦIVA6i]( image/svg+xml 0.20. 0.2 0.5 0.8 muffin-5.2.1/doc/reference/clutter/clutter-overview.xml0000664000175000017500000000522014211404421023370 0ustar jpeisachjpeisach Emmanuele Bassi
ebassi@openedhand.com
Overview Clutter is a GObject based library for creating fast, visually rich, graphical user interfaces. Clutter works by manipulating a scene-graph of 2D surfaces, or 'actors', inside a 3D space. #ClutterActor is the base class for such surfaces. All #ClutterActors can be positioned, scaled and rotated in 3D space. In addition, other properties can be set, such as 2D clipping, children and opacity. Tranforms applied to a parent actor also apply to any children. Actors are also able to receive events. Subclasses of #ClutterActor include #ClutterStage, #ClutterTexture, #ClutterText, #ClutterRectangle, #ClutterCairoTexture, #ClutterGroup and #ClutterBox. #ClutterActors are added to a parent, transformed and then made visible. #ClutterStage is the top level #ClutterActor - it's the representation of a window, or framebuffer. It is created automatically when Clutter is initialised. #ClutterStage is a #ClutterGroup, a class implementing the #ClutterContainer interface. Clutter allows explicit positioning and sizing through the #ClutterFixedLayout layout manager; and implicit positioning and sizing through fluid layout managers like #ClutterBoxLayout, #ClutterFlowLayout and #ClutterTableLayout. Actors inside fixed layout managers like #ClutterGroup and #ClutterStage can also be positioned and sized implicitly using the #ClutterConstraint sub-classes. #ClutterTimelines provide the basis for Clutter's animation utilities. #ClutterActors can be animated using explicit animations through the various #ClutterBehaviour implementations, or implicit animations, through the clutter_actor_animate() function. Animations can also be defined as named states through the #ClutterState class. Clutter further contains a number of utilities, including; #ClutterScript - for loading 'UI definition' files formatted in JSON; #ClutterShader - a class for applying GPU shaders to actors, #ClutterModel - a utility class for MVC list type implementations; #ClutterActions, #ClutterConstraints and #ClutterEffects.
muffin-5.2.1/doc/reference/clutter/actor-box.png0000664000175000017500000004277514211404421021744 0ustar jpeisachjpeisachPNG  IHDR8sBIT|d pHYs 7˭tEXtSoftwarewww.inkscape.org< IDATxy\Wa.o3#A$\Hn/R !u[g(T^£8$BxXؖ`Yҙz֙$>=_JR>,,XdZ3Ǚ {4<V?Ao |I{ff ""aBoo8?+3}9~x7JDDo>}w˞VArqw}j~nFT*ϼ y3QG=# /pR|X=2i+_Pو xi@8x1UV+u\Zűc_j!P*~HdDD=@T= I4_ /$\,""^xi9)e"".Rȑ# T&BQLMMe , (E }JCkoaa!Q-,,@k0 cb!".Z\\a; ۶ B!".* m{0 0Qa0l<+(qV "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "!P 3bR9([Q_'3\Hᅵ{C.!@DbVߠ. y@x^10Fc !b``lp,`,+1u[ L,TCLϓ .X-XhVDX ̖-zpL@ \7-ó_\N.8x欋;W<hFJWYGhF  [vVpʋE;̕c>nY]񼅪GNd蛰L@J !^ kYY g$-]+P5 Z+@k`HwV`,=mϜ Bo(L|dY7/y86gה.ZD!w$We(N[xl?:kx DOeptƑ7l;x] q*2ݵՏ~(c,'1S2ԙ ^ug8l+ Yk(OҬ pٲj$pו%xoۯ1Umym/0Ivg^!*qo ku,8xꌇgf3׫ ^ǾP82ι񔋽!n^AP*kZ +@㵺LG\-,7`P)5>3\KkD58xE5,CcpfmYJ䂍my~Kh+;E9k+j2h& QFw4n^pv|^C#F2^ l0_Ueg㹸e"'w_Jk'} !a-;} g^uwuR`4Aވ]AV8|2Jh( ܾ&̚k0Įeuh\3c<+qb^G\>9G՗U qfYU#OHܶ' !&Wuh-pˮ*&|e(^5QQ7`4Œ&`#qƲBQ9g'\DJQo$b:>&JGBrdW~}`E15F2 `bAih1m`e0lSsU7 Fcpxl˟JΑF8{<}!@xݮ2#%pzѮR(@uo#YrL(-$F^`[ne}nt)® J *" \1 ӊZlAԧ .Tf\9~r9kjr pDfC3b,\s^hj3trW֖oM| q`$Qm^ֱ0kV_tK^Yl2H4kP]#([}#!98`40܆9r`=8m{ʨFOzX=pT/Fl~/ `AO#gL q/7I\9cP?gQA;^up`jcz2/q6?:tb9@Eˑw%Ʋgl|Yl(/8ؖ[{@]UH{K5 {X "j2AbsB4aXV=7.F*d~yD[R!@Db "cC(]ye"Vqh-T <7\D)eH\1c0(Qtd3g3|)ph\žUYQ7;CN/ZxX䂍θ+* %˙ =Y%6Ȉ( )ۨFZSN"",ނv\l}<np I'1: lr*hN<١ў={.BbwP4{ _8ݡ][0 78nW7^B 0!6QJAk (Zk i(i.ֺQzYnz,˂:]]zN{oy 9Nxn?/2p۫`lr1a<eqض x~q ZB)Ց md20M¼!#a(jz]l/7ګu*DEðurݶ*JE\6e<ضl6R9Bvw=I)av/nhZNT2 q.Z=4Md2d,SGQRj裮;h9\.4!2 jkuZ,~cܣ~D/N @Ra``k}b^|E;v ǎÉ'!.:tߝFQzKe9(WTž={}eZj )V@/i}0 8XBujY4`ddmo(8 X|'֐wy} _>n_|emMI+~n>Ck||333iԿzR###MOc3 >caaa|>1>=d5qz.!`[}گꫯߏ}{}wx_mo{ַkR <v؁뮻8lteJ Pij> 㳟,Ξ=ӧOoo0<<}C];di?CwuWWDc4a? yl6>>>ERwߍACPϽe|ӛބ)<3+mMozwb 'Yo⭷ފw׾_ex~mE!U@kF`4a.\¶alpqסCpM78rN:;cs;6*bR 0lf&q`d2 ϙR ZE:a6vDujf2@thhJIHP} }n޽|=ET--A/n!!,+ 6l6vލ뮻= p@]AJA>dE]ߊ`ٮ: 4azlt"0.gB>Tb:uE[]wJAVr,S˂Y.:m[`Poc$B< /cǎ>9\y啘\\PhqQ?V4 w50{p{3:{ַpA<#عs' R\b\>z3M50{` v"[OE0\q1]:5juj]N[u\Ahi) ُVg}N/Va$$]pK_ԩS'?b3Y.#q׆w v0|AX0 q]?{*+'-%d[F>LV.. Y.#Aw53V˰kuLmkpn||y ZƍBT. :m! g]p5qpB.њ|ݻqСCx+/e /V+BX4MoٳgM(j>֡|\MӁCOdpa!neԲ:UhTtUssqK:o'Kх%e> /?яpw-oyK}O~~qW#*9W /?y~ 5~%ijG!ϝCw6X mG?7|W _=GV+X.&EGFV|m||W]u9rѮl6;wBGTB}Rò`Z?;PhLШ0^]4!o{4(`n²n~Va<1pLO|߷cɟ Bթ)?Zzz\#\\=4B0??Gb׮][pM7n v͊b\MVש54RAUnxw3u`&we6vuYͪ_HT sOW {/ W_D_ֈ͎̕ 6}alM Ͷ6,.-]rRKBw>M%eMѺ`pfeN‘#G׼rE/w 8GB!hRPgf` 6=7?ZZ;5: !"MR7 !}D+XԊL-U@>{1y_dzY,M@C :-Z ,]ʴPhlMYM}Of2J5,\Xx7к;?"qNL{.,9–@@|o3tm[N^:[n⮾ۢ8TZx&[J5Ի} 6Ahb.H6h$+Mבzu^se߷'UVWoV}c wuL90HI4hA䅸ݴn,c= ~ݘ˩71]bS; ژ&.ItY%m-5!@[ '5!@[ [DMaCv5!@[ -0hkaK) "cC(p`) Z80LQ1R!@Db "cADMaADMa–QS%@Q1hkawQS;) Z j Ct`8JD|T4.ZBB@ˈ!@[T U!_WÀ!@[LΟK}(E8&@Db "cC(DD) "J1äTBKt1(NB!T+R f&wbf>aIR!@Q *[5 HDCk0DX(@Vaf2IR!@&eDY*AGQE;\58{p0n쭥cPsV "…DwlUmhi RVax^th5E+-%9D"tub'TNaK6Lgf⋿RIg몷 UI0mH"S_ohLw IDATkz:tB!J/u.mQ 3]˂0wӌ\LBBZR25tA~^P0hCk ۆ8ip_-+sy0V^/"кP *V B̀Қ csmC&Lσq. iTqZ?fBea|ZjmCz]5.]g:1apq1)q>`r03##0=g gl ]H<4'Z!@1j=d_n L4nwr2TBX(p4 u,,\¶alUBx`0Ҡ>1 ۆt-?y0<f6 -%bXDԘDkYA]k` V%, ².T>#}D"zRaPgð.M w|QQu0\.F|V@6 E>̓wg0m#{7ī| n܁OMU@ۺqB8N/FXxjlt`Kڢ~}[x|@U*!Uh.60e.N0mC6T fZMX2]IY ͨ 7 2hӄi"wo|G̞=`f&P0hSe!_˼; , Qm1Q;S?w q'']v|>P %@M13L| ua0s9h:-0336wbk:L6۶1uC6Fb+l ǁϳۍ:mzڐ񙿜u]DtQh bK.ɝ=*0x`;RLF6R[= J!\X@I!¶DMJ֌ Z#Z\V V>wr2L\Z6bH+!`f2bٳ.J\6@JY|<JM,W=sBoǨ 2l9o0RYZPY*%ZamV9ĴQ j쒙ёZ#*P=}:2V =j@ BJ 颴UJx! )d&MR\ Qܹ+1$@ %}aPaztAVt ]C mL3ACY.oVV d%@Ht?qD^w:vt&H$MDUlٮ…D~:+H3yȔ|Q: ێC3")-""o!a@$xAaw+.B)lY.*]C e(LXr:]TgEG$yAdzAGtR[L;.!2Iv $? ]C m $BRɵi@lP.џ@I((]C(ϝn8@?iu_.Z\]Ce_iRvr9ky@?iYINULm$)۫#$9WLDDq S*hC}DXV IefwRV*مj}-[$n>Z3] ][Z c8N]# D_K:hc]J^  Xɽq%@#4[R olz^jf Jգ$@iKK ]LrL@?= m ѻCa03=]T0&Z Y$#eH ǁHzL' a0=/b0D273Royr-;Kfጏ'J 2CqwJ]BQ!c@h;aNL$Z-%h P-LDx[n8=3¿1@WJ%CLrinv12XCC0s}[GZK BT,&~hzÉe=4cbE>2ukAٖLOצRCCɖ eH~ :A0BO+B2cugge!o_[{h DW ӆ1JP;TԊRgbdm7-i"oA}!Zt*OOݣ"wڕ쀱a@62{"{wOZMUDU*!`ob`QXV6X;<36aUڱj=tI.J0V%!]B%f.Xlyp~>!nEBO d2d2ka0 ~ccECw1z@`!V.(k"Bϋi7Va !`&Lӄy5E(B\FZe tALl*ӌgcc9 ՞ݻ'մVya,d2yض 47UJƖ@6frG|XDT,V --AU[~&U->~`Y<σ8CJѬ>zE6SW\I I<lZjf ˂50…e2=shJq mv]aN+X\\lV`KGgK[ʩخ}n<yWR ճg[sl㍱jCǔJxNLL\FI-]@|5eabb"j@5sS*dDi (p~B"8pA"@ZX,]]5df [m||]C-` VmAGd Yl\mfl !ЃRրŇldj t^VR"?3) [QA[ގGF:>3gP=sIѣϝyMB`||<)QZkՁX!`LOr"j (= Ur{M, p½)HaRʖF&k`J%>qΟrFͩ䮠:*F2q dk &lX_1){`ŇYUk,amCKKP 2Tಓ ێEQcU²`fBNͤкWgtBTb\֍й_Rw%G(BZmL5Ўi:l5fg C J%?s۴`$8reePH޽(8 fጏfA-B…Ry)'+03@RT*! 5Ad?xI@JJpFGጏ7Z?5󧍪g>.<[ۿt_h`v,m=< u۾];i)!Ej|N!d0'PG0\Z80 -3PJWgh)!eh`X kaۉ$(}H߇Cj*R;[4븣}R0- {`0 +P \,ׅ8fxaY~3Xu|퉤|R=V*ZZ7@s(`iE V>+,mfb#_=j0,+7e1voTVzBQUе3|uW 0V*E?1:v10Dm=.Hcjc@,B@XV20-FKsb_xZWCnRvlB"(f-?v"ZZBX(|wCjMB껍a=2d ~{[֭Gb]CJmSGaċj,TjwC`?!D{f.<B!z_+V*8;;R CCll n+(¹Y-q0h;!Eay–ejJ\30==agSV zwq~_ڠS?g^z !NoFVC`K[-HQJ<2o938xWc /_ėM,x]wuL/<'vī]pbf{ ?0N:O}Syw0+i{o}8s' ܉ ۶~|ıco}kʴq+iˁ44mߎk36]7|sDsp?I[v {`mL>Ǟ{ɉG1U;]5+?2J ZC)r7)9< kh(80׊U?nޫ>Ϸ0,~Wti_o~#\.>zMVbRlii=_0 Xpmw60xBǼ oW\Ǟ{~կbP<};-p嗑<첖[oE$%Sk'pff^wrfð!Ç_}Ke)<*J纇@k`d#8,fwax`t}8ux񚫯KR җI_9xN nF|r=o^Ý\P__pQgC UUnm[[c50(h|6˿ )%>/ߏAqC^zet啸m<7ވsss8/X;''q+Wpa|K_(>\&:!RJ)T*c_8p'& ^{-2{d({oxE˻߽}t}x'q޽__ͷ?|I` ۱#n< ĆDwҥqhʅa522ݹ׵=<v³]nڼHJO> Dzp7p8য়~d;k.%̐ h ;(a0xv܉@A, s> nF r{qzj׿]۾13R SOqvvz NL]5>, m8߿Z#"6&p(`YVcq  sy~aT|c)_C_tη R֒Gž;wGç|_'~wj}?=۷ um^s}xH e7SL/DQL?aPja "ض u&ywm0x`e!ſ~Lʂ`fnWL&"71w/NO߾uoV_~|048@P]UWr?u ObrbwᲹB&׿س{7_gҋ/??E?\.ӧO|-RZ"@5R}AJ4.vbRJ|K%|Ůj|O÷]t-;kE|u_77ww1;0À75^`O'xj}np '>($~zh]v'j!XsY-ӧO㦛no_50> ͫvWѣG`S{LLL`ddb??snKvCn۶mcZk,,,tvK 333, |vdWRj͞={gϞ ~}ll ^,˂8:<׾z+-\y jI= SJyve#H_WJ PTiA\f B  v}iPm#sz)LJyvC:JJ 5",˂m0 ir 6LJX ̅`oĻ:³/;H)EQcj?5eɣi6>Ŵ a4~Q,}&D\ ! JVFwQ})ӫ>ɀ}Qkzk>\ORRۇw{{o "ňR-.pCCCI(zL뮻mR!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC(DD) "J1Q1R!@Db "cC( :BQ" mN DDEmC)a %]""ꢡ!a8c(^L`\.׽uK u{R. p~ۈ?py^""N<0;p>*R{wU+uڻ`rLc~LtDD1~ꪫe2߫?|Q:o߾:f߾}8tТyw ׬{c8|O333X9DD7vmUq~wW<jg93 @tDD^:)y_L~,aIENDB`muffin-5.2.1/doc/reference/clutter/building-clutter.xml0000664000175000017500000002430014211404421023317 0ustar jpeisachjpeisach Emmanuele Bassi
ebassi@openedhand.com
Building Clutter
Clutter Dependencies GLib A general-purpose utility library, not specific to graphical user interfaces. GLib provides many useful data types, macros, type conversions, string utilities, file utilities, a main loop abstraction, and so on. GObject The GLib Object System provides the required implementations of a flexible, extensible and intentionally easy to map (into other languages) object-oriented framework for C. Pango Pango is a library for laying out and rendering text, with an emphasis on internationalization. Backend Windowing System Library GLX, EGL (1.1), Cocoa (OS X) and WGL (Windows) Graphics Rendering Open GL (1.3+ or 1.2 with multitexturing support) or Open GL ES (1.1 or 2.0)
Platform-specific instructions
Linux If you are using Debian or Ubuntu, you can install pre-compiled binary packages the normal Debian way following the instructions at http://debian.o-hand.com/. To build Clutter clutter from sources, get the latest source archives from http://www.clutter-project.org/sources/. Once you have extracted the sources from the archive execute the following commands in the top-level directory: $ ./configure $ make # make install You can configure the build with number of additional arguments passed to the configure script, the full list of which can be obtained by running ./configure --help. The following arguments are specific to Clutter: --enable-debug=[no/minimum/yes] Controls the Clutter debugging level. Possible values are: yes (all GLib asserts, checks and runtime debug messages); minimum - just GLib cast checks and runtime debug messages; no (no GLib asserts or checks and no runtime debug messages). The default is yes for development cycles, and minimum for stable releases. You should not use no, unless the only performance critical paths are the GLib type system checks. --enable-cogl-debug=[no/minimum/yes] Controls the COGL debugging level, similarly to --enable-debug. --enable-maintainer-flags=[no/yes] Use strict compiler flags; default=no. --enable-gtk-doc Use gtk-doc to build documentation; default=no. --enable-manual=[no/yes] Build application developers manual; requires jw and xmlto binaries; default=no. --with-flavour=[glx/eglx/eglnative/win32/osx/cex100] Select the Clutter backend; default=glx. --with-imagebackend=[gdk-pixbuf/quartz/internal] Select the image loading backend; default is set to gdk-pixbuf on Linux and Windows, and to quartz on OS X. The internal image loading backend should only be used when porting to a new platform or for testing purposes, and its stability or functionality are not guaranteed. --with-gles=[1.1/2.0] Select the version of GLES to support in COGL; default is 1.1. --with-json=[internal/check] Select whether to use the internal copy of JSON-GLib to parse the ClutterScript UI definition files, or to check for the system installed library; default is internal. --enable-xinput=[no/yes] Whether to enable XInput 1 support; default is no. --enable-introspection=[no/auto/yes] Whether to generate GObject Introspection data at build time; default is auto.
Windows The recommended way of building Clutter for Windows is using the mingw tool chain. This will work either by cross compiling from a Linux installation or directly on Windows using MSYS. See the wiki for more information.
OSX Before you start you should install XCode either from the OSX installation disk or by downloading it from the Apple website. Note: These instructions have only been tested on OS X 10.6 (a.k.a Snow Leopard) Currently the only way to install Clutter for developing applications, or hacking on Clutter itself, is to build it yourself. The recommended route is to install the dependencies with the MacPorts project, by simply invoking: $ sudo port install libpixman-devel cairo-devel pango gtk-doc on a terminal, after installing and updating MacPorts. This should give you all of the required dependencies for building Clutter. It should be noted that building gtk-doc pulls in a lot of other MacPorts dependencies and takes some considerable time. You can omit this dependency so long as you disable documentation when you are configuring the build with --disable-gtk-doc --disable-docs The Clutter Quartz backend is built by passing the --with-flavour=osx command line argument to the configure script. If not passed, the GLX backend will be built. By default, the Quartz backend depends on CoreGraphics in order to load images into textures, but it can also depend on GDK-Pixbuf or an internal, highly experimental PNG and JPEG loader. GTK introspection is untested on OSX (as there isn't a MacPorts package) so it is recommended that you disable this with the --disable-introspection. If building on top of MacPorts, as recommended, the following configure command should suffice: ./configure --with-flavour=osx --disable-introspection --prefix=/opt
muffin-5.2.1/doc/reference/clutter/easing-modes.png0000664000175000017500000014517214211404421022414 0ustar jpeisachjpeisachPNG  IHDR82bKGD X pHYsHHFk> vpAg"IDATxw|TUCK"%-D#MD]lqѵa_۪kŎ]uWvlX+"HC +'g&{O^rsSs Xj}"}z@8/ v/ y_@P~_@T7_,.....t`()))))I_$ H@8VTTT3lؤI&ӦMyyyyOaaAAAD;dTmBtzk9رcǎ;AР 6ӵٳgSRS=zhcZ\|r*_G2Y۶mfL6eeeećHAGB*[e";\~ƍ76g4hv.Y֒%<Đ!C~}'G5ʯ$Wue H=f̘1ØAƏ?ޘ&M">;E ɏR Uz=~@vbVݺu=wX@?Q Y_߮:,)4J?oNK hCU+ƍ7E!!W@&+W4fM65srrr>; ] }Zӽ@LtkL$ #2꽶,ĉl2eʔ)~%8 Hy;GM[P3fH-P <$eNjxq˖-[w;wl1$+́gz&-([/YdLm\@Hpŋ#G,x1\h8L Hk4H$@1 h"DCD aa)DFܗ$Vh(P@` XzD;F> H "-P&@A}+,q?Bj@DP:H0@زm\R"B`k2ċ-@ ?H "Th(O }[Áݎ> DbAH-D Vv!5"h  O .,Xю+H {8ACز/uV "P({H@uE{F[A V D~w53v@hǃ"|E@a!y u6{@?PS<#+Xh޲, Dvrd=֎Ԣ]P]-˴B)A@b!Tӎ:R{ޯ_III},9\$~!$ u5$@a)鍜o"qC@hH0!)KIo@0p=B{hGIh+bc!bA@hH0!)v%x4M8D, h:dk!xѮd&V >=P]ğ$Jf"rnB{?ÁgH4ڕ Đ!`Cu( #쭅3T:1$C!@g8L2?ҮdE Q@hċ84Z Q3$"Z&TXz TqD8e@@ C$ =Eز O"$S!X,)Hăb!hŊ!H/lYPS'Q$!R\$Ċ"e@u1DM@&H%{H$Ċ43(ׯ>[DC@1Ffkr\bG"(_rJc/oڴiS,x@B` @#B\ cĉlY!D2el1ހLpH| l$ 3|X hH">Ha<R؈+᧴I !x-~ PxTh`1uƇ a M Y@x0adƣB{s rz|X F@LTf"! 4+VXaL˖7oLD! CW[n}>,?D!8Z5vl` >|ߧKAzr.ġPKUEL0ըHŇ:lٲe +D KE s&ܸqFc"XPA++++<HD_S'UaP$v|C q ̜ ħnРAcn^O>})/NƩ}9Ըꪼs}w}~~1W^yW^iLnnnnn1\s5\cg}g̝;wܹѣGlٲe˖-?1Zjժ1{wذaÆ 3c=c9>`crrrrrroF=38 cvu]wÇnׯ_WѰaÆ /15jԨ1mڴiӦ1}ӽxU?~}:묳:,\rʕ 2dȐ!>쳏ߥ;t뮻Θƍ7n+GW]uUW]e?U*__öm۶m֘JݻwuQGu1wywGݿ߫-[lٲ1GqGaqwqǹ߷n1]tE]d̤I&Mḍ>裏3f̘1cdɒ%KxTGnݺu5gygs衇zU租~駟ߢE-ZS~׿k6nܸqyw}wӱcǎ;zU?>7vڵk68>z뭷z1&L0awݗ?ׯ_~XKOע"c?VNbʔ)SL1f]ve]9?pcx7xjxꩧz)}ܹsΝUٳgϞ=ۘ,\<;}ԩSNYvڵkϗ^z饗^c믿zUzo͛7o6I&M4_??s̙3g16lذa1viW_k ]ω'N8}qGo+VX]_]O__T{~ZqƉ'x'z{ٲe˖-m:tw>*ojժUV-cN>O>ٻ.{}=g̘1c c>O?Ԙϟ?ߘꫯʳϏ>裏>2;ü~@N_U_]~_~1ݻw޽{S9Q{EqݓO>O` swq^Һu֭[{'|'xqQ6:^WTTTTTWح[nݺyoj?. .]v՘ .\И7kk-Zh"^zꩧzwt5yɓ' / 4mڴiӦ^zfG*}UT=u_۷o߾1_|_|j_;μy͛g?{Ʀyģ>裏6?y駟~icfΜ9sLUSr 6KW/gygbVޮzn۴iӦMqٮP5n믿WԾꫯ7.ҥK.]4hРAn>n*xZvm۶m۶kU og:=Q~{1W̦?x~mc^yW^yūo*(^)`>u}O?O?{キ>ʱ=s=x?w>j|nݺuyoڿz衇2y͛7'gc9cOŽ{Vi;O4 D5jh{@7nܸk WѣG]+)))))) ¨`G+cǎ;v1W\qW\a//{ (aomJ@)K}>d0u]wuw~4 ug%B.K. (TA4hРAx tF5jԨTfk1}۷18psG}c' DʣJ 0%aʹ:oS%ꫯKȫTI 4)˾jUtU q]wwܫQ}%Dޯ?{ omݺu֭Ƽ{7p/bCqDW}u+]GMLމ%TNQ;%J*a2tСCzSN:u_ۉ*G:k@%vW?$O<^|IeGyGo6 Xu[tҥK \rc;%+AYa_@wڴiӦM;L5PEIL'Sĕ@ٳgϞq[%)XT_]&ohlOߵqř~:_šyxȑ#G7t=5#]O{{sI'tIvRiܥ=9o{{Y0xH\qgaaaaa1~~%5SQ t5.)‰#F1j? ʿX%M,+!qh-.P]TiCz GU}D[+ hE@W^*.}RĀ:i.:?g=s=U zՏVy6DjߢZX񡮋ޗ5xB?*Tm??xfS|¼|˗{ yon;(jk%((wW3Jf5pS`?w|Ux(cVN V)ZրO>}.>0BEOӟ'o`IkFI!r!x3zĎVj#:O_E %EE'6lS{fST{^W'$pQth!^Wɺ򧯺_*JkF3븚YV=J ZK/KހBow\X܈FYf͚5zT\jP}JhZn.z6/^xqdT@\E+n馛nĞˬYf͚UJR?wys9s&D?Z2Q"]GϪ/Dtv^Pݸ0G7W+]C&trF]7_鼔@ҊhB}vWn޹*voo8wv9{<hh?[o[\x^xEc=蠃: /Z&r%Z}FE7ēM/~jZ]MV@*q(ׄ&vY5AXz{Q3Z«^J]5lZSoož9.-VG^XE3q5s,5*p(k 9;C%:f.xuVuܚPK%h4 *fEf5&ShFR{ |z+Qä>Q[4TyԊ`V mՊhTt\{kVՖFu$!&:4@_RP}n"zG:D3 ZW@At\%~E[+0R-*z?N7vLKNrRW*/hzԫW^zUvڵkҫr-$֌]5/ L*aࢉ+%'(VEGOW5%lT:(Q=SDʗ]EKӵ:l?7K]OM*)*Z#ZA$%W[XD˲2o7|7{+rE+u|yR_+;Q?W?~W+jZ? 'tz@dz&҅37jZ~:CطijD&Qyq}ӊ`POOd6.Qq-_˿=1+űZavюo nW\(#l꿴^. i\w QC7ꏕVv\N ?;GƋ*'*?2܎mg>;NKsM)h하R<]4VOʝh*/TWa(jp}]HJʴkze]vey7\Y8AT`~ϞiR ]LJ"jP~t\*NJJ[RIqTBŦ:Xxpg :!S-qU15V Ԁjfe)PЀR+T.hN ]G{TnPP&j5@_ zrkk[WX[4Së[~iꙎ ^3l @QG[TSQ]5+zF%ӚW"T j4p@SG gm!PU}Jh4 hXQoښ~M~R١xX+TxVk]:/}u_Gs 4ՖK*~V|OY?W|_xxA%\Q^ j']/3;R=U\V"JWUwH{;~IqU%PW_SvG?;t}':;F[+O~m?M 8ƹ\h5T8VkSW?Jhgazmit| ʧ~_wTFxW 4ĿQ;omVl꺼ow^`V|gjNE a_+NTWKG:;ZiXھ=,O#{f0TSL&ڳD{ˎv e0Vw%rl *A'v ,vE"h BzQ TSgJa G!h~6k)𳷼އ/%U&jeWT>J=J=A-gh_5vPq(nW'(U X-jg\KVa@3 DN$8@DS] >= JKKKKKc};M#Dqm]6SN1bu0PS$ST5uԩ$j@./ZTPPPمC5СcƌC0XYYއ@h9h{;v2k׮]>KĽu3 M֭,Y>Hr0̅CS  ,^ܲe˖}V-$;Tj!D6L;@L-pZy@!ڳmF\ov<$$Ϡ 6Hk L ؙa*ċ]<$$ Ϡ 6nS6Fsddᐁ]"2S&xqG| p DGZq͘20``oLd: բ}hJ>61`c ([M BufL ;L .3lѶ H&2v~=jv={l|hJ% 1p`k pGLürcVCS.JfL ؚo<`@PEEEE|hJx0c Qy<ѣG6e˗/o(fӁzM:u}HWܘ+7p#P5Œ)j <feUVVVz+~ؚ Xiaof@ D*dI~~~>3ؑ_ A'2d5j(YclMl-CÁ"LJ*1K$HB@1P,:K$(<0T7QH–1 (ДBJ$@H_ T+;DŽCS D*ZQ8ś0~@@e :Ƈ'@\ T-˿]7>4%=@DJ3$)!H_ T[w AÇ'H)׌1 `0$QdR}L >4%@DJ0c.0@@!{/32H ")%1qM1Ph<+;6.vfjՊ|ul]xč C038+?" 7mڴ{eE܈D"" lTҬٶm۶8P+DC|^uc6nܸ>[ĊB@2@Sh׼_\b cZܼyf;Ijڟ^'Yq&E8hra֭[u@U, D;6R > ?*.1" .ġP.K~An+]N.ɓi@80th˖-[>B vPD[E0 [ +څ̴;N,uHt'g4h[#.ӧOc˳> )+++6W]g̋/FHںuܹs>; џ [Šv!~zf͚瞑G+۷5Rv_5*R_<9+++˘[k҃$쳏1|'|b̭z뭷k̄ &L7oۍ9>`︟}g}fL޽{mLNNNNN1??l̺u֭[gL׮]vjL^^^^^1sΝ;w1 6lذ1g}gmӦM6mSVVVVVf̣>裏SVZjU}:իW^ژ,c.袋.Șvmv3;ݳgϞ={1˗/_|1uԩS1wywi)r)ӱcǎ;zsذaÆ z><>1xḧ#FaǏW^yWzoƔu֭[s~7nܸq뮻z?1GyGi5\s5ӴiӦM?y}w}1}w}].7fׯ?s}w}: . ).....篿믿{ԭ[nݺUʏ >|s1s1ϫꪫrh|Ŋ+V0#8#ϫ/W\qW\aLf͚5kfsavaƜwyw1=zѣN;Ӫ 7p 7կ{{~NjTn믿WGy:~z/K㨝ofɹj&OqO?O{vAyD[HMBygy{7nܸkH_r%\r@.:!C 2=U#R[n[9?| O_?W^yW Fx@ <]t]u^غyQTE;;0fӦM6m~^YYYYY q{^{均*]gU tuUU|PqmvmUO?w}߾J)@M/⋽w]>>ʣꍨV,UP?Y1u*?{{5_zj}w}טcǎ;6}Pj\40uJh_]ձizA %:_%fM6m4wy >{{wD zI'tI'_%0yno&4[lٲe˼G}G?shOM_Uo_׵SN:u2g}gA?wy'|I8:tСC߮* u\uJkFFVz?W?/^QQן?^x5N}R9Pu~8Q |Mx)a&pԞ(#7o޼ylj=s=}_Chq]5 0M˔ж` jժUVyq~ߎ~~j"+8NW7NTkĶ5jݺu֭v@gq<+ Q;-NTF:8QLu]턆qbvvvvv~)aDʍ}4'I8Q?Z-NTyU8Q'*1 hqh{ޅ^xzDlj'm?zꩧzjz~q:#귢ʼnr!r1=C=Ml&+.m kֵ/DGupjFo JTt\ T*TT04hfu\x)í4uU֊]TuuQ%&M4i$CҀߞai^M<>f`tAtP>fZӧOcywyǘƍ7nKjK/KW k&EԾZx.5m\gŋ/~SDf8Hus{oC(c%\hU}RFʥʏViW~.^jN$h}5=F+H>OqJw l/j@qGg5-N}Rs%m8QC:5ԎDʼn'|'l믿ޏh? ~d:W|RSoqo(N_xkljw'*_h'jerqB5qaljZIT裏B%|L@]u\ 2Nʳv"QEGǷشbX#jʿDWZ* sԈ~jeЫ|~n`; W[* X5c7f̘1cx|]7WvB[EE++a-x4pTzBj[amѰz_ ^WWh]OvQ5:DCEQ}**/J+Zg]ҩD뮻뮫Y4ڢtkfJqҺ>j',mu@R+uvqʯw{+]D~':NT\8Q' !%wu'z+Z_ONU'jJ3hFD1Qq?+NtWSuQ9VĚD=R@Hqm%JZJSGhBWqe]veyq(NԳ+a-*Oj?5QS:_WhEKzv{~XEq]OhqXƉ:?7*hljo8QuDXD=JA;NVg'Տʏh8Qi<}It\XkD/L@O! DJ0ƺW3QJKT5#m0]ԀH55)"/Y[mWԚס"\hH p""}z@8/ v/ y_@P~_@T7_,.....t`()))))I_$ H rs+***9RcJJ>#?ÆM4i1mڔ'~K XU_ZɎ2$u+bǎ;vRA 6l0G=ژ-/_ܘnܸqccyA j_Wy;$lxJJJJ9LGaT ;C}@vp,Yo[oխ[ڃItC bׯ35j(\խ5w/%( M v!}uljV7n8عvo@l qXb@LC+Dk>UVk+VX٤/V qXr@DF#q0a .U iSVVVfG~葝mg4k֬g^LhD͐@DF"q #Q Cݺ͜9szzƒx@0O (4,"h < ]Ξ={7srrr>c@0O-4,g ?~}={lʔ]v,V D@ C }oH4>SYe˖-Y yXyLlH $A 2urtfcaDHgɖi[F@d"3TɔZ3t1cH=fa"qd| U2mVndɒ%iWV|kaEEVVV+"|@$ _HLٺӕiW{ݻwgaА@DJA2QC_}벽eYte~ɔaGIEb@C~QbWSNnYזe>]@5oٲ;]@DR0D28)UYYY}g d ?-ҡ… zgСCYnH ""(W@~+OL%Hٲ //X`zvڵt$@$ H_oA5ׇ(Aʖe~W Λ׶m۶~\XaDb27EZaOa)F>lhYA Y,2`"A2PG@дiSVVV&@ُV>BH f8+] .\轞5CxBذ1ͱEDBHsa5})+] ,Xཞ?]v>+ċb"qd\!a)Xӧ*AZQ> Rᧉy?o^۶m}v 4AbD2Ca)"Nܽ{ ~ɩ0f\c-G@ 9;H& @栾tъ>@ӧ}V.!@D2@ع,ۇVLO3ZޫԩSzg#H + $G ]홤eqLVgeUVVVzbDG"@@H'E%ݶ, []Og#X0 J$G=.IɴOOoi4'n$J$G=n\)[XH%9HH7!)6.:ӽ{O+AJrə@TbcH,*>|ԟ Ȯ_-[nٲe Hd_SdćRz{ȧ/Kii˖-[}V@zL yxoQQ$hdd2~QITEJv|)h_3-[F D qҭ ħnРAcn^O>})/N)}ԪZ:蠃)/>5z HLAG4o޼1-ZD>DcǥK.5}P]я ujGQ"- >h)r)뮻\s5\s1og}g3cƌ3fӫW^ze˖-[?ƴjժUV{aÆ 6̘?֭[n݌2oWC:t?|ÇaÆ 6s||'|15jԨ1W_}W_mL 4h`L6mڴicl 'p 'xsk9>_~UVZʘnn}dƍ7n4++)(((((0f=s=ѣG='SL2e1<#>ƔgK/R}mܸqƍgѣGkEEEEE1M6mڴWm>Ǎ7n8w}]cF9rϚ5k֬Y^}PBWW<ѩSN:3qĉ'Vovigvoqp;}n馛u1s1֟ݶm۶mf 7p 7xQMߟ}sw}W[.˼xrРA rhFǏ?ދTvڵkW/y?Qfkk5O>䓽vfSܭEZjժUˋu~jw{kTϫ{W_}U/.V\i/^xbc뮻ˋve]v+v;(v=R{5{ٳg3s̙3gV'W֭[nݺ?W?Uʕ+W\i??x[G /Z91bĈ#zv?ύy_|E/~S;vرcYzիrzg>c{{ϫޫM0a„ ,Ydɒ%pٮծ~+};oDʗ֭[n;JK/]<<rx__vN㹯ꫯ :NNNNNN/~5~y^+or%\r%^z3fŊ+V1cƌ'}h\񙮳k\zO=UTy}}o曪y#<#y}\qٲe˖-3fΜ9s1?ϪM]`U0=c=1s=Ę . .~_KE 駟~G t\D }9s9̝;wܹ_׿5k֬YƘ"@ѦKWUST@Yf͚53fڴiӦMvڵkz>%"Eޏ?"^_ݘ}ט8_aT"A ꋨAW"\i@Ví%ZQ[o0+QZ/%~~kׯ_?/@r?)D}~!C ]wuh;T 駟~駽v@?kKġ{u6 (ljtA_]CM=c=}0b'8)Џu_5ę&T a׺w)~'|'4F{/ )r7e;j+~V H}_K7oLݻwRUu[J ?r-hoQ\ӧO_3ōj턃{bf:D_5^}ٳgϞ=8YDy>i?ʉV>>ך(S\aOĤ;Md iz}q}Su&TVn,Q'x'Zy+J(h@ n4Q9`xV*UڹtvӦDŅI&Mcq(^T}WԀA8 MQU⥁vTDă%$X].h`iFtIv\NMQP+ 5T{@ӮZrG}U'-p w}w 2jtC] HKUQuc4s:_[`@z\ͬBeggggg{KS@B HKu|K*ڂ ,X}m%QE 2ѮG.]tQbRGUDhfW|*ZZo,.i-eI e4:V*/ TO%JF5M (!T=5J`>VZaN.Ԋ-Q;c`SMmRЊQP7+%=`% r_hU[<NXf%4@U9KT{ hpyh%۷o߾}{jfn%xT]Zn*/2xQO(@W= VZ;/GKmXM\_SJz&t|Ճx鼦N:u'Pw}j?BDS DŽ{z-Mةj b>^*J4MGOUĊ]c=СC%8+ןT9SFZe;oO4S"SUqd_xکFm-W*_Z;BˊPzڣDx\S$Ѹ^x -Jcq] 4Qvѥ-ź^񑎯~wc8}S| 93vɛoozJ!ZQ gt_hŧڝD3lvM2 PSCeĕHS-K(PkI0Ϫ`-3T앂JiI-xBA#Tqա)Qgu>:J4 UTD3J }QB3U ]wul~%~hj@X)QzrD*Jj&_G+T?T_UNuE ѺvyP9TCxqik:*g{K3zvWZvC_%4îz:hXJ,uWǮ򢄆DɰuR5yɓ'{uP "ڢaot+*ז7 T\[5@ߏ(FE;;YʓV@Q?k`g!*Vp+:ImY+fS@޿V꾩?T{~V z]O%FbNqG o\V)q"zʷ W{Z1:383L.%o)VDǍ?;UbFU?ԟrJ`iŗʵ%N]I޿/u4ȫSe [J (NQ}GkퟻʃO%U0Q9S9JqNo%^].ES0JPzk2ms+Z1xAKvBKR[@аTZ駟~%E:uo߾ DHS{rʕիW{_{p…~5 hH @:E-^{a/D.?HϞ={z??YfV.` DH[XZZZ6mڴ^Y۶mqcݺuӺڵkz+0"H"0?Æ ٸ^z3iӦMۺVZ۷o\d6ftYl2)ZjeR앉ZVf1$ ~h޼yskeׯ\d+3vM je_zg+36r0/oӦMg5jԨQg+3`gH @}UV^Ϟ㇦DVfΐ@4ѡիW{͋/Vfΐ@4ѡÎ+ˋ8le DH ğ~jҤIVfo@k$)lXnݺ^0^lejABMrۺlc+3RpذI&MHLrc_rsssk~\2:uo߾ݘ#9z˛@WAB^hQble{/\p1[]v5k$"\V [E'Ϛ5kGٳgOc;;Θ߿oDbb@K Da+3C}Hgm۶{Æ۷oD-|駟z[~z5iРXZcoe0`Μ9s?I00; J<(#>}ٺVzVn^zzҤvڵ݅+ Z^n:uiiF%e+?a„ U?L!^;Ge#?3bC.J$j\zɓ'S DVvL kÆ &Eʜ안Vƻu<;X'&[PoaaAAAA7 eYƍիCVgJDDd[VL@ w@BLHҏ1 D2ɚh+2"XtYl2)ZjCV;8CZU'A?%^Ɯ@رcǎSa *)))))I_ "3r?zƴl|~UpPt/W|3f̘޶mw=sѢ Dc" ,X/8O4f۶ڵk'YUyɒ|c}vȐ!Ci"r>-Z$=h.]y=}]^?9~7nܸ+8~{lY^=lvNtb.z DTw H5j(??DGn5[j*M4ihQd-=zDStڵkj_[|;/o~L:D>DS.s@KV0x@ }ԴR?$K~@Lͧ!k ĉ 4~Yw;wJĠ%^^^d%`Fׯ_oLEEd+eiHdž"$X@UR_ZNΦM6y_7o[n]c֯e]vIy(QauW"8 /^^g8 D B HH# Tk8餲jU^^^^C+ 핈:{v:KlK,Y.-mݺuk $-@˳mG7nh7?CsuԩcLqq˖-[& 5k5jȿ롕{O2+~STWfjUb>u8VAK j%ȑ\ݽ#Fp=1ab0@bPVk+VX٠H鏄!T?# L \׮w.F֭[΋**Y:[#ĠM2c.8=zD>35kﳃD!9bofqO)W TSŋ[hﳂ@bЭ̙3gzέW^= ³̀JC~W Ο `% ^-Z-] $ߡ]Ξ={72B s04UQIҍ+C0@~.E ~y!œ bb@~uy"co/---2 oiӦMD!+WS++++i;d+"ko۶m1zM:ui:ucH & C6I5k֬^ZոqƩAe.}&h6nL]۰aÆ~"=z̘1c1YY˛6mԘE >cK"CaN Fڱdه +Á"Zyد_IIIپ3 '\:f̘1$_&W^&5óÁ"Zyrʕܹsg.<ؚ Vjw[^d ʽqŋ ݰ1H &mRP"a ^j7 ?~xc0`ચ@KӗV  Dؚ ^eYe˖-iw_>D"pcb8@DFcaa˵ey|M"T.$XyVZ"_ ,7;˜͛իW [ V sHgopG$$J6eeeeބMEEVVV6^ꕇ^kG7mJmg +Q섘E@u6s̙ɓwޝ a>}@ab@DFo'2[4l]Ξ={zڴN:u vK u@1\20ULzh'HH6=;/ogv-ZTPPP@^H@izҥK׬@ 6V "ug2T'&~y]w՘>3^wEzƝ|rigv]HH6H~; RXx8Fi%Z,SuH_x86t-Caᎏ+-mݺuk dP @0@{ DDF x86ٴi&Y]YYYYlڔ; Ү]YYY@D x86t% 5ռʕ+W]QQQaڵ 4h`|(T@D H~o; ҡ… zk۶m[ "P Asko۶m1C3f @ppl"x D.,X{=~v}V Dףnj3fӺL. D$ V []O-WPHx ?~xc0`@^U+uwaf"KN`@M5jnݺu4j~lZN:,[ִiӦ~b D]'Y8:wڴ|^:G,<@X&Ԕ=_0b"|D{ȑl̶mkfZu9sLEEEE~T D0-vL .]"\H "XiX=<@iWSN?mZN:}vP}~$ \~ k$G~JJJJCAJc/ @{p&;<\.eMlYaÆ >;ċ"j$ZPHƇlV> @^qƍ*;V b!smY٬ҍ[4Yzj5 Daó DĄɩCAe–eO_f"cbz!"aZjE@D0,,HWœUر1@1~kӦ[yXQŊ8@d"pabz!abM m̙3ד'w޽;+z+`G~oanڔ"pӗ 4G0شukٳg?mZN:}v2CQNNd]YYY ٴ)2NM#@б0=@L3lE}yyի#hQAAAg EvO_n~˖-[˗7iҤWbdz Đbeaz802-ӧ}g ݰb۷ߺuV$ + Ā7Q( c6nܸ{eŠt;@$ lXH ̒yMa3l]PS4෰O`y Z^tR5+ #Qc)($E32l]x\\vO_@z>J9H &Xu@/3nT‡gx?C3f1h=W}z ,Xཞ?]vR=\OGjҥ}cLyyvvvߧm1;d"m(H_~C/#`Ѣa7bnnd԰a&MdL6~l:蠃)/On޽#~#"dme>WCeee1sΝ;wnޯrH-Zx+鋊~_LRX(.<2~|饇z;;HqFe~ukZjE?O{NN疕DjD}QXqqP@X6@迀I4j~]X}9z7ՉR3iӦMY<&??f="[1Dkjݺu׿ڰaÆ+R~Hv]nE>}wDʤI T\~jaCwqyxt7;/ tТE%]vzbljygϞ=_zinv%4 -+b\M6m0`Μ9s9RcF<#1Q[4ٴi&cv%볲YgE>DV"jekz:-G1n#=@Dʜ(g>@ӳC9k.*hHV眜ő-jX pZ!-sz⮻@2lDٺ?a„ 7ncBWk!WV ,{K2'Xv"QvP++ٟ DؑkEF@`%{+3+`D}d0Doe֧/7hPYYY}U9999~[% If6/џCbG@[E[ų D̬@ v$F2ؑ@5ʬ{|Y DSݭJEdӗp# t^hdU@:neDT{%#"вG1ԩ}x+RQ+@ZJ.^ܨQFlٲe1{/\p{˿M2# |啽k/^:ykyyy1̙3gs.;Bڶm֘&Lٺ @H [kժU˘;8C1fѢ\zu Q˳lH@D DN$8@TkPXXXXXPZZZZZSQ~C$~s" DN$8l[lٲe1__oLF5jdׯ_omvms-r-w}w\s5\~~~~~~1__mLÆ 6lhL۶m۶mkLeeeee1}g}fL޽{mQGuQGswy￿1Zjժ1߿1~nL˖-[liavasnfE]tE駟~ƌ1bĈƌ;vر,]tҥp 7p1mڴiӦ1zի1u֭[1<3>>h)r)su]wuƜygy1GyG޲y͛7{߸qƍaÆ 6sM7tM;<@cƍ7n8cjժUV-c9s97|7{OFk]wu].Yp… {^6mڴiӦ{챇*b//4fӧO7fܹsέZOt+W\88^x^0cǎ;vaYYYYY1??gذaÆ 3]vڵ~u~:_*W_}W|Ƽꫯw838Ø7fիW6&++++++oǏ?ޘI&M4ɘڵk׮]ۘ>}ǘݻw+W^yW^齮SN:u.ڋe˖-[=N;Ӽ?c~{ڋ//6f̘1cƌ1fʔ)SL1&''''';+'j.K.t\ʥu֭[}_vOPUW]uU}{{o;;~ 0`cvڵkWc~~駟9>lc>O>ĘM6mڴɘK/K/ʋڗ=z;NΝ;w콟N8Nz>O=SO=iϞ={iСCQyoFc4hРAc~_kWt]ߩW_}1}w}GC^(^iѢE-vO< jVZj*o߾}뙛G:]ve]vnŊ+Vοy͛7'|'{s=s3f̘Mϟ?wT.4iҤIÇ>;}U}ƍ7n4.˼ݦV/Ծ,ZhѢEqwqmLAAAAA1wqOӊsUkګy]p\pUWTTTTT}R}s7x70w}wyqc͛7o>ؘ~؋_u_~_~[joBqѣGmLf͚5kfLN:u}zUQ]OTTNUTOn}7|<8Ϗ<#zOzN3lP/_bL:t:ITnt?uP MJ(`6ywyK@,_|޸G~k.w%(ʑjxN8.>??-Qq%u~/:&$E۪OQ?}W\q^;1s1U\Q>^uDʿBht7pQ qU>?4s#7 HA(??o'lZ`S'Y+h-Q)Ծh+Z`r@ }s̙3g7PVMXhş̚5k֬Y+ HGz`?[nݺu~h+Z2rȑ#G7u:ջhiEʯ^ZE4vqN:uT/W_׽ ǚъGW;+ |obH_ŋ/^O%05 @%z"* -w#Օ.VrDjj58IHZINU*WJ]FhRJ*/]3WsD źSqrĕVO+U4ET\=?x4p>aZXᒨx"&5 g_M@(ѫqi2 4Sb@f|ifHU3xiŅb}zO?O?W{ 4moPEW@vbSG?hKVvDsGq^ãiMK5SbmEUԊxt =#+DP{{Y G )Q?WB5z^{^;u dEKu|L(QhTQ}VǥZq,W  ,XߩQ}_V0`D}=: VZ)ĦʱK:Æi1r0#@ICput*.)A[[UqEC1WG%:$ T ] e~4WX:%4Њ=fUt|e]2*}5:?:}}0)0uqu|^ڬ5 5*@k \>)UO\?WLTWEM+:]WOtmճqU^]:З^z饗^KxTzĀ cޢvIDM tu|[`Tĭ0_LLj_ZM"J+!-jT^>ߋvi ħjo]jt\%h%Hz$&*`T}Wʝ,];#uQy4̱VV8jOzė3;nz)qWOGAY9+? utUrZ H]O <{Wov`;vE%45꿫^˧Oʳ@ZvnoDzW6]W%xJlha+sWC=zB œ8CRk>#\ǞTVC*xjb"gE{ u_LaEvdh@a?8T]+ĺ_[-Z1V?LG4/+[~!Q+b~BT?M/3Oh|a)S'%KXJ =k(>S&=[j'YgmWW'aES 8H p""'~PXXXXXPZZZZZSQ~C$~SX$qǣ~ӵQh%˗/_~Eh>EDŇO<ׯć&Zw_$zE;~cڶ-+++3&??R~%e}O>KJw|U+(pi|Ŋ+>nGd-[4:w& 'M#M_C}:t̘1cy䑳:,cm]vm:j޶m6z} '`̐!oyĈ#o'ċm̙3~_Z { x0?ʕ+YiӦMy!K)_+sRGUXW*AZ 4mZN:U};o;_yO>ȀC@~;p)---삇@jMX\\\̀ qI8t-홿a{?@D[YaDŽNkԩSLG 4Ieѐx D þ"gmes4v&ޝw^~{[=f"갳*+++rLC@hiت /~V$!)wes4,QBo7԰VXt>d}ֳgϞ+H[A_zFlƎH E鯨|X ,7={+ʉPy 4b=Е䑊ω2(g:/XhybnY-z6Y^"1N(C816L ٰ7u(}xbnY-~6Yiy+[ʄT:NL k6, IWI*Tj:zr™tҩ.ٰL[$^%PN֖rm]Tn[K6, IWI*T#gOS.K=NL-/ ˿eYRU bc<ۻwccccsەTˤ[%J#$\y" NWV7'$KxvrUW X&}=ܲ,T|;!XyңÇg?GHHJ'}gϞ=V;'$VMSg I*Vt4nܸq!۱cǎ IYյ*XϖV5͙&~XrW P泪kURk8u!C ~xL &IeI)>6)Z+Nv2f̘1!ݹsΎgKK&>\VR2KS;۷oޕ'2mMRy 0l@TMqK*nF92u͕'j"LV)}R10kb@.R7g}Y'3<$U䇦HʓJLV &̀\R쫆#F~>bs=wNR9=Z㇦H*4Ab2@TM0aDJzC;cǎCۦYRxÑġbQǗٿHT)g_ PT |6^m2.vѪj*MLJlMcó+I>6Ja})WUlHT)ؚةӸqe[}$WCc>QEΝw:t_}եK.8+Ҥ.+~}hCupMtUf8g}ѣ_y[lE*Jn]⇦&TRqR-fvڷo߾PPRq벤?46y_x\!@TpCRes벤RxYލϽRrL a)f$URДڒ,rT{yUIY3* I1?46=*q_&UIY3* I)Nx}&q_rUzP"(Ҙ gmgRgٳg]*[[%UbLcó;YR+}T\bI "( ,%2Sqƍ a؎;vt³ZP?.\'f&XJ-GܳC B.cƌݹs! <`募Æ54448YmUpE0heIއI*5K*a3hРAO(u6H!~pE0^z߲ ?@R1 8,V/:|mHtrmBRqኚJ*{M $U Kp^[8矿.~N$uH!~pEaȯ00)N XJi7pW\m!na x8y[[%pEaPYH4RdA?ԤTD.W7,K ]D" IF;޻wccccsK)x9olKqwXu"ѭɝARK DUS+"(Rmi3T=KHl3]R$Uߊv|Zµ_* AI"oKQ$^"ѕ+ŝAR{n$wH DֱT)Xy?JWVImV/]ʕ`.Uy3$wHQE*Iq,TӇ؀K*7V(>ĩZVVIŔZsV$N|VtBڕN5\f1 )~~߳m%Zn|SRmi3RjHJz0ge2N*O[$צwHaQK5iS0_~% Rg6+QHjb~|}ݻwމ2N*WVH|>}qHcQd@Ҷo:?d36Z^@[tSu*4qҸ#ux`5dH0`]wuWPؘD\jwy,/Z?E{_|ҭdK$nmv[N%L *`°zjz!*h.LQ駟~zV+3xT*9Oϣ^_|\6fi[sCCa8]*\[_\oZɞH@jb+\e1qXԩSN!tS޽V6HۻzߚV7v׋V~o!44_r*ֳԸ\JڷoZZ+g΁WYeUB7}qjCǎǏO=S!5W3 ULSM5T!L9#Fl꟪}|iD7 >裏}]6 )CB0oYyW~r*5WճtRQG +첣F‡r W)ݕW{NjصBQR)k'SPNtJ+R&k׮]ZkJ$UGݺuVQ* D AZk}#*uW,MB&ݮ|$I$csf&Q#IRT4a(I$T*6mu~fh:bs(Im+Z:$Ibbjts;aQ*CK@0$ITij>\M8I}=Im$Ir31.IR$I* q(I*$IJ3YO@$I$IR2(I$I$)$I$I$$I$IL J$I$IJ2(I$I$)$I$I$$I$IL J$I$IJ2(I$I$)$I$I$$I$IL J$I$IJ2(I$I$)$I$I$$I$IL J$I$IJ2(I$I$)$I$I$$I$I_tڵk׮>=:5jԨQK*Kj;/XcN~Q$I$IRRr$I$I$Q$I$IR DI$I$II&%I$I$%MQrꩧz!6l6[L34L/⋇0nܸqƅ馛nr!rHg}g‹//0|Ç{{!<>l{ݻwM7tM??OW_}W / CXtE]t_~_>wywB~>裏>:r~ , ЧO>}:묳:!{{n_avaO?! :tС!:묳:kv]no=cǎ;6j a=c=Bwywމ+s5\s++'|'!|_|·~߆0zѣG!,K,DW^yW^O>C?~C8ꨣ::vرc~駟~);^g~C8;838#۷o߾ܥtx'x"{{ afaBXz饗^z^_=8Ȯ+1\nݺu-矟:ǯ믿^SN:u ᣏ>裏z;!\|_|q]tҥK#G9rd\r%\SL1h8q^x^87|7a}g}BXyW^yuy߼I'tI'Я_~e~ꩧzC8pᬳ:묳B_~嗬]|7|39s9_߾}ƒ>N|>^z饗^ziv=[l[,mvm >Be]ve=;O9SN9%?<Cgygr׆ѯ{{l;wܹs 0`ivivt7|!3f̘1!oFӾR>ꪫY{.!,K.d34L3mvmЮ]vڅ;8??[n[p_Yy 6lذa! 4hРAY9zq׉qZjBoƬRbYfeYf __8C=C׋σr@G?uM>?3] 2dȐz뭷z+Xc5X#>]uUW]uU~NsG\~ўS?(ロ_qGqDOGVRxO?O/s1sdq'>-2,LO+ƬgFmFe?q ]wu]w / !L0a„ !kf.>?pvo3qyfmfeIri_.[x=qg׃rjR?z_~7|͗ݿ~1袋.zѣG,fmfvmv-ݻw=rθlCxG}Ѭ}g}!nžꫯ*;\N8NȿޔӸ]=HKW??nj383f;O*ߥ~~lW\qWdګ 6` 6 . O?O/]l>3< kZk‰'x'f:~~!'M6dMSh/)R8z뭷zers7}w}7ycfrwqgħ\8sFyxVZiVg?3bĈ#Fd|Oj<{{ȓwG;n8 bTL.0;x-F@nSN9Sf ^{^{4[o[o$,Hdꫯj:Q IT g s=s!jZnnkTλ-r-54(u]wu??f/~~ [n[BX_}- kkvߓ?:W# ,U44p !R9c9&{3rN€ D>mЦO?,MG&sA#Pk^Ga:0&}jFBDD9jKb:R@b,n7i7{{L"!+/K/†nf&_*pp\vviv,!dJ"DOL# |&hGx}#<#LzyP?ZKyH:0F9q~‚ . fǏY Ւ8aF=׃8+F}?>_S(H\FG98:z.:9￟;L)\}KzBLn.]9?c=cY{yrI00sn#A8ޥ~NBD v0UHP>2 qq92BB2?_0 'bs9眓%RHh^~_~yȻTY#QAF $d_S #nbuY뮻&>χz衇J_++fTяyGyx=&_y}7z뭷ޚ%_{^{-#e יvСC!0:b-bVXaVX!;-pTf2$@_nl`Ђtt ha`qI>SO=T)gߑY&x'|^1Td2!b)J_~C6 M^(_(){n:BfRüP_}W_}ux1EzCs|7|M]vڵks:T8R LOگUVYeUVmy 77/1ThoX/!'a / hO !`BQo`RPN!@k-V. [x?F?!(qR(|W01)|\]g+ H0žs1HP$y&7+HuȻ/G׻ZwЎ4WڻX\_EPNl&lIqrq 3J}a0g/Fg(~.DiL? N,՞1^F 3Zj|Qxu# HJ' JrL0_JBWT~D1+Ir]ȫ5dEt<}q@>V8p\fR>>1]b`GEZ`K4?z-I?ׇtH$bX ~JE ^@qp 3[q?R x(`3[7H0a%ǥ=fePuc+Yb?F@pK>u@/@@+wg̨@`%E f,qY#Kw­|%p8E ;E7x_/  hH.8rD|B3?B0x8P~9ƙv"h?s]h㕺G'sYq8'q@C{WiPӁp#!T p  uY>TTqY>33>5$ 8>3a{+5DE,dF\x_*gDpyf ;zA⍀=4 r\ȱ!H# KpQOu=K ߢ'? "Lq^ė ~K=k$+r-m,3'^Sm*V9/6QUmcG޳ڤBU^"ѼgT+,&m"/as:ƟPlU $I$I*$I$I* DI$I$II{:rIENDB`muffin-5.2.1/doc/reference/clutter/ChangeLog0000664000175000017500000007073114211404421021103 0ustar jpeisachjpeisach2008-12-08 Emmanuele Bassi * clutter/clutter-docs.xml: * clutter/clutter-sections.txt: Add ClutterBindingPool section and link. 2008-11-12 Emmanuele Bassi * clutter/clutter-sections.txt: Add new symbols. 2008-10-17 Emmanuele Bassi * clutter/clutter-sections.txt: Add the new ClutterColor symbols. 2008-09-25 Emmanuele Bassi * clutter/clutter-sections.txt: Add clutter_get_option_group_without_init() 2008-08-27 Emmanuele Bassi * doc/reference/clutter/clutter-sections.txt: Add clutter_script_list_objects(). 2008-07-30 Ross Burton * clutter/version.xml.in: * cogl/version.xml.in: Remove trailing newline as it upsets Devhelp 2008-07-17 Emmanuele Bassi * clutter/subclassing-ClutterActor.xml: Update the ClutterActor subclassing section by removing the cogl_push/pop_matrix() calls where not needed. 2008-07-10 Emmanuele Bassi * clutter/clutter-sections.txt: Add the missing X11 backend API. 2008-07-01 Emmanuele Bassi * cogl/cogl-docs.sgml: Add an index to the COGL API reference and the licensing information. 2008-06-26 Emmanuele Bassi * clutter/clutter-overview.xml: Split the overview into its own file, so we gtk-doc can linkify all class names. * clutter/building-clutter.xml: Split the building instructions into its own file, for better maintainability. * clutter/clutter-animation.xml: * clutter/creating-behaviours.xml: * clutter/subclassing-ClutterActor.xml: Rename from SGML to XML; these were not SGML files anyway, but templates. * clutter/clutter-docs.sgml: Use XInclude instead of the ugly entities hack. * clutter/Makefile.am: Update the build. 2008-06-25 Emmanuele Bassi * clutter/clutter-sections.txt: Add missing symbols. 2008-06-25 Emmanuele Bassi * clutter/clutter-sections.txt: Add clutter_backend_get_display_size() to the documented symbols. 2008-06-24 Matthew Allum * cogl/Makefile.am: * cogl/cogl-docs.sgml: * cogl/version.xml.in: * clutter/version.xml.in: Add full version (including minor) to docs. Add version to COGL docs 2008-06-23 Emmanuele Bassi * clutter/clutter-sections.txt: Remove clutter_actor_get_paint_area() and add clutter_actor_allocate_preferred_size(). 2008-06-23 Emmanuele Bassi * clutter/subclassing-ClutterActor.sgml: Remove mention of the get_paint_area() function and virtual function. 2008-06-23 Øyvind Kolås * clutter/subclassing-ClutterActor.sgml: added missing call to cogl_push_matrix () 2008-06-16 Matthew Allum * cogl/cogl-docs.sgml: Add an intro. 2008-06-13 Øyvind Kolås * clutter/event-flow.png: fixed typo. * clutter/event-flow.dia: added source for event-flow.png, this file is not referred to in Makefile.am and thus not distributed in tarballs. 2008-06-12 Emmanuele Bassi * clutter/clutter-docs.sgml: Clean up. * clutter/clutter-sections.txt: Add missing new symbols. * clutter/clutter.types: Add ClutterChildMeta type. 2008-06-11 Emmanuele Bassi * clutter/subclassing-ClutterActor.sgml: Add more notes and remind to relayout when adding children to an actor. 2008-06-10 Emmanuele Bassi * clutter/clutter-sections.txt: Update with the new API. * clutter/subclassing-ClutterActor.sgml: Update with the new size negotiation API. 2008-06-09 Chris Lord * cogl/cogl-sections.txt: Add missing cogl_path_arc 2008-06-06 Emmanuele Bassi Bug #927 - Created ports for clutter, clutter-cairo in macports * clutter/clutter-docs.sgml: Update the OSX build instructions and mention that the preferred way to build Clutter for developing applications is via MacPorts. (#927, Idan Gazit) 2008-05-15 Emmanuele Bassi * clutter/clutter-sections.txt: Update with new symbols. 2008-05-09 Neil Roberts * clutter/clutter-sections.txt: Added clutter_threads_add_frame_source, clutter_threads_add_frame_source_full, clutter_frame_source_add and clutter_frame_source_add_full. 2008-04-29 Neil Roberts * cogl/cogl-sections.txt: Added cogl_shader_ref, cogl_shader_unref, cogl_is_shader, cogl_program_ref, cogl_program_unref, cogl_is_program and cogl_is_offscreen. 2008-04-29 Øyvind Kolås * cogl/cogl-sections.txt: updated after cogl primitives api rename session. 2008-04-28 Emmanuele Bassi * clutter/clutter-docs.sgml: Add index for the 0.8 symbols. * clutter/Makefile.am: * cogl/Makefile.am: Revert back, as EXTRA_DIST has been defined by gtk-doc.make and automake-1.9 complains loudly about a redefinition of EXTRA_DIST. 2008-04-22 Øyvind Kolås * clutter/Makefile.am: * cogl/Makefile.am: s/EXTRA_DIST +=/EXTRA_DIST =/ since newer automake is more stringent and EXTRA_DIST has not been defined earlier. 2008-04-21 Neil Roberts * cogl/cogl-sections.txt: Added CoglTextureVertex, cogl_texture_can_polygon and cogl_texture_polygon. 2008-04-18 Emmanuele Bassi * cogl/cogl-docs.sgml: Fill out and add an "about" section. * cogl/cogl-sections.txt: Remove unused/redundant stuff, divide into logical subsections and in general make the documentation more structured. * cogl/Makefile.am: Ignore some private header files. 2008-04-18 Emmanuele Bassi * cogl/: Add COGL documentation. * Makefile.am: Add cogl/ to the list of SUBDIRS. 2008-04-18 Emmanuele Bassi * clutter/: * *: Moved everything into the clutter/ subdirectory, to make room for the COGL API reference. 2008-04-07 Neil Roberts * clutter-sections.txt: Removed clutter_texture_new_from_pixbuf and clutter_texture_{get,set}_pixbuf. Added clutter_texture_{set,new}_from_file. 2008-04-03 Neil Roberts * clutter-sections.txt: Removed ClutterTexture functions that are no longer neccessary to implement ClutterCloneTexture because of the new COGL texture API. Added clutter_texture_{get,set}_filter_quality and clutter_texture_get_cogl_texture. 2008-03-30 Neil Roberts * clutter-sections.txt: Added clutter_win32_get_stage_from_window 2008-03-26 Neil Roberts * clutter-sections.txt: Added a section for the Win32 specific API. * clutter-docs.sgml: Added comments about the Win32 backend. * Makefile.am: Added bits to ignore the headers for the Win32 backend. 2008-03-18 Emmanuele Bassi * clutter-section.txt: Update after API change in ClutterScore. 2008-03-18 Emmanuele Bassi * clutter-section.txt: Add new score API. 2008-03-18 Emmanuele Bassi * clutter-section.txt: Add timeline-marker API. 2008-03-07 Øyvind Kolås * Makefile.am: Ignore clutter-id-pool.h to avoid picking up private symbols. 2008-02-18 Emmanuele Bassi * clutter-docs.sgml: Add building instructions for OSX 2008-02-18 Emmanuele Bassi * clutter-animation.sgml: Fix warning * creating-your-own-behaviours.sgml: Add a paragraph about setting an initial state on the actors. 2008-02-15 Matthew Allum * clutter-docs.sgml: Minor tweakery. 2008-02-15 Emmanuele Bassi * clutter-sections.txt: Fix ClutterMedia section. 2008-02-15 Emmanuele Bassi * clutter-docs.sgml: Move ClutterStage from the base actors to the container actors section. 2008-02-15 Tomas Frydrych * clutter-docs.sgml: Build instructions for Linux and Windows. 2008-02-15 Emmanuele Bassi * clutter-animation.sgml: Fix the animations documentation. 2008-02-15 Chris Lord * clutter-docs.sgml: Fix documentation. 2008-02-15 Matthew Allum * clutter-docs.sgml: Overhaul the overview. 2008-02-15 Emmanuele Bassi * clutter-animation.sgml: Fix some of the grammar; add a timeout-based animation example. * creating-your-own-behaviours.sgml: Fix some of the linking. * subclassing-ClutterActor.sgml: Remove the FIXMEs; add the initial structure of a section about containers. 2008-02-15 Emmanuele Bassi * clutter-docs.sgml: Fix varlistentry usage. 2008-02-15 Emmanuele Bassi * clutter-sections.txt: Add last-minute API additions. * subclassing-ClutterActor.sgml: Fix some of the notes; the Container implementation will need its own section. 2008-02-14 Matthew Allum * clutter-animation.sgml: Add new animation docs. Needs work. 2008-02-13 Matthew Allum * Makefile.am: * clutter-docs.sgml: Add new appendix + FIXME for building * creating-your-own-behaviours.sgml: Add new initial doc on custom behaviour creation. * subclassing-ClutterActor.sgml: Add FIXME notes. 2008-02-08 Emmanuele Bassi * actor-box.png: * Makefile.am: Add actor-box.png. 2008-02-08 Emmanuele Bassi * clutter-docs.sgml: Add dependencies inside the overview. 2008-02-08 Emmanuele Bassi * Makefile.am: * alpha-func.png: * event-flow.png: More figures. alpha-func.png is a graph showing the flow of some alpha functions; event-flow.png maps the path of an event coming from the underlying windowing system into Clutter and through the entire library. 2008-02-08 Emmanuele Bassi * path-alpha-func.png: Image showing the effects of different alpha functions on the same path behaviour. * Makefile.am: Add fixxref options. 2008-02-04 Emmanuele Bassi * clutter-sections.txt: Add: clutter_actor_move_anchor_point clutter_actor_move_anchor_point_from_gravity clutter_actor_set_shader clutter_actor_get_shader clutter_actor_move_anchor_pointu clutter_texture_new_from_actor clutter_entry_set_cursor_position clutter_entry_get_cursor_position Remove: clutter_actor_apply_shader clutter_behaviour_scale_set_gravity clutter_behaviour_scale_get_gravity clutter_entry_set_position clutter_entry_get_position 2008-01-21 Emmanuele Bassi * clutter-sections.txt: Add ClutterBehaviourDepth properties accessors. 2008-01-18 Emmanuele Bassi * subclassing-ClutterActor.sgml: Fix up the wording and the examples a bit; add a paragraph about the ClutterActor::pick() virtual method. 2008-01-18 Emmanuele Bassi * clutter-sections.txt: Add the new ClutterBehaviourOpacity accessors. 2008-01-17 Emmanuele Bassi * clutter-sections.txt: Add the new ClutterBehaviourScale setters. 2008-01-14 Emmanuele Bassi * clutter-sections.txt: Add clutter_model_insertv() 2008-01-09 Emmanuele Bassi * Makefile.am: Add clutter-model-private.h * clutter-docs.sgml: * clutter-sections.txt: * clutter.types: Rename ClutterModelDefault into ClutterListModel 2008-01-07 Emmanuele Bassi * clutter-sections.txt: Remove symbols of the ClutterModelDefault iterator class. 2008-01-07 Emmanuele Bassi * clutter-sections.txt: Remove clutter_model_append_value() and clutter_model_prepend_value(), and add clutter_model_appendv() and clutter_model_prependv(). 2008-01-04 Emmanuele Bassi * clutter-sections.txt: Add clutter_actor_move_byu() 2007-12-24 Emmanuele Bassi * clutter-sections.txt: Add the units-based clip accessors 2007-12-21 Emmanuele Bassi * clutter-sections.txt: Add clutter_group_add() and clutter_stage_add() convenience macros. 2007-12-21 Emmanuele Bassi * clutter-sections.txt: Add clutter_texture_set_area_from_rgb_data() 2007-12-15 Emmanuele Bassi * clutter-sections.txt: Move the shorthand fixed point macros in the private section 2007-12-15 Emmanuele Bassi * clutter-sections.txt: Added all the unused symbols. 2007-12-14 Emmanuele Bassi * Makefile.am: * clutter-docs.sgml: * clutter-sections.txt: * clutter.types: Update for ClutterModel changes. 2007-12-10 Emmanuele Bassi * clutter-sections.txt: Add the new ClutterModel API. 2007-12-10 Emmanuele Bassi * clutter-docs.sgml: Add ClutterShader... * clutter.types: ... and its type function. 2007-12-04 Emmanuele Bassi * clutter.types: * clutter-docs.sgml: * clutter-sections.txt: Fix ClutterScore symbols. 2007-11-30 Emmanuele Bassi * clutter-sections.txt: Update with the newly added API. 2007-11-28 Tomas Frydrych * clutter-sections.txt: added new CLUTTER_UNITS_FROM_* macros. 2007-11-28 Emmanuele Bassi * clutter-sections.txt: Documentation fixes. * clutter.types: Remove layout and boxes types. 2007-11-28 Emmanuele Bassi * clutter-sections.txt: Add the new ClutterEffectTemplate::construct method. 2007-11-23 Emmanuele Bassi * clutter-docs.sgml: Shuffle around non-actor classes. 2007-11-23 Emmanuele Bassi * subclassing-ClutterActor.sgml: Mention the chain-up needed when overriding the request_coords() vfunc of ClutterActor. 2007-11-23 Emmanuele Bassi * clutter-sections.txt: Add unused API. 2007-11-21 Emmanuele Bassi * clutter-sections.txt: Add the new ClutterStage fog API. 2007-11-19 Emmanuele Bassi * clutter-sections.txt: Add ClutterScore symbols and ClutterLabel:justify accessors. 2007-11-19 Emmanuele Bassi * clutter-sections.txt: Remove clutter_behaviour_bspline_append() and add the new motion events settings API. 2007-11-18 Emmanuele Bassi * Makefile.am: Add clutter-x11.h to the headers scanned. * clutter-sections.txt: Update with the newly added and removed symbols. 2007-11-15 Emmanuele Bassi * Makefile.am: Ignore the OSX backend subdirectory and scan the clutter-x11.h header * clutter-docs.sgml: * clutter-sections.txt: Update. 2007-11-15 Emmanuele Bassi * clutter-sections.txt: Add new ClutterTimeline API 2007-11-15 Emmanuele Bassi * clutter-sections.txt: Add new ClutterEffectTemplate constructor. 2007-11-15 Emmanuele Bassi * clutter-sections.txt: Add new ClutterScript signal connection functions. 2007-11-15 Neil J. Patel * clutter-sections.txt: Fix typo. 2007-11-15 Neil J. Patel * clutter-docs.sgml: * clutter-sections.txt: * clutter.types: Added support for ClutterModel. 2007-11-14 Emmanuele Bassi * clutter-sections.txt: Update with the ClutterScriptable changes and add clutter_get_script_id(). 2007-10-28 Matthew Allum * clutter-animation.sgml: Fix missing func param (#583) 2007-10-25 Emmanuele Bassi * Makefile.am: Ignore clutter-json.h header. 2007-10-25 Emmanuele Bassi * clutter.types: * clutter-sections.txt: * clutter-docs.sgml: Add new ClutterScriptable API. 2007-10-18 Emmanuele Bassi * clutter-sections.txt: Add new ClutterScript API. 2007-10-10 Emmanuele Bassi * clutter-sections.txt: Add new API and rearrange the subsections. 2007-10-10 Emmanuele Bassi * clutter.types: * Makefile.am: Add ClutterScript and ignore clutter-script-private.h to avoid picking up private symbols. 2007-08-21 Emmanuele Bassi * clutter-sections.txt: Move ClutterStage and ClutterStageClass symbols in the right section. 2007-08-20 Emmanuele Bassi * clutter-sections.txt: Move ClutterTimeline and ClutterTimelineClass symbols in the right section. 2007-08-15 Emmanuele Bassi * clutter-sections.txt: Add clutter_effect_depth(). 2007-08-14 Emmanuele Bassi * clutter-sections.txt: Rename raise() and lower() methods of ClutterContainer. 2007-08-13 Emmanuele Bassi * clutter-sections.txt: Add the new ClutterContainer methods. * clutter-docs.sgml: Generate the index for the symbols added in the 0.5/0.6 cycle. 2007-08-08 Emmanuele Bassi * clutter-sections.txt: Add the new clutter_threads_* API. 2007-08-07 Emmanuele Bassi * clutter-sections.txt: Shuffle around a bit the symbols. 2007-08-06 Emmanuele Bassi * clutter-sections.txt: Update with the new ClutterBox API. 2007-08-04 Emmanuele Bassi * clutter-docs.sgml: Add autogeneration of the per-version indexes of symbols, plus the index of deprecated symbols. 2007-08-01 Emmanuele Bassi * clutter-sections.txt: Add clutter_actot_get_r[xyz]ang() functions. 2007-07-31 Emmanuele Bassi * clutter-sections.txt: Update ClutterBackend API. 2007-07-30 Matthew Allum * clutter-animation.sgml: Note on ClutterEffects 2007-07-28 Emmanuele Bassi * clutter-sections.txt: Add new ClutterBehaviourEllipse and ClutterStage API. 2007-07-26 Emmanuele Bassi * clutter-sections.txt: Add new symbols. 2007-07-26 Matthew Allum * Makefile.am: * clutter-animation.sgml: * clutter-docs.sgml: An initial shot at some general animation documentation. Needs some love. 2007-07-25 Emmanuele Bassi * clutter-sections.txt: Rename clutter_behaviour_clear() to clutter_behaviour_remove_all(). 2007-07-24 Emmanuele Bassi * clutter-sections.txt: Add new rotate behaviour methods. 2007-07-24 Emmanuele Bassi * clutter-sections.txt: Add undocumented symbols 2007-07-09 Emmanuele Bassi * clutter.types: * clutter-docs.sgml: * clutter-sections.txt: Add ClutterBehaviourDepth. 2007-07-04 Emmanuele Bassi * clutter-docs.sgml: Remove partintro, as it messes up with devhelp books. * clutter-sections.txt: Update functions. 2007-07-04 Emmanuele Bassi * clutter-docs.sgml: Use the right include file for the effects section. 2007-06-16 Emmanuele Bassi * subclassing-ClutterActor.sgml: Add a chapter about how to correctly subclass the actor base class. * clutter-docs.sgml: Include the new chapter about subclassing ClutterActor; add a description for some of the API reference parts. 2007-06-14 Emmanuele Bassi * clutter-sections.txt: * clutter.types: * clutter-docs.sgml: Add ClutterBox and subclasses. Rework the layout of the API reference, now that we have fairly more classes. 2007-06-09 Emmanuele Bassi * clutter-sections.txt: Add ClutterTimeoutPool API. 2007-06-07 Emmanuele Bassi * tmpl/*.sgml: Remove from revision control the templates: everything is now documented from within the source code. * clutter-sections.txt: Add missing titles. 2007-06-07 Emmanuele Bassi * clutter.types: * clutter-sections.txt: * clutter-docs.sgml: Add ClutterLayout API. 2007-06-07 Emmanuele Bassi * clutter-sections.txt: Add new ClutterTimeline API. 2007-06-01 Neil J. Patel * clutter-sections.txt: * tmpl/clutter-entry.sgml: updated for new functions. 2007-06-01 Neil J. Patel * clutter-sections.txt: * tmpl/clutter-entry.sgml: Added new functions. 2007-06-01 Neil J. Patel * clutter.types: * tmpl/clutter-entry.sgml: Updated for new signals/properties. 2007-06-01 Neil J. Patel * clutter-sections.txt: * tmpl/clutter-entry.sgml: Updated for new functions. 2007-06-01 Tomas Frydrych * tmpl/clutter-alpha.sgml: * tmpl/clutter-fixed.sgml: * tmpl/clutter-units.sgml: * tmpl/clutter-behaviour-rotate.sgml: * tmpl/clutter-behaviour-bspline.sgml: * tmpl/clutter-behaviour-ellipse.sgml: Updated templates. 2007-05-31 Neil J Patel * clutter-docs.sgml: * clutter-sections.txt: * tmpl/clutter-entry.sgml: Added ClutterEntry 2007-05-31 Tomas Frydrych * tmpl/clutter-behaviour-ellipse.sgml: Updated template. 2007-05-31 Tomas Frydrych * clutter.types: Added clutter_vertices_get_type. 2007-05-30 Tomas Frydrych * clutter.types: removed clutter_smoothstep_get_type. * tmpl/clutter-alpha.sgml: * tmpl/clutter-actor.sgml: * tmpl/clutter-media.sgml: Updated templates. 2007-05-22 Tomas Frydrych * clutter-sections.txt: * clutter-docs.sgml: * tmpl/clutter-units.sgml: Added clutter-units. * tmpl/clutter-alpha.sgml: * tmpl/clutter-actor.sgml: * tmpl/clutter-media.sgml: * tmpl/clutter-behaviour-ellipse.sgml: Updated templates. 2007-05-17 Emmanuele Bassi * Makefile.am: Ignore the sdl backend. * clutter-sections.txt: Add undocumented symbols. 2007-05-16 Emmanuele Bassi * Makefile.am: Use the newly added clutter_base_init() function when scanning the library for documentation. 2007-04-16 Emmanuele Bassi * clutter-docs.sgml: * clutter-sections.txt: * clutter.types: Add new b-spline and rotate behaviours to the API documentation. 2007-03-27 Emmanuele Bassi * Makefile.am: Ignore clutter/cogl: it's private API. * clutter-sections.txt: Remove the now private ClutterBackend API; add the ClutterPerspective API. 2007-03-25 Emmanuele Bassi * clutter-sections.txt: Add clutter_get_default_backend(). 2007-03-23 Emmanuele Bassi * clutter-sections.txt: Remove duplicae symbol. 2007-03-22 Emmanuele Bassi * Makefile.am: Include the clutter-glx backend API. 2007-03-22 Emmanuele Bassi * clutter-sections.txt: Update with the backend and API changes * Makefile.am: Don't check into the backend subdirs. 2007-01-18 Emmanuele Bassi * clutter-sections.txt: Add forgotten ClutterGroup API. 2007-01-18 Matthew Allum * clutter-docs.sgml: Update overview. 2007-01-18 Tomas Frydrych * clutter-docs.sgml: added clutter-fixed * tmpl/clutter-fixed.sgml: added intro to fixed point math 2007-01-18 Emmanuele Bassi * clutter-sections.txt: Remove old cruft. * clutter-docs.sgml: Add index of symbols. * tmpl/clutter-fixed.sgml: Fix doc template. 2007-01-16 Emmanuele Bassi * clutter-sections.txt: Remove clutter_vblank_method(): it's private. 2007-01-16 Emmanuele Bassi * clutter-sections.txt: Update. * tmpl/*.sgml: Update templates. 2006-12-13 Emmanuele Bassi * clutter-sections.txt: Update; add clutter_color_equal(). * tmpl/clutter-color.sgml: Update template. 2006-12-13 Emmanuele Bassi * clutter-sections.txt: Update. * tmpl/*.sgml: Update the templates. 2006-12-04 Emmanuele Bassi * clutter-sections.txt: Update with the newly added API. * tmpl/clutter-event.sgml: * tmpl/clutter-fixed.sgml: Provide short and long descriptions. * tmpl/clutter-actor.sgml: * tmpl/clutter-alpha.sgml: * tmpl/clutter-behaviour-path.sgml: * tmpl/clutter-behaviour-scale.sgml: * tmpl/clutter-color.sgml: * tmpl/clutter-feature.sgml: * tmpl/clutter-main.sgml: Update templates. 2006-11-20 Emmanuele Bassi * clutter-sections.txt: Remove debug macros; add clutter-version section. * Makefile.am: Ignore the stamp files. * clutter-docs.sgml: Add a link to the version utils. * tmpl/clutter-actor.sgml: * tmpl/clutter-main.sgml: * tmpl/clutter-version.sgml: Update templates. 2006-11-17 Emmanuele Bassi * clutter-sections.txt: Move stuff around: get_type and Private stuff go in the Private subsection; remove private symbols like pango stuff and the enum gtype signatures; remove cruft. * Makefile.am: Add more private files. * tmpl/clutter-fixed.sgml: * tmpl/clutter-feature.sgml: * tmpl/clutter-actor.sgml: * tmpl/clutter-media.sgml: * tmpl/clutter-behaviour-opacity.sgml: * tmpl/clutter-behaviour-path.sgml: * tmpl/clutter-behaviour-scale.sgml: * tmpl/clutter-behaviour.sgml: * tmpl/clutter-alpha.sgml: Add templates. * tmpl/clutter-0.0-unused.sgml: * tmpl/clutter.sgml: * tmpl/clutter-enum-types.sgml: * tmpl/clutter-element.sgml: Remove old templates. 2006-11-15 Emmanuele Bassi * clutter-sections.txt: * tmpl/*.sgml: Update with the latest API changes. 2006-09-14 Emmanuele Bassi D tmpl/clutter-video-texture.sgml * clutter-sections.txt: * clutter.types: Remove ClutterVideoTexture. 2006-08-30 Jorn Baayen * Makefile.am: 2006-07-06 Emmanuele Bassi * clutter-sections.txt: Add clutter_actor_has_clip() and clutter_actor_unparent(). 2006-06-22 Matthew Allum reviewed by: * tmpl/clutter-main.sgml: 2006-06-22 Iain Holmes * clutter-sections.txt: Remove clutter_util_can_create_texture 2006-06-22 Ross Burton * tmp/*.sgml: Add lots of "no public members" and document some signals. 2006-06-22 Iain Holmes * clutter-sections.txt: Move _get_type to private sections 2006-06-22 Emmanuele Bassi * clutter-sections.txt: Add clutter_timeline_get_loop(). * Makefile.am: Add clutter-marshal.h to the ignored header files. 2006-06-22 Emmanuele Bassi * clutter-docs.sgml: Fix typos. 2006-06-22 Ross Burton * tmpl/clutter-group.sgml: Fix braindead source parser. 2006-06-22 Ross Burton * clutter.sections.txt: * clutter-sections.txt: Rename . to -, and add missing class members. * tmpl/*: Resync 2006-06-22 Matthew Allum * clutter-docs.sgml: Add copyright info. 2006-06-22 Matthew Allum * clutter-docs.sgml: Add overview text. 2006-06-22 Matthew Allum * Makefile.am: * clutter-0.0-sections.txt: * clutter-docs.sgml: * clutter.sections.txt: * clutter.types: * tmpl/clutter-0.0-unused.sgml: * tmpl/clutter-clone-texture.sgml: * tmpl/clutter-color.sgml: * tmpl/clutter-event.sgml: * tmpl/clutter-group.sgml: * tmpl/clutter-keysyms.sgml: * tmpl/clutter-label.sgml: * tmpl/clutter-main.sgml: * tmpl/clutter-marshal.sgml: * tmpl/clutter-rectangle.sgml: * tmpl/clutter-stage.sgml: * tmpl/clutter-texture.sgml: * tmpl/clutter-timeline.sgml: * tmpl/clutter-util.sgml: * tmpl/clutter-video-texture.sgml: Rejig a little and sync up with latest source. 2006-06-13 Matthew Allum * ChangeLog: * clutter-0.0-sections.txt: * clutter.types: * tmpl/clutter-0.0-unused.sgml: * tmpl/clutter-enum-types.sgml: * tmpl/clutter-group.sgml: * tmpl/clutter-main.sgml: * tmpl/clutter-stage.sgml: * tmpl/clutter-video-texture.sgml: rename element -> actor 2006-05-26 Emmanuele Bassi A clutter-0.0-sections.txt * clutter-0.0-sections.txt: Add the -section file: every method signature should go in this file in order to let gtk-doc pick it up when building the template for it. 2006-05-26 Emmanuele Bassi A tmpl A tmpl/*.sgml * tmpl/*.sgml: Add gtk-doc templates. 2006-05-26 Emmanuele Bassi * *: Initial entry. muffin-5.2.1/doc/reference/clutter/easing-modes.svg0000664000175000017500000031363014211404421022423 0ustar jpeisachjpeisach muffin-5.2.1/doc/reference/clutter/migrating-ClutterBehaviour.xml0000664000175000017500000001001714211404421025310 0ustar jpeisachjpeisach Emmanuele Bassi
ebassi@linux.intel.com
Migrating from ClutterBehaviour The #ClutterBehaviour class and its sub-classes have been deprecated since Clutter 1.6. The animation framework provided by #ClutterAnimation, #ClutterAnimator and #ClutterState fully replaces all functionality from the #ClutterBehaviour classes. Generally, animations using #ClutterBehaviour sub-classes can be effectively re-implemented just by using #ClutterActor properties. Here is an example of an animation using a #ClutterBehaviourOpacity instance: ClutterTimeline *timeline = clutter_timeline_new (250); ClutterAlpha *alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); ClutterBehaviour *behaviour = clutter_behaviour_opacity_new (alpha, 255, 0); clutter_behaviour_apply (behaviour, some_actor); clutter_timeline_start (timeline); The same effect can be achieved by using clutter_actor_animate() and the #ClutterActor:opacity property: clutter_actor_set_opacity (some_actor, 255); clutter_actor_animate (some_actor, CLUTTER_LINEAR, 250, "opacity", 0, NULL); #ClutterBehaviours used for continuous animations with looping timelines can still be effectively replaced by looping animations; for instance, the following example of a "pulsating" actor using #ClutterBehaviourScale: static void reverse_timeline (ClutterTimeline *timeline) { ClutterTimelineDirection dir = clutter_timeline_get_direction (timeline); if (dir == CLUTTER_TIMELINE_FORWARD) dir = CLUTTER_TIMELINE_BACKWARD; else dir = CLUTTER_TIMELINE_FORWARD; clutter_timeline_set_direction (timeline, dir); } ClutterTimeline *timeline = clutter_timeline_new (500); ClutterAlpha *alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); ClutterBehaviour *behaviour; g_object_set (some_actor, "scale-gravity", CLUTTER_GRAVITY_CENTER, NULL); behaviour = clutter_behaviour_scale_new (alpha, 1.0, 2.0, 1.0, 2.0); clutter_behaviour_apply (behaviour, some_actor); g_signal_connect (timeline, "completed", G_CALLBACK (reverse_timeline), NULL); clutter_timeline_set_loop (timeline); clutter_timeline_start (timeline); The same effect can be achieved using a #ClutterAnimation: ClutterAnimation *animation = clutter_actor_animate (some_actor, CLUTTER_LINEAR, 500, "scale-x", 2.0, "scale-y", 2.0, "fixed::scale-gravity", CLUTTER_GRAVITY_CENTER, NULL); ClutterTimeline *timeline = clutter_animation_get_timeline (animation); clutter_timeline_set_repeat_count (timeline, -1); clutter_timeline_set_auto_reverse (timeline, TRUE); #ClutterBehaviour sub-classes can be applied to multiple actors, in order to share the duration and the easing mode. It is possible to use the same underlying #ClutterTimeline and #ClutterAlpha instances with #ClutterAnimation to achieve the same effect. Complex animations, spanning multiple actors, should use the #ClutterAnimator and #ClutterState classes instead.
muffin-5.2.1/doc/reference/clutter/path-alpha-func.png0000664000175000017500000012024314211404421023001 0ustar jpeisachjpeisachPNG  IHDR"7MsRGBbKGD pHYs 7˭tIME 3 n IDATxY\Wz>scΉL  dXdeI,$Kk}[t?E_{-n˖J,V"by9̻/"D dxW@d;#2ϻ߭xZk(K_?5B!_I)nk@G)~&?_Vx;e3B!BH)ťKkG \)?0ʹ?/ʕ+2B!B>q]-!B!N.ׯ_eu YQ!B' W?Z07샃%!B!Nnܸa @Mk}yssSjۅB!8%|gssefZٔN2B!Bql655vB!Hݦn+O `0`0!BqܕLDQ$##B!)Ea@= ;!B!NrzZτa( SB!8e8& C3ȦKB!BNGY1d(B!8$ !B!]!B!]!B B!B B!Bf=;VJMvs/_ Q=orۇ{G}B!9J) j  =׻pYB!/pp岼vmMWRca86em!eYc$8s1 hd3,/]om[4W!B ]xRH|U?|"*8F$ɽ5e0M56i$ a`tq\읙i1 jBV>S>S0'/j{j(h4}sp5usqŶ-V.4OCӝpt׸(^zgm&_O J|>υ禗5H-M³e[iRL]]+.f ÈϮ\ö.4_gg{s3+jUJ/Ik|;`U_.8w,!5JuǍoޚ|.B! a+/d -F~K L:GWƾx?8b+%"mOgۇmn$)zT{/hf5ۛ4Zn-FRc8% yn~~^sT? JLU"aE7.H2g8hi6ZMG!BHpG)Kg1 EӣR( h bQnOFE󳬜=i{}B(YXt& Y[r"jR$3B!ܿx=2]YV?ZY,XEcwrә~z 5Q17LRaoVKˋPa[R;÷::MQ1/ {Ŭ|C{B՛ߦ}aM椶H$ӳ B?:4j{ uGcb3t;]$wB!ċ'[&)%I2 Z,p騻i~4c(Uwp,i)NIpNfKVV8i! P Tc`ۓzO ryIIӔVMI7`mm5r <237QNE$]cG09d2\~ hܾN$lm򥗨T/]!EgVf3Gcn\cowXi84-l¶, uLS;jQ{Lf},ˢR) wNCF,,ͣԃ7fpH;V8aqa˶V'N h>3+Җ`pOuO{0ݷ\G}<nwV+ENJy>:Z7DwA^4B!ϖ?܅B!O'2B!B~܅OF !܅UgDڔB!,>iJ)is(3$L-*(qPh=W!xXoz.A!ND%>꯲ e]!x$sX^^fyyf)E!NHt~vE"o2HB!PJ q$ڠgKebm`gPJ܄B* !NQThd5bkSxl&BHpB"{A NZh i0pB!$ !NFy6*8h2fDi B!]qbmЉrl<69˜ӥd0̰ !܅'B~(JS,yT!JdB B ajʄϪפf$BHpBP`'6ͨ_eJ3f+&vB!$ !NNM"{An!#d1t)XtB!$ !NJ61Uʼek7}eB!$ !N,k(uYiFP)U{עldB!]q (TR S1K!snSf؅B B6A @s:=rf $BHpBT4: 60Uʲ{Ȃ!g2.BHpBDt :8G ,5t%Ӥ`B!]q}xev2Q`i B!]q~X ,2J\5:c B!]qRmRD8F̊b1C @I!30 L$c~ee&IN-w!3ajюrl5I1b^όdS!o3gկ.\w/~K9{v_ipr3>C|f3/i6|A8Y\|u6o:/D&A)E◿|rpUx>ڤ:\28.x%K % !8unܸI67yTU~; w_ MS7`mmww1p .]zgϡ gDQĭ[) 5nܸ ~q]_13S?qw!qE/ΰhET)5{ȼaˎB!N~G}=Ν;˭[yضv:?k׮S,X]]w`𵏕)o;6шW^yq?Fݿey  Bi a?IQ̀EJI!))nbyyE~hZ}9'IB7 /Lgx<?/wx׹r*;;muB_R*#3FR-oX׌99-C< B!!)_k67z\ZVY]=CͶ߭h꫗˿)?4{d4y7looɌϐH4AN%ՊR,/5B!(NiZaE~rG7xK,..駟-__޾w!%ڠ T)sN%MaJB!aikR*u6/:ƽ\ ~_cjݧT*{08{,wv:ç'6FR*#)7N>su^P"&Ekkm^RڅB<yOx_˯8=G?!sssޯze+M/--M~NƞqJQ~Xf}\ΰg͐NOºǡZR,cvww '$xq j5?0o˟韰˵kd2'?biibcc|S*"ˡf<?f"%W~Ư>A{, BƩsT^OzMς&k2H ΝcqqqR033>B<./JR`8έ[oM._JJ Lnnn0,dҏWzxSZ_3.Lkƴw!^@6hFvD*am3(>̲?R3gΰpF%miܾ} !ģLiy̗i\0|i{fcc? #ހ[#]LģqT>J\ )Y#f^GAdê$I7]Lt:t:Ip)^Pf/(Oы3nLJ{GT:fƴ֭[2.܅x~`{34<bf+&%k,3:<͖_%.)䶩}2fa'(ngϞ}΢w!cqdbr6ZOPMau6 R +!K^WEJק3SeR.x=S|,]܅x(5i96:(F5˙L)F҃8DxyBh4b ѿMCll1!c&]? +l Y! gԼ !0a~~|>>Wv6{ b4Ċ(UR.]GQ`7(1֤ψ9i0pD;g:Cz])͛7lFqJ)4%ɰDT"z9Y&w% 0̳$ɘ!3v3̰$yLӔw!ı BjeYܾ}f}8f6󅄵AzWF/)Hd$ bmҎrlqD8F¬aQF)F<_?bW)Bj5^~e<# ÐAԀ˳>i M)!yY*]Qt A(G*eMZ*ϥ;e3J)VWWv*Rar91qcۓ_{{{E>3sR53 Kww!"~X"JM5פjDʊ"pyB CFHpa60=`%Ӥd$ qLEMfیԼ lϚ.כQP@ռXyXEbcccZ #]O({E {쵙s;R#WoZnW\W!N{wgXq{Pac']& C ܅xrƩ^P ,2=`)f1tɚ ޿i<2BBeÀ\șhʂs B<96hE 8C ,YR? IDATp;d@6Pa#ռ+XZZP q(r ܻQa%% $ڠgYRm` 3NI% |xZ}Ǚn"8yaȹsh&7wH՘SrN*]_ NPfׯUBR؅xL(lR(xRmیF#RxG\^P*nZV֦Hp1ᤎ}(Xã~=#A1fi9$zuqv-ᐷ4]^``(M=\qL.ck̎_aZ1g3 vJB$P)3v^weX  IB9+VryfQy6R#Cyu1+˚ENh>ᐃ ܅xmЎr%aXX*Yt' O?5=!P 93`mvAS+`[,^pf; lU6Ņ$~^3d=dk?(qtM2$77FsX*o1 ,q{lŋiZ!^(c86 GV#h4ݝ.8.]& ? lum`p6da%ktF̀giEܗ6At4X\jKmfޱM8NLݠ,o̝oҧ}mmMcdIҕ+W@>c/0C@QTdp VLUɛ  c (`^PV uGcW֊=V18;=s8*࡟WLjycE~QA1ts{윧Si=yfy饗O榄v!!T2 q'kkʙdé|^l2.X4;An%Y:9]:'A-cxBόNgFaT HqScY^XfF(qD9f#-QH~<0rkxvc>PwQ5gIf0Dk q5 `=NJi΀Ė_eܧ=6>H<l_~~}ccC ܹs춳?Zg. LlC3O({=ӓhq1ZadkRuLhE*b;pA3*jŢEIȂxfTs3΀Čg'PG,we$, |S93dih-lCޤ/0li!f6J)0$P.QJh4R+eY-$AeƉRJ֘Yǂ>>op(5iFy>s{<åδe{ iw^a{Bc1ekH3,W ReLju3qu,P08>RsD#v} lcQܷH͙,b}l#״qnooBT!öqfffvMՒό.N??oEFQ,mj O,#cXY|^ɳ6T?8Z>/vGׯ.p`3Ek9/ɚ[/ZH֏~y1RV3[YbnQQpOqb fggiBTi/D(QsR u>33C^} k׮)(0B8a69lk SwшYv,ym= 9X@]{]M|y@_J,P}(X\\IJOui/o ^RZ4M9s iNiJՒA E;̱4RZeX<(qR+SDi8^,]j r#K7 C h*.q!f̮ tHA'βK$>@ikSFShïW:?,.P⁴ CB8=ƩC+̳W$ M qzZ2+3n0gq9"ab<"iy*g7PFd|Xbwq D0ʱTiG9RJn5Ɛv! ш?l6eY(/#^d24Mܔ?}5C8(( /Cv!]0e*NeP !xnKZ^t١q51^Ou S^PgHQd̀9˜#g)F!s4MVWWYZZ  "dwqڠ5]x%&Jw:,ym/B! lut:4Mi($x(GMLPfZv!XYYaff5}ܸq0XJbwqbx%tdXvuQ!ĩw'gtJPJa&i\.HEt]I.B8ƉnX (2L\`)f2M!)^ߢ5H5ݔbcNu"4 .7od<n% AXbǯO<m`e9C1̲ !8n:\9pGLޘɺ/^VaYqh4lnn 4vNeݯӋ36bf+&9#.M6\1,Llmیcvww'Me.Nu`7v2{AN3^=֎B!9I[% 4QJI9.N^a?,q4kȼe(iu%Af؅wqEdǯTVFL3#eBL2MYfΔir8CSRlCwqE+ʳ13L\41s^3^ ׈% !xf[oEP M5? 24˥!.N\MQMF;ʑpgkS؅B?ZM$ZQV+14[ijE'βiFR)5ϼۥneS!Ϥ|>jqᐫW>Zkfs05[BHp?xfXOm4鳒iR8F%B,RJ1??2N(Բc !$~Z%65B)Ș!n3^ C؅Bc&Juum\.GE<ϓ7JA+ʳm`w_q]iDŽ$h%r)YZ9}5{nzEɪN$Q(ހ&7EAB)J% 8D~71""riHO`(T ,"O:gQשVضM&!>c2qR^(2re5BIae$\c.'etDD6puvDQbv <]ui4uLdhhZ:Z^4gf ,l#k7 0)FDDL&lRĽ{(t:6NX8Z~`d2$ ժqC;)^b2Rb0\#j:#""GީSfx.JXyj5&akm[G܏-'fXk #At&ȑWrMV:Vn}ߧlR.=)qmN57FĬ.á3"q$""GV&鏮Z-ZbGu]VEV#4TJ=E8s`a l LFJd:ňȑcfy$ (R\.GV;ցhDD"vQp?nn0:aA@iQlXFH%ފR)ry6vVEA ~`ضQvQp? Fg ]w8"fxP驎]DD~0]N.R)LwwX(hl B>}T*E nbx޷VE\}d]]܏&Xk"$*ӑFEDvN>DZfɬH0(O\hE\>u]"nD"A:~I" DŽN2)3aةBkbxZ_ccxl6K8֋E܏Noc>c*2P{Q8hAjmYdR/Qp?| :~Gvi0 c7Ɇ Oy e,6UZ[kID0hxv)CtvGSvHHI#""r;pb؄h+MZRXb99E܏bf0HX"FV= f}B@ ebCqe*(^`RpRltn`bc SIQv9"8y$xNCR6L."'{IË5JI&12˓*4M,<|gddD"Aamm q^Cյ&7v'F'X؆G6`:Rd4RUkG9=L222UN2rn%"3|p>EËN1c *Qѳ+""GB2Ӥi:Jt: n`Oָ_q{ Xpٛ#""\ml6뺔e<ϣjh4ܤ^ N`[9L ĭ&b"/u `K4]kb!EYXX n裏h6ܾ} ]D^3?3H;4['bd:z;4|޽{,//+ȑW؉\`pjù.Q, ۶vAh?wyZOD^4?mRAP4e}}]Hs/Fw IDATpaK6fddH$rU Zf)"vp*T C"/WrDzפд}v⭓,. JvL*jUPD2JE]%yt\;} Z]bmmZ&" @DD{C>U qe^"hM6CC>Y?E䇤މ"""0 paZA"8e49".""rt$̀T!W&cjz4 08"" a07?K*u]r;VWtYDDDDd L&x7Z~gNaT#""""煦SD"|OaY&gΝE׷(zDDDDDx#a0;?KXX,.czvDDDDDvP&l4qNVM&3ѳ#rqg&F"NGe92-GL`Y0 v(Ddn~CK$&I=3~GS4CA94m4q'?B! q3 P( ݏa8s ,>cN6`ccG.]…i?~ͭ[ 3޻˿Kb` |0dG? ݮ:1 v4eYXIҳ#YE:QoyD2W0HS~@Z{z22:LX"M344HR{dHeRB!akc͍h9"haL$gmuX,ف ﳼN0nΤ#IcRuFvlɩqҙ4!ۦ8wsyW&sbaT:E"ۗ)J|-&mqiN][Ԫ5&&z, ۶4=r?O~388;%`:g|7W|"P?h7Xs+++ h4z"Dz 0> N@Xέ{]D~L E,"h4 Bgt1B!k}A)'T0 `dt v\<ôLR$+kQʾzh,J$a+o2t/p7[ms ('Ns]yy,/^o$L]hnw:n`ukmH&;t:O﶑ͦ baǙT:k/jk4[mR8-#F1 w}o2|z+z\9ww]XOD˲p]l6h6 '^}^Qվ׮}|ߧja7nwFE{}?_??hȑ=OlL4M<#_9\׿AeIa`澖M~_k]DDX|? 2NDD~H ""Jp]\N=Ee((((((((((((((((((((((((((((((((7`/geYxܶ1 u i[s 4}Axoeas?.<W(dqf[?֯ۗW ,>i/o~?Dpcjۄ!.:#.z*k ].'9x4Yz'3C~dVō/"""30e)w6d6<qFG1 |x"Y|?u0  1844nϿ< #ÄanX,0Y&V{mN[dbr?RywN"LFxxCoyᑡƁRIοvIJ!_dyie1܅3)L$/fxˌt{>;; """"/ݲ,ffx0 'B ^Gxh4{W?~}0 xw_SdGH8G FF4% lzO$D"L&1 4albʥRA4=p kLɩ 8_j 04MR'O  S}qK}=xa@,%h;߼4Awn=_DDDD^~N˕^Nıq7 N,M˽kt =z#x6##CpsNsNNbニF0 VWYYYo'I}aI,/C#!N,14<&f P70 ǰBw?yxR`yiN΍/oODDDDոOL1=}hcL&DCn$L2l|bBl`J%8w L u=[:өvmŧ>B l.qP(DXyX DHzvd CCLNq"zo'3AkRI'vK sD"^{.ϵϾI(8uz۶h]w:jZ?D'~T*I۝~9ȁ L°a,K$qZTngF+ FZF: zoE90G,jBP8D,hLLbۏ}?U0 'wJ1 &&xO|L&5V@w&uht:lo]ǡlQ. t:]L$JgVWu4M:JqrqWx).~p8۲1I_=XK2vjT@$fkcGdF8({W Q'.Yax$ObYaZ&ف c<|DI"""" trLZO&Ƿdd*I("ZV?>)Do)s,d&':vJp2t}iX荶CoT~jfZB½O O)=1 B Vt] {4 N}z1NװGCa2{}o2`lvrlllrD"f~jBpѱH[۴v'^h2e[v3i^x~v  p~̉e[L~pp^_y؝0:6|oj A:bhh0dMw<_Í/nvXmgOfFLLO8m*'&'D#)l1gx5b\^P(2<:$c.""""`pOS-3|+Bg$ݿ3Sew|bA@"+A/;Djwbjܷ<Wn!fgJ~wO@=@ iɦ]uo?nZέw 1 àjH$IZO?I ~"LG\xdF׾$;{LLa6 'XxţDDDDd:I1_/~,uʠ#ea]ޡt\rLuVdór@{z7i<* vY^Z=r£B!k* Eʥ2b ;'e[r6RF`JlmlQNCa044H֠^hwo'LypX]DDD0|OOOm)}JKhv"Dtw9H?;(^(??G zq 쫟r+ XC; "QpCz!nJYZ-*bdD:'QV<։xV2I;NN&i%tqՆ(s Q.,W*ī~K^'V(mf*E+NJbtc1:_Xo=]mXDDDD]Zd"MR!;ivםTACC4얱(ȷ`ARe%1~)^(D+22Buxaݯ"""" "ߒD  rٝ;|ˢN$h'TFG)R(!Q.3Mfg%^>bt jral_&(""".#ˌ[-L Q0=Mc`7qtZ((|`w:j5FVWvN=0MpF&Cy|ӧOOF"@A]DDDE{瑨TH 3L:r]7Lif2P-j12[[dr9­V/6J2l IDATǩSHEDDDE~\;wYY!Q.Kkl..N$pQB6Ffnb`s!p"jgfX;w8mM022iݦDOT-Up,%Y,aWW0a:qv2&""rLs%~߱ F{LMM?繼֛9sVE@&Rϗ,w}uir\|E:'鴉Fb1\?v$ûI3Ç  f:M~fQjCCumt"|z3h4,vvv~8~Sym~7z4N+W>g?[Ξ=g]<&&&xu_u~bfE<77`cc wg e_g`shkhϳ~4)ZXL5"""/v͵kßqݻo:>$\g/j5O122L(~}A:ҥK,-=jrjuAP(jիWYX8𐂻!]]Sw0w:R #pa,Y.]<: """/}ׯ;gWiM&AնI&juysW?gxxcۿ/eLuVG8* dtyItqʣl/,y$A|{;w)~?R(Rm .d*yRO_zO>So?00o "ZrV*SQ`#CCbQ\%b.3{Lĉ\:7odyy[V}iS'i{] s(˱f;s_|͛ B53V.\`YZ4N$vc&JqE "?5VVVvjj=zĕ+~=Aj<9YKZe?xJ`tc1X|ypXKDD䘲m_gpp_QVߤRPTH$?r->c:΁b~3>z)};;?xԝ;dyr l,.z w={?F|>s~ܹ|,~!ܾ}p8L8}ZcgϞhv`J$޻LOO?ZN*r&{:gmƗloc>hӧY?sx\KDDDxs.۫i;>\Zr9qmTU?h40MwwƷSSS9sӴ8Ν\nݺͭ[ VLܿOVqӧOM9p]N- 7D"n;E7`9| D]҅lB^'^=R)Zs?xJѠ81ѿ,c9XV&sO&÷,j7:"&`i҉Gyjpd[6*ˑj7Y]r(ϳrQPH=fuYY!Y.cwO`Yv,G {eli BmƖ=Q0o<[[m4hl D"y$ 2|?E7>0@ylɌQH]?zkk,~1C:qVy:[ xO|d(NN>vjuFVWO+7bJ Tt@i|m7cj^DDD%f>\3+cj7V/[K_iB\?܍ŨgԆpV72:J:'VRzh#eka;?/2:JVcpc텅C?au8(7_AR *ˋ b*s_~ɩO?%lBl-,pwξ-hsV$v*.#dY?}jH lo]8v5g$K%7ML#.˲0Muw%3BR3K98.?Psׯ3!Ξoh1Mf6K3 n*`hs͓'щ@ed ʡ]cl>u)MN*H 9p",v{|UO d2I6% j Z|Pvl-N)˱*9nj?x@^dzmVϝcEJI/tc1Jcc$K%O,<Ӥ>8#[X0|!?ij d2ӧIӘ066[[[:H"׿ x[TGhf2:P w&@l7Ն-txMFLn kkzQà2:J\&zed68DqO`>Z?UP(ę3gHO}۶M&!a[[[yE jۿ2jU? }ۜ3ot]=˃zi;~S37oҍh'0aJe B6_Y CBt+C;tc1Ϲ7щze!`.(oxh@ח3g<'^zj?u荌hO8gh4ʉ'}M89 U,r!U,axճgY={NmLMM1>>N<gggṛ_'Y,2^udG/>& 1[G8?33|Ie}8_q-!;b7NKa:}xIW`_Ȓ+oH$©Sz'yP?~z^'ll>yB!2 HB*J'M\U7ɣsOv2ʅ я,}\Uei|'2;;;>WxWͻfhct.w`i^lԙ3\{v̓0Mzo{7egnHW6wyaLcdeSW0D@oЇoٳZwqz}':P+++D"2sռollی~tnF. _|', L_oRl#hgDKKZH9ռ{>"B3>0q=-/yƀ( lrduLߧLrX\|ej_F (* nܹs#wWeYd?݂F Kv/w9u\__ eJ""{^͛?T*w9aa ànFIe4`ݺI.]<:.Oc._|իypoҥK-"h4w'OTͻ (͛7iZ!M%pE/矻wrQ+ȫe8 ?l6W/՘ N|)bBo/7?s."?Qw>~1TD'6 HXTp?*ziN|GQըG{."=SSS\.ɤzE 4>r\ۛrQ )c\M$xwFޥcYկ~EO]D^r ضXW䕳,p8L?^zֱcFFaR##*zFn3+66,=܅ HD^RD"7^1ќwyEѣz>dd2ɶe|z3}F sX9yR"y}rr4MUHWs!,";C!Oqk84|>Z) fb1[-J(~+R{.oԩSmfzzۭwvF\.@Xݻ4^lziЈ O؍SR#28"JU*fgg$ =ݶwò,FGG9|0ah40MVE*Rez70PqD@(111A9yoZEyxE0!PS ){m,a |d2ǡjfR)2-FV9y2#j68~?9pXcDy!R)vk ,-n4hݤ;Z$xbccMͦ~% (@ -S_(59֭[>}{}>ܽ{WEy79vƷAZ_(&hy<VV)b8MNX:}ァ."^Zyy1#xS+TUrv[5SpCxkS=}++4m/p槊H(JXղ,,Ryw7uT$w1y~ U OӚ*"]%pС ]# ۶6h?B-6wqC{.ǻؠqm]*"]4Mb'OzqX__Wȟz>|An7 ++ؿ R q0|zW^lTS=Dz waivsvr ({i(bddF&8?d`aoDg(GpLSSpC0ħ2D ,=KS1"% 3>>{WTWo(t\ Dd2lnnR(>ZbHݡv(CصMۦhO,rӿ=CssýK;^="U(/4R077G:VSSSbYfmj8Y2-VNT0w.]"%v{gff_ HdTDyX4MJa8rm5BShx,; EB{oo//wWM0}6Rb&|QpE|"W02;K4Y:si@_ȫ~1/0B]ߛh4ÇH&4 ͦ $ ]rO9|f¹sOhz<*tUxўr9ɭLHWH$4\.kN# ```aǡT*MT**(w a=f>IVhyiЮv08xK%< `]I^/pP(|L&i{m1. q_\ħbt:l9>Ph =/#]Xo[]e]B$S6\LOOD0MZF>#ޥb$3X3qFD>??.]%_ГNc쬖 _-za*d-Oܻ]O&̧ؠqg?#5:DDjhD"|v H0mkB;Ch{ .i>|HRի8Cj>ch~> 1>ˆHwiׅҭ[߾E2FTDY׮q=Zn7gϲ| #"]w{_dGvFZ8 OXA_lwX_ZrUg8eu6gyZ/IȫwOBt+'WEgl;Y ڥ+hyC{SW`W*l9? 8"c vK7, EӡjaY _׮__~]0M ؕJ|H2I;?)>FDDzvv&ap5IDAThZTUqj/p}{7xx;$SaDTin`YX666jR)tbuQpch0} wvpųgiT6^ן9rwc&QOh@)BvrLVckkm_ג<06q-V'pAHr}-O U"˲x< mlۦT*8 SD+2>uOZ-FGG|\.&TD"A6UahhP(D.cqqb,fJMQpS6'._&JQ 5QD^vM . 4qr^`9 `bb$ݓVE.SDMW0H˶QaDt(*Ȑv Bx^677i6ijDBVQpo7Y:v:i:3&"""_OOcccb1jt:ʊ#_(իx*̟?OWaDDD^݋L&NO8T*jP*hi4M,45C_:Vcubap)0"""/gttp8L*baat:͍7hZjcVk~7>ii(_J[yLK&K"""?xv08{,>f7lȋޜ'LAOOFF` `c|RQDDD~ H$a.t:}wumۄB!,]' /,:gϰUDzeYi(lT_}V#sァ.""`<#n BI6|k~vM\RtB!RaDpzpK>իBO.""'vh2I2ZbӴ6>z^S|MYZ{TUj{ݦVQ,i6kyޥIh zi Q (|~_h\oXtڻEӡRPThZx^zE 1޵5FfgZ-ff:zT'g\t:lnnPV)m|>p۶է. Ra⫯#.m| v.t:TMJLf6 #]8F\.Gp\ ~ñX\rg?苈bLLLCP͛C|N lhzl=:zRDV j.H0~:dmzÇAg""3 ۶i48C?@|>O2n?'V؟k%\.l6m>^(tj/ĮT(t4#""{0dpp:t5͇0 8ŝnKLX^zbضME+:Fe`idtED9~8`fRRu?8Z-''."">ãJ=& R.F9:Zp*"  WV0H;FOGUDDh4J,0 VVVh4vJ%ID^n4z.Gg:*""R__Ǐl6I$4 Tyг}Ns(E:""r Pi6vZ9SkkkT*JDހhw@9aiM9,"344D4eeeLF8*|c,:E-qB|bw[^WD !96I2""JghhqXXXVar9j %"ofpoolO 4I;]REDq2kkIan0 ˴Z-?WKpj m*==lru$EDT)K#_ n7JrL2,I]D+0V=3u^Hpb ,.`<=*GnCzDl6KZՆI"DeN:"]fvvw4 C}}?#Qi6*(8"R[_òtEiBȁe@~MDDϤd v/e6bQ+ry<&&&/G7;뻊8H:$" O9 R)Au:!u0[0"w!V\PVEX3nYcǎ0sr40LZƭߐLl*q ?\v39}3NR()K:B""""":;Lyҩ4a`Y&/`ȎWzq! |qeJe a`Z&e=qb41cw˲Ԗ"""啭^ol~;+^oh4 psqK+{y<6ϝ²,n|}z .a6-K+޽OV"0.\.o# {-^vS72M^**R qq*bx,L&C^+.popt:[GG}DcQ\.##,/M<#`$7d3}RivFGG8w/2v9}SSuo6~7O(rqEpcmxw>^̙;6NOOo~[uD v 6a "0 ϋeY$֓Dc'. Pxpv1MC!at:\p۶iZd3G#}vM"v vs50dVR]Tp r(jv `4[-w7?8gϞ!NS*ܽ{l @&%H011mㅾVoG?In޼I;)X__ge;OF9</Ͽ/y={բnr0 crYX.J#򊙖IOj `J+ \ԙm00O0$ ܶ00(\v\6E6zeYJe* 'O0MՕun|}kr12:^4i6ܽs0 FF9qjǃa%U*4/IZ믯3==}.^ev=z,ʴ޾xkL8i/ 8|xRtD j!ܸ~Ff##!ZJJP7F:P*9jc6k+d2'ާ'J~"W4<Tdbza.R)Wv,X,R.<׳ h4( jxll~R)G$_#3'99q$׮xq|>Ν;K/2==*+/-;CTl)țqR2` :"L<VQ< FGF(ʴڭU'>,Z홫X;-'X,.,sٽp6rxVME6|(Zja.6\gc]m3'86~U-=`^"4<(/B":G&R_DD^sJ " ԵZ}oS&mFj(n`OBp$Lq(Im7^g_}(brjvCq"XI Z~BQKLq{rjF(Nm8Rl:Kݦ_T|6nM0`k3npZF}B]ZJ$0D">Z£XzbߊaT+Ur}.Vhw:aYa3mQ?0eRX[biqYd@Mn޼I6IR͛jU ԣt:MZec۱z}b&Hg>~wQTHTdss0X\\nt+WF^,?d9oK.]DD,z>L]DZeDDR. ZqQpwwQpwwQpwwQpQpwQpQpwQpQpwQpQpwwQpwwQpwwQpQpwQpQpwQpQpwQpQpwwQpwwQpwwQpQpwQpQpwQpQpwQpQpwwQpwwQpwwQpQpwQpQpwQpy={0 UBDDDD 0m۶q\rm0M e6m2"""""c9=e۶mvUvmXAUFDDDDy,/ѨFU$F&p{{{ur󥁻&6 (^W9^/qH&~UHDDDDgbb #iQ~owym$""""j;#mQ7wnlrr944JBCCCLNN6v:N/z}zEDDDD^N&O1adӄcrre޶ Ή',KXʼn'8x~ǝ?/~ gjjJLMM_l;#dqO&9YQ5EDDDD~`a0==ͯkb .zfp pF[ny\B*h"""""!۶ҥK9sn \3 ;8m{{{޽{LjJVj"""""b;vo3 ciw8tjJZ smχ#ӳb?(>k3&q\cuDDDDD04,WցcVu-ִIENDB`muffin-5.2.1/doc/reference/clutter/table-layout.png0000664000175000017500000004713214211404421022440 0ustar jpeisachjpeisachPNG  IHDRuX]sBIT|dtEXtSoftwaregnome-screenshot> IDATxy|T?ϝd23d&$llAUQZibBmaڢ"Eji@ֲSÞB>3kfĄrgr'$sr;szKDDj$AEWEDDԃ `)pP"".Myÿ.ܬe#""4h  `Јo;úAS1xUYDQ8Q/뒺J4h}HLBǽ b  JY`Ĉ4@C||aw) u[tqG JPZZ{=(Q bRTTBC'_OfUHNϖC,kfb ŕ0|HN6_Hɓ[:Kl{Rѥmy%0b ?BT*0th뺻*(Q/EbbtwWdxɏ(Q/T* .-",0كSX[ VTD~;LKdPa.(tB;Dĉ ,"EEسO7Mkj۔)iɓRw(g$~{]a&)ш>B^YazNؙ3%'UgBuFr{T8uuHPjnߍF# ֭C6c..%ŭDm="'?a,(:-pDdgVAGI0ͧ:k\Z^5558paC[]o'Bu(cfܷ+WeY? Lyyn^UwAɓ҇BUUɏArYY|o-]ݸewwNt8parԝ=qYJ58:L[s|c-(پt..ECNe**p~v϶'*JmP^FC@@ǽݎKܩD,0U8SeMAv4N?.[&ڈ.-xQv,)m")mXQ02I5dg6+K2-W-Ӕpw0QD|ˡQwt`--EW_ݲ>_}GMM 6,eH<4+u7P>!'%" |]cm-L/JWڑj4\xӟ.]Zћץƣ7c%Ii5N D}÷D›ZYn?K(՛7Jz( /?bcc?slْt4@.WSdei3̳\P,OQ\[Eݢ]п E |(Q@<JDt6Y DD= p}(@zP"C DzbU(&w){a/70yo`%"a8@<JDp70].2oݝ8T]""wv܉lV8vPը>zH}(͆;Sp " MC QP"Iyiǃ'!\_{DDD`%"a8@(Ql DUrT߰uwU iZF D$1c꫽y#]RtII] Dih /MLtÑp!T!\JDj1:jTwW[J%b~ O?-O~B]<'Hz9L+URAګ"*ԅ@3qc}:x^ǠK{ߣ;tS DU` |~*=F`J =8jup#a& f ]u.ugϢ&3 ٰA*0~8x0B.BFܣtNԟ;q>D@m*,2 eN'kjP,> _}[EE J%4!3mtMxyYgE!w/JDnI?(P};f~ sA.Z?FɈ>&y}_ #!\JDn ESOy}]~ &SjA֭0ۇILMmz /pb|zN"""ӦA"\V+.Zc=C:<[jF֭80 -EsBV. D$x8"&MڽO[Y/Yf?QW2??<0??B}H~ D$Y`rWv ł˖ƍn< +WFAAoC$ 7+ŋNg(ZefkjpwPeWLIAРAn;@H~W<]v;G =)~eT8 c'  øw0$8 =ߚ'P~=DCrYo`.(=бc^PJDD=@jE x!p6+ ş}Wc9P"$eϳ9n-C7r(sXeWV#t8Y󤞁:hd}+\oduFCNʿR|#&NjP"v(ZY?}ʚg" ׯБ#%`mvWw6F#;x!Z6蒓e_h˖n8t3 <|X={CuwUA1:fT?.[~r+ߵK A \L}111g.(h5O9U:鄠Tʖg@\/\0{TJ|ШTx$) FD@rǎa{Al6Lƻ#!0U^F#^Wll'܌(pʼ#B%A70v`qF`6uZ3tm5hSlɄ ۶I͉H Al 2 ̋ ~~=wLٗ-tIqsw0v`s^2fB2 xM&$͈oqA3+DT*ᛵrAy NYS(a`g9-Iqw܏=DGmmmؤ-?_:yBVK~LQ_/kPȚ*4JN @;05>32i4b;N2_U6V92e V95aI%723qN*VTXu ѕM"p(qrJֽ2bclGO ^3=x gX=a?t~jHLqg϶Jb,:zoG͆118C0M ľGգGaq:122>ܭ:ݸ|_z+AAPAʪr?ҡ^S'˺X^@}h;Z0|;Lsߍߍ{˼z|J*3i%QPe,WBEقREرyA3}YJCD)Jml%Yp0gE1cdͳ!7PJX,6i=H(5iyKE*~PuyvP 'e][=mD+@zQau؉X$ZQ٪&H}5HidϷJ 6tFP*4x<+3UjWoٳ`0ȚjE>G`% %9ϒ;yAe@z et͝+uYYhp}(Q/T]-mაQ$^5<|8ϗ=p/$/ M|"22a1@z!W5n {aWBO˾hJC|7l ZԜ<)R30B(FB/TȀ5k*0Cz qsviUH[sxeq{ӥK?ޭs8 w0R~ *Q}τ^7hR$DoEFc-L J% fW(T= ˖K/U_$"!t7 (Qa2Ya4J*5 ^].T8h압j'0]#f\P uWlT*N`%#?B A=şsO!\9qsW  iiҢ}(Qb2YQX(m>9s7'lߎseSﬗ;}_ziҔS(  IF\H/Elltw"Qj`ΜAT|52,u AۏPQ}NΟj#66HRzA_X `20 ??t GC..~P>('*t))H{e|ӟ^QV982s&ҥ+ IDAT/F4l׿"eeՒ&@IHmUu7^>`Ǚ_ƥG_t8Pw,..{K~& qq^aJ9.\R.)P f4 ~u(.^Uup{`ܿ'\p'80y2vު=tE\XI@~\M D}lE~~ NbA…ma&^O=3/LxWr44!dG8x $t%͆KV$`:5=P> M ^ӡ].ZMKNWT?nfBlXPy JnEvk}4qסOOGА! %]PށEjՒ F /?, .A/Rt`ͅ9/%۶!bdtii]`p*#VB͉p44T*?t8ZF Eں}(Qp8uh (j$|qijW].++Q>q"}!Ç?< q56QWшCP駨^4oT7p^B!0P_oA^^1/y" /, 9 ŝro*&!aà:ii%%!`JÁƚX\)/ 99;sNV&m7_X]lIø ?{6Sj4{ s,.0l. ?4CPt:pp64^Y kY,W\P[YkkᨭdtvaV{rc%"MAg`ȐD=QADma󯿎ݻ3(:hn~)YkDN Ic!V*+PXX-a+W"@`j  0Q+N=Π €=iȻ Q|Sn DԆD~~)}P 1lJu$n~LKj: DtSEEp6[ J%N݇#?G7'yI]H{R񯙈nQ\\ ÉAѐkii[@.H$̟gJEE s(fkĥKŨGrz[ (&&Bؙ3a ֢"| ΜAs5!ƛR!ft$8PcD}cYC91\.*+kQ_oFjj?DG@!ut4<3GC0ZR[y9ZꣽUJHv"&OF@Z2ka2YPލ=P"""JQa DDD`%""(@<JDDP"""0y\z=ADts(>c@D=Zamgzw:FN^ƓF| 6 ل'/p˲Ձ|{DDn;/ҾFpJ06'*W cQqKuw0anVU:}zc?@P"**qr7BQ!$\6esÅc<U=!Vy383ĈG 鑤NQᧀ__!{D훿$=|3S6LAeV%N,=*M+tgd́a[mܜ&;߉A 'p({=֎%1G<·|{D>9{mvc[CH_:}a:vXr0f&&!@(?Soa:8hqۋK@GsZZ܍h(l dKisnʼ욶u2L0U 8)u(KE_KG:4?KL-@GX5~2C:ͺVt]s-LWLͯME&lM:AjU( RO6F2! DԣmìY6@յIg*6Aou\l.tf mVzFDͅ󥞋GsZ[(M܍:zB4^Gix8lXW򦞉zXcr Ns NM:[ gVKgV50r4B8J+V\u;\m!os9a*2!l~Y1F6o.hVO{:LrVƬb3>~Z÷õxp߃8}('"GFbKw̪38#i=6|{}L{wDQIxmK(q%mz|@Dv<tQKA|{ +p# PF/={BR#xCؼ9Cԭ@HG9U 1@׿EPPV32^A]]o !F;KlV ?]&:2 99#7w#T* ȑˠT4`ӧE^&TU^a^DZӭjh(/"пC5 /FV8 蚻QYM1199㮻o6#t̘sd`[l.in߾0g72e*+pViX2ezǯɓKqҧil:d̝{ 3fM22^o`[M$~4 w~`aAnuZͯnʼnK0qϞ}{6ǿݻaZ&bԨ7_Nq2$'? )Z9lt[b"@O˟wjcdt))=k״NYY+ p8,AP:/-6yEGCmmN뒒:uwtiiOeH~ D737ر1 miLW_gd,FMyLVa:MKVdz2{0 3MVgϮIc2COjul.N:/o3fʀNׯX]]^:])pJBQѿPWwZ}$ qqJ#FͱIͯN V4;#;2/^D D,\klj8=N'_j8)mΜY KΜYs`%i"#c1LX,8u8V6r; e:[KD( Rf<RRAOnYh<=1+p"l>6[ bb㡇'9aj:<^aHLqVuZ=tPC8GNt;?O{l\k{WE&xP_וk\vf ``ejCDDDpJDDԛJDDԅ$O"j/BUy DDD`%""(@<JDDP"""0y@JD\ zconӕ%""jpͱoes&vrt=vy kvz w:FI^9'c}H>9۷V n@gHQ9x1._ƄCЀ:}'x3gvwը 1);_|,zxLݹkE݁CdUf?`_W`uZ[qX7 F1QP&Lc&옂!e6mfʬ,ud נ@ƢE4x0Ξ¶נ13;Ll6 yݻO\a/ЩP*}O7s)U'JJ+0 3cdaamsIslܿ~,Ob(cuN1A t ~p$͟}R| l؀ʬ,Xx سs`4 [Ǎk&;;,{:d,Z{%ץ2+ E|l'=}:N#@%89$~:`bD7=l*M: "Fm /ijCŒKӼ&&)Cx>y}msO=w1,lFo<9K>yCShcb3q"ƿ6աH_ژhcbp!<,N,YҜ&74w.Rz=FFү˗?D{aS0gvsOSp>@;`uZ"k6nDaC!, @)([2͹RaڮiͯƆ)Z0zǭ:k ^ZƋG^nu+/i"k n܈B8,Mנl} k{ ̛]ӾƔ qנtb"g 4M.kȷ1v`qb9c`@C`sڠYiΠ39נ5ۡ"S&l&B@ +yL^B͆uנ 0]4aۄנ~ j $̘x"cbcȘ~~*-6#IgD6VzzQOy3fed@k.5h*.>5h...kPg0`z~ XF+iAձ?jncvMzBl&%lۄ1Qc7QwrZ,׶?j{ nl{ n܈I^& [ԧFa;؁#:7@;05~*g,ƲÆ<U*>K`ӥMXsn >ޜf嘰m4* f$̀ .8Y+gIu~3~~(1௹Ū3p4:ce ma[Uά^5]6m¹5k0˱m4aX Ǐ#k #L;N$\Zc2^~SwlsɇځV#?~q/&l"SV[&݊1+ߐ'bak~0 o$&b߃-nr~:?{j$w~mAᘾk:  p|q$ei3QO2aj{Ŷ `**¸m1+V!?'NaPxah[ LLă!6l6|:p N+נݺb1[j*r6l;w"rHYLEDQIxm}H.!Gng䉨^"k_[X%""=Pj%""Bg9CU%"o` DDD`%""(@<JDDP"""0yW"zp!"Ny@r:~" morw|;!!!ƈ#rV""5{Խ^}UcĉիW[ous 7 C Nww&9rou,{1/Aaa! '{}YLDDn;:Fƴipҥ˖-k*ݲePTT?~Ӽꫯ_H*h ovco7҇E"•jŲe0h hZAUy9w޼yzƓO>*ӑ%>k׮ŦM矣 UUU駟?tqDD1@Ѳ /Xt)l6h44 b U>0F)( 86egɓ':w^k8p}o(c͛~5kIIIm76 8x bcc=ӧ1r6GVO:CX,mu죏>jnƍ4iR &`۶mORRN8ѣG1`NMDD1v`ԩXx1233Q^^wyaت*^eee(++իf,Y9o?Fee%***k.L2Er}~駟ʕ+jlݺK/d"""~lgee8o<1,,LLII_xnJ@lll_|E155Uz!mg͚% 144T_}36mǎ+!!!1cO?s!}ozWo`6&`$"9}oSOӛAN"",oZ֮9{ _EMZlޜQtorgVػw~Mڻ|VңppaL+|]v> AAp]w[ZO[gάJJno&5¹skp{pR$%}zط}{T*mMS7wس)qǢN(*(؎tw?PV[gRW/|6DaӦXb۶ w 'gCxqBC_jā?ƦMᇁغu *ј;`l2 yyw-Ri֮-C8vڵ]O^?q:sfs `П镈5t۷Owmѣۤ=~ LZm,**c߾@T#9ћQQq))9nVĠA?ԩV2Fbly?Ə_騩~ 0&Kۂ"֮}SFhh:n}~))Oۿފ=P"SUu v{-bc'@ IDATfh<|I??HO_C&M4)CI-bԨ7ק@!6vƏ_ӧ2jja0] _!5I:_I64o")i.RRQQ/ccܹouwҥMm_W2{7<7:z;kuJe\6+Zƭ}CQ_Jc>!!qg<ȥ8sfΝ[K9Ν6[luK>mx< hlGI>ysQ#3 | Vk\م;Zt^ܿleHY7.]"#t^pz%HJzit~9 pGbL.\,HM}GwOp̞}G_|q ÈlN܇#G^ѣ 2r$;><DGg˰٪Vu^55$uލkc]ի_Gdqg5T*,ygάFmm&LK9f|( 0#G.m}kP p;}`qgؿ㎶)x*=gáC?-Ϟ";C F9x'uwUz{ ,vniڦszre23DUi(j ęΛz?@M]֭ l^8z(*++VqAg_7JK+h8c˱{nG?(|p\]=">]sq;iii|2jey1JPYYBR!)) #GRlNrp1f!::ǏG```F#9ш@1IIIb4|DٳpW}AcΜ92e *++qĉVi2220c ̙3[nlnNSSS;wbРAx'pw##w/Qm}?!=M9 2(2 eVt|. $ʰ)!n)j"( $hZ)i8\yg֎;dZ՘m6C[SS'^|:/׸0S]]]Hqk{zm(IZbED EN`…rjooW^|)?yUU[[ׯ_kգ}֬YyFлwt޽)jkkSGG?~,N ӈ) dffٳgh"eddիW~k׮UUU޽A͟?_;w4LhTUU~vӧ4Kr[JII]L0=XL?u1yӇǙ!0 PL @0PL @0&kGX'*PLoܸqgϞ=p̵uEGS^^x6Vo?s)66V}^ dp8p8dtq|i->f˥͛7Ç(DS_9u竩I7o4z3g#GsOKKN:-[… ˓ԫW>涶6%%%'%%- @C>}ZYYYӲetAUTT(;;[qqqSvvnj۷okݺuԬYm۶ݻasgg̙ku@0Ν;r\joo$͘aaÆs7nܨ㺺:\R9`AN>|ÇkZ2ܜ#I!l6}iCǎ l6e ]]]la?jPQQ"͝;wǏ!:::hh4'NLKv577hss͛߁z3=y$-55u8%%E86lؠr!@ڵkjllTWWJKK]WeeeRWW#JA{խ[S[555*,, ׯ_t]r:jmmȿ58tJJJp8UVzt:UPP ǣK%á=zTE:qW3-3!Gn~a1y|o< @X,H7y^K` \? *PB @L&">0 PL @0PL @0PL @0PL @44%}نGq:lXb$)iV>OIђfFx|>I#Ocajo=P{x$?$Y~> i,@ @% Tc:O\~vѫ*40;a>?< &}-Pr4 t@6Shpx':C(Y(y)UqgȽ O.@Z4Vojھ(4I O/xIENDB`muffin-5.2.1/doc/reference/clutter/box-layout.png0000664000175000017500000002447514211404421022146 0ustar jpeisachjpeisachPNG  IHDR5q4YsBIT|dtEXtSoftwaregnome-screenshot> IDATx{tr GEăz(" Qlnl9mpQѭawkH],[DDt'F i\U{a2&֬!~WP'P_:FOUfOm72Q=~z|<Ot&*&IB @s3!JR*6Rd΄_=g$#5 Li%8#5 ՙ0hN3RbB[4tQ(H hnh*Fj@L?:T}laĂ6 4?L5tf0μ'@#'j5 B p8P@N 'j5 B p8P@N 'vPiYʓe:/>x:_{UD5<ͣպmm(Ԏ9]&B.L|ES4!B t?1OWDM7 pJaW?FE/r4!B xjd]sC0`@T+Pmx)13>%''kMUW7ydy<ZJkܹ hܸqMrXMa)55Ue<ǣ_] Rg}WUU)++K}QRR~$_v$8p@qqqꫯ$I;wT%?_koBfR^ԭ[7egg?A\rڷokF;w ZsO>ӧk׮ڵOs-=wT5Y~&MΝ;+!!Av9R9*5552k-{9+ 5;wo[]q>z--YD *77WK.u͚5˻w߭nIw;CUթS'wG}D]vey;vL'Nl`3vXeee/k?:uA6e袋sOءC޳L33KOO3fظq,##V\ifgQWׯ x|IgyKKKK.j}Znnwz喒⳽ɿký>})5W\\l=zŋmҤIfyuι v"9n.i.[:H:/h s׶m[kժjLy6ydܹ 6>㰖tqر>|:d;vǏ"j*ի9=z$k߾m޼ALqqw}v=o)))v KLLǏ[RR?jn֬Y㳼>4 |MRRRlvQ;w B֩S'믽j{^z]3Pm5 v=%ᄚS|N7n7]~-h˖-:qN?JJJTRR^xAam;eu]lRkDiڵzGn[PP .Ϋyunm5wu_~ dڵ}]wy.rKJJ &x[毪zm{^,Xz5:t`]t'ھ}ˋLmݺ M޽ۻN{ /XN|敗Oݞy} Tg½w1RӼ3LIk e˖i.Z3QR>NLҩ+]EEE.O  54k|tt7St 2tn @dbKwMvntn./z衁*//Oݻz5kքӧOkԩܹRRRstv.\՜kpFLu) .ݍۥ{Æ Zf&O[nEk׮U~~L_|1}eeeiћo7|8tv.\]]}H:HG.ҽk.33;z9Ӊao߾{sss}?%IkZ إB tGKwEx;vw:$U kvs }}GZCء6tn.;RSّld+--Noܸ11y-@KN.BoGH,_^֭ٳ}KHU߄ 4{l@3f, V4.݁Xһt2{-11c ,{ץkvyU_|aÆ vYjj-]g]i۶mh?4ptd Sڷo}QeddD$@#k0x` :T0a~_E$@#OO9M\.]^C]yf 0A])tǞ7.e@]=d=#*/oѥ?uO֯_I&sJHHmݦ#G]K>L=zK/pymϣڮAGrss+99YӢEjڝ{;v߮c7p[;^aÆYAAڵƏo>wymѢEv1۱c)ce>Fi%%%VRRb#G7`PJKK]we>χU6megg[||wNeW]uZʾ+:uF?8`?PdrJ;~ٳ2333+VX.]|>_Qk@@믭SNV^^nf_ SO=彞#F8 շS9v['''ǧN}ѥn]#'֣GkyW{aÆZiyN(+<~/^l&MN׷xJJ95Zz;j]=]6 ƍnDoXnժUصfΜY{?T]3qD[xwu&h=k.w:77AGjjC&=IIIѣGv鳿P߿g=\5y+9識:ud_w^};\+Vjhᄚҝuy0u] y*ѥ;`$!!Aڵk#DTK=}п < t B~ 4p@]py~ws=.ݯǒlԩMݦ]ݓ=zuRSSmɒ%uRSSg XGQk@쿟ӧSO};:uʦLbIIIַo_f@&Wt{<>idZlRYI%POEEE.0?|PRќqOp?n)e4Kiii?~cL<SNi…z QӘ1cݻѣG}{N .l^k@n+ŋoe]hh橧C=={>з~{ǽ+LoF.ݑېKwM::p]x/G8p򔝝޽{gϞZfwt`1׬)=8}NΝ;+%%EA?Ԙ1c|Z߿pvmO>ӧk׮ڵO^tAAnf%''K/Ղ 'UsZZVZ]7??\:՝}HmHM٥[~sב'IvwXqqeeeYǎb={vm+X BunǓO>i]w]֮]k\sMs4hm߾g^k;}׿#Gݿg͚U>+zƌV[l/~[QQwBK:..ݑ[͡K`Cu>I]vٙƔӉ+X y1{};ڶmk?j=^m5Dr׷os7-gYϞ=o[5}6|[`=c>;qℵk.q 5!v.ݑ[͡K`Cu>/t}Q2Ty۱c|5RS"c:`֬ӿw8Cݧ<ٳ}lw}RSSgϞcm /YC]uBSvjݶ# lݨuήMFyD:Rs뭷yVZZ޸q95Dҝ>еm?Oֽ{w۴iSHC Nm5Ciھ}wUViԨQu ɺJDm;ۍ:Pl;x(++|O>`k߾}[nݬ;/aÆYv,55Ֆ.]zN ttmlڴivڅ^hӦMZﭫ~Z.N8#FoW^^tMfvMݻwo7 rK7Pv߶m222|s=>ϚiL]kNKKѣc5BUbQ8] 5iԩSSO]{zgl\5h 5WkС*//ׄ _*%@H hK7j΍& :{/5tn<ɓ'[nJHHЍ7ި?0} jPb͛5`֝6m̙}O4.ɓxj*?sFXՔu񗓓1|΋4&&tXKM5VIDAT.L =zcqk.IҁJsN_o5G)u+P$TkQp;nmIPuG$)77j񨲲RZipQXfΝo+g[o%KBpBjҥZ~9Yfy׿uM7izw23f<={h˖-̙3#:8v&N$fرҗ_~yβtK/_6mxW^^Ǝ~D[g}V+Wk͛7?7ТE{n 2D ,pI$۰a֬Yɓ'[nڵk)S_ 븵wMgֶm۴i&mڴI3gNuG:" ><=k.j]w^Х6e袋sOءC޳L33KOO3fظq,##V\if?7T`]C'_k]9nsR#yX/I&Eb\r}5.5}gs;q%&&-))N|X/ooa-wEO?N[>q4ݻƍվ}{6_}Zbϼ˗kȐ!dA?`S' ٕ*nV<5W4V5TPSCMM#51TLAmZK~UTȑQJ4aUGhMuV h~o2M:T?4RS3|M5iT!:HMh<hhYf5~88rSQsJW`v2IENDB`muffin-5.2.1/doc/reference/clutter/migrating-ClutterPath.xml0000664000175000017500000001406714211404421024271 0ustar jpeisachjpeisach Emmanuele Bassi
ebassi@linux.intel.com
Migrating to ClutterPath Between Clutter 0.8 and Clutter 1.0 the #ClutterBehaviourPath behaviour lost all the path manipulation functions and the ClutterBehaviourBspline class was entirely deprecated. The class that replaced the path description and manipulation functionality is called #ClutterPath. A #ClutterPath allows describing a path using a sequence of #ClutterPathNodes or using a subset of the SVG path description syntax. A Path instance also allows describing complex paths, with linear and Bezier segments and with gaps. Finally, #ClutterPath also provides integration with Cairo, by being able to add paths described by the Cairo cairo_path_t data structure and being able to "replay" a #ClutterPath onto a cairo_t Cairo context.
Creating a #ClutterPath Before Clutter 1.0, all the path-related functions inside #ClutterBehaviourPath and ClutterBehaviourBspline were replicated, but were also subtly different given the different nature of the types of path handled by the two #ClutterBehaviours. ClutterBehaviourPath example The following code shows how a #ClutterBehaviourPath was created prior to the introduction of #ClutterPath. The path described is a square box between 100, 100 and 200, 200. ClutterBehaviour *behaviour; ClutterKnot knots[] = { { 100, 100 }, { 200, 100 }, { 200, 200 }, { 100, 200 }, { 100, 100 } }; behaviour = clutter_behaviour_path_new (alpha, knots, G_N_ELEMENTS (knots)); The construction for a B-Spline path behaviour was similar, though the #ClutterKnots could only describe a curvilinear path. Constructing ClutterPath The following code shows how to construct a #ClutterPath and assign it to a #ClutterBehaviourPath. The created path is the same as the example above. ClutterBehaviour *behaviour; ClutterPath *path; path = clutter_path_new (); clutter_path_add_move_to (path, 100, 100); clutter_path_add_line_to (path, 200, 100); clutter_path_add_line_to (path, 200, 200); clutter_path_add_line_to (path, 100, 200); clutter_path_add_close (path); behaviour = clutter_behaviour_path_new (alpha, path); A #ClutterPath object can be shared across behaviours, just like the #ClutterAlpha objects can. Path can be described by using a subset of the SVG notation for paths as well as using #ClutterPathNode structures. Describing ClutterPath The SVG path notation subset used by #ClutterPath is in string format and can be both set as the whole path description using clutter_path_set_description() or can be added to an existing #ClutterPath using clutter_path_add_string(). The following example shows the same path as the two examples above. ClutterPath *path = clutter_path_new (); clutter_path_set_description (path, "M 100,100 " /* move to */ "L 200,100 " /* line to */ "L 200,200 " "L 100,200 " "z" /* close */); A #ClutterPath can describe not only linear, closed paths; it can also describe paths with Beziér curvers and can add gaps. Describing a mixed ClutterPath A mixed #ClutterPath, with a Beziér curve between the point at 200, 200 and 100, 100 and both control points in 100, 200. ClutterPath *path = clutter_path_new (); clutter_path_set_description (path, "M 100,100 " "L 200,100 " "L 200,200 " "C 100,200 100,200 100,100");
Iterating over a #ClutterPath It is possible to iterate over all the #ClutterPathNodes inside a #ClutterPath by using clutter_path_get_nodes(), which will return a #GSList of #ClutterPathNodes; or by using clutter_path_foreach() with a function. The function pointer passed to clutter_path_foreach() should have the following definition: static void foreach_node (ClutterPathNode *path_node, gpointer user_data) { }
Integration with Cairo A #ClutterPath can use a previously defined cairo_path_t to add new nodes, by using the clutter_path_add_cairo_path() function. It is also possible to paint a #ClutterPath on a Cairo context, by moving the Cairo pen across the nodes of the path using the clutter_path_to_cairo_path() function.
muffin-5.2.1/doc/reference/clutter/migrating-ClutterEffect.xml0000664000175000017500000001162514211404421024566 0ustar jpeisachjpeisach Emmanuele Bassi
ebassi@linux.intel.com
Migrating from ClutterEffect Since version 1.0, Clutter provides the #ClutterAnimation API and the clutter_actor_animate() family of functions as replacements for the ClutterEffectTemplate and clutter_effect_* API for creating simple, one-off animations.
Using <function>clutter_actor_animate()</function> Prior to Clutter 1.0, the way to create simple, one-off animations involving a single actor was the ClutterEffect API. The major downside of this API was that to abstract the duration and easing function of the animation the application developer had to create a ClutterEffectTemplate and keep it around for the duration of the application. The clutter_actor_animate() function performs all of the memory management that was delegated to the ClutterEffectTemplate, freeing the developer from having to deal with object bookkeeping. Another downside of the ClutterEffect API is that every possible animation has its own function (scaling, opacity, rotation, movement, etc.), and new functions cannot be added outside of Clutter. Effect example The following code shows a simple animation using the ClutterEffect API. It animates an actor linearly in 500 milliseconds, by moving it to the (100, 100) coordinates while fading it out. ClutterEffectTemplate *tmpl; tmpl = clutter_effect_template_new_for_duration (500, clutter_ramp_inc_func); clutter_effect_move (tmpl, actor, 100, 100, NULL, NULL); clutter_effect_fade (tmpl, actor, 0, NULL, NULL); g_object_unref (tmpl); The clutter_actor_animate() function will implicitely create a #ClutterAnimation with the passed duration and easing mode, and will bind all the passed properties. All readable and writable properties specified by a #ClutterActor are animatable through clutter_actor_animate(). Animation example The following code shows the clutter_actor_animate() call equivalent to the previous ClutterEffect example. clutter_actor_animate (actor, CLUTTER_LINEAR, 500, "x", 100.0, "y", 100.0, "opacity", 0, NULL); The ClutterEffect API provided a way to be notified of the effect completion. Since the clutter_actor_animate() function creates a #ClutterAnimation instance it's possible to use the #ClutterAnimation::completed signal for the same notification. Effect complete example The following code shows how to receive notification of the completion of the animation. static void on_fade_complete (ClutterActor *actor, gpointer data) { clutter_actor_hide (actor); } ClutterEffectTemplate *tmpl; tmpl = clutter_effect_template_new_for_duration (500, clutter_ramp_inc_func); clutter_effect_fade (tmpl, actor, 0, on_fade_complete, NULL); g_object_unref (tmpl); The clutter_actor_animate() function also has a convenience wrapper that allows to inline the signal connection: Animation completed example The following code shows how to get the same notification as the example above. ClutterAnimation *animation; animation = clutter_actor_animate (actor, CLUTTER_LINEAR, 500, "opacity", 0, NULL); g_signal_connect_swapped (animation, "completed", G_CALLBACK (clutter_actor_hide), actor); /* OR */ clutter_actor_animate (actor, CLUTTER_LINEAR, 500, "opacity", 0, "signal-swapped::completed", clutter_actor_hide, actor, NULL);
muffin-5.2.1/doc/reference/clutter/clutter-docs.xml.in0000664000175000017500000003542214211404421023066 0ustar jpeisachjpeisach ]> Clutter Reference Manual for Muffin Clutter 2006 2007 2008 OpenedHand LTD 2009 2010 2011 2012 Intel Corporation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to:
The Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Clutter Core Reference Abstract classes and interfaces Base actors Layout managers Actions Constraints Effects Content Paint Objects Clutter Animation Framework Clutter has a fully extensible animation framework providing support for explicit and implicit animations of single actors as well as groups of actors. Base classes Clutter Tools General purpose API User interface definition Generic list model Clutter Backends Clutter is usually compiled against a specific drawing backend. All backends have a common API for querying the underlying platform, and some of them might have specific API exposed by Clutter. Accessibility Clutter provides support for accessibility technologies by implementing the ATK interfaces. Since Clutter is a low-level tool kit, and developers are supposed to create more complex actor classes, we expose a low level API under the Cally namespace; this API can be used as the base to build more accessibility features inside custom derived ClutterActor classes. Base Classes Utility API Migrating from previous version of Clutter This section describes the changes that need to be done in applications using Clutter to use new features or to migrate from old, deprecated API to the new ones. Deprecated Classes Clutter Actors and Objects Object Hierarchy Object Index Glossaries Index of all symbols Index of deprecated symbols Index of new symbols in 0.2 Index of new symbols in 0.4 Index of new symbols in 0.6 Index of new symbols in 0.8 Index of new symbols in 1.0 Index of new symbols in 1.2 Index of new symbols in 1.4 Index of new symbols in 1.6 Index of new symbols in 1.8 Index of new symbols in 1.10 Index of new symbols in 1.12 Index of new symbols in 1.14 Index of new symbols in 1.16 Index of new symbols in 1.18 Index of new symbols in 1.20 Index of new symbols in 1.22 Index of new symbols in 1.24 Index of new symbols in 1.26 License This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 Library General Public License for more details. You may obtain a copy of the GNU Library General Public License from the Free Software Foundation by visiting their Web site or by writing to:
Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307 USA
muffin-5.2.1/doc/reference/clutter/actor-example.png0000664000175000017500000001154614211404421022577 0ustar jpeisachjpeisachPNG  IHDR6_sBIT|dtEXtSoftwaregnome-screenshot>IDATx}ua礀KH*"@x`#-=Á ]* hRZcY]*Z 9CPysg{r&)|%937w~V[;MskS$9csi;Z* e`` }8V=jj%;73ٱ$*I+_~y=tA} x≬X"K.aS˳V7O Gdha#f]]]~0}}}i6i4;lPJzöWղ~?&yJ G>2rLRr|'C 2U* j,X hqr==p-`^~.)gʧzj-Zdv .aGϔǚ={vfdx|VCe~${g7Uwww6omXd߹sl}3Cɞ{w_N8~il6srԒ#{TT)q9SRVhѢ$b;#sIGGۤnigʢL<❣.ϒ#}Isy|tvvg_{Qy9i~.=nZ|,\x@.ϙ$ӮhX̳+W_W1wn{s7-7-KV߸%~{x+/r>hQ۱wuw53gӭ߰!߽傏|sd?sCC91G=_>eygvݺ̟7/|#y˛tttY|yjjvzRRz4G<3,X4kid%|s?77o/OK]fֵ]7qI>vvN<9}>qAzeW\9+}͗$cɺurժ4ߟ䡇$?,+oڎmn\u͵_O]jZlf͚5;w|7-M7#juyr;%3Ϯ̦Mr׏ܱi6KVdw΋/4طX-˯)[fϞٳg>[ӝw{>b6>/9;'p|>td]-3'?~衬[.syOVYּby]7/} Yv Yv /IwwӬ[.\s9;˙˓Ofƍ9p̟?/x Syaۧdpp0?'7f3?V6ztwNsǝw?[lxy9)w~; nd);9<0x{5i[Ν7->8?T9w3s)ǾLeLݲgɒ%I'O-Yd¿-|N׍㵙[lݭTTƭkʹW^$9K/{֬inY&=G٧?sf=~```2[ϩY&]՝J;;]]]9sKsmޛJ_z>z1кZ"?߹kEv3vl͐'[\}uy駳~Ælذ!mwqW+s??.CCCYzMtttL9`*J%jdVh4|$>W_[7si̷,brȷqٙCtx`u N\x@z s3o}.W>_xqZt`>FߍY9Cʕ9w^w۾y{N}FO7ݸo޴9?C[3cF_; oƍ_]KÏ<./en%G枿a~SluwZ[o ^禛nJ̜9sߟ$y=J%/n{ur-[N:)_̜937n?;VחOu-M;444mm,-}}}T*H^OZMwwnqMZ͆ $]]]ꚴvczV*~r˖-Zp۪mWT=KhTzzzё-[=v?0k?if̘4&~=93~+ɦ$G c~ޔd[nݤㆆ?׵XZ&jhh(7nl{200cz6i/s'nwӦMnwN?v?0͔]#fc} .#ju?w_K1cFc>^v_{Od̙;ul5YfeӦMyg3cƌtuu8 3[l{_kfO樣۾[t׉K;͔m %i,͑%)ԑ;IO1{Fwc׍$I6,Fc͔P>#9غz Glossary actor An item on the scenegraph. Every actor has a parent, except the stage, and some actors can be containers. Every actor has a geometry and, when visible, it should paint its contents. The base class for actors is #ClutterActor. allocation The final size of an actor within its parent. For example, an actor might have a preferred minimum size of 20×20 pixels and a natural size of 40×40 pixels, but its parent may decide to allocate 50×20 pixels for it instead. minimum size natural size child A container's child is an actor contained inside it. container An actor which can contain other actors. If a container is meant to be extended using public API it should implement the #ClutterContainer interface; otherwise it is a composite actor. A container can let its children manage their geometry, like #ClutterGroup, or they can take care of assigning one. event Events are the way in which the Clutter backend informs Clutter about external events like pointer motion, button clicks, key presses, etc. geometry An actor's position and size. A geometry can be expressed in actor-relative untransformed coordinates; or in stage-relative, transformed coordinates. minimum size The minimum, useful size of an actor. For instance, a button might have a minimum size of 20×20 millimeters on a touch screen, to retain the ability for the user to press it. A container that manages the size of its children should always try to allocate at least their minimum size. natural size allocation natural size The default size requested by an actor. minimum size allocation parent An actor's parent is the container inside which the actor resides. scenegraph The tree of all actors, starting from the stage at the root and following the containers. stage The top-level container for actors. Depending on the Clutter back end a stage can be associated to a window or to a frame buffer; also depending on the back end is the number of instantiatable stages. Stages in Clutter can be manipulated using the #ClutterStage API. transformation A rotation, scaling or traslation of an actor. Transformations are independent of the actor's geometry. muffin-5.2.1/doc/reference/cogl/0000775000175000017500000000000014211404421016563 5ustar jpeisachjpeisachmuffin-5.2.1/doc/reference/cogl/fill-rule-even-odd.png0000664000175000017500000000606114211404421022666 0ustar jpeisachjpeisachPNG  IHDRhxNsRGB pHYs  tIME .4ІtEXtCommentCreated with GIMPW IDATxۖ8P2`&)_~JDcSJӔd$?!.ӳé  `bRUWsJCt'fjo>?mN4 Ô|mN4 O|YmNh4 O |mNh4  "c*gϿ:4h4/_ cG =ohsGX|@}hP|bI6'X|@}fQ0>;㓿>4wLL}&hZҽ`!X@} q ڜ`!X@} "C@dW߾ >4 3N Ər|W44r7gڜ  hT9  @@c͙6'hh_Dioδ9@@@@x#Z{s Ϧ4d|C]i0˗ı&3"ZO?^#GahspB Eh Z$9_+ C3m I׼n919+VOQ@H(Y=a^̝H}>]WQ'UOQ%j>68{PnΞ\K_/@pk, AFHk2 j `&!56zM;sa/QOK! E^!i`M"h@[4A|L8CHᬋ6zMkeqΜ|% 5=S<3P̉r!ag5]Z[tЖ:}^ ݮZ g-sZiwss}'sr0wyrE0-CH{,ZOk@R?Z SJӫ'Ԃv#vJy0s>3z0F^^f A ^ܢ|7 ;jw",hyj13FPQZ˛jiD8@@ J]"B8v&Z30,ٺ:_P~y7c5g0?ԇ0ptnڧ`Fۮ5`}sȐ]<496>̇&xnڻ` ns5+{+u҄3za>:'ѹvʞJ쾅4ጞ|=cXע̄lݻ&>G16&r3[cD>͟I8C}`>hːڴL8{؟1z}~clg>3} &>}H[A[3v_Xp>Bں$Mr5o,ZH{w͏P`>;c) gF(!B0cl}@@(0{d!pf$g|h_CW{&\) 'F#vYP"̖!. i¬1덆]0`I0$ e!s& iqYqŮs3B|gAN8rASSs|Z7ZMkZ!hyk [GImmoA;斧&hM{੧婥 u<3lmO/,;C7 j`$˖?Snk5uE- haݷi64@8ЂXׄ9=//so6*R4*Y@5ACHЀpgj9/tiFhn}`y9Vfڜ\u,3cUh ~Si׌$3h>H(Z o Xx ڥQ"]v"fsH%?⡵g !5s 6s0pBeݴHf v 9oE5D8! ߕîg c6bjZm;PZ@9!-`,z"qٻW@(! Z|3g![9<#=]V8}q4h* g* Aڛ{Z[CZ f<ZuP-x <5Ejڜp,G0[e0[dd{sP}ڜ C^57@=8O fs<noFjin iwӴ9`?;h?9d81Cw8gf lԮnyjs>vv9дiyVe8k1Cwšiq^!-OmNڇ`6~w-OB:=B2kyV{sJp"I/_*;0ky#@}q,O!PZmH|j x{SKxH;ZڜX@}A@;4 ivӰ@@$߃"Kؚ־f6zb+EL}@SxgYlglԇc@}qkk X|@}pʚZA3} g,P=,[{fZe8sP3AeM@6@iiVҴ<)z PZp怪iq-=Wun\1#IENDB`muffin-5.2.1/doc/reference/cogl/cogl-docs.xml.in0000664000175000017500000001662614211404421021577 0ustar jpeisachjpeisach ]> Cogl 2.0 Reference Manual for Muffin Cogl 2008 OpenedHand LTD 2009 2010 2011 2012 2013 Intel Corporation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to:
The Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Cogl - a modern 3D graphics API
About Cogl Cogl is a modern 3D graphics API with associated utility APIs designed to expose the features of 3D graphics hardware using a more object oriented design than OpenGL. The library has primarily been driven by the practical needs of Clutter but it is not tied to any one toolkit or even constrained to developing UI toolkits.
General API concepts
Setting Up A Drawing Context
Setting Up A GPU Pipeline
Allocating GPU Memory
Describing the layout of GPU Memory
Geometry
Textures
Meta Textures
Primitive Textures
Framebuffers
Utilities
Binding and Integrating
Glossaries Index of all symbols Index of deprecated symbols Index of new symbols in 0.8 Index of new symbols in 1.0 Index of new symbols in 1.2 Index of new symbols in 1.4 License This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 Library General Public License for more details. You may obtain a copy of the GNU Library General Public License from the Free Software Foundation by visiting their Web site or by writing to:
Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307 USA
muffin-5.2.1/doc/reference/cogl/fill-rule-non-zero.png0000664000175000017500000000610714211404421022735 0ustar jpeisachjpeisachPNG  IHDRgBsRGBbKGD pHYs  tIME #DtEXtCommentCreated with GIMPW IDATxњ(P2{8ιٞI,M O?s6JUff _gp iSiJO{3x4 @83lZkmpp 6@8@8ΨCKs1M3*\\k33 lL?o5; `ԋ(C8<P ׵6C8Pԇpƽ7- <  x5blO`]cӔͿc>PC[ڄji0#$ C8@8~TyM,@>,@>3.9&X[3&ggg~&ggGni/ pZkmpp -mhmpp -hmpp "XKs}[Z  ggYNSsg /4 hq:™Z"~EoQ(6A0M8CQ`"3Ef`-=*E h=ҿk^ ~vF꬞0HYp,N"ez;$uUO_ۮi^wPښ9O)ɉ`ls' K]@`6c9к5̜|@0k14'01@0k?=hWlHY_%9̌24z g/I@P&!`8{vziX(L]42eq\ 5L(5=[6goﵵ) д99_ =nmNJI ^6g${lξhڜ\3z(ڜ̈́#У+7KKݘMeQ~AT(wswUBڲ[Ҏ`@aIShםNZu Y6g* e d9_[~ڮ^ZP4.^om6&YVr5mY7K(̾LS>5%9C}8̇p#ݹ[(bm '_9zrP|Ζɻi](잕==:=,Xc[@գݲ''Oa>Ɲ e=. fuOxQNtjˆ0޸6zaB1ˆ0#$R3^oPc{Ė9j(b /K 0|`{qpƄCYϱLAo>~ͶvdѰ[1?@|Pt>>G.Z e/J@{{q*( hU$}|<nyn f۰U|j|cnisji=;OSNP=YT(>G..kkS([͆%A36 ű "2_p*ҜqD@ױq/n ;(Aes[#9mw㡵 s7uf ffz 2>[sR0ۄ4C-w1wh!Mk,. e6'B[` iڜ d'6΀!im9ښ7"lRVikʪMHdbk\)96@8jp6T( 6MHᬬ-Pm.& e4h[i fMM@K-7 v .&ݽ CYwlд9>m͝P h)is@m*fv&neM@5!C& svQz에v.&!.!5tPr 9:.e ᬩ`ǐp@8p$oijchgWk zgg36W. Pg3i 44׃L06=۔{bJ9i ǂ1B\m-%DkiBPQt'6O/z0vi2Puusf=,YƌЄ4,<>80e&.vs8Ci?AڜXx@}0D8l/ i< 蚾ϙPn'CںAjsL(& gp0qxߧIENDB`muffin-5.2.1/doc/reference/cogl/Makefile.am0000664000175000017500000000776314211404421020634 0ustar jpeisachjpeisach## Process this file with automake to produce Makefile.in # We require automake 1.6 at least. AUTOMAKE_OPTIONS = 1.6 # This is a blank Makefile.am for using gtk-doc. # Copy this to your project's API docs directory and modify the variables to # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples # of using the various options. # The name of the module, e.g. 'glib'. DOC_MODULE=cogl # The top-level SGML file. You can change this if you want to. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml # The directory containing the source code. Relative to $(srcdir). # gtk-doc will search all .c & .h files beneath here for inline comments # documenting the functions and macros. # e.g. DOC_SOURCE_DIR=../../../gtk DOC_SOURCE_DIR=../../../cogl # Extra options to pass to gtkdoc-scangobj. Not normally needed. SCANGOBJ_OPTIONS=--type-init-func="g_type_init()" # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS=--deprecated-guards="COGL_DISABLE_DEPRECATED" # Extra options to supply to gtkdoc-mkdb. # e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space=muffin-cogl # Extra options to supply to gtkdoc-mktmpl # e.g. MKTMPL_OPTIONS=--only-section-tmpl MKTMPL_OPTIONS= # Extra options to supply to gtkdoc-fixref. Not normally needed. # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html FIXXREF_OPTIONS=\ --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ --extra-dir=$(GDKPIXBUF_PREFIX)/share/gtk-doc/html/gdk-pixbuf # Used for dependencies. The docs will be rebuilt if any of these change. # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c HFILE_GLOB=\ $(top_srcdir)/cogl/cogl/*.h \ $(top_builddir)/cogl/cogl/*.h \ $(top_srcdir)/cogl/cogl/winsys/*.h CFILE_GLOB=$(top_srcdir)/cogl/cogl/*.c # Header files to ignore when scanning. # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h cogl_private_headers := \ $(shell cd $(top_srcdir)/cogl && echo *-private.h && cd - && \ cd $(top_srcdir)/cogl/cogl/winsys && echo *-private.h && cd -) IGNORE_HFILES=\ driver \ tesselator \ cogl.h \ $(cogl_private_headers) \ cogl-atlas.h \ cogl-bitmap-packing.h \ cogl-bitmask.h \ cogl-blend-string.h \ cogl-blit.h \ cogl-boxed-value.h \ cogl-clip-stack.h \ cogl-debug.h \ cogl-debug-options.h \ cogl-defines.h \ cogl-driver.h \ cogl-enum-types.h \ cogl-flags.h \ cogl-gles2-types.h \ cogl-gl-header.h \ cogl-glsl-shader-boilerplate.h \ cogl-profile.h \ cogl-rectangle-map.h \ cogl-spans.h \ cogl-texture-driver.h \ cogl-util.h \ $(NULL) EXTRA_HFILES= # Images to copy into HTML directory. # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png HTML_IMAGES = \ fill-rule-non-zero.png \ fill-rule-even-odd.png \ quad-indices-order.png \ quad-indices-triangles.png \ cogl_ortho.png # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.sgml building.sgml changes-2.0.sgml content_files = \ blend-strings.xml # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded # These files must be listed here *and* in content_files # e.g. expand_content_files=running.sgml expand_content_files = \ blend-strings.xml # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget # signals and properties. # e.g. AM_CPPFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) AM_CPPFLAGS = -I$(top_srcdir) \ -I$(top_builddir)/cogl \ -DCOGL_ENABLE_EXPERIMENTAL_API \ -DCOGL_ENABLE_EXPERIMENTAL_2_0_API \ -DCOGL_ENABLE_MUFFIN_API \ $(COGL_DEP_CFLAGS) GTKDOC_LIBS = $(top_builddir)/clutter/clutter/libmuffin-cogl-0.la $(COGL_DEP_LIBS) include $(top_srcdir)/gtk-doc.make EXTRA_DIST = # Other files to distribute # e.g. EXTRA_DIST += version.xml.in EXTRA_DIST += $(HTML_IMAGES) $(content_files) muffin-5.2.1/doc/reference/cogl/quad-indices-triangles.png0000664000175000017500000001752214211404421023634 0ustar jpeisachjpeisachPNG  IHDRGd=sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxwU?MЋ(D ХWҥ "? BDz)P#$*E (]@xgs-{fyt_afÁ̀ŀ7WIzDkA0͘@``E`I`VeQ`US,f6p,&000-pASbfFwە>L*z,..;G38{vNoM ?V'4009 i6FmYӗ lV10^_{O^`}3T$(ki/okJZ8PaL%f80:w%&iv`WL_80t `OI_h2DI'ͯV~|XIҳ5?YKz) Zj`GU5-f/]^G?,59k%rTnZ~bf3+T0Hk@`#63'ѝ=p^ǯNll0An$u A&MrW<^i`9IEnmY-Kz },z fVrB{qp_ff=14$!\uwuD҇jlⲹʹ._$E`r=0NFcv N.;7MA44jܾ~A$}nf[ 431g sC'/[Ux8dڭ%/zxL~K`5GHzƴ}A>my?t>hf}3G8 /3uW'wWGv4O{ӾO{e3k =}< i ̐~ӽtg23̟̖mi^o1WHz 3״ e8Nכ1_%n3Wn;A@]#84k=|~i^mtK~'m/2Aj̆>|g2`Asn3@| (3[<^xBҽ=8t <K(45relIowo~Iқ}m0݁ew=)mOl5 ֍941Y{o]Kn>1aLn{鞀|'4-KF1dYF޹oЀ\-Tkl=ėF!8.lG3k~C1A#refUջ~K RHylf)SF ,!sҺfv׌ܛ 5} $2 _s܅G6ϽFQf$Eༀ/ɺ^4+֪,Bk4('%4ȭ>hfKsv |Dp }%]T_!(3[_a.v ص6A0dy?j,[%rlaiE[^^zlEئKKI+4Y‡}*~|Zf)>q:9(I[]nпίIAPo^omuA~gЎInbfk*G"izX[t$[IP%,wfv^vY?(@qꞣ 9Kz$A?VWu~eRSA+08?fl穥|ΒbE lAKzD6)%]8՗=`6fLE lMu/q8}7 VQ麆?{MSu0pk@=$`C8!NZIyӸѨeuc8XIC _\?= 1 3|BAqM; IN@ip]ofAP*}I_H:Oy Wz {58.¶3[& >)$V ΏCk!3I3jWeAP:}Z$XCk: YW SIk|X1]Sx I+אw?&59 Mf.7dS@$I?צT߇& H\yE{ uAٚA@ǒvW2 / ̶N,( ICXC>P RcI9΍C I>/+cd7L,hEJ-Ç|0'3FZWAH:YOA_SzqÀ/ *xx; B8|VXlN4Dq lbMyfn3ͬ<}w)P! Wh$=W)HI24.Yρ̋'>4zp [4~C3"V ZI'ͱiOA]i i fvDZIyӷ % [+H1/iA^1lYPTCħKMq "a͋ipef; ˈ8H| :GIèX3zZWAH:Xx U"#2@,ޓp8=; B#-; R%#rLdDmq L| fvbdDYFFN|zLn,h8Z(Hz1]ڀ;lƂR2"O3",ȕħ##i -<${ =Փ JCҽrivk$>.-SaJFxy>>3IzgAYdkS ٲTq i ~PAaf,e%> lNuFP-[aJ0`+>p΂pa y;`BdD-]+H=>h4=k3fJ,(,#r<]; R1C Kj;hKu@' ҌfvI$>_8􉤽] Rxe!<DFd%c $]!)H3W3> ]Ȗ!c'Hz/f2t TɈ<'2"Q@҇v:#rc<,$=?c"#űH/RAΈA"#űHGאO=ZZWAH:HjAdDOKIg:#ruq3[74$=OE p p͕Xk8N%YxX xqch$gDOlƂ^_iDxគΑXP YItyDdD6Q{7/T]ߘ_54$݃4,H_"#9Kqe;fvhzgAYH4T473"WLn,*8 Iw= tYfv I,(,` ག<Xc8IC;έ!o_.L$J6a .%cCm fWzgAYH'9htZWAwDq#$݄O3{ \lfWٌe SIwŌ%HȈl 8!ǧ]ZCB,UP&FOOȈl081YFnTgD._RmXP 5=[/ uIW+(H_5 lPzgAHH>TgD.?*BDŽH;"p} y?|xДrt143YPYFaT'>}AzgK(>X{lƂҐt6>i<#H|JC'LpeA^1XPOc Rp,0&2"( @yZAL=&ZIo'P~Ҍ>$c!i,c hɍ%>lUv9-[w֜Dqlr$ :|-UP&.ּX7Y=Q'i[ 3"WoYP&FՐȮ؏t>>&_i6`$mNuFT;k83$/V EIn,( IgSkeDnf'FFd5_`h3"=m%"IO2"O^/=ȣ"u2"7N:#r]zrc J~؂48͖WPYF xn(-:#r#ǰRrcAiH4*HlTgDFqlȟ-!L,(,#5ψbH#9 3eeDl _+wV>Q[I/!UCLZWAH?i>VF5f6SzgűEP[rcAi2"/!gD.UyDqlq$4.A'v:#rI<#r1@ҳx5݁GlѤRt5>/4p]dfӧw(0%#TgD~ MzgAYHz YC_c1耤K܈j9̶HT! <H*(I#Հ!L3Y1$m Ϫ0,$sk 0`͗U1I^)H4S"#up<#2c-/Q ENn,(, `-?yN<#fψljA:$TKuZxaƂҐ ~Ҽ s&7V'8=&1Q5###u&>pgDXL5{ *HӀ[lƂR2"ǯ,.y$1&$ Mo+&7;i pLQi&ˈ)9nA]XP^3"ϩ!ŏu5mDq z ip]kf_I,(IK:ؚȅlΦ(A]>vo&5V_Ս1YFyq<#r΂>W4pFdǠHOsy \af eeD |\+;w5Q>A3x5=񸫅Ӻ DUg♂4p2"8}%g}Rß\nYPį*!?i(A# ip%m|V'3"8I8!xӺ D҅ ,4@Fd ޗ5p(nYP&5𩇥dDFq #|ūi63;㮂#]|̑TgD4K+>A)Hz{gAjƘ\ɍ%> afǧ3;<,SN|ZDQ@ei pjwd'c+w |>#c0H5Һ DI4y_wǠ#}; B+ |_`6 {lY?KA0_F{K(Llk5O%-Ф1lР0Ee '}s A*@IGu5=G3p{㒖/DP.f}yIiRf6aAO]굧A߉?Iz6A0uY`lȚ8 /I:]-*3g>k3xLޒF%t(E{a !FvrrC/`)`7`!283{]҈NFI{a [쬈_!_if9RMT9)7`֬R@I f5Mekj3۝KH*W+PI?.84.^M*̞LL\h%mYa\ Sg]|%k? Fbxn\Ivc\Ӱ24m?ڃms_/}ǥz0Ewo䶿Y_GA#}NMaILģޤ>nH?уm'ƂBd`Trn{|8Η^; >$~9mN{ڋ亮} 5,/ACsZA%3   k:N;Q~ VʚyyFǮp Ry~H`\-RЀ!Ź1NSx4*٥H`\I)R`d'srFq f6'R~H)8Tysq2AǠ_`f gM$]PN+V8I(Acfٳ$ҭ0eہE!/45f%c644 ֛,iƺ !g68Mzz~ cogl-object The Object Interface CoglObject cogl_object_ref cogl_object_unref CoglUserDataKey CoglUserDataDestroyCallback cogl_object_get_user_data cogl_object_set_user_data
cogl-error Exception handling CoglError cogl_error_matches cogl_error_free cogl_error_copy COGL_GLIB_ERROR
cogl-types Common Types CoglVertexP2 CoglVertexP3 CoglVertexP2C4 CoglVertexP3C4 CoglVertexP2T2 CoglVertexP3T2 CoglVertexP2T2C4 CoglVertexP3T2C4 CoglVerticesMode CoglFuncPtr CoglPixelFormat CoglBufferTarget CoglBufferBit CoglAttributeType CoglColorMask CoglTextureFlags CoglBool
cogl-renderer CoglRenderer: Connect to a backend renderer CoglRenderer cogl_is_renderer cogl_renderer_new cogl_renderer_get_n_fragment_texture_units cogl_renderer_connect CoglWinsysID cogl_renderer_set_winsys_id cogl_renderer_get_winsys_id CoglRendererConstraint cogl_renderer_add_constraint cogl_renderer_remove_constraint cogl_xlib_renderer_set_foreign_display cogl_xlib_renderer_get_foreign_display CoglXlibFilterFunc CoglFilterReturn cogl_xlib_renderer_add_filter cogl_xlib_renderer_remove_filter cogl_xlib_renderer_handle_event
cogl-onscreen-template CoglOnscreenTemplate: Describe a template for onscreen framebuffers CoglOnscreenTemplate cogl_is_onscreen_template cogl_onscreen_template_new cogl_onscreen_template_set_swap_throttled cogl_onscreen_template_set_samples_per_pixel
cogl-display CoglDisplay: Setup a display pipeline CoglDisplay cogl_is_display cogl_display_new cogl_display_get_renderer cogl_display_setup cogl_wayland_display_set_compositor_display
cogl-context The Top-Level Context CoglContext cogl_is_context cogl_context_new cogl_context_get_display CoglFeatureID cogl_has_feature cogl_has_features CoglFeatureCallback cogl_foreach_feature CoglReadPixelsFlags COGL_TYPE_ATTRIBUTE_TYPE COGL_TYPE_BLEND_STRING_ERROR COGL_TYPE_BUFFER_ACCESS COGL_TYPE_BUFFER_TARGET COGL_TYPE_BUFFER_UPDATE_HINT COGL_TYPE_BUFFER_USAGE_HINT COGL_TYPE_DEBUG_FLAGS COGL_TYPE_DRIVER_ERROR COGL_TYPE_INDICES_TYPE COGL_TYPE_PIXEL_FORMAT COGL_TYPE_READ_PIXELS_FLAGS COGL_TYPE_TEXTURE_FLAGS COGL_TYPE_VERTICES_MODE COGL_DRIVER_ERROR CoglDriverError cogl_attribute_type_get_type cogl_buffer_bit_get_type cogl_buffer_target_get_type cogl_debug_flags_get_type cogl_driver_error_get_type cogl_indices_type_get_type cogl_pixel_format_get_type cogl_read_pixels_flags_get_type cogl_shader_type_get_type cogl_texture_flags_get_type cogl_vertices_mode_get_type COGL_AFIRST_BIT COGL_A_BIT COGL_BGR_BIT COGL_PREMULT_BIT
cogl-poll Main loop integration CoglPollFDEvent CoglPollFD cogl_poll_renderer_get_info cogl_poll_renderer_dispatch cogl_glib_source_new cogl_glib_renderer_source_new
cogl-attribute Vertex Attributes CoglAttribute cogl_attribute_new cogl_is_attribute cogl_attribute_set_normalized cogl_attribute_get_normalized cogl_attribute_get_buffer cogl_attribute_set_buffer
cogl-indices Indices CoglIndices cogl_is_indices CoglIndicesType cogl_indices_new cogl_get_rectangle_indices
cogl-primitive Primitives CoglPrimitive cogl_primitive_new cogl_primitive_new_with_attributes cogl_primitive_new_p2 cogl_primitive_new_p3 cogl_primitive_new_p2c4 cogl_primitive_new_p3c4 cogl_primitive_new_p2t2 cogl_primitive_new_p3t2 cogl_primitive_new_p2t2c4 cogl_primitive_new_p3t2c4 cogl_is_primitive cogl_primitive_get_first_vertex cogl_primitive_set_first_vertex cogl_primitive_get_n_vertices cogl_primitive_set_n_vertices cogl_primitive_get_mode cogl_primitive_set_mode cogl_primitive_set_attributes cogl_primitive_get_indices cogl_primitive_set_indices cogl_primitive_copy CoglPrimitiveAttributeCallback cogl_primitive_foreach_attribute cogl_primitive_draw
cogl-snippet Shader snippets CoglSnippet CoglSnippetHook cogl_snippet_new cogl_snippet_get_hook cogl_is_snippet cogl_snippet_set_declarations cogl_snippet_get_declarations cogl_snippet_set_pre cogl_snippet_get_pre cogl_snippet_set_replace cogl_snippet_get_replace cogl_snippet_set_post cogl_snippet_get_post
cogl-paths Path Primitives CoglPath cogl_is_path cogl_path_new cogl_path_copy cogl_path_move_to cogl_path_close cogl_path_line_to cogl_path_curve_to cogl_path_arc cogl_path_rel_move_to cogl_path_rel_line_to cogl_path_rel_curve_to cogl_path_line cogl_path_polyline cogl_path_polygon cogl_path_rectangle cogl_path_round_rectangle cogl_path_ellipse CoglPathFillRule cogl_path_set_fill_rule cogl_path_get_fill_rule
cogl-bitmap Bitmap CoglBitmap cogl_is_bitmap cogl_bitmap_new_from_file cogl_bitmap_new_from_buffer cogl_bitmap_new_with_size cogl_bitmap_new_for_data cogl_bitmap_get_format cogl_bitmap_get_width cogl_bitmap_get_height cogl_bitmap_get_rowstride cogl_bitmap_get_buffer cogl_bitmap_get_size_from_file cogl_texture_new_from_bitmap COGL_BITMAP_ERROR CoglBitmapError
cogl-texture The Texture Interface CoglTexture cogl_is_texture COGL_TEXTURE_ERROR CoglTextureError cogl_texture_allocate cogl_texture_get_width cogl_texture_get_height cogl_texture_is_sliced cogl_texture_get_data cogl_texture_set_data cogl_texture_set_region CoglTextureType CoglTextureComponents cogl_texture_set_components cogl_texture_get_components cogl_texture_set_premultiplied cogl_texture_get_premultiplied COGL_TEXTURE_MAX_WASTE
cogl-texture-2d 2D textures CoglTexture2D cogl_is_texture_2d cogl_texture_2d_new_with_size cogl_texture_2d_new_from_file cogl_texture_2d_new_from_bitmap cogl_texture_2d_new_from_data cogl_texture_2d_gl_new_from_foreign
cogl-texture-rectangle Rectangle textures (non-normalized coordinates) CoglTextureRectangle cogl_texture_rectangle_new_with_size cogl_texture_rectangle_new_from_bitmap cogl_is_texture_rectangle
cogl-texture-3d 3D textures CoglTexture3D cogl_texture_3d_new_with_size cogl_texture_3d_new_from_bitmap cogl_texture_3d_new_from_data cogl_is_texture_3d
cogl-meta-texture High Level Meta Textures CoglMetaTexture CoglMetaTextureCallback cogl_meta_texture_foreach_in_region
cogl-primitive-texture Low-level primitive textures CoglPrimitiveTexture cogl_is_primitive_texture cogl_primitive_texture_set_auto_mipmap
cogl-sub-texture Sub Textures CoglSubTexture cogl_sub_texture_new cogl_is_sub_texture
cogl-atlas-texture Atlas Textures CoglAtlasTexture cogl_atlas_texture_new_with_size cogl_atlas_texture_new_from_file cogl_atlas_texture_new_from_data cogl_atlas_texture_new_from_bitmap cogl_is_atlas_texture
cogl-texture-2d-sliced Sliced Textures CoglTexture2DSliced cogl_texture_2d_sliced_new_with_size cogl_texture_2d_sliced_new_from_file cogl_texture_2d_sliced_new_from_data cogl_texture_2d_sliced_new_from_bitmap cogl_is_texture_2d_sliced
cogl-texture-pixmap-x11 X11 Texture From Pixmap CoglTexturePixmapX11 cogl_is_texture_pixmap_x11 cogl_texture_pixmap_x11_new cogl_texture_pixmap_x11_update_area cogl_texture_pixmap_x11_is_using_tfp_extension CoglTexturePixmapX11ReportLevel cogl_texture_pixmap_x11_set_damage_object
cogl-framebuffer CoglFramebuffer: The Framebuffer Interface CoglFramebuffer COGL_FRAMEBUFFER cogl_framebuffer_allocate cogl_framebuffer_get_width cogl_framebuffer_get_height cogl_framebuffer_set_viewport cogl_framebuffer_get_viewport_x cogl_framebuffer_get_viewport_y cogl_framebuffer_get_viewport_width cogl_framebuffer_get_viewport_height cogl_framebuffer_get_viewport4fv cogl_framebuffer_get_red_bits cogl_framebuffer_get_green_bits cogl_framebuffer_get_blue_bits cogl_framebuffer_get_alpha_bits cogl_framebuffer_get_depth_bits cogl_framebuffer_get_color_mask cogl_framebuffer_set_color_mask cogl_framebuffer_get_samples_per_pixel cogl_framebuffer_set_samples_per_pixel cogl_framebuffer_resolve_samples cogl_framebuffer_resolve_samples_region cogl_framebuffer_get_context cogl_framebuffer_clear cogl_framebuffer_clear4f cogl_framebuffer_read_pixels_into_bitmap cogl_framebuffer_read_pixels cogl_framebuffer_set_dither_enabled cogl_framebuffer_get_dither_enabled cogl_framebuffer_draw_rectangle cogl_framebuffer_draw_textured_rectangle cogl_framebuffer_draw_multitextured_rectangle cogl_framebuffer_draw_rectangles cogl_framebuffer_draw_textured_rectangles cogl_framebuffer_stroke_path cogl_framebuffer_fill_path cogl_framebuffer_discard_buffers cogl_framebuffer_finish cogl_framebuffer_push_matrix cogl_framebuffer_pop_matrix cogl_framebuffer_identity_matrix cogl_framebuffer_scale cogl_framebuffer_translate cogl_framebuffer_rotate cogl_framebuffer_rotate_euler cogl_framebuffer_rotate_quaternion cogl_framebuffer_transform cogl_framebuffer_get_modelview_matrix cogl_framebuffer_set_modelview_matrix cogl_framebuffer_perspective cogl_framebuffer_frustum cogl_framebuffer_orthographic cogl_framebuffer_get_projection_matrix cogl_framebuffer_set_projection_matrix cogl_framebuffer_push_scissor_clip cogl_framebuffer_push_rectangle_clip cogl_framebuffer_push_path_clip cogl_framebuffer_push_primitive_clip cogl_framebuffer_pop_clip
cogl-onscreen CoglOnscreen: The Onscreen Framebuffer Interface CoglOnscreen cogl_is_onscreen COGL_ONSCREEN cogl_onscreen_new CoglOnscreenX11MaskCallback cogl_x11_onscreen_set_foreign_window_xid cogl_x11_onscreen_get_window_xid cogl_x11_onscreen_get_visual_xid cogl_onscreen_show cogl_onscreen_hide CoglFrameCallback CoglFrameClosure cogl_onscreen_add_frame_callback cogl_onscreen_remove_frame_callback CoglOnscreenDirtyInfo CoglOnscreenDirtyCallback CoglOnscreenDirtyClosure cogl_onscreen_add_dirty_callback cogl_onscreen_remove_dirty_callback CoglOnscreenResizeCallback CoglOnscreenResizeClosure cogl_onscreen_add_resize_callback cogl_onscreen_remove_resize_callback cogl_onscreen_swap_buffers cogl_onscreen_swap_buffers_with_damage cogl_onscreen_swap_region cogl_onscreen_set_swap_throttled
cogl-offscreen Offscreen Framebuffers CoglOffscreen cogl_is_offscreen cogl_offscreen_new_with_texture
cogl-color Color Type CoglColor cogl_color_copy cogl_color_free cogl_color_init_from_4ub cogl_color_init_from_4f cogl_color_init_from_4fv cogl_color_get_red cogl_color_get_green cogl_color_get_blue cogl_color_get_alpha cogl_color_get_red_byte cogl_color_get_green_byte cogl_color_get_blue_byte cogl_color_get_alpha_byte cogl_color_get_red_float cogl_color_get_green_float cogl_color_get_blue_float cogl_color_get_alpha_float cogl_color_set_red cogl_color_set_green cogl_color_set_blue cogl_color_set_alpha cogl_color_set_red_byte cogl_color_set_green_byte cogl_color_set_blue_byte cogl_color_set_alpha_byte cogl_color_set_red_float cogl_color_set_green_float cogl_color_set_blue_float cogl_color_set_alpha_float cogl_color_premultiply cogl_color_unpremultiply cogl_color_equal cogl_color_init_from_hsl cogl_color_to_hsl
cogl-matrix Matrices CoglMatrix cogl_matrix_init_identity cogl_matrix_init_from_array cogl_matrix_init_translation cogl_matrix_init_from_quaternion cogl_matrix_init_from_euler cogl_matrix_copy cogl_matrix_equal cogl_matrix_free cogl_matrix_frustum cogl_matrix_orthographic cogl_matrix_perspective cogl_matrix_look_at cogl_matrix_multiply cogl_matrix_rotate cogl_matrix_rotate_quaternion cogl_matrix_rotate_euler cogl_matrix_translate cogl_matrix_scale cogl_matrix_transpose cogl_matrix_get_array cogl_matrix_get_inverse cogl_matrix_transform_point cogl_matrix_transform_points cogl_matrix_project_points cogl_matrix_is_identity
cogl-matrix-stack Matrix Stacks CoglMatrixStack CoglMatrixEntry cogl_matrix_stack_new cogl_matrix_stack_push cogl_matrix_stack_pop cogl_matrix_stack_load_identity cogl_matrix_stack_scale cogl_matrix_stack_translate cogl_matrix_stack_rotate cogl_matrix_stack_rotate_quaternion cogl_matrix_stack_rotate_euler cogl_matrix_stack_multiply cogl_matrix_stack_frustum cogl_matrix_stack_perspective cogl_matrix_stack_orthographic cogl_matrix_stack_get_inverse cogl_matrix_stack_get_entry cogl_matrix_stack_get cogl_matrix_entry_get cogl_matrix_stack_set cogl_matrix_entry_calculate_translation cogl_matrix_entry_is_identity cogl_matrix_entry_equal cogl_matrix_entry_ref cogl_matrix_entry_unref
cogl-euler Eulers (Rotations) CoglEuler cogl_euler_init cogl_euler_init_from_matrix cogl_euler_init_from_quaternion cogl_euler_equal cogl_euler_copy cogl_euler_free
cogl-quaternion Quaternions (Rotations) CoglQuaternion cogl_quaternion_init_identity cogl_quaternion_init cogl_quaternion_init_from_angle_vector cogl_quaternion_init_from_array cogl_quaternion_init_from_x_rotation cogl_quaternion_init_from_y_rotation cogl_quaternion_init_from_z_rotation cogl_quaternion_init_from_euler cogl_quaternion_equal cogl_quaternion_copy cogl_quaternion_free cogl_quaternion_get_rotation_angle cogl_quaternion_get_rotation_axis cogl_quaternion_normalize cogl_quaternion_dot_product cogl_quaternion_invert cogl_quaternion_multiply cogl_quaternion_pow cogl_quaternion_slerp cogl_quaternion_nlerp cogl_quaternion_squad cogl_get_static_identity_quaternion cogl_get_static_zero_quaternion
cogl-pipeline Pipeline CoglPipeline cogl_pipeline_new cogl_pipeline_copy cogl_is_pipeline cogl_pipeline_set_color cogl_pipeline_set_color4ub cogl_pipeline_set_color4f cogl_pipeline_get_color CoglPipelineAlphaFunc cogl_pipeline_set_alpha_test_function COGL_BLEND_STRING_ERROR CoglBlendStringError cogl_pipeline_set_blend cogl_pipeline_set_blend_constant cogl_pipeline_set_point_size cogl_pipeline_get_point_size cogl_pipeline_set_per_vertex_point_size cogl_pipeline_get_per_vertex_point_size cogl_pipeline_get_color_mask cogl_pipeline_set_color_mask cogl_pipeline_set_depth_state cogl_pipeline_get_depth_state CoglPipelineCullFaceMode cogl_pipeline_set_cull_face_mode CoglWinding cogl_pipeline_set_front_face_winding cogl_pipeline_set_layer_texture cogl_pipeline_set_layer_null_texture cogl_pipeline_get_layer_texture CoglPipelineFilter cogl_pipeline_set_layer_filters cogl_pipeline_get_layer_min_filter cogl_pipeline_get_layer_mag_filter CoglPipelineWrapMode cogl_pipeline_set_layer_wrap_mode cogl_pipeline_set_layer_wrap_mode_s cogl_pipeline_set_layer_wrap_mode_t cogl_pipeline_set_layer_wrap_mode_p cogl_pipeline_set_layer_combine cogl_pipeline_set_layer_combine_constant cogl_pipeline_set_layer_point_sprite_coords_enabled cogl_pipeline_get_layer_point_sprite_coords_enabled cogl_pipeline_remove_layer cogl_pipeline_get_n_layers CoglPipelineLayerCallback cogl_pipeline_foreach_layer cogl_pipeline_get_uniform_location cogl_pipeline_set_uniform_1f cogl_pipeline_set_uniform_1i cogl_pipeline_set_uniform_float cogl_pipeline_set_uniform_int cogl_pipeline_set_uniform_matrix cogl_pipeline_add_snippet cogl_pipeline_add_layer_snippet cogl_blend_string_error_get_type cogl_blend_string_error_domain
cogl-depth-state Depth State CoglDepthState CoglDepthTestFunction cogl_depth_state_init cogl_depth_state_set_test_enabled cogl_depth_state_get_test_enabled cogl_depth_state_set_test_function cogl_depth_state_get_test_function cogl_depth_state_set_write_enabled cogl_depth_state_get_write_enabled cogl_depth_state_set_range cogl_depth_state_get_range
cogl-buffer CoglBuffer: The Buffer Interface CoglBuffer cogl_is_buffer cogl_buffer_get_size CoglBufferUsageHint CoglBufferUpdateHint cogl_buffer_set_update_hint cogl_buffer_get_update_hint CoglBufferAccess CoglBufferMapHint cogl_buffer_map cogl_buffer_map_range cogl_buffer_unmap cogl_buffer_set_data CoglPixelBuffer cogl_pixel_buffer_new cogl_is_pixel_buffer cogl_buffer_access_get_type cogl_buffer_update_hint_get_type cogl_buffer_usage_hint_get_type
cogl-attribute-buffer CoglAttributeBuffer: Buffers of vertex attributes CoglAttributeBuffer cogl_attribute_buffer_new_with_size cogl_attribute_buffer_new cogl_is_attribute_buffer
cogl-index-buffer CoglIndexBuffer: Buffers of vertex indices CoglIndexBuffer cogl_index_buffer_new cogl_is_index_buffer
cogl-vector 3 Component Vectors cogl_vector3_init cogl_vector3_init_zero cogl_vector3_equal cogl_vector3_equal_with_epsilon cogl_vector3_copy cogl_vector3_free cogl_vector3_invert cogl_vector3_add cogl_vector3_subtract cogl_vector3_multiply_scalar cogl_vector3_divide_scalar cogl_vector3_normalize cogl_vector3_magnitude cogl_vector3_cross_product cogl_vector3_dot_product cogl_vector3_distance
cogl-fence GPU synchronisation fences CoglFence CoglFenceCallback CoglFenceClosure cogl_fence_closure_get_user_data cogl_framebuffer_add_fence_callback cogl_framebuffer_cancel_fence_callback
cogl-version Versioning utility macros COGL_VERSION_MAJOR COGL_VERSION_MINOR COGL_VERSION_MICRO COGL_VERSION_STRING COGL_VERSION COGL_VERSION_ENCODE COGL_VERSION_CHECK COGL_VERSION_GET_MAJOR COGL_VERSION_GET_MINOR COGL_VERSION_GET_MICRO
cogl-gtype GType Integration API cogl_gtype_matrix_get_type
cogl-gles2 GLES 2.0 context CoglGLES2Context CoglGLES2Vtable COGL_GLES2_CONTEXT_ERROR CoglGLES2ContextError cogl_gles2_context_new cogl_is_gles2_context cogl_gles2_context_get_vtable cogl_push_gles2_context cogl_pop_gles2_context cogl_gles2_get_current_vtable cogl_gles2_texture_2d_new_from_handle cogl_gles2_texture_get_handle
muffin-5.2.1/doc/reference/cogl/blend-strings.xml0000664000175000017500000000737714211404421022076 0ustar jpeisachjpeisach ]> Blend Strings 3 COGL Library Blend Strings A simple syntax and grammar for describing blending and texture combining functions. Cogl Blend Strings Describing GPU blending and texture combining states is rather awkward to do in a consise but also readable fashion. Cogl helps by supporting string based descriptions using a simple syntax.
Some examples Here is an example used for blending: "RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]), DST_COLOR * (1-SRC_COLOR[A]))" In OpenGL terms this replaces glBlendFunc[Separate] and glBlendEquation[Separate] Actually in this case it's more verbose than the GL equivalent: glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); But unless you are familiar with OpenGL or refer to its API documentation you wouldn't know that the default function used by OpenGL is GL_FUNC_ADD nor would you know that the above arguments determine what the source color and destination color will be multiplied by before being adding. Here is an example used for texture combining: "RGB = REPLACE (PREVIOUS)" "A = MODULATE (PREVIOUS, TEXTURE)" In OpenGL terms this replaces glTexEnv, and the above example is equivalent to this OpenGL code: glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_COLOR); glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_COLOR);
Here's the syntax <statement>: <channel-mask>=<function-name>(<arg-list>) You can either use a single statement with an RGBA channel-mask or you can use two statements; one with an A channel-mask and the other with an RGB channel-mask. <channel-mask>: A or RGB or RGBA <function-name>: [A-Za-z_]* <arg-list>: <arg>,<arg> or <arg> or "" I.e. functions may take 0 or more arguments <arg>: <color-source> 1 - <color-source> : Only intended for texture combining <color-source> * ( <factor> ) : Only intended for blending 0 : Only intended for blending See the blending or texture combining sections for further notes and examples. <color-source>: <source-name>[<channel-mask>] <source-name> See the blending or texture combining sections for the list of source-names valid in each context. If a channel mask is not given then the channel mask of the statement is assumed instead. <factor>: 0 1 <color-source> 1-<color-source> SRC_ALPHA_SATURATE
muffin-5.2.1/doc/reference/cogl/cogl_ortho.png0000664000175000017500000003055214211404421021435 0ustar jpeisachjpeisachPNG  IHDRW9esRGB pHYsaa?itIME:.p IDATx{\׶7!@y]9x ?UHTQ|h{zEV[ZTP@AjAA*/AH @Brs'@1 y|f&ً5;{kI$C * JZ@[[$P*CCCO>Jexxɓ'p@<{LMUDCT:::T?ngg7 V_x&RDj/^ǘ8Ù9s&!P6bXMU@ H$C*0<< 4G[=i466޾}J:88@t##>SSSk 8!N:t萟_II T@Gr#Pe[7o,++#{Q}c++n]xiLL9B>c===P?]_ Sx ݙ3gZ[[[YYAt333vm^\*&GUUՇ~H @@'077xj窧`@@-3]mǏAtGz{{N|@rr͛5>JKKz{{_x!=nbb*d2J&,XprKKK٥zFFFxEs\˗NNNt˗חK$p:RbqAAA{{{@@ 8DB"?y.]_fgg]622Pr8p FE.BCCO:%wns$qԩ 6|7|]]]p-vfffvv6ϟ7o^^^i~).x򥱱1yd^rΚ5 ;'33b ozzzGl6ȑ#۷oǦO>|L&GGGOe\W"755Ο?ݵiiiEEE,+00@IrYTNK$;;;'''tc'yyyW\Am޼977w֭oBᤥ}v󳰰J9r;&&/r_5Ba04mϞ=%KU(-^*0-+++wڅ߿$=!==ö-[V\\i&l_|m566b /--$ool6N DeeeAb@000Tȩ666ccc.cccٮt:6s!?SU@UUa__`*K1<}s]v/)((غuXӹbY&jj__!hw6DU`ѢE!!!EEEgϞݴiӁTYfk׮Ig@U@z$Va Xohhhbb2<<=lC:Avro9~+`}||^(>pš P(5x ())a0L&3--M$!.^fB))) ͛wߕ744\r355!tʕv4ɕX йs:::ٳgEeddDDDp8$停\qY==F FQQQLLre˖YXX p8'Ndgg+[kbb2bѣG$M믿˄~tLt\X[[[iᕋC Ν4"| D[lx. Lۛ€Wo͋xX0qPF*0!`p/`m\@{xҔ*NM9.Ԑ۷oPTp6A -:u!?? @t߼y [ @XS(O`S0?36&:wP6X*.)3gδhS[YCb1ԙ?&hk ҶX,YCjKOOWh 2Ѓۓaxx^-Ǐǂ8ZDR/TO/_>o} j321wxxR5$L^SكjE]]k^mݺu`T);P6N$K5blcc*0c 5DS*M$ؚ9isPww7BQ7JӮӎTU\]]륊NѠ:Um)YC]\\V\ j#)'M}q <<D"޽!ݝ944DRx<'|jժouaIII;v<)H )JHHݻϟ?e_'Z֚5kT.]tR''w*(WٳgJ200Pq@T 6JzD z˗/=<r่Iu&L 5J$Ν;wԏ*WּZ`en=Ҥ8@9.ޜ "NC[SD"D\hjH$›B@U@__=D"ͥ؂nh LGm@CYYY+))ѩNQQo޼YVV-Ԉ-^a<}4&&KRg잞Q/:i)3gδRJ gZ@UUՇ~%  >_ZZ:֧raB=== #''G#AX^*@"@bBǏDz?BPQ-Tz1`˗/7oZD"b^VH$%nP5Pd2J&0}}5k֘TVVJ%bqAAA{{{@@DL˗/oׯ///H$`Bioo?ydFFGxpSիP(㏗/_yKBLK.EFF"oݺ5&DѣGy<%裏"""Z&ĦMG0V6 3ѣO<9s V@ PD"QJJ'|zyy!233j6G'9߯蠊\.svvf0P?KJJ޽{^Sqwmmm!XfffO>\jkkY,VBBx{#000Pq.bdd4 9sLkkF qF]hhHf ~6K"aw9^_>Y5ŋ#ݲtMSC *n J3 v#5. >GmdddAA㨸eʕP9?lhմ8566FEEyxx&?L&O> JȠh~+U:> L]]]bXh$ɭ[oܸ WF^f0f̘1c xk]]]BrqfWG F> `mq\ _z5O8QQQUSS9q~9"8gΜԜ2c@0W]]]iSSSwwws鶶f9BS7crTVVUACCá!^P( `0h4ڞ={ϟjժk׮m߾?xNH$vvvNNN-ÇzÆ 999w^h#Gcbb?xb."gm]]͘Sn*`ll *(al0򪬬ܵk컃lnnB͜93--at:=00!斕o߾6ڎe T@@R@uvv~occ#ۛPQ`llmb*CCþ>8FFF0fhhHjZHMMe0\.ŋ ΜhQ9$I__A5mRHh(Ǿ}jkk\5kϿvt;77^S pG(bMXdǏ[YYݾ}!$H8 ͧv믿.\XSSS__ƏmfL- #'))b{{{;;;]vÆ oDf0L&3--mrUܹS^^k׮TNٳgEeddDDD,^x %%%S4cr\T@!i)ZH$prr"]]]^!=zD"ܦl۶ѣSO @$g͚mϜ9S%`ĪAq[{F=D D,W>PY&6 T?,,,@@UN KW_ XMnDW^Up^5[Bahh( @ݝ@QE(&&&:88uBooq) ϶*Xf bh[D⹉}}}j#P @fnvEq̒q*V XYY|2st-|>_*^V s9GWݢ*T2t-S_S*0jfn,><z|\k @fn.s8#1CfnE,K*G[2wyGWX~テpKiiiZZZ[[Hs玟>o|S$&&n۶MvuupJYphffׇK,?: q2pkf vvv[@h/^SS x`,BBn(i$PElmmγB"h7. @ TP@TP@TP@TP@TP@TP@Ԟ 6X,x}XD"_nݪh &yر7!?ŒQ?Uݱx?*>ヒ ;|͛7'W" ͛75֧'OT֑]\\.]: ]]]B/V\" (}}Q_|B;::9B"m:DP6V;33ɓ'ׯ?|pppphhhIIIZZZll,933b ozzzl#Go߾bŊÇh6a޽H$VWWXJ]T::.H윜:::Z[[޽{#~Ǽ+W 6oޜuַz Sgddڵ/,,b%$$LѶ#Gx{{<|\.믿P( `h={ ,YW*u+++wڥ\|yRR{a˖-+..޴i9v/6z뭑Rn{{{YYYss3koo#6M+++BnnnYYYqqq@нJBH6/rv### F-bpp?}\IDATx^lW,T*CCþ>l7** #@mtNJKK 6h4o;wܵkWKK_򗂂[JG=N&;Fkk-[|}}9^Ӌۨ ,~zyy%!hѢgnڴ)w֬Y|>ڵk#bjm!lD"?~|J^"MXohhhbb2<<,}8KECCC{7'd va_=**/\>((;M(<@r` ʈ>: (Yhs (t[.iD(![[[i1< H Ν;3  ( 0+@ixaX/_&H;woP#T:55m*Ap1T :G˗/D9 *3S 6*`O':W<ܭ\cKOO-))4331 /cJ/((xwdfeeYYYYZZFFFfdd̘1hdr/㱶ŋ?xɓ'|o}ƍ_W^<$M?_nt7))iǎ}||:;; )JHHݻϟ?OR~Q/^__?Vqk֬RtҥK޽;V#wޥhL&ԩSqqq.\ h ޿}򥛛޽{%ڵk׮]+% vuu裏z{{d$ݭS;wb<344TA T@Bٳ f͚ySXZZ:00`gg횚R(;w lmmd666~~~L&;M.kiivbl)؆E@@ݻw;9kD4T9H544P(Q_>00zΊUV)?x!i?L5_Çkmmݲe83YYYY ӓNH$7@UUUI'9˗/=<<^bgg˝*0{l;;wyGEȆz)ʏ?B!?)} B6~ݻsNʚ7~keIoC^phhHK\\"饦Xfɒ%?Prrrhh%KBt:G ߆H$Glry*ra2O?~,eƍc]J)+TbOHO?+V-% DDDX)^g Bsrr;J3gc@]b B`*1I*аtұ> >uwP___a*`nnlٲ>Lioop:x ě,|m xo f>JѦbʬi ,,,T{We: (@G>G娬Dp>:l> hڣD}wD]T> SG"%D}dBQ@9*00@H$...p@G{zPDg3ªO? +*PSSs-[̞={Abb"߿pœN|||kk+T@hhhnO@M4uAuu'***jjjDX,>q~9"e;v 2jH^]]]׽iSSS,ZD"IOO9}t[[ rfqAP( h{?~LL̪U]}?ֶNK$;;;'' lDbmmaÆݻw/Zȑ#111ϟ?_x1믇BBBxTlPq1<|8fe%yQ 'Oܹs' R#DY3g7E `/ "EIII9|0LuUOKKƍǺJ[ ,,b%$$(2ө`U`<8;;)>GnVX@6sMTA@T`<3}h]]]aa!ѸB(""beffuBCCҥK488ԩSpK@˖-#h f|7G`oop:x RMMM4md2;q~r+4 Ѳq*Ν0*~/}7ހ; #P=xE]*#P_ ( 1rH)CQT@cbё`* (*AL%脀裀%˱ !>*=+Ul @Q oѱ裀.5sE"QGG@겴TDfX#6fу8 * * CL͸IENDB`muffin-5.2.1/doc/reference/cogl/quad-indices-order.png0000664000175000017500000000507414211404421022756 0ustar jpeisachjpeisachPNG  IHDRY4 l23:ݐ"188;3W" B`q]Y`H;p agOK2Ԓ=DD,nfCKi lݙo0c(%v}fIsh; DqH "a(Ιkf .[L ۯ; 3_:f6/fpQo^`̝ Dlೝ8f`mҌ֞`;3tff8̼3~h l92s%pyg5mZF4'1yV8#i[c]ѽg2sy/ 8~gYyFv Me.4Y>e!Ik3OK I*`HRC T$0$!I I*mq0pKf>6$[ufʑs'<"E~"`]ODlGπeqcD]gܐ"Mw''-"b!p?p ];8+"~j7֤^D|3 p)MX+ǁy4 <?mpMBב_@n`vr|aļu Sۡ}FL3߱zD Egi_9)3_>,i^*8= K'g|Af8|3{t5vy% ɊU{`==v_gyN68+3ok74dfFĖ[-;ˏtC034#d t )31im991Vh@D._<\mHR"b6}`vhpJf.7$1Muf0=/(>=GtNf?!I㈈́뀽:gg ICDkV̋G5$iqp-C=?m!I#Dđ ]so̼cu Iꈈ#h;l!ཙxy[jE{N`"H)pEo 3e}HR<`v)^#H p|gh#5Ȑ$8~szS; vxRZU66mIENDB`muffin-5.2.1/doc/reference/muffin/0000775000175000017500000000000014211404421017123 5ustar jpeisachjpeisachmuffin-5.2.1/doc/reference/muffin/Makefile.am0000664000175000017500000001230114211404421021154 0ustar jpeisachjpeisach## Process this file with automake to produce Makefile.in # We require automake 1.6 at least. AUTOMAKE_OPTIONS = 1.6 # This is a blank Makefile.am for using gtk-doc. # Copy this to your project's API docs directory and modify the variables to # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples # of using the various options. # The name of the module, e.g. 'glib'. DOC_MODULE=muffin # Uncomment for versioned docs and specify the version of the module, e.g. '2'. #DOC_MODULE_VERSION=2 # The top-level SGML file. You can change this if you want to. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml # Directories containing the source code, relative to $(srcdir). # gtk-doc will search all .c and .h files beneath these paths # for inline comments documenting functions and macros. # e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk DOC_SOURCE_DIR=../../../src # Extra options to pass to gtkdoc-scangobj. Not normally needed. SCANGOBJ_OPTIONS= # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS=--rebuild-types --rebuild-sections # Extra options to supply to gtkdoc-mkdb. # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml MKDB_OPTIONS=--xml-mode --output-format=xml # Extra options to supply to gtkdoc-mktmpl # e.g. MKTMPL_OPTIONS=--only-section-tmpl MKTMPL_OPTIONS= # Extra options to supply to gtkdoc-mkhtml MKHTML_OPTIONS= # Extra options to supply to gtkdoc-fixref. Not normally needed. # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html FIXXREF_OPTIONS = \ --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \ --extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo \ --extra-dir=$(PANGO_PREFIX)/share/gtk-doc/html/pango \ --extra-dir=$(GDK_PREFIX)/share/gtk-doc/html/gdk \ --extra-dir=$(ATK_PREFIX)/share/gtk-doc/html/atk \ --extra-dir=$(GDKPIXBUF_PREFIX)/share/gtk-doc/html/gdk-pixbuf \ --extra-dir=../cogl/html \ --extra-dir=../clutter/html # Used for dependencies. The docs will be rebuilt if any of these change. # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c HFILE_GLOB=$(top_srcdir)/src/*/*.h CFILE_GLOB=$(top_srcdir)/src/*/*.c # Extra header to include when scanning, which are not under DOC_SOURCE_DIR # e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h EXTRA_HFILES= # Header files or dirs to ignore when scanning. Use base file/dir names # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code IGNORE_HFILES= \ async-getprop.h \ atoms.h \ bell.h \ boxes-private.h \ clutter-utils.h \ cogl-utils.h \ compositor-private.h \ constraints.h \ core.h \ display-private.h \ draw-workspace.h \ edge-resistance.h \ eventqueue.h \ frame.h \ frames.h \ group-private.h \ group-props.h \ iconcache.h \ inlinepixbufs.h \ keybindings-private.h \ meta-background-actor-private.h \ meta-background-group-private.h \ meta-dbus-login1.h \ meta-module.h \ meta-plugin-manager.h \ meta-shadow-factory-private.h \ meta-texture-rectangle.h \ meta-texture-tower.h \ meta-window-actor-private.h \ meta-window-group.h \ meta-window-shape.h \ muffin-enum-types.h \ muffin-Xatomtype.h \ place.h \ preview-widget.h \ region-utils.h \ resizepopup.h \ screen-private.h \ session.h \ stack.h \ stack-tracker.h \ stamp-muffin-enum-types.h \ tabpopup.h \ theme.h \ theme-private.h \ tile-preview.h \ ui.h \ window-private.h \ window-props.h \ workspace-private.h \ xprops.h \ $(NULL) MKDB_OPTIONS+=--ignore-files="$(IGNORE_HFILES)" # Images to copy into HTML directory. # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png HTML_IMAGES= # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.sgml building.sgml changes-2.0.sgml content_files= \ muffin-overview.xml \ running-muffin.xml \ $(NULL) # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded # These files must be listed here *and* in content_files # e.g. expand_content_files=running.sgml expand_content_files= \ muffin-overview.xml \ running-muffin.xml \ $(NULL) # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget # signals and properties. # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) GTKDOC_CFLAGS=$(WARN_CFLAGS) $(MUFFIN_CFLAGS) GTKDOC_LIBS=$(MUFFIN_LIBS) $(top_builddir)/src/libmuffin.la # This includes the standard gtk-doc make rules, copied by gtkdocize. include $(top_srcdir)/gtk-doc.make # Other files to distribute # e.g. EXTRA_DIST += version.xml.in EXTRA_DIST += # Files not to distribute # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types # for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt DISTCLEANFILES = $(DOC_MODULE).types $(DOC_MODULE)-sections.txt # Comment this out if you want 'make check' to test you doc status # and run some sanity checks if ENABLE_GTK_DOC TESTS_ENVIRONMENT = cd $(srcdir) && \ DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir) #TESTS = $(GTKDOC_CHECK) endif -include $(top_srcdir)/git.mk muffin-5.2.1/doc/reference/muffin/running-muffin.xml0000664000175000017500000000660114211404421022612 0ustar jpeisachjpeisach Running Muffin
Environment Variables Muffin automatically checks environment variables during its initialization. These environment variables are meant as debug tools or overrides for default behaviours: MUFFIN_VERBOSE Enable verbose mode, in which more information is printed to the console. Muffin needs to be built with the --enable-verbose-mode option (enabled by default). For more fine-grained control of the output, see meta_add_verbose_topic(). MUFFIN_DEBUG Traps and prints X errors to the console. MUFFIN_G_FATAL_WARNINGS Causes any logging from the domains Muffin, Gtk, Gdk, Pango or GLib to terminate the process (only when using the log functions in GLib). MUFFIN_USE_LOGFILE Log all messages to a temporary file. MUFFIN_DEBUG_XINERAMA Log extra information about support of the XINERAMA extension. MUFFIN_DEBUG_SM Log extra information about session management. MUFFIN_DEBUG_BUTTON_GRABS Log extra information about button grabs. MUFFIN_SYNC Call XSync after each X call. MUFFIN_DISPLAY Name of the X11 display to use. META_DISABLE_MIPMAPS Disable use of mipmaps for the textures that back window pixmaps. MUFFIN_USE_STATIC_GRAVITY Enable support for clients with static bit-gravity. MUFFIN_WM_CLASS_FILTER Comma-separated list of WM_CLASS names to which to restrict Muffin to. MUFFIN_DISABLE_FALLBACK_COLOR Disable fallback for themed colors, for easier detection of typographical errors.
muffin-5.2.1/doc/reference/muffin/muffin-overview.xml0000664000175000017500000000114014211404421022771 0ustar jpeisachjpeisach Overview Muffin is a GObject-based library for creating compositing window managers. Compositors that wish to use Mutter must implement a subclass of #MetaPlugin and register it with meta_plugin_manager_set_plugin_type() before calling meta_init() but after g_type_init(). #MetaPlugin provides virtual functions that allow to override default behavior in the window management code, such as the effect to perform when a window is created or when switching workspaces. muffin-5.2.1/doc/reference/muffin/muffin-overrides.txt0000664000175000017500000000000014211404421023136 0ustar jpeisachjpeisachmuffin-5.2.1/doc/reference/muffin/muffin-docs.sgml.in0000664000175000017500000000364614211404421022637 0ustar jpeisachjpeisach ]> Muffin Reference Manual This document is for Muffin &version;. Muffin Core Reference Object Hierarchy API Index Index of deprecated API muffin-5.2.1/doc/man/0000775000175000017500000000000014211404421014454 5ustar jpeisachjpeisachmuffin-5.2.1/doc/man/muffin.10000664000175000017500000000510514211404421016023 0ustar jpeisachjpeisach.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH MUFFIN 1 "11 February 2006" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME MUFFIN \- Clutter based compositing GTK2 Window Manager .SH SYNOPSIS .B muffin [\-\-display=\fIDISPLAY\fP] [\-\-replace] [\-\-sm\-client\-id=\fIID\fP] [\-\-sm\-disable] [\-\-sm\-save\-file=\fIFILENAME\fP] [\-\-version] [\-\-help] .SH DESCRIPTION This manual page documents briefly .B muffin\fP. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBmuffin\fP is a minimal X window manager aimed at nontechnical users and is designed to integrate well with the GNOME desktop. \fBmuffin\fP lacks some features that may be expected by traditional UNIX or other technical users; these users may want to investigate other available window managers for use with GNOME or standalone. .SH OPTIONS .TP .B \-\-display=DISPLAY Connect to X display \fIDISPLAY\fP. .TP .B \-\-replace a window manager which is running is replaced by \fBmuffin\fP. Users are encouraged to change the GNOME window manager by running the new WM with the \-\-replace or \-replace option, and subsequently saving the session. .TP .B \-\-sm\-client\-id=ID Specify a session management \fIID\fP. .TP .B \-\-sm\-disable Disable the session management. .TP .B \-\-sm\-save\-file=FILENAME Load a session from \fIFILENAME\fP. .TP .B \-\-version Print the version number. .TP .B \-?, \-\-help Show summary of options. .SH CONFIGURATION \fBmuffin\fP configuration can be found under \fIPreferences\fP->\fIWindows\fP and \fIPreferences\fP->\fIKeyboard Shortcuts\fP on the menu-panel. Advanced configuration can be achieved directly through gsettings. .SH SEE ALSO .BR muffin-message (1) .SH AUTHOR The original manual page was written by Thom May . It was updated by Akira TAGOH for the Debian GNU/Linux system (with permission to use by others), and then updated by Luke Morton and Philip O'Brien for inclusion in muffin. muffin-5.2.1/doc/man/Makefile.am0000664000175000017500000000016014211404421016505 0ustar jpeisachjpeisachman_MANS = muffin.1 muffin-theme-viewer.1 \ muffin-window-demo.1 muffin-message.1 EXTRA_DIST = $(man_MANS) muffin-5.2.1/doc/man/muffin-theme-viewer.10000664000175000017500000000221514211404421020421 0ustar jpeisachjpeisach.\" In .TH, FOO should be all caps, SECTION should be 1-8, maybe w/ subsection .\" other parms are allowed: see man(7), man(1) .\" .\" Based on template provided by Tom Christiansen . .\" .TH MUFFIN-THEME-VIEWER 1 "1 June 2004" .SH NAME muffin-theme-viewer \- view muffin themes .SH SYNOPSIS .B muffin-theme-viewer [ .I THEMENAME ] .SH DESCRIPTION .\" Putting a newline after each sentence can generate better output. .B muffin-theme-viewer allows you to preview any installed Muffin theme. .PP When designing a new Muffin theme, you can use .B muffin-theme-viewer to measure the performance of a window frame option, and to preview the option. .SH OPTIONS .TP .I THEMENAME Name of the theme to be shown (\fIAtlanta\fR by default). It is case-sensitive. .SH FILES .br .nf .TP .I /usr/share/themes system themes directory .TP .I /usr/share/themes/*/muffin-1/muffin-theme-1.xml theme specification file .SH AUTHOR This manual page was written by Jose M. Moya , for the Debian GNU/Linux system (but may be used by others). .SH "SEE ALSO" .\" Always quote multiple words for .SH .BR muffin (1), .BR muffin-window-demo (1). muffin-5.2.1/doc/man/muffin-message.10000664000175000017500000000425214211404421017447 0ustar jpeisachjpeisach.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .\" ----- .\" This file was confirmed to be licenced under the GPL .\" by its author and copyright holder, Akira TAGOH, on June 1st 2008: .\" .\" > I'm comfortable with DFSG-free. that sounds great if you think it's .\" > useful and worth containing it in upstream. .\" ... .\" > Right I know. any licenses that is DFSG-free, I'm ok with whatever, .\" > since I have contributed that for Debian. so GPL is no problem for me. .\" ----- .TH MUFFIN\-MESSAGE 1 "28 August 2002" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME MUFFIN\-MESSAGE \- a command to send a message to Muffin .SH SYNOPSIS .B MUFFIN\-MESSAGE [restart|reload\-theme|enable\-keybindings|disable\-keybindings] .SH DESCRIPTION This manual page documents briefly the .B muffin\-message\fP. This manual page was written for the Debian distribution because the original program does not have a manual page. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBmuffin\-message\fP send a specified message to \fBmuffin\fP(1). .SH OPTIONS .TP .B restart Restart \fBmuffin\fP(1) which is running. .TP .B reload-theme Reload a theme which is specified on gsettings database. .TP .B enable-keybindings Enable all of keybindings which is specified on gsettings database. .TP .B disable-keybindings Disable all of keybindings which is specified on gsettings database. .SH SEE ALSO .BR muffin (1) .SH AUTHOR This manual page was written by Akira TAGOH , for the Debian GNU/Linux system (but may be used by others). muffin-5.2.1/doc/man/muffin-window-demo.10000664000175000017500000000157614211404421020262 0ustar jpeisachjpeisach.\" In .TH, FOO should be all caps, SECTION should be 1-8, maybe w/ subsection .\" other parms are allowed: see man(7), man(1) .\" .\" Based on template provided by Tom Christiansen . .\" .TH MUFFIN-WINDOW-DEMO 1 "1 June 2004" .SH NAME muffin-window-demo \- demo of window features .SH SYNOPSIS .B muffin-window-demo .SH DESCRIPTION .\" Putting a newline after each sentence can generate better output. This program demonstrates various kinds of windows that window managers and window manager themes should handle. .PP Be sure to tear off the menu and toolbar, those are also a special kind of window. .SH AUTHOR This manual page was written by Jose M. Moya , for the Debian GNU/Linux system (but may be used by others). .SH "SEE ALSO" .\" Always quote multiple words for .SH .BR x-window-manager (1), .BR muffin (1), .BR muffin-theme-viewer (1). muffin-5.2.1/README0000664000175000017500000000010214211404421014005 0ustar jpeisachjpeisachMuffin ====== The Cinnamon Window Manager Based on Mutter 3.2.1 muffin-5.2.1/data/0000775000175000017500000000000014211404421014045 5ustar jpeisachjpeisachmuffin-5.2.1/data/theme/0000775000175000017500000000000014211404421015147 5ustar jpeisachjpeisachmuffin-5.2.1/data/theme/metacity-theme-3.xml0000664000175000017500000030444614211404421020763 0ustar jpeisachjpeisach Adwaita GNOME Art Team <art.gnome.org>  Intel,  Red Hat, Lapo Calamandrei 2014 Default GNOME 3 window theme <title version="< 3.1" x="(0 `max` ((width - title_width) / 2))" y="(0 `max` ((height - title_height) / 2))" color="C_title_focused_hilight_dark" /> <title version="< 3.1" x="(0 `max` ((width - title_width) / 2))" y="(0 `max` ((height - title_height) / 2)) + 1" color="C_title_focused" /> <title version=">= 3.1" x="(0 `max` ((frame_x_center - title_width / 2) `min` (width - title_width)))" y="(0 `max` ((height - title_height) / 2)) + 2" ellipsize_width="width" color="C_title_focused_hilight" /> <title version=">= 3.1" x="(0 `max` ((frame_x_center - title_width / 2) `min` (width - title_width)))" y="(0 `max` ((height - title_height) / 2))" ellipsize_width="width" color="C_title_focused_hilight_dark" /> <title version=">= 3.1" x="(0 `max` ((frame_x_center - title_width / 2) `min` (width - title_width)))" y="(0 `max` ((height - title_height) / 2)) + 1" ellipsize_width="width" color="C_title_focused" /> </draw_ops> <draw_ops name="title_unfocused"> <title version="< 3.1" x="(0 `max` ((width - title_width) / 2))" y="(0 `max` ((height - title_height) / 2)) + 1" color="C_title_unfocused"/> <title version=">= 3.1" x="(0 `max` ((frame_x_center - title_width/2) `min` (width - title_width)))" y="(0 `max` ((height - title_height) / 2)) + 1" ellipsize_width="width" color="C_title_unfocused"/> </draw_ops> <!-- window decorations --> <draw_ops name="entire_background_focused"> <rectangle color="gtk:bg[NORMAL]" x="0" y="0" width="width" height="height" filled="true" /> </draw_ops> <draw_ops name="entire_background_unfocused"> <include name="entire_background_focused" /> </draw_ops> <draw_ops name="titlebar_fill_focused"> <gradient type="vertical" x="0" y="0" width="width" height="height"> <color value="gtk:custom(wm_bg_a,blend/gtk:bg[NORMAL]/gtk:base[NORMAL]/0.4)" /> <color value="gtk:custom(wm_bg_b,gtk:bg[NORMAL])" /> </gradient> </draw_ops> <draw_ops name="titlebar_fill_unfocused"> <rectangle color="C_titlebar_unfocused" x="0" y="0" width="width" height="height" filled="true" /> </draw_ops> <draw_ops name="hilight"> <line x1="0" y1="1" x2="width-1" y2="1" color="C_titlebar_focused_hilight" /> </draw_ops> <draw_ops name="rounded_hilight"> <line x1="5" y1="1" x2="width-6" y2="1" color="C_titlebar_focused_hilight" /> <arc color="C_titlebar_focused_hilight" x="0" y="1" width="8" height="7" start_angle="270" extent_angle="90" /> <arc color="C_titlebar_focused_hilight" x="width-10" y="1" width="9" height="7" start_angle="0" extent_angle="90" /> </draw_ops> <draw_ops name="titlebar_focused"> <include name="titlebar_fill_focused" /> <include name="hilight" /> </draw_ops> <draw_ops name="rounded_titlebar_focused"> <include name="titlebar_fill_focused" /> <include name="rounded_hilight" /> </draw_ops> <draw_ops name="rounded_titlebar_focused_alt"> <include name="titlebar_fill_focused" /> <include name="rounded_hilight" /> </draw_ops> <draw_ops name="rounded_titlebar_unfocused"> <include name="titlebar_fill_unfocused" /> <include name="rounded_hilight" /> </draw_ops> <draw_ops name="titlebar_unfocused"> <include name="titlebar_fill_unfocused" /> <include name="hilight" /> </draw_ops> <draw_ops name="border_focused"> <rectangle color="C_border_focused" x="0" y="0" width="width-1" height="height-1" filled="false" /> </draw_ops> <draw_ops name="border_unfocused"> <rectangle color="C_border_unfocused" x="0" y="0" width="width-1" height="height-1" filled="false" /> </draw_ops> <draw_ops name="rounded_border_focused"> <line color="C_border_focused" x1="4" y1="0" x2="width-5" y2="0" /> <line color="C_border_focused" x1="0" y1="height-1" x2="width-1" y2="height-1" /> <line color="C_border_focused" x1="0" y1="4" x2="0" y2="height-2" /> <line color="C_border_focused" x1="width-1" y1="4" x2="width-1" y2="height-2" /> <arc color="C_border_focused" x="0" y="0" width="9" height="9" start_angle="270" extent_angle="90" /> <arc color="C_border_focused" x="width-10" y="0" width="9" height="9" start_angle="0" extent_angle="90" /> <!-- double arcs for darker borders --> <arc color="C_border_focused" x="0" y="0" width="9" height="9" start_angle="270" extent_angle="90" /> <arc color="C_border_focused" x="width-10" y="0" width="9" height="9" start_angle="0" extent_angle="90" /> </draw_ops> <draw_ops name="rounded_border_unfocused"> <line color="C_border_unfocused" x1="4" y1="0" x2="width-5" y2="0" /> <line color="C_border_unfocused" x1="0" y1="height-1" x2="width-1" y2="height-1" /> <line color="C_border_unfocused" x1="0" y1="4" x2="0" y2="height-2" /> <line color="C_border_unfocused" x1="width-1" y1="4" x2="width-1" y2="height-2" /> <arc color="C_border_unfocused" x="0" y="0" width="9" height="9" start_angle="270" extent_angle="90" /> <arc color="C_border_unfocused" x="width-10" y="0" width="9" height="9" start_angle="0" extent_angle="90" /> <!-- double arcs for darker borders --> <arc color="C_border_unfocused" x="0" y="0" width="9" height="9" start_angle="270" extent_angle="90" /> <arc color="C_border_unfocused" x="width-10" y="0" width="9" height="9" start_angle="0" extent_angle="90" /> </draw_ops> <draw_ops name="border_left_focused"> <line x1="0" y1="0" x2="0" y2="height" color="C_border_focused" /> </draw_ops> <draw_ops name="border_left_unfocused"> <line x1="0" y1="0" x2="0" y2="height" color="C_border_unfocused" /> </draw_ops> <!-- button icons--> <draw_ops name="close_shadow_focused"> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_shadow" /> <line x1="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_shadow" /> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_shadow" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_shadow" /> <line x1="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_shadow" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_shadow" /> </draw_ops> <draw_ops name="close_glyph_focused"> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_focused" /> <line x1="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_focused" /> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_focused" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_focused" /> <line x1="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_focused" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_focused" /> </draw_ops> <draw_ops name="close_focused"> <include name="close_shadow_focused" y="1" /> <include name="close_glyph_focused" /> </draw_ops> <draw_ops name="close_focused_pressed"> <include name="close_focused"/> </draw_ops> <draw_ops name="close_focused_prelight"> <include name="close_focused"/> </draw_ops> <draw_ops name="close_glyph_unfocused"> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused" /> <line x1="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_unfocused" /> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused" /> <line x1="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_unfocused" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused" /> </draw_ops> <draw_ops name="close_unfocused"> <include name="close_glyph_unfocused" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="close_glyph_unfocused_prelight"> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_prelight" /> <line x1="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_prelight" /> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_prelight" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_prelight" /> <line x1="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_prelight" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_prelight" /> </draw_ops> <draw_ops name="close_unfocused_prelight"> <include name="close_glyph_unfocused_prelight" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="close_glyph_unfocused_pressed"> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_pressed" /> <line x1="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_pressed" /> <line x1="(width-width%3)/3+D_icons_shrink-D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_pressed" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_pressed" /> <line x1="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_pressed" /> <line x1="width-(width-width%3)/3-1-D_icons_shrink+D_icons_grow" y1="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" x2="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y2="height-(height-height%3)/3-1-D_icons_shrink+D_icons_grow" color="C_icons_unfocused_pressed" /> </draw_ops> <draw_ops name="close_unfocused_pressed"> <include name="close_glyph_unfocused_pressed" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="maximize_glyph_focused"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-1-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_focused" /> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_focused" /> </draw_ops> <draw_ops name="maximize_shadow_focused"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-1-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_shadow" /> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_shadow" /> </draw_ops> <draw_ops name="maximize_focused"> <include name="maximize_shadow_focused" y="1" /> <include name="maximize_glyph_focused" /> </draw_ops> <draw_ops name="maximize_focused_pressed"> <include name="maximize_focused" /> </draw_ops> <draw_ops name="maximize_focused_prelight"> <include name="maximize_focused" /> </draw_ops> <draw_ops name="maximize_glyph_unfocused"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-1-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused" /> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused" /> </draw_ops> <draw_ops name="maximize_unfocused"> <include name="maximize_glyph_unfocused" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="maximize_glyph_unfocused_prelight"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-1-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_prelight" /> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_prelight" /> </draw_ops> <draw_ops name="maximize_unfocused_prelight"> <include name="maximize_glyph_unfocused_prelight" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="maximize_glyph_unfocused_pressed"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-1-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_pressed" /> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_pressed" /> </draw_ops> <draw_ops name="maximize_unfocused_pressed"> <include name="maximize_glyph_unfocused_pressed" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="minimize_glyph_focused"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_focused" /> </draw_ops> <draw_ops name="minimize_shadow_focused"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_shadow" /> </draw_ops> <draw_ops name="minimize_focused"> <include name="minimize_shadow_focused" y="1" /> <include name="minimize_glyph_focused" /> </draw_ops> <draw_ops name="minimize_focused_pressed"> <include name="minimize_focused" /> </draw_ops> <draw_ops name="minimize_focused_prelight"> <include name="minimize_focused" /> </draw_ops> <draw_ops name="minimize_glyph_unfocused"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused" /> </draw_ops> <draw_ops name="minimize_unfocused"> <include name="minimize_glyph_unfocused" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="minimize_glyph_unfocused_prelight"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_prelight" /> </draw_ops> <draw_ops name="minimize_unfocused_prelight"> <include name="minimize_glyph_unfocused_prelight" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="minimize_glyph_unfocused_pressed"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_pressed" /> </draw_ops> <draw_ops name="minimize_unfocused_pressed"> <include name="minimize_glyph_unfocused_pressed" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="menu_glyph_focused"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_focused" /> <rectangle x="(width-width%3)/3+2+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-5-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_focused" /> <rectangle x="(width-width%3)/3+4+D_icons_shrink-D_icons_grow" y="height/2-1-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-8-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_focused" /> </draw_ops> <draw_ops name="menu_shadow_focused"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_shadow" /> <rectangle x="(width-width%3)/3+2+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-5-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_shadow" /> <rectangle x="(width-width%3)/3+4+D_icons_shrink-D_icons_grow" y="height/2-1-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-8-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_shadow" /> </draw_ops> <draw_ops name="menu_focused"> <include name="menu_shadow_focused" y="1" /> <include name="menu_glyph_focused" /> </draw_ops> <draw_ops name="menu_focused_pressed"> <include name="menu_glyph_focused" /> </draw_ops> <draw_ops name="menu_glyph_unfocused"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused" /> <rectangle x="(width-width%3)/3+2+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-5-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused" /> <rectangle x="(width-width%3)/3+4+D_icons_shrink-D_icons_grow" y="height/2-1-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-8-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused" /> </draw_ops> <draw_ops name="menu_unfocused"> <include name="menu_glyph_unfocused" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="menu_glyph_unfocused_prelight"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_prelight" /> <rectangle x="(width-width%3)/3+2+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-5-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_prelight" /> <rectangle x="(width-width%3)/3+4+D_icons_shrink-D_icons_grow" y="height/2-1-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-8-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_prelight" /> </draw_ops> <draw_ops name="menu_unfocused_prelight"> <include name="menu_glyph_unfocused_prelight" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="menu_glyph_unfocused_pressed"> <rectangle x="(width-width%3)/3+1+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-3-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-1-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_pressed" /> <rectangle x="(width-width%3)/3+2+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+1+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-5-2*D_icons_shrink+2*D_icons_grow" height="height-2*(height-height%3)/3-3-2*D_icons_shrink+2*D_icons_grow" color="C_icons_unfocused_pressed" /> <rectangle x="(width-width%3)/3+4+D_icons_shrink-D_icons_grow" y="height/2-1-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-8-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_pressed" /> </draw_ops> <draw_ops name="menu_unfocused_pressed"> <include name="menu_glyph_unfocused_pressed" y="D_icons_unfocused_offset" /> </draw_ops> <!-- icon size used in GTK --> <constant name="D_appmenu_icon_size" value="16" /> <draw_ops name="appmenu_icon_focused"> <icon x="(width-D_appmenu_icon_size)/2" y="(height-D_appmenu_icon_size)/2" width="D_appmenu_icon_size" height="D_appmenu_icon_size" /> </draw_ops> <draw_ops name="appmenu_focused"> <include name="appmenu_icon_focused" /> </draw_ops> <draw_ops name="appmenu_focused_pressed"> <include name="appmenu_icon_focused" /> </draw_ops> <draw_ops name="appmenu_icon_unfocused"> <icon x="(width-D_appmenu_icon_size)/2" y="(height-D_appmenu_icon_size)/2" width="D_appmenu_icon_size" height="D_appmenu_icon_size" alpha="0.4"/> </draw_ops> <draw_ops name="appmenu_unfocused"> <include name="appmenu_icon_unfocused" /> </draw_ops> <draw_ops name="appmenu_icon_unfocused_prelight"> <icon x="(width-D_appmenu_icon_size)/2" y="(height-D_appmenu_icon_size)/2" width="D_appmenu_icon_size" height="D_appmenu_icon_size" alpha="0.6"/> </draw_ops> <draw_ops name="appmenu_unfocused_prelight"> <include name="appmenu_icon_unfocused_prelight" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="appmenu_unfocused_pressed"> <include name="appmenu_icon_unfocused_prelight" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="shade_glyph_focused"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_focused" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_focused" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_focused" /> <rectangle x="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_focused" /> </draw_ops> <draw_ops name="shade_shadow_focused"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_shadow" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_shadow" /> </draw_ops> <draw_ops name="shade_focused"> <include name="shade_shadow_focused" y="1" /> <include name="shade_glyph_focused" /> </draw_ops> <draw_ops name="shade_focused_pressed"> <include name="shade_glyph_focused" /> </draw_ops> <draw_ops name="shade_glyph_unfocused"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_unfocused" /> <rectangle x="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_unfocused" /> </draw_ops> <draw_ops name="shade_unfocused"> <include name="shade_glyph_unfocused" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="shade_glyph_unfocused_prelight"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_prelight" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_prelight" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_unfocused_prelight" /> <rectangle x="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_unfocused_prelight" /> </draw_ops> <draw_ops name="shade_unfocused_prelight"> <include name="shade_glyph_unfocused_prelight" y="D_icons_unfocused_offset" /> </draw_ops> <draw_ops name="shade_glyph_unfocused_pressed"> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+D_icons_shrink-D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_pressed" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="height-(height-height%3)/3-2-D_icons_shrink+D_icons_grow" width="width-2*(width-width%3)/3-2*D_icons_shrink+2*D_icons_grow" height="2" filled="true" color="C_icons_unfocused_pressed" /> <rectangle x="(width-width%3)/3+D_icons_shrink-D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_unfocused_pressed" /> <rectangle x="width-(width-width%3)/3-2-D_icons_shrink+D_icons_grow" y="(height-height%3)/3+3+D_icons_shrink-D_icons_grow" width="2" height="height-2*(height-height%3)/3-6-D_icons_shrink+D_icons_grow" filled="true" color="C_icons_unfocused_pressed" /> </draw_ops> <draw_ops name="shade_unfocused_pressed"> <include name="shade_glyph_unfocused_pressed" y="D_icons_unfocused_offset" /> </draw_ops> <!-- button backgrounds --> <constant name="C_button_border" value="blend/#000000/gtk:bg[NORMAL]/0.8" /> <constant name="C_button_hilight" value="gtk:custom(wm_highlight,blend/gtk:base[NORMAL]/gtk:bg[NORMAL]/0.6)" /> <draw_ops name="button_border"> <line x1="6" y1="4" x2="width-7" y2="4" color="C_button_border" /> <arc color="C_button_border" x="width-9" y="4" width="4" height="4" start_angle="0" extent_angle="90"/> <line x1="width-5" y1="6" x2="width-5" y2="height-7" color="C_button_border" /> <arc color="C_button_border" x="width-9" y="height-9" width="4" height="4" start_angle="90" extent_angle="90"/> <line x1="width-6" y1="height-5" x2="6" y2="height-5" color="C_button_border" /> <arc color="C_button_border" x="4" y="height-9" width="4" height="4" start_angle="180" extent_angle="90"/> <line x1="4" y1="6" x2="4" y2="height-7" color="C_button_border" /> <arc color="C_button_border" x="4" y="4" width="4" height="4" start_angle="270" extent_angle="90"/> <line x1="width-7" y1="height-4" x2="7" y2="height-4" color="C_title_focused_hilight" /> </draw_ops> <draw_ops name="button_fill"> <!-- button background gradient --> </draw_ops> <draw_ops name="button_fill_prelight"> <!-- button background gradient for prelight status --> <gradient type="vertical" x="5" y="5" width="width-10" height="height-10"> <color value="gtk:custom(wm_button_hover_color_a,gtk:fg[NORMAL])" /> <color value="gtk:custom(wm_button_hover_color_b,gtk:fg[NORMAL])" /> </gradient> <include name="button_border" /> </draw_ops> <draw_ops name="button_fill_pressed"> <!-- button background gradient for pressed status --> <gradient type="vertical" x="5" y="5" width="width-10" height="height-10"> <color value="gtk:custom(wm_button_active_color_b,gtk:fg[NORMAL])" /> <color value="gtk:custom(wm_button_active_color_c,gtk:fg[NORMAL])" /> </gradient> <line x1="5" y1="5" x2="width-6" y2="5" color="blend/#000000/gtk:custom(wm_button_active_color_a,gtk:fg[NORMAL])/0.9" /> <line x1="4" y1="6" x2="width-5" y2="6" color="gtk:custom(wm_button_active_color_a,gtk:fg[NORMAL])" /> <include name="button_border" /> </draw_ops> <draw_ops name="button"> </draw_ops> <draw_ops name="button_prelight"> <include name="button_fill_prelight" /> </draw_ops> <draw_ops name="button_pressed"> <include name="button_fill_pressed" /> </draw_ops> <!-- frame styles --> <frame_style name="normal_focused" geometry="normal"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="rounded_titlebar_focused" /> <piece position="title" draw_ops="title_focused" /> <piece position="overlay" draw_ops="rounded_border_focused" /> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="normal_unfocused" geometry="normal_unfocused"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="rounded_titlebar_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <piece position="overlay" draw_ops="rounded_border_unfocused" /> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal" draw_ops="shade_unfocused" /> <button function="shade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="shade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_unfocused" /> <button function="unshade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="unshade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="normal_max_focused" geometry="max"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="titlebar_focused" /> <piece position="title" draw_ops="title_focused" /> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="normal_max_unfocused" geometry="max"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal" draw_ops="shade_unfocused" /> <button function="shade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="shade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_unfocused" /> <button function="unshade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="unshade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="normal_max_shaded_focused" geometry="max"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="titlebar_focused" /> <piece position="title" draw_ops="title_focused" /> <piece position="overlay"><draw_ops><line x1="0" y1="height-1" x2="width" y2="height-1" color="C_border_focused" /></draw_ops></piece> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="normal_max_shaded_unfocused" geometry="max"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <piece position="overlay"><draw_ops><line x1="0" y1="height-1" x2="width" y2="height-1" color="C_border_unfocused" /></draw_ops></piece> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal" draw_ops="shade_unfocused" /> <button function="shade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="shade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_unfocused" /> <button function="unshade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="unshade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="dialog_focused" geometry="normal"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="rounded_titlebar_focused" /> <piece position="title" draw_ops="title_focused" /> <piece position="overlay" draw_ops="rounded_border_focused" /> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="dialog_unfocused" geometry="normal_unfocused"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <piece position="overlay" draw_ops="rounded_border_unfocused" /> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal"><draw_ops></draw_ops></button> <button function="shade" state="pressed"><draw_ops></draw_ops></button> <button function="unshade" state="normal"><draw_ops></draw_ops></button> <button function="unshade" state="pressed"><draw_ops></draw_ops></button> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="modal_dialog_focused" geometry="modal"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="titlebar_focused" /> <piece position="title" draw_ops="title_focused" /> <piece position="overlay" draw_ops="border_focused" /> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button><button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="modal_dialog_unfocused" geometry="modal"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <piece position="overlay" draw_ops="border_unfocused" /> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal" draw_ops="shade_unfocused" /> <button function="shade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="shade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_unfocused" /> <button function="unshade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="unshade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="utility_focused" geometry="small"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="titlebar_focused" /> <piece position="title" draw_ops="title_focused" /> <piece position="overlay" draw_ops="border_focused" /> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="utility_unfocused" geometry="small_unfocused"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <piece position="overlay" draw_ops="border_unfocused" /> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal" draw_ops="shade_unfocused" /> <button function="shade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="shade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_unfocused" /> <button function="unshade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="unshade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="border_focused" geometry="border"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="overlay" draw_ops="border_focused" /> <button function="close" state="normal"><draw_ops></draw_ops></button> <button function="close" state="pressed"><draw_ops></draw_ops></button> <button function="maximize" state="normal"><draw_ops></draw_ops></button> <button function="maximize" state="pressed"><draw_ops></draw_ops></button> <button function="minimize" state="normal"><draw_ops></draw_ops></button> <button function="minimize" state="pressed"><draw_ops></draw_ops></button> <button function="menu" state="normal"><draw_ops></draw_ops></button> <button function="menu" state="pressed"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="normal"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="pressed"><draw_ops></draw_ops></button> <button function="shade" state="normal"><draw_ops></draw_ops></button> <button function="shade" state="pressed"><draw_ops></draw_ops></button> <button function="unshade" state="normal"><draw_ops></draw_ops></button> <button function="unshade" state="pressed"><draw_ops></draw_ops></button> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="border_unfocused" geometry="border"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="overlay" draw_ops="border_unfocused" /> <button function="close" state="normal"><draw_ops></draw_ops></button> <button function="close" state="pressed"><draw_ops></draw_ops></button> <button function="maximize" state="normal"><draw_ops></draw_ops></button> <button function="maximize" state="pressed"><draw_ops></draw_ops></button> <button function="minimize" state="normal"><draw_ops></draw_ops></button> <button function="minimize" state="pressed"><draw_ops></draw_ops></button> <button function="menu" state="normal"><draw_ops></draw_ops></button> <button function="menu" state="pressed"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="normal"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="pressed"><draw_ops></draw_ops></button> <button function="shade" state="normal"><draw_ops></draw_ops></button> <button function="shade" state="pressed"><draw_ops></draw_ops></button> <button function="unshade" state="normal"><draw_ops></draw_ops></button> <button function="unshade" state="pressed"><draw_ops></draw_ops></button> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="borderless" geometry="borderless"> <button function="close" state="normal"><draw_ops></draw_ops></button> <button function="close" state="pressed"><draw_ops></draw_ops></button> <button function="maximize" state="normal"><draw_ops></draw_ops></button> <button function="maximize" state="pressed"><draw_ops></draw_ops></button> <button function="minimize" state="normal"><draw_ops></draw_ops></button> <button function="minimize" state="pressed"><draw_ops></draw_ops></button> <button function="menu" state="normal"><draw_ops></draw_ops></button> <button function="menu" state="pressed"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="normal"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="pressed"><draw_ops></draw_ops></button> <button function="shade" state="normal"><draw_ops></draw_ops></button> <button function="shade" state="pressed"><draw_ops></draw_ops></button> <button function="unshade" state="normal"><draw_ops></draw_ops></button> <button function="unshade" state="pressed"><draw_ops></draw_ops></button> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="attached_focused" geometry="attached"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="titlebar_fill_focused" /> <piece position="title" draw_ops="title_focused" /> <piece position="overlay" draw_ops="border_focused" /> <button function="close" state="normal"><draw_ops></draw_ops></button> <button function="close" state="pressed"><draw_ops></draw_ops></button> <button function="maximize" state="normal"><draw_ops></draw_ops></button> <button function="maximize" state="pressed"><draw_ops></draw_ops></button> <button function="minimize" state="normal"><draw_ops></draw_ops></button> <button function="minimize" state="pressed"><draw_ops></draw_ops></button> <button function="menu" state="normal"><draw_ops></draw_ops></button> <button function="menu" state="pressed"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="normal"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="pressed"><draw_ops></draw_ops></button> <button function="shade" state="normal"><draw_ops></draw_ops></button> <button function="shade" state="pressed"><draw_ops></draw_ops></button> <button function="unshade" state="normal"><draw_ops></draw_ops></button> <button function="unshade" state="pressed"><draw_ops></draw_ops></button> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="attached_unfocused" geometry="attached"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_fill_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <piece position="overlay" draw_ops="border_unfocused" /> <button function="close" state="normal"><draw_ops></draw_ops></button> <button function="close" state="pressed"><draw_ops></draw_ops></button> <button function="maximize" state="normal"><draw_ops></draw_ops></button> <button function="maximize" state="pressed"><draw_ops></draw_ops></button> <button function="minimize" state="normal"><draw_ops></draw_ops></button> <button function="minimize" state="pressed"><draw_ops></draw_ops></button> <button function="menu" state="normal"><draw_ops></draw_ops></button> <button function="menu" state="pressed"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="normal"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="pressed"><draw_ops></draw_ops></button> <button function="shade" state="normal"><draw_ops></draw_ops></button> <button function="shade" state="pressed"><draw_ops></draw_ops></button> <button function="unshade" state="normal"><draw_ops></draw_ops></button> <button function="unshade" state="pressed"><draw_ops></draw_ops></button> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="tiled_left_focused" geometry="tiled_left"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="titlebar_fill_focused" /> <piece position="title" draw_ops="title_focused" /> <!-- <piece position="overlay" draw_ops="border_right_focused" /> --> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="tiled_left_unfocused" geometry="tiled_left"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_fill_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <!-- <piece position="overlay" draw_ops="border_right_unfocused" /> --> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal" draw_ops="shade_unfocused" /> <button function="shade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="shade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_unfocused" /> <button function="unshade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="unshade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="tiled_right_focused" geometry="tiled_right"> <piece position="entire_background" draw_ops="entire_background_focused" /> <piece position="titlebar" draw_ops="titlebar_fill_focused" /> <piece position="title" draw_ops="title_focused" /> <piece position="overlay" draw_ops="border_left_focused" /> <button function="close" state="normal" draw_ops="close_focused" /> <button function="close" state="pressed" draw_ops="close_focused_pressed" /> <button function="close" state="prelight" draw_ops="close_focused_prelight" /> <button function="maximize" state="normal" draw_ops="maximize_focused" /> <button function="maximize" state="pressed" draw_ops="maximize_focused_pressed" /> <button function="maximize" state="prelight" draw_ops="maximize_focused_prelight" /> <button function="minimize" state="normal" draw_ops="minimize_focused" /> <button function="minimize" state="pressed" draw_ops="minimize_focused_pressed" /> <button function="minimize" state="prelight" draw_ops="minimize_focused_prelight" /> <button function="menu" state="normal" draw_ops="menu_focused" /> <button function="menu" state="pressed" draw_ops="menu_focused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_focused" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_focused_pressed" /> <button function="shade" state="normal" draw_ops="shade_focused" /> <button function="shade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_focused" /> <button function="unshade" state="pressed" draw_ops="shade_focused_pressed" /> <button function="left_middle_background" state="normal" draw_ops="button"/> <button function="left_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="left_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="right_middle_background" state="normal" draw_ops="button"/> <button function="right_middle_background" state="pressed" draw_ops="button_pressed"/> <button function="right_middle_background" state="prelight" draw_ops="button_prelight"/> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <frame_style name="tiled_right_unfocused" geometry="tiled_right"> <piece position="entire_background" draw_ops="entire_background_unfocused" /> <piece position="titlebar" draw_ops="titlebar_fill_unfocused" /> <piece position="title" draw_ops="title_unfocused" /> <piece position="overlay" draw_ops="border_left_unfocused" /> <button function="close" state="normal" draw_ops="close_unfocused"/> <button function="close" state="prelight" draw_ops="close_unfocused_prelight"/> <button function="close" state="pressed" draw_ops="close_unfocused_pressed"/> <button function="maximize" state="normal" draw_ops="maximize_unfocused"/> <button function="maximize" state="prelight" draw_ops="maximize_unfocused_prelight"/> <button function="maximize" state="pressed" draw_ops="maximize_unfocused_pressed"/> <button function="minimize" state="normal" draw_ops="minimize_unfocused"/> <button function="minimize" state="prelight" draw_ops="minimize_unfocused_prelight"/> <button function="minimize" state="pressed" draw_ops="minimize_unfocused_pressed"/> <button function="menu" state="normal" draw_ops="menu_unfocused" /> <button function="menu" state="prelight" draw_ops="menu_unfocused_prelight" /> <button function="menu" state="pressed" draw_ops="menu_unfocused_pressed" /> <button version=">= 3.5" function="appmenu" state="normal" draw_ops="appmenu_unfocused" /> <button version=">= 3.5" function="appmenu" state="prelight" draw_ops="appmenu_unfocused_prelight" /> <button version=">= 3.5" function="appmenu" state="pressed" draw_ops="appmenu_unfocused_pressed" /> <button function="shade" state="normal" draw_ops="shade_unfocused" /> <button function="shade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="shade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="unshade" state="normal" draw_ops="shade_unfocused" /> <button function="unshade" state="prelight" draw_ops="shade_unfocused_prelight" /> <button function="unshade" state="pressed" draw_ops="shade_unfocused_pressed" /> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <!-- placeholder for unimplementated styles--> <frame_style name="blank" geometry="normal"> <button function="close" state="normal"><draw_ops></draw_ops></button> <button function="close" state="pressed"><draw_ops></draw_ops></button> <button function="maximize" state="normal"><draw_ops></draw_ops></button> <button function="maximize" state="pressed"><draw_ops></draw_ops></button> <button function="minimize" state="normal"><draw_ops></draw_ops></button> <button function="minimize" state="pressed"><draw_ops></draw_ops></button> <button function="menu" state="normal"><draw_ops></draw_ops></button> <button function="menu" state="pressed"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="normal"><draw_ops></draw_ops></button> <button version=">= 3.5" function="appmenu" state="pressed"><draw_ops></draw_ops></button> <button function="shade" state="normal"><draw_ops></draw_ops></button> <button function="shade" state="pressed"><draw_ops></draw_ops></button> <button function="unshade" state="normal"><draw_ops></draw_ops></button> <button function="unshade" state="pressed"><draw_ops></draw_ops></button> <button function="above" state="normal"><draw_ops></draw_ops></button> <button function="above" state="pressed"><draw_ops></draw_ops></button> <button function="unabove" state="normal"><draw_ops></draw_ops></button> <button function="unabove" state="pressed"><draw_ops></draw_ops></button> <button function="stick" state="normal"><draw_ops></draw_ops></button> <button function="stick" state="pressed"><draw_ops></draw_ops></button> <button function="unstick" state="normal"><draw_ops></draw_ops></button> <button function="unstick" state="pressed"><draw_ops></draw_ops></button> </frame_style> <!-- frame style sets --> <frame_style_set name="normal_style_set"> <frame focus="yes" state="normal" resize="both" style="normal_focused"/> <frame focus="no" state="normal" resize="both" style="normal_unfocused"/> <frame focus="yes" state="maximized" style="normal_max_focused"/> <frame focus="no" state="maximized" style="normal_max_unfocused"/> <frame focus="yes" state="shaded" style="normal_focused"/> <frame focus="no" state="shaded" style="normal_unfocused"/> <frame focus="yes" state="maximized_and_shaded" style="normal_max_shaded_focused"/> <frame focus="no" state="maximized_and_shaded" style="normal_max_shaded_unfocused"/> <frame version=">= 3.3" focus="yes" state="tiled_left" style="tiled_left_focused"/> <frame version=">= 3.3" focus="no" state="tiled_left" style="tiled_left_unfocused"/> <frame version=">= 3.3" focus="yes" state="tiled_right" style="tiled_right_focused"/> <frame version=">= 3.3" focus="no" state="tiled_right" style="tiled_right_unfocused"/> <frame version=">= 3.3" focus="yes" state="tiled_left_and_shaded" style="tiled_left_focused"/> <frame version=">= 3.3" focus="no" state="tiled_left_and_shaded" style="tiled_left_unfocused"/> <frame version=">= 3.3" focus="yes" state="tiled_right_and_shaded" style="tiled_right_focused"/> <frame version=">= 3.3" focus="no" state="tiled_right_and_shaded" style="tiled_right_unfocused"/> </frame_style_set> <frame_style_set name="dialog_style_set"> <frame focus="yes" state="normal" resize="both" style="dialog_focused"/> <frame focus="no" state="normal" resize="both" style="dialog_unfocused"/> <frame focus="yes" state="maximized" style="blank"/> <frame focus="no" state="maximized" style="blank"/> <frame focus="yes" state="shaded" style="dialog_focused"/> <frame focus="no" state="shaded" style="dialog_unfocused"/> <frame focus="yes" state="maximized_and_shaded" style="blank"/> <frame focus="no" state="maximized_and_shaded" style="blank"/> </frame_style_set> <frame_style_set name="modal_dialog_style_set"> <frame focus="yes" state="normal" resize="both" style="modal_dialog_focused"/> <frame focus="no" state="normal" resize="both" style="modal_dialog_unfocused"/> <frame focus="yes" state="maximized" style="blank"/> <frame focus="no" state="maximized" style="blank"/> <frame focus="yes" state="shaded" style="modal_dialog_focused"/> <frame focus="no" state="shaded" style="modal_dialog_unfocused"/> <frame focus="yes" state="maximized_and_shaded" style="blank"/> <frame focus="no" state="maximized_and_shaded" style="blank"/> </frame_style_set> <frame_style_set name="utility_style_set"> <frame focus="yes" state="normal" resize="both" style="utility_focused"/> <frame focus="no" state="normal" resize="both" style="utility_unfocused"/> <frame focus="yes" state="maximized" style="blank"/> <frame focus="no" state="maximized" style="blank"/> <frame focus="yes" state="shaded" style="utility_focused"/> <frame focus="no" state="shaded" style="utility_unfocused"/> <frame focus="yes" state="maximized_and_shaded" style="blank"/> <frame focus="no" state="maximized_and_shaded" style="blank"/> </frame_style_set> <frame_style_set name="border_style_set"> <frame focus="yes" state="normal" resize="both" style="border_focused"/> <frame focus="no" state="normal" resize="both" style="border_unfocused"/> <frame focus="yes" state="maximized" style="borderless"/> <frame focus="no" state="maximized" style="borderless"/> <frame focus="yes" state="shaded" style="blank"/> <frame focus="no" state="shaded" style="blank"/> <frame focus="yes" state="maximized_and_shaded" style="blank"/> <frame focus="no" state="maximized_and_shaded" style="blank"/> </frame_style_set> <frame_style_set name="attached_style_set"> <frame focus="yes" state="normal" resize="both" style="attached_focused"/> <frame focus="no" state="normal" resize="both" style="attached_unfocused"/> <frame focus="yes" state="maximized" style="blank"/> <frame focus="no" state="maximized" style="blank"/> <frame focus="yes" state="shaded" style="blank"/> <frame focus="no" state="shaded" style="blank"/> <frame focus="yes" state="maximized_and_shaded" style="blank"/> <frame focus="no" state="maximized_and_shaded" style="blank"/> </frame_style_set> <!-- windows --> <window type="normal" style_set="normal_style_set"/> <window type="dialog" style_set="dialog_style_set"/> <window type="modal_dialog" style_set="modal_dialog_style_set"/> <window type="menu" style_set="utility_style_set"/> <window type="utility" style_set="utility_style_set"/> <window type="border" style_set="border_style_set"/> <window version=">= 3.2" type="attached" style_set="attached_style_set"/> </metacity_theme> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/data/Makefile.am�����������������������������������������������������������������������0000664�0001750�0001750�00000000122�14211404421�016074� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������themedir = $(pkgdatadir)/theme dist_theme_DATA = \ theme/metacity-theme-3.xml ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/autogen.sh�����������������������������������������������������������������������������0000775�0001750�0001750�00000002061�14211404421�015134� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # Run this to generate all the initial makefiles, etc. test -n "$srcdir" || srcdir=$(dirname "$0") test -n "$srcdir" || srcdir=. olddir=$(pwd) cd $srcdir (test -f configure.ac) || { echo "*** ERROR: Directory '$srcdir' does not look like the top-level project directory ***" exit 1 } # shellcheck disable=SC2016 PKG_NAME=$(autoconf --trace 'AC_INIT:$1' configure.ac) if [ "$#" = 0 -a "x$NOCONFIGURE" = "x" ]; then echo "*** WARNING: I am going to run 'configure' with no arguments." >&2 echo "*** If you wish to pass any to it, please specify them on the" >&2 echo "*** '$0' command line." >&2 echo "" >&2 fi mkdir -p m4 glib-gettextize --force --copy || exit 1 gtkdocize --copy || exit 1 intltoolize --force --copy --automake || exit 1 autoreconf --verbose --force --install || exit 1 cd "$olddir" if [ "$NOCONFIGURE" = "" ]; then $srcdir/configure "$@" || exit 1 if [ "$1" = "--help" ]; then exit 0 else echo "Now type 'make' to compile $PKG_NAME" || exit 1 fi else echo "Skipping configure process." fi �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/rationales.txt�������������������������������������������������������������������������0000664�0001750�0001750�00000005746�14211404421�016052� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� History ==== Focus issues: see doc/how-to-get-focus-right.txt Keep panel always on top: http://bugzilla.gnome.org/show_bug.cgi?id=81551 Edge flipping: http://bugzilla.gnome.org/show_bug.cgi?id=82917 Opaque resize: http://bugzilla.gnome.org/show_bug.cgi?id=92618 Alt+click to move/resize: http://bugzilla.gnome.org/show_bug.cgi?id=101151 https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=80918 minimized windows in Alt+tab: http://bugzilla.gnome.org/show_bug.cgi?id=89416 dialogs above entire app group: http://bugzilla.gnome.org/show_bug.cgi?id=88926 display window size/position: http://bugzilla.gnome.org/show_bug.cgi?id=85213 http://bugzilla.gnome.org/show_bug.cgi?id=106645 http://bugzilla.gnome.org/show_bug.cgi?id=130821 configure click actions, alt+click: http://bugzilla.gnome.org/show_bug.cgi?id=83210 system modal dialogs: http://bugzilla.gnome.org/show_bug.cgi?id=83357 workspace wrapping: http://bugzilla.gnome.org/show_bug.cgi?id=89315 raise windows on click: http://bugzilla.gnome.org/show_bug.cgi?id=326156 http://bugzilla.gnome.org/show_bug.cgi?id=86108 http://bugzilla.gnome.org/show_bug.cgi?id=115072 http://bugzilla.gnome.org/show_bug.cgi?id=115753 Pointer warping: http://bugzilla.gnome.org/show_bug.cgi?id=134353 http://bugzilla.gnome.org/show_bug.cgi?id=134352 (Think about tasklist & window selector too; this would be a very bad idea) Bugs for easy dupe-finding that seem to be hard to find otherwise: === Applications opening in wrong workspace: http://bugzilla.gnome.org/show_bug.cgi?id=160687 Tracking bugs ==== revise theme format: http://bugzilla.gnome.org/show_bug.cgi?id=102547 session management: http://bugzilla.gnome.org/show_bug.cgi?id=107063 focus-stealing-prevention: http://bugzilla.gnome.org/show_bug.cgi?id=149028 other focus bugs: http://bugzilla.gnome.org/show_bug.cgi?id=155450 drag-and-drop: http://bugzilla.gnome.org/show_bug.cgi?id=155451 raising/stacking: http://bugzilla.gnome.org/show_bug.cgi?id=155452 tasklist/workspace switcher: http://bugzilla.gnome.org/show_bug.cgi?id=155453 window/workspace selection: http://bugzilla.gnome.org/show_bug.cgi?id=155456 key/mouse-binding actions: http://bugzilla.gnome.org/show_bug.cgi?id=155457 moving/resizing (constraints): http://bugzilla.gnome.org/show_bug.cgi?id=155458 window placement: http://bugzilla.gnome.org/show_bug.cgi?id=155460 logout/system-monitor keys: http://bugzilla.gnome.org/show_bug.cgi?id=155462 modal dialogs: http://bugzilla.gnome.org/show_bug.cgi?id=164841 multi-head sans xinerama: http://bugzilla.gnome.org/show_bug.cgi?id=324772 xinerama: http://bugzilla.gnome.org/show_bug.cgi?id=324773 output-only windows: http://bugzilla.gnome.org/show_bug.cgi?id=340584 allowed actions/window-type: http://bugzilla.gnome.org/show_bug.cgi?id=340682 EWMH/ICCCM compliance: http://bugzilla.gnome.org/show_bug.cgi?id=340691 ��������������������������muffin-5.2.1/src/�����������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�013723� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/wm-tester/�������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�015652� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/wm-tester/Makefile.am��������������������������������������������������������������0000664�0001750�0001750�00000001143�14211404421�017705� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� AM_CPPFLAGS=$(WARN_CFLAGS) @MUFFIN_CFLAGS@ wm_tester_SOURCES= \ main.c test_gravity_SOURCES= \ test-gravity.c focus_window_SOURCES= \ focus-window.c test_resizing_SOURCES= \ test-resizing.c test_size_hints_SOURCES= \ test-size-hints.c test_attached_SOURCES= \ test-attached.c noinst_PROGRAMS=wm-tester test-gravity test-resizing focus-window test-size-hints test-attached wm_tester_LDADD= @MUFFIN_LIBS@ test_gravity_LDADD= @MUFFIN_LIBS@ test_resizing_LDADD= @MUFFIN_LIBS@ test_size_hints_LDADD= @MUFFIN_LIBS@ focus_window_LDADD= @MUFFIN_LIBS@ test_attached_LDADD= @MUFFIN_LIBS@ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/wm-tester/test-attached.c����������������������������������������������������������0000664�0001750�0001750�00000005571�14211404421�020560� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <gtk/gtk.h> enum { DESTROY_PARENT, DETACH, ATTACH_1, ATTACH_2 }; GtkWidget *window1, *window2; static void dialog_response (GtkDialog *dialog, int response, gpointer user_data) { if (response == DESTROY_PARENT) { GtkWidget *window = GTK_WIDGET (gtk_window_get_transient_for (GTK_WINDOW (dialog))); if (window == window1) { gtk_dialog_set_response_sensitive (dialog, ATTACH_1, FALSE); window1 = NULL; } else { gtk_dialog_set_response_sensitive (dialog, ATTACH_2, FALSE); window2 = NULL; } gtk_dialog_set_response_sensitive (dialog, DESTROY_PARENT, FALSE); gtk_dialog_set_response_sensitive (dialog, DETACH, FALSE); gtk_widget_destroy (window); } else if (response == DETACH) { gtk_window_set_transient_for (GTK_WINDOW (dialog), NULL); gtk_dialog_set_response_sensitive (dialog, DESTROY_PARENT, FALSE); gtk_dialog_set_response_sensitive (dialog, DETACH, FALSE); gtk_dialog_set_response_sensitive (dialog, ATTACH_1, window1 != NULL); gtk_dialog_set_response_sensitive (dialog, ATTACH_2, window2 != NULL); } else if (response == ATTACH_1) { gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window1)); gtk_dialog_set_response_sensitive (dialog, DESTROY_PARENT, TRUE); gtk_dialog_set_response_sensitive (dialog, DETACH, TRUE); gtk_dialog_set_response_sensitive (dialog, ATTACH_1, FALSE); gtk_dialog_set_response_sensitive (dialog, ATTACH_2, window2 != NULL); } else if (response == ATTACH_2) { gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window2)); gtk_dialog_set_response_sensitive (dialog, DESTROY_PARENT, TRUE); gtk_dialog_set_response_sensitive (dialog, DETACH, TRUE); gtk_dialog_set_response_sensitive (dialog, ATTACH_1, window1 != NULL); gtk_dialog_set_response_sensitive (dialog, ATTACH_2, FALSE); } else if (response == GTK_RESPONSE_CLOSE) gtk_main_quit (); } int main (int argc, char **argv) { GtkWidget *dialog; gtk_init (&argc, &argv); window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window1), "Parent 1"); gtk_widget_show (window1); window2 = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window2), "Parent 2"); gtk_widget_show (window2); dialog = gtk_dialog_new_with_buttons ("Child", NULL, GTK_DIALOG_MODAL, "Destroy Parent", DESTROY_PARENT, "Detach", DETACH, "Attach to 1", ATTACH_1, "Attach to 2", ATTACH_2, "Quit", GTK_RESPONSE_CLOSE, NULL); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), DESTROY_PARENT, FALSE); gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), DETACH, FALSE); g_signal_connect (dialog, "response", G_CALLBACK (dialog_response), NULL); gtk_widget_show (dialog); gtk_main (); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/wm-tester/test-gravity.c�����������������������������������������������������������0000664�0001750�0001750�00000017736�14211404421�020476� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdio.h> #include <string.h> static int gravities[10] = { NorthWestGravity, NorthGravity, NorthEastGravity, WestGravity, CenterGravity, EastGravity, SouthWestGravity, SouthGravity, SouthEastGravity, StaticGravity }; typedef struct { int x, y, width, height; } Rectangle; static Window windows[10]; static int doubled[10] = { 0, }; static Rectangle window_rects[10]; #define WINDOW_WIDTH 100 #define WINDOW_HEIGHT 100 static int x_offset[3] = { 0, - WINDOW_WIDTH/2, -WINDOW_WIDTH }; static int y_offset[3] = { 0, - WINDOW_HEIGHT/2, -WINDOW_HEIGHT }; static double screen_x_fraction[3] = { 0, 0.5, 1.0 }; static double screen_y_fraction[3] = { 0, 0.5, 1.0 }; static int screen_width; static int screen_height; static const char* window_gravity_to_string (int gravity) { switch (gravity) { case NorthWestGravity: return "NorthWestGravity"; case NorthGravity: return "NorthGravity"; case NorthEastGravity: return "NorthEastGravity"; case WestGravity: return "WestGravity"; case CenterGravity: return "CenterGravity"; case EastGravity: return "EastGravity"; case SouthWestGravity: return "SouthWestGravity"; case SouthGravity: return "SouthGravity"; case SouthEastGravity: return "SouthEastGravity"; case StaticGravity: return "StaticGravity"; default: return "NorthWestGravity"; } } static void calculate_position (int i, int doubled, int *x, int *y) { if (i == 9) { *x = 150; *y = 150; } else { int xoff = x_offset[i % 3]; int yoff = y_offset[i / 3]; if (doubled) { xoff *= 2; yoff *= 2; } *x = screen_x_fraction[i % 3] * screen_width + xoff; *y = screen_y_fraction[i / 3] * screen_height + yoff; } } static int find_window (Window window) { int i; for (i=0; i<10; i++) { if (windows[i] == window) return i; } return -1; } typedef struct { unsigned long flags; unsigned long functions; unsigned long decorations; long input_mode; unsigned long status; } MotifWmHints, MwmHints; #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) #define MWM_HINTS_STATUS (1L << 3) int main (int argc, char **argv) { Display *d; Window w; XSizeHints hints; int i; int screen; XEvent ev; int noframes; if (argc > 1 && strcmp (argv[1], "--noframes") == 0) noframes = 1; else noframes = 0; d = XOpenDisplay (NULL); screen = DefaultScreen (d); screen_width = DisplayWidth (d, screen); screen_height = DisplayHeight (d, screen); for (i=0; i<10; i++) { int x, y; calculate_position (i, doubled[i], &x, &y); w = XCreateSimpleWindow (d, RootWindow (d, screen), x, y, WINDOW_WIDTH, WINDOW_HEIGHT, 0, WhitePixel (d, screen), WhitePixel (d, screen)); windows[i] = w; window_rects[i].x = x; window_rects[i].y = y; window_rects[i].width = WINDOW_WIDTH; window_rects[i].height = WINDOW_HEIGHT; XSelectInput (d, w, ButtonPressMask | ExposureMask | StructureNotifyMask); hints.flags = USPosition | PMinSize | PMaxSize | PWinGravity; hints.min_width = WINDOW_WIDTH / 2; hints.min_height = WINDOW_HEIGHT / 2; #if 1 /* we constrain max size below the "doubled" size so that * the WM will have to deal with constraints * at the same time it's dealing with configure request */ hints.max_width = WINDOW_WIDTH * 2 - WINDOW_WIDTH / 2; hints.max_height = WINDOW_HEIGHT * 2 - WINDOW_HEIGHT / 2; #else hints.max_width = WINDOW_WIDTH * 2 + WINDOW_WIDTH / 2; hints.max_height = WINDOW_HEIGHT * 2 + WINDOW_HEIGHT / 2; #endif hints.win_gravity = gravities[i]; XSetWMNormalHints (d, w, &hints); XStoreName (d, w, window_gravity_to_string (hints.win_gravity)); if (noframes) { MotifWmHints mwm; Atom mwm_atom; mwm.decorations = 0; mwm.flags = MWM_HINTS_DECORATIONS; mwm_atom = XInternAtom (d, "_MOTIF_WM_HINTS", False); XChangeProperty (d, w, mwm_atom, mwm_atom, 32, PropModeReplace, (unsigned char *)&mwm, sizeof (MotifWmHints)/sizeof (long)); } XMapWindow (d, w); } while (1) { XNextEvent (d, &ev); if (ev.xany.type == ConfigureNotify) { i = find_window (ev.xconfigure.window); if (i >= 0) { Window ignored; window_rects[i].width = ev.xconfigure.width; window_rects[i].height = ev.xconfigure.height; XClearArea (d, windows[i], 0, 0, ev.xconfigure.width, ev.xconfigure.height, True); if (!ev.xconfigure.send_event) XTranslateCoordinates (d, windows[i], DefaultRootWindow (d), 0, 0, &window_rects[i].x, &window_rects[i].y, &ignored); else { window_rects[i].x = ev.xconfigure.x; window_rects[i].y = ev.xconfigure.y; } } } else if (ev.xany.type == Expose) { i = find_window (ev.xexpose.window); if (i >= 0) { GC gc; XGCValues values; char buf[256]; values.foreground = BlackPixel (d, screen); gc = XCreateGC (d, windows[i], GCForeground, &values); sprintf (buf, "%d,%d", window_rects[i].x, window_rects[i].y); XDrawString (d, windows[i], gc, 10, 15, buf, strlen (buf)); sprintf (buf, "%dx%d", window_rects[i].width, window_rects[i].height); XDrawString (d, windows[i], gc, 10, 35, buf, strlen (buf)); XFreeGC (d, gc); } } else if (ev.xany.type == ButtonPress) { i = find_window (ev.xbutton.window); if (i >= 0) { /* Button 1 = move, 2 = resize, 3 = both at once */ if (ev.xbutton.button == Button1) { int x, y; calculate_position (i, doubled[i], &x, &y); XMoveWindow (d, windows[i], x, y); } else if (ev.xbutton.button == Button2) { if (doubled[i]) XResizeWindow (d, windows[i], WINDOW_WIDTH, WINDOW_HEIGHT); else XResizeWindow (d, windows[i], WINDOW_WIDTH*2, WINDOW_HEIGHT*2); doubled[i] = !doubled[i]; } else if (ev.xbutton.button == Button3) { int x, y; calculate_position (i, !doubled[i], &x, &y); if (doubled[i]) XMoveResizeWindow (d, windows[i], x, y, WINDOW_WIDTH, WINDOW_HEIGHT); else XMoveResizeWindow (d, windows[i], x, y, WINDOW_WIDTH*2, WINDOW_HEIGHT*2); doubled[i] = !doubled[i]; } } } } /* This program has an infinite loop above so a return statement would * just cause compiler warnings. */ } ����������������������������������muffin-5.2.1/src/wm-tester/main.c�������������������������������������������������������������������0000664�0001750�0001750�00000013267�14211404421�016753� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* WM tester main() */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <gtk/gtk.h> #include <stdlib.h> #include <sys/types.h> #include <stdio.h> #include <string.h> #include <unistd.h> static void set_up_the_evil (void); static void set_up_icon_windows (void); static void usage (void) { g_print ("wm-tester [--evil] [--icon-windows]\n"); exit (0); } int main (int argc, char **argv) { int i; gboolean do_evil; gboolean do_icon_windows; gtk_init (&argc, &argv); do_evil = FALSE; do_icon_windows = FALSE; i = 1; while (i < argc) { const char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-h") == 0 || strcmp (arg, "-?") == 0) usage (); else if (strcmp (arg, "--evil") == 0) do_evil = TRUE; else if (strcmp (arg, "--icon-windows") == 0) do_icon_windows = TRUE; else usage (); ++i; } /* Be sure some option was provided */ if (! (do_evil || do_icon_windows)) return 1; if (do_evil) set_up_the_evil (); if (do_icon_windows) set_up_icon_windows (); gtk_main (); return 0; } static GSList *evil_windows = NULL; static gint evil_timeout (gpointer data) { int i; int n_windows; int len; int create_count; int destroy_count; len = g_slist_length (evil_windows); if (len > 35) { create_count = 2; destroy_count = 5; } else { create_count = 5; destroy_count = 5; } /* Create some windows */ n_windows = g_random_int_range (0, create_count); i = 0; while (i < n_windows) { GtkWidget *w; GtkWidget *c; int t; GtkWidget *parent; w = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_move (GTK_WINDOW (w), g_random_int_range (0, gdk_screen_width ()), g_random_int_range (0, gdk_screen_height ())); parent = NULL; /* set transient for random window (may create all kinds of weird cycles) */ if (len > 0) { t = g_random_int_range (- (len / 3), len); if (t >= 0) { parent = g_slist_nth_data (evil_windows, t); if (parent != NULL) gtk_window_set_transient_for (GTK_WINDOW (w), GTK_WINDOW (parent)); } } if (parent != NULL) c = gtk_button_new_with_label ("Evil Transient!"); else c = gtk_button_new_with_label ("Evil Window!"); gtk_container_add (GTK_CONTAINER (w), c); gtk_widget_show_all (w); evil_windows = g_slist_prepend (evil_windows, w); ++i; } /* Destroy some windows */ if (len > destroy_count) { n_windows = g_random_int_range (0, destroy_count); i = 0; while (i < n_windows) { GtkWidget *w; w = g_slist_nth_data (evil_windows, g_random_int_range (0, len)); if (w) { --len; evil_windows = g_slist_remove (evil_windows, w); gtk_widget_destroy (w); } ++i; } } return TRUE; } static void set_up_the_evil (void) { g_timeout_add (400, evil_timeout, NULL); } static void set_up_icon_windows (void) { int i; int n_windows; /* Create some windows */ n_windows = 9; i = 0; while (i < n_windows) { GtkWidget *w; GtkWidget *c; GList *icons; GtkIconTheme *theme; GdkPixbuf *pix; w = gtk_window_new (GTK_WINDOW_TOPLEVEL); c = gtk_button_new_with_label ("Icon window"); gtk_container_add (GTK_CONTAINER (w), c); theme = gtk_icon_theme_get_default (); icons = NULL; pix = gtk_icon_theme_load_icon (theme, "document-save", 24, 0, NULL); icons = g_list_append (icons, pix); if (i % 2) { pix = gtk_icon_theme_load_icon (theme, "document-save", 48, 0, NULL); icons = g_list_append (icons, pix); } if (i % 3) { pix = gtk_icon_theme_load_icon (theme, "document-save", 16, 0, NULL); icons = g_list_append (icons, pix); } gtk_window_set_icon_list (GTK_WINDOW (w), icons); g_list_foreach (icons, (GFunc) g_object_unref, NULL); g_list_free (icons); gtk_widget_show_all (w); ++i; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/wm-tester/focus-window.c�����������������������������������������������������������0000664�0001750�0001750�00000001170�14211404421�020441� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char **argv) { Display *d; Window w; const char *w_str; char *end; if (argc != 2) { fprintf (stderr, "Usage: focus-window WINDOWID\n"); exit (1); } d = XOpenDisplay (NULL); w_str = argv[1]; end = NULL; w = strtoul (w_str, &end, 16); if (end == w_str) { fprintf (stderr, "Usage: focus-window WINDOWID\n"); exit (1); } printf ("Setting input focus to 0x%lx\n", w); XSetInputFocus (d, w, RevertToPointerRoot, CurrentTime); XFlush (d); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/wm-tester/test-resizing.c����������������������������������������������������������0000664�0001750�0001750�00000013322�14211404421�020626� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdlib.h> #include <glib.h> static void calc_rects (XRectangle *rects, int width, int height) { int w = (width - 21) / 3; int h = (height - 21) / 3; int i; i = 0; while (i < 9) { rects[i].width = w; rects[i].height = h; ++i; } /* NW */ rects[0].x = 0; rects[0].y = 0; /* N */ rects[1].x = width / 2 - w / 2; rects[1].y = 0; /* NE */ rects[2].x = width - w; rects[2].y = 0; /* E */ rects[3].x = width - w; rects[3].y = height / 2 - h / 2; /* SE */ rects[4].x = width - w; rects[4].y = height - h; /* S */ rects[5].x = width / 2 - w / 2; rects[5].y = height - h; /* SW */ rects[6].x = 0; rects[6].y = height - h; /* W */ rects[7].x = 0; rects[7].y = height / 2 - h / 2; /* Center */ rects[8].x = width / 2 - w / 2; rects[8].y = height / 2 - h / 2; } static Bool all_events (Display *display, XEvent *event, XPointer arg) { return True; } static void get_size (Display *d, Drawable draw, int *xp, int *yp, int *widthp, int *heightp) { int x, y; unsigned int width=0, height=0, border=0, depth=0; Window root; XGetGeometry (d, draw, &root, &x, &y, &width, &height, &border, &depth); if (xp) *xp = x; if (yp) *yp = y; if (widthp) *widthp = width; if (heightp) *heightp = height; } int main (int argc, char **argv) { Display *d; Window w, cw; XSizeHints hints; int screen; XEvent ev; int x, y, width, height; Pixmap pix; GC gc; XGCValues gc_vals; XSetWindowAttributes set_attrs; XWindowChanges changes; XRectangle rects[9]; gboolean redraw_pending; unsigned int mask; d = XOpenDisplay (NULL); screen = DefaultScreen (d); /* Print some debug spew to show how StaticGravity works */ w = XCreateSimpleWindow (d, RootWindow (d, screen), 0, 0, 100, 100, 0, WhitePixel (d, screen), WhitePixel (d, screen)); cw = XCreateSimpleWindow (d, w, 0, 0, 100, 100, 0, WhitePixel (d, screen), WhitePixel (d, screen)); set_attrs.win_gravity = StaticGravity; XChangeWindowAttributes (d, cw, CWWinGravity, &set_attrs); get_size (d, w, &x, &y, &width, &height); g_print ("Parent is %d,%d %d x %d before configuring parent\n", x, y, width, height); get_size (d, cw, &x, &y, &width, &height); g_print ("Child is %d,%d %d x %d before configuring parent\n", x, y, width, height); changes.x = 10; changes.y = 10; changes.width = 110; changes.height = 110; /* last mask wins */ mask = CWX | CWY; mask = CWWidth | CWHeight; mask = CWX | CWY | CWWidth | CWHeight; XConfigureWindow (d, w, mask, &changes); XSync (d, False); get_size (d, w, &x, &y, &width, &height); g_print ("Parent is %d,%d %d x %d after configuring parent\n", x, y, width, height); get_size (d, cw, &x, &y, &width, &height); g_print ("Child is %d,%d %d x %d after configuring parent\n", x, y, width, height); XDestroyWindow (d, w); /* The window that gets displayed */ x = 20; y = 20; width = 100; height = 100; calc_rects (rects, width, height); w = XCreateSimpleWindow (d, RootWindow (d, screen), x, y, width, height, 0, WhitePixel (d, screen), WhitePixel (d, screen)); set_attrs.bit_gravity = StaticGravity; XChangeWindowAttributes (d, w, CWBitGravity, &set_attrs); XSelectInput (d, w, ButtonPressMask | ExposureMask | StructureNotifyMask); hints.flags = PMinSize; hints.min_width = 100; hints.min_height = 100; XSetWMNormalHints (d, w, &hints); XMapWindow (d, w); redraw_pending = FALSE; while (1) { XNextEvent (d, &ev); switch (ev.xany.type) { case ButtonPress: if (ev.xbutton.button == 3) { g_print ("Exiting on button 3 press\n"); exit (0); } break; case ConfigureNotify: x = ev.xconfigure.x; y = ev.xconfigure.y; width = ev.xconfigure.width; height = ev.xconfigure.height; redraw_pending = TRUE; break; case Expose: redraw_pending = TRUE; break; default: break; } /* Primitive event compression */ if (XCheckIfEvent (d, &ev, all_events, NULL)) { XPutBackEvent (d, &ev); } else if (redraw_pending) { calc_rects (rects, width, height); pix = XCreatePixmap (d, w, width, height, DefaultDepth (d, screen)); gc_vals.foreground = WhitePixel (d, screen); gc = XCreateGC (d, pix, GCForeground, &gc_vals); XFillRectangle (d, pix, gc, 0, 0, width, height); /* Draw rectangles at each gravity point */ gc_vals.foreground = BlackPixel (d, screen); XChangeGC (d, gc, GCForeground, &gc_vals); XFillRectangles (d, pix, gc, rects, G_N_ELEMENTS (rects)); XCopyArea (d, pix, w, gc, 0, 0, width, height, 0, 0); XFreePixmap (d, pix); XFreeGC (d, gc); redraw_pending = FALSE; } } /* This program has an infinite loop above so a return statement would * just cause compiler warnings. */ } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/wm-tester/test-size-hints.c��������������������������������������������������������0000664�0001750�0001750�00000005631�14211404421�021075� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdlib.h> #include <glib.h> static Bool all_events (Display *display, XEvent *event, XPointer arg) { return True; } #if 0 static void get_size (Display *d, Drawable draw, int *xp, int *yp, int *widthp, int *heightp) { int x, y; unsigned int width, height, border, depth; Window root; XGetGeometry (d, draw, &root, &x, &y, &width, &height, &border, &depth); if (xp) *xp = x; if (yp) *yp = y; if (widthp) *widthp = width; if (*heightp) *heightp = height; } #endif int main (int argc, char **argv) { Display *d; Window zero_min_size; XSizeHints hints; int screen; XEvent ev; int x, y, width, height; Pixmap pix; GC gc; XGCValues gc_vals; gboolean redraw_pending; d = XOpenDisplay (NULL); screen = DefaultScreen (d); x = 0; y = 0; width = 100; height = 100; zero_min_size = XCreateSimpleWindow (d, RootWindow (d, screen), x, y, width, height, 0, WhitePixel (d, screen), WhitePixel (d, screen)); XSelectInput (d, zero_min_size, ButtonPressMask | ExposureMask | StructureNotifyMask); hints.flags = PMinSize; hints.min_width = 0; hints.min_height = 0; XSetWMNormalHints (d, zero_min_size, &hints); XMapWindow (d, zero_min_size); redraw_pending = FALSE; while (1) { XNextEvent (d, &ev); switch (ev.xany.type) { case ButtonPress: if (ev.xbutton.button == 1) { g_print ("Exiting on button 1 press\n"); exit (0); } break; case ConfigureNotify: x = ev.xconfigure.x; y = ev.xconfigure.y; width = ev.xconfigure.width; height = ev.xconfigure.height; redraw_pending = TRUE; break; case Expose: redraw_pending = TRUE; break; default: break; } /* Primitive event compression */ if (XCheckIfEvent (d, &ev, all_events, NULL)) { XPutBackEvent (d, &ev); } else if (redraw_pending) { pix = XCreatePixmap (d, zero_min_size, width, height, DefaultDepth (d, screen)); gc_vals.foreground = WhitePixel (d, screen); gc = XCreateGC (d, pix, GCForeground, &gc_vals); XFillRectangle (d, pix, gc, 0, 0, width, height); XCopyArea (d, pix, zero_min_size, gc, 0, 0, width, height, 0, 0); XFreePixmap (d, pix); XFreeGC (d, gc); redraw_pending = FALSE; } } /* This program has an infinite loop above so a return statement would * just cause compiler warnings. */ } �������������������������������������������������������������������������������������������������������muffin-5.2.1/src/muffin.desktop.in������������������������������������������������������������������0000664�0001750�0001750�00000000720�14211404421�017206� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Desktop Entry] Type=Application _Name=Muffin Exec=muffin NoDisplay=true # name of loadable control center module X-GNOME-WMSettingsModule=metacity # name we put on the WM spec check window X-GNOME-WMName=Muffin # back compat only X-GnomeWMSettingsLibrary=metacity X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=muffin X-GNOME-Bugzilla-Component=general X-GNOME-Autostart-Phase=WindowManager X-GNOME-Provides=windowmanager X-GNOME-Autostart-Notify=true ������������������������������������������������muffin-5.2.1/src/stock_minimize.png�����������������������������������������������������������������0000664�0001750�0001750�00000000221�14211404421�017450� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������a���bKGD������ pHYs�� �� ~���tIME 9���IDATxc``0�F4R1Q ������IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/muffin-plugins.pc.in���������������������������������������������������������������0000664�0001750�0001750�00000001445�14211404421�017623� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ plugindir=@MUFFIN_PLUGIN_DIR@ libgnome_serverdir=@libexecdir@ muffin_major_version=@MUFFIN_MAJOR_VERSION@ muffin_minor_version=@MUFFIN_MINOR_VERSION@ muffin_micro_version=@MUFFIN_MICRO_VERSION@ muffin_plugin_api_version=@MUFFIN_PLUGIN_API_VERSION@ Name: muffin-plugins Description: Dev parameters for muffin plugins Requires: muffin-clutter-@MUFFIN_PLUGIN_API_VERSION@ Version: @VERSION@ Libs: @CLUTTER_LIBS@ Cflags: @CLUTTER_CFLAGS@ -DWITH_CLUTTER -I${includedir}/muffin/muffin-private -DMUFFIN_MAJOR_VERSION=${muffin_major_version} -DMUFFIN_MINOR_VERSION=${muffin_minor_version} -DMUFFIN_MICRO_VERSION=${muffin_micro_version} -DMUFFIN_PLUGIN_API_VERSION=${muffin_plugin_api_version} -DMUFFIN_PLUGIN_DIR=\"${plugindir}\" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/Makefile.am������������������������������������������������������������������������0000664�0001750�0001750�00000027546�14211404421�015775� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Flag build for parallelism; see https://savannah.gnu.org/patch/?6905 .AUTOPARALLEL: lib_LTLIBRARIES = libmuffin.la SUBDIRS=wm-tester tools NULL = AM_CPPFLAGS= \ -DCLUTTER_ENABLE_COMPOSITOR_API \ -DCLUTTER_ENABLE_EXPERIMENTAL_API \ -DCOGL_ENABLE_EXPERIMENTAL_API \ -DCOGL_ENABLE_EXPERIMENTAL_2_0_API \ -DCOGL_ENABLE_MUFFIN_API \ $(WARN_CFLAGS) \ $(MUFFIN_CFLAGS) \ -I$(srcdir) \ -I$(srcdir)/core \ -I$(srcdir)/ui \ -I$(srcdir)/compositor \ -I$(top_srcdir)/cogl \ -I$(top_srcdir)/cogl/cogl \ -I$(top_srcdir)/cogl/cogl/winsys \ -I$(top_builddir)/cogl/cogl \ -I$(top_builddir)/cogl \ -I$(top_srcdir)/clutter \ -I$(top_srcdir)/clutter/clutter \ -I$(top_builddir)/clutter \ -I$(top_builddir)/clutter/clutter \ -DMUFFIN_LIBEXECDIR=\"$(libexecdir)\" \ -DHOST_ALIAS=\"@HOST_ALIAS@\" \ -DMUFFIN_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" \ -DMUFFIN_PKGDATADIR=\"$(pkgdatadir)\" \ -DMUFFIN_DATADIR=\"$(datadir)\" \ -DG_LOG_DOMAIN=\"muffin\" \ -DSN_API_NOT_YET_FROZEN=1 \ -DMUFFIN_MAJOR_VERSION=$(MUFFIN_MAJOR_VERSION) \ -DMUFFIN_MINOR_VERSION=$(MUFFIN_MINOR_VERSION) \ -DMUFFIN_MICRO_VERSION=$(MUFFIN_MICRO_VERSION) \ -DMUFFIN_PLUGIN_API_VERSION=$(MUFFIN_PLUGIN_API_VERSION) \ -DMUFFIN_PKGLIBDIR=\"$(pkglibdir)\" \ -DMUFFIN_PLUGIN_DIR=\"@MUFFIN_PLUGIN_DIR@\" \ -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" muffin_built_sources = \ muffin-enum-types.h \ muffin-enum-types.c libmuffin_la_SOURCES = \ core/async-getprop.c \ core/async-getprop.h \ core/bell.c \ core/bell.h \ core/boxes.c \ core/boxes-private.h \ meta/boxes.h \ compositor/clutter-utils.c \ compositor/clutter-utils.h \ compositor/cogl-utils.c \ compositor/cogl-utils.h \ compositor/compositor.c \ compositor/compositor-private.h \ compositor/meta-background.c \ compositor/meta-background.h \ compositor/meta-background-actor.c \ compositor/meta-background-actor-private.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-private.h \ compositor/meta-sync-ring.c \ compositor/meta-sync-ring.h \ compositor/meta-texture-rectangle.c \ compositor/meta-texture-rectangle.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-background-actor.h \ meta/meta-plugin.h \ meta/meta-shadow-factory.h \ meta/meta-window-actor.h \ meta/compositor-muffin.h \ core/above-tab-keycode.c \ core/constraints.c \ core/constraints.h \ core/core.c \ core/delete.c \ core/display.c \ core/display-private.h \ meta/display.h \ ui/draw-workspace.c \ ui/draw-workspace.h \ core/edge-resistance.c \ core/edge-resistance.h \ core/errors.c \ meta/errors.h \ core/eventqueue.c \ core/eventqueue.h \ core/frame.c \ core/frame.h \ ui/gradient.c \ meta/gradient.h \ core/group-private.h \ core/group-props.c \ core/group-props.h \ core/group.c \ meta/group.h \ core/iconcache.c \ core/iconcache.h \ core/keybindings.c \ core/keybindings-private.h \ core/main.c \ core/muffin-Xatomtype.h \ core/place.c \ core/place.h \ core/prefs.c \ meta/prefs.h \ core/screen.c \ core/screen-private.h \ meta/screen.h \ meta/types.h \ core/session.c \ core/session.h \ core/restart.c \ core/stack.c \ core/stack.h \ core/stack-tracker.c \ core/stack-tracker.h \ core/util.c \ meta/util.h \ meta/util-private.h \ core/window-props.c \ core/window-props.h \ core/window.c \ core/window-private.h \ meta/window.h \ core/workspace.c \ core/workspace-private.h \ core/xprops.c \ core/xprops.h \ meta/common.h \ core/core.h \ ui/ui.h \ inlinepixbufs.h \ ui/frames.c \ ui/frames.h \ ui/menu.c \ ui/menu.h \ ui/metaaccellabel.c \ ui/metaaccellabel.h \ ui/resizepopup.c \ ui/resizepopup.h \ ui/theme-parser.c \ ui/theme.c \ meta/theme.h \ ui/theme-private.h \ ui/ui.c \ meta/preview-widget.h \ ui/preview-widget.c \ $(muffin_built_sources) \ $(NULL) libmuffin_la_LDFLAGS = $(WARN_LDFLAGS) -no-undefined -export-symbols-regex "^(meta|ag)_.*" libmuffin_la_LIBADD = \ $(MUFFIN_LIBS) \ $(top_builddir)/clutter/clutter/libmuffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).la \ $(top_builddir)/cogl/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la \ $(top_builddir)/cogl/cogl-pango/libmuffin-cogl-pango-$(MUFFIN_PLUGIN_API_VERSION).la \ $(top_builddir)/cogl/cogl-path/libmuffin-cogl-path-$(MUFFIN_PLUGIN_API_VERSION).la \ -lm \ -lglib-2.0 \ $(NULL) # Headers installed for plugins; introspected information will # be extracted into Muffin-<version>.gir libmuffininclude_base_headers = \ meta/boxes.h \ meta/common.h \ meta/compositor-muffin.h \ meta/compositor.h \ meta/display.h \ meta/errors.h \ meta/gradient.h \ meta/group.h \ meta/keybindings.h \ meta/main.h \ meta/meta-background-actor.h \ meta/meta-plugin.h \ meta/meta-shaped-texture.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 # Excluded from scanning for introspection but installed # atomnames.h: macros cause problems for scanning process libmuffininclude_extra_headers = \ meta/preview-widget.h \ meta/atomnames.h libmuffinincludedir = $(includedir)/muffin/meta libmuffininclude_HEADERS = \ $(libmuffininclude_base_headers) \ $(libmuffininclude_extra_headers) muffin_theme_viewer_SOURCES= \ ui/theme-viewer.c bin_PROGRAMS=muffin muffin-theme-viewer muffin_SOURCES = core/muffin.c muffin_LDADD = $(MUFFIN_LIBS) libmuffin.la libexec_PROGRAMS = muffin-restart-helper muffin_restart_helper_SOURCES = core/restart-helper.c muffin_restart_helper_LDADD = $(MUFFIN_LIBS) if HAVE_INTROSPECTION include $(INTROSPECTION_MAKEFILE) # Since we don't make any guarantees about stability and we don't support # parallel install, there's no real reason to change directories, filenames, # etc. as we change the Muffin tarball version. # # Change the api_version to a muffin specific number since setting it to # 3.0 causes major dependency issues with muffin on distributions which # auto generate typelib dependencies in RPMS api_version = Muffin.0 #api_version = 3.0 # 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. girdir = $(pkglibdir) gir_DATA = Meta-$(api_version).gir typelibdir = $(pkglibdir) typelib_DATA = Meta-$(api_version).typelib INTROSPECTION_GIRS = Meta-$(api_version).gir INTROSPECTION_SCANNER_ARGS = \ --add-include-path=$(top_builddir)/clutter/clutter \ --add-include-path=$(top_builddir)/cogl/cogl \ --add-include-path=$(top_builddir)/cogl/cogl-pango \ --add-include-path=$(top_builddir)/cogl/cogl-path \ $(NULL) INTROSPECTION_COMPILER_ARGS = \ --includedir=$(top_builddir)/clutter/clutter \ --includedir=$(top_builddir)/cogl/cogl \ --includedir=$(top_builddir)/cogl/cogl-pango \ --includedir=$(top_builddir)/cogl/cogl-path \ $(NULL) INTROSPECTION_SCANNER_ENV = \ PKG_CONFIG_PATH=$(top_builddir)/clutter/clutter/:$(top_builddir)/cogl/cogl/:$(top_builddir)/cogl/cogl-pango/:$(top_builddir)/cogl/cogl-path/:$${PKG_CONFIG_PATH} Meta-$(api_version).gir: libmuffin.la @META_GIR@_INCLUDES = GObject-2.0 CDesktopEnums-3.0 Gdk-3.0 Gtk-3.0 Cogl-$(MUFFIN_PLUGIN_API_VERSION) Clutter-$(MUFFIN_PLUGIN_API_VERSION) xlib-2.0 xfixes-4.0 @META_GIR@_PACKAGES = gtk+-3.0 @META_GIR@_CFLAGS = $(AM_CPPFLAGS) @META_GIR@_LIBS = \ libmuffin.la \ $(top_builddir)/clutter/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/cogl/cogl/libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/cogl/cogl-pango/libmuffin-cogl-pango-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/cogl/cogl-path/libmuffin-cogl-path-@MUFFIN_PLUGIN_API_VERSION@.la @META_GIR@_FILES = \ muffin-enum-types.h \ $(libmuffininclude_base_headers) \ $(filter %.c,$(libmuffin_la_SOURCES)) @META_GIR@_SCANNERFLAGS = $(WARN_SCANNERFLAGS) --warn-all --warn-error --identifier-prefix=Meta endif muffin_theme_viewer_LDADD= $(MUFFIN_LIBS) libmuffin.la testboxes_SOURCES = core/testboxes.c core/boxes.c core/util.c testgradient_SOURCES = ui/testgradient.c testasyncgetprop_SOURCES = core/testasyncgetprop.c core/async-getprop.c # NO-OP: work around the fact that source code tested by the programs are # compiled for library testasyncgetprop_CFLAGS = $(WARN_CFLAGS) $(AM_CFLAGS) testboxes_CFLAGS = $(WARN_CFLAGS) $(AM_CFLAGS) noinst_PROGRAMS=testboxes testgradient testasyncgetprop testboxes_LDADD = $(MUFFIN_LIBS) $(top_builddir)/clutter/clutter/libmuffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).la testgradient_LDADD = $(MUFFIN_LIBS) libmuffin.la testasyncgetprop_LDADD = $(MUFFIN_LIBS) @INTLTOOL_DESKTOP_RULE@ desktopfilesdir=$(datadir)/applications desktopfiles_in_files=muffin.desktop.in desktopfiles_files=$(desktopfiles_in_files:.desktop.in=.desktop) desktopfiles_DATA = $(desktopfiles_files) gsettings_SCHEMAS = org.cinnamon.muffin.gschema.xml @INTLTOOL_XML_NOMERGE_RULE@ @GSETTINGS_RULES@ IMAGES=stock_maximize.png stock_minimize.png stock_delete.png VARIABLES=stock_maximize_data $(srcdir)/stock_maximize.png \ stock_minimize_data $(srcdir)/stock_minimize.png \ stock_delete_data $(srcdir)/stock_delete.png BUILT_SOURCES = inlinepixbufs.h CLEANFILES = \ inlinepixbufs.h \ muffin.desktop \ org.cinnamon.muffin.gschema.xml \ $(xml_DATA) \ $(muffin_built_sources) \ $(typelib_DATA) \ $(gir_DATA) inlinepixbufs.h: $(IMAGES) $(GDK_PIXBUF_CSOURCE) --raw --build-list $(VARIABLES) >$(srcdir)/inlinepixbufs.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libmuffin.pc muffin-plugins.pc EXTRA_DIST=$(desktopfiles_files) \ $(IMAGES) \ $(desktopfiles_in_files) \ $(xml_in_files) \ org.cinnamon.muffin.gschema.xml.in \ libmuffin.pc.in \ muffin-plugins.pc.in \ muffin-enum-types.h.in \ muffin-enum-types.c.in BUILT_SOURCES += $(muffin_built_sources) MUFFIN_STAMP_FILES = stamp-muffin-enum-types.h CLEANFILES += $(MUFFIN_STAMP_FILES) muffin-enum-types.h: stamp-muffin-enum-types.h Makefile @true stamp-muffin-enum-types.h: $(libmuffininclude_base_headers) muffin-enum-types.h.in $(AM_V_GEN) ( cd $(srcdir) && \ $(GLIB_MKENUMS) \ --template muffin-enum-types.h.in \ $(libmuffininclude_base_headers) ) >> xgen-teth && \ (cmp -s xgen-teth muffin-enum-types.h || cp xgen-teth muffin-enum-types.h) && \ rm -f xgen-teth && \ echo timestamp > $(@F) muffin-enum-types.c: stamp-muffin-enum-types.h muffin-enum-types.c.in $(AM_V_GEN) ( cd $(srcdir) && \ $(GLIB_MKENUMS) \ --template muffin-enum-types.c.in \ $(libmuffininclude_base_headers) ) >> xgen-tetc && \ cp xgen-tetc muffin-enum-types.c && \ rm -f xgen-tetc compat_libs="clutter cogl cogl-pango cogl-path" install-exec-local: test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" for lib in `echo $(compat_libs)`; do \ (cd $(DESTDIR)$(libdir) && \ rm -f libmuffin-$$lib-0.so; \ ) ; \ (cd $(DESTDIR)$(libdir) && \ { ln -s -f muffin/libmuffin-$$lib-0.so libmuffin-$$lib-0.so || \ { rm -f libmuffin-$$lib-0.so && ln -s muffin/libmuffin-$$lib-0.so libmuffin-$$lib-0.so; }; \ } \ ) ; \ done ����������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/stock_delete.png�������������������������������������������������������������������0000664�0001750�0001750�00000000334�14211404421�017076� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������a���bKGD������ pHYs�� �� ����tIME,���tEXtComment�Created with The GIMPd%n���@IDAT8c`v?-τG!1b 2i�o0\`UDi RH#�S9 ����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/muffin.desktop.desktop�������������������������������������������������������������0000664�0001750�0001750�00000000753�14211404421�020257� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� [Desktop Entry] Type=Application Name=Muffin Exec=muffin NoDisplay=true # name of loadable control center module X-GNOME-WMSettingsModule=metacity # name we put on the WM spec check window X-GNOME-WMName=Muffin # back compat only X-GnomeWMSettingsLibrary=metacity X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=muffin X-GNOME-Bugzilla-Component=general X-GNOME-Autostart-Phase=WindowManager X-GNOME-Provides=windowmanager X-GNOME-Autostart-Notify=true Name[en_US]=muffin.desktop ���������������������muffin-5.2.1/src/compositor/������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�016121� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-shadow-factory.c���������������������������������������������������0000664�0001750�0001750�00000105527�14211404421�022155� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:meta-shadow-factory * @title: MetaShadowFactory * @short_description: Create and cache shadow textures for arbitrary window shapes */ #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; CoglTexture *texture; CoglPipeline *pipeline; /* 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; }; /* The first element in this array also defines the default parameters * for newly created classes */ static MetaShadowClassInfo default_shadow_classes[] = { { "normal", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, { "dialog", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, { "modal_dialog", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, { "utility", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, { "border", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, { "menu", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } }, { "popup-menu", { 1, -1, 0, 0, 128 }, { 1, -1, 0, 0, 128 } }, { "dropdown-menu", { 1, -1, 0, 0, 128 }, { 1, -1, 0, 0, 128 } }, { "attached", { 10, -1, 0, 3, 128 }, { 8, -1, 0, 2, 64 } } }; 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)); } LOCAL_SYMBOL MetaShadow * meta_shadow_ref (MetaShadow *shadow) { shadow->ref_count++; return shadow; } LOCAL_SYMBOL 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_object_unref (shadow->texture); cogl_object_unref (shadow->pipeline); 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. * @clip_strictly: if %TRUE, drawing will be clipped strictly * to @clip, otherwise, it will be only used to optimize * drawing. * * 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.) */ LOCAL_SYMBOL void meta_shadow_paint (MetaShadow *shadow, CoglFramebuffer *framebuffer, int window_x, int window_y, int window_width, int window_height, guint8 opacity, cairo_region_t *clip, gboolean clip_strictly) { 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; gboolean source_updated = FALSE; 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]; if (dest_rect.height == 0) continue; 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 (dest_rect.width == 0) continue; if (clip) overlap = cairo_region_contains_rectangle (clip, &dest_rect); else overlap = CAIRO_REGION_OVERLAP_IN; if (overlap == CAIRO_REGION_OVERLAP_OUT) continue; if (!source_updated) { cogl_pipeline_set_color4ub (shadow->pipeline, opacity, opacity, opacity, opacity); // cogl_set_source (shadow->pipeline); do not believe needed, but still there in mutter source_updated = TRUE; } /* There's quite a bit of overhead from allocating a new * region in order to find an exact intersection and * generating more geometry - we make the assumption that * unless we have to clip strictly it will be cheaper to * just draw the entire rectangle. */ if (overlap == CAIRO_REGION_OVERLAP_IN || (overlap == CAIRO_REGION_OVERLAP_PART && !clip_strictly)) { cogl_framebuffer_draw_textured_rectangle (framebuffer, shadow->pipeline, 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]); } else if (overlap == CAIRO_REGION_OVERLAP_PART) { cairo_region_t *intersection; int n_rectangles, k; float *rects; intersection = cairo_region_create_rectangle (&dest_rect); cairo_region_intersect (intersection, clip); n_rectangles = cairo_region_num_rectangles (intersection); rects = g_alloca (sizeof (float) * 8 * n_rectangles); for (k = 0; k < n_rectangles; k++) { cairo_rectangle_int_t rect; float src_x1, src_x2, src_y1, src_y2; int pos; cairo_region_get_rectangle (intersection, k, &rect); /* Separately linear interpolate X and Y coordinates in the source * based on the destination X and Y coordinates */ src_x1 = (src_x[i] * (dest_rect.x + dest_rect.width - rect.x) + src_x[i + 1] * (rect.x - dest_rect.x)) / dest_rect.width; src_x2 = (src_x[i] * (dest_rect.x + dest_rect.width - (rect.x + rect.width)) + src_x[i + 1] * (rect.x + rect.width - dest_rect.x)) / dest_rect.width; src_y1 = (src_y[j] * (dest_rect.y + dest_rect.height - rect.y) + src_y[j + 1] * (rect.y - dest_rect.y)) / dest_rect.height; src_y2 = (src_y[j] * (dest_rect.y + dest_rect.height - (rect.y + rect.height)) + src_y[j + 1] * (rect.y + rect.height - dest_rect.y)) / dest_rect.height; pos = k*8; rects[pos] = rect.x; rects[pos+1] = rect.y; rects[pos+2] = rect.x + rect.width; rects[pos+3] = rect.y + rect.height; rects[pos+4] = src_x1; rects[pos+5] = src_y1; rects[pos+6] = src_x2; rects[pos+7] = src_y2; } cogl_framebuffer_draw_textured_rectangles (framebuffer, shadow->pipeline, rects, n_rectangles); cairo_region_destroy (intersection); } } } } /** * 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_paint() */ LOCAL_SYMBOL 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_y - 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) { 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; } LOCAL_SYMBOL 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 = 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); } } } 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 = 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]; } 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 = calloc (1, 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 = meta_cogl_texture_new_from_data_wrapper (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); free (buffer); shadow->pipeline = meta_create_texture_pipeline (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() */ LOCAL_SYMBOL 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; meta_compositor_on_shadow_factory_changed (); } /** * 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; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-shaped-texture-private.h�������������������������������������������0000664�0001750�0001750�00000002345�14211404421�023634� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * shaped texture * * An actor to draw a texture clipped to a list of rectangles * * Authored By Neil Roberts <neil@linux.intel.com> * * Copyright (C) 2008 Intel Corporation * 2013 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef __META_SHAPED_TEXTURE_PRIVATE_H__ #define __META_SHAPED_TEXTURE_PRIVATE_H__ #include <meta/meta-shaped-texture.h> ClutterActor *meta_shaped_texture_new (void); void meta_shaped_texture_set_texture (MetaShapedTexture *stex, CoglTexture *texture); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-texture-rectangle.h������������������������������������������������0000664�0001750�0001750�00000002174�14211404421�022664� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * texture rectangle * * A small utility function to help create a rectangle texture * * Authored By Neil Roberts <neil@linux.intel.com> * * Copyright (C) 2011 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __META_TEXTURE_RECTANGLE_H__ #define __META_TEXTURE_RECTANGLE_H__ #include <cogl/cogl.h> G_BEGIN_DECLS gboolean meta_texture_rectangle_check (CoglTexture *texture); G_END_DECLS #endif /* __META_TEXTURE_RECTANGLE_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/plugins/����������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�017602� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/plugins/Makefile.am�����������������������������������������������������0000664�0001750�0001750�00000003275�14211404421�021645� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� pkglibdir=@MUFFIN_PLUGIN_DIR@ AM_CPPFLAGS= \ $(WARN_CFLAGS) \ $(MUFFIN_CFLAGS) \ -I$(top_builddir)/src \ -I$(top_srcdir)/src \ -I$(top_srcdir)/cogl \ -I$(top_builddir)/cogl \ -I$(top_builddir)/cogl/cogl \ -I$(top_srcdir)/clutter \ -I$(top_builddir)/clutter \ -I$(top_builddir)/clutter/clutter \ -DMUFFIN_LIBEXECDIR=\"$(libexecdir)\" \ -DHOST_ALIAS=\"@HOST_ALIAS@\" \ -DMUFFIN_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" \ -DMUFFIN_PKGDATADIR=\"$(pkgdatadir)\" -DMUFFIN_DATADIR=\"$(datadir)\" \ -DG_LOG_DOMAIN=\"muffin\" \ -DSN_API_NOT_YET_FROZEN=1 \ -DMUFFIN_MAJOR_VERSION=$(MUFFIN_MAJOR_VERSION) \ -DMUFFIN_MINOR_VERSION=$(MUFFIN_MINOR_VERSION) \ -DMUFFIN_MICRO_VERSION=$(MUFFIN_MICRO_VERSION) \ -DMUFFIN_PLUGIN_API_VERSION=$(MUFFIN_PLUGIN_API_VERSION) \ -DMUFFIN_PLUGIN_DIR=\"@MUFFIN_PLUGIN_DIR@\" default_la_CFLAGS = $(WARN_CFLAGS) -fPIC default_la_SOURCES = default.c default_la_LDFLAGS = $(WARN_LDFLAGS) -module -avoid-version -no-undefined default_la_LIBADD = \ $(CLUTTER_LIBS) \ $(top_builddir)/src/libmuffin.la \ $(top_builddir)/clutter/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la 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 libmuffin-private.so). install-exec-hook: -rm $(DESTDIR)$(pkglibdir)/*.a -rm $(DESTDIR)$(pkglibdir)/*.la # Since we removed the .la file, 'make uninstall' doesn't work properly, # since it counts on libtool to remove the .la files, so just kill the # .so file manually. uninstall-local: -rm -f $(DESTDIR)$(pkglibdir)/default.so �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/plugins/default.c�������������������������������������������������������0000664�0001750�0001750�00000056710�14211404421�021403� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <meta/meta-plugin.h> #include <meta/window.h> #include <meta/util.h> #include <glib/gi18n-lib.h> #include <clutter/clutter.h> #include <gmodule.h> #include <string.h> #define DESTROY_TIMEOUT 250 #define MINIMIZE_TIMEOUT 250 #define MAXIMIZE_TIMEOUT 250 #define MAP_TIMEOUT 250 #define SWITCH_TIMEOUT 500 #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 META_DEFAULT_PLUGIN_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPluginPrivate)) typedef struct _MetaDefaultPlugin MetaDefaultPlugin; typedef struct _MetaDefaultPluginClass MetaDefaultPluginClass; typedef struct _MetaDefaultPluginPrivate MetaDefaultPluginPrivate; struct _MetaDefaultPlugin { MetaPlugin parent; MetaDefaultPluginPrivate *priv; }; struct _MetaDefaultPluginClass { MetaPluginClass 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 switch_workspace (MetaPlugin *plugin, gint from, gint to, MetaMotionDirection direction); static void kill_window_effects (MetaPlugin *plugin, MetaWindowActor *actor); static const MetaPluginInfo * plugin_info (MetaPlugin *plugin); META_PLUGIN_DECLARE(MetaDefaultPlugin, meta_default_plugin); /* * Plugin private data that we store in the .plugin_private member. */ struct _MetaDefaultPluginPrivate { /* Valid only when switch_workspace effect is in progress */ ClutterTimeline *tml_switch_workspace1; ClutterTimeline *tml_switch_workspace2; ClutterActor *desktop1; ClutterActor *desktop2; MetaPluginInfo info; gboolean debug_mode : 1; }; /* * Per actor private data we attach to each actor. */ typedef struct _ActorPrivate { ClutterActor *orig_parent; ClutterTimeline *tml_minimize; ClutterTimeline *tml_maximize; ClutterTimeline *tml_destroy; ClutterTimeline *tml_map; gboolean is_minimized : 1; gboolean is_maximized : 1; } ActorPrivate; /* callback data for when animations complete */ typedef struct { ClutterActor *actor; MetaPlugin *plugin; } EffectCompleteData; static void meta_default_plugin_dispose (GObject *object) { /* MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (object)->priv; */ G_OBJECT_CLASS (meta_default_plugin_parent_class)->dispose (object); } static void meta_default_plugin_finalize (GObject *object) { G_OBJECT_CLASS (meta_default_plugin_parent_class)->finalize (object); } static void meta_default_plugin_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_default_plugin_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void start (MetaPlugin *plugin) { MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; if (meta_plugin_debug_mode (plugin)) { g_debug ("Plugin %s: Entering debug mode.", priv->info.name); priv->debug_mode = TRUE; } } static void meta_default_plugin_class_init (MetaDefaultPluginClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); MetaPluginClass *plugin_class = META_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; 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->plugin_info = plugin_info; plugin_class->kill_window_effects = kill_window_effects; g_type_class_add_private (gobject_class, sizeof (MetaDefaultPluginPrivate)); } static void meta_default_plugin_init (MetaDefaultPlugin *self) { MetaDefaultPluginPrivate *priv; self->priv = priv = META_DEFAULT_PLUGIN_GET_PRIVATE (self); priv->info.name = "Default Effects"; priv->info.version = "0.1"; priv->info.author = "Intel Corp."; priv->info.license = "GPL"; priv->info.description = "This is an example of a plugin implementation."; } /* * Actor private data accessor */ static void free_actor_private (gpointer data) { if (G_LIKELY (data != NULL)) g_slice_free (ActorPrivate, data); } static ActorPrivate * get_actor_private (MetaWindowActor *actor) { ActorPrivate *priv = g_object_get_qdata (G_OBJECT (actor), actor_data_quark); if (G_UNLIKELY (actor_data_quark == 0)) actor_data_quark = g_quark_from_static_string (ACTOR_DATA_KEY); if (G_UNLIKELY (!priv)) { priv = g_slice_new0 (ActorPrivate); g_object_set_qdata_full (G_OBJECT (actor), actor_data_quark, priv, free_actor_private); } return priv; } static void on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data) { MetaPlugin *plugin = META_PLUGIN (data); MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; MetaScreen *screen = meta_plugin_get_screen (plugin); GList *l = meta_get_window_actors (screen); while (l) { ClutterActor *a = l->data; MetaWindowActor *window_actor = META_WINDOW_ACTOR (a); ActorPrivate *apriv = get_actor_private (window_actor); if (apriv->orig_parent) { clutter_actor_reparent (a, apriv->orig_parent); apriv->orig_parent = NULL; } l = l->next; } clutter_actor_destroy (priv->desktop1); clutter_actor_destroy (priv->desktop2); priv->tml_switch_workspace1 = NULL; priv->tml_switch_workspace2 = NULL; priv->desktop1 = NULL; priv->desktop2 = NULL; meta_plugin_switch_workspace_completed (plugin); } static void switch_workspace (MetaPlugin *plugin, gint from, gint to, MetaMotionDirection direction) { MetaScreen *screen; MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; GList *l; ClutterActor *workspace0 = clutter_group_new (); ClutterActor *workspace1 = clutter_group_new (); ClutterActor *stage; int screen_width, screen_height; ClutterAnimation *animation; 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); } screen = meta_plugin_get_screen (plugin); stage = meta_get_stage_for_screen (screen); meta_screen_get_size (screen, &screen_width, &screen_height); clutter_actor_set_anchor_point (workspace1, screen_width, screen_height); clutter_actor_set_position (workspace1, screen_width, screen_height); clutter_actor_set_scale (workspace1, 0.0, 0.0); clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace1); clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace0); if (from == to) { meta_plugin_switch_workspace_completed (plugin); return; } l = g_list_last (meta_get_window_actors (screen)); while (l) { MetaWindowActor *window_actor = l->data; ActorPrivate *apriv = get_actor_private (window_actor); ClutterActor *actor = CLUTTER_ACTOR (window_actor); gint win_workspace; win_workspace = meta_window_actor_get_workspace (window_actor); if (win_workspace == to || win_workspace == from) { apriv->orig_parent = clutter_actor_get_parent (actor); clutter_actor_reparent (actor, win_workspace == to ? workspace1 : workspace0); clutter_actor_show_all (actor); clutter_actor_raise_top (actor); } else if (win_workspace < 0) { /* Sticky window */ apriv->orig_parent = NULL; } else { /* Window on some other desktop */ clutter_actor_hide (actor); apriv->orig_parent = NULL; } l = l->prev; } priv->desktop1 = workspace0; priv->desktop2 = workspace1; animation = clutter_actor_animate (workspace0, CLUTTER_EASE_IN_SINE, SWITCH_TIMEOUT, "scale-x", 1.0, "scale-y", 1.0, NULL); priv->tml_switch_workspace1 = clutter_animation_get_timeline (animation); g_signal_connect (priv->tml_switch_workspace1, "completed", G_CALLBACK (on_switch_workspace_effect_complete), plugin); animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE, SWITCH_TIMEOUT, "scale-x", 0.0, "scale-y", 0.0, NULL); priv->tml_switch_workspace2 = clutter_animation_get_timeline (animation); } /* * Minimize effect completion callback; this function restores actor state, and * calls the manager callback function. */ static void 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; ActorPrivate *apriv; MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor); apriv = get_actor_private (META_WINDOW_ACTOR (data->actor)); apriv->tml_minimize = NULL; clutter_actor_hide (data->actor); /* FIXME - we shouldn't assume the original scale, it should be saved * at the start of the effect */ clutter_actor_set_scale (data->actor, 1.0, 1.0); clutter_actor_move_anchor_point_from_gravity (data->actor, CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ meta_plugin_minimize_completed (plugin, window_actor); free (data); } /* * Simple minimize handler: it applies a scale effect (which must be reversed on * completion). */ static void minimize (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; MetaRectangle icon_geometry; MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); ClutterActor *actor = CLUTTER_ACTOR (window_actor); type = meta_window_get_window_type (meta_window); if (!meta_window_get_icon_geometry(meta_window, &icon_geometry)) { icon_geometry.x = 0; icon_geometry.y = 0; } if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); apriv->is_minimized = TRUE; clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MINIMIZE_TIMEOUT, "scale-x", 0.0, "scale-y", 0.0, "x", icon_geometry.x, "y", icon_geometry.y, NULL); apriv->tml_minimize = clutter_animation_get_timeline (animation); data->plugin = plugin; data->actor = actor; g_signal_connect (apriv->tml_minimize, "completed", G_CALLBACK (on_minimize_effect_complete), data); } else meta_plugin_minimize_completed (plugin, window_actor); } /* * Minimize effect completion callback; this function restores actor state, and * calls the manager callback function. */ static void 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); apriv->tml_maximize = NULL; /* FIXME - don't assume the original scale was 1.0 */ clutter_actor_set_scale (data->actor, 1.0, 1.0); clutter_actor_move_anchor_point_from_gravity (data->actor, CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ meta_plugin_maximize_completed (plugin, window_actor); free (data); } /* * The Nature of Maximize operation is such that it is difficult to do a visual * effect that would work well. Scaling, the obvious effect, does not work that * well, because at the end of the effect we end up with window content bigger * and differently laid out than in the real window; this is a proof concept. * * (Something like a sound would be more appropriate.) */ static void maximize (MetaPlugin *plugin, MetaWindowActor *window_actor, 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); 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); if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); gfloat width, height; gfloat x, y; apriv->is_maximized = TRUE; clutter_actor_get_size (actor, &width, &height); clutter_actor_get_position (actor, &x, &y); /* * Work out the scale and anchor point so that the window is expanding * smoothly into the target size. */ scale_x = (gdouble)end_width / (gdouble) width; scale_y = (gdouble)end_height / (gdouble) height; anchor_x = (gdouble)(x - end_x)*(gdouble)width / ((gdouble)(end_width - width)); anchor_y = (gdouble)(y - end_y)*(gdouble)height / ((gdouble)(end_height - height)); clutter_actor_move_anchor_point (actor, anchor_x, anchor_y); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MAXIMIZE_TIMEOUT, "scale-x", scale_x, "scale-y", scale_y, NULL); apriv->tml_maximize = clutter_animation_get_timeline (animation); data->plugin = plugin; data->actor = actor; g_signal_connect (apriv->tml_maximize, "completed", G_CALLBACK (on_maximize_effect_complete), data); return; } meta_plugin_maximize_completed (plugin, window_actor); } /* * See comments on the maximize() function. * * (Just a skeleton code.) */ static void unmaximize (MetaPlugin *plugin, MetaWindowActor *window_actor, 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); if (type == META_WINDOW_NORMAL) { ActorPrivate *apriv = get_actor_private (window_actor); apriv->is_maximized = FALSE; } /* Do this conditionally, if the effect requires completion callback. */ meta_plugin_unmaximize_completed (plugin, window_actor); } static void 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); apriv->tml_map = NULL; clutter_actor_move_anchor_point_from_gravity (data->actor, CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ meta_plugin_map_completed (plugin, window_actor); free (data); } /* * Simple map handler: it applies a scale effect which must be reversed on * completion). */ static void map (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); type = meta_window_get_window_type (meta_window); if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); clutter_actor_set_scale (actor, 0.0, 0.0); clutter_actor_show (actor); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MAP_TIMEOUT, "scale-x", 1.0, "scale-y", 1.0, NULL); apriv->tml_map = clutter_animation_get_timeline (animation); data->actor = actor; data->plugin = plugin; g_signal_connect (apriv->tml_map, "completed", G_CALLBACK (on_map_effect_complete), data); apriv->is_minimized = FALSE; } else meta_plugin_map_completed (plugin, window_actor); } /* * Destroy effect completion callback; this is a simple effect that requires no * further action than notifying the manager that the effect is completed. */ 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); apriv->tml_destroy = NULL; meta_plugin_destroy_completed (plugin, window_actor); } /* * Simple TV-out like effect. */ static void destroy (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); type = meta_window_get_window_type (meta_window); if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, DESTROY_TIMEOUT, "scale-x", 0.0, "scale-y", 1.0, NULL); apriv->tml_destroy = clutter_animation_get_timeline (animation); data->plugin = plugin; data->actor = actor; g_signal_connect (apriv->tml_destroy, "completed", G_CALLBACK (on_destroy_effect_complete), data); } else meta_plugin_destroy_completed (plugin, window_actor); } static void kill_window_effects (MetaPlugin *plugin, MetaWindowActor *window_actor) { ActorPrivate *apriv; apriv = get_actor_private (window_actor); if (apriv->tml_minimize) { clutter_timeline_stop (apriv->tml_minimize); g_signal_emit_by_name (apriv->tml_minimize, "completed", NULL); } if (apriv->tml_maximize) { clutter_timeline_stop (apriv->tml_maximize); g_signal_emit_by_name (apriv->tml_maximize, "completed", NULL); } if (apriv->tml_map) { clutter_timeline_stop (apriv->tml_map); g_signal_emit_by_name (apriv->tml_map, "completed", NULL); } if (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) { MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; return &priv->info; } ��������������������������������������������������������muffin-5.2.1/src/compositor/meta-background.h�������������������������������������������������������0000664�0001750�0001750�00000003240�14211404421�021334� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ #ifndef META_BACKGROUND_H #define META_BACKGROUND_H #include <clutter/clutter.h> #include <meta/screen.h> #define META_TYPE_BACKGROUND (meta_background_get_type ()) #define META_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND, MetaBackground)) #define META_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND, MetaBackgroundClass)) #define META_IS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND)) #define META_IS_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND)) #define META_BACKGROUND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND, MetaBackgroundClass)) typedef struct _MetaBackground MetaBackground; typedef struct _MetaBackgroundClass MetaBackgroundClass; typedef struct _MetaBackgroundPrivate MetaBackgroundPrivate; struct _MetaBackgroundClass { ClutterActorClass parent_class; }; struct _MetaBackground { ClutterActor parent; MetaBackgroundPrivate *priv; }; GType meta_background_get_type (void); ClutterActor * meta_background_new (MetaScreen *screen); void meta_background_set_layer (MetaBackground *self, CoglTexture *texture); void meta_background_set_layer_wrap_mode (MetaBackground *self, CoglPipelineWrapMode wrap_mode); void meta_background_set_visible_region (MetaBackground *self, cairo_region_t *visible_region); #endif /* META_BACKGROUND_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-background.c�������������������������������������������������������0000664�0001750�0001750�00000017316�14211404421�021340� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * meta-background.c: Actor used to create a background fade effect * * Copyright 2016 Linux Mint * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Portions adapted from gnome-shell/src/shell-global.c * and meta-window-actor.c */ #include "config.h" #include <clutter/clutter.h> #include "cogl-utils.h" #include <meta/errors.h> // #include "util-private.h" #include "meta-background-actor-private.h" struct _MetaBackgroundPrivate { MetaScreen *screen; CoglPipeline *pipeline; float texture_width; float texture_height; cairo_region_t *visible_region; }; G_DEFINE_TYPE (MetaBackground, meta_background, CLUTTER_TYPE_ACTOR); static void meta_background_dispose (GObject *object) { MetaBackground *self = META_BACKGROUND (object); MetaBackgroundPrivate *priv = self->priv; meta_background_set_visible_region (self, NULL); if (priv->pipeline != NULL) { cogl_object_unref (priv->pipeline); priv->pipeline = NULL; } G_OBJECT_CLASS (meta_background_parent_class)->dispose (object); } static void meta_background_get_preferred_width (ClutterActor *actor, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { MetaBackground *self = META_BACKGROUND (actor); MetaBackgroundPrivate *priv = self->priv; int width, height; meta_screen_get_size (priv->screen, &width, &height); if (min_width_p) *min_width_p = width; if (natural_width_p) *natural_width_p = width; } static void meta_background_get_preferred_height (ClutterActor *actor, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { MetaBackground *self = META_BACKGROUND (actor); MetaBackgroundPrivate *priv = self->priv; int width, height; meta_screen_get_size (priv->screen, &width, &height); if (min_height_p) *min_height_p = height; if (natural_height_p) *natural_height_p = height; } static void meta_background_paint (ClutterActor *actor) { MetaBackground *self = META_BACKGROUND (actor); MetaBackgroundPrivate *priv = self->priv; guint8 opacity = clutter_actor_get_paint_opacity (actor); guint8 color_component; int width, height; meta_screen_get_size (priv->screen, &width, &height); color_component = (int)(0.5 + opacity); cogl_pipeline_set_color4ub (priv->pipeline, color_component, color_component, color_component, opacity); cogl_set_source (priv->pipeline); if (priv->visible_region) { int n_rectangles = cairo_region_num_rectangles (priv->visible_region); int i; for (i = 0; i < n_rectangles; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (priv->visible_region, i, &rect); cogl_rectangle_with_texture_coords (rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, rect.x / priv->texture_width, rect.y / priv->texture_height, (rect.x + rect.width) / priv->texture_width, (rect.y + rect.height) / priv->texture_height); } } else { cogl_rectangle_with_texture_coords (0.0f, 0.0f, width, height, 0.0f, 0.0f, width / priv->texture_width, height / priv->texture_height); } } static gboolean meta_background_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { return clutter_paint_volume_set_from_allocation (volume, actor); } static void meta_background_class_init (MetaBackgroundClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); g_type_class_add_private (klass, sizeof (MetaBackgroundPrivate)); object_class->dispose = meta_background_dispose; actor_class->get_preferred_width = meta_background_get_preferred_width; actor_class->get_preferred_height = meta_background_get_preferred_height; actor_class->get_paint_volume = meta_background_get_paint_volume; actor_class->paint = meta_background_paint; } static void meta_background_init (MetaBackground *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, META_TYPE_BACKGROUND, MetaBackgroundPrivate); } ClutterActor * meta_background_new (MetaScreen *screen) { MetaBackground *self; MetaBackgroundPrivate *priv; self = g_object_new (META_TYPE_BACKGROUND, NULL); priv = self->priv; priv->screen = screen; priv->pipeline = meta_create_texture_pipeline (NULL); return CLUTTER_ACTOR (self); } void meta_background_set_layer (MetaBackground *self, CoglTexture *texture) { MetaBackgroundPrivate *priv = self->priv; MetaDisplay *display = meta_screen_get_display (priv->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_pipeline_set_layer_texture (priv->pipeline, 0, texture); meta_error_trap_pop (display); priv->texture_width = cogl_texture_get_width (texture); priv->texture_height = cogl_texture_get_height (texture); clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); } void meta_background_set_layer_wrap_mode (MetaBackground *self, CoglPipelineWrapMode wrap_mode) { MetaBackgroundPrivate *priv = self->priv; cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, wrap_mode); } void meta_background_set_visible_region (MetaBackground *self, cairo_region_t *visible_region) { MetaBackgroundPrivate *priv; g_return_if_fail (META_IS_BACKGROUND (self)); priv = self->priv; if (priv->visible_region) { cairo_region_destroy (priv->visible_region); priv->visible_region = NULL; } if (visible_region) { cairo_rectangle_int_t screen_rect = { 0 }; meta_screen_get_size (priv->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. */ priv->visible_region = cairo_region_create_rectangle (&screen_rect); cairo_region_intersect (priv->visible_region, visible_region); } }������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-texture-tower.h����������������������������������������������������0000664�0001750�0001750�00000005564�14211404421�022066� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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, CoglTexture *texture); void meta_texture_tower_update_area (MetaTextureTower *tower, int x, int y, int width, int height); CoglTexture *meta_texture_tower_get_paint_texture (MetaTextureTower *tower); G_BEGIN_DECLS #endif /* __META_TEXTURE_TOWER_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-plugin-manager.c���������������������������������������������������0000664�0001750�0001750�00000030146�14211404421�022123� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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 GType plugin_type = G_TYPE_NONE; struct MetaPluginManager { MetaScreen *screen; MetaPlugin *plugin; }; void meta_plugin_manager_set_plugin_type (GType gtype) { if (plugin_type != G_TYPE_NONE) meta_fatal ("Muffin plugin already set: %s", g_type_name (plugin_type)); plugin_type = gtype; } /* * Loads the given plugin. */ void meta_plugin_manager_load (const gchar *plugin_name) { const gchar *dpath = MUFFIN_PLUGIN_DIR "/"; gchar *path; MetaModule *module; 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); } meta_plugin_manager_set_plugin_type (meta_module_get_plugin_type (module)); g_type_module_unuse (G_TYPE_MODULE (module)); free (path); } MetaPluginManager * meta_plugin_manager_new (MetaScreen *screen) { MetaPluginManager *plugin_mgr; MetaPluginClass *klass; MetaPlugin *plugin; plugin_mgr = g_new0 (MetaPluginManager, 1); plugin_mgr->screen = screen; plugin_mgr->plugin = plugin = g_object_new (plugin_type, "screen", screen, NULL); klass = META_PLUGIN_GET_CLASS (plugin); if (klass->start) klass->start(plugin); return plugin_mgr; } static void meta_plugin_manager_kill_window_effects (MetaPluginManager *plugin_mgr, MetaWindowActor *actor) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); if (klass->kill_window_effects) klass->kill_window_effects (plugin, actor); } /* * Public method that the compositor hooks into for events that require * no additional parameters. * * Returns TRUE if the plugin handled the event type (i.e., * if the return value is FALSE, there will be no subsequent call to the * manager completed() callback, and the compositor must ensure that any * appropriate post-effect cleanup is carried out. */ LOCAL_SYMBOL gboolean meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, MetaWindowActor *actor, unsigned long event) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); gboolean retval = FALSE; if (display->display_opening) return FALSE; switch (event) { case META_PLUGIN_MINIMIZE: if (klass->minimize) { retval = TRUE; 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) { retval = TRUE; 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) { retval = TRUE; _meta_plugin_effect_started (plugin); klass->destroy (plugin, actor); } break; default: g_warning ("Incorrect handler called for event %lu", event); } return retval; } /* * The public method that the compositor hooks into for maximize and unmaximize * events. * * Returns TRUE if the plugin handled the event type (i.e., * if the return value is FALSE, there will be no subsequent call to the * manager completed() callback, and the compositor must ensure that any * appropriate post-effect cleanup is carried out. */ LOCAL_SYMBOL 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) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); gboolean retval = FALSE; if (display->display_opening) return FALSE; switch (event) { case META_PLUGIN_MAXIMIZE: if (klass->maximize) { retval = TRUE; 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) { retval = TRUE; 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; case META_PLUGIN_TILE: if (klass->tile) { retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); _meta_plugin_effect_started (plugin); klass->tile (plugin, actor, target_x, target_y, target_width, target_height); } break; default: g_warning ("Incorrect handler called for event %lu", event); } return retval; } /* * The public method that the compositor hooks into for desktop switching. * * Returns TRUE if the plugin handled the event type (i.e., * if the return value is FALSE, there will be no subsequent call to the * manager completed() callback, and the compositor must ensure that any * appropriate post-effect cleanup is carried out. */ LOCAL_SYMBOL gboolean meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr, gint from, gint to, MetaMotionDirection direction) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); gboolean retval = FALSE; if (display->display_opening) return FALSE; if (klass->switch_workspace) { retval = TRUE; _meta_plugin_effect_started (plugin); klass->switch_workspace (plugin, from, to, direction); } return retval; } /* * The public method that the compositor hooks into for desktop switching. * * Returns TRUE if the plugin handled the event type (i.e., * if the return value is FALSE, there will be no subsequent call to the * manager completed() callback, and the compositor must ensure that any * appropriate post-effect cleanup is carried out. */ LOCAL_SYMBOL gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr, XEvent *xev) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); if (!plugin_mgr) return FALSE; /* We need to make sure that clutter gets certain events, like * ConfigureNotify on the stage window. If there is a plugin that * provides an xevent_filter function, then it's the responsibility * of that plugin to pass events to Clutter. Otherwise, we send the * event directly to Clutter ourselves. */ if (klass->xevent_filter) return klass->xevent_filter (plugin, xev); else return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE; } gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number, guint snap_queued) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); if (display->display_opening) return FALSE; if (klass->show_tile_preview) { klass->show_tile_preview (plugin, window, tile_rect, tile_monitor_number, snap_queued); return TRUE; } return FALSE; } gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); if (display->display_opening) return FALSE; if (klass->hide_tile_preview) { klass->hide_tile_preview (plugin); return TRUE; } return FALSE; } gboolean meta_plugin_manager_show_hud_preview (MetaPluginManager *plugin_mgr, guint current_proximity_zone, MetaRectangle *work_area, guint snap_queued) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); if (display->display_opening) return FALSE; if (klass->show_hud_preview) { klass->show_hud_preview (plugin, current_proximity_zone, work_area, snap_queued); return TRUE; } return FALSE; } gboolean meta_plugin_manager_hide_hud_preview (MetaPluginManager *plugin_mgr) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); if (display->display_opening) return FALSE; if (klass->hide_hud_preview) { klass->hide_hud_preview (plugin); return TRUE; } return FALSE; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-shaped-texture.c���������������������������������������������������0000664�0001750�0001750�00000101533�14211404421�022156� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:meta-shaped-texture * @title: MetaShapedTexture * @short_description: An actor to draw a masked texture. */ #include <config.h> #include <meta/meta-shaped-texture.h> #include "clutter-utils.h" #include "meta-texture-tower.h" #include "meta-texture-rectangle.h" #include "meta-shaped-texture-private.h" #include "cogl-utils.h" #include <clutter/clutter.h> #include <cogl/cogl.h> #include <cogl/winsys/cogl-texture-pixmap-x11.h> #include <gdk/gdk.h> /* for gdk_rectangle_intersect() */ #include <string.h> /* MAX_MIPMAPPING_FPS needs to be as small as possible for the best GPU * performance, but higher than the refresh rate of commonly slow updating * windows like top or a blinking cursor, so that such windows do get * mipmapped. */ #define MAX_MIPMAPPING_FPS 5 #define MIN_MIPMAP_AGE_USEC (G_USEC_PER_SEC / MAX_MIPMAPPING_FPS) /* MIN_FAST_UPDATES_BEFORE_UNMIPMAP allows windows to update themselves * occasionally without causing mipmapping to be disabled, so long as such * an update takes fewer update_area calls than: */ #define MIN_FAST_UPDATES_BEFORE_UNMIPMAP 20 static void meta_shaped_texture_dispose (GObject *object); static void meta_shaped_texture_paint (ClutterActor *actor); static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p); static void meta_shaped_texture_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p); static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume); G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture, CLUTTER_TYPE_ACTOR); #define META_SHAPED_TEXTURE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \ MetaShapedTexturePrivate)) enum { SIZE_CHANGED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; struct _MetaShapedTexturePrivate { MetaTextureTower *paint_tower; Pixmap pixmap; CoglTexture *texture; CoglTexture *mask_texture; cairo_region_t *clip_region; cairo_region_t *unobscured_region; cairo_region_t *opaque_region; cairo_region_t *overlay_region; cairo_path_t *overlay_path; guint tex_width, tex_height; gint64 prev_invalidation, last_invalidation; guint fast_updates; guint remipmap_timeout_id; gint64 earliest_remipmap; guint create_mipmaps : 1; guint mask_needs_update : 1; }; static void meta_shaped_texture_class_init (MetaShapedTextureClass *klass) { GObjectClass *gobject_class = (GObjectClass *) klass; ClutterActorClass *actor_class = (ClutterActorClass *) klass; gobject_class->dispose = meta_shaped_texture_dispose; actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width; actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height; actor_class->paint = meta_shaped_texture_paint; actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume; signals[SIZE_CHANGED] = g_signal_new ("size-changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); 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->overlay_path = NULL; priv->overlay_region = NULL; priv->paint_tower = meta_texture_tower_new (); priv->texture = NULL; priv->mask_texture = NULL; priv->create_mipmaps = TRUE; priv->mask_needs_update = TRUE; } static void meta_shaped_texture_dispose (GObject *object) { MetaShapedTexture *self = (MetaShapedTexture *) object; MetaShapedTexturePrivate *priv = self->priv; if (priv->remipmap_timeout_id) { g_source_remove (priv->remipmap_timeout_id); priv->remipmap_timeout_id = 0; } if (priv->paint_tower) meta_texture_tower_free (priv->paint_tower); priv->paint_tower = NULL; meta_shaped_texture_dirty_mask (self); g_clear_pointer (&priv->texture, cogl_object_unref); g_clear_pointer (&priv->opaque_region, cairo_region_destroy); meta_shaped_texture_set_clip_region (self, NULL); meta_shaped_texture_set_overlay_path (self, NULL, NULL); G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object); } static CoglPipeline * get_base_pipeline (CoglContext *ctx) { static CoglPipeline *template = NULL; if (G_UNLIKELY (template == NULL)) { template = cogl_pipeline_new (ctx); cogl_pipeline_set_layer_wrap_mode_s (template, 0, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); cogl_pipeline_set_layer_wrap_mode_t (template, 0, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); cogl_pipeline_set_layer_wrap_mode_s (template, 1, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); cogl_pipeline_set_layer_wrap_mode_t (template, 1, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); } return template; } static CoglPipeline * get_unmasked_pipeline (CoglContext *ctx) { return get_base_pipeline (ctx); } static CoglPipeline * get_masked_pipeline (CoglContext *ctx) { static CoglPipeline *template = NULL; if (G_UNLIKELY (template == NULL)) { template = cogl_pipeline_copy (get_base_pipeline (ctx)); cogl_pipeline_set_layer_combine (template, 1, "RGBA = MODULATE (PREVIOUS, TEXTURE[A])", NULL); } return template; } static CoglPipeline * get_unblended_pipeline (CoglContext *ctx) { static CoglPipeline *template = NULL; if (G_UNLIKELY (template == NULL)) { template = cogl_pipeline_copy (get_base_pipeline (ctx)); cogl_pipeline_set_layer_combine (template, 0, "RGBA = REPLACE (TEXTURE)", NULL); } return template; } static void paint_clipped_rectangle (CoglFramebuffer *fb, CoglPipeline *pipeline, cairo_rectangle_int_t *rect, ClutterActorBox *alloc) { float coords[8]; float x1, y1, x2, y2; x1 = rect->x; y1 = rect->y; x2 = rect->x + rect->width; y2 = rect->y + rect->height; coords[0] = rect->x / (alloc->x2 - alloc->x1); coords[1] = rect->y / (alloc->y2 - alloc->y1); coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1); coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1); coords[4] = coords[0]; coords[5] = coords[1]; coords[6] = coords[2]; coords[7] = coords[3]; cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline, x1, y1, x2, y2, &coords[0], 8); } LOCAL_SYMBOL void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex) { MetaShapedTexturePrivate *priv = stex->priv; g_clear_pointer (&priv->mask_texture, cogl_object_unref); } static void install_overlay_path (MetaShapedTexture *stex, guchar *mask_data, int tex_width, int tex_height, int stride) { MetaShapedTexturePrivate *priv = stex->priv; int i, n_rects; cairo_t *cr; cairo_rectangle_int_t rect; cairo_surface_t *surface; if (priv->overlay_region == NULL) return; surface = cairo_image_surface_create_for_data (mask_data, CAIRO_FORMAT_A8, tex_width, tex_height, stride); cr = cairo_create (surface); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); n_rects = cairo_region_num_rectangles (priv->overlay_region); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (priv->overlay_region, i, &rect); cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height); } cairo_fill_preserve (cr); if (priv->overlay_path == NULL) { /* If we have an overlay region but not an overlay path, then we * just need to clear the rectangles in the overlay region. */ goto out; } cairo_clip (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr, 1, 1, 1, 1); cairo_append_path (cr, priv->overlay_path); cairo_fill (cr); out: cairo_destroy (cr); cairo_surface_destroy (surface); } LOCAL_SYMBOL void meta_shaped_texture_ensure_mask (MetaShapedTexture *stex, cairo_region_t *shape_region, gboolean has_frame) { MetaShapedTexturePrivate *priv = stex->priv; CoglTexture *paint_tex; guint tex_width, tex_height; paint_tex = priv->texture; if (paint_tex == NULL) 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 != NULL && priv->mask_needs_update) { priv->mask_needs_update = FALSE; meta_shaped_texture_dirty_mask (stex); } /* If we don't have a mask texture yet then create one */ if (priv->mask_texture == NULL) { guchar *mask_data; int i; int n_rects; int stride; /* If we have no shape region and no (or an empty) overlay region, we * don't need to create a full mask texture, so quit early. */ if (shape_region == NULL && (priv->overlay_region == NULL || cairo_region_num_rectangles (priv->overlay_region) == 0)) { return; } if (shape_region == NULL) return; n_rects = cairo_region_num_rectangles (shape_region); if (n_rects == 0) return; stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width); /* Create data for an empty image */ mask_data = g_malloc0 (stride * tex_height); /* Fill in each rectangle. */ for (i = 0; i < n_rects; i ++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (shape_region, i, &rect); 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 * stride + x1; y1 < y2; y1++, p += stride) memset (p, 255, x2 - x1); } if (has_frame) install_overlay_path (stex, mask_data, tex_width, tex_height, stride); if (meta_texture_rectangle_check (paint_tex)) priv->mask_texture = meta_cogl_rectangle_new (tex_width, tex_height, COGL_PIXEL_FORMAT_A_8, stride, mask_data); else priv->mask_texture = meta_cogl_texture_new_from_data_wrapper (tex_width, tex_height, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_A_8, COGL_PIXEL_FORMAT_ANY, stride, mask_data); g_free (mask_data); } } static gboolean texture_is_idle_and_not_mipmapped (gpointer user_data) { MetaShapedTexture *stex = META_SHAPED_TEXTURE (user_data); MetaShapedTexturePrivate *priv = stex->priv; if ((g_get_monotonic_time () - priv->earliest_remipmap) < 0) return G_SOURCE_CONTINUE; clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); priv->remipmap_timeout_id = 0; return G_SOURCE_REMOVE; } static void meta_shaped_texture_paint (ClutterActor *actor) { MetaShapedTexture *stex = (MetaShapedTexture *) actor; MetaShapedTexturePrivate *priv = stex->priv; guint tex_width, tex_height; guchar opacity; CoglContext *ctx; CoglFramebuffer *fb; CoglTexture *paint_tex = NULL; ClutterActorBox alloc; CoglPipelineFilter filter; gint64 now = g_get_monotonic_time (); 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 && priv->last_invalidation) { gint64 age = now - priv->last_invalidation; if (age >= MIN_MIPMAP_AGE_USEC || priv->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP) paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower); } if (paint_tex == NULL) { paint_tex = COGL_TEXTURE (priv->texture); if (paint_tex == NULL) return; if (priv->create_mipmaps) { /* Minus 1000 to ensure we don't fail the age test in timeout */ priv->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000; if (!priv->remipmap_timeout_id) priv->remipmap_timeout_id = g_timeout_add (MIN_MIPMAP_AGE_USEC / 1000, texture_is_idle_and_not_mipmapped, stex); } } tex_width = priv->tex_width; tex_height = priv->tex_height; if (tex_width == 0 || tex_height == 0) /* no contents yet */ return; cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height }; /* Use nearest-pixel interpolation if the texture is unscaled. This * improves performance, especially with software rendering. */ filter = COGL_PIPELINE_FILTER_LINEAR; if (meta_actor_painting_untransformed (tex_width, tex_height, NULL, NULL)) filter = COGL_PIPELINE_FILTER_NEAREST; ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); fb = cogl_get_draw_framebuffer (); opacity = clutter_actor_get_paint_opacity (actor); clutter_actor_get_allocation_box (actor, &alloc); cairo_region_t *blended_region; gboolean use_opaque_region = (priv->opaque_region != NULL && opacity == 255); if (use_opaque_region) { if (priv->clip_region != NULL) blended_region = cairo_region_copy (priv->clip_region); else blended_region = cairo_region_create_rectangle (&tex_rect); cairo_region_subtract (blended_region, priv->opaque_region); } else { if (priv->clip_region != NULL) blended_region = cairo_region_reference (priv->clip_region); else blended_region = NULL; } /* Limit to how many separate rectangles we'll draw; beyond this just * fall back and draw the whole thing */ #define MAX_RECTS 16 if (blended_region != NULL) { int n_rects = cairo_region_num_rectangles (blended_region); if (n_rects > MAX_RECTS) { /* Fall back to taking the fully blended path. */ use_opaque_region = FALSE; cairo_region_destroy (blended_region); blended_region = NULL; } } /* First, paint the unblended parts, which are part of the opaque region. */ if (use_opaque_region) { cairo_region_t *region; int n_rects; int i; if (priv->clip_region != NULL) { region = cairo_region_copy (priv->clip_region); cairo_region_intersect (region, priv->opaque_region); } else { region = cairo_region_reference (priv->opaque_region); } if (!cairo_region_is_empty (region)) { CoglPipeline *opaque_pipeline = get_unblended_pipeline (ctx); cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex); cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter); n_rects = cairo_region_num_rectangles (region); for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc); } } cairo_region_destroy (region); } /* Now, go ahead and paint the blended parts. */ /* We have three cases: * 1) blended_region has rectangles - paint the rectangles. * 2) blended_region is empty - don't paint anything * 3) blended_region is NULL - paint fully-blended. * * 1) and 3) are the times where we have to paint stuff. This tests * for 1) and 3). */ if (blended_region == NULL || !cairo_region_is_empty (blended_region)) { CoglPipeline *blended_pipeline; if (priv->mask_texture == NULL) { blended_pipeline = get_unmasked_pipeline (ctx); } else { blended_pipeline = get_masked_pipeline (ctx); cogl_pipeline_set_layer_texture (blended_pipeline, 1, priv->mask_texture); cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter); } cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex); cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter); CoglColor color; cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); cogl_pipeline_set_color (blended_pipeline, &color); if (blended_region != NULL) { /* 1) blended_region is not empty. Paint the rectangles. */ int i; int n_rects = cairo_region_num_rectangles (blended_region); for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (blended_region, i, &rect); if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect)) continue; paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc); } } else { /* 3) blended_region is NULL. Do a full paint. */ cogl_framebuffer_draw_rectangle (fb, blended_pipeline, 0, 0, alloc.x2 - alloc.x1, alloc.y2 - alloc.y1); } } if (blended_region != NULL) cairo_region_destroy (blended_region); } static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { MetaShapedTexturePrivate *priv = META_SHAPED_TEXTURE (self)->priv; if (min_width_p) *min_width_p = priv->tex_width; if (natural_width_p) *natural_width_p = priv->tex_width; } static void meta_shaped_texture_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { MetaShapedTexturePrivate *priv = META_SHAPED_TEXTURE (self)->priv; if (min_height_p) *min_height_p = priv->tex_height; if (natural_height_p) *natural_height_p = priv->tex_height; } static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { return clutter_paint_volume_set_from_allocation (volume, self); } 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) { CoglTexture *base_texture; priv->create_mipmaps = create_mipmaps; base_texture = create_mipmaps ? priv->texture : NULL; meta_texture_tower_set_base_texture (priv->paint_tower, base_texture); } } /** * meta_shaped_texture_update_area: * @stex: #MetaShapedTexture * @x: the x coordinate of the damaged area * @y: the y coordinate of the damaged area * @width: the width of the damaged area * @height: the height of the damaged area * @unobscured_region: The unobscured region of the window or %NULL if * there is no valid one (like when the actor is transformed or * has a mapped clone) * * Repairs the damaged area indicated by @x, @y, @width and @height * and queues a redraw for the intersection @visibible_region and * the damage area. If @visibible_region is %NULL a redraw will always * get queued. * * Return value: Whether a redraw have been queued or not */ gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex, int x, int y, int width, int height, cairo_region_t *unobscured_region) { MetaShapedTexturePrivate *priv; const cairo_rectangle_int_t clip = { x, y, width, height }; priv = stex->priv; if (priv->texture == NULL) return FALSE; meta_texture_tower_update_area (priv->paint_tower, x, y, width, height); priv->prev_invalidation = priv->last_invalidation; priv->last_invalidation = g_get_monotonic_time (); if (priv->prev_invalidation) { gint64 interval = priv->last_invalidation - priv->prev_invalidation; gboolean fast_update = interval < MIN_MIPMAP_AGE_USEC; if (!fast_update) priv->fast_updates = 0; else if (priv->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP) priv->fast_updates++; } if (unobscured_region) { cairo_region_t *intersection; if (cairo_region_is_empty (unobscured_region)) return FALSE; intersection = cairo_region_copy (unobscured_region); cairo_region_intersect_rectangle (intersection, &clip); if (!cairo_region_is_empty (intersection)) { cairo_rectangle_int_t damage_rect; cairo_region_get_extents (intersection, &damage_rect); clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect); cairo_region_destroy (intersection); return TRUE; } cairo_region_destroy (intersection); return FALSE; } else { clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip); return TRUE; } } static void set_cogl_texture (MetaShapedTexture *stex, CoglTexture *cogl_tex) { MetaShapedTexturePrivate *priv; guint width, height; g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); priv = stex->priv; if (priv->texture != NULL) cogl_object_unref (priv->texture); priv->texture = cogl_tex; if (cogl_tex != NULL) { width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); } else { width = 0; height = 0; } priv->mask_needs_update = (priv->tex_width != width || priv->tex_height != height); if (priv->mask_needs_update) { priv->tex_width = width; priv->tex_height = height; meta_shaped_texture_dirty_mask (stex); clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); g_signal_emit (stex, signals[SIZE_CHANGED], 0); } /* NB: We don't queue a redraw of the actor here because we don't * know how much of the buffer has changed with respect to the * previous buffer. We only queue a redraw in response to surface * damage. */ if (priv->create_mipmaps) meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex); } /** * meta_shaped_texture_set_texture: * @stex: The #MetaShapedTexture * @pixmap: The #CoglTexture to display */ void meta_shaped_texture_set_texture (MetaShapedTexture *stex, CoglTexture *texture) { g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); set_cogl_texture (stex, texture); } /** * meta_shaped_texture_get_texture: * @stex: The #MetaShapedTexture * * Returns: (transfer none): the unshaped texture */ CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex) { g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); return stex->priv->texture; } /** * meta_shaped_texture_set_overlay_path: * @stex: a #MetaShapedTexture * @overlay_region: A region containing the parts of the mask to overlay. * All rectangles in this region are wiped clear to full transparency, * and the overlay path is clipped to this region. * @overlay_path: (transfer full): This path will be painted onto the mask * texture with a fully opaque source. Due to the lack of refcounting * in #cairo_path_t, ownership of the path is assumed. */ void meta_shaped_texture_set_overlay_path (MetaShapedTexture *stex, cairo_region_t *overlay_region, cairo_path_t *overlay_path) { MetaShapedTexturePrivate *priv; g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); priv = stex->priv; if (priv->overlay_region != NULL) { cairo_region_destroy (priv->overlay_region); priv->overlay_region = NULL; } if (priv->overlay_path != NULL) { cairo_path_destroy (priv->overlay_path); priv->overlay_path = NULL; } cairo_region_reference (overlay_region); priv->overlay_region = overlay_region; /* cairo_path_t does not have refcounting. */ priv->overlay_path = overlay_path; } /** * meta_shaped_texture_set_clip_region: * @stex: a #MetaShapedTexture * @clip_region: the region of the texture that is visible and * should be painted. * * Provides a hint to the texture about what areas of the texture * are not completely obscured and thus need to be painted. This * 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); if (clip_region) priv->clip_region = cairo_region_copy (clip_region); else priv->clip_region = NULL; } /** * meta_shaped_texture_set_opaque_region: * @stex: a #MetaShapedTexture * @opaque_region: (transfer full): the region of the texture that * can have blending turned off. * * As most windows have a large portion that does not require blending, * we can easily turn off blending if we know the areas that do not * require blending. This sets the region where we will not blend for * optimization purposes. */ void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex, cairo_region_t *opaque_region) { MetaShapedTexturePrivate *priv; g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); priv = stex->priv; if (priv->opaque_region) cairo_region_destroy (priv->opaque_region); if (opaque_region) priv->opaque_region = cairo_region_reference (opaque_region); else priv->opaque_region = NULL; } /** * meta_shaped_texture_get_image: * @stex: A #MetaShapedTexture * @clip: A clipping rectangle, to help prevent extra processing. * In the case that the clipping rectangle is partially or fully * outside the bounds of the texture, the rectangle will be clipped. * * Flattens the two layers of the shaped texture into one ARGB32 * image by alpha blending the two images, and returns the flattened * image. * * Returns: (transfer full): a new cairo surface to be freed with * cairo_surface_destroy(). */ cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_rectangle_int_t *clip) { CoglTexture *texture, *mask_texture; cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 }; cairo_surface_t *surface; g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); texture = stex->priv->texture; if (texture == NULL) return NULL; texture_rect.width = cogl_texture_get_width (texture); texture_rect.height = cogl_texture_get_height (texture); if (clip != NULL) { /* GdkRectangle is just a typedef of cairo_rectangle_int_t, * so we can use the gdk_rectangle_* APIs on these. */ if (!gdk_rectangle_intersect (&texture_rect, clip, clip)) return NULL; } if (clip != NULL) texture = cogl_texture_new_from_sub_texture (texture, clip->x, clip->y, clip->width, clip->height); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, cogl_texture_get_width (texture), cogl_texture_get_height (texture)); cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32, cairo_image_surface_get_stride (surface), cairo_image_surface_get_data (surface)); cairo_surface_mark_dirty (surface); if (clip != NULL) cogl_object_unref (texture); mask_texture = stex->priv->mask_texture; if (mask_texture != NULL) { cairo_t *cr; cairo_surface_t *mask_surface; if (clip != NULL) mask_texture = cogl_texture_new_from_sub_texture (mask_texture, clip->x, clip->y, clip->width, clip->height); mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, cogl_texture_get_width (mask_texture), cogl_texture_get_height (mask_texture)); cogl_texture_get_data (mask_texture, COGL_PIXEL_FORMAT_A_8, cairo_image_surface_get_stride (mask_surface), cairo_image_surface_get_data (mask_surface)); cairo_surface_mark_dirty (mask_surface); cr = cairo_create (surface); cairo_set_source_surface (cr, mask_surface, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN); cairo_paint (cr); cairo_destroy (cr); cairo_surface_destroy (mask_surface); if (clip != NULL) cogl_object_unref (mask_texture); } return surface; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-plugin.c�����������������������������������������������������������0000664�0001750�0001750�00000023353�14211404421�020515� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:meta-plugin * @title: MetaPlugin * @short_description: Entry point for plugins */ #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_DEBUG_MODE, }; struct _MetaPluginPrivate { MetaScreen *screen; gint running; gboolean debug : 1; }; 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_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_DEBUG_MODE: g_value_set_boolean (value, priv->debug); 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->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_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); } 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; } /** * _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 = priv->screen; 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_tile_completed (MetaPlugin *plugin, MetaWindowActor *actor) { meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_TILE); } 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); } /** * 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); } /** * 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; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-sync-ring.c��������������������������������������������������������0000664�0001750�0001750�00000042451�14211404421�021130� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * This is based on an original C++ implementation for compiz that * carries the following copyright notice: * * * Copyright © 2011 NVIDIA Corporation * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of NVIDIA * Corporation not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. NVIDIA Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * * Authors: James Jones <jajones@nvidia.com> */ #include <string.h> #include <stdlib.h> #include <GL/gl.h> #include <GL/glx.h> #include <X11/extensions/sync.h> #include <cogl/cogl.h> #include <clutter/clutter.h> #include <meta/util.h> #include "cogl-utils.h" #include "meta-sync-ring.h" /* Theory of operation: * * We use a ring of NUM_SYNCS fence objects. On each frame we advance * to the next fence in the ring. For each fence we do: * * 1. fence is XSyncTriggerFence()'d and glWaitSync()'d * 2. NUM_SYNCS / 2 frames later, fence should be triggered * 3. fence is XSyncResetFence()'d * 4. NUM_SYNCS / 2 frames later, fence should be reset * 5. go back to 1 and re-use fence * * glClientWaitSync() and XAlarms are used in steps 2 and 4, * respectively, to double-check the expectections. */ #define NUM_SYNCS 10 #define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */ #define MAX_REBOOT_ATTEMPTS 2 typedef enum { META_SYNC_STATE_READY, META_SYNC_STATE_WAITING, META_SYNC_STATE_DONE, META_SYNC_STATE_RESET_PENDING, } MetaSyncState; typedef struct { Display *xdisplay; XSyncFence xfence; GLsync gl_x11_sync; GLsync gpu_fence; XSyncCounter xcounter; XSyncAlarm xalarm; XSyncValue next_counter_value; MetaSyncState state; } MetaSync; typedef struct { Display *xdisplay; int xsync_event_base; int xsync_error_base; GHashTable *alarm_to_sync; MetaSync *syncs_array[NUM_SYNCS]; guint current_sync_idx; MetaSync *current_sync; guint warmup_syncs; guint reboots; } MetaSyncRing; static MetaSyncRing meta_sync_ring = { 0 }; static XSyncValue SYNC_VALUE_ZERO; static XSyncValue SYNC_VALUE_ONE; static const char* (*meta_gl_get_string) (GLenum name); static void (*meta_gl_get_integerv) (GLenum pname, GLint *params); static const char* (*meta_gl_get_stringi) (GLenum name, GLuint index); static void (*meta_gl_delete_sync) (GLsync sync); static GLenum (*meta_gl_client_wait_sync) (GLsync sync, GLbitfield flags, GLuint64 timeout); static void (*meta_gl_wait_sync) (GLsync sync, GLbitfield flags, GLuint64 timeout); static GLsync (*meta_gl_import_sync) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); static GLsync (*meta_gl_fence_sync) (GLenum condition, GLbitfield flags); static MetaSyncRing * meta_sync_ring_get (void) { if (meta_sync_ring.reboots > MAX_REBOOT_ATTEMPTS) return NULL; return &meta_sync_ring; } static gboolean load_gl_symbol (const char *name, void **func) { *func = cogl_get_proc_address (name); if (!*func) { meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"\n", name); return FALSE; } return TRUE; } static gboolean check_gl_extensions (void) { ClutterBackend *backend; CoglContext *cogl_context; CoglDisplay *cogl_display; CoglRenderer *cogl_renderer; backend = clutter_get_default_backend (); cogl_context = clutter_backend_get_cogl_context (backend); cogl_display = cogl_context_get_display (cogl_context); cogl_renderer = cogl_display_get_renderer (cogl_display); meta_cogl_hardware_supports_npot_sizes (); switch (cogl_renderer_get_driver (cogl_renderer)) { case COGL_DRIVER_GL3: { int major, minor; gboolean version_ok = FALSE; int num_extensions, i; gboolean arb_sync = FALSE; gboolean x11_sync_object = FALSE; meta_gl_get_integerv (GL_MAJOR_VERSION, &major); meta_gl_get_integerv (GL_MINOR_VERSION, &minor); version_ok = (major >= 3); g_printerr ("openGL version %d.%d detected (GL3 Cogl Driver)\n", major, minor); meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions); for (i = 0; i < num_extensions; ++i) { const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i); if (g_strcmp0 ("GL_ARB_sync", ext) == 0) arb_sync = TRUE; else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0) x11_sync_object = TRUE; } return version_ok && arb_sync && x11_sync_object; } case COGL_DRIVER_GL: { gboolean version_ok = FALSE; const char *extensions; const char *version_string = meta_gl_get_string (GL_VERSION); /* From the spec: The string returned starts with "<major version>.<minor version>". Following the minor version, there can be another '.', then a vendor-specific build number. The string may have more content, which is completely vendor-specific (thus not a part of the OpenGL standard). So, we can split this by . and care only about the first two substrings returned. Anything else is dumped in the third substring. */ gchar **split = g_strsplit (version_string, ".", 3); if (g_strv_length (split) >= 2) { g_printerr ("openGL version %s.%s detected (GL Cogl Driver)\n", split[0], split[1]); version_ok = (atoi (split[0]) >= 3); } g_strfreev (split); extensions = meta_gl_get_string (GL_EXTENSIONS); return version_ok && (extensions != NULL && strstr (extensions, "GL_ARB_sync") != NULL && strstr (extensions, "GL_EXT_x11_sync_object") != NULL); } case COGL_DRIVER_ANY: case COGL_DRIVER_NOP: case COGL_DRIVER_GLES1: case COGL_DRIVER_GLES2: case COGL_DRIVER_WEBGL: break; default: break; } return FALSE; } static gboolean load_required_symbols (void) { static gboolean success = FALSE; if (success) return TRUE; /* We don't link against libGL directly because cogl may want to * use something else. This assumes that cogl has been initialized * and dynamically loaded libGL at this point. */ if (!load_gl_symbol ("glGetString", (void **) &meta_gl_get_string)) goto out; if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv)) goto out; if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi)) goto out; if (!check_gl_extensions ()) { g_printerr ("MetaSyncRing disabled: couldn't find required GL extensions, or the minimum safe openGL version was not met\n"); goto out; } if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync)) goto out; if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync)) goto out; if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync)) goto out; if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync)) goto out; if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync)) goto out; success = TRUE; out: return success; } static void meta_sync_insert (MetaSync *self) { g_return_if_fail (self->state == META_SYNC_STATE_READY); XSyncTriggerFence (self->xdisplay, self->xfence); XFlush (self->xdisplay); meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED); self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0); self->state = META_SYNC_STATE_WAITING; } static GLenum meta_sync_check_update_finished (MetaSync *self, GLuint64 timeout) { GLenum status = GL_WAIT_FAILED; switch (self->state) { case META_SYNC_STATE_DONE: status = GL_ALREADY_SIGNALED; break; case META_SYNC_STATE_WAITING: status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout); if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED) { self->state = META_SYNC_STATE_DONE; meta_gl_delete_sync (self->gpu_fence); self->gpu_fence = 0; } break; case META_SYNC_STATE_READY: case META_SYNC_STATE_RESET_PENDING: break; default: break; } g_warn_if_fail (status != GL_WAIT_FAILED); return status; } static void meta_sync_reset (MetaSync *self) { XSyncAlarmAttributes attrs; int overflow; g_return_if_fail (self->state == META_SYNC_STATE_DONE); XSyncResetFence (self->xdisplay, self->xfence); attrs.trigger.wait_value = self->next_counter_value; XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs); XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value); XSyncValueAdd (&self->next_counter_value, self->next_counter_value, SYNC_VALUE_ONE, &overflow); self->state = META_SYNC_STATE_RESET_PENDING; } static void meta_sync_handle_event (MetaSync *self, XSyncAlarmNotifyEvent *event) { g_return_if_fail (event->alarm == self->xalarm); g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING); self->state = META_SYNC_STATE_READY; } static MetaSync * meta_sync_new (Display *xdisplay) { MetaSync *self; XSyncAlarmAttributes attrs; self = calloc (1, sizeof (MetaSync)); self->xdisplay = xdisplay; self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE); self->gl_x11_sync = 0; self->gpu_fence = 0; self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO); attrs.trigger.counter = self->xcounter; attrs.trigger.value_type = XSyncAbsolute; attrs.trigger.wait_value = SYNC_VALUE_ONE; attrs.trigger.test_type = XSyncPositiveTransition; attrs.events = TRUE; self->xalarm = XSyncCreateAlarm (xdisplay, XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType | XSyncCAEvents, &attrs); XSyncIntToValue (&self->next_counter_value, 1); self->state = META_SYNC_STATE_READY; return self; } static void meta_sync_import (MetaSync *self) { g_return_if_fail (self->gl_x11_sync == 0); self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0); } static Bool alarm_event_predicate (Display *dpy, XEvent *event, XPointer data) { MetaSyncRing *ring = meta_sync_ring_get (); if (!ring) return False; if (event->type == ring->xsync_event_base + XSyncAlarmNotify) { if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm) return True; } return False; } static void meta_sync_free (MetaSync *self) { /* When our assumptions don't hold, something has gone wrong but we * don't know what, so we reboot the ring. While doing that, we * trigger fences before deleting them to try to get ourselves out * of a potentially stuck GPU state. */ switch (self->state) { case META_SYNC_STATE_WAITING: meta_gl_delete_sync (self->gpu_fence); break; case META_SYNC_STATE_DONE: /* nothing to do */ break; case META_SYNC_STATE_RESET_PENDING: { XEvent event; XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self); meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event); } /* fall through */ case META_SYNC_STATE_READY: XSyncTriggerFence (self->xdisplay, self->xfence); XFlush (self->xdisplay); break; default: break; } meta_gl_delete_sync (self->gl_x11_sync); XSyncDestroyFence (self->xdisplay, self->xfence); XSyncDestroyCounter (self->xdisplay, self->xcounter); XSyncDestroyAlarm (self->xdisplay, self->xalarm); free (self); } gboolean meta_sync_ring_init (Display *xdisplay) { gint major, minor; guint i; MetaSyncRing *ring = meta_sync_ring_get (); if (!ring) return FALSE; g_return_val_if_fail (xdisplay != NULL, FALSE); g_return_val_if_fail (ring->xdisplay == NULL, FALSE); if (!load_required_symbols ()) return FALSE; if (!XSyncQueryExtension (xdisplay, &ring->xsync_event_base, &ring->xsync_error_base) || !XSyncInitialize (xdisplay, &major, &minor)) return FALSE; XSyncIntToValue (&SYNC_VALUE_ZERO, 0); XSyncIntToValue (&SYNC_VALUE_ONE, 1); ring->xdisplay = xdisplay; ring->alarm_to_sync = g_hash_table_new (NULL, NULL); for (i = 0; i < NUM_SYNCS; ++i) { MetaSync *sync = meta_sync_new (ring->xdisplay); ring->syncs_array[i] = sync; g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync); } /* Since the connection we create the X fences on isn't the same as * the one used for the GLX context, we need to XSync() here to * ensure glImportSync() succeeds. */ XSync (xdisplay, False); for (i = 0; i < NUM_SYNCS; ++i) meta_sync_import (ring->syncs_array[i]); ring->current_sync_idx = 0; ring->current_sync = ring->syncs_array[0]; ring->warmup_syncs = 0; return TRUE; } void meta_sync_ring_destroy (void) { guint i; MetaSyncRing *ring = meta_sync_ring_get (); if (!ring) return; g_return_if_fail (ring->xdisplay != NULL); ring->current_sync_idx = 0; ring->current_sync = NULL; ring->warmup_syncs = 0; for (i = 0; i < NUM_SYNCS; ++i) meta_sync_free (ring->syncs_array[i]); g_hash_table_destroy (ring->alarm_to_sync); ring->xsync_event_base = 0; ring->xsync_error_base = 0; ring->xdisplay = NULL; } static gboolean meta_sync_ring_reboot (Display *xdisplay) { MetaSyncRing *ring = meta_sync_ring_get (); if (!ring) return FALSE; meta_sync_ring_destroy (); ring->reboots += 1; if (!meta_sync_ring_get ()) { meta_warning ("MetaSyncRing: Too many reboots -- disabling\n"); return FALSE; } return meta_sync_ring_init (xdisplay); } gboolean meta_sync_ring_after_frame (void) { MetaSyncRing *ring = meta_sync_ring_get (); if (!ring) return FALSE; g_return_val_if_fail (ring->xdisplay != NULL, FALSE); if (ring->warmup_syncs >= NUM_SYNCS / 2) { guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS; MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx]; GLenum status = meta_sync_check_update_finished (sync_to_reset, 0); if (status == GL_TIMEOUT_EXPIRED) { meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?\n"); status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME); } if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED) { meta_warning ("MetaSyncRing: Timed out waiting for sync object.\n"); return meta_sync_ring_reboot (ring->xdisplay); } meta_sync_reset (sync_to_reset); } else { ring->warmup_syncs += 1; } ring->current_sync_idx += 1; ring->current_sync_idx %= NUM_SYNCS; ring->current_sync = ring->syncs_array[ring->current_sync_idx]; return TRUE; } gboolean meta_sync_ring_insert_wait (void) { MetaSyncRing *ring = meta_sync_ring_get (); if (!ring) return FALSE; g_return_val_if_fail (ring->xdisplay != NULL, FALSE); if (ring->current_sync->state != META_SYNC_STATE_READY) { meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?\n"); if (!meta_sync_ring_reboot (ring->xdisplay)) return FALSE; } meta_sync_insert (ring->current_sync); return TRUE; } void meta_sync_ring_handle_event (XEvent *xevent) { XSyncAlarmNotifyEvent *event; MetaSync *sync; MetaSyncRing *ring = meta_sync_ring_get (); if (!ring) return; g_return_if_fail (ring->xdisplay != NULL); if (xevent->type != (ring->xsync_event_base + XSyncAlarmNotify)) return; event = (XSyncAlarmNotifyEvent *) xevent; sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm); if (sync) meta_sync_handle_event (sync, event); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-background-actor.c�������������������������������������������������0000664�0001750�0001750�00000046601�14211404421�022445� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Portions adapted from gnome-shell/src/shell-global.c */ /** * SECTION:meta-background-actor * @title: MetaBackgroundActor * @short_description: Actor for painting the root window background */ #include <config.h> #include <cogl/winsys/cogl-texture-pixmap-x11.h> #include <clutter/clutter.h> #include <X11/Xatom.h> #include "cogl-utils.h" #include "compositor-private.h" #include <meta/errors.h> #include "meta-background-actor-private.h" #define FADE_DURATION 1500 /* We allow creating multiple MetaBackgroundActors for the same MetaScreen to * allow different rendering options to be set for different copies. * But we want to share the same underlying CoglTexture for efficiency and * to avoid driver bugs that might occur if we created multiple CoglTexturePixmaps * for the same pixmap. * * This structure holds common information. */ typedef struct _MetaScreenBackground MetaScreenBackground; struct _MetaScreenBackground { MetaScreen *screen; GSList *actors; float texture_width; float texture_height; CoglTexture *texture; CoglPipelineWrapMode wrap_mode; guint have_pixmap : 1; }; struct _MetaBackgroundActorPrivate { MetaScreenBackground *background; ClutterActor *top_actor; ClutterActor *bottom_actor; cairo_region_t *visible_region; float dim_factor; gboolean transition_running; }; enum { PROP_0, PROP_DIM_FACTOR, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR); static void set_texture (MetaScreenBackground *background, CoglTexture *texture); static void set_texture_to_stage_color (MetaScreenBackground *background); static void on_notify_stage_color (GObject *stage, GParamSpec *pspec, MetaScreenBackground *background) { if (!background->have_pixmap) set_texture_to_stage_color (background); } static void free_screen_background (MetaScreenBackground *background) { set_texture (background, NULL); if (background->screen != NULL) { ClutterActor *stage = meta_get_stage_for_screen (background->screen); g_signal_handlers_disconnect_by_func (stage, (gpointer) on_notify_stage_color, background); background->screen = NULL; } } static MetaScreenBackground * meta_screen_background_get (MetaScreen *screen) { MetaScreenBackground *background; background = g_object_get_data (G_OBJECT (screen), "meta-screen-background"); if (background == NULL) { ClutterActor *stage; background = g_new0 (MetaScreenBackground, 1); background->screen = screen; g_object_set_data_full (G_OBJECT (screen), "meta-screen-background", background, (GDestroyNotify) free_screen_background); stage = meta_get_stage_for_screen (screen); g_signal_connect (stage, "notify::background-color", G_CALLBACK (on_notify_stage_color), background); meta_background_actor_update (screen); } return background; } static void update_wrap_mode_of_actor (MetaBackgroundActor *self) { MetaBackgroundActorPrivate *priv = self->priv; meta_background_set_layer_wrap_mode (META_BACKGROUND (priv->top_actor), priv->background->wrap_mode); meta_background_set_layer_wrap_mode (META_BACKGROUND (priv->bottom_actor), priv->background->wrap_mode); /* this ensures the actors also get resized if the stage size changed */ clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->top_actor)); clutter_actor_queue_relayout (CLUTTER_ACTOR (priv->bottom_actor)); } static void update_wrap_mode (MetaScreenBackground *background) { GSList *l; int width, height; meta_screen_get_size (background->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 == background->texture_width && height == background->texture_height) background->wrap_mode = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; else background->wrap_mode = COGL_PIPELINE_WRAP_MODE_REPEAT; for (l = background->actors; l; l = l->next) update_wrap_mode_of_actor (l->data); } static void cancel_transitions (MetaBackgroundActor *self) { MetaBackgroundActorPrivate *priv = self->priv; clutter_actor_remove_all_transitions (priv->top_actor); clutter_actor_set_opacity (priv->top_actor, 255); meta_background_set_layer (META_BACKGROUND (priv->bottom_actor), priv->background->texture); priv->transition_running = FALSE; } static void on_transition_complete (ClutterActor *actor, gpointer user_data) { MetaBackgroundActor *self = (MetaBackgroundActor *)user_data; MetaBackgroundActorPrivate *priv = self->priv; meta_background_set_layer (META_BACKGROUND (priv->bottom_actor), priv->background->texture); priv->transition_running = FALSE; } static void set_texture_on_actors (MetaBackgroundActor *self) { MetaBackgroundActorPrivate *priv = self->priv; meta_background_set_layer (META_BACKGROUND (priv->bottom_actor), priv->background->texture); meta_background_set_layer (META_BACKGROUND (priv->top_actor), priv->background->texture); clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); } static void set_texture_on_actor (MetaBackgroundActor *self) { MetaBackgroundActorPrivate *priv = self->priv; MetaBackgroundTransition background_transition; if (priv->transition_running) cancel_transitions (self); background_transition = meta_prefs_get_background_transition(); if (background_transition == META_BACKGROUND_TRANSITION_NONE) { // NO TRANSITION clutter_actor_set_opacity (CLUTTER_ACTOR (priv->bottom_actor), 0); meta_background_set_layer (META_BACKGROUND (priv->top_actor), priv->background->texture); on_transition_complete (priv->top_actor, self); } else { if (background_transition == META_BACKGROUND_TRANSITION_FADEIN) { // FADE_IN TRANSITION clutter_actor_set_opacity (CLUTTER_ACTOR (priv->bottom_actor), 0); } // BLEND TRANSITION clutter_actor_set_opacity (CLUTTER_ACTOR (priv->top_actor), 0); meta_background_set_layer (META_BACKGROUND (priv->top_actor), priv->background->texture); priv->transition_running = TRUE; clutter_actor_save_easing_state (priv->top_actor); clutter_actor_set_easing_duration (priv->top_actor, FADE_DURATION); clutter_actor_set_opacity (priv->top_actor, 255); clutter_actor_restore_easing_state (priv->top_actor); g_signal_connect (priv->top_actor, "transitions-completed", G_CALLBACK (on_transition_complete), self); clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); } } static void set_texture (MetaScreenBackground *background, CoglTexture *texture) { MetaDisplay *display = meta_screen_get_display (background->screen); GSList *l; /* 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); if (background->texture != NULL) { cogl_object_unref (background->texture); background->texture = NULL; } meta_error_trap_pop (display); if (texture != NULL) background->texture = cogl_object_ref (texture); background->texture_width = cogl_texture_get_width (background->texture); background->texture_height = cogl_texture_get_height (background->texture); for (l = background->actors; l; l = l->next) set_texture_on_actor (l->data); update_wrap_mode (background); } /* 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 (MetaScreenBackground *background) { ClutterActor *stage = meta_get_stage_for_screen (background->screen); ClutterColor color; CoglTexture *texture; clutter_actor_get_background_color (stage, &color); /* Slicing will prevent COGL from using hardware texturing for * the tiled 1x1 pixmap, and will cause it to draw the window * background in millions of separate 1x1 rectangles */ texture = meta_create_color_texture_4ub (color.red, color.green, color.blue, 0xff, COGL_TEXTURE_NO_SLICING); set_texture (background, texture); cogl_object_unref (texture); } static void meta_background_actor_dispose (GObject *object) { MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); MetaBackgroundActorPrivate *priv = self->priv; meta_background_actor_set_visible_region (self, NULL); if (priv->background != NULL) { priv->background->actors = g_slist_remove (priv->background->actors, self); priv->background = NULL; } if (priv->top_actor != NULL) priv->top_actor = NULL; if (priv->bottom_actor != NULL) priv->bottom_actor = NULL; G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object); } 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); MetaBackgroundActorPrivate *priv = self->priv; int width, height; meta_screen_get_size (priv->background->screen, &width, &height); if (min_width_p) *min_width_p = width; if (natural_width_p) *natural_width_p = width; } 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); MetaBackgroundActorPrivate *priv = self->priv; int width, height; meta_screen_get_size (priv->background->screen, &width, &height); if (min_height_p) *min_height_p = height; if (natural_height_p) *natural_height_p = height; } static gboolean meta_background_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor); MetaBackgroundActorPrivate *priv = self->priv; int width, height; meta_screen_get_size (priv->background->screen, &width, &height); clutter_paint_volume_set_width (volume, width); clutter_paint_volume_set_height (volume, height); return TRUE; } static void meta_background_actor_set_dim_factor (MetaBackgroundActor *self, gfloat dim_factor) { MetaBackgroundActorPrivate *priv = self->priv; if (priv->dim_factor == dim_factor) return; priv->dim_factor = dim_factor; clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DIM_FACTOR]); } static void meta_background_actor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); MetaBackgroundActorPrivate *priv = self->priv; switch (prop_id) { case PROP_DIM_FACTOR: g_value_set_float (value, priv->dim_factor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_background_actor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); switch (prop_id) { case PROP_DIM_FACTOR: meta_background_actor_set_dim_factor (self, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_background_actor_class_init (MetaBackgroundActorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GParamSpec *pspec; g_type_class_add_private (klass, sizeof (MetaBackgroundActorPrivate)); object_class->dispose = meta_background_actor_dispose; object_class->get_property = meta_background_actor_get_property; object_class->set_property = meta_background_actor_set_property; actor_class->get_preferred_width = meta_background_actor_get_preferred_width; actor_class->get_preferred_height = meta_background_actor_get_preferred_height; actor_class->get_paint_volume = meta_background_actor_get_paint_volume; /** * MetaBackgroundActor:dim-factor: * * Factor to dim the background by, between 0.0 (black) and 1.0 (original * colors) */ pspec = g_param_spec_float ("dim-factor", "Dim factor", "Factor to dim the background by", 0.0, 1.0, 1.0, G_PARAM_READWRITE); obj_props[PROP_DIM_FACTOR] = pspec; g_object_class_install_property (object_class, PROP_DIM_FACTOR, pspec); } static void meta_background_actor_init (MetaBackgroundActor *self) { MetaBackgroundActorPrivate *priv; priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, META_TYPE_BACKGROUND_ACTOR, MetaBackgroundActorPrivate); priv->dim_factor = 1.0; priv->transition_running = FALSE; } /** * meta_background_actor_new_for_screen: * @screen: the #MetaScreen * * Creates a new actor to draw the background for the given screen. * * Return value: the newly created background actor */ ClutterActor * meta_background_actor_new_for_screen (MetaScreen *screen) { MetaBackgroundActor *self; MetaBackgroundActorPrivate *priv; g_return_val_if_fail (META_IS_SCREEN (screen), NULL); self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL); priv = self->priv; priv->background = meta_screen_background_get (screen); priv->background->actors = g_slist_prepend (priv->background->actors, self); priv->bottom_actor = meta_background_new (screen); clutter_actor_add_child (CLUTTER_ACTOR (self), priv->bottom_actor); priv->top_actor = meta_background_new (screen); clutter_actor_add_child (CLUTTER_ACTOR (self), priv->top_actor); set_texture_on_actors (self); update_wrap_mode_of_actor (self); return CLUTTER_ACTOR (self); } /** * meta_background_actor_update: * @screen: a #MetaScreen * * 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. */ LOCAL_SYMBOL void meta_background_actor_update (MetaScreen *screen) { MetaScreenBackground *background; MetaDisplay *display; MetaCompositor *compositor; Atom type; int format; gulong nitems; gulong bytes_after; guchar *data; Pixmap root_pixmap_id; background = meta_screen_background_get (screen); display = meta_screen_get_display (screen); compositor = meta_display_get_compositor (display); root_pixmap_id = None; if (!XGetWindowProperty (meta_display_get_xdisplay (display), meta_screen_get_xroot (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; GError *error = NULL; meta_error_trap_push (display); texture = cogl_texture_pixmap_x11_new (compositor->context, root_pixmap_id, FALSE, &error); meta_error_trap_pop (display); if (texture != NULL) { set_texture (background, texture); cogl_object_unref (texture); background->have_pixmap = True; return; } else { g_warning ("Failed to create background texture from pixmap: %s", error->message); g_error_free (error); } } background->have_pixmap = False; set_texture_to_stage_color (background); } /** * 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. */ LOCAL_SYMBOL void meta_background_actor_set_visible_region (MetaBackgroundActor *self, cairo_region_t *visible_region) { MetaBackgroundActorPrivate *priv; g_return_if_fail (META_IS_BACKGROUND_ACTOR (self)); priv = self->priv; if (priv->top_actor != NULL) meta_background_set_visible_region (META_BACKGROUND (priv->top_actor), visible_region); } /** * meta_background_actor_screen_size_changed: * @screen: a #MetaScreen * * Called by the compositor when the size of the #MetaScreen changes */ LOCAL_SYMBOL void meta_background_actor_screen_size_changed (MetaScreen *screen) { MetaScreenBackground *background = meta_screen_background_get (screen); update_wrap_mode (background); } �������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/compositor.c������������������������������������������������������������0000664�0001750�0001750�00000146075�14211404421�020500� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * SECTION:compositor * @title: MetaCompositor * @short_Description: Compositor API * * At a high-level, a window is not-visible or visible. When a * window is added (with meta_compositor_add_window()) it is not visible. * meta_compositor_show_window() indicates a transition from not-visible to * visible. Some of the reasons for this: * * - Window newly created * - Window is unminimized * - Window is moved to the current desktop * - Window was made sticky * * meta_compositor_hide_window() indicates that the window has transitioned from * visible to not-visible. Some reasons include: * * - Window was destroyed * - Window is minimized * - Window is moved to a different desktop * - Window no longer sticky. * * Note that combinations are possible - a window might have first * been minimized and then moved to a different desktop. The 'effect' parameter * to meta_compositor_show_window() and meta_compositor_hide_window() is a hint * as to the appropriate effect to show the user and should not * be considered to be indicative of a state change. * * When the active workspace is changed, meta_compositor_switch_workspace() is * called first, then meta_compositor_show_window() and * meta_compositor_hide_window() are called individually for each window * affected, with an effect of META_COMP_EFFECT_NONE. * If hiding windows will affect the switch workspace animation, the * compositor needs to delay hiding the windows until the switch * workspace animation completes. * * meta_compositor_maximize_window() and meta_compositor_unmaximize_window() * are transitions within the visible state. The window is resized __before__ * the call, so it may be necessary to readjust the display based on the * old_rect to start the animation. * * # Containers # * * There's two containers in the stage that are used to place window actors, here * are listed in the order in which they are painted: * * - window group, accessible with meta_get_window_group_for_screen() * - top window group, accessible with meta_get_top_window_group_for_screen() * * Muffin will place actors representing windows in the window group, except for * override-redirect windows (ie. popups and menus) which will be placed in the * top window group. */ #include <config.h> #include <clutter/x11/clutter-x11.h> #include <meta/screen.h> #include <meta/errors.h> #include <meta/window.h> #include "compositor-private.h" #include <meta/compositor-muffin.h> #include "xprops.h" #include <meta/prefs.h> #include <meta/main.h> #include <meta/meta-shadow-factory.h> #include "meta-window-actor-private.h" #include "meta-window-group.h" #include "meta-background-actor-private.h" #include "window-private.h" /* to check window->hidden */ #include "display-private.h" /* for meta_display_lookup_x_window() */ #include "util-private.h" #include <X11/extensions/shape.h> #include <X11/extensions/Xcomposite.h> #include "meta-sync-ring.h" /* #define DEBUG_TRACE g_print */ #define DEBUG_TRACE(X) static MetaCompositor *compositor_global = NULL; static void frame_callback (ClutterStage *stage, CoglFrameEvent event, ClutterFrameInfo *frame_info, MetaCompositor *compositor); static inline gboolean composite_at_least_version (MetaDisplay *display, int maj, int min) { static int major = -1; static int minor = -1; if (major == -1) meta_display_get_compositor_version (display, &major, &minor); return (major > maj || (major == maj && minor >= min)); } static void sync_actor_stacking (MetaCompositor *compositor); static void meta_finish_workspace_switch (MetaCompositor *compositor) { GList *l; /* Finish hiding and showing actors for the new workspace */ for (l = compositor->windows; l; l = l->next) meta_window_actor_sync_visibility (l->data); /* * Fix up stacking order in case the plugin messed it up. */ sync_actor_stacking (compositor); /* printf ("... FINISHED DESKTOP SWITCH\n"); */ } LOCAL_SYMBOL void meta_switch_workspace_completed (MetaScreen *screen) { MetaCompositor *compositor = screen->display->compositor; /* FIXME -- must redo stacking order */ compositor->switch_workspace_in_progress--; if (compositor->switch_workspace_in_progress < 0) { g_warning ("Error in workspace_switch accounting!"); compositor->switch_workspace_in_progress = 0; } if (!compositor->switch_workspace_in_progress) meta_finish_workspace_switch (compositor); } void meta_compositor_destroy (MetaCompositor *compositor) { clutter_threads_remove_repaint_func (compositor->pre_paint_func_id); clutter_threads_remove_repaint_func (compositor->post_paint_func_id); if (compositor->have_x11_sync_object) meta_sync_ring_destroy (); } static void add_win (MetaWindow *window) { meta_window_actor_new (window); sync_actor_stacking (window->screen->display->compositor); } static void process_damage (MetaCompositor *compositor, XDamageNotifyEvent *event, MetaWindow *window) { MetaWindowActor *window_actor; if (window == NULL) return; window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); if (window_actor == NULL) return; meta_window_actor_process_damage (window_actor, event); compositor->frame_has_updated_xsurfaces = TRUE; } static void process_property_notify (MetaCompositor *compositor, XPropertyEvent *event, MetaWindow *window) { MetaWindowActor *window_actor; if (event->atom == compositor->atom_x_root_pixmap) { GSList *l; for (l = meta_display_get_screens (compositor->display); l; l = l->next) { MetaScreen *screen = l->data; if (event->window == meta_screen_get_xroot (screen)) { meta_background_actor_update (screen); return; } } } if (window == NULL) return; window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); if (window_actor == NULL) return; /* Check for the opacity changing */ if (event->atom == compositor->atom_net_wm_window_opacity) { meta_window_actor_update_opacity (window_actor); DEBUG_TRACE ("process_property_notify: net_wm_window_opacity\n"); return; } DEBUG_TRACE ("process_property_notify: unknown\n"); } static Window get_output_window (MetaScreen *screen) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); Window output, xroot; XWindowAttributes attr; long event_mask; xroot = meta_screen_get_xroot (screen); event_mask = FocusChangeMask | ExposureMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PropertyChangeMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; output = screen->composite_overlay_window; if (XGetWindowAttributes (xdisplay, output, &attr)) { event_mask |= attr.your_event_mask; } XSelectInput (xdisplay, output, event_mask); return output; } /** * meta_get_stage_for_screen: * @screen: a #MetaScreen * * Returns: (transfer none): The #ClutterStage for the screen */ ClutterActor * meta_get_stage_for_screen (MetaScreen *screen) { return screen->display->compositor->stage; } /** * meta_get_overlay_group_for_screen: * @screen: a #MetaScreen * * Returns: (transfer none): The overlay group corresponding to @screen */ ClutterActor * meta_get_overlay_group_for_screen (MetaScreen *screen) { return screen->display->compositor->overlay_group; } /** * meta_get_window_group_for_screen: * @screen: a #MetaScreen * * Returns: (transfer none): The window group corresponding to @screen */ ClutterActor * meta_get_window_group_for_screen (MetaScreen *screen) { return screen->display->compositor->window_group; } /** * meta_get_bottom_window_group_for_screen: * @screen: a #MetaScreen * * Returns: (transfer none): The bottom window group corresponding to @screen */ ClutterActor * meta_get_bottom_window_group_for_screen (MetaScreen *screen) { return screen->display->compositor->bottom_window_group; } /** * meta_get_top_window_group_for_screen: * @screen: a #MetaScreen * * Returns: (transfer none): The top window group corresponding to @screen */ ClutterActor * meta_get_top_window_group_for_screen (MetaScreen *screen) { return screen->display->compositor->top_window_group; } /** * meta_get_background_actor_for_screen: * @screen: a #MetaScreen * * Gets the actor that draws the root window background under the windows. * The root window background automatically tracks the image or color set * by the environment. * * Returns: (transfer none): The background actor corresponding to @screen */ ClutterActor * meta_get_background_actor_for_screen (MetaScreen *screen) { return screen->display->compositor->background_actor; } /** * meta_get_window_actors: * @screen: a #MetaScreen * * Returns: (transfer none) (element-type Clutter.Actor): The set of #MetaWindowActor on @screen */ GList * meta_get_window_actors (MetaScreen *screen) { return screen->display->compositor->windows; } static void do_set_stage_input_region (MetaScreen *screen, XserverRegion region) { MetaDisplay *display = screen->display; MetaCompositor *compositor = display->compositor; Display *xdpy = display->xdisplay; Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); /* It's generally a good heuristic that when a crossing event is generated because * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - * it's not the user doing something, it's the environment changing under the user. */ meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); XFixesSetWindowShapeRegion (xdpy, compositor->output, ShapeInput, 0, 0, region); } void meta_set_stage_input_region (MetaScreen *screen, XserverRegion region) { MetaDisplay *display = screen->display; MetaCompositor *compositor = display->compositor; Display *xdpy = display->xdisplay; if (compositor->stage && compositor->output) { do_set_stage_input_region (screen, region); } else { /* Reset compositor->pending_input_region if one existed before and set the new * one to use it later. */ if (compositor->pending_input_region) { XFixesDestroyRegion (xdpy, compositor->pending_input_region); compositor->pending_input_region = None; } if (region != None) { compositor->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0); XFixesCopyRegion (xdpy, compositor->pending_input_region, region); } } } void meta_empty_stage_input_region (MetaScreen *screen) { /* Using a static region here is a bit hacky, but Metacity never opens more than * one XDisplay, so it works fine. */ static XserverRegion region = None; if (region == None) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdpy = meta_display_get_xdisplay (display); region = XFixesCreateRegion (xdpy, NULL, 0); } meta_set_stage_input_region (screen, region); } LOCAL_SYMBOL gboolean meta_begin_modal_for_plugin (MetaScreen *screen, MetaPlugin *plugin, Window grab_window, Cursor cursor, MetaModalOptions options, guint32 timestamp) { /* To some extent this duplicates code in meta_display_begin_grab_op(), but there * are significant differences in how we handle grabs that make it difficult to * merge the two. */ MetaDisplay *display = meta_screen_get_display (screen); Display *xdpy = meta_display_get_xdisplay (display); MetaCompositor *compositor = display->compositor; gboolean pointer_grabbed = FALSE; int result; if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE) return FALSE; if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0) { result = XGrabPointer (xdpy, grab_window, False, /* owner_events */ (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask), GrabModeAsync, GrabModeAsync, None, /* confine to */ cursor, timestamp); if (result != Success) goto fail; pointer_grabbed = TRUE; } if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0) { result = XGrabKeyboard (xdpy, grab_window, False, /* owner_events */ GrabModeAsync, GrabModeAsync, timestamp); if (result != Success) goto fail; } display->grab_op = META_GRAB_OP_COMPOSITOR; display->grab_window = NULL; display->grab_screen = screen; display->grab_have_pointer = TRUE; display->grab_have_keyboard = TRUE; compositor->modal_plugin = plugin; return TRUE; fail: if (pointer_grabbed) XUngrabPointer (xdpy, timestamp); return FALSE; } LOCAL_SYMBOL void meta_end_modal_for_plugin (MetaScreen *screen, MetaPlugin *plugin, guint32 timestamp) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdpy = meta_display_get_xdisplay (display); MetaCompositor *compositor = display->compositor; g_return_if_fail (compositor->modal_plugin == plugin); XUngrabPointer (xdpy, timestamp); XUngrabKeyboard (xdpy, timestamp); display->grab_op = META_GRAB_OP_NONE; display->grab_window = NULL; display->grab_screen = NULL; display->grab_have_pointer = FALSE; display->grab_have_keyboard = FALSE; compositor->modal_plugin = NULL; } /* This is used when reloading plugins to make sure we don't have * a left-over modal grab for this screen. */ LOCAL_SYMBOL void meta_check_end_modal (MetaScreen *screen) { MetaDisplay *display = meta_screen_get_display (screen); MetaCompositor *compositor = display->compositor; if (compositor->modal_plugin && meta_plugin_get_screen (compositor->modal_plugin) == screen) { meta_end_modal_for_plugin (screen, compositor->modal_plugin, CurrentTime); } } static void after_stage_paint (ClutterStage *stage, gpointer data) { MetaCompositor *compositor = (MetaCompositor*) data; GList *l; for (l = compositor->windows; l; l = l->next) meta_window_actor_post_paint (l->data); } static void redirect_windows (MetaCompositor *compositor, MetaScreen *screen) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); Window xroot = meta_screen_get_xroot (screen); int screen_number = meta_screen_get_screen_number (screen); guint n_retries; guint max_retries; if (meta_get_replace_current_wm ()) max_retries = 5; else max_retries = 1; n_retries = 0; /* Some compositors (like old versions of Muffin) might not properly unredirect * subwindows before destroying the WM selection window; so we wait a while * for such a compositor to exit before giving up. */ while (TRUE) { meta_error_trap_push_with_return (display); XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual); XSync (xdisplay, FALSE); if (!meta_error_trap_pop_with_return (display)) break; if (n_retries == max_retries) { /* This probably means that a non-WM compositor like xcompmgr is running; * we have no way to get it to exit */ meta_fatal ("Another compositing manager is already running on screen %i on display \"%s\".", screen_number, display->name); } n_retries++; g_usleep (G_USEC_PER_SEC); } } LOCAL_SYMBOL void meta_compositor_toggle_send_frame_timings (MetaScreen *screen) { MetaCompositor *compositor = screen->display->compositor; if (meta_prefs_get_send_frame_timings()) { g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "presented", G_CALLBACK (frame_callback), compositor); } else { g_signal_handlers_disconnect_by_func (CLUTTER_STAGE (compositor->stage), frame_callback, NULL); } } void meta_compositor_manage_screen (MetaCompositor *compositor, MetaScreen *screen) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); Window xwin; gint width, height; XWindowAttributes attr; long event_mask; redirect_windows (compositor, screen); /* * We use an empty input region for Clutter as a default because that allows * the user to interact with all the windows displayed on the screen. * We have to initialize compositor->pending_input_region to an empty region explicitly, * because None value is used to mean that the whole screen is an input region. */ compositor->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0); compositor->screen = screen; compositor->output = None; compositor->windows = NULL; meta_screen_set_cm_selection (screen); compositor->stage = clutter_stage_new (); meta_compositor_toggle_send_frame_timings(screen); g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint", G_CALLBACK (after_stage_paint), compositor); clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY); meta_screen_get_size (screen, &width, &height); clutter_actor_realize (compositor->stage); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); XResizeWindow (xdisplay, xwin, width, height); event_mask = FocusChangeMask | ExposureMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PropertyChangeMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask; if (XGetWindowAttributes (xdisplay, xwin, &attr)) { event_mask |= attr.your_event_mask; } XSelectInput (xdisplay, xwin, event_mask); compositor->window_group = meta_window_group_new (screen); compositor->background_actor = meta_background_actor_new_for_screen (screen); compositor->bottom_window_group = clutter_actor_new(); compositor->overlay_group = clutter_actor_new (); compositor->top_window_group = meta_window_group_new (screen); compositor->hidden_group = clutter_actor_new (); clutter_actor_add_child (compositor->window_group, compositor->background_actor); clutter_actor_add_child (compositor->stage, compositor->window_group); clutter_actor_add_child (compositor->stage, compositor->top_window_group); clutter_actor_add_child (compositor->stage, compositor->overlay_group); clutter_actor_add_child (compositor->stage, compositor->hidden_group); clutter_actor_hide (compositor->hidden_group); compositor->plugin_mgr = meta_plugin_manager_new (screen); /* * Delay the creation of the overlay window as long as we can, to avoid * blanking out the screen. This means that during the plugin loading, the * overlay window is not accessible; if the plugin needs to access it * directly, it should hook into the "show" signal on stage, and do * its stuff there. */ compositor->output = get_output_window (screen); XReparentWindow (xdisplay, xwin, compositor->output, 0, 0); /* Make sure there isn't any left-over output shape on the * overlay window by setting the whole screen to be an * output region. * * Note: there doesn't seem to be any real chance of that * because the X server will destroy the overlay window * when the last client using it exits. */ XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); do_set_stage_input_region (screen, compositor->pending_input_region); if (compositor->pending_input_region != None) { XFixesDestroyRegion (xdisplay, compositor->pending_input_region); compositor->pending_input_region = None; } clutter_actor_show (compositor->overlay_group); clutter_actor_show (compositor->stage); /* Map overlay window before redirecting windows offscreen so we catch their * contents until we show the stage. */ XMapWindow (xdisplay, compositor->output); compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay); } void meta_compositor_unmanage_screen (MetaCompositor *compositor, MetaScreen *screen) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); Window xroot = meta_screen_get_xroot (screen); /* This is the most important part of cleanup - we have to do this * before giving up the window manager selection or the next * window manager won't be able to redirect subwindows */ XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); } /* * Shapes the cow so that the given window is exposed, * when metaWindow is NULL it clears the shape again */ static void meta_shape_cow_for_window (MetaScreen *screen, MetaWindow *metaWindow) { MetaDisplay *display = screen->display; MetaCompositor *compositor = display->compositor; Display *xdisplay = display->xdisplay; if (metaWindow == NULL) XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); else { XserverRegion output_region; XRectangle screen_rect, window_bounds; int width, height; MetaRectangle rect; meta_window_get_outer_rect (metaWindow, &rect); window_bounds.x = rect.x; window_bounds.y = rect.y; window_bounds.width = rect.width; window_bounds.height = rect.height; meta_screen_get_size (screen, &width, &height); screen_rect.x = 0; screen_rect.y = 0; screen_rect.width = width; screen_rect.height = height; output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region); XFixesDestroyRegion (xdisplay, output_region); } } void meta_compositor_add_window (MetaCompositor *compositor, MetaWindow *window) { MetaScreen *screen = meta_window_get_screen (window); MetaDisplay *display = meta_screen_get_display (screen); DEBUG_TRACE ("meta_compositor_add_window\n"); meta_error_trap_push (display); add_win (window); meta_error_trap_pop (display); } void meta_compositor_remove_window (MetaCompositor *compositor, MetaWindow *window) { MetaWindowActor *window_actor = NULL; MetaScreen *screen; DEBUG_TRACE ("meta_compositor_remove_window\n"); window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); if (!window_actor) return; screen = window->screen; if (window_actor == compositor->unredirected_window) { meta_window_actor_set_redirected (window_actor, TRUE); meta_shape_cow_for_window (screen, NULL); compositor->unredirected_window = NULL; } meta_window_actor_destroy (window_actor); } void meta_compositor_set_updates_frozen (MetaCompositor *compositor, MetaWindow *window, gboolean updates_frozen) { MetaWindowActor *window_actor; DEBUG_TRACE ("meta_compositor_set_updates_frozen\n"); window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); if (!window_actor) return; meta_window_actor_set_updates_frozen (window_actor, updates_frozen); } void meta_compositor_queue_frame_drawn (MetaCompositor *compositor, MetaWindow *window, gboolean no_delay_frame) { MetaWindowActor *window_actor; DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n"); window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); if (!window_actor) return; meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame); } static gboolean is_grabbed_event (XEvent *event) { switch (event->xany.type) { case ButtonPress: case ButtonRelease: case EnterNotify: case LeaveNotify: case MotionNotify: case KeyPress: case KeyRelease: return TRUE; } return FALSE; } void meta_compositor_window_shape_changed (MetaCompositor *compositor, MetaWindow *window) { MetaWindowActor *window_actor; window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); if (!window_actor) return; meta_window_actor_update_shape (window_actor); } /** * meta_compositor_process_event: (skip) * */ gboolean meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window) { if (compositor->modal_plugin && is_grabbed_event (event)) { MetaPluginClass *klass = META_PLUGIN_GET_CLASS (compositor->modal_plugin); if (klass->xevent_filter) klass->xevent_filter (compositor->modal_plugin, event); /* We always consume events even if the plugin says it didn't handle them; * exclusive is exclusive */ return TRUE; } if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event)) { DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n"); return TRUE; } switch (event->type) { case PropertyNotify: process_property_notify (compositor, (XPropertyEvent *) event, window); break; default: if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify) { /* Core code doesn't handle damage events, so we need to extract the MetaWindow * ourselves */ if (window == NULL) { Window xwin = ((XDamageNotifyEvent *) event)->drawable; window = meta_display_lookup_x_window (compositor->display, xwin); } DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n"); if (window) process_damage (compositor, (XDamageNotifyEvent *) event, window); } break; } if (compositor->have_x11_sync_object) meta_sync_ring_handle_event (event); /* Clutter needs to know about MapNotify events otherwise it will think the stage is invisible */ if (event->type == MapNotify) clutter_x11_handle_event (event); /* The above handling is basically just "observing" the events, so we return * FALSE to indicate that the event should not be filtered out; if we have * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example. */ return FALSE; } void meta_compositor_show_window (MetaCompositor *compositor, MetaWindow *window, MetaCompEffect effect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_show_window\n"); if (!window_actor) return; meta_window_actor_show (window_actor, effect); } void meta_compositor_hide_window (MetaCompositor *compositor, MetaWindow *window, MetaCompEffect effect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_hide_window\n"); if (!window_actor) return; meta_window_actor_hide (window_actor, effect); } void meta_compositor_maximize_window (MetaCompositor *compositor, MetaWindow *window, MetaRectangle *old_rect, MetaRectangle *new_rect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_maximize_window\n"); if (!window_actor) return; meta_window_actor_maximize (window_actor, old_rect, new_rect); } void meta_compositor_unmaximize_window (MetaCompositor *compositor, MetaWindow *window, MetaRectangle *old_rect, MetaRectangle *new_rect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_unmaximize_window\n"); if (!window_actor) return; meta_window_actor_unmaximize (window_actor, old_rect, new_rect); } void meta_compositor_switch_workspace (MetaCompositor *compositor, MetaScreen *screen, MetaWorkspace *from, MetaWorkspace *to, MetaMotionDirection direction) { gint to_indx, from_indx; to_indx = meta_workspace_index (to); from_indx = meta_workspace_index (from); DEBUG_TRACE ("meta_compositor_switch_workspace\n"); compositor->switch_workspace_in_progress++; if (!compositor->plugin_mgr || !meta_plugin_manager_switch_workspace (compositor->plugin_mgr, from_indx, to_indx, direction)) { compositor->switch_workspace_in_progress--; /* We have to explicitely call this to fix up stacking order of the * actors; this is because the abs stacking position of actors does not * necessarily change during the window hiding/unhiding, only their * relative position toward the destkop window. */ meta_finish_workspace_switch (compositor); } } void meta_compositor_tile_window (MetaCompositor *compositor, MetaWindow *window, MetaRectangle *old_rect, MetaRectangle *new_rect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_tile_window\n"); if (!window_actor) return; meta_window_actor_tile (window_actor, old_rect, new_rect); } static void sync_actor_stacking (MetaCompositor *compositor) { GList *children; GList *tmp; GList *old; gboolean reordered; /* NB: The first entries in the lists are stacked the lowest */ /* Restacking will trigger full screen redraws, so it's worth a * little effort to make sure we actually need to restack before * we go ahead and do it */ children = clutter_actor_get_children (compositor->window_group); reordered = FALSE; old = children; /* We allow for actors in the window group other than the actors we * know about, but it's up to a plugin to try and keep them stacked correctly * (we really need extra API to make that reliable.) */ /* Of the actors we know, the bottom actor should be the background actor */ while (old && old->data != compositor->background_actor && !META_IS_WINDOW_ACTOR (old->data)) old = old->next; if (old == NULL || old->data != compositor->background_actor) { reordered = TRUE; goto done_with_check; } /* Then the window actors should follow in sequence */ old = old->next; for (tmp = compositor->windows; tmp != NULL; tmp = tmp->next) { while (old && !META_IS_WINDOW_ACTOR (old->data)) old = old->next; /* old == NULL: someone reparented a window out of the window group, * order undefined, always restack */ if (old == NULL || old->data != tmp->data) { reordered = TRUE; goto done_with_check; } old = old->next; } done_with_check: g_list_free (children); if (!reordered) return; ClutterActor *parent; for (tmp = g_list_last (compositor->windows); tmp != NULL; tmp = tmp->prev) { ClutterActor *actor = tmp->data; parent = clutter_actor_get_parent (actor); clutter_actor_set_child_below_sibling (parent, actor, NULL); } parent = clutter_actor_get_parent (compositor->background_actor); clutter_actor_set_child_below_sibling (parent, compositor->background_actor, NULL); } void meta_compositor_sync_stack (MetaCompositor *compositor, MetaScreen *screen, GList *stack) { GList *old_stack; DEBUG_TRACE ("meta_compositor_sync_stack\n"); /* This is painful because hidden windows that we are in the process * of animating out of existence. They'll be at the bottom of the * stack of X windows, but we want to leave them in their old position * until the animation effect finishes. */ /* Sources: first window is the highest */ stack = g_list_copy (stack); /* The new stack of MetaWindow */ old_stack = g_list_reverse (compositor->windows); /* The old stack of MetaWindowActor */ compositor->windows = NULL; while (TRUE) { MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor; MetaWindow *old_window = NULL, *stack_window = NULL, *window; /* Find the remaining top actor in our existing stack (ignoring * windows that have been hidden and are no longer animating) */ while (old_stack) { old_actor = old_stack->data; old_window = meta_window_actor_get_meta_window (old_actor); if ((old_window->hidden || old_window->unmanaging) && !meta_window_actor_effect_in_progress (old_actor)) { old_stack = g_list_delete_link (old_stack, old_stack); old_actor = NULL; } else break; } /* And the remaining top actor in the new stack */ while (stack) { stack_window = stack->data; stack_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (stack_window)); if (!stack_actor) { meta_verbose ("Failed to find corresponding MetaWindowActor " "for window %s\n", meta_window_get_description (stack_window)); stack = g_list_delete_link (stack, stack); } else break; } if (!old_actor && !stack_actor) /* Nothing more to stack */ break; /* We usually prefer the window in the new stack, but if if we * found a hidden window in the process of being animated out * of existence in the old stack we use that instead. We've * filtered out non-animating hidden windows above. */ if (old_actor && (!stack_actor || old_window->hidden || old_window->unmanaging)) { actor = old_actor; window = old_window; } else { actor = stack_actor; window = stack_window; } /* OK, we know what actor we want next. Add it to our window * list, and remove it from both source lists. (It will * be at the front of at least one, hopefully it will be * near the front of the other.) */ compositor->windows = g_list_prepend (compositor->windows, actor); stack = g_list_remove (stack, window); old_stack = g_list_remove (old_stack, actor); } sync_actor_stacking (compositor); } void meta_compositor_sync_window_geometry (MetaCompositor *compositor, MetaWindow *window, gboolean did_placement) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_sync_window_geometry\n"); if (!window_actor) return; meta_window_actor_sync_actor_geometry (window_actor, did_placement); } void meta_compositor_sync_screen_size (MetaCompositor *compositor, MetaScreen *screen, guint width, guint height) { MetaDisplay *display = compositor->display; Display *xdisplay; Window xwin; DEBUG_TRACE ("meta_compositor_sync_screen_size\n"); xdisplay = meta_display_get_xdisplay (display); xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); XResizeWindow (xdisplay, xwin, width, height); meta_background_actor_screen_size_changed (screen); meta_verbose ("Changed size for stage on screen %d to %dx%d\n", meta_screen_get_screen_number (screen), width, height); } static void frame_callback (ClutterStage *stage, CoglFrameEvent event, ClutterFrameInfo *frame_info, MetaCompositor *compositor) { GList *l; if (event == COGL_FRAME_EVENT_COMPLETE) { gint64 presentation_time_cogl = frame_info->presentation_time; gint64 presentation_time; if (presentation_time_cogl != 0) { /* Cogl reports presentation in terms of its own clock, which is * guaranteed to be in nanoseconds but with no specified base. The * normal case with the open source GPU drivers on Linux 3.8 and * newer is that the base of cogl_get_clock_time() is that of * clock_gettime(CLOCK_MONOTONIC), so the same as g_get_monotonic_time), * but there's no exposure of that through the API. clock_gettime() * is fairly fast, so calling it twice and subtracting to get a * nearly-zero number is acceptable, if a litle ugly. */ gint64 current_cogl_time = cogl_get_clock_time (compositor->context); gint64 current_monotonic_time = g_get_monotonic_time (); presentation_time = current_monotonic_time + (presentation_time_cogl - current_cogl_time) / 1000; } else { presentation_time = 0; } for (l = compositor->windows; l; l = l->next) meta_window_actor_frame_complete (l->data, frame_info, presentation_time); } } static gboolean meta_pre_paint_func (gpointer data) { GList *l; MetaCompositor *compositor = data; GSList *screens = compositor->display->screens; MetaWindowActor *top_window = NULL; MetaWindowActor *expected_unredirected_window = NULL; if (compositor->windows == NULL) return TRUE; for (l = g_list_last (compositor->windows); l; l = l->prev) { MetaRectangle *rect = &meta_window_actor_get_meta_window (l->data)->rect; if (rect->x + rect->width > 0 && rect->y + rect->height > 0) { top_window = l->data; break; } } if (top_window != NULL && meta_window_actor_should_unredirect (top_window) && compositor->disable_unredirect_count == 0) expected_unredirected_window = top_window; if (compositor->unredirected_window != expected_unredirected_window) { if (compositor->unredirected_window != NULL) { meta_window_actor_set_redirected (compositor->unredirected_window, TRUE); meta_shape_cow_for_window (compositor->display->active_screen, NULL); } if (expected_unredirected_window != NULL) { meta_shape_cow_for_window (compositor->display->active_screen, meta_window_actor_get_meta_window (top_window)); meta_window_actor_set_redirected (top_window, FALSE); } compositor->unredirected_window = expected_unredirected_window; } for (l = compositor->windows; l; l = l->next) meta_window_actor_pre_paint (l->data); if (compositor->frame_has_updated_xsurfaces) { /* We need to make sure that any X drawing that happens before * the XDamageSubtract() for each window above is visible to * subsequent GL rendering; the standardized way to do this is * GL_EXT_X11_sync_object. Since this isn't implemented yet in * mesa, we also have a path that relies on the implementation * of the open source drivers. * * Anything else, we just hope for the best. * * Xorg and open source driver specifics: * * The X server makes sure to flush drawing to the kernel before * sending out damage events, but since we use * DamageReportBoundingBox there may be drawing between the last * damage event and the XDamageSubtract() that needs to be * flushed as well. * * Xorg always makes sure that drawing is flushed to the kernel * before writing events or responses to the client, so any * round trip request at this point is sufficient to flush the * GLX buffers. */ if (compositor->have_x11_sync_object) compositor->have_x11_sync_object = meta_sync_ring_insert_wait (); else XSync (compositor->display->xdisplay, False); } return TRUE; } static gboolean meta_post_paint_func (gpointer data) { MetaCompositor *compositor = data; CoglGraphicsResetStatus status; if (compositor->frame_has_updated_xsurfaces) { if (compositor->have_x11_sync_object) compositor->have_x11_sync_object = meta_sync_ring_after_frame (); compositor->frame_has_updated_xsurfaces = FALSE; } status = cogl_get_graphics_reset_status (compositor->context); switch (status) { case COGL_GRAPHICS_RESET_STATUS_NO_ERROR: break; case COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET: g_signal_emit_by_name (compositor->display, "gl-video-memory-purged"); clutter_actor_queue_redraw (CLUTTER_ACTOR (compositor->stage)); break; default: /* The ARB_robustness spec says that, on error, the application should destroy the old context and create a new one. Since we don't have the necessary plumbing to do this we'll simply restart the process. Obviously we can't do this when we are a wayland compositor but in that case we shouldn't get here since we don't enable robustness in that case. */ meta_restart (); break; } return TRUE; } void meta_compositor_on_shadow_factory_changed (void) { GList *l; for (l = compositor_global->windows; l; l = l->next) meta_window_actor_invalidate_shadow (l->data); } /** * meta_compositor_new: (skip) * */ MetaCompositor * meta_compositor_new (MetaDisplay *display) { char *atom_names[] = { "_XROOTPMAP_ID", "_XSETROOT_ID", "_NET_WM_WINDOW_OPACITY", }; Atom atoms[G_N_ELEMENTS(atom_names)]; MetaCompositor *compositor; Display *xdisplay = meta_display_get_xdisplay (display); if (!composite_at_least_version (display, 0, 3)) return NULL; compositor = g_new0 (MetaCompositor, 1); compositor->display = display; compositor->context = clutter_backend_get_cogl_context (clutter_get_default_backend ()); if (g_getenv("META_DISABLE_MIPMAPS")) compositor->no_mipmaps = TRUE; meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names)); XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names), False, atoms); compositor->atom_x_root_pixmap = atoms[0]; compositor->atom_x_set_root = atoms[1]; compositor->atom_net_wm_window_opacity = atoms[2]; compositor->pre_paint_func_id = clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT, meta_pre_paint_func, compositor, NULL); compositor->post_paint_func_id = clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT, meta_post_paint_func, compositor, NULL); compositor_global = compositor; return compositor; } /** * meta_get_overlay_window: (skip) * */ Window meta_get_overlay_window (MetaScreen *screen) { return screen->display->compositor->output; } /** * meta_disable_unredirect_for_screen: * @screen: a #MetaScreen * * Disables unredirection, can be usefull in situations where having * unredirected windows is undesireable like when recording a video. * */ void meta_disable_unredirect_for_screen (MetaScreen *screen) { MetaCompositor *compositor = screen->display->compositor; compositor->disable_unredirect_count = compositor->disable_unredirect_count + 1; } /** * meta_enable_unredirect_for_screen: * @screen: a #MetaScreen * * Enables unredirection which reduces the overhead for apps like games. * */ void meta_enable_unredirect_for_screen (MetaScreen *screen) { MetaCompositor *compositor = screen->display->compositor; if (compositor->disable_unredirect_count == 0) g_warning ("Called enable_unredirect_for_screen while unredirection is enabled."); if (compositor->disable_unredirect_count > 0) compositor->disable_unredirect_count = compositor->disable_unredirect_count - 1; } #define FLASH_TIME_MS 50 static void flash_out_completed (ClutterTimeline *timeline, gboolean is_finished, gpointer user_data) { ClutterActor *flash = CLUTTER_ACTOR (user_data); clutter_actor_destroy (flash); } void meta_compositor_flash_screen (MetaCompositor *compositor, MetaScreen *screen) { ClutterActor *stage; ClutterActor *flash; ClutterTransition *transition; gfloat width, height; stage = meta_get_stage_for_screen (screen); clutter_actor_get_size (stage, &width, &height); flash = clutter_actor_new (); clutter_actor_set_background_color (flash, CLUTTER_COLOR_Black); clutter_actor_set_size (flash, width, height); clutter_actor_set_opacity (flash, 0); clutter_actor_add_child (stage, flash); clutter_actor_save_easing_state (flash); clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD); clutter_actor_set_easing_duration (flash, FLASH_TIME_MS); clutter_actor_set_opacity (flash, 192); transition = clutter_actor_get_transition (flash, "opacity"); clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2); g_signal_connect (transition, "stopped", G_CALLBACK (flash_out_completed), flash); clutter_actor_restore_easing_state (flash); } void meta_compositor_show_tile_preview (MetaCompositor *compositor, MetaScreen *screen, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number, guint snap_queued) { meta_plugin_manager_show_tile_preview (compositor->plugin_mgr, window, tile_rect, tile_monitor_number, snap_queued); } void meta_compositor_hide_tile_preview (MetaCompositor *compositor, MetaScreen *screen) { meta_plugin_manager_hide_tile_preview (compositor->plugin_mgr); } void meta_compositor_show_hud_preview (MetaCompositor *compositor, MetaScreen *screen, guint current_proximity_zone, MetaRectangle *work_area, guint snap_queued) { meta_plugin_manager_show_hud_preview (compositor->plugin_mgr, current_proximity_zone, work_area, snap_queued); } void meta_compositor_hide_hud_preview (MetaCompositor *compositor, MetaScreen *screen) { meta_plugin_manager_hide_hud_preview (compositor->plugin_mgr); } /** * meta_compositor_monotonic_time_to_server_time: * @display: a #MetaDisplay * @monotonic_time: time in the units of g_get_monotonic_time() * * _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages represent time * as a "high resolution server time" - this is the server time interpolated * to microsecond resolution. The advantage of this time representation * is that if X server is running on the same computer as a client, and * the Xserver uses 'clock_gettime(CLOCK_MONOTONIC, ...)' for the server * time, the client can detect this, and all such clients will share a * a time representation with high accuracy. If there is not a common * time source, then the time synchronization will be less accurate. */ gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display, gint64 monotonic_time) { MetaCompositor *compositor = display->compositor; if (compositor->server_time_query_time == 0 || (!compositor->server_time_is_monotonic_time && monotonic_time > compositor->server_time_query_time + 10*1000*1000)) /* 10 seconds */ { guint32 server_time = meta_display_get_current_time_roundtrip (display); gint64 server_time_usec = (gint64)server_time * 1000; gint64 current_monotonic_time = g_get_monotonic_time (); compositor->server_time_query_time = current_monotonic_time; /* If the server time is within a second of the monotonic time, * we assume that they are identical. This seems like a big margin, * but we want to be as robust as possible even if the system * is under load and our processing of the server response is * delayed. */ if (server_time_usec > current_monotonic_time - 1000*1000 && server_time_usec < current_monotonic_time + 1000*1000) compositor->server_time_is_monotonic_time = TRUE; compositor->server_time_offset = server_time_usec - current_monotonic_time; } if (compositor->server_time_is_monotonic_time) return monotonic_time; else return monotonic_time + compositor->server_time_offset; } void meta_compositor_grab_op_begin (MetaCompositor *compositor) { // CLUTTER_ACTOR_NO_LAYOUT set on the window group improves responsiveness of windows, // but causes windows to flicker in and out of view sporadically on some configurations // while dragging windows. Make sure it is disabled during the grab. clutter_actor_unset_flags (compositor->window_group, CLUTTER_ACTOR_NO_LAYOUT); } void meta_compositor_grab_op_end (MetaCompositor *compositor) { clutter_actor_set_flags (compositor->window_group, CLUTTER_ACTOR_NO_LAYOUT); } CoglContext * meta_compositor_get_cogl_context (void) { return compositor_global->context; } void meta_compositor_update_sync_state (MetaCompositor *compositor, MetaSyncMethod method) { clutter_stage_x11_update_sync_state (compositor->stage, method); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/region-utils.c����������������������������������������������������������0000664�0001750�0001750�00000024514�14211404421�020714� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #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 */ LOCAL_SYMBOL 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; } } LOCAL_SYMBOL gboolean meta_region_iterator_at_end (MetaRegionIterator *iter) { return iter->i >= iter->n_rectangles; } LOCAL_SYMBOL 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 */ LOCAL_SYMBOL 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; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-window-group.h�����������������������������������������������������0000664�0001750�0001750�00000004650�14211404421�021664� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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 */ ����������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-window-shape.c�����������������������������������������������������0000664�0001750�0001750�00000016212�14211404421�021620� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #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; }; LOCAL_SYMBOL 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; } LOCAL_SYMBOL MetaWindowShape * meta_window_shape_ref (MetaWindowShape *shape) { shape->ref_count++; return shape; } LOCAL_SYMBOL void meta_window_shape_unref (MetaWindowShape *shape) { shape->ref_count--; if (shape->ref_count == 0) { free (shape->rectangles); g_slice_free (MetaWindowShape, shape); } } LOCAL_SYMBOL guint meta_window_shape_hash (MetaWindowShape *shape) { return shape->hash; } LOCAL_SYMBOL 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; } LOCAL_SYMBOL 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 */ LOCAL_SYMBOL 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; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-background-actor-private.h�����������������������������������������0000664�0001750�0001750�00000001117�14211404421�024113� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ #ifndef META_BACKGROUND_ACTOR_PRIVATE_H #define META_BACKGROUND_ACTOR_PRIVATE_H #include <meta/screen.h> #include <meta/meta-background-actor.h> #include "meta-background.h" void meta_background_actor_set_visible_region (MetaBackgroundActor *self, cairo_region_t *visible_region); void meta_background_actor_update (MetaScreen *screen); void meta_background_actor_screen_size_changed (MetaScreen *screen); #endif /* META_BACKGROUND_ACTOR_PRIVATE_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-module.c�����������������������������������������������������������0000664�0001750�0001750�00000012221�14211404421�020474� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #include <meta/meta-plugin.h> #include "meta-module.h" #include <gmodule.h> enum { PROP_0, PROP_PATH, }; struct _MetaModulePrivate { GModule *lib; gchar *path; GType plugin_type; }; #define META_MODULE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_MODULE, MetaModulePrivate)) G_DEFINE_TYPE (MetaModule, meta_module, G_TYPE_TYPE_MODULE); static gboolean meta_module_load (GTypeModule *gmodule) { MetaModulePrivate *priv = META_MODULE (gmodule)->priv; MetaPluginVersion *info = NULL; GType (*register_type) (GTypeModule *) = NULL; if (priv->lib && priv->plugin_type) return TRUE; g_assert (priv->path); if (!priv->lib && !(priv->lib = g_module_open (priv->path, 0))) { g_warning ("Could not load library [%s (%s)]", priv->path, g_module_error ()); return FALSE; } if (g_module_symbol (priv->lib, "meta_plugin_version", (gpointer *)(void *)&info) && g_module_symbol (priv->lib, "meta_plugin_register_type", (gpointer *)(void *)®ister_type) && info && register_type) { if (info->version_api != MUFFIN_PLUGIN_API_VERSION) g_warning ("Plugin API mismatch for [%s]", priv->path); else { GType plugin_type; if (!(plugin_type = register_type (gmodule))) { g_warning ("Could not register type for plugin %s", priv->path); return FALSE; } else { priv->plugin_type = plugin_type; } return TRUE; } } else g_warning ("Broken plugin module [%s]", priv->path); return FALSE; } static void meta_module_unload (GTypeModule *gmodule) { MetaModulePrivate *priv = META_MODULE (gmodule)->priv; g_module_close (priv->lib); priv->lib = NULL; priv->plugin_type = 0; } static void meta_module_dispose (GObject *object) { G_OBJECT_CLASS (meta_module_parent_class)->dispose (object); } static void meta_module_finalize (GObject *object) { MetaModulePrivate *priv = META_MODULE (object)->priv; free (priv->path); priv->path = NULL; G_OBJECT_CLASS (meta_module_parent_class)->finalize (object); } static void meta_module_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MetaModulePrivate *priv = META_MODULE (object)->priv; switch (prop_id) { case PROP_PATH: free (priv->path); priv->path = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_module_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MetaModulePrivate *priv = META_MODULE (object)->priv; switch (prop_id) { case PROP_PATH: g_value_set_string (value, priv->path); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_module_class_init (MetaModuleClass *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; gmodule_class->load = meta_module_load; gmodule_class->unload = meta_module_unload; g_object_class_install_property (gobject_class, PROP_PATH, g_param_spec_string ("path", "Path", "Load path", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (gobject_class, sizeof (MetaModulePrivate)); } static void meta_module_init (MetaModule *self) { MetaModulePrivate *priv; self->priv = priv = META_MODULE_GET_PRIVATE (self); } LOCAL_SYMBOL GType meta_module_get_plugin_type (MetaModule *module) { MetaModulePrivate *priv = META_MODULE (module)->priv; return priv->plugin_type; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/cogl-utils.c������������������������������������������������������������0000664�0001750�0001750�00000020155�14211404421�020352� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #include <clutter/clutter.h> #include "cogl-utils.h" #include "meta-sync-ring.h" #include <meta/errors.h> #include <gdk/gdk.h> /** * meta_create_color_texture_4ub: * @red: * @green: * @blue: * @alpha: * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE; * %COGL_TEXTURE_NO_SLICING is useful if the texture will be * repeated to create a constant color fill, since hardware * repeat can't be used for a sliced texture. * * Creates a texture that is a single pixel with the specified * unpremultiplied color components. * * Return value: (transfer full): a newly created Cogl texture */ CoglTexture * meta_create_color_texture_4ub (guint8 red, guint8 green, guint8 blue, guint8 alpha, CoglTextureFlags flags) { CoglColor color; guint8 pixel[4]; cogl_color_init_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, flags, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_ANY, 4, pixel); } CoglPipeline * meta_create_texture_pipeline (CoglTexture *src_texture) { static CoglPipeline *texture_pipeline_template = NULL; CoglPipeline *pipeline; /* We use a pipeline that has a dummy texture as a base for all texture pipelines. The idea is that only the Cogl texture object would be different in the children so it is likely that Cogl will be able to share GL programs between all the textures. */ if (G_UNLIKELY (texture_pipeline_template == NULL)) { CoglTexture *dummy_texture; dummy_texture = meta_create_color_texture_4ub (0xff, 0xff, 0xff, 0xff, COGL_TEXTURE_NONE); texture_pipeline_template = cogl_pipeline_new (meta_compositor_get_cogl_context ()); cogl_pipeline_set_layer_texture (texture_pipeline_template, 0, dummy_texture); cogl_object_unref (dummy_texture); } pipeline = cogl_pipeline_copy (texture_pipeline_template); if (src_texture != NULL) cogl_pipeline_set_layer_texture (pipeline, 0, src_texture); return pipeline; } /********************************************************************************************/ /********************************* CoglTexture2d wrapper ************************************/ static gboolean supports_npot = FALSE; static gboolean npot_sizes_checked = FALSE; static gint screen_width = 0; static gint screen_height = 0; gboolean meta_cogl_hardware_supports_npot_sizes (void) { if (npot_sizes_checked) return supports_npot; supports_npot = cogl_has_feature (meta_compositor_get_cogl_context (), COGL_FEATURE_ID_TEXTURE_NPOT); npot_sizes_checked = TRUE; return supports_npot; } inline static void clamp_sizes (gint *width, gint *height) { if (screen_width == 0) { GdkScreen *screen = gdk_screen_get_default (); screen_width = gdk_screen_get_width (screen); screen_height = gdk_screen_get_height (screen); } *width = MIN (*width, screen_width * 2); *height = MIN (*height, screen_height * 2); } /** * meta_cogl_texture_new_from_data_wrapper: (skip) * * Decides whether to use the newer (apparently safer) * cogl_texture_2d_new_from_data or the older cogl_texture_new_from_data * depending on if the GPU supports it. */ CoglTexture * meta_cogl_texture_new_from_data_wrapper (int width, int height, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, int rowstride, const uint8_t *data) { CoglTexture *texture = NULL; clamp_sizes (&width, &height); if (supports_npot) { CoglError *error = NULL; texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (meta_compositor_get_cogl_context (), width, height, format, rowstride, data, &error)); if (error) { meta_verbose ("cogl_texture_2d_new_from_data failed: %s\n", error->message); cogl_error_free (error); } } else { texture = cogl_texture_new_from_data (width, height, flags, format, internal_format, rowstride, data); } return texture; } static CoglTexture * meta_cogl_rectangle_new_compat (unsigned int width, unsigned int height, CoglPixelFormat format, unsigned int rowstride, const guint8 *data) { ClutterBackend *backend = clutter_get_default_backend (); CoglContext *context = clutter_backend_get_cogl_context (backend); CoglTextureRectangle *tex_rect; tex_rect = cogl_texture_rectangle_new_with_size (context, width, height); if (tex_rect == NULL) return NULL; if (data) cogl_texture_set_region (COGL_TEXTURE (tex_rect), 0, 0, /* src_x/y */ 0, 0, /* dst_x/y */ width, height, /* dst_width/height */ width, height, /* width/height */ format, rowstride, data); return COGL_TEXTURE (tex_rect); } CoglTexture * meta_cogl_rectangle_new (int width, int height, CoglPixelFormat format, int stride, const uint8_t *data) { if (!supports_npot) return meta_cogl_rectangle_new_compat (width, height, format, stride, data); CoglTexture *texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (meta_compositor_get_cogl_context (), width, height)); cogl_texture_set_components (texture, COGL_TEXTURE_COMPONENTS_A); cogl_texture_set_region (texture, 0, 0, /* src_x/y */ 0, 0, /* dst_x/y */ width, height, /* dst_width/height */ width, height, /* width/height */ format, stride, data); return texture; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/region-utils.h����������������������������������������������������������0000664�0001750�0001750�00000004753�14211404421�020724� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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__ */ ���������������������muffin-5.2.1/src/compositor/meta-window-group.c�����������������������������������������������������0000664�0001750�0001750�00000026534�14211404421�021664� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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 <core/screen-private.h> #include "clutter-utils.h" #include "compositor-private.h" #include "meta-window-actor-private.h" #include "meta-window-group.h" #include "meta-background-actor-private.h" struct _MetaWindowGroupClass { ClutterActorClass parent_class; }; struct _MetaWindowGroup { ClutterActor parent; MetaScreen *screen; }; G_DEFINE_TYPE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_ACTOR); /* Help macros to scale from OpenGL <-1,1> coordinates system to * window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c */ #define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) #define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) /* Check if we're painting the MetaWindowGroup "untransformed". This can * differ from the result of actor_is_untransformed(window_group) if we're * inside a clone paint. The integer translation, if any, is returned. */ static gboolean painting_untransformed (MetaWindowGroup *window_group, int *x_origin, int *y_origin) { CoglMatrix modelview, projection, modelview_projection; ClutterVertex vertices[4]; int width, height; float viewport[4]; int i; cogl_get_modelview_matrix (&modelview); cogl_get_projection_matrix (&projection); cogl_matrix_multiply (&modelview_projection, &projection, &modelview); meta_screen_get_size (window_group->screen, &width, &height); vertices[0].x = 0; vertices[0].y = 0; vertices[0].z = 0; vertices[1].x = width; vertices[1].y = 0; vertices[1].z = 0; vertices[2].x = 0; vertices[2].y = height; vertices[2].z = 0; vertices[3].x = width; vertices[3].y = height; vertices[3].z = 0; cogl_get_viewport (viewport); for (i = 0; i < 4; i++) { float w = 1; cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w); vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w, viewport[2], viewport[0]); vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w, viewport[3], viewport[1]); } return meta_actor_vertices_are_untransformed (vertices, width, height, x_origin, y_origin); } static void meta_window_group_cull_out (MetaWindowGroup *group, ClutterActor *unredirected_window, gboolean has_unredirected_window, cairo_region_t *unobscured_region, cairo_region_t *clip_region) { ClutterActor *actor = CLUTTER_ACTOR (group); ClutterActor *child; ClutterActorIter iter; /* 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. */ clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_prev (&iter, &child)) { if (!CLUTTER_ACTOR_IS_VISIBLE (child)) continue; if (has_unredirected_window && child == unredirected_window) continue; /* If an actor has effects applied, then that can change the area * it paints and the opacity, so we no longer can figure out what * portion of the actor is obscured and what portion of the screen * it obscures, so we skip the actor. * * This has a secondary beneficial effect: if a ClutterOffscreenEffect * is applied to an actor, then our clipped redraws interfere with the * caching of the FBO - even if we only need to draw a small portion * of the window right now, ClutterOffscreenEffect may use other portions * of the FBO later. So, skipping actors with effects applied also * prevents these bugs. * * Theoretically, we should check clutter_actor_get_offscreen_redirect() * as well for the same reason, but omitted for simplicity in the * hopes that no-one will do that. */ if (clutter_actor_has_effects (child)) continue; if (META_IS_WINDOW_ACTOR (child)) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (child); int x, y; if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y)) continue; /* Temporarily move to the coordinate system of the actor */ cairo_region_translate (unobscured_region, - x, - y); cairo_region_translate (clip_region, - x, - y); meta_window_actor_set_unobscured_region (window_actor, unobscured_region); meta_window_actor_set_visible_region (window_actor, clip_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 (unobscured_region, obscured_region); cairo_region_subtract (clip_region, obscured_region); } } meta_window_actor_set_visible_region_beneath (window_actor, clip_region); cairo_region_translate (unobscured_region, x, y); cairo_region_translate (clip_region, x, y); } else if (META_IS_BACKGROUND_ACTOR (child)) { int x, y; if (!meta_actor_is_untransformed (child, &x, &y)) continue; cairo_region_translate (clip_region, - x, - y); meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (child), clip_region); cairo_region_translate (clip_region, x, y); } } } static void meta_window_group_reset_culling (MetaWindowGroup *group) { ClutterActor *actor = CLUTTER_ACTOR (group); ClutterActor *child; ClutterActorIter iter; /* Now that we are done painting, unset the visible regions (they will * mess up painting clones of our actors) */ clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { if (META_IS_WINDOW_ACTOR (child)) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (child); meta_window_actor_reset_visible_regions (window_actor); } else if (META_IS_BACKGROUND_ACTOR (child)) { MetaBackgroundActor *background_actor = META_BACKGROUND_ACTOR (child); meta_background_actor_set_visible_region (background_actor, NULL); } } } static void meta_window_group_paint (ClutterActor *actor) { cairo_region_t *clip_region; cairo_region_t *unobscured_region; ClutterActorIter iter; ClutterActor *child; cairo_rectangle_int_t visible_rect, clip_rect; int paint_x_offset, paint_y_offset; int paint_x_origin, paint_y_origin; int actor_x_origin, actor_y_origin; MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); MetaCompositor *compositor = window_group->screen->display->compositor; ClutterActor *stage = CLUTTER_STAGE (compositor->stage); /* Start off by treating all windows as completely unobscured, so damage anywhere * in a window queues redraws, but confine it more below. */ clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { if (META_IS_WINDOW_ACTOR (child)) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (child); meta_window_actor_set_unobscured_region (window_actor, NULL); } } /* Normally we expect an actor to be drawn at it's position on the screen. * However, if we're inside the paint of a ClutterClone, that won't be the * case and we need to compensate. We look at the position of the window * group under the current model-view matrix and the position of the actor. * If they are both simply integer translations, then we can compensate * easily, otherwise we give up. * * Possible cleanup: work entirely in paint space - we can compute the * combination of the model-view matrix with the local matrix for each child * actor and get a total transformation for that actor for how we are * painting currently, and never worry about how actors are positioned * on the stage. */ if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) || !meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin)) { CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor); return; } paint_x_offset = paint_x_origin - actor_x_origin; paint_y_offset = paint_y_origin - actor_y_origin; visible_rect.x = visible_rect.y = 0; visible_rect.width = clutter_actor_get_width (stage); visible_rect.height = clutter_actor_get_height (stage); unobscured_region = cairo_region_create_rectangle (&visible_rect); /* Get the clipped redraw bounds from Clutter so that we can avoid * painting shadows on windows that don't need to be painted in this * frame. In the case of a multihead setup with mismatched monitor * sizes, we could intersect this with an accurate union of the * monitors to avoid painting shadows that are visible only in the * holes. */ clutter_stage_get_redraw_clip_bounds (stage, &clip_rect); clip_region = cairo_region_create_rectangle (&clip_rect); cairo_region_translate (clip_region, -paint_x_offset, -paint_y_offset); gboolean has_unredirected_window = compositor->unredirected_window != NULL; if (has_unredirected_window) { cairo_rectangle_int_t unredirected_rect; MetaWindow *window = meta_window_actor_get_meta_window (compositor->unredirected_window); meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect); cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect); cairo_region_subtract_rectangle (clip_region, &unredirected_rect); } meta_window_group_cull_out (window_group, CLUTTER_ACTOR (compositor->unredirected_window), has_unredirected_window, unobscured_region, clip_region); cairo_region_destroy (unobscured_region); cairo_region_destroy (clip_region); CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor); meta_window_group_reset_culling (window_group); } static gboolean meta_window_group_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { return clutter_paint_volume_set_from_allocation (volume, actor); } static void meta_window_group_class_init (MetaWindowGroupClass *klass) { ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); actor_class->paint = meta_window_group_paint; actor_class->get_paint_volume = meta_window_group_get_paint_volume; } static void meta_window_group_init (MetaWindowGroup *window_group) { ClutterActor *actor = CLUTTER_ACTOR (window_group); clutter_actor_set_flags (actor, CLUTTER_ACTOR_NO_LAYOUT); } LOCAL_SYMBOL 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); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/clutter-utils.c���������������������������������������������������������0000664�0001750�0001750�00000015370�14211404421�021113� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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, see <http://www.gnu.org/licenses/>. */ #include "clutter-utils.h" #include <math.h> /* This file uses pixel-aligned region computation to determine what * can be clipped out. This only really works if everything is aligned * to the pixel grid - not scaled or rotated and at integer offsets. * * (This could be relaxed - if we turned off filtering for unscaled * windows then windows would be, by definition aligned to the pixel * grid. And for rectangular windows without a shape, the outline that * we draw for an unrotated window is always a rectangle because we * don't use antialasing for the window boundary - with or without * filtering, with or without a scale. But figuring out exactly * what pixels will be drawn by the graphics system in these cases * gets tricky, so we just go for the easiest part - no scale, * and at integer offsets.) * * The way we check for pixel-aligned is by looking at the * transformation into screen space of the allocation box of an actor * and and checking if the corners are "close enough" to integral * pixel values. */ /* The definition of "close enough" to integral pixel values is * equality when we convert to 24.8 fixed-point. */ static inline int round_to_fixed (float x) { return roundf (x * 256); } /* Help macros to scale from OpenGL <-1,1> coordinates system to * window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c */ #define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) #define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) /* This helper function checks if (according to our fixed point precision) * the vertices @verts form a box of width @widthf and height @heightf * located at integral coordinates. These coordinates are returned * in @x_origin and @y_origin. */ gboolean meta_actor_vertices_are_untransformed (ClutterVertex *verts, float widthf, float heightf, int *x_origin, int *y_origin) { int width, height; int v0x, v0y, v1x, v1y, v2x, v2y, v3x, v3y; int x, y; width = round_to_fixed (widthf); height = round_to_fixed (heightf); 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; if (x_origin) *x_origin = x; if (y_origin) *y_origin = y; return TRUE; } /* Check if an actor is "untransformed" - which actually means transformed by * at most a integer-translation. The integer translation, if any, is returned. */ gboolean meta_actor_is_untransformed (ClutterActor *actor, int *x_origin, int *y_origin) { gfloat widthf, heightf; ClutterVertex verts[4]; clutter_actor_get_size (actor, &widthf, &heightf); clutter_actor_get_abs_allocation_vertices (actor, verts); return meta_actor_vertices_are_untransformed (verts, widthf, heightf, x_origin, y_origin); } /** * meta_actor_painting_untransformed: * @paint_width: the width of the painted area * @paint_height: the height of the painted area * @x_origin: if the transform is only an integer translation * then the X coordinate of the location of the origin under the transformation * from drawing space to screen pixel space is returned here. * @y_origin: if the transform is only an integer translation * then the X coordinate of the location of the origin under the transformation * from drawing space to screen pixel space is returned here. * * Determines if the current painting transform is an integer translation. * This can differ from the result of meta_actor_is_untransformed() when * painting an actor if we're inside a inside a clone paint. @paint_width * and @paint_height are used to determine the vertices of the rectangle * we check to see if the painted area is "close enough" to the integer * transform. */ gboolean meta_actor_painting_untransformed (int paint_width, int paint_height, int *x_origin, int *y_origin) { CoglMatrix modelview, projection, modelview_projection; ClutterVertex vertices[4]; float viewport[4]; int i; cogl_get_modelview_matrix (&modelview); cogl_get_projection_matrix (&projection); cogl_matrix_multiply (&modelview_projection, &projection, &modelview); vertices[0].x = 0; vertices[0].y = 0; vertices[0].z = 0; vertices[1].x = paint_width; vertices[1].y = 0; vertices[1].z = 0; vertices[2].x = 0; vertices[2].y = paint_height; vertices[2].z = 0; vertices[3].x = paint_width; vertices[3].y = paint_height; vertices[3].z = 0; cogl_get_viewport (viewport); for (i = 0; i < 4; i++) { float w = 1; cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w); vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w, viewport[2], viewport[0]); vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w, viewport[3], viewport[1]); } return meta_actor_vertices_are_untransformed (vertices, paint_width, paint_height, x_origin, y_origin); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/clutter-utils.h���������������������������������������������������������0000664�0001750�0001750�00000003320�14211404421�021110� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Utilities for use with Clutter * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __META_CLUTTER_UTILS_H__ #define __META_CLUTTER_UTILS_H__ #include <clutter/clutter.h> gboolean meta_actor_vertices_are_untransformed (ClutterVertex *verts, float widthf, float heightf, int *x_origin, int *y_origin); gboolean meta_actor_is_untransformed (ClutterActor *actor, int *x_origin, int *y_origin); gboolean meta_actor_painting_untransformed (int paint_width, int paint_height, int *x_origin, int *y_origin); #endif /* __META_CLUTTER_UTILS_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-plugin-manager.h���������������������������������������������������0000664�0001750�0001750�00000007605�14211404421�022134� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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_TILE (1<<6) #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_new (MetaScreen *screen); void meta_plugin_manager_load (const gchar *plugin_name); 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); gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number, guint snap_queued); gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr); gboolean meta_plugin_manager_show_hud_preview (MetaPluginManager *plugin_mgr, guint current_proximity_zone, MetaRectangle *work_area, guint snap_queued); gboolean meta_plugin_manager_hide_hud_preview (MetaPluginManager *plugin_mgr); #endif ���������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-window-actor-private.h���������������������������������������������0000664�0001750�0001750�00000006640�14211404421�023311� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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-muffin.h> #include <clutter/clutter-muffin.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_tile (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_post_paint (MetaWindowActor *self); void meta_window_actor_invalidate_shadow (MetaWindowActor *self); void meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state); gboolean meta_window_actor_should_unredirect (MetaWindowActor *self); void meta_window_actor_get_shape_bounds (MetaWindowActor *self, cairo_rectangle_int_t *bounds); gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self); void meta_window_actor_sync_actor_geometry (MetaWindowActor *self, gboolean did_placement); void meta_window_actor_sync_visibility (MetaWindowActor *self); void meta_window_actor_update_shape (MetaWindowActor *self); void meta_window_actor_update_opacity (MetaWindowActor *self); void meta_window_actor_mapped (MetaWindowActor *self); void meta_window_actor_unmapped (MetaWindowActor *self); void meta_window_actor_set_updates_frozen (MetaWindowActor *self, gboolean updates_frozen); void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, gboolean no_delay_frame); cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self); void meta_window_actor_set_visible_region (MetaWindowActor *self, cairo_region_t *visible_region); void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self, cairo_region_t *beneath_region); void meta_window_actor_reset_visible_regions (MetaWindowActor *self); void meta_window_actor_set_unobscured_region (MetaWindowActor *self, cairo_region_t *unobscured_region); void meta_window_actor_effect_completed (MetaWindowActor *actor, gulong event); #endif /* META_WINDOW_ACTOR_PRIVATE_H */ ������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/cogl-utils.h������������������������������������������������������������0000664�0001750�0001750�00000004532�14211404421�020360� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Utilities for use with Cogl * * Copyright 2010 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __META_COGL_UTILS_H__ #define __META_COGL_UTILS_H__ #include <cogl/cogl.h> #include <clutter/clutter.h> #include <compositor/compositor-private.h> CoglTexture * meta_create_color_texture_4ub (guint8 red, guint8 green, guint8 blue, guint8 alpha, CoglTextureFlags flags); CoglPipeline * meta_create_texture_pipeline (CoglTexture *texture); gboolean meta_cogl_hardware_supports_npot_sizes (void); CoglTexture * meta_cogl_texture_new_from_data_wrapper (int width, int height, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, int rowstride, const uint8_t *data); CoglTexture * meta_cogl_rectangle_new (int width, int height, CoglPixelFormat format, int stride, const uint8_t *data); #endif /* __META_COGL_UTILS_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-window-shape.h�����������������������������������������������������0000664�0001750�0001750�00000005114�14211404421�021624� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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 __*/ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-shadow-factory-private.h�������������������������������������������0000664�0001750�0001750�00000006211�14211404421�023620� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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); CoglTexture*meta_shadow_get_texture (MetaShadow *shadow); void meta_shadow_paint (MetaShadow *shadow, CoglFramebuffer *framebuffer, int window_x, int window_y, int window_width, int window_height, guint8 opacity, cairo_region_t *clip, gboolean clip_strictly); 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__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-window-actor.c�����������������������������������������������������0000664�0001750�0001750�00000255441�14211404421�021641� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * SECTION:meta-window-actor * @title: MetaWindowActor * @short_description: An actor representing a top-level window in the scene graph */ #include <config.h> #include <math.h> #include <X11/extensions/shape.h> #include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xdamage.h> #include <X11/extensions/Xrender.h> #include <clutter/x11/clutter-x11.h> #include <cogl/winsys/cogl-texture-pixmap-x11.h> #include <gdk/gdk.h> /* for gdk_rectangle_union() */ #include <meta/display.h> #include <meta/errors.h> #include "frame.h" #include <meta/window.h> #include <meta/meta-shaped-texture.h> #include "xprops.h" #include "compositor-private.h" #include "meta-shaped-texture-private.h" #include "meta-shadow-factory-private.h" #include "meta-window-actor-private.h" enum { POSITION_CHANGED, SIZE_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0}; struct _MetaWindowActorPrivate { MetaWindow *window; Window xwindow; MetaScreen *screen; ClutterActor *actor; /* MetaShadowFactory only caches shadows that are actually in use; * to avoid unnecessary recomputation we do two things: 1) we store * both a focused and unfocused shadow for the window. If the window * doesn't have different focused and unfocused shadow parameters, * these will be the same. 2) when the shadow potentially changes we * don't immediately unreference the old shadow, we just flag it as * dirty and recompute it when we next need it (recompute_focused_shadow, * recompute_unfocused_shadow.) Because of our extraction of * size-invariant window shape, we'll often find that the new shadow * is the same as the old shadow. */ MetaShadow *focused_shadow; MetaShadow *unfocused_shadow; Pixmap back_pixmap; Damage damage; guint8 opacity; /* If the window is shaped, a region that matches the shape */ cairo_region_t *shape_region; /* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with * the shape region. */ cairo_region_t *opaque_region; /* The region we should clip to when painting the shadow */ cairo_region_t *shadow_clip; /* The region that is visible, used to optimize out redraws */ cairo_region_t *unobscured_region; /* Extracted size-invariant shape used for shadows */ MetaWindowShape *shadow_shape; gint last_width; gint last_height; gint last_x; gint last_y; gint freeze_count; char * shadow_class; /* * These need to be counters rather than flags, since more plugins * can implement same effect; the practicality of stacking effects * might be dubious, but we have to at least handle it correctly. */ gint minimize_in_progress; gint maximize_in_progress; gint unmaximize_in_progress; gint tile_in_progress; gint map_in_progress; gint destroy_in_progress; /* List of FrameData for recent frames */ GList *frames; guint visible : 1; guint argb32 : 1; guint disposed : 1; guint redecorating : 1; guint needs_damage_all : 1; guint received_damage : 1; guint repaint_scheduled : 1; /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN * client message using the most recent frame in ->frames */ guint send_frame_messages_timer; gint64 frame_drawn_time; guint needs_frame_drawn : 1; guint size_changed_id; guint opacity_changed_id; guint needs_pixmap : 1; guint needs_reshape : 1; guint recompute_focused_shadow : 1; guint recompute_unfocused_shadow : 1; guint size_changed : 1; guint position_changed : 1; guint updates_frozen : 1; guint needs_destroy : 1; guint no_shadow : 1; guint unredirected : 1; /* This is used to detect fullscreen windows that need to be unredirected */ guint full_damage_frames_count; guint does_full_damage : 1; guint has_desat_effect : 1; guint reshapes; guint should_have_shadow : 1; }; typedef struct _FrameData FrameData; struct _FrameData { int64_t frame_counter; guint64 sync_request_serial; gint64 frame_drawn_time; }; enum { PROP_META_WINDOW = 1, PROP_META_SCREEN, PROP_X_WINDOW, PROP_X_WINDOW_ATTRIBUTES, PROP_NO_SHADOW, PROP_SHADOW_CLASS }; #define DEFAULT_SHADOW_RADIUS 12 #define DEFAULT_SHADOW_X_OFFSET 0 #define DEFAULT_SHADOW_Y_OFFSET 8 static void meta_window_actor_dispose (GObject *object); static void meta_window_actor_finalize (GObject *object); static void meta_window_actor_constructed (GObject *object); static void meta_window_actor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void meta_window_actor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void meta_window_actor_pick (ClutterActor *actor, const ClutterColor *color); static void meta_window_actor_paint (ClutterActor *actor); static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume); static void meta_window_actor_detach (MetaWindowActor *self); static gboolean meta_window_actor_has_shadow (MetaWindowActor *self); static void meta_window_actor_handle_updates (MetaWindowActor *self); static void check_needs_reshape (MetaWindowActor *self); static void do_send_frame_drawn (MetaWindowActor *self, FrameData *frame); static void do_send_frame_timings (MetaWindowActor *self, FrameData *frame, gint refresh_interval, gint64 presentation_time); G_DEFINE_TYPE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR); static void frame_data_free (FrameData *frame) { g_slice_free (FrameData, frame); } static void meta_window_actor_class_init (MetaWindowActorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GParamSpec *pspec; g_type_class_add_private (klass, sizeof (MetaWindowActorPrivate)); object_class->dispose = meta_window_actor_dispose; object_class->finalize = meta_window_actor_finalize; object_class->set_property = meta_window_actor_set_property; object_class->get_property = meta_window_actor_get_property; object_class->constructed = meta_window_actor_constructed; actor_class->pick = meta_window_actor_pick; actor_class->paint = meta_window_actor_paint; actor_class->get_paint_volume = meta_window_actor_get_paint_volume; pspec = g_param_spec_object ("meta-window", "MetaWindow", "The displayed MetaWindow", META_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT); g_object_class_install_property (object_class, PROP_META_WINDOW, pspec); pspec = g_param_spec_pointer ("meta-screen", "MetaScreen", "MetaScreen", G_PARAM_READWRITE | G_PARAM_CONSTRUCT); g_object_class_install_property (object_class, PROP_META_SCREEN, pspec); pspec = g_param_spec_ulong ("x-window", "Window", "Window", 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT); g_object_class_install_property (object_class, PROP_X_WINDOW, pspec); pspec = g_param_spec_boolean ("no-shadow", "No shadow", "Do not add shaddow to this window", FALSE, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_NO_SHADOW, pspec); pspec = g_param_spec_string ("shadow-class", "Name of the shadow class for this window.", "NULL means to use the default shadow class for this window type", NULL, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_SHADOW_CLASS, pspec); signals[POSITION_CHANGED] = g_signal_new ("position-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); signals[SIZE_CHANGED] = g_signal_new ("size-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); } static void meta_window_actor_init (MetaWindowActor *self) { MetaWindowActorPrivate *priv; priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, META_TYPE_WINDOW_ACTOR, MetaWindowActorPrivate); priv->opacity = 0xff; priv->shadow_class = NULL; priv->has_desat_effect = FALSE; priv->reshapes = 0; priv->should_have_shadow = FALSE; } static void meta_window_actor_reset_mask_texture (MetaWindowActor *self, cairo_region_t *shape_region, gboolean force) { MetaShapedTexture *stex = META_SHAPED_TEXTURE (self->priv->actor); if (force) meta_shaped_texture_dirty_mask (stex); meta_shaped_texture_ensure_mask (stex, shape_region, self->priv->window->frame != NULL); } static void maybe_desaturate_window (ClutterActor *actor) { MetaWindowActor *window = META_WINDOW_ACTOR (actor); MetaWindowActorPrivate *priv = window->priv; if (!priv->should_have_shadow && !priv->has_desat_effect) return; guint8 opacity = clutter_actor_get_opacity (actor); if (opacity < 255) { if (priv->has_desat_effect) { return; } else { ClutterEffect *effect = clutter_desaturate_effect_new (0.0); clutter_actor_add_effect_with_name (actor, "desaturate-for-transparency", effect); priv->has_desat_effect = TRUE; } } else { /* This is will tend to get called fairly often - opening new windows, various events on the window, like minimizing... but it's inexpensive - if the ClutterActor priv->effects is NULL, it simply returns. By default cinnamon and muffin add no other effects except the special case of dimmed windows (attached modal dialogs), which isn't a frequent occurrence. */ clutter_actor_remove_effect_by_name (actor, "desaturate-for-transparency"); priv->has_desat_effect = FALSE; } } static void window_decorated_notify (MetaWindow *mw, GParamSpec *arg1, gpointer data) { MetaWindowActor *self = META_WINDOW_ACTOR (data); MetaWindowActorPrivate *priv = self->priv; MetaFrame *frame = meta_window_get_frame (mw); MetaScreen *screen = priv->screen; MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); Window new_xwindow; /* * Basically, we have to reconstruct the the internals of this object * from scratch, as everything has changed. */ priv->redecorating = TRUE; if (frame) new_xwindow = meta_frame_get_xwindow (frame); else new_xwindow = meta_window_get_xwindow (mw); meta_window_actor_detach (self); /* * First of all, clean up any resources we are currently using and will * be replacing. */ if (priv->damage != None) { meta_error_trap_push (display); XDamageDestroy (xdisplay, priv->damage); meta_error_trap_pop (display); priv->damage = None; } priv->xwindow = new_xwindow; /* * Recreate the contents. */ meta_window_actor_constructed (G_OBJECT (self)); } static void window_appears_focused_notify (MetaWindow *mw, GParamSpec *arg1, gpointer data) { clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); } static void clutter_actor_opacity_notify (ClutterActor *actor, GParamSpec *arg1m, gpointer data) { maybe_desaturate_window (actor); } static void texture_size_changed (MetaWindow *mw, gpointer data) { MetaWindowActor *self = META_WINDOW_ACTOR (data); g_signal_emit (self, signals[SIZE_CHANGED], 0); // Compatibility } static void window_position_changed (MetaWindow *mw, gpointer data) { MetaWindowActor *self = META_WINDOW_ACTOR (data); g_signal_emit (self, signals[POSITION_CHANGED], 0); // Compatibility } static void meta_window_actor_constructed (GObject *object) { MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; MetaScreen *screen = priv->screen; MetaDisplay *display = meta_screen_get_display (screen); Window xwindow = priv->xwindow; MetaWindow *window = priv->window; Display *xdisplay = meta_display_get_xdisplay (display); XRenderPictFormat *format; priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox); format = XRenderFindVisualFormat (xdisplay, window->xvisual); if (format && format->type == PictTypeDirect && format->direct.alphaMask) priv->argb32 = TRUE; if (!priv->actor) { priv->actor = meta_shaped_texture_new (); priv->size_changed_id = g_signal_connect (priv->actor, "size-changed", G_CALLBACK (texture_size_changed), self); clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor); /* * Since we are holding a pointer to this actor independently of the * ClutterContainer internals, and provide a public API to access it, * add a reference here, so that if someone is messing about with us * via the container interface, we do not end up with a dangling pointer. * We will release it in dispose(). */ g_object_ref (priv->actor); priv->opacity_changed_id = g_signal_connect (self, "notify::opacity", G_CALLBACK (clutter_actor_opacity_notify), NULL); /* Fix for the case when clients try to re-map their windows after re-decorating while effects are enabled. For reasons currently unknown, the re-shape doesn't happen when #meta_plugin_map_completed is called after a delay. #window_decorated_notify is not always called on re-decoration, and when it is, its only called before the actor is disposed in this case - we can't track after that. */ if (meta_prefs_get_desktop_effects () && window->frame != NULL && window->decorated && !window->pending_compositor_effect && !window->unmaps_pending) priv->needs_reshape = TRUE; } else { /* * This is the case where existing window is gaining/loosing frame. * Just ensure the actor is top most (i.e., above shadow). */ g_signal_handler_disconnect (priv->actor, priv->size_changed_id); g_signal_handler_disconnect (self, priv->opacity_changed_id); clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (self), priv->actor, NULL); } meta_window_actor_update_opacity (self); maybe_desaturate_window (CLUTTER_ACTOR (self)); priv->shape_region = cairo_region_create(); } static void meta_window_actor_dispose (GObject *object) { MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; MetaScreen *screen; MetaDisplay *display; Display *xdisplay; MetaCompositor *compositor; if (priv->disposed) return; priv->disposed = TRUE; if (priv->send_frame_messages_timer != 0) { g_source_remove (priv->send_frame_messages_timer); priv->send_frame_messages_timer = 0; } screen = priv->screen; display = screen->display; xdisplay = display->xdisplay; compositor = display->compositor; meta_window_actor_detach (self); g_clear_pointer (&priv->unobscured_region, cairo_region_destroy); g_clear_pointer (&priv->shape_region, cairo_region_destroy); g_clear_pointer (&priv->opaque_region, cairo_region_destroy); g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); g_clear_pointer (&priv->shadow_class, free); g_clear_pointer (&priv->focused_shadow, meta_shadow_unref); g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref); g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); if (priv->damage != None) { meta_error_trap_push (display); XDamageDestroy (xdisplay, priv->damage); meta_error_trap_pop (display); priv->damage = None; } compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self); g_clear_object (&priv->window); /* * Release the extra reference we took on the actor. */ g_clear_object (&priv->actor); G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); } static void meta_window_actor_finalize (GObject *object) { MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; g_list_free_full (priv->frames, (GDestroyNotify) frame_data_free); G_OBJECT_CLASS (meta_window_actor_parent_class)->finalize (object); } static void meta_window_actor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; switch (prop_id) { case PROP_META_WINDOW: { if (priv->window) g_object_unref (priv->window); priv->window = g_value_dup_object (value); g_signal_connect_object (priv->window, "notify::decorated", G_CALLBACK (window_decorated_notify), self, 0); g_signal_connect_object (priv->window, "notify::appears-focused", G_CALLBACK (window_appears_focused_notify), self, 0); g_signal_connect_object (priv->window, "position-changed", G_CALLBACK (window_position_changed), self, 0); } break; case PROP_META_SCREEN: priv->screen = g_value_get_pointer (value); break; case PROP_X_WINDOW: priv->xwindow = g_value_get_ulong (value); break; case PROP_NO_SHADOW: { gboolean newv = g_value_get_boolean (value); if (newv == priv->no_shadow) return; priv->no_shadow = newv; meta_window_actor_invalidate_shadow (self); } break; case PROP_SHADOW_CLASS: { const char *newv = g_value_get_string (value); if (g_strcmp0 (newv, priv->shadow_class) == 0) return; free (priv->shadow_class); priv->shadow_class = g_strdup (newv); meta_window_actor_invalidate_shadow (self); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_window_actor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MetaWindowActorPrivate *priv = META_WINDOW_ACTOR (object)->priv; switch (prop_id) { case PROP_META_WINDOW: g_value_set_object (value, priv->window); break; case PROP_META_SCREEN: g_value_set_pointer (value, priv->screen); break; case PROP_X_WINDOW: g_value_set_ulong (value, priv->xwindow); break; case PROP_NO_SHADOW: g_value_set_boolean (value, priv->no_shadow); break; case PROP_SHADOW_CLASS: g_value_set_string (value, priv->shadow_class); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static const char * meta_window_actor_get_shadow_class (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; if (priv->shadow_class != NULL) return priv->shadow_class; else { MetaWindowType window_type = meta_window_get_window_type (priv->window); switch (window_type) { case META_WINDOW_DROPDOWN_MENU: return "dropdown-menu"; case META_WINDOW_POPUP_MENU: return "popup-menu"; default: { MetaFrameType frame_type = meta_window_get_frame_type (priv->window); return meta_frame_type_to_string (frame_type); } } } } static void meta_window_actor_get_shadow_params (MetaWindowActor *self, gboolean appears_focused, MetaShadowParams *params) { const char *shadow_class = meta_window_actor_get_shadow_class (self); meta_shadow_factory_get_params (meta_shadow_factory_get_default (), shadow_class, appears_focused, params); } LOCAL_SYMBOL void meta_window_actor_get_shape_bounds (MetaWindowActor *self, cairo_rectangle_int_t *bounds) { MetaWindowActorPrivate *priv = self->priv; /* We need to be defensive here because there are corner cases * where getting the shape fails on a window being destroyed * and similar. */ if (priv->shape_region) cairo_region_get_extents (priv->shape_region, bounds); else bounds->x = bounds->y = bounds->width = bounds->height = 0; } static void meta_window_actor_get_shadow_bounds (MetaWindowActor *self, gboolean appears_focused, cairo_rectangle_int_t *bounds) { MetaWindowActorPrivate *priv = self->priv; MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow; cairo_rectangle_int_t shape_bounds; MetaShadowParams params; meta_window_actor_get_shape_bounds (self, &shape_bounds); meta_window_actor_get_shadow_params (self, appears_focused, ¶ms); meta_shadow_get_bounds (shadow, params.x_offset + shape_bounds.x, params.y_offset + shape_bounds.y, shape_bounds.width, shape_bounds.height, bounds); } /* If we have an ARGB32 window that we decorate with a frame, it's * probably something like a translucent terminal - something where * the alpha channel represents transparency rather than a shape. We * don't want to show the shadow through the translucent areas since * the shadow is wrong for translucent windows (it should be * translucent itself and colored), and not only that, will /look/ * horribly wrong - a misplaced big black blob. As a hack, what we * want to do is just draw the shadow as normal outside the frame, and * inside the frame draw no shadow. This is also not even close to * the right result, but looks OK. We also apply this approach to * windows set to be partially translucent with _NET_WM_WINDOW_OPACITY. */ static gboolean clip_shadow_under_window (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; return (priv->argb32 || priv->opacity != 0xff) && priv->window->frame; } static void assign_frame_counter_to_frames (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; ClutterStage *stage = priv->window->display->compositor->stage; GList *l; /* If the window is obscured, then we're expecting to deal with sending * frame messages in a timeout, rather than in this paint cycle. */ if (priv->send_frame_messages_timer != 0) return; for (l = priv->frames; l; l = l->next) { FrameData *frame = l->data; if (frame->frame_counter == -1) frame->frame_counter = clutter_stage_get_frame_counter (stage); } } static void meta_window_actor_pick (ClutterActor *actor, const ClutterColor *color) { if (!clutter_actor_should_pick_paint (actor)) return; MetaWindowActor *self = (MetaWindowActor *) actor; MetaWindowActorPrivate *priv = self->priv; ClutterActorIter iter; ClutterActor *child; /* If there is no region then use the regular pick */ if (priv->shape_region == NULL) CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->pick (actor, color); else { int n_rects; float *rectangles; int i; CoglPipeline *pipeline; CoglContext *ctx; CoglFramebuffer *fb; CoglColor cogl_color; n_rects = cairo_region_num_rectangles (priv->shape_region); rectangles = g_alloca (sizeof (float) * 4 * n_rects); for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t rect; int pos = i * 4; cairo_region_get_rectangle (priv->shape_region, i, &rect); rectangles[pos + 0] = rect.x; rectangles[pos + 1] = rect.y; rectangles[pos + 2] = rect.x + rect.width; rectangles[pos + 3] = rect.y + rect.height; } ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); fb = cogl_get_draw_framebuffer (); cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); pipeline = cogl_pipeline_new (ctx); cogl_pipeline_set_color (pipeline, &cogl_color); cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects); cogl_object_unref (pipeline); } clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) clutter_actor_paint (child); } static void meta_window_actor_paint (ClutterActor *actor) { MetaWindowActor *self = META_WINDOW_ACTOR (actor); MetaWindowActorPrivate *priv = self->priv; CoglFramebuffer *framebuffer = NULL; gboolean appears_focused = meta_window_appears_focused (priv->window); MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow; if (!priv->window->display->shadows_enabled) { shadow = NULL; } /* This window got damage when obscured; we set up a timer * to send frame completion events, but since we're drawing * the window now (for some other reason) cancel the timer * and send the completion events normally */ if (priv->send_frame_messages_timer != 0) { g_source_remove (priv->send_frame_messages_timer); priv->send_frame_messages_timer = 0; assign_frame_counter_to_frames (self); } if (shadow != NULL) { MetaShadowParams params; cairo_rectangle_int_t shape_bounds; cairo_region_t *clip = priv->shadow_clip; meta_window_actor_get_shape_bounds (self, &shape_bounds); meta_window_actor_get_shadow_params (self, appears_focused, ¶ms); /* The frame bounds are already subtracted from priv->shadow_clip * if that exists. */ if (!clip && clip_shadow_under_window (self)) { cairo_rectangle_int_t bounds; meta_window_actor_get_shadow_bounds (self, appears_focused, &bounds); clip = cairo_region_create_rectangle (&bounds); cairo_region_subtract (clip, meta_window_get_frame_bounds (priv->window)); } framebuffer = cogl_get_draw_framebuffer (); meta_shadow_paint (shadow, framebuffer, params.x_offset + shape_bounds.x, params.y_offset + shape_bounds.y, shape_bounds.width, shape_bounds.height, (clutter_actor_get_paint_opacity (actor) * params.opacity * priv->opacity) / (255 * 255), clip, clip_shadow_under_window (self)); /* clip_strictly - not just as an optimization */ if (clip && clip != priv->shadow_clip) cairo_region_destroy (clip); } CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor); } static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { MetaWindowActor *self = META_WINDOW_ACTOR (actor); MetaWindowActorPrivate *priv = self->priv; gboolean appears_focused = meta_window_appears_focused (priv->window); /* The paint volume is computed before paint functions are called * so our bounds might not be updated yet. Force an update. */ meta_window_actor_handle_updates (self); if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow) { cairo_rectangle_int_t shadow_bounds; ClutterActorBox shadow_box; /* We could compute an full clip region as we do for the window * texture, but the shadow is relatively cheap to draw, and * a little more complex to clip, so we just catch the case where * the shadow is completely obscured and doesn't need to be drawn * at all. */ meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds); shadow_box.x1 = shadow_bounds.x; shadow_box.x2 = shadow_bounds.x + shadow_bounds.width; shadow_box.y1 = shadow_bounds.y; shadow_box.y2 = shadow_bounds.y + shadow_bounds.height; clutter_paint_volume_union_box (volume, &shadow_box); } if (priv->actor) { const ClutterPaintVolume *child_volume; child_volume = clutter_actor_get_transformed_paint_volume (CLUTTER_ACTOR (priv->actor), actor); if (!child_volume) return FALSE; clutter_paint_volume_union (volume, child_volume); } return TRUE; } static gboolean meta_window_actor_has_shadow (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaWindowType window_type = meta_window_get_window_type (priv->window); if (priv->no_shadow) return FALSE; /* Leaving out shadows for maximized and fullscreen windows is an effeciency * win and also prevents the unsightly effect of the shadow of maximized * window appearing on an adjacent window */ if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) || meta_window_is_fullscreen (priv->window)) return FALSE; /* Don't shadow tiled windows of any type */ if (meta_window_get_tile_type (priv->window) != META_WINDOW_TILE_TYPE_NONE) return FALSE; /* * Always put a shadow around windows with a frame - This should override * the restriction about not putting a shadow around ARGB windows. */ if (priv->window) { if (meta_window_get_frame (priv->window)) return TRUE; } /* * Do not add shadows to ARGB windows; eventually we should generate a * shadow from the input shape for such windows. */ if (priv->argb32 || priv->opacity != 0xff) return FALSE; /* * Add shadows to override redirect windows (e.g., Gtk menus). */ if (priv->window->override_redirect) return TRUE; /* * If a window specifies that it has custom frame extents, that likely * means that it is drawing a shadow itself. Don't draw our own. */ if (priv->window->has_custom_frame_extents) return FALSE; /* * Don't put shadow around DND icon windows */ if (window_type == META_WINDOW_DND || window_type == META_WINDOW_DESKTOP || window_type == META_WINDOW_DOCK) return FALSE; if (window_type == META_WINDOW_MENU #if 0 || window_type == META_WINDOW_DROPDOWN_MENU #endif ) return TRUE; if (meta_window_is_client_decorated (priv->window)) { return FALSE; } #if 0 if (window_type == META_WINDOW_TOOLTIP) return TRUE; #endif return FALSE; } /** * meta_window_actor_get_x_window: (skip) * */ Window meta_window_actor_get_x_window (MetaWindowActor *self) { if (!self) return None; return self->priv->xwindow; } /** * meta_window_actor_get_meta_window: * * Gets the #MetaWindow object that the the #MetaWindowActor is displaying * * Return value: (transfer none): the displayed #MetaWindow */ MetaWindow * meta_window_actor_get_meta_window (MetaWindowActor *self) { return self->priv->window; } /** * meta_window_actor_get_texture: * * Gets the ClutterActor that is used to display the contents of the window * * Return value: (transfer none): the #ClutterActor for the contents */ ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self) { return self->priv->actor; } /** * meta_window_actor_is_destroyed: * * Gets whether the X window that the actor was displaying has been destroyed * * Return value: %TRUE when the window is destroyed, otherwise %FALSE */ gboolean meta_window_actor_is_destroyed (MetaWindowActor *self) { return self->priv->disposed || self->priv->needs_destroy; } static gboolean send_frame_messages_timeout (gpointer data) { MetaWindowActor *self = (MetaWindowActor *) data; MetaWindowActorPrivate *priv = self->priv; GList *l; for (l = priv->frames; l;) { GList *l_next = l->next; FrameData *frame = l->data; if (frame->frame_counter == -1) { do_send_frame_drawn (self, frame); do_send_frame_timings (self, frame, 0, 0); priv->frames = g_list_delete_link (priv->frames, l); frame_data_free (frame); } l = l_next; } priv->needs_frame_drawn = FALSE; priv->send_frame_messages_timer = 0; return FALSE; } static void queue_send_frame_messages_timeout (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = meta_window_actor_get_meta_window (self); MetaDisplay *display = meta_screen_get_display (priv->screen); int64_t current_time; float refresh_rate; int interval, offset; if (priv->send_frame_messages_timer != 0) return; if (window->monitor) { refresh_rate = window->monitor->refresh_rate; } else { refresh_rate = 60.0f; } current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ()); interval = (int)(1000000 / refresh_rate) * 6; offset = MAX (0, priv->frame_drawn_time + interval - current_time) / 1000; /* The clutter master clock source has already been added with META_PRIORITY_REDRAW, * so the timer will run *after* the clutter frame handling, if a frame is ready * to be drawn when the timer expires. */ priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL); g_source_set_name_by_id (priv->send_frame_messages_timer, "[muffin] send_frame_messages_timeout"); } gboolean meta_window_actor_is_override_redirect (MetaWindowActor *self) { return meta_window_is_override_redirect (self->priv->window); } /** * meta_window_actor_get_workspace: * @self: #MetaWindowActor * * Returns the index of workspace on which this window is located; if the * window is sticky, or is not currently located on any workspace, returns -1. * This function is deprecated and should not be used in newly written code; * meta_window_get_workspace() instead. * * Return value: index of workspace on which this window is * located. */ gint meta_window_actor_get_workspace (MetaWindowActor *self) { MetaWindowActorPrivate *priv; MetaWorkspace *workspace; if (!self) return -1; priv = self->priv; if (!priv->window || meta_window_is_on_all_workspaces (priv->window)) return -1; workspace = meta_window_get_workspace (priv->window); if (!workspace) return -1; return meta_workspace_index (workspace); } gboolean meta_window_actor_showing_on_its_workspace (MetaWindowActor *self) { if (!self) return FALSE; /* If override redirect: */ if (!self->priv->window) return TRUE; return meta_window_showing_on_its_workspace (self->priv->window); } static void meta_window_actor_freeze (MetaWindowActor *self) { self->priv->freeze_count++; } static void update_area (MetaWindowActor *self, int x, int y, int width, int height) { MetaWindowActorPrivate *priv = self->priv; CoglTexture *texture; texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (texture), x, y, width, height); } static void meta_window_actor_damage_all (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; CoglTexture *texture; if (!priv->needs_damage_all || !priv->window->mapped || priv->needs_pixmap) return; texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); priv->needs_damage_all = FALSE; update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture)); priv->repaint_scheduled = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor), 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture), clutter_actor_has_mapped_clones (priv->actor) ? NULL : priv->unobscured_region); } static void meta_window_actor_thaw (MetaWindowActor *self) { self->priv->freeze_count--; if (G_UNLIKELY (self->priv->freeze_count < 0)) { g_warning ("Error in freeze/thaw accounting."); self->priv->freeze_count = 0; return; } if (self->priv->freeze_count) return; /* We sometimes ignore moves and resizes on frozen windows */ meta_window_actor_sync_actor_geometry (self, FALSE); /* We do this now since we might be going right back into the * frozen state */ meta_window_actor_handle_updates (self); /* Since we ignore damage events while a window is frozen for certain effects * we may need to issue an update_area() covering the whole pixmap if we * don't know what real damage has happened. */ if (self->priv->needs_damage_all) meta_window_actor_damage_all (self); } void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, gboolean no_delay_frame) { MetaWindowActorPrivate *priv = self->priv; FrameData *frame; if (meta_window_actor_is_destroyed (self)) return; frame = g_slice_new0 (FrameData); frame->frame_counter = -1; priv->needs_frame_drawn = TRUE; #ifdef HAVE_XSYNC frame->sync_request_serial = priv->window->sync_request_serial; #else frame->sync_request_serial = 0; #endif priv->frames = g_list_prepend (priv->frames, frame); if (no_delay_frame) { ClutterActor *stage = priv->window->display->compositor->stage; clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage)); } if (!priv->repaint_scheduled) { gboolean is_obscured = FALSE; /* Find out whether the window is completly obscured */ if (priv->unobscured_region) { cairo_region_t *unobscured_window_region; unobscured_window_region = cairo_region_copy (priv->shape_region); cairo_region_intersect (unobscured_window_region, priv->unobscured_region); is_obscured = cairo_region_is_empty (unobscured_window_region); cairo_region_destroy (unobscured_window_region); } /* A frame was marked by the client without actually doing any * damage, or while we had the window frozen (e.g. during an * interactive resize.) We need to make sure that the * pre_paint/post_paint functions get called, enabling us to * send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get * consistent timing with non-empty frames. */ if (is_obscured) { queue_send_frame_messages_timeout (self); } else if (priv->window->mapped && !priv->needs_pixmap) { const cairo_rectangle_int_t clip = { 0, 0, 1, 1 }; clutter_actor_queue_redraw_with_clip (priv->actor, &clip); priv->repaint_scheduled = TRUE; } } } LOCAL_SYMBOL gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self) { return (self->priv->minimize_in_progress || self->priv->maximize_in_progress || self->priv->unmaximize_in_progress || self->priv->map_in_progress || self->priv->tile_in_progress || self->priv->destroy_in_progress); } static gboolean is_frozen (MetaWindowActor *self) { return self->priv->freeze_count ? TRUE : FALSE; } static gboolean is_freeze_thaw_effect (gulong event) { switch (event) { case META_PLUGIN_DESTROY: case META_PLUGIN_MAXIMIZE: case META_PLUGIN_UNMAXIMIZE: case META_PLUGIN_TILE: return TRUE; break; default: return FALSE; } } static gboolean start_simple_effect (MetaWindowActor *self, gulong event) { MetaWindowActorPrivate *priv = self->priv; MetaCompositor *compositor = priv->screen->display->compositor; gint *counter = NULL; gboolean use_freeze_thaw = FALSE; if (!compositor->plugin_mgr) return FALSE; switch (event) { case META_PLUGIN_MINIMIZE: counter = &priv->minimize_in_progress; break; case META_PLUGIN_MAP: counter = &priv->map_in_progress; break; case META_PLUGIN_DESTROY: counter = &priv->destroy_in_progress; break; case META_PLUGIN_UNMAXIMIZE: case META_PLUGIN_MAXIMIZE: case META_PLUGIN_SWITCH_WORKSPACE: case META_PLUGIN_TILE: g_assert_not_reached (); break; } g_assert (counter); use_freeze_thaw = is_freeze_thaw_effect (event); if (use_freeze_thaw) meta_window_actor_freeze (self); (*counter)++; if (!meta_plugin_manager_event_simple (compositor->plugin_mgr, self, event)) { (*counter)--; if (use_freeze_thaw) meta_window_actor_thaw (self); return FALSE; } return TRUE; } static void meta_window_actor_after_effects (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; if (priv->needs_destroy) { clutter_actor_destroy (CLUTTER_ACTOR (self)); return; } meta_window_actor_sync_visibility (self); meta_window_actor_sync_actor_geometry (self, FALSE); if (priv->needs_pixmap) clutter_actor_queue_redraw (priv->actor); } LOCAL_SYMBOL void meta_window_actor_effect_completed (MetaWindowActor *self, gulong event) { MetaWindowActorPrivate *priv = self->priv; /* NB: Keep in mind that when effects get completed it possible * that the corresponding MetaWindow may have be been destroyed. * In this case priv->window will == NULL */ switch (event) { case META_PLUGIN_MINIMIZE: { priv->minimize_in_progress--; if (priv->minimize_in_progress < 0) { g_warning ("Error in minimize accounting."); priv->minimize_in_progress = 0; } } break; case META_PLUGIN_MAP: /* * Make sure that the actor is at the correct place in case * the plugin fscked. */ priv->map_in_progress--; priv->position_changed = TRUE; if (priv->map_in_progress < 0) { g_warning ("Error in map accounting."); priv->map_in_progress = 0; } break; case META_PLUGIN_DESTROY: priv->destroy_in_progress--; if (priv->destroy_in_progress < 0) { g_warning ("Error in destroy accounting."); priv->destroy_in_progress = 0; } break; case META_PLUGIN_UNMAXIMIZE: priv->unmaximize_in_progress--; if (priv->unmaximize_in_progress < 0) { g_warning ("Error in unmaximize accounting."); priv->unmaximize_in_progress = 0; } break; case META_PLUGIN_MAXIMIZE: priv->maximize_in_progress--; if (priv->maximize_in_progress < 0) { g_warning ("Error in maximize accounting."); priv->maximize_in_progress = 0; } break; case META_PLUGIN_TILE: priv->tile_in_progress--; if (priv->tile_in_progress < 0) { g_warning ("Error in tile accounting."); priv->tile_in_progress = 0; } break; case META_PLUGIN_SWITCH_WORKSPACE: g_assert_not_reached (); break; } if (is_freeze_thaw_effect (event)) meta_window_actor_thaw (self); if (!meta_window_actor_effect_in_progress (self)) meta_window_actor_after_effects (self); } /* Called to drop our reference to a window backing pixmap that we * previously obtained with XCompositeNameWindowPixmap. We do this * when the window is unmapped or when we want to update to a new * pixmap for a new size. */ static void meta_window_actor_detach (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaScreen *screen = priv->screen; MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); if (!priv->back_pixmap) return; /* Get rid of all references to the pixmap before freeing it; it's unclear whether * you are supposed to be able to free a GLXPixmap after freeing the underlying * pixmap, but it certainly doesn't work with current DRI/Mesa */ meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL); cogl_flush(); XFreePixmap (xdisplay, priv->back_pixmap); priv->back_pixmap = None; priv->needs_pixmap = TRUE; } LOCAL_SYMBOL gboolean meta_window_actor_should_unredirect (MetaWindowActor *self) { MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); MetaWindowActorPrivate *priv = self->priv; if (meta_window_actor_is_destroyed (self)) return FALSE; if (meta_window_requested_dont_bypass_compositor (metaWindow)) return FALSE; if (priv->opacity != 0xff) return FALSE; if (metaWindow->has_shape) return FALSE; if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow)) return FALSE; if (!meta_window_is_monitor_sized (metaWindow)) return FALSE; if (meta_window_requested_bypass_compositor (metaWindow)) return TRUE; if (meta_window_is_override_redirect (metaWindow)) return TRUE; if (priv->does_full_damage && meta_prefs_get_unredirect_fullscreen_windows ()) return TRUE; return FALSE; } LOCAL_SYMBOL void meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state) { MetaWindowActorPrivate *priv = self->priv; MetaWindow *metaWindow = priv->window; MetaDisplay *display = metaWindow->display; Display *xdisplay = meta_display_get_xdisplay (display); Window xwin = meta_window_actor_get_x_window (self); if (priv->unredirected != state) return; meta_error_trap_push (display); if (state) { XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual); meta_window_actor_detach (self); priv->unredirected = FALSE; } else { XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual); priv->repaint_scheduled = TRUE; priv->unredirected = TRUE; } meta_error_trap_pop (display); } LOCAL_SYMBOL void meta_window_actor_destroy (MetaWindowActor *self) { MetaWindow *window; MetaWindowActorPrivate *priv = self->priv; MetaWindowType window_type; window = priv->window; window_type = meta_window_get_window_type (window); meta_window_set_compositor_private (window, NULL); if (priv->send_frame_messages_timer != 0) { g_source_remove (priv->send_frame_messages_timer); priv->send_frame_messages_timer = 0; } if (window_type == META_WINDOW_DROPDOWN_MENU || window_type == META_WINDOW_POPUP_MENU || window_type == META_WINDOW_TOOLTIP || window_type == META_WINDOW_NOTIFICATION || window_type == META_WINDOW_COMBO || window_type == META_WINDOW_DND || window_type == META_WINDOW_OVERRIDE_OTHER) { /* * No effects, just kill it. */ clutter_actor_destroy (CLUTTER_ACTOR (self)); return; } priv->needs_destroy = TRUE; if (!meta_window_actor_effect_in_progress (self)) clutter_actor_destroy (CLUTTER_ACTOR (self)); } LOCAL_SYMBOL void meta_window_actor_sync_actor_geometry (MetaWindowActor *self, gboolean did_placement) { MetaWindowActorPrivate *priv = self->priv; MetaRectangle window_rect; meta_window_get_input_rect (priv->window, &window_rect); if (priv->last_width != window_rect.width || priv->last_height != window_rect.height) { priv->size_changed = TRUE; priv->last_width = window_rect.width; priv->last_height = window_rect.height; } if (priv->last_x != window_rect.x || priv->last_y != window_rect.y) { priv->position_changed = TRUE; priv->last_x = window_rect.x; priv->last_y = window_rect.y; } /* Normally we want freezing a window to also freeze its position; this allows * windows to atomically move and resize together, either under app control, * or because the user is resizing from the left/top. But on initial placement * we need to assign a position, since immediately after the window * is shown, the map effect will go into effect and prevent further geometry * updates. */ if (is_frozen (self) && !did_placement) return; if (meta_window_actor_effect_in_progress (self)) return; if (priv->size_changed) { priv->needs_pixmap = TRUE; meta_window_actor_update_shape (self); clutter_actor_set_size (CLUTTER_ACTOR (self), window_rect.width, window_rect.height); } if (priv->position_changed) { clutter_actor_set_position (CLUTTER_ACTOR (self), window_rect.x, window_rect.y); } } void meta_window_actor_show (MetaWindowActor *self, MetaCompEffect effect) { MetaWindowActorPrivate *priv = self->priv; gulong event; g_return_if_fail (!priv->visible); priv->visible = TRUE; event = 0; switch (effect) { case META_COMP_EFFECT_CREATE: event = META_PLUGIN_MAP; break; case META_COMP_EFFECT_UNMINIMIZE: /* FIXME: should have META_PLUGIN_UNMINIMIZE */ event = META_PLUGIN_MAP; break; case META_COMP_EFFECT_NONE: break; case META_COMP_EFFECT_DESTROY: case META_COMP_EFFECT_MINIMIZE: g_assert_not_reached(); } if (priv->redecorating || priv->screen->display->compositor->switch_workspace_in_progress || event == 0 || !meta_prefs_get_desktop_effects () || !start_simple_effect (self, event)) { clutter_actor_show (CLUTTER_ACTOR (self)); priv->redecorating = FALSE; } } LOCAL_SYMBOL void meta_window_actor_hide (MetaWindowActor *self, MetaCompEffect effect) { MetaWindowActorPrivate *priv = self->priv; MetaCompositor *compositor = priv->screen->display->compositor; gulong event; g_return_if_fail (priv->visible || (!priv->visible && meta_window_is_attached_dialog (priv->window))); priv->visible = FALSE; /* If a plugin is animating a workspace transition, we have to * hold off on hiding the window, and do it after the workspace * switch completes */ if (compositor->switch_workspace_in_progress) return; event = 0; switch (effect) { case META_COMP_EFFECT_DESTROY: event = META_PLUGIN_DESTROY; break; case META_COMP_EFFECT_MINIMIZE: event = META_PLUGIN_MINIMIZE; break; case META_COMP_EFFECT_NONE: break; case META_COMP_EFFECT_UNMINIMIZE: case META_COMP_EFFECT_CREATE: g_assert_not_reached(); } if (event == 0 || !meta_prefs_get_desktop_effects () || !start_simple_effect (self, event)) clutter_actor_hide (CLUTTER_ACTOR (self)); } LOCAL_SYMBOL void meta_window_actor_maximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect) { MetaCompositor *compositor = self->priv->screen->display->compositor; /* The window has already been resized (in order to compute new_rect), * which by side effect caused the actor to be resized. Restore it to the * old size and position */ clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y); clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height); self->priv->maximize_in_progress++; meta_window_actor_freeze (self); if (!compositor->plugin_mgr || !meta_plugin_manager_event_maximize (compositor->plugin_mgr, self, META_PLUGIN_MAXIMIZE, new_rect->x, new_rect->y, new_rect->width, new_rect->height)) { self->priv->maximize_in_progress--; meta_window_actor_thaw (self); } } LOCAL_SYMBOL void meta_window_actor_unmaximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect) { MetaCompositor *compositor = self->priv->screen->display->compositor; /* The window has already been resized (in order to compute new_rect), * which by side effect caused the actor to be resized. Restore it to the * old size and position */ clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y); clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height); self->priv->unmaximize_in_progress++; meta_window_actor_freeze (self); if (!compositor->plugin_mgr || !meta_plugin_manager_event_maximize (compositor->plugin_mgr, self, META_PLUGIN_UNMAXIMIZE, new_rect->x, new_rect->y, new_rect->width, new_rect->height)) { self->priv->unmaximize_in_progress--; meta_window_actor_thaw (self); } } LOCAL_SYMBOL void meta_window_actor_tile (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect) { MetaCompositor *compositor = self->priv->screen->display->compositor; /* The window has already been resized (in order to compute new_rect), * which by side effect caused the actor to be resized. Restore it to the * old size and position */ clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y); clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height); self->priv->tile_in_progress++; meta_window_actor_freeze (self); if (!compositor->plugin_mgr || !meta_plugin_manager_event_maximize (compositor->plugin_mgr, self, META_PLUGIN_TILE, new_rect->x, new_rect->y, new_rect->width, new_rect->height)) { self->priv->tile_in_progress--; meta_window_actor_thaw (self); } } static void ensure_tooltip_visible (MetaWindow *window) { const MetaMonitorInfo *wmonitor; MetaRectangle work_area, win_rect; gint new_x, new_y; /* Why this is here: * As of gtk 3.24, tooltips for GtkStatusIcons began displaying their tool tip * off the screen in certain situations. * * See: https://github.com/GNOME/gtk/commit/14d22cb3233e * * If the status icon is too small relative to its panel (which has been assigned * as a strut to muffin), tooltip positioning fails both tests in gdkwindowimpl.c * (maybe_flip_position()) skipping repositioning of the tooltip inside the workarea. * This only occurs on bottom panels, and only begins happening when the status icon * becomes 10px or more smaller than the panel it's *centered* on. * * Since the calculations are based upon the monitor's workarea and the status icon * plug window's size, there's no way to compensate for or fool gtk into displaying it * correctly. So here, we do our own check and adjustment if a part of the tooltip * window falls outside the current monitor's work area. This is also useful since * muffin knows *exactly* the work area for each monitor, whereas gtk only has * _NET_WORKAREA to go by, which only keeps track of (primary monitor * n_workspaces), * so an odd monitor layout would trip this up anyhow. * * This may cause regressions - see: https://github.com/linuxmint/muffin/commit/050038690, * but without being able to reproduce the issue mentioned there, we'll just have to address * it if it appears again as a result of this change. */ wmonitor = meta_screen_get_monitor_for_window (window->screen, window); meta_workspace_get_work_area_for_monitor (meta_screen_get_active_workspace (window->screen), wmonitor->number, &work_area); meta_window_get_outer_rect (window, &win_rect); new_x = win_rect.x; new_y = win_rect.y; if (win_rect.y < work_area.y) { new_y = work_area.y; } else if (win_rect.y + win_rect.height > work_area.y + work_area.height) { new_y = (work_area.y + work_area.height - win_rect.height); } if (win_rect.x < work_area.x) { new_x = work_area.x; } else if (win_rect.x + win_rect.width > work_area.x + work_area.width) { new_x = (work_area.x + work_area.width - win_rect.width); } if (new_x != win_rect.x || new_y != win_rect.y) { meta_window_move(window, FALSE, new_x, new_y); } } LOCAL_SYMBOL MetaWindowActor * meta_window_actor_new (MetaWindow *window) { MetaScreen *screen = window->screen; MetaCompositor *compositor = screen->display->compositor; MetaWindowActor *self; MetaWindowActorPrivate *priv; MetaFrame *frame; Window top_window; ClutterActor *window_group; frame = meta_window_get_frame (window); if (frame) top_window = meta_frame_get_xwindow (frame); else top_window = meta_window_get_xwindow (window); meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window); self = g_object_new (META_TYPE_WINDOW_ACTOR, "meta-window", window, "x-window", top_window, "meta-screen", screen, NULL); priv = self->priv; priv->last_width = -1; priv->last_height = -1; priv->last_x = -1; priv->last_y = -1; priv->needs_pixmap = TRUE; meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (priv->window)); /* If a window doesn't start off with updates frozen, we should * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn. */ if (priv->window->extended_sync_request_counter && !priv->updates_frozen) meta_window_actor_queue_frame_drawn (self, FALSE); meta_window_actor_sync_actor_geometry (self, priv->window->placed); /* Hang our compositor window state off the MetaWindow for fast retrieval */ meta_window_set_compositor_private (window, G_OBJECT (self)); if (window->type == META_WINDOW_DND) window_group = compositor->window_group; else if (window->layer == META_LAYER_OVERRIDE_REDIRECT) { if (window->type == META_WINDOW_TOOLTIP) { ensure_tooltip_visible (window); } window_group = compositor->top_window_group; } else if (window->type == META_WINDOW_DESKTOP) window_group = compositor->bottom_window_group; else window_group = compositor->window_group; clutter_actor_add_child (window_group, CLUTTER_ACTOR (self)); clutter_actor_hide (CLUTTER_ACTOR (self)); /* Initial position in the stack is arbitrary; stacking will be synced * before we first paint. */ compositor->windows = g_list_append (compositor->windows, self); return self; } static void meta_window_actor_update_shape_region (MetaWindowActor *self, cairo_region_t *region) { MetaWindowActorPrivate *priv = self->priv; g_clear_pointer (&priv->shape_region, cairo_region_destroy); /* region must be non-null */ priv->shape_region = region; cairo_region_reference (region); } /** * meta_window_actor_get_obscured_region: * @self: a #MetaWindowActor * * Gets the region that is completely obscured by the window. Coordinates * are relative to the upper-left of the window. * * Return value: (transfer none): the area obscured by the window, * %NULL is the same as an empty region. */ LOCAL_SYMBOL cairo_region_t * meta_window_actor_get_obscured_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; if (priv->back_pixmap && priv->opacity == 0xff) return priv->opaque_region; else return NULL; } #if 0 /* Print out a region; useful for debugging */ static void dump_region (cairo_region_t *region) { int n_rects; int i; n_rects = cairo_region_num_rectangles (region); g_print ("["); for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); g_print ("+%d+%dx%dx%d ", rect.x, rect.y, rect.width, rect.height); } g_print ("]\n"); } #endif /** * meta_window_actor_set_unobscured_region: * @self: a #MetaWindowActor * @unobscured_region: the region of the screen that isn't completely * obscured. * * Provides a hint as to what areas of the window need to queue * redraws when damaged. Regions not in @unobscured_region are completely obscured. * Unlike meta_window_actor_set_clip_region(), the region here * doesn't take into account any clipping that is in effect while drawing. */ void meta_window_actor_set_unobscured_region (MetaWindowActor *self, cairo_region_t *unobscured_region) { MetaWindowActorPrivate *priv = self->priv; if (priv->unobscured_region) cairo_region_destroy (priv->unobscured_region); if (unobscured_region) priv->unobscured_region = cairo_region_copy (unobscured_region); else priv->unobscured_region = NULL; } /** * meta_window_actor_set_visible_region: * @self: a #MetaWindowActor * @visible_region: the region of the screen that isn't completely * obscured. * * Provides a hint as to what areas of the window need to be * drawn. Regions not in @visible_region are completely obscured. * This will be set before painting then unset afterwards. */ LOCAL_SYMBOL void meta_window_actor_set_visible_region (MetaWindowActor *self, cairo_region_t *visible_region) { MetaWindowActorPrivate *priv = self->priv; meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor), visible_region); } /** * meta_window_actor_set_visible_region_beneath: * @self: a #MetaWindowActor * @visible_region: the region of the screen that isn't completely * obscured beneath the main window texture. * * Provides a hint as to what areas need to be drawn *beneath* * the main window texture. This is the relevant visible region * when drawing the shadow, properly accounting for areas of the * shadow hid by the window itself. This will be set before painting * then unset afterwards. */ LOCAL_SYMBOL void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self, cairo_region_t *beneath_region) { MetaWindowActorPrivate *priv = self->priv; gboolean appears_focused = meta_window_appears_focused (priv->window); if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow) { g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); priv->shadow_clip = cairo_region_copy (beneath_region); if (clip_shadow_under_window (self)) cairo_region_subtract (priv->shadow_clip, meta_window_get_frame_bounds (priv->window)); } } /** * meta_window_actor_reset_visible_regions: * @self: a #MetaWindowActor * * Unsets the regions set by meta_window_actor_reset_visible_region() and * meta_window_actor_reset_visible_region_beneath() */ LOCAL_SYMBOL void meta_window_actor_reset_visible_regions (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor), NULL); g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); } static void check_needs_pixmap (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaScreen *screen = priv->screen; MetaDisplay *display = screen->display; Display *xdisplay = display->xdisplay; MetaCompositor *compositor = display->compositor; Window xwindow = priv->xwindow; if ((!priv->window->mapped && !priv->window->shaded) || !priv->needs_pixmap) return; if (xwindow == screen->xroot || xwindow == clutter_x11_get_stage_window (compositor->stage)) return; if (priv->size_changed) { meta_window_actor_detach (self); priv->size_changed = FALSE; } if (priv->position_changed) priv->position_changed = FALSE; meta_error_trap_push (display); if (priv->back_pixmap == None) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); CoglTexture *texture; meta_error_trap_push (display); priv->back_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); if (meta_error_trap_pop_with_return (display) != Success) { /* Probably a BadMatch if the window isn't viewable; we could * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync * to avoid this, but there's no reason to take two round trips * when one will do. (We need that Sync if we want to handle failures * for any reason other than !viewable. That's unlikely, but maybe * we'll BadAlloc or something.) */ priv->back_pixmap = None; } if (priv->back_pixmap == None) { meta_verbose ("Unable to get named pixmap for %p\n", self); goto out; } if (compositor->no_mipmaps) meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor), FALSE); texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL)); /* * This only works *after* actually setting the pixmap, so we have to * do it here. * See: http://bugzilla.clutter-project.org/show_bug.cgi?id=2236 */ if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture))) g_warning ("NOTE: Not using GLX TFP!\n"); meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture); } priv->needs_pixmap = FALSE; out: meta_error_trap_pop (display); } static void check_needs_shadow (MetaWindowActor *self) { if (!self->priv->window->display->shadows_enabled) { return; } MetaWindowActorPrivate *priv = self->priv; MetaShadow *old_shadow = NULL; MetaShadow **shadow_location; gboolean recompute_shadow; gboolean should_have_shadow; gboolean appears_focused; if (!priv->window->mapped && !priv->window->shaded) return; /* Calling meta_window_actor_has_shadow() here at every pre-paint is cheap * and avoids the need to explicitly handle window type changes, which * we would do if tried to keep track of when we might be adding or removing * a shadow more explicitly. We only keep track of changes to the *shape* of * the shadow with priv->recompute_shadow. */ should_have_shadow = meta_window_actor_has_shadow (self); priv->should_have_shadow = should_have_shadow; appears_focused = meta_window_appears_focused (priv->window); if (appears_focused) { recompute_shadow = priv->recompute_focused_shadow; priv->recompute_focused_shadow = FALSE; shadow_location = &priv->focused_shadow; } else { recompute_shadow = priv->recompute_unfocused_shadow; priv->recompute_unfocused_shadow = FALSE; shadow_location = &priv->unfocused_shadow; } if (!should_have_shadow || recompute_shadow) { if (*shadow_location != NULL) { old_shadow = *shadow_location; *shadow_location = NULL; } } if (*shadow_location == NULL && should_have_shadow) { if (priv->shadow_shape == NULL) { if (priv->shape_region) priv->shadow_shape = meta_window_shape_new (priv->shape_region); } if (priv->shadow_shape != NULL) { MetaShadowFactory *factory = meta_shadow_factory_get_default (); const char *shadow_class = meta_window_actor_get_shadow_class (self); cairo_rectangle_int_t shape_bounds; meta_window_actor_get_shape_bounds (self, &shape_bounds); *shadow_location = meta_shadow_factory_get_shadow (factory, priv->shadow_shape, shape_bounds.width, shape_bounds.height, shadow_class, appears_focused); } } if (old_shadow != NULL) meta_shadow_unref (old_shadow); } LOCAL_SYMBOL void meta_window_actor_process_damage (MetaWindowActor *self, XDamageNotifyEvent *event) { MetaWindowActorPrivate *priv = self->priv; MetaCompositor *compositor = priv->window->display->compositor; priv->received_damage = TRUE; /* Drop damage event for unredirected windows */ if (priv->unredirected) return; if (meta_window_is_fullscreen (priv->window) && g_list_last (compositor->windows)->data == self) { MetaRectangle window_rect; meta_window_get_outer_rect (priv->window, &window_rect); if (event->area.x == 0 && event->area.y == 0 && window_rect.width == event->area.width && window_rect.height == event->area.height) priv->full_damage_frames_count++; else priv->full_damage_frames_count = 0; if (priv->full_damage_frames_count >= 100) priv->does_full_damage = TRUE; } if (priv->freeze_count) { /* The window is frozen due to an effect in progress: we ignore damage * here on the off chance that this will stop the corresponding * texture_from_pixmap from being update. * * needs_damage_all tracks that some unknown damage happened while the * window was frozen so that when the window becomes unfrozen we can * issue a full window update to cover any lost damage. * * It should be noted that this is an unreliable mechanism since it's * quite likely that drivers will aim to provide a zero-copy * implementation of the texture_from_pixmap extension and in those cases * any drawing done to the window is always immediately reflected in the * texture regardless of damage event handling. */ priv->needs_damage_all = TRUE; return; } if (!priv->window->mapped || priv->needs_pixmap) return; update_area (self, event->area.x, event->area.y, event->area.width, event->area.height); priv->repaint_scheduled = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor), event->area.x, event->area.y, event->area.width, event->area.height, clutter_actor_has_mapped_clones (priv->actor) ? NULL : priv->unobscured_region); } LOCAL_SYMBOL void meta_window_actor_sync_visibility (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible) { if (priv->visible) clutter_actor_show (CLUTTER_ACTOR (self)); else clutter_actor_hide (CLUTTER_ACTOR (self)); } } static inline void set_integral_bounding_rect (cairo_rectangle_int_t *rect, double x, double y, double width, double height) { rect->x = floor(x); rect->y = floor(y); rect->width = ceil(x + width) - rect->x; rect->height = ceil(y + height) - rect->y; } static void update_corners (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaRectangle outer = priv->window->frame->rect; MetaFrameBorders borders; cairo_rectangle_int_t corner_rects[4]; cairo_region_t *corner_region; cairo_path_t *corner_path; float top_left, top_right, bottom_left, bottom_right; float x, y; /* need these to build a path */ cairo_t *cr; cairo_surface_t *surface; meta_frame_calc_borders (priv->window->frame, &borders); outer.width -= borders.invisible.left + borders.invisible.right; outer.height -= borders.invisible.top + borders.invisible.bottom; meta_frame_get_corner_radiuses (priv->window->frame, &top_left, &top_right, &bottom_left, &bottom_right); /* Unfortunately, cairo does not allow us to create a context * without a surface. Create a 0x0 image surface to "paint to" * so we can get the path. */ surface = cairo_image_surface_create (CAIRO_FORMAT_A8, 0, 0); cr = cairo_create (surface); /* top left */ x = borders.invisible.left; y = borders.invisible.top; set_integral_bounding_rect (&corner_rects[0], x, y, top_left, top_left); cairo_arc (cr, x + top_left, y + top_left, top_left, 0, M_PI*2); /* top right */ x = x + outer.width - top_right; set_integral_bounding_rect (&corner_rects[1], x, y, top_right, top_right); cairo_arc (cr, x, y + top_right, top_right, 0, M_PI*2); /* bottom right */ x = borders.invisible.left + outer.width - bottom_right; y = y + outer.height - bottom_right; set_integral_bounding_rect (&corner_rects[2], x, y, bottom_right, bottom_right); cairo_arc (cr, x, y, bottom_right, 0, M_PI*2); /* bottom left */ x = borders.invisible.left; y = borders.invisible.top + outer.height - bottom_left; set_integral_bounding_rect (&corner_rects[3], x, y, bottom_left, bottom_left); cairo_arc (cr, x + bottom_left, y, bottom_left, 0, M_PI*2); corner_path = cairo_copy_path (cr); cairo_surface_destroy (surface); cairo_destroy (cr); corner_region = cairo_region_create_rectangles (corner_rects, 4); meta_shaped_texture_set_overlay_path (META_SHAPED_TEXTURE (priv->actor), corner_region, corner_path); cairo_region_destroy (corner_region); } static void check_needs_reshape (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaScreen *screen = priv->screen; MetaDisplay *display = meta_screen_get_display (screen); cairo_region_t *region = NULL; cairo_rectangle_int_t client_area; gboolean full_mask_reset = priv->window->fullscreen; if ((!priv->window->mapped && !priv->window->shaded) || !priv->needs_reshape) return; g_clear_pointer (&priv->shape_region, cairo_region_destroy); g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); g_clear_pointer (&priv->opaque_region, cairo_region_destroy); meta_window_get_client_area_rect (priv->window, &client_area); if (priv->window->frame) region = meta_window_get_frame_bounds (priv->window); if (region != NULL) { /* This returns the window's internal frame bounds region, * so we need to copy it because we modify it below. */ region = cairo_region_copy (region); } else { /* If we have no region, we have no frame. We have no frame, * so just use the client_area instead */ region = cairo_region_create_rectangle (&client_area); } #ifdef HAVE_SHAPE if (priv->window->has_shape) { Display *xdisplay = meta_display_get_xdisplay (display); XRectangle *rects; int n_rects, ordering; /* Punch out client area. */ cairo_region_subtract_rectangle (region, &client_area); meta_error_trap_push (display); rects = XShapeGetRectangles (xdisplay, priv->window->xwindow, ShapeBounding, &n_rects, &ordering); meta_error_trap_pop (display); if (rects) { int i; for (i = 0; i < n_rects; i ++) { cairo_rectangle_int_t rect = { rects[i].x + client_area.x, rects[i].y + client_area.y, rects[i].width, rects[i].height }; cairo_region_union_rectangle (region, &rect); } XFree (rects); } } #endif if (priv->argb32 && priv->window->opaque_region != NULL) { /* The opaque region is defined to be a part of the * window which ARGB32 will always paint with opaque * pixels. For these regions, we want to avoid painting * windows and shadows beneath them. * * If the client gives bad coordinates where it does not * fully paint, the behavior is defined by the specification * to be undefined, and considered a client bug. In mutter's * case, graphical glitches will occur. */ priv->opaque_region = cairo_region_copy (priv->window->opaque_region); cairo_region_translate (priv->opaque_region, client_area.x, client_area.y); cairo_region_intersect (priv->opaque_region, region); } else if (priv->argb32) priv->opaque_region = NULL; else priv->opaque_region = cairo_region_reference (region); if (priv->window->frame) update_corners (self); else if (priv->window->has_shape && priv->reshapes == 1) full_mask_reset = TRUE; else if (priv->reshapes < 2) priv->reshapes++; if (priv->window->frame != NULL || priv->window->has_shape) meta_window_actor_reset_mask_texture (self, region, full_mask_reset); meta_window_actor_update_shape_region (self, region); cairo_region_destroy (region); priv->needs_reshape = FALSE; meta_window_actor_invalidate_shadow (self); } LOCAL_SYMBOL void meta_window_actor_update_shape (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; priv->needs_reshape = TRUE; if (is_frozen (self)) return; clutter_actor_queue_redraw (priv->actor); } LOCAL_SYMBOL void meta_window_actor_handle_updates (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaScreen *screen = priv->screen; MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); if (is_frozen (self)) { /* The window is frozen due to a pending animation: we'll wait until * the animation finishes to reshape and repair the window */ return; } if (priv->unredirected) { /* Nothing to do here until/if the window gets redirected again */ return; } if (!priv->visible && !priv->needs_pixmap) return; if (priv->received_damage) { meta_error_trap_push (display); XDamageSubtract (xdisplay, priv->damage, None, None); meta_error_trap_pop (display); priv->received_damage = FALSE; } check_needs_pixmap (self); check_needs_reshape (self); check_needs_shadow (self); } void meta_window_actor_pre_paint (MetaWindowActor *self) { if (meta_window_actor_is_destroyed (self)) return; meta_window_actor_handle_updates (self); assign_frame_counter_to_frames (self); } static void do_send_frame_drawn (MetaWindowActor *self, FrameData *frame) { MetaWindowActorPrivate *priv = self->priv; MetaDisplay *display = meta_screen_get_display (priv->screen); MetaWindow *window = meta_window_actor_get_meta_window (self); Display *xdisplay = meta_display_get_xdisplay (display); XClientMessageEvent ev = { 0, }; frame->frame_drawn_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ()); priv->frame_drawn_time = frame->frame_drawn_time; ev.type = ClientMessage; ev.window = meta_window_get_xwindow (window); ev.message_type = display->atom__NET_WM_FRAME_DRAWN; ev.format = 32; ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff); ev.data.l[1] = frame->sync_request_serial >> 32; ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT(0xffffffff); ev.data.l[3] = frame->frame_drawn_time >> 32; meta_error_trap_push (display); XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev); XFlush (xdisplay); meta_error_trap_pop (display); } void meta_window_actor_post_paint (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; priv->repaint_scheduled = FALSE; if (meta_window_actor_is_destroyed (self)) return; /* If the window had damage, but wasn't actually redrawn because * it is obscured, we should wait until timer expiration before * sending _NET_WM_FRAME_* messages. */ if (priv->send_frame_messages_timer == 0 && priv->needs_frame_drawn) { GList *l; for (l = priv->frames; l; l = l->next) { FrameData *frame = l->data; if (frame->frame_drawn_time == 0) do_send_frame_drawn (self, frame); } priv->needs_frame_drawn = FALSE; } } static void do_send_frame_timings (MetaWindowActor *self, FrameData *frame, gint refresh_interval, gint64 presentation_time) { MetaWindowActorPrivate *priv = self->priv; MetaDisplay *display = meta_screen_get_display (priv->screen); MetaWindow *window = meta_window_actor_get_meta_window (self); Display *xdisplay = meta_display_get_xdisplay (display); XClientMessageEvent ev = { 0, }; ev.type = ClientMessage; ev.window = meta_window_get_xwindow (window); ev.message_type = display->atom__NET_WM_FRAME_TIMINGS; ev.format = 32; ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff); ev.data.l[1] = frame->sync_request_serial >> 32; if (presentation_time != 0) { gint64 presentation_time_server = meta_compositor_monotonic_time_to_server_time (display, presentation_time); gint64 presentation_time_offset = presentation_time_server - frame->frame_drawn_time; if (presentation_time_offset == 0) presentation_time_offset = 1; if ((gint32)presentation_time_offset == presentation_time_offset) ev.data.l[2] = presentation_time_offset; } ev.data.l[3] = refresh_interval; ev.data.l[4] = 1000 * META_SYNC_DELAY; meta_error_trap_push (display); XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev); XFlush (xdisplay); meta_error_trap_pop (display); } static void send_frame_timings (MetaWindowActor *self, FrameData *frame, CoglFrameInfo *frame_info, gint64 presentation_time) { MetaWindow *window = meta_window_actor_get_meta_window (self); float refresh_rate; int refresh_interval; refresh_rate = window->monitor->refresh_rate; /* 0.0 is a flag for not known, but sanity-check against other odd numbers */ if (refresh_rate >= 1.0) refresh_interval = (int) (0.5 + 1000000 / refresh_rate); else refresh_interval = 0; do_send_frame_timings (self, frame, refresh_interval, presentation_time); } void meta_window_actor_frame_complete (MetaWindowActor *self, ClutterFrameInfo *frame_info, gint64 presentation_time) { MetaWindowActorPrivate *priv = self->priv; GList *l; if (meta_window_actor_is_destroyed (self)) return; for (l = priv->frames; l;) { GList *l_next = l->next; FrameData *frame = l->data; gint64 frame_counter = frame_info->frame_counter; if (frame->frame_counter != -1 && frame->frame_counter <= frame_counter) { if (G_UNLIKELY (frame->frame_drawn_time == 0)) g_warning ("%s: Frame has assigned frame counter but no frame drawn time", priv->window->desc); if (G_UNLIKELY (frame->frame_counter < frame_counter)) g_warning ("%s: frame_complete callback never occurred for frame %" G_GINT64_FORMAT, priv->window->desc, frame->frame_counter); priv->frames = g_list_delete_link (priv->frames, l); send_frame_timings (self, frame, frame_info, presentation_time); frame_data_free (frame); } l = l_next; } } LOCAL_SYMBOL void meta_window_actor_invalidate_shadow (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; priv->recompute_focused_shadow = TRUE; priv->recompute_unfocused_shadow = TRUE; if (is_frozen (self)) return; clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); } LOCAL_SYMBOL void meta_window_actor_update_opacity (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaDisplay *display = meta_screen_get_display (priv->screen); MetaCompositor *compositor = meta_display_get_compositor (display); Window xwin = meta_window_get_xwindow (priv->window); gulong value; guint8 opacity; if (meta_prop_get_cardinal (display, xwin, compositor->atom_net_wm_window_opacity, &value)) { opacity = (guint8)((gfloat)value * 255.0 / ((gfloat)0xffffffff)); } else opacity = 255; self->priv->opacity = opacity; clutter_actor_set_opacity (self->priv->actor, opacity); } void meta_window_actor_set_updates_frozen (MetaWindowActor *self, gboolean updates_frozen) { MetaWindowActorPrivate *priv = self->priv; updates_frozen = updates_frozen != FALSE; if (priv->updates_frozen != updates_frozen) { priv->updates_frozen = updates_frozen; if (updates_frozen) meta_window_actor_freeze (self); else meta_window_actor_thaw (self); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-module.h�����������������������������������������������������������0000664�0001750�0001750�00000003566�14211404421�020515� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_MODULE_H_ #define META_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)) typedef struct _MetaModule MetaModule; typedef struct _MetaModuleClass MetaModuleClass; typedef struct _MetaModulePrivate MetaModulePrivate; struct _MetaModule { GTypeModule parent; MetaModulePrivate *priv; }; struct _MetaModuleClass { GTypeModuleClass parent_class; }; GType meta_module_get_type (void); GType meta_module_get_plugin_type (MetaModule *module); #endif ������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-texture-tower.c����������������������������������������������������0000664�0001750�0001750�00000036237�14211404421�022062� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #include <math.h> #include <string.h> #include "meta-texture-tower.h" #include "meta-texture-rectangle.h" #include "cogl-utils.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; CoglTexture *textures[MAX_TEXTURE_LEVELS]; CoglOffscreen *fbos[MAX_TEXTURE_LEVELS]; Box invalid[MAX_TEXTURE_LEVELS]; CoglPipeline *pipeline_template; }; /** * 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() */ LOCAL_SYMBOL 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(). */ LOCAL_SYMBOL void meta_texture_tower_free (MetaTextureTower *tower) { g_return_if_fail (tower != NULL); if (tower->pipeline_template != NULL) cogl_object_unref (tower->pipeline_template); meta_texture_tower_set_base_texture (tower, NULL); g_slice_free (MetaTextureTower, tower); } /** * meta_texture_tower_set_base_texture: * @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. */ LOCAL_SYMBOL void meta_texture_tower_set_base_texture (MetaTextureTower *tower, CoglTexture *texture) { int i; g_return_if_fail (tower != NULL); if (texture == tower->textures[0]) return; if (tower->textures[0] != NULL) { for (i = 1; i < tower->n_levels; i++) { if (tower->textures[i] != NULL) { cogl_object_unref (tower->textures[i]); tower->textures[i] = NULL; } if (tower->fbos[i] != NULL) { cogl_object_unref (tower->fbos[i]); tower->fbos[i] = NULL; } } cogl_object_unref (tower->textures[0]); } tower->textures[0] = texture; if (tower->textures[0] != NULL) { int width, height; cogl_object_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. */ LOCAL_SYMBOL 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); if (tower->textures[0] == NULL) return; 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); } static gboolean is_power_of_two (int x) { return (x & (x - 1)) == 0; } static void texture_tower_create_texture (MetaTextureTower *tower, int level, int width, int height) { if ((!is_power_of_two (width) || !is_power_of_two (height)) && meta_texture_rectangle_check (tower->textures[level - 1])) { CoglTextureRectangle *texture_rectangle; texture_rectangle = cogl_texture_rectangle_new_with_size (meta_compositor_get_cogl_context (), width, height); tower->textures[level] = COGL_TEXTURE (texture_rectangle); } else { 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 void texture_tower_revalidate (MetaTextureTower *tower, int level) { CoglTexture *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); CoglTexture *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]; CoglFramebuffer *fb; CoglError *catch_error = NULL; CoglPipeline *pipeline; if (tower->fbos[level] == NULL) tower->fbos[level] = cogl_offscreen_new_with_texture (dest_texture); fb = COGL_FRAMEBUFFER (tower->fbos[level]); if (!cogl_framebuffer_allocate (fb, &catch_error)) { cogl_error_free (catch_error); return; } cogl_framebuffer_orthographic (fb, 0, 0, dest_texture_width, dest_texture_height, -1., 1.); if (!tower->pipeline_template) { tower->pipeline_template = cogl_pipeline_new (meta_compositor_get_cogl_context ()); cogl_pipeline_set_blend (tower->pipeline_template, "RGBA = ADD (SRC_COLOR, 0)", NULL); } pipeline = cogl_pipeline_copy (tower->pipeline_template); cogl_pipeline_set_layer_texture (pipeline, 0, tower->textures[level - 1]); cogl_framebuffer_draw_textured_rectangle (fb, pipeline, 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_object_unref (pipeline); tower->invalid[level].x1 = tower->invalid[level].x2 = 0; tower->invalid[level].y1 = tower->invalid[level].y2 = 0; } /** * 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 * %NULL if no base texture has yet been set. */ LOCAL_SYMBOL CoglTexture * meta_texture_tower_get_paint_texture (MetaTextureTower *tower) { int texture_width, texture_height; int level; g_return_val_if_fail (tower != NULL, NULL); if (tower->textures[0] == NULL) return NULL; 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 NULL; level = MIN (level, tower->n_levels - 1); if (tower->textures[level] == NULL || (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] == NULL) 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]; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/compositor-private.h����������������������������������������������������0000664�0001750�0001750�00000005440�14211404421�022143� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ #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 "meta-window-actor-private.h" #include <clutter/clutter.h> struct _MetaCompositor { MetaDisplay *display; MetaScreen *screen; Atom atom_x_root_pixmap; Atom atom_x_set_root; Atom atom_net_wm_window_opacity; guint pre_paint_func_id; guint post_paint_func_id; ClutterActor *stage, *shadow_src; ClutterActor *bottom_window_group, *window_group, *overlay_group, *top_window_group; ClutterActor *background_actor; ClutterActor *hidden_group; GList *windows; MetaWindowActor *unredirected_window; CoglContext *context; Window output; /* Used for unredirecting fullscreen windows */ guint disable_unredirect_count; /* Before we create the output window */ XserverRegion pending_input_region; gint switch_workspace_in_progress; MetaPluginManager *plugin_mgr; MetaPlugin *modal_plugin; gint64 server_time_query_time; gint64 server_time_offset; guint server_time_is_monotonic_time : 1; guint show_redraw : 1; guint debug : 1; guint no_mipmaps : 1; gboolean frame_has_updated_xsurfaces; gboolean have_x11_sync_object; }; /* Wait 2ms after vblank before starting to draw next frame */ #define META_SYNC_DELAY 0 CoglContext * meta_compositor_get_cogl_context (void); void meta_switch_workspace_completed (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); gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display, gint64 monotonic_time); void meta_compositor_grab_op_begin (MetaCompositor *compositor); void meta_compositor_grab_op_end (MetaCompositor *compositor); void meta_check_end_modal (MetaScreen *screen); void meta_compositor_update_sync_state (MetaCompositor *compositor, MetaSyncMethod method); #endif /* META_COMPOSITOR_PRIVATE_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-sync-ring.h��������������������������������������������������������0000664�0001750�0001750�00000000536�14211404421�021133� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _META_SYNC_RING_H_ #define _META_SYNC_RING_H_ #include <glib.h> #include <X11/Xlib.h> gboolean meta_sync_ring_init (Display *dpy); void meta_sync_ring_destroy (void); gboolean meta_sync_ring_after_frame (void); gboolean meta_sync_ring_insert_wait (void); void meta_sync_ring_handle_event (XEvent *event); #endif /* _META_SYNC_RING_H_ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/compositor/meta-texture-rectangle.c������������������������������������������������0000664�0001750�0001750�00000004215�14211404421�022655� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * texture rectangle * * A small utility function to help create a rectangle texture * * Authored By Neil Roberts <neil@linux.intel.com> * * Copyright (C) 2011, 2012 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <clutter/clutter.h> #include "meta-texture-rectangle.h" static void texture_rectangle_check_cb (CoglTexture *sub_texture, const float *sub_texture_coords, const float *meta_coords, void *user_data) { gboolean *result = user_data; if (cogl_is_texture_rectangle (sub_texture)) *result = TRUE; } /* Determines if the given texture is using a rectangle texture as its * primitive texture type. Eventually this function could be replaced * with cogl_texture_get_type if Cogl makes that public. * * http://git.gnome.org/browse/cogl/commit/?h=8012eee31 */ LOCAL_SYMBOL gboolean meta_texture_rectangle_check (CoglTexture *texture) { gboolean result = FALSE; cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (texture), 0.0f, 0.0f, /* tx_1 / ty_1 */ 1.0f, 1.0f, /* tx_2 / ty_2 */ COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, texture_rectangle_check_cb, &result); return result; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/tools/�����������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�015063� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/tools/muffin-grayscale.c�����������������������������������������������������������0000664�0001750�0001750�00000004722�14211404421�020470� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Hack for grayscaling an image */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <gdk-pixbuf/gdk-pixbuf.h> #include <unistd.h> #include <stdlib.h> #include <math.h> #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) static GdkPixbuf* grayscale_pixbuf (GdkPixbuf *pixbuf) { GdkPixbuf *gray; guchar *pixels; int rowstride; int pixstride; int row; int n_rows; int width; gray = gdk_pixbuf_copy (pixbuf); rowstride = gdk_pixbuf_get_rowstride (gray); pixstride = gdk_pixbuf_get_has_alpha (gray) ? 4 : 3; pixels = gdk_pixbuf_get_pixels (gray); n_rows = gdk_pixbuf_get_height (gray); width = gdk_pixbuf_get_width (gray); row = 0; while (row < n_rows) { guchar *p = pixels + row * rowstride; guchar *end = p + (pixstride * width); while (p != end) { double v = INTENSITY (p[0], p[1], p[2]); p[0] = (guchar) v; p[1] = (guchar) v; p[2] = (guchar) v; p += pixstride; } ++row; } return gray; } int main (int argc, char **argv) { GdkPixbuf *pixbuf; GdkPixbuf *gray; GError *err; if (argc != 2) { g_printerr ("specify a single image on the command line\n"); return 1; } err = NULL; pixbuf = gdk_pixbuf_new_from_file (argv[1], &err); if (err != NULL) { g_printerr ("failed to load image: %s\n", err->message); g_error_free (err); return 1; } gray = grayscale_pixbuf (pixbuf); err = NULL; gdk_pixbuf_save (gray, "grayscale.png", "png", &err, NULL); if (err != NULL) { g_printerr ("failed to save image: %s\n", err->message); g_error_free (err); return 1; } g_print ("wrote grayscale.png\n"); return 0; } ����������������������������������������������muffin-5.2.1/src/tools/Makefile.am������������������������������������������������������������������0000664�0001750�0001750�00000001544�14211404421�017123� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������@INTLTOOL_DESKTOP_RULE@ icondir=$(pkgdatadir)/icons icon_DATA=muffin-window-demo.png AM_CPPFLAGS=$(WARN_CFLAGS) @MUFFIN_WINDOW_DEMO_CFLAGS@ @MUFFIN_MESSAGE_CFLAGS@ \ -I$(top_srcdir)/src \ -DMUFFIN_ICON_DIR=\"$(pkgdatadir)/icons\" \ -DMUFFIN_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" muffin_message_SOURCES= \ muffin-message.c muffin_window_demo_SOURCES= \ muffin-window-demo.c muffin_mag_SOURCES= \ muffin-mag.c muffin_grayscale_SOURCES= \ muffin-grayscale.c bin_PROGRAMS=muffin-message muffin-window-demo ## cheesy hacks I use, don't really have any business existing. ;-) noinst_PROGRAMS=muffin-mag muffin-grayscale muffin_message_LDADD= @MUFFIN_MESSAGE_LIBS@ muffin_window_demo_LDADD= @MUFFIN_WINDOW_DEMO_LIBS@ muffin_mag_LDADD= @MUFFIN_WINDOW_DEMO_LIBS@ muffin_grayscale_LDADD = @MUFFIN_WINDOW_DEMO_LIBS@ EXTRA_DIST=$(icon_DATA) ������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/tools/muffin-message.c�������������������������������������������������������������0000664�0001750�0001750�00000010122�14211404421�020131� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Muffin send-magic-messages app */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <gtk/gtk.h> #include <gdk/gdkx.h> #include <stdlib.h> #include <string.h> #include <glib/gi18n.h> static Display *display; static void send_reload_theme (void) { XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.display = display; xev.xclient.window = gdk_x11_get_default_root_xwindow (); xev.xclient.message_type = XInternAtom (display, "_MUFFIN_RELOAD_THEME_MESSAGE", False); xev.xclient.format = 32; xev.xclient.data.l[0] = 0; xev.xclient.data.l[1] = 0; xev.xclient.data.l[2] = 0; XSendEvent (display, gdk_x11_get_default_root_xwindow (), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); XFlush (display); XSync (display, False); } static void send_set_keybindings (gboolean enabled) { XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.display = display; xev.xclient.window = gdk_x11_get_default_root_xwindow (); xev.xclient.message_type = XInternAtom (display, "_MUFFIN_SET_KEYBINDINGS_MESSAGE", False); xev.xclient.format = 32; xev.xclient.data.l[0] = enabled; xev.xclient.data.l[1] = 0; xev.xclient.data.l[2] = 0; XSendEvent (display, gdk_x11_get_default_root_xwindow (), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); XFlush (display); XSync (display, False); } #ifdef WITH_VERBOSE_MODE static void send_toggle_verbose (void) { XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.display = display; xev.xclient.window = gdk_x11_get_default_root_xwindow (); xev.xclient.message_type = XInternAtom (display, "_MUFFIN_TOGGLE_VERBOSE", False); xev.xclient.format = 32; xev.xclient.data.l[0] = 0; xev.xclient.data.l[1] = 0; xev.xclient.data.l[2] = 0; XSendEvent (display, gdk_x11_get_default_root_xwindow (), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); XFlush (display); XSync (display, False); } #endif static void usage (void) { g_printerr (_("Usage: %s\n"), "muffin-message (reload-theme|enable-keybindings|disable-keybindings|toggle-verbose)"); exit (1); } int main (int argc, char **argv) { bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); gtk_init (&argc, &argv); if (argc < 2) usage (); display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); if (strcmp (argv[1], "reload-theme") == 0) send_reload_theme (); else if (strcmp (argv[1], "enable-keybindings") == 0) send_set_keybindings (TRUE); else if (strcmp (argv[1], "disable-keybindings") == 0) send_set_keybindings (FALSE); else if (strcmp (argv[1], "toggle-verbose") == 0) { #ifndef WITH_VERBOSE_MODE g_printerr (_("Muffin was compiled without support for verbose mode\n")); return 1; #else send_toggle_verbose (); #endif } else usage (); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/tools/muffin-window-demo.c���������������������������������������������������������0000664�0001750�0001750�00000072245�14211404421�020754� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Muffin window types/properties demo app */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <gtk/gtk.h> #include <gdk/gdkx.h> #include <X11/Xatom.h> #include <unistd.h> static GtkWidget* do_appwindow (void); static gboolean aspect_on; static void set_gdk_window_struts (GdkWindow *window, int left, int right, int top, int bottom) { long vals[12]; vals[0] = left; vals[1] = right; vals[2] = top; vals[3] = bottom; vals[4] = 000; vals[5] = 400; vals[6] = 200; vals[7] = 600; vals[8] = 76; vals[9] = 676; vals[10] = 200; vals[11] = 800; XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), XInternAtom (GDK_WINDOW_XDISPLAY (window), "_NET_WM_STRUT_PARTIAL", False), XA_CARDINAL, 32, PropModeReplace, (guchar *)vals, 12); } static void on_realize_set_struts (GtkWindow *window, gpointer data) { GtkWidget *widget; int left; int right; int top; int bottom; widget = GTK_WIDGET (window); g_return_if_fail (gtk_widget_get_realized (widget)); left = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "meta-strut-left")); right = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "meta-strut-right")); top = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "meta-strut-top")); bottom = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "meta-strut-bottom")); set_gdk_window_struts (gtk_widget_get_window (widget), left, right, top, bottom); } static void set_gtk_window_struts (GtkWidget *window, int left, int right, int top, int bottom) { GtkWidget *widget; widget = GTK_WIDGET (window); g_object_set_data (G_OBJECT (window), "meta-strut-left", GINT_TO_POINTER (left)); g_object_set_data (G_OBJECT (window), "meta-strut-right", GINT_TO_POINTER (right)); g_object_set_data (G_OBJECT (window), "meta-strut-top", GINT_TO_POINTER (top)); g_object_set_data (G_OBJECT (window), "meta-strut-bottom", GINT_TO_POINTER (bottom)); g_signal_handlers_disconnect_by_func (G_OBJECT (window), on_realize_set_struts, NULL); g_signal_connect_after (G_OBJECT (window), "realize", G_CALLBACK (on_realize_set_struts), NULL); if (gtk_widget_get_realized (widget)) set_gdk_window_struts (gtk_widget_get_window (widget), left, right, top, bottom); } static void set_gdk_window_type (GdkWindow *window, const char *type) { Atom atoms[2] = { None, None }; atoms[0] = XInternAtom (GDK_WINDOW_XDISPLAY (window), type, False); XChangeProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), XInternAtom (GDK_WINDOW_XDISPLAY (window), "_NET_WM_WINDOW_TYPE", False), XA_ATOM, 32, PropModeReplace, (guchar *)atoms, 1); } static void on_realize_set_type (GtkWindow *window, gpointer data) { GtkWidget *widget; const char *type; widget = GTK_WIDGET (window); g_return_if_fail (gtk_widget_get_realized (widget)); type = g_object_get_data (G_OBJECT (window), "meta-window-type"); g_return_if_fail (type != NULL); set_gdk_window_type (gtk_widget_get_window (widget), type); } static void set_gtk_window_type (GtkWindow *window, const char *type) { GtkWidget *widget; widget = GTK_WIDGET (window); g_object_set_data (G_OBJECT (window), "meta-window-type", (char*) type); g_signal_handlers_disconnect_by_func (G_OBJECT (window), on_realize_set_type, NULL); g_signal_connect_after (G_OBJECT (window), "realize", G_CALLBACK (on_realize_set_type), NULL); if (gtk_widget_get_realized (widget)) set_gdk_window_type (gtk_widget_get_window (widget), type); } static void set_gdk_window_border_only (GdkWindow *window) { gdk_window_set_decorations (window, GDK_DECOR_BORDER); } static void on_realize_set_border_only (GtkWindow *window, gpointer data) { GtkWidget *widget; widget = GTK_WIDGET (window); g_return_if_fail (gtk_widget_get_realized (widget)); set_gdk_window_border_only (gtk_widget_get_window (widget)); } static void set_gtk_window_border_only (GtkWindow *window) { GtkWidget *widget; widget = GTK_WIDGET (window); g_signal_handlers_disconnect_by_func (G_OBJECT (window), on_realize_set_border_only, NULL); g_signal_connect_after (G_OBJECT (window), "realize", G_CALLBACK (on_realize_set_border_only), NULL); if (gtk_widget_get_realized (widget)) set_gdk_window_border_only (gtk_widget_get_window (widget)); } int main (int argc, char **argv) { GList *list; GdkPixbuf *pixbuf; GError *err; gtk_init (&argc, &argv); err = NULL; pixbuf = gdk_pixbuf_new_from_file (MUFFIN_ICON_DIR"/muffin-window-demo.png", &err); if (pixbuf) { list = g_list_prepend (NULL, pixbuf); gtk_window_set_default_icon_list (list); g_list_free (list); g_object_unref (G_OBJECT (pixbuf)); } else { g_printerr ("Could not load icon: %s\n", err->message); g_error_free (err); } do_appwindow (); gtk_main (); return 0; } static void response_cb (GtkDialog *dialog, int response_id, void *data); static void make_dialog (GtkWidget *parent, int depth) { GtkWidget *dialog; char *str; dialog = gtk_message_dialog_new (parent ? GTK_WINDOW (parent) : NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, parent ? "Here is a dialog %d" : "Here is a dialog %d with no transient parent", depth); str = g_strdup_printf ("%d dialog", depth); gtk_window_set_title (GTK_WINDOW (dialog), str); free (str); gtk_dialog_add_button (GTK_DIALOG (dialog), "Open child dialog", GTK_RESPONSE_ACCEPT); /* Close dialog on user response */ g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (response_cb), NULL); g_object_set_data (G_OBJECT (dialog), "depth", GINT_TO_POINTER (depth)); gtk_widget_show (dialog); } static void response_cb (GtkDialog *dialog, int response_id, void *data) { switch (response_id) { case GTK_RESPONSE_ACCEPT: make_dialog (GTK_WIDGET (dialog), GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), "depth")) + 1); break; default: gtk_widget_destroy (GTK_WIDGET (dialog)); break; } } static void dialog_cb (GtkAction *action, gpointer callback_data) { make_dialog (GTK_WIDGET (callback_data), 1); } static void modal_dialog_cb (GtkAction *action, gpointer callback_data) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (callback_data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "Here is a MODAL dialog"); set_gtk_window_type (GTK_WINDOW (dialog), "_NET_WM_WINDOW_TYPE_MODAL_DIALOG"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } static void no_parent_dialog_cb (GtkAction *action, gpointer callback_data) { make_dialog (NULL, 1); } static void utility_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *vbox; GtkWidget *button; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); set_gtk_window_type (GTK_WINDOW (window), "_NET_WM_WINDOW_TYPE_UTILITY"); gtk_window_set_title (GTK_WINDOW (window), "Utility"); gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (callback_data)); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); button = gtk_button_new_with_mnemonic ("_A button"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); button = gtk_button_new_with_mnemonic ("_B button"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); button = gtk_button_new_with_mnemonic ("_C button"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); button = gtk_button_new_with_mnemonic ("_D button"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_widget_show_all (window); } static void toolbar_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *vbox; GtkWidget *label; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); set_gtk_window_type (GTK_WINDOW (window), "_NET_WM_WINDOW_TYPE_TOOLBAR"); gtk_window_set_title (GTK_WINDOW (window), "Toolbar"); gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (callback_data)); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); label = gtk_label_new ("FIXME this needs a resize grip, etc."); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show_all (window); } static void menu_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *vbox; GtkWidget *label; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); set_gtk_window_type (GTK_WINDOW (window), "_NET_WM_WINDOW_TYPE_MENU"); gtk_window_set_title (GTK_WINDOW (window), "Menu"); gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (callback_data)); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); label = gtk_label_new ("FIXME this isn't a menu."); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show_all (window); } static void override_redirect_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *vbox; GtkWidget *label; window = gtk_window_new (GTK_WINDOW_POPUP); gtk_window_set_title (GTK_WINDOW (window), "Override Redirect"); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); label = gtk_label_new ("This is an override\nredirect window\nand should not be managed"); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show_all (window); } static void border_only_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *vbox; GtkWidget *label; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); set_gtk_window_border_only (GTK_WINDOW (window)); gtk_window_set_title (GTK_WINDOW (window), "Border only"); gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (callback_data)); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); label = gtk_label_new ("This window is supposed to have a border but no titlebar."); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show_all (window); } #if 0 static void changing_icon_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *vbox; GtkWidget *label; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Changing Icon"); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), vbox); label = gtk_label_new ("This window has an icon that changes over time"); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show_all (window); } #endif static gboolean focus_in_event_cb (GtkWidget *window, GdkEvent *event, gpointer data) { GtkWidget *widget; widget = GTK_WIDGET (data); gtk_label_set_text (GTK_LABEL (widget), "Has focus"); return TRUE; } static gboolean focus_out_event_cb (GtkWidget *window, GdkEvent *event, gpointer data) { GtkWidget *widget; widget = GTK_WIDGET (data); gtk_label_set_text (GTK_LABEL (widget), "Not focused"); return TRUE; } static GtkWidget* focus_label (GtkWidget *window) { GtkWidget *label; label = gtk_label_new ("Not focused"); g_signal_connect (G_OBJECT (window), "focus_in_event", G_CALLBACK (focus_in_event_cb), label); g_signal_connect (G_OBJECT (window), "focus_out_event", G_CALLBACK (focus_out_event_cb), label); return label; } static void splashscreen_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *image; GtkWidget *vbox; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); set_gtk_window_type (GTK_WINDOW (window), "_NET_WM_WINDOW_TYPE_SPLASHSCREEN"); gtk_window_set_title (GTK_WINDOW (window), "Splashscreen"); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), focus_label (window), FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); } enum { DOCK_TOP = 1, DOCK_BOTTOM = 2, DOCK_LEFT = 3, DOCK_RIGHT = 4, DOCK_ALL = 5 }; static void make_dock (int type) { GtkWidget *window; GtkWidget *image; GtkWidget *box; GtkWidget *button; g_return_if_fail (type != DOCK_ALL); box = NULL; switch (type) { case DOCK_LEFT: case DOCK_RIGHT: box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); break; case DOCK_TOP: case DOCK_BOTTOM: box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); break; case DOCK_ALL: break; } window = gtk_window_new (GTK_WINDOW_TOPLEVEL); set_gtk_window_type (GTK_WINDOW (window), "_NET_WM_WINDOW_TYPE_DOCK"); image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), focus_label (window), FALSE, FALSE, 0); button = gtk_button_new_with_label ("Close"); gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0); g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), window); gtk_container_add (GTK_CONTAINER (window), box); #define DOCK_SIZE 48 switch (type) { case DOCK_LEFT: gtk_widget_set_size_request (window, DOCK_SIZE, 400); gtk_window_move (GTK_WINDOW (window), 0, 000); set_gtk_window_struts (window, DOCK_SIZE, 0, 0, 0); gtk_window_set_title (GTK_WINDOW (window), "LeftDock"); break; case DOCK_RIGHT: gtk_widget_set_size_request (window, DOCK_SIZE, 400); gtk_window_move (GTK_WINDOW (window), gdk_screen_width () - DOCK_SIZE, 200); set_gtk_window_struts (window, 0, DOCK_SIZE, 0, 0); gtk_window_set_title (GTK_WINDOW (window), "RightDock"); break; case DOCK_TOP: gtk_widget_set_size_request (window, 600, DOCK_SIZE); gtk_window_move (GTK_WINDOW (window), 76, 0); set_gtk_window_struts (window, 0, 0, DOCK_SIZE, 0); gtk_window_set_title (GTK_WINDOW (window), "TopDock"); break; case DOCK_BOTTOM: gtk_widget_set_size_request (window, 600, DOCK_SIZE); gtk_window_move (GTK_WINDOW (window), 200, gdk_screen_height () - DOCK_SIZE); set_gtk_window_struts (window, 0, 0, 0, DOCK_SIZE); gtk_window_set_title (GTK_WINDOW (window), "BottomDock"); break; case DOCK_ALL: break; } gtk_widget_show_all (window); } static void dock_cb (GtkAction *action, gpointer callback_data) { guint callback_action; const gchar *name; name = gtk_action_get_name (action); if (!g_strcmp0 (name, "Top dock")) callback_action = DOCK_TOP; else if (!g_strcmp0 (name, "Bottom dock")) callback_action = DOCK_BOTTOM; else if (!g_strcmp0 (name, "Left dock")) callback_action = DOCK_LEFT; else if (!g_strcmp0 (name, "Right dock")) callback_action = DOCK_RIGHT; else if (!g_strcmp0 (name, "All docks")) callback_action = DOCK_ALL; else return; if (callback_action == DOCK_ALL) { make_dock (DOCK_TOP); make_dock (DOCK_BOTTOM); make_dock (DOCK_LEFT); make_dock (DOCK_RIGHT); } else { make_dock (callback_action); } } static void desktop_cb (GtkAction *action, gpointer callback_data) { GtkWidget *window; GtkWidget *label; GdkRGBA desktop_color; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); set_gtk_window_type (GTK_WINDOW (window), "_NET_WM_WINDOW_TYPE_DESKTOP"); gtk_window_set_title (GTK_WINDOW (window), "Desktop"); gtk_widget_set_size_request (window, gdk_screen_width (), gdk_screen_height ()); gtk_window_move (GTK_WINDOW (window), 0, 0); desktop_color.red = 0.32; desktop_color.green = 0.46; desktop_color.blue = 0.65; desktop_color.alpha = 1.0; gtk_widget_override_background_color (window, 0, &desktop_color); label = focus_label (window); gtk_container_add (GTK_CONTAINER (window), label); gtk_widget_show_all (window); } static void sleep_cb (GtkAction *action, gpointer data) { sleep (1000); } static void toggle_aspect_ratio (GtkAction *action, gpointer data) { GtkWidget *window; GdkGeometry geom; GtkWidget *widget = GTK_WIDGET (data); if (aspect_on) { geom.min_aspect = 0; geom.max_aspect = 65535; } else { geom.min_aspect = 1.777778; geom.max_aspect = 1.777778; } aspect_on = !aspect_on; window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); if (window) gtk_window_set_geometry_hints (GTK_WINDOW (window), widget, &geom, GDK_HINT_ASPECT); } static void toggle_decorated_cb (GtkWidget *button, gpointer data) { GtkWidget *window; window = gtk_widget_get_ancestor (data, GTK_TYPE_WINDOW); if (window) gtk_window_set_decorated (GTK_WINDOW (window), !gtk_window_get_decorated (GTK_WINDOW (window))); } static void clicked_toolbar_cb (GtkWidget *button, gpointer data) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (data), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "Clicking the toolbar buttons doesn't do anything"); /* Close dialog on user response */ g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_widget_show (dialog); } static void update_statusbar (GtkTextBuffer *buffer, GtkStatusbar *statusbar) { gchar *msg; gint row, col; gint count; GtkTextIter iter; gtk_statusbar_pop (statusbar, 0); /* clear any previous message, underflow is allowed */ count = gtk_text_buffer_get_char_count (buffer); gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer)); row = gtk_text_iter_get_line (&iter); col = gtk_text_iter_get_line_offset (&iter); msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document", row, col, count); gtk_statusbar_push (statusbar, 0, msg); free (msg); } static void mark_set_callback (GtkTextBuffer *buffer, const GtkTextIter *new_location, GtkTextMark *mark, gpointer data) { update_statusbar (buffer, GTK_STATUSBAR (data)); } static int window_count = 0; static void destroy_cb (GtkWidget *w, gpointer data) { --window_count; if (window_count == 0) gtk_main_quit (); } static const gchar *menu_item_string = "<ui>\n" "<menubar>\n" "<menu name='Windows' action='Windows'>\n" "<menuitem name='Dialog' action='Dialog'/>\n" "<menuitem name='Modal dialog' action='Modal dialog'/>\n" "<menuitem name='Parentless dialog' action='Parentless dialog'/>\n" "<menuitem name='Utility' action='Utility'/>\n" "<menuitem name='Splashscreen' action='Splashscreen'/>\n" "<menuitem name='Top dock' action='Top dock'/>\n" "<menuitem name='Bottom dock' action='Bottom dock'/>\n" "<menuitem name='Left dock' action='Left dock'/>\n" "<menuitem name='Right dock' action='Right dock'/>\n" "<menuitem name='All docks' action='All docks'/>\n" "<menuitem name='Desktop' action='Desktop'/>\n" "<menuitem name='Menu' action='Menu'/>\n" "<menuitem name='Toolbar' action='Toolbar'/>\n" "<menuitem name='Override Redirect' action='Override Redirect'/>\n" "<menuitem name='Border Only' action='Border Only'/>\n" "</menu>\n" "</menubar>\n" "<toolbar>\n" "<toolitem name='New' action='New'/>\n" "<toolitem name='Lock' action='Lock'/>\n" "<toolitem name='Decorations' action='Decorations'/>\n" "<toolitem name='Ratio' action='Ratio'/>\n" "<toolitem name='Quit' action='Quit'/>\n" "</toolbar>\n" "</ui>\n"; static const GtkActionEntry menu_items[] = { { "Windows", NULL, "_Windows", NULL, NULL, NULL }, { "Dialog", NULL, "_Dialog", "<control>d", NULL, G_CALLBACK (dialog_cb) }, { "Modal dialog", NULL, "_Modal dialog", NULL, NULL, G_CALLBACK (modal_dialog_cb) }, { "Parentless dialog", NULL, "_Parentless dialog", NULL, NULL, G_CALLBACK (no_parent_dialog_cb) }, { "Utility", NULL, "_Utility", "<control>u", NULL, G_CALLBACK (utility_cb) }, { "Splashscreen", NULL, "_Splashscreen", "<control>s", NULL, G_CALLBACK (splashscreen_cb) }, { "Top dock", NULL, "_Top dock", NULL, NULL, G_CALLBACK (dock_cb) }, { "Bottom dock", NULL, "_Bottom dock", NULL, NULL, G_CALLBACK (dock_cb) }, { "Left dock", NULL, "_Left dock", NULL, NULL, G_CALLBACK (dock_cb) }, { "Right dock", NULL, "_Right dock", NULL, NULL, G_CALLBACK (dock_cb) }, { "All docks", NULL, "_All docks", NULL, NULL, G_CALLBACK (dock_cb) }, { "Desktop", NULL, "Des_ktop", NULL, NULL, G_CALLBACK (desktop_cb) }, { "Menu", NULL, "Me_nu", NULL, NULL, G_CALLBACK (menu_cb) }, { "Toolbar", NULL, "Tool_bar", NULL, NULL, G_CALLBACK (toolbar_cb) }, { "Override Redirect", NULL, "Override Redirect", NULL, NULL, G_CALLBACK (override_redirect_cb) }, { "Border Only", NULL, "Border Only", NULL, NULL, G_CALLBACK (border_only_cb) } }; static const GtkActionEntry tool_items[] = { { "New", GTK_STOCK_NEW, NULL, NULL, "Open another one of these windows", G_CALLBACK (do_appwindow) }, { "Lock", GTK_STOCK_OPEN, NULL, NULL, "This is a demo button that" " locks up the demo", G_CALLBACK (sleep_cb) }, { "Decorations", GTK_STOCK_OPEN, NULL, NULL, "This is a demo button that " "toggles window decorations", G_CALLBACK (toggle_decorated_cb) }, { "Quit", GTK_STOCK_QUIT, NULL, NULL, "This is a demo button with " " a 'quit' icon", G_CALLBACK (clicked_toolbar_cb) }, { "Ratio", GTK_STOCK_OPEN, NULL, NULL, "This is a demo button that locks the aspect ratio " "using a hint", G_CALLBACK (toggle_aspect_ratio) } }; static GtkWidget * do_appwindow (void) { GtkWidget *window; GtkWidget *grid; GtkWidget *statusbar; GtkWidget *contents; GtkWidget *sw; GtkTextBuffer *buffer; GtkActionGroup *action_group; GtkUIManager *ui_manager; /* Create the toplevel window */ ++window_count; aspect_on = FALSE; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Application Window"); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL); grid = gtk_grid_new (); gtk_widget_set_vexpand (grid, TRUE); gtk_widget_set_hexpand (grid, TRUE); gtk_container_add (GTK_CONTAINER (window), grid); /* Create the menubar */ contents = gtk_text_view_new (); action_group = gtk_action_group_new ("mainmenu"); gtk_action_group_add_actions (action_group, menu_items, G_N_ELEMENTS (menu_items), window); gtk_action_group_add_actions (action_group, tool_items, G_N_ELEMENTS (tool_items), window); ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); /* create menu items */ gtk_ui_manager_add_ui_from_string (ui_manager, menu_item_string, -1, NULL); gtk_grid_attach (GTK_GRID (grid), gtk_ui_manager_get_widget (ui_manager, "/ui/menubar"), 0, 0, 1, 1); gtk_widget_set_hexpand (gtk_ui_manager_get_widget (ui_manager, "/ui/menubar"), TRUE); /* Create document */ sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); gtk_grid_attach (GTK_GRID (grid), sw, 0, 2, 1, 1); gtk_widget_set_hexpand (sw, TRUE); gtk_widget_set_vexpand (sw, TRUE); gtk_window_set_default_size (GTK_WINDOW (window), 200, 200); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (contents), PANGO_WRAP_WORD); gtk_container_add (GTK_CONTAINER (sw), contents); /* Create the toolbar */ gtk_grid_attach (GTK_GRID (grid), gtk_ui_manager_get_widget (ui_manager, "/ui/toolbar"), 0, 1, 1, 1); gtk_widget_set_hexpand (gtk_ui_manager_get_widget (ui_manager, "/ui/toolbar"), TRUE); /* Create statusbar */ statusbar = gtk_statusbar_new (); gtk_grid_attach (GTK_GRID (grid), statusbar, 0, 3, 1, 1); gtk_widget_set_hexpand (statusbar, TRUE); /* Show text widget info in the statusbar */ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (contents)); gtk_text_buffer_set_text (buffer, "This demo demonstrates various kinds of windows that " "window managers and window manager themes should handle. " "Be sure to tear off the menu and toolbar, those are also " "a special kind of window.", -1); g_signal_connect_object (buffer, "changed", G_CALLBACK (update_statusbar), statusbar, 0); g_signal_connect_object (buffer, "mark_set", /* cursor moved */ G_CALLBACK (mark_set_callback), statusbar, 0); update_statusbar (buffer, GTK_STATUSBAR (statusbar)); gtk_widget_show_all (window); g_object_unref (ui_manager); return window; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/tools/muffin-window-demo.png�������������������������������������������������������0000664�0001750�0001750�00000006575�14211404421�021321� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���0���0���W���gAMA�� a�� 4IDATxk]uk>{}8$cLGMDE!iCP[h$VUhp*5 R5UDZUTGEj[JH&1I0C>9{Z6v?$|cs>3{Ykךz{^ojo8ij}-W  g/qk!߽ke~ޟTUĝwo{ @‰:\kNyDzzʕkϘ}U[XDCn/nhjDdXYZ3wN];SNTso?tff�>|"p %+VU/ ps+Y~RW^sgxv'_#q\R~RWNgl\N=}jS7t3yG;=pB5xzz+cjKྵ&}f}{&Ba1ֹ7?Q "@#t_ڼ񁇶^3/'ǻo9!}3jw:`ӯ~KUrԊs3u> chPzHv!mii?~cW\bɿ,B8%EĈ)q֙yGĎ[=ڹ'K,p%n'ί\d=sC(D"[nmx+ [;*>.?olI" 30539Ô +Gzlg='ҩno ˙鑺 "EoW_[{ҵ ;J>W[rnB�0HuBs"LU'*3XXHG|"W}.J04o/Mvu蔁,P (ʀ�(11"uD*%sCH2} W}<?~љp(o{眱~fXNK'}P "Q!:Xtz]f)Bc"l[?xٟ7\v􁡤_/'''֌O,aٲU\UlxGB9h%-! 8NI_:FP(DS _~o{}\f,rݭ7}#;}s޼l1ooell)U5@͓<~\p7Bo*XJ͎ ;^"@ �DU'/x\J|{޾GvgnXsDkqF;⌆3 F=8&FaF. BvCMIIIIq1"ڴywv>H|',޲/]8ieC֊ ejp�Bek 48�88c0Aܡ0>n0S:3ī~c9olIgsWP{LL('Y$iՀꂻbfl;EuADB cQ&a? (KNZu:,#?> 1eR#[3:13[k8N2P<9Y!N!Q1N:HNP^� 5åăwmV @&9T78*X�Ӏ) [ ?!t>9Vs nRS7r<jop'*5dEqpp1 Sq3Rى9n R Qs>f4rG0?"&LQ`UP\ eC \@ E �7P4p挚"j7 L Ffų+i\QU"jE}QLd0?[B#تJIRVrHPYi'cʦ9 pU@JFc&V **ިWGE`8"рNYd@qI0w6M|hv&D f|¨$wv<@ph8)_SRS$42UHJUh^ɰ X#&c6jN"1;&b)nwwuQ�c~"!$D*䔱`ǛDFh]1&%bl U%PUDi^y07=wKudˌ!<j`T-@ʇ.u#k̎SD̍5 e*9RfTT' 5UJ t:r"w{}IUHU !9HLk:JLfY&in]EQ@-SEm03L jǺΝ;'fss˺FY]UB!ENBWG$4roWr&fCoHɨHefbTB^Q^.R?l{艧57n z#oYN HLLJJʑNɨG8䔩62CL*Fb(w�c{�Xaý~RD&b>TYN]g̴ V3uRFÈcݬ*ٌlNNJ:S {l5z-UWD`玧仺[0af) b+u4bNXNEEbjJ hM9rXg\{sw�+e89_;~qݣAg FV'יQh2A&*:26UhVhpJv,GԔيwC& 9@-sW^u)* 4E[co*k0Aq/m`1QDo>p;`+@=70lNJJ$M ҔI&#)f̌|$^hy@sҢ �NlȻVXhyV+$U\@ hv&f"xiyq| <<X 4jxuM]͌�Z6'b{t#*eYv @-�ҬK@hMYf̒S֮D_cٜ]l<^�/ 0 L oΦ!F_ Y s- ̫j&;NOI6o<s-y&hȕ4zhTe{w�H}}h;-%x0s8 llOWs<Y陶O|VJX鵿SK`=RiJЦ",Ll1'}-`;(;AW$����IENDB`�����������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/tools/muffin-mag.c�����������������������������������������������������������������0000664�0001750�0001750�00000020116�14211404421�017255� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Hack for use instead of xmag */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _XOPEN_SOURCE 600 /* C99 -- for rint() */ #include <gtk/gtk.h> #include <gdk/gdkx.h> #include <gdk/gdkkeysyms.h> #include <unistd.h> #include <stdlib.h> #include <math.h> static GtkWidget *grab_widget = NULL; static GtkWidget *display_window = NULL; static int last_grab_x = 0; static int last_grab_y = 0; static int last_grab_width = 150; static int last_grab_height = 150; static GtkAllocation last_grab_allocation; static double width_factor = 4.0; static double height_factor = 4.0; static GdkInterpType interp_mode = GDK_INTERP_NEAREST; static guint regrab_idle_id = 0; static GdkPixbuf* get_pixbuf (void) { GdkPixbuf *screenshot; GdkPixbuf *magnified; #if 0 g_print ("Size %d x %d\n", last_grab_width, last_grab_height); #endif screenshot = gdk_pixbuf_get_from_window (gdk_get_default_root_window (), last_grab_x, last_grab_y, last_grab_width, last_grab_height); if (screenshot == NULL) { g_printerr ("Screenshot failed\n"); exit (1); } magnified = gdk_pixbuf_scale_simple (screenshot, last_grab_width * width_factor, last_grab_height * height_factor, interp_mode); g_object_unref (G_OBJECT (screenshot)); return magnified; } static gboolean regrab_idle (GtkWidget *image) { GtkAllocation allocation; GdkPixbuf *magnified; gtk_widget_get_allocation (image, &allocation); if (allocation.width != last_grab_allocation.width || allocation.height != last_grab_allocation.height) { last_grab_width = rint (allocation.width / width_factor); last_grab_height = rint (allocation.height / height_factor); last_grab_allocation = allocation; magnified = get_pixbuf (); gtk_image_set_from_pixbuf (GTK_IMAGE (image), magnified); g_object_unref (G_OBJECT (magnified)); } regrab_idle_id = 0; return FALSE; } static void image_resized (GtkWidget *image) { if (regrab_idle_id == 0) regrab_idle_id = g_idle_add_full (G_PRIORITY_LOW + 100, (GSourceFunc) regrab_idle, image, NULL); } static void grab_area_at_mouse (GtkWidget *invisible, int x_root, int y_root) { GdkPixbuf *magnified; int width, height; GtkWidget *widget; width = last_grab_width; height = last_grab_height; last_grab_x = x_root; last_grab_y = y_root; last_grab_width = width; last_grab_height = height; magnified = get_pixbuf (); display_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (display_window), last_grab_width, last_grab_height); widget = gtk_image_new_from_pixbuf (magnified); gtk_widget_set_size_request (widget, 40, 40); gtk_container_add (GTK_CONTAINER (display_window), widget); g_object_unref (G_OBJECT (magnified)); g_object_add_weak_pointer (G_OBJECT (display_window), (gpointer) &display_window); g_signal_connect (G_OBJECT (display_window), "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect_after (G_OBJECT (widget), "size_allocate", G_CALLBACK (image_resized), NULL); gtk_widget_show_all (display_window); } static void shutdown_grab (void) { GdkDeviceManager *manager; GdkDevice *device; manager = gdk_display_get_device_manager (gdk_display_get_default ()); device = gdk_device_manager_get_client_pointer (manager); gdk_device_ungrab (device, gtk_get_current_event_time ()); gdk_device_ungrab (gdk_device_get_associated_device (device), gtk_get_current_event_time ()); gtk_grab_remove (grab_widget); } static void mouse_motion (GtkWidget *invisible, GdkEventMotion *event, gpointer data) { } static gboolean mouse_release (GtkWidget *invisible, GdkEventButton *event, gpointer data) { if (event->button != 1) return FALSE; grab_area_at_mouse (invisible, event->x_root, event->y_root); shutdown_grab (); g_signal_handlers_disconnect_by_func (invisible, mouse_motion, NULL); g_signal_handlers_disconnect_by_func (invisible, mouse_release, NULL); return TRUE; } /* Helper Functions */ static gboolean mouse_press (GtkWidget *invisible, GdkEventButton *event, gpointer data); static gboolean key_press (GtkWidget *invisible, GdkEventKey *event, gpointer data) { if (event->keyval == GDK_KEY_Escape) { shutdown_grab (); g_signal_handlers_disconnect_by_func (invisible, mouse_press, NULL); g_signal_handlers_disconnect_by_func (invisible, key_press, NULL); gtk_main_quit (); return TRUE; } return FALSE; } static gboolean mouse_press (GtkWidget *invisible, GdkEventButton *event, gpointer data) { if (event->type == GDK_BUTTON_PRESS && event->button == 1) { g_signal_connect (invisible, "motion_notify_event", G_CALLBACK (mouse_motion), NULL); g_signal_connect (invisible, "button_release_event", G_CALLBACK (mouse_release), NULL); g_signal_handlers_disconnect_by_func (invisible, mouse_press, NULL); g_signal_handlers_disconnect_by_func (invisible, key_press, NULL); return TRUE; } return FALSE; } static void begin_area_grab (void) { GdkWindow *window; GdkDeviceManager *manager; GdkDevice *device; if (grab_widget == NULL) { grab_widget = gtk_invisible_new (); gtk_widget_add_events (grab_widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); gtk_widget_show (grab_widget); } window = gtk_widget_get_window (grab_widget); manager = gdk_display_get_device_manager (gdk_display_get_default ()); device = gdk_device_manager_get_client_pointer (manager); if (gdk_device_grab (device, window, GDK_OWNERSHIP_NONE, FALSE, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK, NULL, gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS) { g_warning ("Failed to grab pointer to do eyedropper"); return; } if (gdk_device_grab (gdk_device_get_associated_device (device), window, GDK_OWNERSHIP_NONE, FALSE, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS) { gdk_device_ungrab (device, gtk_get_current_event_time ()); g_warning ("Failed to grab keyboard to do eyedropper"); return; } gtk_grab_add (grab_widget); g_signal_connect (grab_widget, "button_press_event", G_CALLBACK (mouse_press), NULL); g_signal_connect (grab_widget, "key_press_event", G_CALLBACK (key_press), NULL); } int main (int argc, char **argv) { gtk_init (&argc, &argv); begin_area_grab (); gtk_main (); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�014653� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/screen-private.h��������������������������������������������������������������0000664�0001750�0001750�00000021227�14211404421�017757� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file screen-private.h Screens which Muffin manages * * Managing X screens. * This file contains methods on this class which are available to * routines in core but not outside it. (See screen.h for the routines * which the rest of the world is allowed to use.) */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_SCREEN_PRIVATE_H #define META_SCREEN_PRIVATE_H #include "display-private.h" #include <meta/screen.h> #include <X11/Xutil.h> #include "stack-tracker.h" #include "ui.h" typedef struct _MetaMonitorInfo MetaMonitorInfo; struct _MetaMonitorInfo { int number; MetaRectangle rect; gboolean is_primary; gboolean in_fullscreen; XID output; /* The primary or first output for this crtc, None if no xrandr */ float refresh_rate; }; typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window, gpointer user_data); typedef enum { META_SCREEN_UP, META_SCREEN_DOWN, META_SCREEN_LEFT, META_SCREEN_RIGHT } MetaScreenDirection; #define META_WIREFRAME_XOR_LINE_WIDTH 2 struct _MetaScreen { GObject parent_instance; MetaDisplay *display; int number; char *screen_name; Screen *xscreen; Window xroot; int default_depth; Visual *default_xvisual; MetaRectangle rect; /* Size of screen; rect.x & rect.y are always 0 */ MetaUI *ui; guint tile_preview_timeout_id; guint tile_hud_timeout_id; guint snap_osd_timeout_id; gboolean tile_preview_visible; gboolean tile_hud_visible; MetaWorkspace *active_workspace; /* This window holds the focus when we don't want to focus * any actual clients */ Window no_focus_window; GList *workspaces; MetaStack *stack; MetaStackTracker *stack_tracker; MetaCursor current_cursor; Window flash_window; Window wm_sn_selection_window; Atom wm_sn_atom; guint32 wm_sn_timestamp; MetaMonitorInfo *monitor_infos; int primary_monitor_index; int n_monitor_infos; /* Cache the current monitor */ int last_monitor_index; #ifdef HAVE_STARTUP_NOTIFICATION SnMonitorContext *sn_context; GSList *startup_sequences; guint startup_sequence_timeout; #endif Window wm_cm_selection_window; guint32 wm_cm_timestamp; guint work_area_later; guint check_fullscreen_later; int rows_of_workspaces; int columns_of_workspaces; MetaScreenCorner starting_corner; guint vertical_workspaces : 1; guint workspace_layout_overridden : 1; guint keys_grabbed : 1; guint all_keys_grabbed : 1; int closing; /* Instead of unmapping withdrawn windows we can leave them mapped * and restack them below a guard window. When using a compositor * this allows us to provide live previews of unmapped windows */ Window guard_window; Window composite_overlay_window; }; struct _MetaScreenClass { GObjectClass parent_class; void (*restacked) (MetaScreen *); void (*workareas_changed) (MetaScreen *); void (*monitors_changed) (MetaScreen *); }; MetaScreen* meta_screen_new (MetaDisplay *display, int number, guint32 timestamp); void meta_screen_free (MetaScreen *screen, guint32 timestamp); void meta_screen_manage_all_windows (MetaScreen *screen); void meta_screen_foreach_window (MetaScreen *screen, MetaScreenWindowFunc func, gpointer data); void meta_screen_queue_frame_redraws (MetaScreen *screen); void meta_screen_queue_window_resizes (MetaScreen *screen); void meta_screen_set_cursor (MetaScreen *screen, MetaCursor cursor); void meta_screen_update_cursor (MetaScreen *screen); void meta_screen_tile_preview_update (MetaScreen *screen, gboolean delay); void meta_screen_tile_preview_hide (MetaScreen *screen); gboolean meta_screen_tile_preview_get_visible (MetaScreen *screen); void meta_screen_tile_hud_update (MetaScreen *screen, gboolean delay, gboolean hiding); void meta_screen_tile_hud_hide (MetaScreen *screen); gboolean meta_screen_tile_hud_get_visible (MetaScreen *screen); void meta_screen_hide_hud_and_preview (MetaScreen *screen); const MetaMonitorInfo* meta_screen_get_current_monitor_info (MetaScreen *screen); const MetaMonitorInfo* meta_screen_get_monitor_for_rect (MetaScreen *screen, MetaRectangle *rect); const MetaMonitorInfo* meta_screen_get_monitor_for_window (MetaScreen *screen, MetaWindow *window); const MetaMonitorInfo* meta_screen_get_monitor_neighbor (MetaScreen *screen, int which_monitor, MetaScreenDirection dir); void meta_screen_get_natural_monitor_list (MetaScreen *screen, int** monitors_list, int* n_monitors); void meta_screen_update_workspace_layout (MetaScreen *screen); void meta_screen_update_workspace_names (MetaScreen *screen); void meta_screen_queue_workarea_recalc (MetaScreen *screen); void meta_screen_queue_check_fullscreen (MetaScreen *screen); Window meta_create_offscreen_window (Display *xdisplay, Window parent, long valuemask); typedef struct MetaWorkspaceLayout MetaWorkspaceLayout; struct MetaWorkspaceLayout { int rows; int cols; int *grid; int grid_area; int current_row; int current_col; }; void meta_screen_calc_workspace_layout (MetaScreen *screen, int num_workspaces, int current_space, MetaWorkspaceLayout *layout); void meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout); void meta_screen_resize (MetaScreen *screen, int width, int height); void meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen, MetaWindow *keep); /* Update whether the destkop is being shown for the current active_workspace */ void meta_screen_update_showing_desktop_hint (MetaScreen *screen); gboolean meta_screen_apply_startup_properties (MetaScreen *screen, MetaWindow *window); void meta_screen_composite_all_windows (MetaScreen *screen); void meta_screen_restacked (MetaScreen *screen); void meta_screen_workspace_switched (MetaScreen *screen, int from, int to, MetaMotionDirection direction); void meta_screen_set_active_workspace_hint (MetaScreen *screen); void meta_screen_update_snapped_windows (MetaScreen *screen); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/util.c������������������������������������������������������������������������0000664�0001750�0001750�00000053431�14211404421�016002� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin utilities */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:util * @title: Utility functions * @short_description: Miscellaneous utility functions */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _POSIX_C_SOURCE 200112L /* for fdopen() */ #include <config.h> #include <meta/common.h> #include "util-private.h" #include <meta/main.h> #include <clutter/clutter.h> /* For clutter_threads_add_repaint_func() */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <dirent.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #ifdef HAVE_SYS_RESOURCE_H #include <sys/resource.h> #endif #include <X11/Xlib.h> /* must explicitly be included for Solaris; #326746 */ #include <X11/Xutil.h> /* Just for the definition of the various gravities */ #ifdef WITH_VERBOSE_MODE static void meta_topic_real_valist (MetaDebugTopic topic, const char *format, va_list args); #endif #ifdef HAVE_BACKTRACE #include <execinfo.h> void meta_print_backtrace (void) { void *bt[500]; int bt_size; int i; char **syms; bt_size = backtrace (bt, 500); syms = backtrace_symbols (bt, bt_size); i = 0; while (i < bt_size) { meta_verbose (" %s\n", syms[i]); ++i; } free (syms); } #else void meta_print_backtrace (void) { meta_verbose ("Not compiled with backtrace support\n"); } #endif static gint verbose_topics = 0; static gboolean is_debugging = FALSE; static gboolean replace_current = FALSE; static int no_prefix = 0; #ifdef WITH_VERBOSE_MODE static FILE* logfile = NULL; static void ensure_logfile (void) { if (logfile == NULL && g_getenv ("MUFFIN_USE_LOGFILE")) { char *filename = NULL; char *tmpl; int fd; GError *err; tmpl = g_strdup_printf ("muffin-%d-debug-log-XXXXXX", (int) getpid ()); err = NULL; fd = g_file_open_tmp (tmpl, &filename, &err); free (tmpl); if (err != NULL) { meta_warning ("Failed to open debug log: %s\n", err->message); g_error_free (err); return; } logfile = fdopen (fd, "w"); if (logfile == NULL) { meta_warning ("Failed to fdopen() log file %s: %s\n", filename, strerror (errno)); close (fd); } else { g_printerr ("Opened log file %s\n"), filename; } free (filename); } } #endif gboolean meta_is_verbose (void) { return verbose_topics != 0; } void meta_set_verbose (gboolean setting) { #ifndef WITH_VERBOSE_MODE if (setting) meta_fatal ("Muffin was compiled without support for verbose mode\n"); #else if (setting) ensure_logfile (); #endif if (setting) meta_add_verbose_topic (META_DEBUG_VERBOSE); else meta_remove_verbose_topic (META_DEBUG_VERBOSE); } /** * meta_add_verbose_topic: * @topic: Topic for which logging will be started * * Ensure log messages for the given topic @topic * will be printed. */ void meta_add_verbose_topic (MetaDebugTopic topic) { if (verbose_topics == META_DEBUG_VERBOSE) return; if (topic == META_DEBUG_VERBOSE) verbose_topics = META_DEBUG_VERBOSE; else verbose_topics |= topic; } /** * meta_remove_verbose_topic: * @topic: Topic for which logging will be stopped * * Stop printing log messages for the given topic @topic. Note * that this method does not stack with meta_add_verbose_topic(); * i.e. if two calls to meta_add_verbose_topic() for the same * topic are made, one call to meta_remove_verbose_topic() will * remove it. */ void meta_remove_verbose_topic (MetaDebugTopic topic) { if (topic == META_DEBUG_VERBOSE) verbose_topics = 0; else verbose_topics &= ~topic; } gboolean meta_is_debugging (void) { return is_debugging; } void meta_set_debugging (gboolean setting) { #ifdef WITH_VERBOSE_MODE if (setting) ensure_logfile (); #endif is_debugging = setting; } gboolean meta_get_replace_current_wm (void) { return replace_current; } void meta_set_replace_current_wm (gboolean setting) { replace_current = setting; } char * meta_g_utf8_strndup (const gchar *src, gsize n) { const gchar *s = src; while (n && *s) { s = g_utf8_next_char (s); n--; } return g_strndup (src, s - src); } static int utf8_fputs (const char *str, FILE *f) { char *l; int retval; l = g_locale_from_utf8 (str, -1, NULL, NULL, NULL); if (l == NULL) retval = fputs (str, f); /* just print it anyway, better than nothing */ else retval = fputs (l, f); free (l); return retval; } /** * meta_free_gslist_and_elements: (skip) * */ void meta_free_gslist_and_elements (GSList *list_to_deep_free) { g_slist_foreach (list_to_deep_free, (void (*)(gpointer,gpointer))&free, /* ew, for ugly */ NULL); g_slist_free (list_to_deep_free); } #ifdef WITH_VERBOSE_MODE void meta_debug_spew_real (const char *format, ...) { va_list args; gchar *str; FILE *out; g_return_if_fail (format != NULL); if (!is_debugging) return; va_start (args, format); str = g_strdup_vprintf (format, args); va_end (args); out = logfile ? logfile : stderr; if (no_prefix == 0) utf8_fputs ("muffin: ", out); utf8_fputs (str, out); fflush (out); free (str); } #endif /* WITH_VERBOSE_MODE */ #ifdef WITH_VERBOSE_MODE void meta_verbose_real (const char *format, ...) { va_list args; va_start (args, format); meta_topic_real_valist (META_DEBUG_VERBOSE, format, args); va_end (args); } #endif /* WITH_VERBOSE_MODE */ #ifdef WITH_VERBOSE_MODE static const char* topic_name (MetaDebugTopic topic) { switch (topic) { case META_DEBUG_FOCUS: return "FOCUS"; case META_DEBUG_WORKAREA: return "WORKAREA"; case META_DEBUG_STACK: return "STACK"; case META_DEBUG_THEMES: return "THEMES"; case META_DEBUG_SM: return "SM"; case META_DEBUG_EVENTS: return "EVENTS"; case META_DEBUG_WINDOW_STATE: return "WINDOW_STATE"; case META_DEBUG_WINDOW_OPS: return "WINDOW_OPS"; case META_DEBUG_PLACEMENT: return "PLACEMENT"; case META_DEBUG_GEOMETRY: return "GEOMETRY"; case META_DEBUG_PING: return "PING"; case META_DEBUG_XINERAMA: return "XINERAMA"; case META_DEBUG_KEYBINDINGS: return "KEYBINDINGS"; case META_DEBUG_SYNC: return "SYNC"; case META_DEBUG_ERRORS: return "ERRORS"; case META_DEBUG_STARTUP: return "STARTUP"; case META_DEBUG_PREFS: return "PREFS"; case META_DEBUG_GROUPS: return "GROUPS"; case META_DEBUG_RESIZING: return "RESIZING"; case META_DEBUG_SHAPES: return "SHAPES"; case META_DEBUG_COMPOSITOR: return "COMPOSITOR"; case META_DEBUG_EDGE_RESISTANCE: return "EDGE_RESISTANCE"; case META_DEBUG_VERBOSE: return "VERBOSE"; default: break; } return "WM"; } static int sync_count = 0; static void meta_topic_real_valist (MetaDebugTopic topic, const char *format, va_list args) { gchar *str; FILE *out; g_return_if_fail (format != NULL); if (verbose_topics == 0 || (topic == META_DEBUG_VERBOSE && verbose_topics != META_DEBUG_VERBOSE) || (!(verbose_topics & topic))) return; str = g_strdup_vprintf (format, args); out = logfile ? logfile : stderr; if (no_prefix == 0) fprintf (out, "%s: ", topic_name (topic)); if (topic == META_DEBUG_SYNC) { ++sync_count; fprintf (out, "%d: ", sync_count); } utf8_fputs (str, out); fflush (out); free (str); } void meta_topic_real (MetaDebugTopic topic, const char *format, ...) { va_list args; va_start (args, format); meta_topic_real_valist (topic, format, args); va_end (args); } #endif /* WITH_VERBOSE_MODE */ void meta_bug (const char *format, ...) { va_list args; gchar *str; FILE *out; g_return_if_fail (format != NULL); va_start (args, format); str = g_strdup_vprintf (format, args); va_end (args); #ifdef WITH_VERBOSE_MODE out = logfile ? logfile : stderr; #else out = stderr; #endif if (no_prefix == 0) utf8_fputs ("Bug in muffin: ", out); utf8_fputs (str, out); fflush (out); free (str); meta_print_backtrace (); /* stop us in a debugger */ abort (); } void meta_warning (const char *format, ...) { va_list args; gchar *str; FILE *out; g_return_if_fail (format != NULL); va_start (args, format); str = g_strdup_vprintf (format, args); va_end (args); #ifdef WITH_VERBOSE_MODE out = logfile ? logfile : stderr; #else out = stderr; #endif if (no_prefix == 0) utf8_fputs ("Cinnamon warning: ", out); utf8_fputs (str, out); fflush (out); free (str); } void meta_fatal (const char *format, ...) { va_list args; gchar *str; FILE *out; g_return_if_fail (format != NULL); va_start (args, format); str = g_strdup_vprintf (format, args); va_end (args); #ifdef WITH_VERBOSE_MODE out = logfile ? logfile : stderr; #else out = stderr; #endif if (no_prefix == 0) utf8_fputs ("Cinnamon error: ", out); utf8_fputs (str, out); fflush (out); free (str); meta_exit (META_EXIT_ERROR); } void meta_push_no_msg_prefix (void) { ++no_prefix; } void meta_pop_no_msg_prefix (void) { g_return_if_fail (no_prefix > 0); --no_prefix; } void meta_exit (MetaExitCode code) { exit (code); } gint meta_unsigned_long_equal (gconstpointer v1, gconstpointer v2) { return *((const gulong*) v1) == *((const gulong*) v2); } guint meta_unsigned_long_hash (gconstpointer v) { gulong val = * (const gulong *) v; /* I'm not sure this works so well. */ #if GLIB_SIZEOF_LONG > 4 return (guint) (val ^ (val >> 32)); #else return val; #endif } const char* meta_gravity_to_string (int gravity) { switch (gravity) { case NorthWestGravity: return "NorthWestGravity"; break; case NorthGravity: return "NorthGravity"; break; case NorthEastGravity: return "NorthEastGravity"; break; case WestGravity: return "WestGravity"; break; case CenterGravity: return "CenterGravity"; break; case EastGravity: return "EastGravity"; break; case SouthWestGravity: return "SouthWestGravity"; break; case SouthGravity: return "SouthGravity"; break; case SouthEastGravity: return "SouthEastGravity"; break; case StaticGravity: return "StaticGravity"; break; default: return "NorthWestGravity"; break; } } /* Command line arguments are passed in the locale encoding; in almost * all cases, we'd hope that is UTF-8 and no conversion is necessary. * If it's not UTF-8, then it's possible that the message isn't * representable in the locale encoding. */ static void append_argument (GPtrArray *args, const char *arg) { char *locale_arg = g_locale_from_utf8 (arg, -1, NULL, NULL, NULL); /* This is cheesy, but it's better to have a few ???'s in the dialog * for an unresponsive application than no dialog at all appear */ if (!locale_arg) locale_arg = g_strdup ("???"); g_ptr_array_add (args, locale_arg); } /** * meta_show_dialog: (skip) * */ GPid meta_show_dialog (const char *type, const char *message, const char *timeout, const char *display, const char *ok_text, const char *cancel_text, const int transient_for, GSList *columns, GSList *entries) { GError *error = NULL; GSList *tmp; GPid child_pid; GPtrArray *args; args = g_ptr_array_new (); append_argument (args, "zenity"); append_argument (args, type); append_argument (args, "--display"); append_argument (args, display); append_argument (args, "--class"); append_argument (args, "muffin-dialog"); append_argument (args, "--title"); append_argument (args, ""); append_argument (args, "--text"); append_argument (args, message); append_argument (args, "--width"); append_argument (args, "400"); if (timeout) { append_argument (args, "--timeout"); append_argument (args, timeout); } if (ok_text) { append_argument (args, "--ok-label"); append_argument (args, ok_text); } if (cancel_text) { append_argument (args, "--cancel-label"); append_argument (args, cancel_text); } tmp = columns; while (tmp) { append_argument (args, "--column"); append_argument (args, tmp->data); tmp = tmp->next; } tmp = entries; while (tmp) { append_argument (args, tmp->data); tmp = tmp->next; } g_ptr_array_add (args, NULL); /* NULL-terminate */ if (transient_for) { gchar *env = g_strdup_printf("%d", transient_for); setenv ("WINDOWID", env, 1); free (env); } g_spawn_async ( "/", (gchar**) args->pdata, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &child_pid, &error ); if (transient_for) unsetenv ("WINDOWID"); g_ptr_array_free (args, TRUE); if (error) { meta_warning ("%s\n", error->message); g_error_free (error); } return child_pid; } /*************************************************************************** * Later functions: like idles but integrated with the Clutter repaint loop ***************************************************************************/ static guint last_later_id = 0; typedef struct { guint id; guint ref_count; MetaLaterType when; GSourceFunc func; gpointer data; GDestroyNotify notify; int source; gboolean run_once; } MetaLater; static GSList *laters = NULL; /* This is a dummy timeline used to get the Clutter master clock running */ static ClutterTimeline *later_timeline; static guint later_repaint_func = 0; static void ensure_later_repaint_func (void); static void unref_later (MetaLater *later) { if (--later->ref_count == 0) { if (later->notify) { later->notify (later->data); later->notify = NULL; } g_slice_free (MetaLater, later); } } static void destroy_later (MetaLater *later) { if (later->source) { g_source_remove (later->source); later->source = 0; } later->func = NULL; unref_later (later); } /* Used to sort the list of laters with the highest priority * functions first. */ static int compare_laters (gconstpointer a, gconstpointer b) { return ((const MetaLater *)a)->when - ((const MetaLater *)b)->when; } static gboolean run_repaint_laters (gpointer data) { GSList *laters_copy; GSList *l; gboolean keep_timeline_running = FALSE; laters_copy = NULL; for (l = laters; l; l = l->next) { MetaLater *later = l->data; if (later->source == 0 || (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once)) { later->ref_count++; laters_copy = g_slist_prepend (laters_copy, later); } } laters_copy = g_slist_reverse (laters_copy); for (l = laters_copy; l; l = l->next) { MetaLater *later = l->data; if (later->func && later->func (later->data)) { if (later->source == 0) keep_timeline_running = TRUE; } else meta_later_remove (later->id); unref_later (later); } if (!keep_timeline_running) clutter_timeline_stop (later_timeline); g_slist_free (laters_copy); /* Just keep the repaint func around - it's cheap if the list is empty */ return TRUE; } static void ensure_later_repaint_func (void) { if (!later_timeline) later_timeline = clutter_timeline_new (G_MAXUINT); if (later_repaint_func == 0) later_repaint_func = clutter_threads_add_repaint_func (run_repaint_laters, NULL, NULL); /* Make sure the repaint function gets run */ clutter_timeline_start (later_timeline); } static gboolean call_idle_later (gpointer data) { MetaLater *later = data; if (!later->func (later->data)) { meta_later_remove (later->id); return FALSE; } else { later->run_once = TRUE; return TRUE; } } /** * meta_later_add: * @when: enumeration value determining the phase at which to run the callback * @func: callback to run later * @data: data to pass to the callback * @notify: function to call to destroy @data when it is no longer in use, or %NULL * * Sets up a callback to be called at some later time. @when determines the * particular later occasion at which it is called. This is much like g_idle_add(), * except that the functions interact properly with clutter event handling. * If a "later" function is added from a clutter event handler, and is supposed * to be run before the stage is redrawn, it will be run before that redraw * of the stage, not the next one. * * Return value: an integer ID (guaranteed to be non-zero) that can be used * to cancel the callback and prevent it from being run. */ guint meta_later_add (MetaLaterType when, GSourceFunc func, gpointer data, GDestroyNotify notify) { MetaLater *later = g_slice_new0 (MetaLater); later->id = ++last_later_id; later->ref_count = 1; later->when = when; later->func = func; later->data = data; later->notify = notify; laters = g_slist_insert_sorted (laters, later, compare_laters); switch (when) { case META_LATER_RESIZE: /* We add this one two ways - as a high-priority idle and as a * repaint func. If we are in a clutter event callback, the repaint * handler will get hit first, and we'll take care of this function * there so it gets called before the stage is redrawn, even if * we haven't gotten back to the main loop. Otherwise, the idle * handler will get hit first and we want to call this function * there so it will happen before GTK+ repaints. */ later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL); ensure_later_repaint_func (); break; case META_LATER_CALC_SHOWING: case META_LATER_CHECK_FULLSCREEN: case META_LATER_SYNC_STACK: case META_LATER_BEFORE_REDRAW: ensure_later_repaint_func (); break; case META_LATER_IDLE: later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL); break; default: g_warning ("Default reached in meta_later_add"); break; } return later->id; } /** * meta_later_remove: * @later_id: the integer ID returned from meta_later_add() * * Removes a callback added with meta_later_add() */ void meta_later_remove (guint later_id) { GSList *l; for (l = laters; l; l = l->next) { MetaLater *later = l->data; if (later->id == later_id) { laters = g_slist_delete_link (laters, l); /* If this was a "repaint func" later, we just let the * repaint func run and get removed */ destroy_later (later); return; } } } /* eof util.c */ /* Code to close all file descriptors before we exec; copied from gspawn.c in GLib. * * Authors: Padraig O'Briain, Matthias Clasen, Lennart Poettering * * http://bugzilla.gnome.org/show_bug.cgi?id=469231 * http://bugzilla.gnome.org/show_bug.cgi?id=357585 */ static int set_cloexec (void *data, gint fd) { if (fd >= GPOINTER_TO_INT (data)) fcntl (fd, F_SETFD, FD_CLOEXEC); return 0; } #ifndef HAVE_FDWALK static int fdwalk (int (*cb)(void *data, int fd), void *data) { gint open_max; gint fd; gint res = 0; #ifdef HAVE_SYS_RESOURCE_H struct rlimit rl; #endif #ifdef __linux__ DIR *d; if ((d = opendir("/proc/self/fd"))) { struct dirent *de; while ((de = readdir(d))) { glong l; gchar *e = NULL; if (de->d_name[0] == '.') continue; errno = 0; l = strtol(de->d_name, &e, 10); if (errno != 0 || !e || *e) continue; fd = (gint) l; if ((glong) fd != l) continue; if (fd == dirfd(d)) continue; if ((res = cb (data, fd)) != 0) break; } closedir(d); return res; } /* If /proc is not mounted or not accessible we fall back to the old * rlimit trick */ #endif #ifdef HAVE_SYS_RESOURCE_H if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY) open_max = rl.rlim_max; else #endif open_max = sysconf (_SC_OPEN_MAX); for (fd = 0; fd < open_max; fd++) if ((res = cb (data, fd)) != 0) break; return res; } #endif void meta_pre_exec_close_fds(void) { fdwalk (set_cloexec, GINT_TO_POINTER(3)); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/edge-resistance.c�������������������������������������������������������������0000664�0001750�0001750�00000131251�14211404421�020064� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Edge resistance for move/resize operations */ /* * Copyright (C) 2005, 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "edge-resistance.h" #include "boxes-private.h" #include "display-private.h" #include "workspace-private.h" /* A simple macro for whether a given window's edges are potentially * relevant for resistance/snapping during a move/resize operation */ #define WINDOW_EDGES_RELEVANT(window, display) \ meta_window_should_be_showing (window) && \ window->screen == display->grab_screen && \ window != display->grab_window && \ window->type != META_WINDOW_DESKTOP && \ window->type != META_WINDOW_MENU && \ window->type != META_WINDOW_SPLASHSCREEN struct ResistanceDataForAnEdge { gboolean timeout_setup; guint timeout_id; int timeout_edge_pos; gboolean timeout_over; GSourceFunc timeout_func; MetaWindow *window; int keyboard_buildup; }; typedef struct ResistanceDataForAnEdge ResistanceDataForAnEdge; struct MetaEdgeResistanceData { GArray *left_edges; GArray *right_edges; GArray *top_edges; GArray *bottom_edges; ResistanceDataForAnEdge left_data; ResistanceDataForAnEdge right_data; ResistanceDataForAnEdge top_data; ResistanceDataForAnEdge bottom_data; }; static void compute_resistance_and_snapping_edges (MetaDisplay *display); /* !WARNING!: this function can return invalid indices (namely, either -1 or * edges->len); this is by design, but you need to remember this. */ static int find_index_of_edge_near_position (const GArray *edges, int position, gboolean want_interval_min, gboolean horizontal) { /* This is basically like a binary search, except that we're trying to * find a range instead of an exact value. So, if we have in our array * Value: 3 27 316 316 316 505 522 800 1213 * Index: 0 1 2 3 4 5 6 7 8 * and we call this function with position=500 & want_interval_min=TRUE * then we should get 5 (because 505 is the first value bigger than 500). * If we call this function with position=805 and want_interval_min=FALSE * then we should get 7 (because 800 is the last value smaller than 800). * A couple more, to make things clear: * position want_interval_min correct_answer * 316 TRUE 2 * 316 FALSE 4 * 2 FALSE -1 * 2000 TRUE 9 */ int low, high, mid; int compare; MetaEdge *edge; /* Initialize mid, edge, & compare in the off change that the array only * has one element. */ mid = 0; edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; /* Begin the search... */ low = 0; high = edges->len - 1; while (low < high) { mid = low + (high - low)/2; edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; if (compare == position) break; if (compare > position) high = mid - 1; else low = mid + 1; } /* mid should now be _really_ close to the index we want, so we start * linearly searching. However, note that we don't know if mid is less * than or greater than what we need and it's possible that there are * several equal values equal to what we were searching for and we ended * up in the middle of them instead of at the end. So we may need to * move mid multiple locations over. */ if (want_interval_min) { while (compare >= position && mid > 0) { mid--; edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; } while (compare < position && mid < (int)edges->len - 1) { mid++; edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; } /* Special case for no values in array big enough */ if (compare < position) return edges->len; /* Return the found value */ return mid; } else { while (compare <= position && mid < (int)edges->len - 1) { mid++; edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; } while (compare > position && mid > 0) { mid--; edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; } /* Special case for no values in array small enough */ if (compare > position) return -1; /* Return the found value */ return mid; } } static gboolean points_on_same_side (int ref, int pt1, int pt2) { return (pt1 - ref) * (pt2 - ref) > 0; } static int find_nearest_position (const GArray *edges, int position, int old_position, const MetaRectangle *new_rect, gboolean horizontal, gboolean only_forward) { /* This is basically just a binary search except that we're looking * for the value closest to position, rather than finding that * actual value. Also, we ignore any edges that aren't relevant * given the horizontal/vertical position of new_rect. */ int low, high, mid; int compare; MetaEdge *edge; int best, best_dist, i; gboolean edges_align; /* Initialize mid in the off chance that the array only * has one element. */ mid = 0; /* Begin the search... */ low = 0; high = edges->len - 1; while (low < high) { mid = low + (high - low)/2; edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; if (compare == position) break; if (compare > position) high = mid - 1; else low = mid + 1; } /* mid should now be _really_ close to the index we want, so we * start searching nearby for something that overlaps and is closer * than the original position. */ best = old_position; best_dist = INT_MAX; /* Start the search at mid */ edge = g_array_index (edges, MetaEdge*, mid); compare = horizontal ? edge->rect.x : edge->rect.y; edges_align = meta_rectangle_edge_aligns (new_rect, edge); if (edges_align && (!only_forward || !points_on_same_side (position, compare, old_position))) { int dist = ABS (compare - position); if (dist < best_dist) { best = compare; best_dist = dist; } } /* Now start searching higher than mid */ for (i = mid + 1; i < (int)edges->len; i++) { edge = g_array_index (edges, MetaEdge*, i); compare = horizontal ? edge->rect.x : edge->rect.y; edges_align = horizontal ? meta_rectangle_vert_overlap (&edge->rect, new_rect) : meta_rectangle_horiz_overlap (&edge->rect, new_rect); if (edges_align && (!only_forward || !points_on_same_side (position, compare, old_position))) { int dist = ABS (compare - position); if (dist < best_dist) { best = compare; best_dist = dist; } break; } } /* Now start searching lower than mid */ for (i = mid-1; i >= 0; i--) { edge = g_array_index (edges, MetaEdge*, i); compare = horizontal ? edge->rect.x : edge->rect.y; edges_align = horizontal ? meta_rectangle_vert_overlap (&edge->rect, new_rect) : meta_rectangle_horiz_overlap (&edge->rect, new_rect); if (edges_align && (!only_forward || !points_on_same_side (position, compare, old_position))) { int dist = ABS (compare - position); if (dist < best_dist) { best = compare; } break; } } /* Return the best one found */ return best; } static gboolean movement_towards_edge (MetaSide side, int increment) { switch (side) { case META_SIDE_LEFT: case META_SIDE_TOP: return increment < 0; case META_SIDE_RIGHT: case META_SIDE_BOTTOM: return increment > 0; default: g_assert_not_reached (); } } static gboolean edge_resistance_timeout (gpointer data) { ResistanceDataForAnEdge *resistance_data = data; resistance_data->timeout_over = TRUE; resistance_data->timeout_id = 0; (*resistance_data->timeout_func)(resistance_data->window); return FALSE; } static int apply_edge_resistance (MetaWindow *window, int old_pos, int new_pos, const MetaRectangle *old_rect, const MetaRectangle *new_rect, GArray *edges, ResistanceDataForAnEdge *resistance_data, GSourceFunc timeout_func, gboolean xdir, gboolean keyboard_op) { int i, begin, end; int last_edge; gboolean increasing = new_pos > old_pos; int increment = increasing ? 1 : -1; const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_WINDOW = 16; const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW = 0; const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_MONITOR = 32; const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_MONITOR = 0; const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_SCREEN = 32; const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_SCREEN = 0; const int TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW = 0; const int TIMEOUT_RESISTANCE_LENGTH_MS_MONITOR = 0; const int TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN = 0; /* Edge resistance can be disabled in gettings. */ if (!meta_prefs_get_edge_resistance_window ()) return new_pos; /* Quit if no movement was specified */ if (old_pos == new_pos) return new_pos; /* Remove the old timeout if it's no longer relevant */ if (resistance_data->timeout_setup && ((resistance_data->timeout_edge_pos > old_pos && resistance_data->timeout_edge_pos > new_pos) || (resistance_data->timeout_edge_pos < old_pos && resistance_data->timeout_edge_pos < new_pos))) { resistance_data->timeout_setup = FALSE; if (resistance_data->timeout_id != 0) { g_source_remove (resistance_data->timeout_id); resistance_data->timeout_id = 0; } } /* Get the range of indices in the edge array that we move past/to. */ begin = find_index_of_edge_near_position (edges, old_pos, increasing, xdir); end = find_index_of_edge_near_position (edges, new_pos, !increasing, xdir); /* begin and end can be outside the array index, if the window is partially * off the screen */ last_edge = edges->len - 1; begin = CLAMP (begin, 0, last_edge); end = CLAMP (end, 0, last_edge); /* Loop over all these edges we're moving past/to. */ i = begin; while ((increasing && i <= end) || (!increasing && i >= end)) { gboolean edges_align; MetaEdge *edge = g_array_index (edges, MetaEdge*, i); int compare = xdir ? edge->rect.x : edge->rect.y; /* Find out if this edge is relevant */ edges_align = meta_rectangle_edge_aligns (new_rect, edge) || meta_rectangle_edge_aligns (old_rect, edge); /* Nothing to do unless the edges align */ if (!edges_align) { /* Go to the next edge in the range */ i += increment; continue; } /* Rest is easier to read if we split on keyboard vs. mouse op */ if (keyboard_op) { if ((old_pos < compare && compare < new_pos) || (old_pos > compare && compare > new_pos)) return compare; } else /* mouse op */ { int threshold; /* TIMEOUT RESISTANCE: If the edge is relevant and we're moving * towards it, then we may want to have some kind of time delay * before the user can move past this edge. */ if (movement_towards_edge (edge->side_type, increment)) { /* First, determine the length of time for the resistance */ int timeout_length_ms = 0; switch (edge->edge_type) { case META_EDGE_WINDOW: timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW; break; case META_EDGE_MONITOR: timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_MONITOR; break; case META_EDGE_SCREEN: timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN; break; } if (!resistance_data->timeout_setup && timeout_length_ms != 0) { resistance_data->timeout_id = g_timeout_add (timeout_length_ms, edge_resistance_timeout, resistance_data); resistance_data->timeout_setup = TRUE; resistance_data->timeout_edge_pos = compare; resistance_data->timeout_over = FALSE; resistance_data->timeout_func = timeout_func; resistance_data->window = window; } if (!resistance_data->timeout_over && timeout_length_ms != 0) return compare; } /* PIXEL DISTANCE MOUSE RESISTANCE: If the edge matters and the * user hasn't moved at least threshold pixels past this edge, * stop movement at this edge. (Note that this is different from * keyboard resistance precisely because keyboard move ops are * relative to previous positions, whereas mouse move ops are * relative to differences in mouse position and mouse position * is an absolute quantity rather than a relative quantity) */ /* First, determine the threshold */ threshold = 0; switch (edge->edge_type) { case META_EDGE_WINDOW: if (movement_towards_edge (edge->side_type, increment)) threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_WINDOW; else threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW; break; case META_EDGE_MONITOR: if (movement_towards_edge (edge->side_type, increment)) threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_MONITOR; else threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_MONITOR; break; case META_EDGE_SCREEN: if (movement_towards_edge (edge->side_type, increment)) threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_SCREEN; else threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_SCREEN; break; } if (ABS (compare - new_pos) < threshold) return compare; } /* Go to the next edge in the range */ i += increment; } return new_pos; } static int apply_edge_snapping (int old_pos, int new_pos, const MetaRectangle *new_rect, GArray *edges, gboolean xdir, gboolean keyboard_op) { int snap_to; if (old_pos == new_pos) return new_pos; snap_to = find_nearest_position (edges, new_pos, old_pos, new_rect, xdir, keyboard_op); /* If mouse snap-moving, the user could easily accidentally move just a * couple pixels in a direction they didn't mean to move; so ignore snap * movement in those cases unless it's only a small number of pixels * anyway. */ if (!keyboard_op && ABS (snap_to - old_pos) >= 8 && ABS (new_pos - old_pos) < 8) return old_pos; else /* Otherwise, return the snapping position found */ return snap_to; } /* This function takes the position (including any frame) of the window and * a proposed new position (ignoring edge resistance/snapping), and then * applies edge resistance to EACH edge (separately) updating new_outer. * It returns true if new_outer is modified, false otherwise. * * display->grab_edge_resistance_data MUST already be setup or calling this * function will cause a crash. */ static gboolean apply_edge_resistance_to_each_side (MetaDisplay *display, MetaWindow *window, const MetaRectangle *old_outer, MetaRectangle *new_outer, GSourceFunc timeout_func, gboolean auto_snap, gboolean keyboard_op, gboolean is_resize) { MetaEdgeResistanceData *edge_data; MetaRectangle modified_rect; gboolean modified; int new_left, new_right, new_top, new_bottom; if (display->grab_edge_resistance_data == NULL) compute_resistance_and_snapping_edges (display); edge_data = display->grab_edge_resistance_data; if (auto_snap) { /* Do the auto snapping instead of normal edge resistance; in all * cases, we allow snapping to opposite kinds of edges (e.g. left * sides of windows to both left and right edges. */ new_left = apply_edge_snapping (BOX_LEFT (*old_outer), BOX_LEFT (*new_outer), new_outer, edge_data->left_edges, TRUE, keyboard_op); new_right = apply_edge_snapping (BOX_RIGHT (*old_outer), BOX_RIGHT (*new_outer), new_outer, edge_data->right_edges, TRUE, keyboard_op); new_top = apply_edge_snapping (BOX_TOP (*old_outer), BOX_TOP (*new_outer), new_outer, edge_data->top_edges, FALSE, keyboard_op); new_bottom = apply_edge_snapping (BOX_BOTTOM (*old_outer), BOX_BOTTOM (*new_outer), new_outer, edge_data->bottom_edges, FALSE, keyboard_op); } else { /* Disable edge resistance for resizes when windows have size * increment hints; see #346782. For all other cases, apply * them. */ if (!is_resize || window->size_hints.width_inc == 1) { /* Now, apply the normal horizontal edge resistance */ new_left = apply_edge_resistance (window, BOX_LEFT (*old_outer), BOX_LEFT (*new_outer), old_outer, new_outer, edge_data->left_edges, &edge_data->left_data, timeout_func, TRUE, keyboard_op); new_right = apply_edge_resistance (window, BOX_RIGHT (*old_outer), BOX_RIGHT (*new_outer), old_outer, new_outer, edge_data->right_edges, &edge_data->right_data, timeout_func, TRUE, keyboard_op); } else { new_left = new_outer->x; new_right = new_outer->x + new_outer->width; } /* Same for vertical resizes... */ if (!is_resize || window->size_hints.height_inc == 1) { new_top = apply_edge_resistance (window, BOX_TOP (*old_outer), BOX_TOP (*new_outer), old_outer, new_outer, edge_data->top_edges, &edge_data->top_data, timeout_func, FALSE, keyboard_op); new_bottom = apply_edge_resistance (window, BOX_BOTTOM (*old_outer), BOX_BOTTOM (*new_outer), old_outer, new_outer, edge_data->bottom_edges, &edge_data->bottom_data, timeout_func, FALSE, keyboard_op); } else { new_top = new_outer->y; new_bottom = new_outer->y + new_outer->height; } } /* Determine whether anything changed, and save the changes */ modified_rect = meta_rect (new_left, new_top, new_right - new_left, new_bottom - new_top); modified = !meta_rectangle_equal (new_outer, &modified_rect); *new_outer = modified_rect; return modified; } LOCAL_SYMBOL void meta_display_cleanup_edges (MetaDisplay *display) { guint i,j; MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data; GHashTable *edges_to_be_freed; if (edge_data == NULL) /* Not currently cached */ return; /* We first need to clean out any window edges */ edges_to_be_freed = g_hash_table_new_full (g_direct_hash, g_direct_equal, free, NULL); for (i = 0; i < 4; i++) { GArray *tmp = NULL; MetaSide side; switch (i) { case 0: tmp = edge_data->left_edges; side = META_SIDE_LEFT; break; case 1: tmp = edge_data->right_edges; side = META_SIDE_RIGHT; break; case 2: tmp = edge_data->top_edges; side = META_SIDE_TOP; break; case 3: tmp = edge_data->bottom_edges; side = META_SIDE_BOTTOM; break; default: g_assert_not_reached (); } for (j = 0; j < tmp->len; j++) { MetaEdge *edge = g_array_index (tmp, MetaEdge*, j); if (edge->edge_type == META_EDGE_WINDOW && edge->side_type == side) { /* The same edge will appear in two arrays, and we can't free * it yet we still need to compare edge->side_type for the other * array that it is in. So store it in a hash table for later * freeing. Could also do this in a simple linked list. */ g_hash_table_insert (edges_to_be_freed, edge, edge); } } } /* Now free all the window edges (the key destroy function is free) */ g_hash_table_destroy (edges_to_be_freed); /* Now free the arrays and data */ g_array_free (edge_data->left_edges, TRUE); g_array_free (edge_data->right_edges, TRUE); g_array_free (edge_data->top_edges, TRUE); g_array_free (edge_data->bottom_edges, TRUE); edge_data->left_edges = NULL; edge_data->right_edges = NULL; edge_data->top_edges = NULL; edge_data->bottom_edges = NULL; /* Cleanup the timeouts */ if (edge_data->left_data.timeout_setup && edge_data->left_data.timeout_id != 0) { g_source_remove (edge_data->left_data.timeout_id); edge_data->left_data.timeout_id = 0; } if (edge_data->right_data.timeout_setup && edge_data->right_data.timeout_id != 0) { g_source_remove (edge_data->right_data.timeout_id); edge_data->right_data.timeout_id = 0; } if (edge_data->top_data.timeout_setup && edge_data->top_data.timeout_id != 0) { g_source_remove (edge_data->top_data.timeout_id); edge_data->top_data.timeout_id = 0; } if (edge_data->bottom_data.timeout_setup && edge_data->bottom_data.timeout_id != 0) { g_source_remove (edge_data->bottom_data.timeout_id); edge_data->bottom_data.timeout_id = 0; } free (display->grab_edge_resistance_data); display->grab_edge_resistance_data = NULL; } static int stupid_sort_requiring_extra_pointer_dereference (gconstpointer a, gconstpointer b) { const MetaEdge * const *a_edge = a; const MetaEdge * const *b_edge = b; return meta_rectangle_edge_cmp_ignore_type (*a_edge, *b_edge); } static void cache_edges (MetaDisplay *display, GList *window_edges, GList *monitor_edges, GList *screen_edges) { MetaEdgeResistanceData *edge_data; GList *tmp; int num_left, num_right, num_top, num_bottom; int i; /* * 0th: Print debugging information to the log about the edges */ #ifdef WITH_VERBOSE_MODE if (meta_is_verbose()) { int max_edges = MAX (MAX( g_list_length (window_edges), g_list_length (monitor_edges)), g_list_length (screen_edges)); char big_buffer[(EDGE_LENGTH+2)*max_edges]; meta_rectangle_edge_list_to_string (window_edges, ", ", big_buffer); meta_topic (META_DEBUG_EDGE_RESISTANCE, "Window edges for resistance : %s\n", big_buffer); meta_rectangle_edge_list_to_string (monitor_edges, ", ", big_buffer); meta_topic (META_DEBUG_EDGE_RESISTANCE, "Monitor edges for resistance: %s\n", big_buffer); meta_rectangle_edge_list_to_string (screen_edges, ", ", big_buffer); meta_topic (META_DEBUG_EDGE_RESISTANCE, "Screen edges for resistance : %s\n", big_buffer); } #endif /* * 1st: Get the total number of each kind of edge */ num_left = num_right = num_top = num_bottom = 0; for (i = 0; i < 3; i++) { tmp = NULL; switch (i) { case 0: tmp = window_edges; break; case 1: tmp = monitor_edges; break; case 2: tmp = screen_edges; break; default: g_assert_not_reached (); } while (tmp) { MetaEdge *edge = tmp->data; switch (edge->side_type) { case META_SIDE_LEFT: num_left++; break; case META_SIDE_RIGHT: num_right++; break; case META_SIDE_TOP: num_top++; break; case META_SIDE_BOTTOM: num_bottom++; break; default: g_assert_not_reached (); } tmp = tmp->next; } } /* * 2nd: Allocate the edges */ g_assert (display->grab_edge_resistance_data == NULL); display->grab_edge_resistance_data = g_new0 (MetaEdgeResistanceData, 1); edge_data = display->grab_edge_resistance_data; edge_data->left_edges = g_array_sized_new (FALSE, FALSE, sizeof(MetaEdge*), num_left + num_right); edge_data->right_edges = g_array_sized_new (FALSE, FALSE, sizeof(MetaEdge*), num_left + num_right); edge_data->top_edges = g_array_sized_new (FALSE, FALSE, sizeof(MetaEdge*), num_top + num_bottom); edge_data->bottom_edges = g_array_sized_new (FALSE, FALSE, sizeof(MetaEdge*), num_top + num_bottom); /* * 3rd: Add the edges to the arrays */ for (i = 0; i < 3; i++) { tmp = NULL; switch (i) { case 0: tmp = window_edges; break; case 1: tmp = monitor_edges; break; case 2: tmp = screen_edges; break; default: g_assert_not_reached (); } while (tmp) { MetaEdge *edge = tmp->data; switch (edge->side_type) { case META_SIDE_LEFT: case META_SIDE_RIGHT: g_array_append_val (edge_data->left_edges, edge); g_array_append_val (edge_data->right_edges, edge); break; case META_SIDE_TOP: case META_SIDE_BOTTOM: g_array_append_val (edge_data->top_edges, edge); g_array_append_val (edge_data->bottom_edges, edge); break; default: g_assert_not_reached (); } tmp = tmp->next; } } /* * 4th: Sort the arrays (FIXME: This is kinda dumb since the arrays were * individually sorted earlier and we could have done this faster and * avoided this sort by sticking them into the array with some simple * merging of the lists). */ g_array_sort (display->grab_edge_resistance_data->left_edges, stupid_sort_requiring_extra_pointer_dereference); g_array_sort (display->grab_edge_resistance_data->right_edges, stupid_sort_requiring_extra_pointer_dereference); g_array_sort (display->grab_edge_resistance_data->top_edges, stupid_sort_requiring_extra_pointer_dereference); g_array_sort (display->grab_edge_resistance_data->bottom_edges, stupid_sort_requiring_extra_pointer_dereference); } static void initialize_grab_edge_resistance_data (MetaDisplay *display) { MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data; edge_data->left_data.timeout_setup = FALSE; edge_data->right_data.timeout_setup = FALSE; edge_data->top_data.timeout_setup = FALSE; edge_data->bottom_data.timeout_setup = FALSE; edge_data->left_data.keyboard_buildup = 0; edge_data->right_data.keyboard_buildup = 0; edge_data->top_data.keyboard_buildup = 0; edge_data->bottom_data.keyboard_buildup = 0; } static void compute_resistance_and_snapping_edges (MetaDisplay *display) { GList *stacked_windows; GList *cur_window_iter; GList *edges; /* Lists of window positions (rects) and their relative stacking positions */ int stack_position; GSList *obscuring_windows, *window_stacking; /* The portions of the above lists that still remain at the stacking position * in the layer that we are working on */ GSList *rem_windows, *rem_win_stacking; g_assert (display->grab_window != NULL); meta_topic (META_DEBUG_WINDOW_OPS, "Computing edges to resist-movement or snap-to for %s.\n", display->grab_window->desc); /* * 1st: Get the list of relevant windows, from bottom to top */ stacked_windows = meta_stack_list_windows (display->grab_screen->stack, display->grab_screen->active_workspace); /* * 2nd: we need to separate that stacked list into a list of windows that * can obscure other edges. To make sure we only have windows obscuring * those below it instead of going both ways, we also need to keep a * counter list. Messy, I know. */ obscuring_windows = window_stacking = NULL; cur_window_iter = stacked_windows; stack_position = 0; while (cur_window_iter != NULL) { MetaWindow *cur_window = cur_window_iter->data; if (WINDOW_EDGES_RELEVANT (cur_window, display)) { MetaRectangle *new_rect; new_rect = g_new (MetaRectangle, 1); meta_window_get_outer_rect (cur_window, new_rect); obscuring_windows = g_slist_prepend (obscuring_windows, new_rect); window_stacking = g_slist_prepend (window_stacking, GINT_TO_POINTER (stack_position)); } stack_position++; cur_window_iter = cur_window_iter->next; } /* Put 'em in bottom to top order */ rem_windows = obscuring_windows = g_slist_reverse (obscuring_windows); rem_win_stacking = window_stacking = g_slist_reverse (window_stacking); /* * 3rd: loop over the windows again, this time getting the edges from * them and removing intersections with the relevant obscuring_windows & * obscuring_docks. */ edges = NULL; stack_position = 0; cur_window_iter = stacked_windows; while (cur_window_iter != NULL) { MetaRectangle cur_rect; MetaWindow *cur_window = cur_window_iter->data; meta_window_get_outer_rect (cur_window, &cur_rect); /* Check if we want to use this window's edges for edge * resistance (note that dock edges are considered screen edges * which are handled separately */ if (WINDOW_EDGES_RELEVANT (cur_window, display) && cur_window->type != META_WINDOW_DOCK) { GList *new_edges; MetaEdge *new_edge; MetaRectangle reduced; /* We don't care about snapping to any portion of the window that * is offscreen (we also don't care about parts of edges covered * by other windows or DOCKS, but that's handled below). */ meta_rectangle_intersect (&cur_rect, &display->grab_screen->rect, &reduced); new_edges = NULL; /* Left side of this window is resistance for the right edge of * the window being moved. */ new_edge = g_new (MetaEdge, 1); new_edge->rect = reduced; new_edge->rect.width = 0; new_edge->side_type = META_SIDE_RIGHT; new_edge->edge_type = META_EDGE_WINDOW; new_edges = g_list_prepend (new_edges, new_edge); /* Right side of this window is resistance for the left edge of * the window being moved. */ new_edge = g_new (MetaEdge, 1); new_edge->rect = reduced; new_edge->rect.x += new_edge->rect.width; new_edge->rect.width = 0; new_edge->side_type = META_SIDE_LEFT; new_edge->edge_type = META_EDGE_WINDOW; new_edges = g_list_prepend (new_edges, new_edge); /* Top side of this window is resistance for the bottom edge of * the window being moved. */ new_edge = g_new (MetaEdge, 1); new_edge->rect = reduced; new_edge->rect.height = 0; new_edge->side_type = META_SIDE_BOTTOM; new_edge->edge_type = META_EDGE_WINDOW; new_edges = g_list_prepend (new_edges, new_edge); /* Top side of this window is resistance for the bottom edge of * the window being moved. */ new_edge = g_new (MetaEdge, 1); new_edge->rect = reduced; new_edge->rect.y += new_edge->rect.height; new_edge->rect.height = 0; new_edge->side_type = META_SIDE_TOP; new_edge->edge_type = META_EDGE_WINDOW; new_edges = g_list_prepend (new_edges, new_edge); /* Update the remaining windows to only those at a higher * stacking position than this one. */ while (rem_win_stacking && stack_position >= GPOINTER_TO_INT (rem_win_stacking->data)) { rem_windows = rem_windows->next; rem_win_stacking = rem_win_stacking->next; } /* Remove edge portions overlapped by rem_windows and rem_docks */ new_edges = meta_rectangle_remove_intersections_with_boxes_from_edges ( new_edges, rem_windows); /* Save the new edges */ edges = g_list_concat (new_edges, edges); } stack_position++; cur_window_iter = cur_window_iter->next; } /* * 4th: Free the extra memory not needed and sort the list */ g_list_free (stacked_windows); /* Free the memory used by the obscuring windows/docks lists */ g_slist_free (window_stacking); /* FIXME: Shouldn't there be a helper function to make this one line of code * to free a list instead of four ugly ones? */ g_slist_foreach (obscuring_windows, (void (*)(gpointer,gpointer))&free, /* ew, for ugly */ NULL); g_slist_free (obscuring_windows); /* Sort the list. FIXME: Should I bother with this sorting? I just * sort again later in cache_edges() anyway... */ edges = g_list_sort (edges, meta_rectangle_edge_cmp); /* * 5th: Cache the combination of these edges with the onscreen and * monitor edges in an array for quick access. Free the edges since * they've been cached elsewhere. */ cache_edges (display, edges, display->grab_screen->active_workspace->monitor_edges, display->grab_screen->active_workspace->screen_edges); g_list_free (edges); /* * 6th: Initialize the resistance timeouts and buildups */ initialize_grab_edge_resistance_data (display); } /* Note that old_[xy] and new_[xy] are with respect to inner positions of * the window. */ LOCAL_SYMBOL void meta_window_edge_resistance_for_move (MetaWindow *window, int old_x, int old_y, int *new_x, int *new_y, GSourceFunc timeout_func, gboolean snap, gboolean is_keyboard_op) { MetaRectangle old_outer, proposed_outer, new_outer; gboolean is_resize; meta_window_get_outer_rect (window, &old_outer); proposed_outer = old_outer; proposed_outer.x += (*new_x - old_x); proposed_outer.y += (*new_y - old_y); new_outer = proposed_outer; window->display->grab_last_user_action_was_snap = snap; is_resize = FALSE; if (apply_edge_resistance_to_each_side (window->display, window, &old_outer, &new_outer, timeout_func, snap, is_keyboard_op, is_resize)) { /* apply_edge_resistance_to_each_side independently applies * resistance to both the right and left edges of new_outer as both * could meet areas of resistance. But we don't want a resize, so we * just have both edges move according to the stricter of the * resistances. Same thing goes for top & bottom edges. */ MetaRectangle *reference; int left_change, right_change, smaller_x_change; int top_change, bottom_change, smaller_y_change; if (snap && !is_keyboard_op) reference = &proposed_outer; else reference = &old_outer; left_change = BOX_LEFT (new_outer) - BOX_LEFT (*reference); right_change = BOX_RIGHT (new_outer) - BOX_RIGHT (*reference); if ( snap && is_keyboard_op && left_change == 0) smaller_x_change = right_change; else if (snap && is_keyboard_op && right_change == 0) smaller_x_change = left_change; else if (ABS (left_change) < ABS (right_change)) smaller_x_change = left_change; else smaller_x_change = right_change; top_change = BOX_TOP (new_outer) - BOX_TOP (*reference); bottom_change = BOX_BOTTOM (new_outer) - BOX_BOTTOM (*reference); if ( snap && is_keyboard_op && top_change == 0) smaller_y_change = bottom_change; else if (snap && is_keyboard_op && bottom_change == 0) smaller_y_change = top_change; else if (ABS (top_change) < ABS (bottom_change)) smaller_y_change = top_change; else smaller_y_change = bottom_change; *new_x = old_x + smaller_x_change + (BOX_LEFT (*reference) - BOX_LEFT (old_outer)); *new_y = old_y + smaller_y_change + (BOX_TOP (*reference) - BOX_TOP (old_outer)); meta_topic (META_DEBUG_EDGE_RESISTANCE, "outer x & y move-to coordinate changed from %d,%d to %d,%d\n", proposed_outer.x, proposed_outer.y, old_outer.x + (*new_x - old_x), old_outer.y + (*new_y - old_y)); } } /* Note that old_(width|height) and new_(width|height) are with respect to * sizes of the inner window. */ LOCAL_SYMBOL void meta_window_edge_resistance_for_resize (MetaWindow *window, int old_width, int old_height, int *new_width, int *new_height, int gravity, GSourceFunc timeout_func, gboolean snap, gboolean is_keyboard_op) { MetaRectangle old_outer, new_outer; int proposed_outer_width, proposed_outer_height; gboolean is_resize; meta_window_get_outer_rect (window, &old_outer); proposed_outer_width = old_outer.width + (*new_width - old_width); proposed_outer_height = old_outer.height + (*new_height - old_height); meta_rectangle_resize_with_gravity (&old_outer, &new_outer, gravity, proposed_outer_width, proposed_outer_height); window->display->grab_last_user_action_was_snap = snap; is_resize = TRUE; if (apply_edge_resistance_to_each_side (window->display, window, &old_outer, &new_outer, timeout_func, snap, is_keyboard_op, is_resize)) { *new_width = old_width + (new_outer.width - old_outer.width); *new_height = old_height + (new_outer.height - old_outer.height); meta_topic (META_DEBUG_EDGE_RESISTANCE, "outer width & height got changed from %d,%d to %d,%d\n", proposed_outer_width, proposed_outer_height, new_outer.width, new_outer.height); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/window-private.h��������������������������������������������������������������0000664�0001750�0001750�00000077536�14211404421�020025� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file window-private.h Windows which Muffin manages * * Managing X windows. * This file contains methods on this class which are available to * routines in core but not outside it. (See window.h for the routines * which the rest of the world is allowed to use.) */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002 Red Hat, Inc. * Copyright (C) 2003, 2004 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_WINDOW_PRIVATE_H #define META_WINDOW_PRIVATE_H #include <config.h> #include <meta/compositor.h> #include <meta/window.h> #include "screen-private.h" #include <meta/util.h> #include "stack.h" #include "iconcache.h" #include <X11/Xutil.h> #include <cairo.h> #include <gdk-pixbuf/gdk-pixbuf.h> typedef struct _MetaWindowQueue MetaWindowQueue; typedef enum { META_CLIENT_TYPE_UNKNOWN = 0, META_CLIENT_TYPE_APPLICATION = 1, META_CLIENT_TYPE_PAGER = 2, META_CLIENT_TYPE_MAX_RECOGNIZED = 2 } MetaClientType; typedef enum { META_QUEUE_CALC_SHOWING = 1 << 0, META_QUEUE_MOVE_RESIZE = 1 << 1 } MetaQueueType; /* edge zones for tiling/snapping identification ___________________________ | 4 0 5 | | | | | | | | | | 2 3 | | | | | | | | | | 7 1 6 | |_________________________| */ enum { ZONE_0 = 0, ZONE_1, ZONE_2, ZONE_3, ZONE_4, ZONE_5, ZONE_6, ZONE_7, ZONE_NONE }; #define NUMBER_OF_QUEUES 2 #define HUD_WIDTH 24 #define CSD_TITLEBAR_HEIGHT 48 typedef enum { _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0, _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1, _NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2, } MetaBypassCompositorHintValue; typedef enum { META_EDGE_CONSTRAINT_NONE = 0, META_EDGE_CONSTRAINT_WINDOW = 1, META_EDGE_CONSTRAINT_MONITOR = 2, } MetaEdgeConstraint; struct _MetaWindow { GObject parent_instance; MetaDisplay *display; MetaScreen *screen; const MetaMonitorInfo *monitor; MetaWorkspace *workspace; Window xwindow; /* may be NULL! not all windows get decorated */ MetaFrame *frame; int depth; Visual *xvisual; Colormap colormap; char *desc; /* used in debug spew */ char *title; char *icon_name; /* XAppGtkWindow */ char *theme_icon_name; guint progress; guint progress_pulse : 1; /* /XappGtkWindow */ GdkPixbuf *icon; MetaIconCache icon_cache; int icon_size; Pixmap wm_hints_pixmap; Pixmap wm_hints_mask; MetaWindowType type; Atom type_atom; /* NOTE these five are not in UTF-8, we just treat them as random * binary data */ char *res_class; char *res_name; char *role; char *sm_client_id; char *wm_client_machine; char *startup_id; char *muffin_hints; char *gtk_theme_variant; char *gtk_application_id; char *gtk_unique_bus_name; char *gtk_application_object_path; char *gtk_window_object_path; char *gtk_app_menu_object_path; char *gtk_menubar_object_path; int hide_titlebar_when_maximized; int net_wm_pid; int client_pid; Window xtransient_for; Window xgroup_leader; Window xclient_leader; /* Initial workspace property */ int initial_workspace; /* Initial timestamp property */ guint32 initial_timestamp; /* Whether this is an override redirect window or not */ guint override_redirect : 1; /* Whether we're maximized */ guint maximized_horizontally : 1; guint maximized_vertically : 1; guint32 snap_delay_timestamp; guint snap_queued : 1; guint zone_queued; MetaWindowTileType tile_type; MetaWindowTileType resizing_tile_type; guint custom_snap_size : 1; guint current_proximity_zone; guint mouse_on_edge : 1; guint maybe_retile_maximize : 1; /* Whether we have to maximize/minimize after placement */ guint maximize_horizontally_after_placement : 1; guint maximize_vertically_after_placement : 1; guint minimize_after_placement : 1; guint tile_after_placement : 1; guint move_after_placement : 1; /* The current or requested tile mode. If maximized_vertically is true, * this is the current mode. If not, it is the mode which will be * requested after the window grab is released */ guint tile_mode : 4; guint last_tile_mode : 4; guint resize_tile_mode : 4; /* The last "full" maximized/unmaximized state. We need to keep track of * that to toggle between normal/tiled or maximized/tiled states. */ guint saved_maximize : 1; int tile_monitor_number; /* 0 - top * 1 - right * 2 - bottom * 3 - left */ MetaEdgeConstraint edge_constraints[4]; /* Whether we're shaded */ guint shaded : 1; /* Whether we're fullscreen */ guint fullscreen : 1; /* Whether the urgent flag of WM_HINTS is set */ guint wm_hints_urgent : 1; /* Area to cover when in fullscreen mode. If _NET_WM_FULLSCREEN_MONITORS has * been overridden (via a client message), the window will cover the union of * these monitors. If not, this is the single monitor which the window's * origin is on. */ long fullscreen_monitors[4]; /* Whether we're trying to constrain the window to be fully onscreen */ guint require_fully_onscreen : 1; /* Whether we're trying to constrain the window to be on a single monitor */ guint require_on_single_monitor : 1; /* Whether we're trying to constrain the window's titlebar to be onscreen */ guint require_titlebar_visible : 1; /* Whether we're sticky in the multi-workspace sense * (vs. the not-scroll-with-viewport sense, we don't * have no stupid viewports) */ guint on_all_workspaces : 1; /* This is true if the client requested sticky, and implies on_all_workspaces == TRUE, * however on_all_workspaces can be set TRUE for other internal reasons too, such as * being override_redirect or being on the non-primary monitor. */ guint on_all_workspaces_requested : 1; /* Minimize is the state controlled by the minimize button */ guint minimized : 1; guint tab_unminimized : 1; /* Whether the window is mapped; actual server-side state * see also unmaps_pending */ guint mapped : 1; /* Whether window has been hidden from view by lowering it to the bottom * of window stack. */ guint hidden : 1; /* Whether the compositor thinks the window is visible */ guint visible_to_compositor : 1; /* When we next show or hide the window, what effect we should * tell the compositor to perform. */ guint pending_compositor_effect : 4; /* MetaCompEffect */ /* Iconic is the state in WM_STATE; happens for workspaces/shading * in addition to minimize */ guint iconic : 1; /* initially_iconic is the WM_HINTS setting when we first manage * the window. It's taken to mean initially minimized. */ guint initially_iconic : 1; /* whether an initial workspace was explicitly set */ guint initial_workspace_set : 1; /* whether an initial timestamp was explicitly set */ guint initial_timestamp_set : 1; /* whether net_wm_user_time has been set yet */ guint net_wm_user_time_set : 1; /* whether net_wm_icon_geometry has been set */ guint icon_geometry_set: 1; /* These are the flags from WM_PROTOCOLS */ guint take_focus : 1; guint delete_window : 1; guint net_wm_ping : 1; /* Globally active / No input */ guint input : 1; /* MWM hints about features of window */ guint mwm_decorated : 1; guint mwm_border_only : 1; guint mwm_has_close_func : 1; guint mwm_has_minimize_func : 1; guint mwm_has_maximize_func : 1; guint mwm_has_move_func : 1; guint mwm_has_resize_func : 1; /* Computed features of window */ guint decorated : 1; guint border_only : 1; guint always_sticky : 1; guint has_close_func : 1; guint has_minimize_func : 1; guint has_maximize_func : 1; guint has_shade_func : 1; guint has_move_func : 1; guint has_resize_func : 1; guint has_fullscreen_func : 1; /* Weird "_NET_WM_STATE_MODAL" flag */ guint wm_state_modal : 1; /* TRUE if the client forced these on */ guint wm_state_skip_taskbar : 1; guint wm_state_skip_pager : 1; /* Computed whether to skip taskbar or not */ guint skip_taskbar : 1; guint skip_pager : 1; /* TRUE if client set these */ guint wm_state_above : 1; guint wm_state_below : 1; /* EWHH demands attention flag */ guint wm_state_demands_attention : 1; /* this flag tracks receipt of focus_in focus_out */ guint has_focus : 1; /* Have we placed this window? */ guint placed : 1; /* Must we force_save_user_window_placement? */ guint force_save_user_rect : 1; /* Is this not a transient of the focus window which is being denied focus? */ guint denied_focus_and_not_transient : 1; /* Has this window not ever been shown yet? */ guint showing_for_first_time : 1; /* Are we in meta_window_unmanage()? */ guint unmanaging : 1; /* Are we in meta_window_new()? */ guint constructing : 1; /* Are we in the various queues? (Bitfield: see META_WINDOW_IS_IN_QUEUE) */ guint is_in_queues : NUMBER_OF_QUEUES; /* Used by keybindings.c */ guint keys_grabbed : 1; /* normal keybindings grabbed */ guint grab_on_frame : 1; /* grabs are on the frame */ guint all_keys_grabbed : 1; /* AnyKey grabbed */ /* Set if the reason for unmanaging the window is that * it was withdrawn */ guint withdrawn : 1; /* TRUE if constrain_position should calc placement. * only relevant if !window->placed */ guint calc_placement : 1; /* Transient parent is a root window */ guint transient_parent_is_root_window : 1; /* Info on which props we got our attributes from */ guint using_net_wm_name : 1; /* vs. plain wm_name */ guint using_net_wm_visible_name : 1; /* tracked so we can clear it */ guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */ guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */ /* has a shape mask */ guint has_shape : 1; /* icon props have changed */ guint need_reread_icon : 1; /* if TRUE, window was maximized at start of current grab op */ guint shaken_loose : 1; /* if TRUE we have a grab on the focus click buttons */ guint have_focus_click_grab : 1; /* if TRUE, application is buggy and SYNC resizing is turned off */ guint disable_sync : 1; /* if TRUE, window is attached to its parent */ guint attached : 1; /* if non-NULL, the bounds of the window frame */ cairo_region_t *frame_bounds; /* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */ cairo_region_t *opaque_region; /* if TRUE, the we have the new form of sync request counter which * also handles application frames */ guint extended_sync_request_counter : 1; /* Note: can be NULL */ GSList *struts; #ifdef HAVE_XSYNC /* XSync update counter */ XSyncCounter sync_request_counter; gint64 sync_request_serial; gint64 sync_request_wait_serial; guint sync_request_timeout_id; /* alarm monitoring client's _NET_WM_SYNC_REQUEST_COUNTER */ XSyncAlarm sync_request_alarm; #endif /* Number of UnmapNotify that are caused by us, if * we get UnmapNotify with none pending then the client * is withdrawing the window. */ int unmaps_pending; /* See docs for meta_window_get_stable_sequence() */ guint32 stable_sequence; /* set to the most recent user-interaction event timestamp that we know about for this window */ guint32 net_wm_user_time; /* window that gets updated net_wm_user_time values */ Window user_time_window; /* The size we set the window to last (i.e. what we believe * to be its actual size on the server). The x, y are * the actual server-side x,y so are relative to the frame * (meaning that they just hold the frame width and height) * or the root window (meaning they specify the location * of the top left of the inner window) as appropriate. */ MetaRectangle rect; gboolean has_custom_frame_extents; GtkBorder custom_frame_extents; /* The geometry to restore when we unmaximize. The position is in * root window coords, even if there's a frame, which contrasts with * window->rect above. Note that this gives the position and size * of the client window (i.e. ignoring the frame). */ MetaRectangle saved_rect; /* This is the geometry the window had after the last user-initiated * move/resize operations. We use this whenever we are moving the * implicitly (for example, if we move to avoid a panel, we can snap * back to this position if the panel moves again). Note that this * gives the position and size of the client window (i.e. ignoring * the frame). * * Position valid if user_has_moved, size valid if user_has_resized * * Position always in root coords, unlike window->rect. */ MetaRectangle user_rect; MetaRectangle snapped_rect; /* Cached net_wm_icon_geometry */ MetaRectangle icon_geometry; /* Requested geometry */ int border_width; /* x/y/w/h here get filled with ConfigureRequest values */ XSizeHints size_hints; /* Managed by stack.c */ MetaStackLayer layer; int stack_position; /* see comment in stack.h */ /* Current dialog open for this window */ int dialog_pid; /* maintained by group.c */ MetaGroup *group; GObject *compositor_private; /* Focused window that is (directly or indirectly) attached to this one */ MetaWindow *attached_focus_window; /* The currently complementary tiled window, if any */ MetaWindow *tile_match; /* Bypass compositor hints */ guint bypass_compositor; }; struct _MetaWindowClass { GObjectClass parent_class; void (*workspace_changed) (MetaWindow *window, int old_workspace); void (*focus) (MetaWindow *window); void (*raised) (MetaWindow *window); void (*unmanaged) (MetaWindow *window); }; /* These differ from window->has_foo_func in that they consider * the dynamic window state such as "maximized", not just the * window's type */ #define META_WINDOW_MAXIMIZED(w) ((w)->maximized_horizontally && \ (w)->maximized_vertically) #define META_WINDOW_MAXIMIZED_VERTICALLY(w) ((w)->maximized_vertically) #define META_WINDOW_MAXIMIZED_HORIZONTALLY(w) ((w)->maximized_horizontally) #define META_WINDOW_TILED(w) ((w)->tile_type == META_WINDOW_TILE_TYPE_TILED) #define META_WINDOW_SNAPPED(w) ((w)->tile_type == META_WINDOW_TILE_TYPE_SNAPPED) #define META_WINDOW_TILED_OR_SNAPPED(w) (META_WINDOW_SNAPPED (w) || META_WINDOW_TILED (w)) #define META_WINDOW_TILED_LEFT(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_LEFT) #define META_WINDOW_TILED_RIGHT(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_RIGHT) #define META_WINDOW_TILED_SIDE_BY_SIDE(w) (META_WINDOW_TILED_LEFT (w) || META_WINDOW_TILED_RIGHT (w)) #define META_WINDOW_TILED_ULC(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_ULC) #define META_WINDOW_TILED_LLC(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_LLC) #define META_WINDOW_TILED_URC(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_URC) #define META_WINDOW_TILED_LRC(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_LRC) #define META_WINDOW_TILED_CORNER(w) (META_WINDOW_TILED_ULC (w) || \ META_WINDOW_TILED_LLC (w) || \ META_WINDOW_TILED_URC (w) || \ META_WINDOW_TILED_LRC (w)) #define META_WINDOW_TILED_TOP(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_TOP) #define META_WINDOW_TILED_BOTTOM(w) (META_WINDOW_TILED_OR_SNAPPED (w) && (w)->tile_mode == META_TILE_BOTTOM) #define META_WINDOW_TILED_TOP_BOTTOM(w) (META_WINDOW_TILED_TOP (w) || \ META_WINDOW_TILED_BOTTOM (w)) #define META_WINDOW_ALLOWS_MOVE(w) ((w)->has_move_func && !(w)->fullscreen) #define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w) ((w)->has_resize_func && !META_WINDOW_MAXIMIZED (w) && !(w)->fullscreen && !(w)->shaded) #define META_WINDOW_ALLOWS_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && \ (((w)->size_hints.min_width < (w)->size_hints.max_width) || \ ((w)->size_hints.min_height < (w)->size_hints.max_height))) #define META_WINDOW_ALLOWS_HORIZONTAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_width < (w)->size_hints.max_width && \ !META_WINDOW_TILED_OR_SNAPPED (w)) #define META_WINDOW_ALLOWS_VERTICAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_height < (w)->size_hints.max_height && \ !META_WINDOW_TILED_OR_SNAPPED (w)) #define META_WINDOW_ALLOWS_TOP_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && META_WINDOW_TILED_OR_SNAPPED (w) && \ ((w)->tile_mode == META_TILE_BOTTOM || \ (w)->tile_mode == META_TILE_LLC || (w)->tile_mode == META_TILE_LRC)) #define META_WINDOW_ALLOWS_BOTTOM_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && META_WINDOW_TILED_OR_SNAPPED (w) && \ ((w)->tile_mode == META_TILE_TOP || \ (w)->tile_mode == META_TILE_ULC || (w)->tile_mode == META_TILE_URC)) #define META_WINDOW_ALLOWS_LEFT_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && META_WINDOW_TILED_OR_SNAPPED (w) && \ ((w)->tile_mode == META_TILE_RIGHT || \ (w)->tile_mode == META_TILE_URC || (w)->tile_mode == META_TILE_LRC)) #define META_WINDOW_ALLOWS_RIGHT_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && META_WINDOW_TILED_OR_SNAPPED (w) && \ ((w)->tile_mode == META_TILE_LEFT || \ (w)->tile_mode == META_TILE_ULC || (w)->tile_mode == META_TILE_LLC)) #define GRAB_OP(w) ((w)->display->grab_op) #define META_WINDOW_ MetaWindow* meta_window_new (MetaDisplay *display, Window xwindow, gboolean must_be_viewable); MetaWindow* meta_window_new_with_attrs (MetaDisplay *display, Window xwindow, gboolean must_be_viewable, MetaCompEffect effect, XWindowAttributes *attrs); void meta_window_unmanage (MetaWindow *window, guint32 timestamp); void meta_window_queue (MetaWindow *window, guint queuebits); void meta_window_real_tile (MetaWindow *window, gboolean force); void meta_window_maximize_internal (MetaWindow *window, MetaMaximizeFlags directions, MetaRectangle *saved_rect); void meta_window_unmaximize_with_gravity (MetaWindow *window, MetaMaximizeFlags directions, int new_width, int new_height, int gravity); void meta_window_make_above (MetaWindow *window); void meta_window_unmake_above (MetaWindow *window); void meta_window_shade (MetaWindow *window, guint32 timestamp); void meta_window_unshade (MetaWindow *window, guint32 timestamp); void meta_window_adjust_opacity (MetaWindow *window, gboolean increase); void meta_window_make_fullscreen_internal (MetaWindow *window); void meta_window_make_fullscreen (MetaWindow *window); void meta_window_unmake_fullscreen (MetaWindow *window); void meta_window_update_fullscreen_monitors (MetaWindow *window, unsigned long top, unsigned long bottom, unsigned long left, unsigned long right); /* args to move are window pos, not frame pos */ void meta_window_move_resize (MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw, int w, int h); void meta_window_resize_with_gravity (MetaWindow *window, gboolean user_op, int w, int h, int gravity); /* Return whether the window should be currently mapped */ gboolean meta_window_should_be_showing (MetaWindow *window); /* See warning in window.c about this function */ gboolean __window_is_terminal (MetaWindow *window); void meta_window_update_struts (MetaWindow *window); /* this gets root coords */ void meta_window_get_position (MetaWindow *window, int *x, int *y); /* Gets root coords for x, y, width & height of client window; uses * meta_window_get_position for x & y. */ void meta_window_get_client_root_coords (MetaWindow *window, MetaRectangle *rect); /* gets position we need to set to stay in current position, * assuming position will be gravity-compensated. i.e. * this is the position a client would send in a configure * request. */ void meta_window_get_gravity_position (MetaWindow *window, int gravity, int *x, int *y); /* Get geometry for saving in the session; x/y are gravity * position, and w/h are in resize inc above the base size. */ void meta_window_get_geometry (MetaWindow *window, int *x, int *y, int *width, int *height); void meta_window_kill (MetaWindow *window); void meta_window_focus (MetaWindow *window, guint32 timestamp); void meta_window_update_unfocused_button_grabs (MetaWindow *window); /* Sends a client message */ void meta_window_send_icccm_message (MetaWindow *window, Atom atom, guint32 timestamp); void meta_window_create_sync_request_alarm (MetaWindow *window); void meta_window_destroy_sync_request_alarm (MetaWindow *window); void meta_window_move_resize_request(MetaWindow *window, guint value_mask, int gravity, int x, int y, int width, int height); gboolean meta_window_configure_request (MetaWindow *window, XEvent *event); gboolean meta_window_property_notify (MetaWindow *window, XEvent *event); gboolean meta_window_client_message (MetaWindow *window, XEvent *event); gboolean meta_window_notify_focus (MetaWindow *window, XEvent *event); void meta_window_set_current_workspace_hint (MetaWindow *window); unsigned long meta_window_get_net_wm_desktop (MetaWindow *window); void meta_window_show_menu (MetaWindow *window, int root_x, int root_y, int button, guint32 timestamp); gboolean meta_window_titlebar_is_onscreen (MetaWindow *window); void meta_window_shove_titlebar_onscreen (MetaWindow *window); void meta_window_set_gravity (MetaWindow *window, int gravity); #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, gint64 new_counter_value); #endif /* HAVE_XSYNC */ void meta_window_handle_mouse_grab_op_event (MetaWindow *window, XEvent *event); void meta_window_handle_keyboard_grab_op_event (MetaWindow *window, XEvent *event); GList* meta_window_get_workspaces (MetaWindow *window); gboolean meta_window_located_on_workspace (MetaWindow *window, MetaWorkspace *workspace); void meta_window_get_work_area_current_monitor (MetaWindow *window, MetaRectangle *area); void meta_window_get_work_area_for_monitor (MetaWindow *window, int which_monitor, MetaRectangle *area); void meta_window_get_work_area_all_monitors (MetaWindow *window, MetaRectangle *area); int meta_window_get_current_tile_monitor_number (MetaWindow *window); void meta_window_get_current_tile_area (MetaWindow *window, MetaRectangle *tile_area); void meta_window_get_tile_threshold_area_for_mode (MetaWindow *window, MetaRectangle work_area, MetaTileMode mode, MetaRectangle *tile_area, gint zone_width); void meta_window_get_titlebar_rect (MetaWindow *window, MetaRectangle *titlebar_rect); gboolean meta_window_same_application (MetaWindow *window, MetaWindow *other_window); #define META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE(w) \ ((w)->type != META_WINDOW_DOCK && (w)->type != META_WINDOW_DESKTOP) #define META_WINDOW_IN_NORMAL_TAB_CHAIN(w) \ (((w)->input || (w)->take_focus ) && META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE (w) && (!(w)->skip_taskbar)) #define META_WINDOW_IN_DOCK_TAB_CHAIN(w) \ (((w)->input || (w)->take_focus) && (! META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE (w) || (w)->skip_taskbar)) #define META_WINDOW_IN_GROUP_TAB_CHAIN(w, g) \ (((w)->input || (w)->take_focus) && (!g || meta_window_get_group(w)==g)) void meta_window_refresh_resize_popup (MetaWindow *window); void meta_window_free_delete_dialog (MetaWindow *window); void meta_window_begin_grab_op (MetaWindow *window, MetaGrabOp op, gboolean frame_action, guint32 timestamp); void meta_window_update_keyboard_resize (MetaWindow *window, gboolean update_cursor); void meta_window_update_keyboard_move (MetaWindow *window); void meta_window_update_layer (MetaWindow *window); void meta_window_recalc_features (MetaWindow *window); void meta_window_recalc_window_type (MetaWindow *window); void meta_window_frame_size_changed (MetaWindow *window); void meta_window_stack_just_below (MetaWindow *window, MetaWindow *below_this_one); void meta_window_stack_just_above (MetaWindow *window, MetaWindow *above_this_one); void meta_window_set_user_time (MetaWindow *window, guint32 timestamp); void meta_window_update_role (MetaWindow *window); void meta_window_update_net_wm_type (MetaWindow *window); void meta_window_update_for_monitors_changed (MetaWindow *window); void meta_window_update_on_all_workspaces (MetaWindow *window); void meta_window_propagate_focus_appearance (MetaWindow *window, gboolean focused); gboolean meta_window_should_attach_to_parent (MetaWindow *window); gboolean meta_window_can_tile_side_by_side (MetaWindow *window); gboolean meta_window_can_tile_top_bottom (MetaWindow *window); gboolean meta_window_can_tile_corner (MetaWindow *window); MetaSide meta_window_get_tile_side (MetaWindow *window); void meta_window_compute_tile_match (MetaWindow *window); gboolean meta_window_mouse_on_edge (MetaWindow *window, gint x, gint y); guint meta_window_get_current_zone (MetaWindow *window, MetaRectangle monitor, MetaRectangle work_area, int x, int y, int zone_threshold); void meta_window_set_tile_type (MetaWindow *window, MetaWindowTileType type); MetaWindowTileType meta_window_get_tile_type (MetaWindow *window); gboolean meta_window_is_client_decorated (MetaWindow *window); gboolean meta_window_updates_are_frozen (MetaWindow *window); void meta_window_extend_by_frame (MetaWindow *window, MetaRectangle *rect, const MetaFrameBorders *borders); void meta_window_unextend_by_frame (MetaWindow *window, MetaRectangle *rect, const MetaFrameBorders *borders); void meta_window_get_client_area_rect (const MetaWindow *window, cairo_rectangle_int_t *rect); void meta_window_icon_changed (MetaWindow *window); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/prefs.c�����������������������������������������������������������������������0000664�0001750�0001750�00000177527�14211404421�016161� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin preferences */ /* * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc. * Copyright (C) 2006 Elijah Newren * Copyright (C) 2008 Thomas Thurman * Copyright (C) 2010 Milan Bouchet-Valat, Copyright (C) 2011 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:prefs * @title: Preferences * @short_description: Muffin preferences */ #include <config.h> #include <meta/prefs.h> #include "ui.h" #include "util-private.h" #include "meta-plugin-manager.h" #include <glib.h> #include <gio/gio.h> #include <gtk/gtk.h> #include <string.h> #include <stdlib.h> #include "keybindings-private.h" /* If you add a key, it needs updating in init() and in the gsettings * notify listener and of course in the .schemas file. * * Keys which are handled by one of the unified handlers below are * not given a name here, because the purpose of the unified handlers * is that keys should be referred to exactly once. */ #define KEY_TITLEBAR_FONT "titlebar-font" #define KEY_NUM_WORKSPACES "num-workspaces" #define KEY_WORKSPACE_NAMES "workspace-names" #define KEY_WORKSPACE_CYCLE "workspace-cycle" /* Keys from "foreign" schemas */ #define KEY_GNOME_ANIMATIONS "enable-animations" #define KEY_GNOME_CURSOR_THEME "cursor-theme" #define KEY_GNOME_CURSOR_SIZE "cursor-size" #define KEY_MIN_WINDOW_OPACITY "min-window-opacity" #define KEY_WS_NAMES_GNOME "workspace-names" #define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary" #define KEY_MOUSEWHEEL_ZOOM_ENABLED "screen-magnifier-enabled" #define KEY_BRING_ACTIVATED_WINDOWS_TO_CURRENT_WORKSPACE "bring-windows-to-current-workspace" /* These are the different schemas we are keeping * a GSettings instance for */ #define SCHEMA_GENERAL "org.cinnamon.desktop.wm.preferences" #define SCHEMA_MUFFIN "org.cinnamon.muffin" #define SCHEMA_INTERFACE "org.cinnamon.desktop.interface" #define SCHEMA_A11Y_APPLICATIONS "org.cinnamon.desktop.a11y.applications" #define SCHEMA_CINNAMON "org.cinnamon" #define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s)) static GList *changes = NULL; static guint changed_idle; static GList *listeners = NULL; static GHashTable *settings_schemas; static gboolean use_system_font = FALSE; static PangoFontDescription *titlebar_font = NULL; static MetaVirtualModifier mouse_button_mods = Mod1Mask; static MetaVirtualModifier mouse_button_zoom_mods = Mod1Mask; static gboolean mouse_zoom_enabled = FALSE; static CDesktopFocusMode focus_mode = C_DESKTOP_FOCUS_MODE_CLICK; static CDesktopFocusNewWindows focus_new_windows = C_DESKTOP_FOCUS_NEW_WINDOWS_SMART; static gboolean bring_user_activated_windows_to_current_workspace = FALSE; static gboolean raise_on_click = TRUE; static gboolean attach_modal_dialogs = FALSE; static gboolean ignore_hide_titlebar_when_maximized = FALSE; static char* current_theme = NULL; static int num_workspaces = 4; static gboolean workspace_cycle = FALSE; static CDesktopTitlebarAction action_double_click_titlebar = C_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE; static CDesktopTitlebarAction action_middle_click_titlebar = C_DESKTOP_TITLEBAR_ACTION_LOWER; static CDesktopTitlebarAction action_right_click_titlebar = C_DESKTOP_TITLEBAR_ACTION_MENU; static CDesktopTitlebarScrollAction action_scroll_titlebar = C_DESKTOP_TITLEBAR_SCROLL_ACTION_NONE; static gboolean dynamic_workspaces = FALSE; static gboolean unredirect_fullscreen_windows = FALSE; static gboolean desktop_effects = TRUE; static MetaSyncMethod sync_method = META_SYNC_PRESENTATION_TIME; static gboolean threaded_swap = TRUE; static gboolean send_frame_timings = TRUE; static gboolean application_based = FALSE; static gboolean disable_workarounds = FALSE; static gboolean auto_raise = FALSE; static gboolean auto_raise_delay = 500; static gboolean gnome_animations = TRUE; static char *cursor_theme = NULL; static int cursor_size = 24; static int draggable_border_width = 10; static int tile_hud_threshold = 150; static int resize_threshold = 24; static int ui_scale = 1; static int min_window_opacity = 0; static gboolean resize_with_right_button = FALSE; static gboolean edge_tiling = FALSE; static gboolean edge_resistance_window = TRUE; static gboolean force_fullscreen = TRUE; static unsigned int snap_modifier[2]; static MetaButtonLayout button_layout; /* NULL-terminated array */ static char **workspace_names = NULL; static gboolean workspaces_only_on_primary = FALSE; static gboolean legacy_snap = FALSE; static gboolean invert_workspace_flip = FALSE; static gboolean tile_maximize = FALSE; static void handle_preference_update_enum (GSettings *settings, gchar *key); static gboolean update_binding (MetaKeyPref *binding, gchar **strokes); static gboolean update_key_binding (const char *key, gchar **strokes); static gboolean update_workspace_names (void); static void update_min_win_opacity (void); static void settings_changed (GSettings *settings, gchar *key, gpointer data); static void bindings_changed (GSettings *settings, gchar *key, gpointer data); static void queue_changed (MetaPreference pref); static void maybe_give_disable_workarounds_warning (void); static gboolean titlebar_handler (GVariant*, gpointer*, gpointer); static gboolean theme_name_handler (GVariant*, gpointer*, gpointer); static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer); static gboolean mouse_button_zoom_mods_handler (GVariant*, gpointer*, gpointer); static gboolean snap_modifier_handler (GVariant*, gpointer*, gpointer); static gboolean button_layout_handler (GVariant*, gpointer*, gpointer); static void do_override (char *key, char *schema); static void init_bindings (void); static void init_workspace_names (void); static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_AUTOMATIC; static MetaBackgroundTransition background_transition = META_BACKGROUND_TRANSITION_BLEND; typedef struct { MetaPrefsChangedFunc func; gpointer data; } MetaPrefsListener; typedef struct { char *key; char *schema; MetaPreference pref; } MetaBasePreference; typedef struct { MetaBasePreference base; gpointer target; } MetaEnumPreference; typedef struct { MetaBasePreference base; gboolean *target; } MetaBoolPreference; typedef struct { MetaBasePreference base; /* * A handler. Many of the string preferences aren't stored as * strings and need parsing; others of them have default values * which can't be solved in the general case. If you include a * function pointer here, it will be called instead of writing * the string value out to the target variable. * * The function will be passed to g_settings_get_mapped() and should * return %TRUE if the mapping was successful and %FALSE otherwise. * In the former case the function is expected to handle the result * of the conversion itself and call queue_changed() appropriately; * in particular the @result (out) parameter as returned by * g_settings_get_mapped() will be ignored in all cases. * * This may be NULL. If it is, see "target", below. */ GSettingsGetMapping handler; /* * Where to write the incoming string. * * This must be NULL if the handler is non-NULL. * If the incoming string is NULL, no change will be made. */ gchar **target; } MetaStringPreference; typedef struct { MetaBasePreference base; gint *target; } MetaIntPreference; /* All preferences that are not keybindings must be listed here, * plus in the GSettings schemas and the MetaPreference enum. */ /* FIXMEs: */ /* @@@ Don't use NULL lines at the end; glib can tell you how big it is */ static MetaEnumPreference preferences_enum[] = { { { "focus-new-windows", SCHEMA_GENERAL, META_PREF_FOCUS_NEW_WINDOWS, }, &focus_new_windows, }, { { "focus-mode", SCHEMA_GENERAL, META_PREF_FOCUS_MODE, }, &focus_mode, }, { { "action-double-click-titlebar", SCHEMA_GENERAL, META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR, }, &action_double_click_titlebar, }, { { "action-middle-click-titlebar", SCHEMA_GENERAL, META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR, }, &action_middle_click_titlebar, }, { { "action-right-click-titlebar", SCHEMA_GENERAL, META_PREF_ACTION_RIGHT_CLICK_TITLEBAR, }, &action_right_click_titlebar, }, { { "action-scroll-titlebar", SCHEMA_GENERAL, META_PREF_ACTION_SCROLL_WHEEL_TITLEBAR, }, &action_scroll_titlebar, }, { { "placement-mode", SCHEMA_MUFFIN, META_PREF_PLACEMENT_MODE, }, &placement_mode, }, { { "background-transition", SCHEMA_MUFFIN, META_PREF_BACKGROUND_TRANSITION, }, &background_transition, }, { { "sync-method", SCHEMA_MUFFIN, META_PREF_SYNC_METHOD, }, &sync_method, }, { { NULL, 0, 0 }, NULL }, }; static MetaBoolPreference preferences_bool[] = { { { "attach-modal-dialogs", SCHEMA_MUFFIN, META_PREF_ATTACH_MODAL_DIALOGS, }, &attach_modal_dialogs, }, { { "ignore-hide-titlebar-when-maximized", SCHEMA_MUFFIN, META_PREF_IGNORE_HIDE_TITLEBAR_WHEN_MAXIMIZED, }, &ignore_hide_titlebar_when_maximized, }, { { "raise-on-click", SCHEMA_GENERAL, META_PREF_RAISE_ON_CLICK, }, &raise_on_click, }, { { "bring-windows-to-current-workspace", SCHEMA_CINNAMON, META_PREF_BRING_WINDOWS_TO_CURRENT_WORKSPACE, }, &bring_user_activated_windows_to_current_workspace, }, { { "titlebar-uses-system-font", SCHEMA_GENERAL, META_PREF_TITLEBAR_FONT, /* note! shares a pref */ }, &use_system_font, }, { { "workspace-cycle", SCHEMA_MUFFIN, META_PREF_WORKSPACE_CYCLE, }, &workspace_cycle, }, { { "dynamic-workspaces", SCHEMA_MUFFIN, META_PREF_DYNAMIC_WORKSPACES, }, &dynamic_workspaces, }, { { "unredirect-fullscreen-windows", SCHEMA_MUFFIN, META_PREF_UNREDIRECT_FULLSCREEN_WINDOWS, }, &unredirect_fullscreen_windows, }, { { "desktop-effects", SCHEMA_MUFFIN, META_PREF_DESKTOP_EFFECTS, }, &desktop_effects, }, { { "threaded-swap", SCHEMA_MUFFIN, META_PREF_THREADED_SWAP, }, &threaded_swap, }, { { "send-frame-timings", SCHEMA_MUFFIN, META_PREF_SEND_FRAME_TIMINGS, }, &send_frame_timings, }, { { "application-based", SCHEMA_GENERAL, META_PREF_APPLICATION_BASED, }, NULL, /* feature is known but disabled */ }, { { "disable-workarounds", SCHEMA_GENERAL, META_PREF_DISABLE_WORKAROUNDS, }, &disable_workarounds, }, { { "auto-raise", SCHEMA_GENERAL, META_PREF_AUTO_RAISE, }, &auto_raise, }, { { KEY_MOUSEWHEEL_ZOOM_ENABLED, SCHEMA_A11Y_APPLICATIONS, META_PREF_MOUSE_ZOOM_ENABLED, }, &mouse_zoom_enabled, }, { { KEY_GNOME_ANIMATIONS, SCHEMA_INTERFACE, META_PREF_GNOME_ANIMATIONS, }, &gnome_animations, }, { { "resize-with-right-button", SCHEMA_GENERAL, META_PREF_RESIZE_WITH_RIGHT_BUTTON, }, &resize_with_right_button, }, { { "edge-tiling", SCHEMA_MUFFIN, META_PREF_EDGE_TILING, }, &edge_tiling, }, { { "edge-resistance-window", SCHEMA_MUFFIN, META_PREF_EDGE_RESISTANCE_WINDOW, }, &edge_resistance_window, }, { { "workspaces-only-on-primary", SCHEMA_MUFFIN, META_PREF_WORKSPACES_ONLY_ON_PRIMARY, }, &workspaces_only_on_primary, }, { { "legacy-snap", SCHEMA_MUFFIN, META_PREF_LEGACY_SNAP, }, &legacy_snap, }, { { "invert-workspace-flip-direction", SCHEMA_MUFFIN, META_PREF_INVERT_WORKSPACE_FLIP_DIRECTION, }, &invert_workspace_flip, }, { { "tile-maximize", SCHEMA_MUFFIN, META_PREF_TILE_MAXIMIZE, }, &tile_maximize, }, { { NULL, 0, 0 }, NULL }, }; static MetaStringPreference preferences_string[] = { { { "mouse-button-modifier", SCHEMA_GENERAL, META_PREF_MOUSE_BUTTON_MODS, }, mouse_button_mods_handler, NULL, }, { { "mouse-button-zoom-modifier", SCHEMA_GENERAL, META_PREF_MOUSE_BUTTON_ZOOM_MODS, }, mouse_button_zoom_mods_handler, NULL, }, { { "theme", SCHEMA_GENERAL, META_PREF_THEME, }, theme_name_handler, NULL, }, { { KEY_TITLEBAR_FONT, SCHEMA_GENERAL, META_PREF_TITLEBAR_FONT, }, titlebar_handler, NULL, }, { { "button-layout", SCHEMA_GENERAL, META_PREF_BUTTON_LAYOUT, }, button_layout_handler, NULL, }, { { "cursor-theme", SCHEMA_INTERFACE, META_PREF_CURSOR_THEME, }, NULL, &cursor_theme, }, { { "snap-modifier", SCHEMA_MUFFIN, META_PREF_SNAP_MODIFIER, }, snap_modifier_handler, NULL, }, { { NULL, 0, 0 }, NULL }, }; static MetaIntPreference preferences_int[] = { { { KEY_NUM_WORKSPACES, SCHEMA_GENERAL, META_PREF_NUM_WORKSPACES, }, &num_workspaces }, { { "auto-raise-delay", SCHEMA_GENERAL, META_PREF_AUTO_RAISE_DELAY, }, &auto_raise_delay }, { { "cursor-size", SCHEMA_INTERFACE, META_PREF_CURSOR_SIZE, }, &cursor_size }, { { "draggable-border-width", SCHEMA_MUFFIN, META_PREF_DRAGGABLE_BORDER_WIDTH, }, &draggable_border_width }, { { "tile-hud-threshold", SCHEMA_MUFFIN, META_PREF_TILE_HUD_THRESHOLD, }, &tile_hud_threshold }, { { "resize-threshold", SCHEMA_MUFFIN, META_PREF_RESIZE_THRESHOLD, }, &resize_threshold }, { { NULL, 0, 0 }, NULL }, }; /* * This is used to keep track of override schemas used to * override preferences from the "normal" metacity/muffin * schemas; we modify the preferences arrays directly, but * we also need to remember what we have done to handle * subsequent overrides correctly. */ typedef struct { char *key; char *new_schema; } MetaPrefsOverriddenKey; static GSList *overridden_keys; static void handle_preference_init_enum (void) { MetaEnumPreference *cursor = preferences_enum; while (cursor->base.key != NULL) { if (cursor->target==NULL) continue; *((gint *) cursor->target) = g_settings_get_enum (SETTINGS (cursor->base.schema), cursor->base.key); ++cursor; } } static void handle_preference_init_bool (void) { MetaBoolPreference *cursor = preferences_bool; while (cursor->base.key != NULL) { if (cursor->target!=NULL) *cursor->target = g_settings_get_boolean (SETTINGS (cursor->base.schema), cursor->base.key); ++cursor; } maybe_give_disable_workarounds_warning (); } static void handle_preference_init_string (void) { MetaStringPreference *cursor = preferences_string; while (cursor->base.key != NULL) { char *value; /* Complex keys have a mapping function to check validity */ if (cursor->handler) { if (cursor->target) meta_bug ("%s has both a target and a handler\n", cursor->base.key); g_settings_get_mapped (SETTINGS (cursor->base.schema), cursor->base.key, cursor->handler, NULL); } else { if (!cursor->target) meta_bug ("%s must have handler or target\n", cursor->base.key); free (*(cursor->target)); value = g_settings_get_string (SETTINGS (cursor->base.schema), cursor->base.key); *(cursor->target) = value; } ++cursor; } } static void handle_preference_init_int (void) { MetaIntPreference *cursor = preferences_int; while (cursor->base.key != NULL) { if (cursor->target) *cursor->target = g_settings_get_int (SETTINGS (cursor->base.schema), cursor->base.key); ++cursor; } } static void handle_preference_update_enum (GSettings *settings, gchar *key) { MetaEnumPreference *cursor = preferences_enum; gint old_value; while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0) ++cursor; if (cursor->base.key == NULL) /* Didn't recognise that key. */ return; /* We need to know whether the value changes, so * store the current value away. */ old_value = * ((gint *)cursor->target); *((gint *)cursor->target) = g_settings_get_enum (SETTINGS (cursor->base.schema), key); /* Did it change? If so, tell the listeners about it. */ if (old_value != *((gint *)cursor->target)) queue_changed (cursor->base.pref); } static void handle_preference_update_bool (GSettings *settings, gchar *key) { MetaBoolPreference *cursor = preferences_bool; gboolean old_value; while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0) ++cursor; if (cursor->base.key == NULL || cursor->target == NULL) /* Unknown key or no work for us to do. */ return; /* We need to know whether the value changes, so * store the current value away. */ old_value = *((gboolean *) cursor->target); /* Now look it up... */ *((gboolean *) cursor->target) = g_settings_get_boolean (SETTINGS (cursor->base.schema), key); /* Did it change? If so, tell the listeners about it. */ if (old_value != *((gboolean *)cursor->target)) queue_changed (cursor->base.pref); if (cursor->base.pref==META_PREF_DISABLE_WORKAROUNDS) maybe_give_disable_workarounds_warning (); } static void handle_preference_update_string (GSettings *settings, gchar *key) { MetaStringPreference *cursor = preferences_string; char *value; gboolean inform_listeners = FALSE; while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0) ++cursor; if (cursor->base.key==NULL) /* Didn't recognise that key. */ return; /* Complex keys have a mapping function to check validity */ if (cursor->handler) { if (cursor->target) meta_bug ("%s has both a target and a handler\n", cursor->base.key); g_settings_get_mapped (SETTINGS (cursor->base.schema), cursor->base.key, cursor->handler, NULL); } else { if (!cursor->target) meta_bug ("%s must have handler or target\n", cursor->base.key); value = g_settings_get_string (SETTINGS (cursor->base.schema), cursor->base.key); inform_listeners = (g_strcmp0 (value, *(cursor->target)) != 0); free(*(cursor->target)); *(cursor->target) = value; } if (inform_listeners) queue_changed (cursor->base.pref); } static void handle_preference_update_int (GSettings *settings, gchar *key) { MetaIntPreference *cursor = preferences_int; gint new_value; while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0) ++cursor; if (cursor->base.key == NULL || cursor->target == NULL) /* Unknown key or no work for us to do. */ return; new_value = g_settings_get_int (SETTINGS (cursor->base.schema), key); /* Did it change? If so, tell the listeners about it. */ if (*cursor->target != new_value) { *cursor->target = new_value; queue_changed (cursor->base.pref); } } /****************************************************************************/ /* Listeners. */ /****************************************************************************/ /** * meta_prefs_add_listener: (skip) * */ void meta_prefs_add_listener (MetaPrefsChangedFunc func, gpointer data) { MetaPrefsListener *l; l = g_new (MetaPrefsListener, 1); l->func = func; l->data = data; listeners = g_list_prepend (listeners, l); } /** * meta_prefs_remove_listener: (skip) * */ void meta_prefs_remove_listener (MetaPrefsChangedFunc func, gpointer data) { GList *tmp; tmp = listeners; while (tmp != NULL) { MetaPrefsListener *l = tmp->data; if (l->func == func && l->data == data) { free (l); listeners = g_list_delete_link (listeners, tmp); return; } tmp = tmp->next; } meta_bug ("Did not find listener to remove\n"); } static void emit_changed (MetaPreference pref) { GList *tmp; GList *copy; meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n", meta_preference_to_string (pref)); copy = g_list_copy (listeners); tmp = copy; while (tmp != NULL) { MetaPrefsListener *l = tmp->data; (* l->func) (pref, l->data); tmp = tmp->next; } g_list_free (copy); } static gboolean changed_idle_handler (gpointer data) { GList *tmp; GList *copy; changed_idle = 0; copy = g_list_copy (changes); /* reentrancy paranoia */ g_list_free (changes); changes = NULL; tmp = copy; while (tmp != NULL) { MetaPreference pref = GPOINTER_TO_INT (tmp->data); emit_changed (pref); tmp = tmp->next; } g_list_free (copy); return FALSE; } static void queue_changed (MetaPreference pref) { meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n", meta_preference_to_string (pref)); if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL) changes = g_list_prepend (changes, GINT_TO_POINTER (pref)); #ifdef WITH_VERBOSE_MODE else meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n", meta_preference_to_string (pref)); #endif if (changed_idle == 0) changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY, changed_idle_handler, NULL, NULL); } static void store_initial_ui_scale (void) { GValue value = G_VALUE_INIT; g_value_init (&value, G_TYPE_INT); gdk_screen_get_setting (gdk_screen_get_default (), "gdk-window-scaling-factor", &value); ui_scale = MAX (g_value_get_int (&value), 1); // Never let it be 0; } static void set_ui_scale (int new_scale) { if (new_scale == ui_scale) { return; } ui_scale = new_scale; meta_topic (META_DEBUG_PREFS, "UI Scale changed (to %dx), triggering frames and cursor size updates.\n", ui_scale); queue_changed (META_PREF_UI_SCALE); } /****************************************************************************/ /* Initialisation. */ /****************************************************************************/ void meta_prefs_init (void) { GSettings *settings; GSList *tmp; settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal, free, g_object_unref); settings = g_settings_new (SCHEMA_GENERAL); g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL); g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_GENERAL), settings); settings = g_settings_new (SCHEMA_MUFFIN); g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL); g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_MUFFIN), settings); /* Individual keys we watch outside of our schemas */ settings = g_settings_new (SCHEMA_INTERFACE); g_signal_connect (settings, "changed::" KEY_GNOME_ANIMATIONS, G_CALLBACK (settings_changed), NULL); g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_THEME, G_CALLBACK (settings_changed), NULL); g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_SIZE, G_CALLBACK (settings_changed), NULL); g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings); settings = g_settings_new (SCHEMA_A11Y_APPLICATIONS); g_signal_connect (settings, "changed::" KEY_MOUSEWHEEL_ZOOM_ENABLED, G_CALLBACK (settings_changed), NULL); g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_A11Y_APPLICATIONS), settings); settings = g_settings_new (SCHEMA_CINNAMON); g_signal_connect (settings, "changed::" KEY_BRING_ACTIVATED_WINDOWS_TO_CURRENT_WORKSPACE, G_CALLBACK (settings_changed), NULL); g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_CINNAMON), settings); for (tmp = overridden_keys; tmp; tmp = tmp->next) { MetaPrefsOverriddenKey *override = tmp->data; do_override (override->key, override->new_schema); } /* Pick up initial values. */ handle_preference_init_enum (); handle_preference_init_bool (); handle_preference_init_string (); handle_preference_init_int (); store_initial_ui_scale (); init_bindings (); init_workspace_names (); update_min_win_opacity (); } static gboolean find_pref (void *prefs, size_t pref_size, const char *search_key, MetaBasePreference **pref) { void *p = prefs; while (TRUE) { char **key = p; if (*key == NULL) break; if (strcmp (*key, search_key) == 0) { *pref = p; return TRUE; } p = (guchar *)p + pref_size; } return FALSE; } static void do_override (char *key, char *schema) { MetaBasePreference *pref; GSettings *settings; char *detailed_signal; gpointer data; guint handler_id; g_return_if_fail (settings_schemas != NULL); if (!find_pref (preferences_enum, sizeof(MetaEnumPreference), key, &pref) && !find_pref (preferences_bool, sizeof(MetaBoolPreference), key, &pref) && !find_pref (preferences_string, sizeof(MetaStringPreference), key, &pref) && !find_pref (preferences_int, sizeof(MetaIntPreference), key, &pref)) { meta_warning ("Can't override preference key, \"%s\" not found\n", key); return; } settings = SETTINGS (pref->schema); data = g_object_get_data (G_OBJECT (settings), key); if (data) { handler_id = GPOINTER_TO_UINT (data); g_signal_handler_disconnect (settings, handler_id); } pref->schema = schema; settings = SETTINGS (pref->schema); if (!settings) { settings = g_settings_new (pref->schema); g_hash_table_insert (settings_schemas, g_strdup (pref->schema), settings); } detailed_signal = g_strdup_printf ("changed::%s", key); handler_id = g_signal_connect (settings, detailed_signal, G_CALLBACK (settings_changed), NULL); free (detailed_signal); g_object_set_data (G_OBJECT (settings), key, GUINT_TO_POINTER (handler_id)); settings_changed (settings, key, NULL); } /** * meta_prefs_override_preference_schema: * @key: the preference name * @schema: new schema for preference %key * * Specify a schema whose keys are used to override the standard Metacity * keys. This might be used if a plugin expected a different value for * some preference than the Metacity default. While this function can be * called at any point, this function should generally be called in a * plugin's constructor, rather than in its start() method so the preference * isn't first loaded with one value then changed to another value. */ void meta_prefs_override_preference_schema (const char *key, const char *schema) { MetaPrefsOverriddenKey *overridden; GSList *tmp; /* Merge identical overrides, this isn't an error */ for (tmp = overridden_keys; tmp; tmp = tmp->next) { MetaPrefsOverriddenKey *tmp_overridden = tmp->data; if (strcmp (tmp_overridden->key, key) == 0 && strcmp (tmp_overridden->new_schema, schema) == 0) return; } overridden = NULL; for (tmp = overridden_keys; tmp; tmp = tmp->next) { MetaPrefsOverriddenKey *tmp_overridden = tmp->data; if (strcmp (tmp_overridden->key, key) == 0) overridden = tmp_overridden; } if (overridden) { free (overridden->new_schema); overridden->new_schema = g_strdup (schema); } else { overridden = g_slice_new (MetaPrefsOverriddenKey); overridden->key = g_strdup (key); overridden->new_schema = g_strdup (schema); overridden_keys = g_slist_prepend (overridden_keys, overridden); } if (settings_schemas != NULL) do_override (overridden->key, overridden->new_schema); } /****************************************************************************/ /* Updates. */ /****************************************************************************/ static void settings_changed (GSettings *settings, gchar *key, gpointer data) { GVariant *value; const GVariantType *type; MetaEnumPreference *cursor; gboolean found_enum; gchar *schema; g_object_get(settings, "schema", &schema, NULL); /* String array, handled separately */ if (strcmp (key, KEY_WORKSPACE_NAMES) == 0) { if (update_workspace_names ()) queue_changed (META_PREF_WORKSPACE_NAMES); return; } if (strcmp (key, KEY_MIN_WINDOW_OPACITY) == 0) { update_min_win_opacity (); queue_changed (META_PREF_MIN_WIN_OPACITY); return; } value = g_settings_get_value (settings, key); type = g_variant_get_type (value); if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) handle_preference_update_bool (settings, key); else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32)) handle_preference_update_int (settings, key); else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)) { cursor = preferences_enum; found_enum = FALSE; while (cursor->base.key != NULL) { if (strcmp (key, cursor->base.key) == 0) found_enum = TRUE; cursor++; } if (found_enum) handle_preference_update_enum (settings, key); else handle_preference_update_string (settings, key); } else if (g_str_equal (key, KEY_WS_NAMES_GNOME)) { return; } else { /* Someone added a preference of an unhandled type */ g_assert_not_reached (); } g_variant_unref (value); } static void bindings_changed (GSettings *settings, gchar *key, gpointer data) { gchar **strokes; strokes = g_settings_get_strv (settings, key); if (update_key_binding (key, strokes)) queue_changed (META_PREF_KEYBINDINGS); g_strfreev (strokes); } /* * Special case: give a warning the first time disable_workarounds * is turned on. */ static void maybe_give_disable_workarounds_warning (void) { static gboolean first_disable = TRUE; if (first_disable && disable_workarounds) { first_disable = FALSE; meta_warning ("Workarounds for broken applications disabled. " "Some applications may not behave properly.\n"); } } MetaVirtualModifier meta_prefs_get_mouse_button_mods (void) { return mouse_button_mods; } MetaVirtualModifier meta_prefs_get_mouse_button_zoom_mods (void) { return mouse_button_zoom_mods; } gboolean meta_prefs_get_mouse_zoom_enabled (void) { return mouse_zoom_enabled; } CDesktopFocusMode meta_prefs_get_focus_mode (void) { return focus_mode; } CDesktopFocusNewWindows meta_prefs_get_focus_new_windows (void) { return focus_new_windows; } gboolean meta_prefs_get_attach_modal_dialogs (void) { return attach_modal_dialogs; } gboolean meta_prefs_get_ignore_hide_titlebar_when_maximized (void) { return ignore_hide_titlebar_when_maximized; } gboolean meta_prefs_get_raise_on_click (void) { /* Force raise_on_click on for click-to-focus, as requested by Havoc * in #326156. */ return raise_on_click || focus_mode == C_DESKTOP_FOCUS_MODE_CLICK; } gboolean meta_prefs_get_bring_windows_to_current_workspace (void) { /* Windows that the user activates (with a current timestamp) will * be brought to the currently active workspace if necessary. Normally * the user is brought to the window's workspace instead. */ return bring_user_activated_windows_to_current_workspace; } const char* meta_prefs_get_theme (void) { return current_theme; } const char* meta_prefs_get_cursor_theme (void) { return cursor_theme; } int meta_prefs_get_cursor_size (void) { return cursor_size * ui_scale; } /****************************************************************************/ /* Handlers for string preferences. */ /****************************************************************************/ static gboolean titlebar_handler (GVariant *value, gpointer *result, gpointer data) { PangoFontDescription *desc; const gchar *string_value; *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); desc = pango_font_description_from_string (string_value); if (desc == NULL) { meta_warning ("Could not parse font description " "\"%s\" from GSettings key %s\n", string_value ? string_value : "(null)", KEY_TITLEBAR_FONT); return FALSE; } /* Is the new description the same as the old? */ if (titlebar_font && pango_font_description_equal (desc, titlebar_font)) { pango_font_description_free (desc); } else { if (titlebar_font) pango_font_description_free (titlebar_font); titlebar_font = desc; queue_changed (META_PREF_TITLEBAR_FONT); } return TRUE; } static gboolean theme_name_handler (GVariant *value, gpointer *result, gpointer data) { const gchar *string_value; *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); if (!string_value || !*string_value) return FALSE; if (g_strcmp0 (current_theme, string_value) != 0) { free (current_theme); current_theme = g_strdup (string_value); queue_changed (META_PREF_THEME); } return TRUE; } static gboolean mouse_button_mods_handler (GVariant *value, gpointer *result, gpointer data) { MetaVirtualModifier mods; const gchar *string_value; *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); if (!string_value || !meta_ui_parse_modifier (string_value, &mods)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse new GSettings value\n"); meta_warning ("\"%s\" found in configuration database is " "not a valid value for mouse button modifier\n", string_value); return FALSE; } meta_topic (META_DEBUG_KEYBINDINGS, "Mouse button modifier has new GSettings value \"%s\"\n", string_value); if (mods != mouse_button_mods) { mouse_button_mods = mods; queue_changed (META_PREF_MOUSE_BUTTON_MODS); } return TRUE; } static gboolean mouse_button_zoom_mods_handler (GVariant *value, gpointer *result, gpointer data) { MetaVirtualModifier mods; const gchar *string_value; *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); if (!string_value || !meta_ui_parse_modifier (string_value, &mods)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse new GSettings value\n"); meta_warning ("\"%s\" found in configuration database is " "not a valid value for mouse button zoom modifier\n", string_value); return FALSE; } meta_topic (META_DEBUG_KEYBINDINGS, "Mouse zoom modifier has new GSettings value \"%s\"\n", string_value); if (mods != mouse_button_zoom_mods) { mouse_button_zoom_mods = mods; queue_changed (META_PREF_MOUSE_BUTTON_ZOOM_MODS); } return TRUE; } static gboolean snap_modifier_handler (GVariant *value, gpointer *result, gpointer data) { const gchar *string_value; *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); if (g_strcmp0 (string_value, "Super") == 0) { snap_modifier[0] = XStringToKeysym("Super_L"); snap_modifier[1] = XStringToKeysym("Super_R"); } else if (g_strcmp0 (string_value, "Alt") == 0) { snap_modifier[0] = XStringToKeysym("Alt_L"); snap_modifier[1] = XStringToKeysym("Alt_R"); } else if (g_strcmp0 (string_value, "Shift") == 0) { snap_modifier[0] = XStringToKeysym("Shift_L"); snap_modifier[1] = XStringToKeysym("Shift_R"); } else if (g_strcmp0 (string_value, "Control") == 0) { snap_modifier[0] = XStringToKeysym("Control_L"); snap_modifier[1] = XStringToKeysym("Control_R"); } else { snap_modifier[0] = 0; snap_modifier[1] = 0; } return TRUE; } static gboolean button_layout_equal (const MetaButtonLayout *a, const MetaButtonLayout *b) { int i; i = 0; while (i < MAX_BUTTONS_PER_CORNER) { if (a->left_buttons[i] != b->left_buttons[i]) return FALSE; if (a->right_buttons[i] != b->right_buttons[i]) return FALSE; if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i]) return FALSE; if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i]) return FALSE; ++i; } return TRUE; } /* * This conversion cannot be handled by GSettings since * several values are stored in the same key (as a string). */ static MetaButtonFunction button_function_from_string (const char *str) { if (strcmp (str, "menu") == 0) return META_BUTTON_FUNCTION_MENU; else if (strcmp (str, "minimize") == 0) return META_BUTTON_FUNCTION_MINIMIZE; else if (strcmp (str, "maximize") == 0) return META_BUTTON_FUNCTION_MAXIMIZE; else if (strcmp (str, "close") == 0) return META_BUTTON_FUNCTION_CLOSE; else if (strcmp (str, "shade") == 0) return META_BUTTON_FUNCTION_SHADE; else if (strcmp (str, "above") == 0) return META_BUTTON_FUNCTION_ABOVE; else if (strcmp (str, "stick") == 0) return META_BUTTON_FUNCTION_STICK; else /* don't know; give up */ return META_BUTTON_FUNCTION_LAST; } static MetaButtonFunction button_opposite_function (MetaButtonFunction ofwhat) { switch (ofwhat) { case META_BUTTON_FUNCTION_SHADE: return META_BUTTON_FUNCTION_UNSHADE; case META_BUTTON_FUNCTION_UNSHADE: return META_BUTTON_FUNCTION_SHADE; case META_BUTTON_FUNCTION_ABOVE: return META_BUTTON_FUNCTION_UNABOVE; case META_BUTTON_FUNCTION_UNABOVE: return META_BUTTON_FUNCTION_ABOVE; case META_BUTTON_FUNCTION_STICK: return META_BUTTON_FUNCTION_UNSTICK; case META_BUTTON_FUNCTION_UNSTICK: return META_BUTTON_FUNCTION_STICK; default: return META_BUTTON_FUNCTION_LAST; } } static gboolean button_layout_handler (GVariant *value, gpointer *result, gpointer data) { MetaButtonLayout new_layout; const gchar *string_value; char **sides = NULL; int i; /* We need to ignore unknown button functions, for * compat with future versions */ *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); if (string_value) sides = g_strsplit (string_value, ":", 2); i = 0; if (sides != NULL && sides[0] != NULL) { char **buttons; int b; gboolean used[META_BUTTON_FUNCTION_LAST]; while (i < META_BUTTON_FUNCTION_LAST) { used[i] = FALSE; new_layout.left_buttons_has_spacer[i] = FALSE; ++i; } buttons = g_strsplit (sides[0], ",", -1); i = 0; b = 0; while (buttons[b] != NULL) { MetaButtonFunction f = button_function_from_string (buttons[b]); if (i > 0 && strcmp("spacer", buttons[b]) == 0) { new_layout.left_buttons_has_spacer[i-1] = TRUE; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) { new_layout.left_buttons_has_spacer[i-2] = TRUE; } } else { if (f != META_BUTTON_FUNCTION_LAST && !used[f]) { new_layout.left_buttons[i] = f; used[f] = TRUE; ++i; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) new_layout.left_buttons[i++] = f; } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n", buttons[b]); } #endif } ++b; } g_strfreev (buttons); } for (; i < MAX_BUTTONS_PER_CORNER; i++) { new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST; new_layout.left_buttons_has_spacer[i] = FALSE; } i = 0; if (sides != NULL && sides[0] != NULL && sides[1] != NULL) { char **buttons; int b; gboolean used[META_BUTTON_FUNCTION_LAST]; while (i < META_BUTTON_FUNCTION_LAST) { used[i] = FALSE; new_layout.right_buttons_has_spacer[i] = FALSE; ++i; } buttons = g_strsplit (sides[1], ",", -1); i = 0; b = 0; while (buttons[b] != NULL) { MetaButtonFunction f = button_function_from_string (buttons[b]); if (i > 0 && strcmp("spacer", buttons[b]) == 0) { new_layout.right_buttons_has_spacer[i-1] = TRUE; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) { new_layout.right_buttons_has_spacer[i-2] = TRUE; } } else { if (f != META_BUTTON_FUNCTION_LAST && !used[f]) { new_layout.right_buttons[i] = f; used[f] = TRUE; ++i; f = button_opposite_function (f); if (f != META_BUTTON_FUNCTION_LAST) new_layout.right_buttons[i++] = f; } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n", buttons[b]); } #endif } ++b; } g_strfreev (buttons); } for (; i < MAX_BUTTONS_PER_CORNER; i++) { new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST; new_layout.right_buttons_has_spacer[i] = FALSE; } g_strfreev (sides); /* Invert the button layout for RTL languages */ if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) { MetaButtonLayout rtl_layout; int j; for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++); for (j = 0; j < i; j++) { rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1]; if (j == 0) rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1]; else rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1]; } rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST; rtl_layout.right_buttons_has_spacer[j] = FALSE; for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++); for (j = 0; j < i; j++) { rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1]; if (j == 0) rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1]; else rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1]; } rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST; rtl_layout.left_buttons_has_spacer[j] = FALSE; new_layout = rtl_layout; } if (!button_layout_equal (&button_layout, &new_layout)) { button_layout = new_layout; emit_changed (META_PREF_BUTTON_LAYOUT); } return TRUE; } const PangoFontDescription* meta_prefs_get_titlebar_font (void) { if (use_system_font) return NULL; else return titlebar_font; } int meta_prefs_get_num_workspaces (void) { return num_workspaces; } gboolean meta_prefs_get_workspace_cycle (void) { return workspace_cycle; } gboolean meta_prefs_get_dynamic_workspaces (void) { return dynamic_workspaces; } gboolean meta_prefs_get_unredirect_fullscreen_windows (void) { return unredirect_fullscreen_windows; } gboolean meta_prefs_get_desktop_effects (void) { return desktop_effects; } MetaSyncMethod meta_prefs_get_sync_method (void) { return sync_method; } gboolean meta_prefs_get_threaded_swap (void) { return threaded_swap; } gboolean meta_prefs_get_send_frame_timings (void) { return send_frame_timings; } gboolean meta_prefs_get_application_based (void) { return FALSE; /* For now, we never want this to do anything */ return application_based; } gboolean meta_prefs_get_disable_workarounds (void) { return disable_workarounds; } #ifdef WITH_VERBOSE_MODE const char* meta_preference_to_string (MetaPreference pref) { /* TODO: better handled via GLib enum nicknames */ switch (pref) { case META_PREF_MOUSE_BUTTON_MODS: return "MOUSE_BUTTON_MODS"; case META_PREF_MOUSE_BUTTON_ZOOM_MODS: return "MOUSE_BUTTON_ZOOM_MODS"; case META_PREF_MOUSE_ZOOM_ENABLED: return "MOUSE_ZOOM_ENABLED"; case META_PREF_FOCUS_MODE: return "FOCUS_MODE"; case META_PREF_FOCUS_NEW_WINDOWS: return "FOCUS_NEW_WINDOWS"; case META_PREF_ATTACH_MODAL_DIALOGS: return "ATTACH_MODAL_DIALOGS"; case META_PREF_RAISE_ON_CLICK: return "RAISE_ON_CLICK"; case META_PREF_THEME: return "THEME"; case META_PREF_TITLEBAR_FONT: return "TITLEBAR_FONT"; case META_PREF_NUM_WORKSPACES: return "NUM_WORKSPACES"; case META_PREF_APPLICATION_BASED: return "APPLICATION_BASED"; case META_PREF_KEYBINDINGS: return "KEYBINDINGS"; case META_PREF_DISABLE_WORKAROUNDS: return "DISABLE_WORKAROUNDS"; case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR: return "ACTION_DOUBLE_CLICK_TITLEBAR"; case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR: return "ACTION_MIDDLE_CLICK_TITLEBAR"; case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR: return "ACTION_RIGHT_CLICK_TITLEBAR"; case META_PREF_ACTION_SCROLL_WHEEL_TITLEBAR: return "ACTION_SCROLL_WHEEL_TITLEBAR"; case META_PREF_AUTO_RAISE: return "AUTO_RAISE"; case META_PREF_AUTO_RAISE_DELAY: return "AUTO_RAISE_DELAY"; case META_PREF_BUTTON_LAYOUT: return "BUTTON_LAYOUT"; case META_PREF_WORKSPACE_NAMES: return "WORKSPACE_NAMES"; case META_PREF_GNOME_ANIMATIONS: return "GNOME_ANIMATIONS"; case META_PREF_CURSOR_THEME: return "CURSOR_THEME"; case META_PREF_CURSOR_SIZE: return "CURSOR_SIZE"; case META_PREF_RESIZE_WITH_RIGHT_BUTTON: return "RESIZE_WITH_RIGHT_BUTTON"; case META_PREF_EDGE_TILING: return "EDGE_TILING"; case META_PREF_EDGE_RESISTANCE_WINDOW: return "EDGE_RESISTANCE_WINDOW"; case META_PREF_FORCE_FULLSCREEN: return "FORCE_FULLSCREEN"; case META_PREF_WORKSPACES_ONLY_ON_PRIMARY: return "WORKSPACES_ONLY_ON_PRIMARY"; case META_PREF_WORKSPACE_CYCLE: return "WORKSPACE_CYCLE"; case META_PREF_VISUAL_BELL: return "VISUAL_BELL"; case META_PREF_AUDIBLE_BELL: return "AUDIBLE_BELL"; case META_PREF_VISUAL_BELL_TYPE: return "VISUAL_BELL_TYPE"; case META_PREF_DRAGGABLE_BORDER_WIDTH: return "DRAGGABLE_BORDER_WIDTH"; case META_PREF_TILE_HUD_THRESHOLD: return "TILE_HUD_THRESHOLD"; case META_PREF_RESIZE_THRESHOLD: return "RESIZE_THRESHOLD"; case META_PREF_DYNAMIC_WORKSPACES: return "DYNAMIC_WORKSPACES"; case META_PREF_UNREDIRECT_FULLSCREEN_WINDOWS: return "UNREDIRECT_FULLSCREEN_WINDOWS"; case META_PREF_SYNC_METHOD: return "SYNC_METHOD"; case META_PREF_THREADED_SWAP: return "THREADED_SWAP"; case META_PREF_SEND_FRAME_TIMINGS: return "SEND_FRAME_TIMINGS"; case META_PREF_SNAP_MODIFIER: return "SNAP_MODIFIER"; case META_PREF_LEGACY_SNAP: return "LEGACY_SNAP"; case META_PREF_INVERT_WORKSPACE_FLIP_DIRECTION: return "INVERT_WORKSPACE_FLIP_DIRECTION"; case META_PREF_TILE_MAXIMIZE: return "TILE_MAXIMIZE"; case META_PREF_PLACEMENT_MODE: return "PLACEMENT_MODE"; case META_PREF_BACKGROUND_TRANSITION: return "BACKGROUND_TRANSITION"; case META_PREF_MIN_WIN_OPACITY: return "MIN_WIN_OPACITY"; case META_PREF_BRING_WINDOWS_TO_CURRENT_WORKSPACE: return "BRING_WINDOWS_TO_CURRENT_WORKSPACE"; } return "(unknown)"; } #endif /* WITH_VERBOSE_MODE */ void meta_prefs_set_num_workspaces (int n_workspaces) { MetaBasePreference *pref = NULL; find_pref (preferences_int, sizeof(MetaIntPreference), KEY_NUM_WORKSPACES, &pref); g_settings_set_int (SETTINGS (pref->schema), KEY_NUM_WORKSPACES, n_workspaces); } static GHashTable *key_bindings; static void meta_key_pref_free (MetaKeyPref *pref) { update_binding (pref, NULL); free (pref->name); free (pref->schema); free (pref); } static void init_bindings (void) { key_bindings = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify)meta_key_pref_free); } static void init_workspace_names (void) { update_workspace_names (); } static gboolean update_binding (MetaKeyPref *binding, gchar **strokes) { unsigned int keysym; unsigned int keycode; MetaVirtualModifier mods; MetaKeyCombo *combo; int i; meta_topic (META_DEBUG_KEYBINDINGS, "Binding \"%s\" has new GSettings value\n", binding->name); /* Okay, so, we're about to provide a new list of key combos for this * action. Delete any pre-existing list. */ g_slist_foreach (binding->bindings, (GFunc) free, NULL); g_slist_free (binding->bindings); binding->bindings = NULL; for (i = 0; strokes && strokes[i]; i++) { keysym = 0; keycode = 0; mods = 0; if (!meta_ui_parse_accelerator (strokes[i], &keysym, &keycode, &mods)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse new GSettings value\n"); meta_warning ("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n", strokes[i], binding->name); /* Value is kept and will thus be removed next time we save the key. * Changing the key in response to a modification could lead to cyclic calls. */ continue; } /* Bug 329676: Bindings which can be shifted must not have no modifiers, * nor only SHIFT as a modifier. */ if (binding->add_shift && 0 != keysym && (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods)) { meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier " "such as Ctrl or Alt.\n", binding->name, strokes[i]); /* Value is kept and will thus be removed next time we save the key. * Changing the key in response to a modification could lead to cyclic calls. */ continue; } combo = calloc (1, sizeof (MetaKeyCombo)); combo->keysym = keysym; combo->keycode = keycode; combo->modifiers = mods; binding->bindings = g_slist_prepend (binding->bindings, combo); meta_topic (META_DEBUG_KEYBINDINGS, "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n", binding->name, keysym, keycode, mods); } return TRUE; } static gboolean update_key_binding (const char *key, gchar **strokes) { MetaKeyPref *pref = g_hash_table_lookup (key_bindings, key); if (pref) return update_binding (pref, strokes); else return FALSE; } static gboolean update_workspace_names (void) { int i; char **names; int n_workspace_names, n_names; gboolean changed = FALSE; names = g_settings_get_strv (SETTINGS (SCHEMA_GENERAL), KEY_WORKSPACE_NAMES); n_names = g_strv_length (names); n_workspace_names = workspace_names ? g_strv_length (workspace_names) : 0; for (i = 0; i < n_names; i++) if (n_workspace_names < i + 1 || !workspace_names[i] || g_strcmp0 (names[i], workspace_names[i]) != 0) { changed = TRUE; break; } if (n_workspace_names != n_names) changed = TRUE; if (changed) { if (workspace_names) g_strfreev (workspace_names); workspace_names = names; } else g_strfreev (names); return changed; } static void update_min_win_opacity (void) { int pct; int mapped; pct = g_settings_get_int (SETTINGS (SCHEMA_GENERAL), KEY_MIN_WINDOW_OPACITY); mapped = (int)(((double)pct / 100.0) * 255.0); min_window_opacity = CLAMP (mapped, 0, 255); } const char* meta_prefs_get_workspace_name (int i) { const char *name; if (!workspace_names || g_strv_length (workspace_names) < (guint)i + 1 || !*workspace_names[i]) { char *generated_name = g_strdup_printf ("Workspace %d", i + 1); name = g_intern_string (generated_name); free (generated_name); } else name = workspace_names[i]; meta_topic (META_DEBUG_PREFS, "Getting name of workspace %d: \"%s\"\n", i, name); return name; } void meta_prefs_change_workspace_name (int num, const char *name) { GVariantBuilder builder; int n_workspace_names, i; g_return_if_fail (num >= 0); meta_topic (META_DEBUG_PREFS, "Changing name of workspace %d to %s\n", num, name ? name : "none"); /* NULL and empty string both mean "default" here, * and we also need to match the name against its default value * to avoid saving it literally. */ if (g_strcmp0 (name, meta_prefs_get_workspace_name (num)) == 0) { #ifdef WITH_VERBOSE_MODE if (!name || !*name) meta_topic (META_DEBUG_PREFS, "Workspace %d already uses default name\n", num); else meta_topic (META_DEBUG_PREFS, "Workspace %d already has name %s\n", num, name); #endif return; } g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY); n_workspace_names = workspace_names ? g_strv_length (workspace_names) : 0; for (i = 0; i < MAX (num + 1, n_workspace_names); i++) { const char *value; if (i == num) value = name ? name : ""; else if (i < n_workspace_names) value = workspace_names[i] ? workspace_names[i] : ""; else value = ""; g_variant_builder_add (&builder, "s", value); } g_settings_set_value (SETTINGS (SCHEMA_GENERAL), KEY_WORKSPACE_NAMES, g_variant_builder_end (&builder)); } /** * meta_prefs_get_button_layout: * @button_layout_p: (out): the #MetaButtonLayout * * Returns the titlebar button definitions. */ void meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p) { *button_layout_p = button_layout; } LOCAL_SYMBOL gboolean meta_prefs_add_keybinding (const char *name, const char *schema, MetaKeyBindingAction action, MetaKeyBindingFlags flags) { MetaKeyPref *pref; GSettings *settings; char **strokes; if (g_hash_table_lookup (key_bindings, name)) { meta_warning ("Trying to re-add keybinding \"%s\".\n", name); return FALSE; } settings = SETTINGS (schema); if (settings == NULL) { settings = g_settings_new (schema); if ((flags & META_KEY_BINDING_BUILTIN) != 0) g_signal_connect (settings, "changed", G_CALLBACK (bindings_changed), NULL); g_hash_table_insert (settings_schemas, g_strdup (schema), settings); } pref = g_new0 (MetaKeyPref, 1); pref->name = g_strdup (name); pref->schema = g_strdup (schema); pref->action = action; pref->bindings = NULL; pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0; pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0; pref->builtin = (flags & META_KEY_BINDING_BUILTIN) != 0; strokes = g_settings_get_strv (settings, name); update_binding (pref, strokes); g_strfreev (strokes); g_hash_table_insert (key_bindings, g_strdup (name), pref); if (!pref->builtin) { guint id; char *changed_signal = g_strdup_printf ("changed::%s", name); id = g_signal_connect (settings, changed_signal, G_CALLBACK (bindings_changed), NULL); free (changed_signal); g_object_set_data (G_OBJECT (settings), name, GUINT_TO_POINTER (id)); queue_changed (META_PREF_KEYBINDINGS); } return TRUE; } LOCAL_SYMBOL gboolean meta_prefs_remove_keybinding (const char *name) { MetaKeyPref *pref; GSettings *settings; guint id; pref = g_hash_table_lookup (key_bindings, name); if (!pref) { meta_warning ("Trying to remove non-existent keybinding \"%s\".\n", name); return FALSE; } if (pref->builtin) { meta_warning ("Trying to remove builtin keybinding \"%s\".\n", name); return FALSE; } settings = SETTINGS (pref->schema); id = GPOINTER_TO_UINT (g_object_steal_data (G_OBJECT (settings), name)); g_signal_handler_disconnect (settings, id); g_hash_table_remove (key_bindings, name); queue_changed (META_PREF_KEYBINDINGS); return TRUE; } LOCAL_SYMBOL gboolean meta_prefs_add_custom_keybinding (const char *name, const char **bindings, MetaKeyBindingAction action, MetaKeyBindingFlags flags) { MetaKeyPref *pref; if (g_hash_table_lookup (key_bindings, name)) { meta_warning ("Trying to re-add custom keybinding \"%s\".\n", name); return FALSE; } pref = g_new0 (MetaKeyPref, 1); pref->name = g_strdup (name); pref->schema = NULL; pref->action = action; pref->bindings = NULL; pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0; pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0; pref->builtin = (flags & META_KEY_BINDING_BUILTIN) != 0; update_binding (pref, (gchar **)bindings); g_hash_table_insert (key_bindings, g_strdup (name), pref); return TRUE; } LOCAL_SYMBOL gboolean meta_prefs_remove_custom_keybinding (const char *name) { MetaKeyPref *pref; pref = g_hash_table_lookup (key_bindings, name); if (!pref) { meta_warning ("Trying to remove non-existent custom keybinding \"%s\".\n", name); return FALSE; } g_hash_table_remove (key_bindings, name); queue_changed (META_PREF_KEYBINDINGS); return TRUE; } /** * meta_prefs_get_keybindings: * * Returns: (element-type MetaKeyPref) (transfer container): */ GList * meta_prefs_get_keybindings () { return g_hash_table_get_values (key_bindings); } CDesktopTitlebarAction meta_prefs_get_action_double_click_titlebar (void) { return action_double_click_titlebar; } CDesktopTitlebarAction meta_prefs_get_action_middle_click_titlebar (void) { return action_middle_click_titlebar; } CDesktopTitlebarAction meta_prefs_get_action_right_click_titlebar (void) { return action_right_click_titlebar; } CDesktopTitlebarScrollAction meta_prefs_get_action_scroll_wheel_titlebar (void) { return action_scroll_titlebar; } gboolean meta_prefs_get_auto_raise (void) { return auto_raise; } int meta_prefs_get_auto_raise_delay (void) { return auto_raise_delay; } gboolean meta_prefs_get_gnome_animations () { return gnome_animations; } gboolean meta_prefs_get_edge_tiling () { return edge_tiling; } gboolean meta_prefs_get_edge_resistance_window () { return edge_resistance_window; } MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name) { MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name); return pref ? pref->action : META_KEYBINDING_ACTION_NONE; } /* This is used by the menu system to decide what key binding * to display next to an option. We return the first non-disabled * binding, if any. */ void meta_prefs_get_window_binding (const char *name, unsigned int *keysym, MetaVirtualModifier *modifiers) { MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name); if (pref->per_window) { GSList *s = pref->bindings; while (s) { MetaKeyCombo *c = s->data; if (c->keysym != 0 || c->modifiers != 0) { *keysym = c->keysym; *modifiers = c->modifiers; return; } s = s->next; } /* Not found; return the disabled value */ *keysym = *modifiers = 0; return; } g_assert_not_reached (); } guint meta_prefs_get_mouse_button_resize (void) { return resize_with_right_button ? 3: 2; } guint meta_prefs_get_mouse_button_menu (void) { return resize_with_right_button ? 2: 3; } gboolean meta_prefs_get_force_fullscreen (void) { return force_fullscreen; } gboolean meta_prefs_get_workspaces_only_on_primary (void) { return workspaces_only_on_primary; } gboolean meta_prefs_get_legacy_snap (void) { return legacy_snap; } int meta_prefs_get_draggable_border_width (void) { return draggable_border_width * ui_scale; } int meta_prefs_get_tile_hud_threshold (void) { return tile_hud_threshold * ui_scale; } int meta_prefs_get_resize_threshold (void) { return resize_threshold * ui_scale; } void meta_prefs_set_force_fullscreen (gboolean whether) { force_fullscreen = whether; } unsigned int * meta_prefs_get_snap_modifier (void) { return snap_modifier; } gboolean meta_prefs_get_invert_flip_direction (void) { return invert_workspace_flip; } gboolean meta_prefs_get_tile_maximize (void) { return tile_maximize; } MetaPlacementMode meta_prefs_get_placement_mode (void) { return placement_mode; } MetaBackgroundTransition meta_prefs_get_background_transition (void) { return background_transition; } gint meta_prefs_get_min_win_opacity (void) { return min_window_opacity; } gint meta_prefs_get_ui_scale (void) { return ui_scale; } void meta_prefs_set_ui_scale (int new_scale) { set_ui_scale (new_scale); }�������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/session.c���������������������������������������������������������������������0000664�0001750�0001750�00000143051�14211404421�016506� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin Session Management */ /* * Copyright (C) 2001 Havoc Pennington (some code in here from * libgnomeui, (C) Tom Tromey, Carsten Schaar) * Copyright (C) 2004, 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "util-private.h" #include "session.h" #include <X11/Xatom.h> #include <time.h> #include <sys/wait.h> #ifndef HAVE_SM LOCAL_SYMBOL void meta_session_init (const char *client_id, const char *save_file) { meta_topic (META_DEBUG_SM, "Compiled without session management support\n"); } LOCAL_SYMBOL const MetaWindowSessionInfo* meta_window_lookup_saved_state (MetaWindow *window) { return NULL; } LOCAL_SYMBOL void meta_window_release_saved_state (const MetaWindowSessionInfo *info) { ; } #else /* HAVE_SM */ #include <X11/ICE/ICElib.h> #include <X11/SM/SMlib.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <errno.h> #include <glib.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <meta/main.h> #include <meta/util.h> #include "display-private.h" #include <meta/workspace.h> static void ice_io_error_handler (IceConn connection); static void new_ice_connection (IceConn connection, IcePointer client_data, Bool opening, IcePointer *watch_data); static void save_state (void); static char* load_state (const char *previous_save_file); static void regenerate_save_file (void); static const char* full_save_file (void); static void warn_about_lame_clients_and_finish_interact (gboolean shutdown); static void disconnect (void); /* This is called when data is available on an ICE connection. */ static gboolean process_ice_messages (GIOChannel *channel, GIOCondition condition, gpointer client_data) { IceConn connection = (IceConn) client_data; IceProcessMessagesStatus status; /* This blocks infinitely sometimes. I don't know what * to do about it. Checking "condition" just breaks * session management. */ status = IceProcessMessages (connection, NULL, NULL); if (status == IceProcessMessagesIOError) { #if 0 IcePointer context = IceGetConnectionContext (connection); #endif /* We were disconnected; close our connection to the * session manager, this will result in the ICE connection * being cleaned up, since it is owned by libSM. */ disconnect (); meta_quit (META_EXIT_SUCCESS); return FALSE; } return TRUE; } /* This is called when a new ICE connection is made. It arranges for the ICE connection to be handled via the event loop. */ static void new_ice_connection (IceConn connection, IcePointer client_data, Bool opening, IcePointer *watch_data) { guint input_id; if (opening) { /* Make sure we don't pass on these file descriptors to any * exec'ed children */ GIOChannel *channel; fcntl (IceConnectionNumber (connection), F_SETFD, fcntl (IceConnectionNumber (connection), F_GETFD, 0) | FD_CLOEXEC); channel = g_io_channel_unix_new (IceConnectionNumber (connection)); input_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR, process_ice_messages, connection); g_io_channel_unref (channel); *watch_data = (IcePointer) GUINT_TO_POINTER (input_id); } else { input_id = GPOINTER_TO_UINT ((gpointer) *watch_data); if (input_id) { g_source_remove (input_id); } } } static IceIOErrorHandler ice_installed_handler; /* We call any handler installed before (or after) gnome_ice_init but avoid calling the default libICE handler which does an exit() */ static void ice_io_error_handler (IceConn connection) { if (ice_installed_handler) (*ice_installed_handler) (connection); } static void ice_init (void) { static gboolean ice_initted = FALSE; if (! ice_initted) { IceIOErrorHandler default_handler; ice_installed_handler = IceSetIOErrorHandler (NULL); default_handler = IceSetIOErrorHandler (ice_io_error_handler); if (ice_installed_handler == default_handler) ice_installed_handler = NULL; IceAddConnectionWatch (new_ice_connection, NULL); ice_initted = TRUE; } } typedef enum { STATE_DISCONNECTED, STATE_IDLE, STATE_SAVING_PHASE_1, STATE_WAITING_FOR_PHASE_2, STATE_SAVING_PHASE_2, STATE_WAITING_FOR_INTERACT, STATE_DONE_WITH_INTERACT, STATE_SKIPPING_GLOBAL_SAVE, STATE_FROZEN, STATE_REGISTERING } ClientState; static void save_phase_2_callback (SmcConn smc_conn, SmPointer client_data); static void interact_callback (SmcConn smc_conn, SmPointer client_data); static void shutdown_cancelled_callback (SmcConn smc_conn, SmPointer client_data); static void save_complete_callback (SmcConn smc_conn, SmPointer client_data); static void die_callback (SmcConn smc_conn, SmPointer client_data); static void save_yourself_callback (SmcConn smc_conn, SmPointer client_data, int save_style, Bool shutdown, int interact_style, Bool fast); static void set_clone_restart_commands (void); static char *client_id = NULL; static gpointer session_connection = NULL; static ClientState current_state = STATE_DISCONNECTED; static gboolean interaction_allowed = FALSE; LOCAL_SYMBOL void meta_session_init (const char *previous_client_id, const char *previous_save_file) { /* Some code here from twm */ char buf[256]; unsigned long mask; SmcCallbacks callbacks; char *saved_client_id; meta_topic (META_DEBUG_SM, "Initializing session with save file '%s'\n", previous_save_file ? previous_save_file : "(none)"); if (previous_save_file) { saved_client_id = load_state (previous_save_file); previous_client_id = saved_client_id; } else if (previous_client_id) { char *save_file = g_strconcat (previous_client_id, ".ms", NULL); saved_client_id = load_state (save_file); free (save_file); } else { saved_client_id = NULL; } ice_init (); mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; callbacks.save_yourself.callback = save_yourself_callback; callbacks.save_yourself.client_data = NULL; callbacks.die.callback = die_callback; callbacks.die.client_data = NULL; callbacks.save_complete.callback = save_complete_callback; callbacks.save_complete.client_data = NULL; callbacks.shutdown_cancelled.callback = shutdown_cancelled_callback; callbacks.shutdown_cancelled.client_data = NULL; session_connection = SmcOpenConnection (NULL, /* use SESSION_MANAGER env */ NULL, /* means use existing ICE connection */ SmProtoMajor, SmProtoMinor, mask, &callbacks, (char*) previous_client_id, &client_id, 255, buf); if (session_connection == NULL) { meta_topic (META_DEBUG_SM, "Failed to a open connection to a session manager, so window positions will not be saved: %s\n", buf); goto out; } else { if (client_id == NULL) meta_bug ("Session manager gave us a NULL client ID?"); meta_topic (META_DEBUG_SM, "Obtained session ID '%s'\n", client_id); } if (previous_client_id && strcmp (previous_client_id, client_id) == 0) current_state = STATE_IDLE; else current_state = STATE_REGISTERING; { SmProp prop1, prop2, prop3, prop4, prop5, prop6, *props[6]; SmPropValue prop1val, prop2val, prop3val, prop4val, prop5val, prop6val; char pid[32]; /* Historically, this was SmRestartImmediately, which made sense * for a stateless window manager, but we don't really control * what embedders do, and it's all around better if gnome-session * handles this. */ char hint = SmRestartIfRunning; char priority = 20; /* low to run before other apps */ const char *prgname; prgname = g_get_prgname (); prop1.name = SmProgram; prop1.type = SmARRAY8; prop1.num_vals = 1; prop1.vals = &prop1val; prop1val.value = (char *)prgname; prop1val.length = strlen (prgname); /* twm sets getuid() for this, but the SM spec plainly * says pw_name, twm is on crack */ prop2.name = SmUserID; prop2.type = SmARRAY8; prop2.num_vals = 1; prop2.vals = &prop2val; prop2val.value = (char*) g_get_user_name (); prop2val.length = strlen (prop2val.value); prop3.name = SmRestartStyleHint; prop3.type = SmCARD8; prop3.num_vals = 1; prop3.vals = &prop3val; prop3val.value = &hint; prop3val.length = 1; sprintf (pid, "%d", getpid ()); prop4.name = SmProcessID; prop4.type = SmARRAY8; prop4.num_vals = 1; prop4.vals = &prop4val; prop4val.value = pid; prop4val.length = strlen (prop4val.value); /* Always start in home directory */ prop5.name = SmCurrentDirectory; prop5.type = SmARRAY8; prop5.num_vals = 1; prop5.vals = &prop5val; prop5val.value = (char*) g_get_home_dir (); prop5val.length = strlen (prop5val.value); prop6.name = "_GSM_Priority"; prop6.type = SmCARD8; prop6.num_vals = 1; prop6.vals = &prop6val; prop6val.value = &priority; prop6val.length = 1; props[0] = &prop1; props[1] = &prop2; props[2] = &prop3; props[3] = &prop4; props[4] = &prop5; props[5] = &prop6; SmcSetProperties (session_connection, 6, props); } out: free (saved_client_id); } static void disconnect (void) { SmcCloseConnection (session_connection, 0, NULL); session_connection = NULL; current_state = STATE_DISCONNECTED; } static void save_yourself_possibly_done (gboolean shutdown, gboolean successful) { meta_topic (META_DEBUG_SM, "save possibly done shutdown = %d success = %d\n", shutdown, successful); if (current_state == STATE_SAVING_PHASE_1) { Status status; status = SmcRequestSaveYourselfPhase2 (session_connection, save_phase_2_callback, GINT_TO_POINTER (shutdown)); if (status) current_state = STATE_WAITING_FOR_PHASE_2; meta_topic (META_DEBUG_SM, "Requested phase 2, status = %d\n", status); } if (current_state == STATE_SAVING_PHASE_2 && interaction_allowed) { Status status; status = SmcInteractRequest (session_connection, /* ignore this feature of the protocol by always * claiming normal */ SmDialogNormal, interact_callback, GINT_TO_POINTER (shutdown)); if (status) current_state = STATE_WAITING_FOR_INTERACT; meta_topic (META_DEBUG_SM, "Requested interact, status = %d\n", status); } if (current_state == STATE_SAVING_PHASE_1 || current_state == STATE_SAVING_PHASE_2 || current_state == STATE_DONE_WITH_INTERACT || current_state == STATE_SKIPPING_GLOBAL_SAVE) { meta_topic (META_DEBUG_SM, "Sending SaveYourselfDone\n"); SmcSaveYourselfDone (session_connection, successful); if (shutdown) current_state = STATE_FROZEN; else current_state = STATE_IDLE; } } static void save_phase_2_callback (SmcConn smc_conn, SmPointer client_data) { gboolean shutdown; meta_topic (META_DEBUG_SM, "Phase 2 save"); shutdown = GPOINTER_TO_INT (client_data); current_state = STATE_SAVING_PHASE_2; save_state (); save_yourself_possibly_done (shutdown, TRUE); } static void save_yourself_callback (SmcConn smc_conn, SmPointer client_data, int save_style, Bool shutdown, int interact_style, Bool fast) { gboolean successful; meta_topic (META_DEBUG_SM, "SaveYourself received"); successful = TRUE; /* The first SaveYourself after registering for the first time * is a special case (SM specs 7.2). */ #if 0 /* I think the GnomeClient rationale for this doesn't apply */ if (current_state == STATE_REGISTERING) { current_state = STATE_IDLE; /* Double check that this is a section 7.2 SaveYourself: */ if (save_style == SmSaveLocal && interact_style == SmInteractStyleNone && !shutdown && !fast) { /* The protocol requires this even if xsm ignores it. */ SmcSaveYourselfDone (session_connection, successful); return; } } #endif /* ignore Global style saves * * This interpretaion of the Local/Global/Both styles * was discussed extensively on the xdg-list. See: * * https://listman.redhat.com/pipermail/xdg-list/2002-July/000615.html */ if (save_style == SmSaveGlobal) { current_state = STATE_SKIPPING_GLOBAL_SAVE; save_yourself_possibly_done (shutdown, successful); return; } interaction_allowed = interact_style != SmInteractStyleNone; current_state = STATE_SAVING_PHASE_1; regenerate_save_file (); set_clone_restart_commands (); save_yourself_possibly_done (shutdown, successful); } static void die_callback (SmcConn smc_conn, SmPointer client_data) { meta_topic (META_DEBUG_SM, "Disconnecting from session manager"); disconnect (); /* We don't actually exit here - we will simply go away with the X * server on logout, when we lose the X connection and libx11 kills * us. It looks like *crap* on logout if the user sees their * windows lose the decorations, etc. * * Anything that wants us to go away outside of session management * can use kill(). */ } static void save_complete_callback (SmcConn smc_conn, SmPointer client_data) { /* nothing */ meta_topic (META_DEBUG_SM, "SaveComplete received\n"); } static void shutdown_cancelled_callback (SmcConn smc_conn, SmPointer client_data) { meta_topic (META_DEBUG_SM, "Shutdown cancelled received\n"); if (session_connection != NULL && (current_state != STATE_IDLE && current_state != STATE_FROZEN)) { SmcSaveYourselfDone (session_connection, True); current_state = STATE_IDLE; } } static void interact_callback (SmcConn smc_conn, SmPointer client_data) { /* nothing */ gboolean shutdown; meta_topic (META_DEBUG_SM, "Interaction permission received\n"); shutdown = GPOINTER_TO_INT (client_data); current_state = STATE_DONE_WITH_INTERACT; warn_about_lame_clients_and_finish_interact (shutdown); } static void set_clone_restart_commands (void) { char *restartv[10]; char *clonev[10]; char *discardv[10]; int i; SmProp prop1, prop2, prop3, *props[3]; const char *prgname; prgname = g_get_prgname (); /* Restart (use same client ID) */ prop1.name = SmRestartCommand; prop1.type = SmLISTofARRAY8; g_return_if_fail (client_id); i = 0; restartv[i] = (char *)prgname; ++i; restartv[i] = "--sm-client-id"; ++i; restartv[i] = client_id; ++i; restartv[i] = NULL; prop1.vals = g_new (SmPropValue, i); i = 0; while (restartv[i]) { prop1.vals[i].value = restartv[i]; prop1.vals[i].length = strlen (restartv[i]); ++i; } prop1.num_vals = i; /* Clone (no client ID) */ i = 0; clonev[i] = (char *)prgname; ++i; clonev[i] = NULL; prop2.name = SmCloneCommand; prop2.type = SmLISTofARRAY8; prop2.vals = g_new (SmPropValue, i); i = 0; while (clonev[i]) { prop2.vals[i].value = clonev[i]; prop2.vals[i].length = strlen (clonev[i]); ++i; } prop2.num_vals = i; /* Discard */ i = 0; discardv[i] = "rm"; ++i; discardv[i] = "-f"; ++i; discardv[i] = (char*) full_save_file (); ++i; discardv[i] = NULL; prop3.name = SmDiscardCommand; prop3.type = SmLISTofARRAY8; prop3.vals = g_new (SmPropValue, i); i = 0; while (discardv[i]) { prop3.vals[i].value = discardv[i]; prop3.vals[i].length = strlen (discardv[i]); ++i; } prop3.num_vals = i; props[0] = &prop1; props[1] = &prop2; props[2] = &prop3; SmcSetProperties (session_connection, 3, props); free (prop1.vals); free (prop2.vals); free (prop3.vals); } /* The remaining code in this file actually loads/saves the session, * while the code above this comment handles chatting with the * session manager. */ static const char* window_type_to_string (MetaWindowType type) { switch (type) { case META_WINDOW_NORMAL: return "normal"; case META_WINDOW_DESKTOP: return "desktop"; case META_WINDOW_DOCK: return "dock"; case META_WINDOW_DIALOG: return "dialog"; case META_WINDOW_MODAL_DIALOG: return "modal_dialog"; case META_WINDOW_TOOLBAR: return "toolbar"; case META_WINDOW_MENU: return "menu"; case META_WINDOW_SPLASHSCREEN: return "splashscreen"; case META_WINDOW_UTILITY: return "utility"; case META_WINDOW_DROPDOWN_MENU: return "dropdown_menu"; case META_WINDOW_POPUP_MENU: return "popup_menu"; case META_WINDOW_TOOLTIP: return "tooltip"; case META_WINDOW_NOTIFICATION: return "notification"; case META_WINDOW_COMBO: return "combo"; case META_WINDOW_DND: return "dnd"; case META_WINDOW_OVERRIDE_OTHER: return "override_redirect"; } return ""; } static MetaWindowType window_type_from_string (const char *str) { if (strcmp (str, "normal") == 0) return META_WINDOW_NORMAL; else if (strcmp (str, "desktop") == 0) return META_WINDOW_DESKTOP; else if (strcmp (str, "dock") == 0) return META_WINDOW_DOCK; else if (strcmp (str, "dialog") == 0) return META_WINDOW_DIALOG; else if (strcmp (str, "modal_dialog") == 0) return META_WINDOW_MODAL_DIALOG; else if (strcmp (str, "toolbar") == 0) return META_WINDOW_TOOLBAR; else if (strcmp (str, "menu") == 0) return META_WINDOW_MENU; else if (strcmp (str, "utility") == 0) return META_WINDOW_UTILITY; else if (strcmp (str, "splashscreen") == 0) return META_WINDOW_SPLASHSCREEN; else return META_WINDOW_NORMAL; } static int window_gravity_from_string (const char *str) { if (strcmp (str, "NorthWestGravity") == 0) return NorthWestGravity; else if (strcmp (str, "NorthGravity") == 0) return NorthGravity; else if (strcmp (str, "NorthEastGravity") == 0) return NorthEastGravity; else if (strcmp (str, "WestGravity") == 0) return WestGravity; else if (strcmp (str, "CenterGravity") == 0) return CenterGravity; else if (strcmp (str, "EastGravity") == 0) return EastGravity; else if (strcmp (str, "SouthWestGravity") == 0) return SouthWestGravity; else if (strcmp (str, "SouthGravity") == 0) return SouthGravity; else if (strcmp (str, "SouthEastGravity") == 0) return SouthEastGravity; else if (strcmp (str, "StaticGravity") == 0) return StaticGravity; else return NorthWestGravity; } static char* encode_text_as_utf8_markup (const char *text) { /* text can be any encoding, and is nul-terminated. * we pretend it's Latin-1 and encode as UTF-8 */ GString *str; const char *p; char *escaped; str = g_string_new (""); p = text; while (*p) { g_string_append_unichar (str, *p); ++p; } escaped = g_markup_escape_text (str->str, str->len); g_string_free (str, TRUE); return escaped; } static char* decode_text_from_utf8 (const char *text) { /* Convert back from the encoded (but not escaped) UTF-8 */ GString *str; const char *p; str = g_string_new (""); p = text; while (*p) { /* obviously this barfs if the UTF-8 contains chars > 255 */ g_string_append_c (str, g_utf8_get_char (p)); p = g_utf8_next_char (p); } return g_string_free (str, FALSE); } static void save_state (void) { char *muffin_dir; char *session_dir; FILE *outfile; GSList *windows; GSList *tmp; int stack_position; g_assert (client_id); outfile = NULL; /* * g_get_user_config_dir() is guaranteed to return an existing directory. * Eventually, if SM stays with the WM, I'd like to make this * something like <config>/window_placement in a standard format. * Future optimisers should note also that by the time we get here * we probably already have full_save_path figured out and therefore * can just use the directory name from that. */ muffin_dir = g_strconcat (g_get_user_config_dir (), G_DIR_SEPARATOR_S "muffin", NULL); session_dir = g_strconcat (muffin_dir, G_DIR_SEPARATOR_S "sessions", NULL); if (mkdir (muffin_dir, 0700) < 0 && errno != EEXIST) { meta_warning ("Could not create directory '%s': %s\n", muffin_dir, g_strerror (errno)); } if (mkdir (session_dir, 0700) < 0 && errno != EEXIST) { meta_warning ("Could not create directory '%s': %s\n", session_dir, g_strerror (errno)); } meta_topic (META_DEBUG_SM, "Saving session to '%s'\n", full_save_file ()); outfile = fopen (full_save_file (), "w"); if (outfile == NULL) { meta_warning ("Could not open session file '%s' for writing: %s\n", full_save_file (), g_strerror (errno)); goto out; } /* The file format is: * <muffin_session id="foo"> * <window id="bar" class="XTerm" name="xterm" title="/foo/bar" role="blah" type="normal" stacking="5"> * <workspace index="2"/> * <workspace index="4"/> * <sticky/> <minimized/> <maximized/> * <geometry x="100" y="100" width="200" height="200" gravity="northwest"/> * </window> * </muffin_session> * * Note that attributes on <window> are the match info we use to * see if the saved state applies to a restored window, and * child elements are the saved state to be applied. * */ fprintf (outfile, "<muffin_session id=\"%s\">\n", client_id); windows = meta_display_list_windows (meta_get_display (), META_LIST_DEFAULT); windows = g_slist_sort (windows, meta_display_stack_cmp); tmp = windows; stack_position = 0; while (tmp != NULL) { MetaWindow *window; window = tmp->data; if (window->sm_client_id) { char *sm_client_id; char *res_class; char *res_name; char *role; char *title; /* client id, class, name, role are not expected to be * in UTF-8 (I think they are in XPCS which is Latin-1? * in practice they are always ascii though.) */ sm_client_id = encode_text_as_utf8_markup (window->sm_client_id); res_class = window->res_class ? encode_text_as_utf8_markup (window->res_class) : NULL; res_name = window->res_name ? encode_text_as_utf8_markup (window->res_name) : NULL; role = window->role ? encode_text_as_utf8_markup (window->role) : NULL; if (window->title) title = g_markup_escape_text (window->title, -1); else title = NULL; meta_topic (META_DEBUG_SM, "Saving session managed window %s, client ID '%s'\n", window->desc, window->sm_client_id); fprintf (outfile, " <window id=\"%s\" class=\"%s\" name=\"%s\" title=\"%s\" role=\"%s\" type=\"%s\" stacking=\"%d\">\n", sm_client_id, res_class ? res_class : "", res_name ? res_name : "", title ? title : "", role ? role : "", window_type_to_string (window->type), stack_position); free (sm_client_id); free (res_class); free (res_name); free (role); free (title); /* Sticky */ if (window->on_all_workspaces_requested) fputs (" <sticky/>\n", outfile); /* Minimized */ if (window->minimized) fputs (" <minimized/>\n", outfile); /* Maximized */ if (META_WINDOW_MAXIMIZED (window)) { fprintf (outfile, " <maximized saved_x=\"%d\" saved_y=\"%d\" saved_width=\"%d\" saved_height=\"%d\"/>\n", window->saved_rect.x, window->saved_rect.y, window->saved_rect.width, window->saved_rect.height); } /* Workspaces we're on */ { int n; n = meta_workspace_index (window->workspace); fprintf (outfile, " <workspace index=\"%d\"/>\n", n); } /* Gravity */ { int x, y, w, h; meta_window_get_geometry (window, &x, &y, &w, &h); fprintf (outfile, " <geometry x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" gravity=\"%s\"/>\n", x, y, w, h, meta_gravity_to_string (window->size_hints.win_gravity)); } fputs (" </window>\n", outfile); } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_SM, "Not saving window '%s', not session managed\n", window->desc); } #endif tmp = tmp->next; ++stack_position; } g_slist_free (windows); fputs ("</muffin_session>\n", outfile); out: if (outfile) { /* FIXME need a dialog for this */ if (ferror (outfile)) { meta_warning ("Error writing session file '%s': %s\n", full_save_file (), g_strerror (errno)); } if (fclose (outfile)) { meta_warning ("Error closing session file '%s': %s\n", full_save_file (), g_strerror (errno)); } } free (muffin_dir); free (session_dir); } typedef enum { WINDOW_TAG_NONE, WINDOW_TAC_DESKTOP, WINDOW_TAG_STICKY, WINDOW_TAG_MINIMIZED, WINDOW_TAG_MAXIMIZED, WINDOW_TAG_GEOMETRY } WindowTag; typedef struct { MetaWindowSessionInfo *info; char *previous_id; } ParseData; static void session_info_free (MetaWindowSessionInfo *info); static MetaWindowSessionInfo* session_info_new (void); static void start_element_handler (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error); static void end_element_handler (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error); static void text_handler (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error); static GMarkupParser muffin_session_parser = { start_element_handler, end_element_handler, text_handler, NULL, NULL }; static GSList *window_info_list = NULL; static char* load_state (const char *previous_save_file) { GMarkupParseContext *context; GError *error; ParseData parse_data; char *text; gsize length; char *session_file; session_file = g_strconcat (g_get_user_config_dir (), G_DIR_SEPARATOR_S "muffin" G_DIR_SEPARATOR_S "sessions" G_DIR_SEPARATOR_S, previous_save_file, NULL); error = NULL; if (!g_file_get_contents (session_file, &text, &length, &error)) { char *canonical_session_file = session_file; /* Maybe they were doing it the old way, with ~/.muffin */ session_file = g_strconcat (g_get_home_dir (), G_DIR_SEPARATOR_S ".muffin" G_DIR_SEPARATOR_S "sessions" G_DIR_SEPARATOR_S, previous_save_file, NULL); if (!g_file_get_contents (session_file, &text, &length, NULL)) { /* oh, just give up */ g_error_free (error); free (session_file); free (canonical_session_file); return NULL; } free (canonical_session_file); } meta_topic (META_DEBUG_SM, "Parsing saved session file %s\n", session_file); free (session_file); session_file = NULL; parse_data.info = NULL; parse_data.previous_id = NULL; context = g_markup_parse_context_new (&muffin_session_parser, 0, &parse_data, NULL); error = NULL; if (!g_markup_parse_context_parse (context, text, length, &error)) goto error; error = NULL; if (!g_markup_parse_context_end_parse (context, &error)) goto error; g_markup_parse_context_free (context); goto out; error: meta_warning ("Failed to parse saved session file: %s\n", error->message); g_error_free (error); if (parse_data.info) session_info_free (parse_data.info); free (parse_data.previous_id); parse_data.previous_id = NULL; out: free (text); return parse_data.previous_id; } /* FIXME this isn't very robust against bogus session files */ static void start_element_handler (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { ParseData *pd; pd = user_data; if (strcmp (element_name, "muffin_session") == 0) { /* Get previous ID */ int i; i = 0; while (attribute_names[i]) { const char *name; const char *val; name = attribute_names[i]; val = attribute_values[i]; if (pd->previous_id) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "<muffin_session> attribute seen but we already have the session ID"); return; } if (strcmp (name, "id") == 0) { pd->previous_id = decode_text_from_utf8 (val); } else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute %s on <%s> element", name, "muffin_session"); return; } ++i; } } else if (strcmp (element_name, "window") == 0) { int i; if (pd->info) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "nested <window> tag"); return; } pd->info = session_info_new (); i = 0; while (attribute_names[i]) { const char *name; const char *val; name = attribute_names[i]; val = attribute_values[i]; if (strcmp (name, "id") == 0) { if (*val) pd->info->id = decode_text_from_utf8 (val); } else if (strcmp (name, "class") == 0) { if (*val) pd->info->res_class = decode_text_from_utf8 (val); } else if (strcmp (name, "name") == 0) { if (*val) pd->info->res_name = decode_text_from_utf8 (val); } else if (strcmp (name, "title") == 0) { if (*val) pd->info->title = g_strdup (val); } else if (strcmp (name, "role") == 0) { if (*val) pd->info->role = decode_text_from_utf8 (val); } else if (strcmp (name, "type") == 0) { if (*val) pd->info->type = window_type_from_string (val); } else if (strcmp (name, "stacking") == 0) { if (*val) { pd->info->stack_position = atoi (val); pd->info->stack_position_set = TRUE; } } else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute %s on <%s> element", name, "window"); session_info_free (pd->info); pd->info = NULL; return; } ++i; } } else if (strcmp (element_name, "workspace") == 0) { int i; i = 0; while (attribute_names[i]) { const char *name; name = attribute_names[i]; if (strcmp (name, "index") == 0) { pd->info->workspace_indices = g_slist_prepend (pd->info->workspace_indices, GINT_TO_POINTER (atoi (attribute_values[i]))); } else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute %s on <%s> element", name, "window"); session_info_free (pd->info); pd->info = NULL; return; } ++i; } } else if (strcmp (element_name, "sticky") == 0) { pd->info->on_all_workspaces = TRUE; pd->info->on_all_workspaces_set = TRUE; } else if (strcmp (element_name, "minimized") == 0) { pd->info->minimized = TRUE; pd->info->minimized_set = TRUE; } else if (strcmp (element_name, "maximized") == 0) { int i; i = 0; pd->info->maximized = TRUE; pd->info->maximized_set = TRUE; while (attribute_names[i]) { const char *name; const char *val; name = attribute_names[i]; val = attribute_values[i]; if (strcmp (name, "saved_x") == 0) { if (*val) { pd->info->saved_rect.x = atoi (val); pd->info->saved_rect_set = TRUE; } } else if (strcmp (name, "saved_y") == 0) { if (*val) { pd->info->saved_rect.y = atoi (val); pd->info->saved_rect_set = TRUE; } } else if (strcmp (name, "saved_width") == 0) { if (*val) { pd->info->saved_rect.width = atoi (val); pd->info->saved_rect_set = TRUE; } } else if (strcmp (name, "saved_height") == 0) { if (*val) { pd->info->saved_rect.height = atoi (val); pd->info->saved_rect_set = TRUE; } } else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute %s on <%s> element", name, "maximized"); return; } ++i; } #ifdef WITH_VERBOSE_MODE if (pd->info->saved_rect_set) meta_topic (META_DEBUG_SM, "Saved unmaximized size %d,%d %dx%d \n", pd->info->saved_rect.x, pd->info->saved_rect.y, pd->info->saved_rect.width, pd->info->saved_rect.height); #endif } else if (strcmp (element_name, "geometry") == 0) { int i; pd->info->geometry_set = TRUE; i = 0; while (attribute_names[i]) { const char *name; const char *val; name = attribute_names[i]; val = attribute_values[i]; if (strcmp (name, "x") == 0) { if (*val) pd->info->rect.x = atoi (val); } else if (strcmp (name, "y") == 0) { if (*val) pd->info->rect.y = atoi (val); } else if (strcmp (name, "width") == 0) { if (*val) pd->info->rect.width = atoi (val); } else if (strcmp (name, "height") == 0) { if (*val) pd->info->rect.height = atoi (val); } else if (strcmp (name, "gravity") == 0) { if (*val) pd->info->gravity = window_gravity_from_string (val); } else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute %s on <%s> element", name, "geometry"); return; } ++i; } meta_topic (META_DEBUG_SM, "Loaded geometry %d,%d %dx%d gravity %s\n", pd->info->rect.x, pd->info->rect.y, pd->info->rect.width, pd->info->rect.height, meta_gravity_to_string (pd->info->gravity)); } else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, "Unknown element %s", element_name); return; } } static void end_element_handler (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) { ParseData *pd; pd = user_data; if (strcmp (element_name, "window") == 0) { g_assert (pd->info); window_info_list = g_slist_prepend (window_info_list, pd->info); meta_topic (META_DEBUG_SM, "Loaded window info from session with class: %s name: %s role: %s\n", pd->info->res_class ? pd->info->res_class : "(none)", pd->info->res_name ? pd->info->res_name : "(none)", pd->info->role ? pd->info->role : "(none)"); pd->info = NULL; } } static void text_handler (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error) { /* Right now we don't have any elements where we care about their * content */ } static gboolean both_null_or_matching (const char *a, const char *b) { if (a == NULL && b == NULL) return TRUE; else if (a && b && strcmp (a, b) == 0) return TRUE; else return FALSE; } static GSList* get_possible_matches (MetaWindow *window) { /* Get all windows with this client ID */ GSList *retval; GSList *tmp; gboolean ignore_client_id; retval = NULL; ignore_client_id = g_getenv ("MUFFIN_DEBUG_SM") != NULL; tmp = window_info_list; while (tmp != NULL) { MetaWindowSessionInfo *info; info = tmp->data; if ((ignore_client_id || both_null_or_matching (info->id, window->sm_client_id)) && both_null_or_matching (info->res_class, window->res_class) && both_null_or_matching (info->res_name, window->res_name) && both_null_or_matching (info->role, window->role)) { meta_topic (META_DEBUG_SM, "Window %s may match saved window with class: %s name: %s role: %s\n", window->desc, info->res_class ? info->res_class : "(none)", info->res_name ? info->res_name : "(none)", info->role ? info->role : "(none)"); retval = g_slist_prepend (retval, info); } else { if (meta_is_verbose ()) { if (!both_null_or_matching (info->id, window->sm_client_id)) meta_topic (META_DEBUG_SM, "Window %s has SM client ID %s, saved state has %s, no match\n", window->desc, window->sm_client_id ? window->sm_client_id : "(none)", info->id ? info->id : "(none)"); else if (!both_null_or_matching (info->res_class, window->res_class)) meta_topic (META_DEBUG_SM, "Window %s has class %s doesn't match saved class %s, no match\n", window->desc, window->res_class ? window->res_class : "(none)", info->res_class ? info->res_class : "(none)"); else if (!both_null_or_matching (info->res_name, window->res_name)) meta_topic (META_DEBUG_SM, "Window %s has name %s doesn't match saved name %s, no match\n", window->desc, window->res_name ? window->res_name : "(none)", info->res_name ? info->res_name : "(none)"); else if (!both_null_or_matching (info->role, window->role)) meta_topic (META_DEBUG_SM, "Window %s has role %s doesn't match saved role %s, no match\n", window->desc, window->role ? window->role : "(none)", info->role ? info->role : "(none)"); else meta_topic (META_DEBUG_SM, "???? should not happen - window %s doesn't match saved state %s for no good reason\n", window->desc, info->id); } } tmp = tmp->next; } return retval; } static const MetaWindowSessionInfo* find_best_match (GSList *infos, MetaWindow *window) { GSList *tmp; const MetaWindowSessionInfo *matching_title; const MetaWindowSessionInfo *matching_type; matching_title = NULL; matching_type = NULL; tmp = infos; while (tmp != NULL) { MetaWindowSessionInfo *info; info = tmp->data; if (matching_title == NULL && both_null_or_matching (info->title, window->title)) matching_title = info; if (matching_type == NULL && info->type == window->type) matching_type = info; tmp = tmp->next; } /* Prefer same title, then same type of window, then * just pick something. Eventually we could enhance this * to e.g. break ties by geometry hint similarity, * or other window features. */ if (matching_title) return matching_title; else if (matching_type) return matching_type; else return infos->data; } LOCAL_SYMBOL const MetaWindowSessionInfo* meta_window_lookup_saved_state (MetaWindow *window) { GSList *possibles; const MetaWindowSessionInfo *info; /* Window is not session managed. * I haven't yet figured out how to deal with these * in a way that doesn't cause broken side effects in * situations other than on session restore. */ if (window->sm_client_id == NULL) { meta_topic (META_DEBUG_SM, "Window %s is not session managed, not checking for saved state\n", window->desc); return NULL; } possibles = get_possible_matches (window); if (possibles == NULL) { meta_topic (META_DEBUG_SM, "Window %s has no possible matches in the list of saved window states\n", window->desc); return NULL; } info = find_best_match (possibles, window); g_slist_free (possibles); return info; } LOCAL_SYMBOL void meta_window_release_saved_state (const MetaWindowSessionInfo *info) { /* We don't want to use the same saved state again for another * window. */ window_info_list = g_slist_remove (window_info_list, info); session_info_free ((MetaWindowSessionInfo*) info); } static void session_info_free (MetaWindowSessionInfo *info) { free (info->id); free (info->res_class); free (info->res_name); free (info->title); free (info->role); g_slist_free (info->workspace_indices); free (info); } static MetaWindowSessionInfo* session_info_new (void) { MetaWindowSessionInfo *info; info = g_new0 (MetaWindowSessionInfo, 1); info->type = META_WINDOW_NORMAL; info->gravity = NorthWestGravity; return info; } static char* full_save_path = NULL; static void regenerate_save_file (void) { free (full_save_path); if (client_id) full_save_path = g_strconcat (g_get_user_config_dir (), G_DIR_SEPARATOR_S "muffin" G_DIR_SEPARATOR_S "sessions" G_DIR_SEPARATOR_S, client_id, ".ms", NULL); else full_save_path = NULL; } static const char* full_save_file (void) { return full_save_path; } static int windows_cmp_by_title (MetaWindow *a, MetaWindow *b) { return g_utf8_collate (a->title, b->title); } static void finish_interact (gboolean shutdown) { if (current_state == STATE_DONE_WITH_INTERACT) /* paranoia */ { SmcInteractDone (session_connection, False /* don't cancel logout */); save_yourself_possibly_done (shutdown, TRUE); } } static void dialog_closed (GPid pid, int status, gpointer user_data) { gboolean shutdown = GPOINTER_TO_INT (user_data); if (WIFEXITED (status) && WEXITSTATUS (status) == 0) /* pressed "OK" */ { finish_interact (shutdown); } } static void warn_about_lame_clients_and_finish_interact (gboolean shutdown) { GSList *lame = NULL; GSList *windows; GSList *lame_details = NULL; GSList *tmp; GSList *columns = NULL; GPid pid; windows = meta_display_list_windows (meta_get_display (), META_LIST_DEFAULT); tmp = windows; while (tmp != NULL) { MetaWindow *window; window = tmp->data; /* only complain about normal windows, the others * are kind of dumb to worry about */ if (window->sm_client_id == NULL && window->type == META_WINDOW_NORMAL) lame = g_slist_prepend (lame, window); tmp = tmp->next; } g_slist_free (windows); if (lame == NULL) { /* No lame apps. */ finish_interact (shutdown); return; } columns = g_slist_prepend (columns, "Window"); columns = g_slist_prepend (columns, "Class"); lame = g_slist_sort (lame, (GCompareFunc) windows_cmp_by_title); tmp = lame; while (tmp != NULL) { MetaWindow *w = tmp->data; lame_details = g_slist_prepend (lame_details, w->res_class ? w->res_class : ""); lame_details = g_slist_prepend (lame_details, w->title); tmp = tmp->next; } g_slist_free (lame); pid = meta_show_dialog("--list", "These windows do not support "save current setup" " "and will have to be restarted manually next time " "you log in.", "240", meta_get_display()->active_screen->screen_name, NULL, NULL, None, columns, lame_details); g_slist_free (lame_details); g_child_watch_add (pid, dialog_closed, GINT_TO_POINTER (shutdown)); } #endif /* HAVE_SM */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/above-tab-keycode.c�����������������������������������������������������������0000664�0001750�0001750�00000017347�14211404421�020314� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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 Muffin 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 Muffin 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 = §ion->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 */ LOCAL_SYMBOL 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; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/screen.c����������������������������������������������������������������������0000664�0001750�0001750�00000330457�14211404421�016312� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2001, 2002 Havoc Pennington * Copyright (C) 2002, 2003 Red Hat Inc. * Some ICCCM manager selection code derived from fvwm2, * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:screen * @title: MetaScreen * @short_description: Muffin X screen handler */ #include <config.h> #include "screen-private.h" #include <meta/main.h> #include "util-private.h" #include <meta/errors.h> #include "window-private.h" #include "frame.h" #include <meta/prefs.h> #include "workspace-private.h" #include "keybindings-private.h" #include "stack.h" #include "xprops.h" #include <meta/compositor.h> #include "muffin-enum-types.h" #ifdef HAVE_SOLARIS_XINERAMA #include <X11/extensions/xinerama.h> #endif #ifdef HAVE_XFREE_XINERAMA #include <X11/extensions/Xinerama.h> #endif #ifdef HAVE_RANDR #include <X11/extensions/Xrandr.h> #endif #include <X11/extensions/Xcomposite.h> #include <X11/Xatom.h> #include <locale.h> #include <string.h> #include <stdio.h> static char* get_screen_name (MetaDisplay *display, int number); static void update_num_workspaces (MetaScreen *screen, guint32 timestamp); static void update_focus_mode (MetaScreen *screen); static void set_workspace_names (MetaScreen *screen); static void prefs_changed_callback (MetaPreference pref, gpointer data); static void set_desktop_geometry_hint (MetaScreen *screen); static void set_desktop_viewport_hint (MetaScreen *screen); #ifdef HAVE_STARTUP_NOTIFICATION static void meta_screen_sn_event (SnMonitorEvent *event, void *user_data); #endif #define SNAP_OSD_TIMEOUT 1 #define _NET_WM_ORIENTATION_HORZ 0 #define _NET_WM_ORIENTATION_VERT 1 #define _NET_WM_TOPLEFT 0 #define _NET_WM_TOPRIGHT 1 #define _NET_WM_BOTTOMRIGHT 2 #define _NET_WM_BOTTOMLEFT 3 enum { PROP_N_WORKSPACES = 1, PROP_KEYBOARD_GRABBED, }; enum { RESTACKED, TOGGLE_RECORDING, WORKSPACE_ADDED, WORKSPACE_REMOVED, WORKSPACE_SWITCHED, WINDOW_ENTERED_MONITOR, WINDOW_LEFT_MONITOR, STARTUP_SEQUENCE_CHANGED, WORKAREAS_CHANGED, MONITORS_CHANGED, SNAP_OSD_SHOW, SNAP_OSD_HIDE, WORKSPACE_OSD_SHOW, WINDOW_ADDED, WINDOW_REMOVED, WINDOW_MONITOR_CHANGED, WINDOW_WORKSPACE_CHANGED, WINDOW_SKIP_TASKBAR_CHANGED, IN_FULLSCREEN_CHANGED, LAST_SIGNAL }; static guint screen_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (MetaScreen, meta_screen, G_TYPE_OBJECT); static void meta_screen_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { #if 0 MetaScreen *screen = META_SCREEN (object); #endif switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_screen_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MetaScreen *screen = META_SCREEN (object); switch (prop_id) { case PROP_N_WORKSPACES: g_value_set_int (value, meta_screen_get_n_workspaces (screen)); break; case PROP_KEYBOARD_GRABBED: g_value_set_boolean (value, screen->all_keys_grabbed ? TRUE : FALSE); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_screen_finalize (GObject *object) { /* Actual freeing done in meta_screen_free() for now */ G_OBJECT_CLASS (meta_screen_parent_class)->finalize (object); } static void meta_screen_class_init (MetaScreenClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; object_class->get_property = meta_screen_get_property; object_class->set_property = meta_screen_set_property; object_class->finalize = meta_screen_finalize; screen_signals[RESTACKED] = g_signal_new ("restacked", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MetaScreenClass, restacked), NULL, NULL, NULL, G_TYPE_NONE, 0); pspec = g_param_spec_int ("n-workspaces", "N Workspaces", "Number of workspaces", 1, G_MAXINT, 1, G_PARAM_READABLE); screen_signals[WORKSPACE_ADDED] = g_signal_new ("workspace-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); screen_signals[WORKSPACE_REMOVED] = g_signal_new ("workspace-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); screen_signals[WORKSPACE_SWITCHED] = g_signal_new ("workspace-switched", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_INT, META_TYPE_MOTION_DIRECTION); screen_signals[WINDOW_ENTERED_MONITOR] = g_signal_new ("window-entered-monitor", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, META_TYPE_WINDOW); screen_signals[WINDOW_LEFT_MONITOR] = g_signal_new ("window-left-monitor", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_INT, META_TYPE_WINDOW); screen_signals[STARTUP_SEQUENCE_CHANGED] = g_signal_new ("startup-sequence-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER); screen_signals[TOGGLE_RECORDING] = g_signal_new ("toggle-recording", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); screen_signals[WORKAREAS_CHANGED] = g_signal_new ("workareas-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MetaScreenClass, workareas_changed), NULL, NULL, NULL, G_TYPE_NONE, 0); screen_signals[MONITORS_CHANGED] = g_signal_new ("monitors-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MetaScreenClass, monitors_changed), NULL, NULL, NULL, G_TYPE_NONE, 0); screen_signals[SNAP_OSD_SHOW] = g_signal_new ("show-snap-osd", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); screen_signals[SNAP_OSD_HIDE] = g_signal_new ("hide-snap-osd", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); screen_signals[WORKSPACE_OSD_SHOW] = g_signal_new ("show-workspace-osd", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); screen_signals[WINDOW_ADDED] = g_signal_new ("window-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, META_TYPE_WINDOW, G_TYPE_INT); screen_signals[WINDOW_REMOVED] = g_signal_new ("window-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); screen_signals[WINDOW_MONITOR_CHANGED] = g_signal_new ("window-monitor-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, META_TYPE_WINDOW, G_TYPE_INT); screen_signals[WINDOW_WORKSPACE_CHANGED] = g_signal_new ("window-workspace-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, META_TYPE_WINDOW, META_TYPE_WORKSPACE); screen_signals[WINDOW_SKIP_TASKBAR_CHANGED] = g_signal_new ("window-skip-taskbar-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); screen_signals[IN_FULLSCREEN_CHANGED] = g_signal_new ("in-fullscreen-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); g_object_class_install_property (object_class, PROP_N_WORKSPACES, pspec); pspec = g_param_spec_boolean ("keyboard-grabbed", "Keyboard grabbed", "Whether the keyboard is grabbed", FALSE, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_KEYBOARD_GRABBED, pspec); } static void meta_screen_init (MetaScreen *screen) { } static int set_wm_check_hint (MetaScreen *screen) { unsigned long data[1]; g_return_val_if_fail (screen->display->leader_window != None, 0); data[0] = screen->display->leader_window; XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_SUPPORTING_WM_CHECK, XA_WINDOW, 32, PropModeReplace, (guchar*) data, 1); return Success; } static void unset_wm_check_hint (MetaScreen *screen) { XDeleteProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_SUPPORTING_WM_CHECK); } static int set_supported_hint (MetaScreen *screen) { Atom atoms[] = { #define EWMH_ATOMS_ONLY #define item(x) screen->display->atom_##x, #include <meta/atomnames.h> #undef item #undef EWMH_ATOMS_ONLY screen->display->atom__GTK_FRAME_EXTENTS, screen->display->atom__GTK_SHOW_WINDOW_MENU, screen->display->atom__GTK_EDGE_CONSTRAINTS, }; XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_SUPPORTED, XA_ATOM, 32, PropModeReplace, (guchar*) atoms, G_N_ELEMENTS(atoms)); return Success; } /* The list of monitors reported by the windowing system might include * mirrored monitors with identical bounds. Since mirrored monitors * shouldn't be treated as separate monitors for most purposes, we * filter them out here. (We ignore the possibility of partially * overlapping monitors because they are rare and it's hard to come * up with any sensible interpretation.) */ static void filter_mirrored_monitors (MetaScreen *screen) { int i, j; /* Currently always true and simplifies things */ g_assert (screen->primary_monitor_index == 0); for (i = 1; i < screen->n_monitor_infos; i++) { /* In case we've filtered previous monitors */ screen->monitor_infos[i].number = i; for (j = 0; j < i; j++) { if (meta_rectangle_equal (&screen->monitor_infos[i].rect, &screen->monitor_infos[j].rect)) { memmove (&screen->monitor_infos[i], &screen->monitor_infos[i + 1], (screen->n_monitor_infos - i - 1) * sizeof (MetaMonitorInfo)); screen->n_monitor_infos--; i--; continue; } } } } #ifdef HAVE_RANDR static MetaMonitorInfo * find_monitor_with_rect (MetaScreen *screen, int x, int y, int w, int h) { MetaMonitorInfo *info; int i; for (i = 0; i < screen->n_monitor_infos; i++) { info = &screen->monitor_infos[i]; if (x == info->rect.x && y == info->rect.y && w == info->rect.width && h == info->rect.height) return info; } return NULL; } /* In the case of multiple outputs of a single crtc (mirroring), we consider one of the * outputs the "main". This is the one we consider "owning" the windows, so if * the mirroring is changed to a dual monitor setup then the windows are moved to the * crtc that now has that main output. If one of the outputs is the primary that is * always the main, otherwise we just use the first. */ static XID find_main_output_for_crtc (MetaScreen *screen, XRRScreenResources *resources, XRRCrtcInfo *crtc) { XRROutputInfo *output; RROutput primary_output; int i; XID res; primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot); res = None; for (i = 0; i < crtc->noutput; i++) { output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]); if (output->connection != RR_Disconnected && (res == None || crtc->outputs[i] == primary_output)) res = crtc->outputs[i]; XRRFreeOutputInfo (output); } return res; } #endif static void reload_monitor_infos (MetaScreen *screen) { MetaDisplay *display; { GList *tmp; tmp = screen->workspaces; while (tmp != NULL) { MetaWorkspace *space = tmp->data; meta_workspace_invalidate_work_area (space); tmp = tmp->next; } } display = screen->display; /* Any previous screen->monitor_infos is freed by the caller */ screen->monitor_infos = NULL; screen->n_monitor_infos = 0; screen->last_monitor_index = 0; /* Xinerama doesn't have a concept of primary monitor, however XRandR * does. However, the XRandR xinerama compat code always sorts the * primary output first, so we rely on that here. We could use the * native XRandR calls instead of xinerama, but that would be * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as * that is defined in terms of xinerama monitor indexes. * So, since we don't need anything in xrandr except the primary * we can keep using xinerama and use the first monitor as the * primary. */ screen->primary_monitor_index = 0; screen->display->monitor_cache_invalidated = TRUE; if (g_getenv ("MUFFIN_DEBUG_XINERAMA")) { meta_topic (META_DEBUG_XINERAMA, "Pretending a single monitor has two Xinerama screens\n"); screen->monitor_infos = g_new0 (MetaMonitorInfo, 2); screen->n_monitor_infos = 2; screen->monitor_infos[0].number = 0; screen->monitor_infos[0].rect = screen->rect; screen->monitor_infos[0].rect.width = screen->rect.width / 2; screen->monitor_infos[0].in_fullscreen = -1; screen->monitor_infos[1].number = 1; screen->monitor_infos[1].rect = screen->rect; screen->monitor_infos[1].rect.x = screen->rect.width / 2; screen->monitor_infos[1].rect.width = screen->rect.width / 2; screen->monitor_infos[1].in_fullscreen = -1; } #ifdef HAVE_XFREE_XINERAMA if (screen->n_monitor_infos == 0 && XineramaIsActive (display->xdisplay)) { XineramaScreenInfo *infos; int n_infos; int i, j; n_infos = 0; infos = XineramaQueryScreens (display->xdisplay, &n_infos); meta_topic (META_DEBUG_XINERAMA, "Found %d Xinerama screens on display %s\n", n_infos, display->name); if (n_infos > 0) { screen->monitor_infos = g_new0 (MetaMonitorInfo, n_infos); screen->n_monitor_infos = n_infos; i = 0; while (i < n_infos) { screen->monitor_infos[i].number = infos[i].screen_number; screen->monitor_infos[i].rect.x = infos[i].x_org; screen->monitor_infos[i].rect.y = infos[i].y_org; screen->monitor_infos[i].rect.width = infos[i].width; screen->monitor_infos[i].rect.height = infos[i].height; screen->monitor_infos[i].in_fullscreen = -1; meta_topic (META_DEBUG_XINERAMA, "Monitor %d is %d,%d %d x %d\n", screen->monitor_infos[i].number, screen->monitor_infos[i].rect.x, screen->monitor_infos[i].rect.y, screen->monitor_infos[i].rect.width, screen->monitor_infos[i].rect.height); ++i; } } meta_XFree (infos); #ifdef HAVE_RANDR { XRRScreenResources *resources; resources = XRRGetScreenResourcesCurrent (display->xdisplay, screen->xroot); if (resources) { for (i = 0; i < resources->ncrtc; i++) { XRRCrtcInfo *crtc; MetaMonitorInfo *info; crtc = XRRGetCrtcInfo (display->xdisplay, resources, resources->crtcs[i]); info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height); if (info) { for (j = 0; j < resources->nmode; j++) { if (resources->modes[j].id == crtc->mode) info->refresh_rate = (resources->modes[j].dotClock / ((float)resources->modes[j].hTotal * resources->modes[j].vTotal)); } info->output = find_main_output_for_crtc (screen, resources, crtc); } XRRFreeCrtcInfo (crtc); } XRRFreeScreenResources (resources); } } #endif } else if (screen->n_monitor_infos > 0) { meta_topic (META_DEBUG_XINERAMA, "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n", display->name); } #else meta_topic (META_DEBUG_XINERAMA, "Muffin compiled without XFree86 Xinerama support\n"); #endif /* HAVE_XFREE_XINERAMA */ #ifdef HAVE_SOLARIS_XINERAMA /* This code from GDK, Copyright (C) 2002 Sun Microsystems */ if (screen->n_monitor_infos == 0 && XineramaGetState (screen->display->xdisplay, screen->number)) { XRectangle monitors[MAXFRAMEBUFFERS]; unsigned char hints[16]; int result; int n_monitors; int i; n_monitors = 0; result = XineramaGetInfo (screen->display->xdisplay, screen->number, monitors, hints, &n_monitors); /* Yes I know it should be Success but the current implementation * returns the num of monitor */ if (result > 0) { g_assert (n_monitors > 0); screen->monitor_infos = g_new0 (MetaMonitorInfo, n_monitors); screen->n_monitor_infos = n_monitors; i = 0; while (i < n_monitors) { screen->monitor_infos[i].number = i; screen->monitor_infos[i].rect.x = monitors[i].x; screen->monitor_infos[i].rect.y = monitors[i].y; screen->monitor_infos[i].rect.width = monitors[i].width; screen->monitor_infos[i].rect.height = monitors[i].height; meta_topic (META_DEBUG_XINERAMA, "Monitor %d is %d,%d %d x %d\n", screen->monitor_infos[i].number, screen->monitor_infos[i].rect.x, screen->monitor_infos[i].rect.y, screen->monitor_infos[i].rect.width, screen->monitor_infos[i].rect.height); ++i; } } } else if (screen->n_monitor_infos == 0) { meta_topic (META_DEBUG_XINERAMA, "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n", display->name); } #else meta_topic (META_DEBUG_XINERAMA, "Muffin compiled without Solaris Xinerama support\n"); #endif /* HAVE_SOLARIS_XINERAMA */ /* If no Xinerama, fill in the single screen info so * we can use the field unconditionally */ if (screen->n_monitor_infos == 0) { meta_topic (META_DEBUG_XINERAMA, "No Xinerama screens, using default screen info\n"); screen->monitor_infos = g_new0 (MetaMonitorInfo, 1); screen->n_monitor_infos = 1; screen->monitor_infos[0].number = 0; screen->monitor_infos[0].rect = screen->rect; screen->monitor_infos[0].in_fullscreen = -1; } filter_mirrored_monitors (screen); screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE; g_assert (screen->n_monitor_infos > 0); g_assert (screen->monitor_infos != NULL); } /* The guard window allows us to leave minimized windows mapped so * that compositor code may provide live previews of them. * Instead of being unmapped/withdrawn, they get pushed underneath * the guard window. */ static Window create_guard_window (Display *xdisplay, MetaScreen *screen) { XSetWindowAttributes attributes; Window guard_window; gulong create_serial; attributes.event_mask = NoEventMask; attributes.override_redirect = True; attributes.background_pixel = BlackPixel (xdisplay, screen->number); /* We have to call record_add() after we have the new window ID, * so save the serial for the CreateWindow request until then */ create_serial = XNextRequest(xdisplay); guard_window = XCreateWindow (xdisplay, screen->xroot, 0, /* x */ 0, /* y */ screen->rect.width, screen->rect.height, 0, /* border width */ CopyFromParent, /* depth */ CopyFromParent, /* class */ CopyFromParent, /* visual */ CWEventMask|CWOverrideRedirect|CWBackPixel, &attributes); meta_stack_tracker_record_add (screen->stack_tracker, guard_window, create_serial); meta_stack_tracker_record_lower (screen->stack_tracker, guard_window, XNextRequest (xdisplay)); XLowerWindow (xdisplay, guard_window); XMapWindow (xdisplay, guard_window); return guard_window; } LOCAL_SYMBOL MetaScreen* meta_screen_new (MetaDisplay *display, int number, guint32 timestamp) { MetaScreen *screen; Window xroot; Display *xdisplay; XWindowAttributes attr; Window new_wm_sn_owner; Window current_wm_sn_owner; gboolean replace_current_wm; Atom wm_sn_atom; char buf[128]; guint32 manager_timestamp; gulong current_workspace; replace_current_wm = meta_get_replace_current_wm (); /* Only display->name, display->xdisplay, and display->error_traps * can really be used in this function, since normally screens are * created from the MetaDisplay constructor */ xdisplay = display->xdisplay; meta_verbose ("Trying screen %d on display '%s'\n", number, display->name); xroot = RootWindow (xdisplay, number); /* FVWM checks for None here, I don't know if this * ever actually happens */ if (xroot == None) { meta_warning ("Screen %d on display '%s' is invalid\n", number, display->name); return NULL; } sprintf (buf, "WM_S%d", number); wm_sn_atom = XInternAtom (xdisplay, buf, False); current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom); if (current_wm_sn_owner != None) { XSetWindowAttributes attrs; if (!replace_current_wm) { meta_warning ("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n", number, display->name); return NULL; } /* We want to find out when the current selection owner dies */ meta_error_trap_push_with_return (display); attrs.event_mask = StructureNotifyMask; XChangeWindowAttributes (xdisplay, current_wm_sn_owner, CWEventMask, &attrs); if (meta_error_trap_pop_with_return (display) != Success) current_wm_sn_owner = None; /* don't wait for it to die later on */ } /* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner, * but those cannot be masked, so we only need NoEventMask. */ new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask); manager_timestamp = timestamp; XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner, manager_timestamp); if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner) { meta_warning ("Could not acquire window manager selection on screen %d display \"%s\"\n", number, display->name); XDestroyWindow (xdisplay, new_wm_sn_owner); return NULL; } { /* Send client message indicating that we are now the WM */ XClientMessageEvent ev; ev.type = ClientMessage; ev.window = xroot; ev.message_type = display->atom_MANAGER; ev.format = 32; ev.data.l[0] = manager_timestamp; ev.data.l[1] = wm_sn_atom; XSendEvent (xdisplay, xroot, False, StructureNotifyMask, (XEvent*)&ev); } /* Wait for old window manager to go away */ if (current_wm_sn_owner != None) { XEvent event; /* We sort of block infinitely here which is probably lame. */ meta_verbose ("Waiting for old window manager to exit\n"); do { XWindowEvent (xdisplay, current_wm_sn_owner, StructureNotifyMask, &event); } while (event.type != DestroyNotify); } /* select our root window events */ meta_error_trap_push_with_return (display); /* We need to or with the existing event mask since * gtk+ may be interested in other events. */ XGetWindowAttributes (xdisplay, xroot, &attr); XSelectInput (xdisplay, xroot, SubstructureRedirectMask | SubstructureNotifyMask | ColormapChangeMask | PropertyChangeMask | LeaveWindowMask | EnterWindowMask | KeyPressMask | KeyReleaseMask | FocusChangeMask | StructureNotifyMask | ExposureMask | attr.your_event_mask); if (meta_error_trap_pop_with_return (display) != Success) { meta_warning ("Screen %d on display \"%s\" already has a window manager\n", number, display->name); XDestroyWindow (xdisplay, new_wm_sn_owner); return NULL; } screen = g_object_new (META_TYPE_SCREEN, NULL); screen->closing = 0; screen->display = display; screen->number = number; screen->screen_name = get_screen_name (display, number); screen->xscreen = ScreenOfDisplay (xdisplay, number); screen->xroot = xroot; screen->rect.x = screen->rect.y = 0; screen->rect.width = WidthOfScreen (screen->xscreen); screen->rect.height = HeightOfScreen (screen->xscreen); screen->current_cursor = -1; /* invalid/unset */ screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen); screen->default_depth = DefaultDepthOfScreen (screen->xscreen); screen->flash_window = None; screen->wm_sn_selection_window = new_wm_sn_owner; screen->wm_sn_atom = wm_sn_atom; screen->wm_sn_timestamp = manager_timestamp; screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay, xroot, NoEventMask); screen->work_area_later = 0; screen->check_fullscreen_later = 0; screen->active_workspace = NULL; screen->workspaces = NULL; screen->rows_of_workspaces = 1; screen->columns_of_workspaces = -1; screen->vertical_workspaces = FALSE; screen->starting_corner = META_SCREEN_TOPLEFT; screen->guard_window = None; screen->composite_overlay_window = XCompositeGetOverlayWindow (xdisplay, xroot); screen->monitor_infos = NULL; screen->n_monitor_infos = 0; screen->last_monitor_index = 0; reload_monitor_infos (screen); meta_screen_set_cursor (screen, META_CURSOR_DEFAULT); /* Handle creating a no_focus_window for this screen */ screen->no_focus_window = meta_create_offscreen_window (display->xdisplay, screen->xroot, FocusChangeMask|KeyPressMask|KeyReleaseMask); XMapWindow (display->xdisplay, screen->no_focus_window); /* Done with no_focus_window stuff */ set_supported_hint (screen); set_wm_check_hint (screen); set_desktop_viewport_hint (screen); set_desktop_geometry_hint (screen); meta_screen_update_workspace_layout (screen); /* Get current workspace */ current_workspace = 0; if (meta_prop_get_cardinal (screen->display, screen->xroot, screen->display->atom__NET_CURRENT_DESKTOP, ¤t_workspace)) meta_verbose ("Read existing _NET_CURRENT_DESKTOP = %d\n", (int) current_workspace); else meta_verbose ("No _NET_CURRENT_DESKTOP present\n"); /* Screens must have at least one workspace at all times, * so create that required workspace. */ meta_workspace_activate (meta_workspace_new (screen), timestamp); update_num_workspaces (screen, timestamp); set_workspace_names (screen); screen->all_keys_grabbed = FALSE; screen->keys_grabbed = FALSE; meta_screen_grab_keys (screen); screen->ui = meta_ui_new (display, screen->xscreen); screen->tile_preview_timeout_id = 0; screen->tile_hud_timeout_id = 0; screen->snap_osd_timeout_id = 0; screen->tile_preview_visible = FALSE; screen->tile_hud_visible = FALSE; screen->stack = meta_stack_new (screen); screen->stack_tracker = meta_stack_tracker_new (screen); meta_prefs_add_listener (prefs_changed_callback, screen); #ifdef HAVE_STARTUP_NOTIFICATION screen->sn_context = sn_monitor_context_new (screen->display->sn_display, screen->number, meta_screen_sn_event, screen, NULL); screen->startup_sequences = NULL; screen->startup_sequence_timeout = 0; #endif /* Switch to the _NET_CURRENT_DESKTOP workspace */ { MetaWorkspace *space; space = meta_screen_get_workspace_by_index (screen, current_workspace); if (space != NULL) meta_workspace_activate (space, timestamp); } meta_verbose ("Added screen %d ('%s') root 0x%lx\n", screen->number, screen->screen_name, screen->xroot); return screen; } LOCAL_SYMBOL void meta_screen_free (MetaScreen *screen, guint32 timestamp) { MetaDisplay *display; display = screen->display; screen->closing += 1; meta_display_grab (display); meta_compositor_unmanage_screen (screen->display->compositor, screen); meta_display_unmanage_windows_for_screen (display, screen, timestamp); meta_prefs_remove_listener (prefs_changed_callback, screen); meta_screen_ungrab_keys (screen); #ifdef HAVE_STARTUP_NOTIFICATION g_slist_foreach (screen->startup_sequences, (GFunc) sn_startup_sequence_unref, NULL); g_slist_free (screen->startup_sequences); screen->startup_sequences = NULL; if (screen->startup_sequence_timeout != 0) { g_source_remove (screen->startup_sequence_timeout); screen->startup_sequence_timeout = 0; } if (screen->sn_context) { sn_monitor_context_unref (screen->sn_context); screen->sn_context = NULL; } #endif meta_ui_free (screen->ui); meta_stack_free (screen->stack); meta_stack_tracker_free (screen->stack_tracker); meta_error_trap_push_with_return (screen->display); XSelectInput (screen->display->xdisplay, screen->xroot, 0); if (meta_error_trap_pop_with_return (screen->display) != Success) meta_warning ("Could not release screen %d on display \"%s\"\n", screen->number, screen->display->name); unset_wm_check_hint (screen); XDestroyWindow (screen->display->xdisplay, screen->wm_sn_selection_window); if (screen->work_area_later != 0) { g_source_remove (screen->work_area_later); screen->work_area_later = 0; } if (screen->check_fullscreen_later != 0) g_source_remove (screen->check_fullscreen_later); free (screen->monitor_infos); if (screen->tile_preview_timeout_id) { g_source_remove (screen->tile_preview_timeout_id); screen->tile_preview_timeout_id = 0; } if (screen->tile_hud_timeout_id) { g_source_remove (screen->tile_hud_timeout_id); screen->tile_hud_timeout_id = 0; } if (screen->snap_osd_timeout_id) { g_source_remove (screen->snap_osd_timeout_id); screen->snap_osd_timeout_id = 0; } free (screen->screen_name); g_object_unref (screen); XFlush (display->xdisplay); meta_display_ungrab (display); } typedef struct { Window xwindow; XWindowAttributes attrs; } WindowInfo; static GList * list_windows (MetaScreen *screen) { Window ignored1, ignored2; Window *children; guint n_children, i; GList *result; XQueryTree (screen->display->xdisplay, screen->xroot, &ignored1, &ignored2, &children, &n_children); result = NULL; for (i = 0; i < n_children; ++i) { WindowInfo *info = g_new0 (WindowInfo, 1); meta_error_trap_push_with_return (screen->display); XGetWindowAttributes (screen->display->xdisplay, children[i], &info->attrs); if (meta_error_trap_pop_with_return (screen->display)) { meta_verbose ("Failed to get attributes for window 0x%lx\n", children[i]); free (info); } else { info->xwindow = children[i]; } result = g_list_prepend (result, info); } if (children) XFree (children); return g_list_reverse (result); } LOCAL_SYMBOL void meta_screen_manage_all_windows (MetaScreen *screen) { GList *windows; GList *list; meta_display_grab (screen->display); if (screen->guard_window == None) screen->guard_window = create_guard_window (screen->display->xdisplay, screen); windows = list_windows (screen); meta_stack_freeze (screen->stack); for (list = windows; list != NULL; list = list->next) { WindowInfo *info = list->data; MetaWindow *mw; mw = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE, META_COMP_EFFECT_NONE, &info->attrs); if (mw) { /* In this context, we're creating MetaWindows for pre-existing client windows. * We can probably assume current positions are deliberate, and not force them * either within the screen extents, or within a single monitor when constraints * are run initially. */ mw->require_fully_onscreen = FALSE; mw->require_on_single_monitor = FALSE; mw->require_titlebar_visible = FALSE; } } meta_stack_thaw (screen->stack); g_list_foreach (windows, (GFunc)free, NULL); g_list_free (windows); meta_display_ungrab (screen->display); } LOCAL_SYMBOL void meta_screen_composite_all_windows (MetaScreen *screen) { MetaDisplay *display; GSList *windows, *tmp; display = screen->display; if (!display->compositor) return; windows = meta_display_list_windows (display, META_LIST_INCLUDE_OVERRIDE_REDIRECT); for (tmp = windows; tmp != NULL; tmp = tmp->next) { MetaWindow *window = tmp->data; meta_compositor_add_window (display->compositor, window); if (window->visible_to_compositor) meta_compositor_show_window (display->compositor, window, META_COMP_EFFECT_NONE); } g_slist_free (windows); /* initialize the compositor's view of the stacking order */ meta_stack_tracker_sync_stack (screen->stack_tracker); } /** * meta_screen_for_x_screen: * @xscreen: an X screen structure. * * Gets the #MetaScreen corresponding to an X screen structure. * * Return value: (transfer none): the #MetaScreen for the X screen * %NULL if Metacity is not managing the screen. */ MetaScreen* meta_screen_for_x_screen (Screen *xscreen) { MetaDisplay *display; display = meta_display_for_x_display (DisplayOfScreen (xscreen)); if (display == NULL) return NULL; return meta_display_screen_for_x_screen (display, xscreen); } static void prefs_changed_callback (MetaPreference pref, gpointer data) { MetaScreen *screen = data; if ((pref == META_PREF_NUM_WORKSPACES || pref == META_PREF_DYNAMIC_WORKSPACES) && !meta_prefs_get_dynamic_workspaces ()) { /* GSettings doesn't provide timestamps, but luckily update_num_workspaces * often doesn't need it... */ guint32 timestamp = meta_display_get_current_time_roundtrip (screen->display); update_num_workspaces (screen, timestamp); } else if (pref == META_PREF_FOCUS_MODE) { update_focus_mode (screen); } else if (pref == META_PREF_WORKSPACE_NAMES) { set_workspace_names (screen); } } static char* get_screen_name (MetaDisplay *display, int number) { char *p; char *dname; char *scr; /* DisplayString gives us a sort of canonical display, * vs. the user-entered name from XDisplayName() */ dname = g_strdup (DisplayString (display->xdisplay)); /* Change display name to specify this screen. */ p = strrchr (dname, ':'); if (p) { p = strchr (p, '.'); if (p) *p = '\0'; } scr = g_strdup_printf ("%s.%d", dname, number); free (dname); return scr; } static gint ptrcmp (gconstpointer a, gconstpointer b) { if (a < b) return -1; else if (a > b) return 1; else return 0; } static void listify_func (gpointer key, gpointer value, gpointer data) { GSList **listp; listp = data; *listp = g_slist_prepend (*listp, value); } /** * meta_screen_foreach_window: * @screen: a #MetaScreen * @func: function to call for each window * @data: user data to pass to @func * * Calls the specified function for each window on the screen, * ignoring override-redirect windows. */ LOCAL_SYMBOL void meta_screen_foreach_window (MetaScreen *screen, MetaScreenWindowFunc func, gpointer data) { GSList *winlist; GSList *tmp; /* If we end up doing this often, just keeping a list * of windows might be sensible. */ winlist = NULL; g_hash_table_foreach (screen->display->window_ids, listify_func, &winlist); winlist = g_slist_sort (winlist, ptrcmp); tmp = winlist; while (tmp != NULL) { /* If the next node doesn't contain this window * a second time, delete the window. */ if (tmp->next == NULL || (tmp->next && tmp->next->data != tmp->data)) { MetaWindow *window = tmp->data; if (window->screen == screen && !window->override_redirect) (* func) (screen, window, data); } tmp = tmp->next; } g_slist_free (winlist); } static void queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data) { if (window->frame) meta_frame_queue_draw (window->frame); } LOCAL_SYMBOL void meta_screen_queue_frame_redraws (MetaScreen *screen) { meta_screen_foreach_window (screen, queue_draw, NULL); } static void queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data) { meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } LOCAL_SYMBOL void meta_screen_queue_window_resizes (MetaScreen *screen) { meta_screen_foreach_window (screen, queue_resize, NULL); } int meta_screen_get_n_workspaces (MetaScreen *screen) { return g_list_length (screen->workspaces); } /** * meta_screen_get_workspace_by_index: * @screen: a #MetaScreen * @index: index of one of the screen's workspaces * * Gets the workspace object for one of a screen's workspaces given the workspace * index. It's valid to call this function with an out-of-range index and it * will robustly return %NULL. * * Return value: (transfer none): the workspace object with specified index, or %NULL * if the index is out of range. */ MetaWorkspace* meta_screen_get_workspace_by_index (MetaScreen *screen, int idx) { GList *tmp; int i; /* should be robust, idx is maybe from an app */ if (idx < 0) return NULL; i = 0; tmp = screen->workspaces; while (tmp != NULL) { MetaWorkspace *w = tmp->data; if (i == idx) return w; ++i; tmp = tmp->next; } return NULL; } static void update_net_desktop_layout (MetaScreen *screen, int n_columns) { g_return_if_fail (META_IS_SCREEN (screen)); screen->columns_of_workspaces = n_columns; unsigned long data[4]; /* Orientation */ data[0] = screen->vertical_workspaces ? _NET_WM_ORIENTATION_VERT : _NET_WM_ORIENTATION_HORZ; /* Number of columns */ data[1] = screen->columns_of_workspaces; /* Number of rows */ data[2] = screen->rows_of_workspaces; /* Starting corner */ data[3] = screen->starting_corner; meta_verbose ("Setting _NET_DESKTOP_LAYOUT on root window " "to orientation = %lu, columns = %lu, rows = %lu, starting corner = %lu\n", data[0], data[1], data[2], data[3]); meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_DESKTOP_LAYOUT, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 4); meta_error_trap_pop (screen->display); } static void set_number_of_spaces_hint (MetaScreen *screen, int n_spaces) { unsigned long data[1]; if (screen->closing > 0) return; data[0] = n_spaces; meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]); meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_NUMBER_OF_DESKTOPS, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); meta_error_trap_pop (screen->display); } static void set_desktop_geometry_hint (MetaScreen *screen) { unsigned long data[2]; if (screen->closing > 0) return; data[0] = screen->rect.width; data[1] = screen->rect.height; meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]); meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_DESKTOP_GEOMETRY, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 2); meta_error_trap_pop (screen->display); } static void set_desktop_viewport_hint (MetaScreen *screen) { unsigned long data[2]; if (screen->closing > 0) return; /* * Muffin does not implement viewports, so this is a fixed 0,0 */ data[0] = 0; data[1] = 0; meta_verbose ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n"); meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_DESKTOP_VIEWPORT, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 2); meta_error_trap_pop (screen->display); } void meta_screen_remove_workspace (MetaScreen *screen, MetaWorkspace *workspace, guint32 timestamp) { GList *l; MetaWorkspace *neighbour = NULL; GList *next = NULL; int index; gboolean active_index_changed; int new_num; l = screen->workspaces; while (l) { MetaWorkspace *w = l->data; if (w == workspace) { if (l->next) next = l->next; if (l->prev) neighbour = l->prev->data; else if (l->next) neighbour = l->next->data; else { /* Cannot remove the only workspace! */ return; } break; } l = l->next; } if (!neighbour) return; meta_workspace_relocate_windows (workspace, neighbour); if (workspace == screen->active_workspace) meta_workspace_activate (neighbour, timestamp); /* To emit the signal after removing the workspace */ index = meta_workspace_index (workspace); active_index_changed = index < meta_screen_get_active_workspace_index (screen); /* This also removes the workspace from the screens list */ meta_workspace_remove (workspace); new_num = g_list_length (screen->workspaces); set_number_of_spaces_hint (screen, new_num); if (!meta_prefs_get_dynamic_workspaces ()) meta_prefs_set_num_workspaces (new_num); update_net_desktop_layout (screen, new_num); set_workspace_names (screen); /* If deleting a workspace before the current workspace, the active * workspace index changes, so we need to update that hint */ if (active_index_changed) meta_screen_set_active_workspace_hint (screen); l = next; while (l) { MetaWorkspace *w = l->data; meta_workspace_update_window_hints (w); l = l->next; } meta_screen_queue_workarea_recalc (screen); g_signal_emit (screen, screen_signals[WORKSPACE_REMOVED], 0, index); g_object_notify (G_OBJECT (screen), "n-workspaces"); } /** * meta_screen_append_new_workspace: * @screen: a #MetaScreen * @activate: %TRUE if the workspace should be switched to after creation * @timestamp: if switching to a new workspace, timestamp to be used when * focusing a window on the new workspace. (Doesn't hurt to pass a valid * timestamp when available even if not switching workspaces.) * * Append a new workspace to the screen and (optionally) switch to that * screen. * * Return value: (transfer none): the newly appended workspace. */ MetaWorkspace * meta_screen_append_new_workspace (MetaScreen *screen, gboolean activate, guint32 timestamp) { MetaWorkspace *w; int new_num; /* This also adds the workspace to the screen list */ w = meta_workspace_new (screen); if (!w) return NULL; if (activate) meta_workspace_activate (w, timestamp); new_num = g_list_length (screen->workspaces); set_number_of_spaces_hint (screen, new_num); if (!meta_prefs_get_dynamic_workspaces ()) meta_prefs_set_num_workspaces (new_num); update_net_desktop_layout (screen, new_num); set_workspace_names (screen); meta_screen_queue_workarea_recalc (screen); g_signal_emit (screen, screen_signals[WORKSPACE_ADDED], 0, meta_workspace_index (w)); g_object_notify (G_OBJECT (screen), "n-workspaces"); return w; } static void update_num_workspaces (MetaScreen *screen, guint32 timestamp) { int new_num, old_num; GList *tmp; int i; GList *extras; MetaWorkspace *last_remaining; gboolean need_change_space; new_num = meta_prefs_get_num_workspaces (); g_assert (new_num > 0); if (g_list_length (screen->workspaces) == (guint) new_num) return; last_remaining = NULL; extras = NULL; i = 0; tmp = screen->workspaces; while (tmp != NULL) { MetaWorkspace *w = tmp->data; if (i >= new_num) extras = g_list_prepend (extras, w); else last_remaining = w; ++i; tmp = tmp->next; } old_num = i; g_assert (last_remaining); /* Get rid of the extra workspaces by moving all their windows * to last_remaining, then activating last_remaining if * one of the removed workspaces was active. This will be a bit * wacky if the config tool for changing number of workspaces * is on a removed workspace ;-) */ need_change_space = FALSE; tmp = extras; while (tmp != NULL) { MetaWorkspace *w = tmp->data; meta_workspace_relocate_windows (w, last_remaining); if (w == screen->active_workspace) need_change_space = TRUE; tmp = tmp->next; } if (need_change_space) meta_workspace_activate (last_remaining, timestamp); /* Should now be safe to free the workspaces */ tmp = extras; while (tmp != NULL) { MetaWorkspace *w = tmp->data; g_assert (w->windows == NULL); meta_workspace_remove (w); tmp = tmp->next; } g_list_free (extras); for (i = old_num; i < new_num; i++) meta_workspace_new (screen); set_number_of_spaces_hint (screen, new_num); update_net_desktop_layout (screen, new_num); set_workspace_names (screen); meta_screen_queue_workarea_recalc (screen); for (i = old_num; i < new_num; i++) g_signal_emit (screen, screen_signals[WORKSPACE_ADDED], 0, i); g_object_notify (G_OBJECT (screen), "n-workspaces"); } static void update_focus_mode (MetaScreen *screen) { /* nothing to do anymore */ ; } LOCAL_SYMBOL void meta_screen_set_cursor (MetaScreen *screen, MetaCursor cursor) { Cursor xcursor; if (cursor == screen->current_cursor) return; screen->current_cursor = cursor; xcursor = meta_display_create_x_cursor (screen->display, cursor); XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor); XFlush (screen->display->xdisplay); XFreeCursor (screen->display->xdisplay, xcursor); } LOCAL_SYMBOL void meta_screen_update_cursor (MetaScreen *screen) { Cursor xcursor; xcursor = meta_display_create_x_cursor (screen->display, screen->current_cursor); XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor); XFlush (screen->display->xdisplay); XFreeCursor (screen->display->xdisplay, xcursor); } static gboolean snap_osd_timeout (void *data) { MetaScreen *screen = data; int monitor; monitor = meta_screen_get_current_monitor (screen); if (meta_screen_tile_preview_get_visible (screen) || meta_screen_tile_hud_get_visible (screen)) g_signal_emit (screen, screen_signals[SNAP_OSD_SHOW], 0, monitor); screen->snap_osd_timeout_id = 0; return FALSE; } static gboolean maybe_hide_snap_osd (void *data) { MetaScreen *screen = data; if (!meta_screen_tile_preview_get_visible (screen) && !meta_screen_tile_hud_get_visible (screen)) { if (screen->snap_osd_timeout_id > 0) { g_source_remove (screen->snap_osd_timeout_id); screen->snap_osd_timeout_id = 0; } g_signal_emit (screen, screen_signals[SNAP_OSD_HIDE], 0); } return FALSE; } static gboolean meta_screen_tile_preview_update_timeout (gpointer data) { MetaScreen *screen = data; MetaWindow *window = screen->display->grab_window; gboolean needs_preview = FALSE; screen->tile_preview_timeout_id = 0; if (window && window->mouse_on_edge) { switch (window->tile_mode) { case META_TILE_LEFT: case META_TILE_RIGHT: if (!META_WINDOW_TILED_SIDE_BY_SIDE (window)) needs_preview = TRUE; break; case META_TILE_ULC: case META_TILE_LLC: case META_TILE_URC: case META_TILE_LRC: if (!META_WINDOW_TILED_CORNER (window)) needs_preview = TRUE; break; case META_TILE_TOP: case META_TILE_BOTTOM: if (!META_WINDOW_TILED_TOP_BOTTOM (window)) needs_preview = TRUE; break; case META_TILE_MAXIMIZE: if (!META_WINDOW_MAXIMIZED (window)) needs_preview = TRUE; break; default: needs_preview = FALSE; break; } } if (needs_preview) { MetaRectangle tile_rect; int monitor; monitor = meta_window_get_current_tile_monitor_number (window); meta_window_get_current_tile_area (window, &tile_rect); meta_compositor_show_tile_preview (screen->display->compositor, screen, window, &tile_rect, monitor, window->snap_queued); screen->tile_preview_visible = TRUE; if (screen->snap_osd_timeout_id == 0) screen->snap_osd_timeout_id = g_timeout_add_seconds (SNAP_OSD_TIMEOUT, snap_osd_timeout, screen); } else { meta_compositor_hide_tile_preview (screen->display->compositor, screen); screen->tile_preview_visible = FALSE; } return FALSE; } #define TILE_PREVIEW_TIMEOUT_MS 200 LOCAL_SYMBOL void meta_screen_tile_preview_update (MetaScreen *screen, gboolean delay) { if (delay && !meta_screen_tile_preview_get_visible (screen)) { if (screen->tile_preview_timeout_id > 0) return; screen->tile_preview_timeout_id = g_timeout_add (TILE_PREVIEW_TIMEOUT_MS, meta_screen_tile_preview_update_timeout, screen); } else { if (screen->tile_preview_timeout_id > 0) { g_source_remove (screen->tile_preview_timeout_id); screen->tile_preview_timeout_id = 0; } meta_screen_tile_preview_update_timeout ((gpointer)screen); } } LOCAL_SYMBOL void meta_screen_tile_preview_hide (MetaScreen *screen) { if (screen->tile_preview_timeout_id > 0) { g_source_remove (screen->tile_preview_timeout_id); screen->tile_preview_timeout_id = 0; } if (!screen->tile_preview_visible) return; meta_compositor_hide_tile_preview (screen->display->compositor, screen); screen->tile_preview_visible = FALSE; g_timeout_add (250, maybe_hide_snap_osd, screen); } LOCAL_SYMBOL gboolean meta_screen_tile_preview_get_visible (MetaScreen *screen) { return screen->tile_preview_visible; } static gboolean meta_screen_tile_hud_update_timeout (gpointer data) { MetaScreen *screen = data; MetaWindow *window = screen->display->grab_window; screen->tile_hud_timeout_id = 0; if (!screen->tile_hud_visible && window != NULL && window->current_proximity_zone != ZONE_NONE) { MetaRectangle work_area; /* This bit is liable to get more complicated when there are multiple monitors involved - we'll have partial hud, with a bare area at the monitor 'joint' or something... */ int monitor; monitor = meta_screen_get_current_monitor (screen); meta_window_get_work_area_for_monitor (window, monitor, &work_area); meta_compositor_show_hud_preview (screen->display->compositor, screen, window->current_proximity_zone, &work_area, window->snap_queued); screen->tile_hud_visible = TRUE; if (screen->snap_osd_timeout_id == 0) screen->snap_osd_timeout_id = g_timeout_add_seconds (SNAP_OSD_TIMEOUT, snap_osd_timeout, screen); } else { meta_compositor_hide_hud_preview (screen->display->compositor, screen); screen->tile_hud_visible = FALSE; g_timeout_add (250, maybe_hide_snap_osd, screen); } return FALSE; } #define TILE_HUD_TIMEOUT_MS 100 LOCAL_SYMBOL void meta_screen_tile_hud_update (MetaScreen *screen, gboolean delay, gboolean hiding) { if (screen->tile_hud_visible != hiding) { if (screen->tile_hud_timeout_id > 0) { g_source_remove (screen->tile_hud_timeout_id); screen->tile_hud_timeout_id = 0; } screen->tile_hud_visible = hiding; } if (delay && !meta_screen_tile_hud_get_visible (screen)) { if (screen->tile_hud_timeout_id > 0) return; screen->tile_hud_timeout_id = g_timeout_add (TILE_HUD_TIMEOUT_MS, meta_screen_tile_hud_update_timeout, screen); } else { if (screen->tile_hud_timeout_id > 0) { g_source_remove (screen->tile_hud_timeout_id); screen->tile_hud_timeout_id = 0; } meta_screen_tile_hud_update_timeout ((gpointer)screen); } } LOCAL_SYMBOL void meta_screen_tile_hud_hide (MetaScreen *screen) { if (screen->tile_hud_timeout_id > 0) { g_source_remove (screen->tile_hud_timeout_id); screen->tile_hud_timeout_id = 0; } if (!screen->tile_hud_visible) return; meta_compositor_hide_hud_preview (screen->display->compositor, screen); screen->tile_hud_visible = FALSE; g_timeout_add (250, maybe_hide_snap_osd, screen); } LOCAL_SYMBOL gboolean meta_screen_tile_hud_get_visible (MetaScreen *screen) { return screen->tile_hud_visible; } LOCAL_SYMBOL void meta_screen_hide_hud_and_preview (MetaScreen *screen) { meta_screen_tile_hud_hide (screen); meta_screen_tile_preview_hide (screen); } /** * meta_screen_get_mouse_window: * @screen: an X screen structure. * @not_this_one: (allow-none): window to be excluded * * Gets the #MetaWindow pointed by the mouse * * Return value: (transfer none): the #MetaWindow pointed by the mouse * %NULL when window not found */ MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen, MetaWindow *not_this_one) { MetaWindow *window; GList *windows; Window root_return, child_return; int root_x_return, root_y_return; int win_x_return, win_y_return; unsigned int mask_return; window = NULL; #ifdef WITH_VERBOSE_MODE if (not_this_one) meta_topic (META_DEBUG_FOCUS, "Focusing mouse window excluding %s\n", not_this_one->desc); #endif meta_error_trap_push (screen->display); XQueryPointer (screen->display->xdisplay, screen->xroot, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); meta_error_trap_pop (screen->display); if (screen->active_workspace->showing_desktop) { windows = screen->active_workspace->mru_list; while (windows != NULL) { MetaWindow *w = windows->data; if (w->screen == screen && w->type == META_WINDOW_DESKTOP) { window = w; break; } windows = windows->next; } } else window = meta_stack_get_default_focus_window_at_point (screen->stack, screen->active_workspace, not_this_one, root_x_return, root_y_return); return window; } LOCAL_SYMBOL const MetaMonitorInfo* meta_screen_get_monitor_for_rect (MetaScreen *screen, MetaRectangle *rect) { int i; int best_monitor, monitor_score, rect_area; if (screen->n_monitor_infos == 1) return &screen->monitor_infos[0]; best_monitor = 0; monitor_score = -1; rect_area = meta_rectangle_area (rect); for (i = 0; i < screen->n_monitor_infos; i++) { gboolean result; int cur; if (rect_area > 0) { MetaRectangle dest; result = meta_rectangle_intersect (&screen->monitor_infos[i].rect, rect, &dest); cur = meta_rectangle_area (&dest); } else { result = meta_rectangle_contains_rect (&screen->monitor_infos[i].rect, rect); cur = rect_area; } if (result && cur > monitor_score) { monitor_score = cur; best_monitor = i; } } return &screen->monitor_infos[best_monitor]; } LOCAL_SYMBOL const MetaMonitorInfo* meta_screen_get_monitor_for_window (MetaScreen *screen, MetaWindow *window) { MetaRectangle window_rect; meta_window_get_outer_rect (window, &window_rect); return meta_screen_get_monitor_for_rect (screen, &window_rect); } int meta_screen_get_monitor_index_for_rect (MetaScreen *screen, MetaRectangle *rect) { const MetaMonitorInfo *monitor = meta_screen_get_monitor_for_rect (screen, rect); return monitor->number; } LOCAL_SYMBOL const MetaMonitorInfo* meta_screen_get_monitor_neighbor (MetaScreen *screen, int which_monitor, MetaScreenDirection direction) { MetaMonitorInfo* input = screen->monitor_infos + which_monitor; MetaMonitorInfo* current; int i; for (i = 0; i < screen->n_monitor_infos; i++) { current = screen->monitor_infos + i; if ((direction == META_SCREEN_RIGHT && current->rect.x == input->rect.x + input->rect.width && meta_rectangle_vert_overlap(¤t->rect, &input->rect)) || (direction == META_SCREEN_LEFT && input->rect.x == current->rect.x + current->rect.width && meta_rectangle_vert_overlap(¤t->rect, &input->rect)) || (direction == META_SCREEN_UP && input->rect.y == current->rect.y + current->rect.height && meta_rectangle_horiz_overlap(¤t->rect, &input->rect)) || (direction == META_SCREEN_DOWN && current->rect.y == input->rect.y + input->rect.height && meta_rectangle_horiz_overlap(¤t->rect, &input->rect))) { return current; } } return NULL; } LOCAL_SYMBOL void meta_screen_get_natural_monitor_list (MetaScreen *screen, int** monitors_list, int* n_monitors) { const MetaMonitorInfo* current; const MetaMonitorInfo* tmp; GQueue* monitor_queue; int* visited; int cur = 0; int i; *n_monitors = screen->n_monitor_infos; *monitors_list = g_new (int, screen->n_monitor_infos); /* we calculate a natural ordering by which to choose monitors for * window placement. We start at the current monitor, and perform * a breadth-first search of the monitors starting from that * monitor. We choose preferentially left, then right, then down, * then up. The visitation order produced by this traversal is the * natural monitor ordering. */ visited = g_new (int, screen->n_monitor_infos); for (i = 0; i < screen->n_monitor_infos; i++) { visited[i] = FALSE; } current = meta_screen_get_current_monitor_info (screen); monitor_queue = g_queue_new (); g_queue_push_tail (monitor_queue, (gpointer) current); visited[current->number] = TRUE; while (!g_queue_is_empty (monitor_queue)) { current = (const MetaMonitorInfo*) g_queue_pop_head (monitor_queue); (*monitors_list)[cur++] = current->number; /* enqueue each of the directions */ tmp = meta_screen_get_monitor_neighbor (screen, current->number, META_SCREEN_LEFT); if (tmp && !visited[tmp->number]) { g_queue_push_tail (monitor_queue, (MetaMonitorInfo*) tmp); visited[tmp->number] = TRUE; } tmp = meta_screen_get_monitor_neighbor (screen, current->number, META_SCREEN_RIGHT); if (tmp && !visited[tmp->number]) { g_queue_push_tail (monitor_queue, (MetaMonitorInfo*) tmp); visited[tmp->number] = TRUE; } tmp = meta_screen_get_monitor_neighbor (screen, current->number, META_SCREEN_UP); if (tmp && !visited[tmp->number]) { g_queue_push_tail (monitor_queue, (MetaMonitorInfo*) tmp); visited[tmp->number] = TRUE; } tmp = meta_screen_get_monitor_neighbor (screen, current->number, META_SCREEN_DOWN); if (tmp && !visited[tmp->number]) { g_queue_push_tail (monitor_queue, (MetaMonitorInfo*) tmp); visited[tmp->number] = TRUE; } } /* in case we somehow missed some set of monitors, go through the * visited list and add in any monitors that were missed */ for (i = 0; i < screen->n_monitor_infos; i++) { if (visited[i] == FALSE) { (*monitors_list)[cur++] = i; } } free (visited); g_queue_free (monitor_queue); } const MetaMonitorInfo * meta_screen_get_current_monitor_info (MetaScreen *screen) { int monitor_index; monitor_index = meta_screen_get_current_monitor (screen); return &screen->monitor_infos[monitor_index]; } /** * meta_screen_get_current_monitor: * @screen: a #MetaScreen * * Gets the index of the monitor that currently has the mouse pointer. * * Return value: a monitor index */ int meta_screen_get_current_monitor (MetaScreen *screen) { if (screen->n_monitor_infos == 1) return 0; /* Sadly, we have to do it this way. Yuck. */ if (screen->display->monitor_cache_invalidated) { Window root_return, child_return; int win_x_return, win_y_return; unsigned int mask_return; int i; MetaRectangle pointer_position; screen->display->monitor_cache_invalidated = FALSE; pointer_position.width = pointer_position.height = 1; XQueryPointer (screen->display->xdisplay, screen->xroot, &root_return, &child_return, &pointer_position.x, &pointer_position.y, &win_x_return, &win_y_return, &mask_return); screen->last_monitor_index = 0; for (i = 0; i < screen->n_monitor_infos; i++) { if (meta_rectangle_contains_rect (&screen->monitor_infos[i].rect, &pointer_position)) { screen->last_monitor_index = i; break; } } meta_topic (META_DEBUG_XINERAMA, "Rechecked current monitor, now %d\n", screen->last_monitor_index); } return screen->last_monitor_index; } /** * meta_screen_get_n_monitors: * @screen: a #MetaScreen * * Gets the number of monitors that are joined together to form @screen. * * Return value: the number of monitors */ int meta_screen_get_n_monitors (MetaScreen *screen) { g_return_val_if_fail (META_IS_SCREEN (screen), 0); return screen->n_monitor_infos; } /** * meta_screen_get_primary_monitor: * @screen: a #MetaScreen * * Gets the index of the primary monitor on this @screen. * * Return value: a monitor index */ int meta_screen_get_primary_monitor (MetaScreen *screen) { g_return_val_if_fail (META_IS_SCREEN (screen), 0); return screen->primary_monitor_index; } /** * meta_screen_get_monitor_geometry: * @screen: a #MetaScreen * @monitor: the monitor number * @geometry: (out): location to store the monitor geometry * * Stores the location and size of the indicated monitor in @geometry. */ void meta_screen_get_monitor_geometry (MetaScreen *screen, int monitor, MetaRectangle *geometry) { g_return_if_fail (META_IS_SCREEN (screen)); g_return_if_fail (monitor >= 0 && monitor < screen->n_monitor_infos); g_return_if_fail (geometry != NULL); *geometry = screen->monitor_infos[monitor].rect; } LOCAL_SYMBOL void meta_screen_update_workspace_layout (MetaScreen *screen) { gulong *list; int n_items; if (screen->workspace_layout_overridden) return; list = NULL; n_items = 0; if (meta_prop_get_cardinal_list (screen->display, screen->xroot, screen->display->atom__NET_DESKTOP_LAYOUT, &list, &n_items)) { if (n_items == 3 || n_items == 4) { int cols, rows; switch (list[0]) { case _NET_WM_ORIENTATION_HORZ: screen->vertical_workspaces = FALSE; break; case _NET_WM_ORIENTATION_VERT: screen->vertical_workspaces = TRUE; break; default: meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n"); break; } cols = list[1]; rows = list[2]; if (rows <= 0 && cols <= 0) { meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols); } else { if (rows > 0) screen->rows_of_workspaces = rows; else screen->rows_of_workspaces = -1; if (cols > 0) screen->columns_of_workspaces = cols; else screen->columns_of_workspaces = -1; } if (n_items == 4) { switch (list[3]) { case _NET_WM_TOPLEFT: screen->starting_corner = META_SCREEN_TOPLEFT; break; case _NET_WM_TOPRIGHT: screen->starting_corner = META_SCREEN_TOPRIGHT; break; case _NET_WM_BOTTOMRIGHT: screen->starting_corner = META_SCREEN_BOTTOMRIGHT; break; case _NET_WM_BOTTOMLEFT: screen->starting_corner = META_SCREEN_BOTTOMLEFT; break; default: meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n"); break; } } else screen->starting_corner = META_SCREEN_TOPLEFT; } else { meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 " "(3 is accepted for backwards compat)\n", n_items); } meta_XFree (list); } meta_verbose ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n", screen->rows_of_workspaces, screen->columns_of_workspaces, screen->vertical_workspaces, screen->starting_corner); } /** * meta_screen_override_workspace_layout: * @screen: a #MetaScreen * @starting_corner: the corner at which the first workspace is found * @vertical_layout: if %TRUE the workspaces are laid out in columns rather than rows * @n_rows: number of rows of workspaces, or -1 to determine the number of rows from * @n_columns and the total number of workspaces * @n_columns: number of columns of workspaces, or -1 to determine the number of columns from * @n_rows and the total number of workspaces * * Explicitly set the layout of workspaces. Once this has been called, the contents of the * _NET_DESKTOP_LAYOUT property on the root window are completely ignored. */ void meta_screen_override_workspace_layout (MetaScreen *screen, MetaScreenCorner starting_corner, gboolean vertical_layout, int n_rows, int n_columns) { g_return_if_fail (META_IS_SCREEN (screen)); g_return_if_fail (n_rows > 0 || n_columns > 0); g_return_if_fail (n_rows != 0 && n_columns != 0); screen->workspace_layout_overridden = TRUE; screen->vertical_workspaces = vertical_layout != FALSE; screen->starting_corner = starting_corner; screen->rows_of_workspaces = n_rows; screen->columns_of_workspaces = n_columns; } static void set_workspace_names (MetaScreen *screen) { /* This updates names on root window when the pref changes, * note we only get prefs change notify if things have * really changed. */ GString *flattened; int i; int n_spaces; /* flatten to nul-separated list */ n_spaces = meta_screen_get_n_workspaces (screen); flattened = g_string_new (""); i = 0; while (i < n_spaces) { const char *name; name = meta_prefs_get_workspace_name (i); if (name) g_string_append_len (flattened, name, strlen (name) + 1); else g_string_append_len (flattened, "", 1); ++i; } meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_DESKTOP_NAMES, screen->display->atom_UTF8_STRING, 8, PropModeReplace, (unsigned char *)flattened->str, flattened->len); meta_error_trap_pop (screen->display); g_string_free (flattened, TRUE); } LOCAL_SYMBOL void meta_screen_update_workspace_names (MetaScreen *screen) { char **names; int n_names; int i; /* this updates names in prefs when the root window property changes, * iff the new property contents don't match what's already in prefs */ names = NULL; n_names = 0; if (!meta_prop_get_utf8_list (screen->display, screen->xroot, screen->display->atom__NET_DESKTOP_NAMES, &names, &n_names)) { meta_verbose ("Failed to get workspace names from root window %d\n", screen->number); return; } i = 0; while (i < n_names) { meta_topic (META_DEBUG_PREFS, "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n", i, names[i] ? names[i] : "null"); meta_prefs_change_workspace_name (i, names[i]); ++i; } g_strfreev (names); } LOCAL_SYMBOL Window meta_create_offscreen_window (Display *xdisplay, Window parent, long valuemask) { XSetWindowAttributes attrs; /* we want to be override redirect because sometimes we * create a window on a screen we aren't managing. * (but on a display we are managing at least one screen for) */ attrs.override_redirect = True; attrs.event_mask = valuemask; return XCreateWindow (xdisplay, parent, -100, -100, 1, 1, 0, CopyFromParent, CopyFromParent, (Visual *)CopyFromParent, CWOverrideRedirect | CWEventMask, &attrs); } static void set_work_area_hint (MetaScreen *screen) { int num_workspaces; GList *tmp_list; unsigned long *data, *tmp; MetaRectangle area; num_workspaces = meta_screen_get_n_workspaces (screen); data = g_new (unsigned long, num_workspaces * 4); tmp_list = screen->workspaces; tmp = data; while (tmp_list != NULL) { MetaWorkspace *workspace = tmp_list->data; if (workspace->screen == screen) { meta_workspace_get_work_area_all_monitors (workspace, &area); tmp[0] = area.x; tmp[1] = area.y; tmp[2] = area.width; tmp[3] = area.height; tmp += 4; } tmp_list = tmp_list->next; } meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_WORKAREA, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, num_workspaces*4); free (data); meta_error_trap_pop (screen->display); g_signal_emit (screen, screen_signals[WORKAREAS_CHANGED], 0); } static gboolean set_work_area_later_func (MetaScreen *screen) { meta_topic (META_DEBUG_WORKAREA, "Running work area hint computation function\n"); screen->work_area_later = 0; set_work_area_hint (screen); return FALSE; } LOCAL_SYMBOL void meta_screen_queue_workarea_recalc (MetaScreen *screen) { /* Recompute work area later before redrawing */ if (screen->work_area_later == 0) { meta_topic (META_DEBUG_WORKAREA, "Adding work area hint computation function\n"); screen->work_area_later = meta_later_add (META_LATER_BEFORE_REDRAW, (GSourceFunc) set_work_area_later_func, screen, NULL); } } #ifdef WITH_VERBOSE_MODE static char * meta_screen_corner_to_string (MetaScreenCorner corner) { switch (corner) { case META_SCREEN_TOPLEFT: return "TopLeft"; case META_SCREEN_TOPRIGHT: return "TopRight"; case META_SCREEN_BOTTOMLEFT: return "BottomLeft"; case META_SCREEN_BOTTOMRIGHT: return "BottomRight"; } return "Unknown"; } #endif /* WITH_VERBOSE_MODE */ LOCAL_SYMBOL void meta_screen_calc_workspace_layout (MetaScreen *screen, int num_workspaces, int current_space, MetaWorkspaceLayout *layout) { int rows, cols; int grid_area; int *grid; int i, r, c; int current_row, current_col; rows = screen->rows_of_workspaces; cols = screen->columns_of_workspaces; if (rows <= 0 && cols <= 0) cols = num_workspaces; if (rows <= 0) rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0); if (cols <= 0) cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0); /* paranoia */ if (rows < 1) rows = 1; if (cols < 1) cols = 1; g_assert (rows != 0 && cols != 0); grid_area = rows * cols; meta_verbose ("Getting layout rows = %d cols = %d current = %d " "num_spaces = %d vertical = %s corner = %s\n", rows, cols, current_space, num_workspaces, screen->vertical_workspaces ? "(true)" : "(false)", meta_screen_corner_to_string (screen->starting_corner)); /* ok, we want to setup the distances in the workspace array to go * in each direction. Remember, there are many ways that a workspace * array can be setup. * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html * and look at the _NET_DESKTOP_LAYOUT section for details. * For instance: */ /* starting_corner = META_SCREEN_TOPLEFT * vertical_workspaces = 0 vertical_workspaces=1 * 1234 1357 * 5678 2468 * * starting_corner = META_SCREEN_TOPRIGHT * vertical_workspaces = 0 vertical_workspaces=1 * 4321 7531 * 8765 8642 * * starting_corner = META_SCREEN_BOTTOMLEFT * vertical_workspaces = 0 vertical_workspaces=1 * 5678 2468 * 1234 1357 * * starting_corner = META_SCREEN_BOTTOMRIGHT * vertical_workspaces = 0 vertical_workspaces=1 * 8765 8642 * 4321 7531 * */ /* keep in mind that we could have a ragged layout, e.g. the "8" * in the above grids could be missing */ grid = g_new (int, grid_area); i = 0; switch (screen->starting_corner) { case META_SCREEN_TOPLEFT: if (screen->vertical_workspaces) { c = 0; while (c < cols) { r = 0; while (r < rows) { grid[r*cols+c] = i; ++i; ++r; } ++c; } } else { r = 0; while (r < rows) { c = 0; while (c < cols) { grid[r*cols+c] = i; ++i; ++c; } ++r; } } break; case META_SCREEN_TOPRIGHT: if (screen->vertical_workspaces) { c = cols - 1; while (c >= 0) { r = 0; while (r < rows) { grid[r*cols+c] = i; ++i; ++r; } --c; } } else { r = 0; while (r < rows) { c = cols - 1; while (c >= 0) { grid[r*cols+c] = i; ++i; --c; } ++r; } } break; case META_SCREEN_BOTTOMLEFT: if (screen->vertical_workspaces) { c = 0; while (c < cols) { r = rows - 1; while (r >= 0) { grid[r*cols+c] = i; ++i; --r; } ++c; } } else { r = rows - 1; while (r >= 0) { c = 0; while (c < cols) { grid[r*cols+c] = i; ++i; ++c; } --r; } } break; case META_SCREEN_BOTTOMRIGHT: if (screen->vertical_workspaces) { c = cols - 1; while (c >= 0) { r = rows - 1; while (r >= 0) { grid[r*cols+c] = i; ++i; --r; } --c; } } else { r = rows - 1; while (r >= 0) { c = cols - 1; while (c >= 0) { grid[r*cols+c] = i; ++i; --c; } --r; } } break; } if (i != grid_area) meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n", G_STRFUNC, i); current_row = 0; current_col = 0; r = 0; while (r < rows) { c = 0; while (c < cols) { if (grid[r*cols+c] == current_space) { current_row = r; current_col = c; } else if (grid[r*cols+c] >= num_workspaces) { /* flag nonexistent spaces with -1 */ grid[r*cols+c] = -1; } ++c; } ++r; } layout->rows = rows; layout->cols = cols; layout->grid = grid; layout->grid_area = grid_area; layout->current_row = current_row; layout->current_col = current_col; #ifdef WITH_VERBOSE_MODE if (meta_is_verbose ()) { r = 0; while (r < layout->rows) { meta_verbose (" "); meta_push_no_msg_prefix (); c = 0; while (c < layout->cols) { if (r == layout->current_row && c == layout->current_col) meta_verbose ("*%2d ", layout->grid[r*layout->cols+c]); else meta_verbose ("%3d ", layout->grid[r*layout->cols+c]); ++c; } meta_verbose ("\n"); meta_pop_no_msg_prefix (); ++r; } } #endif /* WITH_VERBOSE_MODE */ } LOCAL_SYMBOL void meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout) { free (layout->grid); } static void meta_screen_resize_func (MetaScreen *screen, MetaWindow *window, void *user_data) { if (window->struts) { meta_window_update_struts (window); } meta_window_queue (window, META_QUEUE_MOVE_RESIZE); meta_window_recalc_features (window); } LOCAL_SYMBOL void meta_screen_resize (MetaScreen *screen, int width, int height) { GSList *windows, *tmp; MetaMonitorInfo *old_monitor_infos; screen->rect.width = width; screen->rect.height = height; /* Save the old monitor infos, so they stay valid during the update */ old_monitor_infos = screen->monitor_infos; reload_monitor_infos (screen); set_desktop_geometry_hint (screen); meta_compositor_sync_screen_size (screen->display->compositor, screen, width, height); /* Queue a resize on all the windows */ meta_screen_foreach_window (screen, meta_screen_resize_func, 0); /* Fix up monitor for all windows on this screen */ windows = meta_display_list_windows (screen->display, META_LIST_INCLUDE_OVERRIDE_REDIRECT); for (tmp = windows; tmp != NULL; tmp = tmp->next) { MetaWindow *window = tmp->data; if (window->screen == screen) meta_window_update_for_monitors_changed (window); } free (old_monitor_infos); g_slist_free (windows); meta_screen_queue_check_fullscreen (screen); g_signal_emit (screen, screen_signals[MONITORS_CHANGED], 0); } LOCAL_SYMBOL void meta_screen_update_showing_desktop_hint (MetaScreen *screen) { unsigned long data[1]; data[0] = screen->active_workspace->showing_desktop ? 1 : 0; meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_SHOWING_DESKTOP, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); meta_error_trap_pop (screen->display); } static void queue_windows_showing (MetaScreen *screen) { GSList *windows; GSList *tmp; /* Must operate on all windows on display instead of just on the * active_workspace's window list, because the active_workspace's * window list may not contain the on_all_workspace windows. */ windows = meta_display_list_windows (screen->display, META_LIST_INCLUDE_OVERRIDE_REDIRECT); tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w->screen == screen) meta_window_queue (w, META_QUEUE_CALC_SHOWING); tmp = tmp->next; } g_slist_free (windows); } LOCAL_SYMBOL void meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen, MetaWindow *keep) { GList *windows; GList *tmp; windows = screen->active_workspace->windows; tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w->screen == screen && w->has_minimize_func && w != keep) meta_window_minimize (w); tmp = tmp->next; } } void meta_screen_toggle_desktop (MetaScreen *screen, guint32 timestamp) { if (screen->active_workspace->showing_desktop) { meta_screen_unshow_desktop (screen); meta_workspace_focus_default_window (screen->active_workspace, NULL, timestamp); } else { meta_screen_show_desktop (screen, timestamp); } } void meta_screen_show_desktop (MetaScreen *screen, guint32 timestamp) { GList *windows; if (screen->active_workspace->showing_desktop) return; screen->active_workspace->showing_desktop = TRUE; queue_windows_showing (screen); /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one; * see bug 159257. */ windows = screen->active_workspace->mru_list; while (windows != NULL) { MetaWindow *w = windows->data; if (w->screen == screen && w->type == META_WINDOW_DESKTOP) { meta_window_focus (w, timestamp); break; } windows = windows->next; } meta_screen_update_showing_desktop_hint (screen); } void meta_screen_unshow_desktop (MetaScreen *screen) { if (!screen->active_workspace->showing_desktop) return; screen->active_workspace->showing_desktop = FALSE; queue_windows_showing (screen); meta_screen_update_showing_desktop_hint (screen); } #ifdef HAVE_STARTUP_NOTIFICATION static gboolean startup_sequence_timeout (void *data); static void update_startup_feedback (MetaScreen *screen) { if (screen->startup_sequences != NULL) { meta_topic (META_DEBUG_STARTUP, "Setting busy cursor\n"); meta_screen_set_cursor (screen, META_CURSOR_BUSY); } else { meta_topic (META_DEBUG_STARTUP, "Setting default cursor\n"); meta_screen_set_cursor (screen, META_CURSOR_DEFAULT); } } static void add_sequence (MetaScreen *screen, SnStartupSequence *sequence) { meta_topic (META_DEBUG_STARTUP, "Adding sequence %s\n", sn_startup_sequence_get_id (sequence)); sn_startup_sequence_ref (sequence); screen->startup_sequences = g_slist_prepend (screen->startup_sequences, sequence); /* our timeout just polls every second, instead of bothering * to compute exactly when we may next time out */ if (screen->startup_sequence_timeout == 0) screen->startup_sequence_timeout = g_timeout_add_seconds (1, startup_sequence_timeout, screen); update_startup_feedback (screen); } static void remove_sequence (MetaScreen *screen, SnStartupSequence *sequence) { meta_topic (META_DEBUG_STARTUP, "Removing sequence %s\n", sn_startup_sequence_get_id (sequence)); screen->startup_sequences = g_slist_remove (screen->startup_sequences, sequence); if (screen->startup_sequences == NULL && screen->startup_sequence_timeout != 0) { g_source_remove (screen->startup_sequence_timeout); screen->startup_sequence_timeout = 0; } update_startup_feedback (screen); sn_startup_sequence_unref (sequence); } typedef struct { GSList *list; GTimeVal now; } CollectTimedOutData; /* This should be fairly long, as it should never be required unless * apps or .desktop files are buggy, and it's confusing if * OpenOffice or whatever seems to stop launching - people * might decide they need to launch it again. */ #define STARTUP_TIMEOUT 15000 static void collect_timed_out_foreach (void *element, void *data) { CollectTimedOutData *ctod = data; SnStartupSequence *sequence = element; long tv_sec, tv_usec; double elapsed; sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec); elapsed = ((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC + (ctod->now.tv_usec - tv_usec))) / 1000.0; meta_topic (META_DEBUG_STARTUP, "Sequence used %g seconds vs. %g max: %s\n", elapsed, (double) STARTUP_TIMEOUT, sn_startup_sequence_get_id (sequence)); if (elapsed > STARTUP_TIMEOUT) ctod->list = g_slist_prepend (ctod->list, sequence); } static gboolean startup_sequence_timeout (void *data) { MetaScreen *screen = data; CollectTimedOutData ctod; GSList *tmp; ctod.list = NULL; g_get_current_time (&ctod.now); g_slist_foreach (screen->startup_sequences, collect_timed_out_foreach, &ctod); tmp = ctod.list; while (tmp != NULL) { SnStartupSequence *sequence = tmp->data; meta_topic (META_DEBUG_STARTUP, "Timed out sequence %s\n", sn_startup_sequence_get_id (sequence)); sn_startup_sequence_complete (sequence); tmp = tmp->next; } g_slist_free (ctod.list); if (screen->startup_sequences != NULL) { return TRUE; } else { /* remove */ screen->startup_sequence_timeout = 0; return FALSE; } } static void meta_screen_sn_event (SnMonitorEvent *event, void *user_data) { MetaScreen *screen; SnStartupSequence *sequence; screen = user_data; sequence = sn_monitor_event_get_startup_sequence (event); sn_startup_sequence_ref (sequence); switch (sn_monitor_event_get_type (event)) { case SN_MONITOR_EVENT_INITIATED: { const char *wmclass; wmclass = sn_startup_sequence_get_wmclass (sequence); meta_topic (META_DEBUG_STARTUP, "Received startup initiated for %s wmclass %s\n", sn_startup_sequence_get_id (sequence), wmclass ? wmclass : "(unset)"); add_sequence (screen, sequence); } break; case SN_MONITOR_EVENT_COMPLETED: { meta_topic (META_DEBUG_STARTUP, "Received startup completed for %s\n", sn_startup_sequence_get_id (sequence)); remove_sequence (screen, sn_monitor_event_get_startup_sequence (event)); } break; case SN_MONITOR_EVENT_CHANGED: meta_topic (META_DEBUG_STARTUP, "Received startup changed for %s\n", sn_startup_sequence_get_id (sequence)); break; case SN_MONITOR_EVENT_CANCELED: meta_topic (META_DEBUG_STARTUP, "Received startup canceled for %s\n", sn_startup_sequence_get_id (sequence)); break; } g_signal_emit (G_OBJECT (screen), screen_signals[STARTUP_SEQUENCE_CHANGED], 0, sequence); sn_startup_sequence_unref (sequence); } /** * meta_screen_get_startup_sequences: (skip) * @screen: * * Return value: (transfer none): Currently active #SnStartupSequence items */ GSList * meta_screen_get_startup_sequences (MetaScreen *screen) { return screen->startup_sequences; } #endif /* Sets the initial_timestamp and initial_workspace properties * of a window according to information given us by the * startup-notification library. * * Returns TRUE if startup properties have been applied, and * FALSE if they have not (for example, if they had already * been applied.) */ LOCAL_SYMBOL gboolean meta_screen_apply_startup_properties (MetaScreen *screen, MetaWindow *window) { #ifdef HAVE_STARTUP_NOTIFICATION const char *startup_id; GSList *tmp; SnStartupSequence *sequence; /* Does the window have a startup ID stored? */ startup_id = meta_window_get_startup_id (window); meta_topic (META_DEBUG_STARTUP, "Applying startup props to %s id \"%s\"\n", window->desc, startup_id ? startup_id : "(none)"); sequence = NULL; if (startup_id == NULL) { /* No startup ID stored for the window. Let's ask the * startup-notification library whether there's anything * stored for the resource name or resource class hints. */ tmp = screen->startup_sequences; while (tmp != NULL) { const char *wmclass; wmclass = sn_startup_sequence_get_wmclass (tmp->data); if (wmclass != NULL && ((window->res_class && strcmp (wmclass, window->res_class) == 0) || (window->res_name && strcmp (wmclass, window->res_name) == 0))) { sequence = tmp->data; g_assert (window->startup_id == NULL); window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence)); startup_id = window->startup_id; meta_topic (META_DEBUG_STARTUP, "Ending legacy sequence %s due to window %s\n", sn_startup_sequence_get_id (sequence), window->desc); sn_startup_sequence_complete (sequence); break; } tmp = tmp->next; } } /* Still no startup ID? Bail. */ if (startup_id == NULL) return FALSE; /* We might get this far and not know the sequence ID (if the window * already had a startup ID stored), so let's look for one if we don't * already know it. */ if (sequence == NULL) { tmp = screen->startup_sequences; while (tmp != NULL) { const char *id; id = sn_startup_sequence_get_id (tmp->data); if (strcmp (id, startup_id) == 0) { sequence = tmp->data; break; } tmp = tmp->next; } } if (sequence != NULL) { gboolean changed_something = FALSE; meta_topic (META_DEBUG_STARTUP, "Found startup sequence for window %s ID \"%s\"\n", window->desc, startup_id); if (!window->initial_workspace_set) { int space = sn_startup_sequence_get_workspace (sequence); if (space >= 0) { meta_topic (META_DEBUG_STARTUP, "Setting initial window workspace to %d based on startup info\n", space); window->initial_workspace_set = TRUE; window->initial_workspace = space; changed_something = TRUE; } } if (!window->initial_timestamp_set) { guint32 timestamp = sn_startup_sequence_get_timestamp (sequence); meta_topic (META_DEBUG_STARTUP, "Setting initial window timestamp to %u based on startup info\n", timestamp); window->initial_timestamp_set = TRUE; window->initial_timestamp = timestamp; changed_something = TRUE; } return changed_something; } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_STARTUP, "Did not find startup sequence for window %s ID \"%s\"\n", window->desc, startup_id); } #endif #endif /* HAVE_STARTUP_NOTIFICATION */ return FALSE; } int meta_screen_get_screen_number (MetaScreen *screen) { return screen->number; } /** * meta_screen_get_display: * Retrieve the display associated with screen. * @screen: A #MetaScreen * * Returns: (transfer none): Display */ MetaDisplay * meta_screen_get_display (MetaScreen *screen) { return screen->display; } /** * meta_screen_get_xroot: (skip) * */ Window meta_screen_get_xroot (MetaScreen *screen) { return screen->xroot; } /** * meta_screen_get_size: * @screen: A #MetaScreen * @width: (out): The width of the screen * @height: (out): The height of the screen * * Retrieve the size of the screen. */ void meta_screen_get_size (MetaScreen *screen, int *width, int *height) { *width = screen->rect.width; *height = screen->rect.height; } void meta_screen_set_cm_selection (MetaScreen *screen) { char selection[32]; Atom a; screen->wm_cm_timestamp = meta_display_get_current_time_roundtrip ( screen->display); g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number); meta_verbose ("Setting selection: %s\n", selection); a = XInternAtom (screen->display->xdisplay, selection, FALSE); XSetSelectionOwner (screen->display->xdisplay, a, screen->wm_cm_selection_window, screen->wm_cm_timestamp); } void meta_screen_unset_cm_selection (MetaScreen *screen) { char selection[32]; Atom a; g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number); a = XInternAtom (screen->display->xdisplay, selection, FALSE); XSetSelectionOwner (screen->display->xdisplay, a, None, screen->wm_cm_timestamp); } /** * meta_screen_get_workspaces: (skip) * @screen: a #MetaScreen * * Returns: (transfer none) (element-type Meta.Workspace): The workspaces for @screen */ GList * meta_screen_get_workspaces (MetaScreen *screen) { return screen->workspaces; } int meta_screen_get_active_workspace_index (MetaScreen *screen) { MetaWorkspace *active = screen->active_workspace; if (!active) return -1; return meta_workspace_index (active); } /** * meta_screen_get_active_workspace: * * Returns: (transfer none): The current workspace */ MetaWorkspace * meta_screen_get_active_workspace (MetaScreen *screen) { return screen->active_workspace; } LOCAL_SYMBOL void meta_screen_restacked (MetaScreen *screen) { g_signal_emit (screen, screen_signals[RESTACKED], 0); } LOCAL_SYMBOL void meta_screen_workspace_switched (MetaScreen *screen, int from, int to, MetaMotionDirection direction) { meta_screen_update_snapped_windows (screen); g_signal_emit (screen, screen_signals[WORKSPACE_SWITCHED], 0, from, to, direction); } LOCAL_SYMBOL void meta_screen_set_active_workspace_hint (MetaScreen *screen) { unsigned long data[1]; /* this is because we destroy the spaces in order, * so we always end up setting a current desktop of * 0 when closing a screen, so lose the current desktop * on restart. By doing this we keep the current * desktop on restart. */ if (screen->closing > 0) return; data[0] = meta_workspace_index (screen->active_workspace); meta_verbose ("Setting _NET_CURRENT_DESKTOP to %lu\n", data[0]); meta_error_trap_push (screen->display); XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom__NET_CURRENT_DESKTOP, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); meta_error_trap_pop (screen->display); } LOCAL_SYMBOL void meta_screen_update_snapped_windows (MetaScreen *screen) { GList* tmp = screen->workspaces; while (tmp) { MetaWorkspace* work = (MetaWorkspace*) tmp->data; meta_workspace_update_snapped_windows (work); tmp = tmp->next; } } static gboolean check_fullscreen_func (gpointer data) { MetaScreen *screen = data; MetaWindow *window; GSList *fullscreen_monitors = NULL; GSList *obscured_monitors = NULL; gboolean in_fullscreen_changed = FALSE; int i; screen->check_fullscreen_later = 0; /* We consider a monitor in fullscreen if it contains a fullscreen window that * is the current top-most window in that monitor. If any window (other than a * dock/toolbar type) is above the fullscreen window, the monitor is no longer * considered to be in fullscreen */ for (window = meta_stack_get_top (screen->stack); window; window = meta_stack_get_below (screen->stack, window, FALSE)) { gboolean covers_monitors = FALSE; if (window->screen != screen || window->hidden || window->xtransient_for) continue; if (window->fullscreen) { covers_monitors = TRUE; } else if (window->override_redirect) { /* We want to handle the case where an application is creating an * override-redirect window the size of the screen (monitor) and treat * it similarly to a fullscreen window, though it doesn't have fullscreen * window management behavior. (Being O-R, it's not managed at all.) */ if (meta_window_is_monitor_sized (window)) covers_monitors = TRUE; } /* Any window type except dock/toolbar that comes before a fullscreen one * will preempt fullscreen for that monitor. */ else if (window->type != META_WINDOW_DOCK && window->type != META_WINDOW_TOOLBAR) { int monitor_index = meta_window_get_monitor (window); /* + 1 to avoid NULL */ gpointer monitor_p = GINT_TO_POINTER(monitor_index + 1); if (!g_slist_find (obscured_monitors, monitor_p)) obscured_monitors = g_slist_prepend (obscured_monitors, monitor_p); } if (covers_monitors) { int *monitors; gsize n_monitors; gsize j; monitors = meta_window_get_all_monitors (window, &n_monitors); for (j = 0; j < n_monitors; j++) { /* + 1 to avoid NULL */ gpointer monitor_p = GINT_TO_POINTER(monitors[j] + 1); if (!g_slist_find (fullscreen_monitors, monitor_p) && !g_slist_find (obscured_monitors, monitor_p)) fullscreen_monitors = g_slist_prepend (fullscreen_monitors, monitor_p); } free (monitors); } } g_slist_free (obscured_monitors); for (i = 0; i < screen->n_monitor_infos; i++) { MetaMonitorInfo *info = &screen->monitor_infos[i]; gboolean in_fullscreen = g_slist_find (fullscreen_monitors, GINT_TO_POINTER (i + 1)) != NULL; if (in_fullscreen != info->in_fullscreen) { info->in_fullscreen = in_fullscreen; in_fullscreen_changed = TRUE; } } g_slist_free (fullscreen_monitors); if (in_fullscreen_changed) { /* DOCK window stacking depends on the monitor's fullscreen status so we need to trigger a re-layering. */ MetaWindow *top_window = meta_stack_get_top (screen->stack); if (top_window) meta_stack_update_layer (screen->stack, top_window); g_signal_emit (screen, screen_signals[IN_FULLSCREEN_CHANGED], 0, NULL); } return FALSE; } void meta_screen_queue_check_fullscreen (MetaScreen *screen) { if (!screen->check_fullscreen_later) screen->check_fullscreen_later = meta_later_add (META_LATER_CHECK_FULLSCREEN, check_fullscreen_func, screen, NULL); } /** * meta_screen_get_monitor_in_fullscreen: * @screen: a #MetaScreen * @monitor: the monitor number * * Determines whether there is a fullscreen window obscuring the specified * monitor. If there is a fullscreen window, the desktop environment will * typically hide any controls that might obscure the fullscreen window. * * You can get notification when this changes by connecting to * MetaScreen::in-fullscreen-changed. * * Returns: %TRUE if there is a fullscreen window covering the specified monitor. */ gboolean meta_screen_get_monitor_in_fullscreen (MetaScreen *screen, int monitor) { g_return_val_if_fail (META_IS_SCREEN (screen), FALSE); g_return_val_if_fail (monitor >= 0 && monitor < screen->n_monitor_infos, FALSE); /* We use -1 as a flag to mean "not known yet" for notification purposes */ return screen->monitor_infos[monitor].in_fullscreen == TRUE; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/eventqueue.h������������������������������������������������������������������0000664�0001750�0001750�00000002620�14211404421�017212� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X event source for main loop */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_EVENT_QUEUE_H #define META_EVENT_QUEUE_H #include <glib.h> #include <X11/Xlib.h> typedef struct _MetaEventQueue MetaEventQueue; typedef void (* MetaEventQueueFunc) (XEvent *event, gpointer data); MetaEventQueue* meta_event_queue_new (Display *display, MetaEventQueueFunc func, gpointer data); void meta_event_queue_free (MetaEventQueue *eq); #endif ����������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/workspace.c�������������������������������������������������������������������0000664�0001750�0001750�00000131623�14211404421�017023� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2003 Rob Adams * Copyright (C) 2004, 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:workspace * @title: MetaWorkspace * @short_description: Workspaces * * A workspace is a set of windows which all live on the same * screen. (You may also see the name "desktop" around the place, * which is the EWMH's name for the same thing.) Only one workspace * of a screen may be active at once; all windows on all other workspaces * are unmapped. */ #include <config.h> #include "screen-private.h" #include <meta/workspace.h> #include "workspace-private.h" #include "boxes-private.h" #include <meta/errors.h> #include <meta/prefs.h> #include <meta/compositor.h> #include <X11/Xatom.h> #include <string.h> #ifdef HAVE_LIBCANBERRA #include <canberra-gtk.h> #endif enum { PROP_0, PROP_N_WINDOWS, }; void meta_workspace_queue_calc_showing (MetaWorkspace *workspace); static void focus_ancestor_or_top_window (MetaWorkspace *workspace, MetaWindow *not_this_one, guint32 timestamp); static void free_this (gpointer candidate, gpointer dummy); G_DEFINE_TYPE (MetaWorkspace, meta_workspace, G_TYPE_OBJECT); enum { WINDOW_ADDED, WINDOW_REMOVED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; static void meta_workspace_finalize (GObject *object) { /* Actual freeing done in meta_workspace_remove() for now */ G_OBJECT_CLASS (meta_workspace_parent_class)->finalize (object); } static void meta_workspace_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_workspace_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MetaWorkspace *ws = META_WORKSPACE (object); switch (prop_id) { case PROP_N_WINDOWS: /* * This is reliable, but not very efficient; should we store * the list lenth ? */ g_value_set_uint (value, g_list_length (ws->windows)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_workspace_class_init (MetaWorkspaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; object_class->finalize = meta_workspace_finalize; object_class->get_property = meta_workspace_get_property; object_class->set_property = meta_workspace_set_property; signals[WINDOW_ADDED] = g_signal_new ("window-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); signals[WINDOW_REMOVED] = g_signal_new ("window-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); pspec = g_param_spec_uint ("n-windows", "N Windows", "Number of windows", 0, G_MAXUINT, 0, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_N_WINDOWS, pspec); } static void meta_workspace_init (MetaWorkspace *workspace) { } static void maybe_add_to_list (MetaScreen *screen, MetaWindow *window, gpointer data) { GList **mru_list = data; if (window->on_all_workspaces) *mru_list = g_list_prepend (*mru_list, window); } LOCAL_SYMBOL MetaWorkspace* meta_workspace_new (MetaScreen *screen) { MetaWorkspace *workspace; workspace = g_object_new (META_TYPE_WORKSPACE, NULL); workspace->screen = screen; workspace->screen->workspaces = g_list_append (workspace->screen->workspaces, workspace); workspace->windows = NULL; workspace->mru_list = NULL; meta_screen_foreach_window (screen, maybe_add_to_list, &workspace->mru_list); workspace->work_areas_invalid = TRUE; workspace->work_area_monitor = NULL; workspace->work_area_screen.x = 0; workspace->work_area_screen.y = 0; workspace->work_area_screen.width = 0; workspace->work_area_screen.height = 0; workspace->screen_region = NULL; workspace->monitor_region = NULL; workspace->screen_edges = NULL; workspace->monitor_edges = NULL; workspace->list_containing_self = g_list_prepend (NULL, workspace); workspace->snapped_windows = NULL; workspace->builtin_struts = NULL; workspace->all_struts = NULL; workspace->showing_desktop = FALSE; return workspace; } /* Foreach function for workspace_free_struts() */ static void free_this (gpointer candidate, gpointer dummy) { free (candidate); } /* * Frees the combined struts list of a workspace. * * \param workspace The workspace. */ static void workspace_free_all_struts (MetaWorkspace *workspace) { if (workspace->all_struts == NULL) return; g_slist_foreach (workspace->all_struts, free_this, NULL); g_slist_free (workspace->all_struts); workspace->all_struts = NULL; } /* * Frees the struts list set with meta_workspace_set_builtin_struts * * \param workspace The workspace. */ static void workspace_free_builtin_struts (MetaWorkspace *workspace) { if (workspace->builtin_struts == NULL) return; g_slist_foreach (workspace->builtin_struts, free_this, NULL); g_slist_free (workspace->builtin_struts); workspace->builtin_struts = NULL; } LOCAL_SYMBOL void meta_workspace_remove (MetaWorkspace *workspace) { GList *tmp; MetaScreen *screen; int i; g_return_if_fail (workspace != workspace->screen->active_workspace); /* Here we assume all the windows are already on another workspace * as well, so they won't be "orphaned" */ tmp = workspace->windows; while (tmp != NULL) { GList *next; MetaWindow *window = tmp->data; next = tmp->next; /* pop front of list we're iterating over */ meta_workspace_remove_window (workspace, window); g_assert (window->workspace != NULL); tmp = next; } g_assert (workspace->windows == NULL); screen = workspace->screen; workspace->screen->workspaces = g_list_remove (workspace->screen->workspaces, workspace); free (workspace->work_area_monitor); g_list_free (workspace->mru_list); g_list_free (workspace->list_containing_self); workspace_free_builtin_struts (workspace); /* screen.c:update_num_workspaces(), which calls us, removes windows from * workspaces first, which can cause the workareas on the workspace to be * invalidated (and hence for struts/regions/edges to be freed). * So, no point trying to double free it; that causes a crash * anyway. #361804. */ if (!workspace->work_areas_invalid) { workspace_free_all_struts (workspace); for (i = 0; i < screen->n_monitor_infos; i++) meta_rectangle_free_list_and_elements (workspace->monitor_region[i]); free (workspace->monitor_region); meta_rectangle_free_list_and_elements (workspace->screen_region); meta_rectangle_free_list_and_elements (workspace->screen_edges); meta_rectangle_free_list_and_elements (workspace->monitor_edges); } g_object_unref (workspace); /* don't bother to reset names, pagers can just ignore * extra ones */ } LOCAL_SYMBOL void meta_workspace_add_window (MetaWorkspace *workspace, MetaWindow *window) { g_return_if_fail (window->workspace == NULL); /* If the window is on all workspaces, we want to add it to all mru * lists, otherwise just add it to this workspaces mru list */ if (window->on_all_workspaces) { if (window->workspace == NULL) { GList* tmp = window->screen->workspaces; while (tmp) { MetaWorkspace* work = (MetaWorkspace*) tmp->data; if (!g_list_find (work->mru_list, window)) work->mru_list = g_list_prepend (work->mru_list, window); tmp = tmp->next; } } } else { g_assert (g_list_find (workspace->mru_list, window) == NULL); workspace->mru_list = g_list_prepend (workspace->mru_list, window); } workspace->windows = g_list_prepend (workspace->windows, window); window->workspace = workspace; meta_window_set_current_workspace_hint (window); if (window->struts) { meta_topic (META_DEBUG_WORKAREA, "Invalidating work area of workspace %d since we're adding window %s to it\n", meta_workspace_index (workspace), window->desc); meta_workspace_invalidate_work_area (workspace); } /* queue a move_resize since changing workspaces may change * the relevant struts */ meta_window_queue (window, META_QUEUE_CALC_SHOWING|META_QUEUE_MOVE_RESIZE); g_signal_emit (workspace, signals[WINDOW_ADDED], 0, window); g_object_notify (G_OBJECT (workspace), "n-windows"); } LOCAL_SYMBOL void meta_workspace_remove_window (MetaWorkspace *workspace, MetaWindow *window) { g_return_if_fail (window->workspace == workspace); workspace->windows = g_list_remove (workspace->windows, window); window->workspace = NULL; /* If the window is on all workspaces, we don't want to remove it * from the MRU list unless this causes it to be removed from all * workspaces */ if (window->on_all_workspaces) { GList* tmp = window->screen->workspaces; while (tmp) { MetaWorkspace* work = (MetaWorkspace*) tmp->data; work->mru_list = g_list_remove (work->mru_list, window); tmp = tmp->next; } } else { workspace->mru_list = g_list_remove (workspace->mru_list, window); g_assert (g_list_find (workspace->mru_list, window) == NULL); } meta_window_set_current_workspace_hint (window); if (window->struts) { meta_topic (META_DEBUG_WORKAREA, "Invalidating work area of workspace %d since we're removing window %s from it\n", meta_workspace_index (workspace), window->desc); meta_workspace_invalidate_work_area (workspace); } /* queue a move_resize since changing workspaces may change * the relevant struts */ meta_window_queue (window, META_QUEUE_CALC_SHOWING|META_QUEUE_MOVE_RESIZE); g_signal_emit (workspace, signals[WINDOW_REMOVED], 0, window); g_object_notify (G_OBJECT (workspace), "n-windows"); } LOCAL_SYMBOL void meta_workspace_relocate_windows (MetaWorkspace *workspace, MetaWorkspace *new_home) { GList *tmp; GList *copy; g_return_if_fail (workspace != new_home); /* can't modify list we're iterating over */ copy = g_list_copy (workspace->windows); tmp = copy; while (tmp != NULL) { MetaWindow *window = tmp->data; meta_workspace_remove_window (workspace, window); meta_workspace_add_window (new_home, window); tmp = tmp->next; } g_list_free (copy); g_assert (workspace->windows == NULL); } LOCAL_SYMBOL void meta_workspace_queue_calc_showing (MetaWorkspace *workspace) { GList *tmp; tmp = workspace->windows; while (tmp != NULL) { meta_window_queue (tmp->data, META_QUEUE_CALC_SHOWING); tmp = tmp->next; } } static void workspace_switch_sound(MetaWorkspace *from, MetaWorkspace *to) { #ifdef HAVE_LIBCANBERRA MetaWorkspaceLayout layout; int i, nw, x, y, fi, ti; const char *e; nw = meta_screen_get_n_workspaces(from->screen); fi = meta_workspace_index(from); ti = meta_workspace_index(to); meta_screen_calc_workspace_layout(from->screen, nw, fi, &layout); for (i = 0; i < nw; i++) if (layout.grid[i] == ti) break; if (i >= nw) { meta_bug("Failed to find destination workspace in layout\n"); goto finish; } y = i / layout.cols; x = i % layout.cols; /* We priorize horizontal over vertical movements here. The rationale for this is that horizontal movements are probably more interesting for sound effects because speakers are usually positioned on a horizontal and not a vertical axis. i.e. your spatial "Woosh!" effects will easily be able to encode horizontal movement but not such much vertical movement. */ if (x < layout.current_col) e = "desktop-switch-left"; else if (x > layout.current_col) e = "desktop-switch-right"; else if (y < layout.current_row) e = "desktop-switch-up"; else if (y > layout.current_row) e = "desktop-switch-down"; else { meta_bug("Uh, origin and destination workspace at same logic position!\n"); goto finish; } ca_context_play(ca_gtk_context_get(), 1, CA_PROP_EVENT_ID, e, CA_PROP_EVENT_DESCRIPTION, "Desktop switched", CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", NULL); finish: meta_screen_free_workspace_layout (&layout); #endif /* HAVE_LIBCANBERRA */ } static MetaMotionDirection get_wrapped_horizontal_direction (gint from, gint to, MetaMotionDirection suggested_dir, gint num_workspaces) { MetaMotionDirection ret = 0; gboolean wrap = meta_prefs_get_workspace_cycle(); if (suggested_dir != 0 && wrap) { if (meta_ui_get_direction () == META_UI_DIRECTION_RTL) { if (suggested_dir == META_MOTION_LEFT) suggested_dir = META_MOTION_RIGHT; else if (suggested_dir == META_MOTION_RIGHT) suggested_dir = META_MOTION_LEFT; } return suggested_dir; } if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) { if (from < to) if (wrap) ret = (to - from) <= ((num_workspaces - to) + from) ? META_MOTION_LEFT : META_MOTION_RIGHT; else ret = META_MOTION_LEFT; else if (from > to) if (wrap) ret = (from - to) <= ((num_workspaces - from) + to) ? META_MOTION_RIGHT : META_MOTION_LEFT; else ret = META_MOTION_RIGHT; } else { if (from < to) if (wrap) ret = (to - from) <= ((num_workspaces - to) + from) ? META_MOTION_RIGHT : META_MOTION_LEFT; else ret = META_MOTION_RIGHT; else if (from > to) if (wrap) ret = (from - to) <= ((num_workspaces - from) + to) ? META_MOTION_LEFT : META_MOTION_RIGHT; else ret = META_MOTION_LEFT; } return ret; } static void meta_workspace_activate_internal (MetaWorkspace *workspace, MetaWindow *focus_this, MetaMotionDirection suggested_dir, guint32 timestamp) { MetaWorkspace *old; MetaWindow *move_window; MetaScreen *screen; MetaDisplay *display; MetaCompositor *comp; MetaWorkspaceLayout layout1, layout2; gint num_workspaces, current_space, new_space; MetaMotionDirection direction; meta_verbose ("Activating workspace %d\n", meta_workspace_index (workspace)); if (workspace->screen->active_workspace == workspace) return; /* Free any cached pointers to the workspaces's edges from * a current resize or move operation */ meta_display_cleanup_edges (workspace->screen->display); if (workspace->screen->active_workspace) workspace_switch_sound (workspace->screen->active_workspace, workspace); /* Note that old can be NULL; e.g. when starting up */ old = workspace->screen->active_workspace; workspace->screen->active_workspace = workspace; meta_screen_set_active_workspace_hint (workspace->screen); /* If the "show desktop" mode is active for either the old workspace * or the new one *but not both*, then update the * _net_showing_desktop hint */ if (old && (old->showing_desktop ^ workspace->showing_desktop)) meta_screen_update_showing_desktop_hint (workspace->screen); if (old == NULL) return; move_window = NULL; if (workspace->screen->display->grab_op == META_GRAB_OP_MOVING || workspace->screen->display->grab_op == META_GRAB_OP_KEYBOARD_MOVING) move_window = workspace->screen->display->grab_window; if (move_window != NULL) { if (move_window->on_all_workspaces) move_window = NULL; /* don't move it after all */ /* We put the window on the new workspace, flip spaces, * then remove from old workspace, so the window * never gets unmapped and we maintain the button grab * on it. * * \bug This comment appears to be the reverse of what happens */ if (move_window && (move_window->workspace != workspace)) { meta_workspace_remove_window (old, move_window); meta_workspace_add_window (workspace, move_window); } } meta_workspace_queue_calc_showing (old); meta_workspace_queue_calc_showing (workspace); /* FIXME: Why do we need this?!? Isn't it handled in the lines above? */ if (move_window) /* Removes window from other spaces */ meta_window_change_workspace (move_window, workspace); /* * Notify the compositor that the active workspace is changing. */ screen = workspace->screen; display = meta_screen_get_display (screen); comp = meta_display_get_compositor (display); direction = 0; current_space = meta_workspace_index (old); new_space = meta_workspace_index (workspace); num_workspaces = meta_screen_get_n_workspaces (workspace->screen); meta_screen_calc_workspace_layout (workspace->screen, num_workspaces, current_space, &layout1); meta_screen_calc_workspace_layout (workspace->screen, num_workspaces, new_space, &layout2); direction = get_wrapped_horizontal_direction (layout1.current_col, layout2.current_col, suggested_dir, num_workspaces); if (layout1.current_row < layout2.current_row) { if (!direction) direction = META_MOTION_DOWN; else if (direction == META_MOTION_RIGHT) direction = META_MOTION_DOWN_RIGHT; else direction = META_MOTION_DOWN_LEFT; } if (layout1.current_row > layout2.current_row) { if (!direction) direction = META_MOTION_UP; else if (direction == META_MOTION_RIGHT) direction = META_MOTION_UP_RIGHT; else direction = META_MOTION_UP_LEFT; } meta_screen_free_workspace_layout (&layout1); meta_screen_free_workspace_layout (&layout2); if (comp != NULL) { meta_compositor_switch_workspace (comp, screen, old, workspace, direction); } /* This needs to be done after telling the compositor we are switching * workspaces since focusing a window will cause it to be immediately * shown and that would confuse the compositor if it didn't know we * were in a workspace switch. */ if (focus_this) { meta_window_activate (focus_this, timestamp); } else if (move_window) { meta_window_raise (move_window); } else { meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n"); meta_workspace_focus_default_window (workspace, NULL, timestamp); } /* Emit switched signal from screen.c */ meta_screen_workspace_switched (screen, current_space, new_space, direction); } /** * meta_workspace_activate_with_focus: * @workspace: a #MetaWorkspace * @focus_this: the #MetaWindow to be focused, or %NULL * @timestamp: timestamp for @focus_this * * Switches to @workspace and possibly activates the window @focus_this. * * The window @focus_this is activated by calling meta_window_activate() * which will unminimize it and transient parents, raise it and give it * the focus. * * If a window is currently being moved by the user, it will be * moved to @workspace. * * The advantage of calling this function instead of meta_workspace_activate() * followed by meta_window_activate() is that it happens as a unit, so * no other window gets focused first before @focus_this. */ void meta_workspace_activate_with_focus (MetaWorkspace *workspace, MetaWindow *focus_this, guint32 timestamp) { g_return_if_fail (META_IS_WORKSPACE (workspace)); meta_workspace_activate_internal (workspace, focus_this, 0, timestamp); } void meta_workspace_activate (MetaWorkspace *workspace, guint32 timestamp) { g_return_if_fail (META_IS_WORKSPACE (workspace)); meta_workspace_activate_internal (workspace, NULL, 0, timestamp); } /** * meta_workspace_activate_with_direction_hint: * @workspace: a #MetaWorkspace * @direction: the suggested #MetaMotionDirection * @timestamp: timestamp for @focus_this * * Switches to @workspace in the specified @direction (if possible) */ void meta_workspace_activate_with_direction_hint (MetaWorkspace *workspace, MetaMotionDirection direction, guint32 timestamp) { g_return_if_fail (META_IS_WORKSPACE (workspace)); meta_workspace_activate_internal (workspace, NULL, direction, timestamp); } int meta_workspace_index (MetaWorkspace *workspace) { g_return_val_if_fail (META_IS_WORKSPACE (workspace), 0); int ret = g_list_index (workspace->screen->workspaces, workspace); /* return value is negative if the workspace is invalid */ return ret; } void meta_workspace_update_window_hints (MetaWorkspace *workspace) { g_return_if_fail (META_IS_WORKSPACE (workspace)); GList *l = workspace->windows; while (l) { MetaWindow *win = l->data; meta_window_set_current_workspace_hint (win); l = l->next; } } /** * meta_workspace_list_windows: * @workspace: a #MetaWorkspace * * Gets windows contained on the workspace, including workspace->windows * and also sticky windows. Override-redirect windows are not included. * * Return value: (transfer container) (element-type MetaWindow): the list of windows. */ GList* meta_workspace_list_windows (MetaWorkspace *workspace) { g_return_val_if_fail (META_IS_WORKSPACE (workspace), NULL); GSList *display_windows; GSList *tmp; GList *workspace_windows; display_windows = meta_display_list_windows (workspace->screen->display, META_LIST_DEFAULT); workspace_windows = NULL; tmp = display_windows; while (tmp != NULL) { MetaWindow *window = tmp->data; if (meta_window_located_on_workspace (window, workspace)) workspace_windows = g_list_prepend (workspace_windows, window); tmp = tmp->next; } g_slist_free (display_windows); return workspace_windows; } LOCAL_SYMBOL void meta_workspace_invalidate_work_area (MetaWorkspace *workspace) { GList *tmp; GList *windows; int i; if (workspace->work_areas_invalid) { meta_topic (META_DEBUG_WORKAREA, "Work area for workspace %d is already invalid\n", meta_workspace_index (workspace)); return; } meta_topic (META_DEBUG_WORKAREA, "Invalidating work area for workspace %d\n", meta_workspace_index (workspace)); /* If we are in the middle of a resize or move operation, we * might have cached pointers to the workspace's edges */ if (workspace == workspace->screen->active_workspace) meta_display_cleanup_edges (workspace->screen->display); free (workspace->work_area_monitor); workspace->work_area_monitor = NULL; workspace_free_all_struts (workspace); for (i = 0; i < workspace->screen->n_monitor_infos; i++) meta_rectangle_free_list_and_elements (workspace->monitor_region[i]); free (workspace->monitor_region); meta_rectangle_free_list_and_elements (workspace->screen_region); meta_rectangle_free_list_and_elements (workspace->screen_edges); meta_rectangle_free_list_and_elements (workspace->monitor_edges); workspace->monitor_region = NULL; workspace->screen_region = NULL; workspace->screen_edges = NULL; workspace->monitor_edges = NULL; workspace->work_areas_invalid = TRUE; /* redo the size/position constraints on all windows */ windows = meta_workspace_list_windows (workspace); tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; meta_window_queue (w, META_QUEUE_MOVE_RESIZE); tmp = tmp->next; } g_list_free (windows); meta_screen_queue_workarea_recalc (workspace->screen); } static MetaStrut * copy_strut(MetaStrut *original) { return g_memdup(original, sizeof(MetaStrut)); } static GSList * copy_strut_list(GSList *original) { GSList *result = NULL; while (original) { result = g_slist_prepend (result, copy_strut (original->data)); original = original->next; } return g_slist_reverse (result); } static void ensure_work_areas_validated (MetaWorkspace *workspace) { GList *windows; GList *tmp; MetaRectangle work_area; int i; /* C89 absolutely sucks... */ if (!workspace->work_areas_invalid) return; g_assert (workspace->all_struts == NULL); g_assert (workspace->monitor_region == NULL); g_assert (workspace->screen_region == NULL); g_assert (workspace->screen_edges == NULL); g_assert (workspace->monitor_edges == NULL); /* STEP 1: Get the list of struts */ workspace->all_struts = copy_strut_list (workspace->builtin_struts); windows = meta_workspace_list_windows (workspace); for (tmp = windows; tmp != NULL; tmp = tmp->next) { MetaWindow *win = tmp->data; GSList *s_iter; for (s_iter = win->struts; s_iter != NULL; s_iter = s_iter->next) { workspace->all_struts = g_slist_prepend (workspace->all_struts, copy_strut(s_iter->data)); } } g_list_free (windows); /* STEP 2: Get the maximal/spanning rects for the onscreen and * on-single-monitor regions */ g_assert (workspace->monitor_region == NULL); g_assert (workspace->screen_region == NULL); workspace->monitor_region = g_new (GList*, workspace->screen->n_monitor_infos); for (i = 0; i < workspace->screen->n_monitor_infos; i++) { workspace->monitor_region[i] = meta_rectangle_get_minimal_spanning_set_for_region ( &workspace->screen->monitor_infos[i].rect, workspace->all_struts); } workspace->screen_region = meta_rectangle_get_minimal_spanning_set_for_region ( &workspace->screen->rect, workspace->all_struts); /* STEP 3: Get the work areas (region-to-maximize-to) for the screen and * monitors. */ work_area = workspace->screen->rect; /* start with the screen */ if (workspace->screen_region == NULL) work_area = meta_rect (0, 0, -1, -1); else meta_rectangle_clip_to_region (workspace->screen_region, FIXED_DIRECTION_NONE, &work_area); /* Lots of paranoia checks, forcing work_area_screen to be sane */ #define MIN_SANE_AREA 100 if (work_area.width < MIN_SANE_AREA) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining width = %d < %d", work_area.width, MIN_SANE_AREA); if (work_area.width < 1) { work_area.x = (workspace->screen->rect.width - MIN_SANE_AREA)/2; work_area.width = MIN_SANE_AREA; } else { int amount = (MIN_SANE_AREA - work_area.width)/2; work_area.x -= amount; work_area.width += 2*amount; } } if (work_area.height < MIN_SANE_AREA) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining height = %d < %d", work_area.height, MIN_SANE_AREA); if (work_area.height < 1) { work_area.y = (workspace->screen->rect.height - MIN_SANE_AREA)/2; work_area.height = MIN_SANE_AREA; } else { int amount = (MIN_SANE_AREA - work_area.height)/2; work_area.y -= amount; work_area.height += 2*amount; } } workspace->work_area_screen = work_area; meta_topic (META_DEBUG_WORKAREA, "Computed work area for workspace %d: %d,%d %d x %d\n", meta_workspace_index (workspace), workspace->work_area_screen.x, workspace->work_area_screen.y, workspace->work_area_screen.width, workspace->work_area_screen.height); /* Now find the work areas for each monitor */ free (workspace->work_area_monitor); workspace->work_area_monitor = g_new (MetaRectangle, workspace->screen->n_monitor_infos); for (i = 0; i < workspace->screen->n_monitor_infos; i++) { work_area = workspace->screen->monitor_infos[i].rect; if (workspace->monitor_region[i] == NULL) /* FIXME: constraints.c untested with this, but it might be nice for * a screen reader or magnifier. */ work_area = meta_rect (work_area.x, work_area.y, -1, -1); else meta_rectangle_clip_to_region (workspace->monitor_region[i], FIXED_DIRECTION_NONE, &work_area); workspace->work_area_monitor[i] = work_area; meta_topic (META_DEBUG_WORKAREA, "Computed work area for workspace %d " "monitor %d: %d,%d %d x %d\n", meta_workspace_index (workspace), i, workspace->work_area_monitor[i].x, workspace->work_area_monitor[i].y, workspace->work_area_monitor[i].width, workspace->work_area_monitor[i].height); } /* STEP 4: Make sure the screen_region is nonempty (separate from step 2 * since it relies on step 3). */ if (workspace->screen_region == NULL) { MetaRectangle *nonempty_region; nonempty_region = g_new (MetaRectangle, 1); *nonempty_region = workspace->work_area_screen; workspace->screen_region = g_list_prepend (NULL, nonempty_region); } /* STEP 5: Cache screen and monitor edges for edge resistance and snapping */ g_assert (workspace->screen_edges == NULL); g_assert (workspace->monitor_edges == NULL); workspace->screen_edges = meta_rectangle_find_onscreen_edges (&workspace->screen->rect, workspace->all_struts); tmp = NULL; for (i = 0; i < workspace->screen->n_monitor_infos; i++) tmp = g_list_prepend (tmp, &workspace->screen->monitor_infos[i].rect); workspace->monitor_edges = meta_rectangle_find_nonintersected_monitor_edges (tmp, workspace->all_struts); g_list_free (tmp); /* We're all done, YAAY! Record that everything has been validated. */ workspace->work_areas_invalid = FALSE; } static gboolean strut_lists_equal (GSList *l, GSList *m) { for (; l && m; l = l->next, m = m->next) { MetaStrut *a = l->data; MetaStrut *b = m->data; if (a->side != b->side || !meta_rectangle_equal (&a->rect, &b->rect)) return FALSE; } return l == NULL && m == NULL; } /** * meta_workspace_set_builtin_struts: * @workspace: a #MetaWorkspace * @struts: (element-type Meta.Strut) (transfer none): list of #MetaStrut * * Sets a list of struts that will be used in addition to the struts * of the windows in the workspace when computing the work area of * the workspace. */ void meta_workspace_set_builtin_struts (MetaWorkspace *workspace, GSList *struts) { MetaScreen *screen = workspace->screen; GSList *l; for (l = struts; l; l = l->next) { MetaStrut *strut = l->data; int idx = meta_screen_get_monitor_index_for_rect (screen, &strut->rect); switch (strut->side) { case META_SIDE_TOP: if (meta_screen_get_monitor_neighbor (screen, idx, META_SCREEN_UP)) continue; strut->rect.height += strut->rect.y; strut->rect.y = 0; break; case META_SIDE_BOTTOM: if (meta_screen_get_monitor_neighbor (screen, idx, META_SCREEN_DOWN)) continue; strut->rect.height = screen->rect.height - strut->rect.y; break; case META_SIDE_LEFT: if (meta_screen_get_monitor_neighbor (screen, idx, META_SCREEN_LEFT)) continue; strut->rect.width += strut->rect.x; strut->rect.x = 0; break; case META_SIDE_RIGHT: if (meta_screen_get_monitor_neighbor (screen, idx, META_SCREEN_RIGHT)) continue; strut->rect.width = screen->rect.width - strut->rect.x; break; } } /* Reordering doesn't actually matter, so we don't catch all * no-impact changes, but this is just a (possibly unnecessary * anyways) optimization */ if (strut_lists_equal (struts, workspace->builtin_struts)) return; workspace_free_builtin_struts (workspace); workspace->builtin_struts = copy_strut_list (struts); meta_workspace_invalidate_work_area (workspace); } void meta_workspace_update_snapped_windows (MetaWorkspace *workspace) { GList *window_list = meta_workspace_list_windows (workspace); GList *old = workspace->snapped_windows; workspace->snapped_windows = NULL; GList *iter; MetaWindow *window; for (iter = window_list; iter != NULL; iter = iter->next) { window = (MetaWindow *) iter->data; if (window->tile_type == META_WINDOW_TILE_TYPE_SNAPPED) workspace->snapped_windows = g_list_prepend (workspace->snapped_windows, window); } g_list_free (old); g_list_free (window_list); meta_workspace_recalc_for_snapped_windows (workspace); } gboolean meta_workspace_has_snapped_windows (MetaWorkspace *workspace) { return g_list_length (workspace->snapped_windows) > 0; } void meta_workspace_recalc_for_snapped_windows (MetaWorkspace *workspace) { GList *window_list = meta_workspace_list_windows (workspace); GList *iter; MetaWindow *win; for (iter = window_list; iter != NULL; iter = iter->next) { win = META_WINDOW (iter->data); if (meta_window_get_maximized (win)) { meta_window_queue(win, META_QUEUE_MOVE_RESIZE); } } g_list_free (window_list); } /** * meta_workspace_get_work_area_for_monitor: * @workspace: a #MetaWorkspace * @which_monitor: a monitor index * @area: (out): location to store the work area * * Stores the work area for @which_monitor on @workspace * in @area. */ void meta_workspace_get_work_area_for_monitor (MetaWorkspace *workspace, int which_monitor, MetaRectangle *area) { g_assert (which_monitor >= 0); ensure_work_areas_validated (workspace); g_assert (which_monitor < workspace->screen->n_monitor_infos); *area = workspace->work_area_monitor[which_monitor]; } void meta_workspace_get_work_area_all_monitors (MetaWorkspace *workspace, MetaRectangle *area) { ensure_work_areas_validated (workspace); *area = workspace->work_area_screen; } LOCAL_SYMBOL GList* meta_workspace_get_onscreen_region (MetaWorkspace *workspace) { ensure_work_areas_validated (workspace); return workspace->screen_region; } LOCAL_SYMBOL GList* meta_workspace_get_onmonitor_region (MetaWorkspace *workspace, int which_monitor) { ensure_work_areas_validated (workspace); return workspace->monitor_region[which_monitor]; } #ifdef WITH_VERBOSE_MODE static char * meta_motion_direction_to_string (MetaMotionDirection direction) { switch (direction) { case META_MOTION_UP: return "Up"; case META_MOTION_DOWN: return "Down"; case META_MOTION_LEFT: return "Left"; case META_MOTION_RIGHT: return "Right"; case META_MOTION_UP_RIGHT: return "Up-Right"; case META_MOTION_DOWN_RIGHT: return "Down-Right"; case META_MOTION_UP_LEFT: return "Up-Left"; case META_MOTION_DOWN_LEFT: return "Down-Left"; case META_MOTION_NOT_EXIST_YET: return "Nothing"; } return "Unknown"; } #endif /* WITH_VERBOSE_MODE */ /** * meta_workspace_get_neighbor: * @workspace: a #MetaWorkspace * @direction: a #MetaMotionDirection, direction in which to look for the neighbor * * Gets the neighbor of the #MetaWorkspace in the given direction * * Return value: (transfer none): the neighbor #MetaWorkspace */ MetaWorkspace* meta_workspace_get_neighbor (MetaWorkspace *workspace, MetaMotionDirection direction) { MetaWorkspaceLayout layout; int i, current_space, num_workspaces; gboolean ltr, cycle; current_space = meta_workspace_index (workspace); num_workspaces = meta_screen_get_n_workspaces (workspace->screen); meta_screen_calc_workspace_layout (workspace->screen, num_workspaces, current_space, &layout); cycle = meta_prefs_get_workspace_cycle(); meta_verbose ("Getting neighbor of %d in direction %s\n", current_space, meta_motion_direction_to_string (direction)); ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR; switch (direction) { case META_MOTION_LEFT: layout.current_col -= ltr ? 1 : -1; break; case META_MOTION_RIGHT: layout.current_col += ltr ? 1 : -1; break; case META_MOTION_UP: layout.current_row -= 1; break; case META_MOTION_DOWN: layout.current_row += 1; break; default:; } if (layout.current_col < 0) layout.current_col = (cycle == 1)? layout.cols - 1 : 0; if (layout.current_col >= layout.cols) layout.current_col = (cycle == 1)? 0 : layout.cols - 1; if (layout.current_row < 0) layout.current_row = 0; if (layout.current_row >= layout.rows) layout.current_row = layout.rows - 1; i = layout.grid[layout.current_row * layout.cols + layout.current_col]; if (i < 0) i = current_space; if (i >= num_workspaces) meta_bug ("calc_workspace_layout left an invalid (too-high) workspace number %d in the grid\n", i); meta_verbose ("Neighbor workspace is %d at row %d col %d\n", i, layout.current_row, layout.current_col); meta_screen_free_workspace_layout (&layout); return meta_screen_get_workspace_by_index (workspace->screen, i); } LOCAL_SYMBOL const char* meta_workspace_get_name (MetaWorkspace *workspace) { return meta_prefs_get_workspace_name (meta_workspace_index (workspace)); } void meta_workspace_focus_default_window (MetaWorkspace *workspace, MetaWindow *not_this_one, guint32 timestamp) { if (timestamp == CurrentTime) { meta_warning ("CurrentTime used to choose focus window; " "focus window may not be correct.\n"); } if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK || !workspace->screen->display->mouse_mode) focus_ancestor_or_top_window (workspace, not_this_one, timestamp); else { MetaWindow * window; window = meta_screen_get_mouse_window (workspace->screen, not_this_one); if (window && window->type != META_WINDOW_DOCK && window->type != META_WINDOW_DESKTOP) { if (timestamp == CurrentTime) { /* We would like for this to never happen. However, if * it does happen then we kludge since using CurrentTime * can mean ugly race conditions--and we can avoid these * by allowing EnterNotify events (which come with * timestamps) to handle focus. */ meta_topic (META_DEBUG_FOCUS, "Not focusing mouse window %s because EnterNotify events should handle that\n", window->desc); } else { meta_topic (META_DEBUG_FOCUS, "Focusing mouse window %s\n", window->desc); meta_window_focus (window, timestamp); } if (workspace->screen->display->autoraise_window != window && meta_prefs_get_auto_raise ()) { meta_display_queue_autoraise_callback (workspace->screen->display, window); } } else if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_SLOPPY) focus_ancestor_or_top_window (workspace, not_this_one, timestamp); else if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_MOUSE) { meta_topic (META_DEBUG_FOCUS, "Setting focus to no_focus_window, since no valid " "window to focus found.\n"); meta_display_focus_the_no_focus_window (workspace->screen->display, workspace->screen, timestamp); } } } static gboolean record_ancestor (MetaWindow *window, void *data) { MetaWindow **result = data; *result = window; return FALSE; /* quit with the first ancestor we find */ } /* Focus ancestor of not_this_one if there is one */ static void focus_ancestor_or_top_window (MetaWorkspace *workspace, MetaWindow *not_this_one, guint32 timestamp) { MetaWindow *window = NULL; #ifdef WITH_VERBOSE_MODE if (not_this_one) meta_topic (META_DEBUG_FOCUS, "Focusing MRU window excluding %s\n", not_this_one->desc); else meta_topic (META_DEBUG_FOCUS, "Focusing MRU window\n"); #endif /* First, check to see if we need to focus an ancestor of a window */ if (not_this_one) { MetaWindow *ancestor; ancestor = NULL; meta_window_foreach_ancestor (not_this_one, record_ancestor, &ancestor); if (ancestor != NULL && (ancestor->on_all_workspaces || ancestor->workspace == workspace) && meta_window_showing_on_its_workspace (ancestor)) { meta_topic (META_DEBUG_FOCUS, "Focusing %s, ancestor of %s\n", ancestor->desc, not_this_one->desc); meta_window_focus (ancestor, timestamp); /* Also raise the window if in click-to-focus */ if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK) meta_window_raise (ancestor); return; } } window = meta_stack_get_default_focus_window (workspace->screen->stack, workspace, not_this_one); if (window) { meta_topic (META_DEBUG_FOCUS, "Focusing workspace MRU window %s\n", window->desc); meta_window_focus (window, timestamp); /* Also raise the window if in click-to-focus */ if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK) meta_window_raise (window); } else { meta_topic (META_DEBUG_FOCUS, "No MRU window to focus found; focusing no_focus_window.\n"); meta_display_focus_the_no_focus_window (workspace->screen->display, workspace->screen, timestamp); } } �������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/frame.h�����������������������������������������������������������������������0000664�0001750�0001750�00000005461�14211404421�016124� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X window decorations */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_FRAME_PRIVATE_H #define META_FRAME_PRIVATE_H #include "window-private.h" #include "workspace-private.h" struct _MetaFrame { /* window we frame */ MetaWindow *window; /* reparent window */ Window xwindow; MetaCursor current_cursor; /* This rect is trusted info from where we put the * frame, not the result of ConfigureNotify */ MetaRectangle rect; MetaFrameBorders cached_borders; /* valid if borders_cached is set */ /* position of client, size of frame */ int child_x; int child_y; int right_width; int bottom_height; guint need_reapply_frame_shape : 1; guint is_flashing : 1; /* used by the visual bell flash */ guint borders_cached : 1; }; void meta_window_ensure_frame (MetaWindow *window); void meta_window_destroy_frame (MetaWindow *window); void meta_frame_queue_draw (MetaFrame *frame); MetaFrameFlags meta_frame_get_flags (MetaFrame *frame); Window meta_frame_get_xwindow (MetaFrame *frame); /* These should ONLY be called from meta_window_move_resize_internal */ void meta_frame_calc_borders (MetaFrame *frame, MetaFrameBorders *borders); void meta_frame_get_corner_radiuses (MetaFrame *frame, float *top_left, float *top_right, float *bottom_left, float *bottom_right); gboolean meta_frame_sync_to_window (MetaFrame *frame, int gravity, gboolean need_move, gboolean need_resize); void meta_frame_clear_cached_borders (MetaFrame *frame); cairo_region_t *meta_frame_get_frame_bounds (MetaFrame *frame); void meta_frame_set_screen_cursor (MetaFrame *frame, MetaCursor cursor); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/window-props.c����������������������������������������������������������������0000664�0001750�0001750�00000216271�14211404421�017500� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * SECTION:window-props * @short_description: #MetaWindow property handling * * A system which can inspect sets of properties of given windows * and take appropriate action given their values. * * Note that all the meta_window_reload_propert* functions require a * round trip to the server. * * The guts of this system are in meta_display_init_window_prop_hooks(). * Reading this function will give you insight into how this all fits * together. */ /* * Copyright (C) 2001, 2002, 2003 Red Hat, Inc. * Copyright (C) 2004, 2005 Elijah Newren * Copyright (C) 2009 Thomas Thurman * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _SVID_SOURCE /* for gethostname() */ #include <config.h> #include "window-props.h" #include <meta/errors.h> #include "xprops.h" #include "frame.h" #include <meta/group.h> #include <X11/Xatom.h> #include <unistd.h> #include <string.h> #include "util-private.h" #ifndef HOST_NAME_MAX /* Solaris headers apparently don't define this so do so manually; #326745 */ #define HOST_NAME_MAX 255 #endif typedef void (* ReloadValueFunc) (MetaWindow *window, MetaPropValue *value, gboolean initial); struct _MetaWindowPropHooks { Atom property; MetaPropValueType type; ReloadValueFunc reload_func; gboolean load_initially; gboolean include_override_redirect; }; static void init_prop_value (MetaWindow *window, MetaWindowPropHooks *hooks, MetaPropValue *value); static void reload_prop_value (MetaWindow *window, MetaWindowPropHooks *hooks, MetaPropValue *value, gboolean initial); static MetaWindowPropHooks* find_hooks (MetaDisplay *display, Atom property); LOCAL_SYMBOL void meta_window_reload_property (MetaWindow *window, Atom property, gboolean initial) { meta_window_reload_properties (window, &property, 1, initial); } LOCAL_SYMBOL void meta_window_reload_properties (MetaWindow *window, const Atom *properties, int n_properties, gboolean initial) { meta_window_reload_properties_from_xwindow (window, window->xwindow, properties, n_properties, initial); } LOCAL_SYMBOL void meta_window_reload_property_from_xwindow (MetaWindow *window, Window xwindow, Atom property, gboolean initial) { meta_window_reload_properties_from_xwindow (window, xwindow, &property, 1, initial); } LOCAL_SYMBOL void meta_window_reload_properties_from_xwindow (MetaWindow *window, Window xwindow, const Atom *properties, int n_properties, gboolean initial) { int i; MetaPropValue *values; g_return_if_fail (properties != NULL); g_return_if_fail (n_properties > 0); values = g_new0 (MetaPropValue, n_properties); i = 0; while (i < n_properties) { MetaWindowPropHooks *hooks = find_hooks (window->display, properties[i]); init_prop_value (window, hooks, &values[i]); ++i; } meta_prop_get_values (window->display, xwindow, values, n_properties); i = 0; while (i < n_properties) { MetaWindowPropHooks *hooks = find_hooks (window->display, properties[i]); reload_prop_value (window, hooks, &values[i], initial); ++i; } meta_prop_free_values (values, n_properties); free (values); } LOCAL_SYMBOL void meta_window_load_initial_properties (MetaWindow *window) { int i, j; MetaPropValue *values; int n_properties = 0; values = g_new0 (MetaPropValue, window->display->n_prop_hooks); j = 0; for (i = 0; i < window->display->n_prop_hooks; i++) { MetaWindowPropHooks *hooks = &window->display->prop_hooks_table[i]; if (hooks->load_initially) { init_prop_value (window, hooks, &values[j]); ++j; } } n_properties = j; meta_prop_get_values (window->display, window->xwindow, values, n_properties); j = 0; for (i = 0; i < window->display->n_prop_hooks; i++) { MetaWindowPropHooks *hooks = &window->display->prop_hooks_table[i]; if (hooks->load_initially) { /* If we didn't actually manage to load anything then we don't need * to call the reload function; this is different from a notification * where disappearance of a previously present value is significant. */ if (values[j].type != META_PROP_VALUE_INVALID) reload_prop_value (window, hooks, &values[j], TRUE); ++j; } } meta_prop_free_values (values, n_properties); free (values); } /* Fill in the MetaPropValue used to get the value of "property" */ static void init_prop_value (MetaWindow *window, MetaWindowPropHooks *hooks, MetaPropValue *value) { if (!hooks || hooks->type == META_PROP_VALUE_INVALID || (window->override_redirect && !hooks->include_override_redirect)) { value->type = META_PROP_VALUE_INVALID; value->atom = None; } else { value->type = hooks->type; value->atom = hooks->property; } } static void reload_prop_value (MetaWindow *window, MetaWindowPropHooks *hooks, MetaPropValue *value, gboolean initial) { if (hooks && hooks->reload_func != NULL && !(window->override_redirect && !hooks->include_override_redirect)) (* hooks->reload_func) (window, value, initial); } static void reload_wm_client_machine (MetaWindow *window, MetaPropValue *value, gboolean initial) { free (window->wm_client_machine); window->wm_client_machine = NULL; if (value->type != META_PROP_VALUE_INVALID) window->wm_client_machine = g_strdup (value->v.str); meta_verbose ("Window has client machine \"%s\"\n", window->wm_client_machine ? window->wm_client_machine : "unset"); } static void reload_theme_icon_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { free (window->theme_icon_name); window->theme_icon_name = NULL; if (value->type != META_PROP_VALUE_INVALID) window->theme_icon_name = g_strdup (value->v.str); meta_verbose ("Window theme icon name or path is \"%s\"\n", window->theme_icon_name ? window->theme_icon_name : "unset"); } static void reload_progress (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { if (window->progress != value->v.cardinal) { window->progress = value->v.cardinal; g_object_notify ((GObject*) window, "progress"); meta_topic (META_DEBUG_WINDOW_STATE, "Read XAppGtkWindow progress prop %u for %s\n", window->progress, window->desc); } } else { if (window->progress != 0) { window->progress = 0; g_object_notify ((GObject*) window, "progress"); meta_topic (META_DEBUG_WINDOW_STATE, "Read XAppGtkWindow progress prop %u for %s\n", window->progress, window->desc); } } } static void reload_progress_pulse (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { gboolean new_val = value->v.cardinal == 1; if (window->progress_pulse != new_val) { window->progress_pulse = new_val; g_object_notify ((GObject*) window, "progress-pulse"); meta_topic (META_DEBUG_WINDOW_STATE, "Read XAppGtkWindow progress-pulse prop %s for %s\n", window->progress_pulse ? "TRUE" : "FALSE", window->desc); } } else { if (window->progress_pulse) { window->progress_pulse = FALSE; g_object_notify ((GObject*) window, "progress-pulse"); meta_topic (META_DEBUG_WINDOW_STATE, "Read XAppGtkWindow progress-pulse prop %s for %s\n", window->progress_pulse ? "TRUE" : "FALSE", window->desc); } } } static void complain_about_broken_client (MetaWindow *window, MetaPropValue *value, gboolean initial) { meta_warning ("Broken client! Window %s changed client leader window or SM client ID\n", window->desc); } static void reload_net_wm_window_type (MetaWindow *window, MetaPropValue *value, gboolean initial) { meta_window_update_net_wm_type (window); } static void reload_icon (MetaWindow *window, Atom atom) { meta_window_icon_changed (window); } static void reload_net_wm_icon (MetaWindow *window, MetaPropValue *value, gboolean initial) { reload_icon (window, window->display->atom__NET_WM_ICON); } static void reload_kwm_win_icon (MetaWindow *window, MetaPropValue *value, gboolean initial) { reload_icon (window, window->display->atom__KWM_WIN_ICON); } static void reload_gtk_frame_extents (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { if (value->v.cardinal_list.n_cardinals != 4) { meta_verbose ("_GTK_FRAME_EXTENTS on %s has %d values instead of 4\n", window->desc, value->v.cardinal_list.n_cardinals); } else { GtkBorder *extents = &window->custom_frame_extents; window->has_custom_frame_extents = TRUE; extents->left = (int)value->v.cardinal_list.cardinals[0]; extents->right = (int)value->v.cardinal_list.cardinals[1]; extents->top = (int)value->v.cardinal_list.cardinals[2]; extents->bottom = (int)value->v.cardinal_list.cardinals[3]; } } else { window->has_custom_frame_extents = FALSE; } } static void reload_icon_geometry (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { if (value->v.cardinal_list.n_cardinals != 4) { meta_verbose ("_NET_WM_ICON_GEOMETRY on %s has %d values instead of 4\n", window->desc, value->v.cardinal_list.n_cardinals); } else { MetaRectangle geometry; geometry.x = (int)value->v.cardinal_list.cardinals[0]; geometry.y = (int)value->v.cardinal_list.cardinals[1]; geometry.width = (int)value->v.cardinal_list.cardinals[2]; geometry.height = (int)value->v.cardinal_list.cardinals[3]; meta_window_set_icon_geometry (window, &geometry); } } else { meta_window_set_icon_geometry (window, NULL); } } static void reload_struts (MetaWindow *window, MetaPropValue *value, gboolean initial) { meta_window_update_struts (window); } static void reload_wm_window_role (MetaWindow *window, MetaPropValue *value, gboolean initial) { meta_window_update_role (window); } static void reload_net_wm_pid (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { gulong cardinal = (int) value->v.cardinal; if (cardinal <= 0) meta_warning ("Application set a bogus _NET_WM_PID %lu\n", cardinal); else { window->net_wm_pid = cardinal; meta_verbose ("Window has _NET_WM_PID %d\n", window->net_wm_pid); } } } static void reload_net_wm_user_time (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { gulong cardinal = value->v.cardinal; meta_window_set_user_time (window, cardinal); } } static void reload_net_wm_user_time_window (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { MetaWindow *prev_owner; /* Unregister old NET_WM_USER_TIME_WINDOW */ if (window->user_time_window != None) { /* See the comment to the meta_display_register_x_window call below. */ meta_display_unregister_x_window (window->display, window->user_time_window); /* Don't get events on not-managed windows */ XSelectInput (window->display->xdisplay, window->user_time_window, NoEventMask); } /* Ensure the new user time window is not used on another MetaWindow, * and unset its user time window if that is the case. */ prev_owner = meta_display_lookup_x_window (window->display, value->v.xwindow); if (prev_owner && prev_owner->user_time_window == value->v.xwindow) { meta_display_unregister_x_window (window->display, value->v.xwindow); prev_owner->user_time_window = None; } /* Obtain the new NET_WM_USER_TIME_WINDOW and register it */ window->user_time_window = value->v.xwindow; if (window->user_time_window != None) { /* Kind of a hack; display.c:event_callback() ignores events * for unknown windows. We make window->user_time_window * known by registering it with window (despite the fact * that window->xwindow is already registered with window). * This basically means that property notifies to either the * window->user_time_window or window->xwindow will be * treated identically and will result in functions for * window being called to update it. Maybe we should ignore * any property notifies to window->user_time_window other * than atom__NET_WM_USER_TIME ones, but I just don't care * and it's not specified in the spec anyway. */ meta_display_register_x_window (window->display, &window->user_time_window, window); /* Just listen for property notify events */ XSelectInput (window->display->xdisplay, window->user_time_window, PropertyChangeMask); /* Manually load the _NET_WM_USER_TIME field from the given window * at this time as well. If the user_time_window ever broadens in * scope, we'll probably want to load all relevant properties here. */ meta_window_reload_property_from_xwindow ( window, window->user_time_window, window->display->atom__NET_WM_USER_TIME, initial); } } } #define MAX_TITLE_LENGTH 512 /* * Called by set_window_title and set_icon_title to set the value of * *target to title. It required and atom is set, it will update the * appropriate property. * * Returns TRUE if a new title was set. */ static gboolean set_title_text (MetaWindow *window, gboolean previous_was_modified, const char *title, Atom atom, char **target) { char hostname[HOST_NAME_MAX + 1]; gboolean modified = FALSE; if (!target) return FALSE; free (*target); if (!title) *target = g_strdup (""); else if (g_utf8_strlen (title, MAX_TITLE_LENGTH + 1) > MAX_TITLE_LENGTH) { *target = meta_g_utf8_strndup (title, MAX_TITLE_LENGTH); modified = TRUE; } /* if WM_CLIENT_MACHINE indicates this machine is on a remote host * lets place that hostname in the title */ else if (window->wm_client_machine && !gethostname (hostname, HOST_NAME_MAX + 1) && strcmp (hostname, window->wm_client_machine)) { *target = g_strdup_printf (_("%s (on %s)"), title, window->wm_client_machine); modified = TRUE; } else *target = g_strdup (title); if (modified && atom != None) meta_prop_set_utf8_string_hint (window->display, window->xwindow, atom, *target); /* Bug 330671 -- Don't forget to clear _NET_WM_VISIBLE_(ICON_)NAME */ if (!modified && previous_was_modified) { meta_error_trap_push (window->display); XDeleteProperty (window->display->xdisplay, window->xwindow, atom); meta_error_trap_pop (window->display); } return modified; } static void set_window_title (MetaWindow *window, const char *title) { char *str; gboolean modified = set_title_text (window, window->using_net_wm_visible_name, title, window->display->atom__NET_WM_VISIBLE_NAME, &window->title); window->using_net_wm_visible_name = modified; /* strndup is a hack since GNU libc has broken %.10s */ str = g_strndup (window->title, 10); free (window->desc); window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str); free (str); if (window->frame) meta_ui_set_frame_title (window->screen->ui, window->frame->xwindow, window->title); g_object_notify (G_OBJECT (window), "title"); } static void reload_net_wm_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { set_window_title (window, value->v.str); window->using_net_wm_name = TRUE; meta_verbose ("Using _NET_WM_NAME for new title of %s: \"%s\"\n", window->desc, window->title); } else { set_window_title (window, NULL); window->using_net_wm_name = FALSE; if (!initial) meta_window_reload_property (window, XA_WM_NAME, FALSE); } } static void reload_wm_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (window->using_net_wm_name) { meta_verbose ("Ignoring WM_NAME \"%s\" as _NET_WM_NAME is set\n", value->v.str); return; } if (value->type != META_PROP_VALUE_INVALID) { set_window_title (window, value->v.str); meta_verbose ("Using WM_NAME for new title of %s: \"%s\"\n", window->desc, window->title); } else { set_window_title (window, NULL); } } static void meta_window_set_opaque_region (MetaWindow *window, cairo_region_t *region) { if (cairo_region_equal (window->opaque_region, region)) return; g_clear_pointer (&window->opaque_region, cairo_region_destroy); if (region != NULL) window->opaque_region = cairo_region_reference (region); meta_compositor_window_shape_changed (window->display->compositor, window); } static void reload_opaque_region (MetaWindow *window, MetaPropValue *value, gboolean initial) { cairo_region_t *opaque_region = NULL; if (value->type != META_PROP_VALUE_INVALID) { gulong *region = value->v.cardinal_list.cardinals; int nitems = value->v.cardinal_list.n_cardinals; cairo_rectangle_int_t *rects; int i, rect_index, nrects; if (nitems % 4 != 0) { meta_verbose ("_NET_WM_OPAQUE_REGION does not have a list of 4-tuples."); goto out; } /* empty region */ if (nitems == 0) goto out; nrects = nitems / 4; rects = g_new (cairo_rectangle_int_t, nrects); rect_index = 0; i = 0; while (i < nitems) { cairo_rectangle_int_t *rect = &rects[rect_index]; rect->x = region[i++]; rect->y = region[i++]; rect->width = region[i++]; rect->height = region[i++]; rect_index++; } opaque_region = cairo_region_create_rectangles (rects, nrects); free (rects); } out: meta_window_set_opaque_region (window, opaque_region); cairo_region_destroy (opaque_region); } static void reload_muffin_hints (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { char *new_hints = value->v.str; char *old_hints = window->muffin_hints; gboolean changed = FALSE; if (new_hints) { if (!old_hints || strcmp (new_hints, old_hints)) changed = TRUE; } else { if (old_hints) changed = TRUE; } if (changed) { free (old_hints); if (new_hints) window->muffin_hints = g_strdup (new_hints); else window->muffin_hints = NULL; g_object_notify (G_OBJECT (window), "muffin-hints"); } } else if (window->muffin_hints) { free (window->muffin_hints); window->muffin_hints = NULL; g_object_notify (G_OBJECT (window), "muffin-hints"); } } static void set_icon_title (MetaWindow *window, const char *title) { gboolean modified = set_title_text (window, window->using_net_wm_visible_icon_name, title, window->display->atom__NET_WM_VISIBLE_ICON_NAME, &window->icon_name); window->using_net_wm_visible_icon_name = modified; } static void reload_net_wm_icon_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { set_icon_title (window, value->v.str); window->using_net_wm_icon_name = TRUE; meta_verbose ("Using _NET_WM_ICON_NAME for new title of %s: \"%s\"\n", window->desc, window->title); } else { set_icon_title (window, NULL); window->using_net_wm_icon_name = FALSE; if (!initial) meta_window_reload_property (window, XA_WM_ICON_NAME, FALSE); } } static void reload_wm_icon_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (window->using_net_wm_icon_name) { meta_verbose ("Ignoring WM_ICON_NAME \"%s\" as _NET_WM_ICON_NAME is set\n", value->v.str); return; } if (value->type != META_PROP_VALUE_INVALID) { set_icon_title (window, value->v.str); meta_verbose ("Using WM_ICON_NAME for new title of %s: \"%s\"\n", window->desc, window->title); } else { set_icon_title (window, NULL); } } static void reload_net_wm_state (MetaWindow *window, MetaPropValue *value, gboolean initial) { int i; /* We know this is only an initial window creation, * clients don't change the property. */ if (!initial) { /* no, they DON'T change the property */ meta_verbose ("Ignoring _NET_WM_STATE: we should be the one who set " "the property in the first place\n"); return; } window->shaded = FALSE; window->maximized_horizontally = FALSE; window->maximized_vertically = FALSE; window->fullscreen = FALSE; window->wm_state_modal = FALSE; window->wm_state_skip_taskbar = FALSE; window->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; window->wm_state_demands_attention = FALSE; if (value->type == META_PROP_VALUE_INVALID) return; i = 0; while (i < value->v.atom_list.n_atoms) { if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_TILED) window->tile_after_placement = TRUE; ++i; } i = 0; while (i < value->v.atom_list.n_atoms) { if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SHADED) window->shaded = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ && !window->tile_after_placement) window->maximize_horizontally_after_placement = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MAXIMIZED_VERT && !window->tile_after_placement) window->maximize_vertically_after_placement = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_HIDDEN) window->minimize_after_placement = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MODAL) window->wm_state_modal = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_TASKBAR) window->wm_state_skip_taskbar = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER) window->wm_state_skip_pager = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN) window->fullscreen = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE) window->wm_state_above = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_BELOW) window->wm_state_below = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION) window->wm_state_demands_attention = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_STICKY) window->on_all_workspaces_requested = TRUE; ++i; } meta_verbose ("Reloaded _NET_WM_STATE for %s\n", window->desc); meta_window_recalc_window_type (window); meta_window_recalc_features (window); } static void reload_mwm_hints (MetaWindow *window, MetaPropValue *value, gboolean initial) { MotifWmHints *hints; gboolean old_decorated = window->decorated; window->mwm_decorated = TRUE; window->mwm_border_only = FALSE; window->mwm_has_close_func = TRUE; window->mwm_has_minimize_func = TRUE; window->mwm_has_maximize_func = TRUE; window->mwm_has_move_func = TRUE; window->mwm_has_resize_func = TRUE; if (value->type == META_PROP_VALUE_INVALID) { meta_verbose ("Window %s has no MWM hints\n", window->desc); meta_window_recalc_features (window); return; } hints = value->v.motif_hints; /* We support those MWM hints deemed non-stupid */ meta_verbose ("Window %s has MWM hints\n", window->desc); if (hints->flags & MWM_HINTS_DECORATIONS) { meta_verbose ("Window %s sets MWM_HINTS_DECORATIONS 0x%lx\n", window->desc, hints->decorations); if (hints->decorations == 0) window->mwm_decorated = FALSE; /* some input methods use this */ else if (hints->decorations == MWM_DECOR_BORDER) window->mwm_border_only = TRUE; } else meta_verbose ("Decorations flag unset\n"); if (hints->flags & MWM_HINTS_FUNCTIONS) { gboolean toggle_value; meta_verbose ("Window %s sets MWM_HINTS_FUNCTIONS 0x%lx\n", window->desc, hints->functions); /* If _ALL is specified, then other flags indicate what to turn off; * if ALL is not specified, flags are what to turn on. * at least, I think so */ if ((hints->functions & MWM_FUNC_ALL) == 0) { toggle_value = TRUE; meta_verbose ("Window %s disables all funcs then reenables some\n", window->desc); window->mwm_has_close_func = FALSE; window->mwm_has_minimize_func = FALSE; window->mwm_has_maximize_func = FALSE; window->mwm_has_move_func = FALSE; window->mwm_has_resize_func = FALSE; } else { meta_verbose ("Window %s enables all funcs then disables some\n", window->desc); toggle_value = FALSE; } if ((hints->functions & MWM_FUNC_CLOSE) != 0) { meta_verbose ("Window %s toggles close via MWM hints\n", window->desc); window->mwm_has_close_func = toggle_value; } if ((hints->functions & MWM_FUNC_MINIMIZE) != 0) { meta_verbose ("Window %s toggles minimize via MWM hints\n", window->desc); window->mwm_has_minimize_func = toggle_value; } if ((hints->functions & MWM_FUNC_MAXIMIZE) != 0) { meta_verbose ("Window %s toggles maximize via MWM hints\n", window->desc); window->mwm_has_maximize_func = toggle_value; } if ((hints->functions & MWM_FUNC_MOVE) != 0) { meta_verbose ("Window %s toggles move via MWM hints\n", window->desc); window->mwm_has_move_func = toggle_value; } if ((hints->functions & MWM_FUNC_RESIZE) != 0) { meta_verbose ("Window %s toggles resize via MWM hints\n", window->desc); window->mwm_has_resize_func = toggle_value; } } else meta_verbose ("Functions flag unset\n"); meta_window_recalc_features (window); /* We do all this anyhow at the end of meta_window_new() */ if (!window->constructing) { if (window->decorated) meta_window_ensure_frame (window); else meta_window_destroy_frame (window); meta_window_queue (window, META_QUEUE_MOVE_RESIZE | /* because ensure/destroy frame may unmap: */ META_QUEUE_CALC_SHOWING); if (old_decorated != window->decorated) g_object_notify (G_OBJECT (window), "decorated"); } } static void reload_wm_class (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (window->res_class) free (window->res_class); if (window->res_name) free (window->res_name); window->res_class = NULL; window->res_name = NULL; if (value->type != META_PROP_VALUE_INVALID) { if (value->v.class_hint.res_name) window->res_name = g_strdup (value->v.class_hint.res_name); if (value->v.class_hint.res_class) window->res_class = g_strdup (value->v.class_hint.res_class); g_object_notify (G_OBJECT (window), "wm-class"); } meta_verbose ("Window %s class: '%s' name: '%s'\n", window->desc, window->res_class ? window->res_class : "none", window->res_name ? window->res_name : "none"); } static void reload_net_wm_desktop (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { window->initial_workspace_set = TRUE; window->initial_workspace = value->v.cardinal; meta_topic (META_DEBUG_PLACEMENT, "Read initial workspace prop %d for %s\n", window->initial_workspace, window->desc); } } static void reload_net_startup_id (MetaWindow *window, MetaPropValue *value, gboolean initial) { guint32 timestamp = window->net_wm_user_time; MetaWorkspace *workspace = NULL; free (window->startup_id); if (value->type != META_PROP_VALUE_INVALID) window->startup_id = g_strdup (value->v.str); else window->startup_id = NULL; /* Update timestamp and workspace on a running window */ if (!window->constructing) { window->initial_timestamp_set = 0; window->initial_workspace_set = 0; if (meta_screen_apply_startup_properties (window->screen, window)) { if (window->initial_timestamp_set) timestamp = window->initial_timestamp; if (window->initial_workspace_set) workspace = meta_screen_get_workspace_by_index (window->screen, window->initial_workspace); meta_window_activate_with_workspace (window, timestamp, workspace); } } meta_verbose ("New _NET_STARTUP_ID \"%s\" for %s\n", window->startup_id ? window->startup_id : "unset", window->desc); } static void reload_update_counter (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { meta_window_destroy_sync_request_alarm (window); #ifdef HAVE_XSYNC window->sync_request_counter = None; if (value->v.xcounter_list.n_counters == 0) { meta_warning ("_NET_WM_SYNC_REQUEST_COUNTER is empty\n"); return; } if (value->v.xcounter_list.n_counters == 1) { window->sync_request_counter = value->v.xcounter_list.counters[0]; window->extended_sync_request_counter = FALSE; } else { window->sync_request_counter = value->v.xcounter_list.counters[1]; window->extended_sync_request_counter = TRUE; } meta_verbose ("Window has _NET_WM_SYNC_REQUEST_COUNTER 0x%lx (extended=%s)\n", window->sync_request_counter, window->extended_sync_request_counter ? "true" : "false"); if (window->extended_sync_request_counter) meta_window_create_sync_request_alarm (window); #endif } } #define FLAG_TOGGLED_ON(old,new,flag) \ (((old)->flags & (flag)) == 0 && \ ((new)->flags & (flag)) != 0) #define FLAG_TOGGLED_OFF(old,new,flag) \ (((old)->flags & (flag)) != 0 && \ ((new)->flags & (flag)) == 0) #define FLAG_CHANGED(old,new,flag) \ (FLAG_TOGGLED_ON(old,new,flag) || FLAG_TOGGLED_OFF(old,new,flag)) static void spew_size_hints_differences (const XSizeHints *old, const XSizeHints *new) { if (FLAG_CHANGED (old, new, USPosition)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: USPosition now %s\n", FLAG_TOGGLED_ON (old, new, USPosition) ? "set" : "unset"); if (FLAG_CHANGED (old, new, USSize)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: USSize now %s\n", FLAG_TOGGLED_ON (old, new, USSize) ? "set" : "unset"); if (FLAG_CHANGED (old, new, PPosition)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PPosition now %s\n", FLAG_TOGGLED_ON (old, new, PPosition) ? "set" : "unset"); if (FLAG_CHANGED (old, new, PSize)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PSize now %s\n", FLAG_TOGGLED_ON (old, new, PSize) ? "set" : "unset"); if (FLAG_CHANGED (old, new, PMinSize)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PMinSize now %s (%d x %d -> %d x %d)\n", FLAG_TOGGLED_ON (old, new, PMinSize) ? "set" : "unset", old->min_width, old->min_height, new->min_width, new->min_height); if (FLAG_CHANGED (old, new, PMaxSize)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PMaxSize now %s (%d x %d -> %d x %d)\n", FLAG_TOGGLED_ON (old, new, PMaxSize) ? "set" : "unset", old->max_width, old->max_height, new->max_width, new->max_height); if (FLAG_CHANGED (old, new, PResizeInc)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PResizeInc now %s (width_inc %d -> %d height_inc %d -> %d)\n", FLAG_TOGGLED_ON (old, new, PResizeInc) ? "set" : "unset", old->width_inc, new->width_inc, old->height_inc, new->height_inc); if (FLAG_CHANGED (old, new, PAspect)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PAspect now %s (min %d/%d -> %d/%d max %d/%d -> %d/%d)\n", FLAG_TOGGLED_ON (old, new, PAspect) ? "set" : "unset", old->min_aspect.x, old->min_aspect.y, new->min_aspect.x, new->min_aspect.y, old->max_aspect.x, old->max_aspect.y, new->max_aspect.x, new->max_aspect.y); if (FLAG_CHANGED (old, new, PBaseSize)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PBaseSize now %s (%d x %d -> %d x %d)\n", FLAG_TOGGLED_ON (old, new, PBaseSize) ? "set" : "unset", old->base_width, old->base_height, new->base_width, new->base_height); if (FLAG_CHANGED (old, new, PWinGravity)) meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PWinGravity now %s (%d -> %d)\n", FLAG_TOGGLED_ON (old, new, PWinGravity) ? "set" : "unset", old->win_gravity, new->win_gravity); } LOCAL_SYMBOL void meta_set_normal_hints (MetaWindow *window, XSizeHints *hints) { int x, y, w, h; double minr, maxr; gint ui_scale; /* Some convenience vars */ int minw, minh, maxw, maxh; /* min/max width/height */ int basew, baseh, winc, hinc; /* base width/height, width/height increment */ ui_scale = meta_prefs_get_ui_scale (); /* Save the last ConfigureRequest, which we put here. * Values here set in the hints are supposed to * be ignored. */ x = window->size_hints.x; y = window->size_hints.y; w = window->size_hints.width; h = window->size_hints.height; /* as far as I can tell, value->v.size_hints.flags is just to * check whether we had old-style normal hints without gravity, * base size as returned by XGetNormalHints(), so we don't * really use it as we fixup window->size_hints to have those * fields if they're missing. */ /* * When the window is first created, NULL hints will * be passed in which will initialize all of the fields * as if flags were zero */ if (hints) window->size_hints = *hints; else window->size_hints.flags = 0; /* Put back saved ConfigureRequest. */ window->size_hints.x = x; window->size_hints.y = y; window->size_hints.width = w; window->size_hints.height = h; /* Get base size hints */ if (window->size_hints.flags & PBaseSize) { meta_topic (META_DEBUG_GEOMETRY, "Window %s sets base size %d x %d\n", window->desc, window->size_hints.base_width, window->size_hints.base_height); } else if (window->size_hints.flags & PMinSize) { window->size_hints.base_width = window->size_hints.min_width; window->size_hints.base_height = window->size_hints.min_height; } else { window->size_hints.base_width = 0; window->size_hints.base_height = 0; } window->size_hints.flags |= PBaseSize; /* Get min size hints */ if (window->size_hints.flags & PMinSize) { meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min size %d x %d\n", window->desc, window->size_hints.min_width, window->size_hints.min_height); } else if (window->size_hints.flags & PBaseSize) { window->size_hints.min_width = window->size_hints.base_width; window->size_hints.min_height = window->size_hints.base_height; } else { window->size_hints.min_width = 0; window->size_hints.min_height = 0; } window->size_hints.flags |= PMinSize; /* Get max size hints */ if (window->size_hints.flags & PMaxSize) { meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max size %d x %d\n", window->desc, window->size_hints.max_width, window->size_hints.max_height); } else { window->size_hints.max_width = G_MAXINT; window->size_hints.max_height = G_MAXINT; window->size_hints.flags |= PMaxSize; } /* Get resize increment hints */ if (window->size_hints.flags & PResizeInc) { meta_topic (META_DEBUG_GEOMETRY, "Window %s sets resize width inc: %d height inc: %d\n", window->desc, window->size_hints.width_inc, window->size_hints.height_inc); } else { window->size_hints.width_inc = ui_scale; window->size_hints.height_inc = ui_scale; window->size_hints.flags |= PResizeInc; } /* Get aspect ratio hints */ if (window->size_hints.flags & PAspect) { meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min_aspect: %d/%d max_aspect: %d/%d\n", window->desc, window->size_hints.min_aspect.x, window->size_hints.min_aspect.y, window->size_hints.max_aspect.x, window->size_hints.max_aspect.y); } else { window->size_hints.min_aspect.x = 1; window->size_hints.min_aspect.y = G_MAXINT; window->size_hints.max_aspect.x = G_MAXINT; window->size_hints.max_aspect.y = 1; window->size_hints.flags |= PAspect; } /* Get gravity hint */ if (window->size_hints.flags & PWinGravity) { meta_topic (META_DEBUG_GEOMETRY, "Window %s sets gravity %d\n", window->desc, window->size_hints.win_gravity); } else { meta_topic (META_DEBUG_GEOMETRY, "Window %s doesn't set gravity, using NW\n", window->desc); window->size_hints.win_gravity = NorthWestGravity; window->size_hints.flags |= PWinGravity; } /*** Lots of sanity checking ***/ /* Verify all min & max hints are at least 1 pixel */ if (window->size_hints.min_width < ui_scale) { /* someone is on crack */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min width to 0, which makes no sense\n", window->desc); window->size_hints.min_width = ui_scale; } if (window->size_hints.max_width < ui_scale) { /* another cracksmoker */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max width to 0, which makes no sense\n", window->desc); window->size_hints.max_width = ui_scale; } if (window->size_hints.min_height < ui_scale) { /* another cracksmoker */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min height to 0, which makes no sense\n", window->desc); window->size_hints.min_height = ui_scale; } if (window->size_hints.max_height < ui_scale) { /* another cracksmoker */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max height to 0, which makes no sense\n", window->desc); window->size_hints.max_height = ui_scale; } /* Verify size increment hints are at least 1 pixel */ if (window->size_hints.width_inc < ui_scale) { /* app authors find so many ways to smoke crack */ window->size_hints.width_inc = ui_scale; meta_topic (META_DEBUG_GEOMETRY, "Corrected too-small width_inc to window scale factor\n"); } if (window->size_hints.height_inc < ui_scale) { /* another cracksmoker */ window->size_hints.height_inc = ui_scale; meta_topic (META_DEBUG_GEOMETRY, "Corrected too-small height_inc to window scale factor\n"); } /* divide by 0 cracksmokers; note that x & y in (min|max)_aspect are * numerator & denominator */ if (window->size_hints.min_aspect.y < 1) window->size_hints.min_aspect.y = 1; if (window->size_hints.max_aspect.y < 1) window->size_hints.max_aspect.y = 1; minw = window->size_hints.min_width; minh = window->size_hints.min_height; maxw = window->size_hints.max_width; maxh = window->size_hints.max_height; basew = window->size_hints.base_width; baseh = window->size_hints.base_height; winc = window->size_hints.width_inc; hinc = window->size_hints.height_inc; /* Make sure min and max size hints are consistent with the base + increment * size hints. If they're not, it's not a real big deal, but it means the * effective min and max size are more restrictive than the application * specified values. */ if ((minw - basew) % winc != 0) { /* Take advantage of integer division throwing away the remainder... */ window->size_hints.min_width = basew + ((minw - basew)/winc + 1)*winc; meta_topic (META_DEBUG_GEOMETRY, "Window %s has width_inc (%d) that does not evenly divide " "min_width - base_width (%d - %d); thus effective " "min_width is really %d\n", window->desc, winc, minw, basew, window->size_hints.min_width); minw = window->size_hints.min_width; } if (maxw != G_MAXINT && (maxw - basew) % winc != 0) { /* Take advantage of integer division throwing away the remainder... */ window->size_hints.max_width = basew + ((maxw - basew)/winc)*winc; meta_topic (META_DEBUG_GEOMETRY, "Window %s has width_inc (%d) that does not evenly divide " "max_width - base_width (%d - %d); thus effective " "max_width is really %d\n", window->desc, winc, maxw, basew, window->size_hints.max_width); maxw = window->size_hints.max_width; } if ((minh - baseh) % hinc != 0) { /* Take advantage of integer division throwing away the remainder... */ window->size_hints.min_height = baseh + ((minh - baseh)/hinc + 1)*hinc; meta_topic (META_DEBUG_GEOMETRY, "Window %s has height_inc (%d) that does not evenly divide " "min_height - base_height (%d - %d); thus effective " "min_height is really %d\n", window->desc, hinc, minh, baseh, window->size_hints.min_height); minh = window->size_hints.min_height; } if (maxh != G_MAXINT && (maxh - baseh) % hinc != 0) { /* Take advantage of integer division throwing away the remainder... */ window->size_hints.max_height = baseh + ((maxh - baseh)/hinc)*hinc; meta_topic (META_DEBUG_GEOMETRY, "Window %s has height_inc (%d) that does not evenly divide " "max_height - base_height (%d - %d); thus effective " "max_height is really %d\n", window->desc, hinc, maxh, baseh, window->size_hints.max_height); maxh = window->size_hints.max_height; } /* make sure maximum size hints are compatible with minimum size hints; min * size hints take precedence. */ if (window->size_hints.max_width < window->size_hints.min_width) { /* another cracksmoker */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max width %d less than min width %d, " "disabling resize\n", window->desc, window->size_hints.max_width, window->size_hints.min_width); maxw = window->size_hints.max_width = window->size_hints.min_width; } if (window->size_hints.max_height < window->size_hints.min_height) { /* another cracksmoker */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max height %d less than min height %d, " "disabling resize\n", window->desc, window->size_hints.max_height, window->size_hints.min_height); maxh = window->size_hints.max_height = window->size_hints.min_height; } /* Make sure the aspect ratio hints are sane. */ minr = window->size_hints.min_aspect.x / (double)window->size_hints.min_aspect.y; maxr = window->size_hints.max_aspect.x / (double)window->size_hints.max_aspect.y; if (minr > maxr) { /* another cracksmoker; not even minimally (self) consistent */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min aspect ratio larger than max aspect " "ratio; disabling aspect ratio constraints.\n", window->desc); window->size_hints.min_aspect.x = 1; window->size_hints.min_aspect.y = G_MAXINT; window->size_hints.max_aspect.x = G_MAXINT; window->size_hints.max_aspect.y = 1; } else /* check consistency of aspect ratio hints with other hints */ { if (minh > 0 && minr > (maxw / (double)minh)) { /* another cracksmoker */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min aspect ratio larger than largest " "aspect ratio possible given min/max size constraints; " "disabling min aspect ratio constraint.\n", window->desc); window->size_hints.min_aspect.x = 1; window->size_hints.min_aspect.y = G_MAXINT; } if (maxr < (minw / (double)maxh)) { /* another cracksmoker */ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max aspect ratio smaller than smallest " "aspect ratio possible given min/max size constraints; " "disabling max aspect ratio constraint.\n", window->desc); window->size_hints.max_aspect.x = G_MAXINT; window->size_hints.max_aspect.y = 1; } /* FIXME: Would be nice to check that aspect ratios are * consistent with base and size increment constraints. */ } } static void reload_normal_hints (MetaWindow *window, MetaPropValue *value, gboolean initial) { if (value->type != META_PROP_VALUE_INVALID) { XSizeHints old_hints; meta_topic (META_DEBUG_GEOMETRY, "Updating WM_NORMAL_HINTS for %s\n", window->desc); old_hints = window->size_hints; meta_set_normal_hints (window, value->v.size_hints.hints); spew_size_hints_differences (&old_hints, &window->size_hints); meta_window_recalc_features (window); if (!initial) meta_window_queue(window, META_QUEUE_MOVE_RESIZE); } } static void reload_wm_protocols (MetaWindow *window, MetaPropValue *value, gboolean initial) { int i; window->take_focus = FALSE; window->delete_window = FALSE; window->net_wm_ping = FALSE; if (value->type == META_PROP_VALUE_INVALID) return; i = 0; while (i < value->v.atom_list.n_atoms) { if (value->v.atom_list.atoms[i] == window->display->atom_WM_TAKE_FOCUS) window->take_focus = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom_WM_DELETE_WINDOW) window->delete_window = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_PING) window->net_wm_ping = TRUE; ++i; } meta_verbose ("New _NET_STARTUP_ID \"%s\" for %s\n", window->startup_id ? window->startup_id : "unset", window->desc); } static void reload_wm_hints (MetaWindow *window, MetaPropValue *value, gboolean initial) { Window old_group_leader; gboolean old_urgent; old_group_leader = window->xgroup_leader; old_urgent = window->wm_hints_urgent; /* Fill in defaults */ window->input = TRUE; window->initially_iconic = FALSE; window->xgroup_leader = None; window->wm_hints_pixmap = None; window->wm_hints_mask = None; window->wm_hints_urgent = FALSE; if (value->type != META_PROP_VALUE_INVALID) { const XWMHints *hints = value->v.wm_hints; if (hints->flags & InputHint) window->input = hints->input; if (hints->flags & StateHint) window->initially_iconic = (hints->initial_state == IconicState); if (hints->flags & WindowGroupHint) window->xgroup_leader = hints->window_group; if (hints->flags & IconPixmapHint) window->wm_hints_pixmap = hints->icon_pixmap; if (hints->flags & IconMaskHint) window->wm_hints_mask = hints->icon_mask; if (hints->flags & XUrgencyHint) window->wm_hints_urgent = TRUE; meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%lx pixmap: 0x%lx mask: 0x%lx\n", window->input, window->initially_iconic, window->xgroup_leader, window->wm_hints_pixmap, window->wm_hints_mask); } if (window->xgroup_leader != old_group_leader) { meta_verbose ("Window %s changed its group leader to 0x%lx\n", window->desc, window->xgroup_leader); meta_window_group_leader_changed (window); } /* * Do not emit urgency notification on the inital property load */ if (!initial && (window->wm_hints_urgent != old_urgent)) g_object_notify (G_OBJECT (window), "urgent"); /* * Do not emit signal for the initial property load, let the constructor to * take care of it once the MetaWindow is fully constructed. * * Only emit if the property is both changed and set. */ if (!initial && window->wm_hints_urgent && !old_urgent) g_signal_emit_by_name (window->display, "window-marked-urgent", window); meta_icon_cache_property_changed (&window->icon_cache, window->display, XA_WM_HINTS); meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } static void reload_gtk_hide_titlebar_when_maximized (MetaWindow *window, MetaPropValue *value, gboolean initial) { gboolean requested_value = FALSE; gboolean current_value = window->hide_titlebar_when_maximized; if (meta_prefs_get_ignore_hide_titlebar_when_maximized ()) { return; } if (value->type != META_PROP_VALUE_INVALID) { requested_value = ((int) value->v.cardinal == 1); meta_verbose ("Request to hide titlebar for window %s.\n", window->desc); } if (requested_value == current_value) return; window->hide_titlebar_when_maximized = requested_value; if (META_WINDOW_MAXIMIZED (window)) { meta_window_queue (window, META_QUEUE_MOVE_RESIZE); if (window->frame) meta_ui_update_frame_style (window->screen->ui, window->frame->xwindow); } } typedef struct { MetaWindow *window; Window transient_for_xid; } FindByLeaderData; static void find_window_by_client_leader (MetaScreen *screen, MetaWindow *window, gpointer user_data) { FindByLeaderData *data = (FindByLeaderData *) user_data; if (data->window != NULL) { return; } if (window->xclient_leader == None) { return; } if (window->xclient_leader == data->transient_for_xid) { data->window = window; } } static MetaWindow * lookup_parent_by_client_leader (MetaWindow *transient, Window xtransient_for) { MetaWindow *parent; FindByLeaderData *data; data = g_new0 (FindByLeaderData, 1); data->transient_for_xid = xtransient_for; meta_screen_foreach_window (transient->screen, (MetaScreenWindowFunc) find_window_by_client_leader, data); if (data != NULL) { parent = data->window; } free (data); return parent; } static void reload_transient_for (MetaWindow *window, MetaPropValue *value, gboolean initial) { MetaWindow *parent = NULL; Window transient_for, old_transient_for; if (value->type != META_PROP_VALUE_INVALID) { transient_for = value->v.xwindow; parent = meta_display_lookup_x_window (window->display, transient_for); if (!parent) { /* QT programs appear to set the transient-for hint to the program's WM_CLIENT_LEADER * instead of the toplevel window's xid. This causes muffin to throw out their transient * state. Since we know the client leader id of existing windows, we can do a quick search * and match up to the correct parent so our stacking and fullscreen detection code works * properly */ parent = lookup_parent_by_client_leader (window, transient_for); if (parent) { transient_for = parent->xwindow; meta_verbose ("WM_TRANSIENT_FOR was parent window 0x%lx's WM_CLIENT_LEADER. " "using the xid instead for %s.\n", transient_for, window->desc); } else { meta_warning ("Invalid WM_TRANSIENT_FOR window 0x%lx specified " "for %s.\n", transient_for, window->desc); transient_for = None; } } /* Make sure there is not a loop */ while (parent) { if (parent == window) { meta_warning ("WM_TRANSIENT_FOR window 0x%lx for %s " "would create loop.\n", transient_for, window->desc); transient_for = None; break; } parent = meta_display_lookup_x_window (parent->display, parent->xtransient_for); } } else transient_for = None; if (transient_for == window->xtransient_for) return; if (meta_window_appears_focused (window) && window->xtransient_for != None) meta_window_propagate_focus_appearance (window, FALSE); old_transient_for = window->xtransient_for; window->xtransient_for = transient_for; window->transient_parent_is_root_window = window->xtransient_for == window->screen->xroot; if (window->xtransient_for != None) meta_verbose ("Window %s transient for 0x%lx (root = %d)\n", window->desc, window->xtransient_for, window->transient_parent_is_root_window); else meta_verbose ("Window %s is not transient\n", window->desc); /* may now be a dialog */ meta_window_recalc_window_type (window); if (!window->constructing) { /* If the window attaches, detaches, or changes attached * parents, we need to destroy the MetaWindow and let a new one * be created (which happens as a side effect of * meta_window_unmanage()). The condition below is correct * because we know window->xtransient_for has changed. */ if (window->attached || meta_window_should_attach_to_parent (window)) { guint32 timestamp; window->xtransient_for = old_transient_for; timestamp = meta_display_get_current_time_roundtrip (window->display); meta_window_unmanage (window, timestamp); return; } } /* update stacking constraints */ if (!window->override_redirect) meta_stack_update_transient (window->screen->stack, window); /* possibly change its group. We treat being a window's transient as * equivalent to making it your group leader, to work around shortcomings * in programs such as xmms-- see #328211. */ if (window->xtransient_for != None && window->xgroup_leader != None && window->xtransient_for != window->xgroup_leader) meta_window_group_leader_changed (window); if (!window->constructing && !window->override_redirect) meta_window_queue (window, META_QUEUE_MOVE_RESIZE); if (meta_window_appears_focused (window) && window->xtransient_for != None) meta_window_propagate_focus_appearance (window, TRUE); } static void reload_gtk_theme_variant (MetaWindow *window, MetaPropValue *value, gboolean initial) { char *requested_variant = NULL; char *current_variant = window->gtk_theme_variant; if (value->type != META_PROP_VALUE_INVALID) { requested_variant = value->v.str; meta_verbose ("Requested \"%s\" theme variant for window %s.\n", requested_variant, window->desc); } if (g_strcmp0 (requested_variant, current_variant) != 0) { free (current_variant); window->gtk_theme_variant = g_strdup (requested_variant); if (window->frame) meta_ui_update_frame_style (window->screen->ui, window->frame->xwindow); } } static void reload_bypass_compositor (MetaWindow *window, MetaPropValue *value, gboolean initial) { int requested_value = 0; int current_value = window->bypass_compositor; if (value->type != META_PROP_VALUE_INVALID) { requested_value = (int) value->v.cardinal; } if (requested_value == current_value) return; if (requested_value == _NET_WM_BYPASS_COMPOSITOR_HINT_ON) meta_verbose ("Request to bypass compositor for window %s.\n", window->desc); else if (requested_value == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF) meta_verbose ("Request to don't bypass compositor for window %s.\n", window->desc); else if (requested_value != _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO) return; window->bypass_compositor = requested_value; } #define RELOAD_STRING(var_name, propname) \ static void \ reload_ ## var_name (MetaWindow *window, \ MetaPropValue *value, \ gboolean initial) \ { \ free (window->var_name); \ \ if (value->type != META_PROP_VALUE_INVALID) \ window->var_name = g_strdup (value->v.str); \ else \ window->var_name = NULL; \ \ g_object_notify (G_OBJECT (window), propname); \ } RELOAD_STRING (gtk_unique_bus_name, "gtk-unique-bus-name") RELOAD_STRING (gtk_application_id, "gtk-application-id") RELOAD_STRING (gtk_application_object_path, "gtk-application-object-path") RELOAD_STRING (gtk_window_object_path, "gtk-window-object-path") RELOAD_STRING (gtk_app_menu_object_path, "gtk-app-menu-object-path") RELOAD_STRING (gtk_menubar_object_path, "gtk-menubar-object-path") #undef RELOAD_STRING /* * Initialises the property hooks system. Each row in the table named "hooks" * represents an action to take when a property is found on a newly-created * window, or when a property changes its value. * * The first column shows which atom the row concerns. * The second gives the type of the property data. The property will be * queried for its new value, unless the type is given as * META_PROP_VALUE_INVALID, in which case nothing will be queried. * The third column gives the name of a callback which gets called with the * new value. (If the new value was not retrieved because the second column * was META_PROP_VALUE_INVALID, the callback still gets called anyway.) * This value may be NULL, in which case no callback will be called. */ LOCAL_SYMBOL void meta_display_init_window_prop_hooks (MetaDisplay *display) { /* INIT: load initially * O-R: fetch for override-redirect windows * * The ordering here is significant for the properties we load * initially: they are roughly ordered in the order we want them to * be gotten. We want to get window name and class first so we can * use them in error messages and such. However, name is modified * depending on wm_client_machine, so push it slightly sooner. * * For override-redirect windows, we pay attention to: * * - properties that identify the window: useful for debugging * purposes. * - NET_WM_WINDOW_TYPE: can be used to do appropriate handling * for different types of override-redirect windows. */ MetaWindowPropHooks hooks[] = { /* INIT O-R */ { display->atom_WM_CLIENT_MACHINE, META_PROP_VALUE_STRING, reload_wm_client_machine, TRUE, TRUE }, { display->atom__NET_WM_NAME, META_PROP_VALUE_UTF8, reload_net_wm_name, TRUE, TRUE }, { XA_WM_CLASS, META_PROP_VALUE_CLASS_HINT, reload_wm_class, TRUE, TRUE }, { display->atom__NET_WM_PID, META_PROP_VALUE_CARDINAL, reload_net_wm_pid, TRUE, TRUE }, { XA_WM_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name, TRUE, TRUE }, { display->atom__MUFFIN_HINTS, META_PROP_VALUE_TEXT_PROPERTY, reload_muffin_hints, TRUE, TRUE }, { display->atom__NET_WM_OPAQUE_REGION, META_PROP_VALUE_CARDINAL_LIST, reload_opaque_region, TRUE, TRUE }, { display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8, reload_net_wm_icon_name, TRUE, FALSE }, { XA_WM_ICON_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE, FALSE }, { display->atom__NET_WM_DESKTOP, META_PROP_VALUE_CARDINAL, reload_net_wm_desktop, TRUE, FALSE }, { display->atom__NET_STARTUP_ID, META_PROP_VALUE_UTF8, reload_net_startup_id, TRUE, FALSE }, { display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER_LIST, reload_update_counter, TRUE, TRUE }, { XA_WM_NORMAL_HINTS, META_PROP_VALUE_SIZE_HINTS, reload_normal_hints, TRUE, FALSE }, { display->atom_WM_PROTOCOLS, META_PROP_VALUE_ATOM_LIST, reload_wm_protocols, TRUE, FALSE }, { XA_WM_HINTS, META_PROP_VALUE_WM_HINTS, reload_wm_hints, TRUE, FALSE }, { display->atom__NET_WM_USER_TIME, META_PROP_VALUE_CARDINAL, reload_net_wm_user_time, TRUE, FALSE }, { display->atom__NET_WM_STATE, META_PROP_VALUE_ATOM_LIST, reload_net_wm_state, TRUE, FALSE }, { display->atom__MOTIF_WM_HINTS, META_PROP_VALUE_MOTIF_HINTS, reload_mwm_hints, TRUE, FALSE }, { XA_WM_TRANSIENT_FOR, META_PROP_VALUE_WINDOW, reload_transient_for, TRUE, FALSE }, { display->atom__GTK_THEME_VARIANT, META_PROP_VALUE_UTF8, reload_gtk_theme_variant, TRUE, FALSE }, { display->atom__GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED, META_PROP_VALUE_CARDINAL, reload_gtk_hide_titlebar_when_maximized, TRUE, FALSE }, { display->atom__GTK_APPLICATION_ID, META_PROP_VALUE_UTF8, reload_gtk_application_id, TRUE, FALSE }, { display->atom__GTK_UNIQUE_BUS_NAME, META_PROP_VALUE_UTF8, reload_gtk_unique_bus_name, TRUE, FALSE }, { display->atom__GTK_APPLICATION_OBJECT_PATH, META_PROP_VALUE_UTF8, reload_gtk_application_object_path, TRUE, FALSE }, { display->atom__GTK_WINDOW_OBJECT_PATH, META_PROP_VALUE_UTF8, reload_gtk_window_object_path, TRUE, FALSE }, { display->atom__GTK_APP_MENU_OBJECT_PATH, META_PROP_VALUE_UTF8, reload_gtk_app_menu_object_path, TRUE, FALSE }, { display->atom__GTK_MENUBAR_OBJECT_PATH, META_PROP_VALUE_UTF8, reload_gtk_menubar_object_path, TRUE, FALSE }, { display->atom__GTK_FRAME_EXTENTS, META_PROP_VALUE_CARDINAL_LIST,reload_gtk_frame_extents, TRUE, FALSE }, { display->atom__NET_WM_USER_TIME_WINDOW, META_PROP_VALUE_WINDOW, reload_net_wm_user_time_window, TRUE, FALSE }, { display->atom_WM_STATE, META_PROP_VALUE_INVALID, NULL, FALSE, FALSE }, { display->atom__NET_WM_ICON, META_PROP_VALUE_INVALID, reload_net_wm_icon, FALSE, FALSE }, { display->atom__KWM_WIN_ICON, META_PROP_VALUE_INVALID, reload_kwm_win_icon, FALSE, FALSE }, { display->atom__NET_WM_ICON_GEOMETRY, META_PROP_VALUE_CARDINAL_LIST, reload_icon_geometry, FALSE, FALSE }, { display->atom_WM_CLIENT_LEADER, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE }, { display->atom_SM_CLIENT_ID, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE }, { display->atom_WM_WINDOW_ROLE, META_PROP_VALUE_INVALID, reload_wm_window_role, FALSE, FALSE }, { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type, FALSE, TRUE }, { display->atom__NET_WM_STRUT, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE }, { display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE }, { display->atom__NET_WM_BYPASS_COMPOSITOR, META_PROP_VALUE_CARDINAL, reload_bypass_compositor, TRUE, TRUE }, { display->atom__NET_WM_XAPP_ICON_NAME, META_PROP_VALUE_UTF8, reload_theme_icon_name, TRUE, TRUE }, { display->atom__NET_WM_XAPP_PROGRESS, META_PROP_VALUE_CARDINAL, reload_progress, TRUE, TRUE }, { display->atom__NET_WM_XAPP_PROGRESS_PULSE, META_PROP_VALUE_CARDINAL, reload_progress_pulse, TRUE, TRUE }, { 0 }, }; MetaWindowPropHooks *table = g_memdup (hooks, sizeof (hooks)), *cursor = table; g_assert (display->prop_hooks == NULL); display->prop_hooks_table = (gpointer) table; display->prop_hooks = g_hash_table_new (NULL, NULL); while (cursor->property) { /* Doing initial loading doesn't make sense if we just want notification */ g_assert (!(hooks->load_initially && hooks->type == META_PROP_VALUE_INVALID)); /* Atoms are safe to use with GINT_TO_POINTER because it's safe with * anything 32 bits or less, and atoms are 32 bits with the top three * bits clear. (Scheifler & Gettys, 2e, p372) */ g_hash_table_insert (display->prop_hooks, GINT_TO_POINTER (cursor->property), cursor); cursor++; } display->n_prop_hooks = cursor - table; } LOCAL_SYMBOL void meta_display_free_window_prop_hooks (MetaDisplay *display) { g_hash_table_unref (display->prop_hooks); display->prop_hooks = NULL; free (display->prop_hooks_table); display->prop_hooks_table = NULL; } static MetaWindowPropHooks* find_hooks (MetaDisplay *display, Atom property) { return g_hash_table_lookup (display->prop_hooks, GINT_TO_POINTER (property)); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/group-props.c�����������������������������������������������������������������0000664�0001750�0001750�00000014075�14211404421�017323� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* MetaGroup property handling */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "group-props.h" #include "group-private.h" #include "xprops.h" #include <X11/Xatom.h> typedef void (* InitValueFunc) (MetaDisplay *display, Atom property, MetaPropValue *value); typedef void (* ReloadValueFunc) (MetaGroup *group, MetaPropValue *value); struct _MetaGroupPropHooks { Atom property; InitValueFunc init_func; ReloadValueFunc reload_func; }; static void init_prop_value (MetaDisplay *display, Atom property, MetaPropValue *value); static void reload_prop_value (MetaGroup *group, MetaPropValue *value); static MetaGroupPropHooks* find_hooks (MetaDisplay *display, Atom property); LOCAL_SYMBOL void meta_group_reload_property (MetaGroup *group, Atom property) { meta_group_reload_properties (group, &property, 1); } LOCAL_SYMBOL void meta_group_reload_properties (MetaGroup *group, const Atom *properties, int n_properties) { int i; MetaPropValue *values; g_return_if_fail (properties != NULL); g_return_if_fail (n_properties > 0); values = g_new0 (MetaPropValue, n_properties); i = 0; while (i < n_properties) { init_prop_value (group->display, properties[i], &values[i]); ++i; } meta_prop_get_values (group->display, group->group_leader, values, n_properties); i = 0; while (i < n_properties) { reload_prop_value (group, &values[i]); ++i; } meta_prop_free_values (values, n_properties); free (values); } /* Fill in the MetaPropValue used to get the value of "property" */ static void init_prop_value (MetaDisplay *display, Atom property, MetaPropValue *value) { MetaGroupPropHooks *hooks; value->type = META_PROP_VALUE_INVALID; value->atom = None; hooks = find_hooks (display, property); if (hooks && hooks->init_func != NULL) (* hooks->init_func) (display, property, value); } static void reload_prop_value (MetaGroup *group, MetaPropValue *value) { MetaGroupPropHooks *hooks; hooks = find_hooks (group->display, value->atom); if (hooks && hooks->reload_func != NULL) (* hooks->reload_func) (group, value); } static void init_wm_client_machine (MetaDisplay *display, Atom property, MetaPropValue *value) { value->type = META_PROP_VALUE_STRING; value->atom = display->atom_WM_CLIENT_MACHINE; } static void reload_wm_client_machine (MetaGroup *group, MetaPropValue *value) { free (group->wm_client_machine); group->wm_client_machine = NULL; if (value->type != META_PROP_VALUE_INVALID) group->wm_client_machine = g_strdup (value->v.str); meta_verbose ("Group has client machine \"%s\"\n", group->wm_client_machine ? group->wm_client_machine : "unset"); } static void init_net_startup_id (MetaDisplay *display, Atom property, MetaPropValue *value) { value->type = META_PROP_VALUE_UTF8; value->atom = display->atom__NET_STARTUP_ID; } static void reload_net_startup_id (MetaGroup *group, MetaPropValue *value) { free (group->startup_id); group->startup_id = NULL; if (value->type != META_PROP_VALUE_INVALID) group->startup_id = g_strdup (value->v.str); meta_verbose ("Group has startup id \"%s\"\n", group->startup_id ? group->startup_id : "unset"); } #define N_HOOKS 3 LOCAL_SYMBOL void meta_display_init_group_prop_hooks (MetaDisplay *display) { int i; MetaGroupPropHooks *hooks; g_assert (display->group_prop_hooks == NULL); display->group_prop_hooks = g_new0 (MetaGroupPropHooks, N_HOOKS); hooks = display->group_prop_hooks; i = 0; hooks[i].property = display->atom_WM_CLIENT_MACHINE; hooks[i].init_func = init_wm_client_machine; hooks[i].reload_func = reload_wm_client_machine; ++i; hooks[i].property = display->atom__NET_WM_PID; hooks[i].init_func = NULL; hooks[i].reload_func = NULL; ++i; hooks[i].property = display->atom__NET_STARTUP_ID; hooks[i].init_func = init_net_startup_id; hooks[i].reload_func = reload_net_startup_id; ++i; if (i != N_HOOKS) { g_error ("Initialized %d group hooks should have been %d\n", i, N_HOOKS); } } LOCAL_SYMBOL void meta_display_free_group_prop_hooks (MetaDisplay *display) { g_assert (display->group_prop_hooks != NULL); free (display->group_prop_hooks); display->group_prop_hooks = NULL; } static MetaGroupPropHooks* find_hooks (MetaDisplay *display, Atom property) { int i; /* FIXME we could sort the array and do binary search or * something */ i = 0; while (i < N_HOOKS) { if (display->group_prop_hooks[i].property == property) return &display->group_prop_hooks[i]; ++i; } return NULL; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/display-private.h�������������������������������������������������������������0000664�0001750�0001750�00000037164�14211404421�020154� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X display handler */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002 Red Hat, Inc. * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_DISPLAY_PRIVATE_H #define META_DISPLAY_PRIVATE_H #ifndef PACKAGE #error "config.h not included" #endif #include <glib.h> #include <X11/Xlib.h> #include "eventqueue.h" #include <meta/common.h> #include <meta/boxes.h> #include <meta/display.h> #include "keybindings-private.h" #include <meta/prefs.h> #include "ui.h" #ifdef HAVE_STARTUP_NOTIFICATION #include <libsn/sn.h> #endif #ifdef HAVE_XSYNC #include <X11/extensions/sync.h> #endif typedef struct _MetaStack MetaStack; typedef struct _MetaUISlave MetaUISlave; typedef struct _MetaGroupPropHooks MetaGroupPropHooks; typedef struct _MetaWindowPropHooks MetaWindowPropHooks; typedef struct MetaEdgeResistanceData MetaEdgeResistanceData; typedef void (* MetaWindowPingFunc) (MetaDisplay *display, Window xwindow, guint32 timestamp, gpointer user_data); #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ #define _NET_WM_STATE_ADD 1 /* add/set property */ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ /* This is basically a bogus number, just has to be large enough * to handle the expected case of the alt+tab operation, where * we want to ignore serials from UnmapNotify on the tab popup, * and the LeaveNotify/EnterNotify from the pointer ungrab. It * also has to be big enough to hold ignored serials from the point * where we reshape the stage to the point where we get events back. */ #define N_IGNORED_CROSSING_SERIALS 10 struct _MetaDisplay { GObject parent_instance; char *name; Display *xdisplay; GdkDisplay *gdk_display; GdkDevice *gdk_device; char *hostname; Window leader_window; Window timestamp_pinging_window; MetaUI *ui; /* Pull in all the names of atoms as fields; we will intern them when the * class is constructed. */ #define item(x) Atom atom_##x; #include <meta/atomnames.h> #undef item /* This is the actual window from focus events, * not the one we last set */ MetaWindow *focus_window; /* window we are expecting a FocusIn event for or the current focus * window if we are not expecting any FocusIn/FocusOut events; not * perfect because applications can call XSetInputFocus directly. * (It could also be messed up if a timestamp later than current * time is sent to meta_display_set_input_focus_window, though that * would be a programming error). See bug 154598 for more info. */ MetaWindow *expected_focus_window; /* last timestamp passed to XSetInputFocus */ guint32 last_focus_time; /* last user interaction time in any app */ guint32 last_user_time; /* whether we're using mousenav (only relevant for sloppy&mouse focus modes; * !mouse_mode means "keynav mode") */ guint mouse_mode : 1; /* Helper var used when focus_new_windows setting is 'strict'; only * relevant in 'strict' mode and if the focus window is a terminal. * In that case, we don't allow new windows to take focus away from * a terminal, but if the user explicitly did something that should * allow a different window to gain focus (e.g. global keybinding or * clicking on a dock), then we will allow the transfer. */ guint allow_terminal_deactivation : 1; guint static_gravity_works : 1; /*< private-ish >*/ guint error_trap_synced_at_last_pop : 1; MetaEventQueue *events; GSList *screens; MetaScreen *active_screen; GHashTable *window_ids; int error_traps; int (* error_trap_handler) (Display *display, XErrorEvent *error); int server_grab_count; /* serials of leave/unmap events that may * correspond to an enter event we should * ignore */ unsigned long ignored_crossing_serials[N_IGNORED_CROSSING_SERIALS]; Window ungrab_should_not_cause_focus_window; guint32 current_time; /* We maintain a sequence counter, incremented for each #MetaWindow * created. This is exposed by meta_window_get_stable_sequence() * but is otherwise not used inside muffin. * * It can be useful to plugins which want to sort windows in a * stable fashion. */ guint32 window_sequence_counter; /* Pings which we're waiting for a reply from */ GSList *pending_pings; /* Pending autoraise */ guint autoraise_timeout_id; MetaWindow* autoraise_window; /* Alt+click button grabs */ unsigned int window_grab_modifiers; unsigned int mouse_zoom_modifiers; /* current window operation */ MetaGrabOp grab_op; MetaScreen *grab_screen; MetaWindow *grab_window; Window grab_xwindow; int grab_button; int grab_anchor_root_x; int grab_anchor_root_y; MetaRectangle grab_anchor_window_pos; MetaTileMode grab_tile_mode; int grab_tile_monitor_number; int grab_latest_motion_x; int grab_latest_motion_y; gulong grab_mask; guint grab_have_pointer : 1; guint grab_have_keyboard : 1; guint grab_frame_action : 1; /* During a resize operation, the directions in which we've broken * out of the initial maximization state */ guint grab_resize_unmaximize : 2; /* MetaMaximizeFlags */ MetaRectangle grab_initial_window_pos; int grab_initial_x, grab_initial_y; /* These are only relevant for */ gboolean grab_threshold_movement_reached; /* raise_on_click == FALSE. */ MetaResizePopup *grab_resize_popup; GTimeVal grab_last_moveresize_time; guint32 grab_motion_notify_time; GList* grab_old_window_stacking; MetaEdgeResistanceData *grab_edge_resistance_data; unsigned int grab_last_user_action_was_snap; /* we use property updates as sentinels for certain window focus events * to avoid some race conditions on EnterNotify events */ int sentinel_counter; #ifdef HAVE_XKB int xkb_base_event_type; guint32 last_bell_time; #endif int grab_resize_timeout_id; /* Keybindings stuff */ MetaKeyBinding *key_bindings; int n_key_bindings; int min_keycode; int max_keycode; KeySym *keymap; int keysyms_per_keycode; XModifierKeymap *modmap; unsigned int above_tab_keycode; unsigned int ignored_modifier_mask; unsigned int num_lock_mask; unsigned int scroll_lock_mask; unsigned int hyper_mask; unsigned int super_mask; unsigned int meta_mask; guint rebuild_keybinding_idle_id; /* Monitor cache */ unsigned int monitor_cache_invalidated : 1; /* Opening the display */ unsigned int display_opening : 1; /* Closing down the display */ int closing; /* Managed by group.c */ GHashTable *groups_by_leader; /* currently-active window menu if any */ MetaWindowMenu *window_menu; MetaWindow *window_with_menu; /* Managed by window-props.c */ MetaWindowPropHooks *prop_hooks_table; GHashTable *prop_hooks; int n_prop_hooks; /* Managed by group-props.c */ MetaGroupPropHooks *group_prop_hooks; /* Managed by compositor.c */ MetaCompositor *compositor; unsigned int mouse_zoom_enabled : 1; int render_event_base; int render_error_base; int composite_event_base; int composite_error_base; int composite_major_version; int composite_minor_version; int damage_event_base; int damage_error_base; int xfixes_event_base; int xfixes_error_base; #ifdef HAVE_STARTUP_NOTIFICATION SnDisplay *sn_display; #endif #ifdef HAVE_XSYNC int xsync_event_base; int xsync_error_base; #endif #ifdef HAVE_SHAPE int shape_event_base; int shape_error_base; #endif #ifdef HAVE_XSYNC unsigned int have_xsync : 1; #define META_DISPLAY_HAS_XSYNC(display) ((display)->have_xsync) #else #define META_DISPLAY_HAS_XSYNC(display) FALSE #endif #ifdef HAVE_SHAPE unsigned int have_shape : 1; #define META_DISPLAY_HAS_SHAPE(display) ((display)->have_shape) #else #define META_DISPLAY_HAS_SHAPE(display) FALSE #endif unsigned int have_render : 1; #define META_DISPLAY_HAS_RENDER(display) ((display)->have_render) unsigned int have_composite : 1; unsigned int have_damage : 1; unsigned int have_xfixes : 1; #define META_DISPLAY_HAS_COMPOSITE(display) ((display)->have_composite) #define META_DISPLAY_HAS_DAMAGE(display) ((display)->have_damage) #define META_DISPLAY_HAS_XFIXES(display) ((display)->have_xfixes) MetaSyncMethod sync_method; guint shadows_enabled : 1; guint debug_button_grabs : 1; }; struct _MetaDisplayClass { GObjectClass parent_class; }; #define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \ ( (( (time1) < (time2) ) && ( (time2) - (time1) < ((guint32)-1)/2 )) || \ (( (time1) > (time2) ) && ( (time1) - (time2) > ((guint32)-1)/2 )) \ ) /** * XSERVER_TIME_IS_BEFORE: * * See the docs for meta_display_xserver_time_is_before(). */ #define XSERVER_TIME_IS_BEFORE(time1, time2) \ ( (time1) == 0 || \ (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) && \ (time2) != 0) \ ) gboolean meta_display_open (void); void meta_display_close (MetaDisplay *display, guint32 timestamp); MetaScreen* meta_display_screen_for_x_screen (MetaDisplay *display, Screen *screen); MetaScreen* meta_display_screen_for_xwindow (MetaDisplay *display, Window xindow); void meta_display_grab (MetaDisplay *display); void meta_display_ungrab (MetaDisplay *display); void meta_display_unmanage_windows_for_screen (MetaDisplay *display, MetaScreen *screen, guint32 timestamp); /* Utility function to compare the stacking of two windows */ int meta_display_stack_cmp (const void *a, const void *b); /* A given MetaWindow may have various X windows that "belong" * to it, such as the frame window. */ MetaWindow* meta_display_lookup_x_window (MetaDisplay *display, Window xwindow); void meta_display_register_x_window (MetaDisplay *display, Window *xwindowp, MetaWindow *window); void meta_display_unregister_x_window (MetaDisplay *display, Window xwindow); #ifdef HAVE_XSYNC MetaWindow* meta_display_lookup_sync_alarm (MetaDisplay *display, XSyncAlarm alarm); void meta_display_register_sync_alarm (MetaDisplay *display, XSyncAlarm *alarmp, MetaWindow *window); void meta_display_unregister_sync_alarm (MetaDisplay *display, XSyncAlarm alarm); #endif /* HAVE_XSYNC */ void meta_display_notify_window_created (MetaDisplay *display, MetaWindow *window); MetaDisplay* meta_display_for_x_display (Display *xdisplay); MetaDisplay* meta_get_display (void); Cursor meta_display_create_x_cursor (MetaDisplay *display, MetaCursor cursor); void meta_display_set_grab_op_cursor (MetaDisplay *display, MetaScreen *screen, MetaGrabOp op, gboolean change_pointer, Window grab_xwindow, guint32 timestamp); void meta_display_check_threshold_reached (MetaDisplay *display, int x, int y); void meta_display_grab_window_buttons (MetaDisplay *display, Window xwindow); void meta_display_ungrab_window_buttons (MetaDisplay *display, Window xwindow); void meta_display_grab_focus_window_button (MetaDisplay *display, MetaWindow *window); void meta_display_ungrab_focus_window_button (MetaDisplay *display, MetaWindow *window); /* Next function is defined in edge-resistance.c */ void meta_display_cleanup_edges (MetaDisplay *display); /* make a request to ensure the event serial has changed */ void meta_display_increment_event_serial (MetaDisplay *display); void meta_display_update_active_window_hint (MetaDisplay *display); /* utility goo */ const char* meta_event_mode_to_string (int m); const char* meta_event_detail_to_string (int d); void meta_display_queue_retheme_all_windows (MetaDisplay *display); void meta_display_retheme_all (void); void meta_display_set_cursor_theme (const char *theme, int size); void meta_display_ping_window (MetaDisplay *display, MetaWindow *window, guint32 timestamp, MetaWindowPingFunc ping_reply_func, MetaWindowPingFunc ping_timeout_func, void *user_data); gboolean meta_display_window_has_pending_pings (MetaDisplay *display, MetaWindow *window); int meta_resize_gravity_from_grab_op (MetaGrabOp op); int meta_resize_gravity_from_tile_mode (MetaTileMode mode); gboolean meta_grab_op_is_moving (MetaGrabOp op); gboolean meta_grab_op_is_resizing (MetaGrabOp op); void meta_display_devirtualize_modifiers (MetaDisplay *display, MetaVirtualModifier modifiers, unsigned int *mask); void meta_display_increment_focus_sentinel (MetaDisplay *display); void meta_display_decrement_focus_sentinel (MetaDisplay *display); gboolean meta_display_focus_sentinel_clear (MetaDisplay *display); void meta_display_queue_autoraise_callback (MetaDisplay *display, MetaWindow *window); void meta_display_remove_autoraise_callback (MetaDisplay *display); /* In above-tab-keycode.c */ guint meta_display_get_above_tab_keycode (MetaDisplay *display); void meta_display_notify_restart (MetaDisplay *display); void meta_display_update_sync_state (MetaSyncMethod method); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/stack-tracker.c���������������������������������������������������������������0000664�0001750�0001750�00000050167�14211404421�017566� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <string.h> #include "frame.h" #include "screen-private.h" #include "stack-tracker.h" #include <meta/util.h> #include <meta/compositor.h> /* The complexity here comes from resolving two competing factors: * * - We need to have a view of the stacking order that takes into * account everything we have done without waiting for events * back from the X server; we don't want to draw intermediate * partially-stacked stack states just because we haven't received * some notification yet. * * - Only the X server has an accurate view of the complete stacking; * when we make a request to restack windows, we don't know how * it will affect override-redirect windows, because at any point * applications may restack these windows without our involvement. * * The technique we use is that we keep three sets of information: * * - The stacking order on the server as known from the last * event we received. * - A queue of stacking requests that *we* made subsequent to * that last event. * - A predicted stacking order, derived from applying the queued * requests to the last state from the server. * * When we receive a new event: a) we compare the serial in the event to * the serial of the queued requests and remove any that are now * no longer pending b) if necessary, drop the predicted stacking * order to recompute it at the next opportunity. * * Possible optimizations: * Keep the stacks as an array + reverse-mapping hash table to avoid * linear lookups. * Keep the stacks as a GList + reverse-mapping hash table to avoid * linear lookups and to make restacking constant-time. */ typedef union _MetaStackOp MetaStackOp; typedef enum { STACK_OP_ADD, STACK_OP_REMOVE, STACK_OP_RAISE_ABOVE, STACK_OP_LOWER_BELOW } MetaStackOpType; /* MetaStackOp represents a "stacking operation" - a change to * apply to a window stack. Depending on the context, it could * either reflect a request we have sent to the server, or a * notification event we received from the X server. */ union _MetaStackOp { struct { MetaStackOpType type; gulong serial; } any; struct { MetaStackOpType type; gulong serial; Window window; } add; struct { MetaStackOpType type; gulong serial; Window window; } remove; struct { MetaStackOpType type; gulong serial; Window window; Window sibling; } raise_above; struct { MetaStackOpType type; gulong serial; Window window; Window sibling; } lower_below; }; struct _MetaStackTracker { MetaScreen *screen; /* This is the last state of the stack as based on events received * from the X server. */ GArray *server_stack; /* This is the serial of the last request we made that was reflected * in server_stack */ gulong server_serial; /* This is a queue of requests we've made to change the stacking order, * where we haven't yet gotten a reply back from the server. */ GQueue *queued_requests; /* This is how we think the stack is, based on server_stack, and * on requests we've made subsequent to server_stack */ GArray *predicted_stack; /* Idle function used to sync the compositor's view of the window * stack up with our best guess before a frame is drawn. */ guint sync_stack_later; }; static void meta_stack_op_dump (MetaStackOp *op, const char *prefix, const char *suffix) { switch (op->any.type) { case STACK_OP_ADD: meta_topic (META_DEBUG_STACK, "%sADD(%#lx; %ld)%s", prefix, op->add.window, op->any.serial, suffix); break; case STACK_OP_REMOVE: meta_topic (META_DEBUG_STACK, "%sREMOVE(%#lx; %ld)%s", prefix, op->add.window, op->any.serial, suffix); break; case STACK_OP_RAISE_ABOVE: meta_topic (META_DEBUG_STACK, "%sRAISE_ABOVE(%#lx, %#lx; %ld)%s", prefix, op->raise_above.window, op->raise_above.sibling, op->any.serial, suffix); break; case STACK_OP_LOWER_BELOW: meta_topic (META_DEBUG_STACK, "%sLOWER_BELOW(%#lx, %#lx; %ld)%s", prefix, op->lower_below.window, op->lower_below.sibling, op->any.serial, suffix); break; } } static void meta_stack_tracker_dump (MetaStackTracker *tracker) { guint i; GList *l; meta_topic (META_DEBUG_STACK, "MetaStackTracker state (screen=%d)\n", tracker->screen->number); meta_push_no_msg_prefix (); meta_topic (META_DEBUG_STACK, " server_serial: %ld\n", tracker->server_serial); meta_topic (META_DEBUG_STACK, " server_stack: "); for (i = 0; i < tracker->server_stack->len; i++) meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->server_stack, Window, i)); if (tracker->predicted_stack) { meta_topic (META_DEBUG_STACK, "\n predicted_stack: "); for (i = 0; i < tracker->predicted_stack->len; i++) meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->predicted_stack, Window, i)); } meta_topic (META_DEBUG_STACK, "\n queued_requests: ["); for (l = tracker->queued_requests->head; l; l = l->next) { MetaStackOp *op = l->data; meta_stack_op_dump (op, "", l->next ? ", " : ""); } meta_topic (META_DEBUG_STACK, "]\n"); meta_pop_no_msg_prefix (); } static void meta_stack_op_free (MetaStackOp *op) { g_slice_free (MetaStackOp, op); } static int find_window (GArray *stack, Window window) { guint i; for (i = 0; i < stack->len; i++) if (g_array_index (stack, Window, i) == window) return i; return -1; } /* Returns TRUE if stack was changed */ static gboolean move_window_above (GArray *stack, Window window, int old_pos, int above_pos) { int i; if (old_pos < above_pos) { for (i = old_pos; i < above_pos; i++) g_array_index (stack, Window, i) = g_array_index (stack, Window, i + 1); g_array_index (stack, Window, above_pos) = window; return TRUE; } else if (old_pos > above_pos + 1) { for (i = old_pos; i > above_pos + 1; i--) g_array_index (stack, Window, i) = g_array_index (stack, Window, i - 1); g_array_index (stack, Window, above_pos + 1) = window; return TRUE; } else return FALSE; } /* Returns TRUE if stack was changed */ static gboolean meta_stack_op_apply (MetaStackOp *op, GArray *stack) { switch (op->any.type) { case STACK_OP_ADD: { int old_pos = find_window (stack, op->add.window); if (old_pos >= 0) { g_warning ("STACK_OP_ADD: window %#lx already in stack", op->add.window); return FALSE; } g_array_append_val (stack, op->add.window); return TRUE; } case STACK_OP_REMOVE: { int old_pos = find_window (stack, op->remove.window); if (old_pos < 0) { g_warning ("STACK_OP_REMOVE: window %#lx not in stack", op->remove.window); return FALSE; } g_array_remove_index (stack, old_pos); return TRUE; } case STACK_OP_RAISE_ABOVE: { int old_pos = find_window (stack, op->raise_above.window); int above_pos; if (old_pos < 0) { g_warning ("STACK_OP_RAISE_ABOVE: window %#lx not in stack", op->raise_above.window); return FALSE; } if (op->raise_above.sibling != None) { above_pos = find_window (stack, op->raise_above.sibling); if (above_pos < 0) { g_warning ("STACK_OP_RAISE_ABOVE: sibling window %#lx not in stack", op->raise_above.sibling); return FALSE; } } else { above_pos = -1; } return move_window_above (stack, op->raise_above.window, old_pos, above_pos); } case STACK_OP_LOWER_BELOW: { int old_pos = find_window (stack, op->lower_below.window); int above_pos; if (old_pos < 0) { g_warning ("STACK_OP_LOWER_BELOW: window %#lx not in stack", op->lower_below.window); return FALSE; } if (op->lower_below.sibling != None) { int below_pos = find_window (stack, op->lower_below.sibling); if (below_pos < 0) { g_warning ("STACK_OP_LOWER_BELOW: sibling window %#lx not in stack", op->lower_below.sibling); return FALSE; } above_pos = below_pos - 1; } else { above_pos = stack->len - 1; } return move_window_above (stack, op->lower_below.window, old_pos, above_pos); } } g_assert_not_reached (); return FALSE; } static GArray * copy_stack (Window *windows, guint n_windows) { GArray *stack = g_array_new (FALSE, FALSE, sizeof (Window)); g_array_set_size (stack, n_windows); memcpy (stack->data, windows, sizeof (Window) * n_windows); return stack; } LOCAL_SYMBOL MetaStackTracker * meta_stack_tracker_new (MetaScreen *screen) { MetaStackTracker *tracker; Window ignored1, ignored2; Window *children; guint n_children; tracker = g_new0 (MetaStackTracker, 1); tracker->screen = screen; tracker->server_serial = XNextRequest (screen->display->xdisplay); XQueryTree (screen->display->xdisplay, screen->xroot, &ignored1, &ignored2, &children, &n_children); tracker->server_stack = copy_stack (children, n_children); XFree (children); tracker->queued_requests = g_queue_new (); return tracker; } LOCAL_SYMBOL void meta_stack_tracker_free (MetaStackTracker *tracker) { if (tracker->sync_stack_later) meta_later_remove (tracker->sync_stack_later); g_array_free (tracker->server_stack, TRUE); if (tracker->predicted_stack) g_array_free (tracker->predicted_stack, TRUE); g_queue_foreach (tracker->queued_requests, (GFunc)meta_stack_op_free, NULL); g_queue_free (tracker->queued_requests); tracker->queued_requests = NULL; free (tracker); } static void stack_tracker_queue_request (MetaStackTracker *tracker, MetaStackOp *op) { meta_stack_op_dump (op, "Queueing: ", "\n"); g_queue_push_tail (tracker->queued_requests, op); if (!tracker->predicted_stack || meta_stack_op_apply (op, tracker->predicted_stack)) meta_stack_tracker_queue_sync_stack (tracker); meta_stack_tracker_dump (tracker); } LOCAL_SYMBOL void meta_stack_tracker_record_add (MetaStackTracker *tracker, Window window, gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_ADD; op->any.serial = serial; op->add.window = window; stack_tracker_queue_request (tracker, op); } LOCAL_SYMBOL void meta_stack_tracker_record_remove (MetaStackTracker *tracker, Window window, gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_REMOVE; op->any.serial = serial; op->remove.window = window; stack_tracker_queue_request (tracker, op); } LOCAL_SYMBOL void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, Window *windows, int n_windows, gulong serial) { int i; /* XRestackWindows() isn't actually a X requests - it's broken down * by XLib into a series of XConfigureWindow(StackMode=below); we * mirror that exactly here. * * Aside: Having a separate StackOp for this would be possible to * get some extra efficiency in memory allocation and in applying * the op, at the expense of a code complexity. Implementation hint * for that - keep op->restack_window.n_complete, and when receiving * events with intermediate serials, set n_complete rather than * removing the op from the queue. */ for (i = 0; i < n_windows - 1; i++) meta_stack_tracker_record_lower_below (tracker, windows[i + 1], windows[i], serial + i); } LOCAL_SYMBOL void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, Window window, Window sibling, gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_RAISE_ABOVE; op->any.serial = serial; op->raise_above.window = window; op->raise_above.sibling = sibling; stack_tracker_queue_request (tracker, op); } LOCAL_SYMBOL LOCAL_SYMBOL void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, Window window, Window sibling, gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_LOWER_BELOW; op->any.serial = serial; op->lower_below.window = window; op->lower_below.sibling = sibling; stack_tracker_queue_request (tracker, op); } LOCAL_SYMBOL void meta_stack_tracker_record_lower (MetaStackTracker *tracker, Window window, gulong serial) { meta_stack_tracker_record_raise_above (tracker, window, None, serial); } static void stack_tracker_event_received (MetaStackTracker *tracker, MetaStackOp *op) { gboolean need_sync = FALSE; meta_stack_op_dump (op, "Stack op event received: ", "\n"); if (op->any.serial < tracker->server_serial) return; tracker->server_serial = op->any.serial; if (meta_stack_op_apply (op, tracker->server_stack)) need_sync = TRUE; while (tracker->queued_requests->head) { MetaStackOp *queued_op = tracker->queued_requests->head->data; if (queued_op->any.serial > op->any.serial) break; g_queue_pop_head (tracker->queued_requests); meta_stack_op_free (queued_op); need_sync = TRUE; } if (need_sync) { if (tracker->predicted_stack) { g_array_free (tracker->predicted_stack, TRUE); tracker->predicted_stack = NULL; } meta_stack_tracker_queue_sync_stack (tracker); } meta_stack_tracker_dump (tracker); } LOCAL_SYMBOL void meta_stack_tracker_create_event (MetaStackTracker *tracker, XCreateWindowEvent *event) { MetaStackOp op; op.any.type = STACK_OP_ADD; op.any.serial = event->serial; op.add.window = event->window; stack_tracker_event_received (tracker, &op); } LOCAL_SYMBOL void meta_stack_tracker_destroy_event (MetaStackTracker *tracker, XDestroyWindowEvent *event) { MetaStackOp op; op.any.type = STACK_OP_REMOVE; op.any.serial = event->serial; op.remove.window = event->window; stack_tracker_event_received (tracker, &op); } LOCAL_SYMBOL void meta_stack_tracker_reparent_event (MetaStackTracker *tracker, XReparentEvent *event) { if (event->parent == event->event) { MetaStackOp op; op.any.type = STACK_OP_ADD; op.any.serial = event->serial; op.add.window = event->window; stack_tracker_event_received (tracker, &op); } else { MetaStackOp op; op.any.type = STACK_OP_REMOVE; op.any.serial = event->serial; op.remove.window = event->window; stack_tracker_event_received (tracker, &op); } } LOCAL_SYMBOL void meta_stack_tracker_configure_event (MetaStackTracker *tracker, XConfigureEvent *event) { MetaStackOp op; op.any.type = STACK_OP_RAISE_ABOVE; op.any.serial = event->serial; op.raise_above.window = event->window; op.raise_above.sibling = event->above; stack_tracker_event_received (tracker, &op); } /** * meta_stack_tracker_get_stack: * @tracker: a #MetaStackTracker * @windows: location to store list of windows, or %NULL * @n_windows: location to store count of windows, or %NULL * * Returns the most current view we have of the stacking order * of the children of the root window. The returned array contains * everything: InputOnly windows, override-redirect windows, * hidden windows, etc. Some of these will correspond to MetaWindow * objects, others won't. * * Assuming that no other clients have made requests that change * the stacking order since we last received a notification, the * returned list of windows is exactly that you'd get as the * children when calling XQueryTree() on the root window. */ LOCAL_SYMBOL void meta_stack_tracker_get_stack (MetaStackTracker *tracker, Window **windows, int *n_windows) { GArray *stack; if (tracker->queued_requests->length == 0) { stack = tracker->server_stack; } else { if (tracker->predicted_stack == NULL) { GList *l; tracker->predicted_stack = copy_stack ((Window *)tracker->server_stack->data, tracker->server_stack->len); for (l = tracker->queued_requests->head; l; l = l->next) { MetaStackOp *op = l->data; meta_stack_op_apply (op, tracker->predicted_stack); } } stack = tracker->predicted_stack; } if (windows) *windows = (Window *)stack->data; if (n_windows) *n_windows = stack->len; } /** * meta_stack_tracker_sync_stack: * @tracker: a #MetaStackTracker * * Informs the compositor of the current stacking order of windows, * based on the predicted view maintained by the #MetaStackTracker. */ LOCAL_SYMBOL void meta_stack_tracker_sync_stack (MetaStackTracker *tracker) { GList *meta_windows; Window *windows; int n_windows; int i; if (tracker->sync_stack_later) { meta_later_remove (tracker->sync_stack_later); tracker->sync_stack_later = 0; } meta_stack_tracker_get_stack (tracker, &windows, &n_windows); meta_windows = NULL; for (i = 0; i < n_windows; i++) { MetaWindow *meta_window; meta_window = meta_display_lookup_x_window (tracker->screen->display, windows[i]); /* When mapping back from xwindow to MetaWindow we have to be a bit careful; * children of the root could include unmapped windows created by toolkits * for internal purposes, including ones that we have registered in our * XID => window table. (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW; * see window-prop.c:reload_net_wm_user_time_window() for registration.) */ if (meta_window && (windows[i] == meta_window->xwindow || (meta_window->frame && windows[i] == meta_window->frame->xwindow))) meta_windows = g_list_prepend (meta_windows, meta_window); } if (tracker->screen->display->compositor) meta_compositor_sync_stack (tracker->screen->display->compositor, tracker->screen, meta_windows); g_list_free (meta_windows); meta_screen_restacked (tracker->screen); } static gboolean stack_tracker_sync_stack_later (gpointer data) { meta_stack_tracker_sync_stack (data); return FALSE; } /** * meta_stack_tracker_queue_sync_stack: * @tracker: a #MetaStackTracker * * Queue informing the compositor of the new stacking order before the * next redraw. (See meta_stack_tracker_sync_stack()). This is called * internally when the stack of X windows changes, but also needs be * called directly when we an undecorated window is first shown or * withdrawn since the compositor's stacking order (which contains only * the windows that have a corresponding MetaWindow) will change without * any change to the stacking order of the X windows, if we are creating * or destroying MetaWindows. */ LOCAL_SYMBOL void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker) { if (tracker->sync_stack_later == 0) { tracker->sync_stack_later = meta_later_add (META_LATER_SYNC_STACK, stack_tracker_sync_stack_later, tracker, NULL); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/place.h�����������������������������������������������������������������������0000664�0001750�0001750�00000002317�14211404421�016113� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window placement */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_PLACE_H #define META_PLACE_H #include "window-private.h" #include "frame.h" void meta_window_place (MetaWindow *window, MetaFrameBorders *borders, int x, int y, int *new_x, int *new_y); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/main.c������������������������������������������������������������������������0000664�0001750�0001750�00000045423�14211404421�015753� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin main() */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:main * @title: Main * @short_description: Program startup. * * Functions which parse the command-line arguments, create the display, * kick everything off and then close down Muffin when it's time to go. * * * * Muffin - a boring window manager for the adult in you * * Many window managers are like Marshmallow Froot Loops; Muffin * is like Cheerios. * * The best way to get a handle on how the whole system fits together * is discussed in doc/code-overview.txt; if you're looking for functions * to investigate, read main(), meta_display_open(), and event_callback(). */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _SVID_SOURCE /* for putenv() and some signal-related functions */ #include <config.h> #include <meta/main.h> #include "util-private.h" #include "display-private.h" #include <meta/errors.h> #include "ui.h" #include "session.h" #include <meta/prefs.h> #include <meta/compositor.h> #include <glib-object.h> #include <gdk/gdkx.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <locale.h> #include <time.h> #include <unistd.h> #include <clutter/clutter.h> #include "clutter/x11/clutter-x11.h" #include "cogl/cogl.h" #include "cogl/cogl-xlib.h" #include "cogl/winsys/cogl-winsys-glx-private.h" #include <GL/gl.h> #ifdef HAVE_INTROSPECTION #include <girepository.h> #endif /* * The exit code we'll return to our parent process when we eventually die. */ static MetaExitCode meta_exit_code = META_EXIT_SUCCESS; /* * Handle on the main loop, so that we have an easy way of shutting Muffin * down. */ static GMainLoop *meta_main_loop = NULL; static void prefs_changed_callback (MetaPreference pref, gpointer data); /* * Prints log messages. If Muffin was compiled with backtrace support, * also prints a backtrace (see meta_print_backtrace()). * * \param log_domain the domain the error occurred in (we ignore this) * \param log_level the log level so that we can filter out less * important messages * \param message the message to log * \param user_data arbitrary data (we ignore this) */ static void log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { meta_warning ("Log level %d: %s\n", log_level, message); meta_print_backtrace (); } static void glib_debug_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { guint i; const gchar *forbidden[] = { "posix_spawn", "setenv()/putenv()", "unsetenv()" }; for (i = 0; i < G_N_ELEMENTS (forbidden); i++) { if (g_str_has_prefix (message, forbidden[i])) { return; } } log_handler (log_domain, log_level, message, user_data); } /* * Prints a list of which configure script options were used to * build this copy of Muffin. This is actually always called * on startup, but it's all no-op unless we're in verbose mode * (see meta_set_verbose). */ static void meta_print_compilation_info (void) { #ifdef HAVE_SHAPE meta_verbose ("Compiled with shape extension\n"); #else meta_verbose ("Compiled without shape extension\n"); #endif #ifdef HAVE_XINERAMA meta_topic (META_DEBUG_XINERAMA, "Compiled with Xinerama extension\n"); #else meta_topic (META_DEBUG_XINERAMA, "Compiled without Xinerama extension\n"); #endif #ifdef HAVE_XFREE_XINERAMA meta_topic (META_DEBUG_XINERAMA, " (using XFree86 Xinerama)\n"); #else meta_topic (META_DEBUG_XINERAMA, " (not using XFree86 Xinerama)\n"); #endif #ifdef HAVE_SOLARIS_XINERAMA meta_topic (META_DEBUG_XINERAMA, " (using Solaris Xinerama)\n"); #else meta_topic (META_DEBUG_XINERAMA, " (not using Solaris Xinerama)\n"); #endif #ifdef HAVE_XSYNC meta_verbose ("Compiled with sync extension\n"); #else meta_verbose ("Compiled without sync extension\n"); #endif #ifdef HAVE_RANDR meta_verbose ("Compiled with randr extension\n"); #else meta_verbose ("Compiled without randr extension\n"); #endif #ifdef HAVE_STARTUP_NOTIFICATION meta_verbose ("Compiled with startup notification\n"); #else meta_verbose ("Compiled without startup notification\n"); #endif } /* * Prints the version number, the current timestamp (not the * build date), the locale, the character encoding, and a list * of configure script options that were used to build this * copy of Muffin. This is actually always called * on startup, but it's all no-op unless we're in verbose mode * (see meta_set_verbose). */ static void meta_print_self_identity (void) { char buf[256]; GDate d; const char *charset; /* Version and current date. */ g_date_clear (&d, 1); g_date_set_time_t (&d, time (NULL)); g_date_strftime (buf, sizeof (buf), "%x", &d); meta_verbose ("Muffin version %s running on %s\n", VERSION, buf); /* Locale and encoding. */ g_get_charset (&charset); meta_verbose ("Running in locale \"%s\" with encoding \"%s\"\n", setlocale (LC_ALL, NULL), charset); /* Compilation settings. */ meta_print_compilation_info (); } /* * The set of possible options that can be set on Muffin's * command line. */ static gchar *opt_save_file; static gchar *opt_display_name; static gchar *opt_client_id; static gboolean opt_replace_wm; static gboolean opt_disable_sm; static gboolean opt_sync; static GOptionEntry meta_options[] = { { "sm-disable", 0, 0, G_OPTION_ARG_NONE, &opt_disable_sm, N_("Disable connection to session manager"), NULL }, { "replace", 0, 0, G_OPTION_ARG_NONE, &opt_replace_wm, N_("Replace the running window manager"), NULL }, { "sm-client-id", 0, 0, G_OPTION_ARG_STRING, &opt_client_id, N_("Specify session management ID"), "ID" }, { "display", 'd', 0, G_OPTION_ARG_STRING, &opt_display_name, N_("X Display to use"), "DISPLAY" }, { "sm-save-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_save_file, N_("Initialize session from savefile"), "FILE" }, { "sync", 0, 0, G_OPTION_ARG_NONE, &opt_sync, N_("Make X calls synchronous"), NULL }, {NULL} }; /** * meta_get_option_context: (skip) * * Returns a #GOptionContext initialized with muffin-related options. * Parse the command-line args with this before calling meta_init(). * * Return value: the #GOptionContext */ GOptionContext * meta_get_option_context (void) { GOptionContext *ctx; if (setlocale (LC_ALL, "") == NULL) meta_warning ("Locale not understood by C library, internationalization will not work\n"); bindtextdomain (GETTEXT_PACKAGE, MUFFIN_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); ctx = g_option_context_new (NULL); g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE); g_option_context_add_group (ctx, clutter_get_option_group_without_init ()); g_option_context_add_group (ctx, cogl_get_option_group ()); return ctx; } /* Muffin is responsible for pulling events off the X queue, so Clutter * doesn't need (and shouldn't) run its normal event source which polls * the X fd, but we do have to deal with dispatching events that accumulate * in the clutter queue. This happens, for example, when clutter generate * enter/leave events on mouse motion - several events are queued in the * clutter queue but only one dispatched. It could also happen because of * explicit calls to clutter_event_put(). We add a very simple custom * event loop source which is simply responsible for pulling events off * of the queue and dispatching them before we block for new events. */ static gboolean event_prepare (GSource *source, gint *timeout_) { *timeout_ = -1; return clutter_events_pending (); } static gboolean event_check (GSource *source) { return clutter_events_pending (); } static gboolean event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterEvent *event = clutter_event_get (); if (event) clutter_do_event (event); return TRUE; } static GSourceFuncs event_funcs = { event_prepare, event_check, event_dispatch }; static void meta_clutter_init (void) { gboolean threaded_swap = meta_prefs_get_threaded_swap (); Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); clutter_x11_set_display (xdisplay); clutter_x11_disable_event_retrieval (); if (CLUTTER_INIT_SUCCESS == clutter_init (NULL, NULL)) { GSource *source = g_source_new (&event_funcs, sizeof (GSource)); g_source_attach (source, NULL); g_source_unref (source); if (threaded_swap) { CoglRenderer *renderer = cogl_renderer_new (); cogl_renderer_set_custom_winsys (renderer, _cogl_winsys_glx_get_vtable (), NULL); cogl_xlib_renderer_set_foreign_display (renderer, xdisplay); cogl_xlib_renderer_request_reset_on_video_memory_purge (renderer, TRUE); /* Set up things so that if the INTEL_swap_event extension is not present, * but the driver is known to have good thread support, we use an extra * thread and call glXWaitVideoSync() in the thread. This allows idles * to work properly, even when Muffin is constantly redrawing new frames; * otherwise, without INTEL_swap_event, we'll just block in glXSwapBuffers(). */ cogl_xlib_renderer_set_threaded_swap_wait_enabled (renderer, TRUE); } } else { meta_fatal ("Unable to initialize Clutter.\n"); } } /* * Selects which display Muffin should use. It first tries to use * display_name as the display. If display_name is NULL then * try to use the environment variable MUFFIN_DISPLAY. If that * also is NULL, use the default - :0.0 */ static void meta_select_display (gchar *display_name) { gchar *envVar = ""; if (display_name) envVar = g_strconcat ("DISPLAY=", display_name, NULL); else if (g_getenv ("MUFFIN_DISPLAY")) envVar = g_strconcat ("DISPLAY=", g_getenv ("MUFFIN_DISPLAY"), NULL); /* DO NOT FREE envVar, putenv() sucks */ putenv (envVar); } static void meta_finalize (void) { MetaDisplay *display = meta_get_display (); if (display) meta_display_close (display, CurrentTime); /* I doubt correct timestamps matter here */ } static int sigterm_pipe_fds[2] = { -1, -1 }; static void sigterm_handler (int signum) { if (sigterm_pipe_fds[1] >= 0) { int G_GNUC_UNUSED dummy; dummy = write (sigterm_pipe_fds[1], "", 1); close (sigterm_pipe_fds[1]); sigterm_pipe_fds[1] = -1; } } static gboolean on_sigterm (void) { meta_quit (META_EXIT_SUCCESS); return FALSE; } /** * meta_init: (skip) * * Initialize muffin. Call this after meta_get_option_context() and * meta_plugin_manager_set_plugin_type(), and before meta_run(). */ void meta_init (void) { struct sigaction act; sigset_t empty_mask; GIOChannel *channel; gboolean threaded_swap = meta_prefs_get_threaded_swap (); /* XInitThreads() is needed to use the "threaded swap wait" functionality * in Cogl. We call it here to hopefully call it before any other use of XLib. */ if (threaded_swap) XInitThreads(); sigemptyset (&empty_mask); act.sa_handler = SIG_IGN; act.sa_mask = empty_mask; act.sa_flags = 0; if (sigaction (SIGPIPE, &act, NULL) < 0) g_printerr ("Failed to register SIGPIPE handler: %s\n", g_strerror (errno)); #ifdef SIGXFSZ if (sigaction (SIGXFSZ, &act, NULL) < 0) g_printerr ("Failed to register SIGXFSZ handler: %s\n", g_strerror (errno)); #endif if (pipe (sigterm_pipe_fds) != 0) g_printerr ("Failed to create SIGTERM pipe: %s\n", g_strerror (errno)); channel = g_io_channel_unix_new (sigterm_pipe_fds[0]); g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL); g_io_channel_set_close_on_unref (channel, TRUE); g_io_channel_unref (channel); act.sa_handler = &sigterm_handler; if (sigaction (SIGTERM, &act, NULL) < 0) g_printerr ("Failed to register SIGTERM handler: %s\n", g_strerror (errno)); if (g_getenv ("MUFFIN_VERBOSE")) meta_set_verbose (TRUE); if (g_getenv ("MUFFIN_DEBUG")) meta_set_debugging (TRUE); if (g_get_home_dir ()) if (chdir (g_get_home_dir ()) < 0) meta_warning ("Could not change to home directory %s.\n", g_get_home_dir ()); meta_print_self_identity (); #ifdef HAVE_INTROSPECTION g_irepository_prepend_search_path (MUFFIN_PKGLIBDIR); #endif meta_set_syncing (opt_sync || (g_getenv ("MUFFIN_SYNC") != NULL)); meta_select_display (opt_display_name); if (opt_replace_wm) meta_set_replace_current_wm (TRUE); if (opt_save_file && opt_client_id) meta_fatal ("Can't specify both SM save file and SM client id\n"); meta_main_loop = g_main_loop_new (NULL, FALSE); meta_ui_init (); /* * Disable some variables that cause rendering issues with private Clutter, * except when software rendering is explicitly set by Cinnamon. */ g_unsetenv ("CLUTTER_VBLANK"); if (g_getenv ("CINNAMON_SOFTWARE_RENDERING") == NULL) g_unsetenv ("CLUTTER_PAINT"); /* Load prefs */ meta_prefs_init (); _clutter_set_sync_method (meta_prefs_get_sync_method ()); /* * Clutter can only be initialized after the UI. */ meta_clutter_init (); const char *renderer = (const char *) glGetString (GL_RENDERER); if (strstr (renderer, "llvmpipe") || strstr (renderer, "Rasterizer") || strstr (renderer, "softpipe")) { /* Clutter envs not set, since they won't work after Clutter init */ g_setenv ("CINNAMON_SOFTWARE_RENDERING", "1", FALSE); g_setenv ("CINNAMON_SLOWDOWN_FACTOR", "0.0001", FALSE); meta_warning ("Software rendering detected: %s\n", renderer); } } /** * meta_run: (skip) * * Runs muffin. Call this after completing your own initialization. * * Return value: muffin's exit status */ int meta_run (void) { const gchar *log_domains[] = { NULL, G_LOG_DOMAIN, "Gtk", "Gdk", "Pango", "GLib-GObject", "GThread" }; guint i; meta_prefs_add_listener (prefs_changed_callback, NULL); // Intercept GLib debug level g_log_set_handler ("GLib", G_LOG_LEVEL_DEBUG, glib_debug_log_handler, NULL); // Direct all but debug to the normal handler g_log_set_handler ("GLib", (G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION) & ~G_LOG_LEVEL_DEBUG, log_handler, NULL); for (i=0; i<G_N_ELEMENTS(log_domains); i++) g_log_set_handler (log_domains[i], G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, log_handler, NULL); if (g_getenv ("MUFFIN_G_FATAL_WARNINGS") != NULL) g_log_set_always_fatal (G_LOG_LEVEL_MASK); meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE); if (!meta_ui_have_a_theme ()) { meta_ui_set_current_theme ("Default", FALSE); meta_warning ("Could not find theme %s. Falling back to default theme.", meta_prefs_get_theme ()); } /* Connect to SM as late as possible - but before managing display, * or we might try to manage a window before we have the session * info */ if (!opt_disable_sm) { if (opt_client_id == NULL) { const gchar *desktop_autostart_id; desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID"); if (desktop_autostart_id != NULL) opt_client_id = g_strdup (desktop_autostart_id); } /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to * use the same client id. */ g_unsetenv ("DESKTOP_AUTOSTART_ID"); meta_session_init (opt_client_id, opt_save_file); } /* Free memory possibly allocated by the argument parsing which are * no longer needed. */ free (opt_save_file); free (opt_display_name); free (opt_client_id); if (!meta_display_open ()) meta_exit (META_EXIT_ERROR); g_main_loop_run (meta_main_loop); meta_finalize (); return meta_exit_code; } /* * Stops Muffin. This tells the event loop to stop processing; it is * rather dangerous to use this because this will leave the user with * no window manager. We generally do this only if, for example, the * session manager asks us to; we assume the session manager knows * what it's talking about. * * \param code The success or failure code to return to the calling process. */ void meta_quit (MetaExitCode code) { if (g_main_loop_is_running (meta_main_loop)) { meta_exit_code = code; g_main_loop_quit (meta_main_loop); } } /* * Called on pref changes. (One of several functions of its kind and purpose.) * * \bug Why are these particular prefs handled in main.c and not others? * Should they be? * * \param pref Which preference has changed * \param data Arbitrary data (which we ignore) */ static void prefs_changed_callback (MetaPreference pref, gpointer data) { switch (pref) { case META_PREF_THEME: case META_PREF_DRAGGABLE_BORDER_WIDTH: meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE); meta_display_retheme_all (); break; case META_PREF_CURSOR_THEME: case META_PREF_CURSOR_SIZE: meta_display_set_cursor_theme (meta_prefs_get_cursor_theme (), meta_prefs_get_cursor_size ()); break; case META_PREF_SYNC_METHOD: meta_display_update_sync_state (meta_prefs_get_sync_method ()); break; case META_PREF_UI_SCALE: meta_ui_set_current_theme (meta_prefs_get_theme (), TRUE); meta_display_retheme_all (); meta_display_set_cursor_theme (meta_prefs_get_cursor_theme (), meta_prefs_get_cursor_size ()); break; default: /* handled elsewhere or otherwise */ break; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/group-props.h�����������������������������������������������������������������0000664�0001750�0001750�00000002670�14211404421�017326� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* MetaGroup property handling */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_GROUP_PROPS_H #define META_GROUP_PROPS_H #include <meta/group.h> #include "window-private.h" void meta_group_reload_property (MetaGroup *group, Atom property); void meta_group_reload_properties (MetaGroup *group, const Atom *properties, int n_properties); void meta_display_init_group_prop_hooks (MetaDisplay *display); void meta_display_free_group_prop_hooks (MetaDisplay *display); #endif /* META_GROUP_PROPS_H */ ������������������������������������������������������������������������muffin-5.2.1/src/core/async-getprop.h���������������������������������������������������������������0000664�0001750�0001750�00000005553�14211404421�017627� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Asynchronous X property getting hack */ /* * Copyright (C) 2002 Havoc Pennington * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation. * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of The Open Group shall not be * used in advertising or otherwise to promote the sale, use or other dealings * in this Software without prior written authorization from The Open Group. */ #ifndef ASYNC_GETPROP_H #define ASYNC_GETPROP_H #include <X11/Xlib.h> #include <X11/Xutil.h> typedef struct _AgGetPropertyTask AgGetPropertyTask; AgGetPropertyTask* ag_task_create (Display *display, Window window, Atom property, long offset, long length, Bool delete, Atom req_type); Status ag_task_get_reply_and_free (AgGetPropertyTask *task, Atom *actual_type, int *actual_format, unsigned long *nitems, unsigned long *bytesafter, unsigned char **prop); Bool ag_task_have_reply (AgGetPropertyTask *task); Atom ag_task_get_property (AgGetPropertyTask *task); Window ag_task_get_window (AgGetPropertyTask *task); Display* ag_task_get_display (AgGetPropertyTask *task); AgGetPropertyTask* ag_get_next_completed_task (Display *display); /* so other headers don't have to include internal Xlib goo */ void* ag_Xmalloc (unsigned long bytes); void* ag_Xmalloc0 (unsigned long bytes); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/testboxes.c�������������������������������������������������������������������0000664�0001750�0001750�00000141362�14211404421�017046� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin box operation testing program */ /* * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "boxes-private.h" #include <glib.h> #include <stdlib.h> #include <stdio.h> #include <X11/Xutil.h> /* Just for the definition of the various gravities */ #include <time.h> /* To initialize random seed */ #define NUM_RANDOM_RUNS 10000 static void init_random_ness () { srand(time(NULL)); } static void get_random_rect (MetaRectangle *rect) { rect->x = rand () % 1600; rect->y = rand () % 1200; rect->width = rand () % 1600 + 1; rect->height = rand () % 1200 + 1; } static MetaRectangle* new_meta_rect (int x, int y, int width, int height) { MetaRectangle* temporary; temporary = g_new (MetaRectangle, 1); temporary->x = x; temporary->y = y; temporary->width = width; temporary->height = height; return temporary; } static MetaStrut* new_meta_strut (int x, int y, int width, int height, int side) { MetaStrut* temporary; temporary = g_new (MetaStrut, 1); temporary->rect = meta_rect(x, y, width, height); temporary->side = side; return temporary; } static MetaEdge* new_screen_edge (int x, int y, int width, int height, int side_type) { MetaEdge* temporary; temporary = g_new (MetaEdge, 1); temporary->rect.x = x; temporary->rect.y = y; temporary->rect.width = width; temporary->rect.height = height; temporary->side_type = side_type; temporary->edge_type = META_EDGE_SCREEN; return temporary; } static MetaEdge* new_monitor_edge (int x, int y, int width, int height, int side_type) { MetaEdge* temporary; temporary = g_new (MetaEdge, 1); temporary->rect.x = x; temporary->rect.y = y; temporary->rect.width = width; temporary->rect.height = height; temporary->side_type = side_type; temporary->edge_type = META_EDGE_MONITOR; return temporary; } static void test_area () { MetaRectangle temp; int i; for (i = 0; i < NUM_RANDOM_RUNS; i++) { get_random_rect (&temp); g_assert (meta_rectangle_area (&temp) == temp.width * temp.height); } temp = meta_rect (0, 0, 5, 7); g_assert (meta_rectangle_area (&temp) == 35); printf ("%s passed.\n", G_STRFUNC); } static void test_intersect () { MetaRectangle a = {100, 200, 50, 40}; MetaRectangle b = { 0, 50, 110, 152}; MetaRectangle c = { 0, 0, 10, 10}; MetaRectangle d = {100, 100, 50, 50}; MetaRectangle b_intersect_d = {100, 100, 10, 50}; MetaRectangle temp; MetaRectangle temp2; meta_rectangle_intersect (&a, &b, &temp); temp2 = meta_rect (100, 200, 10, 2); g_assert (meta_rectangle_equal (&temp, &temp2)); g_assert (meta_rectangle_area (&temp) == 20); meta_rectangle_intersect (&a, &c, &temp); g_assert (meta_rectangle_area (&temp) == 0); meta_rectangle_intersect (&a, &d, &temp); g_assert (meta_rectangle_area (&temp) == 0); meta_rectangle_intersect (&b, &d, &b); g_assert (meta_rectangle_equal (&b, &b_intersect_d)); printf ("%s passed.\n", G_STRFUNC); } static void test_equal () { MetaRectangle a = {10, 12, 4, 18}; MetaRectangle b = a; MetaRectangle c = {10, 12, 4, 19}; MetaRectangle d = {10, 12, 7, 18}; MetaRectangle e = {10, 62, 4, 18}; MetaRectangle f = {27, 12, 4, 18}; g_assert ( meta_rectangle_equal (&a, &b)); g_assert (!meta_rectangle_equal (&a, &c)); g_assert (!meta_rectangle_equal (&a, &d)); g_assert (!meta_rectangle_equal (&a, &e)); g_assert (!meta_rectangle_equal (&a, &f)); printf ("%s passed.\n", G_STRFUNC); } static void test_overlap_funcs () { MetaRectangle temp1, temp2; int i; for (i = 0; i < NUM_RANDOM_RUNS; i++) { get_random_rect (&temp1); get_random_rect (&temp2); g_assert (meta_rectangle_overlap (&temp1, &temp2) == (meta_rectangle_horiz_overlap (&temp1, &temp2) && meta_rectangle_vert_overlap (&temp1, &temp2))); } temp1 = meta_rect ( 0, 0, 10, 10); temp2 = meta_rect (20, 0, 10, 5); g_assert (!meta_rectangle_overlap (&temp1, &temp2)); g_assert (!meta_rectangle_horiz_overlap (&temp1, &temp2)); g_assert ( meta_rectangle_vert_overlap (&temp1, &temp2)); printf ("%s passed.\n", G_STRFUNC); } static void test_basic_fitting () { MetaRectangle temp1, temp2, temp3; int i; /* Four cases: * case temp1 fits temp2 temp1 could fit temp2 * 1 Y Y * 2 N Y * 3 Y N * 4 N N * Of the four cases, case 3 is impossible. An alternate way of looking * at this table is that either the middle column must be no, or the last * column must be yes. So we test that. Also, we can repeat the test * reversing temp1 and temp2. */ for (i = 0; i < NUM_RANDOM_RUNS; i++) { get_random_rect (&temp1); get_random_rect (&temp2); g_assert (meta_rectangle_contains_rect (&temp1, &temp2) == FALSE || meta_rectangle_could_fit_rect (&temp1, &temp2) == TRUE); g_assert (meta_rectangle_contains_rect (&temp2, &temp1) == FALSE || meta_rectangle_could_fit_rect (&temp2, &temp1) == TRUE); } temp1 = meta_rect ( 0, 0, 10, 10); temp2 = meta_rect ( 5, 5, 5, 5); temp3 = meta_rect ( 8, 2, 3, 7); g_assert ( meta_rectangle_contains_rect (&temp1, &temp2)); g_assert (!meta_rectangle_contains_rect (&temp2, &temp1)); g_assert (!meta_rectangle_contains_rect (&temp1, &temp3)); g_assert ( meta_rectangle_could_fit_rect (&temp1, &temp3)); g_assert (!meta_rectangle_could_fit_rect (&temp3, &temp2)); printf ("%s passed.\n", G_STRFUNC); } static void free_strut_list (GSList *struts) { GSList *tmp = struts; while (tmp) { free (tmp->data); tmp = tmp->next; } g_slist_free (struts); } static GSList* get_strut_list (int which) { GSList *ans; MetaSide wc = 0; /* wc == who cares? ;-) */ ans = NULL; g_assert (which >=0 && which <= 6); switch (which) { case 0: break; case 1: ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP)); ans = g_slist_prepend (ans, new_meta_strut ( 400, 1160, 1600, 40, META_SIDE_BOTTOM)); break; case 2: ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP)); ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100, 400, 100, META_SIDE_BOTTOM)); ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150, 150, 50, META_SIDE_BOTTOM)); break; case 3: ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP)); ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100, 400, 100, META_SIDE_LEFT)); ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150, 80, 50, META_SIDE_BOTTOM)); ans = g_slist_prepend (ans, new_meta_strut ( 700, 525, 200, 150, wc)); break; case 4: ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 800, 1200, META_SIDE_LEFT)); ans = g_slist_prepend (ans, new_meta_strut ( 800, 0, 1600, 20, META_SIDE_TOP)); break; case 5: ans = g_slist_prepend (ans, new_meta_strut ( 800, 0, 1600, 20, META_SIDE_TOP)); ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 800, 1200, META_SIDE_LEFT)); ans = g_slist_prepend (ans, new_meta_strut ( 800, 10, 800, 1200, META_SIDE_RIGHT)); break; case 6: ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 40, META_SIDE_TOP)); ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP)); break; } return ans; } static GList* get_screen_region (int which) { GList *ret; GSList *struts; MetaRectangle basic_rect; basic_rect = meta_rect (0, 0, 1600, 1200); ret = NULL; struts = get_strut_list (which); ret = meta_rectangle_get_minimal_spanning_set_for_region (&basic_rect, struts); free_strut_list (struts); return ret; } static GList* get_screen_edges (int which) { GList *ret; GSList *struts; MetaRectangle basic_rect; basic_rect = meta_rect (0, 0, 1600, 1200); ret = NULL; struts = get_strut_list (which); ret = meta_rectangle_find_onscreen_edges (&basic_rect, struts); free_strut_list (struts); return ret; } static GList* get_monitor_edges (int which_monitor_set, int which_strut_set) { GList *ret; GSList *struts; GList *xins; xins = NULL; g_assert (which_monitor_set >=0 && which_monitor_set <= 3); switch (which_monitor_set) { case 0: xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 1600, 1200)); break; case 1: xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 800, 1200)); xins = g_list_prepend (xins, new_meta_rect (800, 0, 800, 1200)); break; case 2: xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 1600, 600)); xins = g_list_prepend (xins, new_meta_rect ( 0, 600, 1600, 600)); break; case 3: xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 1600, 600)); xins = g_list_prepend (xins, new_meta_rect ( 0, 600, 800, 600)); xins = g_list_prepend (xins, new_meta_rect (800, 600, 800, 600)); break; } ret = NULL; struts = get_strut_list (which_strut_set); ret = meta_rectangle_find_nonintersected_monitor_edges (xins, struts); free_strut_list (struts); meta_rectangle_free_list_and_elements (xins); return ret; } #if 0 static void test_merge_regions () { /* logarithmically distributed random number of struts (range?) * logarithmically distributed random size of struts (up to screen size???) * uniformly distributed location of center of struts (within screen) * merge all regions that are possible * print stats on problem setup * number of (non-completely-occluded?) struts * percentage of screen covered * length of resulting non-minimal spanning set * length of resulting minimal spanning set * print stats on merged regions: * number boxes merged * number of those merges that were of the form A contains B * number of those merges that were of the form A partially contains B * number of those merges that were of the form A is adjacent to B */ GList* region; GList* compare; int num_contains, num_merged, num_part_contains, num_adjacent; num_contains = num_merged = num_part_contains = num_adjacent = 0; compare = region = get_screen_region (2); g_assert (region); printf ("Merging stats:\n"); printf (" Length of initial list: %d\n", g_list_length (region)); #ifdef PRINT_DEBUG char rect1[RECT_LENGTH], rect2[RECT_LENGTH]; char region_list[(RECT_LENGTH + 2) * g_list_length (region)]; meta_rectangle_region_to_string (region, ", ", region_list); printf (" Initial rectangles: %s\n", region_list); #endif while (compare && compare->next) { MetaRectangle *a = compare->data; GList *other = compare->next; g_assert (a->width > 0 && a->height > 0); while (other) { MetaRectangle *b = other->data; GList *delete_me = NULL; g_assert (b->width > 0 && b->height > 0); #ifdef PRINT_DEBUG printf (" -- Comparing %s to %s --\n", meta_rectangle_to_string (a, rect1), meta_rectangle_to_string (b, rect2)); #endif /* If a contains b, just remove b */ if (meta_rectangle_contains_rect (a, b)) { delete_me = other; num_contains++; num_merged++; } /* If b contains a, just remove a */ else if (meta_rectangle_contains_rect (a, b)) { delete_me = compare; num_contains++; num_merged++; } /* If a and b might be mergeable horizontally */ else if (a->y == b->y && a->height == b->height) { /* If a and b overlap */ if (meta_rectangle_overlap (a, b)) { int new_x = MIN (a->x, b->x); a->width = MAX (a->x + a->width, b->x + b->width) - new_x; a->x = new_x; delete_me = other; num_part_contains++; num_merged++; } /* If a and b are adjacent */ else if (a->x + a->width == b->x || a->x == b->x + b->width) { int new_x = MIN (a->x, b->x); a->width = MAX (a->x + a->width, b->x + b->width) - new_x; a->x = new_x; delete_me = other; num_adjacent++; num_merged++; } } /* If a and b might be mergeable vertically */ else if (a->x == b->x && a->width == b->width) { /* If a and b overlap */ if (meta_rectangle_overlap (a, b)) { int new_y = MIN (a->y, b->y); a->height = MAX (a->y + a->height, b->y + b->height) - new_y; a->y = new_y; delete_me = other; num_part_contains++; num_merged++; } /* If a and b are adjacent */ else if (a->y + a->height == b->y || a->y == b->y + b->height) { int new_y = MIN (a->y, b->y); a->height = MAX (a->y + a->height, b->y + b->height) - new_y; a->y = new_y; delete_me = other; num_adjacent++; num_merged++; } } other = other->next; /* Delete any rectangle in the list that is no longer wanted */ if (delete_me != NULL) { #ifdef PRINT_DEBUG MetaRectangle *bla = delete_me->data; printf (" Deleting rect %s\n", meta_rectangle_to_string (bla, rect1)); #endif /* Deleting the rect we're compare others to is a little tricker */ if (compare == delete_me) { compare = compare->next; other = compare->next; a = compare->data; } /* Okay, we can free it now */ free (delete_me->data); region = g_list_delete_link (region, delete_me); } #ifdef PRINT_DEBUG char region_list[(RECT_LENGTH + 2) * g_list_length (region)]; meta_rectangle_region_to_string (region, ", ", region_list); printf (" After comparison, new list is: %s\n", region_list); #endif } compare = compare->next; } printf (" Num rectangles contained in others : %d\n", num_contains); printf (" Num rectangles partially contained in others: %d\n", num_part_contains); printf (" Num rectangles adjacent to others : %d\n", num_adjacent); printf (" Num rectangles merged with others : %d\n", num_merged); #ifdef PRINT_DEBUG char region_list2[(RECT_LENGTH + 2) * g_list_length (region)]; meta_rectangle_region_to_string (region, ", ", region_list2); printf (" Final rectangles: %s\n", region_list2); #endif meta_rectangle_free_spanning_set (region); region = NULL; printf ("%s passed.\n", G_STRFUNC); } #endif static void verify_lists_are_equal (GList *code, GList *answer) { int which = 0; while (code && answer) { MetaRectangle *a = code->data; MetaRectangle *b = answer->data; if (a->x != b->x || a->y != b->y || a->width != b->width || a->height != b->height) { g_error ("%dth item in code answer answer lists do not match; " "code rect: %d,%d + %d,%d; answer rect: %d,%d + %d,%d\n", which, a->x, a->y, a->width, a->height, b->x, b->y, b->width, b->height); } code = code->next; answer = answer->next; which++; } /* Ought to be at the end of both lists; check if we aren't */ if (code) { MetaRectangle *tmp = code->data; g_error ("code list longer than answer list by %d items; " "first extra item: %d,%d +%d,%d\n", g_list_length (code), tmp->x, tmp->y, tmp->width, tmp->height); } if (answer) { MetaRectangle *tmp = answer->data; g_error ("answer list longer than code list by %d items; " "first extra item: %d,%d +%d,%d\n", g_list_length (answer), tmp->x, tmp->y, tmp->width, tmp->height); } } static void test_regions_okay () { GList* region; GList* tmp; /*************************************************************/ /* Make sure test region 0 has the right spanning rectangles */ /*************************************************************/ region = get_screen_region (0); tmp = NULL; tmp = g_list_prepend (tmp, new_meta_rect (0, 0, 1600, 1200)); verify_lists_are_equal (region, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (region); /*************************************************************/ /* Make sure test region 1 has the right spanning rectangles */ /*************************************************************/ region = get_screen_region (1); tmp = NULL; tmp = g_list_prepend (tmp, new_meta_rect (0, 20, 400, 1180)); tmp = g_list_prepend (tmp, new_meta_rect (0, 20, 1600, 1140)); verify_lists_are_equal (region, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (region); /*************************************************************/ /* Make sure test region 2 has the right spanning rectangles */ /*************************************************************/ region = get_screen_region (2); tmp = NULL; tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 300, 1180)); tmp = g_list_prepend (tmp, new_meta_rect ( 450, 20, 350, 1180)); tmp = g_list_prepend (tmp, new_meta_rect (1200, 20, 400, 1180)); tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 800, 1130)); tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 1600, 1080)); verify_lists_are_equal (region, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (region); /*************************************************************/ /* Make sure test region 3 has the right spanning rectangles */ /*************************************************************/ region = get_screen_region (3); tmp = NULL; tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 300, 1180)); /* 354000 */ tmp = g_list_prepend (tmp, new_meta_rect ( 380, 20, 1220, 1180)); /* 377600 */ tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 1600, 1130)); /* 791000 */ #if 0 printf ("Got to here...\n"); char region_list[(RECT_LENGTH+2) * g_list_length (region)]; char tmp_list[ (RECT_LENGTH+2) * g_list_length (tmp)]; meta_rectangle_region_to_string (region, ", ", region_list); meta_rectangle_region_to_string (region, ", ", tmp_list); printf ("%s vs. %s\n", region_list, tmp_list); #endif verify_lists_are_equal (region, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (region); /*************************************************************/ /* Make sure test region 4 has the right spanning rectangles */ /*************************************************************/ region = get_screen_region (4); tmp = NULL; tmp = g_list_prepend (tmp, new_meta_rect ( 800, 20, 800, 1180)); verify_lists_are_equal (region, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (region); /*************************************************************/ /* Make sure test region 5 has the right spanning rectangles */ /*************************************************************/ printf ("The next test intentionally causes a warning, " "but it can be ignored.\n"); region = get_screen_region (5); verify_lists_are_equal (region, NULL); /* FIXME: Still to do: * - Create random struts and check the regions somehow */ printf ("%s passed.\n", G_STRFUNC); } static void test_region_fitting () { GList* region; MetaRectangle rect; /* See test_basic_fitting() for how/why these automated random tests work */ int i; region = get_screen_region (3); for (i = 0; i < NUM_RANDOM_RUNS; i++) { get_random_rect (&rect); g_assert (meta_rectangle_contained_in_region (region, &rect) == FALSE || meta_rectangle_could_fit_in_region (region, &rect) == TRUE); } meta_rectangle_free_list_and_elements (region); /* Do some manual tests too */ region = get_screen_region (1); rect = meta_rect (50, 50, 400, 400); g_assert (meta_rectangle_could_fit_in_region (region, &rect)); g_assert (meta_rectangle_contained_in_region (region, &rect)); rect = meta_rect (250, 0, 500, 1150); g_assert (!meta_rectangle_could_fit_in_region (region, &rect)); g_assert (!meta_rectangle_contained_in_region (region, &rect)); rect = meta_rect (250, 0, 400, 400); g_assert (meta_rectangle_could_fit_in_region (region, &rect)); g_assert (!meta_rectangle_contained_in_region (region, &rect)); meta_rectangle_free_list_and_elements (region); region = get_screen_region (2); rect = meta_rect (1000, 50, 600, 1100); g_assert (meta_rectangle_could_fit_in_region (region, &rect)); g_assert (!meta_rectangle_contained_in_region (region, &rect)); meta_rectangle_free_list_and_elements (region); printf ("%s passed.\n", G_STRFUNC); } static void test_clamping_to_region () { GList* region; MetaRectangle rect; MetaRectangle min_size; FixedDirections fixed_directions; int i; min_size.height = min_size.width = 1; fixed_directions = 0; region = get_screen_region (3); for (i = 0; i < NUM_RANDOM_RUNS; i++) { MetaRectangle temp; get_random_rect (&rect); temp = rect; meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (meta_rectangle_could_fit_in_region (region, &rect) == TRUE); g_assert (rect.x == temp.x && rect.y == temp.y); } meta_rectangle_free_list_and_elements (region); /* Do some manual tests too */ region = get_screen_region (1); rect = meta_rect (50, 50, 10000, 10000); meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (rect.width == 1600 && rect.height == 1140); rect = meta_rect (275, -50, 410, 10000); meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (rect.width == 400 && rect.height == 1180); rect = meta_rect (50, 50, 10000, 10000); min_size.height = 1170; meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (rect.width == 400 && rect.height == 1180); printf ("The next test intentionally causes a warning, " "but it can be ignored.\n"); rect = meta_rect (50, 50, 10000, 10000); min_size.width = 600; min_size.height = 1170; meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (rect.width == 600 && rect.height == 1170); rect = meta_rect (350, 50, 100, 1100); min_size.width = 1; min_size.height = 1; fixed_directions = FIXED_DIRECTION_X; meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (rect.width == 100 && rect.height == 1100); rect = meta_rect (300, 70, 500, 1100); min_size.width = 1; min_size.height = 1; fixed_directions = FIXED_DIRECTION_Y; meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (rect.width == 400 && rect.height == 1100); printf ("The next test intentionally causes a warning, " "but it can be ignored.\n"); rect = meta_rect (300, 70, 999999, 999999); min_size.width = 100; min_size.height = 200; fixed_directions = FIXED_DIRECTION_Y; meta_rectangle_clamp_to_fit_into_region (region, fixed_directions, &rect, &min_size); g_assert (rect.width == 100 && rect.height == 999999); meta_rectangle_free_list_and_elements (region); printf ("%s passed.\n", G_STRFUNC); } static gboolean rect_overlaps_region (const GList *spanning_rects, const MetaRectangle *rect) { /* FIXME: Should I move this to boxes.[ch]? */ const GList *temp; gboolean overlaps; temp = spanning_rects; overlaps = FALSE; while (!overlaps && temp != NULL) { overlaps = overlaps || meta_rectangle_overlap (temp->data, rect); temp = temp->next; } return overlaps; } gboolean time_to_print = FALSE; static void test_clipping_to_region () { GList* region; MetaRectangle rect, temp; FixedDirections fixed_directions = 0; int i; region = get_screen_region (3); for (i = 0; i < NUM_RANDOM_RUNS; i++) { get_random_rect (&rect); if (rect_overlaps_region (region, &rect)) { meta_rectangle_clip_to_region (region, 0, &rect); g_assert (meta_rectangle_contained_in_region (region, &rect) == TRUE); } } meta_rectangle_free_list_and_elements (region); /* Do some manual tests too */ region = get_screen_region (2); rect = meta_rect (-50, -10, 10000, 10000); meta_rectangle_clip_to_region (region, fixed_directions, &rect); g_assert (meta_rectangle_equal (region->data, &rect)); rect = meta_rect (300, 1000, 400, 200); temp = meta_rect (300, 1000, 400, 150); meta_rectangle_clip_to_region (region, fixed_directions, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (400, 1000, 300, 200); temp = meta_rect (450, 1000, 250, 200); meta_rectangle_clip_to_region (region, fixed_directions, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (400, 1000, 300, 200); temp = meta_rect (400, 1000, 300, 150); meta_rectangle_clip_to_region (region, FIXED_DIRECTION_X, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (400, 1000, 300, 200); temp = meta_rect (400, 1000, 300, 150); meta_rectangle_clip_to_region (region, FIXED_DIRECTION_X, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); meta_rectangle_free_list_and_elements (region); printf ("%s passed.\n", G_STRFUNC); } static void test_shoving_into_region () { GList* region; MetaRectangle rect, temp; FixedDirections fixed_directions = 0; int i; region = get_screen_region (3); for (i = 0; i < NUM_RANDOM_RUNS; i++) { get_random_rect (&rect); if (meta_rectangle_could_fit_in_region (region, &rect)) { meta_rectangle_shove_into_region (region, 0, &rect); g_assert (meta_rectangle_contained_in_region (region, &rect)); } } meta_rectangle_free_list_and_elements (region); /* Do some manual tests too */ region = get_screen_region (2); rect = meta_rect (300, 1000, 400, 200); temp = meta_rect (300, 950, 400, 200); meta_rectangle_shove_into_region (region, fixed_directions, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (425, 1000, 300, 200); temp = meta_rect (450, 1000, 300, 200); meta_rectangle_shove_into_region (region, fixed_directions, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (425, 1000, 300, 200); temp = meta_rect (425, 950, 300, 200); meta_rectangle_shove_into_region (region, FIXED_DIRECTION_X, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 300, 1000, 400, 200); temp = meta_rect (1200, 1000, 400, 200); meta_rectangle_shove_into_region (region, FIXED_DIRECTION_Y, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 800, 1150, 400, 50); /* Completely "offscreen" :) */ temp = meta_rect ( 800, 1050, 400, 50); meta_rectangle_shove_into_region (region, 0, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (-1000, 0, 400, 150); /* Offscreen in 2 directions */ temp = meta_rect ( 0, 20, 400, 150); meta_rectangle_shove_into_region (region, 0, &rect); g_assert (meta_rectangle_equal (&rect, &temp)); meta_rectangle_free_list_and_elements (region); printf ("%s passed.\n", G_STRFUNC); } static void verify_edge_lists_are_equal (GList *code, GList *answer) { int which = 0; while (code && answer) { MetaEdge *a = code->data; MetaEdge *b = answer->data; if (!meta_rectangle_equal (&a->rect, &b->rect) || a->side_type != b->side_type || a->edge_type != b->edge_type) { g_error ("%dth item in code answer answer lists do not match; " "code rect: %d,%d + %d,%d; answer rect: %d,%d + %d,%d\n", which, a->rect.x, a->rect.y, a->rect.width, a->rect.height, b->rect.x, b->rect.y, b->rect.width, b->rect.height); } code = code->next; answer = answer->next; which++; } /* Ought to be at the end of both lists; check if we aren't */ if (code) { MetaEdge *tmp = code->data; g_error ("code list longer than answer list by %d items; " "first extra item rect: %d,%d +%d,%d\n", g_list_length (code), tmp->rect.x, tmp->rect.y, tmp->rect.width, tmp->rect.height); } if (answer) { MetaEdge *tmp = answer->data; g_error ("answer list longer than code list by %d items; " "first extra item rect: %d,%d +%d,%d\n", g_list_length (answer), tmp->rect.x, tmp->rect.y, tmp->rect.width, tmp->rect.height); } } static void test_find_onscreen_edges () { GList* edges; GList* tmp; int left = META_DIRECTION_LEFT; int right = META_DIRECTION_RIGHT; int top = META_DIRECTION_TOP; int bottom = META_DIRECTION_BOTTOM; /*************************************************/ /* Make sure test region 0 has the correct edges */ /*************************************************/ edges = get_screen_edges (0); tmp = NULL; tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 1600, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 0, 1600, 0, top)); tmp = g_list_prepend (tmp, new_screen_edge (1600, 0, 0, 1200, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 0, 0, 1200, left)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************/ /* Make sure test region 1 has the correct edges */ /*************************************************/ edges = get_screen_edges (1); tmp = NULL; tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 400, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 400, 1160, 1200, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 1600, 0, top)); tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1140, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 400, 1160, 0, 40, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 0, 1180, left)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************/ /* Make sure test region 2 has the correct edges */ /*************************************************/ edges = get_screen_edges (2); tmp = NULL; tmp = g_list_prepend (tmp, new_screen_edge (1200, 1200, 400, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 450, 1200, 350, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 300, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 150, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 400, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 1600, 0, top)); tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1180, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 0, 100, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 0, 50, right)); tmp = g_list_prepend (tmp, new_screen_edge (1200, 1100, 0, 100, left)); tmp = g_list_prepend (tmp, new_screen_edge ( 450, 1150, 0, 50, left)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 0, 1180, left)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************/ /* Make sure test region 3 has the correct edges */ /*************************************************/ edges = get_screen_edges (3); tmp = NULL; tmp = g_list_prepend (tmp, new_screen_edge (1200, 1200, 400, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 380, 1200, 420, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 300, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 80, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 400, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 700, 525, 200, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 700, 675, 200, 0, top)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 1600, 0, top)); tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1180, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 0, 100, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 700, 525, 0, 150, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 0, 50, right)); tmp = g_list_prepend (tmp, new_screen_edge (1200, 1100, 0, 100, left)); tmp = g_list_prepend (tmp, new_screen_edge ( 900, 525, 0, 150, left)); tmp = g_list_prepend (tmp, new_screen_edge ( 380, 1150, 0, 50, left)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 0, 1180, left)); #if 0 #define FUDGE 50 /* number of edges */ char big_buffer1[(EDGE_LENGTH+2)*FUDGE], big_buffer2[(EDGE_LENGTH+2)*FUDGE]; meta_rectangle_edge_list_to_string (edges, "\n ", big_buffer1); meta_rectangle_edge_list_to_string (tmp, "\n ", big_buffer2); printf("Generated edge list:\n %s\nComparison edges list:\n %s\n", big_buffer1, big_buffer2); #endif verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************/ /* Make sure test region 4 has the correct edges */ /*************************************************/ edges = get_screen_edges (4); tmp = NULL; tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1200, 800, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 800, 20, 800, 0, top)); tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1180, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 800, 20, 0, 1180, left)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************/ /* Make sure test region 5 has the correct edges */ /*************************************************/ edges = get_screen_edges (5); tmp = NULL; verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************/ /* Make sure test region 6 has the correct edges */ /*************************************************/ edges = get_screen_edges (6); tmp = NULL; tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 1600, 0, bottom)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 40, 1600, 0, top)); tmp = g_list_prepend (tmp, new_screen_edge (1600, 40, 0, 1160, right)); tmp = g_list_prepend (tmp, new_screen_edge ( 0, 40, 0, 1160, left)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); printf ("%s passed.\n", G_STRFUNC); } static void test_find_nonintersected_monitor_edges () { GList* edges; GList* tmp; int left = META_DIRECTION_LEFT; int right = META_DIRECTION_RIGHT; int top = META_DIRECTION_TOP; int bottom = META_DIRECTION_BOTTOM; /*************************************************************************/ /* Make sure test monitor set 0 for with region 0 has the correct edges */ /*************************************************************************/ edges = get_monitor_edges (0, 0); tmp = NULL; verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************************************/ /* Make sure test monitor set 2 for with region 1 has the correct edges */ /*************************************************************************/ edges = get_monitor_edges (2, 1); tmp = NULL; tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 1600, 0, bottom)); tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 1600, 0, top)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************************************/ /* Make sure test monitor set 1 for with region 2 has the correct edges */ /*************************************************************************/ edges = get_monitor_edges (1, 2); tmp = NULL; tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 20, 0, 1080, right)); tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 20, 0, 1180, left)); #if 0 #define FUDGE 50 char big_buffer1[(EDGE_LENGTH+2)*FUDGE], big_buffer2[(EDGE_LENGTH+2)*FUDGE]; meta_rectangle_edge_list_to_string (edges, "\n ", big_buffer1); meta_rectangle_edge_list_to_string (tmp, "\n ", big_buffer2); printf("Generated edge list:\n %s\nComparison edges list:\n %s\n", big_buffer1, big_buffer2); #endif verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************************************/ /* Make sure test monitor set 3 for with region 3 has the correct edges */ /*************************************************************************/ edges = get_monitor_edges (3, 3); tmp = NULL; tmp = g_list_prepend (tmp, new_monitor_edge ( 900, 600, 700, 0, bottom)); tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 700, 0, bottom)); tmp = g_list_prepend (tmp, new_monitor_edge ( 900, 600, 700, 0, top)); tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 700, 0, top)); tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 675, 0, 425, right)); tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 675, 0, 525, left)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************************************/ /* Make sure test monitor set 3 for with region 4 has the correct edges */ /*************************************************************************/ edges = get_monitor_edges (3, 4); tmp = NULL; tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 800, 0, bottom)); tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 800, 0, top)); tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 0, 600, right)); verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); /*************************************************************************/ /* Make sure test monitor set 3 for with region 5has the correct edges */ /*************************************************************************/ edges = get_monitor_edges (3, 5); tmp = NULL; verify_edge_lists_are_equal (edges, tmp); meta_rectangle_free_list_and_elements (tmp); meta_rectangle_free_list_and_elements (edges); printf ("%s passed.\n", G_STRFUNC); } static void test_gravity_resize () { MetaRectangle oldrect, rect, temp; rect.x = -500; /* Some random amount not equal to oldrect.x to ensure that * the resize is done with respect to oldrect instead of rect */ oldrect = meta_rect ( 50, 300, 250, 400); temp = meta_rect ( 50, 300, 20, 5); meta_rectangle_resize_with_gravity (&oldrect, &rect, NorthWestGravity, 20, 5); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 50, 300, 250, 400); temp = meta_rect (165, 300, 20, 5); meta_rectangle_resize_with_gravity (&rect, &rect, NorthGravity, 20, 5); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 50, 300, 250, 400); temp = meta_rect (280, 300, 20, 5); meta_rectangle_resize_with_gravity (&rect, &rect, NorthEastGravity, 20, 5); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 50, 300, 250, 400); temp = meta_rect ( 50, 695, 50, 5); meta_rectangle_resize_with_gravity (&rect, &rect, SouthWestGravity, 50, 5); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 50, 300, 250, 400); temp = meta_rect (150, 695, 50, 5); meta_rectangle_resize_with_gravity (&rect, &rect, SouthGravity, 50, 5); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 50, 300, 250, 400); temp = meta_rect (250, 695, 50, 5); meta_rectangle_resize_with_gravity (&rect, &rect, SouthEastGravity, 50, 5); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (167, 738, 237, 843); temp = meta_rect (167, 1113, 832, 93); meta_rectangle_resize_with_gravity (&rect, &rect, WestGravity, 832, 93); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect ( 167, 738, 237, 843); temp = meta_rect (-131, 1113, 833, 93); meta_rectangle_resize_with_gravity (&rect, &rect, CenterGravity, 832, 93); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (300, 1000, 400, 200); temp = meta_rect (270, 994, 430, 212); meta_rectangle_resize_with_gravity (&rect, &rect, EastGravity, 430, 211); g_assert (meta_rectangle_equal (&rect, &temp)); rect = meta_rect (300, 1000, 400, 200); temp = meta_rect (300, 1000, 430, 211); meta_rectangle_resize_with_gravity (&rect, &rect, StaticGravity, 430, 211); g_assert (meta_rectangle_equal (&rect, &temp)); printf ("%s passed.\n", G_STRFUNC); } static void test_find_closest_point_to_line () { double x1, y1, x2, y2, px, py, rx, ry; double answer_x, answer_y; x1 = 3.0; y1 = 49.0; x2 = 2.0; y2 = - 1.0; px = -2.6; py = 19.1; answer_x = 2.4; answer_y = 19; meta_rectangle_find_linepoint_closest_to_point (x1, y1, x2, y2, px, py, &rx, &ry); g_assert (rx == answer_x && ry == answer_y); /* Special test for x1 == x2, so that slop of line is infinite */ x1 = 3.0; y1 = 49.0; x2 = 3.0; y2 = - 1.0; px = -2.6; py = 19.1; answer_x = 3.0; answer_y = 19.1; meta_rectangle_find_linepoint_closest_to_point (x1, y1, x2, y2, px, py, &rx, &ry); g_assert (rx == answer_x && ry == answer_y); /* Special test for y1 == y2, so perp line has slope of infinity */ x1 = 3.14; y1 = 7.0; x2 = 2.718; y2 = 7.0; px = -2.6; py = 19.1; answer_x = -2.6; answer_y = 7; meta_rectangle_find_linepoint_closest_to_point (x1, y1, x2, y2, px, py, &rx, &ry); g_assert (rx == answer_x && ry == answer_y); /* Test when we the point we want to be closest to is actually on the line */ x1 = 3.0; y1 = 49.0; x2 = 2.0; y2 = - 1.0; px = 2.4; py = 19.0; answer_x = 2.4; answer_y = 19; meta_rectangle_find_linepoint_closest_to_point (x1, y1, x2, y2, px, py, &rx, &ry); g_assert (rx == answer_x && ry == answer_y); printf ("%s passed.\n", G_STRFUNC); } int main() { init_random_ness (); test_area (); test_intersect (); test_equal (); test_overlap_funcs (); test_basic_fitting (); test_regions_okay (); test_region_fitting (); test_clamping_to_region (); test_clipping_to_region (); test_shoving_into_region (); /* And now the functions dealing with edges more than boxes */ test_find_onscreen_edges (); test_find_nonintersected_monitor_edges (); /* And now the misfit functions that don't quite fit in anywhere else... */ test_gravity_resize (); test_find_closest_point_to_line (); printf ("All tests passed.\n"); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/restart-helper.c��������������������������������������������������������������0000664�0001750�0001750�00000004546�14211404421�017771� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * SECTION:restart-helper * @short_description: helper program during a restart * * To smoothly restart Muffin, we want to keep the composite * overlay window enabled during the restart. This is done by * spawning this program, which keeps a reference to the the composite * overlay window until Muffin picks it back up. */ /* * Copyright (C) 2014 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <stdlib.h> #include <stdio.h> #include <X11/Xlib.h> #include <X11/extensions/Xcomposite.h> int main (int argc, char **argv) { Display *display = XOpenDisplay (NULL); Window selection_window; XSetWindowAttributes xwa; unsigned long mask = 0; xwa.override_redirect = True; mask |= CWOverrideRedirect; XCompositeGetOverlayWindow (display, DefaultRootWindow (display)); selection_window = XCreateWindow (display, DefaultRootWindow (display), -100, -100, 1, 1, 0, 0, InputOnly, DefaultVisual (display, DefaultScreen (display)), mask, &xwa); XSetSelectionOwner (display, XInternAtom (display, "_MUFFIN_RESTART_HELPER", False), selection_window, CurrentTime); /* Muffin looks for an (arbitrary) line printed to stdout to know that * we have started and have a reference to the COW. XSync() so that * everything is set on the X server before Muffin starts restarting. */ XSync (display, False); printf ("STARTED\n"); fflush (stdout); while (True) { XEvent xev; XNextEvent (display, &xev); /* Muffin restarted and unset the selection to indicate that * it has a reference on the COW again */ if (xev.xany.type == SelectionClear) return 0; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/iconcache.h�������������������������������������������������������������������0000664�0001750�0001750�00000004704�14211404421�016745� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window icons */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_ICON_CACHE_H #define META_ICON_CACHE_H #include "screen-private.h" typedef struct _MetaIconCache MetaIconCache; typedef enum { /* These MUST be in ascending order of preference; * i.e. if we get _NET_WM_ICON and already have * WM_HINTS, we prefer _NET_WM_ICON */ USING_NO_ICON, USING_FALLBACK_ICON, USING_KWM_WIN_ICON, USING_WM_HINTS, USING_NET_WM_ICON } IconOrigin; struct _MetaIconCache { int origin; Pixmap prev_pixmap; Pixmap prev_mask; guint want_fallback : 1; /* TRUE if these props have changed */ guint wm_hints_dirty : 1; guint kwm_win_icon_dirty : 1; guint net_wm_icon_dirty : 1; }; void meta_icon_cache_init (MetaIconCache *icon_cache); void meta_icon_cache_free (MetaIconCache *icon_cache); void meta_icon_cache_property_changed (MetaIconCache *icon_cache, MetaDisplay *display, Atom atom); gboolean meta_icon_cache_get_icon_invalidated (MetaIconCache *icon_cache); gboolean meta_read_icons (MetaScreen *screen, Window xwindow, MetaIconCache *icon_cache, Pixmap wm_hints_pixmap, Pixmap wm_hints_mask, GdkPixbuf **iconp, int ideal_width, int ideal_height); #endif ������������������������������������������������������������muffin-5.2.1/src/core/core.h������������������������������������������������������������������������0000664�0001750�0001750�00000022771�14211404421�015765� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin interface used by GTK+ UI to talk to core */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_CORE_H #define META_CORE_H /* Don't include core headers here */ #include <gdk/gdkx.h> #include <meta/common.h> #include <meta/window.h> typedef enum { META_CORE_GET_END = 0, META_CORE_WINDOW_HAS_FRAME, META_CORE_GET_CLIENT_WIDTH, META_CORE_GET_CLIENT_HEIGHT, META_CORE_GET_CLIENT_XWINDOW, META_CORE_GET_FRAME_FLAGS, META_CORE_GET_FRAME_TYPE, META_CORE_GET_X, META_CORE_GET_Y, META_CORE_GET_FRAME_WORKSPACE, META_CORE_GET_FRAME_X, META_CORE_GET_FRAME_Y, META_CORE_GET_FRAME_WIDTH, META_CORE_GET_FRAME_HEIGHT, META_CORE_GET_THEME_VARIANT, META_CORE_GET_SCREEN_WIDTH, META_CORE_GET_SCREEN_HEIGHT, } MetaCoreGetType; /* General information function about the given window. Pass in a sequence of * pairs of MetaCoreGetTypes and pointers to variables; the variables will be * filled with the requested values. End the list with META_CORE_GET_END. * For example: * * meta_core_get (my_display, my_window, * META_CORE_GET_X, &x, * META_CORE_GET_Y, &y, * META_CORE_GET_END); * * If the window doesn't have a frame, this will raise a meta_bug. To suppress * this behaviour, ask META_CORE_WINDOW_HAS_FRAME as the *first* question in * the list. If the window has no frame, the answer to this question will be * False, and anything else you asked will be undefined. Otherwise, the answer * will be True. The answer will necessarily be True if you ask the question * in any other position. The positions of all other questions don't matter. * * The reason for this function is that some parts of the program don't know * about MetaWindows. But they *can* see core.h. So we used to have a whole * load of functions which took a display and an X window, looked up the * relevant MetaWindow, and returned information about it. The trouble with * that is that looking up the MetaWindow is a nontrivial operation, and * consolidating the calls in this way makes (for example) frame exposes * 33% faster, according to valgrind. * * This function would perhaps be slightly better if the questions were * represented by pointers, perhaps gchar*s, because then we could take * advantage of gcc's automatic sentinel checking. On the other hand, this * immediately suggests string comparison, and that's slow. * * Another possible improvement is that core.h still has a bunch of * functions which can't be described by the formula "give a display and * an X window, get a single value" (meta_core_user_move, for example), but * which could theoretically be handled by this function if we relaxed the * requirement that all questions should have exactly one argument. */ MetaWindow *meta_core_get_window (Display *xdisplay, Window frame_xwindow); void meta_core_get (Display *xdisplay, Window window, ...); void meta_core_queue_frame_resize (Display *xdisplay, Window frame_xwindow); /* Move as a result of user operation */ void meta_core_user_move (Display *xdisplay, Window frame_xwindow, int x, int y); void meta_core_user_resize (Display *xdisplay, Window frame_xwindow, int gravity, int width, int height); void meta_core_user_raise (Display *xdisplay, Window frame_xwindow); void meta_core_user_lower_and_unfocus (Display *xdisplay, Window frame_xwindow, guint32 timestamp); void meta_core_user_focus (Display *xdisplay, Window frame_xwindow, guint32 timestamp); void meta_core_lower_beneath_grab_window (Display *xdisplay, Window xwindow, guint32 timestamp); void meta_core_lower_beneath_sibling (Display *xdisplay, Window xwindow, Window grab_window, guint32 timestamp); void meta_core_minimize (Display *xdisplay, Window frame_xwindow); void meta_core_toggle_maximize (Display *xdisplay, Window frame_xwindow); void meta_core_toggle_maximize_horizontally (Display *xdisplay, Window frame_xwindow); void meta_core_toggle_maximize_vertically (Display *xdisplay, Window frame_xwindow); void meta_core_unmaximize (Display *xdisplay, Window frame_xwindow); void meta_core_maximize (Display *xdisplay, Window frame_xwindow); void meta_core_delete (Display *xdisplay, Window frame_xwindow, guint32 timestamp); void meta_core_unshade (Display *xdisplay, Window frame_xwindow, guint32 timestamp); void meta_core_shade (Display *xdisplay, Window frame_xwindow, guint32 timestamp); void meta_core_unstick (Display *xdisplay, Window frame_xwindow); void meta_core_stick (Display *xdisplay, Window frame_xwindow); void meta_core_unmake_above (Display *xdisplay, Window frame_xwindow); void meta_core_make_above (Display *xdisplay, Window frame_xwindow); void meta_core_adjust_opacity (Display *xdisplay, Window frame_xwindow, gboolean increase); void meta_core_change_workspace (Display *xdisplay, Window frame_xwindow, int new_workspace); int meta_core_get_num_workspaces (Screen *xscreen); int meta_core_get_active_workspace (Screen *xscreen); int meta_core_get_frame_workspace (Display *xdisplay, Window frame_xwindow); const char* meta_core_get_workspace_name_with_index (Display *xdisplay, Window xroot, int index); void meta_core_show_window_menu (Display *xdisplay, Window frame_xwindow, int root_x, int root_y, int button, guint32 timestamp); void meta_core_get_menu_accelerator (MetaMenuOp menu_op, int workspace, unsigned int *keysym, MetaVirtualModifier *modifiers); gboolean meta_core_begin_grab_op (Display *xdisplay, Window frame_xwindow, MetaGrabOp op, gboolean pointer_already_grabbed, gboolean frame_action, int button, gulong modmask, guint32 timestamp, int root_x, int root_y); void meta_core_end_grab_op (Display *xdisplay, guint32 timestamp); MetaGrabOp meta_core_get_grab_op (Display *xdisplay); Window meta_core_get_grab_frame (Display *xdisplay); int meta_core_get_grab_button (Display *xdisplay); void meta_core_grab_buttons (Display *xdisplay, Window frame_xwindow); void meta_core_set_screen_cursor (Display *xdisplay, Window frame_on_screen, MetaCursor cursor); /* Used because we ignore EnterNotify when a window is unmapped that * really shouldn't cause focus changes, by comparing the event serial * of the EnterNotify and the UnmapNotify. */ void meta_core_increment_event_serial (Display *display); #endif �������muffin-5.2.1/src/core/window.c����������������������������������������������������������������������0000664�0001750�0001750�00001415155�14211404421�016342� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2001 Havoc Pennington, Anders Carlsson * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:window * @title: MetaWindow * @short_description: Muffin X managed windows */ #include <config.h> #include "window-private.h" #include "boxes-private.h" #include "edge-resistance.h" #include "util-private.h" #include "frame.h" #include <meta/errors.h> #include "workspace-private.h" #include "stack.h" #include "keybindings-private.h" #include "ui.h" #include "place.h" #include "session.h" #include <meta/prefs.h> #include "resizepopup.h" #include "xprops.h" #include <meta/group.h> #include "window-props.h" #include "constraints.h" #include "muffin-enum-types.h" #include <clutter/clutter.h> #include <X11/Xatom.h> #include <X11/Xlibint.h> /* For display->resource_mask */ #include <X11/Xlib-xcb.h> #include <xcb/res.h> #include <string.h> #include <math.h> #ifdef HAVE_SHAPE #include <X11/extensions/shape.h> #endif #include <X11/XKBlib.h> #include <X11/extensions/Xcomposite.h> #include <gdk/gdkx.h> static int destroying_windows_disallowed = 0; static void update_sm_hints (MetaWindow *window); static void update_net_frame_extents (MetaWindow *window); static void recalc_window_type (MetaWindow *window); static void recalc_window_features (MetaWindow *window); static void invalidate_work_areas (MetaWindow *window); static void recalc_window_type (MetaWindow *window); static void set_wm_state_on_xwindow (MetaDisplay *display, Window xwindow, int state); static void set_wm_state (MetaWindow *window, int state); static void set_net_wm_state (MetaWindow *window); static void meta_window_set_above (MetaWindow *window, gboolean new_value); static void send_configure_notify (MetaWindow *window); static gboolean process_property_notify (MetaWindow *window, XPropertyEvent *event); static void meta_window_force_placement (MetaWindow *window); static void meta_window_show (MetaWindow *window); static void meta_window_hide (MetaWindow *window); static gboolean meta_window_same_client (MetaWindow *window, MetaWindow *other_window); static void meta_window_save_rect (MetaWindow *window); static void save_user_window_placement (MetaWindow *window); static void force_save_user_window_placement (MetaWindow *window); static void meta_window_move_resize_internal (MetaWindow *window, MetaMoveResizeFlags flags, int resize_gravity, int root_x_nw, int root_y_nw, int w, int h); static void ensure_mru_position_after (MetaWindow *window, MetaWindow *after_this_one); static void meta_window_move_resize_now (MetaWindow *window); static void meta_window_unqueue (MetaWindow *window, guint queuebits); static void update_move (MetaWindow *window, gboolean legacy_snap, gboolean snap_mode, int x, int y); static gboolean update_move_timeout (gpointer data); static void update_resize (MetaWindow *window, gboolean snap, int x, int y, gboolean force); static gboolean update_resize_timeout (gpointer data); static gboolean should_be_on_all_workspaces (MetaWindow *window); static void meta_window_flush_calc_showing (MetaWindow *window); static gboolean queue_calc_showing_func (MetaWindow *window, void *data); static void meta_window_apply_session_info (MetaWindow *window, const MetaWindowSessionInfo *info); static void meta_window_move_between_rects (MetaWindow *window, const MetaRectangle *old_area, const MetaRectangle *new_area); static void unmaximize_window_before_freeing (MetaWindow *window); static void unminimize_window_and_all_transient_parents (MetaWindow *window); static void meta_window_update_monitor (MetaWindow *window); static void normalize_tile_state (MetaWindow *window); static unsigned int get_mask_from_snap_keysym (MetaWindow *window); static void update_edge_constraints (MetaWindow *window); static void update_gtk_edge_constraints (MetaWindow *window); /* Idle handlers for the three queues (run with meta_later_add()). The * "data" parameter in each case will be a GINT_TO_POINTER of the * index into the queue arrays to use. * * TODO: Possibly there is still some code duplication among these, which we * need to sort out at some point. */ static gboolean idle_calc_showing (gpointer data); static gboolean idle_move_resize (gpointer data); G_DEFINE_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT); #define SNAP_DELAY 2000 enum { PROP_0, PROP_TITLE, PROP_DECORATED, PROP_FULLSCREEN, PROP_MAXIMIZED_HORIZONTALLY, PROP_MAXIMIZED_VERTICALLY, PROP_TILE_TYPE, PROP_MINIMIZED, PROP_WINDOW_TYPE, PROP_USER_TIME, PROP_DEMANDS_ATTENTION, PROP_URGENT, PROP_MUFFIN_HINTS, PROP_APPEARS_FOCUSED, PROP_RESIZEABLE, PROP_ABOVE, PROP_WM_CLASS, PROP_GTK_APPLICATION_ID, PROP_GTK_UNIQUE_BUS_NAME, PROP_GTK_APPLICATION_OBJECT_PATH, PROP_GTK_WINDOW_OBJECT_PATH, PROP_GTK_APP_MENU_OBJECT_PATH, PROP_GTK_MENUBAR_OBJECT_PATH, PROP_PROGRESS, PROP_PROGRESS_PULSE }; enum { WORKSPACE_CHANGED, FOCUS, RAISED, UNMANAGED, SIZE_CHANGED, POSITION_CHANGED, ICON_CHANGED, LAST_SIGNAL }; typedef enum { ZONE_TOP = 1 << 0, ZONE_RIGHT = 1 << 1, ZONE_BOTTOM = 1 << 2, ZONE_LEFT = 1 << 3, ZONE_ULC = ZONE_TOP | ZONE_LEFT, ZONE_LLC = ZONE_BOTTOM | ZONE_LEFT, ZONE_URC = ZONE_TOP | ZONE_RIGHT, ZONE_LRC = ZONE_BOTTOM | ZONE_RIGHT } TileZone; static guint window_signals[LAST_SIGNAL] = { 0 }; static void prefs_changed_callback (MetaPreference pref, gpointer data) { MetaWindow *window = data; if (pref != META_PREF_WORKSPACES_ONLY_ON_PRIMARY) return; meta_window_update_on_all_workspaces (window); meta_window_queue (window, META_QUEUE_CALC_SHOWING); } static void meta_window_finalize (GObject *object) { MetaWindow *window = META_WINDOW (object); if (window->icon) g_object_unref (G_OBJECT (window->icon)); if (window->frame_bounds) cairo_region_destroy (window->frame_bounds); if (window->opaque_region) cairo_region_destroy (window->opaque_region); meta_icon_cache_free (&window->icon_cache); free (window->sm_client_id); free (window->wm_client_machine); free (window->startup_id); free (window->muffin_hints); free (window->role); free (window->res_class); free (window->res_name); free (window->title); free (window->icon_name); free (window->theme_icon_name); free (window->desc); free (window->gtk_theme_variant); free (window->gtk_application_id); free (window->gtk_unique_bus_name); free (window->gtk_application_object_path); free (window->gtk_window_object_path); free (window->gtk_app_menu_object_path); free (window->gtk_menubar_object_path); G_OBJECT_CLASS (meta_window_parent_class)->finalize (object); } static void meta_window_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MetaWindow *win = META_WINDOW (object); switch (prop_id) { case PROP_TITLE: g_value_set_string (value, win->title); break; case PROP_DECORATED: g_value_set_boolean (value, win->decorated); break; case PROP_FULLSCREEN: g_value_set_boolean (value, win->fullscreen); break; case PROP_MAXIMIZED_HORIZONTALLY: g_value_set_boolean (value, win->maximized_horizontally); break; case PROP_MAXIMIZED_VERTICALLY: g_value_set_boolean (value, win->maximized_vertically); break; case PROP_TILE_TYPE: g_value_set_int (value, win->tile_type); break; case PROP_MINIMIZED: g_value_set_boolean (value, win->minimized); break; case PROP_WINDOW_TYPE: g_value_set_enum (value, win->type); break; case PROP_USER_TIME: g_value_set_uint (value, win->net_wm_user_time); break; case PROP_DEMANDS_ATTENTION: g_value_set_boolean (value, win->wm_state_demands_attention); break; case PROP_URGENT: g_value_set_boolean (value, win->wm_hints_urgent); break; case PROP_MUFFIN_HINTS: g_value_set_string (value, win->muffin_hints); break; case PROP_APPEARS_FOCUSED: g_value_set_boolean (value, meta_window_appears_focused (win)); break; case PROP_WM_CLASS: g_value_set_string (value, win->res_class); break; case PROP_RESIZEABLE: g_value_set_boolean (value, win->has_resize_func); break; case PROP_ABOVE: g_value_set_boolean (value, win->wm_state_above); break; case PROP_GTK_APPLICATION_ID: g_value_set_string (value, win->gtk_application_id); break; case PROP_GTK_UNIQUE_BUS_NAME: g_value_set_string (value, win->gtk_unique_bus_name); break; case PROP_GTK_APPLICATION_OBJECT_PATH: g_value_set_string (value, win->gtk_application_object_path); break; case PROP_GTK_WINDOW_OBJECT_PATH: g_value_set_string (value, win->gtk_window_object_path); break; case PROP_GTK_APP_MENU_OBJECT_PATH: g_value_set_string (value, win->gtk_app_menu_object_path); break; case PROP_GTK_MENUBAR_OBJECT_PATH: g_value_set_string (value, win->gtk_menubar_object_path); break; case PROP_PROGRESS: g_value_set_uint (value, win->progress); break; case PROP_PROGRESS_PULSE: g_value_set_boolean (value, win->progress_pulse); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_window_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_window_class_init (MetaWindowClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = meta_window_finalize; object_class->get_property = meta_window_get_property; object_class->set_property = meta_window_set_property; g_object_class_install_property (object_class, PROP_TITLE, g_param_spec_string ("title", "Title", "The title of the window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_DECORATED, g_param_spec_boolean ("decorated", "Decorated", "Whether window is decorated", TRUE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_FULLSCREEN, g_param_spec_boolean ("fullscreen", "Fullscreen", "Whether window is fullscreened", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_MAXIMIZED_HORIZONTALLY, g_param_spec_boolean ("maximized-horizontally", "Maximized horizontally", "Whether window is maximized horizontally", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_MAXIMIZED_VERTICALLY, g_param_spec_boolean ("maximized-vertically", "Maximizing vertically", "Whether window is maximized vertically", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_TILE_TYPE, g_param_spec_int ("tile-type", "Window is tiled or snapped", "Whether window is tiled or snapped", META_WINDOW_TILE_TYPE_NONE, META_WINDOW_TILE_TYPE_SNAPPED, META_WINDOW_TILE_TYPE_NONE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_MINIMIZED, g_param_spec_boolean ("minimized", "Minimizing", "Whether window is minimized", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_WINDOW_TYPE, g_param_spec_enum ("window-type", "Window Type", "The type of the window", META_TYPE_WINDOW_TYPE, META_WINDOW_NORMAL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_USER_TIME, g_param_spec_uint ("user-time", "User time", "Timestamp of last user interaction", 0, G_MAXUINT, 0, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_DEMANDS_ATTENTION, g_param_spec_boolean ("demands-attention", "Demands Attention", "Whether the window has _NET_WM_STATE_DEMANDS_ATTENTION set", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_URGENT, g_param_spec_boolean ("urgent", "Urgent", "Whether the urgent flag of WM_HINTS is set", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_MUFFIN_HINTS, g_param_spec_string ("muffin-hints", "_MUFFIN_HINTS", "Contents of the _MUFFIN_HINTS property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_APPEARS_FOCUSED, g_param_spec_boolean ("appears-focused", "Appears focused", "Whether the window is drawn as being focused", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_RESIZEABLE, g_param_spec_boolean ("resizeable", "Resizeable", "Whether the window can be resized", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_ABOVE, g_param_spec_boolean ("above", "Above", "Whether the window is shown as always-on-top", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_WM_CLASS, g_param_spec_string ("wm-class", "WM_CLASS", "Contents of the WM_CLASS property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_GTK_APPLICATION_ID, g_param_spec_string ("gtk-application-id", "_GTK_APPLICATION_ID", "Contents of the _GTK_APPLICATION_ID property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_GTK_UNIQUE_BUS_NAME, g_param_spec_string ("gtk-unique-bus-name", "_GTK_UNIQUE_BUS_NAME", "Contents of the _GTK_UNIQUE_BUS_NAME property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_GTK_APPLICATION_OBJECT_PATH, g_param_spec_string ("gtk-application-object-path", "_GTK_APPLICATION_OBJECT_PATH", "Contents of the _GTK_APPLICATION_OBJECT_PATH property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_GTK_WINDOW_OBJECT_PATH, g_param_spec_string ("gtk-window-object-path", "_GTK_WINDOW_OBJECT_PATH", "Contents of the _GTK_WINDOW_OBJECT_PATH property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_GTK_APP_MENU_OBJECT_PATH, g_param_spec_string ("gtk-app-menu-object-path", "_GTK_APP_MENU_OBJECT_PATH", "Contents of the _GTK_APP_MENU_OBJECT_PATH property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_GTK_MENUBAR_OBJECT_PATH, g_param_spec_string ("gtk-menubar-object-path", "_GTK_MENUBAR_OBJECT_PATH", "Contents of the _GTK_MENUBAR_OBJECT_PATH property of this window", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_PROGRESS, g_param_spec_uint ("progress", "Progress", "The progress of some long-running operation", 0, 100, 0, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_PROGRESS_PULSE, g_param_spec_boolean ("progress-pulse", "Pulsing progress", "Show indeterminate or ongoing progress of an operation.", FALSE, G_PARAM_READABLE)); window_signals[WORKSPACE_CHANGED] = g_signal_new ("workspace-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MetaWindowClass, workspace_changed), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); window_signals[FOCUS] = g_signal_new ("focus", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MetaWindowClass, focus), NULL, NULL, NULL, G_TYPE_NONE, 0); window_signals[RAISED] = g_signal_new ("raised", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MetaWindowClass, raised), NULL, NULL, NULL, G_TYPE_NONE, 0); window_signals[UNMANAGED] = g_signal_new ("unmanaged", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MetaWindowClass, unmanaged), NULL, NULL, NULL, G_TYPE_NONE, 0); window_signals[POSITION_CHANGED] = g_signal_new ("position-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); window_signals[SIZE_CHANGED] = g_signal_new ("size-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); window_signals[ICON_CHANGED] = g_signal_new ("icon-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); } static void meta_window_init (MetaWindow *self) { meta_prefs_add_listener (prefs_changed_callback, self); } #ifdef WITH_VERBOSE_MODE static const char* wm_state_to_string (int state) { switch (state) { case NormalState: return "NormalState"; case IconicState: return "IconicState"; case WithdrawnState: return "WithdrawnState"; } return "Unknown"; } #endif static gboolean is_desktop_or_dock_foreach (MetaWindow *window, void *data) { gboolean *result = data; *result = window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK; if (*result) return FALSE; /* stop as soon as we find one */ else return TRUE; } /* window is the window that's newly mapped provoking * the possible change */ static void maybe_leave_show_desktop_mode (MetaWindow *window) { gboolean is_desktop_or_dock; if (!window->screen->active_workspace->showing_desktop) return; /* If the window is a transient for the dock or desktop, don't * leave show desktop mode when the window opens. That's * so you can e.g. hide all windows, manipulate a file on * the desktop via a dialog, then unshow windows again. */ is_desktop_or_dock = FALSE; is_desktop_or_dock_foreach (window, &is_desktop_or_dock); meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach, &is_desktop_or_dock); if (!is_desktop_or_dock) { meta_screen_minimize_all_on_active_workspace_except (window->screen, window); meta_screen_unshow_desktop (window->screen); } } static gboolean client_window_should_be_mapped (MetaWindow *window) { return !window->shaded; } static void sync_client_window_mapped (MetaWindow *window) { gboolean should_be_mapped; g_return_if_fail (!window->override_redirect); should_be_mapped = client_window_should_be_mapped (window); if (window->mapped == should_be_mapped) return; window->mapped = should_be_mapped; meta_error_trap_push (window->display); if (should_be_mapped) { XMapWindow (window->display->xdisplay, window->xwindow); } else { XUnmapWindow (window->display->xdisplay, window->xwindow); window->unmaps_pending ++; } meta_error_trap_pop (window->display); } static void update_client_pid (MetaWindow *window) { MetaDisplay *display = window->display; xcb_connection_t *xcb = XGetXCBConnection (display->xdisplay); xcb_res_client_id_spec_t spec = { 0 }; xcb_res_query_client_ids_cookie_t cookie; xcb_res_query_client_ids_reply_t *reply = NULL; spec.client = window->xwindow; spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; cookie = xcb_res_query_client_ids (xcb, 1, &spec); reply = xcb_res_query_client_ids_reply (xcb, cookie, NULL); if (reply == NULL) { window->client_pid = -1; return; } int pid = -1, *value; xcb_res_client_id_value_iterator_t it; for (it = xcb_res_query_client_ids_ids_iterator (reply); it.rem; xcb_res_client_id_value_next (&it)) { spec = it.data->spec; if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { value = xcb_res_client_id_value_value (it.data); window->client_pid = *value; break; } } free (reply); } LOCAL_SYMBOL MetaWindow* meta_window_new (MetaDisplay *display, Window xwindow, gboolean must_be_viewable) { XWindowAttributes attrs; MetaWindow *window; meta_display_grab (display); meta_error_trap_push (display); /* Push a trap over all of window * creation, to reduce XSync() calls */ meta_error_trap_push_with_return (display); if (XGetWindowAttributes (display->xdisplay,xwindow, &attrs)) { if(meta_error_trap_pop_with_return (display) != Success) { meta_verbose ("Failed to get attributes for window 0x%lx\n", xwindow); meta_error_trap_pop (display); meta_display_ungrab (display); return NULL; } window = meta_window_new_with_attrs (display, xwindow, must_be_viewable, META_COMP_EFFECT_CREATE, &attrs); } else { meta_error_trap_pop_with_return (display); meta_verbose ("Failed to get attributes for window 0x%lx\n", xwindow); meta_error_trap_pop (display); meta_display_ungrab (display); return NULL; } meta_error_trap_pop (display); meta_display_ungrab (display); return window; } /* The MUFFIN_WM_CLASS_FILTER environment variable is designed for * performance and regression testing environments where we want to do * tests with only a limited set of windows and ignore all other windows * * When it is set to a comma separated list of WM_CLASS class names, all * windows not matching the list will be ignored. * * Returns TRUE if window has been filtered out and should be ignored. */ static gboolean maybe_filter_window (MetaDisplay *display, Window xwindow, gboolean must_be_viewable, XWindowAttributes *attrs) { static char **filter_wm_classes = NULL; static gboolean initialized = FALSE; XClassHint class_hint; gboolean filtered; Status success; int i; if (!initialized) { const char *filter_string = g_getenv ("MUFFIN_WM_CLASS_FILTER"); if (filter_string) filter_wm_classes = g_strsplit (filter_string, ",", -1); initialized = TRUE; } if (!filter_wm_classes || !filter_wm_classes[0]) return FALSE; filtered = TRUE; meta_error_trap_push (display); success = XGetClassHint (display->xdisplay, xwindow, &class_hint); if (success) { for (i = 0; filter_wm_classes[i]; i++) { if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0) { filtered = FALSE; break; } } XFree (class_hint.res_name); XFree (class_hint.res_class); } if (filtered) { /* We want to try and get the window managed by the next WM that come along, * so we need to make sure that windows that are requested to be mapped while * Muffin is running (!must_be_viewable), or windows already viewable at startup * get a non-withdrawn WM_STATE property. Previously unmapped windows are left * with whatever WM_STATE property they had. */ if (!must_be_viewable || attrs->map_state == IsViewable) { gulong old_state; if (!meta_prop_get_cardinal_with_atom_type (display, xwindow, display->atom_WM_STATE, display->atom_WM_STATE, &old_state)) old_state = WithdrawnState; if (old_state == WithdrawnState) set_wm_state_on_xwindow (display, xwindow, NormalState); } /* Make sure filtered windows are hidden from view */ XUnmapWindow (display->xdisplay, xwindow); } meta_error_trap_pop (display); return filtered; } LOCAL_SYMBOL gboolean meta_window_should_attach_to_parent (MetaWindow *window) { MetaWindow *parent; if (!meta_prefs_get_attach_modal_dialogs () || window->type != META_WINDOW_MODAL_DIALOG) return FALSE; parent = meta_window_get_transient_for (window); if (!parent) return FALSE; switch (parent->type) { case META_WINDOW_NORMAL: case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: return TRUE; default: return FALSE; } } LOCAL_SYMBOL LOCAL_SYMBOL MetaWindow* meta_window_new_with_attrs (MetaDisplay *display, Window xwindow, gboolean must_be_viewable, MetaCompEffect effect, XWindowAttributes *attrs) { MetaWindow *window; GSList *tmp; MetaWorkspace *space; gulong existing_wm_state; gulong event_mask; MetaMoveResizeFlags flags; gboolean has_shape; MetaScreen *screen; g_assert (attrs != NULL); meta_verbose ("Attempting to manage 0x%lx\n", xwindow); if (meta_display_xwindow_is_a_no_focus_window (display, xwindow)) { meta_verbose ("Not managing no_focus_window 0x%lx\n", xwindow); return NULL; } screen = NULL; for (tmp = display->screens; tmp != NULL; tmp = tmp->next) { MetaScreen *scr = tmp->data; if (scr->xroot == attrs->root) { screen = tmp->data; break; } } g_assert (screen); /* A black list of override redirect windows that we don't need to manage: */ if (attrs->override_redirect && (xwindow == screen->no_focus_window || xwindow == screen->flash_window || xwindow == screen->wm_sn_selection_window || attrs->class == InputOnly || /* any windows created via meta_create_offscreen_window: */ (attrs->x == -100 && attrs->y == -100 && attrs->width == 1 && attrs->height == 1) || xwindow == screen->wm_cm_selection_window || xwindow == screen->guard_window || xwindow == screen->composite_overlay_window ) ) { meta_verbose ("Not managing our own windows\n"); return NULL; } if (maybe_filter_window (display, xwindow, must_be_viewable, attrs)) { meta_verbose ("Not managing filtered window\n"); return NULL; } /* Grab server */ meta_display_grab (display); meta_error_trap_push (display); /* Push a trap over all of window * creation, to reduce XSync() calls */ meta_verbose ("must_be_viewable = %d attrs->map_state = %d (%s)\n", must_be_viewable, attrs->map_state, (attrs->map_state == IsUnmapped) ? "IsUnmapped" : (attrs->map_state == IsViewable) ? "IsViewable" : (attrs->map_state == IsUnviewable) ? "IsUnviewable" : "(unknown)"); existing_wm_state = WithdrawnState; if (must_be_viewable && attrs->map_state != IsViewable) { /* Only manage if WM_STATE is IconicState or NormalState */ gulong state; /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */ if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow, display->atom_WM_STATE, display->atom_WM_STATE, &state) && (state == IconicState || state == NormalState))) { meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow); meta_error_trap_pop (display); meta_display_ungrab (display); return NULL; } existing_wm_state = state; meta_verbose ("WM_STATE of %lx = %s\n", xwindow, wm_state_to_string (existing_wm_state)); } meta_error_trap_push_with_return (display); /* * XAddToSaveSet can only be called on windows created by a different client. * with Muffin we want to be able to create manageable windows from within * the process (such as a dummy desktop window), so we do not want this * call failing to prevent the window from being managed -- wrap it in its * own error trap (we use the _with_return() version here to ensure that * XSync() is done on the pop, otherwise the error will not get caught). */ meta_error_trap_push_with_return (display); XAddToSaveSet (display->xdisplay, xwindow); meta_error_trap_pop_with_return (display); event_mask = PropertyChangeMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask | ColormapChangeMask; if (attrs->override_redirect) event_mask |= StructureNotifyMask; /* If the window is from this client (a menu, say) we need to augment * the event mask, not replace it. For windows from other clients, * attrs->your_event_mask will be empty at this point. */ XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask); has_shape = FALSE; #ifdef HAVE_SHAPE if (META_DISPLAY_HAS_SHAPE (display)) { int x_bounding, y_bounding, x_clip, y_clip; unsigned w_bounding, h_bounding, w_clip, h_clip; int bounding_shaped, clip_shaped; XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask); XShapeQueryExtents (display->xdisplay, xwindow, &bounding_shaped, &x_bounding, &y_bounding, &w_bounding, &h_bounding, &clip_shaped, &x_clip, &y_clip, &w_clip, &h_clip); has_shape = bounding_shaped != FALSE; meta_topic (META_DEBUG_SHAPES, "Window has_shape = %d extents %d,%d %u x %u\n", has_shape, x_bounding, y_bounding, w_bounding, h_bounding); } #endif /* Get rid of any borders */ if (attrs->border_width != 0) XSetWindowBorderWidth (display->xdisplay, xwindow, 0); /* Get rid of weird gravities */ if (attrs->win_gravity != NorthWestGravity) { XSetWindowAttributes set_attrs; set_attrs.win_gravity = NorthWestGravity; XChangeWindowAttributes (display->xdisplay, xwindow, CWWinGravity, &set_attrs); } if (meta_error_trap_pop_with_return (display) != Success) { meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n", xwindow); meta_error_trap_pop (display); meta_display_ungrab (display); return NULL; } window = g_object_new (META_TYPE_WINDOW, NULL); window->constructing = TRUE; window->dialog_pid = -1; window->xwindow = xwindow; /* this is in window->screen->display, but that's too annoying to * type */ window->display = display; window->workspace = NULL; #ifdef HAVE_XSYNC window->sync_request_counter = None; window->sync_request_serial = 0; window->sync_request_timeout_id = 0; window->sync_request_alarm = None; #endif window->screen = screen; window->desc = g_strdup_printf ("0x%lx", window->xwindow); // -1 is used as a result in get_client_pid() if it's called with a non-window-argument window->client_pid = -2; window->override_redirect = attrs->override_redirect; /* avoid tons of stack updates */ meta_stack_freeze (window->screen->stack); window->has_shape = has_shape; window->rect.x = attrs->x; window->rect.y = attrs->y; window->rect.width = attrs->width; window->rect.height = attrs->height; /* And border width, size_hints are the "request" */ window->border_width = attrs->border_width; window->size_hints.x = attrs->x; window->size_hints.y = attrs->y; window->size_hints.width = attrs->width; window->size_hints.height = attrs->height; /* initialize the remaining size_hints as if size_hints.flags were zero */ meta_set_normal_hints (window, NULL); /* And this is our unmaximized size */ window->saved_rect = window->rect; window->user_rect = window->rect; window->snapped_rect = window->rect; window->depth = attrs->depth; window->xvisual = attrs->visual; window->colormap = attrs->colormap; window->title = NULL; window->icon_name = NULL; window->icon = NULL; window->icon_size = -1; meta_icon_cache_init (&window->icon_cache); window->theme_icon_name = NULL; window->wm_hints_pixmap = None; window->wm_hints_mask = None; window->wm_hints_urgent = FALSE; window->frame = NULL; window->has_focus = FALSE; window->attached_focus_window = NULL; window->hide_titlebar_when_maximized = FALSE; window->maximized_horizontally = FALSE; window->maximized_vertically = FALSE; window->tile_type = META_WINDOW_TILE_TYPE_NONE; window->snap_queued = FALSE; window->current_proximity_zone = 0; window->mouse_on_edge = FALSE; window->resizing_tile_type = META_WINDOW_TILE_TYPE_NONE; window->custom_snap_size = FALSE; window->zone_queued = ZONE_NONE; window->maximize_horizontally_after_placement = FALSE; window->maximize_vertically_after_placement = FALSE; window->minimize_after_placement = FALSE; window->tile_after_placement = FALSE; window->move_after_placement = FALSE; window->fullscreen = FALSE; window->fullscreen_monitors[0] = -1; window->require_fully_onscreen = TRUE; window->require_on_single_monitor = TRUE; window->require_titlebar_visible = TRUE; window->on_all_workspaces = FALSE; window->on_all_workspaces_requested = FALSE; window->tile_mode = META_TILE_NONE; window->last_tile_mode = META_TILE_NONE; window->resize_tile_mode = META_TILE_NONE; window->maybe_retile_maximize = FALSE; window->tile_monitor_number = -1; window->shaded = FALSE; window->initially_iconic = FALSE; window->minimized = FALSE; window->tab_unminimized = FALSE; window->iconic = FALSE; window->mapped = attrs->map_state != IsUnmapped; window->hidden = FALSE; window->visible_to_compositor = FALSE; window->pending_compositor_effect = effect; /* if already mapped, no need to worry about focus-on-first-time-showing */ window->showing_for_first_time = !window->mapped; /* if already mapped we don't want to do the placement thing; * override-redirect windows are placed by the app */ window->placed = ((window->mapped && !window->hidden) || window->override_redirect); #ifdef WITH_VERBOSE_MODE if (window->placed) meta_topic (META_DEBUG_PLACEMENT, "Not placing window 0x%lx since it's already mapped\n", xwindow); #endif window->force_save_user_rect = TRUE; window->denied_focus_and_not_transient = FALSE; window->unmanaging = FALSE; window->is_in_queues = 0; window->keys_grabbed = FALSE; window->grab_on_frame = FALSE; window->all_keys_grabbed = FALSE; window->withdrawn = FALSE; window->initial_workspace_set = FALSE; window->initial_timestamp_set = FALSE; window->net_wm_user_time_set = FALSE; window->user_time_window = None; window->take_focus = FALSE; window->delete_window = FALSE; window->net_wm_ping = FALSE; window->input = TRUE; window->calc_placement = FALSE; window->shaken_loose = FALSE; window->have_focus_click_grab = FALSE; window->disable_sync = FALSE; window->unmaps_pending = 0; window->mwm_decorated = TRUE; window->mwm_border_only = FALSE; window->mwm_has_close_func = TRUE; window->mwm_has_minimize_func = TRUE; window->mwm_has_maximize_func = TRUE; window->mwm_has_move_func = TRUE; window->mwm_has_resize_func = TRUE; window->decorated = TRUE; window->has_close_func = TRUE; window->has_minimize_func = TRUE; window->has_maximize_func = TRUE; window->has_move_func = TRUE; window->has_resize_func = TRUE; window->has_shade_func = TRUE; window->has_fullscreen_func = TRUE; window->always_sticky = FALSE; window->wm_state_modal = FALSE; window->skip_taskbar = FALSE; window->skip_pager = FALSE; window->wm_state_skip_taskbar = FALSE; window->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; window->wm_state_demands_attention = FALSE; window->res_class = NULL; window->res_name = NULL; window->role = NULL; window->sm_client_id = NULL; window->wm_client_machine = NULL; window->startup_id = NULL; window->net_wm_pid = -1; window->xtransient_for = None; window->xclient_leader = None; window->transient_parent_is_root_window = FALSE; window->type = META_WINDOW_NORMAL; window->type_atom = None; window->struts = NULL; window->using_net_wm_name = FALSE; window->using_net_wm_visible_name = FALSE; window->using_net_wm_icon_name = FALSE; window->using_net_wm_visible_icon_name = FALSE; window->need_reread_icon = TRUE; window->layer = META_LAYER_LAST; /* invalid value */ window->stack_position = -1; window->initial_workspace = 0; /* not used */ window->initial_timestamp = 0; /* not used */ window->compositor_private = NULL; window->monitor = meta_screen_get_monitor_for_window (window->screen, window); window->tile_match = NULL; if (window->override_redirect) { window->decorated = FALSE; window->always_sticky = TRUE; window->has_close_func = FALSE; window->has_shade_func = FALSE; window->has_move_func = FALSE; window->has_resize_func = FALSE; } meta_display_register_x_window (display, &window->xwindow, window); /* Assign this #MetaWindow a sequence number which can be used * for sorting. */ window->stable_sequence = ++display->window_sequence_counter; /* assign the window to its group, or create a new group if needed */ window->group = NULL; window->xgroup_leader = None; meta_window_compute_group (window); meta_window_load_initial_properties (window); if (!window->override_redirect) { update_sm_hints (window); /* must come after transient_for */ meta_window_update_role (window); } meta_window_update_net_wm_type (window); if (window->decorated) meta_window_ensure_frame (window); if (window->initially_iconic) { /* WM_HINTS said minimized */ window->minimized = TRUE; meta_verbose ("Window %s asked to start out minimized\n", window->desc); } if (existing_wm_state == IconicState) { /* WM_STATE said minimized */ window->minimized = TRUE; meta_verbose ("Window %s had preexisting WM_STATE = IconicState, minimizing\n", window->desc); /* Assume window was previously placed, though perhaps it's * been iconic its whole life, we have no way of knowing. */ window->placed = TRUE; } /* Apply any window attributes such as initial workspace * based on startup notification */ meta_screen_apply_startup_properties (window->screen, window); /* Try to get a "launch timestamp" for the window. If the window is * a transient, we'd like to be able to get a last-usage timestamp * from the parent window. If the window has no parent, there isn't * much we can do...except record the current time so that any children * can use this time as a fallback. */ if (!window->override_redirect && !window->net_wm_user_time_set) { MetaWindow *parent = NULL; if (window->xtransient_for) parent = meta_display_lookup_x_window (window->display, window->xtransient_for); /* First, maybe the app was launched with startup notification using an * obsolete version of the spec; use that timestamp if it exists. */ if (window->initial_timestamp_set) /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just * being recorded as a fallback for potential transients */ window->net_wm_user_time = window->initial_timestamp; else if (parent != NULL) meta_window_set_user_time(window, parent->net_wm_user_time); else /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just * being recorded as a fallback for potential transients */ window->net_wm_user_time = meta_display_get_current_time_roundtrip (window->display); } window->attached = meta_window_should_attach_to_parent (window); if (window->attached) recalc_window_features (window); meta_window_grab_keys (window); if (window->type != META_WINDOW_DOCK && !window->override_redirect) { meta_display_grab_window_buttons (window->display, window->xwindow); meta_display_grab_focus_window_button (window->display, window); } if (window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK) { /* Change the default, but don't enforce this if the user * focuses the dock/desktop and unsticks it using key shortcuts. * Need to set this before adding to the workspaces so the MRU * lists will be updated. */ window->on_all_workspaces_requested = TRUE; } window->on_all_workspaces = should_be_on_all_workspaces (window); /* For the workspace, first honor hints, * if that fails put transients with parents, * otherwise put window on active space */ if (window->initial_workspace_set) { if (window->initial_workspace == (int) 0xFFFFFFFF) { meta_topic (META_DEBUG_PLACEMENT, "Window %s is initially on all spaces\n", window->desc); /* need to set on_all_workspaces first so that it will be * added to all the MRU lists */ window->on_all_workspaces_requested = TRUE; window->on_all_workspaces = TRUE; meta_workspace_add_window (window->screen->active_workspace, window); } else { meta_topic (META_DEBUG_PLACEMENT, "Window %s is initially on space %d\n", window->desc, window->initial_workspace); space = meta_screen_get_workspace_by_index (window->screen, window->initial_workspace); if (space) meta_workspace_add_window (space, window); } } /* override-redirect windows are subtly different from other windows * with window->on_all_workspaces == TRUE. Other windows are part of * some workspace (so they can return to that if the flag is turned off), * but appear on other workspaces. override-redirect windows are part * of no workspace. */ if (!window->override_redirect) { if (window->workspace == NULL && window->xtransient_for != None) { /* Try putting dialog on parent's workspace */ MetaWindow *parent; parent = meta_display_lookup_x_window (window->display, window->xtransient_for); if (parent && parent->workspace) { meta_topic (META_DEBUG_PLACEMENT, "Putting window %s on same workspace as parent %s\n", window->desc, parent->desc); if (parent->on_all_workspaces_requested) { window->on_all_workspaces_requested = TRUE; window->on_all_workspaces = TRUE; } /* this will implicitly add to the appropriate MRU lists */ meta_workspace_add_window (parent->workspace, window); } } if (window->workspace == NULL) { meta_topic (META_DEBUG_PLACEMENT, "Putting window %s on active workspace\n", window->desc); space = window->screen->active_workspace; meta_workspace_add_window (space, window); } /* for the various on_all_workspaces = TRUE possible above */ meta_window_set_current_workspace_hint (window); meta_window_update_struts (window); } g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window); g_signal_emit_by_name (window->screen, "window-added", window, window->monitor->number); /* Must add window to stack before doing move/resize, since the * window might have fullscreen size (i.e. should have been * fullscreen'd; acrobat is one such braindead case; it withdraws * and remaps its window whenever trying to become fullscreen...) * and thus constraints may try to auto-fullscreen it which also * means restacking it. */ if (!window->override_redirect) meta_stack_add (window->screen->stack, window); else window->layer = META_LAYER_OVERRIDE_REDIRECT; /* otherwise set by MetaStack */ /* Put our state back where it should be, * passing TRUE for is_configure_request, ICCCM says * initial map is handled same as configure request */ flags = META_IS_CONFIGURE_REQUEST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION; if (!window->override_redirect) meta_window_move_resize_internal (window, flags, window->size_hints.win_gravity, window->size_hints.x, window->size_hints.y, window->size_hints.width, window->size_hints.height); /* Now try applying saved stuff from the session */ { const MetaWindowSessionInfo *info; info = meta_window_lookup_saved_state (window); if (info) { meta_window_apply_session_info (window, info); meta_window_release_saved_state (info); } } if (!window->override_redirect) { /* FIXME we have a tendency to set this then immediately * change it again. */ set_wm_state (window, window->iconic ? IconicState : NormalState); set_net_wm_state (window); } meta_compositor_add_window (screen->display->compositor, window); /* Sync stack changes */ meta_stack_thaw (window->screen->stack); /* Usually the we'll have queued a stack sync anyways, because we've * added a new frame window or restacked. But if an undecorated * window is mapped, already stacked in the right place, then we * might need to do this explicitly. */ meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); /* disable show desktop mode unless we're a desktop component */ maybe_leave_show_desktop_mode (window); meta_window_queue (window, META_QUEUE_CALC_SHOWING); /* See bug 303284; a transient of the given window can already exist, in which * case we think it should probably be shown. */ meta_window_foreach_transient (window, queue_calc_showing_func, NULL); /* See bug 334899; the window may have minimized ancestors * which need to be shown. * * However, we shouldn't unminimize windows here when opening * a new display because that breaks passing _NET_WM_STATE_HIDDEN * between window managers when replacing them; see bug 358042. * * And we shouldn't unminimize windows if they were initially * iconic. */ if (!window->override_redirect && !display->display_opening && !window->initially_iconic) unminimize_window_and_all_transient_parents (window); meta_error_trap_pop (display); /* pop the XSync()-reducing trap */ meta_display_ungrab (display); window->constructing = FALSE; meta_display_notify_window_created (display, window); if (window->wm_state_demands_attention) g_signal_emit_by_name (window->display, "window-demands-attention", window); if (window->wm_hints_urgent) g_signal_emit_by_name (window->display, "window-marked-urgent", window); return window; } /* This function should only be called from the end of meta_window_new_with_attrs () */ static void meta_window_apply_session_info (MetaWindow *window, const MetaWindowSessionInfo *info) { if (info->stack_position_set) { meta_topic (META_DEBUG_SM, "Restoring stack position %d for window %s\n", info->stack_position, window->desc); /* FIXME well, I'm not sure how to do this. */ } if (info->minimized_set) { meta_topic (META_DEBUG_SM, "Restoring minimized state %d for window %s\n", info->minimized, window->desc); if (window->has_minimize_func && info->minimized) meta_window_minimize (window); } if (info->maximized_set) { meta_topic (META_DEBUG_SM, "Restoring maximized state %d for window %s\n", info->maximized, window->desc); if (window->has_maximize_func && info->maximized) { meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); if (info->saved_rect_set) { meta_topic (META_DEBUG_SM, "Restoring saved rect %d,%d %dx%d for window %s\n", info->saved_rect.x, info->saved_rect.y, info->saved_rect.width, info->saved_rect.height, window->desc); window->saved_rect.x = info->saved_rect.x; window->saved_rect.y = info->saved_rect.y; window->saved_rect.width = info->saved_rect.width; window->saved_rect.height = info->saved_rect.height; } } } if (info->on_all_workspaces_set) { window->on_all_workspaces_requested = info->on_all_workspaces; meta_window_update_on_all_workspaces (window); meta_topic (META_DEBUG_SM, "Restoring sticky state %d for window %s\n", window->on_all_workspaces_requested, window->desc); } if (info->workspace_indices) { GSList *tmp; GSList *spaces; spaces = NULL; tmp = info->workspace_indices; while (tmp != NULL) { MetaWorkspace *space; space = meta_screen_get_workspace_by_index (window->screen, GPOINTER_TO_INT (tmp->data)); if (space) spaces = g_slist_prepend (spaces, space); tmp = tmp->next; } if (spaces) { /* This briefly breaks the invariant that we are supposed * to always be on some workspace. But we paranoically * ensured that one of the workspaces from the session was * indeed valid, so we know we'll go right back to one. */ if (window->workspace) meta_workspace_remove_window (window->workspace, window); /* Only restore to the first workspace if the window * happened to be on more than one, since we have replaces * window->workspaces with window->workspace */ meta_workspace_add_window (spaces->data, window); meta_topic (META_DEBUG_SM, "Restoring saved window %s to workspace %d\n", window->desc, meta_workspace_index (spaces->data)); g_slist_free (spaces); } } if (info->geometry_set) { int x, y, w, h; MetaMoveResizeFlags flags; window->placed = TRUE; /* don't do placement algorithms later */ x = info->rect.x; y = info->rect.y; w = window->size_hints.base_width + info->rect.width * window->size_hints.width_inc; h = window->size_hints.base_height + info->rect.height * window->size_hints.height_inc; /* Force old gravity, ignoring anything now set */ window->size_hints.win_gravity = info->gravity; meta_topic (META_DEBUG_SM, "Restoring pos %d,%d size %d x %d for %s\n", x, y, w, h, window->desc); flags = META_DO_GRAVITY_ADJUST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION; meta_window_move_resize_internal (window, flags, window->size_hints.win_gravity, x, y, w, h); } } static gboolean detach_foreach_func (MetaWindow *window, void *data) { if (window->attached) { GList **children = data; MetaWindow *parent; /* Only return the immediate children of the window being unmanaged */ parent = meta_window_get_transient_for (window); if (parent->unmanaging) *children = g_list_prepend (*children, window); } return TRUE; } LOCAL_SYMBOL void meta_window_unmanage (MetaWindow *window, guint32 timestamp) { GList *tmp; meta_verbose ("Unmanaging 0x%lx\n", window->xwindow); if (window->visible_to_compositor || meta_window_is_attached_dialog (window)) meta_compositor_hide_window (window->display->compositor, window, META_COMP_EFFECT_DESTROY); meta_compositor_remove_window (window->display->compositor, window); if (window->display->window_with_menu == window) { meta_ui_window_menu_free (window->display->window_menu); window->display->window_menu = NULL; window->display->window_with_menu = NULL; } if (destroying_windows_disallowed > 0) meta_bug ("Tried to destroy window %s while destruction was not allowed\n", window->desc); window->unmanaging = TRUE; if (meta_prefs_get_attach_modal_dialogs ()) { GList *attached_children = NULL, *iter; /* Detach any attached dialogs by unmapping and letting them * be remapped after @window is destroyed. */ meta_window_foreach_transient (window, detach_foreach_func, &attached_children); for (iter = attached_children; iter; iter = iter->next) meta_window_unmanage (iter->data, timestamp); g_list_free (attached_children); } if (window->fullscreen) { MetaGroup *group; /* If the window is fullscreen, it may be forcing * other windows in its group to a higher layer */ meta_stack_freeze (window->screen->stack); group = meta_window_get_group (window); if (group) meta_group_update_layers (group); meta_stack_thaw (window->screen->stack); } meta_window_shutdown_group (window); /* safe to do this early as * group.c won't re-add to the * group if window->unmanaging */ /* If we have the focus, focus some other window. * This is done first, so that if the unmap causes * an EnterNotify the EnterNotify will have final say * on what gets focused, maintaining sloppy focus * invariants. */ if (meta_window_appears_focused (window)) meta_window_propagate_focus_appearance (window, FALSE); if (window->has_focus) { meta_topic (META_DEBUG_FOCUS, "Focusing default window since we're unmanaging %s\n", window->desc); meta_workspace_focus_default_window (window->screen->active_workspace, window, timestamp); } else if (window->display->expected_focus_window == window) { meta_topic (META_DEBUG_FOCUS, "Focusing default window since expected focus window freed %s\n", window->desc); window->display->expected_focus_window = NULL; meta_workspace_focus_default_window (window->screen->active_workspace, window, timestamp); } else { meta_topic (META_DEBUG_FOCUS, "Unmanaging window %s which doesn't currently have focus\n", window->desc); } if (window->struts) { meta_free_gslist_and_elements (window->struts); window->struts = NULL; meta_topic (META_DEBUG_WORKAREA, "Unmanaging window %s which has struts, so invalidating work areas\n", window->desc); invalidate_work_areas (window); } #ifdef HAVE_XSYNC if (window->sync_request_timeout_id) { g_source_remove (window->sync_request_timeout_id); window->sync_request_timeout_id = 0; } #endif if (window->display->grab_window == window) meta_display_end_grab_op (window->display, timestamp); g_assert (window->display->grab_window != window); if (window->display->focus_window == window) { window->display->focus_window = NULL; g_object_notify (G_OBJECT (window->display), "focus-window"); } if (window->maximized_horizontally || window->maximized_vertically || window->tile_type != META_WINDOW_TILE_TYPE_NONE) unmaximize_window_before_freeing (window); meta_window_unqueue (window, META_QUEUE_CALC_SHOWING | META_QUEUE_MOVE_RESIZE); meta_window_free_delete_dialog (window); if (window->workspace) meta_workspace_remove_window (window->workspace, window); g_assert (window->workspace == NULL); #ifndef G_DISABLE_CHECKS tmp = window->screen->workspaces; while (tmp != NULL) { MetaWorkspace *workspace = tmp->data; g_assert (g_list_find (workspace->windows, window) == NULL); g_assert (g_list_find (workspace->mru_list, window) == NULL); tmp = tmp->next; } #endif if (window->monitor) { g_signal_emit_by_name (window->screen, "window-left-monitor", window->monitor->number, window); window->monitor = NULL; } if (!window->override_redirect) meta_stack_remove (window->screen->stack, window); meta_window_destroy_sync_request_alarm (window); /* If an undecorated window is being withdrawn, that will change the * stack as presented to the compositing manager, without actually * changing the stacking order of X windows. */ meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); if (window->withdrawn) { /* We need to clean off the window's state so it * won't be restored if the app maps it again. */ meta_error_trap_push (window->display); meta_verbose ("Cleaning state from window %s\n", window->desc); XDeleteProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_DESKTOP); XDeleteProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_STATE); XDeleteProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_FULLSCREEN_MONITORS); set_wm_state (window, WithdrawnState); meta_error_trap_pop (window->display); } else { /* We need to put WM_STATE so that others will understand it on * restart. */ if (!window->minimized) { meta_error_trap_push (window->display); set_wm_state (window, NormalState); meta_error_trap_pop (window->display); } /* If we're unmanaging a window that is not withdrawn, then * either (a) muffin is exiting, in which case we need to map * the window so the next WM will know that it's not Withdrawn, * or (b) we want to create a new MetaWindow to replace the * current one, which will happen automatically if we re-map * the X Window. */ meta_error_trap_push (window->display); XMapWindow (window->display->xdisplay, window->xwindow); meta_error_trap_pop (window->display); } meta_window_ungrab_keys (window); meta_display_ungrab_window_buttons (window->display, window->xwindow); meta_display_ungrab_focus_window_button (window->display, window); meta_display_unregister_x_window (window->display, window->xwindow); meta_error_trap_push (window->display); /* Put back anything we messed up */ if (window->border_width != 0) XSetWindowBorderWidth (window->display->xdisplay, window->xwindow, window->border_width); /* No save set */ XRemoveFromSaveSet (window->display->xdisplay, window->xwindow); /* Even though the window is now unmanaged, we can't unselect events. This * window might be a window from this process, like a GdkMenu, in * which case it will have pointer events and so forth selected * for it by GDK. There's no way to disentangle those events from the events * we've selected. Even for a window from a different X client, * GDK could also have selected events for it for IPC purposes, so we * can't unselect in that case either. * * Similarly, we can't unselected for events on window->user_time_window. * It might be our own GDK focus window, or it might be a window that a * different client is using for multiple different things: * _NET_WM_USER_TIME_WINDOW and IPC, perhaps. */ if (window->user_time_window != None) { meta_display_unregister_x_window (window->display, window->user_time_window); window->user_time_window = None; } #ifdef HAVE_SHAPE if (META_DISPLAY_HAS_SHAPE (window->display)) XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask); #endif meta_error_trap_pop (window->display); meta_prefs_remove_listener (prefs_changed_callback, window); meta_screen_queue_check_fullscreen (window->screen); if (window->frame) { /* The XReparentWindow call in meta_window_destroy_frame() moves the * window so we need to send a configure notify; see bug 399552. (We * also do this just in case a window got unmaximized.) */ send_configure_notify (window); meta_window_destroy_frame (window); } g_signal_emit (window, window_signals[UNMANAGED], 0); g_signal_emit_by_name (window->screen, "window-removed", window); g_object_unref (window); } static gboolean should_be_on_all_workspaces (MetaWindow *window) { return window->on_all_workspaces_requested || window->override_redirect || (meta_prefs_get_workspaces_only_on_primary () && !meta_window_is_on_primary_monitor (window)); } LOCAL_SYMBOL void meta_window_update_on_all_workspaces (MetaWindow *window) { gboolean old_value; old_value = window->on_all_workspaces; window->on_all_workspaces = should_be_on_all_workspaces (window); if (window->on_all_workspaces != old_value && !window->override_redirect) { if (window->on_all_workspaces) { GList* tmp = window->screen->workspaces; /* Add to all MRU lists */ while (tmp) { MetaWorkspace* work = (MetaWorkspace*) tmp->data; if (!g_list_find (work->mru_list, window)) work->mru_list = g_list_prepend (work->mru_list, window); tmp = tmp->next; } } else { GList* tmp = window->screen->workspaces; /* Remove from MRU lists except the window's workspace */ while (tmp) { MetaWorkspace* work = (MetaWorkspace*) tmp->data; if (work != window->workspace) work->mru_list = g_list_remove (work->mru_list, window); tmp = tmp->next; } } meta_window_set_current_workspace_hint (window); } meta_screen_update_snapped_windows (window->screen); } static void set_wm_state_on_xwindow (MetaDisplay *display, Window xwindow, int state) { unsigned long data[2]; /* Muffin doesn't use icon windows, so data[1] should be None * according to the ICCCM 2.0 Section 4.1.3.1. */ data[0] = state; data[1] = None; meta_error_trap_push (display); XChangeProperty (display->xdisplay, xwindow, display->atom_WM_STATE, display->atom_WM_STATE, 32, PropModeReplace, (guchar*) data, 2); meta_error_trap_pop (display); } static void set_wm_state (MetaWindow *window, int state) { meta_verbose ("Setting wm state %s on %s\n", wm_state_to_string (state), window->desc); set_wm_state_on_xwindow (window->display, window->xwindow, state); } static void set_net_wm_state (MetaWindow *window) { int i; unsigned long data[14]; i = 0; if (window->shaded) { data[i] = window->display->atom__NET_WM_STATE_SHADED; ++i; } if (window->wm_state_modal) { data[i] = window->display->atom__NET_WM_STATE_MODAL; ++i; } if (window->skip_pager) { data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER; ++i; } if (window->skip_taskbar) { data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR; ++i; } if (window->maximized_horizontally) { data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ; ++i; } /* As of 3.10, Gtk considers _NET_WM_STATE_MAXIMIZED_VERT to be a tiled window also */ if (window->maximized_vertically || window->tile_type != META_WINDOW_TILE_TYPE_NONE) { data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT; ++i; } if (window->tile_type != META_WINDOW_TILE_TYPE_NONE) { data[i] = window->display->atom__NET_WM_STATE_TILED; ++i; } if (window->fullscreen) { data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN; ++i; } if (!meta_window_showing_on_its_workspace (window) || window->shaded) { data[i] = window->display->atom__NET_WM_STATE_HIDDEN; ++i; } if (window->wm_state_above) { data[i] = window->display->atom__NET_WM_STATE_ABOVE; ++i; } if (window->wm_state_below) { data[i] = window->display->atom__NET_WM_STATE_BELOW; ++i; } if (window->wm_state_demands_attention) { data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION; ++i; } if (window->on_all_workspaces_requested) { data[i] = window->display->atom__NET_WM_STATE_STICKY; ++i; } if (meta_window_appears_focused (window)) { data[i] = window->display->atom__NET_WM_STATE_FOCUSED; ++i; } meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i); meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (guchar*) data, i); meta_error_trap_pop (window->display); if (window->fullscreen) { data[0] = window->fullscreen_monitors[0]; data[1] = window->fullscreen_monitors[1]; data[2] = window->fullscreen_monitors[2]; data[3] = window->fullscreen_monitors[3]; meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n"); meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_FULLSCREEN_MONITORS, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 4); meta_error_trap_pop (window->display); } if (window->tile_type != META_WINDOW_TILE_TYPE_NONE) { MetaRectangle rect; meta_window_get_outer_rect (window, &rect); data[0] = (unsigned long) window->tile_mode; data[1] = (unsigned long) window->tile_type; data[2] = (unsigned long) rect.x; data[3] = (unsigned long) rect.y; data[4] = (unsigned long) rect.width; data[5] = (unsigned long) rect.height; data[6] = (unsigned long) window->tile_monitor_number; data[7] = (unsigned long) window->custom_snap_size ? 1 : 0; meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_WINDOW_TILE_INFO, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 8); meta_error_trap_pop (window->display); } else { meta_error_trap_push (window->display); XDeleteProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_WINDOW_TILE_INFO); meta_error_trap_pop (window->display); } meta_error_trap_push (window->display); update_gtk_edge_constraints (window); meta_error_trap_pop (window->display); } LOCAL_SYMBOL gboolean meta_window_located_on_workspace (MetaWindow *window, MetaWorkspace *workspace) { return (window->on_all_workspaces && window->screen == workspace->screen) || (window->workspace == workspace); } static gboolean is_minimized_foreach (MetaWindow *window, void *data) { gboolean *result = data; *result = window->minimized; if (*result) return FALSE; /* stop as soon as we find one */ else return TRUE; } static gboolean ancestor_is_minimized (MetaWindow *window) { gboolean is_minimized; is_minimized = FALSE; meta_window_foreach_ancestor (window, is_minimized_foreach, &is_minimized); return is_minimized; } /** * meta_window_showing_on_its_workspace: * @window: A #MetaWindow * * Returns: %TRUE if window would be visible, if its workspace was current */ gboolean meta_window_showing_on_its_workspace (MetaWindow *window) { gboolean is_desktop_or_dock; MetaWorkspace* workspace_of_window; /* 1. See if we're minimized */ if (window->minimized) return FALSE; /* 2. See if we're in "show desktop" mode */ is_desktop_or_dock = FALSE; is_desktop_or_dock_foreach (window, &is_desktop_or_dock); meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach, &is_desktop_or_dock); if (window->on_all_workspaces) workspace_of_window = window->screen->active_workspace; else if (window->workspace) workspace_of_window = window->workspace; else /* This only seems to be needed for startup */ workspace_of_window = NULL; if (workspace_of_window && workspace_of_window->showing_desktop && !is_desktop_or_dock) return FALSE; /* 3. See if an ancestor is minimized (note that * ancestor's "mapped" field may not be up to date * since it's being computed in this same idle queue) */ if (ancestor_is_minimized (window)) return FALSE; return TRUE; } LOCAL_SYMBOL gboolean meta_window_should_be_showing (MetaWindow *window) { gboolean on_workspace; meta_verbose ("Should be showing for window %s\n", window->desc); /* See if we're on the workspace */ on_workspace = meta_window_located_on_workspace (window, window->screen->active_workspace); if (!on_workspace) meta_verbose ("Window %s is not on workspace %d\n", window->desc, meta_workspace_index (window->screen->active_workspace)); else meta_verbose ("Window %s is on the active workspace %d\n", window->desc, meta_workspace_index (window->screen->active_workspace)); if (window->on_all_workspaces) meta_verbose ("Window %s is on all workspaces\n", window->desc); return on_workspace && meta_window_showing_on_its_workspace (window); } static void implement_showing (MetaWindow *window, gboolean showing) { /* Actually show/hide the window */ meta_verbose ("Implement showing = %d for window %s\n", showing, window->desc); if (!showing) { /* When we manage a new window, we normally delay placing it * until it is is first shown, but if we're previewing hidden * windows we might want to know where they are on the screen, * so we should place the window even if we're hiding it rather * than showing it. */ if (!window->placed) meta_window_force_placement (window); meta_window_hide (window); } else meta_window_show (window); if (!window->override_redirect) sync_client_window_mapped (window); window->pending_compositor_effect = META_COMP_EFFECT_NONE; } static void meta_window_calc_showing (MetaWindow *window) { implement_showing (window, meta_window_should_be_showing (window)); } static guint queue_later[NUMBER_OF_QUEUES] = {0, 0, 0}; static GSList *queue_pending[NUMBER_OF_QUEUES] = {NULL, NULL, NULL}; static int stackcmp (gconstpointer a, gconstpointer b) { MetaWindow *aw = (gpointer) a; MetaWindow *bw = (gpointer) b; if (aw->screen != bw->screen) return 0; /* don't care how they sort with respect to each other */ else return meta_stack_windows_cmp (aw->screen->stack, aw, bw); } static gboolean idle_calc_showing (gpointer data) { GSList *tmp; GSList *copy; GSList *should_show; GSList *should_hide; GSList *unplaced; GSList *displays; MetaWindow *first_window; guint queue_index = GPOINTER_TO_INT (data); g_return_val_if_fail (queue_pending[queue_index] != NULL, FALSE); meta_topic (META_DEBUG_WINDOW_STATE, "Clearing the calc_showing queue\n"); /* Work with a copy, for reentrancy. The allowed reentrancy isn't * complete; destroying a window while we're in here would result in * badness. But it's OK to queue/unqueue calc_showings. */ copy = g_slist_copy (queue_pending[queue_index]); g_slist_free (queue_pending[queue_index]); queue_pending[queue_index] = NULL; queue_later[queue_index] = 0; destroying_windows_disallowed += 1; /* We map windows from top to bottom and unmap from bottom to * top, to avoid extra expose events. The exception is * for unplaced windows, which have to be mapped from bottom to * top so placement works. */ should_show = NULL; should_hide = NULL; unplaced = NULL; displays = NULL; tmp = copy; while (tmp != NULL) { MetaWindow *window; window = tmp->data; if (!window->placed) unplaced = g_slist_prepend (unplaced, window); else if (meta_window_should_be_showing (window)) should_show = g_slist_prepend (should_show, window); else should_hide = g_slist_prepend (should_hide, window); tmp = tmp->next; } /* bottom to top */ unplaced = g_slist_sort (unplaced, stackcmp); should_hide = g_slist_sort (should_hide, stackcmp); /* top to bottom */ should_show = g_slist_sort (should_show, stackcmp); should_show = g_slist_reverse (should_show); first_window = copy->data; meta_display_grab (first_window->display); tmp = unplaced; while (tmp != NULL) { MetaWindow *window; window = tmp->data; meta_window_calc_showing (window); tmp = tmp->next; } tmp = should_show; while (tmp != NULL) { MetaWindow *window; window = tmp->data; implement_showing (window, TRUE); tmp = tmp->next; } tmp = should_hide; while (tmp != NULL) { MetaWindow *window; window = tmp->data; implement_showing (window, FALSE); tmp = tmp->next; } tmp = copy; while (tmp != NULL) { MetaWindow *window; window = tmp->data; /* important to set this here for reentrancy - * if we queue a window again while it's in "copy", * then queue_calc_showing will just return since * we are still in the calc_showing queue */ window->is_in_queues &= ~META_QUEUE_CALC_SHOWING; tmp = tmp->next; } if (meta_prefs_get_focus_mode () != C_DESKTOP_FOCUS_MODE_CLICK) { /* When display->mouse_mode is false, we want to ignore * EnterNotify events unless they come from mouse motion. To do * that, we set a sentinel property on the root window if we're * not in mouse_mode. */ tmp = should_show; while (tmp != NULL) { MetaWindow *window = tmp->data; if (!window->display->mouse_mode) meta_display_increment_focus_sentinel (window->display); tmp = tmp->next; } } meta_display_ungrab (first_window->display); g_slist_free (copy); g_slist_free (unplaced); g_slist_free (should_show); g_slist_free (should_hide); g_slist_free (displays); destroying_windows_disallowed -= 1; return FALSE; } #ifdef WITH_VERBOSE_MODE static const gchar* meta_window_queue_names[NUMBER_OF_QUEUES] = {"calc_showing", "move_resize", "update_icon"}; #endif static void meta_window_unqueue (MetaWindow *window, guint queuebits) { gint queuenum; for (queuenum=0; queuenum<NUMBER_OF_QUEUES; queuenum++) { if ((queuebits & 1<<queuenum) /* they have asked to unqueue */ && (window->is_in_queues & 1<<queuenum)) /* it's in the queue */ { meta_topic (META_DEBUG_WINDOW_STATE, "Removing %s from the %s queue\n", window->desc, meta_window_queue_names[queuenum]); /* Note that window may not actually be in the queue * because it may have been in "copy" inside the idle handler */ queue_pending[queuenum] = g_slist_remove (queue_pending[queuenum], window); window->is_in_queues &= ~(1<<queuenum); /* Okay, so maybe we've used up all the entries in the queue. * In that case, we should kill the function that deals with * the queue, because there's nothing left for it to do. */ if (queue_pending[queuenum] == NULL && queue_later[queuenum] != 0) { meta_later_remove (queue_later[queuenum]); queue_later[queuenum] = 0; } } } } static void meta_window_flush_calc_showing (MetaWindow *window) { if (window->is_in_queues & META_QUEUE_CALC_SHOWING) { meta_window_unqueue (window, META_QUEUE_CALC_SHOWING); meta_window_calc_showing (window); } } LOCAL_SYMBOL void meta_window_queue (MetaWindow *window, guint queuebits) { /* Easier to debug by checking here rather than in the idle */ g_return_if_fail (!window->override_redirect || (queuebits & META_QUEUE_MOVE_RESIZE) == 0); for (guint queuenum=0; queuenum<NUMBER_OF_QUEUES; queuenum++) { if (queuebits & 1<<queuenum) { /* Data which varies between queues. * Yes, these do look a lot like associative arrays: * I seem to be turning into a Perl programmer. */ const MetaLaterType window_queue_later_when[NUMBER_OF_QUEUES] = { META_LATER_CALC_SHOWING, /* CALC_SHOWING */ META_LATER_RESIZE, /* MOVE_RESIZE */ }; const GSourceFunc window_queue_later_handler[NUMBER_OF_QUEUES] = { idle_calc_showing, idle_move_resize }; /* If we're about to drop the window, there's no point in putting * it on a queue. */ if (window->unmanaging) break; /* If the window already claims to be in that queue, there's no * point putting it in the queue. */ if (window->is_in_queues & 1<<queuenum) break; meta_topic (META_DEBUG_WINDOW_STATE, "Putting %s in the %s queue\n", window->desc, meta_window_queue_names[queuenum]); /* So, mark it as being in this queue. */ window->is_in_queues |= 1<<queuenum; /* There's not a lot of point putting things into a queue if * nobody's on the other end pulling them out. Therefore, * let's check to see whether an idle handler exists to do * that. If not, we'll create one. */ if (queue_later[queuenum] == 0) queue_later[queuenum] = meta_later_add ( window_queue_later_when[queuenum], window_queue_later_handler[queuenum], GUINT_TO_POINTER(queuenum), NULL ); /* And now we actually put it on the queue. */ queue_pending[queuenum] = g_slist_prepend (queue_pending[queuenum], window); } } } static gboolean intervening_user_event_occurred (MetaWindow *window) { guint32 compare; MetaWindow *focus_window; focus_window = window->display->focus_window; meta_topic (META_DEBUG_STARTUP, "COMPARISON:\n" " net_wm_user_time_set : %d\n" " net_wm_user_time : %u\n" " initial_timestamp_set: %d\n" " initial_timestamp : %u\n", window->net_wm_user_time_set, window->net_wm_user_time, window->initial_timestamp_set, window->initial_timestamp); #ifdef WITH_VERBOSE_MODE if (focus_window != NULL) { meta_topic (META_DEBUG_STARTUP, "COMPARISON (continued):\n" " focus_window : %s\n" " fw->net_wm_user_time_set : %d\n" " fw->net_wm_user_time : %u\n", focus_window->desc, focus_window->net_wm_user_time_set, focus_window->net_wm_user_time); } #endif /* We expect the most common case for not focusing a new window * to be when a hint to not focus it has been set. Since we can * deal with that case rapidly, we use special case it--this is * merely a preliminary optimization. :) */ if ( ((window->net_wm_user_time_set == TRUE) && (window->net_wm_user_time == 0)) || ((window->initial_timestamp_set == TRUE) && (window->initial_timestamp == 0))) { meta_topic (META_DEBUG_STARTUP, "window %s explicitly requested no focus\n", window->desc); return TRUE; } if (!(window->net_wm_user_time_set) && !(window->initial_timestamp_set)) { meta_topic (META_DEBUG_STARTUP, "no information about window %s found\n", window->desc); return FALSE; } if (focus_window != NULL && !focus_window->net_wm_user_time_set) { meta_topic (META_DEBUG_STARTUP, "focus window, %s, doesn't have a user time set yet!\n", window->desc); return FALSE; } /* To determine the "launch" time of an application, * startup-notification can set the TIMESTAMP and the * application (usually via its toolkit such as gtk or qt) can * set the _NET_WM_USER_TIME. If both are set, we need to be * using the newer of the two values. * * See http://bugzilla.gnome.org/show_bug.cgi?id=573922 */ compare = 0; if (window->net_wm_user_time_set && window->initial_timestamp_set) compare = XSERVER_TIME_IS_BEFORE (window->net_wm_user_time, window->initial_timestamp) ? window->initial_timestamp : window->net_wm_user_time; else if (window->net_wm_user_time_set) compare = window->net_wm_user_time; else if (window->initial_timestamp_set) compare = window->initial_timestamp; if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time)) { meta_topic (META_DEBUG_STARTUP, "window %s focus prevented by other activity; %u < %u\n", window->desc, compare, focus_window->net_wm_user_time); return TRUE; } else { meta_topic (META_DEBUG_STARTUP, "new window %s with no intervening events\n", window->desc); return FALSE; } } /* This function is an ugly hack. It's experimental in nature and ought to be * replaced by a real hint from the app to the WM if we decide the experimental * behavior is worthwhile. The basic idea is to get more feedback about how * usage scenarios of "strict" focus users and what they expect. See #326159. */ LOCAL_SYMBOL gboolean __window_is_terminal (MetaWindow *window) { if (window == NULL || window->res_class == NULL) return FALSE; /* * Compare res_class, which is not user-settable, and thus theoretically * a more-reliable indication of term-ness. */ /* gnome-terminal -- if you couldn't guess */ if (strcmp (window->res_class, "Gnome-terminal") == 0) return TRUE; /* xterm, rxvt, aterm */ else if (strcmp (window->res_class, "XTerm") == 0) return TRUE; /* konsole, KDE's terminal program */ else if (strcmp (window->res_class, "Konsole") == 0) return TRUE; /* rxvt-unicode */ else if (strcmp (window->res_class, "URxvt") == 0) return TRUE; /* eterm */ else if (strcmp (window->res_class, "Eterm") == 0) return TRUE; /* KTerm -- some terminal not KDE based; so not like Konsole */ else if (strcmp (window->res_class, "KTerm") == 0) return TRUE; /* Multi-gnome-terminal */ else if (strcmp (window->res_class, "Multi-gnome-terminal") == 0) return TRUE; /* mlterm ("multi lingual terminal emulator on X") */ else if (strcmp (window->res_class, "mlterm") == 0) return TRUE; /* Terminal -- XFCE Terminal */ else if (strcmp (window->res_class, "Terminal") == 0) return TRUE; return FALSE; } /* This function determines what state the window should have assuming that it * and the focus_window have no relation */ static void window_state_on_map (MetaWindow *window, gboolean *takes_focus, gboolean *places_on_top) { gboolean intervening_events; intervening_events = intervening_user_event_occurred (window); *takes_focus = !intervening_events; *places_on_top = *takes_focus; /* don't initially focus windows that are intended to not accept * focus */ if (!(window->input || window->take_focus)) { *takes_focus = FALSE; return; } /* Terminal usage may be different; some users intend to launch * many apps in quick succession or to just view things in the new * window while still interacting with the terminal. In that case, * apps launched from the terminal should not take focus. This * isn't quite the same as not allowing focus to transfer from * terminals due to new window map, but the latter is a much easier * approximation to enforce so we do that. */ if (*takes_focus && meta_prefs_get_focus_new_windows () == C_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && !window->display->allow_terminal_deactivation && __window_is_terminal (window->display->focus_window) && !meta_window_is_ancestor_of_transient (window->display->focus_window, window)) { meta_topic (META_DEBUG_FOCUS, "focus_window is terminal; not focusing new window.\n"); *takes_focus = FALSE; *places_on_top = FALSE; } switch (window->type) { case META_WINDOW_UTILITY: case META_WINDOW_TOOLBAR: *takes_focus = FALSE; *places_on_top = FALSE; break; case META_WINDOW_DOCK: case META_WINDOW_DESKTOP: case META_WINDOW_SPLASHSCREEN: case META_WINDOW_MENU: /* override redirect types: */ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: /* don't focus any of these; places_on_top may be irrelevant for some of * these (e.g. dock)--but you never know--the focus window might also be * of the same type in some weird situation... */ *takes_focus = FALSE; break; case META_WINDOW_NORMAL: case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: /* The default is correct for these */ break; } } static gboolean windows_overlap (const MetaWindow *w1, const MetaWindow *w2) { MetaRectangle w1rect, w2rect; meta_window_get_outer_rect (w1, &w1rect); meta_window_get_outer_rect (w2, &w2rect); return meta_rectangle_overlap (&w1rect, &w2rect); } /* Returns whether a new window would be covered by any * existing window on the same workspace that is set * to be "above" ("always on top"). A window that is not * set "above" would be underneath the new window anyway. * * We take "covered" to mean even partially covered, but * some people might prefer entirely covered. I think it * is more useful to behave this way if any part of the * window is covered, because a partial coverage could be * (say) ninety per cent and almost indistinguishable from total. */ static gboolean window_would_be_covered (const MetaWindow *newbie) { MetaWorkspace *workspace = newbie->workspace; GList *tmp, *windows; windows = meta_workspace_list_windows (workspace); tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w->wm_state_above && w != newbie) { /* We have found a window that is "above". Perhaps it overlaps. */ if (windows_overlap (w, newbie)) { g_list_free (windows); /* clean up... */ return TRUE; /* yes, it does */ } } tmp = tmp->next; } g_list_free (windows); return FALSE; /* none found */ } static void meta_window_force_placement (MetaWindow *window) { if (window->placed) return; /* We have to recalc the placement here since other windows may * have been mapped/placed since we last did constrain_position */ /* calc_placement is an efficiency hack to avoid * multiple placement calculations before we finally * show the window. */ window->calc_placement = TRUE; meta_window_move_resize_now (window); window->calc_placement = FALSE; /* don't ever do the initial position constraint thing again. * This is toggled here so that initially-iconified windows * still get placed when they are ultimately shown. */ window->placed = TRUE; /* Don't want to accidentally reuse the fact that we had been denied * focus in any future constraints unless we're denied focus again. */ window->denied_focus_and_not_transient = FALSE; } static void meta_window_show (MetaWindow *window) { gboolean did_show; gboolean takes_focus_on_map; gboolean place_on_top_on_map; gboolean needs_stacking_adjustment; MetaWindow *focus_window; gboolean notify_demands_attention = FALSE; meta_topic (META_DEBUG_WINDOW_STATE, "Showing window %s, shaded: %d iconic: %d placed: %d\n", window->desc, window->shaded, window->iconic, window->placed); focus_window = window->display->focus_window; /* May be NULL! */ did_show = FALSE; window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map); needs_stacking_adjustment = FALSE; meta_topic (META_DEBUG_WINDOW_STATE, "Window %s %s focus on map, and %s place on top on map.\n", window->desc, takes_focus_on_map ? "does" : "does not", place_on_top_on_map ? "does" : "does not"); /* Now, in some rare cases we should *not* put a new window on top. * These cases include certain types of windows showing for the first * time, and any window which would be covered because of another window * being set "above" ("always on top"). * * FIXME: Although "place_on_top_on_map" and "takes_focus_on_map" are * generally based on the window type, there is a special case when the * focus window is a terminal for them both to be false; this should * probably rather be a term in the "if" condition below. */ if ( focus_window != NULL && window->showing_for_first_time && ( (!place_on_top_on_map && !takes_focus_on_map) || window_would_be_covered (window) ) ) { if (!meta_window_is_ancestor_of_transient (focus_window, window)) { needs_stacking_adjustment = TRUE; if (!window->placed) window->denied_focus_and_not_transient = TRUE; } } if (!window->placed) { meta_window_force_placement (window); } if (needs_stacking_adjustment) { gboolean overlap; /* This window isn't getting focus on map. We may need to do some * special handing with it in regards to * - the stacking of the window * - the MRU position of the window * - the demands attention setting of the window * * Firstly, set the flag so we don't give the window focus anyway * and confuse people. */ takes_focus_on_map = FALSE; overlap = windows_overlap (window, focus_window); /* We want alt tab to go to the denied-focus window */ ensure_mru_position_after (window, focus_window); /* We don't want the denied-focus window to obscure the focus * window, and if we're in both click-to-focus mode and * raise-on-click mode then we want to maintain the invariant * that MRU order == stacking order. The need for this if * comes from the fact that in sloppy/mouse focus the focus * window may not overlap other windows and also can be * considered "below" them; this combination means that * placing the denied-focus window "below" the focus window * in the stack when it doesn't overlap it confusingly places * that new window below a lot of other windows. */ if (overlap || (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK && meta_prefs_get_raise_on_click ())) meta_window_stack_just_below (window, focus_window); /* If the window will be obscured by the focus window, then the * user might not notice the window appearing so set the * demands attention hint. * * We set the hint ourselves rather than calling * meta_window_set_demands_attention() because that would cause * a recalculation of overlap, and a call to set_net_wm_state() * which we are going to call ourselves here a few lines down. */ if (overlap) { if (!window->wm_state_demands_attention) { window->wm_state_demands_attention = TRUE; notify_demands_attention = TRUE; } } } if (window->hidden) { meta_stack_freeze (window->screen->stack); window->hidden = FALSE; meta_stack_thaw (window->screen->stack); did_show = TRUE; } if (window->iconic) { window->iconic = FALSE; set_wm_state (window, NormalState); } if (!window->visible_to_compositor) { window->visible_to_compositor = TRUE; MetaCompEffect effect = META_COMP_EFFECT_NONE; switch (window->pending_compositor_effect) { case META_COMP_EFFECT_CREATE: case META_COMP_EFFECT_UNMINIMIZE: effect = window->pending_compositor_effect; break; case META_COMP_EFFECT_NONE: case META_COMP_EFFECT_DESTROY: case META_COMP_EFFECT_MINIMIZE: break; } meta_compositor_show_window (window->display->compositor, window, effect); } /* We don't want to worry about all cases from inside * implement_showing(); we only want to worry about focus if this * window has not been shown before. */ if (window->showing_for_first_time) { window->showing_for_first_time = FALSE; if (takes_focus_on_map) { guint32 timestamp; timestamp = meta_display_get_current_time_roundtrip (window->display); meta_window_focus (window, timestamp); if (window->move_after_placement) { timestamp = meta_display_get_current_time_roundtrip (window->display); meta_window_begin_grab_op(window, META_GRAB_OP_KEYBOARD_MOVING, FALSE, timestamp); window->move_after_placement = FALSE; } } else { /* Prevent EnterNotify events in sloppy/mouse focus from * erroneously focusing the window that had been denied * focus. FIXME: This introduces a race; I have a couple * ideas for a better way to accomplish the same thing, but * they're more involved so do it this way for now. */ meta_display_increment_focus_sentinel (window->display); } } set_net_wm_state (window); if (did_show && window->struts) { meta_topic (META_DEBUG_WORKAREA, "Mapped window %s with struts, so invalidating work areas\n", window->desc); invalidate_work_areas (window); } if (did_show) meta_screen_queue_check_fullscreen (window->screen); /* * Now that we have shown the window, we no longer want to consider the * initial timestamp in any subsequent deliberations whether to focus this * window or not, so clear the flag. * * See http://bugzilla.gnome.org/show_bug.cgi?id=573922 */ window->initial_timestamp_set = FALSE; if (notify_demands_attention) { g_object_notify (G_OBJECT (window), "demands-attention"); g_signal_emit_by_name (window->display, "window-demands-attention", window); } } static void meta_window_hide (MetaWindow *window) { gboolean did_hide; meta_topic (META_DEBUG_WINDOW_STATE, "Hiding window %s\n", window->desc); if (window->visible_to_compositor) { window->visible_to_compositor = FALSE; MetaCompEffect effect = META_COMP_EFFECT_NONE; switch (window->pending_compositor_effect) { case META_COMP_EFFECT_CREATE: case META_COMP_EFFECT_UNMINIMIZE: case META_COMP_EFFECT_NONE: break; case META_COMP_EFFECT_DESTROY: case META_COMP_EFFECT_MINIMIZE: effect = window->pending_compositor_effect; break; } meta_compositor_hide_window (window->display->compositor, window, effect); } did_hide = FALSE; if (!window->hidden) { meta_stack_freeze (window->screen->stack); window->hidden = TRUE; meta_stack_thaw (window->screen->stack); did_hide = TRUE; } if (!window->iconic) { window->iconic = TRUE; set_wm_state (window, IconicState); } set_net_wm_state (window); if (did_hide && window->struts) { meta_topic (META_DEBUG_WORKAREA, "Unmapped window %s with struts, so invalidating work areas\n", window->desc); invalidate_work_areas (window); } /* The check on expected_focus_window is a temporary workaround for * https://bugzilla.gnome.org/show_bug.cgi?id=597352 * We may have already switched away from this window but not yet * gotten FocusIn/FocusOut events. A more complete comprehensive * fix for these type of issues is described in the bug. */ if (window->has_focus && window == window->display->expected_focus_window) { MetaWindow *not_this_one = NULL; MetaWorkspace *my_workspace = meta_window_get_workspace (window); guint32 timestamp = meta_display_get_current_time_roundtrip (window->display); /* * If this window is modal, passing the not_this_one window to * _focus_default_window() makes the focus to be given to this window's * ancestor. This can only be the case if the window is on the currently * active workspace; when it is not, we need to pass in NULL, so as to * focus the default window for the active workspace (this scenario * arises when we are switching workspaces). */ if (window->type == META_WINDOW_MODAL_DIALOG && my_workspace == window->screen->active_workspace) not_this_one = window; meta_workspace_focus_default_window (window->screen->active_workspace, not_this_one, timestamp); } if (did_hide) meta_screen_queue_check_fullscreen (window->screen); } static gboolean queue_calc_showing_func (MetaWindow *window, void *data) { meta_window_queue(window, META_QUEUE_CALC_SHOWING); return TRUE; } void meta_window_minimize (MetaWindow *window) { g_return_if_fail (!window->override_redirect); if (!window->minimized) { window->minimized = TRUE; window->pending_compositor_effect = META_COMP_EFFECT_MINIMIZE; meta_window_queue(window, META_QUEUE_CALC_SHOWING); meta_window_foreach_transient (window, queue_calc_showing_func, NULL); #ifdef WITH_VERBOSE_MODE if (window->has_focus) { meta_topic (META_DEBUG_FOCUS, "Focusing default window due to minimization of focus window %s\n", window->desc); } else { meta_topic (META_DEBUG_FOCUS, "Minimizing window %s which doesn't have the focus\n", window->desc); } #endif g_object_notify (G_OBJECT (window), "minimized"); } meta_screen_update_snapped_windows (window->screen); } void meta_window_unminimize (MetaWindow *window) { g_return_if_fail (!window->override_redirect); if (window->minimized) { window->minimized = FALSE; window->pending_compositor_effect = META_COMP_EFFECT_UNMINIMIZE; meta_window_queue(window, META_QUEUE_CALC_SHOWING); meta_window_foreach_transient (window, queue_calc_showing_func, NULL); g_object_notify (G_OBJECT (window), "minimized"); } meta_screen_update_snapped_windows (window->screen); } static void ensure_size_hints_satisfied (MetaRectangle *rect, const XSizeHints *size_hints) { int minw, minh, maxw, maxh; /* min/max width/height */ int basew, baseh, winc, hinc; /* base width/height, width/height increment */ int extra_width, extra_height; minw = size_hints->min_width; minh = size_hints->min_height; maxw = size_hints->max_width; maxh = size_hints->max_height; basew = size_hints->base_width; baseh = size_hints->base_height; winc = size_hints->width_inc; hinc = size_hints->height_inc; /* First, enforce min/max size constraints */ rect->width = CLAMP (rect->width, minw, maxw); rect->height = CLAMP (rect->height, minh, maxh); /* Now, verify size increment constraints are satisfied, or make them be */ extra_width = (rect->width - basew) % winc; extra_height = (rect->height - baseh) % hinc; rect->width -= extra_width; rect->height -= extra_height; /* Adjusting width/height down, as done above, may violate minimum size * constraints, so one last fix. */ if (rect->width < minw) rect->width += ((minw - rect->width)/winc + 1)*winc; if (rect->height < minh) rect->height += ((minh - rect->height)/hinc + 1)*hinc; } static void meta_window_save_rect (MetaWindow *window) { if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED_OR_SNAPPED (window) || window->fullscreen)) { /* save size/pos as appropriate args for move_resize */ if (!window->maximized_horizontally) { window->saved_rect.x = window->rect.x; window->saved_rect.width = window->rect.width; if (window->frame) window->saved_rect.x += window->frame->rect.x; } if (!window->maximized_vertically) { window->saved_rect.y = window->rect.y; window->saved_rect.height = window->rect.height; if (window->frame) window->saved_rect.y += window->frame->rect.y; } } } /* * Save the user_rect regardless of whether the window is maximized or * fullscreen. See save_user_window_placement() for most uses. * * \param window Store current position of this window for future reference */ static void force_save_user_window_placement (MetaWindow *window) { meta_window_get_client_root_coords (window, &window->user_rect); } /* * Save the user_rect, but only if the window is neither maximized nor * fullscreen, otherwise the window may snap back to those dimensions * (bug #461927). * * \param window Store current position of this window for future reference */ static void save_user_window_placement (MetaWindow *window) { if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED_OR_SNAPPED (window) || window->fullscreen)) { MetaRectangle user_rect; meta_window_get_client_root_coords (window, &user_rect); if (!window->maximized_horizontally) { window->user_rect.x = user_rect.x; window->user_rect.width = user_rect.width; } if (!window->maximized_vertically) { window->user_rect.y = user_rect.y; window->user_rect.height = user_rect.height; } } } LOCAL_SYMBOL void meta_window_maximize_internal (MetaWindow *window, MetaMaximizeFlags directions, MetaRectangle *saved_rect) { /* At least one of the two directions ought to be set */ gboolean maximize_horizontally, maximize_vertically; maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL; maximize_vertically = directions & META_MAXIMIZE_VERTICAL; g_assert (maximize_horizontally || maximize_vertically); meta_topic (META_DEBUG_WINDOW_OPS, "Maximizing %s%s\n", window->desc, maximize_horizontally && maximize_vertically ? "" : maximize_horizontally ? " horizontally" : maximize_vertically ? " vertically" : "BUGGGGG"); if (saved_rect != NULL) window->saved_rect = *saved_rect; else meta_window_save_rect (window); meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE); window->tile_mode = META_TILE_NONE; normalize_tile_state (window); window->maximized_horizontally = window->maximized_horizontally || maximize_horizontally; window->maximized_vertically = window->maximized_vertically || maximize_vertically; if (maximize_horizontally || maximize_vertically) window->force_save_user_rect = FALSE; if (window->maximized_horizontally && window->maximized_vertically) { window->saved_maximize = TRUE; } /* Update the edge constraints */ update_edge_constraints (window);; recalc_window_features (window); set_net_wm_state (window); if (window->monitor->in_fullscreen) meta_screen_queue_check_fullscreen (window->screen); g_object_freeze_notify (G_OBJECT (window)); g_object_notify (G_OBJECT (window), "maximized-horizontally"); g_object_notify (G_OBJECT (window), "maximized-vertically"); g_object_thaw_notify (G_OBJECT (window)); } void meta_window_maximize (MetaWindow *window, MetaMaximizeFlags directions) { MetaRectangle *saved_rect = NULL; gboolean maximize_horizontally, maximize_vertically; g_return_if_fail (!window->override_redirect); /* At least one of the two directions ought to be set */ maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL; maximize_vertically = directions & META_MAXIMIZE_VERTICAL; g_assert (maximize_horizontally || maximize_vertically); /* Only do something if the window isn't already maximized in the * given direction(s). */ if ((maximize_horizontally && !window->maximized_horizontally) || (maximize_vertically && !window->maximized_vertically)) { if (window->shaded && maximize_vertically) { /* Shading sucks anyway; I'm not adding a timestamp argument * to this function just for this niche usage & corner case. */ guint32 timestamp = meta_display_get_current_time_roundtrip (window->display); meta_window_unshade (window, timestamp); } /* if the window hasn't been placed yet, we'll maximize it then */ if (!window->placed) { window->maximize_horizontally_after_placement = window->maximize_horizontally_after_placement || maximize_horizontally; window->maximize_vertically_after_placement = window->maximize_vertically_after_placement || maximize_vertically; return; } if ((window->tile_mode != META_TILE_NONE || window->last_tile_mode != META_TILE_NONE) && window->tile_mode != META_TILE_MAXIMIZE) { saved_rect = &window->saved_rect; window->maximized_vertically = FALSE; } meta_window_maximize_internal (window, directions, saved_rect); MetaRectangle old_rect; MetaRectangle new_rect; gboolean desktop_effects = meta_prefs_get_desktop_effects (); if (desktop_effects) meta_window_get_outer_rect (window, &old_rect); meta_window_move_resize_now (window); if (desktop_effects) { meta_window_get_outer_rect (window, &new_rect); meta_compositor_maximize_window (window->display->compositor, window, &old_rect, &new_rect); } } meta_screen_tile_preview_hide (window->screen); normalize_tile_state (window); } /** * meta_window_get_maximized: * * Gets the current maximization state of the window, as combination * of the %META_MAXIMIZE_HORIZONTAL and %META_MAXIMIZE_VERTICAL flags; * * Return value: current maximization state */ MetaMaximizeFlags meta_window_get_maximized (MetaWindow *window) { return ((window->maximized_horizontally ? META_MAXIMIZE_HORIZONTAL : 0) | (window->maximized_vertically ? META_MAXIMIZE_VERTICAL : 0)); } /** * meta_window_is_fullscreen: * * Return value: %TRUE if the window is currently fullscreen */ gboolean meta_window_is_fullscreen (MetaWindow *window) { return window->fullscreen; } /** * meta_window_get_all_monitors: * @window: The #MetaWindow * @length: (out caller-allocates): gint holding the length, may be %NULL to * ignore * * Returns: (array length=length) (element-type gint) (transfer container): * List of the monitor indices the window is on. */ gint * meta_window_get_all_monitors (MetaWindow *window, gsize *length) { GArray *monitors; MetaRectangle window_rect; int i; monitors = g_array_new (FALSE, FALSE, sizeof (int)); if (meta_window_is_client_decorated (window)) { window_rect = window->rect; } else { meta_window_get_outer_rect (window, &window_rect); } for (i = 0; i < window->screen->n_monitor_infos; i++) { MetaRectangle *monitor_rect = &window->screen->monitor_infos[i].rect; if (window->fullscreen) { if (meta_rectangle_contains_rect (&window_rect, monitor_rect)) { g_array_append_val (monitors, i); } } else { if (meta_rectangle_overlap (&window_rect, monitor_rect)) { g_array_append_val (monitors, i); } } } if (length) *length = monitors->len; i = -1; g_array_append_val (monitors, i); return (gint*) g_array_free (monitors, FALSE); } /** * meta_window_is_monitor_sized: * * Return value: %TRUE if the window is occupies an entire monitor or * the whole screen. */ gboolean meta_window_is_monitor_sized (MetaWindow *window) { if (window->fullscreen) return TRUE; if (window->override_redirect) { MetaRectangle window_rect, monitor_rect; int screen_width, screen_height; meta_screen_get_size (window->screen, &screen_width, &screen_height); meta_window_get_outer_rect (window, &window_rect); if (window_rect.x == 0 && window_rect.y == 0 && window_rect.width == screen_width && window_rect.height == screen_height) return TRUE; meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect); if (meta_rectangle_equal (&window_rect, &monitor_rect)) return TRUE; } return FALSE; } /** * meta_window_is_on_primary_monitor: * * Return value: %TRUE if the window is on the primary monitor */ gboolean meta_window_is_on_primary_monitor (MetaWindow *window) { return window->monitor->is_primary; } /** * meta_window_requested_bypass_compositor: * * Return value: %TRUE if the window requested to bypass the compositor */ gboolean meta_window_requested_bypass_compositor (MetaWindow *window) { return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_ON; } /** * meta_window_requested_dont_bypass_compositor: * * Return value: %TRUE if the window requested to opt out of unredirecting */ gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window) { return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF; } static void normalize_tile_state (MetaWindow *window) { window->snap_queued = FALSE; window->resize_tile_mode = META_TILE_NONE; window->resizing_tile_type = META_WINDOW_TILE_TYPE_NONE; meta_screen_update_snapped_windows (window->screen); } LOCAL_SYMBOL void meta_window_real_tile (MetaWindow *window, gboolean force) { /* Don't do anything if no tiling is requested or we're already tiled */ if (window->tile_mode == META_TILE_NONE || (META_WINDOW_TILED_OR_SNAPPED (window) && !force)) return; if (window->last_tile_mode == META_TILE_NONE && window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE && !META_WINDOW_MAXIMIZED (window)) { meta_window_save_rect (window); } window->maximized_horizontally = FALSE; window->maximized_vertically = FALSE; if (window->tile_mode != META_TILE_NONE) { if (window->snap_queued || window->resizing_tile_type == META_WINDOW_TILE_TYPE_SNAPPED) { meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_SNAPPED); } else { meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_TILED); } } else { meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE); } recalc_window_features (window); meta_screen_tile_preview_update (window->screen, FALSE); if (window->resize_tile_mode == META_TILE_NONE) { MetaRectangle old_rect; MetaRectangle new_rect; gboolean desktop_effects = meta_prefs_get_desktop_effects (); if (desktop_effects) meta_window_get_input_rect (window, &old_rect); meta_window_move_resize_now (window); if (desktop_effects) { meta_window_get_input_rect (window, &new_rect); meta_compositor_tile_window (window->display->compositor, window, &old_rect, &new_rect); } if (window->frame) meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow); } else { /* move_resize with new tiling constraints */ meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } normalize_tile_state (window); set_net_wm_state (window); meta_screen_tile_preview_hide (window->screen); meta_window_get_outer_rect (window, &window->snapped_rect); } static gboolean meta_window_can_tile_maximized (MetaWindow *window) { return window->has_maximize_func; } LOCAL_SYMBOL gboolean meta_window_can_tile_side_by_side (MetaWindow *window) { int monitor; MetaRectangle tile_area; MetaFrameBorders borders; if (!meta_window_can_tile_maximized (window)) return FALSE; monitor = meta_screen_get_current_monitor (window->screen); meta_window_get_work_area_for_monitor (window, monitor, &tile_area); tile_area.width /= 2; meta_frame_calc_borders (window->frame, &borders); meta_window_unextend_by_frame (window, &tile_area, &borders); return tile_area.width >= window->size_hints.min_width && tile_area.height >= window->size_hints.min_height; } LOCAL_SYMBOL gboolean meta_window_can_tile_top_bottom (MetaWindow *window) { int monitor; MetaRectangle tile_area; MetaFrameBorders borders; if (!meta_window_can_tile_maximized (window)) return FALSE; monitor = meta_screen_get_current_monitor (window->screen); meta_window_get_work_area_for_monitor (window, monitor, &tile_area); tile_area.height /= 2; meta_frame_calc_borders (window->frame, &borders); meta_window_unextend_by_frame (window, &tile_area, &borders); return tile_area.width >= window->size_hints.min_width && tile_area.height >= window->size_hints.min_height; } LOCAL_SYMBOL gboolean meta_window_can_tile_corner (MetaWindow *window) { int monitor; MetaRectangle tile_area; MetaFrameBorders borders; if (!meta_window_can_tile_maximized (window)) return FALSE; monitor = meta_screen_get_current_monitor (window->screen); meta_window_get_work_area_for_monitor (window, monitor, &tile_area); tile_area.width /= 2; tile_area.height /= 2; meta_frame_calc_borders (window->frame, &borders); meta_window_unextend_by_frame (window, &tile_area, &borders); return tile_area.width >= window->size_hints.min_width && tile_area.height >= window->size_hints.min_height; } static void unmaximize_window_before_freeing (MetaWindow *window) { meta_topic (META_DEBUG_WINDOW_OPS, "Unmaximizing %s just before freeing\n", window->desc); window->maximized_horizontally = FALSE; window->maximized_vertically = FALSE; window->custom_snap_size = FALSE; if (window->tile_type != META_WINDOW_TILE_TYPE_NONE) { meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE); meta_screen_update_snapped_windows (window->screen); } if (window->withdrawn) /* See bug #137185 */ { window->rect = window->saved_rect; set_net_wm_state (window); } else if (window->screen->closing) /* See bug #358042 */ { /* Do NOT update net_wm_state: this screen is closing, * it likely will be managed by another window manager * that will need the current _NET_WM_STATE atoms. * Moreover, it will need to know the unmaximized geometry, * therefore move_resize the window to saved_rect here * before closing it. */ meta_window_move_resize (window, FALSE, window->saved_rect.x, window->saved_rect.y, window->saved_rect.width, window->saved_rect.height); } } static void meta_window_unmaximize_internal (MetaWindow *window, MetaMaximizeFlags directions, MetaRectangle *desired_rect, int gravity) { gboolean unmaximize_horizontally, unmaximize_vertically; g_return_if_fail (!window->override_redirect); /* At least one of the two directions ought to be set */ unmaximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL; unmaximize_vertically = directions & META_MAXIMIZE_VERTICAL; if (unmaximize_horizontally && unmaximize_vertically) window->saved_maximize = FALSE; /* Only do something if the window is tiled, or maximized in the * given direction(s). */ if ((unmaximize_horizontally && window->maximized_horizontally) || (unmaximize_vertically && window->maximized_vertically) || window->tile_type != META_WINDOW_TILE_TYPE_NONE || window->tile_mode != META_TILE_NONE) { MetaRectangle target_rect; MetaRectangle work_area; window->last_tile_mode = META_TILE_NONE; window->tile_mode = META_TILE_NONE; window->resizing_tile_type = META_WINDOW_TILE_TYPE_NONE; meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE); meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area); meta_topic (META_DEBUG_WINDOW_OPS, "Unmaximizing %s%s\n", window->desc, unmaximize_horizontally && unmaximize_vertically ? "" : unmaximize_horizontally ? " horizontally" : unmaximize_vertically ? " vertically" : "BUGGGGG"); window->maximized_horizontally = window->maximized_horizontally && !unmaximize_horizontally; window->maximized_vertically = window->maximized_vertically && !unmaximize_vertically; /* Update the edge constraints */ update_edge_constraints (window); /* recalc_features() will eventually clear the cached frame * extents, but we need the correct frame extents in the code below, * so invalidate the old frame extents manually up front. */ meta_window_frame_size_changed (window); /* Unmaximize to the saved_rect position in the direction(s) * being unmaximized. */ meta_window_get_client_root_coords (window, &target_rect); if (unmaximize_horizontally) { target_rect.x = desired_rect->x; target_rect.width = desired_rect->width; } if (unmaximize_vertically) { target_rect.y = desired_rect->y; target_rect.height = desired_rect->height; } /* Window's size hints may have changed while maximized, making * saved_rect invalid. #329152 */ ensure_size_hints_satisfied (&target_rect, &window->size_hints); if (window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE) { MetaRectangle old_rect, new_rect; gboolean desktop_effects = meta_prefs_get_desktop_effects (); if (desktop_effects) meta_window_get_outer_rect (window, &old_rect); meta_window_move_resize_internal (window, META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, gravity, target_rect.x, target_rect.y, target_rect.width, target_rect.height); if (desktop_effects) { meta_window_get_outer_rect (window, &new_rect); meta_compositor_unmaximize_window (window->display->compositor, window, &old_rect, &new_rect); } } else { meta_window_move_resize_internal (window, META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, gravity, target_rect.x, target_rect.y, target_rect.width, target_rect.height); } /* Make sure user_rect is current. */ force_save_user_window_placement (window); /* When we unmaximize, if we're doing a mouse move also we could * get the window suddenly jumping to the upper left corner of * the workspace, since that's where it was when the grab op * started. So we need to update the grab state. We have to do * it after the actual operation, as the window may have been moved * by constraints. */ if (meta_grab_op_is_moving (window->display->grab_op) && window->display->grab_window == window) { window->display->grab_anchor_window_pos = window->user_rect; } if (window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE) window->custom_snap_size = FALSE; meta_screen_update_snapped_windows (window->screen); recalc_window_features (window); set_net_wm_state (window); if (!window->monitor->in_fullscreen) meta_screen_queue_check_fullscreen (window->screen); } g_object_freeze_notify (G_OBJECT (window)); g_object_notify (G_OBJECT (window), "maximized-horizontally"); g_object_notify (G_OBJECT (window), "maximized-vertically"); g_object_thaw_notify (G_OBJECT (window)); } void meta_window_unmaximize (MetaWindow *window, MetaMaximizeFlags directions) { meta_window_unmaximize_internal (window, directions, &window->saved_rect, NorthWestGravity); } /* Like meta_window_unmaximize(), but instead of unmaximizing to the * saved position, we give the new desired size, and the gravity that * determines the positioning relationship between the area occupied * maximized and the new are. The arguments are similar to * meta_window_resize_with_gravity(). * Unlike meta_window_unmaximize(), tiling is not restored for windows * with a tile mode other than META_TILE_NONE. */ LOCAL_SYMBOL void meta_window_unmaximize_with_gravity (MetaWindow *window, MetaMaximizeFlags directions, int new_width, int new_height, int gravity) { MetaRectangle desired_rect; meta_window_get_position (window, &desired_rect.x, &desired_rect.y); desired_rect.width = new_width; desired_rect.height = new_height; meta_window_unmaximize_internal (window, directions, &desired_rect, gravity); } LOCAL_SYMBOL void meta_window_make_above (MetaWindow *window) { g_return_if_fail (!window->override_redirect); meta_window_set_above (window, TRUE); meta_window_raise (window); } LOCAL_SYMBOL void meta_window_unmake_above (MetaWindow *window) { g_return_if_fail (!window->override_redirect); meta_window_set_above (window, FALSE); meta_window_raise (window); } static void meta_window_set_above (MetaWindow *window, gboolean new_value) { new_value = new_value != FALSE; if (new_value == window->wm_state_above) return; window->wm_state_above = new_value; meta_window_update_layer (window); set_net_wm_state (window); meta_window_frame_size_changed (window); g_object_notify (G_OBJECT (window), "above"); } LOCAL_SYMBOL LOCAL_SYMBOL void meta_window_make_fullscreen_internal (MetaWindow *window) { if (!window->fullscreen) { meta_topic (META_DEBUG_WINDOW_OPS, "Fullscreening %s\n", window->desc); if (window->shaded) { /* Shading sucks anyway; I'm not adding a timestamp argument * to this function just for this niche usage & corner case. */ guint32 timestamp = meta_display_get_current_time_roundtrip (window->display); meta_window_unshade (window, timestamp); } meta_window_save_rect (window); window->fullscreen = TRUE; window->force_save_user_rect = FALSE; meta_stack_freeze (window->screen->stack); meta_window_raise (window); meta_stack_thaw (window->screen->stack); recalc_window_features (window); set_net_wm_state (window); /* For the auto-minimize feature, if we fail to get focus */ meta_screen_queue_check_fullscreen (window->screen); meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); g_object_notify (G_OBJECT (window), "fullscreen"); } } LOCAL_SYMBOL void meta_window_make_fullscreen (MetaWindow *window) { g_return_if_fail (!window->override_redirect); if (!window->fullscreen) { meta_window_make_fullscreen_internal (window); /* move_resize with new constraints */ meta_window_queue(window, META_QUEUE_MOVE_RESIZE); } } LOCAL_SYMBOL void meta_window_unmake_fullscreen (MetaWindow *window) { g_return_if_fail (!window->override_redirect); if (window->fullscreen) { MetaRectangle target_rect; meta_topic (META_DEBUG_WINDOW_OPS, "Unfullscreening %s\n", window->desc); window->fullscreen = FALSE; target_rect = window->saved_rect; /* Window's size hints may have changed while maximized, making * saved_rect invalid. #329152 */ ensure_size_hints_satisfied (&target_rect, &window->size_hints); /* Need to update window->has_resize_func before we move_resize() */ recalc_window_features (window); set_net_wm_state (window); meta_window_move_resize (window, FALSE, target_rect.x, target_rect.y, target_rect.width, target_rect.height); /* Make sure user_rect is current. */ force_save_user_window_placement (window); meta_screen_queue_check_fullscreen (window->screen); meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); g_object_notify (G_OBJECT (window), "fullscreen"); } } LOCAL_SYMBOL void meta_window_update_fullscreen_monitors (MetaWindow *window, unsigned long top, unsigned long bottom, unsigned long left, unsigned long right) { if ((int)top < window->screen->n_monitor_infos && (int)bottom < window->screen->n_monitor_infos && (int)left < window->screen->n_monitor_infos && (int)right < window->screen->n_monitor_infos) { window->fullscreen_monitors[0] = top; window->fullscreen_monitors[1] = bottom; window->fullscreen_monitors[2] = left; window->fullscreen_monitors[3] = right; } else { window->fullscreen_monitors[0] = -1; } if (window->fullscreen) { meta_window_queue(window, META_QUEUE_MOVE_RESIZE); } } LOCAL_SYMBOL void meta_window_shade (MetaWindow *window, guint32 timestamp) { g_return_if_fail (!window->override_redirect); meta_topic (META_DEBUG_WINDOW_OPS, "Shading %s\n", window->desc); if (!window->shaded) { window->shaded = TRUE; meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING); meta_window_frame_size_changed (window); /* After queuing the calc showing, since _focus flushes it, * and we need to focus the frame */ meta_topic (META_DEBUG_FOCUS, "Re-focusing window %s after shading it\n", window->desc); meta_window_focus (window, timestamp); set_net_wm_state (window); } } LOCAL_SYMBOL void meta_window_unshade (MetaWindow *window, guint32 timestamp) { g_return_if_fail (!window->override_redirect); meta_topic (META_DEBUG_WINDOW_OPS, "Unshading %s\n", window->desc); if (window->shaded) { window->shaded = FALSE; meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING); meta_window_frame_size_changed (window); /* focus the window */ meta_topic (META_DEBUG_FOCUS, "Focusing window %s after unshading it\n", window->desc); meta_window_focus (window, timestamp); set_net_wm_state (window); } } #define OPACITY_STEP 32 LOCAL_SYMBOL void meta_window_adjust_opacity (MetaWindow *window, gboolean increase) { ClutterActor *actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window)); gint current_opacity, new_opacity; current_opacity = clutter_actor_get_opacity (actor); if (increase) { new_opacity = MIN (current_opacity + OPACITY_STEP, 255); } else { new_opacity = MAX (current_opacity - OPACITY_STEP, MAX (0, meta_prefs_get_min_win_opacity ())); } if (new_opacity != current_opacity) { clutter_actor_set_opacity (actor, (guint8) new_opacity); } } void meta_window_reset_opacity (MetaWindow *window) { ClutterActor *actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window)); clutter_actor_set_opacity (actor, 255); } static gboolean unminimize_func (MetaWindow *window, void *data) { meta_window_unminimize (window); return TRUE; } static void unminimize_window_and_all_transient_parents (MetaWindow *window) { meta_window_unminimize (window); meta_window_foreach_ancestor (window, unminimize_func, NULL); } static void window_activate (MetaWindow *window, guint32 timestamp, MetaClientType source_indication, MetaWorkspace *workspace) { gboolean can_ignore_outdated_timestamps; meta_topic (META_DEBUG_FOCUS, "_NET_ACTIVE_WINDOW message sent for %s at time %u " "by client type %u.\n", window->desc, timestamp, source_indication); /* Older EWMH spec didn't specify a timestamp; we decide to honor these only * if the app specifies that it is a pager. * * Update: Unconditionally honor 0 timestamps for now; we'll fight * that battle later. Just remove the "FALSE &&" in order to only * honor 0 timestamps for pagers. */ can_ignore_outdated_timestamps = (timestamp != 0 || (FALSE && source_indication != META_CLIENT_TYPE_PAGER)); if (XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time) && can_ignore_outdated_timestamps) { meta_topic (META_DEBUG_FOCUS, "last_user_time (%u) is more recent; ignoring " " _NET_ACTIVE_WINDOW message.\n", window->display->last_user_time); meta_window_set_demands_attention(window); return; } /* For those stupid pagers, get a valid timestamp and show a warning */ if (timestamp == 0) { meta_topic (META_DEBUG_FOCUS, "meta_window_activate called by a pager with a 0 timestamp; " "the pager needs to be fixed.\n"); timestamp = meta_display_get_current_time_roundtrip (window->display); } meta_window_set_user_time (window, timestamp); /* disable show desktop mode unless we're a desktop component */ maybe_leave_show_desktop_mode (window); /* Get window on current or given workspace */ if (workspace == NULL) workspace = window->screen->active_workspace; /* For non-transient windows, we just set up a pulsing indicator, rather than move windows or workspaces. See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */ if (window->xtransient_for == None) { if (!meta_window_located_on_workspace (window, workspace)) { if (meta_prefs_get_bring_windows_to_current_workspace ()) { meta_window_change_workspace (window, workspace); } else { meta_workspace_activate (window->workspace, timestamp); } } } else if (window->xtransient_for != None) { /* Move transients to current workspace - preference dialogs should appear over the source window. */ meta_window_change_workspace (window, workspace); } if (window->shaded) meta_window_unshade (window, timestamp); unminimize_window_and_all_transient_parents (window); if (meta_prefs_get_raise_on_click () || source_indication == META_CLIENT_TYPE_PAGER) meta_window_raise (window); meta_topic (META_DEBUG_FOCUS, "Focusing window %s due to activation\n", window->desc); meta_window_focus (window, timestamp); } /* This function exists since most of the functionality in window_activate * is useful for Muffin, but Muffin shouldn't need to specify a client * type for itself. ;-) */ void meta_window_activate (MetaWindow *window, guint32 timestamp) { g_return_if_fail (!window->override_redirect); /* We're not really a pager, but the behavior we want is the same as if * we were such. If we change the pager behavior later, we could revisit * this and just add extra flags to window_activate. */ window_activate (window, timestamp, META_CLIENT_TYPE_PAGER, NULL); } void meta_window_activate_with_workspace (MetaWindow *window, guint32 timestamp, MetaWorkspace *workspace) { g_return_if_fail (!window->override_redirect); /* We're not really a pager, but the behavior we want is the same as if * we were such. If we change the pager behavior later, we could revisit * this and just add extra flags to window_activate. */ window_activate (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace); } /* Manually fix all the weirdness explained in the big comment at the * beginning of meta_window_move_resize_internal() giving positions * expected by meta_window_constrain (i.e. positions & sizes of the * internal or client window). */ static void adjust_for_gravity (MetaWindow *window, MetaFrameBorders *borders, gboolean coords_assume_border, int gravity, MetaRectangle *rect) { int ref_x, ref_y; int bw; int child_x, child_y; int frame_width, frame_height; if (coords_assume_border) bw = window->border_width; else bw = 0; if (borders) { child_x = borders->visible.left; child_y = borders->visible.top; frame_width = child_x + rect->width + borders->visible.right; frame_height = child_y + rect->height + borders->visible.bottom; } else { child_x = 0; child_y = 0; frame_width = rect->width; frame_height = rect->height; } /* We're computing position to pass to window_move, which is * the position of the client window (StaticGravity basically) * * (see WM spec description of gravity computation, but note that * their formulas assume we're honoring the border width, rather * than compensating for having turned it off) */ switch (gravity) { case NorthWestGravity: ref_x = rect->x; ref_y = rect->y; break; case NorthGravity: ref_x = rect->x + rect->width / 2 + bw; ref_y = rect->y; break; case NorthEastGravity: ref_x = rect->x + rect->width + bw * 2; ref_y = rect->y; break; case WestGravity: ref_x = rect->x; ref_y = rect->y + rect->height / 2 + bw; break; case CenterGravity: ref_x = rect->x + rect->width / 2 + bw; ref_y = rect->y + rect->height / 2 + bw; break; case EastGravity: ref_x = rect->x + rect->width + bw * 2; ref_y = rect->y + rect->height / 2 + bw; break; case SouthWestGravity: ref_x = rect->x; ref_y = rect->y + rect->height + bw * 2; break; case SouthGravity: ref_x = rect->x + rect->width / 2 + bw; ref_y = rect->y + rect->height + bw * 2; break; case SouthEastGravity: ref_x = rect->x + rect->width + bw * 2; ref_y = rect->y + rect->height + bw * 2; break; case StaticGravity: default: ref_x = rect->x; ref_y = rect->y; break; } switch (gravity) { case NorthWestGravity: rect->x = ref_x + child_x; rect->y = ref_y + child_y; break; case NorthGravity: rect->x = ref_x - frame_width / 2 + child_x; rect->y = ref_y + child_y; break; case NorthEastGravity: rect->x = ref_x - frame_width + child_x; rect->y = ref_y + child_y; break; case WestGravity: rect->x = ref_x + child_x; rect->y = ref_y - frame_height / 2 + child_y; break; case CenterGravity: rect->x = ref_x - frame_width / 2 + child_x; rect->y = ref_y - frame_height / 2 + child_y; break; case EastGravity: rect->x = ref_x - frame_width + child_x; rect->y = ref_y - frame_height / 2 + child_y; break; case SouthWestGravity: rect->x = ref_x + child_x; rect->y = ref_y - frame_height + child_y; break; case SouthGravity: rect->x = ref_x - frame_width / 2 + child_x; rect->y = ref_y - frame_height + child_y; break; case SouthEastGravity: rect->x = ref_x - frame_width + child_x; rect->y = ref_y - frame_height + child_y; break; case StaticGravity: default: rect->x = ref_x; rect->y = ref_y; break; } } static gboolean static_gravity_works (MetaDisplay *display) { return display->static_gravity_works; } void meta_window_create_sync_request_alarm (MetaWindow *window) { #ifdef HAVE_XSYNC XSyncAlarmAttributes values; XSyncValue init; if (window->sync_request_counter == None || window->sync_request_alarm != None) return; meta_error_trap_push_with_return (window->display); /* In the new (extended style), the counter value is initialized by * the client before mapping the window. In the old style, we're * responsible for setting the initial value of the counter. */ if (window->extended_sync_request_counter) { if (!XSyncQueryCounter(window->display->xdisplay, window->sync_request_counter, &init)) { meta_error_trap_pop_with_return (window->display); window->sync_request_counter = None; return; } window->sync_request_serial = XSyncValueLow32 (init) + ((gint64)XSyncValueHigh32 (init) << 32); /* if the value is odd, the window starts off with updates frozen */ meta_compositor_set_updates_frozen (window->display->compositor, window, meta_window_updates_are_frozen (window)); } else { XSyncIntToValue (&init, 0); XSyncSetCounter (window->display->xdisplay, window->sync_request_counter, init); window->sync_request_serial = 0; } values.trigger.counter = window->sync_request_counter; values.trigger.test_type = XSyncPositiveComparison; /* Initialize to one greater than the current value */ values.trigger.value_type = XSyncRelative; XSyncIntToValue (&values.trigger.wait_value, 1); /* After triggering, increment test_value by this until * until the test condition is false */ XSyncIntToValue (&values.delta, 1); /* we want events (on by default anyway) */ values.events = True; window->sync_request_alarm = XSyncCreateAlarm (window->display->xdisplay, XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType | XSyncCADelta | XSyncCAEvents, &values); if (meta_error_trap_pop_with_return (window->display) == Success) meta_display_register_sync_alarm (window->display, &window->sync_request_alarm, window); else { window->sync_request_alarm = None; window->sync_request_counter = None; } #endif } void meta_window_destroy_sync_request_alarm (MetaWindow *window) { #ifdef HAVE_XSYNC if (window->sync_request_alarm != None) { /* Has to be unregistered _before_ clearing the structure field */ meta_display_unregister_sync_alarm (window->display, window->sync_request_alarm); XSyncDestroyAlarm (window->display->xdisplay, window->sync_request_alarm); window->sync_request_alarm = None; } #endif /* HAVE_XSYNC */ } #ifdef HAVE_XSYNC static gboolean sync_request_timeout (gpointer data) { MetaWindow *window = data; window->sync_request_timeout_id = 0; /* We have now waited for more than a second for the * application to respond to the sync request */ window->disable_sync = TRUE; /* Reset the wait serial, so we don't continue freezing * window updates */ window->sync_request_wait_serial = 0; meta_compositor_set_updates_frozen (window->display->compositor, window, meta_window_updates_are_frozen (window)); if (window == window->display->grab_window && meta_grab_op_is_resizing (window->display->grab_op)) { update_resize (window, window->display->grab_last_user_action_was_snap, window->display->grab_latest_motion_x, window->display->grab_latest_motion_y, TRUE); } return FALSE; } static void send_sync_request (MetaWindow *window) { XClientMessageEvent ev; gint64 wait_serial; /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to * increase the value, but for the new "extended" style we need to * pick an even (unfrozen) value sufficiently ahead of the last serial * that we received from the client; the same code still works * for the old style. The increment of 240 is specified by the EWMH * and is (1 second) * (60fps) * (an increment of 4 per frame). */ wait_serial = window->sync_request_serial + 240; window->sync_request_wait_serial = wait_serial; ev.type = ClientMessage; ev.window = window->xwindow; ev.message_type = window->display->atom_WM_PROTOCOLS; ev.format = 32; ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST; ev.data.l[1] = window->display->current_time; ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff); ev.data.l[3] = wait_serial >> 32; ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0; /* We don't need to trap errors here as we are already * inside an error_trap_push()/pop() pair. */ XSendEvent (window->display->xdisplay, window->xwindow, False, 0, (XEvent*) &ev); /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST; * if this time expires, we consider the window unresponsive * and resize it unsynchonized. */ window->sync_request_timeout_id = g_timeout_add (1000, sync_request_timeout, window); meta_compositor_set_updates_frozen (window->display->compositor, window, meta_window_updates_are_frozen (window)); } #endif /** * meta_window_updates_are_frozen: * @window: a #MetaWindow * * Gets whether the compositor should be updating the window contents; * window content updates may be frozen at client request by setting * an odd value in the extended _NET_WM_SYNC_REQUEST_COUNTER counter r * by the window manager during a resize operation while waiting for * the client to redraw. * * Return value: %TRUE if updates are currently frozen */ gboolean meta_window_updates_are_frozen (MetaWindow *window) { #ifdef HAVE_XSYNC if (window->extended_sync_request_counter && window->sync_request_serial % 2 == 1) return TRUE; if (window->sync_request_serial < window->sync_request_wait_serial) return TRUE; #endif return FALSE; } static gboolean maybe_move_attached_dialog (MetaWindow *window, void *data) { if (meta_window_is_attached_dialog (window)) /* It ignores x,y for such a dialog */ meta_window_move (window, FALSE, 0, 0); return FALSE; } /** * meta_window_get_monitor: * @window: a #MetaWindow * * Gets index of the monitor that this window is on. * * Return Value: The index of the monitor in the screens monitor list */ int meta_window_get_monitor (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), -1); if (window->monitor == NULL) return -1; return window->monitor->number; } /* This is called when the monitor setup has changed. The window->monitor * reference is still "valid", but refer to the previous monitor setup */ LOCAL_SYMBOL void meta_window_update_for_monitors_changed (MetaWindow *window) { const MetaMonitorInfo *old, *new; int i; if (window->override_redirect) { meta_window_update_monitor (window); return; } old = window->monitor; /* Start on primary */ new = &window->screen->monitor_infos[window->screen->primary_monitor_index]; /* But, if we can find the old output on a new monitor, use that */ for (i = 0; i < window->screen->n_monitor_infos; i++) { MetaMonitorInfo *info = &window->screen->monitor_infos[i]; if (info->output == old->output) { new = info; break; } } if (window->tile_mode != META_TILE_NONE) window->tile_monitor_number = new->number; /* This will eventually reach meta_window_update_monitor that * will send leave/enter-monitor events. The old != new monitor * check will always fail (due to the new monitor_infos set) so * we will always send the events, even if the new and old monitor * index is the same. That is right, since the enumeration of the * monitors changed and the same index could be refereing * to a different monitor. */ meta_window_move_between_rects (window, &old->rect, &new->rect); } static void meta_window_update_monitor (MetaWindow *window) { const MetaMonitorInfo *old; old = window->monitor; window->monitor = meta_screen_get_monitor_for_window (window->screen, window); if (old != window->monitor) { meta_window_update_on_all_workspaces (window); /* If workspaces only on primary and we moved back to primary, ensure that the * window is now in that workspace. We do this because while the window is on a * non-primary monitor it is always visible, so it would be very jarring if it * disappeared when it crossed the monitor border. * The one time we want it to both change to the primary monitor and a non-active * workspace is when dropping the window on some other workspace thumbnail directly. * That should be handled by explicitly moving the window before changing the * workspace * Don't do this if old == NULL, because thats what happens when starting up, and * we don't want to move all windows around from a previous WM instance. Nor do * we want it when moving from one primary monitor to another (can happen during * screen reconfiguration. */ if (meta_prefs_get_workspaces_only_on_primary () && meta_window_is_on_primary_monitor (window) && old != NULL && !old->is_primary && window->screen->active_workspace != window->workspace) meta_window_change_workspace (window, window->screen->active_workspace); if (old) { meta_screen_queue_check_fullscreen (window->screen); g_signal_emit_by_name (window->screen, "window-left-monitor", old->number, window); } g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window); g_signal_emit_by_name (window->screen, "window-monitor-changed", window, window->monitor->number); /* If we're changing monitors, we need to update the has_maximize_func flag, * as the working area has changed. */ recalc_window_features (window); } } static void meta_window_move_resize_internal (MetaWindow *window, MetaMoveResizeFlags flags, int gravity, int root_x_nw, int root_y_nw, int w, int h) { /* meta_window_move_resize_internal gets called with very different * meanings for root_x_nw and root_y_nw. w & h are always the area * of the inner or client window (i.e. excluding the frame) and * gravity is the relevant gravity associated with the request (note * that gravity is ignored for move-only operations unless its * e.g. a configure request). The location is different for * different cases because of how this function gets called; note * that in all cases what we want to find out is the upper left * corner of the position of the inner window: * * Case | Called from (flags; gravity) * -----+----------------------------------------------- * 1 | A resize only ConfigureRequest * 1 | meta_window_resize * 1 | meta_window_resize_with_gravity * 2 | New window * 2 | Session restore * 2 | A not-resize-only ConfigureRequest/net_moveresize_window request * 3 | meta_window_move * 3 | meta_window_move_resize * * For each of the cases, root_x_nw and root_y_nw must be treated as follows: * * (1) They should be entirely ignored; instead the previous position * and size of the window should be resized according to the given * gravity in order to determine the new position of the window. * (2) Needs to be fixed up by adjust_for_gravity() as these * coordinates are relative to some corner or side of the outer * window (except for the case of StaticGravity) and we want to * know the location of the upper left corner of the inner window. * (3) These values are already the desired positon of the NW corner * of the inner window */ XWindowChanges values; unsigned int mask; gboolean need_configure_notify; MetaFrameBorders borders; gboolean need_move_client = FALSE; gboolean need_move_frame = FALSE; gboolean need_resize_client = FALSE; gboolean need_resize_frame = FALSE; int frame_size_dx; int frame_size_dy; int size_dx; int size_dy; gboolean frame_shape_changed = FALSE; gboolean is_configure_request; gboolean do_gravity_adjust; gboolean is_user_action; gboolean did_placement; gboolean configure_frame_first; gboolean use_static_gravity; /* used for the configure request, but may not be final * destination due to StaticGravity etc. */ int client_move_x; int client_move_y; MetaRectangle new_rect; MetaRectangle old_rect; if (window->type != META_WINDOW_TOOLTIP) { g_return_if_fail (!window->override_redirect); } is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0; do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0; is_user_action = (flags & META_IS_USER_ACTION) != 0; /* The action has to be a move or a resize or both... */ g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)); /* We don't need it in the idle queue anymore. */ meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE); meta_window_get_client_root_coords (window, &old_rect); meta_topic (META_DEBUG_GEOMETRY, "Move/resize %s to %d,%d %dx%d%s%s from %d,%d %dx%d\n", window->desc, root_x_nw, root_y_nw, w, h, is_configure_request ? " (configure request)" : "", is_user_action ? " (user move/resize)" : "", old_rect.x, old_rect.y, old_rect.width, old_rect.height); meta_frame_calc_borders (window->frame, &borders); new_rect.x = root_x_nw; new_rect.y = root_y_nw; new_rect.width = w; new_rect.height = h; /* If this is a resize only, the position should be ignored and * instead obtained by resizing the old rectangle according to the * relevant gravity. */ if ((flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)) == META_IS_RESIZE_ACTION) { meta_rectangle_resize_with_gravity (&old_rect, &new_rect, gravity, new_rect.width, new_rect.height); meta_topic (META_DEBUG_GEOMETRY, "Compensated for gravity in resize action; new pos %d,%d\n", new_rect.x, new_rect.y); } else if (is_configure_request || do_gravity_adjust) { adjust_for_gravity (window, window->frame ? &borders : NULL, /* configure request coords assume * the border width existed */ is_configure_request, gravity, &new_rect); meta_topic (META_DEBUG_GEOMETRY, "Compensated for configure_request/do_gravity_adjust needing " "weird positioning; new pos %d,%d\n", new_rect.x, new_rect.y); } did_placement = !window->placed && window->calc_placement; meta_window_constrain (window, window->frame ? &borders : NULL, flags, gravity, &old_rect, &new_rect); w = new_rect.width; h = new_rect.height; root_x_nw = new_rect.x; root_y_nw = new_rect.y; size_dx = w - window->rect.width; size_dy = h - window->rect.height; if (size_dx != 0 || size_dy != 0) need_resize_client = TRUE; window->rect.width = w; window->rect.height = h; if (window->frame) { int new_w, new_h; new_w = window->rect.width + borders.total.left + borders.total.right; if (window->shaded) new_h = borders.total.top; else new_h = window->rect.height + borders.total.top + borders.total.bottom; if (new_w != window->frame->rect.width || new_h != window->frame->rect.height) { need_resize_frame = TRUE; window->frame->rect.width = new_w; window->frame->rect.height = new_h; } meta_topic (META_DEBUG_GEOMETRY, "Calculated frame size %dx%d\n", window->frame->rect.width, window->frame->rect.height); } /* For nice effect, when growing the window we want to move/resize * the frame first, when shrinking the window we want to move/resize * the client first. If we grow one way and shrink the other, * see which way we're moving "more" * * Mail from Owen subject "Suggestion: Gravity and resizing from the left" * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html * * An annoying fact you need to know in this code is that StaticGravity * does nothing if you _only_ resize or _only_ move the frame; * it must move _and_ resize, otherwise you get NorthWestGravity * behavior. The move and resize must actually occur, it is not * enough to set CWX | CWWidth but pass in the current size/pos. */ if (window->frame) { int new_x, new_y; int frame_pos_dx, frame_pos_dy; /* Compute new frame coords */ new_x = root_x_nw - borders.total.left; new_y = root_y_nw - borders.total.top; frame_pos_dx = new_x - window->frame->rect.x; frame_pos_dy = new_y - window->frame->rect.y; need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0); window->frame->rect.x = new_x; window->frame->rect.y = new_y; /* If frame will both move and resize, then StaticGravity * on the child window will kick in and implicitly move * the child with respect to the frame. The implicit * move will keep the child in the same place with * respect to the root window. If frame only moves * or only resizes, then the child will just move along * with the frame. */ /* window->rect.x, window->rect.y are relative to frame, * remember they are the server coords */ new_x = borders.total.left; new_y = borders.total.top; if (need_resize_frame && need_move_frame && static_gravity_works (window->display)) { /* static gravity kicks in because frame * is both moved and resized */ /* when we move the frame by frame_pos_dx, frame_pos_dy the * client will implicitly move relative to frame by the * inverse delta. * * When moving client then frame, we move the client by the * frame delta, to be canceled out by the implicit move by * the inverse frame delta, resulting in a client at new_x, * new_y. * * When moving frame then client, we move the client * by the same delta as the frame, because the client * was "left behind" by the frame - resulting in a client * at new_x, new_y. * * In both cases we need to move the client window * in all cases where we had to move the frame window. */ client_move_x = new_x + frame_pos_dx; client_move_y = new_y + frame_pos_dy; if (need_move_frame) need_move_client = TRUE; use_static_gravity = TRUE; } else { client_move_x = new_x; client_move_y = new_y; if (client_move_x != window->rect.x || client_move_y != window->rect.y) need_move_client = TRUE; use_static_gravity = FALSE; } /* This is the final target position, but not necessarily what * we pass to XConfigureWindow, due to StaticGravity implicit * movement. */ window->rect.x = new_x; window->rect.y = new_y; } else { if (root_x_nw != window->rect.x || root_y_nw != window->rect.y) need_move_client = TRUE; window->rect.x = root_x_nw; window->rect.y = root_y_nw; client_move_x = window->rect.x; client_move_y = window->rect.y; use_static_gravity = FALSE; } /* If frame extents have changed, fill in other frame fields and change frame's extents property. */ if (window->frame && (window->frame->child_x != borders.total.left || window->frame->child_y != borders.total.top || window->frame->right_width != borders.total.right || window->frame->bottom_height != borders.total.bottom)) { window->frame->child_x = borders.total.left; window->frame->child_y = borders.total.top; window->frame->right_width = borders.total.right; window->frame->bottom_height = borders.total.bottom; update_net_frame_extents (window); } /* See ICCCM 4.1.5 for when to send ConfigureNotify */ need_configure_notify = FALSE; /* If this is a configure request and we change nothing, then we * must send configure notify. */ if (is_configure_request && !(need_move_client || need_move_frame || need_resize_client || need_resize_frame || window->border_width != 0)) need_configure_notify = TRUE; /* We must send configure notify if we move but don't resize, since * the client window may not get a real event */ if ((need_move_client || need_move_frame) && !(need_resize_client || need_resize_frame) && window->type != META_WINDOW_TOOLTIP) need_configure_notify = TRUE; /* MapRequest events with a PPosition or UPosition hint with a frame * are moved by muffin without resizing; send a configure notify * in such cases. See #322840. (Note that window->constructing is * only true iff this call is due to a MapRequest, and when * PPosition/UPosition hints aren't set, muffin seems to send a * ConfigureNotify anyway due to the above code.) */ if (window->constructing && window->frame && ((window->size_hints.flags & PPosition) || (window->size_hints.flags & USPosition))) need_configure_notify = TRUE; /* The rest of this function syncs our new size/pos with X as * efficiently as possible */ /* Normally, we configure the frame first depending on whether * we grow the frame more than we shrink. The idea is to avoid * messing up the window contents by having a temporary situation * where the frame is smaller than the window. However, if we're * cooperating with the client to create an atomic frame upate, * and the window is redirected, then we should always update * the frame first, since updating the frame will force a new * backing pixmap to be allocated, and the old backing pixmap * will be left undisturbed for us to paint to the screen until * the client finishes redrawing. */ if (window->extended_sync_request_counter) { configure_frame_first = TRUE; } else { size_dx = w - window->rect.width; size_dy = h - window->rect.height; configure_frame_first = size_dx + size_dy >= 0; } if (use_static_gravity) meta_window_set_gravity (window, StaticGravity); if (configure_frame_first && window->frame) frame_shape_changed = meta_frame_sync_to_window (window->frame, gravity, need_move_frame, need_resize_frame); values.border_width = 0; values.x = client_move_x; values.y = client_move_y; values.width = window->rect.width; values.height = window->rect.height; mask = 0; if (is_configure_request && window->border_width != 0) mask |= CWBorderWidth; /* must force to 0 */ if (need_move_client) mask |= (CWX | CWY); if (need_resize_client) mask |= (CWWidth | CWHeight); if (mask != 0) { meta_error_trap_push (window->display); #ifdef HAVE_XSYNC if (window == window->display->grab_window && meta_grab_op_is_resizing (window->display->grab_op) && !window->disable_sync && window->sync_request_counter != None && window->sync_request_alarm != None && window->sync_request_timeout_id == 0) { send_sync_request (window); } #endif XConfigureWindow (window->display->xdisplay, window->xwindow, mask, &values); meta_error_trap_pop (window->display); } if (!configure_frame_first && window->frame) frame_shape_changed = meta_frame_sync_to_window (window->frame, gravity, need_move_frame, need_resize_frame); /* Put gravity back to be nice to lesser window managers */ if (use_static_gravity) meta_window_set_gravity (window, NorthWestGravity); if (need_configure_notify) send_configure_notify (window); if (!window->placed && window->force_save_user_rect && !window->fullscreen) force_save_user_window_placement (window); else if (is_user_action) save_user_window_placement (window); if (need_move_frame || need_move_client) g_signal_emit (window, window_signals[POSITION_CHANGED], 0); if (need_resize_client) g_signal_emit (window, window_signals[SIZE_CHANGED], 0); if (need_move_frame || need_resize_frame || need_move_client || need_resize_client || did_placement) { int newx, newy; meta_window_get_position (window, &newx, &newy); meta_topic (META_DEBUG_GEOMETRY, "New size/position %d,%d %dx%d (user %d,%d %dx%d)\n", newx, newy, window->rect.width, window->rect.height, window->user_rect.x, window->user_rect.y, window->user_rect.width, window->user_rect.height); meta_compositor_sync_window_geometry (window->display->compositor, window, did_placement); } else { meta_topic (META_DEBUG_GEOMETRY, "Size/position not modified\n"); } meta_window_refresh_resize_popup (window); meta_window_update_monitor (window); /* Invariants leaving this function are: * a) window->rect and frame->rect reflect the actual * server-side size/pos of window->xwindow and frame->xwindow * b) all constraints are obeyed by window->rect and frame->rect */ if (frame_shape_changed && window->frame_bounds) { cairo_region_destroy (window->frame_bounds); window->frame_bounds = NULL; } meta_window_foreach_transient (window, maybe_move_attached_dialog, NULL); meta_stack_update_window_tile_matches (window->screen->stack, window->screen->active_workspace); } /** * meta_window_resize: * @window: a #MetaWindow * @user_op: bool to indicate whether or not this is a user operation * @w: desired width * @h: desired height * * Resize the window to the desired size. */ void meta_window_resize (MetaWindow *window, gboolean user_op, int w, int h) { int x, y; MetaMoveResizeFlags flags; g_return_if_fail (!window->override_redirect); meta_window_get_position (window, &x, &y); flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION; meta_window_move_resize_internal (window, flags, NorthWestGravity, x, y, w, h); } /** * meta_window_move: * @window: a #MetaWindow * @user_op: bool to indicate whether or not this is a user operation * @root_x_nw: desired x pos * @root_y_nw: desired y pos * * Moves the window to the desired location on window's assigned workspace. * NOTE: does NOT place according to the origin of the enclosing * frame/window-decoration, but according to the origin of the window, * itself. */ void meta_window_move (MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw) { MetaMoveResizeFlags flags; if (window->type != META_WINDOW_TOOLTIP) { g_return_if_fail (!window->override_redirect); } flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_MOVE_ACTION; meta_window_move_resize_internal (window, flags, NorthWestGravity, root_x_nw, root_y_nw, window->rect.width, window->rect.height); } /** * meta_window_move_frame: * @window: a #MetaWindow * @user_op: bool to indicate whether or not this is a user operation * @root_x_nw: desired x pos * @root_y_nw: desired y pos * * Moves the window to the desired location on window's assigned * workspace, using the northwest edge of the frame as the reference, * instead of the actual window's origin, but only if a frame is present. * Otherwise, acts identically to meta_window_move(). */ void meta_window_move_frame (MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw) { int x = root_x_nw; int y = root_y_nw; if (window->frame) { MetaFrameBorders borders; meta_frame_calc_borders (window->frame, &borders); /* root_x_nw and root_y_nw correspond to where the top of * the visible frame should be. Offset by the distance between * the origin of the window and the origin of the enclosing * window decorations. */ x += window->frame->child_x - borders.invisible.left; y += window->frame->child_y - borders.invisible.top; } meta_window_move (window, user_op, x, y); } static void meta_window_move_between_rects (MetaWindow *window, const MetaRectangle *old_area, const MetaRectangle *new_area) { int rel_x, rel_y; double scale_x, scale_y; rel_x = window->user_rect.x - old_area->x; rel_y = window->user_rect.y - old_area->y; scale_x = (double)new_area->width / old_area->width; scale_y = (double)new_area->height / old_area->height; window->user_rect.x = new_area->x + rel_x * scale_x; window->user_rect.y = new_area->y + rel_y * scale_y; window->saved_rect.x = window->user_rect.x; window->saved_rect.y = window->user_rect.y; meta_window_move_resize (window, FALSE, window->user_rect.x, window->user_rect.y, window->user_rect.width, window->user_rect.height); } /** * meta_window_move_resize_frame: * @window: a #MetaWindow * @user_op: bool to indicate whether or not this is a user operation * @root_x_nw: new x * @root_y_nw: new y * @w: desired width * @h: desired height * * Resizes the window so that its outer bounds (including frame) * fit within the given rect */ void meta_window_move_resize_frame (MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw, int w, int h) { MetaFrameBorders borders; meta_frame_calc_borders (window->frame, &borders); /* offset by the distance between the origin of the window * and the origin of the enclosing window decorations ( + border) */ root_x_nw += borders.visible.left; root_y_nw += borders.visible.top; w -= borders.visible.left + borders.visible.right; h -= borders.visible.top + borders.visible.bottom; meta_window_move_resize (window, user_op, root_x_nw, root_y_nw, w, h); } /** * meta_window_move_to_monitor: * @window: a #MetaWindow * @monitor: desired monitor index * * Moves the window to the monitor with index @monitor, keeping * the relative position of the window's top left corner. */ void meta_window_move_to_monitor (MetaWindow *window, int monitor) { MetaRectangle old_area, new_area; if (monitor == window->monitor->number) return; meta_window_get_work_area_for_monitor (window, window->monitor->number, &old_area); meta_window_get_work_area_for_monitor (window, monitor, &new_area); if (window->tile_mode != META_TILE_NONE) window->tile_monitor_number = monitor; meta_window_move_between_rects (window, &old_area, &new_area); } void meta_window_move_resize (MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw, int w, int h) { MetaMoveResizeFlags flags; g_return_if_fail (!window->override_redirect); flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION; meta_window_move_resize_internal (window, flags, NorthWestGravity, root_x_nw, root_y_nw, w, h); } LOCAL_SYMBOL void meta_window_resize_with_gravity (MetaWindow *window, gboolean user_op, int w, int h, int gravity) { int x, y; MetaMoveResizeFlags flags; meta_window_get_position (window, &x, &y); flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION; meta_window_move_resize_internal (window, flags, gravity, x, y, w, h); } static void meta_window_move_resize_now (MetaWindow *window) { /* If constraints have changed then we want to snap back to wherever * the user had the window. We use user_rect for this reason. See * also bug 426519 comment 3. */ meta_window_move_resize (window, FALSE, window->user_rect.x, window->user_rect.y, window->user_rect.width, window->user_rect.height); } static gboolean idle_move_resize (gpointer data) { GSList *tmp; GSList *copy; guint queue_index = GPOINTER_TO_INT (data); meta_topic (META_DEBUG_GEOMETRY, "Clearing the move_resize queue\n"); /* Work with a copy, for reentrancy. The allowed reentrancy isn't * complete; destroying a window while we're in here would result in * badness. But it's OK to queue/unqueue move_resizes. */ copy = g_slist_copy (queue_pending[queue_index]); g_slist_free (queue_pending[queue_index]); queue_pending[queue_index] = NULL; queue_later[queue_index] = 0; destroying_windows_disallowed += 1; tmp = copy; while (tmp != NULL) { MetaWindow *window; window = tmp->data; /* As a side effect, sets window->move_resize_queued = FALSE */ meta_window_move_resize_now (window); tmp = tmp->next; } g_slist_free (copy); destroying_windows_disallowed -= 1; return FALSE; } /** * meta_window_configure_notify: (skip) * @window: a #MetaWindow * @event: a #XConfigureEvent * * This is used to notify us of an unrequested configuration * (only applicable to override redirect windows) */ void meta_window_configure_notify (MetaWindow *window, XConfigureEvent *event) { g_assert (window->override_redirect); g_assert (window->frame == NULL); window->rect.x = event->x; window->rect.y = event->y; window->rect.width = event->width; window->rect.height = event->height; meta_window_update_monitor (window); /* Whether an override-redirect window is considered fullscreen depends * on its geometry. */ if (window->override_redirect) meta_screen_queue_check_fullscreen (window->screen); if (!event->override_redirect && !event->send_event) meta_warning ("Unhandled change of windows override redirect status\n"); meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE); } LOCAL_SYMBOL void meta_window_get_position (MetaWindow *window, int *x, int *y) { if (window->frame) { if (x) *x = window->frame->rect.x + window->frame->child_x; if (y) *y = window->frame->rect.y + window->frame->child_y; } else { if (x) *x = window->rect.x; if (y) *y = window->rect.y; } } LOCAL_SYMBOL void meta_window_get_client_root_coords (MetaWindow *window, MetaRectangle *rect) { meta_window_get_position (window, &rect->x, &rect->y); rect->width = window->rect.width; rect->height = window->rect.height; } LOCAL_SYMBOL void meta_window_get_gravity_position (MetaWindow *window, int gravity, int *root_x, int *root_y) { MetaRectangle frame_extents; int w, h; int x, y; w = window->rect.width; h = window->rect.height; if (gravity == StaticGravity) { frame_extents = window->rect; if (window->frame) { frame_extents.x = window->frame->rect.x + window->frame->child_x; frame_extents.y = window->frame->rect.y + window->frame->child_y; } } else { if (window->frame == NULL) frame_extents = window->rect; else frame_extents = window->frame->rect; } x = frame_extents.x; y = frame_extents.y; switch (gravity) { case NorthGravity: case CenterGravity: case SouthGravity: /* Find center of frame. */ x += frame_extents.width / 2; /* Center client window on that point. */ x -= w / 2; break; case SouthEastGravity: case EastGravity: case NorthEastGravity: /* Find right edge of frame */ x += frame_extents.width; /* Align left edge of client at that point. */ x -= w; break; default: break; } switch (gravity) { case WestGravity: case CenterGravity: case EastGravity: /* Find center of frame. */ y += frame_extents.height / 2; /* Center client window there. */ y -= h / 2; break; case SouthWestGravity: case SouthGravity: case SouthEastGravity: /* Find south edge of frame */ y += frame_extents.height; /* Place bottom edge of client there */ y -= h; break; default: break; } if (root_x) *root_x = x; if (root_y) *root_y = y; } LOCAL_SYMBOL void meta_window_get_geometry (MetaWindow *window, int *x, int *y, int *width, int *height) { meta_window_get_gravity_position (window, window->size_hints.win_gravity, x, y); *width = (window->rect.width - window->size_hints.base_width) / window->size_hints.width_inc; *height = (window->rect.height - window->size_hints.base_height) / window->size_hints.height_inc; } /** * meta_window_get_input_rect: * @window: a #MetaWindow * @rect: (out): pointer to an allocated #MetaRectangle * * Gets the rectangle that bounds @window that is responsive to mouse events. * This includes decorations - the visible portion of its border - and (if * present) any invisible area that we make make responsive to mouse clicks in * order to allow convenient border dragging. */ void meta_window_get_input_rect (const MetaWindow *window, MetaRectangle *rect) { if (window->frame) *rect = window->frame->rect; else *rect = window->rect; } /** * meta_window_get_outer_rect: * @window: a #MetaWindow * @rect: (out): pointer to an allocated #MetaRectangle * * Gets the rectangle that bounds @window that is responsive to mouse events. * This includes only what is visible; it doesn't include any extra reactive * area we add to the edges of windows. */ void meta_window_get_outer_rect (const MetaWindow *window, MetaRectangle *rect) { if (window->frame) { MetaFrameBorders borders; *rect = window->frame->rect; meta_frame_calc_borders (window->frame, &borders); rect->x += borders.invisible.left; rect->y += borders.invisible.top; rect->width -= borders.invisible.left + borders.invisible.right; rect->height -= borders.invisible.top + borders.invisible.bottom; } else { *rect = window->rect; if (window->has_custom_frame_extents) { const GtkBorder *extents = &window->custom_frame_extents; rect->x += extents->left; rect->y += extents->top; rect->width -= extents->left + extents->right; rect->height -= extents->top + extents->bottom; } } } /** * meta_window_get_client_area_rect: * @window: a #MetaWindow * @rect: (out): pointer to a cairo rectangle * * Gets the rectangle for the boundaries of the client area, relative * to the frame. If the window is shaded, the height of the rectangle * is 0. */ void meta_window_get_client_area_rect (const MetaWindow *window, cairo_rectangle_int_t *rect) { if (window->frame) { rect->x = window->frame->child_x; rect->y = window->frame->child_y; } else { rect->x = 0; rect->y = 0; } rect->width = window->rect.width; if (window->shaded) rect->height = 0; else rect->height = window->rect.height; } MetaSide meta_window_get_tile_side (MetaWindow *window) { MetaSide side; switch (window->tile_mode) { case META_TILE_LEFT: side = META_SIDE_LEFT; break; case META_TILE_ULC: side = (META_SIDE_LEFT | META_SIDE_TOP); break; case META_TILE_LLC: side = (META_SIDE_LEFT | META_SIDE_BOTTOM); break; case META_TILE_RIGHT: side = META_SIDE_RIGHT; break; case META_TILE_URC: side = (META_SIDE_RIGHT | META_SIDE_TOP); break; case META_TILE_LRC: side = (META_SIDE_RIGHT | META_SIDE_BOTTOM); break; case META_TILE_TOP: side = META_SIDE_TOP; break; case META_TILE_BOTTOM: side = META_SIDE_BOTTOM; break; default: side = META_SIDE_TOP; break; } return side; } void meta_window_get_titlebar_rect (MetaWindow *window, MetaRectangle *rect) { meta_window_get_outer_rect (window, rect); /* The returned rectangle is relative to the frame rect. */ rect->x = 0; rect->y = 0; if (window->frame) { rect->height = window->frame->child_y; } else { /* Pick an arbitrary height for a titlebar. We might want to * eventually have CSD windows expose their borders to us. */ rect->height = CSD_TITLEBAR_HEIGHT * meta_prefs_get_ui_scale (); } } const char* meta_window_get_startup_id (MetaWindow *window) { if (window->startup_id == NULL) { MetaGroup *group; group = meta_window_get_group (window); if (group != NULL) return meta_group_get_startup_id (group); } return window->startup_id; } static MetaWindow* get_modal_transient (MetaWindow *window) { GSList *windows; GSList *tmp; MetaWindow *modal_transient; /* A window can't be the transient of itself, but this is just for * convenience in the loop below; we manually fix things up at the * end if no real modal transient was found. */ modal_transient = window; windows = meta_display_list_windows (window->display, META_LIST_DEFAULT); tmp = windows; while (tmp != NULL) { MetaWindow *transient = tmp->data; if (transient->xtransient_for == modal_transient->xwindow && transient->wm_state_modal) { modal_transient = transient; tmp = windows; continue; } tmp = tmp->next; } g_slist_free (windows); if (window == modal_transient) modal_transient = NULL; return modal_transient; } /* XXX META_EFFECT_FOCUS */ LOCAL_SYMBOL void meta_window_focus (MetaWindow *window, guint32 timestamp) { MetaWindow *modal_transient; g_return_if_fail (!window->override_redirect); meta_topic (META_DEBUG_FOCUS, "Setting input focus to window %s, input: %d take_focus: %d\n", window->desc, window->input, window->take_focus); if (window->display->grab_window && window->display->grab_window->all_keys_grabbed) { meta_topic (META_DEBUG_FOCUS, "Current focus window %s has global keygrab, not focusing window %s after all\n", window->display->grab_window->desc, window->desc); return; } modal_transient = get_modal_transient (window); if (modal_transient != NULL && !modal_transient->unmanaging) { meta_topic (META_DEBUG_FOCUS, "%s has %s as a modal transient, so focusing it instead.\n", window->desc, modal_transient->desc); if (!modal_transient->on_all_workspaces && modal_transient->workspace != window->screen->active_workspace) meta_window_change_workspace (modal_transient, window->screen->active_workspace); window = modal_transient; } meta_window_flush_calc_showing (window); if ((!window->mapped || window->hidden) && !window->shaded) { meta_topic (META_DEBUG_FOCUS, "Window %s is not showing, not focusing after all\n", window->desc); return; } /* For output-only or shaded windows, focus the frame. * This seems to result in the client window getting key events * though, so I don't know if it's icccm-compliant. * * Still, we have to do this or keynav breaks for these windows. */ if (window->frame && (window->shaded || !(window->input || window->take_focus))) { meta_topic (META_DEBUG_FOCUS, "Focusing frame of %s\n", window->desc); meta_display_set_input_focus_window (window->display, window, TRUE, timestamp); } else { if (window->input) { meta_topic (META_DEBUG_FOCUS, "Setting input focus on %s since input = true\n", window->desc); meta_display_set_input_focus_window (window->display, window, FALSE, timestamp); } if (window->take_focus) { meta_topic (META_DEBUG_FOCUS, "Sending WM_TAKE_FOCUS to %s since take_focus = true\n", window->desc); meta_window_send_icccm_message (window, window->display->atom_WM_TAKE_FOCUS, timestamp); window->display->expected_focus_window = window; } } if (window->wm_state_demands_attention) meta_window_unset_demands_attention(window); } static void meta_window_change_workspace_without_transients (MetaWindow *window, MetaWorkspace *workspace) { int old_workspace = -1; meta_verbose ("Changing window %s to workspace %d\n", window->desc, meta_workspace_index (workspace)); if (!window->on_all_workspaces_requested) { old_workspace = meta_workspace_index (window->workspace); } /* unstick if stuck. meta_window_unstick would call * meta_window_change_workspace recursively if the window * is not in the active workspace. */ if (window->on_all_workspaces_requested) meta_window_unstick (window); /* See if we're already on this space. If not, make sure we are */ if (window->workspace != workspace) { meta_workspace_remove_window (window->workspace, window); meta_workspace_add_window (workspace, window); g_signal_emit (window, window_signals[WORKSPACE_CHANGED], 0, old_workspace); g_signal_emit_by_name (window->screen, "window-workspace-changed", window, window->workspace); } } static gboolean change_workspace_foreach (MetaWindow *window, void *data) { meta_window_change_workspace_without_transients (window, data); return TRUE; } /** * meta_window_change_workspace: * @window: a #MetaWindow * @workspace: the #MetaWorkspace where to put the window * * Moves the window to the specified workspace. */ void meta_window_change_workspace (MetaWindow *window, MetaWorkspace *workspace) { g_return_if_fail (!window->override_redirect); meta_window_change_workspace_without_transients (window, workspace); meta_window_foreach_transient (window, change_workspace_foreach, workspace); meta_window_foreach_ancestor (window, change_workspace_foreach, workspace); } static void window_stick_impl (MetaWindow *window) { meta_verbose ("Sticking window %s current on_all_workspaces = %d\n", window->desc, window->on_all_workspaces); if (window->on_all_workspaces_requested) return; /* We don't change window->workspaces, because we revert * to that original workspace list if on_all_workspaces is * toggled back off. */ int old_workspace = meta_workspace_index (window->workspace); window->on_all_workspaces_requested = TRUE; meta_window_frame_size_changed (window); meta_window_update_on_all_workspaces (window); meta_window_queue(window, META_QUEUE_CALC_SHOWING); g_signal_emit (window, window_signals[WORKSPACE_CHANGED], 0, old_workspace); } static void window_unstick_impl (MetaWindow *window) { if (!window->on_all_workspaces_requested) return; /* Revert to window->workspaces */ window->on_all_workspaces_requested = FALSE; meta_window_frame_size_changed (window); meta_window_update_on_all_workspaces (window); /* We change ourselves to the active workspace, since otherwise you'd get * a weird window-vaporization effect. Once we have UI for being * on more than one workspace this should probably be add_workspace * not change_workspace. */ if (window->screen->active_workspace != window->workspace) meta_window_change_workspace (window, window->screen->active_workspace); meta_window_queue(window, META_QUEUE_CALC_SHOWING); g_signal_emit (window, window_signals[WORKSPACE_CHANGED], 0, -1); } static gboolean stick_foreach_func (MetaWindow *window, void *data) { gboolean stick; stick = *(gboolean*)data; if (stick) window_stick_impl (window); else window_unstick_impl (window); return TRUE; } void meta_window_stick (MetaWindow *window) { gboolean stick = TRUE; g_return_if_fail (!window->override_redirect); window_stick_impl (window); meta_window_foreach_transient (window, stick_foreach_func, &stick); } void meta_window_unstick (MetaWindow *window) { gboolean stick = FALSE; g_return_if_fail (!window->override_redirect); window_unstick_impl (window); meta_window_foreach_transient (window, stick_foreach_func, &stick); } LOCAL_SYMBOL unsigned long meta_window_get_net_wm_desktop (MetaWindow *window) { if (window->on_all_workspaces) return 0xFFFFFFFF; else return meta_workspace_index (window->workspace); } static void update_net_frame_extents (MetaWindow *window) { unsigned long data[4]; MetaFrameBorders borders; meta_frame_calc_borders (window->frame, &borders); /* Left */ data[0] = borders.visible.left; /* Right */ data[1] = borders.visible.right; /* Top */ data[2] = borders.visible.top; /* Bottom */ data[3] = borders.visible.bottom; meta_topic (META_DEBUG_GEOMETRY, "Setting _NET_FRAME_EXTENTS on managed window 0x%lx " "to left = %lu, right = %lu, top = %lu, bottom = %lu\n", window->xwindow, data[0], data[1], data[2], data[3]); meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_FRAME_EXTENTS, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 4); meta_error_trap_pop (window->display); } static void update_gtk_edge_constraints (MetaWindow *window) { MetaEdgeConstraint *constraints = window->edge_constraints; unsigned long data[1]; /* Edge constraints */ data[0] = (constraints[0] != META_EDGE_CONSTRAINT_NONE ? 1 : 0) << 0 | (constraints[0] != META_EDGE_CONSTRAINT_MONITOR ? 1 : 0) << 1 | (constraints[1] != META_EDGE_CONSTRAINT_NONE ? 1 : 0) << 2 | (constraints[1] != META_EDGE_CONSTRAINT_MONITOR ? 1 : 0) << 3 | (constraints[2] != META_EDGE_CONSTRAINT_NONE ? 1 : 0) << 4 | (constraints[2] != META_EDGE_CONSTRAINT_MONITOR ? 1 : 0) << 5 | (constraints[3] != META_EDGE_CONSTRAINT_NONE ? 1 : 0) << 6 | (constraints[3] != META_EDGE_CONSTRAINT_MONITOR ? 1 : 0) << 7; meta_verbose ("Setting _GTK_EDGE_CONSTRAINTS to %lu\n", data[0]); meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom__GTK_EDGE_CONSTRAINTS, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); meta_error_trap_pop (window->display); } LOCAL_SYMBOL void meta_window_set_current_workspace_hint (MetaWindow *window) { /* FIXME if on more than one workspace, we claim to be "sticky", * the WM spec doesn't say what to do here. */ unsigned long data[1]; if (window->workspace == NULL) { /* this happens when unmanaging windows */ return; } data[0] = meta_window_get_net_wm_desktop (window); meta_verbose ("Setting _NET_WM_DESKTOP of %s to %lu\n", window->desc, data[0]); meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_DESKTOP, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); meta_error_trap_pop (window->display); } static gboolean find_root_ancestor (MetaWindow *window, void *data) { MetaWindow **ancestor = data; /* Overwrite the previously "most-root" ancestor with the new one found */ *ancestor = window; /* We want this to continue until meta_window_foreach_ancestor quits because * there are no more valid ancestors. */ return TRUE; } /** * meta_window_find_root_ancestor: * @window: a #MetaWindow * * Follow the chain of parents of @window, skipping transient windows, * and return the "root" window which has no non-transient parent. * * Returns: (transfer none): The root ancestor window */ MetaWindow * meta_window_find_root_ancestor (MetaWindow *window) { MetaWindow *ancestor; ancestor = window; meta_window_foreach_ancestor (window, find_root_ancestor, &ancestor); return ancestor; } void meta_window_raise (MetaWindow *window) { MetaWindow *ancestor; g_return_if_fail (!window->override_redirect); ancestor = meta_window_find_root_ancestor (window); meta_topic (META_DEBUG_WINDOW_OPS, "Raising window %s, ancestor of %s\n", ancestor->desc, window->desc); /* Raise the ancestor of the window (if the window has no ancestor, * then ancestor will be set to the window itself); do this because * it's weird to see windows from other apps stacked between a child * and parent window of the currently active app. The stacking * constraints in stack.c then magically take care of raising all * the child windows appropriately. */ if (window->screen->stack == ancestor->screen->stack) meta_stack_raise (window->screen->stack, ancestor); else { meta_warning ( "Either stacks aren't per screen or some window has a weird " "transient_for hint; window->screen->stack != " "ancestor->screen->stack. window = %s, ancestor = %s.\n", window->desc, ancestor->desc); /* We could raise the window here, but don't want to do that twice and * so we let the case below handle that. */ } /* Okay, so stacking constraints misses one case: If a window has * two children and we want to raise one of those children, then * raising the ancestor isn't enough; we need to also raise the * correct child. See bug 307875. */ if (window != ancestor) meta_stack_raise (window->screen->stack, window); g_signal_emit (window, window_signals[RAISED], 0); } void meta_window_lower (MetaWindow *window) { g_return_if_fail (!window->override_redirect); meta_topic (META_DEBUG_WINDOW_OPS, "Lowering window %s\n", window->desc); meta_stack_lower (window->screen->stack, window); } LOCAL_SYMBOL void meta_window_send_icccm_message (MetaWindow *window, Atom atom, guint32 timestamp) { /* This comment and code are from twm, copyright * Open Group, Evans & Sutherland, etc. */ /* * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all * client messages will have the following form: * * event type ClientMessage * message type _XA_WM_PROTOCOLS * window tmp->w * format 32 * data[0] message atom * data[1] time stamp */ XClientMessageEvent ev; ev.type = ClientMessage; ev.window = window->xwindow; ev.message_type = window->display->atom_WM_PROTOCOLS; ev.format = 32; ev.data.l[0] = atom; ev.data.l[1] = timestamp; meta_error_trap_push (window->display); XSendEvent (window->display->xdisplay, window->xwindow, False, 0, (XEvent*) &ev); meta_error_trap_pop (window->display); } LOCAL_SYMBOL void meta_window_move_resize_request (MetaWindow *window, guint value_mask, int gravity, int new_x, int new_y, int new_width, int new_height) { int x, y, width, height; gboolean allow_position_change; gboolean in_grab_op; MetaMoveResizeFlags flags; /* We ignore configure requests while the user is moving/resizing * the window, since these represent the app sucking and fighting * the user, most likely due to a bug in the app (e.g. pfaedit * seemed to do this) * * Still have to do the ConfigureNotify and all, but pretend the * app asked for the current size/position instead of the new one. */ in_grab_op = FALSE; if (window->display->grab_op != META_GRAB_OP_NONE && window == window->display->grab_window) { switch (window->display->grab_op) { case META_GRAB_OP_MOVING: case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_RESIZING_E: in_grab_op = TRUE; break; default: break; } } /* it's essential to use only the explicitly-set fields, * and otherwise use our current up-to-date position. * * Otherwise you get spurious position changes when the app changes * size, for example, if window->rect is not in sync with the * server-side position in effect when the configure request was * generated. */ meta_window_get_gravity_position (window, gravity, &x, &y); allow_position_change = FALSE; if (meta_prefs_get_disable_workarounds ()) { if (window->type == META_WINDOW_DIALOG || window->type == META_WINDOW_MODAL_DIALOG || window->type == META_WINDOW_SPLASHSCREEN) ; /* No position change for these */ else if ((window->size_hints.flags & PPosition) || /* USPosition is just stale if window is placed; * no --geometry involved here. */ ((window->size_hints.flags & USPosition) && !window->placed)) allow_position_change = TRUE; } else { allow_position_change = TRUE; } if (in_grab_op) allow_position_change = FALSE; if (allow_position_change) { if (value_mask & CWX) x = new_x; if (value_mask & CWY) y = new_y; if (value_mask & (CWX | CWY)) { /* Once manually positioned, windows shouldn't be placed * by the window manager. */ window->placed = TRUE; } } else { meta_topic (META_DEBUG_GEOMETRY, "Not allowing position change for window %s PPosition 0x%lx USPosition 0x%lx type %u\n", window->desc, window->size_hints.flags & PPosition, window->size_hints.flags & USPosition, window->type); } width = window->rect.width; height = window->rect.height; if (!in_grab_op) { if (value_mask & CWWidth) width = new_width; if (value_mask & CWHeight) height = new_height; } /* ICCCM 4.1.5 */ /* We're ignoring the value_mask here, since sizes * not in the mask will be the current window geometry. */ window->size_hints.x = x; window->size_hints.y = y; window->size_hints.width = width; window->size_hints.height = height; /* NOTE: We consider ConfigureRequests to be "user" actions in one * way, but not in another. Explanation of the two cases are in the * next two big comments. */ /* The constraints code allows user actions to move windows * offscreen, etc., and configure request actions would often send * windows offscreen when users don't want it if not constrained * (e.g. hitting a dropdown triangle in a fileselector to show more * options, which makes the window bigger). Thus we do not set * META_IS_USER_ACTION in flags to the * meta_window_move_resize_internal() call. */ flags = META_IS_CONFIGURE_REQUEST; if (value_mask & (CWX | CWY)) flags |= META_IS_MOVE_ACTION; if (value_mask & (CWWidth | CWHeight)) flags |= META_IS_RESIZE_ACTION; if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)) { MetaRectangle rect, monitor_rect; rect.x = x; rect.y = y; rect.width = width; rect.height = height; /* Workaround braindead legacy apps that don't know how to * fullscreen themselves properly - don't get fooled by * windows which hide their titlebar when maximized or which are * client decorated; that's not the same as fullscreen, even * if there are no struts making the workarea smaller than * the monitor. */ if (window->monitor) { meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect); if (meta_prefs_get_force_fullscreen() && !window->hide_titlebar_when_maximized && (window->decorated && !meta_window_is_client_decorated (window)) && meta_rectangle_equal (&rect, &monitor_rect) && window->has_fullscreen_func && !window->fullscreen) { /* meta_topic (META_DEBUG_GEOMETRY, */ meta_warning ( "Treating resize request of legacy application %s as a " "fullscreen request\n", window->desc); meta_window_make_fullscreen_internal (window); } } meta_window_move_resize_internal (window, flags, gravity, x, y, width, height); } /* window->user_rect exists to allow "snapping-back" the window if a * new strut is set (causing the window to move) and then the strut * is later removed without the user moving the window in the * interim. We'd like to "snap-back" to the position specified by * ConfigureRequest events (at least the constrained version of the * ConfigureRequest, since that is guaranteed to be onscreen) so we * set user_rect here. * * See also bug 426519. */ save_user_window_placement (window); } static void restack_window (MetaWindow *window, MetaWindow *sibling, int direction) { switch (direction) { case Above: if (sibling) meta_window_stack_just_above (window, sibling); else meta_window_raise (window); break; case Below: if (sibling) meta_window_stack_just_below (window, sibling); else meta_window_lower (window); break; case TopIf: case BottomIf: case Opposite: break; } } LOCAL_SYMBOL gboolean meta_window_configure_request (MetaWindow *window, XEvent *event) { /* Note that x, y is the corner of the window border, * and width, height is the size of the window inside * its border, but that we always deny border requests * and give windows a border of 0. But we save the * requested border here. */ if (event->xconfigurerequest.value_mask & CWBorderWidth) window->border_width = event->xconfigurerequest.border_width; meta_window_move_resize_request(window, event->xconfigurerequest.value_mask, window->size_hints.win_gravity, event->xconfigurerequest.x, event->xconfigurerequest.y, event->xconfigurerequest.width, event->xconfigurerequest.height); /* Handle stacking. We only handle raises/lowers, mostly because * stack.c really can't deal with anything else. I guess we'll fix * that if a client turns up that really requires it. Only a very * few clients even require the raise/lower (and in fact all client * attempts to deal with stacking order are essentially broken, * since they have no idea what other clients are involved or how * the stack looks). * * I'm pretty sure no interesting client uses TopIf, BottomIf, or * Opposite anyway. */ if (event->xconfigurerequest.value_mask & CWStackMode) { MetaWindow *active_window; active_window = window->display->expected_focus_window; if (meta_prefs_get_disable_workarounds ()) { meta_topic (META_DEBUG_STACK, "%s sent an xconfigure stacking request; this is " "broken behavior and the request is being ignored.\n", window->desc); } else if (active_window && !meta_window_same_application (window, active_window) && !meta_window_same_client (window, active_window) && XSERVER_TIME_IS_BEFORE (window->net_wm_user_time, active_window->net_wm_user_time)) { meta_topic (META_DEBUG_STACK, "Ignoring xconfigure stacking request from %s (with " "user_time %u); currently active application is %s (with " "user_time %u).\n", window->desc, window->net_wm_user_time, active_window->desc, active_window->net_wm_user_time); if (event->xconfigurerequest.detail == Above) meta_window_set_demands_attention(window); } else { MetaWindow *sibling = NULL; /* Handle Above/Below with a sibling set */ if (event->xconfigurerequest.above != None) { MetaDisplay *display; display = meta_window_get_display (window); sibling = meta_display_lookup_x_window (display, event->xconfigurerequest.above); if (sibling == NULL) return TRUE; meta_topic (META_DEBUG_STACK, "xconfigure stacking request from window %s sibling %s stackmode %d\n", window->desc, sibling->desc, event->xconfigurerequest.detail); } restack_window (window, sibling, event->xconfigurerequest.detail); } } return TRUE; } LOCAL_SYMBOL gboolean meta_window_property_notify (MetaWindow *window, XEvent *event) { return process_property_notify (window, &event->xproperty); } static void handle_net_restack_window (MetaDisplay *display, XEvent *event) { MetaWindow *window, *sibling = NULL; /* Ignore if this does not come from a pager, see the WM spec */ if (event->xclient.data.l[0] != 2) return; window = meta_display_lookup_x_window (display, event->xclient.window); if (window) { if (event->xclient.data.l[1]) sibling = meta_display_lookup_x_window (display, event->xclient.data.l[1]); restack_window (window, sibling, event->xclient.data.l[2]); } } /* * Move window to the requested workspace; append controls whether new WS * should be created if one does not exist. */ void meta_window_change_workspace_by_index (MetaWindow *window, gint space_index, gboolean append, guint32 timestamp) { MetaWorkspace *workspace; MetaScreen *screen; g_return_if_fail (!window->override_redirect); if (space_index == -1) { meta_window_stick (window); return; } screen = window->screen; workspace = meta_screen_get_workspace_by_index (screen, space_index); if (!workspace && append) { if (timestamp == CurrentTime) timestamp = meta_display_get_current_time_roundtrip (window->display); workspace = meta_screen_append_new_workspace (screen, FALSE, timestamp); } if (workspace) { if (window->on_all_workspaces_requested) meta_window_unstick (window); meta_window_change_workspace (window, workspace); } } #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 #define _NET_WM_MOVERESIZE_SIZE_TOP 1 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 #define _NET_WM_MOVERESIZE_SIZE_LEFT 7 #define _NET_WM_MOVERESIZE_MOVE 8 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 #define _NET_WM_MOVERESIZE_CANCEL 11 LOCAL_SYMBOL gboolean meta_window_client_message (MetaWindow *window, XEvent *event) { MetaDisplay *display; display = window->display; if (window->override_redirect) { /* Don't warn here: we could warn on any of the messages below, * but we might also receive other client messages that are * part of protocols we don't know anything about. So, silently * ignoring is simplest. */ return FALSE; } if (event->xclient.message_type == display->atom__NET_CLOSE_WINDOW) { guint32 timestamp; if (event->xclient.data.l[0] != 0) timestamp = event->xclient.data.l[0]; else { meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without " "a timestamp! This means some buggy (outdated) " "application is on the loose!\n", window->desc); timestamp = meta_display_get_current_time (window->display); } meta_window_delete (window, timestamp); return TRUE; } else if (event->xclient.message_type == display->atom__NET_WM_DESKTOP) { int space; MetaWorkspace *workspace; space = event->xclient.data.l[0]; meta_verbose ("Request to move %s to workspace %d\n", window->desc, space); workspace = meta_screen_get_workspace_by_index (window->screen, space); if (workspace) meta_window_change_workspace (window, workspace); else if (space == (int) 0xFFFFFFFF) meta_window_stick (window); else meta_verbose ("No such workspace %d for screen\n", space); meta_verbose ("Window %s now on_all_workspaces = %d\n", window->desc, window->on_all_workspaces); return TRUE; } else if (event->xclient.message_type == display->atom__NET_WM_STATE) { gulong action; Atom first; Atom second; action = event->xclient.data.l[0]; first = event->xclient.data.l[1]; second = event->xclient.data.l[2]; if (meta_is_verbose ()) { char *str1; char *str2; meta_error_trap_push_with_return (display); str1 = XGetAtomName (display->xdisplay, first); if (meta_error_trap_pop_with_return (display) != Success) str1 = NULL; meta_error_trap_push_with_return (display); str2 = XGetAtomName (display->xdisplay, second); if (meta_error_trap_pop_with_return (display) != Success) str2 = NULL; meta_verbose ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s\n", action, str1 ? str1 : "(unknown)", str2 ? str2 : "(unknown)"); meta_XFree (str1); meta_XFree (str2); } if (first == display->atom__NET_WM_STATE_SHADED || second == display->atom__NET_WM_STATE_SHADED) { gboolean shade; guint32 timestamp; /* Stupid protocol has no timestamp; of course, shading * sucks anyway so who really cares that we're forced to do * a roundtrip here? */ timestamp = meta_display_get_current_time_roundtrip (window->display); shade = (action == _NET_WM_STATE_ADD || (action == _NET_WM_STATE_TOGGLE && !window->shaded)); if (shade && window->has_shade_func) meta_window_shade (window, timestamp); else meta_window_unshade (window, timestamp); } if (first == display->atom__NET_WM_STATE_FULLSCREEN || second == display->atom__NET_WM_STATE_FULLSCREEN) { gboolean make_fullscreen; make_fullscreen = (action == _NET_WM_STATE_ADD || (action == _NET_WM_STATE_TOGGLE && !window->fullscreen)); if (make_fullscreen && window->has_fullscreen_func) meta_window_make_fullscreen (window); else meta_window_unmake_fullscreen (window); } if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ) { gboolean max; max = (action == _NET_WM_STATE_ADD || (action == _NET_WM_STATE_TOGGLE && !window->maximized_horizontally)); if (max && window->has_maximize_func) { if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL); } else { if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL); } } if (first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) { gboolean max; max = (action == _NET_WM_STATE_ADD || (action == _NET_WM_STATE_TOGGLE && !window->maximized_vertically)); if (max && window->has_maximize_func) { if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_maximize (window, META_MAXIMIZE_VERTICAL); } else { if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL); } } if (first == display->atom__NET_WM_STATE_MODAL || second == display->atom__NET_WM_STATE_MODAL) { window->wm_state_modal = (action == _NET_WM_STATE_ADD) || (action == _NET_WM_STATE_TOGGLE && !window->wm_state_modal); recalc_window_type (window); meta_window_queue(window, META_QUEUE_MOVE_RESIZE); } if (first == display->atom__NET_WM_STATE_SKIP_PAGER || second == display->atom__NET_WM_STATE_SKIP_PAGER) { window->wm_state_skip_pager = (action == _NET_WM_STATE_ADD) || (action == _NET_WM_STATE_TOGGLE && !window->skip_pager); recalc_window_features (window); set_net_wm_state (window); } if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR || second == display->atom__NET_WM_STATE_SKIP_TASKBAR) { window->wm_state_skip_taskbar = (action == _NET_WM_STATE_ADD) || (action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar); recalc_window_features (window); set_net_wm_state (window); } if (first == display->atom__NET_WM_STATE_ABOVE || second == display->atom__NET_WM_STATE_ABOVE) { meta_window_set_above(window, (action == _NET_WM_STATE_ADD) || (action == _NET_WM_STATE_TOGGLE && !window->wm_state_above)); } if (first == display->atom__NET_WM_STATE_BELOW || second == display->atom__NET_WM_STATE_BELOW) { window->wm_state_below = (action == _NET_WM_STATE_ADD) || (action == _NET_WM_STATE_TOGGLE && !window->wm_state_below); meta_window_update_layer (window); set_net_wm_state (window); } if (first == display->atom__NET_WM_STATE_DEMANDS_ATTENTION || second == display->atom__NET_WM_STATE_DEMANDS_ATTENTION) { if ((action == _NET_WM_STATE_ADD) || (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention)) meta_window_set_demands_attention (window); else meta_window_unset_demands_attention (window); } if (first == display->atom__NET_WM_STATE_STICKY || second == display->atom__NET_WM_STATE_STICKY) { if ((action == _NET_WM_STATE_ADD) || (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces_requested)) meta_window_stick (window); else meta_window_unstick (window); } return TRUE; } else if (event->xclient.message_type == display->atom_WM_CHANGE_STATE) { meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n", event->xclient.data.l[0]); if (event->xclient.data.l[0] == IconicState) meta_window_minimize (window); return TRUE; } else if (event->xclient.message_type == display->atom__NET_WM_MOVERESIZE) { int x_root; int y_root; int action; MetaGrabOp op; int button; guint32 timestamp; /* _NET_WM_MOVERESIZE messages are almost certainly going to come from * clients when users click on the fake "frame" that the client has, * thus we should also treat such messages as though it were a * "frame action". */ gboolean const frame_action = TRUE; x_root = event->xclient.data.l[0]; y_root = event->xclient.data.l[1]; action = event->xclient.data.l[2]; button = event->xclient.data.l[3]; /* FIXME: What a braindead protocol; no timestamp?!? */ timestamp = meta_display_get_current_time_roundtrip (display); meta_topic (META_DEBUG_WINDOW_OPS, "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d\n", window->desc, x_root, y_root, action, button); op = META_GRAB_OP_NONE; switch (action) { case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: op = META_GRAB_OP_RESIZING_NW; break; case _NET_WM_MOVERESIZE_SIZE_TOP: op = META_GRAB_OP_RESIZING_N; break; case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: op = META_GRAB_OP_RESIZING_NE; break; case _NET_WM_MOVERESIZE_SIZE_RIGHT: op = META_GRAB_OP_RESIZING_E; break; case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: op = META_GRAB_OP_RESIZING_SE; break; case _NET_WM_MOVERESIZE_SIZE_BOTTOM: op = META_GRAB_OP_RESIZING_S; break; case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: op = META_GRAB_OP_RESIZING_SW; break; case _NET_WM_MOVERESIZE_SIZE_LEFT: op = META_GRAB_OP_RESIZING_W; break; case _NET_WM_MOVERESIZE_MOVE: op = META_GRAB_OP_MOVING; break; case _NET_WM_MOVERESIZE_SIZE_KEYBOARD: op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN; break; case _NET_WM_MOVERESIZE_MOVE_KEYBOARD: op = META_GRAB_OP_KEYBOARD_MOVING; break; case _NET_WM_MOVERESIZE_CANCEL: /* handled below */ break; default: break; } if (action == _NET_WM_MOVERESIZE_CANCEL) { meta_display_end_grab_op (window->display, timestamp); } else if (op != META_GRAB_OP_NONE && ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) || (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN))) { meta_window_begin_grab_op (window, op, frame_action, timestamp); } else if (op != META_GRAB_OP_NONE && ((window->has_move_func && op == META_GRAB_OP_MOVING) || (window->has_resize_func && (op != META_GRAB_OP_MOVING && op != META_GRAB_OP_KEYBOARD_MOVING)))) { /* * the button SHOULD already be included in the message */ if (button == 0) { int x, y, query_root_x, query_root_y; Window root, child; guint mask; /* The race conditions in this _NET_WM_MOVERESIZE thing * are mind-boggling */ mask = 0; meta_error_trap_push (window->display); XQueryPointer (window->display->xdisplay, window->xwindow, &root, &child, &query_root_x, &query_root_y, &x, &y, &mask); meta_error_trap_pop (window->display); if (mask & Button1Mask) button = 1; else if (mask & Button2Mask) button = 2; else if (mask & Button3Mask) button = 3; else button = 0; } if (button != 0) { meta_topic (META_DEBUG_WINDOW_OPS, "Beginning move/resize with button = %d\n", button); meta_display_begin_grab_op (window->display, window->screen, window, op, FALSE, frame_action, button, 0, timestamp, x_root, y_root); } } return TRUE; } else if (event->xclient.message_type == display->atom__NET_MOVERESIZE_WINDOW) { int gravity; guint value_mask; gravity = (event->xclient.data.l[0] & 0xff); value_mask = (event->xclient.data.l[0] & 0xf00) >> 8; /* source = (event->xclient.data.l[0] & 0xf000) >> 12; */ if (gravity == 0) gravity = window->size_hints.win_gravity; meta_window_move_resize_request(window, value_mask, gravity, event->xclient.data.l[1], /* x */ event->xclient.data.l[2], /* y */ event->xclient.data.l[3], /* width */ event->xclient.data.l[4]); /* height */ } else if (event->xclient.message_type == display->atom__NET_ACTIVE_WINDOW) { MetaClientType source_indication; guint32 timestamp; meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating\n", window->desc); source_indication = event->xclient.data.l[0]; timestamp = event->xclient.data.l[1]; if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED) source_indication = META_CLIENT_TYPE_UNKNOWN; if (timestamp == 0) { /* Client using older EWMH _NET_ACTIVE_WINDOW without a timestamp */ meta_topic (META_DEBUG_FOCUS, "Buggy client sent a _NET_ACTIVE_WINDOW message with a " "timestamp of 0 for %s\n", window->desc); timestamp = meta_display_get_current_time (display); } window_activate (window, timestamp, source_indication, NULL); return TRUE; } else if (event->xclient.message_type == display->atom__NET_WM_FULLSCREEN_MONITORS) { gulong top, bottom, left, right; meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", window->desc); top = event->xclient.data.l[0]; bottom = event->xclient.data.l[1]; left = event->xclient.data.l[2]; right = event->xclient.data.l[3]; /* source_indication = event->xclient.data.l[4]; */ meta_window_update_fullscreen_monitors (window, top, bottom, left, right); } else if (event->xclient.message_type == display->atom__GTK_SHOW_WINDOW_MENU) { if (meta_window_is_client_decorated (window)) { int x_root, y_root; x_root = event->xclient.data.l[1]; y_root = event->xclient.data.l[2]; meta_screen_hide_hud_and_preview (window->screen); if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_focus (window, meta_display_get_current_time_roundtrip (display)); meta_window_show_menu (window, x_root, y_root, GDK_BUTTON_SECONDARY, meta_display_get_current_time_roundtrip (display)); } } else if (event->xclient.message_type == display->atom__NET_RESTACK_WINDOW) { handle_net_restack_window (display, event); } return FALSE; } static void meta_window_appears_focused_changed (MetaWindow *window) { set_net_wm_state (window); meta_window_frame_size_changed (window); g_object_notify (G_OBJECT (window), "appears-focused"); if (window->frame) meta_frame_queue_draw (window->frame); } /** * meta_window_propagate_focus_appearance: * @window: the window to start propagating from * @focused: %TRUE if @window's ancestors should appear focused, * %FALSE if they should not. * * Adjusts the value of #MetaWindow:appears-focused on @window's * ancestors (but not @window itself). If @focused is %TRUE, each of * @window's ancestors will have its %attached_focus_window field set * to the current %focus_window. If @focused if %FALSE, each of * @window's ancestors will have its %attached_focus_window field * cleared if it is currently %focus_window. */ LOCAL_SYMBOL void meta_window_propagate_focus_appearance (MetaWindow *window, gboolean focused) { MetaWindow *child, *parent, *focus_window; focus_window = window->display->focus_window; child = window; parent = meta_window_get_transient_for (child); while (parent && (!focused || meta_window_is_attached_dialog (child))) { gboolean child_focus_state_changed; if (focused) { if (parent->attached_focus_window == focus_window) break; child_focus_state_changed = (parent->attached_focus_window == NULL); parent->attached_focus_window = focus_window; } else { if (parent->attached_focus_window != focus_window) break; child_focus_state_changed = (parent->attached_focus_window != NULL); parent->attached_focus_window = NULL; } if (child_focus_state_changed && !parent->has_focus && parent != window->display->expected_focus_window) { meta_window_appears_focused_changed (parent); } child = parent; parent = meta_window_get_transient_for (child); } } LOCAL_SYMBOL gboolean meta_window_notify_focus (MetaWindow *window, XEvent *event) { /* note the event can be on either the window or the frame, * we focus the frame for shaded windows */ /* The event can be FocusIn, FocusOut, or UnmapNotify. * On UnmapNotify we have to pretend it's focus out, * because we won't get a focus out if it occurs, apparently. */ /* We ignore grabs, though this is questionable. * It may be better to increase the intelligence of * the focus window tracking. * * The problem is that keybindings for windows are done with * XGrabKey, which means focus_window disappears and the front of * the MRU list gets confused from what the user expects once a * keybinding is used. */ meta_topic (META_DEBUG_FOCUS, "Focus %s event received on %s 0x%lx (%s) " "mode %s detail %s\n", event->type == FocusIn ? "in" : event->type == FocusOut ? "out" : event->type == UnmapNotify ? "unmap" : "???", window->desc, event->xany.window, event->xany.window == window->xwindow ? "client window" : (window->frame && event->xany.window == window->frame->xwindow) ? "frame window" : "unknown window", event->type != UnmapNotify ? meta_event_mode_to_string (event->xfocus.mode) : "n/a", event->type != UnmapNotify ? meta_event_detail_to_string (event->xfocus.detail) : "n/a"); /* FIXME our pointer tracking is broken; see how * gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c * handle it for the correct way. In brief you need to track * pointer focus and regular focus, and handle EnterNotify in * PointerRoot mode with no window manager. However as noted above, * accurate focus tracking will break things because we want to keep * windows "focused" when using keybindings on them, and also we * sometimes "focus" a window by focusing its frame or * no_focus_window; so this all needs rethinking massively. * * My suggestion is to change it so that we clearly separate * actual keyboard focus tracking using the xterm algorithm, * and muffin's "pretend" focus window, and go through all * the code and decide which one should be used in each place; * a hard bit is deciding on a policy for that. * * http://bugzilla.gnome.org/show_bug.cgi?id=90382 */ if ((event->type == FocusIn || event->type == FocusOut) && (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab || /* From WindowMaker, ignore all funky pointer root events */ event->xfocus.detail > NotifyNonlinearVirtual)) { meta_topic (META_DEBUG_FOCUS, "Ignoring focus event generated by a grab or other weirdness\n"); return TRUE; } if (event->type == FocusIn) { if (window->override_redirect) { window->display->focus_window = NULL; g_object_notify (G_OBJECT (window->display), "focus-window"); return FALSE; } if (window != window->display->focus_window) { meta_topic (META_DEBUG_FOCUS, "* Focus --> %s\n", window->desc); window->display->focus_window = window; window->has_focus = TRUE; /* Move to the front of the focusing workspace's MRU list. * We should only be "removing" it from the MRU list if it's * not already there. Note that it's possible that we might * be processing this FocusIn after we've changed to a * different workspace; we should therefore update the MRU * list only if the window is actually on the active * workspace. */ if (window->screen->active_workspace && meta_window_located_on_workspace (window, window->screen->active_workspace)) { GList* link; link = g_list_find (window->screen->active_workspace->mru_list, window); g_assert (link); window->screen->active_workspace->mru_list = g_list_remove_link (window->screen->active_workspace->mru_list, link); g_list_free (link); window->screen->active_workspace->mru_list = g_list_prepend (window->screen->active_workspace->mru_list, window); } if (window->frame) meta_frame_queue_draw (window->frame); meta_error_trap_push (window->display); XInstallColormap (window->display->xdisplay, window->colormap); meta_error_trap_pop (window->display); /* Ungrab click to focus button since the sync grab can interfere * with some things you might do inside the focused window, by * causing the client to get funky enter/leave events. * * The reason we usually have a passive grab on the window is * so that we can intercept clicks and raise the window in * response. For click-to-focus we don't need that since the * focused window is already raised. When raise_on_click is * FALSE we also don't need that since we don't do anything * when the window is clicked. * * There is dicussion in bugs 102209, 115072, and 461577 */ if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK || !meta_prefs_get_raise_on_click()) meta_display_ungrab_focus_window_button (window->display, window); g_signal_emit (window, window_signals[FOCUS], 0); g_object_notify (G_OBJECT (window->display), "focus-window"); if (!window->attached_focus_window) meta_window_appears_focused_changed (window); meta_window_propagate_focus_appearance (window, TRUE); } } else if (event->type == FocusOut || event->type == UnmapNotify) { if (event->type == FocusOut && event->xfocus.detail == NotifyInferior) { /* This event means the client moved focus to a subwindow */ meta_topic (META_DEBUG_FOCUS, "Ignoring focus out on %s with NotifyInferior\n", window->desc); return TRUE; } if (window == window->display->focus_window) { meta_topic (META_DEBUG_FOCUS, "%s is now the previous focus window due to being focused out or unmapped\n", window->desc); meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL (was %s)\n", window->desc); meta_window_propagate_focus_appearance (window, FALSE); window->display->focus_window = NULL; g_object_notify (G_OBJECT (window->display), "focus-window"); window->has_focus = FALSE; if (!window->attached_focus_window) meta_window_appears_focused_changed (window); meta_error_trap_push (window->display); XUninstallColormap (window->display->xdisplay, window->colormap); meta_error_trap_pop (window->display); /* Re-grab for click to focus and raise-on-click, if necessary */ if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK || !meta_prefs_get_raise_on_click ()) meta_display_grab_focus_window_button (window->display, window); } } /* Now set _NET_ACTIVE_WINDOW hint */ meta_display_update_active_window_hint (window->display); return FALSE; } static gboolean process_property_notify (MetaWindow *window, XPropertyEvent *event) { Window xid = window->xwindow; if (meta_is_verbose ()) /* avoid looking up the name if we don't have to */ { char *property_name = XGetAtomName (window->display->xdisplay, event->atom); meta_verbose ("Property notify on %s for %s\n", window->desc, property_name); XFree (property_name); } if (event->atom == window->display->atom__NET_WM_USER_TIME && window->user_time_window) { xid = window->user_time_window; } meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE); return TRUE; } static void send_configure_notify (MetaWindow *window) { g_return_if_fail (!window->override_redirect); XEvent event; /* from twm */ event.type = ConfigureNotify; event.xconfigure.display = window->display->xdisplay; event.xconfigure.event = window->xwindow; event.xconfigure.window = window->xwindow; event.xconfigure.x = window->rect.x - window->border_width; event.xconfigure.y = window->rect.y - window->border_width; if (window->frame) { if (window->withdrawn) { MetaFrameBorders borders; /* We reparent the client window and put it to the position * where the visible top-left of the frame window currently is. */ meta_frame_calc_borders (window->frame, &borders); event.xconfigure.x = window->frame->rect.x + borders.invisible.left; event.xconfigure.y = window->frame->rect.y + borders.invisible.top; } else { /* Need to be in root window coordinates */ event.xconfigure.x += window->frame->rect.x; event.xconfigure.y += window->frame->rect.y; } } event.xconfigure.width = window->rect.width; event.xconfigure.height = window->rect.height; event.xconfigure.border_width = window->border_width; /* requested not actual */ event.xconfigure.above = None; /* FIXME */ event.xconfigure.override_redirect = False; meta_topic (META_DEBUG_GEOMETRY, "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n", window->desc, event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height); meta_error_trap_push (window->display); XSendEvent (window->display->xdisplay, window->xwindow, False, StructureNotifyMask, &event); meta_error_trap_pop (window->display); } /* * meta_window_get_icon_geometry: * @window: a #MetaWindow * @rect: (out): rectangle into which to store the returned geometry. * * Gets the location of the icon corresponding to the window. The location * will be provided set by the task bar or other user interface element * displaying the icon, and is relative to the root window. * * Return value: %TRUE if the icon geometry was succesfully retrieved. */ gboolean meta_window_get_icon_geometry (MetaWindow *window, MetaRectangle *rect) { g_return_val_if_fail (!window->override_redirect, FALSE); if (window->icon_geometry_set) { if (rect) *rect = window->icon_geometry; return TRUE; } return FALSE; } /** * meta_window_set_icon_geometry: * @window: a #MetaWindow * @rect: (allow-none): rectangle with the desired geometry or %NULL. * * Sets or unsets the location of the icon corresponding to the window. If * set, the location should correspond to a dock, task bar or other user * interface element displaying the icon, and is relative to the root window. */ void meta_window_set_icon_geometry (MetaWindow *window, MetaRectangle *rect) { if (rect) { window->icon_geometry = *rect; window->icon_geometry_set = TRUE; } else { window->icon_geometry_set = FALSE; } } static Window read_client_leader (MetaDisplay *display, Window xwindow) { Window retval = None; meta_prop_get_window (display, xwindow, display->atom_WM_CLIENT_LEADER, &retval); return retval; } typedef struct { Window leader; } ClientLeaderData; static gboolean find_client_leader_func (MetaWindow *ancestor, void *data) { ClientLeaderData *d; d = data; d->leader = read_client_leader (ancestor->display, ancestor->xwindow); /* keep going if no client leader found */ return d->leader == None; } static void update_sm_hints (MetaWindow *window) { Window leader; window->xclient_leader = None; window->sm_client_id = NULL; /* If not on the current window, we can get the client * leader from transient parents. If we find a client * leader, we read the SM_CLIENT_ID from it. */ leader = read_client_leader (window->display, window->xwindow); if (leader == None) { ClientLeaderData d; d.leader = None; meta_window_foreach_ancestor (window, find_client_leader_func, &d); leader = d.leader; } if (leader != None) { char *str; window->xclient_leader = leader; if (meta_prop_get_latin1_string (window->display, leader, window->display->atom_SM_CLIENT_ID, &str)) { window->sm_client_id = g_strdup (str); meta_XFree (str); } } else { meta_verbose ("Didn't find a client leader for %s\n", window->desc); if (!meta_prefs_get_disable_workarounds ()) { /* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app * instead of the client leader */ char *str; str = NULL; if (meta_prop_get_latin1_string (window->display, window->xwindow, window->display->atom_SM_CLIENT_ID, &str)) { if (window->sm_client_id == NULL) /* first time through */ meta_warning ("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n", window->desc); window->sm_client_id = g_strdup (str); meta_XFree (str); } } } meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n", window->desc, window->xclient_leader, window->sm_client_id ? window->sm_client_id : "none"); } LOCAL_SYMBOL void meta_window_update_role (MetaWindow *window) { char *str; g_return_if_fail (!window->override_redirect); if (window->role) free (window->role); window->role = NULL; if (meta_prop_get_latin1_string (window->display, window->xwindow, window->display->atom_WM_WINDOW_ROLE, &str)) { window->role = g_strdup (str); meta_XFree (str); } meta_verbose ("Updated role of %s to '%s'\n", window->desc, window->role ? window->role : "null"); } LOCAL_SYMBOL void meta_window_update_net_wm_type (MetaWindow *window) { int n_atoms; Atom *atoms; int i; window->type_atom = None; n_atoms = 0; atoms = NULL; meta_prop_get_atom_list (window->display, window->xwindow, window->display->atom__NET_WM_WINDOW_TYPE, &atoms, &n_atoms); i = 0; while (i < n_atoms) { /* We break as soon as we find one we recognize, * supposed to prefer those near the front of the list */ if (atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DOCK || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_MENU || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_COMBO || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DND || atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) { window->type_atom = atoms[i]; break; } ++i; } meta_XFree (atoms); if (meta_is_verbose ()) { char *str; str = NULL; if (window->type_atom != None) { meta_error_trap_push (window->display); str = XGetAtomName (window->display->xdisplay, window->type_atom); meta_error_trap_pop (window->display); } meta_verbose ("Window %s type atom %s\n", window->desc, str ? str : "(none)"); if (str) meta_XFree (str); } meta_window_recalc_window_type (window); } void meta_window_icon_changed (MetaWindow *window) { g_clear_object (&window->icon); g_signal_emit (window, window_signals[ICON_CHANGED], 0, window); } /** * meta_window_create_icon: * @window: a #MetaWindow * @size: icon width and height * * Creates an icon for @window. This is intended to only be used for * window-backed apps. * * Return value: (transfer none): a #GdkPixbuf, or NULL. */ GdkPixbuf * meta_window_create_icon (MetaWindow *window, int size) { GdkPixbuf *icon; if (window->override_redirect) return NULL; if (window->icon) return window->icon; icon = NULL; if (meta_read_icons (window->screen, window->xwindow, &window->icon_cache, window->wm_hints_pixmap, window->wm_hints_mask, &icon, size, size)) { /* Cinnamon is handling the fallback icon case in CinnamonApp */ if (icon == NULL) return NULL; if (window->icon) g_object_unref (G_OBJECT (window->icon)); window->icon = icon; window->icon_size = size; return icon; } return NULL; } LOCAL_SYMBOL GList* meta_window_get_workspaces (MetaWindow *window) { if (window->on_all_workspaces) return window->screen->workspaces; else if (window->workspace != NULL) return window->workspace->list_containing_self; else return NULL; } static void invalidate_work_areas (MetaWindow *window) { GList *tmp; tmp = meta_window_get_workspaces (window); while (tmp != NULL) { meta_workspace_invalidate_work_area (tmp->data); tmp = tmp->next; } } void meta_window_update_struts (MetaWindow *window) { GSList *old_struts; GSList *new_struts; GSList *old_iter, *new_iter; gulong *struts = NULL; int nitems; gboolean changed; g_return_if_fail (!window->override_redirect); meta_verbose ("Updating struts for %s\n", window->desc); old_struts = window->struts; new_struts = NULL; if (meta_prop_get_cardinal_list (window->display, window->xwindow, window->display->atom__NET_WM_STRUT_PARTIAL, &struts, &nitems)) { if (nitems != 12) meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead " "of 12\n", window->desc, nitems); else { /* Pull out the strut info for each side in the hint */ int i; for (i=0; i<4; i++) { MetaStrut *temp; int thickness, strut_begin, strut_end; thickness = struts[i]; if (thickness == 0) continue; strut_begin = struts[4+(i*2)]; strut_end = struts[4+(i*2)+1]; temp = g_new (MetaStrut, 1); temp->side = 1 << i; /* See MetaSide def. Matches nicely, eh? */ temp->rect = window->screen->rect; switch (temp->side) { case META_SIDE_RIGHT: temp->rect.x = BOX_RIGHT(temp->rect) - thickness; /* Intentionally fall through without breaking */ case META_SIDE_LEFT: temp->rect.width = thickness; temp->rect.y = strut_begin; temp->rect.height = strut_end - strut_begin + 1; break; case META_SIDE_BOTTOM: temp->rect.y = BOX_BOTTOM(temp->rect) - thickness; /* Intentionally fall through without breaking */ case META_SIDE_TOP: temp->rect.height = thickness; temp->rect.x = strut_begin; temp->rect.width = strut_end - strut_begin + 1; break; default: g_assert_not_reached (); } new_struts = g_slist_prepend (new_struts, temp); } meta_verbose ("_NET_WM_STRUT_PARTIAL struts %lu %lu %lu %lu for " "window %s\n", struts[0], struts[1], struts[2], struts[3], window->desc); } meta_XFree (struts); } else { meta_verbose ("No _NET_WM_STRUT property for %s\n", window->desc); } if (!new_struts && meta_prop_get_cardinal_list (window->display, window->xwindow, window->display->atom__NET_WM_STRUT, &struts, &nitems)) { if (nitems != 4) meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4\n", window->desc, nitems); else { /* Pull out the strut info for each side in the hint */ int i; for (i=0; i<4; i++) { MetaStrut *temp; int thickness; thickness = struts[i]; if (thickness == 0) continue; temp = g_new (MetaStrut, 1); temp->side = 1 << i; temp->rect = window->screen->rect; switch (temp->side) { case META_SIDE_RIGHT: temp->rect.x = BOX_RIGHT(temp->rect) - thickness; /* Intentionally fall through without breaking */ case META_SIDE_LEFT: temp->rect.width = thickness; break; case META_SIDE_BOTTOM: temp->rect.y = BOX_BOTTOM(temp->rect) - thickness; /* Intentionally fall through without breaking */ case META_SIDE_TOP: temp->rect.height = thickness; break; default: g_assert_not_reached (); } new_struts = g_slist_prepend (new_struts, temp); } meta_verbose ("_NET_WM_STRUT struts %lu %lu %lu %lu for window %s\n", struts[0], struts[1], struts[2], struts[3], window->desc); } meta_XFree (struts); } else if (!new_struts) { meta_verbose ("No _NET_WM_STRUT property for %s\n", window->desc); } /* Determine whether old_struts and new_struts are the same */ old_iter = old_struts; new_iter = new_struts; while (old_iter && new_iter) { MetaStrut *old_strut = (MetaStrut*) old_iter->data; MetaStrut *new_strut = (MetaStrut*) new_iter->data; if (old_strut->side != new_strut->side || !meta_rectangle_equal (&old_strut->rect, &new_strut->rect)) break; old_iter = old_iter->next; new_iter = new_iter->next; } changed = (old_iter != NULL || new_iter != NULL); /* Update appropriately */ meta_free_gslist_and_elements (old_struts); window->struts = new_struts; if (changed) { meta_topic (META_DEBUG_WORKAREA, "Invalidating work areas of window %s due to struts update\n", window->desc); invalidate_work_areas (window); } else { meta_topic (META_DEBUG_WORKAREA, "Struts on %s were unchanged\n", window->desc); } } LOCAL_SYMBOL void meta_window_recalc_window_type (MetaWindow *window) { recalc_window_type (window); } static void recalc_window_type (MetaWindow *window) { MetaWindowType old_type; old_type = window->type; if (window->type_atom != None) { if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP) window->type = META_WINDOW_DESKTOP; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK) window->type = META_WINDOW_DOCK; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR) window->type = META_WINDOW_TOOLBAR; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU) window->type = META_WINDOW_MENU; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY) window->type = META_WINDOW_UTILITY; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH) window->type = META_WINDOW_SPLASHSCREEN; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG) window->type = META_WINDOW_DIALOG; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) window->type = META_WINDOW_NORMAL; /* The below are *typically* override-redirect windows, but the spec does * not disallow using them for managed windows. */ else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU) window->type = META_WINDOW_DROPDOWN_MENU; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU) window->type = META_WINDOW_POPUP_MENU; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP) window->type = META_WINDOW_TOOLTIP; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION) window->type = META_WINDOW_NOTIFICATION; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO) window->type = META_WINDOW_COMBO; else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND) window->type = META_WINDOW_DND; else { char *atom_name; /* * Fallback on a normal type, and print warning. Don't abort. */ window->type = META_WINDOW_NORMAL; meta_error_trap_push (window->display); atom_name = XGetAtomName (window->display->xdisplay, window->type_atom); meta_error_trap_pop (window->display); meta_warning ("Unrecognized type atom [%s] set for %s \n", atom_name ? atom_name : "unknown", window->desc); if (atom_name) XFree (atom_name); } } else if (window->xtransient_for != None) { window->type = META_WINDOW_DIALOG; } else { window->type = META_WINDOW_NORMAL; } if (window->type == META_WINDOW_DIALOG && window->wm_state_modal) window->type = META_WINDOW_MODAL_DIALOG; /* We don't want to allow override-redirect windows to have decorated-window * types since that's just confusing. */ if (window->override_redirect) { switch (window->type) { /* Decorated types */ case META_WINDOW_NORMAL: case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: case META_WINDOW_MENU: case META_WINDOW_UTILITY: window->type = META_WINDOW_OVERRIDE_OTHER; break; /* Undecorated types, normally not override-redirect */ case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_TOOLBAR: case META_WINDOW_SPLASHSCREEN: /* Undecorated types, normally override-redirect types */ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: /* To complete enum */ case META_WINDOW_OVERRIDE_OTHER: break; } } meta_verbose ("Calculated type %u for %s, old type %u\n", window->type, window->desc, old_type); if (old_type != window->type) { gboolean old_decorated = window->decorated; GObject *object = G_OBJECT (window); recalc_window_features (window); if (!window->override_redirect) set_net_wm_state (window); /* Update frame */ if (window->decorated) meta_window_ensure_frame (window); else meta_window_destroy_frame (window); /* update stacking constraints */ meta_window_update_layer (window); meta_window_grab_keys (window); g_object_freeze_notify (object); if (old_decorated != window->decorated) g_object_notify (object, "decorated"); g_object_notify (object, "window-type"); g_object_thaw_notify (object); } } void meta_window_frame_size_changed (MetaWindow *window) { if (window->frame) meta_frame_clear_cached_borders (window->frame); } static void set_allowed_actions_hint (MetaWindow *window) { #define MAX_N_ACTIONS 12 unsigned long data[MAX_N_ACTIONS]; int i; i = 0; if (window->has_move_func) { data[i] = window->display->atom__NET_WM_ACTION_MOVE; ++i; } if (window->has_resize_func) { data[i] = window->display->atom__NET_WM_ACTION_RESIZE; ++i; } if (window->has_fullscreen_func) { data[i] = window->display->atom__NET_WM_ACTION_FULLSCREEN; ++i; } if (window->has_minimize_func) { data[i] = window->display->atom__NET_WM_ACTION_MINIMIZE; ++i; } if (window->has_shade_func) { data[i] = window->display->atom__NET_WM_ACTION_SHADE; ++i; } /* sticky according to EWMH is different from muffin's sticky; * muffin doesn't support EWMH sticky */ if (window->has_maximize_func) { data[i] = window->display->atom__NET_WM_ACTION_MAXIMIZE_HORZ; ++i; data[i] = window->display->atom__NET_WM_ACTION_MAXIMIZE_VERT; ++i; } /* We always allow this */ data[i] = window->display->atom__NET_WM_ACTION_CHANGE_DESKTOP; ++i; if (window->has_close_func) { data[i] = window->display->atom__NET_WM_ACTION_CLOSE; ++i; } /* I guess we always allow above/below operations */ data[i] = window->display->atom__NET_WM_ACTION_ABOVE; ++i; data[i] = window->display->atom__NET_WM_ACTION_BELOW; ++i; g_assert (i <= MAX_N_ACTIONS); meta_verbose ("Setting _NET_WM_ALLOWED_ACTIONS with %d atoms\n", i); meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom__NET_WM_ALLOWED_ACTIONS, XA_ATOM, 32, PropModeReplace, (guchar*) data, i); meta_error_trap_pop (window->display); #undef MAX_N_ACTIONS } LOCAL_SYMBOL void meta_window_recalc_features (MetaWindow *window) { recalc_window_features (window); } static void recalc_window_features (MetaWindow *window) { gboolean old_has_close_func; gboolean old_has_minimize_func; gboolean old_has_move_func; gboolean old_has_resize_func; gboolean old_has_shade_func; gboolean old_always_sticky; gboolean old_skip_taskbar; old_has_close_func = window->has_close_func; old_has_minimize_func = window->has_minimize_func; old_has_move_func = window->has_move_func; old_has_resize_func = window->has_resize_func; old_has_shade_func = window->has_shade_func; old_always_sticky = window->always_sticky; old_skip_taskbar = window->skip_taskbar; /* Use MWM hints initially */ window->decorated = window->mwm_decorated; window->border_only = window->mwm_border_only; window->has_close_func = window->mwm_has_close_func; window->has_minimize_func = window->mwm_has_minimize_func; window->has_maximize_func = window->mwm_has_maximize_func; window->has_move_func = window->mwm_has_move_func; window->has_resize_func = TRUE; /* If min_size == max_size, then don't allow resize */ if (window->size_hints.min_width == window->size_hints.max_width && window->size_hints.min_height == window->size_hints.max_height) window->has_resize_func = FALSE; else if (!window->mwm_has_resize_func) { /* We ignore mwm_has_resize_func because WM_NORMAL_HINTS is the * authoritative source for that info. Some apps such as mplayer or * xine disable resize via MWM but not WM_NORMAL_HINTS, but that * leads to e.g. us not fullscreening their windows. Apps that set * MWM but not WM_NORMAL_HINTS are basically broken. We complain * about these apps but make them work. */ meta_warning ("Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n", window->desc, window->size_hints.min_width, window->size_hints.min_height, window->size_hints.max_width, window->size_hints.max_height); } window->has_shade_func = TRUE; window->has_fullscreen_func = TRUE; window->always_sticky = FALSE; /* Semantic category overrides the MWM hints */ if (window->type == META_WINDOW_TOOLBAR) window->decorated = FALSE; if (meta_window_is_attached_dialog (window)) window->border_only = TRUE; if (window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK || window->override_redirect) window->always_sticky = TRUE; if (window->override_redirect || meta_window_get_frame_type (window) == META_FRAME_TYPE_LAST) { window->decorated = FALSE; window->has_close_func = FALSE; window->has_shade_func = FALSE; /* FIXME this keeps panels and things from using * NET_WM_MOVERESIZE; the problem is that some * panels (edge panels) have fixed possible locations, * and others ("floating panels") do not. * * Perhaps we should require edge panels to explicitly * disable movement? */ window->has_move_func = FALSE; window->has_resize_func = FALSE; } if (window->type != META_WINDOW_NORMAL) { window->has_minimize_func = FALSE; window->has_maximize_func = FALSE; window->has_fullscreen_func = FALSE; } if (!window->has_resize_func) { window->has_maximize_func = FALSE; /* don't allow fullscreen if we can't resize, unless the size * is entire screen size (kind of broken, because we * actually fullscreen to monitor size not screen size) */ if (window->size_hints.min_width == window->screen->rect.width && window->size_hints.min_height == window->screen->rect.height) ; /* leave fullscreen available */ else window->has_fullscreen_func = FALSE; } /* We leave fullscreen windows decorated, just push the frame outside * the screen. This avoids flickering to unparent them. * * Note that setting has_resize_func = FALSE here must come after the * above code that may disable fullscreen, because if the window * is not resizable purely due to fullscreen, we don't want to * disable fullscreen mode. */ if (window->fullscreen) { window->has_shade_func = FALSE; window->has_move_func = FALSE; window->has_resize_func = FALSE; window->has_maximize_func = FALSE; } if (window->has_maximize_func) { MetaRectangle work_area; MetaFrameBorders borders; int min_frame_width, min_frame_height; meta_window_get_work_area_current_monitor (window, &work_area); meta_frame_calc_borders (window->frame, &borders); min_frame_width = window->size_hints.min_width + borders.visible.left + borders.visible.right; min_frame_height = window->size_hints.min_height + borders.visible.top + borders.visible.bottom; if (min_frame_width >= work_area.width || min_frame_height >= work_area.height) window->has_maximize_func = FALSE; } meta_topic (META_DEBUG_WINDOW_OPS, "Window %s fullscreen = %d not resizable, maximizable = %d fullscreenable = %d min size %dx%d max size %dx%d\n", window->desc, window->fullscreen, window->has_maximize_func, window->has_fullscreen_func, window->size_hints.min_width, window->size_hints.min_height, window->size_hints.max_width, window->size_hints.max_height); /* no shading if not decorated */ if (!window->decorated || window->border_only) window->has_shade_func = FALSE; window->skip_taskbar = FALSE; window->skip_pager = FALSE; if (window->wm_state_skip_taskbar) window->skip_taskbar = TRUE; if (window->wm_state_skip_pager) window->skip_pager = TRUE; switch (window->type) { /* Force skip taskbar/pager on these window types */ case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_TOOLBAR: case META_WINDOW_MENU: case META_WINDOW_UTILITY: case META_WINDOW_SPLASHSCREEN: case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: window->skip_taskbar = TRUE; window->skip_pager = TRUE; break; case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: /* only skip taskbar if we have a real transient parent */ if (window->xtransient_for != None && window->xtransient_for != window->screen->xroot) window->skip_taskbar = TRUE; break; case META_WINDOW_NORMAL: break; } meta_topic (META_DEBUG_WINDOW_OPS, "Window %s decorated = %d border_only = %d has_close = %d has_minimize = %d has_maximize = %d has_move = %d has_shade = %d skip_taskbar = %d skip_pager = %d\n", window->desc, window->decorated, window->border_only, window->has_close_func, window->has_minimize_func, window->has_maximize_func, window->has_move_func, window->has_shade_func, window->skip_taskbar, window->skip_pager); /* FIXME: * Lame workaround for recalc_window_features * being used overzealously. The fix is to * only recalc_window_features when something * has actually changed. */ if (window->constructing || old_has_close_func != window->has_close_func || old_has_minimize_func != window->has_minimize_func || old_has_move_func != window->has_move_func || old_has_resize_func != window->has_resize_func || old_has_shade_func != window->has_shade_func || old_always_sticky != window->always_sticky) set_allowed_actions_hint (window); if (window->has_resize_func != old_has_resize_func) g_object_notify (G_OBJECT (window), "resizeable"); meta_window_frame_size_changed (window); if (old_skip_taskbar != window->skip_taskbar) g_signal_emit_by_name (window->screen, "window-skip-taskbar-changed", window); /* FIXME perhaps should ensure if we don't have a shade func, * we aren't shaded, etc. */ } static void menu_callback (MetaWindowMenu *menu, Display *xdisplay, Window client_xwindow, guint32 timestamp, MetaMenuOp op, int workspace_index, gpointer data) { MetaDisplay *display; MetaWindow *window; MetaWorkspace *workspace; display = meta_display_for_x_display (xdisplay); window = meta_display_lookup_x_window (display, client_xwindow); workspace = NULL; if (window != NULL) /* window can be NULL */ { meta_verbose ("Menu op %u on %s\n", op, window->desc); switch (op) { case META_MENU_OP_NONE: /* nothing */ break; case META_MENU_OP_DELETE: meta_window_delete (window, timestamp); break; case META_MENU_OP_MINIMIZE: meta_window_minimize (window); break; case META_MENU_OP_UNMAXIMIZE: meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); break; case META_MENU_OP_MAXIMIZE: meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); break; case META_MENU_OP_UNSHADE: meta_window_unshade (window, timestamp); break; case META_MENU_OP_SHADE: meta_window_shade (window, timestamp); break; case META_MENU_OP_MOVE_LEFT: workspace = meta_workspace_get_neighbor (window->screen->active_workspace, META_MOTION_LEFT); break; case META_MENU_OP_MOVE_RIGHT: workspace = meta_workspace_get_neighbor (window->screen->active_workspace, META_MOTION_RIGHT); break; case META_MENU_OP_MOVE_UP: workspace = meta_workspace_get_neighbor (window->screen->active_workspace, META_MOTION_UP); break; case META_MENU_OP_MOVE_DOWN: workspace = meta_workspace_get_neighbor (window->screen->active_workspace, META_MOTION_DOWN); break; case META_MENU_OP_WORKSPACES: workspace = meta_screen_get_workspace_by_index (window->screen, workspace_index); break; case META_MENU_OP_MOVE_NEW: workspace = meta_screen_append_new_workspace (window->screen, FALSE, timestamp); GSettings *cinnamon = g_settings_new ("org.cinnamon"); g_settings_set_int (cinnamon, "number-workspaces", g_list_length (window->screen->workspaces)); g_object_unref (cinnamon); break; case META_MENU_OP_STICK: meta_window_stick (window); break; case META_MENU_OP_UNSTICK: meta_window_unstick (window); break; case META_MENU_OP_ABOVE: case META_MENU_OP_UNABOVE: if (window->wm_state_above == FALSE) meta_window_make_above (window); else meta_window_unmake_above (window); break; case META_MENU_OP_MOVE: meta_window_begin_grab_op (window, META_GRAB_OP_KEYBOARD_MOVING, TRUE, timestamp); break; case META_MENU_OP_RESIZE: if (window->tile_mode != META_TILE_NONE) { window->resize_tile_mode = window->tile_mode; window->resizing_tile_type = window->tile_type; } meta_window_begin_grab_op (window, META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN, TRUE, timestamp); break; case META_MENU_OP_RECOVER: meta_window_shove_titlebar_onscreen (window); break; default: meta_warning (G_STRLOC": Unknown window op\n"); break; } if (workspace) { meta_window_change_workspace (window, workspace); #if 0 meta_workspace_activate (workspace); meta_window_raise (window); #endif } } else { meta_verbose ("Menu callback on nonexistent window\n"); } if (display->window_menu == menu) { display->window_menu = NULL; display->window_with_menu = NULL; } meta_ui_window_menu_free (menu); } LOCAL_SYMBOL void meta_window_show_menu (MetaWindow *window, int root_x, int root_y, int button, guint32 timestamp) { MetaMenuOp ops; MetaMenuOp insensitive; MetaWindowMenu *menu; MetaWorkspaceLayout layout; int n_workspaces; // gboolean ltr; g_return_if_fail (!window->override_redirect); if (window->display->window_menu) { meta_ui_window_menu_free (window->display->window_menu); window->display->window_menu = NULL; window->display->window_with_menu = NULL; } ops = META_MENU_OP_NONE; insensitive = META_MENU_OP_NONE; //ops |= (META_MENU_OP_DELETE | META_MENU_OP_MINIMIZE | META_MENU_OP_MOVE | META_MENU_OP_RESIZE | META_MENU_OP_MOVE_NEW); ops |= (META_MENU_OP_DELETE | META_MENU_OP_MINIMIZE | META_MENU_OP_MOVE | META_MENU_OP_RESIZE); if (!meta_window_is_client_decorated (window) && !meta_window_titlebar_is_onscreen (window) && window->type != META_WINDOW_DOCK && window->type != META_WINDOW_DESKTOP) ops |= META_MENU_OP_RECOVER; if (!meta_prefs_get_workspaces_only_on_primary () || meta_window_is_on_primary_monitor (window)) { n_workspaces = meta_screen_get_n_workspaces (window->screen); if (n_workspaces > 1) ops |= META_MENU_OP_WORKSPACES; meta_screen_calc_workspace_layout (window->screen, n_workspaces, meta_workspace_index ( window->screen->active_workspace), &layout); // if (!window->on_all_workspaces) // { // ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR; // if (layout.current_col > 0) // ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT; // if ((layout.current_col < layout.cols - 1) && // (layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces)) // ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT; // if (layout.current_row > 0) // ops |= META_MENU_OP_MOVE_UP; // if ((layout.current_row < layout.rows - 1) && // ((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces)) // ops |= META_MENU_OP_MOVE_DOWN; // } meta_screen_free_workspace_layout (&layout); ops |= META_MENU_OP_UNSTICK; ops |= META_MENU_OP_STICK; } if (META_WINDOW_MAXIMIZED (window)) ops |= META_MENU_OP_UNMAXIMIZE; else ops |= META_MENU_OP_MAXIMIZE; #if 0 if (window->shaded) ops |= META_MENU_OP_UNSHADE; else ops |= META_MENU_OP_SHADE; #endif if (window->wm_state_above) ops |= META_MENU_OP_UNABOVE; else ops |= META_MENU_OP_ABOVE; if (!window->has_maximize_func) insensitive |= META_MENU_OP_UNMAXIMIZE | META_MENU_OP_MAXIMIZE; if (!window->has_minimize_func) insensitive |= META_MENU_OP_MINIMIZE; if (!window->has_close_func) insensitive |= META_MENU_OP_DELETE; if (!window->has_shade_func) insensitive |= META_MENU_OP_SHADE | META_MENU_OP_UNSHADE; if (!META_WINDOW_ALLOWS_MOVE (window)) insensitive |= META_MENU_OP_MOVE; if (!META_WINDOW_ALLOWS_RESIZE (window)) insensitive |= META_MENU_OP_RESIZE; if (window->always_sticky) insensitive |= META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES; if ((window->type == META_WINDOW_DESKTOP) || (window->type == META_WINDOW_DOCK) || (window->type == META_WINDOW_SPLASHSCREEN)) insensitive |= META_MENU_OP_ABOVE | META_MENU_OP_UNABOVE; /* If all operations are disabled, just quit without showing the menu. * This is the case, for example, with META_WINDOW_DESKTOP windows. */ if ((ops & ~insensitive) == 0) return; menu = meta_ui_window_menu_new (window->screen->ui, window->xwindow, ops, insensitive, meta_window_get_net_wm_desktop (window), meta_screen_get_n_workspaces (window->screen), menu_callback, NULL); window->display->window_menu = menu; window->display->window_with_menu = window; meta_verbose ("Popping up window menu for %s\n", window->desc); meta_ui_window_menu_popup (menu, root_x, root_y, button, timestamp); } LOCAL_SYMBOL void meta_window_shove_titlebar_onscreen (MetaWindow *window) { MetaRectangle outer_rect; GList *onscreen_region; int horiz_amount, vert_amount; int newx, newy; g_return_if_fail (!window->override_redirect); /* If there's no titlebar, don't bother */ if (!window->frame) return; /* Get the basic info we need */ meta_window_get_outer_rect (window, &outer_rect); onscreen_region = window->screen->active_workspace->screen_region; /* Extend the region (just in case the window is too big to fit on the * screen), then shove the window on screen, then return the region to * normal. */ horiz_amount = outer_rect.width; vert_amount = outer_rect.height; meta_rectangle_expand_region (onscreen_region, horiz_amount, horiz_amount, 0, vert_amount); meta_rectangle_shove_into_region(onscreen_region, FIXED_DIRECTION_X, &outer_rect); meta_rectangle_expand_region (onscreen_region, -horiz_amount, -horiz_amount, 0, -vert_amount); newx = outer_rect.x + window->frame->child_x; newy = outer_rect.y + window->frame->child_y; meta_window_move_resize (window, FALSE, newx, newy, window->rect.width, window->rect.height); } LOCAL_SYMBOL gboolean meta_window_titlebar_is_onscreen (MetaWindow *window) { MetaRectangle titlebar_rect; GList *onscreen_region; gboolean is_onscreen; const int min_height_needed = 8; const int min_width_percent = 0.5; const int min_width_absolute = 50; /* Titlebar can't be offscreen if there is no titlebar... */ if (!window->frame) return FALSE; /* Get the rectangle corresponding to the titlebar */ meta_window_get_outer_rect (window, &titlebar_rect); titlebar_rect.height = window->frame->child_y; /* Run through the spanning rectangles for the screen and see if one of * them overlaps with the titlebar sufficiently to consider it onscreen. */ is_onscreen = FALSE; onscreen_region = window->screen->active_workspace->screen_region; while (onscreen_region) { MetaRectangle *spanning_rect = onscreen_region->data; MetaRectangle overlap; meta_rectangle_intersect (&titlebar_rect, spanning_rect, &overlap); if (overlap.height > MIN (titlebar_rect.height, min_height_needed) && overlap.width > MIN (titlebar_rect.width * min_width_percent, min_width_absolute)) { is_onscreen = TRUE; break; } onscreen_region = onscreen_region->next; } return is_onscreen; } static double timeval_to_ms (const GTimeVal *timeval) { return (timeval->tv_sec * G_USEC_PER_SEC + timeval->tv_usec) / 1000.0; } static double time_diff (const GTimeVal *first, const GTimeVal *second) { double first_ms = timeval_to_ms (first); double second_ms = timeval_to_ms (second); return first_ms - second_ms; } static gboolean check_moveresize_frequency (MetaWindow *window, gdouble *remaining) { GTimeVal current_time; const double max_resizes_per_second = 25.0; const double ms_between_resizes = 1000.0 / max_resizes_per_second; double elapsed; g_get_current_time (¤t_time); #ifdef HAVE_XSYNC /* If we are throttling via _NET_WM_SYNC_REQUEST, we don't need * an artificial timeout-based throttled */ if (!window->disable_sync && window->sync_request_alarm != None) return TRUE; #endif /* HAVE_XSYNC */ elapsed = time_diff (¤t_time, &window->display->grab_last_moveresize_time); if (elapsed >= 0.0 && elapsed < ms_between_resizes) { meta_topic (META_DEBUG_RESIZING, "Delaying move/resize as only %g of %g ms elapsed\n", elapsed, ms_between_resizes); if (remaining) *remaining = (ms_between_resizes - elapsed); return FALSE; } meta_topic (META_DEBUG_RESIZING, " Checked moveresize freq, allowing move/resize now (%g of %g seconds elapsed)\n", elapsed / 1000.0, 1.0 / max_resizes_per_second); return TRUE; } static gboolean update_move_timeout (gpointer data) { MetaWindow *window = data; update_move (window, window->display->grab_last_user_action_was_snap, window->snap_queued, window->display->grab_latest_motion_x, window->display->grab_latest_motion_y); return FALSE; } guint meta_window_get_current_zone (MetaWindow *window, MetaRectangle monitor, MetaRectangle work_area, int x, int y, int zone_threshold) { TileZone edge_zone = 0; guint zone = ZONE_NONE; /* First, establish edges, with top and bottom first, so they take priority in the corners */ if (y >= monitor.y && y <= work_area.y + zone_threshold) edge_zone |= ZONE_TOP; if (y >= (work_area.y + work_area.height - zone_threshold) && y < (monitor.y + monitor.height)) edge_zone |= ZONE_BOTTOM; if (x >= monitor.x && x < (work_area.x + zone_threshold)) edge_zone |= ZONE_LEFT; if (x >= (work_area.x + work_area.width - zone_threshold) && x < (monitor.x + monitor.width)) edge_zone |= ZONE_RIGHT; /* Now for each edge zone, we can figure out the specific subzone we're in */ /* split the screen into a 4 x 4 grid.. the middle 2 boxes along each edge are considered a single zone though, so effectively we'll have 3 zones per edge */ switch (edge_zone) { case ZONE_ULC: if (meta_window_can_tile_corner (window)) zone = ZONE_4; break; case ZONE_LLC: if (meta_window_can_tile_corner (window)) zone = ZONE_7; break; case ZONE_URC: if (meta_window_can_tile_corner (window)) zone = ZONE_5; break; case ZONE_LRC: if (meta_window_can_tile_corner (window)) zone = ZONE_6; break; case ZONE_TOP: if (meta_prefs_get_tile_maximize() || window->maybe_retile_maximize) { if (meta_window_can_tile_maximized(window)) zone = ZONE_0; } else if (meta_window_can_tile_top_bottom (window)) zone = ZONE_0; break; case ZONE_BOTTOM: if (meta_window_can_tile_top_bottom (window)) zone = ZONE_1; break; case ZONE_LEFT: if (meta_window_can_tile_side_by_side (window)) zone = ZONE_2; break; case ZONE_RIGHT: if (meta_window_can_tile_side_by_side (window)) zone = ZONE_3; break; default: zone = ZONE_NONE; break; } return zone; } static unsigned int get_mask_from_snap_keysym (MetaWindow *window) { unsigned int *pref = meta_prefs_get_snap_modifier (); return XkbKeysymToModifiers(window->display->xdisplay, pref[0]); } static inline void get_size_limits (const MetaWindow *window, const MetaFrameBorders *borders, gboolean include_frame, MetaRectangle *min_size, MetaRectangle *max_size) { /* We pack the results into MetaRectangle structs just for convienience; we * don't actually use the position of those rects. */ min_size->width = window->size_hints.min_width; min_size->height = window->size_hints.min_height; max_size->width = window->size_hints.max_width; max_size->height = window->size_hints.max_height; if (include_frame) { int fw = borders->visible.left + borders->visible.right; int fh = borders->visible.top + borders->visible.bottom; min_size->width += fw; min_size->height += fh; /* Do check to avoid overflow (e.g. max_size->width & max_size->height * may be set to G_MAXINT by meta_set_normal_hints()). */ if (max_size->width < (G_MAXINT - fw)) max_size->width += fw; else max_size->width = G_MAXINT; if (max_size->height < (G_MAXINT - fh)) max_size->height += fh; else max_size->height = G_MAXINT; } } static void update_move (MetaWindow *window, gboolean legacy_snap, gboolean snap_mode, int x, int y) { int dx, dy; int new_x, new_y; MetaRectangle old; int breakloose_threshold; MetaDisplay *display = window->display; display->grab_latest_motion_x = x; display->grab_latest_motion_y = y; dx = x - display->grab_anchor_root_x; dy = y - display->grab_anchor_root_y; new_x = display->grab_anchor_window_pos.x + dx; new_y = display->grab_anchor_window_pos.y + dy; meta_verbose ("x,y = %d,%d anchor ptr %d,%d anchor pos %d,%d dx,dy %d,%d\n", x, y, display->grab_anchor_root_x, display->grab_anchor_root_y, display->grab_anchor_window_pos.x, display->grab_anchor_window_pos.y, dx, dy); if (snap_mode) window->snap_queued = TRUE; else window->snap_queued = FALSE; /* Don't bother doing anything if no move has been specified. (This * happens often, even in keyboard moving, due to the warping of the * pointer. */ if (dx == 0 && dy == 0) return; /* Originally for detaching maximized windows, but we use this * for the zones at the sides of the monitor where trigger tiling * because it's about the right size */ if (legacy_snap && meta_prefs_get_legacy_snap ()) { /* We don't want to tile while snapping. Also, clear any previous tile request. */ window->tile_mode = META_TILE_NONE; window->tile_monitor_number = -1; } else if (meta_prefs_get_edge_tiling () && !META_WINDOW_TILED_OR_SNAPPED (window)) { const MetaMonitorInfo *monitor; MetaRectangle work_area; /* For side-by-side tiling we are interested in the inside vertical * edges of the work area of the monitor where the pointer is located, * and in the outside top edge for maximized tiling. * * For maximized tiling we use the outside edge instead of the * inside edge, because we don't want to force users to maximize * windows they are placing near the top of their screens. * * The "current" idea of meta_window_get_work_area_current_monitor() and * meta_screen_get_current_monitor() is slightly different: the former * refers to the monitor which contains the largest part of the window, * the latter to the one where the pointer is located. */ monitor = meta_screen_get_current_monitor_info (window->screen); meta_window_get_work_area_for_monitor (window, monitor->number, &work_area); /* Check if the cursor is in a position which triggers tiling * and set tile_mode accordingly. */ window->current_proximity_zone = meta_window_get_current_zone (window, monitor->rect, work_area, x, y, meta_prefs_get_tile_hud_threshold ()); guint edge_zone = meta_window_get_current_zone (window, monitor->rect, work_area, x, y, HUD_WIDTH * meta_prefs_get_ui_scale ()); switch (edge_zone) { case ZONE_0: window->tile_mode = window->maybe_retile_maximize ? META_TILE_MAXIMIZE : (meta_prefs_get_tile_maximize() ? META_TILE_MAXIMIZE : META_TILE_TOP); break; case ZONE_1: window->tile_mode = META_TILE_BOTTOM; break; case ZONE_2: window->tile_mode = META_TILE_LEFT; break; case ZONE_3: window->tile_mode = META_TILE_RIGHT; break; case ZONE_4: window->tile_mode = META_TILE_ULC; break; case ZONE_5: window->tile_mode = META_TILE_URC; break; case ZONE_6: window->tile_mode = META_TILE_LRC; break; case ZONE_7: window->tile_mode = META_TILE_LLC; break; default: window->tile_mode = META_TILE_NONE; break; } if (window->tile_mode != META_TILE_NONE) window->tile_monitor_number = monitor->number; } update_edge_constraints (window); /* shake loose (unmaximize) maximized or tiled window if dragged beyond * the threshold in the Y direction. Tiled windows can also be pulled * loose via X motion. */ breakloose_threshold = meta_prefs_get_resize_threshold () * 2; if (window->tile_type == META_WINDOW_TILE_TYPE_SNAPPED) breakloose_threshold *= 2; if ((META_WINDOW_MAXIMIZED (window) && ABS (dy) >= breakloose_threshold) || (META_WINDOW_MAXIMIZED_VERTICALLY (window) && ABS (dy) >= breakloose_threshold) || (META_WINDOW_MAXIMIZED_HORIZONTALLY (window) && ABS (dx) >= breakloose_threshold) || (META_WINDOW_TILED_OR_SNAPPED (window) && (MAX (ABS (dx), ABS (dy)) >= breakloose_threshold))) { double prop; /* Shake loose, so that the window snaps back to maximized * when dragged near the top; do not snap back if tiling * is enabled, as top edge tiling can be used in that case */ window->shaken_loose = !meta_prefs_get_edge_tiling (); if (window->saved_maximize) window->maybe_retile_maximize = TRUE; window->tile_mode = META_TILE_NONE; /* move the unmaximized window to the cursor */ prop = ((double)(x - display->grab_initial_window_pos.x)) / ((double)display->grab_initial_window_pos.width); display->grab_initial_window_pos.x = x - window->saved_rect.width * prop; if (window->frame) { display->grab_initial_window_pos.y = y + (window->frame->child_y / 2); display->grab_anchor_root_x = x; display->grab_anchor_root_y = y; } window->saved_rect.x = display->grab_initial_window_pos.x; window->saved_rect.y = display->grab_initial_window_pos.y; meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); return; } /* remaximize window on another monitor if window has been shaken * loose or it is still maximized (then move straight) */ else if ((window->shaken_loose || META_WINDOW_MAXIMIZED (window)) && window->tile_mode != META_TILE_LEFT && window->tile_mode != META_TILE_RIGHT) { const MetaMonitorInfo *wmonitor; MetaRectangle work_area; int monitor; window->tile_mode = META_TILE_NONE; wmonitor = meta_screen_get_monitor_for_window (window->screen, window); for (monitor = 0; monitor < window->screen->n_monitor_infos; monitor++) { meta_window_get_work_area_for_monitor (window, monitor, &work_area); /* check if cursor is near the top of a monitor work area */ if (x >= work_area.x && x < (work_area.x + work_area.width) && y >= work_area.y && y < (work_area.y + breakloose_threshold)) { /* move the saved rect if window will become maximized on an * other monitor so user isn't surprised on a later unmaximize */ if (wmonitor->number != monitor) { window->saved_rect.x = work_area.x; window->saved_rect.y = work_area.y; if (window->frame) { window->saved_rect.x += window->frame->child_x; window->saved_rect.y += window->frame->child_y; } window->user_rect.x = window->saved_rect.x; window->user_rect.y = window->saved_rect.y; meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } display->grab_initial_window_pos = work_area; display->grab_anchor_root_x = x; display->grab_anchor_root_y = y; window->shaken_loose = FALSE; meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); return; } } } window->mouse_on_edge = meta_window_mouse_on_edge (window, x, y); MetaRectangle min_size, max_size, target_size; gboolean hminbad = FALSE; gboolean vminbad = FALSE; { if (meta_prefs_get_edge_tiling ()) { if (window->current_proximity_zone != ZONE_NONE && !window->mouse_on_edge) meta_screen_tile_hud_update (window->screen, TRUE, FALSE); else meta_screen_tile_hud_update (window->screen, TRUE, TRUE); } if (window->tile_mode == META_TILE_NONE) { meta_screen_tile_preview_hide (window->screen); } else { get_size_limits (window, NULL, FALSE, &min_size, &max_size); meta_window_get_current_tile_area (window, &target_size); MetaFrameBorders borders; meta_frame_calc_borders (window->frame, &borders); meta_window_unextend_by_frame (window, &target_size, &borders); hminbad = target_size.width < min_size.width; vminbad = target_size.height < min_size.height; /* Delay showing the tile preview slightly to make it more unlikely to * trigger it unwittingly, e.g. when shaking loose the window or moving * it to another monitor. */ if (!hminbad && !vminbad) meta_screen_tile_preview_update (window->screen, window->tile_mode != META_TILE_NONE && !window->screen->tile_preview_visible); else meta_screen_tile_preview_hide (window->screen); } } meta_window_get_client_root_coords (window, &old); /* Don't allow movement in the maximized directions or while tiled */ if (window->maximized_horizontally || META_WINDOW_TILED_OR_SNAPPED (window)) new_x = old.x; if (window->maximized_vertically) new_y = old.y; /* Do any edge resistance/snapping */ meta_window_edge_resistance_for_move (window, old.x, old.y, &new_x, &new_y, update_move_timeout, legacy_snap && meta_prefs_get_legacy_snap (), FALSE); meta_window_move (window, TRUE, new_x, new_y); } /* When resizing a maximized window by using alt-middle-drag (resizing * with the grips or the menu for a maximized window is not enabled), * the user can "break" out of the maximized state. This checks for * that possibility. During such a break-out resize the user can also * return to the previous maximization state by resizing back to near * the original size. */ static MetaMaximizeFlags check_resize_unmaximize(MetaWindow *window, int dx, int dy) { int threshold; MetaMaximizeFlags new_unmaximize; threshold = meta_prefs_get_resize_threshold (); new_unmaximize = 0; if (window->maximized_horizontally || window->tile_mode != META_TILE_NONE || (window->display->grab_resize_unmaximize & META_MAXIMIZE_HORIZONTAL) != 0) { int x_amount; /* We allow breaking out of maximization in either direction, to make * the window larger than the monitor as well as smaller than the * monitor. If we wanted to only allow resizing smaller than the * monitor, we'd use - dx for NE/E/SE and dx for SW/W/NW. */ switch (window->display->grab_op) { case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: x_amount = dx < 0 ? - dx : dx; break; default: x_amount = 0; break; } if (x_amount > threshold) new_unmaximize |= META_MAXIMIZE_HORIZONTAL; } if (window->maximized_vertically || window->tile_mode != META_TILE_NONE || (window->display->grab_resize_unmaximize & META_MAXIMIZE_VERTICAL) != 0) { int y_amount; switch (window->display->grab_op) { case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_SW: y_amount = dy < 0 ? - dy : dy; break; default: y_amount = 0; break; } if (y_amount > threshold) new_unmaximize |= META_MAXIMIZE_VERTICAL; } /* Metacity doesn't have a full user interface for only horizontally or * vertically maximized, so while only unmaximizing in the direction drags * has some advantages, it will also confuse the user. So, we always * unmaximize both ways if possible. */ if (new_unmaximize != 0) { new_unmaximize = 0; if (window->maximized_horizontally || (window->display->grab_resize_unmaximize & META_MAXIMIZE_HORIZONTAL) != 0) new_unmaximize |= META_MAXIMIZE_HORIZONTAL; if ((window->tile_type == META_WINDOW_TILE_TYPE_NONE || window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE) && (window->maximized_vertically || (window->display->grab_resize_unmaximize & META_MAXIMIZE_VERTICAL) != 0)) new_unmaximize |= META_MAXIMIZE_VERTICAL; } return new_unmaximize; } static gboolean update_resize_timeout (gpointer data) { MetaWindow *window = data; update_resize (window, window->display->grab_last_user_action_was_snap, window->display->grab_latest_motion_x, window->display->grab_latest_motion_y, TRUE); return FALSE; } static void update_resize (MetaWindow *window, gboolean snap, int x, int y, gboolean force) { int dx, dy; int new_w, new_h; int gravity; MetaRectangle old; double remaining; MetaMaximizeFlags new_unmaximize; window->display->grab_latest_motion_x = x; window->display->grab_latest_motion_y = y; dx = x - window->display->grab_anchor_root_x; dy = y - window->display->grab_anchor_root_y; /* Don't bother doing anything if no move has been specified. (This * happens often, even in keyboard resizing, due to the warping of the * pointer. */ if (dx == 0 && dy == 0) return; /* Attached modal dialogs are special in that size * changes apply to both sides, so that the dialog * remains centered to the parent. */ if (meta_window_is_attached_dialog (window)) { dx *= 2; dy *= 2; } new_w = window->display->grab_anchor_window_pos.width; new_h = window->display->grab_anchor_window_pos.height; if (window->display->grab_op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN) { if (window->tile_mode == META_TILE_NONE) { if ((dx > 0) && (dy > 0)) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SE; meta_window_update_keyboard_resize (window, TRUE); } else if ((dx < 0) && (dy > 0)) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SW; meta_window_update_keyboard_resize (window, TRUE); } else if ((dx > 0) && (dy < 0)) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NE; meta_window_update_keyboard_resize (window, TRUE); } else if ((dx < 0) && (dy < 0)) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NW; meta_window_update_keyboard_resize (window, TRUE); } else if (dx < 0) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; meta_window_update_keyboard_resize (window, TRUE); } else if (dx > 0) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; meta_window_update_keyboard_resize (window, TRUE); } else if (dy > 0) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; meta_window_update_keyboard_resize (window, TRUE); } else if (dy < 0) { window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; meta_window_update_keyboard_resize (window, TRUE); } } else { switch (window->tile_mode) { case META_TILE_LEFT: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; break; case META_TILE_RIGHT: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; break; case META_TILE_TOP: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; break; case META_TILE_BOTTOM: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; break; case META_TILE_ULC: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SE; break; case META_TILE_LLC: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NE; break; case META_TILE_URC: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SW; break; case META_TILE_LRC: window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NW; break; default: break; } meta_window_update_keyboard_resize (window, TRUE); } } new_unmaximize = check_resize_unmaximize (window, dx, dy); switch (window->display->grab_op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_E: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_RIGHT)) new_w += dx; break; case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_W: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_LEFT)) new_w -= dx; break; default: break; } switch (window->display->grab_op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_SW: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_DOWN)) new_h += dy; break; case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_NW: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_UP)) new_h -= dy; break; default: break; } #ifdef HAVE_XSYNC /* If we're waiting for a request for _NET_WM_SYNC_REQUEST, we'll * resize the window when the window responds, or when we time * the response out. */ if (window->sync_request_timeout_id != 0) return; #endif if (!check_moveresize_frequency (window, &remaining) && !force) { /* we are ignoring an event here, so we schedule a * compensation event when we would otherwise not ignore * an event. Otherwise we can become stuck if the user never * generates another event. */ if (!window->display->grab_resize_timeout_id) { window->display->grab_resize_timeout_id = g_timeout_add ((int)remaining, update_resize_timeout, window); } return; } /* Remove any scheduled compensation events */ if (window->display->grab_resize_timeout_id) { g_source_remove (window->display->grab_resize_timeout_id); window->display->grab_resize_timeout_id = 0; } old = window->rect; /* Don't actually care about x,y */ /* One sided resizing ought to actually be one-sided, despite the fact that * aspect ratio windows don't interact nicely with the above stuff. So, * to avoid some nasty flicker, we enforce that. */ switch (window->display->grab_op) { case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_N: new_w = old.width; break; case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_W: new_h = old.height; break; default: break; } /* compute gravity of client during operation */ if (window->tile_mode != META_TILE_NONE) gravity = meta_resize_gravity_from_tile_mode (window->tile_mode); else gravity = meta_resize_gravity_from_grab_op (window->display->grab_op); g_assert (gravity >= 0); /* Do any edge resistance/snapping */ meta_window_edge_resistance_for_resize (window, old.width, old.height, &new_w, &new_h, gravity, update_resize_timeout, snap, FALSE); if (new_unmaximize == window->display->grab_resize_unmaximize && window->tile_type == META_WINDOW_TILE_TYPE_NONE) { /* We don't need to update unless the specified width and height * are actually different from what we had before. */ if (old.width != new_w || old.height != new_h) { meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity); } } else { if ((new_unmaximize & ~window->display->grab_resize_unmaximize) != 0) { meta_window_unmaximize_with_gravity (window, (new_unmaximize & ~window->display->grab_resize_unmaximize), new_w, new_h, gravity); } if (window->tile_type != META_WINDOW_TILE_TYPE_NONE) { if (window->tile_mode != META_TILE_NONE) { window->resize_tile_mode = window->tile_mode; window->resizing_tile_type = window->tile_type; } meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity); } if (window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE && (window->display->grab_resize_unmaximize & ~new_unmaximize)) { MetaRectangle saved_rect = window->saved_rect; meta_window_maximize (window, (window->display->grab_resize_unmaximize & ~new_unmaximize)); window->saved_rect = saved_rect; } } window->display->grab_resize_unmaximize = new_unmaximize; /* Store the latest resize time, if we actually resized. */ if (window->rect.width != old.width || window->rect.height != old.height) g_get_current_time (&window->display->grab_last_moveresize_time); } typedef struct { const XEvent *current_event; int count; guint32 last_time; } EventScannerData; static Bool find_last_time_predicate (Display *display, XEvent *xevent, XPointer arg) { EventScannerData *esd = (void*) arg; if (esd->current_event->type == xevent->type && esd->current_event->xany.window == xevent->xany.window) { esd->count += 1; esd->last_time = xevent->xmotion.time; } return False; } static gboolean check_use_this_motion_notify (MetaWindow *window, XEvent *event) { EventScannerData esd; XEvent useless; /* This code is copied from Owen's GDK code. */ if (window->display->grab_motion_notify_time != 0) { /* == is really the right test, but I'm all for paranoia */ if (window->display->grab_motion_notify_time <= event->xmotion.time) { meta_topic (META_DEBUG_RESIZING, "Arrived at event with time %u (waiting for %u), using it\n", (unsigned int)event->xmotion.time, window->display->grab_motion_notify_time); window->display->grab_motion_notify_time = 0; return TRUE; } else return FALSE; /* haven't reached the saved timestamp yet */ } esd.current_event = event; esd.count = 0; esd.last_time = 0; /* "useless" isn't filled in because the predicate never returns True */ XCheckIfEvent (window->display->xdisplay, &useless, find_last_time_predicate, (XPointer) &esd); #ifdef WITH_VERBOSE_MODE if (esd.count > 0) meta_topic (META_DEBUG_RESIZING, "Will skip %d motion events and use the event with time %u\n", esd.count, (unsigned int) esd.last_time); #endif if (esd.last_time == 0) return TRUE; else { /* Save this timestamp, and ignore all motion notify * until we get to the one with this stamp. */ window->display->grab_motion_notify_time = esd.last_time; return FALSE; } } static void update_tile_mode (MetaWindow *window) { switch (window->tile_mode) { case META_TILE_LEFT: case META_TILE_RIGHT: case META_TILE_ULC: case META_TILE_LLC: case META_TILE_URC: case META_TILE_LRC: case META_TILE_TOP: case META_TILE_BOTTOM: case META_TILE_MAXIMIZE: if (!META_WINDOW_TILED_OR_SNAPPED (window)) window->tile_mode = META_TILE_NONE; break; } } #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, gint64 new_counter_value) { gboolean needs_frame_drawn = FALSE; gboolean no_delay_frame = FALSE; if (window->extended_sync_request_counter && new_counter_value % 2 == 0) { needs_frame_drawn = TRUE; no_delay_frame = new_counter_value == window->sync_request_serial + 1; } window->sync_request_serial = new_counter_value; meta_compositor_set_updates_frozen (window->display->compositor, window, meta_window_updates_are_frozen (window)); if (window == window->display->grab_window && meta_grab_op_is_resizing (window->display->grab_op) && new_counter_value >= window->sync_request_wait_serial && (!window->extended_sync_request_counter || new_counter_value % 2 == 0) && window->sync_request_timeout_id) { meta_topic (META_DEBUG_RESIZING, "Alarm event received last motion x = %d y = %d\n", window->display->grab_latest_motion_x, window->display->grab_latest_motion_y); g_source_remove (window->sync_request_timeout_id); window->sync_request_timeout_id = 0; /* This means we are ready for another configure; * no pointer round trip here, to keep in sync */ update_resize (window, window->display->grab_last_user_action_was_snap, window->display->grab_latest_motion_x, window->display->grab_latest_motion_y, TRUE); } /* If sync was previously disabled, turn it back on and hope * the application has come to its senses (maybe it was just * busy with a pagefault or a long computation). */ window->disable_sync = FALSE; if (needs_frame_drawn) meta_compositor_queue_frame_drawn (window->display->compositor, window, no_delay_frame); } #endif /* HAVE_XSYNC */ LOCAL_SYMBOL void meta_window_handle_mouse_grab_op_event (MetaWindow *window, XEvent *event) { #ifdef HAVE_XSYNC if (event->type == (window->display->xsync_event_base + XSyncAlarmNotify)) { meta_topic (META_DEBUG_RESIZING, "Alarm event received last motion x = %d y = %d\n", window->display->grab_latest_motion_x, window->display->grab_latest_motion_y); /* If sync was previously disabled, turn it back on and hope * the application has come to its senses (maybe it was just * busy with a pagefault or a long computation). */ window->disable_sync = FALSE; meta_window_destroy_sync_request_alarm (window); /* This means we are ready for another configure. */ switch (window->display->grab_op) { case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: /* no pointer round trip here, to keep in sync */ update_resize (window, window->display->grab_last_user_action_was_snap, window->display->grab_latest_motion_x, window->display->grab_latest_motion_y, TRUE); break; default: break; } } #endif /* HAVE_XSYNC */ switch (event->type) { case ButtonRelease: meta_display_check_threshold_reached (window->display, event->xbutton.x_root, event->xbutton.y_root); /* If the user was snap moving then ignore the button release * because they may have let go of shift before releasing the * mouse button and they almost certainly do not want a * non-snapped movement to occur from the button release. */ if (!window->display->grab_last_user_action_was_snap) { if (meta_grab_op_is_moving (window->display->grab_op)) { if (window->tile_mode != META_TILE_NONE && meta_window_mouse_on_edge (window, event->xbutton.x_root, event->xbutton.y_root)) { window->custom_snap_size = FALSE; if (window->tile_mode == META_TILE_MAXIMIZE) meta_window_maximize(window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL); else meta_window_real_tile (window, FALSE); } else if (event->xbutton.root == window->screen->xroot) update_move (window, event->xbutton.state & ShiftMask, event->xbutton.state & get_mask_from_snap_keysym (window), event->xbutton.x_root, event->xbutton.y_root); if (meta_prefs_get_edge_tiling ()) meta_screen_tile_hud_update (window->screen, FALSE, TRUE); } else if (meta_grab_op_is_resizing (window->display->grab_op)) { if (event->xbutton.root == window->screen->xroot) update_resize (window, event->xbutton.state & ShiftMask, event->xbutton.x_root, event->xbutton.y_root, TRUE); } /* If a tiled window has been dragged free with a * mouse resize without snapping back to the tiled * state, it will end up with an inconsistent tile * mode on mouse release; cleaning the mode earlier * would break the ability to snap back to the tiled * state, so we wait until mouse release. */ if (window->tile_type == META_WINDOW_TILE_TYPE_NONE) update_tile_mode (window); } window->maybe_retile_maximize = FALSE; meta_display_end_grab_op (window->display, event->xbutton.time); break; case MotionNotify: meta_display_check_threshold_reached (window->display, event->xmotion.x_root, event->xmotion.y_root); if (meta_grab_op_is_moving (window->display->grab_op)) { if (event->xmotion.root == window->screen->xroot) { if (check_use_this_motion_notify (window, event)) update_move (window, event->xmotion.state & ShiftMask, event->xmotion.state & get_mask_from_snap_keysym (window), event->xmotion.x_root, event->xmotion.y_root); } } else if (meta_grab_op_is_resizing (window->display->grab_op)) { if (event->xmotion.root == window->screen->xroot) { if (check_use_this_motion_notify (window, event)) update_resize (window, event->xmotion.state & ShiftMask, event->xmotion.x_root, event->xmotion.y_root, FALSE); } } break; default: break; } } LOCAL_SYMBOL void meta_window_handle_keyboard_grab_op_event (MetaWindow *window, XEvent *event) { switch (event->type) { case KeyPress: case KeyRelease: meta_display_check_threshold_reached (window->display, event->xmotion.x_root, event->xmotion.y_root); if (window->display->grab_op == META_GRAB_OP_MOVING) { if (event->xmotion.root == window->screen->xroot) { if (check_use_this_motion_notify (window, event)) { unsigned int *mod_set = meta_prefs_get_snap_modifier (); KeySym keysym = XkbKeycodeToKeysym (window->display->xdisplay, event->xkey.keycode, 0, 0); if (mod_set[0] != 0) { gboolean snap = FALSE; if (event->type == KeyPress && (keysym == mod_set[0] || keysym == mod_set[1])) snap = TRUE; update_move (window, event->xmotion.state & ShiftMask, snap, event->xmotion.x_root, event->xmotion.y_root); } } } } break; default: break; } } LOCAL_SYMBOL void meta_window_set_gravity (MetaWindow *window, int gravity) { XSetWindowAttributes attrs; meta_verbose ("Setting gravity of %s to %d\n", window->desc, gravity); attrs.win_gravity = gravity; meta_error_trap_push (window->display); XChangeWindowAttributes (window->display->xdisplay, window->xwindow, CWWinGravity, &attrs); meta_error_trap_pop (window->display); } static void get_work_area_monitor (MetaWindow *window, MetaRectangle *area, int which_monitor) { GList *tmp; g_assert (which_monitor >= 0); /* Initialize to the whole monitor */ *area = window->screen->monitor_infos[which_monitor].rect; tmp = meta_window_get_workspaces (window); while (tmp != NULL) { MetaRectangle workspace_work_area; meta_workspace_get_work_area_for_monitor (tmp->data, which_monitor, &workspace_work_area); meta_rectangle_intersect (area, &workspace_work_area, area); tmp = tmp->next; } meta_topic (META_DEBUG_WORKAREA, "Window %s monitor %d has work area %d,%d %d x %d\n", window->desc, which_monitor, area->x, area->y, area->width, area->height); } LOCAL_SYMBOL void meta_window_get_work_area_current_monitor (MetaWindow *window, MetaRectangle *area) { const MetaMonitorInfo *monitor = NULL; monitor = meta_screen_get_monitor_for_window (window->screen, window); meta_window_get_work_area_for_monitor (window, monitor->number, area); } LOCAL_SYMBOL void meta_window_get_work_area_for_monitor (MetaWindow *window, int which_monitor, MetaRectangle *area) { g_return_if_fail (which_monitor >= 0); get_work_area_monitor (window, area, which_monitor); } LOCAL_SYMBOL void meta_window_get_work_area_all_monitors (MetaWindow *window, MetaRectangle *area) { GList *tmp; /* Initialize to the whole screen */ *area = window->screen->rect; tmp = meta_window_get_workspaces (window); while (tmp != NULL) { MetaRectangle workspace_work_area; meta_workspace_get_work_area_all_monitors (tmp->data, &workspace_work_area); meta_rectangle_intersect (area, &workspace_work_area, area); tmp = tmp->next; } meta_topic (META_DEBUG_WORKAREA, "Window %s has whole-screen work area %d,%d %d x %d\n", window->desc, area->x, area->y, area->width, area->height); } LOCAL_SYMBOL void meta_window_get_tile_threshold_area_for_mode (MetaWindow *window, MetaRectangle work_area, MetaTileMode mode, MetaRectangle *tile_area, gint zone_width) { int tile_monitor_number; g_return_if_fail (mode != META_TILE_NONE); if (window != NULL) { tile_monitor_number = meta_window_get_current_tile_monitor_number(window); meta_window_get_work_area_for_monitor (window, tile_monitor_number, tile_area); } else { tile_area->x = work_area.x; tile_area->y = work_area.y; tile_area->height = work_area.height; tile_area->width = work_area.width; } switch (mode) { case META_TILE_LEFT: tile_area->width = zone_width; tile_area->y = tile_area->y + zone_width; tile_area->height = tile_area->height - (2 * zone_width); break; case META_TILE_RIGHT: tile_area->x = tile_area->width - zone_width; tile_area->width = zone_width; tile_area->y = tile_area->y + zone_width; tile_area->height = tile_area->height - (2 * zone_width); break; case META_TILE_ULC: tile_area->width = zone_width; tile_area->height = zone_width; break; case META_TILE_LLC: tile_area->y = tile_area->height - zone_width; tile_area->width = zone_width; tile_area->height = zone_width; break; case META_TILE_URC: tile_area->x = tile_area->width - zone_width; tile_area->width = zone_width; tile_area->height = zone_width; break; case META_TILE_LRC: tile_area->x = tile_area->width - zone_width; tile_area->width = zone_width; tile_area->y = tile_area->height - zone_width; tile_area->height = zone_width; break; case META_TILE_TOP: case META_TILE_MAXIMIZE: tile_area->height = zone_width; tile_area->x = tile_area->x + zone_width; tile_area->width = tile_area->width - (2 * zone_width); break; case META_TILE_BOTTOM: tile_area->y = tile_area->height - zone_width; tile_area->height = zone_width; tile_area->x = tile_area->x + zone_width; tile_area->width = tile_area->width - (2 * zone_width); break; default: break; } } int meta_window_get_current_tile_monitor_number (MetaWindow *window) { int tile_monitor_number = window->tile_monitor_number; if (tile_monitor_number < 0) { meta_warning ("%s called with an invalid monitor number, using 0 instead\n", G_STRFUNC); tile_monitor_number = 0; } return tile_monitor_number; } LOCAL_SYMBOL void meta_window_get_current_tile_area (MetaWindow *window, MetaRectangle *tile_area) { int tile_monitor_number; g_return_if_fail (window->tile_mode != META_TILE_NONE); tile_monitor_number = meta_window_get_current_tile_monitor_number (window); meta_window_get_work_area_for_monitor (window, tile_monitor_number, tile_area); if (window->tile_mode == META_TILE_LEFT || window->tile_mode == META_TILE_RIGHT) tile_area->width /= 2; if (window->tile_mode == META_TILE_RIGHT) tile_area->x += tile_area->width; if (window->tile_mode == META_TILE_ULC) { tile_area->width /= 2; tile_area->height /= 2; } if (window->tile_mode == META_TILE_LLC) { tile_area->width /= 2; tile_area->height /= 2; tile_area->y += tile_area->height; } if (window->tile_mode == META_TILE_URC) { tile_area->width /= 2; tile_area->height /= 2; tile_area->x += tile_area->width; } if (window->tile_mode == META_TILE_LRC) { tile_area->width /= 2; tile_area->height /= 2; tile_area->x += tile_area->width; tile_area->y += tile_area->height; } if (window->tile_mode == META_TILE_TOP || window->tile_mode == META_TILE_BOTTOM) tile_area->height /= 2; if (window->tile_mode == META_TILE_BOTTOM) tile_area->y += tile_area->height; } LOCAL_SYMBOL gboolean meta_window_same_application (MetaWindow *window, MetaWindow *other_window) { MetaGroup *group = meta_window_get_group (window); MetaGroup *other_group = meta_window_get_group (other_window); return group!=NULL && other_group!=NULL && group==other_group; } /* Generally meta_window_same_application() is a better idea * of "sameness", since it handles the case where multiple apps * want to look like the same app or the same app wants to look * like multiple apps, but in the case of workarounds for legacy * applications (which likely aren't setting the group properly * anyways), it may be desirable to check this as well. */ static gboolean meta_window_same_client (MetaWindow *window, MetaWindow *other_window) { int resource_mask = window->display->xdisplay->resource_mask; return ((window->xwindow & ~resource_mask) == (other_window->xwindow & ~resource_mask)); } /** * meta_window_is_client_decorated: * * Check if if the window has decorations drawn by the client. * (window->decorated refers only to whether we should add decorations) */ gboolean meta_window_is_client_decorated (MetaWindow *window) { /* Currently the implementation here is hackish - * has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set * to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for * client-side-decorated window, even if the value is 0 because * the window is maxized and has no invisible borders or shadows. */ return window->has_custom_frame_extents; } void meta_window_extend_by_frame (MetaWindow *window, MetaRectangle *rect, const MetaFrameBorders *borders) { if (window->frame) { rect->x -= borders->visible.left; rect->y -= borders->visible.top; rect->width += borders->visible.left + borders->visible.right; rect->height += borders->visible.top + borders->visible.bottom; } else if (meta_window_is_client_decorated (window)) { const GtkBorder *extents = &window->custom_frame_extents; rect->x += extents->left; rect->y += extents->top; rect->width -= extents->left + extents->right; rect->height -= extents->top + extents->bottom; } } void meta_window_unextend_by_frame (MetaWindow *window, MetaRectangle *rect, const MetaFrameBorders *borders) { if (window->frame) { rect->x += borders->visible.left; rect->y += borders->visible.top; rect->width -= borders->visible.left + borders->visible.right; rect->height -= borders->visible.top + borders->visible.bottom; } else if (meta_window_is_client_decorated (window)) { const GtkBorder *extents = &window->custom_frame_extents; rect->x -= extents->left; rect->y -= extents->top; rect->width += extents->left + extents->right; rect->height += extents->top + extents->bottom; } } LOCAL_SYMBOL void meta_window_refresh_resize_popup (MetaWindow *window) { if (window->display->grab_op == META_GRAB_OP_NONE) return; if (window->display->grab_window != window) return; switch (window->display->grab_op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: break; default: /* Not resizing */ return; } if (window->display->grab_resize_popup == NULL) { gint scale; scale = meta_prefs_get_ui_scale (); if (window->size_hints.width_inc > scale || window->size_hints.height_inc > scale) { window->display->grab_resize_popup = meta_ui_resize_popup_new (window->display->xdisplay, window->screen->number); } } if (window->display->grab_resize_popup != NULL) { MetaRectangle rect; meta_window_get_client_root_coords (window, &rect); meta_ui_resize_popup_set (window->display->grab_resize_popup, rect, window->size_hints.base_width, window->size_hints.base_height, window->size_hints.width_inc, window->size_hints.height_inc); meta_ui_resize_popup_set_showing (window->display->grab_resize_popup, TRUE); } } /** * meta_window_foreach_transient: * @window: a #MetaWindow * @func: (scope call) (closure user_data): Called for each window which is a transient of @window (transitively) * @user_data: User data * * Call @func for every window which is either transient for @window, or is * a transient of a window which is in turn transient for @window. * The order of window enumeration is not defined. * * Iteration will stop if @func at any point returns %FALSE. */ void meta_window_foreach_transient (MetaWindow *window, MetaWindowForeachFunc func, void *user_data) { GSList *windows; GSList *tmp; windows = meta_display_list_windows (window->display, META_LIST_DEFAULT); tmp = windows; while (tmp != NULL) { MetaWindow *transient = tmp->data; if (meta_window_is_ancestor_of_transient (window, transient)) { if (!(* func) (transient, user_data)) break; } tmp = tmp->next; } g_slist_free (windows); } /** * meta_window_foreach_ancestor: * @window: a #MetaWindow * @func: (scope call) (closure user_data): Called for each window which is a transient parent of @window * @user_data: User data * * If @window is transient, call @func with the window for which it's transient, * repeatedly until either we find a non-transient window, or @func returns %FALSE. */ void meta_window_foreach_ancestor (MetaWindow *window, MetaWindowForeachFunc func, void *user_data) { MetaWindow *w; w = window; do { if (w->xtransient_for == None || w->transient_parent_is_root_window) break; w = meta_display_lookup_x_window (w->display, w->xtransient_for); } while (w && (* func) (w, user_data)); } typedef struct { MetaWindow *ancestor; gboolean found; } FindAncestorData; static gboolean find_ancestor_func (MetaWindow *window, void *data) { FindAncestorData *d = data; if (window == d->ancestor) { d->found = TRUE; return FALSE; } return TRUE; } /** * meta_window_is_ancestor_of_transient: * @window: a #MetaWindow * @transient: a #MetaWindow * * The function determines whether @window is an ancestor of @transient; it does * so by traversing the @transient's ancestors until it either locates @window * or reaches an ancestor that is not transient. * * Return Value: %TRUE if window is an ancestor of transient. */ gboolean meta_window_is_ancestor_of_transient (MetaWindow *window, MetaWindow *transient) { FindAncestorData d; d.ancestor = window; d.found = FALSE; meta_window_foreach_ancestor (transient, find_ancestor_func, &d); return d.found; } /* Warp pointer to location appropriate for grab, * return root coordinates where pointer ended up. */ static gboolean warp_grab_pointer (MetaWindow *window, MetaGrabOp grab_op, int *x, int *y) { MetaRectangle rect; MetaDisplay *display; display = window->display; /* We may not have done begin_grab_op yet, i.e. may not be in a grab */ meta_window_get_outer_rect (window, &rect); switch (grab_op) { case META_GRAB_OP_KEYBOARD_MOVING: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: *x = rect.width / 2; *y = rect.height / 2; break; case META_GRAB_OP_KEYBOARD_RESIZING_S: *x = rect.width / 2; *y = rect.height - 1; break; case META_GRAB_OP_KEYBOARD_RESIZING_N: *x = rect.width / 2; *y = 0; break; case META_GRAB_OP_KEYBOARD_RESIZING_W: *x = 0; *y = rect.height / 2; break; case META_GRAB_OP_KEYBOARD_RESIZING_E: *x = rect.width - 1; *y = rect.height / 2; break; case META_GRAB_OP_KEYBOARD_RESIZING_SE: *x = rect.width - 1; *y = rect.height - 1; break; case META_GRAB_OP_KEYBOARD_RESIZING_NE: *x = rect.width - 1; *y = 0; break; case META_GRAB_OP_KEYBOARD_RESIZING_SW: *x = 0; *y = rect.height - 1; break; case META_GRAB_OP_KEYBOARD_RESIZING_NW: *x = 0; *y = 0; break; default: return FALSE; } *x += rect.x; *y += rect.y; /* Avoid weird bouncing at the screen edge; see bug 154706 */ *x = CLAMP (*x, 0, window->screen->rect.width-1); *y = CLAMP (*y, 0, window->screen->rect.height-1); meta_error_trap_push_with_return (display); meta_topic (META_DEBUG_WINDOW_OPS, "Warping pointer to %d,%d with window at %d,%d\n", *x, *y, rect.x, rect.y); /* Need to update the grab positions so that the MotionNotify and other * events generated by the XWarpPointer() call below don't cause complete * funkiness. See bug 124582 and bug 122670. */ display->grab_anchor_root_x = *x; display->grab_anchor_root_y = *y; display->grab_latest_motion_x = *x; display->grab_latest_motion_y = *y; meta_window_get_client_root_coords (window, &display->grab_anchor_window_pos); XWarpPointer (display->xdisplay, None, window->screen->xroot, 0, 0, 0, 0, *x, *y); if (meta_error_trap_pop_with_return (display) != Success) { meta_verbose ("Failed to warp pointer for window %s\n", window->desc); return FALSE; } return TRUE; } LOCAL_SYMBOL void meta_window_begin_grab_op (MetaWindow *window, MetaGrabOp op, gboolean frame_action, guint32 timestamp) { int x, y; warp_grab_pointer (window, op, &x, &y); meta_display_begin_grab_op (window->display, window->screen, window, op, FALSE, frame_action, 0 /* button */, 0, timestamp, x, y); } LOCAL_SYMBOL void meta_window_update_keyboard_resize (MetaWindow *window, gboolean update_cursor) { int x, y; warp_grab_pointer (window, window->display->grab_op, &x, &y); if (update_cursor) { guint32 timestamp; /* FIXME: Using CurrentTime is really bad mojo */ timestamp = CurrentTime; meta_display_set_grab_op_cursor (window->display, NULL, window->display->grab_op, TRUE, window->display->grab_xwindow, timestamp); } } LOCAL_SYMBOL void meta_window_update_keyboard_move (MetaWindow *window) { int x, y; warp_grab_pointer (window, window->display->grab_op, &x, &y); } LOCAL_SYMBOL void meta_window_update_layer (MetaWindow *window) { MetaGroup *group; meta_stack_freeze (window->screen->stack); group = meta_window_get_group (window); if (group) meta_group_update_layers (group); else meta_stack_update_layer (window->screen->stack, window); meta_stack_thaw (window->screen->stack); } /* ensure_mru_position_after ensures that window appears after * below_this_one in the active_workspace's mru_list (i.e. it treats * window as having been less recently used than below_this_one) */ static void ensure_mru_position_after (MetaWindow *window, MetaWindow *after_this_one) { /* This is sort of slow since it runs through the entire list more * than once (especially considering the fact that we expect the * windows of interest to be the first two elements in the list), * but it doesn't matter while we're only using it on new window * map. */ GList* active_mru_list; GList* window_position; GList* after_this_one_position; active_mru_list = window->screen->active_workspace->mru_list; after_this_one_position = g_list_find (active_mru_list, after_this_one); /* after_this_one_position is NULL when we switch workspaces, but in * that case we don't need to do any MRU shuffling so we can simply * return. */ if (after_this_one_position == NULL) return; window_position = g_list_find (active_mru_list, window); if (g_list_length (window_position) > g_list_length (after_this_one_position)) { window->screen->active_workspace->mru_list = g_list_delete_link (window->screen->active_workspace->mru_list, window_position); window->screen->active_workspace->mru_list = g_list_insert_before (window->screen->active_workspace->mru_list, after_this_one_position->next, window); } } LOCAL_SYMBOL void meta_window_stack_just_below (MetaWindow *window, MetaWindow *below_this_one) { g_return_if_fail (window != NULL); g_return_if_fail (below_this_one != NULL); if (window->stack_position > below_this_one->stack_position) { meta_topic (META_DEBUG_STACK, "Setting stack position of window %s to %d (making it below window %s).\n", window->desc, below_this_one->stack_position, below_this_one->desc); meta_window_set_stack_position (window, below_this_one->stack_position); } else { meta_topic (META_DEBUG_STACK, "Window %s was already below window %s.\n", window->desc, below_this_one->desc); } } void meta_window_stack_just_above (MetaWindow *window, MetaWindow *above_this_one) { g_return_if_fail (window != NULL); g_return_if_fail (above_this_one != NULL); if (window->stack_position < above_this_one->stack_position) { meta_topic (META_DEBUG_STACK, "Setting stack position of window %s to %d (making it above window %s).\n", window->desc, above_this_one->stack_position, above_this_one->desc); meta_window_set_stack_position (window, above_this_one->stack_position); } else { meta_topic (META_DEBUG_STACK, "Window %s was already above window %s.\n", window->desc, above_this_one->desc); } } /** * meta_window_get_user_time: * * The user time represents a timestamp for the last time the user * interacted with this window. Note this property is only available * for non-override-redirect windows. * * The property is set by Muffin initially upon window creation, * and updated thereafter on input events (key and button presses) seen by Muffin, * client updates to the _NET_WM_USER_TIME property (if later than the current time) * and when focusing the window. * * Returns: The last time the user interacted with this window. */ guint32 meta_window_get_user_time (MetaWindow *window) { return window->net_wm_user_time; } LOCAL_SYMBOL void meta_window_set_user_time (MetaWindow *window, guint32 timestamp) { /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow * us to sanity check the timestamp here and ensure it doesn't correspond to * a future time. */ g_return_if_fail (!window->override_redirect); /* Only update the time if this timestamp is newer... */ if (window->net_wm_user_time_set && XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time)) { meta_topic (META_DEBUG_STARTUP, "Window %s _NET_WM_USER_TIME not updated to %u, because it " "is less than %u\n", window->desc, timestamp, window->net_wm_user_time); } else { meta_topic (META_DEBUG_STARTUP, "Window %s has _NET_WM_USER_TIME of %u\n", window->desc, timestamp); window->net_wm_user_time_set = TRUE; window->net_wm_user_time = timestamp; if (XSERVER_TIME_IS_BEFORE (window->display->last_user_time, timestamp)) window->display->last_user_time = timestamp; /* If this is a terminal, user interaction with it means the user likely * doesn't want to have focus transferred for now due to new windows. */ if (meta_prefs_get_focus_new_windows () == C_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && __window_is_terminal (window)) window->display->allow_terminal_deactivation = FALSE; } g_object_notify (G_OBJECT (window), "user-time"); } /** * meta_window_get_stable_sequence: * @window: A #MetaWindow * * The stable sequence number is a monotonicially increasing * unique integer assigned to each #MetaWindow upon creation. * * This number can be useful for sorting windows in a stable * fashion. * * Returns: Internal sequence number for this window */ guint32 meta_window_get_stable_sequence (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), 0); return window->stable_sequence; } /* Sets the demands_attention hint on a window, but only * if it's at least partially obscured (see #305882). */ void meta_window_set_demands_attention (MetaWindow *window) { GList *stack; MetaRectangle candidate_rect, other_rect; MetaWindow *other_window; gboolean obscured; MetaWorkspace *workspace; if (window->wm_state_demands_attention) return; obscured = FALSE; stack = window->screen->stack->sorted; workspace = window->screen->active_workspace; if (workspace!=window->workspace) { /* windows on other workspaces are necessarily obscured */ obscured = TRUE; } else if (window->minimized) { obscured = TRUE; } else { meta_window_get_outer_rect (window, &candidate_rect); /* The stack is sorted with the top windows first. */ while (stack != NULL && stack->data != window) { other_window = stack->data; stack = stack->next; if (other_window->on_all_workspaces || window->on_all_workspaces || other_window->workspace == window->workspace) { meta_window_get_outer_rect (other_window, &other_rect); if (meta_rectangle_overlap (&candidate_rect, &other_rect)) { obscured = TRUE; break; } } } } if (obscured) { meta_topic (META_DEBUG_WINDOW_OPS, "Marking %s as needing attention\n", window->desc); window->wm_state_demands_attention = TRUE; set_net_wm_state (window); g_object_notify (G_OBJECT (window), "demands-attention"); g_signal_emit_by_name (window->display, "window-demands-attention", window); } #ifdef WITH_VERBOSE_MODE else { /* If the window's in full view, there's no point setting the flag. */ meta_topic (META_DEBUG_WINDOW_OPS, "Not marking %s as needing attention because " "it's in full view\n", window->desc); } #endif } /** * meta_window_is_demanding_attention: * @window: A #MetaWindow * * Returns true if window has the demands-attention flag set. * * Return value: %TRUE if wm_state_demands_attention is set. */ gboolean meta_window_is_demanding_attention (MetaWindow *window) { return window->wm_state_demands_attention; } /** * meta_window_is_urgent: * @window: A #MetaWindow * * Returns true if window has the urgent hint set. * * Return value: %TRUE if wm_hints_urgent is set. */ gboolean meta_window_is_urgent (MetaWindow *window) { return window->wm_hints_urgent; } void meta_window_unset_demands_attention (MetaWindow *window) { meta_topic (META_DEBUG_WINDOW_OPS, "Marking %s as not needing attention\n", window->desc); if (window->wm_state_demands_attention) { window->wm_state_demands_attention = FALSE; set_net_wm_state (window); g_object_notify (G_OBJECT (window), "demands-attention"); } } /** * meta_window_get_frame: (skip) * */ MetaFrame * meta_window_get_frame (MetaWindow *window) { return window->frame; } /** * meta_window_appears_focused: * @window: a #MetaWindow * * Determines if the window should be drawn with a focused appearance. This is * true for focused windows but also true for windows with a focused modal * dialog attached. * * Return value: %TRUE if the window should be drawn with a focused frame */ gboolean meta_window_appears_focused (MetaWindow *window) { return window->has_focus || (window->attached_focus_window != NULL); } gboolean meta_window_has_focus (MetaWindow *window) { return window->has_focus; } gboolean meta_window_is_shaded (MetaWindow *window) { return window->shaded; } /** * meta_window_is_override_redirect: * @window: A #MetaWindow * * Returns if this window isn't managed by muffin; it will * control its own positioning and muffin won't draw decorations * among other things. In X terminology this is "override redirect". */ gboolean meta_window_is_override_redirect (MetaWindow *window) { return window->override_redirect; } /** * meta_window_is_skip_taskbar: * @window: A #MetaWindow * * Gets whether this window should be ignored by task lists. * * Return value: %TRUE if the skip bar hint is set. */ gboolean meta_window_is_skip_taskbar (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), FALSE); return window->skip_taskbar; } gboolean meta_window_is_interesting (MetaWindow *window) { if (window->override_redirect || window->skip_taskbar) return FALSE; switch (window->type) { /* Definitely ignore these. */ case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_SPLASHSCREEN: /* Should have already been handled by override_redirect above, * but explicitly list here so we get the "unhandled enum" * warning if in the future anything is added.*/ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: return FALSE; case META_WINDOW_NORMAL: case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: case META_WINDOW_MENU: case META_WINDOW_TOOLBAR: case META_WINDOW_UTILITY: break; default: g_warning ("meta_window_is_interesting: default reached"); break; } return TRUE; } /** * meta_window_get_rect: * @window: a #MetaWindow * * Gets the rectangle that bounds @window, ignoring any window decorations. * * Return value: (transfer none): the #MetaRectangle for the window */ MetaRectangle * meta_window_get_rect (MetaWindow *window) { return &window->rect; } /** * meta_window_get_screen: * @window: a #MetaWindow * * Gets the #MetaScreen that the window is on. * * Return value: (transfer none): the #MetaScreen for the window */ MetaScreen * meta_window_get_screen (MetaWindow *window) { return window->screen; } /** * meta_window_get_display: * @window: A #MetaWindow * * Returns: (transfer none): The display for @window */ MetaDisplay * meta_window_get_display (MetaWindow *window) { return window->display; } /** * meta_window_get_xwindow: * @window: A #MetaWindow * * Returns: The Window id of the @window * note - we return unsigned long because Window * Can't be introspected (but Window *is* a ulong) * */ unsigned long meta_window_get_xwindow (MetaWindow *window) { return window->xwindow; } MetaWindowType meta_window_get_window_type (MetaWindow *window) { return window->type; } /** * meta_window_get_window_type_atom: (skip) * @window: a #MetaWindow * * Gets the X atom from the _NET_WM_WINDOW_TYPE property used by the * application to set the window type. (Note that this is constrained * to be some value that Muffin recognizes - a completely unrecognized * type atom will be returned as None.) * * Return value: the raw X atom for the window type, or None */ Atom meta_window_get_window_type_atom (MetaWindow *window) { return window->type_atom; } /** * meta_window_get_workspace: * @window: a #MetaWindow * * Gets the #MetaWorkspace that the window is currently displayed on. * If the window is on all workspaces, returns the currently active * workspace. * * Return value: (transfer none): the #MetaWorkspace for the window */ MetaWorkspace * meta_window_get_workspace (MetaWindow *window) { if (window->on_all_workspaces) return window->screen->active_workspace; return window->workspace; } gboolean meta_window_is_on_all_workspaces (MetaWindow *window) { return window->on_all_workspaces; } gboolean meta_window_is_hidden (MetaWindow *window) { return window->hidden; } const char * meta_window_get_description (MetaWindow *window) { if (!window) return NULL; return window->desc; } /** * meta_window_get_wm_class: * @window: a #MetaWindow * * Return the current value of the name part of WM_CLASS X property. */ const char * meta_window_get_wm_class (MetaWindow *window) { if (!window) return NULL; return window->res_class; } /** * meta_window_get_wm_class_instance: * @window: a #MetaWindow * * Return the current value of the instance part of WM_CLASS X property. */ const char * meta_window_get_wm_class_instance (MetaWindow *window) { if (!window) return NULL; return window->res_name; } /** * meta_window_get_gtk_application_id: * @window: a #MetaWindow * * Return value: (transfer none): the application ID **/ const char * meta_window_get_gtk_application_id (MetaWindow *window) { return window->gtk_application_id; } /** * meta_window_get_gtk_unique_bus_name: * @window: a #MetaWindow * * Return value: (transfer none): the unique name **/ const char * meta_window_get_gtk_unique_bus_name (MetaWindow *window) { return window->gtk_unique_bus_name; } /** * meta_window_get_gtk_application_object_path: * @window: a #MetaWindow * * Return value: (transfer none): the object path **/ const char * meta_window_get_gtk_application_object_path (MetaWindow *window) { return window->gtk_application_object_path; } /** * meta_window_get_gtk_window_object_path: * @window: a #MetaWindow * * Return value: (transfer none): the object path **/ const char * meta_window_get_gtk_window_object_path (MetaWindow *window) { return window->gtk_window_object_path; } /** * meta_window_get_gtk_app_menu_object_path: * @window: a #MetaWindow * * Return value: (transfer none): the object path **/ const char * meta_window_get_gtk_app_menu_object_path (MetaWindow *window) { return window->gtk_app_menu_object_path; } /** * meta_window_get_gtk_menubar_object_path: * @window: a #MetaWindow * * Return value: (transfer none): the object path **/ const char * meta_window_get_gtk_menubar_object_path (MetaWindow *window) { return window->gtk_menubar_object_path; } /** * meta_window_get_compositor_private: * @window: a #MetaWindow * * Gets the compositor's wrapper object for @window. * * Return value: (transfer none): the wrapper object. **/ GObject * meta_window_get_compositor_private (MetaWindow *window) { if (!window) return NULL; return window->compositor_private; } void meta_window_set_compositor_private (MetaWindow *window, GObject *priv) { if (!window) return; window->compositor_private = priv; } const char * meta_window_get_role (MetaWindow *window) { if (!window) return NULL; return window->role; } /** * meta_window_get_title: * @window: a #MetaWindow * * Returns the current title of the window. */ const char * meta_window_get_title (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), NULL); return window->title; } MetaStackLayer meta_window_get_layer (MetaWindow *window) { return window->layer; } /** * meta_window_get_transient_for: * @window: a #MetaWindow * * Returns the #MetaWindow for the window that is pointed to by the * WM_TRANSIENT_FOR hint on this window (see XGetTransientForHint() * or XSetTransientForHint()). Metacity keeps transient windows above their * parents. A typical usage of this hint is for a dialog that wants to stay * above its associated window. * * Return value: (transfer none): the window this window is transient for, or * %NULL if the WM_TRANSIENT_FOR hint is unset or does not point to a toplevel * window that Metacity knows about. */ MetaWindow * meta_window_get_transient_for (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), NULL); if (window->xtransient_for) return meta_display_lookup_x_window (window->display, window->xtransient_for); else return NULL; } /** * meta_window_get_transient_for_as_xid: * @window: a #MetaWindow * * Returns the XID of the window that is pointed to by the * WM_TRANSIENT_FOR hint on this window (see XGetTransientForHint() * or XSetTransientForHint()). Metacity keeps transient windows above their * parents. A typical usage of this hint is for a dialog that wants to stay * above its associated window. * * Return value: the window this window is transient for, or * None if the WM_TRANSIENT_FOR hint is unset. */ Window meta_window_get_transient_for_as_xid (MetaWindow *window) { return window->xtransient_for; } /** * meta_window_get_pid: * @window: a #MetaWindow * * Returns pid of the process that created this window, if known (obtained from * the _NET_WM_PID property). * * Return value: the pid, or -1 if not known. */ int meta_window_get_pid (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), -1); return window->net_wm_pid; } /** * meta_window_get_client_pid: * @window: a #MetaWindow * * Returns the client pid of the process that created this window, if known (obtained from XCB). * * Return value: the pid, or -1 if not known. */ int meta_window_get_client_pid (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), -1); if (window->client_pid == -2) { update_client_pid (window); } return window->client_pid; } /** * meta_window_get_client_machine: * @window: a #MetaWindow * * Returns name of the client machine from which this windows was created, * if known (obtained from the WM_CLIENT_MACHINE property). * * Return value: (transfer none): the machine name, or NULL; the string is * owned by the window manager and should not be freed or modified by the * caller. */ const char * meta_window_get_client_machine (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), NULL); return window->wm_client_machine; } /** * meta_window_is_remote: * @window: a #MetaWindow * * Returns: %TRUE if this window originates from a host * different from the one running muffin. */ gboolean meta_window_is_remote (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), FALSE); if (window->wm_client_machine != NULL) return g_strcmp0 (window->wm_client_machine, window->display->hostname) != 0; return FALSE; } /** * meta_window_is_modal: * @window: a #MetaWindow * * Queries whether the window is in a modal state as described by the * _NET_WM_STATE protocol. * * Return value: TRUE if the window is in modal state. */ gboolean meta_window_is_modal (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), FALSE); return window->wm_state_modal; } /** * meta_window_get_muffin_hints: * @window: a #MetaWindow * * Gets the current value of the _MUFFIN_HINTS property. * * The purpose of the hints is to allow fine-tuning of the Window Manager and * Compositor behaviour on per-window basis, and is intended primarily for * hints that are plugin-specific. * * The property is a list of colon-separated key=value pairs. The key names for * any plugin-specific hints must be suitably namespaced to allow for shared * use; 'muffin-' key prefix is reserved for internal use, and must not be used * by plugins. * * Return value: (transfer none): the _MUFFIN_HINTS string, or %NULL if no hints * are set. */ const char * meta_window_get_muffin_hints (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), NULL); return window->muffin_hints; } /** * meta_window_get_frame_type: * @window: a #MetaWindow * * Gets the type of window decorations that should be used for this window. * * Return value: the frame type */ MetaFrameType meta_window_get_frame_type (MetaWindow *window) { MetaFrameType base_type = META_FRAME_TYPE_LAST; switch (window->type) { case META_WINDOW_NORMAL: base_type = META_FRAME_TYPE_NORMAL; break; case META_WINDOW_DIALOG: base_type = META_FRAME_TYPE_DIALOG; break; case META_WINDOW_MODAL_DIALOG: if (meta_window_is_attached_dialog (window)) base_type = META_FRAME_TYPE_ATTACHED; else base_type = META_FRAME_TYPE_MODAL_DIALOG; break; case META_WINDOW_MENU: base_type = META_FRAME_TYPE_MENU; break; case META_WINDOW_UTILITY: base_type = META_FRAME_TYPE_UTILITY; break; case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_TOOLBAR: case META_WINDOW_SPLASHSCREEN: case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: /* No frame */ base_type = META_FRAME_TYPE_LAST; break; } if (base_type == META_FRAME_TYPE_LAST) { /* can't add border if undecorated */ return META_FRAME_TYPE_LAST; } else if ((window->border_only && base_type != META_FRAME_TYPE_ATTACHED) || (window->hide_titlebar_when_maximized && META_WINDOW_MAXIMIZED (window))) { /* override base frame type */ return META_FRAME_TYPE_BORDER; } else { return base_type; } } /** * meta_window_get_frame_bounds: * * Gets a region representing the outer bounds of the window's frame. * * Return value: (transfer none) (allow-none): a #cairo_region_t * holding the outer bounds of the window, or %NULL if the window * doesn't have a frame. */ cairo_region_t * meta_window_get_frame_bounds (MetaWindow *window) { if (!window->frame_bounds) { if (window->frame) window->frame_bounds = meta_frame_get_frame_bounds (window->frame); } return window->frame_bounds; } /** * meta_window_is_attached_dialog: * @window: a #MetaWindow * * Tests if @window is should be attached to its parent window. * (If the "attach_modal_dialogs" option is not enabled, this will * always return %FALSE.) * * Return value: whether @window should be attached to its parent */ gboolean meta_window_is_attached_dialog (MetaWindow *window) { return window->attached; } /** * meta_window_get_tile_match: * * Returns the matching tiled window on the same monitory as @window. This is * the topmost tiled window in a complementary tile mode that is: * * - on the same monitor; * - on the same workspace; * - spanning the remaining monitor width; * - there is no 3rd window stacked between both tiled windows that's * partially visible in the common edge. * * Return value: (transfer none) (allow-none): the matching tiled window or * %NULL if it doesn't exist. */ MetaWindow * meta_window_get_tile_match (MetaWindow *window) { return window->tile_match; } LOCAL_SYMBOL void meta_window_compute_tile_match (MetaWindow *window) { MetaWindow *match; MetaStack *stack; MetaTileMode match_tile_mode; window->tile_match = NULL; if (window->shaded || window->minimized) return; match_tile_mode = META_TILE_NONE; if (META_WINDOW_TILED_LEFT (window)) match_tile_mode = META_TILE_RIGHT; else if (META_WINDOW_TILED_RIGHT (window)) match_tile_mode = META_TILE_LEFT; else if (META_WINDOW_TILED_ULC (window)) match_tile_mode = META_TILE_ULC; else if (META_WINDOW_TILED_LLC (window)) match_tile_mode = META_TILE_LLC; else if (META_WINDOW_TILED_URC (window)) match_tile_mode = META_TILE_URC; else if (META_WINDOW_TILED_LRC (window)) match_tile_mode = META_TILE_LRC; else if (META_WINDOW_TILED_TOP (window)) match_tile_mode = META_TILE_TOP; else if (META_WINDOW_TILED_BOTTOM (window)) match_tile_mode = META_TILE_BOTTOM; else return; stack = window->screen->stack; for (match = meta_stack_get_top (stack); match; match = meta_stack_get_below (stack, match, FALSE)) { if (!match->shaded && !match->minimized && match->tile_mode == match_tile_mode && match->monitor == window->monitor && meta_window_get_workspace (match) == meta_window_get_workspace (window)) break; } if (match) { MetaWindow *above, *bottommost, *topmost; MetaRectangle above_rect, bottommost_rect, topmost_rect; if (meta_stack_windows_cmp (window->screen->stack, match, window) > 0) { topmost = match; bottommost = window; } else { topmost = window; bottommost = match; } meta_window_get_outer_rect (bottommost, &bottommost_rect); meta_window_get_outer_rect (topmost, &topmost_rect); /* * If there's a window stacked in between which is partially visible * behind the topmost tile we don't consider the tiles to match. */ for (above = meta_stack_get_above (stack, bottommost, FALSE); above && above != topmost; above = meta_stack_get_above (stack, above, FALSE)) { if (above->minimized || above->monitor != window->monitor || meta_window_get_workspace (above) != meta_window_get_workspace (window)) continue; meta_window_get_outer_rect (above, &above_rect); if (meta_rectangle_overlap (&above_rect, &bottommost_rect) && meta_rectangle_overlap (&above_rect, &topmost_rect)) return; } window->tile_match = match; } } void meta_window_set_tile_type (MetaWindow *window, MetaWindowTileType type) { g_return_if_fail (META_IS_WINDOW (window)); if (window->tile_type != type) { window->tile_type = type; g_object_freeze_notify (G_OBJECT (window)); g_object_notify (G_OBJECT (window), "tile-type"); g_object_thaw_notify (G_OBJECT (window)); } } MetaWindowTileType meta_window_get_tile_type (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), META_WINDOW_TILE_TYPE_NONE); return window->tile_type; } #define ORIGIN_CONSTANT 1 #define EXTREME_CONSTANT 2 #define COMMON_EDGE_PADDING 10 static void get_extra_padding_for_common_monitor_edges (MetaWindow *window, gint monitor_num, MetaRectangle cur_rect, gint *left_shift, gint *right_shift, gint *up_shift, gint *down_shift) { gint num_mons; gint i; MetaRectangle other_rect; num_mons = meta_screen_get_n_monitors (window->screen); if (num_mons == 1) return; for (i = 0; i < num_mons; i++) { if (i == monitor_num) continue; meta_screen_get_monitor_geometry (window->screen, i, &other_rect); if (BOX_CENTER_X (other_rect) < BOX_LEFT (cur_rect)) { *left_shift += COMMON_EDGE_PADDING; continue; } if (BOX_CENTER_X (other_rect) > BOX_RIGHT (cur_rect)) { *right_shift += COMMON_EDGE_PADDING; continue; } if (BOX_CENTER_Y (other_rect) < BOX_TOP (cur_rect)) { *up_shift += COMMON_EDGE_PADDING; continue; } if (BOX_CENTER_Y (other_rect) > BOX_BOTTOM (cur_rect)) { *down_shift += COMMON_EDGE_PADDING; continue; } } } gboolean meta_window_mouse_on_edge (MetaWindow *window, gint x, gint y) { MetaRectangle work_area; gboolean ret = FALSE; int monitor; gint left_shift, right_shift, up_shift, down_shift; left_shift = right_shift = up_shift = down_shift = 0; monitor = meta_screen_get_current_monitor (window->screen); meta_window_get_work_area_for_monitor (window, monitor, &work_area); get_extra_padding_for_common_monitor_edges (window, monitor, work_area, &left_shift, &right_shift, &up_shift, &down_shift); ret = x <= BOX_LEFT (work_area) + ORIGIN_CONSTANT + left_shift || x >= BOX_RIGHT (work_area) - EXTREME_CONSTANT - right_shift || y <= BOX_TOP (work_area) + ORIGIN_CONSTANT + up_shift || y >= BOX_BOTTOM (work_area) - EXTREME_CONSTANT - down_shift; return ret; } gboolean meta_window_can_maximize (MetaWindow *window) { return window->has_maximize_func; } gboolean meta_window_can_minimize (MetaWindow *window) { return window->has_minimize_func; } gboolean meta_window_can_shade (MetaWindow *window) { return window->has_shade_func; } gboolean meta_window_can_close (MetaWindow *window) { return window->has_close_func; } gboolean meta_window_is_always_on_all_workspaces (MetaWindow *window) { return window->always_sticky; } gboolean meta_window_is_always_on_top (MetaWindow *window) { return window->wm_state_above; } gboolean meta_window_can_move (MetaWindow *window) { return META_WINDOW_ALLOWS_MOVE (window); } gboolean meta_window_can_resize (MetaWindow *window) { return META_WINDOW_ALLOWS_RESIZE (window); } /** * meta_window_can_tile: * @window: a #MetaWindow * @mode: the #MetaTileMode to check for * * Tests if @window can be tiled or snapped in the supplied * tiling zone * * Return value: whether @window can be tiled */ gboolean meta_window_can_tile (MetaWindow *window, MetaTileMode mode) { g_return_val_if_fail (META_IS_WINDOW (window), FALSE); switch (mode) { case META_TILE_LEFT: case META_TILE_RIGHT: return meta_window_can_tile_side_by_side (window); case META_TILE_TOP: case META_TILE_BOTTOM: return meta_window_can_tile_top_bottom (window); case META_TILE_ULC: case META_TILE_LLC: case META_TILE_URC: case META_TILE_LRC: return meta_window_can_tile_corner (window); case META_TILE_MAXIMIZE: case META_TILE_NONE: return TRUE; default: return FALSE; } } static void update_edge_constraints (MetaWindow *window) { switch (window->tile_mode) { case META_TILE_NONE: window->edge_constraints[0] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[1] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[2] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[3] = META_EDGE_CONSTRAINT_NONE; break; case META_TILE_MAXIMIZE: window->edge_constraints[0] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[1] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[2] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[3] = META_EDGE_CONSTRAINT_MONITOR; break; case META_TILE_LEFT: window->edge_constraints[0] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[1] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[2] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[3] = META_EDGE_CONSTRAINT_MONITOR; break; case META_TILE_RIGHT: window->edge_constraints[0] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[1] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[2] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[3] = META_EDGE_CONSTRAINT_NONE; break; case META_TILE_TOP: window->edge_constraints[0] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[1] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[2] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[3] = META_EDGE_CONSTRAINT_MONITOR; break; case META_TILE_BOTTOM: window->edge_constraints[0] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[1] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[2] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[3] = META_EDGE_CONSTRAINT_MONITOR; break; case META_TILE_ULC: window->edge_constraints[0] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[1] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[2] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[3] = META_EDGE_CONSTRAINT_MONITOR; break; case META_TILE_URC: window->edge_constraints[0] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[1] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[2] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[3] = META_EDGE_CONSTRAINT_NONE; break; case META_TILE_LLC: window->edge_constraints[0] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[1] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[2] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[3] = META_EDGE_CONSTRAINT_MONITOR; break; case META_TILE_LRC: window->edge_constraints[0] = META_EDGE_CONSTRAINT_NONE; window->edge_constraints[1] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[2] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[3] = META_EDGE_CONSTRAINT_NONE; break; } /* h/vmaximize also modify the edge constraints */ if (window->maximized_vertically) { window->edge_constraints[0] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[2] = META_EDGE_CONSTRAINT_MONITOR; } if (window->maximized_horizontally) { window->edge_constraints[1] = META_EDGE_CONSTRAINT_MONITOR; window->edge_constraints[3] = META_EDGE_CONSTRAINT_MONITOR; } } /** * meta_window_tile: * @window: a #MetaWindow * @mode: the #MetaTileMode to use * @snap: whether to snap the window (as opposed to simple tile) * * Tiles or snaps the window in the requested configuration * * Return value: whether or not @window was successfully tiled */ gboolean meta_window_tile (MetaWindow *window, MetaTileMode mode, gboolean snap) { g_return_val_if_fail (META_IS_WINDOW (window), FALSE); if (!meta_window_can_tile (window, mode)) return FALSE; if (mode != META_TILE_NONE) { window->last_tile_mode = window->tile_mode; window->snap_queued = snap; window->tile_monitor_number = window->monitor->number; window->tile_mode = mode; window->custom_snap_size = FALSE; window->saved_maximize = FALSE; /* Maximization constraints beat tiling constraints, so if the window * is maximized, tiling won't have any effect unless we unmaximize it * horizontally first; rather than calling meta_window_unmaximize(), * we just set the flag and rely on meta_window_real_tile() syncing it to * save an additional roundtrip. */ meta_window_real_tile (window, TRUE); } else { window->last_tile_mode = window->tile_mode; window->custom_snap_size = FALSE; window->tile_monitor_number = window->saved_maximize ? window->monitor->number : -1; if (window->saved_maximize) meta_window_maximize (window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL); else meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL); } return TRUE; } /** * meta_window_get_icon_name: * @window: a #MetaWindow * * Returns the currently set icon name or icon path for the window. * * Note: * * This will currently only be non-NULL for programs that use XAppGtkWindow * in place of GtkWindow and use xapp_gtk_window_set_icon_name() or * set_icon_from_file(). These methods will need to be used explicitly in * C programs, but for introspection use you should not need to treat it any * differently (except for using the correct window class.) */ const char * meta_window_get_icon_name (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), NULL); return window->theme_icon_name; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/iconcache.c�������������������������������������������������������������������0000664�0001750�0001750�00000043225�14211404421�016741� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window icons */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "iconcache.h" #include "ui.h" #include <meta/errors.h> #include <X11/Xatom.h> /* The icon-reading code is also in libwnck, please sync bugfixes */ static gboolean find_largest_sizes (gulong *data, gulong nitems, int *width, int *height) { *width = 0; *height = 0; while (nitems > 0) { int w, h; if (nitems < 3) return FALSE; /* no space for w, h */ w = data[0]; h = data[1]; if (nitems < ((gulong)(w * h) + 2)) return FALSE; /* not enough data */ *width = MAX (w, *width); *height = MAX (h, *height); data += (w * h) + 2; nitems -= (w * h) + 2; } return TRUE; } static gboolean find_best_size (gulong *data, gulong nitems, int ideal_width, int ideal_height, int *width, int *height, gulong **start) { int best_w; int best_h; gulong *best_start; int max_width, max_height; *width = 0; *height = 0; *start = NULL; if (!find_largest_sizes (data, nitems, &max_width, &max_height)) return FALSE; if (ideal_width < 0) ideal_width = max_width; if (ideal_height < 0) ideal_height = max_height; best_w = 0; best_h = 0; best_start = NULL; while (nitems > 0) { int w, h; gboolean replace; replace = FALSE; if (nitems < 3) return FALSE; /* no space for w, h */ w = data[0]; h = data[1]; if (nitems < ((gulong)(w * h) + 2)) break; /* not enough data */ if (best_start == NULL) { replace = TRUE; } else { /* work with averages */ const int ideal_size = (ideal_width + ideal_height) / 2; int best_size = (best_w + best_h) / 2; int this_size = (w + h) / 2; /* larger than desired is always better than smaller */ if (best_size < ideal_size && this_size >= ideal_size) replace = TRUE; /* if we have too small, pick anything bigger */ else if (best_size < ideal_size && this_size > best_size) replace = TRUE; /* if we have too large, pick anything smaller * but still >= the ideal */ else if (best_size > ideal_size && this_size >= ideal_size && this_size < best_size) replace = TRUE; } if (replace) { best_start = data + 2; best_w = w; best_h = h; } data += (w * h) + 2; nitems -= (w * h) + 2; } if (best_start) { *start = best_start; *width = best_w; *height = best_h; return TRUE; } else return FALSE; } static void argbdata_to_pixdata (gulong *argb_data, int len, guchar **pixdata) { guchar *p; int i; *pixdata = g_new (guchar, len * 4); p = *pixdata; /* One could speed this up a lot. */ i = 0; while (i < len) { guint argb; guint rgba; argb = argb_data[i]; rgba = (argb << 8) | (argb >> 24); *p = rgba >> 24; ++p; *p = (rgba >> 16) & 0xff; ++p; *p = (rgba >> 8) & 0xff; ++p; *p = rgba & 0xff; ++p; ++i; } } static gboolean read_rgb_icon (MetaDisplay *display, Window xwindow, int ideal_width, int ideal_height, int *width, int *height, guchar **pixdata) { Atom type; int format; gulong nitems; gulong bytes_after; int result, err; guchar *data; gulong *best; int w, h; gulong *data_as_long; meta_error_trap_push_with_return (display); type = None; data = NULL; result = XGetWindowProperty (display->xdisplay, xwindow, display->atom__NET_WM_ICON, 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &data); err = meta_error_trap_pop_with_return (display); if (err != Success || result != Success) return FALSE; if (type != XA_CARDINAL) { XFree (data); return FALSE; } data_as_long = (gulong *)data; if (!find_best_size (data_as_long, nitems, ideal_width, ideal_height, &w, &h, &best)) { XFree (data); return FALSE; } *width = w; *height = h; argbdata_to_pixdata (best, w * h, pixdata); XFree (data); return TRUE; } static void free_pixels (guchar *pixels, gpointer data) { free (pixels); } static void get_pixmap_geometry (MetaDisplay *display, Pixmap pixmap, int *w, int *h, int *d) { Window root_ignored; int x_ignored, y_ignored; guint width, height; guint border_width_ignored; guint depth; if (w) *w = 1; if (h) *h = 1; if (d) *d = 1; XGetGeometry (display->xdisplay, pixmap, &root_ignored, &x_ignored, &y_ignored, &width, &height, &border_width_ignored, &depth); if (w) *w = width; if (h) *h = height; if (d) *d = depth; } static void apply_foreground_background (GdkPixbuf *pixbuf) { int w, h; int i, j; guchar *pixels; int stride; w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); pixels = gdk_pixbuf_get_pixels (pixbuf); stride = gdk_pixbuf_get_rowstride (pixbuf); i = 0; while (i < h) { j = 0; while (j < w) { guchar *p = pixels + i * stride + j * 4; if (p[3] == 0) p[0] = p[1] = p[2] = 0xff; /* white background */ else p[0] = p[1] = p[2] = 0x00; /* black foreground */ p[3] = 0xff; ++j; } ++i; } } static GdkPixbuf* apply_mask (GdkPixbuf *pixbuf, GdkPixbuf *mask) { int w, h; int i, j; GdkPixbuf *with_alpha; guchar *src; guchar *dest; int src_stride; int dest_stride; w = MIN (gdk_pixbuf_get_width (mask), gdk_pixbuf_get_width (pixbuf)); h = MIN (gdk_pixbuf_get_height (mask), gdk_pixbuf_get_height (pixbuf)); with_alpha = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); dest = gdk_pixbuf_get_pixels (with_alpha); src = gdk_pixbuf_get_pixels (mask); dest_stride = gdk_pixbuf_get_rowstride (with_alpha); src_stride = gdk_pixbuf_get_rowstride (mask); i = 0; while (i < h) { j = 0; while (j < w) { guchar *s = src + i * src_stride + j * 4; guchar *d = dest + i * dest_stride + j * 4; d[3] = s[3]; ++j; } ++i; } return with_alpha; } static gboolean try_pixmap_and_mask (MetaDisplay *display, Pixmap src_pixmap, Pixmap src_mask, GdkPixbuf **iconp, int ideal_width, int ideal_height) { GdkPixbuf *unscaled = NULL; GdkPixbuf *mask = NULL; int w, h, d; if (src_pixmap == None) return FALSE; meta_error_trap_push (display); get_pixmap_geometry (display, src_pixmap, &w, &h, &d); unscaled = meta_gdk_pixbuf_get_from_pixmap (src_pixmap, 0, 0, w, h); /* A depth 1 pixmap has 0 background, and 1 foreground, but * cairo and meta_gdk_pixbuf_get_from_pixmap consider it * to be 0 transparent, 1 opaque */ if (d == 1) apply_foreground_background (unscaled); if (unscaled && src_mask != None) { get_pixmap_geometry (display, src_mask, &w, &h, &d); if (d == 1) mask = meta_gdk_pixbuf_get_from_pixmap (src_mask, 0, 0, w, h); } meta_error_trap_pop (display); if (mask) { GdkPixbuf *masked; masked = apply_mask (unscaled, mask); g_object_unref (G_OBJECT (unscaled)); unscaled = masked; g_object_unref (G_OBJECT (mask)); mask = NULL; } if (unscaled) { *iconp = gdk_pixbuf_scale_simple (unscaled, ideal_width > 0 ? ideal_width : gdk_pixbuf_get_width (unscaled), ideal_height > 0 ? ideal_height : gdk_pixbuf_get_height (unscaled), GDK_INTERP_BILINEAR); g_object_unref (G_OBJECT (unscaled)); if (*iconp) return TRUE; else { if (*iconp) g_object_unref (G_OBJECT (*iconp)); return FALSE; } } else return FALSE; } static void get_kwm_win_icon (MetaDisplay *display, Window xwindow, Pixmap *pixmap, Pixmap *mask) { Atom type; int format; gulong nitems; gulong bytes_after; guchar *data; Pixmap *icons; int err, result; *pixmap = None; *mask = None; meta_error_trap_push_with_return (display); icons = NULL; result = XGetWindowProperty (display->xdisplay, xwindow, display->atom__KWM_WIN_ICON, 0, G_MAXLONG, False, display->atom__KWM_WIN_ICON, &type, &format, &nitems, &bytes_after, &data); icons = (Pixmap *)data; err = meta_error_trap_pop_with_return (display); if (err != Success || result != Success) return; if (type != display->atom__KWM_WIN_ICON) { XFree (icons); return; } *pixmap = icons[0]; *mask = icons[1]; XFree (icons); return; } LOCAL_SYMBOL void meta_icon_cache_init (MetaIconCache *icon_cache) { g_return_if_fail (icon_cache != NULL); icon_cache->origin = USING_NO_ICON; icon_cache->prev_pixmap = None; icon_cache->prev_mask = None; icon_cache->want_fallback = TRUE; icon_cache->wm_hints_dirty = TRUE; icon_cache->kwm_win_icon_dirty = TRUE; icon_cache->net_wm_icon_dirty = TRUE; } static void clear_icon_cache (MetaIconCache *icon_cache, gboolean dirty_all) { #if 0 if (icon_cache->icon) g_object_unref (G_OBJECT (icon_cache->icon)); icon_cache->icon = NULL; if (icon_cache->mini_icon) g_object_unref (G_OBJECT (icon_cache->mini_icon)); icon_cache->mini_icon = NULL; #endif icon_cache->origin = USING_NO_ICON; if (dirty_all) { icon_cache->wm_hints_dirty = TRUE; icon_cache->kwm_win_icon_dirty = TRUE; icon_cache->net_wm_icon_dirty = TRUE; } } LOCAL_SYMBOL void meta_icon_cache_free (MetaIconCache *icon_cache) { clear_icon_cache (icon_cache, FALSE); } LOCAL_SYMBOL void meta_icon_cache_property_changed (MetaIconCache *icon_cache, MetaDisplay *display, Atom atom) { if (atom == display->atom__NET_WM_ICON) icon_cache->net_wm_icon_dirty = TRUE; else if (atom == display->atom__KWM_WIN_ICON) icon_cache->kwm_win_icon_dirty = TRUE; else if (atom == XA_WM_HINTS) icon_cache->wm_hints_dirty = TRUE; } LOCAL_SYMBOL gboolean meta_icon_cache_get_icon_invalidated (MetaIconCache *icon_cache) { if (icon_cache->origin <= USING_KWM_WIN_ICON && icon_cache->kwm_win_icon_dirty) return TRUE; else if (icon_cache->origin <= USING_WM_HINTS && icon_cache->wm_hints_dirty) return TRUE; else if (icon_cache->origin <= USING_NET_WM_ICON && icon_cache->net_wm_icon_dirty) return TRUE; else if (icon_cache->origin < USING_FALLBACK_ICON && icon_cache->want_fallback) return TRUE; else if (icon_cache->origin == USING_NO_ICON) return TRUE; else if (icon_cache->origin == USING_FALLBACK_ICON && !icon_cache->want_fallback) return TRUE; else return FALSE; } static void replace_cache (MetaIconCache *icon_cache, IconOrigin origin, GdkPixbuf *new_icon) { clear_icon_cache (icon_cache, FALSE); icon_cache->origin = origin; } static GdkPixbuf* scaled_from_pixdata (guchar *pixdata, int w, int h, int new_w, int new_h) { GdkPixbuf *src; GdkPixbuf *dest; src = gdk_pixbuf_new_from_data (pixdata, GDK_COLORSPACE_RGB, TRUE, 8, w, h, w * 4, free_pixels, NULL); if (src == NULL) return NULL; if (w != h) { GdkPixbuf *tmp; int size; size = MAX (w, h); tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size); if (tmp) { gdk_pixbuf_fill (tmp, 0); gdk_pixbuf_copy_area (src, 0, 0, w, h, tmp, (size - w) / 2, (size - h) / 2); g_object_unref (src); src = tmp; } } if (w != new_w || h != new_h) { dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR); g_object_unref (G_OBJECT (src)); } else { dest = src; } return dest; } LOCAL_SYMBOL gboolean meta_read_icons (MetaScreen *screen, Window xwindow, MetaIconCache *icon_cache, Pixmap wm_hints_pixmap, Pixmap wm_hints_mask, GdkPixbuf **iconp, int ideal_width, int ideal_height) { guchar *pixdata; int w, h; Pixmap pixmap; Pixmap mask; /* Return value is whether the icon changed */ g_return_val_if_fail (icon_cache != NULL, FALSE); *iconp = NULL; clear_icon_cache (icon_cache, TRUE); pixdata = NULL; /* Our algorithm here assumes that we can't have for example origin * < USING_NET_WM_ICON and icon_cache->net_wm_icon_dirty == FALSE * unless we have tried to read NET_WM_ICON. * * Put another way, if an icon origin is not dirty, then we have * tried to read it at the current size. If it is dirty, then * we haven't done that since the last change. */ if (icon_cache->origin <= USING_NET_WM_ICON && icon_cache->net_wm_icon_dirty) { icon_cache->net_wm_icon_dirty = FALSE; if (read_rgb_icon (screen->display, xwindow, ideal_width, ideal_height, &w, &h, &pixdata)) { *iconp = scaled_from_pixdata (pixdata, w, h, ideal_width, ideal_height); if (*iconp) { replace_cache (icon_cache, USING_NET_WM_ICON, *iconp); return TRUE; } else { if (*iconp) g_object_unref (G_OBJECT (*iconp)); } } } if (icon_cache->origin <= USING_WM_HINTS && icon_cache->wm_hints_dirty) { icon_cache->wm_hints_dirty = FALSE; pixmap = wm_hints_pixmap; mask = wm_hints_mask; /* We won't update if pixmap is unchanged; * avoids a get_from_drawable() on every geometry * hints change */ if ((pixmap != icon_cache->prev_pixmap || mask != icon_cache->prev_mask) && pixmap != None) { if (try_pixmap_and_mask (screen->display, pixmap, mask, iconp, ideal_width, ideal_height)) { icon_cache->prev_pixmap = pixmap; icon_cache->prev_mask = mask; replace_cache (icon_cache, USING_WM_HINTS, *iconp); return TRUE; } } } if (icon_cache->origin <= USING_KWM_WIN_ICON && icon_cache->kwm_win_icon_dirty) { icon_cache->kwm_win_icon_dirty = FALSE; get_kwm_win_icon (screen->display, xwindow, &pixmap, &mask); if ((pixmap != icon_cache->prev_pixmap || mask != icon_cache->prev_mask) && pixmap != None) { if (try_pixmap_and_mask (screen->display, pixmap, mask, iconp, ideal_width, ideal_height)) { icon_cache->prev_pixmap = pixmap; icon_cache->prev_mask = mask; replace_cache (icon_cache, USING_KWM_WIN_ICON, *iconp); return TRUE; } } } if (icon_cache->origin < USING_FALLBACK_ICON) { replace_cache (icon_cache, USING_FALLBACK_ICON, *iconp); return TRUE; } if (!icon_cache->want_fallback && icon_cache->origin == USING_FALLBACK_ICON) { /* Get rid of current icon */ clear_icon_cache (icon_cache, FALSE); return TRUE; } /* found nothing new */ return FALSE; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/errors.c����������������������������������������������������������������������0000664�0001750�0001750�00000004423�14211404421�016336� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X error handling */ /* * Copyright (C) 2001 Havoc Pennington, error trapping inspired by GDK * code copyrighted by the GTK team. * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:errors * @title: Errors * @short_description: Muffin X error handling */ #include <config.h> #include <meta/errors.h> #include "display-private.h" #include <errno.h> #include <stdlib.h> #include <gdk/gdkx.h> /* In GTK+-3.0, the error trapping code was significantly rewritten. The new code * has some neat features (like knowing automatically if a sync is needed or not * and handling errors asynchronously when the error code isn't needed immediately), * but it's basically incompatible with the hacks we played with GTK+-2.0 to * use a custom error handler along with gdk_error_trap_push(). * * Since the main point of our custom error trap was to get the error logged * to the right place, with GTK+-3.0 we simply omit our own error handler and * use the GTK+ handling straight-up. * (See https://bugzilla.gnome.org/show_bug.cgi?id=630216 for restoring logging.) */ void meta_error_trap_push (MetaDisplay *display) { gdk_x11_display_error_trap_push (display->gdk_display); } void meta_error_trap_pop (MetaDisplay *display) { gdk_x11_display_error_trap_pop_ignored (display->gdk_display); } void meta_error_trap_push_with_return (MetaDisplay *display) { gdk_x11_display_error_trap_push (display->gdk_display); } int meta_error_trap_pop_with_return (MetaDisplay *display) { return gdk_x11_display_error_trap_pop (display->gdk_display); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/eventqueue.c������������������������������������������������������������������0000664�0001750�0001750�00000007605�14211404421�017215� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X event source for main loop */ /* * Copyright (C) 2001 Havoc Pennington (based on GDK code (C) Owen * Taylor, 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #include "eventqueue.h" #include <X11/Xlib.h> static gboolean eq_prepare (GSource *source, gint *timeout); static gboolean eq_check (GSource *source); static gboolean eq_dispatch (GSource *source, GSourceFunc callback, gpointer user_data); static void eq_destroy (GSource *source); static GSourceFuncs eq_funcs = { eq_prepare, eq_check, eq_dispatch, eq_destroy }; struct _MetaEventQueue { GSource source; Display *display; GPollFD poll_fd; int connection_fd; GQueue *events; }; LOCAL_SYMBOL MetaEventQueue* meta_event_queue_new (Display *display, MetaEventQueueFunc func, gpointer data) { GSource *source; MetaEventQueue *eq; source = g_source_new (&eq_funcs, sizeof (MetaEventQueue)); eq = (MetaEventQueue*) source; eq->connection_fd = ConnectionNumber (display); eq->poll_fd.fd = eq->connection_fd; eq->poll_fd.events = G_IO_IN; eq->events = g_queue_new (); eq->display = display; g_source_set_priority (source, G_PRIORITY_DEFAULT); g_source_add_poll (source, &eq->poll_fd); g_source_set_can_recurse (source, TRUE); g_source_set_callback (source, (GSourceFunc) func, data, NULL); g_source_attach (source, NULL); g_source_unref (source); return eq; } LOCAL_SYMBOL void meta_event_queue_free (MetaEventQueue *eq) { GSource *source; source = (GSource*) eq; g_source_destroy (source); } static gboolean eq_events_pending (MetaEventQueue *eq) { return eq->events->length > 0 || XPending (eq->display); } static void eq_queue_events (MetaEventQueue *eq) { XEvent xevent; while (XPending (eq->display)) { XEvent *copy; XNextEvent (eq->display, &xevent); copy = g_new (XEvent, 1); *copy = xevent; g_queue_push_tail (eq->events, copy); } } static gboolean eq_prepare (GSource *source, gint *timeout) { MetaEventQueue *eq; eq = (MetaEventQueue*) source; *timeout = -1; return eq_events_pending (eq); } static gboolean eq_check (GSource *source) { MetaEventQueue *eq; eq = (MetaEventQueue*) source; if (eq->poll_fd.revents & G_IO_IN) return eq_events_pending (eq); else return FALSE; } static gboolean eq_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { MetaEventQueue *eq; eq = (MetaEventQueue*) source; eq_queue_events (eq); if (eq->events->length > 0) { XEvent *event; MetaEventQueueFunc func; event = g_queue_pop_head (eq->events); func = (MetaEventQueueFunc) callback; (* func) (event, user_data); free (event); } return TRUE; } static void eq_destroy (GSource *source) { MetaEventQueue *eq; eq = (MetaEventQueue*) source; while (eq->events->length > 0) { XEvent *event; event = g_queue_pop_head (eq->events); free (event); } g_queue_free (eq->events); /* source itself is freed by glib */ } ���������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/util-private.h����������������������������������������������������������������0000664�0001750�0001750�00000002274�14211404421�017456� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Mutter utilities */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef META_UTIL_PRIVATE_H #define META_UTIL_PRIVATE_H #include <meta/util.h> #include <glib/gi18n-lib.h> void meta_set_verbose (gboolean setting); void meta_set_debugging (gboolean setting); void meta_set_syncing (gboolean setting); void meta_set_replace_current_wm (gboolean setting); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/workspace-private.h�����������������������������������������������������������0000664�0001750�0001750�00000006655�14211404421�020506� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file workspace.h Workspaces * * A workspace is a set of windows which all live on the same * screen. (You may also see the name "desktop" around the place, * which is the EWMH's name for the same thing.) Only one workspace * of a screen may be active at once; all windows on all other workspaces * are unmapped. */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2004, 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_WORKSPACE_PRIVATE_H #define META_WORKSPACE_PRIVATE_H #include <meta/workspace.h> #include "window-private.h" struct _MetaWorkspace { GObject parent_instance; MetaScreen *screen; GList *windows; /* The "MRU list", or "most recently used" list, is a list of * MetaWindows ordered based on the time the the user interacted * with the window most recently. * * For historical reasons, we keep an MRU list per workspace. * It used to be used to calculate the default focused window, * but isn't anymore, as the window next in the stacking order * can sometimes be not the window the user interacted with last, */ GList *mru_list; GList *list_containing_self; MetaRectangle work_area_screen; MetaRectangle *work_area_monitor; GList *screen_region; GList **monitor_region; gint n_monitor_regions; GList *screen_edges; GList *monitor_edges; GSList *builtin_struts; GSList *all_struts; GList *snapped_windows; guint work_areas_invalid : 1; guint showing_desktop : 1; }; struct _MetaWorkspaceClass { GObjectClass parent_class; }; MetaWorkspace* meta_workspace_new (MetaScreen *screen); void meta_workspace_remove (MetaWorkspace *workspace); void meta_workspace_add_window (MetaWorkspace *workspace, MetaWindow *window); void meta_workspace_remove_window (MetaWorkspace *workspace, MetaWindow *window); void meta_workspace_update_snapped_windows (MetaWorkspace *workspace); gboolean meta_workspace_has_snapped_windows (MetaWorkspace *workspace); void meta_workspace_recalc_for_snapped_windows (MetaWorkspace *workspace); void meta_workspace_relocate_windows (MetaWorkspace *workspace, MetaWorkspace *new_home); void meta_workspace_invalidate_work_area (MetaWorkspace *workspace); GList* meta_workspace_get_onscreen_region (MetaWorkspace *workspace); GList* meta_workspace_get_onmonitor_region (MetaWorkspace *workspace, int which_monitor); const char* meta_workspace_get_name (MetaWorkspace *workspace); #endif �����������������������������������������������������������������������������������muffin-5.2.1/src/core/bell.c������������������������������������������������������������������������0000664�0001750�0001750�00000006634�14211404421�015746� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin visual bell */ /* * Copyright (C) 2002 Sun Microsystems Inc. * Copyright (C) 2005, 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:Bell * @short_description: Ring the bell or flash the screen * * Sometimes, X programs "ring the bell", whatever that means. Muffin lets * the user configure the bell to be audible or visible (aka visual), and * if it's visual it can be configured to be frame-flash or fullscreen-flash. * We never get told about audible bells; X handles them just fine by itself. * * Visual bells come in at meta_bell_notify(), which checks we are actually * in visual mode and calls through to bell_visual_notify(). That * function then checks what kind of visual flash you like, and calls either * bell_flash_fullscreen()-- which calls bell_flash_screen() to do * its work-- or bell_flash_frame(), which flashes the focussed window * using bell_flash_window_frame(), unless there is no such window, in * which case it flashes the screen instead. bell_flash_window_frame() * flashes the frame and calls bell_unflash_frame() as a timeout to * remove the flash. * * The visual bell was the result of a discussion in Bugzilla here: * <http://bugzilla.gnome.org/show_bug.cgi?id=99886>. * * Several of the functions in this file are ifdeffed out entirely if we are * found not to have the XKB extension, which is required to do these clever * things with bells; some others are entirely no-ops in that case. */ #include <config.h> #include "bell.h" LOCAL_SYMBOL gboolean meta_bell_init (MetaDisplay *display) { #ifdef HAVE_XKB int xkb_base_error_type, xkb_opcode; if (!XkbQueryExtension (display->xdisplay, &xkb_opcode, &display->xkb_base_event_type, &xkb_base_error_type, NULL, NULL)) { display->xkb_base_event_type = -1; g_message ("could not find XKB extension."); return FALSE; } else { XkbSelectEvents (display->xdisplay, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); return TRUE; } #endif return FALSE; } LOCAL_SYMBOL void meta_bell_shutdown (MetaDisplay *display) { #ifdef HAVE_XKB /* TODO: persist initial bell state in display, reset here */ XkbChangeEnabledControls (display->xdisplay, XkbUseCoreKbd, XkbAudibleBellMask, XkbAudibleBellMask); #endif } LOCAL_SYMBOL void meta_bell_notify (MetaDisplay *display, XkbAnyEvent *xkb_ev) { XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev; MetaWindow *bell_window = NULL; bell_window = meta_display_lookup_x_window (display, xkb_bell_event->window); g_signal_emit_by_name (display, "bell", bell_window); }����������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/bell.h������������������������������������������������������������������������0000664�0001750�0001750�00000006203�14211404421�015743� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file bell.h Ring the bell or flash the screen * * Sometimes, X programs "ring the bell", whatever that means. Muffin lets * the user configure the bell to be audible or visible (aka visual), and * if it's visual it can be configured to be frame-flash or fullscreen-flash. * We never get told about audible bells; X handles them just fine by itself. * * The visual bell was the result of a discussion in Bugzilla here: * <http://bugzilla.gnome.org/show_bug.cgi?id=99886>. */ /* * Copyright (C) 2002 Sun Microsystems 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <X11/Xlib.h> #ifdef HAVE_XKB #include <X11/XKBlib.h> #endif #include "display-private.h" #include "window-private.h" #ifdef HAVE_XKB /** * Gives the user some kind of visual bell; in fact, this is our response * to any kind of bell request, but we set it up so that we only get * notified about visual bells, and X deals with audible ones. * * If the configure script found we had no XKB, this does not exist. * * \param display The display the bell event came in on * \param xkb_ev The bell event we just received */ void meta_bell_notify (MetaDisplay *display, XkbAnyEvent *xkb_ev); #endif /** * Initialises the bell subsystem. This involves intialising * XKB (which, despite being a keyboard extension, is the * place to look for bell notifications), then asking it * to send us bell notifications, and then also switching * off the audible bell if we're using a visual one ourselves. * * Unlike most X extensions we use, we only initialise XKB here * (rather than in main()). It's possible that XKB is not * installed at all, but if that was known at build time * we will have HAVE_XKB undefined, which will cause this * function to be a no-op. * * \param display The display which is opening * * \bug There is a line of code that's never run that tells * XKB to reset the bell status after we quit. Bill H said * (<http://bugzilla.gnome.org/show_bug.cgi?id=99886#c12>) * that XFree86's implementation is broken so we shouldn't * call it, but that was in 2002. Is it working now? */ gboolean meta_bell_init (MetaDisplay *display); /** * Shuts down the bell subsystem. * * \param display The display which is closing * * \bug This is never called! If we had XkbSetAutoResetControls * enabled in meta_bell_init(), this wouldn't be a problem, but * we don't. */ void meta_bell_shutdown (MetaDisplay *display); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/boxes-private.h���������������������������������������������������������������0000664�0001750�0001750�00000025467�14211404421�017632� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Simple box operations */ /* * Copyright (C) 2005, 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_BOXES_PRIVATE_H #define META_BOXES_PRIVATE_H #include <glib-object.h> #include <meta/common.h> #include <meta/boxes.h> #define BOX_LEFT(box) ((box).x) /* Leftmost pixel of rect */ #define BOX_RIGHT(box) ((box).x + (box).width) /* One pixel past right */ #define BOX_TOP(box) ((box).y) /* Topmost pixel of rect */ #define BOX_BOTTOM(box) ((box).y + (box).height) /* One pixel past bottom */ #define BOX_CENTER_X(box) ((box).x + (box).width / 2) /* Center in X */ #define BOX_CENTER_Y(box) ((box).y + (box).height / 2) /* Center in Y */ typedef enum { FIXED_DIRECTION_NONE = 0, FIXED_DIRECTION_X = 1 << 0, FIXED_DIRECTION_Y = 1 << 1, } FixedDirections; /* Output functions -- note that the output buffer had better be big enough: * rect_to_string: RECT_LENGTH * region_to_string: (RECT_LENGTH+strlen(separator_string)) * * g_list_length (region) * edge_to_string: EDGE_LENGTH * edge_list_to_...: (EDGE_LENGTH+strlen(separator_string)) * * g_list_length (edge_list) */ #define RECT_LENGTH 27 #define EDGE_LENGTH 37 char* meta_rectangle_to_string (const MetaRectangle *rect, char *output); char* meta_rectangle_region_to_string (GList *region, const char *separator_string, char *output); char* meta_rectangle_edge_to_string (const MetaEdge *edge, char *output); char* meta_rectangle_edge_list_to_string ( GList *edge_list, const char *separator_string, char *output); /* Resize old_rect to the given new_width and new_height, but store the * result in rect. NOTE THAT THIS IS RESIZE ONLY SO IT CANNOT BE USED FOR * A MOVERESIZE OPERATION (that simplies the routine a little bit as it * means there's no difference between NorthWestGravity and StaticGravity. * Also, I lied a little bit--technically, you could use it in a MoveResize * operation if you muck with old_rect just right). */ void meta_rectangle_resize_with_gravity (const MetaRectangle *old_rect, MetaRectangle *rect, int gravity, int new_width, int new_height); /* find a list of rectangles with the property that a window is contained * in the given region if and only if it is contained in one of the * rectangles in the list. * * In this case, the region is given by taking basic_rect, removing from * it the intersections with all the rectangles in the all_struts list, * then expanding all the rectangles in the resulting list by the given * amounts on each side. * * See boxes.c for more details. */ GList* meta_rectangle_get_minimal_spanning_set_for_region ( const MetaRectangle *basic_rect, const GSList *all_struts); /* Expand all rectangles in region by the given amount on each side */ GList* meta_rectangle_expand_region (GList *region, const int left_expand, const int right_expand, const int top_expand, const int bottom_expand); /* Same as for meta_rectangle_expand_region except that rectangles not at * least min_x or min_y in size are not expanded in that direction */ GList* meta_rectangle_expand_region_conditionally ( GList *region, const int left_expand, const int right_expand, const int top_expand, const int bottom_expand, const int min_x, const int min_y); void meta_rectangle_expand_to_snapped_borders (MetaRectangle *rect, const MetaRectangle *expand_to, const GSList *all_struts, const GSList *snapped_windows_as_struts, const MetaRectangle *user_rect); /* Expand rect in direction to the size of expand_to, and then clip out any * overlapping struts oriented orthognal to the expansion direction. (Think * horizontal or vertical maximization) */ void meta_rectangle_expand_to_avoiding_struts ( MetaRectangle *rect, const MetaRectangle *expand_to, const MetaDirection direction, const GSList *all_struts); /* Free the list created by * meta_rectangle_get_minimal_spanning_set_for_region() * or * meta_rectangle_find_onscreen_edges () * or * meta_rectangle_find_nonintersected_monitor_edges() */ void meta_rectangle_free_list_and_elements (GList *filled_list); /* could_fit_in_region determines whether one of the spanning_rects is * big enough to contain rect. contained_in_region checks whether one * actually contains it. */ gboolean meta_rectangle_could_fit_in_region ( const GList *spanning_rects, const MetaRectangle *rect); gboolean meta_rectangle_contained_in_region ( const GList *spanning_rects, const MetaRectangle *rect); gboolean meta_rectangle_overlaps_with_region ( const GList *spanning_rects, const MetaRectangle *rect); /* Make the rectangle small enough to fit into one of the spanning_rects, * but make it no smaller than min_size. */ void meta_rectangle_clamp_to_fit_into_region ( const GList *spanning_rects, FixedDirections fixed_directions, MetaRectangle *rect, const MetaRectangle *min_size); /* Clip the rectangle so that it fits into one of the spanning_rects, assuming * it overlaps with at least one of them */ void meta_rectangle_clip_to_region (const GList *spanning_rects, FixedDirections fixed_directions, MetaRectangle *rect); /* Shove the rectangle into one of the spanning_rects, assuming it fits in * one of them. */ void meta_rectangle_shove_into_region( const GList *spanning_rects, FixedDirections fixed_directions, MetaRectangle *rect); /* Finds the point on the line connecting (x1,y1) to (x2,y2) which is closest * to (px, py). Useful for finding an optimal rectangle size when given a * range between two sizes that are all candidates. */ void meta_rectangle_find_linepoint_closest_to_point (double x1, double y1, double x2, double y2, double px, double py, double *valx, double *valy); /***************************************************************************/ /* */ /* Switching gears to code for edges instead of just rectangles */ /* */ /***************************************************************************/ /* Return whether an edge overlaps or is adjacent to the rectangle in the * nonzero-width dimension of the edge. */ gboolean meta_rectangle_edge_aligns (const MetaRectangle *rect, const MetaEdge *edge); /* Compare two edges, so that sorting functions can put a list of edges in * canonical order. */ gint meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b); /* Compare two edges, so that sorting functions can put a list of edges in * order. This function doesn't separate left edges first, then right edges, * etc., but rather compares only upon location. */ gint meta_rectangle_edge_cmp_ignore_type (gconstpointer a, gconstpointer b); /* Removes an parts of edges in the given list that intersect any box in the * given rectangle list. Returns the result. */ GList* meta_rectangle_remove_intersections_with_boxes_from_edges ( GList *edges, const GSList *rectangles); /* Finds all the edges of an onscreen region, returning a GList* of * MetaEdgeRect's. */ GList* meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect, const GSList *all_struts); /* Finds edges between adjacent monitors which are not covered by the given * struts. */ GList* meta_rectangle_find_nonintersected_monitor_edges ( const GList *monitor_rects, const GSList *all_struts); #endif /* META_BOXES_PRIVATE_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/testasyncgetprop.c������������������������������������������������������������0000664�0001750�0001750�00000027071�14211404421�020444� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2002 Havoc Pennington * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation. * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of The Open Group shall not be * used in advertising or otherwise to promote the sale, use or other dealings * in this Software without prior written authorization from The Open Group. */ #include "async-getprop.h" #include <time.h> #include <sys/time.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <signal.h> #include <assert.h> #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef NULL #define NULL ((void*) 0) #endif #ifdef HAVE_BACKTRACE #include <execinfo.h> static void print_backtrace (void) { void *bt[500]; int bt_size; int i; char **syms; bt_size = backtrace (bt, 500); syms = backtrace_symbols (bt, bt_size); i = 0; while (i < bt_size) { fprintf (stderr, " %s\n", syms[i]); ++i; } free (syms); } #else static void print_backtrace (void) { fprintf (stderr, "Not compiled with backtrace support\n"); } #endif static int error_trap_depth = 0; static int x_error_handler (Display *xdisplay, XErrorEvent *error) { char buf[64]; XGetErrorText (xdisplay, error->error_code, buf, 63); if (error_trap_depth == 0) { print_backtrace (); fprintf (stderr, "Unexpected X error: %s serial %ld error_code %d request_code %d minor_code %d)\n", buf, error->serial, error->error_code, error->request_code, error->minor_code); exit (1); } return 1; /* return value is meaningless */ } static void error_trap_push (Display *xdisplay) { ++error_trap_depth; } static void error_trap_pop (Display *xdisplay) { if (error_trap_depth == 0) { fprintf (stderr, "Error trap underflow!\n"); exit (1); } XSync (xdisplay, False); /* get all errors out of the queue */ --error_trap_depth; } static char* my_strdup (const char *str) { char *s; s = malloc (strlen (str) + 1); if (s == NULL) { fprintf (stderr, "malloc failed\n"); exit (1); } strcpy (s, str); return s; } static char* atom_name (Display *display, Atom atom) { if (atom == None) { return my_strdup ("None"); } else { char *xname; char *ret; error_trap_push (display); xname = XGetAtomName (display, atom); error_trap_pop (display); if (xname == NULL) return my_strdup ("[unknown atom]"); ret = my_strdup (xname); XFree (xname); return ret; } } #define ELAPSED(start_time, current_time) \ (((((double)current_time.tv_sec - start_time.tv_sec) * 1000000 + \ (current_time.tv_usec - start_time.tv_usec))) / 1000.0) static struct timeval program_start_time; static Bool try_get_reply (Display *xdisplay, AgGetPropertyTask *task) { if (ag_task_have_reply (task)) { int result; Atom actual_type; int actual_format; unsigned long n_items; unsigned long bytes_after; unsigned char *data; char *name; struct timeval current_time; gettimeofday (¤t_time, NULL); printf (" %gms (we have a reply for property %ld)\n", ELAPSED (program_start_time, current_time), ag_task_get_property (task)); data = NULL; name = atom_name (xdisplay, ag_task_get_property (task)); printf (" %s on 0x%lx:\n", name, ag_task_get_window (task)); free (name); result = ag_task_get_reply_and_free (task, &actual_type, &actual_format, &n_items, &bytes_after, &data); task = NULL; if (result != Success) { fprintf (stderr, " error code %d getting reply\n", result); } else { name = atom_name (xdisplay, actual_type); printf (" actual_type = %s\n", name); free (name); printf (" actual_format = %d\n", actual_format); printf (" n_items = %lu\n", n_items); printf (" bytes_after = %lu\n", bytes_after); printf (" data = \"%s\"\n", data ? (char*) data : "NULL"); } return True; } return False; } static void run_speed_comparison (Display *xdisplay, Window window); int main (int argc, char **argv) { Display *xdisplay; int i; int n_left; int n_props; Window window; const char *window_str; char *end; Atom *props; struct timeval current_time; if (argc < 2) { fprintf (stderr, "specify window ID\n"); return 1; } window_str = argv[1]; end = NULL; window = strtoul (window_str, &end, 0); if (end == NULL || *end != '\0') { fprintf (stderr, "\"%s\" does not parse as a window ID\n", window_str); return 1; } xdisplay = XOpenDisplay (NULL); if (xdisplay == NULL) { fprintf (stderr, "Could not open display\n"); return 1; } if (getenv ("MUFFIN_SYNC") != NULL) XSynchronize (xdisplay, True); XSetErrorHandler (x_error_handler); n_props = 0; props = XListProperties (xdisplay, window, &n_props); if (n_props == 0 || props == NULL) { fprintf (stderr, "Window has no properties\n"); return 1; } gettimeofday (&program_start_time, NULL); i = 0; while (i < n_props) { gettimeofday (¤t_time, NULL); printf (" %gms (sending request for property %ld)\n", ELAPSED (program_start_time, current_time), props[i]); if (ag_task_create (xdisplay, window, props[i], 0, 0xffffffff, False, AnyPropertyType) == NULL) { fprintf (stderr, "Failed to send request\n"); return 1; } ++i; } XFree (props); props = NULL; n_left = n_props; while (TRUE) { XEvent xevent; int connection; fd_set set; AgGetPropertyTask *task; /* Mop up event queue */ while (XPending (xdisplay) > 0) { XNextEvent (xdisplay, &xevent); gettimeofday (¤t_time, NULL); printf (" %gms (processing event type %d)\n", ELAPSED (program_start_time, current_time), xevent.xany.type); } while ((task = ag_get_next_completed_task (xdisplay))) { try_get_reply (xdisplay, task); n_left -= 1; } if (n_left == 0) { printf ("All %d replies received.\n", n_props); break; } /* Wake up if we may have a reply */ connection = ConnectionNumber (xdisplay); FD_ZERO (&set); FD_SET (connection, &set); gettimeofday (¤t_time, NULL); printf (" %gms (blocking for data %d left)\n", ELAPSED (program_start_time, current_time), n_left); select (connection + 1, &set, NULL, NULL, NULL); } run_speed_comparison (xdisplay, window); return 0; } /* This function doesn't have all the printf's * and other noise, it just compares async to sync */ static void run_speed_comparison (Display *xdisplay, Window window) { int i; int n_props; struct timeval start, end; int n_left; /* We just use atom values (0 to n_props) % 200, many are probably * BadAtom, that's fine, but the %200 keeps most of them valid. The * async case is about twice as advantageous when using valid atoms * (or the issue may be that it's more advantageous when the * properties are present and data is transmitted). */ n_props = 4000; printf ("Timing with %d property requests\n", n_props); gettimeofday (&start, NULL); i = 0; while (i < n_props) { if (ag_task_create (xdisplay, window, (Atom) i % 200, 0, 0xffffffff, False, AnyPropertyType) == NULL) { fprintf (stderr, "Failed to send request\n"); exit (1); } ++i; } n_left = n_props; while (TRUE) { int connection; fd_set set; XEvent xevent; AgGetPropertyTask *task; /* Mop up event queue */ while (XPending (xdisplay) > 0) XNextEvent (xdisplay, &xevent); while ((task = ag_get_next_completed_task (xdisplay))) { Atom actual_type; int actual_format; unsigned long n_items; unsigned long bytes_after; unsigned char *data; assert (ag_task_have_reply (task)); data = NULL; ag_task_get_reply_and_free (task, &actual_type, &actual_format, &n_items, &bytes_after, &data); if (data) XFree (data); n_left -= 1; } if (n_left == 0) break; /* Wake up if we may have a reply */ connection = ConnectionNumber (xdisplay); FD_ZERO (&set); FD_SET (connection, &set); select (connection + 1, &set, NULL, NULL, NULL); } gettimeofday (&end, NULL); printf ("Async time: %gms\n", ELAPSED (start, end)); gettimeofday (&start, NULL); error_trap_push (xdisplay); i = 0; while (i < n_props) { Atom actual_type; int actual_format; unsigned long n_items; unsigned long bytes_after; unsigned char *data; data = NULL; if (XGetWindowProperty (xdisplay, window, (Atom) i % 200, 0, 0xffffffff, False, AnyPropertyType, &actual_type, &actual_format, &n_items, &bytes_after, &data) == Success) { if (data) XFree (data); } ++i; } error_trap_pop (xdisplay); gettimeofday (&end, NULL); printf ("Sync time: %gms\n", ELAPSED (start, end)); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/constraints.c�����������������������������������������������������������������0000664�0001750�0001750�00000203465�14211404421�017400� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin size/position constraints */ /* * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003, 2004 Rob Adams * Copyright (C) 2005, 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "boxes-private.h" #include "constraints.h" #include "workspace-private.h" #include "place.h" #include <meta/prefs.h> #include "xprops.h" #include <stdlib.h> #include <math.h> #if 0 // This is the short and sweet version of how to hack on this file; see // doc/how-constraints-works.txt for the gory details. The basics of // understanding this file can be shown by the steps needed to add a new // constraint, which are: // 1) Add a new entry in the ConstraintPriority enum; higher values // have higher priority // 2) Write a new function following the format of the example below, // "constrain_whatever". // 3) Add your function to the all_constraints and all_constraint_names // arrays (the latter of which is for debugging purposes) // // An example constraint function, constrain_whatever: // // /* constrain_whatever does the following: // * Quits (returning true) if priority is higher than PRIORITY_WHATEVER // * If check_only is TRUE // * Returns whether the constraint is satisfied or not // * otherwise // * Enforces the constraint // * Note that the value of PRIORITY_WHATEVER is centralized with the // * priorities of other constraints in the definition of ConstrainPriority // * for easier maintenance and shuffling of priorities. // */ // static gboolean // constrain_whatever (MetaWindow *window, // ConstraintInfo *info, // ConstraintPriority priority, // gboolean check_only) // { // if (priority > PRIORITY_WHATEVER) // return TRUE; // // /* Determine whether constraint applies; note that if the constraint // * cannot possibly be satisfied, constraint_applies should be set to // * false. If we don't do this, all constraints with a lesser priority // * will be dropped along with this one, and we'd rather apply as many as // * possible. // */ // if (!constraint_applies) // return TRUE; // // /* Determine whether constraint is already satisfied; if we're only // * checking the status of whether the constraint is satisfied, we end // * here. // */ // if (check_only || constraint_already_satisfied) // return constraint_already_satisfied; // // /* Enforce constraints */ // return TRUE; /* Note that we exited early if check_only is FALSE; also, // * we know we can return TRUE here because we exited early // * if the constraint could not be satisfied; not that the // * return value is heeded in this case... // */ // } #endif typedef enum { PRIORITY_MINIMUM = 0, /* Dummy value used for loop start = min(all priorities) */ PRIORITY_ASPECT_RATIO = 0, PRIORITY_ENTIRELY_VISIBLE_ON_SINGLE_MONITOR = 0, PRIORITY_ENTIRELY_VISIBLE_ON_WORKAREA = 1, PRIORITY_SIZE_HINTS_INCREMENTS = 1, PRIORITY_MAXIMIZATION = 2, PRIORITY_TILING = 2, PRIORITY_FULLSCREEN = 2, PRIORITY_SIZE_HINTS_LIMITS = 3, PRIORITY_TITLEBAR_VISIBLE = 4, PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA = 4, PRIORITY_MAXIMUM = 4 /* Dummy value used for loop end = max(all priorities) */ } ConstraintPriority; typedef enum { ACTION_MOVE, ACTION_RESIZE, ACTION_MOVE_AND_RESIZE } ActionType; typedef struct { MetaRectangle orig; MetaRectangle current; MetaFrameBorders *borders; gboolean must_free_borders; ActionType action_type; gboolean is_user_action; /* I know that these two things probably look similar at first, but they * have much different uses. See doc/how-constraints-works.txt for for * explanation of the differences and similarity between resize_gravity * and fixed_directions */ int resize_gravity; FixedDirections fixed_directions; /* work_area_monitor - current monitor region minus struts * entire_monitor - current monitor, including strut regions */ MetaRectangle work_area_monitor; MetaRectangle entire_monitor; /* Spanning rectangles for the non-covered (by struts) region of the * screen and also for just the current monitor */ GList *usable_screen_region; GList *usable_monitor_region; } ConstraintInfo; static gboolean do_screen_and_monitor_relative_constraints (MetaWindow *window, GList *region_spanning_rectangles, ConstraintInfo *info, gboolean check_only); static gboolean constrain_modal_dialog (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_maximization (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_tiling (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_fullscreen (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_size_increments (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_size_limits (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_aspect_ratio (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_to_single_monitor (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_fully_onscreen (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_titlebar_visible (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static gboolean constrain_partially_onscreen (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); static void setup_constraint_info (ConstraintInfo *info, MetaWindow *window, MetaFrameBorders *orig_borders, MetaMoveResizeFlags flags, int resize_gravity, const MetaRectangle *orig, MetaRectangle *new); static void place_window_if_needed (MetaWindow *window, ConstraintInfo *info); static void update_onscreen_requirements (MetaWindow *window, ConstraintInfo *info); static inline void get_size_limits (const MetaWindow *window, const MetaFrameBorders *borders, gboolean include_frame, MetaRectangle *min_size, MetaRectangle *max_size); typedef gboolean (* ConstraintFunc) (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only); typedef struct { ConstraintFunc func; const char* name; } Constraint; static const Constraint all_constraints[] = { {constrain_modal_dialog, "constrain_modal_dialog"}, {constrain_maximization, "constrain_maximization"}, {constrain_tiling, "constrain_tiling"}, {constrain_fullscreen, "constrain_fullscreen"}, {constrain_size_increments, "constrain_size_increments"}, {constrain_size_limits, "constrain_size_limits"}, {constrain_aspect_ratio, "constrain_aspect_ratio"}, {constrain_to_single_monitor, "constrain_to_single_monitor"}, {constrain_fully_onscreen, "constrain_fully_onscreen"}, {constrain_titlebar_visible, "constrain_titlebar_visible"}, {constrain_partially_onscreen, "constrain_partially_onscreen"}, {NULL, NULL} }; static gboolean do_all_constraints (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { const Constraint *constraint; gboolean satisfied; constraint = &all_constraints[0]; satisfied = TRUE; while (constraint->func != NULL) { satisfied = satisfied && (*constraint->func) (window, info, priority, check_only); if (!check_only) { /* Log how the constraint modified the position */ meta_topic (META_DEBUG_GEOMETRY, "info->current is %d,%d +%d,%d after %s\n", info->current.x, info->current.y, info->current.width, info->current.height, constraint->name); } else if (!satisfied) { /* Log which constraint was not satisfied */ meta_topic (META_DEBUG_GEOMETRY, "constraint %s not satisfied.\n", constraint->name); return FALSE; } ++constraint; } return TRUE; } LOCAL_SYMBOL void meta_window_constrain (MetaWindow *window, MetaFrameBorders *orig_borders, MetaMoveResizeFlags flags, int resize_gravity, const MetaRectangle *orig, MetaRectangle *new) { ConstraintInfo info; ConstraintPriority priority = PRIORITY_MINIMUM; gboolean satisfied = FALSE; /* WARNING: orig and new specify positions and sizes of the inner window, * not the outer. This is a common gotcha since half the constraints * deal with inner window position/size and half deal with outer. See * doc/how-constraints-works.txt for more information. */ meta_topic (META_DEBUG_GEOMETRY, "Constraining %s in move from %d,%d %dx%d to %d,%d %dx%d\n", window->desc, orig->x, orig->y, orig->width, orig->height, new->x, new->y, new->width, new->height); setup_constraint_info (&info, window, orig_borders, flags, resize_gravity, orig, new); place_window_if_needed (window, &info); while (!satisfied && priority <= PRIORITY_MAXIMUM) { gboolean check_only = TRUE; /* Individually enforce all the high-enough priority constraints */ do_all_constraints (window, &info, priority, !check_only); /* Check if all high-enough priority constraints are simultaneously * satisfied */ satisfied = do_all_constraints (window, &info, priority, check_only); /* Drop the least important constraints if we can't satisfy them all */ priority++; } /* Make sure we use the constrained position */ *new = info.current; /* We may need to update window->require_fully_onscreen, * window->require_on_single_monitor, and perhaps other quantities * if this was a user move or user move-and-resize operation. */ update_onscreen_requirements (window, &info); /* Ew, what an ugly way to do things. Destructors (in a real OOP language, * not gobject-style--gobject would be more pain than it's worth) or * smart pointers would be so much nicer here. *shrug* */ if (info.must_free_borders) free (info.borders); } static void setup_constraint_info (ConstraintInfo *info, MetaWindow *window, MetaFrameBorders *orig_borders, MetaMoveResizeFlags flags, int resize_gravity, const MetaRectangle *orig, MetaRectangle *new) { const MetaMonitorInfo *monitor_info; MetaWorkspace *cur_workspace; info->orig = *orig; info->current = *new; /* Create a fake frame geometry if none really exists */ if (orig_borders && !window->fullscreen) { info->borders = orig_borders; info->must_free_borders = FALSE; } else { info->borders = g_new0 (MetaFrameBorders, 1); info->must_free_borders = TRUE; } if (flags & META_IS_MOVE_ACTION && flags & META_IS_RESIZE_ACTION) info->action_type = ACTION_MOVE_AND_RESIZE; else if (flags & META_IS_RESIZE_ACTION) info->action_type = ACTION_RESIZE; else if (flags & META_IS_MOVE_ACTION) info->action_type = ACTION_MOVE; else g_error ("BAD, BAD developer! No treat for you! (Fix your calls to " "meta_window_move_resize_internal()).\n"); info->is_user_action = (flags & META_IS_USER_ACTION); info->resize_gravity = resize_gravity; /* FIXME: fixed_directions might be more sane if we (a) made it * depend on the grab_op type instead of current amount of movement * (thus implying that it only has effect when user_action is true, * and (b) ignored it for aspect ratio windows -- at least in those * cases where both directions do actually change size. */ info->fixed_directions = FIXED_DIRECTION_NONE; /* If x directions don't change but either y direction does */ if ( orig->x == new->x && orig->x + orig->width == new->x + new->width && (orig->y != new->y || orig->y + orig->height != new->y + new->height)) { info->fixed_directions = FIXED_DIRECTION_X; } /* If y directions don't change but either x direction does */ if ( orig->y == new->y && orig->y + orig->height == new->y + new->height && (orig->x != new->x || orig->x + orig->width != new->x + new->width )) { info->fixed_directions = FIXED_DIRECTION_Y; } /* The point of fixed directions is just that "move to nearest valid * position" is sometimes a poorer choice than "move to nearest * valid position but only change this coordinate" for windows the * user is explicitly moving. This isn't ever true for things that * aren't explicit user interaction, though, so just clear it out. */ if (!info->is_user_action) info->fixed_directions = FIXED_DIRECTION_NONE; monitor_info = meta_screen_get_monitor_for_rect (window->screen, &info->current); meta_window_get_work_area_for_monitor (window, monitor_info->number, &info->work_area_monitor); if (!window->fullscreen || window->fullscreen_monitors[0] == -1) { info->entire_monitor = monitor_info->rect; } else { int i = 0; long monitor; monitor = window->fullscreen_monitors[i]; info->entire_monitor = window->screen->monitor_infos[monitor].rect; for (i = 1; i <= 3; i++) { monitor = window->fullscreen_monitors[i]; meta_rectangle_union (&info->entire_monitor, &window->screen->monitor_infos[monitor].rect, &info->entire_monitor); } } cur_workspace = window->screen->active_workspace; info->usable_screen_region = meta_workspace_get_onscreen_region (cur_workspace); info->usable_monitor_region = meta_workspace_get_onmonitor_region (cur_workspace, monitor_info->number); /* Log all this information for debugging */ meta_topic (META_DEBUG_GEOMETRY, "Setting up constraint info:\n" " orig: %d,%d +%d,%d\n" " new : %d,%d +%d,%d\n" " action_type : %s\n" " is_user_action : %s\n" " resize_gravity : %s\n" " fixed_directions: %s\n" " work_area_monitor: %d,%d +%d,%d\n" " entire_monitor : %d,%d +%d,%d\n", info->orig.x, info->orig.y, info->orig.width, info->orig.height, info->current.x, info->current.y, info->current.width, info->current.height, (info->action_type == ACTION_MOVE) ? "Move" : (info->action_type == ACTION_RESIZE) ? "Resize" : (info->action_type == ACTION_MOVE_AND_RESIZE) ? "Move&Resize" : "Freakin' Invalid Stupid", (info->is_user_action) ? "true" : "false", meta_gravity_to_string (info->resize_gravity), (info->fixed_directions == FIXED_DIRECTION_NONE) ? "None" : (info->fixed_directions == FIXED_DIRECTION_X) ? "X fixed" : (info->fixed_directions == FIXED_DIRECTION_Y) ? "Y fixed" : "Freakin' Invalid Stupid", info->work_area_monitor.x, info->work_area_monitor.y, info->work_area_monitor.width, info->work_area_monitor.height, info->entire_monitor.x, info->entire_monitor.y, info->entire_monitor.width, info->entire_monitor.height); } static void place_window_if_needed(MetaWindow *window, ConstraintInfo *info) { gboolean did_placement; /* Do placement if any, so we go ahead and apply position * constraints in a move-only context. Don't place * maximized/minimized/fullscreen windows until they are * unmaximized, unminimized and unfullscreened. */ did_placement = FALSE; if (!window->placed && window->calc_placement && !(window->maximized_horizontally || window->maximized_vertically) && !window->minimized && !window->fullscreen) { MetaRectangle placed_rect = info->orig; MetaWorkspace *cur_workspace; const MetaMonitorInfo *monitor_info; meta_window_place (window, info->borders, info->orig.x, info->orig.y, &placed_rect.x, &placed_rect.y); did_placement = TRUE; /* placing the window may have changed the monitor. Find the * new monitor and update the ConstraintInfo */ monitor_info = meta_screen_get_monitor_for_rect (window->screen, &placed_rect); info->entire_monitor = monitor_info->rect; meta_window_get_work_area_for_monitor (window, monitor_info->number, &info->work_area_monitor); cur_workspace = window->screen->active_workspace; info->usable_monitor_region = meta_workspace_get_onmonitor_region (cur_workspace, monitor_info->number); info->current.x = placed_rect.x; info->current.y = placed_rect.y; /* Since we just barely placed the window, there's no reason to * consider any of the directions fixed. */ info->fixed_directions = FIXED_DIRECTION_NONE; } if (window->placed || did_placement) { if (window->maximize_horizontally_after_placement || window->maximize_vertically_after_placement) { /* define a sane saved_rect so that the user can unmaximize or * make unfullscreen to something reasonable. */ if (info->current.width >= info->work_area_monitor.width) { info->current.width = .75 * info->work_area_monitor.width; info->current.x = info->work_area_monitor.x + .125 * info->work_area_monitor.width; } if (info->current.height >= info->work_area_monitor.height) { info->current.height = .75 * info->work_area_monitor.height; info->current.y = info->work_area_monitor.y + .083 * info->work_area_monitor.height; } /* idle_move_resize() uses the user_rect, * so make sure it uses the placed coordinates. */ window->user_rect = info->current; if (window->maximize_horizontally_after_placement || window->maximize_vertically_after_placement) meta_window_maximize_internal (window, (window->maximize_horizontally_after_placement ? META_MAXIMIZE_HORIZONTAL : 0 ) | (window->maximize_vertically_after_placement ? META_MAXIMIZE_VERTICAL : 0), &info->current); /* maximization may have changed frame geometry */ if (!window->fullscreen) meta_frame_calc_borders (window->frame, info->borders); window->maximize_horizontally_after_placement = FALSE; window->maximize_vertically_after_placement = FALSE; } if (window->minimize_after_placement) { meta_window_minimize (window); window->minimize_after_placement = FALSE; } if (window->tile_after_placement) { window->tile_after_placement = FALSE; gulong *tile_info = NULL; int nitems; if (meta_prop_get_cardinal_list (window->display, window->xwindow, window->display->atom__NET_WM_WINDOW_TILE_INFO, &tile_info, &nitems)) { if (nitems == 8) { window->tile_mode = (MetaTileMode) tile_info[0]; meta_window_move_resize_frame (window, TRUE, tile_info[2], tile_info[3], tile_info[4], tile_info[5]); window->custom_snap_size = tile_info[7] == 1; window->tile_monitor_number = tile_info[6]; if (tile_info[1] == META_WINDOW_TILE_TYPE_SNAPPED) window->snap_queued = TRUE; else window->snap_queued = FALSE; meta_window_real_tile (window, TRUE); window->saved_rect = info->current; meta_XFree (tile_info); } } } } } static void update_onscreen_requirements (MetaWindow *window, ConstraintInfo *info) { gboolean old; /* We only apply the various onscreen requirements to normal windows */ if (window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK) return; /* We don't want to update the requirements for fullscreen windows; * fullscreen windows are specially handled anyway, and it updating * the requirements when windows enter fullscreen mode mess up the * handling of the window when it leaves that mode (especially when * the application sends a bunch of configurerequest events). See * #353699. */ if (window->fullscreen) return; /* USABILITY NOTE: Naturally, I only want the require_fully_onscreen, * require_on_single_monitor, and require_titlebar_visible flags to * *become false* due to user interactions (which is allowed since * certain constraints are ignored for user interactions regardless of * the setting of these flags). However, whether to make these flags * *become true* due to just an application interaction is a little * trickier. It's possible that users may find not doing that strange * since two application interactions that resize in opposite ways don't * necessarily end up cancelling--but it may also be strange for the user * to have an application resize the window so that it's onscreen, the * user forgets about it, and then later the app is able to resize itself * off the screen. Anyway, for now, I think the latter is the more * problematic case but this may need to be revisited. */ /* The require onscreen/on-single-monitor and titlebar_visible * stuff is relative to the outer window, not the inner */ meta_window_extend_by_frame (window, &info->current, info->borders); /* Update whether we want future constraint runs to require the * window to be on fully onscreen. */ old = window->require_fully_onscreen; window->require_fully_onscreen = meta_rectangle_contained_in_region (info->usable_screen_region, &info->current); #ifdef WITH_VERBOSE_MODE if (old ^ window->require_fully_onscreen) meta_topic (META_DEBUG_GEOMETRY, "require_fully_onscreen for %s toggled to %s\n", window->desc, window->require_fully_onscreen ? "TRUE" : "FALSE"); #endif /* Update whether we want future constraint runs to require the * window to be on a single monitor. */ old = window->require_on_single_monitor; window->require_on_single_monitor = meta_rectangle_contained_in_region (info->usable_monitor_region, &info->current); #ifdef WITH_VERBOSE_MODE if (old ^ window->require_on_single_monitor) meta_topic (META_DEBUG_GEOMETRY, "require_on_single_monitor for %s toggled to %s\n", window->desc, window->require_on_single_monitor ? "TRUE" : "FALSE"); #endif /* Update whether we want future constraint runs to require the * titlebar to be visible. */ MetaRectangle titlebar_rect; meta_window_get_titlebar_rect (window, &titlebar_rect); titlebar_rect.x += info->current.x; titlebar_rect.y += info->current.y; old = window->require_titlebar_visible; window->require_titlebar_visible = meta_rectangle_overlaps_with_region (info->usable_screen_region, &titlebar_rect); #ifdef WITH_VERBOSE_MODE if (old ^ window->require_titlebar_visible) meta_topic (META_DEBUG_GEOMETRY, "require_titlebar_visible for %s toggled to %s\n", window->desc, window->require_titlebar_visible ? "TRUE" : "FALSE"); #endif /* Don't forget to restore the position of the window */ meta_window_unextend_by_frame (window, &info->current, info->borders); } static inline void get_size_limits (const MetaWindow *window, const MetaFrameBorders *borders, gboolean include_frame, MetaRectangle *min_size, MetaRectangle *max_size) { /* We pack the results into MetaRectangle structs just for convienience; we * don't actually use the position of those rects. */ min_size->width = window->size_hints.min_width; min_size->height = window->size_hints.min_height; max_size->width = window->size_hints.max_width; max_size->height = window->size_hints.max_height; if (include_frame) { int fw = borders->visible.left + borders->visible.right; int fh = borders->visible.top + borders->visible.bottom; min_size->width += fw; min_size->height += fh; /* Do check to avoid overflow (e.g. max_size->width & max_size->height * may be set to G_MAXINT by meta_set_normal_hints()). */ if (max_size->width < (G_MAXINT - fw)) max_size->width += fw; else max_size->width = G_MAXINT; if (max_size->height < (G_MAXINT - fh)) max_size->height += fh; else max_size->height = G_MAXINT; } } static gboolean constrain_modal_dialog (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { int x, y; MetaWindow *parent = meta_window_get_transient_for (window); gboolean constraint_already_satisfied; if (!meta_window_is_attached_dialog (window)) return TRUE; x = parent->rect.x + (parent->rect.width / 2 - info->current.width / 2); y = parent->rect.y + (parent->rect.height / 2 - info->current.height / 2); if (parent->frame) { x += parent->frame->rect.x; y += parent->frame->rect.y; } constraint_already_satisfied = (x == info->current.x) && (y == info->current.y); if (check_only || constraint_already_satisfied) return constraint_already_satisfied; info->current.y = y; info->current.x = x; /* The calculated position above may need adjustment to make sure the * dialog does not end up partially off-screen */ return do_screen_and_monitor_relative_constraints (window, info->usable_screen_region, info, check_only); } static gboolean constrain_maximization (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { MetaRectangle target_size; MetaRectangle min_size, max_size; gboolean hminbad, vminbad; gboolean horiz_equal, vert_equal; gboolean constraint_already_satisfied; if (priority > PRIORITY_MAXIMIZATION) return TRUE; /* Determine whether constraint applies; exit if it doesn't */ if ((!window->maximized_horizontally && !window->maximized_vertically) || META_WINDOW_TILED_OR_SNAPPED (window)) return TRUE; /* Calculate target_size = maximized size of (window + frame) */ if (META_WINDOW_MAXIMIZED (window) && (g_list_length (window->workspace->snapped_windows) == 0 || window->type == META_WINDOW_DESKTOP)) { target_size = info->work_area_monitor; } else { /* Amount of maximization possible in a single direction depends * on which struts could occlude the window given its current * position. For example, a vertical partial strut on the right * is only relevant for a horizontally maximized window when the * window is at a vertical position where it could be occluded * by that partial strut. */ MetaDirection direction; GSList *active_workspace_struts; if (window->maximized_horizontally) direction = META_DIRECTION_HORIZONTAL; else direction = META_DIRECTION_VERTICAL; active_workspace_struts = window->screen->active_workspace->all_struts; if (g_list_length (window->screen->active_workspace->snapped_windows) > 0) { GList *tmp = window->screen->active_workspace->snapped_windows; GSList *snapped_windows_as_struts = NULL; while (tmp) { if (tmp->data == window || META_WINDOW (tmp->data)->minimized || meta_window_get_monitor (window) != meta_window_get_monitor (META_WINDOW (tmp->data))) { tmp = tmp->next; continue; } MetaStrut *strut = g_slice_new0 (MetaStrut); MetaSide side; MetaRectangle rect; meta_window_get_outer_rect (META_WINDOW (tmp->data), &rect); side = meta_window_get_tile_side (META_WINDOW (tmp->data)); strut->rect = rect; strut->side = side; snapped_windows_as_struts = g_slist_prepend (snapped_windows_as_struts, strut); tmp = tmp->next; } target_size = info->current; meta_window_extend_by_frame (window, &target_size, info->borders); meta_rectangle_expand_to_snapped_borders (&target_size, &info->entire_monitor, active_workspace_struts, snapped_windows_as_struts, &window->user_rect); g_slist_free (snapped_windows_as_struts); } else { target_size = info->current; meta_rectangle_expand_to_avoiding_struts (&target_size, &info->entire_monitor, direction, active_workspace_struts); } } /* Now make target_size = maximized size of client window */ if (!meta_window_is_client_decorated(window)) meta_window_unextend_by_frame (window, &target_size, info->borders); /* Check min size constraints; max size constraints are ignored for maximized * windows, as per bug 327543. */ get_size_limits (window, info->borders, FALSE, &min_size, &max_size); hminbad = target_size.width < min_size.width && window->maximized_horizontally; vminbad = target_size.height < min_size.height && window->maximized_vertically; if (hminbad || vminbad) return TRUE; /* Determine whether constraint is already satisfied; exit if it is */ horiz_equal = target_size.x == info->current.x && target_size.width == info->current.width; vert_equal = target_size.y == info->current.y && target_size.height == info->current.height; constraint_already_satisfied = (horiz_equal || !window->maximized_horizontally) && (vert_equal || !window->maximized_vertically); if (check_only || constraint_already_satisfied) return constraint_already_satisfied; /*** Enforce constraint ***/ if (window->maximized_horizontally) { info->current.x = target_size.x; info->current.width = target_size.width; } if (window->maximized_vertically) { info->current.y = target_size.y; info->current.height = target_size.height; } return TRUE; } static gboolean constrain_tiling (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { MetaRectangle target_size; MetaRectangle min_size, max_size; MetaRectangle actual_position; gboolean hminbad, vminbad; gboolean horiz_equal, vert_equal; gboolean constraint_already_satisfied; if (priority > PRIORITY_TILING) return TRUE; /* Determine whether constraint applies; exit if it doesn't */ if (!META_WINDOW_TILED_OR_SNAPPED (window) || window->resizing_tile_type != META_WINDOW_TILE_TYPE_NONE) return TRUE; /* Calculate target_size - as the tile previews need this as well, we * use an external function for the actual calculation */ if (window->tile_mode != META_TILE_NONE) meta_window_get_current_tile_area (window, &target_size); else return TRUE; meta_window_get_outer_rect (window, &actual_position); if (window->custom_snap_size) { switch (window->tile_mode) { case META_TILE_LEFT: target_size.width = BOX_RIGHT (actual_position) - target_size.x; break; case META_TILE_RIGHT: target_size.width = BOX_RIGHT (target_size) - BOX_LEFT (actual_position); target_size.x = BOX_LEFT (actual_position); break; case META_TILE_TOP: target_size.height = BOX_BOTTOM (actual_position) - BOX_TOP (target_size); break; case META_TILE_BOTTOM: target_size.height = BOX_BOTTOM (target_size) - BOX_TOP (actual_position); target_size.y = BOX_TOP (actual_position); break; case META_TILE_ULC: if (GRAB_OP (window) == META_GRAB_OP_RESIZING_S || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_S) { target_size.width = window->snapped_rect.width; target_size.height = BOX_BOTTOM (actual_position) - BOX_TOP (target_size); } else if (GRAB_OP (window) == META_GRAB_OP_RESIZING_E || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_E) { target_size.width = BOX_RIGHT (actual_position) - target_size.x; target_size.height = window->snapped_rect.height; } else { target_size.width = BOX_RIGHT (actual_position) - target_size.x; target_size.height = BOX_BOTTOM (actual_position) - BOX_TOP (target_size); } break; case META_TILE_LLC: if (GRAB_OP (window) == META_GRAB_OP_RESIZING_N || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_N) { target_size.width = window->snapped_rect.width; target_size.height = BOX_BOTTOM (target_size) - BOX_TOP (actual_position); target_size.y = BOX_TOP (actual_position); } else if (GRAB_OP (window) == META_GRAB_OP_RESIZING_E || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_E) { target_size.width = BOX_RIGHT (actual_position) - target_size.x; target_size.height = window->snapped_rect.height; target_size.y = window->snapped_rect.y; } else { target_size.width = BOX_RIGHT (actual_position) - target_size.x; target_size.height = BOX_BOTTOM (target_size) - BOX_TOP (actual_position); target_size.y = BOX_TOP (actual_position); } break; case META_TILE_URC: if (GRAB_OP (window) == META_GRAB_OP_RESIZING_W || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_W) { target_size.width = BOX_RIGHT (target_size) - BOX_LEFT (actual_position); target_size.x = BOX_LEFT (actual_position); target_size.height = window->snapped_rect.height; } else if (GRAB_OP (window) == META_GRAB_OP_RESIZING_S || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_S) { target_size.width = window->snapped_rect.width; target_size.x = window->snapped_rect.x; target_size.height = BOX_BOTTOM (actual_position) - BOX_TOP (target_size); } else { target_size.width = BOX_RIGHT (target_size) - BOX_LEFT (actual_position); target_size.x = BOX_LEFT (actual_position); target_size.height = BOX_BOTTOM (actual_position) - BOX_TOP (target_size); } break; case META_TILE_LRC: if (GRAB_OP (window) == META_GRAB_OP_RESIZING_W || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_W) { target_size.width = BOX_RIGHT (target_size) - BOX_LEFT (actual_position); target_size.x = BOX_LEFT (actual_position); target_size.height = window->snapped_rect.height; target_size.y = window->snapped_rect.y; } else if (GRAB_OP (window) == META_GRAB_OP_RESIZING_N || GRAB_OP (window) == META_GRAB_OP_KEYBOARD_RESIZING_N) { target_size.width = window->snapped_rect.width; target_size.x = window->snapped_rect.x; target_size.height = BOX_BOTTOM (target_size) - BOX_TOP (actual_position); target_size.y = BOX_TOP (actual_position); } else { target_size.width = BOX_RIGHT (target_size) - BOX_LEFT (actual_position); target_size.x = BOX_LEFT (actual_position); target_size.height = BOX_BOTTOM (target_size) - BOX_TOP (actual_position); target_size.y = BOX_TOP (actual_position); } break; default: break; } } meta_window_unextend_by_frame (window, &target_size, info->borders); /* Check min size constraints; max size constraints are ignored as for * maximized windows. */ get_size_limits (window, info->borders, FALSE, &min_size, &max_size); hminbad = target_size.width < min_size.width; vminbad = target_size.height < min_size.height; if (hminbad || vminbad) return TRUE; /* Determine whether constraint is already satisfied; exit if it is */ horiz_equal = target_size.x == info->current.x && target_size.width == info->current.width; vert_equal = target_size.y == info->current.y && target_size.height == info->current.height; constraint_already_satisfied = horiz_equal && vert_equal; if (check_only || constraint_already_satisfied) return constraint_already_satisfied; /*** Enforce constraint ***/ info->current.x = target_size.x; info->current.width = target_size.width; info->current.y = target_size.y; info->current.height = target_size.height; return TRUE; } static gboolean constrain_fullscreen (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { MetaRectangle min_size, max_size, monitor; gboolean too_big, too_small, constraint_already_satisfied; if (priority > PRIORITY_FULLSCREEN) return TRUE; /* Determine whether constraint applies; exit if it doesn't */ if (!window->fullscreen) return TRUE; monitor = info->entire_monitor; get_size_limits (window, info->borders, FALSE, &min_size, &max_size); too_big = !meta_rectangle_could_fit_rect (&monitor, &min_size); too_small = !meta_rectangle_could_fit_rect (&max_size, &monitor); if (too_big || too_small) return TRUE; /* Determine whether constraint is already satisfied; exit if it is */ constraint_already_satisfied = meta_rectangle_equal (&info->current, &monitor); if (check_only || constraint_already_satisfied) return constraint_already_satisfied; /*** Enforce constraint ***/ info->current = monitor; return TRUE; } static gboolean constrain_size_increments (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { int bh, hi, bw, wi, extra_height, extra_width; int new_width, new_height; gboolean constraint_already_satisfied; MetaRectangle *start_rect; if (priority > PRIORITY_SIZE_HINTS_INCREMENTS) return TRUE; /* Determine whether constraint applies; exit if it doesn't */ if (META_WINDOW_MAXIMIZED (window) || window->fullscreen || META_WINDOW_TILED_OR_SNAPPED (window) || info->action_type == ACTION_MOVE || window->resizing_tile_type != META_WINDOW_TILE_TYPE_NONE) return TRUE; /* Determine whether constraint is already satisfied; exit if it is */ bh = window->size_hints.base_height; hi = window->size_hints.height_inc; bw = window->size_hints.base_width; wi = window->size_hints.width_inc; extra_height = (info->current.height - bh) % hi; extra_width = (info->current.width - bw) % wi; /* ignore size increments for maximized windows */ if (window->maximized_horizontally) extra_width *= 0; if (window->maximized_vertically) extra_height *= 0; /* constraint is satisfied iff there is no extra height or width */ constraint_already_satisfied = (extra_height == 0 && extra_width == 0); if (check_only || constraint_already_satisfied) return constraint_already_satisfied; /*** Enforce constraint ***/ new_width = info->current.width - extra_width; new_height = info->current.height - extra_height; /* Adjusting down instead of up (as done in the above two lines) may * violate minimum size constraints; fix the adjustment if this * happens. */ if (new_width < window->size_hints.min_width) new_width += ((window->size_hints.min_width - new_width)/wi + 1)*wi; if (new_height < window->size_hints.min_height) new_height += ((window->size_hints.min_height - new_height)/hi + 1)*hi; /* Figure out what original rect to pass to meta_rectangle_resize_with_gravity * See bug 448183 */ if (info->action_type == ACTION_MOVE_AND_RESIZE) start_rect = &info->current; else start_rect = &info->orig; /* Resize to the new size */ meta_rectangle_resize_with_gravity (start_rect, &info->current, info->resize_gravity, new_width, new_height); return TRUE; } static gboolean constrain_size_limits (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { MetaRectangle min_size, max_size; gboolean too_big, too_small, constraint_already_satisfied; int new_width, new_height; MetaRectangle *start_rect; if (priority > PRIORITY_SIZE_HINTS_LIMITS) return TRUE; /* Determine whether constraint applies; exit if it doesn't. * * Note: The old code didn't apply this constraint for fullscreen or * maximized windows--but that seems odd to me. *shrug* */ if (info->action_type == ACTION_MOVE) return TRUE; /* Determine whether constraint is already satisfied; exit if it is */ get_size_limits (window, info->borders, FALSE, &min_size, &max_size); /* We ignore max-size limits for maximized windows; see #327543 */ if (window->maximized_horizontally) max_size.width = MAX (max_size.width, info->current.width); if (window->maximized_vertically) max_size.height = MAX (max_size.height, info->current.height); too_small = !meta_rectangle_could_fit_rect (&info->current, &min_size); too_big = !meta_rectangle_could_fit_rect (&max_size, &info->current); constraint_already_satisfied = !too_big && !too_small; if (check_only || constraint_already_satisfied) return constraint_already_satisfied; /*** Enforce constraint ***/ new_width = CLAMP (info->current.width, min_size.width, max_size.width); new_height = CLAMP (info->current.height, min_size.height, max_size.height); /* Figure out what original rect to pass to meta_rectangle_resize_with_gravity * See bug 448183 */ if (info->action_type == ACTION_MOVE_AND_RESIZE) start_rect = &info->current; else start_rect = &info->orig; meta_rectangle_resize_with_gravity (start_rect, &info->current, info->resize_gravity, new_width, new_height); return TRUE; } static gboolean constrain_aspect_ratio (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { double minr, maxr; gboolean constraints_are_inconsistent, constraint_already_satisfied; int fudge, new_width, new_height; double best_width, best_height; double alt_width, alt_height; MetaRectangle *start_rect; if (priority > PRIORITY_ASPECT_RATIO) return TRUE; /* Determine whether constraint applies; exit if it doesn't. */ minr = window->size_hints.min_aspect.x / (double)window->size_hints.min_aspect.y; maxr = window->size_hints.max_aspect.x / (double)window->size_hints.max_aspect.y; constraints_are_inconsistent = minr > maxr; if (constraints_are_inconsistent || META_WINDOW_MAXIMIZED (window) || window->fullscreen || META_WINDOW_TILED_OR_SNAPPED (window) || info->action_type == ACTION_MOVE) return TRUE; /* Determine whether constraint is already satisfied; exit if it is. We * need the following to hold: * * width * minr <= ------ <= maxr * height * * But we need to allow for some slight fudging since width and height * are integers instead of floating point numbers (this is particularly * important when minr == maxr), so we allow width and height to be off * a little bit from strictly satisfying these equations. For just one * sided resizing, we have to make the fudge factor a little bigger * because of how meta_rectangle_resize_with_gravity treats those as * being a resize increment (FIXME: I should handle real resize * increments better here...) */ switch (info->resize_gravity) { case WestGravity: case NorthGravity: case SouthGravity: case EastGravity: fudge = 2; break; case NorthWestGravity: case SouthWestGravity: case CenterGravity: case NorthEastGravity: case SouthEastGravity: case StaticGravity: default: fudge = 1; break; } constraint_already_satisfied = info->current.width - (info->current.height * minr ) > -minr*fudge && info->current.width - (info->current.height * maxr ) < maxr*fudge; if (check_only || constraint_already_satisfied) return constraint_already_satisfied; /*** Enforce constraint ***/ new_width = info->current.width; new_height = info->current.height; switch (info->resize_gravity) { case WestGravity: case EastGravity: /* Yeah, I suck for doing implicit rounding -- sue me */ new_height = CLAMP (new_height, new_width / maxr, new_width / minr); break; case NorthGravity: case SouthGravity: /* Yeah, I suck for doing implicit rounding -- sue me */ new_width = CLAMP (new_width, new_height * minr, new_height * maxr); break; case NorthWestGravity: case SouthWestGravity: case CenterGravity: case NorthEastGravity: case SouthEastGravity: case StaticGravity: default: /* Find what width would correspond to new_height, and what height would * correspond to new_width */ alt_width = CLAMP (new_width, new_height * minr, new_height * maxr); alt_height = CLAMP (new_height, new_width / maxr, new_width / minr); /* The line connecting the points (alt_width, new_height) and * (new_width, alt_height) provide a range of * valid-for-the-aspect-ratio-constraint sizes. We want the * size in that range closest to the value requested, i.e. the * point on the line which is closest to the point (new_width, * new_height) */ meta_rectangle_find_linepoint_closest_to_point (alt_width, new_height, new_width, alt_height, new_width, new_height, &best_width, &best_height); /* Yeah, I suck for doing implicit rounding -- sue me */ new_width = best_width; new_height = best_height; break; } /* Figure out what original rect to pass to meta_rectangle_resize_with_gravity * See bug 448183 */ if (info->action_type == ACTION_MOVE_AND_RESIZE) start_rect = &info->current; else start_rect = &info->orig; meta_rectangle_resize_with_gravity (start_rect, &info->current, info->resize_gravity, new_width, new_height); return TRUE; } static gboolean do_screen_and_monitor_relative_constraints ( MetaWindow *window, GList *region_spanning_rectangles, ConstraintInfo *info, gboolean check_only) { gboolean exit_early = FALSE, constraint_satisfied; MetaRectangle how_far_it_can_be_smushed, min_size, max_size; #ifdef WITH_VERBOSE_MODE if (meta_is_verbose ()) { /* First, log some debugging information */ char spanning_region[1 + 28 * g_list_length (region_spanning_rectangles)]; meta_topic (META_DEBUG_GEOMETRY, "screen/monitor constraint; region_spanning_rectangles: %s\n", meta_rectangle_region_to_string (region_spanning_rectangles, ", ", spanning_region)); } #endif /* Determine whether constraint applies; exit if it doesn't */ how_far_it_can_be_smushed = info->current; get_size_limits (window, info->borders, TRUE, &min_size, &max_size); meta_window_extend_by_frame (window, &info->current, info->borders); if (info->action_type != ACTION_MOVE) { if (!(info->fixed_directions & FIXED_DIRECTION_X)) how_far_it_can_be_smushed.width = min_size.width; if (!(info->fixed_directions & FIXED_DIRECTION_Y)) how_far_it_can_be_smushed.height = min_size.height; } if (!meta_rectangle_could_fit_in_region (region_spanning_rectangles, &how_far_it_can_be_smushed)) exit_early = TRUE; /* Determine whether constraint is already satisfied; exit if it is */ constraint_satisfied = meta_rectangle_contained_in_region (region_spanning_rectangles, &info->current); if (exit_early || constraint_satisfied || check_only) { meta_window_unextend_by_frame (window, &info->current, info->borders); return constraint_satisfied; } /* Enforce constraint */ /* Clamp rectangle size for resize or move+resize actions */ if (info->action_type != ACTION_MOVE) meta_rectangle_clamp_to_fit_into_region (region_spanning_rectangles, info->fixed_directions, &info->current, &min_size); if (info->is_user_action && info->action_type == ACTION_RESIZE) /* For user resize, clip to the relevant region */ meta_rectangle_clip_to_region (region_spanning_rectangles, info->fixed_directions, &info->current); else { /* For everything else, shove the rectangle into the relevant region */ meta_rectangle_shove_into_region (region_spanning_rectangles, info->fixed_directions, &info->current); } meta_window_unextend_by_frame (window, &info->current, info->borders); return TRUE; } static gboolean constrain_to_single_monitor (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { if (priority > PRIORITY_ENTIRELY_VISIBLE_ON_SINGLE_MONITOR) return TRUE; /* Exit early if we know the constraint won't apply--note that this constraint * is only meant for normal windows (e.g. we don't want docks to be shoved * "onscreen" by their own strut) and we can't apply it to frameless windows * or else users will be unable to move windows such as XMMS across monitors. */ if (window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK || window->screen->n_monitor_infos == 1 || !window->require_on_single_monitor || (!window->frame && !meta_window_is_client_decorated (window)) || info->is_user_action) return TRUE; /* Have a helper function handle the constraint for us */ return do_screen_and_monitor_relative_constraints (window, info->usable_monitor_region, info, check_only); } static gboolean constrain_fully_onscreen (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { MetaWindow *transient_for; if (priority > PRIORITY_ENTIRELY_VISIBLE_ON_WORKAREA) return TRUE; transient_for = meta_window_get_transient_for(window); /* Exit early if we know the constraint won't apply--note that this constraint * is only meant for normal windows (e.g. we don't want docks to be shoved * "onscreen" by their own strut). */ if (window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK || window->fullscreen || (transient_for && transient_for->fullscreen) || !window->require_fully_onscreen || info->is_user_action) return TRUE; /* Have a helper function handle the constraint for us */ return do_screen_and_monitor_relative_constraints (window, info->usable_screen_region, info, check_only); } static gboolean constrain_titlebar_visible (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { gboolean unconstrained_user_action; gboolean retval; int bottom_amount; int horiz_amount_offscreen, vert_amount_offscreen; int horiz_amount_onscreen, vert_amount_onscreen; int scale = meta_prefs_get_ui_scale (); if (priority > PRIORITY_TITLEBAR_VISIBLE) return TRUE; /* Allow the titlebar beyond the top of the screen only if the user wasn't * clicking on the frame to start the move. */ unconstrained_user_action = info->is_user_action && !window->display->grab_frame_action; /* Exit early if we know the constraint won't apply--note that this constraint * is only meant for normal windows (e.g. we don't want docks to be shoved * "onscreen" by their own strut). */ if (window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK || window->fullscreen || !window->require_titlebar_visible || unconstrained_user_action) return TRUE; /* Determine how much offscreen things are allowed. We first need to * figure out how much must remain on the screen. For that, we use 25% * window width/height but clamp to the range of (10,75) pixels. This is * somewhat of a seat of my pants random guess at what might look good. * Then, the amount that is allowed off is just the window size minus * this amount (but no less than 0 for tiny windows). */ horiz_amount_onscreen = info->current.width / 4; vert_amount_onscreen = info->current.height / 4; horiz_amount_onscreen = CLAMP (horiz_amount_onscreen, 10 * scale, 75 * scale); vert_amount_onscreen = CLAMP (vert_amount_onscreen, 10 * scale, 75 * scale); horiz_amount_offscreen = info->current.width - horiz_amount_onscreen; vert_amount_offscreen = info->current.height - vert_amount_onscreen; horiz_amount_offscreen = MAX (horiz_amount_offscreen, 0); vert_amount_offscreen = MAX (vert_amount_offscreen, 0); /* Allow the titlebar to touch the bottom panel; If there is no titlebar, * require vert_amount to remain on the screen. */ if (window->frame) { bottom_amount = info->current.height + info->borders->visible.bottom; vert_amount_onscreen = info->borders->visible.top; } else if (meta_window_is_client_decorated (window)) { vert_amount_onscreen = CSD_TITLEBAR_HEIGHT * scale; /* Hardcoded for now, we don't get this from Gtk */ bottom_amount = vert_amount_offscreen = MAX ((info->current.height - (vert_amount_onscreen * 2)), 0); } else bottom_amount = vert_amount_offscreen; /* Extend the region, have a helper function handle the constraint, * then return the region to its original size. */ meta_rectangle_expand_region_conditionally (info->usable_screen_region, horiz_amount_offscreen, horiz_amount_offscreen, 0, /* Don't let titlebar off */ bottom_amount, horiz_amount_onscreen, vert_amount_onscreen); retval = do_screen_and_monitor_relative_constraints (window, info->usable_screen_region, info, check_only); meta_rectangle_expand_region_conditionally (info->usable_screen_region, -horiz_amount_offscreen, -horiz_amount_offscreen, 0, /* Don't let titlebar off */ -bottom_amount, horiz_amount_onscreen, vert_amount_onscreen); return retval; } static gboolean constrain_partially_onscreen (MetaWindow *window, ConstraintInfo *info, ConstraintPriority priority, gboolean check_only) { gboolean retval; int top_amount, bottom_amount; int horiz_amount_offscreen, vert_amount_offscreen; int horiz_amount_onscreen, vert_amount_onscreen; int scale = meta_prefs_get_ui_scale (); if (priority > PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA) return TRUE; /* Exit early if we know the constraint won't apply--note that this constraint * is only meant for normal windows (e.g. we don't want docks to be shoved * "onscreen" by their own strut). */ if (window->type == META_WINDOW_DESKTOP || window->type == META_WINDOW_DOCK) return TRUE; /* Determine how much offscreen things are allowed. We first need to * figure out how much must remain on the screen. For that, we use 25% * window width/height but clamp to the range of (10,75) pixels. This is * somewhat of a seat of my pants random guess at what might look good. * Then, the amount that is allowed off is just the window size minus * this amount (but no less than 0 for tiny windows). */ horiz_amount_onscreen = info->current.width / 4; vert_amount_onscreen = info->current.height / 4; horiz_amount_onscreen = CLAMP (horiz_amount_onscreen, 10 * scale, 75 * scale); vert_amount_onscreen = CLAMP (vert_amount_onscreen, 10 * scale, 75 * scale); horiz_amount_offscreen = info->current.width - horiz_amount_onscreen; vert_amount_offscreen = info->current.height - vert_amount_onscreen; horiz_amount_offscreen = MAX (horiz_amount_offscreen, 0); vert_amount_offscreen = MAX (vert_amount_offscreen, 0); top_amount = vert_amount_offscreen; /* Allow the titlebar to touch the bottom panel; If there is no titlebar, * require vert_amount to remain on the screen. */ if (window->frame) { bottom_amount = info->current.height + info->borders->visible.bottom; vert_amount_onscreen = info->borders->visible.top; } else { bottom_amount = vert_amount_offscreen; } /* Extend the region, have a helper function handle the constraint, * then return the region to its original size. */ meta_rectangle_expand_region_conditionally (info->usable_screen_region, horiz_amount_offscreen, horiz_amount_offscreen, top_amount, bottom_amount, horiz_amount_onscreen, vert_amount_onscreen); retval = do_screen_and_monitor_relative_constraints (window, info->usable_screen_region, info, check_only); meta_rectangle_expand_region_conditionally (info->usable_screen_region, -horiz_amount_offscreen, -horiz_amount_offscreen, -top_amount, -bottom_amount, horiz_amount_onscreen, vert_amount_onscreen); return retval; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/async-getprop.c���������������������������������������������������������������0000664�0001750�0001750�00000043031�14211404421�017613� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Asynchronous X property getting hack */ /* * Copyright (C) 2002 Havoc Pennington * Copyright (C) 1986, 1998 The Open Group * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation. * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of The Open Group shall not be * used in advertising or otherwise to promote the sale, use or other dealings * in this Software without prior written authorization from The Open Group. */ #if HAVE_CONFIG_H #include <config.h> #endif #include <assert.h> #undef DEBUG_SPEW #ifdef DEBUG_SPEW #include <stdio.h> #endif #include "async-getprop.h" #define NEED_REPLIES #include <X11/Xlibint.h> #ifndef NULL #define NULL ((void*)0) #endif typedef struct _ListNode ListNode; typedef struct _AgPerDisplayData AgPerDisplayData; struct _ListNode { ListNode *next; }; struct _AgGetPropertyTask { ListNode node; AgPerDisplayData *dd; Window window; Atom property; unsigned long request_seq; int error; Atom actual_type; int actual_format; unsigned long n_items; unsigned long bytes_after; char *data; Bool have_reply; }; struct _AgPerDisplayData { ListNode node; _XAsyncHandler async; Display *display; ListNode *pending_tasks; ListNode *pending_tasks_tail; ListNode *completed_tasks; ListNode *completed_tasks_tail; int n_tasks_pending; int n_tasks_completed; }; static ListNode *display_datas = NULL; static ListNode *display_datas_tail = NULL; static void append_to_list (ListNode **head, ListNode **tail, ListNode *task) { task->next = NULL; if (*tail == NULL) { assert (*head == NULL); *head = task; *tail = task; } else { (*tail)->next = task; *tail = task; } } static void remove_from_list (ListNode **head, ListNode **tail, ListNode *task) { ListNode *prev; ListNode *node; prev = NULL; node = *head; while (node != NULL) { if (node == task) { if (prev) prev->next = node->next; else *head = node->next; if (node == *tail) *tail = prev; break; } prev = node; node = node->next; } /* can't remove what's not there */ assert (node != NULL); node->next = NULL; } static void move_to_completed (AgPerDisplayData *dd, AgGetPropertyTask *task) { remove_from_list (&dd->pending_tasks, &dd->pending_tasks_tail, &task->node); append_to_list (&dd->completed_tasks, &dd->completed_tasks_tail, &task->node); dd->n_tasks_pending -= 1; dd->n_tasks_completed += 1; } static AgGetPropertyTask* find_pending_by_request_sequence (AgPerDisplayData *dd, unsigned long request_seq) { ListNode *node; /* if the sequence is after our last pending task, we * aren't going to find a match */ { AgGetPropertyTask *task = (AgGetPropertyTask*) dd->pending_tasks_tail; if (task != NULL) { if (task->request_seq < request_seq) return NULL; else if (task->request_seq == request_seq) return task; /* why not check this */ } } /* Generally we should get replies in the order we sent * requests, so we should usually be using the task * at the head of the list, if we use any task at all. * I'm not sure this is 100% guaranteed, if it is, * it would be a big speedup. */ node = dd->pending_tasks; while (node != NULL) { AgGetPropertyTask *task = (AgGetPropertyTask*) node; if (task->request_seq == request_seq) return task; node = node->next; } return NULL; } static Bool async_get_property_handler (Display *dpy, xReply *rep, char *buf, int len, XPointer data) { xGetPropertyReply replbuf; xGetPropertyReply *reply; AgGetPropertyTask *task; AgPerDisplayData *dd; int bytes_read; dd = (AgPerDisplayData*) data; #if 0 printf ("%s: seeing request seq %ld buflen %d\n", __FUNCTION__, dpy->last_request_read, len); #endif task = find_pending_by_request_sequence (dd, dpy->last_request_read); if (task == NULL) return False; assert (dpy->last_request_read == task->request_seq); task->have_reply = True; move_to_completed (dd, task); /* read bytes so far */ bytes_read = SIZEOF (xReply); if (rep->generic.type == X_Error) { xError errbuf; task->error = rep->error.errorCode; #ifdef DEBUG_SPEW printf ("%s: error code = %d (ignoring error, eating %d bytes, generic.length = %ld)\n", __FUNCTION__, task->error, (SIZEOF (xError) - bytes_read), rep->generic.length); #endif /* We return True (meaning we consumed the reply) * because otherwise it would invoke the X error handler, * and an async API is useless if you have to synchronously * trap X errors. Also GetProperty can always fail, pretty * much, so trapping errors is always what you want. * * We have to eat all the error reply data here. * (kind of a charade as we know sizeof(xError) == sizeof(xReply)) * * Passing discard = True seems to break things; I don't understand * why, because there should be no extra data in an error reply, * right? */ _XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len, (SIZEOF (xError) - bytes_read) >> 2, /* in 32-bit words */ False); /* really seems like it should be True */ return True; } #ifdef DEBUG_SPEW printf ("%s: already read %d bytes reading %d more for total of %d; generic.length = %ld\n", __FUNCTION__, bytes_read, (SIZEOF (xGetPropertyReply) - bytes_read) >> 2, SIZEOF (xGetPropertyReply), rep->generic.length); #endif /* (kind of a silly as we know sizeof(xGetPropertyReply) == sizeof(xReply)) */ reply = (xGetPropertyReply *) _XGetAsyncReply (dpy, (char *)&replbuf, rep, buf, len, (SIZEOF (xGetPropertyReply) - bytes_read) >> 2, /* in 32-bit words */ False); /* False means expecting more data to follow, * don't eat the rest of the reply */ bytes_read = SIZEOF (xGetPropertyReply); #ifdef DEBUG_SPEW printf ("%s: have reply propertyType = %ld format = %d n_items = %ld\n", __FUNCTION__, reply->propertyType, reply->format, reply->nItems); #endif assert (task->data == NULL); /* This is all copied from XGetWindowProperty(). Not sure we should * LockDisplay(). Not sure I'm passing the right args to * XGetAsyncData(). Not sure about a lot of things. */ /* LockDisplay (dpy); */ if (reply->propertyType != None) { long nbytes, netbytes; /* this alignment macro from orbit2 */ #define ALIGN_VALUE(this, boundary) \ (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) switch (reply->format) { /* * One extra byte is malloced than is needed to contain the property * data, but this last byte is null terminated and convenient for * returning string properties, so the client doesn't then have to * recopy the string to make it null terminated. */ case 8: nbytes = reply->nItems; /* there's padding to word boundary */ netbytes = ALIGN_VALUE (nbytes, 4); if (nbytes + 1 > 0 && (task->data = (char *) Xmalloc ((unsigned)nbytes + 1))) { #ifdef DEBUG_SPEW printf ("%s: already read %d bytes using %ld, more eating %ld more\n", __FUNCTION__, bytes_read, nbytes, netbytes); #endif /* _XReadPad (dpy, (char *) task->data, netbytes); */ _XGetAsyncData (dpy, task->data, buf, len, bytes_read, nbytes, netbytes); } break; case 16: nbytes = reply->nItems * sizeof (short); netbytes = reply->nItems << 1; netbytes = ALIGN_VALUE (netbytes, 4); /* align to word boundary */ if (nbytes + 1 > 0 && (task->data = (char *) Xmalloc ((unsigned)nbytes + 1))) { #ifdef DEBUG_SPEW printf ("%s: already read %d bytes using %ld more, eating %ld more\n", __FUNCTION__, bytes_read, nbytes, netbytes); #endif /* _XRead16Pad (dpy, (short *) task->data, netbytes); */ _XGetAsyncData (dpy, task->data, buf, len, bytes_read, nbytes, netbytes); } break; case 32: /* NOTE buffer is in longs to match XGetWindowProperty() */ nbytes = reply->nItems * sizeof (long); netbytes = reply->nItems << 2; /* wire size is always 32 bits though */ if (nbytes + 1 > 0 && (task->data = (char *) Xmalloc ((unsigned)nbytes + 1))) { #ifdef DEBUG_SPEW printf ("%s: already read %d bytes using %ld more, eating %ld more\n", __FUNCTION__, bytes_read, nbytes, netbytes); #endif /* We have to copy the XGetWindowProperty() crackrock * and get format 32 as long even on 64-bit platforms. */ if (sizeof (long) == 8) { char *netdata; char *lptr; char *end_lptr; /* Store the 32-bit values in the end of the array */ netdata = task->data + nbytes / 2; _XGetAsyncData (dpy, netdata, buf, len, bytes_read, netbytes, netbytes); /* Now move the 32-bit values to the front */ lptr = task->data; end_lptr = task->data + nbytes; while (lptr != end_lptr) { *(long*) lptr = *(CARD32*) netdata; lptr += sizeof (long); netdata += sizeof (CARD32); } } else { /* Here the wire format matches our actual format */ _XGetAsyncData (dpy, task->data, buf, len, bytes_read, netbytes, netbytes); } } break; default: /* * This part of the code should never be reached. If it is, * the server sent back a property with an invalid format. * This is a BadImplementation error. * * However this async GetProperty API doesn't report errors * via the standard X mechanism, so don't do anything about * it, other than store it in task->error. */ { #if 0 xError error; #endif task->error = BadImplementation; #if 0 error.sequenceNumber = task->request_seq; error.type = X_Error; error.majorCode = X_GetProperty; error.minorCode = 0; error.errorCode = BadImplementation; _XError (dpy, &error); #endif } nbytes = netbytes = 0L; break; } if (task->data == NULL) { task->error = BadAlloc; #ifdef DEBUG_SPEW printf ("%s: already read %d bytes eating %ld\n", __FUNCTION__, bytes_read, netbytes); #endif /* _XEatData (dpy, (unsigned long) netbytes); */ _XGetAsyncData (dpy, NULL, buf, len, bytes_read, 0, netbytes); /* UnlockDisplay (dpy); */ return BadAlloc; /* not Success */ } (task->data)[nbytes] = '\0'; } #ifdef DEBUG_SPEW printf ("%s: have data\n", __FUNCTION__); #endif task->actual_type = reply->propertyType; task->actual_format = reply->format; task->n_items = reply->nItems; task->bytes_after = reply->bytesAfter; /* UnlockDisplay (dpy); */ return True; } static AgPerDisplayData* get_display_data (Display *display, Bool create) { ListNode *node; AgPerDisplayData *dd; node = display_datas; while (node != NULL) { dd = (AgPerDisplayData*) node; if (dd->display == display) return dd; node = node->next; } if (!create) return NULL; dd = Xcalloc (1, sizeof (AgPerDisplayData)); if (dd == NULL) return NULL; dd->display = display; dd->async.next = display->async_handlers; dd->async.handler = async_get_property_handler; dd->async.data = (XPointer) dd; dd->display->async_handlers = &dd->async; append_to_list (&display_datas, &display_datas_tail, &dd->node); return dd; } static void maybe_free_display_data (AgPerDisplayData *dd) { if (dd->pending_tasks == NULL && dd->completed_tasks == NULL) { DeqAsyncHandler (dd->display, &dd->async); remove_from_list (&display_datas, &display_datas_tail, &dd->node); XFree (dd); } } LOCAL_SYMBOL AgGetPropertyTask* ag_task_create (Display *dpy, Window window, Atom property, long offset, long length, Bool delete, Atom req_type) { AgGetPropertyTask *task; xGetPropertyReq *req; AgPerDisplayData *dd; /* Fire up our request */ LockDisplay (dpy); dd = get_display_data (dpy, True); if (dd == NULL) { UnlockDisplay (dpy); return NULL; } GetReq (GetProperty, req); req->window = window; req->property = property; req->type = req_type; req->delete = delete; req->longOffset = offset; req->longLength = length; /* Queue up our async task */ task = Xcalloc (1, sizeof (AgGetPropertyTask)); if (task == NULL) { UnlockDisplay (dpy); return NULL; } task->dd = dd; task->window = window; task->property = property; task->request_seq = dpy->request; append_to_list (&dd->pending_tasks, &dd->pending_tasks_tail, &task->node); dd->n_tasks_pending += 1; UnlockDisplay (dpy); SyncHandle (); return task; } static void free_task (AgGetPropertyTask *task) { remove_from_list (&task->dd->completed_tasks, &task->dd->completed_tasks_tail, &task->node); task->dd->n_tasks_completed -= 1; maybe_free_display_data (task->dd); XFree (task); } LOCAL_SYMBOL Status ag_task_get_reply_and_free (AgGetPropertyTask *task, Atom *actual_type, int *actual_format, unsigned long *nitems, unsigned long *bytesafter, unsigned char **prop) { Display *dpy; *prop = NULL; dpy = task->dd->display; /* Xlib macros require a variable named "dpy" */ if (task->error != Success) { Status s = task->error; free_task (task); return s; } if (!task->have_reply) { free_task (task); return BadAlloc; /* not Success */ } *actual_type = task->actual_type; *actual_format = task->actual_format; *nitems = task->n_items; *bytesafter = task->bytes_after; *prop = (unsigned char*) task->data; /* pass out ownership of task->data */ SyncHandle (); free_task (task); return Success; } LOCAL_SYMBOL Bool ag_task_have_reply (AgGetPropertyTask *task) { return task->have_reply; } LOCAL_SYMBOL Atom ag_task_get_property (AgGetPropertyTask *task) { return task->property; } LOCAL_SYMBOL Window ag_task_get_window (AgGetPropertyTask *task) { return task->window; } LOCAL_SYMBOL Display* ag_task_get_display (AgGetPropertyTask *task) { return task->dd->display; } LOCAL_SYMBOL AgGetPropertyTask* ag_get_next_completed_task (Display *display) { AgPerDisplayData *dd; dd = get_display_data (display, False); if (dd == NULL) return NULL; #ifdef DEBUG_SPEW printf ("%d pending %d completed\n", dd->n_tasks_pending, dd->n_tasks_completed); #endif return (AgGetPropertyTask*) dd->completed_tasks; } LOCAL_SYMBOL void* ag_Xmalloc (unsigned long bytes) { return (void*) Xmalloc (bytes); } LOCAL_SYMBOL void* ag_Xmalloc0 (unsigned long bytes) { return (void*) Xcalloc (bytes, 1); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/muffin.c����������������������������������������������������������������������0000664�0001750�0001750�00000004461�14211404421�016310� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright 2011 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include <stdlib.h> #include <meta/main.h> #include <meta/util.h> #include "meta-plugin-manager.h" #include <glib/gi18n-lib.h> #include <glib.h> static gboolean print_version (const gchar *option_name, const gchar *value, gpointer data, GError **error) { const int latest_year = 2011; g_print (_("muffin %s\n" "Copyright (C) 2001-%d Havoc Pennington, Red Hat, Inc., and others\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"), VERSION, latest_year); exit (0); } static gchar *plugin = "default"; GOptionEntry muffin_options[] = { { "version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, print_version, N_("Print version"), NULL }, { "muffin-plugin", 0, 0, G_OPTION_ARG_STRING, &plugin, N_("Muffin plugin to use"), "PLUGINS" }, { NULL } }; int main (int argc, char **argv) { GOptionContext *ctx; GError *error = NULL; g_setenv ("CLUTTER_BACKEND", "x11", TRUE); ctx = meta_get_option_context (); g_option_context_add_main_entries (ctx, muffin_options, GETTEXT_PACKAGE); if (!g_option_context_parse (ctx, &argc, &argv, &error)) { g_printerr ("muffin: %s\n", error->message); exit (1); } if (plugin) meta_plugin_manager_load (plugin); meta_init (); return meta_run (); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/display.c���������������������������������������������������������������������0000664�0001750�0001750�00000531367�14211404421�016503� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X display handler */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. * Copyright (C) 2003, 2004 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:display * @title: MetaDisplay * @short_description: Handles operations on an X display. * * The display is represented as a MetaDisplay struct. */ #define _XOPEN_SOURCE 600 /* for gethostname() */ #include <config.h> #include <errno.h> #include "display-private.h" #include <meta/util.h> #include <meta/main.h> #include "screen-private.h" #include "window-private.h" #include "window-props.h" #include "group-props.h" #include "frame.h" #include <meta/errors.h> #include "keybindings-private.h" #include <meta/prefs.h> #include "resizepopup.h" #include "xprops.h" #include "workspace-private.h" #include "bell.h" #include <meta/compositor.h> #include <X11/Xatom.h> #include <X11/cursorfont.h> #include "muffin-enum-types.h" #ifdef HAVE_SOLARIS_XINERAMA #include <X11/extensions/xinerama.h> #endif #ifdef HAVE_XFREE_XINERAMA #include <X11/extensions/Xinerama.h> #endif #ifdef HAVE_RANDR #include <X11/extensions/Xrandr.h> #endif #ifdef HAVE_SHAPE #include <X11/extensions/shape.h> #endif #ifdef HAVE_XKB #include <X11/XKBlib.h> #endif #ifdef HAVE_XCURSOR #include <X11/Xcursor/Xcursor.h> #endif #include <X11/extensions/Xrender.h> #include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xdamage.h> #include <X11/extensions/Xfixes.h> #include <string.h> #include <unistd.h> #define GRAB_OP_IS_WINDOW_SWITCH(g) \ (g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \ g == META_GRAB_OP_KEYBOARD_TABBING_DOCK || \ g == META_GRAB_OP_KEYBOARD_TABBING_GROUP || \ g == META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL || \ g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK || \ g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP) /* * \defgroup pings Pings * * Sometimes we want to see whether a window is responding, * so we send it a "ping" message and see whether it sends us back a "pong" * message within a reasonable time. Here we have a system which lets us * nominate one function to be called if we get the pong in time and another * function if we don't. The system is rather more complicated than it needs * to be, since we only ever use it to destroy windows which are asked to * close themselves and don't do so within a reasonable amount of time, and * therefore we always use the same callbacks. It's possible that we might * use it for other things in future, or on the other hand we might decide * that we're never going to do so and simplify it a bit. */ /* * Describes a ping on a window. When we send a ping to a window, we build * one of these structs, and it eventually gets passed to the timeout function * or to the function which handles the response from the window. If the window * does or doesn't respond to the ping, we use this information to deal with * these facts; we have a handler function for each. * * \ingroup pings */ typedef struct { MetaDisplay *display; Window xwindow; guint32 timestamp; MetaWindowPingFunc ping_reply_func; MetaWindowPingFunc ping_timeout_func; void *user_data; guint ping_timeout_id; } MetaPingData; typedef struct { MetaDisplay *display; Window xwindow; } MetaAutoRaiseData; G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT); /* Signals */ enum { FOCUS_WINDOW, WINDOW_CREATED, WINDOW_DEMANDS_ATTENTION, WINDOW_MARKED_URGENT, GRAB_OP_BEGIN, GRAB_OP_END, ZOOM_SCROLL_IN, ZOOM_SCROLL_OUT, BELL, GL_VIDEO_MEMORY_PURGED, RESTART, LAST_SIGNAL }; enum { PROP_0, PROP_FOCUS_WINDOW }; static guint display_signals [LAST_SIGNAL] = { 0 }; /* * The display we're managing. This is a singleton object. (Historically, * this was a list of displays, but there was never any way to add more * than one element to it.) The goofy name is because we don't want it * to shadow the parameter in its object methods. */ static MetaDisplay *the_display = NULL; #ifdef WITH_VERBOSE_MODE static void meta_spew_event (MetaDisplay *display, XEvent *event); #endif static gboolean event_callback (XEvent *event, gpointer data); static Window event_get_modified_window (MetaDisplay *display, XEvent *event); static guint32 event_get_time (MetaDisplay *display, XEvent *event); static void process_request_frame_extents (MetaDisplay *display, XEvent *event); static void process_pong_message (MetaDisplay *display, XEvent *event); static void process_selection_request (MetaDisplay *display, XEvent *event); static void process_selection_clear (MetaDisplay *display, XEvent *event); static void update_window_grab_modifiers (MetaDisplay *display); static void update_mouse_zoom_modifiers (MetaDisplay *display); static void prefs_changed_callback (MetaPreference pref, void *data); static void sanity_check_timestamps (MetaDisplay *display, guint32 known_good_timestamp); static MetaGroup* get_focussed_group (MetaDisplay *display); static void meta_display_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MetaDisplay *display = META_DISPLAY (object); switch (prop_id) { case PROP_FOCUS_WINDOW: g_value_set_object (value, display->focus_window); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_display_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void meta_display_class_init (MetaDisplayClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = meta_display_get_property; object_class->set_property = meta_display_set_property; display_signals[WINDOW_CREATED] = g_signal_new ("window-created", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); display_signals[WINDOW_DEMANDS_ATTENTION] = g_signal_new ("window-demands-attention", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); display_signals[WINDOW_MARKED_URGENT] = g_signal_new ("window-marked-urgent", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); display_signals[GRAB_OP_BEGIN] = g_signal_new ("grab-op-begin", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 3, META_TYPE_SCREEN, META_TYPE_WINDOW, META_TYPE_GRAB_OP); display_signals[GRAB_OP_END] = g_signal_new ("grab-op-end", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 3, META_TYPE_SCREEN, META_TYPE_WINDOW, META_TYPE_GRAB_OP); display_signals[ZOOM_SCROLL_IN] = g_signal_new ("zoom-scroll-in", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); display_signals[ZOOM_SCROLL_OUT] = g_signal_new ("zoom-scroll-out", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); display_signals[BELL] = g_signal_new ("bell", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_WINDOW); display_signals[GL_VIDEO_MEMORY_PURGED] = g_signal_new ("gl-video-memory-purged", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); /** * MetaDisplay::restart: * @display: the #MetaDisplay instance * * The ::restart signal is emitted to indicate that Muffin * will restart the process. */ display_signals[RESTART] = g_signal_new ("restart", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); g_object_class_install_property (object_class, PROP_FOCUS_WINDOW, g_param_spec_object ("focus-window", "Focus window", "Currently focused window", META_TYPE_WINDOW, G_PARAM_READABLE)); } /* * Destructor for MetaPingData structs. Will destroy the * event source for the struct as well. * * \ingroup pings */ static void ping_data_free (MetaPingData *ping_data) { /* Remove the timeout */ if (ping_data->ping_timeout_id != 0) { g_source_remove (ping_data->ping_timeout_id); ping_data->ping_timeout_id = 0; } free (ping_data); } /* * Frees every pending ping structure for the given X window on the * given display. This means that we also destroy the timeouts. * * \param display The display the window appears on * \param xwindow The X ID of the window whose pings we should remove * * \ingroup pings * */ static void remove_pending_pings_for_window (MetaDisplay *display, Window xwindow) { GSList *tmp; GSList *dead; /* could obviously be more efficient, don't care */ /* build list to be removed */ dead = NULL; for (tmp = display->pending_pings; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; if (ping_data->xwindow == xwindow) dead = g_slist_prepend (dead, ping_data); } /* remove what we found */ for (tmp = dead; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; display->pending_pings = g_slist_remove (display->pending_pings, ping_data); ping_data_free (ping_data); } g_slist_free (dead); } #ifdef HAVE_STARTUP_NOTIFICATION static void sn_error_trap_push (SnDisplay *sn_display, Display *xdisplay) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); if (display != NULL) meta_error_trap_push (display); } static void sn_error_trap_pop (SnDisplay *sn_display, Display *xdisplay) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); if (display != NULL) meta_error_trap_pop (display); } #endif static void enable_compositor (MetaDisplay *display, gboolean composite_windows) { GSList *list; if (!META_DISPLAY_HAS_COMPOSITE (display) || !META_DISPLAY_HAS_DAMAGE (display) || !META_DISPLAY_HAS_XFIXES (display) || !META_DISPLAY_HAS_RENDER (display)) { meta_warning ("Missing %s extension required for compositing", !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" : !META_DISPLAY_HAS_DAMAGE (display) ? "damage" : !META_DISPLAY_HAS_XFIXES (display) ? "xfixes" : "render"); return; } if (!display->compositor) display->compositor = meta_compositor_new (display); if (!display->compositor) return; for (list = display->screens; list != NULL; list = list->next) { MetaScreen *screen = list->data; meta_compositor_manage_screen (screen->display->compositor, screen); if (composite_windows) meta_screen_composite_all_windows (screen); } } static void meta_display_init (MetaDisplay *disp) { /* Some stuff could go in here that's currently in _open, * but it doesn't really matter. */ } /* * Opens a new display, sets it up, initialises all the X extensions * we will need, and adds it to the list of displays. * * \return True if the display was opened successfully, and False * otherwise-- that is, if the display doesn't exist or it already * has a window manager. * * \ingroup main */ LOCAL_SYMBOL gboolean meta_display_open (void) { Display *xdisplay; GSList *screens; GSList *tmp; int i; guint32 timestamp; Window old_active_xwindow = None; char buf[257]; /* A list of all atom names, so that we can intern them in one go. */ char *atom_names[] = { #define item(x) #x, #include <meta/atomnames.h> #undef item }; Atom atoms[G_N_ELEMENTS(atom_names)]; meta_verbose ("Opening display '%s'\n", XDisplayName (NULL)); xdisplay = meta_ui_get_display (); if (xdisplay == NULL) { meta_warning ("Failed to open X Window System display '%s'\n", XDisplayName (NULL)); return FALSE; } if (meta_is_syncing ()) XSynchronize (xdisplay, True); g_assert (the_display == NULL); the_display = g_object_new (META_TYPE_DISPLAY, NULL); the_display->closing = 0; /* here we use XDisplayName which is what the user * probably put in, vs. DisplayString(display) which is * canonicalized by XOpenDisplay() */ the_display->name = g_strdup (XDisplayName (NULL)); the_display->xdisplay = xdisplay; the_display->gdk_display = gdk_display_get_default(); the_display->gdk_device = gdk_seat_get_pointer (gdk_display_get_default_seat (the_display->gdk_display)); if (gethostname (buf, sizeof(buf)-1) == 0) { buf[sizeof(buf)-1] = '\0'; the_display->hostname = g_strdup (buf); } else the_display->hostname = NULL; the_display->error_trap_synced_at_last_pop = TRUE; the_display->error_traps = 0; the_display->error_trap_handler = NULL; the_display->server_grab_count = 0; the_display->display_opening = TRUE; the_display->pending_pings = NULL; the_display->autoraise_timeout_id = 0; the_display->autoraise_window = NULL; the_display->focus_window = NULL; the_display->expected_focus_window = NULL; the_display->grab_old_window_stacking = NULL; the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */ the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a terminal has the focus */ the_display->rebuild_keybinding_idle_id = 0; the_display->sync_method = meta_prefs_get_sync_method(); /* FIXME copy the checks from GDK probably */ the_display->static_gravity_works = g_getenv ("MUFFIN_USE_STATIC_GRAVITY") != NULL; meta_bell_init (the_display); meta_display_init_keys (the_display); update_window_grab_modifiers (the_display); update_mouse_zoom_modifiers (the_display); the_display->mouse_zoom_enabled = meta_prefs_get_mouse_zoom_enabled (); meta_prefs_add_listener (prefs_changed_callback, the_display); meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names)); XInternAtoms (the_display->xdisplay, atom_names, G_N_ELEMENTS (atom_names), False, atoms); { int i = 0; #define item(x) the_display->atom_##x = atoms[i++]; #include <meta/atomnames.h> #undef item } the_display->prop_hooks = NULL; meta_display_init_window_prop_hooks (the_display); the_display->group_prop_hooks = NULL; meta_display_init_group_prop_hooks (the_display); /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK, * created in screen_new */ the_display->leader_window = None; the_display->timestamp_pinging_window = None; the_display->monitor_cache_invalidated = TRUE; the_display->groups_by_leader = NULL; the_display->window_with_menu = NULL; the_display->window_menu = NULL; the_display->screens = NULL; the_display->active_screen = NULL; #ifdef HAVE_STARTUP_NOTIFICATION the_display->sn_display = sn_display_new (the_display->xdisplay, sn_error_trap_push, sn_error_trap_pop); #endif the_display->events = NULL; /* Get events */ meta_ui_add_event_func (the_display->xdisplay, event_callback, the_display); the_display->window_ids = g_hash_table_new (meta_unsigned_long_hash, meta_unsigned_long_equal); i = 0; while (i < N_IGNORED_CROSSING_SERIALS) { the_display->ignored_crossing_serials[i] = 0; ++i; } the_display->ungrab_should_not_cause_focus_window = None; the_display->current_time = CurrentTime; the_display->sentinel_counter = 0; the_display->grab_resize_timeout_id = 0; the_display->grab_have_keyboard = FALSE; #ifdef HAVE_XKB the_display->last_bell_time = 0; #endif the_display->grab_op = META_GRAB_OP_NONE; the_display->grab_window = NULL; the_display->grab_screen = NULL; the_display->grab_resize_popup = NULL; the_display->grab_tile_mode = META_TILE_NONE; the_display->grab_tile_monitor_number = -1; the_display->grab_edge_resistance_data = NULL; #ifdef HAVE_XSYNC { int major, minor; the_display->have_xsync = FALSE; the_display->xsync_error_base = 0; the_display->xsync_event_base = 0; /* I don't think we really have to fill these in */ major = SYNC_MAJOR_VERSION; minor = SYNC_MINOR_VERSION; if (!XSyncQueryExtension (the_display->xdisplay, &the_display->xsync_event_base, &the_display->xsync_error_base) || !XSyncInitialize (the_display->xdisplay, &major, &minor)) { the_display->xsync_error_base = 0; the_display->xsync_event_base = 0; } else { the_display->have_xsync = TRUE; XSyncSetPriority (the_display->xdisplay, None, 10); } meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d\n", major, minor, the_display->xsync_error_base, the_display->xsync_event_base); } #else /* HAVE_XSYNC */ meta_verbose ("Not compiled with Xsync support\n"); #endif /* !HAVE_XSYNC */ #ifdef HAVE_SHAPE { the_display->have_shape = FALSE; the_display->shape_error_base = 0; the_display->shape_event_base = 0; if (!XShapeQueryExtension (the_display->xdisplay, &the_display->shape_event_base, &the_display->shape_error_base)) { the_display->shape_error_base = 0; the_display->shape_event_base = 0; } else the_display->have_shape = TRUE; meta_verbose ("Attempted to init Shape, found error base %d event base %d\n", the_display->shape_error_base, the_display->shape_event_base); } #else /* HAVE_SHAPE */ meta_verbose ("Not compiled with Shape support\n"); #endif /* !HAVE_SHAPE */ { the_display->have_render = FALSE; the_display->render_error_base = 0; the_display->render_event_base = 0; if (!XRenderQueryExtension (the_display->xdisplay, &the_display->render_event_base, &the_display->render_error_base)) { the_display->render_error_base = 0; the_display->render_event_base = 0; } else the_display->have_render = TRUE; meta_verbose ("Attempted to init Render, found error base %d event base %d\n", the_display->render_error_base, the_display->render_event_base); } { the_display->have_composite = FALSE; the_display->composite_error_base = 0; the_display->composite_event_base = 0; if (!XCompositeQueryExtension (the_display->xdisplay, &the_display->composite_event_base, &the_display->composite_error_base)) { the_display->composite_error_base = 0; the_display->composite_event_base = 0; } else { the_display->composite_major_version = 0; the_display->composite_minor_version = 0; if (XCompositeQueryVersion (the_display->xdisplay, &the_display->composite_major_version, &the_display->composite_minor_version)) { the_display->have_composite = TRUE; } else { the_display->composite_major_version = 0; the_display->composite_minor_version = 0; } } meta_verbose ("Attempted to init Composite, found error base %d event base %d " "extn ver %d %d\n", the_display->composite_error_base, the_display->composite_event_base, the_display->composite_major_version, the_display->composite_minor_version); the_display->have_damage = FALSE; the_display->damage_error_base = 0; the_display->damage_event_base = 0; if (!XDamageQueryExtension (the_display->xdisplay, &the_display->damage_event_base, &the_display->damage_error_base)) { the_display->damage_error_base = 0; the_display->damage_event_base = 0; } else the_display->have_damage = TRUE; meta_verbose ("Attempted to init Damage, found error base %d event base %d\n", the_display->damage_error_base, the_display->damage_event_base); the_display->have_xfixes = FALSE; the_display->xfixes_error_base = 0; the_display->xfixes_event_base = 0; if (!XFixesQueryExtension (the_display->xdisplay, &the_display->xfixes_event_base, &the_display->xfixes_error_base)) { the_display->xfixes_error_base = 0; the_display->xfixes_event_base = 0; } else the_display->have_xfixes = TRUE; meta_verbose ("Attempted to init XFixes, found error base %d event base %d\n", the_display->xfixes_error_base, the_display->xfixes_event_base); } #ifdef HAVE_XCURSOR { XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ()); XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ()); } #else /* HAVE_XCURSOR */ meta_verbose ("Not compiled with Xcursor support\n"); #endif /* !HAVE_XCURSOR */ /* Create the leader window here. Set its properties and * use the timestamp from one of the PropertyNotify events * that will follow. */ { gulong data[1]; XEvent event; /* We only care about the PropertyChangeMask in the next 30 or so lines of * code. Note that gdk will at some point unset the PropertyChangeMask for * this window, so we can't rely on it still being set later. See bug * 354213 for details. */ the_display->leader_window = meta_create_offscreen_window (the_display->xdisplay, DefaultRootWindow (the_display->xdisplay), PropertyChangeMask); meta_prop_set_utf8_string_hint (the_display, the_display->leader_window, the_display->atom__NET_WM_NAME, "Mutter (Muffin)"); /* The GNOME keybindings capplet should include both the Muffin and Metacity * keybindings */ meta_prop_set_utf8_string_hint (the_display, the_display->leader_window, the_display->atom__GNOME_WM_KEYBINDINGS, "Muffin,Metacity"); meta_prop_set_utf8_string_hint (the_display, the_display->leader_window, the_display->atom__MUFFIN_VERSION, VERSION); data[0] = the_display->leader_window; XChangeProperty (the_display->xdisplay, the_display->leader_window, the_display->atom__NET_SUPPORTING_WM_CHECK, XA_WINDOW, 32, PropModeReplace, (guchar*) data, 1); XWindowEvent (the_display->xdisplay, the_display->leader_window, PropertyChangeMask, &event); timestamp = event.xproperty.time; /* Make it painfully clear that we can't rely on PropertyNotify events on * this window, as per bug 354213. */ XSelectInput(the_display->xdisplay, the_display->leader_window, NoEventMask); } /* Make a little window used only for pinging the server for timestamps; note * that meta_create_offscreen_window already selects for PropertyChangeMask. */ the_display->timestamp_pinging_window = meta_create_offscreen_window (the_display->xdisplay, DefaultRootWindow (the_display->xdisplay), PropertyChangeMask); the_display->last_focus_time = timestamp; the_display->last_user_time = timestamp; the_display->compositor = NULL; the_display->shadows_enabled = g_getenv ("MUFFIN_NO_SHADOWS") == NULL; the_display->debug_button_grabs = g_getenv ("MUFFIN_DEBUG_BUTTON_GRABS") != NULL; screens = NULL; i = 0; while (i < ScreenCount (xdisplay)) { MetaScreen *screen; screen = meta_screen_new (the_display, i, timestamp); if (screen) screens = g_slist_prepend (screens, screen); ++i; } the_display->screens = screens; if (screens == NULL) { /* This would typically happen because all the screens already * have window managers. */ meta_display_close (the_display, timestamp); return FALSE; } meta_prop_get_window (the_display, ((MetaScreen*) the_display->screens->data)->xroot, the_display->atom__NET_ACTIVE_WINDOW, &old_active_xwindow); /* We don't composite the windows here because they will be composited faster with the call to meta_screen_manage_all_windows further down the code */ enable_compositor (the_display, FALSE); meta_display_grab (the_display); /* Now manage all existing windows */ tmp = the_display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; meta_screen_manage_all_windows (screen); tmp = tmp->next; } { meta_error_trap_push (the_display); if (old_active_xwindow != None) { MetaWindow *old_active_window = meta_display_lookup_x_window (the_display, old_active_xwindow); if (old_active_window) meta_display_set_input_focus_window (the_display, old_active_window, FALSE, timestamp); else meta_display_focus_the_no_focus_window (the_display, the_display->screens->data, timestamp); } else meta_display_focus_the_no_focus_window (the_display, the_display->screens->data, timestamp); meta_error_trap_pop (the_display); } meta_display_ungrab (the_display); /* Done opening new display */ the_display->display_opening = FALSE; return TRUE; } static gint ptrcmp (gconstpointer a, gconstpointer b) { if (a < b) return -1; else if (a > b) return 1; else return 0; } /** * meta_display_list_windows: * @display: a #MetaDisplay * @flags: options for listing * * Lists windows for the display, the @flags parameter for * now determines whether override-redirect windows will be * included. * * Return value: (transfer container) (element-type MetaWindow): the list of windows. */ GSList* meta_display_list_windows (MetaDisplay *display, MetaListWindowsFlags flags) { GSList *winlist; GSList *tmp; GSList *prev; GHashTableIter iter; gpointer key, value; winlist = NULL; g_hash_table_iter_init (&iter, display->window_ids); while (g_hash_table_iter_next (&iter, &key, &value)) { MetaWindow *window = value; if (!window->override_redirect || (flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0) winlist = g_slist_prepend (winlist, window); } /* Uniquify the list, since both frame windows and plain * windows are in the hash */ winlist = g_slist_sort (winlist, ptrcmp); prev = NULL; tmp = winlist; while (tmp != NULL) { GSList *next; next = tmp->next; if (next && next->data == tmp->data) { /* Delete tmp from list */ if (prev) prev->next = next; if (tmp == winlist) winlist = next; g_slist_free_1 (tmp); /* leave prev unchanged */ } else { prev = tmp; } tmp = next; } return winlist; } LOCAL_SYMBOL void meta_display_close (MetaDisplay *display, guint32 timestamp) { GSList *tmp; g_assert (display != NULL); if (display->closing != 0) { /* The display's already been closed. */ return; } if (display->error_traps > 0) meta_bug ("Display closed with error traps pending\n"); display->closing += 1; meta_prefs_remove_listener (prefs_changed_callback, display); meta_display_remove_autoraise_callback (display); if (display->grab_old_window_stacking) g_list_free (display->grab_old_window_stacking); /* Stop caring about events */ meta_ui_remove_event_func (display->xdisplay, event_callback, display); /* Free all screens */ tmp = display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; meta_screen_free (screen, timestamp); tmp = tmp->next; } g_slist_free (display->screens); display->screens = NULL; #ifdef HAVE_STARTUP_NOTIFICATION if (display->sn_display) { sn_display_unref (display->sn_display); display->sn_display = NULL; } #endif /* Must be after all calls to meta_window_unmanage() since they * unregister windows */ g_hash_table_destroy (display->window_ids); if (display->leader_window != None) XDestroyWindow (display->xdisplay, display->leader_window); XFlush (display->xdisplay); meta_display_free_window_prop_hooks (display); meta_display_free_group_prop_hooks (display); free (display->hostname); free (display->name); meta_display_shutdown_keys (display); if (display->compositor) meta_compositor_destroy (display->compositor); g_object_unref (display); the_display = NULL; meta_quit (META_EXIT_SUCCESS); } /** * meta_display_screen_for_root: * @display: a #MetaDisplay * * Return the #MetaScreen corresponding to a specified X root window ID. * * Return Value: (transfer none): the screen for the specified root window ID, or %NULL */ MetaScreen* meta_display_screen_for_root (MetaDisplay *display, Window xroot) { GSList *tmp; tmp = display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; if (xroot == screen->xroot) return screen; tmp = tmp->next; } return NULL; } LOCAL_SYMBOL MetaScreen* meta_display_screen_for_xwindow (MetaDisplay *display, Window xwindow) { XWindowAttributes attr; int result; meta_error_trap_push (display); attr.screen = NULL; result = XGetWindowAttributes (display->xdisplay, xwindow, &attr); meta_error_trap_pop (display); /* Note, XGetWindowAttributes is on all kinds of crack * and returns 1 on success 0 on failure, rather than Success * on success. */ if (result == 0 || attr.screen == NULL) return NULL; return meta_display_screen_for_x_screen (display, attr.screen); } LOCAL_SYMBOL MetaScreen* meta_display_screen_for_x_screen (MetaDisplay *display, Screen *xscreen) { GSList *tmp; tmp = display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; if (xscreen == screen->xscreen) return screen; tmp = tmp->next; } return NULL; } /* Grab/ungrab routines taken from fvwm */ LOCAL_SYMBOL void meta_display_grab (MetaDisplay *display) { if (display->server_grab_count == 0) { XGrabServer (display->xdisplay); } display->server_grab_count += 1; meta_verbose ("Grabbing display, grab count now %d\n", display->server_grab_count); } LOCAL_SYMBOL void meta_display_ungrab (MetaDisplay *display) { if (display->server_grab_count == 0) meta_bug ("Ungrabbed non-grabbed server\n"); display->server_grab_count -= 1; if (display->server_grab_count == 0) { /* FIXME we want to purge all pending "queued" stuff * at this point, such as window hide/show */ XUngrabServer (display->xdisplay); XFlush (display->xdisplay); } meta_verbose ("Ungrabbing display, grab count now %d\n", display->server_grab_count); } /* * Returns the singleton MetaDisplay if "xdisplay" matches the X display it's * managing; otherwise gives a warning and returns NULL. When we were claiming * to be able to manage multiple displays, this was supposed to find the * display out of the list which matched that display. Now it's merely an * extra sanity check. * * \param xdisplay An X display * \return The singleton X display, or NULL if "xdisplay" isn't the one * we're managing. */ LOCAL_SYMBOL MetaDisplay* meta_display_for_x_display (Display *xdisplay) { if (the_display->xdisplay == xdisplay) return the_display; meta_warning ("Could not find display for X display %p, probably going to crash\n", xdisplay); return NULL; } /* * Accessor for the singleton MetaDisplay. * * \return The only MetaDisplay there is. This can be NULL, but only * during startup. */ LOCAL_SYMBOL MetaDisplay* meta_get_display (void) { return the_display; } #ifdef WITH_VERBOSE_MODE static gboolean dump_events = TRUE; #endif static gboolean grab_op_is_mouse_only (MetaGrabOp op) { switch (op) { case META_GRAB_OP_MOVING: case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_RESIZING_E: return TRUE; default: return FALSE; } } static gboolean grab_op_is_mouse (MetaGrabOp op) { switch (op) { case META_GRAB_OP_MOVING: case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: case META_GRAB_OP_KEYBOARD_MOVING: case META_GRAB_OP_COMPOSITOR: return TRUE; default: return FALSE; } } static gboolean grab_op_is_keyboard (MetaGrabOp op) { switch (op) { case META_GRAB_OP_KEYBOARD_MOVING: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: case META_GRAB_OP_KEYBOARD_TABBING_NORMAL: case META_GRAB_OP_KEYBOARD_TABBING_DOCK: case META_GRAB_OP_KEYBOARD_TABBING_GROUP: case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL: case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK: case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP: case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING: case META_GRAB_OP_COMPOSITOR: return TRUE; default: return FALSE; } } LOCAL_SYMBOL gboolean meta_grab_op_is_resizing (MetaGrabOp op) { switch (op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: return TRUE; default: return FALSE; } } LOCAL_SYMBOL gboolean meta_grab_op_is_moving (MetaGrabOp op) { switch (op) { case META_GRAB_OP_MOVING: case META_GRAB_OP_KEYBOARD_MOVING: return TRUE; default: return FALSE; } } /** * meta_display_xserver_time_is_before: * @display: a #MetaDisplay * @time1: An event timestamp * @time2: An event timestamp * * Xserver time can wraparound, thus comparing two timestamps needs to take * this into account. If no wraparound has occurred, this is equivalent to * time1 < time2 * Otherwise, we need to account for the fact that wraparound can occur * and the fact that a timestamp of 0 must be special-cased since it * means "older than anything else". * * Note that this is NOT an equivalent for time1 <= time2; if that's what * you need then you'll need to swap the order of the arguments and negate * the result. */ gboolean meta_display_xserver_time_is_before (MetaDisplay *display, guint32 time1, guint32 time2) { return XSERVER_TIME_IS_BEFORE(time1, time2); } /** * meta_display_get_last_user_time: * @display: a #MetaDisplay * * Returns: Timestamp of the last user interaction event with a window */ guint32 meta_display_get_last_user_time (MetaDisplay *display) { return display->last_user_time; } /* Get time of current event, or CurrentTime if none. */ guint32 meta_display_get_current_time (MetaDisplay *display) { return display->current_time; } /* Get a timestamp, even if it means a roundtrip */ guint32 meta_display_get_current_time_roundtrip (MetaDisplay *display) { guint32 timestamp; timestamp = meta_display_get_current_time (display); if (timestamp == CurrentTime) { XEvent property_event; /* Using the property XA_PRIMARY because it's safe; nothing * would use it as a property. The type doesn't matter. */ XChangeProperty (display->xdisplay, display->timestamp_pinging_window, XA_PRIMARY, XA_STRING, 8, PropModeAppend, NULL, 0); XWindowEvent (display->xdisplay, display->timestamp_pinging_window, PropertyChangeMask, &property_event); timestamp = property_event.xproperty.time; } sanity_check_timestamps (display, timestamp); return timestamp; } /** * meta_display_get_ignored_modifier_mask: * @display: a #MetaDisplay * * Returns: a mask of modifiers that should be ignored * when matching keybindings to events */ unsigned int meta_display_get_ignored_modifier_mask (MetaDisplay *display) { return display->ignored_modifier_mask; } /** * meta_display_add_ignored_crossing_serial: * @display: a #MetaDisplay * @serial: the serial to ignore * * Save the specified serial and ignore crossing events with that * serial for the purpose of focus-follows-mouse. This can be used * for certain changes to the window hierarchy that we don't want * to change the focus window, even if they cause the pointer to * end up in a new window. */ void meta_display_add_ignored_crossing_serial (MetaDisplay *display, unsigned long serial) { int i; /* don't add the same serial more than once */ if (display->ignored_crossing_serials[N_IGNORED_CROSSING_SERIALS-1] == serial) return; /* shift serials to the left */ i = 0; while (i < (N_IGNORED_CROSSING_SERIALS - 1)) { display->ignored_crossing_serials[i] = display->ignored_crossing_serials[i+1]; ++i; } /* put new one on the end */ display->ignored_crossing_serials[i] = serial; } static gboolean crossing_serial_is_ignored (MetaDisplay *display, unsigned long serial) { int i; i = 0; while (i < N_IGNORED_CROSSING_SERIALS) { if (display->ignored_crossing_serials[i] == serial) return TRUE; ++i; } return FALSE; } static void reset_ignored_crossing_serials (MetaDisplay *display) { int i; i = 0; while (i < N_IGNORED_CROSSING_SERIALS) { display->ignored_crossing_serials[i] = 0; ++i; } display->ungrab_should_not_cause_focus_window = None; } static gboolean window_raise_with_delay_callback (void *data) { MetaWindow *window; MetaAutoRaiseData *auto_raise; auto_raise = data; meta_topic (META_DEBUG_FOCUS, "In autoraise callback for window 0x%lx\n", auto_raise->xwindow); auto_raise->display->autoraise_timeout_id = 0; auto_raise->display->autoraise_window = NULL; window = meta_display_lookup_x_window (auto_raise->display, auto_raise->xwindow); if (window == NULL) return FALSE; /* If we aren't already on top, check whether the pointer is inside * the window and raise the window if so. */ if (meta_stack_get_top (window->screen->stack) != window) { int x, y, root_x, root_y; Window root, child; unsigned int mask; gboolean same_screen; gboolean point_in_window; meta_error_trap_push (window->display); same_screen = XQueryPointer (window->display->xdisplay, window->xwindow, &root, &child, &root_x, &root_y, &x, &y, &mask); meta_error_trap_pop (window->display); point_in_window = (window->frame && META_POINT_IN_RECT (root_x, root_y, window->frame->rect)) || (window->frame == NULL && META_POINT_IN_RECT (root_x, root_y, window->rect)); if (same_screen && point_in_window) meta_window_raise (window); #ifdef WITH_VERBOSE_MODE else meta_topic (META_DEBUG_FOCUS, "Pointer not inside window, not raising %s\n", window->desc); #endif } return FALSE; } LOCAL_SYMBOL void meta_display_queue_autoraise_callback (MetaDisplay *display, MetaWindow *window) { MetaAutoRaiseData *auto_raise_data; meta_topic (META_DEBUG_FOCUS, "Queuing an autoraise timeout for %s with delay %d\n", window->desc, meta_prefs_get_auto_raise_delay ()); auto_raise_data = g_new (MetaAutoRaiseData, 1); auto_raise_data->display = window->display; auto_raise_data->xwindow = window->xwindow; if (display->autoraise_timeout_id != 0) { g_source_remove (display->autoraise_timeout_id); display->autoraise_timeout_id = 0; } display->autoraise_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, meta_prefs_get_auto_raise_delay (), window_raise_with_delay_callback, auto_raise_data, free); display->autoraise_window = window; } /* * This is the most important function in the whole program. It is the heart, * it is the nexus, it is the Grand Central Station of Muffin's world. * When we create a MetaDisplay, we ask GDK to pass *all* events for *all* * windows to this function. So every time anything happens that we might * want to know about, this function gets called. You see why it gets a bit * busy around here. Most of this function is a ginormous switch statement * dealing with all the kinds of events that might turn up. * * \param event The event that just happened * \param data The MetaDisplay that events are coming from, cast to a gpointer * so that it can be sent to a callback * * \ingroup main */ static gboolean event_callback (XEvent *event, gpointer data) { MetaWindow *window; MetaWindow *property_for_window; MetaDisplay *display; Window modified; gboolean frame_was_receiver; gboolean bypass_compositor; gboolean filter_out_event; display = data; #ifdef WITH_VERBOSE_MODE if (dump_events) meta_spew_event (display, event); #endif #ifdef HAVE_STARTUP_NOTIFICATION sn_display_process_event (display->sn_display, event); #endif bypass_compositor = FALSE; filter_out_event = FALSE; display->current_time = event_get_time (display, event); display->monitor_cache_invalidated = TRUE; modified = event_get_modified_window (display, event); if (event->type == UnmapNotify) { if (meta_ui_window_should_not_cause_focus (display->xdisplay, modified)) { meta_display_add_ignored_crossing_serial (display, event->xany.serial); meta_topic (META_DEBUG_FOCUS, "Adding EnterNotify serial %lu to ignored focus serials\n", event->xany.serial); } } else if (event->type == LeaveNotify && event->xcrossing.mode == NotifyUngrab && modified == display->ungrab_should_not_cause_focus_window) { meta_display_add_ignored_crossing_serial (display, event->xany.serial); meta_topic (META_DEBUG_FOCUS, "Adding LeaveNotify serial %lu to ignored focus serials\n", event->xany.serial); } if (modified != None) window = meta_display_lookup_x_window (display, modified); else window = NULL; /* We only want to respond to _NET_WM_USER_TIME property notify * events on _NET_WM_USER_TIME_WINDOW windows; in particular, * responding to UnmapNotify events is kind of bad. */ property_for_window = NULL; if (window && modified == window->user_time_window) { property_for_window = window; window = NULL; } frame_was_receiver = FALSE; if (window && window->frame && modified == window->frame->xwindow) { /* Note that if the frame and the client both have an * XGrabButton (as is normal with our setup), the event * goes to the frame. */ frame_was_receiver = TRUE; meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n", window->desc); } #ifdef HAVE_XSYNC if (META_DISPLAY_HAS_XSYNC (display) && event->type == (display->xsync_event_base + XSyncAlarmNotify)) { MetaWindow *alarm_window = meta_display_lookup_sync_alarm (display, ((XSyncAlarmNotifyEvent*)event)->alarm); if (alarm_window != NULL) { XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value; gint64 new_counter_value; new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32); meta_window_update_sync_request_counter (alarm_window, new_counter_value); filter_out_event = TRUE; /* GTK doesn't want to see this really */ } } #endif /* HAVE_XSYNC */ #ifdef HAVE_SHAPE if (META_DISPLAY_HAS_SHAPE (display) && event->type == (display->shape_event_base + ShapeNotify)) { filter_out_event = TRUE; /* GTK doesn't want to see this really */ if (window && !frame_was_receiver) { XShapeEvent *sev = (XShapeEvent*) event; if (sev->kind == ShapeBounding) { if (sev->shaped && !window->has_shape) { window->has_shape = TRUE; meta_topic (META_DEBUG_SHAPES, "Window %s now has a shape\n", window->desc); } else if (!sev->shaped && window->has_shape) { window->has_shape = FALSE; meta_topic (META_DEBUG_SHAPES, "Window %s no longer has a shape\n", window->desc); } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_SHAPES, "Window %s shape changed\n", window->desc); } #endif meta_compositor_window_shape_changed (display->compositor, window); } } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_SHAPES, "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n", window ? window->desc : "(none)", frame_was_receiver); } #endif } #endif /* HAVE_SHAPE */ if (window && !window->override_redirect && ((event->type == KeyPress) || (event->type == ButtonPress))) { if (CurrentTime == display->current_time) { /* We can't use missing (i.e. invalid) timestamps to set user time, * nor do we want to use them to sanity check other timestamps. * See bug 313490 for more details. */ meta_warning ("Event has no timestamp! You may be using a broken " "program such as xse. Please ask the authors of that " "program to fix it.\n"); } else { meta_window_set_user_time (window, display->current_time); sanity_check_timestamps (display, display->current_time); } } switch (event->type) { case KeyPress: case KeyRelease: if (display->grab_op == META_GRAB_OP_COMPOSITOR) break; /* For key events, it's important to enforce single-handling, or * we can get into a confused state. So if a keybinding is * handled (because it's one of our hot-keys, or because we are * in a keyboard-grabbed mode like moving a window, we don't * want to pass the key event to the compositor or GTK+ at all. */ if (display->grab_window == window && grab_op_is_mouse (display->grab_op)) meta_window_handle_keyboard_grab_op_event (window, event); if (meta_display_process_key_event (display, window, event)) filter_out_event = bypass_compositor = TRUE; break; case ButtonPress: if (display->grab_op == META_GRAB_OP_COMPOSITOR) break; if (display->mouse_zoom_modifiers > 0 && (event->xbutton.button == 4 || event->xbutton.button == 5)) { if ((event->xbutton.state & ~display->ignored_modifier_mask) == display->mouse_zoom_modifiers) { if (event->xbutton.button == 4) { g_signal_emit (display, display_signals[ZOOM_SCROLL_IN], 0); } if (event->xbutton.button == 5) { g_signal_emit (display, display_signals[ZOOM_SCROLL_OUT], 0); } filter_out_event = bypass_compositor = TRUE; } break; } if ((window && grab_op_is_mouse (display->grab_op) && display->grab_button != (int) event->xbutton.button && display->grab_window == window) || grab_op_is_keyboard (display->grab_op)) { meta_topic (META_DEBUG_WINDOW_OPS, "Ending grab op %u on window %s due to button press\n", display->grab_op, (display->grab_window ? display->grab_window->desc : "none")); if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op)) { MetaScreen *screen; meta_topic (META_DEBUG_WINDOW_OPS, "Syncing to old stack positions.\n"); screen = meta_display_screen_for_root (display, event->xany.window); if (screen!=NULL) meta_stack_set_positions (screen->stack, display->grab_old_window_stacking); } if (display->grab_window->tile_mode == META_TILE_NONE) meta_display_end_grab_op (display, event->xbutton.time); } else if (window && display->grab_op == META_GRAB_OP_NONE) { gboolean begin_move = FALSE; unsigned int grab_mask; gboolean unmodified; grab_mask = display->window_grab_modifiers; if (display->debug_button_grabs) grab_mask |= ControlMask; /* Two possible sources of an unmodified event; one is a * client that's letting button presses pass through to the * frame, the other is our focus_window_grab on unmodified * button 1. So for all such events we focus the window. */ unmodified = (event->xbutton.state & grab_mask) == 0; if (unmodified || event->xbutton.button == 1) { /* don't focus if frame received, will be lowered in * frames.c or special-cased if the click was on a * minimize/close button. */ if (!frame_was_receiver) { if (meta_prefs_get_raise_on_click () && !meta_ui_window_is_widget (display->active_screen->ui, modified)) meta_window_raise (window); #ifdef WITH_VERBOSE_MODE else meta_topic (META_DEBUG_FOCUS, "Not raising window on click due to don't-raise-on-click option\n"); #endif /* Don't focus panels--they must explicitly request focus. * See bug 160470 */ if (window->type != META_WINDOW_DOCK && !meta_ui_window_is_widget (display->active_screen->ui, modified)) { meta_topic (META_DEBUG_FOCUS, "Focusing %s due to unmodified button %u press (display.c)\n", window->desc, event->xbutton.button); meta_window_focus (window, event->xbutton.time); } else /* However, do allow terminals to lose focus due to new * window mappings after the user clicks on a panel. */ display->allow_terminal_deactivation = TRUE; } /* you can move on alt-click but not on * the click-to-focus */ if (!unmodified) begin_move = TRUE; } else if (!unmodified && event->xbutton.button == meta_prefs_get_mouse_button_resize()) { if (window->has_resize_func) { gboolean north, south; gboolean west, east; int root_x, root_y; MetaGrabOp op; meta_window_get_position (window, &root_x, &root_y); west = event->xbutton.x_root < (root_x + 1 * window->rect.width / 3); east = event->xbutton.x_root > (root_x + 2 * window->rect.width / 3); north = event->xbutton.y_root < (root_y + 1 * window->rect.height / 3); south = event->xbutton.y_root > (root_y + 2 * window->rect.height / 3); if (north && west) op = META_GRAB_OP_RESIZING_NW; else if (north && east) op = META_GRAB_OP_RESIZING_NE; else if (south && west) op = META_GRAB_OP_RESIZING_SW; else if (south && east) op = META_GRAB_OP_RESIZING_SE; else if (north) op = META_GRAB_OP_RESIZING_N; else if (west) op = META_GRAB_OP_RESIZING_W; else if (east) op = META_GRAB_OP_RESIZING_E; else if (south) op = META_GRAB_OP_RESIZING_S; else /* Middle region is no-op to avoid user triggering wrong action */ op = META_GRAB_OP_NONE; if (op != META_GRAB_OP_NONE) meta_display_begin_grab_op (display, window->screen, window, op, TRUE, FALSE, event->xbutton.button, 0, event->xbutton.time, event->xbutton.x_root, event->xbutton.y_root); } } else if (event->xbutton.button == meta_prefs_get_mouse_button_menu()) { if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_show_menu (window, event->xbutton.x_root, event->xbutton.y_root, event->xbutton.button, event->xbutton.time); } if (!frame_was_receiver && unmodified) { /* This is from our synchronous grab since * it has no modifiers and was on the client window */ int mode; /* When clicking a different app in click-to-focus * in application-based mode, and the different * app is not a dock or desktop, eat the focus click. */ if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK && meta_prefs_get_application_based () && !window->has_focus && window->type != META_WINDOW_DOCK && window->type != META_WINDOW_DESKTOP && (display->focus_window == NULL || !meta_window_same_application (window, display->focus_window))) mode = AsyncPointer; /* eat focus click */ else mode = ReplayPointer; /* give event back */ meta_verbose ("Allowing events mode %s time %u\n", mode == AsyncPointer ? "AsyncPointer" : "ReplayPointer", (unsigned int)event->xbutton.time); XAllowEvents (display->xdisplay, mode, event->xbutton.time); } if (begin_move && window->has_move_func) { meta_display_begin_grab_op (display, window->screen, window, META_GRAB_OP_MOVING, TRUE, FALSE, event->xbutton.button, 0, event->xbutton.time, event->xbutton.x_root, event->xbutton.y_root); } } break; case ButtonRelease: if (display->grab_op == META_GRAB_OP_COMPOSITOR) break; if (display->grab_window == window && grab_op_is_mouse (display->grab_op)) meta_window_handle_mouse_grab_op_event (window, event); break; case MotionNotify: if (display->grab_op == META_GRAB_OP_COMPOSITOR) break; if (display->grab_window == window && grab_op_is_mouse (display->grab_op)) meta_window_handle_mouse_grab_op_event (window, event); break; case EnterNotify: if (display->grab_op == META_GRAB_OP_COMPOSITOR) break; if (display->grab_window == window && grab_op_is_mouse (display->grab_op)) { meta_window_handle_mouse_grab_op_event (window, event); break; } /* If the mouse switches screens, active the default window on the new * screen; this will make keybindings and workspace-launched items * actually appear on the right screen. */ { MetaScreen *new_screen = meta_display_screen_for_root (display, event->xcrossing.root); if (new_screen != NULL && display->active_screen != new_screen) meta_workspace_focus_default_window (new_screen->active_workspace, NULL, event->xcrossing.time); } /* Check if we've entered a window; do this even if window->has_focus to * avoid races. */ if (window && !crossing_serial_is_ignored (display, event->xany.serial) && event->xcrossing.mode != NotifyGrab && event->xcrossing.mode != NotifyUngrab && event->xcrossing.detail != NotifyInferior && meta_display_focus_sentinel_clear (display)) { switch (meta_prefs_get_focus_mode ()) { case C_DESKTOP_FOCUS_MODE_SLOPPY: case C_DESKTOP_FOCUS_MODE_MOUSE: display->mouse_mode = TRUE; if (window->type != META_WINDOW_DOCK && window->type != META_WINDOW_DESKTOP) { meta_topic (META_DEBUG_FOCUS, "Focusing %s due to enter notify with serial %lu " "at time %lu, and setting display->mouse_mode to " "TRUE.\n", window->desc, event->xany.serial, event->xcrossing.time); meta_window_focus (window, event->xcrossing.time); /* stop ignoring stuff */ reset_ignored_crossing_serials (display); if (meta_prefs_get_auto_raise ()) { meta_display_queue_autoraise_callback (display, window); } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled\n"); } #endif } /* In mouse focus mode, we defocus when the mouse *enters* * the DESKTOP window, instead of defocusing on LeaveNotify. * This is because having the mouse enter override-redirect * child windows unfortunately causes LeaveNotify events that * we can't distinguish from the mouse actually leaving the * toplevel window as we expect. But, since we filter out * EnterNotify events on override-redirect windows, this * alternative mechanism works great. */ if (window->type == META_WINDOW_DESKTOP && meta_prefs_get_focus_mode() == C_DESKTOP_FOCUS_MODE_MOUSE && display->expected_focus_window != NULL) { meta_topic (META_DEBUG_FOCUS, "Unsetting focus from %s due to mouse entering " "the DESKTOP window\n", display->expected_focus_window->desc); meta_display_focus_the_no_focus_window (display, window->screen, event->xcrossing.time); } break; case C_DESKTOP_FOCUS_MODE_CLICK: break; } if (window->type == META_WINDOW_DOCK) meta_window_raise (window); } break; case LeaveNotify: if (display->grab_op == META_GRAB_OP_COMPOSITOR) break; if (display->grab_window == window && grab_op_is_mouse (display->grab_op)) meta_window_handle_mouse_grab_op_event (window, event); else if (window != NULL) { if (window->type == META_WINDOW_DOCK && event->xcrossing.mode != NotifyGrab && event->xcrossing.mode != NotifyUngrab && !window->has_focus) meta_window_lower (window); } break; case FocusIn: case FocusOut: if (window) { meta_window_notify_focus (window, event); } else if (meta_display_xwindow_is_a_no_focus_window (display, event->xany.window)) { meta_topic (META_DEBUG_FOCUS, "Focus %s event received on no_focus_window 0x%lx " "mode %s detail %s\n", event->type == FocusIn ? "in" : event->type == FocusOut ? "out" : "???", event->xany.window, meta_event_mode_to_string (event->xfocus.mode), meta_event_detail_to_string (event->xfocus.detail)); } else { MetaScreen *screen = meta_display_screen_for_root(display, event->xany.window); if (screen == NULL) break; meta_topic (META_DEBUG_FOCUS, "Focus %s event received on root window 0x%lx " "mode %s detail %s\n", event->type == FocusIn ? "in" : event->type == FocusOut ? "out" : "???", event->xany.window, meta_event_mode_to_string (event->xfocus.mode), meta_event_detail_to_string (event->xfocus.detail)); if (event->type == FocusIn && event->xfocus.detail == NotifyDetailNone) { meta_topic (META_DEBUG_FOCUS, "Focus got set to None, probably due to " "brain-damage in the X protocol (see bug " "125492). Setting the default focus window.\n"); meta_workspace_focus_default_window (screen->active_workspace, NULL, meta_display_get_current_time_roundtrip (display)); } else if (event->type == FocusIn && event->xfocus.mode == NotifyNormal && event->xfocus.detail == NotifyInferior) { meta_topic (META_DEBUG_FOCUS, "Focus got set to root window, probably due to " "gnome-session logout dialog usage (see bug " "153220). Setting the default focus window.\n"); meta_workspace_focus_default_window (screen->active_workspace, NULL, meta_display_get_current_time_roundtrip (display)); } } break; case KeymapNotify: break; case Expose: break; case GraphicsExpose: break; case NoExpose: break; case VisibilityNotify: break; case CreateNotify: { MetaScreen *screen; screen = meta_display_screen_for_root (display, event->xcreatewindow.parent); if (screen) meta_stack_tracker_create_event (screen->stack_tracker, &event->xcreatewindow); } break; case DestroyNotify: { MetaScreen *screen; screen = meta_display_screen_for_root (display, event->xdestroywindow.event); if (screen) meta_stack_tracker_destroy_event (screen->stack_tracker, &event->xdestroywindow); } if (window) { /* FIXME: It sucks that DestroyNotify events don't come with * a timestamp; could we do something better here? Maybe X * will change one day? */ guint32 timestamp; timestamp = meta_display_get_current_time_roundtrip (display); if (display->grab_op != META_GRAB_OP_NONE && display->grab_window == window) meta_display_end_grab_op (display, timestamp); if (frame_was_receiver) { meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", window->frame->xwindow); meta_error_trap_push (display); meta_window_destroy_frame (window->frame->window); meta_error_trap_pop (display); } else { /* Unmanage destroyed window */ meta_window_unmanage (window, timestamp); window = NULL; } } break; case UnmapNotify: if (window) { /* FIXME: It sucks that UnmapNotify events don't come with * a timestamp; could we do something better here? Maybe X * will change one day? */ guint32 timestamp; timestamp = meta_display_get_current_time_roundtrip (display); if (display->grab_op != META_GRAB_OP_NONE && display->grab_window == window && window->frame == NULL) meta_display_end_grab_op (display, timestamp); if (!frame_was_receiver) { if (window->unmaps_pending == 0) { meta_topic (META_DEBUG_WINDOW_STATE, "Window %s withdrawn\n", window->desc); /* Unmanage withdrawn window */ window->withdrawn = TRUE; meta_window_unmanage (window, timestamp); window = NULL; } else { window->unmaps_pending -= 1; meta_topic (META_DEBUG_WINDOW_STATE, "Received pending unmap, %d now pending\n", window->unmaps_pending); } } /* Unfocus on UnmapNotify, do this after the possible * window_free above so that window_free can see if window->has_focus * and move focus to another window */ if (window) meta_window_notify_focus (window, event); } break; case MapNotify: /* NB: override redirect windows wont cause a map request so we * watch out for map notifies against any root windows too if a * compositor is enabled: */ if (window == NULL && meta_display_screen_for_root (display, event->xmap.event)) { window = meta_window_new (display, event->xmap.window, FALSE); } break; case MapRequest: if (window == NULL) { window = meta_window_new (display, event->xmaprequest.window, FALSE); } /* if frame was receiver it's some malicious send event or something */ else if (!frame_was_receiver && window) { meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n", window->desc, window->mapped, window->minimized); if (window->minimized) { meta_window_unminimize (window); if (window->workspace != window->screen->active_workspace) { meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n", window->mapped, window->minimized); meta_window_change_workspace (window, window->screen->active_workspace); } } } break; case ReparentNotify: { MetaScreen *screen; screen = meta_display_screen_for_root (display, event->xconfigure.event); if (screen) meta_stack_tracker_reparent_event (screen->stack_tracker, &event->xreparent); } break; case ConfigureNotify: if (event->xconfigure.event != event->xconfigure.window) { MetaScreen *screen; screen = meta_display_screen_for_root (display, event->xconfigure.event); if (screen && event->xconfigure.event == screen->xroot && event->xconfigure.window != screen->composite_overlay_window) meta_stack_tracker_configure_event (screen->stack_tracker, &event->xconfigure); } if (window && window->override_redirect) meta_window_configure_notify (window, &event->xconfigure); else /* Handle screen resize */ { MetaScreen *screen; screen = meta_display_screen_for_root (display, event->xconfigure.window); if (screen != NULL) { #ifdef HAVE_RANDR /* do the resize the official way */ XRRUpdateConfiguration (event); #else /* poke around in Xlib */ screen->xscreen->width = event->xconfigure.width; screen->xscreen->height = event->xconfigure.height; #endif meta_screen_resize (screen, event->xconfigure.width, event->xconfigure.height); } } break; case ConfigureRequest: /* This comment and code is found in both twm and fvwm */ /* * According to the July 27, 1988 ICCCM draft, we should ignore size and * position fields in the WM_NORMAL_HINTS property when we map a window. * Instead, we'll read the current geometry. Therefore, we should respond * to configuration requests for windows which have never been mapped. */ if (window == NULL) { unsigned int xwcm; XWindowChanges xwc; xwcm = event->xconfigurerequest.value_mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); xwc.x = event->xconfigurerequest.x; xwc.y = event->xconfigurerequest.y; xwc.width = event->xconfigurerequest.width; xwc.height = event->xconfigurerequest.height; xwc.border_width = event->xconfigurerequest.border_width; meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n", xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width); meta_error_trap_push (display); XConfigureWindow (display->xdisplay, event->xconfigurerequest.window, xwcm, &xwc); meta_error_trap_pop (display); } else { if (!frame_was_receiver) meta_window_configure_request (window, event); } break; case GravityNotify: break; case ResizeRequest: break; case CirculateNotify: break; case CirculateRequest: break; case PropertyNotify: { MetaGroup *group; MetaScreen *screen; if (window && !frame_was_receiver) meta_window_property_notify (window, event); else if (property_for_window && !frame_was_receiver) meta_window_property_notify (property_for_window, event); group = meta_display_lookup_group (display, event->xproperty.window); if (group != NULL) meta_group_property_notify (group, event); screen = NULL; if (window == NULL && group == NULL) /* window/group != NULL means it wasn't a root window */ screen = meta_display_screen_for_root (display, event->xproperty.window); if (screen != NULL) { if (event->xproperty.atom == display->atom__NET_DESKTOP_LAYOUT) meta_screen_update_workspace_layout (screen); else if (event->xproperty.atom == display->atom__NET_DESKTOP_NAMES) meta_screen_update_workspace_names (screen); #if 0 else if (event->xproperty.atom == display->atom__NET_RESTACK_WINDOW) handle_net_restack_window (display, event); #endif /* we just use this property as a sentinel to avoid * certain race conditions. See the comment for the * sentinel_counter variable declaration in display.h */ if (event->xproperty.atom == display->atom__MUFFIN_SENTINEL) { meta_display_decrement_focus_sentinel (display); } } } break; case SelectionClear: /* do this here instead of at end of function * so we can return */ /* FIXME: Clearing display->current_time here makes no sense to * me; who put this here and why? */ display->current_time = CurrentTime; process_selection_clear (display, event); /* Note that processing that may have resulted in * closing the display... so return right away. */ return FALSE; case SelectionRequest: process_selection_request (display, event); break; case SelectionNotify: break; case ColormapNotify: if (window && !frame_was_receiver) window->colormap = event->xcolormap.colormap; break; case ClientMessage: if (window) { if (!frame_was_receiver) meta_window_client_message (window, event); } else { MetaScreen *screen; screen = meta_display_screen_for_root (display, event->xclient.window); if (screen) { if (event->xclient.message_type == display->atom__NET_CURRENT_DESKTOP) { int space; MetaWorkspace *workspace; guint32 time; space = event->xclient.data.l[0]; time = event->xclient.data.l[1]; meta_verbose ("Request to change current workspace to %d with " "specified timestamp of %u\n", space, time); workspace = meta_screen_get_workspace_by_index (screen, space); /* Handle clients using the older version of the spec... */ if (time == 0 && workspace) { meta_warning ("Received a NET_CURRENT_DESKTOP message " "from a broken (outdated) client who sent " "a 0 timestamp\n"); time = meta_display_get_current_time_roundtrip (display); } if (workspace) meta_workspace_activate (workspace, time); else meta_verbose ("Don't know about workspace %d\n", space); } else if (event->xclient.message_type == display->atom__NET_NUMBER_OF_DESKTOPS) { int num_spaces; num_spaces = event->xclient.data.l[0]; meta_verbose ("Request to set number of workspaces to %d\n", num_spaces); meta_prefs_set_num_workspaces (num_spaces); } else if (event->xclient.message_type == display->atom__NET_SHOWING_DESKTOP) { gboolean showing_desktop; guint32 timestamp; showing_desktop = event->xclient.data.l[0] != 0; /* FIXME: Braindead protocol doesn't have a timestamp */ timestamp = meta_display_get_current_time_roundtrip (display); meta_verbose ("Request to %s desktop\n", showing_desktop ? "show" : "hide"); if (showing_desktop) meta_screen_show_desktop (screen, timestamp); else { meta_screen_unshow_desktop (screen); meta_workspace_focus_default_window (screen->active_workspace, NULL, timestamp); } } else if (event->xclient.message_type == display->atom__MUFFIN_RELOAD_THEME_MESSAGE) { meta_verbose ("Received reload theme request\n"); meta_ui_set_current_theme (meta_prefs_get_theme (), TRUE); meta_display_retheme_all (); } else if (event->xclient.message_type == display->atom__MUFFIN_SET_KEYBINDINGS_MESSAGE) { meta_verbose ("Received set keybindings request = %d\n", (int) event->xclient.data.l[0]); meta_set_keybindings_disabled (!event->xclient.data.l[0]); } else if (event->xclient.message_type == display->atom__MUFFIN_TOGGLE_VERBOSE) { meta_verbose ("Received toggle verbose message\n"); meta_set_verbose (!meta_is_verbose ()); } else if (event->xclient.message_type == display->atom_WM_PROTOCOLS) { meta_verbose ("Received WM_PROTOCOLS message\n"); if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING) { process_pong_message (display, event); /* We don't want ping reply events going into * the GTK+ event loop because gtk+ will treat * them as ping requests and send more replies. */ filter_out_event = TRUE; } } } if (event->xclient.message_type == display->atom__NET_REQUEST_FRAME_EXTENTS) { meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n"); process_request_frame_extents (display, event); } } break; case MappingNotify: { gboolean ignore_current; ignore_current = FALSE; /* Check whether the next event is an identical MappingNotify * event. If it is, ignore the current event, we'll update * when we get the next one. */ if (XPending (display->xdisplay)) { XEvent next_event; XPeekEvent (display->xdisplay, &next_event); if (next_event.type == MappingNotify && next_event.xmapping.request == event->xmapping.request) ignore_current = TRUE; } if (!ignore_current) { /* Let XLib know that there is a new keyboard mapping. */ XRefreshKeyboardMapping (&event->xmapping); meta_display_process_mapping_event (display, event); } } break; default: #ifdef HAVE_XKB if (event->type == display->xkb_base_event_type) { XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; switch (xkb_ev->xkb_type) { case XkbBellNotify: if (XSERVER_TIME_IS_BEFORE(display->last_bell_time, xkb_ev->time - 100)) { display->last_bell_time = xkb_ev->time; meta_bell_notify (display, xkb_ev); } break; case XkbNewKeyboardNotify: case XkbMapNotify: meta_display_process_mapping_event (display, event); break; } } #endif break; } if (!bypass_compositor) { if (meta_compositor_process_event (display->compositor, event, window)) filter_out_event = TRUE; } display->current_time = CurrentTime; return filter_out_event; } /* Return the window this has to do with, if any, rather * than the frame or root window that was selecting * for substructure */ static Window event_get_modified_window (MetaDisplay *display, XEvent *event) { switch (event->type) { case KeyPress: case KeyRelease: case ButtonPress: case ButtonRelease: case MotionNotify: case FocusIn: case FocusOut: case KeymapNotify: case Expose: case GraphicsExpose: case NoExpose: case VisibilityNotify: case ResizeRequest: case PropertyNotify: case SelectionClear: case SelectionRequest: case SelectionNotify: case ColormapNotify: case ClientMessage: case EnterNotify: case LeaveNotify: return event->xany.window; case CreateNotify: return event->xcreatewindow.window; case DestroyNotify: return event->xdestroywindow.window; case UnmapNotify: return event->xunmap.window; case MapNotify: return event->xmap.window; case MapRequest: return event->xmaprequest.window; case ReparentNotify: return event->xreparent.window; case ConfigureNotify: return event->xconfigure.window; case ConfigureRequest: return event->xconfigurerequest.window; case GravityNotify: return event->xgravity.window; case CirculateNotify: return event->xcirculate.window; case CirculateRequest: return event->xcirculaterequest.window; case MappingNotify: return None; default: #ifdef HAVE_SHAPE if (META_DISPLAY_HAS_SHAPE (display) && event->type == (display->shape_event_base + ShapeNotify)) { XShapeEvent *sev = (XShapeEvent*) event; return sev->window; } #endif return None; } } static guint32 event_get_time (MetaDisplay *display, XEvent *event) { switch (event->type) { case KeyPress: case KeyRelease: return event->xkey.time; case ButtonPress: case ButtonRelease: return event->xbutton.time; case MotionNotify: return event->xmotion.time; case PropertyNotify: return event->xproperty.time; case SelectionClear: case SelectionRequest: case SelectionNotify: return event->xselection.time; case EnterNotify: case LeaveNotify: return event->xcrossing.time; case FocusIn: case FocusOut: case KeymapNotify: case Expose: case GraphicsExpose: case NoExpose: case MapNotify: case UnmapNotify: case VisibilityNotify: case ResizeRequest: case ColormapNotify: case ClientMessage: case CreateNotify: case DestroyNotify: case MapRequest: case ReparentNotify: case ConfigureNotify: case ConfigureRequest: case GravityNotify: case CirculateNotify: case CirculateRequest: case MappingNotify: default: return CurrentTime; } } #ifdef WITH_VERBOSE_MODE LOCAL_SYMBOL const char* meta_event_detail_to_string (int d) { const char *detail = "???"; switch (d) { /* We are an ancestor in the A<->B focus change relationship */ case NotifyAncestor: detail = "NotifyAncestor"; break; case NotifyDetailNone: detail = "NotifyDetailNone"; break; /* We are a descendant in the A<->B focus change relationship */ case NotifyInferior: detail = "NotifyInferior"; break; case NotifyNonlinear: detail = "NotifyNonlinear"; break; case NotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break; case NotifyPointer: detail = "NotifyPointer"; break; case NotifyPointerRoot: detail = "NotifyPointerRoot"; break; case NotifyVirtual: detail = "NotifyVirtual"; break; } return detail; } #endif /* WITH_VERBOSE_MODE */ #ifdef WITH_VERBOSE_MODE LOCAL_SYMBOL const char* meta_event_mode_to_string (int m) { const char *mode = "???"; switch (m) { case NotifyNormal: mode = "NotifyNormal"; break; case NotifyGrab: mode = "NotifyGrab"; break; case NotifyUngrab: mode = "NotifyUngrab"; break; /* not sure any X implementations are missing this, but * it seems to be absent from some docs. */ #ifdef NotifyWhileGrabbed case NotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break; #endif } return mode; } #endif /* WITH_VERBOSE_MODE */ #ifdef WITH_VERBOSE_MODE static const char* stack_mode_to_string (int mode) { switch (mode) { case Above: return "Above"; case Below: return "Below"; case TopIf: return "TopIf"; case BottomIf: return "BottomIf"; case Opposite: return "Opposite"; } return "Unknown"; } #endif /* WITH_VERBOSE_MODE */ #ifdef WITH_VERBOSE_MODE static char* key_event_description (Display *xdisplay, XEvent *event) { KeySym keysym; const char *str; keysym = XkbKeycodeToKeysym (xdisplay, event->xkey.keycode, 0, 0); str = XKeysymToString (keysym); return g_strdup_printf ("Key '%s' state 0x%x", str ? str : "none", event->xkey.state); } #endif /* WITH_VERBOSE_MODE */ #ifdef HAVE_XSYNC #ifdef WITH_VERBOSE_MODE static gint64 sync_value_to_64 (const XSyncValue *value) { gint64 v; v = XSyncValueLow32 (*value); v |= (((gint64)XSyncValueHigh32 (*value)) << 32); return v; } #endif /* WITH_VERBOSE_MODE */ #ifdef WITH_VERBOSE_MODE static const char* alarm_state_to_string (XSyncAlarmState state) { switch (state) { case XSyncAlarmActive: return "Active"; case XSyncAlarmInactive: return "Inactive"; case XSyncAlarmDestroyed: return "Destroyed"; default: return "(unknown)"; } } #endif /* WITH_VERBOSE_MODE */ #endif /* HAVE_XSYNC */ #ifdef WITH_VERBOSE_MODE static void meta_spew_event (MetaDisplay *display, XEvent *event) { const char *name = NULL; char *extra = NULL; char *winname; MetaScreen *screen; if (!meta_is_verbose()) return; /* filter overnumerous events */ if (event->type == Expose || event->type == MotionNotify || event->type == NoExpose) return; switch (event->type) { case KeyPress: name = "KeyPress"; extra = key_event_description (display->xdisplay, event); break; case KeyRelease: name = "KeyRelease"; extra = key_event_description (display->xdisplay, event); break; case ButtonPress: name = "ButtonPress"; extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d", event->xbutton.button, event->xbutton.state, event->xbutton.x, event->xbutton.y, event->xbutton.root, event->xbutton.same_screen); break; case ButtonRelease: name = "ButtonRelease"; extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d", event->xbutton.button, event->xbutton.state, event->xbutton.x, event->xbutton.y, event->xbutton.root, event->xbutton.same_screen); break; case MotionNotify: name = "MotionNotify"; extra = g_strdup_printf ("win: 0x%lx x: %d y: %d", event->xmotion.window, event->xmotion.x, event->xmotion.y); break; case EnterNotify: name = "EnterNotify"; extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d", event->xcrossing.window, event->xcrossing.root, event->xcrossing.subwindow, meta_event_mode_to_string (event->xcrossing.mode), meta_event_detail_to_string (event->xcrossing.detail), event->xcrossing.focus, event->xcrossing.x, event->xcrossing.y); break; case LeaveNotify: name = "LeaveNotify"; extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d", event->xcrossing.window, event->xcrossing.root, event->xcrossing.subwindow, meta_event_mode_to_string (event->xcrossing.mode), meta_event_detail_to_string (event->xcrossing.detail), event->xcrossing.focus, event->xcrossing.x, event->xcrossing.y); break; case FocusIn: name = "FocusIn"; extra = g_strdup_printf ("detail: %s mode: %s\n", meta_event_detail_to_string (event->xfocus.detail), meta_event_mode_to_string (event->xfocus.mode)); break; case FocusOut: name = "FocusOut"; extra = g_strdup_printf ("detail: %s mode: %s\n", meta_event_detail_to_string (event->xfocus.detail), meta_event_mode_to_string (event->xfocus.mode)); break; case KeymapNotify: name = "KeymapNotify"; break; case Expose: name = "Expose"; break; case GraphicsExpose: name = "GraphicsExpose"; break; case NoExpose: name = "NoExpose"; break; case VisibilityNotify: name = "VisibilityNotify"; break; case CreateNotify: name = "CreateNotify"; extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx", event->xcreatewindow.parent, event->xcreatewindow.window); break; case DestroyNotify: name = "DestroyNotify"; extra = g_strdup_printf ("event: 0x%lx window: 0x%lx", event->xdestroywindow.event, event->xdestroywindow.window); break; case UnmapNotify: name = "UnmapNotify"; extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d", event->xunmap.event, event->xunmap.window, event->xunmap.from_configure); break; case MapNotify: name = "MapNotify"; extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d", event->xmap.event, event->xmap.window, event->xmap.override_redirect); break; case MapRequest: name = "MapRequest"; extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n", event->xmaprequest.window, event->xmaprequest.parent); break; case ReparentNotify: name = "ReparentNotify"; extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n", event->xreparent.window, event->xreparent.parent, event->xreparent.event); break; case ConfigureNotify: name = "ConfigureNotify"; extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d", event->xconfigure.x, event->xconfigure.y, event->xconfigure.width, event->xconfigure.height, event->xconfigure.above, event->xconfigure.override_redirect); break; case ConfigureRequest: name = "ConfigureRequest"; extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s", event->xconfigurerequest.parent, event->xconfigurerequest.window, event->xconfigurerequest.x, event->xconfigurerequest.value_mask & CWX ? "" : "(unset) ", event->xconfigurerequest.y, event->xconfigurerequest.value_mask & CWY ? "" : "(unset) ", event->xconfigurerequest.width, event->xconfigurerequest.value_mask & CWWidth ? "" : "(unset) ", event->xconfigurerequest.height, event->xconfigurerequest.value_mask & CWHeight ? "" : "(unset) ", event->xconfigurerequest.border_width, event->xconfigurerequest.value_mask & CWBorderWidth ? "" : "(unset)", event->xconfigurerequest.above, event->xconfigurerequest.value_mask & CWSibling ? "" : "(unset)", stack_mode_to_string (event->xconfigurerequest.detail), event->xconfigurerequest.value_mask & CWStackMode ? "" : "(unset)"); break; case GravityNotify: name = "GravityNotify"; break; case ResizeRequest: name = "ResizeRequest"; extra = g_strdup_printf ("width = %d height = %d", event->xresizerequest.width, event->xresizerequest.height); break; case CirculateNotify: name = "CirculateNotify"; break; case CirculateRequest: name = "CirculateRequest"; break; case PropertyNotify: { char *str; const char *state; name = "PropertyNotify"; meta_error_trap_push (display); str = XGetAtomName (display->xdisplay, event->xproperty.atom); meta_error_trap_pop (display); if (event->xproperty.state == PropertyNewValue) state = "PropertyNewValue"; else if (event->xproperty.state == PropertyDelete) state = "PropertyDelete"; else state = "???"; extra = g_strdup_printf ("atom: %s state: %s", str ? str : "(unknown atom)", state); meta_XFree (str); } break; case SelectionClear: name = "SelectionClear"; break; case SelectionRequest: name = "SelectionRequest"; break; case SelectionNotify: name = "SelectionNotify"; break; case ColormapNotify: name = "ColormapNotify"; break; case ClientMessage: { char *str; name = "ClientMessage"; meta_error_trap_push (display); str = XGetAtomName (display->xdisplay, event->xclient.message_type); meta_error_trap_pop (display); extra = g_strdup_printf ("type: %s format: %d\n", str ? str : "(unknown atom)", event->xclient.format); meta_XFree (str); } break; case MappingNotify: name = "MappingNotify"; break; default: #ifdef HAVE_XSYNC if (META_DISPLAY_HAS_XSYNC (display) && event->type == (display->xsync_event_base + XSyncAlarmNotify)) { XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event; name = "XSyncAlarmNotify"; extra = g_strdup_printf ("alarm: 0x%lx" " counter_value: %" G_GINT64_FORMAT " alarm_value: %" G_GINT64_FORMAT " time: %u alarm state: %s", aevent->alarm, (gint64) sync_value_to_64 (&aevent->counter_value), (gint64) sync_value_to_64 (&aevent->alarm_value), (unsigned int)aevent->time, alarm_state_to_string (aevent->state)); } else #endif /* HAVE_XSYNC */ #ifdef HAVE_SHAPE if (META_DISPLAY_HAS_SHAPE (display) && event->type == (display->shape_event_base + ShapeNotify)) { XShapeEvent *sev = (XShapeEvent*) event; name = "ShapeNotify"; extra = g_strdup_printf ("kind: %s " "x: %d y: %d w: %u h: %u " "shaped: %d", sev->kind == ShapeBounding ? "ShapeBounding" : (sev->kind == ShapeClip ? "ShapeClip" : "(unknown)"), sev->x, sev->y, sev->width, sev->height, sev->shaped); } else #endif /* HAVE_SHAPE */ { name = "(Unknown event)"; extra = g_strdup_printf ("type: %d", event->xany.type); } break; } screen = meta_display_screen_for_root (display, event->xany.window); if (screen) winname = g_strdup_printf ("root %d", screen->number); else winname = g_strdup_printf ("0x%lx", event->xany.window); meta_topic (META_DEBUG_EVENTS, "%s on %s%s %s %sserial %lu\n", name, winname, extra ? ":" : "", extra ? extra : "", event->xany.send_event ? "SEND " : "", event->xany.serial); free (winname); if (extra) free (extra); } #endif /* WITH_VERBOSE_MODE */ LOCAL_SYMBOL MetaWindow* meta_display_lookup_x_window (MetaDisplay *display, Window xwindow) { return g_hash_table_lookup (display->window_ids, &xwindow); } LOCAL_SYMBOL void meta_display_register_x_window (MetaDisplay *display, Window *xwindowp, MetaWindow *window) { g_return_if_fail (g_hash_table_lookup (display->window_ids, xwindowp) == NULL); g_hash_table_insert (display->window_ids, xwindowp, window); } LOCAL_SYMBOL void meta_display_unregister_x_window (MetaDisplay *display, Window xwindow) { g_return_if_fail (g_hash_table_lookup (display->window_ids, &xwindow) != NULL); g_hash_table_remove (display->window_ids, &xwindow); /* Remove any pending pings */ remove_pending_pings_for_window (display, xwindow); } LOCAL_SYMBOL void meta_display_notify_window_created (MetaDisplay *display, MetaWindow *window) { g_signal_emit (display, display_signals[WINDOW_CREATED], 0, window); } /** * meta_display_xwindow_is_a_no_focus_window: * @display: A #MetaDisplay * @xwindow: An X11 window * * Returns %TRUE iff window is one of muffin's internal "no focus" windows * (there is one per screen) which will have the focus when there is no * actual client window focused. */ gboolean meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display, Window xwindow) { gboolean is_a_no_focus_window = FALSE; GSList *temp = display->screens; while (temp != NULL) { MetaScreen *screen = temp->data; if (screen->no_focus_window == xwindow) { is_a_no_focus_window = TRUE; break; } temp = temp->next; } return is_a_no_focus_window; } LOCAL_SYMBOL Cursor meta_display_create_x_cursor (MetaDisplay *display, MetaCursor cursor) { Cursor xcursor; guint glyph; switch (cursor) { case META_CURSOR_DEFAULT: glyph = XC_left_ptr; break; case META_CURSOR_NORTH_RESIZE: glyph = XC_top_side; break; case META_CURSOR_SOUTH_RESIZE: glyph = XC_bottom_side; break; case META_CURSOR_WEST_RESIZE: glyph = XC_left_side; break; case META_CURSOR_EAST_RESIZE: glyph = XC_right_side; break; case META_CURSOR_SE_RESIZE: glyph = XC_bottom_right_corner; break; case META_CURSOR_SW_RESIZE: glyph = XC_bottom_left_corner; break; case META_CURSOR_NE_RESIZE: glyph = XC_top_right_corner; break; case META_CURSOR_NW_RESIZE: glyph = XC_top_left_corner; break; case META_CURSOR_MOVE_OR_RESIZE_WINDOW: glyph = XC_fleur; break; case META_CURSOR_BUSY: glyph = XC_watch; break; default: g_assert_not_reached (); glyph = 0; /* silence compiler */ break; } xcursor = XCreateFontCursor (display->xdisplay, glyph); return xcursor; } static Cursor xcursor_for_op (MetaDisplay *display, MetaGrabOp op) { MetaCursor cursor = META_CURSOR_DEFAULT; switch (op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_SE: cursor = META_CURSOR_SE_RESIZE; break; case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_S: cursor = META_CURSOR_SOUTH_RESIZE; break; case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_SW: cursor = META_CURSOR_SW_RESIZE; break; case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_N: cursor = META_CURSOR_NORTH_RESIZE; break; case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: cursor = META_CURSOR_NE_RESIZE; break; case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: cursor = META_CURSOR_NW_RESIZE; break; case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_W: cursor = META_CURSOR_WEST_RESIZE; break; case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_E: cursor = META_CURSOR_EAST_RESIZE; break; case META_GRAB_OP_MOVING: case META_GRAB_OP_KEYBOARD_MOVING: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: cursor = META_CURSOR_MOVE_OR_RESIZE_WINDOW; break; default: break; } if (cursor == META_CURSOR_DEFAULT) return None; return meta_display_create_x_cursor (display, cursor); } LOCAL_SYMBOL void meta_display_set_grab_op_cursor (MetaDisplay *display, MetaScreen *screen, MetaGrabOp op, gboolean change_pointer, Window grab_xwindow, guint32 timestamp) { Cursor cursor; cursor = xcursor_for_op (display, op); #define GRAB_MASK (PointerMotionMask | \ ButtonPressMask | ButtonReleaseMask | \ EnterWindowMask | LeaveWindowMask) if (change_pointer) { meta_error_trap_push_with_return (display); XChangeActivePointerGrab (display->xdisplay, GRAB_MASK, cursor, timestamp); meta_topic (META_DEBUG_WINDOW_OPS, "Changed pointer with XChangeActivePointerGrab()\n"); if (meta_error_trap_pop_with_return (display) != Success) { meta_topic (META_DEBUG_WINDOW_OPS, "Error trapped from XChangeActivePointerGrab()\n"); if (display->grab_have_pointer) display->grab_have_pointer = FALSE; } } else { g_assert (screen != NULL); meta_error_trap_push (display); if (XGrabPointer (display->xdisplay, grab_xwindow, False, GRAB_MASK, GrabModeAsync, GrabModeAsync, screen->xroot, cursor, timestamp) == GrabSuccess) { display->grab_have_pointer = TRUE; meta_topic (META_DEBUG_WINDOW_OPS, "XGrabPointer() returned GrabSuccess time %u\n", timestamp); } #ifdef WITH_VERBOSE_MODE else { meta_topic (META_DEBUG_WINDOW_OPS, "XGrabPointer() failed time %u\n", timestamp); } #endif meta_error_trap_pop (display); } #undef GRAB_MASK if (cursor != None) XFreeCursor (display->xdisplay, cursor); } gboolean meta_display_begin_grab_op (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, MetaGrabOp op, gboolean pointer_already_grabbed, gboolean frame_action, int button, gulong modmask, guint32 timestamp, int root_x, int root_y) { MetaWindow *grab_window = NULL; Window grab_xwindow; meta_topic (META_DEBUG_WINDOW_OPS, "Doing grab op %u on window %s button %d pointer already grabbed: %d pointer pos %d,%d\n", op, window ? window->desc : "none", button, pointer_already_grabbed, root_x, root_y); if (display->grab_op != META_GRAB_OP_NONE) { if (window) meta_warning ("Attempt to perform window operation %u on window %s when operation %u on %s already in effect\n", op, window->desc, display->grab_op, display->grab_window ? display->grab_window->desc : "none"); return FALSE; } if (window && (meta_grab_op_is_moving (op) || meta_grab_op_is_resizing (op))) { if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); else { display->grab_initial_x = root_x; display->grab_initial_y = root_y; display->grab_threshold_movement_reached = FALSE; } } /* If window is a modal dialog attached to its parent, * grab the parent instead for moving. */ if (window && meta_window_is_attached_dialog (window) && meta_grab_op_is_moving (op)) grab_window = meta_window_get_transient_for (window); if (grab_window == NULL) grab_window = window; /* FIXME: * If we have no MetaWindow we do our best * and try to do the grab on the RootWindow. * This will fail if anyone else has any * key grab on the RootWindow. */ if (grab_window) grab_xwindow = grab_window->frame ? grab_window->frame->xwindow : grab_window->xwindow; else grab_xwindow = screen->xroot; display->grab_have_pointer = FALSE; if (pointer_already_grabbed) display->grab_have_pointer = TRUE; meta_display_set_grab_op_cursor (display, screen, op, FALSE, grab_xwindow, timestamp); if (!display->grab_have_pointer && !grab_op_is_keyboard (op)) { meta_topic (META_DEBUG_WINDOW_OPS, "XGrabPointer() failed\n"); return FALSE; } /* Grab keys for keyboard ops and mouse move/resizes; see #126497 */ if (grab_op_is_keyboard (op) || grab_op_is_mouse_only (op)) { if (grab_window) display->grab_have_keyboard = meta_window_grab_all_keys (grab_window, timestamp); else display->grab_have_keyboard = meta_screen_grab_all_keys (screen, timestamp); if (!display->grab_have_keyboard) { meta_topic (META_DEBUG_WINDOW_OPS, "grabbing all keys failed, ungrabbing pointer\n"); XUngrabPointer (display->xdisplay, timestamp); display->grab_have_pointer = FALSE; return FALSE; } } display->grab_op = op; display->grab_window = grab_window; display->grab_screen = screen; display->grab_xwindow = grab_xwindow; display->grab_button = button; display->grab_mask = modmask; if (window) { display->grab_tile_mode = window->tile_mode; display->grab_tile_monitor_number = window->tile_monitor_number; } else { display->grab_tile_mode = META_TILE_NONE; display->grab_tile_monitor_number = -1; } display->grab_anchor_root_x = root_x; display->grab_anchor_root_y = root_y; display->grab_latest_motion_x = root_x; display->grab_latest_motion_y = root_y; display->grab_last_moveresize_time.tv_sec = 0; display->grab_last_moveresize_time.tv_usec = 0; display->grab_motion_notify_time = 0; display->grab_old_window_stacking = NULL; #ifdef HAVE_XSYNC display->grab_last_user_action_was_snap = FALSE; #endif display->grab_frame_action = frame_action; display->grab_resize_unmaximize = 0; if (display->grab_resize_timeout_id) { g_source_remove (display->grab_resize_timeout_id); display->grab_resize_timeout_id = 0; } if (display->grab_window) { meta_window_get_client_root_coords (display->grab_window, &display->grab_initial_window_pos); display->grab_anchor_window_pos = display->grab_initial_window_pos; #ifdef HAVE_XSYNC if ( meta_grab_op_is_resizing (display->grab_op) && display->grab_window->sync_request_counter != None) { meta_window_create_sync_request_alarm (display->grab_window); } #endif } meta_topic (META_DEBUG_WINDOW_OPS, "Grab op %u on window %s successful\n", display->grab_op, window ? window->desc : "(null)"); g_assert (display->grab_window != NULL || display->grab_screen != NULL); g_assert (display->grab_op != META_GRAB_OP_NONE); /* Save the old stacking */ if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op)) { meta_topic (META_DEBUG_WINDOW_OPS, "Saving old stack positions; old pointer was %p.\n", display->grab_old_window_stacking); display->grab_old_window_stacking = meta_stack_get_positions (screen->stack); } if (display->grab_window) { meta_window_refresh_resize_popup (display->grab_window); } meta_compositor_grab_op_begin (display->compositor); g_signal_emit (display, display_signals[GRAB_OP_BEGIN], 0, screen, display->grab_window, display->grab_op); return TRUE; } #ifdef HAVE_XSYNC /* We store sync alarms in the window ID hash table, because they are * just more types of XIDs in the same global space, but we have * typesafe functions to register/unregister for readability. */ MetaWindow* meta_display_lookup_sync_alarm (MetaDisplay *display, XSyncAlarm alarm) { return g_hash_table_lookup (display->window_ids, &alarm); } void meta_display_register_sync_alarm (MetaDisplay *display, XSyncAlarm *alarmp, MetaWindow *window) { g_return_if_fail (g_hash_table_lookup (display->window_ids, alarmp) == NULL); g_hash_table_insert (display->window_ids, alarmp, window); } void meta_display_unregister_sync_alarm (MetaDisplay *display, XSyncAlarm alarm) { g_return_if_fail (g_hash_table_lookup (display->window_ids, &alarm) != NULL); g_hash_table_remove (display->window_ids, &alarm); } #endif /* HAVE_XSYNC */ void meta_display_end_grab_op (MetaDisplay *display, guint32 timestamp) { meta_topic (META_DEBUG_WINDOW_OPS, "Ending grab op %u at time %u\n", display->grab_op, timestamp); if (display->grab_op == META_GRAB_OP_NONE) return; meta_compositor_grab_op_end (display->compositor); g_signal_emit (display, display_signals[GRAB_OP_END], 0, display->grab_screen, display->grab_window, display->grab_op); if (display->grab_window != NULL) display->grab_window->shaken_loose = FALSE; if (display->grab_window != NULL && !meta_prefs_get_raise_on_click () && (meta_grab_op_is_moving (display->grab_op) || meta_grab_op_is_resizing (display->grab_op))) { /* Only raise the window in orthogonal raise * ('do-not-raise-on-click') mode if the user didn't try to move * or resize the given window by at least a threshold amount. * For raise on click mode, the window was raised at the * beginning of the grab_op. */ if (!display->grab_threshold_movement_reached) meta_window_raise (display->grab_window); } if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op) || display->grab_op == META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING) { /* If the ungrab here causes an EnterNotify, ignore it for * sloppy focus */ display->ungrab_should_not_cause_focus_window = display->grab_xwindow; } /* If this was a move or resize clear out the edge cache */ if (meta_grab_op_is_resizing (display->grab_op) || meta_grab_op_is_moving (display->grab_op)) { meta_topic (META_DEBUG_WINDOW_OPS, "Clearing out the edges for resistance/snapping\n"); meta_display_cleanup_edges (display); } if (display->grab_old_window_stacking != NULL) { meta_topic (META_DEBUG_WINDOW_OPS, "Clearing out the old stack position, which was %p.\n", display->grab_old_window_stacking); g_list_free (display->grab_old_window_stacking); display->grab_old_window_stacking = NULL; } if (display->grab_have_pointer) { meta_topic (META_DEBUG_WINDOW_OPS, "Ungrabbing pointer with timestamp %u\n", timestamp); XUngrabPointer (display->xdisplay, timestamp); } if (display->grab_have_keyboard) { meta_topic (META_DEBUG_WINDOW_OPS, "Ungrabbing all keys timestamp %u\n", timestamp); if (display->grab_window) meta_window_ungrab_all_keys (display->grab_window, timestamp); else meta_screen_ungrab_all_keys (display->grab_screen, timestamp); } if (display->grab_window && display->grab_window->resizing_tile_type != META_WINDOW_TILE_TYPE_NONE) { display->grab_window->snap_queued = display->grab_window->resizing_tile_type == META_WINDOW_TILE_TYPE_SNAPPED; display->grab_window->tile_mode = display->grab_window->resize_tile_mode; display->grab_window->custom_snap_size = TRUE; meta_window_real_tile (display->grab_window, TRUE); } meta_screen_hide_hud_and_preview (display->grab_screen); display->grab_window = NULL; display->grab_screen = NULL; display->grab_xwindow = None; display->grab_tile_mode = META_TILE_NONE; display->grab_tile_monitor_number = -1; display->grab_op = META_GRAB_OP_NONE; if (display->grab_resize_popup) { meta_ui_resize_popup_free (display->grab_resize_popup); display->grab_resize_popup = NULL; } if (display->grab_resize_timeout_id) { g_source_remove (display->grab_resize_timeout_id); display->grab_resize_timeout_id = 0; } } /** * meta_display_get_grab_op: * Gets the current grab operation, if any. * * Return value: the current grab operation, or %META_GRAB_OP_NONE if * Muffin doesn't currently have a grab. %META_GRAB_OP_COMPOSITOR will * be returned if a compositor-plugin modal operation is in effect * (See muffin_begin_modal_for_plugin()) */ MetaGrabOp meta_display_get_grab_op (MetaDisplay *display) { return display->grab_op; } LOCAL_SYMBOL void meta_display_check_threshold_reached (MetaDisplay *display, int x, int y) { /* Don't bother doing the check again if we've already reached the threshold */ if (meta_prefs_get_raise_on_click () || display->grab_threshold_movement_reached) return; if (ABS (display->grab_initial_x - x) >= 8 || ABS (display->grab_initial_y - y) >= 8) display->grab_threshold_movement_reached = TRUE; } static void meta_change_button_grab (MetaDisplay *display, Window xwindow, gboolean grab, gboolean sync, int button, int modmask) { unsigned int ignored_mask; meta_verbose ("%s 0x%lx sync = %d button = %d modmask 0x%x\n", grab ? "Grabbing" : "Ungrabbing", xwindow, sync, button, modmask); meta_error_trap_push (display); ignored_mask = 0; while (ignored_mask <= display->ignored_modifier_mask) { if (ignored_mask & ~(display->ignored_modifier_mask)) { /* Not a combination of ignored modifiers * (it contains some non-ignored modifiers) */ ++ignored_mask; continue; } if (meta_is_debugging ()) meta_error_trap_push_with_return (display); /* GrabModeSync means freeze until XAllowEvents */ if (grab) XGrabButton (display->xdisplay, button, modmask | ignored_mask, xwindow, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PointerMotionHintMask, sync ? GrabModeSync : GrabModeAsync, GrabModeAsync, False, None); else XUngrabButton (display->xdisplay, button, modmask | ignored_mask, xwindow); if (meta_is_debugging ()) { int result; result = meta_error_trap_pop_with_return (display); if (result != Success) meta_verbose ("Failed to %s button %d with mask 0x%x for window 0x%lx error code %d\n", grab ? "grab" : "ungrab", button, modmask | ignored_mask, xwindow, result); } ++ignored_mask; } meta_error_trap_pop (display); } LOCAL_SYMBOL void meta_display_grab_window_buttons (MetaDisplay *display, Window xwindow) { /* Grab Alt + button1 for moving window. * Grab Alt + button2 for resizing window. * Grab Alt + button3 for popping up window menu. * Grab Alt + Shift + button1 for snap-moving window. * Grab Alt + button4 for scrolling in * Grab Alt + button5 for scrolling out */ meta_verbose ("Grabbing window buttons for 0x%lx\n", xwindow); /* FIXME If we ignored errors here instead of spewing, we could * put one big error trap around the loop and avoid a bunch of * XSync() */ gboolean debug = display->debug_button_grabs; if (display->window_grab_modifiers != 0) { int i; for (i = 1; i < 4; i++) { meta_change_button_grab (display, xwindow, TRUE, FALSE, i, display->window_grab_modifiers); /* This is for debugging, since I end up moving the Xnest * otherwise ;-) */ if (debug) meta_change_button_grab (display, xwindow, TRUE, FALSE, i, ControlMask); } /* In addition to grabbing Alt+Button1 for moving the window, * grab Alt+Shift+Button1 for snap-moving the window. See bug * 112478. Unfortunately, this doesn't work with * Shift+Alt+Button1 for some reason; so at least part of the * order still matters, which sucks (please FIXME). */ meta_change_button_grab (display, xwindow, TRUE, FALSE, 1, display->window_grab_modifiers | ShiftMask); } if (display->mouse_zoom_enabled && display->mouse_zoom_modifiers != 0) { int i; for (i = 4; i < 6; i++) { meta_change_button_grab (display, xwindow, TRUE, FALSE, i, display->mouse_zoom_modifiers); /* This is for debugging, since I end up moving the Xnest * otherwise ;-) */ if (debug) meta_change_button_grab (display, xwindow, TRUE, FALSE, i, ControlMask); } } } LOCAL_SYMBOL void meta_display_ungrab_window_buttons (MetaDisplay *display, Window xwindow) { gboolean debug; int i; if (display->window_grab_modifiers == 0) return; debug = display->debug_button_grabs; i = 1; while (i < 4) { meta_change_button_grab (display, xwindow, FALSE, FALSE, i, display->window_grab_modifiers); if (debug) meta_change_button_grab (display, xwindow, FALSE, FALSE, i, ControlMask); ++i; } if (display->mouse_zoom_modifiers == 0) return; i = 4; while (i < 6) { meta_change_button_grab (display, xwindow, FALSE, FALSE, i, display->mouse_zoom_modifiers); if (debug) meta_change_button_grab (display, xwindow, FALSE, FALSE, i, ControlMask); ++i; } } /* Grab buttons we only grab while unfocused in click-to-focus mode */ #define MAX_FOCUS_BUTTON 4 LOCAL_SYMBOL void meta_display_grab_focus_window_button (MetaDisplay *display, MetaWindow *window) { /* Grab button 1 for activating unfocused windows */ meta_verbose ("Grabbing unfocused window buttons for %s\n", window->desc); #if 0 /* FIXME:115072 */ /* Don't grab at all unless in click to focus mode. In click to * focus, we may sometimes be clever about intercepting and eating * the focus click. But in mouse focus, we never do that since the * focus window may not be raised, and who wants to think about * mouse focus anyway. */ if (meta_prefs_get_focus_mode () != C_DESKTOP_FOCUS_MODE_CLICK) { meta_verbose (" (well, not grabbing since not in click to focus mode)\n"); return; } #endif if (window->have_focus_click_grab) { meta_verbose (" (well, not grabbing since we already have the grab)\n"); return; } /* FIXME If we ignored errors here instead of spewing, we could * put one big error trap around the loop and avoid a bunch of * XSync() */ { int i = 1; while (i < MAX_FOCUS_BUTTON) { meta_change_button_grab (display, window->xwindow, TRUE, TRUE, i, 0); ++i; } window->have_focus_click_grab = TRUE; } } LOCAL_SYMBOL void meta_display_ungrab_focus_window_button (MetaDisplay *display, MetaWindow *window) { meta_verbose ("Ungrabbing unfocused window buttons for %s\n", window->desc); if (!window->have_focus_click_grab) return; { int i = 1; while (i < MAX_FOCUS_BUTTON) { meta_change_button_grab (display, window->xwindow, FALSE, FALSE, i, 0); ++i; } window->have_focus_click_grab = FALSE; } } LOCAL_SYMBOL void meta_display_increment_event_serial (MetaDisplay *display) { /* We just make some random X request */ XDeleteProperty (display->xdisplay, display->leader_window, display->atom__MOTIF_WM_HINTS); } LOCAL_SYMBOL void meta_display_update_active_window_hint (MetaDisplay *display) { GSList *tmp; gulong data[1]; if (display->closing) return; /* Leave old value for a replacement */ if (display->focus_window) data[0] = display->focus_window->xwindow; else data[0] = None; tmp = display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; meta_error_trap_push (display); XChangeProperty (display->xdisplay, screen->xroot, display->atom__NET_ACTIVE_WINDOW, XA_WINDOW, 32, PropModeReplace, (guchar*) data, 1); meta_error_trap_pop (display); tmp = tmp->next; } } LOCAL_SYMBOL void meta_display_queue_retheme_all_windows (MetaDisplay *display) { GSList* windows; GSList *tmp; windows = meta_display_list_windows (display, META_LIST_DEFAULT); tmp = windows; while (tmp != NULL) { MetaWindow *window = tmp->data; meta_window_queue (window, META_QUEUE_MOVE_RESIZE); meta_window_frame_size_changed (window); if (window->frame) { meta_frame_queue_draw (window->frame); } tmp = tmp->next; } g_slist_free (windows); } LOCAL_SYMBOL void meta_display_retheme_all (void) { meta_display_queue_retheme_all_windows (meta_get_display ()); } LOCAL_SYMBOL void meta_display_set_cursor_theme (const char *theme, int size) { #ifdef HAVE_XCURSOR GSList *tmp; MetaDisplay *display = meta_get_display (); XcursorSetTheme (display->xdisplay, theme); XcursorSetDefaultSize (display->xdisplay, size); tmp = display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; meta_screen_update_cursor (screen); tmp = tmp->next; } #endif } /* * Stores whether syncing is currently enabled. */ static gboolean is_syncing = FALSE; /* * Returns whether X synchronisation is currently enabled. * * \return true if we must wait for events whenever we send X requests; * false otherwise. * * \bug This is *only* called by meta_display_open, but by that time * we have already turned syncing on or off on startup, and we don't * have any way to do so while Muffin is running, so it's rather * pointless. */ gboolean meta_is_syncing (void) { return is_syncing; } /* * A handy way to turn on synchronisation on or off for every display. * * \bug Of course there is only one display ever anyway, so this can * be rather hugely simplified. */ void meta_set_syncing (gboolean setting) { if (setting != is_syncing) { is_syncing = setting; if (meta_get_display ()) XSynchronize (meta_get_display ()->xdisplay, is_syncing); } } /* * How long, in milliseconds, we should wait after pinging a window * before deciding it's not going to get back to us. */ #define PING_TIMEOUT_DELAY 5000 /* * Does whatever it is we decided to do when a window didn't respond * to a ping. We also remove the ping from the display's list of * pending pings. This function is called by the event loop when the timeout * times out which we created at the start of the ping. * * \param data All the information about this ping. It is a MetaPingData * cast to a void* in order to be passable to a timeout function. * This function will also free this parameter. * * \return Always returns false, because this function is called as a * timeout and we don't want to run the timer again. * * \ingroup pings */ static gboolean meta_display_ping_timeout (gpointer data) { MetaPingData *ping_data; ping_data = data; ping_data->ping_timeout_id = 0; meta_topic (META_DEBUG_PING, "Ping %u on window %lx timed out\n", ping_data->timestamp, ping_data->xwindow); (* ping_data->ping_timeout_func) (ping_data->display, ping_data->xwindow, ping_data->timestamp, ping_data->user_data); ping_data->display->pending_pings = g_slist_remove (ping_data->display->pending_pings, ping_data); ping_data_free (ping_data); return FALSE; } /* * Sends a ping request to a window. The window must respond to * the request within a certain amount of time. If it does, we * will call one callback; if the time passes and we haven't had * a response, we call a different callback. The window must have * the hint showing that it can respond to a ping; if it doesn't, * we call the "got a response" callback immediately and return. * This function returns straight away after setting things up; * the callbacks will be called from the event loop. * * \param display The MetaDisplay that the window is on * \param window The MetaWindow to send the ping to * \param timestamp The timestamp of the ping. Used for uniqueness. * Cannot be CurrentTime; use a real timestamp! * \param ping_reply_func The callback to call if we get a response. * \param ping_timeout_func The callback to call if we don't get a response. * \param user_data Arbitrary data that will be passed to the callback * function. (In practice it's often a pointer to * the window.) * * \bug This should probably be a method on windows, rather than displays * for one of their windows. * * \ingroup pings */ LOCAL_SYMBOL void meta_display_ping_window (MetaDisplay *display, MetaWindow *window, guint32 timestamp, MetaWindowPingFunc ping_reply_func, MetaWindowPingFunc ping_timeout_func, gpointer user_data) { MetaPingData *ping_data; if (timestamp == CurrentTime) { meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n"); return; } if (!window->net_wm_ping) { if (ping_reply_func) (* ping_reply_func) (display, window->xwindow, timestamp, user_data); return; } ping_data = g_new (MetaPingData, 1); ping_data->display = display; ping_data->xwindow = window->xwindow; ping_data->timestamp = timestamp; ping_data->ping_reply_func = ping_reply_func; ping_data->ping_timeout_func = ping_timeout_func; ping_data->user_data = user_data; ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY, meta_display_ping_timeout, ping_data); display->pending_pings = g_slist_prepend (display->pending_pings, ping_data); meta_topic (META_DEBUG_PING, "Sending ping with timestamp %u to window %s\n", timestamp, window->desc); meta_window_send_icccm_message (window, display->atom__NET_WM_PING, timestamp); } static void process_request_frame_extents (MetaDisplay *display, XEvent *event) { /* The X window whose frame extents will be set. */ Window xwindow = event->xclient.window; unsigned long data[4] = { 0, 0, 0, 0 }; MotifWmHints *hints = NULL; gboolean hints_set = FALSE; meta_verbose ("Setting frame extents for 0x%lx\n", xwindow); /* See if the window is decorated. */ hints_set = meta_prop_get_motif_hints (display, xwindow, display->atom__MOTIF_WM_HINTS, &hints); if ((hints_set && hints->decorations) || !hints_set) { MetaFrameBorders borders; MetaScreen *screen; screen = meta_display_screen_for_xwindow (display, event->xclient.window); if (screen == NULL) { meta_warning ("Received request to set _NET_FRAME_EXTENTS " "on 0x%lx which is on a screen we are not managing\n", event->xclient.window); meta_XFree (hints); return; } /* Return estimated frame extents for a normal window. */ meta_ui_theme_get_frame_borders (screen->ui, META_FRAME_TYPE_NORMAL, 0, &borders); data[0] = borders.visible.left; data[1] = borders.visible.right; data[2] = borders.visible.top; data[3] = borders.visible.bottom; } meta_topic (META_DEBUG_GEOMETRY, "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx " "to top = %lu, left = %lu, bottom = %lu, right = %lu\n", xwindow, data[0], data[1], data[2], data[3]); meta_error_trap_push (display); XChangeProperty (display->xdisplay, xwindow, display->atom__NET_FRAME_EXTENTS, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 4); meta_error_trap_pop (display); meta_XFree (hints); } /* * Process the pong (the response message) from the ping we sent * to the window. This involves removing the timeout, calling the * reply handler function, and freeing memory. * * \param display the display we got the pong from * \param event the XEvent which is a pong; we can tell which * ping it corresponds to because it bears the * same timestamp. * * \ingroup pings */ static void process_pong_message (MetaDisplay *display, XEvent *event) { GSList *tmp; guint32 timestamp = event->xclient.data.l[1]; meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n", timestamp); for (tmp = display->pending_pings; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; if (timestamp == ping_data->timestamp) { meta_topic (META_DEBUG_PING, "Matching ping found for pong %u\n", ping_data->timestamp); /* Remove the ping data from the list */ display->pending_pings = g_slist_remove (display->pending_pings, ping_data); /* Remove the timeout */ if (ping_data->ping_timeout_id != 0) { g_source_remove (ping_data->ping_timeout_id); ping_data->ping_timeout_id = 0; } /* Call callback */ (* ping_data->ping_reply_func) (display, ping_data->xwindow, ping_data->timestamp, ping_data->user_data); ping_data_free (ping_data); break; } } } /* * Finds whether a window has any pings waiting on it. * * \param display The MetaDisplay of the window. * \param window The MetaWindow whose pings we want to know about. * * \return True if there is at least one ping which has been sent * to the window without getting a response; false otherwise. * * \bug This should probably be a method on windows, rather than displays * for one of their windows. * * \ingroup pings */ LOCAL_SYMBOL gboolean meta_display_window_has_pending_pings (MetaDisplay *display, MetaWindow *window) { GSList *tmp; for (tmp = display->pending_pings; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; if (ping_data->xwindow == window->xwindow) return TRUE; } return FALSE; } static MetaGroup* get_focussed_group (MetaDisplay *display) { if (display->focus_window) return display->focus_window->group; else return NULL; } #define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \ || ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \ || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display))) \ || ((t) == META_TAB_LIST_NORMAL_ALL && META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE (w))) static MetaWindow* find_tab_forward (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace, GList *start, gboolean skip_first) { GList *tmp; g_return_val_if_fail (start != NULL, NULL); g_return_val_if_fail (workspace != NULL, NULL); tmp = start; if (skip_first) tmp = tmp->next; while (tmp != NULL) { MetaWindow *window = tmp->data; if (window->screen == screen && IN_TAB_CHAIN (window, type)) return window; tmp = tmp->next; } tmp = workspace->mru_list; while (tmp != start) { MetaWindow *window = tmp->data; if (IN_TAB_CHAIN (window, type)) return window; tmp = tmp->next; } return NULL; } static MetaWindow* find_tab_backward (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace, GList *start, gboolean skip_last) { GList *tmp; g_return_val_if_fail (start != NULL, NULL); g_return_val_if_fail (workspace != NULL, NULL); tmp = start; if (skip_last) tmp = tmp->prev; while (tmp != NULL) { MetaWindow *window = tmp->data; if (window->screen == screen && IN_TAB_CHAIN (window, type)) return window; tmp = tmp->prev; } tmp = g_list_last (workspace->mru_list); while (tmp != start) { MetaWindow *window = tmp->data; if (IN_TAB_CHAIN (window, type)) return window; tmp = tmp->prev; } return NULL; } /** * meta_display_get_tab_list: * @display: a #MetaDisplay * @type: type of tab list * @screen: a #MetaScreen * @workspace: origin workspace * * Determine the list of windows that should be displayed for Alt-TAB * functionality. The windows are returned in most recently used order. * * Returns: (transfer container) (element-type Meta.Window): List of windows */ GList* meta_display_get_tab_list (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace) { GList *tab_list; g_return_val_if_fail (workspace != NULL, NULL); /* Windows sellout mode - MRU order. Collect unminimized windows * then minimized so minimized windows aren't in the way so much. */ { GList *tmp; tab_list = NULL; tmp = workspace->mru_list; while (tmp != NULL) { MetaWindow *window = tmp->data; if (!window->minimized && window->screen == screen && IN_TAB_CHAIN (window, type)) tab_list = g_list_prepend (tab_list, window); tmp = tmp->next; } } { GList *tmp; tmp = workspace->mru_list; while (tmp != NULL) { MetaWindow *window = tmp->data; if (window->minimized && window->screen == screen && IN_TAB_CHAIN (window, type)) tab_list = g_list_prepend (tab_list, window); tmp = tmp->next; } } tab_list = g_list_reverse (tab_list); { GSList *windows, *tmp; MetaWindow *l_window; windows = meta_display_list_windows (display, META_LIST_DEFAULT); /* Go through all windows */ tmp = windows; while (tmp != NULL) { l_window=tmp->data; /* Check to see if it demands attention */ if (l_window->wm_state_demands_attention && l_window->workspace!=workspace && IN_TAB_CHAIN (l_window, type)) { /* if it does, add it to the popup */ tab_list = g_list_prepend (tab_list, l_window); } tmp = tmp->next; } /* End while tmp!=NULL */ g_slist_free (windows); } return tab_list; } /** * meta_display_get_tab_next: * @display: a #MetaDisplay * @type: type of tab list * @screen: a #MetaScreen * @workspace: origin workspace * @window: (allow-none): starting window * @backward: If %TRUE, look for the previous window. * * Determine the next window that should be displayed for Alt-TAB * functionality. * * Returns: (transfer none): Next window * */ MetaWindow* meta_display_get_tab_next (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace, MetaWindow *window, gboolean backward) { gboolean skip; GList *tab_list; MetaWindow *ret; tab_list = meta_display_get_tab_list(display, type, screen, workspace); if (tab_list == NULL) return NULL; if (window != NULL) { g_assert (window->display == display); if (backward) ret = find_tab_backward (display, type, screen, workspace, g_list_find (tab_list, window), TRUE); else ret = find_tab_forward (display, type, screen, workspace, g_list_find (tab_list, window), TRUE); } else { skip = display->focus_window != NULL && tab_list->data == display->focus_window; if (backward) ret = find_tab_backward (display, type, screen, workspace, tab_list, skip); else ret = find_tab_forward (display, type, screen, workspace, tab_list, skip); } g_list_free (tab_list); return ret; } /** * meta_display_get_tab_current: * @display: a #MetaDisplay * @type: type of tab list * @screen: a #MetaScreen * @workspace: origin workspace * * Determine the active window that should be displayed for Alt-TAB. * * Returns: (transfer none): Current window * */ MetaWindow* meta_display_get_tab_current (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace) { MetaWindow *window; window = display->focus_window; if (window != NULL && window->screen == screen && IN_TAB_CHAIN (window, type) && (workspace == NULL || meta_window_located_on_workspace (window, workspace))) return window; else return NULL; } LOCAL_SYMBOL int meta_resize_gravity_from_grab_op (MetaGrabOp op) { int gravity; gravity = -1; switch (op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_SE: gravity = NorthWestGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_RESIZING_S: gravity = NorthGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_RESIZING_SW: gravity = NorthEastGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_RESIZING_N: gravity = SouthGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_RESIZING_NE: gravity = SouthWestGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_NW: case META_GRAB_OP_RESIZING_NW: gravity = SouthEastGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_RESIZING_E: gravity = WestGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_RESIZING_W: gravity = EastGravity; break; case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: gravity = CenterGravity; break; default: break; } return gravity; } LOCAL_SYMBOL int meta_resize_gravity_from_tile_mode (MetaTileMode mode) { int gravity; gravity = -1; switch (mode) { case META_TILE_LEFT: gravity = WestGravity; break; case META_TILE_RIGHT: gravity = EastGravity; break; case META_TILE_TOP: gravity = NorthGravity; break; case META_TILE_BOTTOM: gravity = SouthGravity; break; case META_TILE_ULC: gravity = NorthWestGravity; break; case META_TILE_LLC: gravity = SouthWestGravity; break; case META_TILE_URC: gravity = NorthEastGravity; break; case META_TILE_LRC: gravity = SouthEastGravity; break; case META_TILE_MAXIMIZE: gravity = CenterGravity; break; default: break; } return gravity; } static MetaScreen* find_screen_for_selection (MetaDisplay *display, Window owner, Atom selection) { GSList *tmp; tmp = display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; if (screen->wm_sn_selection_window == owner && screen->wm_sn_atom == selection) return screen; tmp = tmp->next; } return NULL; } /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ static gboolean convert_property (MetaDisplay *display, MetaScreen *screen, Window w, Atom target, Atom property) { #define N_TARGETS 4 Atom conversion_targets[N_TARGETS]; long icccm_version[] = { 2, 0 }; conversion_targets[0] = display->atom_TARGETS; conversion_targets[1] = display->atom_MULTIPLE; conversion_targets[2] = display->atom_TIMESTAMP; conversion_targets[3] = display->atom_VERSION; meta_error_trap_push_with_return (display); if (target == display->atom_TARGETS) XChangeProperty (display->xdisplay, w, property, XA_ATOM, 32, PropModeReplace, (unsigned char *)conversion_targets, N_TARGETS); else if (target == display->atom_TIMESTAMP) XChangeProperty (display->xdisplay, w, property, XA_INTEGER, 32, PropModeReplace, (unsigned char *)&screen->wm_sn_timestamp, 1); else if (target == display->atom_VERSION) XChangeProperty (display->xdisplay, w, property, XA_INTEGER, 32, PropModeReplace, (unsigned char *)icccm_version, 2); else { meta_error_trap_pop_with_return (display); return FALSE; } if (meta_error_trap_pop_with_return (display) != Success) return FALSE; /* Be sure the PropertyNotify has arrived so we * can send SelectionNotify */ /* FIXME the error trap pop synced anyway, right? */ meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC); XSync (display->xdisplay, False); return TRUE; } /* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ static void process_selection_request (MetaDisplay *display, XEvent *event) { XSelectionEvent reply; MetaScreen *screen; screen = find_screen_for_selection (display, event->xselectionrequest.owner, event->xselectionrequest.selection); if (screen == NULL) { char *str; meta_error_trap_push (display); str = XGetAtomName (display->xdisplay, event->xselectionrequest.selection); meta_error_trap_pop (display); meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n", str ? str : "(bad atom)", event->xselectionrequest.owner); meta_XFree (str); return; } reply.type = SelectionNotify; reply.display = display->xdisplay; reply.requestor = event->xselectionrequest.requestor; reply.selection = event->xselectionrequest.selection; reply.target = event->xselectionrequest.target; reply.property = None; reply.time = event->xselectionrequest.time; if (event->xselectionrequest.target == display->atom_MULTIPLE) { if (event->xselectionrequest.property != None) { Atom type, *adata; int i, format; unsigned long num, rest; unsigned char *data; meta_error_trap_push_with_return (display); if (XGetWindowProperty (display->xdisplay, event->xselectionrequest.requestor, event->xselectionrequest.property, 0, 256, False, display->atom_ATOM_PAIR, &type, &format, &num, &rest, &data) != Success) { meta_error_trap_pop_with_return (display); return; } if (meta_error_trap_pop_with_return (display) == Success) { /* FIXME: to be 100% correct, should deal with rest > 0, * but since we have 4 possible targets, we will hardly ever * meet multiple requests with a length > 8 */ adata = (Atom*)data; i = 0; while (i < (int) num) { if (!convert_property (display, screen, event->xselectionrequest.requestor, adata[i], adata[i+1])) adata[i+1] = None; i += 2; } meta_error_trap_push (display); XChangeProperty (display->xdisplay, event->xselectionrequest.requestor, event->xselectionrequest.property, display->atom_ATOM_PAIR, 32, PropModeReplace, data, num); meta_error_trap_pop (display); meta_XFree (data); } } } else { if (event->xselectionrequest.property == None) event->xselectionrequest.property = event->xselectionrequest.target; if (convert_property (display, screen, event->xselectionrequest.requestor, event->xselectionrequest.target, event->xselectionrequest.property)) reply.property = event->xselectionrequest.property; } XSendEvent (display->xdisplay, event->xselectionrequest.requestor, False, 0L, (XEvent*)&reply); meta_verbose ("Handled selection request\n"); } static void process_selection_clear (MetaDisplay *display, XEvent *event) { /* We need to unmanage the screen on which we lost the selection */ MetaScreen *screen; screen = find_screen_for_selection (display, event->xselectionclear.window, event->xselectionclear.selection); if (screen != NULL) { meta_verbose ("Got selection clear for screen %d on display %s\n", screen->number, display->name); meta_display_unmanage_screen (display, screen, event->xselectionclear.time); /* display and screen may both be invalid memory... */ return; } { char *str; meta_error_trap_push (display); str = XGetAtomName (display->xdisplay, event->xselectionclear.selection); meta_error_trap_pop (display); meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n", str ? str : "(bad atom)", event->xselectionclear.window); meta_XFree (str); } } void meta_display_unmanage_screen (MetaDisplay *display, MetaScreen *screen, guint32 timestamp) { meta_verbose ("Unmanaging screen %d on display %s\n", screen->number, display->name); g_return_if_fail (g_slist_find (display->screens, screen) != NULL); meta_screen_free (screen, timestamp); display->screens = g_slist_remove (display->screens, screen); if (display->screens == NULL) meta_display_close (display, timestamp); } LOCAL_SYMBOL void meta_display_unmanage_windows_for_screen (MetaDisplay *display, MetaScreen *screen, guint32 timestamp) { GSList *tmp; GSList *winlist; winlist = meta_display_list_windows (display, META_LIST_INCLUDE_OVERRIDE_REDIRECT); winlist = g_slist_sort (winlist, meta_display_stack_cmp); g_slist_foreach (winlist, (GFunc)g_object_ref, NULL); /* Unmanage all windows */ tmp = winlist; while (tmp != NULL) { MetaWindow *window = tmp->data; /* Check if already unmanaged for safety - in particular, catch * the case where unmanaging a parent window can cause attached * dialogs to be (temporarily) unmanaged. */ if (!window->unmanaging) meta_window_unmanage (window, timestamp); g_object_unref (window); tmp = tmp->next; } g_slist_free (winlist); } LOCAL_SYMBOL int meta_display_stack_cmp (const void *a, const void *b) { MetaWindow *aw = (void*) a; MetaWindow *bw = (void*) b; if (aw->screen == bw->screen) return meta_stack_windows_cmp (aw->screen->stack, aw, bw); /* Then assume screens are stacked by number */ else if (aw->screen->number < bw->screen->number) return -1; else if (aw->screen->number > bw->screen->number) return 1; else return 0; /* not reached in theory, if windows on same display */ } /** * meta_display_sort_windows_by_stacking: * @display: a #MetaDisplay * @windows: (element-type MetaWindow): Set of windows * * Sorts a set of windows according to their current stacking order. If windows * from multiple screens are present in the set of input windows, then all the * windows on screen 0 are sorted below all the windows on screen 1, and so forth. * Since the stacking order of override-redirect windows isn't controlled by * Metacity, if override-redirect windows are in the input, the result may not * correspond to the actual stacking order in the X server. * * An example of using this would be to sort the list of transient dialogs for a * window into their current stacking order. * * Returns: (transfer container) (element-type MetaWindow): Input windows sorted by stacking order, from lowest to highest */ GSList * meta_display_sort_windows_by_stacking (MetaDisplay *display, GSList *windows) { GSList *copy = g_slist_copy (windows); copy = g_slist_sort (copy, meta_display_stack_cmp); return copy; } LOCAL_SYMBOL void meta_display_devirtualize_modifiers (MetaDisplay *display, MetaVirtualModifier modifiers, unsigned int *mask) { *mask = 0; if (modifiers & META_VIRTUAL_SHIFT_MASK) *mask |= ShiftMask; if (modifiers & META_VIRTUAL_CONTROL_MASK) *mask |= ControlMask; if (modifiers & META_VIRTUAL_ALT_MASK) *mask |= Mod1Mask; if (modifiers & META_VIRTUAL_META_MASK) *mask |= display->meta_mask; if (modifiers & META_VIRTUAL_HYPER_MASK) *mask |= display->hyper_mask; if (modifiers & META_VIRTUAL_SUPER_MASK) *mask |= display->super_mask; if (modifiers & META_VIRTUAL_MOD2_MASK) *mask |= Mod2Mask; if (modifiers & META_VIRTUAL_MOD3_MASK) *mask |= Mod3Mask; if (modifiers & META_VIRTUAL_MOD4_MASK) *mask |= Mod4Mask; if (modifiers & META_VIRTUAL_MOD5_MASK) *mask |= Mod5Mask; } static void update_window_grab_modifiers (MetaDisplay *display) { MetaVirtualModifier virtual_mods; unsigned int mods; virtual_mods = meta_prefs_get_mouse_button_mods (); meta_display_devirtualize_modifiers (display, virtual_mods, &mods); display->window_grab_modifiers = mods; } static void update_mouse_zoom_modifiers (MetaDisplay *display) { MetaVirtualModifier virtual_mods; unsigned int mods; virtual_mods = meta_prefs_get_mouse_button_zoom_mods (); meta_display_devirtualize_modifiers (display, virtual_mods, &mods); display->mouse_zoom_modifiers = mods; } static void prefs_changed_callback (MetaPreference pref, void *data) { /* It may not be obvious why we regrab on focus mode * change; it's because we handle focus clicks a * bit differently for the different focus modes. */ if (pref == META_PREF_MOUSE_BUTTON_MODS || pref == META_PREF_FOCUS_MODE || pref == META_PREF_MOUSE_BUTTON_ZOOM_MODS || pref == META_PREF_MOUSE_ZOOM_ENABLED) { MetaDisplay *display = data; GSList *windows; GSList *tmp; windows = meta_display_list_windows (display, META_LIST_DEFAULT); /* Ungrab all */ tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; meta_display_ungrab_window_buttons (display, w->xwindow); if (w->frame) { meta_display_ungrab_window_buttons (display, w->frame->xwindow); } meta_display_ungrab_focus_window_button (display, w); tmp = tmp->next; } /* change our modifier */ if (pref == META_PREF_MOUSE_BUTTON_MODS) update_window_grab_modifiers (display); if (pref == META_PREF_MOUSE_BUTTON_ZOOM_MODS) update_mouse_zoom_modifiers (display); display->mouse_zoom_enabled = meta_prefs_get_mouse_zoom_enabled (); /* Grab all */ tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w->type != META_WINDOW_DOCK) { meta_display_grab_focus_window_button (display, w); meta_display_grab_window_buttons (display, w->xwindow); if (w->frame) { meta_display_grab_window_buttons (display, w->frame->xwindow); } } tmp = tmp->next; } g_slist_free (windows); } } LOCAL_SYMBOL void meta_display_increment_focus_sentinel (MetaDisplay *display) { unsigned long data[1]; data[0] = meta_display_get_current_time (display); XChangeProperty (display->xdisplay, ((MetaScreen*) display->screens->data)->xroot, display->atom__MUFFIN_SENTINEL, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); display->sentinel_counter += 1; } LOCAL_SYMBOL void meta_display_decrement_focus_sentinel (MetaDisplay *display) { display->sentinel_counter -= 1; if (display->sentinel_counter < 0) display->sentinel_counter = 0; } LOCAL_SYMBOL gboolean meta_display_focus_sentinel_clear (MetaDisplay *display) { return (display->sentinel_counter == 0); } static void sanity_check_timestamps (MetaDisplay *display, guint32 timestamp) { if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time)) { meta_warning ("last_focus_time (%u) is greater than comparison " "timestamp (%u). This most likely represents a buggy " "client sending inaccurate timestamps in messages such as " "_NET_ACTIVE_WINDOW. Trying to work around...\n", display->last_focus_time, timestamp); display->last_focus_time = timestamp; } if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_user_time)) { GSList *windows; GSList *tmp; meta_warning ("last_user_time (%u) is greater than comparison " "timestamp (%u). This most likely represents a buggy " "client sending inaccurate timestamps in messages such as " "_NET_ACTIVE_WINDOW. Trying to work around...\n", display->last_user_time, timestamp); display->last_user_time = timestamp; windows = meta_display_list_windows (display, META_LIST_DEFAULT); tmp = windows; while (tmp != NULL) { MetaWindow *window = tmp->data; if (XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time)) { meta_warning ("%s appears to be one of the offending windows " "with a timestamp of %u. Working around...\n", window->desc, window->net_wm_user_time); meta_window_set_user_time (window, timestamp); } tmp = tmp->next; } g_slist_free (windows); } } static gboolean timestamp_too_old (MetaDisplay *display, MetaWindow *window, guint32 *timestamp) { /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow * us to sanity check the timestamp here and ensure it doesn't correspond to * a future time (though we would want to rename to * timestamp_too_old_or_in_future). */ if (*timestamp == CurrentTime) { meta_warning ("Got a request to focus %s with a timestamp of 0. This " "shouldn't happen!\n", window ? window->desc : "the no_focus_window"); meta_print_backtrace (); *timestamp = meta_display_get_current_time_roundtrip (display); return FALSE; } else if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_focus_time)) { if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_user_time)) { meta_topic (META_DEBUG_FOCUS, "Ignoring focus request for %s since %u " "is less than %u and %u.\n", window ? window->desc : "the no_focus_window", *timestamp, display->last_user_time, display->last_focus_time); return TRUE; } else { meta_topic (META_DEBUG_FOCUS, "Received focus request for %s which is newer than most " "recent user_time, but less recent than " "last_focus_time (%u < %u < %u); adjusting " "accordingly. (See bug 167358)\n", window ? window->desc : "the no_focus_window", display->last_user_time, *timestamp, display->last_focus_time); *timestamp = display->last_focus_time; return FALSE; } } return FALSE; } void meta_display_set_input_focus_window (MetaDisplay *display, MetaWindow *window, gboolean focus_frame, guint32 timestamp) { if (timestamp_too_old (display, window, ×tamp)) return; meta_error_trap_push (display); XSetInputFocus (display->xdisplay, focus_frame ? window->frame->xwindow : window->xwindow, RevertToPointerRoot, timestamp); meta_error_trap_pop (display); display->expected_focus_window = window; display->last_focus_time = timestamp; display->active_screen = window->screen; if (window != display->autoraise_window) meta_display_remove_autoraise_callback (window->display); } void meta_display_focus_the_no_focus_window (MetaDisplay *display, MetaScreen *screen, guint32 timestamp) { if (timestamp_too_old (display, NULL, ×tamp)) return; XSetInputFocus (display->xdisplay, screen->no_focus_window, RevertToPointerRoot, timestamp); display->expected_focus_window = NULL; display->last_focus_time = timestamp; display->active_screen = screen; meta_display_remove_autoraise_callback (display); } LOCAL_SYMBOL void meta_display_remove_autoraise_callback (MetaDisplay *display) { if (display->autoraise_timeout_id != 0) { g_source_remove (display->autoraise_timeout_id); display->autoraise_timeout_id = 0; display->autoraise_window = NULL; } } void meta_display_get_compositor_version (MetaDisplay *display, int *major, int *minor) { *major = display->composite_major_version; *minor = display->composite_minor_version; } /** * meta_display_get_xdisplay: (skip) * */ Display * meta_display_get_xdisplay (MetaDisplay *display) { return display->xdisplay; } /** * meta_display_get_compositor: (skip) * */ MetaCompositor * meta_display_get_compositor (MetaDisplay *display) { return display->compositor; } /** * meta_display_get_screens: * @display: a #MetaDisplay * * Returns: (transfer none) (element-type Meta.Screen): Screens for this display */ GSList * meta_display_get_screens (MetaDisplay *display) { return display->screens; } gboolean meta_display_has_shape (MetaDisplay *display) { return META_DISPLAY_HAS_SHAPE (display); } /** * meta_display_get_focus_window: * @display: a #MetaDisplay * * Get the window that, according to events received from X server, * currently has the input focus. We may have already sent a request * to the X server to move the focus window elsewhere. (The * expected_focus_window records where we've last set the input * focus.) * * Return Value: (transfer none): The current focus window */ MetaWindow * meta_display_get_focus_window (MetaDisplay *display) { return display->focus_window; } int meta_display_get_damage_event_base (MetaDisplay *display) { return display->damage_event_base; } #ifdef HAVE_SHAPE int meta_display_get_shape_event_base (MetaDisplay *display) { return display->shape_event_base; } #endif /** * meta_display_get_leader_window: * @display: a #MetaDisplay * * Returns the window manager's leader window (as defined by the * _NET_SUPPORTING_WM_CHECK mechanism of EWMH). For use by plugins that wish * to attach additional custom properties to this window. * * Return value: xid of the leader window. **/ Window meta_display_get_leader_window (MetaDisplay *display) { return display->leader_window; } static gboolean meta_display_restart_internal (MetaDisplay *display) { GPtrArray *arr; gsize len; char *buf; char *buf_p; char *buf_end; GError *error = NULL; if (!g_file_get_contents ("/proc/self/cmdline", &buf, &len, &error)) { g_warning ("Failed to get /proc/self/cmdline: %s", error->message); return FALSE; } buf_end = buf+len; arr = g_ptr_array_new (); /* The cmdline file is NUL-separated */ for (buf_p = buf; buf_p < buf_end; buf_p = buf_p + strlen (buf_p) + 1) g_ptr_array_add (arr, buf_p); g_ptr_array_add (arr, NULL); /* Close all file descriptors other than stdin/stdout/stderr, otherwise * they will leak and stay open after the exec. In particular, this is * important for file descriptors that represent mapped graphics buffer * objects. */ meta_pre_exec_close_fds (); meta_display_unmanage_screen (display, (MetaScreen*) display->screens->data, meta_display_get_current_time (display)); execvp (arr->pdata[0], (char**)arr->pdata); g_warning ("Failed to reexec: %s", g_strerror (errno)); g_ptr_array_free (arr, TRUE); free (buf); return FALSE; } LOCAL_SYMBOL void meta_display_notify_restart (MetaDisplay *display) { g_signal_emit (display, display_signals[RESTART], 0); } /** * meta_display_restart: * @display: a #MetaDisplay * * Restart the current process. Only intended for development purposes. */ void meta_display_restart (MetaDisplay *display) { g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) meta_display_restart_internal, display, NULL); } void meta_display_update_sync_state (MetaSyncMethod method) { meta_compositor_update_sync_state (the_display->compositor, method); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/keybindings.c�����������������������������������������������������������������0000664�0001750�0001750�00000361742�14211404421�017342� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin Keybindings */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002 Red Hat Inc. * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:keybindings * @title: MetaKeybinding * @short_description: Key bindings */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _SVID_SOURCE /* for putenv() */ #include <config.h> #include "keybindings-private.h" #include "workspace-private.h" #include <meta/errors.h> #include "window-private.h" #include "edge-resistance.h" #include "ui.h" #include "frame.h" #include "place.h" #include <meta/prefs.h> #include "util-private.h" #include <X11/keysym.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #ifdef HAVE_XKB #include <X11/XKBlib.h> #endif #if __GNUC__ >= 7 #define DISABLE_GCC7_FALL_THRU_WARNING __attribute__ ((fallthrough)) #else #define DISABLE_GCC7_FALL_THRU_WARNING "" #endif #define SCHEMA_MUFFIN_KEYBINDINGS "org.cinnamon.desktop.keybindings.wm" #define SCHEMA_MUFFIN "org.cinnamon.muffin" static gboolean all_bindings_disabled = FALSE; static gboolean modifier_only_is_down = FALSE; static gboolean add_builtin_keybinding (MetaDisplay *display, const char *name, const char *schema, MetaKeyBindingFlags flags, MetaKeyBindingAction action, MetaKeyHandlerFunc handler, int handler_arg); static void invoke_handler_by_name (MetaDisplay *display, MetaScreen *screen, const char *handler_name, MetaWindow *window, XEvent *event); enum { META_MOVE_TO_XCHANGE_FLAG = 8, // 1000 META_MOVE_TO_YCHANGE_FLAG = 4, // 0100 META_MOVE_TO_RIGHT_FLAG = 2, // 0010 META_MOVE_TO_BOTTOM_FLAG = 1 // 0001 }; // Using flags above enum { META_MOVE_TO_SE = 15, // 1111 META_MOVE_TO_NE = 14, // 1110 META_MOVE_TO_SW = 13, // 1101 META_MOVE_TO_NW = 12, // 1100 META_MOVE_TO_E = 10, // 1010 META_MOVE_TO_W = 8, // 1000 META_MOVE_TO_S = 5, // 0101 META_MOVE_TO_N = 4 // 0100 }; static void meta_key_binding_free (MetaKeyBinding *binding) { g_slice_free (MetaKeyBinding, binding); } static MetaKeyBinding * meta_key_binding_copy (MetaKeyBinding *binding) { return g_slice_dup (MetaKeyBinding, binding); } GType meta_key_binding_get_type (void) { static GType type_id = 0; if (G_UNLIKELY (type_id == 0)) type_id = g_boxed_type_register_static (g_intern_static_string ("MetaKeyBinding"), (GBoxedCopyFunc)meta_key_binding_copy, (GBoxedFreeFunc)meta_key_binding_free); return type_id; } const char * meta_key_binding_get_name (MetaKeyBinding *binding) { return binding->name; } MetaVirtualModifier meta_key_binding_get_modifiers (MetaKeyBinding *binding) { return binding->modifiers; } guint meta_key_binding_get_mask (MetaKeyBinding *binding) { return binding->mask; } /* These can't be bound to anything, but they are used to handle * various other events. TODO: Possibly we should include them as event * handler functions and have some kind of flag to say they're unbindable. */ static gboolean process_mouse_move_resize_grab (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym); static gboolean process_keyboard_move_grab (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym); static gboolean process_keyboard_resize_grab (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym); static void regrab_key_bindings (MetaDisplay *display); static GHashTable *key_handlers; #define HANDLER(name) g_hash_table_lookup (key_handlers, (name)) static void key_handler_free (MetaKeyHandler *handler) { free (handler->name); if (handler->user_data_free_func && handler->user_data) handler->user_data_free_func (handler->user_data); free (handler); } static void reload_keymap (MetaDisplay *display) { if (display->keymap) meta_XFree (display->keymap); /* This is expensive to compute, so we'll lazily load if and when we first * need it */ display->above_tab_keycode = 0; display->keymap = XGetKeyboardMapping (display->xdisplay, display->min_keycode, display->max_keycode - display->min_keycode + 1, &display->keysyms_per_keycode); } static void reload_modmap (MetaDisplay *display) { XModifierKeymap *modmap; int map_size; int i; if (display->modmap) XFreeModifiermap (display->modmap); modmap = XGetModifierMapping (display->xdisplay); display->modmap = modmap; display->ignored_modifier_mask = 0; /* Multiple bits may get set in each of these */ display->num_lock_mask = 0; display->scroll_lock_mask = 0; display->meta_mask = 0; display->hyper_mask = 0; display->super_mask = 0; /* there are 8 modifiers, and the first 3 are shift, shift lock, * and control */ map_size = 8 * modmap->max_keypermod; i = 3 * modmap->max_keypermod; while (i < map_size) { /* get the key code at this point in the map, * see if its keysym is one we're interested in */ int keycode = modmap->modifiermap[i]; if (keycode >= display->min_keycode && keycode <= display->max_keycode) { int j = 0; KeySym *syms = display->keymap + (keycode - display->min_keycode) * display->keysyms_per_keycode; while (j < display->keysyms_per_keycode) { if (syms[j] != 0) { const char *str; str = XKeysymToString (syms[j]); meta_topic (META_DEBUG_KEYBINDINGS, "Keysym %s bound to modifier 0x%x\n", str ? str : "none", (1 << ( i / modmap->max_keypermod))); } if (syms[j] == XK_Num_Lock) { /* Mod1Mask is 1 << 3 for example, i.e. the * fourth modifier, i / keyspermod is the modifier * index */ display->num_lock_mask |= (1 << ( i / modmap->max_keypermod)); } else if (syms[j] == XK_Scroll_Lock) { display->scroll_lock_mask |= (1 << ( i / modmap->max_keypermod)); } else if (syms[j] == XK_Super_L || syms[j] == XK_Super_R) { display->super_mask |= (1 << ( i / modmap->max_keypermod)); } else if (syms[j] == XK_Hyper_L || syms[j] == XK_Hyper_R) { display->hyper_mask |= (1 << ( i / modmap->max_keypermod)); } else if (syms[j] == XK_Meta_L || syms[j] == XK_Meta_R) { display->meta_mask |= (1 << ( i / modmap->max_keypermod)); } ++j; } } ++i; } display->ignored_modifier_mask = (display->num_lock_mask | display->scroll_lock_mask | LockMask); meta_topic (META_DEBUG_KEYBINDINGS, "Ignoring modmask 0x%x num lock 0x%x scroll lock 0x%x hyper 0x%x super 0x%x meta 0x%x\n", display->ignored_modifier_mask, display->num_lock_mask, display->scroll_lock_mask, display->hyper_mask, display->super_mask, display->meta_mask); } static guint keysym_to_keycode (MetaDisplay *display, guint keysym) { if (keysym == META_KEY_ABOVE_TAB) return meta_display_get_above_tab_keycode (display); else return XKeysymToKeycode (display->xdisplay, keysym); } static void reload_keycodes (MetaDisplay *display) { meta_topic (META_DEBUG_KEYBINDINGS, "Reloading keycodes for binding tables\n"); if (display->key_bindings) { int i; i = 0; while (i < display->n_key_bindings) { if (display->key_bindings[i].keysym != 0) { display->key_bindings[i].keycode = keysym_to_keycode (display, display->key_bindings[i].keysym); } ++i; } } } static void reload_modifiers (MetaDisplay *display) { meta_topic (META_DEBUG_KEYBINDINGS, "Reloading keycodes for binding tables\n"); if (display->key_bindings) { int i; i = 0; while (i < display->n_key_bindings) { meta_display_devirtualize_modifiers (display, display->key_bindings[i].modifiers, &display->key_bindings[i].mask); meta_topic (META_DEBUG_KEYBINDINGS, " Devirtualized mods 0x%x -> 0x%x (%s)\n", display->key_bindings[i].modifiers, display->key_bindings[i].mask, display->key_bindings[i].name); ++i; } } } static int count_bindings (GList *prefs) { GList *p; int count; count = 0; p = prefs; while (p) { MetaKeyPref *pref = (MetaKeyPref*)p->data; GSList *tmp = pref->bindings; while (tmp) { MetaKeyCombo *combo = tmp->data; if (combo && (combo->keysym != None || combo->keycode != 0)) { count += 1; if (pref->add_shift && (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0) count += 1; } tmp = tmp->next; } p = p->next; } return count; } static void rebuild_binding_table (MetaDisplay *display, MetaKeyBinding **bindings_p, int *n_bindings_p, GList *prefs) { GList *p; int n_bindings; int i; n_bindings = count_bindings (prefs); free (*bindings_p); *bindings_p = g_new0 (MetaKeyBinding, n_bindings); i = 0; p = prefs; while (p) { MetaKeyPref *pref = (MetaKeyPref*)p->data; GSList *tmp = pref->bindings; while (tmp) { MetaKeyCombo *combo = tmp->data; if (combo && (combo->keysym != None || combo->keycode != 0)) { MetaKeyHandler *handler = HANDLER (pref->name); (*bindings_p)[i].name = pref->name; (*bindings_p)[i].handler = handler; (*bindings_p)[i].keysym = combo->keysym; (*bindings_p)[i].keycode = combo->keycode; (*bindings_p)[i].modifiers = combo->modifiers; (*bindings_p)[i].mask = 0; ++i; if (pref->add_shift && (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0) { meta_topic (META_DEBUG_KEYBINDINGS, "Binding %s also needs Shift grabbed\n", pref->name); (*bindings_p)[i].name = pref->name; (*bindings_p)[i].handler = handler; (*bindings_p)[i].keysym = combo->keysym; (*bindings_p)[i].keycode = combo->keycode; (*bindings_p)[i].modifiers = combo->modifiers | META_VIRTUAL_SHIFT_MASK; (*bindings_p)[i].mask = 0; ++i; } } tmp = tmp->next; } p = p->next; } g_assert (i == n_bindings); *n_bindings_p = i; meta_topic (META_DEBUG_KEYBINDINGS, " %d bindings in table\n", *n_bindings_p); } static void rebuild_key_binding_table (MetaDisplay *display) { GList *prefs; meta_topic (META_DEBUG_KEYBINDINGS, "Rebuilding key binding table from preferences\n"); prefs = meta_prefs_get_keybindings (); rebuild_binding_table (display, &display->key_bindings, &display->n_key_bindings, prefs); g_list_free (prefs); } static void regrab_key_bindings (MetaDisplay *display) { GSList *tmp; GSList *windows; meta_error_trap_push (display); /* for efficiency push outer trap */ tmp = display->screens; while (tmp != NULL) { MetaScreen *screen = tmp->data; meta_screen_ungrab_keys (screen); meta_screen_grab_keys (screen); tmp = tmp->next; } windows = meta_display_list_windows (display, META_LIST_DEFAULT); tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; meta_window_ungrab_keys (w); meta_window_grab_keys (w); tmp = tmp->next; } meta_error_trap_pop (display); g_slist_free (windows); } static MetaKeyBinding * display_get_keybinding (MetaDisplay *display, unsigned int keysym, unsigned int keycode, unsigned long mask) { int i; i = display->n_key_bindings - 1; while (i >= 0) { if (display->key_bindings[i].keysym == keysym && display->key_bindings[i].keycode == keycode && display->key_bindings[i].mask == mask) { return &display->key_bindings[i]; } --i; } return NULL; } static gboolean add_keybinding_internal (MetaDisplay *display, const char *name, const char *schema, MetaKeyBindingFlags flags, MetaKeyBindingAction action, MetaKeyHandlerFunc func, int data, gpointer user_data, GDestroyNotify free_data) { MetaKeyHandler *handler; if (!meta_prefs_add_keybinding (name, schema, action, flags)) return FALSE; handler = g_new0 (MetaKeyHandler, 1); handler->name = g_strdup (name); handler->func = func; handler->default_func = func; handler->data = data; handler->flags = flags; handler->action = action; handler->user_data = user_data; handler->user_data_free_func = free_data; g_hash_table_insert (key_handlers, g_strdup (name), handler); return TRUE; } static gboolean add_builtin_keybinding (MetaDisplay *display, const char *name, const char *schema, MetaKeyBindingFlags flags, MetaKeyBindingAction action, MetaKeyHandlerFunc handler, int handler_arg) { return add_keybinding_internal (display, name, schema, flags | META_KEY_BINDING_BUILTIN, action, handler, handler_arg, NULL, NULL); } /** * meta_display_add_keybinding: * @display: a #MetaDisplay * @name: the binding's name * @schema: the #GSettings schema where @name is stored * @flags: flags to specify binding details * @handler: function to run when the keybinding is invoked * @user_data: the data to pass to @handler * @free_data: function to free @user_data * * Add a keybinding at runtime. The key @name in @schema needs to be of type * %G_VARIANT_TYPE_STRING_ARRAY, with each string describing a keybinding in * the form of "<Control>a" or "<Shift><Alt>F1". The parser * is fairly liberal and allows lower or upper case, and also abbreviations * such as "<Ctl>" and "<Ctrl>". If the key is set to the empty * list or a list with a single element of either "" or "disabled", the * keybinding is disabled. If %META_KEY_BINDING_REVERSES is specified in * @flags, the binding may be reversed by holding down the "shift" key; * therefore, "<Shift>" * cannot be one of the keys used. @handler is expected to check for the * "shift" modifier in this case and reverse its action. * * Use meta_display_remove_keybinding() to remove the binding. * * Returns: %TRUE if the keybinding was added successfully, * otherwise %FALSE */ gboolean meta_display_add_keybinding (MetaDisplay *display, const char *name, const char *schema, MetaKeyBindingFlags flags, MetaKeyHandlerFunc handler, gpointer user_data, GDestroyNotify free_data) { return add_keybinding_internal (display, name, schema, flags, META_KEYBINDING_ACTION_NONE, handler, 0, user_data, free_data); } /** * meta_display_remove_keybinding: * @display: the #MetaDisplay * @name: name of the keybinding to remove * * Remove keybinding @name; the function will fail if @name is not a known * keybinding or has not been added with meta_display_add_keybinding(). * * Returns: %TRUE if the binding has been removed sucessfully, * otherwise %FALSE */ gboolean meta_display_remove_keybinding (MetaDisplay *display, const char *name) { if (!meta_prefs_remove_keybinding (name)) return FALSE; g_hash_table_remove (key_handlers, name); return TRUE; } static gboolean add_custom_keybinding_internal (MetaDisplay *display, const char *name, const char **bindings, MetaKeyBindingFlags flags, MetaKeyBindingAction action, MetaKeyHandlerFunc func, int data, gpointer user_data, GDestroyNotify free_data) { MetaKeyHandler *handler; if (!meta_prefs_add_custom_keybinding (name, bindings, action, flags)) return FALSE; handler = g_new0 (MetaKeyHandler, 1); handler->name = g_strdup (name); handler->func = func; handler->default_func = func; handler->data = data; handler->flags = flags; handler->action = action; handler->user_data = user_data; handler->user_data_free_func = free_data; g_hash_table_insert (key_handlers, g_strdup (name), handler); return TRUE; } /** * meta_display_add_custom_keybinding: * @display: a #MetaDisplay * @name: the binding's unique name * @bindings: (allow-none) (array zero-terminated=1): array of parseable keystrokes * @callback: function to run when the keybinding is invoked * @user_data: the data to pass to @handler * @free_data: function to free @user_data * * * Use meta_display_remove_custom_keybinding() to remove the binding. * * Returns: %TRUE if the keybinding was added successfully, * otherwise %FALSE */ gboolean meta_display_add_custom_keybinding (MetaDisplay *display, const char *name, const char **bindings, MetaKeyHandlerFunc callback, gpointer user_data, GDestroyNotify free_data) { return add_custom_keybinding_internal (display, name, bindings, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_CUSTOM, (MetaKeyHandlerFunc)callback, 0, user_data, free_data); } /** * meta_display_remove_custom_keybinding: * @display: the #MetaDisplay * @name: name of the keybinding to remove * * Remove keybinding @name; the function will fail if @name is not a known * keybinding or has not been added with meta_display_add_custom_keybinding(). * * Returns: %TRUE if the binding has been removed sucessfully, * otherwise %FALSE */ gboolean meta_display_remove_custom_keybinding (MetaDisplay *display, const char *name) { if (!meta_prefs_remove_custom_keybinding (name)) return FALSE; g_hash_table_remove (key_handlers, name); return TRUE; } /** * meta_display_get_keybinding_action: * @display: A #MetaDisplay * @keycode: Raw keycode * @mask: Event mask * * Get the #MetaKeyBindingAction bound to %keycode. Only builtin * keybindings have an associated #MetaKeyBindingAction, for * bindings added dynamically with meta_display_add_keybinding() * the function will always return %META_KEYBINDING_ACTION_NONE. * * Returns: The action that should be taken for the given key, or * %META_KEYBINDING_ACTION_NONE. */ MetaKeyBindingAction meta_display_get_keybinding_action (MetaDisplay *display, unsigned int keycode, unsigned long mask) { MetaKeyBinding *binding; KeySym keysym; keysym = XkbKeycodeToKeysym (display->xdisplay, keycode, 0, 0); mask = mask & 0xff & ~display->ignored_modifier_mask; binding = display_get_keybinding (display, keysym, keycode, mask); if (!binding && keycode == meta_display_get_above_tab_keycode (display)) binding = display_get_keybinding (display, META_KEY_ABOVE_TAB, keycode, mask); if (binding) return meta_prefs_get_keybinding_action (binding->name); else return META_KEYBINDING_ACTION_NONE; } void meta_display_keybinding_action_invoke_by_code (MetaDisplay *display, unsigned int keycode, unsigned long mask) { MetaKeyBinding *binding; KeySym keysym; keysym = XkbKeycodeToKeysym (display->xdisplay, keycode, 0, 0); mask = mask & 0xff & ~display->ignored_modifier_mask; binding = display_get_keybinding (display, keysym, keycode, mask); if (!binding && keycode == meta_display_get_above_tab_keycode (display)) binding = display_get_keybinding (display, META_KEY_ABOVE_TAB, keycode, mask); if (binding) invoke_handler_by_name (display, NULL, binding->name, NULL, NULL); } LOCAL_SYMBOL void meta_display_process_mapping_event (MetaDisplay *display, XEvent *event) { gboolean keymap_changed = FALSE; gboolean modmap_changed = FALSE; #ifdef HAVE_XKB if (event->type == display->xkb_base_event_type) { meta_topic (META_DEBUG_KEYBINDINGS, "XKB mapping changed, will redo keybindings\n"); keymap_changed = TRUE; modmap_changed = TRUE; } else #endif if (event->xmapping.request == MappingModifier) { meta_topic (META_DEBUG_KEYBINDINGS, "Received MappingModifier event, will reload modmap and redo keybindings\n"); modmap_changed = TRUE; } else if (event->xmapping.request == MappingKeyboard) { meta_topic (META_DEBUG_KEYBINDINGS, "Received MappingKeyboard event, will reload keycodes and redo keybindings\n"); keymap_changed = TRUE; } /* Now to do the work itself */ if (keymap_changed || modmap_changed) { if (keymap_changed) reload_keymap (display); /* Deciphering the modmap depends on the loaded keysyms to find out * what modifiers is Super and so forth, so we need to reload it * even when only the keymap changes */ reload_modmap (display); if (keymap_changed) reload_keycodes (display); reload_modifiers (display); regrab_key_bindings (display); } } static gboolean rebuild_keybindings_at_idle (MetaDisplay *display) { display->rebuild_keybinding_idle_id = 0; rebuild_key_binding_table (display); reload_keycodes (display); reload_modifiers (display); regrab_key_bindings (display); return FALSE; } static void queue_rebuild_keybindings (MetaDisplay *display) { if (display->rebuild_keybinding_idle_id > 0) { g_source_remove (display->rebuild_keybinding_idle_id); display->rebuild_keybinding_idle_id = 0; } display->rebuild_keybinding_idle_id = g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) rebuild_keybindings_at_idle, display, NULL); } static void bindings_changed_callback (MetaPreference pref, void *data) { MetaDisplay *display; display = data; switch (pref) { case META_PREF_KEYBINDINGS: queue_rebuild_keybindings (display); break; default: break; } } /** * meta_display_rebuild_keybindings: * @display: the #MetaDisplay * * Rebuild all keybindings (typically done after adding, removing, or changing * one or more keybindings) * */ void meta_display_rebuild_keybindings (MetaDisplay *display) { queue_rebuild_keybindings (display); } LOCAL_SYMBOL void meta_display_shutdown_keys (MetaDisplay *display) { /* Note that display->xdisplay is invalid in this function */ meta_prefs_remove_listener (bindings_changed_callback, display); if (display->keymap) meta_XFree (display->keymap); if (display->modmap) XFreeModifiermap (display->modmap); free (display->key_bindings); } static const char* keysym_name (int keysym) { const char *name; name = XKeysymToString (keysym); if (name == NULL) name = "(unknown)"; return name; } /* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */ static void meta_change_keygrab (MetaDisplay *display, Window xwindow, gboolean grab, int keysym, unsigned int keycode, int modmask) { unsigned int ignored_mask; /* Grab keycode/modmask, together with * all combinations of ignored modifiers. * X provides no better way to do this. */ meta_topic (META_DEBUG_KEYBINDINGS, "%s keybinding %s keycode %d mask 0x%x on 0x%lx\n", grab ? "Grabbing" : "Ungrabbing", keysym_name (keysym), keycode, modmask, xwindow); /* efficiency, avoid so many XSync() */ meta_error_trap_push (display); ignored_mask = 0; while (ignored_mask <= display->ignored_modifier_mask) { if (ignored_mask & ~(display->ignored_modifier_mask)) { /* Not a combination of ignored modifiers * (it contains some non-ignored modifiers) */ ++ignored_mask; continue; } if (meta_is_debugging ()) meta_error_trap_push_with_return (display); if (grab) XGrabKey (display->xdisplay, keycode, modmask | ignored_mask, xwindow, True, GrabModeAsync, GrabModeSync); else XUngrabKey (display->xdisplay, keycode, modmask | ignored_mask, xwindow); if (meta_is_debugging ()) { int result; result = meta_error_trap_pop_with_return (display); if (grab && result != Success) { if (result == BadAccess) meta_warning ("Some other program is already using the key %s with modifiers %x as a binding\n", keysym_name (keysym), modmask | ignored_mask); #ifdef WITH_VERBOSE_MODE else meta_topic (META_DEBUG_KEYBINDINGS, "Failed to grab key %s with modifiers %x\n", keysym_name (keysym), modmask | ignored_mask); #endif } } ++ignored_mask; } meta_error_trap_pop (display); } static void meta_grab_key (MetaDisplay *display, Window xwindow, int keysym, unsigned int keycode, int modmask) { meta_change_keygrab (display, xwindow, TRUE, keysym, keycode, modmask); } static void grab_keys (MetaKeyBinding *bindings, int n_bindings, MetaDisplay *display, Window xwindow, gboolean binding_per_window) { int i; g_assert (n_bindings == 0 || bindings != NULL); meta_error_trap_push (display); i = 0; while (i < n_bindings) { if (!!binding_per_window == !!(bindings[i].handler->flags & META_KEY_BINDING_PER_WINDOW) && bindings[i].keycode != 0) { meta_grab_key (display, xwindow, bindings[i].keysym, bindings[i].keycode, bindings[i].mask); } ++i; } meta_error_trap_pop (display); } static void ungrab_all_keys (MetaDisplay *display, Window xwindow) { if (meta_is_debugging ()) meta_error_trap_push_with_return (display); else meta_error_trap_push (display); XUngrabKey (display->xdisplay, AnyKey, AnyModifier, xwindow); if (meta_is_debugging ()) { int result; result = meta_error_trap_pop_with_return (display); #ifdef WITH_VERBOSE_MODE if (result != Success) meta_topic (META_DEBUG_KEYBINDINGS, "Ungrabbing all keys on 0x%lx failed\n", xwindow); #endif } else meta_error_trap_pop (display); } LOCAL_SYMBOL void meta_screen_grab_keys (MetaScreen *screen) { if (screen->all_keys_grabbed) return; if (screen->keys_grabbed) return; grab_keys (screen->display->key_bindings, screen->display->n_key_bindings, screen->display, screen->xroot, FALSE); screen->keys_grabbed = TRUE; } LOCAL_SYMBOL void meta_screen_ungrab_keys (MetaScreen *screen) { if (screen->keys_grabbed) { ungrab_all_keys (screen->display, screen->xroot); screen->keys_grabbed = FALSE; } } LOCAL_SYMBOL void meta_window_grab_keys (MetaWindow *window) { if (window->all_keys_grabbed) return; if (window->type == META_WINDOW_DOCK || window->override_redirect) { if (window->keys_grabbed) ungrab_all_keys (window->display, window->xwindow); window->keys_grabbed = FALSE; return; } if (window->keys_grabbed) { if (window->frame && !window->grab_on_frame) ungrab_all_keys (window->display, window->xwindow); else if (window->frame == NULL && window->grab_on_frame) ; /* continue to regrab on client window */ else return; /* already all good */ } grab_keys (window->display->key_bindings, window->display->n_key_bindings, window->display, window->frame ? window->frame->xwindow : window->xwindow, TRUE); window->keys_grabbed = TRUE; window->grab_on_frame = window->frame != NULL; } LOCAL_SYMBOL void meta_window_ungrab_keys (MetaWindow *window) { if (window->keys_grabbed) { if (window->grab_on_frame && window->frame != NULL) ungrab_all_keys (window->display, window->frame->xwindow); else if (!window->grab_on_frame) ungrab_all_keys (window->display, window->xwindow); window->keys_grabbed = FALSE; } } #ifdef WITH_VERBOSE_MODE static const char* grab_status_to_string (int status) { switch (status) { case AlreadyGrabbed: return "AlreadyGrabbed"; case GrabSuccess: return "GrabSuccess"; case GrabNotViewable: return "GrabNotViewable"; case GrabFrozen: return "GrabFrozen"; case GrabInvalidTime: return "GrabInvalidTime"; default: return "(unknown)"; } } #endif /* WITH_VERBOSE_MODE */ static gboolean grab_keyboard (MetaDisplay *display, Window xwindow, guint32 timestamp) { int result; int grab_status; /* Grab the keyboard, so we get key releases and all key * presses */ meta_error_trap_push_with_return (display); grab_status = XGrabKeyboard (display->xdisplay, xwindow, True, GrabModeAsync, GrabModeAsync, timestamp); if (grab_status != GrabSuccess) { meta_error_trap_pop_with_return (display); meta_topic (META_DEBUG_KEYBINDINGS, "XGrabKeyboard() returned failure status %s time %u\n", grab_status_to_string (grab_status), timestamp); return FALSE; } else { result = meta_error_trap_pop_with_return (display); if (result != Success) { meta_topic (META_DEBUG_KEYBINDINGS, "XGrabKeyboard() resulted in an error\n"); return FALSE; } } meta_topic (META_DEBUG_KEYBINDINGS, "Grabbed all keys\n"); return TRUE; } static void ungrab_keyboard (MetaDisplay *display, guint32 timestamp) { meta_error_trap_push (display); meta_topic (META_DEBUG_KEYBINDINGS, "Ungrabbing keyboard with timestamp %u\n", timestamp); XUngrabKeyboard (display->xdisplay, timestamp); meta_error_trap_pop (display); } gboolean meta_screen_grab_all_keys (MetaScreen *screen, guint32 timestamp) { gboolean retval; if (screen->all_keys_grabbed) return FALSE; if (screen->keys_grabbed) meta_screen_ungrab_keys (screen); meta_topic (META_DEBUG_KEYBINDINGS, "Grabbing all keys on RootWindow\n"); retval = grab_keyboard (screen->display, screen->xroot, timestamp); if (retval) { screen->all_keys_grabbed = TRUE; g_object_notify (G_OBJECT (screen), "keyboard-grabbed"); } else meta_screen_grab_keys (screen); return retval; } void meta_screen_ungrab_all_keys (MetaScreen *screen, guint32 timestamp) { if (screen->all_keys_grabbed) { ungrab_keyboard (screen->display, timestamp); screen->all_keys_grabbed = FALSE; screen->keys_grabbed = FALSE; /* Re-establish our standard bindings */ meta_screen_grab_keys (screen); g_object_notify (G_OBJECT (screen), "keyboard-grabbed"); } } LOCAL_SYMBOL gboolean meta_window_grab_all_keys (MetaWindow *window, guint32 timestamp) { Window grabwindow; gboolean retval; if (window->all_keys_grabbed) return FALSE; if (window->keys_grabbed) meta_window_ungrab_keys (window); /* Make sure the window is focused, otherwise the grab * won't do a lot of good. */ meta_topic (META_DEBUG_FOCUS, "Focusing %s because we're grabbing all its keys\n", window->desc); meta_window_focus (window, timestamp); grabwindow = window->frame ? window->frame->xwindow : window->xwindow; meta_topic (META_DEBUG_KEYBINDINGS, "Grabbing all keys on window %s\n", window->desc); retval = grab_keyboard (window->display, grabwindow, timestamp); if (retval) { window->keys_grabbed = FALSE; window->all_keys_grabbed = TRUE; window->grab_on_frame = window->frame != NULL; } return retval; } LOCAL_SYMBOL void meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp) { if (window->all_keys_grabbed) { ungrab_keyboard (window->display, timestamp); window->grab_on_frame = FALSE; window->all_keys_grabbed = FALSE; window->keys_grabbed = FALSE; /* Re-establish our standard bindings */ meta_window_grab_keys (window); } } LOCAL_SYMBOL gboolean meta_window_resize_or_move_allowed (MetaWindow *window, MetaDirection dir) { if (!META_WINDOW_MAXIMIZED (window) && !META_WINDOW_TILED_OR_SNAPPED (window)) return TRUE; switch (dir) { case META_DIRECTION_LEFT: if (window->tile_mode == META_TILE_RIGHT || window->tile_mode == META_TILE_URC || window->tile_mode == META_TILE_LRC) return TRUE; break; case META_DIRECTION_RIGHT: if (window->tile_mode == META_TILE_LEFT || window->tile_mode == META_TILE_ULC || window->tile_mode == META_TILE_LLC) return TRUE; break; case META_DIRECTION_UP: if (window->tile_mode == META_TILE_BOTTOM || window->tile_mode == META_TILE_LLC || window->tile_mode == META_TILE_LRC) return TRUE; break; case META_DIRECTION_DOWN: if (window->tile_mode == META_TILE_TOP || window->tile_mode == META_TILE_ULC || window->tile_mode == META_TILE_URC) return TRUE; break; default: return FALSE; } return FALSE; } static gboolean is_modifier (MetaDisplay *display, unsigned int keycode) { int i; int map_size; gboolean retval = FALSE; g_assert (display->modmap); map_size = 8 * display->modmap->max_keypermod; i = 0; while (i < map_size) { if (keycode == display->modmap->modifiermap[i]) { retval = TRUE; break; } ++i; } return retval; } /* Indexes: * shift = 0 * lock = 1 * control = 2 * mod1 = 3 * mod2 = 4 * mod3 = 5 * mod4 = 6 * mod5 = 7 */ static void invoke_handler (MetaDisplay *display, MetaScreen *screen, MetaKeyHandler *handler, MetaWindow *window, XEvent *event, MetaKeyBinding *binding) { if (handler->func) (* handler->func) (display, screen, handler->flags & META_KEY_BINDING_PER_WINDOW ? window : NULL, event, binding, handler->user_data); else (* handler->default_func) (display, screen, handler->flags & META_KEY_BINDING_PER_WINDOW ? window: NULL, event, binding, NULL); } static void invoke_handler_by_name (MetaDisplay *display, MetaScreen *screen, const char *handler_name, MetaWindow *window, XEvent *event) { MetaKeyHandler *handler; handler = HANDLER (handler_name); if (handler) invoke_handler (display, screen, handler, window, event, NULL); } static gboolean modifier_only_keysym (KeySym keysym) { return keysym == XK_Super_L || keysym == XK_Super_R || keysym == XK_Control_L || keysym == XK_Control_R || keysym == XK_Alt_L || keysym == XK_Alt_R || keysym == XK_Shift_L || keysym == XK_Shift_R; } static void strip_self_mod (KeySym keysym, unsigned long *mask) { unsigned long mod = 0; switch (keysym) { case XK_Super_L: case XK_Super_R: mod = GDK_MOD4_MASK; break; case XK_Control_L: case XK_Control_R: mod = GDK_CONTROL_MASK; break; case XK_Alt_L: case XK_Alt_R: mod = GDK_MOD1_MASK; break; case XK_Shift_L: case XK_Shift_R: mod = GDK_SHIFT_MASK; break; default: mod = 0; break; } *mask = *mask & ~mod; } static gboolean is_modifier_only_kb (MetaDisplay *display, XEvent *event, KeySym keysym) { unsigned long mask; mask = (event->xkey.state & 0xff & ~(display->ignored_modifier_mask)); strip_self_mod (keysym, &mask); return mask == 0 && modifier_only_keysym (keysym); } /* now called from only one place, may be worth merging */ static gboolean process_event (MetaKeyBinding *bindings, int n_bindings, MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym, gboolean on_window, gboolean allow_release, gboolean mouse_grab_move) { int i; unsigned long mask; /* we used to have release-based bindings but no longer. */ if (event->type == KeyRelease && !allow_release) return FALSE; mask = event->xkey.state & 0xff & ~(display->ignored_modifier_mask); if (allow_release) { strip_self_mod (keysym, &mask); } /* * TODO: This would be better done with a hash table; * it doesn't suit to use O(n) for such a common operation. */ for (i=0; i<n_bindings; i++) { MetaKeyHandler *handler = bindings[i].handler; /* Custom keybindings are from Cinnamon, and never need a window */ if (!on_window && handler->flags & META_KEY_BINDING_PER_WINDOW && handler->action < META_KEYBINDING_ACTION_CUSTOM) continue; /* We allow workspace navigation in a grab state. Ordinarily we'd not make it this far, and we need to make sure * to stop processing in this case so we return TRUE (event handled) regardless of whether we found a matching * binding, to prevent further processing by cinnamon */ if (mouse_grab_move && (handler->action < META_KEYBINDING_ACTION_WORKSPACE_1 || handler->action > META_KEYBINDING_ACTION_WORKSPACE_RIGHT)) continue; if ((event->type != KeyPress && !allow_release) || bindings[i].keycode != event->xkey.keycode || mask != bindings[i].mask) continue; /* * window must be non-NULL for on_window to be true, * and so also window must be non-NULL if we get here and * this is a META_KEY_BINDING_PER_WINDOW binding. */ meta_topic (META_DEBUG_KEYBINDINGS, "Binding keycode 0x%x mask 0x%x matches event 0x%x state 0x%x\n", bindings[i].keycode, bindings[i].mask, event->xkey.keycode, event->xkey.state); if (handler == NULL) meta_bug ("Binding %s has no handler\n", bindings[i].name); #ifdef WITH_VERBOSE_MODE else meta_topic (META_DEBUG_KEYBINDINGS, "Running handler for %s\n", bindings[i].name); #endif /* Global keybindings count as a let-the-terminal-lose-focus * due to new window mapping until the user starts * interacting with the terminal again. */ display->allow_terminal_deactivation = TRUE; invoke_handler (display, screen, handler, window, event, &bindings[i]); return TRUE; } meta_topic (META_DEBUG_KEYBINDINGS, "No handler found for this event in this binding table\n"); /* If we're in the middle of a mouse grab move, we always return TRUE here, to * prevent further processing no matter what */ return mouse_grab_move; } static gboolean process_modifier_key (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym, gboolean have_window, gboolean *allow_key_up) { if (event->xkey.type == KeyPress) { /* check if we're just Pressing a captured modifier at this time */ if (is_modifier_only_kb (display, event, keysym)) { /* remember this state, because we'll need to know it for subsequent events */ modifier_only_is_down = TRUE; /* We keep the keyboard frozen - this allows us to use ReplayKeyboard * on the next event if it's not the release of this modifier key */ XAllowEvents (display->xdisplay, SyncKeyboard, event->xkey.time); return TRUE; } else { /* If it's a press, with a mod+key combination, we try our own keybindings * first, then pass it to the current window if we don't have anything for it. * Also, negate modifier_only_is_down. At this point we won't want a modifier * release to trigger a binding, since when it happens now, it will only be the * user releasing the keys after a combination binding has been used */ modifier_only_is_down = FALSE; /* Try our keybindings */ if (process_event (display->key_bindings, display->n_key_bindings, display, screen, window, event, keysym, have_window, FALSE, FALSE)) { /* we had a binding, we're done */ XAllowEvents (display->xdisplay, AsyncKeyboard, event->xkey.time); return TRUE; } else { /* if we have nothing, let focused window handle it */ XAllowEvents (display->xdisplay, ReplayKeyboard, event->xkey.time); return FALSE; } } } else { /* We only care about key releases for modifier-only bindings - * and only when that release directly follows a press. When this happens, * negate modifier_only_is_down, and allow the binding handler to accept * a key release. */ if (is_modifier_only_kb (display, event, keysym)) { if (modifier_only_is_down) *allow_key_up = TRUE; modifier_only_is_down = FALSE; } } return FALSE; } /* Handle a key event. May be called recursively: some key events cause * grabs to be ended and then need to be processed again in their own * right. This cannot cause infinite recursion because we never call * ourselves when there wasn't a grab, and we always clear the grab * first; the invariant is enforced using an assertion. See #112560. * * The return value is whether we handled the key event. * * FIXME: We need to prove there are no race conditions here. * FIXME: Does it correctly handle alt-Tab being followed by another * grabbing keypress without letting go of alt? * FIXME: An iterative solution would probably be simpler to understand * (and help us solve the other fixmes). */ LOCAL_SYMBOL gboolean meta_display_process_key_event (MetaDisplay *display, MetaWindow *window, XEvent *event) { KeySym keysym; gboolean keep_grab; gboolean all_keys_grabbed; gboolean handled; gboolean allow_key_up = FALSE; gboolean mouse_grab_move; const char *str; MetaScreen *screen; if (all_bindings_disabled) { /* In this mode, we try to pretend we don't have grabs, so we * immediately replay events and drop the grab. (This still * messes up global passive grabs from other clients.) The * FALSE return here is a little suspect, but we don't really * know if we'll see the event again or not, and it's pretty * poorly defined how this mode is supposed to interact with * plugins. */ XAllowEvents (display->xdisplay, ReplayKeyboard, event->xkey.time); return FALSE; } /* if key event was on root window, we have a shortcut */ screen = meta_display_screen_for_root (display, event->xkey.window); /* else round-trip to server */ if (screen == NULL) screen = meta_display_screen_for_xwindow (display, event->xany.window); if (screen == NULL) return FALSE; /* event window is destroyed */ /* ignore key events on popup menus and such. */ if (meta_ui_window_is_widget (screen->ui, event->xany.window)) return FALSE; /* window may be NULL */ keysym = XkbKeycodeToKeysym (display->xdisplay, event->xkey.keycode, 0, 0); str = XKeysymToString (keysym); /* was topic */ meta_topic (META_DEBUG_KEYBINDINGS, "Processing key %s event, keysym: %s state: 0x%x window: %s\n", event->type == KeyPress ? "press" : "release", str ? str : "none", event->xkey.state, window ? window->desc : "(no window)"); all_keys_grabbed = window ? window->all_keys_grabbed : screen->all_keys_grabbed; if (!all_keys_grabbed) { handled = process_modifier_key (display, screen, window, event, keysym, (!all_keys_grabbed && window), &allow_key_up); if (handled) return TRUE; } XAllowEvents (display->xdisplay, AsyncKeyboard, event->xkey.time); mouse_grab_move = FALSE; keep_grab = TRUE; if (all_keys_grabbed) { if (display->grab_op == META_GRAB_OP_NONE) return TRUE; /* If we get here we have a global grab, because * we're in some special keyboard mode such as window move * mode. */ if (window ? (window == display->grab_window) : (screen == display->grab_screen)) { switch (display->grab_op) { case META_GRAB_OP_MOVING: mouse_grab_move = TRUE; /* Fall through - this is just a flag for if we make it to process_event */ case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_RESIZING_E: meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for mouse-only move/resize\n"); g_assert (window != NULL); keep_grab = process_mouse_move_resize_grab (display, screen, window, event, keysym); break; case META_GRAB_OP_KEYBOARD_MOVING: meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for keyboard move\n"); g_assert (window != NULL); keep_grab = process_keyboard_move_grab (display, screen, window, event, keysym); break; case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: case META_GRAB_OP_KEYBOARD_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for keyboard resize\n"); g_assert (window != NULL); keep_grab = process_keyboard_resize_grab (display, screen, window, event, keysym); break; default: break; } } if (!keep_grab) { meta_topic (META_DEBUG_KEYBINDINGS, "Ending grab op %u on key event sym %s\n", display->grab_op, XKeysymToString (keysym)); meta_display_end_grab_op (display, event->xkey.time); } /* If this isn't specifically a mouse-based window move, we don't process keybindings * in the middle of a grab, so we end early and prevent further processing, otherwise * we let process_event() handle this. */ if (!mouse_grab_move) { return TRUE; } } /* Do the normal keybindings */ return process_event (display->key_bindings, display->n_key_bindings, display, screen, window, event, keysym, !all_keys_grabbed && window, allow_key_up, mouse_grab_move); } static void handle_workspace_shift (MetaWindow *window, XEvent *event, KeySym keysym) { MetaWorkspace *target_workspace; guint motion = META_MOTION_LEFT; gboolean should_handle = FALSE; if (keysym == XK_Left || keysym == XK_KP_Left) { motion = meta_prefs_get_invert_flip_direction () ? META_MOTION_RIGHT : META_MOTION_LEFT; should_handle = TRUE; } else if (keysym == XK_Right || keysym == XK_KP_Right) { motion = meta_prefs_get_invert_flip_direction () ? META_MOTION_LEFT : META_MOTION_RIGHT; should_handle = TRUE; } if (!should_handle) { return; } target_workspace = meta_workspace_get_neighbor (window->screen->active_workspace, motion); if (target_workspace) { meta_workspace_activate (target_workspace, event->xkey.time); } } static gboolean process_mouse_move_resize_grab (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym) { MetaWorkspace *target_workspace; gulong mask; gboolean numlock = FALSE; /* don't care about releases, but eat them, don't end grab */ if (event->type == KeyRelease) return TRUE; if (keysym == XK_Escape) { /* Hide the tiling preview if necessary */ meta_screen_tile_preview_hide (screen); meta_screen_tile_hud_hide (screen); /* Restore the original tile mode */ window->tile_mode = display->grab_tile_mode; window->tile_monitor_number = display->grab_tile_monitor_number; /* End move or resize and restore to original state. If the * window was a maximized window that had been "shaken loose" we * need to remaximize it. In normal cases, we need to do a * moveresize now to get the position back to the original. */ if (window->shaken_loose) meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); else if (window->tile_mode != META_TILE_NONE) { window->custom_snap_size = FALSE; meta_window_real_tile (window, FALSE); } else meta_window_move_resize (display->grab_window, TRUE, display->grab_initial_window_pos.x, display->grab_initial_window_pos.y, display->grab_initial_window_pos.width, display->grab_initial_window_pos.height); /* End grab */ return FALSE; } /* Don't use ignored_modifier_mask here - we don't want to ignore numlock */ mask = event->xkey.state & 0xff & ~(display->scroll_lock_mask | LockMask); /* Only proceed if no mod or only numlock */ if (mask == display->num_lock_mask) { numlock = TRUE; } else if (mask > display->num_lock_mask) { return TRUE; } gint index = -1; switch (keysym) { case XK_Left: case XK_Right: handle_workspace_shift (window, event, keysym); return TRUE; case XK_KP_End: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_1: index = 0; break; case XK_KP_Down: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_2: index = 1; break; case XK_KP_Next: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_3: index = 2; break; case XK_KP_Left: if (!numlock) { handle_workspace_shift (window, event, keysym); return TRUE; } DISABLE_GCC7_FALL_THRU_WARNING; case XK_4: index = 3; break; case XK_KP_Begin: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_5: index = 4; break; case XK_KP_Right: if (!numlock) { handle_workspace_shift (window, event, keysym); return TRUE; } DISABLE_GCC7_FALL_THRU_WARNING; case XK_6: index = 5; break; case XK_KP_Home: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_7: index = 6; break; case XK_KP_Up: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_8: index = 7; break; case XK_KP_Prior: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_9: index = 8; break; case XK_KP_Insert: if (!numlock) break; DISABLE_GCC7_FALL_THRU_WARNING; case XK_0: index = 9; break; default: break; } if (index >= 0) { target_workspace = meta_screen_get_workspace_by_index (window->screen, index); if (target_workspace) { meta_workspace_activate (target_workspace, event->xkey.time); } } return TRUE; } static gboolean process_keyboard_move_grab (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym) { gboolean handled; int x, y; int incr; gboolean smart_snap; handled = FALSE; /* don't care about releases, but eat them, don't end grab */ if (event->type == KeyRelease) return TRUE; /* don't end grab on modifier key presses */ if (is_modifier (display, event->xkey.keycode)) return TRUE; meta_window_get_position (window, &x, &y); smart_snap = (event->xkey.state & ShiftMask) != 0; #define SMALL_INCREMENT 1 #define NORMAL_INCREMENT 10 if (smart_snap) incr = 1; else if (event->xkey.state & ControlMask) incr = SMALL_INCREMENT; else incr = NORMAL_INCREMENT; if (keysym == XK_Escape) { /* End move and restore to original state. If the window was a * maximized window that had been "shaken loose" we need to * remaximize it. In normal cases, we need to do a moveresize * now to get the position back to the original. */ if (window->shaken_loose) { meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } else if (window->tile_mode != META_TILE_NONE) { window->custom_snap_size = FALSE; meta_window_real_tile (window, FALSE); } else { meta_window_move_resize (display->grab_window, TRUE, display->grab_initial_window_pos.x, display->grab_initial_window_pos.y, display->grab_initial_window_pos.width, display->grab_initial_window_pos.height); } } /* When moving by increments, we still snap to edges if the move * to the edge is smaller than the increment. This is because * Shift + arrow to snap is sort of a hidden feature. This way * people using just arrows shouldn't get too frustrated. */ switch (keysym) { case XK_KP_Home: case XK_KP_Prior: case XK_Up: case XK_KP_Up: y -= incr; handled = TRUE; break; case XK_KP_End: case XK_KP_Next: case XK_Down: case XK_KP_Down: y += incr; handled = TRUE; break; } switch (keysym) { case XK_KP_Home: case XK_KP_End: case XK_Left: case XK_KP_Left: x -= incr; handled = TRUE; break; case XK_KP_Prior: case XK_KP_Next: case XK_Right: case XK_KP_Right: x += incr; handled = TRUE; break; } if (handled) { MetaRectangle old_rect; meta_topic (META_DEBUG_KEYBINDINGS, "Computed new window location %d,%d due to keypress\n", x, y); meta_window_tile (window, META_TILE_NONE, FALSE); meta_window_get_client_root_coords (window, &old_rect); meta_window_edge_resistance_for_move (window, old_rect.x, old_rect.y, &x, &y, NULL, smart_snap, TRUE); meta_window_move (window, TRUE, x, y); meta_window_update_keyboard_move (window); } return handled; } static gboolean process_keyboard_resize_grab_op_change (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym) { gboolean handled; handled = FALSE; switch (display->grab_op) { case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: switch (keysym) { case XK_Up: case XK_KP_Up: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_UP)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; } handled = TRUE; break; case XK_Down: case XK_KP_Down: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_DOWN)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; } handled = TRUE; break; case XK_Left: case XK_KP_Left: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_LEFT)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; } handled = TRUE; break; case XK_Right: case XK_KP_Right: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_RIGHT)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; } handled = TRUE; break; } break; case META_GRAB_OP_KEYBOARD_RESIZING_S: switch (keysym) { case XK_Left: case XK_KP_Left: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_LEFT)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; } handled = TRUE; break; case XK_Right: case XK_KP_Right: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_RIGHT)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; } handled = TRUE; break; } break; case META_GRAB_OP_KEYBOARD_RESIZING_N: switch (keysym) { case XK_Left: case XK_KP_Left: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_LEFT)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; } handled = TRUE; break; case XK_Right: case XK_KP_Right: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_RIGHT)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; } handled = TRUE; break; } break; case META_GRAB_OP_KEYBOARD_RESIZING_W: switch (keysym) { case XK_Up: case XK_KP_Up: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_UP)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; } handled = TRUE; break; case XK_Down: case XK_KP_Down: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_DOWN)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; } handled = TRUE; break; } break; case META_GRAB_OP_KEYBOARD_RESIZING_E: switch (keysym) { case XK_Up: case XK_KP_Up: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_UP)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; } handled = TRUE; break; case XK_Down: case XK_KP_Down: if (meta_window_resize_or_move_allowed (window, META_DIRECTION_DOWN)) { display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; } handled = TRUE; break; } break; case META_GRAB_OP_KEYBOARD_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: break; default: g_assert_not_reached (); break; } if (handled) { meta_window_update_keyboard_resize (window, TRUE); return TRUE; } return FALSE; } static gboolean process_keyboard_resize_grab (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, KeySym keysym) { gboolean handled; int height_inc; int width_inc; int width, height; gboolean smart_snap; int gravity; handled = FALSE; /* don't care about releases, but eat them, don't end grab */ if (event->type == KeyRelease) return TRUE; /* don't end grab on modifier key presses */ if (is_modifier (display, event->xkey.keycode)) return TRUE; if (keysym == XK_Escape) { /* End resize and restore to original state. */ meta_window_move_resize (display->grab_window, TRUE, display->grab_initial_window_pos.x, display->grab_initial_window_pos.y, display->grab_initial_window_pos.width, display->grab_initial_window_pos.height); return FALSE; } if (process_keyboard_resize_grab_op_change (display, screen, window, event, keysym)) return TRUE; width = window->rect.width; height = window->rect.height; if (window->tile_mode != META_TILE_NONE) gravity = meta_resize_gravity_from_tile_mode (window->tile_mode); else gravity = meta_resize_gravity_from_grab_op (display->grab_op); smart_snap = (event->xkey.state & ShiftMask) != 0; #define SMALL_INCREMENT 1 #define NORMAL_INCREMENT 10 if (smart_snap) { height_inc = 1; width_inc = 1; } else if (event->xkey.state & ControlMask) { width_inc = SMALL_INCREMENT; height_inc = SMALL_INCREMENT; } else { width_inc = NORMAL_INCREMENT; height_inc = NORMAL_INCREMENT; } /* If this is a resize increment window, make the amount we resize * the window by match that amount (well, unless snap resizing...) */ if (window->size_hints.width_inc > 1) width_inc = window->size_hints.width_inc; if (window->size_hints.height_inc > 1) height_inc = window->size_hints.height_inc; switch (keysym) { case XK_Up: case XK_KP_Up: switch (gravity) { case NorthGravity: case NorthWestGravity: case NorthEastGravity: /* Move bottom edge up */ height -= height_inc; break; case SouthGravity: case SouthWestGravity: case SouthEastGravity: /* Move top edge up */ height += height_inc; break; case EastGravity: case WestGravity: case CenterGravity: g_assert_not_reached (); break; } handled = TRUE; break; case XK_Down: case XK_KP_Down: switch (gravity) { case NorthGravity: case NorthWestGravity: case NorthEastGravity: /* Move bottom edge down */ height += height_inc; break; case SouthGravity: case SouthWestGravity: case SouthEastGravity: /* Move top edge down */ height -= height_inc; break; case EastGravity: case WestGravity: case CenterGravity: g_assert_not_reached (); break; } handled = TRUE; break; case XK_Left: case XK_KP_Left: switch (gravity) { case EastGravity: case SouthEastGravity: case NorthEastGravity: /* Move left edge left */ width += width_inc; break; case WestGravity: case SouthWestGravity: case NorthWestGravity: /* Move right edge left */ width -= width_inc; break; case NorthGravity: case SouthGravity: case CenterGravity: g_assert_not_reached (); break; } handled = TRUE; break; case XK_Right: case XK_KP_Right: switch (gravity) { case EastGravity: case SouthEastGravity: case NorthEastGravity: /* Move left edge right */ width -= width_inc; break; case WestGravity: case SouthWestGravity: case NorthWestGravity: /* Move right edge right */ width += width_inc; break; case NorthGravity: case SouthGravity: case CenterGravity: g_assert_not_reached (); break; } handled = TRUE; break; default: break; } /* fixup hack (just paranoia, not sure it's required) */ if (height < 1) height = 1; if (width < 1) width = 1; if (handled) { MetaRectangle old_rect; meta_topic (META_DEBUG_KEYBINDINGS, "Computed new window size due to keypress: " "%dx%d, gravity %s\n", width, height, meta_gravity_to_string (gravity)); old_rect = window->rect; /* Don't actually care about x,y */ /* Do any edge resistance/snapping */ meta_window_edge_resistance_for_resize (window, old_rect.width, old_rect.height, &width, &height, gravity, NULL, smart_snap, TRUE); /* We don't need to update unless the specified width and height * are actually different from what we had before. */ if (window->rect.width != width || window->rect.height != height) meta_window_resize_with_gravity (window, TRUE, width, height, gravity); meta_window_update_keyboard_resize (window, FALSE); } return handled; } static void handle_switch_to_workspace (MetaDisplay *display, MetaScreen *screen, MetaWindow *event_window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { gint which = binding->handler->data; MetaWorkspace *workspace; workspace = meta_screen_get_workspace_by_index (screen, which); if (workspace) meta_workspace_activate (workspace, event->xkey.time); } static void handle_maximize_vertically (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->has_resize_func) { if (window->maximized_vertically) meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL); else meta_window_maximize (window, META_MAXIMIZE_VERTICAL); } } static void handle_maximize_horizontally (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->has_resize_func) { if (window->maximized_horizontally) meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL); else meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL); } } static void handle_opacity (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { MetaKeyBindingAction action = meta_prefs_get_keybinding_action (binding->name); meta_window_adjust_opacity (window, action == META_KEYBINDING_ACTION_INCREASE_OPACITY); } static void handle_move_to (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { guint direction = binding->handler->data; MetaRectangle work_area, outer; int monitor, new_x, new_y; monitor = meta_screen_get_current_monitor (window->screen); meta_window_get_work_area_for_monitor (window, monitor, &work_area); meta_window_get_outer_rect (window, &outer); if (direction & META_MOVE_TO_XCHANGE_FLAG) { new_x = work_area.x + (direction & META_MOVE_TO_RIGHT_FLAG ? work_area.width - outer.width : 0); } else { new_x = outer.x; } if (direction & META_MOVE_TO_YCHANGE_FLAG) { new_y = work_area.y + (direction & META_MOVE_TO_BOTTOM_FLAG ? work_area.height - outer.height : 0); } else { new_y = outer.y; } if (window->has_custom_frame_extents) { const GtkBorder *extents = &window->custom_frame_extents; new_x -= extents->left; new_y -= extents->top; } meta_window_move_frame (window, TRUE, new_x, new_y); } static void handle_move_to_center (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { MetaFrameBorders borders; MetaRectangle work_area, outer_rect; int center_x, center_y; int x, y; meta_window_get_work_area_current_monitor (window, &work_area); meta_window_get_input_rect (window, &outer_rect); meta_frame_calc_borders (window->frame, &borders); center_x = work_area.x + work_area.width / 2; center_y = work_area.y + work_area.height / 2; x = center_x - (window->rect.width / 2); y = center_y - (outer_rect.height / 2) + borders.visible.top + borders.invisible.top; meta_window_move_resize (window, TRUE, x, y, window->rect.width, window->rect.height); } static void handle_show_desktop (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { meta_screen_toggle_desktop (screen, event->xkey.time); } static void handle_toggle_recording (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { g_signal_emit_by_name (screen, "toggle-recording"); } static void handle_activate_window_menu (MetaDisplay *display, MetaScreen *screen, MetaWindow *event_window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (display->focus_window) { int x, y; meta_window_get_position (display->focus_window, &x, &y); if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) x += display->focus_window->rect.width; meta_window_show_menu (display->focus_window, x, y, 0, event->xkey.time); } } static void handle_toggle_fullscreen (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->fullscreen) meta_window_unmake_fullscreen (window); else if (window->has_fullscreen_func) meta_window_make_fullscreen (window); } static void handle_toggle_above (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->wm_state_above) meta_window_unmake_above (window); else meta_window_make_above (window); } static MetaTileMode get_new_tile_mode (MetaTileMode direction, MetaTileMode current) { MetaTileMode ret = META_TILE_NONE; switch (current) { case META_TILE_NONE: ret = direction; break; case META_TILE_MAXIMIZE: if (direction == META_TILE_LEFT) ret = META_TILE_LEFT; else if (direction == META_TILE_RIGHT) ret = META_TILE_RIGHT; else if (direction == META_TILE_TOP) ret = direction; else if (direction == META_TILE_BOTTOM) ret = META_TILE_TOP; else ret = META_TILE_NONE; break; case META_TILE_LEFT: if (direction == META_TILE_LEFT) ret = META_TILE_LEFT; else if (direction == META_TILE_RIGHT) ret = META_TILE_NONE; else if (direction == META_TILE_TOP) ret = META_TILE_ULC; else ret = META_TILE_LLC; break; case META_TILE_RIGHT: if (direction == META_TILE_LEFT) ret = META_TILE_NONE; else if (direction == META_TILE_RIGHT) ret = META_TILE_RIGHT; else if (direction == META_TILE_TOP) ret = META_TILE_URC; else ret = META_TILE_LRC; break; case META_TILE_TOP: if (direction == META_TILE_LEFT) ret = META_TILE_ULC; else if (direction == META_TILE_RIGHT) ret = META_TILE_URC; else if (direction == META_TILE_TOP) ret = META_TILE_MAXIMIZE; else ret = META_TILE_NONE; break; case META_TILE_BOTTOM: if (direction == META_TILE_LEFT) ret = META_TILE_LLC; else if (direction == META_TILE_RIGHT) ret = META_TILE_LRC; else if (direction == META_TILE_TOP) ret = META_TILE_NONE; else ret = META_TILE_BOTTOM; break; case META_TILE_ULC: if (direction == META_TILE_LEFT) ret = META_TILE_ULC; else if (direction == META_TILE_RIGHT) ret = META_TILE_TOP; else if (direction == META_TILE_TOP) ret = META_TILE_ULC; else ret = META_TILE_LEFT; break; case META_TILE_LLC: if (direction == META_TILE_LEFT) ret = META_TILE_LLC; else if (direction == META_TILE_RIGHT) ret = META_TILE_BOTTOM; else if (direction == META_TILE_TOP) ret = META_TILE_LEFT; else ret = META_TILE_LLC; break; case META_TILE_URC: if (direction == META_TILE_LEFT) ret = META_TILE_TOP; else if (direction == META_TILE_RIGHT) ret = META_TILE_URC; else if (direction == META_TILE_TOP) ret = META_TILE_URC; else ret = META_TILE_RIGHT; break; case META_TILE_LRC: if (direction == META_TILE_LEFT) ret = META_TILE_BOTTOM; else if (direction == META_TILE_RIGHT) ret = META_TILE_LRC; else if (direction == META_TILE_TOP) ret = META_TILE_RIGHT; else ret = META_TILE_LRC; break; default: ret = current; break; } return ret; } static void handle_tile_action (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { MetaTileMode mode = binding->handler->data; MetaKeyBindingAction action = meta_prefs_get_keybinding_action (binding->name); gboolean snap = action == META_KEYBINDING_ACTION_PUSH_SNAP_LEFT || action == META_KEYBINDING_ACTION_PUSH_SNAP_RIGHT || action == META_KEYBINDING_ACTION_PUSH_SNAP_UP || action == META_KEYBINDING_ACTION_PUSH_SNAP_DOWN; MetaTileMode new_mode = get_new_tile_mode (mode, META_WINDOW_MAXIMIZED (window) ? META_TILE_MAXIMIZE : window->tile_mode); if (new_mode == window->tile_mode) return; if (new_mode == META_TILE_MAXIMIZE) { meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } else { meta_window_tile (window, new_mode, snap); } } static void handle_toggle_maximized (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (META_WINDOW_MAXIMIZED (window)) meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); else if (window->has_maximize_func) meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } static void handle_maximize (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->has_maximize_func) meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } static void handle_unmaximize (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->maximized_vertically || window->maximized_horizontally) meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } static void handle_toggle_shaded (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->shaded) meta_window_unshade (window, event->xkey.time); else if (window->has_shade_func) meta_window_shade (window, event->xkey.time); } static void handle_close (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->has_close_func) meta_window_delete (window, event->xkey.time); } static void handle_minimize (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->has_minimize_func) meta_window_minimize (window); } static void handle_begin_move (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->has_move_func) { meta_window_begin_grab_op (window, META_GRAB_OP_KEYBOARD_MOVING, FALSE, event->xkey.time); } } static void handle_begin_resize (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->has_resize_func) { if (window->tile_mode != META_TILE_NONE) { window->resize_tile_mode = window->tile_mode; window->resizing_tile_type = window->tile_type; } meta_window_begin_grab_op (window, META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN, FALSE, event->xkey.time); } } static void handle_toggle_on_all_workspaces (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { if (window->on_all_workspaces_requested) meta_window_unstick (window); else meta_window_stick (window); } static void handle_move_to_workspace (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { gint which = binding->handler->data; gboolean flip = (which < 0); gboolean new = (which == META_MOTION_NOT_EXIST_YET); MetaWorkspace *workspace; /* If which is zero or positive, it's a workspace number, and the window * should move to the workspace with that number. * * However, if it's negative, it's a direction with respect to the current * position; it's expressed as a member of the MetaMotionDirection enum, * all of whose members are negative. Such a change is called a flip. */ if (window->always_sticky) return; workspace = NULL; if (!new) { if (flip) { workspace = meta_workspace_get_neighbor (screen->active_workspace, which); } else { workspace = meta_screen_get_workspace_by_index (screen, which); } } if (workspace) { /* Activate second, so the window is never unmapped */ meta_window_change_workspace (window, workspace); if (flip) { meta_topic (META_DEBUG_FOCUS, "Resetting mouse_mode to FALSE due to " "handle_move_to_workspace() call with flip set.\n"); workspace->screen->display->mouse_mode = FALSE; meta_workspace_activate_with_focus (workspace, window, event->xkey.time); } } else if (new) { workspace = meta_screen_append_new_workspace (window->screen, FALSE, event->xkey.time); GSettings *cinnamon = g_settings_new ("org.cinnamon"); g_settings_set_int (cinnamon, "number-workspaces", g_list_length (screen->workspaces)); g_object_unref (cinnamon); meta_window_change_workspace (window, workspace); } } static void handle_move_to_monitor (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { gint which = binding->handler->data; const MetaMonitorInfo *current, *new; current = meta_screen_get_monitor_for_window (screen, window); new = meta_screen_get_monitor_neighbor (screen, current->number, which); if (new == NULL) return; meta_window_move_to_monitor (window, new->number); } static void handle_raise_or_lower (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { /* Get window at pointer */ MetaWindow *above = NULL; /* Check if top */ if (meta_stack_get_top (window->screen->stack) == window) { meta_window_lower (window); return; } /* else check if windows in same layer are intersecting it */ above = meta_stack_get_above (window->screen->stack, window, TRUE); while (above) { MetaRectangle tmp, win_rect, above_rect; if (above->mapped && meta_window_should_be_showing(above)) { meta_window_get_outer_rect (window, &win_rect); meta_window_get_outer_rect (above, &above_rect); /* Check if obscured */ if (meta_rectangle_intersect (&win_rect, &above_rect, &tmp)) { meta_window_raise (window); return; } } above = meta_stack_get_above (window->screen->stack, above, TRUE); } /* window is not obscured */ meta_window_lower (window); } static void handle_raise (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { meta_window_raise (window); } static void handle_lower (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { meta_window_lower (window); } static void handle_set_spew_mark (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer dummy) { meta_verbose ("-- MARK MARK MARK MARK --\n"); } LOCAL_SYMBOL void meta_set_keybindings_disabled (gboolean setting) { all_bindings_disabled = setting; meta_topic (META_DEBUG_KEYBINDINGS, "Keybindings %s\n", all_bindings_disabled ? "disabled" : "enabled"); } gboolean meta_keybindings_set_custom_handler (const gchar *name, MetaKeyHandlerFunc handler, gpointer user_data, GDestroyNotify free_data) { MetaKeyHandler *key_handler = HANDLER (name); if (!key_handler) return FALSE; if (key_handler->user_data_free_func && key_handler->user_data) key_handler->user_data_free_func (key_handler->user_data); key_handler->func = handler; key_handler->user_data = user_data; key_handler->user_data_free_func = free_data; return TRUE; } static void init_builtin_key_bindings (MetaDisplay *display) { #define REVERSES_AND_REVERSED (META_KEY_BINDING_REVERSES | \ META_KEY_BINDING_IS_REVERSED) add_builtin_keybinding (display, "switch-to-workspace-1", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_1, handle_switch_to_workspace, 0); add_builtin_keybinding (display, "switch-to-workspace-2", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_2, handle_switch_to_workspace, 1); add_builtin_keybinding (display, "switch-to-workspace-3", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_3, handle_switch_to_workspace, 2); add_builtin_keybinding (display, "switch-to-workspace-4", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_4, handle_switch_to_workspace, 3); add_builtin_keybinding (display, "switch-to-workspace-5", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_5, handle_switch_to_workspace, 4); add_builtin_keybinding (display, "switch-to-workspace-6", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_6, handle_switch_to_workspace, 5); add_builtin_keybinding (display, "switch-to-workspace-7", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_7, handle_switch_to_workspace, 6); add_builtin_keybinding (display, "switch-to-workspace-8", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_8, handle_switch_to_workspace, 7); add_builtin_keybinding (display, "switch-to-workspace-9", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_9, handle_switch_to_workspace, 8); add_builtin_keybinding (display, "switch-to-workspace-10", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_10, handle_switch_to_workspace, 9); add_builtin_keybinding (display, "switch-to-workspace-11", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_11, handle_switch_to_workspace, 10); add_builtin_keybinding (display, "switch-to-workspace-12", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_12, handle_switch_to_workspace, 11); // Handled by Cinnamon, hence handler is NULL add_builtin_keybinding (display, "switch-to-workspace-left", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_LEFT, NULL, META_MOTION_LEFT); add_builtin_keybinding (display, "switch-to-workspace-right", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_RIGHT, NULL, META_MOTION_RIGHT); add_builtin_keybinding (display, "switch-to-workspace-up", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_UP, NULL, META_MOTION_UP); add_builtin_keybinding (display, "switch-to-workspace-down", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_WORKSPACE_DOWN, NULL, META_MOTION_DOWN); /* The ones which have inverses. These can't be bound to any keystroke * containing Shift because Shift will invert their "backward" state. * * TODO: "NORMAL" and "DOCKS" should be renamed to the same name as their * action, for obviousness. * * TODO: handle_switch and handle_cycle should probably really be the * same function checking a bit in the parameter for difference. */ add_builtin_keybinding (display, "switch-group", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_REVERSES, META_KEYBINDING_ACTION_SWITCH_GROUP, NULL, META_TAB_LIST_GROUP); add_builtin_keybinding (display, "switch-group-backward", SCHEMA_MUFFIN_KEYBINDINGS, REVERSES_AND_REVERSED, META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD, NULL, META_TAB_LIST_GROUP); add_builtin_keybinding (display, "switch-windows", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_REVERSES, META_KEYBINDING_ACTION_SWITCH_WINDOWS, NULL, META_TAB_LIST_NORMAL); add_builtin_keybinding (display, "switch-windows-backward", SCHEMA_MUFFIN_KEYBINDINGS, REVERSES_AND_REVERSED, META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD, NULL, META_TAB_LIST_NORMAL); add_builtin_keybinding (display, "switch-panels", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_REVERSES, META_KEYBINDING_ACTION_SWITCH_PANELS, NULL, META_TAB_LIST_DOCKS); add_builtin_keybinding (display, "switch-panels-backward", SCHEMA_MUFFIN_KEYBINDINGS, REVERSES_AND_REVERSED, META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD, NULL, META_TAB_LIST_DOCKS); add_builtin_keybinding (display, "show-desktop", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_SHOW_DESKTOP, handle_show_desktop, 0); add_builtin_keybinding (display, "panel-run-dialog", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_PANEL_RUN_DIALOG, NULL, META_KEYBINDING_ACTION_PANEL_RUN_DIALOG); add_builtin_keybinding (display, "toggle-recording", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_TOGGLE_RECORDING, handle_toggle_recording, 0); add_builtin_keybinding (display, "set-spew-mark", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_NONE, META_KEYBINDING_ACTION_SET_SPEW_MARK, handle_set_spew_mark, 0); #undef REVERSES_AND_REVERSED /************************ PER WINDOW BINDINGS ************************/ /* These take a window as an extra parameter; they have no effect * if no window is active. */ add_builtin_keybinding (display, "activate-window-menu", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_ACTIVATE_WINDOW_MENU, handle_activate_window_menu, 0); add_builtin_keybinding (display, "toggle-fullscreen", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_TOGGLE_FULLSCREEN, handle_toggle_fullscreen, 0); add_builtin_keybinding (display, "toggle-maximized", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_TOGGLE_MAXIMIZED, handle_toggle_maximized, 0); add_builtin_keybinding (display, "push-tile-left", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_TILE_LEFT, handle_tile_action, META_TILE_LEFT); add_builtin_keybinding (display, "push-tile-right", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_TILE_RIGHT, handle_tile_action, META_TILE_RIGHT); add_builtin_keybinding (display, "push-tile-up", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_TILE_UP, handle_tile_action, META_TILE_TOP); add_builtin_keybinding (display, "push-tile-down", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_TILE_DOWN, handle_tile_action, META_TILE_BOTTOM); add_builtin_keybinding (display, "push-snap-left", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_SNAP_LEFT, handle_tile_action, META_TILE_LEFT); add_builtin_keybinding (display, "push-snap-right", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_SNAP_RIGHT, handle_tile_action, META_TILE_RIGHT); add_builtin_keybinding (display, "push-snap-up", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_SNAP_UP, handle_tile_action, META_TILE_TOP); add_builtin_keybinding (display, "push-snap-down", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_PUSH_SNAP_DOWN, handle_tile_action, META_TILE_BOTTOM); add_builtin_keybinding (display, "toggle-above", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_TOGGLE_ABOVE, handle_toggle_above, 0); add_builtin_keybinding (display, "maximize", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MAXIMIZE, handle_maximize, 0); add_builtin_keybinding (display, "unmaximize", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_UNMAXIMIZE, handle_unmaximize, 0); add_builtin_keybinding (display, "toggle-shaded", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_TOGGLE_SHADED, handle_toggle_shaded, 0); add_builtin_keybinding (display, "minimize", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MINIMIZE, handle_minimize, 0); add_builtin_keybinding (display, "close", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_CLOSE, handle_close, 0); add_builtin_keybinding (display, "begin-move", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_BEGIN_MOVE, handle_begin_move, 0); add_builtin_keybinding (display, "begin-resize", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_BEGIN_RESIZE, handle_begin_resize, 0); add_builtin_keybinding (display, "toggle-on-all-workspaces", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_TOGGLE_ON_ALL_WORKSPACES, handle_toggle_on_all_workspaces, 0); add_builtin_keybinding (display, "move-to-workspace-1", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_1, handle_move_to_workspace, 0); add_builtin_keybinding (display, "move-to-workspace-2", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_2, handle_move_to_workspace, 1); add_builtin_keybinding (display, "move-to-workspace-3", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_3, handle_move_to_workspace, 2); add_builtin_keybinding (display, "move-to-workspace-4", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_4, handle_move_to_workspace, 3); add_builtin_keybinding (display, "move-to-workspace-5", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_5, handle_move_to_workspace, 4); add_builtin_keybinding (display, "move-to-workspace-6", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_6, handle_move_to_workspace, 5); add_builtin_keybinding (display, "move-to-workspace-7", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_7, handle_move_to_workspace, 6); add_builtin_keybinding (display, "move-to-workspace-8", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_8, handle_move_to_workspace, 7); add_builtin_keybinding (display, "move-to-workspace-9", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_9, handle_move_to_workspace, 8); add_builtin_keybinding (display, "move-to-workspace-10", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_10, handle_move_to_workspace, 9); add_builtin_keybinding (display, "move-to-workspace-11", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_11, handle_move_to_workspace, 10); add_builtin_keybinding (display, "move-to-workspace-12", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_12, handle_move_to_workspace, 11); add_builtin_keybinding (display, "move-to-workspace-left", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_LEFT, NULL, META_MOTION_LEFT); add_builtin_keybinding (display, "move-to-workspace-right", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_RIGHT, NULL, META_MOTION_RIGHT); add_builtin_keybinding (display, "move-to-workspace-up", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_UP, handle_move_to_workspace, META_MOTION_UP); add_builtin_keybinding (display, "move-to-workspace-down", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_DOWN, handle_move_to_workspace, META_MOTION_DOWN); add_builtin_keybinding (display, "move-to-workspace-new", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_NEW, handle_move_to_workspace, META_MOTION_NOT_EXIST_YET); add_builtin_keybinding (display, "move-to-monitor-left", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_LEFT, handle_move_to_monitor, META_SCREEN_LEFT); add_builtin_keybinding (display, "move-to-monitor-right", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_RIGHT, handle_move_to_monitor, META_SCREEN_RIGHT); add_builtin_keybinding (display, "move-to-monitor-down", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_DOWN, handle_move_to_monitor, META_SCREEN_DOWN); add_builtin_keybinding (display, "move-to-monitor-up", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_UP, handle_move_to_monitor, META_SCREEN_UP); add_builtin_keybinding (display, "raise-or-lower", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_RAISE_OR_LOWER, handle_raise_or_lower, 0); add_builtin_keybinding (display, "raise", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_RAISE, handle_raise, 0); add_builtin_keybinding (display, "lower", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_LOWER, handle_lower, 0); add_builtin_keybinding (display, "maximize-vertically", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MAXIMIZE_VERTICALLY, handle_maximize_vertically, 0); add_builtin_keybinding (display, "maximize-horizontally", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MAXIMIZE_HORIZONTALLY, handle_maximize_horizontally, 0); add_builtin_keybinding (display, "move-to-corner-nw", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_CORNER_NW, handle_move_to, META_MOVE_TO_NW); add_builtin_keybinding (display, "move-to-corner-ne", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_CORNER_NE, handle_move_to, META_MOVE_TO_NE); add_builtin_keybinding (display, "move-to-corner-sw", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_CORNER_SW, handle_move_to, META_MOVE_TO_SW); add_builtin_keybinding (display, "move-to-corner-se", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_CORNER_SE, handle_move_to, META_MOVE_TO_SE); add_builtin_keybinding (display, "move-to-side-n", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_SIDE_N, handle_move_to, META_MOVE_TO_N); add_builtin_keybinding (display, "move-to-side-s", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_SIDE_S, handle_move_to, META_MOVE_TO_S); add_builtin_keybinding (display, "move-to-side-e", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_SIDE_E, handle_move_to, META_MOVE_TO_E); add_builtin_keybinding (display, "move-to-side-w", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_SIDE_W, handle_move_to, META_MOVE_TO_W); add_builtin_keybinding (display, "move-to-center", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_MOVE_TO_CENTER, handle_move_to_center, 0); add_builtin_keybinding (display, "increase-opacity", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_INCREASE_OPACITY, handle_opacity, 0); add_builtin_keybinding (display, "decrease-opacity", SCHEMA_MUFFIN_KEYBINDINGS, META_KEY_BINDING_PER_WINDOW, META_KEYBINDING_ACTION_DECREASE_OPACITY, handle_opacity, 0); } LOCAL_SYMBOL void meta_display_init_keys (MetaDisplay *display) { /* Keybindings */ display->keymap = NULL; display->keysyms_per_keycode = 0; display->modmap = NULL; display->min_keycode = 0; display->max_keycode = 0; display->ignored_modifier_mask = 0; display->num_lock_mask = 0; display->scroll_lock_mask = 0; display->hyper_mask = 0; display->super_mask = 0; display->meta_mask = 0; display->key_bindings = NULL; display->n_key_bindings = 0; XDisplayKeycodes (display->xdisplay, &display->min_keycode, &display->max_keycode); meta_topic (META_DEBUG_KEYBINDINGS, "Display has keycode range %d to %d\n", display->min_keycode, display->max_keycode); reload_keymap (display); reload_modmap (display); key_handlers = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify) key_handler_free); init_builtin_key_bindings (display); rebuild_key_binding_table (display); reload_keycodes (display); reload_modifiers (display); /* Keys are actually grabbed in meta_screen_grab_keys() */ meta_prefs_add_listener (bindings_changed_callback, display); #ifdef HAVE_XKB /* meta_display_init_keys() should have already called XkbQueryExtension() */ if (display->xkb_base_event_type != -1) XkbSelectEvents (display->xdisplay, XkbUseCoreKbd, XkbNewKeyboardNotifyMask | XkbMapNotifyMask, XkbNewKeyboardNotifyMask | XkbMapNotifyMask); #endif } ������������������������������muffin-5.2.1/src/core/session.h���������������������������������������������������������������������0000664�0001750�0001750�00000004776�14211404421�016525� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file session.h Session management * * Maps windows to information about their placing and state on startup. * This is window matching, which we have a policy of leaving in general * to programs such as Devil's Pie, but the session manager specification * requires us to do it here. */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_SESSION_H #define META_SESSION_H #include "window-private.h" typedef struct _MetaWindowSessionInfo MetaWindowSessionInfo; struct _MetaWindowSessionInfo { /* Fields we use to match against */ char *id; char *res_class; char *res_name; char *title; char *role; MetaWindowType type; /* Information we restore */ GSList *workspace_indices; int stack_position; /* width/height should be multiplied by resize inc and * added to base size; position should be interpreted in * light of gravity. This preserves semantics of the * window size/pos, even if fonts/themes change, etc. */ int gravity; MetaRectangle rect; MetaRectangle saved_rect; guint on_all_workspaces : 1; guint minimized : 1; guint maximized : 1; guint stack_position_set : 1; guint geometry_set : 1; guint on_all_workspaces_set : 1; guint minimized_set : 1; guint maximized_set : 1; guint saved_rect_set : 1; }; /* If lookup_saved_state returns something, it should be used, * and then released when you're done with it. */ const MetaWindowSessionInfo* meta_window_lookup_saved_state (MetaWindow *window); void meta_window_release_saved_state (const MetaWindowSessionInfo *info); void meta_session_init (const char *client_id, const char *save_file); void meta_session_shutdown (void); #endif ��muffin-5.2.1/src/core/edge-resistance.h�������������������������������������������������������������0000664�0001750�0001750�00000004370�14211404421�020072� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Edge resistance for move/resize operations */ /* * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_EDGE_RESISTANCE_H #define META_EDGE_RESISTANCE_H #include "window-private.h" void meta_window_edge_resistance_for_move (MetaWindow *window, int old_x, int old_y, int *new_x, int *new_y, GSourceFunc timeout_func, gboolean snap, gboolean is_keyboard_op); void meta_window_edge_resistance_for_resize (MetaWindow *window, int old_width, int old_height, int *new_width, int *new_height, int gravity, GSourceFunc timeout_func, gboolean snap, gboolean is_keyboard_op); #endif /* META_EDGE_RESISTANCE_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/group.c�����������������������������������������������������������������������0000664�0001750�0001750�00000016676�14211404421�016173� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2002 Red Hat Inc. * Copyright (C) 2003 Rob Adams * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:group * @title: MetaGroup * @short_description: Muffin window groups * */ #include <config.h> #include <meta/util.h> #include "group-private.h" #include "group-props.h" #include "window-private.h" #include <meta/window.h> static MetaGroup* meta_group_new (MetaDisplay *display, Window group_leader) { MetaGroup *group; #define N_INITIAL_PROPS 3 Atom initial_props[N_INITIAL_PROPS]; int i; g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props)); group = g_new0 (MetaGroup, 1); group->display = display; group->windows = NULL; group->group_leader = group_leader; group->refcount = 1; /* owned by caller, hash table has only weak ref */ if (display->groups_by_leader == NULL) display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash, meta_unsigned_long_equal); g_assert (g_hash_table_lookup (display->groups_by_leader, &group_leader) == NULL); g_hash_table_insert (display->groups_by_leader, &group->group_leader, group); /* Fill these in the order we want them to be gotten */ i = 0; initial_props[i++] = display->atom_WM_CLIENT_MACHINE; initial_props[i++] = display->atom__NET_WM_PID; initial_props[i++] = display->atom__NET_STARTUP_ID; g_assert (N_INITIAL_PROPS == i); meta_group_reload_properties (group, initial_props, N_INITIAL_PROPS); meta_topic (META_DEBUG_GROUPS, "Created new group with leader 0x%lx\n", group->group_leader); return group; } static void meta_group_unref (MetaGroup *group) { g_return_if_fail (group->refcount > 0); group->refcount -= 1; if (group->refcount == 0) { meta_topic (META_DEBUG_GROUPS, "Destroying group with leader 0x%lx\n", group->group_leader); g_assert (group->display->groups_by_leader != NULL); g_hash_table_remove (group->display->groups_by_leader, &group->group_leader); /* mop up hash table, this is how it gets freed on display close */ if (g_hash_table_size (group->display->groups_by_leader) == 0) { g_hash_table_destroy (group->display->groups_by_leader); group->display->groups_by_leader = NULL; } free (group->wm_client_machine); free (group->startup_id); free (group); } } /** * meta_window_get_group: (skip) * */ MetaGroup* meta_window_get_group (MetaWindow *window) { if (window->unmanaging) return NULL; return window->group; } void meta_window_compute_group (MetaWindow* window) { MetaGroup *group; MetaWindow *ancestor; /* use window->xwindow if no window->xgroup_leader */ group = NULL; /* Determine the ancestor of the window; its group setting will override the * normal grouping rules; see bug 328211. */ ancestor = meta_window_find_root_ancestor (window); if (window->display->groups_by_leader) { if (ancestor != window) group = ancestor->group; else if (window->xgroup_leader != None) group = g_hash_table_lookup (window->display->groups_by_leader, &window->xgroup_leader); else group = g_hash_table_lookup (window->display->groups_by_leader, &window->xwindow); } if (group != NULL) { window->group = group; group->refcount += 1; } else { if (ancestor != window && ancestor->xgroup_leader != None) group = meta_group_new (window->display, ancestor->xgroup_leader); else if (window->xgroup_leader != None) group = meta_group_new (window->display, window->xgroup_leader); else group = meta_group_new (window->display, window->xwindow); window->group = group; } window->group->windows = g_slist_prepend (window->group->windows, window); meta_topic (META_DEBUG_GROUPS, "Adding %s to group with leader 0x%lx\n", window->desc, group->group_leader); } static void remove_window_from_group (MetaWindow *window) { if (window->group != NULL) { meta_topic (META_DEBUG_GROUPS, "Removing %s from group with leader 0x%lx\n", window->desc, window->group->group_leader); window->group->windows = g_slist_remove (window->group->windows, window); meta_group_unref (window->group); window->group = NULL; } } void meta_window_group_leader_changed (MetaWindow *window) { remove_window_from_group (window); meta_window_compute_group (window); } void meta_window_shutdown_group (MetaWindow *window) { remove_window_from_group (window); } /** * meta_display_lookup_group: (skip) * */ MetaGroup* meta_display_lookup_group (MetaDisplay *display, Window group_leader) { MetaGroup *group; group = NULL; if (display->groups_by_leader) group = g_hash_table_lookup (display->groups_by_leader, &group_leader); return group; } /** * meta_group_list_windows: * @group: A #MetaGroup * * Returns: (transfer container) (element-type Meta.Window): List of windows */ GSList* meta_group_list_windows (MetaGroup *group) { return g_slist_copy (group->windows); } void meta_group_update_layers (MetaGroup *group) { GSList *tmp; GSList *frozen_stacks; if (group->windows == NULL) return; frozen_stacks = NULL; tmp = group->windows; while (tmp != NULL) { MetaWindow *window = tmp->data; /* we end up freezing the same stack a lot of times, * but doesn't hurt anything. have to handle * groups that span 2 screens. */ meta_stack_freeze (window->screen->stack); frozen_stacks = g_slist_prepend (frozen_stacks, window->screen->stack); meta_stack_update_layer (window->screen->stack, window); tmp = tmp->next; } tmp = frozen_stacks; while (tmp != NULL) { meta_stack_thaw (tmp->data); tmp = tmp->next; } g_slist_free (frozen_stacks); } const char* meta_group_get_startup_id (MetaGroup *group) { return group->startup_id; } /** * meta_group_property_notify: (skip) * */ gboolean meta_group_property_notify (MetaGroup *group, XEvent *event) { meta_group_reload_property (group, event->xproperty.atom); return TRUE; } int meta_group_get_size (MetaGroup *group) { if (!group) return 0; return group->refcount; } ������������������������������������������������������������������muffin-5.2.1/src/core/core.c������������������������������������������������������������������������0000664�0001750�0001750�00000056273�14211404421�015764� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin interface used by GTK+ UI to talk to core */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2003 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "core.h" #include "frame.h" #include "workspace-private.h" #include <meta/prefs.h> #include <meta/errors.h> #include "util-private.h" /* Looks up the MetaWindow representing the frame of the given X window. * Used as a helper function by a bunch of the functions below. * * FIXME: The functions that use this function throw the result away * after use. Many of these functions tend to be called in small groups, * which results in get_window() getting called several times in succession * with the same parameters. We should profile to see whether this wastes * much time, and if it does we should look into a generalised * meta_core_get_window_info() which takes a bunch of pointers to variables * to put its results in, and only fills in the non-null ones. */ LOCAL_SYMBOL MetaWindow * meta_core_get_window (Display *xdisplay, Window frame_xwindow) { MetaDisplay *display; MetaWindow *window; display = meta_display_for_x_display (xdisplay); window = meta_display_lookup_x_window (display, frame_xwindow); if (window == NULL || window->frame == NULL) { meta_bug ("No such frame window 0x%lx!\n", frame_xwindow); return NULL; } return window; } LOCAL_SYMBOL void meta_core_get (Display *xdisplay, Window xwindow, ...) { va_list args; MetaCoreGetType request; MetaDisplay *display = meta_display_for_x_display (xdisplay); MetaWindow *window = meta_display_lookup_x_window (display, xwindow); va_start (args, xwindow); request = va_arg (args, MetaCoreGetType); /* Now, we special-case the first request slightly. Mostly, requests * for information on windows which have no frame are errors. * But sometimes we may want to know *whether* a window has a frame. * In this case, pass the key META_CORE_WINDOW_HAS_FRAME * as the *first* request, with a pointer to a boolean; if the window * has no frame, this will be set to False and meta_core_get will * exit immediately (so the values of any other requests will be * undefined). Otherwise it will be set to True and meta_core_get will * continue happily on its way. */ if (request != META_CORE_WINDOW_HAS_FRAME && (window == NULL || window->frame == NULL)) { meta_bug ("No such frame window 0x%lx!\n", xwindow); va_end (args); return; } while (request != META_CORE_GET_END) { gpointer answer = va_arg (args, gpointer); switch (request) { case META_CORE_WINDOW_HAS_FRAME: *((gboolean*)answer) = window != NULL && window->frame != NULL; if (!*((gboolean*)answer)) return; /* see above */ break; case META_CORE_GET_CLIENT_WIDTH: *((gint*)answer) = window->rect.width; break; case META_CORE_GET_CLIENT_HEIGHT: *((gint*)answer) = window->rect.height; break; case META_CORE_GET_CLIENT_XWINDOW: *((Window*)answer) = window->xwindow; break; case META_CORE_GET_FRAME_FLAGS: *((MetaFrameFlags*)answer) = meta_frame_get_flags (window->frame); break; case META_CORE_GET_FRAME_TYPE: *((MetaFrameType*)answer) = meta_window_get_frame_type (window); break; case META_CORE_GET_X: meta_window_get_position (window, (int*)answer, NULL); break; case META_CORE_GET_Y: meta_window_get_position (window, NULL, (int*)answer); break; case META_CORE_GET_FRAME_WORKSPACE: *((gint*)answer) = meta_window_get_net_wm_desktop (window); break; case META_CORE_GET_FRAME_X: *((gint*)answer) = window->frame->rect.x; break; case META_CORE_GET_FRAME_Y: *((gint*)answer) = window->frame->rect.y; break; case META_CORE_GET_FRAME_WIDTH: *((gint*)answer) = window->frame->rect.width; break; case META_CORE_GET_FRAME_HEIGHT: *((gint*)answer) = window->frame->rect.height; break; case META_CORE_GET_THEME_VARIANT: *((char**)answer) = window->gtk_theme_variant; break; case META_CORE_GET_SCREEN_WIDTH: *((gint*)answer) = window->screen->rect.width; break; case META_CORE_GET_SCREEN_HEIGHT: *((gint*)answer) = window->screen->rect.height; break; default: meta_warning("Unknown window information request: %d", request); } request = va_arg (args, MetaCoreGetType); } va_end (args); } LOCAL_SYMBOL void meta_core_queue_frame_resize (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_queue (window, META_QUEUE_MOVE_RESIZE); meta_window_frame_size_changed (window); } LOCAL_SYMBOL void meta_core_user_move (Display *xdisplay, Window frame_xwindow, int x, int y) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_move (window, TRUE, x, y); } LOCAL_SYMBOL void meta_core_user_resize (Display *xdisplay, Window frame_xwindow, int gravity, int width, int height) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_resize_with_gravity (window, TRUE, width, height, gravity); } LOCAL_SYMBOL void meta_core_user_raise (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_raise (window); } static gboolean lower_window_and_transients (MetaWindow *window, gpointer data) { meta_window_lower (window); meta_window_foreach_transient (window, lower_window_and_transients, NULL); if (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK && meta_prefs_get_raise_on_click ()) { /* Move window to the back of the focusing workspace's MRU list. * Do extra sanity checks to avoid possible race conditions. * (Borrowed from window.c.) */ if (window->screen->active_workspace && meta_window_located_on_workspace (window, window->screen->active_workspace)) { GList* link; link = g_list_find (window->screen->active_workspace->mru_list, window); g_assert (link); window->screen->active_workspace->mru_list = g_list_remove_link (window->screen->active_workspace->mru_list, link); g_list_free (link); window->screen->active_workspace->mru_list = g_list_append (window->screen->active_workspace->mru_list, window); } } return FALSE; } LOCAL_SYMBOL void meta_core_user_lower_and_unfocus (Display *xdisplay, Window frame_xwindow, guint32 timestamp) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); lower_window_and_transients (window, NULL); /* Rather than try to figure that out whether we just lowered * the focus window, assume that's always the case. (Typically, * this will be invoked via keyboard action or by a mouse action; * in either case the window or a modal child will have been focused.) */ meta_workspace_focus_default_window (window->screen->active_workspace, NULL, timestamp); } LOCAL_SYMBOL void meta_core_lower_beneath_grab_window (Display *xdisplay, Window xwindow, guint32 timestamp) { XWindowChanges changes; MetaDisplay *display; MetaScreen *screen; MetaWindow *grab_window; display = meta_display_for_x_display (xdisplay); screen = meta_display_screen_for_xwindow (display, xwindow); grab_window = display->grab_window; if (grab_window == NULL) return; changes.stack_mode = Below; changes.sibling = grab_window->frame ? grab_window->frame->xwindow : grab_window->xwindow; meta_stack_tracker_record_lower_below (screen->stack_tracker, xwindow, changes.sibling, XNextRequest (screen->display->xdisplay)); meta_error_trap_push (display); XConfigureWindow (xdisplay, xwindow, CWSibling | CWStackMode, &changes); meta_error_trap_pop (display); } LOCAL_SYMBOL void meta_core_lower_beneath_sibling (Display *xdisplay, Window xwindow, Window grab_window, guint32 timestamp) { XWindowChanges changes; MetaDisplay *display; MetaScreen *screen; display = meta_display_for_x_display (xdisplay); screen = meta_display_screen_for_xwindow (display, xwindow); changes.stack_mode = Below; changes.sibling = grab_window; meta_stack_tracker_record_lower_below (screen->stack_tracker, xwindow, changes.sibling, XNextRequest (screen->display->xdisplay)); meta_error_trap_push (display); XConfigureWindow (xdisplay, xwindow, CWSibling | CWStackMode, &changes); meta_error_trap_pop (display); } LOCAL_SYMBOL void meta_core_user_focus (Display *xdisplay, Window frame_xwindow, guint32 timestamp) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_focus (window, timestamp); } LOCAL_SYMBOL void meta_core_minimize (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); meta_window_minimize (window); } LOCAL_SYMBOL void meta_core_maximize (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } LOCAL_SYMBOL void meta_core_toggle_maximize_vertically (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); if (META_WINDOW_MAXIMIZED_VERTICALLY (window)) meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL); else meta_window_maximize (window, META_MAXIMIZE_VERTICAL); } LOCAL_SYMBOL void meta_core_toggle_maximize_horizontally (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); if (META_WINDOW_MAXIMIZED_HORIZONTALLY (window)) meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL); else meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL); } LOCAL_SYMBOL void meta_core_toggle_maximize (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); if (META_WINDOW_MAXIMIZED (window)) meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); else meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } LOCAL_SYMBOL void meta_core_unmaximize (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL); } LOCAL_SYMBOL void meta_core_delete (Display *xdisplay, Window frame_xwindow, guint32 timestamp) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_delete (window, timestamp); } LOCAL_SYMBOL void meta_core_unshade (Display *xdisplay, Window frame_xwindow, guint32 timestamp) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); meta_window_unshade (window, timestamp); } LOCAL_SYMBOL void meta_core_shade (Display *xdisplay, Window frame_xwindow, guint32 timestamp) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); meta_window_shade (window, timestamp); } LOCAL_SYMBOL void meta_core_unstick (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_unstick (window); } LOCAL_SYMBOL void meta_core_make_above (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_make_above (window); } LOCAL_SYMBOL void meta_core_unmake_above (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_unmake_above (window); } LOCAL_SYMBOL void meta_core_adjust_opacity (Display *xdisplay, Window frame_xwindow, gboolean increase) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_adjust_opacity (window, increase); } LOCAL_SYMBOL void meta_core_stick (Display *xdisplay, Window frame_xwindow) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_stick (window); } LOCAL_SYMBOL void meta_core_change_workspace (Display *xdisplay, Window frame_xwindow, int new_workspace) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_window_change_workspace (window, meta_screen_get_workspace_by_index (window->screen, new_workspace)); } LOCAL_SYMBOL int meta_core_get_num_workspaces (Screen *xscreen) { MetaScreen *screen; screen = meta_screen_for_x_screen (xscreen); return meta_screen_get_n_workspaces (screen); } LOCAL_SYMBOL int meta_core_get_active_workspace (Screen *xscreen) { MetaScreen *screen; screen = meta_screen_for_x_screen (xscreen); return meta_workspace_index (screen->active_workspace); } LOCAL_SYMBOL void meta_core_show_window_menu (Display *xdisplay, Window frame_xwindow, int root_x, int root_y, int button, guint32 timestamp) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); meta_screen_hide_hud_and_preview (window->screen); if (meta_prefs_get_raise_on_click ()) meta_window_raise (window); meta_window_focus (window, timestamp); meta_window_show_menu (window, root_x, root_y, button, timestamp); } LOCAL_SYMBOL void meta_core_get_menu_accelerator (MetaMenuOp menu_op, int workspace, unsigned int *keysym, MetaVirtualModifier *modifiers) { const char *name; name = NULL; switch (menu_op) { case META_MENU_OP_NONE: /* No keybinding for this one */ break; case META_MENU_OP_DELETE: name = "close"; break; case META_MENU_OP_MINIMIZE: name = "minimize"; break; case META_MENU_OP_UNMAXIMIZE: name = "unmaximize"; break; case META_MENU_OP_MAXIMIZE: name = "maximize"; break; case META_MENU_OP_UNSHADE: case META_MENU_OP_SHADE: name = "toggle_shaded"; break; case META_MENU_OP_UNSTICK: case META_MENU_OP_STICK: name = "toggle-on-all-workspaces"; break; case META_MENU_OP_ABOVE: case META_MENU_OP_UNABOVE: name = "toggle-above"; break; case META_MENU_OP_WORKSPACES: switch (workspace) { case 1: name = "move-to-workspace-1"; break; case 2: name = "move-to-workspace-2"; break; case 3: name = "move-to-workspace-3"; break; case 4: name = "move-to-workspace-4"; break; case 5: name = "move-to-workspace-5"; break; case 6: name = "move-to-workspace-6"; break; case 7: name = "move-to-workspace-7"; break; case 8: name = "move-to-workspace-8"; break; case 9: name = "move-to-workspace-9"; break; case 10: name = "move-to-workspace-10"; break; case 11: name = "move-to-workspace-11"; break; case 12: name = "move-to-workspace-12"; break; } break; case META_MENU_OP_MOVE: name = "begin-move"; break; case META_MENU_OP_RESIZE: name = "begin-resize"; break; case META_MENU_OP_MOVE_LEFT: name = "move-to-workspace-left"; break; case META_MENU_OP_MOVE_RIGHT: name = "move-to-workspace-right"; break; case META_MENU_OP_MOVE_UP: name = "move-to-workspace-up"; break; case META_MENU_OP_MOVE_DOWN: name = "move-to-workspace-down"; break; case META_MENU_OP_MOVE_NEW: name = "move-to-workspace-new"; break; case META_MENU_OP_RECOVER: /* No keybinding for this one */ break; default: break; } if (name) { meta_prefs_get_window_binding (name, keysym, modifiers); } else { *keysym = 0; *modifiers = 0; } } LOCAL_SYMBOL const char* meta_core_get_workspace_name_with_index (Display *xdisplay, Window xroot, int index) { MetaDisplay *display; MetaScreen *screen; MetaWorkspace *workspace; display = meta_display_for_x_display (xdisplay); screen = meta_display_screen_for_root (display, xroot); g_assert (screen != NULL); workspace = meta_screen_get_workspace_by_index (screen, index); return workspace ? meta_workspace_get_name (workspace) : NULL; } LOCAL_SYMBOL gboolean meta_core_begin_grab_op (Display *xdisplay, Window frame_xwindow, MetaGrabOp op, gboolean pointer_already_grabbed, gboolean frame_action, int button, gulong modmask, guint32 timestamp, int root_x, int root_y) { MetaWindow *window = meta_core_get_window (xdisplay, frame_xwindow); MetaDisplay *display; MetaScreen *screen; display = meta_display_for_x_display (xdisplay); screen = meta_display_screen_for_xwindow (display, frame_xwindow); g_assert (screen != NULL); return meta_display_begin_grab_op (display, screen, window, op, pointer_already_grabbed, frame_action, button, modmask, timestamp, root_x, root_y); } LOCAL_SYMBOL void meta_core_end_grab_op (Display *xdisplay, guint32 timestamp) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); meta_display_end_grab_op (display, timestamp); } LOCAL_SYMBOL MetaGrabOp meta_core_get_grab_op (Display *xdisplay) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); return display->grab_op; } LOCAL_SYMBOL Window meta_core_get_grab_frame (Display *xdisplay) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); g_assert (display != NULL); g_assert (display->grab_op == META_GRAB_OP_NONE || display->grab_screen != NULL); g_assert (display->grab_op == META_GRAB_OP_NONE || display->grab_screen->display->xdisplay == xdisplay); if (display->grab_op != META_GRAB_OP_NONE && display->grab_window && display->grab_window->frame) return display->grab_window->frame->xwindow; else return None; } LOCAL_SYMBOL int meta_core_get_grab_button (Display *xdisplay) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); if (display->grab_op == META_GRAB_OP_NONE) return -1; return display->grab_button; } LOCAL_SYMBOL void meta_core_grab_buttons (Display *xdisplay, Window frame_xwindow) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); meta_verbose ("Grabbing buttons on frame 0x%lx\n", frame_xwindow); meta_display_grab_window_buttons (display, frame_xwindow); } LOCAL_SYMBOL void meta_core_set_screen_cursor (Display *xdisplay, Window frame_on_screen, MetaCursor cursor) { MetaWindow *window = meta_core_get_window (xdisplay, frame_on_screen); meta_frame_set_screen_cursor (window->frame, cursor); } LOCAL_SYMBOL void meta_core_increment_event_serial (Display *xdisplay) { MetaDisplay *display; display = meta_display_for_x_display (xdisplay); meta_display_increment_event_serial (display); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/muffin-Xatomtype.h������������������������������������������������������������0000664�0001750�0001750�00000012303�14211404421�020277� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file muffin-Xatomtype.h Types for communicating with X about properties * * This files defines crock C structures for calling XGetWindowProperty and * XChangeProperty. All fields must be longs as the semantics of property * routines will handle conversion to and from actual 32 bit objects. If your * compiler doesn't treat &structoflongs the same as &arrayoflongs[0], you * will have some work to do. */ /*********************************************************** Copyright 1987, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Digital not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ #ifndef _XATOMTYPE_H_ #define _XATOMTYPE_H_ #define BOOL long #define SIGNEDINT long #define UNSIGNEDINT unsigned long #define RESOURCEID unsigned long /* this structure may be extended, but do not change the order */ typedef struct { UNSIGNEDINT flags; SIGNEDINT x, y, width, height; /* need to cvt; only for pre-ICCCM */ SIGNEDINT minWidth, minHeight; /* need to cvt */ SIGNEDINT maxWidth, maxHeight; /* need to cvt */ SIGNEDINT widthInc, heightInc; /* need to cvt */ SIGNEDINT minAspectX, minAspectY; /* need to cvt */ SIGNEDINT maxAspectX, maxAspectY; /* need to cvt */ SIGNEDINT baseWidth,baseHeight; /* need to cvt; ICCCM version 1 */ SIGNEDINT winGravity; /* need to cvt; ICCCM version 1 */ } xPropSizeHints; #define OldNumPropSizeElements 15 /* pre-ICCCM */ #define NumPropSizeElements 18 /* ICCCM version 1 */ /* this structure may be extended, but do not change the order */ /* RGB properties */ typedef struct { RESOURCEID colormap; UNSIGNEDINT red_max; UNSIGNEDINT red_mult; UNSIGNEDINT green_max; UNSIGNEDINT green_mult; UNSIGNEDINT blue_max; UNSIGNEDINT blue_mult; UNSIGNEDINT base_pixel; RESOURCEID visualid; /* ICCCM version 1 */ RESOURCEID killid; /* ICCCM version 1 */ } xPropStandardColormap; #define OldNumPropStandardColormapElements 8 /* pre-ICCCM */ #define NumPropStandardColormapElements 10 /* ICCCM version 1 */ /* this structure may be extended, but do not change the order */ typedef struct { UNSIGNEDINT flags; BOOL input; /* need to convert */ SIGNEDINT initialState; /* need to cvt */ RESOURCEID iconPixmap; RESOURCEID iconWindow; SIGNEDINT iconX; /* need to cvt */ SIGNEDINT iconY; /* need to cvt */ RESOURCEID iconMask; UNSIGNEDINT windowGroup; } xPropWMHints; #define NumPropWMHintsElements 9 /* number of elements in this structure */ /* this structure defines the icon size hints information */ typedef struct { SIGNEDINT minWidth, minHeight; /* need to cvt */ SIGNEDINT maxWidth, maxHeight; /* need to cvt */ SIGNEDINT widthInc, heightInc; /* need to cvt */ } xPropIconSize; #define NumPropIconSizeElements 6 /* number of elements in this structure */ /* this structure defines the window manager state information */ typedef struct { SIGNEDINT state; /* need to cvt */ RESOURCEID iconWindow; } xPropWMState; #define NumPropWMStateElements 2 /* number of elements in struct */ #undef BOOL #undef SIGNEDINT #undef UNSIGNEDINT #undef RESOURCEID #endif /* _XATOMTYPE_H_ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/xprops.h����������������������������������������������������������������������0000664�0001750�0001750�00000020102�14211404421�016352� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X property convenience routines */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_XPROPS_H #define META_XPROPS_H #include <config.h> #include <meta/display.h> #include <X11/Xutil.h> #ifdef HAVE_XSYNC #include <X11/extensions/sync.h> #endif /* Copied from Lesstif by way of GTK. Rudimentary docs can be * found in some Motif reference guides online. */ typedef struct { unsigned long flags; unsigned long functions; unsigned long decorations; long input_mode; unsigned long status; } MotifWmHints, MwmHints; #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) #define MWM_HINTS_STATUS (1L << 3) #define MWM_FUNC_ALL (1L << 0) #define MWM_FUNC_RESIZE (1L << 1) #define MWM_FUNC_MOVE (1L << 2) #define MWM_FUNC_MINIMIZE (1L << 3) #define MWM_FUNC_MAXIMIZE (1L << 4) #define MWM_FUNC_CLOSE (1L << 5) #define MWM_DECOR_ALL (1L << 0) #define MWM_DECOR_BORDER (1L << 1) #define MWM_DECOR_RESIZEH (1L << 2) #define MWM_DECOR_TITLE (1L << 3) #define MWM_DECOR_MENU (1L << 4) #define MWM_DECOR_MINIMIZE (1L << 5) #define MWM_DECOR_MAXIMIZE (1L << 6) #define MWM_INPUT_MODELESS 0 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 #define MWM_INPUT_SYSTEM_MODAL 2 #define MWM_INPUT_FULL_APPLICATION_MODAL 3 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL #define MWM_TEAROFF_WINDOW (1L<<0) /* These all return the memory from Xlib, so require an XFree() * when they return TRUE. They return TRUE on success. */ gboolean meta_prop_get_atom_list (MetaDisplay *display, Window xwindow, Atom xatom, Atom **atoms_p, int *n_atoms_p); gboolean meta_prop_get_motif_hints (MetaDisplay *display, Window xwindow, Atom xatom, MotifWmHints **hints_p); gboolean meta_prop_get_cardinal_list (MetaDisplay *display, Window xwindow, Atom xatom, gulong **cardinals_p, int *n_cardinals_p); gboolean meta_prop_get_latin1_string (MetaDisplay *display, Window xwindow, Atom xatom, char **str_p); gboolean meta_prop_get_utf8_string (MetaDisplay *display, Window xwindow, Atom xatom, char **str_p); gboolean meta_prop_get_utf8_list (MetaDisplay *display, Window xwindow, Atom xatom, char ***str_p, int *n_str_p); void meta_prop_set_utf8_string_hint (MetaDisplay *display, Window xwindow, Atom atom, const char *val); gboolean meta_prop_get_window (MetaDisplay *display, Window xwindow, Atom xatom, Window *window_p); gboolean meta_prop_get_cardinal (MetaDisplay *display, Window xwindow, Atom xatom, gulong *cardinal_p); gboolean meta_prop_get_cardinal_with_atom_type (MetaDisplay *display, Window xwindow, Atom xatom, Atom prop_type, gulong *cardinal_p); gboolean meta_prop_get_text_property (MetaDisplay *display, Window xwindow, Atom xatom, char **utf8_str_p); gboolean meta_prop_get_wm_hints (MetaDisplay *display, Window xwindow, Atom xatom, XWMHints **hints_p); gboolean meta_prop_get_class_hint (MetaDisplay *display, Window xwindow, Atom xatom, XClassHint *class_hint); gboolean meta_prop_get_size_hints (MetaDisplay *display, Window xwindow, Atom xatom, XSizeHints **hints_p, gulong *flags_p); typedef enum { META_PROP_VALUE_INVALID, META_PROP_VALUE_UTF8, META_PROP_VALUE_STRING, META_PROP_VALUE_STRING_AS_UTF8, META_PROP_VALUE_MOTIF_HINTS, META_PROP_VALUE_CARDINAL, META_PROP_VALUE_WINDOW, META_PROP_VALUE_CARDINAL_LIST, META_PROP_VALUE_UTF8_LIST, META_PROP_VALUE_ATOM_LIST, META_PROP_VALUE_TEXT_PROPERTY, /* comes back as UTF-8 string */ META_PROP_VALUE_WM_HINTS, META_PROP_VALUE_CLASS_HINT, META_PROP_VALUE_SIZE_HINTS, META_PROP_VALUE_SYNC_COUNTER, /* comes back as CARDINAL */ META_PROP_VALUE_SYNC_COUNTER_LIST /* comes back as CARDINAL */ } MetaPropValueType; /* used to request/return/store property values */ typedef struct { MetaPropValueType type; Atom atom; Atom required_type; /* autofilled if None */ union { char *str; MotifWmHints *motif_hints; Window xwindow; gulong cardinal; XWMHints *wm_hints; XClassHint class_hint; #ifdef HAVE_XSYNC XSyncCounter xcounter; struct { gulong *counters; int n_counters; } xcounter_list; #endif struct { XSizeHints *hints; unsigned long flags; } size_hints; struct { gulong *cardinals; int n_cardinals; } cardinal_list; struct { char **strings; int n_strings; } string_list; struct { Atom *atoms; int n_atoms; } atom_list; } v; } MetaPropValue; /* Each value has type and atom initialized. If there's an error, * or property is unset, type comes back as INVALID; * else type comes back as it originated, and the data * is filled in. */ void meta_prop_get_values (MetaDisplay *display, Window xwindow, MetaPropValue *values, int n_values); void meta_prop_free_values (MetaPropValue *values, int n_values); #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/boxes.c�����������������������������������������������������������������������0000664�0001750�0001750�00000216647�14211404421�016157� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * SECTION:boxes * @title: MetaRectangle * @short_description: Simple box operations */ /* * Copyright (C) 2005, 2006 Elijah Newren * [meta_rectangle_intersect() is copyright the GTK+ Team according to Havoc, * see gdkrectangle.c. As far as Havoc knows, he probably wrote * meta_rectangle_equal(), and I'm guessing it's (C) Red Hat. So...] * Copyright (C) 1995-2000 GTK+ Team * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #include "boxes-private.h" #include <meta/util.h> #include <X11/Xutil.h> /* Just for the definition of the various gravities */ /* It would make sense to use GSlice here, but until we clean up the * rest of this file and the internal API to use these functions, we * leave it using malloc()/free() for consistency. */ MetaRectangle * meta_rectangle_copy (const MetaRectangle *rect) { return g_memdup (rect, sizeof (MetaRectangle)); } void meta_rectangle_free (MetaRectangle *rect) { free (rect); } GType meta_rectangle_get_type (void) { static GType type_id = 0; if (!type_id) type_id = g_boxed_type_register_static (g_intern_static_string ("MetaRectangle"), (GBoxedCopyFunc) meta_rectangle_copy, (GBoxedFreeFunc) meta_rectangle_free); return type_id; } LOCAL_SYMBOL char* meta_rectangle_to_string (const MetaRectangle *rect, char *output) { /* 25 chars: 2 commas, space, plus, trailing \0 + 5 for each digit. * Should be more than enough space. Note that of this space, the * trailing \0 will be overwritten for all but the last rectangle. */ g_snprintf (output, RECT_LENGTH, "%d,%d +%d,%d", rect->x, rect->y, rect->width, rect->height); return output; } LOCAL_SYMBOL char* meta_rectangle_region_to_string (GList *region, const char *separator_string, char *output) { /* 27 chars: 2 commas, 2 square brackets, space, plus, trailing \0 + 5 * for each digit. Should be more than enough space. Note that of this * space, the trailing \0 will be overwritten for all but the last * rectangle. */ char rect_string[RECT_LENGTH]; GList *tmp = region; char *cur = output; if (region == NULL) g_snprintf (output, 10, "(EMPTY)"); while (tmp) { MetaRectangle *rect = tmp->data; g_snprintf (rect_string, RECT_LENGTH, "[%d,%d +%d,%d]", rect->x, rect->y, rect->width, rect->height); cur = g_stpcpy (cur, rect_string); tmp = tmp->next; if (tmp) cur = g_stpcpy (cur, separator_string); } return output; } LOCAL_SYMBOL char* meta_rectangle_edge_to_string (const MetaEdge *edge, char *output) { /* 25 chars: 2 commas, space, plus, trailing \0 + 5 for each digit. * Should be more than enough space. Note that of this space, the * trailing \0 will be overwritten for all but the last rectangle. * * Plus 2 for parenthesis, 4 for 2 more numbers, 2 more commas, and * 2 more spaces, for a total of 10 more. */ g_snprintf (output, EDGE_LENGTH, "[%d,%d +%d,%d], %2d, %2d", edge->rect.x, edge->rect.y, edge->rect.width, edge->rect.height, edge->side_type, edge->edge_type); return output; } LOCAL_SYMBOL char* meta_rectangle_edge_list_to_string (GList *edge_list, const char *separator_string, char *output) { /* 27 chars: 2 commas, 2 square brackets, space, plus, trailing \0 + 5 for * each digit. Should be more than enough space. Note that of this * space, the trailing \0 will be overwritten for all but the last * rectangle. * * Plus 2 for parenthesis, 4 for 2 more numbers, 2 more commas, and * 2 more spaces, for a total of 10 more. */ char rect_string[EDGE_LENGTH]; char *cur = output; GList *tmp = edge_list; if (edge_list == NULL) g_snprintf (output, 10, "(EMPTY)"); while (tmp) { MetaEdge *edge = tmp->data; MetaRectangle *rect = &edge->rect; g_snprintf (rect_string, EDGE_LENGTH, "([%d,%d +%d,%d], %2d, %2d)", rect->x, rect->y, rect->width, rect->height, edge->side_type, edge->edge_type); cur = g_stpcpy (cur, rect_string); tmp = tmp->next; if (tmp) cur = g_stpcpy (cur, separator_string); } return output; } MetaRectangle meta_rect (int x, int y, int width, int height) { MetaRectangle temporary; temporary.x = x; temporary.y = y; temporary.width = width; temporary.height = height; return temporary; } int meta_rectangle_area (const MetaRectangle *rect) { g_return_val_if_fail (rect != NULL, 0); return rect->width * rect->height; } /** * meta_rectangle_intersect: * @src1: a #MetaRectangle * @src2: another #MetaRectangle * @dest: (out caller-allocates): an empty #MetaRectangle, to be filled * with the coordinates of the intersection. * * Returns: TRUE is some intersection exists and is not degenerate, FALSE * otherwise. */ gboolean meta_rectangle_intersect (const MetaRectangle *src1, const MetaRectangle *src2, MetaRectangle *dest) { int dest_x, dest_y; int dest_w, dest_h; int return_val; g_return_val_if_fail (src1 != NULL, FALSE); g_return_val_if_fail (src2 != NULL, FALSE); g_return_val_if_fail (dest != NULL, FALSE); return_val = FALSE; dest_x = MAX (src1->x, src2->x); dest_y = MAX (src1->y, src2->y); dest_w = MIN (src1->x + src1->width, src2->x + src2->width) - dest_x; dest_h = MIN (src1->y + src1->height, src2->y + src2->height) - dest_y; if (dest_w > 0 && dest_h > 0) { dest->x = dest_x; dest->y = dest_y; dest->width = dest_w; dest->height = dest_h; return_val = TRUE; } else { dest->width = 0; dest->height = 0; } return return_val; } gboolean meta_rectangle_equal (const MetaRectangle *src1, const MetaRectangle *src2) { return ((src1->x == src2->x) && (src1->y == src2->y) && (src1->width == src2->width) && (src1->height == src2->height)); } /** * meta_rectangle_union: * @rect1: a #MetaRectangle * @rect2: another #MetaRectangle * @dest: (out caller-allocates): an empty #MetaRectangle, to be filled * with the coordinates of the bounding box. */ void meta_rectangle_union (const MetaRectangle *rect1, const MetaRectangle *rect2, MetaRectangle *dest) { int dest_x, dest_y; int dest_w, dest_h; dest_x = rect1->x; dest_y = rect1->y; dest_w = rect1->width; dest_h = rect1->height; if (rect2->x < dest_x) { dest_w += dest_x - rect2->x; dest_x = rect2->x; } if (rect2->y < dest_y) { dest_h += dest_y - rect2->y; dest_y = rect2->y; } if (rect2->x + rect2->width > dest_x + dest_w) dest_w = rect2->x + rect2->width - dest_x; if (rect2->y + rect2->height > dest_y + dest_h) dest_h = rect2->y + rect2->height - dest_y; dest->x = dest_x; dest->y = dest_y; dest->width = dest_w; dest->height = dest_h; } gboolean meta_rectangle_overlap (const MetaRectangle *rect1, const MetaRectangle *rect2) { g_return_val_if_fail (rect1 != NULL, FALSE); g_return_val_if_fail (rect2 != NULL, FALSE); return !((rect1->x + rect1->width <= rect2->x) || (rect2->x + rect2->width <= rect1->x) || (rect1->y + rect1->height <= rect2->y) || (rect2->y + rect2->height <= rect1->y)); } gboolean meta_rectangle_vert_overlap (const MetaRectangle *rect1, const MetaRectangle *rect2) { return (rect1->y < rect2->y + rect2->height && rect2->y < rect1->y + rect1->height); } gboolean meta_rectangle_horiz_overlap (const MetaRectangle *rect1, const MetaRectangle *rect2) { return (rect1->x < rect2->x + rect2->width && rect2->x < rect1->x + rect1->width); } gboolean meta_rectangle_could_fit_rect (const MetaRectangle *outer_rect, const MetaRectangle *inner_rect) { return (outer_rect->width >= inner_rect->width && outer_rect->height >= inner_rect->height); } gboolean meta_rectangle_contains_rect (const MetaRectangle *outer_rect, const MetaRectangle *inner_rect) { return inner_rect->x >= outer_rect->x && inner_rect->y >= outer_rect->y && inner_rect->x + inner_rect->width <= outer_rect->x + outer_rect->width && inner_rect->y + inner_rect->height <= outer_rect->y + outer_rect->height; } LOCAL_SYMBOL void meta_rectangle_resize_with_gravity (const MetaRectangle *old_rect, MetaRectangle *rect, int gravity, int new_width, int new_height) { /* FIXME: I'm too deep into this to know whether the below comment is * still clear or not now that I've moved it out of constraints.c. * boxes.h has a good comment, but I'm not sure if the below info is also * helpful on top of that (or whether it has superfluous info). */ /* These formulas may look overly simplistic at first but you can work * everything out with a left_frame_with, right_frame_width, * border_width, and old and new client area widths (instead of old total * width and new total width) and you come up with the same formulas. * * Also, note that the reason we can treat NorthWestGravity and * StaticGravity the same is because we're not given a location at * which to place the window--the window was already placed * appropriately before. So, NorthWestGravity for this function * means to just leave the upper left corner of the outer window * where it already is, and StaticGravity for this function means to * just leave the upper left corner of the inner window where it * already is. But leaving either of those two corners where they * already are will ensure that the other corner is fixed as well * (since frame size doesn't change)--thus making the two * equivalent. */ /* First, the x direction */ switch (gravity) { case NorthWestGravity: case WestGravity: case SouthWestGravity: rect->x = old_rect->x; break; case NorthGravity: case CenterGravity: case SouthGravity: /* FIXME: Needing to adjust new_width kind of sucks, but not doing so * would cause drift. */ new_width -= (old_rect->width - new_width) % 2; rect->x = old_rect->x + (old_rect->width - new_width)/2; break; case NorthEastGravity: case EastGravity: case SouthEastGravity: rect->x = old_rect->x + (old_rect->width - new_width); break; case StaticGravity: default: rect->x = old_rect->x; break; } rect->width = new_width; /* Next, the y direction */ switch (gravity) { case NorthWestGravity: case NorthGravity: case NorthEastGravity: rect->y = old_rect->y; break; case WestGravity: case CenterGravity: case EastGravity: /* FIXME: Needing to adjust new_height kind of sucks, but not doing so * would cause drift. */ new_height -= (old_rect->height - new_height) % 2; rect->y = old_rect->y + (old_rect->height - new_height)/2; break; case SouthWestGravity: case SouthGravity: case SouthEastGravity: rect->y = old_rect->y + (old_rect->height - new_height); break; case StaticGravity: default: rect->y = old_rect->y; break; } rect->height = new_height; } /* Not so simple helper function for get_minimal_spanning_set_for_region() */ static GList* merge_spanning_rects_in_region (GList *region) { /* NOTE FOR ANY OPTIMIZATION PEOPLE OUT THERE: Please see the * documentation of get_minimal_spanning_set_for_region() for performance * considerations that also apply to this function. */ GList* compare; compare = region; if (region == NULL) { meta_warning ("Region to merge was empty! Either you have a some " "pathological STRUT list or there's a bug somewhere!\n"); return NULL; } while (compare && compare->next) { MetaRectangle *a = compare->data; GList *other = compare->next; g_assert (a->width > 0 && a->height > 0); while (other) { MetaRectangle *b = other->data; GList *delete_me = NULL; g_assert (b->width > 0 && b->height > 0); /* If a contains b, just remove b */ if (meta_rectangle_contains_rect (a, b)) { delete_me = other; } /* If b contains a, just remove a */ else if (meta_rectangle_contains_rect (b, a)) { delete_me = compare; } /* If a and b might be mergeable horizontally */ else if (a->y == b->y && a->height == b->height) { /* If a and b overlap */ if (meta_rectangle_overlap (a, b)) { int new_x = MIN (a->x, b->x); a->width = MAX (a->x + a->width, b->x + b->width) - new_x; a->x = new_x; delete_me = other; } /* If a and b are adjacent */ else if (a->x + a->width == b->x || a->x == b->x + b->width) { int new_x = MIN (a->x, b->x); a->width = MAX (a->x + a->width, b->x + b->width) - new_x; a->x = new_x; delete_me = other; } } /* If a and b might be mergeable vertically */ else if (a->x == b->x && a->width == b->width) { /* If a and b overlap */ if (meta_rectangle_overlap (a, b)) { int new_y = MIN (a->y, b->y); a->height = MAX (a->y + a->height, b->y + b->height) - new_y; a->y = new_y; delete_me = other; } /* If a and b are adjacent */ else if (a->y + a->height == b->y || a->y == b->y + b->height) { int new_y = MIN (a->y, b->y); a->height = MAX (a->y + a->height, b->y + b->height) - new_y; a->y = new_y; delete_me = other; } } other = other->next; /* Delete any rectangle in the list that is no longer wanted */ if (delete_me != NULL) { /* Deleting the rect we compare others to is a little tricker */ if (compare == delete_me) { compare = compare->next; other = compare->next; a = compare->data; } /* Okay, we can free it now */ free (delete_me->data); region = g_list_delete_link (region, delete_me); } } compare = compare->next; } return region; } /* Simple helper function for get_minimal_spanning_set_for_region()... */ static gint compare_rect_areas (gconstpointer a, gconstpointer b) { const MetaRectangle *a_rect = (gconstpointer) a; const MetaRectangle *b_rect = (gconstpointer) b; int a_area = meta_rectangle_area (a_rect); int b_area = meta_rectangle_area (b_rect); return b_area - a_area; /* positive ret value denotes b > a, ... */ } /* ... and another helper for get_minimal_spanning_set_for_region()... */ static gboolean check_strut_align (MetaStrut *strut, const MetaRectangle *rect) { /* Check whether @strut actually aligns to the side of @rect it claims */ switch (strut->side) { case META_SIDE_TOP: return BOX_TOP (strut->rect) <= BOX_TOP (*rect); case META_SIDE_BOTTOM: return BOX_BOTTOM (strut->rect) >= BOX_BOTTOM (*rect); case META_SIDE_LEFT: return BOX_LEFT (strut->rect) <= BOX_LEFT (*rect); case META_SIDE_RIGHT: return BOX_RIGHT (strut->rect) >= BOX_RIGHT (*rect); default: return FALSE; } } /** * meta_rectangle_get_minimal_spanning_set_for_region: * @basic_rect: Input rectangle * @all_struts: (element-type Meta.Rectangle): List of struts * * This function is trying to find a "minimal spanning set (of rectangles)" * for a given region. * * The region is given by taking basic_rect, then removing the areas * covered by all the rectangles in the all_struts list, and then expanding * the resulting region by the given number of pixels in each direction. * * A "minimal spanning set (of rectangles)" is the best name I could come * up with for the concept I had in mind. Basically, for a given region, I * want a set of rectangles with the property that a window is contained in * the region if and only if it is contained within at least one of the * rectangles. * * Returns: (transfer full) (element-type Meta.Rectangle): Minimal spanning set */ LOCAL_SYMBOL GList* meta_rectangle_get_minimal_spanning_set_for_region ( const MetaRectangle *basic_rect, const GSList *all_struts) { /* NOTE FOR OPTIMIZERS: This function *might* be somewhat slow, * especially due to the call to merge_spanning_rects_in_region() (which * is O(n^2) where n is the size of the list generated in this function). * This is made more onerous due to the fact that it involves a fair * number of memory allocation and deallocation calls. However, n is 1 * for default installations of Gnome (because partial struts aren't used * by default and only partial struts increase the size of the spanning * set generated). With one partial strut, n will be 2 or 3. With 2 * partial struts, n will probably be 4 or 5. So, n probably isn't large * enough to make this worth bothering. Further, it is only called from * workspace.c:ensure_work_areas_validated (at least as of the time of * writing this comment), which in turn should only be called if the * strut list changes or the screen or monitor size changes. If it ever * does show up on profiles (most likely because people start using * ridiculously huge numbers of partial struts), possible optimizations * include: * * (1) rewrite merge_spanning_rects_in_region() to be O(n) or O(nlogn). * I'm not totally sure it's possible, but with a couple copies of * the list and sorting them appropriately, I believe it might be. * (2) only call merge_spanning_rects_in_region() with a subset of the * full list of rectangles. I believe from some of my preliminary * debugging and thinking about it that it is possible to figure out * apriori groups of rectangles which are only merge candidates with * each other. (See testboxes.c:get_screen_region() when which==2 * and track the steps of this function carefully to see what gave * me the hint that this might work) * (3) figure out how to avoid merge_spanning_rects_in_region(). I think * it might be possible to modify this function to make that * possible, and I spent just a little while thinking about it, but n * wasn't large enough to convince me to care yet. * (4) Some of the stuff Rob mentioned at http://mail.gnome.org/archives\ * /metacity-devel-list/2005-November/msg00028.html. (Sorry for the * URL splitting.) */ GList *ret; GList *tmp_list; const GSList *strut_iter; MetaRectangle *temp_rect; /* The algorithm is basically as follows: * Initialize rectangle_set to basic_rect * Foreach strut: * Foreach rectangle in rectangle_set: * - Split the rectangle into new rectangles that don't overlap the * strut (but which are as big as possible otherwise) * - Remove the old (pre-split) rectangle from the rectangle_set, * and replace it with the new rectangles generated from the * splitting */ temp_rect = g_new (MetaRectangle, 1); *temp_rect = *basic_rect; ret = g_list_prepend (NULL, temp_rect); for (strut_iter = all_struts; strut_iter; strut_iter = strut_iter->next) { GList *rect_iter; MetaStrut *strut = (MetaStrut*)strut_iter->data; MetaRectangle *strut_rect = &strut->rect; tmp_list = ret; ret = NULL; rect_iter = tmp_list; while (rect_iter) { MetaRectangle *rect = (MetaRectangle*) rect_iter->data; if (!meta_rectangle_overlap (strut_rect, rect) || !check_strut_align (strut, basic_rect)) ret = g_list_prepend (ret, rect); else { /* If there is area in rect left of strut */ if (BOX_LEFT (*rect) < BOX_LEFT (*strut_rect)) { temp_rect = g_new (MetaRectangle, 1); *temp_rect = *rect; temp_rect->width = BOX_LEFT (*strut_rect) - BOX_LEFT (*rect); ret = g_list_prepend (ret, temp_rect); } /* If there is area in rect right of strut */ if (BOX_RIGHT (*rect) > BOX_RIGHT (*strut_rect)) { int new_x; temp_rect = g_new (MetaRectangle, 1); *temp_rect = *rect; new_x = BOX_RIGHT (*strut_rect); temp_rect->width = BOX_RIGHT(*rect) - new_x; temp_rect->x = new_x; ret = g_list_prepend (ret, temp_rect); } /* If there is area in rect above strut */ if (BOX_TOP (*rect) < BOX_TOP (*strut_rect)) { temp_rect = g_new (MetaRectangle, 1); *temp_rect = *rect; temp_rect->height = BOX_TOP (*strut_rect) - BOX_TOP (*rect); ret = g_list_prepend (ret, temp_rect); } /* If there is area in rect below strut */ if (BOX_BOTTOM (*rect) > BOX_BOTTOM (*strut_rect)) { int new_y; temp_rect = g_new (MetaRectangle, 1); *temp_rect = *rect; new_y = BOX_BOTTOM (*strut_rect); temp_rect->height = BOX_BOTTOM (*rect) - new_y; temp_rect->y = new_y; ret = g_list_prepend (ret, temp_rect); } free (rect); } rect_iter = rect_iter->next; } g_list_free (tmp_list); } /* Sort by maximal area, just because I feel like it... */ ret = g_list_sort (ret, compare_rect_areas); /* Merge rectangles if possible so that the list really is minimal */ ret = merge_spanning_rects_in_region (ret); return ret; } /** * meta_rectangle_expand_region: (skip) * */ LOCAL_SYMBOL GList* meta_rectangle_expand_region (GList *region, const int left_expand, const int right_expand, const int top_expand, const int bottom_expand) { return meta_rectangle_expand_region_conditionally (region, left_expand, right_expand, top_expand, bottom_expand, 0, 0); } /** * meta_rectangle_expand_region_conditionally: (skip) * */ LOCAL_SYMBOL GList* meta_rectangle_expand_region_conditionally (GList *region, const int left_expand, const int right_expand, const int top_expand, const int bottom_expand, const int min_x, const int min_y) { GList *tmp_list = region; while (tmp_list) { MetaRectangle *rect = (MetaRectangle*) tmp_list->data; if (rect->width >= min_x) { rect->x -= left_expand; rect->width += (left_expand + right_expand); } if (rect->height >= min_y) { rect->y -= top_expand; rect->height += (top_expand + bottom_expand); } tmp_list = tmp_list->next; } return region; } LOCAL_SYMBOL void meta_rectangle_expand_to_snapped_borders (MetaRectangle *rect, const MetaRectangle *expand_to, const GSList *all_struts, const GSList *snapped_windows_as_struts, const MetaRectangle *user_rect) { const GSList *strut_iter; gint x_c, y_c, max_x, max_y, min_x, min_y, fallback_x, fallback_y, fallback_width, fallback_height; gboolean ulc = FALSE, llc = FALSE, urc = FALSE, lrc = FALSE; x_c = BOX_CENTER_X (*user_rect); y_c = BOX_TOP (*user_rect); min_x = BOX_LEFT (*expand_to); max_x = BOX_RIGHT (*expand_to); min_y = BOX_TOP (*expand_to); max_y = BOX_BOTTOM (*expand_to); /* Iterate over all struts, find a box containing the center of the current rectangle */ for (strut_iter = all_struts; strut_iter; strut_iter = strut_iter->next) { MetaStrut *strut = (MetaStrut*) strut_iter->data; if (!meta_rectangle_overlap (&strut->rect, expand_to)) continue; if (strut->side & META_SIDE_LEFT) if (BOX_RIGHT (strut->rect) > min_x) min_x = BOX_RIGHT (strut->rect); if (strut->side & META_SIDE_RIGHT) if (BOX_LEFT (strut->rect) < max_x) max_x = BOX_LEFT (strut->rect); if (strut->side & META_SIDE_TOP) if (BOX_BOTTOM (strut->rect) > min_y) min_y = BOX_BOTTOM (strut->rect); if (strut->side & META_SIDE_BOTTOM) if (BOX_TOP (strut->rect) < max_y) max_y = BOX_TOP (strut->rect); } /* end loop over struts */ /* store safe fallback values if we end up with an impossible situation at the end */ fallback_x = min_x; fallback_y = min_y; fallback_width = max_x - min_x; fallback_height = max_y - min_y; for (strut_iter = snapped_windows_as_struts; strut_iter; strut_iter = strut_iter->next) { MetaStrut *strut = (MetaStrut*) strut_iter->data; if (strut->side == (META_SIDE_LEFT | META_SIDE_TOP) || strut->side == (META_SIDE_LEFT | META_SIDE_BOTTOM) || strut->side == (META_SIDE_RIGHT | META_SIDE_TOP) || strut->side == (META_SIDE_RIGHT | META_SIDE_BOTTOM)) { ulc = ulc || strut->side == (META_SIDE_LEFT | META_SIDE_TOP); llc = llc || strut->side == (META_SIDE_LEFT | META_SIDE_BOTTOM); urc = urc || strut->side == (META_SIDE_RIGHT | META_SIDE_TOP); lrc = lrc || strut->side == (META_SIDE_RIGHT | META_SIDE_BOTTOM); continue; } if (strut->side & META_SIDE_LEFT) if (BOX_RIGHT (strut->rect) > min_x) min_x = BOX_RIGHT (strut->rect); if (strut->side & META_SIDE_RIGHT) if (BOX_LEFT (strut->rect) < max_x) max_x = BOX_LEFT (strut->rect); if (strut->side & META_SIDE_TOP) if (BOX_BOTTOM (strut->rect) > min_y) min_y = BOX_BOTTOM (strut->rect); if (strut->side & META_SIDE_BOTTOM) if (BOX_TOP (strut->rect) < max_y) max_y = BOX_TOP (strut->rect); } /* end loop over struts */ for (strut_iter = snapped_windows_as_struts; strut_iter; strut_iter = strut_iter->next) { MetaStrut *strut = (MetaStrut*) strut_iter->data; if (strut->side == (META_SIDE_LEFT | META_SIDE_TOP)) { if (llc) { min_x = BOX_RIGHT (strut->rect); } if (urc) { min_y = BOX_BOTTOM (strut->rect); } if (!llc && !urc) { if (x_c > BOX_RIGHT (strut->rect) && y_c < BOX_BOTTOM (strut->rect)) min_x = BOX_RIGHT (strut->rect); else min_y = BOX_BOTTOM (strut->rect); } } else if (strut->side == (META_SIDE_LEFT | META_SIDE_BOTTOM)) { if (ulc) { min_x = BOX_RIGHT (strut->rect); } if (lrc) { max_y = BOX_TOP (strut->rect); } if (!ulc && !lrc) { if (x_c > BOX_RIGHT (strut->rect) && y_c > BOX_TOP (strut->rect)) { min_x = BOX_RIGHT (strut->rect); } else { max_y = BOX_TOP (strut->rect); } } } else if (strut->side == (META_SIDE_RIGHT | META_SIDE_TOP)) { if (lrc) { max_x = BOX_LEFT (strut->rect); } if (ulc) { min_y = BOX_BOTTOM (strut->rect); } if (!lrc && !ulc) { if (x_c < BOX_LEFT (strut->rect) && y_c < BOX_BOTTOM (strut->rect)) max_x = BOX_LEFT (strut->rect); else min_y = BOX_BOTTOM (strut->rect); } } else if (strut->side == (META_SIDE_RIGHT | META_SIDE_BOTTOM)) { if (urc) { max_x = BOX_LEFT (strut->rect); } if (llc) { max_y = BOX_TOP (strut->rect); } if (!urc && !llc) { if (x_c < BOX_LEFT (strut->rect) && y_c > BOX_TOP (strut->rect)) max_x = BOX_LEFT (strut->rect); else max_y = BOX_TOP (strut->rect); } } else { continue; } } /* end loop over struts */ rect->x = min_x; rect->y = min_y; rect->width = max_x - min_x; rect->height = max_y - min_y; if (rect->width <= 0) { rect->x = fallback_x; rect->width = fallback_width; } if (rect->height <= 0) { rect->y = fallback_y; rect->height = fallback_height; } } LOCAL_SYMBOL void meta_rectangle_expand_to_avoiding_struts (MetaRectangle *rect, const MetaRectangle *expand_to, const MetaDirection direction, const GSList *all_struts) { const GSList *strut_iter; /* If someone wants this function to handle more fine-grained * direction expanding in the future (e.g. only left, or fully * horizontal plus upward), feel free. But I'm hard-coding for both * horizontal directions (exclusive-)or both vertical directions. */ g_assert ((direction == META_DIRECTION_HORIZONTAL) ^ (direction == META_DIRECTION_VERTICAL )); if (direction == META_DIRECTION_HORIZONTAL) { rect->x = expand_to->x; rect->width = expand_to->width; } else { rect->y = expand_to->y; rect->height = expand_to->height; } /* Run over all struts */ for (strut_iter = all_struts; strut_iter; strut_iter = strut_iter->next) { MetaStrut *strut = (MetaStrut*) strut_iter->data; /* Skip struts that don't overlap */ if (!meta_rectangle_overlap (&strut->rect, rect)) continue; if (direction == META_DIRECTION_HORIZONTAL) { if (strut->side == META_SIDE_LEFT) { int offset = BOX_RIGHT(strut->rect) - BOX_LEFT(*rect); rect->x += offset; rect->width -= offset; } else if (strut->side == META_SIDE_RIGHT) { int offset = BOX_RIGHT (*rect) - BOX_LEFT(strut->rect); rect->width -= offset; } /* else ignore the strut */ } else /* direction == META_DIRECTION_VERTICAL */ { if (strut->side == META_SIDE_TOP) { int offset = BOX_BOTTOM(strut->rect) - BOX_TOP(*rect); rect->y += offset; rect->height -= offset; } else if (strut->side == META_SIDE_BOTTOM) { int offset = BOX_BOTTOM(*rect) - BOX_TOP(strut->rect); rect->height -= offset; } /* else ignore the strut */ } } /* end loop over struts */ } /* end meta_rectangle_expand_to_avoiding_struts */ LOCAL_SYMBOL void meta_rectangle_free_list_and_elements (GList *filled_list) { g_list_foreach (filled_list, (void (*)(gpointer,gpointer))&free, /* ew, for ugly */ NULL); g_list_free (filled_list); } LOCAL_SYMBOL gboolean meta_rectangle_could_fit_in_region (const GList *spanning_rects, const MetaRectangle *rect) { const GList *temp; gboolean could_fit; temp = spanning_rects; could_fit = FALSE; while (!could_fit && temp != NULL) { could_fit = could_fit || meta_rectangle_could_fit_rect (temp->data, rect); temp = temp->next; } return could_fit; } LOCAL_SYMBOL gboolean meta_rectangle_contained_in_region (const GList *spanning_rects, const MetaRectangle *rect) { const GList *temp; gboolean contained; temp = spanning_rects; contained = FALSE; while (!contained && temp != NULL) { contained = contained || meta_rectangle_contains_rect (temp->data, rect); temp = temp->next; } return contained; } LOCAL_SYMBOL gboolean meta_rectangle_overlaps_with_region (const GList *spanning_rects, const MetaRectangle *rect) { const GList *temp; gboolean overlaps; temp = spanning_rects; overlaps = FALSE; while (!overlaps && temp != NULL) { overlaps = overlaps || meta_rectangle_overlap (temp->data, rect); temp = temp->next; } return overlaps; } LOCAL_SYMBOL void meta_rectangle_clamp_to_fit_into_region (const GList *spanning_rects, FixedDirections fixed_directions, MetaRectangle *rect, const MetaRectangle *min_size) { const GList *temp; const MetaRectangle *best_rect = NULL; int best_overlap = 0; /* First, find best rectangle from spanning_rects to which we can clamp * rect to fit into. */ for (temp = spanning_rects; temp; temp = temp->next) { MetaRectangle *compare_rect = temp->data; int maximal_overlap_amount_for_compare; /* If x is fixed and the entire width of rect doesn't fit in compare, * skip this rectangle. */ if ((fixed_directions & FIXED_DIRECTION_X) && (compare_rect->x > rect->x || compare_rect->x + compare_rect->width < rect->x + rect->width)) continue; /* If y is fixed and the entire height of rect doesn't fit in compare, * skip this rectangle. */ if ((fixed_directions & FIXED_DIRECTION_Y) && (compare_rect->y > rect->y || compare_rect->y + compare_rect->height < rect->y + rect->height)) continue; /* If compare can't hold the min_size window, skip this rectangle. */ if (compare_rect->width < min_size->width || compare_rect->height < min_size->height) continue; /* Determine maximal overlap amount */ maximal_overlap_amount_for_compare = MIN (rect->width, compare_rect->width) * MIN (rect->height, compare_rect->height); /* See if this is the best rect so far */ if (maximal_overlap_amount_for_compare > best_overlap) { best_rect = compare_rect; best_overlap = maximal_overlap_amount_for_compare; } } /* Clamp rect appropriately */ if (best_rect == NULL) { meta_warning ("No rect whose size to clamp to found!\n"); /* If it doesn't fit, at least make it no bigger than it has to be */ if (!(fixed_directions & FIXED_DIRECTION_X)) rect->width = min_size->width; if (!(fixed_directions & FIXED_DIRECTION_Y)) rect->height = min_size->height; } else { rect->width = MIN (rect->width, best_rect->width); rect->height = MIN (rect->height, best_rect->height); } } LOCAL_SYMBOL void meta_rectangle_clip_to_region (const GList *spanning_rects, FixedDirections fixed_directions, MetaRectangle *rect) { const GList *temp; const MetaRectangle *best_rect = NULL; int best_overlap = 0; /* First, find best rectangle from spanning_rects to which we will clip * rect into. */ for (temp = spanning_rects; temp; temp = temp->next) { MetaRectangle *compare_rect = temp->data; MetaRectangle overlap; int maximal_overlap_amount_for_compare; /* If x is fixed and the entire width of rect doesn't fit in compare, * skip the rectangle. */ if ((fixed_directions & FIXED_DIRECTION_X) && (compare_rect->x > rect->x || compare_rect->x + compare_rect->width < rect->x + rect->width)) continue; /* If y is fixed and the entire height of rect doesn't fit in compare, * skip the rectangle. */ if ((fixed_directions & FIXED_DIRECTION_Y) && (compare_rect->y > rect->y || compare_rect->y + compare_rect->height < rect->y + rect->height)) continue; /* Determine maximal overlap amount */ meta_rectangle_intersect (rect, compare_rect, &overlap); maximal_overlap_amount_for_compare = meta_rectangle_area (&overlap); /* See if this is the best rect so far */ if (maximal_overlap_amount_for_compare > best_overlap) { best_rect = compare_rect; best_overlap = maximal_overlap_amount_for_compare; } } /* Clip rect appropriately */ if (best_rect == NULL) meta_warning ("No rect to clip to found!\n"); else { /* Extra precaution with checking fixed direction shouldn't be needed * due to logic above, but it shouldn't hurt either. */ if (!(fixed_directions & FIXED_DIRECTION_X)) { /* Find the new left and right */ int new_x = MAX (rect->x, best_rect->x); rect->width = MIN ((rect->x + rect->width) - new_x, (best_rect->x + best_rect->width) - new_x); rect->x = new_x; } /* Extra precaution with checking fixed direction shouldn't be needed * due to logic above, but it shouldn't hurt either. */ if (!(fixed_directions & FIXED_DIRECTION_Y)) { /* Clip the top, if needed */ int new_y = MAX (rect->y, best_rect->y); rect->height = MIN ((rect->y + rect->height) - new_y, (best_rect->y + best_rect->height) - new_y); rect->y = new_y; } } } LOCAL_SYMBOL void meta_rectangle_shove_into_region (const GList *spanning_rects, FixedDirections fixed_directions, MetaRectangle *rect) { const GList *temp; const MetaRectangle *best_rect = NULL; int best_overlap = 0; int shortest_distance = G_MAXINT; /* First, find best rectangle from spanning_rects to which we will shove * rect into. */ for (temp = spanning_rects; temp; temp = temp->next) { MetaRectangle *compare_rect = temp->data; int maximal_overlap_amount_for_compare; int dist_to_compare; /* If x is fixed and the entire width of rect doesn't fit in compare, * skip this rectangle. */ if ((fixed_directions & FIXED_DIRECTION_X) && (compare_rect->x > rect->x || compare_rect->x + compare_rect->width < rect->x + rect->width)) continue; /* If y is fixed and the entire height of rect doesn't fit in compare, * skip this rectangle. */ if ((fixed_directions & FIXED_DIRECTION_Y) && (compare_rect->y > rect->y || compare_rect->y + compare_rect->height < rect->y + rect->height)) continue; /* Determine maximal overlap amount between rect & compare_rect */ maximal_overlap_amount_for_compare = MIN (rect->width, compare_rect->width) * MIN (rect->height, compare_rect->height); /* Determine distance necessary to put rect into compare_rect */ dist_to_compare = 0; if (compare_rect->x > rect->x) dist_to_compare += compare_rect->x - rect->x; if (compare_rect->x + compare_rect->width < rect->x + rect->width) dist_to_compare += (rect->x + rect->width) - (compare_rect->x + compare_rect->width); if (compare_rect->y > rect->y) dist_to_compare += compare_rect->y - rect->y; if (compare_rect->y + compare_rect->height < rect->y + rect->height) dist_to_compare += (rect->y + rect->height) - (compare_rect->y + compare_rect->height); /* See if this is the best rect so far */ if ((maximal_overlap_amount_for_compare > best_overlap) || (maximal_overlap_amount_for_compare == best_overlap && dist_to_compare < shortest_distance)) { best_rect = compare_rect; best_overlap = maximal_overlap_amount_for_compare; shortest_distance = dist_to_compare; } } /* Shove rect appropriately */ if (best_rect == NULL) meta_warning ("No rect to shove into found!\n"); else { /* Extra precaution with checking fixed direction shouldn't be needed * due to logic above, but it shouldn't hurt either. */ if (!(fixed_directions & FIXED_DIRECTION_X)) { /* Shove to the right, if needed */ if (best_rect->x > rect->x) rect->x = best_rect->x; /* Shove to the left, if needed */ if (best_rect->x + best_rect->width < rect->x + rect->width) rect->x = (best_rect->x + best_rect->width) - rect->width; } /* Extra precaution with checking fixed direction shouldn't be needed * due to logic above, but it shouldn't hurt either. */ if (!(fixed_directions & FIXED_DIRECTION_Y)) { /* Shove down, if needed */ if (best_rect->y > rect->y) rect->y = best_rect->y; /* Shove up, if needed */ if (best_rect->y + best_rect->height < rect->y + rect->height) rect->y = (best_rect->y + best_rect->height) - rect->height; } } } LOCAL_SYMBOL void meta_rectangle_find_linepoint_closest_to_point (double x1, double y1, double x2, double y2, double px, double py, double *valx, double *valy) { /* I'll use the shorthand rx, ry for the return values, valx & valy. * Now, we need (rx,ry) to be on the line between (x1,y1) and (x2,y2). * For that to happen, we first need the slope of the line from (x1,y1) * to (rx,ry) must match the slope of (x1,y1) to (x2,y2), i.e.: * (ry-y1) (y2-y1) * ------- = ------- * (rx-x1) (x2-x1) * If x1==x2, though, this gives divide by zero errors, so we want to * rewrite the equation by multiplying both sides by (rx-x1)*(x2-x1): * (ry-y1)(x2-x1) = (y2-y1)(rx-x1) * This is a valid requirement even when x1==x2 (when x1==x2, this latter * equation will basically just mean that rx must be equal to both x1 and * x2) * * The other requirement that we have is that the line from (rx,ry) to * (px,py) must be perpendicular to the line from (x1,y1) to (x2,y2). So * we just need to get a vector in the direction of each line, take the * dot product of the two, and ensure that the result is 0: * (rx-px)*(x2-x1) + (ry-py)*(y2-y1) = 0. * * This gives us two equations and two unknowns: * * (ry-y1)(x2-x1) = (y2-y1)(rx-x1) * (rx-px)*(x2-x1) + (ry-py)*(y2-y1) = 0. * * This particular pair of equations is always solvable so long as * (x1,y1) and (x2,y2) are not the same point (and note that anyone who * calls this function that way is braindead because it means that they * really didn't specify a line after all). However, the caller should * be careful to avoid making (x1,y1) and (x2,y2) too close (e.g. like * 10^{-8} apart in each coordinate), otherwise roundoff error could * cause issues. Solving these equations by hand (or using Maple(TM) or * Mathematica(TM) or whatever) results in slightly messy expressions, * but that's all the below few lines do. */ double diffx, diffy, den; diffx = x2 - x1; diffy = y2 - y1; den = diffx * diffx + diffy * diffy; *valx = (py * diffx * diffy + px * diffx * diffx + y2 * x1 * diffy - y1 * x2 * diffy) / den; *valy = (px * diffx * diffy + py * diffy * diffy + x2 * y1 * diffx - x1 * y2 * diffx) / den; } /***************************************************************************/ /* */ /* Switching gears to code for edges instead of just rectangles */ /* */ /***************************************************************************/ LOCAL_SYMBOL gboolean meta_rectangle_edge_aligns (const MetaRectangle *rect, const MetaEdge *edge) { /* The reason for the usage of <= below instead of < is because we are * interested in in-the-way-or-adject'ness. So, a left (i.e. vertical * edge) occupying y positions 0-9 (which has a y of 0 and a height of * 10) and a rectangle with top at y=10 would be considered to "align" by * this function. */ switch (edge->side_type) { case META_SIDE_LEFT: case META_SIDE_RIGHT: return BOX_TOP (*rect) <= BOX_BOTTOM (edge->rect) && BOX_TOP (edge->rect) <= BOX_BOTTOM (*rect); case META_SIDE_TOP: case META_SIDE_BOTTOM: return BOX_LEFT (*rect) <= BOX_RIGHT (edge->rect) && BOX_LEFT (edge->rect) <= BOX_RIGHT (*rect); default: g_assert_not_reached (); } } static GList* get_rect_minus_overlap (const GList *rect_in_list, MetaRectangle *overlap) { MetaRectangle *temp; MetaRectangle *rect = rect_in_list->data; GList *ret = NULL; if (BOX_LEFT (*rect) < BOX_LEFT (*overlap)) { temp = g_new (MetaRectangle, 1); *temp = *rect; temp->width = BOX_LEFT (*overlap) - BOX_LEFT (*rect); ret = g_list_prepend (ret, temp); } if (BOX_RIGHT (*rect) > BOX_RIGHT (*overlap)) { temp = g_new (MetaRectangle, 1); *temp = *rect; temp->x = BOX_RIGHT (*overlap); temp->width = BOX_RIGHT (*rect) - BOX_RIGHT (*overlap); ret = g_list_prepend (ret, temp); } if (BOX_TOP (*rect) < BOX_TOP (*overlap)) { temp = g_new (MetaRectangle, 1); temp->x = overlap->x; temp->width = overlap->width; temp->y = BOX_TOP (*rect); temp->height = BOX_TOP (*overlap) - BOX_TOP (*rect); ret = g_list_prepend (ret, temp); } if (BOX_BOTTOM (*rect) > BOX_BOTTOM (*overlap)) { temp = g_new (MetaRectangle, 1); temp->x = overlap->x; temp->width = overlap->width; temp->y = BOX_BOTTOM (*overlap); temp->height = BOX_BOTTOM (*rect) - BOX_BOTTOM (*overlap); ret = g_list_prepend (ret, temp); } return ret; } static GList* replace_rect_with_list (GList *old_element, GList *new_list) { GList *ret; g_assert (old_element != NULL); if (!new_list) { /* If there is no new list, just remove the old_element */ ret = g_list_remove_link (old_element, old_element); } else { /* Fix up the prev and next pointers everywhere */ ret = new_list; if (old_element->prev) { old_element->prev->next = new_list; new_list->prev = old_element->prev; } if (old_element->next) { GList *tmp = g_list_last (new_list); old_element->next->prev = tmp; tmp->next = old_element->next; } } /* Free the old_element and return the appropriate "next" point */ free (old_element->data); g_list_free_1 (old_element); return ret; } /* Make a copy of the strut list, make sure that copy only contains parts * of the old_struts that intersect with the region rect, and then do some * magic to make all the new struts disjoint (okay, we we break up struts * that aren't disjoint in a way that the overlapping part is only included * once, so it's not really magic...). */ static GList* get_disjoint_strut_rect_list_in_region (const GSList *old_struts, const MetaRectangle *region) { GList *strut_rects; GList *tmp; /* First, copy the list */ strut_rects = NULL; while (old_struts) { MetaRectangle *cur = &((MetaStrut*)old_struts->data)->rect; MetaRectangle *copy = g_new (MetaRectangle, 1); *copy = *cur; if (meta_rectangle_intersect (copy, region, copy)) strut_rects = g_list_prepend (strut_rects, copy); else free (copy); old_struts = old_struts->next; } /* Now, loop over the list and check for intersections, fixing things up * where they do intersect. */ tmp = strut_rects; while (tmp) { GList *compare; MetaRectangle *cur = tmp->data; compare = tmp->next; while (compare) { MetaRectangle *comp = compare->data; MetaRectangle overlap; if (meta_rectangle_intersect (cur, comp, &overlap)) { /* Get a list of rectangles for each strut that don't overlap * the intersection region. */ GList *cur_leftover = get_rect_minus_overlap (tmp, &overlap); GList *comp_leftover = get_rect_minus_overlap (compare, &overlap); /* Add the intersection region to cur_leftover */ MetaRectangle *overlap_allocated = g_new (MetaRectangle, 1); *overlap_allocated = overlap; cur_leftover = g_list_prepend (cur_leftover, overlap_allocated); /* Fix up tmp, compare, and cur -- maybe struts too */ if (strut_rects == tmp) { strut_rects = replace_rect_with_list (tmp, cur_leftover); tmp = strut_rects; } else tmp = replace_rect_with_list (tmp, cur_leftover); compare = replace_rect_with_list (compare, comp_leftover); if (compare == NULL) break; cur = tmp->data; } compare = compare->next; } tmp = tmp->next; } return strut_rects; } LOCAL_SYMBOL gint meta_rectangle_edge_cmp_ignore_type (gconstpointer a, gconstpointer b) { const MetaEdge *a_edge_rect = (gconstpointer) a; const MetaEdge *b_edge_rect = (gconstpointer) b; int a_compare, b_compare; /* Edges must be both vertical or both horizontal, or it doesn't make * sense to compare them. */ g_assert ((a_edge_rect->rect.width == 0 && b_edge_rect->rect.width == 0) || (a_edge_rect->rect.height == 0 && b_edge_rect->rect.height == 0)); a_compare = b_compare = 0; /* gcc-3.4.2 sucks at figuring initialized'ness */ if (a_edge_rect->side_type == META_SIDE_LEFT || a_edge_rect->side_type == META_SIDE_RIGHT) { a_compare = a_edge_rect->rect.x; b_compare = b_edge_rect->rect.x; if (a_compare == b_compare) { a_compare = a_edge_rect->rect.y; b_compare = b_edge_rect->rect.y; } } else if (a_edge_rect->side_type == META_SIDE_TOP || a_edge_rect->side_type == META_SIDE_BOTTOM) { a_compare = a_edge_rect->rect.y; b_compare = b_edge_rect->rect.y; if (a_compare == b_compare) { a_compare = a_edge_rect->rect.x; b_compare = b_edge_rect->rect.x; } } else g_assert ("Some idiot wanted to sort sides of different types.\n"); return a_compare - b_compare; /* positive value denotes a > b ... */ } /* To make things easily testable, provide a nice way of sorting edges */ LOCAL_SYMBOL gint meta_rectangle_edge_cmp (gconstpointer a, gconstpointer b) { const MetaEdge *a_edge_rect = (gconstpointer) a; const MetaEdge *b_edge_rect = (gconstpointer) b; int a_compare, b_compare; a_compare = a_edge_rect->side_type; b_compare = b_edge_rect->side_type; if (a_compare == b_compare) return meta_rectangle_edge_cmp_ignore_type (a, b); return a_compare - b_compare; /* positive value denotes a > b ... */ } /* Determine whether two given edges overlap */ static gboolean edges_overlap (const MetaEdge *edge1, const MetaEdge *edge2) { if (edge1->rect.width == 0 && edge2->rect.width == 0) { return meta_rectangle_vert_overlap (&edge1->rect, &edge2->rect) && edge1->rect.x == edge2->rect.x; } else if (edge1->rect.height == 0 && edge2->rect.height == 0) { return meta_rectangle_horiz_overlap (&edge1->rect, &edge2->rect) && edge1->rect.y == edge2->rect.y; } else { return FALSE; } } static gboolean rectangle_and_edge_intersection (const MetaRectangle *rect, const MetaEdge *edge, MetaEdge *overlap, int *handle_type) { const MetaRectangle *rect2 = &edge->rect; MetaRectangle *result = &overlap->rect; gboolean intersect = TRUE; /* We don't know how to set these, so set them to invalid values */ overlap->edge_type = -1; overlap->side_type = -1; /* Figure out what the intersection is */ result->x = MAX (rect->x, rect2->x); result->y = MAX (rect->y, rect2->y); result->width = MIN (BOX_RIGHT (*rect), BOX_RIGHT (*rect2)) - result->x; result->height = MIN (BOX_BOTTOM (*rect), BOX_BOTTOM (*rect2)) - result->y; /* Find out if the intersection is empty; have to do it this way since * edges have a thickness of 0 */ if ((result->width < 0 || result->height < 0) || (result->width == 0 && result->height == 0)) { result->width = 0; result->height = 0; intersect = FALSE; } else { /* Need to figure out the handle_type, a somewhat weird quantity: * 0 - overlap is in middle of rect * -1 - overlap is at the side of rect, and is on the opposite side * of rect than the edge->side_type side * 1 - overlap is at the side of rect, and the side of rect it is * on is the edge->side_type side */ switch (edge->side_type) { case META_SIDE_LEFT: if (result->x == rect->x) *handle_type = 1; else if (result->x == BOX_RIGHT (*rect)) *handle_type = -1; else *handle_type = 0; break; case META_SIDE_RIGHT: if (result->x == rect->x) *handle_type = -1; else if (result->x == BOX_RIGHT (*rect)) *handle_type = 1; else *handle_type = 0; break; case META_SIDE_TOP: if (result->y == rect->y) *handle_type = 1; else if (result->y == BOX_BOTTOM (*rect)) *handle_type = -1; else *handle_type = 0; break; case META_SIDE_BOTTOM: if (result->y == rect->y) *handle_type = -1; else if (result->y == BOX_BOTTOM (*rect)) *handle_type = 1; else *handle_type = 0; break; default: g_assert_not_reached (); } } return intersect; } /* Add all edges of the given rect to cur_edges and return the result. If * rect_is_internal is false, the side types are switched (LEFT<->RIGHT and * TOP<->BOTTOM). */ static GList* add_edges (GList *cur_edges, const MetaRectangle *rect, gboolean rect_is_internal) { MetaEdge *temp_edge; int i; for (i=0; i<4; i++) { temp_edge = g_new (MetaEdge, 1); temp_edge->rect = *rect; switch (i) { case 0: temp_edge->side_type = rect_is_internal ? META_SIDE_LEFT : META_SIDE_RIGHT; temp_edge->rect.width = 0; break; case 1: temp_edge->side_type = rect_is_internal ? META_SIDE_RIGHT : META_SIDE_LEFT; temp_edge->rect.x += temp_edge->rect.width; temp_edge->rect.width = 0; break; case 2: temp_edge->side_type = rect_is_internal ? META_SIDE_TOP : META_SIDE_BOTTOM; temp_edge->rect.height = 0; break; case 3: temp_edge->side_type = rect_is_internal ? META_SIDE_BOTTOM : META_SIDE_TOP; temp_edge->rect.y += temp_edge->rect.height; temp_edge->rect.height = 0; break; } temp_edge->edge_type = META_EDGE_SCREEN; cur_edges = g_list_prepend (cur_edges, temp_edge); } return cur_edges; } /* Remove any part of old_edge that intersects remove and add any resulting * edges to cur_list. Return cur_list when finished. */ static GList* split_edge (GList *cur_list, const MetaEdge *old_edge, const MetaEdge *remove) { MetaEdge *temp_edge; switch (old_edge->side_type) { case META_SIDE_LEFT: case META_SIDE_RIGHT: g_assert (meta_rectangle_vert_overlap (&old_edge->rect, &remove->rect)); if (BOX_TOP (old_edge->rect) < BOX_TOP (remove->rect)) { temp_edge = g_new (MetaEdge, 1); *temp_edge = *old_edge; temp_edge->rect.height = BOX_TOP (remove->rect) - BOX_TOP (old_edge->rect); cur_list = g_list_prepend (cur_list, temp_edge); } if (BOX_BOTTOM (old_edge->rect) > BOX_BOTTOM (remove->rect)) { temp_edge = g_new (MetaEdge, 1); *temp_edge = *old_edge; temp_edge->rect.y = BOX_BOTTOM (remove->rect); temp_edge->rect.height = BOX_BOTTOM (old_edge->rect) - BOX_BOTTOM (remove->rect); cur_list = g_list_prepend (cur_list, temp_edge); } break; case META_SIDE_TOP: case META_SIDE_BOTTOM: g_assert (meta_rectangle_horiz_overlap (&old_edge->rect, &remove->rect)); if (BOX_LEFT (old_edge->rect) < BOX_LEFT (remove->rect)) { temp_edge = g_new (MetaEdge, 1); *temp_edge = *old_edge; temp_edge->rect.width = BOX_LEFT (remove->rect) - BOX_LEFT (old_edge->rect); cur_list = g_list_prepend (cur_list, temp_edge); } if (BOX_RIGHT (old_edge->rect) > BOX_RIGHT (remove->rect)) { temp_edge = g_new (MetaEdge, 1); *temp_edge = *old_edge; temp_edge->rect.x = BOX_RIGHT (remove->rect); temp_edge->rect.width = BOX_RIGHT (old_edge->rect) - BOX_RIGHT (remove->rect); cur_list = g_list_prepend (cur_list, temp_edge); } break; default: g_assert_not_reached (); } return cur_list; } /* Split up edge and remove preliminary edges from strut_edges depending on * if and how rect and edge intersect. */ static void fix_up_edges (MetaRectangle *rect, MetaEdge *edge, GList **strut_edges, GList **edge_splits, gboolean *edge_needs_removal) { MetaEdge overlap; int handle_type; if (!rectangle_and_edge_intersection (rect, edge, &overlap, &handle_type)) return; if (handle_type == 0 || handle_type == 1) { /* Put the result of removing overlap from edge into edge_splits */ *edge_splits = split_edge (*edge_splits, edge, &overlap); *edge_needs_removal = TRUE; } if (handle_type == -1 || handle_type == 1) { /* Remove the overlap from strut_edges */ /* First, loop over the edges of the strut */ GList *tmp = *strut_edges; while (tmp) { MetaEdge *cur = tmp->data; /* If this is the edge that overlaps, then we need to split it */ if (edges_overlap (cur, &overlap)) { GList *delete_me = tmp; /* Split this edge into some new ones */ *strut_edges = split_edge (*strut_edges, cur, &overlap); /* Delete the old one */ tmp = tmp->next; free (cur); *strut_edges = g_list_delete_link (*strut_edges, delete_me); } else tmp = tmp->next; } } } /** * meta_rectangle_remove_intersections_with_boxes_from_edges: (skip) * * This function removes intersections of edges with the rectangles from the * list of edges. */ LOCAL_SYMBOL GList* meta_rectangle_remove_intersections_with_boxes_from_edges ( GList *edges, const GSList *rectangles) { const GSList *rect_iter; const int opposing = 1; /* Now remove all intersections of rectangles with the edge list */ rect_iter = rectangles; while (rect_iter) { MetaRectangle *rect = rect_iter->data; GList *edge_iter = edges; while (edge_iter) { MetaEdge *edge = edge_iter->data; MetaEdge overlap; int handle; gboolean edge_iter_advanced = FALSE; /* If this edge overlaps with this rect... */ if (rectangle_and_edge_intersection (rect, edge, &overlap, &handle)) { /* "Intersections" where the edges touch but are opposite * sides (e.g. a left edge against the right edge) should not * be split. Note that the comments in * rectangle_and_edge_intersection() say that opposing edges * occur when handle is -1, BUT you need to remember that we * treat the left side of a window as a right edge because * it's what the right side of the window being moved should * be-resisted-by/snap-to. So opposing is really 1. Anyway, * we just keep track of it in the opposing constant set up * above and if handle isn't equal to that, then we know the * edge should be split. */ if (handle != opposing) { /* Keep track of this edge so we can delete it below */ GList *delete_me = edge_iter; edge_iter = edge_iter->next; edge_iter_advanced = TRUE; /* Split the edge and add the result to beginning of edges */ edges = split_edge (edges, edge, &overlap); /* Now free the edge... */ free (edge); edges = g_list_delete_link (edges, delete_me); } } if (!edge_iter_advanced) edge_iter = edge_iter->next; } rect_iter = rect_iter->next; } return edges; } /** * meta_rectangle_find_onscreen_edges: (skip) * * This function is trying to find all the edges of an onscreen region. */ LOCAL_SYMBOL GList* meta_rectangle_find_onscreen_edges (const MetaRectangle *basic_rect, const GSList *all_struts) { GList *ret; GList *fixed_strut_rects; GList *edge_iter; const GList *strut_rect_iter; /* The algorithm is basically as follows: * Make sure the struts are disjoint * Initialize the edge_set to the edges of basic_rect * Foreach strut: * Put together a preliminary new edge from the edges of the strut * Foreach edge in edge_set: * - Split the edge if it is partially contained inside the strut * - If the edge matches an edge of the strut (i.e. a strut just * against the edge of the screen or a not-next-to-edge-of-screen * strut adjacent to another), then both the edge from the * edge_set and the preliminary edge for the strut will need to * be split * Add any remaining "preliminary" strut edges to the edge_set */ /* Make sure the struts are disjoint */ fixed_strut_rects = get_disjoint_strut_rect_list_in_region (all_struts, basic_rect); /* Start off the list with the edges of basic_rect */ ret = add_edges (NULL, basic_rect, TRUE); strut_rect_iter = fixed_strut_rects; while (strut_rect_iter) { MetaRectangle *strut_rect = (MetaRectangle*) strut_rect_iter->data; /* Get the new possible edges we may need to add from the strut */ GList *new_strut_edges = add_edges (NULL, strut_rect, FALSE); edge_iter = ret; while (edge_iter) { MetaEdge *cur_edge = edge_iter->data; GList *splits_of_cur_edge = NULL; gboolean edge_needs_removal = FALSE; fix_up_edges (strut_rect, cur_edge, &new_strut_edges, &splits_of_cur_edge, &edge_needs_removal); if (edge_needs_removal) { /* Delete the old edge */ GList *delete_me = edge_iter; edge_iter = edge_iter->next; free (cur_edge); ret = g_list_delete_link (ret, delete_me); /* Add the new split parts of the edge */ ret = g_list_concat (splits_of_cur_edge, ret); } else { edge_iter = edge_iter->next; } /* edge_iter was already advanced above */ } ret = g_list_concat (new_strut_edges, ret); strut_rect_iter = strut_rect_iter->next; } /* Sort the list */ ret = g_list_sort (ret, meta_rectangle_edge_cmp); /* Free the fixed struts list */ meta_rectangle_free_list_and_elements (fixed_strut_rects); return ret; } /** * meta_rectangle_find_nonintersected_monitor_edges: (skip) * */ LOCAL_SYMBOL GList* meta_rectangle_find_nonintersected_monitor_edges ( const GList *monitor_rects, const GSList *all_struts) { /* This function cannot easily be merged with * meta_rectangle_find_onscreen_edges() because real screen edges * and strut edges both are of the type "there ain't anything * immediately on the other side"; monitor edges are different. */ GList *ret; const GList *cur; GSList *temp_rects; /* Initialize the return list to be empty */ ret = NULL; /* start of ret with all the edges of monitors that are adjacent to * another monitor. */ cur = monitor_rects; while (cur) { MetaRectangle *cur_rect = cur->data; const GList *compare = monitor_rects; while (compare) { MetaRectangle *compare_rect = compare->data; /* Check if cur might be horizontally adjacent to compare */ if (meta_rectangle_vert_overlap(cur_rect, compare_rect)) { MetaSide side_type; int y = MAX (cur_rect->y, compare_rect->y); int height = MIN (BOX_BOTTOM (*cur_rect) - y, BOX_BOTTOM (*compare_rect) - y); int width = 0; int x; if (BOX_LEFT (*cur_rect) == BOX_RIGHT (*compare_rect)) { /* compare_rect is to the left of cur_rect */ x = BOX_LEFT (*cur_rect); side_type = META_SIDE_LEFT; } else if (BOX_RIGHT (*cur_rect) == BOX_LEFT (*compare_rect)) { /* compare_rect is to the right of cur_rect */ x = BOX_RIGHT (*cur_rect); side_type = META_SIDE_RIGHT; } else /* These rectangles aren't adjacent after all */ x = INT_MIN; /* If the rectangles really are adjacent */ if (x != INT_MIN) { /* We need a left edge for the monitor on the right, and * a right edge for the monitor on the left. Just fill * up the edges and stick 'em on the list. */ MetaEdge *new_edge = g_new (MetaEdge, 1); new_edge->rect = meta_rect (x, y, width, height); new_edge->side_type = side_type; new_edge->edge_type = META_EDGE_MONITOR; ret = g_list_prepend (ret, new_edge); } } /* Check if cur might be vertically adjacent to compare */ if (meta_rectangle_horiz_overlap(cur_rect, compare_rect)) { MetaSide side_type; int x = MAX (cur_rect->x, compare_rect->x); int width = MIN (BOX_RIGHT (*cur_rect) - x, BOX_RIGHT (*compare_rect) - x); int height = 0; int y; if (BOX_TOP (*cur_rect) == BOX_BOTTOM (*compare_rect)) { /* compare_rect is to the top of cur_rect */ y = BOX_TOP (*cur_rect); side_type = META_SIDE_TOP; } else if (BOX_BOTTOM (*cur_rect) == BOX_TOP (*compare_rect)) { /* compare_rect is to the bottom of cur_rect */ y = BOX_BOTTOM (*cur_rect); side_type = META_SIDE_BOTTOM; } else /* These rectangles aren't adjacent after all */ y = INT_MIN; /* If the rectangles really are adjacent */ if (y != INT_MIN) { /* We need a top edge for the monitor on the bottom, and * a bottom edge for the monitor on the top. Just fill * up the edges and stick 'em on the list. */ MetaEdge *new_edge = g_new (MetaEdge, 1); new_edge->rect = meta_rect (x, y, width, height); new_edge->side_type = side_type; new_edge->edge_type = META_EDGE_MONITOR; ret = g_list_prepend (ret, new_edge); } } compare = compare->next; } cur = cur->next; } temp_rects = NULL; for (; all_struts; all_struts = all_struts->next) temp_rects = g_slist_prepend (temp_rects, &((MetaStrut*)all_struts->data)->rect); ret = meta_rectangle_remove_intersections_with_boxes_from_edges (ret, temp_rects); g_slist_free (temp_rects); /* Sort the list */ ret = g_list_sort (ret, meta_rectangle_edge_cmp); return ret; } �����������������������������������������������������������������������������������������muffin-5.2.1/src/core/keybindings-private.h���������������������������������������������������������0000664�0001750�0001750�00000007244�14211404421�021011� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file keybindings.h Grab and ungrab keys, and process the key events * * Performs global X grabs on the keys we need to be told about, like * the one to close a window. It also deals with incoming key events. */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_KEYBINDINGS_PRIVATE_H #define META_KEYBINDINGS_PRIVATE_H #include <meta/keybindings.h> struct _MetaKeyHandler { char *name; MetaKeyHandlerFunc func; MetaKeyHandlerFunc default_func; gint data, flags, action; gpointer user_data; GDestroyNotify user_data_free_func; }; struct _MetaKeyBinding { const char *name; KeySym keysym; KeyCode keycode; unsigned int mask; MetaVirtualModifier modifiers; MetaKeyHandler *handler; }; void meta_display_init_keys (MetaDisplay *display); void meta_display_shutdown_keys (MetaDisplay *display); void meta_screen_grab_keys (MetaScreen *screen); void meta_screen_ungrab_keys (MetaScreen *screen); void meta_window_grab_keys (MetaWindow *window); void meta_window_ungrab_keys (MetaWindow *window); gboolean meta_window_grab_all_keys (MetaWindow *window, guint32 timestamp); void meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp); gboolean meta_window_resize_or_move_allowed (MetaWindow *window, MetaDirection dir); gboolean meta_display_grabbed_event_is_action (MetaDisplay *display, XEvent *event, MetaKeyBindingAction action); gboolean meta_display_process_key_event (MetaDisplay *display, MetaWindow *window, XEvent *event); void meta_set_keybindings_disabled (gboolean setting); void meta_display_process_mapping_event (MetaDisplay *display, XEvent *event); gboolean meta_prefs_add_keybinding (const char *name, const char *schema, MetaKeyBindingAction action, MetaKeyBindingFlags flags); gboolean meta_prefs_remove_keybinding (const char *name); gboolean meta_prefs_add_custom_keybinding (const char *name, const char **binding, MetaKeyBindingAction action, MetaKeyBindingFlags flags); gboolean meta_prefs_remove_custom_keybinding (const char *name); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/place.c�����������������������������������������������������������������������0000664�0001750�0001750�00000073711�14211404421�016114� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window placement */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2003 Rob Adams * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "boxes-private.h" #include "place.h" #include <meta/workspace.h> #include <meta/prefs.h> #include <gdk/gdk.h> #include <math.h> #include <stdlib.h> typedef enum { META_LEFT, META_RIGHT, META_TOP, META_BOTTOM } MetaWindowDirection; static gint northwestcmp (gconstpointer a, gconstpointer b) { MetaWindow *aw = (gpointer) a; MetaWindow *bw = (gpointer) b; int from_origin_a; int from_origin_b; int ax, ay, bx, by; /* we're interested in the frame position for cascading, * not meta_window_get_position() */ if (aw->frame) { ax = aw->frame->rect.x; ay = aw->frame->rect.y; } else { ax = aw->rect.x; ay = aw->rect.y; } if (bw->frame) { bx = bw->frame->rect.x; by = bw->frame->rect.y; } else { bx = bw->rect.x; by = bw->rect.y; } /* probably there's a fast good-enough-guess we could use here. */ from_origin_a = sqrt (ax * ax + ay * ay); from_origin_b = sqrt (bx * bx + by * by); if (from_origin_a < from_origin_b) return -1; else if (from_origin_a > from_origin_b) return 1; else return 0; } static gboolean place_by_pointer(MetaWindow *window, MetaFrameBorders *borders, MetaPlacementMode placement_mode, int *new_x, int *new_y) { int window_width, window_height; Window root_return, child_return; int root_x_return, root_y_return; int win_x_return, win_y_return; unsigned int mask_return; XQueryPointer (window->display->xdisplay, window->screen->xroot, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); window_width = window->frame ? window->frame->rect.width : window->rect.width; window_height = window->frame ? window->frame->rect.height : window->rect.height; if (borders) { *new_x = root_x_return + borders->visible.left - window_width / 2; *new_y = root_y_return + borders->visible.top - window_height / 2; } else { *new_x = root_x_return - window_width / 2; *new_y = root_y_return - window_height / 2; } if (placement_mode == META_PLACEMENT_MODE_MANUAL) window->move_after_placement = TRUE; return TRUE; } static gboolean place_in_center (MetaWindow *window, MetaFrameBorders *borders, MetaPlacementMode placement_mode, int *new_x, int *new_y) { int center_x, center_y, monitor_n; MetaRectangle work_area, outer_rect; monitor_n = meta_screen_get_current_monitor (window->screen); meta_window_get_work_area_for_monitor (window, monitor_n, &work_area); meta_window_get_input_rect (window, &outer_rect); center_x = work_area.x + work_area.width / 2; center_y = work_area.y + work_area.height / 2; *new_x = center_x - (window->rect.width / 2); *new_y = center_y - (outer_rect.height / 2) + borders->visible.top + borders->invisible.top; return TRUE; } static void find_next_cascade (MetaWindow *window, MetaFrameBorders *borders, /* visible windows on relevant workspaces */ GList *windows, int x, int y, int *new_x, int *new_y) { GList *tmp; GList *sorted; int cascade_x, cascade_y; MetaRectangle titlebar_rect; int x_threshold, y_threshold; int window_width, window_height; int cascade_stage; MetaRectangle work_area; int current; sorted = g_list_copy (windows); sorted = g_list_sort (sorted, northwestcmp); /* This is a "fuzzy" cascade algorithm. * For each window in the list, we find where we'd cascade a * new window after it. If a window is already nearly at that * position, we move on. */ /* arbitrary-ish threshold, honors user attempts to * manually cascade. */ #define CASCADE_FUZZ 15 meta_window_get_titlebar_rect (window, &titlebar_rect); x_threshold = MAX (titlebar_rect.x, CASCADE_FUZZ); y_threshold = MAX (titlebar_rect.y, CASCADE_FUZZ); /* Find furthest-SE origin of all workspaces. * cascade_x, cascade_y are the target position * of NW corner of window frame. */ current = meta_screen_get_current_monitor (window->screen); meta_window_get_work_area_for_monitor (window, current, &work_area); cascade_x = MAX (0, work_area.x); cascade_y = MAX (0, work_area.y); /* Find first cascade position that's not used. */ window_width = window->frame ? window->frame->rect.width : window->rect.width; window_height = window->frame ? window->frame->rect.height : window->rect.height; cascade_stage = 0; tmp = sorted; while (tmp != NULL) { MetaWindow *w; int wx, wy; w = tmp->data; /* we want frame position, not window position */ if (w->frame) { wx = w->frame->rect.x; wy = w->frame->rect.y; } else { wx = w->rect.x; wy = w->rect.y; } if (ABS (wx - cascade_x) < x_threshold && ABS (wy - cascade_y) < y_threshold) { /* This window is "in the way", move to next cascade * point. The new window frame should go at the origin * of the client window we're stacking above. */ meta_window_get_titlebar_rect (w, &titlebar_rect); /* Cascade the window evenly by the titlebar height; this isn't a typo. */ cascade_x = wx + titlebar_rect.height; cascade_y = wy + titlebar_rect.height; /* If we go off the screen, start over with a new cascade */ if (((cascade_x + window_width) > (work_area.x + work_area.width)) || ((cascade_y + window_height) > (work_area.y + work_area.height))) { cascade_x = MAX (0, work_area.x); cascade_y = MAX (0, work_area.y); #define CASCADE_INTERVAL 50 /* space between top-left corners of cascades */ cascade_stage += 1; cascade_x += CASCADE_INTERVAL * cascade_stage; /* start over with a new cascade translated to the right, unless * we are out of space */ if ((cascade_x + window_width) < (work_area.x + work_area.width)) { tmp = sorted; continue; } else { /* All out of space, this cascade_x won't work */ cascade_x = MAX (0, work_area.x); break; } } } else { /* Keep searching for a further-down-the-diagonal window. */ } tmp = tmp->next; } /* cascade_x and cascade_y will match the last window in the list * that was "in the way" (in the approximate cascade diagonal) */ g_list_free (sorted); /* Convert coords to position of window, not position of frame. */ if (borders == NULL) { *new_x = cascade_x; *new_y = cascade_y; } else { *new_x = cascade_x + borders->visible.left; *new_y = cascade_y + borders->visible.top; } } static void find_most_freespace (MetaWindow *window, MetaFrameBorders *borders, /* visible windows on relevant workspaces */ MetaWindow *focus_window, int x, int y, int *new_x, int *new_y) { MetaWindowDirection side; int max_area; int max_width, max_height, left, right, top, bottom; int left_space, right_space, top_space, bottom_space; int frame_size_left, frame_size_top; MetaRectangle work_area; MetaRectangle avoid; MetaRectangle outer; frame_size_left = borders ? borders->visible.left : 0; frame_size_top = borders ? borders->visible.top : 0; meta_window_get_work_area_current_monitor (focus_window, &work_area); meta_window_get_outer_rect (focus_window, &avoid); meta_window_get_outer_rect (window, &outer); /* Find the areas of choosing the various sides of the focus window */ max_width = MIN (avoid.width, outer.width); max_height = MIN (avoid.height, outer.height); left_space = avoid.x - work_area.x; right_space = work_area.width - (avoid.x + avoid.width - work_area.x); top_space = avoid.y - work_area.y; bottom_space = work_area.height - (avoid.y + avoid.height - work_area.y); left = MIN (left_space, outer.width); right = MIN (right_space, outer.width); top = MIN (top_space, outer.height); bottom = MIN (bottom_space, outer.height); /* Find out which side of the focus_window can show the most of the window */ side = META_LEFT; max_area = left*max_height; if (right*max_height > max_area) { side = META_RIGHT; max_area = right*max_height; } if (top*max_width > max_area) { side = META_TOP; max_area = top*max_width; } if (bottom*max_width > max_area) { side = META_BOTTOM; max_area = bottom*max_width; } /* Give up if there's no where to put it (i.e. focus window is maximized) */ if (max_area == 0) return; /* Place the window on the relevant side; if the whole window fits, * make it adjacent to the focus window; if not, make sure the * window doesn't go off the edge of the screen. */ switch (side) { case META_LEFT: *new_y = avoid.y + frame_size_top; if (left_space > outer.width) *new_x = avoid.x - outer.width + frame_size_left; else *new_x = work_area.x + frame_size_left; break; case META_RIGHT: *new_y = avoid.y + frame_size_top; if (right_space > outer.width) *new_x = avoid.x + avoid.width + frame_size_left; else *new_x = work_area.x + work_area.width - outer.width + frame_size_left; break; case META_TOP: *new_x = avoid.x + frame_size_left; if (top_space > outer.height) *new_y = avoid.y - outer.height + frame_size_top; else *new_y = work_area.y + frame_size_top; break; case META_BOTTOM: *new_x = avoid.x + frame_size_left; if (bottom_space > outer.height) *new_y = avoid.y + avoid.height + frame_size_top; else *new_y = work_area.y + work_area.height - outer.height + frame_size_top; break; } } static void avoid_being_obscured_as_second_modal_dialog (MetaWindow *window, MetaFrameBorders *borders, int *x, int *y) { /* We can't center this dialog if it was denied focus and it * overlaps with the focus window and this dialog is modal and this * dialog is in the same app as the focus window (*phew*...please * don't make me say that ten times fast). See bug 307875 comment 11 * and 12 for details, but basically it means this is probably a * second modal dialog for some app while the focus window is the * first modal dialog. We should probably make them simultaneously * visible in general, but it becomes mandatory to do so due to * buggy apps (e.g. those using gtk+ *sigh*) because in those cases * this second modal dialog also happens to be modal to the first * dialog in addition to the main window, while it has only let us * know about the modal-to-the-main-window part. */ MetaWindow *focus_window; MetaRectangle overlap; focus_window = window->display->focus_window; if (window->denied_focus_and_not_transient && window->wm_state_modal && /* FIXME: Maybe do this for all transients? */ meta_window_same_application (window, focus_window) && meta_rectangle_intersect (&window->rect, &focus_window->rect, &overlap)) { find_most_freespace (window, borders, focus_window, *x, *y, x, y); meta_topic (META_DEBUG_PLACEMENT, "Dialog window %s was denied focus but may be modal " "to the focus window; had to move it to avoid the " "focus window\n", window->desc); } } static gboolean rectangle_overlaps_some_window (MetaRectangle *rect, GList *windows) { GList *tmp; MetaRectangle dest; tmp = windows; while (tmp != NULL) { MetaWindow *other = tmp->data; MetaRectangle other_rect; switch (other->type) { case META_WINDOW_DOCK: case META_WINDOW_SPLASHSCREEN: case META_WINDOW_DESKTOP: case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: /* override redirect window types: */ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: break; case META_WINDOW_NORMAL: case META_WINDOW_UTILITY: case META_WINDOW_TOOLBAR: case META_WINDOW_MENU: meta_window_get_outer_rect (other, &other_rect); if (meta_rectangle_intersect (rect, &other_rect, &dest)) return TRUE; break; } tmp = tmp->next; } return FALSE; } static gint leftmost_cmp (gconstpointer a, gconstpointer b) { MetaWindow *aw = (gpointer) a; MetaWindow *bw = (gpointer) b; int ax, bx; /* we're interested in the frame position for cascading, * not meta_window_get_position() */ if (aw->frame) ax = aw->frame->rect.x; else ax = aw->rect.x; if (bw->frame) bx = bw->frame->rect.x; else bx = bw->rect.x; if (ax < bx) return -1; else if (ax > bx) return 1; else return 0; } static gint topmost_cmp (gconstpointer a, gconstpointer b) { MetaWindow *aw = (gpointer) a; MetaWindow *bw = (gpointer) b; int ay, by; /* we're interested in the frame position for cascading, * not meta_window_get_position() */ if (aw->frame) ay = aw->frame->rect.y; else ay = aw->rect.y; if (bw->frame) by = bw->frame->rect.y; else by = bw->rect.y; if (ay < by) return -1; else if (ay > by) return 1; else return 0; } static void center_tile_rect_in_area (MetaRectangle *rect, MetaRectangle *work_area) { int fluff; /* The point here is to tile a window such that "extra" * space is equal on either side (i.e. so a full screen * of windows tiled this way would center the windows * as a group) */ fluff = (work_area->width % (rect->width+1)) / 2; rect->x = work_area->x + fluff; fluff = (work_area->height % (rect->height+1)) / 3; rect->y = work_area->y + fluff; } /* Find the leftmost, then topmost, empty area on the workspace * that can contain the new window. * * Cool feature to have: if we can't fit the current window size, * try shrinking the window (within geometry constraints). But * beware windows such as Emacs with no sane minimum size, we * don't want to create a 1x1 Emacs. */ static gboolean find_first_fit (MetaWindow *window, MetaFrameBorders *borders, /* visible windows on relevant workspaces */ GList *windows, int monitor, int x, int y, int *new_x, int *new_y) { /* This algorithm is limited - it just brute-force tries * to fit the window in a small number of locations that are aligned * with existing windows. It tries to place the window on * the bottom of each existing window, and then to the right * of each existing window, aligned with the left/top of the * existing window in each of those cases. */ int retval; GList *below_sorted; GList *right_sorted; GList *tmp; MetaRectangle rect; MetaRectangle work_area; retval = FALSE; /* Below each window */ below_sorted = g_list_copy (windows); below_sorted = g_list_sort (below_sorted, leftmost_cmp); below_sorted = g_list_sort (below_sorted, topmost_cmp); /* To the right of each window */ right_sorted = g_list_copy (windows); right_sorted = g_list_sort (right_sorted, topmost_cmp); right_sorted = g_list_sort (right_sorted, leftmost_cmp); rect.width = window->rect.width; rect.height = window->rect.height; if (borders) { rect.width += borders->visible.left + borders->visible.right; rect.height += borders->visible.top + borders->visible.bottom; } #ifdef WITH_VERBOSE_MODE { char monitor_location_string[RECT_LENGTH]; meta_rectangle_to_string (&window->screen->monitor_infos[monitor].rect, monitor_location_string); meta_topic (META_DEBUG_XINERAMA, "Natural monitor is %s\n", monitor_location_string); } #endif meta_window_get_work_area_for_monitor (window, monitor, &work_area); center_tile_rect_in_area (&rect, &work_area); if (meta_rectangle_contains_rect (&work_area, &rect) && !rectangle_overlaps_some_window (&rect, windows)) { *new_x = rect.x; *new_y = rect.y; if (borders) { *new_x += borders->visible.left; *new_y += borders->visible.top; } retval = TRUE; goto out; } /* try below each window */ tmp = below_sorted; while (tmp != NULL) { MetaWindow *w = tmp->data; MetaRectangle outer_rect; meta_window_get_outer_rect (w, &outer_rect); rect.x = outer_rect.x; rect.y = outer_rect.y + outer_rect.height; if (meta_rectangle_contains_rect (&work_area, &rect) && !rectangle_overlaps_some_window (&rect, below_sorted)) { *new_x = rect.x; *new_y = rect.y; if (borders) { *new_x += borders->visible.left; *new_y += borders->visible.top; } retval = TRUE; goto out; } tmp = tmp->next; } /* try to the right of each window */ tmp = right_sorted; while (tmp != NULL) { MetaWindow *w = tmp->data; MetaRectangle outer_rect; meta_window_get_outer_rect (w, &outer_rect); rect.x = outer_rect.x + outer_rect.width; rect.y = outer_rect.y; if (meta_rectangle_contains_rect (&work_area, &rect) && !rectangle_overlaps_some_window (&rect, right_sorted)) { *new_x = rect.x; *new_y = rect.y; if (borders) { *new_x += borders->visible.left; *new_y += borders->visible.top; } retval = TRUE; goto out; } tmp = tmp->next; } out: g_list_free (below_sorted); g_list_free (right_sorted); return retval; } LOCAL_SYMBOL void meta_window_place (MetaWindow *window, MetaFrameBorders *borders, int x, int y, int *new_x, int *new_y) { GList *windows; const MetaMonitorInfo *xi; MetaPlacementMode placement_mode; MetaWindow *parent; /* frame member variables should NEVER be used in here, only * MetaFrameBorders. But remember borders == NULL * for undecorated windows. Also, this function should * NEVER have side effects other than computing the * placement coordinates. */ meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc); windows = NULL; parent = meta_display_lookup_x_window (window->display, window->xtransient_for); switch (window->type) { /* Run placement algorithm on these. */ case META_WINDOW_NORMAL: case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: case META_WINDOW_SPLASHSCREEN: break; /* Assume the app knows best how to place these, no placement * algorithm ever (other than "leave them as-is") */ case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_TOOLBAR: case META_WINDOW_MENU: case META_WINDOW_UTILITY: /* override redirect window types: */ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: goto done_no_constraints; } if (meta_prefs_get_disable_workarounds () || (parent != NULL && parent->type == META_WINDOW_DESKTOP)) { switch (window->type) { /* Only accept USPosition on normal windows because the app is full * of shit claiming the user set -geometry for a dialog or dock */ case META_WINDOW_NORMAL: if (window->size_hints.flags & USPosition) { /* don't constrain with placement algorithm */ meta_topic (META_DEBUG_PLACEMENT, "Honoring USPosition for %s instead of using placement algorithm\n", window->desc); goto done; } break; /* Ignore even USPosition on dialogs, splashscreen */ case META_WINDOW_DIALOG: case META_WINDOW_MODAL_DIALOG: case META_WINDOW_SPLASHSCREEN: break; /* Assume the app knows best how to place these. */ case META_WINDOW_DESKTOP: case META_WINDOW_DOCK: case META_WINDOW_TOOLBAR: case META_WINDOW_MENU: case META_WINDOW_UTILITY: /* override redirect window types: */ case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_DND: case META_WINDOW_OVERRIDE_OTHER: if (window->size_hints.flags & PPosition) { meta_topic (META_DEBUG_PLACEMENT, "Not placing non-normal non-dialog window with PPosition set\n"); goto done_no_constraints; } break; } } else { /* workarounds enabled */ if ((window->size_hints.flags & PPosition) || (window->size_hints.flags & USPosition)) { meta_topic (META_DEBUG_PLACEMENT, "Not placing window with PPosition or USPosition set\n"); avoid_being_obscured_as_second_modal_dialog (window, borders, &x, &y); goto done_no_constraints; } } if ((window->type == META_WINDOW_DIALOG || window->type == META_WINDOW_MODAL_DIALOG) && window->xtransient_for != None && (parent != NULL && parent->type != META_WINDOW_DESKTOP)) { /* Center horizontally, at top of parent vertically */ if (parent) { int w; meta_window_get_position (parent, &x, &y); w = parent->rect.width; /* center of parent */ x = x + w / 2; /* center of child over center of parent */ x -= window->rect.width / 2; /* "visually" center window over parent, leaving twice as * much space below as on top. */ y += (parent->rect.height - window->rect.height)/3; /* put top of child's frame, not top of child's client */ if (borders) y += borders->visible.top; meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n", window->desc); avoid_being_obscured_as_second_modal_dialog (window, borders, &x, &y); goto done; } } /* FIXME UTILITY with transient set should be stacked up * on the sides of the parent window or something. */ if (window->type == META_WINDOW_DIALOG || window->type == META_WINDOW_MODAL_DIALOG || window->type == META_WINDOW_SPLASHSCREEN) { /* Center on current monitor */ int w, h; /* Warning, this function is a round trip! */ xi = meta_screen_get_current_monitor_info (window->screen); w = xi->rect.width; h = xi->rect.height; x = (w - window->rect.width) / 2; y = (h - window->rect.height) / 2; x += xi->rect.x; y += xi->rect.y; avoid_being_obscured_as_second_modal_dialog (window, borders, &x, &y); meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d monitor %d\n", window->desc, window->screen->number, xi->number); goto done_check_denied_focus; } /* Find windows that matter (not minimized, on same workspace * as placed window, may be shaded - if shaded we pretend it isn't * for placement purposes) */ { GSList *all_windows; GSList *tmp; all_windows = meta_display_list_windows (window->display, META_LIST_DEFAULT); tmp = all_windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (meta_window_showing_on_its_workspace (w) && w != window && (window->workspace == w->workspace || window->on_all_workspaces || w->on_all_workspaces)) windows = g_list_prepend (windows, w); tmp = tmp->next; } g_slist_free (all_windows); } /* Warning, this is a round trip! */ xi = meta_screen_get_current_monitor_info (window->screen); /* "Origin" placement algorithm */ x = xi->rect.x; y = xi->rect.y; /* Placement based on pointer position */ placement_mode = meta_prefs_get_placement_mode(); if (placement_mode == META_PLACEMENT_MODE_POINTER || placement_mode == META_PLACEMENT_MODE_MANUAL) { if (place_by_pointer (window, borders, placement_mode, &x, &y)) goto done_check_denied_focus; } else if (placement_mode == META_PLACEMENT_MODE_CENTER) { if (place_in_center (window, borders, placement_mode, &x, &y)) goto done_check_denied_focus; } if (find_first_fit (window, borders, windows, xi->number, x, y, &x, &y)) goto done_check_denied_focus; /* Maximize windows if they are too big for their work area (bit of * a hack here). Assume undecorated windows probably don't intend to * be maximized. */ if (window->has_maximize_func && window->decorated && !window->fullscreen) { MetaRectangle workarea; MetaRectangle outer; meta_window_get_work_area_for_monitor (window, xi->number, &workarea); meta_window_get_outer_rect (window, &outer); /* If the window is bigger than the screen, then automaximize. Do NOT * auto-maximize the directions independently. See #419810. */ if (outer.width >= workarea.width && outer.height >= workarea.height) { window->maximize_horizontally_after_placement = TRUE; window->maximize_vertically_after_placement = TRUE; } } /* If no placement has been done, revert to cascade to avoid * fully overlapping window (e.g. starting multiple terminals) * */ if (x == xi->rect.x && y == xi->rect.y) find_next_cascade (window, borders, windows, x, y, &x, &y); done_check_denied_focus: /* If the window is being denied focus and isn't a transient of the * focus window, we do NOT want it to overlap with the focus window * if at all possible. This is guaranteed to only be called if the * focus_window is non-NULL, and we try to avoid that window. */ if (window->denied_focus_and_not_transient) { gboolean found_fit; MetaWindow *focus_window; MetaRectangle overlap; focus_window = window->display->focus_window; g_assert (focus_window != NULL); /* No need to do anything if the window doesn't overlap at all */ found_fit = !meta_rectangle_intersect (&window->rect, &focus_window->rect, &overlap); /* Try to do a first fit again, this time only taking into account the * focus window. */ if (!found_fit) { GList *focus_window_list; focus_window_list = g_list_prepend (NULL, focus_window); /* Reset x and y ("origin" placement algorithm) */ x = xi->rect.x; y = xi->rect.y; found_fit = find_first_fit (window, borders, focus_window_list, xi->number, x, y, &x, &y); g_list_free (focus_window_list); } /* If that still didn't work, just place it where we can see as much * as possible. */ if (!found_fit) find_most_freespace (window, borders, focus_window, x, y, &x, &y); } done: g_list_free (windows); done_no_constraints: *new_x = x; *new_y = y; } �������������������������������������������������������muffin-5.2.1/src/core/constraints.h�����������������������������������������������������������������0000664�0001750�0001750�00000003164�14211404421�017377� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin size/position constraints */ /* * Copyright (C) 2002 Red Hat, Inc. * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_CONSTRAINTS_H #define META_CONSTRAINTS_H #include <meta/util.h> #include "window-private.h" #include "frame.h" typedef enum { META_IS_CONFIGURE_REQUEST = 1 << 0, META_DO_GRAVITY_ADJUST = 1 << 1, META_IS_USER_ACTION = 1 << 2, META_IS_MOVE_ACTION = 1 << 3, META_IS_RESIZE_ACTION = 1 << 4 } MetaMoveResizeFlags; void meta_window_constrain (MetaWindow *window, MetaFrameBorders *orig_borders, MetaMoveResizeFlags flags, int resize_gravity, const MetaRectangle *orig, MetaRectangle *new); #endif /* META_CONSTRAINTS_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/delete.c����������������������������������������������������������������������0000664�0001750�0001750�00000017441�14211404421�016270� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window deletion */ /* * Copyright (C) 2001, 2002 Havoc Pennington * Copyright (C) 2004 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #define _XOPEN_SOURCE /* for kill() */ #include <config.h> #include "util-private.h" #include "window-private.h" #include <meta/errors.h> #include <meta/workspace.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <stdio.h> static void meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp); static void delete_ping_reply_func (MetaDisplay *display, Window xwindow, guint32 timestamp, void *user_data) { meta_topic (META_DEBUG_PING, "Got reply to delete ping for %s\n", ((MetaWindow*)user_data)->desc); /* we do nothing */ } static void dialog_exited (GPid pid, int status, gpointer user_data) { MetaWindow *ours = (MetaWindow*) user_data; ours->dialog_pid = -1; /* exit status of 1 means the user pressed "Force Quit" */ if (WIFEXITED (status) && WEXITSTATUS (status) == 1) meta_window_kill (ours); } static void delete_ping_timeout_func (MetaDisplay *display, Window xwindow, guint32 timestamp, void *user_data) { MetaWindow *window = user_data; char *window_title; gchar *window_content, *tmp; GPid dialog_pid; meta_topic (META_DEBUG_PING, "Got delete ping timeout for %s\n", window->desc); if (window->dialog_pid >= 0) { meta_window_present_delete_dialog (window, timestamp); return; } /* This is to get a better string if the title isn't representable * in the locale encoding; actual conversion to UTF-8 is done inside * meta_show_dialog */ if (window->title && window->title[0]) { tmp = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL); if (tmp == NULL) window_title = NULL; else window_title = window->title; free (tmp); } else { window_title = NULL; } /* Translators: %s is a window title */ if (window_title) { // FIXME: Didn't want to lose translations for this.. needed to remove the // monospace tt but it's part of the translation. Cancel them out for now. gchar *unmarkup_title = g_markup_printf_escaped("</tt>%s<tt>", window_title); tmp = g_strdup_printf (_("<tt>%s</tt> is not responding."), unmarkup_title); free (unmarkup_title); } else tmp = g_strdup (_("Application is not responding.")); window_content = g_strdup_printf ( "<big><b>%s</b></big>\n\n%s", tmp, _("You may choose to wait a short while for it to " "continue or force the application to quit entirely.")); dialog_pid = meta_show_dialog ("--question", window_content, NULL, window->screen->screen_name, _("_Wait"), _("_Force Quit"), window->xwindow, NULL, NULL); free (window_content); free (tmp); window->dialog_pid = dialog_pid; g_child_watch_add (dialog_pid, dialog_exited, window); } void meta_window_delete (MetaWindow *window, guint32 timestamp) { meta_error_trap_push (window->display); if (window->delete_window) { meta_topic (META_DEBUG_WINDOW_OPS, "Deleting %s with delete_window request\n", window->desc); meta_window_send_icccm_message (window, window->display->atom_WM_DELETE_WINDOW, timestamp); } else { meta_topic (META_DEBUG_WINDOW_OPS, "Deleting %s with explicit kill\n", window->desc); XKillClient (window->display->xdisplay, window->xwindow); } meta_error_trap_pop (window->display); meta_display_ping_window (window->display, window, timestamp, delete_ping_reply_func, delete_ping_timeout_func, window); if (window->has_focus) { /* FIXME Clean this up someday * http://bugzilla.gnome.org/show_bug.cgi?id=108706 */ #if 0 /* This is unfortunately going to result in weirdness * if the window doesn't respond to the delete event. * I don't know how to avoid that though. */ meta_topic (META_DEBUG_FOCUS, "Focusing default window because focus window %s was deleted/killed\n", window->desc); meta_workspace_focus_default_window (window->screen->active_workspace, window); #else meta_topic (META_DEBUG_FOCUS, "Not unfocusing %s on delete/kill\n", window->desc); #endif } else { meta_topic (META_DEBUG_FOCUS, "Window %s was deleted/killed but didn't have focus\n", window->desc); } } LOCAL_SYMBOL void meta_window_kill (MetaWindow *window) { meta_topic (META_DEBUG_WINDOW_OPS, "Killing %s brutally\n", window->desc); if (!meta_window_is_remote (window) && window->net_wm_pid > 0) { meta_topic (META_DEBUG_WINDOW_OPS, "Killing %s with kill()\n", window->desc); if (kill (window->net_wm_pid, 9) < 0) meta_topic (META_DEBUG_WINDOW_OPS, "Failed to signal %s: %s\n", window->desc, strerror (errno)); } meta_topic (META_DEBUG_WINDOW_OPS, "Disconnecting %s with XKillClient()\n", window->desc); meta_error_trap_push (window->display); XKillClient (window->display->xdisplay, window->xwindow); meta_error_trap_pop (window->display); } LOCAL_SYMBOL void meta_window_free_delete_dialog (MetaWindow *window) { if (window->dialog_pid >= 0) { kill (window->dialog_pid, 9); window->dialog_pid = -1; } } static void meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp) { meta_topic (META_DEBUG_PING, "Presenting existing ping dialog for %s\n", window->desc); if (window->dialog_pid >= 0) { GSList *windows; GSList *tmp; /* Activate transient for window that belongs to * muffin-dialog */ windows = meta_display_list_windows (window->display, META_LIST_DEFAULT); tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w->xtransient_for == window->xwindow && w->res_class && g_ascii_strcasecmp (w->res_class, "muffin-dialog") == 0) { meta_window_activate (w, timestamp); break; } tmp = tmp->next; } g_slist_free (windows); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/stack-tracker.h���������������������������������������������������������������0000664�0001750�0001750�00000007571�14211404421�017574� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file stack-tracker.h Track stacking order for compositor * * MetaStackTracker maintains the most accurate view we have at a * given point of time of the ordering of the children of the root * window (including override-redirect windows.) This is used to order * the windows when the compositor draws them. * * By contrast, MetaStack is responsible for keeping track of how we * think that windows *should* be ordered. For windows we manage * (non-override-redirect windows), the two stacking orders will be * the same. */ /* * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_STACK_TRACKER_H #define META_STACK_TRACKER_H #include <meta/screen.h> typedef struct _MetaStackTracker MetaStackTracker; MetaStackTracker *meta_stack_tracker_new (MetaScreen *screen); void meta_stack_tracker_free (MetaStackTracker *tracker); /* These functions are called when we make an X call that changes the * stacking order; this allows MetaStackTracker to predict stacking * order before it receives events back from the X server */ void meta_stack_tracker_record_add (MetaStackTracker *tracker, Window window, gulong serial); void meta_stack_tracker_record_remove (MetaStackTracker *tracker, Window window, gulong serial); void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, Window *windows, int n_windows, gulong serial); void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, Window window, Window sibling, gulong serial); void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, Window window, Window sibling, gulong serial); void meta_stack_tracker_record_lower (MetaStackTracker *tracker, Window window, gulong serial); /* These functions are used to update the stack when we get events * reflecting changes to the stacking order */ void meta_stack_tracker_create_event (MetaStackTracker *tracker, XCreateWindowEvent *event); void meta_stack_tracker_destroy_event (MetaStackTracker *tracker, XDestroyWindowEvent *event); void meta_stack_tracker_reparent_event (MetaStackTracker *tracker, XReparentEvent *event); void meta_stack_tracker_configure_event (MetaStackTracker *tracker, XConfigureEvent *event); void meta_stack_tracker_get_stack (MetaStackTracker *tracker, Window **windows, int *n_windows); void meta_stack_tracker_sync_stack (MetaStackTracker *tracker); void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker); #endif /* META_STACK_TRACKER_H */ ���������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/xprops.c����������������������������������������������������������������������0000664�0001750�0001750�00000112137�14211404421�016357� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X property convenience routines */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002 Red Hat Inc. * * Some trivial property-unpacking code from Xlib: * Copyright 1987, 1988, 1998 The Open Group * Copyright 1988 by Wyse Technology, Inc., San Jose, Ca, * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /*********************************************************** Copyright 1988 by Wyse Technology, Inc., San Jose, Ca, Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name Digital not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL AND WYSE DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL OR WYSE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* Copyright 1987, 1988, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. */ #include <config.h> #include "xprops.h" #include <meta/errors.h> #include "util-private.h" #include "async-getprop.h" #include "ui.h" #include "muffin-Xatomtype.h" #include <X11/Xatom.h> #include <string.h> #include "window-private.h" typedef struct { MetaDisplay *display; Window xwindow; Atom xatom; Atom type; int format; unsigned long n_items; unsigned long bytes_after; unsigned char *prop; } GetPropertyResults; static gboolean validate_or_free_results (GetPropertyResults *results, int expected_format, Atom expected_type, gboolean must_have_items) { char *type_name; char *expected_name; char *prop_name; const char *title; const char *res_class; const char *res_name; MetaWindow *w; if (expected_format == results->format && expected_type == results->type && (!must_have_items || results->n_items > 0)) return TRUE; meta_error_trap_push (results->display); type_name = XGetAtomName (results->display->xdisplay, results->type); expected_name = XGetAtomName (results->display->xdisplay, expected_type); prop_name = XGetAtomName (results->display->xdisplay, results->xatom); meta_error_trap_pop (results->display); w = meta_display_lookup_x_window (results->display, results->xwindow); if (w != NULL) { title = w->title; res_class = w->res_class; res_name = w->res_name; } else { title = NULL; res_class = NULL; res_name = NULL; } if (title == NULL) title = "unknown"; if (res_class == NULL) res_class = "unknown"; if (res_name == NULL) res_name = "unknown"; meta_warning ("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n", results->xwindow, prop_name ? prop_name : "(bad atom)", expected_name ? expected_name : "(bad atom)", expected_format, type_name ? type_name : "(bad atom)", results->format, (int) results->n_items, title, res_class, res_name); if (type_name) XFree (type_name); if (expected_name) XFree (expected_name); if (prop_name) XFree (prop_name); if (results->prop) { XFree (results->prop); results->prop = NULL; } return FALSE; } static gboolean get_property (MetaDisplay *display, Window xwindow, Atom xatom, Atom req_type, GetPropertyResults *results) { results->display = display; results->xwindow = xwindow; results->xatom = xatom; results->prop = NULL; results->n_items = 0; results->type = None; results->bytes_after = 0; results->format = 0; meta_error_trap_push_with_return (display); if (XGetWindowProperty (display->xdisplay, xwindow, xatom, 0, G_MAXLONG, False, req_type, &results->type, &results->format, &results->n_items, &results->bytes_after, &results->prop) != Success || results->type == None) { if (results->prop) XFree (results->prop); meta_error_trap_pop_with_return (display); return FALSE; } if (meta_error_trap_pop_with_return (display) != Success) { if (results->prop) XFree (results->prop); return FALSE; } return TRUE; } static gboolean atom_list_from_results (GetPropertyResults *results, Atom **atoms_p, int *n_atoms_p) { if (!validate_or_free_results (results, 32, XA_ATOM, FALSE)) return FALSE; *atoms_p = (Atom*) results->prop; *n_atoms_p = results->n_items; results->prop = NULL; return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_atom_list (MetaDisplay *display, Window xwindow, Atom xatom, Atom **atoms_p, int *n_atoms_p) { GetPropertyResults results; *atoms_p = NULL; *n_atoms_p = 0; if (!get_property (display, xwindow, xatom, XA_ATOM, &results)) return FALSE; return atom_list_from_results (&results, atoms_p, n_atoms_p); } static gboolean cardinal_list_from_results (GetPropertyResults *results, gulong **cardinals_p, int *n_cardinals_p) { if (!validate_or_free_results (results, 32, XA_CARDINAL, FALSE)) return FALSE; *cardinals_p = (gulong*) results->prop; *n_cardinals_p = results->n_items; results->prop = NULL; #if GLIB_SIZEOF_LONG == 8 /* Xlib sign-extends format=32 items, but we want them unsigned */ { int i; for (i = 0; i < *n_cardinals_p; i++) (*cardinals_p)[i] = (*cardinals_p)[i] & 0xffffffff; } #endif return TRUE; } LOCAL_SYMBOL LOCAL_SYMBOL gboolean meta_prop_get_cardinal_list (MetaDisplay *display, Window xwindow, Atom xatom, gulong **cardinals_p, int *n_cardinals_p) { GetPropertyResults results; *cardinals_p = NULL; *n_cardinals_p = 0; if (!get_property (display, xwindow, xatom, XA_CARDINAL, &results)) return FALSE; return cardinal_list_from_results (&results, cardinals_p, n_cardinals_p); } static gboolean motif_hints_from_results (GetPropertyResults *results, MotifWmHints **hints_p) { int real_size, max_size; #define MAX_ITEMS sizeof (MotifWmHints)/sizeof (gulong) *hints_p = NULL; if (results->type == None || results->n_items <= 0) { meta_verbose ("Motif hints had unexpected type or n_items\n"); if (results->prop) { XFree (results->prop); results->prop = NULL; } return FALSE; } /* The issue here is that some old crufty code will set a smaller * MotifWmHints than the one we expect, apparently. I'm not sure of * the history behind it. See bug #89841 for example. */ *hints_p = ag_Xmalloc (sizeof (MotifWmHints)); if (*hints_p == NULL) { if (results->prop) { XFree (results->prop); results->prop = NULL; } return FALSE; } real_size = results->n_items * sizeof (gulong); max_size = MAX_ITEMS * sizeof (gulong); memcpy (*hints_p, results->prop, MIN (real_size, max_size)); if (results->prop) { XFree (results->prop); results->prop = NULL; } return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_motif_hints (MetaDisplay *display, Window xwindow, Atom xatom, MotifWmHints **hints_p) { GetPropertyResults results; *hints_p = NULL; if (!get_property (display, xwindow, xatom, AnyPropertyType, &results)) return FALSE; return motif_hints_from_results (&results, hints_p); } static gboolean latin1_string_from_results (GetPropertyResults *results, char **str_p) { *str_p = NULL; if (!validate_or_free_results (results, 8, XA_STRING, FALSE)) return FALSE; *str_p = (char*) results->prop; results->prop = NULL; return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_latin1_string (MetaDisplay *display, Window xwindow, Atom xatom, char **str_p) { GetPropertyResults results; *str_p = NULL; if (!get_property (display, xwindow, xatom, XA_STRING, &results)) return FALSE; return latin1_string_from_results (&results, str_p); } static gboolean utf8_string_from_results (GetPropertyResults *results, char **str_p) { *str_p = NULL; if (!validate_or_free_results (results, 8, results->display->atom_UTF8_STRING, FALSE)) return FALSE; if (results->n_items > 0 && !g_utf8_validate ((gchar *)results->prop, results->n_items, NULL)) { char *name; name = XGetAtomName (results->display->xdisplay, results->xatom); meta_warning ("Property %s on window 0x%lx contained invalid UTF-8\n", name, results->xwindow); meta_XFree (name); XFree (results->prop); results->prop = NULL; return FALSE; } *str_p = (char*) results->prop; results->prop = NULL; return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_utf8_string (MetaDisplay *display, Window xwindow, Atom xatom, char **str_p) { GetPropertyResults results; *str_p = NULL; if (!get_property (display, xwindow, xatom, display->atom_UTF8_STRING, &results)) return FALSE; return utf8_string_from_results (&results, str_p); } /* this one freakishly returns malloc memory */ static gboolean utf8_list_from_results (GetPropertyResults *results, char ***str_p, int *n_str_p) { int i; int n_strings; char **retval; const char *p; *str_p = NULL; *n_str_p = 0; if (!validate_or_free_results (results, 8, results->display->atom_UTF8_STRING, FALSE)) return FALSE; /* I'm not sure this is right, but I'm guessing the * property is nul-separated */ i = 0; n_strings = 0; while (i < (int) results->n_items) { if (results->prop[i] == '\0') ++n_strings; ++i; } if (results->prop[results->n_items - 1] != '\0') ++n_strings; /* we're guaranteed that results->prop has a nul on the end * by XGetWindowProperty */ retval = g_new0 (char*, n_strings + 1); p = (char *)results->prop; i = 0; while (i < n_strings) { if (!g_utf8_validate (p, -1, NULL)) { char *name; meta_error_trap_push (results->display); name = XGetAtomName (results->display->xdisplay, results->xatom); meta_error_trap_pop (results->display); meta_warning ("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n", name, results->xwindow, i); meta_XFree (name); meta_XFree (results->prop); results->prop = NULL; g_strfreev (retval); return FALSE; } retval[i] = g_strdup (p); p = p + strlen (p) + 1; ++i; } *str_p = retval; *n_str_p = i; meta_XFree (results->prop); results->prop = NULL; return TRUE; } /* returns malloc not Xmalloc memory */ LOCAL_SYMBOL gboolean meta_prop_get_utf8_list (MetaDisplay *display, Window xwindow, Atom xatom, char ***str_p, int *n_str_p) { GetPropertyResults results; *str_p = NULL; if (!get_property (display, xwindow, xatom, display->atom_UTF8_STRING, &results)) return FALSE; return utf8_list_from_results (&results, str_p, n_str_p); } LOCAL_SYMBOL void meta_prop_set_utf8_string_hint (MetaDisplay *display, Window xwindow, Atom atom, const char *val) { meta_error_trap_push (display); XChangeProperty (display->xdisplay, xwindow, atom, display->atom_UTF8_STRING, 8, PropModeReplace, (guchar*) val, strlen (val)); meta_error_trap_pop (display); } static gboolean window_from_results (GetPropertyResults *results, Window *window_p) { if (!validate_or_free_results (results, 32, XA_WINDOW, TRUE)) return FALSE; *window_p = *(Window*) results->prop; XFree (results->prop); results->prop = NULL; return TRUE; } #ifdef HAVE_XSYNC static gboolean counter_from_results (GetPropertyResults *results, XSyncCounter *counter_p) { if (!validate_or_free_results (results, 32, XA_CARDINAL, TRUE)) return FALSE; *counter_p = *(XSyncCounter*) results->prop; XFree (results->prop); results->prop = NULL; return TRUE; } static gboolean counter_list_from_results (GetPropertyResults *results, XSyncCounter **counters_p, int *n_counters_p) { if (!validate_or_free_results (results, 32, XA_CARDINAL, FALSE)) return FALSE; *counters_p = (XSyncCounter*) results->prop; *n_counters_p = results->n_items; results->prop = NULL; return TRUE; } #endif LOCAL_SYMBOL gboolean meta_prop_get_window (MetaDisplay *display, Window xwindow, Atom xatom, Window *window_p) { GetPropertyResults results; *window_p = None; if (!get_property (display, xwindow, xatom, XA_WINDOW, &results)) return FALSE; return window_from_results (&results, window_p); } LOCAL_SYMBOL gboolean meta_prop_get_cardinal (MetaDisplay *display, Window xwindow, Atom xatom, gulong *cardinal_p) { return meta_prop_get_cardinal_with_atom_type (display, xwindow, xatom, XA_CARDINAL, cardinal_p); } static gboolean cardinal_with_atom_type_from_results (GetPropertyResults *results, Atom prop_type, gulong *cardinal_p) { if (!validate_or_free_results (results, 32, prop_type, TRUE)) return FALSE; *cardinal_p = *(gulong*) results->prop; #if GLIB_SIZEOF_LONG == 8 /* Xlib sign-extends format=32 items, but we want them unsigned */ *cardinal_p &= 0xffffffff; #endif XFree (results->prop); results->prop = NULL; return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_cardinal_with_atom_type (MetaDisplay *display, Window xwindow, Atom xatom, Atom prop_type, gulong *cardinal_p) { GetPropertyResults results; *cardinal_p = 0; if (!get_property (display, xwindow, xatom, prop_type, &results)) return FALSE; return cardinal_with_atom_type_from_results (&results, prop_type, cardinal_p); } static gboolean text_property_from_results (GetPropertyResults *results, char **utf8_str_p) { XTextProperty tp; *utf8_str_p = NULL; tp.value = results->prop; results->prop = NULL; tp.encoding = results->type; tp.format = results->format; tp.nitems = results->n_items; *utf8_str_p = meta_text_property_to_utf8 (results->display->xdisplay, &tp); if (tp.value != NULL) XFree (tp.value); return *utf8_str_p != NULL; } LOCAL_SYMBOL gboolean meta_prop_get_text_property (MetaDisplay *display, Window xwindow, Atom xatom, char **utf8_str_p) { GetPropertyResults results; if (!get_property (display, xwindow, xatom, AnyPropertyType, &results)) return FALSE; return text_property_from_results (&results, utf8_str_p); } /* From Xmd.h */ #ifndef cvtINT32toInt #if SIZEOF_VOID_P == 8 #define cvtINT8toInt(val) ((((unsigned int)val) & 0x00000080) ? (((unsigned int)val) | 0xffffffffffffff00) : ((unsigned int)val)) #define cvtINT16toInt(val) ((((unsigned int)val) & 0x00008000) ? (((unsigned int)val) | 0xffffffffffff0000) : ((unsigned int)val)) #define cvtINT32toInt(val) ((((unsigned int)val) & 0x80000000) ? (((unsigned int)val) | 0xffffffff00000000) : ((unsigned int)val)) #define cvtINT8toShort(val) cvtINT8toInt(val) #define cvtINT16toShort(val) cvtINT16toInt(val) #define cvtINT32toShort(val) cvtINT32toInt(val) #define cvtINT8toLong(val) cvtINT8toInt(val) #define cvtINT16toLong(val) cvtINT16toInt(val) #define cvtINT32toLong(val) cvtINT32toInt(val) #else #define cvtINT8toInt(val) (val) #define cvtINT16toInt(val) (val) #define cvtINT32toInt(val) (val) #define cvtINT8toShort(val) (val) #define cvtINT16toShort(val) (val) #define cvtINT32toShort(val) (val) #define cvtINT8toLong(val) (val) #define cvtINT16toLong(val) (val) #define cvtINT32toLong(val) (val) #endif /* SIZEOF_VOID_P == 8 */ #endif /* cvtINT32toInt() */ static gboolean wm_hints_from_results (GetPropertyResults *results, XWMHints **hints_p) { XWMHints *hints; xPropWMHints *raw; *hints_p = NULL; if (!validate_or_free_results (results, 32, XA_WM_HINTS, TRUE)) return FALSE; /* pre-R3 bogusly truncated window_group, don't fail on them */ if (results->n_items < (NumPropWMHintsElements - 1)) { meta_verbose ("WM_HINTS property too short: %d should be %d\n", (int) results->n_items, NumPropWMHintsElements - 1); if (results->prop) { XFree (results->prop); results->prop = NULL; } return FALSE; } hints = ag_Xmalloc0 (sizeof (XWMHints)); raw = (xPropWMHints*) results->prop; hints->flags = raw->flags; hints->input = (raw->input ? True : False); hints->initial_state = cvtINT32toInt (raw->initialState); hints->icon_pixmap = raw->iconPixmap; hints->icon_window = raw->iconWindow; hints->icon_x = cvtINT32toInt (raw->iconX); hints->icon_y = cvtINT32toInt (raw->iconY); hints->icon_mask = raw->iconMask; if (results->n_items >= NumPropWMHintsElements) hints->window_group = raw->windowGroup; else hints->window_group = 0; if (results->prop) { XFree (results->prop); results->prop = NULL; } *hints_p = hints; return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_wm_hints (MetaDisplay *display, Window xwindow, Atom xatom, XWMHints **hints_p) { GetPropertyResults results; *hints_p = NULL; if (!get_property (display, xwindow, xatom, XA_WM_HINTS, &results)) return FALSE; return wm_hints_from_results (&results, hints_p); } static gboolean class_hint_from_results (GetPropertyResults *results, XClassHint *class_hint) { int len_name, len_class; class_hint->res_class = NULL; class_hint->res_name = NULL; if (!validate_or_free_results (results, 8, XA_STRING, FALSE)) return FALSE; len_name = strlen ((char *) results->prop); if (! (class_hint->res_name = ag_Xmalloc (len_name+1))) { XFree (results->prop); results->prop = NULL; return FALSE; } strcpy (class_hint->res_name, (char *)results->prop); if (len_name == (int) results->n_items) len_name--; len_class = strlen ((char *)results->prop + len_name + 1); if (! (class_hint->res_class = ag_Xmalloc(len_class+1))) { XFree(class_hint->res_name); class_hint->res_name = NULL; XFree (results->prop); results->prop = NULL; return FALSE; } strcpy (class_hint->res_class, (char *)results->prop + len_name + 1); XFree (results->prop); results->prop = NULL; return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_class_hint (MetaDisplay *display, Window xwindow, Atom xatom, XClassHint *class_hint) { GetPropertyResults results; class_hint->res_class = NULL; class_hint->res_name = NULL; if (!get_property (display, xwindow, xatom, XA_STRING, &results)) return FALSE; return class_hint_from_results (&results, class_hint); } static gboolean size_hints_from_results (GetPropertyResults *results, XSizeHints **hints_p, gulong *flags_p) { xPropSizeHints *raw; XSizeHints *hints; *hints_p = NULL; *flags_p = 0; if (!validate_or_free_results (results, 32, XA_WM_SIZE_HINTS, FALSE)) return FALSE; if (results->n_items < OldNumPropSizeElements) { XFree (results->prop); results->prop = NULL; return FALSE; } raw = (xPropSizeHints*) results->prop; hints = ag_Xmalloc (sizeof (XSizeHints)); /* XSizeHints misdeclares these as int instead of long */ hints->flags = raw->flags; hints->x = cvtINT32toInt (raw->x); hints->y = cvtINT32toInt (raw->y); hints->width = cvtINT32toInt (raw->width); hints->height = cvtINT32toInt (raw->height); hints->min_width = cvtINT32toInt (raw->minWidth); hints->min_height = cvtINT32toInt (raw->minHeight); hints->max_width = cvtINT32toInt (raw->maxWidth); hints->max_height = cvtINT32toInt (raw->maxHeight); hints->width_inc = cvtINT32toInt (raw->widthInc); hints->height_inc = cvtINT32toInt (raw->heightInc); hints->min_aspect.x = cvtINT32toInt (raw->minAspectX); hints->min_aspect.y = cvtINT32toInt (raw->minAspectY); hints->max_aspect.x = cvtINT32toInt (raw->maxAspectX); hints->max_aspect.y = cvtINT32toInt (raw->maxAspectY); *flags_p = (USPosition | USSize | PAllHints); if (results->n_items >= NumPropSizeElements) { hints->base_width= cvtINT32toInt (raw->baseWidth); hints->base_height= cvtINT32toInt (raw->baseHeight); hints->win_gravity= cvtINT32toInt (raw->winGravity); *flags_p |= (PBaseSize | PWinGravity); } hints->flags &= (*flags_p); /* get rid of unwanted bits */ XFree (results->prop); results->prop = NULL; *hints_p = hints; return TRUE; } LOCAL_SYMBOL gboolean meta_prop_get_size_hints (MetaDisplay *display, Window xwindow, Atom xatom, XSizeHints **hints_p, gulong *flags_p) { GetPropertyResults results; *hints_p = NULL; *flags_p = 0; if (!get_property (display, xwindow, xatom, XA_WM_SIZE_HINTS, &results)) return FALSE; return size_hints_from_results (&results, hints_p, flags_p); } static AgGetPropertyTask* get_task (MetaDisplay *display, Window xwindow, Atom xatom, Atom req_type) { return ag_task_create (display->xdisplay, xwindow, xatom, 0, G_MAXLONG, False, req_type); } static char* latin1_to_utf8 (const char *text) { GString *str; const char *p; str = g_string_new (""); p = text; while (*p) { g_string_append_unichar (str, *p); ++p; } return g_string_free (str, FALSE); } LOCAL_SYMBOL void meta_prop_get_values (MetaDisplay *display, Window xwindow, MetaPropValue *values, int n_values) { int i; AgGetPropertyTask **tasks; meta_verbose ("Requesting %d properties of 0x%lx at once\n", n_values, xwindow); if (n_values == 0) return; tasks = g_new0 (AgGetPropertyTask*, n_values); /* Start up tasks. The "values" array can have values * with atom == None, which means to ignore that element. */ i = 0; while (i < n_values) { if (values[i].required_type == None) { switch (values[i].type) { case META_PROP_VALUE_INVALID: /* This means we don't really want a value, e.g. got * property notify on an atom we don't care about. */ if (values[i].atom != None) meta_bug ("META_PROP_VALUE_INVALID requested in %s\n", G_STRFUNC); break; case META_PROP_VALUE_UTF8_LIST: case META_PROP_VALUE_UTF8: values[i].required_type = display->atom_UTF8_STRING; break; case META_PROP_VALUE_STRING: case META_PROP_VALUE_STRING_AS_UTF8: values[i].required_type = XA_STRING; break; case META_PROP_VALUE_MOTIF_HINTS: values[i].required_type = AnyPropertyType; break; case META_PROP_VALUE_CARDINAL_LIST: case META_PROP_VALUE_CARDINAL: values[i].required_type = XA_CARDINAL; break; case META_PROP_VALUE_WINDOW: values[i].required_type = XA_WINDOW; break; case META_PROP_VALUE_ATOM_LIST: values[i].required_type = XA_ATOM; break; case META_PROP_VALUE_TEXT_PROPERTY: values[i].required_type = AnyPropertyType; break; case META_PROP_VALUE_WM_HINTS: values[i].required_type = XA_WM_HINTS; break; case META_PROP_VALUE_CLASS_HINT: values[i].required_type = XA_STRING; break; case META_PROP_VALUE_SIZE_HINTS: values[i].required_type = XA_WM_SIZE_HINTS; break; case META_PROP_VALUE_SYNC_COUNTER: case META_PROP_VALUE_SYNC_COUNTER_LIST: values[i].required_type = XA_CARDINAL; break; } } if (values[i].atom != None) tasks[i] = get_task (display, xwindow, values[i].atom, values[i].required_type); ++i; } /* Get replies for all our tasks */ meta_topic (META_DEBUG_SYNC, "Syncing to get %d GetProperty replies in %s\n", n_values, G_STRFUNC); XSync (display->xdisplay, False); /* Collect results, should arrive in order requested */ i = 0; while (i < n_values) { AgGetPropertyTask *task; GetPropertyResults results; if (tasks[i] == NULL) { /* Probably values[i].type was None, or ag_task_create() * returned NULL. */ values[i].type = META_PROP_VALUE_INVALID; goto next; } task = ag_get_next_completed_task (display->xdisplay); g_assert (task != NULL); g_assert (ag_task_have_reply (task)); results.display = display; results.xwindow = xwindow; results.xatom = values[i].atom; results.prop = NULL; results.n_items = 0; results.type = None; results.bytes_after = 0; results.format = 0; if (ag_task_get_reply_and_free (task, &results.type, &results.format, &results.n_items, &results.bytes_after, &results.prop) != Success || results.type == None) { values[i].type = META_PROP_VALUE_INVALID; if (results.prop) { XFree (results.prop); results.prop = NULL; } goto next; } switch (values[i].type) { case META_PROP_VALUE_INVALID: g_assert_not_reached (); break; case META_PROP_VALUE_UTF8_LIST: if (!utf8_list_from_results (&results, &values[i].v.string_list.strings, &values[i].v.string_list.n_strings)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_UTF8: if (!utf8_string_from_results (&results, &values[i].v.str)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_STRING: if (!latin1_string_from_results (&results, &values[i].v.str)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_STRING_AS_UTF8: if (!latin1_string_from_results (&results, &values[i].v.str)) values[i].type = META_PROP_VALUE_INVALID; else { char *new_str; char *xmalloc_new_str; new_str = latin1_to_utf8 (values[i].v.str); xmalloc_new_str = ag_Xmalloc (strlen (new_str) + 1); if (xmalloc_new_str != NULL) { strcpy (xmalloc_new_str, new_str); meta_XFree (values[i].v.str); values[i].v.str = xmalloc_new_str; } free (new_str); } break; case META_PROP_VALUE_MOTIF_HINTS: if (!motif_hints_from_results (&results, &values[i].v.motif_hints)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_CARDINAL_LIST: if (!cardinal_list_from_results (&results, &values[i].v.cardinal_list.cardinals, &values[i].v.cardinal_list.n_cardinals)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_CARDINAL: if (!cardinal_with_atom_type_from_results (&results, values[i].required_type, &values[i].v.cardinal)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_WINDOW: if (!window_from_results (&results, &values[i].v.xwindow)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_ATOM_LIST: if (!atom_list_from_results (&results, &values[i].v.atom_list.atoms, &values[i].v.atom_list.n_atoms)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_TEXT_PROPERTY: if (!text_property_from_results (&results, &values[i].v.str)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_WM_HINTS: if (!wm_hints_from_results (&results, &values[i].v.wm_hints)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_CLASS_HINT: if (!class_hint_from_results (&results, &values[i].v.class_hint)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_SIZE_HINTS: if (!size_hints_from_results (&results, &values[i].v.size_hints.hints, &values[i].v.size_hints.flags)) values[i].type = META_PROP_VALUE_INVALID; break; #ifdef HAVE_XSYNC case META_PROP_VALUE_SYNC_COUNTER: if (!counter_from_results (&results, &values[i].v.xcounter)) values[i].type = META_PROP_VALUE_INVALID; break; case META_PROP_VALUE_SYNC_COUNTER_LIST: if (!counter_list_from_results (&results, &values[i].v.xcounter_list.counters, &values[i].v.xcounter_list.n_counters)) values[i].type = META_PROP_VALUE_INVALID; break; #else case META_PROP_VALUE_SYNC_COUNTER: case META_PROP_VALUE_SYNC_COUNTER_LIST: values[i].type = META_PROP_VALUE_INVALID; if (results.prop) { XFree (results.prop); results.prop = NULL; } break; #endif } next: ++i; } free (tasks); } static void free_value (MetaPropValue *value) { switch (value->type) { case META_PROP_VALUE_INVALID: break; case META_PROP_VALUE_UTF8: case META_PROP_VALUE_STRING: case META_PROP_VALUE_STRING_AS_UTF8: meta_XFree (value->v.str); break; case META_PROP_VALUE_MOTIF_HINTS: meta_XFree (value->v.motif_hints); break; case META_PROP_VALUE_CARDINAL: break; case META_PROP_VALUE_WINDOW: break; case META_PROP_VALUE_ATOM_LIST: meta_XFree (value->v.atom_list.atoms); break; case META_PROP_VALUE_TEXT_PROPERTY: meta_XFree (value->v.str); break; case META_PROP_VALUE_WM_HINTS: meta_XFree (value->v.wm_hints); break; case META_PROP_VALUE_CLASS_HINT: meta_XFree (value->v.class_hint.res_class); meta_XFree (value->v.class_hint.res_name); break; case META_PROP_VALUE_SIZE_HINTS: meta_XFree (value->v.size_hints.hints); break; case META_PROP_VALUE_UTF8_LIST: g_strfreev (value->v.string_list.strings); break; case META_PROP_VALUE_CARDINAL_LIST: meta_XFree (value->v.cardinal_list.cardinals); break; case META_PROP_VALUE_SYNC_COUNTER: break; #ifdef HAVE_XSYNC case META_PROP_VALUE_SYNC_COUNTER_LIST: meta_XFree (value->v.xcounter_list.counters); break; #endif } } LOCAL_SYMBOL void meta_prop_free_values (MetaPropValue *values, int n_values) { int i; i = 0; while (i < n_values) { free_value (&values[i]); ++i; } /* Zero the whole thing to quickly detect breakage */ memset (values, '\0', sizeof (MetaPropValue) * n_values); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/restart.c���������������������������������������������������������������������0000664�0001750�0001750�00000011554�14211404421�016511� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2014 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* * SECTION:restart * @short_description: Smoothly restart the compositor * * There are some cases where we need to restart Muffin in order * to deal with changes in state - the particular case inspiring * this is enabling or disabling stereo output. To make this * fairly smooth for the user, we need to do two things: * * - Display a message to the user and make sure that it is * actually painted before we exit. * - Use a helper program so that the Composite Overlay Window * isn't unmapped and mapped. * * This handles both of these. */ #include <config.h> #include <clutter/clutter.h> #include <gio/gunixinputstream.h> #include <meta/main.h> #include "ui.h" #include <meta/util.h> #include "display-private.h" static gboolean restart_helper_started = FALSE; static gboolean restart_stage_shown = FALSE; static void restart_check_ready (void) { if (restart_helper_started && restart_stage_shown) meta_display_restart (meta_get_display ()); } static void restart_helper_read_line_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; gsize length; char *line = g_data_input_stream_read_line_finish_utf8 (G_DATA_INPUT_STREAM (source_object), res, &length, &error); if (line == NULL) { meta_warning ("Failed to read output from restart helper%s%s\n", error ? ": " : NULL, error ? error->message : NULL); } else free (line); /* We don't actually care what the restart helper outputs */ g_object_unref (source_object); restart_helper_started = TRUE; restart_check_ready (); } static gboolean restart_stage_painted (gpointer data) { restart_stage_shown = TRUE; restart_check_ready (); return FALSE; } /** * meta_restart: * * Starts the process of restarting the compositor. */ void meta_restart (void) { MetaDisplay *display = meta_get_display(); GInputStream *unix_stream; GDataInputStream *data_stream; GError *error = NULL; int helper_out_fd; static const char * const helper_argv[] = { MUFFIN_LIBEXECDIR "/muffin-restart-helper", NULL }; meta_display_notify_restart (display); /* Wait until the stage was painted */ clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT, restart_stage_painted, NULL, NULL); /* We also need to wait for the restart helper to get its * reference to the Composite Overlay Window. */ if (!g_spawn_async_with_pipes (NULL, /* working directory */ (char **)helper_argv, NULL, /* envp */ G_SPAWN_DEFAULT, NULL, NULL, /* child_setup */ NULL, /* child_pid */ NULL, /* standard_input */ &helper_out_fd, NULL, /* standard_error */ &error)) { meta_warning ("Failed to start restart helper: %s\n", error->message); goto error; } unix_stream = g_unix_input_stream_new (helper_out_fd, TRUE); data_stream = g_data_input_stream_new (unix_stream); g_object_unref (unix_stream); g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT, NULL, restart_helper_read_line_callback, &error); if (error != NULL) { meta_warning ("Failed to read from restart helper: %s\n", error->message); g_object_unref (data_stream); goto error; } return; error: /* If starting the restart helper fails, then we just go ahead and restart * immediately. We won't get a smooth transition, since the overlay window * will be destroyed and recreated, but otherwise it will work fine. */ restart_helper_started = TRUE; restart_check_ready (); return; }����������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/window-props.h����������������������������������������������������������������0000664�0001750�0001750�00000011753�14211404421�017503� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file window-props.h MetaWindow property handling * * A system which can inspect sets of properties of given windows * and take appropriate action given their values. * * Note that all the meta_window_reload_propert* functions require a * round trip to the server. */ /* * Copyright (C) 2001, 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_WINDOW_PROPS_H #define META_WINDOW_PROPS_H #include "window-private.h" /** * Requests the current values of a single property for a given * window from the server, and deals with it appropriately. * Does not return it to the caller (it's been dealt with!) * * \param window The window. * \param property A single X atom. */ void meta_window_reload_property (MetaWindow *window, Atom property, gboolean initial); /** * Requests the current values of a set of properties for a given * window from the server, and deals with them appropriately. * Does not return them to the caller (they've been dealt with!) * * \param window The window. * \param properties A pointer to a list of X atoms, "n_properties" long. * \param n_properties The length of the properties list. */ void meta_window_reload_properties (MetaWindow *window, const Atom *properties, int n_properties, gboolean initial); /** * Requests the current values of a single property for a given * window from the server, and deals with it appropriately. * Does not return it to the caller (it's been dealt with!) * * \param window A window on the same display as the one we're * investigating (only used to find the display) * \param xwindow The X handle for the window. * \param property A single X atom. */ void meta_window_reload_property_from_xwindow (MetaWindow *window, Window xwindow, Atom property, gboolean initial); /** * Requests the current values of a set of properties for a given * window from the server, and deals with them appropriately. * Does not return them to the caller (they've been dealt with!) * * \param window A window on the same display as the one we're * investigating (only used to find the display) * \param xwindow The X handle for the window. * \param properties A pointer to a list of X atoms, "n_properties" long. * \param n_properties The length of the properties list. */ void meta_window_reload_properties_from_xwindow (MetaWindow *window, Window xwindow, const Atom *properties, int n_properties, gboolean initial); /** * Requests the current values for standard properties for a given * window from the server, and deals with them appropriately. * Does not return them to the caller (they've been dealt with!) * * \param window The window. */ void meta_window_load_initial_properties (MetaWindow *window); /** * Initialises the hooks used for the reload_propert* functions * on a particular display, and stores a pointer to them in the * display. * * \param display The display. */ void meta_display_init_window_prop_hooks (MetaDisplay *display); /** * Frees the hooks used for the reload_propert* functions * for a particular display. * * \param display The display. */ void meta_display_free_window_prop_hooks (MetaDisplay *display); /** * Sets the size hints for a window. This happens when a * WM_NORMAL_HINTS property is set on a window, but it is public * because the size hints are set to defaults when a window is * created. See * http://tronche.com/gui/x/icccm/sec-4.html#WM_NORMAL_HINTS * for the X details. * * \param window The window to set the size hints on. * \param hints Either some X size hints, or NULL for default. */ void meta_set_normal_hints (MetaWindow *window, XSizeHints *hints); #endif /* META_WINDOW_PROPS_H */ ���������������������muffin-5.2.1/src/core/frame.c�����������������������������������������������������������������������0000664�0001750�0001750�00000034543�14211404421�016122� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X window decorations */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2003, 2004 Red Hat, Inc. * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "frame.h" #include <meta/errors.h> #include "keybindings-private.h" #include <X11/extensions/Xrender.h> #define EVENT_MASK (SubstructureRedirectMask | \ StructureNotifyMask | SubstructureNotifyMask | \ ExposureMask | \ ButtonPressMask | ButtonReleaseMask | \ PointerMotionMask | PointerMotionHintMask | \ EnterWindowMask | LeaveWindowMask | \ FocusChangeMask | \ ColormapChangeMask) LOCAL_SYMBOL void meta_window_ensure_frame (MetaWindow *window) { MetaFrame *frame; XSetWindowAttributes attrs; Visual *visual; gulong create_serial; if (window->frame) return; /* See comment below for why this is required. */ meta_display_grab (window->display); frame = g_new (MetaFrame, 1); frame->window = window; frame->xwindow = None; frame->rect = window->rect; frame->child_x = 0; frame->child_y = 0; frame->bottom_height = 0; frame->right_width = 0; frame->current_cursor = 0; frame->is_flashing = FALSE; frame->borders_cached = FALSE; meta_verbose ("Framing window %s: visual %s default, depth %d default depth %d\n", window->desc, XVisualIDFromVisual (window->xvisual) == XVisualIDFromVisual (window->screen->default_xvisual) ? "is" : "is not", window->depth, window->screen->default_depth); meta_verbose ("Frame geometry %d,%d %dx%d\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height); /* Default depth/visual handles clients with weird visuals; they can * always be children of the root depth/visual obviously, but * e.g. DRI games can't be children of a parent that has the same * visual as the client. NULL means default visual. * * We look for an ARGB visual if we can find one, otherwise use * the default of NULL. */ /* Special case for depth 32 windows (assumed to be ARGB), * we use the window's visual. Otherwise we just use the system visual. */ if (window->depth == 32) visual = window->xvisual; else visual = NULL; frame->xwindow = meta_ui_create_frame_window (window->screen->ui, window->display->xdisplay, visual, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, frame->window->screen->number, &create_serial); meta_stack_tracker_record_add (window->screen->stack_tracker, frame->xwindow, create_serial); meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow); attrs.event_mask = EVENT_MASK; XChangeWindowAttributes (window->display->xdisplay, frame->xwindow, CWEventMask, &attrs); meta_display_register_x_window (window->display, &frame->xwindow, window); /* Reparent the client window; it may be destroyed, * thus the error trap. We'll get a destroy notify later * and free everything. Comment in FVWM source code says * we need a server grab or the child can get its MapNotify * before we've finished reparenting and getting the decoration * window onscreen, so ensure_frame must be called with * a grab. */ meta_error_trap_push (window->display); if (window->mapped) { window->mapped = FALSE; /* the reparent will unmap the window, * we don't want to take that as a withdraw */ meta_topic (META_DEBUG_WINDOW_STATE, "Incrementing unmaps_pending on %s for reparent\n", window->desc); window->unmaps_pending += 1; } /* window was reparented to this position */ window->rect.x = 0; window->rect.y = 0; meta_stack_tracker_record_remove (window->screen->stack_tracker, window->xwindow, XNextRequest (window->display->xdisplay)); XReparentWindow (window->display->xdisplay, window->xwindow, frame->xwindow, window->rect.x, window->rect.y); /* FIXME handle this error */ meta_error_trap_pop (window->display); /* stick frame to the window */ window->frame = frame; /* Now that frame->xwindow is registered with window, we can set its * style and background. */ meta_ui_update_frame_style (window->screen->ui, frame->xwindow); if (window->title) meta_ui_set_frame_title (window->screen->ui, window->frame->xwindow, window->title); /* Move keybindings to frame instead of window */ meta_window_grab_keys (window); meta_ui_map_frame (frame->window->screen->ui, frame->xwindow); meta_display_ungrab (window->display); } LOCAL_SYMBOL void meta_window_destroy_frame (MetaWindow *window) { MetaFrame *frame; MetaFrameBorders borders; if (window->frame == NULL) return; meta_verbose ("Unframing window %s\n", window->desc); frame = window->frame; meta_frame_calc_borders (frame, &borders); /* Unparent the client window; it may be destroyed, * thus the error trap. */ meta_error_trap_push (window->display); if (window->mapped) { window->mapped = FALSE; /* Keep track of unmapping it, so we * can identify a withdraw initiated * by the client. */ meta_topic (META_DEBUG_WINDOW_STATE, "Incrementing unmaps_pending on %s for reparent back to root\n", window->desc); window->unmaps_pending += 1; } meta_stack_tracker_record_add (window->screen->stack_tracker, window->xwindow, XNextRequest (window->display->xdisplay)); XReparentWindow (window->display->xdisplay, window->xwindow, window->screen->xroot, /* Using anything other than meta_window_get_position() * coordinates here means we'll need to ensure a configure * notify event is sent; see bug 399552. */ window->frame->rect.x + borders.total.left, window->frame->rect.y + borders.total.top); meta_error_trap_pop (window->display); meta_ui_destroy_frame_window (window->screen->ui, frame->xwindow); meta_display_unregister_x_window (window->display, frame->xwindow); window->frame = NULL; if (window->frame_bounds) { cairo_region_destroy (window->frame_bounds); window->frame_bounds = NULL; } /* Move keybindings to window instead of frame */ meta_window_grab_keys (window); free (frame); /* Put our state back where it should be */ meta_window_queue (window, META_QUEUE_CALC_SHOWING); meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } LOCAL_SYMBOL MetaFrameFlags meta_frame_get_flags (MetaFrame *frame) { MetaFrameFlags flags; flags = 0; if (frame->window->border_only) { ; /* FIXME this may disable the _function_ as well as decor * in some cases, which is sort of wrong. */ } else { flags |= META_FRAME_ALLOWS_MENU; if (frame->window->has_close_func) flags |= META_FRAME_ALLOWS_DELETE; if (frame->window->has_maximize_func) flags |= META_FRAME_ALLOWS_MAXIMIZE; if (frame->window->has_minimize_func) flags |= META_FRAME_ALLOWS_MINIMIZE; if (frame->window->has_shade_func) flags |= META_FRAME_ALLOWS_SHADE; } if (META_WINDOW_ALLOWS_MOVE (frame->window)) flags |= META_FRAME_ALLOWS_MOVE; if (META_WINDOW_ALLOWS_HORIZONTAL_RESIZE (frame->window)) flags |= META_FRAME_ALLOWS_HORIZONTAL_RESIZE; if (META_WINDOW_ALLOWS_VERTICAL_RESIZE (frame->window)) flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE; if (META_WINDOW_ALLOWS_TOP_RESIZE (frame->window)) flags |= META_FRAME_ALLOWS_TOP_RESIZE; if (META_WINDOW_ALLOWS_BOTTOM_RESIZE (frame->window)) flags |= META_FRAME_ALLOWS_BOTTOM_RESIZE; if (META_WINDOW_ALLOWS_LEFT_RESIZE (frame->window)) flags |= META_FRAME_ALLOWS_LEFT_RESIZE; if (META_WINDOW_ALLOWS_RIGHT_RESIZE (frame->window)) flags |= META_FRAME_ALLOWS_RIGHT_RESIZE; if (meta_window_appears_focused (frame->window)) flags |= META_FRAME_HAS_FOCUS; if (frame->window->shaded) flags |= META_FRAME_SHADED; if (frame->window->on_all_workspaces_requested) flags |= META_FRAME_STUCK; /* FIXME: Should we have some kind of UI for windows that are just vertically * maximized or just horizontally maximized? */ if (META_WINDOW_MAXIMIZED (frame->window)) flags |= META_FRAME_MAXIMIZED; if (META_WINDOW_TILED_LEFT (frame->window) || META_WINDOW_TILED_ULC (frame->window) || META_WINDOW_TILED_LLC (frame->window)) flags |= META_FRAME_TILED_LEFT; if (META_WINDOW_TILED_RIGHT (frame->window) || META_WINDOW_TILED_URC (frame->window) || META_WINDOW_TILED_LRC (frame->window)) flags |= META_FRAME_TILED_RIGHT; if (META_WINDOW_TILED_TOP (frame->window) || META_WINDOW_TILED_BOTTOM (frame->window)) { flags |= META_FRAME_MAXIMIZED; } if (frame->window->fullscreen) flags |= META_FRAME_FULLSCREEN; if (frame->is_flashing) flags |= META_FRAME_IS_FLASHING; if (frame->window->wm_state_above) flags |= META_FRAME_ABOVE; return flags; } void meta_frame_borders_clear (MetaFrameBorders *self) { self->visible.top = self->invisible.top = self->total.top = 0; self->visible.bottom = self->invisible.bottom = self->total.bottom = 0; self->visible.left = self->invisible.left = self->total.left = 0; self->visible.right = self->invisible.right = self->total.right = 0; } LOCAL_SYMBOL void meta_frame_calc_borders (MetaFrame *frame, MetaFrameBorders *borders) { /* Save on if statements and potential uninitialized values * in callers -- if there's no frame, then zero the borders. */ if (frame == NULL) meta_frame_borders_clear (borders); else { if (!frame->borders_cached) { meta_ui_get_frame_borders (frame->window->screen->ui, frame->xwindow, &frame->cached_borders); frame->borders_cached = TRUE; } *borders = frame->cached_borders; } } void meta_frame_clear_cached_borders (MetaFrame *frame) { frame->borders_cached = FALSE; } LOCAL_SYMBOL void meta_frame_get_corner_radiuses (MetaFrame *frame, float *top_left, float *top_right, float *bottom_left, float *bottom_right) { meta_ui_get_corner_radiuses (frame->window->screen->ui, frame->xwindow, top_left, top_right, bottom_left, bottom_right); } LOCAL_SYMBOL gboolean meta_frame_sync_to_window (MetaFrame *frame, int resize_gravity, gboolean need_move, gboolean need_resize) { meta_topic (META_DEBUG_GEOMETRY, "Syncing frame geometry %d,%d %dx%d (SE: %d,%d)\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, frame->rect.x + frame->rect.width, frame->rect.y + frame->rect.height); meta_ui_move_resize_frame (frame->window->screen->ui, frame->xwindow, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height); if (need_resize) { /* If we're interactively resizing the frame, repaint * it immediately so we don't start to lag. */ if (frame->window->display->grab_window == frame->window) meta_ui_repaint_frame (frame->window->screen->ui, frame->xwindow); } return need_resize; } LOCAL_SYMBOL cairo_region_t * meta_frame_get_frame_bounds (MetaFrame *frame) { return meta_ui_get_frame_bounds (frame->window->screen->ui, frame->xwindow, frame->rect.width, frame->rect.height); } LOCAL_SYMBOL void meta_frame_queue_draw (MetaFrame *frame) { meta_ui_queue_frame_draw (frame->window->screen->ui, frame->xwindow); } LOCAL_SYMBOL void meta_frame_set_screen_cursor (MetaFrame *frame, MetaCursor cursor) { Cursor xcursor; if (cursor == frame->current_cursor) return; frame->current_cursor = cursor; if (cursor == META_CURSOR_DEFAULT) XUndefineCursor (frame->window->display->xdisplay, frame->xwindow); else { xcursor = meta_display_create_x_cursor (frame->window->display, cursor); XDefineCursor (frame->window->display->xdisplay, frame->xwindow, xcursor); XFlush (frame->window->display->xdisplay); XFreeCursor (frame->window->display->xdisplay, xcursor); } } LOCAL_SYMBOL Window meta_frame_get_xwindow (MetaFrame *frame) { return frame->xwindow; } �������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/stack.h�����������������������������������������������������������������������0000664�0001750�0001750�00000034456�14211404421�016145� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * \file stack.h Which windows cover which other windows * * There are two factors that determine window position. * * One is window->stack_position, which is a unique integer * indicating how windows are ordered with respect to one * another. The ordering here transcends layers; it isn't changed * as the window is moved among layers. This allows us to move several * windows from one layer to another, while preserving the relative * order of the moved windows. Also, it allows us to restore * the stacking order from a saved session. * * However when actually stacking windows on the screen, the * layer overrides the stack_position; windows are first sorted * by layer, then by stack_position within each layer. */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_STACK_H #define META_STACK_H #include "screen-private.h" /** * A sorted list of windows bearing some level of resemblance to the stack of * windows on the X server. * * (This is only used as a field within a MetaScreen; we treat it as a separate * class for simplicity.) */ struct _MetaStack { /** The MetaScreen containing this stack. */ MetaScreen *screen; /** * A sequence of all the Windows (X handles, not MetaWindows) of the windows * we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST. */ GArray *windows; /** The MetaWindows of the windows we manage, sorted in order. */ GList *sorted; /** * MetaWindows waiting to be added to the "sorted" and "windows" list, after * being added by meta_stack_add() and before being assimilated by * stack_ensure_sorted(). * * The order of the elements in this list is not important; what is important * is the stack_position element of each window. */ GList *added; /** * Windows (X handles, not MetaWindows) waiting to be removed from the * "windows" list, after being removed by meta_stack_remove() and before * being assimilated by stack_ensure_sorted(). (We already removed them * from the "sorted" list.) * * The order of the elements in this list is not important. */ GList *removed; /** * If this is zero, the local stack oughtn't to be brought up to date with * the X server's stack, because it is in the middle of being updated. * If it is positive, the local stack is said to be "frozen", and will need * to be thawed that many times before the stack can be brought up to date * again. You may freeze the stack with meta_stack_freeze() and thaw it * with meta_stack_thaw(). */ int freeze_count; /** * The last-known stack of all windows, bottom to top. We cache it here * so that subsequent times we'll be able to do incremental moves. */ GArray *last_root_children_stacked; /** * Number of stack positions; same as the length of added, but * kept for quick reference. */ gint n_positions; /** Is the stack in need of re-sorting? */ unsigned int need_resort : 1; /** * Are the windows in the stack in need of having their * layers recalculated? */ unsigned int need_relayer : 1; /** * Are the windows in the stack in need of having their positions * recalculated with respect to transiency (parent and child windows)? */ unsigned int need_constrain : 1; }; /** * Creates and initialises a MetaStack. * * \param screen The MetaScreen which will be the parent of this stack. * \return The new screen. */ MetaStack *meta_stack_new (MetaScreen *screen); /** * Destroys and frees a MetaStack. * * \param stack The stack to destroy. */ void meta_stack_free (MetaStack *stack); /** * Adds a window to the local stack. It is a fatal error to call this * function on a window which already exists on the stack of any screen. * * \param window The window to add * \param stack The stack to add it to */ void meta_stack_add (MetaStack *stack, MetaWindow *window); /** * Removes a window from the local stack. It is a fatal error to call this * function on a window which exists on the stack of any screen. * * \param window The window to remove * \param stack The stack to remove it from */ void meta_stack_remove (MetaStack *stack, MetaWindow *window); /** * Recalculates the correct layer for all windows in the stack, * and moves them about accordingly. * * \param window Dummy parameter * \param stack The stack to recalculate * \bug What's with the dummy parameter? */ void meta_stack_update_layer (MetaStack *stack, MetaWindow *window); /** * Recalculates the correct stacking order for all windows in the stack * according to their transience, and moves them about accordingly. * * \param window Dummy parameter * \param stack The stack to recalculate * \bug What's with the dummy parameter? */ void meta_stack_update_transient (MetaStack *stack, MetaWindow *window); /** * Move a window to the top of its layer. * * \param stack The stack to modify. * \param window The window that's making an ascension. * (Amulet of Yendor not required.) */ void meta_stack_raise (MetaStack *stack, MetaWindow *window); /** * Move a window to the bottom of its layer. * * \param stack The stack to modify. * \param window The window that's on the way downwards. */ void meta_stack_lower (MetaStack *stack, MetaWindow *window); /** * Prevent syncing to server until the next call of meta_stack_thaw(), * so that we can carry out multiple operations in one go without having * everything halfway reflected on the X server. * * (Calls to meta_stack_freeze() nest, so that multiple calls to * meta_stack_freeze will require multiple calls to meta_stack_thaw().) * * \param stack The stack to freeze. */ void meta_stack_freeze (MetaStack *stack); /** * Undoes a meta_stack_freeze(), and processes anything which has become * necessary during the freeze. It is an error to call this function if * the stack has not been frozen. * * \param stack The stack to thaw. */ void meta_stack_thaw (MetaStack *stack); /** * Finds the top window on the stack. * * \param stack The stack to examine. * \return The top window on the stack, or NULL in the vanishingly unlikely * event that you have no windows on your screen whatsoever. */ MetaWindow* meta_stack_get_top (MetaStack *stack); /** * Finds the window at the bottom of the stack. Since that's pretty much * always the desktop, this isn't the most useful of functions, and nobody * actually calls it. We should probably get rid of it. * * \param stack The stack to search */ MetaWindow* meta_stack_get_bottom (MetaStack *stack); /** * Finds the window above a given window in the stack. * It is not an error to pass in a window which does not exist in * the stack; the function will merely return NULL. * * \param stack The stack to search. * \param window The window to look above. * \param only_within_layer If true, will return NULL if "window" is the * top window in its layer. * \return NULL if there is no such window; * the window above "window" otherwise. */ MetaWindow* meta_stack_get_above (MetaStack *stack, MetaWindow *window, gboolean only_within_layer); /** * Finds the window below a given window in the stack. * It is not an error to pass in a window which does not exist in * the stack; the function will merely return NULL. * * \param stack The stack to search. * \param window The window to look below. * \param only_within_layer If true, will return NULL if "window" is the * bottom window in its layer. * \return NULL if there is no such window; * the window below "window" otherwise. */ MetaWindow* meta_stack_get_below (MetaStack *stack, MetaWindow *window, gboolean only_within_layer); /** * Find the topmost, focusable, mapped, window in a stack. If you supply * a window as "not_this_one", we won't return that one (presumably * because it's going to be going away). But if you do supply "not_this_one" * and we find its parent, we'll return that; and if "not_this_one" is in * a group, we'll return the top window of that group. * * Also, we are prejudiced against dock windows. Every kind of window, even * the desktop, will be returned in preference to a dock window. * * \param stack The stack to search. * \param workspace NULL to search all workspaces; otherwise only windows * from that workspace will be returned. * \param not_this_one Window to ignore because it's being unfocussed or * going away. * \return The window matching all these constraints or NULL if none does. * * \bug Never called! */ MetaWindow* meta_stack_get_default_focus_window (MetaStack *stack, MetaWorkspace *workspace, MetaWindow *not_this_one); /** * Find the topmost, focusable, mapped, window in a stack. If you supply * a window as "not_this_one", we won't return that one (presumably * because it's going to be going away). But if you do supply "not_this_one" * and we find its parent, we'll return that; and if "not_this_one" is in * a group, we'll return the top window of that group. * * Also, we are prejudiced against dock windows. Every kind of window, even * the desktop, will be returned in preference to a dock window. * * \param stack The stack to search. * \param workspace NULL to search all workspaces; otherwise only windows * from that workspace will be returned. * \param not_this_one Window to ignore because it's being unfocussed or * going away. * \param root_x The returned window must contain this point, * unless it's a dock. * \param root_y See root_x. * \return The window matching all these constraints or NULL if none does. */ MetaWindow* meta_stack_get_default_focus_window_at_point (MetaStack *stack, MetaWorkspace *workspace, MetaWindow *not_this_one, int root_x, int root_y); /** * Finds all the windows in the stack, in order. * * \param stack The stack to examine. * \param workspace If non-NULL, only windows on this workspace will be * returned; otherwise all windows in the stack will be * returned. * \return A list of windows, in stacking order, honouring layers. */ GList* meta_stack_list_windows (MetaStack *stack, MetaWorkspace *workspace); /** * Comparison function for windows within a stack. This is not directly * suitable for use within a standard comparison routine, because it takes * an extra parameter; you will need to wrap it. * * (FIXME: We could remove the stack parameter and use the stack of * the screen of window A, and complain if the stack of the screen of * window B differed; then this would be a usable general comparison function.) * * (FIXME: Apparently identical to compare_window_position(). Merge them.) * * \param stack A stack containing both window_a and window_b * \param window_a A window * \param window_b Another window * \return -1 if window_a is below window_b, honouring layers; 1 if it's * above it; 0 if you passed in the same window twice! */ int meta_stack_windows_cmp (MetaStack *stack, MetaWindow *window_a, MetaWindow *window_b); /** * Sets the position of a window within the stack. This will only move it * up or down within its layer. It is an error to attempt to move this * below position zero or above the last position in the stack (however, since * we don't provide a simple way to tell the number of windows in the stack, * this requirement may not be easy to fulfil). * * \param window The window which is moving. * \param position Where it should move to (0 is the bottom). */ void meta_window_set_stack_position (MetaWindow *window, int position); /** * Returns the current stack state, allowing rudimentary transactions. * * \param stack The stack to examine. * \return An opaque GList representing the current stack sort order; * it is the caller's responsibility to free it. * Pass this to meta_stack_set_positions() later if you want to restore * the state to where it was when you called this function. */ GList* meta_stack_get_positions (MetaStack *stack); /** * Rolls back a transaction, given the list returned from * meta_stack_get_positions(). * * \param stack The stack to roll back. * \param windows The list returned from meta_stack_get_positions(). */ void meta_stack_set_positions (MetaStack *stack, GList *windows); void meta_stack_update_window_tile_matches (MetaStack *stack, MetaWorkspace *workspace); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/group-private.h���������������������������������������������������������������0000664�0001750�0001750�00000002147�14211404421�017634� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window group private header */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_GROUP_PRIVATE_H #define META_GROUP_PRIVATE_H #include <meta/group.h> struct _MetaGroup { int refcount; MetaDisplay *display; GSList *windows; Window group_leader; char *startup_id; char *wm_client_machine; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/core/stack.c�����������������������������������������������������������������������0000664�0001750�0001750�00000140666�14211404421�016141� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /** * SECTION:stack * @short_description: Which windows cover which other windows */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002, 2003 Red Hat, Inc. * Copyright (C) 2004 Rob Adams * Copyright (C) 2004, 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "stack.h" #include "window-private.h" #include <meta/errors.h> #include "frame.h" #include <meta/group.h> #include <meta/prefs.h> #include <meta/workspace.h> #include <X11/Xatom.h> #define WINDOW_HAS_TRANSIENT_TYPE(w) \ (w->type == META_WINDOW_DIALOG || \ w->type == META_WINDOW_MODAL_DIALOG || \ w->type == META_WINDOW_TOOLBAR || \ w->type == META_WINDOW_MENU || \ w->type == META_WINDOW_UTILITY) #define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w) \ ((w->xtransient_for == None || \ w->transient_parent_is_root_window) && \ WINDOW_HAS_TRANSIENT_TYPE (w)) #define WINDOW_IN_STACK(w) (w->stack_position >= 0) static void stack_sync_to_server (MetaStack *stack); static void meta_window_set_stack_position_no_sync (MetaWindow *window, int position); static void stack_do_window_deletions (MetaStack *stack); static void stack_do_window_additions (MetaStack *stack); static void stack_do_relayer (MetaStack *stack); static void stack_do_constrain (MetaStack *stack); static void stack_do_resort (MetaStack *stack); static void stack_ensure_sorted (MetaStack *stack); LOCAL_SYMBOL MetaStack* meta_stack_new (MetaScreen *screen) { MetaStack *stack; stack = g_new (MetaStack, 1); stack->screen = screen; stack->windows = g_array_new (FALSE, FALSE, sizeof (Window)); stack->sorted = NULL; stack->added = NULL; stack->removed = NULL; stack->freeze_count = 0; stack->last_root_children_stacked = NULL; stack->n_positions = 0; stack->need_resort = FALSE; stack->need_relayer = FALSE; stack->need_constrain = FALSE; return stack; } LOCAL_SYMBOL void meta_stack_free (MetaStack *stack) { g_array_free (stack->windows, TRUE); g_list_free (stack->sorted); g_list_free (stack->added); g_list_free (stack->removed); if (stack->last_root_children_stacked) g_array_free (stack->last_root_children_stacked, TRUE); free (stack); } LOCAL_SYMBOL void meta_stack_add (MetaStack *stack, MetaWindow *window) { meta_topic (META_DEBUG_STACK, "Adding window %s to the stack\n", window->desc); if (window->stack_position >= 0) meta_bug ("Window %s had stack position already\n", window->desc); stack->added = g_list_prepend (stack->added, window); window->stack_position = stack->n_positions; stack->n_positions += 1; meta_topic (META_DEBUG_STACK, "Window %s has stack_position initialized to %d\n", window->desc, window->stack_position); stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } LOCAL_SYMBOL void meta_stack_remove (MetaStack *stack, MetaWindow *window) { meta_topic (META_DEBUG_STACK, "Removing window %s from the stack\n", window->desc); if (window->stack_position < 0) meta_bug ("Window %s removed from stack but had no stack position\n", window->desc); /* Set window to top position, so removing it will not leave gaps * in the set of positions */ meta_window_set_stack_position_no_sync (window, stack->n_positions - 1); window->stack_position = -1; stack->n_positions -= 1; /* We don't know if it's been moved from "added" to "stack" yet */ stack->added = g_list_remove (stack->added, window); stack->sorted = g_list_remove (stack->sorted, window); /* Remember the window ID to remove it from the stack array. * The macro is safe to use: Window is guaranteed to be 32 bits, and * GUINT_TO_POINTER says it only works on 32 bits. */ stack->removed = g_list_prepend (stack->removed, GUINT_TO_POINTER (window->xwindow)); if (window->frame) stack->removed = g_list_prepend (stack->removed, GUINT_TO_POINTER (window->frame->xwindow)); stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } LOCAL_SYMBOL void meta_stack_update_layer (MetaStack *stack, MetaWindow *window) { stack->need_relayer = TRUE; stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } LOCAL_SYMBOL void meta_stack_update_transient (MetaStack *stack, MetaWindow *window) { stack->need_constrain = TRUE; stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } /* raise/lower within a layer */ LOCAL_SYMBOL void meta_stack_raise (MetaStack *stack, MetaWindow *window) { GList *l; int max_stack_position = window->stack_position; MetaWorkspace *workspace; stack_ensure_sorted (stack); workspace = meta_window_get_workspace (window); for (l = stack->sorted; l; l = l->next) { MetaWindow *w = (MetaWindow *) l->data; if (meta_window_located_on_workspace (w, workspace) && w->stack_position > max_stack_position) max_stack_position = w->stack_position; } if (max_stack_position == window->stack_position) return; meta_window_set_stack_position_no_sync (window, max_stack_position); stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } LOCAL_SYMBOL void meta_stack_lower (MetaStack *stack, MetaWindow *window) { GList *l; int min_stack_position = window->stack_position; MetaWorkspace *workspace; stack_ensure_sorted (stack); workspace = meta_window_get_workspace (window); for (l = stack->sorted; l; l = l->next) { MetaWindow *w = (MetaWindow *) l->data; if (meta_window_located_on_workspace (w, workspace) && w->stack_position < min_stack_position) min_stack_position = w->stack_position; } if (min_stack_position == window->stack_position) return; meta_window_set_stack_position_no_sync (window, min_stack_position); stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } LOCAL_SYMBOL void meta_stack_freeze (MetaStack *stack) { stack->freeze_count += 1; } LOCAL_SYMBOL void meta_stack_thaw (MetaStack *stack) { g_return_if_fail (stack->freeze_count > 0); stack->freeze_count -= 1; stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, NULL); } LOCAL_SYMBOL void meta_stack_update_window_tile_matches (MetaStack *stack, MetaWorkspace *workspace) { GList *windows, *tmp; if (stack->freeze_count > 0) return; windows = meta_stack_list_windows (stack, workspace); tmp = windows; while (tmp) { meta_window_compute_tile_match ((MetaWindow *) tmp->data); tmp = tmp->next; } g_list_free (windows); } /* Get layer ignoring any transient or group relationships */ static MetaStackLayer get_standalone_layer (MetaWindow *window) { MetaStackLayer layer; switch (window->type) { case META_WINDOW_DESKTOP: layer = META_LAYER_DESKTOP; break; case META_WINDOW_DOCK: /* still experimenting here */ if (window->wm_state_below || (window->monitor && window->monitor->in_fullscreen)) { layer = META_LAYER_BOTTOM; } else { layer = META_LAYER_DOCK; } break; case META_WINDOW_DROPDOWN_MENU: case META_WINDOW_POPUP_MENU: case META_WINDOW_TOOLTIP: case META_WINDOW_NOTIFICATION: case META_WINDOW_COMBO: case META_WINDOW_OVERRIDE_OTHER: layer = META_LAYER_OVERRIDE_REDIRECT; break; default: if (window->wm_state_below) layer = META_LAYER_BOTTOM; else if (window->wm_state_above) layer = META_LAYER_TOP; else layer = META_LAYER_NORMAL; break; } return layer; } /* Note that this function can never use window->layer only * get_standalone_layer, or we'd have issues. */ static MetaStackLayer get_maximum_layer_in_group (MetaWindow *window) { GSList *members; MetaGroup *group; GSList *tmp; MetaStackLayer max; MetaStackLayer layer; max = META_LAYER_DESKTOP; group = meta_window_get_group (window); if (group != NULL) members = meta_group_list_windows (group); else members = NULL; tmp = members; while (tmp != NULL) { MetaWindow *w = tmp->data; if (!w->override_redirect) { layer = get_standalone_layer (w); if (layer > max) max = layer; } tmp = tmp->next; } g_slist_free (members); return max; } static void compute_layer (MetaWindow *window) { window->layer = get_standalone_layer (window); /* We can only do promotion-due-to-group for dialogs and other * transients, or weird stuff happens like the desktop window and * nautilus windows getting in the same layer, or all gnome-terminal * windows getting in fullscreen layer if any terminal is * fullscreen. */ if (window->layer != META_LAYER_DESKTOP && WINDOW_HAS_TRANSIENT_TYPE(window) && (window->xtransient_for == None || window->transient_parent_is_root_window)) { /* We only do the group thing if the dialog is NOT transient for * a particular window. Imagine a group with a normal window, a dock, * and a dialog transient for the normal window; you don't want the dialog * above the dock if it wouldn't normally be. */ MetaStackLayer group_max; group_max = get_maximum_layer_in_group (window); if (group_max > window->layer) { meta_topic (META_DEBUG_STACK, "Promoting window %s from layer %u to %u due to group membership\n", window->desc, window->layer, group_max); window->layer = group_max; } } meta_topic (META_DEBUG_STACK, "Window %s on layer %u type = %u has_focus = %d\n", window->desc, window->layer, window->type, window->has_focus); } /* Front of the layer list is the topmost window, * so the lower stack position is later in the list */ static int compare_window_position (void *a, void *b) { MetaWindow *window_a = a; MetaWindow *window_b = b; /* Go by layer, then stack_position */ if (window_a->layer < window_b->layer) return 1; /* move window_a later in list */ else if (window_a->layer > window_b->layer) return -1; else if (window_a->stack_position < window_b->stack_position) return 1; /* move window_a later in list */ else if (window_a->stack_position > window_b->stack_position) return -1; else return 0; /* not reached */ } /* * Stacking constraints * * Assume constraints of the form "AB" meaning "window A must be * below window B" * * If we have windows stacked from bottom to top * "ABC" then raise A we get "BCA". Say C is * transient for B is transient for A. So * we have constraints AB and BC. * * After raising A, we need to reapply the constraints. * If we do this by raising one window at a time - * * start: BCA * apply AB: CAB * apply BC: ABC * * but apply constraints in the wrong order and it breaks: * * start: BCA * apply BC: BCA * apply AB: CAB * * We make a directed graph of the constraints by linking * from "above windows" to "below windows as follows: * * AB -> BC -> CD * \ * CE * * If we then walk that graph and apply the constraints in the order * that they appear, we will apply them correctly. Note that the * graph MAY have cycles, so we have to guard against that. * */ typedef struct Constraint Constraint; struct Constraint { MetaWindow *above; MetaWindow *below; /* used to keep the constraint in the * list of constraints for window "below" */ Constraint *next; /* used to create the graph. */ GSList *next_nodes; /* constraint has been applied, used * to detect cycles. */ unsigned int applied : 1; /* constraint has a previous node in the graph, * used to find places to start in the graph. * (I think this also has the side effect * of preventing cycles, since cycles will * have no starting point - so maybe * the "applied" flag isn't needed.) */ unsigned int has_prev : 1; }; /* We index the array of constraints by window * stack positions, just because the stack * positions are a convenient index. */ static void add_constraint (Constraint **constraints, MetaWindow *above, MetaWindow *below) { Constraint *c; g_assert (above->screen == below->screen); /* check if constraint is a duplicate */ c = constraints[below->stack_position]; while (c != NULL) { if (c->above == above) return; c = c->next; } /* if not, add the constraint */ c = g_new (Constraint, 1); c->above = above; c->below = below; c->next = constraints[below->stack_position]; c->next_nodes = NULL; c->applied = FALSE; c->has_prev = FALSE; constraints[below->stack_position] = c; } static void create_constraints (Constraint **constraints, GList *windows) { GList *tmp; tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (!WINDOW_IN_STACK (w)) { meta_topic (META_DEBUG_STACK, "Window %s not in the stack, not constraining it\n", w->desc); tmp = tmp->next; continue; } if (WINDOW_TRANSIENT_FOR_WHOLE_GROUP (w)) { GSList *group_windows; GSList *tmp2; MetaGroup *group; group = meta_window_get_group (w); if (group != NULL) group_windows = meta_group_list_windows (group); else group_windows = NULL; tmp2 = group_windows; while (tmp2 != NULL) { MetaWindow *group_window = tmp2->data; if (!WINDOW_IN_STACK (group_window) || w->screen != group_window->screen || group_window->override_redirect) { tmp2 = tmp2->next; continue; } #if 0 /* old way of doing it */ if (!(meta_window_is_ancestor_of_transient (w, group_window)) && !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window)) /* note */;/*note*/ #else /* better way I think, so transient-for-group are constrained * only above non-transient-type windows in their group */ if (!WINDOW_HAS_TRANSIENT_TYPE (group_window)) #endif { meta_topic (META_DEBUG_STACK, "Constraining %s above %s as it's transient for its group\n", w->desc, group_window->desc); add_constraint (constraints, w, group_window); } tmp2 = tmp2->next; } g_slist_free (group_windows); } else if (w->xtransient_for != None && !w->transient_parent_is_root_window) { MetaWindow *parent; parent = meta_display_lookup_x_window (w->display, w->xtransient_for); if (parent && WINDOW_IN_STACK (parent) && parent->screen == w->screen) { meta_topic (META_DEBUG_STACK, "Constraining %s above %s due to transiency\n", w->desc, parent->desc); add_constraint (constraints, w, parent); } } tmp = tmp->next; } } static void graph_constraints (Constraint **constraints, int n_constraints) { int i; i = 0; while (i < n_constraints) { Constraint *c; /* If we have "A below B" and "B below C" then AB -> BC so we * add BC to next_nodes in AB. */ c = constraints[i]; while (c != NULL) { Constraint *n; g_assert (c->below->stack_position == i); /* Constraints where ->above is below are our * next_nodes and we are their previous */ n = constraints[c->above->stack_position]; while (n != NULL) { c->next_nodes = g_slist_prepend (c->next_nodes, n); /* c is a previous node of n */ n->has_prev = TRUE; n = n->next; } c = c->next; } ++i; } } static void free_constraints (Constraint **constraints, int n_constraints) { int i; i = 0; while (i < n_constraints) { Constraint *c; c = constraints[i]; while (c != NULL) { Constraint *next = c->next; g_slist_free (c->next_nodes); free (c); c = next; } ++i; } } static void ensure_above (MetaWindow *above, MetaWindow *below) { if (WINDOW_HAS_TRANSIENT_TYPE(above) && above->layer < below->layer) { meta_topic (META_DEBUG_STACK, "Promoting window %s from layer %u to %u due to contraint\n", above->desc, above->layer, below->layer); above->layer = below->layer; } if (above->stack_position < below->stack_position) { /* move above to below->stack_position bumping below down the stack */ meta_window_set_stack_position_no_sync (above, below->stack_position); g_assert (below->stack_position + 1 == above->stack_position); } meta_topic (META_DEBUG_STACK, "%s above at %d > %s below at %d\n", above->desc, above->stack_position, below->desc, below->stack_position); } static void traverse_constraint (Constraint *c) { GSList *tmp; if (c->applied) return; ensure_above (c->above, c->below); c->applied = TRUE; tmp = c->next_nodes; while (tmp != NULL) { traverse_constraint (tmp->data); tmp = tmp->next; } } static void apply_constraints (Constraint **constraints, int n_constraints) { GSList *heads; GSList *tmp; int i; /* List all heads in an ordered constraint chain */ heads = NULL; i = 0; while (i < n_constraints) { Constraint *c; c = constraints[i]; while (c != NULL) { if (!c->has_prev) heads = g_slist_prepend (heads, c); c = c->next; } ++i; } /* Now traverse the chain and apply constraints */ tmp = heads; while (tmp != NULL) { Constraint *c = tmp->data; traverse_constraint (c); tmp = tmp->next; } g_slist_free (heads); } /* * Go through "deleted" and take the matching windows * out of "windows". */ static void stack_do_window_deletions (MetaStack *stack) { /* Do removals before adds, with paranoid idea that we might re-add * the same window IDs. */ GList *tmp; int i; tmp = stack->removed; while (tmp != NULL) { Window xwindow; xwindow = GPOINTER_TO_UINT (tmp->data); /* We go from the end figuring removals are more * likely to be recent. */ i = stack->windows->len; while (i > 0) { --i; /* there's no guarantee we'll actually find windows to * remove, e.g. the same xwindow could have been * added/removed before we ever synced, and we put * both the window->xwindow and window->frame->xwindow * in the removal list. */ if (xwindow == g_array_index (stack->windows, Window, i)) { g_array_remove_index (stack->windows, i); goto next; } } next: tmp = tmp->next; } g_list_free (stack->removed); stack->removed = NULL; } static void stack_do_window_additions (MetaStack *stack) { GList *tmp; gint i, n_added; n_added = g_list_length (stack->added); if (n_added > 0) { Window *end; int old_size; meta_topic (META_DEBUG_STACK, "Adding %d windows to sorted list\n", n_added); old_size = stack->windows->len; g_array_set_size (stack->windows, old_size + n_added); end = &g_array_index (stack->windows, Window, old_size); /* stack->added has the most recent additions at the * front of the list, so we need to reverse it */ stack->added = g_list_reverse (stack->added); i = 0; tmp = stack->added; while (tmp != NULL) { MetaWindow *w; w = tmp->data; end[i] = w->xwindow; /* add to the main list */ stack->sorted = g_list_prepend (stack->sorted, w); ++i; tmp = tmp->next; } stack->need_resort = TRUE; /* may not be needed as we add to top */ stack->need_constrain = TRUE; stack->need_relayer = TRUE; } g_list_free (stack->added); stack->added = NULL; } /* * Update the layers that windows are in */ static void stack_do_relayer (MetaStack *stack) { GList *tmp; if (!stack->need_relayer) return; meta_topic (META_DEBUG_STACK, "Recomputing layers\n"); tmp = stack->sorted; while (tmp != NULL) { MetaWindow *w; MetaStackLayer old_layer; w = tmp->data; old_layer = w->layer; compute_layer (w); if (w->layer != old_layer) { meta_topic (META_DEBUG_STACK, "Window %s moved from layer %u to %u\n", w->desc, old_layer, w->layer); stack->need_resort = TRUE; stack->need_constrain = TRUE; /* don't need to constrain as constraining * purely operates in terms of stack_position * not layer */ } tmp = tmp->next; } stack->need_relayer = FALSE; } /* * Update stack_position and layer to reflect transiency * constraints */ static void stack_do_constrain (MetaStack *stack) { Constraint **constraints; /* It'd be nice if this were all faster, probably */ if (!stack->need_constrain) return; meta_topic (META_DEBUG_STACK, "Reapplying constraints\n"); constraints = g_new0 (Constraint*, stack->n_positions); create_constraints (constraints, stack->sorted); graph_constraints (constraints, stack->n_positions); apply_constraints (constraints, stack->n_positions); free_constraints (constraints, stack->n_positions); free (constraints); stack->need_constrain = FALSE; } /* * Sort stack->sorted with layers having priority over stack_position. */ static void stack_do_resort (MetaStack *stack) { if (!stack->need_resort) return; meta_topic (META_DEBUG_STACK, "Sorting stack list\n"); stack->sorted = g_list_sort (stack->sorted, (GCompareFunc) compare_window_position); meta_screen_queue_check_fullscreen (stack->screen); stack->need_resort = FALSE; } /* * Puts the stack into canonical form. * * Honour the removed and added lists of the stack, and then recalculate * all the layers (if the flag is set), re-run all the constraint calculations * (if the flag is set), and finally re-sort the stack (if the flag is set, * and if it wasn't already it might have become so during all the previous * activity). */ static void stack_ensure_sorted (MetaStack *stack) { stack_do_window_deletions (stack); stack_do_window_additions (stack); stack_do_relayer (stack); stack_do_constrain (stack); stack_do_resort (stack); } /* * This function is used to avoid raising a window above popup * menus and other such things. * * The key to the operation of this function is that we are expecting * at most one window to be added at a time. If xwindow is newly added, * then its own stack position will be too high (the frame window * is created at the top of the stack), but if we ignore xwindow, * then the *next* managed window in the stack will be a window that * we've already stacked. * * We could generalize this and remove the assumption that windows * are added one at a time by keeping an explicit ->stacked flag in * MetaWindow. * * An alternate approach would be to reverse the stacking algorithm to * work by placing each window above the others, and start by lowering * a window to the bottom (instead of the current way, which works by * placing each window below another and starting with a raise) */ static void raise_window_relative_to_managed_windows (MetaScreen *screen, Window xwindow) { Window *children; int n_children; int i; meta_stack_tracker_get_stack (screen->stack_tracker, &children, &n_children); /* Children are in order from bottom to top. We want to * find the topmost managed child, then configure * our window to be above it. */ i = n_children - 1; while (i >= 0) { if (children[i] == xwindow) { /* Do nothing. This means we're already the topmost managed * window, but it DOES NOT mean we are already just above * the topmost managed window. This is important because if * an override redirect window is up, and we map a new * managed window, the new window is probably above the old * popup by default, and we want to push it below that * popup. So keep looking for a sibling managed window * to be moved below. */ } else { MetaWindow *other = meta_display_lookup_x_window (screen->display, children[i]); if (other != NULL && !other->override_redirect && !other->unmanaging) { XWindowChanges changes; /* children[i] is the topmost managed child */ meta_topic (META_DEBUG_STACK, "Moving 0x%lx above topmost managed child window 0x%lx\n", xwindow, children[i]); changes.sibling = children[i]; changes.stack_mode = Above; meta_error_trap_push (screen->display); meta_stack_tracker_record_raise_above (screen->stack_tracker, xwindow, children[i], XNextRequest (screen->display->xdisplay)); XConfigureWindow (screen->display->xdisplay, xwindow, CWSibling | CWStackMode, &changes); meta_error_trap_pop (screen->display); break; } } --i; } if (i < 0) { /* No sibling to use, just lower ourselves to the bottom * to be sure we're below any override redirect windows. */ meta_error_trap_push (screen->display); meta_stack_tracker_record_lower (screen->stack_tracker, xwindow, XNextRequest (screen->display->xdisplay)); XLowerWindow (screen->display->xdisplay, xwindow); meta_error_trap_pop (screen->display); } } /* * Order the windows on the X server to be the same as in our structure. * We do this using XRestackWindows if we don't know the previous order, * or XConfigureWindow on a few particular windows if we do and can figure * out the minimum set of changes. After that, we set __NET_CLIENT_LIST * and __NET_CLIENT_LIST_STACKING. * * FIXME: Now that we have a good view of the stacking order on the server * with MetaStackTracker it should be possible to do a simpler and better * job of computing the minimal set of stacking requests needed. */ static void stack_sync_to_server (MetaStack *stack) { GArray *stacked; GArray *root_children_stacked; GList *tmp; GArray *all_hidden; int n_override_redirect = 0; int n_unmanaging = 0; /* Bail out if frozen */ if (stack->freeze_count > 0) return; meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n"); stack_ensure_sorted (stack); /* Create stacked xwindow arrays. * Painfully, "stacked" is in bottom-to-top order for the * _NET hints, and "root_children_stacked" is in top-to-bottom * order for XRestackWindows() */ stacked = g_array_new (FALSE, FALSE, sizeof (Window)); root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); all_hidden = g_array_new (FALSE, FALSE, sizeof (Window)); /* The screen guard window sits above all hidden windows and acts as * a barrier to input reaching these windows. */ g_array_append_val (all_hidden, stack->screen->guard_window); meta_topic (META_DEBUG_STACK, "Top to bottom: "); meta_push_no_msg_prefix (); for (tmp = stack->sorted; tmp != NULL; tmp = tmp->next) { MetaWindow *w = tmp->data; Window top_level_window; if (w->unmanaging) { n_unmanaging ++; continue; } meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc); /* remember, stacked is in reverse order (bottom to top) */ if (w->override_redirect) n_override_redirect++; else g_array_prepend_val (stacked, w->xwindow); if (w->frame) top_level_window = w->frame->xwindow; else top_level_window = w->xwindow; /* We don't restack hidden windows along with the rest, though they are * reflected in the _NET hints. Hidden windows all get pushed below * the screens fullscreen guard_window. */ if (w->hidden) { g_array_append_val (all_hidden, top_level_window); continue; } /* build XRestackWindows() array from top to bottom */ g_array_append_val (root_children_stacked, top_level_window); } meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); /* All windows should be in some stacking order */ if (stacked->len != stack->windows->len - n_override_redirect - n_unmanaging) meta_bug ("%u windows stacked, %u windows exist in stack\n", stacked->len, stack->windows->len); /* Sync to server */ meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", root_children_stacked->len); meta_error_trap_push (stack->screen->display); if (stack->last_root_children_stacked == NULL) { /* Just impose our stack, we don't know the previous state. * This involves a ton of circulate requests and may flicker. */ meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n"); if (root_children_stacked->len > 0) { meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, (Window *) root_children_stacked->data, root_children_stacked->len, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, (Window *) root_children_stacked->data, root_children_stacked->len); } } else if (root_children_stacked->len > 0) { /* Try to do minimal window moves to get the stack in order */ /* A point of note: these arrays include frames not client windows, * so if a client window has changed frame since last_root_children_stacked * was saved, then we may have inefficiency, but I don't think things * break... */ const Window *old_stack = (Window *) stack->last_root_children_stacked->data; const Window *new_stack = (Window *) root_children_stacked->data; const int old_len = stack->last_root_children_stacked->len; const int new_len = root_children_stacked->len; const Window *oldp = old_stack; const Window *newp = new_stack; const Window *old_end = old_stack + old_len; const Window *new_end = new_stack + new_len; Window last_window = None; while (oldp != old_end && newp != new_end) { if (*oldp == *newp) { /* Stacks are the same here, move on */ ++oldp; last_window = *newp; ++newp; } else if (meta_display_lookup_x_window (stack->screen->display, *oldp) == NULL) { /* *oldp is no longer known to us (probably destroyed), * so we can just skip it */ ++oldp; } else { /* Move *newp below last_window */ if (last_window == None) { meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp); raise_window_relative_to_managed_windows (stack->screen, *newp); } else { /* This means that if last_window is dead, but not * *newp, then we fail to restack *newp; but on * unmanaging last_window, we'll fix it up. */ XWindowChanges changes; changes.sibling = last_window; changes.stack_mode = Below; meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n", *newp, last_window); meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, *newp, last_window, XNextRequest (stack->screen->display->xdisplay)); XConfigureWindow (stack->screen->display->xdisplay, *newp, CWSibling | CWStackMode, &changes); } last_window = *newp; ++newp; } } if (newp != new_end) { /* Restack remaining windows */ meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n", (int) (new_end - newp)); /* We need to include an already-stacked window * in the restack call, so we get in the proper position * with respect to it. */ if (newp != new_stack) --newp; meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, (Window *) newp, new_end - newp, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, (Window *) newp, new_end - newp); } } /* Push hidden windows to the bottom of the stack under the guard window */ meta_stack_tracker_record_lower (stack->screen->stack_tracker, stack->screen->guard_window, XNextRequest (stack->screen->display->xdisplay)); XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window); meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, (Window *)all_hidden->data, all_hidden->len, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, (Window *)all_hidden->data, all_hidden->len); g_array_free (all_hidden, TRUE); meta_error_trap_pop (stack->screen->display); /* on error, a window was destroyed; it should eventually * get removed from the stacking list when we unmanage it * and we'll fix stacking at that time. */ /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */ XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST, XA_WINDOW, 32, PropModeReplace, (unsigned char *)stack->windows->data, stack->windows->len); XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST_STACKING, XA_WINDOW, 32, PropModeReplace, (unsigned char *)stacked->data, stacked->len); g_array_free (stacked, TRUE); if (stack->last_root_children_stacked) g_array_free (stack->last_root_children_stacked, TRUE); stack->last_root_children_stacked = root_children_stacked; /* That was scary... */ } LOCAL_SYMBOL MetaWindow* meta_stack_get_top (MetaStack *stack) { stack_ensure_sorted (stack); if (stack->sorted) return stack->sorted->data; else return NULL; } LOCAL_SYMBOL MetaWindow* meta_stack_get_bottom (MetaStack *stack) { GList *link; stack_ensure_sorted (stack); link = g_list_last (stack->sorted); if (link != NULL) return link->data; else return NULL; } LOCAL_SYMBOL MetaWindow* meta_stack_get_above (MetaStack *stack, MetaWindow *window, gboolean only_within_layer) { GList *link; MetaWindow *above; stack_ensure_sorted (stack); link = g_list_find (stack->sorted, window); if (link == NULL) return NULL; if (link->prev == NULL) return NULL; above = link->prev->data; if (only_within_layer && above->layer != window->layer) return NULL; else return above; } LOCAL_SYMBOL MetaWindow* meta_stack_get_below (MetaStack *stack, MetaWindow *window, gboolean only_within_layer) { GList *link; MetaWindow *below; stack_ensure_sorted (stack); link = g_list_find (stack->sorted, window); if (link == NULL) return NULL; if (link->next == NULL) return NULL; below = link->next->data; if (only_within_layer && below->layer != window->layer) return NULL; else return below; } static gboolean window_contains_point (MetaWindow *window, int root_x, int root_y) { MetaRectangle rect; meta_window_get_outer_rect (window, &rect); return META_POINT_IN_RECT (root_x, root_y, rect); } static MetaWindow* get_default_focus_window (MetaStack *stack, MetaWorkspace *workspace, MetaWindow *not_this_one, gboolean must_be_at_point, int root_x, int root_y) { /* Find the topmost, focusable, mapped, window. * not_this_one is being unfocused or going away, so exclude it. * Also, prefer to focus transient parent of not_this_one, * or top window in same group as not_this_one. */ MetaWindow *topmost_dock; MetaWindow *transient_parent; MetaWindow *topmost_in_group; MetaWindow *topmost_overall; MetaGroup *not_this_one_group; GList *link; topmost_dock = NULL; transient_parent = NULL; topmost_in_group = NULL; topmost_overall = NULL; if (not_this_one) not_this_one_group = meta_window_get_group (not_this_one); else not_this_one_group = NULL; stack_ensure_sorted (stack); /* top of this layer is at the front of the list */ link = stack->sorted; while (link) { MetaWindow *window = link->data; if (window && window != not_this_one && (window->unmaps_pending == 0) && !window->minimized && (window->input || window->take_focus) && (workspace == NULL || meta_window_located_on_workspace (window, workspace))) { if (topmost_dock == NULL && window->type == META_WINDOW_DOCK) topmost_dock = window; if (not_this_one != NULL) { if (transient_parent == NULL && not_this_one->xtransient_for != None && not_this_one->xtransient_for == window->xwindow && (!must_be_at_point || window_contains_point (window, root_x, root_y))) transient_parent = window; if (topmost_in_group == NULL && not_this_one_group != NULL && not_this_one_group == meta_window_get_group (window) && (!must_be_at_point || window_contains_point (window, root_x, root_y))) topmost_in_group = window; } /* Note that DESKTOP windows can be topmost_overall so * we prefer focusing desktop or other windows over * focusing dock, even though docks are stacked higher. */ if (topmost_overall == NULL && window->type != META_WINDOW_DOCK && (!must_be_at_point || window_contains_point (window, root_x, root_y))) topmost_overall = window; /* We could try to bail out early here for efficiency in * some cases, but it's just not worth the code. */ } link = link->next; } if (transient_parent) return transient_parent; else if (topmost_in_group) return topmost_in_group; else if (topmost_overall) return topmost_overall; else return topmost_dock; } LOCAL_SYMBOL MetaWindow* meta_stack_get_default_focus_window_at_point (MetaStack *stack, MetaWorkspace *workspace, MetaWindow *not_this_one, int root_x, int root_y) { return get_default_focus_window (stack, workspace, not_this_one, TRUE, root_x, root_y); } LOCAL_SYMBOL MetaWindow* meta_stack_get_default_focus_window (MetaStack *stack, MetaWorkspace *workspace, MetaWindow *not_this_one) { return get_default_focus_window (stack, workspace, not_this_one, FALSE, 0, 0); } LOCAL_SYMBOL GList* meta_stack_list_windows (MetaStack *stack, MetaWorkspace *workspace) { GList *workspace_windows = NULL; GList *link; stack_ensure_sorted (stack); /* do adds/removes */ link = stack->sorted; while (link) { MetaWindow *window = link->data; if (window && (workspace == NULL || meta_window_located_on_workspace (window, workspace))) { workspace_windows = g_list_prepend (workspace_windows, window); } link = link->next; } return workspace_windows; } LOCAL_SYMBOL int meta_stack_windows_cmp (MetaStack *stack, MetaWindow *window_a, MetaWindow *window_b) { g_return_val_if_fail (window_a->screen == window_b->screen, 0); /* -1 means a below b */ stack_ensure_sorted (stack); /* update constraints, layers */ if (window_a->layer < window_b->layer) return -1; else if (window_a->layer > window_b->layer) return 1; else if (window_a->stack_position < window_b->stack_position) return -1; else if (window_a->stack_position > window_b->stack_position) return 1; else return 0; /* not reached */ } static int compare_just_window_stack_position (void *a, void *b) { MetaWindow *window_a = a; MetaWindow *window_b = b; if (window_a->stack_position < window_b->stack_position) return -1; /* move window_a earlier in list */ else if (window_a->stack_position > window_b->stack_position) return 1; else return 0; /* not reached */ } LOCAL_SYMBOL GList* meta_stack_get_positions (MetaStack *stack) { GList *tmp; /* Make sure to handle any adds or removes */ stack_ensure_sorted (stack); tmp = g_list_copy (stack->sorted); tmp = g_list_sort (tmp, (GCompareFunc) compare_just_window_stack_position); return tmp; } static gint compare_pointers (gconstpointer a, gconstpointer b) { if (a > b) return 1; else if (a < b) return -1; else return 0; } static gboolean lists_contain_same_windows (GList *a, GList *b) { GList *copy1, *copy2; GList *tmp1, *tmp2; if (g_list_length (a) != g_list_length (b)) return FALSE; tmp1 = copy1 = g_list_sort (g_list_copy (a), compare_pointers); tmp2 = copy2 = g_list_sort (g_list_copy (b), compare_pointers); while (tmp1 && tmp1->data == tmp2->data) /* tmp2 is non-NULL if tmp1 is */ { tmp1 = tmp1->next; tmp2 = tmp2->next; } g_list_free (copy1); g_list_free (copy2); return (tmp1 == NULL); /* tmp2 is non-NULL if tmp1 is */ } LOCAL_SYMBOL void meta_stack_set_positions (MetaStack *stack, GList *windows) { int i; GList *tmp; /* Make sure any adds or removes aren't in limbo -- is this needed? */ stack_ensure_sorted (stack); if (!lists_contain_same_windows (windows, stack->sorted)) { meta_warning ("This list of windows has somehow changed; not resetting " "positions of the windows.\n"); return; } g_list_free (stack->sorted); stack->sorted = g_list_copy (windows); stack->need_resort = TRUE; stack->need_constrain = TRUE; i = 0; tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; w->stack_position = i++; tmp = tmp->next; } meta_topic (META_DEBUG_STACK, "Reset the stack positions of (nearly) all windows\n"); stack_sync_to_server (stack); meta_stack_update_window_tile_matches (stack, NULL); } void meta_window_set_stack_position_no_sync (MetaWindow *window, int position) { int low, high, delta; GList *tmp; g_return_if_fail (window->screen->stack != NULL); g_return_if_fail (window->stack_position >= 0); g_return_if_fail (position >= 0); g_return_if_fail (position < window->screen->stack->n_positions); if (position == window->stack_position) { meta_topic (META_DEBUG_STACK, "Window %s already has position %d\n", window->desc, position); return; } window->screen->stack->need_resort = TRUE; window->screen->stack->need_constrain = TRUE; if (position < window->stack_position) { low = position; high = window->stack_position - 1; delta = 1; } else { low = window->stack_position + 1; high = position; delta = -1; } tmp = window->screen->stack->sorted; while (tmp != NULL) { MetaWindow *w = tmp->data; if (w->stack_position >= low && w->stack_position <= high) w->stack_position += delta; tmp = tmp->next; } window->stack_position = position; meta_topic (META_DEBUG_STACK, "Window %s had stack_position set to %d\n", window->desc, window->stack_position); } LOCAL_SYMBOL void meta_window_set_stack_position (MetaWindow *window, int position) { meta_window_set_stack_position_no_sync (window, position); stack_sync_to_server (window->screen->stack); meta_stack_update_window_tile_matches (window->screen->stack, window->screen->active_workspace); } ��������������������������������������������������������������������������muffin-5.2.1/src/libmuffin.pc.in��������������������������������������������������������������������0000664�0001750�0001750�00000001410�14211404421�016623� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ girdir=@libdir@/muffin typelibdir=@libdir@/muffin apiversion=@MUFFIN_PLUGIN_API_VERSION@ muffin_major_version=@MUFFIN_MAJOR_VERSION@ muffin_minor_version=@MUFFIN_MINOR_VERSION@ muffin_micro_version=@MUFFIN_MICRO_VERSION@ muffin_plugin_api_version=@MUFFIN_PLUGIN_API_VERSION@ Name: libmuffin Description: Muffin window manager library Requires: cinnamon-desktop gtk+-3.0 muffin-clutter-@MUFFIN_PLUGIN_API_VERSION@ x11 Version: @VERSION@ Libs: -L${libdir} -lmuffin Cflags: -I${includedir}/muffin -DMUFFIN_MAJOR_VERSION=${muffin_major_version} -DMUFFIN_MINOR_VERSION=${muffin_minor_version} -DMUFFIN_MICRO_VERSION=${muffin_micro_version} -DMUFFIN_PLUGIN_API_VERSION=${muffin_plugin_api_version} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/org.cinnamon.muffin.gschema.xml.in�������������������������������������������������0000664�0001750�0001750�00000054456�14211404421�022351� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<schemalist> <enum id="sync_method"> <value value="0" nick="none"/> <value value="1" nick="fallback"/> <value value="2" nick="swap_throttling"/> <value value="3" nick="presentation_time"/> </enum> <enum id="placement_type"> <value value="0" nick="automatic"/> <value value="1" nick="pointer"/> <value value="2" nick="manual"/> <value value="3" nick="center"/> </enum> <enum id="background_transition"> <value value="0" nick="none"/> <value value="1" nick="fade-in"/> <value value="2" nick="blend"/> </enum> <schema id="org.cinnamon.muffin" path="/org/cinnamon/muffin/" gettext-domain="@GETTEXT_DOMAIN"> <key name="attach-modal-dialogs" type="b"> <default>false</default> <_summary>Attach modal dialogs</_summary> <_description> When true, instead of having independent titlebars, modal dialogs appear attached to the titlebar of the parent window and are moved together with the parent window. </_description> </key> <key name="ignore-hide-titlebar-when-maximized" type="b"> <default>false</default> <_summary>Ignore client requests to hide the window's titlebar when maximized.</_summary> <_description> If true, causes the _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED hint to be ignored by muffin. Most apps that utilize this should (one would hope) use the hint responsibly, but this will allow it to be overridden just in case. </_description> </key> <key name="edge-tiling" type="b"> <default>true</default> <_summary>Enable edge tiling and snapping</_summary> <_description> If enabled, allows you to drag windows to the screen edges to tile or snap them in place. </_description> </key> <key name="edge-resistance-window" type="b"> <default>true</default> <summary>Enable window edge resistance</summary> <description>Determine whether there is tension along other window and screen/monitor edges when dragging a window.</description> </key> <key name="dynamic-workspaces" type="b"> <default>false</default> <_summary>Workspaces are managed dynamically</_summary> <_description> Determines whether workspaces are managed dynamically or whether there's a static number of workspaces (determined by the num-workspaces key in org.cinnamon.desktop.wm.preferences). </_description> </key> <key name="unredirect-fullscreen-windows" type="b"> <default>false</default> <_summary>Fullscreen windows are unredirected (i.e. they bypass compositing)</_summary> <_description> Determines whether fullscreen windows bypass compositing. False is better for vsync/screen-tearing, True gives games and apps i </_description> </key> <key name="sync-to-vblank" type="b"> <default>true</default> <_summary>Enable vertical blanking interval</_summary> <_description> Determines whether or not VBLANK is enabled. </_description> </key> <key name="sync-method" enum="sync_method"> <default>'presentation_time'</default> <_summary>Sync method</_summary> <_description>The method used by Muffin to provide VSync.</_description> </key> <key name="threaded-swap" type="b"> <default>true</default> <_summary>Enable threaded swap waiting</_summary> <_description> Determines whether or not Cogl uses a threaded implementation for waiting for swap events. </_description> </key> <key name="send-frame-timings" type="b"> <default>true</default> <_summary>Enable high-precision frame synchronization</_summary> <_description> Sends a _NET_WM_FRAME_TIMINGS message to the X server after each frame rendered to help keep frames synchronized. </_description> </key> <key name="workspace-cycle" type="b"> <default>false</default> <_summary>Allow cycling through workspaces</_summary> <_description> Allows cycling through workspaces, going to the workspace at the other end if you are at the left-most or right-most one. </_description> </key> <key name="workspaces-only-on-primary" type="b"> <default>false</default> <_summary>Workspaces only on primary</_summary> <_description> Determines whether workspace switching should happen for windows on all monitors or only for windows on the primary monitor. </_description> </key> <key name="draggable-border-width" type="i"> <default>10</default> <range min="0" max="64"/> <_summary>Draggable border width</_summary> <_description> The amount of total draggable borders. If the theme's visible borders are not enough, invisible borders will be added to meet this value. </_description> </key> <key name="tile-hud-threshold" type="i"> <default>25</default> <range min="1" max="400"/> <_summary>Window tile HUD threshold</_summary> <_description> The distance from the edge of the screen you must be within before the tile/snap HUD appears </_description> </key> <key name="resize-threshold" type="i"> <default>24</default> <range min="1" max="400"/> <_summary>Window resize tension threshold</_summary> <_description> The distance you have to move a resize grip before it's actually registered as a resize </_description> </key> <key name="snap-modifier" type="s"> <default>'Control'</default> <_summary>Modifier for toggling between tile and snap mode</_summary> <_description> When dragging a window, holding this key will engage snap mode. </_description> </key> <key name="legacy-snap" type="b"> <default>false</default> <_summary>Enable legacy drag snapping</_summary> <_description> Enables old-style snapping by holding the shift key while dragging a window </_description> </key> <key name="button-layout" type="s"> <default>":minimize,maximize,close"</default> <summary>Arrangement of buttons on the titlebar</summary> <description> Since Cinnamon 3.8, this key is obsolete and doesn't do anything anymore. The only reason it's still here is because its absence makes Chromium crash at launch in Debian Stretch. </description> </key> <key name="invert-workspace-flip-direction" type="b"> <default>false</default> <_summary>Inverts the direction the left and right arrows take you when you switch workspaces during a window drag</_summary> <_description> Changes left-right arrow keys to window-centric directions rather than workspace-centric </_description> </key> <key name="tile-maximize" type="b"> <default>false</default> <_summary>Sets maximize as the tile action for the top edge of the screen</_summary> <_description> Makes tiling to the top maximize the window </_description> </key> <key name="placement-mode" enum="placement_type"> <default>'center'</default> <_summary>Window placement mode</_summary> <_description>The window placement mode indicates how new windows are positioned. "automatic" means the system chooses a location automatically based on the space available on the desktop, or by a simple cascade if there is no space; "pointer" means that new windows are placed according to the mouse pointer position; "manual" means that the user must manually place the new window with the mouse or keyboard; "center" means that the system places new windows in the center of the desktop.</_description> </key> <key name="background-transition" enum="background_transition"> <default>'blend'</default> <_summary>Background transition</_summary> <_description>The type of animation performed when changing background. "none" means no animation at all. "fade-in" means the old background switches to black and the new background appears with a fade-in effect. "blend" means the old background disappears as the new background appears with a fade-in effect. </_description> </key> <key name="desktop-effects" type="b"> <default>true</default> <_summary>Enable desktop effects</_summary> <_description> Whether to enable desktop effects and window animations. </_description> </key> <child name="keybindings" schema="org.cinnamon.muffin.keybindings"/> </schema> <schema id="org.cinnamon.muffin.keybindings" path="/org/cinnamon/muffin/keybindings/"> <key name="toggle-recording" type="as"> <default>[]</default> </key> <key name="push-tile-left" type="as"> <default>[]</default> </key> <key name="push-tile-right" type="as"> <default>[]</default> </key> <key name="push-tile-up" type="as"> <default>[]</default> </key> <key name="push-tile-down" type="as"> <default>[]</default> </key> <key name="push-snap-left" type="as"> <default>[]</default> </key> <key name="push-snap-right" type="as"> <default>[]</default> </key> <key name="push-snap-up" type="as"> <default>[]</default> </key> <key name="push-snap-down" type="as"> <default>[]</default> </key> <key name="tab-popup-select" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="tab-popup-cancel" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-1" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-2" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-3" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-4" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-5" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-6" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-7" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-8" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-9" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-10" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-11" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-12" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-left" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-right" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-up" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-to-workspace-down" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-group" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-group-backward" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-windows" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-windows-backward" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-panels" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="switch-panels-backward" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="cycle-group" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="cycle-group-backward" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="cycle-windows" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="cycle-windows-backward" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="cycle-panels" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="cycle-panels-backward" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="show-desktop" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="panel-main-menu" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="panel-run-dialog" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="set-spew-mark" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="activate-window-menu" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="toggle-fullscreen" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="toggle-maximized" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="toggle-above" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="maximize" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="unmaximize" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="toggle-shaded" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="minimize" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="close" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="begin-move" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="begin-resize" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="toggle-on-all-workspaces" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-1" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-2" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-3" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-4" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-5" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-6" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-7" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-8" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-9" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-10" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-11" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-12" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-left" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-right" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-up" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-workspace-down" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="raise-or-lower" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="raise" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="lower" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="maximize-vertically" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="maximize-horizontally" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-corner-nw" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-corner-ne" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-corner-sw" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-corner-se" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-side-n" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-side-s" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-side-e" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-side-w" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="move-to-center" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="increase-opacity" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> <key name="decrease-opacity" type="as"> <default>[]</default> <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.wm</_summary> </key> </schema> </schemalist> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/stock_maximize.png�����������������������������������������������������������������0000664�0001750�0001750�00000000246�14211404421�017461� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������a���bKGD������ pHYs�� �� ~���tIMElz9h���3IDATxc`T}LbX=- '́004 ��b-����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/muffin-enum-types.h.in�������������������������������������������������������������0000664�0001750�0001750�00000001014�14211404421�020065� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** BEGIN file-header ***/ #ifndef __MUFFIN_ENUM_TYPES_H__ #define __MUFFIN_ENUM_TYPES_H__ #include <glib-object.h> G_BEGIN_DECLS /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ /*** END file-production ***/ /*** BEGIN file-tail ***/ G_END_DECLS #endif /* !__MUFFIN_ENUM_TYPES_H__ */ /*** END file-tail ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) G_GNUC_CONST; #define META_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) /*** END value-header ***/ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�014651� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/atomnames.h�������������������������������������������������������������������0000664�0001750�0001750�00000012666�14211404421�017021� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. * Copyright (C) 2003, 2004 Rob Adams * Copyright (C) 2004-2006 Elijah Newren * Copyright (C) 2008 Thomas Thurman * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * \file atomnames.h A list of atom names. * * This is a list of the names of all the X atoms that Muffin uses. * Each is wrapped in a macro "item()" which is undefined here; the * idea is that when you need to make a big list of all the X atoms, * you can define item(), include this file, and then undefine it * again. * * If you also define EWMH_ATOMS_ONLY then you will only get _NET_WM_* * atoms rather than all of them. */ #ifndef item #error "item(x) must be defined when you include atomnames.h" #endif #ifndef EWMH_ATOMS_ONLY item(WM_PROTOCOLS) /* MUST BE FIRST */ item(WM_TAKE_FOCUS) item(WM_DELETE_WINDOW) item(WM_STATE) item(_MOTIF_WM_HINTS) item(WM_CHANGE_STATE) item(SM_CLIENT_ID) item(WM_CLIENT_LEADER) item(WM_WINDOW_ROLE) item(UTF8_STRING) item(WM_ICON_SIZE) item(_KWM_WIN_ICON) item(_MUFFIN_RELOAD_THEME_MESSAGE) item(_MUFFIN_SET_KEYBINDINGS_MESSAGE) item(_MUFFIN_TOGGLE_VERBOSE) item(_MUFFIN_HINTS) item(_GTK_THEME_VARIANT) item(_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED) item(_GTK_APPLICATION_ID) item(_GTK_UNIQUE_BUS_NAME) item(_GTK_APPLICATION_OBJECT_PATH) item(_GTK_WINDOW_OBJECT_PATH) item(_GTK_APP_MENU_OBJECT_PATH) item(_GTK_MENUBAR_OBJECT_PATH) item(_GTK_FRAME_EXTENTS) item(_GTK_SHOW_WINDOW_MENU) item(_GTK_EDGE_CONSTRAINTS) item(_GNOME_WM_KEYBINDINGS) item(_GNOME_PANEL_ACTION) item(_GNOME_PANEL_ACTION_RUN_DIALOG) item(_MUFFIN_SENTINEL) item(_MUFFIN_VERSION) item(WM_CLIENT_MACHINE) item(_NET_WM_XAPP_ICON_NAME) item(_NET_WM_XAPP_PROGRESS) item(_NET_WM_XAPP_PROGRESS_PULSE) item(MANAGER) item(TARGETS) item(MULTIPLE) item(TIMESTAMP) item(VERSION) item(ATOM_PAIR) /* Oddities: These are used, and we need atoms for them, * but when we need all _NET_WM hints (i.e. when we're making * lists of which _NET_WM hints we support in order to advertise * it) we haven't historically listed them. I don't know what * the reason for this is. It may be a bug. */ item(_NET_WM_SYNC_REQUEST) item(_NET_WM_SYNC_REQUEST_COUNTER) item(_NET_WM_VISIBLE_NAME) item(_NET_WM_VISIBLE_ICON_NAME) item(_NET_SUPPORTING_WM_CHECK) /* But I suppose it's quite reasonable not to advertise using * _NET_SUPPORTED that we support _NET_SUPPORTED :) */ item(_NET_SUPPORTED) #endif /* !EWMH_ATOMS_ONLY */ /**************************************************************************/ item(_NET_WM_NAME) item(_NET_CLOSE_WINDOW) item(_NET_WM_STATE) item(_NET_WM_STATE_SHADED) item(_NET_WM_STATE_MAXIMIZED_HORZ) item(_NET_WM_STATE_MAXIMIZED_VERT) item(_NET_WM_STATE_TILED) item(_NET_WM_DESKTOP) item(_NET_NUMBER_OF_DESKTOPS) item(_NET_CURRENT_DESKTOP) item(_NET_WM_WINDOW_TYPE) item(_NET_WM_WINDOW_TYPE_DESKTOP) item(_NET_WM_WINDOW_TYPE_DOCK) item(_NET_WM_WINDOW_TYPE_TOOLBAR) item(_NET_WM_WINDOW_TYPE_MENU) item(_NET_WM_WINDOW_TYPE_UTILITY) item(_NET_WM_WINDOW_TYPE_SPLASH) item(_NET_WM_WINDOW_TYPE_DIALOG) item(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU) item(_NET_WM_WINDOW_TYPE_POPUP_MENU) item(_NET_WM_WINDOW_TYPE_TOOLTIP) item(_NET_WM_WINDOW_TYPE_NOTIFICATION) item(_NET_WM_WINDOW_TYPE_COMBO) item(_NET_WM_WINDOW_TYPE_DND) item(_NET_WM_WINDOW_TYPE_NORMAL) item(_NET_WM_STATE_MODAL) item(_NET_CLIENT_LIST) item(_NET_CLIENT_LIST_STACKING) item(_NET_WM_STATE_SKIP_TASKBAR) item(_NET_WM_STATE_SKIP_PAGER) item(_NET_WM_WINDOW_TILE_INFO) item(_NET_WM_ICON_NAME) item(_NET_WM_ICON) item(_NET_WM_ICON_GEOMETRY) item(_NET_WM_MOVERESIZE) item(_NET_ACTIVE_WINDOW) item(_NET_WM_STRUT) item(_NET_WM_STATE_HIDDEN) item(_NET_WM_STATE_FULLSCREEN) item(_NET_WM_PING) item(_NET_WM_PID) item(_NET_WORKAREA) item(_NET_SHOWING_DESKTOP) item(_NET_DESKTOP_LAYOUT) item(_NET_DESKTOP_NAMES) item(_NET_WM_ALLOWED_ACTIONS) item(_NET_WM_ACTION_MOVE) item(_NET_WM_ACTION_RESIZE) item(_NET_WM_ACTION_SHADE) item(_NET_WM_ACTION_STICK) item(_NET_WM_ACTION_MAXIMIZE_HORZ) item(_NET_WM_ACTION_MAXIMIZE_VERT) item(_NET_WM_ACTION_CHANGE_DESKTOP) item(_NET_WM_ACTION_CLOSE) item(_NET_WM_STATE_ABOVE) item(_NET_WM_STATE_BELOW) item(_NET_STARTUP_ID) item(_NET_WM_STRUT_PARTIAL) item(_NET_WM_ACTION_FULLSCREEN) item(_NET_WM_ACTION_MINIMIZE) item(_NET_FRAME_EXTENTS) item(_NET_REQUEST_FRAME_EXTENTS) item(_NET_WM_USER_TIME) item(_NET_WM_STATE_DEMANDS_ATTENTION) item(_NET_MOVERESIZE_WINDOW) item(_NET_DESKTOP_GEOMETRY) item(_NET_DESKTOP_VIEWPORT) item(_NET_WM_USER_TIME_WINDOW) item(_NET_WM_ACTION_ABOVE) item(_NET_WM_ACTION_BELOW) item(_NET_WM_STATE_STICKY) item(_NET_WM_FULLSCREEN_MONITORS) item(_NET_WM_STATE_FOCUSED) item(_NET_WM_BYPASS_COMPOSITOR) item(_NET_WM_OPAQUE_REGION) item(_NET_WM_FRAME_DRAWN) item(_NET_WM_FRAME_TIMINGS) item(_NET_RESTACK_WINDOW) /* eof atomnames.h */ ��������������������������������������������������������������������������muffin-5.2.1/src/meta/screen.h����������������������������������������������������������������������0000664�0001750�0001750�00000010717�14211404421�016307� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_SCREEN_H #define META_SCREEN_H #include <X11/Xlib.h> #include <glib-object.h> #include <meta/types.h> #include <meta/workspace.h> #define META_TYPE_SCREEN (meta_screen_get_type ()) #define META_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SCREEN, MetaScreen)) #define META_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SCREEN, MetaScreenClass)) #define META_IS_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SCREEN)) #define META_IS_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SCREEN)) #define META_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SCREEN, MetaScreenClass)) typedef struct _MetaScreenClass MetaScreenClass; GType meta_screen_get_type (void); int meta_screen_get_screen_number (MetaScreen *screen); MetaDisplay *meta_screen_get_display (MetaScreen *screen); Window meta_screen_get_xroot (MetaScreen *screen); void meta_screen_get_size (MetaScreen *screen, int *width, int *height); MetaScreen *meta_screen_for_x_screen (Screen *xscreen); void meta_screen_set_cm_selection (MetaScreen *screen); void meta_screen_unset_cm_selection (MetaScreen *screen); GSList *meta_screen_get_startup_sequences (MetaScreen *screen); GList *meta_screen_get_workspaces (MetaScreen *screen); int meta_screen_get_n_workspaces (MetaScreen *screen); MetaWorkspace* meta_screen_get_workspace_by_index (MetaScreen *screen, int index); void meta_screen_remove_workspace (MetaScreen *screen, MetaWorkspace *workspace, guint32 timestamp); MetaWorkspace *meta_screen_append_new_workspace (MetaScreen *screen, gboolean activate, guint32 timestamp); int meta_screen_get_active_workspace_index (MetaScreen *screen); MetaWorkspace * meta_screen_get_active_workspace (MetaScreen *screen); void meta_screen_show_desktop (MetaScreen *screen, guint32 timestamp); void meta_screen_toggle_desktop (MetaScreen *screen, guint32 timestamp); void meta_screen_unshow_desktop (MetaScreen *screen); int meta_screen_get_n_monitors (MetaScreen *screen); int meta_screen_get_primary_monitor (MetaScreen *screen); int meta_screen_get_current_monitor (MetaScreen *screen); void meta_screen_get_monitor_geometry (MetaScreen *screen, int monitor, MetaRectangle *geometry); gboolean meta_screen_get_monitor_in_fullscreen (MetaScreen *screen, int monitor); int meta_screen_get_monitor_index_for_rect (MetaScreen *screen, MetaRectangle *rect); MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen, MetaWindow *not_this_one); typedef enum { META_SCREEN_TOPLEFT, META_SCREEN_TOPRIGHT, META_SCREEN_BOTTOMLEFT, META_SCREEN_BOTTOMRIGHT } MetaScreenCorner; void meta_screen_override_workspace_layout (MetaScreen *screen, MetaScreenCorner starting_corner, gboolean vertical_layout, int n_rows, int n_columns); #endif �������������������������������������������������muffin-5.2.1/src/meta/meta-background-actor.h�������������������������������������������������������0000664�0001750�0001750�00000004702�14211404421�021176� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, 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; struct _MetaBackgroundActorClass { ClutterActorClass parent_class; }; struct _MetaBackgroundActor { ClutterActor parent; MetaBackgroundActorPrivate *priv; }; GType meta_background_actor_get_type (void); ClutterActor *meta_background_actor_new_for_screen (MetaScreen *screen); #endif /* META_BACKGROUND_ACTOR_H */ ��������������������������������������������������������������muffin-5.2.1/src/meta/prefs.h�����������������������������������������������������������������������0000664�0001750�0001750�00000033020�14211404421�016137� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin preferences */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_PREFS_H #define META_PREFS_H /* This header is a "common" one between the UI and core side */ #include <meta/common.h> #include <meta/types.h> #include <pango/pango-font.h> #include <libcinnamon-desktop/cdesktop-enums.h> #include <X11/XKBlib.h> /* Keep in sync with GSettings schemas! */ typedef enum { META_PREF_MOUSE_BUTTON_MODS, META_PREF_FOCUS_MODE, META_PREF_FOCUS_NEW_WINDOWS, META_PREF_ATTACH_MODAL_DIALOGS, META_PREF_IGNORE_HIDE_TITLEBAR_WHEN_MAXIMIZED, META_PREF_RAISE_ON_CLICK, META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR, META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR, META_PREF_ACTION_RIGHT_CLICK_TITLEBAR, META_PREF_ACTION_SCROLL_WHEEL_TITLEBAR, META_PREF_AUTO_RAISE, META_PREF_AUTO_RAISE_DELAY, META_PREF_THEME, META_PREF_TITLEBAR_FONT, META_PREF_NUM_WORKSPACES, META_PREF_DYNAMIC_WORKSPACES, META_PREF_UNREDIRECT_FULLSCREEN_WINDOWS, META_PREF_DESKTOP_EFFECTS, META_PREF_SYNC_METHOD, META_PREF_THREADED_SWAP, META_PREF_SEND_FRAME_TIMINGS, META_PREF_APPLICATION_BASED, META_PREF_KEYBINDINGS, META_PREF_DISABLE_WORKAROUNDS, META_PREF_BUTTON_LAYOUT, META_PREF_WORKSPACE_NAMES, META_PREF_WORKSPACE_CYCLE, META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, META_PREF_VISUAL_BELL_TYPE, META_PREF_GNOME_ANIMATIONS, META_PREF_CURSOR_THEME, META_PREF_CURSOR_SIZE, META_PREF_RESIZE_WITH_RIGHT_BUTTON, META_PREF_EDGE_TILING, META_PREF_FORCE_FULLSCREEN, META_PREF_EDGE_RESISTANCE_WINDOW, META_PREF_WORKSPACES_ONLY_ON_PRIMARY, META_PREF_DRAGGABLE_BORDER_WIDTH, META_PREF_TILE_HUD_THRESHOLD, META_PREF_RESIZE_THRESHOLD, META_PREF_SNAP_MODIFIER, META_PREF_LEGACY_SNAP, META_PREF_INVERT_WORKSPACE_FLIP_DIRECTION, META_PREF_TILE_MAXIMIZE, META_PREF_PLACEMENT_MODE, META_PREF_BACKGROUND_TRANSITION, META_PREF_MIN_WIN_OPACITY, META_PREF_MOUSE_ZOOM_ENABLED, META_PREF_MOUSE_BUTTON_ZOOM_MODS, META_PREF_UI_SCALE, META_PREF_BRING_WINDOWS_TO_CURRENT_WORKSPACE, } MetaPreference; typedef void (* MetaPrefsChangedFunc) (MetaPreference pref, gpointer data); void meta_prefs_add_listener (MetaPrefsChangedFunc func, gpointer data); void meta_prefs_remove_listener (MetaPrefsChangedFunc func, gpointer data); void meta_prefs_init (void); void meta_prefs_override_preference_schema (const char *key, const char *schema); const char* meta_preference_to_string (MetaPreference pref); MetaVirtualModifier meta_prefs_get_mouse_button_mods (void); MetaVirtualModifier meta_prefs_get_mouse_button_zoom_mods (void); gboolean meta_prefs_get_mouse_zoom_enabled (void); guint meta_prefs_get_mouse_button_resize (void); guint meta_prefs_get_mouse_button_menu (void); CDesktopFocusMode meta_prefs_get_focus_mode (void); CDesktopFocusNewWindows meta_prefs_get_focus_new_windows (void); gboolean meta_prefs_get_attach_modal_dialogs (void); gboolean meta_prefs_get_ignore_hide_titlebar_when_maximized (void); gboolean meta_prefs_get_raise_on_click (void); gboolean meta_prefs_get_bring_windows_to_current_workspace (void); const char* meta_prefs_get_theme (void); /* returns NULL if GTK default should be used */ const PangoFontDescription* meta_prefs_get_titlebar_font (void); int meta_prefs_get_num_workspaces (void); gboolean meta_prefs_get_workspace_cycle (void); gboolean meta_prefs_get_dynamic_workspaces (void); gboolean meta_prefs_get_unredirect_fullscreen_windows (void); MetaSyncMethod meta_prefs_get_sync_method (void); gboolean meta_prefs_get_threaded_swap (void); gboolean meta_prefs_get_send_frame_timings (void); gboolean meta_prefs_get_application_based (void); gboolean meta_prefs_get_disable_workarounds (void); gboolean meta_prefs_get_auto_raise (void); int meta_prefs_get_auto_raise_delay (void); gboolean meta_prefs_get_gnome_accessibility (void); gboolean meta_prefs_get_gnome_animations (void); gboolean meta_prefs_get_edge_tiling (void); gboolean meta_prefs_get_edge_resistance_window (void); const char* meta_prefs_get_screenshot_command (void); const char* meta_prefs_get_window_screenshot_command (void); const char* meta_prefs_get_terminal_command (void); void meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p); /* Double, right, middle click can be configured to any titlebar meta-action */ CDesktopTitlebarAction meta_prefs_get_action_double_click_titlebar (void); CDesktopTitlebarAction meta_prefs_get_action_middle_click_titlebar (void); CDesktopTitlebarAction meta_prefs_get_action_right_click_titlebar (void); CDesktopTitlebarScrollAction meta_prefs_get_action_scroll_wheel_titlebar (void); void meta_prefs_set_num_workspaces (int n_workspaces); const char* meta_prefs_get_workspace_name (int i); void meta_prefs_change_workspace_name (int i, const char *name); const char* meta_prefs_get_cursor_theme (void); int meta_prefs_get_cursor_size (void); gboolean meta_prefs_get_compositing_manager (void); gboolean meta_prefs_get_force_fullscreen (void); /* * Sets whether the compositor is turned on. * * \param whether TRUE to turn on, FALSE to turn off */ void meta_prefs_set_compositing_manager (gboolean whether); void meta_prefs_set_force_fullscreen (gboolean whether); gboolean meta_prefs_get_workspaces_only_on_primary (void); int meta_prefs_get_draggable_border_width (void); int meta_prefs_get_tile_hud_threshold (void); int meta_prefs_get_resize_threshold (void); unsigned int * meta_prefs_get_snap_modifier (void); gboolean meta_prefs_get_legacy_snap (void); gboolean meta_prefs_get_invert_flip_direction (void); gboolean meta_prefs_get_tile_maximize (void); gint meta_prefs_get_min_win_opacity (void); gint meta_prefs_get_ui_scale (void); void meta_prefs_set_ui_scale (int ui_scale); /* XXX FIXME This should be x-macroed, but isn't yet because it would be * difficult (or perhaps impossible) to add the suffixes using the current * system. It needs some more thought, perhaps after the current system * evolves a little. */ typedef enum _MetaKeyBindingAction { META_KEYBINDING_ACTION_NONE = -1, /* WARNING: Watch keybindings.c 'process_event' if you change these enums */ META_KEYBINDING_ACTION_WORKSPACE_1, META_KEYBINDING_ACTION_WORKSPACE_2, META_KEYBINDING_ACTION_WORKSPACE_3, META_KEYBINDING_ACTION_WORKSPACE_4, META_KEYBINDING_ACTION_WORKSPACE_5, META_KEYBINDING_ACTION_WORKSPACE_6, META_KEYBINDING_ACTION_WORKSPACE_7, META_KEYBINDING_ACTION_WORKSPACE_8, META_KEYBINDING_ACTION_WORKSPACE_9, META_KEYBINDING_ACTION_WORKSPACE_10, META_KEYBINDING_ACTION_WORKSPACE_11, META_KEYBINDING_ACTION_WORKSPACE_12, META_KEYBINDING_ACTION_WORKSPACE_LEFT, META_KEYBINDING_ACTION_WORKSPACE_RIGHT, META_KEYBINDING_ACTION_WORKSPACE_UP, META_KEYBINDING_ACTION_WORKSPACE_DOWN, META_KEYBINDING_ACTION_SWITCH_GROUP, META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD, META_KEYBINDING_ACTION_SWITCH_WINDOWS, META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD, META_KEYBINDING_ACTION_SWITCH_PANELS, META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD, META_KEYBINDING_ACTION_CYCLE_GROUP, META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD, META_KEYBINDING_ACTION_CYCLE_WINDOWS, META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD, META_KEYBINDING_ACTION_CYCLE_PANELS, META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD, META_KEYBINDING_ACTION_TAB_POPUP_SELECT, META_KEYBINDING_ACTION_TAB_POPUP_CANCEL, META_KEYBINDING_ACTION_SHOW_DESKTOP, META_KEYBINDING_ACTION_PANEL_RUN_DIALOG, META_KEYBINDING_ACTION_TOGGLE_RECORDING, META_KEYBINDING_ACTION_SET_SPEW_MARK, META_KEYBINDING_ACTION_ACTIVATE_WINDOW_MENU, META_KEYBINDING_ACTION_TOGGLE_FULLSCREEN, META_KEYBINDING_ACTION_TOGGLE_MAXIMIZED, META_KEYBINDING_ACTION_PUSH_TILE_LEFT, META_KEYBINDING_ACTION_PUSH_TILE_RIGHT, META_KEYBINDING_ACTION_PUSH_TILE_UP, META_KEYBINDING_ACTION_PUSH_TILE_DOWN, META_KEYBINDING_ACTION_PUSH_SNAP_LEFT, META_KEYBINDING_ACTION_PUSH_SNAP_RIGHT, META_KEYBINDING_ACTION_PUSH_SNAP_UP, META_KEYBINDING_ACTION_PUSH_SNAP_DOWN, META_KEYBINDING_ACTION_TOGGLE_ABOVE, META_KEYBINDING_ACTION_MAXIMIZE, META_KEYBINDING_ACTION_UNMAXIMIZE, META_KEYBINDING_ACTION_TOGGLE_SHADED, META_KEYBINDING_ACTION_MINIMIZE, META_KEYBINDING_ACTION_CLOSE, META_KEYBINDING_ACTION_BEGIN_MOVE, META_KEYBINDING_ACTION_BEGIN_RESIZE, META_KEYBINDING_ACTION_TOGGLE_ON_ALL_WORKSPACES, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_1, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_2, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_3, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_4, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_5, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_6, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_7, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_8, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_9, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_10, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_11, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_12, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_LEFT, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_RIGHT, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_UP, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_DOWN, META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_NEW, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_LEFT, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_RIGHT, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_DOWN, META_KEYBINDING_ACTION_MOVE_TO_MONITOR_UP, META_KEYBINDING_ACTION_RAISE_OR_LOWER, META_KEYBINDING_ACTION_RAISE, META_KEYBINDING_ACTION_LOWER, META_KEYBINDING_ACTION_MAXIMIZE_VERTICALLY, META_KEYBINDING_ACTION_MAXIMIZE_HORIZONTALLY, META_KEYBINDING_ACTION_MOVE_TO_CORNER_NW, META_KEYBINDING_ACTION_MOVE_TO_CORNER_NE, META_KEYBINDING_ACTION_MOVE_TO_CORNER_SW, META_KEYBINDING_ACTION_MOVE_TO_CORNER_SE, META_KEYBINDING_ACTION_MOVE_TO_SIDE_N, META_KEYBINDING_ACTION_MOVE_TO_SIDE_S, META_KEYBINDING_ACTION_MOVE_TO_SIDE_E, META_KEYBINDING_ACTION_MOVE_TO_SIDE_W, META_KEYBINDING_ACTION_MOVE_TO_CENTER, META_KEYBINDING_ACTION_INCREASE_OPACITY, META_KEYBINDING_ACTION_DECREASE_OPACITY, META_KEYBINDING_ACTION_CUSTOM, META_KEYBINDING_ACTION_LAST } MetaKeyBindingAction; typedef enum { META_KEY_BINDING_NONE, META_KEY_BINDING_PER_WINDOW = 1 << 0, META_KEY_BINDING_BUILTIN = 1 << 1, META_KEY_BINDING_REVERSES = 1 << 2, META_KEY_BINDING_IS_REVERSED = 1 << 3 } MetaKeyBindingFlags; typedef struct { unsigned int keysym; unsigned int keycode; MetaVirtualModifier modifiers; } MetaKeyCombo; /** * MetaKeyHandlerFunc: * @event: (type gpointer): * */ typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, XEvent *event, MetaKeyBinding *binding, gpointer user_data); typedef struct _MetaKeyHandler MetaKeyHandler; typedef struct { char *name; char *schema; MetaKeyBindingAction action; /* * A list of MetaKeyCombos. Each of them is bound to * this keypref. If one has keysym==modifiers==0, it is * ignored. */ GSList *bindings; /* for keybindings that can have shift or not like Alt+Tab */ gboolean add_shift:1; /* for keybindings that apply only to a window */ gboolean per_window:1; /* for keybindings not added with meta_display_add_keybinding() */ gboolean builtin:1; } MetaKeyPref; GType meta_key_binding_get_type (void); GList *meta_prefs_get_keybindings (void); MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name); void meta_prefs_get_window_binding (const char *name, unsigned int *keysym, MetaVirtualModifier *modifiers); gboolean meta_prefs_get_visual_bell (void); gboolean meta_prefs_bell_is_audible (void); CDesktopVisualBellType meta_prefs_get_visual_bell_type (void); MetaPlacementMode meta_prefs_get_placement_mode (void); MetaBackgroundTransition meta_prefs_get_background_transition (void); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/compositor.h������������������������������������������������������������������0000664�0001750�0001750�00000020500�14211404421�017215� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_COMPOSITOR_H #define META_COMPOSITOR_H #include <glib.h> #include <X11/Xlib.h> #include <meta/types.h> #include <meta/boxes.h> #include <meta/window.h> #include <meta/workspace.h> /** * MetaCompEffect: * @META_COMP_EFFECT_CREATE: The window is newly created * (also used for a window that was previously on a different * workspace and is changed to become visible on the active * workspace.) * @META_COMP_EFFECT_UNMINIMIZE: The window should be shown * as unminimizing from its icon geometry. * @META_COMP_EFFECT_DESTROY: The window is being destroyed * @META_COMP_EFFECT_MINIMIZE: The window should be shown * as minimizing to its icon geometry. * @META_COMP_EFFECT_NONE: No effect, the window should be * shown or hidden immediately. * * Indicates the appropriate effect to show the user for * meta_compositor_show_window() and meta_compositor_hide_window() */ typedef enum { META_COMP_EFFECT_CREATE, META_COMP_EFFECT_UNMINIMIZE, META_COMP_EFFECT_DESTROY, META_COMP_EFFECT_MINIMIZE, META_COMP_EFFECT_NONE } MetaCompEffect; MetaCompositor *meta_compositor_new (MetaDisplay *display); void meta_compositor_destroy (MetaCompositor *compositor); void meta_compositor_manage_screen (MetaCompositor *compositor, MetaScreen *screen); void meta_compositor_unmanage_screen (MetaCompositor *compositor, MetaScreen *screen); void meta_compositor_window_shape_changed (MetaCompositor *compositor, MetaWindow *window); gboolean meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window); /* At a high-level, a window is not-visible or visible. When a * window is added (with add_window()) it is not visible. * show_window() indicates a transition from not-visible to * visible. Some of the reasons for this: * * - Window newly created * - Window is unminimized * - Window is moved to the current desktop * - Window was made sticky * * hide_window() indicates that the window has transitioned from * visible to not-visible. Some reasons include: * * - Window was destroyed * - Window is minimized * - Window is moved to a different desktop * - Window no longer sticky. * * Note that combinations are possible - a window might have first * been minimized and then moved to a different desktop. The * 'effect' parameter to show_window() and hide_window() is a hint * as to the appropriate effect to show the user and should not * be considered to be indicative of a state change. * * When the active workspace is changed, switch_workspace() is called * first, then show_window() and hide_window() are called individually * for each window affected, with an effect of META_COMP_EFFECT_NONE. * If hiding windows will affect the switch workspace animation, the * compositor needs to delay hiding the windows until the switch * workspace animation completes. * * maximize_window() and unmaximize_window() are transitions within * the visible state. The window is resized *before* the call, so * it may be necessary to readjust the display based on the old_rect * to start the animation. */ void meta_compositor_add_window (MetaCompositor *compositor, MetaWindow *window); void meta_compositor_remove_window (MetaCompositor *compositor, MetaWindow *window); void meta_compositor_show_window (MetaCompositor *compositor, MetaWindow *window, MetaCompEffect effect); void meta_compositor_hide_window (MetaCompositor *compositor, MetaWindow *window, MetaCompEffect effect); void meta_compositor_switch_workspace (MetaCompositor *compositor, MetaScreen *screen, MetaWorkspace *from, MetaWorkspace *to, MetaMotionDirection direction); void meta_compositor_maximize_window (MetaCompositor *compositor, MetaWindow *window, MetaRectangle *old_rect, MetaRectangle *new_rect); void meta_compositor_unmaximize_window (MetaCompositor *compositor, MetaWindow *window, MetaRectangle *old_rect, MetaRectangle *new_rect); void meta_compositor_sync_window_geometry (MetaCompositor *compositor, MetaWindow *window, gboolean did_placement); void meta_compositor_set_updates_frozen (MetaCompositor *compositor, MetaWindow *window, gboolean updates_frozen); void meta_compositor_queue_frame_drawn (MetaCompositor *compositor, MetaWindow *window, gboolean no_delay_frame); void meta_compositor_sync_stack (MetaCompositor *compositor, MetaScreen *screen, GList *stack); void meta_compositor_sync_screen_size (MetaCompositor *compositor, MetaScreen *screen, guint width, guint height); void meta_compositor_flash_screen (MetaCompositor *compositor, MetaScreen *screen); void meta_compositor_tile_window (MetaCompositor *compositor, MetaWindow *window, MetaRectangle *old_rect, MetaRectangle *new_rect); void meta_compositor_show_tile_preview (MetaCompositor *compositor, MetaScreen *screen, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number, guint snap_queued); void meta_compositor_hide_tile_preview (MetaCompositor *compositor, MetaScreen *screen); void meta_compositor_show_hud_preview (MetaCompositor *compositor, MetaScreen *screen, guint current_proximity_zone, MetaRectangle *work_area, guint snap_queued); void meta_compositor_hide_hud_preview (MetaCompositor *compositor, MetaScreen *screen); void meta_compositor_toggle_send_frame_timings (MetaScreen *screen); #endif /* META_COMPOSITOR_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/meta-shadow-factory.h���������������������������������������������������������0000664�0001750�0001750�00000006677�14211404421�020720� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __META_SHADOW_FACTORY_H__ #define __META_SHADOW_FACTORY_H__ #include <glib-object.h> /** * MetaShadowParams: * The #MetaShadowParams structure holds information about how to draw * a particular style of shadow. * @radius: the radius (gaussian standard deviation) of the shadow * @top_fade: if >= 0, the shadow doesn't extend above the top * of the shape, and fades out over the given number of pixels * @x_offset: horizontal offset of the shadow with respect to the * shape being shadowed, in pixels * @y_offset: vertical offset of the shadow with respect to the * shape being shadowed, in pixels * @opacity: opacity of the shadow, from 0 to 255 */ typedef struct _MetaShadowParams MetaShadowParams; struct _MetaShadowParams { int radius; int top_fade; int x_offset; int y_offset; guint8 opacity; }; #define META_TYPE_SHADOW_FACTORY (meta_shadow_factory_get_type ()) #define META_SHADOW_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SHADOW_FACTORY, MetaShadowFactory)) #define META_SHADOW_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass)) #define META_IS_SHADOW_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SHADOW_FACTORY)) #define META_IS_SHADOW_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SHADOW_FACTORY)) #define META_SHADOW_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass)) /** * MetaShadowFactory: * #MetaShadowFactory is used to create window shadows. It caches shadows internally * so that multiple shadows created for the same shape with the same radius will * share the same MetaShadow. */ typedef struct _MetaShadowFactory MetaShadowFactory; typedef struct _MetaShadowFactoryClass MetaShadowFactoryClass; MetaShadowFactory *meta_shadow_factory_get_default (void); GType meta_shadow_factory_get_type (void); void meta_shadow_factory_set_params (MetaShadowFactory *factory, const char *class_name, gboolean focused, MetaShadowParams *params); void meta_shadow_factory_get_params (MetaShadowFactory *factory, const char *class_name, gboolean focused, MetaShadowParams *params); void meta_compositor_on_shadow_factory_changed (void); #endif /* __META_SHADOW_FACTORY_H__ */ �����������������������������������������������������������������muffin-5.2.1/src/meta/compositor-muffin.h�����������������������������������������������������������0000664�0001750�0001750�00000004107�14211404421�020504� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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 * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef MUFFIN_H_ #define MUFFIN_H_ #include <clutter/clutter.h> #include <X11/Xlib.h> #include <X11/extensions/Xfixes.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_bottom_window_group_for_screen (MetaScreen *screen); ClutterActor *meta_get_top_window_group_for_screen (MetaScreen *screen); void meta_disable_unredirect_for_screen (MetaScreen *screen); void meta_enable_unredirect_for_screen (MetaScreen *screen); ClutterActor *meta_get_background_actor_for_screen (MetaScreen *screen); void meta_set_stage_input_region (MetaScreen *screen, XserverRegion region); void meta_empty_stage_input_region (MetaScreen *screen); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/keybindings.h�����������������������������������������������������������������0000664�0001750�0001750�00000003021�14211404421�017324� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2009 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_KEYBINDINGS_H #define META_KEYBINDINGS_H #include <meta/display.h> #include <meta/common.h> #define META_TYPE_KEY_BINDING (meta_key_binding_get_type ()) const char *meta_key_binding_get_name (MetaKeyBinding *binding); MetaVirtualModifier meta_key_binding_get_modifiers (MetaKeyBinding *binding); guint meta_key_binding_get_mask (MetaKeyBinding *binding); gboolean meta_keybindings_set_custom_handler (const gchar *name, MetaKeyHandlerFunc handler, gpointer user_data, GDestroyNotify free_data); void meta_screen_ungrab_all_keys (MetaScreen *screen, guint32 timestamp); gboolean meta_screen_grab_all_keys (MetaScreen *screen, guint32 timestamp); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/meta-shaped-texture.h���������������������������������������������������������0000664�0001750�0001750�00000007162�14211404421�020716� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __META_SHAPED_TEXTURE_H__ #define __META_SHAPED_TEXTURE_H__ #include <clutter/clutter.h> #include <X11/Xlib.h> 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 { ClutterActorClass parent_class; }; struct _MetaShapedTexture { ClutterActor parent; MetaShapedTexturePrivate *priv; }; GType meta_shaped_texture_get_type (void) G_GNUC_CONST; void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, gboolean create_mipmaps); gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex, int x, int y, int width, int height, cairo_region_t *unobscured_region); CoglTexture *meta_shaped_texture_get_texture (MetaShapedTexture *stex); void meta_shaped_texture_set_overlay_path (MetaShapedTexture *stex, cairo_region_t *overlay_region, cairo_path_t *overlay_path); void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex, cairo_region_t *clip_region); void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex, cairo_region_t *opaque_region); cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_rectangle_int_t *clip); void meta_shaped_texture_ensure_mask (MetaShapedTexture *stex, cairo_region_t *shape_region, gboolean has_frame); void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex); G_END_DECLS #endif /* __META_SHAPED_TEXTURE_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/meta-plugin.h�����������������������������������������������������������������0000664�0001750�0001750�00000031056�14211404421�017251� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_PLUGIN_H_ #define META_PLUGIN_H_ #include <meta/types.h> #include <meta/compositor.h> #include <meta/compositor-muffin.h> #include <clutter/clutter.h> #include <X11/extensions/Xfixes.h> #include <gmodule.h> #define META_TYPE_PLUGIN (meta_plugin_get_type ()) #define META_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_PLUGIN, MetaPlugin)) #define META_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_PLUGIN, MetaPluginClass)) #define META_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_PLUGIN)) #define META_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_PLUGIN)) #define META_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_PLUGIN, MetaPluginClass)) /** * MetaPlugin: (skip) * */ typedef struct _MetaPlugin MetaPlugin; /** * MetaPluginClass: (skip) * */ typedef struct _MetaPluginClass MetaPluginClass; typedef struct _MetaPluginVersion MetaPluginVersion; typedef struct _MetaPluginInfo MetaPluginInfo; typedef struct _MetaPluginPrivate MetaPluginPrivate; struct _MetaPlugin { GObject parent; MetaPluginPrivate *priv; }; struct _MetaPluginClass { GObjectClass parent_class; void (*start) (MetaPlugin *plugin); void (*minimize) (MetaPlugin *plugin, MetaWindowActor *actor); void (*maximize) (MetaPlugin *plugin, MetaWindowActor *actor, gint x, gint y, gint width, gint height); void (*unmaximize) (MetaPlugin *plugin, MetaWindowActor *actor, gint x, gint y, gint width, gint height); void (*tile) (MetaPlugin *plugin, MetaWindowActor *actor, gint x, gint y, gint width, gint height); void (*map) (MetaPlugin *plugin, MetaWindowActor *actor); void (*destroy) (MetaPlugin *plugin, MetaWindowActor *actor); void (*switch_workspace) (MetaPlugin *plugin, gint from, gint to, MetaMotionDirection direction); void (*show_tile_preview) (MetaPlugin *plugin, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number, guint snap_queued); void (*hide_tile_preview) (MetaPlugin *plugin); void (*show_hud_preview) (MetaPlugin *plugin, guint current_proximity_zone, MetaRectangle *work_area, guint snap_queued); void (*hide_hud_preview) (MetaPlugin *plugin); /* * Called if an effects should be killed prematurely; the plugin must * call the completed() callback as if the effect terminated naturally. */ void (*kill_window_effects) (MetaPlugin *plugin, MetaWindowActor *actor); /* General XEvent filter. This is fired *before* meta itself handles * an event. Return TRUE to block any further processing. */ gboolean (*xevent_filter) (MetaPlugin *plugin, XEvent *event); const MetaPluginInfo * (*plugin_info) (MetaPlugin *plugin); }; struct _MetaPluginInfo { const gchar *name; const gchar *version; const gchar *author; const gchar *license; const gchar *description; }; GType meta_plugin_get_type (void); gboolean meta_plugin_running (MetaPlugin *plugin); gboolean meta_plugin_debug_mode (MetaPlugin *plugin); const MetaPluginInfo * meta_plugin_get_info (MetaPlugin *plugin); struct _MetaPluginVersion { /* * Version information; the first three numbers match the Meta version * with which the plugin was compiled (see clutter-plugins/simple.c for sample * code). */ guint version_major; guint version_minor; guint version_micro; /* * Version of the plugin API; this is unrelated to the matacity version * per se. The API version is checked by the plugin manager and must match * the one used by it (see clutter-plugins/default.c for sample code). */ guint version_api; }; /* * Convenience macro to set up the plugin type. Based on GEdit. */ #define META_PLUGIN_DECLARE(ObjectName, object_name) \ G_MODULE_EXPORT MetaPluginVersion meta_plugin_version = \ { \ MUFFIN_MAJOR_VERSION, \ MUFFIN_MINOR_VERSION, \ MUFFIN_MICRO_VERSION, \ MUFFIN_PLUGIN_API_VERSION \ }; \ \ static GType g_define_type_id = 0; \ \ /* Prototypes */ \ G_MODULE_EXPORT \ GType object_name##_get_type (void); \ \ G_MODULE_EXPORT \ GType object_name##_register_type (GTypeModule *type_module); \ \ G_MODULE_EXPORT \ GType meta_plugin_register_type (GTypeModule *type_module); \ \ GType \ object_name##_get_type () \ { \ return g_define_type_id; \ } \ \ static void object_name##_init (ObjectName *self); \ static void object_name##_class_init (ObjectName##Class *klass); \ static gpointer object_name##_parent_class = NULL; \ static void object_name##_class_intern_init (gpointer klass) \ { \ object_name##_parent_class = g_type_class_peek_parent (klass); \ object_name##_class_init ((ObjectName##Class *) klass); \ } \ \ GType \ object_name##_register_type (GTypeModule *type_module) \ { \ static const GTypeInfo our_info = \ { \ sizeof (ObjectName##Class), \ NULL, /* base_init */ \ NULL, /* base_finalize */ \ (GClassInitFunc) object_name##_class_intern_init, \ NULL, \ NULL, /* class_data */ \ sizeof (ObjectName), \ 0, /* n_preallocs */ \ (GInstanceInitFunc) object_name##_init \ }; \ \ g_define_type_id = g_type_module_register_type (type_module, \ META_TYPE_PLUGIN, \ #ObjectName, \ &our_info, \ 0); \ \ \ return g_define_type_id; \ } \ \ G_MODULE_EXPORT GType \ meta_plugin_register_type (GTypeModule *type_module) \ { \ return object_name##_register_type (type_module); \ } \ void meta_plugin_switch_workspace_completed (MetaPlugin *plugin); void meta_plugin_minimize_completed (MetaPlugin *plugin, MetaWindowActor *actor); void meta_plugin_maximize_completed (MetaPlugin *plugin, MetaWindowActor *actor); void meta_plugin_unmaximize_completed (MetaPlugin *plugin, MetaWindowActor *actor); void meta_plugin_tile_completed (MetaPlugin *plugin, MetaWindowActor *actor); void meta_plugin_map_completed (MetaPlugin *plugin, MetaWindowActor *actor); void meta_plugin_destroy_completed (MetaPlugin *plugin, MetaWindowActor *actor); /** * MetaModalOptions: * @META_MODAL_POINTER_ALREADY_GRABBED: if set the pointer is already * grabbed by the plugin and should not be grabbed again. * @META_MODAL_KEYBOARD_ALREADY_GRABBED: if set the keyboard is already * grabbed by the plugin and should not be grabbed again. * * Options that can be provided when calling meta_plugin_begin_modal(). */ typedef enum { META_MODAL_POINTER_ALREADY_GRABBED = 1 << 0, META_MODAL_KEYBOARD_ALREADY_GRABBED = 1 << 1 } MetaModalOptions; gboolean meta_plugin_begin_modal (MetaPlugin *plugin, Window grab_window, Cursor cursor, MetaModalOptions options, guint32 timestamp); void meta_plugin_end_modal (MetaPlugin *plugin, guint32 timestamp); MetaScreen *meta_plugin_get_screen (MetaPlugin *plugin); void _meta_plugin_effect_started (MetaPlugin *plugin); /* Putting this here so it's in the public header */ void meta_plugin_manager_set_plugin_type (GType gtype); #endif /* META_PLUGIN_H_ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/boxes.h�����������������������������������������������������������������������0000664�0001750�0001750�00000007330�14211404421�016145� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Simple box operations */ /* * Copyright (C) 2005, 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_BOXES_H #define META_BOXES_H #include <glib-object.h> #include <meta/common.h> #define META_TYPE_RECTANGLE (meta_rectangle_get_type ()) typedef struct _MetaRectangle MetaRectangle; struct _MetaRectangle { int x; int y; int width; int height; }; typedef struct _MetaStrut MetaStrut; struct _MetaStrut { MetaRectangle rect; MetaSide side; }; typedef enum { META_EDGE_WINDOW, META_EDGE_MONITOR, META_EDGE_SCREEN } MetaEdgeType; typedef struct _MetaEdge MetaEdge; struct _MetaEdge { MetaRectangle rect; /* width or height should be 1 */ MetaSide side_type; MetaEdgeType edge_type; }; GType meta_rectangle_get_type (void); MetaRectangle *meta_rectangle_copy (const MetaRectangle *rect); void meta_rectangle_free (MetaRectangle *rect); /* Function to make initializing a rect with a single line of code easy */ MetaRectangle meta_rect (int x, int y, int width, int height); /* Basic comparison functions */ int meta_rectangle_area (const MetaRectangle *rect); gboolean meta_rectangle_intersect (const MetaRectangle *src1, const MetaRectangle *src2, MetaRectangle *dest); gboolean meta_rectangle_equal (const MetaRectangle *src1, const MetaRectangle *src2); /* Find the bounding box of the union of two rectangles */ void meta_rectangle_union (const MetaRectangle *rect1, const MetaRectangle *rect2, MetaRectangle *dest); /* overlap is similar to intersect but doesn't provide location of * intersection information. */ gboolean meta_rectangle_overlap (const MetaRectangle *rect1, const MetaRectangle *rect2); /* vert_overlap means ignore the horizontal location and ask if the * vertical parts overlap. An alternate way to think of it is "Does there * exist a way to shift either rect horizontally so that the two rects * overlap?" horiz_overlap is similar. */ gboolean meta_rectangle_vert_overlap (const MetaRectangle *rect1, const MetaRectangle *rect2); gboolean meta_rectangle_horiz_overlap (const MetaRectangle *rect1, const MetaRectangle *rect2); /* could_fit_rect determines whether "outer_rect" is big enough to contain * inner_rect. contains_rect checks whether it actually contains it. */ gboolean meta_rectangle_could_fit_rect (const MetaRectangle *outer_rect, const MetaRectangle *inner_rect); gboolean meta_rectangle_contains_rect (const MetaRectangle *outer_rect, const MetaRectangle *inner_rect); #endif /* META_BOXES_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/display.h���������������������������������������������������������������������0000664�0001750�0001750�00000021423�14211404421�016471� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_DISPLAY_H #define META_DISPLAY_H #include <glib-object.h> #include <X11/Xlib.h> #include <meta/types.h> #include <meta/prefs.h> #include <meta/common.h> typedef enum { META_TAB_LIST_NORMAL, META_TAB_LIST_DOCKS, META_TAB_LIST_GROUP, META_TAB_LIST_NORMAL_ALL } MetaTabList; typedef enum { META_TAB_SHOW_ICON, /* Alt-Tab mode */ META_TAB_SHOW_INSTANTLY /* Alt-Esc mode */ } MetaTabShowType; typedef struct _MetaDisplayClass MetaDisplayClass; #define META_TYPE_DISPLAY (meta_display_get_type ()) #define META_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), META_TYPE_DISPLAY, MetaDisplay)) #define META_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DISPLAY, MetaDisplayClass)) #define META_IS_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), META_TYPE_DISPLAY)) #define META_IS_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DISPLAY)) #define META_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DISPLAY, MetaDisplayClass)) GType meta_display_get_type (void) G_GNUC_CONST; #define meta_XFree(p) do { if ((p)) XFree ((p)); } while (0) typedef enum { META_LIST_DEFAULT = 0, /* normal windows */ META_LIST_INCLUDE_OVERRIDE_REDIRECT = 1 << 0, /* normal and O-R */ } MetaListWindowsFlags; void meta_display_get_compositor_version (MetaDisplay *display, int *major, int *minor); Display *meta_display_get_xdisplay (MetaDisplay *display); MetaCompositor *meta_display_get_compositor (MetaDisplay *display); GSList *meta_display_get_screens (MetaDisplay *display); gboolean meta_display_has_shape (MetaDisplay *display); MetaScreen *meta_display_screen_for_root (MetaDisplay *display, Window xroot); MetaWindow *meta_display_get_focus_window (MetaDisplay *display); GSList* meta_display_list_windows (MetaDisplay *display, MetaListWindowsFlags flags); gboolean meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display, Window xwindow); int meta_display_get_damage_event_base (MetaDisplay *display); int meta_display_get_shape_event_base (MetaDisplay *display); gboolean meta_display_xserver_time_is_before (MetaDisplay *display, guint32 time1, guint32 time2); guint32 meta_display_get_last_user_time (MetaDisplay *display); guint32 meta_display_get_current_time (MetaDisplay *display); guint32 meta_display_get_current_time_roundtrip (MetaDisplay *display); unsigned int meta_display_get_ignored_modifier_mask (MetaDisplay *display); GList* meta_display_get_tab_list (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace); MetaWindow* meta_display_get_tab_next (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace, MetaWindow *window, gboolean backward); MetaWindow* meta_display_get_tab_current (MetaDisplay *display, MetaTabList type, MetaScreen *screen, MetaWorkspace *workspace); gboolean meta_display_begin_grab_op (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, MetaGrabOp op, gboolean pointer_already_grabbed, gboolean frame_action, int button, gulong modmask, guint32 timestamp, int root_x, int root_y); void meta_display_end_grab_op (MetaDisplay *display, guint32 timestamp); MetaGrabOp meta_display_get_grab_op (MetaDisplay *display); gboolean meta_display_add_keybinding (MetaDisplay *display, const char *name, const char *schema, MetaKeyBindingFlags flags, MetaKeyHandlerFunc handler, gpointer user_data, GDestroyNotify free_data); gboolean meta_display_remove_keybinding (MetaDisplay *display, const char *name); void meta_display_rebuild_keybindings (MetaDisplay *display); gboolean meta_display_add_custom_keybinding (MetaDisplay *display, const char *name, const char **bindings, MetaKeyHandlerFunc callback, gpointer user_data, GDestroyNotify free_data); gboolean meta_display_remove_custom_keybinding (MetaDisplay *display, const char *name); MetaKeyBindingAction meta_display_get_keybinding_action (MetaDisplay *display, unsigned int keycode, unsigned long mask); /* meta_display_set_input_focus_window is like XSetInputFocus, except * that (a) it can't detect timestamps later than the current time, * since Muffin isn't part of the XServer, and thus gives erroneous * behavior in this circumstance (so don't do it), (b) it uses * display->last_focus_time since we don't have access to the true * Xserver one, (c) it makes use of display->user_time since checking * whether a window should be allowed to be focused should depend * on user_time events (see bug 167358, comment 15 in particular) */ void meta_display_set_input_focus_window (MetaDisplay *display, MetaWindow *window, gboolean focus_frame, guint32 timestamp); /* meta_display_focus_the_no_focus_window is called when the * designated no_focus_window should be focused, but is otherwise the * same as meta_display_set_input_focus_window */ void meta_display_focus_the_no_focus_window (MetaDisplay *display, MetaScreen *screen, guint32 timestamp); GSList *meta_display_sort_windows_by_stacking (MetaDisplay *display, GSList *windows); Window meta_display_get_leader_window (MetaDisplay *display); void meta_display_add_ignored_crossing_serial (MetaDisplay *display, unsigned long serial); void meta_display_unmanage_screen (MetaDisplay *display, MetaScreen *screen, guint32 timestamp); void meta_display_keybinding_action_invoke_by_code (MetaDisplay *display, unsigned int keycode, unsigned long mask); void meta_display_restart (MetaDisplay *display); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/preview-widget.h��������������������������������������������������������������0000664�0001750�0001750�00000005743�14211404421�017775� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity theme preview widget */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <meta/common.h> #include <meta/theme.h> #include <gtk/gtk.h> #ifndef META_PREVIEW_WIDGET_H #define META_PREVIEW_WIDGET_H #define META_TYPE_PREVIEW (meta_preview_get_type ()) #define META_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_PREVIEW, MetaPreview)) #define META_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_PREVIEW, MetaPreviewClass)) #define META_IS_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_PREVIEW)) #define META_IS_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_PREVIEW)) #define META_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_PREVIEW, MetaPreviewClass)) typedef struct _MetaPreview MetaPreview; typedef struct _MetaPreviewClass MetaPreviewClass; struct _MetaPreview { GtkBin bin; MetaTheme *theme; char *title; MetaFrameType type; MetaFrameFlags flags; PangoLayout *layout; int text_height; MetaFrameBorders borders; guint borders_cached : 1; MetaButtonLayout button_layout; }; struct _MetaPreviewClass { GtkBinClass parent_class; }; GType meta_preview_get_type (void) G_GNUC_CONST; GtkWidget* meta_preview_new (void); void meta_preview_set_theme (MetaPreview *preview, MetaTheme *theme); void meta_preview_set_title (MetaPreview *preview, const char *title); void meta_preview_set_frame_type (MetaPreview *preview, MetaFrameType type); void meta_preview_set_frame_flags (MetaPreview *preview, MetaFrameFlags flags); void meta_preview_set_button_layout (MetaPreview *preview, const MetaButtonLayout *button_layout); cairo_region_t * meta_preview_get_clip_region (MetaPreview *preview, gint new_window_width, gint new_window_height); #endif �����������������������������muffin-5.2.1/src/meta/meta-window-actor.h�����������������������������������������������������������0000664�0001750�0001750�00000005366�14211404421�020375� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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 * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_WINDOW_ACTOR_H_ #define META_WINDOW_ACTOR_H_ #include <clutter/clutter.h> #include <X11/Xlib.h> #include <meta/compositor.h> /* * MetaWindowActor object (ClutterGroup sub-class) */ #define META_TYPE_WINDOW_ACTOR (meta_window_actor_get_type ()) #define META_WINDOW_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_ACTOR, MetaWindowActor)) #define META_WINDOW_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_ACTOR, MetaWindowActorClass)) #define META_IS_WINDOW_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_ACTOR)) #define META_IS_WINDOW_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_ACTOR)) #define META_WINDOW_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_ACTOR, MetaWindowActorClass)) typedef struct _MetaWindowActor MetaWindowActor; typedef struct _MetaWindowActorClass MetaWindowActorClass; typedef struct _MetaWindowActorPrivate MetaWindowActorPrivate; struct _MetaWindowActorClass { ClutterActorClass parent_class; }; struct _MetaWindowActor { ClutterActor parent; MetaWindowActorPrivate *priv; }; GType meta_window_actor_get_type (void); Window meta_window_actor_get_x_window (MetaWindowActor *self); gint meta_window_actor_get_workspace (MetaWindowActor *self); MetaWindow * meta_window_actor_get_meta_window (MetaWindowActor *self); ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self); gboolean meta_window_actor_is_override_redirect (MetaWindowActor *self); gboolean meta_window_actor_showing_on_its_workspace (MetaWindowActor *self); gboolean meta_window_actor_is_destroyed (MetaWindowActor *self); #endif /* META_WINDOW_ACTOR_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/util.h������������������������������������������������������������������������0000664�0001750�0001750�00000012476�14211404421�016011� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin utilities */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_UTIL_H #define META_UTIL_H #include <glib.h> #include <glib-object.h> #include <meta/common.h> gboolean meta_is_verbose (void); gboolean meta_is_debugging (void); gboolean meta_is_syncing (void); void meta_debug_spew_real (const char *format, ...) G_GNUC_PRINTF (1, 2); void meta_verbose_real (const char *format, ...) G_GNUC_PRINTF (1, 2); void meta_bug (const char *format, ...) G_GNUC_PRINTF (1, 2); void meta_warning (const char *format, ...) G_GNUC_PRINTF (1, 2); void meta_fatal (const char *format, ...) G_GNUC_PRINTF (1, 2); typedef enum { META_DEBUG_VERBOSE = -1, META_DEBUG_FOCUS = 1 << 0, META_DEBUG_WORKAREA = 1 << 1, META_DEBUG_STACK = 1 << 2, META_DEBUG_THEMES = 1 << 3, META_DEBUG_SM = 1 << 4, META_DEBUG_EVENTS = 1 << 5, META_DEBUG_WINDOW_STATE = 1 << 6, META_DEBUG_WINDOW_OPS = 1 << 7, META_DEBUG_GEOMETRY = 1 << 8, META_DEBUG_PLACEMENT = 1 << 9, META_DEBUG_PING = 1 << 10, META_DEBUG_XINERAMA = 1 << 11, META_DEBUG_KEYBINDINGS = 1 << 12, META_DEBUG_SYNC = 1 << 13, META_DEBUG_ERRORS = 1 << 14, META_DEBUG_STARTUP = 1 << 15, META_DEBUG_PREFS = 1 << 16, META_DEBUG_GROUPS = 1 << 17, META_DEBUG_RESIZING = 1 << 18, META_DEBUG_SHAPES = 1 << 19, META_DEBUG_COMPOSITOR = 1 << 20, META_DEBUG_EDGE_RESISTANCE = 1 << 21 } MetaDebugTopic; void meta_topic_real (MetaDebugTopic topic, const char *format, ...) G_GNUC_PRINTF (2, 3); void meta_add_verbose_topic (MetaDebugTopic topic); void meta_remove_verbose_topic (MetaDebugTopic topic); void meta_push_no_msg_prefix (void); void meta_pop_no_msg_prefix (void); gint meta_unsigned_long_equal (gconstpointer v1, gconstpointer v2); guint meta_unsigned_long_hash (gconstpointer v); void meta_print_backtrace (void); const char* meta_frame_type_to_string (MetaFrameType type); const char* meta_gravity_to_string (int gravity); char* meta_g_utf8_strndup (const gchar *src, gsize n); void meta_free_gslist_and_elements (GSList *list_to_deep_free); GPid meta_show_dialog (const char *type, const char *message, const char *timeout, const char *display, const char *ok_text, const char *cancel_text, const int transient_for, GSList *columns, GSList *entries); /* To disable verbose mode, we make these functions into no-ops */ #ifdef WITH_VERBOSE_MODE #define meta_debug_spew meta_debug_spew_real #define meta_verbose meta_verbose_real #define meta_topic meta_topic_real #else # ifdef G_HAVE_ISO_VARARGS # define meta_debug_spew(...) # define meta_verbose(...) # define meta_topic(...) # elif defined(G_HAVE_GNUC_VARARGS) # define meta_debug_spew(format...) # define meta_verbose(format...) # define meta_topic(format...) # else # error "This compiler does not support varargs macros and thus verbose mode can't be disabled meaningfully" # endif #endif /* !WITH_VERBOSE_MODE */ /** * MetaLaterType: * @META_LATER_RESIZE: call in a resize processing phase that is done * before GTK+ repainting (including window borders) is done. * @META_LATER_CALC_SHOWING: used by Muffin to compute which windows should be mapped * @META_LATER_CHECK_FULLSCREEN: used by Muffin to see if there's a fullscreen window * @META_LATER_SYNC_STACK: used by Muffin to send it's idea of the stacking order to the server * @META_LATER_BEFORE_REDRAW: call before the stage is redrawn * @META_LATER_IDLE: call at a very low priority (can be blocked * by running animations or redrawing applications) **/ typedef enum { META_LATER_RESIZE, META_LATER_CALC_SHOWING, META_LATER_CHECK_FULLSCREEN, META_LATER_SYNC_STACK, META_LATER_BEFORE_REDRAW, META_LATER_IDLE } MetaLaterType; guint meta_later_add (MetaLaterType when, GSourceFunc func, gpointer data, GDestroyNotify notify); void meta_later_remove (guint later_id); void meta_pre_exec_close_fds(void); #endif /* META_UTIL_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/gradient.h��������������������������������������������������������������������0000664�0001750�0001750�00000005167�14211404421�016630� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin gradient rendering */ /* * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_GRADIENT_H #define META_GRADIENT_H #include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk/gdk.h> typedef enum { META_GRADIENT_VERTICAL, META_GRADIENT_HORIZONTAL, META_GRADIENT_DIAGONAL, META_GRADIENT_LAST } MetaGradientType; GdkPixbuf* meta_gradient_create_simple (int width, int height, const GdkRGBA *from, const GdkRGBA *to, MetaGradientType style); GdkPixbuf* meta_gradient_create_multi (int width, int height, const GdkRGBA *colors, int n_colors, MetaGradientType style); GdkPixbuf* meta_gradient_create_interwoven (int width, int height, const GdkRGBA colors1[2], int thickness1, const GdkRGBA colors2[2], int thickness2); /* Generate an alpha gradient and multiply it with the existing alpha * channel of the given pixbuf */ void meta_gradient_add_alpha (GdkPixbuf *pixbuf, const guchar *alphas, int n_alphas, MetaGradientType type); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/window.h����������������������������������������������������������������������0000664�0001750�0001750�00000023340�14211404421�016333� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_WINDOW_H #define META_WINDOW_H #include <glib-object.h> #include <cairo.h> #include <X11/Xlib.h> #include <meta/boxes.h> #include <meta/types.h> typedef enum { META_WINDOW_NORMAL, META_WINDOW_DESKTOP, META_WINDOW_DOCK, META_WINDOW_DIALOG, META_WINDOW_MODAL_DIALOG, META_WINDOW_TOOLBAR, META_WINDOW_MENU, META_WINDOW_UTILITY, META_WINDOW_SPLASHSCREEN, /* override redirect window types: */ META_WINDOW_DROPDOWN_MENU, META_WINDOW_POPUP_MENU, META_WINDOW_TOOLTIP, META_WINDOW_NOTIFICATION, META_WINDOW_COMBO, META_WINDOW_DND, META_WINDOW_OVERRIDE_OTHER } MetaWindowType; typedef enum { META_MAXIMIZE_HORIZONTAL = 1 << 0, META_MAXIMIZE_VERTICAL = 1 << 1 } MetaMaximizeFlags; #define META_TYPE_WINDOW (meta_window_get_type ()) #define META_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW, MetaWindow)) #define META_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW, MetaWindowClass)) #define META_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW)) #define META_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW)) #define META_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW, MetaWindowClass)) typedef struct _MetaWindowClass MetaWindowClass; GType meta_window_get_type (void); MetaFrame *meta_window_get_frame (MetaWindow *window); gboolean meta_window_has_focus (MetaWindow *window); gboolean meta_window_appears_focused (MetaWindow *window); gboolean meta_window_is_shaded (MetaWindow *window); gboolean meta_window_is_override_redirect (MetaWindow *window); gboolean meta_window_is_skip_taskbar (MetaWindow *window); gboolean meta_window_is_interesting (MetaWindow *window); MetaRectangle *meta_window_get_rect (MetaWindow *window); void meta_window_get_input_rect (const MetaWindow *window, MetaRectangle *rect); void meta_window_get_outer_rect (const MetaWindow *window, MetaRectangle *rect); MetaScreen *meta_window_get_screen (MetaWindow *window); MetaDisplay *meta_window_get_display (MetaWindow *window); unsigned long meta_window_get_xwindow (MetaWindow *window); MetaWindowType meta_window_get_window_type (MetaWindow *window); Atom meta_window_get_window_type_atom (MetaWindow *window); MetaWorkspace *meta_window_get_workspace (MetaWindow *window); int meta_window_get_monitor (MetaWindow *window); gboolean meta_window_is_on_all_workspaces (MetaWindow *window); gboolean meta_window_is_hidden (MetaWindow *window); void meta_window_activate (MetaWindow *window,guint32 current_time); void meta_window_activate_with_workspace (MetaWindow *window, guint32 current_time, MetaWorkspace *workspace); const char * meta_window_get_description (MetaWindow *window); const char * meta_window_get_wm_class (MetaWindow *window); const char * meta_window_get_wm_class_instance (MetaWindow *window); gboolean meta_window_showing_on_its_workspace (MetaWindow *window); const char * meta_window_get_gtk_application_id (MetaWindow *window); const char * meta_window_get_gtk_unique_bus_name (MetaWindow *window); const char * meta_window_get_gtk_application_object_path (MetaWindow *window); const char * meta_window_get_gtk_window_object_path (MetaWindow *window); const char * meta_window_get_gtk_app_menu_object_path (MetaWindow *window); const char * meta_window_get_gtk_menubar_object_path (MetaWindow *window); void meta_window_move(MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw); void meta_window_move_frame(MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw); void meta_window_move_resize_frame (MetaWindow *window, gboolean user_op, int root_x_nw, int root_y_nw, int w, int h); void meta_window_move_to_monitor (MetaWindow *window, int monitor); void meta_window_resize(MetaWindow *window, gboolean user_op, int w, int h); void meta_window_set_demands_attention (MetaWindow *window); void meta_window_unset_demands_attention (MetaWindow *window); const char* meta_window_get_startup_id (MetaWindow *window); void meta_window_change_workspace_by_index (MetaWindow *window, gint space_index, gboolean append, guint32 timestamp); void meta_window_change_workspace (MetaWindow *window, MetaWorkspace *workspace); void meta_window_stick (MetaWindow *window); void meta_window_unstick (MetaWindow *window); GObject *meta_window_get_compositor_private (MetaWindow *window); void meta_window_set_compositor_private (MetaWindow *window, GObject *priv); void meta_window_configure_notify (MetaWindow *window, XConfigureEvent *event); const char *meta_window_get_role (MetaWindow *window); MetaStackLayer meta_window_get_layer (MetaWindow *window); MetaWindow* meta_window_find_root_ancestor (MetaWindow *window); gboolean meta_window_is_ancestor_of_transient (MetaWindow *window, MetaWindow *transient); typedef gboolean (*MetaWindowForeachFunc) (MetaWindow *window, void *data); void meta_window_foreach_transient (MetaWindow *window, MetaWindowForeachFunc func, void *user_data); void meta_window_foreach_ancestor (MetaWindow *window, MetaWindowForeachFunc func, void *user_data); MetaMaximizeFlags meta_window_get_maximized (MetaWindow *window); gboolean meta_window_is_fullscreen (MetaWindow *window); gboolean meta_window_is_monitor_sized (MetaWindow *window); gboolean meta_window_is_on_primary_monitor (MetaWindow *window); gint *meta_window_get_all_monitors (MetaWindow *window, gsize *length); gboolean meta_window_is_demanding_attention (MetaWindow *window); gboolean meta_window_is_urgent (MetaWindow *window); gboolean meta_window_requested_bypass_compositor (MetaWindow *window); gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window); gboolean meta_window_get_icon_geometry (MetaWindow *window, MetaRectangle *rect); void meta_window_set_icon_geometry (MetaWindow *window, MetaRectangle *rect); void meta_window_maximize (MetaWindow *window, MetaMaximizeFlags directions); void meta_window_unmaximize (MetaWindow *window, MetaMaximizeFlags directions); void meta_window_minimize (MetaWindow *window); void meta_window_unminimize (MetaWindow *window); void meta_window_raise (MetaWindow *window); void meta_window_lower (MetaWindow *window); void meta_window_reset_opacity (MetaWindow *window); const char *meta_window_get_title (MetaWindow *window); MetaWindow *meta_window_get_transient_for (MetaWindow *window); Window meta_window_get_transient_for_as_xid (MetaWindow *window); void meta_window_delete (MetaWindow *window, guint32 timestamp); guint meta_window_get_stable_sequence (MetaWindow *window); guint32 meta_window_get_user_time (MetaWindow *window); int meta_window_get_pid (MetaWindow *window); int meta_window_get_client_pid (MetaWindow *window); const char *meta_window_get_client_machine (MetaWindow *window); gboolean meta_window_is_remote (MetaWindow *window); gboolean meta_window_is_modal (MetaWindow *window); gboolean meta_window_is_attached_dialog (MetaWindow *window); const char *meta_window_get_muffin_hints (MetaWindow *window); MetaFrameType meta_window_get_frame_type (MetaWindow *window); cairo_region_t *meta_window_get_frame_bounds (MetaWindow *window); MetaWindow *meta_window_get_tile_match (MetaWindow *window); gboolean meta_window_can_maximize (MetaWindow *window); gboolean meta_window_can_minimize (MetaWindow *window); gboolean meta_window_can_shade (MetaWindow *window); gboolean meta_window_can_close (MetaWindow *window); gboolean meta_window_is_always_on_all_workspaces (MetaWindow *window); gboolean meta_window_is_always_on_top (MetaWindow *window); gboolean meta_window_can_move (MetaWindow *window); gboolean meta_window_can_resize (MetaWindow *window); gboolean meta_window_can_tile (MetaWindow *window, MetaTileMode mode); gboolean meta_window_tile (MetaWindow *window, MetaTileMode mode, gboolean snap); const char *meta_window_get_icon_name (MetaWindow *window); GdkPixbuf *meta_window_create_icon (MetaWindow *window, int size); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/errors.h����������������������������������������������������������������������0000664�0001750�0001750�00000002412�14211404421�016335� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin X error handling */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_ERRORS_H #define META_ERRORS_H #include <X11/Xlib.h> #include <meta/util.h> #include <meta/display.h> void meta_error_trap_push (MetaDisplay *display); void meta_error_trap_pop (MetaDisplay *display); void meta_error_trap_push_with_return (MetaDisplay *display); /* returns X error code, or 0 for no error */ int meta_error_trap_pop_with_return (MetaDisplay *display); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/main.h������������������������������������������������������������������������0000664�0001750�0001750�00000003166�14211404421�015754� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin main */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_MAIN_H #define META_MAIN_H #include <glib.h> GOptionContext *meta_get_option_context (void); void meta_init (void); int meta_run (void); gboolean meta_get_replace_current_wm (void); /* Actually defined in util.c */ void meta_set_wm_name (const char *wm_name); void meta_set_gnome_wm_keybindings (const char *wm_keybindings); void meta_restart (void); /** * MetaExitCode: * @META_EXIT_SUCCESS: Success * @META_EXIT_ERROR: Error */ typedef enum { META_EXIT_SUCCESS, META_EXIT_ERROR } MetaExitCode; /* exit immediately */ void meta_exit (MetaExitCode code); /* g_main_loop_quit() then fall out of main() */ void meta_quit (MetaExitCode code); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/group.h�����������������������������������������������������������������������0000664�0001750�0001750�00000003364�14211404421�016164� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window groups */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_GROUP_H #define META_GROUP_H #include <X11/Xlib.h> #include <glib.h> #include <meta/types.h> /* note, can return NULL */ MetaGroup* meta_window_get_group (MetaWindow *window); void meta_window_compute_group (MetaWindow* window); void meta_window_shutdown_group (MetaWindow *window); void meta_window_group_leader_changed (MetaWindow *window); /* note, can return NULL */ MetaGroup* meta_display_lookup_group (MetaDisplay *display, Window group_leader); GSList* meta_group_list_windows (MetaGroup *group); void meta_group_update_layers (MetaGroup *group); const char* meta_group_get_startup_id (MetaGroup *group); int meta_group_get_size (MetaGroup *group); gboolean meta_group_property_notify (MetaGroup *group, XEvent *event); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/workspace.h�������������������������������������������������������������������0000664�0001750�0001750�00000007070�14211404421�017024� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2004, 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_WORKSPACE_H #define META_WORKSPACE_H /** * SECTION:Workspaces * @short_description:Workspaces * * A workspace is a set of windows which all live on the same * screen. (You may also see the name "desktop" around the place, * which is the EWMH's name for the same thing.) Only one workspace * of a screen may be active at once; all windows on all other workspaces * are unmapped. */ #include <meta/types.h> #include <meta/boxes.h> #include <meta/screen.h> #define META_TYPE_WORKSPACE (meta_workspace_get_type ()) #define META_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WORKSPACE, MetaWorkspace)) #define META_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WORKSPACE, MetaWorkspaceClass)) #define META_IS_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WORKSPACE)) #define META_IS_WORKSPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WORKSPACE)) #define META_WORKSPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WORKSPACE, MetaWorkspaceClass)) typedef struct _MetaWorkspaceClass MetaWorkspaceClass; GType meta_workspace_get_type (void); int meta_workspace_index (MetaWorkspace *workspace); GList* meta_workspace_list_windows (MetaWorkspace *workspace); void meta_workspace_get_work_area_for_monitor (MetaWorkspace *workspace, int which_monitor, MetaRectangle *area); void meta_workspace_get_work_area_all_monitors (MetaWorkspace *workspace, MetaRectangle *area); void meta_workspace_activate (MetaWorkspace *workspace, guint32 timestamp); void meta_workspace_activate_with_focus (MetaWorkspace *workspace, MetaWindow *focus_this, guint32 timestamp); void meta_workspace_activate_with_direction_hint (MetaWorkspace *workspace, MetaMotionDirection direction, guint32 timestamp); void meta_workspace_update_window_hints (MetaWorkspace *workspace); void meta_workspace_set_builtin_struts (MetaWorkspace *workspace, GSList *struts); MetaWorkspace *meta_workspace_get_neighbor (MetaWorkspace *workspace, MetaMotionDirection direction); void meta_workspace_focus_default_window (MetaWorkspace *workspace, MetaWindow *not_this_one, guint32 timestamp); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/common.h����������������������������������������������������������������������0000664�0001750�0001750�00000032255�14211404421�016321� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin common types shared by core.h and ui.h * * PLEASE KEEP IN SYNC WITH GSETTINGS SCHEMAS! */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_COMMON_H #define META_COMMON_H /* Don't include core headers here */ #include <stdlib.h> #include <X11/Xlib.h> #include <glib.h> #include <gtk/gtk.h> /** * SECTION:common * @title: Common * @short_description: Muffin common types */ typedef struct _MetaResizePopup MetaResizePopup; typedef enum { META_FRAME_ALLOWS_DELETE = 1 << 0, META_FRAME_ALLOWS_MENU = 1 << 1, META_FRAME_ALLOWS_MINIMIZE = 1 << 2, META_FRAME_ALLOWS_MAXIMIZE = 1 << 3, META_FRAME_ALLOWS_LEFT_RESIZE = 1 << 4, META_FRAME_ALLOWS_RIGHT_RESIZE = 1 << 5, META_FRAME_ALLOWS_TOP_RESIZE = 1 << 6, META_FRAME_ALLOWS_BOTTOM_RESIZE = 1 << 7, META_FRAME_HAS_FOCUS = 1 << 8, META_FRAME_SHADED = 1 << 9, META_FRAME_STUCK = 1 << 10, META_FRAME_MAXIMIZED = 1 << 11, META_FRAME_ALLOWS_SHADE = 1 << 12, META_FRAME_ALLOWS_MOVE = 1 << 13, META_FRAME_FULLSCREEN = 1 << 14, META_FRAME_IS_FLASHING = 1 << 15, META_FRAME_ABOVE = 1 << 16, META_FRAME_TILED_LEFT = 1 << 17, META_FRAME_TILED_RIGHT = 1 << 18, META_FRAME_ALLOWS_VERTICAL_RESIZE = (META_FRAME_ALLOWS_TOP_RESIZE | META_FRAME_ALLOWS_BOTTOM_RESIZE), META_FRAME_ALLOWS_HORIZONTAL_RESIZE = (META_FRAME_ALLOWS_LEFT_RESIZE | META_FRAME_ALLOWS_RIGHT_RESIZE) } MetaFrameFlags; typedef enum { META_MENU_OP_NONE = 0, META_MENU_OP_DELETE = 1 << 0, META_MENU_OP_MINIMIZE = 1 << 1, META_MENU_OP_UNMAXIMIZE = 1 << 2, META_MENU_OP_MAXIMIZE = 1 << 3, META_MENU_OP_UNSHADE = 1 << 4, META_MENU_OP_SHADE = 1 << 5, META_MENU_OP_UNSTICK = 1 << 6, META_MENU_OP_STICK = 1 << 7, META_MENU_OP_WORKSPACES = 1 << 8, META_MENU_OP_MOVE = 1 << 9, META_MENU_OP_RESIZE = 1 << 10, META_MENU_OP_ABOVE = 1 << 11, META_MENU_OP_UNABOVE = 1 << 12, META_MENU_OP_MOVE_LEFT = 1 << 13, META_MENU_OP_MOVE_RIGHT = 1 << 14, META_MENU_OP_MOVE_UP = 1 << 15, META_MENU_OP_MOVE_DOWN = 1 << 16, META_MENU_OP_RECOVER = 1 << 17, META_MENU_OP_MOVE_NEW = 1 << 18 } MetaMenuOp; typedef struct _MetaWindowMenu MetaWindowMenu; typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu, Display *xdisplay, Window client_xwindow, guint32 timestamp, MetaMenuOp op, int workspace, gpointer data); /* when changing this enum, there are various switch statements * you have to update */ typedef enum { META_GRAB_OP_NONE, /* Mouse ops */ META_GRAB_OP_MOVING, META_GRAB_OP_RESIZING_SE, META_GRAB_OP_RESIZING_S, META_GRAB_OP_RESIZING_SW, META_GRAB_OP_RESIZING_N, META_GRAB_OP_RESIZING_NE, META_GRAB_OP_RESIZING_NW, META_GRAB_OP_RESIZING_W, META_GRAB_OP_RESIZING_E, /* Keyboard ops */ META_GRAB_OP_KEYBOARD_MOVING, META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN, META_GRAB_OP_KEYBOARD_RESIZING_S, META_GRAB_OP_KEYBOARD_RESIZING_N, META_GRAB_OP_KEYBOARD_RESIZING_W, META_GRAB_OP_KEYBOARD_RESIZING_E, META_GRAB_OP_KEYBOARD_RESIZING_SE, META_GRAB_OP_KEYBOARD_RESIZING_NE, META_GRAB_OP_KEYBOARD_RESIZING_SW, META_GRAB_OP_KEYBOARD_RESIZING_NW, /* Alt+Tab */ META_GRAB_OP_KEYBOARD_TABBING_NORMAL, META_GRAB_OP_KEYBOARD_TABBING_DOCK, /* Alt+Esc */ META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL, META_GRAB_OP_KEYBOARD_ESCAPING_DOCK, META_GRAB_OP_KEYBOARD_ESCAPING_GROUP, /* Alt+F6 */ META_GRAB_OP_KEYBOARD_TABBING_GROUP, META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING, /* Frame button ops */ META_GRAB_OP_CLICKING_MINIMIZE, META_GRAB_OP_CLICKING_MAXIMIZE, META_GRAB_OP_CLICKING_UNMAXIMIZE, META_GRAB_OP_CLICKING_DELETE, META_GRAB_OP_CLICKING_MENU, META_GRAB_OP_CLICKING_SHADE, META_GRAB_OP_CLICKING_UNSHADE, META_GRAB_OP_CLICKING_ABOVE, META_GRAB_OP_CLICKING_UNABOVE, META_GRAB_OP_CLICKING_STICK, META_GRAB_OP_CLICKING_UNSTICK, /* Special grab op when the compositor asked for a grab */ META_GRAB_OP_COMPOSITOR } MetaGrabOp; typedef enum { META_CURSOR_DEFAULT, META_CURSOR_NORTH_RESIZE, META_CURSOR_SOUTH_RESIZE, META_CURSOR_WEST_RESIZE, META_CURSOR_EAST_RESIZE, META_CURSOR_SE_RESIZE, META_CURSOR_SW_RESIZE, META_CURSOR_NE_RESIZE, META_CURSOR_NW_RESIZE, META_CURSOR_MOVE_OR_RESIZE_WINDOW, META_CURSOR_BUSY } MetaCursor; typedef enum { META_FRAME_TYPE_NORMAL, META_FRAME_TYPE_DIALOG, META_FRAME_TYPE_MODAL_DIALOG, META_FRAME_TYPE_UTILITY, META_FRAME_TYPE_MENU, META_FRAME_TYPE_BORDER, META_FRAME_TYPE_ATTACHED, META_FRAME_TYPE_LAST } MetaFrameType; typedef enum { /* Create gratuitous divergence from regular * X mod bits, to be sure we find bugs */ META_VIRTUAL_SHIFT_MASK = 1 << 5, META_VIRTUAL_CONTROL_MASK = 1 << 6, META_VIRTUAL_ALT_MASK = 1 << 7, META_VIRTUAL_META_MASK = 1 << 8, META_VIRTUAL_SUPER_MASK = 1 << 9, META_VIRTUAL_HYPER_MASK = 1 << 10, META_VIRTUAL_MOD2_MASK = 1 << 11, META_VIRTUAL_MOD3_MASK = 1 << 12, META_VIRTUAL_MOD4_MASK = 1 << 13, META_VIRTUAL_MOD5_MASK = 1 << 14 } MetaVirtualModifier; /* Relative directions or sides seem to come up all over the place... */ /* FIXME: Replace * screen.[ch]:MetaScreenDirection, * workspace.[ch]:MetaMotionDirection, * with the use of MetaDirection. */ typedef enum { META_DIRECTION_LEFT = 1 << 0, META_DIRECTION_RIGHT = 1 << 1, META_DIRECTION_TOP = 1 << 2, META_DIRECTION_BOTTOM = 1 << 3, /* Some aliases for making code more readable for various circumstances. */ META_DIRECTION_UP = META_DIRECTION_TOP, META_DIRECTION_DOWN = META_DIRECTION_BOTTOM, /* A few more definitions using aliases */ META_DIRECTION_HORIZONTAL = META_DIRECTION_LEFT | META_DIRECTION_RIGHT, META_DIRECTION_VERTICAL = META_DIRECTION_UP | META_DIRECTION_DOWN, } MetaDirection; /* Negative to avoid conflicting with real workspace * numbers */ typedef enum { META_MOTION_UP = -1, META_MOTION_DOWN = -2, META_MOTION_LEFT = -3, META_MOTION_RIGHT = -4, /* These are only used for effects */ META_MOTION_UP_LEFT = -5, META_MOTION_UP_RIGHT = -6, META_MOTION_DOWN_LEFT = -7, META_MOTION_DOWN_RIGHT = -8, META_MOTION_NOT_EXIST_YET = -30 } MetaMotionDirection; /* Sometimes we want to talk about sides instead of directions; note * that the values must be as follows or meta_window_update_struts() * won't work. Using these values also is a safety blanket since * MetaDirection used to be used as a side. */ typedef enum { META_SIDE_LEFT = META_DIRECTION_LEFT, META_SIDE_RIGHT = META_DIRECTION_RIGHT, META_SIDE_TOP = META_DIRECTION_TOP, META_SIDE_BOTTOM = META_DIRECTION_BOTTOM } MetaSide; /* Function a window button can have. Note, you can't add stuff here * without extending the theme format to draw a new function and * breaking all existing themes. */ typedef enum { META_BUTTON_FUNCTION_MENU, META_BUTTON_FUNCTION_MINIMIZE, META_BUTTON_FUNCTION_MAXIMIZE, META_BUTTON_FUNCTION_CLOSE, META_BUTTON_FUNCTION_SHADE, META_BUTTON_FUNCTION_ABOVE, META_BUTTON_FUNCTION_STICK, META_BUTTON_FUNCTION_UNSHADE, META_BUTTON_FUNCTION_UNABOVE, META_BUTTON_FUNCTION_UNSTICK, META_BUTTON_FUNCTION_LAST } MetaButtonFunction; typedef enum { META_TILE_NONE, META_TILE_LEFT, META_TILE_RIGHT, META_TILE_ULC, META_TILE_LLC, META_TILE_URC, META_TILE_LRC, META_TILE_TOP, META_TILE_BOTTOM, META_TILE_MAXIMIZE } MetaTileMode; typedef enum { META_WINDOW_TILE_TYPE_NONE, META_WINDOW_TILE_TYPE_TILED, META_WINDOW_TILE_TYPE_SNAPPED } MetaWindowTileType; typedef enum { META_BELL_TYPE_NONE, META_BELL_TYPE_STICKY_KEYS, META_BELL_TYPE_SLOW_KEYS, META_BELL_TYPE_BOUNCE_KEYS } MetaBellType; #define MAX_BUTTONS_PER_CORNER META_BUTTON_FUNCTION_LAST /* Keep array size in sync with MAX_BUTTONS_PER_CORNER */ /** * MetaButtonLayout: * @left_buttons: (array fixed-size=10): * @right_buttons: (array fixed-size=10): * @left_buttons_has_spacer: (array fixed-size=10): * @right_buttons_has_spacer: (array fixed-size=10): */ typedef struct _MetaButtonLayout MetaButtonLayout; struct _MetaButtonLayout { /* buttons in the group on the left side */ MetaButtonFunction left_buttons[MAX_BUTTONS_PER_CORNER]; gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNER]; /* buttons in the group on the right side */ MetaButtonFunction right_buttons[MAX_BUTTONS_PER_CORNER]; gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNER]; }; typedef struct _MetaFrameBorders MetaFrameBorders; struct _MetaFrameBorders { /* The frame border is made up of two pieces - an inner visible portion * and an outer portion that is invisible but responds to events. */ GtkBorder visible; GtkBorder invisible; /* For convenience, we have a "total" border which is equal to the sum * of the two borders above. */ GtkBorder total; }; /* sets all dimensions to zero */ void meta_frame_borders_clear (MetaFrameBorders *self); #define META_DEFAULT_ICON_NAME "window" /* Main loop priorities determine when activity in the GLib * will take precendence over the others. Priorities are sometimes * used to enforce ordering: give A a higher priority than B if * A must occur before B. But that poses a problem since then * if A occurs frequently enough, B will never occur. * * Anything we want to occur more or less immediately should * have a priority of G_PRIORITY_DEFAULT. When we want to * coelesce multiple things together, the appropriate place to * do it is usually META_PRIORITY_BEFORE_REDRAW. * * Note that its usually better to use meta_later_add() rather * than calling g_idle_add() directly; this will make sure things * get run when added from a clutter event handler without * waiting for another repaint cycle. * * If something has a priority lower than the redraw priority * (such as a default priority idle), then it may be arbitrarily * delayed. This happens if the screen is updating rapidly: we * are spending all our time either redrawing or waiting for a * vblank-synced buffer swap. (When X is improved to allow * clutter to do the buffer-swap asychronously, this will get * better.) */ /* G_PRIORITY_DEFAULT: * events * many timeouts */ /* GTK_PRIORITY_RESIZE: (G_PRIORITY_HIGH_IDLE + 10) */ #define META_PRIORITY_RESIZE (G_PRIORITY_HIGH_IDLE + 15) /* GTK_PRIORITY_REDRAW: (G_PRIORITY_HIGH_IDLE + 20) */ #define META_PRIORITY_BEFORE_REDRAW (G_PRIORITY_HIGH_IDLE + 40) /* calc-showing idle * update-icon idle */ /* CLUTTER_PRIORITY_REDRAW: (G_PRIORITY_HIGH_IDLE + 50) */ #define META_PRIORITY_REDRAW (G_PRIORITY_HIGH_IDLE + 50) /* ==== Anything below here can be starved arbitrarily ==== */ /* G_PRIORITY_DEFAULT_IDLE: * Muffin plugin unloading */ #define META_PRIORITY_PREFS_NOTIFY (G_PRIORITY_DEFAULT_IDLE + 10) /************************************************************/ #define META_POINT_IN_RECT(xcoord, ycoord, rect) \ ((xcoord) >= (rect).x && \ (xcoord) < ((rect).x + (rect).width) && \ (ycoord) >= (rect).y && \ (ycoord) < ((rect).y + (rect).height)) /* * Layers a window can be in. * These MUST be in the order of stacking. */ typedef enum { META_LAYER_DESKTOP = 0, META_LAYER_BOTTOM = 1, META_LAYER_NORMAL = 2, META_LAYER_TOP = 4, /* Same as DOCK; see EWMH and bug 330717 */ META_LAYER_DOCK = 4, META_LAYER_FULLSCREEN = 5, META_LAYER_FOCUSED_WINDOW = 6, META_LAYER_OVERRIDE_REDIRECT = 7, META_LAYER_LAST = 8 } MetaStackLayer; /* * Placement mode */ typedef enum { META_PLACEMENT_MODE_AUTOMATIC, META_PLACEMENT_MODE_POINTER, META_PLACEMENT_MODE_MANUAL, META_PLACEMENT_MODE_CENTER } MetaPlacementMode; /* * Background transition */ typedef enum { META_BACKGROUND_TRANSITION_NONE, META_BACKGROUND_TRANSITION_FADEIN, META_BACKGROUND_TRANSITION_BLEND } MetaBackgroundTransition; typedef enum { META_SYNC_NONE = 0, META_SYNC_FALLBACK, META_SYNC_SWAP_THROTTLING, META_SYNC_PRESENTATION_TIME } MetaSyncMethod; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/meta/theme.h�����������������������������������������������������������������������0000664�0001750�0001750�00000002656�14211404421�016135� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity Theme Rendering */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_THEME_H #define META_THEME_H #include <glib.h> /** * MetaTheme: * */ typedef struct _MetaTheme MetaTheme; MetaTheme* meta_theme_get_current (void); void meta_theme_set_current (const char *name, gboolean force_reload); MetaTheme* meta_theme_new (void); void meta_theme_free (MetaTheme *theme); gboolean meta_theme_validate (MetaTheme *theme, GError **error); MetaTheme* meta_theme_load (const char *theme_name, GError **err); #endif ����������������������������������������������������������������������������������muffin-5.2.1/src/meta/types.h�����������������������������������������������������������������������0000664�0001750�0001750�00000002443�14211404421�016171� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_TYPES_H #define META_TYPES_H /** * MetaCompositor: (skip) * */ typedef struct _MetaCompositor MetaCompositor; typedef struct _MetaDisplay MetaDisplay; typedef struct _MetaFrame MetaFrame; typedef struct _MetaScreen MetaScreen; typedef struct _MetaWindow MetaWindow; typedef struct _MetaWorkspace MetaWorkspace; /** * MetaGroup: (skip) * */ typedef struct _MetaGroup MetaGroup; typedef struct _MetaKeyBinding MetaKeyBinding; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/muffin-enum-types.c.in�������������������������������������������������������������0000664�0001750�0001750�00000001625�14211404421�020070� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** BEGIN file-header ***/ #include "muffin-enum-types.h" /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ #include "@filename@" /*** END file-production ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) { static volatile gsize g_enum_type_id__volatile = 0; if (g_once_init_enter (&g_enum_type_id__volatile)) { static const G@Type@Value values[] = { /*** END value-header ***/ /*** BEGIN value-production ***/ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, /*** END value-production ***/ /*** BEGIN value-tail ***/ { 0, NULL, NULL } }; GType g_enum_type_id; g_enum_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id); } return g_enum_type_id__volatile; } /*** END value-tail ***/ �����������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/��������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�014340� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/resizepopup.c�������������������������������������������������������������������0000664�0001750�0001750�00000012505�14211404421�017074� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity resizing-terminal-window feedback */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "resizepopup.h" #include "util-private.h" #include <gtk/gtk.h> #include <gdk/gdkx.h> struct _MetaResizePopup { GtkWidget *size_window; GtkWidget *size_label; Display *display; int screen_number; int vertical_size; int horizontal_size; gboolean showing; MetaRectangle rect; }; LOCAL_SYMBOL MetaResizePopup* meta_ui_resize_popup_new (Display *display, int screen_number) { MetaResizePopup *popup; popup = g_new0 (MetaResizePopup, 1); popup->display = display; popup->screen_number = screen_number; return popup; } LOCAL_SYMBOL void meta_ui_resize_popup_free (MetaResizePopup *popup) { g_return_if_fail (popup != NULL); if (popup->size_window) gtk_widget_destroy (popup->size_window); free (popup); } static void ensure_size_window (MetaResizePopup *popup) { GtkWidget *frame; if (popup->size_window) return; popup->size_window = gtk_window_new (GTK_WINDOW_POPUP); gtk_window_set_screen (GTK_WINDOW (popup->size_window), gdk_display_get_screen (gdk_x11_lookup_xdisplay (popup->display), popup->screen_number)); /* never shrink the size window */ gtk_window_set_resizable (GTK_WINDOW (popup->size_window), TRUE); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); gtk_container_add (GTK_CONTAINER (popup->size_window), frame); popup->size_label = gtk_label_new (""); gtk_misc_set_padding (GTK_MISC (popup->size_label), 3, 3); gtk_container_add (GTK_CONTAINER (frame), popup->size_label); gtk_widget_show_all (frame); } static void update_size_window (MetaResizePopup *popup) { char *str; int x, y; int width, height; g_return_if_fail (popup->size_window != NULL); /* Translators: This represents the size of a window. The first number is * the width of the window and the second is the height. */ str = g_strdup_printf (_("%d x %d"), popup->horizontal_size, popup->vertical_size); gtk_label_set_text (GTK_LABEL (popup->size_label), str); free (str); gtk_window_get_size (GTK_WINDOW (popup->size_window), &width, &height); x = popup->rect.x + (popup->rect.width - width) / 2; y = popup->rect.y + (popup->rect.height - height) / 2; if (gtk_widget_get_realized (popup->size_window)) { /* using move_resize to avoid jumpiness */ gdk_window_move_resize (gtk_widget_get_window (popup->size_window), x, y, width, height); } else { gtk_window_move (GTK_WINDOW (popup->size_window), x, y); } } static void sync_showing (MetaResizePopup *popup) { if (popup->showing) { if (popup->size_window) gtk_widget_show (popup->size_window); if (popup->size_window && gtk_widget_get_realized (popup->size_window)) gdk_window_raise (gtk_widget_get_window (popup->size_window)); } else { if (popup->size_window) gtk_widget_hide (popup->size_window); } } LOCAL_SYMBOL void meta_ui_resize_popup_set (MetaResizePopup *popup, MetaRectangle rect, int base_width, int base_height, int width_inc, int height_inc) { gboolean need_update_size; int display_w, display_h; g_return_if_fail (popup != NULL); need_update_size = FALSE; display_w = rect.width - base_width; if (width_inc > 0) display_w /= width_inc; display_h = rect.height - base_height; if (height_inc > 0) display_h /= height_inc; if (!meta_rectangle_equal(&popup->rect, &rect) || display_w != popup->horizontal_size || display_h != popup->vertical_size) need_update_size = TRUE; popup->rect = rect; popup->vertical_size = display_h; popup->horizontal_size = display_w; if (need_update_size) { ensure_size_window (popup); update_size_window (popup); } sync_showing (popup); } LOCAL_SYMBOL void meta_ui_resize_popup_set_showing (MetaResizePopup *popup, gboolean showing) { g_return_if_fail (popup != NULL); if (showing == popup->showing) return; popup->showing = !!showing; if (popup->showing) { ensure_size_window (popup); update_size_window (popup); } sync_showing (popup); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/metaaccellabel.c����������������������������������������������������������������0000664�0001750�0001750�00000036123�14211404421�017427� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity hacked-up GtkAccelLabel */ /* Copyright (C) 2002 Red Hat, Inc. */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * MetaAccelLabel: GtkLabel with accelerator monitoring facilities. * Copyright (C) 1998 Tim Janik * * 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., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ /* * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include <config.h> #include "metaaccellabel.h" #include <gtk/gtk.h> #include <string.h> #include "util-private.h" static void meta_accel_label_destroy (GtkWidget *object); static void meta_accel_label_finalize (GObject *object); static void meta_accel_label_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural); static void meta_accel_label_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); static gboolean meta_accel_label_draw (GtkWidget *widget, cairo_t *cr); static void meta_accel_label_update (MetaAccelLabel *accel_label); static int meta_accel_label_get_accel_width (MetaAccelLabel *accel_label); G_DEFINE_TYPE (MetaAccelLabel, meta_accel_label, GTK_TYPE_LABEL); static void meta_accel_label_class_init (MetaAccelLabelClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); gobject_class->finalize = meta_accel_label_finalize; widget_class->destroy = meta_accel_label_destroy; widget_class->get_preferred_width = meta_accel_label_get_preferred_width; widget_class->get_preferred_height = meta_accel_label_get_preferred_height; widget_class->draw = meta_accel_label_draw; class->signal_quote1 = g_strdup ("<:"); class->signal_quote2 = g_strdup (":>"); /* This is the text that should appear next to menu accelerators * that use the shift key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_shift = g_strdup (_("Shift")); /* This is the text that should appear next to menu accelerators * that use the control key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_control = g_strdup (_("Ctrl")); /* This is the text that should appear next to menu accelerators * that use the alt key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_alt = g_strdup (_("Alt")); /* This is the text that should appear next to menu accelerators * that use the meta key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_meta = g_strdup (_("Meta")); /* This is the text that should appear next to menu accelerators * that use the super key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_super = g_strdup (_("Super")); /* This is the text that should appear next to menu accelerators * that use the hyper key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_hyper = g_strdup (_("Hyper")); /* This is the text that should appear next to menu accelerators * that use the mod2 key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_mod2 = g_strdup (_("Mod2")); /* This is the text that should appear next to menu accelerators * that use the mod3 key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_mod3 = g_strdup (_("Mod3")); /* This is the text that should appear next to menu accelerators * that use the mod4 key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_mod4 = g_strdup (_("Mod4")); /* This is the text that should appear next to menu accelerators * that use the mod5 key. If the text on this key isn't typically * translated on keyboards used for your language, don't translate * this. */ class->mod_name_mod5 = g_strdup (_("Mod5")); class->mod_separator = g_strdup ("+"); class->accel_seperator = g_strdup (" / "); class->latin1_to_char = TRUE; } static void meta_accel_label_init (MetaAccelLabel *accel_label) { accel_label->accel_padding = 3; accel_label->accel_string = NULL; meta_accel_label_update (accel_label); } LOCAL_SYMBOL GtkWidget* meta_accel_label_new_with_mnemonic (const gchar *string) { MetaAccelLabel *accel_label; g_return_val_if_fail (string != NULL, NULL); accel_label = g_object_new (META_TYPE_ACCEL_LABEL, NULL); gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), string); return GTK_WIDGET (accel_label); } static void meta_accel_label_destroy (GtkWidget *object) { MetaAccelLabel *accel_label = META_ACCEL_LABEL (object); free (accel_label->accel_string); accel_label->accel_string = NULL; accel_label->accel_mods = 0; accel_label->accel_key = 0; GTK_WIDGET_CLASS (meta_accel_label_parent_class)->destroy (object); } static void meta_accel_label_finalize (GObject *object) { MetaAccelLabel *accel_label = META_ACCEL_LABEL (object); free (accel_label->accel_string); G_OBJECT_CLASS (meta_accel_label_parent_class)->finalize (object); } LOCAL_SYMBOL void meta_accel_label_set_accelerator (MetaAccelLabel *accel_label, guint accelerator_key, MetaVirtualModifier accelerator_mods) { g_return_if_fail (META_IS_ACCEL_LABEL (accel_label)); if (accelerator_key != accel_label->accel_key || accelerator_mods != accel_label->accel_mods) { accel_label->accel_mods = accelerator_mods; accel_label->accel_key = accelerator_key; meta_accel_label_update (accel_label); } } static int meta_accel_label_get_accel_width (MetaAccelLabel *accel_label) { g_return_val_if_fail (META_IS_ACCEL_LABEL (accel_label), 0); return (accel_label->accel_string_width + (accel_label->accel_string_width ? accel_label->accel_padding : 0)); } static void meta_accel_label_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget); PangoLayout *layout; gint width; GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_width (widget, minimum, natural); layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string); pango_layout_get_pixel_size (layout, &width, NULL); accel_label->accel_string_width = width; g_object_unref (G_OBJECT (layout)); } static void meta_accel_label_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_height (widget, minimum, natural); } /* Mostly taken from GTK3. */ static gboolean meta_accel_label_draw (GtkWidget *widget, cairo_t *cr) { MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget); GtkMisc *misc = GTK_MISC (accel_label); GtkTextDirection direction; int ac_width; GtkAllocation allocation; GtkRequisition requisition; direction = gtk_widget_get_direction (widget); ac_width = meta_accel_label_get_accel_width (accel_label); gtk_widget_get_allocation (widget, &allocation); gtk_widget_get_preferred_size (widget, &requisition, NULL); if (allocation.width >= requisition.width + ac_width) { GtkStyleContext *style; PangoLayout *label_layout; PangoLayout *accel_layout; GtkLabel *label = GTK_LABEL (widget); gint x, y, xpad, ypad; gfloat xalign, yalign; label_layout = gtk_label_get_layout (GTK_LABEL (accel_label)); gtk_misc_get_alignment (misc, &xalign, &yalign); cairo_save (cr); /* XXX: Mad hack: We modify the label's width so it renders * properly in its draw function that we chain to. */ if (direction == GTK_TEXT_DIR_RTL) cairo_translate (cr, ac_width, 0); if (gtk_label_get_ellipsize (label)) pango_layout_set_width (label_layout, pango_layout_get_width (label_layout) - ac_width * PANGO_SCALE); allocation.width -= ac_width; gtk_widget_set_allocation (widget, &allocation); if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw) GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget, cr); allocation.width += ac_width; gtk_widget_set_allocation (widget, &allocation); if (gtk_label_get_ellipsize (label)) pango_layout_set_width (label_layout, pango_layout_get_width (label_layout) + ac_width * PANGO_SCALE); cairo_restore (cr); gtk_misc_get_padding (misc, &xpad, &ypad); if (direction == GTK_TEXT_DIR_RTL) x = xpad; else x = gtk_widget_get_allocated_width (widget) - xpad - ac_width; gtk_label_get_layout_offsets (GTK_LABEL (accel_label), NULL, &y); accel_layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string); y = (allocation.height - (requisition.height - ypad * 2)) * yalign + 1.5; style = gtk_widget_get_style_context (widget); gtk_style_context_save (style); gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget)); gtk_render_layout (gtk_widget_get_style_context (widget), cr, x, y, accel_layout); gtk_style_context_restore (style); g_object_unref (accel_layout); } else { if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw) GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget, cr); } return FALSE; } static void meta_accel_label_update (MetaAccelLabel *accel_label) { MetaAccelLabelClass *class; GString *gstring; gboolean seen_mod = FALSE; gunichar ch; g_return_if_fail (META_IS_ACCEL_LABEL (accel_label)); class = META_ACCEL_LABEL_GET_CLASS (accel_label); free (accel_label->accel_string); accel_label->accel_string = NULL; gstring = g_string_new (accel_label->accel_string); g_string_append (gstring, gstring->len ? class->accel_seperator : " "); if (accel_label->accel_mods & META_VIRTUAL_SHIFT_MASK) { g_string_append (gstring, class->mod_name_shift); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_CONTROL_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_control); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_ALT_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_alt); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_META_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_meta); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_SUPER_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_super); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_HYPER_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_hyper); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_MOD2_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_mod2); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_MOD3_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_mod3); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_MOD4_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_mod4); seen_mod = TRUE; } if (accel_label->accel_mods & META_VIRTUAL_MOD5_MASK) { if (seen_mod) g_string_append (gstring, class->mod_separator); g_string_append (gstring, class->mod_name_mod5); seen_mod = TRUE; } if (seen_mod) g_string_append (gstring, class->mod_separator); ch = gdk_keyval_to_unicode (accel_label->accel_key); if (ch && (g_unichar_isgraph (ch) || ch == ' ') && (ch < 0x80 || class->latin1_to_char)) { switch (ch) { case ' ': g_string_append (gstring, "Space"); break; case '\\': g_string_append (gstring, "Backslash"); break; default: g_string_append_unichar (gstring, g_unichar_toupper (ch)); break; } } else { gchar *tmp; tmp = gtk_accelerator_name (accel_label->accel_key, 0); if (tmp[0] != 0 && tmp[1] == 0) tmp[0] = g_ascii_toupper (tmp[0]); g_string_append (gstring, tmp); free (tmp); } free (accel_label->accel_string); accel_label->accel_string = gstring->str; g_string_free (gstring, FALSE); g_assert (accel_label->accel_string); /* accel_label->accel_string = g_strdup ("-/-"); */ gtk_widget_queue_resize (GTK_WIDGET (accel_label)); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/ui.c����������������������������������������������������������������������������0000664�0001750�0001750�00000066042�14211404421�015131� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin interface for talking to GTK+ UI module */ /* * Copyright (C) 2002 Havoc Pennington * stock icon code Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <meta/prefs.h> #include "ui.h" #include "frames.h" #include <meta/util.h> #include "menu.h" #include "core.h" #include "theme-private.h" #include "display-private.h" #include "inlinepixbufs.h" #include <string.h> #include <stdlib.h> #include <cairo-xlib.h> static void meta_stock_icons_init (void); static void meta_ui_accelerator_parse (const char *accel, guint *keysym, guint *keycode, GdkModifierType *keymask); struct _MetaUI { Display *xdisplay; Screen *xscreen; MetaFrames *frames; /* For double-click tracking */ guint button_click_number; Window button_click_window; int button_click_x; int button_click_y; guint32 button_click_time; }; LOCAL_SYMBOL void meta_ui_init (void) { /* As of 2.91.7, Gdk uses XI2 by default, which conflicts with the * direct X calls we use - in particular, events caused by calls to * XGrabPointer/XGrabKeyboard are no longer understood by GDK, while * GDK will no longer generate the core XEvents we process. * So at least for now, enforce the previous behavior. */ gdk_disable_multidevice (); if (!gtk_init_check (NULL, NULL)) meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL)); /* We need to be able to fully trust that the window and monitor sizes + that Gdk reports corresponds to the X ones, so we disable the automatic + scale handling */ gdk_x11_display_set_window_scale (gdk_display_get_default (), 1); meta_stock_icons_init (); } LOCAL_SYMBOL Display* meta_ui_get_display (void) { return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); } /* We do some of our event handling in frames.c, which expects * GDK events delivered by GTK+. However, since the transition to * client side windows, we can't let GDK see button events, since the * client-side tracking of implicit and explicit grabs it does will * get confused by our direct use of X grabs in the core code. * * So we do a very minimal GDK => GTK event conversion here and send on the * events we care about, and then filter them out so they don't go * through the normal GDK event handling. * * To reduce the amount of code, the only events fields filled out * below are the ones that frames.c uses. If frames.c is modified to * use more fields, more fields need to be filled out below. */ static gboolean maybe_redirect_mouse_event (MetaDisplay *display, XEvent *xevent) { GdkDisplay *gdisplay; GdkDevice *gdevice; MetaUI *ui; GdkEvent *gevent; GdkWindow *gdk_window; Window window; switch (xevent->type) { case ButtonPress: case ButtonRelease: window = xevent->xbutton.window; break; case MotionNotify: window = xevent->xmotion.window; break; case EnterNotify: case LeaveNotify: window = xevent->xcrossing.window; break; default: return FALSE; } gdisplay = display->gdk_display; ui = display->ui; if (!ui) return FALSE; gdk_window = gdk_x11_window_lookup_for_display (gdisplay, window); if (gdk_window == NULL) return FALSE; gdevice = display->gdk_device; /* If GDK already thinks it has a grab, we better let it see events; this * is the menu-navigation case and events need to get sent to the appropriate * (client-side) subwindow for individual menu items. */ if (gdk_display_device_is_grabbed (gdisplay, gdevice)) return FALSE; switch (xevent->type) { case ButtonPress: case ButtonRelease: if (xevent->type == ButtonPress) { GtkSettings *settings = gtk_settings_get_default (); int double_click_time; int double_click_distance; g_object_get (settings, "gtk-double-click-time", &double_click_time, "gtk-double-click-distance", &double_click_distance, NULL); if (xevent->xbutton.button == ui->button_click_number && xevent->xbutton.window == ui->button_click_window && xevent->xbutton.time < ui->button_click_time + double_click_time && ABS (xevent->xbutton.x - ui->button_click_x) <= double_click_distance && ABS (xevent->xbutton.y - ui->button_click_y) <= double_click_distance) { gevent = gdk_event_new (GDK_2BUTTON_PRESS); ui->button_click_number = 0; } else { gevent = gdk_event_new (GDK_BUTTON_PRESS); ui->button_click_number = xevent->xbutton.button; ui->button_click_window = xevent->xbutton.window; ui->button_click_time = xevent->xbutton.time; ui->button_click_x = xevent->xbutton.x; ui->button_click_y = xevent->xbutton.y; } } else { gevent = gdk_event_new (GDK_BUTTON_RELEASE); } gevent->button.window = g_object_ref (gdk_window); gevent->button.button = xevent->xbutton.button; gevent->button.time = xevent->xbutton.time; gevent->button.x = xevent->xbutton.x; gevent->button.y = xevent->xbutton.y; gevent->button.x_root = xevent->xbutton.x_root; gevent->button.y_root = xevent->xbutton.y_root; break; case MotionNotify: gevent = gdk_event_new (GDK_MOTION_NOTIFY); gevent->motion.type = GDK_MOTION_NOTIFY; gevent->motion.window = g_object_ref (gdk_window); break; case EnterNotify: case LeaveNotify: gevent = gdk_event_new (xevent->type == EnterNotify ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY); gevent->crossing.window = g_object_ref (gdk_window); gevent->crossing.x = xevent->xcrossing.x; gevent->crossing.y = xevent->xcrossing.y; break; default: g_assert_not_reached (); break; } /* If we've gotten here, we've created the gdk_event and should send it on */ gdk_event_set_device (gevent, gdevice); gtk_main_do_event (gevent); gdk_event_free (gevent); return TRUE; } typedef struct _EventFunc EventFunc; struct _EventFunc { MetaEventFunc func; gpointer data; }; static EventFunc *ef = NULL; static GdkFilterReturn filter_func (GdkXEvent *xevent, GdkEvent *event, gpointer data) { MetaDisplay *display = (MetaDisplay*) ef->data; g_return_val_if_fail (ef != NULL && ef->data != NULL && display != NULL && !display->closing, GDK_FILTER_CONTINUE); if ((* ef->func) (xevent, ef->data) || maybe_redirect_mouse_event (display, xevent)) return GDK_FILTER_REMOVE; else return GDK_FILTER_CONTINUE; } LOCAL_SYMBOL void meta_ui_add_event_func (Display *xdisplay, MetaEventFunc func, gpointer data) { g_return_if_fail (ef == NULL); ef = g_new (EventFunc, 1); ef->func = func; ef->data = data; gdk_window_add_filter (NULL, filter_func, ef); } /* removal is by data due to proxy function */ LOCAL_SYMBOL void meta_ui_remove_event_func (Display *xdisplay, MetaEventFunc func, gpointer data) { g_return_if_fail (ef != NULL); gdk_window_remove_filter (NULL, filter_func, ef); free (ef); ef = NULL; } LOCAL_SYMBOL MetaUI* meta_ui_new (MetaDisplay *display, Screen *screen) { GdkDisplay *gdisplay; MetaUI *ui; ui = display->ui = g_new0 (MetaUI, 1); ui->xdisplay = display->xdisplay; ui->xscreen = screen; gdisplay = display->gdk_display; g_assert (gdisplay == gdk_display_get_default ()); ui->frames = meta_frames_new (XScreenNumberOfScreen (screen)); /* GTK+ needs the frame-sync protocol to work in order to properly * handle style changes. This means that the dummy widget we create * to get the style for title bars actually needs to be mapped * and fully tracked as a MetaWindow. Horrible, but mostly harmless - * the window is a 1x1 overide redirect window positioned offscreen. */ gtk_widget_show (GTK_WIDGET (ui->frames)); g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui); return ui; } LOCAL_SYMBOL void meta_ui_free (MetaUI *ui) { GdkDisplay *gdisplay; gtk_widget_destroy (GTK_WIDGET (ui->frames)); gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay); g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL); free (ui); } LOCAL_SYMBOL void meta_ui_get_frame_borders (MetaUI *ui, Window frame_xwindow, MetaFrameBorders *borders) { meta_frames_get_borders (ui->frames, frame_xwindow, borders); } LOCAL_SYMBOL void meta_ui_get_corner_radiuses (MetaUI *ui, Window xwindow, float *top_left, float *top_right, float *bottom_left, float *bottom_right) { meta_frames_get_corner_radiuses (ui->frames, xwindow, top_left, top_right, bottom_left, bottom_right); } LOCAL_SYMBOL void set_background_none (Display *xdisplay, Window xwindow) { XSetWindowAttributes attrs; attrs.background_pixmap = None; XChangeWindowAttributes (xdisplay, xwindow, CWBackPixmap, &attrs); } LOCAL_SYMBOL Window meta_ui_create_frame_window (MetaUI *ui, Display *xdisplay, Visual *xvisual, gint x, gint y, gint width, gint height, gint screen_no, gulong *create_serial) { GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay); GdkScreen *screen = gdk_display_get_screen (display, screen_no); GdkWindowAttr attrs; gint attributes_mask; GdkWindow *window; GdkVisual *visual; /* Default depth/visual handles clients with weird visuals; they can * always be children of the root depth/visual obviously, but * e.g. DRI games can't be children of a parent that has the same * visual as the client. */ if (!xvisual) visual = gdk_screen_get_system_visual (screen); else { visual = gdk_x11_screen_lookup_visual (screen, XVisualIDFromVisual (xvisual)); } attrs.title = NULL; /* frame.c is going to replace the event mask immediately, but * we still have to set it here to let GDK know what it is. */ attrs.event_mask = GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK; attrs.x = x; attrs.y = y; attrs.wclass = GDK_INPUT_OUTPUT; attrs.visual = visual; attrs.window_type = GDK_WINDOW_CHILD; attrs.cursor = NULL; attrs.wmclass_name = NULL; attrs.wmclass_class = NULL; attrs.override_redirect = FALSE; attrs.width = width; attrs.height = height; attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; /* We make an assumption that gdk_window_new() is going to call * XCreateWindow as it's first operation; this seems to be true currently * as long as you pass in a colormap. */ if (create_serial) *create_serial = XNextRequest (xdisplay); window = gdk_window_new (gdk_screen_get_root_window(screen), &attrs, attributes_mask); gdk_window_resize (window, width, height); set_background_none (xdisplay, GDK_WINDOW_XID (window)); meta_frames_manage_window (ui->frames, GDK_WINDOW_XID (window), window); return GDK_WINDOW_XID (window); } LOCAL_SYMBOL void meta_ui_destroy_frame_window (MetaUI *ui, Window xwindow) { meta_frames_unmanage_window (ui->frames, xwindow); } LOCAL_SYMBOL void meta_ui_move_resize_frame (MetaUI *ui, Window frame, int x, int y, int width, int height) { meta_frames_move_resize_frame (ui->frames, frame, x, y, width, height); } LOCAL_SYMBOL void meta_ui_map_frame (MetaUI *ui, Window xwindow) { GdkWindow *window; GdkDisplay *display; display = gdk_x11_lookup_xdisplay (ui->xdisplay); window = gdk_x11_window_lookup_for_display (display, xwindow); if (window) gdk_window_show_unraised (window); } LOCAL_SYMBOL void meta_ui_unmap_frame (MetaUI *ui, Window xwindow) { GdkWindow *window; GdkDisplay *display; display = gdk_x11_lookup_xdisplay (ui->xdisplay); window = gdk_x11_window_lookup_for_display (display, xwindow); if (window) gdk_window_hide (window); } LOCAL_SYMBOL void meta_ui_update_frame_style (MetaUI *ui, Window xwindow) { meta_frames_update_frame_style (ui->frames, xwindow); } LOCAL_SYMBOL void meta_ui_repaint_frame (MetaUI *ui, Window xwindow) { meta_frames_repaint_frame (ui->frames, xwindow); } LOCAL_SYMBOL cairo_region_t * meta_ui_get_frame_bounds (MetaUI *ui, Window xwindow, int window_width, int window_height) { return meta_frames_get_frame_bounds (ui->frames, xwindow, window_width, window_height); } LOCAL_SYMBOL void meta_ui_queue_frame_draw (MetaUI *ui, Window xwindow) { meta_frames_queue_draw (ui->frames, xwindow); } LOCAL_SYMBOL void meta_ui_set_frame_title (MetaUI *ui, Window xwindow, const char *title) { meta_frames_set_title (ui->frames, xwindow, title); } LOCAL_SYMBOL MetaWindowMenu* meta_ui_window_menu_new (MetaUI *ui, Window client_xwindow, MetaMenuOp ops, MetaMenuOp insensitive, unsigned long active_workspace, int n_workspaces, MetaWindowMenuFunc func, gpointer data) { return meta_window_menu_new (ui->frames, ops, insensitive, client_xwindow, active_workspace, n_workspaces, func, data); } LOCAL_SYMBOL void meta_ui_window_menu_popup (MetaWindowMenu *menu, int root_x, int root_y, int button, guint32 timestamp) { meta_window_menu_popup (menu, root_x, root_y, button, timestamp); } LOCAL_SYMBOL void meta_ui_window_menu_free (MetaWindowMenu *menu) { meta_window_menu_free (menu); } LOCAL_SYMBOL GdkPixbuf* meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap, int src_x, int src_y, int width, int height) { cairo_surface_t *surface; Display *display; Window root_return; int x_ret, y_ret; unsigned int w_ret, h_ret, bw_ret, depth_ret; XWindowAttributes attrs; GdkPixbuf *retval; display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); if (!XGetGeometry (display, xpixmap, &root_return, &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret)) return NULL; if (depth_ret == 1) { surface = cairo_xlib_surface_create_for_bitmap (display, xpixmap, GDK_SCREEN_XSCREEN (gdk_screen_get_default ()), w_ret, h_ret); } else { if (!XGetWindowAttributes (display, root_return, &attrs)) return NULL; surface = cairo_xlib_surface_create (display, xpixmap, attrs.visual, w_ret, h_ret); } retval = gdk_pixbuf_get_from_surface (surface, src_x, src_y, width, height); cairo_surface_destroy (surface); return retval; } LOCAL_SYMBOL gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay, Window xwindow) { GdkWindow *window; GdkDisplay *display; display = gdk_x11_lookup_xdisplay (xdisplay); window = gdk_x11_window_lookup_for_display (display, xwindow); /* we shouldn't cause focus if we're an override redirect * toplevel which is not foreign */ if (window && gdk_window_get_window_type (window) == GDK_WINDOW_TEMP) return TRUE; else return FALSE; } LOCAL_SYMBOL char* meta_text_property_to_utf8 (Display *xdisplay, const XTextProperty *prop) { GdkDisplay *display; char **list; int count; char *retval; list = NULL; display = gdk_x11_lookup_xdisplay (xdisplay); count = gdk_text_property_to_utf8_list_for_display (display, gdk_x11_xatom_to_atom_for_display (display, prop->encoding), prop->format, prop->value, prop->nitems, &list); if (count == 0) retval = NULL; else { retval = list[0]; list[0] = g_strdup (""); /* something to free */ } g_strfreev (list); return retval; } LOCAL_SYMBOL void meta_ui_theme_get_frame_borders (MetaUI *ui, MetaFrameType type, MetaFrameFlags flags, MetaFrameBorders *borders) { int text_height; GtkStyleContext *style = NULL; PangoContext *context; const PangoFontDescription *font_desc; PangoFontDescription *free_font_desc = NULL; if (meta_ui_have_a_theme ()) { context = gtk_widget_get_pango_context (GTK_WIDGET (ui->frames)); font_desc = meta_prefs_get_titlebar_font (); if (!font_desc) { style = gtk_style_context_new (); gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &free_font_desc, NULL); font_desc = (const PangoFontDescription *) free_font_desc; } text_height = meta_pango_font_desc_get_text_height (font_desc, context); meta_theme_get_frame_borders (meta_theme_get_current (), type, text_height, flags, borders); if (free_font_desc) pango_font_description_free (free_font_desc); } else { meta_frame_borders_clear (borders); } if (style != NULL) g_object_unref (style); } LOCAL_SYMBOL void meta_ui_set_current_theme (const char *name, gboolean force_reload) { meta_theme_set_current (name, force_reload); } LOCAL_SYMBOL gboolean meta_ui_have_a_theme (void) { return meta_theme_get_current () != NULL; } static void meta_ui_accelerator_parse (const char *accel, guint *keysym, guint *keycode, GdkModifierType *keymask) { const char *above_tab; if (accel[0] == '0' && accel[1] == 'x') { *keysym = 0; *keycode = (guint) strtoul (accel, NULL, 16); *keymask = 0; return; } /* The key name 'Above_Tab' is special - it's not an actual keysym name, * but rather refers to the key above the tab key. In order to use * the GDK parsing for modifiers in combination with it, we substitute * it with 'Tab' temporarily before calling gtk_accelerator_parse(). */ #define is_word_character(c) (g_ascii_isalnum(c) || ((c) == '_')) #define ABOVE_TAB "Above_Tab" #define ABOVE_TAB_LEN 9 above_tab = strstr (accel, ABOVE_TAB); if (above_tab && (above_tab == accel || !is_word_character (above_tab[-1])) && !is_word_character (above_tab[ABOVE_TAB_LEN])) { char *before = g_strndup (accel, above_tab - accel); char *after = g_strdup (above_tab + ABOVE_TAB_LEN); char *replaced = g_strconcat (before, "Tab", after, NULL); gtk_accelerator_parse (replaced, NULL, keymask); free (before); free (after); free (replaced); *keysym = META_KEY_ABOVE_TAB; return; } #undef is_word_character #undef ABOVE_TAB #undef ABOVE_TAB_LEN gtk_accelerator_parse (accel, keysym, keymask); } LOCAL_SYMBOL gboolean meta_ui_parse_accelerator (const char *accel, unsigned int *keysym, unsigned int *keycode, MetaVirtualModifier *mask) { GdkModifierType gdk_mask = 0; guint gdk_sym = 0; guint gdk_code = 0; *keysym = 0; *keycode = 0; *mask = 0; if (!accel[0] || strcmp (accel, "disabled") == 0) return TRUE; meta_ui_accelerator_parse (accel, &gdk_sym, &gdk_code, &gdk_mask); if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0) return FALSE; if (gdk_sym == None && gdk_code == 0) return FALSE; if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */ return FALSE; *keysym = gdk_sym; *keycode = gdk_code; if (gdk_mask & GDK_SHIFT_MASK) *mask |= META_VIRTUAL_SHIFT_MASK; if (gdk_mask & GDK_CONTROL_MASK) *mask |= META_VIRTUAL_CONTROL_MASK; if (gdk_mask & GDK_MOD1_MASK) *mask |= META_VIRTUAL_ALT_MASK; if (gdk_mask & GDK_MOD2_MASK) *mask |= META_VIRTUAL_MOD2_MASK; if (gdk_mask & GDK_MOD3_MASK) *mask |= META_VIRTUAL_MOD3_MASK; if (gdk_mask & GDK_MOD4_MASK) *mask |= META_VIRTUAL_MOD4_MASK; if (gdk_mask & GDK_MOD5_MASK) *mask |= META_VIRTUAL_MOD5_MASK; if (gdk_mask & GDK_SUPER_MASK) *mask |= META_VIRTUAL_SUPER_MASK; if (gdk_mask & GDK_HYPER_MASK) *mask |= META_VIRTUAL_HYPER_MASK; if (gdk_mask & GDK_META_MASK) *mask |= META_VIRTUAL_META_MASK; return TRUE; } /* Caller responsible for freeing return string of meta_ui_accelerator_name! */ LOCAL_SYMBOL gchar* meta_ui_accelerator_name (unsigned int keysym, MetaVirtualModifier mask) { GdkModifierType mods = 0; if (keysym == 0 && mask == 0) { return g_strdup ("disabled"); } if (mask & META_VIRTUAL_SHIFT_MASK) mods |= GDK_SHIFT_MASK; if (mask & META_VIRTUAL_CONTROL_MASK) mods |= GDK_CONTROL_MASK; if (mask & META_VIRTUAL_ALT_MASK) mods |= GDK_MOD1_MASK; if (mask & META_VIRTUAL_MOD2_MASK) mods |= GDK_MOD2_MASK; if (mask & META_VIRTUAL_MOD3_MASK) mods |= GDK_MOD3_MASK; if (mask & META_VIRTUAL_MOD4_MASK) mods |= GDK_MOD4_MASK; if (mask & META_VIRTUAL_MOD5_MASK) mods |= GDK_MOD5_MASK; if (mask & META_VIRTUAL_SUPER_MASK) mods |= GDK_SUPER_MASK; if (mask & META_VIRTUAL_HYPER_MASK) mods |= GDK_HYPER_MASK; if (mask & META_VIRTUAL_META_MASK) mods |= GDK_META_MASK; return gtk_accelerator_name (keysym, mods); } LOCAL_SYMBOL gboolean meta_ui_parse_modifier (const char *accel, MetaVirtualModifier *mask) { GdkModifierType gdk_mask = 0; guint gdk_sym = 0; guint gdk_code = 0; *mask = 0; if (accel == NULL || !accel[0] || strcmp (accel, "disabled") == 0) return TRUE; meta_ui_accelerator_parse (accel, &gdk_sym, &gdk_code, &gdk_mask); if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0) return FALSE; if (gdk_sym != None || gdk_code != 0) return FALSE; if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */ return FALSE; if (gdk_mask & GDK_SHIFT_MASK) *mask |= META_VIRTUAL_SHIFT_MASK; if (gdk_mask & GDK_CONTROL_MASK) *mask |= META_VIRTUAL_CONTROL_MASK; if (gdk_mask & GDK_MOD1_MASK) *mask |= META_VIRTUAL_ALT_MASK; if (gdk_mask & GDK_MOD2_MASK) *mask |= META_VIRTUAL_MOD2_MASK; if (gdk_mask & GDK_MOD3_MASK) *mask |= META_VIRTUAL_MOD3_MASK; if (gdk_mask & GDK_MOD4_MASK) *mask |= META_VIRTUAL_MOD4_MASK; if (gdk_mask & GDK_MOD5_MASK) *mask |= META_VIRTUAL_MOD5_MASK; if (gdk_mask & GDK_SUPER_MASK) *mask |= META_VIRTUAL_SUPER_MASK; if (gdk_mask & GDK_HYPER_MASK) *mask |= META_VIRTUAL_HYPER_MASK; if (gdk_mask & GDK_META_MASK) *mask |= META_VIRTUAL_META_MASK; return TRUE; } LOCAL_SYMBOL gboolean meta_ui_window_is_widget (MetaUI *ui, Window xwindow) { GdkDisplay *display; GdkWindow *window; display = gdk_x11_lookup_xdisplay (ui->xdisplay); window = gdk_x11_window_lookup_for_display (display, xwindow); if (window) { void *user_data = NULL; gdk_window_get_user_data (window, &user_data); return user_data != NULL && user_data != ui->frames; } else return FALSE; } /* stock icon code Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> */ typedef struct { char *stock_id; const guint8 *icon_data; } MetaStockIcon; static void meta_stock_icons_init (void) { GtkIconFactory *factory; int i; MetaStockIcon items[] = { { METACITY_STOCK_DELETE, stock_delete_data }, { METACITY_STOCK_MINIMIZE, stock_minimize_data }, { METACITY_STOCK_MAXIMIZE, stock_maximize_data } }; factory = gtk_icon_factory_new (); gtk_icon_factory_add_default (factory); for (i = 0; i < (gint) G_N_ELEMENTS (items); i++) { GtkIconSet *icon_set; GdkPixbuf *pixbuf; pixbuf = gdk_pixbuf_new_from_inline (-1, items[i].icon_data, FALSE, NULL); icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); gtk_icon_factory_add (factory, items[i].stock_id, icon_set); gtk_icon_set_unref (icon_set); g_object_unref (G_OBJECT (pixbuf)); } g_object_unref (G_OBJECT (factory)); } LOCAL_SYMBOL MetaUIDirection meta_ui_get_direction (void) { if (gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL) return META_UI_DIRECTION_RTL; return META_UI_DIRECTION_LTR; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/frames.c������������������������������������������������������������������������0000664�0001750�0001750�00000235451�14211404421�015773� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity window frame manager widget */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2005, 2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <math.h> #include <string.h> #include <meta/boxes.h> #include "frames.h" #include <meta/util.h> #include "core.h" #include "menu.h" #include "window-private.h" #include <meta/theme.h> #include <meta/prefs.h> #include "ui.h" #include <cairo-xlib.h> #ifdef HAVE_SHAPE #include <X11/extensions/shape.h> #endif #define DEFAULT_INNER_BUTTON_BORDER 3 static void meta_frames_destroy (GtkWidget *object); static void meta_frames_finalize (GObject *object); static void meta_frames_style_updated (GtkWidget *widget); static void meta_frames_update_prelit_control (MetaFrames *frames, MetaUIFrame *frame, MetaFrameControl control); static gboolean meta_frames_button_press_event (GtkWidget *widget, GdkEventButton *event); static gboolean meta_frames_button_release_event (GtkWidget *widget, GdkEventButton *event); static gboolean meta_frames_motion_notify_event (GtkWidget *widget, GdkEventMotion *event); static gboolean meta_frames_destroy_event (GtkWidget *widget, GdkEventAny *event); static gboolean meta_frames_draw (GtkWidget *widget, cairo_t *cr); static gboolean meta_frames_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event); static gboolean meta_frames_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event); static void meta_frames_attach_style (MetaFrames *frames, MetaUIFrame *frame); static void meta_frames_paint (MetaFrames *frames, MetaUIFrame *frame, cairo_t *cr); static void meta_frames_calc_geometry (MetaFrames *frames, MetaUIFrame *frame, MetaFrameGeometry *fgeom); static void meta_frames_ensure_layout (MetaFrames *frames, MetaUIFrame *frame); static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames, Window xwindow); static void meta_frames_font_changed (MetaFrames *frames); static void meta_frames_button_layout_changed (MetaFrames *frames); static GdkRectangle* control_rect (MetaFrameControl control, MetaFrameGeometry *fgeom); static MetaFrameControl get_control (MetaFrames *frames, MetaUIFrame *frame, int x, int y); static void invalidate_all_caches (MetaFrames *frames); static void invalidate_whole_window (MetaFrames *frames, MetaUIFrame *frame); G_DEFINE_TYPE (MetaFrames, meta_frames, GTK_TYPE_WINDOW); static GObject * meta_frames_constructor (GType gtype, guint n_properties, GObjectConstructParam *properties) { GObject *object; GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (meta_frames_parent_class); object = gobject_class->constructor (gtype, n_properties, properties); g_object_set (object, "type", GTK_WINDOW_POPUP, NULL); return object; } static void meta_frames_class_init (MetaFramesClass *class) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; gobject_class = G_OBJECT_CLASS (class); widget_class = (GtkWidgetClass*) class; gobject_class->constructor = meta_frames_constructor; gobject_class->finalize = meta_frames_finalize; widget_class->destroy = meta_frames_destroy; widget_class->style_updated = meta_frames_style_updated; widget_class->draw = meta_frames_draw; widget_class->destroy_event = meta_frames_destroy_event; widget_class->button_press_event = meta_frames_button_press_event; widget_class->button_release_event = meta_frames_button_release_event; widget_class->motion_notify_event = meta_frames_motion_notify_event; widget_class->enter_notify_event = meta_frames_enter_notify_event; widget_class->leave_notify_event = meta_frames_leave_notify_event; } static gint unsigned_long_equal (gconstpointer v1, gconstpointer v2) { return *((const gulong*) v1) == *((const gulong*) v2); } static guint unsigned_long_hash (gconstpointer v) { gulong val = * (const gulong *) v; /* I'm not sure this works so well. */ #if GLIB_SIZEOF_LONG > 4 return (guint) (val ^ (val >> 32)); #else return val; #endif } static void prefs_changed_callback (MetaPreference pref, void *data) { switch (pref) { case META_PREF_TITLEBAR_FONT: meta_frames_font_changed (META_FRAMES (data)); break; case META_PREF_BUTTON_LAYOUT: meta_frames_button_layout_changed (META_FRAMES (data)); break; default: break; } } static GtkStyleContext * create_style_context (MetaFrames *frames, const gchar *variant) { GtkStyleContext *style; GdkScreen *screen; char *theme_name; screen = gtk_widget_get_screen (GTK_WIDGET (frames)); g_object_get (gtk_settings_get_for_screen (screen), "gtk-theme-name", &theme_name, NULL); style = gtk_style_context_new (); gtk_style_context_set_path (style, gtk_widget_get_path (GTK_WIDGET (frames))); if (theme_name && *theme_name) { GtkCssProvider *provider; provider = gtk_css_provider_get_named (theme_name, variant); gtk_style_context_add_provider (style, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_SETTINGS); } free (theme_name); return style; } static GtkStyleContext * meta_frames_get_theme_variant (MetaFrames *frames, const gchar *variant) { GtkStyleContext *style; style = g_hash_table_lookup (frames->style_variants, variant); if (style == NULL) { style = create_style_context (frames, variant); g_hash_table_insert (frames->style_variants, g_strdup (variant), style); } return style; } static void update_style_contexts (MetaFrames *frames) { GtkStyleContext *style; GList *variant_list, *variant; if (frames->normal_style) g_object_unref (frames->normal_style); frames->normal_style = create_style_context (frames, NULL); variant_list = g_hash_table_get_keys (frames->style_variants); for (variant = variant_list; variant; variant = variant->next) { style = create_style_context (frames, (char *)variant->data); g_hash_table_insert (frames->style_variants, g_strdup (variant->data), style); } g_list_free (variant_list); } static void meta_frames_init (MetaFrames *frames) { frames->text_heights = g_hash_table_new (NULL, NULL); frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal); frames->invalidate_cache_timeout_id = 0; frames->invalidate_frames = NULL; frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal); frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal, free, g_object_unref); update_style_contexts (frames); gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE); meta_prefs_add_listener (prefs_changed_callback, frames); } static void listify_func (gpointer key, gpointer value, gpointer data) { GSList **listp; listp = data; *listp = g_slist_prepend (*listp, value); } static void meta_frames_destroy (GtkWidget *object) { GSList *winlist; GSList *tmp; MetaFrames *frames; frames = META_FRAMES (object); winlist = NULL; g_hash_table_foreach (frames->frames, listify_func, &winlist); /* Unmanage all frames */ for (tmp = winlist; tmp != NULL; tmp = tmp->next) { MetaUIFrame *frame; frame = tmp->data; meta_frames_unmanage_window (frames, frame->xwindow); } g_slist_free (winlist); if (frames->normal_style) { g_object_unref (frames->normal_style); frames->normal_style = NULL; } if (frames->style_variants) { g_hash_table_destroy (frames->style_variants); frames->style_variants = NULL; } GTK_WIDGET_CLASS (meta_frames_parent_class)->destroy (object); } static void meta_frames_finalize (GObject *object) { MetaFrames *frames; frames = META_FRAMES (object); meta_prefs_remove_listener (prefs_changed_callback, frames); g_hash_table_destroy (frames->text_heights); invalidate_all_caches (frames); if (frames->invalidate_cache_timeout_id) { g_source_remove (frames->invalidate_cache_timeout_id); frames->invalidate_cache_timeout_id = 0; } g_assert (g_hash_table_size (frames->frames) == 0); g_hash_table_destroy (frames->frames); g_hash_table_destroy (frames->cache); G_OBJECT_CLASS (meta_frames_parent_class)->finalize (object); } typedef struct { cairo_rectangle_int_t rect; cairo_surface_t *pixmap; } CachedFramePiece; typedef struct { /* Caches of the four rendered sides in a MetaFrame. * Order: top (titlebar), left, right, bottom. */ CachedFramePiece piece[4]; } CachedPixels; static CachedPixels * get_cache (MetaFrames *frames, MetaUIFrame *frame) { CachedPixels *pixels; pixels = g_hash_table_lookup (frames->cache, frame); if (!pixels) { pixels = g_new0 (CachedPixels, 1); g_hash_table_insert (frames->cache, frame, pixels); } return pixels; } static void invalidate_cache (MetaFrames *frames, MetaUIFrame *frame) { CachedPixels *pixels = get_cache (frames, frame); int i; for (i = 0; i < 4; i++) if (pixels->piece[i].pixmap) cairo_surface_destroy (pixels->piece[i].pixmap); free (pixels); g_hash_table_remove (frames->cache, frame); } static void invalidate_all_caches (MetaFrames *frames) { GList *l; for (l = frames->invalidate_frames; l; l = l->next) { MetaUIFrame *frame = l->data; invalidate_cache (frames, frame); } g_list_free (frames->invalidate_frames); frames->invalidate_frames = NULL; } static gboolean invalidate_cache_timeout (gpointer data) { MetaFrames *frames = data; invalidate_all_caches (frames); frames->invalidate_cache_timeout_id = 0; return FALSE; } static void queue_recalc_func (gpointer key, gpointer value, gpointer data) { MetaUIFrame *frame; MetaFrames *frames; frames = META_FRAMES (data); frame = value; invalidate_whole_window (frames, frame); meta_core_queue_frame_resize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow); if (frame->layout) { /* save title to recreate layout */ free (frame->title); frame->title = g_strdup (pango_layout_get_text (frame->layout)); g_object_unref (G_OBJECT (frame->layout)); frame->layout = NULL; } } static void meta_frames_font_changed (MetaFrames *frames) { if (g_hash_table_size (frames->text_heights) > 0) { g_hash_table_destroy (frames->text_heights); frames->text_heights = g_hash_table_new (NULL, NULL); } /* Queue a draw/resize on all frames */ g_hash_table_foreach (frames->frames, queue_recalc_func, frames); } static void queue_draw_func (gpointer key, gpointer value, gpointer data) { MetaUIFrame *frame; MetaFrames *frames; frames = META_FRAMES (data); frame = value; invalidate_whole_window (frames, frame); } static void meta_frames_button_layout_changed (MetaFrames *frames) { g_hash_table_foreach (frames->frames, queue_draw_func, frames); } static void reattach_style_func (gpointer key, gpointer value, gpointer data) { MetaUIFrame *frame; MetaFrames *frames; frames = META_FRAMES (data); frame = value; meta_frames_attach_style (frames, frame); } static void meta_frames_style_updated (GtkWidget *widget) { MetaFrames *frames; frames = META_FRAMES (widget); meta_frames_font_changed (frames); update_style_contexts (frames); g_hash_table_foreach (frames->frames, reattach_style_func, frames); GTK_WIDGET_CLASS (meta_frames_parent_class)->style_updated (widget); } static void meta_frames_ensure_layout (MetaFrames *frames, MetaUIFrame *frame) { GtkWidget *widget; MetaFrameFlags flags; MetaFrameType type; MetaFrameStyle *style; widget = GTK_WIDGET (frames); g_return_if_fail (gtk_widget_get_realized (widget)); meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_FRAME_TYPE, &type, META_CORE_GET_END); style = meta_theme_get_frame_style (meta_theme_get_current (), type, flags); if (style != frame->cache_style) { if (frame->layout) { /* save title to recreate layout */ free (frame->title); frame->title = g_strdup (pango_layout_get_text (frame->layout)); g_object_unref (G_OBJECT (frame->layout)); frame->layout = NULL; } } frame->cache_style = style; if (frame->layout == NULL) { gpointer key, value; PangoFontDescription *font_desc; double scale; int size; scale = meta_theme_get_title_scale (meta_theme_get_current (), type, flags); frame->layout = gtk_widget_create_pango_layout (widget, frame->title); pango_layout_set_ellipsize (frame->layout, PANGO_ELLIPSIZE_END); pango_layout_set_auto_dir (frame->layout, FALSE); font_desc = meta_gtk_widget_get_font_desc (widget, scale, meta_prefs_get_titlebar_font ()); size = pango_font_description_get_size (font_desc); if (g_hash_table_lookup_extended (frames->text_heights, GINT_TO_POINTER (size), &key, &value)) { frame->text_height = GPOINTER_TO_INT (value); } else { frame->text_height = meta_pango_font_desc_get_text_height (font_desc, gtk_widget_get_pango_context (widget)); g_hash_table_replace (frames->text_heights, GINT_TO_POINTER (size), GINT_TO_POINTER (frame->text_height)); } pango_layout_set_font_description (frame->layout, font_desc); pango_font_description_free (font_desc); /* Save some RAM */ free (frame->title); frame->title = NULL; } } static void meta_frames_calc_geometry (MetaFrames *frames, MetaUIFrame *frame, MetaFrameGeometry *fgeom) { int width, height; MetaFrameFlags flags; MetaFrameType type; MetaButtonLayout button_layout; meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CORE_GET_CLIENT_WIDTH, &width, META_CORE_GET_CLIENT_HEIGHT, &height, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_FRAME_TYPE, &type, META_CORE_GET_END); meta_frames_ensure_layout (frames, frame); meta_prefs_get_button_layout (&button_layout); meta_theme_calc_geometry (meta_theme_get_current (), type, frame->text_height, flags, width, height, &button_layout, fgeom); } LOCAL_SYMBOL MetaFrames* meta_frames_new (int screen_number) { GdkScreen *screen; MetaFrames *frames; screen = gdk_display_get_screen (gdk_display_get_default (), screen_number); frames = g_object_new (META_TYPE_FRAMES, "screen", screen, "type", GTK_WINDOW_POPUP, NULL); /* Put the window at an arbitrary offscreen location; the one place * it can't be is at -100x-100, since the meta_window_new() will * mistake it for a window created via meta_create_offscreen_window() * and ignore it, and we need this window to get frame-synchronization * messages so that GTK+'s style change handling works. */ gtk_window_move (GTK_WINDOW (frames), -200, -200); gtk_window_resize (GTK_WINDOW (frames), 1, 1); return frames; } /* In order to use a style with a window it has to be attached to that * window. Actually, the colormaps just have to match, but since GTK+ * already takes care of making sure that its cheap to attach a style * to multiple windows with the same colormap, we can just go ahead * and attach separately for each window. */ static void meta_frames_attach_style (MetaFrames *frames, MetaUIFrame *frame) { gboolean has_frame; char *variant = NULL; if (frame->style != NULL) g_object_unref (frame->style); meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CORE_WINDOW_HAS_FRAME, &has_frame, META_CORE_GET_THEME_VARIANT, &variant, META_CORE_GET_END); if (variant == NULL || strcmp(variant, "normal") == 0) frame->style = g_object_ref (frames->normal_style); else frame->style = g_object_ref (meta_frames_get_theme_variant (frames, variant)); } LOCAL_SYMBOL void meta_frames_manage_window (MetaFrames *frames, Window xwindow, GdkWindow *window) { MetaUIFrame *frame; g_assert (window); frame = g_new (MetaUIFrame, 1); frame->window = window; gdk_window_set_user_data (frame->window, frames); frame->style = NULL; /* Don't set event mask here, it's in frame.c */ frame->xwindow = xwindow; frame->cache_style = NULL; frame->layout = NULL; frame->text_height = -1; frame->title = NULL; frame->shape_applied = FALSE; frame->prelit_control = META_FRAME_CONTROL_NONE; meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow); g_hash_table_replace (frames->frames, &frame->xwindow, frame); } LOCAL_SYMBOL void meta_frames_unmanage_window (MetaFrames *frames, Window xwindow) { MetaUIFrame *frame; frame = g_hash_table_lookup (frames->frames, &xwindow); if (frame) { /* invalidating all caches ensures the frame * is not actually referenced anymore */ invalidate_all_caches (frames); /* restore the cursor */ meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CURSOR_DEFAULT); gdk_window_set_user_data (frame->window, NULL); if (frames->last_motion_frame == frame) frames->last_motion_frame = NULL; g_hash_table_remove (frames->frames, &frame->xwindow); g_object_unref (frame->style); gdk_window_destroy (frame->window); if (frame->layout) g_object_unref (G_OBJECT (frame->layout)); free (frame->title); free (frame); } else meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow); } static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames, Window xwindow) { MetaUIFrame *frame; frame = g_hash_table_lookup (frames->frames, &xwindow); return frame; } LOCAL_SYMBOL void meta_frames_get_borders (MetaFrames *frames, Window xwindow, MetaFrameBorders *borders) { MetaFrameFlags flags; MetaUIFrame *frame; MetaFrameType type; frame = meta_frames_lookup_window (frames, xwindow); if (frame == NULL) meta_bug ("No such frame 0x%lx\n", xwindow); meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_FRAME_TYPE, &type, META_CORE_GET_END); g_return_if_fail (type < META_FRAME_TYPE_LAST); meta_frames_ensure_layout (frames, frame); /* We can't get the full geometry, because that depends on * the client window size and probably we're being called * by the core move/resize code to decide on the client * window size */ meta_theme_get_frame_borders (meta_theme_get_current (), type, frame->text_height, flags, borders); } LOCAL_SYMBOL void meta_frames_get_corner_radiuses (MetaFrames *frames, Window xwindow, float *top_left, float *top_right, float *bottom_left, float *bottom_right) { MetaUIFrame *frame; MetaFrameGeometry fgeom; frame = meta_frames_lookup_window (frames, xwindow); meta_frames_calc_geometry (frames, frame, &fgeom); /* For compatibility with the code in get_visible_rect(), there's * a mysterious sqrt() added to the corner radiuses: * * const float radius = sqrt(corner) + corner; * * It's unclear why the radius is calculated like this, but we * need to be consistent with it. */ if (top_left) *top_left = fgeom.top_left_corner_rounded_radius + sqrt(fgeom.top_left_corner_rounded_radius); if (top_right) *top_right = fgeom.top_right_corner_rounded_radius + sqrt(fgeom.top_right_corner_rounded_radius); if (bottom_left) *bottom_left = fgeom.bottom_left_corner_rounded_radius + sqrt(fgeom.bottom_left_corner_rounded_radius); if (bottom_right) *bottom_right = fgeom.bottom_right_corner_rounded_radius + sqrt(fgeom.bottom_right_corner_rounded_radius); } /* The client rectangle surrounds client window; it subtracts both * the visible and invisible borders from the frame window's size. */ static void get_client_rect (MetaFrameGeometry *fgeom, int window_width, int window_height, cairo_rectangle_int_t *rect) { rect->x = fgeom->borders.total.left; rect->y = fgeom->borders.total.top; rect->width = window_width - fgeom->borders.total.right - rect->x; rect->height = window_height - fgeom->borders.total.bottom - rect->y; } /* The visible frame rectangle surrounds the visible portion of the * frame window; it subtracts only the invisible borders from the frame * window's size. */ static void get_visible_frame_rect (MetaFrameGeometry *fgeom, int window_width, int window_height, cairo_rectangle_int_t *rect) { rect->x = fgeom->borders.invisible.left; rect->y = fgeom->borders.invisible.top; rect->width = window_width - fgeom->borders.invisible.right - rect->x; rect->height = window_height - fgeom->borders.invisible.bottom - rect->y; } static cairo_region_t * get_visible_region (MetaFrames *frames, MetaUIFrame *frame, MetaFrameGeometry *fgeom, int window_width, int window_height) { cairo_region_t *corners_region; cairo_region_t *visible_region; cairo_rectangle_int_t rect; cairo_rectangle_int_t frame_rect; corners_region = cairo_region_create (); get_visible_frame_rect (fgeom, window_width, window_height, &frame_rect); if (fgeom->top_left_corner_rounded_radius != 0) { const int corner = fgeom->top_left_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); rect.x = frame_rect.x; rect.y = frame_rect.y + i; rect.width = width; rect.height = 1; cairo_region_union_rectangle (corners_region, &rect); } } if (fgeom->top_right_corner_rounded_radius != 0) { const int corner = fgeom->top_right_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); rect.x = frame_rect.x + frame_rect.width - width; rect.y = frame_rect.y + i; rect.width = width; rect.height = 1; cairo_region_union_rectangle (corners_region, &rect); } } if (fgeom->bottom_left_corner_rounded_radius != 0) { const int corner = fgeom->bottom_left_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); rect.x = frame_rect.x; rect.y = frame_rect.y + frame_rect.height - i - 1; rect.width = width; rect.height = 1; cairo_region_union_rectangle (corners_region, &rect); } } if (fgeom->bottom_right_corner_rounded_radius != 0) { const int corner = fgeom->bottom_right_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); rect.x = frame_rect.x + frame_rect.width - width; rect.y = frame_rect.y + frame_rect.height - i - 1; rect.width = width; rect.height = 1; cairo_region_union_rectangle (corners_region, &rect); } } visible_region = cairo_region_create_rectangle (&frame_rect); cairo_region_subtract (visible_region, corners_region); cairo_region_destroy (corners_region); return visible_region; } LOCAL_SYMBOL cairo_region_t * meta_frames_get_frame_bounds (MetaFrames *frames, Window xwindow, int window_width, int window_height) { MetaUIFrame *frame; MetaFrameGeometry fgeom; frame = meta_frames_lookup_window (frames, xwindow); g_return_val_if_fail (frame != NULL, NULL); meta_frames_calc_geometry (frames, frame, &fgeom); return get_visible_region (frames, frame, &fgeom, window_width, window_height); } LOCAL_SYMBOL void meta_frames_move_resize_frame (MetaFrames *frames, Window xwindow, int x, int y, int width, int height) { MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow); int old_width, old_height; old_width = gdk_window_get_width (frame->window); old_height = gdk_window_get_height (frame->window); gdk_window_move_resize (frame->window, x, y, width, height); if (old_width != width || old_height != height) invalidate_whole_window (frames, frame); } LOCAL_SYMBOL void meta_frames_queue_draw (MetaFrames *frames, Window xwindow) { MetaUIFrame *frame; frame = meta_frames_lookup_window (frames, xwindow); invalidate_whole_window (frames, frame); } LOCAL_SYMBOL void meta_frames_set_title (MetaFrames *frames, Window xwindow, const char *title) { MetaUIFrame *frame; frame = meta_frames_lookup_window (frames, xwindow); g_assert (frame); free (frame->title); frame->title = g_strdup (title); if (frame->layout) { g_object_unref (frame->layout); frame->layout = NULL; } invalidate_whole_window (frames, frame); } LOCAL_SYMBOL void meta_frames_update_frame_style (MetaFrames *frames, Window xwindow) { MetaUIFrame *frame; frame = meta_frames_lookup_window (frames, xwindow); g_assert (frame); meta_frames_attach_style (frames, frame); invalidate_whole_window (frames, frame); } LOCAL_SYMBOL void meta_frames_repaint_frame (MetaFrames *frames, Window xwindow) { MetaUIFrame *frame; frame = meta_frames_lookup_window (frames, xwindow); g_assert (frame); /* repaint everything, so the other frame don't * lag behind if they are exposed */ gdk_window_process_all_updates (); } static void redraw_control (MetaFrames *frames, MetaUIFrame *frame, MetaFrameControl control) { MetaFrameGeometry fgeom; GdkRectangle *rect; meta_frames_calc_geometry (frames, frame, &fgeom); rect = control_rect (control, &fgeom); gdk_window_invalidate_rect (frame->window, rect, FALSE); invalidate_cache (frames, frame); } enum { MOUSEWHEEL_UP = 4, MOUSEWHEEL_DOWN = 5 }; static gboolean meta_frame_titlebar_event (MetaUIFrame *frame, GdkEventButton *event, int action) { MetaFrameFlags flags; Display *display; display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); switch (action) { case C_DESKTOP_TITLEBAR_ACTION_TOGGLE_SHADE: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ALLOWS_SHADE) { if (flags & META_FRAME_SHADED) meta_core_unshade (display, frame->xwindow, event->time); else meta_core_shade (display, frame->xwindow, event->time); } } break; case C_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ALLOWS_MAXIMIZE) { meta_core_toggle_maximize (display, frame->xwindow); } } break; case C_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_HORIZONTALLY: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ALLOWS_MAXIMIZE) { meta_core_toggle_maximize_horizontally (display, frame->xwindow); } } break; case C_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_VERTICALLY: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ALLOWS_MAXIMIZE) { meta_core_toggle_maximize_vertically (display, frame->xwindow); } } break; case C_DESKTOP_TITLEBAR_ACTION_TOGGLE_STUCK: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_STUCK) meta_core_unstick (display, frame->xwindow); else meta_core_stick (display, frame->xwindow); } break; case C_DESKTOP_TITLEBAR_ACTION_TOGGLE_ABOVE: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ABOVE) meta_core_unmake_above (display, frame->xwindow); else meta_core_make_above (display, frame->xwindow); } break; case C_DESKTOP_TITLEBAR_ACTION_MINIMIZE: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ALLOWS_MINIMIZE) { meta_core_minimize (display, frame->xwindow); } } break; case C_DESKTOP_TITLEBAR_ACTION_NONE: /* Yaay, a sane user that doesn't use that other weird crap! */ break; case C_DESKTOP_TITLEBAR_ACTION_LOWER: meta_core_user_lower_and_unfocus (display, frame->xwindow, event->time); break; case C_DESKTOP_TITLEBAR_ACTION_MENU: meta_core_show_window_menu (display, frame->xwindow, event->x_root, event->y_root, event->button, event->time); break; /* These last 3 are CDesktopTitlebarScrollAction but since we're working with ints, it doesn't matter */ case C_DESKTOP_TITLEBAR_SCROLL_ACTION_SHADE: { meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ALLOWS_SHADE) { if (event->button == MOUSEWHEEL_DOWN && flags & META_FRAME_SHADED) meta_core_unshade (display, frame->xwindow, event->time); else if (event->button == MOUSEWHEEL_UP && flags & ~META_FRAME_SHADED) meta_core_shade (display, frame->xwindow, event->time); } } break; case C_DESKTOP_TITLEBAR_SCROLL_ACTION_OPACITY: { if (event->button == MOUSEWHEEL_UP) { meta_core_adjust_opacity (display, frame->xwindow, TRUE); /* TRUE = increase */ } else { meta_core_adjust_opacity (display, frame->xwindow, FALSE); /* decrease */ } } break; case C_DESKTOP_TITLEBAR_SCROLL_ACTION_NONE: break; } return TRUE; } static gboolean meta_frame_double_click_event (MetaUIFrame *frame, GdkEventButton *event) { int action = meta_prefs_get_action_double_click_titlebar (); return meta_frame_titlebar_event (frame, event, action); } static gboolean meta_frame_middle_click_event (MetaUIFrame *frame, GdkEventButton *event) { int action = meta_prefs_get_action_middle_click_titlebar(); return meta_frame_titlebar_event (frame, event, action); } static gboolean meta_frame_right_click_event(MetaUIFrame *frame, GdkEventButton *event) { int action = meta_prefs_get_action_right_click_titlebar(); return meta_frame_titlebar_event (frame, event, action); } static gboolean meta_frame_scroll_wheel_event (MetaUIFrame *frame, GdkEventButton *event) { int action = meta_prefs_get_action_scroll_wheel_titlebar(); return meta_frame_titlebar_event (frame, event, action); } static gboolean meta_frame_double_click_edge_event (MetaUIFrame *frame, GdkEventButton *event, MetaFrameControl control) { switch (control) { case META_FRAME_CONTROL_RESIZE_N: case META_FRAME_CONTROL_RESIZE_S: return meta_frame_titlebar_event (frame, event, C_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_VERTICALLY); case META_FRAME_CONTROL_RESIZE_E: case META_FRAME_CONTROL_RESIZE_W: return meta_frame_titlebar_event (frame, event, C_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_HORIZONTALLY); default: return FALSE; } } static gboolean meta_frames_button_press_event (GtkWidget *widget, GdkEventButton *event) { MetaUIFrame *frame; MetaFrames *frames; MetaFrameControl control; Display *display; frames = META_FRAMES (widget); display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); /* Remember that the display may have already done something with this event. * If so there's probably a GrabOp in effect. */ frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); if (frame == NULL) return FALSE; control = get_control (frames, frame, event->x, event->y); /* focus on click, even if click was on client area */ if (event->button == 1 && !(control == META_FRAME_CONTROL_MINIMIZE || control == META_FRAME_CONTROL_DELETE || control == META_FRAME_CONTROL_MAXIMIZE)) { meta_topic (META_DEBUG_FOCUS, "Focusing window with frame 0x%lx due to button 1 press\n", frame->xwindow); meta_core_user_focus (display, frame->xwindow, event->time); } /* don't do the rest of this if on client area */ if (control == META_FRAME_CONTROL_CLIENT_AREA) return FALSE; /* not on the frame, just passed through from client */ /* We want to shade even if we have a GrabOp, since we'll have a move grab * if we double click the titlebar. */ if (control == META_FRAME_CONTROL_TITLE && event->button == 1 && event->type == GDK_2BUTTON_PRESS) { meta_core_end_grab_op (display, event->time); return meta_frame_double_click_event (frame, event); } if (event->button == 1 && event->type == GDK_2BUTTON_PRESS && (control == META_FRAME_CONTROL_RESIZE_N || control == META_FRAME_CONTROL_RESIZE_S || control == META_FRAME_CONTROL_RESIZE_E || control == META_FRAME_CONTROL_RESIZE_W)) { meta_core_end_grab_op (display, event->time); return meta_frame_double_click_edge_event (frame, event, control); } if (meta_core_get_grab_op (display) != META_GRAB_OP_NONE) return FALSE; /* already up to something */ if (event->button == 1 && (control == META_FRAME_CONTROL_MAXIMIZE || control == META_FRAME_CONTROL_UNMAXIMIZE || control == META_FRAME_CONTROL_MINIMIZE || control == META_FRAME_CONTROL_DELETE || control == META_FRAME_CONTROL_SHADE || control == META_FRAME_CONTROL_UNSHADE || control == META_FRAME_CONTROL_ABOVE || control == META_FRAME_CONTROL_UNABOVE || control == META_FRAME_CONTROL_STICK || control == META_FRAME_CONTROL_UNSTICK || control == META_FRAME_CONTROL_MENU)) { MetaGrabOp op = META_GRAB_OP_NONE; switch (control) { case META_FRAME_CONTROL_MINIMIZE: op = META_GRAB_OP_CLICKING_MINIMIZE; break; case META_FRAME_CONTROL_MAXIMIZE: op = META_GRAB_OP_CLICKING_MAXIMIZE; break; case META_FRAME_CONTROL_UNMAXIMIZE: op = META_GRAB_OP_CLICKING_UNMAXIMIZE; break; case META_FRAME_CONTROL_DELETE: op = META_GRAB_OP_CLICKING_DELETE; break; case META_FRAME_CONTROL_MENU: op = META_GRAB_OP_CLICKING_MENU; break; case META_FRAME_CONTROL_SHADE: op = META_GRAB_OP_CLICKING_SHADE; break; case META_FRAME_CONTROL_UNSHADE: op = META_GRAB_OP_CLICKING_UNSHADE; break; case META_FRAME_CONTROL_ABOVE: op = META_GRAB_OP_CLICKING_ABOVE; break; case META_FRAME_CONTROL_UNABOVE: op = META_GRAB_OP_CLICKING_UNABOVE; break; case META_FRAME_CONTROL_STICK: op = META_GRAB_OP_CLICKING_STICK; break; case META_FRAME_CONTROL_UNSTICK: op = META_GRAB_OP_CLICKING_UNSTICK; break; default: g_assert_not_reached (); break; } meta_core_begin_grab_op (display, frame->xwindow, op, TRUE, TRUE, event->button, 0, event->time, event->x_root, event->y_root); frame->prelit_control = control; redraw_control (frames, frame, control); if (op == META_GRAB_OP_CLICKING_MENU) { MetaFrameGeometry fgeom; GdkRectangle *rect; int dx, dy; meta_frames_calc_geometry (frames, frame, &fgeom); rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom); /* get delta to convert to root coords */ dx = event->x_root - event->x; dy = event->y_root - event->y; /* Align to the right end of the menu rectangle if RTL */ if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) dx += rect->width; meta_core_show_window_menu (display, frame->xwindow, rect->x + dx, rect->y + rect->height + dy, event->button, event->time); } } else if (event->button == 1 && (control == META_FRAME_CONTROL_RESIZE_SE || control == META_FRAME_CONTROL_RESIZE_S || control == META_FRAME_CONTROL_RESIZE_SW || control == META_FRAME_CONTROL_RESIZE_NE || control == META_FRAME_CONTROL_RESIZE_N || control == META_FRAME_CONTROL_RESIZE_NW || control == META_FRAME_CONTROL_RESIZE_E || control == META_FRAME_CONTROL_RESIZE_W)) { MetaGrabOp op; op = META_GRAB_OP_NONE; switch (control) { case META_FRAME_CONTROL_RESIZE_SE: op = META_GRAB_OP_RESIZING_SE; break; case META_FRAME_CONTROL_RESIZE_S: op = META_GRAB_OP_RESIZING_S; break; case META_FRAME_CONTROL_RESIZE_SW: op = META_GRAB_OP_RESIZING_SW; break; case META_FRAME_CONTROL_RESIZE_NE: op = META_GRAB_OP_RESIZING_NE; break; case META_FRAME_CONTROL_RESIZE_N: op = META_GRAB_OP_RESIZING_N; break; case META_FRAME_CONTROL_RESIZE_NW: op = META_GRAB_OP_RESIZING_NW; break; case META_FRAME_CONTROL_RESIZE_E: op = META_GRAB_OP_RESIZING_E; break; case META_FRAME_CONTROL_RESIZE_W: op = META_GRAB_OP_RESIZING_W; break; default: g_assert_not_reached (); break; } meta_core_begin_grab_op (display, frame->xwindow, op, TRUE, TRUE, event->button, 0, event->time, event->x_root, event->y_root); } else if (control == META_FRAME_CONTROL_TITLE && event->button == 1) { MetaFrameFlags flags; meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_END); if (flags & META_FRAME_ALLOWS_MOVE) { meta_core_begin_grab_op (display, frame->xwindow, META_GRAB_OP_MOVING, TRUE, TRUE, event->button, 0, event->time, event->x_root, event->y_root); } } else if (control == META_FRAME_CONTROL_TITLE && (event->button == 4 || event->button == 5)) { return meta_frame_scroll_wheel_event (frame, event); } else if (event->button == 2) { return meta_frame_middle_click_event (frame, event); } else if (event->button == 3) { return meta_frame_right_click_event (frame, event); } return TRUE; } LOCAL_SYMBOL void meta_frames_notify_menu_hide (MetaFrames *frames) { Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); if (meta_core_get_grab_op (display) == META_GRAB_OP_CLICKING_MENU) { Window grab_frame; grab_frame = meta_core_get_grab_frame (display); if (grab_frame != None) { MetaUIFrame *frame; frame = meta_frames_lookup_window (frames, grab_frame); if (frame) { redraw_control (frames, frame, META_FRAME_CONTROL_MENU); meta_core_end_grab_op (display, CurrentTime); } } } } static gboolean meta_frames_button_release_event (GtkWidget *widget, GdkEventButton *event) { MetaUIFrame *frame; MetaFrames *frames; MetaGrabOp op; Display *display; frames = META_FRAMES (widget); display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); if (frame == NULL) return FALSE; op = meta_core_get_grab_op (display); if (op == META_GRAB_OP_NONE) return FALSE; /* We only handle the releases we handled the presses for (things * involving frame controls). Window ops that don't require a * frame are handled in the Xlib part of the code, display.c/window.c */ if (frame->xwindow == meta_core_get_grab_frame (display) && ((int) event->button) == meta_core_get_grab_button (display)) { MetaFrameControl control; control = get_control (frames, frame, event->x, event->y); switch (op) { case META_GRAB_OP_CLICKING_MINIMIZE: if (control == META_FRAME_CONTROL_MINIMIZE) meta_core_minimize (display, frame->xwindow); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_MAXIMIZE: if (control == META_FRAME_CONTROL_MAXIMIZE) { /* Focus the window on the maximize */ meta_core_user_focus (display, frame->xwindow, event->time); meta_core_maximize (display, frame->xwindow); } meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_UNMAXIMIZE: if (control == META_FRAME_CONTROL_UNMAXIMIZE) meta_core_unmaximize (display, frame->xwindow); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_DELETE: if (control == META_FRAME_CONTROL_DELETE) meta_core_delete (display, frame->xwindow, event->time); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_MENU: meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_SHADE: if (control == META_FRAME_CONTROL_SHADE) meta_core_shade (display, frame->xwindow, event->time); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_UNSHADE: if (control == META_FRAME_CONTROL_UNSHADE) meta_core_unshade (display, frame->xwindow, event->time); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_ABOVE: if (control == META_FRAME_CONTROL_ABOVE) meta_core_make_above (display, frame->xwindow); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_UNABOVE: if (control == META_FRAME_CONTROL_UNABOVE) meta_core_unmake_above (display, frame->xwindow); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_STICK: if (control == META_FRAME_CONTROL_STICK) meta_core_stick (display, frame->xwindow); meta_core_end_grab_op (display, event->time); break; case META_GRAB_OP_CLICKING_UNSTICK: if (control == META_FRAME_CONTROL_UNSTICK) meta_core_unstick (display, frame->xwindow); meta_core_end_grab_op (display, event->time); break; default: break; } /* Update the prelit control regardless of what button the mouse * was released over; needed so that the new button can become * prelit so to let the user know that it can now be pressed. * :) */ meta_frames_update_prelit_control (frames, frame, control); } return TRUE; } static void meta_frames_update_prelit_control (MetaFrames *frames, MetaUIFrame *frame, MetaFrameControl control) { MetaFrameControl old_control; MetaCursor cursor; meta_verbose ("Updating prelit control from %u to %u\n", frame->prelit_control, control); cursor = META_CURSOR_DEFAULT; switch (control) { case META_FRAME_CONTROL_CLIENT_AREA: break; case META_FRAME_CONTROL_NONE: break; case META_FRAME_CONTROL_TITLE: break; case META_FRAME_CONTROL_DELETE: break; case META_FRAME_CONTROL_MENU: break; case META_FRAME_CONTROL_MINIMIZE: break; case META_FRAME_CONTROL_MAXIMIZE: break; case META_FRAME_CONTROL_UNMAXIMIZE: break; case META_FRAME_CONTROL_SHADE: break; case META_FRAME_CONTROL_UNSHADE: break; case META_FRAME_CONTROL_ABOVE: break; case META_FRAME_CONTROL_UNABOVE: break; case META_FRAME_CONTROL_STICK: break; case META_FRAME_CONTROL_UNSTICK: break; case META_FRAME_CONTROL_RESIZE_SE: cursor = META_CURSOR_SE_RESIZE; break; case META_FRAME_CONTROL_RESIZE_S: cursor = META_CURSOR_SOUTH_RESIZE; break; case META_FRAME_CONTROL_RESIZE_SW: cursor = META_CURSOR_SW_RESIZE; break; case META_FRAME_CONTROL_RESIZE_N: cursor = META_CURSOR_NORTH_RESIZE; break; case META_FRAME_CONTROL_RESIZE_NE: cursor = META_CURSOR_NE_RESIZE; break; case META_FRAME_CONTROL_RESIZE_NW: cursor = META_CURSOR_NW_RESIZE; break; case META_FRAME_CONTROL_RESIZE_W: cursor = META_CURSOR_WEST_RESIZE; break; case META_FRAME_CONTROL_RESIZE_E: cursor = META_CURSOR_EAST_RESIZE; break; } /* set/unset the prelight cursor */ meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, cursor); switch (control) { case META_FRAME_CONTROL_MENU: case META_FRAME_CONTROL_MINIMIZE: case META_FRAME_CONTROL_MAXIMIZE: case META_FRAME_CONTROL_DELETE: case META_FRAME_CONTROL_SHADE: case META_FRAME_CONTROL_UNSHADE: case META_FRAME_CONTROL_ABOVE: case META_FRAME_CONTROL_UNABOVE: case META_FRAME_CONTROL_STICK: case META_FRAME_CONTROL_UNSTICK: case META_FRAME_CONTROL_UNMAXIMIZE: /* leave control set */ break; default: /* Only prelight buttons */ control = META_FRAME_CONTROL_NONE; break; } if (control == frame->prelit_control) return; /* Save the old control so we can unprelight it */ old_control = frame->prelit_control; frame->prelit_control = control; redraw_control (frames, frame, old_control); redraw_control (frames, frame, control); } static gboolean meta_frames_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) { MetaUIFrame *frame; MetaFrames *frames; MetaGrabOp grab_op; Display *display; frames = META_FRAMES (widget); display = GDK_DISPLAY_XDISPLAY (gdk_window_get_display (event->window)); frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); if (frame == NULL) return FALSE; frames->last_motion_frame = frame; grab_op = meta_core_get_grab_op (display); switch (grab_op) { case META_GRAB_OP_CLICKING_MENU: case META_GRAB_OP_CLICKING_DELETE: case META_GRAB_OP_CLICKING_MINIMIZE: case META_GRAB_OP_CLICKING_MAXIMIZE: case META_GRAB_OP_CLICKING_UNMAXIMIZE: case META_GRAB_OP_CLICKING_SHADE: case META_GRAB_OP_CLICKING_UNSHADE: case META_GRAB_OP_CLICKING_ABOVE: case META_GRAB_OP_CLICKING_UNABOVE: case META_GRAB_OP_CLICKING_STICK: case META_GRAB_OP_CLICKING_UNSTICK: { MetaFrameControl control; int x, y; gdk_window_get_device_position (frame->window, event->device, &x, &y, NULL); /* Control is set to none unless it matches * the current grab */ control = get_control (frames, frame, x, y); if (! ((control == META_FRAME_CONTROL_MENU && grab_op == META_GRAB_OP_CLICKING_MENU) || (control == META_FRAME_CONTROL_DELETE && grab_op == META_GRAB_OP_CLICKING_DELETE) || (control == META_FRAME_CONTROL_MINIMIZE && grab_op == META_GRAB_OP_CLICKING_MINIMIZE) || ((control == META_FRAME_CONTROL_MAXIMIZE || control == META_FRAME_CONTROL_UNMAXIMIZE) && (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE || grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)) || (control == META_FRAME_CONTROL_SHADE && grab_op == META_GRAB_OP_CLICKING_SHADE) || (control == META_FRAME_CONTROL_UNSHADE && grab_op == META_GRAB_OP_CLICKING_UNSHADE) || (control == META_FRAME_CONTROL_ABOVE && grab_op == META_GRAB_OP_CLICKING_ABOVE) || (control == META_FRAME_CONTROL_UNABOVE && grab_op == META_GRAB_OP_CLICKING_UNABOVE) || (control == META_FRAME_CONTROL_STICK && grab_op == META_GRAB_OP_CLICKING_STICK) || (control == META_FRAME_CONTROL_UNSTICK && grab_op == META_GRAB_OP_CLICKING_UNSTICK))) control = META_FRAME_CONTROL_NONE; /* Update prelit control and cursor */ meta_frames_update_prelit_control (frames, frame, control); } break; case META_GRAB_OP_NONE: { MetaFrameControl control; int x, y; gdk_window_get_device_position (frame->window, event->device, &x, &y, NULL); control = get_control (frames, frame, x, y); /* Update prelit control and cursor */ meta_frames_update_prelit_control (frames, frame, control); } break; default: break; } return TRUE; } static gboolean meta_frames_destroy_event (GtkWidget *widget, GdkEventAny *event) { MetaUIFrame *frame; MetaFrames *frames; frames = META_FRAMES (widget); frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); if (frame == NULL) return FALSE; return TRUE; } static void setup_bg_cr (cairo_t *cr, GdkWindow *window, int x_offset, int y_offset) { GdkWindow *parent = gdk_window_get_parent (window); cairo_pattern_t *bg_pattern; bg_pattern = gdk_window_get_background_pattern (window); if (bg_pattern == NULL && parent) { gint window_x, window_y; gdk_window_get_position (window, &window_x, &window_y); setup_bg_cr (cr, parent, x_offset + window_x, y_offset + window_y); } else if (bg_pattern) { cairo_translate (cr, - x_offset, - y_offset); cairo_set_source (cr, bg_pattern); cairo_translate (cr, x_offset, y_offset); } } /* Returns a pixmap with a piece of the windows frame painted on it. */ static cairo_surface_t * generate_pixmap (MetaFrames *frames, MetaUIFrame *frame, cairo_rectangle_int_t *rect) { cairo_surface_t *result; cairo_t *cr; /* do not create a pixmap for nonexisting areas */ if (rect->width <= 0 || rect->height <= 0) return NULL; result = gdk_window_create_similar_surface (frame->window, CAIRO_CONTENT_COLOR, rect->width, rect->height); cr = cairo_create (result); cairo_translate (cr, -rect->x, -rect->y); setup_bg_cr (cr, frame->window, 0, 0); cairo_paint (cr); meta_frames_paint (frames, frame, cr); cairo_destroy (cr); return result; } static void populate_cache (MetaFrames *frames, MetaUIFrame *frame) { MetaFrameBorders borders; int width, height; int frame_width, frame_height, screen_width, screen_height; CachedPixels *pixels; MetaFrameType frame_type; MetaFrameFlags frame_flags; int i; meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CORE_GET_FRAME_WIDTH, &frame_width, META_CORE_GET_FRAME_HEIGHT, &frame_height, META_CORE_GET_SCREEN_WIDTH, &screen_width, META_CORE_GET_SCREEN_HEIGHT, &screen_height, META_CORE_GET_CLIENT_WIDTH, &width, META_CORE_GET_CLIENT_HEIGHT, &height, META_CORE_GET_FRAME_TYPE, &frame_type, META_CORE_GET_FRAME_FLAGS, &frame_flags, META_CORE_GET_END); /* don't cache extremely large windows */ if (frame_width > 2 * screen_width || frame_height > 2 * screen_height) { return; } meta_theme_get_frame_borders (meta_theme_get_current (), frame_type, frame->text_height, frame_flags, &borders); pixels = get_cache (frames, frame); /* Setup the rectangles for the four visible frame borders. First top, then * left, right and bottom. Top and bottom extend to the invisible borders * while left and right snugly fit in between: * ----- * | | * ----- */ /* width and height refer to the client window's * size without any border added. */ /* top */ pixels->piece[0].rect.x = borders.invisible.left; pixels->piece[0].rect.y = borders.invisible.top; pixels->piece[0].rect.width = width + borders.visible.left + borders.visible.right; pixels->piece[0].rect.height = borders.visible.top; /* left */ pixels->piece[1].rect.x = borders.invisible.left; pixels->piece[1].rect.y = borders.total.top; pixels->piece[1].rect.height = height; pixels->piece[1].rect.width = borders.visible.left; /* right */ pixels->piece[2].rect.x = borders.total.left + width; pixels->piece[2].rect.y = borders.total.top; pixels->piece[2].rect.width = borders.visible.right; pixels->piece[2].rect.height = height; /* bottom */ pixels->piece[3].rect.x = borders.invisible.left; pixels->piece[3].rect.y = borders.total.top + height; pixels->piece[3].rect.width = width + borders.visible.left + borders.visible.right; pixels->piece[3].rect.height = borders.visible.bottom; for (i = 0; i < 4; i++) { CachedFramePiece *piece = &pixels->piece[i]; /* generate_pixmap() returns NULL for 0 width/height pieces, but * does so cheaply so we don't need to cache the NULL return */ if (!piece->pixmap) piece->pixmap = generate_pixmap (frames, frame, &piece->rect); } if (frames->invalidate_cache_timeout_id) { g_source_remove (frames->invalidate_cache_timeout_id); frames->invalidate_cache_timeout_id = 0; } frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames); if (!g_list_find (frames->invalidate_frames, frame)) frames->invalidate_frames = g_list_prepend (frames->invalidate_frames, frame); } static void clip_to_screen (cairo_region_t *region, MetaUIFrame *frame) { cairo_rectangle_int_t frame_area; cairo_rectangle_int_t screen_area = { 0, 0, 0, 0 }; cairo_region_t *tmp_region; /* Chop off stuff outside the screen; this optimization * is crucial to handle huge client windows, * like "xterm -geometry 1000x1000" */ meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CORE_GET_FRAME_X, &frame_area.x, META_CORE_GET_FRAME_Y, &frame_area.y, META_CORE_GET_FRAME_WIDTH, &frame_area.width, META_CORE_GET_FRAME_HEIGHT, &frame_area.height, META_CORE_GET_SCREEN_WIDTH, &screen_area.width, META_CORE_GET_SCREEN_HEIGHT, &screen_area.height, META_CORE_GET_END); cairo_region_translate (region, frame_area.x, frame_area.y); tmp_region = cairo_region_create_rectangle (&frame_area); cairo_region_intersect (region, tmp_region); cairo_region_destroy (tmp_region); tmp_region = cairo_region_create_rectangle (&screen_area); cairo_region_intersect (region, tmp_region); cairo_region_destroy (tmp_region); cairo_region_translate (region, - frame_area.x, - frame_area.y); } static void subtract_client_area (cairo_region_t *region, MetaUIFrame *frame) { cairo_rectangle_int_t area; MetaFrameFlags flags; MetaFrameType type; MetaFrameBorders borders; cairo_region_t *tmp_region; Display *display; display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_FRAME_TYPE, &type, META_CORE_GET_CLIENT_WIDTH, &area.width, META_CORE_GET_CLIENT_HEIGHT, &area.height, META_CORE_GET_END); meta_theme_get_frame_borders (meta_theme_get_current (), type, frame->text_height, flags, &borders); area.x = borders.total.left; area.y = borders.total.top; tmp_region = cairo_region_create_rectangle (&area); cairo_region_subtract (region, tmp_region); cairo_region_destroy (tmp_region); } static void cached_pixels_draw (CachedPixels *pixels, cairo_t *cr, cairo_region_t *region) { cairo_region_t *region_piece; int i; for (i = 0; i < 4; i++) { CachedFramePiece *piece; piece = &pixels->piece[i]; if (piece->pixmap) { cairo_set_source_surface (cr, piece->pixmap, piece->rect.x, piece->rect.y); cairo_paint (cr); region_piece = cairo_region_create_rectangle (&piece->rect); cairo_region_subtract (region, region_piece); cairo_region_destroy (region_piece); } } } static gboolean meta_frames_draw (GtkWidget *widget, cairo_t *cr) { MetaUIFrame *frame; MetaFrames *frames; CachedPixels *pixels; cairo_region_t *region; cairo_rectangle_int_t clip; int i, n_areas; cairo_surface_t *target; frames = META_FRAMES (widget); target = cairo_get_target (cr); gdk_cairo_get_clip_rectangle (cr, &clip); g_assert (cairo_surface_get_type (target) == CAIRO_SURFACE_TYPE_XLIB); frame = meta_frames_lookup_window (frames, cairo_xlib_surface_get_drawable (target)); if (frame == NULL) return FALSE; populate_cache (frames, frame); region = cairo_region_create_rectangle (&clip); pixels = get_cache (frames, frame); cached_pixels_draw (pixels, cr, region); clip_to_screen (region, frame); subtract_client_area (region, frame); n_areas = cairo_region_num_rectangles (region); for (i = 0; i < n_areas; i++) { cairo_rectangle_int_t area; cairo_region_get_rectangle (region, i, &area); cairo_save (cr); cairo_rectangle (cr, area.x, area.y, area.width, area.height); cairo_clip (cr); cairo_push_group (cr); meta_frames_paint (frames, frame, cr); cairo_pop_group_to_source (cr); cairo_paint (cr); cairo_restore (cr); } cairo_region_destroy (region); return TRUE; } static void meta_frames_paint (MetaFrames *frames, MetaUIFrame *frame, cairo_t *cr) { GtkWidget *widget; MetaFrameFlags flags; MetaFrameType type; int w, h; MetaButtonState button_states[META_BUTTON_TYPE_LAST]; Window grab_frame; int i; MetaButtonLayout button_layout; MetaGrabOp grab_op; Display *display; widget = GTK_WIDGET (frames); display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); for (i = 0; i < META_BUTTON_TYPE_LAST; i++) button_states[i] = META_BUTTON_STATE_NORMAL; grab_frame = meta_core_get_grab_frame (display); grab_op = meta_core_get_grab_op (display); if (grab_frame != frame->xwindow) grab_op = META_GRAB_OP_NONE; /* Set prelight state */ switch (frame->prelit_control) { case META_FRAME_CONTROL_MENU: if (grab_op == META_GRAB_OP_CLICKING_MENU) button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_MINIMIZE: if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE) button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_MAXIMIZE: if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE) button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_UNMAXIMIZE: if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE) button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_SHADE: if (grab_op == META_GRAB_OP_CLICKING_SHADE) button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_UNSHADE: if (grab_op == META_GRAB_OP_CLICKING_UNSHADE) button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_ABOVE: if (grab_op == META_GRAB_OP_CLICKING_ABOVE) button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_UNABOVE: if (grab_op == META_GRAB_OP_CLICKING_UNABOVE) button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_STICK: if (grab_op == META_GRAB_OP_CLICKING_STICK) button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_UNSTICK: if (grab_op == META_GRAB_OP_CLICKING_UNSTICK) button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT; break; case META_FRAME_CONTROL_DELETE: if (grab_op == META_GRAB_OP_CLICKING_DELETE) button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED; else button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT; break; default: break; } meta_core_get (display, frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_FRAME_TYPE, &type, META_CORE_GET_CLIENT_WIDTH, &w, META_CORE_GET_CLIENT_HEIGHT, &h, META_CORE_GET_END); meta_frames_ensure_layout (frames, frame); meta_prefs_get_button_layout (&button_layout); meta_theme_draw_frame_with_style (meta_theme_get_current (), frame->style, widget, cr, type, flags, w, h, frame->layout, frame->text_height, &button_layout, button_states); } static gboolean meta_frames_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event) { MetaUIFrame *frame; MetaFrames *frames; MetaFrameControl control; frames = META_FRAMES (widget); frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); if (frame == NULL) return FALSE; control = get_control (frames, frame, event->x, event->y); meta_frames_update_prelit_control (frames, frame, control); return TRUE; } static gboolean meta_frames_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) { MetaUIFrame *frame; MetaFrames *frames; frames = META_FRAMES (widget); frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); if (frame == NULL) return FALSE; meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE); return TRUE; } static GdkRectangle* control_rect (MetaFrameControl control, MetaFrameGeometry *fgeom) { GdkRectangle *rect; rect = NULL; switch (control) { case META_FRAME_CONTROL_TITLE: rect = &fgeom->title_rect; break; case META_FRAME_CONTROL_DELETE: rect = &fgeom->close_rect.visible; break; case META_FRAME_CONTROL_MENU: rect = &fgeom->menu_rect.visible; break; case META_FRAME_CONTROL_MINIMIZE: rect = &fgeom->min_rect.visible; break; case META_FRAME_CONTROL_MAXIMIZE: case META_FRAME_CONTROL_UNMAXIMIZE: rect = &fgeom->max_rect.visible; break; case META_FRAME_CONTROL_SHADE: rect = &fgeom->shade_rect.visible; break; case META_FRAME_CONTROL_UNSHADE: rect = &fgeom->unshade_rect.visible; break; case META_FRAME_CONTROL_ABOVE: rect = &fgeom->above_rect.visible; break; case META_FRAME_CONTROL_UNABOVE: rect = &fgeom->unabove_rect.visible; break; case META_FRAME_CONTROL_STICK: rect = &fgeom->stick_rect.visible; break; case META_FRAME_CONTROL_UNSTICK: rect = &fgeom->unstick_rect.visible; break; case META_FRAME_CONTROL_RESIZE_SE: break; case META_FRAME_CONTROL_RESIZE_S: break; case META_FRAME_CONTROL_RESIZE_SW: break; case META_FRAME_CONTROL_RESIZE_N: break; case META_FRAME_CONTROL_RESIZE_NE: break; case META_FRAME_CONTROL_RESIZE_NW: break; case META_FRAME_CONTROL_RESIZE_W: break; case META_FRAME_CONTROL_RESIZE_E: break; case META_FRAME_CONTROL_NONE: break; case META_FRAME_CONTROL_CLIENT_AREA: break; } return rect; } #define TOP_RESIZE_HEIGHT 4 #define CORNER_SIZE_MULT 2 static MetaFrameControl get_control (MetaFrames *frames, MetaUIFrame *frame, int x, int y) { MetaFrameGeometry fgeom; MetaFrameFlags flags; MetaFrameType type; MetaWindow *window; gboolean has_vert, has_horiz, has_left, has_right, has_bottom, has_top; gboolean has_north_resize; cairo_rectangle_int_t client; window = meta_core_get_window (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow); meta_frames_calc_geometry (frames, frame, &fgeom); get_client_rect (&fgeom, fgeom.width, fgeom.height, &client); if (META_POINT_IN_RECT (x, y, client)) return META_FRAME_CONTROL_CLIENT_AREA; if (META_POINT_IN_RECT (x, y, fgeom.close_rect.clickable)) return META_FRAME_CONTROL_DELETE; if (META_POINT_IN_RECT (x, y, fgeom.min_rect.clickable)) return META_FRAME_CONTROL_MINIMIZE; if (META_POINT_IN_RECT (x, y, fgeom.menu_rect.clickable)) return META_FRAME_CONTROL_MENU; meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, META_CORE_GET_FRAME_FLAGS, &flags, META_CORE_GET_FRAME_TYPE, &type, META_CORE_GET_END); has_north_resize = (type != META_FRAME_TYPE_ATTACHED); has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0; has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0; has_top = (flags & META_FRAME_ALLOWS_TOP_RESIZE) != 0; has_left = (flags & META_FRAME_ALLOWS_LEFT_RESIZE) != 0; has_right = (flags & META_FRAME_ALLOWS_RIGHT_RESIZE) != 0; has_bottom = (flags & META_FRAME_ALLOWS_BOTTOM_RESIZE) != 0; if (META_POINT_IN_RECT (x, y, fgeom.title_rect)) { if (has_vert && y <= TOP_RESIZE_HEIGHT && has_north_resize) return META_FRAME_CONTROL_RESIZE_N; else return META_FRAME_CONTROL_TITLE; } if (META_POINT_IN_RECT (x, y, fgeom.max_rect.clickable)) { if (flags & META_FRAME_MAXIMIZED && (META_WINDOW_TILED_TOP (window) || META_WINDOW_TILED_BOTTOM (window))) return META_FRAME_CONTROL_MAXIMIZE; if (flags & META_FRAME_MAXIMIZED) return META_FRAME_CONTROL_UNMAXIMIZE; else return META_FRAME_CONTROL_MAXIMIZE; } if (META_POINT_IN_RECT (x, y, fgeom.shade_rect.clickable)) { return META_FRAME_CONTROL_SHADE; } if (META_POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable)) { return META_FRAME_CONTROL_UNSHADE; } if (META_POINT_IN_RECT (x, y, fgeom.above_rect.clickable)) { return META_FRAME_CONTROL_ABOVE; } if (META_POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable)) { return META_FRAME_CONTROL_UNABOVE; } if (META_POINT_IN_RECT (x, y, fgeom.stick_rect.clickable)) { return META_FRAME_CONTROL_STICK; } if (META_POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable)) { return META_FRAME_CONTROL_UNSTICK; } /* South resize always has priority over north resize, * in case of overlap. */ if (y >= (fgeom.height - fgeom.borders.total.bottom * CORNER_SIZE_MULT) && x >= (fgeom.width - fgeom.borders.total.right * CORNER_SIZE_MULT)) { if ((has_vert && has_horiz) || (has_bottom && has_right)) return META_FRAME_CONTROL_RESIZE_SE; else if (has_bottom) return META_FRAME_CONTROL_RESIZE_S; else if (has_right) return META_FRAME_CONTROL_RESIZE_E; } else if (y >= (fgeom.height - fgeom.borders.total.bottom * CORNER_SIZE_MULT) && x <= fgeom.borders.total.left * CORNER_SIZE_MULT) { if ((has_vert && has_horiz) || (has_bottom && has_left)) return META_FRAME_CONTROL_RESIZE_SW; else if (has_bottom) return META_FRAME_CONTROL_RESIZE_S; else if (has_left) return META_FRAME_CONTROL_RESIZE_W; } else if (y < (fgeom.borders.invisible.top * CORNER_SIZE_MULT) && (x <= fgeom.borders.total.left * CORNER_SIZE_MULT) && has_north_resize) { if ((has_vert && has_horiz) || (has_top && has_left)) return META_FRAME_CONTROL_RESIZE_NW; else if (has_top) return META_FRAME_CONTROL_RESIZE_N; else if (has_left) return META_FRAME_CONTROL_RESIZE_W; } else if (y < (fgeom.borders.invisible.top * CORNER_SIZE_MULT) && x >= (fgeom.width - fgeom.borders.total.right * CORNER_SIZE_MULT) && has_north_resize) { if ((has_vert && has_horiz) || (has_top && has_right)) return META_FRAME_CONTROL_RESIZE_NE; else if (has_top) return META_FRAME_CONTROL_RESIZE_N; else if (has_right) return META_FRAME_CONTROL_RESIZE_E; } else if (y < (fgeom.borders.invisible.top + TOP_RESIZE_HEIGHT)) { if (has_top && has_north_resize) return META_FRAME_CONTROL_RESIZE_N; } else if (y >= (fgeom.height - fgeom.borders.total.bottom)) { if (has_bottom) return META_FRAME_CONTROL_RESIZE_S; } else if (x <= fgeom.borders.total.left) { if (has_left) return META_FRAME_CONTROL_RESIZE_W; } else if (x >= (fgeom.width - fgeom.borders.total.right)) { if (has_right) return META_FRAME_CONTROL_RESIZE_E; } if (y >= fgeom.borders.total.top) return META_FRAME_CONTROL_NONE; else return META_FRAME_CONTROL_TITLE; } static void invalidate_whole_window (MetaFrames *frames, MetaUIFrame *frame) { gdk_window_invalidate_rect (frame->window, NULL, FALSE); invalidate_cache (frames, frame); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/theme.c�������������������������������������������������������������������������0000664�0001750�0001750�00000625647�14211404421�015632� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity Theme Rendering */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ /** * SECTION:theme * @short_description: Making Metacity look pretty * * The window decorations drawn by Metacity are described by files on disk * known internally as "themes" (externally as "window border themes" on * http://art.gnome.org/themes/metacity/ or "Metacity themes"). This file * contains most of the code necessary to support themes; it does not * contain the XML parser, which is in theme-parser.c. * * \bug This is a big file with lots of different subsystems, which might * be better split out into separate files. */ /* * \defgroup tokenizer The theme expression tokenizer * * Themes can use a simple expression language to represent the values of * things. This is the tokeniser used for that language. * * \bug We could remove almost all this code by using GScanner instead, * but we would also have to find every expression in every existing theme * we could and make sure the parse trees were the same. */ /* * \defgroup parser The theme expression parser * * Themes can use a simple expression language to represent the values of * things. This is the parser used for that language. */ #include <config.h> #include "theme-private.h" #include "util-private.h" #include <meta/gradient.h> #include <meta/prefs.h> #include <gtk/gtk.h> #include <string.h> #include <stdlib.h> #include <math.h> #define GDK_COLOR_RGBA(color) \ ((guint32) (0xff | \ ((int)((color).red * 255) << 24) | \ ((int)((color).green * 255) << 16) | \ ((int)((color).blue * 255) << 8))) #define GDK_COLOR_RGB(color) \ ((guint32) (((int)((color).red * 255) << 16) | \ ((int)((color).green * 255) << 8) | \ ((int)((color).blue * 255)))) #define ALPHA_TO_UCHAR(d) ((unsigned char) ((d) * 255)) #define DEBUG_FILL_STRUCT(s) memset ((s), 0xef, sizeof (*(s))) #define CLAMP_UCHAR(v) ((guchar) (CLAMP (((int)v), (int)0, (int)255))) #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) static void gtk_style_shade (GdkRGBA *a, GdkRGBA *b, gdouble k); static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b); static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s); /* * The current theme. (Themes are singleton.) */ static MetaTheme *meta_current_theme = NULL; static GdkPixbuf * colorize_pixbuf (GdkPixbuf *orig, GdkRGBA *new_color) { GdkPixbuf *pixbuf; double intensity; int x, y; const guchar *src; guchar *dest; int orig_rowstride; int dest_rowstride; int width, height; gboolean has_alpha; const guchar *src_pixels; guchar *dest_pixels; pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig), gdk_pixbuf_get_bits_per_sample (orig), gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig)); if (pixbuf == NULL) return NULL; orig_rowstride = gdk_pixbuf_get_rowstride (orig); dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); has_alpha = gdk_pixbuf_get_has_alpha (orig); src_pixels = gdk_pixbuf_get_pixels (orig); dest_pixels = gdk_pixbuf_get_pixels (pixbuf); for (y = 0; y < height; y++) { src = src_pixels + y * orig_rowstride; dest = dest_pixels + y * dest_rowstride; for (x = 0; x < width; x++) { double dr, dg, db; intensity = INTENSITY (src[0], src[1], src[2]) / 255.0; if (intensity <= 0.5) { /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */ dr = new_color->red * intensity * 2.0; dg = new_color->green * intensity * 2.0; db = new_color->blue * intensity * 2.0; } else { /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */ dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0; dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0; db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0; } dest[0] = CLAMP_UCHAR (255 * dr); dest[1] = CLAMP_UCHAR (255 * dg); dest[2] = CLAMP_UCHAR (255 * db); if (has_alpha) { dest[3] = src[3]; src += 4; dest += 4; } else { src += 3; dest += 3; } } } return pixbuf; } static void color_composite (const GdkRGBA *bg, const GdkRGBA *fg, double alpha, GdkRGBA *color) { *color = *bg; color->red = color->red + (fg->red - color->red) * alpha; color->green = color->green + (fg->green - color->green) * alpha; color->blue = color->blue + (fg->blue - color->blue) * alpha; } /* * Sets all the fields of a border to dummy values. * * \param border The border whose fields should be reset. */ static void init_border (GtkBorder *border) { border->top = -1; border->bottom = -1; border->left = -1; border->right = -1; } /** * meta_frame_layout_new: (skip) * * Creates a new, empty MetaFrameLayout. The fields will be set to dummy * values. * * Returns: The newly created MetaFrameLayout. */ LOCAL_SYMBOL MetaFrameLayout* meta_frame_layout_new (void) { MetaFrameLayout *layout; layout = g_new0 (MetaFrameLayout, 1); layout->refcount = 1; /* Fill with -1 values to detect invalid themes */ layout->left_width = -1; layout->right_width = -1; layout->bottom_height = -1; init_border (&layout->title_border); layout->title_vertical_pad = -1; layout->right_titlebar_edge = -1; layout->left_titlebar_edge = -1; layout->button_sizing = META_BUTTON_SIZING_LAST; layout->button_aspect = 1.0; layout->button_width = -1; layout->button_height = -1; layout->has_title = TRUE; layout->title_scale = 1.0; init_border (&layout->button_border); return layout; } /* * */ static gboolean validate_border (const GtkBorder *border, const char **bad) { *bad = NULL; if (border->top < 0) *bad = _("top"); else if (border->bottom < 0) *bad = _("bottom"); else if (border->left < 0) *bad = _("left"); else if (border->right < 0) *bad = _("right"); return *bad == NULL; } /* * Ensures that the theme supplied a particular dimension. When a * MetaFrameLayout is created, all its integer fields are set to -1 * by meta_frame_layout_new(). After an instance of this type * should have been initialised, this function checks that * a given field is not still at -1. It is never called directly, but * rather via the CHECK_GEOMETRY_VALUE and CHECK_GEOMETRY_BORDER * macros. * * \param val The value to check * \param name The name to use in the error message * \param[out] error Set to an error if val was not initialised */ static gboolean validate_geometry_value (int val, const char *name, GError **error) { if (val < 0) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FRAME_GEOMETRY, _("frame geometry does not specify \"%s\" dimension"), name); return FALSE; } else return TRUE; } static gboolean validate_geometry_border (const GtkBorder *border, const char *name, GError **error) { const char *bad; if (!validate_border (border, &bad)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FRAME_GEOMETRY, _("frame geometry does not specify dimension \"%s\" for border \"%s\""), bad, name); return FALSE; } else return TRUE; } LOCAL_SYMBOL gboolean meta_frame_layout_validate (const MetaFrameLayout *layout, GError **error) { g_return_val_if_fail (layout != NULL, FALSE); #define CHECK_GEOMETRY_VALUE(vname) if (!validate_geometry_value (layout->vname, #vname, error)) return FALSE #define CHECK_GEOMETRY_BORDER(bname) if (!validate_geometry_border (&layout->bname, #bname, error)) return FALSE CHECK_GEOMETRY_VALUE (left_width); CHECK_GEOMETRY_VALUE (right_width); CHECK_GEOMETRY_VALUE (bottom_height); CHECK_GEOMETRY_BORDER (title_border); CHECK_GEOMETRY_VALUE (title_vertical_pad); CHECK_GEOMETRY_VALUE (right_titlebar_edge); CHECK_GEOMETRY_VALUE (left_titlebar_edge); switch (layout->button_sizing) { case META_BUTTON_SIZING_ASPECT: if (layout->button_aspect < (0.1) || layout->button_aspect > (15.0)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FRAME_GEOMETRY, _("Button aspect ratio %g is not reasonable"), layout->button_aspect); return FALSE; } break; case META_BUTTON_SIZING_FIXED: CHECK_GEOMETRY_VALUE (button_width); CHECK_GEOMETRY_VALUE (button_height); break; case META_BUTTON_SIZING_LAST: g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FRAME_GEOMETRY, _("Frame geometry does not specify size of buttons")); return FALSE; } CHECK_GEOMETRY_BORDER (button_border); return TRUE; } LOCAL_SYMBOL MetaFrameLayout* meta_frame_layout_copy (const MetaFrameLayout *src) { MetaFrameLayout *layout; layout = g_new0 (MetaFrameLayout, 1); *layout = *src; layout->refcount = 1; return layout; } LOCAL_SYMBOL void meta_frame_layout_ref (MetaFrameLayout *layout) { g_return_if_fail (layout != NULL); layout->refcount += 1; } LOCAL_SYMBOL void meta_frame_layout_unref (MetaFrameLayout *layout) { g_return_if_fail (layout != NULL); g_return_if_fail (layout->refcount > 0); layout->refcount -= 1; if (layout->refcount == 0) { DEBUG_FILL_STRUCT (layout); free (layout); } } LOCAL_SYMBOL void meta_frame_layout_get_borders (const MetaFrameLayout *layout, int text_height, MetaFrameFlags flags, MetaFrameType type, MetaFrameBorders *borders) { int buttons_height, title_height, draggable_borders; meta_frame_borders_clear (borders); /* For a full-screen window, we don't have any borders, visible or not. */ if (flags & META_FRAME_FULLSCREEN) return; g_return_if_fail (layout != NULL); if (!layout->has_title) text_height = 0; buttons_height = layout->button_height + layout->button_border.top + layout->button_border.bottom; title_height = text_height + layout->title_vertical_pad + layout->title_border.top + layout->title_border.bottom; borders->visible.top = MAX (buttons_height, title_height); borders->visible.left = layout->left_width; borders->visible.right = layout->right_width; borders->visible.bottom = layout->bottom_height; draggable_borders = meta_prefs_get_draggable_border_width (); if (flags & META_FRAME_ALLOWS_TOP_RESIZE) { if (type != META_FRAME_TYPE_ATTACHED) borders->invisible.top = MAX (0, draggable_borders - 2); } if (flags & META_FRAME_ALLOWS_BOTTOM_RESIZE) { borders->invisible.bottom = MAX (0, draggable_borders - borders->visible.bottom); } if (flags & META_FRAME_ALLOWS_LEFT_RESIZE) { borders->invisible.left = MAX (0, draggable_borders - borders->visible.left); } if (flags & META_FRAME_ALLOWS_RIGHT_RESIZE) { borders->invisible.right = MAX (0, draggable_borders - borders->visible.right); } borders->total.left = borders->invisible.left + borders->visible.left; borders->total.right = borders->invisible.right + borders->visible.right; borders->total.bottom = borders->invisible.bottom + borders->visible.bottom; borders->total.top = borders->invisible.top + borders->visible.top; } static MetaButtonType map_button_function_to_type (MetaButtonFunction function) { switch (function) { case META_BUTTON_FUNCTION_SHADE: return META_BUTTON_TYPE_SHADE; case META_BUTTON_FUNCTION_ABOVE: return META_BUTTON_TYPE_ABOVE; case META_BUTTON_FUNCTION_STICK: return META_BUTTON_TYPE_STICK; case META_BUTTON_FUNCTION_UNSHADE: return META_BUTTON_TYPE_UNSHADE; case META_BUTTON_FUNCTION_UNABOVE: return META_BUTTON_TYPE_UNABOVE; case META_BUTTON_FUNCTION_UNSTICK: return META_BUTTON_TYPE_UNSTICK; case META_BUTTON_FUNCTION_MENU: return META_BUTTON_TYPE_MENU; case META_BUTTON_FUNCTION_MINIMIZE: return META_BUTTON_TYPE_MINIMIZE; case META_BUTTON_FUNCTION_MAXIMIZE: return META_BUTTON_TYPE_MAXIMIZE; case META_BUTTON_FUNCTION_CLOSE: return META_BUTTON_TYPE_CLOSE; case META_BUTTON_FUNCTION_LAST: return META_BUTTON_TYPE_LAST; } return META_BUTTON_TYPE_LAST; } static MetaButtonSpace* rect_for_function (MetaFrameGeometry *fgeom, MetaFrameFlags flags, MetaButtonFunction function, MetaTheme *theme) { /* Firstly, check version-specific things. */ if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)) { switch (function) { case META_BUTTON_FUNCTION_SHADE: if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED)) return &fgeom->shade_rect; else return NULL; case META_BUTTON_FUNCTION_ABOVE: if (!(flags & META_FRAME_ABOVE)) return &fgeom->above_rect; else return NULL; case META_BUTTON_FUNCTION_STICK: if (!(flags & META_FRAME_STUCK)) return &fgeom->stick_rect; else return NULL; case META_BUTTON_FUNCTION_UNSHADE: if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED)) return &fgeom->unshade_rect; else return NULL; case META_BUTTON_FUNCTION_UNABOVE: if (flags & META_FRAME_ABOVE) return &fgeom->unabove_rect; else return NULL; case META_BUTTON_FUNCTION_UNSTICK: if (flags & META_FRAME_STUCK) return &fgeom->unstick_rect; default: /* just go on to the next switch block */; } } /* now consider the buttons which exist in all versions */ switch (function) { case META_BUTTON_FUNCTION_MENU: if (flags & META_FRAME_ALLOWS_MENU) return &fgeom->menu_rect; else return NULL; case META_BUTTON_FUNCTION_MINIMIZE: if (flags & META_FRAME_ALLOWS_MINIMIZE) return &fgeom->min_rect; else return NULL; case META_BUTTON_FUNCTION_MAXIMIZE: if (flags & META_FRAME_ALLOWS_MAXIMIZE) return &fgeom->max_rect; else return NULL; case META_BUTTON_FUNCTION_CLOSE: if (flags & META_FRAME_ALLOWS_DELETE) return &fgeom->close_rect; else return NULL; case META_BUTTON_FUNCTION_STICK: case META_BUTTON_FUNCTION_SHADE: case META_BUTTON_FUNCTION_ABOVE: case META_BUTTON_FUNCTION_UNSTICK: case META_BUTTON_FUNCTION_UNSHADE: case META_BUTTON_FUNCTION_UNABOVE: /* we are being asked for a >v1 button which hasn't been handled yet, * so obviously we're not in a theme which supports that version. * therefore, we don't show the button. return NULL and all will * be well. */ return NULL; case META_BUTTON_FUNCTION_LAST: return NULL; } return NULL; } static gboolean strip_button (MetaButtonSpace *func_rects[MAX_BUTTONS_PER_CORNER], GdkRectangle *bg_rects[MAX_BUTTONS_PER_CORNER], int *n_rects, MetaButtonSpace *to_strip) { int i; i = 0; while (i < *n_rects) { if (func_rects[i] == to_strip) { *n_rects -= 1; /* shift the other rects back in the array */ while (i < *n_rects) { func_rects[i] = func_rects[i+1]; bg_rects[i] = bg_rects[i+1]; ++i; } func_rects[i] = NULL; bg_rects[i] = NULL; return TRUE; } ++i; } return FALSE; /* did not strip anything */ } LOCAL_SYMBOL void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout, int text_height, MetaFrameFlags flags, int client_width, int client_height, const MetaButtonLayout *button_layout, MetaFrameType type, MetaFrameGeometry *fgeom, MetaTheme *theme) { int i, n_left, n_right, n_left_spacers, n_right_spacers; int x; int button_y; int title_right_edge; int width, height; int button_width, button_height; int min_size_for_rounding; /* the left/right rects in order; the max # of rects * is the number of button functions */ MetaButtonSpace *left_func_rects[MAX_BUTTONS_PER_CORNER]; MetaButtonSpace *right_func_rects[MAX_BUTTONS_PER_CORNER]; GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNER]; gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNER]; GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNER]; gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNER]; MetaFrameBorders borders; meta_frame_layout_get_borders (layout, text_height, flags, type, &borders); fgeom->borders = borders; width = client_width + borders.total.left + borders.total.right; height = ((flags & META_FRAME_SHADED) ? 0: client_height) + borders.total.top + borders.total.bottom; fgeom->width = width; fgeom->height = height; fgeom->top_titlebar_edge = layout->title_border.top; fgeom->bottom_titlebar_edge = layout->title_border.bottom; fgeom->left_titlebar_edge = layout->left_titlebar_edge; fgeom->right_titlebar_edge = layout->right_titlebar_edge; /* gcc warnings */ button_width = -1; button_height = -1; switch (layout->button_sizing) { case META_BUTTON_SIZING_ASPECT: button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom; button_width = button_height / layout->button_aspect; break; case META_BUTTON_SIZING_FIXED: button_width = layout->button_width; button_height = layout->button_height; break; case META_BUTTON_SIZING_LAST: g_assert_not_reached (); break; } /* FIXME all this code sort of pretends that duplicate buttons * with the same function are allowed, but that breaks the * code in frames.c, so isn't really allowed right now. * Would need left_close_rect, right_close_rect, etc. */ /* Init all button rects to 0, lame hack */ memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0', LENGTH_OF_BUTTON_RECTS); n_left = 0; n_right = 0; n_left_spacers = 0; n_right_spacers = 0; if (!layout->hide_buttons) { /* Try to fill in rects */ for (i = 0; i < MAX_BUTTONS_PER_CORNER && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++) { left_func_rects[n_left] = rect_for_function (fgeom, flags, button_layout->left_buttons[i], theme); if (left_func_rects[n_left] != NULL) { left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i]; if (button_layout->left_buttons_has_spacer[i]) ++n_left_spacers; ++n_left; } } for (i = 0; i < MAX_BUTTONS_PER_CORNER && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++) { right_func_rects[n_right] = rect_for_function (fgeom, flags, button_layout->right_buttons[i], theme); if (right_func_rects[n_right] != NULL) { right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i]; if (button_layout->right_buttons_has_spacer[i]) ++n_right_spacers; ++n_right; } } } for (i = 0; i < MAX_BUTTONS_PER_CORNER; i++) { left_bg_rects[i] = NULL; right_bg_rects[i] = NULL; } for (i = 0; i < n_left; i++) { if (n_left == 1) left_bg_rects[i] = &fgeom->left_single_background; else if (i == 0) left_bg_rects[i] = &fgeom->left_left_background; else if (i == (n_left - 1)) left_bg_rects[i] = &fgeom->left_right_background; else left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1]; } for (i = 0; i < n_right; i++) { if (n_right == 1) right_bg_rects[i] = &fgeom->right_single_background; else if (i == (n_right - 1)) right_bg_rects[i] = &fgeom->right_right_background; else if (i == 0) right_bg_rects[i] = &fgeom->right_left_background; else right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1]; } /* Be sure buttons fit */ while (n_left > 0 || n_right > 0) { int space_used_by_buttons; int space_available; space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge; space_used_by_buttons = 0; space_used_by_buttons += button_width * n_left; space_used_by_buttons += (button_width * 0.75) * n_left_spacers; space_used_by_buttons += layout->button_border.left * n_left; space_used_by_buttons += layout->button_border.right * n_left; space_used_by_buttons += button_width * n_right; space_used_by_buttons += (button_width * 0.75) * n_right_spacers; space_used_by_buttons += layout->button_border.left * n_right; space_used_by_buttons += layout->button_border.right * n_right; if (space_used_by_buttons <= space_available) break; /* Everything fits, bail out */ /* First try to remove separators */ if (n_left_spacers > 0) { left_buttons_has_spacer[--n_left_spacers] = FALSE; continue; } else if (n_right_spacers > 0) { right_buttons_has_spacer[--n_right_spacers] = FALSE; continue; } /* Otherwise we need to shave out a button. Shave * above, stick, shade, min, max, close, then menu (menu is most useful); * prefer the default button locations. */ if (strip_button (left_func_rects, left_bg_rects, &n_left, &fgeom->above_rect)) continue; else if (strip_button (right_func_rects, right_bg_rects, &n_right, &fgeom->above_rect)) continue; else if (strip_button (left_func_rects, left_bg_rects, &n_left, &fgeom->stick_rect)) continue; else if (strip_button (right_func_rects, right_bg_rects, &n_right, &fgeom->stick_rect)) continue; else if (strip_button (left_func_rects, left_bg_rects, &n_left, &fgeom->shade_rect)) continue; else if (strip_button (right_func_rects, right_bg_rects, &n_right, &fgeom->shade_rect)) continue; else if (strip_button (left_func_rects, left_bg_rects, &n_left, &fgeom->min_rect)) continue; else if (strip_button (right_func_rects, right_bg_rects, &n_right, &fgeom->min_rect)) continue; else if (strip_button (left_func_rects, left_bg_rects, &n_left, &fgeom->max_rect)) continue; else if (strip_button (right_func_rects, right_bg_rects, &n_right, &fgeom->max_rect)) continue; else if (strip_button (left_func_rects, left_bg_rects, &n_left, &fgeom->close_rect)) continue; else if (strip_button (right_func_rects, right_bg_rects, &n_right, &fgeom->close_rect)) continue; else if (strip_button (right_func_rects, right_bg_rects, &n_right, &fgeom->menu_rect)) continue; else if (strip_button (left_func_rects, left_bg_rects, &n_left, &fgeom->menu_rect)) continue; else { meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n", n_left, n_right); } } /* Save the button layout */ fgeom->button_layout = *button_layout; fgeom->n_left_buttons = n_left; fgeom->n_right_buttons = n_right; /* center buttons vertically */ button_y = (borders.visible.top - (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + borders.invisible.top; /* right edge of farthest-right button */ x = width - layout->right_titlebar_edge - borders.invisible.right; i = n_right - 1; while (i >= 0) { MetaButtonSpace *rect; if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */ break; rect = right_func_rects[i]; rect->visible.x = x - layout->button_border.right - button_width; if (right_buttons_has_spacer[i]) rect->visible.x -= (button_width * 0.75); rect->visible.y = button_y; rect->visible.width = button_width; rect->visible.height = button_height; if (flags & META_FRAME_MAXIMIZED || flags & META_FRAME_TILED_LEFT || flags & META_FRAME_TILED_RIGHT) { rect->clickable.x = rect->visible.x; rect->clickable.y = 0; rect->clickable.width = rect->visible.width; rect->clickable.height = button_height + button_y; if (i == n_right - 1) rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right; } else g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable)); *(right_bg_rects[i]) = rect->visible; x = rect->visible.x - layout->button_border.left; --i; } /* save right edge of titlebar for later use */ title_right_edge = x - layout->title_border.right; /* Now x changes to be position from the left and we go through * the left-side buttons */ x = layout->left_titlebar_edge + borders.invisible.left; for (i = 0; i < n_left; i++) { MetaButtonSpace *rect; rect = left_func_rects[i]; rect->visible.x = x + layout->button_border.left; rect->visible.y = button_y; rect->visible.width = button_width; rect->visible.height = button_height; if (flags & META_FRAME_MAXIMIZED) { if (i==0) { rect->clickable.x = 0; rect->clickable.width = button_width + x; } else { rect->clickable.x = rect->visible.x; rect->clickable.width = button_width; } rect->clickable.y = 0; rect->clickable.height = button_height + button_y; } else g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable)); x = rect->visible.x + rect->visible.width + layout->button_border.right; if (left_buttons_has_spacer[i]) x += (button_width * 0.75); *(left_bg_rects[i]) = rect->visible; } /* We always fill as much vertical space as possible with title rect, * rather than centering it like the buttons */ fgeom->title_rect.x = x + layout->title_border.left; fgeom->title_rect.y = layout->title_border.top + borders.invisible.top; fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x; fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom; /* Nuke title if it won't fit */ if (fgeom->title_rect.width < 0 || fgeom->title_rect.height < 0) { fgeom->title_rect.width = 0; fgeom->title_rect.height = 0; } if (flags & META_FRAME_SHADED) min_size_for_rounding = 0; else min_size_for_rounding = 5; fgeom->top_left_corner_rounded_radius = 0; fgeom->top_right_corner_rounded_radius = 0; fgeom->bottom_left_corner_rounded_radius = 0; fgeom->bottom_right_corner_rounded_radius = 0; if (borders.visible.top + borders.visible.left >= min_size_for_rounding) fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius; if (borders.visible.top + borders.visible.right >= min_size_for_rounding) fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius; if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding) fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius; if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding) fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius; } /** * meta_gradient_spec_new: (skip) * */ LOCAL_SYMBOL MetaGradientSpec* meta_gradient_spec_new (MetaGradientType type) { MetaGradientSpec *spec; spec = g_new (MetaGradientSpec, 1); spec->type = type; spec->color_specs = NULL; return spec; } static void free_color_spec (gpointer spec, gpointer user_data) { meta_color_spec_free (spec); } LOCAL_SYMBOL void meta_gradient_spec_free (MetaGradientSpec *spec) { g_return_if_fail (spec != NULL); g_slist_foreach (spec->color_specs, free_color_spec, NULL); g_slist_free (spec->color_specs); DEBUG_FILL_STRUCT (spec); free (spec); } LOCAL_SYMBOL GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *spec, GtkStyleContext *style, int width, int height) { int n_colors; GdkRGBA *colors; GSList *tmp; int i; GdkPixbuf *pixbuf; n_colors = g_slist_length (spec->color_specs); if (n_colors == 0) return NULL; colors = g_new (GdkRGBA, n_colors); i = 0; tmp = spec->color_specs; while (tmp != NULL) { meta_color_spec_render (tmp->data, style, &colors[i]); tmp = tmp->next; ++i; } pixbuf = meta_gradient_create_multi (width, height, colors, n_colors, spec->type); free (colors); return pixbuf; } LOCAL_SYMBOL gboolean meta_gradient_spec_validate (MetaGradientSpec *spec, GError **error) { g_return_val_if_fail (spec != NULL, FALSE); if (g_slist_length (spec->color_specs) < 2) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Gradients should have at least two colors")); return FALSE; } return TRUE; } /** * meta_alpha_gradient_spec_new: (skip) * */ LOCAL_SYMBOL LOCAL_SYMBOL MetaAlphaGradientSpec* meta_alpha_gradient_spec_new (MetaGradientType type, int n_alphas) { MetaAlphaGradientSpec *spec; g_return_val_if_fail (n_alphas > 0, NULL); spec = g_new0 (MetaAlphaGradientSpec, 1); spec->type = type; spec->alphas = g_new0 (unsigned char, n_alphas); spec->n_alphas = n_alphas; return spec; } LOCAL_SYMBOL void meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec) { g_return_if_fail (spec != NULL); free (spec->alphas); free (spec); } /** * meta_color_spec_new: (skip) * */ LOCAL_SYMBOL MetaColorSpec* meta_color_spec_new (MetaColorSpecType type) { MetaColorSpec *spec; MetaColorSpec dummy; int size; size = G_STRUCT_OFFSET (MetaColorSpec, data); switch (type) { case META_COLOR_SPEC_BASIC: size += sizeof (dummy.data.basic); break; case META_COLOR_SPEC_GTK: size += sizeof (dummy.data.gtk); break; case META_COLOR_SPEC_GTK_CUSTOM: size += sizeof (dummy.data.gtkcustom); break; case META_COLOR_SPEC_BLEND: size += sizeof (dummy.data.blend); break; case META_COLOR_SPEC_SHADE: size += sizeof (dummy.data.shade); break; } spec = calloc (1, size); spec->type = type; return spec; } LOCAL_SYMBOL void meta_color_spec_free (MetaColorSpec *spec) { g_return_if_fail (spec != NULL); switch (spec->type) { case META_COLOR_SPEC_BASIC: DEBUG_FILL_STRUCT (&spec->data.basic); break; case META_COLOR_SPEC_GTK: DEBUG_FILL_STRUCT (&spec->data.gtk); break; case META_COLOR_SPEC_GTK_CUSTOM: free (spec->data.gtkcustom.color_name); if (spec->data.gtkcustom.fallback) meta_color_spec_free (spec->data.gtkcustom.fallback); DEBUG_FILL_STRUCT (&spec->data.gtkcustom); break; case META_COLOR_SPEC_BLEND: if (spec->data.blend.foreground) meta_color_spec_free (spec->data.blend.foreground); if (spec->data.blend.background) meta_color_spec_free (spec->data.blend.background); DEBUG_FILL_STRUCT (&spec->data.blend); break; case META_COLOR_SPEC_SHADE: if (spec->data.shade.base) meta_color_spec_free (spec->data.shade.base); DEBUG_FILL_STRUCT (&spec->data.shade); break; } free (spec); } /** * meta_color_spec_new_from_string: (skip) * */ LOCAL_SYMBOL MetaColorSpec* meta_color_spec_new_from_string (const char *str, GError **err) { MetaColorSpec *spec; spec = NULL; if (str[0] == 'g' && str[1] == 't' && str[2] == 'k' && str[3] == ':' && str[4] == 'c' && str[5] == 'u' && str[6] == 's' && str[7] == 't' && str[8] == 'o' && str[9] == 'm') { const char *color_name_start, *fallback_str_start, *end; char *color_name; MetaColorSpec *fallback = NULL; static gboolean debug, debug_set = FALSE; if (!debug_set) { debug = g_getenv ("MUFFIN_DISABLE_FALLBACK_COLOR") != NULL; debug_set = TRUE; } if (str[10] != '(') { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\""), str); return NULL; } color_name_start = str + 11; fallback_str_start = color_name_start; while (*fallback_str_start && *fallback_str_start != ',') { if (!(g_ascii_isalnum (*fallback_str_start) || *fallback_str_start == '-' || *fallback_str_start == '_')) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid"), *fallback_str_start); return NULL; } fallback_str_start++; } fallback_str_start++; end = strrchr (str, ')'); if (color_name_start == NULL || fallback_str_start == NULL || end == NULL) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format"), str); return NULL; } if (!debug) { char *fallback_str; fallback_str = g_strndup (fallback_str_start, end - fallback_str_start); fallback = meta_color_spec_new_from_string (fallback_str, err); free (fallback_str); } else { fallback = meta_color_spec_new_from_string ("pink", err); } if (fallback == NULL) return NULL; color_name = g_strndup (color_name_start, fallback_str_start - color_name_start - 1); spec = meta_color_spec_new (META_COLOR_SPEC_GTK_CUSTOM); spec->data.gtkcustom.color_name = color_name; spec->data.gtkcustom.fallback = fallback; } else if (str[0] == 'g' && str[1] == 't' && str[2] == 'k' && str[3] == ':') { /* GTK color */ const char *bracket; const char *end_bracket; char *tmp; GtkStateFlags state; MetaGtkColorComponent component; bracket = str; while (*bracket && *bracket != '[') ++bracket; if (*bracket == '\0') { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""), str); return NULL; } end_bracket = bracket; ++end_bracket; while (*end_bracket && *end_bracket != ']') ++end_bracket; if (*end_bracket == '\0') { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""), str); return NULL; } tmp = g_strndup (bracket + 1, end_bracket - bracket - 1); state = meta_gtk_state_from_string (tmp); if (((int) state) == -1) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Did not understand state \"%s\" in color specification"), tmp); free (tmp); return NULL; } free (tmp); tmp = g_strndup (str + 4, bracket - str - 4); component = meta_color_component_from_string (tmp); if (component == META_GTK_COLOR_LAST) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Did not understand color component \"%s\" in color specification"), tmp); free (tmp); return NULL; } free (tmp); spec = meta_color_spec_new (META_COLOR_SPEC_GTK); spec->data.gtk.state = state; spec->data.gtk.component = component; g_assert (spec->data.gtk.component < META_GTK_COLOR_LAST); } else if (str[0] == 'b' && str[1] == 'l' && str[2] == 'e' && str[3] == 'n' && str[4] == 'd' && str[5] == '/') { /* blend */ char **split; double alpha; char *end; MetaColorSpec *fg; MetaColorSpec *bg; split = g_strsplit (str, "/", 4); if (split[0] == NULL || split[1] == NULL || split[2] == NULL || split[3] == NULL) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format"), str); g_strfreev (split); return NULL; } alpha = g_ascii_strtod (split[3], &end); if (end == split[3]) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Could not parse alpha value \"%s\" in blended color"), split[3]); g_strfreev (split); return NULL; } if (alpha < (0.0 - 1e6) || alpha > (1.0 + 1e6)) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Alpha value \"%s\" in blended color is not between 0.0 and 1.0"), split[3]); g_strfreev (split); return NULL; } fg = NULL; bg = NULL; bg = meta_color_spec_new_from_string (split[1], err); if (bg == NULL) { g_strfreev (split); return NULL; } fg = meta_color_spec_new_from_string (split[2], err); if (fg == NULL) { meta_color_spec_free (bg); g_strfreev (split); return NULL; } g_strfreev (split); spec = meta_color_spec_new (META_COLOR_SPEC_BLEND); spec->data.blend.alpha = alpha; spec->data.blend.background = bg; spec->data.blend.foreground = fg; } else if (str[0] == 's' && str[1] == 'h' && str[2] == 'a' && str[3] == 'd' && str[4] == 'e' && str[5] == '/') { /* shade */ char **split; double factor; char *end; MetaColorSpec *base; split = g_strsplit (str, "/", 3); if (split[0] == NULL || split[1] == NULL || split[2] == NULL) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"), str); g_strfreev (split); return NULL; } factor = g_ascii_strtod (split[2], &end); if (end == split[2]) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Could not parse shade factor \"%s\" in shaded color"), split[2]); g_strfreev (split); return NULL; } if (factor < (0.0 - 1e6)) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Shade factor \"%s\" in shaded color is negative"), split[2]); g_strfreev (split); return NULL; } base = NULL; base = meta_color_spec_new_from_string (split[1], err); if (base == NULL) { g_strfreev (split); return NULL; } g_strfreev (split); spec = meta_color_spec_new (META_COLOR_SPEC_SHADE); spec->data.shade.factor = factor; spec->data.shade.base = base; } else { spec = meta_color_spec_new (META_COLOR_SPEC_BASIC); if (!gdk_rgba_parse (&spec->data.basic.color, str)) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Could not parse color \"%s\""), str); meta_color_spec_free (spec); return NULL; } } g_assert (spec); return spec; } /** * meta_color_spec_new_gtk: (skip) * */ LOCAL_SYMBOL LOCAL_SYMBOL MetaColorSpec* meta_color_spec_new_gtk (MetaGtkColorComponent component, GtkStateFlags state) { MetaColorSpec *spec; spec = meta_color_spec_new (META_COLOR_SPEC_GTK); spec->data.gtk.component = component; spec->data.gtk.state = state; return spec; } static void get_background_color (GtkStyleContext *context, GtkStateFlags state, GdkRGBA *color) { gtk_style_context_get_background_color (context, state, color); GdkRGBA empty = {0.0, 0.0, 0.0, 0.0}; // Sometimes the widget has no background color, so append the background // class and ask again. if (gdk_rgba_equal(color, &empty)) { gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND); gtk_style_context_get_background_color (context, state, color); } } /* Based on set_color() in gtkstyle.c */ #define LIGHTNESS_MULT 1.3 #define DARKNESS_MULT 0.7 LOCAL_SYMBOL void meta_gtk_style_get_light_color (GtkStyleContext *style, GtkStateFlags state, GdkRGBA *color) { get_background_color (style, state, color); gtk_style_shade (color, color, LIGHTNESS_MULT); } LOCAL_SYMBOL void meta_gtk_style_get_dark_color (GtkStyleContext *style, GtkStateFlags state, GdkRGBA *color) { get_background_color (style, state, color); gtk_style_shade (color, color, DARKNESS_MULT); } static void meta_set_color_from_style (GdkRGBA *color, GtkStyleContext *context, GtkStateFlags state, MetaGtkColorComponent component) { GdkRGBA other; switch (component) { case META_GTK_COLOR_BG: case META_GTK_COLOR_BASE: get_background_color (context, state, color); break; case META_GTK_COLOR_FG: case META_GTK_COLOR_TEXT: gtk_style_context_get_color (context, state, color); break; case META_GTK_COLOR_TEXT_AA: gtk_style_context_get_color (context, state, color); meta_set_color_from_style (&other, context, state, META_GTK_COLOR_BASE); color->red = (color->red + other.red) / 2; color->green = (color->green + other.green) / 2; color->blue = (color->blue + other.blue) / 2; break; case META_GTK_COLOR_MID: meta_gtk_style_get_light_color (context, state, color); meta_gtk_style_get_dark_color (context, state, &other); color->red = (color->red + other.red) / 2; color->green = (color->green + other.green) / 2; color->blue = (color->blue + other.blue) / 2; break; case META_GTK_COLOR_LIGHT: meta_gtk_style_get_light_color (context, state, color); break; case META_GTK_COLOR_DARK: meta_gtk_style_get_dark_color (context, state, color); break; case META_GTK_COLOR_LAST: g_assert_not_reached (); break; } } static void meta_set_custom_color_from_style (GdkRGBA *color, GtkStyleContext *context, char *color_name, MetaColorSpec *fallback) { if (!gtk_style_context_lookup_color (context, color_name, color)) meta_color_spec_render (fallback, context, color); } LOCAL_SYMBOL void meta_color_spec_render (MetaColorSpec *spec, GtkStyleContext *context, GdkRGBA *color) { g_return_if_fail (spec != NULL); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); switch (spec->type) { case META_COLOR_SPEC_BASIC: *color = spec->data.basic.color; break; case META_COLOR_SPEC_GTK: meta_set_color_from_style (color, context, spec->data.gtk.state, spec->data.gtk.component); break; case META_COLOR_SPEC_GTK_CUSTOM: meta_set_custom_color_from_style (color, context, spec->data.gtkcustom.color_name, spec->data.gtkcustom.fallback); break; case META_COLOR_SPEC_BLEND: { GdkRGBA bg, fg; meta_color_spec_render (spec->data.blend.background, context, &bg); meta_color_spec_render (spec->data.blend.foreground, context, &fg); color_composite (&bg, &fg, spec->data.blend.alpha, &spec->data.blend.color); *color = spec->data.blend.color; } break; case META_COLOR_SPEC_SHADE: { meta_color_spec_render (spec->data.shade.base, context, &spec->data.shade.color); gtk_style_shade (&spec->data.shade.color, &spec->data.shade.color, spec->data.shade.factor); *color = spec->data.shade.color; } break; } } /* * Represents an operation as a string. * * \param type an operation, such as addition * \return a string, such as "+" */ static const char* op_name (PosOperatorType type) { switch (type) { case POS_OP_ADD: return "+"; case POS_OP_SUBTRACT: return "-"; case POS_OP_MULTIPLY: return "*"; case POS_OP_DIVIDE: return "/"; case POS_OP_MOD: return "%"; case POS_OP_MAX: return "`max`"; case POS_OP_MIN: return "`min`"; case POS_OP_NONE: break; } return "<unknown>"; } /* * Parses a string and returns an operation. * * \param p a pointer into a string representing an operation; part of an * expression somewhere, so not null-terminated * \param len set to the length of the string found. Set to 0 if none is. * \return the operation found. If none was, returns POS_OP_NONE. */ static PosOperatorType op_from_string (const char *p, int *len) { *len = 0; switch (*p) { case '+': *len = 1; return POS_OP_ADD; case '-': *len = 1; return POS_OP_SUBTRACT; case '*': *len = 1; return POS_OP_MULTIPLY; case '/': *len = 1; return POS_OP_DIVIDE; case '%': *len = 1; return POS_OP_MOD; case '`': if (p[0] == '`' && p[1] == 'm' && p[2] == 'a' && p[3] == 'x' && p[4] == '`') { *len = 5; return POS_OP_MAX; } else if (p[0] == '`' && p[1] == 'm' && p[2] == 'i' && p[3] == 'n' && p[4] == '`') { *len = 5; return POS_OP_MIN; } } return POS_OP_NONE; } /* * Frees an array of tokens. All the tokens and their associated memory * will be freed. * * \param tokens an array of tokens to be freed * \param n_tokens how many tokens are in the array. */ static void free_tokens (PosToken *tokens, int n_tokens) { int i; /* n_tokens can be 0 since tokens may have been allocated more than * it was initialized */ for (i = 0; i < n_tokens; i++) if (tokens[i].type == POS_TOKEN_VARIABLE) free (tokens[i].d.v.name); free (tokens); } /* * Tokenises a number in an expression. * * \param p a pointer into a string representing an operation; part of an * expression somewhere, so not null-terminated * \param end_return set to a pointer to the end of the number found; but * not updated if no number was found at all * \param next set to either an integer or a float token * \param[out] err set to the problem if there was a problem * \return TRUE if a valid number was found, FALSE otherwise (and "err" will * have been set) * * \bug The "while (*start)..." part: what's wrong with strchr-ish things? * \bug The name is wrong: it doesn't parse anything. * \ingroup tokenizer */ static gboolean parse_number (const char *p, const char **end_return, PosToken *next, GError **err) { const char *start = p; char *end; gboolean is_float; char *num_str; while (*p && (*p == '.' || g_ascii_isdigit (*p))) ++p; if (p == start) { char buf[7] = { '\0' }; buf[g_unichar_to_utf8 (g_utf8_get_char (p), buf)] = '\0'; g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_BAD_CHARACTER, _("Coordinate expression contains character '%s' which is not allowed"), buf); return FALSE; } *end_return = p; /* we need this to exclude floats like "1e6" */ num_str = g_strndup (start, p - start); start = num_str; is_float = FALSE; while (*start) { if (*start == '.') is_float = TRUE; ++start; } if (is_float) { next->type = POS_TOKEN_DOUBLE; next->d.d.val = g_ascii_strtod (num_str, &end); if (end == num_str) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression contains floating point number '%s' which could not be parsed"), num_str); free (num_str); return FALSE; } } else { next->type = POS_TOKEN_INT; next->d.i.val = strtol (num_str, &end, 10); if (end == num_str) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression contains integer '%s' which could not be parsed"), num_str); free (num_str); return FALSE; } } free (num_str); g_assert (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE); return TRUE; } /* * Whether a variable can validly appear as part of the name of a variable. */ #define IS_VARIABLE_CHAR(c) (g_ascii_isalpha ((c)) || (c) == '_') #if 0 static void debug_print_tokens (PosToken *tokens, int n_tokens) { int i; for (i = 0; i < n_tokens; i++) { PosToken *t = &tokens[i]; g_print (" "); switch (t->type) { case POS_TOKEN_INT: g_print ("\"%d\"", t->d.i.val); break; case POS_TOKEN_DOUBLE: g_print ("\"%g\"", t->d.d.val); break; case POS_TOKEN_OPEN_PAREN: g_print ("\"(\""); break; case POS_TOKEN_CLOSE_PAREN: g_print ("\")\""); break; case POS_TOKEN_VARIABLE: g_print ("\"%s\"", t->d.v.name); break; case POS_TOKEN_OPERATOR: g_print ("\"%s\"", op_name (t->d.o.op)); break; } } g_print ("\n"); } #endif /* * Tokenises an expression. * * \param expr The expression * \param[out] tokens_p The resulting tokens * \param[out] n_tokens_p The number of resulting tokens * \param[out] err set to the problem if there was a problem * * \return True if the expression was successfully tokenised; false otherwise. * * \ingroup tokenizer */ static gboolean pos_tokenize (const char *expr, PosToken **tokens_p, int *n_tokens_p, GError **err) { PosToken *tokens; int n_tokens; int allocated; const char *p; *tokens_p = NULL; *n_tokens_p = 0; allocated = 3; n_tokens = 0; tokens = g_new (PosToken, allocated); p = expr; while (*p) { PosToken *next; int len; if (n_tokens == allocated) { allocated *= 2; tokens = g_renew (PosToken, tokens, allocated); } next = &tokens[n_tokens]; switch (*p) { case '*': case '/': case '+': case '-': /* negative numbers aren't allowed so this is easy */ case '%': case '`': next->type = POS_TOKEN_OPERATOR; next->d.o.op = op_from_string (p, &len); if (next->d.o.op != POS_OP_NONE) { ++n_tokens; p = p + (len - 1); /* -1 since we ++p later */ } else { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression contained unknown operator at the start of this text: \"%s\""), p); goto error; } break; case '(': next->type = POS_TOKEN_OPEN_PAREN; ++n_tokens; break; case ')': next->type = POS_TOKEN_CLOSE_PAREN; ++n_tokens; break; case ' ': case '\t': case '\n': break; default: if (IS_VARIABLE_CHAR (*p)) { /* Assume variable */ const char *start = p; while (*p && IS_VARIABLE_CHAR (*p)) ++p; g_assert (p != start); next->type = POS_TOKEN_VARIABLE; next->d.v.name = g_strndup (start, p - start); ++n_tokens; --p; /* since we ++p again at the end of while loop */ } else { /* Assume number */ const char *end; if (!parse_number (p, &end, next, err)) goto error; ++n_tokens; p = end - 1; /* -1 since we ++p again at the end of while loop */ } break; } ++p; } if (n_tokens == 0) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression was empty or not understood")); goto error; } *tokens_p = tokens; *n_tokens_p = n_tokens; return TRUE; error: g_assert (err == NULL || *err != NULL); free_tokens (tokens, n_tokens); return FALSE; } /* * The type of a PosExpr: either integer, double, or an operation. * \ingroup parser */ typedef enum { POS_EXPR_INT, POS_EXPR_DOUBLE, POS_EXPR_OPERATOR } PosExprType; /* * Type and value of an expression in a parsed sequence. We don't * keep expressions in a tree; if this is of type POS_EXPR_OPERATOR, * the arguments of the operator will be in the array positions * immediately preceding and following this operator; they cannot * themselves be operators. * * \bug operator is char; it should really be of PosOperatorType. * \ingroup parser */ typedef struct { PosExprType type; union { double double_val; int int_val; char operator; } d; } PosExpr; #if 0 static void debug_print_exprs (PosExpr *exprs, int n_exprs) { int i; for (i = 0; i < n_exprs; i++) { switch (exprs[i].type) { case POS_EXPR_INT: g_print (" %d", exprs[i].d.int_val); break; case POS_EXPR_DOUBLE: g_print (" %g", exprs[i].d.double_val); break; case POS_EXPR_OPERATOR: g_print (" %s", op_name (exprs[i].d.operator)); break; } } g_print ("\n"); } #endif static gboolean do_operation (PosExpr *a, PosExpr *b, PosOperatorType op, GError **err) { /* Promote types to double if required */ if (a->type == POS_EXPR_DOUBLE || b->type == POS_EXPR_DOUBLE) { if (a->type != POS_EXPR_DOUBLE) { a->type = POS_EXPR_DOUBLE; a->d.double_val = a->d.int_val; } if (b->type != POS_EXPR_DOUBLE) { b->type = POS_EXPR_DOUBLE; b->d.double_val = b->d.int_val; } } g_assert (a->type == b->type); if (a->type == POS_EXPR_INT) { switch (op) { case POS_OP_MULTIPLY: a->d.int_val = a->d.int_val * b->d.int_val; break; case POS_OP_DIVIDE: if (b->d.int_val == 0) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_DIVIDE_BY_ZERO, _("Coordinate expression results in division by zero")); return FALSE; } a->d.int_val = a->d.int_val / b->d.int_val; break; case POS_OP_MOD: if (b->d.int_val == 0) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_DIVIDE_BY_ZERO, _("Coordinate expression results in division by zero")); return FALSE; } a->d.int_val = a->d.int_val % b->d.int_val; break; case POS_OP_ADD: a->d.int_val = a->d.int_val + b->d.int_val; break; case POS_OP_SUBTRACT: a->d.int_val = a->d.int_val - b->d.int_val; break; case POS_OP_MAX: a->d.int_val = MAX (a->d.int_val, b->d.int_val); break; case POS_OP_MIN: a->d.int_val = MIN (a->d.int_val, b->d.int_val); break; case POS_OP_NONE: g_assert_not_reached (); break; } } else if (a->type == POS_EXPR_DOUBLE) { switch (op) { case POS_OP_MULTIPLY: a->d.double_val = a->d.double_val * b->d.double_val; break; case POS_OP_DIVIDE: if (b->d.double_val == 0.0) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_DIVIDE_BY_ZERO, _("Coordinate expression results in division by zero")); return FALSE; } a->d.double_val = a->d.double_val / b->d.double_val; break; case POS_OP_MOD: g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_MOD_ON_FLOAT, _("Coordinate expression tries to use mod operator on a floating-point number")); return FALSE; case POS_OP_ADD: a->d.double_val = a->d.double_val + b->d.double_val; break; case POS_OP_SUBTRACT: a->d.double_val = a->d.double_val - b->d.double_val; break; case POS_OP_MAX: a->d.double_val = MAX (a->d.double_val, b->d.double_val); break; case POS_OP_MIN: a->d.double_val = MIN (a->d.double_val, b->d.double_val); break; case POS_OP_NONE: g_assert_not_reached (); break; } } else g_assert_not_reached (); return TRUE; } static gboolean do_operations (PosExpr *exprs, int *n_exprs, int precedence, GError **err) { int i; #if 0 g_print ("Doing prec %d ops on %d exprs\n", precedence, *n_exprs); debug_print_exprs (exprs, *n_exprs); #endif i = 1; while (i < *n_exprs) { gboolean compress; /* exprs[i-1] first operand * exprs[i] operator * exprs[i+1] second operand * * we replace first operand with result of mul/div/mod, * or skip over operator and second operand if we have * an add/subtract */ if (exprs[i-1].type == POS_EXPR_OPERATOR) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression has an operator \"%s\" where an operand was expected"), op_name (exprs[i-1].d.operator)); return FALSE; } if (exprs[i].type != POS_EXPR_OPERATOR) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression had an operand where an operator was expected")); return FALSE; } if (i == (*n_exprs - 1)) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression ended with an operator instead of an operand")); return FALSE; } g_assert ((i+1) < *n_exprs); if (exprs[i+1].type == POS_EXPR_OPERATOR) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between"), exprs[i+1].d.operator, exprs[i].d.operator); return FALSE; } compress = FALSE; switch (precedence) { case 2: switch (exprs[i].d.operator) { case POS_OP_DIVIDE: case POS_OP_MOD: case POS_OP_MULTIPLY: compress = TRUE; if (!do_operation (&exprs[i-1], &exprs[i+1], exprs[i].d.operator, err)) return FALSE; break; } break; case 1: switch (exprs[i].d.operator) { case POS_OP_ADD: case POS_OP_SUBTRACT: compress = TRUE; if (!do_operation (&exprs[i-1], &exprs[i+1], exprs[i].d.operator, err)) return FALSE; break; } break; /* I have no rationale at all for making these low-precedence */ case 0: switch (exprs[i].d.operator) { case POS_OP_MAX: case POS_OP_MIN: compress = TRUE; if (!do_operation (&exprs[i-1], &exprs[i+1], exprs[i].d.operator, err)) return FALSE; break; } break; } if (compress) { /* exprs[i-1] first operand (now result) * exprs[i] operator * exprs[i+1] second operand * exprs[i+2] new operator * * we move new operator just after first operand */ if ((i+2) < *n_exprs) { g_memmove (&exprs[i], &exprs[i+2], sizeof (PosExpr) * (*n_exprs - i - 2)); } *n_exprs -= 2; } else { /* Skip operator and next operand */ i += 2; } } return TRUE; } /* * There is a predefined set of variables which can appear in an expression. * Here we take a token representing a variable, and return the current value * of that variable in a particular environment. * (The value is always an integer.) * * There are supposedly some circumstances in which this function can be * called from outside Metacity, in which case env->theme will be NULL, and * therefore we can't use it to find out quark values, so we do the comparison * using strcmp, which is slower. * * \param t The token representing a variable * \param[out] result The value of that variable; not set if the token did * not represent a known variable * \param env The environment within which t should be evaluated * \param[out] err set to the problem if there was a problem * * \return true if we found the variable asked for, false if we didn't * * \bug shouldn't t be const? * \bug we should perhaps consider some sort of lookup arrangement into an * array; also, the duplication of code is unlovely; perhaps using glib * string hashes instead of quarks would fix both problems? * \ingroup parser */ static gboolean pos_eval_get_variable (PosToken *t, int *result, const MetaPositionExprEnv *env, GError **err) { if (env->theme) { if (t->d.v.name_quark == env->theme->quark_width) *result = env->rect.width; else if (t->d.v.name_quark == env->theme->quark_height) *result = env->rect.height; else if (env->object_width >= 0 && t->d.v.name_quark == env->theme->quark_object_width) *result = env->object_width; else if (env->object_height >= 0 && t->d.v.name_quark == env->theme->quark_object_height) *result = env->object_height; else if (t->d.v.name_quark == env->theme->quark_left_width) *result = env->left_width; else if (t->d.v.name_quark == env->theme->quark_right_width) *result = env->right_width; else if (t->d.v.name_quark == env->theme->quark_top_height) *result = env->top_height; else if (t->d.v.name_quark == env->theme->quark_bottom_height) *result = env->bottom_height; else if (t->d.v.name_quark == env->theme->quark_mini_icon_width) *result = env->mini_icon_width; else if (t->d.v.name_quark == env->theme->quark_mini_icon_height) *result = env->mini_icon_height; else if (t->d.v.name_quark == env->theme->quark_icon_width) *result = env->icon_width; else if (t->d.v.name_quark == env->theme->quark_icon_height) *result = env->icon_height; else if (t->d.v.name_quark == env->theme->quark_title_width) *result = env->title_width; else if (t->d.v.name_quark == env->theme->quark_title_height) *result = env->title_height; else if (t->d.v.name_quark == env->theme->quark_frame_x_center) *result = env->frame_x_center; else if (t->d.v.name_quark == env->theme->quark_frame_y_center) *result = env->frame_y_center; else { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_UNKNOWN_VARIABLE, _("Coordinate expression had unknown variable or constant \"%s\""), t->d.v.name); return FALSE; } } else { if (strcmp (t->d.v.name, "width") == 0) *result = env->rect.width; else if (strcmp (t->d.v.name, "height") == 0) *result = env->rect.height; else if (env->object_width >= 0 && strcmp (t->d.v.name, "object_width") == 0) *result = env->object_width; else if (env->object_height >= 0 && strcmp (t->d.v.name, "object_height") == 0) *result = env->object_height; else if (strcmp (t->d.v.name, "left_width") == 0) *result = env->left_width; else if (strcmp (t->d.v.name, "right_width") == 0) *result = env->right_width; else if (strcmp (t->d.v.name, "top_height") == 0) *result = env->top_height; else if (strcmp (t->d.v.name, "bottom_height") == 0) *result = env->bottom_height; else if (strcmp (t->d.v.name, "mini_icon_width") == 0) *result = env->mini_icon_width; else if (strcmp (t->d.v.name, "mini_icon_height") == 0) *result = env->mini_icon_height; else if (strcmp (t->d.v.name, "icon_width") == 0) *result = env->icon_width; else if (strcmp (t->d.v.name, "icon_height") == 0) *result = env->icon_height; else if (strcmp (t->d.v.name, "title_width") == 0) *result = env->title_width; else if (strcmp (t->d.v.name, "title_height") == 0) *result = env->title_height; else if (strcmp (t->d.v.name, "frame_x_center") == 0) *result = env->frame_x_center; else if (strcmp (t->d.v.name, "frame_y_center") == 0) *result = env->frame_y_center; else { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_UNKNOWN_VARIABLE, _("Coordinate expression had unknown variable or constant \"%s\""), t->d.v.name); return FALSE; } } return TRUE; } /* * Evaluates a sequence of tokens within a particular environment context, * and returns the current value. May recur if parantheses are found. * * \param tokens A list of tokens to evaluate. * \param n_tokens How many tokens are in the list. * \param env The environment context in which to evaluate the expression. * \param[out] result The current value of the expression * * \bug Yes, we really do reparse the expression every time it's evaluated. * We should keep the parse tree around all the time and just * run the new values through it. * \ingroup parser */ static gboolean pos_eval_helper (PosToken *tokens, int n_tokens, const MetaPositionExprEnv *env, PosExpr *result, GError **err) { /* Lazy-ass hardcoded limit on number of terms in expression */ #define MAX_EXPRS 32 int paren_level; int first_paren; int i; PosExpr exprs[MAX_EXPRS]; int n_exprs; int precedence; /* Our first goal is to get a list of PosExpr, essentially * substituting variables and handling parentheses. */ first_paren = 0; paren_level = 0; n_exprs = 0; for (i = 0; i < n_tokens; i++) { PosToken *t = &tokens[i]; if (n_exprs >= MAX_EXPRS) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression parser overflowed its buffer.")); return FALSE; } if (paren_level == 0) { switch (t->type) { case POS_TOKEN_INT: exprs[n_exprs].type = POS_EXPR_INT; exprs[n_exprs].d.int_val = t->d.i.val; ++n_exprs; break; case POS_TOKEN_DOUBLE: exprs[n_exprs].type = POS_EXPR_DOUBLE; exprs[n_exprs].d.double_val = t->d.d.val; ++n_exprs; break; case POS_TOKEN_OPEN_PAREN: ++paren_level; if (paren_level == 1) first_paren = i; break; case POS_TOKEN_CLOSE_PAREN: g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_BAD_PARENS, _("Coordinate expression had a close parenthesis with no open parenthesis")); return FALSE; case POS_TOKEN_VARIABLE: exprs[n_exprs].type = POS_EXPR_INT; /* FIXME we should just dump all this crap * in a hash, maybe keep width/height out * for optimization purposes */ if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err)) return FALSE; ++n_exprs; break; case POS_TOKEN_OPERATOR: exprs[n_exprs].type = POS_EXPR_OPERATOR; exprs[n_exprs].d.operator = t->d.o.op; ++n_exprs; break; } } else { g_assert (paren_level > 0); switch (t->type) { case POS_TOKEN_INT: case POS_TOKEN_DOUBLE: case POS_TOKEN_VARIABLE: case POS_TOKEN_OPERATOR: break; case POS_TOKEN_OPEN_PAREN: ++paren_level; break; case POS_TOKEN_CLOSE_PAREN: if (paren_level == 1) { /* We closed a toplevel paren group, so recurse */ if (!pos_eval_helper (&tokens[first_paren+1], i - first_paren - 1, env, &exprs[n_exprs], err)) return FALSE; ++n_exprs; } --paren_level; break; } } } if (paren_level > 0) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_BAD_PARENS, _("Coordinate expression had an open parenthesis with no close parenthesis")); return FALSE; } /* Now we have no parens and no vars; so we just do all the multiplies * and divides, then all the add and subtract. */ if (n_exprs == 0) { g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Coordinate expression doesn't seem to have any operators or operands")); return FALSE; } /* precedence 1 ops */ precedence = 2; while (precedence >= 0) { if (!do_operations (exprs, &n_exprs, precedence, err)) return FALSE; --precedence; } g_assert (n_exprs == 1); *result = *exprs; return TRUE; } /* * expr = int | double | expr * expr | expr / expr | * expr + expr | expr - expr | (expr) * * so very not worth fooling with bison, yet so very painful by hand. */ /* * Evaluates an expression. * * \param spec The expression to evaluate. * \param env The environment context to evaluate the expression in. * \param[out] val_p The integer value of the expression; if the expression * is of type float, this will be rounded. If we return * FALSE because the expression is invalid, this will be * zero. * \param[out] err The error, if anything went wrong. * * \return True if we evaluated the expression successfully; false otherwise. * * \bug Shouldn't spec be const? * \ingroup parser */ static gboolean pos_eval (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *val_p, GError **err) { PosExpr expr; *val_p = 0; if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err)) { switch (expr.type) { case POS_EXPR_INT: *val_p = expr.d.int_val; break; case POS_EXPR_DOUBLE: *val_p = expr.d.double_val; break; case POS_EXPR_OPERATOR: g_assert_not_reached (); break; } return TRUE; } else { return FALSE; } } /* We always return both X and Y, but only one will be meaningful in * most contexts. */ /** * meta_parse_position_expression: (skip) * */ LOCAL_SYMBOL gboolean meta_parse_position_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *x_return, int *y_return, GError **err) { /* All positions are in a coordinate system with x, y at the origin. * The expression can have -, +, *, / as operators, floating point * or integer constants, and the variables "width" and "height" and * optionally "object_width" and object_height". Negative numbers * aren't allowed. */ int val; if (spec->constant) val = spec->value; else { if (pos_eval (spec, env, &spec->value, err) == FALSE) { g_assert (err == NULL || *err != NULL); return FALSE; } val = spec->value; } if (x_return) *x_return = env->rect.x + val; if (y_return) *y_return = env->rect.y + val; return TRUE; } /** * meta_parse_size_expression: (skip) * */ LOCAL_SYMBOL gboolean meta_parse_size_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *val_return, GError **err) { int val; if (spec->constant) val = spec->value; else { if (pos_eval (spec, env, &spec->value, err) == FALSE) { g_assert (err == NULL || *err != NULL); return FALSE; } val = spec->value; } if (val_return) *val_return = MAX (val, 1); /* require that sizes be at least 1x1 */ return TRUE; } /* To do this we tokenize, replace variable tokens * that are constants, then reassemble. The purpose * here is to optimize expressions so we don't do hash * lookups to eval them. Obviously it's a tradeoff that * slows down theme load times. */ LOCAL_SYMBOL gboolean meta_theme_replace_constants (MetaTheme *theme, PosToken *tokens, int n_tokens, GError **err) { int i; double dval; int ival; gboolean is_constant = TRUE; /* Loop through tokenized string looking for variables to replace */ for (i = 0; i < n_tokens; i++) { PosToken *t = &tokens[i]; if (t->type == POS_TOKEN_VARIABLE) { if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival)) { free (t->d.v.name); t->type = POS_TOKEN_INT; t->d.i.val = ival; } else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval)) { free (t->d.v.name); t->type = POS_TOKEN_DOUBLE; t->d.d.val = dval; } else { /* If we've found a variable that cannot be replaced then the expression is not a constant expression and we want to replace it with a GQuark */ t->d.v.name_quark = g_quark_from_string (t->d.v.name); is_constant = FALSE; } } } return is_constant; } static int parse_x_position_unchecked (MetaDrawSpec *spec, const MetaPositionExprEnv *env) { int retval; GError *error; retval = 0; error = NULL; if (!meta_parse_position_expression (spec, env, &retval, NULL, &error)) { meta_warning (_("Theme contained an expression that resulted in an error: %s\n"), error->message); g_error_free (error); } return retval; } static int parse_y_position_unchecked (MetaDrawSpec *spec, const MetaPositionExprEnv *env) { int retval; GError *error; retval = 0; error = NULL; if (!meta_parse_position_expression (spec, env, NULL, &retval, &error)) { meta_warning (_("Theme contained an expression that resulted in an error: %s\n"), error->message); g_error_free (error); } return retval; } static int parse_size_unchecked (MetaDrawSpec *spec, MetaPositionExprEnv *env) { int retval; GError *error; retval = 0; error = NULL; if (!meta_parse_size_expression (spec, env, &retval, &error)) { meta_warning (_("Theme contained an expression that resulted in an error: %s\n"), error->message); g_error_free (error); } return retval; } LOCAL_SYMBOL void meta_draw_spec_free (MetaDrawSpec *spec) { if (!spec) return; free_tokens (spec->tokens, spec->n_tokens); g_slice_free (MetaDrawSpec, spec); } /** * meta_draw_spec_new: (skip) * */ LOCAL_SYMBOL MetaDrawSpec * meta_draw_spec_new (MetaTheme *theme, const char *expr, GError **error) { MetaDrawSpec *spec; spec = g_slice_new0 (MetaDrawSpec); pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL); spec->constant = meta_theme_replace_constants (theme, spec->tokens, spec->n_tokens, NULL); if (spec->constant) { gboolean result; result = pos_eval (spec, NULL, &spec->value, error); if (result == FALSE) { meta_draw_spec_free (spec); return NULL; } } return spec; } /** * meta_draw_op_new: (skip) * */ LOCAL_SYMBOL MetaDrawOp* meta_draw_op_new (MetaDrawType type) { MetaDrawOp *op; MetaDrawOp dummy; int size; size = G_STRUCT_OFFSET (MetaDrawOp, data); switch (type) { case META_DRAW_LINE: size += sizeof (dummy.data.line); break; case META_DRAW_RECTANGLE: size += sizeof (dummy.data.rectangle); break; case META_DRAW_ARC: size += sizeof (dummy.data.arc); break; case META_DRAW_CLIP: size += sizeof (dummy.data.clip); break; case META_DRAW_TINT: size += sizeof (dummy.data.tint); break; case META_DRAW_GRADIENT: size += sizeof (dummy.data.gradient); break; case META_DRAW_IMAGE: size += sizeof (dummy.data.image); break; case META_DRAW_GTK_ARROW: size += sizeof (dummy.data.gtk_arrow); break; case META_DRAW_GTK_BOX: size += sizeof (dummy.data.gtk_box); break; case META_DRAW_GTK_VLINE: size += sizeof (dummy.data.gtk_vline); break; case META_DRAW_ICON: size += sizeof (dummy.data.icon); break; case META_DRAW_TITLE: size += sizeof (dummy.data.title); break; case META_DRAW_OP_LIST: size += sizeof (dummy.data.op_list); break; case META_DRAW_TILE: size += sizeof (dummy.data.tile); break; } op = calloc (1, size); op->type = type; return op; } LOCAL_SYMBOL void meta_draw_op_free (MetaDrawOp *op) { g_return_if_fail (op != NULL); switch (op->type) { case META_DRAW_LINE: if (op->data.line.color_spec) meta_color_spec_free (op->data.line.color_spec); meta_draw_spec_free (op->data.line.x1); meta_draw_spec_free (op->data.line.y1); meta_draw_spec_free (op->data.line.x2); meta_draw_spec_free (op->data.line.y2); break; case META_DRAW_RECTANGLE: free (op->data.rectangle.color_spec); meta_draw_spec_free (op->data.rectangle.x); meta_draw_spec_free (op->data.rectangle.y); meta_draw_spec_free (op->data.rectangle.width); meta_draw_spec_free (op->data.rectangle.height); break; case META_DRAW_ARC: free (op->data.arc.color_spec); meta_draw_spec_free (op->data.arc.x); meta_draw_spec_free (op->data.arc.y); meta_draw_spec_free (op->data.arc.width); meta_draw_spec_free (op->data.arc.height); break; case META_DRAW_CLIP: meta_draw_spec_free (op->data.clip.x); meta_draw_spec_free (op->data.clip.y); meta_draw_spec_free (op->data.clip.width); meta_draw_spec_free (op->data.clip.height); break; case META_DRAW_TINT: if (op->data.tint.color_spec) meta_color_spec_free (op->data.tint.color_spec); if (op->data.tint.alpha_spec) meta_alpha_gradient_spec_free (op->data.tint.alpha_spec); meta_draw_spec_free (op->data.tint.x); meta_draw_spec_free (op->data.tint.y); meta_draw_spec_free (op->data.tint.width); meta_draw_spec_free (op->data.tint.height); break; case META_DRAW_GRADIENT: if (op->data.gradient.gradient_spec) meta_gradient_spec_free (op->data.gradient.gradient_spec); if (op->data.gradient.alpha_spec) meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec); meta_draw_spec_free (op->data.gradient.x); meta_draw_spec_free (op->data.gradient.y); meta_draw_spec_free (op->data.gradient.width); meta_draw_spec_free (op->data.gradient.height); break; case META_DRAW_IMAGE: if (op->data.image.alpha_spec) meta_alpha_gradient_spec_free (op->data.image.alpha_spec); if (op->data.image.pixbuf) g_object_unref (G_OBJECT (op->data.image.pixbuf)); if (op->data.image.colorize_spec) meta_color_spec_free (op->data.image.colorize_spec); if (op->data.image.colorize_cache_pixbuf) g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)); meta_draw_spec_free (op->data.image.x); meta_draw_spec_free (op->data.image.y); meta_draw_spec_free (op->data.image.width); meta_draw_spec_free (op->data.image.height); break; case META_DRAW_GTK_ARROW: meta_draw_spec_free (op->data.gtk_arrow.x); meta_draw_spec_free (op->data.gtk_arrow.y); meta_draw_spec_free (op->data.gtk_arrow.width); meta_draw_spec_free (op->data.gtk_arrow.height); break; case META_DRAW_GTK_BOX: meta_draw_spec_free (op->data.gtk_box.x); meta_draw_spec_free (op->data.gtk_box.y); meta_draw_spec_free (op->data.gtk_box.width); meta_draw_spec_free (op->data.gtk_box.height); break; case META_DRAW_GTK_VLINE: meta_draw_spec_free (op->data.gtk_vline.x); meta_draw_spec_free (op->data.gtk_vline.y1); meta_draw_spec_free (op->data.gtk_vline.y2); break; case META_DRAW_ICON: if (op->data.icon.alpha_spec) meta_alpha_gradient_spec_free (op->data.icon.alpha_spec); meta_draw_spec_free (op->data.icon.x); meta_draw_spec_free (op->data.icon.y); meta_draw_spec_free (op->data.icon.width); meta_draw_spec_free (op->data.icon.height); break; case META_DRAW_TITLE: if (op->data.title.color_spec) meta_color_spec_free (op->data.title.color_spec); meta_draw_spec_free (op->data.title.x); meta_draw_spec_free (op->data.title.y); if (op->data.title.ellipsize_width) meta_draw_spec_free (op->data.title.ellipsize_width); break; case META_DRAW_OP_LIST: if (op->data.op_list.op_list) meta_draw_op_list_unref (op->data.op_list.op_list); meta_draw_spec_free (op->data.op_list.x); meta_draw_spec_free (op->data.op_list.y); meta_draw_spec_free (op->data.op_list.width); meta_draw_spec_free (op->data.op_list.height); break; case META_DRAW_TILE: if (op->data.tile.op_list) meta_draw_op_list_unref (op->data.tile.op_list); meta_draw_spec_free (op->data.tile.x); meta_draw_spec_free (op->data.tile.y); meta_draw_spec_free (op->data.tile.width); meta_draw_spec_free (op->data.tile.height); meta_draw_spec_free (op->data.tile.tile_xoffset); meta_draw_spec_free (op->data.tile.tile_yoffset); meta_draw_spec_free (op->data.tile.tile_width); meta_draw_spec_free (op->data.tile.tile_height); break; } free (op); } static GdkPixbuf* apply_alpha (GdkPixbuf *pixbuf, MetaAlphaGradientSpec *spec, gboolean force_copy) { GdkPixbuf *new_pixbuf; gboolean needs_alpha; g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); needs_alpha = spec && (spec->n_alphas > 1 || spec->alphas[0] != 0xff); if (!needs_alpha) return pixbuf; if (!gdk_pixbuf_get_has_alpha (pixbuf)) { new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); g_object_unref (G_OBJECT (pixbuf)); pixbuf = new_pixbuf; } else if (force_copy) { new_pixbuf = gdk_pixbuf_copy (pixbuf); g_object_unref (G_OBJECT (pixbuf)); pixbuf = new_pixbuf; } g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type); return pixbuf; } static GdkPixbuf* pixbuf_tile (GdkPixbuf *tile, int width, int height) { GdkPixbuf *pixbuf; int tile_width; int tile_height; int i, j; tile_width = gdk_pixbuf_get_width (tile); tile_height = gdk_pixbuf_get_height (tile); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha (tile), 8, width, height); i = 0; while (i < width) { j = 0; while (j < height) { int w, h; w = MIN (tile_width, width - i); h = MIN (tile_height, height - j); gdk_pixbuf_copy_area (tile, 0, 0, w, h, pixbuf, i, j); j += tile_height; } i += tile_width; } return pixbuf; } static GdkPixbuf * replicate_rows (GdkPixbuf *src, int src_x, int src_y, int width, int height) { unsigned int n_channels = gdk_pixbuf_get_n_channels (src); unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src); unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels); unsigned char *dest_pixels; GdkPixbuf *result; unsigned int dest_rowstride; int i; result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width); return result; } static GdkPixbuf * replicate_cols (GdkPixbuf *src, int src_x, int src_y, int width, int height) { unsigned int n_channels = gdk_pixbuf_get_n_channels (src); unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src); unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels); unsigned char *dest_pixels; GdkPixbuf *result; unsigned int dest_rowstride; int i, j; result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8, width, height); dest_rowstride = gdk_pixbuf_get_rowstride (result); dest_pixels = gdk_pixbuf_get_pixels (result); for (i = 0; i < height; i++) { unsigned char *p = dest_pixels + dest_rowstride * i; unsigned char *q = pixels + src_rowstride * i; unsigned char r = *(q++); unsigned char g = *(q++); unsigned char b = *(q++); if (n_channels == 4) { unsigned char a; a = *(q++); for (j = 0; j < width; j++) { *(p++) = r; *(p++) = g; *(p++) = b; *(p++) = a; } } else { for (j = 0; j < width; j++) { *(p++) = r; *(p++) = g; *(p++) = b; } } } return result; } /* gdk_pixbuf_scale_simple doesn't do too well with scaling a pixel or two up or down, you end up with a blurry icon. Avoid scaling the icon if the scaled size difference is within our arbitrary tolerance. This isn't perfect.. if you use a crazy-sized window title font, your icons still may end up less than ideal, but for most users, this will solve things. It would be more effective to avoid scaling at all, and load the image from a file directly here (especially with SVG images,) but images are used in some themes to construct frames and I don't want to affect that. There are also unknown performance implications to loading here every time a window is added) */ #define PIXBUF_SIZE_TOLERANCE 2 static gboolean in_tolerance_to (gint size, gint scale_size) { return scale_size <= size + PIXBUF_SIZE_TOLERANCE && scale_size >= size - PIXBUF_SIZE_TOLERANCE; } static GdkPixbuf* scale_and_alpha_pixbuf (GdkPixbuf *src, MetaAlphaGradientSpec *alpha_spec, MetaImageFillType fill_type, int width, int height, gboolean vertical_stripes, gboolean horizontal_stripes) { GdkPixbuf *pixbuf; GdkPixbuf *temp_pixbuf; pixbuf = NULL; pixbuf = src; if (gdk_pixbuf_get_width (pixbuf) == width && gdk_pixbuf_get_height (pixbuf) == height) { g_object_ref (G_OBJECT (pixbuf)); } else { if (fill_type == META_IMAGE_FILL_TILE) { pixbuf = pixbuf_tile (pixbuf, width, height); } else { int src_h, src_w, dest_h, dest_w; src_h = gdk_pixbuf_get_height (src); src_w = gdk_pixbuf_get_width (src); /* prefer to replicate_cols if possible, as that * is faster (no memory reads) */ if (horizontal_stripes) { dest_w = gdk_pixbuf_get_width (src); dest_h = height; } else if (vertical_stripes) { dest_w = width; dest_h = gdk_pixbuf_get_height (src); } else { dest_w = width; dest_h = height; } if (in_tolerance_to (src_w, dest_w) && in_tolerance_to (src_h, dest_h)) { temp_pixbuf = src; g_object_ref (G_OBJECT (temp_pixbuf)); } else { temp_pixbuf = gdk_pixbuf_scale_simple (src, dest_w, dest_h, GDK_INTERP_BILINEAR); } /* prefer to replicate_cols if possible, as that * is faster (no memory reads) */ if (horizontal_stripes) { pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height); g_object_unref (G_OBJECT (temp_pixbuf)); } else if (vertical_stripes) { pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height); g_object_unref (G_OBJECT (temp_pixbuf)); } else { pixbuf = temp_pixbuf; } } } if (pixbuf) pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src); return pixbuf; } static GdkPixbuf* draw_op_as_pixbuf (const MetaDrawOp *op, GtkStyleContext *context, const MetaDrawInfo *info, int width, int height) { /* Try to get the op as a pixbuf, assuming w/h in the op * matches the width/height passed in. return NULL * if the op can't be converted to an equivalent pixbuf. */ GdkPixbuf *pixbuf; pixbuf = NULL; switch (op->type) { case META_DRAW_LINE: break; case META_DRAW_RECTANGLE: if (op->data.rectangle.filled) { GdkRGBA color; meta_color_spec_render (op->data.rectangle.color_spec, context, &color); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); gdk_pixbuf_fill (pixbuf, GDK_COLOR_RGBA (color)); } break; case META_DRAW_ARC: break; case META_DRAW_CLIP: break; case META_DRAW_TINT: { GdkRGBA color; guint32 rgba; gboolean has_alpha; meta_color_spec_render (op->data.rectangle.color_spec, context, &color); has_alpha = op->data.tint.alpha_spec && (op->data.tint.alpha_spec->n_alphas > 1 || op->data.tint.alpha_spec->alphas[0] != 0xff); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8, width, height); if (!has_alpha) { rgba = GDK_COLOR_RGBA (color); gdk_pixbuf_fill (pixbuf, rgba); } else if (op->data.tint.alpha_spec->n_alphas == 1) { rgba = GDK_COLOR_RGBA (color); rgba &= ~0xff; rgba |= op->data.tint.alpha_spec->alphas[0]; gdk_pixbuf_fill (pixbuf, rgba); } else { rgba = GDK_COLOR_RGBA (color); gdk_pixbuf_fill (pixbuf, rgba); meta_gradient_add_alpha (pixbuf, op->data.tint.alpha_spec->alphas, op->data.tint.alpha_spec->n_alphas, op->data.tint.alpha_spec->type); } } break; case META_DRAW_GRADIENT: { pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec, context, width, height); pixbuf = apply_alpha (pixbuf, op->data.gradient.alpha_spec, FALSE); } break; case META_DRAW_IMAGE: { if (op->data.image.colorize_spec) { GdkRGBA color; meta_color_spec_render (op->data.image.colorize_spec, context, &color); if (op->data.image.colorize_cache_pixbuf == NULL || op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)) { if (op->data.image.colorize_cache_pixbuf) g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)); /* const cast here */ ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf = colorize_pixbuf (op->data.image.pixbuf, &color); ((MetaDrawOp*)op)->data.image.colorize_cache_pixel = GDK_COLOR_RGB (color); } if (op->data.image.colorize_cache_pixbuf) { pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf, op->data.image.alpha_spec, op->data.image.fill_type, width, height, op->data.image.vertical_stripes, op->data.image.horizontal_stripes); } } else { pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf, op->data.image.alpha_spec, op->data.image.fill_type, width, height, op->data.image.vertical_stripes, op->data.image.horizontal_stripes); } break; } case META_DRAW_GTK_ARROW: case META_DRAW_GTK_BOX: case META_DRAW_GTK_VLINE: break; case META_DRAW_ICON: break; case META_DRAW_TITLE: break; case META_DRAW_OP_LIST: break; case META_DRAW_TILE: break; } return pixbuf; } static void fill_env (MetaPositionExprEnv *env, const MetaDrawInfo *info, MetaRectangle logical_region) { /* FIXME this stuff could be raised into draw_op_list_draw() probably */ env->rect = logical_region; env->object_width = -1; env->object_height = -1; if (info->fgeom) { env->left_width = info->fgeom->borders.visible.left; env->right_width = info->fgeom->borders.visible.right; env->top_height = info->fgeom->borders.visible.top; env->bottom_height = info->fgeom->borders.visible.bottom; env->frame_x_center = info->fgeom->width / 2 - logical_region.x; env->frame_y_center = info->fgeom->height / 2 - logical_region.y; } else { env->left_width = 0; env->right_width = 0; env->top_height = 0; env->bottom_height = 0; env->frame_x_center = 0; env->frame_y_center = 0; } #define META_ICON_WIDTH 32 #define META_ICON_HEIGHT 32 #define META_MINI_ICON_WIDTH 16 #define META_MINI_ICON_HEIGHT 16 env->mini_icon_width = META_MINI_ICON_WIDTH; env->mini_icon_height = META_MINI_ICON_HEIGHT; env->icon_width = META_ICON_WIDTH; env->icon_height = META_ICON_HEIGHT; env->title_width = info->title_layout_width; env->title_height = info->title_layout_height; env->theme = meta_current_theme; } /* This code was originally rendering anti-aliased using X primitives, and * now has been switched to draw anti-aliased using cairo. In general, the * closest correspondence between X rendering and cairo rendering is given * by offsetting the geometry by 0.5 pixels in both directions before rendering * with cairo. This is because X samples at the upper left corner of the * pixel while cairo averages over the entire pixel. However, in the cases * where the X rendering was an exact rectangle with no "jaggies" * we need to be a bit careful about applying the offset. We want to produce * the exact same pixel-aligned rectangle, rather than a rectangle with * fuzz around the edges. */ static void meta_draw_op_draw_with_env (const MetaDrawOp *op, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, MetaRectangle rect, MetaPositionExprEnv *env) { GdkRGBA color; cairo_save (cr); gtk_style_context_save (style_gtk); cairo_set_line_width (cr, 1.0); switch (op->type) { case META_DRAW_LINE: { int x1, x2, y1, y2; meta_color_spec_render (op->data.line.color_spec, style_gtk, &color); gdk_cairo_set_source_rgba (cr, &color); if (op->data.line.width > 0) cairo_set_line_width (cr, op->data.line.width); if (op->data.line.dash_on_length > 0 && op->data.line.dash_off_length > 0) { double dash_list[2]; dash_list[0] = op->data.line.dash_on_length; dash_list[1] = op->data.line.dash_off_length; cairo_set_dash (cr, dash_list, 2, 0); } x1 = parse_x_position_unchecked (op->data.line.x1, env); y1 = parse_y_position_unchecked (op->data.line.y1, env); if (!op->data.line.x2 && !op->data.line.y2 && op->data.line.width==0) { cairo_rectangle (cr, x1, y1, 1, 1); cairo_fill (cr); } else { if (op->data.line.x2) x2 = parse_x_position_unchecked (op->data.line.x2, env); else x2 = x1; if (op->data.line.y2) y2 = parse_y_position_unchecked (op->data.line.y2, env); else y2 = y1; /* This is one of the cases where we are matching the exact * pixel aligned rectangle produced by X; for zero-width lines * the generic algorithm produces the right result so we don't * need to handle them here. */ if ((y1 == y2 || x1 == x2) && op->data.line.width != 0) { double offset = op->data.line.width % 2 ? .5 : 0; if (y1 == y2) { cairo_move_to (cr, x1, y1 + offset); cairo_line_to (cr, x2, y2 + offset); } else { cairo_move_to (cr, x1 + offset, y1); cairo_line_to (cr, x2 + offset, y2); } } else { /* zero-width lines include both end-points in X, unlike wide lines */ if (op->data.line.width == 0) cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_move_to (cr, x1 + .5, y1 + .5); cairo_line_to (cr, x2 + .5, y2 + .5); } cairo_stroke (cr); } } break; case META_DRAW_RECTANGLE: { int rx, ry, rwidth, rheight; meta_color_spec_render (op->data.rectangle.color_spec, style_gtk, &color); gdk_cairo_set_source_rgba (cr, &color); rx = parse_x_position_unchecked (op->data.rectangle.x, env); ry = parse_y_position_unchecked (op->data.rectangle.y, env); rwidth = parse_size_unchecked (op->data.rectangle.width, env); rheight = parse_size_unchecked (op->data.rectangle.height, env); /* Filled and stroked rectangles are the other cases * we pixel-align to X rasterization */ if (op->data.rectangle.filled) { cairo_rectangle (cr, rx, ry, rwidth, rheight); cairo_fill (cr); } else { cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight); cairo_stroke (cr); } } break; case META_DRAW_ARC: { int rx, ry, rwidth, rheight; double start_angle, end_angle; double center_x, center_y; meta_color_spec_render (op->data.arc.color_spec, style_gtk, &color); gdk_cairo_set_source_rgba (cr, &color); rx = parse_x_position_unchecked (op->data.arc.x, env); ry = parse_y_position_unchecked (op->data.arc.y, env); rwidth = parse_size_unchecked (op->data.arc.width, env); rheight = parse_size_unchecked (op->data.arc.height, env); start_angle = op->data.arc.start_angle * (M_PI / 180.) - (.5 * M_PI); /* start at 12 instead of 3 oclock */ end_angle = start_angle + op->data.arc.extent_angle * (M_PI / 180.); center_x = rx + (double)rwidth / 2. + .5; center_y = ry + (double)rheight / 2. + .5; cairo_save (cr); cairo_translate (cr, center_x, center_y); cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.); if (op->data.arc.extent_angle >= 0) cairo_arc (cr, 0, 0, 1, start_angle, end_angle); else cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle); cairo_restore (cr); if (op->data.arc.filled) { cairo_line_to (cr, center_x, center_y); cairo_fill (cr); } else cairo_stroke (cr); } break; case META_DRAW_CLIP: break; case META_DRAW_TINT: { int rx, ry, rwidth, rheight; gboolean needs_alpha; needs_alpha = op->data.tint.alpha_spec && (op->data.tint.alpha_spec->n_alphas > 1 || op->data.tint.alpha_spec->alphas[0] != 0xff); rx = parse_x_position_unchecked (op->data.tint.x, env); ry = parse_y_position_unchecked (op->data.tint.y, env); rwidth = parse_size_unchecked (op->data.tint.width, env); rheight = parse_size_unchecked (op->data.tint.height, env); if (!needs_alpha) { meta_color_spec_render (op->data.tint.color_spec, style_gtk, &color); gdk_cairo_set_source_rgba (cr, &color); cairo_rectangle (cr, rx, ry, rwidth, rheight); cairo_fill (cr); } else { GdkPixbuf *pixbuf; pixbuf = draw_op_as_pixbuf (op, style_gtk, info, rwidth, rheight); if (pixbuf) { gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry); cairo_paint (cr); g_object_unref (G_OBJECT (pixbuf)); } } } break; case META_DRAW_GRADIENT: { int rx, ry, rwidth, rheight; GdkPixbuf *pixbuf; rx = parse_x_position_unchecked (op->data.gradient.x, env); ry = parse_y_position_unchecked (op->data.gradient.y, env); rwidth = parse_size_unchecked (op->data.gradient.width, env); rheight = parse_size_unchecked (op->data.gradient.height, env); pixbuf = draw_op_as_pixbuf (op, style_gtk, info, rwidth, rheight); if (pixbuf) { gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry); cairo_paint (cr); g_object_unref (G_OBJECT (pixbuf)); } } break; case META_DRAW_IMAGE: { int rx, ry, rwidth, rheight; GdkPixbuf *pixbuf; if (op->data.image.pixbuf) { env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf); env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf); } rwidth = parse_size_unchecked (op->data.image.width, env); rheight = parse_size_unchecked (op->data.image.height, env); pixbuf = draw_op_as_pixbuf (op, style_gtk, info, rwidth, rheight); if (pixbuf) { rx = parse_x_position_unchecked (op->data.image.x, env); ry = parse_y_position_unchecked (op->data.image.y, env); gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry); cairo_paint (cr); g_object_unref (G_OBJECT (pixbuf)); } } break; case META_DRAW_GTK_ARROW: { int rx, ry, rwidth, rheight; double angle = 0, size; rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env); ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env); rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env); rheight = parse_size_unchecked (op->data.gtk_arrow.height, env); size = MAX(rwidth, rheight); switch (op->data.gtk_arrow.arrow) { case GTK_ARROW_UP: angle = 0; break; case GTK_ARROW_RIGHT: angle = M_PI / 2; break; case GTK_ARROW_DOWN: angle = M_PI; break; case GTK_ARROW_LEFT: angle = 3 * M_PI / 2; break; case GTK_ARROW_NONE: return; } gtk_style_context_set_state (style_gtk, op->data.gtk_arrow.state); gtk_render_arrow (style_gtk, cr, angle, rx, ry, size); } break; case META_DRAW_GTK_BOX: { int rx, ry, rwidth, rheight; rx = parse_x_position_unchecked (op->data.gtk_box.x, env); ry = parse_y_position_unchecked (op->data.gtk_box.y, env); rwidth = parse_size_unchecked (op->data.gtk_box.width, env); rheight = parse_size_unchecked (op->data.gtk_box.height, env); gtk_style_context_set_state (style_gtk, op->data.gtk_box.state); gtk_render_background (style_gtk, cr, rx, ry, rwidth, rheight); gtk_render_frame (style_gtk, cr, rx, ry, rwidth, rheight); } break; case META_DRAW_GTK_VLINE: { int rx, ry1, ry2; rx = parse_x_position_unchecked (op->data.gtk_vline.x, env); ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env); ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env); gtk_style_context_set_state (style_gtk, op->data.gtk_vline.state); gtk_render_line (style_gtk, cr, rx, ry1, rx, ry2); } break; case META_DRAW_ICON: { int rx, ry, rwidth, rheight; GdkPixbuf *pixbuf; rwidth = parse_size_unchecked (op->data.icon.width, env); rheight = parse_size_unchecked (op->data.icon.height, env); pixbuf = draw_op_as_pixbuf (op, style_gtk, info, rwidth, rheight); if (pixbuf) { rx = parse_x_position_unchecked (op->data.icon.x, env); ry = parse_y_position_unchecked (op->data.icon.y, env); gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry); cairo_paint (cr); g_object_unref (G_OBJECT (pixbuf)); } } break; case META_DRAW_TITLE: if (info->title_layout) { int rx, ry; PangoRectangle ink_rect, logical_rect; meta_color_spec_render (op->data.title.color_spec, style_gtk, &color); gdk_cairo_set_source_rgba (cr, &color); rx = parse_x_position_unchecked (op->data.title.x, env); ry = parse_y_position_unchecked (op->data.title.y, env); if (op->data.title.ellipsize_width) { int ellipsize_width; int right_bearing; ellipsize_width = parse_x_position_unchecked (op->data.title.ellipsize_width, env); /* HACK: parse_x_position_unchecked adds in env->rect.x, subtract out again */ ellipsize_width -= env->rect.x; pango_layout_set_width (info->title_layout, -1); pango_layout_get_pixel_extents (info->title_layout, &ink_rect, &logical_rect); /* Pango's idea of ellipsization is with respect to the logical rect. * correct for this, by reducing the ellipsization width by the overflow * of the un-ellipsized text on the right... it's always the visual * right we want regardless of bidi, since since the X we pass in to * cairo_move_to() is always the left edge of the line. */ right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width); right_bearing = MAX (right_bearing, 0); ellipsize_width -= right_bearing; ellipsize_width = MAX (ellipsize_width, 0); /* Only ellipsizing when necessary is a performance optimization - * pango_layout_set_width() will force a relayout if it isn't the * same as the current width of -1. */ if (ellipsize_width < logical_rect.width) pango_layout_set_width (info->title_layout, PANGO_SCALE * ellipsize_width); } cairo_move_to (cr, rx, ry); pango_cairo_show_layout (cr, info->title_layout); /* Remove any ellipsization we might have set; will short-circuit * if the width is already -1 */ pango_layout_set_width (info->title_layout, -1); } break; case META_DRAW_OP_LIST: { MetaRectangle d_rect; d_rect.x = parse_x_position_unchecked (op->data.op_list.x, env); d_rect.y = parse_y_position_unchecked (op->data.op_list.y, env); d_rect.width = parse_size_unchecked (op->data.op_list.width, env); d_rect.height = parse_size_unchecked (op->data.op_list.height, env); meta_draw_op_list_draw_with_style (op->data.op_list.op_list, style_gtk, widget, cr, info, d_rect); } break; case META_DRAW_TILE: { int rx, ry, rwidth, rheight; int tile_xoffset, tile_yoffset; MetaRectangle tile; rx = parse_x_position_unchecked (op->data.tile.x, env); ry = parse_y_position_unchecked (op->data.tile.y, env); rwidth = parse_size_unchecked (op->data.tile.width, env); rheight = parse_size_unchecked (op->data.tile.height, env); cairo_save (cr); cairo_rectangle (cr, rx, ry, rwidth, rheight); cairo_clip (cr); tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env); tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env); /* tile offset should not include x/y */ tile_xoffset -= rect.x; tile_yoffset -= rect.y; tile.width = parse_size_unchecked (op->data.tile.tile_width, env); tile.height = parse_size_unchecked (op->data.tile.tile_height, env); tile.x = rx - tile_xoffset; while (tile.x < (rx + rwidth)) { tile.y = ry - tile_yoffset; while (tile.y < (ry + rheight)) { meta_draw_op_list_draw_with_style (op->data.tile.op_list, style_gtk, widget, cr, info, tile); tile.y += tile.height; } tile.x += tile.width; } cairo_restore (cr); } break; } cairo_restore (cr); gtk_style_context_restore (style_gtk); } LOCAL_SYMBOL void meta_draw_op_draw_with_style (const MetaDrawOp *op, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, MetaRectangle logical_region) { MetaPositionExprEnv env; fill_env (&env, info, logical_region); meta_draw_op_draw_with_env (op, style_gtk, widget, cr, info, logical_region, &env); } LOCAL_SYMBOL void meta_draw_op_draw (const MetaDrawOp *op, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, MetaRectangle logical_region) { meta_draw_op_draw_with_style (op, gtk_widget_get_style_context (widget), widget, cr, info, logical_region); } /** * meta_draw_op_list_new: (skip) * */ LOCAL_SYMBOL MetaDrawOpList* meta_draw_op_list_new (int n_preallocs) { MetaDrawOpList *op_list; g_return_val_if_fail (n_preallocs >= 0, NULL); op_list = g_new (MetaDrawOpList, 1); op_list->refcount = 1; op_list->n_allocated = n_preallocs; op_list->ops = g_new (MetaDrawOp*, op_list->n_allocated); op_list->n_ops = 0; return op_list; } LOCAL_SYMBOL void meta_draw_op_list_ref (MetaDrawOpList *op_list) { g_return_if_fail (op_list != NULL); op_list->refcount += 1; } LOCAL_SYMBOL void meta_draw_op_list_unref (MetaDrawOpList *op_list) { g_return_if_fail (op_list != NULL); g_return_if_fail (op_list->refcount > 0); op_list->refcount -= 1; if (op_list->refcount == 0) { int i; for (i = 0; i < op_list->n_ops; i++) meta_draw_op_free (op_list->ops[i]); free (op_list->ops); DEBUG_FILL_STRUCT (op_list); free (op_list); } } LOCAL_SYMBOL void meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, MetaRectangle rect) { int i; MetaPositionExprEnv env; if (op_list->n_ops == 0) return; fill_env (&env, info, rect); /* FIXME this can be optimized, potentially a lot, by * compressing multiple ops when possible. For example, * anything convertible to a pixbuf can be composited * client-side, and putting a color tint over a pixbuf * can be done without creating the solid-color pixbuf. * * To implement this my plan is to have the idea of a * compiled draw op (with the string expressions already * evaluated), we make an array of those, and then fold * adjacent items when possible. */ cairo_save (cr); for (i = 0; i < op_list->n_ops; i++) { MetaDrawOp *op = op_list->ops[i]; if (op->type == META_DRAW_CLIP) { cairo_restore (cr); cairo_rectangle (cr, parse_x_position_unchecked (op->data.clip.x, &env), parse_y_position_unchecked (op->data.clip.y, &env), parse_size_unchecked (op->data.clip.width, &env), parse_size_unchecked (op->data.clip.height, &env)); cairo_clip (cr); cairo_save (cr); } else if (gdk_cairo_get_clip_rectangle (cr, NULL)) { meta_draw_op_draw_with_env (op, style_gtk, widget, cr, info, rect, &env); } } cairo_restore (cr); } LOCAL_SYMBOL void meta_draw_op_list_draw (const MetaDrawOpList *op_list, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, MetaRectangle rect) { meta_draw_op_list_draw_with_style (op_list, gtk_widget_get_style_context (widget), widget, cr, info, rect); } LOCAL_SYMBOL void meta_draw_op_list_append (MetaDrawOpList *op_list, MetaDrawOp *op) { if (op_list->n_ops == op_list->n_allocated) { op_list->n_allocated *= 2; op_list->ops = g_renew (MetaDrawOp*, op_list->ops, op_list->n_allocated); } op_list->ops[op_list->n_ops] = op; op_list->n_ops += 1; } LOCAL_SYMBOL gboolean meta_draw_op_list_validate (MetaDrawOpList *op_list, GError **error) { g_return_val_if_fail (op_list != NULL, FALSE); /* empty lists are OK, nothing else to check really */ return TRUE; } /* This is not done in validate, since we wouldn't know the name * of the list to report the error. It might be nice to * store names inside the list sometime. */ LOCAL_SYMBOL gboolean meta_draw_op_list_contains (MetaDrawOpList *op_list, MetaDrawOpList *child) { int i; /* mmm, huge tree recursion */ for (i = 0; i < op_list->n_ops; i++) { if (op_list->ops[i]->type == META_DRAW_OP_LIST) { if (op_list->ops[i]->data.op_list.op_list == child) return TRUE; if (meta_draw_op_list_contains (op_list->ops[i]->data.op_list.op_list, child)) return TRUE; } else if (op_list->ops[i]->type == META_DRAW_TILE) { if (op_list->ops[i]->data.tile.op_list == child) return TRUE; if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list, child)) return TRUE; } } return FALSE; } /* * Constructor for a MetaFrameStyle. * * \param parent The parent style. Data not filled in here will be * looked for in the parent style, and in its parent * style, and so on. * * \return The newly-constructed style. */ LOCAL_SYMBOL MetaFrameStyle* meta_frame_style_new (MetaFrameStyle *parent) { MetaFrameStyle *style; style = g_new0 (MetaFrameStyle, 1); style->refcount = 1; /* Default alpha is fully opaque */ style->window_background_alpha = 255; style->parent = parent; if (parent) meta_frame_style_ref (parent); return style; } /* * Increases the reference count of a frame style. * If the style is NULL, this is a no-op. * * \param style The style. */ LOCAL_SYMBOL void meta_frame_style_ref (MetaFrameStyle *style) { g_return_if_fail (style != NULL); style->refcount += 1; } static void free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST]) { int i, j; for (i = 0; i < META_BUTTON_TYPE_LAST; i++) for (j = 0; j < META_BUTTON_STATE_LAST; j++) if (op_lists[i][j]) meta_draw_op_list_unref (op_lists[i][j]); } LOCAL_SYMBOL void meta_frame_style_unref (MetaFrameStyle *style) { g_return_if_fail (style != NULL); g_return_if_fail (style->refcount > 0); style->refcount -= 1; if (style->refcount == 0) { int i; free_button_ops (style->buttons); for (i = 0; i < META_FRAME_PIECE_LAST; i++) if (style->pieces[i]) meta_draw_op_list_unref (style->pieces[i]); if (style->layout) meta_frame_layout_unref (style->layout); if (style->window_background_color) meta_color_spec_free (style->window_background_color); /* we hold a reference to any parent style */ if (style->parent) meta_frame_style_unref (style->parent); DEBUG_FILL_STRUCT (style); free (style); } } static MetaButtonState map_button_state (MetaButtonType button_type, const MetaFrameGeometry *fgeom, int middle_bg_offset, MetaButtonState button_states[META_BUTTON_TYPE_LAST]) { MetaButtonFunction function = META_BUTTON_FUNCTION_LAST; switch (button_type) { /* First hande functions, which map directly */ case META_BUTTON_TYPE_SHADE: case META_BUTTON_TYPE_ABOVE: case META_BUTTON_TYPE_STICK: case META_BUTTON_TYPE_UNSHADE: case META_BUTTON_TYPE_UNABOVE: case META_BUTTON_TYPE_UNSTICK: case META_BUTTON_TYPE_MENU: case META_BUTTON_TYPE_MINIMIZE: case META_BUTTON_TYPE_MAXIMIZE: case META_BUTTON_TYPE_CLOSE: return button_states[button_type]; /* Map position buttons to the corresponding function */ case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND: case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND: if (fgeom->n_right_buttons > 0) function = fgeom->button_layout.right_buttons[0]; break; case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND: if (fgeom->n_right_buttons > 0) function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1]; break; case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND: if (middle_bg_offset + 1 < fgeom->n_right_buttons) function = fgeom->button_layout.right_buttons[middle_bg_offset + 1]; break; case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND: case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND: if (fgeom->n_left_buttons > 0) function = fgeom->button_layout.left_buttons[0]; break; case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND: if (fgeom->n_left_buttons > 0) function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1]; break; case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND: if (middle_bg_offset + 1 < fgeom->n_left_buttons) function = fgeom->button_layout.left_buttons[middle_bg_offset + 1]; break; case META_BUTTON_TYPE_LAST: break; } if (function != META_BUTTON_FUNCTION_LAST) return button_states[map_button_function_to_type (function)]; return META_BUTTON_STATE_LAST; } static MetaDrawOpList* get_button (MetaFrameStyle *style, MetaButtonType type, MetaButtonState state) { MetaDrawOpList *op_list; MetaFrameStyle *parent; parent = style; op_list = NULL; while (parent && op_list == NULL) { op_list = parent->buttons[type][state]; parent = parent->parent; } /* We fall back to the side buttons if we don't have * single button backgrounds, and to middle button * backgrounds if we don't have the ones on the sides */ if (op_list == NULL && type == META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND) return get_button (style, META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, state); if (op_list == NULL && type == META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND) return get_button (style, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, state); if (op_list == NULL && (type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND || type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND)) return get_button (style, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND, state); if (op_list == NULL && (type == META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND || type == META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND)) return get_button (style, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND, state); /* We fall back to normal if no prelight */ if (op_list == NULL && state == META_BUTTON_STATE_PRELIGHT) return get_button (style, type, META_BUTTON_STATE_NORMAL); return op_list; } LOCAL_SYMBOL gboolean meta_frame_style_validate (MetaFrameStyle *style, guint current_theme_version, GError **error) { int i, j; g_return_val_if_fail (style != NULL, FALSE); g_return_val_if_fail (style->layout != NULL, FALSE); for (i = 0; i < META_BUTTON_TYPE_LAST; i++) { /* for now the "positional" buttons are optional */ if (i >= META_BUTTON_TYPE_CLOSE) { for (j = 0; j < META_BUTTON_STATE_LAST; j++) { if (get_button (style, i, j) == NULL && meta_theme_earliest_version_with_button (i) <= current_theme_version ) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style"), meta_button_type_to_string (i), meta_button_state_to_string (j)); return FALSE; } } } } return TRUE; } static void button_rect (MetaButtonType type, const MetaFrameGeometry *fgeom, int middle_background_offset, GdkRectangle *rect) { switch (type) { case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND: *rect = fgeom->left_left_background; break; case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND: *rect = fgeom->left_middle_backgrounds[middle_background_offset]; break; case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND: *rect = fgeom->left_right_background; break; case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND: *rect = fgeom->left_single_background; break; case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND: *rect = fgeom->right_left_background; break; case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND: *rect = fgeom->right_middle_backgrounds[middle_background_offset]; break; case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND: *rect = fgeom->right_right_background; break; case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND: *rect = fgeom->right_single_background; break; case META_BUTTON_TYPE_CLOSE: *rect = fgeom->close_rect.visible; break; case META_BUTTON_TYPE_SHADE: *rect = fgeom->shade_rect.visible; break; case META_BUTTON_TYPE_UNSHADE: *rect = fgeom->unshade_rect.visible; break; case META_BUTTON_TYPE_ABOVE: *rect = fgeom->above_rect.visible; break; case META_BUTTON_TYPE_UNABOVE: *rect = fgeom->unabove_rect.visible; break; case META_BUTTON_TYPE_STICK: *rect = fgeom->stick_rect.visible; break; case META_BUTTON_TYPE_UNSTICK: *rect = fgeom->unstick_rect.visible; break; case META_BUTTON_TYPE_MAXIMIZE: *rect = fgeom->max_rect.visible; break; case META_BUTTON_TYPE_MINIMIZE: *rect = fgeom->min_rect.visible; break; case META_BUTTON_TYPE_MENU: *rect = fgeom->menu_rect.visible; break; case META_BUTTON_TYPE_LAST: g_assert_not_reached (); break; } } LOCAL_SYMBOL LOCAL_SYMBOL void meta_frame_style_draw_with_style (MetaFrameStyle *style, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, const MetaFrameGeometry *fgeom, int client_width, int client_height, PangoLayout *title_layout, int text_height, MetaButtonState button_states[META_BUTTON_TYPE_LAST]) { int i, j; GdkRectangle visible_rect; GdkRectangle titlebar_rect; GdkRectangle left_titlebar_edge; GdkRectangle right_titlebar_edge; GdkRectangle bottom_titlebar_edge; GdkRectangle top_titlebar_edge; GdkRectangle left_edge, right_edge, bottom_edge; PangoRectangle logical_rect; MetaDrawInfo draw_info; const MetaFrameBorders *borders; borders = &fgeom->borders; visible_rect.x = borders->invisible.left; visible_rect.y = borders->invisible.top; visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right; visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom; titlebar_rect.x = visible_rect.x; titlebar_rect.y = visible_rect.y; titlebar_rect.width = visible_rect.width; titlebar_rect.height = borders->visible.top; left_titlebar_edge.x = titlebar_rect.x; left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge; left_titlebar_edge.width = fgeom->left_titlebar_edge; left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge; right_titlebar_edge.y = left_titlebar_edge.y; right_titlebar_edge.height = left_titlebar_edge.height; right_titlebar_edge.width = fgeom->right_titlebar_edge; right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width; top_titlebar_edge.x = titlebar_rect.x; top_titlebar_edge.y = titlebar_rect.y; top_titlebar_edge.width = titlebar_rect.width; top_titlebar_edge.height = fgeom->top_titlebar_edge; bottom_titlebar_edge.x = titlebar_rect.x; bottom_titlebar_edge.width = titlebar_rect.width; bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge; bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height; left_edge.x = visible_rect.x; left_edge.y = visible_rect.y + borders->visible.top; left_edge.width = borders->visible.left; left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom; right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right; right_edge.y = visible_rect.y + borders->visible.top; right_edge.width = borders->visible.right; right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom; bottom_edge.x = visible_rect.x; bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom; bottom_edge.width = visible_rect.width; bottom_edge.height = borders->visible.bottom; if (title_layout) pango_layout_get_pixel_extents (title_layout, NULL, &logical_rect); draw_info.title_layout = title_layout; draw_info.title_layout_width = title_layout ? logical_rect.width : 0; draw_info.title_layout_height = title_layout ? logical_rect.height : 0; draw_info.fgeom = fgeom; /* The enum is in the order the pieces should be rendered. */ i = 0; while (i < META_FRAME_PIECE_LAST) { GdkRectangle rect; switch ((MetaFramePiece) i) { case META_FRAME_PIECE_ENTIRE_BACKGROUND: rect = visible_rect; break; case META_FRAME_PIECE_TITLEBAR: rect = titlebar_rect; break; case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE: rect = left_titlebar_edge; break; case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE: rect = right_titlebar_edge; break; case META_FRAME_PIECE_TOP_TITLEBAR_EDGE: rect = top_titlebar_edge; break; case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE: rect = bottom_titlebar_edge; break; case META_FRAME_PIECE_TITLEBAR_MIDDLE: rect.x = left_titlebar_edge.x + left_titlebar_edge.width; rect.y = top_titlebar_edge.y + top_titlebar_edge.height; rect.width = titlebar_rect.width - left_titlebar_edge.width - right_titlebar_edge.width; rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height; break; case META_FRAME_PIECE_TITLE: rect = fgeom->title_rect; break; case META_FRAME_PIECE_LEFT_EDGE: rect = left_edge; break; case META_FRAME_PIECE_RIGHT_EDGE: rect = right_edge; break; case META_FRAME_PIECE_BOTTOM_EDGE: rect = bottom_edge; break; case META_FRAME_PIECE_OVERLAY: rect = visible_rect; break; case META_FRAME_PIECE_LAST: g_assert_not_reached (); break; } cairo_save (cr); gdk_cairo_rectangle (cr, &rect); cairo_clip (cr); if (gdk_cairo_get_clip_rectangle (cr, NULL)) { MetaDrawOpList *op_list; MetaFrameStyle *parent; parent = style; op_list = NULL; while (parent && op_list == NULL) { op_list = parent->pieces[i]; parent = parent->parent; } if (op_list) { MetaRectangle m_rect; m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height); meta_draw_op_list_draw_with_style (op_list, style_gtk, widget, cr, &draw_info, m_rect); } } cairo_restore (cr); /* Draw buttons just before overlay */ if ((i + 1) == META_FRAME_PIECE_OVERLAY) { MetaDrawOpList *op_list; int middle_bg_offset; middle_bg_offset = 0; j = 0; while (j < META_BUTTON_TYPE_LAST) { MetaButtonState button_state; button_rect (j, fgeom, middle_bg_offset, &rect); button_state = map_button_state (j, fgeom, middle_bg_offset, button_states); op_list = get_button (style, j, button_state); if (op_list) { cairo_save (cr); gdk_cairo_rectangle (cr, &rect); cairo_clip (cr); if (gdk_cairo_get_clip_rectangle (cr, NULL)) { MetaRectangle m_rect; m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height); meta_draw_op_list_draw_with_style (op_list, style_gtk, widget, cr, &draw_info, m_rect); } cairo_restore (cr); } /* MIDDLE_BACKGROUND type may get drawn more than once */ if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND || j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) && middle_bg_offset < MAX_MIDDLE_BACKGROUNDS) { ++middle_bg_offset; } else { middle_bg_offset = 0; ++j; } } } ++i; } } LOCAL_SYMBOL void meta_frame_style_draw (MetaFrameStyle *style, GtkWidget *widget, cairo_t *cr, const MetaFrameGeometry *fgeom, int client_width, int client_height, PangoLayout *title_layout, int text_height, MetaButtonState button_states[META_BUTTON_TYPE_LAST]) { meta_frame_style_draw_with_style (style, gtk_widget_get_style_context (widget), widget, cr, fgeom, client_width, client_height, title_layout, text_height, button_states); } LOCAL_SYMBOL MetaFrameStyleSet* meta_frame_style_set_new (MetaFrameStyleSet *parent) { MetaFrameStyleSet *style_set; style_set = g_new0 (MetaFrameStyleSet, 1); style_set->parent = parent; if (parent) meta_frame_style_set_ref (parent); style_set->refcount = 1; return style_set; } static void free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST]) { int i; for (i = 0; i < META_FRAME_FOCUS_LAST; i++) if (focus_styles[i]) meta_frame_style_unref (focus_styles[i]); } LOCAL_SYMBOL void meta_frame_style_set_ref (MetaFrameStyleSet *style_set) { g_return_if_fail (style_set != NULL); style_set->refcount += 1; } LOCAL_SYMBOL void meta_frame_style_set_unref (MetaFrameStyleSet *style_set) { g_return_if_fail (style_set != NULL); g_return_if_fail (style_set->refcount > 0); style_set->refcount -= 1; if (style_set->refcount == 0) { int i; for (i = 0; i < META_FRAME_RESIZE_LAST; i++) { free_focus_styles (style_set->normal_styles[i]); free_focus_styles (style_set->shaded_styles[i]); } free_focus_styles (style_set->maximized_styles); free_focus_styles (style_set->tiled_left_styles); free_focus_styles (style_set->tiled_right_styles); free_focus_styles (style_set->maximized_and_shaded_styles); free_focus_styles (style_set->tiled_left_and_shaded_styles); free_focus_styles (style_set->tiled_right_and_shaded_styles); if (style_set->parent) meta_frame_style_set_unref (style_set->parent); DEBUG_FILL_STRUCT (style_set); free (style_set); } } static MetaFrameStyle* get_style (MetaFrameStyleSet *style_set, MetaFrameState state, MetaFrameResize resize, MetaFrameFocus focus) { MetaFrameStyle *style; style = NULL; switch (state) { case META_FRAME_STATE_NORMAL: case META_FRAME_STATE_SHADED: { if (state == META_FRAME_STATE_SHADED) style = style_set->shaded_styles[resize][focus]; else style = style_set->normal_styles[resize][focus]; /* Try parent if we failed here */ if (style == NULL && style_set->parent) style = get_style (style_set->parent, state, resize, focus); /* Allow people to omit the vert/horz/none resize modes */ if (style == NULL && resize != META_FRAME_RESIZE_BOTH) style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus); } break; default: { MetaFrameStyle **styles; styles = NULL; switch (state) { case META_FRAME_STATE_MAXIMIZED: styles = style_set->maximized_styles; break; case META_FRAME_STATE_TILED_LEFT: styles = style_set->tiled_left_styles; break; case META_FRAME_STATE_TILED_RIGHT: styles = style_set->tiled_right_styles; break; case META_FRAME_STATE_MAXIMIZED_AND_SHADED: styles = style_set->maximized_and_shaded_styles; break; case META_FRAME_STATE_TILED_LEFT_AND_SHADED: styles = style_set->tiled_left_and_shaded_styles; break; case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: styles = style_set->tiled_right_and_shaded_styles; break; case META_FRAME_STATE_NORMAL: case META_FRAME_STATE_SHADED: case META_FRAME_STATE_LAST: break; } style = styles[focus]; /* Tiled states are optional, try falling back to non-tiled states */ if (style == NULL) { if (state == META_FRAME_STATE_TILED_LEFT || state == META_FRAME_STATE_TILED_RIGHT) style = get_style (style_set, META_FRAME_STATE_NORMAL, resize, focus); else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED || state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED) style = get_style (style_set, META_FRAME_STATE_SHADED, resize, focus); } /* Try parent if we failed here */ if (style == NULL && style_set->parent) style = get_style (style_set->parent, state, resize, focus); } } return style; } static gboolean check_state (MetaFrameStyleSet *style_set, MetaFrameState state, GError **error) { int i; for (i = 0; i < META_FRAME_FOCUS_LAST; i++) { if (get_style (style_set, state, META_FRAME_RESIZE_NONE, i) == NULL) { /* Translators: This error occurs when a <frame> tag is missing * in theme XML. The "<frame ...>" is intended as a noun phrase, * and the "missing" qualifies it. You should translate "whatever". */ g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"), meta_frame_state_to_string (state), meta_frame_resize_to_string (META_FRAME_RESIZE_NONE), meta_frame_focus_to_string (i)); return FALSE; } } return TRUE; } LOCAL_SYMBOL gboolean meta_frame_style_set_validate (MetaFrameStyleSet *style_set, GError **error) { int i, j; g_return_val_if_fail (style_set != NULL, FALSE); for (i = 0; i < META_FRAME_RESIZE_LAST; i++) for (j = 0; j < META_FRAME_FOCUS_LAST; j++) if (get_style (style_set, META_FRAME_STATE_NORMAL, i, j) == NULL) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"), meta_frame_state_to_string (META_FRAME_STATE_NORMAL), meta_frame_resize_to_string (i), meta_frame_focus_to_string (j)); return FALSE; } if (!check_state (style_set, META_FRAME_STATE_SHADED, error)) return FALSE; if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error)) return FALSE; if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error)) return FALSE; return TRUE; } /** * meta_theme_get_current: (skip) * */ MetaTheme* meta_theme_get_current (void) { return meta_current_theme; } void meta_theme_set_current (const char *name, gboolean force_reload) { MetaTheme *new_theme; GError *err; meta_topic (META_DEBUG_THEMES, "Setting current theme to \"%s\"\n", name); if (!force_reload && meta_current_theme && strcmp (name, meta_current_theme->name) == 0) return; err = NULL; new_theme = meta_theme_load (name, &err); if (new_theme == NULL) { meta_warning (_("Failed to load theme \"%s\": %s\n"), name, err->message); g_error_free (err); } else { if (meta_current_theme) meta_theme_free (meta_current_theme); meta_current_theme = new_theme; meta_topic (META_DEBUG_THEMES, "New theme is \"%s\"\n", meta_current_theme->name); } } /** * meta_theme_new: (skip) * */ MetaTheme* meta_theme_new (void) { MetaTheme *theme; theme = g_new0 (MetaTheme, 1); theme->images_by_filename = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify) g_object_unref); theme->layouts_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify) meta_frame_layout_unref); theme->draw_op_lists_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify) meta_draw_op_list_unref); theme->styles_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify) meta_frame_style_unref); theme->style_sets_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify) meta_frame_style_set_unref); /* Create our variable quarks so we can look up variables without having to strcmp for the names */ theme->quark_width = g_quark_from_static_string ("width"); theme->quark_height = g_quark_from_static_string ("height"); theme->quark_object_width = g_quark_from_static_string ("object_width"); theme->quark_object_height = g_quark_from_static_string ("object_height"); theme->quark_left_width = g_quark_from_static_string ("left_width"); theme->quark_right_width = g_quark_from_static_string ("right_width"); theme->quark_top_height = g_quark_from_static_string ("top_height"); theme->quark_bottom_height = g_quark_from_static_string ("bottom_height"); theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width"); theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height"); theme->quark_icon_width = g_quark_from_static_string ("icon_width"); theme->quark_icon_height = g_quark_from_static_string ("icon_height"); theme->quark_title_width = g_quark_from_static_string ("title_width"); theme->quark_title_height = g_quark_from_static_string ("title_height"); theme->quark_frame_x_center = g_quark_from_static_string ("frame_x_center"); theme->quark_frame_y_center = g_quark_from_static_string ("frame_y_center"); return theme; } void meta_theme_free (MetaTheme *theme) { int i; g_return_if_fail (theme != NULL); free (theme->name); free (theme->dirname); free (theme->filename); free (theme->readable_name); free (theme->date); free (theme->description); free (theme->author); free (theme->copyright); /* be more careful when destroying the theme hash tables, since they are only constructed as needed, and may be NULL. */ if (theme->integer_constants) g_hash_table_destroy (theme->integer_constants); if (theme->images_by_filename) g_hash_table_destroy (theme->images_by_filename); if (theme->layouts_by_name) g_hash_table_destroy (theme->layouts_by_name); if (theme->draw_op_lists_by_name) g_hash_table_destroy (theme->draw_op_lists_by_name); if (theme->styles_by_name) g_hash_table_destroy (theme->styles_by_name); if (theme->style_sets_by_name) g_hash_table_destroy (theme->style_sets_by_name); for (i = 0; i < META_FRAME_TYPE_LAST; i++) if (theme->style_sets_by_type[i]) meta_frame_style_set_unref (theme->style_sets_by_type[i]); DEBUG_FILL_STRUCT (theme); free (theme); } gboolean meta_theme_validate (MetaTheme *theme, GError **error) { int i; g_return_val_if_fail (theme != NULL, FALSE); /* FIXME what else should be checked? */ g_assert (theme->name); if (theme->readable_name == NULL) { /* Translators: This error means that a necessary XML tag (whose name * is given in angle brackets) was not found in a given theme (whose * name is given second, in quotation marks). */ g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("No <%s> set for theme \"%s\""), "name", theme->name); return FALSE; } if (theme->author == NULL) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("No <%s> set for theme \"%s\""), "author", theme->name); return FALSE; } if (theme->date == NULL) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("No <%s> set for theme \"%s\""), "date", theme->name); return FALSE; } if (theme->description == NULL) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("No <%s> set for theme \"%s\""), "description", theme->name); return FALSE; } if (theme->copyright == NULL) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("No <%s> set for theme \"%s\""), "copyright", theme->name); return FALSE; } for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++) if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"), meta_frame_type_to_string (i), theme->name, meta_frame_type_to_string (i)); return FALSE; } return TRUE; } /** * meta_theme_load_image: (skip) * */ LOCAL_SYMBOL GdkPixbuf* meta_theme_load_image (MetaTheme *theme, const char *filename, guint scale, GError **error) { GdkPixbuf *pixbuf; pixbuf = g_hash_table_lookup (theme->images_by_filename, filename); if (pixbuf == NULL) { if (g_str_has_prefix (filename, "theme:") && META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES)) { pixbuf = gtk_icon_theme_load_icon_for_scale (gtk_icon_theme_get_default (), filename+6, 20, scale, 0, error); if (pixbuf == NULL) return NULL; } else { char *full_path; gint width, height; full_path = g_build_filename (theme->dirname, filename, NULL); if (gdk_pixbuf_get_file_info (full_path, &width, &height) == NULL) { g_free (full_path); return NULL; } width *= scale; height *= scale; pixbuf = gdk_pixbuf_new_from_file_at_size (full_path, width, height, error); if (pixbuf == NULL) { g_free (full_path); return NULL; } g_free (full_path); } g_hash_table_replace (theme->images_by_filename, g_strdup (filename), pixbuf); } g_assert (pixbuf); g_object_ref (G_OBJECT (pixbuf)); return pixbuf; } static MetaFrameStyle* theme_get_style (MetaTheme *theme, MetaFrameType type, MetaFrameFlags flags) { MetaFrameState state; MetaFrameResize resize; MetaFrameFocus focus; MetaFrameStyle *style; MetaFrameStyleSet *style_set; style_set = theme->style_sets_by_type[type]; if (style_set == NULL && type == META_FRAME_TYPE_ATTACHED) style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER]; /* Right now the parser forces a style set for all other types, * but this fallback code is here in case I take that out. */ if (style_set == NULL) style_set = theme->style_sets_by_type[META_FRAME_TYPE_NORMAL]; if (style_set == NULL) return NULL; switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED | META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT)) { case 0: state = META_FRAME_STATE_NORMAL; break; case META_FRAME_MAXIMIZED: state = META_FRAME_STATE_MAXIMIZED; break; case META_FRAME_TILED_LEFT: state = META_FRAME_STATE_TILED_LEFT; break; case META_FRAME_TILED_RIGHT: state = META_FRAME_STATE_TILED_RIGHT; break; case META_FRAME_SHADED: state = META_FRAME_STATE_SHADED; break; case (META_FRAME_MAXIMIZED | META_FRAME_SHADED): state = META_FRAME_STATE_MAXIMIZED_AND_SHADED; break; case (META_FRAME_TILED_LEFT | META_FRAME_SHADED): state = META_FRAME_STATE_TILED_LEFT_AND_SHADED; break; case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED): state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED; break; default: state = META_FRAME_STATE_LAST; /* compiler */ break; } switch (flags & (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE)) { case 0: resize = META_FRAME_RESIZE_NONE; break; case META_FRAME_ALLOWS_VERTICAL_RESIZE: case META_FRAME_ALLOWS_BOTTOM_RESIZE: case META_FRAME_ALLOWS_TOP_RESIZE: resize = META_FRAME_RESIZE_VERTICAL; break; case META_FRAME_ALLOWS_HORIZONTAL_RESIZE: case META_FRAME_ALLOWS_LEFT_RESIZE: case META_FRAME_ALLOWS_RIGHT_RESIZE: resize = META_FRAME_RESIZE_HORIZONTAL; break; case (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE): case (META_FRAME_ALLOWS_LEFT_RESIZE | META_FRAME_ALLOWS_BOTTOM_RESIZE): case (META_FRAME_ALLOWS_RIGHT_RESIZE | META_FRAME_ALLOWS_BOTTOM_RESIZE): case (META_FRAME_ALLOWS_LEFT_RESIZE | META_FRAME_ALLOWS_TOP_RESIZE): case (META_FRAME_ALLOWS_RIGHT_RESIZE | META_FRAME_ALLOWS_TOP_RESIZE): resize = META_FRAME_RESIZE_BOTH; break; default: g_assert_not_reached (); resize = META_FRAME_RESIZE_LAST; /* compiler */ break; } /* re invert the styles used for focus/unfocussed while flashing a frame */ if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING)) || (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING))) focus = META_FRAME_FOCUS_YES; else focus = META_FRAME_FOCUS_NO; style = get_style (style_set, state, resize, focus); return style; } LOCAL_SYMBOL MetaFrameStyle* meta_theme_get_frame_style (MetaTheme *theme, MetaFrameType type, MetaFrameFlags flags) { MetaFrameStyle *style; g_return_val_if_fail (type < META_FRAME_TYPE_LAST, NULL); style = theme_get_style (theme, type, flags); return style; } LOCAL_SYMBOL double meta_theme_get_title_scale (MetaTheme *theme, MetaFrameType type, MetaFrameFlags flags) { MetaFrameStyle *style; g_return_val_if_fail (type < META_FRAME_TYPE_LAST, 1.0); style = theme_get_style (theme, type, flags); /* Parser is not supposed to allow this currently */ if (style == NULL) return 1.0; return style->layout->title_scale; } LOCAL_SYMBOL void meta_theme_draw_frame_with_style (MetaTheme *theme, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, MetaFrameType type, MetaFrameFlags flags, int client_width, int client_height, PangoLayout *title_layout, int text_height, const MetaButtonLayout *button_layout, MetaButtonState button_states[META_BUTTON_TYPE_LAST]) { MetaFrameGeometry fgeom; MetaFrameStyle *style; g_return_if_fail (type < META_FRAME_TYPE_LAST); style = theme_get_style (theme, type, flags); /* Parser is not supposed to allow this currently */ if (style == NULL) return; meta_frame_layout_calc_geometry (style->layout, text_height, flags, client_width, client_height, button_layout, type, &fgeom, theme); meta_frame_style_draw_with_style (style, style_gtk, widget, cr, &fgeom, client_width, client_height, title_layout, text_height, button_states); } void meta_theme_draw_frame (MetaTheme *theme, GtkWidget *widget, cairo_t *cr, MetaFrameType type, MetaFrameFlags flags, int client_width, int client_height, PangoLayout *title_layout, int text_height, const MetaButtonLayout *button_layout, MetaButtonState button_states[META_BUTTON_TYPE_LAST]) { meta_theme_draw_frame_with_style (theme, gtk_widget_get_style_context (widget), widget, cr, type,flags, client_width, client_height, title_layout, text_height, button_layout, button_states); } void meta_theme_get_frame_borders (MetaTheme *theme, MetaFrameType type, int text_height, MetaFrameFlags flags, MetaFrameBorders *borders) { MetaFrameStyle *style; g_return_if_fail (type < META_FRAME_TYPE_LAST); style = theme_get_style (theme, type, flags); meta_frame_borders_clear (borders); /* Parser is not supposed to allow this currently */ if (style == NULL) return; meta_frame_layout_get_borders (style->layout, text_height, flags, type, borders); } LOCAL_SYMBOL void meta_theme_calc_geometry (MetaTheme *theme, MetaFrameType type, int text_height, MetaFrameFlags flags, int client_width, int client_height, const MetaButtonLayout *button_layout, MetaFrameGeometry *fgeom) { MetaFrameStyle *style; g_return_if_fail (type < META_FRAME_TYPE_LAST); style = theme_get_style (theme, type, flags); /* Parser is not supposed to allow this currently */ if (style == NULL) return; meta_frame_layout_calc_geometry (style->layout, text_height, flags, client_width, client_height, button_layout, type, fgeom, theme); } LOCAL_SYMBOL MetaFrameLayout* meta_theme_lookup_layout (MetaTheme *theme, const char *name) { return g_hash_table_lookup (theme->layouts_by_name, name); } LOCAL_SYMBOL void meta_theme_insert_layout (MetaTheme *theme, const char *name, MetaFrameLayout *layout) { meta_frame_layout_ref (layout); g_hash_table_replace (theme->layouts_by_name, g_strdup (name), layout); } LOCAL_SYMBOL MetaDrawOpList* meta_theme_lookup_draw_op_list (MetaTheme *theme, const char *name) { return g_hash_table_lookup (theme->draw_op_lists_by_name, name); } LOCAL_SYMBOL void meta_theme_insert_draw_op_list (MetaTheme *theme, const char *name, MetaDrawOpList *op_list) { meta_draw_op_list_ref (op_list); g_hash_table_replace (theme->draw_op_lists_by_name, g_strdup (name), op_list); } LOCAL_SYMBOL MetaFrameStyle* meta_theme_lookup_style (MetaTheme *theme, const char *name) { return g_hash_table_lookup (theme->styles_by_name, name); } LOCAL_SYMBOL void meta_theme_insert_style (MetaTheme *theme, const char *name, MetaFrameStyle *style) { meta_frame_style_ref (style); g_hash_table_replace (theme->styles_by_name, g_strdup (name), style); } LOCAL_SYMBOL MetaFrameStyleSet* meta_theme_lookup_style_set (MetaTheme *theme, const char *name) { return g_hash_table_lookup (theme->style_sets_by_name, name); } LOCAL_SYMBOL LOCAL_SYMBOL void meta_theme_insert_style_set (MetaTheme *theme, const char *name, MetaFrameStyleSet *style_set) { meta_frame_style_set_ref (style_set); g_hash_table_replace (theme->style_sets_by_name, g_strdup (name), style_set); } static gboolean first_uppercase (const char *str) { return g_ascii_isupper (*str); } LOCAL_SYMBOL gboolean meta_theme_define_int_constant (MetaTheme *theme, const char *name, int value, GError **error) { if (theme->integer_constants == NULL) theme->integer_constants = g_hash_table_new_full (g_str_hash, g_str_equal, free, NULL); if (!first_uppercase (name)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("User-defined constants must begin with a capital letter; \"%s\" does not"), name); return FALSE; } if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL, NULL)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Constant \"%s\" has already been defined"), name); return FALSE; } g_hash_table_insert (theme->integer_constants, g_strdup (name), GINT_TO_POINTER (value)); return TRUE; } LOCAL_SYMBOL gboolean meta_theme_lookup_int_constant (MetaTheme *theme, const char *name, int *value) { gpointer old_value; *value = 0; if (theme->integer_constants == NULL) return FALSE; if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL, &old_value)) { *value = GPOINTER_TO_INT (old_value); return TRUE; } else { return FALSE; } } LOCAL_SYMBOL gboolean meta_theme_define_float_constant (MetaTheme *theme, const char *name, double value, GError **error) { double *d; if (theme->float_constants == NULL) theme->float_constants = g_hash_table_new_full (g_str_hash, g_str_equal, free, free); if (!first_uppercase (name)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("User-defined constants must begin with a capital letter; \"%s\" does not"), name); return FALSE; } if (g_hash_table_lookup_extended (theme->float_constants, name, NULL, NULL)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Constant \"%s\" has already been defined"), name); return FALSE; } d = g_new (double, 1); *d = value; g_hash_table_insert (theme->float_constants, g_strdup (name), d); return TRUE; } LOCAL_SYMBOL gboolean meta_theme_lookup_float_constant (MetaTheme *theme, const char *name, double *value) { double *d; *value = 0.0; if (theme->float_constants == NULL) return FALSE; d = g_hash_table_lookup (theme->float_constants, name); if (d) { *value = *d; return TRUE; } else { return FALSE; } } LOCAL_SYMBOL gboolean meta_theme_define_color_constant (MetaTheme *theme, const char *name, const char *value, GError **error) { if (theme->color_constants == NULL) theme->color_constants = g_hash_table_new_full (g_str_hash, g_str_equal, free, NULL); if (!first_uppercase (name)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("User-defined constants must begin with a capital letter; \"%s\" does not"), name); return FALSE; } if (g_hash_table_lookup_extended (theme->color_constants, name, NULL, NULL)) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Constant \"%s\" has already been defined"), name); return FALSE; } g_hash_table_insert (theme->color_constants, g_strdup (name), g_strdup (value)); return TRUE; } /* * Looks up a colour constant. * * \param theme the theme containing the constant * \param name the name of the constant * \param value [out] the string representation of the colour, or NULL if it * doesn't exist * \return TRUE if it exists, FALSE otherwise */ LOCAL_SYMBOL gboolean meta_theme_lookup_color_constant (MetaTheme *theme, const char *name, char **value) { char *result; *value = NULL; if (theme->color_constants == NULL) return FALSE; result = g_hash_table_lookup (theme->color_constants, name); if (result) { *value = result; return TRUE; } else { return FALSE; } } LOCAL_SYMBOL PangoFontDescription* meta_gtk_widget_get_font_desc (GtkWidget *widget, double scale, const PangoFontDescription *override) { GtkStyleContext *style; PangoFontDescription *font_desc; g_return_val_if_fail (gtk_widget_get_realized (widget), NULL); style = gtk_widget_get_style_context (widget); gtk_style_context_get (style, gtk_style_context_get_state (style), GTK_STYLE_PROPERTY_FONT, &font_desc, NULL); if (override) pango_font_description_merge (font_desc, override, TRUE); pango_font_description_set_size (font_desc, MAX (pango_font_description_get_size (font_desc) * scale, 1)); return font_desc; } /* * Returns the height of the letters in a particular font. * * \param font_desc the font * \param context the context of the font * \return the height of the letters */ int meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc, PangoContext *context) { PangoFontMetrics *metrics; PangoLanguage *lang; int retval; lang = pango_context_get_language (context); metrics = pango_context_get_metrics (context, font_desc, lang); retval = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)); pango_font_metrics_unref (metrics); return retval; } LOCAL_SYMBOL MetaGtkColorComponent meta_color_component_from_string (const char *str) { if (strcmp ("fg", str) == 0) return META_GTK_COLOR_FG; else if (strcmp ("bg", str) == 0) return META_GTK_COLOR_BG; else if (strcmp ("light", str) == 0) return META_GTK_COLOR_LIGHT; else if (strcmp ("dark", str) == 0) return META_GTK_COLOR_DARK; else if (strcmp ("mid", str) == 0) return META_GTK_COLOR_MID; else if (strcmp ("text", str) == 0) return META_GTK_COLOR_TEXT; else if (strcmp ("base", str) == 0) return META_GTK_COLOR_BASE; else if (strcmp ("text_aa", str) == 0) return META_GTK_COLOR_TEXT_AA; else return META_GTK_COLOR_LAST; } LOCAL_SYMBOL const char* meta_color_component_to_string (MetaGtkColorComponent component) { switch (component) { case META_GTK_COLOR_FG: return "fg"; case META_GTK_COLOR_BG: return "bg"; case META_GTK_COLOR_LIGHT: return "light"; case META_GTK_COLOR_DARK: return "dark"; case META_GTK_COLOR_MID: return "mid"; case META_GTK_COLOR_TEXT: return "text"; case META_GTK_COLOR_BASE: return "base"; case META_GTK_COLOR_TEXT_AA: return "text_aa"; case META_GTK_COLOR_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaButtonState meta_button_state_from_string (const char *str) { if (strcmp ("normal", str) == 0) return META_BUTTON_STATE_NORMAL; else if (strcmp ("pressed", str) == 0) return META_BUTTON_STATE_PRESSED; else if (strcmp ("prelight", str) == 0) return META_BUTTON_STATE_PRELIGHT; else return META_BUTTON_STATE_LAST; } LOCAL_SYMBOL const char* meta_button_state_to_string (MetaButtonState state) { switch (state) { case META_BUTTON_STATE_NORMAL: return "normal"; case META_BUTTON_STATE_PRESSED: return "pressed"; case META_BUTTON_STATE_PRELIGHT: return "prelight"; case META_BUTTON_STATE_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaButtonType meta_button_type_from_string (const char *str, MetaTheme *theme) { if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)) { if (strcmp ("shade", str) == 0) return META_BUTTON_TYPE_SHADE; else if (strcmp ("above", str) == 0) return META_BUTTON_TYPE_ABOVE; else if (strcmp ("stick", str) == 0) return META_BUTTON_TYPE_STICK; else if (strcmp ("unshade", str) == 0) return META_BUTTON_TYPE_UNSHADE; else if (strcmp ("unabove", str) == 0) return META_BUTTON_TYPE_UNABOVE; else if (strcmp ("unstick", str) == 0) return META_BUTTON_TYPE_UNSTICK; } if (strcmp ("close", str) == 0) return META_BUTTON_TYPE_CLOSE; else if (strcmp ("maximize", str) == 0) return META_BUTTON_TYPE_MAXIMIZE; else if (strcmp ("minimize", str) == 0) return META_BUTTON_TYPE_MINIMIZE; else if (strcmp ("menu", str) == 0) return META_BUTTON_TYPE_MENU; else if (strcmp ("left_left_background", str) == 0) return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND; else if (strcmp ("left_middle_background", str) == 0) return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND; else if (strcmp ("left_right_background", str) == 0) return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND; else if (strcmp ("left_single_background", str) == 0) return META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND; else if (strcmp ("right_left_background", str) == 0) return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND; else if (strcmp ("right_middle_background", str) == 0) return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND; else if (strcmp ("right_right_background", str) == 0) return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND; else if (strcmp ("right_single_background", str) == 0) return META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND; else return META_BUTTON_TYPE_LAST; } LOCAL_SYMBOL const char* meta_button_type_to_string (MetaButtonType type) { switch (type) { case META_BUTTON_TYPE_CLOSE: return "close"; case META_BUTTON_TYPE_MAXIMIZE: return "maximize"; case META_BUTTON_TYPE_MINIMIZE: return "minimize"; case META_BUTTON_TYPE_SHADE: return "shade"; case META_BUTTON_TYPE_ABOVE: return "above"; case META_BUTTON_TYPE_STICK: return "stick"; case META_BUTTON_TYPE_UNSHADE: return "unshade"; case META_BUTTON_TYPE_UNABOVE: return "unabove"; case META_BUTTON_TYPE_UNSTICK: return "unstick"; case META_BUTTON_TYPE_MENU: return "menu"; case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND: return "left_left_background"; case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND: return "left_middle_background"; case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND: return "left_right_background"; case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND: return "left_single_background"; case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND: return "right_left_background"; case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND: return "right_middle_background"; case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND: return "right_right_background"; case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND: return "right_single_background"; case META_BUTTON_TYPE_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaFramePiece meta_frame_piece_from_string (const char *str) { if (strcmp ("entire_background", str) == 0) return META_FRAME_PIECE_ENTIRE_BACKGROUND; else if (strcmp ("titlebar", str) == 0) return META_FRAME_PIECE_TITLEBAR; else if (strcmp ("titlebar_middle", str) == 0) return META_FRAME_PIECE_TITLEBAR_MIDDLE; else if (strcmp ("left_titlebar_edge", str) == 0) return META_FRAME_PIECE_LEFT_TITLEBAR_EDGE; else if (strcmp ("right_titlebar_edge", str) == 0) return META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE; else if (strcmp ("top_titlebar_edge", str) == 0) return META_FRAME_PIECE_TOP_TITLEBAR_EDGE; else if (strcmp ("bottom_titlebar_edge", str) == 0) return META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE; else if (strcmp ("title", str) == 0) return META_FRAME_PIECE_TITLE; else if (strcmp ("left_edge", str) == 0) return META_FRAME_PIECE_LEFT_EDGE; else if (strcmp ("right_edge", str) == 0) return META_FRAME_PIECE_RIGHT_EDGE; else if (strcmp ("bottom_edge", str) == 0) return META_FRAME_PIECE_BOTTOM_EDGE; else if (strcmp ("overlay", str) == 0) return META_FRAME_PIECE_OVERLAY; else return META_FRAME_PIECE_LAST; } LOCAL_SYMBOL const char* meta_frame_piece_to_string (MetaFramePiece piece) { switch (piece) { case META_FRAME_PIECE_ENTIRE_BACKGROUND: return "entire_background"; case META_FRAME_PIECE_TITLEBAR: return "titlebar"; case META_FRAME_PIECE_TITLEBAR_MIDDLE: return "titlebar_middle"; case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE: return "left_titlebar_edge"; case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE: return "right_titlebar_edge"; case META_FRAME_PIECE_TOP_TITLEBAR_EDGE: return "top_titlebar_edge"; case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE: return "bottom_titlebar_edge"; case META_FRAME_PIECE_TITLE: return "title"; case META_FRAME_PIECE_LEFT_EDGE: return "left_edge"; case META_FRAME_PIECE_RIGHT_EDGE: return "right_edge"; case META_FRAME_PIECE_BOTTOM_EDGE: return "bottom_edge"; case META_FRAME_PIECE_OVERLAY: return "overlay"; case META_FRAME_PIECE_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaFrameState meta_frame_state_from_string (const char *str) { if (strcmp ("normal", str) == 0) return META_FRAME_STATE_NORMAL; else if (strcmp ("maximized", str) == 0) return META_FRAME_STATE_MAXIMIZED; else if (strcmp ("tiled_left", str) == 0) return META_FRAME_STATE_TILED_LEFT; else if (strcmp ("tiled_right", str) == 0) return META_FRAME_STATE_TILED_RIGHT; else if (strcmp ("shaded", str) == 0) return META_FRAME_STATE_SHADED; else if (strcmp ("maximized_and_shaded", str) == 0) return META_FRAME_STATE_MAXIMIZED_AND_SHADED; else if (strcmp ("tiled_left_and_shaded", str) == 0) return META_FRAME_STATE_TILED_LEFT_AND_SHADED; else if (strcmp ("tiled_right_and_shaded", str) == 0) return META_FRAME_STATE_TILED_RIGHT_AND_SHADED; else return META_FRAME_STATE_LAST; } LOCAL_SYMBOL const char* meta_frame_state_to_string (MetaFrameState state) { switch (state) { case META_FRAME_STATE_NORMAL: return "normal"; case META_FRAME_STATE_MAXIMIZED: return "maximized"; case META_FRAME_STATE_TILED_LEFT: return "tiled_left"; case META_FRAME_STATE_TILED_RIGHT: return "tiled_right"; case META_FRAME_STATE_SHADED: return "shaded"; case META_FRAME_STATE_MAXIMIZED_AND_SHADED: return "maximized_and_shaded"; case META_FRAME_STATE_TILED_LEFT_AND_SHADED: return "tiled_left_and_shaded"; case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: return "tiled_right_and_shaded"; case META_FRAME_STATE_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaFrameResize meta_frame_resize_from_string (const char *str) { if (strcmp ("none", str) == 0) return META_FRAME_RESIZE_NONE; else if (strcmp ("vertical", str) == 0) return META_FRAME_RESIZE_VERTICAL; else if (strcmp ("horizontal", str) == 0) return META_FRAME_RESIZE_HORIZONTAL; else if (strcmp ("both", str) == 0) return META_FRAME_RESIZE_BOTH; else return META_FRAME_RESIZE_LAST; } LOCAL_SYMBOL const char* meta_frame_resize_to_string (MetaFrameResize resize) { switch (resize) { case META_FRAME_RESIZE_NONE: return "none"; case META_FRAME_RESIZE_VERTICAL: return "vertical"; case META_FRAME_RESIZE_HORIZONTAL: return "horizontal"; case META_FRAME_RESIZE_BOTH: return "both"; case META_FRAME_RESIZE_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaFrameFocus meta_frame_focus_from_string (const char *str) { if (strcmp ("no", str) == 0) return META_FRAME_FOCUS_NO; else if (strcmp ("yes", str) == 0) return META_FRAME_FOCUS_YES; else return META_FRAME_FOCUS_LAST; } LOCAL_SYMBOL const char* meta_frame_focus_to_string (MetaFrameFocus focus) { switch (focus) { case META_FRAME_FOCUS_NO: return "no"; case META_FRAME_FOCUS_YES: return "yes"; case META_FRAME_FOCUS_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaFrameType meta_frame_type_from_string (const char *str) { if (strcmp ("normal", str) == 0) return META_FRAME_TYPE_NORMAL; else if (strcmp ("dialog", str) == 0) return META_FRAME_TYPE_DIALOG; else if (strcmp ("modal_dialog", str) == 0) return META_FRAME_TYPE_MODAL_DIALOG; else if (strcmp ("utility", str) == 0) return META_FRAME_TYPE_UTILITY; else if (strcmp ("menu", str) == 0) return META_FRAME_TYPE_MENU; else if (strcmp ("border", str) == 0) return META_FRAME_TYPE_BORDER; else if (strcmp ("attached", str) == 0) return META_FRAME_TYPE_ATTACHED; #if 0 else if (strcmp ("toolbar", str) == 0) return META_FRAME_TYPE_TOOLBAR; #endif else return META_FRAME_TYPE_LAST; } /** * meta_frame_type_to_string: * * Converts a frame type enum value to the name string that would * appear in the theme definition file. * * Return value: the string value */ const char* meta_frame_type_to_string (MetaFrameType type) { switch (type) { case META_FRAME_TYPE_NORMAL: return "normal"; case META_FRAME_TYPE_DIALOG: return "dialog"; case META_FRAME_TYPE_MODAL_DIALOG: return "modal_dialog"; case META_FRAME_TYPE_UTILITY: return "utility"; case META_FRAME_TYPE_MENU: return "menu"; case META_FRAME_TYPE_BORDER: return "border"; case META_FRAME_TYPE_ATTACHED: return "attached"; #if 0 case META_FRAME_TYPE_TOOLBAR: return "toolbar"; #endif case META_FRAME_TYPE_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL MetaGradientType meta_gradient_type_from_string (const char *str) { if (strcmp ("vertical", str) == 0) return META_GRADIENT_VERTICAL; else if (strcmp ("horizontal", str) == 0) return META_GRADIENT_HORIZONTAL; else if (strcmp ("diagonal", str) == 0) return META_GRADIENT_DIAGONAL; else return META_GRADIENT_LAST; } LOCAL_SYMBOL const char* meta_gradient_type_to_string (MetaGradientType type) { switch (type) { case META_GRADIENT_VERTICAL: return "vertical"; case META_GRADIENT_HORIZONTAL: return "horizontal"; case META_GRADIENT_DIAGONAL: return "diagonal"; case META_GRADIENT_LAST: break; } return "<unknown>"; } LOCAL_SYMBOL GtkStateFlags meta_gtk_state_from_string (const char *str) { if (g_ascii_strcasecmp ("normal", str) == 0) return GTK_STATE_FLAG_NORMAL; else if (g_ascii_strcasecmp ("prelight", str) == 0) return GTK_STATE_FLAG_PRELIGHT; else if (g_ascii_strcasecmp ("active", str) == 0) return GTK_STATE_FLAG_ACTIVE; else if (g_ascii_strcasecmp ("selected", str) == 0) return GTK_STATE_FLAG_SELECTED; else if (g_ascii_strcasecmp ("insensitive", str) == 0) return GTK_STATE_FLAG_INSENSITIVE; else if (g_ascii_strcasecmp ("inconsistent", str) == 0) return GTK_STATE_FLAG_INCONSISTENT; else if (g_ascii_strcasecmp ("focused", str) == 0) return GTK_STATE_FLAG_FOCUSED; else if (g_ascii_strcasecmp ("backdrop", str) == 0) return GTK_STATE_FLAG_BACKDROP; else return -1; /* hack */ } LOCAL_SYMBOL const char* meta_gtk_state_to_string (GtkStateFlags state) { switch (state) { case GTK_STATE_FLAG_NORMAL: return "NORMAL"; case GTK_STATE_FLAG_PRELIGHT: return "PRELIGHT"; case GTK_STATE_FLAG_ACTIVE: return "ACTIVE"; case GTK_STATE_FLAG_SELECTED: return "SELECTED"; case GTK_STATE_FLAG_INSENSITIVE: return "INSENSITIVE"; case GTK_STATE_FLAG_INCONSISTENT: return "INCONSISTENT"; case GTK_STATE_FLAG_FOCUSED: return "FOCUSED"; case GTK_STATE_FLAG_BACKDROP: return "BACKDROP"; #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 7) case GTK_STATE_FLAG_DIR_LTR: return "DIR_LTR"; case GTK_STATE_FLAG_DIR_RTL: return "DIR_RTL"; #endif #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 12) case GTK_STATE_FLAG_LINK: return "LINK"; case GTK_STATE_FLAG_VISITED: return "VISITED"; #endif #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 14) case GTK_STATE_FLAG_CHECKED: return "CHECKED"; #endif } return "<unknown>"; } LOCAL_SYMBOL GtkShadowType meta_gtk_shadow_from_string (const char *str) { if (strcmp ("none", str) == 0) return GTK_SHADOW_NONE; else if (strcmp ("in", str) == 0) return GTK_SHADOW_IN; else if (strcmp ("out", str) == 0) return GTK_SHADOW_OUT; else if (strcmp ("etched_in", str) == 0) return GTK_SHADOW_ETCHED_IN; else if (strcmp ("etched_out", str) == 0) return GTK_SHADOW_ETCHED_OUT; else return -1; } LOCAL_SYMBOL const char* meta_gtk_shadow_to_string (GtkShadowType shadow) { switch (shadow) { case GTK_SHADOW_NONE: return "none"; case GTK_SHADOW_IN: return "in"; case GTK_SHADOW_OUT: return "out"; case GTK_SHADOW_ETCHED_IN: return "etched_in"; case GTK_SHADOW_ETCHED_OUT: return "etched_out"; } return "<unknown>"; } LOCAL_SYMBOL GtkArrowType meta_gtk_arrow_from_string (const char *str) { if (strcmp ("up", str) == 0) return GTK_ARROW_UP; else if (strcmp ("down", str) == 0) return GTK_ARROW_DOWN; else if (strcmp ("left", str) == 0) return GTK_ARROW_LEFT; else if (strcmp ("right", str) == 0) return GTK_ARROW_RIGHT; else if (strcmp ("none", str) == 0) return GTK_ARROW_NONE; else return -1; } LOCAL_SYMBOL const char* meta_gtk_arrow_to_string (GtkArrowType arrow) { switch (arrow) { case GTK_ARROW_UP: return "up"; case GTK_ARROW_DOWN: return "down"; case GTK_ARROW_LEFT: return "left"; case GTK_ARROW_RIGHT: return "right"; case GTK_ARROW_NONE: return "none"; } return "<unknown>"; } /* * Returns a fill_type from a string. The inverse of * meta_image_fill_type_to_string(). * * \param str a string representing a fill_type * \result the fill_type, or -1 if it represents no fill_type. */ LOCAL_SYMBOL MetaImageFillType meta_image_fill_type_from_string (const char *str) { if (strcmp ("tile", str) == 0) return META_IMAGE_FILL_TILE; else if (strcmp ("scale", str) == 0) return META_IMAGE_FILL_SCALE; else return -1; } /* * Returns a string representation of a fill_type. The inverse of * meta_image_fill_type_from_string(). * * \param fill_type the fill type * \result a string representing that type */ LOCAL_SYMBOL const char* meta_image_fill_type_to_string (MetaImageFillType fill_type) { switch (fill_type) { case META_IMAGE_FILL_TILE: return "tile"; case META_IMAGE_FILL_SCALE: return "scale"; } return "<unknown>"; } /* * Takes a colour "a", scales the lightness and saturation by a certain amount, * and sets "b" to the resulting colour. * gtkstyle.c cut-and-pastage. * * \param a the starting colour * \param b [out] the resulting colour * \param k amount to scale lightness and saturation by */ static void gtk_style_shade (GdkRGBA *a, GdkRGBA *b, gdouble k) { gdouble red; gdouble green; gdouble blue; red = a->red; green = a->green; blue = a->blue; rgb_to_hls (&red, &green, &blue); green *= k; if (green > 1.0) green = 1.0; else if (green < 0.0) green = 0.0; blue *= k; if (blue > 1.0) blue = 1.0; else if (blue < 0.0) blue = 0.0; hls_to_rgb (&red, &green, &blue); b->red = red; b->green = green; b->blue = blue; } /* * Converts a red/green/blue triplet to a hue/lightness/saturation triplet. * * \param r on input, red; on output, hue * \param g on input, green; on output, lightness * \param b on input, blue; on output, saturation */ static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b) { gdouble min; gdouble max; gdouble red; gdouble green; gdouble blue; gdouble h, l, s; gdouble delta; red = *r; green = *g; blue = *b; if (red > green) { if (red > blue) max = red; else max = blue; if (green < blue) min = green; else min = blue; } else { if (green > blue) max = green; else max = blue; if (red < blue) min = red; else min = blue; } l = (max + min) / 2; s = 0; h = 0; if (max != min) { if (l <= 0.5) s = (max - min) / (max + min); else s = (max - min) / (2 - max - min); delta = max -min; if (red == max) h = (green - blue) / delta; else if (green == max) h = 2 + (blue - red) / delta; else if (blue == max) h = 4 + (red - green) / delta; h *= 60; if (h < 0.0) h += 360; } *r = h; *g = l; *b = s; } /* * Converts a hue/lightness/saturation triplet to a red/green/blue triplet. * * \param h on input, hue; on output, red * \param l on input, lightness; on output, green * \param s on input, saturation; on output, blue */ static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s) { gdouble hue; gdouble lightness; gdouble saturation; gdouble m1, m2; gdouble r, g, b; lightness = *l; saturation = *s; if (lightness <= 0.5) m2 = lightness * (1 + saturation); else m2 = lightness + saturation - lightness * saturation; m1 = 2 * lightness - m2; if (saturation == 0) { *h = lightness; *l = lightness; *s = lightness; } else { hue = *h + 120; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) r = m1 + (m2 - m1) * hue / 60; else if (hue < 180) r = m2; else if (hue < 240) r = m1 + (m2 - m1) * (240 - hue) / 60; else r = m1; hue = *h; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) g = m1 + (m2 - m1) * hue / 60; else if (hue < 180) g = m2; else if (hue < 240) g = m1 + (m2 - m1) * (240 - hue) / 60; else g = m1; hue = *h - 120; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; if (hue < 60) b = m1 + (m2 - m1) * hue / 60; else if (hue < 180) b = m2; else if (hue < 240) b = m1 + (m2 - m1) * (240 - hue) / 60; else b = m1; *h = r; *l = g; *s = b; } } #if 0 /* These are some functions I'm saving to use in optimizing * MetaDrawOpList, namely to pre-composite pixbufs on client side * prior to rendering to the server */ static void draw_bg_solid_composite (const MetaTextureSpec *bg, const MetaTextureSpec *fg, double alpha, GtkWidget *widget, GdkDrawable *drawable, const GdkRectangle *clip, MetaTextureDrawMode mode, double xalign, double yalign, int x, int y, int width, int height) { GdkRGBA bg_color; g_assert (bg->type == META_TEXTURE_SOLID); g_assert (fg->type != META_TEXTURE_COMPOSITE); g_assert (fg->type != META_TEXTURE_SHAPE_LIST); meta_color_spec_render (bg->data.solid.color_spec, widget, &bg_color); switch (fg->type) { case META_TEXTURE_SOLID: { GdkRGBA fg_color; meta_color_spec_render (fg->data.solid.color_spec, widget, &fg_color); color_composite (&bg_color, &fg_color, alpha, &fg_color); draw_color_rectangle (widget, drawable, &fg_color, clip, x, y, width, height); } break; case META_TEXTURE_GRADIENT: /* FIXME I think we could just composite all the colors in * the gradient prior to generating the gradient? */ /* FALL THRU */ case META_TEXTURE_IMAGE: { GdkPixbuf *pixbuf; GdkPixbuf *composited; pixbuf = meta_texture_spec_render (fg, widget, mode, 255, width, height); if (pixbuf == NULL) return; composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha (pixbuf), 8, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); if (composited == NULL) { g_object_unref (G_OBJECT (pixbuf)); return; } gdk_pixbuf_composite_color (pixbuf, composited, 0, 0, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), 0.0, 0.0, /* offsets */ 1.0, 1.0, /* scale */ GDK_INTERP_BILINEAR, 255 * alpha, 0, 0, /* check offsets */ 0, /* check size */ GDK_COLOR_RGB (bg_color), GDK_COLOR_RGB (bg_color)); /* Need to draw background since pixbuf is not * necessarily covering the whole thing */ draw_color_rectangle (widget, drawable, &bg_color, clip, x, y, width, height); render_pixbuf_aligned (drawable, clip, composited, xalign, yalign, x, y, width, height); g_object_unref (G_OBJECT (pixbuf)); g_object_unref (G_OBJECT (composited)); } break; case META_TEXTURE_BLANK: case META_TEXTURE_COMPOSITE: case META_TEXTURE_SHAPE_LIST: g_assert_not_reached (); break; } } static void draw_bg_gradient_composite (const MetaTextureSpec *bg, const MetaTextureSpec *fg, double alpha, GtkWidget *widget, GdkDrawable *drawable, const GdkRectangle *clip, MetaTextureDrawMode mode, double xalign, double yalign, int x, int y, int width, int height) { g_assert (bg->type == META_TEXTURE_GRADIENT); g_assert (fg->type != META_TEXTURE_COMPOSITE); g_assert (fg->type != META_TEXTURE_SHAPE_LIST); switch (fg->type) { case META_TEXTURE_SOLID: case META_TEXTURE_GRADIENT: case META_TEXTURE_IMAGE: { GdkPixbuf *bg_pixbuf; GdkPixbuf *fg_pixbuf; GdkPixbuf *composited; int fg_width, fg_height; bg_pixbuf = meta_texture_spec_render (bg, widget, mode, 255, width, height); if (bg_pixbuf == NULL) return; fg_pixbuf = meta_texture_spec_render (fg, widget, mode, 255, width, height); if (fg_pixbuf == NULL) { g_object_unref (G_OBJECT (bg_pixbuf)); return; } /* gradients always fill the entire target area */ g_assert (gdk_pixbuf_get_width (bg_pixbuf) == width); g_assert (gdk_pixbuf_get_height (bg_pixbuf) == height); composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha (bg_pixbuf), 8, gdk_pixbuf_get_width (bg_pixbuf), gdk_pixbuf_get_height (bg_pixbuf)); if (composited == NULL) { g_object_unref (G_OBJECT (bg_pixbuf)); g_object_unref (G_OBJECT (fg_pixbuf)); return; } fg_width = gdk_pixbuf_get_width (fg_pixbuf); fg_height = gdk_pixbuf_get_height (fg_pixbuf); /* If we wanted to be all cool we could deal with the * offsets and try to composite only in the clip rectangle, * but I just don't care enough to figure it out. */ gdk_pixbuf_composite (fg_pixbuf, composited, x + (width - fg_width) * xalign, y + (height - fg_height) * yalign, gdk_pixbuf_get_width (fg_pixbuf), gdk_pixbuf_get_height (fg_pixbuf), 0.0, 0.0, /* offsets */ 1.0, 1.0, /* scale */ GDK_INTERP_BILINEAR, 255 * alpha); gdk_cairo_set_source_pixbuf (cr, composited, x, y); cairo_paint (cr); g_object_unref (G_OBJECT (bg_pixbuf)); g_object_unref (G_OBJECT (fg_pixbuf)); g_object_unref (G_OBJECT (composited)); } break; case META_TEXTURE_BLANK: case META_TEXTURE_SHAPE_LIST: case META_TEXTURE_COMPOSITE: g_assert_not_reached (); break; } } #endif /* * Returns the earliest version of the theme format which required support * for a particular button. (For example, "shade" first appeared in v2, and * "close" in v1.) * * \param type the button type * \return the number of the theme format */ LOCAL_SYMBOL guint meta_theme_earliest_version_with_button (MetaButtonType type) { switch (type) { case META_BUTTON_TYPE_CLOSE: case META_BUTTON_TYPE_MAXIMIZE: case META_BUTTON_TYPE_MINIMIZE: case META_BUTTON_TYPE_MENU: case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND: case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND: case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND: case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND: case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND: case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND: return 1000; case META_BUTTON_TYPE_SHADE: case META_BUTTON_TYPE_ABOVE: case META_BUTTON_TYPE_STICK: case META_BUTTON_TYPE_UNSHADE: case META_BUTTON_TYPE_UNABOVE: case META_BUTTON_TYPE_UNSTICK: return 2000; case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND: case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND: return 3003; default: meta_warning("Unknown button %d\n", type); return 1000; } } �����������������������������������������������������������������������������������������muffin-5.2.1/src/ui/theme-private.h�����������������������������������������������������������������0000664�0001750�0001750�00000122053�14211404421�017266� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity Theme Rendering */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_THEME_PRIVATE_H #define META_THEME_PRIVATE_H #include <meta/boxes.h> #include <meta/gradient.h> #include <meta/theme.h> #include <meta/common.h> #include <gtk/gtk.h> /** * MetaFrameStyle: (skip) * */ typedef struct _MetaFrameStyle MetaFrameStyle; /** * MetaFrameStyleSet: (skip) * */ typedef struct _MetaFrameStyleSet MetaFrameStyleSet; /** * MetaDrawOp: (skip) * */ typedef struct _MetaDrawOp MetaDrawOp; /** * MetaDrawOpList: (skip) * */ typedef struct _MetaDrawOpList MetaDrawOpList; /** * MetaGradientSpec: (skip) * */ typedef struct _MetaGradientSpec MetaGradientSpec; /** * MetaAlphaGradientSpec: (skip) * */ typedef struct _MetaAlphaGradientSpec MetaAlphaGradientSpec; /** * MetaColorSpec: (skip) * */ typedef struct _MetaColorSpec MetaColorSpec; /** * MetaFrameLayout: (skip) * */ typedef struct _MetaFrameLayout MetaFrameLayout; /** * MetaButtonSpace: (skip) * */ typedef struct _MetaButtonSpace MetaButtonSpace; /** * MetaFrameGeometry: (skip) * */ typedef struct _MetaFrameGeometry MetaFrameGeometry; /** * MetaPositionExprEnv: (skip) * */ typedef struct _MetaPositionExprEnv MetaPositionExprEnv; /** * MetaDrawInfo: (skip) * */ typedef struct _MetaDrawInfo MetaDrawInfo; #define META_THEME_ERROR (g_quark_from_static_string ("meta-theme-error")) typedef enum { META_THEME_ERROR_FRAME_GEOMETRY, META_THEME_ERROR_BAD_CHARACTER, META_THEME_ERROR_BAD_PARENS, META_THEME_ERROR_UNKNOWN_VARIABLE, META_THEME_ERROR_DIVIDE_BY_ZERO, META_THEME_ERROR_MOD_ON_FLOAT, META_THEME_ERROR_FAILED } MetaThemeError; /** * Whether a button's size is calculated from the area around it (aspect * sizing) or is given as a fixed height and width in pixels (fixed sizing). * * \bug This could be done away with; see the comment at the top of * MetaFrameLayout. */ typedef enum { META_BUTTON_SIZING_ASPECT, META_BUTTON_SIZING_FIXED, META_BUTTON_SIZING_LAST } MetaButtonSizing; /** * Various parameters used to calculate the geometry of a frame. * They are used inside a MetaFrameStyle. * This corresponds closely to the <frame_geometry> tag in a theme file. * * \bug button_sizing isn't really necessary, because we could easily say * that if button_aspect is zero, the height and width are fixed values. * This would also mean that MetaButtonSizing didn't need to exist, and * save code. **/ struct _MetaFrameLayout { /** Reference count. */ int refcount; /** Size of left side */ int left_width; /** Size of right side */ int right_width; /** Size of bottom side */ int bottom_height; /** Border of blue title region * \bug (blue?!) **/ GtkBorder title_border; /** Extra height for inside of title region, above the font height */ int title_vertical_pad; /** Right indent of buttons from edges of frame */ int right_titlebar_edge; /** Left indent of buttons from edges of frame */ int left_titlebar_edge; /** * Sizing rule of buttons, either META_BUTTON_SIZING_ASPECT * (in which case button_aspect will be honoured, and * button_width and button_height set from it), or * META_BUTTON_SIZING_FIXED (in which case we read the width * and height directly). */ MetaButtonSizing button_sizing; /** * Ratio of height/width. Honoured only if * button_sizing==META_BUTTON_SIZING_ASPECT. * Otherwise we figure out the height from the button_border. */ double button_aspect; /** Width of a button; set even when we are using aspect sizing */ int button_width; /** Height of a button; set even when we are using aspect sizing */ int button_height; /** Space around buttons */ GtkBorder button_border; /** scale factor for title text */ double title_scale; /** Whether title text will be displayed */ guint has_title : 1; /** Whether we should hide the buttons */ guint hide_buttons : 1; /** Radius of the top left-hand corner; 0 if not rounded */ guint top_left_corner_rounded_radius; /** Radius of the top right-hand corner; 0 if not rounded */ guint top_right_corner_rounded_radius; /** Radius of the bottom left-hand corner; 0 if not rounded */ guint bottom_left_corner_rounded_radius; /** Radius of the bottom right-hand corner; 0 if not rounded */ guint bottom_right_corner_rounded_radius; }; /** * The computed size of a button (really just a way of tying its * visible and clickable areas together). * The reason for two different rectangles here is Fitts' law & maximized * windows; see bug #97703 for more details. */ struct _MetaButtonSpace { /** The screen area where the button's image is drawn */ GdkRectangle visible; /** The screen area where the button can be activated by clicking */ GdkRectangle clickable; }; /** * Calculated actual geometry of the frame */ struct _MetaFrameGeometry { MetaFrameBorders borders; int width; int height; GdkRectangle title_rect; int left_titlebar_edge; int right_titlebar_edge; int top_titlebar_edge; int bottom_titlebar_edge; /* used for a memset hack */ #define ADDRESS_OF_BUTTON_RECTS(fgeom) (((char*)(fgeom)) + G_STRUCT_OFFSET (MetaFrameGeometry, close_rect)) #define LENGTH_OF_BUTTON_RECTS (G_STRUCT_OFFSET (MetaFrameGeometry, right_single_background) + sizeof (GdkRectangle) - G_STRUCT_OFFSET (MetaFrameGeometry, close_rect)) /* The button rects (if changed adjust memset hack) */ MetaButtonSpace close_rect; MetaButtonSpace max_rect; MetaButtonSpace min_rect; MetaButtonSpace menu_rect; MetaButtonSpace shade_rect; MetaButtonSpace above_rect; MetaButtonSpace stick_rect; MetaButtonSpace unshade_rect; MetaButtonSpace unabove_rect; MetaButtonSpace unstick_rect; #define MAX_MIDDLE_BACKGROUNDS (MAX_BUTTONS_PER_CORNER - 2) GdkRectangle left_left_background; GdkRectangle left_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS]; GdkRectangle left_right_background; GdkRectangle left_single_background; GdkRectangle right_left_background; GdkRectangle right_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS]; GdkRectangle right_right_background; GdkRectangle right_single_background; /* End of button rects (if changed adjust memset hack) */ /* Saved button layout */ MetaButtonLayout button_layout; int n_left_buttons; int n_right_buttons; /* Round corners */ guint top_left_corner_rounded_radius; guint top_right_corner_rounded_radius; guint bottom_left_corner_rounded_radius; guint bottom_right_corner_rounded_radius; }; typedef enum { META_IMAGE_FILL_SCALE, /* default, needs to be all-bits-zero for g_new0 */ META_IMAGE_FILL_TILE } MetaImageFillType; typedef enum { META_COLOR_SPEC_BASIC, META_COLOR_SPEC_GTK, META_COLOR_SPEC_GTK_CUSTOM, META_COLOR_SPEC_BLEND, META_COLOR_SPEC_SHADE } MetaColorSpecType; typedef enum { META_GTK_COLOR_FG, META_GTK_COLOR_BG, META_GTK_COLOR_LIGHT, META_GTK_COLOR_DARK, META_GTK_COLOR_MID, META_GTK_COLOR_TEXT, META_GTK_COLOR_BASE, META_GTK_COLOR_TEXT_AA, META_GTK_COLOR_LAST } MetaGtkColorComponent; struct _MetaColorSpec { MetaColorSpecType type; union { struct { GdkRGBA color; } basic; struct { MetaGtkColorComponent component; GtkStateFlags state; } gtk; struct { char *color_name; MetaColorSpec *fallback; } gtkcustom; struct { MetaColorSpec *foreground; MetaColorSpec *background; double alpha; GdkRGBA color; } blend; struct { MetaColorSpec *base; double factor; GdkRGBA color; } shade; } data; }; struct _MetaGradientSpec { MetaGradientType type; GSList *color_specs; }; struct _MetaAlphaGradientSpec { MetaGradientType type; unsigned char *alphas; int n_alphas; }; struct _MetaDrawInfo { PangoLayout *title_layout; int title_layout_width; int title_layout_height; const MetaFrameGeometry *fgeom; }; /** * A drawing operation in our simple vector drawing language. */ typedef enum { /** Basic drawing-- line */ META_DRAW_LINE, /** Basic drawing-- rectangle */ META_DRAW_RECTANGLE, /** Basic drawing-- arc */ META_DRAW_ARC, /** Clip to a rectangle */ META_DRAW_CLIP, /* Texture thingies */ /** Just a filled rectangle with alpha */ META_DRAW_TINT, META_DRAW_GRADIENT, META_DRAW_IMAGE, /** GTK theme engine stuff */ META_DRAW_GTK_ARROW, META_DRAW_GTK_BOX, META_DRAW_GTK_VLINE, /** App's window icon */ META_DRAW_ICON, /** App's window title */ META_DRAW_TITLE, /** a draw op list */ META_DRAW_OP_LIST, /** tiled draw op list */ META_DRAW_TILE } MetaDrawType; typedef enum { POS_TOKEN_INT, POS_TOKEN_DOUBLE, POS_TOKEN_OPERATOR, POS_TOKEN_VARIABLE, POS_TOKEN_OPEN_PAREN, POS_TOKEN_CLOSE_PAREN } PosTokenType; typedef enum { POS_OP_NONE, POS_OP_ADD, POS_OP_SUBTRACT, POS_OP_MULTIPLY, POS_OP_DIVIDE, POS_OP_MOD, POS_OP_MAX, POS_OP_MIN } PosOperatorType; /** * A token, as output by the tokeniser. * * \ingroup tokenizer */ typedef struct { PosTokenType type; union { struct { int val; } i; struct { double val; } d; struct { PosOperatorType op; } o; struct { char *name; GQuark name_quark; } v; } d; } PosToken; /** * MetaDrawSpec: (skip) * * A computed expression in our simple vector drawing language. * While it appears to take the form of a tree, this is actually * merely a list; concerns such as precedence of operators are * currently recomputed on every recalculation. * * Created by meta_draw_spec_new(), destroyed by meta_draw_spec_free(). * pos_eval() fills this with ...FIXME. Are tokens a tree or a list? * \ingroup parser */ typedef struct _MetaDrawSpec MetaDrawSpec; struct _MetaDrawSpec { /** * If this spec is constant, this is the value of the constant; * otherwise it is zero. */ int value; /** A list of tokens in the expression. */ PosToken *tokens; /** How many tokens are in the tokens list. */ int n_tokens; /** Does the expression contain any variables? */ gboolean constant : 1; }; /** * A single drawing operation in our simple vector drawing language. */ struct _MetaDrawOp { MetaDrawType type; /* Positions are strings because they can be expressions */ union { struct { MetaColorSpec *color_spec; int dash_on_length; int dash_off_length; int width; MetaDrawSpec *x1; MetaDrawSpec *y1; MetaDrawSpec *x2; MetaDrawSpec *y2; } line; struct { MetaColorSpec *color_spec; gboolean filled; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; } rectangle; struct { MetaColorSpec *color_spec; gboolean filled; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; double start_angle; double extent_angle; } arc; struct { MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; } clip; struct { MetaColorSpec *color_spec; MetaAlphaGradientSpec *alpha_spec; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; } tint; struct { MetaGradientSpec *gradient_spec; MetaAlphaGradientSpec *alpha_spec; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; } gradient; struct { MetaColorSpec *colorize_spec; MetaAlphaGradientSpec *alpha_spec; GdkPixbuf *pixbuf; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; guint32 colorize_cache_pixel; GdkPixbuf *colorize_cache_pixbuf; MetaImageFillType fill_type; unsigned int vertical_stripes : 1; unsigned int horizontal_stripes : 1; } image; struct { GtkStateFlags state; GtkShadowType shadow; GtkArrowType arrow; gboolean filled; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; } gtk_arrow; struct { GtkStateFlags state; GtkShadowType shadow; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; } gtk_box; struct { GtkStateFlags state; MetaDrawSpec *x; MetaDrawSpec *y1; MetaDrawSpec *y2; } gtk_vline; struct { MetaAlphaGradientSpec *alpha_spec; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; MetaImageFillType fill_type; } icon; struct { MetaColorSpec *color_spec; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *ellipsize_width; } title; struct { MetaDrawOpList *op_list; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; } op_list; struct { MetaDrawOpList *op_list; MetaDrawSpec *x; MetaDrawSpec *y; MetaDrawSpec *width; MetaDrawSpec *height; MetaDrawSpec *tile_xoffset; MetaDrawSpec *tile_yoffset; MetaDrawSpec *tile_width; MetaDrawSpec *tile_height; } tile; } data; }; /** * A list of MetaDrawOp objects. Maintains a reference count. * Grows as necessary and allows the allocation of unused spaces * to keep reallocations to a minimum. * * \bug Do we really win anything from not using the equivalent * GLib structures? */ struct _MetaDrawOpList { int refcount; MetaDrawOp **ops; int n_ops; int n_allocated; }; typedef enum { META_BUTTON_STATE_NORMAL, META_BUTTON_STATE_PRESSED, META_BUTTON_STATE_PRELIGHT, META_BUTTON_STATE_LAST } MetaButtonState; typedef enum { /* Ordered so that background is drawn first */ META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND, META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND, META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND, META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND, META_BUTTON_TYPE_CLOSE, META_BUTTON_TYPE_MAXIMIZE, META_BUTTON_TYPE_MINIMIZE, META_BUTTON_TYPE_MENU, META_BUTTON_TYPE_SHADE, META_BUTTON_TYPE_ABOVE, META_BUTTON_TYPE_STICK, META_BUTTON_TYPE_UNSHADE, META_BUTTON_TYPE_UNABOVE, META_BUTTON_TYPE_UNSTICK, META_BUTTON_TYPE_LAST } MetaButtonType; typedef enum { META_MENU_ICON_TYPE_CLOSE, META_MENU_ICON_TYPE_MAXIMIZE, META_MENU_ICON_TYPE_UNMAXIMIZE, META_MENU_ICON_TYPE_MINIMIZE, META_MENU_ICON_TYPE_LAST } MetaMenuIconType; typedef enum { /* Listed in the order in which the textures are drawn. * (though this only matters for overlaps of course.) * Buttons are drawn after the frame textures. * * On the corners, horizontal pieces are arbitrarily given the * corner area: * * ===== |==== * | | * | rather than | * */ /* entire frame */ META_FRAME_PIECE_ENTIRE_BACKGROUND, /* entire titlebar background */ META_FRAME_PIECE_TITLEBAR, /* portion of the titlebar background inside the titlebar * background edges */ META_FRAME_PIECE_TITLEBAR_MIDDLE, /* left end of titlebar */ META_FRAME_PIECE_LEFT_TITLEBAR_EDGE, /* right end of titlebar */ META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE, /* top edge of titlebar */ META_FRAME_PIECE_TOP_TITLEBAR_EDGE, /* bottom edge of titlebar */ META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE, /* render over title background (text area) */ META_FRAME_PIECE_TITLE, /* left edge of the frame */ META_FRAME_PIECE_LEFT_EDGE, /* right edge of the frame */ META_FRAME_PIECE_RIGHT_EDGE, /* bottom edge of the frame */ META_FRAME_PIECE_BOTTOM_EDGE, /* place over entire frame, after drawing everything else */ META_FRAME_PIECE_OVERLAY, /* Used to get size of the enum */ META_FRAME_PIECE_LAST } MetaFramePiece; /** * How to draw a frame in a particular state (say, a focussed, non-maximised, * resizable frame). This corresponds closely to the <frame_style> tag * in a theme file. */ struct _MetaFrameStyle { /** Reference count. */ int refcount; /** * Parent style. * Settings which are unspecified here will be taken from there. */ MetaFrameStyle *parent; /** Operations for drawing each kind of button in each state. */ MetaDrawOpList *buttons[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST]; /** Operations for drawing each piece of the frame. */ MetaDrawOpList *pieces[META_FRAME_PIECE_LAST]; /** * Details such as the height and width of each edge, the corner rounding, * and the aspect ratio of the buttons. */ MetaFrameLayout *layout; /** * Background colour of the window. Only present in theme formats * 2 and above. Can be NULL to use the standard GTK theme engine. */ MetaColorSpec *window_background_color; /** * Transparency of the window background. 0=transparent; 255=opaque. */ guint8 window_background_alpha; }; /* Kinds of frame... * * normal -> noresize / vert only / horz only / both * focused / unfocused * max -> focused / unfocused * shaded -> focused / unfocused * max/shaded -> focused / unfocused * * so 4 states with 8 sub-states in one, 2 sub-states in the other 3, * meaning 14 total * * 14 window states times 7 or 8 window types. Except some * window types never get a frame so that narrows it down a bit. * */ typedef enum { META_FRAME_STATE_NORMAL, META_FRAME_STATE_MAXIMIZED, META_FRAME_STATE_TILED_LEFT, META_FRAME_STATE_TILED_RIGHT, META_FRAME_STATE_SHADED, META_FRAME_STATE_MAXIMIZED_AND_SHADED, META_FRAME_STATE_TILED_LEFT_AND_SHADED, META_FRAME_STATE_TILED_RIGHT_AND_SHADED, META_FRAME_STATE_LAST } MetaFrameState; typedef enum { META_FRAME_RESIZE_NONE, META_FRAME_RESIZE_VERTICAL, META_FRAME_RESIZE_HORIZONTAL, META_FRAME_RESIZE_BOTH, META_FRAME_RESIZE_LAST } MetaFrameResize; typedef enum { META_FRAME_FOCUS_NO, META_FRAME_FOCUS_YES, META_FRAME_FOCUS_LAST } MetaFrameFocus; /** * How to draw frames at different times: when it's maximised or not, shaded * or not, when it's focussed or not, and (for non-maximised windows), when * it can be horizontally or vertically resized, both, or neither. * Not all window types actually get a frame. * * A theme contains one of these objects for each type of window (each * MetaFrameType), that is, normal, dialogue (modal and non-modal), etc. * * This corresponds closely to the <frame_style_set> tag in a theme file. */ struct _MetaFrameStyleSet { int refcount; MetaFrameStyleSet *parent; MetaFrameStyle *normal_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST]; MetaFrameStyle *maximized_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_left_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_right_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_ulc_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_llc_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_urc_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_lrc_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *shaded_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST]; MetaFrameStyle *maximized_and_shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_left_and_shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_right_and_shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_ulc_and_shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_llc_and_shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_urc_and_shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *tiled_lrc_and_shaded_styles[META_FRAME_FOCUS_LAST]; }; /** * A theme. This is a singleton class which groups all settings from a theme * on disk together. * * \bug It is rather useless to keep the metadata fields in core, I think. */ struct _MetaTheme { /** Name of the theme (on disk), e.g. "Crux" */ char *name; /** Path to the files associated with the theme */ char *dirname; /** * Filename of the XML theme file. * \bug Kept lying around for no discernable reason. */ char *filename; /** Metadata: Human-readable name of the theme. */ char *readable_name; /** Metadata: Author of the theme. */ char *author; /** Metadata: Copyright holder. */ char *copyright; /** Metadata: Date of the theme. */ char *date; /** Metadata: Description of the theme. */ char *description; /** Version of the theme format. Older versions cannot use the features * of newer versions even if they think they can (this is to allow forward * and backward compatibility. */ guint format_version; guint scale; /** Symbol table of integer constants. */ GHashTable *integer_constants; /** Symbol table of float constants. */ GHashTable *float_constants; /** * Symbol table of colour constants (hex triples, and triples * plus alpha). * */ GHashTable *color_constants; GHashTable *images_by_filename; GHashTable *layouts_by_name; GHashTable *draw_op_lists_by_name; GHashTable *styles_by_name; GHashTable *style_sets_by_name; MetaFrameStyleSet *style_sets_by_type[META_FRAME_TYPE_LAST]; GQuark quark_width; GQuark quark_height; GQuark quark_object_width; GQuark quark_object_height; GQuark quark_left_width; GQuark quark_right_width; GQuark quark_top_height; GQuark quark_bottom_height; GQuark quark_mini_icon_width; GQuark quark_mini_icon_height; GQuark quark_icon_width; GQuark quark_icon_height; GQuark quark_title_width; GQuark quark_title_height; GQuark quark_frame_x_center; GQuark quark_frame_y_center; }; struct _MetaPositionExprEnv { MetaRectangle rect; /* size of an object being drawn, if it has a natural size */ int object_width; int object_height; /* global object sizes, always available */ int left_width; int right_width; int top_height; int bottom_height; int title_width; int title_height; int frame_x_center; int frame_y_center; int mini_icon_width; int mini_icon_height; int icon_width; int icon_height; /* Theme so we can look up constants */ MetaTheme *theme; }; MetaFrameLayout* meta_frame_layout_new (void); MetaFrameLayout* meta_frame_layout_copy (const MetaFrameLayout *src); void meta_frame_layout_ref (MetaFrameLayout *layout); void meta_frame_layout_unref (MetaFrameLayout *layout); void meta_frame_layout_get_borders (const MetaFrameLayout *layout, int text_height, MetaFrameFlags flags, MetaFrameType type, MetaFrameBorders *borders); void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout, int text_height, MetaFrameFlags flags, int client_width, int client_height, const MetaButtonLayout *button_layout, MetaFrameType type, MetaFrameGeometry *fgeom, MetaTheme *theme); gboolean meta_frame_layout_validate (const MetaFrameLayout *layout, GError **error); gboolean meta_parse_position_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *x_return, int *y_return, GError **err); gboolean meta_parse_size_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *val_return, GError **err); MetaDrawSpec* meta_draw_spec_new (MetaTheme *theme, const char *expr, GError **error); void meta_draw_spec_free (MetaDrawSpec *spec); MetaColorSpec* meta_color_spec_new (MetaColorSpecType type); MetaColorSpec* meta_color_spec_new_from_string (const char *str, GError **err); MetaColorSpec* meta_color_spec_new_gtk (MetaGtkColorComponent component, GtkStateFlags state); void meta_color_spec_free (MetaColorSpec *spec); void meta_color_spec_render (MetaColorSpec *spec, GtkStyleContext *style_gtk, GdkRGBA *color); MetaDrawOp* meta_draw_op_new (MetaDrawType type); void meta_draw_op_free (MetaDrawOp *op); void meta_draw_op_draw (const MetaDrawOp *op, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, /* logical region being drawn */ MetaRectangle logical_region); void meta_draw_op_draw_with_style (const MetaDrawOp *op, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, /* logical region being drawn */ MetaRectangle logical_region); MetaDrawOpList* meta_draw_op_list_new (int n_preallocs); void meta_draw_op_list_ref (MetaDrawOpList *op_list); void meta_draw_op_list_unref (MetaDrawOpList *op_list); void meta_draw_op_list_draw (const MetaDrawOpList *op_list, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, MetaRectangle rect); void meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, const MetaDrawInfo *info, MetaRectangle rect); void meta_draw_op_list_append (MetaDrawOpList *op_list, MetaDrawOp *op); gboolean meta_draw_op_list_validate (MetaDrawOpList *op_list, GError **error); gboolean meta_draw_op_list_contains (MetaDrawOpList *op_list, MetaDrawOpList *child); MetaGradientSpec* meta_gradient_spec_new (MetaGradientType type); void meta_gradient_spec_free (MetaGradientSpec *desc); GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *desc, GtkStyleContext *gtk_style, int width, int height); gboolean meta_gradient_spec_validate (MetaGradientSpec *spec, GError **error); MetaAlphaGradientSpec* meta_alpha_gradient_spec_new (MetaGradientType type, int n_alphas); void meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec); MetaFrameStyle* meta_frame_style_new (MetaFrameStyle *parent); void meta_frame_style_ref (MetaFrameStyle *style); void meta_frame_style_unref (MetaFrameStyle *style); void meta_frame_style_draw (MetaFrameStyle *style, GtkWidget *widget, cairo_t *cr, const MetaFrameGeometry *fgeom, int client_width, int client_height, PangoLayout *title_layout, int text_height, MetaButtonState button_states[META_BUTTON_TYPE_LAST]); void meta_frame_style_draw_with_style (MetaFrameStyle *style, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, const MetaFrameGeometry *fgeom, int client_width, int client_height, PangoLayout *title_layout, int text_height, MetaButtonState button_states[META_BUTTON_TYPE_LAST]); gboolean meta_frame_style_validate (MetaFrameStyle *style, guint current_theme_version, GError **error); MetaFrameStyleSet* meta_frame_style_set_new (MetaFrameStyleSet *parent); void meta_frame_style_set_ref (MetaFrameStyleSet *style_set); void meta_frame_style_set_unref (MetaFrameStyleSet *style_set); gboolean meta_frame_style_set_validate (MetaFrameStyleSet *style_set, GError **error); GdkPixbuf* meta_theme_load_image (MetaTheme *theme, const char *filename, guint size_of_theme_icons, GError **error); MetaFrameStyle* meta_theme_get_frame_style (MetaTheme *theme, MetaFrameType type, MetaFrameFlags flags); double meta_theme_get_title_scale (MetaTheme *theme, MetaFrameType type, MetaFrameFlags flags); void meta_theme_draw_frame (MetaTheme *theme, GtkWidget *widget, cairo_t *cr, MetaFrameType type, MetaFrameFlags flags, int client_width, int client_height, PangoLayout *title_layout, int text_height, const MetaButtonLayout *button_layout, MetaButtonState button_states[META_BUTTON_TYPE_LAST]); void meta_theme_draw_frame_with_style (MetaTheme *theme, GtkStyleContext *style_gtk, GtkWidget *widget, cairo_t *cr, MetaFrameType type, MetaFrameFlags flags, int client_width, int client_height, PangoLayout *title_layout, int text_height, const MetaButtonLayout *button_layout, MetaButtonState button_states[META_BUTTON_TYPE_LAST]); void meta_theme_get_frame_borders (MetaTheme *theme, MetaFrameType type, int text_height, MetaFrameFlags flags, MetaFrameBorders *borders); void meta_theme_calc_geometry (MetaTheme *theme, MetaFrameType type, int text_height, MetaFrameFlags flags, int client_width, int client_height, const MetaButtonLayout *button_layout, MetaFrameGeometry *fgeom); MetaFrameLayout* meta_theme_lookup_layout (MetaTheme *theme, const char *name); void meta_theme_insert_layout (MetaTheme *theme, const char *name, MetaFrameLayout *layout); MetaDrawOpList* meta_theme_lookup_draw_op_list (MetaTheme *theme, const char *name); void meta_theme_insert_draw_op_list (MetaTheme *theme, const char *name, MetaDrawOpList *op_list); MetaFrameStyle* meta_theme_lookup_style (MetaTheme *theme, const char *name); void meta_theme_insert_style (MetaTheme *theme, const char *name, MetaFrameStyle *style); MetaFrameStyleSet* meta_theme_lookup_style_set (MetaTheme *theme, const char *name); void meta_theme_insert_style_set (MetaTheme *theme, const char *name, MetaFrameStyleSet *style_set); gboolean meta_theme_define_int_constant (MetaTheme *theme, const char *name, int value, GError **error); gboolean meta_theme_lookup_int_constant (MetaTheme *theme, const char *name, int *value); gboolean meta_theme_define_float_constant (MetaTheme *theme, const char *name, double value, GError **error); gboolean meta_theme_lookup_float_constant (MetaTheme *theme, const char *name, double *value); gboolean meta_theme_define_color_constant (MetaTheme *theme, const char *name, const char *value, GError **error); gboolean meta_theme_lookup_color_constant (MetaTheme *theme, const char *name, char **value); gboolean meta_theme_replace_constants (MetaTheme *theme, PosToken *tokens, int n_tokens, GError **err); /* random stuff */ PangoFontDescription* meta_gtk_widget_get_font_desc (GtkWidget *widget, double scale, const PangoFontDescription *override); int meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc, PangoContext *context); /* Enum converters */ MetaGtkColorComponent meta_color_component_from_string (const char *str); const char* meta_color_component_to_string (MetaGtkColorComponent component); MetaButtonState meta_button_state_from_string (const char *str); const char* meta_button_state_to_string (MetaButtonState state); MetaButtonType meta_button_type_from_string (const char *str, MetaTheme *theme); const char* meta_button_type_to_string (MetaButtonType type); MetaFramePiece meta_frame_piece_from_string (const char *str); const char* meta_frame_piece_to_string (MetaFramePiece piece); MetaFrameState meta_frame_state_from_string (const char *str); const char* meta_frame_state_to_string (MetaFrameState state); MetaFrameResize meta_frame_resize_from_string (const char *str); const char* meta_frame_resize_to_string (MetaFrameResize resize); MetaFrameFocus meta_frame_focus_from_string (const char *str); const char* meta_frame_focus_to_string (MetaFrameFocus focus); MetaFrameType meta_frame_type_from_string (const char *str); MetaGradientType meta_gradient_type_from_string (const char *str); const char* meta_gradient_type_to_string (MetaGradientType type); GtkStateFlags meta_gtk_state_from_string (const char *str); const char* meta_gtk_state_to_string (GtkStateFlags state); GtkShadowType meta_gtk_shadow_from_string (const char *str); const char* meta_gtk_shadow_to_string (GtkShadowType shadow); GtkArrowType meta_gtk_arrow_from_string (const char *str); const char* meta_gtk_arrow_to_string (GtkArrowType arrow); MetaImageFillType meta_image_fill_type_from_string (const char *str); const char* meta_image_fill_type_to_string (MetaImageFillType fill_type); void meta_gtk_style_get_light_color (GtkStyleContext *style, GtkStateFlags state, GdkRGBA *color); void meta_gtk_style_get_dark_color (GtkStyleContext *style, GtkStateFlags state, GdkRGBA *color); guint meta_theme_earliest_version_with_button (MetaButtonType type); #define META_THEME_ALLOWS(theme, feature) (theme->format_version >= feature) /* What version of the theme file format were various features introduced in? */ #define META_THEME_SHADE_STICK_ABOVE_BUTTONS 2 #define META_THEME_UBIQUITOUS_CONSTANTS 2 #define META_THEME_VARIED_ROUND_CORNERS 2 #define META_THEME_IMAGES_FROM_ICON_THEMES 2 #define META_THEME_UNRESIZABLE_SHADED_STYLES 2 #define META_THEME_DEGREES_IN_ARCS 2 #define META_THEME_HIDDEN_BUTTONS 2 #define META_THEME_COLOR_CONSTANTS 2 #define META_THEME_FRAME_BACKGROUNDS 2 #endif /* META_THEME_PRIVATE_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/testgradient.c������������������������������������������������������������������0000664�0001750�0001750�00000020164�14211404421�017204� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin gradient test program */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <meta/gradient.h> #include <gtk/gtk.h> typedef void (* RenderGradientFunc) (cairo_t *cr, int width, int height); static void draw_checkerboard (cairo_t *cr, int width, int height) { gint i, j, xcount, ycount; GdkRGBA color1, color2; #define CHECK_SIZE 10 #define SPACING 2 color1.red = 30000. / 65535.; color1.green = 30000. / 65535.; color1.blue = 30000. / 65535.; color1.alpha = 1.0; color2.red = 50000. / 65535.; color2.green = 50000. / 65535.; color2.blue = 50000. / 65535.; color2.alpha = 1.0; xcount = 0; i = SPACING; while (i < width) { j = SPACING; ycount = xcount % 2; /* start with even/odd depending on row */ while (j < height) { if (ycount % 2) gdk_cairo_set_source_rgba (cr, &color1); else gdk_cairo_set_source_rgba (cr, &color2); /* If we're outside event->area, this will do nothing. * It might be mildly more efficient if we handled * the clipping ourselves, but again we're feeling lazy. */ cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE); cairo_fill (cr); j += CHECK_SIZE + SPACING; ++ycount; } i += CHECK_SIZE + SPACING; ++xcount; } } static void render_simple (cairo_t *cr, int width, int height, MetaGradientType type, gboolean with_alpha) { GdkPixbuf *pixbuf; GdkRGBA from, to; gdk_rgba_parse (&from, "blue"); gdk_rgba_parse (&to, "green"); pixbuf = meta_gradient_create_simple (width, height, &from, &to, type); if (with_alpha) { const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff }; if (!gdk_pixbuf_get_has_alpha (pixbuf)) { GdkPixbuf *new_pixbuf; new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); g_object_unref (G_OBJECT (pixbuf)); pixbuf = new_pixbuf; } meta_gradient_add_alpha (pixbuf, alphas, G_N_ELEMENTS (alphas), META_GRADIENT_HORIZONTAL); draw_checkerboard (cr , width, height); } gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); g_object_unref (G_OBJECT (pixbuf)); } static void render_vertical_func (cairo_t *cr, int width, int height) { render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE); } static void render_horizontal_func (cairo_t *cr, int width, int height) { render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE); } static void render_diagonal_func (cairo_t *cr, int width, int height) { render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE); } static void render_diagonal_alpha_func (cairo_t *cr, int width, int height) { render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE); } static void render_multi (cairo_t *cr, int width, int height, MetaGradientType type) { GdkPixbuf *pixbuf; #define N_COLORS 5 GdkRGBA colors[N_COLORS]; gdk_rgba_parse (&colors[0], "red"); gdk_rgba_parse (&colors[1], "blue"); gdk_rgba_parse (&colors[2], "orange"); gdk_rgba_parse (&colors[3], "pink"); gdk_rgba_parse (&colors[4], "green"); pixbuf = meta_gradient_create_multi (width, height, colors, N_COLORS, type); gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); g_object_unref (G_OBJECT (pixbuf)); #undef N_COLORS } static void render_vertical_multi_func (cairo_t *cr, int width, int height) { render_multi (cr, width, height, META_GRADIENT_VERTICAL); } static void render_horizontal_multi_func (cairo_t *cr, int width, int height) { render_multi (cr, width, height, META_GRADIENT_HORIZONTAL); } static void render_diagonal_multi_func (cairo_t *cr, int width, int height) { render_multi (cr, width, height, META_GRADIENT_DIAGONAL); } static void render_interwoven_func (cairo_t *cr, int width, int height) { GdkPixbuf *pixbuf; #define N_COLORS 4 GdkRGBA colors[N_COLORS]; gdk_rgba_parse (&colors[0], "red"); gdk_rgba_parse (&colors[1], "blue"); gdk_rgba_parse (&colors[2], "pink"); gdk_rgba_parse (&colors[3], "green"); pixbuf = meta_gradient_create_interwoven (width, height, colors, height / 10, colors + 2, height / 14); gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); g_object_unref (G_OBJECT (pixbuf)); } static gboolean draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data) { RenderGradientFunc func = data; GtkStyleContext *style; GdkRGBA color; style = gtk_widget_get_style_context (widget); gtk_style_context_save (style); gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget)); gtk_style_context_lookup_color (style, "foreground-color", &color); gtk_style_context_restore (style); gdk_cairo_set_source_rgba (cr, &color); (* func) (cr, gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); return FALSE; } static GtkWidget* create_gradient_window (const char *title, RenderGradientFunc func) { GtkWidget *window; GtkWidget *drawing_area; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), title); drawing_area = gtk_drawing_area_new (); gtk_widget_set_size_request (drawing_area, 1, 1); gtk_window_set_default_size (GTK_WINDOW (window), 175, 175); g_signal_connect (G_OBJECT (drawing_area), "draw", G_CALLBACK (draw_callback), func); gtk_container_add (GTK_CONTAINER (window), drawing_area); gtk_widget_show_all (window); return window; } static void meta_gradient_test (void) { create_gradient_window ("Simple vertical", render_vertical_func); create_gradient_window ("Simple horizontal", render_horizontal_func); create_gradient_window ("Simple diagonal", render_diagonal_func); create_gradient_window ("Multi vertical", render_vertical_multi_func); create_gradient_window ("Multi horizontal", render_horizontal_multi_func); create_gradient_window ("Multi diagonal", render_diagonal_multi_func); create_gradient_window ("Interwoven", render_interwoven_func); create_gradient_window ("Simple diagonal with horizontal multi alpha", render_diagonal_alpha_func); } int main (int argc, char **argv) { gtk_init (&argc, &argv); meta_gradient_test (); gtk_main (); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/ui.h����������������������������������������������������������������������������0000664�0001750�0001750�00000015122�14211404421�015127� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin interface for talking to GTK+ UI module */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_UI_H #define META_UI_H /* Don't include gtk.h or gdk.h here */ #include <meta/common.h> #include <meta/display.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <cairo.h> #include <glib.h> #include <gdk-pixbuf/gdk-pixbuf.h> typedef struct _MetaUI MetaUI; typedef gboolean (* MetaEventFunc) (XEvent *xevent, gpointer data); typedef enum { META_UI_DIRECTION_LTR, META_UI_DIRECTION_RTL } MetaUIDirection; void meta_ui_init (void); Display* meta_ui_get_display (void); void meta_ui_add_event_func (Display *xdisplay, MetaEventFunc func, gpointer data); void meta_ui_remove_event_func (Display *xdisplay, MetaEventFunc func, gpointer data); MetaUI* meta_ui_new (MetaDisplay *display, Screen *screen); void meta_ui_free (MetaUI *ui); void meta_ui_theme_get_frame_borders (MetaUI *ui, MetaFrameType type, MetaFrameFlags flags, MetaFrameBorders *borders); void meta_ui_get_frame_borders (MetaUI *ui, Window frame_xwindow, MetaFrameBorders *borders); Window meta_ui_create_frame_window (MetaUI *ui, Display *xdisplay, Visual *xvisual, gint x, gint y, gint width, gint height, gint screen_no, gulong *create_serial); void meta_ui_destroy_frame_window (MetaUI *ui, Window xwindow); void meta_ui_move_resize_frame (MetaUI *ui, Window frame, int x, int y, int width, int height); /* GDK insists on tracking map/unmap */ void meta_ui_map_frame (MetaUI *ui, Window xwindow); void meta_ui_unmap_frame (MetaUI *ui, Window xwindow); cairo_region_t *meta_ui_get_frame_bounds (MetaUI *ui, Window xwindow, int window_width, int window_height); void meta_ui_get_corner_radiuses (MetaUI *ui, Window xwindow, float *top_left, float *top_right, float *bottom_left, float *bottom_right); void meta_ui_queue_frame_draw (MetaUI *ui, Window xwindow); void meta_ui_set_frame_title (MetaUI *ui, Window xwindow, const char *title); void meta_ui_update_frame_style (MetaUI *ui, Window window); void meta_ui_repaint_frame (MetaUI *ui, Window xwindow); MetaWindowMenu* meta_ui_window_menu_new (MetaUI *ui, Window client_xwindow, MetaMenuOp ops, MetaMenuOp insensitive, unsigned long active_workspace, int n_workspaces, MetaWindowMenuFunc func, gpointer data); void meta_ui_window_menu_popup (MetaWindowMenu *menu, int root_x, int root_y, int button, guint32 timestamp); void meta_ui_window_menu_free (MetaWindowMenu *menu); /* FIXME these lack a display arg */ GdkPixbuf* meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap, int src_x, int src_y, int width, int height); gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay, Window xwindow); char* meta_text_property_to_utf8 (Display *xdisplay, const XTextProperty *prop); void meta_ui_set_current_theme (const char *name, gboolean force_reload); gboolean meta_ui_have_a_theme (void); /* Not a real key symbol but means "key above the tab key"; this is * used as the default keybinding for cycle_group. * 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are * randomly chosen */ #define META_KEY_ABOVE_TAB 0x2f7259c9 gboolean meta_ui_parse_accelerator (const char *accel, unsigned int *keysym, unsigned int *keycode, MetaVirtualModifier *mask); gboolean meta_ui_parse_modifier (const char *accel, MetaVirtualModifier *mask); /* Caller responsible for freeing return string of meta_ui_accelerator_name! */ gchar* meta_ui_accelerator_name (unsigned int keysym, MetaVirtualModifier mask); gboolean meta_ui_window_is_widget (MetaUI *ui, Window xwindow); MetaUIDirection meta_ui_get_direction (void); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/metaaccellabel.h����������������������������������������������������������������0000664�0001750�0001750�00000006703�14211404421�017435� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity hacked-up GtkAccelLabel */ /* Copyright (C) 2002 Red Hat, Inc. */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * MetaAccelLabel: GtkLabel with accelerator monitoring facilities. * Copyright (C) 1998 Tim Janik * * 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., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ /* * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #ifndef __META_ACCEL_LABEL_H__ #define __META_ACCEL_LABEL_H__ #include <gtk/gtk.h> #include <meta/common.h> #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define META_TYPE_ACCEL_LABEL (meta_accel_label_get_type ()) #define META_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabel)) #define META_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass)) #define META_IS_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_ACCEL_LABEL)) #define META_IS_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_ACCEL_LABEL)) #define META_ACCEL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass)) typedef struct _MetaAccelLabel MetaAccelLabel; typedef struct _MetaAccelLabelClass MetaAccelLabelClass; struct _MetaAccelLabel { GtkLabel label; MetaVirtualModifier accel_mods; guint accel_key; guint accel_padding; gchar *accel_string; guint16 accel_string_width; }; struct _MetaAccelLabelClass { GtkLabelClass parent_class; gchar *signal_quote1; gchar *signal_quote2; gchar *mod_name_shift; gchar *mod_name_control; gchar *mod_name_alt; gchar *mod_name_meta; gchar *mod_name_super; gchar *mod_name_hyper; gchar *mod_name_mod2; gchar *mod_name_mod3; gchar *mod_name_mod4; gchar *mod_name_mod5; gchar *mod_separator; gchar *accel_seperator; guint latin1_to_char : 1; /* Padding for future expansion */ void (*_gtk_reserved1) (void); void (*_gtk_reserved2) (void); void (*_gtk_reserved3) (void); void (*_gtk_reserved4) (void); }; GType meta_accel_label_get_type (void) G_GNUC_CONST; GtkWidget* meta_accel_label_new_with_mnemonic (const gchar *string); void meta_accel_label_set_accelerator (MetaAccelLabel *accel_label, guint accelerator_key, MetaVirtualModifier accelerator_mods); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __META_ACCEL_LABEL_H__ */ �������������������������������������������������������������muffin-5.2.1/src/ui/resizepopup.h�������������������������������������������������������������������0000664�0001750�0001750�00000003577�14211404421�017112� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin resizing-terminal-window feedback */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_RESIZEPOPUP_H #define META_RESIZEPOPUP_H /* Don't include gtk.h or gdk.h here */ #include <meta/boxes.h> #include <meta/common.h> #include <X11/Xlib.h> #include <glib.h> #include <gdk-pixbuf/gdk-pixbuf.h> MetaResizePopup* meta_ui_resize_popup_new (Display *display, int screen_number); void meta_ui_resize_popup_free (MetaResizePopup *popup); void meta_ui_resize_popup_set (MetaResizePopup *popup, MetaRectangle rect, int base_width, int base_height, int width_inc, int height_inc); void meta_ui_resize_popup_set_showing (MetaResizePopup *popup, gboolean showing); #endif ���������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/frames.h������������������������������������������������������������������������0000664�0001750�0001750�00000012051�14211404421�015765� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity window frame manager widget */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_FRAMES_H #define META_FRAMES_H #include <gtk/gtk.h> #include <gdk/gdkx.h> #include <meta/common.h> #include "theme-private.h" typedef enum { META_FRAME_CONTROL_NONE, META_FRAME_CONTROL_TITLE, META_FRAME_CONTROL_DELETE, META_FRAME_CONTROL_MENU, META_FRAME_CONTROL_MINIMIZE, META_FRAME_CONTROL_MAXIMIZE, META_FRAME_CONTROL_UNMAXIMIZE, META_FRAME_CONTROL_SHADE, META_FRAME_CONTROL_UNSHADE, META_FRAME_CONTROL_ABOVE, META_FRAME_CONTROL_UNABOVE, META_FRAME_CONTROL_STICK, META_FRAME_CONTROL_UNSTICK, META_FRAME_CONTROL_RESIZE_SE, META_FRAME_CONTROL_RESIZE_S, META_FRAME_CONTROL_RESIZE_SW, META_FRAME_CONTROL_RESIZE_N, META_FRAME_CONTROL_RESIZE_NE, META_FRAME_CONTROL_RESIZE_NW, META_FRAME_CONTROL_RESIZE_W, META_FRAME_CONTROL_RESIZE_E, META_FRAME_CONTROL_CLIENT_AREA } MetaFrameControl; /* This is one widget that manages all the window frames * as subwindows. */ #define META_TYPE_FRAMES (meta_frames_get_type ()) #define META_FRAMES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_FRAMES, MetaFrames)) #define META_FRAMES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_FRAMES, MetaFramesClass)) #define META_IS_FRAMES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_FRAMES)) #define META_IS_FRAMES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_FRAMES)) #define META_FRAMES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_FRAMES, MetaFramesClass)) typedef struct _MetaFrames MetaFrames; typedef struct _MetaFramesClass MetaFramesClass; typedef struct _MetaUIFrame MetaUIFrame; struct _MetaUIFrame { Window xwindow; GdkWindow *window; GtkStyleContext *style; MetaFrameStyle *cache_style; PangoLayout *layout; int text_height; char *title; /* NULL once we have a layout */ guint shape_applied : 1; /* FIXME get rid of this, it can just be in the MetaFrames struct */ MetaFrameControl prelit_control; }; struct _MetaFrames { GtkWindow parent_instance; GHashTable *text_heights; GHashTable *frames; MetaUIFrame *last_motion_frame; GtkStyleContext *normal_style; GHashTable *style_variants; int invalidate_cache_timeout_id; GList *invalidate_frames; GHashTable *cache; }; struct _MetaFramesClass { GtkWindowClass parent_class; }; GType meta_frames_get_type (void) G_GNUC_CONST; MetaFrames *meta_frames_new (int screen_number); void meta_frames_manage_window (MetaFrames *frames, Window xwindow, GdkWindow *window); void meta_frames_unmanage_window (MetaFrames *frames, Window xwindow); void meta_frames_set_title (MetaFrames *frames, Window xwindow, const char *title); void meta_frames_update_frame_style (MetaFrames *frames, Window xwindow); void meta_frames_repaint_frame (MetaFrames *frames, Window xwindow); void meta_frames_get_borders (MetaFrames *frames, Window xwindow, MetaFrameBorders *borders); cairo_region_t *meta_frames_get_frame_bounds (MetaFrames *frames, Window xwindow, int window_width, int window_height); void meta_frames_get_corner_radiuses (MetaFrames *frames, Window xwindow, float *top_left, float *top_right, float *bottom_left, float *bottom_right); void meta_frames_move_resize_frame (MetaFrames *frames, Window xwindow, int x, int y, int width, int height); void meta_frames_queue_draw (MetaFrames *frames, Window xwindow); void meta_frames_notify_menu_hide (MetaFrames *frames); Window meta_frames_get_moving_frame (MetaFrames *frames); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/preview-widget.c����������������������������������������������������������������0000664�0001750�0001750�00000034046�14211404421�017455� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity theme preview widget */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _XOPEN_SOURCE 600 /* for the maths routines over floats */ #include <math.h> #include <gtk/gtk.h> #include <meta/preview-widget.h> #include "theme-private.h" static void meta_preview_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural); static void meta_preview_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); static void meta_preview_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gboolean meta_preview_draw (GtkWidget *widget, cairo_t *cr); static void meta_preview_finalize (GObject *object); G_DEFINE_TYPE (MetaPreview, meta_preview, GTK_TYPE_BIN); static void meta_preview_class_init (MetaPreviewClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class; widget_class = (GtkWidgetClass*) class; gobject_class->finalize = meta_preview_finalize; widget_class->draw = meta_preview_draw; widget_class->get_preferred_width = meta_preview_get_preferred_width; widget_class->get_preferred_height = meta_preview_get_preferred_height; widget_class->size_allocate = meta_preview_size_allocate; gtk_container_class_handle_border_width (GTK_CONTAINER_CLASS (class)); } static void meta_preview_init (MetaPreview *preview) { int i; gtk_widget_set_has_window (GTK_WIDGET (preview), FALSE); i = 0; while (i < MAX_BUTTONS_PER_CORNER) { preview->button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST; preview->button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST; ++i; } preview->button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU; preview->button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE; preview->button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE; preview->button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE; preview->type = META_FRAME_TYPE_NORMAL; preview->flags = META_FRAME_ALLOWS_DELETE | META_FRAME_ALLOWS_MENU | META_FRAME_ALLOWS_MINIMIZE | META_FRAME_ALLOWS_MAXIMIZE | META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE | META_FRAME_HAS_FOCUS | META_FRAME_ALLOWS_SHADE | META_FRAME_ALLOWS_MOVE; preview->borders_cached = FALSE; } GtkWidget* meta_preview_new (void) { MetaPreview *preview; preview = g_object_new (META_TYPE_PREVIEW, NULL); return GTK_WIDGET (preview); } static void meta_preview_finalize (GObject *object) { MetaPreview *preview; preview = META_PREVIEW (object); free (preview->title); preview->title = NULL; G_OBJECT_CLASS (meta_preview_parent_class)->finalize (object); } static void ensure_info (MetaPreview *preview) { GtkWidget *widget; widget = GTK_WIDGET (preview); if (preview->layout == NULL) { PangoFontDescription *font_desc; double scale; PangoAttrList *attrs; PangoAttribute *attr; if (preview->theme) scale = meta_theme_get_title_scale (preview->theme, preview->type, preview->flags); else scale = 1.0; preview->layout = gtk_widget_create_pango_layout (widget, preview->title); font_desc = meta_gtk_widget_get_font_desc (widget, scale, NULL); preview->text_height = meta_pango_font_desc_get_text_height (font_desc, gtk_widget_get_pango_context (widget)); attrs = pango_attr_list_new (); attr = pango_attr_size_new (pango_font_description_get_size (font_desc)); attr->start_index = 0; attr->end_index = G_MAXINT; pango_attr_list_insert (attrs, attr); pango_layout_set_attributes (preview->layout, attrs); pango_attr_list_unref (attrs); pango_font_description_free (font_desc); } if (!preview->borders_cached) { if (preview->theme) meta_theme_get_frame_borders (preview->theme, preview->type, preview->text_height, preview->flags, &preview->borders); else meta_frame_borders_clear (&preview->borders); preview->borders_cached = TRUE; } } static gboolean meta_preview_draw (GtkWidget *widget, cairo_t *cr) { MetaPreview *preview = META_PREVIEW (widget); GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); if (preview->theme) { int client_width; int client_height; MetaButtonState button_states[META_BUTTON_TYPE_LAST] = { META_BUTTON_STATE_NORMAL, META_BUTTON_STATE_NORMAL, META_BUTTON_STATE_NORMAL, META_BUTTON_STATE_NORMAL }; ensure_info (preview); cairo_save (cr); client_width = allocation.width - preview->borders.total.left - preview->borders.total.right; client_height = allocation.height - preview->borders.total.top - preview->borders.total.bottom; if (client_width < 0) client_width = 1; if (client_height < 0) client_height = 1; meta_theme_draw_frame (preview->theme, widget, cr, preview->type, preview->flags, client_width, client_height, preview->layout, preview->text_height, &preview->button_layout, button_states); cairo_restore (cr); } /* draw child */ return GTK_WIDGET_CLASS (meta_preview_parent_class)->draw (widget, cr); } #define NO_CHILD_WIDTH 80 #define NO_CHILD_HEIGHT 20 static void meta_preview_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { MetaPreview *preview; GtkWidget *child; preview = META_PREVIEW (widget); ensure_info (preview); *minimum = *natural = preview->borders.total.left + preview->borders.total.right; child = gtk_bin_get_child (GTK_BIN (preview)); if (child && gtk_widget_get_visible (child)) { gint child_min, child_nat; gtk_widget_get_preferred_width (child, &child_min, &child_nat); *minimum += child_min; *natural += child_nat; } else { *minimum += NO_CHILD_WIDTH; *natural += NO_CHILD_WIDTH; } } static void meta_preview_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { MetaPreview *preview; GtkWidget *child; preview = META_PREVIEW (widget); ensure_info (preview); *minimum = *natural = preview->borders.total.top + preview->borders.total.bottom; child = gtk_bin_get_child (GTK_BIN (preview)); if (child && gtk_widget_get_visible (child)) { gint child_min, child_nat; gtk_widget_get_preferred_height (child, &child_min, &child_nat); *minimum += child_min; *natural += child_nat; } else { *minimum += NO_CHILD_HEIGHT; *natural += NO_CHILD_HEIGHT; } } static void meta_preview_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { MetaPreview *preview; GtkAllocation widget_allocation, child_allocation; GtkWidget *child; preview = META_PREVIEW (widget); ensure_info (preview); gtk_widget_set_allocation (widget, allocation); child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) { gtk_widget_get_allocation (widget, &widget_allocation); child_allocation.x = widget_allocation.x + preview->borders.total.left; child_allocation.y = widget_allocation.y + preview->borders.total.top; child_allocation.width = MAX (1, widget_allocation.width - preview->borders.total.left - preview->borders.total.right); child_allocation.height = MAX (1, widget_allocation.height - preview->borders.total.top - preview->borders.total.bottom); gtk_widget_size_allocate (child, &child_allocation); } } static void clear_cache (MetaPreview *preview) { if (preview->layout) { g_object_unref (G_OBJECT (preview->layout)); preview->layout = NULL; } preview->borders_cached = FALSE; } void meta_preview_set_theme (MetaPreview *preview, MetaTheme *theme) { g_return_if_fail (META_IS_PREVIEW (preview)); preview->theme = theme; clear_cache (preview); gtk_widget_queue_resize (GTK_WIDGET (preview)); } void meta_preview_set_title (MetaPreview *preview, const char *title) { g_return_if_fail (META_IS_PREVIEW (preview)); free (preview->title); preview->title = g_strdup (title); clear_cache (preview); gtk_widget_queue_resize (GTK_WIDGET (preview)); } void meta_preview_set_frame_type (MetaPreview *preview, MetaFrameType type) { g_return_if_fail (META_IS_PREVIEW (preview)); preview->type = type; clear_cache (preview); gtk_widget_queue_resize (GTK_WIDGET (preview)); } void meta_preview_set_frame_flags (MetaPreview *preview, MetaFrameFlags flags) { g_return_if_fail (META_IS_PREVIEW (preview)); preview->flags = flags; clear_cache (preview); gtk_widget_queue_resize (GTK_WIDGET (preview)); } void meta_preview_set_button_layout (MetaPreview *preview, const MetaButtonLayout *button_layout) { g_return_if_fail (META_IS_PREVIEW (preview)); preview->button_layout = *button_layout; gtk_widget_queue_draw (GTK_WIDGET (preview)); } cairo_region_t * meta_preview_get_clip_region (MetaPreview *preview, gint new_window_width, gint new_window_height) { cairo_rectangle_int_t xrect; cairo_region_t *corners_xregion, *window_xregion; gint flags; MetaFrameLayout *fgeom; MetaFrameStyle *frame_style; g_return_val_if_fail (META_IS_PREVIEW (preview), NULL); flags = (META_PREVIEW (preview)->flags); window_xregion = cairo_region_create (); xrect.x = 0; xrect.y = 0; xrect.width = new_window_width; xrect.height = new_window_height; cairo_region_union_rectangle (window_xregion, &xrect); if (preview->theme == NULL) return window_xregion; /* Otherwise, we do have a theme, so calculate the corners */ frame_style = meta_theme_get_frame_style (preview->theme, META_FRAME_TYPE_NORMAL, flags); fgeom = frame_style->layout; corners_xregion = cairo_region_create (); if (fgeom->top_left_corner_rounded_radius != 0) { const int corner = fgeom->top_left_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); xrect.x = 0; xrect.y = i; xrect.width = width; xrect.height = 1; cairo_region_union_rectangle (corners_xregion, &xrect); } } if (fgeom->top_right_corner_rounded_radius != 0) { const int corner = fgeom->top_right_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); xrect.x = new_window_width - width; xrect.y = i; xrect.width = width; xrect.height = 1; cairo_region_union_rectangle (corners_xregion, &xrect); } } if (fgeom->bottom_left_corner_rounded_radius != 0) { const int corner = fgeom->bottom_left_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); xrect.x = 0; xrect.y = new_window_height - i - 1; xrect.width = width; xrect.height = 1; cairo_region_union_rectangle (corners_xregion, &xrect); } } if (fgeom->bottom_right_corner_rounded_radius != 0) { const int corner = fgeom->bottom_right_corner_rounded_radius; const float radius = sqrt(corner) + corner; int i; for (i=0; i<corner; i++) { const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); xrect.x = new_window_width - width; xrect.y = new_window_height - i - 1; xrect.width = width; xrect.height = 1; cairo_region_union_rectangle (corners_xregion, &xrect); } } cairo_region_subtract (window_xregion, corners_xregion); cairo_region_destroy (corners_xregion); return window_xregion; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/theme-parser.c������������������������������������������������������������������0000664�0001750�0001750�00000416344�14211404421�017114� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity theme parsing */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include "theme-private.h" #include "util-private.h" #include <meta/prefs.h> #include <string.h> #include <stdlib.h> #include <clutter/clutter.h> /* We were intending to put the version number * in the subdirectory name, but we ended up * using the filename instead. The "-1" survives * as a fossil. */ #define THEME_SUBDIR "metacity-1" /* Highest version of the theme format to * look out for. */ #define THEME_MAJOR_VERSION 3 #define THEME_MINOR_VERSION 4 #define THEME_VERSION (1000 * THEME_MAJOR_VERSION + THEME_MINOR_VERSION) #define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml" typedef enum { STATE_START, STATE_THEME, /* info section */ STATE_INFO, STATE_NAME, STATE_AUTHOR, STATE_COPYRIGHT, STATE_DATE, STATE_DESCRIPTION, /* constants */ STATE_CONSTANT, /* geometry */ STATE_FRAME_GEOMETRY, STATE_DISTANCE, STATE_BORDER, STATE_ASPECT_RATIO, /* draw ops */ STATE_DRAW_OPS, STATE_LINE, STATE_RECTANGLE, STATE_ARC, STATE_CLIP, STATE_TINT, STATE_GRADIENT, STATE_IMAGE, STATE_GTK_ARROW, STATE_GTK_BOX, STATE_GTK_VLINE, STATE_ICON, STATE_TITLE, STATE_INCLUDE, /* include another draw op list */ STATE_TILE, /* tile another draw op list */ /* sub-parts of gradient */ STATE_COLOR, /* frame style */ STATE_FRAME_STYLE, STATE_PIECE, STATE_BUTTON, /* style set */ STATE_FRAME_STYLE_SET, STATE_FRAME, /* assigning style sets to windows */ STATE_WINDOW, /* things we don't use any more but we can still parse: */ STATE_MENU_ICON, STATE_FALLBACK, /* an ubuntu specific ignore-this-element state */ UBUNTU_STATE_IGNORE } ParseState; typedef struct { /* This two lists contain stacks of state and required version * (cast to pointers.) There is one list item for each currently * open element. */ GSList *states; GSList *required_versions; const char *theme_name; /* name of theme (directory it's in) */ const char *theme_file; /* theme filename */ const char *theme_dir; /* dir the theme is inside */ MetaTheme *theme; /* theme being parsed */ guint format_version; /* version of format of theme file */ char *name; /* name of named thing being parsed */ MetaFrameLayout *layout; /* layout being parsed if any */ MetaDrawOpList *op_list; /* op list being parsed if any */ MetaDrawOp *op; /* op being parsed if any */ MetaFrameStyle *style; /* frame style being parsed if any */ MetaFrameStyleSet *style_set; /* frame style set being parsed if any */ MetaFramePiece piece; /* position of piece being parsed */ MetaButtonType button_type; /* type of button/menuitem being parsed */ MetaButtonState button_state; /* state of button being parsed */ int skip_level; /* depth of elements that we're ignoring */ } ParseInfo; typedef enum { THEME_PARSE_ERROR_TOO_OLD, THEME_PARSE_ERROR_TOO_FAILED } ThemeParseError; static GQuark theme_parse_error_quark (void) { return g_quark_from_static_string ("theme-parse-error-quark"); } #define THEME_PARSE_ERROR (theme_parse_error_quark ()) static void set_error (GError **err, GMarkupParseContext *context, int error_domain, int error_code, const char *format, ...) G_GNUC_PRINTF (5, 6); static void add_context_to_error (GError **err, GMarkupParseContext *context); static void parse_info_init (ParseInfo *info); static void parse_info_free (ParseInfo *info); static void push_state (ParseInfo *info, ParseState state); static void pop_state (ParseInfo *info); static ParseState peek_state (ParseInfo *info); static void parse_toplevel_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_info_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_geometry_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_draw_op_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_gradient_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_style_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_style_set_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_piece_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_button_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void parse_menu_icon_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error); static void start_element_handler (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error); static void end_element_handler (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error); static void text_handler (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error); /* Translators: This means that an attribute which should have been found * on an XML element was not in fact found. */ #define ATTRIBUTE_NOT_FOUND _("No \"%s\" attribute on element <%s>") static GMarkupParser metacity_theme_parser = { start_element_handler, end_element_handler, text_handler, NULL, NULL }; static void set_error (GError **err, GMarkupParseContext *context, int error_domain, int error_code, const char *format, ...) { int line, ch; va_list args; char *str; g_markup_parse_context_get_position (context, &line, &ch); va_start (args, format); str = g_strdup_vprintf (format, args); va_end (args); g_set_error (err, error_domain, error_code, _("Line %d character %d: %s"), line, ch, str); free (str); } static void add_context_to_error (GError **err, GMarkupParseContext *context) { int line, ch; char *str; if (err == NULL || *err == NULL) return; g_markup_parse_context_get_position (context, &line, &ch); str = g_strdup_printf (_("Line %d character %d: %s"), line, ch, (*err)->message); free ((*err)->message); (*err)->message = str; } static void parse_info_init (ParseInfo *info) { info->theme_file = NULL; info->states = g_slist_prepend (NULL, GINT_TO_POINTER (STATE_START)); info->required_versions = NULL; info->theme = NULL; info->name = NULL; info->layout = NULL; info->op_list = NULL; info->op = NULL; info->style = NULL; info->style_set = NULL; info->piece = META_FRAME_PIECE_LAST; info->button_type = META_BUTTON_TYPE_LAST; info->button_state = META_BUTTON_STATE_LAST; info->skip_level = 0; } static void parse_info_free (ParseInfo *info) { g_slist_free (info->states); g_slist_free (info->required_versions); if (info->theme) meta_theme_free (info->theme); if (info->layout) meta_frame_layout_unref (info->layout); if (info->op_list) meta_draw_op_list_unref (info->op_list); if (info->op) meta_draw_op_free (info->op); if (info->style) meta_frame_style_unref (info->style); if (info->style_set) meta_frame_style_set_unref (info->style_set); } static void push_state (ParseInfo *info, ParseState state) { info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state)); } static void pop_state (ParseInfo *info) { g_return_if_fail (info->states != NULL); info->states = g_slist_remove (info->states, info->states->data); } static ParseState peek_state (ParseInfo *info) { g_return_val_if_fail (info->states != NULL, STATE_START); return GPOINTER_TO_INT (info->states->data); } static void push_required_version (ParseInfo *info, int version) { info->required_versions = g_slist_prepend (info->required_versions, GINT_TO_POINTER (version)); } static void pop_required_version (ParseInfo *info) { g_return_if_fail (info->required_versions != NULL); info->required_versions = g_slist_delete_link (info->required_versions, info->required_versions); } static int peek_required_version (ParseInfo *info) { if (info->required_versions) return GPOINTER_TO_INT (info->required_versions->data); else return info->format_version; } #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0) typedef struct { const char *name; const char **retloc; gboolean required; } LocateAttr; /* Attribute names can have a leading '!' to indicate that they are * required. */ static gboolean locate_attributes (GMarkupParseContext *context, const char *element_name, const char **attribute_names, const char **attribute_values, GError **error, const char *first_attribute_name, const char **first_attribute_retloc, ...) { va_list args; const char *name; const char **retloc; int n_attrs; #define MAX_ATTRS 24 LocateAttr attrs[MAX_ATTRS]; gboolean retval; int i; g_return_val_if_fail (first_attribute_name != NULL, FALSE); g_return_val_if_fail (first_attribute_retloc != NULL, FALSE); retval = TRUE; /* FIXME: duplicated code; refactor loop */ n_attrs = 1; attrs[0].name = first_attribute_name; attrs[0].retloc = first_attribute_retloc; attrs[0].required = attrs[0].name[0]=='!'; if (attrs[0].required) attrs[0].name++; /* skip past it */ *first_attribute_retloc = NULL; va_start (args, first_attribute_retloc); name = va_arg (args, const char*); retloc = va_arg (args, const char**); while (name != NULL) { g_return_val_if_fail (retloc != NULL, FALSE); g_assert (n_attrs < MAX_ATTRS); attrs[n_attrs].name = name; attrs[n_attrs].retloc = retloc; attrs[n_attrs].required = attrs[n_attrs].name[0]=='!'; if (attrs[n_attrs].required) attrs[n_attrs].name++; /* skip past it */ n_attrs += 1; *retloc = NULL; name = va_arg (args, const char*); retloc = va_arg (args, const char**); } va_end (args); i = 0; while (attribute_names[i]) { int j; gboolean found; /* Can be present anywhere */ if (strcmp (attribute_names[i], "version") == 0) { ++i; continue; } found = FALSE; j = 0; while (j < n_attrs) { if (strcmp (attrs[j].name, attribute_names[i]) == 0) { retloc = attrs[j].retloc; if (*retloc != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Attribute \"%s\" repeated twice on the same <%s> element"), attrs[j].name, element_name); retval = FALSE; goto out; } *retloc = attribute_values[i]; found = TRUE; } ++j; } if (!found) { j = 0; while (j < n_attrs) { g_warning ("It could have been %s.\n", attrs[j++].name); } set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Attribute \"%s\" is invalid on <%s> element in this context"), attribute_names[i], element_name); retval = FALSE; goto out; } ++i; } /* Did we catch them all? */ i = 0; while (i < n_attrs) { if (attrs[i].required && *(attrs[i].retloc)==NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, ATTRIBUTE_NOT_FOUND, attrs[i].name, element_name); retval = FALSE; goto out; } ++i; } out: return retval; } static gboolean check_no_attributes (GMarkupParseContext *context, const char *element_name, const char **attribute_names, const char **attribute_values, GError **error) { int i = 0; /* Can be present anywhere */ if (attribute_names[0] && strcmp (attribute_names[i], "version") == 0) i++; if (attribute_names[i] != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Attribute \"%s\" is invalid on <%s> element in this context"), attribute_names[0], element_name); return FALSE; } return TRUE; } #define MAX_REASONABLE 4096 static gboolean parse_positive_integer (const char *str, int *val, GMarkupParseContext *context, MetaTheme *theme, GError **error) { char *end; long l; int j; *val = 0; end = NULL; /* Is str a constant? */ if (META_THEME_ALLOWS (theme, META_THEME_UBIQUITOUS_CONSTANTS) && meta_theme_lookup_int_constant (theme, str, &j)) { /* Yes. */ l = j; } else { /* No. Let's try parsing it instead. */ l = strtol (str, &end, 10); if (end == NULL || end == str) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Could not parse \"%s\" as an integer"), str); return FALSE; } if (*end != '\0') { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand trailing characters \"%s\" in string \"%s\""), end, str); return FALSE; } } if (l < 0) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Integer %ld must be positive"), l); return FALSE; } if (l > MAX_REASONABLE) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Integer %ld is too large, current max is %d"), l, MAX_REASONABLE); return FALSE; } *val = (int) l * theme->scale; return TRUE; } static gboolean parse_double (const char *str, double *val, GMarkupParseContext *context, GError **error) { char *end; *val = 0; end = NULL; *val = g_ascii_strtod (str, &end); if (end == NULL || end == str) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Could not parse \"%s\" as a floating point number"), str); return FALSE; } if (*end != '\0') { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand trailing characters \"%s\" in string \"%s\""), end, str); return FALSE; } return TRUE; } static gboolean parse_boolean (const char *str, gboolean *val, GMarkupParseContext *context, GError **error) { if (strcmp ("true", str) == 0) *val = TRUE; else if (strcmp ("false", str) == 0) *val = FALSE; else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Boolean values must be \"true\" or \"false\" not \"%s\""), str); return FALSE; } return TRUE; } static gboolean parse_rounding (const char *str, guint *val, GMarkupParseContext *context, MetaTheme *theme, GError **error) { if (strcmp ("true", str) == 0) *val = 5; /* historical "true" value */ else if (strcmp ("false", str) == 0) *val = 0; else { int tmp; gboolean result; if (!META_THEME_ALLOWS (theme, META_THEME_VARIED_ROUND_CORNERS)) { /* Not known in this version, so bail. */ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Boolean values must be \"true\" or \"false\" not \"%s\""), str); return FALSE; } result = parse_positive_integer (str, &tmp, context, theme, error); *val = tmp; return result; } return TRUE; } static gboolean parse_angle (const char *str, double *val, GMarkupParseContext *context, GError **error) { if (!parse_double (str, val, context, error)) return FALSE; if (*val < (0.0 - 1e6) || *val > (360.0 + 1e6)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Angle must be between 0.0 and 360.0, was %g\n"), *val); return FALSE; } return TRUE; } static gboolean parse_alpha (const char *str, MetaAlphaGradientSpec **spec_ret, GMarkupParseContext *context, GError **error) { char **split; int i; int n_alphas; MetaAlphaGradientSpec *spec; *spec_ret = NULL; split = g_strsplit (str, ":", -1); i = 0; while (split[i]) ++i; if (i == 0) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Could not parse \"%s\" as a floating point number"), str); g_strfreev (split); return FALSE; } n_alphas = i; /* FIXME allow specifying horizontal/vertical/diagonal in theme format, * once we implement vertical/diagonal in gradient.c */ spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL, n_alphas); i = 0; while (i < n_alphas) { double v; if (!parse_double (split[i], &v, context, error)) { /* clear up, but don't set error: it was set by parse_double */ g_strfreev (split); meta_alpha_gradient_spec_free (spec); return FALSE; } if (v < (0.0 - 1e-6) || v > (1.0 + 1e-6)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"), v); g_strfreev (split); meta_alpha_gradient_spec_free (spec); return FALSE; } spec->alphas[i] = (unsigned char) (v * 255); ++i; } g_strfreev (split); *spec_ret = spec; return TRUE; } static MetaColorSpec* parse_color (MetaTheme *theme, const char *str, GError **err) { char* referent; if (META_THEME_ALLOWS (theme, META_THEME_COLOR_CONSTANTS) && meta_theme_lookup_color_constant (theme, str, &referent)) { if (referent) return meta_color_spec_new_from_string (referent, err); /* no need to free referent: it's a pointer into the actual hash table */ } return meta_color_spec_new_from_string (str, err); } static gboolean parse_title_scale (const char *str, double *val, GMarkupParseContext *context, GError **error) { double factor; if (strcmp (str, "xx-small") == 0) factor = PANGO_SCALE_XX_SMALL; else if (strcmp (str, "x-small") == 0) factor = PANGO_SCALE_X_SMALL; else if (strcmp (str, "small") == 0) factor = PANGO_SCALE_SMALL; else if (strcmp (str, "medium") == 0) factor = PANGO_SCALE_MEDIUM; else if (strcmp (str, "large") == 0) factor = PANGO_SCALE_LARGE; else if (strcmp (str, "x-large") == 0) factor = PANGO_SCALE_X_LARGE; else if (strcmp (str, "xx-large") == 0) factor = PANGO_SCALE_XX_LARGE; else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Invalid title scale \"%s\" (must be one of xx-small,x-small,small,medium,large,x-large,xx-large)\n"), str); return FALSE; } *val = factor; return TRUE; } static void parse_toplevel_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_THEME); if (ELEMENT_IS ("info")) { if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; push_state (info, STATE_INFO); } else if (ELEMENT_IS ("constant")) { const char *name; const char *value; int ival = 0; double dval = 0.0; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, "!value", &value, NULL)) return; /* We don't know how a a constant is going to be used, so we have guess its * type from its contents: * * - Starts like a number and contains a '.': float constant * - Starts like a number and doesn't contain a '.': int constant * - Starts with anything else: a color constant. * (colors always start with # or a letter) */ if (value[0] == '.' || value[0] == '+' || value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) { if (strchr (value, '.')) { if (!parse_double (value, &dval, context, error)) return; if (!meta_theme_define_float_constant (info->theme, name, dval, error)) { add_context_to_error (error, context); return; } } else { if (!parse_positive_integer (value, &ival, context, info->theme, error)) return; if (!meta_theme_define_int_constant (info->theme, name, ival, error)) { add_context_to_error (error, context); return; } } } else { if (!meta_theme_define_color_constant (info->theme, name, value, error)) { add_context_to_error (error, context); return; } } push_state (info, STATE_CONSTANT); } else if (ELEMENT_IS ("frame_geometry")) { const char *name = NULL; const char *parent = NULL; const char *has_title = NULL; const char *title_scale = NULL; const char *rounded_top_left = NULL; const char *rounded_top_right = NULL; const char *rounded_bottom_left = NULL; const char *rounded_bottom_right = NULL; const char *hide_buttons = NULL; gboolean has_title_val; guint rounded_top_left_val; guint rounded_top_right_val; guint rounded_bottom_left_val; guint rounded_bottom_right_val; gboolean hide_buttons_val; double title_scale_val; MetaFrameLayout *parent_layout; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, "parent", &parent, "has_title", &has_title, "title_scale", &title_scale, "rounded_top_left", &rounded_top_left, "rounded_top_right", &rounded_top_right, "rounded_bottom_left", &rounded_bottom_left, "rounded_bottom_right", &rounded_bottom_right, "hide_buttons", &hide_buttons, NULL)) return; has_title_val = TRUE; if (has_title && !parse_boolean (has_title, &has_title_val, context, error)) return; hide_buttons_val = FALSE; if (hide_buttons && !parse_boolean (hide_buttons, &hide_buttons_val, context, error)) return; rounded_top_left_val = 0; rounded_top_right_val = 0; rounded_bottom_left_val = 0; rounded_bottom_right_val = 0; if (rounded_top_left && !parse_rounding (rounded_top_left, &rounded_top_left_val, context, info->theme, error)) return; if (rounded_top_right && !parse_rounding (rounded_top_right, &rounded_top_right_val, context, info->theme, error)) return; if (rounded_bottom_left && !parse_rounding (rounded_bottom_left, &rounded_bottom_left_val, context, info->theme, error)) return; if (rounded_bottom_right && !parse_rounding (rounded_bottom_right, &rounded_bottom_right_val, context, info->theme, error)) return; title_scale_val = 1.0; if (title_scale && !parse_title_scale (title_scale, &title_scale_val, context, error)) return; if (meta_theme_lookup_layout (info->theme, name)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> name \"%s\" used a second time"), element_name, name); return; } parent_layout = NULL; if (parent) { parent_layout = meta_theme_lookup_layout (info->theme, parent); if (parent_layout == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> parent \"%s\" has not been defined"), element_name, parent); return; } } g_assert (info->layout == NULL); if (parent_layout) info->layout = meta_frame_layout_copy (parent_layout); else info->layout = meta_frame_layout_new (); if (has_title) /* only if explicit, otherwise inherit */ info->layout->has_title = has_title_val; if (META_THEME_ALLOWS (info->theme, META_THEME_HIDDEN_BUTTONS) && hide_buttons_val) info->layout->hide_buttons = hide_buttons_val; if (title_scale) info->layout->title_scale = title_scale_val; if (rounded_top_left) info->layout->top_left_corner_rounded_radius = rounded_top_left_val; if (rounded_top_right) info->layout->top_right_corner_rounded_radius = rounded_top_right_val; if (rounded_bottom_left) info->layout->bottom_left_corner_rounded_radius = rounded_bottom_left_val; if (rounded_bottom_right) info->layout->bottom_right_corner_rounded_radius = rounded_bottom_right_val; meta_theme_insert_layout (info->theme, name, info->layout); push_state (info, STATE_FRAME_GEOMETRY); } else if (ELEMENT_IS ("draw_ops")) { const char *name = NULL; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, NULL)) return; if (meta_theme_lookup_draw_op_list (info->theme, name)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> name \"%s\" used a second time"), element_name, name); return; } g_assert (info->op_list == NULL); info->op_list = meta_draw_op_list_new (2); meta_theme_insert_draw_op_list (info->theme, name, info->op_list); push_state (info, STATE_DRAW_OPS); } else if (ELEMENT_IS ("frame_style")) { const char *name = NULL; const char *parent = NULL; const char *geometry = NULL; const char *background = NULL; const char *alpha = NULL; MetaFrameStyle *parent_style; MetaFrameLayout *layout; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, "parent", &parent, "geometry", &geometry, "background", &background, "alpha", &alpha, NULL)) return; if (meta_theme_lookup_style (info->theme, name)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> name \"%s\" used a second time"), element_name, name); return; } parent_style = NULL; if (parent) { parent_style = meta_theme_lookup_style (info->theme, parent); if (parent_style == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> parent \"%s\" has not been defined"), element_name, parent); return; } } layout = NULL; if (geometry) { layout = meta_theme_lookup_layout (info->theme, geometry); if (layout == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> geometry \"%s\" has not been defined"), element_name, geometry); return; } } else if (parent_style) { layout = parent_style->layout; } if (layout == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> must specify either a geometry or a parent that has a geometry"), element_name); return; } g_assert (info->style == NULL); info->style = meta_frame_style_new (parent_style); g_assert (info->style->layout == NULL); meta_frame_layout_ref (layout); info->style->layout = layout; if (background != NULL && META_THEME_ALLOWS (info->theme, META_THEME_FRAME_BACKGROUNDS)) { info->style->window_background_color = meta_color_spec_new_from_string (background, error); if (!info->style->window_background_color) return; if (alpha != NULL) { gboolean success; MetaAlphaGradientSpec *alpha_vector; g_clear_error (error); /* fortunately, we already have a routine to parse alpha values, * though it produces a vector of them, which is a superset of * what we want. */ success = parse_alpha (alpha, &alpha_vector, context, error); if (!success) return; /* alpha_vector->alphas must contain at least one element */ info->style->window_background_alpha = alpha_vector->alphas[0]; meta_alpha_gradient_spec_free (alpha_vector); } } else if (alpha != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("You must specify a background for an alpha value to be meaningful")); return; } meta_theme_insert_style (info->theme, name, info->style); push_state (info, STATE_FRAME_STYLE); } else if (ELEMENT_IS ("frame_style_set")) { const char *name = NULL; const char *parent = NULL; MetaFrameStyleSet *parent_set; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, "parent", &parent, NULL)) return; if (meta_theme_lookup_style_set (info->theme, name)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> name \"%s\" used a second time"), element_name, name); return; } parent_set = NULL; if (parent) { parent_set = meta_theme_lookup_style_set (info->theme, parent); if (parent_set == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> parent \"%s\" has not been defined"), element_name, parent); return; } } g_assert (info->style_set == NULL); info->style_set = meta_frame_style_set_new (parent_set); meta_theme_insert_style_set (info->theme, name, info->style_set); push_state (info, STATE_FRAME_STYLE_SET); } else if (ELEMENT_IS ("window")) { const char *type_name = NULL; const char *style_set_name = NULL; MetaFrameStyleSet *style_set; MetaFrameType type; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!type", &type_name, "!style_set", &style_set_name, NULL)) return; type = meta_frame_type_from_string (type_name); if (type == META_FRAME_TYPE_LAST || (type == META_FRAME_TYPE_ATTACHED && peek_required_version (info) < 3002)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Unknown type \"%s\" on <%s> element"), type_name, element_name); return; } style_set = meta_theme_lookup_style_set (info->theme, style_set_name); if (style_set == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Unknown style_set \"%s\" on <%s> element"), style_set_name, element_name); return; } if (info->theme->style_sets_by_type[type] != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Window type \"%s\" has already been assigned a style set"), type_name); return; } meta_frame_style_set_ref (style_set); info->theme->style_sets_by_type[type] = style_set; push_state (info, STATE_WINDOW); } else if (ELEMENT_IS ("menu_icon")) { /* Not supported any more, but we have to parse it if they include it, * for backwards compatibility. */ g_assert (info->op_list == NULL); push_state (info, STATE_MENU_ICON); } else if (ELEMENT_IS ("fallback")) { /* Not supported any more, but we have to parse it if they include it, * for backwards compatibility. */ push_state (info, STATE_FALLBACK); } else if (ELEMENT_IS ("shadow")) { /* ubuntu specific, workaround for light-themes: silently ignore shadow tag. */ push_state (info, UBUNTU_STATE_IGNORE); } else if (ELEMENT_IS ("padding")) { /* ubuntu specific, workaround for light-themes: silently ignore padding tag. */ push_state (info, UBUNTU_STATE_IGNORE); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "metacity_theme"); } } static void parse_info_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_INFO); if (ELEMENT_IS ("name")) { if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; push_state (info, STATE_NAME); } else if (ELEMENT_IS ("author")) { if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; push_state (info, STATE_AUTHOR); } else if (ELEMENT_IS ("copyright")) { if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; push_state (info, STATE_COPYRIGHT); } else if (ELEMENT_IS ("description")) { if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; push_state (info, STATE_DESCRIPTION); } else if (ELEMENT_IS ("date")) { if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; push_state (info, STATE_DATE); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "info"); } } static void parse_distance (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { const char *name; const char *value; int val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, "!value", &value, NULL)) return; val = 0; if (!parse_positive_integer (value, &val, context, info->theme, error)) return; g_assert (val >= 0); /* yeah, "non-negative" not "positive" get over it */ g_assert (info->layout); if (strcmp (name, "left_width") == 0) info->layout->left_width = val; else if (strcmp (name, "right_width") == 0) info->layout->right_width = val; else if (strcmp (name, "bottom_height") == 0) info->layout->bottom_height = val; else if (strcmp (name, "title_vertical_pad") == 0) info->layout->title_vertical_pad = val; else if (strcmp (name, "right_titlebar_edge") == 0) info->layout->right_titlebar_edge = val; else if (strcmp (name, "left_titlebar_edge") == 0) info->layout->left_titlebar_edge = val; else if (strcmp (name, "button_width") == 0) { info->layout->button_width = val; if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST || info->layout->button_sizing == META_BUTTON_SIZING_FIXED)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons")); return; } info->layout->button_sizing = META_BUTTON_SIZING_FIXED; } else if (strcmp (name, "button_height") == 0) { info->layout->button_height = val; if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST || info->layout->button_sizing == META_BUTTON_SIZING_FIXED)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons")); return; } info->layout->button_sizing = META_BUTTON_SIZING_FIXED; } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Distance \"%s\" is unknown"), name); return; } } static void parse_aspect_ratio (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { const char *name; const char *value; double val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, "!value", &value, NULL)) return; val = 0; if (!parse_double (value, &val, context, error)) return; g_assert (info->layout); if (strcmp (name, "button") == 0) { info->layout->button_aspect = val; if (info->layout->button_sizing != META_BUTTON_SIZING_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons")); return; } info->layout->button_sizing = META_BUTTON_SIZING_ASPECT; } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Aspect ratio \"%s\" is unknown"), name); return; } } static void parse_border (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { const char *name; const char *top; const char *bottom; const char *left; const char *right; int top_val; int bottom_val; int left_val; int right_val; GtkBorder *border; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!name", &name, "!top", &top, "!bottom", &bottom, "!left", &left, "!right", &right, NULL)) return; top_val = 0; if (!parse_positive_integer (top, &top_val, context, info->theme, error)) return; bottom_val = 0; if (!parse_positive_integer (bottom, &bottom_val, context, info->theme, error)) return; left_val = 0; if (!parse_positive_integer (left, &left_val, context, info->theme, error)) return; right_val = 0; if (!parse_positive_integer (right, &right_val, context, info->theme, error)) return; g_assert (info->layout); border = NULL; if (strcmp (name, "title_border") == 0) border = &info->layout->title_border; else if (strcmp (name, "button_border") == 0) border = &info->layout->button_border; if (border == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Border \"%s\" is unknown"), name); return; } border->top = top_val; border->bottom = bottom_val; border->left = left_val; border->right = right_val; } static void parse_geometry_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_FRAME_GEOMETRY); if (ELEMENT_IS ("distance")) { parse_distance (context, element_name, attribute_names, attribute_values, info, error); push_state (info, STATE_DISTANCE); } else if (ELEMENT_IS ("border")) { parse_border (context, element_name, attribute_names, attribute_values, info, error); push_state (info, STATE_BORDER); } else if (ELEMENT_IS ("aspect_ratio")) { parse_aspect_ratio (context, element_name, attribute_names, attribute_values, info, error); push_state (info, STATE_ASPECT_RATIO); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "frame_geometry"); } } #if 0 static gboolean check_expression (PosToken *tokens, int n_tokens, gboolean has_object, MetaTheme *theme, GMarkupParseContext *context, GError **error) { MetaPositionExprEnv env; int x, y; /* We set it all to 0 to try and catch divide-by-zero screwups. * it's possible we should instead guarantee that widths and heights * are at least 1. */ env.rect = meta_rect (0, 0, 0, 0); if (has_object) { env.object_width = 0; env.object_height = 0; } else { env.object_width = -1; env.object_height = -1; } env.left_width = 0; env.right_width = 0; env.top_height = 0; env.bottom_height = 0; env.title_width = 0; env.title_height = 0; env.icon_width = 0; env.icon_height = 0; env.mini_icon_width = 0; env.mini_icon_height = 0; env.theme = theme; if (!meta_parse_position_expression (tokens, n_tokens, &env, &x, &y, error)) { add_context_to_error (error, context); return FALSE; } return TRUE; } #endif static void parse_draw_op_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_DRAW_OPS); if (ELEMENT_IS ("line")) { MetaDrawOp *op; const char *color; const char *x1; const char *y1; const char *x2; const char *y2; const char *dash_on_length; const char *dash_off_length; const char *width; MetaColorSpec *color_spec; int dash_on_val; int dash_off_val; int width_val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!color", &color, "!x1", &x1, "!y1", &y1, "!x2", &x2, "!y2", &y2, "dash_on_length", &dash_on_length, "dash_off_length", &dash_off_length, "width", &width, NULL)) return; #if 0 if (!check_expression (x1, FALSE, info->theme, context, error)) return; if (!check_expression (y1, FALSE, info->theme, context, error)) return; if (!check_expression (x2, FALSE, info->theme, context, error)) return; if (!check_expression (y2, FALSE, info->theme, context, error)) return; #endif dash_on_val = 0; if (dash_on_length && !parse_positive_integer (dash_on_length, &dash_on_val, context, info->theme, error)) return; dash_off_val = 0; if (dash_off_length && !parse_positive_integer (dash_off_length, &dash_off_val, context, info->theme, error)) return; width_val = 0; if (width && !parse_positive_integer (width, &width_val, context, info->theme, error)) return; /* Check last so we don't have to free it when other * stuff fails */ color_spec = parse_color (info->theme, color, error); if (color_spec == NULL) { add_context_to_error (error, context); return; } op = meta_draw_op_new (META_DRAW_LINE); op->data.line.color_spec = color_spec; op->data.line.x1 = meta_draw_spec_new (info->theme, x1, NULL); op->data.line.y1 = meta_draw_spec_new (info->theme, y1, NULL); if (strcmp(x1, x2)==0) op->data.line.x2 = NULL; else op->data.line.x2 = meta_draw_spec_new (info->theme, x2, NULL); if (strcmp(y1, y2)==0) op->data.line.y2 = NULL; else op->data.line.y2 = meta_draw_spec_new (info->theme, y2, NULL); op->data.line.width = width_val; op->data.line.dash_on_length = dash_on_val; op->data.line.dash_off_length = dash_off_val; g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_LINE); } else if (ELEMENT_IS ("rectangle")) { MetaDrawOp *op; const char *color; const char *x; const char *y; const char *width; const char *height; const char *filled; gboolean filled_val; MetaColorSpec *color_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!color", &color, "!x", &x, "!y", &y, "!width", &width, "!height", &height, "filled", &filled, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif filled_val = FALSE; if (filled && !parse_boolean (filled, &filled_val, context, error)) return; /* Check last so we don't have to free it when other * stuff fails */ color_spec = parse_color (info->theme, color, error); if (color_spec == NULL) { add_context_to_error (error, context); return; } op = meta_draw_op_new (META_DRAW_RECTANGLE); op->data.rectangle.color_spec = color_spec; op->data.rectangle.x = meta_draw_spec_new (info->theme, x, NULL); op->data.rectangle.y = meta_draw_spec_new (info->theme, y, NULL); op->data.rectangle.width = meta_draw_spec_new (info->theme, width, NULL); op->data.rectangle.height = meta_draw_spec_new (info->theme, height, NULL); op->data.rectangle.filled = filled_val; g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_RECTANGLE); } else if (ELEMENT_IS ("arc")) { MetaDrawOp *op; const char *color; const char *x; const char *y; const char *width; const char *height; const char *filled; const char *start_angle; const char *extent_angle; const char *from; const char *to; gboolean filled_val; double start_angle_val; double extent_angle_val; MetaColorSpec *color_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!color", &color, "!x", &x, "!y", &y, "!width", &width, "!height", &height, "filled", &filled, "start_angle", &start_angle, "extent_angle", &extent_angle, "from", &from, "to", &to, NULL)) return; if (META_THEME_ALLOWS (info->theme, META_THEME_DEGREES_IN_ARCS) ) { if (start_angle == NULL && from == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No \"start_angle\" or \"from\" attribute on element <%s>"), element_name); return; } if (extent_angle == NULL && to == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No \"extent_angle\" or \"to\" attribute on element <%s>"), element_name); return; } } else { if (start_angle == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, ATTRIBUTE_NOT_FOUND, "start_angle", element_name); return; } if (extent_angle == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, ATTRIBUTE_NOT_FOUND, "extent_angle", element_name); return; } } #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif if (start_angle == NULL) { if (!parse_angle (from, &start_angle_val, context, error)) return; start_angle_val = (180-start_angle_val)/360.0; } else { if (!parse_angle (start_angle, &start_angle_val, context, error)) return; } if (extent_angle == NULL) { if (!parse_angle (to, &extent_angle_val, context, error)) return; extent_angle_val = ((180-extent_angle_val)/360.0) - start_angle_val; } else { if (!parse_angle (extent_angle, &extent_angle_val, context, error)) return; } filled_val = FALSE; if (filled && !parse_boolean (filled, &filled_val, context, error)) return; /* Check last so we don't have to free it when other * stuff fails */ color_spec = parse_color (info->theme, color, error); if (color_spec == NULL) { add_context_to_error (error, context); return; } op = meta_draw_op_new (META_DRAW_ARC); op->data.arc.color_spec = color_spec; op->data.arc.x = meta_draw_spec_new (info->theme, x, NULL); op->data.arc.y = meta_draw_spec_new (info->theme, y, NULL); op->data.arc.width = meta_draw_spec_new (info->theme, width, NULL); op->data.arc.height = meta_draw_spec_new (info->theme, height, NULL); op->data.arc.filled = filled_val; op->data.arc.start_angle = start_angle_val; op->data.arc.extent_angle = extent_angle_val; g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_ARC); } else if (ELEMENT_IS ("clip")) { MetaDrawOp *op; const char *x; const char *y; const char *width; const char *height; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!x", &x, "!y", &y, "!width", &width, "!height", &height, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif op = meta_draw_op_new (META_DRAW_CLIP); op->data.clip.x = meta_draw_spec_new (info->theme, x, NULL); op->data.clip.y = meta_draw_spec_new (info->theme, y, NULL); op->data.clip.width = meta_draw_spec_new (info->theme, width, NULL); op->data.clip.height = meta_draw_spec_new (info->theme, height, NULL); g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_CLIP); } else if (ELEMENT_IS ("tint")) { MetaDrawOp *op; const char *color; const char *x; const char *y; const char *width; const char *height; const char *alpha; MetaAlphaGradientSpec *alpha_spec; MetaColorSpec *color_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!color", &color, "!x", &x, "!y", &y, "!width", &width, "!height", &height, "!alpha", &alpha, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif alpha_spec = NULL; if (!parse_alpha (alpha, &alpha_spec, context, error)) return; /* Check last so we don't have to free it when other * stuff fails */ color_spec = parse_color (info->theme, color, error); if (color_spec == NULL) { if (alpha_spec) meta_alpha_gradient_spec_free (alpha_spec); add_context_to_error (error, context); return; } op = meta_draw_op_new (META_DRAW_TINT); op->data.tint.color_spec = color_spec; op->data.tint.alpha_spec = alpha_spec; op->data.tint.x = meta_draw_spec_new (info->theme, x, NULL); op->data.tint.y = meta_draw_spec_new (info->theme, y, NULL); op->data.tint.width = meta_draw_spec_new (info->theme, width, NULL); op->data.tint.height = meta_draw_spec_new (info->theme, height, NULL); g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_TINT); } else if (ELEMENT_IS ("gradient")) { const char *x; const char *y; const char *width; const char *height; const char *type; const char *alpha; MetaAlphaGradientSpec *alpha_spec; MetaGradientType type_val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!type", &type, "!x", &x, "!y", &y, "!width", &width, "!height", &height, "alpha", &alpha, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif type_val = meta_gradient_type_from_string (type); if (type_val == META_GRADIENT_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand value \"%s\" for type of gradient"), type); return; } alpha_spec = NULL; if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) return; g_assert (info->op == NULL); info->op = meta_draw_op_new (META_DRAW_GRADIENT); info->op->data.gradient.x = meta_draw_spec_new (info->theme, x, NULL); info->op->data.gradient.y = meta_draw_spec_new (info->theme, y, NULL); info->op->data.gradient.width = meta_draw_spec_new (info->theme, width, NULL); info->op->data.gradient.height = meta_draw_spec_new (info->theme, height, NULL); info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val); info->op->data.gradient.alpha_spec = alpha_spec; push_state (info, STATE_GRADIENT); /* op gets appended on close tag */ } else if (ELEMENT_IS ("image")) { MetaDrawOp *op; const char *filename; const char *x; const char *y; const char *width; const char *height; const char *alpha; const char *colorize; const char *fill_type; MetaAlphaGradientSpec *alpha_spec; GdkPixbuf *pixbuf; MetaColorSpec *colorize_spec = NULL; MetaImageFillType fill_type_val; int h, w, c; int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride; guchar *pixbuf_pixels; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!x", &x, "!y", &y, "!width", &width, "!height", &height, "alpha", &alpha, "!filename", &filename, "colorize", &colorize, "fill_type", &fill_type, NULL)) return; #if 0 if (!check_expression (x, TRUE, info->theme, context, error)) return; if (!check_expression (y, TRUE, info->theme, context, error)) return; if (!check_expression (width, TRUE, info->theme, context, error)) return; if (!check_expression (height, TRUE, info->theme, context, error)) return; #endif fill_type_val = META_IMAGE_FILL_SCALE; if (fill_type) { fill_type_val = meta_image_fill_type_from_string (fill_type); if (((int) fill_type_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand fill type \"%s\" for <%s> element"), fill_type, element_name); } } /* Check last so we don't have to free it when other * stuff fails. * */ pixbuf = meta_theme_load_image (info->theme, filename, info->theme->scale, error); if (pixbuf == NULL) { add_context_to_error (error, context); return; } if (colorize) { colorize_spec = parse_color (info->theme, colorize, error); if (colorize_spec == NULL) { add_context_to_error (error, context); g_object_unref (G_OBJECT (pixbuf)); return; } } alpha_spec = NULL; if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) { g_object_unref (G_OBJECT (pixbuf)); return; } op = meta_draw_op_new (META_DRAW_IMAGE); op->data.image.pixbuf = pixbuf; op->data.image.colorize_spec = colorize_spec; op->data.image.x = meta_draw_spec_new (info->theme, x, NULL); op->data.image.y = meta_draw_spec_new (info->theme, y, NULL); op->data.image.width = meta_draw_spec_new (info->theme, width, NULL); op->data.image.height = meta_draw_spec_new (info->theme, height, NULL); op->data.image.alpha_spec = alpha_spec; op->data.image.fill_type = fill_type_val; /* Check for vertical & horizontal stripes */ pixbuf_n_channels = gdk_pixbuf_get_n_channels(pixbuf); pixbuf_width = gdk_pixbuf_get_width(pixbuf); pixbuf_height = gdk_pixbuf_get_height(pixbuf); pixbuf_rowstride = gdk_pixbuf_get_rowstride(pixbuf); pixbuf_pixels = gdk_pixbuf_get_pixels(pixbuf); /* Check for horizontal stripes */ for (h = 0; h < pixbuf_height; h++) { for (w = 1; w < pixbuf_width; w++) { for (c = 0; c < pixbuf_n_channels; c++) { if (pixbuf_pixels[(h * pixbuf_rowstride) + c] != pixbuf_pixels[(h * pixbuf_rowstride) + w + c]) break; } if (c < pixbuf_n_channels) break; } if (w < pixbuf_width) break; } if (h >= pixbuf_height) { op->data.image.horizontal_stripes = TRUE; } else { op->data.image.horizontal_stripes = FALSE; } /* Check for vertical stripes */ for (w = 0; w < pixbuf_width; w++) { for (h = 1; h < pixbuf_height; h++) { for (c = 0; c < pixbuf_n_channels; c++) { if (pixbuf_pixels[w + c] != pixbuf_pixels[(h * pixbuf_rowstride) + w + c]) break; } if (c < pixbuf_n_channels) break; } if (h < pixbuf_height) break; } if (w >= pixbuf_width) { op->data.image.vertical_stripes = TRUE; } else { op->data.image.vertical_stripes = FALSE; } g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_IMAGE); } else if (ELEMENT_IS ("gtk_arrow")) { MetaDrawOp *op; const char *state; const char *shadow; const char *arrow; const char *x; const char *y; const char *width; const char *height; const char *filled; gboolean filled_val; GtkStateFlags state_val; GtkShadowType shadow_val; GtkArrowType arrow_val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!state", &state, "!shadow", &shadow, "!arrow", &arrow, "!x", &x, "!y", &y, "!width", &width, "!height", &height, "filled", &filled, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif filled_val = TRUE; if (filled && !parse_boolean (filled, &filled_val, context, error)) return; state_val = meta_gtk_state_from_string (state); if (((int) state_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand state \"%s\" for <%s> element"), state, element_name); return; } shadow_val = meta_gtk_shadow_from_string (shadow); if (((int) shadow_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand shadow \"%s\" for <%s> element"), shadow, element_name); return; } arrow_val = meta_gtk_arrow_from_string (arrow); if (((int) arrow_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand arrow \"%s\" for <%s> element"), arrow, element_name); return; } op = meta_draw_op_new (META_DRAW_GTK_ARROW); op->data.gtk_arrow.x = meta_draw_spec_new (info->theme, x, NULL); op->data.gtk_arrow.y = meta_draw_spec_new (info->theme, y, NULL); op->data.gtk_arrow.width = meta_draw_spec_new (info->theme, width, NULL); op->data.gtk_arrow.height = meta_draw_spec_new (info->theme, height, NULL); op->data.gtk_arrow.filled = filled_val; op->data.gtk_arrow.state = state_val; op->data.gtk_arrow.shadow = shadow_val; op->data.gtk_arrow.arrow = arrow_val; g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_GTK_ARROW); } else if (ELEMENT_IS ("gtk_box")) { MetaDrawOp *op; const char *state; const char *shadow; const char *x; const char *y; const char *width; const char *height; GtkStateFlags state_val; GtkShadowType shadow_val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!state", &state, "!shadow", &shadow, "!x", &x, "!y", &y, "!width", &width, "!height", &height, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif state_val = meta_gtk_state_from_string (state); if (((int) state_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand state \"%s\" for <%s> element"), state, element_name); return; } shadow_val = meta_gtk_shadow_from_string (shadow); if (((int) shadow_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand shadow \"%s\" for <%s> element"), shadow, element_name); return; } op = meta_draw_op_new (META_DRAW_GTK_BOX); op->data.gtk_box.x = meta_draw_spec_new (info->theme, x, NULL); op->data.gtk_box.y = meta_draw_spec_new (info->theme, y, NULL); op->data.gtk_box.width = meta_draw_spec_new (info->theme, width, NULL); op->data.gtk_box.height = meta_draw_spec_new (info->theme, height, NULL); op->data.gtk_box.state = state_val; op->data.gtk_box.shadow = shadow_val; g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_GTK_BOX); } else if (ELEMENT_IS ("gtk_vline")) { MetaDrawOp *op; const char *state; const char *x; const char *y1; const char *y2; GtkStateFlags state_val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!state", &state, "!x", &x, "!y1", &y1, "!y2", &y2, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y1, FALSE, info->theme, context, error)) return; if (!check_expression (y2, FALSE, info->theme, context, error)) return; #endif state_val = meta_gtk_state_from_string (state); if (((int) state_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand state \"%s\" for <%s> element"), state, element_name); return; } op = meta_draw_op_new (META_DRAW_GTK_VLINE); op->data.gtk_vline.x = meta_draw_spec_new (info->theme, x, NULL); op->data.gtk_vline.y1 = meta_draw_spec_new (info->theme, y1, NULL); op->data.gtk_vline.y2 = meta_draw_spec_new (info->theme, y2, NULL); op->data.gtk_vline.state = state_val; g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_GTK_VLINE); } else if (ELEMENT_IS ("icon")) { MetaDrawOp *op; const char *x; const char *y; const char *width; const char *height; const char *alpha; const char *fill_type; MetaAlphaGradientSpec *alpha_spec; MetaImageFillType fill_type_val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!x", &x, "!y", &y, "!width", &width, "!height", &height, "alpha", &alpha, "fill_type", &fill_type, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (width, FALSE, info->theme, context, error)) return; if (!check_expression (height, FALSE, info->theme, context, error)) return; #endif fill_type_val = META_IMAGE_FILL_SCALE; if (fill_type) { fill_type_val = meta_image_fill_type_from_string (fill_type); if (((int) fill_type_val) == -1) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Did not understand fill type \"%s\" for <%s> element"), fill_type, element_name); } } alpha_spec = NULL; if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) return; op = meta_draw_op_new (META_DRAW_ICON); op->data.icon.x = meta_draw_spec_new (info->theme, x, NULL); op->data.icon.y = meta_draw_spec_new (info->theme, y, NULL); op->data.icon.width = meta_draw_spec_new (info->theme, width, NULL); op->data.icon.height = meta_draw_spec_new (info->theme, height, NULL); op->data.icon.alpha_spec = alpha_spec; op->data.icon.fill_type = fill_type_val; g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_ICON); } else if (ELEMENT_IS ("title")) { MetaDrawOp *op; const char *color; const char *x; const char *y; const char *ellipsize_width; MetaColorSpec *color_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!color", &color, "!x", &x, "!y", &y, "ellipsize_width", &ellipsize_width, NULL)) return; #if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; if (!check_expression (ellipsize_width, FALSE, info->theme, context, error)) return; #endif if (ellipsize_width && peek_required_version (info) < 3001) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, ATTRIBUTE_NOT_FOUND, "ellipsize_width", element_name); return; } /* Check last so we don't have to free it when other * stuff fails */ color_spec = parse_color (info->theme, color, error); if (color_spec == NULL) { add_context_to_error (error, context); return; } op = meta_draw_op_new (META_DRAW_TITLE); op->data.title.color_spec = color_spec; op->data.title.x = meta_draw_spec_new (info->theme, x, NULL); op->data.title.y = meta_draw_spec_new (info->theme, y, NULL); if (ellipsize_width) op->data.title.ellipsize_width = meta_draw_spec_new (info->theme, ellipsize_width, NULL); g_assert (info->op_list); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_TITLE); } else if (ELEMENT_IS ("include")) { MetaDrawOp *op; const char *name; const char *x; const char *y; const char *width; const char *height; MetaDrawOpList *op_list; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "x", &x, "y", &y, "width", &width, "height", &height, "!name", &name, NULL)) return; /* x/y/width/height default to 0,0,width,height - should * probably do this for all the draw ops */ #if 0 if (x && !check_expression (x, FALSE, info->theme, context, error)) return; if (y && !check_expression (y, FALSE, info->theme, context, error)) return; if (width && !check_expression (width, FALSE, info->theme, context, error)) return; if (height && !check_expression (height, FALSE, info->theme, context, error)) return; #endif op_list = meta_theme_lookup_draw_op_list (info->theme, name); if (op_list == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No <draw_ops> called \"%s\" has been defined"), name); return; } g_assert (info->op_list); if (op_list == info->op_list || meta_draw_op_list_contains (op_list, info->op_list)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Including draw_ops \"%s\" here would create a circular reference"), name); return; } op = meta_draw_op_new (META_DRAW_OP_LIST); meta_draw_op_list_ref (op_list); op->data.op_list.op_list = op_list; op->data.op_list.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL); op->data.op_list.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL); op->data.op_list.width = meta_draw_spec_new (info->theme, width ? width : "width", NULL); op->data.op_list.height = meta_draw_spec_new (info->theme, height ? height : "height", NULL); meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_INCLUDE); } else if (ELEMENT_IS ("tile")) { MetaDrawOp *op; const char *name; const char *x; const char *y; const char *width; const char *height; const char *tile_xoffset; const char *tile_yoffset; const char *tile_width; const char *tile_height; MetaDrawOpList *op_list; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "x", &x, "y", &y, "width", &width, "height", &height, "!name", &name, "tile_xoffset", &tile_xoffset, "tile_yoffset", &tile_yoffset, "!tile_width", &tile_width, "!tile_height", &tile_height, NULL)) return; /* These default to 0 */ #if 0 if (tile_xoffset && !check_expression (tile_xoffset, FALSE, info->theme, context, error)) return; if (tile_yoffset && !check_expression (tile_yoffset, FALSE, info->theme, context, error)) return; /* x/y/width/height default to 0,0,width,height - should * probably do this for all the draw ops */ if (x && !check_expression (x, FALSE, info->theme, context, error)) return; if (y && !check_expression (y, FALSE, info->theme, context, error)) return; if (width && !check_expression (width, FALSE, info->theme, context, error)) return; if (height && !check_expression (height, FALSE, info->theme, context, error)) return; if (!check_expression (tile_width, FALSE, info->theme, context, error)) return; if (!check_expression (tile_height, FALSE, info->theme, context, error)) return; #endif op_list = meta_theme_lookup_draw_op_list (info->theme, name); if (op_list == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No <draw_ops> called \"%s\" has been defined"), name); return; } g_assert (info->op_list); if (op_list == info->op_list || meta_draw_op_list_contains (op_list, info->op_list)) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Including draw_ops \"%s\" here would create a circular reference"), name); return; } op = meta_draw_op_new (META_DRAW_TILE); meta_draw_op_list_ref (op_list); op->data.tile.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL); op->data.tile.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL); op->data.tile.width = meta_draw_spec_new (info->theme, width ? width : "width", NULL); op->data.tile.height = meta_draw_spec_new (info->theme, height ? height : "height", NULL); op->data.tile.tile_xoffset = meta_draw_spec_new (info->theme, tile_xoffset ? tile_xoffset : "0", NULL); op->data.tile.tile_yoffset = meta_draw_spec_new (info->theme, tile_yoffset ? tile_yoffset : "0", NULL); op->data.tile.tile_width = meta_draw_spec_new (info->theme, tile_width, NULL); op->data.tile.tile_height = meta_draw_spec_new (info->theme, tile_height, NULL); op->data.tile.op_list = op_list; meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_TILE); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "draw_ops"); } } static void parse_gradient_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_GRADIENT); if (ELEMENT_IS ("color")) { const char *value = NULL; MetaColorSpec *color_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!value", &value, NULL)) return; color_spec = parse_color (info->theme, value, error); if (color_spec == NULL) { add_context_to_error (error, context); return; } g_assert (info->op); g_assert (info->op->type == META_DRAW_GRADIENT); g_assert (info->op->data.gradient.gradient_spec != NULL); info->op->data.gradient.gradient_spec->color_specs = g_slist_append (info->op->data.gradient.gradient_spec->color_specs, color_spec); push_state (info, STATE_COLOR); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "gradient"); } } static void parse_style_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE); g_assert (info->style); if (ELEMENT_IS ("piece")) { const char *position = NULL; const char *draw_ops = NULL; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!position", &position, "draw_ops", &draw_ops, NULL)) return; info->piece = meta_frame_piece_from_string (position); if (info->piece == META_FRAME_PIECE_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Unknown position \"%s\" for frame piece"), position); return; } if (info->style->pieces[info->piece] != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Frame style already has a piece at position %s"), position); return; } g_assert (info->op_list == NULL); if (draw_ops) { MetaDrawOpList *op_list; op_list = meta_theme_lookup_draw_op_list (info->theme, draw_ops); if (op_list == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No <draw_ops> with the name \"%s\" has been defined"), draw_ops); return; } meta_draw_op_list_ref (op_list); info->op_list = op_list; } push_state (info, STATE_PIECE); } else if (ELEMENT_IS ("button")) { const char *function = NULL; const char *state = NULL; const char *draw_ops = NULL; gint required_version; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!function", &function, "!state", &state, "draw_ops", &draw_ops, NULL)) return; info->button_type = meta_button_type_from_string (function, info->theme); if (info->button_type == META_BUTTON_TYPE_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Unknown function \"%s\" for button"), function); return; } required_version = peek_required_version (info); if (meta_theme_earliest_version_with_button (info->button_type) > (guint)required_version) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Button function \"%s\" does not exist in this version (%d, need %d)"), function, required_version, meta_theme_earliest_version_with_button (info->button_type) ); return; } info->button_state = meta_button_state_from_string (state); if (info->button_state == META_BUTTON_STATE_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Unknown state \"%s\" for button"), state); return; } if (info->style->buttons[info->button_type][info->button_state] != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Frame style already has a button for function %s state %s"), function, state); return; } g_assert (info->op_list == NULL); if (draw_ops) { MetaDrawOpList *op_list; op_list = meta_theme_lookup_draw_op_list (info->theme, draw_ops); if (op_list == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No <draw_ops> with the name \"%s\" has been defined"), draw_ops); return; } meta_draw_op_list_ref (op_list); info->op_list = op_list; } push_state (info, STATE_BUTTON); } else if (ELEMENT_IS ("shadow")) { /* ubuntu specific, workaround for light-themes: silently ignore shadow tag. */ push_state (info, UBUNTU_STATE_IGNORE); } else if (ELEMENT_IS ("padding")) { /* ubuntu specific, workaround for light-themes: silently ignore padding tag. */ push_state (info, UBUNTU_STATE_IGNORE); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "frame_style"); } } static void parse_style_set_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE_SET); if (ELEMENT_IS ("frame")) { const char *focus = NULL; const char *state = NULL; const char *resize = NULL; const char *style = NULL; MetaFrameFocus frame_focus; MetaFrameState frame_state; MetaFrameResize frame_resize; MetaFrameStyle *frame_style; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!focus", &focus, "!state", &state, "resize", &resize, "!style", &style, NULL)) return; frame_focus = meta_frame_focus_from_string (focus); if (frame_focus == META_FRAME_FOCUS_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("\"%s\" is not a valid value for focus attribute"), focus); return; } frame_state = meta_frame_state_from_string (state); if (frame_state == META_FRAME_STATE_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("\"%s\" is not a valid value for state attribute"), focus); return; } frame_style = meta_theme_lookup_style (info->theme, style); if (frame_style == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("A style called \"%s\" has not been defined"), style); return; } switch (frame_state) { case META_FRAME_STATE_NORMAL: if (resize == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, ATTRIBUTE_NOT_FOUND, "resize", element_name); return; } frame_resize = meta_frame_resize_from_string (resize); if (frame_resize == META_FRAME_RESIZE_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("\"%s\" is not a valid value for resize attribute"), focus); return; } break; case META_FRAME_STATE_SHADED: if (META_THEME_ALLOWS (info->theme, META_THEME_UNRESIZABLE_SHADED_STYLES)) { if (resize == NULL) /* In state="normal" we would complain here. But instead we accept * not having a resize attribute and default to resize="both", since * that most closely mimics what we did in v1, and thus people can * upgrade a theme to v2 without as much hassle. */ frame_resize = META_FRAME_RESIZE_BOTH; else { frame_resize = meta_frame_resize_from_string (resize); if (frame_resize == META_FRAME_RESIZE_LAST) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("\"%s\" is not a valid value for resize attribute"), focus); return; } } } else /* v1 theme */ { if (resize != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Should not have \"resize\" attribute on <%s> element for maximized/shaded states"), element_name); return; } /* resize="both" is equivalent to the old behaviour */ frame_resize = META_FRAME_RESIZE_BOTH; } break; default: if (resize != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Should not have \"resize\" attribute on <%s> element for maximized states"), element_name); return; } frame_resize = META_FRAME_RESIZE_LAST; } switch (frame_state) { case META_FRAME_STATE_NORMAL: if (info->style_set->normal_styles[frame_resize][frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s resize %s focus %s"), state, resize, focus); return; } meta_frame_style_ref (frame_style); info->style_set->normal_styles[frame_resize][frame_focus] = frame_style; break; case META_FRAME_STATE_MAXIMIZED: if (info->style_set->maximized_styles[frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s focus %s"), state, focus); return; } meta_frame_style_ref (frame_style); info->style_set->maximized_styles[frame_focus] = frame_style; break; case META_FRAME_STATE_TILED_LEFT: if (info->style_set->tiled_left_styles[frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s focus %s"), state, focus); return; } meta_frame_style_ref (frame_style); info->style_set->tiled_left_styles[frame_focus] = frame_style; break; case META_FRAME_STATE_TILED_RIGHT: if (info->style_set->tiled_right_styles[frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s focus %s"), state, focus); return; } meta_frame_style_ref (frame_style); info->style_set->tiled_right_styles[frame_focus] = frame_style; break; meta_frame_style_ref (frame_style); info->style_set->tiled_right_styles[frame_focus] = frame_style; break; case META_FRAME_STATE_SHADED: if (info->style_set->shaded_styles[frame_resize][frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s resize %s focus %s"), state, resize, focus); return; } meta_frame_style_ref (frame_style); info->style_set->shaded_styles[frame_resize][frame_focus] = frame_style; break; case META_FRAME_STATE_MAXIMIZED_AND_SHADED: if (info->style_set->maximized_and_shaded_styles[frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s focus %s"), state, focus); return; } meta_frame_style_ref (frame_style); info->style_set->maximized_and_shaded_styles[frame_focus] = frame_style; break; case META_FRAME_STATE_TILED_LEFT_AND_SHADED: if (info->style_set->tiled_left_and_shaded_styles[frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s focus %s"), state, focus); return; } meta_frame_style_ref (frame_style); info->style_set->tiled_left_and_shaded_styles[frame_focus] = frame_style; break; case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: if (info->style_set->tiled_right_and_shaded_styles[frame_focus]) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Style has already been specified for state %s focus %s"), state, focus); return; } meta_frame_style_ref (frame_style); info->style_set->tiled_right_and_shaded_styles[frame_focus] = frame_style; break; case META_FRAME_STATE_LAST: g_assert_not_reached (); break; } push_state (info, STATE_FRAME); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "frame_style_set"); } } static void parse_piece_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_PIECE); if (ELEMENT_IS ("draw_ops")) { if (info->op_list) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Can't have a two draw_ops for a <piece> element (theme specified a draw_ops attribute and also a <draw_ops> element, or specified two elements)")); return; } if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; g_assert (info->op_list == NULL); info->op_list = meta_draw_op_list_new (2); push_state (info, STATE_DRAW_OPS); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "piece"); } } static void parse_button_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_BUTTON); if (ELEMENT_IS ("draw_ops")) { if (info->op_list) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Can't have a two draw_ops for a <button> element (theme specified a draw_ops attribute and also a <draw_ops> element, or specified two elements)")); return; } if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; g_assert (info->op_list == NULL); info->op_list = meta_draw_op_list_new (2); push_state (info, STATE_DRAW_OPS); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "button"); } } static void parse_menu_icon_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, ParseInfo *info, GError **error) { g_return_if_fail (peek_state (info) == STATE_MENU_ICON); if (ELEMENT_IS ("draw_ops")) { if (info->op_list) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Can't have a two draw_ops for a <menu_icon> element (theme specified a draw_ops attribute and also a <draw_ops> element, or specified two elements)")); return; } if (!check_no_attributes (context, element_name, attribute_names, attribute_values, error)) return; g_assert (info->op_list == NULL); info->op_list = meta_draw_op_list_new (2); push_state (info, STATE_DRAW_OPS); } else { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed below <%s>"), element_name, "menu_icon"); } } static const char * find_version (const char **attribute_names, const char **attribute_values) { int i; for (i = 0; attribute_names[i]; i++) { if (strcmp (attribute_names[i], "version") == 0) return attribute_values[i]; } return NULL; } /* Returns whether the version element was successfully parsed. * If successfully parsed, then two additional items are returned: * * satisfied: whether this version of Muffin meets the version check * minimum_required: minimum version of theme format required by version check */ static gboolean check_version (GMarkupParseContext *context, const char *version_str, gboolean *satisfied, guint *minimum_required, GError **error) { static GRegex *version_regex; GMatchInfo *info; char *comparison_str, *major_str, *minor_str; guint version; *minimum_required = 0; if (!version_regex) version_regex = g_regex_new ("^\\s*([<>]=?)\\s*(\\d+)(\\.\\d+)?\\s*$", 0, 0, NULL); if (!g_regex_match (version_regex, version_str, 0, &info)) { g_match_info_free (info); set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Bad version specification '%s'"), version_str); return FALSE; } comparison_str = g_match_info_fetch (info, 1); major_str = g_match_info_fetch (info, 2); minor_str = g_match_info_fetch (info, 3); version = 1000 * atoi (major_str); /* might get NULL, see: https://bugzilla.gnome.org/review?bug=588217 */ if (minor_str && minor_str[0]) version += atoi (minor_str + 1); if (comparison_str[0] == '<') { if (comparison_str[1] == '=') *satisfied = THEME_VERSION <= version; else { *satisfied = THEME_VERSION < version; } } else { if (comparison_str[1] == '=') { *satisfied = THEME_VERSION >= version; *minimum_required = version; } else { *satisfied = THEME_VERSION > version; *minimum_required = version + 1; } } free (comparison_str); free (major_str); free (minor_str); g_match_info_free (info); return TRUE; } static void start_element_handler (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { ParseInfo *info = user_data; const char *version; guint required_version = 0; if (info->skip_level > 0) { info->skip_level++; return; } required_version = peek_required_version (info); version = find_version (attribute_names, attribute_values); if (version != NULL) { gboolean satisfied; guint element_required; if (required_version < 3000) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("\"version\" attribute cannot be used in metacity-theme-1.xml or metacity-theme-2.xml")); return; } if (!check_version (context, version, &satisfied, &element_required, error)) return; /* Two different ways of handling an unsatisfied version check: * for the toplevel element of a file, we throw an error back so * that the controlling code can go ahead and look for an * alternate metacity-theme-1.xml or metacity-theme-2.xml; for * other elements we just silently skip the element and children. */ if (peek_state (info) == STATE_START) { if (satisfied) { if (element_required > info->format_version) info->format_version = element_required; } else { set_error (error, context, THEME_PARSE_ERROR, THEME_PARSE_ERROR_TOO_OLD, _("Theme requires version %s but latest supported theme version is %d.%d"), version, THEME_VERSION, THEME_MINOR_VERSION); return; } } else if (!satisfied) { info->skip_level = 1; return; } if (element_required > required_version) required_version = element_required; } push_required_version (info, required_version); switch (peek_state (info)) { case STATE_START: if (strcmp (element_name, "metacity_theme") == 0) { info->theme = meta_theme_new (); info->theme->name = g_strdup (info->theme_name); info->theme->filename = g_strdup (info->theme_file); info->theme->dirname = g_strdup (info->theme_dir); info->theme->format_version = info->format_version; info->theme->scale = meta_prefs_get_ui_scale (); push_state (info, STATE_THEME); } else set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Outermost element in theme must be <metacity_theme> not <%s>"), element_name); break; case STATE_THEME: parse_toplevel_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_INFO: parse_info_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_NAME: case STATE_AUTHOR: case STATE_COPYRIGHT: case STATE_DATE: case STATE_DESCRIPTION: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a name/author/date/description element"), element_name); break; case STATE_CONSTANT: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a <constant> element"), element_name); break; case STATE_FRAME_GEOMETRY: parse_geometry_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_DISTANCE: case STATE_BORDER: case STATE_ASPECT_RATIO: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a distance/border/aspect_ratio element"), element_name); break; case STATE_DRAW_OPS: parse_draw_op_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_LINE: case STATE_RECTANGLE: case STATE_ARC: case STATE_CLIP: case STATE_TINT: case STATE_IMAGE: case STATE_GTK_ARROW: case STATE_GTK_BOX: case STATE_GTK_VLINE: case STATE_ICON: case STATE_TITLE: case STATE_INCLUDE: case STATE_TILE: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a draw operation element"), element_name); break; case STATE_GRADIENT: parse_gradient_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_COLOR: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a <%s> element"), element_name, "color"); break; case STATE_FRAME_STYLE: parse_style_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_PIECE: parse_piece_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_BUTTON: parse_button_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_MENU_ICON: parse_menu_icon_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_FRAME_STYLE_SET: parse_style_set_element (context, element_name, attribute_names, attribute_values, info, error); break; case STATE_FRAME: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a <%s> element"), element_name, "frame"); break; case STATE_WINDOW: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a <%s> element"), element_name, "window"); break; case STATE_FALLBACK: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a <%s> element"), element_name, "fallback"); break; case UBUNTU_STATE_IGNORE: break; } } static void end_element_handler (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) { ParseInfo *info = user_data; if (info->skip_level > 0) { info->skip_level--; return; } switch (peek_state (info)) { case STATE_START: break; case STATE_THEME: g_assert (info->theme); if (!meta_theme_validate (info->theme, error)) { add_context_to_error (error, context); meta_theme_free (info->theme); info->theme = NULL; } pop_state (info); g_assert (peek_state (info) == STATE_START); break; case STATE_INFO: pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case STATE_NAME: pop_state (info); g_assert (peek_state (info) == STATE_INFO); break; case STATE_AUTHOR: pop_state (info); g_assert (peek_state (info) == STATE_INFO); break; case STATE_COPYRIGHT: pop_state (info); g_assert (peek_state (info) == STATE_INFO); break; case STATE_DATE: pop_state (info); g_assert (peek_state (info) == STATE_INFO); break; case STATE_DESCRIPTION: pop_state (info); g_assert (peek_state (info) == STATE_INFO); break; case STATE_CONSTANT: pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case STATE_FRAME_GEOMETRY: g_assert (info->layout); if (!meta_frame_layout_validate (info->layout, error)) { add_context_to_error (error, context); } /* layout will already be stored in the theme under * its name */ meta_frame_layout_unref (info->layout); info->layout = NULL; pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case STATE_DISTANCE: pop_state (info); g_assert (peek_state (info) == STATE_FRAME_GEOMETRY); break; case STATE_BORDER: pop_state (info); g_assert (peek_state (info) == STATE_FRAME_GEOMETRY); break; case STATE_ASPECT_RATIO: pop_state (info); g_assert (peek_state (info) == STATE_FRAME_GEOMETRY); break; case STATE_DRAW_OPS: { g_assert (info->op_list); if (!meta_draw_op_list_validate (info->op_list, error)) { add_context_to_error (error, context); meta_draw_op_list_unref (info->op_list); info->op_list = NULL; } pop_state (info); switch (peek_state (info)) { case STATE_BUTTON: case STATE_PIECE: case STATE_MENU_ICON: /* Leave info->op_list to be picked up * when these elements are closed */ g_assert (info->op_list); break; case STATE_THEME: g_assert (info->op_list); meta_draw_op_list_unref (info->op_list); info->op_list = NULL; break; default: /* Op list can't occur in other contexts */ g_assert_not_reached (); break; } } break; case STATE_LINE: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_RECTANGLE: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_ARC: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_CLIP: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_TINT: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_GRADIENT: g_assert (info->op); g_assert (info->op->type == META_DRAW_GRADIENT); if (!meta_gradient_spec_validate (info->op->data.gradient.gradient_spec, error)) { add_context_to_error (error, context); meta_draw_op_free (info->op); info->op = NULL; } else { g_assert (info->op_list); meta_draw_op_list_append (info->op_list, info->op); info->op = NULL; } pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_IMAGE: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_GTK_ARROW: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_GTK_BOX: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_GTK_VLINE: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_ICON: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_TITLE: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_INCLUDE: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_TILE: pop_state (info); g_assert (peek_state (info) == STATE_DRAW_OPS); break; case STATE_COLOR: pop_state (info); g_assert (peek_state (info) == STATE_GRADIENT); break; case STATE_FRAME_STYLE: g_assert (info->style); if (!meta_frame_style_validate (info->style, peek_required_version (info), error)) { add_context_to_error (error, context); } /* Frame style is in the theme hash table and a ref * is held there */ meta_frame_style_unref (info->style); info->style = NULL; pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case STATE_PIECE: g_assert (info->style); if (info->op_list == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No draw_ops provided for frame piece")); } else { info->style->pieces[info->piece] = info->op_list; info->op_list = NULL; } pop_state (info); g_assert (peek_state (info) == STATE_FRAME_STYLE); break; case STATE_BUTTON: g_assert (info->style); if (info->op_list == NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No draw_ops provided for button")); } else { info->style->buttons[info->button_type][info->button_state] = info->op_list; info->op_list = NULL; } pop_state (info); break; case STATE_MENU_ICON: g_assert (info->theme); if (info->op_list != NULL) { meta_draw_op_list_unref (info->op_list); info->op_list = NULL; } pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case STATE_FRAME_STYLE_SET: g_assert (info->style_set); if (!meta_frame_style_set_validate (info->style_set, error)) { add_context_to_error (error, context); } /* Style set is in the theme hash table and a reference * is held there. */ meta_frame_style_set_unref (info->style_set); info->style_set = NULL; pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case STATE_FRAME: pop_state (info); g_assert (peek_state (info) == STATE_FRAME_STYLE_SET); break; case STATE_WINDOW: pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case STATE_FALLBACK: pop_state (info); g_assert (peek_state (info) == STATE_THEME); break; case UBUNTU_STATE_IGNORE: pop_state (info); break; } pop_required_version (info); } #define NO_TEXT(element_name) set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No text is allowed inside element <%s>"), element_name) static gboolean all_whitespace (const char *text, int text_len) { const char *p; const char *end; p = text; end = text + text_len; while (p != end) { if (!g_ascii_isspace (*p)) return FALSE; p = g_utf8_next_char (p); } return TRUE; } static void text_handler (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error) { ParseInfo *info = user_data; if (info->skip_level > 0) return; if (all_whitespace (text, text_len)) return; /* FIXME http://bugzilla.gnome.org/show_bug.cgi?id=70448 would * allow a nice cleanup here. */ switch (peek_state (info)) { case STATE_START: g_assert_not_reached (); /* gmarkup shouldn't do this */ break; case STATE_THEME: NO_TEXT ("metacity_theme"); break; case STATE_INFO: NO_TEXT ("info"); break; case STATE_NAME: if (info->theme->readable_name != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> specified twice for this theme"), "name"); return; } info->theme->readable_name = g_strndup (text, text_len); break; case STATE_AUTHOR: if (info->theme->author != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> specified twice for this theme"), "author"); return; } info->theme->author = g_strndup (text, text_len); break; case STATE_COPYRIGHT: if (info->theme->copyright != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> specified twice for this theme"), "copyright"); return; } info->theme->copyright = g_strndup (text, text_len); break; case STATE_DATE: if (info->theme->date != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> specified twice for this theme"), "date"); return; } info->theme->date = g_strndup (text, text_len); break; case STATE_DESCRIPTION: if (info->theme->description != NULL) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("<%s> specified twice for this theme"), "description"); return; } info->theme->description = g_strndup (text, text_len); break; case STATE_CONSTANT: NO_TEXT ("constant"); break; case STATE_FRAME_GEOMETRY: NO_TEXT ("frame_geometry"); break; case STATE_DISTANCE: NO_TEXT ("distance"); break; case STATE_BORDER: NO_TEXT ("border"); break; case STATE_ASPECT_RATIO: NO_TEXT ("aspect_ratio"); break; case STATE_DRAW_OPS: NO_TEXT ("draw_ops"); break; case STATE_LINE: NO_TEXT ("line"); break; case STATE_RECTANGLE: NO_TEXT ("rectangle"); break; case STATE_ARC: NO_TEXT ("arc"); break; case STATE_CLIP: NO_TEXT ("clip"); break; case STATE_TINT: NO_TEXT ("tint"); break; case STATE_GRADIENT: NO_TEXT ("gradient"); break; case STATE_IMAGE: NO_TEXT ("image"); break; case STATE_GTK_ARROW: NO_TEXT ("gtk_arrow"); break; case STATE_GTK_BOX: NO_TEXT ("gtk_box"); break; case STATE_GTK_VLINE: NO_TEXT ("gtk_vline"); break; case STATE_ICON: NO_TEXT ("icon"); break; case STATE_TITLE: NO_TEXT ("title"); break; case STATE_INCLUDE: NO_TEXT ("include"); break; case STATE_TILE: NO_TEXT ("tile"); break; case STATE_COLOR: NO_TEXT ("color"); break; case STATE_FRAME_STYLE: NO_TEXT ("frame_style"); break; case STATE_PIECE: NO_TEXT ("piece"); break; case STATE_BUTTON: NO_TEXT ("button"); break; case STATE_MENU_ICON: NO_TEXT ("menu_icon"); break; case STATE_FRAME_STYLE_SET: NO_TEXT ("frame_style_set"); break; case STATE_FRAME: NO_TEXT ("frame"); break; case STATE_WINDOW: NO_TEXT ("window"); break; case STATE_FALLBACK: NO_TEXT ("fallback"); break; case UBUNTU_STATE_IGNORE: NO_TEXT ("ignored_element"); break; } } /* If the theme is not-corrupt, keep looking for alternate versions * in other locations we might be compatible with */ static gboolean theme_error_is_fatal (GError *error) { return !(error->domain == G_FILE_ERROR || (error->domain == THEME_PARSE_ERROR && error->code == THEME_PARSE_ERROR_TOO_OLD)); } static MetaTheme * load_theme (const char *theme_dir, const char *theme_name, guint major_version, GError **error) { GMarkupParseContext *context; ParseInfo info; char *text; gsize length; char *theme_filename; char *theme_file; MetaTheme *retval; g_return_val_if_fail (error && *error == NULL, NULL); text = NULL; retval = NULL; context = NULL; theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT, major_version); theme_file = g_build_filename (theme_dir, theme_filename, NULL); if (!g_file_get_contents (theme_file, &text, &length, error)) goto out; meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file); parse_info_init (&info); info.theme_name = theme_name; info.theme_file = theme_file; info.theme_dir = theme_dir; info.format_version = 1000 * major_version; context = g_markup_parse_context_new (&metacity_theme_parser, 0, &info, NULL); if (!g_markup_parse_context_parse (context, text, length, error)) goto out; if (!g_markup_parse_context_end_parse (context, error)) goto out; retval = info.theme; info.theme = NULL; out: #ifdef WITH_VERBOSE_MODE if (*error && !theme_error_is_fatal (*error)) { meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n", theme_file, (*error)->message); } #endif free (theme_filename); free (theme_file); free (text); if (context) { g_markup_parse_context_free (context); parse_info_free (&info); } return retval; } static gboolean keep_trying (GError **error) { if (*error && !theme_error_is_fatal (*error)) { g_clear_error (error); return TRUE; } return FALSE; } /** * meta_theme_load: (skip) * */ MetaTheme* meta_theme_load (const char *theme_name, GError **err) { GError *error = NULL; char *theme_dir; MetaTheme *retval; const gchar* const* xdg_data_dirs; int major_version; int i; retval = NULL; if (meta_is_debugging ()) { /* Try in themes in our source tree */ /* We try all supported major versions from current to oldest */ for (major_version = THEME_MAJOR_VERSION; (major_version > 0); major_version--) { theme_dir = g_build_filename ("./themes", theme_name, NULL); retval = load_theme (theme_dir, theme_name, major_version, &error); free (theme_dir); if (!keep_trying (&error)) goto out; } } if (strcmp(theme_name, "Default") == 0) { theme_dir = g_build_filename (MUFFIN_DATADIR, "muffin", "theme", NULL); retval = load_theme (theme_dir, "Default", 3, &error); free (theme_dir); if (!keep_trying (&error)) goto out; } /* We try all supported major versions from current to oldest */ for (major_version = THEME_MAJOR_VERSION; (major_version > 0); major_version--) { /* We try first in XDG_DATA_HOME, home dir, XDG_DATA_DIRS, then system dir for themes */ /* user data dir */ theme_dir = g_build_filename (g_get_user_data_dir (), "themes", theme_name, THEME_SUBDIR, NULL); retval = load_theme (theme_dir, theme_name, major_version, &error); free (theme_dir); if (!keep_trying (&error)) goto out; /* Try home dir for themes */ theme_dir = g_build_filename (g_get_home_dir (), ".themes", theme_name, THEME_SUBDIR, NULL); retval = load_theme (theme_dir, theme_name, major_version, &error); free (theme_dir); if (!keep_trying (&error)) goto out; /* Try each XDG_DATA_DIRS for theme */ xdg_data_dirs = g_get_system_data_dirs(); for(i = 0; xdg_data_dirs[i] != NULL; i++) { theme_dir = g_build_filename (xdg_data_dirs[i], "themes", theme_name, THEME_SUBDIR, NULL); retval = load_theme (theme_dir, theme_name, major_version, &error); free (theme_dir); if (!keep_trying (&error)) goto out; } /* Look for themes in MUFFIN_DATADIR */ theme_dir = g_build_filename (MUFFIN_DATADIR, "themes", theme_name, THEME_SUBDIR, NULL); retval = load_theme (theme_dir, theme_name, major_version, &error); free (theme_dir); if (!keep_trying (&error)) goto out; } out: if (!error && !retval) g_set_error (&error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("Failed to find a valid file for theme %s\n"), theme_name); if (error) { g_propagate_error (err, error); } return retval; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/gradient.c����������������������������������������������������������������������0000664�0001750�0001750�00000056635�14211404421�016320� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity gradient rendering */ /* * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <meta/gradient.h> #include <meta/util.h> #include <string.h> /* This is all Alfredo's and Dan's usual very nice WindowMaker code, * slightly GTK-ized */ static GdkPixbuf* meta_gradient_create_horizontal (int width, int height, const GdkRGBA *from, const GdkRGBA *to); static GdkPixbuf* meta_gradient_create_vertical (int width, int height, const GdkRGBA *from, const GdkRGBA *to); static GdkPixbuf* meta_gradient_create_diagonal (int width, int height, const GdkRGBA *from, const GdkRGBA *to); static GdkPixbuf* meta_gradient_create_multi_horizontal (int width, int height, const GdkRGBA *colors, int count); static GdkPixbuf* meta_gradient_create_multi_vertical (int width, int height, const GdkRGBA *colors, int count); static GdkPixbuf* meta_gradient_create_multi_diagonal (int width, int height, const GdkRGBA *colors, int count); /* Used as the destroy notification function for gdk_pixbuf_new() */ static void free_buffer (guchar *pixels, gpointer data) { free (pixels); } static GdkPixbuf* blank_pixbuf (int width, int height, gboolean no_padding) { guchar *buf; int rowstride; g_return_val_if_fail (width > 0, NULL); g_return_val_if_fail (height > 0, NULL); if (no_padding) rowstride = width * 3; else /* Always align rows to 32-bit boundaries */ rowstride = 4 * ((3 * width + 3) / 4); buf = g_try_malloc (height * rowstride); if (!buf) return NULL; return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB, FALSE, 8, width, height, rowstride, free_buffer, NULL); } /** * meta_gradient_create_simple: * @width: Width in pixels * @height: Height in pixels * @from: Starting color * @to: Ending color * @style: Gradient style * * Returns: (transfer full): A new linear gradient */ GdkPixbuf* meta_gradient_create_simple (int width, int height, const GdkRGBA *from, const GdkRGBA *to, MetaGradientType style) { switch (style) { case META_GRADIENT_HORIZONTAL: return meta_gradient_create_horizontal (width, height, from, to); case META_GRADIENT_VERTICAL: return meta_gradient_create_vertical (width, height, from, to); case META_GRADIENT_DIAGONAL: return meta_gradient_create_diagonal (width, height, from, to); case META_GRADIENT_LAST: break; default: break; } g_assert_not_reached (); return NULL; } /** * meta_gradient_create_multi: * @width: Width in pixels * @height: Height in pixels * @colors: (array length=n_colors): Array of colors * @n_colors: Number of colors * @style: Gradient style * * Returns: (transfer full): A new multi-step linear gradient */ GdkPixbuf* meta_gradient_create_multi (int width, int height, const GdkRGBA *colors, int n_colors, MetaGradientType style) { if (n_colors > 2) { switch (style) { case META_GRADIENT_HORIZONTAL: return meta_gradient_create_multi_horizontal (width, height, colors, n_colors); case META_GRADIENT_VERTICAL: return meta_gradient_create_multi_vertical (width, height, colors, n_colors); case META_GRADIENT_DIAGONAL: return meta_gradient_create_multi_diagonal (width, height, colors, n_colors); case META_GRADIENT_LAST: g_assert_not_reached (); break; default: break; } } else if (n_colors > 1) { return meta_gradient_create_simple (width, height, &colors[0], &colors[1], style); } else if (n_colors > 0) { return meta_gradient_create_simple (width, height, &colors[0], &colors[0], style); } g_assert_not_reached (); return NULL; } /** * meta_gradient_create_interwoven: (skip) * * Interwoven essentially means we have two vertical gradients, * cut into horizontal strips of the given thickness, and then the strips * are alternated. I'm not sure what it's good for, just copied since * WindowMaker had it. */ GdkPixbuf* meta_gradient_create_interwoven (int width, int height, const GdkRGBA colors1[2], int thickness1, const GdkRGBA colors2[2], int thickness2) { int i, j, k, l, ll; long r1, g1, b1, dr1, dg1, db1; long r2, g2, b2, dr2, dg2, db2; GdkPixbuf *pixbuf; unsigned char *ptr; unsigned char *pixels; int rowstride; pixbuf = blank_pixbuf (width, height, FALSE); if (pixbuf == NULL) return NULL; pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); r1 = (long)(colors1[0].red*0xffffff); g1 = (long)(colors1[0].green*0xffffff); b1 = (long)(colors1[0].blue*0xffffff); r2 = (long)(colors2[0].red*0xffffff); g2 = (long)(colors2[0].green*0xffffff); b2 = (long)(colors2[0].blue*0xffffff); dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height; dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height; db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height; dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height; dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height; db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height; for (i=0,k=0,l=0,ll=thickness1; i<height; i++) { ptr = pixels + i * rowstride; if (k == 0) { ptr[0] = (unsigned char) (r1>>16); ptr[1] = (unsigned char) (g1>>16); ptr[2] = (unsigned char) (b1>>16); } else { ptr[0] = (unsigned char) (r2>>16); ptr[1] = (unsigned char) (g2>>16); ptr[2] = (unsigned char) (b2>>16); } for (j=1; j <= width/2; j *= 2) memcpy (&(ptr[j*3]), ptr, j*3); memcpy (&(ptr[j*3]), ptr, (width - j)*3); if (++l == ll) { if (k == 0) { k = 1; ll = thickness2; } else { k = 0; ll = thickness1; } l = 0; } r1+=dr1; g1+=dg1; b1+=db1; r2+=dr2; g2+=dg2; b2+=db2; } return pixbuf; } /* *---------------------------------------------------------------------- * meta_gradient_create_horizontal-- * Renders a horizontal linear gradient of the specified size in the * GdkPixbuf format with a border of the specified type. * * Returns: * A 24bit GdkPixbuf with the gradient (no alpha channel). * * Side effects: * None *---------------------------------------------------------------------- */ static GdkPixbuf* meta_gradient_create_horizontal (int width, int height, const GdkRGBA *from, const GdkRGBA *to) { int i; long r, g, b, dr, dg, db; GdkPixbuf *pixbuf; unsigned char *ptr; unsigned char *pixels; int r0, g0, b0; int rf, gf, bf; int rowstride; pixbuf = blank_pixbuf (width, height, FALSE); if (pixbuf == NULL) return NULL; pixels = gdk_pixbuf_get_pixels (pixbuf); ptr = pixels; rowstride = gdk_pixbuf_get_rowstride (pixbuf); r0 = (guchar) (from->red * 0xff); g0 = (guchar) (from->green * 0xff); b0 = (guchar) (from->blue * 0xff); rf = (guchar) (to->red * 0xff); gf = (guchar) (to->green * 0xff); bf = (guchar) (to->blue * 0xff); r = r0 << 16; g = g0 << 16; b = b0 << 16; dr = ((rf-r0)<<16)/(int)width; dg = ((gf-g0)<<16)/(int)width; db = ((bf-b0)<<16)/(int)width; /* render the first line */ for (i=0; i<width; i++) { *(ptr++) = (unsigned char)(r>>16); *(ptr++) = (unsigned char)(g>>16); *(ptr++) = (unsigned char)(b>>16); r += dr; g += dg; b += db; } /* copy the first line to the other lines */ for (i=1; i<height; i++) { memcpy (&(pixels[i*rowstride]), pixels, rowstride); } return pixbuf; } /* *---------------------------------------------------------------------- * meta_gradient_create_vertical-- * Renders a vertical linear gradient of the specified size in the * GdkPixbuf format with a border of the specified type. * * Returns: * A 24bit GdkPixbuf with the gradient (no alpha channel). * * Side effects: * None *---------------------------------------------------------------------- */ static GdkPixbuf* meta_gradient_create_vertical (int width, int height, const GdkRGBA *from, const GdkRGBA *to) { int i, j; long r, g, b, dr, dg, db; GdkPixbuf *pixbuf; unsigned char *ptr; int r0, g0, b0; int rf, gf, bf; int rowstride; unsigned char *pixels; pixbuf = blank_pixbuf (width, height, FALSE); if (pixbuf == NULL) return NULL; pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); r0 = (guchar) (from->red * 0xff); g0 = (guchar) (from->green * 0xff); b0 = (guchar) (from->blue * 0xff); rf = (guchar) (to->red * 0xff); gf = (guchar) (to->green * 0xff); bf = (guchar) (to->blue * 0xff); r = r0<<16; g = g0<<16; b = b0<<16; dr = ((rf-r0)<<16)/(int)height; dg = ((gf-g0)<<16)/(int)height; db = ((bf-b0)<<16)/(int)height; for (i=0; i<height; i++) { ptr = pixels + i * rowstride; ptr[0] = (unsigned char)(r>>16); ptr[1] = (unsigned char)(g>>16); ptr[2] = (unsigned char)(b>>16); for (j=1; j <= width/2; j *= 2) memcpy (&(ptr[j*3]), ptr, j*3); memcpy (&(ptr[j*3]), ptr, (width - j)*3); r+=dr; g+=dg; b+=db; } return pixbuf; } /* *---------------------------------------------------------------------- * meta_gradient_create_diagonal-- * Renders a diagonal linear gradient of the specified size in the * GdkPixbuf format with a border of the specified type. * * Returns: * A 24bit GdkPixbuf with the gradient (no alpha channel). * * Side effects: * None *---------------------------------------------------------------------- */ static GdkPixbuf* meta_gradient_create_diagonal (int width, int height, const GdkRGBA *from, const GdkRGBA *to) { GdkPixbuf *pixbuf, *tmp; int j; float a, offset; unsigned char *ptr; unsigned char *pixels; int rowstride; if (width == 1) return meta_gradient_create_vertical (width, height, from, to); else if (height == 1) return meta_gradient_create_horizontal (width, height, from, to); pixbuf = blank_pixbuf (width, height, FALSE); if (pixbuf == NULL) return NULL; pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to); if (!tmp) { g_object_unref (G_OBJECT (pixbuf)); return NULL; } ptr = gdk_pixbuf_get_pixels (tmp); a = ((float)(width - 1))/((float)(height - 1)); width = width * 3; /* copy the first line to the other lines with corresponding offset */ for (j=0, offset=0.0; j<rowstride*height; j += rowstride) { memcpy (&(pixels[j]), &ptr[3*(int)offset], width); offset += a; } g_object_unref (G_OBJECT (tmp)); return pixbuf; } static GdkPixbuf* meta_gradient_create_multi_horizontal (int width, int height, const GdkRGBA *colors, int count) { int i, j, k; long r, g, b, dr, dg, db; GdkPixbuf *pixbuf; unsigned char *ptr; unsigned char *pixels; int width2; int rowstride; g_return_val_if_fail (count > 2, NULL); pixbuf = blank_pixbuf (width, height, FALSE); if (pixbuf == NULL) return NULL; pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); ptr = pixels; if (count > width) count = width; if (count > 1) width2 = width/(count-1); else width2 = width; k = 0; r = (long)(colors[0].red * 0xffffff); g = (long)(colors[0].green * 0xffffff); b = (long)(colors[0].blue * 0xffffff); /* render the first line */ for (i=1; i<count; i++) { dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)width2; dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)width2; db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)width2; for (j=0; j<width2; j++) { *ptr++ = (unsigned char)(r>>16); *ptr++ = (unsigned char)(g>>16); *ptr++ = (unsigned char)(b>>16); r += dr; g += dg; b += db; k++; } r = (long)(colors[i].red * 0xffffff); g = (long)(colors[i].green * 0xffffff); b = (long)(colors[i].blue * 0xffffff); } for (j=k; j<width; j++) { *ptr++ = (unsigned char)(r>>16); *ptr++ = (unsigned char)(g>>16); *ptr++ = (unsigned char)(b>>16); } /* copy the first line to the other lines */ for (i=1; i<height; i++) { memcpy (&(pixels[i*rowstride]), pixels, rowstride); } return pixbuf; } static GdkPixbuf* meta_gradient_create_multi_vertical (int width, int height, const GdkRGBA *colors, int count) { int i, j, k; long r, g, b, dr, dg, db; GdkPixbuf *pixbuf; unsigned char *ptr, *tmp, *pixels; int height2; int x; int rowstride; g_return_val_if_fail (count > 2, NULL); pixbuf = blank_pixbuf (width, height, FALSE); if (pixbuf == NULL) return NULL; pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); ptr = pixels; if (count > height) count = height; if (count > 1) height2 = height/(count-1); else height2 = height; k = 0; r = (long)(colors[0].red * 0xffffff); g = (long)(colors[0].green * 0xffffff); b = (long)(colors[0].blue * 0xffffff); for (i=1; i<count; i++) { dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)height2; dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)height2; db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)height2; for (j=0; j<height2; j++) { ptr[0] = (unsigned char)(r>>16); ptr[1] = (unsigned char)(g>>16); ptr[2] = (unsigned char)(b>>16); for (x=1; x <= width/2; x *= 2) memcpy (&(ptr[x*3]), ptr, x*3); memcpy (&(ptr[x*3]), ptr, (width - x)*3); ptr += rowstride; r += dr; g += dg; b += db; k++; } r = (long)(colors[i].red * 0xffffff); g = (long)(colors[i].green * 0xffffff); b = (long)(colors[i].blue * 0xffffff); } if (k<height) { tmp = ptr; ptr[0] = (unsigned char) (r>>16); ptr[1] = (unsigned char) (g>>16); ptr[2] = (unsigned char) (b>>16); for (x=1; x <= width/2; x *= 2) memcpy (&(ptr[x*3]), ptr, x*3); memcpy (&(ptr[x*3]), ptr, (width - x)*3); ptr += rowstride; for (j=k+1; j<height; j++) { memcpy (ptr, tmp, rowstride); ptr += rowstride; } } return pixbuf; } static GdkPixbuf* meta_gradient_create_multi_diagonal (int width, int height, const GdkRGBA *colors, int count) { GdkPixbuf *pixbuf, *tmp; float a, offset; int j; unsigned char *ptr; unsigned char *pixels; int rowstride; g_return_val_if_fail (count > 2, NULL); if (width == 1) return meta_gradient_create_multi_vertical (width, height, colors, count); else if (height == 1) return meta_gradient_create_multi_horizontal (width, height, colors, count); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); if (pixbuf == NULL) return NULL; pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); if (count > width) count = width; if (count > height) count = height; if (count > 2) tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count); else /* wrlib multiplies these colors by 256 before passing them in, but * I think it's a bug in wrlib, so changed here. I could be wrong * though, if we notice two-color multi diagonals not working. */ tmp = meta_gradient_create_horizontal (2*width-1, 1, &colors[0], &colors[1]); if (!tmp) { g_object_unref (G_OBJECT (pixbuf)); return NULL; } ptr = gdk_pixbuf_get_pixels (tmp); a = ((float)(width - 1))/((float)(height - 1)); width = width * 3; /* copy the first line to the other lines with corresponding offset */ for (j=0, offset=0; j<rowstride*height; j += rowstride) { memcpy (&(pixels[j]), &ptr[3*(int)offset], width); offset += a; } g_object_unref (G_OBJECT (tmp)); return pixbuf; } static void simple_multiply_alpha (GdkPixbuf *pixbuf, guchar alpha) { guchar *pixels; int rowstride; int height; int row; g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); if (alpha == 255) return; g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); height = gdk_pixbuf_get_height (pixbuf); row = 0; while (row < height) { guchar *p; guchar *end; p = pixels + row * rowstride; end = p + rowstride; while (p != end) { p += 3; /* skip RGB */ /* multiply the two alpha channels. not sure this is right. * but some end cases are that if the pixbuf contains 255, * then it should be modified to contain "alpha"; if the * pixbuf contains 0, it should remain 0. */ /* ((*p / 255.0) * (alpha / 255.0)) * 255; */ *p = (guchar) (((int) *p * (int) alpha) / (int) 255); ++p; /* skip A */ } ++row; } } static void meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf, const unsigned char *alphas, int n_alphas) { int i, j; long a, da; unsigned char *p; unsigned char *pixels; int width2; int rowstride; int width, height; unsigned char *gradient; unsigned char *gradient_p; unsigned char *gradient_end; g_return_if_fail (n_alphas > 0); if (n_alphas == 1) { /* Optimize this */ simple_multiply_alpha (pixbuf, alphas[0]); return; } width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); gradient = g_new (unsigned char, width); gradient_end = gradient + width; if (n_alphas > width) n_alphas = width; if (n_alphas > 1) width2 = width / (n_alphas - 1); else width2 = width; a = alphas[0] << 8; gradient_p = gradient; /* render the gradient into an array */ for (i = 1; i < n_alphas; i++) { da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2; for (j = 0; j < width2; j++) { *gradient_p++ = (a >> 8); a += da; } a = alphas[i] << 8; } /* get leftover pixels */ while (gradient_p != gradient_end) { *gradient_p++ = a >> 8; } /* Now for each line of the pixbuf, fill in with the gradient */ pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); p = pixels; i = 0; while (i < height) { unsigned char *row_end = p + rowstride; gradient_p = gradient; p += 3; while (gradient_p != gradient_end) { /* multiply the two alpha channels. not sure this is right. * but some end cases are that if the pixbuf contains 255, * then it should be modified to contain "alpha"; if the * pixbuf contains 0, it should remain 0. */ /* ((*p / 255.0) * (alpha / 255.0)) * 255; */ *p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255); p += 4; ++gradient_p; } p = row_end; ++i; } free (gradient); } void meta_gradient_add_alpha (GdkPixbuf *pixbuf, const guchar *alphas, int n_alphas, MetaGradientType type) { g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf)); g_return_if_fail (n_alphas > 0); switch (type) { case META_GRADIENT_HORIZONTAL: meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas); break; case META_GRADIENT_VERTICAL: g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n"); break; case META_GRADIENT_DIAGONAL: g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n"); break; case META_GRADIENT_LAST: g_assert_not_reached (); break; default: break; } } ���������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/menu.h��������������������������������������������������������������������������0000664�0001750�0001750�00000004435�14211404421�015463� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window menu */ /* * Copyright (C) 2001 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef META_MENU_H #define META_MENU_H #include <gtk/gtk.h> #include "frames.h" /* Stock icons */ #define METACITY_STOCK_DELETE "metacity-delete" #define METACITY_STOCK_MINIMIZE "metacity-minimize" #define METACITY_STOCK_MAXIMIZE "metacity-maximize" struct _MetaWindowMenu { MetaFrames *frames; Window client_xwindow; GtkWidget *menu; MetaWindowMenuFunc func; gpointer data; MetaMenuOp ops; MetaMenuOp insensitive; }; MetaWindowMenu* meta_window_menu_new (MetaFrames *frames, MetaMenuOp ops, MetaMenuOp insensitive, Window client_xwindow, unsigned long active_workspace, int n_workspaces, MetaWindowMenuFunc func, gpointer data); void meta_window_menu_popup (MetaWindowMenu *menu, int root_x, int root_y, int button, guint32 timestamp); void meta_window_menu_free (MetaWindowMenu *menu); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/draw-workspace.h����������������������������������������������������������������0000664�0001750�0001750�00000003750�14211404421�017447� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Draw a workspace */ /* This file should not be modified to depend on other files in * libwnck or metacity, since it's used in both of them */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef WNCK_DRAW_WORKSPACE_H #define WNCK_DRAW_WORKSPACE_H #include <gdk/gdk.h> #include <gdk-pixbuf/gdk-pixbuf.h> #include <gtk/gtk.h> typedef struct { int x; int y; int width; int height; guint is_active : 1; } WnckWindowDisplayInfo; void wnck_draw_workspace (GtkWidget *widget, cairo_t *cr, int x, int y, int width, int height, int screen_width, int screen_height, GdkPixbuf *workspace_background, gboolean is_active, const WnckWindowDisplayInfo *windows, int n_windows); #endif ������������������������muffin-5.2.1/src/ui/draw-workspace.c����������������������������������������������������������������0000664�0001750�0001750�00000012020�14211404421�017430� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Draw a workspace */ /* This file should not be modified to depend on other files in * libwnck or muffin, since it's used in both of them */ /* * Copyright (C) 2002 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #if HAVE_CONFIG_H #include <config.h> #endif #include "draw-workspace.h" #include "theme-private.h" static void get_window_rect (const WnckWindowDisplayInfo *win, int screen_width, int screen_height, const GdkRectangle *workspace_rect, GdkRectangle *rect) { double width_ratio, height_ratio; int x, y, width, height; width_ratio = (double) workspace_rect->width / (double) screen_width; height_ratio = (double) workspace_rect->height / (double) screen_height; x = win->x; y = win->y; width = win->width; height = win->height; x *= width_ratio; y *= height_ratio; width *= width_ratio; height *= height_ratio; x += workspace_rect->x; y += workspace_rect->y; if (width < 3) width = 3; if (height < 3) height = 3; rect->x = x; rect->y = y; rect->width = width; rect->height = height; } static void draw_window (GtkWidget *widget, cairo_t *cr, const WnckWindowDisplayInfo *win, const GdkRectangle *winrect, GtkStateFlags state) { gboolean is_active; GdkRGBA color; GtkStyleContext *style; is_active = win->is_active; cairo_save (cr); cairo_rectangle (cr, winrect->x, winrect->y, winrect->width, winrect->height); cairo_clip (cr); style = gtk_widget_get_style_context (widget); if (is_active) meta_gtk_style_get_light_color (style, state, &color); else gtk_style_context_get_background_color (style, state, &color); gdk_cairo_set_source_rgba (cr, &color); cairo_rectangle (cr, winrect->x + 1, winrect->y + 1, MAX (0, winrect->width - 2), MAX (0, winrect->height - 2)); cairo_fill (cr); gtk_style_context_get_color (style, state, &color); gdk_cairo_set_source_rgba (cr, &color); cairo_set_line_width (cr, 1.0); cairo_rectangle (cr, winrect->x + 0.5, winrect->y + 0.5, MAX (0, winrect->width - 1), MAX (0, winrect->height - 1)); cairo_stroke (cr); cairo_restore (cr); } LOCAL_SYMBOL void wnck_draw_workspace (GtkWidget *widget, cairo_t *cr, int x, int y, int width, int height, int screen_width, int screen_height, GdkPixbuf *workspace_background, gboolean is_active, const WnckWindowDisplayInfo *windows, int n_windows) { int i; GdkRectangle workspace_rect; GtkStateFlags state; GtkStyleContext *style; workspace_rect.x = x; workspace_rect.y = y; workspace_rect.width = width; workspace_rect.height = height; if (is_active) state = GTK_STATE_FLAG_SELECTED; else if (workspace_background) state = GTK_STATE_FLAG_PRELIGHT; else state = GTK_STATE_FLAG_NORMAL; style = gtk_widget_get_style_context (widget); cairo_save (cr); if (workspace_background) { gdk_cairo_set_source_pixbuf (cr, workspace_background, x, y); cairo_paint (cr); } else { GdkRGBA color; meta_gtk_style_get_dark_color (style,state, &color); gdk_cairo_set_source_rgba (cr, &color); cairo_rectangle (cr, x, y, width, height); cairo_fill (cr); } i = 0; while (i < n_windows) { const WnckWindowDisplayInfo *win = &windows[i]; GdkRectangle winrect; get_window_rect (win, screen_width, screen_height, &workspace_rect, &winrect); draw_window (widget, cr, win, &winrect, state); ++i; } cairo_restore (cr); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/src/ui/menu.c��������������������������������������������������������������������������0000664�0001750�0001750�00000043733�14211404421�015462� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Muffin window menu */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2004 Rob Adams * Copyright (C) 2005 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <stdio.h> #include <string.h> #include "menu.h" #include <meta/main.h> #include "util-private.h" #include "core.h" #include "metaaccellabel.h" #include "ui.h" typedef struct _MenuItem MenuItem; typedef struct _MenuData MenuData; typedef enum { MENU_ITEM_SEPARATOR = 0, MENU_ITEM_NORMAL, MENU_ITEM_IMAGE, MENU_ITEM_CHECKBOX, MENU_ITEM_RADIOBUTTON, MENU_ITEM_WORKSPACE_LIST, } MetaMenuItemType; struct _MenuItem { MetaMenuOp op; MetaMenuItemType type; const char *stock_id; const gboolean checked; const char *label; }; struct _MenuData { MetaWindowMenu *menu; MetaMenuOp op; }; static void activate_cb (GtkWidget *menuitem, gpointer data); static MenuItem menuitems[] = { /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_MINIMIZE, MENU_ITEM_IMAGE, METACITY_STOCK_MINIMIZE, FALSE, N_("Mi_nimize") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_MAXIMIZE, MENU_ITEM_IMAGE, METACITY_STOCK_MAXIMIZE, FALSE, N_("Ma_ximize") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_UNMAXIMIZE, MENU_ITEM_NORMAL, NULL, FALSE, N_("Unma_ximize") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_SHADE, MENU_ITEM_NORMAL, NULL, FALSE, N_("Roll _Up") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_UNSHADE, MENU_ITEM_NORMAL, NULL, FALSE, N_("_Unroll") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_MOVE, MENU_ITEM_NORMAL, NULL, FALSE, N_("_Move") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_RESIZE, MENU_ITEM_NORMAL, NULL, FALSE, N_("_Resize") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_RECOVER, MENU_ITEM_NORMAL, NULL, FALSE, N_("Move Titlebar On_screen") }, { META_MENU_OP_WORKSPACES, MENU_ITEM_SEPARATOR, NULL, FALSE, NULL }, /* separator */ /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_ABOVE, MENU_ITEM_CHECKBOX, NULL, FALSE, N_("Always on _Top") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_UNABOVE, MENU_ITEM_CHECKBOX, NULL, TRUE, N_("Always on _Top") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_STICK, MENU_ITEM_RADIOBUTTON, NULL, FALSE, N_("_Always on Visible Workspace") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_UNSTICK, MENU_ITEM_RADIOBUTTON, NULL, FALSE, N_("_Only on This Workspace") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_MOVE_LEFT, MENU_ITEM_NORMAL, NULL, FALSE, N_("Move to Workspace _Left") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_MOVE_RIGHT, MENU_ITEM_NORMAL, NULL, FALSE, N_("Move to Workspace R_ight") }, /* Translators: This will create a new workspace, and move this window to that new workspace */ { META_MENU_OP_MOVE_NEW, MENU_ITEM_NORMAL, NULL, FALSE, N_("Move to a New W_orkspace") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_MOVE_UP, MENU_ITEM_NORMAL, NULL, FALSE, N_("Move to Workspace _Up") }, /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_MOVE_DOWN, MENU_ITEM_NORMAL, NULL, FALSE, N_("Move to Workspace _Down") }, { 0, MENU_ITEM_WORKSPACE_LIST, NULL, FALSE, NULL }, { 0, MENU_ITEM_SEPARATOR, NULL, FALSE, NULL }, /* separator */ /* Translators: Translate this string the same way as you do in libwnck! */ { META_MENU_OP_DELETE, MENU_ITEM_IMAGE, METACITY_STOCK_DELETE, FALSE, N_("_Close") } }; static void popup_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data) { GtkRequisition req; GdkPoint *pos; pos = user_data; gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL); *x = pos->x; *y = pos->y; if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) *x = MAX (0, *x - req.width); /* Ensure onscreen */ *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width)); *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height)); } static void menu_closed (GtkMenu *widget, gpointer data) { MetaWindowMenu *menu; menu = data; meta_frames_notify_menu_hide (menu->frames); (* menu->func) (menu, GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), menu->client_xwindow, gtk_get_current_event_time (), 0, 0, menu->data); /* menu may now be freed */ } static void activate_cb (GtkWidget *menuitem, gpointer data) { MenuData *md; g_return_if_fail (GTK_IS_WIDGET (menuitem)); md = data; meta_frames_notify_menu_hide (md->menu->frames); (* md->menu->func) (md->menu, GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), md->menu->client_xwindow, gtk_get_current_event_time (), md->op, GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), "workspace")), md->menu->data); /* menu may now be freed */ } /* * Given a Display and an index, get the workspace name and add any * accelerators. At the moment this means adding a _ if the name is of * the form "Workspace n" where n is less than 10, and escaping any * other '_'s so they do not create inadvertant accelerators. * * The calling code owns the string, and is reponsible to free the * memory after use. * * See also http://mail.gnome.org/archives/gnome-i18n/2008-March/msg00380.html * which discusses possible i18n concerns. */ static char* get_workspace_name_with_accel (Display *display, Window xroot, int index) { const char *name; int number; int charcount=0; name = meta_core_get_workspace_name_with_index (display, xroot, index); g_assert (name != NULL); /* * If the name is of the form "Workspace x" where x is an unsigned * integer, insert a '_' before the number if it is less than 10 and * return it */ number = 0; if (sscanf (name, _("Workspace %d%n"), &number, &charcount) != 0 && *(name + charcount)=='\0') { char *new_name; /* * Above name is a pointer into the Workspace struct. Here we make * a copy copy so we can have our wicked way with it. */ if (number == 10) new_name = g_strdup_printf (_("Workspace 1_0")); else new_name = g_strdup_printf (_("Workspace %s%d"), number < 10 ? "_" : "", number); return new_name; } else { /* * Otherwise this is just a normal name. Escape any _ characters so that * the user's workspace names do not get mangled. If the number is less * than 10 we provide an accelerator. */ char *new_name; const char *source; char *dest; /* * Assume the worst case, that every character is a _. We also * provide memory for " (_#)" */ new_name = calloc (1, strlen (name) * 2 + 6 + 1); /* * Now iterate down the strings, adding '_' to escape as we go */ dest = new_name; source = name; while (*source != '\0') { if (*source == '_') *dest++ = '_'; *dest++ = *source++; } /* People don't start at workspace 0, but workspace 1 */ if (index < 9) { g_snprintf (dest, 6, " (_%d)", index + 1); } else if (index == 9) { g_snprintf (dest, 6, " (_0)"); } return new_name; } } static GtkWidget * menu_item_new (MenuItem *menuitem, int workspace_id) { unsigned int key; MetaVirtualModifier mods; const char *i18n_label; GtkWidget *mi; GtkWidget *accel_label; if (menuitem->type == MENU_ITEM_NORMAL) { mi = gtk_menu_item_new (); } else if (menuitem->type == MENU_ITEM_IMAGE) { GtkWidget *image; image = gtk_image_new_from_stock (menuitem->stock_id, GTK_ICON_SIZE_MENU); mi = gtk_image_menu_item_new (); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image); gtk_widget_show (image); } else if (menuitem->type == MENU_ITEM_CHECKBOX) { mi = gtk_check_menu_item_new (); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), menuitem->checked); } else if (menuitem->type == MENU_ITEM_RADIOBUTTON) { mi = gtk_check_menu_item_new (); gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (mi), TRUE); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), menuitem->checked); } else if (menuitem->type == MENU_ITEM_WORKSPACE_LIST) return NULL; else return gtk_separator_menu_item_new (); i18n_label = _(menuitem->label); meta_core_get_menu_accelerator (menuitem->op, workspace_id, &key, &mods); accel_label = meta_accel_label_new_with_mnemonic (i18n_label); gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (mi), accel_label); gtk_widget_show (accel_label); meta_accel_label_set_accelerator (META_ACCEL_LABEL (accel_label), key, mods); return mi; } LOCAL_SYMBOL MetaWindowMenu* meta_window_menu_new (MetaFrames *frames, MetaMenuOp ops, MetaMenuOp insensitive, Window client_xwindow, unsigned long active_workspace, int n_workspaces, MetaWindowMenuFunc func, gpointer data) { int i; MetaWindowMenu *menu; /* FIXME: Modifications to 'ops' should happen in meta_window_show_menu */ if (n_workspaces < 2) ops &= ~(META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES); menu = g_new (MetaWindowMenu, 1); menu->frames = frames; menu->client_xwindow = client_xwindow; menu->func = func; menu->data = data; menu->ops = ops; menu->insensitive = insensitive; menu->menu = gtk_menu_new (); gtk_menu_set_screen (GTK_MENU (menu->menu), gtk_widget_get_screen (GTK_WIDGET (frames))); for (i = 0; i < (int) G_N_ELEMENTS (menuitems); i++) { MenuItem menuitem = menuitems[i]; if (ops & menuitem.op || menuitem.op == 0) { GtkWidget *mi; MenuData *md; unsigned int key; MetaVirtualModifier mods; mi = menu_item_new (&menuitem, -1); /* Set the activeness of radiobuttons. */ switch (menuitem.op) { case META_MENU_OP_STICK: gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), active_workspace == 0xFFFFFFFF); break; case META_MENU_OP_UNSTICK: gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), active_workspace != 0xFFFFFFFF); break; case META_MENU_OP_NONE: case META_MENU_OP_DELETE: case META_MENU_OP_MINIMIZE: case META_MENU_OP_UNMAXIMIZE: case META_MENU_OP_MAXIMIZE: case META_MENU_OP_UNSHADE: case META_MENU_OP_SHADE: case META_MENU_OP_WORKSPACES: case META_MENU_OP_MOVE: case META_MENU_OP_RESIZE: case META_MENU_OP_ABOVE: case META_MENU_OP_UNABOVE: case META_MENU_OP_MOVE_LEFT: case META_MENU_OP_MOVE_RIGHT: case META_MENU_OP_MOVE_UP: case META_MENU_OP_MOVE_DOWN: case META_MENU_OP_RECOVER: case META_MENU_OP_MOVE_NEW: break; default: break; } if (menuitem.type == MENU_ITEM_WORKSPACE_LIST) { if (ops & META_MENU_OP_WORKSPACES) { Display *display; Window xroot; GdkScreen *screen; GdkWindow *window; GtkWidget *submenu; int j; MenuItem to_another_workspace = { 0, MENU_ITEM_NORMAL, NULL, FALSE, N_("Move to Another _Workspace") }; meta_verbose ("Creating %d-workspace menu current space %lu\n", n_workspaces, active_workspace); window = gtk_widget_get_window (GTK_WIDGET (frames)); display = GDK_WINDOW_XDISPLAY (window); screen = gdk_window_get_screen (window); xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); submenu = gtk_menu_new (); g_assert (mi==NULL); mi = menu_item_new (&to_another_workspace, -1); gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu); for (j = 0; j < n_workspaces; j++) { char *label; MenuData *md1; unsigned int key1; MetaVirtualModifier mods1; MenuItem moveitem; GtkWidget *submi; meta_core_get_menu_accelerator (META_MENU_OP_WORKSPACES, j + 1, &key1, &mods1); label = get_workspace_name_with_accel (display, xroot, j); moveitem.type = MENU_ITEM_NORMAL; moveitem.op = META_MENU_OP_WORKSPACES; moveitem.label = label; submi = menu_item_new (&moveitem, j + 1); free (label); if ((active_workspace == (unsigned)j) && (ops & META_MENU_OP_UNSTICK)) gtk_widget_set_sensitive (submi, FALSE); md1 = g_new (MenuData, 1); md1->menu = menu; md1->op = META_MENU_OP_WORKSPACES; g_object_set_data (G_OBJECT (submi), "workspace", GINT_TO_POINTER (j)); g_signal_connect_data (G_OBJECT (submi), "activate", G_CALLBACK (activate_cb), md1, (GClosureNotify) free, 0); gtk_menu_shell_append (GTK_MENU_SHELL (submenu), submi); gtk_widget_show (submi); } } else meta_verbose ("not creating workspace menu\n"); } else if (menuitem.type != MENU_ITEM_SEPARATOR) { meta_core_get_menu_accelerator (menuitems[i].op, -1, &key, &mods); if (insensitive & menuitem.op) gtk_widget_set_sensitive (mi, FALSE); md = g_new (MenuData, 1); md->menu = menu; md->op = menuitem.op; g_signal_connect_data (G_OBJECT (mi), "activate", G_CALLBACK (activate_cb), md, (GClosureNotify) free, 0); } if (mi) { gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), mi); gtk_widget_show (mi); } } } g_signal_connect (menu->menu, "selection_done", G_CALLBACK (menu_closed), menu); return menu; } LOCAL_SYMBOL void meta_window_menu_popup (MetaWindowMenu *menu, int root_x, int root_y, int button, guint32 timestamp) { GdkPoint *pt; pt = g_new (GdkPoint, 1); g_object_set_data_full (G_OBJECT (menu->menu), "destroy-point", pt, free); pt->x = root_x; pt->y = root_y; gtk_menu_popup (GTK_MENU (menu->menu), NULL, NULL, popup_position_func, pt, button, timestamp); if (!gtk_widget_get_visible (menu->menu)) meta_warning ("GtkMenu failed to grab the pointer\n"); } LOCAL_SYMBOL void meta_window_menu_free (MetaWindowMenu *menu) { gtk_widget_destroy (menu->menu); free (menu); } �������������������������������������muffin-5.2.1/src/ui/theme-viewer.c������������������������������������������������������������������0000664�0001750�0001750�00000110255�14211404421�017111� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* Metacity theme viewer and test app main() */ /* * Copyright (C) 2002 Havoc Pennington * * 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., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include <config.h> #include <meta/util.h> #include <meta/theme.h> #include "theme-private.h" #include <meta/preview-widget.h> #include <gtk/gtk.h> #include <time.h> #include <stdlib.h> #include <string.h> #include <glib/gi18n.h> /* We need to compute all different button arrangements * in terms of button location. We don't care about * different arrangements in terms of button function. * * So if dups are allowed, from 0-4 buttons on the left, from 0-4 on * the right, 5x5=25 combinations. * * If no dups, 0-4 on left determines the number on the right plus * we have a special case for the "no buttons on either side" case. */ #ifndef ALLOW_DUPLICATE_BUTTONS #define BUTTON_LAYOUT_COMBINATIONS (MAX_BUTTONS_PER_CORNER + 1 + 1) #else #define BUTTON_LAYOUT_COMBINATIONS ((MAX_BUTTONS_PER_CORNER+1)*(MAX_BUTTONS_PER_CORNER+1)) #endif enum { FONT_SIZE_SMALL, FONT_SIZE_NORMAL, FONT_SIZE_LARGE, FONT_SIZE_LAST }; static MetaTheme *global_theme = NULL; static GtkWidget *previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + BUTTON_LAYOUT_COMBINATIONS] = { NULL, }; static double milliseconds_to_draw_frame = 0.0; static void run_position_expression_tests (void); #if 0 static void run_position_expression_timings (void); #endif static void run_theme_benchmark (void); static const gchar *menu_item_string = "<ui>\n" "<menubar>\n" "<menu name='Windows' action='Windows'>\n" "<menuitem name='Dialog' action='Dialog'/>\n" "<menuitem name='Modal dialog' action='Modal dialog'/>\n" "<menuitem name='Utility' action='Utility'/>\n" "<menuitem name='Splashscreen' action='Splashscreen'/>\n" "<menuitem name='Top dock' action='Top dock'/>\n" "<menuitem name='Bottom dock' action='Bottom dock'/>\n" "<menuitem name='Left dock' action='Left dock'/>\n" "<menuitem name='Right dock' action='Right dock'/>\n" "<menuitem name='Desktop' action='Desktop'/>\n" "</menu>\n" "</menubar>\n" "<toolbar>\n" "<separator/>\n" "<toolitem name='New' action='New'/>\n" "<toolitem name='Open' action='Open'/>\n" "<toolitem name='Quit' action='Quit'/>\n" "<separator/>\n" "</toolbar>\n" "</ui>\n"; static GtkActionEntry menu_items[] = { { "Windows", NULL, N_("_Windows"), NULL, NULL, NULL }, { "Dialog", NULL, N_("_Dialog"), "<control>d", NULL, NULL }, { "Modal dialog", NULL, N_("_Modal dialog"), NULL, NULL, NULL }, { "Utility", NULL, N_("_Utility"), "<control>u", NULL, NULL }, { "Splashscreen", NULL, N_("_Splashscreen"), "<control>s", NULL, NULL }, { "Top dock", NULL, N_("_Top dock"), NULL, NULL, NULL }, { "Bottom dock", NULL, N_("_Bottom dock"), NULL, NULL, NULL }, { "Left dock", NULL, N_("_Left dock"), NULL, NULL, NULL }, { "Right dock", NULL, N_("_Right dock"), NULL, NULL, NULL }, { "All docks", NULL, N_("_All docks"), NULL, NULL, NULL }, { "Desktop", NULL, N_("Des_ktop"), NULL, NULL, NULL } }; static GtkActionEntry tool_items[] = { { "New", GTK_STOCK_NEW, NULL, NULL, N_("Open another one of these windows"), NULL }, { "Open", GTK_STOCK_OPEN, NULL, NULL, N_("This is a demo button with an 'open' icon"), NULL }, { "Quit", GTK_STOCK_QUIT, NULL, NULL, N_("This is a demo button with a 'quit' icon"), NULL } }; static GtkWidget * normal_contents (void) { GtkWidget *grid; GtkWidget *statusbar; GtkWidget *contents; GtkWidget *sw; GtkActionGroup *action_group; GtkUIManager *ui_manager; grid = gtk_grid_new (); /* Create the menubar */ action_group = gtk_action_group_new ("mainmenu"); gtk_action_group_add_actions (action_group, menu_items, G_N_ELEMENTS (menu_items), NULL); gtk_action_group_add_actions (action_group, tool_items, G_N_ELEMENTS (tool_items), NULL); ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); /* create menu items */ gtk_ui_manager_add_ui_from_string (ui_manager, menu_item_string, -1, NULL); gtk_grid_attach (GTK_GRID (grid), gtk_ui_manager_get_widget (ui_manager, "/ui/menubar"), 0, 0, 1, 1); gtk_widget_set_hexpand (gtk_ui_manager_get_widget (ui_manager, "/ui/menubar"), TRUE); /* Create the toolbar */ gtk_grid_attach (GTK_GRID (grid), gtk_ui_manager_get_widget (ui_manager, "/ui/toolbar"), 0, 1, 1, 1); gtk_widget_set_hexpand (gtk_ui_manager_get_widget (ui_manager, "/ui/toolbar"), TRUE); /* Create document */ sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); gtk_grid_attach (GTK_GRID (grid), sw, 0, 2, 1, 1); gtk_widget_set_hexpand (sw, TRUE); gtk_widget_set_vexpand (sw, TRUE); contents = gtk_text_view_new (); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (contents), PANGO_WRAP_WORD); gtk_container_add (GTK_CONTAINER (sw), contents); /* Create statusbar */ statusbar = gtk_statusbar_new (); gtk_grid_attach (GTK_GRID (grid), statusbar, 0, 3, 1, 1); gtk_widget_set_hexpand (statusbar, TRUE); gtk_widget_show_all (grid); g_object_unref (ui_manager); return grid; } static void update_spacings (GtkWidget *vbox, GtkWidget *action_area) { gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); gtk_box_set_spacing (GTK_BOX (action_area), 10); gtk_container_set_border_width (GTK_CONTAINER (action_area), 5); } static GtkWidget* dialog_contents (void) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *action_area; GtkWidget *label; GtkWidget *image; GtkWidget *button; vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), GTK_BUTTONBOX_END); button = gtk_button_new_from_stock (GTK_STOCK_OK); gtk_box_pack_end (GTK_BOX (action_area), button, FALSE, TRUE, 0); gtk_box_pack_end (GTK_BOX (vbox), action_area, FALSE, TRUE, 0); update_spacings (vbox, action_area); label = gtk_label_new (_("This is a sample message in a sample dialog")); image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_selectable (GTK_LABEL (label), TRUE); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show_all (vbox); return vbox; } static GtkWidget* utility_contents (void) { GtkWidget *grid; GtkWidget *button; int i, j; grid = gtk_grid_new (); i = 0; while (i < 3) { j = 0; while (j < 4) { char *str; str = g_strdup_printf ("_%c", (char) ('A' + 4*i + j)); button = gtk_button_new_with_mnemonic (str); free (str); gtk_grid_attach (GTK_GRID (grid), button, i, j, 1, 1); ++j; } ++i; } gtk_widget_show_all (grid); return grid; } static GtkWidget* menu_contents (void) { GtkWidget *vbox; GtkWidget *mi; int i; GtkWidget *frame; frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); i = 0; while (i < 10) { char *str = g_strdup_printf (_("Fake menu item %d\n"), i + 1); mi = gtk_label_new (str); gtk_misc_set_alignment (GTK_MISC (mi), 0.0, 0.5); free (str); gtk_box_pack_start (GTK_BOX (vbox), mi, FALSE, FALSE, 0); ++i; } gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_widget_show_all (frame); return frame; } static GtkWidget* border_only_contents (void) { GtkWidget *event_box; GtkWidget *vbox; GtkWidget *w; GdkRGBA color; event_box = gtk_event_box_new (); color.red = 0.6; color.green = 0; color.blue = 0.6; color.alpha = 1.0; gtk_widget_override_background_color (event_box, 0, &color); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); w = gtk_label_new (_("Border-only window")); gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); w = gtk_button_new_with_label (_("Bar")); gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (event_box), vbox); gtk_widget_show_all (event_box); return event_box; } static GtkWidget* get_window_contents (MetaFrameType type, const char **title) { switch (type) { case META_FRAME_TYPE_NORMAL: *title = _("Normal Application Window"); return normal_contents (); case META_FRAME_TYPE_DIALOG: *title = _("Dialog Box"); return dialog_contents (); case META_FRAME_TYPE_MODAL_DIALOG: *title = _("Modal Dialog Box"); return dialog_contents (); case META_FRAME_TYPE_UTILITY: *title = _("Utility Palette"); return utility_contents (); case META_FRAME_TYPE_MENU: *title = _("Torn-off Menu"); return menu_contents (); case META_FRAME_TYPE_BORDER: *title = _("Border"); return border_only_contents (); case META_FRAME_TYPE_ATTACHED: *title = _("Attached Modal Dialog"); return dialog_contents (); case META_FRAME_TYPE_LAST: g_assert_not_reached (); break; } return NULL; } static MetaFrameFlags get_window_flags (MetaFrameType type) { MetaFrameFlags flags; flags = META_FRAME_ALLOWS_DELETE | META_FRAME_ALLOWS_MENU | META_FRAME_ALLOWS_MINIMIZE | META_FRAME_ALLOWS_MAXIMIZE | META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE | META_FRAME_HAS_FOCUS | META_FRAME_ALLOWS_SHADE | META_FRAME_ALLOWS_MOVE; switch (type) { case META_FRAME_TYPE_NORMAL: break; case META_FRAME_TYPE_DIALOG: case META_FRAME_TYPE_MODAL_DIALOG: flags &= ~(META_FRAME_ALLOWS_MINIMIZE | META_FRAME_ALLOWS_MAXIMIZE); break; case META_FRAME_TYPE_UTILITY: flags &= ~(META_FRAME_ALLOWS_MINIMIZE | META_FRAME_ALLOWS_MAXIMIZE); break; case META_FRAME_TYPE_MENU: flags &= ~(META_FRAME_ALLOWS_MINIMIZE | META_FRAME_ALLOWS_MAXIMIZE); break; case META_FRAME_TYPE_BORDER: break; case META_FRAME_TYPE_ATTACHED: break; case META_FRAME_TYPE_LAST: g_assert_not_reached (); break; } return flags; } static GtkWidget* preview_collection (int font_size, const PangoFontDescription *base_desc) { GtkWidget *box; GtkWidget *sw; GdkRGBA desktop_color; int i; GtkWidget *eventbox; sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_set_spacing (GTK_BOX (box), 20); gtk_container_set_border_width (GTK_CONTAINER (box), 20); eventbox = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (eventbox), box); gtk_container_add (GTK_CONTAINER (sw), eventbox); desktop_color.red = 0.32; desktop_color.green = 0.46; desktop_color.blue = 0.65; desktop_color.alpha = 1.0; gtk_widget_override_background_color (eventbox, 0, &desktop_color); i = 0; while (i < META_FRAME_TYPE_LAST) { const char *title = NULL; GtkWidget *contents; GtkWidget *align; double xalign, yalign; GtkWidget *eventbox2; GtkWidget *preview; PangoFontDescription *font_desc; double scale; eventbox2 = gtk_event_box_new (); preview = meta_preview_new (); gtk_container_add (GTK_CONTAINER (eventbox2), preview); meta_preview_set_frame_type (META_PREVIEW (preview), i); meta_preview_set_frame_flags (META_PREVIEW (preview), get_window_flags (i)); meta_preview_set_theme (META_PREVIEW (preview), global_theme); contents = get_window_contents (i, &title); meta_preview_set_title (META_PREVIEW (preview), title); gtk_container_add (GTK_CONTAINER (preview), contents); if (i == META_FRAME_TYPE_MENU) { xalign = 0.0; yalign = 0.0; } else { xalign = 0.5; yalign = 0.5; } align = gtk_alignment_new (0.0, 0.0, xalign, yalign); gtk_container_add (GTK_CONTAINER (align), eventbox2); gtk_box_pack_start (GTK_BOX (box), align, TRUE, TRUE, 0); switch (font_size) { case FONT_SIZE_SMALL: scale = PANGO_SCALE_XX_SMALL; break; case FONT_SIZE_LARGE: scale = PANGO_SCALE_XX_LARGE; break; default: scale = 1.0; break; } if (scale != 1.0) { font_desc = pango_font_description_new (); pango_font_description_set_size (font_desc, MAX (pango_font_description_get_size (base_desc) * scale, 1)); gtk_widget_override_font (preview, font_desc); pango_font_description_free (font_desc); } previews[font_size*META_FRAME_TYPE_LAST + i] = preview; ++i; } return sw; } static MetaButtonLayout different_layouts[BUTTON_LAYOUT_COMBINATIONS]; static void init_layouts (void) { int i; /* Blank out all the layouts */ i = 0; while (i < (int) G_N_ELEMENTS (different_layouts)) { int j; j = 0; while (j < MAX_BUTTONS_PER_CORNER) { different_layouts[i].left_buttons[j] = META_BUTTON_FUNCTION_LAST; different_layouts[i].right_buttons[j] = META_BUTTON_FUNCTION_LAST; ++j; } ++i; } #ifndef ALLOW_DUPLICATE_BUTTONS i = 0; while (i <= MAX_BUTTONS_PER_CORNER) { int j; j = 0; while (j < i) { different_layouts[i].right_buttons[j] = (MetaButtonFunction) j; ++j; } while (j < MAX_BUTTONS_PER_CORNER) { different_layouts[i].left_buttons[j-i] = (MetaButtonFunction) j; ++j; } ++i; } /* Special extra case for no buttons on either side */ different_layouts[i].left_buttons[0] = META_BUTTON_FUNCTION_LAST; different_layouts[i].right_buttons[0] = META_BUTTON_FUNCTION_LAST; #else /* FIXME this code is if we allow duplicate buttons, * which we currently do not */ int left; int i; left = 0; i = 0; while (left < MAX_BUTTONS_PER_CORNER) { int right; right = 0; while (right < MAX_BUTTONS_PER_CORNER) { int j; static MetaButtonFunction left_functions[MAX_BUTTONS_PER_CORNER] = { META_BUTTON_FUNCTION_MENU, META_BUTTON_FUNCTION_MINIMIZE, META_BUTTON_FUNCTION_MAXIMIZE, META_BUTTON_FUNCTION_CLOSE }; static MetaButtonFunction right_functions[MAX_BUTTONS_PER_CORNER] = { META_BUTTON_FUNCTION_MINIMIZE, META_BUTTON_FUNCTION_MAXIMIZE, META_BUTTON_FUNCTION_CLOSE, META_BUTTON_FUNCTION_MENU }; g_assert (i < BUTTON_LAYOUT_COMBINATIONS); j = 0; while (j <= left) { different_layouts[i].left_buttons[j] = left_functions[j]; ++j; } j = 0; while (j <= right) { different_layouts[i].right_buttons[j] = right_functions[j]; ++j; } ++i; ++right; } ++left; } #endif } static GtkWidget* previews_of_button_layouts (void) { static gboolean initted = FALSE; GtkWidget *box; GtkWidget *sw; GdkRGBA desktop_color; int i; GtkWidget *eventbox; if (!initted) { init_layouts (); initted = TRUE; } sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_set_spacing (GTK_BOX (box), 20); gtk_container_set_border_width (GTK_CONTAINER (box), 20); eventbox = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (eventbox), box); gtk_container_add (GTK_CONTAINER (sw), eventbox); desktop_color.red = 0.32; desktop_color.green = 0.46; desktop_color.blue = 0.65; desktop_color.alpha = 1.0; gtk_widget_override_background_color (eventbox, 0, &desktop_color); i = 0; while (i < BUTTON_LAYOUT_COMBINATIONS) { GtkWidget *align; double xalign, yalign; GtkWidget *eventbox2; GtkWidget *preview; char *title; eventbox2 = gtk_event_box_new (); preview = meta_preview_new (); gtk_container_add (GTK_CONTAINER (eventbox2), preview); meta_preview_set_theme (META_PREVIEW (preview), global_theme); title = g_strdup_printf (_("Button layout test %d"), i+1); meta_preview_set_title (META_PREVIEW (preview), title); free (title); meta_preview_set_button_layout (META_PREVIEW (preview), &different_layouts[i]); xalign = 0.5; yalign = 0.5; align = gtk_alignment_new (0.0, 0.0, xalign, yalign); gtk_container_add (GTK_CONTAINER (align), eventbox2); gtk_box_pack_start (GTK_BOX (box), align, TRUE, TRUE, 0); previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + i] = preview; ++i; } return sw; } static GtkWidget* benchmark_summary (void) { char *msg; GtkWidget *label; msg = g_strdup_printf (_("%g milliseconds to draw one window frame"), milliseconds_to_draw_frame); label = gtk_label_new (msg); free (msg); return label; } int main (int argc, char **argv) { GtkStyleContext *style; PangoFontDescription *font_desc; GtkWidget *window; GtkWidget *collection; GError *err; clock_t start, end; GtkWidget *notebook; int i; bindtextdomain (GETTEXT_PACKAGE, MUFFIN_LOCALEDIR); textdomain(GETTEXT_PACKAGE); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); run_position_expression_tests (); #if 0 run_position_expression_timings (); #endif gtk_init (&argc, &argv); if (g_getenv ("MUFFIN_DEBUG") != NULL) { meta_set_debugging (TRUE); meta_set_verbose (TRUE); } start = clock (); err = NULL; if (argc == 1) global_theme = meta_theme_load ("Atlanta", &err); else if (argc == 2) global_theme = meta_theme_load (argv[1], &err); else { g_printerr (_("Usage: metacity-theme-viewer [THEMENAME]\n")); exit (1); } end = clock (); if (global_theme == NULL) { g_printerr (_("Error loading theme: %s\n"), err->message); g_error_free (err); exit (1); } g_print (_("Loaded theme \"%s\" in %g seconds\n"), global_theme->name, (end - start) / (double) CLOCKS_PER_SEC); run_theme_benchmark (); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (window), 350, 350); if (strcmp (global_theme->name, global_theme->readable_name)==0) gtk_window_set_title (GTK_WINDOW (window), global_theme->readable_name); else { /* The theme directory name is different from the name the theme * gives itself within its file. Display both, directory name first. */ gchar *title = g_strconcat (global_theme->name, " - ", global_theme->readable_name, NULL); gtk_window_set_title (GTK_WINDOW (window), title); free (title); } g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_widget_realize (window); style = gtk_widget_get_style_context (window); gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL); g_assert (style); g_assert (font_desc); notebook = gtk_notebook_new (); gtk_container_add (GTK_CONTAINER (window), notebook); collection = preview_collection (FONT_SIZE_NORMAL, font_desc); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), collection, gtk_label_new (_("Normal Title Font"))); collection = preview_collection (FONT_SIZE_SMALL, font_desc); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), collection, gtk_label_new (_("Small Title Font"))); collection = preview_collection (FONT_SIZE_LARGE, font_desc); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), collection, gtk_label_new (_("Large Title Font"))); collection = previews_of_button_layouts (); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), collection, gtk_label_new (_("Button Layouts"))); collection = benchmark_summary (); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), collection, gtk_label_new (_("Benchmark"))); pango_font_description_free (font_desc); i = 0; while (i < (int) G_N_ELEMENTS (previews)) { /* preview widget likes to be realized before its size request. * it's lame that way. */ gtk_widget_realize (previews[i]); ++i; } gtk_widget_show_all (window); gtk_main (); return 0; } static MetaFrameFlags get_flags (GtkWidget *widget) { return META_FRAME_ALLOWS_DELETE | META_FRAME_ALLOWS_MENU | META_FRAME_ALLOWS_MINIMIZE | META_FRAME_ALLOWS_MAXIMIZE | META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE | META_FRAME_HAS_FOCUS | META_FRAME_ALLOWS_SHADE | META_FRAME_ALLOWS_MOVE; } static int get_text_height (GtkWidget *widget) { GtkStyleContext *style; PangoFontDescription *font_desc; int text_height; style = gtk_widget_get_style_context (widget); gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL); text_height = meta_pango_font_desc_get_text_height (font_desc, gtk_widget_get_pango_context (widget)); pango_font_description_free (font_desc); return text_height; } static PangoLayout* create_title_layout (GtkWidget *widget) { PangoLayout *layout; layout = gtk_widget_create_pango_layout (widget, _("Window Title Goes Here")); return layout; } static void run_theme_benchmark (void) { GtkWidget* widget; cairo_surface_t *pixmap; MetaFrameBorders borders; MetaButtonState button_states[META_BUTTON_TYPE_LAST] = { META_BUTTON_STATE_NORMAL, META_BUTTON_STATE_NORMAL, META_BUTTON_STATE_NORMAL, META_BUTTON_STATE_NORMAL }; PangoLayout *layout; clock_t start; clock_t end; GTimer *timer; int i; MetaButtonLayout button_layout; #define ITERATIONS 100 int client_width; int client_height; cairo_t *cr; int inc; widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_realize (widget); meta_theme_get_frame_borders (global_theme, META_FRAME_TYPE_NORMAL, get_text_height (widget), get_flags (widget), &borders); layout = create_title_layout (widget); i = 0; while (i < MAX_BUTTONS_PER_CORNER) { button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST; button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST; ++i; } button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU; button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE; button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE; button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE; timer = g_timer_new (); start = clock (); client_width = 50; client_height = 50; inc = 1000 / ITERATIONS; /* Increment to grow width/height, * eliminates caching effects. */ i = 0; while (i < ITERATIONS) { /* Creating the pixmap in the loop is right, since * GDK does the same with its double buffering. */ pixmap = gdk_window_create_similar_surface (gtk_widget_get_window (widget), CAIRO_CONTENT_COLOR, client_width + borders.total.left + borders.total.right, client_height + borders.total.top + borders.total.bottom); cr = cairo_create (pixmap); meta_theme_draw_frame (global_theme, widget, cr, META_FRAME_TYPE_NORMAL, get_flags (widget), client_width, client_height, layout, get_text_height (widget), &button_layout, button_states); cairo_destroy (cr); cairo_surface_destroy (pixmap); ++i; client_width += inc; client_height += inc; } end = clock (); g_timer_stop (timer); milliseconds_to_draw_frame = (g_timer_elapsed (timer, NULL) / (double) ITERATIONS) * 1000; g_print (_("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n"), ITERATIONS, ((double)end - (double)start) / CLOCKS_PER_SEC, (((double)end - (double)start) / CLOCKS_PER_SEC / (double) ITERATIONS) * 1000, g_timer_elapsed (timer, NULL), milliseconds_to_draw_frame); g_timer_destroy (timer); g_object_unref (G_OBJECT (layout)); gtk_widget_destroy (widget); #undef ITERATIONS } typedef struct { GdkRectangle rect; const char *expr; int expected_x; int expected_y; MetaThemeError expected_error; } PositionExpressionTest; #define NO_ERROR -1 static const PositionExpressionTest position_expression_tests[] = { /* Just numbers */ { { 10, 20, 40, 50 }, "10", 20, 30, NO_ERROR }, { { 10, 20, 40, 50 }, "14.37", 24, 34, NO_ERROR }, /* Binary expressions with 2 ints */ { { 10, 20, 40, 50 }, "14 * 10", 150, 160, NO_ERROR }, { { 10, 20, 40, 50 }, "14 + 10", 34, 44, NO_ERROR }, { { 10, 20, 40, 50 }, "14 - 10", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "8 / 2", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "8 % 3", 12, 22, NO_ERROR }, /* Binary expressions with floats and mixed float/ints */ { { 10, 20, 40, 50 }, "7.0 / 3.5", 12, 22, NO_ERROR }, { { 10, 20, 40, 50 }, "12.1 / 3", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "12 / 2.95", 14, 24, NO_ERROR }, /* Binary expressions without whitespace after first number */ { { 10, 20, 40, 50 }, "14* 10", 150, 160, NO_ERROR }, { { 10, 20, 40, 50 }, "14+ 10", 34, 44, NO_ERROR }, { { 10, 20, 40, 50 }, "14- 10", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "8/ 2", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "7.0/ 3.5", 12, 22, NO_ERROR }, { { 10, 20, 40, 50 }, "12.1/ 3", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "12/ 2.95", 14, 24, NO_ERROR }, /* Binary expressions without whitespace before second number */ { { 10, 20, 40, 50 }, "14 *10", 150, 160, NO_ERROR }, { { 10, 20, 40, 50 }, "14 +10", 34, 44, NO_ERROR }, { { 10, 20, 40, 50 }, "14 -10", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "8 /2", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "7.0 /3.5", 12, 22, NO_ERROR }, { { 10, 20, 40, 50 }, "12.1 /3", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "12 /2.95", 14, 24, NO_ERROR }, /* Binary expressions without any whitespace */ { { 10, 20, 40, 50 }, "14*10", 150, 160, NO_ERROR }, { { 10, 20, 40, 50 }, "14+10", 34, 44, NO_ERROR }, { { 10, 20, 40, 50 }, "14-10", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "8/2", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "7.0/3.5", 12, 22, NO_ERROR }, { { 10, 20, 40, 50 }, "12.1/3", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "12/2.95", 14, 24, NO_ERROR }, /* Binary expressions with parentheses */ { { 10, 20, 40, 50 }, "(14) * (10)", 150, 160, NO_ERROR }, { { 10, 20, 40, 50 }, "(14) + (10)", 34, 44, NO_ERROR }, { { 10, 20, 40, 50 }, "(14) - (10)", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "(8) / (2)", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "(7.0) / (3.5)", 12, 22, NO_ERROR }, { { 10, 20, 40, 50 }, "(12.1) / (3)", 14, 24, NO_ERROR }, { { 10, 20, 40, 50 }, "(12) / (2.95)", 14, 24, NO_ERROR }, /* Lots of extra parentheses */ { { 10, 20, 40, 50 }, "(((14)) * ((10)))", 150, 160, NO_ERROR }, { { 10, 20, 40, 50 }, "((((14)))) + ((((((((10))))))))", 34, 44, NO_ERROR }, { { 10, 20, 40, 50 }, "((((((((((14 - 10))))))))))", 14, 24, NO_ERROR }, /* Binary expressions with variables */ { { 10, 20, 40, 50 }, "2 * width", 90, 100, NO_ERROR }, { { 10, 20, 40, 50 }, "2 * height", 110, 120, NO_ERROR }, { { 10, 20, 40, 50 }, "width - 10", 40, 50, NO_ERROR }, { { 10, 20, 40, 50 }, "height / 2", 35, 45, NO_ERROR }, /* More than two operands */ { { 10, 20, 40, 50 }, "8 / 2 + 5", 19, 29, NO_ERROR }, { { 10, 20, 40, 50 }, "8 * 2 + 5", 31, 41, NO_ERROR }, { { 10, 20, 40, 50 }, "8 + 2 * 5", 28, 38, NO_ERROR }, { { 10, 20, 40, 50 }, "8 + 8 / 2", 22, 32, NO_ERROR }, { { 10, 20, 40, 50 }, "14 / (2 + 5)", 12, 22, NO_ERROR }, { { 10, 20, 40, 50 }, "8 * (2 + 5)", 66, 76, NO_ERROR }, { { 10, 20, 40, 50 }, "(8 + 2) * 5", 60, 70, NO_ERROR }, { { 10, 20, 40, 50 }, "(8 + 8) / 2", 18, 28, NO_ERROR }, /* Errors */ { { 10, 20, 40, 50 }, "2 * foo", 0, 0, META_THEME_ERROR_UNKNOWN_VARIABLE }, { { 10, 20, 40, 50 }, "2 *", 0, 0, META_THEME_ERROR_FAILED }, { { 10, 20, 40, 50 }, "- width", 0, 0, META_THEME_ERROR_FAILED }, { { 10, 20, 40, 50 }, "5 % 1.0", 0, 0, META_THEME_ERROR_MOD_ON_FLOAT }, { { 10, 20, 40, 50 }, "1.0 % 5", 0, 0, META_THEME_ERROR_MOD_ON_FLOAT }, { { 10, 20, 40, 50 }, "! * 2", 0, 0, META_THEME_ERROR_BAD_CHARACTER }, { { 10, 20, 40, 50 }, " ", 0, 0, META_THEME_ERROR_FAILED }, { { 10, 20, 40, 50 }, "() () (( ) ()) ((()))", 0, 0, META_THEME_ERROR_FAILED }, { { 10, 20, 40, 50 }, "(*) () ((/) ()) ((()))", 0, 0, META_THEME_ERROR_FAILED }, { { 10, 20, 40, 50 }, "2 * 5 /", 0, 0, META_THEME_ERROR_FAILED }, { { 10, 20, 40, 50 }, "+ 2 * 5", 0, 0, META_THEME_ERROR_FAILED }, { { 10, 20, 40, 50 }, "+ 2 * 5", 0, 0, META_THEME_ERROR_FAILED } }; static void run_position_expression_tests (void) { #if 0 int i; MetaPositionExprEnv env; i = 0; while (i < (int) G_N_ELEMENTS (position_expression_tests)) { GError *err; gboolean retval; const PositionExpressionTest *test; PosToken *tokens; int n_tokens; int x, y; test = &position_expression_tests[i]; if (g_getenv ("META_PRINT_TESTS") != NULL) g_print ("Test expression: \"%s\" expecting x = %d y = %d", test->expr, test->expected_x, test->expected_y); err = NULL; env.rect = meta_rect (test->rect.x, test->rect.y, test->rect.width, test->rect.height); env.object_width = -1; env.object_height = -1; env.left_width = 0; env.right_width = 0; env.top_height = 0; env.bottom_height = 0; env.title_width = 5; env.title_height = 5; env.icon_width = 32; env.icon_height = 32; env.mini_icon_width = 16; env.mini_icon_height = 16; env.theme = NULL; if (err == NULL) { retval = meta_parse_position_expression (tokens, n_tokens, &env, &x, &y, &err); } if (retval && err) g_error (_("position expression test returned TRUE but set error")); if (!retval && err == NULL) g_error (_("position expression test returned FALSE but didn't set error")); if (((int) test->expected_error) != NO_ERROR) { if (err == NULL) g_error (_("Error was expected but none given")); if (err->code != (int) test->expected_error) g_error (_("Error %d was expected but %d given"), test->expected_error, err->code); } else { if (err) g_error (_("Error not expected but one was returned: %s"), err->message); if (x != test->expected_x) g_error (_("x value was %d, %d was expected"), x, test->expected_x); if (y != test->expected_y) g_error (_("y value was %d, %d was expected"), y, test->expected_y); } if (err) g_error_free (err); meta_pos_tokens_free (tokens, n_tokens); ++i; } #endif } #if 0 static void run_position_expression_timings (void) { int i; int iters; clock_t start; clock_t end; MetaPositionExprEnv env; #define ITERATIONS 100000 start = clock (); iters = 0; i = 0; while (iters < ITERATIONS) { const PositionExpressionTest *test; int x, y; test = &position_expression_tests[i]; env.x = test->rect.x; env.y = test->rect.y; env.width = test->rect.width; env.height = test->rect.height; env.object_width = -1; env.object_height = -1; env.left_width = 0; env.right_width = 0; env.top_height = 0; env.bottom_height = 0; env.title_width = 5; env.title_height = 5; env.icon_width = 32; env.icon_height = 32; env.mini_icon_width = 16; env.mini_icon_height = 16; env.theme = NULL; meta_parse_position_expression (test->expr, &env, &x, &y, NULL); ++iters; ++i; if (i == G_N_ELEMENTS (position_expression_tests)) i = 0; } end = clock (); g_print (_("%d coordinate expressions parsed in %g seconds (%g seconds average)\n"), ITERATIONS, ((double)end - (double)start) / CLOCKS_PER_SEC, ((double)end - (double)start) / CLOCKS_PER_SEC / (double) ITERATIONS); } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/HACKING��������������������������������������������������������������������������������0000664�0001750�0001750�00000033325�14211404421�014131� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Intro... Window managers have a few ways in which they are significantly different from other applications. This file, combined with the code overview in doc/code-overview.txt, should hopefully provide a series of relatively quick pointers (hopefully only a few minutes each) to some of the places one can look to orient themselves and get started. Some of this will be general to window managers on X, much will be specific to Metacity, and there's probably some information that's common to programs in general but is nonetheless useful. Overview Administrative issues Minimal Building/Testing Environment Relevant standards and X properties Debugging and testing Debugging logs Adding information to the log Valgrind Testing Utilities Technical gotchas to keep in mind Other important reading Extra reading Ideas for tasks to work on Administrative issues Don't commit substantive code in here without asking hp@redhat.com. Adding translations, no-brainer typo fixes, etc. is fine. The code could use cleanup in a lot of places, feel free to do so. See http://developer.gnome.org/dotplan/for_maintainers.html for information on how to make a release. The only difference from those instructions is that the minor version number of a Metacity release should always be a number from the Fibonacci sequence. Minimal Building/Testing Environment You do not need to _install_ a development version of Metacity to build, run and test it; you can run it from some temporary directory. Also, you do not need to build all of Gnome in order to build a development version of Metacity -- odds are, you may be able to build metacity from CVS without building any other modules. As long as you have gtk+ >= 3.0 and GIO >= 2.25.10 with your distro (gtk+ >= 2.6 if you manually revert the change from bug 348633), you should be able to install your distro's development packagesh (e.g. gtk2-devel, glib-devel, startup-notification-devel on Fedora; also, remember to install the gnome-common package which is needed for building cvs versions of Gnome modules like Metacity) as well as the standard development tools (gcc, autoconf, automake, pkg-config, intltool, and libtool) and be ready to build and test Metacity. Steps to do so: $ svn checkout http://svn.gnome.org/svn/metacity/trunk metacity $ cd metacity $ ./autogen.sh --prefix /usr $ make $ ./src/metacity --replace Again, note that you do not need to run 'make install'. Relevant standards and X properties There are two documents that describe some basics about how window managers should behave: the ICCCM (Inter-Client Communication Conventions Manual) and EWMH (Extended Window Manager Hints). You can find these at the following locations: ICCCM - http://tronche.com/gui/x/icccm/ EWMH - :pserver:anoncvs@pdx.freedesktop.org:/cvs The ICCCM is usually available in RPM or DEB format as well. There is actually an online version of the EWMH, but it is almost always woefully out of date. Just get it from cvs with these commands (the backslash means include the stuff from the next line): cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions login cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions \ checkout wm-spec DO NOT GO AND READ THOSE THINGS. THEY ARE REALLY, REALLY BORING. If you do, you'll probably end up catching up on your sleep instead of hacking on Metacity. ;-) Instead, just look at the table of contents and glance at a page or two to get an idea of what's in there. Then only refer to it if you see something weird in the code and you don't know what it is but has some funny looking name like you see in one of those two documents. You can refer to the COMPLIANCE file for additional information on these specifications and Metacity's compliance therewith. One of the major things those documents cover that are useful to learn about immediately are X properties. The right way to learn about those, though, is through hand on experimentation with the xprop command (and then look up things you find from xprop in those two manuals if you're curious enough). First, try running xprop in a terminal and click on one of the windows on your screen. That gives you the x properties for that window. Look through them and get a basic idea of what's there for kicks. Note that you can get rid of some of the verboseness by grepping out the _NET_WM_ICON stuff, i.e. xprop | grep -v _NET_WM_ICON Next, try running xprop -root in a terminal. There's all the properties of the root window (which you can think of as the "main" Xserver window). You can also manually specify individual windows that you want the properties of with xprop -id <id> if you know the id of the window in question. You can get the id of a given window by either running xwininfo, e.g. xwininfo | grep "Window id" | cut -f 4 -d ' ' or by looking at the _NET_CLIENT_STACKING property of the root window. Finally, it can also be useful to add "-spy" (without the quotes) to the xprop command to get it to continually monitor that window and report any changes to you. Debugging information Trying to run a window manager under a typical debugger, such as gdb, unfortunately just doesn't work very well. So, we have to resort to other methods. Debugging logs First, note that you can start a new version of metacity to replace the existing one by running metacity --replace (which also comes in handy in the form "./src/metacity --replace" when trying to quickly test a small change while hacking on metacity without doing a full "make install", though I'm going off topic...) This will allow you to see any warnings printed at the terminal. Sometimes it's useful to have these directed to a logfile instead, which you can do by running METACITY_USE_LOGFILE=1 metacity --replace The logfile it uses will be printed in the terminal. Sometimes, it's useful to get more information than just warnings. You can set METACITY_VERBOSE to do that, like so: METACITY_VERBOSE=1 METACITY_USE_LOGFILE=1 metacity --replace (note that METACITY_VERBOSE=1 can be problematic without METACITY_USE_LOGFILE=1; avoid it unless running in from something that won't be managed by the new Metacity--see bug 305091 for more details). There are also other flags, such as METACITY_DEBUG, most of which I haven't tried and don't know what they do. Go to the source code directory and run grep "METACITY_" * | grep getenv to find out what the other ones are. Adding information to the log Since we can't single step with a debugger, we often have to fall back to the primitive method of getting information we want to know: adding "print" statements. Metacity has a fairly structured way to do this, using the functions meta_warning, meta_topic, and meta_verbose. All three have the same basic format as printf, except that meta_topic also takes a leading enumeration parameter to specify the type of message being shown (makes it easier for grepping in a verbose log). You'll find tons of examples in the source code if you need them; just do a quick grep or look in most any file. Note that meta_topic and meta_verbose messages only appear if verbosity is turned on. I tend to frequently add temporary meta_warning statements (or switch meta_topic or meta_verbose ones to meta_warning ones) and then undo the changes once I've learned the info that I needed. There is also a meta_print_backtrace (which again is only active if verbosity is turned on) that can also be useful if you want to learn how a particular line of code gets called. And, of course, there's always g_assert if you want to make sure some section isn't executed (or isn't executed under certain conditions). Valgrind Valgrind is awesome for finding memory leaks or corruption and uninitialized variables. But I also tend to use it in a non-traditional way as a partial substitute for a normal debugger: it can provide me with a stack trace of where metacity is crashing if I made a change that caused it to do so, which is one of the major uses of debuggers. (And, what makes it cooler than a debugger is that there will also often be warnings pinpointing the cause of the crash from either some kind of simple memory corruption or an uninitialized variable). Sometimes, when I merely want to know what is calling a particular function I'll just throw in an "int i; printf("%d\n", i);" just because valgrind will give me a full stacktrace whenever it sees that uninitialized variable being used (yes, I could use meta_print_backtrace, but that means I have to turn verbosity on). To run metacity under valgrind, use options typical for any Gnome program, such as valgrind --log-file=metacity.log --tool=memcheck --num-callers=48 \ --leak-check=yes --leak-resolution=high --show-reachable=yes \ ./src/metacity --replace where, again, the backslashes mean to join all the stuff on the following line with the previous one. However, there is a downside. Things run a little bit slowly, and it appears that you'll need about 1.5GB of ram, which unfortunately prevents most people from trying this. Testing Utilities src/run-metacity.sh The script src/run-metacity.sh is useful to hack on the window manager. It runs metacity in an Xnest. e.g.: CLIENTS=3 ./run-metacity.sh or DEBUG=memprof ./run-metacity.sh or DEBUG_TEST=1 ./run-metacity-sh or whatever. metacity-message The tool metacity-message can be used as follows: metacity-message reload-theme metacity-message restart metacity-message enable-keybindings metacity-message disable-keybindings The first of these is useful for testing themes, the second is just another way (besides the --restart flag to metacity itself) of restarting metacity, and the third is useful for testing Metacity when running it under an Xnest (typically, the Metacity under the Xnest wouldn't get keybinding notifications--making keyboard navigation not work--but if you disable the keybindings for the global Metacity then the Metacity under the Xnest can then get those keybinding notifications). metacity-window-demo metacity-window-demo is good for trying behavior of various kinds of window without launching a full desktop. Technical gotchas to keep in mind Files that include gdk.h or gtk.h are not supposed to include display.h or window.h or other core files. Files in the core (display.[hc], window.[hc]) are not supposed to include gdk.h or gtk.h. Reasons: "Basically you don't want GDK most of the time. It adds abstractions that cause problems, because they aren't designed to be used in a WM where we do weird stuff (display grabs, and just being the WM). At best GDK adds inefficiency, at worst it breaks things in weird ways where you have to be a GDK guru to figure them out. Owen also told me that they didn't want to start adding a lot of hacks to GDK to let a WM use it; we both agreed back in the mists of time that metacity would only use it for the "UI" bits as it does. Having the split in the source code contains and makes very clear the interface between the WM and GDK/GTK. This keeps people from introducing extra GDK/GTK usage when it isn't needed or appropriate. Also, it speeds up the compilation a bit, though this was perhaps more relevant 5 years ago than it is now. There was also a very old worry that the GDK stuff might have to be in a separate process to work right; that turned out to be untrue. Though who knows what issues the CM will introduce." Remember that strings stored in X properties are not in UTF-8, and they have to end up in UTF-8 before we try putting them through Pango. If you make any X request involving a client window, you have to meta_error_trap_push() around the call; this is not necessary for X requests on the frame windows. Remember that not all windows have frames, and window->frame can be NULL. Other important reading & where to get started Extra reading There are some other important things to read to get oriented as well. These are: http://pobox.com/~hp/features.html rationales.txt doc/code-overview.txt It pays to read http://pobox.com/~hp/features.html in order to understand the philosophy of Metacity. The rationales.txt file has two things: (1) a list of design choices with links in the form of bugzilla bugs that discuss the issue, and (2) a list outstanding bug categories, each of which is tracked by a particular tracker bug in bugzilla from which you can find several closely related bug reports. doc/code-overview.txt provides a fairly good overview of the code, including coverage of the function of the various files, the main structures and their relationships, and places to start looking in the code tailored to general categories of tasks. Ideas for tasks to work on There are a variety of things you could work on in the code. You may have ideas of your own, but in case you don't, let me provide a list of ideas you could choose from: If you're ambitious, there's a list of things Havoc made that he'd really like to see tackled, which you can find at http://log.ometer.com/2004-05.html. Be sure to double check with someone to make sure the item is still relevant if you're interested in one of these. Another place to look for ideas, of course, is bugzilla. One can just do queries and look for things that look fixable. However, perhaps the best way of getting ideas of related tasks to work on, is to look at the second half of the rationales.txt file, which tries to group bugs by type. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/COPYING��������������������������������������������������������������������������������0000664�0001750�0001750�00000043113�14211404421�014171� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/.gitignore�����������������������������������������������������������������������������0000664�0001750�0001750�00000013525�14211404421�015132� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������INSTALL Makefile Makefile.in aclocal.m4 autom4te.cache/ compile config.guess config.h config.h.in config.log config.status config.sub configure data/Makefile data/Makefile.in depcomp doc/Makefile doc/Makefile.in doc/man/Makefile doc/man/Makefile.in doc/reference/*.txt doc/reference/*.stamp doc/reference/.libs/ doc/reference/Makefile doc/reference/Makefile.in doc/reference/muffin/Makefile doc/reference/muffin/Makefile.in doc/reference/muffin/html/ doc/reference/muffin/muffin-docs.sgml doc/reference/muffin/muffin.args doc/reference/muffin/muffin.hierarchy doc/reference/muffin/muffin.interfaces doc/reference/muffin/muffin.prerequisites doc/reference/muffin/muffin.signals doc/reference/muffin/muffin.types doc/reference/muffin/xml/ doc/reference/clutter/clutter-*.txt !/doc/reference/clutter/clutter-sections.txt doc/reference/clutter/html doc/reference/clutter/tmpl doc/reference/clutter/xml doc/reference/clutter/clutter.args doc/reference/clutter/clutter.hierarchy doc/reference/clutter/clutter.interfaces doc/reference/clutter/clutter.prerequisites doc/reference/clutter/clutter.signals doc/reference/clutter/clutter-docs.xml doc/reference/clutter/*.stamp doc/reference/clutter/*.bak doc/reference/clutter/*.log doc/reference/clutter/gtkdoc-check.* /doc/reference/cogl/cogl-*.txt !/doc/reference/cogl/cogl-sections.txt /doc/reference/cogl/html /doc/reference/cogl/tmpl /doc/reference/cogl/xml /doc/reference/cogl/cogl.args /doc/reference/cogl/cogl.hierarchy /doc/reference/cogl/cogl.interfaces /doc/reference/cogl/cogl.prerequisites /doc/reference/cogl/cogl.signals /doc/reference/cogl/cogl-docs.xml /doc/reference/cogl/*.stamp /doc/reference/cogl/*.bak gnome-doc-utils.make gtk-doc.make install-sh intltool-extract.in intltool-merge.in libtool ltmain.sh m4/ missing omf.make po/.intltool-merge-cache po/Makefile po/Makefile.in po/POTFILES po/stamp-it po/*.gmo src/.deps/ src/.libs/ src/Makefile src/Makefile.in src/Meta-Muffin.0.gir src/Meta-Muffin.0.typelib src/*/*.lo src/*/*.o src/compositor/.deps/ src/compositor/.dirstamp src/compositor/.libs/ src/compositor/plugins/.deps/ src/compositor/plugins/.libs/ src/compositor/plugins/Makefile src/compositor/plugins/Makefile.in src/compositor/plugins/default.la src/compositor/plugins/default_la-default.lo src/compositor/plugins/default_la-default.o src/core/.deps/ src/core/.dirstamp src/core/.libs/ src/inlinepixbufs.h src/libmuffin.la src/libmuffin.pc src/muffin src/muffin-enum-types.c src/muffin-enum-types.h src/muffin-enum-types.lo src/muffin-enum-types.o src/muffin-plugins.pc src/muffin-restart-helper src/muffin-theme-viewer src/muffin.desktop src/org.cinnamon.muffin.gschema.valid src/org.cinnamon.muffin.gschema.xml src/stamp-muffin-enum-types.h src/testasyncgetprop src/testboxes src/testgradient src/tools/.deps/ src/tools/Makefile src/tools/Makefile.in src/tools/muffin-grayscale src/tools/muffin-mag src/tools/muffin-message src/tools/muffin-window-demo src/ui/.deps/ src/ui/.dirstamp src/ui/.libs/ src/wm-tester/.deps/ src/wm-tester/Makefile src/wm-tester/Makefile.in src/wm-tester/focus-window src/wm-tester/test-attached src/wm-tester/test-gravity src/wm-tester/test-resizing src/wm-tester/test-size-hints src/wm-tester/wm-tester stamp-h1 xmldocs.make /.vscode/ /clutter/tests/interactive/stamp* /clutter/tests/interactive/test-actors /clutter/tests/interactive/test-animation /clutter/tests/interactive/test-animator /clutter/tests/interactive/test-bind-constraint /clutter/tests/interactive/test-binding-pool /clutter/tests/interactive/test-cairo-clock /clutter/tests/interactive/test-cairo-flowers /clutter/tests/interactive/test-cogl-multitexture /clutter/tests/interactive/test-cogl-offscreen /clutter/tests/interactive/test-cogl-point-sprites /clutter/tests/interactive/test-cogl-shader-arbfp /clutter/tests/interactive/test-cogl-shader-glsl /clutter/tests/interactive/test-cogl-tex-convert /clutter/tests/interactive/test-cogl-tex-foreign /clutter/tests/interactive/test-cogl-tex-polygon /clutter/tests/interactive/test-cogl-tex-tile /clutter/tests/interactive/test-cogl-vertex-buffer /clutter/tests/interactive/test-content /clutter/tests/interactive/test-devices /clutter/tests/interactive/test-easing /clutter/tests/interactive/test-events /clutter/tests/interactive/test-fbo /clutter/tests/interactive/test-grab /clutter/tests/interactive/test-image /clutter/tests/interactive/test-interactive /clutter/tests/interactive/test-keyframe-transition /clutter/tests/interactive/test-layout /clutter/tests/interactive/test-multistage /clutter/tests/interactive/test-paint-wrapper /clutter/tests/interactive/test-path-constraint /clutter/tests/interactive/test-pixmap /clutter/tests/interactive/test-rotate-zoom /clutter/tests/interactive/test-scale /clutter/tests/interactive/test-script /clutter/tests/interactive/test-scrolling /clutter/tests/interactive/test-shader-effects /clutter/tests/interactive/test-stage-read-pixels /clutter/tests/interactive/test-stage-sizing /clutter/tests/interactive/test-state /clutter/tests/interactive/test-state-animator /clutter/tests/interactive/test-state-script /clutter/tests/interactive/test-swipe-action /clutter/tests/interactive/test-table-layout /clutter/tests/interactive/test-text /clutter/tests/interactive/test-text-field /clutter/tests/interactive/test-texture-async /clutter/tests/interactive/test-texture-material /clutter/tests/interactive/test-texture-quality /clutter/tests/interactive/test-texture-slicing /clutter/tests/interactive/test-touch-events /clutter/tests/interactive/test-unit-names.h /cogl/stamp-h2 /debian/*.log /debian/*.debhelper /debian/*.substvars /debian/.debhelper/ /debian/libmuffin0/ /debian/muffin-common/ /debian/muffin-dbg/ /debian/muffin-doc/ /debian/muffin/ /debian/tmp/ /debian/autoreconf.after /debian/autoreconf.before /debian/debhelper-build-stamp /debian/files /debian/gir1.2-meta-muffin-0.0/ /doc/reference/muffin/.libs/ /doc/reference/muffin/*.stamp /doc/reference/muffin/muffin-*.txt /po/muffin.pot ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/debian/��������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�014356� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/ChangeLog������������������������������������������������������������������������������0000664�0001750�0001750�00002007237�14211404421�014721� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������2009-03-16 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.26.0 release. 2009-02-04 Neil Jagdish Patel <njpatel@gmail.com> * src/core/frame.c: queue resize on window undecorate 2009-02-03 Luca Ferretti <elle.uca@libero.it> * src/include/all-keybindings.h: Fix description, focus the desktop, not desktop backgroung (Closes bug #569649) 2009-02-02 Matt Kraai <kraai@ftfbs.org> * src/core/schema-bindings.c: Wrap g_error calls in braces. 2009-02-01 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.233. 2009-02-01 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.144 release. 2009-02-01 Matt Kraai <kraai@ftbfs.org> Set prop_hooks_table to NULL after freeing it. * src/core/window-props.c: 2009-01-29 Thomas Thurman <tthurman@gnome.org> Window properties are looked up in a hash table rather than by iteration over an array. Saves ~44us per window, but also makes the code cleaner. * src/core/display-private.h: * src/core/window-props.c: 2009-01-27 Matthias Claesen <mclasen@redhat.com> * src/core/edge-resistance.c: some lists failed to keep track of their contents and therefore didn't free correctly. Closes #552303. 2009-01-27 Matthias Claesen <mclasen@redhat.com> * src/core/prefs.c: Free name of old theme when new theme is loaded. Closes #552973. 2009-01-27 Matthias Claesen <mclasen@redhat.com> * src/ui/ui.c: free the result of gdk_text_property_to_utf8_list() even when it returns no data. 2009-01-27 Owen Taylor <otaylor@redhat.com> GtkStyle is specific to a particular colormap. Metacity uses different colormaps for windows with different visuals, so it must specialize the GtkStyle. Closes #568365 and #513944. * src/ui/frames.[ch]: Keep a GtkStyle for each MetaUIFrame, which is obtained by calling gtk_style_attach() on the style for the MetaFrames. When the style of the MetaFrames changes, reattach everything. When we call gtk_style_set_background() pass in the right style. * src/ui/themes.[ch]: Create a _with_style() variant of functions that previously took the style from widget->style passed in, so we can draw with the right style for the colormap. 2009-01-27 Thomas Thurman <tthurman@gnome.org> Added a gconf key to swap the meanings of the right and middle buttons when the modifier key is held down. Closes #437910. Thanks to Matt Kraai for looking over the patch. * src/core/display.c: * src/core/prefs.c: * src/include/prefs.h: * src/metacity.schemas.in.in: 2009-01-27 Thomas Thurman <tthurman@gnome.org> All the window properties are now handled using simple window property handlers. Closes #549886. * src/core/window-private.h: * src/core/window-props.c: * src/core/window.c: 2009-01-26 Thomas Thurman <tthurman@gnome.org> More of the window properties are checked using simple window property handlers. The ones which remain don't actually look up the new value in the ordinary way, and so are a little trickier to merge. Added an "initial" flag to be on the safe side that the behaviour is the same as before (so we don't do things when a window's first mapped that we only used to do when a property changed). Partial fix for bug #549886. * src/core/window-props.c: * src/core/window-props.h: * src/core/window.c: 2009-01-25 Elijah Newren <newren gmail com> * src/core/window.c: add support for _NET_WM_MOVERESIZE_CANCEL. 2009-01-10 Thomas Thurman <tthurman@gnome.org> * src/ui/theme.[ch]: add meta_theme_draw_frame_by_name, which is needed for the theme editor. 2008-12-26 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.144. 2008-12-26 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.89 release. 2008-12-25 Thomas Thurman <tthurman@gnome.org> * src/include/all-keybindings.h: alt-F10 toggles maximisation, alt-F5 only restores. Also rename "unmaximize" to "restore". * src/ui/frames.c: Rename "unmaximize" to "restore". Closes #343824. 2008-12-25 Frederic Peters <fpeters@0d.be> * src/core/main.c: (main): added call to g_thread_init(), as ORBit2 stopped doing it and Metacity is using gconf; closes #565517. 2008-12-24 Yanko Kaneti <yaneti@declera.com> * src/metacity.schemas.in.in: add screenshot commands which had mistakenly been removed; closes #564343, Launchpad bug 298463, Red Hat bug 474635, and probably others. 2008-12-24 Thomas Thurman <tthurman@gnome.org> * src/include/all-keybindings.h: fix move_to_corner_se 2008-12-21 Colin Walters <walters@verbum.org> * src/core/window.c: windows which attempt to present themselves but are offscreen end up demanding attention, unless they are transient, when they move to the current workspace as before. Closes #482354. 2008-12-19 Thomas Thurman <tthurman@gnome.org> * src/ui/frames.c: when the user double-clicks the title bar, end the grab op. Closes #401028. 2008-12-16 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.89. 2008-12-16 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.55 release. 2008-12-15 Erwann Chenede <erwann.chenede@sun.com> * configure.in: fix build on Solaris. Closes #564123. 2008-12-02 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.55. 2008-12-02 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.34 release. 2008-12-02 Matt Kraai <kraai@ftbfs.org> * src/core/iconcache.c: patches to fixes for -Wall. Closes #562939. 2008-12-01 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.34. 2008-12-01 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.21 release. 2008-12-01 Thomas Thurman <tthurman@gnome.org> * configure.in: gnome-doc-tools version doesn't need to be so high. * src/compositor/compositor-xrender.c: disable the entire file if the compositor is disabled. * src/core/async-getprop.[ch]: fixes for -Wall * src/core/iconcache.c: fixes for -Wall * src/core/testasyncgetprop.c: fixes for -Wall * src/core/xprops.c: fixes for -Wall 2008-11-26 Thomas Thurman <tthurman@gnome.org> * tools/announce-wrangler.py: linked language codes to po files * tools/commit-wrangler.py: print revision url 2008-11-26 Thomas Thurman <tthurman@gnome.org> * tools/announce-wrangler.py: renamed ini file * tools/commit-wrangler.py: rewriting in terms of moap 2008-11-25 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.21. 2008-11-25 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.13 release. 2008-11-26 Thomas Thurman <tthurman@gnome.org> * tools/announce-wrangler.py (added): script to produce announcements 2008-11-26 Thomas Thurman <tthurman@gnome.org> * src/core/xprops.c: add casts (#562106) 2008-11-25 Thomas Thurman <tthurman@gnome.org> * metacity.doap: change to standard description. 2008-11-23 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.13. 2008-11-23 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.8 release. 2008-11-23 Thomas Thurman <tthurman@gnome.org> * po/POTFILES.in: add new bindings file 2008-11-23 Daniel Macks <dmacks@netspace.org> reviewed by: Thomas Thurman * src/Makefile.am: reorder compiler flags so local includes come last. Closes #562033. 2008-11-23 Daniel Macks <dmacks@netspace.org> reviewed by: Thomas Thurman * configure.in: only accept --enable-compositor if we find we can actually composite. Closes #560990. 2008-11-23 Thomas Thurman <tthurman@gnome.org> * src/core/display.c: remove apparently spurious warnings about operations on window "none" 2008-11-23 Thomas Thurman <tthurman@gnome.org> * src/core/util.c: Set _POSIX_C_SOURCE to 200112L as it should always have been, in an attempt to close #561962. 2008-11-22 Thomas Thurman <tthurman@gnome.org> * configure.in: Set -ansi so people stop complaining about C99. 2008-11-22 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.c: fix stupid infinite loop when GConf is turned off. 2008-11-22 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.c: fix two places where there was a warning if GConf was turned off. 2008-11-22 Thomas Thurman <tthurman@gnome.org> * src/core/all-keybindings.h: "backward", not "backwards" throughout. 2008-11-20 Thomas Thurman <tthurman@gnome.org> * configure.in: turned on -Wall and -Werror in order to trap as many problems as possible. * src/ui/resizepopup.c: added correct #include. * src/ui/theme-viewer.c: initialised variable. * src/core/xprops.c: corrected cast. * src/core/main.c: added warning if chdir() fails. * src/core/schema-bindings.c: checking the return result of fgets(). 2008-11-20 Thomas Thurman <tthurman@gnome.org> Merged screen and window keybinding tables so that we can use just one file for the both. Also incidentally closes #528337. Further efficiencies of scale to come. * src/include/prefs.h: replace META_PREF_*_KEYBINDINGS with META_PREF_KEYBINDINGS * src/core/keybindings.c: replace *_bindings with key_bindings and similar throughout; all window-based functions are now guaranteed to receive a window so don't need to check for themselves (find_handler): moved so it can also be called from rebuild_binding_table * src/core/display-private.h: replace *_bindings with key_bindings * src/core/prefs.c: update_*_binding becomes update_key_binding; (change_notify): tidy up references to "enormous if statement" since it's almost entirely gone now * src/core/all-keybindings.h: new merged version of screen-bindings.h and window-bindings.h. 2008-11-16 David Trowbridge <trowbrds@gmail.com> This change adds support for the new _NET_WM_FULLSCREEN_MONITORS property and client message. This allows client applications to request that a fullscreen window cover more than one monitor. * src/include/boxes.h: * src/core/boxes.c: Add meta_rectangle_union * src/core/window-private.h: * src/core/window.c: (meta_window_new_with_attrs, meta_window_free, set_net_wm_state, meta_window_update_fullscreen_monitors, meta_window_client_message): Add MetaWindow property to store fullscreen monitors field, update _NET_WM_FULLSCREEN_MONITORS property on windows, and handle client message. * src/core/atomnames.h: Add _NET_WM_FULLSCREEN_MONITORS atom. * src/core/constraints.c (setup_constraint_info): If _NET_WM_FULLSCREEN_MONITORS is interesting, use the data stored in MetaWindow::fullscreen_monitors to determine the fullscreen area instead of the basic xinerama_info area. 2008-11-11 Thomas Thurman <tthurman@gnome.org> Removed deprecated calls. Closes #560445. * src/core/delete.c: remove deprecated g_strcasecmp. * src/include/main.h: no actual deprecated call, but a mention of one which was out of date. 2008-11-11 Maxim Ermilov <zaspire@rambler.ru> Clean up #includes according to the GNOME Goal. Closes #560449. Patch is 122467. * src/core/place.c: * src/ui/draw-workspace.h: * src/ui/gradient.h: * src/ui/metaaccellabel.c: * src/ui/metaaccellabel.h: * src/ui/preview-widget.c: * src/ui/preview-widget.h: * src/ui/resizepopup.c: * src/ui/theme.c: * src/ui/theme.h: * src/ui/themewidget.h: 2008-11-10 Elijah Newren <newren gmail com> * src/metacity.schemas.in.in: updated description of raise_on_click: http://bugzilla.gnome.org/show_bug.cgi?id=445447#c6 2008-11-08 Thomas Thurman <tthurman@gnome.org> * configure.in: added dependency on Zenity * src/core/keybindings.c: remove error_on_generic_command() and error_on_terminal_command(); rewrite error_on_command in terms of meta_show_dialog() * src/core/util.c: add meta_show_dialog() to call Zenity * src/include/util.h: ditto 2008-11-03 Olav Vitters <olav@bkor.dhs.org> * src/ui/theme-parser.c: Fix build by readding accidentally removed '}'. 2008-10-29 Thomas Thurman <tthurman@gnome.org> * src/ui/theme-parser.c: variable names in messages should be double-quoted. Closes #558309. 2008-10-28 Thomas Thurman <tthurman@gnome.org> * src/include/screen-bindings.h: fix accidental name change of run_command_terminal. Closes #557943. 2008-10-27 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.c (titlebar_handler, handle_preference_update_enum): Add initialisation which I missed on the previous checkin. Also an extra comment. 2008-10-27 Brian Cameron <brian.cameron@sun.com> Fix some crashes with the new GDM 2.24. Closes #558058. * src/ui/ui.c (meta_ui_parse_modifier): another null check * src/core/prefs.c (titlebar_handler, button_layout_handler): more null checks. 2008-10-26 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.c (mouse_button_mods_handler): Ignore values of .../mouse_button_modifier key if the key's missing. Closes Launchpad bug #258054, Launchpad bug #266929. 2008-10-23 Frederic Peters <fpeters@0d.be> * doc/creating_themes/C/creating-metacity-themes.xml: added missing @id on <book> top element. 2008-10-23 Frederic Peters <fpeters@0d.be> * doc/creating_themes/Makefile.am: * doc/creating_themes/C/creating_metacity_themes.xml: renamed document to creating-metacity-themes to match other manuals usage of dashes. 2008-10-23 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.8. 2008-10-23 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.5 release. 2008-10-23 Thomas Thurman <tthurman@gnome.org> * src/core/schema-bindings.c: fix stupid thinko which caused defaults to be incorrect * src/include/window-bindings.h: "space" needs to be lowercase 2008-10-23 Thomas Thurman <tthurman@gnome.org> Support _NET_WM_STATE_STICKY (i.e. allow third-party apps to decide whether a window is on all workspaces). Bug found by Ka-Hing Cheung. Closes #557536. * src/core/window.c (set_net_wm_state): report it * src/core/window.c (meta_window_client_message): set sticky if we receive it * src/core/window-props.c: set sticky if we find it * src/core/atomnames.h: add _NET_WM_STATE_STICKY 2008-10-22 Thomas Thurman <tthurman@gnome.org> * src/core/schema-bindings.c: support builds outside tree properly. * src/Makefile.am: ditto. * po/POTFILES.skip: ditto. 2008-10-22 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.5. 2008-10-22 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.3 release. 2008-10-22 Thomas Thurman <tthurman@gnome.org> * configure.in: bump to 2.25.3 (thought the release script had already done this) 2008-10-22 Thomas Thurman <tthurman@gnome.org> Fixes to make distcheck work again. * src/Makefile.am: include *-binding.h, and make the schema building work when builddir != srcdir * po/POTFILES.in (src/core/keybindings.): include *-binding.h 2008-10-22 Götz Waschk <waschk@mandriva.org> * configure.in: add libm reference. Closes #557357. 2008-10-22 Murray Cumming <murrayc@murrayc.com> * doc/creating_themes/C/creating_metacity_themes.xml: Fixed various tags to make this validate. Bug #557337 2008-10-22 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.2 release. 2008-10-22 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.2 release. 2008-10-22 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.2 release. 2008-10-22 Joe Marcus Clarke <marcus@freebsd.org> * src/core/main.c (meta_finalize, sigterm_handler): new functions * src/core/main.c (main): add sigterm_handler in case we receive a SIGTERM. Closes #553980. 2008-10-22 Matthew Martin <mtt.martin@gmail.com> * src/core/window.c (meta_window_set_demands_attention): minimised windows are necessarily obscured. Closes #528927. 2008-10-22 Thomas Thurman <tthurman@gnome.org> Slight transformation of the x-macros used in keybindings to make them clearer: write handler names out in full because the old suffix system was confusing to people skim-reading, and switched the order of the last two parameters so more would generally fit on a screen. * src/core/keybindings.c, src/core/schema-bindings.c src/core/prefs.c: sympathy changes * src/core/window-bindings.h, src/core/screen-bindings.h: transformation as above 2008-10-21 Christian Persch <chpe@gnome.org> * src/Makefile.am: fix build when schemas are not installed. Closes #557335. 2008-10-21 Tomas Frydrych <tf@linux.intel.com> * src/core/screen-bindings.h: Fix off-by-one error. * src/core/window-bindings.h: Fix off-by-one error. Closes #557201. 2008-10-18 Thomas Thurman <tthurman@gnome.org> During a discussion with Rodney Dawes about making life easier for the translators, he pointed out that the short and long forms of almost all the keybindings say much the same thing in different words. I believe this is an unconscionable burden to place on translators, and have therefore merged the short and long descriptions into the short description. The long is now a general explanation of the format, plus possibly a notice about reversibility. Closes #469361, and should solve the l10n issue previously mentioned. * src/core/keybindings.c: reflect changes in *-bindings.h * src/core/schema-bindings.c: reflect changes in *-bindings.h * src/core/prefs.c: reflect changes in *-bindings.h * src/core/window-bindings.h: Add flags field, always the same currently, so that it's the same as screen-bindings.h. Also, lose ONLY_BOUND_BY_DEFAULT, since we already had a rather more elegant way to perform the same effect. And merge the long and short descriptions. * src/core/screen-bindings.h (, item): Merge the long and short descriptions. 2008-10-17 Murray Cumming <murrayc@murrayc.com> * configure.in: Call GNOME_DOC_INIT() so we can use the gnome-doc-utils variables in our Makefile.am: * doc/Makefile.am: * doc/creating_themes/Makefile.am * doc/creating_themes/C/creating_metacity_themes.xml: Added this new DocBook document, converted from the HTML here http://blogs.gnome.org/metacity/2008/05/30/themes/ This will be installed for yelp and can be translated and hosted on library.gnome.org. 2008-10-15 Thomas Thurman <tthurman@gnome.org> Since Patrick Niklaus's checkin of 2008-08-14 dealt with windows with no icons not using fallback icons, we don't need fallback icons. * src/ui/theme.h: remove fallback icons from struct. * src/core/iconcache.c (meta_read_icons): don't look for fallbacks. * src/*/ui.[ch] (meta_ui_get_fallback_icons): removed * src/ui/theme-parser.c (typedef, parse_toplevel_element): don't parse fallback specifications. 2008-10-13 Thomas Thurman <tthurman@gnome.org> * po/POTFILES.in: add screen-bindings.h 2008-10-13 Thomas Thurman <tthurman@gnome.org> * po/POTFILES.in: raw schemas is now .in.in * po/LINGUAS: add Latin 2008-10-12 Thomas Thurman <tthurman@gnome.org> Make the bindings in src/core/*-bindings.h generate GConf schemas too. Note that there's an i18n issue (documented in schema-bindings.c) which will be fixed next checkin. * src/core/schema-bindings.c: major fixup to make it ready for use as part of the actual build process. * src/Makefile.am: added magic to make it call schema-bindings after it builds it. * src/core/window-bindings.h: added comments; also, window menu was listed variously as alt-Space and alt-Print; it should have been alt-Space. * src/metacity.schemas.in.in: renamed from s/\.in$//, sentinel added for the generated bindings, warning at the top now untrue, and removed. 2008-10-12 Thomas Thurman <tthurman@gnome.org> Fix annoying bug where alt-tab and friends would jump backwards a space on initial movement. * src/core/screen-bindings.h: although reversed bindings are necessarily reversible, don't set both bits in the constant, or when we test for them we'll get confused. 2008-10-12 Thomas Thurman <tthurman@gnome.org> An attempt to make life a little easier for our beloved translators; this has the same behaviour as before, but removes over thirty translation strings. * src/core/session.c (start_element_handler): all "attribute not found on element" strings are identical * src/ui/theme-parser.c (locate_attributes): allow attribute names to be preceded with "!" (in the code) to show they're required. (parse_aspect_ratio, parse_distance, parse_toplevel_element, parse_style_element, parse_gradient_element, static, parse_border, parse_style_set_element, parse_draw_op_element): use the new "!" prefix for locate_attributes(), or in some cases just the identical constant, for generating this error. * src/ui/theme.c (check_state, meta_theme_validate): add translator comments * src/ui/resizepopup.c (update_size_window): add translator comments 2008-10-06 William Lachance <wrlach@gmail.com> Pass modified mouse button events down to panel windows instead of dealing with them ourselves. Closes #554428. * src/core/display.c (prefs_changed_callback): don't grab mouse buttons on panels * src/core/window.c (meta_window_new_with_attrs): ditto 2008-10-05 Thomas Thurman <tthurman@gnome.org> Second half of the switch to using x-macros for keybindings so that we don't have lots of places with the same information which must stay in the same order. This time it's screen bindings. * src/core/screen-bindings.h: New file, containing screen bindings. * src/core/schema-bindings.c: added ability to output screen bindings. * src/core/window-bindings.h: tiny tweak to comment * src/core/keybindings.c: generate function prototypes using s-b.h; several handlers modified to use ints rather than ints cast into pointers, or renamed. * src/include/prefs.h: generate names of bindings using s-b.h; generate screen_handlers using s-b.h; arguments to bindings are ints and not ints cast to pointers; several handler functions renamed to consistent names. * src/core/prefs.c (meta_prefs_set_num_workspaces, init_bindings): generate screen_handlers using s-b.h; generate screen_string_bindings using s-b.h (and add check for null bindings in init_bindings to enable this simply). 2008-10-05 Thomas Thurman <tthurman@gnome.org> * tools/ppa-magic.py: experimental tool for Launchpad upload 2008-10-05 Thomas Thurman <tthurman@gnome.org> * metacity.doap: Havoc is an author; Thomas has an email address; add a ton of release information going back to the early days, although not right to the beginning. 2008-09-26 Thomas Thurman <tthurman@gnome.org> * autogen.sh: not all versions of /bin/sh can handle this script, so specify one. Also update the error message because we don't use CVS these days. 2008-09-20 Thomas Thurman <tthurman@gnome.org> * po/POTFILES.in: fix name of window-bindings.h 2008-09-20 Thomas Thurman <tthurman@gnome.org> * po/POTFILES.in: added new files and re-sorted 2008-09-12 Vincent Untz <vuntz@gnome.org> Install desktop files in both .../share/applications and .../share/gnome/wm-properties. Copied in from the 2.23.x branch. Closes #549479. * src/metacity-wm.desktop.in: new file * src/.cvsignore: include the above * src/Makefile.am: install the above 2008-09-06 Thomas Thurman <tthurman@gnome.org> An attempt to keep all information about window bindings in the same place. Screen bindings to come. * src/core/window-bindings.h: new file, list of all window bindings * src/include/prefs.h: drop all the existing window-binding macros * src/core/schema-bindings.c (): output all the schema blocks that would appear in metacity.schema for these window bindings. This ought to become part of the build process, and hopefully will soon. When this works it will also close #469361. * src/core/keybindings.c: generate handle_* prototypes using x-macros; populate window_handlers using x-macros; rename several functions to have consistent names; do_handle_move_to_workspace(), handle_move_to_workspace_flip(), and handle_move_to_workspace() all merged into handle_move_to_workspace. * src/core/prefs.c: generate window_bindings and window_string_bindings using x-macros; (meta_prefs_set_compositing_manager) fix unrelated problem with use of GConf functions when GConf was disabled. * src/core/core.c (meta_core_get_menu_accelerator): binding names given as literals since this is the only place in the code they now appear 2008-09-03 Thomas Thurman <tthurman@gnome.org> * src/metacity.desktop.in: removed invalid "Window Manager" group at request of Matthias Clasen. 2008-09-02 Thomas Thurman <tthurman@gnome.org> Desktop file moved, according to policy change. Closes #549479. * src/metacity.desktop.in: Don't display the desktop file * src/Makefile.am: Desktop file goes in apps directory 2008-09-01 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.25.2. 2008-09-01 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.1 release. 2008-09-01 Thomas Thurman <tthurman@gnome.org> * src/core/workspace.c: When a workspace's list of struts is freed, free the struts too. Closes #549952, and #468075. 2008-09-01 Thomas Thurman <tthurman@gnome.org> Add new move_to_center keybinding, requested by Khanh-Dang Nguyen Thu Lam; closes #549979. * src/include/prefs.h (void): add name of new binding * src/core/prefs.c: added pref for it * src/core/keybindings.c (handle_move_to_center): new function * src/metacity.schemas.in: included new binding 2008-08-31 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.[ch] (meta_prefs_set_compositing_manager): new function. * src/core/main.c (meta_parse_options): turn the compositing manager on or off as necessary. 2008-08-30 Thomas Thurman <tthurman@gnome.org> * src/core/window.c (process_property_notify): moving all messages about properties to the top, as a start at #549886 2008-08-18 Thomas Thurman <tthurman@gnome.org> * NEWS: fix version number which broke 2008-08-18 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release version bump to 2.25.1. 2008-08-18 Thomas Thurman <tthurman@gnome.org> * configure.in: correct incorrect version number 2008-08-18 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.25.1 release. 2008-08-18 Thomas Thurman <tthurman@gnome.org> Adding doxygen headers to some files. * src/core/metacity-Xatomtype.h * src/core/main.c * src/core/screen-private.h * src/core/window-private.h * src/core/keybindings.h * src/core/session.h * src/core/workspace.h * src/core/window-props.h () 2008-08-18 Eric Piel <e.a.b.piel@tudelft.nl> * src/core/workspace.c (ensure_work_areas_validated): add a copy of each strut in a window to the workspace's strut list, instead of using the copy in the list (which would mean it was double-freed). Believed to fix #468075. 2008-08-16 Ted Percival <ted@midg3t.net> Ensure the user_rect is set sanely for windows that start maximized. Prevents maximized windows from warping across the screen. Fixes bug #504692. * src/core/window.c (save_user_placement): renamed version of meta_window_save_user_rect(). * src/core/window.c (force_save_user_placement): similar, but will always save user_rect even if the window is maximised or fullscreen. * src/core/window.c (meta_window_move_resize_internal): unplaced windows have force_save_user_placement() called instead of save_user_placement(). 2008-08-14 Patrick Niklaus <marex@compiz-fusion.org> Icons for windows are taken from the desktop theme, not from the Metacity theme or from the fallback icon that Metacity provided. Closes #524343. * src/ui/ui.c: Use GtkIconTheme to load the default window icon. Assumes the existence of an icon called "window", otherwise falls back to "gtk-missing-image". Fixes #524343. * src/ui/preview-widget: See above. * src/include/common.h: Add META_DEFAULT_ICON_NAME. * src/Makefile.am: Remove default_icon.png from inlinepixbufs.h. * src/default_icon.png: Removed. 2008-08-14 Akira TAGOH <akira@tagoh.org> * doc/man/metacity-message.1: new manual page. * doc/man/Makefile.am: added new reference. 2008-08-13 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-branch bump to 2.25.0. 2008-08-04 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.144. 2008-08-04 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.89 release. 2008-07-26 Thomas Thurman <tthurman@gnome.org> * metacity.doap (added): DOAP file (first pass, anyway). 2008-07-14 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.89. 2008-07-14 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.55 release. 2008-07-13 Thomas Thurman <tthurman@gnome.org> * src/core/display.c (event_callback): meta_display_screen_for_root() can return NULL, so check for that. Fixes #422242. Also tidying. 2008-07-13 Elijah Newren <newren gmail com> * src/core/workspace.c (meta_workspace_free): Don't attempt to double-free struts, edges and regions if work areas have already been invalidated at the time of freeing a workspace. Possible fix to #361804. 2008-07-12 Thomas Thurman <tthurman@gnome.org> * src/core/constraints.c (do_screen_and_xinerama_relative_constraints): Don't allocate memory for log messages unless we're logging. 2008-07-12 Thomas Thurman <tthurman@gnome.org> * src/core/group.c (meta_window_get_group): This function can now officially return NULL. * src/core/window.c (meta_window_same_application): Two windows can't belong to the same application unless they both belong to some application. (Both belonging to no application is not the same.) 2008-06-30 Thomas Thurman <tthurman@gnome.org> * src/core/bell.c (meta_bell_set_audible): Fix typo that slipped through. 2008-06-30 Thomas Thurman <tthurman@gnome.org> * src/core/bell.[ch]: Move comments for non-statics from the .c to .h. * Doxyfile: adapt better for C, and make quiet. 2008-06-29 Thomas Thurman <tthurman@gnome.org> * src/ui/theme-viewer.c (main): display the theme name in the title bar. Closes #430198. 2008-06-29 Thomas Thurman <tthurman@gnome.org> Allow toggling of non-compositor effects (since there's a non-Metacity key to do so: /desktop/gnome/interface/enable_animations). Closes #92867. * src/include/prefs.h: add META_PREFS_GNOME_ANIMATIONS key and meta_prefs_get_gnome_animations() function * src/include/prefs.c: added meta_prefs_get_gnome_animations() function, and made supporting changes to structs. * src/core/effects.c (run_handler): checked whether enable_animations is set before running an effect. * src/core/effects.c (meta_effect_run_minimize): remove debug message. 2008-06-29 Thomas Thurman <tthurman@gnome.org> * src/core/bell.c: remove meta_ prefix on all static functions. 2008-06-29 Thomas Thurman <tthurman@gnome.org> * src/core/stack.c (stack_sync_to_server): lose meta prefix since it's static. * src/core/stack.c (meta_stack_remove, stack_do_window_deletions): replace our own cast with glib macro designed to do the same thing 2008-06-28 Thomas Thurman <tthurman@gnome.org> * src/core/display.c, src/compositor/compositor-xrender.c: add checks for HAVE_SHAPE where appropriate. * src/core/xprops.c: fix type error which was causing warnings. 2008-06-28 Thomas Thurman <tthurman@gnome.org> Some refactoring, simplifying, and commenting of the non-composited effects code. effects.c could still do with some polish, which will come along later. * src/core/effects.h (meta_push_effect_handler): removed since it's never used and does nothing very useful. * src/core/effects.h (meta_pop_effect_handler): removed since its only effect is to crash the program. * src/core/effects.h (META_MINIMIZE_ANIMATION_LENGTH, META_SHADE_ANIMATION_LENGTH): move to effects.c because they're used nowhere else. * src/core/effects.c: there were three versions of the box-zoom effect. Remove the one which was never used, and make only the ones which are used with certain configure settings be compiled. * src/core/effects.h (meta_effect_end): move to effects.c, make static, and rename to effect_free. * src/core/effects.h (meta_effects_draw_box_animation): move to effects.c, make static, and rename to draw_box_animation. * src/core/effects.h (MetaEffectType): remove the values which weren't used. * src/core/window.c (meta_window_shade): remove commented-out code to call effect for shading. * src/core/effects.h (MetaEffectFinish): remove useless MetaEffect parameter. * src/core/window.c (finish_minimize): remove MetaEffect parameter. 2008-06-27 Thomas Thurman <tthurman@gnome.org> * src/core/stack.h: Commented everything. 2008-06-26 Thomas Thurman <tthurman@gnome.org> Keep the compiler from giving some warnings. * src/compositor/compositor-xrender.c (xrender_begin_move, xrender_update_move, xrender_end_move, xrender_free_window): four functions which were never called and contain no code #iffed out. * src/tools/metacity-mag.c (grab_area_at_mouse): fixed typecast error. 2008-06-26 Thomas Thurman <tthurman@gnome.org> Refactor so the long scary stack functions are less long and scary: * stack.c (stack_ensure_sorted): the five parts of this long function broken out into the new functions stack_do_window_deletions, stack_do_window_additions, stack_do_relayer, stack_do_constrain (which was already separate: see next) and stack_do_resort. * stack.c (constrain_stacking): renamed to stack_do_constrain. * stack.c (stack_ignore_sorted): lose meta prefix since it's static. 2008-06-16 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.55. 2008-06-16 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.34 release. 2008-06-16 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.34 release. 2008-06-13 Thomas Thurman <tthurman@gnome.org> * src/core/window-props.c: Some commenting. * src/core/prefs.c: Added unified handling of integer preferences. Re-ordered fields in existing preferences so that changing to a union-based system will be easier in the future. 2008-06-10 Thomas Thurman <tthurman@gnome.org> * test/tokentest/tokentest.c (draw_string_to_spec): doubles are %f or %g, not %d * test/tokentest/tokentest.ini: re-created fair copy accordingly 2008-06-10 Thomas Thurman <tthurman@gnome.org> * test/tokentest: A preliminary attempt at a test for the theme expression tokeniser. 2008-06-05 Thomas Thurman <tthurman@gnome.org> * src/compositor/compositor-xrender.c (paint_root, destroy_win, create_root_buffer, paint_windows, repair_screen, window_has_shadow, xrender_set_active_window, paint_dock_shadows, unmap_win, restack_win, make_shadow, resize_win, process_property_notify, free_win, process_configure_notify, process_circulate_notify, add_damage): defensive programming; check meta_screen_get_compositor_data() throughout in case it returns NULL. In particular, when this happened in a certain situation in xrender_set_active_window this caused a segfault; refs #530702 (and LP#178953 has more data) but this doesn't close them. 2008-06-02 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.34 release. 2008-06-02 Thomas Thurman <tthurman@gnome.org> * src/core/display.c: make sure compositor things don't get compiled when we're not using the compositor. 2008-06-02 Thomas Thurman <tthurman@gnome.org> * test/metacity-test: new test script, imported from branch. 2008-05-30 Thomas Thurman <tthurman@gnome.org> * src/core/window-props.h: fix comments (number) 2008-05-30 Thomas Thurman <tthurman@gnome.org> * src/core/window-props.h: commenting 2008-05-28 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.c (handle_preference_update_string, meta_prefs_remove_listener, queue_changed): Make disabling gconf work again. Closes #530870. 2008-05-26 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.34. 2008-05-26 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.21 release. 2008-05-26 Thomas Thurman <tthurman@gnome.org> * src/Makefile.am: added in two files needed for Iain's changes earlier to work in a release tarball 2008-05-24 Iain Holmes <iain@gnome.org> * src/compositor/compositor-xrender.c: Add Dropdown menu atoms so we can add shadows to them. Fixes #517442 Handle tooltips as well. Fixes #517524 2008-05-24 Iain Holmes <iain@gnome.org> * src/compositor/compositor.c: Check the compositor isn't NULL before dereferencing it. Fixes #534569 (meta_compositor_get_window_pixmap): Actually return a value 2008-05-19 Iain Holmes <iain@gnome.org> * src/core/window.c: Applied patch from Ed Catmur to fix #528787 2008-05-19 Iain Holmes <iain@gnome.org> * src/include/frame.h * src/include/display.h * src/include/xprops.h * src/include/compositor.h * src/include/types.h * src/include/window.h * src/include/errors.h * src/include/screen.h: New basic public API for compositor. * src/compositor/*: Separate the compositor out into its own separate directory and set it up for backends. Initial XRender backend. * src/core/compositor.[ch]: Remove * src/core/frame.h * src/core/screen.h * src/core/display.h * src/core/window.h: Rename to -private.h so as not to clash with the new files in include * src/core/delete.c * src/core/workspace.h * src/core/stack.[ch] * src/core/keybindings.[ch] * src/core/errors.c * src/core/effects.[ch] * src/core/core.c * src/core/group.h * src/core/edge-resistance.[ch] * src/core/window-props.[ch] * src/core/constraints.h * src/core/bell.[ch] * src/core/iconcache.h * src/core/session.[ch] * src/core/main.c * src/core/place.h * src/core/xprops.c * src/ui/tabpopup.c: Use the new -private headers * src/core/display.c * src/core/frame.c * src/core/window.c * src/core/screen.c: Add the API functions required by the compositor * src/Makefile.am: Relocate the new files 2008-05-13 Robert Escriva <me@robescriva.com> * src/ui/theme.h (struct): remove color_set flag * src/ui/theme.c (meta_color_spec_render, meta_color_spec_new_from_string): remove check of color_set flag before rendering (we always do it now). Closes #511826. 2008-05-12 Thomas Thurman <tthurman@gnome.org> * tools/xlib.py: Basic Python-based Xlib client for testing and building upon. 2008-05-09 Elijah Newren <newren gmail com> * src/ui/color.[ch]: Remove these two unused files 2008-05-04 Thomas Thurman <tthurman@gnome.org> Added curly brackets in two places to keep -pedantic happy. * src/core/window-props.c (meta_display_init_window_prop_hooks) * src/core/group-props.c (meta_display_init_group_prop_hooks) 2008-05-03 Matt Krai <mkraai@beckman.com> * src/core/delete.c (io_from_ping_dialog): fix type of "len" variable (refs #526049) 2008-05-02 Thomas Thurman <tthurman@gnome.org> All information should live in exactly one place. This means that the list of atoms should not be replicated anywhere. Therefore, we include it via x-macros. Closes #530843. * src/core/atomnames.h: added list of atom names * src/Makefile.am: added reference to new file * src/core/display.h * src/core/display.c (twice) * src/core/screen.c: #included atomnames.h instead of having an enormous list of atoms * src/core/group-props.c * src/core/window.c * src/core/compositor.c * src/core/window-props.c * src/core/delete.c * src/core/workspace.c * src/core/stack.c * src/core/keybindings.c * src/core/iconcache.c * src/core/group.c * src/core/xprops.c: changed to new, simpler identifiers for atoms 2008-04-29 Chris Wang <chris.wang@sun.com> * src/core/window.c (meta_window_new): XGetWindowAttributes can return an error value, and if it does its other results are invalid! (#530485) 2008-04-29 Thomas Thurman <tthurman@gnome.org> * src/ui/fixedtip.[ch]: documentation 2008-04-27 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.21. 2008-04-27 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.13 release. 2008-04-27 Erwann Chenede <erwann.chenede@sun.com> * src/core/place.c (meta_window_place): re-enable cascade code which was wrongly removed a year ago. Closes #529925. 2008-04-22 Carlos Garnacho <carlos@imendio.com> * src/core/compositor.c (process_property_notify, find_window_in_display): Propagate opacity to frame window. 2008-04-22 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.13. 2008-04-22 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.8 release. 2008-04-22 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.21.8. (Which was seriously belated. Sorry, folks.) 2008-04-22 Thomas Thurman <tthurman@gnome.org> * src/core/effects.c: a few comments 2008-04-10 Lucas Rocha <lucasr@gnome.org> * src/Makefile.am: no need to create a symlink to .desktop file in default-session directory anymore as gnome-session will find metacity's .desktop in its original place. 2008-04-07 iain <iain@gnome.org> * src/core/compositor.c (hide_overlay_window): Hide the overlay window (meta_compositor_unmanage_screen): Release the compositor overlay. (#526770) 2008-04-07 Jens Granseuer <jensgr@gmx.net> * src/core/session.c: (save_state), (warn_about_lame_clients_and_finish_interact): reorder declarations so we don't break C89 compilers. 2008-04-06 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.5 release. 2008-04-03 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.c (handle_preference_update_bool): preferences which have a null target don't get updated! (#526016) 2008-03-29 Lucas Rocha <lucasr.at.mundo@gmail.com> * src/metacity.desktop.in, src/Makefile.am: make Metacity install its desktop files in the default session directory as required by the new gnome-session. (Closes #525051.) 2008-03-29 Thomas Thurman <tthurman@gnome.org> * src/ui/preview-widget.c (meta_preview_get_clip_region): prevent null dereference if the theme was invalid, which caused crashes in gnome-appearance-properties. No GNOME bug number, but I believe this is a fix for Launchpad bug #199402 and its many duplicates. 2008-03-28 Owen Taylor <otaylor@redhat.com> * src/core/window.c (meta_window_new_with_attrs): Don't immediately unminimize an initially iconic window (#491090) 2008-03-27 Thomas Thurman <tthurman@gnome.org> * src/core/session.c (regenerate_save_file, save_state, load_state): files are saved in ~/.config/metacity/sessions and checked for there and in ~/.metacity/sessions. Fixes #518596. 2008-03-27 Thomas Thurman <tthurman@gnome.org> * src/core/display.c (meta_display_close): fix regression where Metacity sometimes wouldn't quit when replaced 2008-03-26 Thomas Thurman <tthurman@gnome.org> * src/core/display.c (event_callback): meta_display_screen_for_root is quite capable of returning NULL. 2008-03-25 Thomas Thurman <tthurman@gnome.org> * src/core/display.c (meta_display_queue_retheme_all_windows, meta_set_syncing, meta_display_set_cursor_theme, disable_compositor, meta_display_for_x_display, meta_display_open, meta_display_close, meta_display_ungrab): MetaDisplay becomes a singleton. The static variable which holds this singleton is renamed "the_display" so as not to mask the this parameter in the methods. * src/core/main.c (main): * src/core/session.c (warn_about_lame_clients_and_finish_inte, save_state, io_from_warning_dialog): * src/core/core.c (meta_core_increment_event_serial): * src/core/delete.c (release_window_with_fd, search_and_destroy_window): sympathy changes for this, and consequent simplification. Closes #499301. 2008-03-21 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.5. 2008-03-21 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.3 release. 2008-03-21 Thomas Thurman <tthurman@gnome.org> * src/ui/menu.c (activate_cb, get_workspace_name_with_accel): Workspaces whose name is the standard name plus a non-empty string are handled correctly in menus. Closes #453678. 2008-03-19 Iain Holmes <iain@gnome.org> * src/core/compositor.c (meta_compositor_set_active_window): Handle compositor being disabled and don't crash. 2008-03-19 Iain Holmes <iain@gnome.org> * src/core/compositor.c (meta_compositor_set_active_window): Add a screen argument. (process_property_notify): Damage the whole screen when the background changes. Fixes 522599 (add_repair): Use the idle instead of the timeout. Fixes 522166 (unmap_win): If the window is also focus window NULLify it. * src/core/window.c (meta_window_notify_focus): Notify when a window has lost focus, pass in screen as well. 2008-03-18 Iain Holmes <iain@gnome.org> * src/core/compositor.c (window_has_shadow): Allow shaped windows _with frames_ to have shadows. (meta_compositor_set_active_window): Watch for the focus of windows and change the size of the drop shadows. (generate_shadows): Create differently sized shadows. (meta_compositor_get_window_pixmap): Get the xwindow correctly. * src/core/window.c (meta_window_notify_focus): Set the active window in the compositor. 2008-03-18 Marco Pesenti Gritti <mpgritti@gmail.com> * src/core/window.c (window_would_be_covered): newly created windows can't be considered to be above themselves; fixes bug #519188. 2008-03-11 Matthew Wilson <msw@gimp.org> * src/core/keybindings.c (meta_display_process_key_event, process_event, find_handler, process_mouse_move_resize_grab): allow moving workspace while moving window with modifier * src/core/workspace.c (meta_workspace_activate_with_focus): remove the correct window on jumping workspace while moving 2008-03-10 Josh Lee <jleedev@gmail.com> * src/core/compositor.c (window_has_shadow): Don't shadow shaped windows. 2008-03-07 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.3. 2008-03-07 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.2 release. 2008-03-07 Thomas Thurman <tthurman@gnome.org> * src/core/prefs.c (mouse_button_mods_handler): remove debug statements (*blush*) 2008-03-06 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.2. 2008-03-06 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.1 release. 2008-03-06 Thomas Thurman <tthurman@gnome.org> * tools/release-wrangler.py: basic md5 printing (not used yet); also print release announcements to stdout (eventually will need to be emailed to release list and blogged) 2008-03-06 Thomas Thurman <tthurman@gnome.org> Part three of the great prefs refactor, this time dealing with string preferences. (This was the most complicated part, and has been especially tested and valground before committing. As ever, though, let us know if you find a problem.) * src/core/prefs.c (MetaStringPreference): new struct. * src/core/prefs.c (update_*): replaced with *_handler * src/core/prefs.c (meta_prefs_init): uses new string prefs init; uses array of gconf dirs to monitor rather than repeating code. * src/core/prefs.c (handle_preference_init_enum): tidying * src/core/prefs.c (change_notify): uses new string prefs 2008-03-04 Thomas Thurman <tthurman@gnome.org> * MAINTAINERS: added some spacing to see whether it helps Pulse 2008-03-03 Cosimo Cecchi <anarki@lilik.it> Add ability to vertically and horizontally maximise using the mouse, by clicking the titlebar in various ways. A very similar patch was received from Jason Ribero. Thanks also go to Tony Houghton and Carlo Wood, who both submitted patches which solved this differently. Closes #358674. * src/include/common.h (MetaActionTitlebar): new values for the new actions * src/core/core.c (meta_core_maximize_{vertic|horizont}ally): new functions. * src/ui/frames.c (meta_frame_titlebar_event): handle the new action values * src/core/window.h: new macros (for regularity, not really necessary) * src/core/prefs.c (symtab_titlebar_action): new string representations of the action values * src/metacity.schemas.in: documentation 2008-02-29 Andrea Del Signore <sejerpz@tin.it> Add support for "spacer" as a button type which adds some empty space. Closes #509165. * src/ui/theme.c (meta_frame_layout_calc_geometry), src/include/common.h (MetaButtonLayout), src/core/prefs.c (update_button_layout, button_layout_equal), src/metacity.schemas.in: add spacer support 2008-02-28 Thomas Thurman <tthurman@gnome.org> * src/core/compositor.h: removed unnecessary #include which should have been in Jim's patch (not sure how it slipped through the tests!) 2008-02-27 Jim Huang <jserv.tw@gmail.com> * src/core/spring-model.[ch]: deleted as no longer used * src/Makefile.am: modified accordingly 2008-02-27 Thomas Thurman <tthurman@gnome.org> Lots of tiny fixes to make sure we compile with "gcc -ansi -Werror". 2008-02-26 Jens Granseuer <jensgr@gmx.net> * src/core/constraints.c (constrain_aspect_ratio, constrain_size_limits, constrain_size_increments): reorder declarations so we don't break C89 compilers. Closes #518917. 2008-02-26 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.23.1. 2008-02-26 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.23.0 release. 2008-02-26 Thomas Thurman <tthurman@gnome.org> * tools/release-wrangler.py: ANY post-release bump is now the most recent, not just the one that matches the current version. Otherwise, you can't use these tools straight after a branch. The changeset before this one was mislabelled because of this. It has now been excised from the changelog. 2008-02-25 Thomas Wood <thos@gnome.org> * src/ui/preview-widget.[ch] (meta_preview_get_clip_region): allow users of the preview widget to get a mask for windows in the correct shape for the current theme. 2008-02-23 Thomas Thurman <tthurman@gnome.org> Refactor handling of boolean preferences. * src/core/prefs.c (handle_preference_init_bool, handle_preference_update_bool): new functions. * src/core/prefs.c (meta_prefs_init, change_notify): use the new functions. * src/core/prefs.c (update_*): several of these removed whose only purpose was to receive boolean preferences. * src/core/prefs.c (cleanup_error, get_bool): moved down to make the flow of ideas more obvious. * src/core/prefs.c (maybe_give_disable_workarounds_warning): new function containing duplicated code from elsewhere. * src/core/prefs.c (init_button_layout): only compiled when HAVE_GCONF is not defined. Removed a compiler warning. 2008-02-23 Thomas Thurman <tthurman@gnome.org> * tools/commit-wrangler.py: Print URL of changeset on success. 2008-02-23 Thomas Thurman <tthurman@gnome.org> Refactored handling of enumerated preferences. * src/core/prefs.c (handle_preference_init_enum, handle_preference_update_enum): new functions. (meta_prefs_init, change_notify): use regularised forms and remove old copy-and-pasted code. Also many small similar functions removed which only existed to deal with each kind of enum. Also some amount of correction of which parts were and weren't inside "#ifdef HAVE_GCONF" blocks. 2008-02-21 Mikkel Kamstrup Erlandsen <mikkel.kamstrup@gmail.com> * src/core/constraints.c: Respect requested position on _NET_MOVERESIZE_WINDOW. Closes #448183. 2008-02-18 Matthias Clasen <mclasen@redhat.com> * src/core/window.h: Make skip-taskbar windows appear in the Ctrl-Alt-Tab list. Closes #106249. 2008-02-18 Thomas Thurman <tthurman@gnome.org> * configure.in: if we have libSM and its headers, that means we did find it, not that we didn't. Closes #328210. 2008-02-18 Thomas Thurman <tthurman@gnome.org> * src/core/window.c (warp_grab_pointer): When resizing a window with the keyboard, stay one pixels from the edges so that the cursor remains resting on a window edge even if we escape, whatever side it was on. Closes #436257. 2008-02-17 Thomas Thurman <tthurman@gnome.org> * tools/commit-wrangler.py: added new script to manage commits 2008-02-17 Jim Huang <jserv.tw@gmail.com> * src/core/prefs.c (update_binding): Allow compilation when gconf mode is disabled. Closes #515019. 2008-02-14 Jim Huang <jserv.tw@gmail.com> * src/core/display.c, src/core/util.c: fixups to allow compilation in non-verbose mode. Closes #515152. 2008-02-12 Thomas Thurman <tthurman@gnome.org> * configure.in: Correct help for verbose option name. 2008-02-12 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-branch bump to 2.23.0. 2008-02-12 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.21.21. 2008-02-11 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.21.13 release. 2008-02-04 Thomas Thurman <tthurman@gnome.org> * src/core/compositor.c: only use compositor version if we have a compositor. Closes #514453. 2008-02-04 Thomas Thurman <tthurman@gnome.org> * configure.in, src/ui/ui.c: remove workaround for a problem in GTK 1.3.9(!) which was causing problems. Closes #513737. 2008-01-28 Michael Meeks <michael.meeks@novell.com> * src/core/display.c (meta_display_open), * src/core/compositor.c: fetch & use composite version, for remote screens that don't match the compile system's version. (meta_compositor_manage_screen): bin erroneous FIXME. (add_win): remove common warning churn for (very) transient windows 2008-02-03 Thomas Thurman <tthurman@gnome.org> * tools/patch-wrangler.py: another program I use for maintenance which other people might find useful and which should probably be in svn. Also not very polished. 2008-02-03 Thomas Thurman <tthurman@gnome.org> * test/tokentest/tokentest.c, test/tokentest/tokentest.ini: added new files for a regression test on the tokeniser. (They aren't very polished at the moment and aren't included in the autotools build.) 2008-02-03 Thomas Thurman <tthurman@gnome.org> * configure.in: Post-release bump to 2.21.13. 2008-02-03 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.21.8 release. 2008-02-03 Thomas Thurman <tthurman@gnome.org> * tools/release-wrangler.py: Fix quoting error and added some more error checking. 2008-02-03 Thomas Thurman <tthurman@gnome.org> * tools/release-wrangler.py: basic release script; needs work, but probably good enough for the current unstable release 2008-02-02 Thomas Thurman <tthurman@gnome.org> * src/Makefile.am: core.h is in include, not core. (Last one, I promise.) 2008-02-02 Thomas Thurman <tthurman@gnome.org> * src/Makefile.am: main.h is in include, not core. 2008-02-02 Thomas Thurman <tthurman@gnome.org> * src/Makefile.am: draw-workspace.h is in ui, not core. 2008-02-01 Alex R.M. Turner <armtuk@gmail.com> * src/core/display.c (meta_get_tab_entry_list): Have the list also pull windows that are in other workspaces that have the wm_state_needs_attention flag set * src/core/window.c (meta_window_set_demands_attention): Make windows that are on other workspaces that demand attention that aren't obscured count as being obscured Bug #333548. 2008-01-28 Christian Persch <chpe@gnome.org> * src/core/display.c (convert_property): * src/core/screen.c (meta_screen_calc_workspace_layout): * src/core/xprops.c (meta_prop_get_values): Use G_STRFUNC instead of the deprecated G_GNUC_FUNCTION. Bug #512561. 2008-01-21 Thomas Thurman <tthurman@gnome.org> * src/ui/theme.[ch]: more commenting. 2008-01-18 Thomas Thurman <tthurman@gnome.org> * src/ui/theme.[ch]: some more commenting. 2008-01-16 Thomas Thurman <tthurman@gnome.org> * src/core/bell.c: Correct comment. * src/core/main.c: Correct comment. * src/ui/theme.c: Much commenting; #ifdeffed-out debug code removed. * src/ui/theme.h: Much commenting. 2008-01-13 Thomas Thurman <tthurman@gnome.org> * src/core/bell.c: Commenting. * src/core/main.c: Commenting, and fixing existing comments. 2008-01-12 Thomas Thurman <tthurman@gnome.org> * src/core/main.c: Refactor repeated lines in main() to iterate instead. 2008-01-12 Thomas Thurman <tthurman@gnome.org> * src/core/main.[ch] (meta_get_main_loop): removed as it was never used. * src/core/main.c: lots of comments. * src/core/main.c (version): copyright year is 2008. * src/core/c-screen.[ch], src/core/c-window.[ch]: removed files from Søren's compositor which were removed by the merge with Iain's compositor but reintroduced by the split to separate subdirectories. * src/core/display.c: fix comments. 2008-01-12 Thomas Thurman <tthurman@gnome.org> * src/core/display.c: reinstated missing first character! * Doxyfile: correct reordering of blank fields. 2008-01-12 Thomas Thurman <tthurman@gnome.org> * src/core/display.c: change comments from /*! to /** because the other way makes doxygen think they are Qt comments, which messes up brief descriptions. * Doxyfile: check in so other people can generate documentation too. 2008-01-07 Thomas Thurman <tthurman@gnome.org> * src/core/display.c: further commenting (trying to keep comment addings down to once a day at most so you don't all get spammed too much). 2008-01-07 Thomas Thurman <tthurman@gnome.org> * src/core/main.c (main): g_free is a no-op on nulls; there is no need to test. 2008-01-06 Thomas Thurman <tthurman@gnome.org> * src/core/display.c: Function commenting marathon; more to come. 2008-01-02 Thomas Thurman <tthurman@gnome.org> * src/core/xprops.c (meta_prop_get_cardinal), src/core/compositor.c (timeout_debug): Two really minor coding standards layout tweaks. 2007-12-27 Iain Holmes <iain@gnome.org> * src/core/compositor.c: Don't do anything in meta_compositor_free_window, it doesn't seem to be needed and breaks things very badly. http://bugzilla.gnome.org/show_bug.cgi?id=504876 2007-12-27 Iain Holmes <iain@gnome.org> * src/core/compositor.c: When a window is mapped, don't set damaged to TRUE. Fixes a bug when redrawing shadows. 2007-12-25 Iain Holmes <iain@gnome.org> * src/core/compositor.c: USe the compositor overlay window instead of the root window. 2007-12-21 Paolo Borelli <pborelli@katamail.com> * src/core/core.c (meta_invalidate_default_icons): do not leak list. * src/core/edge-resistance.c (meta_display_compute_resistance_and_snapping_edges): ditto. * src/core/workspace.c (meta_workspace_index): small cleanup in list handling. 2007-12-19 Havoc Pennington <hp@redhat.com> * src/core/display.c (meta_display_open): fix a third warning about %d and long int * src/core/delete.c (io_from_ping_dialog): fix another warning about long int to %d * src/core/compositor.c (meta_compositor_new): fix a warning about long int to %d * src/core/iconcache.c (meta_read_icons): use meta_ui_get_fallback_icons() instead of incorrectly including theme.h * src/ui/ui.c (meta_ui_get_fallback_icons): new function 2007-12-19 Havoc Pennington <hp@redhat.com> * src/ui, src/core, src/include: sort source files into these directories according to which part of the WM they are supposed to be in. In an eventual plan, we should also create src/compositor/render, src/compositor/fallback and move some of the compositor stuff into that. * autogen.sh: require a newer automake, so we don't have to use a recursive build * src/ui/tabpopup.c: put in a hack to make the build temporarily work, want to commit the large rearrangement before fixing this not to include workspace.h or frame.h * src/core/iconcache.c (meta_read_icons): temporarily break this to get the build to work, want to commit the large rearrangement before fixing this file not to include theme.h 2007-12-19 Thomas Thurman <thomas@thurman.org.uk> * configure.in: Post-release bump to 2.21.8. 2007-12-19 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.21.5 release. 2007-12-19 Thomas Thurman <tthurman@gnome.org> * configure.in: print "Subversion" and not "CVS". 2007-12-18 Thomas Thurman <tthurman@gnome.org> * configure.in: compositor enabled by default. 2007-12-18 Iain Holmes <iain@gnome.org> * configure.in, src/theme.c, src/display.c, src/theme.h, src/display.h, src/theme-parser.c, src/compositor.c, src/c-screen.c, src/compositor.h, src/c-screen.h, src/ui.c, src/screen.c, src/ui.h, src/screen.h, src/c-window.c, src/c-window.h, src/theme-viewer.c, src/Makefile.am: Merge compositor branch. 2007-12-14 Thomas Thurman <thomas@thurman.org.uk> * configure.in: Post-release bump to 2.21.5. 2007-12-14 Thomas Thurman <tthurman@gnome.org> * NEWS: 2.21.3 release. 2007-12-11 Thomas Thurman <tthurman@gnome.org> * src/theme-parser.c: remove dead code; closes #501365. 2007-12-08 Thomas Thurman <tthurman@gnome.org> * src/metacity.schemas.in: rewrite long description of /schemas/apps/metacity/general/focus_new_windows because we love the translators really. Closes #474889. 2007-12-08 Matthias Clasen <mclasen@redhat.com> * src/menu.c (meta_window_menu_new): check for null before adding menu; closes #496054. 2007-12-08 Thomas Thurman <tthurman@gnome.org> * src/keybindings.c (meta_display_process_key_event): Recur if the keypress ended a grab, so it can be processed in its own right. Closes #112560. 2007-12-08 Martin Meyer <elreydetodo@gmail.com> * src/theme-parser.c (parse_draw_op_element): Fix typo where wrong variable was checked (reported by Kjartan Maraas). Closes #501362. 2007-11-19 Lucas Rocha <lucasr@gnome.org> * src/main.c (main): try to get the session client ID from DESKTOP_AUTOSTART_ID environment variable in case the --sm-client-id is not used. Closes #498033. 2007-11-17 Thomas Thurman <thomas@thurman.org.uk> * configure.in: Post-release bump to 2.21.3. 2007-11-17 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.21.2 release. 2007-11-17 Benjamin Gramlich <benjamin.gramlich@gmail.com> * src/theme-parser.c (meta_theme_load): make our theme search compliant to the XDG Base Directory Specification. Closes #480026. 2007-11-15 Thomas Thurman <thomas@thurman.org.uk> * src/api.[ch]: remove almost-unused files. * src/colors.[ch]: move the used parts of api.[ch] in here. Closes #496947. 2007-11-13 Peter Bloomfield <pbloomfield@bellsouth.net> * src/window.c: (meta_window_save_user_rect): new helper, saves only unmaximized dimensions, and not when fullscreen. (meta_window_move_resize_internal, meta_window_move_resize_request): use it. (#461927) 2007-11-11 Thomas Thurman <thomas@thurman.org.uk> * configure.in: Post-release bump to 2.21.2. 2007-11-11 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.21.1 release. 2007-11-11 Thomas Thurman <thomas@thurman.org.uk> * src/window.c (meta_window_show): adjust expression which decides whether new windows should not go on top, so that restacking happens only the first time a window is mapped. Thanks to Olav Vitters for pointing out the problem. Re-fixes #486445. 2007-11-11 Alex R.M. Turner <armtuk@gmail.com> * src/tabpopup.c (tab_entry_new, meta_ui_tab_popup_new): Instruct the GtkLabel in the tabpopup to ellipsize text that is too big. Set the maximum window width of the tabpopup to screen_width/4, which seems a sensible size for the popup. 2007-11-09 Elijah Newren <newren gmail com> * src/window.c (meta_window_new_with_attrs): If a window is launched without any kind of launch timestamp, grab the current time and stash it away. When transients of that window are also launched without a timestamp, we can use the stashed timestamp from the parent. Fixes #488468. 2007-11-07 Federico Mena Quintero <federico@novell.com> * src/window-props.c (reload_net_wm_user_time_window): Fix typo; the arguments to meta_window_reload_property_from_xwindow() were reversed. This is why the wm_user_time wasn't getting initialized properly from the _NET_WM_USER_TIME_WINDOW. Fixes part of http://bugzilla.gnome.org/show_bug.cgi?id=488468 2007-11-06 Peter Bloomfield <pbloomfield@bellsouth.net> * src/window.c (meta_window_move_resize_internal): save unmaximized part of client root coords. (#461927) 2007-11-06 Peter Bloomfield <pbloomfield@bellsouth.net> * src/window.c (meta_window_move_resize_internal): do not save client root coords while window is maximized. (#461927) 2007-10-30 iain Holmes <iain@gnome.org> * src/main.c (meta_parse_options): Add --sync option (main): Check if the --sync option was passed on command line. 2007-10-28 Jans Granseuer <jensgr@gmx.net> * src/preview-widget.c (meta_preview_finalize): Free title of preview when the preview is destroyed. Closes #469682. 2007-10-27 Alex R.M. Turner <armtuk@gmail.com> * src/tabpopup.c (tab_entry_new): Truncate the string to max_char_per_title before adding bold tags and fix general flow of function. 2007-10-16 Thomas Thurman <thomas@thurman.org.uk> * src/window.c (window_would_be_covered): new function. * src/window.c (meta_window_show): rewrite assertion not to put window on top in terms of window_would_be_covered(); remove assertion because it's no longer valid; explicitly don't focus windows that shouldn't be focussed; closes #486445. 2007-10-14 Thomas Thurman <thomas@thurman.org.uk> * configure.in: Post-branch bump to 2.21.1. 2007-10-03 Kjartan Maraas <kmaraas@gnome.org> * configure.in: Remove circular dep metacity<->gnomecc. 2007-09-15 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.20.1 2007-09-15 Elijah Newren <newren gmail com> * configure.in: * NEWS: 2.20.0 release 2007-09-15 Elijah Newren <newren gmail com> * src/session.c (warn_about_lame_clients_and_finish_interact): Patch from Alexey Rusakov to prevent a crash on logout with metacity subsequently not being restored in future sessions. Fixes #433253. 2007-09-01 Elijah Newren <newren gmail com> * HACKING: update; cvs->svn & mention GConf needed * MAINTAINERS: Make it match idiotic format requirements (I love you Olav!) 2007-08-07 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.19.89. 2007-08-07 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.19.55 release. 2007-08-06 Thomas Thurman <thomas@thurman.org.uk> If KEY_AUTO_RAISE_DELAY is undefined or non-integer, it is not treated as zero. * src/prefs.c (meta_prefs_init): check type of key, and behave sensibly if it's unexpected. * src/prefs.c (find_and_update_list_binding): remove old comment. 2007-08-03 Frederic Crozat <fcrozat@mandriva.com> * src/delete.c: Fix mangled window title in "Force Quit" dialog when using non-UTF8 locale. Close #462734. 2007-08-02 Thomas Thurman <thomas@thurman.org.uk> Move "close" to bottom of window menu; allow workspace list to appear at any position in the menu. Closes #104026. * src/menu.c (MetaMenuItemType): added new MENU_ITEM_WORKSPACE_LIST item. * src/menu.c (menuitems): reordered "close", added a workspace list. * src/menu.c (menu_item_new): return null for workspace lists. * src/menu.c (meta_window_menu_new): handle workspace lists. 2007-07-31 Thomas Thurman <thomas@thurman.org.uk> * src/window.c (meta_window_show_menu): windows which are always on top have the "stick" menu option insensitive. (#460997). 2007-07-23 Thomas Thurman <thomas@thurman.org.uk> * src/window.h (MetaWindow): Put all bitfields together to help with optimisation. Closes #450271 (for real this time). 2007-07-23 Matthias Clasen <mclasen@redhat.com> * configure.in: * src/Makefile.am: Use the correct directory when installing keybindings. (#454055) 2007-07-22 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.19.55. 2007-07-22 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.19.34 release. 2007-07-22 Rob Bradford <rob@robster.org.uk> Fix a bug where the window can be focused without being raised if the maximize is aborted. Fixes #459027. * src/frames.c (meta_frames_button_press_event, meta_frames_button_release_event): When maximising only focus the window once the button press is released. 2007-07-22 Cosimo Cecchi <anarki@lilik.it> Unset fullscreen is an allowed action where relevant. Fixes #449427. * src/window.c (set_allowed_actions_hint): Separate FULLSCREEN action from RESIZE action. 2007-07-22 Yair Hershkovitz <yairhr@gmail.com> Reverse window buttons and align them to the left for RTL locales. Fixed #92212. * src/prefs.c (button_layout, init_button_layout, update_button_layout): Support reversing and left-aligning of buttons for both Gconf and NO-Gconf modes. * src/main.c (main): Call meta_ui_init() before meta_prefs_init(). meta_prefs_init() check for RTL locales which is initialized in meta_ui_init(). * src/theme.c (meta_frame_layout_calc_geometry): Fixed access to button_layout to stop iterating when getting to a META_BUTTON_FUNCTION_LAST value. 2007-06-23 Thomas Thurman <thomas@thurman.org.uk> * src/window.c (MetaWindow): Put all bitfields together to help with optimisation. Closes #450271. 2007-06-18 Thomas Thurman <thomas@thurman.org.uk> * src/main.c (version): Update copyright year because it was five years out of date. 2007-06-18 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.19.34. 2007-06-18 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.19.21 release. 2007-06-18 Thomas Thurman <thomas@thurman.org.uk> * src/place.c (find_first_fit, meta_window_place): Only open new windows on the current xinerama. Closes #145503, for now. 2007-06-17 Thomas Thurman <thomas@thurman.org.uk> * src/screen.[ch] (meta_screen_apply_startup_properties): return a boolean instead a void, to show whether startup properties were applied. Also some commenting. * src/window-props.c: (reload_net_startup_id): Only activate the window if the startup_id was actually changed. Closes #400167. 2007-06-16 Damien Carbery <damien.carbery@sun.com> * effects.h: MetaCloseEffect and MetaFocusEffect, which were empty structs, #ifdeffed out because they broke the build on Solaris. Closes #397296. 2007-06-16 Damien Carbery <damien.carbery@sun.com> * window.h: make prototype of meta_window_unqueue match implementation. Closes #446535. 2007-06-10 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.19.21. 2007-06-10 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.19.13 release. 2007-06-10 Thomas Thurman <thomas@thurman.org.uk> Refactor thrice-duplicated queue code in window.c. Closes #376760. * src/window.c (meta_window_queue, meta_window_unqueue): New functiortl.patchns. * src/window.[ch] (meta_window_unqueue_*, meta_window_queue_*): Removed functions. * src/window.c (meta_window_new_with_attrs, meta_window_free, meta_window_flush_calc_showing, queue_calc_showing_func, meta_window_minimize, meta_window_unminimize, meta_window_maximize, meta_window_make_fullscreen, meta_window_shade, meta_window_unshade, meta_window_move_resize_internal, window_stick_impl, window_unstick_impl, meta_window_client_message, process_property_notify): Modified to use new queueing functions. * src/window.c (idle_move_resize, idle_update_icon, idle_calc_showing): update to receive queue number from pointer. * src/window.h (MetaQueueType): new enum. * src/window.h (MetaWindow): *_queued replaced with is_in_queue bitfield. * src/core.c (meta_core_queue_frame_resize): * src/display.c (event_callback, meta_display_queue_retheme_all_windows): Using new queueing functions. * src/frame.c (meta_window_destroy_frame): Using new queueing functions. * src/screen.c (queue_resize, meta_screen_resize_func, queue_windows_showing): Using new queueing functions. * src/window-props.c (reload_mwm_hints, reload_wm_hints, reload_transient_for): Using new queueing functions. * src/workspace.c (meta_workspace_add_window, meta_workspace_remove_window, meta_workspace_queue_calc_showing, meta_workspace_invalidate_work_area): Using new queueing functions. 2007-06-09 Thomas Thurman <thomas@thurman.org.uk> * src/50-metacity-key.xml.in: added switch_group; closes #444879. 2007-06-08 Elijah Newren <newren gmail com> * src/metacity.schemas.in: Update the raise_on_click description to try to prevent misuses, to appropriately warn users, and to stop wasting the time of application developers. #445447, #389923 2007-06-06 Thomas Thurman <thomas@thurman.org.uk> * frames.c, core.[ch]: changed all tabs to spaces. * core.[ch] (meta_core_get_client_size, meta_core_window_has_frame, meta_core_titlebar_is_onscreen, meta_core_get_client_xwindow, meta_core_get_frame_flags, meta_core_get_frame_type, meta_core_get_mini_icon, meta_core_get_icon, meta_core_get_position, meta_core_get_size, meta_core_get_frame_workspace, meta_core_get_frame_extents, meta_core_get_screen_size): Removed and replaced with meta_core_get(). * core.[ch] (meta_core_get): New function. * core.h (MetaCoreGetType): New enum. * frames.c (meta_frames_ensure_layout, meta_frames_calc_geometry, meta_frames_get_geometry, meta_frames_apply_shapes, meta_frame_titlebar_event, meta_frames_button_press_event, populate_cache, clip_to_screen, meta_frames_paint_to_drawable, meta_frames_set_window_background, get_control): Replace use of removed functions in ui.c with meta_core_get(). All this should make things a little faster. Closes #377495. 2007-06-04 Thomas Thurman <thomas@thurman.org.uk> * NEWS: Added translators' names from 2.19.8 (sorry, folks: I forgot to save NEWS with their names in it before shipping.) 2007-06-04 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.19.13. 2007-06-04 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.19.8 release. 2007-06-04 Thomas Thurman <thomas@thurman.org.uk> * src/metaaccellabel.c (meta_accel_label_expose_event): fix label layout for RTL languages. Closes #433400. 2007-06-03 Thomas Thurman <thomas@thurman.org.uk> * src/frames.c (meta_frames_ensure_layout): Pango layout for titlebars should take LTR/RTL-ness from the underlying widget and not from sniffing the content. Closes #438944. 2007-05-25 Yair Hershkovitz <yairhr@yahoo.com> * src/workspace.c (meta_workspace_get_neighbor): Add support for RTL languages so that alt-tab, etc., go the other way. * src/keybindings.c (handle_activate_menu): In RTL locales, pop up the menu on the right-hand side when the menu keystroke is pressed. * src/fixedtip.c (meta_fixed_tip_show): right-justify tooltips in RTL locales. * src/menu.c (popup_position_func): popup menus in RTL locales are flush with the right-hand side of the window where possible. * src/frames.c (show_tip_now, meta_frames_button_press_event): tooltips are aligned with the right-hand side of buttons in RTL locales. * src/ui.[ch] (meta_ui_get_direction, enum MetaUIDirection): New content. * src/window.c (meta_window_show_menu): "move left" appears above "move right" in the window menu for LTR locales, and vice versa for RTL locales. This is all to close bug #387893. 2007-04-24 Linus Torvalds <torvalds@woody.linux-foundation.org> * src/prefs.[ch] (init_action_meta_prefs, meta_prefs_init, action_change_titlebar, change_notify, update_action_titlebar, meta_preference_to_string): Add code to configure what happens when the titlebar is right or middle clicked as well as double clicked. 2007-04-23 Elijah Newren <newren gmail com> * configure.in: post-release bump to 2.19.8. 2007-04-23 Elijah Newren <newren gmail com> * NEWS: 2.19.5 release. 2007-04-23 Elijah Newren <newren gmail com> Fix some uninitialized memory usage errors. #427385 * src/frame.c (meta_window_ensure_frame): * src/frames.c (meta_frames_manage_window): Do not try to set the window background in meta_frames_manage_window() since the frame window is not yet created and not yet registered with the corresponding MetaWindow. Do it inside meta_window_ensure_frame() instead. 2007-04-17 Elijah Newren <newren gmail com> Fix some fallout from #426519; update user_rect for all position changes prior to the window being marked as placed. Prevents emacs in particular from flickering on start and always being shoved to the upper-left corner. * src/window.c (meta_window_move_resize_internal): Record position in user_rect if the window is not yet marked as placed too * src/window.c (struct MetaWindow, meta_window_new_with_attrs, meta_window_move_resize_internal): Remove window->user_has_move_resized; it's not needed or used anymore. * src/window.[ch] (meta_window_get_user_position): Remove this function as it is no longer needed or used. 2007-04-16 Elijah Newren <newren gmail com> Prevent metacity from "forgetting" which machine a window is on. #418552 * src/window.c (meta_window_new_with_attrs): reorder the property loading so that we know the wm_client_machine when we load the name of the window and can modify the window name accordingly. 2007-04-16 Elijah Newren <newren gmail com> * configure.in: post-release bump to 2.19.5. 2007-04-16 Elijah Newren <newren gmail com> * NEWS: 2.19.3 release. 2007-04-15 Elijah Newren <newren gmail com> Preserve stacking order across restarts. * src/display.c (meta_display_unmanage_windows_for_screen): unmap windows in stacking order so that stacking is preserved upon shutdown * src/display.[ch] (meta_display_stack_cmp): * src/session.c (stack_cmp, save_state): rename stack_cmp() -> meta_display_stack_cmp() and move it to a different function so that it can be used in both session.c:save_state() and meta_display_unmanage_windows_for_screen() 2007-04-15 Elijah Newren <newren gmail com> Remove incorrect usage of window.h from menu.c. See #426791 & #382962. * src/menu.c (enum MetaMenuItemType, variable menuitems, meta_menu_item_new): cleanup: add a MENU_ITEM_RADIOBUTTON for the sticky stuff * src/menu.c (variable menuitems): * src/core.c (meta_core_get_menu_accelerator): * src/window.c (menu_callback, meta_window_show_menu): * src/common.h (enum MetaMenuOp): reinstate META_MENU_OP_UNABOVE * src/menu.c (meta_window_menu_new): remove hacks (using inappropriate data) for STICK/UNSTICK/ABOVE and clean it up while just setting STICK/UNSTICK activeness as necessary * src/menu.[ch] (meta_window_menu_new): * src/ui.[ch] (meta_ui_window_menu_new): make the active_workspace parameter an unsigned long 2007-04-15 Bruno Boaventura <brunobol@gnome.org> * src/menu.c (meta_window_menu_new): don't show the current workspace as a possible workspace to switch to. Fixes #426791. 2007-04-12 Elijah Newren <newren gmail com> * src/place.c (meta_window_place): do not auto-maximize windows larger than the workarea in only a single direction. Fixes #419810. 2007-04-11 Elijah Newren <newren gmail com> Make sure apps have correct info about their coordinates, even on unmap. Fixes temporary hang with libXt (XtVaSetValues setting x & y coordinates). #399552. * src/frame.c (meta_window_destroy_frame): Add a comment noting that the current choice causes the need for a ConfigureNotify event * src/window.c (meta_window_free): Send a configure notify event due to our XReparentWindow coordinate choices on withdrawal, (unmaximize_window_before_freeing): no need to send a configure notify from here since it is always done in meta_window_free new, (send_configure_notify): have to special case the coordinates used when withdrawing the window 2007-04-11 Thomas Thurman <thomas@thurman.org.uk> Workaround for a gdk bug which dies with BadAlloc if you try to allocate an insanely huge rectangle for an insanely huge window. Fixes #399529. 2007-04-11 Elijah Newren <newren gmail com> Advertise support of Above and Below operations (assuming the proposed EWMH additions of _NET_WM_ACTION_(ABOVE|BELOW) will be accepted, otherwise these changes will have to be modified). Part of #115247. * src/display.[ch] (meta_display_open, struct MetaDisplay): * src/screen.c (set_wm_check_hint): Add support for _NET_WM_ACTION_ABOVE and _NET_WM_ACTION_BELOW * src/window.c (set_allowed_actions_hints): add active_above and action_below 2007-04-10 Elijah Newren <newren gmail com> * src/window.c (recalc_window_features): make sure to set _NET_WM_ALLOWED_ACTIONS so that libwnck menus don't have sensitive but ineffective menu items. The "On Top" item is now buggy, but due to the fact that _NET_WM_ACTION_ABOVE is not yet defined in the EWMH. Fixes #115247. 2007-04-09 Elijah Newren <newren gmail com> Add support for _NET_MOVERESIZE_WINDOW. Based on patch from Magnus Therning. #344521. * src/display.c (handle_net_moveresize_window, event_callback): Remove handle_net_moveresize_window() and the call to it; this code was highly buggy, though to be fair it was never tested and had simply been put into the code in commented out form. * src/screen.c (set_supported_hint): add atom_net_moveresize_window * src/window.[ch]: (meta_window_configure_request, meta_window_move_resize_request): Split out the moving/resize part of the configure request and put it into meta_window_move_resize_request (meta_window_client_message): check for NET_MOVERESIZE_WINDOW messages and call meta_window_move_resize_request() with the appropriate parameters to handle them (meta_window_move_resize_internal): fix some of the big comment at this function -- it wasn't quite right, use the passed in gravity instead of window->size_hints.win_gravity when calling adjust_for_gravity() to make sure the correct adjustments are used. (meta_window_get_gravity_position, meta_window_get_geometry, meta_window_move_resize_request): add a gravity parameter to meta_window_get_gravity_position and have it use that gravity instead of window->size_hints.win_gravity 2007-04-09 Elijah Newren <newren gmail com> * configure.in: post-release bump to 2.19.3. 2007-04-09 Elijah Newren <newren gmail com> * NEWS: 2.19.2 release. 2007-04-08 Elijah Newren <newren gmail com> Remove grab_start_serial, which we expect to be an ancient attempt to workaround sloppy/mouse focus bugs that have since been correctly fixed. May fix some race conditions. May cause nasty bugs in sloppy/mouse focus modes. We'll find out soon enough... See #304430. * src/display.c (event_callback): remove event->xany.serial >= display->grab_start_serial in several event callback handlers * src/display.[ch] (struct _MetaDisplay, meta_display_begin_grab_op): * src/keybindings.c (do_choose_window, handle_workspace_switch): * src/frames.c (meta_frames_button_press_event): * src/core.[ch] (meta_core_begin_grab_op): * src/window.c (meta_window_client_message, meta_window_begin_grab_op): don't require an event_serial to be passed to meta_display_begin_grab_op () and don't record it anymore. * src/ui.c (struct _EventFunc, filter_func, meta_ui_get_last_event_serial) * src/core.h (meta_ui_get_last_event_serial): remove meta_ui_get_last_event_serial() function (don't ask me why it was declared in core.h) and the last_even_serial field of _EventFunc 2007-04-08 Elijah Newren <newren gmail com> Fix move/resize events in relation to combinations of ConfigureRequest and WM_NORMAL_HINTS change notifications (plus a few code cleanups). Fixes #426519. * src/window.c (meta_window_move_resize_now): move to the user_rect position, not some weird combination of rect and user_rect * src/window.c (meta_window_configure_request): set user_rect in response to ConfigureRequest events (after the ConfigureRequest values have been constrained) and add a big comment explaining this change, remove unused only_resize variable and irrelevant huge FIXME comment about it * src/window.[ch] (meta_window_get_client_root_coords): new function * src/display.c (meta_display_begin_grab_op): * src/keybindings.c (process_keyboard_move_grab): * src/window.c (meta_window_unmaximize, meta_window_move_resize_internal, meta_window_begin_wireframe, update_move, meta_window_refresh_resize_popup, warp_grab_pointer) combine multi-step client rect root coord setting into a single function call to meta_window_get_client_root_coords() 2007-04-08 Thomas Thurman <thomas@thurman.org.uk> * ChangeLog: removed conflict line. 2007-04-07 Elijah Newren <newren gmail com> * src/prefs.[ch] (screen_bindings array, META_KEYBINDING_SET_SPEW_MARK definition): * src/keybindings.c (handle_spew_mark, screen_handlers array): Add an (unbound by default) keybinding for setting spew marks in verbose debugging logs. I'm not sure why this was ever removed; I've wanted it so many times. * HACKING: valgrind wants --log-file not --logfile. 2007-04-07 Elijah Newren <newren gmail com> * src/window.c (meta_window_free): Fix memory bug (invalid free) introduced in 2007-04-02 strut cleanup commit. Part of #427385. 2007-04-05 Thomas Thurman <thomas@thurman.org.uk> * src/theme_parser.c: if theme is invalid and therefore got freed, don't attempt to read from it. Closes #423855. 2007-04-05 Bastien Nocera <hadess@hadess.net> * src/50-metacity-desktop-key.xml.in: * src/50-metacity-key.xml.in: * src/Makefile.am: Add new control-center key bindings definitions (Closes: #420145) 2007-04-04 Elijah Newren <newren gmail com> * configure.in: post-release bump to 2.19.2. 2007-04-04 Elijah Newren <newren gmail com> * NEWS: 2.19.1 release. 2007-04-04 Elijah Newren <newren gmail com> * src/window.c (meta_window_move_resize_internal): send synthetic configurenotify events also in response to MapRequest events when the window has a frame and the application specifies PPosition or UPosition hints. I believe they are already sent for all other cases. Should fix #322840. Fixes the testcase at least. :) 2007-04-04 Elijah Newren <newren gmail com> Fix lots of little issues with min/max constraints and size increment constraints. Fixes #329152, #418395, and possibly others. * src/window-props.c (meta_set_normal_hints): Do more checking to make sure application specified constraints are self-consistent, modifying the size_hints as necessary to achieve self-consistency. * src/constraints.c (setup_constraint_info): remove ugly copy-pasto, (constrain_size_increments): be careful that fixing violation of the constraints doesn't cause a violation of the minimum size constraints. * src/window.c (ensure_size_hints_satisfied): new function, (meta_window_unmaximize, meta_window_unmake_fullscreen): the saved_rect may no longer be valid (as in the case of #329152) so call ensure_size_hints_satisfied to fix it up. * doc/how-to-get-focus-right.txt: Some minor spacing and wording fixes completely unrelated to the rest of this commit 2007-04-03 Elijah Newren <newren gmail com> * src/window.c (meta_window_unmaximize): Only use saved_rect for determining the position to unmaximize to for the previously-maximized direction(s). Fixes #355497. 2007-04-03 Elijah Newren <newren gmail com> * MAINTAINERS: Update. #412319. 2007-04-03 Elijah Newren <newren gmail com> * src/display.c (meta_display_update_active_window_hint): _NET_ACTIVE_WINDOW is a single xwindow id, not two. 2007-04-03 Elijah Newren <newren gmail com> * src/keybindings.c (handle_panel_keybinding): turn mouse_mode off to prevent focus issues with the run application dialog. Fixes #374752. 2007-04-03 Elijah Newren <newren gmail com> Avoid some crashes when dragging windows partially offscreen. Possible (or at least partial) fix for #353513. * src/edge-resistance.c (apply_edge_resistance): be more careful about calls to find_index_of_edge_near_position() returning possibly invalid indices. Also, add a warning comment to find_index_of_edge_near_position(). 2007-04-03 Elijah Newren <newren gmail com> Patch from Carlo Wood to do some miscellaneous code cleanups found while working on #358311. * src/constraints.c (do_screen_and_xinerama_relative_constraints): nicer way of avoiding compilation warning * src/boxes.c (meta_rectangle_clamp_to_fit_into_region, meta_rectangle_clip_to_region, meta_rectangle_shove_into_region): Much cleaner way of ignoring invalid boxes in comparisons 2007-04-02 Elijah Newren <newren gmail com> Patch from Carlo Wood to fix handling of unidirectional maximization and partial struts. #358311. * src/constraints.c (constrain_maximization): determine target size for unidirectionally maximized windows by determining how far they can be maximized without hitting orthogonal struts. Avoids weird "empty spaces". * src/boxes.[ch] (meta_rectangle_expand_to_avoiding_struts): new function 2007-04-02 Elijah Newren <newren gmail com> Make the strut lists (stored in workspaces) record both the rectangle and the side that the strut is on. Lots of code cleanups relating to struts. * src/boxes.h (struct MetaStrut): new struct for struts * src/window.[ch] (struct MetaStruts, struct MetaWindow, meta_window_update_struts): overhaul to make window's struts remember their side as well as their rectangular location, and just use a list instead of several copies of near-identical code for left/right/top/bottom (allowing us to nuke MetaStruts struct as well) * src/testboxes.c (new_meta_strut, get_strut_list): * src/workspace.c (ensure_work_areas_validated): * src/boxes.c (meta_rectangle_get_minimal_spanning_set_for_region, meta_rectangle_expand_to_avoiding_struts, get_disjoint_strut_rect_list_in_region, fix_up_edges, meta_rectangle_find_onscreen_edges, meta_rectangle_find_nonintersected_xinerama_edges): modify to handle struts being rectangle + side instead of just rectangle * src/workspace.c (ensure_work_areas_validated): simplify strut list creation considerably given MetaWindow change, modify work_area computations to take advantage of region computations being done (makes the code shorter as well as more robust against pathological cases). * src/util.[ch] (meta_free_gslist_and_elements): new convenience function * src/common.h (enum MetaDirection): * src/edge-resistance.c (movement_towards_edge): * src/boxes.c (meta_rectangle_edge_aligns, rectangle_and_edge_intersection, split_edge): Add more MetaDirection fields for convenience * src/boxes.h (enum FixedDirections): * src/constraints.c (setup_constraint_info, place_window_if_needed): add a FIXED_DIRECTION_NONE to the FixedDirections enum to make code more clear 2007-04-01 Bruno Boaventura <brunobol@gnome.org> * src/theme.c (kill_window_question): Fallback to NORMAL state after checking for the middle button. Fixes bug #419043. Patch from Benjamin Berg <benjamin@sipsolutions.net>. 2007-03-31 Elijah Newren <newren gmail com> Clean up event mask handling and meta_create_offscreen_window, to prevent nasty metacity/gdk interactions causing hangs. See #354213. * src/screen.[ch] (meta_create_offscreen_window): * src/display.c (meta_display_open): * src/screen.c (meta_screen_new): Add a valuemask parameter to meta_create_offscreen_window * src/display.c (meta_display_open): make it explicit that we can't rely on PropertyNotify events for the leader_window due to nasty metacity/gdk interaction * src/session.c (warn_about_lame_clients_and_finish_interact): remove cut-and-paste code for timestamp pinging and just call meta_display_get_current_time_roundtrip 2007-03-30 Elijah Newren <newren gmail com> Add support for _NET_WM_USER_TIME_WINDOW in order to cut down on context switches. Fixes #354213. * src/display.c (meta_display_open): * src/display.h (struct _MetaDisplay): * src/screen.c (set_supported_hint): new atom * src/display.c (meta_display_open, meta_display_get_current_time_roundtrip): * src/display.h (struct _MetaDisplay): create a dedicated timestamp pinging window instead of reusing display->leader_window * src/display.c (event_callback): * src/window-props.c (reload_net_wm_user_time_window): * src/window.c (meta_window_new_with_attrs, meta_window_free, process_property_notify): * src/window.h (struct _MetaWindow): monitor property notify events on _NET_WM_USER_TIME_WINDOW windows too * src/window-props.[ch]: new meta_window_reload_propert(y|ies)_from_xwindow() functions * src/window-props.[ch] (init_net_wm_user_time_window, reload_net_wm_user_time_window, meta_display_init_window_prop_hooks): * src/window.c (meta_window_new_with_attrs): new hooks to handle new atom 2007-03-26 Josselin Mouette <joss@malsain.org> * src/session.c (meta_session_init): if previous client ID was supplied, use it in filename. * src/session.c (set_clone_restart_commands): use --sm-client-id in command line to restore session, not original file name. * src/session.c (regenerate_save_file): generate filename using client ID and not original file name. * src/session.c (base_save_file): removed function. Closes GNOME 407981, Debian 391287, Debian 315169. 2007-03-25 Elijah Newren <newren gmail com> * configure.in: bump version to 2.19.1; doesn't make sense to have the development version have a version number less than the stable version. ;-) 2007-03-20 Arthur Taylor <theycallhimart@gmail.com> * src/frames.c (meta_frames_apply_shapes): adjusted the rounded corners so that they fit nicely with the arcs around them. Fixes #399373. 2007-03-17 Kjartan Maraas <kmaraas@gnome.org> * src/ui.c: Remove #include <pango/pangox.h> since it's apparently not installed anymore. Builds just fine without it too. 2007-03-10 Charlie Brej <cbrej@cs.man.ac.uk> * src/metacity.schemas.in: add action_{middle|right}_click_titlebar. Closes #408903. 2007-03-09 Linus Torvalds <torvalds@woody.linux-foundation.org> * src/frames.c (meta_frame_middle_click_event, meta_frame_right_click_event): honour preferences. * src/prefs.[ch] (meta_prefs_get_action_middle_click_titlebar, meta_prefs_get_action_right_click_titlebar): new functions. 2007-02-20 Kjartan Maraas <kmaraas@gnome.org> * Makefile.am: Add MAINTAINERS to EXTRA_DIST so others can find out where to send patches. Hi Linus :-) 2007-02-17 Linus Torvalds <torvalds@woody.linux-foundation.org> * src/common.h (MetaActionTitleBar): renamed from MetaActionDoubleClickTitleBar; added _LOWER and _MENU. * src/frames.c (meta_frame_titlebar_event): renamed enums as above; added code to handle _LOWER and _MENU, which is moved in from meta_frame_{middle|right}_click_event. * src/frames.c (meta_frame_middle_click_event, meta_frame_right_click_event): rewrote in terms of meta_frame_titlebar_event. * src/prefs.c: removed "DoubleClick" from names as above. * src/prefs.c (action_titlebar_from_string): added cases for "lower" and "menu". Fixes #408902. 2007-02-17 Linus Torvalds <torvalds@woody.linux-foundation.org> * src/frames.c (meta_frames_button_press_event): Split out code for different kinds of click into separate functions. Fixes #408899. * src/frames.c (meta_frame_titlebar_event, meta_frame_double_click_event, meta_frame_middle_click_event, meta_frame_right_click_event): new functions. 2007-01-27 Bruno Boaventura <brunobol@gnome.org> * src/metacity-dialog.c (kill_window_question): Change dialog icon because gnome-icon-theme have no more "panel-force-quit". Patch from Jaap A. Haitsma <jaap@haitsma.org>. 2007-01-16 Thomas Thurman <thomas@thurman.org.uk> * doc/compositor-control.txt: fix silly thinko. 2007-01-16 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.17.8. 2007-01-16 Thomas Thurman <thomas@thurman.org.uk> * doc/compositor-control.txt: New file. 2007-01-16 Thomas Thurman <thomas@thurman.org.uk> * src/compositor.c (meta_compositor_new): Removed #ifdef SPIFFY_COMPOSITOR throughout the file. Replaced with check for environment variable METACITY_BLING, which may be temporary. 2007-01-13 Bruno Boaventura <brunobol@gnome.org> * src/frames.c (meta_frames_motion_notify_event): Unmaximize button must keep preesed appearence when clicked (hold down), move off, and back over the button. Fixes #395560. Patch from Mad Alex <madalexonline@yahoo.co.uk>. 2007-01-02 Thomas Thurman <thomas@thurman.org.uk> * src/c-screen.c (meta_comp_screen_redirect): Remove double unref of stacker object. Fixes #387761. 2006-12-27 Bruno Boaventura <brunoboaventura@gmail.com> Move "On Top" option in menu. Fix #382962. * src/common.h, src/core.c: Remove META_MENU_OP_UNABOVE. * src/menu.c: remove unabove menu item and put above item next "Always on Visible Viewport". * src/window.c: remove handles of META_MENU_OP_UNABOVE. 2006-12-21 Thomas Thurman <thomas@thurman.org.uk> * src/compositor.c: Disabled bling for now; added function for handling CirculateNotify XEvent; some commenting. * src/compositor.h, src/c-window.c: fix function prototype visibility. 2006-12-12 Thomas Thurman <thomas@thurman.org.uk> * src/compositor.c (do_effect): Sanity check to avoid dereferencing a null pointer. 2006-12-10 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.17.5. 2006-12-10 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.17.3 release. 2006-12-05 Christof Krüger <mail@pop2wap.net> * src/window.c (update_move): Fix flickering about when dragging maximised windows between xineramas. Closes #358715. 2006-12-03 Federico Mena Quintero <federico@novell.com> Fix http://bugzilla.gnome.org/show_bug.cgi?id=381127: * src/window.c (idle_calc_showing): Grab the server while the windows are being shuffled. First show the windows to be shown, and then hide the windows to be hidden, in order to minimize the number of expose events. 2006-11-15 Bruno Boaventura <brunoboaventura@gmail.com> 2006-11-15 Björn Lindqvist <bjourne@gmail.com> * src/menu.c: added MetaMenuItemType enum; added it to MenuItem; added values of this type to menuitems array. * src/menu.c (menu_item_new): rewrite to take a MenuItem instead of a set of parameters describing the menu item. * src/menu.c (meta_window_menu_new): use proper checkboxes or radio buttons on the window menu. (#343108) * src/window.c (meta_window_show_menu): unstick and stick are always shown. 2006-11-06 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.17.3. 2006-11-06 Thomas Thurman <thomas@thurman.org.uk> * configure.in: pre-release bump to 2.17.2. * NEWS: 2.17.2 release. 2006-11-05 Priit Laes <amd@store20.com> * src/main.c, src/ui.c: remove deprecated gtk stuff. 2006-11-05 Bruno Boaventura <brunoboaventura@gmail.com> * src/theme.c, src/testgradient.c: remove deprecated gtk stuff. 2006-11-05 Kjartan Maraas <kmaraas@gnome.org> * src/ui.c: use g_strdup to allocate a string, not strdup. Fixes #363354. * src/metacity-dialog.c: add missing spaces to string. Fixes #363355. 2006-11-05 Justin Mason <jm@jmason.org> * src/keybindings.c: implement handle_move_to_{side|corner}_* to allow the user to flip a window to the side or corner of the screen. Fixes #317884. * src/prefs.h: keybindings for the above. * src/metacity.schemas.in: keybindings for the above. 2006-11-05 Elijah Newren <newren gmail com> * src/frames.c: improved rounding of rounded corners. Fixes #360542, mostly. 2006-10-30 Dan Mick <dan.mick@sun.com> * src/window.c: (__window_is_terminal): Fix strict focus mode by picking up on res_class. Fixes #361054, strict focus mode still not working; should look for res_class, not res_name 2006-10-16 Elijah Newren <newren gmail com> * NEWS: 2.17.1 release. 2006-10-13 Carlo Wood <carlo@alinoe.com> Fix cases when titlebar is allowed offscreen and shouldn't be (and vice-versa). #333995. * src/display.[ch] (struct _MetaDisplay): add grab_frame_action member * src/display.[ch] (meta_display_begin_grab_op): * src/window.[ch] (meta_window_begin_grab_op): * src/core.[ch] (meta_core_begin_grab_op): Add frame_action parameter (core & window versions pass it on to display) * src/display.c (event_callback): * src/window.c (meta_window_begin_grab_op, meta_window_client_message, menu_callback): * frames.c (meta_frames_button_press_event): * keybindings.c (do_choose_window, handle_begin_move, handle_begin_resize, handle_workspace_switch): Pass whether the action should be considered a 'frame_action', which will be used to determine whether to force the titlebar to remain onscreen, to meta_*_begin_grab_op * constraints.c (constrain_titlebar_visible): Replace previous ugly hack by using grab_frame_action (and whether the action is a user action) to determine whether to enforce the titlebar_visible constraint. 2006-10-10 Elijah Newren <newren gmail com> * src/draw-workspace.c (draw_window, wnck_draw_workspace): Patch from Bruno Boaventura to sync metacity workspace previews with libwnck. #341893 2006-10-07 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.17.1. 2006-10-07 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.17.0 release. 2006-10-07 Thomas Thurman <thomas@thurman.org.uk> * src/themes/Crux/metacity-theme-2.xml: removed hide_buttons. Closes #360498. 2006-10-07 Thomas Thurman <thomas@thurman.org.uk> * MAINTAINERS: added myself. 2006-10-07 Thomas Thurman <thomas@thurman.org.uk> * doc/theme-format.txt: described new theme format. * src/themes/Bright, src/themes/Crux: added version 2 themes. 2006-10-07 Thomas Thurman <thomas@thurman.org.uk> * common.h: Added "above" to the list of flags a frame can have, so that we know when to mark it as always on top. Added six grab ops, one to do and one to undo each of the three new titlebar buttons (shade, above, stick). Added six new button functions, similarly. (#96229) * frame.c (meta_frame_get_flags): If a frame has the WM_STATE_ABOVE X attribute, set META_FRAME_ABOVE in its flags. * frames.c (meta_frames_apply_shapes): Allow variable amounts of rounding. (#113162) * frames.c (show_tip_now, meta_frames_paint_to_drawable, control_rect, get_control): extend handling of existing buttons to the 3*2 new kinds of button. (#96229) * frames.c (meta_frames_button_press_event): translate clicks on the 3*2 new kinds of button to the new grab ops. (#96229) * frames.c (meta_frames_button_release_event): implement the various actions for the 3*2 new kinds of button. (#96229) * frames.c (meta_frames_update_prelit_control, meta_frames_motion_notify_event): extend existing motion notifications for buttons to the 3*2 new kinds of button. (#96229) * frames.c (meta_frames_set_window_background): handle specified background colours and alpha transparency. (#151261) * frames.h (MetaFrameControl): New control types for the 3*2 new kinds of button. (#96229) * iconcache.[ch] (meta_read_icons): use theme's fallback icons if a window has no icon; use metacity's fallback icons only if the theme does not provide any. (#11363) * iconcache.[ch] (meta_invalidate_default_icons (new function)): clear icon cache on windows using default icons, and update them. (#11363) * main.c (main): added \n to error message. * prefs.c (button_function_from_string): extend for 3 new button types. (#96229) * prefs.c (button_opposite_function (new function)): return a button function's inverse (shade -> unshade, etc) (#96229) * prefs.c (update_button_layout): allocate space for a button's inverse, if it has one. (#96229) * theme-parser.c (ParseState): add state for fallback icons (#11363) * theme-parser.c (ParseInfo): add format_version; remove menu_icon_* (#114305) * theme-parser.c (parse_positive_integer): add lookup for integer constants (#331356) * theme-parser.c (parse_rounding (new function)): parse window rounding amount (#113162) * theme-parser.c (parse_alpha): don't set error if the number can't be parsed since it'll already be set; change tolerance in comparison from 1e6 to 1e-6 * theme-parser.c (parse_color (new function)): parse colour, including possible constant lookup. * theme-parser.c (parse_toplevel_element): allow defining of various new kinds of constant; allow hide_buttons (#121639) and more detailed rounding attributes on <frame_geometry> (#113162); allow background and alpha attributes on <frame_style>; (#151261) remove support for <menu_icon> except as stub; (#114305) add support for loading stock images (#113465); add support for <fallback>. (#11363)) * theme-parser.c (parse_draw_op_element): add from and to attribute for arcs. (#121603) * theme-parser.c (parse_style_element): add check for theme version supporting a button function. (#96229) * theme-parser.c (parse_style_set_element): add ability for shaded windows to be resizable (#114304) * theme-parser.c (meta_theme_load): add theme versioning routine. * theme.c ( meta_frame_layout_get_borders): return rectangles for the new 3*2 kinds of button, except where they're inapplicable. (#96229) * theme.c (meta_frame_layout_calc_geometry): don't format buttons on windows with no buttons (#121639); strip the 3*2 new kinds of button correctly (#96229); allow variable amounts of rounding (#113162). * theme.c (meta_frame_style_new): set alpha to 255 by default. (#151261) * theme.c (meta_frame_style_unref): free colour spec if allocated. (#151261) * theme.c (meta_frame_style_validate): it's only an error not to include a button if that button is valid in the current theme. (#96229) * theme.c (button_rect): return rectangles for the new 3*2 kinds of button. (#96229) * theme.c (meta_frame_style_set_unref): free differently resizable shaded styles. (#114304) * theme.c (get_style): look up differently resizable styles for shaded windows. (#114304) * theme.c (free_menu_ops (removed function), get_menu_icon (removed function), meta_theme_draw_menu_icon (removed function), meta_menu_icon_type_from_string (removed function), meta_menu_icon_type_to_string (removed function), meta_theme_free, meta_theme_validate): removed menu icon code. (#114305) * theme.c (meta_theme_load_image): add size_of_theme_icons parameter. (#113465) * theme.c (meta_theme_define_color_constant (new function), meta_theme_lookup_color_constant (new function)): allow definition of colour constants. (#129747) * theme.c (meta_button_type_from_string, meta_button_type_to_string): add the 3*2 new kinds of button. (#96229) * theme.c (meta_theme_earliest_version_with_button (new function)): return the theme version each button was introduced in. (#96229) * theme.h ( MetaFrameLayout): add "hide_buttons" flag (#121639) and corner radiuses. (#113162) * theme.h (MetaFrameGeometry): add rectangles for the 3*2 new buttons. (#96229) * theme.h (MetaButtonType): the 3*2 new buttons. (#96229) * theme.h (MetaFrameStyle): add window_background_color and window_background_alpha so that we can specify background on a <frame_style>. (#151261) * theme.h (MetaFrameStyleSet): shaded_styles gets resize dimension. (#114304) * theme.h (MetaTheme): added format_version, color_constants hash, (#129747) fallback_icon and fallback_mini_icon, (#11363) and removed menu_icons. (#114305) * theme.h (META_THEME_ALLOWS (new macro)): return whether a theme supports a given feature. Also, several macros representing new features in v2. * ui.c (meta_ui_set_current_theme)): also invalidate default icons. (#11363) * window.[ch] (meta_window_update_icon_now)): became non-static. (#11363) 2006-10-06 Elijah Newren <newren gmail com> * src/metacity-dialog.c (kill_window_question): Be nice to translators; remove unnecessary markup from strings marked for translation (oops, I missed this in my review before previous commit) 2006-10-06 Elijah Newren <newren gmail com> * src/metacity-dialog.c (kill_window_question): Patch from Bruno Boaventura to improve the "Force Quit" dialog. #121936 2006-10-02 Elijah Newren <newren gmail com> Ignore edge resistance for size-increment windows when resizing with the keyboard. #346782. * src/edge-resistance.c (apply_edge_resistance_to_each_side): ignore edge resistance for size-increment windows when resizing with the keyboard, (apply_edge_resistance_to_each_side, meta_window_edge_resistance_for_move, meta_window_edge_resistance_for_resize): pass a is_resize parameter as well 2006-10-01 Elijah Newren <newren gmail com> * src/display.c (meta_display_set_input_focus_window): * src/window.c (meta_window_focus): Don't require a push/pop trap around meta_display_set_input_focus_window(), but rather move the push/pop into that function surrounding the XSetInputFocus() call directly. Follow up to #358514. 2006-10-01 Elijah Newren <newren gmail com> * src/*.[ch]: Stick an emacs comment directive at the beginning of all the code files so that people using emacs will be more likely to get coding style correct in their patches. We still need a similar vi directive. #358866 2006-10-01 Elijah Newren <newren gmail com> Patch from Carlo Wood to ensure that maximized and minimized properties are maintained across restarts. #358042. * src/constraints.c (place_window_if_needed): fix up partial maximization handling and add minimize_after_placement handling. * src/display.[ch] (struct MetaDisplay, meta_display_open): add a new display->display_opening flag to allow handling startup differently where needed. * src/window-props.c (reload_net_wm_state): handle _net_wm_state_hidden as well, setting window->minimize_after_placement appropriately * src/window.[ch] (struct MetaWindow, meta_window_new_with_attrs): add a window->minimize_after_placement field * src/window.c (meta_window_new_with_attrs): only unminimize the window and its transients if the display isn't being opened, (unmaximize_window_before_freeing): don't reset the state unless the window is becoming withdrawn, if the screen is being closed be sure to save the unmaximized state of the window so the next window manager can restore it 2006-10-01 Elijah Newren <newren gmail com> * src/window-props.c (set_title_text): surround the XDeleteProperty() call with a meta_error_trap_push/meta_error_trap_pop pair to prevent a crash when closing a remote instance of gedit (and perhaps other apps). #358514. 2006-10-01 Elijah Newren <newren gmail com> Fix longstanding focus bug with mouse (not sloppy) focus mode with popup override-redirect windows, particularly mozilla and firefox's location bar autocompletion. #357695. * src/display.c (event_callback -- EnterNotify & LeaveNotify events): for mouse focus, defocus the focused window when the mouse enters the desktop window rather than when the mouse leaves the focused window. * doc/how-to-get-focus-right.txt: update for the slightly nuanced definition of mouse focus (people without a DESKTOP window like nautilus get sloppy focus behavior now) 2006-09-27 Elijah Newren <newren gmail com> * src/menu.c (var menuitems): Patch from Bruno Boaventura to add notes to remind translators to keep translations in sync with libwnck. #355620. 2006-09-18 Elijah Newren <newren gmail com> * src/window.c (meta_window_show): Patch from Jens Granseuer to fix c89 cleanness, again. #356631. 2006-09-18 Elijah Newren <newren gmail com> * src/constraints.c (constrain_maximization): Ignore maximum size hints when maximizing. Should fix #327543 (see comment 4 and comment 5). 2006-09-18 Elijah Newren <newren gmail com> * src/ui.c (filter_func): avoid a compilation warning by making sure to return something. #348067 2006-09-18 Thomas Thurman <thomas@thurman.org.uk> Branched for Gnome 2.17. * configure.in: bump version to 2.17.0. 2006-09-18 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.16.3 2006-09-18 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.16.2 release 2006-09-18 Elijah Newren <newren gmail com> Partial audit to fix timestamp usage. One step towards fixing #355180; see important comments in that bug. * src/core.[ch] (meta_core_unshade, meta_core_shade): * src/delete.c (meta_window_present_delete_dialog, delete_ping_timeout_func): * src/display.[ch] (meta_display_open, meta_display_close, event_callback, meta_display_begin_grab_op, process_selection_clear, meta_display_unmanage_screen, meta_display_unmanage_windows_for_screen): * src/frames.c (meta_frames_button_press_event): * src/keybindings.c (handle_toggle_shade): * src/main.c (main): * src/screen.[ch] (update_num_workspaces, meta_screen_new, meta_screen_free, prefs_changed_callback): * src/window.[ch] (meta_window_free, finish_minimize, implement_showing, meta_window_show, meta_window_maximize, meta_window_make_fullscreen_internal, meta_window_unmake_fullscreen, meta_window_shade, meta_window_unshade, window_activate, send_sync_request, meta_window_client_message, menu_callback, meta_window_update_keyboard_resize): Remove usage of CurrentTime, meta_display_get_current_time() and meta_display_get_current_time_roundtrip() where possible, or document why it isn't possible, or at very least add a FIXME with some explanation of my laziness and what needs to be done. 2006-09-18 Elijah Newren <newren gmail com> * src/spring-model.c (on_end_move, model_is_calm): Patch from Maik Beckmann to remove compilation warnings. Fixes #355876. 2006-09-18 Elijah Newren <newren gmail com> * configure.in: Make detection of stable vs. unstable automatic and based upon the version number. Partially based on patch from Christian Hamar in #356122. Fixes #356122. 2006-09-13 Elijah Newren <newren gmail com> * HACKING: update -- we depend on gtk+ >= 2.10 since Vincent's July patches for #348633. 2006-09-13 Elijah Newren <newren gmail com> * src/window.c (meta_window_show): Patch from Thomas Andersen to make windows be stacked correctly before showing them, to prevent flicker with focus stealing prevention. #332385. 2006-09-13 Elijah Newren <newren gmail com> * src/common.h (MetaWindowMenuFunc): * src/core.[ch] (meta_core_user_lower_and_unfocus, meta_core_user_focus, meta_core_show_window_menu, meta_core_begin_grab_op, meta_core_end_grab_op): * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func, meta_window_delete): * src/display.[ch] (struct MetaDisplay, struct MetaPingData, sanity_check_timestamps, meta_display_open, event_callback, meta_spew_event, meta_display_set_grab_op_cursor, meta_display_begin_grab_op, meta_display_end_grab_op, meta_display_ping_timeout, meta_display_ping_window, process_pong_message, timestamp_too_old, meta_display_set_input_focus_window): * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard, meta_screen_grab_all_keys, meta_window_grab_all_keys, meta_window_ungrab_all_keys, error_on_generic_command, error_on_command, error_on_terminal_command): * src/metacity-dialog.c (on_realize, warn_about_no_sm_support, error_about_command, main): * src/screen.[ch] (struct _MetaScreen, meta_screen_new, meta_screen_show_desktop, meta_screen_apply_startup_properties): * src/session.c (warn_about_lame_clients_and_finish_interact): * src/window.[ch] (struct _MetaWindow, intervening_user_event_occurred, window_activate, meta_window_delete, meta_window_focus, meta_window_send_icccm_message, meta_window_client_message, menu_callback, meta_window_show_menu, struct EventScannerData, check_use_this_motion_notify, meta_window_begin_grab_op, meta_window_set_user_time): * src/workspace.[ch] (focus_ancestor_or_mru_window, meta_workspace_activate_with_focus, meta_workspace_activate, meta_workspace_focus_default_window, focus_ancestor_or_mru_window): Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ does) instead of Time. #348305 2006-09-12 Elijah Newren <newren gmail com> * src/theme.c (meta_gtk_arrow_from_string, meta_gtk_arrow_to_string): patch from Bruno Boaventura de Oliveira to fix a compiler warning about not handling GTK_ARRROW_NONE. #355490. 2006-09-12 Elijah Newren <newren gmail com> * src/compositor.c: Patch from Bruno Boaventura de Oliveira Lacerda to fix warnings about unused function and global var. #355489. 2006-09-11 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release bump to 2.16.2 2006-09-11 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.16.1 release 22006-09-09 Elijah Newren <newren gmail com> * src/display.c (meta_display_open): Fix build when XKB not found. #354211 2006-09-09 Elijah Newren <newren gmail com> Avoid a stuck grab, preventing focus from being transferred between windows. Thanks to Fryderyk Dziarmagowski for steps to reproduce. Fixes at least part of #354422. * src/display.c (meta_display_begin_grab_op, meta_display_end_grab_op): pass timestamp to meta_screen_ungrab_all_keys, meta_screen_ungrab_all_keys, and meta_window_ungrab_all_keys * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard): add a timestamp parameter and remove call to meta_display_get_current_time(), (meta_screen_grab_all_keys, meta_screen_ungrab_all_keys, meta_window_ungrab_all_keys): add a timestamp parameter and pass it on to grab_keyboard and ungrab_keyboard 2006-09-07 Elijah Newren <newren gmail com> * src/constraints.c (update_onscreen_requirements): make sure windows returning from fullscreen mode are constrained to be "onscreen"; fixes #353699. 2006-08-30 Colin Watson <cjwatson@ubuntu.com> * src/window-props.c (reload_transient_for): Clear window->xtransient_for after emitting the invalid window warning. #353540 2006-09-07 Elijah Newren <newren gmail com> * src/metacity-dialog.c: Patch from Bruno Boaventura de Oliveira Lacerda to replace copy_of_gdk_x11_window_set_user_time() with gdk_x11_window_set_user_time(). We've long since adopted gtk+ >= 2.6 as a dependency. #352293 2006-09-04 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release version bump to 2.16.1 2006-09-04 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.16.0 release 2006-08-22 Elijah Newren <newren gmail com> * src/metacity-dialog.c (main): Patch from Jens Granseuer to fix the build with c89/gcc 2.95. 2006-08-21 Elijah Newren <newren gmail com> * NEWS: Oops, forgot to mention the translators in the 2.15.34 release; add them retroactively 2006-08-21 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.15.55 2006-08-21 Elijah Newren <newren gmail com> * NEWS: 2.15.34 release 2006-08-21 Elijah Newren <newren gmail com> Patch from Thomas Andersen to fix metacity-dialog handling of arguments. #340690 * src/metacity-dialog.c (main): replace hackish argument parsing with GOption parsing. Much nicer. :) 2006-08-21 Elijah Newren <newren gmail com> Patch from Ed Catmur to fix keybindings with hex-values (coming from special extended keyboard keys). #140448. * src/keybindings.c (struct _MetaKeyBinding): change keycode from KeyCode to unsigned int (comment from Elijah: why???), (reload_keycodes): only grab keysyms for keybindings that have them, (count_bindings, rebuild_binding_table): bindings can be valid either due to a valid keysym or a valid keycode, (display_get_keybinding_action, meta_change_keygrab, process_tab_grab, process_workspace_switch_grab): handle keycode as well as keysym * src/prefs.[ch] (struct MetaKeyCombo, update_binding, update_list_binding): handle keycode as well as keysym * src/ui.[ch] (meta_ui_accelerator_parse): new function special cases strings of the form "0x[0-9a-fA-F]+" and otherwise calling gtk_accelerator_parse(), (meta_ui_parse_accelerator, meta_ui_parse_modifier): call meta_ui_accelerator_parse instead of gtk_accelerator_parse. 2006-08-21 Elijah Newren <newren gmail com> Allow drags & resizes to be reverted by hitting escape. Based on patch from Thomas Andersen. #126497. * src/display.c (grab_op_is_mouse_only): new function, (meta_display_begin_grab_op): grab the keyboard when moving or resizing too so that we can get escape keypresses * src/display.h (struct _MetaDisplay): add a comment to remind that grab_was_cancelled is only used in wireframe mode * src/keybindings.[ch] (process_mouse_move_resize_grab): add new function for handling keypresses during mouse-only moving and resizing, (meta_window_grab_all_keys): add a timestamp parameter and pass it to meta_window_focus(), (meta_display_process_key_event): make sure process_mouse_move_resize_grab() gets called when needed, (process_keyboard_move_grab, process_keyboard_resize_grab): rearrange some code slightly and improve the comments to make it more readable 2006-08-21 Elijah Newren <newren gmail com> Fix several bugs with handling of fullscreen windows, causing them to not actually be fullscreen. #343115 (and also #346927, #350547, #351643, the recent additional WINE-related issue mentioned on the mailing list, and probably others...) * src/constraints.c (setup_constraint_info): if a window tries to resize to fullscreen-size and it has a fullscreen function but isn't actually marked as fullscreen then assist it by marking it as such, (constrain_fully_onscreen, constrain_titlebar_visible): ignore this constraint for fullscreen windows since such windows have a separate specialized constraint * src/stack.c (window_is_fullscreen_size, get_standalone_layer): remove the old window_is_fullscreen_size() hack for detecting windows to treat as fullscreen since it doesn't work well with the new constraints framework (i.e. we needed a slightly different hack) * src/window.[ch] (meta_window_new_with_addrs): shuffle the order of adding the window to the stack and moveresizing the window since moveresizing can cause stack changes if the window's initial size is fullscreen size, (meta_window_make_fullscreen, meta_window_make_fullscreen_internal): split meta_window_make_fullscreen() similar to meta_window_maximize() so that constraints can make use of it 2006-08-19 Baptiste Mille-Mathias <baptiste.millemathias@gmail.com> * src/stock_delete.png: Update the pixmap to a new one which fit better with the other pixmaps of the menu. First patch in metacity, woot! #345498 2006-08-18 Elijah Newren <newren gmail com> * src/tabpopup.c (meta_ui_tab_popup_new): Patch from Willie Walker to restore the part of the patch that I should not have reverted in #123372, in order to fix accessibility. #350624 2006-08-09 Elijah Newren <newren gmail com> * src/window.c (intervening_user_event_occurred): Vytautus Liuolia totally rocks; he tested and debugged and tracked down where we were using the focus window's net_wm_user_time even when it was uninitialized. This may fix bug 311868 and others I've heard about (with Valknut, IIRC). It definitely fixes the issues Vytas was seeing with his single instance library. :-) 2006-08-07 Elijah Newren <newren gmail com> * src/constraints.c (setup_constraint_info): patch from Stéphane Rosi to allow moving maximized windows between xineramas again. #323820 2006-08-07 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.15.34 2006-08-07 Elijah Newren <newren gmail com> * NEWS: 2.15.21 release 2006-08-07 Elijah Newren <newren gmail com> Add a constrain_titlebar_visible constraint; should fix both bug 333328 and bug 345522. Not perfect (minor annoying snap pulling windows back onscreen, plus an ugly hack almost as bad as the old one), but tarballs are due in less than half an hour. ;-) * src/boxes.[ch] (meta_rectangle_overlaps_with_region): new function * src/constraints.c (constrain_titlebar_visible): new function, (enum ConstraintPriority, array all_constraints, update_onscreen_requirements): various small changes to accomodate the new function * src/edge-resistance.c: remove the infinite edge resistance, which was a big hack of a way to workaround the lack of a titlebar_visible constraint * src/window.[ch] (MetaWindow): new require_titlebar_visible bitfield, (meta_window_new_with_attrs): initialized here 2006-08-07 Elijah Newren <newren gmail com> * src/frames.c (meta_frames_button_press_event): Patch from Chris Ball to not minimize in response to double clicks on the titlebar when minimiziation should not be allowed. #347377 2006-08-07 Elijah Newren <newren gmail com> Patch from Björn Lindqvist to fix button lighting with dragged clicks. #321474. * src/frames.c (meta_frames_button_press_event): update the prelit_control, (meta_frames_button_release_event): some code refactoring to simplify things a bit, and make sure to update the prelit_control 2006-08-07 Elijah Newren <newren gmail com> * src/keybindings.c (process_keyboard_move_grab): Patch from Thomas Andersen to return the window to maximized state if the window was "shaken loose" from maximized state during a resize but the resize is later aborted. #346719. 2006-08-07 Elijah Newren <newren gmail com> Patch from Vytautas Liuolia to react to _NET_STARTUP_ID changes, as proposed for the new startup-notification/EWMH spec. #347515 * src/window-props.c (reload_net_startup_id): be sure to act on the new id instead of just recording it * src/window.[ch] (window_activate, meta_window_activate, meta_window_activate_with_workspace, meta_window_client_message): change window_activate() to take a workspace parameter instead of hardcoding to the current workspace, add meta_window_activate_with_workspace() function needed by reload_net_startup_id(). 2006-08-07 Thomas Thurman <thomas@thurman.org.uk> * src/frames.h: add new MetaButtonSpace struct; use it for close_rect, max_rect, min_rect and menu_rect. (#97703) * src/frames.c (control_rect, get_control): modify to support the new fields in MetaButtonSpace. * src/theme.c (meta_frame_layout_get_borders, rect_for_function, meta_frame_layout_calc_geometry, button_rect): add support for the new fields in MetaButtonSpace. 2006-08-07 Elijah Newren <newren gmail com> * src/screen.c (meta_screen_resize_func): patch from Dmitry Timoshkov to make sure window features get recalculated when the screen is resized via XRandR. Part of #346927. 2006-08-04 Elijah Newren <newren gmail com> Patch from Dmitry Timoshkov to fix the heuristic for determining if windows can be made fullscreen (needed for WINE and possible also some legacy applications). Part of #346927. * src/window.c (recalc_window_features): ignore window decoration when checking size for determing whether an unresizable window should be allowed ot be considered for fullscreening 2006-07-31 Björn Lindqvist <bjourne@gmail.com> * src/window.c: Make it so maximized windows do not have rounded corners. #336850. 2006-07-30 Jens Granseuer <jensgr@gmx.net> * src/tabpopup.c: Fix another C89 vs. C99 issue. #347621. 2006-07-26 Vincent Untz <vuntz@gnome.org> * src/update-from-egg.sh: also kill this 2006-07-25 Vincent Untz <vuntz@gnome.org> * src/Makefile.am, ui.c: Kill usage of libegg. #348633. 2006-07-24 Thomas Thurman <thomas@thurman.org.uk> * configure.in: post-release version bump to 2.15.21 2006-07-24 Thomas Thurman <thomas@thurman.org.uk> * NEWS: 2.15.13 release 2006-07-24 Björn Lindqvist <bjourne@gmail.com> * src/display.c (meta_display_grab_window_buttons): Grab Alt+Shift+Button1 as well to partially fix operation ordering issues when trying to snap-move windows. Part of #112478. 2006-07-21 Thomas Thurman <thomas@thurman.org.uk> * ui.[ch] (filter_func): Avoid a case where a struct's fields might be updated after it was freed. #348067. 2006-07-10 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.15.13 2006-07-10 Elijah Newren <newren gmail com> * NEWS: 2.15.8 release 2006-06-12 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.15.8 2006-06-12 Elijah Newren <newren gmail com> * NEWS: 2.15.5 release 2006-06-10 Elijah Newren <newren gmail com> Patch from Aidan Delaney to tidy tabpopup.c by factoring out tab_entry_new(). #166890. * src/tabpopup.c (tab_entry_new): new function, (meta_ui_tab_popup_new): use tab_entry_new() to remove a big chunk of code, plus a few other small cleanups. Tue Jun 6 12:46:42 2006 Søren Sandmann <sandmann@redhat.com> * configure.in (GETTEXT_PACKAGE): Bunp intltool requirement to 0.35.0. 2006-05-29 Elijah Newren <newren gmail com> * HACKING: Slightly more detailed instructions on setting up a build environment to mention relevant development tools in addition to the needed development libraries. Fri May 26 16:48:29 2006 Søren Sandmann <sandmann@redhat.com> * src/effects.c (meta_effect_run_unminimize): Run an unminimize effect * src/window.c (meta_window_unminimize): Store a "was_minimized" boolean in the window. * src/window.c (meta_window_show): If the window was minimized, run an unminimize animation. * src/c-window.c (meta_comp_window_run_unminimize): Add an unminimize animation, running the minimize one in reverse. Fri May 26 14:55:07 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (meta_comp_window_run_focus): Rename from _bounce() to _focus(). 2006-05-26 Elijah Newren <newren gmail com> * src/display.c (meta_display_close): Fix a crash on exit/logout from assuming a compositor would always exist 2006-05-25 Elijah Newren <newren gmail com> * src/place.h: * src/common.h: Remove MetaWindowEdgePosition enum that isn't used anymore Thu May 25 15:56:43 2006 Søren Sandmann <sandmann@redhat.com> * src/effects.h (struct MetaEffect): Move duplicated window field outside the union * src/compositor.c: delete duplicated code to get at the window. Thu May 25 15:17:29 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c: Fix compilation in non-compositor case, by moving the stack functions into the HAVE_COMPOSITOR defines. Thu May 25 15:11:58 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.h: Add a destroy notifier to the window. * src/c-screen.c (on_window_destroy): New function. * src/c-screen.c (meta_comp_screen_add_window): Use the destroy notifier here. * src/c-window.c (generate_phases): New function. Simplify the minimize animation a lot by generating all the rectangle information into an array, then processing that. 2006-05-25 Adam Jackson <ajax@freedesktop.org> * src/c-window.c: * src/c-window.h: * src/compositor.c: * src/compositor.h: * src/effects.c: * src/effects.h: * src/spring-model.c: * src/window.c: Bounce on window focus. Wed May 24 22:15:01 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (do_effect): Make sure windows are kept on top of the panel during minimize. Wed May 24 21:17:59 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (do_effect): Shrink the window instead of explode it. * src/compositor.c (do_effect): don't read the frame if it is NULL. * src/c-window.c (meta_comp_window_run_minimize): Resurrect the shrinking minimize animation. * src/c-window.c (meta_comp_window_fade_in): Make dialogs 90% translucent. * src/c-window.c (update_fade): End at end_fade, not 1.0. Wed May 24 19:15:45 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (cancel_fade): Add a fade-in animation when windows are mapped. Wed May 24 16:37:11 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (private_metacity_window): New function * src/c-window.c (meta_comp_window_refresh_attrs): Map metacity's own windows directly. Wed May 24 16:35:54 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (private_metacity_window): Wed May 24 14:36:42 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (meta_comp_window_{freeze,thaw}_stack: Add a stack-freeze feature to CWindow. * src/c-screen.c (meta_comp_screen_restack): Don't restack if the window is frozen. Wed May 24 13:09:49 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c: Fix compilation in the non-composited case. Wed May 24 12:57:32 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (meta_comp_window_free): return TRUE when the window is actually freed. * src/compositor.c (do_effect): Disable updating before exploding the window. * src/c-window.c: Make MetaCompWindow refcounted. * src/c-window.[ch]: New functions meta_comp_window_{show,hide} * src/c-screen.c (meta_comp_screen_unmap): Call meta_comp_window_hide() instead of directly setting the viewable status of the node. * src/c-screen.c (meta_comp_screen_remove_window): Only remove the window when it is actually freed. Wed May 24 12:45:21 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c: Delete unused meta_comp_screen_hide_window(). 2006-05-23 Adam Jackson <ajax@freedesktop.org> * src/c-window.c: * src/c-window.h: * src/compositor.c: * src/effects.c: * src/effects.h: * src/window.c: Move shrink effect code from compositor.c to c-window.c. Stubs for restore effect. Notes in various places for where to hook in other effects. Tue May 23 16:36:04 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (do_effect): Also use explode when windows close. * src/c-window.c (meta_comp_window_explode): Add refcounting to comp window, and use it in the explosion effect * src/effects.h (struct MetaEffect): Add new MetaCloseEffect. * src/display.c (event_callback): Run it from the UnmapNotify event handler. Tue May 23 15:23:58 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (send_sync_request): New function to send a sync request to newly mapped windows. (on_request_alarm): Show the window here. 2006-05-23 Adam Jackson <ajax@freedesktop.org> * src/effects.h: Add more effect tokens. Mon May 22 17:35:52 2006 Søren Sandmann <sandmann@redhat.com> * src/effects.[ch]: Beginning of new layer that abstracts transition effects. New functions: (meta_push_effect_handler): Install an effect handler (meta_pop_effect_handler): Remove last effect handler (meta_effect_run_minimize): Create a minimize effect and pass it to the handler. (meta_effect_end): Called by handler when the effect is finished. * src/compositor.c: Move explosion code form there to src/c-window.c. * src/c-screen.c: Delete explosion related code. 2006-05-22 Björn Lindqvist <bjourne@gmail.com> * common.h (enum MetaCursor): * display.c (meta_display_create_x_cursor): Make mouse cursor when moving windows become a hand. Fixes #337376. 2006-05-19 Björn Lindqvist <bjourne@gmail.com> * frames.c: Fix a logic bug so that the whole titlebar becomes sensitive to mouse clicks. Fixes #336320. 2006-05-18 Björn Lindqvist <bjourne@gmail.com> * resizepopup.c: Remove the unused attributes resize_gravity, width_inc, height_inc, min_width, min_height, frame_left, frame_right, frame_top, frame_bottom, tick_origin_x, tick_origin_y from the MetaResizePopup struct. Delete all code that references those attributes. 2006-05-15 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.15.5 2006-05-15 Elijah Newren <newren gmail com> * NEWS: 2.15.3 release 2006-05-15 Elijah Newren <newren gmail com> Revert the accessibility module loading workaround from Gnome 2.6, since gtk+ has long since fixed this for us. #123372. * src/Makefile.am: remove METACITY_LIBDIR define * src/main.c (find_accessibility_module, accessibility_invoke_module, accessibility_invoke, main): remove the first three of these functions and all calls to them * src/tabpopup.c (meta_ui_tab_popup_new): not sure if this part of 120025 needed to be reverted but doing the reversion, if wrong, is the best way to get someone from the accessibility team to scream, er, I mean comment. ;-) 2006-05-15 Elijah Newren <newren gmail com> * src/screen.c (reload_xinerama_infos): Patch from jylefort@FreeBSD.org to prevent a crash when changing resolution. Fixes #340847. 2006-05-15 Björn Lindqvist <bjourne@gmail.com> * places.[ch] (intcmp, window_get_edges, get_windows_showing_on_same_screen, get_vertical_edges, get_horizontal_edges, meta_window_find_next_vertical_edge, meta_window_find_next_horizontal_edge, meta_window_find_nearest_vertical_edge, meta_window_find_nearest_horizontal_edge): Remove the preceeding functions as they are all obsoleted by the new edge-resistance stuff. Fixes #341561. 2006-05-15 Paolo Borelli <pborelli@katamail.com> * src/prefs.c (update_binding): plug a small leak. 2006-05-12 Elijah Newren <newren gmail com> * configure.in: I don't think we want a config file for the no-gconf case; embedded people would prefer hard-coding things into the binary (http://mail.gnome.org/archives/metacity-devel-list/2006-May/msg00010.html) 2006-04-25 Elijah Newren <newren gmail com> * HACKING: Clarify that gnome-common is needed now that autogen.sh has been rewritten to use gnome-autogen.sh Fri May 5 12:50:58 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.c (has_counter): Some experimental code to handle sync counter notifications on a window. * src/c-screen.c (meta_comp_screen_add_window): Pass a MetaDisplay 2006-04-25 Elijah Newren <newren gmail com> Clear _NET_WM_VISIBLE_NAME (and the ICON_ equivalent) when no longer being used. Fixes #330671. * src/window.[ch] (struct MetaWindow): new using_net_wm_visible_name and using_net_wm_visible_icon_name bits, (meta_window_new_with_attrs): initialize these new bits to false * src/window-props.c (set_title_text, set_window_title, set_icon_title): if the _NET_WM_VISIBLE_(ICON_)NAME property was previously set but doesn't need to be this time, make sure to clear it 2006-04-25 Elijah Newren <newren gmail com> * rationales.txt: add three new tracker bugs Thu May 4 13:30:04 2006 Søren Sandmann <sandmann@redhat.com> * src/ui.h: Delete unused META_PRIORITY_COMPOSITE * src/ui.c: Delete argument from meta_ui_get_display(). * src/c-window.c: Remove the xid->window hashtable and associated code. * src/c-screen.[ch]: Rename MetaScreenInfo to MetaCompScreen. Put the xid->windows table here instaed of as a static variable. Also make sure that CompWindows are freed when the screen is unredirected. * src/display.c: Delete non USE_GDK_DISPLAY case, as it didn't work and hasn't been compiled for a long time. * src/display.[ch] (meta_display_open): Remove argument as it was always NULL (and couldn't possibly be anything else in the USE_GDK_DISPLAY case). Tue May 2 17:12:54 2006 Søren Sandmann <sandmann@redhat.com> * src/c-window.[ch]: New files * src/c-screen.c: Move WindowInfo struct to new c-window.[ch] files. Delete various bits of obsolete, commented-out code. Fri Apr 28 12:53:23 2006 Søren Sandmann <sandmann@redhat.com> * src/core.c (get_window): New function. * src/core.c: Use get_window() instead of cutted-and-pasted code all over the place. 2006-04-25 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.15.3 2006-04-25 Elijah Newren <newren gmail com> * NEWS: 2.15.2 release 2006-04-25 Elijah Newren <newren gmail com> * autogen.sh: Nuke the old version, copy one from gcalctool that uses gnome-autogen.sh. Seems to fix the translations-aren't-included-in-the-tarball problem. Fix from Rodney in IRC. 2006-04-25 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.15.2 2006-04-25 Elijah Newren <newren gmail com> * NEWS: 2.15.1 release * configure.in: belated post-release version bump to 2.15.1 * src/Makefile.am: Include boxes.h so that control-center won't fail to build #339708. 2006-04-24 Elijah Newren <newren gmail com> * NEWS: 2.15.0 release 2006-04-20 Brian Pepple <bdpepple@gmail.com> #337951. * po/LINGUAS: New file listing all supported languages. * configure.in: Use po/LINGUAS instead of including all languages directly in this file. See the wiki for more information: http://live.gnome.org/GnomeGoals/PoLinguas. 2006-04-19 Thomas Andersen <phomes@gmail.com> * src/window-props.c (reload_transient_for): warn and ignore if transient_for is set to a non-top-level window. Fixes #335524. 2006-04-19 Björn Lindqvist <bjourne@gmail.com> * src/frames.c (struct CachedPixels, meta_frames_destroy, invalidate_cache, generate_pixmap, populate_cache, cached_pixels_draw, meta_frames_expose_event, meta_frames_paint_to_drawable): Replace while loops iterating over sequences with for loops. Also, replace the attributes in the CachedPixels struct with a list of four CachedFramePiece:s, this allows iteration over the four pixmaps instead of treating each one separately. Fixes #338359. 2006-04-18 Björn Lindqvist <bjourne@gmail.com> * makefile.am: Add boxes.{c,h} to libmetacity_private * src/theme-parser.c (check_expression): * src/theme-viewer.c (run_position_expression_tests): Use meta_rect (). * src/theme.c: Replace while loops iterating over sequences with for loops. * src/theme.c, src/theme.h (struct _MetaPositionExprEnv, meta_draw_op_draw, meta_draw_op_list_draw, meta_theme_draw_menu_icon): Use MetaRectangles in function prototypes instead of x, y, with, height ints where applicable. 2006-04-18 Kjartan Maraas <kmaraas@gnome.org> * configure.in: Remove obsolete entry for no_NO * po/no.po: And the translation. 2004-04-17 Thomas Thurman <thomas@thurman.org.uk> * keybindings.c (count_bindings, rebuild_binding_table): * prefs.c (change_notify, screen_bindings, window_bindings, init_bindings, update_binding, find_and_update_list_binding, update_list_binding, meta_prefs_get_window_binding): Allow any keybinding pref to be specified either with <foo>, a string, or <foo>_list, a list of strings, or both. Fixes #164831. 2006-04-16 Elijah Newren <newren gmail com> Patch from Dan Sanders to fix #334899. * window.c (meta_window_new_with_attrs): Unminimize ancestors of new windows when mapped; this prevents e.g. confirmation windows from causing applications to appear locked when closing via the window list. 2006-04-15 Elijah Newren <newren gmail com> Patch from Dan Sanders to fix #335076. * src/core.c (meta_core_maximize, meta_core_toggle_maximize, meta_core_unmaximize): * src/window.c (meta_window_client_message): Raise windows on maximize/unmaximize. 2006-04-15 Elijah Newren <newren gmail com> * src/display.h: Patch from Andy Morum to fix the build with --disable-xsync. #336605 2006-04-14 Elijah Newren <newren gmail com> * HACKING: Include instructions on setting up a minimal building/testing environment 2006-04-14 Thomas Thurman <thomas@thurman.org.uk> Add a tabbing function, bound to alt-f6 by default, to cycle through the windows of the current application. Fixes #94682. * src/common.h: two new MetaGrabOpts values for group switching * src/display.c (ping_data_free, meta_display_in_grab_op, IN_TAB_CHAIN): adapt to new MetaGrabOpts * src/display.h: new enum value for MetaTabList for group switching * src/keybindings.c (meta_display_process_key_event): adapt to new MetaGrabOpts (process_tab_grab): adapt to new MetaGrabOpts, and use switch statement for cancelling instead of if statement * src/metacity.schemas.in: new keybindings * src/prefs.c, src/prefs.h: handle new keybindings * src/window.h: define META_WINDOW_IN_GROUP_TAB_CHAIN macro 2006-04-14 Elijah Newren <newren gmail com> * HACKING: Include reasons why gdk/gtk.h and core includes like display.h/window.h must be kept separate. Taken from a private email from Havoc. 2006-04-13 Alejandro Andres <fuzzy.alej@gmail.com> * README: Fixed broken links. #333303 Thu Apr 13 12:23:28 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_add_window): Check for both POPUP and DROPDOWN. 2006-04-13 Björn Lindqvist <bjourne@gmail.com> * src/async-getprop.c, src/async-getprop.h (async_get_property_handler, ag_task_get_reply_and_free): * src/testasyncgetprop.c (try_get_reply, run_speed_comparison): Change unsigned chars to chars. * src/display.h (struct MetaDisplay): * src/keybindings.c (reload_modmap): Change unsigned ints to ints. * src/screen.c (set_workspace_names) * src/stack.c (meta_stack_sync_to_server): * src/xprops.c (utf8_string_from_results, utf8_list_from_results, class_hint_from_results, meta_prop_get_values): Introduce casts. Add a number of casts and change signedness on a number of variables so that Metacity compiles with many fewer warnings. Fixes #336032. 2006-04-12 Elijah Newren <newren gmail com> Patch from Ron Yorston to add a focus_new_windows option. Default is 'smart' (focus by default but normal focus-stealing-prevention can kick in); 'strict' is current other choice (like 'smart' except that programs launched by the terminal will not be focused). Fixes remainder of #326159. Should also close #152004 and a bunch of others. * src/common.h: Add a MetaFocusNewWindows enum giving the current types allowed * src/display.h: Update docs on allow_terminal_deactivation to note that it is only relevant when focus_new_windows is 'strict' * src/metacity.schemas.in: add the new gconf key and explanation * src/prefs.[ch] (#define KEY_FOCUS_NEW_WINDOWS, static gboolean focus_new_windows, update_focus_new_windows, meta_prefs_init, change_notify, meta_prefs_get_focus_new_windows, meta_preference_to_string): Add all the normal preference handling stuff for this new focus-new-windows option. * src/window.c (window_state_on_map, meta_window_set_user_time): Don't focus windows launched from a terminal Mon Apr 10 16:44:51 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (is_menu): Check if the window is a menu and make it 90% opaque in that case. * src/c-screen.c (claim_selection): Handle CM_Sn selection properly. * src/c-screen.c: Remove debug spew * src/screen.c (meta_screen_composite_all_windows): Remove debug spew 2006-04-10 Björn Lindqvist <bjourne@gmail.com> * display.c (meta_display_open, event_callback): * ui.c (meta_ui_get_double_click_timeout): Delete dead code that used to handle double click on the titlebar. Remove the attributes last_button_time, last_button_xwindow, last_button_num and is_double_click from MetaDisplay and the functions meta_ui_get_double_click_timeout() and meta_display_is_double_click() from their respective files. Fixes #337507. 2006-03-27 Gora Mohanty <gmohanty@cvs.gnome.org> * src/metacity.schemas.in: * src/theme.c: Changes strings to make them more readable, and more translatable. Fixes #335720. 2006-04-02 Elijah Newren <newren gmail com> Fix constraints bug causing negative width windows and crashes. #336651 * src/constraints.c (constrain_partially_onscreen): Don't accidentally shove & resize the window by requiring more pixels to be onscreen than the size of the window. Fri Mar 31 16:44:56 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_unredirect): Release the GL window here. Disconect from the magnifier, not the stacker. Fri Mar 31 12:24:26 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_redirect): Only use magnifier when USE_MAGNIFIER is set. * src/compositor.c (meta_compositor_free_window): Only wobble when USE_WOBBLE is set. Fri Mar 31 12:13:21 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_redirect): Don't hardcode screen size. Thu Mar 30 17:01:12 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (struct MetaCompositor): Fix the memory corruption in a better way. Thu Mar 30 16:38:35 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (meta_compositor_begin_move): Fix an illegal write. Thu Mar 30 16:13:52 2006 Søren Sandmann <sandmann@redhat.com> * composite.c: Turn wobbling back on Add new explosion effect. 2006-03-29 Elijah Newren <newren gmail com> Fix grouping in the presence of ancestors; caught by Björn. #336184 * src/group.c (meta_window_compute_group): Use new meta_window_find_root_ancestor() function to get ancestor; for the computed group, use the ancestor's group instead of the ancestor itself * src/window.[ch] (meta_window_find_root_ancestor, meta_window_raise): split meta_window_find_root_ancestor() functionality of meta_window_raise() and make it available elsewhere 2006-03-29 Elijah Newren <newren gmail com> * rationales.txt: Add bugs about pointer warping; update raise-on-click ones. 2006-03-29 Thomas Thurman <thomas@thurman.org.uk> Abstract out the functions for setting/unsetting demands attention hint and avoid doing it when the window isn't obscured. Fixes the remainder of #305882. * src/window.c, src/window.h (meta_window_set_demands_attention, meta_window_unset_demands_attention): new functions to mark a window as needing or not needing the user's attention * src/window.c (meta_window_show, window_activate, meta_window_focus, meta_window_configure_request, meta_window_client_message): use the new set/unset demands attention functions. 2006-03-29 Björn Lindqvist <bjourne@gmail.com> * src/resizepopup.c: * src/resizepopup.h: * src/window.c (meta_window_refresh_resize_popup): Aggregate the x, y, width and height attributes of MetaResizePopup to one MetaRectangle rect attribute and update code using the MetaResizePopup struct. Fixes #335177. 2006-03-28 Elijah Newren <newren gmail com> * MAINTAINERS: New file. #335026. ;-) Tue Mar 28 09:57:26 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_add_window): Also check for overlay_window. * src/c-screen.c (meta_screen_info_redirect): Trap errors out of unredirect(). 2006-03-25 Thomas Thurman <thomas@thurman.org.uk> * src/window.c, src/window.h (update_net_wm_state, update_mwm_hints, update_wm_class, update_transient_for): deleted and moved into window-props.c (meta_window_new_with_attrs): added constructing field and four new initial properties (as above) (meta_window_recalc_features, meta_window_recalc_window_type): new functions * src/window-props.c (init_net_wm_state, reload_net_wm_state init_mwm_hints, reload_mwm_hints, init_wm_class, reload_mwm_class, init_transient_for, reload_transient_for): new functions, moved in from window.c (meta_display_init_window_prop_hooks): initialise new properties Closes #309567. 2006-03-25 Paolo Borelli <pborelli@katamail.com> * src/prefs.c: use g_str_has_prefix instead of a local copy of the function. 2006-03-16 Ray Strode <rstrode@redhat.com> Add patch from Elijah Newren to fix type for compositing_manager schema entry (bug 335901) * src/metacity.schemas.in: Change type from "boolean" to "bool" and default value from "FALSE" to "false" Wed Mar 22 13:16:48 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (meta_compositor_remove_window): Actually remove the window. * src/c-screen.c (meta_screen_info_remove_window): Only remove node if non-NULL Wed Mar 22 10:33:21 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_redirect): Put a square below the desktop stack. Mon Mar 20 11:50:44 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_redirect): Put the desktop into a magnifier. * src/c-screen.c (struct MetaScreenInfo): Add a CmMagnifier * src/c-screen.c (meta_screen_info_redirect): Move some of the gl window related stuff here. 2006-03-16 Soren Sandmann (sandmann@daimi.au.dk) * src/c-screen.c (meta_screen_info_set_target_rect): Put inside COMPOSIT_EXTENSIONS 2006-03-03 Thomas Thurman <thomas@thurman.org.uk> Always set _NET_WM_STATE when a window is shown or hidden, even if it wasn't mapped. Fixes #315142. * src/window.c (meta_window_hide, meta_window_show): call set_net_wm_state unconditionally 2006-03-16 Elijah Newren <newren gmail com> Add debugging information for edge resistance * src/edge-resistance.c (cache_edges): print out the edges that are being cached if in verbose mode, (meta_window_edge_resistance_for_move, meta_window_edge_resistance_for_resize): if edge resistance kicked in then print out a message about it * src/util.c: * src/util.h: Add META_DEBUG_EDGE_RESISTANCE to MetaDebugTopic enum list Thu Mar 16 14:55:18 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (struct WindowInfo): Maintain the size of the window. Wed Mar 15 16:30:09 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (set_geometry): Use set_target_rect() instead of set_size(). * src/c-screen.c: Add set_target_rect() as a way of scaling windows. * src/window.c (meta_window_handle_mouse_grab_op_event): Turn updates on after a button release. * src/window.c (meta_window_move_resize_internal): Fix indentation. Wed Mar 15 11:34:54 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_add_window): Use unset_patch() instead of unset_geometry(). Tue Mar 14 11:57:46 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: Comment out wobbling * src/compositor.c (blow_up): remove this function * src/compositor.c (process_configure_notify): Uncomment set_size(). * src/c-screen.c (meta_screen_info_set_updates): When updates are true, set all the properties such as size and shape. * src/c-screen.c (meta_screen_info_add_window): Create a special WindowInfo structure for each window. * src/c-screen.c (meta_screen_info_set_size): Set size and output shape of the drawable node. 2006-03-13 Elijah Newren <newren gmail com> * README: * configure.in: Update to reflect that we're now targetting 2.15 development. 2006-03-12 Thomas Thurman <thomas@thurman.org.uk> * src/window-props.c (set_title_text): Mark a particular string for translation. #334332. 2006-03-06 Ryan Lortie <desrt@desrt.ca> * src/window.c (meta_window_free): Only unmaximise window before freeing if the window is actually maximised. #333563. Fri Mar 3 15:31:04 2006 Søren Sandmann <sandmann@redhat.com> * src/c-screen.c (meta_screen_info_new): Update for libcm API change. Wed Mar 3 13:25:03 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c, src/c-screen.[ch]: Split the ScreenInfo data structure into separate, new files c-screen.[ch]. * src/errors.c (x_error_handler): Forward foreign errors to foreign displays. * src/errors.c (meta_errors_register_foreign_display): Implement this function * src/errors.h: Add new meta_errors_register_foreign_display() Tue Feb 28 14:49:23 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: Put the windows in a stacker rather than do the traversing outselves. 2006-02-27 Elijah Newren <newren gmail com> Patch from Thomas Thurman to prevent setting cycle_windows to keybindings that won't work. #329676 * src/prefs.c (update_binding): Make sure that bindings which require a modifier key are set to a keybinding with one or else that the binding is reverted. * src/ui.[ch] (meta_ui_accelerator_name): New function 2006-02-27 Elijah Newren <newren gmail com> Patch from Thomas Thurman to work around buggy application grouping with transient windows. #328211 * src/group.c (meta_window_compute_group): Put transients in the same group with their parent, always. * src/window.c (update_transient_for): Update group too 2006-02-27 Elijah Newren <newren gmail com> * configure.in: Patch from Sylvain Bertrand to fix build issues with library search order. #330695. Sat Feb 25 14:50:17 2006 Søren Sandmann <sandmann@redhat.com> * src/window.c: Remove include of flash.h Sat Feb 25 11:46:14 2006 Søren Sandmann <sandmann@redhat.com> * src/display.c (meta_display_begin_grab_op): Call meta_compositor_begin_move if there is a compositor * src/compositor.c (meta_compositor_begin/update/end_move): Implement those functions. * src/spring-model.[ch]: New files Thu Feb 23 15:40:52 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (meta_compositor_manage_screen): Don't attempt to manage the screen if it already is managed. * src/compositor.c (meta_compositor_unmanage_screen): Synchronize the display. 2006-02-19 Thomas Thurman <thomas thurman org uk> Removed "move to another workspace" menu when there are exactly two workspaces. Fixes #151183. * src/menu.c (meta_window_menu_new): clear META_MENU_OP_WORKSPACES bit when n_workspaces==2 Fri Feb 17 11:56:35 2006 Søren Sandmann <sandmann@redhat.com> * src/screen.c (meta_screen_free): Only uncomposite the screen if there is a compositor. * src/compositor.c (meta_compositor_new): Warn and fail if the server doesn't have composite Thu Feb 16 18:57:48 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: Fix the build when --enable-compositor is there. Thu Feb 16 15:54:48 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: Insert #ifdef's to make it build again Thu Feb 16 15:24:42 2006 Søren Sandmann <sandmann@redhat.com> * src/screen.c (meta_screen_composite_all_windows): New function. * src/prefs.[ch], src/metacity.schemas.in: Add new compositing_manager key. * src/display.c (prefs_changed_callback): Handle META_PREF_COMPOSITOR_MANAGER * src/display.c (event_callback): Only call meta_compositor_process_event() if there is in fact a compositor. * src/display.c (enable/disable_compositor): Add code to enable/disable compositor at runtime Wed Feb 15 18:42:03 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.[ch]: Add code to destroy compositor. Implement unmanage_screen() functionality. Wed Feb 15 14:47:50 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (meta_compositor_unminimize): Add unused wobbly unminimize animation by Kristian * src/compositor.c (meta_compositor_minimize): Add wobbly minimize animation by Kristian. * src/compositor.c: Add support for turning updates on and off. * src/window.c (meta_window_move_resize_internal): Use sync counter to make composited resizing tear free 2006-02-14 Elijah Newren <newren gmail com> Patch from Jens Granseuer to fix more build issues with gcc 2.95. #331166. * src/prefs.c (meta_prefs_init): Remove C99 style variable initiailization 2006-02-13 Elijah Newren <newren gmail com> * configure.in: post-release version bump to 2.13.144 2006-02-13 Elijah Newren <newren gmail com> * NEWS: 2.13.89 release 2006-02-13 Elijah Newren <newren gmail com> * src/keybindings.c (process_tab_grab): We had that prev_window code in multiple places and it was all identical. Let's just stick it in one place to make the function easier to read. 2006-02-13 Thomas Thurman <thomas thurman org uk> * src/keybindings.c (process_tab_grab): Allow alt-escape to cancel alt-tabbing, and vice versa. Fixes #141425. 2006-02-11 Thomas Thurman <thomas thurman org uk> Disable alt-f7 if a window can't be moved, and alt-f8 if it can't be resized. Fixes #328920. * src/keybindings.c (handle_begin_move, handle_begin_resize): check window->has_*_func before beginning operation 2006-02-11 Elijah Newren <newren gmail com> Add a man page for metacity. Original version taken from Debian (written by Thom May and Akira Tagoh) and updated by Luke Morton and Philip O'Brien. Necessary auto-fu supplied by Philip O'Brien. Fixes #321279. 2006-02-11 Elijah Newren <newren gmail com> * src/stack.h (enum MetaStackLayer): * src/stack.c (get_standalone_layer): actually use META_LAYER_TOP but just manually make it equal to META_LAYER_DOCK. Add a note point to the EWMH for why we do this. #330717 2006-02-11 Elijah Newren <newren gmail com> * src/window.c (enum GnomeWinLayer): remove this legacy cruft that we stopped using years ago 2006-02-10 Thomas Thurman <thomas thurman org uk> Avoid a memory leak when checking which workspace(s) a window is on. Fixes #322059. * src/workspace.h (struct MetaWorkspace): * src/workspace.c (meta_workspace_new, meta_workspace_free): added list_containing_self member to MetaWorkspace * src/window.c (meta_window_get_workspaces): use window->workspace->list_containing_self instead of allocating (and leaking) such a list on the fly. 2006-02-09 Thomas Thurman <thomas thurman org uk> * src/testboxes.c (test_regions_okay, test_clamping_to_region): add messages to explain that warnings are harmless Tue Feb 7 00:58:05 2006 Soeren Sandmann <sandmann@redhat.com> * src/compositor.c: Wrap fade code in #ifdef HAVE_COMPOSITE_EXTENSIONS Mon Feb 6 17:45:39 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: New fancy minimize animation. Fade windows in and out. 2006-02-03 Thomas Thurman <thomas thurman org uk> * src/display.c (event_callback): produce warning when invalid events with no timestamp are received, rather than failing an assertion Thu Feb 2 17:58:22 2006 Søren Sandmann <sandmann@redhat.com> * compositor.c (process_map): update the pixmap. (update) print out framerate. (dump_stacking_order) new debug function. (meta_compositor_add_window) error trap fixes (MiniInfo): Make the minimize animation fade out. 2006-01-30 Elijah Newren <newren gmail.com> * configure.in: post-release version bump to 2.13.89 2006-01-30 Elijah Newren <newren gmail com> * NEWS: 2.13.55 release 2006-01-30 Elijah Newren <newren gmail com> * src/display.[ch] (struct MetaDisplay), meta_display_open, meta_display_set_input_focus_window, meta_display_focus_the_no_focus_window): Track the active_screen, (event_callback): If the mouse enters a window on a different screen, activate the default window on the new screen. May need to be modified for click-to-focus; we'll wait for feedback. Fixes #319348. 2006-01-23 Elijah Newren <newren gmail com> * src/display.c (meta_display_check_threshold_reached): change the order of the ||'ed items in the if to avoid using an uninitialized value * src/prefs.c (meta_prefs_init): fix a couple uninitialized value problems 2006-01-21 Elijah Newren <newren gmail com> Patch from Christian Kirbach to prevent a critical warning crasher when switching themes. #327847. * src/theme.c (meta_theme_free): since themes are only constructed as needed and may be NULL, check for that before freeing theme hash tables 2006-01-21 Elijah Newren <newren gmail com> * src/common.h (enum MetaActionDoubleClickTitlebar): * src/frames.c (meta_frames_button_press_event): * src/prefs.c (action_double_click_titlebar_from_string): * src/metacity.schemas.in: Patch from Dick Marinus to add a minimize double-click-titlebar-action; slightly modified to also include a none action. #300210. 2006-01-20 Elijah Newren <newren gmail.com> * configure.in: post-release version bump to 2.13.55 2006-01-20 Elijah Newren <newren gmail com> * NEWS: 2.13.34 release 2006-01-20 Elijah Newren <newren gmail com> * src/constraints.c (setup_constraint_info): fixed_directions is only meant for explicit user interactions; disable it for everything else. There are other bugs and improvements that could be made with fixed_directions that I should be filing too, but at least put a FIXME there for now--I'm so lame. Fixes #327822. 2006-01-20 Elijah Newren <newren gmail com> Avoid flashing when closing a maximized window. Fixes #317254. * src/window.c (unmaximize_window_before_freeing): new function that just fixes the net_wm_state and sends a configure_notify, (meta_window_free): use unmaximize_window_before_freeing() instead of meta_window_unmaximize() to avoid flicker 2006-01-20 Elijah Newren <newren gmail com> Fix unitialized value problem when in raise-on-click mode. Søren, #327572. * src/display.c (meta_display_check_threshold_reached): make function be a no op if raise_on_click!=FALSE * src/display.h (struct MetaDisplay): point out that grab_initial_[xy] and grab_threshold_movement_reached are only for raise_on_click==FALSE mode. 2006-01-20 Elijah Newren <newren gmail com> Patch from Søren to fix some reading-from-free'd-data errors. #327575 * src/edge-resistance.c (meta_display_cleanup_edges): store the edges in a hash table so that we can still read their values within the loop from the other array they are stored in, then free them all at the end. 2006-01-20 Elijah Newren <newren gmail com> Fix various initialization and default issues, especially for --disable-gconf. Make --disable-gconf actually work. #326661. * configure.in: Fix compilation with --disable-gconf * src/metacity.schemas.in: Add a note that if any defaults are changed in this file, src/prefs.c may need to be updated to reflect the change * src/prefs.c: set various static global vars to the right default value, (meta_prefs_init): get the titlebar_font and current_theme handled better when not using gconf, (struct MetaSimpleKeyMapping, screen_string_bindings, window_string_bindings): helper vars to allow some keybindings to work even without gconf, (init_bindings): initialize bindings for the without-gconf case too, (init_commands): make sure these are all NULL for the non-gconf case so that we don't access random memory, (init_workspace_names): just give these all a default name for the non-gconf case, (meta_prefs_change_workspace_name): actually change the name for the non-gconf case too 2006-01-20 Elijah Newren <newren gmail com> More careful error handling of values returned by GConf. Fixes #326615. * src/prefs.c (get_bool): new helper function, (meta_prefs_init): use get_bool to handle the case of a gconf key not existing, (update_cursor_size): sanity check for sane values 2006-01-20 Elijah Newren <newren gmail com> Prevent rapidly repeated visual bells from hanging metacity. Fixes #322032. * src/display.h (struct MetaDisplay): add a last_bell_time field, (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS macro, XERVER_TIME_IS_BEFORE macro): add parentheses around usage of macro parameter * src/display.c (meta_display_open): initialize last_bell_time, (event_callback): don't allow more than one bell per second 2006-01-20 Elijah Newren <newren gmail com> * src/async-getprop.c: * src/common.h: * src/display.c: * src/eggaccelerators.c: * src/frames.c: * src/gradient.c: * src/iconcache.c: * src/keybindings.c: * src/metaaccellabel.c: * src/place.c: * src/prefs.c: * src/preview-widget.c: * src/screen.c: * src/session.c: * src/stack.c: * src/tabpopup.c: * src/theme-viewer.c: * src/theme.c: * src/window-props.c: * src/window.c: * src/workspace.c: * src/tools/metacity-window-demo.c: * src/wm-tester/test-gravity.c: * src/wm-tester/test-resizing.c: * src/wm-tester/test-size-hints.c: Patch from Kjartan Maraas to fix a lot of tiny issues (unused variable removal, making unused variables used again, correction of types passed/declared for printf arguments, removal of unneeded breaks and returns, dead code removal, dead code revival, renaming to prevent shadowed variables, declaring unexported functions as static) spotted by the intel compiler. #321439 2006-01-20 Elijah Newren <newren gmail com> Patch from Björn Lindqvist to fix #98340. * src/screen.c (meta_screen_ensure_tab_popup): Make sure an outline border is shown even if a window frame's width is 0. Also, correctly handle window outlines in showing desktop mode. Fri Jan 20 16:42:25 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: Make minimize animation update again. Thu Jan 19 18:05:47 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (meta_compositor_manage_screen): g_object_unref() rather than ws_region_unref(). Thu Jan 19 16:50:50 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: Port to changes in libcm Tue Jan 17 17:25:29 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c: Port to changes in libcm. 2006-01-16 Elijah Newren <newren gmail com> * src/window-props.c: manually define HOST_NAME_MAX if not already defined to fix Solaris compilation issue. Caught by Damien Carbery, patch from Havoc. #326745 2006-01-16 Elijah Newren <newren gmail.com> * configure.in: post-release version bump to 2.13.34 2006-01-16 Elijah Newren <newren gmail com> * NEWS: 2.13.21 release Mon Jan 16 11:55:20 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (meta_compositor_manage_screen): Really turn off draw-in-a-loop. 2006-01-15 Kyle Ambroff <kambroff@csus.edu> * src/workspace.c (focus_ancestor_or_mru_window): If no valid window is found in the MRU list, then set focus to the desktop window. (#317405) 2006-01-15 Elijah Newren <newren gmail com> Fix accidental overzealous focus holding by the terminal introduced by the original patch in bug 326159. Windows launched from panel icons, the panel menu, or global keybindings should get focus now. #326159. * src/display.c (meta_display_open, event_callback): * src/display.h (struct MetaDisplay): * src/keybindings.c (process_event): * src/window.c (meta_window_set_user_time): Add a new allow_terminal_deactivation field to MetaDisplay and use it to track whether the user's last action was interaction with the terminal or some outside action (global keybinding, clicking on a dock, etc.) likely to launch a new window. * src/window.c (window_state_on_map): Allow the focus switch from a terminal to something else if allow_terminal_deactiviation is true. * src/keybindings.c (handle_panel_keybinding): Remove some unneeded code. 2006-01-15 Elijah Newren <newren gmail com> Patch from Jens Granseuer to fix more build issues with gcc 2.95. #327050. * src/boxes.c (meta_rectangle_edge_cmp_ignore_type): * src/window.c (meta_window_show): Remove C99 style variable initiailization 2006-01-14 Elijah Newren <newren gmail com> * src/window.c (__window_is_terminal): Don't dereference a NULL string. Fixes #327013. 2006-01-14 Elijah Newren <newren gmail com> * src/compositor.[ch]: fix compilation when HAVE_COMPOSITE_EXTENSIONS is undefined. #326912 Fri Jan 13 16:37:26 2006 Søren Sandmann <sandmann@redhat.com> * src/compositor.c (update): Only update on damage events. 2006-01-13 Elijah Newren <newren gmail com> Patch from Damien Carbery. Fixes #326746. * src/util.c: explicitly #include Xlib.h to fix a compilation issue on Solaris. Fri Jan 13 14:40:19 2006 Søren Sandmann <sandmann@redhat.com> * configure.in: Add a dependency on libcm when building with compositor. * src/window.c (meta_window_hide): Make this function static. * src/window.c (implement_showing): Use meta_compositor_minimize() to do a weird minimize effect. * src/compositor.[ch]: Beginning of new GL based compositor. * src/screen.h (struct _MetaScreen): Add void pointer to compositor data. * src/screen.c (meta_screen_new): Remove obsolete compositor stuff; initialize compositor_data. Don't composite manage screen out of this function. * src/errors.c (x_error_handler): Check that display is non-NULL before using it. Add comment about how that can happen. * src/display.c (meta_display_{begin,end}_grab_op): Remove explicity damage of windows. * src/display.c (meta_display_open): Composite manage all the screens. 2006-01-11 Elijah Newren <newren gmail com> * src/textboxes.c (test_area, test_intersect, test_equal, test_overlap_funcs, test_basic_fitting, test_merge_regions, test_regions_okay, test_region_fitting, test_clamping_to_region, test_clipping_to_region, test_shoving_into_region, test_find_onscreen_edges, test_find_nonintersected_xinerama_edges, test_gravity_resize, test_find_closest_point_to_line): Replace __PRETTY_FUNCTION__ with G_STRFUNC, because lesser compilers don't support the former. Caught by Damien Carbery, fix suggested by Ray Strode. #326281. 2006-01-10 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.13.21 2006-01-10 Elijah Newren <newren@gmail.com> * NEWS: 2.13.13 release 2006-01-10 Elijah Newren <newren@gmail.com> * src/bell.c: * src/boxes.c: * src/boxes.h: * src/constraints.c: * src/core.c: * src/display.c: * src/display.h: * src/edge-resistance.c: * src/frames.c: * src/keybindings.c: * src/main.c: * src/prefs.c: * src/prefs.h: * src/screen.c: * src/screen.h: * src/window.c: * src/window.h: Whoops, I forgot to keep my copyright info updated with my previous commits as Havoc had asked me to do. Doing that now... 2006-01-10 Elijah Newren <newren@gmail.com> Add a raise on click option, basically only because all the major distros are patching it in anyway. See #326156. * src/metacity.schemas.in: add the new gconf key and explanation * src/prefs.[ch] (#define KEY_RAISE_ON_CLICK, static gboolean raise_on_click, update_raise_on_click, meta_prefs_init, change_notify, meta_prefs_get_raise_on_click, meta_preference_to_string): Add all the normal preference handling stuff for this new raise-on-click option. * src/core.c (meta_core_show_window_menu): * src/display.c (event_callback, meta_display_begin_grab_op): * src/window.c (window_activate, meta_window_configure_request, ): Only raise the window if in raise_on_click mode. * src/display.c (meta_display_begin_grab_op, meta_display_end_grab_op, meta_display_check_threshold_reached): * src/display.h (struct MetaDisplay): * src/window.c (meta_window_handle_mouse_grab_op_event): if not in raise-on-click mode only raise on button release if the click didn't start a move or resize operation; needs a few extra MetaDisplay fields to handle this * src/core.c (meta_core_user_lower_and_unfocus): no need to do the MRU shuffling if not maintaining the stacking order == MRU order invariant * src/frames.c (meta_frames_button_press_event): * src/window.c (meta_window_begin_grab_op): remove an unneeded window raising that is already handled elsewhere 2006-01-10 Elijah Newren <newren@gmail.com> Don't "steal" focus from terminal windows for new window mappings as the difference in usage between terminals and other apps seems to suggest this difference in treatment. See #326159 for details, feedback welcome. * src/window.[ch] (__window_is_terminal): New function, currently an ugly hack and should be replaced by a new property set by applications if the behavior works to our liking, (window_state_on_map): don't transfer focus to new windows from terminals unless the new window is a transient of the focused terminal * src/keybindigns.c (handle_panel_keybinding): panel run dialog keybinding should be counted as an explicit transfer of focus to the new window, so override the don't-transfer-focus-from-terminals in this case 2006-01-09 Elijah Newren <newren@gmail.com> More thorough handling of source indication. Part of #326041. * src/window.c (window_activate): new function based off the old meta_window_activate but which also takes source indication into account, (meta_window_active): just call window_activate() with the necessary source indication to get the behavior wanted, (meta_window_client_message): check source indication too for _net_active_window messages * src/window.h (enum MetaClientType): convenience enum for source indication handling 2006-01-09 Elijah Newren <newren@gmail.com> Make the taskbar less flash happy and fix up some related stacking issues. #326035. * src/window.c (windows_overlap): new function, (meta_window_show): if a window is denied focus but doesn't overlap with the focus window there is no need to set the demands attention hint nor stack that window below the focus window, (meta_window_get_outer_rect): we're not modifying the window so declare it to be const 2006-01-09 Elijah Newren <newren@gmail.com> Fix window outline for minimized windows when using alt-esc. #325092. * src/display.c (meta_display_begin_grab_op): Specify the showing type of tabbing operation (Alt tab vs. alt-esc) in addition to the listing type of tabbing operation (docks vs normal windows) to meta_screen_ensure_tab_popup(). * src/display.h (enum MetaTabShowType): new convenience enum * src/screen.[ch] (meta_screen_ensure_tab_popup): require the showing type be specified in addition to the tabbing type; put the outline around the window instead of the icon when in alt-esc mode. 2006-01-09 Elijah Newren <newren@gmail.com> Fix reduced resources resize handling for windows with sizing or resizing constraints. #325774. * src/display.c (meta_display_end_grab_op): Provide constraints.c with the correct gravity information. 2006-01-09 Elijah Newren <newren@gmail.com> Be more strict about what is considered a valid region with partial struts. Fixes #322070. * src/boxes.[ch]: (meta_rectangle_expand_region_conditionally): new function behaving like meta_rectangle_expand_region() but which only does so when the width and height of the rectangles meet a certain threshold (replace_rect_with_list): Remove a compiling warning * src/constraints.c: (constrain_partially_onscreen): provide minimum thresholds in each direction for the size of the rectangles to avoid cases where only a single pixel thick layer of a window might be showing 2006-01-09 Elijah Newren <newren@gmail.com> * src/bell.c (meta_bell_notify_frame_destroy): Use the right function to remove the timeout so that we don't crash if removed at an inopportune time. Fixes #322031. 2006-01-09 Elijah Newren <newren@gmail.com> * src/edge-resistance.c (apply_edge_resistance): Remove the "pull-away" edge resistance. Fixes another of the zillions of issues covered in #321905. 2006-01-09 Elijah Newren <newren@gmail.com> * src/edge-resistance.c (apply_edge_resistance): Revert to the old edge resistance behavior for keyboard movement/resizing based resistance. Not only makes the code much simpler and shorter, but also fixes another of the zillions of issues covered in #321905. 2006-01-09 Elijah Newren <newren@gmail.com> * src/edge-resistance.c (apply_edge_resistance): Remove the timeout resistance at screen/xinerama edges for the whiners. Okay, it made sense. Fixes another of the zillions of issues covered in #321905. 2006-01-09 Elijah Newren <newren@gmail.com> * src/edge-resistance.c (apply_edge_resistance): Make extra timeout edge resistance apply even if one edge already offscreen. Fixes another of the zillions of issues covered in #321905. 2006-01-09 Elijah Newren <newren@gmail.com> Allow edge resistance at both sides of a window and also when edges don't overlap but are a single pixel away from doing so. Fixes one of the zillions of issues covered in #321905. * src/boxes.[ch]: (meta_rectangle_edges_align): new function to handle the overlap or off by one determining whether edge resistance should kick in for an edge. (meta_rectangle_edge_cmp_ignore_type): new function to sort edges but ignore the type so that e.g. left & right edges of windows can be used interchangeably. (meta_rectangle_edge_cmp): now uses meta_rectangle_edge_cmp_ignore_type() to do most the work and just adds an extra condition * src/edge-resistance.c: (find_nearest_position): use meta_rectangle_edges_align() now to determine whether the edges align, (apply_edge_resistance, apply_edge_resistance_to_each_side): have the edge resistance kick in if either the beginning or ending positions would cause overlap in the given direction -- fixes an uncommon but annoying corner case, (apply_edge_snapping, apply_edge_resistance_to_each_side, meta_display_cleanup_edges, stupid_sort_requiring_extra_pointer_dereference, cache_edges): mix edges from both sides now 2006-01-09 Elijah Newren <newren@gmail.com> Plug a few leaks. Fixes #309178. * src/main.c (main): remove an unneeded g_set_prgname() call, free some strings allocated by the GOptions parsing 2006-01-02 Elijah Newren <newren@gmail.com> Patch from Björn Lindqvist to fix a logic error. #322149. * src/window.c (update_resize): && should have been ||. 2006-01-02 Elijah Newren <newren@gmail.com> Patch from Jens Granseuer to fix build with gcc 2.95. #322622. * src/boxes.c (meta_rectangle_region_to_string, meta_rectangle_edge_list_to_string, fix_up_edges): * src/constraints.c (meta_window_constrain, setup_constraint_info, place_window_if_needed, constrain_maximization, constrain_fullscreen, constrain_size_increments, constrain_size_limits, constrain_aspect_ratio, do_screen_and_xinerama_relative_constrai, constrain_to_single_xinerama, constrain_fully_onscreen, constrain_partially_onscreen): * src/edge-resistance.c (find_nearest_position, apply_edge_resistance, apply_edge_resistance_to_each_side): * src/testboxes.c (test_clamping_to_region, test_clipping_to_region, test_shoving_into_region): * src/window.c (meta_window_new_with_attrs, meta_window_apply_session_info, meta_window_resize, meta_window_resize_with_gravity, meta_window_configure_request): Remove C99 style variable initiailization 2006-01-02 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.13.13 2006-01-02 Elijah Newren <newren@gmail.com> * NEWS: 2.13.8 release 2005-12-27 Elijah Newren <newren@gmail.com> Make the workspace switcher work with dual-head (non-xinerama) setups. Fixes #319423. * src/display.c (meta_display_open, event_callback, meta_display_focus_the_no_focus_window): * src/display.h (struct MetaDisplay, meta_display_focus_the_no_focus_window): * src/keybindings.c (primary_modifier_still_pressed): * src/screen.c (meta_screen_new): * src/screen.h (struct MetaScreen): * src/window.c (meta_window_new_with_attrs, meta_window_show): * src/workspace.c (meta_workspace_focus_default_window): Replace display->no_focus_window with a no_focus_window for each screen. * src/display.[ch] (meta_display_xwindow_is_a_no_focus_window, event_callback): * src/window.c (meta_window_new_with_attrs): New utility function, meta_display_xwindow_is_a_no_focus_window(), for checking if the given xwindow is a no_focus_window for one of the screens. 2005-12-27 Elijah Newren <newren@gmail.com> * src/tabpopup.c (meta_ui_tab_popup_new): since the title is going to be treated as markup, escape it. Fixes #324846. 2005-12-13 Kang Jeong-Hee <Keizi@mail.co.kr> * src/compositor.c: replace old call to width and height of MetaScreen struct with rect.width and rect.height. Now compile ok. * src/delete.c: make an int variable into unsigned int. Now compile warning has gone. 2005-12-12 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.13.8 2005-12-12 Elijah Newren <newren@gmail.com> * NEWS: 2.13.5 release 2005-12-12 Elijah Newren <newren@gmail.com> * src/window.c (update_net_frame_extents): make the debugging message actually correspond to the code. Patch from Björn Lindqvist. Fixes #322051. 2005-11-29 Kjartan Maraas <kmaraas@gnome.org> * src/screen.h: Make the wireframe a bit slimmer. Closes bug #320051. 2005-11-24 Davyd Madeley <davyd@fugro-fsi.com.au> * src/window-props.c: display hostname in titlebar for remote X clients. Closes bug #322202. 2005-11-22 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.13.5 2005-11-22 Elijah Newren <newren@gmail.com> * NEWS: 2.13.3 release 2005-11-22 Elijah Newren <newren@gmail.com> Don't allow removing a window from maximized or fullscreened state to place the titlebar under the top panel. Fixes #322075. * src/display.c (handle_net_moveresize_window): fix up previous comments now that I know a little more, modify the code just slightly to clarify that this is NOT a manual user move/resize operation * src/window.c (meta_window_unmaximize, meta_window_unmake_fullscreen, meta_window_shove_titlebar_onscreen): don't claim that these are manual user move/resize operations 2005-11-21 Elijah Newren <newren@gmail.com> * src/constraints.c (constrain_partially_onscreen): Relax the partially onscreen constraint to allow the titlebar to touch the bottom panel in order to make the new constraints code function the same as the old version. Fixes #322071. 2005-11-21 Elijah Newren <newren@gmail.com> * src/constraints.c (place_window_if_needed): When updating the xinerama due to placement, update which maximal/spanning rect set to use as well. Fixes #322068. 2005-11-21 Elijah Newren <newren@gmail.com> * doc/strut-and-related-updating.txt: It took me a little while to figure out how struts & workareas are updated and to learn what all the related functions were used for so I thought I'd clean up my notes and make them available. This will probably be more useful now since regions and edges are also computed and stored at the same time as the workareas. 2005-11-20 Elijah Newren <newren@gmail.com> * src/constraints.c (place_window_if_needed): compute the frame geometry due to maximization only after actually maximizing. Fixes #321902. 2005-11-21 Davyd Madeley <davyd@fugro-fsi.com.au> * src/edge-resistance.c (meta_display_compute_resistance_and_snap): Use GPOINTER_TO_INT() macro instead of cast to allow compilation on 64-bit architectures without warning. 2005-11-19 Elijah Newren <newren@gmail.com> * src/edge-resistance.c (apply_edge_resistance): differentiate between movement towards an edge and movement away from one. Pick smaller constants for movement away from an edge. 2005-11-19 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.13.3 2005-11-19 Elijah Newren <newren@gmail.com> * NEWS: 2.13.2 release 2005-11-18 Elijah Newren <newren@gmail.com> Merge of all the changes on the constraints_experiments branch. This is just a summary, to get the full ChangeLog of those changes (approx. 2000 lines): cvs -q -z3 update -Pd -r constraints_experiments cvs -q -z3 diff -pu -r CONSTRAINTS_EXPERIMENTS_BRANCHPOINT ChangeLog Bugs fixed: unfiled - constraints.c is overly complicated[1] unfiled - constraints.c is not robust when all constraints cannot simultaneously be met (constraints need to be prioritized) unfiled - keep-titlebar-onscreen constraint is decoration unaware (since get_outermost_onscreen_positions() forgets to include decorations) unfiled - keyboard snap-moving and snap-resizing snap to hidden edges 86644 - resize should have a shift option like move does 109553 - gravity w/ simultaneous move & resize doesn't work 113601 - maximize vertical and horizontal should toggle and be constrained 122196 - windows show up under vertical panels 122670 - jerky/random resizing of window via keyboard[2] 124582 - keyboard and mouse snap-resizing and snap-moving erroneously moves the window multidimensionally 136307 - don't allow apps to resize themselves off the screen (*cough* filechooser *cough*) 142016, 143784 - windows should not span multiple xineramas unless placed there by the user 143145 - clamp new windows to screensize and force them onscreen, if they'll fit 144126 - Handle pathological strut lists sanely[3] 149867 - fixed aspect ratio windows are difficult to resize[4] 152898 - make screen edges consistent; allow easy slamming of windows into the left, right, and bottom edges of the screen too. 154706 - bouncing weirdness at screen edge with keyboard moving or resizing 156699 - avoid struts when placing windows, if possible (nasty a11y blocker) 302456 - dragging offscreen too restrictive 304857 - wireframe moving off the top of the screen is misleading 308521 - make uni-directional resizing easier with alt-middle-drag and prevent the occasional super annoying resize-the-wrong-side(s) behavior 312007 - snap-resize moves windows with a minimum size constraint 312104 - resizing the top of a window can cause the bottom to grow 319351 - don't instantly snap on mouse-move-snapping, remove braindeadedness of having order of releasing shift and releasing button press matter so much [1] fixed in my opinion, anyway. [2] Actually, it's not totally fixed--it's just annoying instead of almost completely unusable. Matthias had a suggestion that may fix the remainder of the problems (see http://tinyurl.com/bwzuu). [3] This bug was originally about not-quite-so-pathological cases but was left open for the worse cases. The code from the branch handles the remainder of the cases mentioned in this bug. [4] Actually, although it's far better there's still some minor issues left: a slight drift that's only noticeable after lots of resizing, and potential problems with partially onscreen constraints due to not clearing any fixed_directions flags (aspect ratio windows get resized in both directions and thus aren't fixed in one of them) New feature: 81704 - edge resistance for user move and resize operations; in particular 3 different kinds of resistance are implemented: Pixel-Distance: window movement is resisted when it aligns with an edge unless the movement is greater than a threshold number of pixels Timeout: window movement past an edge is prevented until a certain amount of time has elapsed during the operation since the first request to move it past that edge Keyboard-Buildup: when moving or resizing with the keyboard, once a window is aligned with a certain edge it cannot move past until the correct direction has been pressed enough times (e.g. 2 or 3 times) Major changes: - constraints.c has been rewritten; very few lines of code from the old version remain. There is a comment near the top of the function explaining the basics of how the new framework works. A more detailed explanation can be found in doc/how-constraints-works.txt - edge-resistance.[ch] are new files implementing edge-resistance. - boxes.[ch] are new files containing low-level error-prone functions used heavily in constraints.c and edge-resistance.c, among various places throughout the code. testboxes.c contains a thorough testsuite for the boxes.[ch] functions compiled into a program, testboxes. - meta_window_move_resize_internal() *must* be told the gravity of the associated operation (if it's just a move operation, the gravity will be ignored, but for resize and move+resize the correct value is needed) - the craziness of different values that meta_window_move_resize_internal() accepts has been documented in a large comment at the beginning of the function. It may be possible to clean this up some, but until then things will remain as they were before--caller beware. - screen and xinerama usable areas (i.e. places not covered by e.g. panels) are cached in the workspace now, as are the screen and xinerama edges. These get updated with the workarea in src/workspace.c:ensure_work_areas_validated() 2005-11-14 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.13.2 2005-11-14 Elijah Newren <newren@gmail.com> * NEWS: 2.13.1 release 2005-11-11 Aidan Delaney <a.j.delaney@brighton.ac.uk> * src/tabpopup.h: (struct _MetaTabEntry): * src/tabpopup.c: (meta_ui_tab_popup_new): * src/screen.c: (meta_screen_ensure_tab_popup): Changed the 'minimized' field of the MetaTabEntry struct to 'hidden'. Fixes reopened bug #168455. 2005-10-29 Kjartan Maraas <kmaraas@gnome.org> * src/eventqueue.c: (meta_event_queue_new): Merge fix for bug #320050 from stable. 2005-10-27 Erdal Ronahi <erdal.ronahi@gmail.com> * configure.in: Added ku (Kurdish) to ALL_LINGUAS 2005-10-25 Philip O'Brien <philip.obrien@dal.ca> * src/prefs.c (meta_preference_to_string): add handling for META_PREF_CURSOR_THEME and META_PREF_CURSOR_SIZE for more complete debug info 2005-10-24 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.13.1 2005-10-24 Elijah Newren <newren@gmail.com> * NEWS: 2.13.0 release 2005-10-23 Elijah Newren <newren@gmail.com> Fix edge snapping for multi-screen (non-xinerama) setups. #319425 * src/place.c (get_windows_showing_on_same_screen, get_vertical_edges, get_horizontal_edges): rename get_windows_on_same_workspace() to get_windows_showing_on_same_screen() * src/place.c (get_windows_showing_on_same_screen): exclude windows in the list that are on a different screen 2005-10-20 Elijah Newren <newren@gmail.com> * HACKING: Clarify why METACITY_VERBOSE=1 is bad without META_USE_LOGFILE=1; point to bug 305091 for details. 2005-10-13 Muktha <muktha.narayan@wipro.com> * src/themes/Simple/metacity-theme-1.xml: Make the unfocussed Simple window border visible with high contrast inverse theme. Fixes #121361. 2005-10-08 Elijah Newren <newren@gmail.com> Fix a crash that occurs when removing some virtual desktops and windows happen to be on those desktops. #318306. * src/workspace.c (meta_workspace_relocate_windows): Since windows cannot be on more than one workspace at a time, remove the window from the old workspace before adding it to the new one. 2005-10-08 Elijah Newren <newren@gmail.com> Add my copyright notice to a number of files on which it should already exist. 2005-10-03 Elijah Newren <newren@gmail.com> * src/metacity.schemas.in: clarify the meaning of the auto_raise preference. Fixes one of the issues in #312421. 2005-10-03 Elijah Newren <newren@gmail.com> Patch from Ross Cohen to make alt-esc consistent with alt-tab by leaving stacking of unselected windows unchanged. Fixes #314285. * src/keybindings.c (process_tab_grab): before raising and showing the next candidate, reset the stack positions to what they were at the beginning of the grab 2005-10-03 Elijah Newren <newren@gmail.com> Patch from Ross Cohen to make alt-esc (show windows instantly) actually show minimized windows too. Fixes #107072. * src/keybindings.c (process_tab_grab): initialize tab_unminimized to FALSE for the target window when starting the grab, when advancing through the list check to find the previous window and re-minimize it if it was tab-unminimized, unminimize the new window we're alt-esc'ing to if it's minimized, (do_choose_window): raise and unminimize the initial window as well in alt-esc'ing * src/window.h (struct _MetaWindow): add a tab_unminimized field * src/window.c (meta_window_new_with_attrs): initialize tab_unminimized to false 2005-10-03 Elijah Newren <newren@gmail.com> Branched for Gnome 2.13. :-) * configure.in: bump version to 2.13.0. Add UNSTABLE warning. * README: add 2.13.x to the list of unstable branches 2005-10-03 Elijah Newren <newren@gmail.com> A combination of a couple memory leaks fixes, from Kjartan, Soeren, and I. Fixes #313030. * src/bell.c (meta_bell_flash_screen): call XFreeGC() * src/frames.c (invalidate_cache): free pixels * src/window.c (meta_window_show_menu): call meta_screen_free_workspace_layout() 2005-10-03 Elijah Newren <newren@gmail.com> Patch from Björn Lindqvist fix the workspace switcher tabpopup to display the right windows and to fix the pick-a-new-window-to-focus algorithm in order to not select windows that aren't showing. Fixes #170475. * src/tabpopup.c (meta_convert_meta_to_wnck, meta_select_workspace_expose_event): factor out conversion code from meta_select_workspace_expose_event() into the new meta_convert_meta_to_wnck() function * src/tabpopup.c (meta_select_workspace_expose_event): * src/workspace.c (focus_ancestor_or_mru_window): replace the buggy window->minimized logic with !meta_window_showing_on_its_workspace (window) 2005-10-03 Elijah Newren <newren@gmail.com> Patch from Björn Lindqvist to have ancestors come along with the transient when moving the window from one workspace to another. Fixes #314977. * src/window.c (meta_window_change_workspace): have all ancestors change workspaces too 2005-10-03 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.12.2 2005-10-03 Elijah Newren <newren@gmail.com> * NEWS: 2.12.1 release 2005-10-03 Elijah Newren <newren@gmail.com> Truncate ridiculously long titles to avoid crashing or letting the pager crash. Based on patch from Ray, incorporating suggestions from Havoc and some extensions of my own. Fixes #315070. * src/display.c (set_utf8_string_hint, meta_display_open): * src/xprops.[ch] (meta_prop_set_utf8_string_hint): Move set_utf8_string_hint() to props.[ch], namespace it ("meta_prop_"), and make it public * src/tabpopup.c (utf8_strndup, meta_ui_tab_popup_new): * src/util.[ch] (meta_g_utf8_strndup): Move utf8_strndup() to util.[ch], namespace it ("meta_g_"), and make it public * src/display.c (meta_display_open): * src/display.h (struct _MetaDisplay): add net_wm_visible_name and net_wm_visible_icon_name atoms to the list of atoms we work with * src/window-props.c (set_window_title, set_icon_title): If title length is greater than 512, truncate it and set _NET_WM_VISIBLE_NAME or _NET_WM_VISIBLE_ICON_NAME accordingly 2005-10-03 Elijah Newren <newren@gmail.com> Get the tabbing window outline to work with gtk+ 2.8.4 again. Fixes #317528. * src/tabpopup.c (display_entry): gtk+ 2.8.4 needs to know the mapped state of its windows (see bug 316180), and since we manually map with gdk_window_show_unraised() we need to manually set the mapped state too 2005-09-05 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.12.1 2005-09-05 Elijah Newren <newren@gmail.com> * configure.in: * README: * NEWS: 2.12.0 release 2005-09-04 Danilo Šegan <danilo@gnome.org> * configure.in: Added Armenian (hy) to ALL_LINGUAS. 2005-09-03 Elijah Newren <newren@gmail.com> * HACKING: Add tips on how to more easily get the ids of windows, and how to shorten xprop output. 2005-09-02 Brent Smith <gnome@nextreality.net> * src/place.c: (meta_window_place): Moved the call to meta_screen_get_natural_xinerama_list to earlier in function so that xineramas_list is allocated before find_first_fit is called. Fixes #315000 2005-08-22 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.11.5 2005-08-22 Elijah Newren <newren@gmail.com> * NEWS: 2.11.3 release 2005-08-22 Elijah Newren <newren@gmail.com> * configure.in: Patch from Björn Lindqvist to check for the appropriate versions of glib and gtk. Fixes #314116. 2005-08-12 Elijah Newren <newren@gmail.com> * src/place.c (meta_window_place): Avoid obscuring centered-on-desktop windows which are denied focus. Fixes #313234. 2005-08-08 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.11.3 2005-08-08 Elijah Newren <newren@gmail.com> * NEWS: 2.11.2 release 2005-08-08 Elijah Newren <newren@gmail.com> Patch from Brent Smith to fix a duplicate string. Fixes #309774. * src/theme-parser.c (parse_toplevel_element, parse_draw_op_element): Change "No \"%s\" attribute on element <%s>" string to "No \"%s\" attribute on <%s> element" 2005-08-03 Ray Strode <rstrode@redhat.com> Improve the behavior of keyboard move/resize and edge snapping. Still not perfect, bug 310888. * src/effects.c (draw_xor_rect): Make the outside of a wireframe rectangle line up with the outside edge of its window, instead of centering the wireframe edges on the window edges. * src/keybindings.c (process_keyboard_move_grab): allow edge snapping in wireframe mode. Adjust code to take into account changed semantics of find_next_*_edge functions. (process_keyboard_resize_grab_op_change): new function to take some orthogonal logic out of process_keyboard_resize_grab_op. Only allow keyboard resize cursor to go to flat edges, not corners. (process_keyboard_resize_grab): allow edge snapping in wireframe mode. Fix up snapping logic. * src/place.c (get_{vertical,horizontal}_edges): use GArray instead of int *, since the number of output edges isn't known until the middle of the function now. Use xor rect extents instead of window extends if in wireframe mode. (meta_window_find_next_{vertical,horizontal}_edge: add new source_edge_position parameter to specify which edge on the active window to start from when looking for next edge on the screen. Return the coordinate of the edge found and not the coordinate of where the window should be moved to snap to where the edge was found. * src/window.c (update_move): all the user to specify an edge to resize with mouse in keyboard resize mode. window 2005-08-01 Elijah Newren <newren@gmail.com> * src/metacity.schemas.in: Change default theme from "Simple" to "Clearlooks". 2005-07-31 Elijah Newren <newren@gmail.com> * src/stack.c (is_focused_foreach, get_standalone_layer): use only the expected_focus_window instead of both the focused_window and the expected_focus_window. Removes an infinite flicker loop in sloppy and mouse focus, and an ugly one time flicker in click to focus. Fixes #311400. 2005-07-30 Elijah Newren <newren@gmail.com> Patch from Jaap Haitsma to make sure that Metacity dialogs have icons. Fixes #309876. * src/metacity-dialog.c (kill_window_question, warn_about_no_sm_support, error_about_command): call gtk_window_set_icon_name() to set the dialog icon 2005-07-28 Elijah Newren <newren@gmail.com> * src/place.c (avoid_being_obscured_as_second_modal_dialog): remove some unneeded debug spew that was causing crashes. Fixes #311819. 2005-07-24 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.11.2 2005-07-24 Elijah Newren <newren@gmail.com> * NEWS: 2.11.1 release 2005-07-24 Elijah Newren <newren@gmail.com> * src/place.c (find_most_freespace): try to place windows denied focus near the focus window and fix a xinerama bug with the placement, (avoid_being_obscured_as_a_second_modal_dialog): avoid modal dialogs being obscured in somewhat pathologically strange circumstances that Eclipse seems to be good at triggering, (meta_window_place): have dialog windows make use of avoid_being_obscured_as_a_second_modal_dialog(). Fixes one of the issues found in #307875. 2005-07-24 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_raise): raise the window as well as its ancestor; fixes a stacking bug with an ancestor that has more than one child window. Fixes one of the issues in #307875. 2005-07-24 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_free): restore original window size if the window was maximized, as the FIXME says. ;-) Fixes #137185. Thanks to Christian Persch for the testcase that made this easier to track down. 2005-07-23 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_activate): revert the patch from #128380--change _NET_ACTIVE_WINDOW behavior to what it originally was. 2005-07-18 Matthias Clasen <mclasen@redhat.com> * configure.in: Add checks for Xcursor, to make the changes done on 2005-07-11 effective. 2005-07-14 Elijah Newren <newren@gmail.com> Patch from Ken Harris to provide a more lenient threshold for drawing rounded corners. Fixes #122065. * src/theme.c (meta_frame_layout_calc_geometry): use height + width > 5 instead of height > 3 && width > 3 as criterion 2005-07-13 Elijah Newren <newren@gmail.com> Fix a slight bug (causing possible miscoloring of parts of the titlebar) introduced by the patch from #169982. * src/gradient.c: (meta_gradient_create_interwoven): (meta_gradient_create_multi_vertical): bitshifting operators do not take precedence over typecasting, so make sure to use parentheses to get the right operation order. 2005-07-12 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.11.1 2005-07-12 Elijah Newren <newren@gmail.com> * NEWS: 2.11.0 release 2005-07-12 Elijah Newren <newren@gmail.com> Patch from Andrew Johnson to speed up vertical gradients. Fixes #169982. * src/gradient.c: (meta_gradient_create_interwoven): (meta_gradient_create_vertical): (meta_gradient_create_multi_vertical): use memcpy instead of really long loops to set values in memory to a given pattern. 2005-07-12 Elijah Newren <newren@gmail.com> Patch from Björn Lindqvist to split up main() into more manageable chunks and make use of GOpt. Closes #305331. * src/main.c (usage): remove this function, (meta_print_compilation_info): new function taken from main(), (meta_print_self_identity): new function taken from main(), (struct MetaArguments) new struct to replace some free variables, (meta_parse_options): new funcion taken from main() but now using GOpt, (meta_select_display): new function taken from main() 2005-07-12 Aivars Kalvans <aivars.kalvans@inbox.lv> * src/screen.c (meta_screen_free): free ->xinerama_infos Closes #307884 2005-07-11 Elijah Newren <newren@gmail.com> Stuff I forgot to do when I branched an hour or so ago before Matthias' commit... * configure.in: bump version to 2.11.0. Add UNSTABLE warning. * README: add 2.11.x to the list of unstable branches 2005-07-11 Matthias Clasen <mclasen@redhat.com> React to cursor theme changes: (#308106) * src/prefs.h: * src/prefs.c: Expose the GConf keys for cursor theme and size as preferences META_PREF_CURSOR_THEME and META_PREF_CURSOR_SIZE with getters meta_prefs_get_cursor_theme() and meta_prefs_get_cursor_size(). * src/display.c (meta_display_open): Initialize the cursor theme and size. * src/display.h: * src/display.c (meta_display_set_cursor_theme): New function to change the cursor theme and update all cursors. * src/screen.h * src/screen.c (meta_screen_update_cursor): New function to refesh the root cursor of a screen. * src/main.c (prefs_changed_callback): Update the cursor theme when the cursor preferences change. 2005-06-27 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.10.3 2005-06-27 Elijah Newren <newren@gmail.com> * NEWS: 2.10.2 release Sun Jun 26 11:19:18 2005 Soeren Sandmann <sandmann@redhat.com> * src/frames.c: Add a cache of pixmaps for recently exposed frame areas. Makes metacity a bit faster when dragging windows around. See bug 141813. 2005-06-10 Ryan Lortie <desrt@desrt.ca> * src/frames.c: Prevent using the address of a local variable as a hash key. (Bug #307209) * src/xprops.c (meta_prop_get_values): Fix a small leak in the case of a SYNC_COUNTER property value and HAVE_XSYNC not defined. (Bug #307214) 2005-06-07 Ray Strode <rstrode@redhat.com> Cleanup font data when done with it (bug 306720). * src/effects.c (draw_xor_rect): free font info structure. * src/screen.c (meta_screen_new): pass a 1 not a 0 to XFreeFontInfo to free font info structure. (meta_screen_free): call XUnloadFont on GC font before freeing the GC. 2005-06-02 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_focus): if the window has a modal transient which is being unmanaged, don't focus it. Fixes the Metacity issue reported in #305362. 2005-05-30 Ray Strode <rstrode@redhat.com> Bug 305564 again. When drawing XOR resize popup use "fixed" font instead of -misc-fixed-*-16-* xlfd. Should work on more xservers. Also take steps to fail better if the xserver isn't cooperating. * src/effects.c (draw_xor_rect): if we can't draw font box for whatever reason, at least draw grid frames. * src/screen.c (meta_screen_new): use fixed alias instead of a xfld. Don't pass GCFont to XCreateGC if font couldn't be loaded. Print a warning if font couldn't be loaded. 2005-05-26 Elijah Newren <newren@gmail.com> * HACKING: Add a clarification that METACITY_VERBOSE needs to be accompanied by METACITY_USE_LOGFILE 2005-05-26 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_configure_request): Patch from Greg Hudson to make sure window position is calculated correctly for reconfigure requests when part of the XWindowChanges structure is uninitialized. Fixes #305257. 2005-05-26 Ray Strode <rstrode@redhat.com> Actually commit the stuff mentioned in the last ChangeLog entry. 2005-05-26 Ray Strode <rstrode@redhat.com> Add a resize popup when resizing constrained windows, (bug 305564). * src/display.c: (meta_display_begin_grab_op), (meta_display_end_grab_op): * src/keybindings.c (process_keyboard_move_grab), (process_keyboard_resize_grab): Call meta_window_{begin,update,end}_wireframe convenience functions instead of the meta_effects counterparts. * src/display.h: keep track of old wireframe geometry to clean up xor popup on resize * src/effects.[ch] (meta_effects_begin_wireframe), (meta_effects_update_wireframe), (meta_effects_end_wireframe), (draw_xor_rect): take optional width and height arguments to show to user in resize popup. Draw resize popup if width and height >= 0 and wireframe isn't smaller than the popup would be. * src/screen.c (meta_screen_new): load a largish font for the resize popup * src/window.[ch] (meta_window_move_resize_internal): update wireframe resize popup when the window is resized. (meta_window_get_wireframe_geometry): new function to calculate the numbers to display in resize popup (meta_window_begin_wireframe), (meta_window_update_wireframe), (meta_window_end_wireframe): new functions to reduce repetitive wireframe code. Functions handle updating wireframe and resize popup geometry. (update_move), (update_resize), (meta_window_refresh_resize_popup): remove fixme and add debug message. 2005-05-26 Elijah Newren <newren@gmail.com> * src/window.c (check_maximize_to_work_area): don't accidentally treat maximize vertically as maximize in both directions. Fixes #302204. 2005-05-26 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_new_with_attrs): put all transients of the new window, if any exist, in the calc_showing queue. Fixes #303284. Thanks to Billy Biggs for the testcase that made this easy to track down. 2005-04-11 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.10.2 2005-04-11 Elijah Newren <newren@gmail.com> * NEWS: 2.10.1 release 2005-04-05 Dan Winship <danw@novell.com> * src/metacity-dialog.c (warn_about_no_sm_support): Make sure the "Close" button has the focus, not the table. (#172703) 2005-04-05 Pawan Chitrakar <pawan@nplinux.org> * configure.in: Added ne in ALL_LINGUAS 2005-03-31 Steve Murphy <murf@e-tools.com> * configure.in: Added "rw" to ALL_LINGUAS. 2005-03-17 Lex Hider <Lex.Hider@gmail.com> * doc/Makefile.am (EXTRA_DIST): add doc/code-overview.txt and doc/how-to-get-focus-right.txt 2005-03-10 Adi Attar <aattar@cvs.gnome.org> * configure.in: Added "xh" to ALL_LINGUAS. 2005-03-07 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.10.1 2005-03-07 Elijah Newren <newren@gmail.com> * configure.in: * README: * NEWS: 2.10.0 release 2005-02-28 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.55 2005-02-28 Elijah Newren <newren@gmail.com> * NEWS: Metacity 2.9.34 unstable release 2005-02-28 Elijah Newren <newren@gmail.com> Patch from Aidan Delaney to make sure that icons in the alt-tab popup are dimmed for all hidden windows, not just minimized ones. Fixes #168455. * src/screen.c: (meta_screen_ensure_tab_popup): make use meta_window_showing_on_its_workspace() instead of just checking if the window is minimized. 2005-02-25 Elijah Newren <newren@gmail.com> Prevent the visual bell from changing the focus window. Fixes #123366. * src/bell.c: (meta_bell_flash_screen): if not in click-to-focus mode and mouse_mode is also false, increment the focus sentinel so that we can ignore spurious EnterNotify and LeaveNotify events. * src.display.c: (event_callback): make sure to also ignore LeaveNotify events when the focus sentinel isn't clear 2005-02-23 Elijah Newren <newren@gmail.com> * src/window.c: (meta_window_new_with_attrs): Fix crash that occurs when stupid apps claim that a window is its own parent. #168207 2005-02-21 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.34 2005-02-21 Elijah Newren <newren@gmail.com> * NEWS: Metacity 2.9.21 unstable release 2005-02-21 Elijah Newren <newren@gmail.com> Handle keynav vs. mousenav in mouse and sloppy focus modes. Fixes #167545. * doc/how-to-get-focus-right.txt: Update due to this new method for handling keynav vs. mousenav, plus various other updates that I previously forgot. * src/display.h: (struct _MetaDisplay): add a mouse_mode boolean * src/display.c: (meta_display_open): initialize mouse_mode to true, (event_callback): have EnterNotify and LeaveNotify events set mouse_mode to true when focusing a window * src/keybindings.c: (process_tab_grab): set mouse_mode to false when using alt-tab/alt-esc, (do_choose_window): likewise, (do_handle_move_to_workspace): set mouse_mode to false on move-window-to-workspace-<n> keybindings * src/window.c (idle_calc_showing): if we're in keynav mode while using sloppy or mouse focus, use metacity_sentinel to avoid EnterNotify events being generated from events other than mouse movement. * src/workspace.c (meta_workspace_activate_with_focus): add a FIXME in a potentially duplicate section of code, (meta_workspace_focus_default_window): use the same focus choice as click-to-focus if in keynav mode. 2005-02-20 Elijah Newren <newren@gmail.com> * src/display.c: (event_callback): Handle _NET_CURRENT_DESKTOP messages that come with timestamps. Fixes the metacity portion of #161361 other than the portion handled by #128380. 2005-02-20 Elijah Newren <newren@gmail.com> * src/window.c: (meta_window_activate): when receiving a _NET_ACTIVE_WINDOW message, switch to the desktop where the window is located before activating instead of moving the window to the current desktop. Thanks to Lubos Lunak for catching this issue. Fixes #128380. 2005-02-20 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_show): Ignore all focus and focus-stealing-prevention code in meta_window_show when not showing the window for the first time. Fixes #167199. 2005-02-20 Elijah Newren <newren@gmail.com> Fix an obscure xinerama placement bug with windows that are too large to fit in the workarea in both dimensions. #166757 * src/place.c: (meta_window_place): use the current xinerama instead of arbitrarily resetting to 0 2005-02-20 Elijah Newren <newren@gmail.com> Patch from Joe Marcus Clarke to fix a possible crash on logout. #167935. Thanks for fixing my mistakes, Joe! * src/display.c: (meta_display_open): initialize display->grab_old_window_stacking to NULL. 2005-02-20 Elijah Newren <newren@gmail.com> Big patch to cover about 6 different issues in order to correct rare problems with timestamps (make sure window selected in tasklist actually gets focus, sanity check timestamps to avoid rogue apps hosing the system, correct the updating of net_wm_user_time, correctly handle timestamps of 0 when comparing xserver timestamps for those who have had their systems up for over 25 days or so, add some debugging information to verbose logs, some code cleanups). Fixes all issues listed in #167358. * src/display.h: (struct _MetaDisplay): clarify comment on last_focus_time, introduce a new variable--last_user_time, (XSERVER_TIME_IS_BEFORE macro): put this functionality into a separate macro and then introduce a new macro with this name that uses the old one but adds additional special-case checks for timestamps that are 0, (comment to meta_display_set_input_focus_window): add information about how last_user_time should be used in this function * src/display.c (santiy_check_timestamps): new function, (meta_display_open): intialize display->last_user_time, (meta_display_get_current_time_roundtrip): use the timestamp, which is known to be good, in order to sanity_check_timestamps, (event_callback): use the new meta_window_ste_user_time() function in order to correct problems, use the timestamp of KeyPress and ButtonPress events, which are known to be good, in order to sanity_check_timestamps, (timestamp_too_old): new function for common behavior of meta_display_focus_the_no_focus_window and meta_display_set_input_focus_window, with added checking for display->last_user_time in addition to display->last_focus_time, (meta_display_set_input_focus_window): replace some of the code with a call to timestamp_too_old(), (meta_display_focus_the_no_focus_window): replace some of th ecode with a call to timestamp_too_old() * src/window.h: (meta_window_set_user_time): new function to abstract the many things that need to be done when updating the net_wm_user_time of any window * src/window.c: (meta_window_activate): add debugging spew, make sure the comparison is made with last_user_time NOT last_focus_time, use meta_window_set_user_time() function in order to correct problems, (meta_window_client_message): add a newline to a debugging message to make them easier to read, (meta_window_set_user_time): new function * src/window-props.c (reload_net_wm_user_time): use the new meta_window_ste_user_time() function in order to correct problems 2005-02-16 Elijah Newren <newren@gmail.com> * src/display.c: (event_callback): trivial fix to a log message: change %d to %lu (see debugging log from bug 167358). 2005-02-12 Elijah Newren <newren@gmail.com> Raise the ancestor of a window instead of the window itself. Fixes #166894. * src/window.c: (find_root_ancestor): new function, (meta_window_raise): get the ancestor of the given window and raise it if possible instead of the window 2005-02-12 Elijah Newren <newren@gmail.com> Don't unconditionally place splashscreens (and other not-to-be-focused windows) below the focus window. Fixes #167042. * src/window.c: (intervening_user_event_occurred): new function taken from the timestamp comparison portion of the old window_takes_focus_on_map function, (window_state_on_map): new function with remainder of old window_takes_focus_on_map function that determines both whether the window will take focus and whether it should be placed on top, (meta_window_show): use place_on_top_on_map to determine window stacking instead of trying to infer it from takes_focus_on_map 2005-02-11 Elijah Newren <newren@gmail.com> Avoid new windows being obscured by the focus window (and thus possibly lost). Fixes #166524. * src/place.c: new MetaWindowDirection enum, (find_most_freespace): new function to find where there is the most space available around the focused window, (meta_window_place): if a window is denied focus and the window overlaps the focused window, retry the first-fit algorithm only paying attention to the focus window position and if that fails just find the location on the screen with the most space available. * src/window.h: (struct MetaWindow): new denied_focus_and_not_transient bitfield * src/window.c: (meta_window_new_with_attrs): initialize denied_focus_and_not_transient, (meta_window_show): set and unset the denied_focus_and_not_transient field appropriately 2005-02-08 Aidan Delaney <adelaney@cs.may.ie> Removed useless function call. #166730 * src/tabpopup.c: (outline_window_expose): Removed unused references to variables and an unnecessary function call to gdk_window_get_size(). 2005-02-08 Elijah Newren <newren@gmail.com> Avoid using CurrentTime when focusing, handle it better in case we miss any cases. Fixes #166732. * src/window.c: (meta_window_shade): use meta_display_get_current_time_roundtrip() to ensure we have a valid timestamp, (meta_window_unshade): same * src/display.c: (meta_display_set_input_focus_window): If CurrentTime was passed, get one from the XServer in addition to throwing a warning, (meta_display_focus_the_no_focus_window): same 2005-02-08 Elijah Newren <newren@gmail.com> * src/window.c: (meta_window_activate): If we're not passed a timestamp, make sure to manually get one. Fixes #166728. 2005-02-07 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.21 2005-02-07 Elijah Newren <newren@gmail.com> * NEWS: Metacity 2.9.13 unstable release 2005-02-06 Elijah Newren <newren@gmail.com> Set a _METACITY_VERSION property (a utf8 string) on the WM check window. #165350. * src/display.h: (struct MetaDisplay): add a atom_metacity_version field * src/display.c: (meta_display_open): initialize the _METACITY_VERSION property on the WM check window to the current version of Metacity. 2005-02-06 Elijah Newren <newren@gmail.com> Ignore xconfigurerequest events for stacking when it should be safe to do so. Again, thanks to Crispin Flowerday for the test case. Thanks to KWin for the inspiration (and to Google for indexing their source code). Fixes the other half of #166395. * src/window.c: (meta_window_configure_request): if the active_window is from a separate application than the one getting the configure request and the net_wm_user_time of the active window is later than that of the window getting the configure request, then ignore the request. 2005-02-06 Elijah Newren <newren@gmail.com> If activation requests are too old, set the demands_attention hint instead of actually activating. Thanks to Crispin Flowerday for the test case and for testing the patch. Fixes half of #166395. * src/window.c: (meta_window_activate): if the request came before the last focus time, set the demands attention hint instead 2005-02-04 Dave Ahlswede <mightyquinn@letterboxes.org> * src/metacity.schemas.in: Add period to the end of reduced_resources' description. Fixes #165780. 2005-02-04 Elijah Newren <newren@gmail.com> Make sure window->border_only is initialized so we don't get random windows without decorations. Thanks to Sinisa Segvic and Owen Taylor for providing test cases. Fixes #145131. * src/window.c: (update_mwm_hints): Be sure to call recalc_window_features even if no MWM hints are set 2005-02-02 Elijah Newren <newren@gmail.com> Focus parents of dismissed transient windows in preference to the window that most recently had keyboard focus. Fixes #157360. * doc/how-to-get-focus-right.txt: Note the distinction between "most recently used window" and "most recent to have keyboard focus" that we are now making. * src/workspace.c: (focus_ancestor_or_mru_window): rename from meta_workspace_focus_mru_window, and first check whether we need to focus an ancestor window before looking for the mru window, (record_ancestor): helper function for focus_ancestor_or_mru_window, (meta_workspace_focus_default_window): update due to the function rename from meta_workspace_focus_mru_window to focus_ancestor_or_mru_window 2005-01-31 Elijah Newren <newren@gmail.com> Try 2 to correct misleading and inaccurate wording. Hopefully, really fixes #165380. * src/menu.c: Change wording of menu from "Always on Current Workspace" to "Always on Visible Workspace". "Always on Current Workspace" could sound like a synonym of "Only on This Workspace" when it was supposed to be the opposite. 2005-01-31 Elijah Newren <newren@gmail.com> Correct the stacking when return from fullscreen mode. Fixes #165718. * src/window.c: (meta_window_unmake_fullscreen): Update the layer after resizing the window 2005-01-31 Muktha <muktha.narayan@wipro.com> src/themes/Atlanta/metacity-theme-1.xml: src/themes/Simple/metacity-theme-1.xml: src/themes/Bright/metacity-theme-1.xml: Make the unfocussed title bar distinguishable. Fixes #125291. 2005-01-28 Elijah Newren <newren@gmail.com> Patch from RHEL-3 (Havoc doesn't remember how it got there) that Havoc posted in bug 156511 to fix the problem with fullscreen windows on a different xinerama monitor not staying on top. I updated to HEAD. Should fix #156511. * src/stack.c: (windows_on_different_xinerama): new function, (get_standalone_layer): let windows on a different screen than the one with the focus window stay in the fullscreen layer 2005-01-28 Elijah Newren <newren@gmail.com> * src/metacity-dialog.c: (warn_about_no_sm_support): make this dialog be sticky. Fixes #164745. 2005-01-28 Elijah Newren <newren@gmail.com> Patch from Tim Herold to handle xcomposite pkgconfig version regression. Fixes #149368. * configure.in: Change XCOMPOSITE_VERSION from 1.0 to 0.2 2005-01-28 Elijah Newren <newren@gmail.com> Correct misleading and inaccurate wording. Fixes #165380. * src/menu.c: Change wording of menu to "Always on Current Workspace" from "Put on All Workspaces", remove a quick-key conflict between "On _Top" and "Only on _This Workspace" by switching the latter to "_Only on This Workspace" * src/window.c: Remove a comment that is no longer necessary (since bug 87531 has been fixed) 2005-01-28 Elijah Newren <newren@gmail.com> Take into account the appropriate list of windows when placing a new one. Fixes #165381. * src/place.c: (meta_window_place): use meta_window_showing_on_its_workspace(w) instead of !w->minimzed, also take into account sticky windows * src/window.[ch]: rename window_showing_on_its_workspace to meta_window_showing_on_its_workspace and export it 2005-01-27 Elijah Newren <newren@gmail.com> Plug a pair of leaks. Fixes #165378 * src/place.c: (meta_window_place, get_windows_on_same_workspace): free list returned by meta_display_list_windows. 2005-01-27 Elijah Newren <newren@gmail.com> Treat splashscreens same as other windows for stacking. Fixes #165243. * src/stack.h: (MetaStackLayer enum): remove META_LAYER_SPLASH from the list * src/stack.c: (get_standalone_layer): remove the special casing of META_WINDOW_SPLASHSCREEN 2005-01-27 Elijah Newren <newren@gmail.com> * src/window.c: (set_net_wm_state): shaded windows should not show up in pagers. Fixes #165377. 2005-01-26 Elijah Newren <newren@gmail.com> Stick and unstick transients with their parent automatically. Fixes #152283. * src/window.c: (window_stick_impl, window_unstick_impl): rename from meta_window_stick and meta_window_unstick respectively, (stick_foreach_func): a function to assist calling window_(un)stick_impl on each transient, (meta_window_stick, meta_window_unstick): new functions that call window_stick_impl or window_unstick_impl for the window and each of its transients. 2005-01-26 Elijah Newren <newren@gmail.com> Patch from John Paul Wallington to keep tooltip on screen horizontally for xinerama. Fixes #165261. * src/fixedtip.c: (meta_fixed_tip_show): rename screen_width and screen_height to screen_right_edge and screen_bottom_edge, set them using xinerama info instead of just screen geometry, and use them to determine where to place the tooltip window. 2005-01-26 Arvind Samptur <arvind.samptur@wipro.com> Don't wireframe when accessibility is on, it apparently causes a desktop wide freeze. * src/prefs.[ch] (meta_prefs_init) (change_notify) (update_gnome_accessibility) (meta_preference_to_string) (meta_prefs_get_gnome_accessibility) : Add code to monitor accessibility status. * src/display.c (meta_display_begin_grab_op): Check accessibility status before going ahead with wireframe. Fixes #159538 2005-01-25 Elijah Newren <newren@gmail.com> * src/tabpopup.c: (meta_select_workspace_expose_event): ignore sticky windows for non-active workspaces. Fixes #165259. 2005-01-25 Elijah Newren <newren@gmail.com> * src/window.c: (meta_window_new_with_attrs): set the window state hints _after_ applying session information. Fixes #164677. 2005-01-25 Elijah Newren <newren@gmail.com> Add man pages for metacity-window-demo and metacity-theme-viewer. Man pages from Jose Moya, auto-fu from Dave Ahlswede. (#143513) * doc/man/metacity-theme-viewer.1: * doc/man/metacity-window-demo.1: New man pages * doc/man/Makefile.am: * doc/Makefile.am: * configure.in: Make sure to install the man pages * doc/man/.cvsignore: Silence cvs 2005-01-25 Benjamin Kahn <xkahn@novell.com> New 48x48 default icon as specified in bug #160660 2005-01-25 Elijah Newren <newren@math.utah.edu> Patch from Stephane LOEUILLET in bug #151850. * src/metacity.desktop.in: specify encoding 2005-01-25 Balamurali Viswanathan <balamurali.viswanathan@wipro.com> * src/prefs.c (meta_prefs_init): Get gconf to load the terminal dir so that we get the notifications when the command is changed. Fixes bug #160934 2005-01-25 Elijah Newren <newren@gmail.com> Refuse to focus a window with a modal transient, and focus the transient instead. Fixes #164716. * src/window.c: (get_modal_transient): new function, (meta_window_focus): if the window has a modal transient, make sure it is on the current workspace and then focus it instead. 2005-01-24 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.13 2005-01-24 Elijah Newren <newren@gmail.com> * NEWS: Metacity 2.9.8 unstable release 2005-01-24 Elijah Newren <newren@gmail.com> * src/display.c: (meta_display_begin_grab_op): don't forget to initialize display->grab_old_window_stacking. Thanks to Sebastien Bacher and the bleeding edge Ubuntu users for catching the occasional crash this could cause so quickly, and for verifying that the patch worked (I couldn't duplicate). Fixes #165093. 2005-01-23 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.8 2005-01-23 Elijah Newren <newren@gmail.com> * NEWS: Metacity 2.9.5 unstable release * README: there are more stable releases beyond 2.8.6... 2005-01-23 Elijah Newren <newren@gmail.com> Restore original stacking when aborting an alt-esc window switch operation. Fixes #123576. * src/display.c: (GRAB_OP_IS_WINDOW_SWITCH): new macro, (meta_display_close): clear grab_old_window_stacking if non-NULL, (event_callback): restore stack positions if alt-esc op cancelled with button press, (meta_display_begin_grab_op): store the old stacking positions, (meta_display_end_grab_op): free the old stack positions * src/display.h: (struct _MetaDisplay): add a grab_old_window_stacking list * src/keybindings.c: (process_tab_grab): restore stack positions if alt-esc op cancelled with an errant key press * src/stack.c: (compare_just_window_stack_position): new GCompareFunc function, (meta_stack_get_positions): get current stack positions, (compare_pointers): new GCompareFunc function, (lists_contain_same_windows): simple utility func to see if two lists contains the same windows, (meta_stack_set_positions): new function to set the positions of all the windows in the stack * src/stack.h: (meta_stack_get_postions, meta_stack_set_positions): new functions 2005-01-23 Elijah Newren <newren@gmail.com> Patch from John Paul Wallington to fix #163420. * src/window.c: (check_maximize_to_work_area): fix vertical maximization for second screen 2005-01-21 Elijah Newren <newren@gmail.com> * rationales.txt: Add a tracker bug for modal dialog issues 2005-01-20 Elijah Newren <newren@gmail.com> * src/tabpopup.c (dimm_icon): use pixbuf, not dimmed_pixbuf (which isn't defined yet). Fixes crash from #136666. 2005-01-20 Vincent Noel <vnoel@cox.net> * src/screen.c: (meta_screen_ensure_tab_popup), (meta_screen_ensure_workspace_popup): * src/tabpopup.c: (meta_ui_tab_popup_new), (display_entry): * src/tabpopup.h: Show labels in bold for windows that demand attention. Fixes #164590. 2005-01-18 Vincent Noel <vnoel@cox.net> * src/screen.c: (meta_screen_ensure_tab_popup), (meta_screen_ensure_workspace_popup): * src/tabpopup.c: (dimm_icon), (meta_ui_tab_popup_new), (free_entry): * src/tabpopup.h: In the tab task switcher popup, dim the window icon and put its name between brackets when the window is minimized. Fixes #136666. 2005-01-11 Elijah Newren <newren@gmail.com> Correct highlighting of windows in workspace switcher popup. Fixes #163450. * src/tabpopup.c (meta_select_workspace_expose_event): Remove race between FocusIn/FocusOut events and the expose event by replacing window->has_focus with window==window->display->expected_focus_window. 2005-01-09 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.5 2005-01-09 Elijah Newren <newren@gmail.com> * NEWS: Metacity 2.9.3 unstable release 2005-01-09 Elijah Newren <newren@gmail.com> * src/display.c (meta_display_open): * src/display.h (struct _MetaDisplay): * src/window.c (meta_window_free, meta_window_client_message, meta_window_notify_focus): Remove the hack from bug 128200; it isn't needed anymore with the fix from bug #160470. 2005-01-09 Elijah Newren <newren@gmail.com> Don't focus the panel on click. Fixes #160470 (and 100470 and removes the need for the hack from 128200) * doc/how-to-get-focus-right.txt: Update section on focusing non-decorated windows (specifically, DOCKS and DESKTOPS) * src/display.c (event_callback): don't focus dock windows on click 2005-01-06 Elijah Newren <newren@gmail.com> Make sure the save session dialog appears focused. Fixes #162983. * src/session.c (warn_about_lame_clients_and_finish_inter): Get a timestamp by explicit request from Xserver, since none is available otherwise. 2005-01-06 Leena Gunda <leena.gunda@wipro.com> * src/window.c (meta_window_unmaximize): Restore the wireframe rectangle co-ordinates to saved window co-ordinates. Fixes bug #161236. 2005-01-03 Thomas Fitzsimmons <fitzsim@redhat.com> * src/Makefile.am (install-data-local): Install schema data from builddir not srcdir. 2005-01-02 Elijah Newren <newren@gmail.com> Provide more documentation to make it easier for people to contribute to Metacity. (#162646) * HACKING: Add lots of information to extend this document: more on relevant standards and X properties, lots of information on debugging and testing, and add a list of some other important things to read; also move some information to src/code-overview.txt and organize this file into sections. * doc/code-overview.txt: New file including some small parts from the old HACKING file and lots of new stuff. This file gives a brief overview of some of the bigger structures and files, with guides for a variety of task categories providing places to start looking in the code and things to look for. 2004-12-28 Elijah Newren <newren@gmail.com> Allow users to move the window around immediately after double-clicking to shade (#90290) * src/display.c (event_callback): only end the grab op if either there is no frame or else the frame is not mapped 2004-12-27 Elijah Newren <newren@gmail.com> Focus windows that manually position themselves too (fixes #107347). * src/window.h (struct _MetaWindow): add a new showing_for_first_time flag * src/window.c (meta_window_new_with_attrs): initialize showing_for_first_time flag to !mapped, (meta_window_show): replace did_placement with showing_for_first_time in the section to decided whether to focus since did_placement isn't quite what we want 2004-12-27 Elijah Newren <newren@gmail.com> * src/display.c (meta_display_set_input_focus_window, meta_display_focus_the_no_focus_window): Spew warning if CurrentTime is passed to the function, but don't exit prematurely. (fixes #162353) 2004-12-24 Elijah Newren <newren@gmail.com> * src/window.c (meta_window_show_menu): Don't show menu if all options are invalid (fixes #148915) 2004-12-24 Elijah Newren <newren@gmail.com> * src/window.c (window_takes_focus_on_map): Fix error in distinguishing < vs. <= introduced by the patch in #154598, restructure code so that verbose log matches code better in order ensure such mistakes are harder to make in the future (fixes #162172) 2004-12-24 Elijah Newren <newren@gmail.com> Thanks to mild7@users.sourceforge.net for this fix. * src/window.h: (META_WINDOW_IN_NORMAL_TAB_CHAIN): Excludes windows with skip_taskbar hint set from the alt-tab list; they'll appear in the ctrl-alt-tab list instead. (fixes #106249) 2004-12-22 Elijah Newren <newren@gmail.com> Wrap XSetInputFocus, making display->expected_focus_window a little more reliable (see #154598) * src/display.h: (struct _MetaDisplay): add a large comment about the expected_focus_window, add a last_focus_time field, (XSERVER_TIME_IS_BEFORE): new macro moved from window.c but fixed for 64-bit systems, (meta_display_set_input_focus_window): new function * src/display.c (meta_display_open): initialize last_focus_time, add a comment about brokenness of trying to set intial focus window, (meta_display_set_input_focus_window): new function that wraps XSetInputFocus, (meta_display_focus_the_no_focus_window): make this function closer to a wrapping of XSetInputFocus for the no_focus_window. * src/window.c (XSERVER_TIME_IS_LATER): remove this macro in favor of the improved one added to display.h * src/display.c (meta_display_open): * src/window.c (meta_window_focus): use meta_display_focus_the_no_focus_window and meta_display_set_input_focus instead of XSetInputFocus 2004-12-22 Elijah Newren <newren@gmail.com> * src/core.c (meta_core_user_lower_and_unfocus): * src/display.c (meta_display_get_current_tab): * src/stack.c (get_default_focus_window, meta_stack_list_windows): * src/window.c (set_net_wm_state, meta_window_should_be_showing, implement_showing, meta_window_activate, meta_window_notify_focus): * src/window.h: * src/workspace.c (meta_workspace_list_windows): Rename meta_window_visible_on_workspace to meta_window_located_on_workspace (whether or not the window was showing wasn't taken into account, which made "visible" confusing). Fixes #136314. 2004-12-22 Elijah Newren <newren@gmail.com> Partially resolve the conflicting requirements of windows on multiple workspaces and hidden being a global quantity for windows (fixes bug 156182; the remainder of the work is bug 87531 and is a libwnck issue) * src/display.c (event_callback): * src/window.c (meta_window_visible_on_workspace, meta_window_unstick): * src/workspace.c (meta_workspace_add_window, meta_workspace_contains_window, meta_workspace_queue_calc_showing): * src/workspace.h: Remove meta_workspace_contains_window, replace with simple comparison utilizing window->workspace * src/place.c (meta_window_place): * src/window.c (meta_window_shares_some_workspace): * src/window.h: Remove meta_window_shares_some_workspace, replace with a simple comparison utilizing window->workspace * src/session.c (save_state), * src/window.c (meta_window_new_with_attrs, meta_window_apply_session_info, meta_window_free, window_showing_on_its_workspace, meta_window_change_workspace_without_transients, meta_window_unstick, meta_window_set_current_workspace_hint, meta_window_get_workspaces): * src/window.h: * src/workspace.c (meta_workspace_free, meta_workspace_add_window, meta_workspace_remove_window): Only one workspace now 2004-12-20 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.3 2004-12-20 Elijah Newren <newren@gmail.com> * NEWS: Metacity 2.9.2 unstable release 2004-12-20 Elijah Newren <newren@gmail.com> * configure.in: re-add the note about Fibonacci sequence micro version numbers that was lost with 2.8.5 2004-12-19 Elijah Newren <newren@gmail.com> Thanks to Baptiste Mille-Mathias for this fix. * src/metacity.schemas.in: Add a missing period at the end of a sentence. 2004-12-19 Elijah Newren <newren@gmail.com> When snap-moving, don't snap to transients of minimized windows since they are hidden. Fixes #157180 * src/place.c (get_windows_on_same_workspace): make the logic to determine hidden windows more thorough by calling meta_window_should_be_showing() * src/window.c (meta_window_should_be_showing): rename this function from window_should_be_showing and also export it, (implement_showing): s/window_should_be_showing/meta_window_should_be_showing/, (idle_calc_showing): s/window_should_be_showing/meta_window_should_be_showing/ * src/window.h (meta_window_should_be_showing): Add this function to the list so that it can be used in src/place.c 2004-12-19 Elijah Newren <newren@gmail.com> Focus the desktop when showing it. Fixes #159257. * src/display.c (event_callback): obtain a timestamp to pass to meta_screen_show_desktop * src/keybindings.c (handle_toggle_desktop): obtain a timestamp to pass to meta_screen_show_desktop * src/screen.c (meta_screen_show_desktop): add a timestamp parameter, get the most recently used window of type DESKTOP (if there is one) and focus it * src/screen.h (meta_screen_show_desktop): add a timestamp parameter 2004-12-19 Elijah Newren <newren@gmail.com> Thanks to ash@contact.bg for this fix. * po/POTFILES.in: Remove reference to metacity-properties.* files since Alex removed them in his 2004-12-07 commit. 2004-12-13 Elijah Newren <newren@gmail.com> * configure.in: post-release version bump to 2.9.2 that I forgot to do last week (oops) 2004-12-07 Alex Duggan <aldug@astrolinux.com> * configure.in: * src/tools/Makefile.am: Remove deprecated capplet from GNOME 2.0 * src/tools/metacity-properties.c: * src/tools/metacity-properties.desktop.in: * src/tools/metacity-properties.glade: * src/tools/metacity-properties.png: Removed from cvs 2004-12-06 Elijah Newren <newren@math.utah.edu> * NEWS: Metacity 2.9.1 unstable release 2004-12-06 Benjamin Kahn <xkahn@novell.com> * src/default_icon.png: Use a better default application icon. Fixes bug #160373 2004-11-16 Marco Pesenti Gritti <marco@gnome.org> * src/Makefile.am: Fix build out of src directory. Bug #158325 2004-11-10 James Henstridge <james@jamesh.id.au> * Makefile.am (DISTCLEANFILES): remove intltool stuff on distclean. * src/themes/Makefile.am (uninstall-local): add uninstall rule. * src/Makefile.am (libmetacity_private_la_CFLAGS): set this variable so that the files shared with metacity get compiled with different names. * configure.in: use more modern macros in some places, and make sure that $ACLOCAL_AMFLAGS is set so that rebuilds work better. * autogen.sh (conf_flags): use newer automake. 2004-11-06 Vincent Untz <vincent@vuntz.net> * src/metacity.schemas.in: gnome-panel-screenshot was renamed to gnome-screenshot 2004-11-01 Elijah Newren <newren@math.utah.edu> * configure.in: bump version to 2.9.1 2004-11-01 Elijah Newren <newren@math.utah.edu> * NEWS, README: Metacity 2.9.0 (unstable release) 2004-10-25 Elijah Newren <newren@math.utah.edu> Don't lower newly mapped windows when they're denied focus, if they are transients of the focused window. Instead, defocus the currently focused window. (fixes #151996). (Also, reenable focus stealing prevention and do a small spacing cleanup) * src/window-props.c (init_net_startup_id): fix spacing * src/window.c (window_takes_focus_on_map): re-enable focus stealing prevention, (meta_window_show): if the new window is denied focus and is a transient of the currently focused window, defocus the currently focused window but keep the transient on top; remove some old code about transients and focus; make sure that EnterNotify events won't accidentally focus the new window. 2004-10-25 Elijah Newren <newren@math.utah.edu> Fix the alt-tab order--if the most recently used window is not focused, start alt tabbing with that window instead of the one after it (fixes #156251) * src/display.c (find_tab_forward): add a skip_first parameter, (find_tab_backward): add a skip_last parameter, (meta_display_get_tab_next): if a beginning window wasn't given and the focused window isn't the tab chain, don't skip the MRU window 2004-10-22 Elijah Newren <newren@math.utah.edu> Update _NET_WM_STATE_HIDDEN so the pager on the panel will know whether to display windows as visible or hidden (#105665) * src/screen.c (queue_windows_showing): Revert the queue_windows_showing portion of the patch committed on 2004-10-16 for #142198--it was an ill-advised optimization. * src/window.c (window_showing_on_its_workspace, window_should_be_showing): split the old window_should_be_showing into these two functions, (set_net_wm_state): hidden state is more complex; use window_showing_on_its_workspace to determine the correct value 2004-10-20 Elijah Newren <newren@math.utah.edu> Patch from Soeren to fix the modifier key breakage introduced by an Xorg change. (fixes #151554) * src/keybindings.c: include X11/XKBlib.h if available, (handle_spew_mark): remove this unused function declaration, (end_keyboard_grab): new function, uses XKB if available, (process_tab_grab): use end_keyboard_grab to determine whether to end the grab, (error_on_command): make key a const char *, (process_workspace_switch_grab): use end_keyboard_grab to determine whether to end the grab 2004-10-19 Anders Carlsson <andersca@gnome.org> * src/frame.c: (meta_window_ensure_frame): Don't try to use an ARGB visual at all if the depth isn't 32-bit. This caused major slowdowns with Composite enabled. 2004-10-16 Elijah Newren <newren@math.utah.edu> Make the "showing desktop" mode be per-workspace instead of per-screen. (fixes #142198) * src/keybindings.c (handle_toggle_desktop): access showing_desktop through the active workspace * src/screen.c (meta_screen_new): remove initialization of screen->showing_desktop, (meta_screen_update_showing_desktop_hint): rename and make not static and access showing_desktop through the active workspace, (queue_windows_showing): replace meta_display_list_windows() with screen->active_workspace->windows, (meta_screen_minimize_all_on_active_workspace_except): renamed from meta_screen_minimize_all_except since it now only works on the active workspace, (meta_screen_show_desktop, meta_screen_unshow_desktop): access showing_desktop through the active workspace * src/screen.h (struct _MetaScreen): remove showing_desktop field, (meta_screen_minimize_all_on_active_workspace_except): rename from meta_screen_minimize_all_except, (meta_screen_update)_showing_desktop_hint): export this function too * src/window.c (maybe_leave_show_desktop_mode): access showing_desktop through the active workspace and use new name for meta_screen_minimize_all_on_active_workspace_except, (window_should_be_showing): access showing_desktop through the active workspace * src/workspace.c (meta_workspace_new): initialize workspace->showing_desktop, (meta_workspace_activate_with_focus): add note that old can be NULL, update showing_desktop_hint if different on this workspace than the previous one * src/workspace.h (struct _MetaWorkspace): add showing_desktop field 2004-10-16 Elijah Newren <newren@math.utah.edu> * rationales.txt: Add new tracker bugs 2004-10-15 Elijah Newren <newren@math.utah.edu> * src/keybindings.c (reload_keymap): Fix from Rob to correct requested number of keycodes (#155247) 2004-10-13 Elijah Newren <newren@math.utah.edu> Code cleanup * src/window.c (is_in_dock_group, docks_at_end_cmp, shuffle_docks_to_end): removed functions, (meta_window_notify_focus): no need to call is_in_dock_group or shuffle_docks_to_end because of the patch from #120100 that was committed. 2004-10-13 Vincent Untz <vincent@vuntz.net> Add a keybinding to launch a terminal * src/keybindings.c: (handle_run_terminal): new function, (error_on_generic_command): new function, (error_on_command): wrapper around error_on_generic_command(), (error_on_terminal_command): new function * src/metacity.schemas.in: add run_command_terminal key * src/prefs.[ch]: (meta_prefs_init): cache the terminal command and register a gconf callback to update it, (change_notify): handle the notification of terminal command changes, (meta_preference_to_string): add the terminal command case, (update_terminal_command): new function, (meta_prefs_get_terminal_command): new function, (meta_prefs_get_gconf_key_for_terminal_command): new function 2004-10-11 Rob Adams <readams@readams.net> * configure.in: bump version to 2.9.0. Add UNSTABLE warning. 2004-10-11 Rob Adams <readams@readams.net> * NEWS, README: Metacity 2.8.6 (stable release) 2004-10-08 Elijah Newren <newren@math.utah.edu> Fix middle-frame-click-to-lower focus inconsistency (#154601) * src/core.c (meta_core_user_lower_and_unfocus): focus the default window in all focus modes, not just click-to-focus (EnterNotify events will not handle this case for sloppy and mouse focus) * src/display.c (event_callback): replace window->has_focus with window == display->expected_focus_window to avoid a race issue 2004-10-08 Elijah Newren <newren@math.utah.edu> Alter the meaning of expected_focus_window; doesn't affect current operation but assists in fixing some other bugs (#154598) * src/display.c (meta_display_focus_the_no_focus_window): set the expected_focus_window to NULL. * src/window.c (meta_window_notify_focus): don't NULL the expected_focus_window when that window receives a FocusIn event 2004-10-04 Elijah Newren <newren@math.utah.edu> * src/display.c (event_callback): if the root window gets focused, set the focus to the default window; this fixes the "focus-follows-mouse" behavior seen for click-to-focus mode after cancelling log out (fixes #153220) 2004-10-04 Elijah Newren <newren@math.utah.edu> Fix a variety of issues with autoraise (#134206) * src/display.h: (struct _MetaDisplay): add an autoraise_window parameter * src/display.[hc] (meta_display_focus_the_no_focus_window): new function, (meta_display_queue_autoraise_callback): new function, (meta_display_remove_autoraise_callback): new function * src/display.c (meta_display_open): intialize display->autoraise_window too, (meta_display_close): remove any pending autoraise callback, (window_raise_with_delay_callback): clear out auto_raise->display->autoraise_window too, (event_callback): call meta_display_queue_autoraise_callback instead of having the code inline, call meta_display_focus_the_no_focus_window to handle focusing that window * src/window.c (meta_window_focus): If there's a window with an autoraise timeout that isn't the window being focused, remove the autoraise timeout * src/workspace.c (meta_workspace_focus_default_window): If no autoraise timeout is queued for the given window then queue one now, call meta_display_focus_the_no_focus_window to handle focusing that window, (meta_workspace_focus_mru_window): call meta_display_focus_the_no_focus_window to handle focusing that window 2004-10-04 Elijah Newren <newren@math.utah.edu> * src/display.c (event_callback): When no window becomes focused, focus the default window instead of punting to the no_focus_window. Also, change the warning to a verbose message--this will happen frequently due to brain-damage in the X protocol. (see #125492) 2004-10-04 Elijah Newren <newren@math.utah.edu> Fix a variety of focus race conditions in all focus modes, or at least make them harder to trigger (fixes #152000) * src/core.[ch] (meta_core_user_lower_and_unfocus): add a timestamp parameter; pass it along to meta_workspace_focus_default_window * src/display.[ch] (meta_display_get_current_time_roundtrip): new function * src/display.c (event_callback): pass a timestamp to the meta_workspace_activate and meta_workspace_focus_default_window function calls * src/frames.c (meta_frames_button_press_event): pass a timestamp to meta_core_user_lower_and_unfocus * src/keybindings.c (handle_activate_workspace): pass a timestamp to meta_workspace_activate, (process_workspace_switch_grab): pass a timestamp to meta_workspace_focus_default_window and meta_workspace_activate, (handle_toggle_desktop): pass a timestamp to meta_workspace_focus_default_window, (do_handle_move_to_workspace): pass a timestamp to meta_workspace_activate_with_focus, (handle_workspace_switch): meta_workspace_activate * src/screen.c (meta_screen_new): pass a timestamp to meta_workspace_activate * src/window.c (meta_window_free): pass a timestamp to meta_workspace_focus_default_window, (idle_calc_showing): don't increment the focus sentinel here, (meta_window_minimize): pass a timestamp to meta_workspace_focus_default_window, (meta_window_client_message), pass a timestamp to meta_workspace_focus_default_window * src/workspace.h (meta_workspace_activate): add timestamp parameter, (meta_workspace_activate_with_focus): add timestamp parameter, (meta_workspace_focus_default_window): add timestamp parameter * src/workspace.c (meta_workspace_focus_mru_window): make this function take a timestamp and use it for meta_window_focus or XSetInputFocus, (meta_workspace_activate_with_focus): make this function take a timestamp and pass it along to meta_window_focus and meta_workspace_focus_default_window, (meta_workspace_activate): make this function take a timestamp and pass it to meta_workspace_activate_with_focus), (meta_workspace_focus_default_window): make this function take a timestamp, warn if its 0 but try to handle that case sanely, and pass the timestamp on to meta_window_focus or meta_workspace_focus_mru_window or XSetInputFocus 2004-09-22 Elijah Newren <newren@math.utah.edu> * src/keybindings.c (process_workspace_switch_grab): Focus the default window after the user dismisses the workspace switcher popup (fixes #123803; note that an alternate fix was made independently by David Baron for sloppy and mouse focus users) 2004-09-22 Elijah Newren <newren@math.utah.edu> Fix some uninitialized variable errors reported by valgrind (see #153338) * src/display.c (meta_display_open): initialize display->grab_resize_timeout_id, and display->grab_have_keyboard * src/ui.c (meta_ui_create_frame_window): initialize attrs.width and attrs.height 2004-09-17 Elijah Newren <newren@math.utah.edu> * src/workspace.c (meta_workspace_focus_mru_window): Don't focus a window that is minimized (fixes #147947) 2004-09-17 Kjartan Maraas <kmaraas@gnome.org> * src/bell.c: (meta_bell_flash_screen): * src/compositor.c: * src/effects.c: (meta_effects_draw_box_animation): * src/fixedtip.c: (meta_fixed_tip_show): * src/frame.c: (find_argb_visual): * src/frames.c: (unsigned_long_hash), (meta_frames_manage_window), (meta_frames_apply_shapes): * src/iconcache.c: (find_largest_sizes), (find_best_size): * src/keybindings.c: (meta_spawn_command_line_async_on_screen): * src/main.c: (main): * src/menu.c: (meta_window_menu_new): * src/prefs.c: (meta_prefs_get_visual_bell), (meta_prefs_bell_is_audible), (meta_prefs_get_visual_bell_type), (meta_prefs_get_action_double_click_titlebar), (meta_prefs_get_auto_raise), (meta_prefs_get_auto_raise_delay), (meta_prefs_get_reduced_resources): * src/screen.c: (meta_create_offscreen_window): * src/tabpopup.c: (meta_ui_tab_popup_get_selected): * src/theme-parser.c: (meta_theme_load): * src/theme.c: (meta_gtk_widget_get_font_desc): * src/tools/metacity-mag.c: (mouse_press), (begin_area_grab): * src/util.c: (meta_unsigned_long_hash): A load of fixes of issues reported by sparse. Closes bug #152849 2004-09-15 Elijah Newren <newren@math.utah.edu> * src/display.c (event_callback): Remove some redundant code regarding focusing the default window (#152117) 2004-09-15 Elijah Newren <newren@math.utah.edu> Patch from Ken Harris in #135786 to focus a new default window when lowering via middle-click on the frame. * src/core.[hc], src/frames.c: rename meta_core_user_lower to meta_core_user_lower_and_unfocus * src/core.c (meta_core_user_lower_and_unfocus): if in click-to-focus mode then also move the window to the back of the mru list and focus the new default window for the active workspace 2004-09-15 Elijah Newren <newren@math.utah.edu> Focus the no_focus_window if no suitable window is in the mru list (should fix the almost contrived extra issue found in #147475) * doc/how-to-get-focus-right.txt: We no longer need to lie about only focusing panels upon explicit request. * src/workspace.c: (meta_workspace_focus_top_window): removed this function--it was more code than needed and was unreliable anyway, (meta_workspace_focus_mru_window): if a suitable window isn't in the mru list, focus the no_focus_window instead of calling focus_top_window. 2004-09-15 Elijah Newren <newren@math.utah.edu> Prevent focus inconsistencies by only providing one focus method (fixes #151990) * src/screen.c (meta_screen_show_desktop): remove call to meta_workspace_focus_top_window (it was merely focusing a window that was going to be hidden anyway, and likely the one that already had focus) * src/workspace.[hc]: remove meta_workspace_focus_mru_window and meta_workspace_focus_top_window from workspace.h, make them static functions in workspace.c 2004-09-15 Elijah Newren <newren@math.utah.edu> Remove race condition for focus window choice on window close followed by rapid mouse movement in sloppy and mouse focus modes (partially fixes #152000) * src/window.c (meta_window_free): Don't increment the focus sentinel for windows being freed, (idle_calc_showing): don't increment the focus sentinel for windows being minimized 2004-09-15 Elijah Newren <newren@math.utah.edu> Fix unwanted loss of focus to the mouse window when using keynav (fixes #101190) * src/display.c (event_callback): Ignore EnterNotify events with xcrossing.mode of either NotifyGrab or NotifyUngrab 2004-09-15 Elijah Newren <newren@math.utah.edu> Focus correct window after minimizing via the tasklist (fixes #128200; see also #107681) * src/display.h (struct _MetaDisplay): track the previously_focused_window * src/display.c (meta_display_open): initialize previously_focused_window * src/window.c (meta_window_free): clear the previously_focused_window if it's being freed, (meta_window_client_message): if we get a request to minimize the previously_focused_window and the focus_window is a dock or the desktop, focus the default window, (meta_window_notify_focus): update the previously_focused_window 2004-09-13 Rob Adams <readams@readams.net> * configure.in: post-release increment 2004-09-13 Rob Adams <readams@readams.net> * configure.in: bump version number * NEWS: 2.8.5 release * README: 2.8.5 release 2004-09-14 Gora Mohanty <gmohanty@cvs.gnome.org> * configure.in: Added 'or' to ALL_LINGUAS. 2004-09-07 Elijah Newren <newren@math.utah.edu> Add a new write-up on making window focus consistent (see #152004) * doc/how-to-get-focus-right.txt: New document * rationales.txt: Remove references to focus bugs, instead point to doc/how-to-get-focus-right.txt 2004-09-06 Elijah Newren <newren@math.utah.edu> * rationales.txt: Add bugs regarding window focus 2004-08-29 Elijah Newren <newren@math.utah.edu> * NEWS: 2.8.4 release 2004-08-29 Elijah Newren <newren@math.utah.edu> * src/window.c (window_takes_focus_on_map): Disable focus-stealing-prevention for now; there are still some issues and hard code freeze is tomorrow...so this will have to wait until Gnome 2.10. 2004-08-27 Havoc Pennington <hp@redhat.com> * src/compositor.c (meta_compositor_new): disable NameWindowPixmap stuff always for now, it seemed kind of busted (paint_screen): don't grab the server during repaint, adds to the speed, though only slightly. * src/frames.c (meta_frames_set_window_background): factor out all the set_background stuff to one function; disable setting background to transparent, because it breaks existing themes. We need to add a flag in the theme XML file to say "start me with a transparent background" 2004-08-27 Elijah Newren <newren@math.utah.edu> Prevent an assertion failure that can occur after increasing the number of workspaces; also fix a warning and stacking order when a window is denied focus (fixes #150615) * src/window.c (meta_window_stack_just_below): the position of the window should be set equal to that of the one we want to be below, not 1 lower than that number * src/workspace.c (maybe_add_to_list): new function to add on_all_workspace windows to an mru_list, (meta_workspace_new): call maybe_add_to_list for all windows on the screen in order to initialize the mru_list 2004-08-26 Havoc Pennington <hp@redhat.com> * src/frame.c: delete extra copy of find_argb_visual so things compile * src/compositor.c (HAS_NAME_WINDOW_PIXMAP): copy the XCompositeNameWindowPixmap() stuff from xcompmgr, though I can't say I really know what it's supposed to help with (painting the window border?) 2004-08-26 Havoc Pennington <hp@redhat.com> * src/frame.c, src/theme.c: couple of cosmetic tweaks from resolving my local patch with the bugzilla patch from the 8-19 entry below 2004-08-26 Havoc Pennington <hp@redhat.com> * configure.in: move the have_xrender variable initialization up in the file since it can be set as part of composite check 2004-08-19 Havoc Pennington <hp@redhat.com> Fixes from Rich Wareham * src/display.h (struct _MetaDisplay): add render extension check to the display * src/display.c: check for render * configure.in: don't build compositing manager by default, don't want any nasty surprises; check for render separately from compositing manager * src/frame.c: use an ARGB visual when available for the window frame, so we can be all cool-ass 2004-08-25 Elijah Newren <newren@math.utah.edu> Make dialogs that Metacity shows follow focus-stealing-prevention conventions. (fixes one issue in #149028; see comments 47-54) * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func): Make callback functions take a timestamp arg, (delete_ping_timeout_func): pass the timestamp to metacity-dialog * src/display.c (meta_display_ping_timeout): add a timestamp to the call to the ping_timeout_func, (meta_display_ping_window, process_pong_message): add a timestamp to the call to the ping_reply_func * src/display.h (MetaWindowPingFunc typedef): add a timestamp to this function typedef * src/keybindings.c (error_on_command): require a timestamp and pass the timestamp on to metacity-dialog, (handle_run_command): pass a timestamp to error_on_command * src/metacity-dialog.c (copy_of_gdk_x11_window_set_user_time): new function (temporary; only for use while using gtk+-2.4), (kill_window_question, warn_about_no_sm_support, error_about_command): make these functions take a timestamp and call copy_of_gdk_x11_window_set_user_time, (main): require the first two args to the program to be "--timestamp <timestamp>" * src/session.c (warn_about_lame_clients_and_finish_inter): pass a timestamp of 0 to metacity-dialog to prevent focus (it's a popup not generated by and kind of user request). Fri Aug 20 12:54:12 2004 Soeren Sandmann <sandmann@daimi.au.dk> * src/display.c (meta_display_end_grab_op): Move wireframe code before grab is released to prevent endless loops with fullscreen windows. 2004-08-18 Havoc Pennington <hp@redhat.com> * src/display.h (struct _MetaDisplay): track the last_xor_rect separately from the current window size, and then use that to paint the wireframe including the frame, and taking into account shaded windows. * src/window.c (meta_window_get_xor_rect): new function to compute the xor rect; it is not really 100% right, because it uses the frame dimensions from the window at the start of the move/resize. But probably won't break in practice. 2004-08-17 Christian Rose <menthos@menthos.com> * configure.in: Added "bs" to ALL_LINGUAS. 2004-08-16 Kjartan Maraas <kmaraas@gnome.org> * configure.in: Added nb to ALL_LINGUAS. 2004-08-15 Rob Adams <readams@readams.net> * configure.in: Bump version to 2.8.4 2004-08-15 Rob Adams <readams@readams.net> * NEWS: 2.8.3 release 2004-08-15 Rob Adams <readams@readams.net> * src/windows.c (meta_window_update_struts): use height and top/bottom struts to compute gap (copy/paste bug). 2004-08-15 Rob Adams <readams@readams.net> * src/window.c (meta_window_update_struts): Allow struts larger than 1/2 the screen width/height, as long as there's a minimum sized gap between them. Patch from Bill Haneman <billh@gnome.org> for bug #144126. 2004-08-13 Gurban M. Tewekgeli <gmtavakkoli@yahoo.com> * po/tk.po: Added Turkmen translation. * configure.in: Added "tk" to ALL_LINGUAS. Mon Aug 9 05:38:33 2004 Soeren Sandmann <sandmann@daimi.au.dk> * src/effects.c (graphics_sync): New function. * src/effects.c (effects_draw_box_animation_timeout): Use it here to synchronize with the hardware between each frame. 2004-08-08 Rob Adams <readams@readams.net> * src/window.c (meta_window_move_resize_internal): Add #ifdef around XSYNC code; fixes compile problem if XSYNC is disabled. Path for #149314 from Peter O'Shea and independently Mike Castle. Sun Aug 8 14:20:00 2004 Soeren Sandmann <sandmann@daimi.au.dk> * src/frame.c (meta_frame_set_screen_cursor): Flush after setting cursor. (Rest of #149413). 2004-08-07 Elijah Newren <newren@math.utah.edu> * src/display.c (event_callback): activating the current workspace should be a no-op. This prevents a race condition in focus window choice when activating a window via the taskbar. Fix for #149589. 2004-08-07 Elijah Newren <newren@math.utah.edu> * src/window.c, src/window.h: Revert Rob's 2004-07-31 patch that ignored net_wm_user_time when unminimizing a window * src/window.c (meta_window_activate): If a nonzero timestamp is passed, update the window's net_wm_user_time accordingly. (see comments 102-108 of bug 118372) 2004-08-07 Rob Adams <readams@readams.net> Remove some extraneous items that could sometimes appear in the window menu. Fix for #144493. * src/menu.c (menuitems): Change the second separator to key on whether there are any workspaces. (meta_window_menu_new): use NULL label instead of 0 op to identify separator * src/window.c (meta_window_show_menu): Change the conditions on the directions to take into account "holes" in the workspace layout and also only set META_MENU_OP_WORKSPACES when there's more than one workspace. 2004-08-07 Havoc Pennington <hp@redhat.com> * src/screen.c (meta_screen_set_cursor): add XFlush() after setting cursor, #149413 2004-08-06 Elijah Newren <newren@math.utah.edu> * src/display.c (event_callback): Focusing a window upon unshowing the desktop in various ways (panel applet or keybinding) was inconsistent for sloppy and click focus modes. Fix this by calling meta_workspace_focus_default_window after unshowing the desktop via a _NET_SHOWING_DESKTOP message. (resolves #149543) 2004-08-06 Elijah Newren <newren@math.utah.edu> * src/workspace.c (meta_workspace_focus_default_window): prevent keyboard from "getting locked" upon workspace switch, by making sure that the no_focus_window has focus if no other window does. (fixes #147475) 2004-08-05 Elijah Newren <newren@math.utah.edu> Have newly mapped windows that are denied focus appear after the focused window in the alt-tab list. This allows one to switch to such a window with a single alt-tab press. (fixes #149366) * src/window.c (ensure_mru_position_after): new function, (meta_window_show): If newly mapped window is denied focus, call ensure_mru_position_after to make the window appear after the focus window in the mru list. 2004-08-05 Elijah Newren <newren@math.utah.edu> * src/window.c (meta_window_stick): prepend window to mru list instead of appending, since making the window sticky should imply that it is the most recently used, not the least recently. (fixes #149369) 2004-08-04 Elijah Newren <newren@math.utah.edu> * configure.in: post-release version bump (2.8.3) that I forgot to do yesterday. 2004-08-03 Elijah Newren <newren@math.utah.edu> Released 2.8.2 * NEWS, README: update 2004-08-02 Elijah Newren <newren@math.utah.edu> Fix some bugs (reported in #120100) regarding the focus window when using the workspace switcher. * src/display.c (event_callback): When switching workspaces due to a _NET_CURRENT_DESKTOP message, make sure to focus the default window as well. * src/workspace.c (meta_workspace_focus_default_window, meta_workspace_focus_mru_window): Make DOCK or DESKTOP windows have lower priority than others when choosing a window to focus. (For the former function, this means don't focus them at all; for the latter, this means only focus them (via the meta_workspace_focus_top_window call) if no other mru window can be found.) 2004-07-31 Rob Adams <readams@readams.net> Fix bug that caused windows to not be focused on unminimizing because of user time support. * src/window.c (meta_window_new_with_attrs): initialize focus_despite_user_time bit (window_takes_focus_on_map): focus if focus_despite_user_time despite user time, interestingly enough (meta_window_show): reset focus_despite_user_time after showing * src/window.h (_MetaWindow): add focus_despite_user_time bit 2004-07-31 Rob Adams <readams@readams.net> Fix some support for EWMH hints, and fix USER_TIME support to include the DEMANDS_ATTENTION hint. Also includes some code for implementing _NET_RESTACK_WINDOW and _NET_MOVERESIZE_WINDOW, but this is disabled pending feature thaw. * COMPLIANCE: update with new information * src/display.c (meta_display_open): add new hints to list * src/display.h (_MetaDisplay): Add new atoms to struct * src/screen.c (set_supported_hint): update the list of support hints. (set_desktop_viewport_hint): new function sets the viewport hint to (0,0) as required by the spec for WMs with no viewport support. (set_desktop_geometry_hint): new function to set the desktop size hint to the size of the display, since we don't implement large desktop support, as required by the spec. (meta_screen_resize): update the geometry hint on screen resize * src/window.c (meta_window_new_with_attrs): Initialize demands_attention state (set_net_wm_state): Set demands_attention hint in the window state (meta_window_show): If we don't pop up a window because of USER_TIME, set DEMANDS_ATTENTION on the window. (meta_window_focus): When a window receives focus, remove DEMANDS_ATTENTION hint (meta_window_client_message): Allow other apps to set DEMANDS_ATTENTION on a window. Also, if the _NET_ACTIVE_WINDOW hint includes a timestamp, use it. (update_net_wm_state): Read DEMANDS_ATTENTION state also * src/window.h (_MetaWindow): add wm_state_demands_attention bit. 2004-07-22 Rob Adams <readams@readams.net> * src/metacity.schemas.in: Add trailing quotes to keybinding explanation text. Patch from Emil Soleyman-Zomalan. Fri Jun 25 17:41:53 2004 Soeren Sandmann <sandmann@daimi.au.dk> * configure.in: Require startup-notification 0.7 2004-06-25 Rob Adams <readams@readams.net> * COMPLIANCE: indicate that _NET_WM_USER_TIME is now supported 2004-06-24 Elijah Newren <newren@math.utah.edu> * src/keybindings.c: (handle_toggle_desktop): Choose correct window to focus when "un-showing" the desktop. Fixes #144900. 2004-06-24 Elijah Newren <newren@math.utah.edu> Make choice of focus window be consistent for each focus mode. Fixes #135810. * src/delete.c: (meta_window_delete): In some #if 0'ed code, replace meta_workspace_focus_mru_window with meta_workspace_focus_default_window (just in case the code becomes un-#if 0'ed out). * src/screen.c, src/screen.h: Change meta_screen_focus_mouse_window to meta_screen_get_mouse_window, and don't focus the window when found but rather return it. * src/window.c: (meta_window_free, meta_window_minimize): replace meta_workspace_focus_mru_window with meta_workspace_focus_default_window. * src/workspace.c: (meta_workspace_focus_default_window): Focus appropriately for the given focus method: click-to-focus: focus MRU window (== toplevel window) sloppy focus: focus the window under the pointer if there is such a window, otherwise focus the mru window mouse focus: focus the window under the pointer if there is such a window, otherwise don't focus anything 2004-06-24 Elijah Newren <newren@math.utah.edu> * src/window.c: Avoid a race condition on the choice of window to focus after the previously focused window gets closed or minimized. Fixes #131582. 2004-06-24 Elijah Newren <newren@math.utah.edu> * src/metacity.schemas.in: make naming for "move a window"/"move the window"/"move window" more consistent. Patch from Michael Terry for #142235. 2004-06-24 Elijah Newren <newren@math.utah.edu> * src/session.c: Change meta_warning to meta_topic on failure to connect to a session manager. Fixes #136218. 2004-06-17 Elijah Newren <newren@math.utah.edu> Add support for _NET_WM_USER_TIME * src/display.c: (meta_display_open): Add _NET_WM_USER_TIME to atom_names[], (event_callback): Manually set _NET_WM_USER_TIME upon KeyPress (doesn't work since keyboard isn't grabbed) and ButtonPress (does work), this is just a fallback for applications that don't update this themselves. * src/display.h: (struct _MetaDisplay): Add atom_net_wm_user_time field * src/screen.c: (meta_screen_apply_startup_properties): Check for TIMESTAMP provided from startup sequence as well. * src/stack.c: s/meta_window_set_stack_position/meta_window_set_stack_position_no_sync/, (meta_window_set_stack_position): New function which calls the meta_window_set_stack_position_no_sync function followed immediately by calling meta_stack_sync_to_server. * src/window-props.c: (init_net_wm_user_time), (reload_net_wm_user_time): new functions, (reload_wm_hints): also load atom_net_wm_user_time * src/window.c: new XSERVER_TIME_IS_LATER macro (accounts for timestamp wraparound), (meta_window_new_with_attrs): add timestamp attributes, (window_takes_focus_on_map): use TIMESTAMP from startup notification and _NET_WM_USER_TIME to decide whether to focus new windows, (meta_window_show): if app doesn't take focus on map, place it just below the focused window in the stack (process_property_notify): check for changes to _NET_WM_USRE_TIME, (meta_window_stack_just_below): new function * src/window.h: (_MetaWindow struct): new fields for initial_timestamp, initial_timestamp_set, net_wm_user_time_set, and net_wm_user_time, (meta_window_stack_just_below): new function 2004-06-21 Anders Carlsson <andersca@gnome.org> * src/common.h: * src/menu.c: (menu_closed), (activate_cb): * src/window.c: (menu_callback): Add a timestamp argument to menu functions and use it in meta_window_delete. 2004-06-21 Anders Carlsson <andersca@gnome.org> * src/window.c: (meta_window_client_message): Get the timestamp from the client message. Sat Jun 19 02:21:08 2004 Soeren Sandmann <sandmann@daimi.au.dk> Fix bug 143333, support for update counter spec, and 109362, schedule compensation events when events are ignored. * src/display.c (meta_display_open): Add _NET_WM_SYNC_REQUEST and _NET_WM_SYNC_REQUEST_COUNTER atoms. Remove the old METACITY_SYNC_COUNTER stuff. (meta_display_begin_op): Setup the sync counter * src/xprops.c, src/xprops.h, src/window-props.c, src/display.h: Add new atoms. * src/window.c (send_sync_request): new function. (meta_window_move_resize_internal): send a sync request before resizing. (check_move_resize_frequence): Rework logic to also check the SYNC case. If an event is ignored return the remaining time. (update_resize_timeout): Timeout that gets called when a compensation event is scheduled. (uddate_resize): schedule compensation events when an event is ignored. (meta_window_handle_mouse_grap_op_event): When an alarm is received and sync was turned off, turn it back on. * src/window.h (struct MetaWindow) Add some variables 2004-06-16 Havoc Pennington <hp@redhat.com> * configure.in: bump version, add the UNSTABLE note * Branch off GNOME 2.6, we are now officially unstable 2004-06-04 Jeff Waugh <jdub@perkypants.org> * src/metacity.schemas.in: Set titlebar_uses_system_font = false. The previous default was almost violent in its lack of appreciation for human beings. In fact, this entire setting should probably be removed, but for now, let's just fix the default. Permission granted by Havoc. 2004-05-04 Elijah Newren <newren@math.utah.edu> * configure.in: 2.8.1 * NEWS: update 2004-05-02 Rob Adams <readams@readams.net> * src/metacity-dialog.c (warn_about_no_sm_support): make the no sm support warning dialog resizable, since the default GTK warning dialog not has default not resizable. Fix for #141672 from Olivier Crete. 2004-04-29 Rob Adams <readams@readams.net> * src/prefs.c (change_notify): Add a value type check for the visual bell/audible bell gconf settings. Patch from Jarrod Johnson for #141409. 2004-04-19 Mark McLoughlin <mark@skynet.ie> Syncing across this change from libwnck. Patch from Neil Muller <neil@dip.sun.ac.za> in bug #133979. * src/iconcache.c: (find_largest_sizes), (find_best_size): Don't down-size nitems from a gulong to an int. Fixes a crash with enlightenment, apparently. 2004-04-16 Iñaki Larrañaga <dooteo@euskalgnu.org> * configure.in: Added "eu" (Basque) to ALL_LINGUAS. 2004-04-15 Elijah Newren <newren@math.utah.edu> * src/display.c: Prevent unwanted grab op from occurring. Previously, for some people under certain conditions, clicking and releasing the mouse button rapidly enough would result in Metacity starting a move operation due to ignoring the button release. This should fix that problem (it does for me). See bug 136587. 2004-04-11 Rob Adams <readams@readams.net> * configure.in: Make the --enable-xinerama switch work properly. Fix for #138562 from foser@gentoo.org. 2004-04-09 Guntupalli Karunakar <karunakar@freedomink.org> * configure.in: Added "gu" (Gujarati) to ALL_LINGUAS. 2004-03-27 Tõivo Leedjärv <toivo@linux.ee> * configure.in: Added et to ALL_LINGUAS. 2004-03-24 Guntupalli Karunakar <karunakar@freedomink.org> * configure.in: Added "pa" (Punjabi) to ALL_LINGUAS. 2004-03-21 Havoc Pennington <hp@redhat.com> * configure.in: 2.8.0 * NEWS: update 2004-03-07 Elijah Newren <newren@math.utah.edu> * rationales.txt: Bring up to date (see bug 136252). 2004-03-07 Havoc Pennington <hp@redhat.com> * configure.in: 2.7.1 2004-03-04 Paisa Seeluangsawat <paisa@users.sf.net> * configure.in: Added "th" (Thai) to ALL_LINGUAS. 2004-03-01 Rob Adams <readams@readams.net> * src/stack.c (compute_layer): don't promote due to transiency; we handle that elsewhere now. (ensure_above): perform layer promotion here as well as stack position promotion. Note that this means that we need to do stack constraints now on layer change now. (get_maximum_layer_of_ancestor): remove function (max_layer_func): remove function (MaxLayerData): remove struct 2004-02-28 Rob Adams <readams@readams.net> Revert 2/27 patch for layer promotion. 2004-02-27 Rob Adams <readams@readams.net> * src/window.c (meta_window_notify_focus): only move on MRU list if the window belongs on the workspace, since the FocusIn event could be for a window whose workspace we've since switched away from. Possible fix for #122016. * src/workspace.c (meta_workspace_contains_window): search for the workspace in window->workspaces rather than the window in workspace->windows. Since the number of workspaces is at most 36, this is a O(1) lookup rather than a O(n) lookup. Sorry; couldn't resist. 2004-02-27 Rob Adams <readams@readams.net> * src/metacity.schemas.in: Change move_to_workspace_left/right/up/down keybindings to <Control><Alt><Shift> arrow to avoid conflicting with new keybindings in spacial nautilus. 2004-02-27 Rob Adams <readams@readams.net> Handle layer promotion of transient descendants of layer-promoted windows to also be layer promoted, using a simple iterative algorithm. * src/stack.c (compute_layer): change name to promote_layer, and convert to simply perform any necessary layer promotion without computing the standalone layer. (max_layer_func): use window->layer instead of get_standalone_layer (get_maximum_layer_of_ancestor): use window->layer instead of get_standalone_layer (meta_stack_ensure_sorted): implement iterative algorithm, explained in a long comment. * src/window.h: add a tmp_layer field used by stack.c for determining if the stack is dirty or not, since maintaining this information in meta_stack_ensure_sorted is no longer practical. 2004-02-23 Rob Adams <readams@readams.net> Add my copyright notice to a number of files on which it should already exist. * src/window.c (meta_window_notify_focus): modify code to move to front of MRU list so that we can have an assert that it was there in the first place. This code may be causing some crashes. See #131196. 2004-02-22 Christian Rose <menthos@menthos.com> * configure.in: Added "en_CA" to ALL_LINGUAS. 2004-02-19 Rob Adams <readams@readams.net> * src/prefs.h: remove trailing comma in MetaKeyBindingAction enum. Fix for #134868 thanks to bugzilla-gnome@thewrittenword.com. 2004-02-16 Rob Adams <readams@readams.net> * src/window.c (update_move): reset drag state after shaking loose or reattaching. Fix for #132625. 2004-02-15 Anders Carlsson <andersca@gnome.org> * src/menu.c (meta_window_menu_new): Actually translate a message, don't just mark it for translation. 2004-02-14 Elijah Newren <newren@math.utah.edu> * src/workspace.c: When moving a window to a different workspace, prepend it to the mru list insted of appending it. Fixes #134368. 2004-02-14 Rob Adams <readams@readams.net> If we're moving a window and receive a _NET_CURRENT_DESKTOP message indicating a workspace switch, bring along the drag window to the new workspace, solving a potentially weird bug where the window would be lost on the old workspace. This also makes it possible to implement edge flipping in an external program with just a few lines of code. Patch for #131630 from ed@catmur.co.uk. * src/keybindings.c (switch_to_workspace): remove function -- no longer needed. (handle_activate_workspace): call meta_workspace_activate instead of switch_to_workspace * src/workspace.c (meta_workspace_activate_with_focus): if we're in a move grab op, bring along the drag window. 2004-02-14 Rob Adams <readams@readams.net> * configure.in: Add configure option to not even try using xinerama, to make metacity buildable on systems with no shared library version of the xinerama libraries. Patch for #134203 from Julio M. Merino Vidal. 2004-02-01 Rob Adams <readams@readams.net> * COMPLIANCE: Bring up to date with current draft EWHM. 2004-01-27 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Use the 'utility' frame for dialogs too. 2004-01-24 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Updated this theme. 2004-01-21 Elijah Newren <newren@math.utah.edu> * src/screen.c (set_supported_hint): Removed some duplicate entries. 2004-01-17 Rob Adams <readams@readams.net> * src/metacity.schemas.in: Default binding removed for toggle_shaded, since we don't have anything in the graphical UI for it any more. 2004-01-17 Rob Adams <readams@readams.net> * src/window.c (meta_window_show_menu): Don't show left/right/up/down if a window is sticky. Make "On Top" insensitive for docks, splash screens, and desktops since it has no effect anyway. 2004-01-10 Rob Adams <readams@readams.net> * src/metacity.schemas.in: update default action_double_click_titlebar to be toggle_maximize instead of toggle_shade. See #131126. 2004-01-10 Rob Adams <readams@readams.net> * src/constraints.c (meta_window_constrain): if we maximize after placement, and the window is too big to fix in the work area, define a sane saved_rect approximately with dimensions three-quarters approximately three quarters the size of the work area. This avoids the problem where large windows would unmaximize and actually get bigger. See #93590. 2004-01-09 Thomas Fitzsimmons <fitzsim@redhat.com> Add _NET_FRAME_EXTENTS and _NET_REQUEST_FRAME_EXTENTS. * src/display.c: include xprops.h (process_request_frame_extents): new function (meta_display_open): add _NET_FRAME_EXTENTS and _NET_REQUEST_FRAME_EXTENTS atoms (event_callback): handle frame extents message * src/display.h (struct _MetaDisplay): add atom_net_frame_extents and atom_net_request_frame_extents * src/theme.c (meta_pango_font_desc_get_text_height): make font_desc parameter const * src/ui.c: include prefs.h (meta_ui_theme_get_frame_borders): new function * src/window.c (update_net_frame_extents): new function (meta_window_move_resize_internal): update frame extents property when frame geometry changes * src/screen.c (set_supported_hint): add atom_net_frame_extents and atom_net_request_frame_extents 2004-01-09 Calum Benson <calum.benson@sun.com> * src/themes/Atlanta/metacity-theme-1.xml: Ensure Atlanta window buttons get larger when using large print themes. Fixes #123469. 2003-01-04 Rob Adams <readams@readams.net> Maintain the button grab for sloppy and mouse focus all the time. This fixes a number of problem introduced by trying to drop the grab; we now do this only for click to focus mode. This has the unfortunate effect that #102209 reappears for sloppy and mouse focus, but this seems unavoidable, because of limitations in the X protocol. See #115072. * src/display.c (meta_display_grab_focus_window_button): #if 0 the section on not grabbing unless in click-to-focus mode. * src/window.c (meta_window_notify_focus): drop focus button grab on FocusIn and acquire it on FocusOut only when in click-to-focus mode. 2004-01-03 Robert Sedak <robert.sedak@sk.htnet.hr> * configure.in: Added "hr" in ALL_LINGUAS. 2003-01-02 Rob Adams <readams@readams.net> * README: Update reference to EWMH. * HACKING: Add a reference to COMPLIANCE and to the ICCCM and EWHM. 2003-12-25 Havoc Pennington <hp@redhat.com> * src/compositor.c (process_reparent): handle ReparentNotify, and add a lot of debug output. 2003-12-25 Havoc Pennington <hp@redhat.com> * src/compositor.c (meta_compositor_process_event): change to track all children of the root window, not only mapped children; this keeps us from losing track of the stacking order * src/display.c (event_callback): don't do any of the compositor event handling inline, do it all in compositor.c 2003-12-21 Rob Adams <readams@readams.net * src/main.c (main): fix minor punctuation error in a string. Fix for #129805. 2003-12-20 Rob Adams <readams@readams.net> Reorganize the window menu according to discussion on #110904. The workspace name mnemonic chunk of the patch is thanks to Jonathan Blandford. * src/common.h: add MENU_OP_ABOVE, MENU_OP_UNABOVE, MENU_UP_MOVE_TO_* menu ops. * src/core.c (meta_core_get_menu_accelerator): add accelerator for the new menu ops. * src/menu.c: add checked attribute in _MenuItem struct to display a checkmark next to a menu item. Add the new menu items to menuitems. (get_workspace_name_with_accel): Add mnemonics even to renamed workspaces. (menu_item_new): provide support for the checked attribute (meta_window_menu_new): construct new submenu for workspace switching. * src/window.c (menu_callback): implement support for the new menu ops. (meta_window_show_menu): don't use the OP_*SHAPE operations, and compute which of the OP_MOVE_TO_* ops should be used for the current workspace and workspace layout. Add the OP_*ABOVE operations. 2003-12-20 Arafat Medini <lumina@silverpen.de> * configure.in: Added Arabic locale "ar" to ALL_LINGUAS 2003-12-17 Rob Adams <readams@readams.net> * src/display.c (meta_display_open): initialize grab_wireframe_active to FALSE. Fix for #128090. 2003-12-17 Rob Adams <readams@readams.net> * src/tabpopup.c (meta_ui_tab_popup_new): Don't try to call utf8_strndup on a null title for an entry. Fix for #128566. * src/workspace.c (meta_workspace_free): Call g_list_free on the mru_list, since with sticky windows that MRU list could well not be emtpy. See #122016. 2003-12-13 Rob Adams <readams@readams.net> * src/window.c (meta_window_new_with_attrs): set on_all_workspaces in all cases _before_ adding to the workspaces, so that windows initially on all workspaces are added correctly to the MRU lists. Fix for #120907. * src/workspace.c (meta_workspace_add_window): handle sticky windows so that we add to add mru lists if needed (meta_workspace_remove_window): handle sticky windows so that they are removed from all mru lists if needed. 2003-12-12 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_free): unstick window to get it out of mru_list it should not be in; assert that window has been removed from all mru_list. Perhaps fixes #122016 crash. 2003-11-29 Havoc Pennington <hp@redhat.com> * fix up compositing manager to somewhat work 2003-11-26 Rob Adams <readams@readams.net> * COMPLIANCE: fix a couple of minor typos. 2003-11-24 Havoc Pennington <hp@redhat.com> * src/compositor.c (meta_compositor_new): fix the extension checks 2003-11-24 Havoc Pennington <hp@redhat.com> * src/iconcache.c (meta_icon_cache_init): init prev_mask field * src/window.c (meta_window_new_with_attrs): init xgroup_leader prior to use 2003-11-24 Havoc Pennington <hp@redhat.com> * src/display.c (meta_display_begin_grab_op): add an event_serial argument and use it when the pointer is already grabbed automatically on the button press. May fix bug #126871 2003-11-24 Havoc Pennington <hp@redhat.com> * Apply patch from Gregory Merchan to avoid using CurrentTime when setting input focus. Bug #108881 2003-11-23 Havoc Pennington <hp@redhat.com> * src/compositor.c: move xcompmgr code in here (minus drop shadows), untested since Keith's server just crashes at the moment. "It compiles" 2003-11-20 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_new_with_attrs): new function * src/display.c, src/screen.c: create the compositor and feed windows and events to it 2003-11-20 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_notify_focus): revert the change here 2003-11-17 Rob Adams <readams@readams.net * src/window.c (set_allowed_actions_hint): increment i between resize and fullscreen. 2003-11-16 Rob Adams <readams@readams.net> Create COMPLIANCE document describing metacity specification compliance. Right now gives detailed EWMH compliance; still need to add ICCCM compliance information. Also some minor fixes to bring metacity into compliance on some points. * COMPLIANCE: new file * src/display.h, src/display.c (meta_display_open), src/screen.c (set_supported_hint): add atom_net_wm_action_fullscreen and atom_net_wm_action_minimize * src/window.c (set_allowed_actions_hint): some fixes to which hints to set and add fullscreen and minimize. 2003-11-16 Rob Adams <readams@readams.net> * src/window.c (meta_window_notify_focus): add paranoia check to make sure a window is really on a workspace before inserting it at the beginning of the MRU list. Maybe there's a race condition with focusing and workspace switching. Hopefully a fix for #122016. 2003-11-15 Havoc Pennington <hp@redhat.com> * src/main.c (main): fix warning * src/compositor.c: add a new file to contain compositing manager functionality; not yet implemented at all. 2003-11-15 Rob Adams <readams@readams.net> Inherit visual from frame window so that metacity will work with the new compositing manager extension work by Keith on freedesktop.org, so that ARGB windows can be full alpha-transparent without a metacity frame getting drawn in the background. In the long term, we need to actually set alpha values when drawing the frame so that it will really work; this is a stopgap solution. Patch from Keith Packard; see Bug 126875. * src/frame.c (meta_window_ensure_frame): pass client visual to frame. * src/ui.[ch] (meta_ui_create_frame_window): add new xvisual parameter and use it to create new window. 2003-11-15 Rob Adams <readams@readams.net> * src/window.c (update_net_wm_type): don't set window->type_atom here so that the type-inference code will actually be called. Fix for #126873 from Keith Packard. 2003-11-08 Rob Adams <readams@readams.net> * src/window.c (meta_window_move_resize_internal): configure frame first if we grow more than we shrink combined in both dimensions. Patch from Soren Sandmann for #108925. 2003-11-07 Rob Adams <readams@readams.net> * src/place.c (meta_window_place): use maximize_after_placement to automaximize in meta_window_place; avoids a problem with not recalculating the frame geometry after auto-maximizing. 2003-11-07 Rob Adams <readams@readams.net> * src/window.c (window_should_be_showing): show the window if it's a transient of a dock or desktop, since otherwise such windows are invisible in show desktop mode. Fix for #124648. 2003-11-07 Rob Adams <readams@readams.net> * src/main.c (main): Try harder to find a theme in the event that the theme in the preference cannot be found. Patch from Marcin Krzyzanowski. See #125815. * src/place.c (meta_window_place): use "visual" centering for dialog placement and clip new dialogs to an xinerama workspace. Fix for #118336. 2003-10-30 Havoc Pennington <hp@redhat.com> * src/menu.c (meta_window_menu_new): patch to avoid creating stick/unstick menu items when only one workspace, bug #116563 from Michael Terry 2003-10-25 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_notify_focus): if a window is focused which is not either a dock or a transient in the same group as a dock, shuffle all dock/desktop windows to the end of the MRU list so they won't annoyingly get focus all the time. #123816 2003-10-15 Yukihiro Nakai <nakai@gnome.gr.jp> Gettextize metacity-theme-viewer. #121747 * src/theme-viewer.c: gettextize. * po/POTFILES.in: Add src/theme-viewer.c 2003-10-13 Havoc Pennington <hp@redhat.com> In the "prefs cause code complexity" department, here's a "sloppy focus die die die" kind of moment. * src/display.c (meta_display_grab_focus_window_button): don't grab in sloppy focus mode, since we were dropping the grab on window enter anyway this just removes races from the current behavior. * src/display.c (prefs_changed_callback): ungrab/grab on focus mode changes, since we treat sloppy and click differently. 2003-10-12 Havoc Pennington <hp@redhat.com> Merge reduced_resources mode patch from the branch. Offers wireframe and no-animations. * src/window.c (implement_showing): no animation if we are in reduced resources mode * src/prefs.c: add REDUCED_RESOURCES pref * src/window.c (meta_window_update_keyboard_resize): fix to modify grab_anchor_window_pos to grab_wireframe_rect if appropriate instead of window->rect * src/display.h (struct _MetaDisplay): add grab_start_serial used to avoid responding to events that occurred prior to the grab initialization. Still broken in various ways, specifically EnterNotify that occurred prior to XGrabPointer is processed as if it occurred after. * src/window.c (meta_window_update_keyboard_move): add this instead of meta_window_warp_pointer() crack * src/effects.c (meta_effects_update_wireframe): draw a kind of grid for the wireframe, instead of just a rectangle, like twm * src/screen.c (meta_screen_new): line width of 3 for the XOR gc "Reduced resources" mode based on wireframe patch from Erwann Chenede. Still pretty buggy. * src/keybindings.c (process_keyboard_move_grab) (process_keyboard_resize_grab): add gruesome wireframe hacks * src/display.c (meta_display_end_grab_op): end wireframe (meta_display_begin_grab_op): begin wireframe * src/effects.c (meta_effects_end_wireframe) (meta_effects_update_wireframe, meta_effects_begin_wireframe): routines to draw the wireframe stuff * src/window.c (window_should_be_showing): hide window when doing wireframe, commented out as it breaks grab * src/window.c (meta_window_refresh_resize_popup): handle wireframe * src/screen.c (meta_screen_new): create a screen->root_xor_gc for use in drawing wireframes * src/frames.c (meta_frames_push_delay_exposes): repaint everything before we delay 2003-10-11 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_begin_grab_op): initialize display->grab_have_pointer to FALSE, previously I think you could get a case where we didn't have the grab and thought we did. Bugs were reported with this happening. Of course we still have the "why did the grab fail" problem, but it should be less noticeable with this fixed. 2003-10-06 Rob Adams <readams@readams.net> * src/constraints.c (constraint_onscreen_*_func): disable onscreen resize constraints for right, left, and bottom, since there is no way to violate onscreen constraints by resizing in these directions and the code to implement the constraints made some incorrect assumptions. Fix for #120701, #120756, #123165, #123631, #123838. 2003-10-06 Žygimantas Beručka <uid0@tuxfamily.org> * configure.in: Added "lt" to ALL_LINGUAS 2003-10-01 Havoc Pennington <hp@redhat.com> * NEWS: update * configure.in: 2.6.2 2003-09-30 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_queue_move_resize): add the moveresize idle at META_PRIORITY_RESIZE so it runs before GTK does any drawing, may fix bug #109211 (seems to for me) * src/ui.h (META_PRIORITY_RESIZE): add this between GTK resize/redraw priorities * src/display.c (meta_display_queue_retheme_all_windows): remove some debug spew from meta_warning 2003-09-30 Havoc Pennington <hp@redhat.com> * src/testasyncgetprop.c: remove nonstandard header include, #121870 2003-09-30 Havoc Pennington <hp@redhat.com> * src/tools/metacity-message.c (main): call bind_textdomain_codeset(), fix from Yukihiro Nakai bug #121743 2003-07-28 Rached Ben Mustapha <rached@benmur.net> Fix bug #118428 * src/window.c (redraw_icon): Also redraw window icon if the window is not mapped but its frame is. (idle_update_icon): Unset the window->update_icon_queued flag. 2003-09-29 Havoc Pennington <hp@redhat.com> * src/tabpopup.c (meta_ui_tab_popup_new): put a random cap on number of characters in the title of each window, bug #109301 2003-09-29 Havoc Pennington <hp@redhat.com> * configure.in: put -lXext in Xrandr check, bug #115996 2003-09-29 Havoc Pennington <hp@redhat.com> * src/wm-tester/test-size-hints.c: a little program to test size hints, for now just a 0x0 min size to verify bug #113320 2003-09-29 Havoc Pennington <hp@redhat.com> * src/async-getprop.c (async_get_property_handler): attempt to fix this to return the data as an array of long even on 64-bit as with XGetWindowProperty() breakage, bug #114035, credit to Gwenole Beauchesne for tracking down. 2003-09-29 Havoc Pennington <hp@redhat.com> * src/xprops.c (cvtINT16toInt): fix the 64-bit check not to use macros from the X tree that don't get set * configure.in: check for sizes of various types 2003-09-29 Havoc Pennington <hp@redhat.com> * src/delete.c (meta_window_delete): don't move the focus after you click the close button on a window. bug #108706 2003-09-29 Havoc Pennington <hp@redhat.com> * src/main.c (find_accessibility_module): fix warnings (one was a real bug) * src/ui.c (meta_gdk_pixbuf_get_from_pixmap): fix warning that probably explains remaining crash on bug #116923. Jeez, need to use -Werror here or something. Fix #103575, spawn child processes on proper screen. * src/keybindings.c (error_on_command): pass --screen to metacity-dialog (handle_run_command): launch user command with DISPLAY reflecting the screen you launch it from * src/delete.c (delete_ping_timeout_func): pass --screen to metacity-dialog 2003-09-26 Havoc Pennington <hp@redhat.com> * src/display.c (event_callback): when focus on root window becomes None, set it to something other than None so keybindings keep working and print a warning about how some application sucks. #84564 (event_callback): Fix debug spew to print focus event details properly (meta_display_open): when setting initial focus, always use RevertToPointerRoot and fix the focus if it's None or PointerRoot 2003-09-26 Padraig O'Briain <padraig.obriain@sun.com> * src/Makefile.am: Add -DMETACITY_LIBDIR to support loading of modules * src/main.c: Add functions find_accessibility_module, accessibility_invoke_module and accessibility_invoke (main); Check whether GConf accessibility key is true and if so load accessibility modules. This code is based on the libgnome code. src/tabpopup.c (meta_ui_tab_popup_new): Set accessible role of accessible for label containing window name to STATUSBAR so AT can be aware of window name. This fixes bug #120025 2003-09-24 Havoc Pennington <hp@pobox.com> * src/session.c (io_from_warning_dialog): fix hang when we get EOF, #121376 from Laurent Vivier 2003-09-22 Taneem Ahmed <taneem@bengalinux.org> * configure.in: Added "bn" to ALL_LINGUAS. 2003-09-20 Åsmund Skjæveland <aasmunds@fys.uio.no> * configure.in: Added Norwegian (nynorsk) translation code to ALL_LINGUAS 2003-09-20 Rob Adams <readams@readams.net> Fix bug where multiple entries could appear in MRU lists, or no entry when sticking/unsticking windows. Fix for #122016 * src/window.c (meta_window_stick): use window->screen->workspaces instead of window->workspaces. (meta_window_unstick): use window->screen->workspaces instead of window->workspaces. 2003-09-19 Rob Adams <readams@readams.net> Fix a bug with partial-width panel struts caused by incorrect computation of rectangle widths, and another when using different screen resolutions on xineramas. See #122404. Also fix a crash bug with the MRU list when sticking and unsticking windows. See #120809. * src/constraints.c (get_outermost_onscreen_positions): Fix off-by-one error with partial-width struts. * src/window.c (meta_window_update_struts): Fix off-by-one error with partial-width struts. (meta_window_stick): assign back to GList after g_list_append (meta_window_unstick): assign back to GList after g_list_append * src/workspace.c (ensure_work_areas_validated): For right and bottom struts, compute strut relative to root window and not to xinerama edge in compliance with EWMH recommendations. 2003-09-17 Fatih Demir <kabalak@gtranslator.org> * configure.in: Added "ta" (Tamil) to the languages' list. Wed Sep 10 15:38:09 2003 Jonathan Blandford <jrb@redhat.com> * configure.in: Rerelease 2.4.0.1 to fix glib-gettext problem. 2003-09-08 Havoc Pennington <hp@redhat.com> * configure.in: remove "this is the unstable branch" warning 2003-09-08 Havoc Pennington <hp@redhat.com> * configure.in: 2.6.0 2003-09-04 Havoc Pennington <hp@redhat.com> * configure.in: 2.5.5 * HACKING: add instructions on how to make a release 2003-08-29 Rob Adams <robadams@ucla.edu> * src/ui.c (meta_gdk_pixbuf_get_from_pixmap): harden against null return from gdk_pixmap_foreign_new. Fix for #116923. 2003-08-26 Guntupalli Karunakar <karunakar@freedomink.org> * configure.in: Added "hi" (Hindi) to ALL_LINGUAS. 2003-08-20 Rob Adams <robadams@ucla.edu> Complete the transition to using the MRU window as the default focus window instead of the topmost window; fixes a number of problems with sloppy focus and utility windows. See #112031. * src/window.c (meta_window_free): call meta_workspace_focus_mru_window (meta_window_minimize): call meta_workspace_focus_mru_window 2003-08-20 Rob Adams <robadams@ucla.edu> * src/constraints.c (meta_window_constrain): do northwest resize when maximizing and fullscreening to avoid potential "off-by-one" problems. 2003-08-19 Rob Adams <robadams@uclu.edu> * src/stack.c (get_standalone_layer): put windows with wm_state_below at the bottom. Make this higher priority than full screen layer; see #120238. 2003-08-18 Rob Adams <robadams@ucla.edu> * src/constraints.c (meta_window_constrain): recalculate frame geometry if the window gets maximized after placement, since it's likely to change. Fix for #120117. 2003-08-17 Ray Strode <halfline@hawaii.rr.com> * src/delete.c (meta_window_delete): Use MRU list to find focusing window after a window is deleted instead of using top window. Fix for #108643. 2003-08-16 Havoc Pennington <hp@pobox.com> Patch from Soeren Sandmann #108926 to improve opaque resize * src/frame.c (meta_window_ensure_frame): new function * src/ui.c (meta_ui_create_frame_window): new function to create a frame with GDK, so that GDK's invalidation etc. work properly 2003-08-16 Havoc Pennington <hp@pobox.com> * src/display.c (xcursor_for_op): fix cursor for META_GRAB_OP_MOVING, #111943 from John Paul Wallington 2003-08-15 Rob Adams <robadams@ucla.edu> * src/constraints.c (meta_window_constrain): move to upper left corner since we're resizing/moving instead of moving/resizing. Fix for #119988. 2003-08-15 Ray Strode <halfline@hawaii.rr.com> Changed MRU list to be per workspace instead of per display, so sticky windows don't hijack the window focus after workspace switching (Bug #97635). * src/delete.c (meta_window_delete): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window. * src/display.c (meta_display_open): Stop using display->mru_list. (find_tab_forward): (find_tab_backward): (meta_display_get_tab_list): Use workspace->mru_list instead of display->mru_list and remove unneeded calls to meta_window_visible_on_workspace * src/display.h: Remove mru_list from MetaDisplay * src/keybindings.c (handle_toggle_desktop): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window. * src/screen.c (meta_screen_focus_top_window): (meta_screen_focus_default_window): Remove functions. (meta_screen_show_desktop): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window. * src/screen.h: Remove meta_screen_focus_top_window and meta_screen_focus_default_window declarations. * src/window.c (meta_window_new): Stop using display->mru_list. (meta_window_free): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window and stop using display->mru_list. (meta_window_stick): Add sticky window to all workspace MRU lists. (meta_window_unstick): Remove non-sticky window from the workspace MRU lists it doesn't belong in. (meta_window_notify_focus): Move newly focused window to the front of active workspace's MRU list. * src/workspace.c (meta_workspace_new): Initialize workspace->mru_list to NULL. (meta_workspace_add_window): Add window to workspace's MRU list. (meta_workspace_remove_window): Remove window from workspace's MRU list. (meta_workspace_activate_with_focus): Use meta_workspace_focus_default_window instead of meta_screen_focus_default_window. (meta_workspace_focus_default_window): (meta_workspace_focus_mru_window): (meta_workspace_focus_top_window): Add functions. * src/workspace.h: Add mru_list to MetaWorkspace and add function declarations for meta_workspace_focus_default_window, meta_workspace_focus_mru_window, meta_workspace_focus_top_window. 2003-08-14 Rob Adams <robadams@ucla.edu> Allow windows that are too tall for the workarea to break the onscreen constraints just enough so that their bottom edges can be made visible. Fix for #106740. Also, changes constraints to constrain the resize and then the move to avoid complexities in the code for the above fix. * src/constraints.c (get_outermost_onscreen_positions) Compute the "effective" height of the work area and the minimum size for the window to compute a value by which a window is allowed to violate the top constraint. (meta_window_constrain): convert to a resize then a move instead of a move then resize. 2003-08-13 Rob Adams <robadams@ucla.edu> * configure.in: remove metacity.spec from AC_OUTPUT 2003-08-13 Havoc Pennington <hp@redhat.com> * metacity.spec.in: remove, nobody is maintaining it. 2003-08-13 Laurent Dhima <laurenti@alblinux.net> * configure.in: Added "sq" to ALL_LINGUAS. 2003-08-10 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_new): don't select for button press/release events, as that keeps other clients from doing so, and it doesn't seem that metacity has any reason to do it. Patch from Andreas Volz. 2003-08-08 Bastien Nocera <hadess@hadess.net> * src/metacity-dialog.c: (kill_window_question), (warn_about_no_sm_support): fix markup being ignored when a window title has a forbidden character in it (eg. "Send & Receive") * src/tools/metacity-window-demo.c: fix warning 2003-07-29 Arvind Samptur <arvind.samptur@wipro.com> * src/xprops.c (utf8_list_from_results): Number of strings we are processing is one more than required. Also get the string count right even without a null byte at the end. Pointed out by Havoc. 2003-07-27 Rob Adams <robadams@ucla.edu> * src/window.c (update_move): Update window shaking loose so that the window is moved to the pointer and certain drag state is properly restored once windows "reattach". Fix for #115000 based on the patch by Jurg Billeter. * src/screen.c (meta_screen_resize): Invalidate work areas after an xrandr screen size update. Fix for #117230. * src/stack.c (window_is_fullscreen_size): Check the bottom corner of the window in addition to the top corner. Fix for #118194. * src/constraints.c (meta_window_constrain): Support aspect ratio hints in the new constraints code. Fix for #113798. * src/tools/metacity-window-demo.c (toggle_aspect_ratio): toggle the aspect ratio hints to force a 16:9 aspect ratio. (do_appwindow): add a button to toggle aspect ratio. 2003-07-27 Havoc Pennington <hp@pobox.com> * src/theme-viewer.c (run_theme_benchmark): also measure wall clock time, and run over a number of window sizes. 2003-07-15 Havoc Pennington <hp@redhat.com> * NEWS: update * configure.in: 2.5.3 2003-07-12 Pablo Saratxaga <pablo@mandrakesoft.com> * configure.in: Added Walloon (wa) to ALL_LINGUAS 2003-07-04 Havoc Pennington <hp@pobox.com> * Makefile.am (EXTRA_DIST): add rationales.txt 2003-07-02 Jordi Mallach <jordi@sindominio.net> * src/metacity.desktop.in: Add X-GNOME-Bugzilla entries. 2003-07-01 Padraig O'Briain <padraig.obriain@sun.com> * src/keybindings.c (process_tab_grab): Activate window before ending grab. This fixes bug #114037. 2003-06-20 Rob Adams <robadams@ucla.edu> * src/window.c (meta_window_unmaximize): Update grab state when we unmaximize so double-clicking doesn't cause weird window-jumping problems. See #116292. 2003-06-29 Rob Adams <robadams@ucla.edu> * src/constraints.c (meta_window_constrain): Actually maximize after placement. See #116285. 2003-06-26 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_invalidate_work_area): nuke the lists of struts here, to improve confidence that we never try to use them after a window with rects in the list gets freed. (it wasn't broken before I don't think, just making the code more robust against future mods) * src/window.c (meta_window_update_struts): replace magic "75" with a macro * src/constraints.c (constraint_hints_applies_func): don't apply hints to maximized or fullscreen, rather than only fullscreen (constrain_move): add paranoia max number of iterations to the heuristic loop 2003-06-26 Rob Adams <robadams@ucla.edu> Add keybinding to allow the user to toggle _NET_WM_STATE_ABOVE on windows. Disabled by default. See #98387. * src/keybindings.c (handle_toggle_above): new function implements the keybinding * src/metacity.schemas.in: add toggle_above keybinding * src/prefs.[ch]: add toggle_above keybinding * src/window.[ch] (meta_window_make_above): new function to put a window into the above state (meta_window_unmake_above): new function takes a window out of the above state 2003-06-26 Mohammad DAMT <mdamt@bisnisweb.com> * po/id.po: Added Indonesian translation * configure.in: Added "id" to ALL_LINGUAS 2003-06-25 Rob Adams <robadams@ucla.edu> Update constraints code to support the new _NET_WM_STRUT_PARTIAL EWMH draft specification. See #86682. Also, fix a bug involving work area invalidation on metacity startup. Fix for #108497. Finally, some minor fixes for full screen windows. * src/window.h: Add new MetaStruts structure to store strut rects for a window. Remove has_struts and do_not_cover flag, and support new MetaStruts instead of the four ints. * src/window.c (meta_window_new): change initialization to work with new struts. Also, move meta_window_update_struts call to after the workspaces are initialized to fix #108497. Remove do_not_cover and related code. (process_property_notify): add strut_partial (update_struts): change function name to meta_window_update_struts and expose in external MetaWindow API. Support partial width struts and the new strut rects. * src/workspace.h: add new GSLists containing pointers to all relevant struts for this workspace. * src/workspace.c (meta_workspace_new): initialize the list of strut rects for this workspace. (meta_workspace_free): free the strut rect lists (ensure_work_areas_validated): support new struts and new strut rect lists. Unleash the per-xinerama work areas. * src/constraints.c (get_outermost_onscreen_positions): Use the current window position along with the new per-workspace strut rects to compute the constraints that apply to a particular window. (constraint_hint_applies_func): don't do hints constraints on fullscreen windows (update_position_limits): for maximized windows use the work areas to set the position limits; for other windows rely on the struts constraints to be computed later in get_outermost_onscreen_positions (meta_window_constrain): don't apply aspect ratio hints to full screen windows * src/display.c (meta_display_open): add _NET_WM_STRUT_PARTIAL atom (meta_rectangle_equal): new helper function for MetaRectangles (event_queue_callback): #ifndef out if USE_GDK_DISPLAY not set to avoid compiler warning * src/display.h: add atom_net_wm_strut_partial, and add meta_rectangle_equal. * src/screen.c (meta_screen_rect_intersects_xinerama): change _window_intersects_ to _rect_intersects_ which is more useful now. (meta_screen_resize_func): update struts on windows with struts since struts are relative to the screen size, and this function is called when the screen size updates. * src/screen.h (meta_screen_rect_intersects_xinerama): change _window_intersects_ to _rect_intersects_ which is more useful now. * src/window-props.c (meta_display_init_window_prop_hooks): add hook for strut_partial * src/tools/metacity-window-demo.c: Support partial-width struts on the dock window tests for metacity testing purposes. 2003-06-22 Samúel Jón Gunnarsson <sammi@techattack.nu> * configure.in: Added "is" to ALL_LINGUAS 2003-06-12 Rob Adams <robadams@ucla.edu> * src/display.c (event_callback): Focus on mouse click in sloppy/mouse to fix keynav. Fix for #115072. 2003-06-12 Rob Adams <robadams@ucla.edu> * src/Makefile.am: honor --disable-schemas-install. Fix for #106123 from Julio Merino 2003-06-12 Rob Adams <robadams@ucla.edu> Remove legacy support for Gnome 1 hints, since we deem it unlikely that anyone is running a current metacity with Gnome 1. The removed hints are _WIN_WORKSPACE, _WIN_LAYER, _WIN_PROTOCOLS, _WIN_SUPPORTING_WM_CHECK, and _WIN_HINTS. Thanks to Ben Jansens for much of this patch. * display.c (meta_display_open): remove hints * display.h: remove atoms for hints * screen.c (set_wm_check_hint): don't set legacy hint (set_supported_hint): don't set legacy hint * window-props.c (init_win_workspace): removed (reload_win_workspace): removed (meta_display_init_window_prop_hooks): remove hints * window.h: remove do_not_cover flag * window.c: remove GnomeWinHints enum (recalc_do_not_cover_struts): removed (meta_window_new): don't initialize removed flags or compute legacy struts (move_resize_cmp): removed (idle_move_resize): Don't bother sorting the idle queue (meta_window_client_message): don't set legacy hint (process_property_notify): remove hints (update_net_wm_type): don't fall back to WIN_LAYER hint (update_struts): remove legacy struts 2003-06-12 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): make raise-on-click explicitly only happen in click to focus mode. * src/window.c (update_move): apply patch from Jurg Billeter to allow you to "shake loose" maximized windows and move them between Xinerama heads. #93586 * src/display.c: delete event_queue_callback * src/display.h (struct _MetaDisplay): get rid of grab_current_window_pos and grab_current_root_[xy] as I could find absolutely no code using them for anything. They were just sort of randomly assigned to for no apparent reason. * src/display.c (event_callback): double-click timeout is per screen, so get the screen and pass screen->ui to meta_ui_get_double_click_timeout() * src/ui.c (meta_ui_get_double_click_timeout): take a MetaUI argument so we get the right settings for each screen (meta_ui_get_drag_threshold): new function 2003-06-09 Rob Adams <robadams@ucla.edu> Revamp placement policy for windows that are maximized when they are mapped, including windows that set a hint to be maximized or windows that are auto-maximized using our heuristic. See #111902. * src/window.h: add new flag maximize_after_placement and new function meta_window_maximize_internal. * src/window.c (meta_window_new): initialize maximize_after_placement to FALSE and remove the automaximize heuristic. (meta_window_maximize_internal): new function accepts a saved_rect argument to be used as the new saved_rect for the window, and does not queue a move_resize. (meta_window_maximize): re-implement using meta_window_maximize_internal. (update_net_wm_state): If a window has a maximize hint set on startup set maximize_after_placement to TRUE * src/constraints.c (meta_window_constrain): Update the xinerama information in the ConstraintInfo after placing the window, and maximize the window after placement if window->maximize_after_placement * src/place.c (find_first_fit): take a natural xinerama list as an argument instead of generating it here (constrain_placement): remove function, since it is no longer needed (meta_window_place): generate the natural xinerama list here and pass it into find_first_fit. If find_first_fit fails, use the list to find empty xineramas where we can place windows that may be maximized later. This makes maximized windows follow the correct placement policy. Move the automaximize heuristic here. 2003-06-09 Rob Adams <robadams@ucla.edu> * src/metacity-dialog.c (warn_about_no_sm_support): install an alarm to timeout the no-sm-dialog after 4 minutes of inactivity. Patch from Ximian. See #114789. 2003-06-07 Rob Adams <robadams@ucla.edu> * src/window.c (meta_window_new): call meta_group_compute_group after setting window->desc to avoid SIGSEGV when verbose mode is enabled. 2003-06-07 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_notify_focus): drop the mouse button grabs for the focused window; we'll see if this breaks anything. It should fix #102209 Fri Jun 6 19:27:53 2003 Jonathan Blandford <jrb@gnome.org> * src/metacity.schemas.in: fix the location of the schemas file. 2003-06-04 Rob Adams <robadams@ucla.edu> * src/window.c (meta_window_new): don't be stupid and set window->group = NULL after calling meta_window_compute_group. * src/group.c (meta_window_get_group): assert that window->group != NULL in here instead of computing the group to ensure robustness. 2003-06-04 Rob Adams <robadams@ucla.edu> Precompute groups to guarantee that meta_group_list_windows always returns the correct list of windows. See Bug #96973 * src/window.h: change cached_group variable to group * src/window.c (meta_window_new): change cached_group to group and call meta_window_compute_group * src/groups.c (meta_window_get_group): simply return window->group rather than computing it and returning window->cached_group (meta_window_compute_group): new function computes window->group. Designed to be called once from meta_window_new (remove_window_from_group): change cached_group to group (meta_window_group_leader_changed): call meta_window_compute_group instead of meta_window_get_group 2003-05-29 Rob Adams <robadams@ucla.edu> Use a new property _METACITY_SENTINEL to eliminate a race condition that causes focus to behave badly with sloppy/mouse focus when lots of windows are mapped/unmapped, such as with a workspace switch. The EnterNotify events on a display are ignored until the PropertyNotify sent after all the window maps is received. This is a fix for #110970. * src/display.[ch]: New _METACITY_SENTINEL atom. (event_callback): ignore EnterNotify if the sentinel isn't clear, and decrement the sentinel counter when the PropertyNotify is received. (meta_display_increment_focus_sentinel): new function. Increments the sentinel counter and updates the property on a root window on this display. (meta_display_decrement_focus_sentinel): Decrement the sentinel counter. (meta_display_focus_sentinel_clear): returns whether the sentinel counter is zero. * src/window.c (idle_calc_showing): after showing windows, call meta_display_increment_focus_sentinel on each display for windows to be shown. * src/workspace.[ch] (meta_workspace_activate_with_focus): new function activates a workspace and focuses a particular window after the workspace is activated. (meta_workspace_activate): now just a wrapper for meta_workspace_activate_with_focus * src/keybindings.c: use new meta_workspace_activate_with_focus function to ensure that focus will follow the focused window through the workspace switch. 2003-05-29 Havoc Pennington <hp@redhat.com> * src/theme-parser.c (meta_theme_load): s/int/gsize/ for g_file_get_contents() (found independently by marcus@freebsd.org on SPARC and James Laska on s390x; #113661 * src/main.c (main): fix theme location mentioned in error message 2003-05-29 Ray Strode <halfline@hawaii.rr.com> Get and use double-click speed from GtkSettings (Bug #103218). * src/ui.c, src/ui.h: add function meta_ui_get_double_click_timeout for looking up the global double-click speed. * src/display.c, src/display.h: remove double_click_time field from MetaDisplay and use meta_ui_get_double_click_timeout instead. 2003-05-29 Rob Adams <robadams@ucla.edu> * src/main.c (main): chdir to the user's home directory on startup. See #113755. * src/stack.c (get_standalone_layer): a window should be in the fullscreen layer if it or any of its transient descendants are focused or expecting the focus and it is either fullscreen or fullscreen sized. Fix for #104369. * src/stack.c (is_focused_foreach): foreach used by get_standalone_layer to find focused transient descendants. 2003-05-20 Havoc Pennington <hp@pobox.com> * src/keybindings.c (meta_change_keygrab): the mask display->ignored_modifier_mask wasn't being bound, due to "<" instead of "<=" (most people didn't notice as display->ignored_modifier_mask included Scroll_Lock). Red Hat bugzilla #91301 reported by Youssef Makki * src/display.c (meta_change_button_grab): make corresponding change for button grabs. 2003-05-20 Havoc Pennington <hp@redhat.com> * NEWS: update * configure.in: 2.5.2 2003-05-20 Anders Carlsson <andersc@codefactory.se> * src/metacity-dialog.c: (kill_window_question): Split up the strings to make life easier for translators. 2003-05-20 Anders Carlsson <andersca@codefactory.se> * src/metacity-dialog.c: (kill_window_question): Fix the wording and HIGify the dialog. 2003-05-18 Havoc Pennington <hp@pobox.com> * src/window.c (unminimize_window_and_all_transient_parents): revert broken change that assumed foreach_ancestor iterated over the window itself. Andrew Sobala, Rob Adams, #113232 2003-05-16 Rob Adams <robadams@ucla.edu> Flip the workspace when using up/down/left/right for move window to, but not when specifying a workspace explicitly as in move to workspace 4. Possible fix for #105492. * src/keybindings.c (do_handle_move_to_workspace): new function moves a window to a workspace with the option to flip to that workspace. (handle_move_to_workspace): Use new do_handle_move_to_workspace function without flipping (a keybinding) (handle_move_to_workspace_flip): Use new do_handle_move_to_workspace function with flipping (a keybinding) 2003-05-16 Havoc Pennington <hp@redhat.com> * src/frames.c (meta_frames_paint_to_drawable): fix for bug #104018 from David Santiago, change button state to normal while it's being pressed if you move the mouse outside it. Do this by tracking prelit_control for whether to draw a button as active, not just for whether to draw it as prelit. (meta_frames_motion_notify_event): also update prelit_control while clicking a button 2003-05-16 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_new): fill in window->desc sooner since we use it sooner now. * src/display.c (meta_display_open): init display->grab_update_alarm * src/window.c (meta_window_new): initialize the always_sticky field (meta_window_new): initialize the update_icon_queued field Patch from Julien Olivier bug #92335 for converting "show desktop mode" to "all windows are minimized" when you open a new window, instead of just mapping all the windows again. * src/window.c (meta_window_activate): minimize all windows before coming out of show desktop mode. (meta_window_unminimize): don't toggle show desktop mode here * src/screen.c (meta_screen_minimize_all_except): new function 2003-05-01 Havoc Pennington <hp@redhat.com> * src/theme-parser.c (meta_theme_load): fix memleak on error 2003-05-16 Telsa Gwynne <hobbit@aloss.ukuu.org.uk> * configure.in: Added "cy" (Welsh) to ALL_LINGUAS. 2003-05-06 Danilo Å egan <dsegan@gmx.net> * configure.in: Added "sr" and "sr@Latn" to ALL_LINGUAS. 2003-05-03 Havoc Pennington <hp@pobox.com> * src/keybindings.c (handle_move_to_workspace): when moving window to another workspace, don't switch to that workspace. * src/window.c (menu_callback): when moving window to another workspace, don't switch to that workspace. 2003-05-03 Havoc Pennington <hp@pobox.com> * configure.in: 2.5.1 * NEWS: update 2003-05-01 Rob Adams <robadams@ucla.edu> * src/constraints.c (constraint_onscreen_applies_func): Don't apply onscreen constraints to full screen windows. Fix for #110048 2003-04-29 Havoc Pennington <hp@redhat.com> * src/bell.h: include Xlib.h before XKBlib.h which is required on Solaris. #111877 from Peter O'Shea 2003-04-23 Havoc Pennington <hp@pobox.com> * src/keybindings.c (process_keyboard_move_grab): support diagonal keypad keybindings, from Dafydd Harries 2003-04-21 Havoc Pennington <hp@redhat.com> * purge HAVE_GTK_MULTIHEAD from the source code, not just from configure.in. Yes I am a loser. 2003-04-19 Masahiro Sakai <sakai@tom.sfc.keio.ac.jp> * configure.in: call AC_LIBTOOL_WIN32_DLL. * src/Makefile.am: add -no-undefined to libmetacity_private_la_LDFLAGS and write dependency libraries in libmetacity_private_la_LIBADD. 2003-04-06 Rob Adams <robadams@ucla.edu> * src/place.c (find_next_cascade): cascade on xinerama with pointer instead of on first xinerama. 2003-04-05 Rob Adams <robadams@ucla.edu> Update placement policy for screen with multiple xineramas. Windows will be placed preferentially on the xinerama with the pointer, and progressively further away as needed to find a place where the window does not overlap other windows. * src/place.c (rect_fits_in_work_area): function fit_rect_in_xinerama greatly simplified to work with new placement policy. (find_first_fit): implement new first fit placement scheme * src/screen.c (meta_screen_get_xinerama_neighbor): look for an xinerama in the xinerama list that is adjacent to the specified xinerama. (meta_screen_get_natural_xinerama_list): return a list of xineramas in the order to be preferred by the placement algorithm as determined by the current location of the pointer. * src/screen.h: add function prototypes and an enum used by meta_screen_get_xinerama_neighbor. 2003-04-05 Rob Adams <robadams@ucla.edu> * src/place.c (center_tile_rect_in_area): Fix a minor off-by-one error. See #110079. 2003-03-30 Rob Adams <robadams@ucla.edu> * src/window.c (meta_window_move_resize_internal): When passing frame geometry to meta_window_constrain, send null if no frame. Possible fix for #109039. 2003-03-29 Havoc Pennington <hp@pobox.com> * src/wm-tester/test-gravity.c (main): add --noframes option for testing, showing how broken we currently are. Fri Mar 28 14:13:37 2003 Soeren Sandmann <sandmann@daimi.au.dk> * src/window.c (update_resize): Only cap refresh rate when not using SYNC. Remove bogus update-if-we-moved-more-than-a-delta. * src/window.c (update_move): Don't cap refresh rate during moves. Remove bogus update-if-we-moved-more-than-a-delta. 2003-03-26 Havoc Pennington <hp@pobox.com> * NEWS: update * configure.in: release 2.5.0 Sun Mar 23 23:04:06 2003 Soeren Sandmann <sandmann@daimi.au.dk> * src/display.c (meta_spew_event): just return if we are not verbose. 2003-03-11 Havoc Pennington <hp@pobox.com> Should fix #108108, #106217, tracked down by Owen Taylor and Frederic Crozat * src/window.c (meta_window_foreach_transient): change MetaWindowForeachFunc to return a boolean for whether to continue (meta_window_foreach_ancestor): new function (window_should_be_showing): use meta_window_foreach_ancestor (unminimize_window_and_all_transient_parents): ditto (update_sm_hints): ditto (meta_window_is_ancestor_of_transient): ditto * src/stack.c (get_maximum_layer_of_ancestor): use meta_window_foreach_ancestor 2003-03-16 Rob Adams <robadams@ucla.edu> * window.c (meta_window_show_menu): Free old window menu if it already exists so we don't end up with more than one. Fix for #108392. 2003-03-14 Rob Adams <robadams@ucla.edu> * contraints.c (get_outermost_screen_positions): Don't try to force a window onscreen by more than its width. Fix for #94815. 2003-03-13 Rob Adams <robadams@ucla.edu> Make it so that the alt-tabbing won't try to go to a minimized window by default. Fix for #107071. * display.c (meta_display_get_tab_list): use a GList instead of a GSList (meta_display_get_tab_next): use meta_display_get_tab_list to decide what the next/previous tab window should be. * display.h (meta_display_get_tab_list): update function prototype to return GList instead of GSList. * screen.c (meta_screen_ensure_tab_popup): update function to deal with GList returned by meta_display_get_tab_list instead of GSList. 2003-03-13 Christian Rose <menthos@menthos.com> * configure.in: Added "ml" to ALL_LINGUAS. 2003-03-11 Paul Duffy <dubhthach@zion.nuigalway.ie> * configure.in: Added "ga" to ALL_LINGUAS 2003-03-11 Rob Adams <robadams@ucla.edu> * src/constraints.c (meta_window_constrain): include left frame geometry when maximizing or fullscreening windows. Fix for #108127. 2003-03-10 Roozbeh Pournader <roozbeh@sharif.edu> * configure.in: Added "fa" to ALL_LINGUAS. 2003-02-27 Havoc Pennington <hp@redhat.com> Switch over to new constraints code, unquestionably introduces some bugs, but should get us on the right path. * src/window.c (meta_window_get_work_area_all_xineramas): create this function again as it turned out to be legitimate for window position constraint (adjust_for_gravity): use the width/height from the configure request to compute the requested move (meta_window_move_resize_internal): use meta_window_constrain (update_size_hints): clamp max size to MAXSHORT to avoid worrying about overflow stuff * src/constraints.c (meta_window_constrain): don't base placement on uninitialized variables, general hacking * src/Makefile.am (metacity_SOURCES): add constraints.c, constraints.h * src/constraints.c (meta_window_constrain): update the cut-and-paste aspect ratio code to have latest bugfixes 2003-03-08 Rob Adams <robadams@ucla.edu> * src/window-props.c (reload_normal_hints): Check that window min and max size hints are at least 1. Fix for #107110. 2003-02-27 Havoc Pennington <hp@pobox.com> Changes made on plane from FOSDEM, syncing from laptop. * src/main.c (main): add more debug spew about conditional build stuff (main): panic to "Simple" theme * src/window.c, src/window-props.c: move WM_NORMAL_HINTS and WM_PROTOCOLS to new property system; don't queue move resize on updating WM_PROTOCOLS; move WM_HINTS to new property system; reload icon in an idle handler. 2003-02-28 Mark McLoughlin <mark@skynet.ie> Give me back my keys. * src/keybindings.c: (meta_window_grab_keys): don't grab keys on DOCK windows. * src/window.c: (recalc_window_type): re-grab the keys. 2003-02-26 Dmitry G. Mastrukov <dmitry@taurussoft.org> * configure.in: Added Belarusian to ALL_LINGUAS. 2003-02-26 Mark McLoughlin <mark@skynet.ie> * src/keybindings.c: (handle_panel_keybinding): release the keyboard grab before sending the action message to the panel. 2003-02-24 Mark McLoughlin <mark@skynet.ie> Take control of the panel's global keybindings. The screenshot utility is hooked up using a special case run_command and the menu and run dialog bindings are done using the _GNOME_PANEL_ACTION ClientMessage protocol. * src/display.[ch]: (meta_display_open): add some atoms. * src/keybindings.c: (handle_panel_keybinding): impl to handle a keybinding by sending an action message to the panel. * src/metacity.schemas.in: add schemas for the panel and screenshot keybindings and the screenshot commands. * src/prefs.[ch]: (update_command), (meta_prefs_get_gconf_key_for_command): impl special case handling for the screenshot commands. They are stored at the the end of the commands array but have named keys. 2003-02-23 Havoc Pennington <hp@pobox.com> Patch from Rob Adams addresses #95014 (placement issues), makes first fit algorithm "center tile", adds most code for per-xinerama workspaces (#86682) but disables it for now. * src/workspace.c (meta_workspace_get_work_area_for_xinerama) (meta_workspace_get_work_area_all_xineramas): new xinerama functions, maintain workspace->work_areas with a different work area for each xinerama. However for now all the work areas are the same, because haven't quite figured out how _NET_WM_STRUT is supposed to work * src/window.c: adapt to new meta_window_* xinerama APIs (meta_window_get_work_area_current_xinerama): new xinerama API (meta_window_get_work_area_for_xinerama): new xinerama API (constrain_position): be a bit more clever about which xinerama's work area we choose to use. * src/stack.c: adapt to new Xinerama API * src/screen.c (reload_xinerama_infos): invalidate all work areas (meta_screen_get_xinerama_for_rect): new function (meta_screen_window_intersects_xinerama): new function * src/place.c (find_first_fit): change to use "center tiling" (center a screen full of tiled windows, rather than aligning them top left). Adapt to new xinerama functions. 2003-02-22 Rob Adams <robadams@ucla.edu> * src/metacity.schemas.in: change toggle_maximized to toggle_maximize and toggle_shaded to toggle_shade in action_double_click_titlebar long description to match the values used by metacity * po/*.po: change toggle_maximized to toggle_maximize and toggle_shaded to toggle_shade in action_double_click_titlebar long description to match the values used by metacity 2003-02-22 Rob Adams <robadams@ucla.edu> * window.c (set_wm_state): modify comment to explain why the icon window element is set to None. Fix for #97357 thanks to Gregory Merchan. 2003-02-22 Havoc Pennington <hp@pobox.com> * README: fix a typo, pointed out by Steve Kemp 2003-02-22 Havoc Pennington <hp@pobox.com> * src/prefs.c (MAX_REASONABLE_WORKSPACES): change max workspaces to 36 #81855 2003-02-22 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): fix to unfocus window only when you leave the window frame, not when you leave the window itself, unless window has no frame. #100248 fix from Orien Vandenbergh 2003-02-22 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_get_tab_next): when tabbing backward, we are still tabbing *from* the most recently used window, not from the least recently used window. * src/keybindings.c (struct _MetaKeyBinding): make keycode unsigned to match XEvent Patch for #84999 based on patch from Mark McLoughlin * src/prefs.c: add an add_shift field to MetaKeyPref to add shift when grabbing the given keybinding. * src/keybindings.c (rebuild_screen_binding_table) (rebuild_window_binding_table): refactor to share code, and honor add_shift field in MetaKeyPref 2003-02-20 Havoc Pennington <hp@redhat.com> * src/stack.c (create_constraints): don't create constraints between windows on different screens, #106086 tracked down by Arvind 2003-02-14 Arvind Samptur <arvind.samptur@wipro.com> * src/screen.c: (meta_screen_new) : Update the workspace names from gconf and set the NET_DESKTOP_NAMES atom. Renamed update_workspace_names() to set_workspace_names(). Fixes #105498 2003-02-13 Havoc Pennington <hp@redhat.com> * configure.in: require GTK+ 2.2.0 * src/ui.c (meta_ui_init): remove hackaround for Pango X core fonts backend 2003-02-05 Abel Cheung <maddog@linux.org.hk> * configure.in: Added "en_GB" and "nl" to ALL_LINGUAS. 2003-02-05 Akira TAGOH <tagoh@gnome.gr.jp> * src/main.c (usage): fix a typo and missing option. (#105186) 2003-02-04 Havoc Pennington <hp@redhat.com> * src/themes/Simple/ChangeLog: nuke subdir ChangeLog, there can be only one true ChangeLog. 2003-01-30 Havoc Pennington <hp@redhat.com> * src/keybindings.c (process_event): match handlers to key events using key codes, not key syms Thu Jan 30 22:55:16 2003 Jonathan Blandford <jrb@redhat.com> * src/themes/Makefile.am (THEMES): add Simple to the list of themes. * src/metacity.schemas.in: change default theme to Simple. 2003-01-29 Havoc Pennington <hp@pobox.com> * src/menu.c (meta_window_menu_new): don't create workspaces menu items if only 1 workspace. Fix for #101952 from Orien Vandenbergh 2003-01-28 Bill Haneman <bill.haneman@sun.com> * Re-instated visual-bell patch (please see ChangeLog entry for 2002-12-16 for details). * src/prefs.c: (visual_bell_type_from_string): Accept a NULL string for 'visual-bell-type'. 2003-01-25 Havoc Pennington <hp@pobox.com> * src/stack.c (window_is_fullscreen_size): When checking if a window is fullscreen size, only require it to be at the origin of the work area, not at the origin of the screen/xinerama. Still require it to be full screen in width x height. May fix xine in the case where the user has a top panel. * src/window.c (constrain_position): restore the ability for undecorated windows to position themselves overlapping the top panel, but don't let decorated windows do so. Oh the hacks... 2003-01-08 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_apply_startup_properties): small code snippet to fix startup sequences that set legacy class/name 2003-01-22 Havoc Pennington <hp@redhat.com> * src/async-getprop.c (async_get_property_handler): do not read sizeof(long) off the X connection. The X protocol does not vary by architecture. Fixes longstanding hang on all 64-bit platforms. 2003-01-22 Havoc Pennington <hp@redhat.com> * src/tools/Makefile.am: fix conditional so we get metacity-properties.c in the distribution #103071 2003-01-22 Havoc Pennington <hp@pobox.com> * src/window.c (update_struts): be robust against the panel's lame "set a negative number for struts" thing, even though we'll also fix the panel. 2003-01-21 Havoc Pennington <hp@pobox.com> Fix for the "mangles focus window when switching workspaces and using mouse focus" bug * src/stack.c (meta_stack_get_default_focus_window_at_point): new function * src/screen.c (meta_screen_focus_mouse_window): new function (meta_screen_focus_default_window): new function * src/workspace.c (meta_workspace_activate): use the new meta_screen_focus_default_window() 2003-01-17 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_handle_mouse_grab_op_event): fix event compression code to use GDK algorithm suggested by Owen, should be more efficient. 2003-01-22 Christian Rose <menthos@menthos.com> * configure.in: Added "mn" to ALL_LINGUAS. 2003-01-21 Havoc Pennington <hp@redhat.com> * src/display.c (event_callback): only hop window to the current workspace if the window was previously minimized. Should keep mozilla from popping windows over to your current workspace. 2003-01-20 Havoc Pennington <hp@redhat.com> Attempt to fix #85916 * src/keybindings.c (primary_modifier_still_pressed): new function (handle_workspace_switch): handle modifier release prior to getting the grab (do_choose_window): handle modifier release prior to getting the grab * src/keybindings.c (grab_keyboard): properly return failure if the GrabKeyboard doesn't work 2003-01-19 Havoc Pennington <hp@pobox.com> * configure.in: add note about how this is the unstable branch, set version to 2.5.0 2003-01-14 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_maximize, meta_window_unmaximize) (meta_window_make_fullscreen, meta_window_unmake_fullscreen): recalc_window_features() after making these changes, should fix #103317 2003-01-14 Rob Adams <robadams@ucla.edu> * src/prefs.c: Increase the number of run_command bindings in screen_bindings from 12 to 32. * src/prefs.h: Increase the number of META_KEYBINDING_COMMAND_N macros from 12 to 32. * src/keybindings.c: Increase the number of run_command handlers from 12 to 32. 2003-01-11 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_handle_mouse_grab_op_event): implement compression of motion events (drop all but the most recently received), guessing at fixes for #103009 2003-01-11 Havoc Pennington <hp@pobox.com> * configure.in: add ability to --disable-shape 2003-01-11 Akira TAGOH <tagoh@gnome.gr.jp> * configure.in: fix the behavior of --enable-*. 2003-01-10 Havoc Pennington <hp@redhat.com> * src/Makefile.am (desktopfiles_in_files): revert that change, I got the wrong .desktop file. doh. 2003-01-10 Havoc Pennington <hp@redhat.com> * src/Makefile.am (desktopfiles_DATA): don't install .desktop file for properties dialog if we aren't building/installing the properties dialog. 2003-01-10 Havoc Pennington <hp@pobox.com> * NEWS: update * configure.in: bump to 2.4.13, require 2.2.0 for multihead 2003-01-09 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Use a line for the titlebar text bg. 2003-01-09 Havoc Pennington <hp@redhat.com> * src/window.c (recalc_window_features): argh, we were making all dialogs skip taskbar; when did that get added. Fix to match libwnck, only skip taskbar when the dialog is transient for some other app window. 2003-01-09 Havoc Pennington <hp@redhat.com> * src/metacity.schemas.in: change Windows+click back to Alt+click, Windows+click just surprised everybody and didn't work half the time. Maya users can configure it, and GTK DND can change its default. 2003-01-08 Havoc Pennington <hp@pobox.com> * src/metacity.schemas.in: assign Alt+F12 to shade window, per #102658 2003-01-07 Havoc Pennington <hp@pobox.com> * src/screen.c (update_num_workspaces): fix off-by-one, patch from readams@hmc.edu, #102806 2003-01-06 Arvind Samptur <arvind.samptur@wipro.com> * src/window.c: (constrain_position) don't apply offscreen height difference. This would get the window under the panel on a resize or a move. Fixes #102418 2003-01-05 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_calc_workspace_layout): invert vertical_workspaces cases (we want to go down each column if it's vertical, and across each row if horizontal). Patch from readams@hmc.edu 2003-01-05 Pablo Saratxaga <pablo@mandrakesoft.com> * configure.in: Added Macedonian (mk) to ALL_LINGUAS 2003-01-05 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_apply_shapes): put in the HAVE_GTK_MULTIHEAD conditionals so we build with GTK 2.0 2003-01-05 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_show): focus new windows even in mouse focus mode, #89981, patch from readams@hmc.edu 2003-01-05 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_get_neighbor): redo using new calc_workspace_layout to fix #98302 * src/util.c (topic_name): shorten default prefix * src/screen.c (meta_screen_calc_workspace_layout): enhance this to handle all the funky layouts and calculate more information than before 2003-01-05 Pauli Virtanen <pauli.virtanen@hut.fi> * configure.in (ALL_LINGUAS): Added "fi" (Finnish). 2003-01-05 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_apply_shapes): handle the client having a shape mask, fixes #101806 * src/core.c (meta_core_get_client_xwindow): new function * src/frame.c, src/frame.h: keep a flag for whether we need to update the frame shape * src/window.c (meta_window_new): select for ShapeNotify * src/display.h, src/display.c: actually query the shape extension, instead of just using it all over the place. * src/prefs.c (update_application_based): don't let people turn on application_based, as it just causes funky bugs. We can reenable the pref when/if it ever does something useful. 2003-01-03 Havoc Pennington <hp@redhat.com> * src/display.c: include the Xrandr header file * src/window.c (meta_window_fill_horizontal) (meta_window_fill_vertical): maximize to work area, not entire screen. doh. 2002-12-19 Ross Burton <ross@burtonini.com> * doc/metacity-theme.dtd: Fix a typo and loosen the requirements for the resize element. 2002-12-19 Havoc Pennington <hp@pobox.com> * Reverted visual bell patch, #99886 2002-12-19 Yanko Kaneti <yaneti@declera.com> * configure.in: (ALL_LINGUAS) Added Bulgarian (bg). 2002-12-18 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_new): select ColormapChangeMask on toplevel windows, maybe a partial fix for #101478 Tue Dec 17 17:50:19 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> * src/themes/AgingGorilla/metacity-theme-1.xml: added support for border only windows. #100984. 2002-12-17 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_begin_grab_op): don't use "(null)" for null pointers, use "none", so I can distinguish glibc-generated (null) which is a bug. (key_event_description): ditto (meta_display_begin_grab_op): ditto * src/window.c (update_sm_hints): ditto * src/keybindings.c (reload_modmap): ditto (meta_display_process_key_event): ditto 2002-12-17 Havoc Pennington <hp@pobox.com> * src/metacity.schemas.in: s/focussed/focused/ 2002-12-17 Havoc Pennington <hp@pobox.com> * src/xprops.c (validate_or_free_results): add a comma to message #101401 2002-12-16 Bill Haneman <bill.haneman@sun.com> * configure.in: Check for XKB extension. * src/Makefile.am: Added bell.c and bell.h to metacity sources. * src/common.h: (MetaFrameFlags): Added META_FRAME_IS_FLASHING flag. * src/frame.h: (MetaFrame): Added is_flashing field. * src/frame.c: (meta_window_ensure_frame): Initialize the is_flashing flag to FALSE. (meta_frame_get_flags): Handle the FRAME_IS_FLASHING flag. (meta_window_destroy_frame): Call meta_bell_notify_frame_destroy. * src/prefs.h: (MetaPreference): Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, META_PREF_VISUAL_BELL_TYPE. (MetaVisualBellType): New enum. (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): (meta_prefs_get_visual_bell_type): New accessor declarations. * src/prefs.c: (#includes): Include "display.h", since we now call meta_displays_list() in our update func. (#defines): Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL, and KEY_VISUAL_BELL_TYPE. (provide_visual_bell, bell_is_audible, visual_bell_type): New static state variables. (update_visual_bell): New method to update visual-bell boolean settings from keys "visual_bell" and "audible_bell". (update_visual_bell_type): New method to update visual-bell type setting. (visual_bell_type_from_string) : New method to convert from gconf string to visual-bell type enum. Only currently recognized values are "fullscreen" and "frame_flash". (change_notify): Handle changes to visual and audible bell properties. (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): (meta_prefs_get_visual_bell_type): New accessor definitions. (meta_prefs_init): Added a second call to notify_add, listens to "/desktop/gnome/interface" as well as "apps/metacity". Also call the update funcs for the new visual-bell gconf keys. (meta_preference_to_string): Handle the visual/audible bell cases. * src/bell.h: (meta_bell_notify); New method, calls a visual notifucation method based on the visual-bell-type, or none if the type is unrecognized or invalid. (meta_bell_set_audible): New public method for setting the audible bell setting, used in updater for new gconf key "audible_bell". (meta_bell_init): Initialize the bell notification for a display. (meta_bell_shutdown): Shutdown the bell notification for a display. (meta_bell_notify_frame_destroy): Remove pending idle handlers on notification. * src/bell.c: Include "bell.h", and conditionally include <Xll/Xkblib.h>. (meta_bell_set_audible): If XKB is present, enable/disable the audible system bell based on the gconf key /desktop/gnome/interface/audible_bell. (meta_bell_init): Query and initialize XKB if present, register for notification on the bell, and set audible bell according to gconf settings. (meta_bell_flash_screen): Maps and unmaps a fullscreen X window (painted white, then black), which causes a fullscreen 'flash' transient. (meta_bell_flash_window_frame): Flashes the titlebar of a specified window. (meta_bell_flash_frame): Calls meta_bell_flash_window_frame on the window which was the source of the current bell event, or the currently focussed window if the event source cannot be determined. (meta_bell_unflash_frame): Restore the frame's appearance to normal. (meta_bell_flash_fullscreen): Call meta_bell_flash_fullscreen for all screens. (meta_bell_shutdown): New method. (meta_bell_notify_frame_destroy): Remove pending idle handlers on notification, testing for frame->is_flashing first. * src/display.h: (MetaDisplay): Added xkb_base_event_type field. * src/display.c: Check for XKB and include "X11/XKBlib.h" if present. (meta_display_open): Call meta_bell_init. (event_callback): Call meta_bell_notify when event comes from XKB and is XkbBellNotify (prefs_changed_callback): Handle META_PREF_AUDIBLE_BELL notification. * src/screen.h: (MetaScreen): Add flash_window field. * src/screen.c: (meta_screen_new): Initialize flash_window field. * src/theme.c: (theme_get_style): New heuristic for focus-style, to invert sense of focus flag when META_FRAME_IS_FLASHING flag is set. * src/metacity.schemas.in: Added scheme information for /apps/metacity/general/visual_bell, /apps/metacity/general/audible_bell, and /apps/metacity/general/visual_bell_type. 2002-12-16 Havoc Pennington <hp@pobox.com> * src/window-props.c (init_wm_name): argh, screwed that up. get WM_NAME as VALUE_TEXT_PROPERTY #101383 2002-12-16 Bill Haneman <bill.haneman@sun.com> * configure.in: Check for XKB extension. * src/Makefile.am: Added bell.c and bell.h to metacity sources. * src/common.h: (MetaFrameFlags): Added META_FRAME_IS_FLASHING flag. * src/frame.h: (MetaFrame): Added is_flashing field. * src/frame.c: (meta_window_ensure_frame): Initialize the is_flashing flag to FALSE. (meta_frame_get_flags): Handle the FRAME_IS_FLASHING flag. (meta_window_destroy_frame): Call meta_bell_notify_frame_destroy. * src/prefs.h: (MetaPreference): Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, META_PREF_VISUAL_BELL_TYPE. (MetaVisualBellType): New enum. (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): (meta_prefs_get_visual_bell_type): New accessor declarations. * src/prefs.c: (#includes): Include "display.h", since we now call meta_displays_list() in our update func. (#defines): Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL, and KEY_VISUAL_BELL_TYPE. (provide_visual_bell, bell_is_audible, visual_bell_type): New static state variables. (update_visual_bell): New method to update visual-bell boolean settings from keys "visual_bell" and "audible_bell". (update_visual_bell_type): New method to update visual-bell type setting. (visual_bell_type_from_string) : New method to convert from gconf string to visual-bell type enum. Only currently recognized values are "fullscreen" and "frame_flash". (change_notify): Handle changes to visual and audible bell properties. (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): (meta_prefs_get_visual_bell_type): New accessor definitions. (meta_prefs_init): Added a second call to notify_add, listens to "/desktop/gnome/interface" as well as "apps/metacity". Also call the update funcs for the new visual-bell gconf keys. (meta_preference_to_string): Handle the visual/audible bell cases. * src/bell.h: (meta_bell_notify); New method, calls a visual notifucation method based on the visual-bell-type, or none if the type is unrecognized or invalid. (meta_bell_set_audible): New public method for setting the audible bell setting, used in updater for new gconf key "audible_bell". (meta_bell_init): Initialize the bell notification for a display. (meta_bell_shutdown): Shutdown the bell notification for a display. (meta_bell_notify_frame_destroy): Remove pending idle handlers on notification. * src/bell.c: Include "bell.h", and conditionally include <Xll/Xkblib.h>. (meta_bell_set_audible): If XKB is present, enable/disable the audible system bell based on the gconf key /desktop/gnome/interface/audible_bell. (meta_bell_init): Query and initialize XKB if present, register for notification on the bell, and set audible bell according to gconf settings. (meta_bell_flash_screen): Maps and unmaps a fullscreen X window (painted white, then black), which causes a fullscreen 'flash' transient. (meta_bell_flash_window_frame): Flashes the titlebar of a specified window. (meta_bell_flash_frame): Calls meta_bell_flash_window_frame on the window which was the source of the current bell event, or the currently focussed window if the event source cannot be determined. (meta_bell_unflash_frame): Restore the frame's appearance to normal. (meta_bell_flash_fullscreen): Call meta_bell_flash_fullscreen for all screens. (meta_bell_shutdown): New method. (meta_bell_notify_frame_destroy): Remove pending idle handlers on notification, testing for frame->is_flashing first. * src/display.h: (MetaDisplay): Added xkb_base_event_type field. * src/display.c: Check for XKB and include "X11/XKBlib.h" if present. (meta_display_open): Call meta_bell_init. (event_callback): Call meta_bell_notify when event comes from XKB and is XkbBellNotify (prefs_changed_callback): Handle META_PREF_AUDIBLE_BELL notification. * src/screen.h: (MetaScreen): Add flash_window field. * src/screen.c: (meta_screen_new): Initialize flash_window field. * src/theme.c: (theme_get_style): New heuristic for focus-style, to invert sense of focus flag when META_FRAME_IS_FLASHING flag is set. * src/metacity.schemas.in: Added scheme information for /apps/metacity/general/visual_bell, /apps/metacity/general/audible_bell, and /apps/metacity/general/visual_bell_type. 2002-12-16 Havoc Pennington <hp@pobox.com> * src/window-props.c: use META_PROP_VALUE_STRING_AS_UTF8 so we convert old Latin-1 WM_NAME to UTF-8 * src/xprops.h (enum): add META_PROP_VALUE_STRING_AS_UTF8 to get a latin1 string then convert. 2002-12-15 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): get window name before anything else. * src/xprops.c (validate_or_free_results): instead of suggesting how to get window title etc. with xprop, just print out the window title. much better. 2002-12-15 Havoc Pennington <hp@pobox.com> * src/xprops.c (validate_or_free_results): make the warning about strange property contents blame the application and explain how to use xprop to diagnose which app is causing the problem. 2002-12-15 Havoc Pennington <hp@pobox.com> * src/prefs.c (meta_prefs_change_workspace_name): don't pass NULL string to gconf_client_set_string #101237 2002-12-13 Havoc Pennington <hp@redhat.com> * src/tools/Makefile.am (Desktop_in_files): only install .desktop file for metacity-properties if we actually install metacity-properties * src/display.c (event_callback): not focusing on button 2 click was crack, revert that change. 2002-12-09 Havoc Pennington <hp@pobox.com> * AUTHORS: add myself here, bug #100789 * src/display.c (meta_display_set_grab_op_cursor): drop PointerMotionHintMask * src/window.c (meta_window_handle_mouse_grab_op_event): don't use XQueryPointer, as we aren't using PointerMotionHint now * src/display.c (event_callback): rearrange a bit of code for slight speedup and clarity * src/window.c (update_resize) (meta_window_handle_mouse_grab_op_event): implement usage of the _METACITY_UPDATE_COUNTER (meta_window_handle_mouse_grab_op_event): fix code that used event->xbutton with a motion event * src/display.c (meta_display_open): add new atoms, and initialize Xsync if we have it (grab_op_is_resizing): new function (meta_display_begin_grab_op): create an alarm monitoring window's _METACITY_UPDATE_COUNTER (meta_spew_event): conditionalize this on WITH_VERBOSE_MODE and print alarm events. * src/window.c (meta_window_new): fetch _METACITY_UPDATE_COUNTER * configure.in (HAVE_XSYNC): check for Xsync extension Mon Dec 9 22:09:56 2002 Soeren Sandmann <sandmann@daimi.au.dk> * src/display.c, src/window.c: Handle crossing events during resizing. (#93384). 2002-12-09 Havoc Pennington <hp@redhat.com> * configure.in: 2.4.8 2002-12-08 Havoc Pennington <hp@pobox.com> * README: updates * src/window.c (MAX_RESIZES_PER_SECOND): change to 20 instead of 30, just as an experiment. (MOVE_THRESHOLD): change 15 to 20 (RESIZE_THRESHOLD): change 15 to 20 * src/util.c (ensure_logfile): kill this function when verbose mode is disabled. 2002-12-08 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_fill_vertical) (meta_window_fill_horizontal): new functions to resize to fill screen * src/keybindings.c: add vert, horiz maximize * src/prefs.c: had vert, horiz maximize * src/metacity.schemas.in: shorten some overlong short descriptions that make the keybindings capplet look ugly. Add maximize_vertically, maximize_horizontally keys. 2002-12-08 Havoc Pennington <hp@pobox.com> * src/prefs.c (meta_prefs_get_application_based): make this always return FALSE for now, to avoid bug reports. * src/util.c (ensure_logfile): put "opened log file" message on stderr so it will normally land in ~/.xsession-errors * configure.in: remove extra AC_ARG_PROGRAM * src/display.c (event_callback): handle the toggle-verbose message * src/tools/metacity-message.c: add a toggle-verbose message, been meaning to do this for a while. * src/util.c (meta_set_verbose): if verbose mode is enabled and we don't support it, then exit. * src/prefs.c: allow building without gconf (currently means some prefs are no-ops) * src/util.c, src/util.h: support defining macros to kill all verbose output entirely. (Removes the code and strings associated with it) * configure.in: don't get METACITY_PROPS_LIBS if not building the config dialog. (HAVE_GCONF): allow building sans gconf, if you are size-sensitive and not using gnome. (WITH_VERBOSE_MODE): add ability to disable all the verbose debug spew strings, to shrink the binary. (--disable-sm): allow SM support to be forced on or off (--disable-startup-notification): allow forcing this on or off 2002-12-08 Havoc Pennington <hp@pobox.com> * src/prefs.c (update_workspace_name): also treat empty string as "unset" in this function. Thu Dec 5 18:41:02 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> * src/window.h (META_WINDOW_IN_NORMAL_TAB_CHAIN, META_WINDOW_IN_DOCK_TAB_CHAIN) : never use a window with input = FALSE take_focus = FALSE in the normal and dock tab chains. #90409 Thu Dec 5 13:56:52 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> * src/display.c (event_callback): move a window to the current space on the MapRequest when it's not on the space yet. #100390 2002-12-01 Havoc Pennington <hp@pobox.com> * src/frames.c (get_control): rearrange this function a bit, so that we return CONTROL_TITLE for anything above the bottom of the titlebar, in the fallback case where no other control was found. Also, don't return RESIZE_N for title rect above the top resize size, unless the window is resizable. (meta_frames_button_press_event): only start a move when clicking control TITLE, not control NONE. This way you don't start moving a nonresizable window if you click its edges. 2002-12-01 Havoc Pennington <hp@pobox.com> * src/tools/Makefile.am: conditionalize building the config dialog * configure.in (BUILD_CONFIG_DIALOG): add --enable-config-dialog option to turn on the "window focus" dialog. This is part of deprecating this dialog. 2002-11-30 Havoc Pennington <hp@pobox.com> * src/screen.c (STARTUP_TIMEOUT): lengthen to 15 seconds * src/util.c (utf8_fputs): hmm, return a value * src/screen.c (meta_screen_apply_startup_properties): new function to apply initial workspace based on startup sequence. * src/window.c (meta_window_new): load _NET_STARTUP_ID (meta_window_get_startup_id): new function * src/window-props.c (meta_display_init_window_prop_hooks): add hooks for _NET_STARTUP_ID * src/display.c (event_callback): send property events to groups. * src/xprops.c (meta_prop_get_values): make a type of INVALID mean to ignore that property (don't fetch its value). * src/group.c (meta_group_property_notify): new function * src/screen.c (set_supported_hint): support _NET_STARTUP_ID * src/display.c (meta_display_open): add _NET_STARTUP_ID to atoms we initialize * src/group-private.h: private header shared between group-props.c, group.c * src/group-props.h, src/group-props.c: new files to contain functions for retrieving group properties * src/window.c (meta_window_same_application): change this a bit to work with new definition of group * src/group.c (meta_window_get_group): always create a group for every window, using the window's own ID as group leader if required. * src/window.c (update_wm_hints): handle changes to group leader * src/group.c (meta_window_group_leader_changed): new function * src/display.h (struct _MetaDisplay): _NET_WM_WINDOW_TYPE_SPLASH, not SPLASHSCREEN. Reported by Gregory Merchan and Matthias Clasen. * src/screen.c (startup_sequence_timeout): when timing out a startup sequence, send a remove message, don't just time it out locally. 2002-11-26 Calum Benson <calum.benson@sun.com> * src/themes/Crux : Removed alpha layers from the pixmaps that don't need them. Fixes #98389, results in 10-15% speedup on most machines. 2002-11-26 Glynn Foster <glynn.foster@sun.com> * configure.in: 2.4.5 2002-11-23 Dan Mills <thunder@ximian.com> * Makefile.am: remove theme-format.txt, it's now in doc/. 2002-11-22 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_change_workspace): patch from Hidetoshi Tajima to move a window's transients when moving the window between workspaces. #98900 2002-11-21 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_open): init ret_to to RevertToPointerRoot out of sheer paranoia; don't want no RevertToNone in my code! 2002-11-21 Havoc Pennington <hp@pobox.com> * src/window.c (update_initial_workspace): delete (meta_window_new): add getting initial workspace to the batch property get call * src/window-props.c (meta_display_init_window_prop_hooks): add net_wm_desktop and win_workspace support 2002-11-20 Havoc Pennington <hp@pobox.com> * src/window-props.c (set_icon_title): remove unused variable * src/screen.c (meta_screen_new): read an existing _NET_CURRENT_DESKTOP and restore it if set. Makes a restart even less visible. * src/workspace.c (set_active_space_hint): don't set the hint during the process of unmanaging a screen 2002-11-20 Havoc Pennington <hp@pobox.com> * configure.in: add doc/Makefile * doc/metacity-theme.dtd: add DTD for themes from Ross Burton * doc/Makefile.am: doc subdir * doc/theme-format.txt: move to doc subdir 2002-11-19 Havoc Pennington <hp@pobox.com> Should really fix #98303 * src/prefs.c (meta_prefs_change_workspace_name): add bad hack to treat empty string the same as null * src/menu.c (get_workspace_name_with_accel): allocate one more than the length of "name" so we have room for a nul byte (and don't malloc(0) on empty strings). Also some formatting cleanups. 2002-11-19 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_client_message): do a recalc_window_features after setting new wm_state in order to update skip_pager in addition to wm_state_skip_pager (set_net_wm_state): base _NET_WM_STATE on skip_pager not wm_state_skip_pager, ditto for skip_taskbar 2002-11-19 Havoc Pennington <hp@pobox.com> Fix #98303 and assorted cleanup * src/prefs.c (meta_preference_to_string): handle META_PREF_WORKSPACE_NAMES * src/menu.c (get_workspace_name_with_accel): assert that the workspace has a name * src/screen.c (meta_screen_ensure_workspace_popup): assert that we got a workspace name (meta_screen_ensure_workspace_popup): assert that we got a workspace name * src/prefs.c (update_workspace_name): fix screwiness (strcmp with a freed string, assorted bad logic) (init_workspace_names): assert that we filled in a default workspace name (meta_prefs_get_workspace_name): assert non-NULL workspace name 2002-11-16 Bill Haneman <bill.haneman@sun.com> * src/themes/Atlanta/metacity-theme-1.xml: Changed outer bevel and focus line color to work better with inverse themes (no effect on Default or other existing gtk+ themes). 2002-11-13 Havoc Pennington <hp@pobox.com> * src/ui.c (get_cmap): fix a multihead safety thing (use proper system colormap for the drawable's screen) Thu Nov 14 17:30:10 2002 Jonathan Blandford <jrb@gnome.org> * src/Makefile.am (libmetacityinclude_HEADERS): include common.h. 2002-11-12 Havoc Pennington <hp@pobox.com> * src/theme.c (draw_op_as_pixbuf): don't read from op->data.image when the op is an icon 2002-11-12 Havoc Pennington <hp@redhat.com> * src/stack.c (meta_stack_get_default_focus_window): never use a window with input = FALSE take_focus = FALSE as the default focus window #95454 fix from Hidetoshi Tajima 2002-11-10 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Major changes to look of theme. I'd also recommend "minimize,maximize:close" for the button_layout, it looks really slick :-). 2002-11-08 Mark McLoughlin <mark@skynet.ie> * src/workspace.c: (meta_motion_direction_to_string), (meta_screen_corner_to_string): impl for nice debugging. (meta_workspace_get_neighbor): fix broken logic and cleanup debugging. Thu Nov 7 17:07:21 2002 Jonathan Blandford <jrb@redhat.com> * src/libmetacity-private.pc.in: add a pc file for libmetacity-private * src/Makefile.am: Install a few files as a shared library so that others can draw metacity themes. 2002-11-06 Havoc Pennington <hp@pobox.com> * src/keybindings.c (grab_keys): push an error trap around the whole window-key-grab loop (ungrab_all_keys): avoid requiring return value from the error trap, unless in debugging mode (regrab_window_bindings, regrab_screen_bindings): push traps around the loops, for efficiency * src/display.c (event_callback): fix from Padraig O'Briain to compress extra MappingNotify events to avoid extra work. 2002-11-05 Calum Benson <calum.benson@sun.com> * src/themes/Crux/active-restore-button.png: * src/themes/Crux/inactive-restore-button.png: * src/themes/Crux/metacity-theme-1.xml: add a restore button for maximized windows, and un-hard-code titlebar text colors. Fixes #97759. 2002-11-05 Havoc Pennington <hp@redhat.com> * src/workspace.c (meta_workspace_get_neighbor): apply patch from Nikos Mouat to fix this function 2002-11-04 Havoc Pennington <hp@pobox.com> * src/theme.c (scale_and_alpha_pixbuf): fix bug I introduced in case where scaling was done in both directions. 2002-11-04 Havoc Pennington <hp@pobox.com> Patch from Brian Cameron to implement the vertical/horizontal striped image accelerated scaling from the gtk pixbuf engine. * src/theme.c (scale_and_alpha_pixbuf): if an image is vertical/horizontal stripes, use special extra-fast scaling routines. * src/theme-parser.c (parse_draw_op_element): when loading an image, mark it as vertically/horizontally striped when appropriate 2002-11-04 Erwann Chenede - <erwann.chenede@sun.com> * src/xprops.c (meta_prop_get_values): changed __FUNCTION__ to G_GNUC_FUNCTION as __FUNCTION__ is not portable. 2002-11-03 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_grab): remove XSync calls from here (meta_display_ungrab): remove XSync from here, but put in an XFlush to be sure we get the ungrab sent. * src/util.c (meta_topic): track sync count here * src/errors.c: move sync count out of here Throughout: error spew on all XSync() calls * src/run-metacity.sh: don't set METACITY_DEBUG 2002-11-03 Havoc Pennington <hp@pobox.com> * src/window-props.c (meta_display_init_window_prop_hooks): add _NET_WM_NAME, WM_NAME, _NET_WM_ICON_NAME, WM_ICON_NAME support * src/window.c (meta_window_new): use window-props.h for _NET_WM_NAME, WM_NAME, _NET_WM_ICON_NAME, WM_ICON_NAME 2002-11-03 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): use window-props.h stuff for a couple of properties (implement_showing): fix printf string * src/xprops.c (meta_prop_free_values): new function * src/window-props.h, src/window-props.c: start moving code that handles loading window properties into this file. 2002-11-03 Havoc Pennington <hp@pobox.com> * src/stack.c (create_constraints): filter out windows that aren't in the stack for whatever reason, avoids a crash 2002-11-03 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_calc_showing): split into "see if we should be showing" and "actually show/hide" functions (idle_calc_showing): rework to first unmap all newly-hidden windows from bottom to top then map all newly-showing windows from top to bottom resulting in fewer exposes, #95220 2002-11-03 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_frame_layout_calc_geometry): fix from Garrett LeSage for which button backgrounds we draw when 2002-11-03 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_get_name): new function, and remove workspace->name field, instead just get the name from prefs each time * src/screen.c (meta_screen_update_workspace_names): update the gconf key to persist workspace names here, instead of changing the names we use * src/util.c (topic_name): add META_DEBUG_PREFS * src/prefs.c: change NUM_COMMANDS to 32 to allow more custom commands, implement workspace names * src/metacity.schemas.in: add workspace_names/name_NN gconf keys. 2002-11-01 Christian Neumair <chris@gnome-de.org> * configure.in: We want at least autoconf 2.5. 2002-10-29 Havoc Pennington <hp@pobox.com> * configure.in: 2.4.3, why not 2002-10-28 Havoc Pennington <hp@redhat.com> * src/window.c (update_size_hints): use meta_prop_get_size_hints * src/xprops.c: add support for getting XSizeHints 2002-10-28 Havoc Pennington <hp@pobox.com> * src/window.c, src/display.c: store the window menu on the display and blow it away when a window closes, so we don't get funny stuck menus. Patch from Martin Garton #87514 2002-10-27 Anders Carlsson <andersca@gnu.org> * configure.in: Make XRandr detection work better. 2002-10-27 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_free): move meta_window_shutdown_group() much earlier in the destroy process. May fix #96928 tracked down by Kjartan Maraas and Martin Garton. * src/group.c (meta_window_get_group): never add window to a group after we've started unmanaging the window 2002-10-26 Havoc Pennington <hp@pobox.com> * src/iconcache.c: include config.h * src/group.c: include config.h * src/frame.c: include config.h * src/core.c: include config.h so it doesn't crash all over the place due to #ifdef HAVE_STARTUP_NOTIFICATION * src/util.c (meta_print_backtrace): export from this file * src/main.c (log_handler): print backtrace here 2002-10-26 Havoc Pennington <hp@pobox.com> * src/wm-tester/main.c (evil_timeout): make windows randomly transient for each other http://bugzilla.gnome.org/show_bug.cgi?id=96928 2002-10-26 Havoc Pennington <hp@pobox.com> * src/xprops.c (meta_prop_get_text_property): new function (meta_prop_get_wm_hints): new function (meta_prop_get_class_hint): new function 2002-10-26 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): use multi-value-get on a couple of properties for testing * src/xprops.c (meta_prop_get_values): implement multi-value-get * src/window.c (update_mwm_hints): XFree motif hints as we changed it to use Xmalloc * src/xprops.c: massively rework this to set up a get-multiple-properties-at-once API. * src/async-getprop.c (ag_Xmalloc): new function 2002-10-25 Havoc Pennington <hp@pobox.com> Add "busy cursor on app startup" support, conditionally - works only if libstartup-notification is found, and in practice requires a GTK patch that's not in yet. * src/screen.c: monitor startup events and set busy cursor if appropriate * src/display.c (meta_display_open): create SnDisplay * configure.in: check for startup notification, and add the cute "configure summary" at the end 2002-10-24 Havoc Pennington <hp@redhat.com> * src/theme.c (meta_frame_layout_calc_geometry): if only one right-corner button, use right_right_background not right_left_background 2002-10-24 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_get_icon_geometry): make public * src/screen.c (meta_screen_ensure_tab_popup): put the alt+tab highlight-window indicator on the icon, not the window itself, if the window is minimized. 2002-10-24 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_get_tab_list): put minimized windows at the end of Alt+Tab, #89416 2002-10-23 Havoc Pennington <hp@redhat.com> * src/theme.c (meta_frame_layout_calc_geometry): initialize the left button background rectangles. 2002-10-21 Havoc Pennington <hp@redhat.com> Optimizations for managing new windows (do not all take effect if METACITY_DEBUG=1). Bug #96404 * src/keybindings.c (meta_change_keygrab): use error trap nesting and conditionalize on meta_is_verbose() to avoid a ton of XSync * src/display.c (meta_change_button_grab): ditto Throughout: move to new error trap setup to save on XSync calls, new setup is: * src/errors.c (meta_error_trap_push_with_return): new function, an error trap that needs to care about return value and thus sync even if an outer trap still exists (meta_error_trap_pop_with_return): new function (meta_error_trap_pop): add "last_request_was_roundtrip" argument allowing us to avoid XSync() if we just did a GetProperty or whatever. * src/util.c (meta_warning): flush the warning file descriptor * src/Makefile.am (INCLUDES): define G_LOG_DOMAIN 2002-10-20 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_image_window_new): put multihead stuff in HAVE_GTK_MULTIHEAD, reported by John Palmieri 2002-10-20 Havoc Pennington <hp@pobox.com> * src/keybindings.c (handle_raise_or_lower): check above->mapped before deciding if it overlaps the window being raiselowered, fix from Stephane Chauveau 2002-10-19 Jeremy Katz <katzj@redhat.com> * configure.in: make Xrandr check less noisy 2002-10-18 Havoc Pennington <hp@redhat.com> * src/effects.c (meta_effects_draw_box_animation): call meta_image_window_new in multihead-safe way * src/ui.c (meta_image_window_new): multihead safety 2002-10-18 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_refresh_resize_popup): only create the resize popup if width_inc or height_inc are > 1 * src/resizepopup.c: Clear out all the weird tickmark cruft, saves us about 2.5K of binary size, whee (meta_ui_resize_popup_new): take display/screen arguments and make multihead-safe #94349 2002-10-18 Havoc Pennington <hp@redhat.com> * src/keybindings.c (do_choose_window): don't start the cycle process if the binding for switching windows has no modifier bits, just focus the window immediately. * src/prefs.c, src/keybindings.c: add a keybinding to move between windows that goes in the opposite direction. This is mostly useful if you want to bind unmodified keys to the switch windows functions, e.g. if you have "Forward" and "Back" keys on your keyboard. Patch from Shilad Sen <shilad sourcelight com> 2002-10-18 Havoc Pennington <hp@redhat.com> * src/prefs.c, src/frames.c: add "what happens when you double click the titlebar" setting, patch from Sean Middleditch bug #95625. This is basically an "add Windows emulation mode" patch. 2002-10-18 Havoc Pennington <hp@redhat.com> * src/metacity.schemas.in: move window-click to Super+click not Alt+click by default. Super should be the Windows key on keyboards that have one and are so configured. Prepare for the FAQ on this. 2002-10-18 Havoc Pennington <hp@redhat.com> * src/window.c (constrain_size): fix min aspect handling, patch from Martin Garton #94943 2002-10-18 Andras Timar <timar@gnome.hu> * configure.in: Added hu to ALL_LINGUAS. 2002-10-18 Havoc Pennington <hp@pobox.com> * src/stack.c (constrain_stacking): replace the old apply_constraints with wacky new approach involving graphing all the constraints then walking the graph. Fixes #94876 and probably other stacking bugs as well, thanks to Arvind for tracking down the issue. (compute_layer): add FIXME and reference to bug #96140 2002-10-17 Havoc Pennington <hp@redhat.com> * src/stack.c (apply_constraints): don't place transient-for-whole-group windows above _each other_, only above other windows in the group that aren't themselves transient-for-whole-group. Should help with part of #94876 2002-10-17 Havoc Pennington <hp@redhat.com> * src/stack.c (apply_constraints): fix memory leak of group_windows, and don't use the variable name "tmp" twice. Shadow variables bad. 2002-10-17 Havoc Pennington <hp@redhat.com> * src/tools/metacity-window-demo.c (dialog_cb): add code to create big stacks of dialogs transient for each other, for testing. 2002-10-16 Havoc Pennington <hp@redhat.com> * src/workspace.c: workspaces are all per-screen now, fix accordingly * src/core.c: fix multihead workspace stuff * src/keybindings.c: multihead-rama * src/screen.c (meta_screen_show_desktop): new functions to replace display equivalents * src/display.c (meta_display_get_workspace_by_screen_index): get rid of this (meta_display_get_workspace_by_index): get rid of this (event_callback): handle _NET_SHOWING_DESKTOP message per-screen * src/screen.c (meta_screen_get_workspace_by_index): new function * src/screen.h (struct _MetaScreen): move workspace list, and showing_desktop flag, to be per-screen * src/window.c (window_query_root_pointer): return whether pointer is on window's screen (meta_window_handle_mouse_grab_op_event): don't use coordinates from other screens when updating a window operation on the current screen. I can't believe no one has reported this... 2002-10-16 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_client_message): update window layer when above/below state is changed. Fixed by Ross Burton. 2002-10-14 Federico Mena Quintero <federico@ximian.com> * src/display.c (event_callback): Ignore EnterNotify events when the detail field is set to NotifyInferior. Fixes #95747. 2002-10-12 Havoc Pennington <hp@pobox.com> * src/metacity.schemas.in: button layout key * src/prefs.c: Add button layout gconf key (change_notify): use some "else if" instead of "if" where we should have been 2002-10-11 Havoc Pennington <hp@redhat.com> * src/display.c (event_callback): don't raise window on button 2 click, only on button 1 and button 3. * src/frames.c (meta_frames_button_press_event): lower on button 2 press on frame * src/core.c (meta_core_user_lower): new function 2002-10-11 Havoc Pennington <hp@pobox.com> * src/stack.c (window_is_fullscreen_size): make the checks here allow windows larger than the screen in addition to exactly-screen-size * src/window.c (meta_window_configure_request): delete the "try to auto-enter-fullscreen-state" hack here, because it was broken, and the changes to the stacking code to move screen-size focused windows to the fullscreen layer should work better. (meta_window_new): remove auto-fullscreen hack from here too 2002-10-09 Havoc Pennington <hp@pobox.com> * src/stack.c (apply_constraints): also keep utility/menu/toolbar windows above their whole group. (get_standalone_layer): don't use META_LAYER_FOCUSED_WINDOW, but only use META_LAYER_FULLSCREEN while the fullscreen window has focus. Also, put screen-sized windows in the fullscreen layer, even if we didn't dare to actually put them in the fullscreen state. 2002-10-07 Havoc Pennington <hp@redhat.com> Add a modifier key preference for the Alt+click stuff. Can be set to "disabled" as well. * src/run-metacity.sh: load .Xmodmap in the Xnest if it exists * src/display.c (meta_display_ungrab_window_buttons): ungrab AnyModifier in case the modifier changed since we grabbed (meta_display_open): rearrange code to use meta_display_close() to mop up when we can't find any screens, avoiding the need to keep the bail-out code in sync with meta_display_close. * src/keybindings.c (devirtualize_modifiers): move this function to a public place in display.c * src/metacity.schemas.in: add setting for the modifier key to use for Alt+left/middle/right click. * src/prefs.c (update_binding): add a missing newline to a warning (meta_prefs_get_mouse_button_mods): new function * src/ui.c (meta_ui_parse_modifier): new function 2002-10-07 Havoc Pennington <hp@pobox.com> * src/async-getprop.c: don't include unportable Xproto.h, fix from Glynn Foster. 2002-10-06 Havoc Pennington <hp@pobox.com> * src/async-getprop.c: change to add only one _XAsyncHandler per display, speeding things up a bit. 2002-10-06 Havoc Pennington <hp@pobox.com> * src/async-getprop.c: Add wacky hack suggested by Keith Packard to get X properties asynchronously. Not actually used by metacity yet, but thinking about it. 2002-10-04 Havoc Pennington <hp@redhat.com> * configure.in: actually link to RANDR_LIBS 2002-10-04 Havoc Pennington <hp@redhat.com> * src/display.c (event_callback): do XRRUpdateConfiguration() if we have RandR extension, else poke in Xlib's screen struct to update the screen size. * configure.in: fix a bogus overwrite of cppflags, add a check for RandR extension 2002-10-04 Arvind Samptur <arvind.samptur@wipro.com> * src/window.c (meta_window_change_workspace): call meta_window_unstick before adding window to workspace. (menu_callback): call meta_workspace_activate before meta_window_change_workspace. This would avoid us running an extra loop for determining the window workspace list. Patches from Jeyasudha and Arvind. Fixes #92575 2002-10-03 Havoc Pennington <hp@pobox.com> * src/themes/Esco/metacity-theme-1.xml: only specify the middle backgrounds, let left/right fall back to middle * src/theme.c (get_button): fall back to middle_background draw routines when missing the left/right button backgrounds. (button_rect): fix to handle drawing middle button backgrounds (meta_frame_style_draw): draw middle background once per middle button 2002-10-03 Havoc Pennington <hp@pobox.com> Button-reordering patch. Has all the code except actually installing a gconf schema and reading the gconf key in prefs.c. metacity-theme-viewer displays the button layouts for testing themes. * src/preview-widget.c (meta_preview_size_request): make up a width/height if no child widget * src/prefs.c (meta_prefs_get_button_layout): new function * src/frames.c: get the button layout from prefs and use it when drawing * src/theme.c (meta_frame_layout_calc_geometry): enhance to be able to lay out buttons in different arrangements (button_rect): draw the new button background rectangles (meta_theme_draw_frame): require a button layout argument (meta_theme_calc_geometry): pass in the button layout * src/preview-widget.h: mod to handle button layouts * src/theme-viewer.c: mod to handle button layouts 2002-10-03 Havoc Pennington <hp@redhat.com> * configure.in: 2.4.2 2002-10-03 Havoc Pennington <hp@redhat.com> * src/window.c (check_moveresize_frequency): handle the case where the clock is set backward 2002-10-01 Havoc Pennington <hp@pobox.com> * src/place.c (find_next_cascade): try extra cascades alongside the first, if the first fails; patch from readams@hmc.edu 2002-10-01 Havoc Pennington <hp@pobox.com> * src/stack.c (get_standalone_layer): put ABOVE windows in same layer as docks. 2002-10-01 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_resize_func): make it static * src/stack.c (get_standalone_layer): put above/below windows in an appropriate layer. * src/screen.c (set_supported_hint): say we support above/below * src/display.h (struct _MetaDisplay): add _NET_WM_STATE_ABOVE, _NET_WM_STATE_BELOW atoms * src/window.c (meta_window_client_message): handle above/below state messages (set_net_wm_state): handler above/below state (update_net_wm_state): handle above/below states 2002-10-01 Mark McLoughlin <mark@skynet.ie> * src/screen.c: (meta_screen_new): default to topleft starting corner. (meta_screen_update_workspace_layout): handle new property format : orient,x,y,starting corner. Fixes #89373. * src/screen.h: add MetaScreenCorner enum. 2002-10-01 Havoc Pennington <hp@pobox.com> * src/window.c (constrain_position): always align fullscreen windows to top, as we do with maximized windows. 2002-10-01 Stanislav Brabec <sbrabec@suse.cz> * configure.in: Added cs to ALL_LINGUAS. 2002-09-30 Havoc Pennington <hp@pobox.com> * src/screen.c (reload_xinerama_infos): fix compilation on Solaris, patch from Satyajit Kanungo 2002-09-29 Havoc Pennington <hp@pobox.com> * src/eggaccelerators.c: update from libegg to get fix from Ralph Loader for <Super> <Hyper> <Meta> parsing, #93005 2002-09-29 Havoc Pennington <hp@pobox.com> * src/effects.h (META_MINIMIZE_ANIMATION_LENGTH): shorten minimize animation a bit 2002-09-28 Havoc Pennington <hp@pobox.com> Patch from Keith Packard to handle root window resizes. * src/screen.c (reload_xinerama_infos): factor out Xinerama code (meta_screen_resize): implement this, to be called from display.c on screen resize * src/display.c (event_callback): handle ConfigureNotify on root windows 2002-09-28 Havoc Pennington <hp@pobox.com> * src/stack.c (get_standalone_layer): re-enable the FOCUSED_WINDOW layer, should now work correctly. 2002-09-28 Havoc Pennington <hp@pobox.com> * src/window.c, src/stack.c: Rewrite stack code to work a lot differently. Should be better now, and not lose relative positions of windows when moving among layers. Also should now be possible to get session management to restore the stacking order. Probably breaks some stuff, and makes all the stack.c changes I made yesterday sort of irrelevant. 2002-09-27 Havoc Pennington <hp@pobox.com> * src/stack.c (get_standalone_layer): Temporarily disable use of the FOCUSED_WINDOW layer, because given the fact that moving multiple windows into the same layer changes the Z-order of those windows, it was breaking click-to-focus. 2002-09-27 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_focus_top_window): raise the focused window, since it may not be the window on top, given the below change. * src/stack.c (meta_stack_get_default_focus_window): make this more complex to prefer to focus the transient parent, followed by other windows in group, followed by topmost non-dock, followed by dock. Previously was just topmost non-dock followed by dock ignoring groups and transiency. 2002-09-27 Havoc Pennington <hp@pobox.com> * src/place.c (constrain_placement): constrain placement to try to keep windows from going offscreen to the right/bottom * src/stack.c (compute_layer): rearrange the logic here to say that a window must always be in at least as high a layer as any of its transient parents or group members, rather than special-casing fullscreen. Also, group_member_is_fullscreen was leaking the list of group members every time, a fairly major memory leak. 2002-09-27 Havoc Pennington <hp@redhat.com> * src/themes/Makefile.am (THEMES): use AgingGorilla not Gorilla (renamed on the CVS server) 2002-09-27 Havoc Pennington <hp@redhat.com> Try to handle Solaris Xinerama, all coded blind, someone on Solaris will need to debug the typos. * src/display.c: updates for Solaris Xinerama * src/screen.c: updates for Solaris Xinerama * configure.in: make Xinerama check more complicated to catch Solaris Xinerama 2002-09-27 Havoc Pennington <hp@redhat.com> * src/window.c (update_transient_for): keep a flag transient_parent_is_root_window for whether the root-window-as-parent convention was used. 2002-09-25 Arvind Samptur <arvind.samptur@wipro.com> * src/stack.c (sort_window_list): Keep dialogs without transient parent above entire app. Fixes #88926 2002-09-26 Havoc Pennington <hp@pobox.com> * src/menu.c (meta_window_menu_new): use MetaAccelLabel to display accelerators for the menu items * src/metaaccellabel.c: cut-and-paste GtkAccelLabel and port to use virtual modifiers * src/Makefile.am (metacity_SOURCES): add metaaccellabel.[hc] * src/prefs.c (meta_prefs_get_window_binding): new function * src/core.c (meta_core_get_menu_accelerator): new function 2002-09-25 Havoc Pennington <hp@redhat.com> * src/metacity.schemas.in: Change short desc of switch_windows and cycle_windows to be different 2002-09-24 Havoc Pennington <hp@pobox.com> * src/place.c (fit_rect_in_xinerama): update best_overlap as we go through the loop - doh. Fix from readams@hmc.edu for #90799. (find_first_fit): try the origin of each xinerama screen after the first. Also from readams@hmc.edu 2002-09-24 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_save_rect): new function, only saves rect after checking current state, #93795 (meta_window_make_fullscreen): use new function (meta_window_maximize): use new function 2002-09-24 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_update_layer): new function * src/stack.c (compute_layer): put focused window in a layer above all other windows, in click-to-focus mode. #93022 * src/window.c (meta_window_notify_focus): update window layer on focus change. 2002-09-24 Havoc Pennington <hp@redhat.com> * src/main.c (main): support --version, #92796 patch from Christian Neumair * autogen.sh: change gettext test to be happy with glib-gettextize, #81425 * src/menu.c: change mnemonics to match bug #78999 * src/theme.c (meta_theme_validate): consolidate some nearly-identical themes for ease of translation, #70962 2002-09-24 Arvind Samptur <arvind.samptur@wipro.com> * src/menu.c: Replace strings Shade with Roll Up and Unshade with Unroll. 2002-09-23 Havoc Pennington <hp@pobox.com> * src/main.c (main): re-enable the log handler, maybe it will break something, I don't remember why I turned it off. * src/display.c: s/_NET_SHOW_DESKTOP/_NET_SHOWING_DESKTOP/ which is what's in the spec 2002-09-22 Havoc Pennington <hp@pobox.com> * src/window.c (recalc_window_features): small reordering of code * src/display.c (meta_spew_event): more spew for MapNotify, UnmapNotify * src/window.c (recalc_window_features): spew more stuff * src/display.c (meta_spew_event): spew override_redirect field of ConfigureNotify 2002-09-20 Arvind Samptur <arvind.samputr@wipro.com> * src/metacity.schemas.in: added keybindings for moving windows between workspaces. Patch from Jeyasudha. Fixes #91944. 2002-09-19 Arvind Samptur <arvind.samptur@wipro.com> * src/tools/metacity-properties.desktop.in : change in the tooltip suggested in ui-review. 2002-09-18 Havoc Pennington <hp@redhat.com> * src/window.c (update_net_wm_state): handle fullscreen state here. 2002-09-15 Havoc Pennington <hp@pobox.com> * src/session.c (save_state): escape the window title before saving in the session file, reported by Jos Vos 2002-09-12 Havoc Pennington <hp@redhat.com> * src/workspace.c (meta_workspace_screen_index) (meta_workspace_index): fix compiler warnings * src/tools/metacity-window-demo.c (menu_items): add a test for dialogs with no transient parent * src/place.c (find_first_fit): Try placing window at origin of first Xinerama, even if there are no windows to place next to; makes placement work when no other windows are open on the screen. 2002-09-09 Havoc Pennington <hp@pobox.com> * configure.in: 2.4.1 2002-09-09 Christian Neumair <chris@gnome-de.org> * src/keybindings.c: Make virtual desktops apply instantly and still show the pager popup by Benjamin Kahn <xkahn@zoned.net>, fixes #86590. 2002-09-06 Frederic Crozat <fred@crozat.net> * src/themes/Crux/metacity-theme-1.xml: Fix titlebar glitch on small dialogs. 2002-09-06 Arvind Samptur <arvind.samptur@wipro.com> * theme-format.txt : corrected some of the attributes which were not in sync with theme-parser.c Patch from Jim Bowen. #92057. 2002-09-05 Havoc Pennington <hp@pobox.com> * configure.in: put ro back in ALL_LINGUAS 2002-09-05 Havoc Pennington <hp@redhat.com> * configure.in (ALL_LINGUAS): remove 'ro' from ALL_LINGUAS, it contained invalid XML and broke the build. No <> in the translations of gconf keys! 2002-09-04 Marius Andreiana <mandreiana@yahoo.com> * configure.in: added 'ro' to ALL_LINGUAS 2002-09-03 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_get_tab_current): new function * src/keybindings.c (do_choose_window): apply modified patch from JeyaSudha to still display tab popup if only one window is on the desktop. 2002-06-25 JeyaSudha <jeyasudha.duraipandy@wipro.com> * src/session.c, src/window.c: Session saves the unmaximized postion, size of a maximized window. #86059 2002-09-03 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_update_prelit_control): don't filter out prelight for unmaximize button. #83860 (meta_frames_paint_to_drawable): handle unmaximize here as well 2002-08-27 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_frame_layout_calc_geometry): always apply rounding for shaded windows, fixes Bluecurve theme when shaded 2002-08-25 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_free): when freeing a fullscreen window, update layers of the window's group. 2002-08-25 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_open): _NET_SUPPORTING_WM_CHECK is supposed to have type WINDOW not CARDINAL. reported by Ben Jansens 2002-08-24 Havoc Pennington <hp@redhat.com> * src/window.c (process_property_notify): recalculate mapped-ness of frame after toggling decorations on/off, so that windows don't disappear when decorations are toggled on. * src/tools/metacity-window-demo.c (toggle_decorated_cb): add a test for toggling decoration state on the fly 2002-08-24 Havoc Pennington <hp@redhat.com> * src/window.c (update_sm_hints): hack around bug in kmail etc. where SM_CLIENT_ID was set on the window, not the client leader. * src/theme.c (meta_frame_layout_calc_geometry): don't round corners unless we have enough frame to chop off. 2002-08-24 Havoc Pennington <hp@redhat.com> * src/util.c: translate some strings that should have been, and convert to locale encoding before printing stuff. * src/stack.c (group_member_is_fullscreen): if window itself is fullscreen, return TRUE immediately. * src/window.c (meta_window_configure_request): add hack to fullscreenize large undecorated windows. 2002-08-21 Deepa Natarajan <deepa.natarajan@wipro.com> * src/keybindings.c, src/metacity.schemas.in, src/prefs.[ch]: add maximize and unmaximize keybinding setting. Partly fixes bug# 78999. 2002-08-20 Steve Fox <drfickle@k-lug.org> * metacity.spec.in: Add so that the spec file gets auto-updated whenever configure.in gets bumped. Include some missing directories. * Makefile.am * configure.in: Necessary changes for spec file magic 2002-08-20 Havoc Pennington <hp@redhat.com> * src/frames.c (get_control): if in the title rect check for y <= TOP_RESIZE_HEIGHT * src/display.c (meta_spew_event): put x/y coordinates in spew for enter/leave notify * src/frames.c (meta_frames_motion_notify_event): move cursor changing from here to update_prelit_control so it happens on enter notify as well (get_control): change test "y < TOP_RESIZE_HEIGHT" to "y <= TOP_RESIZE_HEIGHT" * src/Makefile.am (EXTRA_DIST): include .in files in EXTRA_DIST 2002-08-17 Simos Xenitellis <simos@hellug.gr> * configure.in (ALL_LINGUAS): Added Greek (el). 2002-08-17 Evandro Fernandes Giovanini <evandrofg@ig.com.br> * configure.in (ALL_LINGUAS): Added Brazilian Portuguese (pt_BR). 2002-08-15 Havoc Pennington <hp@redhat.com> * src/metacity.schemas.in: default to "Sans Bold 10" for the titlebar font. 2002-08-15 Havoc Pennington <hp@pobox.com> * src/window.c (recalc_window_features): leave has_fullscreen_func set to TRUE if the window is screen sized and undecorated, even if the window isn't resizable. idea from Christian - Manny Calavera - Neumair * src/keybindings.c (handle_toggle_fullscreen) (handle_toggle_maximize): these disabled fullscreen/maximize if the window wasn't resizable, should have used has_fullscreen_func has_maximize_func instead. 2002-08-15 Havoc Pennington <hp@pobox.com> * src/keybindings.c: implement raise/lower * src/metacity.schemas.in: add raise/lower * src/prefs.c: add "raise" and "lower" prefs to keybindings * src/display.c (meta_display_set_grab_op_cursor): assert that the screen arg is non-NULL in appropriate cases 2002-08-14 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> * src/display.c (meta_display_set_grab_op_cursor): In XGrabPointer, set the confine_to argument to the root window of the screen the window is on. * src/display.h: add screen argument. * src/window.c (meta_window_update_resize_grab_op): pass screen argument as NULL. 2002-08-14 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: use button positioning theme stuff. 2002-08-14 Mark McLoughlin <mark@skynet.ie> * src/screen.c: (set_number_of_spaces_hint), move from workspace.c. (update_num_workspaces): set the hint here. Fixes #90123. * src/workspace.c: (meta_workspace_new), (meta_workspace_free): don't set the hint here. (update_num_workspaces): move to screen.c 2002-08-12 Havoc Pennington <hp@redhat.com> * src/stack.c (compute_layer): window is in fullscreen layer if any member of its group is fullscreen * src/window.c (meta_window_unmake_fullscreen): update layer for whole window group (meta_window_make_fullscreen): ditto * src/util.c (meta_unsigned_long_hash): move hash/equal funcs for Window in here. * src/group.c: track window groups so we can do stuff with them. 2002-08-11 Havoc Pennington <hp@pobox.com> * src/menu.c: don't include nonexistent stock-icons.h file 2002-08-10 Havoc Pennington <hp@pobox.com> * src/metacity.schemas.in: default keybindings for move, resize, maximize, etc. from Deepa #78999 2002-08-10 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_maximize): unshade window if shaded, from JeyaSudha (meta_window_make_fullscreen): ditto 2002-08-10 Havoc Pennington <hp@pobox.com> * src/menu.c: reorder the menu items so that Close is at the bottom * src/theme-viewer.c (main): set debugging mode if METACITY_DEBUG enabled 2002-08-10 Havoc Pennington <hp@pobox.com> * src/xprops.c (meta_prop_get_motif_hints): allow Motif hints to be smaller than expected; GLUT for example seems to set a smaller struct. #89841 * src/window.c (update_mwm_hints): use g_free on motif hints as we don't use the XGetWindowProperty return directly anymore 2002-08-10 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_free): be sure window is mapped if we unmanage it and it's not withdrawn; bug #90369 * src/screen.c (meta_screen_new): change string s/override/replace/ bug #89077 * src/theme.c (scale_and_alpha_pixbuf): dump the sometimes-use-NEAREST-instead-of-BILINEAR optimization, bug #87489 2002-08-10 Havoc Pennington <hp@pobox.com> * src/window.c (menu_callback): raise window when moving to another workspace bug #88896 * src/keybindings.c (switch_to_workspace): raise window when moving between spaces 2002-08-10 Jorn Baayen <jorn@nl.linux.org> Register window menu icons with the Gtk stock system, instead of using the ones from the Metacity theme (which looked very bad with some themes). * src/Makefile.am: * src/main.c: * src/menu.c: * src/stock_delete.png: added these files * src/stock_minimize.png: * src/stock_maximize.png: * src/ui.c 2002-08-10 Havoc Pennington <hp@pobox.com> * src/keybindings.c (meta_display_process_key_event): filter out key events that happen on popup menus etc. * src/ui.c (meta_ui_window_is_widget): new function to check whether a window belongs to a GtkWidget such as the popup menu * src/prefs.c (change_notify): put in a no-op line for AIX compiler, #84252 2002-08-10 Havoc Pennington <hp@pobox.com> * src/window.c (update_resize): track time to avoid sending a deluge of move/resize requests, suggestion from xavier.bestel@free.fr bug #86830. Not really sure if this will make a difference or not. We'll see I guess. (update_move): do same on move though it seems less important here. * src/display.h (struct _MetaDisplay): store the last time we sent a move/resize event. 2002-08-10 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_notify_focus): add a FIXME comment with a link to bug #90382 2002-08-09 Havoc Pennington <hp@pobox.com> * src/keybindings.c (handle_toggle_maximize): disable maximize, fullscreen, shade via keybindings on windows that don't support it. 2002-08-08 Craig Black <blackc@speakeasy.net> Patch to provide extra cues when using the window menu move and resize items, #85724. * src/common.h: add new cursors * src/display.c: (grab_op_is_mouse) (meta_display_create_x_cursor), (xcursor_for_op), (meta_display_set_grab_op_cursor), (meta_display_begin_grab_op): The keyboard move and resize grab ops now also use the mouse. Allow the grab cursor to be changed during the grab op. Hold onto the initial grab position in case of reset. * src/display.h: save the initial grab position * src/keybindings.c: (process_keyboard_move_grab), (process_keyboard_resize_grab), (handle_begin_move), (handle_begin_resize): The keyboard move and resize grab ops now also use the mouse. * src/window.c: (meta_window_client_message), (menu_callback), (update_move), (update_resize), (meta_window_handle_mouse_grab_op_event), (warp_pointer), (meta_window_warp_pointer), (meta_window_begin_grab_op), (meta_window_update_resize_grab_op): When moving or resizing a window use the last grab position in computing change increment. Provide support for warping the mouse pointer. * src/window.h: new warp pointer and grab op helper functions 2002-08-08 Craig Black <blackc@speakeasy.net> * src/display.h: update comment * src/window.c: (meta_window_focus): also set expected focus window when setting input focus. 2002-08-07 Craig Black <blackc@speakeasy.net> * src/display.c: (meta_display_unshow_desktop): focus top window after showing desktop, fixes #88080. 2002-08-07 Craig Black <blackc@speakeasy.net> * src/core.c: (meta_core_show_window_menu): focus window on right click for menu, #87299. 2002-08-07 Craig Black <blackc@speakeasy.net> * src/display.c: (meta_display_open): clear expected focus window on open * src/display.h: add expected_focus_window field * src/window.c: (meta_window_make_fullscreen), (meta_window_unmake_fullscreen): change meta_window_update_layer() to meta_stack_update_layer() so build works again. (meta_window_free), (meta_window_make_fullscreen), (meta_window_focus), (meta_window_notify_focus): keep track of expected focus window after sending WM_TAKE_FOCUS event, previously if a UnmapNotify event arrived before the FocusIn event we would lose focus, fixes #84564. 2002-08-07 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_unmake_fullscreen): update layer (meta_window_make_fullscreen): update layer * src/stack.c (compute_layer): put window on fullscreen layer if fullscreen 2002-08-06 Craig Black <blackc@speakeasy.net> * src/window.c: (meta_window_client_message): implement _NET_WM_MOVERESIZE enhancements, see #90077. 2002-08-06 Havoc Pennington <hp@redhat.com> * configure.in: 2.4.0 (this version number has no special significance, just didn't want to go to 4-digit micro version ;-) 2002-07-28 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_shade): disable animation when shading windows, just doesn't really convey the idea anyway. * src/effects.c: Move to using a shaped window instead of IncludeInferiors to do the animations, looks a lot better because we don't have to grab the server. * src/window.c (meta_window_change_workspace): remove bogus assertion that was causing a crash (meta_window_new): auto-fullscreen huge undecorated windows. * src/keybindings.c (switch_to_workspace): use meta_window_change_workspace() to avoid same bug in cut-and-paste code from there 2002-08-06 He Qiangqiang <carton@linux.net.cn> * configure.in: Added "zh_CN" to ALL_LINGUAS. 2002-08-05 Ross Burton <ross@burtonini.com> * src/window.c: (meta_window_client_message): Set ->wm_state_skip_pager (ditto for _taskbar) instead of ->skip_pager so that these hints actually work. Fixes #89850. 2002-08-04 Havoc Pennington <hp@redhat.com> * src/frames.c (meta_frames_paint_to_drawable): init button states for the button backgrounds * src/themes/Atlanta/metacity-theme-1.xml: adapt to work correctly with button repositioning 2002-08-04 Havoc Pennington <hp@redhat.com> * src/frames.c (meta_frames_button_press_event): raise/focus on click, even if the click was on the client area (this makes Alt+button1 raise windows again, yay) * src/stack.c (compute_layer): put panels in the DOCK layer always (keep them on top of other windows). Still sloppy-focus raised with respect to other docks. * configure.in: remove -Wshadow for now as GTK headers make all kinds of noise with it. 2002-08-02 Mark McLoughlin <mark@skynet.ie> * src/screen.c: (meta_screen_new): set active_workspace to NULL. Also actually activate the first workspace instead of just setting active_workspace. Fixes #87367. (meta_screen_ensure_workspace_popup): don't re-use our iterator for setting the entries list, stop iterating when we've gone beyond the last workspace (there may be empty spaces in the last row). * src/workspace.c: (meta_workspace_activate): if no workspace was previously activated, return. 2002-08-04 Havoc Pennington <hp@redhat.com> * src/theme.c (free_menu_ops): use MetaMenuIconType not button type for the size of the menu ops array (meta_theme_define_int_constant): return TRUE on success (how the heck did this ever work?) (meta_theme_define_float_constant): return TRUE on success (meta_frame_style_validate): allow the "positional" buttons to be omitted for now. * src/testgradient.c (render_multi): don't define N_COLORS twice * src/theme-viewer.c (run_theme_benchmark): don't define ITERATIONS twice * src/theme.c (button_rect): handle new button types (meta_button_type_to_string): update (meta_button_type_from_string): update * src/theme.h (enum): add button types for the 6 possible button positions. No way to reposition buttons still but this will allow themes to go ahead and support doing so. 2002-08-03 Craig Black <blackc@speakeasy.net> * src/keybindings.c: (meta_display_process_key_event), (process_tab_grab), (do_choose_window): change alt+tab to a windowless grab, fixes #83499 2002-08-03 Craig Black <blackc@speakeasy.net> * src/display.c: (event_callback): Have ButtonPress and UnmapNotify events account for a null grab window, fixes #87896 2002-08-03 Gaute Lindkvist <lindkvis@linpro.no> Corrected some issues with the Bright theme. Mainly making sure the text does not clip, as well as increasing the size of the menu icon. 2002-08-01 Mark McLoughlin <mark@skynet.ie> Implements support for _NET_WM_ALLOWED_ACTIONS. Fixes #84282. * src/display.[ch]: (meta_display_open): add _NET_WM_ALLOWED_ACTIONS atoms. * src/screen.c: (set_supported_hint): set them as being supported. * src/window.c: (set_allowed_actions_hint): impl setting _NET_WM_ALLOWED_ACTIONS. (recalc_window_features): use it here, but only if things have changed. 2002-08-01 Christophe Fergeau <teuf@users.sourceforge.net> * src/metacity-dialog.c: focus the "Close" button by default on the dialog which appears at exit when some apps can't be session managed 2002-08-01 Mark McLoughlin <mark@skynet.ie> * src/session.c: (save_yourself_possibly_done): send a SaveYourselfDone if we're skipping this global save. (save_yourself_callback): don't not save session state if the save style is Global. Fixes #89390. * theme-format.txt: update. 2002-07-30 Pablo Saratxaga <pablo@mandrakesoft.com> * configure.in: Added Vietnamese (vi) to ALL_LINGUAS 2002-07-24 Havoc Pennington <hp@pobox.com> * src/themes/Makefile.am (THEMES): add Metabox theme from Garrett * README: updates 2002-07-21 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): don't automaximize fullscreen windows. 2002-07-14 Havoc Pennington <hp@pobox.com> * src/window.c (recalc_window_features): don't allow shading of border-only windows. 2002-07-24 Havoc Pennington <hp@redhat.com> * src/theme-parser.c (meta_theme_load): look for themes in ~/.themes/NAME/metacity-1/ and datadir/themes/NAME/metacity-1 instead of the old locations. * src/themes/Makefile.am: install themes to datadir/themes/NAME/metacity-1/ to match how GTK works, breaking third-party themes yet again! woot! 2002-07-20 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_open): grab display across managing each screen; XGetInputFocus() on startup. 2002-07-19 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_configure_request): disable configure requests during a user move/resize operation, mostly a workaround for stoopid apps. 2002-07-24 jacob berkman <jacob@ximian.com> * configure.in: fix x11 header checks when x11 is not in the default include path 2002-07-23 Ross Burton <ross@burtonini.com> * src/menu.c (meta_window_menu_new): Use the real workspace names instead of making up numbers. 2002-07-23 Havoc Pennington <hp@redhat.com> * src/themes/Makefile.am (THEMES): put Gorilla back in the build * src/themes/Gorilla/metacity-theme-1.xml, src/themes/Crux/metacity-theme-1.xml: fixes from Sebastien Delestaing so that these themes work properly with different font sizes. * src/frames.c (get_control): patch from Balamurali Viswanathan for #81984 (resize titlebar from the top not the bottom) 2002-07-23 Havoc Pennington <hp@redhat.com> * src/keybindings.c (meta_display_process_key_event): handle NULL screen from screen_for_xwindow * src/display.c (meta_display_screen_for_xwindow): put an error trap around the XGetWindowAttributes(), should fix the popular "closing a window results in a crash" bug. * src/util.c (print_backtrace): support optional backtrace feature using gnu libc backtrace() call 2002-07-15 jacob berkman <jacob@ximian.com> * src/update-from-egg.sh: steal from profterm to fix build 2002-07-13 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_new): don't put a newline after the default workspace name 2002-07-13 Havoc Pennington <hp@pobox.com> * src/keybindings.c: adapt to virtual modifiers (meta_display_process_mapping_event): we need to reload the binding tables now when the modmap changes. * src/prefs.c (update_binding): parse virtual modifiers, not plain modmask * src/common.h (MetaVirtualModifer): new enum * src/ui.c (meta_ui_parse_accelerator): use egg_accelerator_parse_virtual() * src/Makefile.am: add eggaccelerators.[hc] for the virtual accelerator parsing function 2002-07-13 Christophe Fergeau <teuf@users.sourceforge.net> * configure.in: added fr to ALL_LINGUAS 2002-07-12 Havoc Pennington <hp@pobox.com> * src/session.c (warn_about_lame_clients_and_finish_interact): don't display the dialog if all the apps were session managed. 2002-07-12 Havoc Pennington <hp@pobox.com> * src/session.c: don't send SmInteractDone until the warning dialog about crappy clients has been closed. 2002-07-12 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_new): try to maximize windows that are too big for the work area * src/place.c (find_next_cascade): don't let the cascade algorithm place windows off the screen, and fix it to always exhaustively search the window list for cascade parents. 2002-07-11 Havoc Pennington <hp@pobox.com> * src/metacity-dialog.c (main): option to display error when a command fails to run. * src/keybindings.c (handle_run_command): run commands in response to keybindings. * src/prefs.c: add command keybinding stuff * src/metacity.schemas.in: add keybindings for running commands, and keys to store the commands themselves. 2002-07-10 Havoc Pennington <hp@redhat.com> * src/display.c: properly attribute selection code to Matthias Clasen 2002-07-10 Havoc Pennington <hp@pobox.com> * README: couple of updates * src/main.c (usage): add --replace to usage, reported by Matthias Clasen 2002-07-09 Havoc Pennington <hp@pobox.com> * src/metacity.schemas.in: fix short description for begin_resize, patch from Jayaraj, #87654 * src/keybindings.c (handle_begin_resize): apply patch from Jayaraj to actually handle the begin resize keybinding. 2002-07-09 Havoc Pennington <hp@pobox.com> * src/window.c (constrain_position): don't center vertically for maximized windows that don't fill the screen, just leave them at the top. 2002-07-06 Havoc Pennington <hp@pobox.com> * src/tabpopup.c (selectable_workspace_new): increase the size of the mini workspaces 2002-07-06 Havoc Pennington <hp@pobox.com> Apply blackc@speakeasy.net patch, bug #83940, to do mini-workspaces similar to the pager, when switching spaces. * src/window.c (update_net_wm_state): actually fill in wm_state_skip_taskbar, wm_state_skip_pager flags * src/tabpopup.c: support drawing a mini-workspace similar to the one the pager draws. * src/stack.c (meta_stack_list_windows): new function to list the windows in stacking order * src/screen.c (meta_screen_ensure_workspace_popup): don't pass in the ugly default app icon for workspaces * src/display.c (event_callback): fix from blackc@speakeasy.net to avoid dereferencing a NULL grab window. 2002-07-06 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_open): put _NET_DESKTOP_NAMES in the array of atom names, so desktop names might work and we don't read uninitialized memory. * src/main.c (main): add VERSION/timestamp verbose message. * src/keybindings.c: implement cycle_windows cycle_panels * src/metacity.schemas.in: add the cycle_windows cycle_panels keybindings * src/prefs.h (META_KEYBINDING_FOCUS_PREVIOUS): replace FOCUS_PREVIOUS key binding with CYCLE_WINDOWS and CYCLE_PANELS (not good names really, but I don't have ideas). * src/common.h: add a grab op for alt+esc window cycling 2002-07-05 Havoc Pennington <hp@pobox.com> * src/themes/Makefile.am (THEMES): Take Gorilla out until it gets repaired. 2002-07-05 Havoc Pennington <hp@pobox.com> * src/window.c (update_wm_hints): Change default value of input hint (if not specified) to true instead of false. This is what some clients assume, such as Visual SlickEdit. 2002-07-02 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_show_menu): use new macros to get whether we allow move/resize correct * src/frame.c (meta_frame_get_flags): use new macros to get whether we can move/resize correct, considering maximized/fullscreen for the move case. * src/window.h (META_WINDOW_ALLOWS_RESIZE, META_WINDOW_ALLOWS_MOVE): new macros * src/keybindings.c (process_keyboard_resize_grab): finish the right/left resize, patch from Jayaraj #78179. Has the same old move/resize bug, if it hits a constraint it starts to break because we move without resizing. 2002-07-02 Mark McLoughlin <mark@skynet.ie> * src/keybindings.c: (grab_keyboard), (ungrab_keyboard): rename from {un}grab_all_keys_and_keyboard and only do an XKeyboardGrab, the XKeyGrab isn't neccessary. (meta_screen_grab_all_keys), (meta_screen_ungrab_all_keys), (meta_window_grab_all_keys), (meta_window_ungrab_all_keys): update for above change. (handle_workspace_switch): don't use a MetaWindow when workspace switching, use the root window instead. 2002-07-01 Mark McLoughlin <mark@skynet.ie> Fix broken workspace switching from my previous commit. * src/display.c: (meta_display_begin_grab_op): don't leak a pointer grab if we fail to grab the keyboard. * src/keybindings.c: (meta_screen_grab_keys): check screen->all_keys_grabbed. (meta_screen_grab_all_keys): regrab our standard bindings if we fail. (handle_workspace_switch): revert to our previous behaviour of using the last focused window to do the grab upon. Only use the RootWindow if there isn't anything else to use. * src/screen.c: (meta_screen_new): initialise all_keys_grabbed. 2002-06-26 Mark McLoughlin <mark@skynet.ie> Fixes not being able to tab out of a workspace which contains no windows. * src/core.c: (meta_core_begin_grab_op): upd for meta_display_begin_grab_op change. (meta_core_get_grab_frame): allow for grab_window == NULL. * src/display.[ch]: (meta_display_screen_for_xwindow): implement. (meta_display_begin_grab_op): grab on the root window if window == NULL. (meta_display_end_grab_op): use grab_screen instead of grab_window. * src/keybindings.c: (grab_all_keys_and_keyboard): split out from meta_window_grab_all_keys. (ungrab_all_keys_and_keyboard): split out from meta_window_ungrab_all_keys. (meta_screen_grab_all_keys), (meta_screen_ungrab_all_keys): implement grabbing and ungrabbing on the root window. (meta_display_process_key_event): if window == NULL, check the event is from the same screen and process. Only happens with workspace switching. (process_workspace_switch_grab): kill window param and don't use grab_window. (handle_tab_forward), (handle_begin_move): upd for meta_display_begin_grab_op change. (handle_workspace_switch): remove brokeness. Always do the grab op on the root window. * src/keybindings.h: add meta_screen_{un}grab_all_keys. * src/window.c: (meta_window_client_message), (menu_callback): update for meta_display_begin_grab_op change. 2002-06-25 Mark McLoughlin <mark@skynet.ie> * src/fixedtip.c: (meta_fixed_tip_show): * src/frames.c: (meta_frames_new): * src/tabpopup.c: (meta_ui_tab_popup_new): s/gdk_get_default_display/gdk_display_get_default/ s/gdk_get_default_screen/gdk_screen_get_default/ 2002-06-25 Mark McLoughlin <mark@skynet.ie> * src/themes/Crux/active-border-top-left-border.png: * src/themes/Crux/active-border-top-right-border.png: * src/themes/Crux/active-top-left-corner.png: * src/themes/Crux/active-top-mid-left-border.png: * src/themes/Crux/active-top-mid-right-border.png: * src/themes/Crux/active-top-right-corner.png: * src/themes/Crux/inactive-border-top-left-border.png: * src/themes/Crux/inactive-border-top-right-border.png: * src/themes/Crux/inactive-top-left-corner.png: * src/themes/Crux/inactive-top-mid-border.png: * src/themes/Crux/inactive-top-right-corner.png: * src/themes/Crux/metacity-theme-1.xml: added support for border only windows. 2002-06-24 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Added some stuff to the window buttons, so they use the ACTIVE bg/fg. 2002-06-25 Mark McLoughlin <mark@skynet.ie> * src/display.[ch]: (meta_display_open): src/screen.c: (set_supported_hint), (set_work_area_hint): Its _NET_WORKAREA, not _NET_WM_WORKAREA silly :-) 2002-06-25 Mark McLoughlin <mark@skynet.ie> * src/screen.[ch]: (update_num_workspaces), recalc workarea hint when new workspaces created. Fixes bug that workarea not calculated until first non-dock window is mapped. (set_work_area_hint), (set_work_area_idle_func), (meta_screen_queue_workarea_recalc): move all this stuff from workspace.c. * src/workspace.c: (meta_workspace_invalidate_work_area): use meta_screen_queue_workarea_recalc. 2002-06-23 Gediminas Paulauskas <menesis@delfi.lt> * src/themes/Bright/metacity-theme-1.xml: Update with border-only window stuff from Atlanta. 2002-06-22 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Update for "border" frame stuff, minor button/spacing improvements. 2002-06-22 Havoc Pennington <hp@pobox.com> Partially fix Jacob's SM bugs. * src/window.c (meta_window_apply_session_info): restore the extra stuff we're saving, except stack position I didn't figure out yet. * src/session.c: save stack position, minimized, maximized, in the session file. 2002-06-22 Havoc Pennington <hp@pobox.com> * src/workspace.c (set_number_of_spaces_hint): do nothing if screen is being unmanaged, we don't want to blow away state, we want to remember it for the next window manager. 2002-06-22 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_screen_ensure_workspace_popup): rename from meta_workspace_ensure_tab_popup, and use workspace->name instead of a hardcoded name 2002-06-22 Havoc Pennington <hp@pobox.com> * src/xprops.c (meta_prop_get_utf8_list): new utility function * src/display.c (meta_display_open): _NET_DESKTOP_NAMES atom (event_callback): update workspace names when the property changes * src/screen.c (set_supported_hint): "support" _NET_DESKTOP_NAMES (nothing to do really) 2002-06-21 Havoc Pennington <hp@pobox.com> Theme breakage! Themes have to implement "border" frames now, see Atlanta for an example. Fixes #84285 * src/tools/metacity-window-demo.c (do_appwindow): add a border-only window * src/window.c (update_mwm_hints): read border only from the MWM hints * src/window.h (struct _MetaWindow): add border_only flag * src/core.c (meta_core_get_frame_type): report border type if required * src/common.h (enum): add META_FRAME_TYPE_BORDER 2002-06-20 Mark McLoughlin <mark@skynet.ie> * src/window.c: (meta_window_visible_on_workspace): sticky windows aren't visibile on all screens. Check the workspace is on the same screen as the window. * src/workspace.c: (meta_workspace_list_windows): use meta_window_visible_on_workspace here. 2002-06-19 Havoc Pennington <hp@pobox.com> * src/display.c (meta_resize_gravity_from_grab_op): handle UNKNOWN keyboard resizing state * src/keybindings.c (process_keyboard_resize_grab): implement keyboard resize key handling somewhat (only vertical resize works, left/right arrow not implemented, and visual feedback of the edge we're resizing isn't implemented) * src/window.c (menu_callback): start keyboard resize grab when it's chosen from the menu 2002-06-17 Havoc Pennington <hp@pobox.com> * src/stack.c (meta_stack_get_default_focus_window): don't use a minimized window as the next focus window, patch from blackc@speakeasy.net 2002-06-17 Havoc Pennington <hp@pobox.com> * src/place.c (find_next_cascade): increase the cascade threshold a bit. (find_first_fit): implement a somewhat lame first fit algorithm 2002-06-17 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_change_workspace): fix from Gaute Lindkvist #82977 for unsticking windows 2002-06-17 Frederic Crozat <fcrozat@mandrakesoft.com> * src/metacity.schemas.in: associate close_window keybinding to Alt-F4 2002-06-16 Havoc Pennington <hp@pobox.com> * src/main.c (main): fix spelling error, #85452 2002-06-15 Havoc Pennington <hp@pobox.com> * src/keybindings.c (meta_display_process_key_event): don't pass a null string to printf * src/display.c (key_event_description): don't pass a null string to printf * src/keybindings.c (meta_set_keybindings_disabled): allow enable/disable keybindings regardless of debug mode. 2002-06-15 Havoc Pennington <hp@pobox.com> * src/draw-workspace.h, src/draw-workspace.c: workspace-drawing code factored out of libwnck, needs wiring up to tabpopup.c (which is kind of annoying since you have to get the list of workspaces and MetaWindow across the barrier between the GDK-aware and non-GDK-aware sides of metacity) 2002-06-14 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_show): always focus new windows, trying to be smart about it was a flop. 2002-06-14 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> * src/delete.c (io_from_ping_dialog): Check for NULL string before calling strlen(). Fixes the core dump issue reported in #84873. 2002-06-13 Anders Carlsson <andersca@gnu.org> * src/theme.c (meta_frame_layout_calc_geometry): Set client height as 0 when the window actually is shaded, not the other way around. 2002-06-12 Havoc Pennington <hp@redhat.com> * src/theme.c (meta_frame_layout_calc_geometry): when a window is shaded, don't include client height in the height calculation. * src/workspace.c (meta_workspace_get_neighbor): apply fix from Mads Villadsen for the Up arrow key, #84582 2002-06-12 Havoc Pennington <hp@redhat.com> * src/theme.c (meta_frame_style_draw): Draw the buttons right before the "overlay" piece. 2002-06-12 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> * src/tools/metacity-properties.glade: accessibility work for metacity-properties capplet. Set appropriate atk relations. Fixes bug #84749 2002-06-11 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_show): allow dialogs to steal focus from panels/desktop 2002-06-10 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> * src/fixedtip.c: include <config.h> - fix for #83960 2002-06-10 Erwann Chenede - <erwann.chenede@sun.com> * src/keybindings.c : (handle_close_window, handle_minimize_window) verify the active window has the appropriate close/minimize function before closing or minimizing the window. 2002-06-09 Havoc Pennington <hp@pobox.com> * configure.in: 2.3.987 2002-06-09 Havoc Pennington <hp@pobox.com> * src/delete.c (delete_ping_timeout_func): add G_IO_NVAL to watch condition, patch from Gustavo Giraldez, avoids another 100% CPU thingy 2002-06-09 Havoc Pennington <hp@pobox.com> * src/place.c (meta_window_place): don't run constrain_placement on windows we allow to go anywhere (docks, etc.). Fixes positioning of panel windows in certain cases. 2002-06-09 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_button_press_event): don't raise/focus the window if minimize/close are clicked, patch from Gaute Lindkvist #75460 2002-06-08 Havoc Pennington <hp@pobox.com> Cleanups to workspace popup patch. Space before all parens in a couple places. * src/prefs.c (meta_prefs_get_keybinding_action): fix brace indentation, and use while instead of for loop. Take a "mask" argument to avoid ambiguity issues. * src/keybindings.c (handle_workspace_switch): rename from handle_workspace_forward since there's no directionality here (handle_workspace_switch): add a FIXME about how screwed it is that we need a window in order to do our grab. Should be able to grab on a dummy window like no_focus_window or the root window. (process_workspace_switch_grab): rename from tab_grab for clarity, no tab involved here. * src/common.h (enum): have only one grab op for all workspace switching directions, instead of one for each. 2002-06-08 Havoc Pennington <hp@pobox.com> Apply big patch from blackc@speakeasy.net adding a popup window to the Ctrl+Alt+arrows shortcuts. #83940 2002-06-08 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_new): select key press/release on the display->no_focus_window, another attempted fix for not getting keybindings when no window is focused. Still doesn't seem to work though. I don't get what's going wrong. (meta_create_offscreen_window): new function, used instead of XCreateSimpleWindow so we get override redirect offscreen windows. 2002-06-08 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_open): set net_supporting_wm_check in addition to win_supporting_wm_check, patch from JeyaSudha for #83365 * src/screen.c (set_wm_check_hint): remove setting win_supporting_wm_check on leader window here, done already in display.c 2002-06-08 Havoc Pennington <hp@pobox.com> * src/keybindings.c (meta_window_ungrab_keys): set keys_grabbed to FALSE, patch from Jayaraj for #81857 2002-06-08 Havoc Pennington <hp@pobox.com> * src/xprops.c (meta_prop_get_utf8_string): don't die on bad atom name * src/display.c (meta_display_close): don't unmanage windows here, do it in screen_free and then closing the display unmanages windows as a side effect of unmanaging the screen (meta_display_unmanage_screen): new function (process_selection_clear, process_selection_request): handle selection stuff (meta_spew_event): don't crash on client message containing invalid atom (meta_spew_event): don't crash on property notify with invalid atom * src/main.c (main): add --replace option to replace existing window manager. * src/screen.c: implement holding manager selection. * src/display.c (meta_display_open): add new selection-related atoms. 2002-06-08 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_new): select keypress/keyrelease events on root window, this may fix the bug where keybindings didn't work if you didn't have a focused window. 2002-06-08 Havoc Pennington <hp@pobox.com> * src/main.c (main): call meta_session_shutdown when exiting cleanly * src/session.c (meta_session_shutdown): function to change use to RestartIfRunning (meta_session_init): change normal restart hint to RestartImmediately 2002-06-08 Havoc Pennington <hp@pobox.com> Yeah I know maximization is broken, I'm too tired to fix it. Probably because of the change to update_struts() that was supposed to fix the 100% CPU bug. * src/place.c (meta_window_place): don't run docks and things through the placement algorithm. Thought it might fix metacity-window-demo but it didn't. * src/window.c (constrain_size): only get work area when needed (meta_window_new): init the do_not_cover field 2002-06-08 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_get_xinerama_for_window): short-circuit the "only one xinerama" case, and use outer rect of window instead of window->rect, so we get root window coords. * src/theme.c (meta_frame_layout_get_borders): if fullscreen all frame edges are zero-width. * src/frame.c (meta_frame_get_flags): init fullscreen flag. * src/common.h (enum): add META_FRAME_FULLSCREEN frame flag * src/place.c: fix up calls to meta_window_get_work_area * src/window.c (meta_window_get_work_area): add an arg for whether the work area is for the screen or the xinerama subscreen. (constrain_position): fix up calls to meta_window_get_work_area (constrain_size): ditto * src/screen.c (meta_screen_new): add METACITY_DEBUG_XINERAMA environment variable which simulates xinerama on a single head. 2002-06-08 Havoc Pennington <hp@pobox.com> * src/window.c (update_struts): only invalidate things if the struts actually change, since the panel likes to set them over and over. May fix the infinite loop that caused 100% CPU usage. 2002-06-07 Havoc Pennington <hp@redhat.com> * src/screen.c (meta_screen_new): use XineramaIsActive() not XineramaQueryExtension() 2002-06-07 Havoc Pennington <hp@redhat.com> * src/screen.c (meta_screen_get_current_xinerama): don't return null on non-multihead 2002-06-06 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_get_current_xinerama): implement * src/place.c (meta_window_place): cascade windows on the active Xinerama screen * src/window.c (meta_window_move_resize_internal): strip out the #if 0 cruft about guessing fullscreen mode (constrain_position, constrain_size): fullscreen/maximize to the Xinerama head, not the whole screen (meta_window_get_work_area): autocreate struts at the Xinerama physical screen edges for the screen the window is on. * src/screen.c (meta_screen_get_xinerama_for_window): someone snuck in a for loop, fix it. ;-) 2002-06-06 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Increase the border size of the buttons so they aren't quite so huge on my box. Also get a *little* closer to finally fixing the horizontal line behind the icon. It now works decently with common font sizes (in pixels). 2002-06-05 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_color_spec_new_from_string): parse "shade/foo/factor" as a color (colorize_pixbuf): remove the unused hsv_to_rgb and vice-versa stuff, add the gtk_style_shade stuff. (meta_color_spec_render): render the shaded color spec * src/theme.h (struct _MetaColorSpec): add "shade" mode to MetaColorSpec. 2002-06-04 Seth Nickell <snickell@stanford.edu> * src/metacity.desktop.in: Add X-GnomeWMSettingsLibrary to desktop file to support new Window capplet. 2002-06-04 Havoc Pennington <hp@redhat.com> * src/window.c (update_wm_hints): fix for how we read the input hint, from Hidetoshi Tajima (meta_window_show): from Hidetoshi, don't autofocus windows with input = FALSE wm_take_focus = FALSE when they first appear. We do allow these windows to be focused (so keynav works), but they don't get focused automatically. Now how do we keep them out of the task list? 2002-06-04 Gustavo GirÃ�¡ldez <gustavo.giraldez@gmx.net> * src/theme.c (draw_op_as_pixbuf): Use icon's instead of image's fill_type when type is META_DRAW_ICON. 2002-06-03 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): don't automatically fullscreen things opened fullscreen, because there's no GUI to un-fullscreen them. 2002-06-03 Havoc Pennington <hp@pobox.com> * src/theme-parser.c (parse_aspect_ratio): fix error message about bad aspect ratio name. 2002-06-03 Havoc Pennington <hp@pobox.com> * src/themes/Esco/metacity-theme-1.xml: test button aspect ratio instead of hardcoded button size, James feel free to revert if you don't like it this way. * src/theme-parser.c: parse the aspect_ratio element for button aspect ratios. * src/theme.h (struct _MetaFrameLayout): allow button sizes to be given as an aspect ratio derived from the titlebar height, instead of as a fixed size. * src/theme.c (meta_frame_layout_validate): validate new button sizing parameters * src/theme.c (meta_frame_layout_calc_geometry): use new button layout params Mon Jun 3 15:12:11 2002 HideToshi Tajima <hidetoshi.tajima@sun.com> * configure.in (METACITY_LIBS): put -lXext into SHAPE_LIBS 2002-06-03 Kjartan Maraas <kmaraas@gnome.org> * src/tools/metacity-properties.desktop.in: Someone forgot to mark the two strings in here for translation :) 2002-06-02 Havoc Pennington <hp@pobox.com> * configure.in: 2.3.610 2002-06-01 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_finalize): move the remove_listener to finalize instead of destroy, thanks to Jayaraj for tracking down the bug. 2002-06-01 Havoc Pennington <hp@pobox.com> * src/session.c: add some missing \n (meta_session_init): remove the #if 0 interact callback from our initial SmcOpenConnection call, this arg to SmcOpenConnection doesn't exist. 2002-06-01 Havoc Pennington <hp@pobox.com> * src/session.c: put in more debug spew about the session 2002-05-30 Havoc Pennington <hp@pobox.com> * src/Makefile.am (INCLUDES): use $(prefix)/@DATADIRNAME@/locale for localedir to work with Solaris native gettext, patch from Hidetoshi Tajima * src/tools/Makefile.am: ditto 2002-05-31 Havoc Pennington <hp@redhat.com> * src/theme.c: add MetaImageFillType and implement TILE in addition to the existing SCALE * src/theme.h (struct _MetaDrawOp): remove no-longer-used "alpha" field 2002-05-31 Havoc Pennington <hp@redhat.com> * src/theme.c (multiply_alpha): now just uses meta_gradient_add_alpha (draw_op_as_pixbuf): implement alpha gradients for tint, gradient, and image draw ops, so I can implement garrett's stuff. * src/gradient.c (meta_gradient_add_alpha): new function to multiply the alpha channel of a pixbuf by an alpha gradient 2002-05-30 Havoc Pennington <hp@redhat.com> * src/main.c (main): verbose-log on startup whether we were compiled with various extensions * src/display.c (meta_display_queue_retheme_all_windows): reapply shape mask when changing themes, sucks to do it here though, makes theme changing slower. Needs fixing. * src/theme-parser.c (parse_toplevel_element): parse rounded corner options to frame_geometry * src/frames.c (meta_frames_apply_shapes): apply rounded corners if requested by the theme * configure.in (HAVE_SHAPE): check for shape extension 2002-05-30 Stephen Browne <stephen.browne@sun.com> * src/tools/metacity-properties.c: Some day I'll make all my changes in one commit :) Needed to rip out code for adding icon to the dialog since it was removed from teh galde file in my previous change. 2002-05-30 Stephen Browne <stephen.browne@sun.com> * src/tools/metacity-properties.glade: Some UI changes demanded by Pat and Calum. Make Close default response Change mnemonic for Click so as not to clash with Close 2002-05-30 Stephen Browne <stephen.browne@sun.com> * src/tools/metacity-properties.glade: changed window title to match other control center dialogs 2002-05-29 Havoc Pennington <hp@pobox.com> * src/session.c (meta_session_init): improve error about failing to open session manager. (shutdown_cancelled_callback): send SmcSaveYourselfDone when we get cancelled (interact_callback): implement an interact callback that complains about lame clients that can't be saved. Still somewhat buggy in that it sends InteractDone before the user has closed the dialog. 2002-05-29 Havoc Pennington <hp@redhat.com> * src/tools/metacity-mag.c: add a magnifier I'm using when making themes. Not installed. * src/tools/metacity-properties.c: reindentation, show window, add copyright info. * src/tools/metacity-properties.glade: make main window !visible on startup, to avoid funkiness. 2002-05-29 Jacob Berkman <jacob@ximian.com> * src/tools/Makefile.am (EXTRA_DIST): dist .desktop.in files 2002-05-29 Stephen Browne <stephen.browne@sun.com> New simple metacity-properties dialog to configure focus mode and auto raise. * configure.in: added build support for metacity-properties * src/tools/Makefile: more build stuff * src/tools/metacity-properties.c: added these files * src/tools/metacity-properties.glade: * src/tools/metacity-properties.desktop.in: * src/tools/metacity-properties.png: 2002-05-29 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_move_resize_internal): add code to also guess that client wants to come out of fullscreen, then #if 0 the whole deal, I'm not sure it's such a good idea. 2002-05-29 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_move_resize_internal): guess if a window meant to be fullscreen, and if so put it in that state. 2002-05-28 Havoc Pennington <hp@pobox.com> * src/window.c (redraw_icon): handle missing frame, prevents segv with undecorated windows. #83298 2002-05-28 Havoc Pennington <hp@pobox.com> Patch from Erwann Chenede for raise_or_lower keybinding * src/display.c, src/common.h: META_POINT_IN_RECT moved to a common location, removed from here (meta_rectangle_intersect): move here and make it public * src/prefs.c: add raise_or_lower keybinding * src/stack.c (meta_stack_get_below, meta_stack_get_above): add an arg to only get windows within the same layer * src/keybindings.c (handle_raise_or_lower): add handling for a "raise window if obscured, else lower" keybinding 2002-05-28 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_configure_request): handle CWStackMode in configure requests (meta_window_new): if a window is opened at 0,0 and screen size, put it in the fullscreen state. (meta_window_new): remove old code that set the window position to 0,0 if PPosition/USPosition unset, that will be handled by whether we place the window or not. 2002-05-28 Abel Cheung <maddog@linux.org.hk> * configure.in: Added "zh_TW" to ALL_LINGUAS. 2002-05-27 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): search for the window's screen by root window instead of Screen*, maybe it will help with bug #82664 2002-05-27 Kjartan Maraas <kmaraas@gnome.org> * autogen.sh: Hook up intltoolize here. * configure.in: Initialize intltool. * src/metacity.schemas.in: Add this. * src/metacity.desktop.in: Add this too * src/Makefile.am: Hook up intltool support for .schemas and .desktop. * Makefile.am: Dist the intltool files. 2002-05-27 Anders Carlsson <andersca@gnu.org> * src/themes/Gorilla/metacity-theme-1.xml: Apparently someone thinks my name is Anders Carlsom. Well, it's not. (Thanks to Carl-Johan Kjellander for noticing.) 2002-05-26 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Remove borders from Esco theme as well (didn't know you could), apparently fixed the problem where the spacing between the icon & the title got larger as the fontsize went up. 2002-05-26 Havoc Pennington <hp@pobox.com> * src/themes/Atlanta/metacity-theme-1.xml: totally drop the borders off of maximized windows. 2002-05-26 Havoc Pennington <hp@pobox.com> Patch from Gaute Lindkvist so you can't move the panel or desktop to only one workspace. * src/keybindings.c (handle_move_to_workspace): don't allow moving window to another space if the window is always_sticky * src/window.c (recalc_window_features): set the always_sticky field for desktop/dock windows. (meta_window_show_menu): disable unsticking always sticky windows via the menus * src/menu.c (meta_window_menu_new): disable workspace items if requested 2002-05-26 Matthias Warkus <mawarkus@gnome.org> * po/de.po: Added. * configure.in: de added to ALL_LINGUAS 2002-05-25 Erwann Chenede - <erwann.chenede@sun.com> * src/keybindings.c (rebuild_screen_binding_table, rebuild_window_binding_table, meta_change_keygrab): allow key grabbing for unmodified keys (e.g F1, etc) fix #82630 2002-05-25 Anders Carlsson <andersca@gnu.org> * src/place.c: (get_vertical_edges), (get_horizontal_edges): Take Xinerama screen edges into consideration. * src/screen.c: (meta_rectangle_intersect), (meta_screen_get_xinerama_for_window): * src/screen.h: Add a new function that returns the xinerama monitor that a window is on. 2002-05-24 Havoc Pennington <hp@pobox.com> * src/window.c (menu_callback): follow windows to their new workspace * src/keybindings.c (handle_move_to_workspace): follow windows to their new workspace 2002-05-24 Havoc Pennington <hp@pobox.com> * src/metacity.schemas: add minimize window binding * src/keybindings.c (handle_minimize_window): add minimize keybinding 2002-05-24 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_show): change how focusing windows on initial map works, so that we only steal focus from our transient parent or from a panel/desktop, never from other normal windows. 2002-05-24 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_configure_request): modify to ignore PPosition and USPosition once the window has been placed 2002-05-24 Anders Carlsson <andersca@gnu.org> * src/window.c: Redraw the window frame when the icon changes. Fixes #78543, reported by Kang Jeong-Hee. 2002-05-23 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): also filter out LeaveNotify with NotifyInferior 2002-05-23 Jayaraj Rajappan <jayaraj.rajappan@wipro.com> * src/display.c (event_callback): fix for bugzilla bug #72314, filter out LeaveNotify caused by grabs when in mouse focus mode. 2002-05-23 Havoc Pennington <hp@pobox.com> * src/metacity.schemas: clean up the font preference * src/prefs.c: font pref * src/frames.c: pay attention to the font pref 2002-05-23 Havoc Pennington <hp@pobox.com> Crack from Erwann * src/metacity.schemas: add autoraise crackrock * src/display.c (event_callback): autoraise window if autoraise is enabled * src/prefs.c: autoraise crack 2002-05-21 Havoc Pennington <hp@redhat.com> * src/window.c (constrain_position): fix positioning in fullscreen mode, patch from Gustavo GirÃ�¡ldez 2002-05-20 Alessio Frusciante <algol@firenze.linux.it> * configure.in: Added Italian to ALL_LINGUAS. 2002-05-20 Pablo Saratxaga <pablo@mandrakesoft.com> * configure.in: Added Catalan (ca) and Azeri (az) to ALL_LINGUAS 2002-05-17 Havoc Pennington <hp@redhat.com> * configure.in: 2.3.377 2002-05-16 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_get_neighbor): fix it, maybe 2002-05-16 Havoc Pennington <hp@redhat.com> * src/window.c (constrain_position): lock desktop to position 0,0 2002-05-16 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_show): don't focus dock, desktop, etc. windows on initial map, only windows that should have focus. 2002-05-15 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_get_neighbor): use the layout information to figure out up/down neighbors * src/display.c (event_callback): catch propertynotify on _NET_DESKTOP_LAYOUT * src/screen.c (meta_screen_update_workspace_layout): keep track of the layout of workspaces as set by the pager 2002-05-15 James M. Cape <jcape@ignore-your.tv> * src/themes/Esco/metacity-theme-1.xml: Minor tweak to minimize button. 2002-05-14 Havoc Pennington <hp@pobox.com> * src/themes/Makefile.am (THEMES): add Esco theme from James Cape 2002-05-12 Havoc Pennington <hp@pobox.com> * src/place.c (meta_window_place): move pposition/usposition honoring code into here, instead of putting it in window.c. Makes focusing new windows work, and cleans things up a bit. #81585 2002-05-12 Havoc Pennington <hp@pobox.com> * src/main.c (main): turn on --g-fatal-warnings if METACITY_G_FATAL_WARNINGS env variable is set. 2002-05-11 Anders Carlsson <andersca@gnu.org> * src/display.c: (find_tab_forward), (find_tab_backward), (meta_display_get_tab_next): * src/display.h: * src/keybindings.c: (handle_tab_forward), (handle_focus_previous): Add screen argument to meta_display_get_tab_next, since we only want windows on the same screen to appear in the tab chain. * src/screen.c: (meta_screen_new): Or the event mask with existing events since gtk+ may listen to certain events and we don't want to disable those events. (meta_screen_ensure_tab_popup): * src/tabpopup.c: (meta_ui_tab_popup_new): * src/tabpopup.h: Add a screen number argument to meta_ui_tab_popup_new so we can position the popup on the correct screen. 2002-05-11 Havoc Pennington <hp@pobox.com> * src/main.c: include locale.h, fix from Hidetoshi Tajima * src/window.c (meta_window_new): disable show desktop mode when a new window is managed. 2002-05-11 Havoc Pennington <hp@pobox.com> * src/fixedtip.c (meta_fixed_tip_show): keep the tooltip on the screen horizontally, #76825 * src/window.c (meta_window_handle_mouse_grab_op_event): end grab op _after_ doing the final update of the move or resize. Hopefully I didn't have a reason for the order I was using before. 2002-05-10 Havoc Pennington <hp@pobox.com> * src/tools/metacity-window-demo.c: add override redirect test window * src/stack.c (raise_window_relative_to_managed_windows): new function, used to avoid moving windows above override redirect popup windows. * src/display.c (event_callback): don't lower panels on LeaveNotify if they have focus, #70895 2002-05-10 Havoc Pennington <hp@pobox.com> * src/window.c (constrain_position): when maximizing/fullscreening something with a grid, like a terminal, center it in the maximization area in case it can't fill the whole area. #70554 * src/main.c (main): use g_strerror() to get proper UTF-8. 2002-05-10 Havoc Pennington <hp@pobox.com> * src/keybindings.c (reload_modmap): put LockMask into the ignored_modifier_mask so that caps lock doesn't mess up keybindings. 2002-05-10 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_focus): if window is not mapped after the calc_showing, don't focus it, it's probably on another workspace or something. 2002-05-09 Havoc Pennington <hp@redhat.com> * src/frames.c (show_tip_now): DefaultScreen() returns the screen number not Screen* * src/frame.c (meta_frame_sync_to_window): immediately repaint frame whenever we resize it, if we're inside a grab operation. * src/frames.c (meta_frames_repaint_frame): new function * src/window.c (meta_window_new): initialize window's colormap (meta_window_notify_focus): install the colormap for a window when it gets focus, uninstall on unfocus. * src/window.h (struct _MetaWindow): store window's colormap * src/display.c (event_callback): note changes to window colormap * src/frame.c (EVENT_MASK): add ColormapChangeMask 2002-05-09 Havoc Pennington <hp@redhat.com> * src/display.c (event_callback): make Alt+button2 do a resize 2002-05-08 Anders Carlsson <andersca@gnu.org> * src/fixedtip.c (meta_fixed_tip_show): #ifdef out call to gtk_window_set_screen, reported by Erwann Chenede. 2002-05-08 Anders Carlsson <andersca@gnu.org> * configure.in: * src/display.c: (meta_display_open): * src/fixedtip.c: (meta_fixed_tip_show): * src/fixedtip.h: * src/frames.c: (meta_frames_new), (show_tip_now): * src/frames.h: * src/menu.c: (meta_window_menu_new): * src/ui.c: (meta_ui_new): Add multi-screen support. Also add patch by Erwann Chenede to make tooltips appear on the correct screen. 2002-05-07 Anders Carlsson <andersca@gnu.org> * src/workspace.c (set_work_area_hint): Doh, only update the tmp pointer when the screen matches. Fixes a segfault when running with multiple screens. * src/display.c: (meta_display_open), (event_callback), (meta_display_update_show_desktop_hint): * src/display.h: * src/screen.c: (set_supported_hint): Fix atom name; it's _NET_SHOW_DESKTOP, not _NET_WM_SHOW_DESKTOP. * src/frames.c: (meta_frames_unmanage_window): Restore the mouse cursor to default when unmanaging a window. 2002-05-06 Anders Carlsson <andersca@gnu.org> * src/display.c: (set_utf8_string_hint): Fix an off-by-one error. (meta_display_open), (event_callback), (meta_display_update_show_desktop_hint), (meta_display_show_desktop), (meta_display_unshow_desktop): * src/display.h: * src/screen.c: (set_supported_hint): Add support for _NET_WM_SHOW_DESKTOP, both as a message and as a root window property. 2002-05-05 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_unminimize): on unminimize, queue calc_showing on all transients (meta_window_activate): on activate, unminimize all a window's ancestors, not just the window itself. * src/workspace.c (set_work_area_hint): don't increment "tmp" by 16 unsigned long, increment by 4 * src/window.c (meta_window_free): if a window isn't minimized, restore its WM_STATE to NormalState instead of IconicState, since IconicState on initial window map means that the window should be minimized. * src/workspace.c (meta_workspace_invalidate_work_area): queue an idle to recompute the work area hint. (set_work_area_hint): we need 4*num_workspaces ints, not just num_workspaces. * src/screen.c (meta_screen_new): add work_area_idle field, handle it on screen shutdown * src/common.h (META_PRIORITY_PREFS_NOTIFY, META_PRIORITY_WORK_AREA_HINT): define some idle priorities * src/window.c (meta_window_calc_showing): hide windows if their parent window is minimized (meta_window_minimize): also queue_calc_showing on all transients of the window being minimized * src/place.c (constrain_placement): function to apply placement-time-only constraints, such as "not off the left of the screen" (meta_window_place): put dialogs down a bit over their parent, not right at the top. (meta_window_place): when centering a dialog, center it on the current xinerama screen, rather than the entire screen. * src/screen.c (meta_screen_get_current_xinerama): new function, but not implemented 2002-05-04 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_paint_to_drawable): chop out the portion of the region that's outside the screen. * src/core.c (meta_core_get_screen_size): new function (meta_core_get_frame_extents): new function 2002-05-04 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_init): disable automatic GTK double buffering, since it resulted in gigantic backing pixmaps the size of the whole screen. (meta_frames_paint_to_drawable): change to take a region argument; punch the client area out of the expose region, then iterate over rectangles in the region and draw each, manually doing begin_paint_rect. Results in 4 long thin backing pixmaps per frame repaint, instead of one large backing pixmap. Suggested by Owen. 2002-05-05 Bastien Nocera <hadess@hadess.net> * src/workspace.c: (meta_workspace_get_neighbor): Wrap-around workspaces (ie. when on the last workspace, "switch_to_workspace_right" goes back to the first one) 2002-05-05 Anders Carlsson <andersca@gnu.org> * src/metacity.schemas: Fix a spelling error and change switch_to_workspace_up and switch_to_workspace_down to use Ctrl+Alt since Nautilus uses Alt now. 2002-05-04 Havoc Pennington <hp@pobox.com> * src/window.c (update_net_wm_type): correctly print things if the type_atom is unset (meta_window_new): with workarounds disabled, always allow self-placement for windows with PPosition or USPosition set. 2002-05-03 Havoc Pennington <hp@redhat.com> * src/Makefile.am: fix for automake 1.5, patch from Tomasz Kloczko 2002-05-03 Laszlo Peter <laca@sun.com> * configure.in: add the X libs to METACITY_MESSAGE_LIBS and METACITY_WINDOW_DEMO_LIBS 2002-05-02 Havoc Pennington <hp@redhat.com> * README: updates * configure.in: 2.3.233 2002-05-02 Bastien Nocera <hadess@hadess.net> * src/metacity.schemas: change the default for switch_to_workspace_* to be <Control><Alt>arrow as just <Alt>arrow collides with some apps (especially web browsers) 2002-05-01 Havoc Pennington <hp@redhat.com> * src/screen.c (meta_screen_new): Xlib doesn't like NULL for out arguments; fix for #80472 from lbedford 2002-04-30 Havoc Pennington <hp@pobox.com> * src/keybindings.c: finish mopping up mode_switch_mask field * src/display.h (struct _MetaDisplay): remove mode_switch_mask field 2002-04-30 Havoc Pennington <hp@pobox.com> * src/window.c (recalc_window_features): don't try to decorate toolbars. * src/tools/metacity-window-demo.c: add menu and toolbar tests * src/place.c (meta_window_place): only dialogs should be centered over parent, not anything with transient for set. * src/window.c (meta_window_configure_request): become more fascist about window positioning if workarounds are disabled, and less fascist if they are enabled. * src/metacity.schemas: add a "disable_workarounds" option. Kind of crack-smoking. But we just can't get all applications fixed. And I need no-workarounds mode to monitor which apps are broken and what needs fixing in specs. * src/window.c (meta_window_configure_request): always allow windows to resize themselves * src/keybindings.c (reload_modmap): don't filter out Mode_switch, apparently some people bind window manager shortcuts to that. 2002-04-30 Havoc Pennington <hp@redhat.com> * src/window.c (constrain_position): oops, fix maximization. Pointed out by Gustavo GirÃ�¡ldez Tue Apr 30 06:24:09 2002 Jonathan Blandford <jrb@gnome.org> * src/menu.c: give Maximize/Unmaximize and Shade/Unshade the same mnemonic for consistency's sake. 2002-04-29 Havoc Pennington <hp@redhat.com> * src/window.c (TITLEBAR_LENGTH_ONSCREEN): require 36 pixels onscreen so you typically get a sliver of titlebar, suggested by tigert. Should still fix this to consider actual theme geometry. (constrain_position): change to allow movement off the left 2002-04-29 Havoc Pennington <hp@redhat.com> * src/display.c (event_callback): always raise windows on focus click, regardless of focus mode. 2002-04-29 Havoc Pennington <hp@redhat.com> * configure.in: 2.3.144 2002-04-29 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_ui_init): don't leak the PangoContext 2002-04-28 Anders Carlsson <andersca@gnu.org> * src/display.c: (meta_display_open): * src/display.h: * src/screen.c: (set_supported_hint): * src/workspace.c: (set_number_of_spaces_hint), (set_workarea_hint): Add support for setting the _NET_WM_WORKAREA hint. No code does it yet though. 2002-04-28 Havoc Pennington <hp@pobox.com> * README: remove caveats about keybindings * src/metacity.schemas: add schemas for all the keybindings. * src/window.c (meta_window_activate): if in "show desktop" mode when a window is activated, leave show desktop mode. So e.g. when you click on a task in the task list, show desktop mode will be turned off. * src/workspace.c (meta_workspace_get_neighbor): new function that doesn't quite work yet (needs support for getting workspace layout from the pager) * src/prefs.c: keybindings stuff * src/keybindings.c: make keybindings configurable * src/ui.c (meta_ui_parse_accelerator): new function 2002-04-25 Havoc Pennington <hp@redhat.com> * metacity.spec: fix to install gconf schemas 2002-04-25 jacob berkman <jacob@ximian.com> * src/session.c (load_state): g_file_get_contents() takes a gsize not int (fixes bus error on 64-bit platforms) 2002-04-22 Havoc Pennington <hp@redhat.com> * src/main.c (main): call setlocale ourselves because due to a GLib bug that sticks us in ASCII if you call g_print or anything prior to setlocale, and print a warning if we don't set the locale successfully. #79280 * src/workspace.c (meta_workspace_get_work_area): be more verbose about how the work area was computed, to help find bugs here. * src/main.c (main): put locale and codeset in the log file 2002-04-21 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_send_icccm_message): add error trap, fixes a possible BadWindow if a window closed itself in response to the delete window message prior to us sending the ping message. 2002-04-21 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_move_resize_now): never revert to user_rect.width, user_rect.height. Maybe fixes assorted resize screwups e.g. with gnome-terminal. 2002-04-21 Anders Carlsson <andersca@gnu.org> * src/iconcache.c (scaled_from_pixdata): Add padding if icon width and height differ. 2002-04-17 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_new): query Xinerama screen information if HAVE_XINERAMA * configure.in (found_xinerama): check for Xinerama 2002-04-17 Changwoo Ryu <cwryu@debian.org> * configure.in (ALL_LINGUAS): Added ko (Korean). 2002-04-16 Akira TAGOH <tagoh@gnome.gr.jp> * configure.in (ALL_LINGUAS): add ja.po entry. 2002-04-15 Havoc Pennington <hp@pobox.com> * src/window.c (update_title): fix issue with GNU libc mangling %.10s format * metacity.spec: Fix up spec file * README: update README * configure.in (ALL_LINGUAS): require GTK 2.0.0 2002-04-15 Havoc Pennington <hp@redhat.com> * src/display.c (meta_display_ping_window): reply immediately for windows that don't support _NET_WM_PING * src/window.c (update_protocols): check whether windows support _NET_WM_PING 2002-04-13 Havoc Pennington <hp@pobox.com> * src/ui.c (get_cmap): same fix as libwnck, avoid using cmap with the wrong depth 2002-04-13 Havoc Pennington <hp@pobox.com> * src/delete.c: new file containing all the wacky mess I just added to a simple "click the close button", contains all the dealing-with-dead-application cruft. Use metacity-window-demo to test by clicking the toolbar button that locks it up. 2002-04-12 Havoc Pennington <hp@redhat.com> * src/tools/metacity-window-demo.c (do_appwindow): make one of the toolbar buttons lock up the demo * src/window.c (meta_window_delete): move error trap to be around a narrower part of the function, and add part of the ping stuff, nothing user-visible yet * src/metacity-dialog.c (main): metacity-dialog executable to live in libexecdir and pop up dialogs for us. 2002-04-09 Havoc Pennington <hp@pobox.com> * src/theme.c (multiply_alpha): fix alpha multiplication routine to perhaps work correctly, reported by tigert. Also, be sure we always copy the image if necessary before modifying the alpha channel. 2002-04-05 Havoc Pennington <hp@pobox.com> * src/stack.c: remove the unused tab stuff * src/display.c: implement tab list among panels * src/keybindings.c: fill in move-between-panels keybindings 2002-03-31 Johan Dahlin <jdahlin@telia.com> * src/menu.c (meta_window_menu_new): Make sure all menu items are translated. 2002-03-27 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_free): remove unmanaged windows from save set, and unselect input so we don't get events from them. Fixes annoying bug where withdrawn windows would decide to map themselves due to save set stuff. 2002-03-22 Zbigniew Chyla <cyba@gnome.pl> * configure.in (ALL_LINGUAS): Added pl (Polish). 2002-03-21 Havoc Pennington <hp@pobox.com> * src/themes/Bright/metacity-theme-1.xml: Added "Bright" theme from Gaute Lindkvist, with some small clipping tweaks to keep text/icons from overlapping their frames. 2002-03-19 Havoc Pennington <hp@redhat.com> * src/resizepopup.c (place_vertical_size_window) (place_horizontal_size_window): disable the little shaped windows with the window size, they caused a crash anytime you tried to resize with Xft. And they were kind of on crack anyway. 2002-03-17 Havoc Pennington <hp@pobox.com> * src/resizepopup.c (ensure_tick_windows): turn off the tick marks, that got annoying after about 5 minutes. One big shape window instead of lots of little windows might fix it. 2002-03-17 Havoc Pennington <hp@pobox.com> * src/resizepopup.c: Add some total crackrock resize-grid indication for windows that have width_inc/height_inc so I can debug gnome-terminal sizing. 2002-03-17 Havoc Pennington <hp@pobox.com> * src/session.c (set_clone_restart_commands): use proper property name for SmDiscardCommand (instead of setting the clone command to "rm"). Also fix typo that iterated over clonev not discardv to fill in prop list, and NULL-terminate discardv. #74584 from Kang Jeong-Hee. 2002-03-13 Havoc Pennington <hp@pobox.com> * src/main.c (main): put back --sm-client-id argument, needed for including us in a default session 2002-03-13 Havoc Pennington <hp@pobox.com> * src/session.c (meta_session_init): don't save a file here, only in response to SaveYourself. Change the code to properly use a unique state file for each SaveYourself. Totally, totally untested. 2002-03-12 Havoc Pennington <hp@pobox.com> * src/theme-viewer.c: improve the theme viewer so people can see the broken aspects of their themes. 2002-03-11 Havoc Pennington <hp@pobox.com> * src/keybindings.c: use new functions * src/display.c (meta_display_get_tab_next): (meta_display_get_tab_list): new tab order functions using MRU list instead of map order * src/window.c (meta_window_notify_focus): maintain focus MRU list * src/display.h (struct _MetaDisplay): Keep an MRU list of windows. 2002-03-10 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): support _NET_NUMBER_OF_DESKTOPS message so you can change number of desktops with the pager * src/prefs.c (meta_prefs_set_num_workspaces): new function * src/display.c (meta_spew_event): print stacking aspects of configure requests 2002-03-10 Havoc Pennington <hp@pobox.com> * src/screen.c (set_supported_hint): we didn't claim to support _NET_ACTIVE_WINDOW so gtk_window_present() didn't work. Mumble. Only worked with tasklist because libwnck didn't check for WM support. * src/window.c (meta_window_free): clean off window state when windows are withdrawn, to avoid sticking dialogs to their initial desktop. (meta_window_queue_calc_showing): return if window is withdrawn 2002-03-08 Laszlo Peter <laca@ireland.sun.com> * configure.in: fix the X linker flags 2002-03-06 Havoc Pennington <hp@pobox.com> * src/core.c (meta_core_get_grab_frame): add some assertions * src/menu.c (meta_window_menu_new): make another warning into a verbose * src/display.c (meta_change_button_grab): use verbose rather than warning to log failures to grab button, since these are typically BadWindow from a destroyed window. 2002-03-06 Havoc Pennington <hp@redhat.com> * src/frames.c (meta_frames_manage_window): use hash_table_replace instead of g_hash_table_insert * src/main.c (main): only enable verbose/debug if you set METACITY_VERBOSE/METACITY_DEBUG * src/util.c (ensure_logfile): only use a log file if METACITY_USE_LOGFILE is set * src/display.c (meta_display_for_x_display): add warning if MetaDisplay isn't found * src/window.c (meta_window_free): add an assertion that we successfully cleared the grab window 2002-03-05 Havoc Pennington <hp@pobox.com> Work on opaque animations more, still suck too much to turn on. Not sure how to make them good. * src/effects.c (meta_effects_draw_box_animation): add a slide-up mode for shading * src/ui.c (meta_image_window_set): change image window to work by setting back pixmap on the GtkWindow, instead of using GtkImage. 2002-03-04 Havoc Pennington <hp@pobox.com> * src/main.c (main): try ignoring SIGXFSZ, though I'm not sure what that does exactly. I'm hoping it gives me EFBIG. * src/util.c (ensure_logfile): log to a file in /tmp instead of to ~/metacity.log. 2002-03-04 Havoc Pennington <hp@redhat.com> * configure.in: fix configure.in since GTK no longer gives us -L/usr/X11R6/lib 2002-03-03 Havoc Pennington <hp@pobox.com> * src/window.c: improve debug spew about initial workspace 2002-03-02 Havoc Pennington <hp@pobox.com> * src/window.c (recalc_window_features): disable resize etc. if we're fullscreen (constrain_size): fix size constraints when fullscreen * src/display.c (meta_display_open): fix missing comma that ended up concatenating two of the properties breaking FULLSCREEN state and PING protocol 2002-03-02 Havoc Pennington <hp@pobox.com> * src/display.c: Add hacking to fix the problem that we made our XGrabPointer() during Alt+Tab actually succeed, so on popping down Alt+Tab we got an EnterNotify from the ungrab, which resulted in focusing the window under the mouse. i.e. Alt+Tab didn't work with sloppy focus. 2002-02-26 Havoc Pennington <hp@pobox.com> Screw around with Anders's ping patch so he'll get plenty of CVS conflicts. ;-) * src/display.c (meta_display_ping_window): spew warnings if we try to call this with CurrentTime (meta_display_ping_timeout): remove ping from the pending pings after it times out. * src/util.h: added PING debug category * src/display.c (remove_pending_pings_for_window): don't remove "tmp" just before "tmp->next", don't break out of loop after finding the first match (meta_display_open): no trailing comma in array init (event_callback): move the processing of ping replies into a separate function * src/screen.c (set_supported_hint): add _NET_WM_PING to supported list * src/display.h: change gpointer to void* 2002-02-26 Anders Carlsson <andersca@gnu.org> * src/display.c: (ping_data_free), (remove_pending_pings_for_window), (meta_display_open), (event_callback), (meta_display_unregister_x_window), (meta_display_ping_timeout), (meta_display_ping_window), (meta_display_window_has_pending_pings): Implement meta_display_ping_window, and filter out scroll wheel events. * src/display.h: Add MetaWindowPingFunc, meta_display_ping_window and meta_display_window_has_pending_pings. 2002-02-24 Havoc Pennington <hp@pobox.com> * src/display.c (xcursor_for_op): switch on the op passed in, not the active op. Gives us the right cursor during resizing, etc. * src/errors.c: rearrange all the error stuff to adapt to the GDK change a while back, so now we print our X errors again * src/display.c (meta_display_begin_grab_op): remove KeyPressMask and KeyReleaseMask from the XGrabPointer(), this caused BadValue and kept the grab from ever succeeding. Fixes the problem with the GTK resize grip - this is why you shouldn't break your X error spew. ;-) * src/display.c: debug spew tweaks * src/window.c (meta_window_client_message): do some s/verbose/topic/ stuff 2002-02-23 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_ui_init): fix the be-sure-we-create-coverage-cache hack 2002-02-19 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_ui_init): put in hack to keep Pango from mangling our server grab and locking up on startup. (hack doesn't work but I want to fix it on my real computer not this laptop) * src/window.c: Implement _NET_WM_STATE_FULLSCREEN * src/display.c (meta_display_open): add atoms for _NET_WM_STATE_FULLSCREEN 2002-02-16 Kjartan Maraas <kmaraas@gnome.org> * src/main.c: Use bind_textdomain_codeset etc. 2002-02-14 Havoc Pennington <hp@pobox.com> * src/theme-viewer.c: use the preview widget here * src/preview-widget.h, src/preview-widget.c: make the theme preview into a nice widget * src/frames.c (meta_frames_ensure_layout): replace frame layout if the frame style changes, this only ends up mattering if you e.g. changed the font size for windows in a different state such as maximized, which is crack, but the code may as well be correct * src/theme.c (meta_theme_get_frame_style): new function so we can detect an invalid cache of the PangoLayout in a frame 2002-02-14 Anders Carlsson <andersca@gnu.org> * src/themes/Crux/metacity-theme-1.xml: Fix some bugs with prelighting. 2002-02-13 Anders Carlsson <andersca@gnu.org> * src/theme.c (meta_pango_font_desc_get_text_height): Use pango_context_get_metrics instead of loading the font. 2002-02-12 Anders Carlsson <andersca@gnu.org> * src/frames.c (meta_frames_manage_window): Set prelit_control to META_FRAME_CONTROL_NONE. (meta_frames_update_prelit_control): New function for setting the prelit control. (meta_frames_paint_to_drawable): Set prelight state. (meta_frames_enter_notify_event): Update prelit control. (meta_frames_leave_notify_event): Likewise. (meta_frames_motion_notify_event): Likewise. * src/frames.h (struct _MetaUIFrame): add prelit_control. * src/window.c (update_mwm_hints): and MWM_FUNC_ALL with hints->functions instead of hints->flags. 2002-02-11 Anders Carlsson <andersca@gnu.org> * src/theme.c (meta_frame_layout_new): Set title_scale to 1.0 2002-02-11 Bastien Nocera <hadess@hadess.net> * src/theme-viewer.c: (main): change default theme to be Atlanta like in the .schema file 2002-02-10 Havoc Pennington <hp@pobox.com> * src/tools/Makefile.am (EXTRA_DIST): add $(icon_DATA) * configure.in: 2.3.55 * HACKING: update * README: update 2002-02-09 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_theme_set_current): add a newline to an error message * src/themes/Gorilla: add Gorilla theme by Jakub Steiner ported to metacity by Kenneth Christiansen 2002-02-09 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_draw_op_draw_with_env): implement wacky "tile" draw op to lose some of the PNG files in Gorilla theme * src/theme-parser.c: parse the tile primitive 2002-02-09 Havoc Pennington <hp@pobox.com> * src/window.c (update_icon): port to icon cache * src/iconcache.c, src/iconcache.c: begin process of cleaning up window.c by moving the icon-reading code in here, based on the code in libwnck, which was in turn based on the earlier metacity code 2002-02-09 Havoc Pennington <hp@pobox.com> * src/stack.c (meta_stack_sync_to_server): hmm, and don't set last_window at all if we don't ++newp. Fixes even more obscure stacking bug. 2002-02-09 Havoc Pennington <hp@pobox.com> * src/stack.c (meta_stack_sync_to_server): assign last_window prior to ++newp, so we don't try to stack windows with respect to themselves. Fixes some obscure stacking bugs. 2002-02-09 Havoc Pennington <hp@pobox.com> * src/theme-parser.c: try to make more error message strings the same, easier for translators * src/theme.c (meta_draw_op_free): free color spec for line op (meta_theme_free): free the integer_constants hash * src/theme-parser.c (parse_boolean): move above first use * src/theme-viewer.c: fixes for theme.h changes * src/frames.c (queue_recalc_func): don't recreate layout immediately, just save title text. should speed things up. (meta_frames_set_title): just remove the layout here also, and save title text. * src/theme-parser.c (parse_toplevel_element): parse title_scale attribute on frame_geometry * src/theme.c: support setting the text size * src/frames.c: support setting the text size * theme-format.txt: updates 2002-02-09 Havoc Pennington <hp@pobox.com> * src/themes/Atlanta/metacity-theme-1.xml: put in some kind of distinctive frame for UTILITY, though it's ugly. Also put in the borderless look for maximized windows. * src/stack.c (compute_layer): put splash screen in the splash layer * src/stack.h (enum): create a splash screen layer * src/place.c (meta_window_place): center splashscreen, and fix a typo in the centering code * src/window.c (recalc_window_features): disable most features on splash screens * src/screen.c (set_supported_hint): add UTILITY and SPLASHSCREEN hints * src/window.c: add UTILITY, SPLASHSCREEN implementation * src/window.h (enum): add UTILITY, SPLASHSCREEN types * src/theme-parser.c (parse_toplevel_element): parser support for has_title attribute * src/theme.c (meta_frame_layout_get_borders): handle a has_title field in the layout, for utility windows that don't display a title (would be better to be able to shrink the title text, but that's kind of tricky to implement :-/) 2002-02-08 Havoc Pennington <hp@pobox.com> * src/screen.c (set_supported_hint): add _NET_WM_STATE_HIDDEN to _NET_SUPPORTED * src/keybindings.c (meta_set_keybindings_disabled): put in header file, to fix warning. * src/display.c (meta_display_open): add _NET_WM_STATE_HIDDEN atom * src/window.c (set_net_wm_state): set _NET_WM_STATE_HIDDEN for shaded and minimized windows (meta_window_show): call set_net_wm_state() if we map the window or frame (meta_window_hide): call set_net_wm_state() if we unmap the window or frame 2002-02-08 Havoc Pennington <hp@pobox.com> * src/window.c (set_net_wm_state): only set skip pager/tasklist if the app set it, don't set it again based on semantic type. 2002-02-08 Anders Carlsson <andersca@gnu.org> * src/theme.c (scale_and_alpha_pixbuf): If we're only scaling horizontally or vertically, use GDK_INTERP_NEAREST. 2002-02-08 Havoc Pennington <hp@pobox.com> * autogen.sh: unbreak 2002-02-08 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_grab_focus_window_button): grab buttons 2 and 3 also, so you can focus a window with those, #70840 (event_callback): fix this to let you focus a window with any unmodified click, and also with Alt+button1 * configure.in (AC_OUTPUT): add po/Makefile.in * autogen.sh: port to glib-gettextize, remove stupid auto-find-subdirs crap * Makefile.am (SUBDIRS): add po to subdirs, #70615 * src/window.c (meta_window_activate): unshaded window if shaded, I thought this was in bugzilla but I don't see it. anyway thanks whoever mentioned it to me. 2002-02-08 Havoc Pennington <hp@pobox.com> * src/tools/metacity-window-demo.c (menu_items): add modal dialog test 2002-02-08 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_show): when mapping a window with struts, invalidate the work areas it's on. Should fix at least part of the problem with windows maximizing over panels. * src/workspace.c (meta_workspace_invalidate_work_area): also queue move/resize on sticky windows * src/tools/Makefile.am: consolidate reload-theme, restart into a "metacity-message" app and add enable/disable keybindings to the messages it knows about. * src/keybindings.c: (meta_change_keygrab): grab keyboard synchronously (meta_display_process_key_event): if all keybindings are toggled off, ReplayKeyboard, else AsyncKeyboard, except that the debug binding for toggling back on is always processed (meta_set_keybindings_disabled): function to disable/enable all keybindings 2002-02-07 Havoc Pennington <hp@pobox.com> * src/run-metacity.sh: if DEMO_TEST is set then run the window demo * src/tools/metacity-window-demo.c: Create an app with all the semantic window types, for testing and for designing themes. 2002-02-07 Havoc Pennington <hp@pobox.com> Throughout: move to meta_topic rather than meta_verbose so metacity.log can start being more useful * src/util.h (enum): add more debug topics * src/frames.c: clean up some cruft that caused warnings 2002-02-07 Havoc Pennington <hp@pobox.com> * src/theme.c (colorize_pixbuf): do random voodoo on the algorithm 2002-02-07 Havoc Pennington <hp@pobox.com> * src/theme.c (colorize_pixbuf): use the intensity of the gray pixel for both saturation and value, not just value. 2002-02-07 Havoc Pennington <hp@pobox.com> * src/theme.c (INTENSITY): don't define the macro twice 2002-02-07 Havoc Pennington <hp@pobox.com> * src/theme.c (colorize_pixbuf): get algorithm right (use HSV/RGB conversion) at cost of making it a lot slower. It doesn't matter anyhow with the cache, though. 2002-02-06 Havoc Pennington <hp@pobox.com> * src/theme.c (colorize_pixbuf): handle out-of-memory creating target pixbuf * src/themes/Crux/*.png: convert the green-channel images to grayscale 2002-02-06 Havoc Pennington <hp@pobox.com> * src/prefs.c (change_notify): s/update_focus_mode/update_theme/ in case of theme key changing 2002-02-06 Havoc Pennington <hp@pobox.com> * src/theme-viewer.c: benchmark theme on startup * src/theme-parser.c (parse_draw_op_element): fix "colorize != NULL" to "colorize_spec != NULL" and free pixbuf on color spec failure * src/theme.c (colorize_pixbuf): minor reformatting, raise function calls out of inner loop, clamp r/g/b values to uchar range before assigning to uchar (draw_op_as_pixbuf): cache the colorized pixbuf (meta_draw_op_free): free the cache pixbuf 2002-02-07 Anders Carlsson <andersca@gnu.org> * src/theme-parser.c: (parse_draw_op_element): Add support for "colorize" image attribute. * src/theme.c: (colorize_pixbuf): New function that colorizes a pixbuf. (pos_tokenize): Allow "\n" as a whitespace character. (meta_draw_op_free): Free colorize_spec; (draw_op_as_pixbuf): Colorize image if needed. * src/theme.h: Add colorize_spec to struct. 2002-02-07 Anders Carlsson <andersca@gnu.org> * src/themes/Crux/metacity-theme-1.xml: Add maximized and shaded_and_maximized frame styles. 2002-02-06 Havoc Pennington <hp@pobox.com> * src/main.c (prefs_changed_callback): redo window sizes/appearance when the theme changes * src/display.c (meta_display_retheme_all): new function * src/theme-parser.c (locate_attributes): remove error handling for MAX_ATTRS reached, add an assert instead, the way this code ended up the attrs in the array depend on the code not the theme file. 2002-02-06 Havoc Pennington <hp@pobox.com> * src/main.c (main): disable custom log handler and fatal mask for now * src/theme.c (meta_draw_op_list_draw): Add META_DRAW_CLIP * src/main.c: load theme, monitor current theme setting * src/prefs.c: add "current theme" setting * src/stack.c (meta_stack_free): don't try to free last_root_children_stacked if it doesn't exist * src/themewidget.c: pluggable GtkMisc subclass to use for menu icons * src/screen.c (meta_screen_manage_all_windows): fix signed/unsigned warning * src/frames.c: port to theme system (meta_frames_style_set): chain up * theme-format.txt: new file * configure.in: add more compiler warnings * src/theme.c: add various stuff needed to get theme parser working. Remove the "spacer" concept from FrameLayout object. Add draw op that references a draw op list. * configure.in: require GTK 1.3.13 * src/Makefile.am: add theme-parser.[hc], implement loading a theme * src/theme.c: add "draw title" and "draw window icon" operations (meta_draw_op_draw): put object_width/object_height in expression environment before computing x/y. Handle out-of-memory when creating pixbufs. Assorted other cleanups. 2002-02-07 Anders Carlsson <andersca@gnu.org> * src/themes/Crux/metacity-theme-1.xml: Simplify things so we can remove some now unnecessary .png files. * src/themes/Crux/*.png: Remove some files. 2002-02-07 Anders Carlsson <andersca@gnu.org> * src/themes/Crux/metacity-theme-1.xml * src/themes/Crux/*.png: Add Crux theme 2002-02-07 Kenneth Rohde Christiansen <kenneth@gnu.org> * configure.in: add da to ALL_LINGUAS * po/da.po: add Danish translation 2002-02-02 Havoc Pennington <hp@pobox.com> * src/theme-viewer.c: test % operator * src/theme.c (pos_tokenize): add % to switch for operators * src/theme.c: rework theme stuff so we have MetaDrawOp/MetaDrawOpList instead of MetaTextureSpec/MetaShapeSpec 2002-01-28 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_texture_spec_render): fix shadowed variable (stupid -Wall should have that) * src/theme-viewer.c (main): implement a simple viewer for frame styles * src/theme.c (meta_frame_style_get_test): create partial frame style to test drawing 2002-01-27 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_shape_spec_draw): implement (meta_texture_spec_draw): implement shape spec and blank texture support (meta_frame_style_draw): implement 2002-01-27 Havoc Pennington <hp@pobox.com> * src/display.c (meta_set_syncing): move in here so util.c doesn't require display.[hc] * src/theme.h, src/theme.c: implement coordinate expression parser, write MetaShapeSpec declaration * src/util.c (meta_exit): move in here so we can link to util.c with a different main() * src/theme.h: rename the MetaWindow* enums to MetaFrame* 2002-01-27 Peteris Krisjanis <peteris.krisjanis@ttc.lv> * configure.in - Added lv to ALL_LINGUAS 2002-01-27 Havoc Pennington <hp@pobox.com> * src/frames.c (get_control): Only consider the bottom of the titlebar a resize control; I keep accidentally resizing windows instead of activating them. Also, give south resizing priority over north, if the window is so small the active regions overlap * src/theme.c: add MetaTheme, get MetaFrameStyleSet into a usable state * src/common.h: move window type back to window.h, decided not to use it on frame side (MetaFrameType): add this instead 2002-01-27 Havoc Pennington <hp@pobox.com> * src/theme.h, src/theme.c: implement all kinds of crazy compositing-one-texture-onto-another BS. 2002-01-27 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): make the check for whether to eat focus click a lot more complicated * src/window.c (meta_window_same_application): new function * src/prefs.h, src/prefs.c: add application based pref * src/metacity.schemas: add "application_based" setting to give me a mode to fool with being application based, without being unusable in the meantime. Yeah the crack flows freely these days. Everyone knew it would happen. 2002-01-27 Havoc Pennington <hp@pobox.com> * src/frames.c: separate code to draw frame from the expose_event handler, so in principle we can draw the frame to a pixmap, but this isn't used yet. 2002-01-22 Hasbullah Bin Pit <sebol@ikhlas.com> * configure.in: Added Malay (ms)to ALL_LINGUAS. * po/ms.po: Added Malay Translation. 2002-01-19 Havoc Pennington <hp@pobox.com> * src/wm-tester/test-resizing.c: cheesy client with static bit gravity, used to test the below change. * src/window.c (meta_window_move_resize_internal): implement Owen's proposal for window resizing. http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html Currently you have to do METACITY_USE_STATIC_GRAVITY=1 in order to use it, because some GDK bug is screwing up exposes on my frames when it's enabled. * src/display.c (meta_display_create_x_cursor): fix glyph for NE/NW cursors * src/frames.c (get_control): add ability to resize from top * src/frame.c (meta_frame_get_flags): can't resize shaded windows (meta_frame_sync_to_window): add gravity arg * src/common.h (MetaWindowType): move here from window.h so it can be used in themes stuff. (MetaFrameFlags): remove META_FRAME_TRANSIENT since it overlaps with window type and was unused. 2002-01-18 Havoc Pennington <hp@pobox.com> * src/window.c (constrain_position): give priority to keeping NW corner onscreen rather than SE, if we need to shift the window to fit inside constraints * src/frames.c (meta_frames_get_geometry): don't depend on the current window size * src/theme.c: move geometry stuff in here, to be calculated as part of the theme * src/core.c (meta_core_get_client_size): new function to replace meta_core_get_frame_size() so we don't have weird cycles in the geometry calculation 2002-01-12 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_queue_move_resize): make this actually queue, rather than being synchronous as it was before. We'll see what breaks. Should be more efficient and reduce flickery stuff a bit in some cases. 2002-01-15 Havoc Pennington <hp@redhat.com> * src/keybindings.c (handle_tab_backward): fix crash when grab failed due to another operation in progress (handle_tab_forward): fix crash when grab failed 2002-01-10 Havoc Pennington <hp@pobox.com> * src/frame.c (meta_window_destroy_frame): only bump unmaps_pending if the window was mapped (meta_window_ensure_frame): ditto * src/keybindings.c: change arrow key bindings to use Ctrl+Alt not just Alt, and add debug mode key bindings * src/stack.c (meta_stack_get_default_focus_window): don't choose a default focus window with unmaps pending, since we probably just unmapped it. * src/display.c (event_callback): move notify_focus on UnmapNotify after the window_free check, so we can move focus to another window when we unmanage * src/window.c (meta_window_hide): invalidate work areas when hiding a window with struts (meta_window_free): invalidate work areas when unmanaging a window with struts 2002-01-09 Havoc Pennington <hp@pobox.com> * src/window.c, src/window.h: store strut information, update it on property changes, etc. etc. so we avoid panel on maximize. * src/workspace.c (meta_workspace_get_work_area): add accessor for work area so we can compute it lazily * src/display.h, src/display.c: add _NET_WM_STRUT atom and _WIN_HINTS atom 2002-01-08 Havoc Pennington <hp@pobox.com> * configure.in (ACLOCAL): add code to save ACLOCAL_FLAGS * src/frames.c (meta_frames_expose_event): max dither * src/testgradient.c (render_simple): change dither mode to MAX to avoid banding * src/theme.c: lose the gradient cache, and put in some initial data types for the theme format 2002-01-07 Havoc Pennington <hp@redhat.com> * src/frames.c (meta_frames_expose_event): make gradient a bit more subtle (don't go to the full background, but to a blend of selection and background; put lighter color on top) 2002-01-06 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_notify_focus): rearrange code a bit to make it clear that has_focus flag always follows display->focus_window 2002-01-06 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_notify_focus): put in attempted fix for the GTK 1.2 plug/socket screwup, now that my fixed debug spew reveals what's actually happening. ;-) * src/gradient.c (meta_gradient_description_new): object to store gradient descriptions * src/window.c (meta_window_notify_focus): fix the debug spew that was confusing me * src/wm-tester/focus-window.c: add little program to focus a window ID 2002-01-06 Havoc Pennington <hp@pobox.com> * src/theme.c (meta_theme_get_gradient): change to use spiffy gradient code. * src/gradient.c: copy lovely gradient code from WindowMaker, as usual Dan and Alfredo have very nice code 2002-01-06 Fatih Demir <kabalak@gtranslator.org> * configure.in: Added "tr" to the languages list. 2002-01-05 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_expose_event): draw titlebar highlight with snazzy gradient that needs some tweaking to be less dumb-looking * src/theme.c: replace old theme.[hc] contents with newer stuff that doesn't do anything 2002-01-05 Havoc Pennington <hp@pobox.com> GTK 1.2 plug/socket clients still broken, don't know why. * src/screen.c (meta_screen_new): select focus change on root window, for debugging * src/display.c (event_callback): when unfocusing, use no_focus_window to hold the focus * src/display.h (struct _MetaDisplay): have a no_focus_window to hold the focus when we don't want to have anything focused. Then we can avoid confusing focusing-the-frame stuff. * src/window.c (meta_window_notify_focus): improve some debug spew (meta_window_notify_focus): add hack from WindowMaker to ignore focus in events with detail > NotifyNonlinearVirtual 2002-01-04 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): don't lower docks when a grab causes them to get LeaveNotify 2002-01-04 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_free): set event mask on root window to 0 so other window managers (such as ourselves restarting) can start up; addresses race condition on restart where the old WM still had RedirectMask when the new WM was trying to start up. * src/display.c (meta_display_close): free each screen * src/window.c (meta_window_show): always focus new windows in click-to-focus mode 2002-01-03 Havoc Pennington <hp@pobox.com> * src/window.c: use meta_XFree not XFree * src/display.h (meta_XFree): add null-safe XFree * src/util.c (meta_warning): have message prefix indicate that it's a warning (meta_fatal): indicate it's an error * src/window.c (update_sm_hints): clean up using meta_prop_get_latin1_string (update_role): ditto (read_client_leader): clean up using meta_prop_get_window (update_net_wm_type): clean up using meta_prop_get_cardinal (update_initial_workspace): ditto (update_net_wm_type): clean up using meta_prop_get_atom_list (read_rgb_icon): get result from XGetWindowProperty return value not from error trap (update_kwm_icon): ditto (meta_window_new): fix to read WM_STATE correctly 2002-01-03 Havoc Pennington <hp@pobox.com> * src/window.c (update_net_wm_state): clean up using meta_prop_get_atom_list (update_mwm_hints): clean up using meta_prop_get_motif_hints * src/Makefile.am (metacity_SOURCES): add xprops.[hc] * src/xprops.c: new file with convenience functions for X properties 2002-01-03 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_activate): focus top window when switching to a new workspace * src/util.c (meta_topic): start putting verbose output in categories * src/window.c (meta_window_shade): focus frame after we queue the calc_showing so the maps/unmaps have already happened. * src/display.c (meta_display_get_current_time): add the "get time of current event" function and call it occasionally. * src/window.c (meta_window_free): if we have focus, call meta_screen_focus_top_window(). (meta_window_minimize): ditto (meta_window_delete): ditto * src/screen.c (meta_screen_ensure_tab_popup): fix memory leak - didn't free tab list (meta_screen_focus_top_window): new function to use when we unmap or unmanage a focused window * src/stack.c (meta_stack_get_default_focus_window): function used in meta_screen_focus_top_window 2001-12-21 Havoc Pennington <hp@redhat.com> * src/frame.c (meta_window_ensure_frame): add a server grab here since we were failing to have one when calling the function 2001-12-27 Duarte Loreto <happyguy_pt@hotmail.com> * configure.in: Added portuguese to ALL_LINGUAS 2001-12-16 Kjartan Maraas <kmaraas@gnome.org> * configure.in: Added "no" to ALL_LINGUAS. 2001-12-11 Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz> * configure.in: Added "sk" to ALL_LINGUAS. 2001-12-10 Havoc Pennington <hp@pobox.com> Rework the click-client-area-to-focus support to use synchronous grabs, avoids a big mess, lets us pass through click when required (for dock/desktop). Disadvantage is all left-button clicks now require window manager approval. ;-) * src/display.c (event_callback): don't focus dock/desktop when the mouse enters them; require a click. (meta_change_button_grab): allow sync grabs (meta_display_grab_unfocused_window_buttons): establish a synchronous grab and maintain it all the time, rename to meta_display_grab_focus_window_button * src/window.c: change to reflect display.c 2001-12-10 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_update_unfocused_button_grabs): oops, unbreak this _again_ - reported by Josh Barrow 2001-12-10 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_update_unfocused_button_grabs): don't allow grab on docks/desktop for now; needs fixing later to do the grab, but pass thru click, so we can focus those windows. And in fact we need to do that even in sloppy mode. 2001-12-10 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_foreach_window): fix broken "tmp = tmp->data" Implement do-not-pass-thru-click for click-to-focus mode. * src/screen.c (update_focus_mode): when focus mode changes, update all the window grabs * src/display.c (meta_display_grab_unfocused_window_buttons): implement grabbing button 1 on client area of unfocused click-to-focus windows * src/window.c (meta_window_update_unfocused_button_grabs): update whether we're grabbing unmodified button 1 on client area according to focus state and focus mode (meta_window_new): start out with proper grab state 2001-12-10 Havoc Pennington <hp@pobox.com> * src/menu.c (meta_window_menu_new): don't do mnemonics for workspaces above 9 2001-12-10 Havoc Pennington <hp@pobox.com> * src/screen.c (meta_screen_new): oops, remove extra workspace creation, and update to current pref. 2001-12-09 Havoc Pennington <hp@pobox.com> * src/workspace.c (meta_workspace_free): update number of workspaces hint * src/screen.c (update_num_workspaces): implement number of workspaces setting * src/window.c (meta_window_configure_request): honor configure requests on windows of type NORMAL, but still be mean to those of type DIALOG * src/main.c (main): add more log domains to those we set a log handler for, and only set warnings fatal in debug mode * src/metacity.schemas: add number of workspaces setting 2001-12-09 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): in click-to-focus mode don't focus on enter notify. Implement unfocusing on LeaveNotify in mouse focus mode. Click to focus just ends up working if we do nothing on enter/leave, because of the way things already worked. Except I need to add some relatively complex hack to allow clicking on client area, right now you have to click on the frame. 2001-12-09 Havoc Pennington <hp@pobox.com> * src/main.c (main): move SM init a bit later in the process, and init prefs * src/session.c: fix no SM case (though I hardly know why I'm bothering) * src/main.c (main): call bindtextdomain * src/util.h (_): actually call gettext * configure.in: put in AM_GLIB_GNU_GETTEXT and gconf stuff * src/prefs.c: Preferences - this marks the beginning of our doom. None of them are actually implemented yet, but we monitor some stuff from gconf. 2001-12-07 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_unminimize): when unminimizing an app, if we're in "show desktop" (all windows minimized) mode, leave show desktop mode. Will occasionally be a bit weird, but allows people to recover via task list if they accidentally do the show desktop thing, and don't know what's going on. 2001-12-06 Havoc Pennington <hp@redhat.com> * src/ui.c (meta_text_property_to_utf8): fix gdkatom/xatom screwup - gee, I should read my warnings 2001-12-03 Laszlo Peter <laca@ireland.sun.com> * src/frames.c: add a dummy element to the enum so the signals array is not empty. (breaks the build with Forte C) * src/window.c: s/__FUNCTION__/G_GNUC_FUNCTION/ 2001-11-27 Havoc Pennington <hp@pobox.com> * src/window.c (constrain_position): change so that window can be offscreen to the bottom or the right, as long as a small top-left corner of the window remains onscreen. However, windows still can't go off the left or top. 2001-11-26 Havoc Pennington <hp@redhat.com> * src/window.c (window_query_root_pointer): add error trap 2001-11-27 Jesus Bravo Alvarez <jba@pobox.com> * configure.in: Added gl (Galician) to ALL_LINGUAS. Tue Nov 20 18:49:16 2001 Owen Taylor <otaylor@redhat.com> * configure.in (found_sm): Add some additional quoting to make it work with autoconf-2.5x. 2001-11-02 Laszlo Peter <laca@ireland.sun.com> * src/window.c (update_sm_hints): protect meta_verbose from a NULL pointer. 2001-10-29 Havoc Pennington <hp@pobox.com> * configure.in: bump version 2001-10-29 Havoc Pennington <hp@pobox.com> * src/window.c (idle_calc_showing): handle queue/unqueue of calc showings as we are iterating over the pending list (meta_window_show): focus placed transients in here instead of in meta_window_place - now it should actually work, yay * src/place.c (meta_window_place): remove focusing of transient child from here; this was really broken 2001-10-29 Yuriy Syrota <rasta@renome.rovno.ua> * configure.in: Added "uk" to ALL_LINGUAS. 2001-10-29 Havoc Pennington <hp@pobox.com> * README: note exciting new unminimize feature for the tab popup * src/keybindings.c (process_tab_grab): use meta_window_activate() when choosing a window with tab popup, this should deiconify it * src/window.c (meta_window_client_message): use meta_window_activate for _NET_ACTIVE_WINDOW message (meta_window_activate): new function to raise/focus/unminimize (meta_window_flush_calc_showing): new function (meta_window_focus): force a calc showing on focus, so that we can focus the window if appropriate (it must be mapped) 2001-10-26 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_grab_window_buttons): fix for ignoring NumLock on Alt-windowclick (previous NumLock fix was only for key grabs not button grabs) 2001-10-25 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_new): set the current workspace hint 2001-10-25 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_visible_on_workspace): I was using meta_workspace_contains_window() in a number of places where on_all_workspaces should also have been considered, thus this new function. Fixes bugs such as pinned windows not appearing in the tab order. (meta_window_client_message): use meta_window_visible_on_workspace * src/stack.c (find_tab_forward): ditto (find_tab_backward): ditto (meta_stack_get_tab_next): ditto (meta_stack_get_tab_list): ditto * src/place.c (get_windows_on_same_workspace): ditto * src/keybindings.c (handle_focus_previous): ditto (handle_focus_previous): ditto 2001-10-24 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_expose_event): use bg/fg not base/text for the window title area. 2001-10-24 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): support initial on-all-workspaces setting 2001-10-22 Havoc Pennington <hp@pobox.com> * src/stack.c (meta_stack_sync_to_server): fix to keep desktop window from appearing on top of everything else, among other stack bugs. Untested. 2001-10-15 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): use queried attributes to check whether window should be initially maximized, rather than window rect 2001-10-15 Havoc Pennington <hp@pobox.com> * src/main.c (meta_restart): add a restart feature, for debugging * src/tools/metacity-restart.c: little utility program to trigger the restart 2001-10-14 Havoc Pennington <hp@pobox.com> * src/frames.c (meta_frames_button_press_event): raise/focus windows on left-click, seem to have broken that yesterday * src/keybindings.c, src/display.c, src/window.c: add keybinding to show/hide all normal windows (so you can see the desktop). Currently Ctrl+Alt+D, which I don't like, but yay. 2001-10-14 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_new): take a window mapped at fullscreen size/pos to desire maximization; once I add a fullscreen state, will change to copy kwin and take this mapping as a desire for fullscreen, but for now testing with maximization. * src/window.h: remove fullscreen window type, now proposing it as a window state instead. 2001-10-14 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_maximize): always raise windows on maximize (meta_window_client_message): when activating a window, move it to current workspace, instead of moving user to the window's workspace. 2001-10-14 HÃ�©ctor GarcÃ�­a Ã�lvarez <hector@scouts-es.org> * configure.in: Added "es" to ALL_LINGUAS for Spanish translation. 2001-10-14 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): only handle events here if the modmask from our button grab is active. i.e. only the Alt-click is handled here. * src/frames.c: add check for whether button presses are in the frame client area before handling them, so we don't weirdly let you move a frame by clicking in its client area if the client hasn't selected button press events. 2001-10-13 Havoc Pennington <hp@pobox.com> * src/stack.c (meta_stack_sync_to_server): set last window before setting newp, so we don't get the current window as the last window and screw everything up (IN_TAB_CHAIN): use type not layer to decide if a window is in the tab chain, keeps panel out of alt-tab choices 2001-10-13 Havoc Pennington <hp@redhat.com> * configure.in: add bad hack to work with GTK 1.3.9.90 RPMs from gnomehide for now * src/ui.c: another piece of bad hack in here 2001-10-13 Havoc Pennington <hp@redhat.com> * configure.in: bump version 2001-10-13 Havoc Pennington <hp@pobox.com> * src/session.c (meta_session_init): hmm, fix build 2001-10-12 Havoc Pennington <hp@pobox.com> * src/session.c (meta_session_init): set the session manager priority so we start up before other apps. 2001-10-12 Mikael Hallendal <micke@codefactory.se> * src/ui.c (meta_ui_get_default_window_icon): use gdk_pixbuf_new_from_inline (meta_ui_get_default_mini_icon): use gdk_pixbuf_new_from_inline 2001-10-11 Christian Rose <menthos@menthos.com> * configure.in: Added "sv" to ALL_LINGUAS. 2001-10-10 Havoc Pennington <hp@pobox.com> * src/stack.c (meta_stack_free): fix mem leak of the MetaStack object (meta_stack_sync_to_server): try to avoid the restack-flicker thing 2001-10-07 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_update_active_window_hint): set _NET_ACTIVE_WINDOW hint * src/window.c (meta_window_client_message): support _NET_ACTIVE_WINDOW client message 2001-10-07 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_client_message): don't allow shade/maximize/minimize for windows that don't support those operations. (minimizing the panel = bad) 2001-10-04 Havoc Pennington <hp@pobox.com> * src/keybindings.c (meta_change_keygrab): add code to grab all modifier combinations, so keybindings work with NumLock etc. * src/menu.c (meta_window_menu_new): remove newlines from menu items 2001-09-27 Havoc Pennington <hp@pobox.com> * src/session.c (save_state): when encoding text for session file, escape XML entities 2001-09-21 Alex Graveley <alex@ximian.com> * src/Makefile.am (metacity_SOURCES): Add inlinepixbufs.h so that it gets generated. * src/frames.c (meta_frames_style_set): Update for new opaque PangoFontMetrics. 2001-09-17 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_ui_init): add hackaround for the warning about gtk-menu-bar-accel 2001-09-17 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_ui_get_default_mini_icon): (meta_ui_get_default_window_icon): ref the returned icon, oops. * src/main.c (main): get the GLib warning/error output into the metacity logfile, set warnings to be always fatal * configure.in: bump version to 2.3.13 * src/window.c (get_text_property): hrm, fix bug where we didn't check errors on XGetTextProperty 2001-09-17 Havoc Pennington <hp@pobox.com> * src/Makefile.am (VARIABLES): fix srcdir != builddir glitch 2001-09-17 Havoc Pennington <hp@pobox.com> * src/ui.c: use the inline image data for default icon * src/common.h (META_MINI_ICON_HEIGHT): move icon size defines here * src/Makefile.am: Create an inlinepixbufs.h header with inline images 2001-09-16 Havoc Pennington <hp@pobox.com> * src/session.c (process_ice_messages): disconnect this callback on error 2001-09-16 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_lower): new function * configure.in: bump version to 2.3.8 * src/display.c (event_callback): raise dock on enter notify, lower it on leave notify (need to refine this behavior) * src/stack.c (compute_layer): experiment with putting the panel in the normal layer, and raising it on mouseover 2001-09-15 Havoc Pennington <hp@pobox.com> * src/window.c: add support for a mini icon in the titlebar (update_icon): re-enable support for _NET_WM_ICON * src/session.c (save_state): add an ferror check when writing session file 2001-09-11 Havoc Pennington <hp@pobox.com> * src/main.c (usage): exit with error code on usage() (kind of wrong for --help, but oh well). 2001-09-11 Havoc Pennington <hp@pobox.com> * src/window.c: fix up handling of text properties, so we get UTF8_STRING as that type and not as text list, and so we properly convert from text list to UTF-8 2001-09-10 Havoc Pennington <hp@pobox.com> * src/menu.c (meta_window_menu_new): icon for unmaximize * src/ui.c (meta_ui_init): fix call to XDisplayName * src/util.c: add missing header * src/frames.c: draw an unmaximize control if already maximized 2001-09-10 Havoc Pennington <hp@pobox.com> * src/window.c: Don't separate user_has_moved/user_has_resized, fixes bug in east-resizing Emacs, among other things * src/frame.c (meta_frame_sync_to_window): return immediately if nothing to do * src/util.c (ensure_logfile): replace rather than truncate old logfiles 2001-09-08 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_ui_init): don't use gdk_display_name * src/frame.c (meta_window_ensure_frame): create frame with screen default visual, rather than client window visual; for DRI games, the client window visual was not allowed to be a child of another window with the same visual, apparently. Anyhow now we copy twm, etc. so it must be correct. * src/place.c (meta_window_place): if a transient is placed and its parent has focus, focus the transient. 2001-09-06 Havoc Pennington <hp@pobox.com> * configure.in: bump version 2.3.5, require newer GTK release 2001-09-04 Havoc Pennington <hp@pobox.com> * src/wm-tester/Makefile.am (noinst_PROGRAMS): make test apps noinst * src/metacity.desktop: for the capplet * src/Makefile.am: add .desktop file 2001-09-01 Havoc Pennington <hp@pobox.com> * src/errors.c: clean up the code, and replace GDK X error handler with one that chains up to GDK but first logs the error to logfile. 2001-08-31 Havoc Pennington <hp@pobox.com> * src/tabpopup.c (meta_ui_tab_popup_new): fix args to gtk_alignment_new() 2001-08-29 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): avoid focusing a window on tab popup popdown * src/screen.c (meta_screen_ensure_tab_popup): compute frame outline size here 2001-08-29 Havoc Pennington <hp@redhat.com> * src/tabpopup.c: Switch back to outline. 2001-08-29 Havoc Pennington <hp@pobox.com> * src/tabpopup.c: experiment with window-cover-with-icon instead of just the outline; can't decide. 2001-08-29 Havoc Pennington <hp@pobox.com> * src/tabpopup.c: add crackrock window-outlining feature * src/session.c (window_type_to_string): handle fullscreen 2001-08-29 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_open): wrong atom name - _NET_SUPPORTED not _NET_WM_SUPPORTED * src/window.c (meta_window_configure_request): geez, why were we honoring configure requests for width/height for normal windows. Denied! (meta_window_client_message): _NET_WM_MOVERESIZE support, sort of (doesn't quite work, acts like owner_events = true?) * src/display.c: add _NET_WM_MOVERESIZE atom 2001-08-28 Havoc Pennington <hp@pobox.com> Unbreak tab popup a bit. * src/stack.c (meta_stack_get_tab_list): add workspace argument (meta_stack_get_tab_next): add workspace argument * src/window.c: implement recording of the last user-initiated window position, so we can magically handle moving panels around really nicely. * src/wm-tester/main.c (set_up_icon_windows): fix to use new GTK API 2001-08-24 Havoc Pennington <hp@pobox.com> * src/window.c (constrain_position): force fullscreen windows to be at 0,0 * src/ui.c: use NULL colormap to get bitmaps, requires very latest GTK from CVS or it will spew warnings and not work. * src/window.c (constrain_size): disallow larger than screen in all cases, even if user has performed a resize operation. (constrain_position): keep window boxed onscreen. * src/keybindings.c (meta_display_process_key_event): revert an earlier change that disabled global keybindings when a grab is in effect; instead, only disable global keybindings if a _keyboard_ grab is in effect. The earlier change was just a broken workaround, the problems it fixed should have been solved by the addition of XGrabKeyboard() on the metacity keyboard grabs. This should fix the problem with pick-up-window-and-move-to-another-desktop. 2001-08-23 Havoc Pennington <hp@pobox.com> * src/window.c (update_icon): attempt to use the mask as well as the pixmap. Probably doesn't work so well. * src/tabpopup.c: make this look a little nicer 2001-08-22 Havoc Pennington <hp@pobox.com> * src/window.c (update_mwm_hints): all the MWM flag tests were backward 2001-08-22 Havoc Pennington <hp@pobox.com> * src/window.c (update_icon): half-ass implementation of getting pixmap icons (WM_NORMAL_HINTS and KWM_WIN_ICON). Ignores mask for now, with possibly ugly results for some apps. (read_rgb_icon): fixage 2001-08-19 Havoc Pennington <hp@pobox.com> * src/window.c: add a "fullscreen" semantic type; if a window requests the screen size exactly, and is undecorated, and is not a desktop window, we consider it a fullscreen window and keep it on top. Totally untested. 2001-08-19 Havoc Pennington <hp@pobox.com> * src/screen.c (set_supported_hint): we support _NET_WM_ICON * src/wm-tester/main.c: add stuff to test _NET_WM_ICON (but it doesn't work, so it isn't tested yet) * src/window.c (update_icon): read _NET_WM_ICON * src/screen.c (meta_screen_new): set the WM_ICON_SIZE hint * src/tabpopup.c (meta_ui_tab_popup_select): remove assertion * src/window.c (meta_window_get_icon_geometry): fix obscure memleak 2001-08-19 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_grab_window_buttons): remove XSync, error traps already do that (meta_display_grab_window_buttons): implement * src/keybindings.c: src/display.c: wire up the tab window, it rulez! 2001-08-19 Havoc Pennington <hp@pobox.com> * src/tabpopup.c: add prototype thingy to display windows we're cycling through with tab. Not wired up to keybindings yet. 2001-08-18 Havoc Pennington <hp@pobox.com> * src/effects.c (meta_effects_draw_box_animation): put an XFlush() right after starting things moving 2001-08-18 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_configure_request): (meta_window_move_resize_internal): Make a half-hearted not-very-tested attempt to handle window resizes correctly with respect to window gravity. 2001-08-18 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_get_gravity_position): hrm, I fixed this wrong the other day. Fixes static gravity when moving windows. 2001-08-18 Havoc Pennington <hp@pobox.com> * src/ui.c (meta_image_window_set_position): also set the current size. Lame hack of the day. * src/effects.c (effects_draw_box_animation_timeout): use the delay exposes feature to avoid the screen dirt * src/ui.c (meta_ui_push_delay_exposes): (meta_ui_pop_delay_exposes): feature to let us delay redraws until after we do server-grabbed draw-on-inferiors effects 2001-08-17 Havoc Pennington <hp@redhat.com> * src/window.c (meta_window_get_gravity_position): fix for StaticGravity 2001-08-09 Havoc Pennington <hp@pobox.com> * src/window.c (meta_window_configure_request): Honor USPosition even post-map. I know I'll regret this. 2001-08-07 Havoc Pennington <hp@pobox.com> * src/display.c (meta_display_open): set _NET_WM_NAME hint as a UTF8_STRING not STRING. Patch from Anders. 2001-08-06 Havoc Pennington <hp@redhat.com> * src/effects.c: disable opaque animations by default, current implementation suXors. 2001-08-06 Havoc Pennington <hp@pobox.com> * src/effects.c (meta_effects_draw_box_animation): Get start time after we do the pixbuf from drawable, so we don't count time spent getting pixbuf from drawable in the animation time. 2001-08-06 Havoc Pennington <hp@pobox.com> * src/effects.c: add opaque minimize/shade feature. The wireframe seemed kind of confusing and unclear from a UI standpoint. I know, I know. The bloat begins here. Also, we don't need to grab the server during opaque min/shade, which has some nice implications. * src/ui.c: Add features to render a window with an image in it, and also wrap pixbuf_from_drawable * src/effects.c (meta_effects_draw_box_animation): modify to be smoother (at least theoretically) by syncing to current time and "dropping frames" as appropriate. * src/window.c (meta_window_shade): draw animation for shading too 2001-08-05 Anders Carlsson <andersca@gnu.org> * src/display.h, src/display.c: Add _NET_WM_ICON_GEOMETRY atom. * src/window.c (meta_window_calc_showing): See if the window has an icon geometry and show a morphing animation from the window's coordinates to the icon's coordinates. (meta_window_get_icon_geometry): New function that fetches a window's icon geometry. * src/Makefile.am: Add effects.[ch]. * src/effects.c: New file with cool effects. 2001-08-03 Havoc Pennington <hp@pobox.com> * src/keybindings.c: Add Alt + left/right arrow to move between workspaces. * src/screen.c (set_wm_check_hint): put property pointing back to itself on the _WIN_SUPPORTING_WM_CHECK window. 2001-08-03 Havoc Pennington <hp@pobox.com> * src/display.c (event_callback): push error trap around configure of withdrawn window, fixes a crash caused by rapidly creating/destroying a window. * src/window.c (recalc_window_features): don't allow shading undecorated windows. * src/wm-tester/main.c: add a program to torture window managers. 2001-08-01 Havoc Pennington <hp@pobox.com> * src/window.c (recalc_window_features): if a window isn't resizeable, turn off maximize function. If min size is equal to max size, turn off resize function. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/AUTHORS��������������������������������������������������������������������������������0000664�0001750�0001750�00000000041�14211404421�014177� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Havoc Pennington <hp@redhat.com> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/�������������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�014616� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/Makefile.am��������������������������������������������������������������������0000664�0001750�0001750�00000003142�14211404421�016652� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������NULL = SUBDIRS = build clutter tests if BUILD_EXAMPLES SUBDIRS += examples endif DIST_SUBDIRS = clutter tests examples build # XXX - this is a massive hack to make autoreconf honour the ACLOCAL_FLAGS # that jhbuild sets while still retaining build/autotools as the authoritative # source for m4 macros ACLOCAL_AMFLAGS = -I build/autotools ${ACLOCAL_FLAGS} CLEANFILES = $(pcfiles) DISTCLEANFILES = DISTCHECK_CONFIGURE_FLAGS = --enable-maintainer-flags # proxy rules for tests test-report full-report: $(MAKE) -C tests/conform $(@) perf-report: $(MAKE) -C tests/performance $(@) if ENABLE_GCOV # use recursive makes in order to ignore errors during check/perf lcov: -$(MAKE) $(AM_MAKEFLAGS) -C clutter check -$(MAKE) $(AM_MAKEFLAGS) -C tests/conform test $(MAKE) $(AM_MAKEFLAGS) genlcov # we have to massage the lcov.info file slightly to hide the effect of libtool # placing the objects files in the .libs/ directory separate from the *.c genlcov: $(LTP) --directory $(top_builddir) --capture --output-file clutter-lcov.info --test-name CLUTTER_TEST --no-checksum $(SED) -e 's#.libs/##' < clutter-lcov.info > clutter-lcov.info.tmp LANG=C $(LTP_GENHTML) --prefix $(top_builddir) --output-directory clutter-lcov --title "Clutter Code Coverage" --show-details clutter-lcov.info.tmp rm -f clutter-lcov.info.tmp lcov-clean: -$(LTP) --directory $(top_builddir) -z -$(RM) -rf clutter-lcov.info clutter-lcov else lcov genlcov lcov-clean: @echo You need to configure Clutter with support for gcov enabled. @echo e.g., ./configure --enable-gcov endif .PHONY: test-report full-report perf-report lcov genlcov lcov-clean ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/����������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�016434� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/pan-action.c����������������������������������������������������������0000664�0001750�0001750�00000013765�14211404421�020645� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gdk-pixbuf/gdk-pixbuf.h> #include <clutter/clutter.h> #ifdef CLUTTER_WINDOWING_X11 #include <clutter/x11/clutter-x11.h> #endif static ClutterActor * create_content_actor (void) { ClutterActor *content; ClutterContent *image; GdkPixbuf *pixbuf; content = clutter_actor_new (); clutter_actor_set_size (content, 720, 720); pixbuf = gdk_pixbuf_new_from_file ("redhand.png", NULL); image = clutter_image_new (); clutter_image_set_data (CLUTTER_IMAGE (image), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_has_alpha (pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), NULL); g_object_unref (pixbuf); clutter_actor_set_content_scaling_filters (content, CLUTTER_SCALING_FILTER_TRILINEAR, CLUTTER_SCALING_FILTER_LINEAR); clutter_actor_set_content_gravity (content, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT); clutter_actor_set_content (content, image); g_object_unref (image); return content; } static gboolean on_pan (ClutterPanAction *action, ClutterActor *scroll, gboolean is_interpolated, gpointer *user_data) { gfloat delta_x, delta_y; const ClutterEvent *event = NULL; if (is_interpolated) clutter_pan_action_get_interpolated_delta (action, &delta_x, &delta_y); else { clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (action), 0, &delta_x, &delta_y); event = clutter_gesture_action_get_last_event (CLUTTER_GESTURE_ACTION (action), 0); } g_print ("[%s] panning dx:%.2f dy:%.2f\n", event == NULL ? "INTERPOLATED" : event->type == CLUTTER_MOTION ? "MOTION" : event->type == CLUTTER_TOUCH_UPDATE ? "TOUCH UPDATE" : "?", delta_x, delta_y); return TRUE; } static ClutterActor * create_scroll_actor (ClutterActor *stage) { ClutterActor *scroll; ClutterAction *pan_action; /* our scrollable viewport */ scroll = clutter_actor_new (); clutter_actor_set_name (scroll, "scroll"); clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0)); clutter_actor_add_constraint (scroll, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0)); clutter_actor_add_child (scroll, create_content_actor ()); pan_action = clutter_pan_action_new (); clutter_pan_action_set_interpolate (CLUTTER_PAN_ACTION (pan_action), TRUE); g_signal_connect (pan_action, "pan", G_CALLBACK (on_pan), NULL); clutter_actor_add_action_with_name (scroll, "pan", pan_action); clutter_actor_set_reactive (scroll, TRUE); return scroll; } static gboolean on_key_press (ClutterActor *stage, ClutterEvent *event, gpointer unused) { ClutterActor *scroll; guint key_symbol; scroll = clutter_actor_get_first_child (stage); key_symbol = clutter_event_get_key_symbol (event); if (key_symbol == CLUTTER_KEY_space) { clutter_actor_save_easing_state (scroll); clutter_actor_set_easing_duration (scroll, 1000); clutter_actor_set_child_transform (scroll, NULL); clutter_actor_restore_easing_state (scroll); } return CLUTTER_EVENT_STOP; } static gboolean label_clicked_cb (ClutterText *label, ClutterEvent *event, ClutterActor *scroll) { ClutterPanAction *action = CLUTTER_PAN_ACTION (clutter_actor_get_action (scroll, "pan")); const gchar *label_text = clutter_text_get_text (label); if (g_str_equal (label_text, "X AXIS")) clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_X_AXIS); else if (g_str_equal (label_text, "Y AXIS")) clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_Y_AXIS); else if (g_str_equal (label_text, "AUTO")) clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_AXIS_AUTO); else clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_AXIS_NONE); return TRUE; } static void add_label (const gchar *text, ClutterActor *box, ClutterActor *scroll) { ClutterActor *label; label = clutter_text_new_with_text (NULL, text); clutter_actor_set_reactive (label, TRUE); clutter_actor_set_x_align (label, CLUTTER_ACTOR_ALIGN_START); clutter_actor_set_x_expand (label, TRUE); clutter_actor_add_child (box, label); g_signal_connect (label, "button-release-event", G_CALLBACK (label_clicked_cb), scroll); } int main (int argc, char *argv[]) { ClutterActor *stage, *scroll, *box, *info; ClutterLayoutManager *layout; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; /* create a new stage */ stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Pan Action"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); scroll = create_scroll_actor (stage); clutter_actor_add_child (stage, scroll); box = clutter_actor_new (); clutter_actor_add_child (stage, box); clutter_actor_set_position (box, 12, 12); layout = clutter_box_layout_new (); clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout), CLUTTER_ORIENTATION_VERTICAL); clutter_actor_set_layout_manager (box, layout); info = clutter_text_new_with_text (NULL, "Press <space> to reset the image position."); clutter_actor_add_child (box, info); info = clutter_text_new_with_text (NULL, "Click labels below to change AXIS pinning."); clutter_actor_add_child (box, info); add_label ("NONE", box, scroll); add_label ("X AXIS", box, scroll); add_label ("Y AXIS", box, scroll); add_label ("AUTO", box, scroll); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), scroll); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } �����������muffin-5.2.1/clutter/examples/Makefile.am�����������������������������������������������������������0000664�0001750�0001750�00000001354�14211404421�020473� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������all_examples = \ actor-model \ basic-actor \ box-layout \ canvas \ constraints \ drag-action \ drop-action \ easing-modes \ flow-layout \ grid-layout \ layout-manager \ pan-action \ rounded-rectangle \ scroll-actor \ threads if PIXBUF_TESTS all_examples += \ bin-layout \ image-content endif LDADD = $(top_builddir)/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la $(CLUTTER_LIBS) $(GDK_PIXBUF_LIBS) $(LIBM) AM_CFLAGS = $(CLUTTER_CFLAGS) $(GDK_PIXBUF_CFLAGS) $(MAINTAINER_CFLAGS) AM_CPPFLAGS = \ -DG_DISABLE_SINGLE_INCLUDES \ -DGLIB_DISABLE_DEPRECATION_WARNINGS \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(top_srcdir)/clutter \ -I$(top_builddir)/clutter noinst_PROGRAMS = $(all_examples) EXTRA_DIST = redhand.png ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/flow-layout.c���������������������������������������������������������0000664�0001750�0001750�00000010161�14211404421�021061� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <cairo.h> #include <clutter/clutter.h> #define N_RECTS 20 static gboolean is_homogeneous = FALSE; static gboolean vertical = FALSE; static gboolean random_size = FALSE; static gboolean fixed_size = FALSE; static gboolean snap_to_grid = TRUE; static gint n_rects = N_RECTS; static gint x_spacing = 0; static gint y_spacing = 0; static GOptionEntry entries[] = { { "random-size", 'r', 0, G_OPTION_ARG_NONE, &random_size, "Randomly size the rectangles", NULL }, { "num-rects", 'n', 0, G_OPTION_ARG_INT, &n_rects, "Number of rectangles", "RECTS" }, { "vertical", 'v', 0, G_OPTION_ARG_NONE, &vertical, "Set vertical orientation", NULL }, { "homogeneous", 'h', 0, G_OPTION_ARG_NONE, &is_homogeneous, "Whether the layout should be homogeneous", NULL }, { "x-spacing", 0, 0, G_OPTION_ARG_INT, &x_spacing, "Horizontal spacing between elements", "PX" }, { "y-spacing", 0, 0, G_OPTION_ARG_INT, &y_spacing, "Vertical spacing between elements", "PX" }, { "fixed-size", 'f', 0, G_OPTION_ARG_NONE, &fixed_size, "Fix the layout size", NULL }, { "no-snap-to-grid", 's', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &snap_to_grid, "Don't snap elements to grid", NULL }, { NULL } }; int main (int argc, char *argv[]) { ClutterActor *stage, *box; ClutterLayoutManager *layout; GError *error; gint i; error = NULL; if (clutter_init_with_args (&argc, &argv, NULL, entries, NULL, &error) != CLUTTER_INIT_SUCCESS) { g_print ("Unable to run flow-layout: %s", error->message); g_error_free (error); return EXIT_FAILURE; } stage = clutter_stage_new (); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); clutter_stage_set_title (CLUTTER_STAGE (stage), "Flow Layout"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); layout = clutter_flow_layout_new (vertical ? CLUTTER_FLOW_VERTICAL : CLUTTER_FLOW_HORIZONTAL); clutter_flow_layout_set_homogeneous (CLUTTER_FLOW_LAYOUT (layout), is_homogeneous); clutter_flow_layout_set_column_spacing (CLUTTER_FLOW_LAYOUT (layout), x_spacing); clutter_flow_layout_set_row_spacing (CLUTTER_FLOW_LAYOUT (layout), y_spacing); clutter_flow_layout_set_snap_to_grid (CLUTTER_FLOW_LAYOUT (layout), snap_to_grid); box = clutter_actor_new (); clutter_actor_set_layout_manager (box, layout); clutter_actor_set_background_color (box, CLUTTER_COLOR_Aluminium2); clutter_actor_add_child (stage, box); if (!fixed_size) clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0)); clutter_actor_set_position (box, 0, 0); clutter_actor_set_name (box, "box"); for (i = 0; i < n_rects; i++) { ClutterColor color = CLUTTER_COLOR_INIT (255, 255, 255, 255); gfloat width, height; ClutterActor *rect; gchar *name; name = g_strdup_printf ("rect%02d", i); clutter_color_from_hls (&color, 360.0 / n_rects * i, 0.5, 0.8); rect = clutter_actor_new (); clutter_actor_set_background_color (rect, &color); if (random_size) { width = g_random_int_range (50, 100); height = g_random_int_range (50, 100); } else width = height = 50.f; clutter_actor_set_size (rect, width, height); clutter_actor_set_name (rect, name); clutter_actor_add_child (box, rect); free (name); } clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/basic-actor.c���������������������������������������������������������0000664�0001750�0001750�00000011563�14211404421�020775� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> #define SIZE 128 static gboolean animate_color (ClutterActor *actor, ClutterEvent *event) { static gboolean toggled = TRUE; const ClutterColor *end_color; if (toggled) end_color = CLUTTER_COLOR_Blue; else end_color = CLUTTER_COLOR_Red; clutter_actor_save_easing_state (actor); clutter_actor_set_easing_duration (actor, 500); clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR); clutter_actor_set_background_color (actor, end_color); clutter_actor_restore_easing_state (actor); toggled = !toggled; return CLUTTER_EVENT_STOP; } static gboolean on_crossing (ClutterActor *actor, ClutterEvent *event) { gboolean is_enter = clutter_event_type (event) == CLUTTER_ENTER; float zpos; if (is_enter) zpos = -250.0; else zpos = 0.0; clutter_actor_save_easing_state (actor); clutter_actor_set_easing_duration (actor, 500); clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_BOUNCE); clutter_actor_set_z_position (actor, zpos); clutter_actor_restore_easing_state (actor); return CLUTTER_EVENT_STOP; } static void on_transition_stopped (ClutterActor *actor, const gchar *transition_name, gboolean is_finished) { clutter_actor_save_easing_state (actor); clutter_actor_set_rotation_angle (actor, CLUTTER_Y_AXIS, 0.0f); clutter_actor_restore_easing_state (actor); /* disconnect so we don't get multiple notifications */ g_signal_handlers_disconnect_by_func (actor, on_transition_stopped, NULL); } static gboolean animate_rotation (ClutterActor *actor, ClutterEvent *event) { clutter_actor_save_easing_state (actor); clutter_actor_set_easing_duration (actor, 1000); clutter_actor_set_rotation_angle (actor, CLUTTER_Y_AXIS, 360.0); clutter_actor_restore_easing_state (actor); /* get a notification when the rotation-angle-y transition ends */ g_signal_connect (actor, "transition-stopped::rotation-angle-y", G_CALLBACK (on_transition_stopped), NULL); return CLUTTER_EVENT_STOP; } int main (int argc, char *argv[]) { ClutterActor *stage, *vase; ClutterActor *flowers[3]; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_stage_set_title (CLUTTER_STAGE (stage), "Three Flowers in a Vase"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); /* there are three flowers in a vase */ vase = clutter_actor_new (); clutter_actor_set_name (vase, "vase"); clutter_actor_set_layout_manager (vase, clutter_box_layout_new ()); clutter_actor_set_background_color (vase, CLUTTER_COLOR_LightSkyBlue); clutter_actor_add_constraint (vase, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_add_child (stage, vase); flowers[0] = clutter_actor_new (); clutter_actor_set_name (flowers[0], "flower.1"); clutter_actor_set_size (flowers[0], SIZE, SIZE); clutter_actor_set_margin_left (flowers[0], 12); clutter_actor_set_background_color (flowers[0], CLUTTER_COLOR_Red); clutter_actor_set_reactive (flowers[0], TRUE); clutter_actor_add_child (vase, flowers[0]); g_signal_connect (flowers[0], "button-press-event", G_CALLBACK (animate_color), NULL); flowers[1] = clutter_actor_new (); clutter_actor_set_name (flowers[1], "flower.2"); clutter_actor_set_size (flowers[1], SIZE, SIZE); clutter_actor_set_margin_top (flowers[1], 12); clutter_actor_set_margin_left (flowers[1], 6); clutter_actor_set_margin_right (flowers[1], 6); clutter_actor_set_margin_bottom (flowers[1], 12); clutter_actor_set_background_color (flowers[1], CLUTTER_COLOR_Yellow); clutter_actor_set_reactive (flowers[1], TRUE); clutter_actor_add_child (vase, flowers[1]); g_signal_connect (flowers[1], "enter-event", G_CALLBACK (on_crossing), NULL); g_signal_connect (flowers[1], "leave-event", G_CALLBACK (on_crossing), NULL); /* the third one is green */ flowers[2] = clutter_actor_new (); clutter_actor_set_name (flowers[2], "flower.3"); clutter_actor_set_size (flowers[2], SIZE, SIZE); clutter_actor_set_margin_right (flowers[2], 12); clutter_actor_set_background_color (flowers[2], CLUTTER_COLOR_Green); clutter_actor_set_pivot_point (flowers[2], 0.5f, 0.0f); clutter_actor_set_reactive (flowers[2], TRUE); clutter_actor_add_child (vase, flowers[2]); g_signal_connect (flowers[2], "button-press-event", G_CALLBACK (animate_rotation), NULL); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/box-layout.c����������������������������������������������������������0000664�0001750�0001750�00000021553�14211404421�020711� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright 2009 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * Boston, MA 02111-1307, USA. * */ #include <stdlib.h> #include <clutter/clutter.h> #define INSTRUCTIONS \ "Press v\t\342\236\236\tSwitch horizontal/vertical\n" \ "Press h\t\342\236\236\tToggle homogeneous\n" \ "Press p\t\342\236\236\tToggle pack start/end\n" \ "Press s\t\342\236\236\tIncrement spacing (up to 12px)\n" \ "Press +\t\342\236\236\tAdd a new actor\n" \ "Press a\t\342\236\236\tToggle animations\n" \ "Press q\t\342\236\236\tQuit" static const gchar * get_align_name (ClutterActorAlign align) { switch (align) { case CLUTTER_ACTOR_ALIGN_FILL: return "fill"; case CLUTTER_ACTOR_ALIGN_START: return "start"; case CLUTTER_ACTOR_ALIGN_CENTER: return "center"; case CLUTTER_ACTOR_ALIGN_END: return "end"; default: g_assert_not_reached (); } } static gboolean button_release_cb (ClutterActor *rect, ClutterEvent *event, gpointer user_data) { ClutterActorAlign x_align, y_align; gboolean x_expand, y_expand; g_object_get (rect, "x-align", &x_align, "y-align", &y_align, "x-expand", &x_expand, "y-expand", &y_expand, NULL); switch (clutter_event_get_button (event)) { case CLUTTER_BUTTON_PRIMARY: if (clutter_event_has_shift_modifier (event)) { if (y_align < 3) y_align += 1; else y_align = 0; break; } else { if (x_align < 3) x_align += 1; else x_align = 0; } break; case CLUTTER_BUTTON_SECONDARY: if (clutter_event_has_shift_modifier (event)) y_expand = !y_expand; else x_expand = !x_expand; break; default: break; } g_object_set (rect, "x-align", x_align, "y-align", y_align, "x-expand", x_expand, "y-expand", y_expand, NULL); return TRUE; } static void changed_cb (ClutterActor *actor, GParamSpec *pspec, ClutterActor *text) { ClutterActorAlign x_align, y_align; gboolean x_expand, y_expand; gchar *label; g_object_get (actor, "x-align", &x_align, "y-align", &y_align, "x-expand", &x_expand, "y-expand", &y_expand, NULL); label = g_strdup_printf ("%d,%d\n" "%s\n%s", x_expand, y_expand, get_align_name (x_align), get_align_name (y_align)); clutter_text_set_text (CLUTTER_TEXT (text), label); free (label); } static void add_actor (ClutterActor *box, gint position) { ClutterActor *rect, *text; ClutterColor color; ClutterLayoutManager *layout; clutter_color_from_hls (&color, g_random_double_range (0.0, 360.0), 0.5, 0.5); color.alpha = 255; layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_CENTER); rect = clutter_actor_new (); clutter_actor_set_layout_manager (rect, layout); clutter_actor_set_background_color (rect, &color); clutter_actor_set_reactive (rect, TRUE); clutter_actor_set_size (rect, 32, 64); clutter_actor_set_x_expand (rect, TRUE); clutter_actor_set_y_expand (rect, TRUE); clutter_actor_set_x_align (rect, CLUTTER_ACTOR_ALIGN_CENTER); clutter_actor_set_y_align (rect, CLUTTER_ACTOR_ALIGN_CENTER); text = clutter_text_new_with_text ("Sans 8px", NULL); clutter_text_set_line_alignment (CLUTTER_TEXT (text), PANGO_ALIGN_CENTER); clutter_actor_add_child (rect, text); g_signal_connect (rect, "button-release-event", G_CALLBACK (button_release_cb), NULL); g_signal_connect (rect, "notify::x-expand", G_CALLBACK (changed_cb), text); g_signal_connect (rect, "notify::y-expand", G_CALLBACK (changed_cb), text); g_signal_connect (rect, "notify::x-align", G_CALLBACK (changed_cb), text); g_signal_connect (rect, "notify::y-align", G_CALLBACK (changed_cb), text); changed_cb (rect, NULL, text); clutter_actor_insert_child_at_index (box, rect, position); } static gboolean key_release_cb (ClutterActor *stage, ClutterEvent *event, ClutterActor *box) { ClutterBoxLayout *layout; gboolean toggle; guint spacing; layout = CLUTTER_BOX_LAYOUT (clutter_actor_get_layout_manager (box)); switch (clutter_event_get_key_symbol (event)) { case CLUTTER_KEY_a: { ClutterActorIter iter; ClutterActor *child; clutter_actor_iter_init (&iter, box); while (clutter_actor_iter_next (&iter, &child)) { guint duration; duration = clutter_actor_get_easing_duration (child); if (duration != 0) duration = 0; else duration = 250; clutter_actor_set_easing_duration (child, duration); } } break; case CLUTTER_KEY_v: { ClutterOrientation orientation; orientation = clutter_box_layout_get_orientation (layout); if (orientation == CLUTTER_ORIENTATION_HORIZONTAL) orientation = CLUTTER_ORIENTATION_VERTICAL; else orientation = CLUTTER_ORIENTATION_HORIZONTAL; clutter_box_layout_set_orientation (layout, orientation); } break; case CLUTTER_KEY_h: toggle = clutter_box_layout_get_homogeneous (layout); clutter_box_layout_set_homogeneous (layout, !toggle); break; case CLUTTER_KEY_p: toggle = clutter_box_layout_get_pack_start (layout); clutter_box_layout_set_pack_start (layout, !toggle); break; case CLUTTER_KEY_s: spacing = clutter_box_layout_get_spacing (layout); if (spacing > 12) spacing = 0; else spacing++; clutter_box_layout_set_spacing (layout, spacing); break; case CLUTTER_KEY_plus: add_actor (box, g_random_int_range (0, clutter_actor_get_n_children (box))); break; case CLUTTER_KEY_q: clutter_main_quit (); break; default: return FALSE; } return TRUE; } int main (int argc, char *argv[]) { ClutterActor *stage, *box, *instructions; ClutterLayoutManager *layout; gint i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Box Layout"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); /* make the stage a vbox */ layout = clutter_box_layout_new (); clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout), CLUTTER_ORIENTATION_VERTICAL); clutter_actor_set_layout_manager (stage, layout); box = clutter_actor_new (); clutter_actor_set_background_color (box, CLUTTER_COLOR_LightGray); clutter_actor_set_x_expand (box, TRUE); clutter_actor_set_y_expand (box, TRUE); layout = clutter_box_layout_new (); clutter_actor_set_layout_manager (box, layout); clutter_actor_add_child (stage, box); instructions = clutter_text_new_with_text ("Sans 12px", INSTRUCTIONS); clutter_actor_set_x_expand (instructions, TRUE); clutter_actor_set_y_expand (instructions, FALSE); clutter_actor_set_x_align (instructions, CLUTTER_ACTOR_ALIGN_START); clutter_actor_set_margin_top (instructions, 4); clutter_actor_set_margin_left (instructions, 4); clutter_actor_set_margin_bottom (instructions, 4); clutter_actor_add_child (stage, instructions); for (i = 0; i < 5; i++) add_actor (box, i); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "key-release-event", G_CALLBACK (key_release_cb), box); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/layout-manager.c������������������������������������������������������0000664�0001750�0001750�00000031743�14211404421�021535� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <math.h> #include <stdlib.h> #include <clutter/clutter.h> typedef struct _MultiLayout MultiLayout; typedef struct _MultiLayoutClass MultiLayoutClass; typedef enum { MULTI_LAYOUT_GRID, MULTI_LAYOUT_CIRCLE } MultiLayoutState; struct _MultiLayout { ClutterLayoutManager parent_instance; /* the state of the layout */ MultiLayoutState state; /* spacing between children */ float spacing; /* cell size */ float cell_width; float cell_height; }; struct _MultiLayoutClass { ClutterLayoutManagerClass parent_class; }; GType multi_layout_get_type (void); ClutterLayoutManager * multi_layout_new (void); void multi_layout_set_state (MultiLayout *layout, MultiLayoutState state); MultiLayoutState multi_layout_get_state (MultiLayout *layout); void multi_layout_set_spacing (MultiLayout *layout, float spacing); G_DEFINE_TYPE (MultiLayout, multi_layout, CLUTTER_TYPE_LAYOUT_MANAGER) static void multi_layout_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, float for_height, float *min_width_p, float *nat_width_p) { MultiLayout *self = (MultiLayout *) manager; float minimum, natural; float max_natural_width; ClutterActorIter iter; ClutterActor *child; int n_children; minimum = natural = 0.f; max_natural_width = 0.f; n_children = 0; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container)); while (clutter_actor_iter_next (&iter, &child)) { float child_minimum, child_natural; if (!clutter_actor_is_visible (child)) continue; clutter_actor_get_preferred_width (child, -1.f, &child_minimum, &child_natural); max_natural_width = MAX (max_natural_width, child_natural); if (self->state == MULTI_LAYOUT_GRID) { minimum += child_minimum; natural += child_natural; } else if (self->state == MULTI_LAYOUT_CIRCLE) { minimum = MAX (minimum, child_minimum); natural = MAX (natural, child_natural); } n_children += 1; } self->cell_width = max_natural_width; minimum += (self->spacing * (n_children - 1)); natural += (self->spacing * (n_children - 1)); if (min_width_p != NULL) *min_width_p = minimum; if (nat_width_p != NULL) *nat_width_p = natural; } static void multi_layout_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, float for_width, float *min_height_p, float *nat_height_p) { MultiLayout *self = (MultiLayout *) manager; float minimum, natural; ClutterActorIter iter; ClutterActor *child; int n_children; minimum = natural = self->spacing * 2.f; n_children = 0; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container)); while (clutter_actor_iter_next (&iter, &child)) { float child_minimum, child_natural; if (!clutter_actor_is_visible (child)) continue; clutter_actor_get_preferred_height (child, -1.f, &child_minimum, &child_natural); minimum = MAX (minimum, child_minimum); natural = MAX (natural, child_natural); n_children += 1; } self->cell_height = natural; minimum += (self->spacing * (n_children - 1)); natural += (self->spacing * (n_children - 1)); if (min_height_p != NULL) *min_height_p = minimum; if (nat_height_p != NULL) *nat_height_p = natural; } static int get_items_per_row (MultiLayout *self, float for_width) { int n_columns; if (for_width < 0) return 1; if (self->cell_width <= 0) return 1; n_columns = (int) ((for_width + self->spacing) / (self->cell_width + self->spacing)); return MAX (n_columns, 1); } static int get_visible_children (ClutterActor *actor) { ClutterActorIter iter; ClutterActor *child; int n_visible_children = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { if (clutter_actor_is_visible (child)) n_visible_children += 1; } return n_visible_children; } static void multi_layout_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { MultiLayout *self = (MultiLayout *) manager; float avail_width, avail_height; float x_offset, y_offset; ClutterActorIter iter; ClutterActor *child; float item_x = 0.f, item_y = 0.f; int n_items, n_items_per_row = 0, item_index; ClutterPoint center = CLUTTER_POINT_INIT_ZERO; double radius = 0, theta = 0; n_items = get_visible_children (CLUTTER_ACTOR (container)); if (n_items == 0) return; clutter_actor_box_get_origin (allocation, &x_offset, &y_offset); clutter_actor_box_get_size (allocation, &avail_width, &avail_height); /* ensure we have an updated value of cell_width and cell_height */ multi_layout_get_preferred_width (manager, container, avail_width, NULL, NULL); multi_layout_get_preferred_height (manager, container, avail_height, NULL, NULL); item_index = 0; if (self->state == MULTI_LAYOUT_GRID) { n_items_per_row = get_items_per_row (self, avail_width); item_x = x_offset; item_y = y_offset; } else if (self->state == MULTI_LAYOUT_CIRCLE) { center.x = allocation->x2 / 2.f; center.y = allocation->y2 / 2.f; radius = MIN ((avail_width - self->cell_width) / 2.0, (avail_height - self->cell_height) / 2.0); } clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container)); while (clutter_actor_iter_next (&iter, &child)) { ClutterActorBox child_allocation = CLUTTER_ACTOR_BOX_INIT_ZERO; if (!clutter_actor_is_visible (child)) continue; if (self->state == MULTI_LAYOUT_GRID) { if (item_index == n_items_per_row) { item_index = 0; item_x = x_offset; item_y += self->cell_height + self->spacing; } child_allocation.x1 = item_x; child_allocation.y1 = item_y; child_allocation.x2 = child_allocation.x1 + self->cell_width; child_allocation.y2 = child_allocation.y1 + self->cell_height; item_x += self->cell_width + self->spacing; } else if (self->state == MULTI_LAYOUT_CIRCLE) { theta = 2.0 * G_PI / n_items * item_index; child_allocation.x1 = center.x + radius * sinf (theta) - (self->cell_width / 2.f); child_allocation.y1 = center.y + radius * -cosf (theta) - (self->cell_height / 2.f); child_allocation.x2 = child_allocation.x1 + self->cell_width; child_allocation.y2 = child_allocation.y1 + self->cell_height; } clutter_actor_allocate (child, &child_allocation, flags); item_index += 1; } } static void multi_layout_class_init (MultiLayoutClass *klass) { ClutterLayoutManagerClass *manager_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass); manager_class->get_preferred_width = multi_layout_get_preferred_width; manager_class->get_preferred_height = multi_layout_get_preferred_height; manager_class->allocate = multi_layout_allocate; } static void multi_layout_init (MultiLayout *self) { self->state = MULTI_LAYOUT_GRID; self->cell_width = -1.f; self->cell_height = -1.f; self->spacing = 0.f; } ClutterLayoutManager * multi_layout_new (void) { return g_object_new (multi_layout_get_type (), NULL); } void multi_layout_set_state (MultiLayout *self, MultiLayoutState state) { if (self->state == state) return; self->state = state; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (self)); } MultiLayoutState multi_layout_get_state (MultiLayout *self) { return self->state; } void multi_layout_set_spacing (MultiLayout *self, float spacing) { self->spacing = spacing; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (self)); } #define N_RECTS 16 #define RECT_SIZE 64.0 #define N_ROWS 4 #define PADDING 12.0 #define BOX_SIZE (RECT_SIZE * (N_RECTS / N_ROWS) + PADDING * (N_RECTS / N_ROWS - 1)) static gboolean on_enter (ClutterActor *rect, ClutterEvent *event) { clutter_actor_set_scale (rect, 1.2, 1.2); return CLUTTER_EVENT_STOP; } static gboolean on_leave (ClutterActor *rect, ClutterEvent *event) { clutter_actor_set_scale (rect, 1.0, 1.0); return CLUTTER_EVENT_STOP; } static gboolean on_key_press (ClutterActor *stage, ClutterEvent *event, ClutterActor *box) { guint keysym = clutter_event_get_key_symbol (event); MultiLayout *layout = (MultiLayout *) clutter_actor_get_layout_manager (box); switch (keysym) { case CLUTTER_KEY_q: clutter_main_quit (); break; case CLUTTER_KEY_t: { MultiLayoutState state = multi_layout_get_state (layout); if (state == MULTI_LAYOUT_GRID) multi_layout_set_state (layout, MULTI_LAYOUT_CIRCLE); if (state == MULTI_LAYOUT_CIRCLE) multi_layout_set_state (layout, MULTI_LAYOUT_GRID); } break; default: break; } return CLUTTER_EVENT_STOP; } int main (int argc, char *argv[]) { ClutterActor *stage, *box, *label; ClutterLayoutManager *manager; ClutterMargin margin; ClutterTransition *transition; int i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Multi-layout"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_actor_show (stage); /* the layout manager for the main container */ manager = multi_layout_new (); multi_layout_set_spacing ((MultiLayout *) manager, PADDING); margin.top = margin.bottom = margin.left = margin.right = PADDING; /* our main container, centered on the stage */ box = clutter_actor_new (); clutter_actor_set_margin (box, &margin); clutter_actor_set_layout_manager (box, manager); clutter_actor_set_size (box, BOX_SIZE, BOX_SIZE); clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_add_child (stage, box); for (i = 0; i < N_RECTS; i++) { ClutterActor *rect = clutter_actor_new (); ClutterColor color; clutter_color_from_hls (&color, 360.0 / N_RECTS * i, 0.5, 0.8); color.alpha = 128 + 128 / N_RECTS * i; /* elements on the layout */ clutter_actor_set_size (rect, RECT_SIZE, RECT_SIZE); clutter_actor_set_pivot_point (rect, .5f, .5f); clutter_actor_set_background_color (rect, &color); clutter_actor_set_opacity (rect, 0); clutter_actor_set_reactive (rect, TRUE); /* explicit transition that fades in the element; the delay on * the transition staggers the fade depending on the index */ transition = clutter_property_transition_new ("opacity"); clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 250); clutter_timeline_set_delay (CLUTTER_TIMELINE (transition), i * 50); clutter_transition_set_from (transition, G_TYPE_UINT, 0); clutter_transition_set_to (transition, G_TYPE_UINT, 255); clutter_actor_add_transition (rect, "fadeIn", transition); g_object_unref (transition); /* we want all state transitions to be animated */ clutter_actor_set_easing_duration (rect, 250); clutter_actor_set_easing_mode (rect, CLUTTER_EASE_OUT_CUBIC); clutter_actor_add_child (box, rect); /* simple hover effect */ g_signal_connect (rect, "enter-event", G_CALLBACK (on_enter), NULL); g_signal_connect (rect, "leave-event", G_CALLBACK (on_leave), NULL); } label = clutter_text_new (); clutter_text_set_text (CLUTTER_TEXT (label), "Press t\t\342\236\236\tToggle layout\n" "Press q\t\342\236\236\tQuit"); clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5)); clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.95)); clutter_actor_add_child (stage, label); g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), box); clutter_main (); return EXIT_SUCCESS; } �����������������������������muffin-5.2.1/clutter/examples/easing-modes.c��������������������������������������������������������0000664�0001750�0001750�00000017167�14211404421�021167� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> /* all the easing modes provided by Clutter */ static const struct { const gchar *name; ClutterAnimationMode mode; } easing_modes[] = { { "linear", CLUTTER_LINEAR }, { "easeInQuad", CLUTTER_EASE_IN_QUAD }, { "easeOutQuad", CLUTTER_EASE_OUT_QUAD }, { "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD }, { "easeInCubic", CLUTTER_EASE_IN_CUBIC }, { "easeOutCubic", CLUTTER_EASE_OUT_CUBIC }, { "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC }, { "easeInQuart", CLUTTER_EASE_IN_QUART }, { "easeOutQuart", CLUTTER_EASE_OUT_QUART }, { "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART }, { "easeInQuint", CLUTTER_EASE_IN_QUINT }, { "easeOutQuint", CLUTTER_EASE_OUT_QUINT }, { "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT }, { "easeInSine", CLUTTER_EASE_IN_SINE }, { "easeOutSine", CLUTTER_EASE_OUT_SINE }, { "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE }, { "easeInExpo", CLUTTER_EASE_IN_EXPO }, { "easeOutExpo", CLUTTER_EASE_OUT_EXPO }, { "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO }, { "easeInCirc", CLUTTER_EASE_IN_CIRC }, { "easeOutCirc", CLUTTER_EASE_OUT_CIRC }, { "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC }, { "easeInElastic", CLUTTER_EASE_IN_ELASTIC }, { "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC }, { "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC }, { "easeInBack", CLUTTER_EASE_IN_BACK }, { "easeOutBack", CLUTTER_EASE_OUT_BACK }, { "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK }, { "easeInBounce", CLUTTER_EASE_IN_BOUNCE }, { "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE }, { "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE }, { "stepStart", CLUTTER_STEP_START }, { "stepEnd", CLUTTER_STEP_END }, { "ease", CLUTTER_EASE }, { "easeIn", CLUTTER_EASE_IN }, { "easeOut", CLUTTER_EASE_OUT }, { "easeInOut", CLUTTER_EASE_IN_OUT }, }; #define HELP_TEXT "<b>Easing mode: %s (%d of %d)</b>\n" \ "Left click to tween\n" \ "Middle click to jump\n" \ "Right click to change the easing mode" static const gint n_easing_modes = G_N_ELEMENTS (easing_modes); static gint current_mode = 0; static gint duration = 1; static ClutterActor *main_stage = NULL; static ClutterActor *easing_mode_label = NULL; static gboolean on_button_press (ClutterActor *actor, ClutterButtonEvent *event, ClutterActor *rectangle) { if (event->button == CLUTTER_BUTTON_SECONDARY) { gchar *text; /* cycle through the various easing modes */ current_mode = (current_mode + 1 < n_easing_modes) ? current_mode + 1 : 0; /* update the text of the label */ text = g_strdup_printf (HELP_TEXT, easing_modes[current_mode].name, current_mode + 1, n_easing_modes); clutter_text_set_markup (CLUTTER_TEXT (easing_mode_label), text); free (text); } else if (event->button == CLUTTER_BUTTON_MIDDLE) { clutter_actor_set_position (rectangle, event->x, event->y); } else if (event->button == CLUTTER_BUTTON_PRIMARY) { ClutterAnimationMode cur_mode; cur_mode = easing_modes[current_mode].mode; clutter_actor_save_easing_state (rectangle); /* tween the actor using the current easing mode */ clutter_actor_set_easing_mode (rectangle, cur_mode); clutter_actor_set_easing_duration (rectangle, duration * 1000); clutter_actor_set_position (rectangle, event->x, event->y); clutter_actor_restore_easing_state (rectangle); } return CLUTTER_EVENT_STOP; } static gboolean draw_bouncer (ClutterCanvas *canvas, cairo_t *cr, int width, int height) { const ClutterColor *bouncer_color; cairo_pattern_t *pattern; float radius; cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); radius = MAX (width, height); cairo_arc (cr, radius / 2, radius / 2, radius / 2, 0.0, 2.0 * G_PI); bouncer_color = CLUTTER_COLOR_DarkScarletRed; pattern = cairo_pattern_create_radial (radius / 2, radius / 2, 0, radius, radius, radius); cairo_pattern_add_color_stop_rgba (pattern, 0, bouncer_color->red / 255.0, bouncer_color->green / 255.0, bouncer_color->blue / 255.0, bouncer_color->alpha / 255.0); cairo_pattern_add_color_stop_rgba (pattern, 0.85, bouncer_color->red / 255.0, bouncer_color->green / 255.0, bouncer_color->blue / 255.0, 0.25); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); return TRUE; } static ClutterActor * make_bouncer (gfloat width, gfloat height) { ClutterActor *retval; ClutterContent *canvas; retval = clutter_actor_new (); canvas = clutter_canvas_new (); g_signal_connect (canvas, "draw", G_CALLBACK (draw_bouncer), NULL); clutter_canvas_set_size (CLUTTER_CANVAS (canvas), width, height); clutter_actor_set_name (retval, "bouncer"); clutter_actor_set_size (retval, width, height); clutter_actor_set_pivot_point (retval, 0.5f, 0.5f); clutter_actor_set_translation (retval, width / -2.f, height / -2.f, 0.f); clutter_actor_set_reactive (retval, TRUE); clutter_actor_set_content (retval, canvas); g_object_unref (canvas); return retval; } static GOptionEntry test_easing_entries[] = { { "duration", 'd', 0, G_OPTION_ARG_INT, &duration, "Duration of the animation", "SECONDS" }, { NULL } }; int main (int argc, char *argv[]) { ClutterActor *stage, *rect, *label; gchar *text; gfloat stage_width, stage_height; GError *error = NULL; if (clutter_init_with_args (&argc, &argv, NULL, test_easing_entries, NULL, &error) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Easing Modes"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); main_stage = stage; clutter_actor_get_size (stage, &stage_width, &stage_height); /* create the actor that we want to tween */ rect = make_bouncer (50, 50); clutter_actor_add_child (stage, rect); clutter_actor_set_position (rect, stage_width / 2, stage_height / 2); text = g_strdup_printf (HELP_TEXT, easing_modes[current_mode].name, current_mode + 1, n_easing_modes); label = clutter_text_new (); clutter_actor_add_child (stage, label); clutter_text_set_markup (CLUTTER_TEXT (label), text); clutter_text_set_line_alignment (CLUTTER_TEXT (label), PANGO_ALIGN_RIGHT); clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.95)); clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.95)); easing_mode_label = label; free (text); g_signal_connect (stage, "button-press-event", G_CALLBACK (on_button_press), rect); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/drag-action.c���������������������������������������������������������0000664�0001750�0001750�00000016604�14211404421�020777� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> static gboolean on_enter (ClutterActor *actor, ClutterEvent *event) { ClutterTransition *t; t = clutter_actor_get_transition (actor, "curl"); if (t == NULL) { t = clutter_property_transition_new ("@effects.curl.period"); clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250); clutter_actor_add_transition (actor, "curl", t); g_object_unref (t); } clutter_transition_set_from (t, G_TYPE_DOUBLE, 0.0); clutter_transition_set_to (t, G_TYPE_DOUBLE, 0.25); clutter_timeline_rewind (CLUTTER_TIMELINE (t)); clutter_timeline_start (CLUTTER_TIMELINE (t)); return CLUTTER_EVENT_STOP; } static gboolean on_leave (ClutterActor *actor, ClutterEvent *event) { ClutterTransition *t; t = clutter_actor_get_transition (actor, "curl"); if (t == NULL) { t = clutter_property_transition_new ("@effects.curl.period"); clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250); clutter_actor_add_transition (actor, "curl", t); g_object_unref (t); } clutter_transition_set_from (t, G_TYPE_DOUBLE, 0.25); clutter_transition_set_to (t, G_TYPE_DOUBLE, 0.0); clutter_timeline_rewind (CLUTTER_TIMELINE (t)); clutter_timeline_start (CLUTTER_TIMELINE (t)); return CLUTTER_EVENT_STOP; } static void on_drag_begin (ClutterDragAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y, ClutterModifierType modifiers) { gboolean is_copy = (modifiers & CLUTTER_SHIFT_MASK) ? TRUE : FALSE; ClutterActor *drag_handle = NULL; ClutterTransition *t; if (is_copy) { ClutterActor *stage = clutter_actor_get_stage (actor); drag_handle = clutter_actor_new (); clutter_actor_set_size (drag_handle, 48, 48); clutter_actor_set_background_color (drag_handle, CLUTTER_COLOR_DarkSkyBlue); clutter_actor_add_child (stage, drag_handle); clutter_actor_set_position (drag_handle, event_x, event_y); } else drag_handle = actor; clutter_drag_action_set_drag_handle (action, drag_handle); /* fully desaturate the actor */ t = clutter_actor_get_transition (actor, "disable"); if (t == NULL) { t = clutter_property_transition_new ("@effects.disable.factor"); clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250); clutter_actor_add_transition (actor, "disable", t); g_object_unref (t); } clutter_transition_set_from (t, G_TYPE_DOUBLE, 0.0); clutter_transition_set_to (t, G_TYPE_DOUBLE, 1.0); clutter_timeline_rewind (CLUTTER_TIMELINE (t)); clutter_timeline_start (CLUTTER_TIMELINE (t)); } static void on_drag_end (ClutterDragAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y, ClutterModifierType modifiers) { ClutterActor *drag_handle; ClutterTransition *t; drag_handle = clutter_drag_action_get_drag_handle (action); if (actor != drag_handle) { gfloat real_x, real_y; ClutterActor *parent; /* if we are dragging a copy we can destroy the copy now * and animate the real actor to the drop coordinates, * transformed in the parent's coordinate space */ clutter_actor_save_easing_state (drag_handle); clutter_actor_set_easing_mode (drag_handle, CLUTTER_LINEAR); clutter_actor_set_opacity (drag_handle, 0); clutter_actor_restore_easing_state (drag_handle); g_signal_connect (drag_handle, "transitions-completed", G_CALLBACK (clutter_actor_destroy), NULL); parent = clutter_actor_get_parent (actor); clutter_actor_transform_stage_point (parent, event_x, event_y, &real_x, &real_y); clutter_actor_save_easing_state (actor); clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC); clutter_actor_set_position (actor, real_x, real_y); clutter_actor_restore_easing_state (actor); } t = clutter_actor_get_transition (actor, "disable"); if (t == NULL) { t = clutter_property_transition_new ("@effects.disable.factor"); clutter_timeline_set_duration (CLUTTER_TIMELINE (t), 250); clutter_actor_add_transition (actor, "disable", t); g_object_unref (t); } clutter_transition_set_from (t, G_TYPE_DOUBLE, 1.0); clutter_transition_set_to (t, G_TYPE_DOUBLE, 0.0); clutter_timeline_rewind (CLUTTER_TIMELINE (t)); clutter_timeline_start (CLUTTER_TIMELINE (t)); } static ClutterDragAxis get_drag_axis (const gchar *str) { if (str == NULL || *str == '\0') return CLUTTER_DRAG_AXIS_NONE; if (*str == 'x' || *str == 'X') return CLUTTER_DRAG_X_AXIS; if (*str == 'y' || *str == 'Y') return CLUTTER_DRAG_Y_AXIS; g_warn_if_reached (); return CLUTTER_DRAG_AXIS_NONE; } static gchar *drag_axis = NULL; static gint x_drag_threshold = 0; static gint y_drag_threshold = 0; static GOptionEntry entries[] = { { "x-threshold", 'x', 0, G_OPTION_ARG_INT, &x_drag_threshold, "Set the horizontal drag threshold", "PIXELS" }, { "y-threshold", 'y', 0, G_OPTION_ARG_INT, &y_drag_threshold, "Set the vertical drag threshold", "PIXELS" }, { "axis", 'a', 0, G_OPTION_ARG_STRING, &drag_axis, "Set the drag axis", "AXIS" }, { NULL } }; int main (int argc, char *argv[]) { ClutterActor *stage, *handle; ClutterAction *action; GError *error; error = NULL; if (clutter_init_with_args (&argc, &argv, "test-drag", entries, NULL, &error) != CLUTTER_INIT_SUCCESS) { g_print ("Unable to run drag-action: %s\n", error->message); g_error_free (error); return EXIT_FAILURE; } stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Drag Test"); clutter_actor_set_size (stage, 800, 600); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); handle = clutter_actor_new (); clutter_actor_set_background_color (handle, CLUTTER_COLOR_SkyBlue); clutter_actor_set_size (handle, 128, 128); clutter_actor_set_position (handle, (800 - 128) / 2, (600 - 128) / 2); clutter_actor_set_reactive (handle, TRUE); clutter_actor_add_child (stage, handle); g_signal_connect (handle, "enter-event", G_CALLBACK (on_enter), NULL); g_signal_connect (handle, "leave-event", G_CALLBACK (on_leave), NULL); action = clutter_drag_action_new (); clutter_drag_action_set_drag_threshold (CLUTTER_DRAG_ACTION (action), x_drag_threshold, y_drag_threshold); clutter_drag_action_set_drag_axis (CLUTTER_DRAG_ACTION (action), get_drag_axis (drag_axis)); g_signal_connect (action, "drag-begin", G_CALLBACK (on_drag_begin), NULL); g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL); clutter_actor_add_action (handle, action); clutter_actor_add_effect_with_name (handle, "disable", clutter_desaturate_effect_new (0.0)); clutter_actor_add_effect_with_name (handle, "curl", clutter_page_turn_effect_new (0.0, 45.0, 12.0)); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/grid-layout.c���������������������������������������������������������0000664�0001750�0001750�00000025740�14211404421�021050� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright 2012 Bastian Winkler <buz@netbuz.org> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * Boston, MA 02111-1307, USA. * */ #include <stdlib.h> #include <clutter/clutter.h> #define INSTRUCTIONS \ "Press r\t\342\236\236\tSwitch row homogeneous\n" \ "Press c\t\342\236\236\tSwitch column homogeneous\n" \ "Press s\t\342\236\236\tIncrement spacing (up to 12px)\n" \ "Press q\t\342\236\236\tQuit\n\n" \ "Left/right click\t\t\342\236\236\tChange actor align\n" \ "Shift left/right click\t\342\236\236\tChange actor expand" static gboolean random_size = FALSE; static gboolean random_align = FALSE; static gboolean default_expand = TRUE; static gboolean use_box = FALSE; static gboolean is_vertical = FALSE; static GOptionEntry entries[] = { { "random-size", 'r', 0, G_OPTION_ARG_NONE, &random_size, "Randomly size the rectangles", NULL }, { "random-align", 'f', 0, G_OPTION_ARG_NONE, &random_align, "Randomly set the align values", NULL }, { "no-expand", 'e', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &default_expand, "Don't expand all actors by default", NULL, }, { "box", 'b', 0, G_OPTION_ARG_NONE, &use_box, "Use the layout in a ClutterBoxLayout style", NULL }, { "vertical", 'v', 0, G_OPTION_ARG_NONE, &is_vertical, "Use a vertical orientation when used with --box", NULL }, { NULL } }; static gboolean button_release_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterActorAlign x_align, y_align; gboolean x_expand, y_expand; g_object_get (actor, "x-align", &x_align, "y-align", &y_align, "x-expand", &x_expand, "y-expand", &y_expand, NULL); switch (clutter_event_get_button (event)) { case CLUTTER_BUTTON_PRIMARY: if (clutter_event_has_shift_modifier (event)) x_expand = !x_expand; else { if (x_align < 3) x_align += 1; else x_align = 0; } break; case CLUTTER_BUTTON_SECONDARY: if (clutter_event_has_shift_modifier (event)) y_expand = !y_expand; else { if (y_align < 3) y_align += 1; else y_align = 0; } break; default: return FALSE; } g_object_set (actor, "x-align", x_align, "y-align", y_align, "x-expand", x_expand, "y-expand", y_expand, NULL); return TRUE; } static const gchar * get_align_name (ClutterActorAlign align) { switch (align) { case CLUTTER_ACTOR_ALIGN_FILL: return "fill"; case CLUTTER_ACTOR_ALIGN_START: return "start"; case CLUTTER_ACTOR_ALIGN_CENTER: return "center"; case CLUTTER_ACTOR_ALIGN_END: return "end"; default: g_assert_not_reached (); } } static void changed_cb (ClutterActor *actor, GParamSpec *pspec, ClutterActor *text) { ClutterActorAlign x_align, y_align; ClutterActor *box; ClutterLayoutManager *layout; ClutterLayoutMeta *meta; gboolean x_expand, y_expand; gchar *label; gint left, top, width, height; box = clutter_actor_get_parent (actor); layout = clutter_actor_get_layout_manager (box); meta = clutter_layout_manager_get_child_meta (layout, CLUTTER_CONTAINER (box), actor); g_object_get (actor, "x-align", &x_align, "y-align", &y_align, "x-expand", &x_expand, "y-expand", &y_expand, NULL); g_object_get (meta, "left-attach", &left, "top-attach", &top, "width", &width, "height", &height, NULL); label = g_strdup_printf ("attach: %d,%d\n" "span: %d,%d\n" "expand: %d,%d\n" "align: %s,%s", left, top, width, height, x_expand, y_expand, get_align_name (x_align), get_align_name (y_align)); clutter_text_set_text (CLUTTER_TEXT (text), label); free (label); } static void add_actor (ClutterActor *box, gint left, gint top, gint width, gint height) { ClutterActor *rect, *text; ClutterColor color; ClutterLayoutManager *layout; clutter_color_from_hls (&color, g_random_double_range (0.0, 360.0), 0.5, 0.5); color.alpha = 255; layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_CENTER); rect = clutter_actor_new (); clutter_actor_set_layout_manager (rect, layout); clutter_actor_set_background_color (rect, &color); clutter_actor_set_reactive (rect, TRUE); if (random_size) clutter_actor_set_size (rect, g_random_int_range (40, 80), g_random_int_range (40, 80)); else clutter_actor_set_size (rect, 60, 60); clutter_actor_set_x_expand (rect, default_expand); clutter_actor_set_y_expand (rect, default_expand); if (!default_expand) { clutter_actor_set_x_align (rect, CLUTTER_ACTOR_ALIGN_CENTER); clutter_actor_set_y_align (rect, CLUTTER_ACTOR_ALIGN_CENTER); } if (random_align) { clutter_actor_set_x_align (rect, g_random_int_range (0, 3)); clutter_actor_set_y_align (rect, g_random_int_range (0, 3)); } text = clutter_text_new_with_text ("Sans 8px", NULL); clutter_text_set_line_alignment (CLUTTER_TEXT (text), PANGO_ALIGN_CENTER); clutter_actor_add_child (rect, text); g_signal_connect (rect, "button-release-event", G_CALLBACK (button_release_cb), NULL); g_signal_connect (rect, "notify::x-expand", G_CALLBACK (changed_cb), text); g_signal_connect (rect, "notify::y-expand", G_CALLBACK (changed_cb), text); g_signal_connect (rect, "notify::x-align", G_CALLBACK (changed_cb), text); g_signal_connect (rect, "notify::y-align", G_CALLBACK (changed_cb), text); layout = clutter_actor_get_layout_manager (box); if (use_box) clutter_actor_add_child (box, rect); else clutter_grid_layout_attach (CLUTTER_GRID_LAYOUT (layout), rect, left, top, width, height); changed_cb (rect, NULL, text); } static gboolean key_release_cb (ClutterActor *stage, ClutterEvent *event, ClutterActor *box) { ClutterGridLayout *layout; gboolean toggle; guint spacing; layout = CLUTTER_GRID_LAYOUT (clutter_actor_get_layout_manager (box)); switch (clutter_event_get_key_symbol (event)) { case CLUTTER_KEY_c: toggle = clutter_grid_layout_get_column_homogeneous (layout); clutter_grid_layout_set_column_homogeneous (layout, !toggle); break; case CLUTTER_KEY_r: toggle = clutter_grid_layout_get_row_homogeneous (layout); clutter_grid_layout_set_row_homogeneous (layout, !toggle); break; case CLUTTER_KEY_s: spacing = clutter_grid_layout_get_column_spacing (layout); if (spacing < 12) spacing += 1; else spacing = 0; clutter_grid_layout_set_column_spacing (layout, spacing); clutter_grid_layout_set_row_spacing (layout, spacing); break; case CLUTTER_KEY_q: clutter_main_quit (); break; default: return FALSE; } return TRUE; } int main (int argc, char *argv[]) { ClutterActor *stage, *box, *instructions; ClutterLayoutManager *stage_layout, *grid_layout; GError *error = NULL; if (clutter_init_with_args (&argc, &argv, NULL, entries, NULL, &error) != CLUTTER_INIT_SUCCESS) { g_print ("Unable to run grid-layout: %s", error->message); g_error_free (error); return EXIT_FAILURE; } stage = clutter_stage_new (); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); stage_layout = clutter_box_layout_new (); clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (stage_layout), CLUTTER_ORIENTATION_VERTICAL); clutter_actor_set_layout_manager (stage, stage_layout); grid_layout = clutter_grid_layout_new (); if (is_vertical) clutter_grid_layout_set_orientation (CLUTTER_GRID_LAYOUT (grid_layout), CLUTTER_ORIENTATION_VERTICAL); box = clutter_actor_new (); clutter_actor_set_background_color (box, CLUTTER_COLOR_LightGray); clutter_actor_set_x_expand (box, TRUE); clutter_actor_set_y_expand (box, TRUE); clutter_actor_set_layout_manager (box, grid_layout); clutter_box_layout_pack (CLUTTER_BOX_LAYOUT (stage_layout), box, TRUE, TRUE, TRUE, CLUTTER_BOX_ALIGNMENT_CENTER, CLUTTER_BOX_ALIGNMENT_CENTER); add_actor (box, 0, 0, 1, 1); add_actor (box, 1, 0, 1, 1); add_actor (box, 2, 0, 1, 1); add_actor (box, 0, 1, 1, 1); add_actor (box, 1, 1, 2, 1); add_actor (box, 0, 2, 3, 1); add_actor (box, 0, 3, 2, 2); add_actor (box, 2, 3, 1, 1); add_actor (box, 2, 4, 1, 1); instructions = clutter_text_new_with_text ("Sans 12px", INSTRUCTIONS); clutter_actor_set_margin_top (instructions, 4); clutter_actor_set_margin_left (instructions, 4); clutter_actor_set_margin_bottom (instructions, 4); clutter_box_layout_pack (CLUTTER_BOX_LAYOUT (stage_layout), instructions, FALSE, TRUE, FALSE, CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_CENTER); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "key-release-event", G_CALLBACK (key_release_cb), box); clutter_actor_show (stage); clutter_main (); return 0; } ��������������������������������muffin-5.2.1/clutter/examples/actor-model.c���������������������������������������������������������0000664�0001750�0001750�00000036021�14211404421�021010� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib-object.h> #include <gio/gio.h> #include <clutter/clutter.h> /* {{{ MenuItemModel */ /* This is our "model" of a Menu item; it has a "label" property, and * a "selected" state property. The user is supposed to operate on the * model instance, and change its state. */ #define EXAMPLE_TYPE_MENU_ITEM_MODEL (example_menu_item_model_get_type ()) G_DECLARE_FINAL_TYPE (ExampleMenuItemModel, example_menu_item_model, EXAMPLE, MENU_ITEM_MODEL, GObject) struct _ExampleMenuItemModel { GObject parent_instance; char *label; gboolean selected; }; struct _ExampleMenuItemModelClass { GObjectClass parent_class; }; enum { MENU_ITEM_MODEL_PROP_LABEL = 1, MENU_ITEM_MODEL_PROP_SELECTED, MENU_ITEM_MODEL_N_PROPS }; static GParamSpec *menu_item_model_props[MENU_ITEM_MODEL_N_PROPS] = { NULL, }; G_DEFINE_TYPE (ExampleMenuItemModel, example_menu_item_model, G_TYPE_OBJECT) static void example_menu_item_model_finalize (GObject *gobject) { ExampleMenuItemModel *self = (ExampleMenuItemModel *) gobject; free (self->label); G_OBJECT_CLASS (example_menu_item_model_parent_class)->finalize (gobject); } static void example_menu_item_model_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ExampleMenuItemModel *self = (ExampleMenuItemModel *) gobject; switch (prop_id) { case MENU_ITEM_MODEL_PROP_LABEL: free (self->label); self->label = g_value_dup_string (value); break; case MENU_ITEM_MODEL_PROP_SELECTED: self->selected = g_value_get_boolean (value); break; } } static void example_menu_item_model_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ExampleMenuItemModel *self = (ExampleMenuItemModel *) gobject; switch (prop_id) { case MENU_ITEM_MODEL_PROP_LABEL: g_value_set_string (value, self->label); break; case MENU_ITEM_MODEL_PROP_SELECTED: g_value_set_boolean (value, self->selected); break; } } static void example_menu_item_model_class_init (ExampleMenuItemModelClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = example_menu_item_model_set_property; gobject_class->get_property = example_menu_item_model_get_property; gobject_class->finalize = example_menu_item_model_finalize; menu_item_model_props[MENU_ITEM_MODEL_PROP_LABEL] = g_param_spec_string ("label", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); menu_item_model_props[MENU_ITEM_MODEL_PROP_SELECTED] = g_param_spec_boolean ("selected", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, MENU_ITEM_MODEL_N_PROPS, menu_item_model_props); } static void example_menu_item_model_init (ExampleMenuItemModel *self) { } /* }}} */ /* {{{ MenuItemView */ /* This is our "view" of a Menu item; it changes state depending on whether * the "selected" property is set. The "view" reflects the state of the * "model" instance, though it has no direct connection to it. */ #define EXAMPLE_TYPE_MENU_ITEM_VIEW (example_menu_item_view_get_type ()) G_DECLARE_FINAL_TYPE (ExampleMenuItemView, example_menu_item_view, EXAMPLE, MENU_ITEM_VIEW, ClutterText) struct _ExampleMenuItemView { ClutterText parent_instance; gboolean is_selected; }; struct _ExampleMenuItemViewClass { ClutterTextClass parent_class; }; G_DEFINE_TYPE (ExampleMenuItemView, example_menu_item_view, CLUTTER_TYPE_TEXT) enum { MENU_ITEM_VIEW_PROP_SELECTED = 1, MENU_ITEM_VIEW_N_PROPS }; static GParamSpec *menu_item_view_props[MENU_ITEM_VIEW_N_PROPS] = { NULL, }; static void example_menu_item_view_set_selected (ExampleMenuItemView *self, gboolean selected) { selected = !!selected; if (self->is_selected == selected) return; self->is_selected = selected; if (self->is_selected) clutter_text_set_color (CLUTTER_TEXT (self), CLUTTER_COLOR_LightSkyBlue); else clutter_text_set_color (CLUTTER_TEXT (self), CLUTTER_COLOR_White); g_object_notify_by_pspec (G_OBJECT (self), menu_item_view_props[MENU_ITEM_VIEW_PROP_SELECTED]); } static void example_menu_item_view_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case MENU_ITEM_VIEW_PROP_SELECTED: example_menu_item_view_set_selected (EXAMPLE_MENU_ITEM_VIEW (gobject), g_value_get_boolean (value)); break; } } static void example_menu_item_view_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case MENU_ITEM_VIEW_PROP_SELECTED: g_value_set_boolean (value, EXAMPLE_MENU_ITEM_VIEW (gobject)->is_selected); break; } } static void example_menu_item_view_class_init (ExampleMenuItemViewClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = example_menu_item_view_set_property; gobject_class->get_property = example_menu_item_view_get_property; menu_item_view_props[MENU_ITEM_VIEW_PROP_SELECTED] = g_param_spec_boolean ("selected", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, MENU_ITEM_VIEW_N_PROPS, menu_item_view_props); } static void example_menu_item_view__transition_stopped (ClutterActor *actor, const char *transition, gboolean is_finished) { clutter_actor_set_scale (actor, 1.0, 1.0); clutter_actor_set_opacity (actor, 255); } static void example_menu_item_view_init (ExampleMenuItemView *self) { ClutterText *text = CLUTTER_TEXT (self); ClutterActor *actor = CLUTTER_ACTOR (self); ClutterTransition *scalex_trans, *scaley_trans, *fade_trans; ClutterTransition *group; clutter_text_set_font_name (text, "Sans Bold 24px"); clutter_text_set_color (text, CLUTTER_COLOR_White); clutter_actor_set_margin_left (actor, 12); clutter_actor_set_margin_right (actor, 12); clutter_actor_set_pivot_point (actor, 0.5, 0.5); scalex_trans = clutter_property_transition_new ("scale-x"); clutter_transition_set_from (scalex_trans, G_TYPE_FLOAT, 1.0); clutter_transition_set_to (scalex_trans, G_TYPE_FLOAT, 3.0); scaley_trans = clutter_property_transition_new ("scale-y"); clutter_transition_set_from (scaley_trans, G_TYPE_FLOAT, 1.0); clutter_transition_set_to (scaley_trans, G_TYPE_FLOAT, 3.0); fade_trans = clutter_property_transition_new ("opacity"); clutter_transition_set_to (fade_trans, G_TYPE_UINT, 0); group = clutter_transition_group_new (); clutter_transition_group_add_transition (CLUTTER_TRANSITION_GROUP (group), scalex_trans); clutter_transition_group_add_transition (CLUTTER_TRANSITION_GROUP (group), scaley_trans); clutter_transition_group_add_transition (CLUTTER_TRANSITION_GROUP (group), fade_trans); clutter_timeline_set_duration (CLUTTER_TIMELINE (group), 250); clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (group), CLUTTER_EASE_OUT); clutter_actor_add_transition (actor, "activateTransition", group); g_object_unref (group); clutter_timeline_stop (CLUTTER_TIMELINE (group)); g_signal_connect (actor, "transition-stopped", G_CALLBACK (example_menu_item_view__transition_stopped), group); } static void example_menu_item_view_activate (ExampleMenuItemView *self) { ClutterTransition *t; t = clutter_actor_get_transition (CLUTTER_ACTOR (self), "activateTransition"); clutter_timeline_start (CLUTTER_TIMELINE (t)); } /* }}} */ /* {{{ Menu */ /* This is our container actor, which binds the GListStore with the * ExampleMenuItemModel instances to the ExampleMenuItemView actors */ #define EXAMPLE_TYPE_MENU (example_menu_get_type ()) G_DECLARE_FINAL_TYPE (ExampleMenu, example_menu, EXAMPLE, MENU, ClutterActor) struct _ExampleMenu { ClutterActor parent_instance; int current_idx; }; struct _ExampleMenuClass { ClutterActorClass parent_class; }; G_DEFINE_TYPE (ExampleMenu, example_menu, CLUTTER_TYPE_ACTOR) static void example_menu_class_init (ExampleMenuClass *klass) { } static void example_menu_init (ExampleMenu *self) { ClutterActor *actor = CLUTTER_ACTOR (self); ClutterLayoutManager *layout; layout = clutter_box_layout_new (); clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout), CLUTTER_ORIENTATION_VERTICAL); clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout), 12); clutter_actor_set_layout_manager (actor, layout); clutter_actor_set_background_color (actor, CLUTTER_COLOR_Black); self->current_idx = -1; } static ClutterActor * example_menu_select_item (ExampleMenu *self, int idx) { ClutterActor *item; /* Any change in the view is reflected into the model */ if (idx == self->current_idx) return clutter_actor_get_child_at_index (CLUTTER_ACTOR (self), self->current_idx); item = clutter_actor_get_child_at_index (CLUTTER_ACTOR (self), self->current_idx); if (item != NULL) example_menu_item_view_set_selected ((ExampleMenuItemView *) item, FALSE); if (idx < 0) idx = clutter_actor_get_n_children (CLUTTER_ACTOR (self)) - 1; else if (idx >= clutter_actor_get_n_children (CLUTTER_ACTOR (self))) idx = 0; self->current_idx = idx; item = clutter_actor_get_child_at_index (CLUTTER_ACTOR (self), self->current_idx); if (item != NULL) example_menu_item_view_set_selected ((ExampleMenuItemView *) item, TRUE); return item; } static ClutterActor * example_menu_select_next (ExampleMenu *self) { return example_menu_select_item (self, self->current_idx + 1); } static ClutterActor * example_menu_select_prev (ExampleMenu *self) { return example_menu_select_item (self, self->current_idx - 1); } static void example_menu_activate_item (ExampleMenu *self) { ClutterActor *child; child = clutter_actor_get_child_at_index (CLUTTER_ACTOR (self), self->current_idx); if (child == NULL) return; example_menu_item_view_activate ((ExampleMenuItemView *) child); } /* }}} */ /* {{{ main */ static gboolean on_key_press (ClutterActor *stage, ClutterEvent *event) { ClutterActor *scroll = clutter_actor_get_first_child (stage); ClutterActor *menu = clutter_actor_get_first_child (scroll); ClutterActor *item = NULL; guint key = clutter_event_get_key_symbol (event); ClutterPoint p; switch (key) { case CLUTTER_KEY_q: clutter_main_quit (); break; case CLUTTER_KEY_Up: item = example_menu_select_prev ((ExampleMenu *) menu); clutter_actor_get_position (item, &p.x, &p.y); break; case CLUTTER_KEY_Down: item = example_menu_select_next ((ExampleMenu *) menu); clutter_actor_get_position (item, &p.x, &p.y); break; case CLUTTER_KEY_Return: case CLUTTER_KEY_KP_Enter: example_menu_activate_item ((ExampleMenu *) menu); break; } if (item != NULL) clutter_scroll_actor_scroll_to_point (CLUTTER_SCROLL_ACTOR (scroll), &p); return CLUTTER_EVENT_PROPAGATE; } static void on_model_item_selection (GObject *model_item, GParamSpec *pspec, gpointer data) { char *label = NULL; gboolean is_selected = FALSE; g_object_get (model_item, "label", &label, "selected", &is_selected, NULL); if (is_selected) g_print ("Item '%s' selected!\n", label); free (label); } static ClutterActor * create_menu_actor (void) { /* Our store of menu item models */ GListStore *model = g_list_store_new (EXAMPLE_TYPE_MENU_ITEM_MODEL); ClutterActor *menu = g_object_new (EXAMPLE_TYPE_MENU, NULL); int i; /* Populate the model */ for (i = 0; i < 12; i++) { char *label = g_strdup_printf ("Option %02d", i + 1); ExampleMenuItemModel *item = g_object_new (EXAMPLE_TYPE_MENU_ITEM_MODEL, "label", label, NULL); g_list_store_append (model, item); g_signal_connect (item, "notify::selected", G_CALLBACK (on_model_item_selection), NULL); g_object_unref (item); free (label); } /* Bind the list of menu item models to the menu actor; this will * create ClutterActor views of each item in the model, and add them * to the menu actor */ clutter_actor_bind_model_with_properties (menu, G_LIST_MODEL (model), EXAMPLE_TYPE_MENU_ITEM_VIEW, "label", "text", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE, "selected", "selected", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, NULL); /* We don't need a pointer to the model any more, so we transfer ownership * to the menu actor; this means that the model will go away when the menu * actor is destroyed */ g_object_unref (model); /* Select the first item in the menu */ example_menu_select_item ((ExampleMenu *) menu, 0); return menu; } /* The scrolling container for the menu */ static ClutterActor * create_scroll_actor (void) { ClutterActor *menu = clutter_scroll_actor_new (); clutter_actor_set_name (menu, "scroll"); clutter_scroll_actor_set_scroll_mode (CLUTTER_SCROLL_ACTOR (menu), CLUTTER_SCROLL_VERTICALLY); clutter_actor_set_easing_duration (menu, 250); clutter_actor_add_child (menu, create_menu_actor ()); return menu; } int main (int argc, char *argv[]) { ClutterActor *stage, *menu; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Actor Model"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), NULL); clutter_actor_show (stage); #define PADDING 18.f menu = create_scroll_actor (); clutter_actor_set_position (menu, 0, PADDING); clutter_actor_add_constraint (menu, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5)); clutter_actor_add_constraint (menu, clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, -PADDING * 2)); clutter_actor_add_child (stage, menu); clutter_main (); return 0; } /* }}} */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/image-content.c�������������������������������������������������������0000664�0001750�0001750�00000007024�14211404421�021335� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gdk-pixbuf/gdk-pixbuf.h> #include <clutter/clutter.h> static const struct { ClutterContentGravity gravity; const char *name; } gravities[] = { { CLUTTER_CONTENT_GRAVITY_TOP_LEFT, "Top Left" }, { CLUTTER_CONTENT_GRAVITY_TOP, "Top" }, { CLUTTER_CONTENT_GRAVITY_TOP_RIGHT, "Top Right" }, { CLUTTER_CONTENT_GRAVITY_LEFT, "Left" }, { CLUTTER_CONTENT_GRAVITY_CENTER, "Center" }, { CLUTTER_CONTENT_GRAVITY_RIGHT, "Right" }, { CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT, "Bottom Left" }, { CLUTTER_CONTENT_GRAVITY_BOTTOM, "Bottom" }, { CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT, "Bottom Right" }, { CLUTTER_CONTENT_GRAVITY_RESIZE_FILL, "Resize Fill" }, { CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT, "Resize Aspect" }, }; static int n_gravities = G_N_ELEMENTS (gravities); static int cur_gravity = 0; static void on_tap (ClutterTapAction *action, ClutterActor *actor, ClutterText *label) { gchar *str; clutter_actor_save_easing_state (actor); clutter_actor_set_content_gravity (actor, gravities[cur_gravity].gravity); clutter_actor_restore_easing_state (actor); str = g_strconcat ("Content gravity: ", gravities[cur_gravity].name, NULL); clutter_text_set_text (label, str); free (str); cur_gravity += 1; if (cur_gravity >= n_gravities) cur_gravity = 0; } int main (int argc, char *argv[]) { ClutterActor *stage, *text; ClutterContent *image; ClutterAction *action; GdkPixbuf *pixbuf; gchar *str; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_actor_set_name (stage, "Stage"); clutter_stage_set_title (CLUTTER_STAGE (stage), "Content Box"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_actor_set_margin_top (stage, 12); clutter_actor_set_margin_right (stage, 12); clutter_actor_set_margin_bottom (stage, 12); clutter_actor_set_margin_left (stage, 12); clutter_actor_show (stage); pixbuf = gdk_pixbuf_new_from_file ("redhand.png", NULL); image = clutter_image_new (); clutter_image_set_data (CLUTTER_IMAGE (image), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_has_alpha (pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), NULL); g_object_unref (pixbuf); clutter_actor_set_content_scaling_filters (stage, CLUTTER_SCALING_FILTER_TRILINEAR, CLUTTER_SCALING_FILTER_LINEAR); clutter_actor_set_content_gravity (stage, gravities[n_gravities - 1].gravity); clutter_actor_set_content (stage, image); g_object_unref (image); str = g_strconcat ("Content gravity: ", gravities[n_gravities - 1].name, NULL); text = clutter_text_new (); clutter_text_set_text (CLUTTER_TEXT (text), str); clutter_actor_add_constraint (text, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_add_child (stage, text); free (str); action = clutter_tap_action_new (); g_signal_connect (action, "tap", G_CALLBACK (on_tap), text); clutter_actor_add_action (stage, action); clutter_main (); return EXIT_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/rounded-rectangle.c���������������������������������������������������0000664�0001750�0001750�00000007557�14211404421�022220� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <cairo.h> #include <clutter/clutter.h> static gboolean draw_content (ClutterCanvas *canvas, cairo_t *cr, int surface_width, int surface_height) { /* rounded rectangle taken from: * * http://cairographics.org/samples/rounded_rectangle/ * * we leave 1 pixel around the edges to avoid jagged edges * when rotating the actor */ double x = 1.0, /* parameters like cairo_rectangle */ y = 1.0, width = surface_width - 2.0, height = surface_height - 2.0, aspect = 1.0, /* aspect ratio */ corner_radius = height / 20.0; /* and corner curvature radius */ double radius = corner_radius / aspect; double degrees = M_PI / 180.0; cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); cairo_new_sub_path (cr); cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees); cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees); cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees); cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees); cairo_close_path (cr); cairo_set_source_rgba (cr, 0.5, 0.5, 1, 0.95); cairo_fill (cr); /* we're done drawing */ return TRUE; } int main (int argc, char *argv[]) { ClutterActor *stage, *actor; ClutterContent *canvas; ClutterTransition *transition; /* initialize Clutter */ if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; /* create a stage */ stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Rectangle with rounded corners"); clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black); clutter_actor_set_size (stage, 500, 500); clutter_actor_set_opacity (stage, 64); clutter_actor_show (stage); /* our 2D canvas, courtesy of Cairo */ canvas = clutter_canvas_new (); clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300); /* the actor that will display the contents of the canvas */ actor = clutter_actor_new (); clutter_actor_set_content (actor, canvas); clutter_actor_set_content_gravity (actor, CLUTTER_CONTENT_GRAVITY_CENTER); clutter_actor_set_content_scaling_filters (actor, CLUTTER_SCALING_FILTER_TRILINEAR, CLUTTER_SCALING_FILTER_LINEAR); clutter_actor_set_pivot_point (actor, 0.5f, 0.5f); clutter_actor_add_constraint (actor, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_set_request_mode (actor, CLUTTER_REQUEST_CONTENT_SIZE); clutter_actor_add_child (stage, actor); /* the actor now owns the canvas */ g_object_unref (canvas); /* create the continuous animation of the actor spinning around its center */ transition = clutter_property_transition_new ("rotation-angle-y"); clutter_transition_set_from (transition, G_TYPE_DOUBLE, 0.0); clutter_transition_set_to (transition, G_TYPE_DOUBLE, 360.0); clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 2000); clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1); clutter_actor_add_transition (actor, "rotateActor", transition); /* the actor now owns the transition */ g_object_unref (transition); /* quit on destroy */ g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* connect our drawing code */ g_signal_connect (canvas, "draw", G_CALLBACK (draw_content), NULL); /* invalidate the canvas, so that we can draw before the main loop starts */ clutter_content_invalidate (canvas); clutter_main (); return EXIT_SUCCESS; } �������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/redhand.png�����������������������������������������������������������0000664�0001750�0001750�00000020072�14211404421�020550� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������������bKGD������ pHYs�� �� ����tIME 3x<,��IDATx]y|M~>( "HQV> Q)UU:hPzRJu]\PBiBEDD99Z9kwg=Z888888888888888888888888D),rU0H#ۜ#Tىm!8Ad' ` (�@9�cɂ 4$ p.w Y�) $m"!Eچ.�RT 3 49m0L)c&f=(cl+TRJRJ/e-JcPJ#VboL)}RYp'l0t0;]X Lfse(4VuC]e J)SDؐmC)N)-۸6?! [R:ֆ^l*xE%<c~|�8es J;jۆRM*mNnXŢ%Lcu'3~&<nam% d'_NMJWI<pf.'"u:'$CNAr L&?BH!$-LJy)\,Bל2qpWJ0BlɄ3gPK//60>#wo&&+b�}i)JFuZ ` aa+<\0N<5uWT�@m:t@P>M芋Qv~ 0Cpu٪EeB:8:A.BK-۸W�`v2ϖ-vDN M^KKݠz }=s&&u156v- l0Dھ4^^6O x1J~ζqwGOHر$$t !dBJSRpaLzγuktZ�Æ:3CMw?J:l:/^ m|^f=H3y6z…h9tlu1{Fm i"KXn*b)ANJ�we:\0AZ|ot7n<uJ;7ҟbY Lm=c:Lnm pPoM4*B, G<!$MҔl2?.D2͓kTTסCE؟=0}wO^_˟.m^z qK~GEkVţE ݽ[jܶ2VJrE֢E ��]/m6pv$Y� ?*iQ6r�@5O6Rg&Lƍ^I=cA{x *6Mp;oKܵkQzA~Y[WRӧFf,_J_Iy瑵x4tcRؗ,_޴|k՞?GJd/]j|j O?VPY}$z]&~}jx tBDPY+kڬ׶lAC~E{`F#B/u̴|"[:ԅtK)&8 A�>|c.Ńpv_ԀE;wZɢEۆR\ۺ6דE-ÑҔW2QmӺPq٦637lZCEΉ 0A�Wµz%"%lnb9/GDRKca+.bi9R4ټ.TuiY^@-<kQƂrl IKVbihpjQ%0J Xj;'R#̜ ~ @m!NM \Ap +W \Ap +W>s +W \ApuvApipU],L],s +Ws +W \Ap \Ap +W . TNJ^Z v]ލX[ S}=�P @􄛏. .AX�}yC+A8x cp +W vBJhPrWSXUgQaKvѣ;wX ׯa(;reRW֮qMouuq3V(ؼ`= @WRf<3gx RG>\s^O0Jqu2Ǐ󞼛ۥ!sB{ _c O2EA4h||  D3F6264^GqӮ5d ҿ!t Ovh֩uxm Z-A�[v)5@u:XX<E\+W@umi4TVi8(B�$& 11Rh4иC wx"Gr JKC4%5|Arڠ <Z>}֬m3A68!!d ̞ ]QdT?d1h4>C؜w#gX"ƍCsϡ>?׶l-[k(6rUwfwDz _}E?eP061Bj:bOfqqDj6jBG=^8䷻K qHX:ur=VawNkxic 4.Wx8]Ĥ$:>:|88)S xxpK8E˸1iՙH??͝>w,gXz}=̓Sw_.u+:&;w!߿]j!fL$&%eK>]ٳiɁ v'VD7ް+7C-͛ǹ pGϤ$9/D<qehw40憸3kVNcQp&-ZmyNt>OO\7O3)<Q~~HܴBD2O 1{wދ3<cgVKk;]>- Ɛ vI'ӵZ$Xx l ܯ|rⷄիp#$Vpr?>13XDA_3,l1nZ],Gw<,B|h'A@ŋ pTKۼ9by9s t,:k>z4lq ~I`hSvi<S]Qu,._F]v6 0Ԁ MH}|٪|:tol,{WDݝl$ :} f4BwCdgA}(ܶ 'N?k#"b`],ݺ!駑ĥBJlWeh,*յky3eegTu99]W֮_׮h+h#Z~4l$fAWZd.ZC!{2P4<Gz%xGE! ?_?s)޻ /Ʀedd183itk $ՃȘ?ƍS4.w!CPvjE. hRcu5Ne]\<Um'N1*HرՕOAm@z\9?L${cjB&ߕÞB3Jx1rWR~D.'mP^l!cnݪxѭFpNrgpibm'1 g@MFzGEkW 䡇-d~\ieɓnU-~+ ~ Qn̙`&CtVMFR2c{qNt)rW@]vb$$Xug#wdD`ފ+)A5aF\S^77],],B=p嫯`wN+LNV `^R^pWP7i`+ڕ,wX쁡¡;p6ٶ :u1Pbk*|t=*.F/( j ʸ'F#ʎqSl!x4A䚥ڶU4 Jn؝>T>J{o%5/t%GV._v0 u99RJDj rĀb }yWjxAkkjԔD< R)8NEco 6*)E�4NՁJJ# TA:Aj)j1$_1iR[gh2y<+lljF4XM6?||NΜ.K$HCa" VԢԫbWCHgEgQgUEa[#X vv_)KRPX[ =GZ HQTCcQ'(u[tŋ5O8|wX<UZ"o{W$2RREj32K߭UHO?XY5钟ue^ADh+)p4TUV脠ԩi!!ʉȭ �pB 5>>OV?XFwTCvZ/*eF~qDRJ*RSq7we/n&)VRE/ �A0Jk|ˡC[ 5xy)VdiJU]aQ/OwMQtY#0ŗK~ c�|Ʈ]3, ݖ-y"Ed%Q/j%o鸾cw< :#-[YG]vR]s7DԔ)h+vG�$~*+n a lwg^ $Um�D9zmx6VWO?aH}oL ۷\bfB>jƢϏ??!A oWD b@jU'h}m3֒O]i^3W.:.:i5rZScj LLD={9q7bBeˬZ\߱Ckޜ d/o.]$ULw 6oV=@hݹ-~&hat?xP_L ":H1c$W.grȦ߭w.?dq|cb{Yz[j)Q:<.Q1� hva,/[CUJCiJ ʏEcQ݉L4Cp<ݻJf4S92(1#!DA6j7mTÆ)zm 5 R_G}~>srTܚ5gVn׮FY_@ƍ>cJ! �Qjpx�ß~/)t8t}0TVި_D܂bjA?(ꋘy+v^۲ nwEd̟/;9BH-d<J Ji3#Z!&yuQ f)v_PhMe�BB cɔG)^vCGCy`bY@ӹh2M9 `!d!$R<MugRym9]YE;wQ-N)ν]s$'RJU �ꟐVZQp7PP9gGUvޣ'!dcoP"B-c)v|]5*+qajh# "룏l^JABPJB3VHQ֭NSy4ҦLQgBmf&Nw~t$J)OUS)϶6 11VhN\=KUxN }y+4ח/kHbɠRTD@O>zE7Ғ%uT**pbh4+~N~ [˟+9I,Nhd;SݔҖo}fƐ1o2,*SUׯctD3IVb5A*2Gʳ//$\)֜q~tlvFȑ]T$c�$qalYܤC a*V *OƩ瞃X:40�i'gh:B2%^Ba� Bڴie<Zk8'+Ji.s|/">#G1~<í}wъĬ"k�L򬩡#GYYA &0VW㷷FmN>"'L@W_l c Rڌr _ǯh((NO=N qV[Y2uJݳf[="}�t(!Drݚt CUlulqs"tpTcu5.})~K-R qfJM1\2E b.x3g>_~(N-CFG;MQ8Î\Ih}w$,Q fW$�Wr�N=쇤4h;q"^z -Z8(3*Ϝ%K\z�}w풲30!d1/!jQ̤I6I 6>^gǎ!{R8w܄n˗OJvA0)N3I^$Xò4%ƏYXZ?$"'NOt](TGiJ rWDّ# pG T f~+YSSqz8+*lVO"?8iUWnߎk?<΂ q&)7pIL5=�Xڬ,3W//48-~!<�VQףEߏw*-Q"1nO|72O5I҆r Ut%%8=a*S迧 zkWxGFB4h<}Ǐ)4.5XG}>62WUIYE ͮooxGF«MxiPh' `�`24>/ h((�3Ȗ 13!$@ﺶe .̞ cM M C e%K6 \`M`9O>~{"gO>28Ɨ qQ|MScAv'93f~e An"9H"h1E`^|09D" �4}w Uh>pqڍb  D^p'縺aO0*A$;~IW}_!_ 1ßŀ#G1nbpr&H!�kQڅQ}^| / ;!qj*o:M1ďMm}E򓒐Դeopxݿ<"O!3 7d IrɄ_~Aߢx^氹9s.gnsE2"/ cM Cю(=|bAVs"rD8EY]p"t8~%QԤDtvht^Y},!$ɡ r𪛱UgϢ*- 騹pOs;_Fѣل(#l�jףh((iny9Luuz}jh<= ot4~]u."p(ܤ&�X�+κs4B,8b )] !�mP�!_v,j ' AӽٗxsX�`r8,A?n#$�x.x1TSD99k !;n&\�yXG$KqfPJ#<+r]RRB�sUq dx|8AĹ_]0@;8BT3� !ܟ3)42�0&hJsXsWե?nf$� cs �6M Ncx3a"54+ rR SpքpRDsV����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/bin-layout.c����������������������������������������������������������0000664�0001750�0001750�00000024706�14211404421�020674� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <cairo.h> #include <gdk-pixbuf/gdk-pixbuf.h> #include <clutter/clutter.h> static const ClutterColor bg_color = { 0xcc, 0xcc, 0xcc, 0x99 }; static gboolean is_expanded = FALSE; static gboolean on_canvas_draw (ClutterCanvas *canvas, cairo_t *cr, gint width, gint height) { cairo_pattern_t *pat; gfloat x, y; g_print (G_STRLOC ": Painting at %d x %d\n", width, height); cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); #define BG_ROUND_RADIUS 12 x = y = 0; cairo_move_to (cr, BG_ROUND_RADIUS, y); cairo_line_to (cr, width - BG_ROUND_RADIUS, y); cairo_curve_to (cr, width, y, width, y, width, BG_ROUND_RADIUS); cairo_line_to (cr, width, height - BG_ROUND_RADIUS); cairo_curve_to (cr, width, height, width, height, width - BG_ROUND_RADIUS, height); cairo_line_to (cr, BG_ROUND_RADIUS, height); cairo_curve_to (cr, x, height, x, height, x, height - BG_ROUND_RADIUS); cairo_line_to (cr, x, BG_ROUND_RADIUS); cairo_curve_to (cr, x, y, x, y, BG_ROUND_RADIUS, y); cairo_close_path (cr); clutter_cairo_set_source_color (cr, &bg_color); cairo_stroke (cr); x += 4; y += 4; width -= 4; height -= 4; cairo_move_to (cr, BG_ROUND_RADIUS, y); cairo_line_to (cr, width - BG_ROUND_RADIUS, y); cairo_curve_to (cr, width, y, width, y, width, BG_ROUND_RADIUS); cairo_line_to (cr, width, height - BG_ROUND_RADIUS); cairo_curve_to (cr, width, height, width, height, width - BG_ROUND_RADIUS, height); cairo_line_to (cr, BG_ROUND_RADIUS, height); cairo_curve_to (cr, x, height, x, height, x, height - BG_ROUND_RADIUS); cairo_line_to (cr, x, BG_ROUND_RADIUS); cairo_curve_to (cr, x, y, x, y, BG_ROUND_RADIUS, y); cairo_close_path (cr); pat = cairo_pattern_create_linear (0, 0, 0, height); cairo_pattern_add_color_stop_rgba (pat, 1, .85, .85, .85, 1); cairo_pattern_add_color_stop_rgba (pat, .95, 1, 1, 1, 1); cairo_pattern_add_color_stop_rgba (pat, .05, 1, 1, 1, 1); cairo_pattern_add_color_stop_rgba (pat, 0, .85, .85, .85, 1); cairo_set_source (cr, pat); cairo_fill (cr); cairo_pattern_destroy (pat); #undef BG_ROUND_RADIUS return TRUE; } static gboolean on_box_enter (ClutterActor *box, ClutterEvent *event, ClutterActor *emblem) { /* we ease the opacity linearly */ clutter_actor_save_easing_state (emblem); clutter_actor_set_easing_mode (emblem, CLUTTER_LINEAR); clutter_actor_set_opacity (emblem, 255); clutter_actor_restore_easing_state (emblem); return CLUTTER_EVENT_STOP; } static gboolean on_box_leave (ClutterActor *box, ClutterEvent *event, ClutterActor *emblem) { clutter_actor_save_easing_state (emblem); clutter_actor_set_easing_mode (emblem, CLUTTER_LINEAR); clutter_actor_set_opacity (emblem, 0); clutter_actor_restore_easing_state (emblem); return CLUTTER_EVENT_STOP; } static void on_emblem_clicked (ClutterClickAction *action, ClutterActor *emblem, ClutterActor *box) { /* we add a little bounce to the resizing of the box */ clutter_actor_save_easing_state (box); clutter_actor_set_easing_mode (box, CLUTTER_EASE_OUT_BOUNCE); clutter_actor_set_easing_duration (box, 500); if (!is_expanded) clutter_actor_set_size (box, 400, 400); else clutter_actor_set_size (box, 200, 200); clutter_actor_restore_easing_state (box); is_expanded = !is_expanded; } static gboolean on_emblem_long_press (ClutterClickAction *action, ClutterActor *emblem, ClutterLongPressState state, ClutterActor *box) { switch (state) { case CLUTTER_LONG_PRESS_QUERY: g_print ("*** long press: query ***\n"); return is_expanded; case CLUTTER_LONG_PRESS_CANCEL: g_print ("*** long press: cancel ***\n"); break; case CLUTTER_LONG_PRESS_ACTIVATE: g_print ("*** long press: activate ***\n"); break; } return TRUE; } static void redraw_canvas (ClutterActor *actor, ClutterCanvas *canvas) { /* we want to invalidate the canvas and redraw its contents * only when the size changes at the end of the animation, * to avoid drawing all the states inbetween */ clutter_canvas_set_size (canvas, clutter_actor_get_width (actor), clutter_actor_get_height (actor)); } int main (int argc, char *argv[]) { ClutterActor *stage, *box, *bg, *icon, *emblem, *label; ClutterLayoutManager *layout; ClutterContent *canvas, *image; ClutterColor *color; ClutterAction *action; GdkPixbuf *pixbuf; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* prepare the stage */ stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "BinLayout"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium2); clutter_actor_set_size (stage, 640, 480); clutter_actor_show (stage); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* this is our BinLayout, with its default alignments */ layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_CENTER); /* the main container; this actor will use the BinLayout to lay * out its children; we use the anchor point to keep it centered * on the same position even when we change its size */ box = clutter_actor_new (); clutter_actor_set_layout_manager (box, layout); clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_set_position (box, 320, 240); clutter_actor_set_reactive (box, TRUE); clutter_actor_set_name (box, "box"); clutter_actor_add_child (stage, box); /* the background is drawn using a canvas content */ canvas = clutter_canvas_new (); g_signal_connect (canvas, "draw", G_CALLBACK (on_canvas_draw), NULL); clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 200, 200); /* this is the background actor; we want it to fill the whole * of the allocation given to it by its parent */ bg = clutter_actor_new (); clutter_actor_set_name (bg, "background"); clutter_actor_set_size (bg, 200, 200); clutter_actor_set_content (bg, canvas); clutter_actor_set_x_expand (bg, TRUE); clutter_actor_set_y_expand (bg, TRUE); clutter_actor_set_x_align (bg, CLUTTER_ACTOR_ALIGN_FILL); clutter_actor_set_y_align (bg, CLUTTER_ACTOR_ALIGN_FILL); clutter_actor_add_child (box, bg); /* we use the ::transitions-completed signal to get notification * of the end of the sizing animation; this allows us to redraw * the canvas only once the animation has stopped */ g_signal_connect (box, "transitions-completed", G_CALLBACK (redraw_canvas), canvas); /* we use GdkPixbuf to load an image from our data directory */ pixbuf = gdk_pixbuf_new_from_file ("redhand.png", NULL); image = clutter_image_new (); clutter_image_set_data (CLUTTER_IMAGE (image), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_has_alpha (pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), NULL); g_object_unref (pixbuf); /* this is the icon; it's going to be centered inside the box actor. * we use the content gravity to keep the aspect ratio of the image, * and the scaling filters to get a better result when scaling the * image down. */ icon = clutter_actor_new (); clutter_actor_set_name (icon, "icon"); clutter_actor_set_size (icon, 196, 196); clutter_actor_set_x_expand (icon, TRUE); clutter_actor_set_y_expand (icon, TRUE); clutter_actor_set_x_align (icon, CLUTTER_ACTOR_ALIGN_CENTER); clutter_actor_set_y_align (icon, CLUTTER_ACTOR_ALIGN_CENTER); clutter_actor_set_content_gravity (icon, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT); clutter_actor_set_content_scaling_filters (icon, CLUTTER_SCALING_FILTER_TRILINEAR, CLUTTER_SCALING_FILTER_LINEAR); clutter_actor_set_content (icon, image); clutter_actor_add_child (box, icon); color = clutter_color_new (g_random_int_range (0, 255), g_random_int_range (0, 255), g_random_int_range (0, 255), 224); /* this is the emblem: a small rectangle with a random color, that we * want to put in the bottom right corner */ emblem = clutter_actor_new (); clutter_actor_set_name (emblem, "emblem"); clutter_actor_set_size (emblem, 48, 48); clutter_actor_set_background_color (emblem, color); clutter_actor_set_x_expand (emblem, TRUE); clutter_actor_set_y_expand (emblem, TRUE); clutter_actor_set_x_align (emblem, CLUTTER_ACTOR_ALIGN_END); clutter_actor_set_y_align (emblem, CLUTTER_ACTOR_ALIGN_END); clutter_actor_set_reactive (emblem, TRUE); clutter_actor_set_opacity (emblem, 0); clutter_actor_add_child (box, emblem); clutter_color_free (color); /* when clicking on the emblem, we want to perform an action */ action = clutter_click_action_new (); clutter_actor_add_action (emblem, action); g_signal_connect (action, "clicked", G_CALLBACK (on_emblem_clicked), box); g_signal_connect (action, "long-press", G_CALLBACK (on_emblem_long_press), box); /* whenever the pointer enters the box, we show the emblem; we hide * the emblem when the pointer leaves the box */ g_signal_connect (box, "enter-event", G_CALLBACK (on_box_enter), emblem); g_signal_connect (box, "leave-event", G_CALLBACK (on_box_leave), emblem); /* a label, that we want to position at the top and center of the box */ label = clutter_text_new (); clutter_actor_set_name (label, "text"); clutter_text_set_text (CLUTTER_TEXT (label), "A simple test"); clutter_actor_set_x_expand (label, TRUE); clutter_actor_set_x_align (label, CLUTTER_ACTOR_ALIGN_CENTER); clutter_actor_set_y_expand (label, TRUE); clutter_actor_set_y_align (label, CLUTTER_ACTOR_ALIGN_START); clutter_actor_add_child (box, label); clutter_main (); return EXIT_SUCCESS; } ����������������������������������������������������������muffin-5.2.1/clutter/examples/constraints.c���������������������������������������������������������0000664�0001750�0001750�00000007705�14211404421�021160� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> int main (int argc, char *argv[]) { ClutterActor *stage, *layer_a, *layer_b, *layer_c; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* the main container */ stage = clutter_stage_new (); clutter_actor_set_name (stage, "stage"); clutter_stage_set_title (CLUTTER_STAGE (stage), "Snap Constraint"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium1); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* first layer, with a fixed (100, 25) size */ layer_a = clutter_actor_new (); clutter_actor_set_background_color (layer_a, CLUTTER_COLOR_ScarletRed); clutter_actor_set_name (layer_a, "layerA"); clutter_actor_set_size (layer_a, 100.0, 25.0); clutter_actor_add_child (stage, layer_a); /* the first layer is anchored to the middle of the stage */ clutter_actor_add_constraint (layer_a, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); /* second layer, with no implicit size */ layer_b = clutter_actor_new (); clutter_actor_set_background_color (layer_b, CLUTTER_COLOR_DarkButter); clutter_actor_set_name (layer_b, "layerB"); clutter_actor_add_child (stage, layer_b); /* the second layer tracks the X coordinate and the width of * the first layer */ clutter_actor_add_constraint (layer_b, clutter_bind_constraint_new (layer_a, CLUTTER_BIND_X, 0.0)); clutter_actor_add_constraint (layer_b, clutter_bind_constraint_new (layer_a, CLUTTER_BIND_WIDTH, 0.0)); /* the second layer is snapped between the bottom edge of * the first layer, and the bottom edge of the stage; a * spacing of 10 pixels in each direction is added for padding */ clutter_actor_add_constraint (layer_b, clutter_snap_constraint_new (layer_a, CLUTTER_SNAP_EDGE_TOP, CLUTTER_SNAP_EDGE_BOTTOM, 10.0)); clutter_actor_add_constraint (layer_b, clutter_snap_constraint_new (stage, CLUTTER_SNAP_EDGE_BOTTOM, CLUTTER_SNAP_EDGE_BOTTOM, -10.0)); /* the third layer, with no implicit size */ layer_c = clutter_actor_new (); clutter_actor_set_background_color (layer_c, CLUTTER_COLOR_LightChameleon); clutter_actor_set_name (layer_c, "layerC"); clutter_actor_add_child (stage, layer_c); /* as for the second layer, the third layer tracks the X * coordinate and width of the first layer */ clutter_actor_add_constraint (layer_c, clutter_bind_constraint_new (layer_a, CLUTTER_BIND_X, 0.0)); clutter_actor_add_constraint (layer_c, clutter_bind_constraint_new (layer_a, CLUTTER_BIND_WIDTH, 0.0)); /* the third layer is snapped between the top edge of the stage * and the top edge of the first layer; again, a spacing of * 10 pixels in each direction is added for padding */ clutter_actor_add_constraint (layer_c, clutter_snap_constraint_new (layer_a, CLUTTER_SNAP_EDGE_BOTTOM, CLUTTER_SNAP_EDGE_TOP, -10.0)); clutter_actor_add_constraint (layer_c, clutter_snap_constraint_new (stage, CLUTTER_SNAP_EDGE_TOP, CLUTTER_SNAP_EDGE_TOP, 10.0)); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } �����������������������������������������������������������muffin-5.2.1/clutter/examples/drop-action.c���������������������������������������������������������0000664�0001750�0001750�00000021014�14211404421�021015� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> #define TARGET_SIZE 200 #define HANDLE_SIZE 128 static ClutterActor *stage = NULL; static ClutterActor *target1 = NULL; static ClutterActor *target2 = NULL; static ClutterActor *drag = NULL; static gboolean drop_successful = FALSE; static void add_drag_object (ClutterActor *target); static void on_drag_end (ClutterDragAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y, ClutterModifierType modifiers) { ClutterActor *handle = clutter_drag_action_get_drag_handle (action); g_print ("Drag ended at: %.0f, %.0f\n", event_x, event_y); clutter_actor_save_easing_state (actor); clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR); clutter_actor_set_opacity (actor, 255); clutter_actor_restore_easing_state (actor); clutter_actor_save_easing_state (handle); if (!drop_successful) { ClutterActor *parent = clutter_actor_get_parent (actor); gfloat x_pos, y_pos; clutter_actor_save_easing_state (parent); clutter_actor_set_easing_mode (parent, CLUTTER_LINEAR); clutter_actor_set_opacity (parent, 255); clutter_actor_restore_easing_state (parent); clutter_actor_get_transformed_position (actor, &x_pos, &y_pos); clutter_actor_set_easing_mode (handle, CLUTTER_EASE_OUT_BOUNCE); clutter_actor_set_position (handle, x_pos, y_pos); clutter_actor_set_opacity (handle, 0); } else { clutter_actor_set_easing_mode (handle, CLUTTER_LINEAR); clutter_actor_set_opacity (handle, 0); } clutter_actor_restore_easing_state (handle); g_signal_connect (handle, "transitions-completed", G_CALLBACK (clutter_actor_destroy), NULL); } static void on_drag_begin (ClutterDragAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y, ClutterModifierType modifiers) { ClutterActor *handle; gfloat x_pos, y_pos; clutter_actor_get_position (actor, &x_pos, &y_pos); handle = clutter_actor_new (); clutter_actor_set_background_color (handle, CLUTTER_COLOR_DarkSkyBlue); clutter_actor_set_size (handle, 128, 128); clutter_actor_set_position (handle, event_x - x_pos, event_y - y_pos); clutter_actor_add_child (stage, handle); clutter_drag_action_set_drag_handle (action, handle); clutter_actor_save_easing_state (actor); clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR); clutter_actor_set_opacity (actor, 128); clutter_actor_restore_easing_state (actor); drop_successful = FALSE; } static void add_drag_object (ClutterActor *target) { ClutterActor *parent; if (drag == NULL) { ClutterAction *action; drag = clutter_actor_new (); clutter_actor_set_background_color (drag, CLUTTER_COLOR_LightSkyBlue); clutter_actor_set_size (drag, HANDLE_SIZE, HANDLE_SIZE); clutter_actor_set_position (drag, (TARGET_SIZE - HANDLE_SIZE) / 2.0, (TARGET_SIZE - HANDLE_SIZE) / 2.0); clutter_actor_set_reactive (drag, TRUE); action = clutter_drag_action_new (); g_signal_connect (action, "drag-begin", G_CALLBACK (on_drag_begin), NULL); g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL); clutter_actor_add_action (drag, action); } parent = clutter_actor_get_parent (drag); if (parent == target) { clutter_actor_save_easing_state (target); clutter_actor_set_easing_mode (target, CLUTTER_LINEAR); clutter_actor_set_opacity (target, 255); clutter_actor_restore_easing_state (target); return; } g_object_ref (drag); if (parent != NULL && parent != stage) { clutter_actor_remove_child (parent, drag); clutter_actor_save_easing_state (parent); clutter_actor_set_easing_mode (parent, CLUTTER_LINEAR); clutter_actor_set_opacity (parent, 64); clutter_actor_restore_easing_state (parent); } clutter_actor_add_child (target, drag); clutter_actor_save_easing_state (target); clutter_actor_set_easing_mode (target, CLUTTER_LINEAR); clutter_actor_set_opacity (target, 255); clutter_actor_restore_easing_state (target); g_object_unref (drag); } static void on_target_over (ClutterDropAction *action, ClutterActor *actor, gpointer _data) { gboolean is_over = GPOINTER_TO_UINT (_data); guint8 final_opacity = is_over ? 128 : 64; ClutterActor *target; target = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); clutter_actor_save_easing_state (target); clutter_actor_set_easing_mode (target, CLUTTER_LINEAR); clutter_actor_set_opacity (target, final_opacity); clutter_actor_restore_easing_state (target); } static void on_target_drop (ClutterDropAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y) { gfloat actor_x, actor_y; actor_x = actor_y = 0.0f; clutter_actor_transform_stage_point (actor, event_x, event_y, &actor_x, &actor_y); g_print ("Dropped at %.0f, %.0f (screen: %.0f, %.0f)\n", actor_x, actor_y, event_x, event_y); drop_successful = TRUE; add_drag_object (actor); } int main (int argc, char *argv[]) { ClutterActor *dummy; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Drop Action"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); target1 = clutter_actor_new (); clutter_actor_set_background_color (target1, CLUTTER_COLOR_LightScarletRed); clutter_actor_set_size (target1, TARGET_SIZE, TARGET_SIZE); clutter_actor_set_opacity (target1, 64); clutter_actor_add_constraint (target1, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5)); clutter_actor_set_x (target1, 10); clutter_actor_set_reactive (target1, TRUE); clutter_actor_add_action_with_name (target1, "drop", clutter_drop_action_new ()); g_signal_connect (clutter_actor_get_action (target1, "drop"), "over-in", G_CALLBACK (on_target_over), GUINT_TO_POINTER (TRUE)); g_signal_connect (clutter_actor_get_action (target1, "drop"), "over-out", G_CALLBACK (on_target_over), GUINT_TO_POINTER (FALSE)); g_signal_connect (clutter_actor_get_action (target1, "drop"), "drop", G_CALLBACK (on_target_drop), NULL); dummy = clutter_actor_new (); clutter_actor_set_background_color (dummy, CLUTTER_COLOR_DarkOrange); clutter_actor_set_size (dummy, 640 - (2 * 10) - (2 * (TARGET_SIZE + 10)), TARGET_SIZE); clutter_actor_add_constraint (dummy, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5)); clutter_actor_add_constraint (dummy, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5)); clutter_actor_set_reactive (dummy, TRUE); target2 = clutter_actor_new (); clutter_actor_set_background_color (target2, CLUTTER_COLOR_LightChameleon); clutter_actor_set_size (target2, TARGET_SIZE, TARGET_SIZE); clutter_actor_set_opacity (target2, 64); clutter_actor_add_constraint (target2, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5)); clutter_actor_set_x (target2, 640 - TARGET_SIZE - 10); clutter_actor_set_reactive (target2, TRUE); clutter_actor_add_action_with_name (target2, "drop", clutter_drop_action_new ()); g_signal_connect (clutter_actor_get_action (target2, "drop"), "over-in", G_CALLBACK (on_target_over), GUINT_TO_POINTER (TRUE)); g_signal_connect (clutter_actor_get_action (target2, "drop"), "over-out", G_CALLBACK (on_target_over), GUINT_TO_POINTER (FALSE)); g_signal_connect (clutter_actor_get_action (target2, "drop"), "drop", G_CALLBACK (on_target_drop), NULL); clutter_actor_add_child (stage, target1); clutter_actor_add_child (stage, dummy); clutter_actor_add_child (stage, target2); add_drag_object (target1); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/scroll-actor.c��������������������������������������������������������0000664�0001750�0001750�00000013041�14211404421�021203� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <clutter/clutter.h> static const char *menu_items_name[] = { "Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Option 6", "Option 7", "Option 8", "Option 9", "Option 10", "Option 11", }; static const guint menu_items_len = G_N_ELEMENTS (menu_items_name); static void select_item_at_index (ClutterActor *scroll, int index_) { ClutterPoint point; ClutterActor *menu, *item; gpointer old_selected; menu = clutter_actor_get_first_child (scroll); old_selected = g_object_get_data (G_OBJECT (scroll), "selected-item"); if (old_selected != NULL) { item = clutter_actor_get_child_at_index (menu, GPOINTER_TO_INT (old_selected)); clutter_text_set_color (CLUTTER_TEXT (item), CLUTTER_COLOR_White); } /* wrap around the index */ if (index_ < 0) index_ = clutter_actor_get_n_children (menu) - 1; else if (index_ >= clutter_actor_get_n_children (menu)) index_ = 0; item = clutter_actor_get_child_at_index (menu, index_); clutter_actor_get_position (item, &point.x, &point.y); /* scroll to the actor's position; the menu actor is always set at (0, 0), * so it does not contribute any further offset, and we can use the position * of its children to ask the ScrollActor to scroll the visible region; if * the menu actor had an offset, or was transformed, we would have needed to * get their relative transformed position instead. */ clutter_actor_save_easing_state (scroll); clutter_scroll_actor_scroll_to_point (CLUTTER_SCROLL_ACTOR (scroll), &point); clutter_actor_restore_easing_state (scroll); clutter_text_set_color (CLUTTER_TEXT (item), CLUTTER_COLOR_LightSkyBlue); /* store the index of the currently selected item, so that we can * implement select_next_item() and select_prev_item() */ g_object_set_data (G_OBJECT (scroll), "selected-item", GINT_TO_POINTER (index_)); } static void select_next_item (ClutterActor *scroll) { gpointer selected_ = g_object_get_data (G_OBJECT (scroll), "selected-item"); select_item_at_index (scroll, GPOINTER_TO_INT (selected_) + 1); } static void select_prev_item (ClutterActor *scroll) { gpointer selected_ = g_object_get_data (G_OBJECT (scroll), "selected-item"); select_item_at_index (scroll, GPOINTER_TO_INT (selected_) - 1); } static ClutterActor * create_menu_item (const char *name) { ClutterActor *text; text = clutter_text_new (); clutter_text_set_font_name (CLUTTER_TEXT (text), "Sans Bold 24"); clutter_text_set_text (CLUTTER_TEXT (text), name); clutter_text_set_color (CLUTTER_TEXT (text), CLUTTER_COLOR_White); clutter_actor_set_margin_left (text, 12.f); clutter_actor_set_margin_right (text, 12.f); return text; } static ClutterActor * create_menu_actor (ClutterActor *scroll) { ClutterActor *menu; ClutterLayoutManager *layout_manager; guint i; /* this is our menu; it contains items in a vertical layout */ layout_manager = clutter_box_layout_new (); clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout_manager), CLUTTER_ORIENTATION_VERTICAL); clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout_manager), 12.f); menu = clutter_actor_new (); clutter_actor_set_layout_manager (menu, layout_manager); clutter_actor_set_background_color (menu, CLUTTER_COLOR_Black); /* these are the items */ for (i = 0; i < menu_items_len; i++) clutter_actor_add_child (menu, create_menu_item (menu_items_name[i])); return menu; } static ClutterActor * create_scroll_actor (ClutterActor *stage) { ClutterActor *scroll; /* our scrollable viewport */ scroll = clutter_scroll_actor_new (); clutter_actor_set_name (scroll, "scroll"); /* give a vertical offset, and constrain the viewport so that its size * is bound to the stage size */ clutter_actor_set_position (scroll, 0.f, 18.f); clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5)); clutter_actor_add_constraint (scroll, clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, -36.f)); /* we only want to scroll the contents vertically, and * ignore any horizontal component */ clutter_scroll_actor_set_scroll_mode (CLUTTER_SCROLL_ACTOR (scroll), CLUTTER_SCROLL_VERTICALLY); clutter_actor_add_child (scroll, create_menu_actor (scroll)); /* select the first item */ select_item_at_index (scroll, 0); return scroll; } static gboolean on_key_press (ClutterActor *stage, ClutterEvent *event, gpointer unused) { ClutterActor *scroll; guint key_symbol; scroll = clutter_actor_get_first_child (stage); key_symbol = clutter_event_get_key_symbol (event); if (key_symbol == CLUTTER_KEY_Up) select_prev_item (scroll); else if (key_symbol == CLUTTER_KEY_Down) select_next_item (scroll); return CLUTTER_EVENT_STOP; } int main (int argc, char *argv[]) { ClutterActor *stage; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; /* create a new stage */ stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Scroll Actor"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), NULL); clutter_actor_add_child (stage, create_scroll_actor (stage)); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/threads.c�������������������������������������������������������������0000664�0001750�0001750�00000020151�14211404421�020231� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <clutter/clutter.h> /* our thread-specific data */ typedef struct { ClutterActor *stage; ClutterActor *label; ClutterActor *progress; ClutterActor *rect; ClutterTransition *flip; ClutterTransition *bounce; } TestThreadData; static TestThreadData * test_thread_data_new (void) { TestThreadData *data; data = g_new0 (TestThreadData, 1); return data; } static void test_thread_data_free (gpointer _data) { TestThreadData *data = _data; if (data == NULL) return; g_print ("Removing thread data [%p]\n", _data); g_clear_object (&data->progress); g_clear_object (&data->label); g_clear_object (&data->stage); g_clear_object (&data->rect); g_clear_object (&data->flip); g_clear_object (&data->bounce); free (data); } static gboolean test_thread_done_idle (gpointer user_data) { TestThreadData *data = user_data; g_print ("Last update [%p]\n", data); clutter_text_set_text (CLUTTER_TEXT (data->label), "Completed"); clutter_actor_remove_transition (data->rect, "bounce"); clutter_actor_remove_transition (data->rect, "flip"); return G_SOURCE_REMOVE; } static void test_thread_data_done (gpointer _data) { if (_data == NULL) return; g_print ("Thread completed\n"); /* since the TestThreadData structure references Clutter data structures * we need to free it from within the same thread that called clutter_main() * which means using an idle handler in the main loop. * * clutter_threads_add_idle() is guaranteed to run the callback passed to * to it under the Big Clutter Lock. */ clutter_threads_add_idle_full (G_PRIORITY_DEFAULT, test_thread_done_idle, _data, test_thread_data_free); } /* thread local storage */ static GPrivate test_thread_data = G_PRIVATE_INIT (test_thread_data_done); typedef struct { gint count; TestThreadData *thread_data; } TestUpdate; static gboolean update_label_idle (gpointer data) { TestUpdate *update = data; guint width; gchar *text; if (update->thread_data->label == NULL) return G_SOURCE_REMOVE; text = g_strdup_printf ("Count to %d", update->count); clutter_text_set_text (CLUTTER_TEXT (update->thread_data->label), text); clutter_actor_set_width (update->thread_data->label, -1); if (update->count == 0) width = 0; else if (update->count == 100) width = 350; else width = (guint) (update->count / 100.0 * 350.0); clutter_actor_save_easing_state (update->thread_data->progress); clutter_actor_set_width (update->thread_data->progress, width); clutter_actor_restore_easing_state (update->thread_data->progress); free (text); free (update); return G_SOURCE_REMOVE; } static void do_something_very_slow (void) { TestThreadData *data; gint i; data = g_private_get (&test_thread_data); for (i = 0; i <= 100; i++) { gint msecs; msecs = 1 + (int) (100.0 * rand () / ((RAND_MAX + 1.0) / 3)); /* sleep for a while, to emulate some work being done */ g_usleep (msecs * 1000); if ((i % 10) == 0) { TestUpdate *update; /* update the UI from within the main loop, making sure that the * Big Clutter Lock is held; only one thread at a time can call * Clutter API, and it's mandatory to do this from the same thread * that called clutter_init()/clutter_main(). */ update = g_new (TestUpdate, 1); update->count = i; update->thread_data = data; clutter_threads_add_idle_full (G_PRIORITY_HIGH, update_label_idle, update, NULL); } } } static gpointer test_thread_func (gpointer user_data) { TestThreadData *data = user_data; g_private_set (&test_thread_data, data); /* this function will block */ do_something_very_slow (); return NULL; } static ClutterActor *count_label = NULL; static ClutterActor *help_label = NULL; static ClutterActor *progress_rect = NULL; static ClutterActor *rect = NULL; static ClutterTransition *flip = NULL; static ClutterTransition *bounce = NULL; static gboolean on_key_press_event (ClutterStage *stage, ClutterEvent *event, gpointer user_data) { TestThreadData *data; switch (clutter_event_get_key_symbol (event)) { case CLUTTER_KEY_s: clutter_text_set_text (CLUTTER_TEXT (help_label), "Press 'q' to quit"); /* start the animations */ clutter_actor_add_transition (rect, "flip", flip); clutter_actor_add_transition (rect, "bounce", bounce); /* the data structure holding all our objects */ data = test_thread_data_new (); data->stage = g_object_ref (stage); data->label = g_object_ref (count_label); data->progress = g_object_ref (progress_rect); data->rect = g_object_ref (rect); data->flip = g_object_ref (flip); data->bounce = g_object_ref (bounce); /* start the thread that updates the counter and the progress bar */ g_thread_new ("counter", test_thread_func, data); return CLUTTER_EVENT_STOP; case CLUTTER_KEY_q: clutter_main_quit (); return CLUTTER_EVENT_STOP; default: break; } return CLUTTER_EVENT_PROPAGATE; } int main (int argc, char *argv[]) { ClutterTransition *transition; ClutterActor *stage; ClutterPoint start = CLUTTER_POINT_INIT (75.f, 150.f); ClutterPoint end = CLUTTER_POINT_INIT (400.f, 150.f); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Threading"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium3); clutter_actor_set_size (stage, 600, 300); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); count_label = clutter_text_new_with_text ("Mono 12", "Counter"); clutter_actor_set_position (count_label, 350, 50); clutter_actor_add_child (stage, count_label); help_label = clutter_text_new_with_text ("Mono 12", "Press 's' to start"); clutter_actor_set_position (help_label, 50, 50); clutter_actor_add_child (stage, help_label); /* a progress bar */ progress_rect = clutter_actor_new (); clutter_actor_set_background_color (progress_rect, CLUTTER_COLOR_DarkChameleon); clutter_actor_set_position (progress_rect, 50, 225); clutter_actor_set_size (progress_rect, 350, 50); clutter_actor_add_child (stage, progress_rect); /* an actor we bounce around */ rect = clutter_actor_new (); clutter_actor_set_background_color (rect, CLUTTER_COLOR_LightScarletRed); clutter_actor_set_position (rect, 75, 150); clutter_actor_set_size (rect, 50, 50); clutter_actor_set_pivot_point (rect, .5f, .5f); clutter_actor_set_opacity (rect, 224); clutter_actor_add_child (stage, rect); /* two transitions we use to bounce rect around */ transition = clutter_property_transition_new ("rotation-angle-z"); clutter_transition_set_from (transition, G_TYPE_DOUBLE, 0.0); clutter_transition_set_to (transition, G_TYPE_DOUBLE, 360.0); clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1); clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000); flip = transition; transition = clutter_property_transition_new ("position"); clutter_transition_set_from (transition, CLUTTER_TYPE_POINT, &start); clutter_transition_set_to (transition, CLUTTER_TYPE_POINT, &end); clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1); clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000); bounce = transition; g_signal_connect (stage, "button-press-event", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press_event), NULL); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/examples/canvas.c��������������������������������������������������������������0000664�0001750�0001750�00000011545�14211404421�020061� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <cairo.h> #include <clutter/clutter.h> static gboolean draw_clock (ClutterCanvas *canvas, cairo_t *cr, int width, int height) { GDateTime *now; float hours, minutes, seconds; ClutterColor color; /* get the current time and compute the angles */ now = g_date_time_new_now_local (); seconds = g_date_time_get_second (now) * G_PI / 30; minutes = g_date_time_get_minute (now) * G_PI / 30; hours = g_date_time_get_hour (now) * G_PI / 6; cairo_save (cr); /* clear the contents of the canvas, to avoid painting * over the previous frame */ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); /* scale the modelview to the size of the surface */ cairo_scale (cr, width, height); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_width (cr, 0.1); /* the black rail that holds the seconds indicator */ clutter_cairo_set_source_color (cr, CLUTTER_COLOR_Black); cairo_translate (cr, 0.5, 0.5); cairo_arc (cr, 0, 0, 0.4, 0, G_PI * 2); cairo_stroke (cr); /* the seconds indicator */ color = *CLUTTER_COLOR_White; color.alpha = 128; clutter_cairo_set_source_color (cr, &color); cairo_move_to (cr, 0, 0); cairo_arc (cr, sinf (seconds) * 0.4, - cosf (seconds) * 0.4, 0.05, 0, G_PI * 2); cairo_fill (cr); /* the minutes hand */ color = *CLUTTER_COLOR_DarkChameleon; color.alpha = 196; clutter_cairo_set_source_color (cr, &color); cairo_move_to (cr, 0, 0); cairo_line_to (cr, sinf (minutes) * 0.4, -cosf (minutes) * 0.4); cairo_stroke (cr); /* the hours hand */ cairo_move_to (cr, 0, 0); cairo_line_to (cr, sinf (hours) * 0.2, -cosf (hours) * 0.2); cairo_stroke (cr); g_date_time_unref (now); /* we're done drawing */ return TRUE; } static gboolean invalidate_clock (gpointer data_) { /* invalidate the contents of the canvas */ clutter_content_invalidate (data_); /* keep the timeout source */ return G_SOURCE_CONTINUE; } static guint idle_resize_id; static gboolean idle_resize (gpointer data) { ClutterActor *actor = data; float width, height; /* match the canvas size to the actor's */ clutter_actor_get_size (actor, &width, &height); clutter_canvas_set_size (CLUTTER_CANVAS (clutter_actor_get_content (actor)), ceilf (width), ceilf (height)); /* unset the guard */ idle_resize_id = 0; /* remove the timeout */ return G_SOURCE_REMOVE; } static void on_actor_resize (ClutterActor *actor, const ClutterActorBox *allocation, ClutterAllocationFlags flags, gpointer user_data) { /* throttle multiple actor allocations to one canvas resize; we use a guard * variable to avoid queueing multiple resize operations */ if (idle_resize_id == 0) idle_resize_id = clutter_threads_add_timeout (1000, idle_resize, actor); } int main (int argc, char *argv[]) { ClutterActor *stage, *actor; ClutterContent *canvas; /* initialize Clutter */ if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; /* create a resizable stage */ stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "2D Clock"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); clutter_actor_set_size (stage, 300, 300); clutter_actor_show (stage); /* our 2D canvas, courtesy of Cairo */ canvas = clutter_canvas_new (); clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300); actor = clutter_actor_new (); clutter_actor_set_content (actor, canvas); clutter_actor_set_content_scaling_filters (actor, CLUTTER_SCALING_FILTER_TRILINEAR, CLUTTER_SCALING_FILTER_LINEAR); clutter_actor_add_child (stage, actor); /* the actor now owns the canvas */ g_object_unref (canvas); /* bind the size of the actor to that of the stage */ clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0)); /* resize the canvas whenever the actor changes size */ g_signal_connect (actor, "allocation-changed", G_CALLBACK (on_actor_resize), NULL); /* quit on destroy */ g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* connect our drawing code */ g_signal_connect (canvas, "draw", G_CALLBACK (draw_clock), NULL); /* invalidate the canvas, so that we can draw before the main loop starts */ clutter_content_invalidate (canvas); /* set up a timer that invalidates the canvas every second */ clutter_threads_add_timeout (1000, invalidate_clock, canvas); clutter_main (); return EXIT_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/�������������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�015760� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/Makefile.am��������������������������������������������������������������0000664�0001750�0001750�00000000162�14211404421�020013� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SUBDIRS = accessibility conform interactive micro-bench performance EXTRA_DIST = README clutter-1.0.suppressions ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/�������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�020275� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-multitexture.c�������������������������������������0000664�0001750�0001750�00000016447�14211404421�025127� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <string.h> #include <glib.h> #include <glib-object.h> #include <gmodule.h> #include <clutter/clutter.h> #include <cogl/cogl.h> typedef struct _TestMultiLayerMaterialState { ClutterActor *group; CoglHandle alpha_tex; CoglHandle redhand_tex; gfloat *tex_coords; ClutterTimeline *timeline; CoglHandle material0; CoglMatrix tex_matrix0; CoglMatrix rot_matrix0; CoglHandle light_tex0; CoglHandle material1; CoglMatrix tex_matrix1; CoglMatrix rot_matrix1; CoglHandle light_tex1; } TestMultiLayerMaterialState; static void frame_cb (ClutterTimeline *timeline, gint frame_no, gpointer data) { TestMultiLayerMaterialState *state = data; cogl_matrix_multiply (&state->tex_matrix0, &state->tex_matrix0, &state->rot_matrix0); cogl_material_set_layer_matrix (state->material0, 2, &state->tex_matrix0); cogl_matrix_multiply (&state->tex_matrix1, &state->tex_matrix1, &state->rot_matrix1); cogl_material_set_layer_matrix (state->material1, 2, &state->tex_matrix1); } static void material_rectangle_paint (ClutterActor *actor, gpointer data) { TestMultiLayerMaterialState *state = data; cogl_push_matrix (); cogl_translate (150, 15, 0); cogl_set_source (state->material0); cogl_rectangle_with_multitexture_coords (0, 0, 200, 213, state->tex_coords, 12); cogl_translate (-300, -30, 0); cogl_set_source (state->material1); cogl_rectangle_with_multitexture_coords (0, 0, 200, 213, state->tex_coords, 12); cogl_pop_matrix (); } static void animation_completed_cb (ClutterAnimation *animation, TestMultiLayerMaterialState *state) { static gboolean go_back = FALSE; gdouble new_rotation_y; if (go_back) new_rotation_y = 30; else new_rotation_y = -30; go_back = !go_back; clutter_actor_animate_with_timeline (state->group, CLUTTER_LINEAR, state->timeline, "rotation-angle-y", new_rotation_y, "signal-after::completed", animation_completed_cb, state, NULL); } G_MODULE_EXPORT int test_cogl_multitexture_main (int argc, char *argv[]) { GError *error = NULL; ClutterActor *stage; ClutterColor stage_color = { 0x61, 0x56, 0x56, 0xff }; TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1); gfloat stage_w, stage_h; gchar **files; gfloat tex_coords[] = { /* tx1 ty1 tx2 ty2 */ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_get_size (stage, &stage_w, &stage_h); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl: Multi-texturing"); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* We create a non-descript actor that we know doesn't have a * default paint handler, so that we can easily control * painting in a paint signal handler, without having to * sub-class anything etc. */ state->group = clutter_group_new (); clutter_actor_set_position (state->group, stage_w / 2, stage_h / 2); g_signal_connect (state->group, "paint", G_CALLBACK(material_rectangle_paint), state); files = g_new (gchar*, 4); files[0] = g_build_filename (TESTS_DATADIR, "redhand_alpha.png", NULL); files[1] = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); files[2] = g_build_filename (TESTS_DATADIR, "light0.png", NULL); files[3] = NULL; state->alpha_tex = cogl_texture_new_from_file (files[0], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->alpha_tex) g_critical ("Failed to load redhand_alpha.png: %s", error->message); state->redhand_tex = cogl_texture_new_from_file (files[1], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->redhand_tex) g_critical ("Failed to load redhand.png: %s", error->message); state->light_tex0 = cogl_texture_new_from_file (files[2], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->light_tex0) g_critical ("Failed to load light0.png: %s", error->message); state->light_tex1 = cogl_texture_new_from_file (files[2], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->light_tex1) g_critical ("Failed to load light0.png: %s", error->message); g_strfreev (files); state->material0 = cogl_material_new (); cogl_material_set_layer (state->material0, 0, state->alpha_tex); cogl_material_set_layer (state->material0, 1, state->redhand_tex); cogl_material_set_layer (state->material0, 2, state->light_tex0); state->material1 = cogl_material_new (); cogl_material_set_layer (state->material1, 0, state->alpha_tex); cogl_material_set_layer (state->material1, 1, state->redhand_tex); cogl_material_set_layer (state->material1, 2, state->light_tex1); state->tex_coords = tex_coords; cogl_matrix_init_identity (&state->tex_matrix0); cogl_matrix_init_identity (&state->tex_matrix1); cogl_matrix_init_identity (&state->rot_matrix0); cogl_matrix_init_identity (&state->rot_matrix1); cogl_matrix_translate (&state->rot_matrix0, 0.5, 0.5, 0); cogl_matrix_rotate (&state->rot_matrix0, 10.0, 0, 0, 1.0); cogl_matrix_translate (&state->rot_matrix0, -0.5, -0.5, 0); cogl_matrix_translate (&state->rot_matrix1, 0.5, 0.5, 0); cogl_matrix_rotate (&state->rot_matrix1, -10.0, 0, 0, 1.0); cogl_matrix_translate (&state->rot_matrix1, -0.5, -0.5, 0); clutter_actor_set_anchor_point (state->group, 86, 125); clutter_container_add_actor (CLUTTER_CONTAINER(stage), state->group); state->timeline = clutter_timeline_new (2812); g_signal_connect (state->timeline, "new-frame", G_CALLBACK (frame_cb), state); clutter_actor_animate_with_timeline (state->group, CLUTTER_LINEAR, state->timeline, "rotation-angle-y", 30.0, "signal-after::completed", animation_completed_cb, state, NULL); /* start the timeline and thus the animations */ clutter_timeline_start (state->timeline); clutter_actor_show_all (stage); clutter_main(); cogl_handle_unref (state->material1); cogl_handle_unref (state->material0); cogl_handle_unref (state->alpha_tex); cogl_handle_unref (state->redhand_tex); cogl_handle_unref (state->light_tex0); cogl_handle_unref (state->light_tex1); free (state); return 0; } G_MODULE_EXPORT const char * test_cogl_multitexture_describe (void) { return "Multi-texturing support in Cogl."; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-tex-polygon.c��������������������������������������0000664�0001750�0001750�00000026167�14211404421�024641� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <gmodule.h> #include <stdlib.h> #include <clutter/clutter.h> #include <cogl/cogl.h> /* Coglbox declaration *--------------------------------------------------*/ G_BEGIN_DECLS #define TEST_TYPE_COGLBOX test_coglbox_get_type() #define TEST_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_IS_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ TEST_TYPE_COGLBOX)) #define TEST_IS_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ TEST_TYPE_COGLBOX)) #define TEST_COGLBOX_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) typedef struct _TestCoglbox TestCoglbox; typedef struct _TestCoglboxClass TestCoglboxClass; typedef struct _TestCoglboxPrivate TestCoglboxPrivate; struct _TestCoglbox { ClutterActor parent; /*< private >*/ TestCoglboxPrivate *priv; }; struct _TestCoglboxClass { ClutterActorClass parent_class; /* padding for future expansion */ void (*_test_coglbox1) (void); void (*_test_coglbox2) (void); void (*_test_coglbox3) (void); void (*_test_coglbox4) (void); }; static GType test_coglbox_get_type (void) G_GNUC_CONST; G_END_DECLS /* Coglbox private declaration *--------------------------------------------------*/ G_DEFINE_TYPE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR); #define TEST_COGLBOX_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TEST_TYPE_COGLBOX, TestCoglboxPrivate)) struct _TestCoglboxPrivate { CoglHandle sliced_tex, not_sliced_tex; gint frame; gboolean use_sliced; gboolean use_linear_filtering; }; /* Coglbox implementation *--------------------------------------------------*/ static void test_coglbox_fade_texture (gfloat x1, gfloat y1, gfloat x2, gfloat y2, gfloat tx1, gfloat ty1, gfloat tx2, gfloat ty2) { CoglTextureVertex vertices[4]; int i; vertices[0].x = x1; vertices[0].y = y1; vertices[0].z = 0; vertices[0].tx = tx1; vertices[0].ty = ty1; vertices[1].x = x1; vertices[1].y = y2; vertices[1].z = 0; vertices[1].tx = tx1; vertices[1].ty = ty2; vertices[2].x = x2; vertices[2].y = y2; vertices[2].z = 0; vertices[2].tx = tx2; vertices[2].ty = ty2; vertices[3].x = x2; vertices[3].y = y1; vertices[3].z = 0; vertices[3].tx = tx2; vertices[3].ty = ty1; for (i = 0; i < 4; i++) { cogl_color_init_from_4ub (&(vertices[i].color), 255, 255, 255, ((i ^ (i >> 1)) & 1) ? 0 : 128); cogl_color_premultiply (&(vertices[i].color)); } cogl_polygon (vertices, 4, TRUE); } static void test_coglbox_triangle_texture (int tex_width, int tex_height, gfloat x, gfloat y, gfloat tx1, gfloat ty1, gfloat tx2, gfloat ty2, gfloat tx3, gfloat ty3) { CoglTextureVertex vertices[3]; vertices[0].x = x + tx1 * tex_width; vertices[0].y = y + ty1 * tex_height; vertices[0].z = 0; vertices[0].tx = tx1; vertices[0].ty = ty1; vertices[1].x = x + tx2 * tex_width; vertices[1].y = y + ty2 * tex_height; vertices[1].z = 0; vertices[1].tx = tx2; vertices[1].ty = ty2; vertices[2].x = x + tx3 * tex_width; vertices[2].y = y + ty3 * tex_height; vertices[2].z = 0; vertices[2].tx = tx3; vertices[2].ty = ty3; cogl_polygon (vertices, 3, FALSE); } static void test_coglbox_paint (ClutterActor *self) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self); CoglHandle tex_handle = priv->use_sliced ? priv->sliced_tex : priv->not_sliced_tex; int tex_width = cogl_texture_get_width (tex_handle); int tex_height = cogl_texture_get_height (tex_handle); CoglHandle material = cogl_material_new (); cogl_material_set_layer (material, 0, tex_handle); cogl_material_set_layer_filters (material, 0, priv->use_linear_filtering ? COGL_MATERIAL_FILTER_LINEAR : COGL_MATERIAL_FILTER_NEAREST, priv->use_linear_filtering ? COGL_MATERIAL_FILTER_LINEAR : COGL_MATERIAL_FILTER_NEAREST); cogl_push_matrix (); cogl_translate (tex_width / 2, 0, 0); cogl_rotate (priv->frame, 0, 1, 0); cogl_translate (-tex_width / 2, 0, 0); /* Draw a hand and refect it */ cogl_set_source (material); cogl_rectangle_with_texture_coords (0, 0, tex_width, tex_height, 0, 0, 1, 1); test_coglbox_fade_texture (0, tex_height, tex_width, (tex_height * 3 / 2), 0.0, 1.0, 1.0, 0.5); cogl_pop_matrix (); cogl_push_matrix (); cogl_translate (tex_width * 3 / 2 + 60, 0, 0); cogl_rotate (priv->frame, 0, 1, 0); cogl_translate (-tex_width / 2 - 10, 0, 0); /* Draw the texture split into two triangles */ test_coglbox_triangle_texture (tex_width, tex_height, 0, 0, 0, 0, 0, 1, 1, 1); test_coglbox_triangle_texture (tex_width, tex_height, 20, 0, 0, 0, 1, 0, 1, 1); cogl_pop_matrix (); cogl_handle_unref (material); } static void test_coglbox_finalize (GObject *object) { G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object); } static void test_coglbox_dispose (GObject *object) { TestCoglboxPrivate *priv; priv = TEST_COGLBOX_GET_PRIVATE (object); cogl_handle_unref (priv->not_sliced_tex); cogl_handle_unref (priv->sliced_tex); G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object); } static void test_coglbox_init (TestCoglbox *self) { TestCoglboxPrivate *priv; GError *error = NULL; gchar *file; self->priv = priv = TEST_COGLBOX_GET_PRIVATE (self); priv->use_linear_filtering = FALSE; priv->use_sliced = FALSE; file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); priv->sliced_tex = cogl_texture_new_from_file (file, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, &error); if (priv->sliced_tex == COGL_INVALID_HANDLE) { if (error) { g_warning ("Texture loading failed: %s", error->message); g_error_free (error); error = NULL; } else g_warning ("Texture loading failed: <unknown>"); } priv->not_sliced_tex = cogl_texture_new_from_file (file, COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (priv->not_sliced_tex == COGL_INVALID_HANDLE) { if (error) { g_warning ("Texture loading failed: %s", error->message); g_error_free (error); } else g_warning ("Texture loading failed: <unknown>"); } free (file); } static void test_coglbox_class_init (TestCoglboxClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); gobject_class->finalize = test_coglbox_finalize; gobject_class->dispose = test_coglbox_dispose; actor_class->paint = test_coglbox_paint; g_type_class_add_private (gobject_class, sizeof (TestCoglboxPrivate)); } static ClutterActor* test_coglbox_new (void) { return g_object_new (TEST_TYPE_COGLBOX, NULL); } static void frame_cb (ClutterTimeline *timeline, gint elapsed_msecs, gpointer data) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (data); gdouble progress = clutter_timeline_get_progress (timeline); priv->frame = 360.0 * progress; clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); } static void update_toggle_text (ClutterText *button, gboolean val) { clutter_text_set_text (button, val ? "Enabled" : "Disabled"); } static gboolean on_toggle_click (ClutterActor *button, ClutterEvent *event, gboolean *toggle_val) { update_toggle_text (CLUTTER_TEXT (button), *toggle_val = !*toggle_val); return TRUE; } static ClutterActor * make_toggle (const char *label_text, gboolean *toggle_val) { ClutterActor *group = clutter_group_new (); ClutterActor *label = clutter_text_new_with_text ("Sans 14", label_text); ClutterActor *button = clutter_text_new_with_text ("Sans 14", ""); clutter_actor_set_reactive (button, TRUE); update_toggle_text (CLUTTER_TEXT (button), *toggle_val); clutter_actor_set_position (button, clutter_actor_get_width (label) + 10, 0); clutter_container_add (CLUTTER_CONTAINER (group), label, button, NULL); g_signal_connect (button, "button-press-event", G_CALLBACK (on_toggle_click), toggle_val); return group; } G_MODULE_EXPORT int test_cogl_tex_polygon_main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *coglbox; ClutterActor *filtering_toggle; ClutterActor *slicing_toggle; ClutterActor *note; ClutterTimeline *timeline; ClutterColor blue = { 0x30, 0x30, 0xff, 0xff }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* Stage */ stage = clutter_stage_new (); clutter_stage_set_color (CLUTTER_STAGE (stage), &blue); clutter_actor_set_size (stage, 640, 480); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Texture Polygon"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* Cogl Box */ coglbox = test_coglbox_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox); /* Timeline for animation */ timeline = clutter_timeline_new (6000); clutter_timeline_set_loop (timeline, TRUE); g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox); clutter_timeline_start (timeline); /* Labels for toggling settings */ slicing_toggle = make_toggle ("Texture slicing: ", &(TEST_COGLBOX_GET_PRIVATE (coglbox) ->use_sliced)); clutter_actor_set_position (slicing_toggle, 0, clutter_actor_get_height (stage) - clutter_actor_get_height (slicing_toggle)); filtering_toggle = make_toggle ("Linear filtering: ", &(TEST_COGLBOX_GET_PRIVATE (coglbox) ->use_linear_filtering)); clutter_actor_set_position (filtering_toggle, 0, clutter_actor_get_y (slicing_toggle) - clutter_actor_get_height (filtering_toggle)); note = clutter_text_new_with_text ("Sans 10", "<- Click to change"); clutter_actor_set_position (note, clutter_actor_get_width (filtering_toggle) + 10, (clutter_actor_get_height (stage) + clutter_actor_get_y (filtering_toggle)) / 2 - clutter_actor_get_height (note) / 2); clutter_container_add (CLUTTER_CONTAINER (stage), slicing_toggle, filtering_toggle, note, NULL); clutter_actor_show (stage); clutter_main (); return 0; } G_MODULE_EXPORT const char * test_cogl_tex_polygon_describe (void) { return "Texture polygon primitive."; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-text-field.c��������������������������������������������0000664�0001750�0001750�00000025410�14211404421�023465� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> static void on_entry_activate (ClutterText *text, gpointer data) { g_print ("Text activated: %s (cursor: %d, selection at: %d)\n", clutter_text_get_text (text), clutter_text_get_cursor_position (text), clutter_text_get_selection_bound (text)); } #define is_hex_digit(c) (((c) >= '0' && (c) <= '9') || \ ((c) >= 'a' && (c) <= 'f') || \ ((c) >= 'A' && (c) <= 'F')) #define to_hex_digit(c) (((c) <= '9') ? (c) - '0' : ((c) & 7) + 9) static gboolean on_captured_event (ClutterText *text, ClutterEvent *event, gpointer dummy G_GNUC_UNUSED) { gboolean is_unicode_mode = FALSE; gunichar c; guint keyval; if (event->type != CLUTTER_KEY_PRESS) return FALSE; is_unicode_mode = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (text), "unicode-mode")); c = clutter_event_get_key_unicode (event); keyval = clutter_event_get_key_symbol (event); if (keyval == CLUTTER_KEY_U) { if (is_unicode_mode) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); clutter_text_set_preedit_string (text, NULL, NULL, 0); g_object_set_data (G_OBJECT (text), "unicode-mode", GINT_TO_POINTER (FALSE)); g_object_set_data (G_OBJECT (text), "unicode-str", NULL); g_string_free (str, TRUE); return FALSE; } if (clutter_event_has_control_modifier (event)) { PangoAttrList *attrs; PangoAttribute *a; GString *str = g_string_sized_new (5); g_string_append (str, "u"); g_object_set_data (G_OBJECT (text), "unicode-mode", GINT_TO_POINTER (TRUE)); g_object_set_data (G_OBJECT (text), "unicode-str", str); attrs = pango_attr_list_new (); a = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); a->start_index = 0; a->end_index = str->len; pango_attr_list_insert (attrs, a); clutter_text_set_preedit_string (text, str->str, attrs, str->len); pango_attr_list_unref (attrs); return TRUE; } return FALSE; } else if (is_unicode_mode && is_hex_digit (c)) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); PangoAttrList *attrs; PangoAttribute *a; gchar buf[8]; gsize len; len = g_unichar_to_utf8 (c, buf); buf[len] = '\0'; g_string_append (str, buf); g_print ("added '%s' to '%s' (len:%d)\n", buf, str->str, (int) str->len); attrs = pango_attr_list_new (); a = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); a->start_index = 0; a->end_index = str->len; pango_attr_list_insert (attrs, a); clutter_text_set_preedit_string (text, str->str, attrs, str->len); pango_attr_list_unref (attrs); return TRUE; } else if (is_unicode_mode && (keyval == CLUTTER_KEY_BackSpace)) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); PangoAttrList *attrs; PangoAttribute *a; g_string_truncate (str, str->len - 1); attrs = pango_attr_list_new (); a = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); a->start_index = 0; a->end_index = str->len; pango_attr_list_insert (attrs, a); clutter_text_set_preedit_string (text, str->str, attrs, str->len); pango_attr_list_unref (attrs); return TRUE; } else if (is_unicode_mode && (keyval == CLUTTER_KEY_Return || keyval == CLUTTER_KEY_KP_Enter || keyval == CLUTTER_KEY_ISO_Enter || keyval == CLUTTER_KEY_KP_Space)) { GString *str = g_object_get_data (G_OBJECT (text), "unicode-str"); const gchar *contents = clutter_text_get_text (text); gunichar uchar = 0; gchar ch; gint i; clutter_text_set_preedit_string (text, NULL, NULL, 0); g_object_set_data (G_OBJECT (text), "unicode-mode", GINT_TO_POINTER (FALSE)); g_object_set_data (G_OBJECT (text), "unicode-str", NULL); for (i = 0; i < str->len; i++) { ch = str->str[i]; if (is_hex_digit (ch)) uchar += ((gunichar) to_hex_digit (ch) << ((4 - i) * 4)); } g_assert (g_unichar_validate (uchar)); g_string_overwrite (str, 0, contents); g_string_insert_unichar (str, clutter_text_get_cursor_position (text), uchar); i = clutter_text_get_cursor_position (text); clutter_text_set_text (text, str->str); if (i >= 0) i += 1; else i = -1; clutter_text_set_cursor_position (text, i); clutter_text_set_selection_bound (text, i); g_string_free (str, TRUE); return TRUE; } else return FALSE; } static ClutterActor * create_label (const ClutterColor *color, const gchar *text) { ClutterActor *retval = clutter_text_new (); clutter_text_set_color (CLUTTER_TEXT (retval), color); clutter_text_set_markup (CLUTTER_TEXT (retval), text); clutter_text_set_editable (CLUTTER_TEXT (retval), FALSE); clutter_text_set_selectable (CLUTTER_TEXT (retval), FALSE); clutter_text_set_single_line_mode (CLUTTER_TEXT (retval), TRUE); clutter_text_set_ellipsize (CLUTTER_TEXT (retval), PANGO_ELLIPSIZE_END); return retval; } static ClutterActor * create_entry (const ClutterColor *color, const gchar *text, PangoAttrList *attrs, gunichar password_char, gint max_length) { ClutterActor *retval = clutter_text_new_full (NULL, text, color); ClutterColor selection = { 0, }; ClutterColor selected_text = { 0x00, 0x00, 0xff, 0xff }; clutter_actor_set_reactive (retval, TRUE); clutter_color_darken (color, &selection); clutter_text_set_editable (CLUTTER_TEXT (retval), TRUE); clutter_text_set_selectable (CLUTTER_TEXT (retval), TRUE); clutter_text_set_activatable (CLUTTER_TEXT (retval), TRUE); clutter_text_set_single_line_mode (CLUTTER_TEXT (retval), TRUE); clutter_text_set_password_char (CLUTTER_TEXT (retval), password_char); clutter_text_set_cursor_color (CLUTTER_TEXT (retval), &selection); clutter_text_set_max_length (CLUTTER_TEXT (retval), max_length); clutter_text_set_selected_text_color (CLUTTER_TEXT (retval), &selected_text); clutter_actor_set_background_color (retval, CLUTTER_COLOR_LightGray); if (attrs) clutter_text_set_attributes (CLUTTER_TEXT (retval), attrs); g_signal_connect (retval, "activate", G_CALLBACK (on_entry_activate), NULL); g_signal_connect (retval, "captured-event", G_CALLBACK (on_captured_event), NULL); return retval; } G_MODULE_EXPORT gint test_text_field_main (gint argc, gchar **argv) { ClutterActor *stage; ClutterActor *box, *label, *entry; ClutterLayoutManager *table; PangoAttrList *entry_attrs; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Text Fields"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); table = clutter_table_layout_new (); clutter_table_layout_set_column_spacing (CLUTTER_TABLE_LAYOUT (table), 6); clutter_table_layout_set_row_spacing (CLUTTER_TABLE_LAYOUT (table), 6); box = clutter_actor_new (); clutter_actor_set_layout_manager (box, table); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_WIDTH, -24.0)); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, -24.0)); clutter_actor_set_position (box, 12, 12); clutter_actor_add_child (stage, box); label = create_label (CLUTTER_COLOR_White, "<b>Input field:</b>"); g_object_set (label, "min-width", 150.0, NULL); clutter_actor_add_child (box, label); clutter_layout_manager_child_set (table, CLUTTER_CONTAINER (box), label, "row", 0, "column", 0, "x-expand", FALSE, "y-expand", FALSE, NULL); entry_attrs = pango_attr_list_new (); pango_attr_list_insert (entry_attrs, pango_attr_underline_new (PANGO_UNDERLINE_ERROR)); pango_attr_list_insert (entry_attrs, pango_attr_underline_color_new (65535, 0, 0)); entry = create_entry (CLUTTER_COLOR_Black, "somme misspeeled textt", entry_attrs, 0, 0); clutter_actor_add_child (box, entry); clutter_layout_manager_child_set (table, CLUTTER_CONTAINER (box), entry, "row", 0, "column", 1, "x-expand", TRUE, "x-fill", TRUE, "y-expand", FALSE, NULL); clutter_actor_grab_key_focus (entry); label = create_label (CLUTTER_COLOR_White, "<b>A very long password field:</b>"); clutter_actor_add_child (box, label); clutter_layout_manager_child_set (table, CLUTTER_CONTAINER (box), label, "row", 1, "column", 0, "x-expand", FALSE, "y-expand", FALSE, NULL); entry = create_entry (CLUTTER_COLOR_Black, "password", NULL, '*', 8); clutter_actor_add_child (box, entry); clutter_layout_manager_child_set (table, CLUTTER_CONTAINER (box), entry, "row", 1, "column", 1, "x-expand", TRUE, "x-fill", TRUE, "y-expand", FALSE, NULL); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_text_field_describe (void) { return "Text actor single-line and password mode support\n" "\n" "This test checks the :single-line-mode and :password-char properties of\n" "the ClutterText actor, plus the password hint feature and the :max-length\n" "property."; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-animation.c���������������������������������������������0000664�0001750�0001750�00000007230�14211404421�023377� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> static gboolean is_expanded = FALSE; static void on_rect_transitions_completed (ClutterActor *actor) { is_expanded = !is_expanded; g_print ("Animation complete\n"); clutter_actor_set_reactive (actor, TRUE); } static void on_clicked (ClutterClickAction *action, ClutterActor *actor, gpointer dummy G_GNUC_UNUSED) { ClutterAnimation *animation; gfloat old_x, old_y, new_x, new_y; gfloat old_width, old_height, new_width, new_height; gdouble new_angle; const ClutterColor *new_color; guint8 new_opacity; clutter_actor_get_position (actor, &old_x, &old_y); clutter_actor_get_size (actor, &old_width, &old_height); /* determine the final state of the animation depending on * the state of the actor */ if (!is_expanded) { new_x = old_x - 100; new_y = old_y - 100; new_width = old_width + 200; new_height = old_height + 200; new_angle = 360.0; new_color = CLUTTER_COLOR_DarkScarletRed; new_opacity = 255; } else { new_x = old_x + 100; new_y = old_y + 100; new_width = old_width - 200; new_height = old_height - 200; new_angle = 0.0; new_color = CLUTTER_COLOR_LightOrange; new_opacity = 128; } clutter_actor_save_easing_state (actor); clutter_actor_set_easing_mode (actor, CLUTTER_EASE_IN_EXPO); clutter_actor_set_easing_duration (actor, 2000); clutter_actor_set_position (actor, new_x, new_y); clutter_actor_set_size (actor, new_width, new_height); clutter_actor_set_background_color (actor, new_color); clutter_actor_set_rotation_angle (actor, CLUTTER_Z_AXIS, new_angle); clutter_actor_set_reactive (actor, FALSE); /* animate the opacity halfway through, with a different pacing */ clutter_actor_save_easing_state (actor); clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR); clutter_actor_set_easing_delay (actor, 1000); clutter_actor_set_easing_duration (actor, 1000); clutter_actor_set_opacity (actor, new_opacity); clutter_actor_restore_easing_state (actor); clutter_actor_restore_easing_state (actor); } G_MODULE_EXPORT int test_animation_main (int argc, char *argv[]) { ClutterActor *stage, *rect; ClutterColor rect_color = { 0x44, 0xdd, 0x44, 0xff }; ClutterAction *action; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); clutter_stage_set_title (CLUTTER_STAGE (stage), "Animation"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); rect = clutter_actor_new (); clutter_actor_set_background_color (rect, CLUTTER_COLOR_LightOrange); clutter_actor_add_child (stage, rect); clutter_actor_set_size (rect, 50, 50); clutter_actor_set_pivot_point (rect, .5f, .5f); clutter_actor_set_translation (rect, -25, -25, 0); clutter_actor_set_position (rect, clutter_actor_get_width (stage) / 2, clutter_actor_get_height (stage) / 2); clutter_actor_set_opacity (rect, 128); clutter_actor_set_reactive (rect, TRUE); g_signal_connect (rect, "transitions-completed", G_CALLBACK (on_rect_transitions_completed), NULL); action = clutter_click_action_new (); g_signal_connect (action, "clicked", G_CALLBACK (on_clicked), NULL); clutter_actor_add_action_with_name (rect, "click", action); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_animation_describe (void) { return "Simple animation demo"; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-tex-tile.c�����������������������������������������0000664�0001750�0001750�00000012631�14211404421�024076� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <gmodule.h> #include <stdlib.h> #include <math.h> #include <clutter/clutter.h> #include <cogl/cogl.h> /* Coglbox declaration *--------------------------------------------------*/ G_BEGIN_DECLS #define TEST_TYPE_COGLBOX test_coglbox_get_type() #define TEST_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_IS_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ TEST_TYPE_COGLBOX)) #define TEST_IS_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ TEST_TYPE_COGLBOX)) #define TEST_COGLBOX_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) typedef struct _TestCoglbox TestCoglbox; typedef struct _TestCoglboxClass TestCoglboxClass; typedef struct _TestCoglboxPrivate TestCoglboxPrivate; struct _TestCoglbox { ClutterActor parent; /*< private >*/ TestCoglboxPrivate *priv; }; struct _TestCoglboxClass { ClutterActorClass parent_class; /* padding for future expansion */ void (*_test_coglbox1) (void); void (*_test_coglbox2) (void); void (*_test_coglbox3) (void); void (*_test_coglbox4) (void); }; static GType test_coglbox_get_type (void) G_GNUC_CONST; G_END_DECLS /* Coglbox private declaration *--------------------------------------------------*/ G_DEFINE_TYPE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR); #define TEST_COGLBOX_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TEST_TYPE_COGLBOX, TestCoglboxPrivate)) struct _TestCoglboxPrivate { CoglHandle cogl_tex_id; gdouble animation_progress; }; /* Coglbox implementation *--------------------------------------------------*/ static void test_coglbox_paint (ClutterActor *self) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self); gfloat texcoords[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; gfloat angle; gfloat frac; gint t; angle = priv->animation_progress * 2 * G_PI; frac = ((priv->animation_progress <= 0.5f ? priv->animation_progress : 1.0f - priv->animation_progress) + 0.5f) * 2.0f; for (t=0; t<4; t+=2) { texcoords[t] += cos (angle); texcoords[t+1] += sin (angle); texcoords[t] *= frac; texcoords[t+1] *= frac; } priv = TEST_COGLBOX_GET_PRIVATE (self); cogl_push_matrix (); cogl_set_source_color4ub (0x66, 0x66, 0xdd, 0xff); cogl_rectangle (0, 0, 400, 400); cogl_translate (100, 100, 0); cogl_set_source_texture (priv->cogl_tex_id); cogl_rectangle_with_texture_coords (0, 0, 200, 213, texcoords[0], texcoords[1], texcoords[2], texcoords[3]); cogl_pop_matrix(); } static void test_coglbox_finalize (GObject *object) { G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object); } static void test_coglbox_dispose (GObject *object) { TestCoglboxPrivate *priv; priv = TEST_COGLBOX_GET_PRIVATE (object); cogl_handle_unref (priv->cogl_tex_id); G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object); } static void test_coglbox_init (TestCoglbox *self) { TestCoglboxPrivate *priv; gchar *file; self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); priv->cogl_tex_id = cogl_texture_new_from_file (file, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); free (file); } static void test_coglbox_class_init (TestCoglboxClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); gobject_class->finalize = test_coglbox_finalize; gobject_class->dispose = test_coglbox_dispose; actor_class->paint = test_coglbox_paint; g_type_class_add_private (gobject_class, sizeof (TestCoglboxPrivate)); } static ClutterActor* test_coglbox_new (void) { return g_object_new (TEST_TYPE_COGLBOX, NULL); } static void frame_cb (ClutterTimeline *timeline, gint msecs, gpointer data) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (data); priv->animation_progress = clutter_timeline_get_progress (timeline); clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); } G_MODULE_EXPORT int test_cogl_tex_tile_main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *coglbox; ClutterTimeline *timeline; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* Stage */ stage = clutter_stage_new (); clutter_actor_set_size (stage, 400, 400); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Texture Tiling"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* Cogl Box */ coglbox = test_coglbox_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox); /* Timeline for animation */ timeline = clutter_timeline_new (6000); /* 6 second duration */ clutter_timeline_set_loop (timeline, TRUE); g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox); clutter_timeline_start (timeline); clutter_actor_show_all (stage); clutter_main (); return 0; } G_MODULE_EXPORT const char * test_cogl_tex_tile_describe (void) { return "Texture tiling."; } �������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-animator.c����������������������������������������������0000664�0001750�0001750�00000012016�14211404421�023230� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> static ClutterAnimator *animator; static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { GError *error = NULL; ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *rectangle; gchar *file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); rectangle = clutter_texture_new_from_file (file, &error); if (rectangle == NULL) g_error ("image load failed: %s", error->message); free (file); clutter_actor_set_size (rectangle, 128, 128); clutter_color_free (color); return rectangle; } static gboolean nuke_one (gpointer actor) { clutter_actor_destroy (actor); return FALSE; } #define COUNT 4 static void reverse_timeline (ClutterTimeline *timeline, gpointer data) { ClutterTimelineDirection direction = clutter_timeline_get_direction (timeline); if (direction == CLUTTER_TIMELINE_FORWARD) clutter_timeline_set_direction (timeline, CLUTTER_TIMELINE_BACKWARD); else clutter_timeline_set_direction (timeline, CLUTTER_TIMELINE_FORWARD); clutter_timeline_start (timeline); } G_MODULE_EXPORT gint test_animator_main (gint argc, gchar **argv) { ClutterActor *stage; ClutterActor *rects[COUNT]; gint i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Animator"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); for (i = 0; i < COUNT; i++) { rects[i] = new_rect (255 * (i * 1.0 / COUNT), 50, 160, 255); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rects[i]); clutter_actor_set_anchor_point (rects[i], 64, 64); clutter_actor_set_position (rects[i], 320.0, 240.0); clutter_actor_set_opacity (rects[i], 0x70); } clutter_threads_add_timeout (10000, nuke_one, rects[2]); animator = clutter_animator_new (); /* Note: when both animations are active for the same actor at the same * time there is a race, such races should be handled by avoiding * controlling the same properties from multiple animations. This is * an intentional design flaw of this test for testing the corner case. */ clutter_animator_set (animator, rects[0], "x", 1, 0.0, 180.0, rects[0], "x", CLUTTER_LINEAR, 0.25, 450.0, rects[0], "x", CLUTTER_LINEAR, 0.5, 450.0, rects[0], "x", CLUTTER_LINEAR, 0.75, 180.0, rects[0], "x", CLUTTER_LINEAR, 1.0, 180.0, rects[0], "y", -1, 0.0, 100.0, rects[0], "y", CLUTTER_LINEAR, 0.25, 100.0, rects[0], "y", CLUTTER_LINEAR, 0.5, 380.0, rects[0], "y", CLUTTER_LINEAR, 0.75, 380.0, rects[0], "y", CLUTTER_LINEAR, 1.0, 100.0, rects[3], "x", 0, 0.0, 180.0, rects[3], "x", CLUTTER_LINEAR, 0.25, 180.0, rects[3], "x", CLUTTER_LINEAR, 0.5, 450.0, rects[3], "x", CLUTTER_LINEAR, 0.75, 450.0, rects[3], "x", CLUTTER_LINEAR, 1.0, 180.0, rects[3], "y", 0, 0.0, 100.0, rects[3], "y", CLUTTER_LINEAR, 0.25, 380.0, rects[3], "y", CLUTTER_LINEAR, 0.5, 380.0, rects[3], "y", CLUTTER_LINEAR, 0.75, 100.0, rects[3], "y", CLUTTER_LINEAR, 1.0, 100.0, rects[2], "rotation-angle-y", 0, 0.0, 0.0, rects[2], "rotation-angle-y", CLUTTER_LINEAR, 1.0, 360.0, rects[1], "scale-x", 0, 0.0, 1.0, rects[1], "scale-x", CLUTTER_LINEAR, 1.0, 2.0, rects[1], "scale-y", 0, 0.0, 1.0, rects[1], "scale-y", CLUTTER_LINEAR, 1.0, 2.0, NULL); clutter_actor_set_scale (rects[0], 1.4, 1.4); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[0]), "x", TRUE); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[0]), "y", TRUE); clutter_animator_property_set_interpolation (animator, G_OBJECT (rects[0]), "x", CLUTTER_INTERPOLATION_CUBIC); clutter_animator_property_set_interpolation (animator, G_OBJECT (rects[0]), "y", CLUTTER_INTERPOLATION_CUBIC); clutter_stage_hide_cursor(CLUTTER_STAGE (stage)); clutter_actor_show (stage); clutter_animator_set_duration (animator, 5000); g_signal_connect (clutter_animator_start (animator), "completed", G_CALLBACK (reverse_timeline), NULL); clutter_main (); g_object_unref (animator); return EXIT_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-rotate-zoom.c�������������������������������������������0000664�0001750�0001750�00000006215�14211404421�023702� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2013 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * Boston, MA 02111-1307, USA. * */ #include <stdlib.h> #include <math.h> #include <cairo.h> #include <glib.h> #include <clutter/clutter.h> #include <gdk-pixbuf/gdk-pixbuf.h> #define STAGE_WIDTH 800 #define STAGE_HEIGHT 550 static ClutterActor * create_hand (void) { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL); ClutterContent *image = clutter_image_new (); ClutterActor *actor = clutter_actor_new (); clutter_image_set_data (CLUTTER_IMAGE (image), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_has_alpha (pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), NULL); clutter_actor_set_content (actor, image); clutter_actor_set_size (actor, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); clutter_actor_set_reactive (actor, TRUE); g_object_unref (pixbuf); return actor; } G_MODULE_EXPORT int test_rotate_zoom_main (int argc, char *argv[]) { ClutterActor *stage, *actor; gfloat width, height; /* initialize Clutter */ if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; /* create a resizable stage */ stage = clutter_stage_new (); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_stage_set_title (CLUTTER_STAGE (stage), "Rotate and Zoom actions"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); clutter_actor_set_reactive (stage, FALSE); clutter_actor_show (stage); actor = create_hand (); clutter_actor_add_action (actor, clutter_rotate_action_new ()); clutter_actor_add_action (actor, clutter_zoom_action_new ()); clutter_actor_add_child (stage, actor); clutter_actor_get_size (actor, &width, &height); clutter_actor_set_position (actor, STAGE_WIDTH / 2 - width / 2, STAGE_HEIGHT / 2 - height / 2); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_rotate_zoom_describe (void) { return "Rotates and zooms an actor using touch events"; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-texture-async.c�����������������������������������������0000664�0001750�0001750�00000010007�14211404421�024227� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> enum { LOAD_SYNC, LOAD_DATA_ASYNC, LOAD_ASYNC }; static ClutterActor *stage = NULL; static void on_load_finished (ClutterTexture *texture, const GError *error, gpointer user_data) { gint load_type = GPOINTER_TO_INT (user_data); const gchar *load_str = NULL; switch (load_type) { case LOAD_SYNC: load_str = "synchronous loading"; break; case LOAD_DATA_ASYNC: load_str = "asynchronous data loading"; break; case LOAD_ASYNC: load_str = "asynchronous loading"; break; } if (error != NULL) g_print ("%s failed: %s\n", load_str, error->message); else g_print ("%s successful\n", load_str); } static void size_change_cb (ClutterTexture *texture, gint width, gint height, gpointer user_data) { clutter_actor_set_size (user_data, width, height); } static gboolean task (gpointer user_data) { const gchar *path = user_data; ClutterActor *image[3]; ClutterActor *clone[3]; gint i; image[0] = g_object_new (CLUTTER_TYPE_TEXTURE, NULL); g_signal_connect (image[0], "load-finished", G_CALLBACK (on_load_finished), GINT_TO_POINTER (LOAD_SYNC)); image[1] = g_object_new (CLUTTER_TYPE_TEXTURE, "load-data-async", TRUE, NULL); g_signal_connect (image[1], "load-finished", G_CALLBACK (on_load_finished), GINT_TO_POINTER (LOAD_DATA_ASYNC)); image[2] = g_object_new (CLUTTER_TYPE_TEXTURE, "load-async", TRUE, NULL); g_signal_connect (image[2], "load-finished", G_CALLBACK (on_load_finished), GINT_TO_POINTER (LOAD_ASYNC)); for (i = 0; i < 3; i++) { GError *error = NULL; clutter_texture_set_from_file (CLUTTER_TEXTURE (image[i]), path, &error); if (error != NULL) g_error ("Unable to load image at '%s': %s", path != NULL ? path : "<unknown>", error->message); } for (i = 0; i < 3; i++) clutter_container_add_actor (CLUTTER_CONTAINER (stage), image[i]); for (i = 0; i < 3; i++) { clutter_actor_set_position (image[i], 50 + i * 100, 0 + i * 50); clutter_actor_set_depth (image[i], -2500); clone[i] = clutter_clone_new (image[i]); g_signal_connect (image[i], "size-change", G_CALLBACK (size_change_cb), clone[i]); clutter_container_add_actor (CLUTTER_CONTAINER (stage), clone[i]); clutter_actor_set_position (clone[i], 50 + i * 100, 150 + i * 50 + 100); } for (i = 0; i < 3; i++) { clutter_actor_save_easing_state (image[i]); clutter_actor_set_easing_duration (image[i], 5000); clutter_actor_set_depth (image[i], 0); clutter_actor_restore_easing_state (image[i]); } return FALSE; } static void cleanup_task (gpointer data) { } G_MODULE_EXPORT gint test_texture_async_main (int argc, char *argv[]) { gchar *path; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Asynchronous Texture Loading"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_actor_show (stage); path = (argc > 1) ? g_strdup (argv[1]) : g_build_filename (TESTS_DATADIR, "redhand.png", NULL); clutter_threads_add_timeout_full (G_PRIORITY_DEFAULT, 500, task, path, cleanup_task); clutter_threads_enter (); clutter_main (); clutter_threads_leave (); free (path); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_texture_async_describe (void) { return "Texture asynchronous loading using threads"; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/Makefile.am��������������������������������������������������0000664�0001750�0001750�00000007143�14211404421�022336� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UNIT_TESTS = \ test-texture-slicing.c \ test-texture-async.c \ test-texture-material.c \ test-events.c \ test-scale.c \ test-actors.c \ test-shader-effects.c \ test-script.c \ test-grab.c \ test-cogl-shader-arbfp.c \ test-cogl-shader-glsl.c \ test-animator.c \ test-state.c \ test-state-animator.c \ test-fbo.c \ test-multistage.c \ test-cogl-tex-tile.c \ test-cogl-tex-convert.c \ test-cogl-tex-foreign.c \ test-cogl-offscreen.c \ test-cogl-tex-polygon.c \ test-cogl-multitexture.c \ test-stage-read-pixels.c \ test-paint-wrapper.c \ test-texture-quality.c \ test-layout.c \ test-animation.c \ test-easing.c \ test-binding-pool.c \ test-text.c \ test-text-field.c \ test-cairo-clock.c \ test-cairo-flowers.c \ test-cogl-vertex-buffer.c \ test-stage-sizing.c \ test-scrolling.c \ test-swipe-action.c \ test-cogl-point-sprites.c \ test-table-layout.c \ test-path-constraint.c \ test-state-script.c \ test-devices.c \ test-content.c \ test-keyframe-transition.c \ test-bind-constraint.c \ test-touch-events.c \ test-rotate-zoom.c if X11_TESTS UNIT_TESTS += test-pixmap.c endif if PIXBUF_TESTS UNIT_TESTS += \ test-image.c endif SHEXT = $(EXEEXT) # For convenience, this provides a way to easily run individual unit tests: wrappers: stamp-test-interactive @true GIT_IGNORE_EXTRA = \ stamp-test-interactive \ stamp-test-unit-names \ test-unit-names.h \ $(UNIT_TESTS:.c=$(SHEXT)) stamp-test-interactive: Makefile @wrapper=$(abs_builddir)/wrapper.sh ; \ chmod +x $$wrapper && \ for i in $(UNIT_TESTS); \ do \ test_bin=$${i%*.c} ; \ echo " GEN $$test_bin" ; \ ( echo "#!/bin/sh" ; \ echo "$$wrapper $$test_bin \$$@" \ ) > $$test_bin$(SHEXT) ; \ chmod +x $$test_bin$(SHEXT) ; \ done \ && echo timestamp > $(@F) test-unit-names.h: stamp-test-unit-names @true stamp-test-unit-names: Makefile @( echo "/* ** This file is autogenerated. Do not edit. ** */" ; \ echo "" ; \ echo "const char *test_unit_names[] = {" ) > test-unit-names.h ; \ for i in $(UNIT_TESTS); \ do \ test_bin=$${i%*.c} ; \ echo " \"$$test_bin\"," >> test-unit-names.h ; \ done \ && echo "};" >> test-unit-names.h \ && echo timestamp > $(@F) clean-wrappers: @for i in $(UNIT_TESTS); \ do \ test_bin=$${i%*.c} ; \ echo " RM $$test_bin"; \ rm -f $$test_bin$(SHEXT); \ done \ && rm -f stamp-test-unit-names \ && rm -f stamp-test-interactive .PHONY: wrappers clean-wrappers common_ldadd = \ $(top_builddir)/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl/libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la check_PROGRAMS = test-interactive check_SCRIPTS = wrappers test_interactive_SOURCES = test-main.c $(UNIT_TESTS) nodist_test_interactive_SOURCES = test-unit-names.h test_interactive_CFLAGS = $(CLUTTER_CFLAGS) $(GDK_PIXBUF_CFLAGS) test_interactive_CPPFLAGS = \ -DTESTS_DATADIR=\""$(abs_srcdir)"\" \ -DG_DISABLE_SINGLE_INCLUDES \ -DGLIB_DISABLE_DEPRECATION_WARNINGS \ -DCOGL_DISABLE_DEPRECATION_WARNINGS \ -DCLUTTER_DISABLE_DEPRECATION_WARNINGS \ -I$(top_srcdir)/../cogl \ -I$(top_builddir)/../cogl \ -I$(top_builddir)/../cogl/cogl \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(top_srcdir)/clutter \ -I$(top_builddir)/clutter test_interactive_LDFLAGS = -export-dynamic test_interactive_LDADD = $(CLUTTER_LIBS) $(GDK_PIXBUF_LIBS) $(common_ldadd) $(LIBM) EXTRA_DIST = \ wrapper.sh.in \ test-script.json \ test-script-signals.json \ redhand.png DISTCLEANFILES = wrapper.sh .gitignore test-unit-names.h BUILT_SOURCES = test-unit-names.h clean-local: clean-wrappers �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-shader-effects.c����������������������������������������0000664�0001750�0001750�00000006055�14211404421�024307� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <string.h> #include <glib.h> #include <gmodule.h> #include <clutter/clutter.h> G_MODULE_EXPORT int test_shader_effects_main (int argc, char *argv[]) { ClutterTimeline *timeline; ClutterActor *stage, *hand, *label, *rect; gchar *file; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* Make a timeline */ timeline = clutter_timeline_new (7692); clutter_timeline_set_repeat_count (timeline, -1); stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Rotations"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium3); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* Make a hand */ file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); hand = clutter_texture_new_from_file (file, NULL); if (!hand) g_error("Unable to load '%s'", file); free (file); clutter_actor_set_position (hand, 326, 265); clutter_actor_add_effect_with_name (hand, "desaturate", clutter_desaturate_effect_new (0.75)); clutter_actor_add_effect_with_name (hand, "blur", clutter_blur_effect_new ()); clutter_actor_animate_with_timeline (hand, CLUTTER_LINEAR, timeline, "@effects.desaturate.factor", 1.0, "rotation-angle-z", 360.0, "fixed::anchor-x", 86.0, "fixed::anchor-y", 125.0, "opacity", 128, NULL); rect = clutter_rectangle_new_with_color (CLUTTER_COLOR_DarkOrange); clutter_actor_add_effect_with_name (rect, "blur", clutter_blur_effect_new ()); clutter_actor_set_position (rect, 415, 215); clutter_actor_set_size (rect, 150, 150); clutter_actor_animate_with_timeline (rect, CLUTTER_LINEAR, timeline, "rotation-angle-z", 360.0, "fixed::anchor-x", 75.0, "fixed::anchor-y", 75.0, NULL); label = clutter_text_new_with_text ("Mono 16", "The Wonder\n" "of the\n" "Spinning Hand"); clutter_text_set_line_alignment (CLUTTER_TEXT (label), PANGO_ALIGN_CENTER); clutter_actor_set_position (label, 336, 275); clutter_actor_set_size (label, 500, 100); clutter_actor_animate_with_timeline (label, CLUTTER_LINEAR, timeline, "rotation-angle-z", 360.0, "fixed::anchor-x", 86.0, "fixed::anchor-y", 125.0, NULL); clutter_container_add (CLUTTER_CONTAINER (stage), rect, hand, label, NULL); /* start the timeline and thus the animations */ clutter_timeline_start (timeline); clutter_actor_show_all (stage); clutter_main(); g_object_unref (timeline); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-state.c�������������������������������������������������0000664�0001750�0001750�00000015521�14211404421�022542� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> #define STAGE_WIDTH 1024 #define STAGE_HEIGHT 768 #define ACTOR_WIDTH 128 #define ACTOR_HEIGHT 128 #define COLS (STAGE_WIDTH/ACTOR_WIDTH) #define ROWS (STAGE_HEIGHT/ACTOR_HEIGHT) #define TOTAL (ROWS*COLS) static gboolean press_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "right"); return TRUE; } static gboolean release_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "active"); return TRUE; } static gboolean enter_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "hover"); return TRUE; } static gboolean leave_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "normal"); return TRUE; } static void completed (ClutterState *state, gpointer data) { g_print ("Completed transitioning to state: %s\n", clutter_state_get_state (state)); if (g_str_equal (clutter_state_get_state (state), "right")) { /* skip straight to left state when reaching right */ clutter_state_warp_to_state (state, "left"); } } static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { GError *error = NULL; ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *group = clutter_actor_new (); ClutterActor *rectangle = clutter_actor_new (); ClutterActor *hand = NULL; gchar *file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); hand = clutter_texture_new_from_file (file, &error); if (rectangle == NULL) g_error ("image load failed: %s", error->message); free (file); clutter_actor_set_size (hand, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_actor_set_background_color (rectangle, color); clutter_actor_set_size (rectangle, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_color_free (color); clutter_actor_add_child (group, rectangle); clutter_actor_add_child (group, hand); return group; } G_MODULE_EXPORT gint test_state_main (gint argc, gchar **argv) { ClutterActor *stage; ClutterState *layout_state; gint i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; layout_state = clutter_state_new (); stage = clutter_stage_new (); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "State Machine"); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "button-press-event", G_CALLBACK (press_event), layout_state); g_signal_connect (stage, "button-release-event", G_CALLBACK (release_event), layout_state); for (i = 0; i < TOTAL; i++) { ClutterActor *actor; ClutterState *a_state; int row = i/COLS; int col = i%COLS; actor = new_rect (255 * (1.0 * col / COLS), 50, 255 * (1.0 * row / ROWS), 255); clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor); clutter_actor_set_position (actor, 320.0, 240.0); clutter_actor_set_reactive (actor, TRUE); clutter_actor_add_effect_with_name (actor, "fade", clutter_desaturate_effect_new (0.0)); clutter_state_set (layout_state, NULL, "active", actor, "delayed::x", CLUTTER_LINEAR, ACTOR_WIDTH * 1.0 * ((TOTAL-1-i) % COLS), ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, ACTOR_HEIGHT * 1.0 * ((TOTAL-1-i) / COLS), ((row*1.0/ROWS))/2, 0.0, actor, "rotation-angle-x", CLUTTER_LINEAR, 0.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (layout_state, NULL, "right", actor, "delayed::x", CLUTTER_LINEAR, STAGE_WIDTH * 1.0, ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, STAGE_HEIGHT * 1.0, ((row*1.0/ROWS))/2, 0.0, NULL); clutter_state_set (layout_state, NULL, "left", actor, "rotation-angle-x", CLUTTER_LINEAR, 45.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 5.0, actor, "x", CLUTTER_LINEAR, 0-64.0, actor, "y", CLUTTER_LINEAR, 0-64.0, NULL); a_state = clutter_state_new (); g_object_set_data_full (G_OBJECT (actor), "hover-state-machine", a_state, g_object_unref); g_signal_connect (actor, "enter-event", G_CALLBACK (enter_event), a_state); g_signal_connect (actor, "leave-event", G_CALLBACK (leave_event), a_state); clutter_state_set (a_state, NULL, "normal", actor, "opacity", CLUTTER_LINEAR, 0x77, actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0, actor, "@effects.fade.factor", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (a_state, NULL, "hover", actor, "opacity", CLUTTER_LINEAR, 0xff, actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0, actor, "@effects.fade.factor", CLUTTER_LINEAR, 1.0, NULL); clutter_actor_set_opacity (actor, 0x77); clutter_state_set_duration (a_state, NULL, NULL, 500); } clutter_state_set_duration (layout_state, NULL, NULL, 1000); clutter_state_set_duration (layout_state, "active", "left", 1400); g_signal_connect (layout_state, "completed", G_CALLBACK (completed), NULL); clutter_actor_show (stage); clutter_state_warp_to_state (layout_state, "left"); clutter_state_set_state (layout_state, "active"); clutter_main (); g_object_unref (layout_state); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_state_describe (void) { return "Animating using the State class."; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-stage-sizing.c������������������������������������������0000664�0001750�0001750�00000012123�14211404421�024021� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> static gboolean fullscreen_clicked_cb (ClutterStage *stage) { clutter_stage_set_fullscreen (stage, !clutter_stage_get_fullscreen (stage)); return CLUTTER_EVENT_STOP; } static gboolean resize_clicked_cb (ClutterStage *stage) { clutter_stage_set_user_resizable (stage, !clutter_stage_get_user_resizable (stage)); return CLUTTER_EVENT_STOP; } static gboolean shrink_clicked_cb (ClutterActor *stage) { gfloat width, height; clutter_actor_get_size (stage, &width, &height); clutter_actor_set_size (stage, MAX (0, width - 10.f), MAX (0, height - 10.f)); return CLUTTER_EVENT_STOP; } static gboolean expand_clicked_cb (ClutterActor *stage) { gfloat width, height; clutter_actor_get_size (stage, &width, &height); clutter_actor_set_size (stage, width + 10.f, height + 10.f); return CLUTTER_EVENT_STOP; } static void on_fullscreen (ClutterStage *stage) { float width, height; gboolean is_fullscreen; is_fullscreen = clutter_stage_get_fullscreen (stage); clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height); g_print ("Stage size [%s]: %d x %d\n", is_fullscreen ? "fullscreen" : "not fullscreen", (int) width, (int) height); } G_MODULE_EXPORT int test_stage_sizing_main (int argc, char *argv[]) { ClutterActor *stage, *rect, *label, *box; ClutterMargin margin = { 12.f, 12.f, 6.f, 6.f }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Stage Sizing"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect_after (stage, "notify::fullscreen-set", G_CALLBACK (on_fullscreen), NULL); box = clutter_actor_new (); clutter_actor_set_layout_manager (box, clutter_box_layout_new ()); clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_add_child (stage, box); rect = clutter_actor_new (); clutter_actor_set_layout_manager (rect, clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_CENTER)); clutter_actor_set_background_color (rect, CLUTTER_COLOR_LightScarletRed); clutter_actor_set_reactive (rect, TRUE); g_signal_connect_swapped (rect, "button-press-event", G_CALLBACK (fullscreen_clicked_cb), stage); label = clutter_text_new_with_text ("Sans 16", "Toggle fullscreen"); clutter_actor_set_margin (label, &margin); clutter_actor_add_child (rect, label); clutter_actor_add_child (box, rect); rect = clutter_actor_new (); clutter_actor_set_layout_manager (rect, clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_CENTER)); clutter_actor_set_background_color (rect, CLUTTER_COLOR_Chameleon); clutter_actor_set_reactive (rect, TRUE); g_signal_connect_swapped (rect, "button-press-event", G_CALLBACK (resize_clicked_cb), stage); label = clutter_text_new_with_text ("Sans 16", "Toggle resizable"); clutter_actor_set_margin (label, &margin); clutter_actor_add_child (rect, label); clutter_actor_add_child (box, rect); rect = clutter_actor_new (); clutter_actor_set_layout_manager (rect, clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_CENTER)); clutter_actor_set_background_color (rect, CLUTTER_COLOR_SkyBlue); clutter_actor_set_reactive (rect, TRUE); g_signal_connect_swapped (rect, "button-press-event", G_CALLBACK (shrink_clicked_cb), stage); label = clutter_text_new_with_text ("Sans 16", "Shrink"); clutter_actor_set_margin (label, &margin); clutter_actor_add_child (rect, label); clutter_actor_add_child (box, rect); rect = clutter_actor_new (); clutter_actor_set_layout_manager (rect, clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_BIN_ALIGNMENT_CENTER)); clutter_actor_set_background_color (rect, CLUTTER_COLOR_Butter); clutter_actor_set_reactive (rect, TRUE); g_signal_connect_swapped (rect, "button-press-event", G_CALLBACK (expand_clicked_cb), stage); label = clutter_text_new_with_text ("Sans 16", "Expand"); clutter_actor_set_margin (label, &margin); clutter_actor_add_child (rect, label); clutter_actor_add_child (box, rect); clutter_stage_set_minimum_size (CLUTTER_STAGE (stage), clutter_actor_get_width (box), clutter_actor_get_height (box)); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_stage_sizing_describe (void) { return "Check stage sizing policies."; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cairo-flowers.c�����������������������������������������0000664�0001750�0001750�00000014152�14211404421�024175� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Pretty cairo flower hack. */ #include <clutter/clutter.h> #ifndef _MSC_VER #include <unistd.h> /* for sleep(), used for screenshots */ #endif #include <stdlib.h> #ifdef _MSC_VER #define _USE_MATH_DEFINES #endif #include <math.h> #define PETAL_MIN 20 #define PETAL_VAR 40 #define N_FLOWERS 40 /* reduce if you have a small card */ typedef struct Flower { ClutterActor *ctex; gint x,y,rot,v,rv; } Flower; static ClutterActor *stage = NULL; static gboolean draw_flower (ClutterCanvas *canvas, cairo_t *cr, gint width, gint height, gpointer user_data) { /* No science here, just a hack from toying */ gint i, j; double colors[] = { 0.71, 0.81, 0.83, 1.0, 0.78, 0.57, 0.64, 0.30, 0.35, 0.73, 0.40, 0.39, 0.91, 0.56, 0.64, 0.70, 0.47, 0.45, 0.92, 0.75, 0.60, 0.82, 0.86, 0.85, 0.51, 0.56, 0.67, 1.0, 0.79, 0.58, }; gint size; gint petal_size; gint n_groups; /* Num groups of petals 1-3 */ gint n_petals; /* num of petals 4 - 8 */ gint pm1, pm2; gint idx, last_idx = -1; petal_size = GPOINTER_TO_INT (user_data); size = petal_size * 8; n_groups = rand() % 3 + 1; cairo_set_tolerance (cr, 0.1); /* Clear */ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint(cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_translate(cr, size/2, size/2); for (i=0; i<n_groups; i++) { n_petals = rand() % 5 + 4; cairo_save (cr); cairo_rotate (cr, rand() % 6); do { idx = (rand() % (sizeof (colors) / sizeof (double) / 3)) * 3; } while (idx == last_idx); cairo_set_source_rgba (cr, colors[idx], colors[idx+1], colors[idx+2], 0.5); last_idx = idx; /* some bezier randomness */ pm1 = rand() % 20; pm2 = rand() % 4; for (j=1; j<n_petals+1; j++) { cairo_save (cr); cairo_rotate (cr, ((2*M_PI)/n_petals)*j); /* Petals are made up beziers */ cairo_new_path (cr); cairo_move_to (cr, 0, 0); cairo_rel_curve_to (cr, petal_size, petal_size, (pm2+2)*petal_size, petal_size, (2*petal_size) + pm1, 0); cairo_rel_curve_to (cr, 0 + (pm2*petal_size), -petal_size, -petal_size, -petal_size, -((2*petal_size) + pm1), 0); cairo_close_path (cr); cairo_fill (cr); cairo_restore (cr); } petal_size -= rand() % (size/8); cairo_restore (cr); } /* Finally draw flower center */ do { idx = (rand() % (sizeof (colors) / sizeof (double) / 3)) * 3; } while (idx == last_idx); if (petal_size < 0) petal_size = rand() % 10; cairo_set_source_rgba (cr, colors[idx], colors[idx+1], colors[idx+2], 0.5); cairo_arc(cr, 0, 0, petal_size, 0, M_PI * 2); cairo_fill(cr); return TRUE; } static ClutterActor * make_flower_actor (void) { gint petal_size = PETAL_MIN + rand() % PETAL_VAR; gint size = petal_size * 8; ClutterActor *ctex; ClutterContent *canvas; canvas = clutter_canvas_new (); g_signal_connect (canvas, "draw", G_CALLBACK (draw_flower), GINT_TO_POINTER (petal_size)); clutter_canvas_set_size (CLUTTER_CANVAS (canvas), size, size); ctex = g_object_new (CLUTTER_TYPE_ACTOR, "content", canvas, "width", (gfloat) size, "height", (gfloat) size, NULL); g_object_unref (canvas); return ctex; } static void tick (ClutterTimeline *timeline, gint msecs, gpointer data) { Flower **flowers = data; gint i = 0; for (i = 0; i < N_FLOWERS; i++) { flowers[i]->y += flowers[i]->v; flowers[i]->rot += flowers[i]->rv; if (flowers[i]->y > (gint) clutter_actor_get_height (stage)) flowers[i]->y = -clutter_actor_get_height (flowers[i]->ctex); clutter_actor_set_position (flowers[i]->ctex, flowers[i]->x, flowers[i]->y); clutter_actor_set_rotation (flowers[i]->ctex, CLUTTER_Z_AXIS, flowers[i]->rot, clutter_actor_get_width (flowers[i]->ctex)/2, clutter_actor_get_height (flowers[i]->ctex)/2, 0); } } static void stop_and_quit (ClutterActor *actor, ClutterTimeline *timeline) { clutter_timeline_stop (timeline); clutter_main_quit (); } G_MODULE_EXPORT int test_cairo_flowers_main (int argc, char **argv) { Flower *flowers[N_FLOWERS]; ClutterTimeline *timeline; int i; srand (time (NULL)); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* Create a timeline to manage animation */ timeline = clutter_timeline_new (6000); clutter_timeline_set_repeat_count (timeline, -1); stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cairo Flowers"); g_signal_connect (stage, "destroy", G_CALLBACK (stop_and_quit), timeline); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black); for (i=0; i< N_FLOWERS; i++) { flowers[i] = g_new0(Flower, 1); flowers[i]->ctex = make_flower_actor(); flowers[i]->x = rand() % (int) clutter_actor_get_width (stage) - (PETAL_MIN + PETAL_VAR) * 2; flowers[i]->y = rand() % (int) clutter_actor_get_height (stage); flowers[i]->rv = rand() % 5 + 1; flowers[i]->v = rand() % 10 + 2; clutter_container_add_actor (CLUTTER_CONTAINER (stage), flowers[i]->ctex); clutter_actor_set_position (flowers[i]->ctex, flowers[i]->x, flowers[i]->y); } /* fire a callback for frame change */ g_signal_connect (timeline, "new-frame", G_CALLBACK (tick), flowers); clutter_actor_show (stage); clutter_timeline_start (timeline); g_signal_connect (stage, "key-press-event", G_CALLBACK (clutter_main_quit), NULL); clutter_main(); g_object_unref (timeline); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_cairo_flowers_describe (void) { return "Drawing pretty flowers with Cairo"; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-depth.c�������������������������������������������������0000664�0001750�0001750�00000015321�14211404421�022524� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> /* each time the timeline animating the label completes, swap the direction */ static void timeline_completed (ClutterTimeline *timeline, gpointer user_data) { clutter_timeline_set_direction (timeline, !clutter_timeline_get_direction (timeline)); clutter_timeline_start (timeline); } static ClutterActor *raise_actor[2]; static gboolean raise_no = 0; static gboolean raise_top (gpointer ignored G_GNUC_UNUSED) { ClutterActor *parent = clutter_actor_get_parent (raise_actor[raise_no]); clutter_actor_set_child_above_sibling (parent, raise_actor[raise_no], NULL); raise_no = !raise_no; return G_SOURCE_CONTINUE; } static ClutterActor * clone_box (ClutterActor *original) { gfloat width, height; ClutterActor *group; ClutterActor *clone; clutter_actor_get_size (original, &width, &height); group = clutter_actor_new (); clone = clutter_clone_new (original); clutter_actor_add_child (group, clone); clutter_actor_set_depth (clone, width / 2); clone = clutter_clone_new (original); clutter_actor_add_child (group, clone); clutter_actor_set_rotation (clone, CLUTTER_Y_AXIS, 180, width / 2, 0, 0); clutter_actor_set_depth (clone, -width / 2); clone = clutter_clone_new (original); clutter_actor_add_child (group, clone); clutter_actor_set_rotation (clone, CLUTTER_Y_AXIS, 90, 0, 0, 0); clutter_actor_set_depth (clone, width / 2); clutter_actor_set_position (clone, 0, 0); clone = clutter_clone_new (original); clutter_actor_add_child (group, clone); clutter_actor_set_rotation (clone, CLUTTER_Y_AXIS, 90, 0, 0, 0); clutter_actor_set_depth (clone, width / 2); clutter_actor_set_position (clone, width, 0); clone = clutter_clone_new (original); clutter_actor_add_child (group, clone); clutter_actor_set_rotation (clone, CLUTTER_X_AXIS, 90, 0, 0, 0); clutter_actor_set_depth (clone, -width / 2); clutter_actor_set_position (clone, 0, height); clone = clutter_clone_new (original); clutter_actor_add_child (group, clone); clutter_actor_set_rotation (clone, CLUTTER_X_AXIS, 90, 0, 0, 0); clutter_actor_set_depth (clone, -width / 2); clutter_actor_set_position (clone, 0, 0); return group; } static ClutterActor * janus_group (const gchar *front_text, const gchar *back_text) { ClutterActor *group, *rectangle, *front, *back; gfloat width, height; gfloat width2, height2; group = clutter_actor_new (); rectangle = clutter_actor_new (); clutter_actor_set_background_color (rectangle, CLUTTER_COLOR_White); front = clutter_text_new_with_text ("Sans 50px", front_text); back = clutter_text_new_with_text ("Sans 50px", back_text); clutter_text_set_color (CLUTTER_TEXT (front), CLUTTER_COLOR_Red); clutter_text_set_color (CLUTTER_TEXT (back), CLUTTER_COLOR_Green); clutter_actor_get_size (front, &width, &height); clutter_actor_get_size (back, &width2, &height2); if (width2 > width) width = width2; if (height2 > height) height = height2; clutter_actor_set_size (rectangle, width, height); clutter_actor_set_rotation (back, CLUTTER_Y_AXIS, 180, width / 2, 0, 0); clutter_actor_add_child (group, back); clutter_actor_add_child (group, rectangle); clutter_actor_add_child (group, front); return group; } G_MODULE_EXPORT gint test_depth_main (int argc, char *argv[]) { ClutterTimeline *timeline; ClutterBehaviour *d_behave; ClutterBehaviour *r_behave; ClutterActor *stage; ClutterActor *group, *hand, *label, *rect, *janus, *box; GError *error; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Depth Test"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium2); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "button-press-event", G_CALLBACK (clutter_main_quit), NULL); group = clutter_actor_new (); clutter_actor_add_child (stage, group); label = clutter_text_new_with_text ("Mono 26", "Clutter"); clutter_actor_set_position (label, 120, 200); clutter_actor_add_child (stage, label); error = NULL; hand = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", &error); if (error) g_error ("Unable to load redhand.png: %s", error->message); clutter_actor_set_position (hand, 240, 100); rect = clutter_rectangle_new_with_color (CLUTTER_COLOR_Black); clutter_actor_set_position (rect, 340, 100); clutter_actor_set_size (rect, 200, 200); clutter_actor_set_opacity (rect, 128); clutter_actor_add_child (group, hand); clutter_actor_add_child (group, rect); timeline = clutter_timeline_new (3000); g_signal_connect (timeline, "completed", G_CALLBACK (timeline_completed), NULL); d_behave = clutter_behaviour_depth_new (clutter_alpha_new_full (timeline, CLUTTER_LINEAR), -100, 100); clutter_behaviour_apply (d_behave, label); /* add two faced actor */ janus = janus_group ("GREEN", "RED"); clutter_container_add_actor (CLUTTER_CONTAINER (stage), janus); clutter_actor_set_position (janus, 300, 350); r_behave = clutter_behaviour_rotate_new (clutter_alpha_new_full (timeline, CLUTTER_LINEAR), CLUTTER_Y_AXIS, CLUTTER_ROTATE_CW, 0, 360); clutter_behaviour_apply (r_behave, janus); /* add hand box */ box = clone_box (hand); clutter_actor_add_child (stage, box); clutter_actor_set_position (box, 200, 250); clutter_actor_set_scale (box, 0.5, 0.5); clutter_actor_set_rotation (box, CLUTTER_X_AXIS, 45, 0, 0, 0); clutter_actor_set_opacity (box, 0x44); r_behave = clutter_behaviour_rotate_new (clutter_alpha_new_full (timeline, CLUTTER_LINEAR), CLUTTER_Y_AXIS, CLUTTER_ROTATE_CW, 0, 360); clutter_behaviour_apply (r_behave, box); clutter_actor_show (stage); clutter_timeline_start (timeline); raise_actor[0] = rect; raise_actor[1] = hand; clutter_threads_add_timeout (2000, raise_top, NULL); clutter_main (); g_object_unref (d_behave); g_object_unref (timeline); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cairo-clock.c�������������������������������������������0000664�0001750�0001750�00000006475�14211404421�023620� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <cairo.h> #include <clutter/clutter.h> static gboolean draw_clock (ClutterCanvas *canvas, cairo_t *cr, int width, int height) { GDateTime *now; float hours, minutes, seconds; /* get the current time and compute the angles */ now = g_date_time_new_now_local (); seconds = g_date_time_get_second (now) * G_PI / 30; minutes = g_date_time_get_minute (now) * G_PI / 30; hours = g_date_time_get_hour (now) * G_PI / 6; /* clear the contents of the canvas, to avoid painting * over the previous frame */ cairo_save (cr); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_restore (cr); /* scale the modelview to the size of the surface */ cairo_scale (cr, width, height); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_width (cr, 0.1); /* the black rail that holds the seconds indicator */ clutter_cairo_set_source_color (cr, CLUTTER_COLOR_Black); cairo_translate (cr, 0.5, 0.5); cairo_arc (cr, 0, 0, 0.4, 0, G_PI * 2); cairo_stroke (cr); /* the seconds indicator */ clutter_cairo_set_source_color (cr, CLUTTER_COLOR_White); cairo_move_to (cr, 0, 0); cairo_arc (cr, sinf (seconds) * 0.4, - cosf (seconds) * 0.4, 0.05, 0, G_PI * 2); cairo_fill (cr); /* the minutes hand */ clutter_cairo_set_source_color (cr, CLUTTER_COLOR_DarkChameleon); cairo_move_to (cr, 0, 0); cairo_line_to (cr, sinf (minutes) * 0.4, -cosf (minutes) * 0.4); cairo_stroke (cr); /* the hours hand */ cairo_move_to (cr, 0, 0); cairo_line_to (cr, sinf (hours) * 0.2, -cosf (hours) * 0.2); cairo_stroke (cr); g_date_time_unref (now); /* we're done drawing */ return TRUE; } static gboolean invalidate_clock (gpointer data_) { /* invalidate the contents of the canvas */ clutter_content_invalidate (data_); /* keep the timeout source */ return TRUE; } G_MODULE_EXPORT int test_cairo_clock_main (int argc, char *argv[]) { ClutterActor *stage; ClutterContent *canvas; /* initialize Clutter */ if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; /* create a resizable stage */ stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "2D Clock"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); clutter_actor_set_size (stage, 300, 300); clutter_actor_show (stage); /* our 2D canvas, courtesy of Cairo */ canvas = clutter_canvas_new (); clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300); clutter_actor_set_content (stage, canvas); /* quit on destroy */ g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* connect our drawing code */ g_signal_connect (canvas, "draw", G_CALLBACK (draw_clock), NULL); /* invalidate the canvas, so that we can draw before the main loop starts */ clutter_content_invalidate (canvas); /* set up a timer that invalidates the canvas every second */ clutter_threads_add_timeout (1000, invalidate_clock, canvas); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_cairo_clock_describe (void) { return "Simple 2D canvas using a Cairo texture actor"; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-script-signals.json�������������������������������������0000664�0001750�0001750�00000003232�14211404421�025107� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "id" : "button", "type" : "ClutterRectangle", "width" : "16 em", "height" : "6 em", "color" : "rgb(255, 0, 0)", "opacity" : 128, "scale-gravity" : "center", "reactive" : true, "signals" : [ { "name" : "button-press-event", "handler" : "on_button_press" }, { "name" : "enter-event", "states" : "button-states", "target-state" : "hover" }, { "name" : "leave-event", "states" : "button-states", "target-state" : "base" }, { "name" : "button-press-event", "states" : "button-states", "target-state" : "active" }, { "name" : "button-release-event", "states" : "button-states", "target-state" : "hover" } ] }, { "id" : "button-states", "type" : "ClutterState", "duration" : 250, "transitions" : [ { "source" : null, "target" : "base", "keys" : [ [ "button", "opacity", "linear", 128 ], [ "button", "scale-x", "ease-in-cubic", 1.0 ], [ "button", "scale-y", "ease-in-cubic", 1.0 ], [ "button", "color", "linear", "rgb(255, 0, 0)" ] ] }, { "source" : null, "target" : "hover", "keys" : [ [ "button", "opacity", "linear", 255 ], [ "button", "scale-x", "ease-out-bounce", 1.4 ], [ "button", "scale-y", "ease-out-bounce", 1.4 ], [ "button", "color", "linear", "rgb(0, 255, 0)" ] ] }, { "source" : null, "target" : "active", "keys" : [ [ "button", "opacity", "linear", 255 ], [ "button", "color", "linear", "rgb(0, 0, 255)" ] ] } ] } ] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-keyframe-transition.c�����������������������������������0000664�0001750�0001750�00000006714�14211404421�025421� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> static const ClutterColor colors[] = { { 255, 0, 0, 255 }, { 0, 255, 0, 255 }, { 0, 0, 255, 255 }, }; #define PADDING (64.0f) #define SIZE (64.0f) static void on_transition_stopped (ClutterActor *actor, const gchar *transition_name, gboolean is_finished) { g_print ("%s: transition stopped: %s (finished: %s)\n", clutter_actor_get_name (actor), transition_name, is_finished ? "yes" : "no"); } G_MODULE_EXPORT const char * test_keyframe_transition_describe (void) { return "Demonstrate the keyframe transition."; } G_MODULE_EXPORT int test_keyframe_transition_main (int argc, char *argv[]) { ClutterActor *stage; int i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Keyframe Transitions"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); for (i = 0; i < 3; i++) { ClutterTransition *transition, *group; ClutterActor *rect; float cur_x, cur_y; float new_x, new_y; gchar *name; cur_x = PADDING; cur_y = PADDING + ((SIZE + PADDING) * i); new_x = clutter_actor_get_width (stage) - PADDING - SIZE; new_y = g_random_double_range (PADDING, clutter_actor_get_height (stage) - PADDING - SIZE); name = g_strdup_printf ("rect%02d", i); rect = clutter_actor_new (); clutter_actor_set_name (rect, name); clutter_actor_set_background_color (rect, &colors[i]); clutter_actor_set_size (rect, SIZE, SIZE); clutter_actor_set_position (rect, PADDING, cur_y); clutter_actor_add_child (stage, rect); group = clutter_transition_group_new (); clutter_timeline_set_duration (CLUTTER_TIMELINE (group), 2000); clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (group), 1); clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (group), TRUE); transition = clutter_keyframe_transition_new ("x"); clutter_transition_set_from (transition, G_TYPE_FLOAT, cur_x); clutter_transition_set_to (transition, G_TYPE_FLOAT, new_x); clutter_keyframe_transition_set (CLUTTER_KEYFRAME_TRANSITION (transition), G_TYPE_FLOAT, 1, 0.5, new_x / 2.0f, CLUTTER_EASE_OUT_EXPO); clutter_transition_group_add_transition (CLUTTER_TRANSITION_GROUP (group), transition); g_object_unref (transition); transition = clutter_keyframe_transition_new ("y"); clutter_transition_set_from (transition, G_TYPE_FLOAT, cur_y); clutter_transition_set_to (transition, G_TYPE_FLOAT, cur_y); clutter_keyframe_transition_set (CLUTTER_KEYFRAME_TRANSITION (transition), G_TYPE_FLOAT, 1, 0.5, new_y, CLUTTER_EASE_OUT_EXPO); clutter_transition_group_add_transition (CLUTTER_TRANSITION_GROUP (group), transition); g_object_unref (transition); clutter_actor_add_transition (rect, "rectAnimation", group); g_signal_connect (rect, "transition-stopped", G_CALLBACK (on_transition_stopped), NULL); g_object_unref (group); free (name); } clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ����������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-table-layout.c������������������������������������������0000664�0001750�0001750�00000021666�14211404421�024033� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> #include <cogl/cogl.h> #include <cogl-pango/cogl-pango.h> #define FONT "Sans 12" static void set_text (ClutterActor *actor, const gchar *text) { GList *children, *l; children = clutter_container_get_children (CLUTTER_CONTAINER (actor)); for (l = children; l; l = g_list_next (l)) { if (CLUTTER_IS_TEXT (l->data)) { clutter_text_set_text (CLUTTER_TEXT (l->data), text); break; } } g_list_free (children); } static void toggle_expand (ClutterActor *actor, ClutterEvent *event, ClutterBox *box) { gboolean x_expand; gchar *label; ClutterLayoutManager *layout = clutter_box_get_layout_manager (box); clutter_layout_manager_child_get (layout, CLUTTER_CONTAINER (box), actor, "x-expand", &x_expand, NULL); x_expand = !x_expand; clutter_layout_manager_child_set (layout, CLUTTER_CONTAINER (box), actor, "x-expand", x_expand, "y-expand", x_expand, NULL); label = g_strdup_printf ("Expand = %d", x_expand); set_text (actor, label); free (label); } static const gchar * get_alignment_name (ClutterTableAlignment alignment) { switch (alignment) { case CLUTTER_TABLE_ALIGNMENT_START: return "start"; case CLUTTER_TABLE_ALIGNMENT_CENTER: return "center"; case CLUTTER_TABLE_ALIGNMENT_END: return "end"; } return "undefined"; } static void randomise_align (ClutterActor *actor, ClutterEvent *event, ClutterBox *box) { ClutterTableAlignment x_align, y_align; gchar *label; ClutterLayoutManager *layout; layout = clutter_box_get_layout_manager (box); x_align = (ClutterTableAlignment) g_random_int_range (0, 3); y_align = (ClutterTableAlignment) g_random_int_range (0, 3); clutter_layout_manager_child_set (layout, CLUTTER_CONTAINER (box), actor, "x-align", x_align, "y-align", y_align, NULL); label = g_strdup_printf ("Align (%s, %s)", get_alignment_name (x_align), get_alignment_name (y_align)); set_text (actor, label); free (label); } static void toggle_visible (ClutterActor *actor, ClutterEvent *event, gpointer userdata) { clutter_actor_hide (actor); } gboolean drag = FALSE; static ClutterActor * create_cell (ClutterActor *actor, const gchar *color_str) { ClutterActor *result; ClutterActor *rectangle; ClutterColor color; result = clutter_box_new (clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FILL, CLUTTER_BIN_ALIGNMENT_FILL)); rectangle = clutter_rectangle_new (); clutter_color_from_string (&color, color_str); clutter_rectangle_set_color (CLUTTER_RECTANGLE (rectangle), (const ClutterColor *) &color); clutter_color_from_string (&color, "#000f"); clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle), (const ClutterColor *) &color); clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 2); clutter_actor_show (rectangle); clutter_actor_set_reactive (result, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (result), rectangle); clutter_box_pack (CLUTTER_BOX (result), actor, "x-align", CLUTTER_BIN_ALIGNMENT_CENTER, "y-align", CLUTTER_BIN_ALIGNMENT_CENTER, NULL); return result; } static ClutterActor * create_text (const gchar *label, const gchar *color) { ClutterActor *text; ClutterActor *result; text = clutter_text_new_with_text (FONT, label); clutter_actor_show (text); result = create_cell (text, color); clutter_actor_show (result); return result; } static ClutterActor * create_image (const gchar *file, const gchar *color) { ClutterActor *texture; ClutterActor *result; texture = clutter_texture_new_from_file (file, NULL); g_object_set (G_OBJECT (texture), "keep-aspect-ratio", TRUE, NULL); clutter_actor_show (texture); result = create_cell (texture, color); clutter_actor_show (result); return result; } G_MODULE_EXPORT int test_table_layout_main (int argc, char *argv[]) { ClutterActor *stage; ClutterLayoutManager *layout; ClutterActor *actor1, *actor2, *actor3, *actor4, *actor5, *actor6, *actor7, *actor8, *actor9, *actor10; ClutterActor *box; gchar *file; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Table Layout"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_size (stage, 640, 480); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); layout = clutter_table_layout_new (); clutter_table_layout_set_column_spacing (CLUTTER_TABLE_LAYOUT (layout), 10); clutter_table_layout_set_row_spacing (CLUTTER_TABLE_LAYOUT (layout), 10); clutter_table_layout_set_use_animations (CLUTTER_TABLE_LAYOUT (layout), TRUE); box = clutter_box_new (layout); clutter_container_add_actor (CLUTTER_CONTAINER (stage), box); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_WIDTH, -10.0)); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, -10.0)); actor1 = create_text ("label 1", "#f66f"); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); actor2 = create_image (file, "#bbcf"); free (file); actor3 = create_text ("label 3", "#6f6f"); actor4 = create_text ("Expand = 1", "#66ff"); actor5 = create_text ("label 5", "#f6ff"); actor6 = create_text ("label 6", "#6fff"); actor7 = create_text ("Align (center, center)", "#66ff"); actor8 = create_text ("label 8", "#ffff"); actor9 = create_text ("label 9", "#666f"); actor10 = create_text ("label 10", "#aaaf"); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor1, 0, 0); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor2, 1, 0); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor3, 1, 1); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor4, 0, 2); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor5, 0, 3); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor6, 1, 3); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor7, 1, 4); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor8, 0, 4); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor9, 0, 5); clutter_table_layout_pack (CLUTTER_TABLE_LAYOUT (layout), actor10, 0, -1); clutter_table_layout_set_span (CLUTTER_TABLE_LAYOUT (layout), actor1, 1, 2); clutter_table_layout_set_span (CLUTTER_TABLE_LAYOUT (layout), actor7, 1, 2); clutter_table_layout_set_span (CLUTTER_TABLE_LAYOUT (layout), actor4, 2, 1); clutter_actor_set_size (actor1, 100, 100); clutter_actor_set_width (actor4, 250); clutter_layout_manager_child_set (CLUTTER_LAYOUT_MANAGER (layout), CLUTTER_CONTAINER (box), actor1, "x-expand", FALSE, "y-expand", FALSE, NULL); clutter_layout_manager_child_set (CLUTTER_LAYOUT_MANAGER (layout), CLUTTER_CONTAINER (box), actor4, "x-expand", TRUE, "y-expand", TRUE, "x-fill", TRUE, "y-fill", TRUE, NULL); clutter_layout_manager_child_set (CLUTTER_LAYOUT_MANAGER (layout), CLUTTER_CONTAINER (box), actor7, "x-expand", TRUE, "y-expand", TRUE, "x-fill", FALSE, "y-fill", FALSE, NULL); clutter_layout_manager_child_set (CLUTTER_LAYOUT_MANAGER (layout), CLUTTER_CONTAINER (box), actor8, "x-expand", FALSE, "y-expand", FALSE, NULL); clutter_layout_manager_child_set (CLUTTER_LAYOUT_MANAGER (layout), CLUTTER_CONTAINER (box), actor9, "x-expand", FALSE, "y-expand", FALSE, NULL); clutter_layout_manager_child_set (CLUTTER_LAYOUT_MANAGER (layout), CLUTTER_CONTAINER (box), actor2, "y-fill", FALSE, "x-fill", FALSE, NULL); clutter_actor_set_position (box, 5, 5); g_signal_connect (actor4, "button-release-event", G_CALLBACK (toggle_expand), box); g_signal_connect (actor7, "button-release-event", G_CALLBACK (randomise_align), box); g_signal_connect (actor10, "button-release-event", G_CALLBACK (toggle_visible), NULL); /* g_signal_connect (stage, "button-press-event", G_CALLBACK (button_press), */ /* box); */ /* g_signal_connect (stage, "motion-event", G_CALLBACK (motion_event), */ /* box); */ /* g_signal_connect (stage, "button-release-event", G_CALLBACK (button_release), */ /* box); */ clutter_actor_show (stage); g_debug ("table row count = %d", clutter_table_layout_get_row_count (CLUTTER_TABLE_LAYOUT (layout))); g_debug ("table column count = %d", clutter_table_layout_get_column_count (CLUTTER_TABLE_LAYOUT (layout))); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_table_layout_describe (void) { return "TableLayout layout manager example."; } ��������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-tex-foreign.c��������������������������������������0000664�0001750�0001750�00000016502�14211404421�024573� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <gmodule.h> #include <stdlib.h> #include <clutter/clutter.h> #include <cogl/cogl.h> #ifndef GL_UNPACK_ALIGNMENT #define GL_UNPACK_ALIGNMENT 0x0CF5 #endif #ifndef GL_TEXTURE_BINDING_2D #define GL_TEXTURE_BINDING_2D 0x8069 #endif #ifndef GL_TEXTURE_2D #define GL_TEXTURE_2D 0x0DE1 #endif #ifndef GL_RGB #define GL_RGB 0x1907 #endif #ifndef GL_UNSIGNED_BYTE #define GL_UNSIGNED_BYTE 0x1401 #endif #ifndef GL_TEXTURE_MAG_FILTER #define GL_TEXTURE_MAG_FILTER 0x2800 #endif #ifndef GL_LINEAR #define GL_LINEAR 0x1208 #endif #ifndef GL_TEXTURE_MIN_FILTER #define GL_TEXTURE_MIN_FILTER 0x2801 #endif /* Coglbox declaration *--------------------------------------------------*/ G_BEGIN_DECLS #define TEST_TYPE_COGLBOX test_coglbox_get_type() #define TEST_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_IS_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ TEST_TYPE_COGLBOX)) #define TEST_IS_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ TEST_TYPE_COGLBOX)) #define TEST_COGLBOX_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) typedef struct _TestCoglbox TestCoglbox; typedef struct _TestCoglboxClass TestCoglboxClass; typedef struct _TestCoglboxPrivate TestCoglboxPrivate; struct _TestCoglbox { ClutterActor parent; /*< private >*/ TestCoglboxPrivate *priv; }; struct _TestCoglboxClass { ClutterActorClass parent_class; /* padding for future expansion */ void (*_test_coglbox1) (void); void (*_test_coglbox2) (void); void (*_test_coglbox3) (void); void (*_test_coglbox4) (void); }; static GType test_coglbox_get_type (void) G_GNUC_CONST; G_END_DECLS /* Coglbox private declaration *--------------------------------------------------*/ G_DEFINE_TYPE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR); #define TEST_COGLBOX_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TEST_TYPE_COGLBOX, TestCoglboxPrivate)) struct _TestCoglboxPrivate { guint gl_handle; CoglHandle cogl_handle; void (* glGetIntegerv) (guint pname, int *params); void (* glPixelStorei) (guint pname, int param); void (* glTexParameteri) (guint target, guint pname, int param); void (* glTexImage2D) (guint target, int level, int internalFormat, int width, int height, int border, guint format, guint type, const void *pixels); void (* glGenTextures) (int n, guint *textures); void (* glDeleteTextures) (int n, const guint *textures); void (* glBindTexture) (guint target, guint texture); }; /* Coglbox implementation *--------------------------------------------------*/ static void test_coglbox_paint(ClutterActor *self) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self); gfloat texcoords[4] = { 0.3f, 0.3f, 0.7f, 0.7f }; cogl_set_source_color4ub (0x66, 0x66, 0xdd, 0xff); cogl_rectangle (0,0,400,400); cogl_push_matrix (); cogl_translate (100,100,0); cogl_set_source_texture (priv->cogl_handle); cogl_rectangle_with_texture_coords (0, 0, 200, 200, texcoords[0], texcoords[1], texcoords[2], texcoords[3]); cogl_pop_matrix(); } static void test_coglbox_finalize (GObject *object) { G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object); } static void test_coglbox_dispose (GObject *object) { TestCoglboxPrivate *priv; priv = TEST_COGLBOX_GET_PRIVATE (object); cogl_handle_unref (priv->cogl_handle); priv->glDeleteTextures (1, &priv->gl_handle); G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object); } static void test_coglbox_init (TestCoglbox *self) { TestCoglboxPrivate *priv; guchar data[12]; int prev_unpack_alignment; int prev_2d_texture_binding; self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); /* Prepare a 2x2 pixels texture */ data[0] = 255; data[1] = 0; data[2] = 0; data[3] = 0; data[4] = 255; data[5] = 0; data[6] = 0; data[7] = 0; data[8] = 255; data[9] = 0; data[10] = 0; data[11] = 0; priv->glGetIntegerv = (void *) cogl_get_proc_address ("glGetIntegerv"); priv->glPixelStorei = (void *) cogl_get_proc_address ("glPixelStorei"); priv->glTexParameteri = (void *) cogl_get_proc_address ("glTexParameteri"); priv->glTexImage2D = (void *) cogl_get_proc_address ("glTexImage2D"); priv->glGenTextures = (void *) cogl_get_proc_address ("glGenTextures"); priv->glDeleteTextures = (void *) cogl_get_proc_address ("glDeleteTextures"); priv->glBindTexture = (void *) cogl_get_proc_address ("glBindTexture"); /* We are about to use OpenGL directly to create a TEXTURE_2D * texture so we need to save the state that we modify so we can * restore it afterwards and be sure not to interfere with any state * caching that Cogl may do internally. */ priv->glGetIntegerv (GL_UNPACK_ALIGNMENT, &prev_unpack_alignment); priv->glGetIntegerv (GL_TEXTURE_BINDING_2D, &prev_2d_texture_binding); priv->glGenTextures (1, &priv->gl_handle); priv->glBindTexture (GL_TEXTURE_2D, priv->gl_handle); priv->glPixelStorei (GL_UNPACK_ALIGNMENT, 1); priv->glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data); /* Now restore the original GL state as Cogl had left it */ priv->glPixelStorei (GL_UNPACK_ALIGNMENT, prev_unpack_alignment); priv->glBindTexture (GL_TEXTURE_2D, prev_2d_texture_binding); priv->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); priv->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* Create texture from foreign */ priv->cogl_handle = cogl_texture_new_from_foreign (priv->gl_handle, GL_TEXTURE_2D, 2, 2, 0, 0, COGL_PIXEL_FORMAT_RGB_888); if (priv->cogl_handle == COGL_INVALID_HANDLE) { printf ("Failed creating texture from foreign!\n"); return; } } static void test_coglbox_class_init (TestCoglboxClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); gobject_class->finalize = test_coglbox_finalize; gobject_class->dispose = test_coglbox_dispose; actor_class->paint = test_coglbox_paint; g_type_class_add_private (gobject_class, sizeof (TestCoglboxPrivate)); } static ClutterActor* test_coglbox_new (void) { return g_object_new (TEST_TYPE_COGLBOX, NULL); } G_MODULE_EXPORT int test_cogl_tex_foreign_main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *coglbox; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* Stage */ stage = clutter_stage_new (); clutter_actor_set_size (stage, 400, 400); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Foreign Textures"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* Cogl Box */ coglbox = test_coglbox_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox); clutter_actor_show_all (stage); clutter_main (); return 0; } G_MODULE_EXPORT const char * test_cogl_tex_foreign_describe (void) { return "Foreign textures support in Cogl."; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/redhand.png��������������������������������������������������0000664�0001750�0001750�00000020072�14211404421�022411� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������������bKGD������ pHYs�� �� ����tIME 3x<,��IDATx]y|M~>( "HQV> Q)UU:hPzRJu]\PBiBEDD99Z9kwg=Z888888888888888888888888D),rU0H#ۜ#Tىm!8Ad' ` (�@9�cɂ 4$ p.w Y�) $m"!Eچ.�RT 3 49m0L)c&f=(cl+TRJRJ/e-JcPJ#VboL)}RYp'l0t0;]X Lfse(4VuC]e J)SDؐmC)N)-۸6?! [R:ֆ^l*xE%<c~|�8es J;jۆRM*mNnXŢ%Lcu'3~&<nam% d'_NMJWI<pf.'"u:'$CNAr L&?BH!$-LJy)\,Bל2qpWJ0BlɄ3gPK//60>#wo&&+b�}i)JFuZ ` aa+<\0N<5uWT�@m:t@P>M芋Qv~ 0Cpu٪EeB:8:A.BK-۸W�`v2ϖ-vDN M^KKݠz }=s&&u156v- l0Dھ4^^6O x1J~ζqwGOHر$$t !dBJSRpaLzγuktZ�Æ:3CMw?J:l:/^ m|^f=H3y6z…h9tlu1{Fm i"KXn*b)ANJ�we:\0AZ|ot7n<uJ;7ҟbY Lm=c:Lnm pPoM4*B, G<!$MҔl2?.D2͓kTTסCE؟=0}wO^_˟.m^z qK~GEkVţE ݽ[jܶ2VJrE֢E ��]/m6pv$Y� ?*iQ6r�@5O6Rg&Lƍ^I=cA{x *6Mp;oKܵkQzA~Y[WRӧFf,_J_Iy瑵x4tcRؗ,_޴|k՞?GJd/]j|j O?VPY}$z]&~}jx tBDPY+kڬ׶lAC~E{`F#B/u̴|"[:ԅtK)&8 A�>|c.Ńpv_ԀE;wZɢEۆR\ۺ6דE-ÑҔW2QmӺPq٦637lZCEΉ 0A�Wµz%"%lnb9/GDRKca+.bi9R4ټ.TuiY^@-<kQƂrl IKVbihpjQ%0J Xj;'R#̜ ~ @m!NM \Ap +W \Ap +W>s +W \ApuvApipU],L],s +Ws +W \Ap \Ap +W . TNJ^Z v]ލX[ S}=�P @􄛏. .AX�}yC+A8x cp +W vBJhPrWSXUgQaKvѣ;wX ׯa(;reRW֮qMouuq3V(ؼ`= @WRf<3gx RG>\s^O0Jqu2Ǐ󞼛ۥ!sB{ _c O2EA4h||  D3F6264^GqӮ5d ҿ!t Ovh֩uxm Z-A�[v)5@u:XX<E\+W@umi4TVi8(B�$& 11Rh4иC wx"Gr JKC4%5|Arڠ <Z>}֬m3A68!!d ̞ ]QdT?d1h4>C؜w#gX"ƍCsϡ>?׶l-[k(6rUwfwDz _}E?eP061Bj:bOfqqDj6jBG=^8䷻K qHX:ur=VawNkxic 4.Wx8]Ĥ$:>:|88)S xxpK8E˸1iՙH??͝>w,gXz}=̓Sw_.u+:&;w!߿]j!fL$&%eK>]ٳiɁ v'VD7ް+7C-͛ǹ pGϤ$9/D<qehw40憸3kVNcQp&-ZmyNt>OO\7O3)<Q~~HܴBD2O 1{wދ3<cgVKk;]>- Ɛ vI'ӵZ$Xx l ܯ|rⷄիp#$Vpr?>13XDA_3,l1nZ],Gw<,B|h'A@ŋ pTKۼ9by9s t,:k>z4lq ~I`hSvi<S]Qu,._F]v6 0Ԁ MH}|٪|:tol,{WDݝl$ :} f4BwCdgA}(ܶ 'N?k#"b`],ݺ!駑ĥBJlWeh,*յky3eegTu99]W֮_׮h+h#Z~4l$fAWZd.ZC!{2P4<Gz%xGE! ?_?s)޻ /Ʀedd183itk $ՃȘ?ƍS4.w!CPvjE. hRcu5Ne]\<Um'N1*HرՕOAm@z\9?L${cjB&ߕÞB3Jx1rWR~D.'mP^l!cnݪxѭFpNrgpibm'1 g@MFzGEkW 䡇-d~\ieɓnU-~+ ~ Qn̙`&CtVMFR2c{qNt)rW@]vb$$Xug#wdD`ފ+)A5aF\S^77],],B=p嫯`wN+LNV `^R^pWP7i`+ڕ,wX쁡¡;p6ٶ :u1Pbk*|t=*.F/( j ʸ'F#ʎqSl!x4A䚥ڶU4 Jn؝>T>J{o%5/t%GV._v0 u99RJDj rĀb }yWjxAkkjԔD< R)8NEco 6*)E�4NՁJJ# TA:Aj)j1$_1iR[gh2y<+lljF4XM6?||NΜ.K$HCa" VԢԫbWCHgEgQgUEa[#X vv_)KRPX[ =GZ HQTCcQ'(u[tŋ5O8|wX<UZ"o{W$2RREj32K߭UHO?XY5钟ue^ADh+)p4TUV脠ԩi!!ʉȭ �pB 5>>OV?XFwTCvZ/*eF~qDRJ*RSq7we/n&)VRE/ �A0Jk|ˡC[ 5xy)VdiJU]aQ/OwMQtY#0ŗK~ c�|Ʈ]3, ݖ-y"Ed%Q/j%o鸾cw< :#-[YG]vR]s7DԔ)h+vG�$~*+n a lwg^ $Um�D9zmx6VWO?aH}oL ۷\bfB>jƢϏ??!A oWD b@jU'h}m3֒O]i^3W.:.:i5rZScj LLD={9q7bBeˬZ\߱Ckޜ d/o.]$ULw 6oV=@hݹ-~&hat?xP_L ":H1c$W.grȦ߭w.?dq|cb{Yz[j)Q:<.Q1� hva,/[CUJCiJ ʏEcQ݉L4Cp<ݻJf4S92(1#!DA6j7mTÆ)zm 5 R_G}~>srTܚ5gVn׮FY_@ƍ>cJ! �Qjpx�ß~/)t8t}0TVި_D܂bjA?(ꋘy+v^۲ nwEd̟/;9BH-d<J Ji3#Z!&yuQ f)v_PhMe�BB cɔG)^vCGCy`bY@ӹh2M9 `!d!$R<MugRym9]YE;wQ-N)ν]s$'RJU �ꟐVZQp7PP9gGUvޣ'!dcoP"B-c)v|]5*+qajh# "룏l^JABPJB3VHQ֭NSy4ҦLQgBmf&Nw~t$J)OUS)϶6 11VhN\=KUxN }y+4ח/kHbɠRTD@O>zE7Ғ%uT**pbh4+~N~ [˟+9I,Nhd;SݔҖo}fƐ1o2,*SUׯctD3IVb5A*2Gʳ//$\)֜q~tlvFȑ]T$c�$qalYܤC a*V *OƩ瞃X:40�i'gh:B2%^Ba� Bڴie<Zk8'+Ji.s|/">#G1~<í}wъĬ"k�L򬩡#GYYA &0VW㷷FmN>"'L@W_l c Rڌr _ǯh((NO=N qV[Y2uJݳf[="}�t(!Drݚt CUlulqs"tpTcu5.})~K-R qfJM1\2E b.x3g>_~(N-CFG;MQ8Î\Ih}w$,Q fW$�Wr�N=쇤4h;q"^z -Z8(3*Ϝ%K\z�}w풲30!d1/!jQ̤I6I 6>^gǎ!{R8w܄n˗OJvA0)N3I^$Xò4%ƏYXZ?$"'NOt](TGiJ rWDّ# pG T f~+YSSqz8+*lVO"?8iUWnߎk?<΂ q&)7pIL5=�Xڬ,3W//48-~!<�VQףEߏw*-Q"1nO|72O5I҆r Ut%%8=a*S迧 zkWxGFB4h<}Ǐ)4.5XG}>62WUIYE ͮooxGF«MxiPh' `�`24>/ h((�3Ȗ 13!$@ﺶe .̞ cM M C e%K6 \`M`9O>~{"gO>28Ɨ qQ|MScAv'93f~e An"9H"h1E`^|09D" �4}w Uh>pqڍb  D^p'縺aO0*A$;~IW}_!_ 1ßŀ#G1nbpr&H!�kQڅQ}^| / ;!qj*o:M1ďMm}E򓒐Դeopxݿ<"O!3 7d IrɄ_~Aߢx^氹9s.gnsE2"/ cM Cю(=|bAVs"rD8EY]p"t8~%QԤDtvht^Y},!$ɡ r𪛱UgϢ*- 騹pOs;_Fѣل(#l�jףh((iny9Luuz}jh<= ot4~]u."p(ܤ&�X�+κs4B,8b )] !�mP�!_v,j ' AӽٗxsX�`r8,A?n#$�x.x1TSD99k !;n&\�yXG$KqfPJ#<+r]RRB�sUq dx|8AĹ_]0@;8BT3� !ܟ3)42�0&hJsXsWե?nf$� cs �6M Ncx3a"54+ rR SpքpRDsV����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-text.c��������������������������������������������������0000664�0001750�0001750�00000006215�14211404421�022406� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> #define FONT "Mono Bold 24px" static const gchar *runes = "ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ\n" "ᛋᚳᛖᚪᛚ᛫ᚦᛖᚪᚻ᛫ᛗᚪᚾᚾᚪ᛫ᚷᛖᚻᚹᛦᛚᚳ᛫ᛗᛁᚳᛚᚢᚾ᛫ᚻᛦᛏ᛫ᛞᚫᛚᚪᚾ\n" "ᚷᛁᚠ᛫ᚻᛖ᛫ᚹᛁᛚᛖ᛫ᚠᚩᚱ᛫ᛞᚱᛁᚻᛏᚾᛖ᛫ᛞᚩᛗᛖᛋ᛫ᚻᛚᛇᛏᚪᚾ᛬\n"; G_MODULE_EXPORT gint test_text_main (gint argc, gchar **argv) { ClutterActor *stage; ClutterActor *text, *text2; ClutterColor text_color = { 0x33, 0xff, 0x33, 0xff }; ClutterColor cursor_color = { 0xff, 0x33, 0x33, 0xff }; ClutterTextBuffer *buffer; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Text Editing"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); buffer = clutter_text_buffer_new_with_text ("·", -1); text = clutter_text_new_with_buffer (buffer); clutter_text_set_font_name (CLUTTER_TEXT (text), FONT); clutter_text_set_color (CLUTTER_TEXT (text), &text_color); clutter_container_add (CLUTTER_CONTAINER (stage), text, NULL); clutter_actor_set_position (text, 40, 30); clutter_actor_set_width (text, 1024); clutter_text_set_line_wrap (CLUTTER_TEXT (text), TRUE); clutter_actor_set_reactive (text, TRUE); clutter_stage_set_key_focus (CLUTTER_STAGE (stage), text); clutter_text_set_editable (CLUTTER_TEXT (text), TRUE); clutter_text_set_selectable (CLUTTER_TEXT (text), TRUE); clutter_text_set_cursor_color (CLUTTER_TEXT (text), &cursor_color); clutter_text_set_selected_text_color (CLUTTER_TEXT (text), CLUTTER_COLOR_Blue); text2 = clutter_text_new_with_buffer (buffer); clutter_text_set_color (CLUTTER_TEXT (text2), &text_color); clutter_container_add (CLUTTER_CONTAINER (stage), text2, NULL); clutter_actor_set_position (text2, 40, 300); clutter_actor_set_width (text2, 1024); clutter_text_set_line_wrap (CLUTTER_TEXT (text2), TRUE); clutter_actor_set_reactive (text2, TRUE); clutter_text_set_editable (CLUTTER_TEXT (text2), TRUE); clutter_text_set_selectable (CLUTTER_TEXT (text2), TRUE); clutter_text_set_cursor_color (CLUTTER_TEXT (text2), &cursor_color); clutter_text_set_selected_text_color (CLUTTER_TEXT (text2), CLUTTER_COLOR_Green); if (argv[1]) { GError *error = NULL; gchar *utf8; g_file_get_contents (argv[1], &utf8, NULL, &error); if (error) { utf8 = g_strconcat ("Unable to open '", argv[1], "':\n", error->message, NULL); g_error_free (error); } clutter_text_set_text (CLUTTER_TEXT (text), utf8); } else clutter_text_set_text (CLUTTER_TEXT (text), runes); clutter_actor_set_size (stage, 1024, 768); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_text_describe (void) { return "Multi-line text editing."; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-devices.c�����������������������������������������������0000664�0001750�0001750�00000017531�14211404421�023047� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> #ifdef CLUTTER_WINDOWING_X11 #include <clutter/x11/clutter-x11.h> #endif typedef struct { ClutterActor *stage; GHashTable *devices; } TestDevicesApp; static const gchar * device_type_name (ClutterInputDevice *device) { ClutterInputDeviceType d_type; d_type = clutter_input_device_get_device_type (device); switch (d_type) { case CLUTTER_POINTER_DEVICE: return "Pointer"; case CLUTTER_KEYBOARD_DEVICE: return "Keyboard"; case CLUTTER_EXTENSION_DEVICE: return "Extension"; case CLUTTER_PEN_DEVICE: return "Pen"; case CLUTTER_ERASER_DEVICE: return "Eraser"; case CLUTTER_CURSOR_DEVICE: return "Cursor"; default: return "Unknown"; } } static const gchar * axis_type_name (ClutterInputAxis axis) { switch (axis) { case CLUTTER_INPUT_AXIS_X: return "Absolute X"; case CLUTTER_INPUT_AXIS_Y: return "Absolute Y"; case CLUTTER_INPUT_AXIS_PRESSURE: return "Pressure"; case CLUTTER_INPUT_AXIS_XTILT: return "X Tilt"; case CLUTTER_INPUT_AXIS_YTILT: return "Y Tilt"; case CLUTTER_INPUT_AXIS_WHEEL: return "Wheel"; default: return "Unknown"; } } static gboolean stage_button_event_cb (ClutterActor *actor, ClutterEvent *event, TestDevicesApp *app) { ClutterInputDevice *device; ClutterInputDevice *source_device; ClutterActor *hand = NULL; gdouble *axes; guint n_axes, i; device = clutter_event_get_device (event); source_device = clutter_event_get_source_device (event); hand = g_hash_table_lookup (app->devices, device); g_print ("Device: '%s' (id:%d, type: %s, source: '%s', axes: %d)\n", clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device), device_type_name (device), source_device != device ? clutter_input_device_get_device_name (source_device) : "<same>", clutter_input_device_get_n_axes (device)); if (hand != NULL) { gfloat event_x, event_y; clutter_event_get_coords (event, &event_x, &event_y); clutter_actor_set_position (hand, event_x, event_y); } axes = clutter_event_get_axes (event, &n_axes); for (i = 0; i < n_axes; i++) { ClutterInputAxis axis; axis = clutter_input_device_get_axis (device, i); if (axis == CLUTTER_INPUT_AXIS_IGNORE) continue; g_print ("\tAxis[%2d][%s].value: %.2f\n", i, axis_type_name (axis), axes[i]); } return FALSE; } static gboolean stage_motion_event_cb (ClutterActor *actor, ClutterEvent *event, TestDevicesApp *app) { ClutterInputDevice *device; ClutterActor *hand = NULL; device = clutter_event_get_device (event); hand = g_hash_table_lookup (app->devices, device); if (hand != NULL) { gfloat event_x, event_y; clutter_event_get_coords (event, &event_x, &event_y); clutter_actor_set_position (hand, event_x, event_y); return TRUE; } return FALSE; } static void manager_device_added_cb (ClutterDeviceManager *manager, ClutterInputDevice *device, TestDevicesApp *app) { ClutterInputDeviceType device_type; ClutterActor *hand = NULL; g_print ("got a %s device '%s' with id %d\n", device_type_name (device), clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device)); device_type = clutter_input_device_get_device_type (device); if (device_type == CLUTTER_POINTER_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_POINTER_DEVICE) { g_print ("*** enabling device '%s' ***\n", clutter_input_device_get_device_name (device)); clutter_input_device_set_enabled (device, TRUE); hand = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL); g_hash_table_insert (app->devices, device, hand); clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand); } } static void manager_device_removed_cb (ClutterDeviceManager *manager, ClutterInputDevice *device, TestDevicesApp *app) { ClutterInputDeviceType device_type; ClutterActor *hand = NULL; g_print ("removed a %s device '%s' with id %d\n", device_type_name (device), clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device)); device_type = clutter_input_device_get_device_type (device); if (device_type == CLUTTER_POINTER_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_POINTER_DEVICE) { hand = g_hash_table_lookup (app->devices, device); if (hand != NULL) clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand); g_hash_table_remove (app->devices, device); } } G_MODULE_EXPORT int test_devices_main (int argc, char **argv) { ClutterActor *stage; TestDevicesApp *app; ClutterDeviceManager *manager; const GSList *stage_devices, *l; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; app = g_new0 (TestDevicesApp, 1); app->devices = g_hash_table_new (g_direct_hash, g_direct_equal) ; stage = clutter_stage_new (); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); clutter_stage_set_title (CLUTTER_STAGE (stage), "Devices"); clutter_stage_hide_cursor (CLUTTER_STAGE (stage)); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "motion-event", G_CALLBACK (stage_motion_event_cb), app); g_signal_connect (stage, "button-press-event", G_CALLBACK (stage_button_event_cb), app); app->stage = stage; clutter_actor_show_all (stage); manager = clutter_device_manager_get_default (); g_signal_connect (manager, "device-added", G_CALLBACK (manager_device_added_cb), app); g_signal_connect (manager, "device-removed", G_CALLBACK (manager_device_removed_cb), app); stage_devices = clutter_device_manager_peek_devices (manager); if (stage_devices == NULL) g_error ("No input devices found."); for (l = stage_devices; l != NULL; l = l->next) { ClutterInputDevice *device = l->data; ClutterInputDeviceType device_type; ClutterActor *hand = NULL; g_print ("got a %s device '%s' with id %d\n", device_type_name (device), clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device)); device_type = clutter_input_device_get_device_type (device); if (device_type == CLUTTER_POINTER_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_POINTER_DEVICE) { g_print ("*** enabling device '%s' ***\n", clutter_input_device_get_device_name (device)); clutter_input_device_set_enabled (device, TRUE); hand = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL); g_hash_table_insert (app->devices, device, hand); clutter_container_add_actor (CLUTTER_CONTAINER (stage), hand); } } clutter_main (); return EXIT_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-path-constraint.c���������������������������������������0000664�0001750�0001750�00000006541�14211404421�024542� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> #define PATH_DESCRIPTION \ "M 0, 0 " \ "L 0, 300 " \ "L 300, 300 " \ "L 300, 0 " \ "L 0, 0" static gboolean toggled = FALSE; static gboolean on_button_press (ClutterActor *actor, const ClutterEvent *event, gpointer dummy G_GNUC_UNUSED) { if (!toggled) clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 500, "@constraints.path.offset", 1.0, NULL); else clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 500, "@constraints.path.offset", 0.0, NULL); toggled = !toggled; return TRUE; } static gchar * node_to_string (const ClutterPathNode *node) { GString *buffer = g_string_sized_new (256); gsize len = 0, i; switch (node->type) { case CLUTTER_PATH_MOVE_TO: g_string_append (buffer, "move-to "); len = 1; break; case CLUTTER_PATH_LINE_TO: g_string_append (buffer, "line-to "); len = 1; break; case CLUTTER_PATH_CURVE_TO: g_string_append (buffer, "curve-to "); len = 3; break; case CLUTTER_PATH_CLOSE: g_string_append (buffer, "close"); len = 0; break; default: break; } for (i = 0; i < len; i++) { if (i == 0) g_string_append (buffer, "[ "); g_string_append_printf (buffer, "[ %d, %d ]", node->points[i].x, node->points[i].y); if (i == len - 1) g_string_append (buffer, " ]"); } return g_string_free (buffer, FALSE); } static void on_node_reached (ClutterPathConstraint *constraint, ClutterActor *actor, guint index_) { ClutterPath *path = clutter_path_constraint_get_path (constraint); ClutterPathNode node; gchar *str; clutter_path_get_node (path, index_, &node); str = node_to_string (&node); g_print ("Node %d reached: %s\n", index_, str); free (str); } G_MODULE_EXPORT int test_path_constraint_main (int argc, char *argv[]) { ClutterActor *stage, *rect; ClutterPath *path; ClutterColor rect_color = { 0xcc, 0x00, 0x00, 0xff }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Path Constraint"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); path = clutter_path_new (); clutter_path_set_description (path, PATH_DESCRIPTION); rect = clutter_rectangle_new (); clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color); clutter_actor_set_size (rect, 128, 128); clutter_actor_set_reactive (rect, TRUE); clutter_actor_add_constraint_with_name (rect, "path", clutter_path_constraint_new (path, 0.0)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); g_signal_connect (rect, "button-press-event", G_CALLBACK (on_button_press), NULL); g_signal_connect (clutter_actor_get_constraint (rect, "path"), "node-reached", G_CALLBACK (on_node_reached), NULL); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-shader-glsl.c��������������������������������������0000664�0001750�0001750�00000025431�14211404421�024552� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <errno.h> #include <stdlib.h> #include <glib.h> #include <gmodule.h> typedef struct { char *name; char *source; } ShaderSource; /* a couple of boilerplate defines that are common amongst all the * sample shaders */ /* FRAGMENT_SHADER_BEGIN: generate boilerplate with a local vec4 color already * initialized, from a sampler2D in a variable tex. */ #define FRAGMENT_SHADER_VARS \ "uniform sampler2D tex;" \ "uniform float x_step, y_step;" #define FRAGMENT_SHADER_BEGIN \ "void main (){" \ " vec4 color = texture2D (tex, vec2(cogl_tex_coord_in[0]));" /* FRAGMENT_SHADER_END: apply the changed color to the output buffer correctly * blended with the gl specified color (makes the opacity of actors work * correctly). */ #define FRAGMENT_SHADER_END \ " cogl_color_out = color;" \ " cogl_color_out = cogl_color_out * cogl_color_in;" \ "}" static ShaderSource shaders[]= { {"brightness-contrast", FRAGMENT_SHADER_VARS "uniform float brightness, contrast;" FRAGMENT_SHADER_BEGIN " color.rgb /= color.a;" " color.rgb = (color.rgb - vec3(0.5, 0.5, 0.5)) * contrast + " "vec3 (brightness + 0.5, brightness + 0.5, brightness + 0.5);" " color.rgb *= color.a;" FRAGMENT_SHADER_END }, {"box-blur", FRAGMENT_SHADER_VARS #if GPU_SUPPORTS_DYNAMIC_BRANCHING "uniform float radius;" FRAGMENT_SHADER_BEGIN "float u, v;" "int count = 1;" "for (u=-radius;u<radius;u++)" " for (v=-radius;v<radius;v++)" " {" " color += texture2D(tex, " " vec2(cogl_tex_coord_in[0].s + u * 2.0 * x_step, " " cogl_tex_coord_in[0].t + v * 2.0 * y_step));" " count ++;" " }" "color = color / float(count);" FRAGMENT_SHADER_END #else "vec4 get_rgba_rel(sampler2D tex, float dx, float dy)" "{" " return texture2D (tex, cogl_tex_coord_in[0].st " " + vec2(dx, dy) * 2.0);" "}" FRAGMENT_SHADER_BEGIN " float count = 1.0;" " color += get_rgba_rel (tex, -x_step, -y_step); count++;" " color += get_rgba_rel (tex, -x_step, 0.0); count++;" " color += get_rgba_rel (tex, -x_step, y_step); count++;" " color += get_rgba_rel (tex, 0.0, -y_step); count++;" " color += get_rgba_rel (tex, 0.0, 0.0); count++;" " color += get_rgba_rel (tex, 0.0, y_step); count++;" " color += get_rgba_rel (tex, x_step, -y_step); count++;" " color += get_rgba_rel (tex, x_step, 0.0); count++;" " color += get_rgba_rel (tex, x_step, y_step); count++;" " color = color / count;" FRAGMENT_SHADER_END #endif }, {"invert", FRAGMENT_SHADER_VARS FRAGMENT_SHADER_BEGIN " color.rgb /= color.a;" " color.rgb = vec3(1.0, 1.0, 1.0) - color.rgb;\n" " color.rgb *= color.a;" FRAGMENT_SHADER_END }, {"brightness-contrast", FRAGMENT_SHADER_VARS "uniform float brightness;" "uniform float contrast;" FRAGMENT_SHADER_BEGIN " color.rgb /= color.a;" " color.r = (color.r - 0.5) * contrast + brightness + 0.5;" " color.g = (color.g - 0.5) * contrast + brightness + 0.5;" " color.b = (color.b - 0.5) * contrast + brightness + 0.5;" " color.rgb *= color.a;" FRAGMENT_SHADER_END }, {"gray", FRAGMENT_SHADER_VARS FRAGMENT_SHADER_BEGIN " float avg = (color.r + color.g + color.b) / 3.0;" " color.r = avg;" " color.g = avg;" " color.b = avg;" FRAGMENT_SHADER_END }, {"combined-mirror", FRAGMENT_SHADER_VARS FRAGMENT_SHADER_BEGIN " vec4 colorB = texture2D (tex, vec2(cogl_tex_coord_in[0].ts));" " float avg = (color.r + color.g + color.b) / 3.0;" " color.r = avg;" " color.g = avg;" " color.b = avg;" " color = (color + colorB)/2.0;" FRAGMENT_SHADER_END }, {"edge-detect", FRAGMENT_SHADER_VARS "float get_avg_rel(sampler2D texB, float dx, float dy)" "{" " vec4 colorB = texture2D (texB, cogl_tex_coord_in[0].st + vec2(dx, dy));" " return (colorB.r + colorB.g + colorB.b) / 3.0;" "}" FRAGMENT_SHADER_BEGIN " mat3 sobel_h = mat3( 1.0, 2.0, 1.0," " 0.0, 0.0, 0.0," " -1.0, -2.0, -1.0);" " mat3 sobel_v = mat3( 1.0, 0.0, -1.0," " 2.0, 0.0, -2.0," " 1.0, 0.0, -1.0);" " mat3 map = mat3( get_avg_rel(tex, -x_step, -y_step)," " get_avg_rel(tex, -x_step, 0.0)," " get_avg_rel(tex, -x_step, y_step)," " get_avg_rel(tex, 0.0, -y_step)," " get_avg_rel(tex, 0.0, 0.0)," " get_avg_rel(tex, 0.0, y_step)," " get_avg_rel(tex, x_step, -y_step)," " get_avg_rel(tex, x_step, 0.0)," " get_avg_rel(tex, x_step, y_step) );" " mat3 gh = sobel_h * map;" " mat3 gv = map * sobel_v;" " float avgh = (gh[0][0] + gh[0][1] + gh[0][2] +" " gh[1][0] + gh[1][1] + gh[1][2] +" " gh[2][0] + gh[2][1] + gh[2][2]) / 18.0 + 0.5;" " float avgv = (gv[0][0] + gv[0][1] + gv[0][2] +" " gv[1][0] + gv[1][1] + gv[1][2] +" " gv[2][0] + gv[2][1] + gv[2][2]) / 18.0 + 0.5;" " float avg = (avgh + avgv) / 2.0;" " color.r = avg * color.r;" " color.g = avg * color.g;" " color.b = avg * color.b;" FRAGMENT_SHADER_END } }; static CoglHandle redhand; static CoglMaterial *material; static unsigned int timeout_id = 0; static int shader_no = 0; static void paint_cb (ClutterActor *actor) { float stage_width = clutter_actor_get_width (actor); float stage_height = clutter_actor_get_height (actor); float image_width = cogl_texture_get_width (redhand); float image_height = cogl_texture_get_height (redhand); cogl_set_source (material); cogl_rectangle (stage_width/2.0f - image_width/2.0f, stage_height/2.0f - image_height/2.0f, stage_width/2.0f + image_width/2.0f, stage_height/2.0f + image_height/2.0f); } static void set_shader_num (int new_no) { CoglHandle shader; CoglHandle program; int image_width = cogl_texture_get_width (redhand); int image_height = cogl_texture_get_height (redhand); int uniform_no; g_print ("setting shaders[%i] named '%s'\n", new_no, shaders[new_no].name); shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); cogl_shader_source (shader, shaders[new_no].source); cogl_shader_compile (shader); program = cogl_create_program (); cogl_program_attach_shader (program, shader); cogl_handle_unref (shader); cogl_program_link (program); uniform_no = cogl_program_get_uniform_location (program, "tex"); cogl_program_set_uniform_1i (program, uniform_no, 0); uniform_no = cogl_program_get_uniform_location (program, "radius"); cogl_program_set_uniform_1f (program, uniform_no, 3.0); uniform_no = cogl_program_get_uniform_location (program, "brightness"); cogl_program_set_uniform_1f (program, uniform_no, 0.4); uniform_no = cogl_program_get_uniform_location (program, "contrast"); cogl_program_set_uniform_1f (program, uniform_no, -1.9); uniform_no = cogl_program_get_uniform_location (program, "x_step"); cogl_program_set_uniform_1f (program, uniform_no, 1.0f / image_width); uniform_no = cogl_program_get_uniform_location (program, "y_step"); cogl_program_set_uniform_1f (program, uniform_no, 1.0f / image_height); cogl_material_set_user_program (material, program); cogl_handle_unref (program); shader_no = new_no; } static gboolean button_release_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { int new_no; /* Stop the automatic cycling if the user want to manually control * which shader to display */ if (timeout_id) { g_source_remove (timeout_id); timeout_id = 0; } if (event->button.button == 1) { new_no = shader_no - 1; if (new_no < 0) new_no = G_N_ELEMENTS (shaders) - 1; } else { new_no = shader_no + 1; if (new_no >= G_N_ELEMENTS (shaders)) new_no = 0; } set_shader_num (new_no); return CLUTTER_EVENT_STOP; } static gboolean key_release_cb (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { guint keysym = clutter_event_get_key_symbol (event); ClutterModifierType mods = clutter_event_get_state (event); if (keysym == CLUTTER_KEY_q || ((mods & CLUTTER_SHIFT_MASK) && keysym == CLUTTER_KEY_q)) clutter_main_quit (); return CLUTTER_EVENT_STOP; } static gboolean timeout_cb (gpointer user_data) { shader_no++; if (shader_no > (G_N_ELEMENTS (shaders) - 1)) shader_no = 0; set_shader_num (shader_no); return G_SOURCE_CONTINUE; } static gboolean idle_cb (gpointer data) { clutter_actor_queue_redraw (data); return G_SOURCE_CONTINUE; } static gboolean destroy_window_cb (ClutterStage *stage, ClutterEvent *event, gpointer user_data) { clutter_main_quit (); return CLUTTER_EVENT_STOP; } G_MODULE_EXPORT int test_cogl_shader_glsl_main (int argc, char *argv[]) { ClutterActor *stage; char *file; GError *error; ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Assembly Shader Test"); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); error = NULL; redhand = cogl_texture_new_from_file (file, COGL_TEXTURE_NO_ATLAS, COGL_PIXEL_FORMAT_ANY, &error); if (redhand == COGL_INVALID_HANDLE) g_error ("image load failed: %s", error->message); material = cogl_material_new (); cogl_material_set_layer (material, 0, redhand); set_shader_num (0); g_signal_connect_after (stage, "paint", G_CALLBACK (paint_cb), NULL); clutter_actor_set_reactive (stage, TRUE); g_signal_connect (stage, "button-release-event", G_CALLBACK (button_release_cb), NULL); g_signal_connect (stage, "key-release-event", G_CALLBACK (key_release_cb), NULL); g_signal_connect (stage, "delete-event", G_CALLBACK (destroy_window_cb), NULL); timeout_id = clutter_threads_add_timeout (1000, timeout_cb, NULL); clutter_threads_add_idle (idle_cb, stage); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-binding-pool.c������������������������������������������0000664�0001750�0001750�00000022425�14211404421�024004� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <stdio.h> #include <glib.h> #include <gmodule.h> #include <clutter/clutter.h> #include <clutter/clutter-keysyms.h> #define TYPE_KEY_GROUP (key_group_get_type ()) #define KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_KEY_GROUP, KeyGroup)) #define IS_KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_KEY_GROUP)) #define KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_KEY_GROUP, KeyGroupClass)) #define IS_KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_KEY_GROUP)) typedef struct _KeyGroup KeyGroup; typedef struct _KeyGroupClass KeyGroupClass; struct _KeyGroup { ClutterActor parent_instance; gint selected_index; }; struct _KeyGroupClass { ClutterActorClass parent_class; void (* activate) (KeyGroup *group, ClutterActor *child); }; G_DEFINE_TYPE (KeyGroup, key_group, CLUTTER_TYPE_ACTOR) enum { ACTIVATE, LAST_SIGNAL }; static guint group_signals[LAST_SIGNAL] = { 0, }; static gboolean key_group_action_move_left (KeyGroup *self, const gchar *action_name, guint key_val, ClutterModifierType modifiers) { gint n_children; g_debug ("%s: activated '%s' (k:%d, m:%d)", G_STRLOC, action_name, key_val, modifiers); n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self)); self->selected_index -= 1; if (self->selected_index < 0) self->selected_index = n_children - 1; return TRUE; } static gboolean key_group_action_move_right (KeyGroup *self, const gchar *action_name, guint key_val, ClutterModifierType modifiers) { gint n_children; g_debug ("%s: activated '%s' (k:%d, m:%d)", G_STRLOC, action_name, key_val, modifiers); n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self)); self->selected_index += 1; if (self->selected_index >= n_children) self->selected_index = 0; return TRUE; } static gboolean key_group_action_activate (KeyGroup *self, const gchar *action_name, guint key_val, ClutterModifierType modifiers) { ClutterActor *child = NULL; g_debug ("%s: activated '%s' (k:%d, m:%d)", G_STRLOC, action_name, key_val, modifiers); if (self->selected_index == -1) return FALSE; child = clutter_actor_get_child_at_index (CLUTTER_ACTOR (self), self->selected_index); if (child != NULL) { g_signal_emit (self, group_signals[ACTIVATE], 0, child); return TRUE; } else return FALSE; } static gboolean key_group_key_press (ClutterActor *actor, ClutterKeyEvent *event) { ClutterBindingPool *pool; gboolean res; pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor)); g_assert (pool != NULL); res = clutter_binding_pool_activate (pool, event->keyval, event->modifier_state, G_OBJECT (actor)); /* if we activate a key binding, redraw the actor */ if (res) clutter_actor_queue_redraw (actor); return res ? CLUTTER_EVENT_STOP : CLUTTER_EVENT_PROPAGATE; } static void key_group_paint (ClutterActor *actor) { KeyGroup *self = KEY_GROUP (actor); ClutterActorIter iter; ClutterActor *child; gint i = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { /* paint the selection rectangle */ if (i == self->selected_index) { ClutterActorBox box = { 0, }; clutter_actor_get_allocation_box (child, &box); box.x1 -= 2; box.y1 -= 2; box.x2 += 2; box.y2 += 2; cogl_set_source_color4ub (255, 255, 0, 224); cogl_rectangle (box.x1, box.y1, box.x2, box.y2); } clutter_actor_paint (child); i += 1; } } static void key_group_class_init (KeyGroupClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); ClutterBindingPool *binding_pool; actor_class->paint = key_group_paint; actor_class->key_press_event = key_group_key_press; group_signals[ACTIVATE] = g_signal_new (g_intern_static_string ("activate"), G_OBJECT_CLASS_TYPE (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (KeyGroupClass, activate), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); binding_pool = clutter_binding_pool_get_for_class (klass); clutter_binding_pool_install_action (binding_pool, "move-right", CLUTTER_KEY_Right, 0, G_CALLBACK (key_group_action_move_right), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "move-left", CLUTTER_KEY_Left, 0, G_CALLBACK (key_group_action_move_left), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_Return, 0, G_CALLBACK (key_group_action_activate), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_KP_Enter, 0, G_CALLBACK (key_group_action_activate), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_ISO_Enter, 0, G_CALLBACK (key_group_action_activate), NULL, NULL); } static void key_group_init (KeyGroup *self) { self->selected_index = -1; } static void on_key_group_activate (KeyGroup *group, ClutterActor *child) { g_print ("Child '%s' activated!\n", clutter_actor_get_name (child)); } G_MODULE_EXPORT int test_binding_pool_main (int argc, char *argv[]) { ClutterActor *stage, *key_group; gint group_x, group_y; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Key Binding Pool"); g_signal_connect (stage, "button-press-event", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); key_group = g_object_new (TYPE_KEY_GROUP, NULL); clutter_actor_add_child (stage, key_group); /* add three rectangles to the key group */ clutter_container_add (CLUTTER_CONTAINER (key_group), g_object_new (CLUTTER_TYPE_ACTOR, "background-color", CLUTTER_COLOR_Red, "name", "Red Rectangle", "width", 100.0, "height", 100.0, "x", 0.0, "y", 0.0, NULL), g_object_new (CLUTTER_TYPE_ACTOR, "background-color", CLUTTER_COLOR_Green, "name", "Green Rectangle", "width", 100.0, "height", 100.0, "x", 125.0, "y", 0.0, NULL), g_object_new (CLUTTER_TYPE_ACTOR, "background-color", CLUTTER_COLOR_Blue, "name", "Blue Rectangle", "width", 100.0, "height", 100.0, "x", 250.0, "y", 0.0, NULL), NULL); g_signal_connect (key_group, "activate", G_CALLBACK (on_key_group_activate), NULL); group_x = (clutter_actor_get_width (stage) - clutter_actor_get_width (key_group)) / 2; group_y = (clutter_actor_get_height (stage) - clutter_actor_get_height (key_group)) / 2; clutter_actor_set_position (key_group, group_x, group_y); clutter_actor_set_reactive (key_group, TRUE); clutter_stage_set_key_focus (CLUTTER_STAGE (stage), key_group); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_binding_pool_describe (void) { return "Binding pools example"; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-script.c������������������������������������������������0000664�0001750�0001750�00000012212�14211404421�022720� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <stdio.h> #include <math.h> #include <glib.h> #include <gmodule.h> #include <clutter/clutter.h> static ClutterScript *script = NULL; static guint merge_id = 0; static const gchar *test_unmerge = "[" " {" " \"id\" : \"main-stage\"," " \"type\" : \"ClutterStage\"," " \"children\" : [ \"blue-button\" ]" " }," " {" " \"id\" : \"blue-button\"," " \"type\" : \"ClutterRectangle\"," " \"color\" : \"#0000ffff\"," " \"x\" : 350," " \"y\" : 50," " \"width\" : 100," " \"height\" : 100," " \"visible\" : true," " \"reactive\" : true" " }" "]"; static const gchar *test_behaviour = "[" " {" " \"id\" : \"main-timeline\"," " \"type\" : \"ClutterTimeline\"," " \"duration\" : 5000," " \"loop\" : true" " }," " {" " \"id\" : \"sine-alpha\"," " \"type\" : \"ClutterAlpha\"," " \"function\" : \"sine_alpha\"," " \"timeline\" : \"main-timeline\"" " }," " {" " \"id\" : \"path-behaviour\"," " \"type\" : \"ClutterBehaviourPath\"," " \"path\" : \"M 50 50 L 100 100\"," " \"alpha\" : {" " \"timeline\" : \"main-timeline\"," " \"function\" : \"double_ramp_alpha\"" " }" " }," " {" " \"id\" : \"rotate-behaviour\"," " \"type\" : \"ClutterBehaviourRotate\"," " \"angle-start\" : 0.0," " \"angle-end\" : 360.0," " \"axis\" : \"y-axis\"," " \"alpha\" : \"sine-alpha\"" " }," " {" " \"id\" : \"fade-behaviour\"," " \"type\" : \"ClutterBehaviourOpacity\"," " \"opacity-start\" : 255," " \"opacity-end\" : 0," " \"alpha\" : {" " \"id\" : \"fade-alpha\"," " \"type\" : \"ClutterAlpha\"," " \"timeline\" : \"main-timeline\"," " \"mode\" : \"linear\"" " }" " }" "]"; gdouble sine_alpha (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); return sin (clutter_timeline_get_progress (timeline) * G_PI); } gdouble double_ramp_alpha (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); gdouble progress = clutter_timeline_get_progress (timeline); if (progress >= 0.5) return 1.0 - progress; return progress; } static gboolean blue_button_press (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { g_print ("[*] Pressed '%s'\n", clutter_get_script_id (G_OBJECT (actor))); g_print ("[*] Unmerging objects with merge id: %d\n", merge_id); clutter_script_unmerge_objects (script, merge_id); return TRUE; } static gboolean red_button_press (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { GObject *timeline; g_print ("[*] Pressed '%s'\n", clutter_get_script_id (G_OBJECT (actor))); timeline = clutter_script_get_object (script, "main-timeline"); g_assert (CLUTTER_IS_TIMELINE (timeline)); if (!clutter_timeline_is_playing (CLUTTER_TIMELINE (timeline))) clutter_timeline_start (CLUTTER_TIMELINE (timeline)); else clutter_timeline_pause (CLUTTER_TIMELINE (timeline)); return TRUE; } G_MODULE_EXPORT int test_script_main (int argc, char *argv[]) { GObject *stage, *blue_button, *red_button; GError *error = NULL; gchar *file; gint res; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; script = clutter_script_new (); g_assert (CLUTTER_IS_SCRIPT (script)); clutter_script_load_from_data (script, test_behaviour, -1, &error); if (error) { g_print ("*** Error:\n" "*** %s\n", error->message); g_error_free (error); g_object_unref (script); return EXIT_FAILURE; } file = g_build_filename (TESTS_DATADIR, "test-script.json", NULL); clutter_script_load_from_file (script, file, &error); if (error) { g_print ("*** Error:\n" "*** %s\n", error->message); g_error_free (error); g_object_unref (script); free (file); return EXIT_FAILURE; } free (file); merge_id = clutter_script_load_from_data (script, test_unmerge, -1, &error); if (error) { g_print ("*** Error:\n" "*** %s\n", error->message); g_error_free (error); g_object_unref (script); return EXIT_FAILURE; } clutter_script_connect_signals (script, NULL); res = clutter_script_get_objects (script, "main-stage", &stage, "red-button", &red_button, "blue-button", &blue_button, NULL); g_assert (res == 3); clutter_actor_show (CLUTTER_ACTOR (stage)); g_signal_connect (red_button, "button-press-event", G_CALLBACK (red_button_press), NULL); g_signal_connect (blue_button, "button-press-event", G_CALLBACK (blue_button_press), NULL); clutter_main (); g_object_unref (script); return EXIT_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-fbo.c���������������������������������������������������0000664�0001750�0001750�00000006240�14211404421�022166� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <errno.h> #include <stdlib.h> #include <glib.h> #include <gmodule.h> #define STAGE_WIDTH 800 #define STAGE_HEIGHT 600 ClutterActor * make_source (void) { ClutterActor *source, *actor; GError *error = NULL; gchar *file; ClutterColor yellow = {0xff, 0xff, 0x00, 0xff}; source = clutter_group_new (); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); actor = clutter_texture_new_from_file (file, &error); if (!actor) g_error("pixbuf load failed: %s", error ? error->message : "Unknown"); free (file); clutter_container_add_actor (CLUTTER_CONTAINER (source), actor); actor = clutter_text_new_with_text ("Sans Bold 50px", "Clutter"); clutter_text_set_color (CLUTTER_TEXT (actor), &yellow); clutter_actor_set_y (actor, clutter_actor_get_height(source) + 5); clutter_container_add_actor (CLUTTER_CONTAINER (source), actor); return source; } G_MODULE_EXPORT int test_fbo_main (int argc, char *argv[]) { ClutterActor *fbo; ClutterActor *onscreen_source; ClutterActor *stage; ClutterAnimation *animation; int x_pos = 200; int y_pos = 100; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; if (clutter_feature_available (CLUTTER_FEATURE_OFFSCREEN) == FALSE) g_error("This test requires CLUTTER_FEATURE_OFFSCREEN"); stage = clutter_stage_new (); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); clutter_actor_set_background_color (stage, CLUTTER_COLOR_SkyBlue); clutter_stage_set_title (CLUTTER_STAGE (stage), "Texture from Actor"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* Create the first source */ onscreen_source = make_source(); clutter_actor_show_all (onscreen_source); clutter_container_add_actor (CLUTTER_CONTAINER (stage), onscreen_source); y_pos = (STAGE_HEIGHT/2.0) - (clutter_actor_get_height (onscreen_source)/2.0); clutter_actor_set_position (onscreen_source, x_pos, y_pos); x_pos += clutter_actor_get_width (onscreen_source); animation = clutter_actor_animate (onscreen_source, CLUTTER_LINEAR, 5000, /* 1 second duration */ "rotation-angle-y", 360.0f, NULL); clutter_animation_set_loop (animation, TRUE); /* Second hand = actor from onscreen_source */ if ((fbo = clutter_texture_new_from_actor (onscreen_source)) == NULL) g_error("onscreen fbo creation failed"); clutter_actor_set_position (fbo, x_pos, y_pos); x_pos += clutter_actor_get_width (fbo); clutter_container_add_actor (CLUTTER_CONTAINER (stage), fbo); /* Third hand = actor from Second hand */ if ((fbo = clutter_texture_new_from_actor (fbo)) == NULL) g_error("fbo from fbo creation failed"); clutter_actor_set_position (fbo, x_pos, y_pos); x_pos += clutter_actor_get_width (fbo); clutter_container_add_actor (CLUTTER_CONTAINER (stage), fbo); clutter_actor_show_all (stage); clutter_main (); return 0; } G_MODULE_EXPORT const char * test_fbo_describe (void) { return "Create a texture from an actor."; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-tex-convert.c��������������������������������������0000664�0001750�0001750�00000013463�14211404421�024625� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <gmodule.h> #include <stdlib.h> #include <clutter/clutter.h> #include <cogl/cogl.h> /* Coglbox declaration *--------------------------------------------------*/ G_BEGIN_DECLS #define TEST_TYPE_COGLBOX test_coglbox_get_type() #define TEST_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_IS_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ TEST_TYPE_COGLBOX)) #define TEST_IS_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ TEST_TYPE_COGLBOX)) #define TEST_COGLBOX_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) typedef struct _TestCoglbox TestCoglbox; typedef struct _TestCoglboxClass TestCoglboxClass; typedef struct _TestCoglboxPrivate TestCoglboxPrivate; struct _TestCoglbox { ClutterActor parent; /*< private >*/ TestCoglboxPrivate *priv; }; struct _TestCoglboxClass { ClutterActorClass parent_class; /* padding for future expansion */ void (*_test_coglbox1) (void); void (*_test_coglbox2) (void); void (*_test_coglbox3) (void); void (*_test_coglbox4) (void); }; static GType test_coglbox_get_type (void) G_GNUC_CONST; G_END_DECLS /* Coglbox private declaration *--------------------------------------------------*/ G_DEFINE_TYPE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR); #define TEST_COGLBOX_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TEST_TYPE_COGLBOX, TestCoglboxPrivate)) struct _TestCoglboxPrivate { CoglHandle cogl_tex_id[4]; gint frame; }; /* Coglbox implementation *--------------------------------------------------*/ static void test_coglbox_paint(ClutterActor *self) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self); gfloat texcoords[4] = { 0.0, 0.0, 1.0, 1.0 }; priv = TEST_COGLBOX_GET_PRIVATE (self); cogl_set_source_color4ub (0x66, 0x66, 0xdd, 0xff); cogl_rectangle (0, 0, 400, 400); cogl_push_matrix (); cogl_set_source_texture (priv->cogl_tex_id[0]); cogl_rectangle_with_texture_coords (0, 0, 200, 213, texcoords[0], texcoords[1], texcoords[2], texcoords[3]); cogl_pop_matrix (); cogl_push_matrix (); cogl_translate (200, 0, 0); cogl_set_source_texture (priv->cogl_tex_id[1]); cogl_rectangle_with_texture_coords (0, 0, 200, 213, texcoords[0], texcoords[1], texcoords[2], texcoords[3]); cogl_pop_matrix (); cogl_push_matrix (); cogl_translate (0, 200, 0); cogl_set_source_texture (priv->cogl_tex_id[2]); cogl_rectangle_with_texture_coords (0, 0, 200, 213, texcoords[0], texcoords[1], texcoords[2], texcoords[3]); cogl_pop_matrix (); cogl_push_matrix (); cogl_translate (200, 200, 0); cogl_set_source_texture (priv->cogl_tex_id[3]); cogl_rectangle_with_texture_coords (0, 0, 200, 213, texcoords[0], texcoords[1], texcoords[2], texcoords[3]); cogl_pop_matrix(); } static void test_coglbox_finalize (GObject *object) { G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object); } static void test_coglbox_dispose (GObject *object) { TestCoglboxPrivate *priv; priv = TEST_COGLBOX_GET_PRIVATE (object); cogl_handle_unref (priv->cogl_tex_id); G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object); } static void test_coglbox_init (TestCoglbox *self) { TestCoglboxPrivate *priv; gchar *file; self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); priv->cogl_tex_id[0] = cogl_texture_new_from_file (file, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); priv->cogl_tex_id[1] = cogl_texture_new_from_file (file, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_BGRA_8888, NULL); priv->cogl_tex_id[2] = cogl_texture_new_from_file (file, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ARGB_8888, NULL); priv->cogl_tex_id[3] = cogl_texture_new_from_file (file, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_G_8, NULL); free (file); } static void test_coglbox_class_init (TestCoglboxClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); gobject_class->finalize = test_coglbox_finalize; gobject_class->dispose = test_coglbox_dispose; actor_class->paint = test_coglbox_paint; g_type_class_add_private (gobject_class, sizeof (TestCoglboxPrivate)); } static ClutterActor* test_coglbox_new (void) { return g_object_new (TEST_TYPE_COGLBOX, NULL); } G_MODULE_EXPORT int test_cogl_tex_convert_main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *coglbox; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* Stage */ stage = clutter_stage_new (); clutter_actor_set_size (stage, 400, 400); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Texture Conversion"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* Cogl Box */ coglbox = test_coglbox_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox); clutter_actor_show_all (stage); clutter_main (); return 0; } G_MODULE_EXPORT const char * test_cogl_tex_convert_describe (void) { return "Pixel format conversion of Cogl textures."; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-content.c�����������������������������������������������0000664�0001750�0001750�00000015023�14211404421�023071� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> typedef struct _ColorContent { GObject parent_instance; double red; double green; double blue; double alpha; float padding; } ColorContent; typedef struct _ColorContentClass { GObjectClass parent_class; } ColorContentClass; static void clutter_content_iface_init (ClutterContentIface *iface); G_DEFINE_TYPE_WITH_CODE (ColorContent, color_content, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, clutter_content_iface_init)) static void color_content_paint_content (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *root) { ColorContent *self = (ColorContent *) content; ClutterActorBox box, content_box; ClutterColor color; PangoLayout *layout; PangoRectangle logical; ClutterPaintNode *node; #if 0 g_debug ("Painting content [%p] " "{ r:%.2f, g:%.2f, b:%.2f, a:%.2f } " "for actor [%p] (context: [%p])", content, self->red, self->green, self->blue, self->alpha, actor, context); #endif clutter_actor_get_content_box (actor, &content_box); box = content_box; box.x1 += self->padding; box.y1 += self->padding; box.x2 -= self->padding; box.y2 -= self->padding; color.alpha = self->alpha * 255; color.red = self->red * 255; color.green = self->green * 255; color.blue = self->blue * 255; node = clutter_color_node_new (&color); clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); color.red = (1.0 - self->red) * 255; color.green = (1.0 - self->green) * 255; color.blue = (1.0 - self->blue) * 255; layout = clutter_actor_create_pango_layout (actor, "A"); pango_layout_get_pixel_extents (layout, NULL, &logical); node = clutter_text_node_new (layout, &color); /* top-left */ box.x1 = clutter_actor_box_get_x (&content_box); box.y1 = clutter_actor_box_get_y (&content_box); box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* top-right */ box.x1 = clutter_actor_box_get_x (&content_box) + clutter_actor_box_get_width (&content_box) - logical.width; box.y1 = clutter_actor_box_get_y (&content_box); box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* bottom-right */ box.x1 = clutter_actor_box_get_x (&content_box) + clutter_actor_box_get_width (&content_box) - logical.width; box.y1 = clutter_actor_box_get_y (&content_box) + clutter_actor_box_get_height (&content_box) - logical.height; box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* bottom-left */ box.x1 = clutter_actor_box_get_x (&content_box); box.y1 = clutter_actor_box_get_y (&content_box) + clutter_actor_box_get_height (&content_box) - logical.height; box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* center */ box.x1 = clutter_actor_box_get_x (&content_box) + (clutter_actor_box_get_width (&content_box) - logical.width) / 2.0; box.y1 = clutter_actor_box_get_y (&content_box) + (clutter_actor_box_get_height (&content_box) - logical.height) / 2.0; box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); g_object_unref (layout); } static void clutter_content_iface_init (ClutterContentIface *iface) { iface->paint_content = color_content_paint_content; } static void color_content_class_init (ColorContentClass *klass) { } static void color_content_init (ColorContent *self) { } static ClutterContent * color_content_new (double red, double green, double blue, double alpha, float padding) { ColorContent *self = g_object_new (color_content_get_type (), NULL); self->red = red; self->green = green; self->blue = blue; self->alpha = alpha; self->padding = padding; return (ClutterContent *) self; } G_MODULE_EXPORT int test_content_main (int argc, char *argv[]) { ClutterActor *stage, *grid; ClutterContent *content; int i, n_rects; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_actor_set_name (stage, "Stage"); clutter_stage_set_title (CLUTTER_STAGE (stage), "Content"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_actor_show (stage); grid = clutter_actor_new (); clutter_actor_set_name (grid, "Grid"); clutter_actor_set_margin_top (grid, 12); clutter_actor_set_margin_right (grid, 12); clutter_actor_set_margin_bottom (grid, 12); clutter_actor_set_margin_left (grid, 12); clutter_actor_set_layout_manager (grid, clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL)); clutter_actor_add_constraint (grid, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0)); clutter_actor_add_child (stage, grid); content = color_content_new (g_random_double_range (0.0, 1.0), g_random_double_range (0.0, 1.0), g_random_double_range (0.0, 1.0), 1.0, 2.0); n_rects = g_random_int_range (12, 24); for (i = 0; i < n_rects; i++) { ClutterActor *box = clutter_actor_new (); ClutterColor bg_color = { g_random_int_range (0, 255), g_random_int_range (0, 255), g_random_int_range (0, 255), 255 }; char *name, *color; color = clutter_color_to_string (&bg_color); name = g_strconcat ("Box <", color, ">", NULL); clutter_actor_set_name (box, name); free (name); free (color); clutter_actor_set_background_color (box, &bg_color); clutter_actor_set_content (box, content); clutter_actor_set_size (box, 64, 64); clutter_actor_add_child (grid, box); } clutter_main (); g_object_unref (content); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_content_describe (void) { return "A simple test for ClutterContent"; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-paint-wrapper.c�����������������������������������������0000664�0001750�0001750�00000021473�14211404421�024216� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <gmodule.h> #include <clutter/clutter.h> #if defined (_MSC_VER) && !defined (_USE_MATH_DEFINES) #define _USE_MATH_DEFINES #endif #include <math.h> #include <errno.h> #include <stdlib.h> #include <glib.h> #ifdef CLUTTER_WINDOWING_X11 #include "clutter/x11/clutter-x11.h" #endif #define NHANDS 6 typedef struct SuperOH { ClutterActor **hand, *bgtex; ClutterActor *real_hand; ClutterActor *group; ClutterActor *stage; gint stage_width; gint stage_height; gfloat radius; ClutterBehaviour *scaler_1; ClutterBehaviour *scaler_2; ClutterTimeline *timeline; guint frame_id; gboolean *paint_guards; } SuperOH; static gint n_hands = NHANDS; static gint use_alpha = 255; static GOptionEntry super_oh_entries[] = { { "num-hands", 'n', 0, G_OPTION_ARG_INT, &n_hands, "Number of hands", "HANDS" }, { "use-alpha", 'a', 0, G_OPTION_ARG_INT, &use_alpha, "Stage opacity", "VALUE" }, { NULL } }; static gboolean on_button_press_event (ClutterActor *actor, ClutterEvent *event, SuperOH *oh) { gfloat x, y; clutter_event_get_coords (event, &x, &y); g_print ("*** button press event (button:%d) at %.2f, %.2f ***\n", clutter_event_get_button (event), x, y); clutter_actor_hide (actor); return TRUE; } static gboolean input_cb (ClutterActor *stage, ClutterEvent *event, gpointer data) { SuperOH *oh = data; if (event->type == CLUTTER_KEY_RELEASE) { g_print ("*** key press event (key:%c) ***\n", clutter_event_get_key_symbol (event)); if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_q) { clutter_main_quit (); return TRUE; } else if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_r) { gint i; for (i = 0; i < n_hands; i++) clutter_actor_show (oh->hand[i]); return TRUE; } } return FALSE; } /* Timeline handler */ static void frame_cb (ClutterTimeline *timeline, gint msecs, gpointer data) { SuperOH *oh = data; gint i; float rotation = clutter_timeline_get_progress (timeline) * 360.0f; /* Rotate everything clockwise about stage center*/ clutter_actor_set_rotation (oh->group, CLUTTER_Z_AXIS, rotation, oh->stage_width / 2, oh->stage_height / 2, 0); for (i = 0; i < n_hands; i++) { /* Rotate each hand around there centers - to get this we need * to take into account any scaling. */ clutter_actor_set_rotation (oh->hand[i], CLUTTER_Z_AXIS, -6.0 * rotation, 0, 0, 0); } } static gdouble my_sine_wave (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); gdouble progress = clutter_timeline_get_progress (timeline); return sin (progress * G_PI); } static void hand_pre_paint (ClutterActor *actor, gpointer user_data) { SuperOH *oh = user_data; gfloat w, h; int actor_num; for (actor_num = 0; oh->hand[actor_num] != actor; actor_num++) ; g_assert (oh->paint_guards[actor_num] == FALSE); clutter_actor_get_size (actor, &w, &h); cogl_set_source_color4ub (255, 0, 0, 128); cogl_rectangle (0, 0, w / 2, h / 2); oh->paint_guards[actor_num] = TRUE; } static void hand_post_paint (ClutterActor *actor, gpointer user_data) { SuperOH *oh = user_data; gfloat w, h; int actor_num; for (actor_num = 0; oh->hand[actor_num] != actor; actor_num++) ; g_assert (oh->paint_guards[actor_num] == TRUE); clutter_actor_get_size (actor, &w, &h); cogl_set_source_color4ub (0, 255, 0, 128); cogl_rectangle (w / 2, h / 2, w, h); oh->paint_guards[actor_num] = FALSE; } static void stop_and_quit (ClutterActor *actor, SuperOH *oh) { g_signal_handler_disconnect (oh->timeline, oh->frame_id); clutter_timeline_stop (oh->timeline); clutter_main_quit (); } G_MODULE_EXPORT int test_paint_wrapper_main (int argc, char *argv[]) { ClutterAlpha *alpha; ClutterActor *stage; ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; SuperOH *oh; gint i; GError *error; ClutterActor *real_hand; error = NULL; #ifdef CLUTTER_WINDOWING_X11 clutter_x11_set_use_argb_visual (TRUE); #endif if (clutter_init_with_args (&argc, &argv, NULL, super_oh_entries, NULL, &error) != CLUTTER_INIT_SUCCESS) { g_warning ("Unable to initialise Clutter:\n%s", error->message); g_error_free (error); return EXIT_FAILURE; } oh = g_new(SuperOH, 1); stage = clutter_stage_new (); clutter_actor_set_size (stage, 800, 600); if (use_alpha != 255) { clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_opacity (stage, use_alpha); } clutter_stage_set_title (CLUTTER_STAGE (stage), "Paint Test"); clutter_actor_set_background_color (stage, &stage_color); g_signal_connect (stage, "destroy", G_CALLBACK (stop_and_quit), oh); oh->stage = stage; /* Create a timeline to manage animation */ oh->timeline = clutter_timeline_new (6000); clutter_timeline_set_repeat_count (oh->timeline, -1); /* fire a callback for frame change */ oh->frame_id = g_signal_connect (oh->timeline, "new-frame", G_CALLBACK (frame_cb), oh); /* Set up some behaviours to handle scaling */ alpha = clutter_alpha_new_with_func (oh->timeline, my_sine_wave, NULL, NULL); oh->scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, 1.0, 1.0); oh->scaler_2 = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 0.5, 0.5); real_hand = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", &error); if (real_hand == NULL) { g_error ("image load failed: %s", error->message); return EXIT_FAILURE; } /* create a new group to hold multiple actors in a group */ oh->group = clutter_group_new(); oh->hand = g_new (ClutterActor*, n_hands); oh->stage_width = clutter_actor_get_width (stage); oh->stage_height = clutter_actor_get_height (stage); oh->radius = (oh->stage_width + oh->stage_height) / n_hands; for (i = 0; i < n_hands; i++) { gint x, y, w, h; if (i == 0) oh->hand[i] = real_hand; else oh->hand[i] = clutter_clone_new (real_hand); clutter_actor_set_reactive (oh->hand[i], TRUE); clutter_actor_set_size (oh->hand[i], 200, 213); /* Place around a circle */ w = clutter_actor_get_width (oh->hand[i]); h = clutter_actor_get_height (oh->hand[i]); x = oh->stage_width / 2 + oh->radius * cos (i * G_PI / (n_hands / 2)) - w / 2; y = oh->stage_height / 2 + oh->radius * sin (i * G_PI / (n_hands / 2)) - h / 2; clutter_actor_set_position (oh->hand[i], x, y); clutter_actor_move_anchor_point_from_gravity (oh->hand[i], CLUTTER_GRAVITY_CENTER); g_signal_connect (oh->hand[i], "button-press-event", G_CALLBACK (on_button_press_event), oh); /* paint something before each hand */ g_signal_connect (oh->hand[i], "paint", G_CALLBACK (hand_pre_paint), oh); /* paint something after each hand */ g_signal_connect_after (oh->hand[i], "paint", G_CALLBACK (hand_post_paint), oh); /* Add to our group group */ clutter_container_add_actor (CLUTTER_CONTAINER (oh->group), oh->hand[i]); if (i % 2) clutter_behaviour_apply (oh->scaler_1, oh->hand[i]); else clutter_behaviour_apply (oh->scaler_2, oh->hand[i]); } oh->paint_guards = calloc (1, sizeof (gboolean) * n_hands); /* Add the group to the stage */ clutter_container_add_actor (CLUTTER_CONTAINER (stage), CLUTTER_ACTOR (oh->group)); /* Show everying ( and map window ) */ clutter_actor_show (stage); g_signal_connect (stage, "key-release-event", G_CALLBACK (input_cb), oh); /* and start it */ clutter_timeline_start (oh->timeline); clutter_main (); g_object_unref (oh->scaler_1); g_object_unref (oh->scaler_2); g_object_unref (oh->timeline); free (oh->paint_guards); free (oh->hand); free (oh); return 0; } G_MODULE_EXPORT const char * test_paint_wrapper_describe (void) { return "Wrap an actor's paint cycle for pre and post processing."; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-texture-material.c��������������������������������������0000664�0001750�0001750�00000002764�14211404421�024723� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <gmodule.h> #include <clutter/clutter.h> G_MODULE_EXPORT int test_texture_material_main (int argc, char *argv[]) { ClutterActor *stage, *box; ClutterLayoutManager *manager; int i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Texture Material"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); manager = clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL); box = clutter_box_new (manager); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_WIDTH, -25.0)); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, -25.0)); clutter_actor_set_position (box, 25.0, 25.0); clutter_container_add_actor (CLUTTER_CONTAINER (stage), box); for (i = 0; i < 48; i++) { ClutterActor *texture = clutter_texture_new (); clutter_texture_set_load_data_async (CLUTTER_TEXTURE (texture), TRUE); clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), TRUE); clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), TESTS_DATADIR "/redhand.png", NULL); clutter_actor_set_width (texture, 96); clutter_container_add_actor (CLUTTER_CONTAINER (box), texture); } clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ������������muffin-5.2.1/clutter/tests/interactive/test-image.c�������������������������������������������������0000664�0001750�0001750�00000016352�14211404421�022507� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <gdk-pixbuf/gdk-pixbuf.h> #include <clutter/clutter.h> typedef struct _SolidContent { GObject parent_instance; double red; double green; double blue; double alpha; float padding; } SolidContent; typedef struct _SolidContentClass { GObjectClass parent_class; } SolidContentClass; static void clutter_content_iface_init (ClutterContentIface *iface); G_DEFINE_TYPE_WITH_CODE (SolidContent, solid_content, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, clutter_content_iface_init)) static void solid_content_paint_content (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *root) { SolidContent *self = (SolidContent *) content; ClutterActorBox box, content_box; ClutterColor color; PangoLayout *layout; PangoRectangle logical; ClutterPaintNode *node; #if 0 g_debug ("Painting content [%p] " "{ r:%.2f, g:%.2f, b:%.2f, a:%.2f } " "for actor [%p] (context: [%p])", content, self->red, self->green, self->blue, self->alpha, actor, context); #endif clutter_actor_get_content_box (actor, &content_box); box = content_box; box.x1 += self->padding; box.y1 += self->padding; box.x2 -= self->padding; box.y2 -= self->padding; color.alpha = self->alpha * 255; color.red = self->red * 255; color.green = self->green * 255; color.blue = self->blue * 255; node = clutter_color_node_new (&color); clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); color.red = (1.0 - self->red) * 255; color.green = (1.0 - self->green) * 255; color.blue = (1.0 - self->blue) * 255; layout = clutter_actor_create_pango_layout (actor, "A"); pango_layout_get_pixel_extents (layout, NULL, &logical); node = clutter_text_node_new (layout, &color); /* top-left */ box.x1 = clutter_actor_box_get_x (&content_box); box.y1 = clutter_actor_box_get_y (&content_box); box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* top-right */ box.x1 = clutter_actor_box_get_x (&content_box) + clutter_actor_box_get_width (&content_box) - logical.width; box.y1 = clutter_actor_box_get_y (&content_box); box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* bottom-right */ box.x1 = clutter_actor_box_get_x (&content_box) + clutter_actor_box_get_width (&content_box) - logical.width; box.y1 = clutter_actor_box_get_y (&content_box) + clutter_actor_box_get_height (&content_box) - logical.height; box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* bottom-left */ box.x1 = clutter_actor_box_get_x (&content_box); box.y1 = clutter_actor_box_get_y (&content_box) + clutter_actor_box_get_height (&content_box) - logical.height; box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); /* center */ box.x1 = clutter_actor_box_get_x (&content_box) + (clutter_actor_box_get_width (&content_box) - logical.width) / 2.0; box.y1 = clutter_actor_box_get_y (&content_box) + (clutter_actor_box_get_height (&content_box) - logical.height) / 2.0; box.x2 = box.x1 + logical.width; box.y2 = box.y1 + logical.height; clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); g_object_unref (layout); } static void clutter_content_iface_init (ClutterContentIface *iface) { iface->paint_content = solid_content_paint_content; } static void solid_content_class_init (SolidContentClass *klass) { } static void solid_content_init (SolidContent *self) { } static ClutterContent * solid_content_new (double red, double green, double blue, double alpha, float padding) { SolidContent *self = g_object_new (solid_content_get_type (), NULL); self->red = red; self->green = green; self->blue = blue; self->alpha = alpha; self->padding = padding; return (ClutterContent *) self; } G_MODULE_EXPORT const char * test_image_describe (void) { return "A test with image content."; } G_MODULE_EXPORT int test_image_main (int argc, char *argv[]) { ClutterActor *stage, *grid; ClutterContent *color, *image; GdkPixbuf *pixbuf; int i, n_rects; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; stage = clutter_stage_new (); clutter_actor_set_name (stage, "Stage"); clutter_stage_set_title (CLUTTER_STAGE (stage), "Content"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_actor_show (stage); grid = clutter_actor_new (); clutter_actor_set_name (grid, "Grid"); clutter_actor_set_margin_top (grid, 12); clutter_actor_set_margin_right (grid, 12); clutter_actor_set_margin_bottom (grid, 12); clutter_actor_set_margin_left (grid, 12); clutter_actor_set_layout_manager (grid, clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL)); clutter_actor_add_constraint (grid, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0)); clutter_actor_add_child (stage, grid); color = solid_content_new (g_random_double_range (0.0, 1.0), g_random_double_range (0.0, 1.0), g_random_double_range (0.0, 1.0), 1.0, 2.0); pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL); image = clutter_image_new (); clutter_image_set_data (CLUTTER_IMAGE (image), gdk_pixbuf_get_pixels (pixbuf), gdk_pixbuf_get_has_alpha (pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), gdk_pixbuf_get_rowstride (pixbuf), NULL); g_object_unref (pixbuf); n_rects = g_random_int_range (12, 24); for (i = 0; i < n_rects; i++) { ClutterActor *box = clutter_actor_new (); ClutterColor bg_color = { g_random_int_range (0, 255), g_random_int_range (0, 255), g_random_int_range (0, 255), 255 }; char *name, *str; str = clutter_color_to_string (&bg_color); name = g_strconcat ("Box <", color, ">", NULL); clutter_actor_set_name (box, name); free (name); free (str); if ((i % 2) == 0) clutter_actor_set_content (box, color); else clutter_actor_set_content (box, image); clutter_actor_set_size (box, 64, 64); clutter_actor_add_child (grid, box); } clutter_main (); g_object_unref (color); g_object_unref (image); return EXIT_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-easing.c������������������������������������������������0000664�0001750�0001750�00000020545�14211404421�022672� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> /* all the easing modes provided by Clutter */ static const struct { const gchar *name; ClutterAnimationMode mode; } easing_modes[] = { { "linear", CLUTTER_LINEAR }, { "easeInQuad", CLUTTER_EASE_IN_QUAD }, { "easeOutQuad", CLUTTER_EASE_OUT_QUAD }, { "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD }, { "easeInCubic", CLUTTER_EASE_IN_CUBIC }, { "easeOutCubic", CLUTTER_EASE_OUT_CUBIC }, { "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC }, { "easeInQuart", CLUTTER_EASE_IN_QUART }, { "easeOutQuart", CLUTTER_EASE_OUT_QUART }, { "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART }, { "easeInQuint", CLUTTER_EASE_IN_QUINT }, { "easeOutQuint", CLUTTER_EASE_OUT_QUINT }, { "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT }, { "easeInSine", CLUTTER_EASE_IN_SINE }, { "easeOutSine", CLUTTER_EASE_OUT_SINE }, { "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE }, { "easeInExpo", CLUTTER_EASE_IN_EXPO }, { "easeOutExpo", CLUTTER_EASE_OUT_EXPO }, { "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO }, { "easeInCirc", CLUTTER_EASE_IN_CIRC }, { "easeOutCirc", CLUTTER_EASE_OUT_CIRC }, { "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC }, { "easeInElastic", CLUTTER_EASE_IN_ELASTIC }, { "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC }, { "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC }, { "easeInBack", CLUTTER_EASE_IN_BACK }, { "easeOutBack", CLUTTER_EASE_OUT_BACK }, { "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK }, { "easeInBounce", CLUTTER_EASE_IN_BOUNCE }, { "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE }, { "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE }, }; #define HELP_TEXT "Easing mode: %s (%d of %d)\n" \ "Left click to tween\n" \ "Right click to change the easing mode" static const gint n_easing_modes = G_N_ELEMENTS (easing_modes); static gint current_mode = 0; static gint duration = 1; static gboolean recenter = FALSE; static ClutterActor *main_stage = NULL; static ClutterActor *easing_mode_label = NULL; static ClutterAnimation *last_animation = NULL; /* recenter_bouncer: * * repositions (through an animation) the bouncer at the center of the stage */ static void recenter_bouncer (ClutterAnimation *animation, ClutterActor *rectangle) { gfloat base_x, base_y; gint cur_mode; base_x = clutter_actor_get_width (main_stage) / 2; base_y = clutter_actor_get_height (main_stage) / 2; cur_mode = easing_modes[current_mode].mode; clutter_actor_animate (rectangle, cur_mode, 250, "x", base_x, "y", base_y, NULL); } static gboolean on_button_press (ClutterActor *actor, ClutterButtonEvent *event, ClutterActor *rectangle) { if (event->button == CLUTTER_BUTTON_SECONDARY) { gchar *text; /* cycle through the various easing modes */ current_mode = (current_mode + 1 < n_easing_modes) ? current_mode + 1 : 0; /* update the text of the label */ text = g_strdup_printf (HELP_TEXT, easing_modes[current_mode].name, current_mode + 1, n_easing_modes); clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text); free (text); } else if (event->button == CLUTTER_BUTTON_PRIMARY) { ClutterAnimation *animation; ClutterAnimationMode cur_mode; cur_mode = easing_modes[current_mode].mode; /* tween the actor using the current easing mode */ animation = clutter_actor_animate (rectangle, cur_mode, duration * 1000, "x", event->x, "y", event->y, NULL); /* if we were asked to, recenter the bouncer at the end of the * animation. we keep track of the animation to avoid connecting * the signal handler to the same Animation twice. */ if (recenter && last_animation != animation) g_signal_connect_after (animation, "completed", G_CALLBACK (recenter_bouncer), rectangle); last_animation = animation; } return TRUE; } static gboolean draw_bouncer (ClutterCairoTexture *texture, cairo_t *cr) { const ClutterColor *bouncer_color; cairo_pattern_t *pattern; guint width, height; float radius; clutter_cairo_texture_get_surface_size (texture, &width, &height); radius = MAX (width, height); clutter_cairo_texture_clear (texture); cairo_arc (cr, radius / 2, radius / 2, radius / 2, 0.0, 2.0 * G_PI); bouncer_color = CLUTTER_COLOR_DarkScarletRed; pattern = cairo_pattern_create_radial (radius / 2, radius / 2, 0, radius, radius, radius); cairo_pattern_add_color_stop_rgba (pattern, 0, bouncer_color->red / 255.0, bouncer_color->green / 255.0, bouncer_color->blue / 255.0, bouncer_color->alpha / 255.0); cairo_pattern_add_color_stop_rgba (pattern, 0.85, bouncer_color->red / 255.0, bouncer_color->green / 255.0, bouncer_color->blue / 255.0, 0.25); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); return TRUE; } static ClutterActor * make_bouncer (gfloat width, gfloat height) { ClutterActor *retval; retval = clutter_cairo_texture_new (width, height); g_signal_connect (retval, "draw", G_CALLBACK (draw_bouncer), NULL); clutter_actor_set_name (retval, "bouncer"); clutter_actor_set_size (retval, width, height); clutter_actor_set_anchor_point (retval, width / 2, height / 2); clutter_actor_set_reactive (retval, TRUE); /* make sure we draw the bouncer immediately */ clutter_cairo_texture_invalidate (CLUTTER_CAIRO_TEXTURE (retval)); return retval; } static GOptionEntry test_easing_entries[] = { { "re-center", 'r', 0, G_OPTION_ARG_NONE, &recenter, "Re-center the actor when the animation ends", NULL }, { "duration", 'd', 0, G_OPTION_ARG_INT, &duration, "Duration of the animation", "SECONDS" }, { NULL } }; G_MODULE_EXPORT int test_easing_main (int argc, char *argv[]) { ClutterActor *stage, *rect, *label; gchar *text; gfloat stage_width, stage_height; GError *error = NULL; if (clutter_init_with_args (&argc, &argv, NULL, test_easing_entries, NULL, &error) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Easing Modes"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); main_stage = stage; clutter_actor_get_size (stage, &stage_width, &stage_height); /* create the actor that we want to tween */ rect = make_bouncer (50, 50); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); clutter_actor_set_position (rect, stage_width / 2, stage_height / 2); text = g_strdup_printf (HELP_TEXT, easing_modes[current_mode].name, current_mode + 1, n_easing_modes); label = clutter_text_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); clutter_text_set_text (CLUTTER_TEXT (label), text); clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.95)); clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.95)); easing_mode_label = label; free (text); g_signal_connect (stage, "button-press-event", G_CALLBACK (on_button_press), rect); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_easing_describe (void) { return "Visualize all easing modes provided by Clutter"; } �����������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-touch-events.c������������������������������������������0000664�0001750�0001750�00000013544�14211404421�024051� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2012 Collabora Ltd. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * Boston, MA 02111-1307, USA. * */ #include <stdlib.h> #include <math.h> #include <cairo.h> #include <glib.h> #include <clutter/clutter.h> #define STAGE_WIDTH 800 #define STAGE_HEIGHT 550 #define NUM_COLORS 10 #define NUM_ACTORS 10 static GQueue events = G_QUEUE_INIT; static GQueue all_events = G_QUEUE_INIT; static gboolean new_surface = TRUE; static const ClutterColor const static_colors[] = { { 0xff, 0x00, 0x00, 0xff }, /* red */ { 0x80, 0x00, 0x00, 0xff }, /* dark red */ { 0x00, 0xff, 0x00, 0xff }, /* green */ { 0x00, 0x80, 0x00, 0xff }, /* dark green */ { 0x00, 0x00, 0xff, 0xff }, /* blue */ { 0x00, 0x00, 0x80, 0xff }, /* dark blue */ { 0x00, 0xff, 0xff, 0xff }, /* cyan */ { 0x00, 0x80, 0x80, 0xff }, /* dark cyan */ { 0xff, 0x00, 0xff, 0xff }, /* magenta */ { 0xff, 0xff, 0x00, 0xff }, /* yellow */ }; static GHashTable *sequence_to_color = NULL; static void canvas_paint (ClutterCairoTexture *canvas) { clutter_cairo_texture_invalidate (canvas); } static void draw_touch (ClutterEvent *event, cairo_t *cr) { ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); const ClutterColor *color; color = g_hash_table_lookup (sequence_to_color, sequence); if (color == NULL) { color = &static_colors[g_random_int_range (0, NUM_COLORS)]; g_hash_table_insert (sequence_to_color, (gpointer) sequence, (gpointer) color); } cairo_set_source_rgba (cr, color->red / 255, color->green / 255, color->blue / 255, color->alpha / 255); cairo_arc (cr, event->touch.x, event->touch.y, 5, 0, 2 * G_PI); cairo_fill (cr); } static gboolean draw_touches (ClutterCairoTexture *canvas, cairo_t *cr) { g_queue_foreach (new_surface ? &all_events : &events, (GFunc) draw_touch, cr); g_queue_clear (&events); new_surface = FALSE; return TRUE; } static cairo_surface_t * create_surface (ClutterCairoTexture *texture, guint width, guint height, gpointer user_data) { new_surface = TRUE; return NULL; } static gboolean event_cb (ClutterActor *actor, ClutterEvent *event, ClutterActor *canvas) { ClutterEvent *copy; if (event->type != CLUTTER_TOUCH_UPDATE) return FALSE; copy = clutter_event_copy (event); g_queue_push_tail (&events, copy); g_queue_push_tail (&all_events, copy); clutter_actor_queue_redraw (canvas); return TRUE; } static gboolean rect_event_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterColor color; if (event->type != CLUTTER_TOUCH_BEGIN) return FALSE; color = static_colors[g_random_int_range (0, NUM_COLORS)]; clutter_rectangle_set_color (CLUTTER_RECTANGLE (actor), &color); return TRUE; } G_MODULE_EXPORT int test_touch_events_main (int argc, char *argv[]) { ClutterActor *stage, *canvas; int i; /* initialize Clutter */ if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; /* create a resizable stage */ stage = clutter_stage_new (); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_stage_set_title (CLUTTER_STAGE (stage), "Touch events"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); clutter_actor_set_reactive (stage, TRUE); clutter_actor_show (stage); /* our 2D canvas, courtesy of Cairo */ canvas = clutter_cairo_texture_new (1, 1); g_signal_connect (canvas, "paint", G_CALLBACK (canvas_paint), NULL); g_signal_connect (canvas, "draw", G_CALLBACK (draw_touches), NULL); g_signal_connect (canvas, "create-surface", G_CALLBACK (create_surface), NULL); clutter_cairo_texture_set_auto_resize (CLUTTER_CAIRO_TEXTURE (canvas), TRUE); clutter_actor_add_constraint (canvas, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), canvas); g_signal_connect (stage, "event", G_CALLBACK (event_cb), canvas); for (i = 0; i < NUM_ACTORS; i++) { gfloat size = STAGE_HEIGHT / NUM_ACTORS; ClutterColor color = static_colors[i % NUM_COLORS]; ClutterActor *rectangle = clutter_rectangle_new_with_color (&color); /* Test that event delivery to actors work */ g_signal_connect (rectangle, "event", G_CALLBACK (rect_event_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle); clutter_actor_set_size (rectangle, size, size); clutter_actor_set_position (rectangle, 0, i * size); clutter_actor_set_reactive (rectangle, TRUE); } sequence_to_color = g_hash_table_new (NULL, NULL); clutter_main (); g_queue_foreach (&all_events, (GFunc) clutter_event_free, NULL); g_queue_clear (&events); g_queue_clear (&all_events); g_hash_table_destroy (sequence_to_color); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_touch_events_describe (void) { return "Draw shapes based on touch events"; } ������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-vertex-buffer.c������������������������������������0000664�0001750�0001750�00000030352�14211404421�025127� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <gmodule.h> #include <stdlib.h> #include <clutter/clutter.h> #include <cogl/cogl.h> #include <math.h> /* Defines the size and resolution of the quad mesh we morph: */ #define MESH_WIDTH 100.0 /* number of quads along x axis */ #define MESH_HEIGHT 100.0 /* number of quads along y axis */ #define QUAD_WIDTH 5.0 /* width in pixels of a single quad */ #define QUAD_HEIGHT 5.0 /* height in pixels of a single quad */ /* Defines a sine wave that sweeps across the mesh: */ #define WAVE_DEPTH ((MESH_WIDTH * QUAD_WIDTH) / 16.0) /* peak amplitude */ #define WAVE_PERIODS 4.0 #define WAVE_SPEED 10.0 /* Defines a rippling sine wave emitted from a point: */ #define RIPPLE_CENTER_X ((MESH_WIDTH / 2.0) * QUAD_WIDTH) #define RIPPLE_CENTER_Y ((MESH_HEIGHT / 2.0) * QUAD_HEIGHT) #define RIPPLE_RADIUS (MESH_WIDTH * QUAD_WIDTH) #define RIPPLE_DEPTH ((MESH_WIDTH * QUAD_WIDTH) / 16.0) /* peak amplitude */ #define RIPPLE_PERIODS 4.0 #define RIPPLE_SPEED -10.0 /* Defines the width of the gaussian bell used to fade out the alpha * towards the edges of the mesh (starting from the ripple center): */ #define GAUSSIAN_RADIUS ((MESH_WIDTH * QUAD_WIDTH) / 6.0) /* Our hues lie in the range [0, 1], and this defines how we map amplitude * to hues (before scaling by {WAVE,RIPPLE}_DEPTH) * As we are interferring two sine waves together; amplitudes lie in the * range [-2, 2] */ #define HSL_OFFSET 0.5 /* the hue that we map an amplitude of 0 too */ #define HSL_SCALE 0.25 typedef struct _TestState { ClutterActor *dummy; CoglHandle buffer; float *quad_mesh_verts; guint8 *quad_mesh_colors; guint16 *static_indices; guint n_static_indices; CoglHandle indices; ClutterTimeline *timeline; guint frame_id; } TestState; static void frame_cb (ClutterTimeline *timeline, gint elapsed_msecs, TestState *state) { guint x, y; float period_progress = clutter_timeline_get_progress (timeline); float period_progress_sin = sinf (period_progress); float wave_shift = period_progress * WAVE_SPEED; float ripple_shift = period_progress * RIPPLE_SPEED; for (y = 0; y <= MESH_HEIGHT; y++) for (x = 0; x <= MESH_WIDTH; x++) { guint vert_index = (MESH_WIDTH + 1) * y + x; float *vert = &state->quad_mesh_verts[3 * vert_index]; float real_x = x * QUAD_WIDTH; float real_y = y * QUAD_HEIGHT; float wave_offset = (float)x / (MESH_WIDTH + 1); float wave_angle = (WAVE_PERIODS * 2 * G_PI * wave_offset) + wave_shift; float wave_sin = sinf (wave_angle); float a_sqr = (RIPPLE_CENTER_X - real_x) * (RIPPLE_CENTER_X - real_x); float b_sqr = (RIPPLE_CENTER_Y - real_y) * (RIPPLE_CENTER_Y - real_y); float ripple_offset = sqrtf (a_sqr + b_sqr) / RIPPLE_RADIUS; float ripple_angle = (RIPPLE_PERIODS * 2 * G_PI * ripple_offset) + ripple_shift; float ripple_sin = sinf (ripple_angle); float h, s, l; guint8 *color; vert[2] = (wave_sin * WAVE_DEPTH) + (ripple_sin * RIPPLE_DEPTH); /* Burn some CPU time picking a pretty color... */ h = (HSL_OFFSET + wave_sin + ripple_sin + period_progress_sin) * HSL_SCALE; s = 0.5; l = 0.25 + (period_progress_sin + 1.0) / 4.0; color = &state->quad_mesh_colors[4 * vert_index]; /* A bit of a sneaky cast, but it seems safe to assume the ClutterColor * typedef is set in stone... */ clutter_color_from_hls ((ClutterColor *)color, h * 360.0, l, s); color[0] = (color[0] * color[3] + 128) / 255; color[1] = (color[1] * color[3] + 128) / 255; color[2] = (color[2] * color[3] + 128) / 255; } cogl_vertex_buffer_add (state->buffer, "gl_Vertex", 3, /* n components */ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, /* normalized */ 0, /* stride */ state->quad_mesh_verts); cogl_vertex_buffer_add (state->buffer, "gl_Color", 4, /* n components */ COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, FALSE, /* normalized */ 0, /* stride */ state->quad_mesh_colors); cogl_vertex_buffer_submit (state->buffer); clutter_actor_set_rotation (state->dummy, CLUTTER_Z_AXIS, 360 * period_progress, (MESH_WIDTH * QUAD_WIDTH) / 2, (MESH_HEIGHT * QUAD_HEIGHT) / 2, 0); clutter_actor_set_rotation (state->dummy, CLUTTER_X_AXIS, 360 * period_progress, (MESH_WIDTH * QUAD_WIDTH) / 2, (MESH_HEIGHT * QUAD_HEIGHT) / 2, 0); } static void on_paint (ClutterActor *actor, TestState *state) { cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw_elements (state->buffer, COGL_VERTICES_MODE_TRIANGLE_STRIP, state->indices, 0, /* min index */ (MESH_WIDTH + 1) * (MESH_HEIGHT + 1) - 1, /* max index */ 0, /* indices offset */ state->n_static_indices); } static void init_static_index_arrays (TestState *state) { guint n_indices; int x, y; guint16 *i; guint dir; /* - Each row takes (2 + 2 * MESH_WIDTH indices) * - Thats 2 to start the triangle strip then 2 indices to add 2 triangles * per mesh quad. * - We have MESH_HEIGHT rows * - It takes one extra index for linking between rows (MESH_HEIGHT - 1) * - A 2 x 3 mesh == 20 indices... */ n_indices = (2 + 2 * MESH_WIDTH) * MESH_HEIGHT + (MESH_HEIGHT - 1); state->static_indices = malloc (sizeof (guint16) * n_indices); state->n_static_indices = n_indices; #define MESH_INDEX(X, Y) (Y) * (MESH_WIDTH + 1) + (X) i = state->static_indices; /* NB: front facing == anti-clockwise winding */ i[0] = MESH_INDEX (0, 0); i[1] = MESH_INDEX (0, 1); i += 2; #define LEFT 0 #define RIGHT 1 dir = RIGHT; for (y = 0; y < MESH_HEIGHT; y++) { for (x = 0; x < MESH_WIDTH; x++) { /* Add 2 triangles per mesh quad... */ if (dir == RIGHT) { i[0] = MESH_INDEX (x + 1, y); i[1] = MESH_INDEX (x + 1, y + 1); } else { i[0] = MESH_INDEX (MESH_WIDTH - x - 1, y); i[1] = MESH_INDEX (MESH_WIDTH - x - 1, y + 1); } i += 2; } /* Link rows... */ if (y == (MESH_HEIGHT - 1)) break; if (dir == RIGHT) { i[0] = MESH_INDEX (MESH_WIDTH, y + 1); i[1] = MESH_INDEX (MESH_WIDTH, y + 1); i[2] = MESH_INDEX (MESH_WIDTH, y + 2); } else { i[0] = MESH_INDEX (0, y + 1); i[1] = MESH_INDEX (0, y + 1); i[2] = MESH_INDEX (0, y + 2); } i += 3; dir = !dir; } #undef MESH_INDEX state->indices = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT, state->static_indices, state->n_static_indices); } static float gaussian (float x, float y) { /* Bell width */ float c = GAUSSIAN_RADIUS; /* Peak amplitude */ float a = 1.0; /* float a = 1.0 / (c * sqrtf (2.0 * G_PI)); */ /* Center offset */ float b = 0.0; float dist; x = x - RIPPLE_CENTER_X; y = y - RIPPLE_CENTER_Y; dist = sqrtf (x*x + y*y); return a * exp ((- ((dist - b) * (dist - b))) / (2.0 * c * c)); } static void init_quad_mesh (TestState *state) { int x, y; float *vert; guint8 *color; /* Note: we maintain the minimum number of vertices possible. This minimizes * the work required when we come to morph the geometry. * * We use static indices into our mesh so that we can treat the data like a * single triangle list and drawing can be done in one operation (Note: We * are using degenerate triangles at the edges to link to the next row) */ state->quad_mesh_verts = calloc (1, sizeof (float) * 3 * (MESH_WIDTH + 1) * (MESH_HEIGHT + 1)); state->quad_mesh_colors = calloc (1, sizeof (guint8) * 4 * (MESH_WIDTH + 1) * (MESH_HEIGHT + 1)); vert = state->quad_mesh_verts; color = state->quad_mesh_colors; for (y = 0; y <= MESH_HEIGHT; y++) for (x = 0; x <= MESH_WIDTH; x++) { vert[0] = x * QUAD_WIDTH; vert[1] = y * QUAD_HEIGHT; vert += 3; color[3] = gaussian (x * QUAD_WIDTH, y * QUAD_HEIGHT) * 255.0; color += 4; } state->buffer = cogl_vertex_buffer_new ((MESH_WIDTH + 1)*(MESH_HEIGHT + 1)); cogl_vertex_buffer_add (state->buffer, "gl_Vertex", 3, /* n components */ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, /* normalized */ 0, /* stride */ state->quad_mesh_verts); cogl_vertex_buffer_add (state->buffer, "gl_Color", 4, /* n components */ COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, FALSE, /* normalized */ 0, /* stride */ state->quad_mesh_colors); cogl_vertex_buffer_submit (state->buffer); init_static_index_arrays (state); } /* This creates an actor that has a specific size but that does not result * in any drawing so we can do our own drawing using Cogl... */ static ClutterActor * create_dummy_actor (guint width, guint height) { ClutterActor *group, *rect; ClutterColor clr = { 0xff, 0xff, 0xff, 0xff}; group = clutter_group_new (); rect = clutter_rectangle_new_with_color (&clr); clutter_actor_set_size (rect, width, height); clutter_actor_hide (rect); clutter_container_add_actor (CLUTTER_CONTAINER (group), rect); return group; } static void stop_and_quit (ClutterActor *actor, TestState *state) { clutter_timeline_stop (state->timeline); clutter_main_quit (); } G_MODULE_EXPORT int test_cogl_vertex_buffer_main (int argc, char *argv[]) { TestState state; ClutterActor *stage; gfloat stage_w, stage_h; gint dummy_width, dummy_height; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Vertex Buffers"); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); g_signal_connect (stage, "destroy", G_CALLBACK (stop_and_quit), &state); clutter_actor_get_size (stage, &stage_w, &stage_h); dummy_width = MESH_WIDTH * QUAD_WIDTH; dummy_height = MESH_HEIGHT * QUAD_HEIGHT; state.dummy = create_dummy_actor (dummy_width, dummy_height); clutter_container_add_actor (CLUTTER_CONTAINER (stage), state.dummy); clutter_actor_set_position (state.dummy, (stage_w / 2.0) - (dummy_width / 2.0), (stage_h / 2.0) - (dummy_height / 2.0)); state.timeline = clutter_timeline_new (1000); clutter_timeline_set_loop (state.timeline, TRUE); state.frame_id = g_signal_connect (state.timeline, "new-frame", G_CALLBACK (frame_cb), &state); g_signal_connect (state.dummy, "paint", G_CALLBACK (on_paint), &state); init_quad_mesh (&state); clutter_actor_show_all (stage); clutter_timeline_start (state.timeline); clutter_main (); cogl_handle_unref (state.buffer); cogl_handle_unref (state.indices); return 0; } G_MODULE_EXPORT const char * test_cogl_vertex_buffer_describe (void) { return "Vertex buffers support in Cogl."; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-swipe-action.c������������������������������������������0000664�0001750�0001750�00000014200�14211404421�024015� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> enum { VERTICAL = 0, HORIZONTAL = 1, BOTH = 2 }; static void swept_cb (ClutterSwipeAction *action, ClutterActor *actor, ClutterSwipeDirection direction, gpointer data_) { guint axis = GPOINTER_TO_UINT (data_); gchar *direction_str = g_strdup (""); if (axis == HORIZONTAL && ((direction & CLUTTER_SWIPE_DIRECTION_UP) != 0 || (direction & CLUTTER_SWIPE_DIRECTION_DOWN) != 0)) { g_print ("discarding non-horizontal swipe on '%s'\n", clutter_actor_get_name (actor)); return; } if (axis == VERTICAL && ((direction & CLUTTER_SWIPE_DIRECTION_LEFT) != 0 || (direction & CLUTTER_SWIPE_DIRECTION_RIGHT) != 0)) { g_print ("discarding non-vertical swipe on '%s'\n", clutter_actor_get_name (actor)); return; } if (direction & CLUTTER_SWIPE_DIRECTION_UP) { char *old_str = direction_str; direction_str = g_strconcat (direction_str, " up", NULL); free (old_str); } if (direction & CLUTTER_SWIPE_DIRECTION_DOWN) { char *old_str = direction_str; direction_str = g_strconcat (direction_str, " down", NULL); free (old_str); } if (direction & CLUTTER_SWIPE_DIRECTION_LEFT) { char *old_str = direction_str; direction_str = g_strconcat (direction_str, " left", NULL); free (old_str); } if (direction & CLUTTER_SWIPE_DIRECTION_RIGHT) { char *old_str = direction_str; direction_str = g_strconcat (direction_str, " right", NULL); free (old_str); } g_print ("swept: '%s': %s\n", clutter_actor_get_name (actor), direction_str); free (direction_str); } static void gesture_cancel_cb (ClutterSwipeAction *action, ClutterActor *actor, gpointer user_data) { g_debug ("gesture cancelled: '%s'", clutter_actor_get_name (actor)); } static void attach_action (ClutterActor *actor, guint axis) { ClutterAction *action; action = g_object_new (CLUTTER_TYPE_SWIPE_ACTION, NULL); clutter_actor_add_action (actor, action); g_signal_connect (action, "swept", G_CALLBACK (swept_cb), GUINT_TO_POINTER (axis)); g_signal_connect (action, "gesture-cancel", G_CALLBACK (gesture_cancel_cb), NULL); } G_MODULE_EXPORT int test_swipe_action_main (int argc, char *argv[]) { ClutterActor *stage, *rect; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Swipe action"); clutter_actor_set_size (stage, 640, 480); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); rect = clutter_rectangle_new_with_color (CLUTTER_COLOR_Red); clutter_actor_set_name (rect, "Vertical swipes"); clutter_actor_set_size (rect, 150, 150); clutter_actor_set_position (rect, 10, 100); clutter_actor_set_reactive (rect, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); attach_action (rect, VERTICAL); rect = clutter_rectangle_new_with_color (CLUTTER_COLOR_Blue); clutter_actor_set_name (rect, "Horizontal swipes"); clutter_actor_set_size (rect, 150, 150); clutter_actor_set_position (rect, 170, 100); clutter_actor_set_reactive (rect, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); attach_action (rect, HORIZONTAL); rect = clutter_rectangle_new_with_color (CLUTTER_COLOR_Green); clutter_actor_set_name (rect, "All swipes"); clutter_actor_set_size (rect, 150, 150); clutter_actor_set_position (rect, 330, 100); clutter_actor_set_reactive (rect, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); attach_action (rect, BOTH); { ClutterLayoutManager *layout = clutter_box_layout_new (); ClutterActor *box, *label; float offset; clutter_box_layout_set_vertical (CLUTTER_BOX_LAYOUT (layout), TRUE); clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout), 6); box = clutter_box_new (layout); label = clutter_text_new (); clutter_text_set_markup (CLUTTER_TEXT (label), "<b>Red</b>: vertical swipes only"); clutter_box_layout_pack (CLUTTER_BOX_LAYOUT (layout), label, TRUE, TRUE, TRUE, CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_CENTER); label = clutter_text_new (); clutter_text_set_markup (CLUTTER_TEXT (label), "<b>Blue</b>: horizontal swipes only"); clutter_box_layout_pack (CLUTTER_BOX_LAYOUT (layout), label, TRUE, TRUE, TRUE, CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_CENTER); label = clutter_text_new (); clutter_text_set_markup (CLUTTER_TEXT (label), "<b>Green</b>: both"); clutter_box_layout_pack (CLUTTER_BOX_LAYOUT (layout), label, TRUE, TRUE, TRUE, CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_CENTER); offset = clutter_actor_get_height (stage) - clutter_actor_get_height (box) - 12.0; clutter_container_add_actor (CLUTTER_CONTAINER (stage), box); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_X, 12.0)); clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_Y, offset)); } clutter_actor_show_all (stage); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_swipe_action_describe (void) { return "Swipe gesture recognizer."; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-layout.c������������������������������������������������0000664�0001750�0001750�00000045606�14211404421�022746� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <gmodule.h> #include <cogl/cogl.h> #include <clutter/clutter.h> /* layout actor, by Lucas Rocha */ #define MY_TYPE_THING (my_thing_get_type ()) #define MY_THING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_THING, MyThing)) #define MY_IS_THING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_THING)) #define MY_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_THING, MyThingClass)) #define MY_IS_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_THING)) #define MY_THING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_THING, MyThingClass)) typedef struct _MyThing MyThing; typedef struct _MyThingPrivate MyThingPrivate; typedef struct _MyThingClass MyThingClass; struct _MyThing { ClutterActor parent_instance; MyThingPrivate *priv; }; struct _MyThingClass { ClutterActorClass parent_class; }; enum { PROP_0, PROP_SPACING, PROP_PADDING, PROP_USE_TRANSFORMED_BOX }; G_DEFINE_TYPE (MyThing, my_thing, CLUTTER_TYPE_ACTOR) #define MY_THING_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MY_TYPE_THING, MyThingPrivate)) struct _MyThingPrivate { gfloat spacing; gfloat padding; guint use_transformed_box : 1; }; static void my_thing_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { MyThingPrivate *priv = MY_THING (gobject)->priv; gboolean needs_relayout = TRUE; switch (prop_id) { case PROP_SPACING: priv->spacing = g_value_get_float (value); break; case PROP_PADDING: priv->padding = g_value_get_float (value); break; case PROP_USE_TRANSFORMED_BOX: priv->use_transformed_box = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); needs_relayout = FALSE; break; } /* setting spacing or padding queues a relayout because they are supposed to change the internal allocation of children */ if (needs_relayout) clutter_actor_queue_relayout (CLUTTER_ACTOR (gobject)); } static void my_thing_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { MyThingPrivate *priv = MY_THING (gobject)->priv; switch (prop_id) { case PROP_SPACING: g_value_set_float (value, priv->spacing); break; case PROP_PADDING: g_value_set_float (value, priv->padding); break; case PROP_USE_TRANSFORMED_BOX: g_value_set_boolean (value, priv->use_transformed_box); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void my_thing_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterActorIter iter; ClutterActor *child; gfloat min_left, min_right; gfloat natural_left, natural_right; min_left = 0; min_right = 0; natural_left = 0; natural_right = 0; clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_x, child_min, child_natural; child_x = clutter_actor_get_x (child); clutter_actor_get_preferred_size (child, &child_min, NULL, &child_natural, NULL); if (child == clutter_actor_get_first_child (self)) { /* First child */ min_left = child_x; natural_left = child_x; min_right = min_left + child_min; natural_right = natural_left + child_natural; } else { /* Union of extents with previous children */ if (child_x < min_left) min_left = child_x; if (child_x < natural_left) natural_left = child_x; if (child_x + child_min > min_right) min_right = child_x + child_min; if (child_x + child_natural > natural_right) natural_right = child_x + child_natural; } } if (min_left < 0) min_left = 0; if (natural_left < 0) natural_left = 0; if (min_right < 0) min_right = 0; if (natural_right < 0) natural_right = 0; g_assert (min_right >= min_left); g_assert (natural_right >= natural_left); if (min_width_p) *min_width_p = min_right - min_left; if (natural_width_p) *natural_width_p = natural_right - min_left; } static void my_thing_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterActorIter iter; ClutterActor *child; gfloat min_top, min_bottom; gfloat natural_top, natural_bottom; min_top = 0; min_bottom = 0; natural_top = 0; natural_bottom = 0; clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_y, child_min, child_natural; child_y = clutter_actor_get_y (child); clutter_actor_get_preferred_size (child, NULL, &child_min, NULL, &child_natural); if (child == clutter_actor_get_first_child (self)) { /* First child */ min_top = child_y; natural_top = child_y; min_bottom = min_top + child_min; natural_bottom = natural_top + child_natural; } else { /* Union of extents with previous children */ if (child_y < min_top) min_top = child_y; if (child_y < natural_top) natural_top = child_y; if (child_y + child_min > min_bottom) min_bottom = child_y + child_min; if (child_y + child_natural > natural_bottom) natural_bottom = child_y + child_natural; } } if (min_top < 0) min_top = 0; if (natural_top < 0) natural_top = 0; if (min_bottom < 0) min_bottom = 0; if (natural_bottom < 0) natural_bottom = 0; g_assert (min_bottom >= min_top); g_assert (natural_bottom >= natural_top); if (min_height_p) *min_height_p = min_bottom - min_top; if (natural_height_p) *natural_height_p = natural_bottom - min_top; } static void my_thing_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { MyThingPrivate *priv; gfloat current_x, current_y, max_row_height; ClutterActorIter iter; ClutterActor *child; clutter_actor_set_allocation (self, box, flags); priv = MY_THING (self)->priv; current_x = priv->padding; current_y = priv->padding; max_row_height = 0; /* The allocation logic here is to horizontally place children * side-by-side and reflow into a new row when we run out of * space */ clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) { gfloat natural_width, natural_height; ClutterActorBox child_box; clutter_actor_get_preferred_size (child, NULL, NULL, &natural_width, &natural_height); /* if it fits in the current row, keep it there; otherwise * reflow into another row */ if (current_x + natural_width > box->x2 - box->x1 - priv->padding) { current_x = priv->padding; current_y += max_row_height + priv->spacing; max_row_height = 0; } child_box.x1 = current_x; child_box.y1 = current_y; child_box.x2 = child_box.x1 + natural_width; child_box.y2 = child_box.y1 + natural_height; clutter_actor_allocate (child, &child_box, flags); /* if we take into account the transformation of the children * then we first check if it's transformed; then we get the * onscreen coordinates of the two points of the bounding box * of the actor (origin(x, y) and (origin + size)(x,y)) and * we update the coordinates and area given to the next child */ if (priv->use_transformed_box) { if (clutter_actor_is_scaled (child) || clutter_actor_is_rotated (child)) { ClutterVertex v1 = { 0, }, v2 = { 0, }; ClutterActorBox transformed_box = { 0, }; /* origin */ if (!(flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED)) { v1.x = 0; v1.y = 0; } else { v1.x = box->x1; v1.y = box->y1; } clutter_actor_apply_transform_to_point (child, &v1, &v2); transformed_box.x1 = v2.x; transformed_box.y1 = v2.y; /* size */ v1.x = natural_width; v1.y = natural_height; clutter_actor_apply_transform_to_point (child, &v1, &v2); transformed_box.x2 = v2.x; transformed_box.y2 = v2.y; natural_width = transformed_box.x2 - transformed_box.x1; natural_height = transformed_box.y2 - transformed_box.y1; } } /* Record the maximum child height on current row to know * what's the increment that should be used for the next * row */ if (natural_height > max_row_height) max_row_height = natural_height; current_x += natural_width + priv->spacing; } } #define MIN_SIZE 24 #define MAX_SIZE 64 static void my_thing_class_init (MyThingClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); gobject_class->set_property = my_thing_set_property; gobject_class->get_property = my_thing_get_property; actor_class->get_preferred_width = my_thing_get_preferred_width; actor_class->get_preferred_height = my_thing_get_preferred_height; actor_class->allocate = my_thing_allocate; g_object_class_install_property (gobject_class, PROP_SPACING, g_param_spec_float ("spacing", "Spacing", "Spacing of the thing", 0, G_MAXFLOAT, 0, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_PADDING, g_param_spec_float ("padding", "Padding", "Padding around the thing", 0, G_MAXFLOAT, 0, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_USE_TRANSFORMED_BOX, g_param_spec_boolean ("use-transformed-box", "Use Transformed Box", "Use transformed box when allocating", FALSE, G_PARAM_READWRITE)); g_type_class_add_private (klass, sizeof (MyThingPrivate)); } static void my_thing_init (MyThing *thing) { thing->priv = MY_THING_GET_PRIVATE (thing); } ClutterActor * my_thing_new (gfloat padding, gfloat spacing) { return g_object_new (MY_TYPE_THING, "padding", padding, "spacing", spacing, NULL); } /* test code */ static ClutterActor *box = NULL; static ClutterActor *icon = NULL; static ClutterTimeline *main_timeline = NULL; static void toggle_property_value (ClutterActor *actor, const gchar *property_name) { gboolean value; g_object_get (actor, property_name, &value, NULL); value = !value; g_object_set (box, property_name, value, NULL); } static void increase_property_value (ClutterActor *actor, const char *property_name) { gfloat value; g_object_get (actor, property_name, &value, NULL); value = value + 10.0; g_object_set (box, property_name, value, NULL); } static void decrease_property_value (ClutterActor *actor, const char *property_name) { gfloat value; g_object_get (actor, property_name, &value, NULL); value = MAX (0, value - 10.0); g_object_set (box, property_name, value, NULL); } static ClutterActor * create_item (void) { ClutterActor *clone = clutter_clone_new (icon); gint32 size = g_random_int_range (MIN_SIZE, MAX_SIZE); clutter_actor_set_size (clone, size, size); clutter_actor_animate_with_timeline (clone, CLUTTER_EASE_OUT_CUBIC, main_timeline, "scale-x", 2.0, "scale-y", 2.0, "fixed::scale-gravity", CLUTTER_GRAVITY_CENTER, NULL); return clone; } static gboolean keypress_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { switch (clutter_event_get_key_symbol (event)) { case CLUTTER_KEY_q: clutter_main_quit (); break; case CLUTTER_KEY_a: { if (icon != NULL) { ClutterActor *clone = create_item (); /* Add one item to container */ clutter_actor_add_child (box, clone); } break; } case CLUTTER_KEY_d: { ClutterActor *last_child; last_child = clutter_actor_get_last_child (box); if (last_child != NULL) { /* Remove last item on container */ clutter_actor_remove_child (box, last_child); } break; } case CLUTTER_KEY_w: { decrease_property_value (box, "padding"); break; } case CLUTTER_KEY_e: { increase_property_value (box, "padding"); break; } case CLUTTER_KEY_r: { decrease_property_value (box, "spacing"); break; } case CLUTTER_KEY_s: { toggle_property_value (box, "use-transformed-box"); break; } case CLUTTER_KEY_t: { increase_property_value (box, "spacing"); break; } case CLUTTER_KEY_z: { if (clutter_timeline_is_playing (main_timeline)) clutter_timeline_pause (main_timeline); else clutter_timeline_start (main_timeline); break; } default: break; } return FALSE; } static void relayout_on_frame (ClutterTimeline *timeline) { gboolean use_transformed_box; /* if we care about transformations updating the layout, we need to inform * the layout that a transformation is happening; this is either done by * attaching a notification on the transformation properties or by simply * queuing a relayout on each frame of the timeline used to drive the * behaviour. for simplicity's sake, we used the latter */ g_object_get (G_OBJECT (box), "use-transformed-box", &use_transformed_box, NULL); if (use_transformed_box) clutter_actor_queue_relayout (box); } G_MODULE_EXPORT int test_layout_main (int argc, char *argv[]) { ClutterActor *stage, *instructions; gint i, size; GError *error = NULL; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_set_size (stage, 800, 600); clutter_stage_set_title (CLUTTER_STAGE (stage), "Layout"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); main_timeline = clutter_timeline_new (2000); clutter_timeline_set_repeat_count (main_timeline, -1); clutter_timeline_set_auto_reverse (main_timeline, TRUE); g_signal_connect (main_timeline, "new-frame", G_CALLBACK (relayout_on_frame), NULL); box = my_thing_new (10, 10); clutter_actor_set_position (box, 20, 20); clutter_actor_set_size (box, 350, -1); icon = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", &error); if (error) g_error ("Unable to load 'redhand.png': %s", error->message); size = g_random_int_range (MIN_SIZE, MAX_SIZE); clutter_actor_set_size (icon, size, size); clutter_actor_add_child (box, icon); clutter_actor_animate_with_timeline (icon, CLUTTER_EASE_OUT_CUBIC, main_timeline, "scale-x", 2.0, "scale-y", 2.0, "fixed::scale-gravity", CLUTTER_GRAVITY_CENTER, NULL); for (i = 1; i < 33; i++) { ClutterActor *clone = create_item (); clutter_actor_add_child (box, clone); } clutter_actor_add_child (stage, box); instructions = clutter_text_new_with_text (NULL, "<b>Instructions:</b>\n" "a - add a new item\n" "d - remove last item\n" "z - start/pause behaviour\n" "w - decrease padding\n" "e - increase padding\n" "r - decrease spacing\n" "t - increase spacing\n" "s - use transformed box\n" "q - quit"); clutter_text_set_use_markup (CLUTTER_TEXT (instructions), TRUE); clutter_actor_set_position (instructions, 450, 10); clutter_actor_add_child (stage, instructions); g_signal_connect (stage, "key-release-event", G_CALLBACK (keypress_cb), NULL); clutter_timeline_stop (main_timeline); clutter_actor_show (stage); clutter_main (); g_object_unref (main_timeline); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_layout_describe (void) { return "Container implementing a layout policy."; } ��������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-state-script.c������������������������������������������0000664�0001750�0001750�00000002642�14211404421�024044� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> #define TEST_STATE_SCRIPT_FILE "test-script-signals.json" gboolean on_button_press (ClutterActor *actor, ClutterEvent *event, gpointer dummy G_GNUC_UNUSED) { g_print ("Button pressed!\n"); return FALSE; } G_MODULE_EXPORT int test_state_script_main (int argc, char *argv[]) { ClutterActor *stage, *button; ClutterScript *script; GError *error = NULL; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; script = clutter_script_new (); clutter_script_load_from_file (script, TEST_STATE_SCRIPT_FILE, &error); if (error != NULL) g_error ("Unable to load '%s': %s\n", TEST_STATE_SCRIPT_FILE, error->message); stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "State Script"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_actor_show (stage); button = CLUTTER_ACTOR (clutter_script_get_object (script, "button")); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button); clutter_actor_add_constraint (button, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_script_connect_signals (script, NULL); clutter_main (); g_object_unref (script); return EXIT_SUCCESS; } ����������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-shader-arbfp.c�������������������������������������0000664�0001750�0001750�00000026612�14211404421�024705� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <errno.h> #include <stdlib.h> #include <glib.h> #include <gmodule.h> typedef struct { char *name; char *source; } ShaderSource; static ShaderSource shaders[]= { /*{"brightness-contrast", FRAGMENT_SHADER_VARS "uniform float brightness, contrast;" FRAGMENT_SHADER_BEGIN " color.rgb = (color.rgb - vec3(0.5, 0.5, 0.5)) * contrast + " "vec3 (brightness + 0.5, brightness + 0.5, brightness + 0.5);" FRAGMENT_SHADER_END },*/ {"brightness-contrast", "!!ARBfp1.0\n" "PARAM bc = program.local[0];" "TEMP color;" "TEMP color2;" "TEX color.rgba, fragment.texcoord[0], texture[0], 2D;" "SUB color.rgb, color, 0.5;" "MUL color2, color, bc.w;" "ADD color.rgb, color2, bc.z;" "MOV result.color, color;" "END" }, /*{"box-blur", FRAGMENT_SHADER_VARS "vec4 get_rgba_rel(sampler2D tex, float dx, float dy)" "{" " return texture2D (tex, " TEX_COORD ".st " " + vec2(dx, dy) * 2.0);" "}" FRAGMENT_SHADER_BEGIN " float count = 1.0;" " color += get_rgba_rel (tex, -x_step, -y_step); count++;" " color += get_rgba_rel (tex, -x_step, 0.0); count++;" " color += get_rgba_rel (tex, -x_step, y_step); count++;" " color += get_rgba_rel (tex, 0.0, -y_step); count++;" " color += get_rgba_rel (tex, 0.0, 0.0); count++;" " color += get_rgba_rel (tex, 0.0, y_step); count++;" " color += get_rgba_rel (tex, x_step, -y_step); count++;" " color += get_rgba_rel (tex, x_step, 0.0); count++;" " color += get_rgba_rel (tex, x_step, y_step); count++;" " color = color / count;" FRAGMENT_SHADER_END },*/ {"box-blur", "!!ARBfp1.0\n" "PARAM params = program.local[0];" "TEMP accum;" "TEMP color;" "TEMP coord;" "TEMP step;" "MUL step, params, 2.0;" "SUB coord, fragment.texcoord[0], step;" "TEX color.rgba, coord, texture[0], 2D;" "MOV accum, color;" "MOV coord, fragment.texcoord[0];" "SUB coord.x, coord.x, step.x;" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MOV coord, fragment.texcoord[0];" "SUB coord.x, coord.x, step.x;" "ADD coord.y, coord.y, step.y;" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MOV coord, fragment.texcoord[0];" "SUB coord.y, coord.y, step.y;" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MOV coord, fragment.texcoord[0];" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MOV coord, fragment.texcoord[0];" "ADD coord.y, coord.y, step.y;" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MOV coord, fragment.texcoord[0];" "ADD coord.x, coord.x, step.x;" "SUB coord.y, coord.y, step.y;" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MOV coord, fragment.texcoord[0];" "ADD coord.x, coord.x, step.x;" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MOV coord, fragment.texcoord[0];" "ADD coord.x, coord.x, step.x;" "ADD coord.y, coord.y, step.y;" "TEX color.rgba, coord, texture[0], 2D;" "ADD accum, accum, color;" "MUL color, accum, 0.11111111;" "MOV result.color, color;" "END" }, /*{"invert", FRAGMENT_SHADER_VARS FRAGMENT_SHADER_BEGIN " color.rgb = vec3(1.0, 1.0, 1.0) - color.rgb;\n" FRAGMENT_SHADER_END },*/ {"invert", "!!ARBfp1.0\n" "TEMP color;" "TEX color.rgba, fragment.texcoord[0], texture[0], 2D;" "ADD color.rgb, 1.0, -color;" "MOV result.color, color;" "END" }, /*{"gray", FRAGMENT_SHADER_VARS FRAGMENT_SHADER_BEGIN " float avg = (color.r + color.g + color.b) / 3.0;" " color.r = avg;" " color.g = avg;" " color.b = avg;" FRAGMENT_SHADER_END },*/ {"gray", "!!ARBfp1.0\n" "TEMP color;" "TEMP grey;" "TEX color.rgba, fragment.texcoord[0], texture[0], 2D;" "ADD grey, color.r, color.g;" "ADD grey, grey, color.b;" "MUL grey, grey, 0.33333333;" "MOV color.rgb, grey;" "MOV result.color, color;" "END" }, /* {"combined-mirror", FRAGMENT_SHADER_VARS FRAGMENT_SHADER_BEGIN " vec4 colorB = texture2D (tex, vec2(" TEX_COORD ".ts));" " float avg = (color.r + color.g + color.b) / 3.0;" " color.r = avg;" " color.g = avg;" " color.b = avg;" " color = (color + colorB)/2.0;" FRAGMENT_SHADER_END },*/ {"combined-mirror", "!!ARBfp1.0\n" "TEMP color1;" "TEMP color2;" "TEMP coord;" "MOV coord.x, fragment.texcoord[0].y;" "MOV coord.y, fragment.texcoord[0].x;" "TEX color1.rgba, fragment.texcoord[0], texture[0], 2D;" "TEX color2.rgba, coord, texture[0], 2D;" "MUL color1, color1, 0.5;" "MUL color2, color2, 0.5;" "ADD result.color, color1, color2;" "END" }, /* {"edge-detect", FRAGMENT_SHADER_VARS "float get_avg_rel(sampler2D texB, float dx, float dy)" "{" " vec4 colorB = texture2D (texB, " TEX_COORD ".st + vec2(dx, dy));" " return (colorB.r + colorB.g + colorB.b) / 3.0;" "}" FRAGMENT_SHADER_BEGIN " mat3 sobel_h = mat3( 1.0, 2.0, 1.0," " 0.0, 0.0, 0.0," " -1.0, -2.0, -1.0);" " mat3 sobel_v = mat3( 1.0, 0.0, -1.0," " 2.0, 0.0, -2.0," " 1.0, 0.0, -1.0);" " mat3 map = mat3( get_avg_rel(tex, -x_step, -y_step)," " get_avg_rel(tex, -x_step, 0.0)," " get_avg_rel(tex, -x_step, y_step)," " get_avg_rel(tex, 0.0, -y_step)," " get_avg_rel(tex, 0.0, 0.0)," " get_avg_rel(tex, 0.0, y_step)," " get_avg_rel(tex, x_step, -y_step)," " get_avg_rel(tex, x_step, 0.0)," " get_avg_rel(tex, x_step, y_step) );" " mat3 gh = sobel_h * map;" " mat3 gv = map * sobel_v;" " float avgh = (gh[0][0] + gh[0][1] + gh[0][2] +" " gh[1][0] + gh[1][1] + gh[1][2] +" " gh[2][0] + gh[2][1] + gh[2][2]) / 18.0 + 0.5;" " float avgv = (gv[0][0] + gv[0][1] + gv[0][2] +" " gv[1][0] + gv[1][1] + gv[1][2] +" " gv[2][0] + gv[2][1] + gv[2][2]) / 18.0 + 0.5;" " float avg = (avgh + avgv) / 2.0;" " color.r = avg * color.r;" " color.g = avg * color.g;" " color.b = avg * color.b;" FRAGMENT_SHADER_END },*/ /* Don't really fancy doing this one in assembly :) */ }; static CoglHandle redhand; static CoglMaterial *material; static unsigned int timeout_id = 0; static int shader_no = 0; static void paint_cb (ClutterActor *actor) { int stage_width = clutter_actor_get_width (actor); int stage_height = clutter_actor_get_height (actor); int image_width = cogl_texture_get_width (redhand); int image_height = cogl_texture_get_height (redhand); cogl_set_source (material); cogl_rectangle (stage_width/2.0f - image_width/2.0f, stage_height/2.0f - image_height/2.0f, stage_width/2.0f + image_width/2.0f, stage_height/2.0f + image_height/2.0f); } static void set_shader_num (int new_no) { CoglHandle shader; CoglHandle program; int image_width = cogl_texture_get_width (redhand); int image_height = cogl_texture_get_height (redhand); float param0[4]; int uniform_no; g_print ("setting shaders[%i] named '%s'\n", new_no, shaders[new_no].name); shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); cogl_shader_source (shader, shaders[new_no].source); cogl_shader_compile (shader); program = cogl_create_program (); cogl_program_attach_shader (program, shader); cogl_handle_unref (shader); cogl_program_link (program); param0[0] = 1.0f/image_width; /* texel x step delta */ param0[1] = 1.0f/image_height; /* texel y step delta */ param0[2] = 0.4; /* brightness */ param0[3] = -1.9; /* contrast */ uniform_no = cogl_program_get_uniform_location (program, "program.local[0]"); cogl_program_set_uniform_float (program, uniform_no, 4, 1, param0); cogl_material_set_user_program (material, program); cogl_handle_unref (program); shader_no = new_no; } static gboolean button_release_cb (ClutterActor *actor, ClutterEvent *event, void *data) { int new_no; /* Stop the automatic cycling if the user want to manually control * which shader to display */ if (timeout_id) { g_source_remove (timeout_id); timeout_id = 0; } if (event->button.button == 1) { new_no = shader_no - 1; if (new_no < 0) new_no = G_N_ELEMENTS (shaders) - 1; } else { new_no = shader_no + 1; if (new_no >= G_N_ELEMENTS (shaders)) new_no = 0; } set_shader_num (new_no); return CLUTTER_EVENT_STOP; } static gboolean key_release_cb (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { guint keysym = clutter_event_get_key_symbol (event); ClutterModifierType mods = clutter_event_get_state (event); if (keysym == CLUTTER_KEY_q || ((mods & CLUTTER_SHIFT_MASK) && keysym == CLUTTER_KEY_q)) clutter_main_quit (); return CLUTTER_EVENT_STOP; } static gboolean timeout_cb (gpointer user_data) { shader_no++; if (shader_no > (G_N_ELEMENTS (shaders) - 1)) shader_no = 0; set_shader_num (shader_no); return G_SOURCE_CONTINUE; } static gboolean idle_cb (gpointer data) { clutter_actor_queue_redraw (data); return G_SOURCE_CONTINUE; } static gboolean destroy_window_cb (ClutterStage *stage, ClutterEvent *event, void *user_data) { clutter_main_quit (); return TRUE; } G_MODULE_EXPORT int test_cogl_shader_arbfp_main (int argc, char *argv[]) { ClutterActor *stage; char *file; GError *error; ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Assembly Shader Test"); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); error = NULL; redhand = cogl_texture_new_from_file (file, 0, COGL_PIXEL_FORMAT_ANY, &error); if (redhand == COGL_INVALID_HANDLE) g_error ("image load failed: %s", error->message); material = cogl_material_new (); cogl_material_set_layer (material, 0, redhand); set_shader_num (0); g_signal_connect_after (stage, "paint", G_CALLBACK (paint_cb), NULL); clutter_actor_set_reactive (stage, TRUE); g_signal_connect (stage, "button-release-event", G_CALLBACK (button_release_cb), NULL); g_signal_connect (stage, "key-release-event", G_CALLBACK (key_release_cb), NULL); g_signal_connect (stage, "delete-event", G_CALLBACK (destroy_window_cb), NULL); timeout_id = clutter_threads_add_timeout (1000, timeout_cb, NULL); clutter_threads_add_idle (idle_cb, stage); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-texture-slicing.c���������������������������������������0000664�0001750�0001750�00000005673�14211404421�024557� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> guchar* make_rgba_data (int width, int height, int bpp, int has_alpha, int *rowstride_p) { #define CHECK_SIZE 20 gint x,y, rowstride, i = 0; guchar *pixels; g_assert(bpp == 4); g_assert(has_alpha == TRUE); rowstride = width * bpp; *rowstride_p = rowstride; pixels = g_try_malloc (height * rowstride); if (!pixels) return NULL; for (y = 0; y < height; y++) { i = 0; for (x = 0; x < width; x++) { guchar *p; p = pixels + y * rowstride + x * bpp; p[0] = p[1] = p[2] = 0; p[3] = 0xff; if (x && y && y % CHECK_SIZE && x % CHECK_SIZE) { if (x % CHECK_SIZE == 1) { if (++i > 3) i = 0; } p[i] = 0xff; } } } return pixels; } static void exit_on_destroy (ClutterActor *actor) { exit(EXIT_SUCCESS); } #define SPIN() while (g_main_context_pending (NULL)) \ g_main_context_iteration (NULL, FALSE); G_MODULE_EXPORT int test_textures_main (int argc, char *argv[]) { ClutterActor *texture; ClutterActor *stage; gint i, j; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_show_all (CLUTTER_ACTOR (stage)); g_signal_connect (stage, "destroy", G_CALLBACK (exit_on_destroy), NULL); SPIN(); for (i=100; i<=5000; i += 100) for (j=0; j<4; j++) { const int width = i+j; const int height = i+j; const gboolean has_alpha = TRUE; const int bpp = has_alpha ? 4 : 3; int rowstride; guchar *pixels; pixels = make_rgba_data (width, height, bpp, has_alpha, &rowstride); if (!pixels) g_error("No memory for %ix%i RGBA data failed", width, height); printf("o %ix%i texture... ", width, height); texture = clutter_texture_new (); if (!clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture), pixels, has_alpha, width, height, rowstride, bpp, 0, NULL)) g_error("texture creation failed"); free(pixels); printf("uploaded to texture...\n"); clutter_container_add (CLUTTER_CONTAINER (stage), texture, NULL); clutter_actor_set_size (texture, 400, 400); clutter_actor_show (texture); /* Hide & show to unreaise then realise the texture */ clutter_actor_hide (texture); clutter_actor_show (texture); SPIN(); clutter_container_remove (CLUTTER_CONTAINER (stage), texture, NULL); } return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_texture_slicing_describe (void) { return "Check texture slicing support in CoglTexture"; } ���������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-offscreen.c����������������������������������������0000664�0001750�0001750�00000022534�14211404421�024320� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <gmodule.h> #include <stdlib.h> #include <clutter/clutter.h> #include <cogl/cogl.h> /* Coglbox declaration *--------------------------------------------------*/ G_BEGIN_DECLS #define TEST_TYPE_COGLBOX test_coglbox_get_type() #define TEST_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) #define TEST_IS_COGLBOX(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ TEST_TYPE_COGLBOX)) #define TEST_IS_COGLBOX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ TEST_TYPE_COGLBOX)) #define TEST_COGLBOX_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ TEST_TYPE_COGLBOX, TestCoglboxClass)) typedef struct _TestCoglbox TestCoglbox; typedef struct _TestCoglboxClass TestCoglboxClass; typedef struct _TestCoglboxPrivate TestCoglboxPrivate; struct _TestCoglbox { ClutterActor parent; /*< private >*/ TestCoglboxPrivate *priv; }; struct _TestCoglboxClass { ClutterActorClass parent_class; /* padding for future expansion */ void (*_test_coglbox1) (void); void (*_test_coglbox2) (void); void (*_test_coglbox3) (void); void (*_test_coglbox4) (void); }; static GType test_coglbox_get_type (void) G_GNUC_CONST; G_END_DECLS /* Coglbox private declaration *--------------------------------------------------*/ G_DEFINE_TYPE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR); #define TEST_COGLBOX_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TEST_TYPE_COGLBOX, TestCoglboxPrivate)) struct _TestCoglboxPrivate { CoglHandle texhand_id; CoglHandle texture_id; CoglHandle offscreen_id; }; /* Coglbox implementation *--------------------------------------------------*/ static void test_coglbox_paint (ClutterActor *self) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self); gfloat texcoords[4] = { 0, 0, 1, 1 }; CoglHandle material; cogl_set_source_color4ub (0x66, 0x66, 0xdd, 0xff); cogl_rectangle (0, 0, 400, 400); cogl_set_source_texture (priv->texhand_id); cogl_rectangle_with_texture_coords (0, 0, 400, 400, 0, 0, 6, 6); cogl_push_framebuffer (priv->offscreen_id); cogl_set_source_color4ub (0xff, 0, 0, 0xff); cogl_rectangle (20, 20, 20 + 100, 20 + 100); cogl_set_source_color4ub (0, 0xff, 0, 0xff); cogl_rectangle (80, 80, 80 + 100, 80 + 100); cogl_pop_framebuffer (); material = cogl_material_new (); cogl_material_set_color4ub (material, 0x88, 0x88, 0x88, 0x88); cogl_material_set_layer (material, 0, priv->texture_id); cogl_set_source (material); cogl_rectangle_with_texture_coords (100, 100, 300, 300, texcoords[0], texcoords[1], texcoords[2], texcoords[3]); } static void test_coglbox_finalize (GObject *object) { G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object); } static void test_coglbox_dispose (GObject *object) { TestCoglboxPrivate *priv; priv = TEST_COGLBOX_GET_PRIVATE (object); cogl_handle_unref (priv->texture_id); cogl_handle_unref (priv->offscreen_id); G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object); } /* A newly created Cogl framebuffer will be initialized with a * viewport covering the size of the viewport i.e. equavalent to: * * calling cogl_framebuffer_set_viewport ( * fb, * 0, 0, * cogl_framebuffer_get_viewport_width (fb), * cogl_framebuffer_get_viewport_width (fb)); * * The projection matrix will be an identity matrix. * * The modelview matrix will be an identity matrix, and this will * create a coordinate system - like OpenGL - with the viewport * being mapped to a unit cube with the origin (0, 0, 0) in the * center, x, y and z ranging from -1 to 1 with (-1, -1) being top * left and (1, 1) bottom right. * * This sets up a Clutter like coordinate system for a Cogl * framebuffer */ void setup_viewport (unsigned int width, unsigned int height, float fovy, float aspect, float z_near, float z_far) { float z_camera; CoglMatrix projection_matrix; CoglMatrix mv_matrix; cogl_set_viewport (0, 0, width, height); /* For Ortho projection. * _cogl_matrix_stack_ortho (projection_stack, 0, width, 0, height, -1, 1); */ cogl_perspective (fovy, aspect, z_near, z_far); /* * In theory, we can compute the camera distance from screen as: * * 0.5 * tan (FOV) * * However, it's better to compute the z_camera from our projection * matrix so that we get a 1:1 mapping at the screen distance. Consider * the upper-left corner of the screen. It has object coordinates * (0,0,0), so by the transform below, ends up with eye coordinate * * x_eye = x_object / width - 0.5 = - 0.5 * y_eye = (height - y_object) / width - 0.5 = 0.5 * z_eye = z_object / width - z_camera = - z_camera * * From cogl_perspective(), we know that the projection matrix has * the form: * * (x, 0, 0, 0) * (0, y, 0, 0) * (0, 0, c, d) * (0, 0, -1, 0) * * Applied to the above, we get clip coordinates of * * x_clip = x * (- 0.5) * y_clip = y * 0.5 * w_clip = - 1 * (- z_camera) = z_camera * * Dividing through by w to get normalized device coordinates, we * have, x_nd = x * 0.5 / z_camera, y_nd = - y * 0.5 / z_camera. * The upper left corner of the screen has normalized device coordinates, * (-1, 1), so to have the correct 1:1 mapping, we have to have: * * z_camera = 0.5 * x = 0.5 * y * * If x != y, then we have a non-uniform aspect ration, and a 1:1 mapping * doesn't make sense. */ cogl_get_projection_matrix (&projection_matrix); z_camera = 0.5 * projection_matrix.xx; cogl_matrix_init_identity (&mv_matrix); cogl_matrix_translate (&mv_matrix, -0.5f, -0.5f, -z_camera); cogl_matrix_scale (&mv_matrix, 1.0f / width, -1.0f / height, 1.0f / width); cogl_matrix_translate (&mv_matrix, 0.0f, -1.0 * height, 0.0f); cogl_set_modelview_matrix (&mv_matrix); } static void test_coglbox_map (ClutterActor *actor) { TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (actor); ClutterActor *stage; ClutterPerspective perspective; float stage_width; float stage_height; CLUTTER_ACTOR_CLASS (test_coglbox_parent_class)->map (actor); printf ("Creating offscreen\n"); priv->offscreen_id = cogl_offscreen_new_to_texture (priv->texture_id); stage = clutter_actor_get_stage (actor); clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective); clutter_actor_get_size (stage, &stage_width, &stage_height); cogl_push_framebuffer (priv->offscreen_id); setup_viewport (stage_width, stage_height, perspective.fovy, perspective.aspect, perspective.z_near, perspective.z_far); cogl_pop_framebuffer (); if (priv->offscreen_id == COGL_INVALID_HANDLE) printf ("Failed creating offscreen to texture!\n"); } static void test_coglbox_init (TestCoglbox *self) { TestCoglboxPrivate *priv; gchar *file; self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); printf ("Loading redhand.png\n"); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); priv->texhand_id = cogl_texture_new_from_file (file, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ANY, NULL); free (file); printf ("Creating texture with size\n"); priv->texture_id = cogl_texture_new_with_size (200, 200, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGB_888); if (priv->texture_id == COGL_INVALID_HANDLE) printf ("Failed creating texture with size!\n"); } static void test_coglbox_class_init (TestCoglboxClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); gobject_class->finalize = test_coglbox_finalize; gobject_class->dispose = test_coglbox_dispose; actor_class->map = test_coglbox_map; actor_class->paint = test_coglbox_paint; g_type_class_add_private (gobject_class, sizeof (TestCoglboxPrivate)); } static ClutterActor* test_coglbox_new (void) { return g_object_new (TEST_TYPE_COGLBOX, NULL); } G_MODULE_EXPORT int test_cogl_offscreen_main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *coglbox; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; /* Stage */ stage = clutter_stage_new (); clutter_actor_set_size (stage, 400, 400); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Offscreen Buffers"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* Cogl Box */ coglbox = test_coglbox_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox); clutter_actor_show_all (stage); clutter_main (); return 0; } G_MODULE_EXPORT const char * test_cogl_offscreen_describe (void) { return "Offscreen buffer support in Cogl."; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-script.json���������������������������������������������0000664�0001750�0001750�00000004163�14211404421�023455� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "My Scene" : { "id" : "main-stage", "type" : "ClutterStage", "title" : { "translatable" : true, "string" : "ClutterScript test" }, "color" : "white", "signals" : [ { "name" : "key-press-event", "handler" : "clutter_main_quit" }, { "name" : "destroy", "handler" : "clutter_main_quit" } ], "children" : [ { "id" : "red-button", "type" : "ClutterRectangle", "color" : "#ff0000ff", "x" : 50, "y" : 50, "width" : 100, "height" : 100, "reactive" : true, "rotation" : [ { "z-axis" : [ 45.0, [ 75, 75 ] ] } ], "behaviours" : [ "fade-behaviour", "path-behaviour" ] }, { "id" : "green-button", "type" : "ClutterRectangle", "color" : "#00ff00ff", "border-width" : 5, "border-color" : "#00cc00ff", "position" : [ 200.0, 50.0 ], "size" : { "width" : 100.0, "height" : 100.0 }, "depth" : -200.0, "reactive" : true, "signals" : [ { "name" : "button-press-event", "handler" : "clutter_main_quit" } ] }, { "id" : "red-hand", "type" : "ClutterTexture", "filename" : "redhand.png", "position" : { "x" : 100.0, "y" : 100.0 }, "width" : "20 mm", "keep-aspect-ratio" : true, "anchor-x" : "5 em", "anchor-y" : "5 pt", "opacity" : 100, "behaviours" : [ "rotate-behaviour", "fade-behaviour" ] }, { "id" : "red-hand-clone", "type" : "ClutterClone", "source" : "red-hand", "position" : [ 250.0, 150.0 ], "opacity" : 100 }, { "id" : "label", "type" : "ClutterText", "x" : 50, "y" : 200, "text" : { "translatable" : true, "string" : "Clutter Script" }, "font-name" : "Sans 24px", "color" : "black", "line-alignment" : "center", "line-wrap" : false, "ellipsize" : "none", "rotation" : [ { "y-axis" : [ 60.0, [ 275, 100 ] ] }, { "z-axis" : [ 45.0, [ 75, 75 ] ] } ] } ] } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-events.c������������������������������������������������0000664�0001750�0001750�00000037365�14211404421�022740� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <gmodule.h> #include <clutter/clutter.h> #include <string.h> gboolean IsFullScreen = FALSE, IsMotion = TRUE; static const gchar * get_event_type_name (const ClutterEvent *event) { switch (event->type) { case CLUTTER_BUTTON_PRESS: return "BUTTON PRESS"; case CLUTTER_BUTTON_RELEASE: return "BUTTON_RELEASE"; case CLUTTER_KEY_PRESS: return "KEY PRESS"; case CLUTTER_KEY_RELEASE: return "KEY RELEASE"; case CLUTTER_ENTER: return "ENTER"; case CLUTTER_LEAVE: return "LEAVE"; case CLUTTER_MOTION: return "MOTION"; case CLUTTER_DELETE: return "DELETE"; case CLUTTER_TOUCH_BEGIN: return "TOUCH BEGIN"; case CLUTTER_TOUCH_UPDATE: return "TOUCH UPDATE"; case CLUTTER_TOUCH_END: return "TOUCH END"; case CLUTTER_TOUCH_CANCEL: return "TOUCH CANCEL"; default: return "EVENT"; } } static gchar * get_event_state_string (const ClutterEvent *event) { gchar *mods[18]; int i = 0; ClutterModifierType state = clutter_event_get_state (event); if (state & CLUTTER_SHIFT_MASK) mods[i++] = "shift"; if (state & CLUTTER_LOCK_MASK) mods[i++] = "lock"; if (state & CLUTTER_CONTROL_MASK) mods[i++] = "ctrl"; if (state & CLUTTER_MOD1_MASK) mods[i++] = "mod1"; if (state & CLUTTER_MOD2_MASK) mods[i++] = "mod2"; if (state & CLUTTER_MOD3_MASK) mods[i++] = "mod3"; if (state & CLUTTER_MOD4_MASK) mods[i++] = "mod4"; if (state & CLUTTER_MOD5_MASK) mods[i++] = "mod5"; if (state & CLUTTER_BUTTON1_MASK) mods[i++] = "btn1"; if (state & CLUTTER_BUTTON2_MASK) mods[i++] = "btn2"; if (state & CLUTTER_BUTTON3_MASK) mods[i++] = "btn3"; if (state & CLUTTER_BUTTON4_MASK) mods[i++] = "btn4"; if (state & CLUTTER_BUTTON5_MASK) mods[i++] = "btn5"; if (state & CLUTTER_SUPER_MASK) mods[i++] = "super"; if (state & CLUTTER_HYPER_MASK) mods[i++] = "hyper"; if (state & CLUTTER_META_MASK) mods[i++] = "meta"; if (state & CLUTTER_RELEASE_MASK) mods[i++] = "release"; if (i == 0) mods[i++] = "-"; mods[i] = NULL; return g_strjoinv (",", mods); } static void stage_state_cb (ClutterStage *stage, gpointer data) { gchar *detail = (gchar*)data; printf("[stage signal] %s\n", detail); } static gboolean blue_button_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterActor *stage; stage = clutter_actor_get_stage (actor); if (IsFullScreen) IsFullScreen = FALSE; else IsFullScreen = TRUE; clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), IsFullScreen); g_print ("*** Fullscreen %s ***\n", IsFullScreen ? "enabled" : "disabled"); return FALSE; } static gboolean red_button_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterActor *stage; if (IsMotion) IsMotion = FALSE; else IsMotion = TRUE; stage = clutter_actor_get_stage (actor); clutter_stage_set_motion_events_enabled (CLUTTER_STAGE (stage), IsMotion); g_print ("*** Per actor motion events %s ***\n", IsMotion ? "enabled" : "disabled"); return FALSE; } static gboolean capture_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { g_print ("* captured event '%s' for type '%s' *\n", get_event_type_name (event), G_OBJECT_TYPE_NAME (actor)); return FALSE; } static void key_focus_in_cb (ClutterActor *actor, gpointer data) { ClutterActor *focus_box = CLUTTER_ACTOR (data); if (CLUTTER_IS_STAGE (actor)) clutter_actor_hide (focus_box); else { clutter_actor_set_position (focus_box, clutter_actor_get_x (actor) - 5, clutter_actor_get_y (actor) - 5); clutter_actor_set_size (focus_box, clutter_actor_get_width (actor) + 10, clutter_actor_get_height (actor) + 10); clutter_actor_show (focus_box); } } static void fill_keybuf (char *keybuf, ClutterKeyEvent *event) { char utf8[6]; int len; /* printable character, if any (ß, ∑) */ len = g_unichar_to_utf8 (event->unicode_value, utf8); utf8[len] = '\0'; sprintf (keybuf, "'%s' ", utf8); /* key combination (<Mod1>s, <Shift><Mod1>S, <Ctrl><Mod1>Delete) */ len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->keyval), utf8); utf8[len] = '\0'; if (event->modifier_state & CLUTTER_SHIFT_MASK) strcat (keybuf, "<Shift>"); if (event->modifier_state & CLUTTER_LOCK_MASK) strcat (keybuf, "<Lock>"); if (event->modifier_state & CLUTTER_CONTROL_MASK) strcat (keybuf, "<Control>"); if (event->modifier_state & CLUTTER_MOD1_MASK) strcat (keybuf, "<Mod1>"); if (event->modifier_state & CLUTTER_MOD2_MASK) strcat (keybuf, "<Mod2>"); if (event->modifier_state & CLUTTER_MOD3_MASK) strcat (keybuf, "<Mod3>"); if (event->modifier_state & CLUTTER_MOD4_MASK) strcat (keybuf, "<Mod4>"); if (event->modifier_state & CLUTTER_MOD5_MASK) strcat (keybuf, "<Mod5>"); strcat (keybuf, utf8); } static gboolean input_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterActor *stage = clutter_actor_get_stage (actor); ClutterActor *source_actor = clutter_event_get_source (event); ClutterPoint position; gchar *state; gchar keybuf[128]; gint device_id; gint source_device_id = 0; device_id = clutter_event_get_device_id (event); if (clutter_event_get_source_device (event) != NULL) source_device_id = clutter_input_device_get_device_id (clutter_event_get_source_device (event)); state = get_event_state_string (event); switch (event->type) { case CLUTTER_KEY_PRESS: fill_keybuf (keybuf, &event->key); printf ("[%s] KEY PRESS %s", clutter_actor_get_name (source_actor), keybuf); break; case CLUTTER_KEY_RELEASE: fill_keybuf (keybuf, &event->key); printf ("[%s] KEY RELEASE %s", clutter_actor_get_name (source_actor), keybuf); break; case CLUTTER_MOTION: clutter_event_get_position (event, &position); g_print ("[%s] MOTION (coords:%.02f,%.02f device:%d/%d state:%s)", clutter_actor_get_name (source_actor), position.x, position.y, device_id, source_device_id, state); break; case CLUTTER_ENTER: g_print ("[%s] ENTER (from:%s device:%d/%d state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_related (event) != NULL ? clutter_actor_get_name (clutter_event_get_related (event)) : "<out of stage>", device_id, source_device_id, state); break; case CLUTTER_LEAVE: g_print ("[%s] LEAVE (to:%s device:%d/%d state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_related (event) != NULL ? clutter_actor_get_name (clutter_event_get_related (event)) : "<out of stage>", device_id, source_device_id, state); break; case CLUTTER_BUTTON_PRESS: clutter_event_get_position (event, &position); g_print ("[%s] BUTTON PRESS (button:%i, click count:%i coords:%.02f,%.02f device:%d/%d, state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_button (event), clutter_event_get_click_count (event), position.x, position.y, device_id, source_device_id, state); break; case CLUTTER_BUTTON_RELEASE: clutter_event_get_position (event, &position); g_print ("[%s] BUTTON RELEASE (button:%i, click count:%i coords:%.02f,%.02f device:%d/%d state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_button (event), clutter_event_get_click_count (event), position.x, position.y, device_id, source_device_id, state); if (source_actor == stage) clutter_stage_set_key_focus (CLUTTER_STAGE (stage), NULL); else if (source_actor == actor && clutter_actor_get_parent (actor) == stage) clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor); break; case CLUTTER_TOUCH_BEGIN: clutter_event_get_position (event, &position); g_print ("[%s] TOUCH BEGIN (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_event_sequence (event), position.x, position.y, device_id, source_device_id, state); break; case CLUTTER_TOUCH_UPDATE: clutter_event_get_position (event, &position); g_print ("[%s] TOUCH UPDATE (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_event_sequence (event), position.x, position.y, device_id, source_device_id, state); break; case CLUTTER_TOUCH_END: clutter_event_get_position (event, &position); g_print ("[%s] TOUCH END (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_event_sequence (event), position.x, position.y, device_id, source_device_id, state); break; case CLUTTER_TOUCH_CANCEL: clutter_event_get_position (event, &position); g_print ("[%s] TOUCH CANCEL (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)", clutter_actor_get_name (source_actor), clutter_event_get_event_sequence (event), position.x, position.y, device_id, source_device_id, state); break; case CLUTTER_SCROLL: { ClutterScrollDirection dir = clutter_event_get_scroll_direction (event); if (dir == CLUTTER_SCROLL_SMOOTH) { gdouble dx, dy; clutter_event_get_scroll_delta (event, &dx, &dy); g_print ("[%s] BUTTON SCROLL (direction:smooth %.02f,%.02f state:%s)", clutter_actor_get_name (source_actor), dx, dy, state); } else g_print ("[%s] BUTTON SCROLL (direction:%s state:%s)", clutter_actor_get_name (source_actor), dir == CLUTTER_SCROLL_UP ? "up" : dir == CLUTTER_SCROLL_DOWN ? "down" : dir == CLUTTER_SCROLL_LEFT ? "left" : dir == CLUTTER_SCROLL_RIGHT ? "right" : "?", state); } break; case CLUTTER_STAGE_STATE: g_print ("[%s] STAGE STATE", clutter_actor_get_name (source_actor)); break; case CLUTTER_DESTROY_NOTIFY: g_print ("[%s] DESTROY NOTIFY", clutter_actor_get_name (source_actor)); break; case CLUTTER_CLIENT_MESSAGE: g_print ("[%s] CLIENT MESSAGE", clutter_actor_get_name (source_actor)); break; case CLUTTER_DELETE: g_print ("[%s] DELETE", clutter_actor_get_name (source_actor)); break; case CLUTTER_NOTHING: return FALSE; } free (state); if (source_actor == actor) g_print (" *source*"); g_print ("\n"); return FALSE; } G_MODULE_EXPORT int test_events_main (int argc, char *argv[]) { ClutterActor *stage, *actor, *focus_box, *group; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Events"); clutter_actor_set_name (stage, "Stage"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "event", G_CALLBACK (input_cb), "stage"); g_signal_connect (stage, "fullscreen", G_CALLBACK (stage_state_cb), "fullscreen"); g_signal_connect (stage, "unfullscreen", G_CALLBACK (stage_state_cb), "unfullscreen"); g_signal_connect (stage, "activate", G_CALLBACK (stage_state_cb), "activate"); g_signal_connect (stage, "deactivate", G_CALLBACK (stage_state_cb), "deactivate"); focus_box = clutter_rectangle_new_with_color (CLUTTER_COLOR_Black); clutter_actor_set_name (focus_box, "Focus Box"); clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL); actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Red); clutter_actor_set_name (actor, "Red Box"); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 100, 100); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (input_cb), "red box"); g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb), focus_box); /* Toggle motion - enter/leave capture */ g_signal_connect (actor, "button-press-event", G_CALLBACK (red_button_cb), NULL); clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor); actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Green); clutter_actor_set_name (actor, "Green Box"); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 250, 100); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (input_cb), "green box"); g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb), focus_box); g_signal_connect (actor, "captured-event", G_CALLBACK (capture_cb), NULL); actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Blue); clutter_actor_set_name (actor, "Blue Box"); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 400, 100); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box"); g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb), focus_box); /* Fullscreen */ g_signal_connect (actor, "button-press-event", G_CALLBACK (blue_button_cb), NULL); /* non reactive */ actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Black); clutter_actor_set_name (actor, "Black Box"); clutter_actor_set_size (actor, 400, 50); clutter_actor_set_position (actor, 100, 250); clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box"); g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb), focus_box); g_signal_connect (stage, "key-focus-in", G_CALLBACK (key_focus_in_cb), focus_box); /* non reactive group, with reactive child */ actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Yellow); clutter_actor_set_name (actor, "Yellow Box"); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_reactive (actor, TRUE); g_signal_connect (actor, "event", G_CALLBACK (input_cb), "yellow box"); /* note group not reactive */ group = clutter_group_new (); clutter_container_add (CLUTTER_CONTAINER (group), actor, NULL); clutter_container_add (CLUTTER_CONTAINER (stage), group, NULL); clutter_actor_set_position (group, 100, 350); clutter_actor_show_all (group); /* border actor */ actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Magenta); clutter_actor_set_name (actor, "Border Box"); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, (clutter_actor_get_width (stage) - 100) / 2, clutter_actor_get_height (stage) - 100); clutter_actor_set_reactive (actor, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor); g_signal_connect (actor, "event", G_CALLBACK (input_cb), NULL); clutter_actor_show_all (CLUTTER_ACTOR (stage)); clutter_main(); return 0; } G_MODULE_EXPORT const char * test_events_describe (void) { return "Event handling and propagation."; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-bind-constraint.c���������������������������������������0000664�0001750�0001750�00000021657�14211404421�024527� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> #define RECT_SIZE 128 #define H_PADDING 32 #define V_PADDING 32 enum { NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast, N_RECTS }; static ClutterActor *rects[N_RECTS] = { NULL, }; static const gchar *colors[N_RECTS] = { "#8ae234", "#73d216", "#4e9a06", "#729fcf", "#3465a4", "#204a87", "#ef2929", "#cc0000", "#a40000" }; static const gchar *names[N_RECTS] = { "North West", "North", "North East", "West", "Center", "East", "South West", "South", "South East" }; static const gchar *desaturare_glsl_shader = "uniform sampler2D tex;\n" "uniform float factor;\n" "\n" "vec3 desaturate (const vec3 color, const float desaturation)\n" "{\n" " const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n" " vec3 gray = vec3 (dot (gray_conv, color));\n" " return vec3 (mix (color.rgb, gray, desaturation));\n" "}\n" "\n" "void main ()\n" "{\n" " vec4 color = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));\n" " color.rgb = desaturate (color.rgb, factor);\n" " cogl_color_out = color;\n" "}\n"; static gboolean is_expanded = FALSE; static gboolean on_button_release (ClutterActor *actor, ClutterEvent *event, gpointer data G_GNUC_UNUSED) { if (!is_expanded) { gfloat north_offset, south_offset; gfloat west_offset, east_offset; /* expand the 8 rectangles by animating the offset of the * bind constraints */ north_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING) * -1.0f; south_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING); west_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING) * -1.0f; east_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING); clutter_actor_animate (rects[NorthWest], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.x-bind.offset", west_offset, "@constraints.y-bind.offset", north_offset, "reactive", TRUE, NULL); clutter_actor_animate (rects[North], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.y-bind.offset", north_offset, "reactive", TRUE, NULL); clutter_actor_animate (rects[NorthEast], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.x-bind.offset", east_offset, "@constraints.y-bind.offset", north_offset, "reactive", TRUE, NULL); clutter_actor_animate (rects[West], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.x-bind.offset", west_offset, "reactive", TRUE, NULL); /* turn on the desaturation effect and set the center * rectangle not reactive */ clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500, "@effects.desaturate.enabled", TRUE, "reactive", FALSE, NULL); clutter_actor_animate (rects[East], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.x-bind.offset", east_offset, "reactive", TRUE, NULL); clutter_actor_animate (rects[SouthWest], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.x-bind.offset", west_offset, "@constraints.y-bind.offset", south_offset, "reactive", TRUE, NULL); clutter_actor_animate (rects[South], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.y-bind.offset", south_offset, "reactive", TRUE, NULL); clutter_actor_animate (rects[SouthEast], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 255, "@constraints.x-bind.offset", east_offset, "@constraints.y-bind.offset", south_offset, "reactive", TRUE, NULL); } else { gint i; clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500, "@effects.desaturate.enabled", FALSE, "reactive", TRUE, NULL); for (i = NorthWest; i < N_RECTS; i++) { if (i == Center) continue; /* put the 8 rectangles back into their initial state */ clutter_actor_animate (rects[i], CLUTTER_EASE_OUT_EXPO, 500, "opacity", 0, "@constraints.x-bind.offset", 0.0f, "@constraints.y-bind.offset", 0.0f, "reactive", FALSE, NULL); } } is_expanded = !is_expanded; g_print ("Selected: [%s]\n", clutter_actor_get_name (actor)); return TRUE; } G_MODULE_EXPORT const char * test_bind_constraint_describe (void) { return "Demonstrate the usage of ClutterBindConstraint"; } G_MODULE_EXPORT int test_bind_constraint_main (int argc, char *argv[]) { ClutterActor *stage, *rect; ClutterConstraint *constraint; ClutterEffect *effect; ClutterColor rect_color; gint i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_stage_set_title (CLUTTER_STAGE (stage), "Constraints"); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_size (stage, 800, 600); /* main rectangle */ clutter_color_from_string (&rect_color, "#3465a4"); rect = clutter_actor_new (); g_signal_connect (rect, "button-release-event", G_CALLBACK (on_button_release), NULL); clutter_actor_set_background_color (rect, &rect_color); clutter_actor_set_size (rect, RECT_SIZE, RECT_SIZE); clutter_actor_set_reactive (rect, TRUE); clutter_actor_set_name (rect, names[Center]); clutter_actor_add_child (stage, rect); /* align the center rectangle to the center of the stage */ constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5); clutter_actor_add_constraint_with_name (rect, "align", constraint); /* this is the equivalent of the DesaturateEffect; we cannot animate * the factor because the animation API only understands GObject * properties; so we use the ActorMeta:enabled property to toggle * the shader */ effect = clutter_shader_effect_new (CLUTTER_FRAGMENT_SHADER); clutter_shader_effect_set_shader_source (CLUTTER_SHADER_EFFECT (effect), desaturare_glsl_shader); clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect), "tex", G_TYPE_INT, 1, 0); clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect), "factor", G_TYPE_FLOAT, 1, 0.66); clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE); clutter_actor_add_effect_with_name (rect, "desaturate", effect); rects[Center] = rect; /* build the other rectangles, and bind their position and size * to the center rectangle. we are going to animate the offset * of the BindConstraints */ for (i = 0; i < N_RECTS; i++) { if (i == Center) continue; clutter_color_from_string (&rect_color, colors[i]); rect = clutter_actor_new (); clutter_actor_set_background_color (rect, &rect_color); clutter_actor_set_opacity (rect, 0); clutter_actor_set_name (rect, names[i]); clutter_actor_add_child (stage, rect); constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_X, 0.0); clutter_actor_add_constraint_with_name (rect, "x-bind", constraint); constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_Y, 0.0); clutter_actor_add_constraint_with_name (rect, "y-bind", constraint); constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_SIZE, 0.0); clutter_actor_add_constraint_with_name (rect, "size-bind", constraint); g_signal_connect (rect, "button-release-event", G_CALLBACK (on_button_release), NULL); rects[i] = rect; } clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-state-animator.c����������������������������������������0000664�0001750�0001750�00000012253�14211404421�024351� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> static ClutterState *state; static ClutterAnimator *animator; static gboolean press_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { clutter_grab_pointer (actor); clutter_state_set_state (state, "end"); return TRUE; } static gboolean release_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { clutter_state_set_state (state, "start"); clutter_ungrab_pointer (); return TRUE; } static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { GError *error = NULL; ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *rectangle; gchar *file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); rectangle = clutter_texture_new_from_file (file, &error); if (rectangle == NULL) g_error ("image load failed: %s", error->message); free (file); clutter_actor_set_size (rectangle, 128, 128); clutter_color_free (color); return rectangle; } G_MODULE_EXPORT gint test_state_animator_main (gint argc, gchar **argv) { ClutterActor *stage; ClutterActor *rects[40]; gint i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "State and Animator"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); for (i = 0; i < 2; i++) { rects[i] = new_rect (255 * (i * 1.0 / 40), 50, 160, 255); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rects[i]); clutter_actor_set_anchor_point (rects[i], 64, 64); clutter_actor_set_position (rects[i], 320.0, 240.0); clutter_actor_set_opacity (rects[i], 0x70); clutter_actor_set_reactive (rects[i], TRUE); g_signal_connect (rects[i], "button-press-event", G_CALLBACK (press_event), NULL); g_signal_connect (rects[i], "button-release-event", G_CALLBACK (release_event), NULL); } state = clutter_state_new (); clutter_state_set (state, NULL, "start", rects[0], "depth", CLUTTER_LINEAR, 0.0, rects[0], "x", CLUTTER_LINEAR, 100.0, rects[0], "y", CLUTTER_LINEAR, 300.0, rects[1], "opacity", CLUTTER_LINEAR, 0x20, rects[1], "scale-x", CLUTTER_LINEAR, 1.0, rects[1], "scale-y", CLUTTER_LINEAR, 1.0, NULL); clutter_state_set (state, NULL, "end", rects[0], "depth", CLUTTER_LINEAR, 200.0, rects[0], "x", CLUTTER_LINEAR, 320.0, rects[0], "y", CLUTTER_LINEAR, 240.0, rects[1], "opacity", CLUTTER_LINEAR, 0xff, rects[1], "scale-x", CLUTTER_LINEAR, 2.0, rects[1], "scale-y", CLUTTER_LINEAR, 2.0, NULL); animator = clutter_animator_new (); clutter_animator_set (animator, rects[0], "depth", -1, 0.0, 0.0, rects[0], "depth", CLUTTER_LINEAR, 1.0, 275.0, rects[0], "x", -1, 0.0, 0.0, rects[0], "x", CLUTTER_LINEAR, 0.5, 200.0, rects[0], "x", CLUTTER_LINEAR, 1.0, 320.0, rects[0], "y", -1, 0.0, 0.0, rects[0], "y", CLUTTER_LINEAR, 0.3, 100.0, rects[0], "y", CLUTTER_LINEAR, 1.0, 240.0, rects[1], "opacity", -1, 0.0, 0x20, rects[1], "opacity", CLUTTER_LINEAR, 1.0, 0xff, rects[1], "scale-x", -1, 0.0, 1.0, rects[1], "scale-x", CLUTTER_LINEAR, 0.5, 2.0, rects[1], "scale-x", CLUTTER_LINEAR, 1.0, 2.0, rects[1], "scale-y", -1, 0.0, 1.0, rects[1], "scale-y", CLUTTER_LINEAR, 0.5, 2.0, rects[1], "scale-y", CLUTTER_LINEAR, 1.0, 2.0, NULL); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[0]), "depth", TRUE); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[0]), "x", TRUE); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[0]), "y", TRUE); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[1]), "opacity", TRUE); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[1]), "scale-x", TRUE); clutter_animator_property_set_ease_in (animator, G_OBJECT (rects[1]), "scale-y", TRUE); clutter_animator_property_set_interpolation (animator, G_OBJECT (rects[0]), "x", CLUTTER_INTERPOLATION_CUBIC); clutter_animator_property_set_interpolation (animator, G_OBJECT (rects[0]), "y", CLUTTER_INTERPOLATION_CUBIC); clutter_state_set_animator (state, "start", "end", animator); g_object_unref (animator); clutter_actor_show (stage); clutter_state_set_state (state, "start"); clutter_main (); g_object_unref (state); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_state_animator_describe (void) { return "Animate using the State and Animator classes."; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-cogl-point-sprites.c������������������������������������0000664�0001750�0001750�00000020047�14211404421�025163� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <clutter/clutter.h> #include <math.h> #include <gmodule.h> #include <string.h> #define N_FIREWORKS 32 /* Units per second per second */ #define GRAVITY -1.5f #define N_SPARKS (N_FIREWORKS * 32) /* Must be a power of two */ #define TIME_PER_SPARK 0.01f /* in seconds */ #define TEXTURE_SIZE 32 typedef struct _Firework Firework; struct _Firework { float size; float x, y; float start_x, start_y; ClutterColor color; /* Velocities are in units per second */ float initial_x_velocity; float initial_y_velocity; GTimer *timer; }; typedef struct _Spark Spark; struct _Spark { float x, y; ClutterColor color; ClutterColor base_color; }; typedef struct _Data Data; struct _Data { Firework fireworks[N_FIREWORKS]; int next_spark_num; Spark sparks[N_SPARKS]; GTimer *last_spark_time; CoglMaterial *material; }; static CoglHandle generate_round_texture (void) { guint8 *p, *data; int x, y; CoglHandle tex; p = data = malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4); /* Generate a yellow circle which gets transparent towards the edges */ for (y = 0; y < TEXTURE_SIZE; y++) for (x = 0; x < TEXTURE_SIZE; x++) { int dx = x - TEXTURE_SIZE / 2; int dy = y - TEXTURE_SIZE / 2; float value = sqrtf (dx * dx + dy * dy) * 255.0 / (TEXTURE_SIZE / 2); if (value > 255.0f) value = 255.0f; value = 255.0f - value; *(p++) = value; *(p++) = value; *(p++) = value; *(p++) = value; } tex = cogl_texture_new_from_data (TEXTURE_SIZE, TEXTURE_SIZE, COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_ANY, TEXTURE_SIZE * 4, data); free (data); return tex; } static void paint_cb (ClutterActor *stage, Data *data) { CoglMatrix old_matrix, new_matrix; int i; float diff_time; CoglHandle vbo; cogl_get_projection_matrix (&old_matrix); /* Use an orthogonal projection from -1 -> 1 in both axes */ cogl_matrix_init_identity (&new_matrix); cogl_set_projection_matrix (&new_matrix); cogl_push_matrix (); cogl_set_modelview_matrix (&new_matrix); /* Update all of the firework's positions */ for (i = 0; i < N_FIREWORKS; i++) { Firework *firework = data->fireworks + i; if ((fabsf (firework->x - firework->start_x) > 2.0f) || firework->y < -1.0f) { firework->size = g_random_double_range (0.001f, 0.1f); firework->start_x = 1.0f + firework->size; firework->start_y = -1.0f; firework->initial_x_velocity = g_random_double_range (-0.1f, -2.0f); firework->initial_y_velocity = g_random_double_range (0.1f, 4.0f); g_timer_reset (firework->timer); /* Pick a random color out of six */ if (g_random_boolean ()) { memset (&firework->color, 0, sizeof (ClutterColor)); ((guint8 *) &firework->color)[g_random_int_range (0, 3)] = 255; } else { memset (&firework->color, 255, sizeof (ClutterColor)); ((guint8 *) &firework->color)[g_random_int_range (0, 3)] = 0; } firework->color.alpha = 255; /* Fire some of the fireworks from the other side */ if (g_random_boolean ()) { firework->start_x = -firework->start_x; firework->initial_x_velocity = -firework->initial_x_velocity; } } diff_time = g_timer_elapsed (firework->timer, NULL); firework->x = (firework->start_x + firework->initial_x_velocity * diff_time); firework->y = ((firework->initial_y_velocity * diff_time + 0.5f * GRAVITY * diff_time * diff_time) + firework->start_y); } diff_time = g_timer_elapsed (data->last_spark_time, NULL); if (diff_time < 0.0f || diff_time >= TIME_PER_SPARK) { /* Add a new spark for each firework, overwriting the oldest ones */ for (i = 0; i < N_FIREWORKS; i++) { Spark *spark = data->sparks + data->next_spark_num; Firework *firework = data->fireworks + i; spark->x = (firework->x + g_random_double_range (-firework->size / 2.0f, firework->size / 2.0f)); spark->y = (firework->y + g_random_double_range (-firework->size / 2.0f, firework->size / 2.0f)); spark->base_color = firework->color; data->next_spark_num = (data->next_spark_num + 1) & (N_SPARKS - 1); } /* Update the colour of each spark */ for (i = 0; i < N_SPARKS; i++) { float color_value; /* First spark is the oldest */ Spark *spark = data->sparks + ((data->next_spark_num + i) & (N_SPARKS - 1)); color_value = i / (N_SPARKS - 1.0f); spark->color.red = spark->base_color.red * color_value; spark->color.green = spark->base_color.green * color_value; spark->color.blue = spark->base_color.blue * color_value; spark->color.alpha = 255.0f * color_value; } g_timer_reset (data->last_spark_time); } vbo = cogl_vertex_buffer_new (N_SPARKS); cogl_vertex_buffer_add (vbo, "gl_Vertex", 2, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (Spark), &data->sparks[0].x); cogl_vertex_buffer_add (vbo, "gl_Color", 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, TRUE, sizeof (Spark), &data->sparks[0].color.red); cogl_vertex_buffer_submit (vbo); cogl_set_source (data->material); cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_POINTS, 0, N_SPARKS); cogl_handle_unref (vbo); cogl_set_projection_matrix (&old_matrix); cogl_pop_matrix (); } static gboolean idle_cb (gpointer data) { clutter_actor_queue_redraw (data); return G_SOURCE_CONTINUE; } G_MODULE_EXPORT int test_cogl_point_sprites_main (int argc, char *argv[]) { ClutterActor *stage; CoglHandle tex; Data data; GError *error = NULL; int i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; data.material = cogl_material_new (); data.last_spark_time = g_timer_new (); data.next_spark_num = 0; cogl_material_set_point_size (data.material, TEXTURE_SIZE); tex = generate_round_texture (); cogl_material_set_layer (data.material, 0, tex); cogl_handle_unref (tex); if (!cogl_material_set_layer_point_sprite_coords_enabled (data.material, 0, TRUE, &error)) { g_warning ("Failed to enable point sprite coords: %s", error->message); g_clear_error (&error); } for (i = 0; i < N_FIREWORKS; i++) { data.fireworks[i].x = -FLT_MAX; data.fireworks[i].y = FLT_MAX; data.fireworks[i].size = 0.0f; data.fireworks[i].timer = g_timer_new (); } for (i = 0; i < N_SPARKS; i++) { data.sparks[i].x = 2.0f; data.sparks[i].y = 2.0f; } stage = clutter_stage_new (); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Point Sprites"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect_after (stage, "paint", G_CALLBACK (paint_cb), &data); clutter_actor_show (stage); clutter_threads_add_idle (idle_cb, stage); clutter_main (); cogl_object_unref (data.material); g_timer_destroy (data.last_spark_time); for (i = 0; i < N_FIREWORKS; i++) g_timer_destroy (data.fireworks[i].timer); return 0; } G_MODULE_EXPORT const char * test_cogl_point_sprites_describe (void) { return "Point sprites support in Cogl."; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-texture-quality.c���������������������������������������0000664�0001750�0001750�00000007033�14211404421�024607� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> /* each time the timeline animating the label completes, swap the direction */ static void timeline_completed (ClutterTimeline *timeline, gpointer user_data) { clutter_timeline_set_direction (timeline, !clutter_timeline_get_direction (timeline)); clutter_timeline_start (timeline); } static gboolean change_filter (gpointer actor) { ClutterTextureQuality old_quality; old_quality = clutter_texture_get_filter_quality (actor); switch (old_quality) { case CLUTTER_TEXTURE_QUALITY_LOW: clutter_texture_set_filter_quality (actor, CLUTTER_TEXTURE_QUALITY_MEDIUM); g_print ("Setting texture rendering quality to medium\n"); break; case CLUTTER_TEXTURE_QUALITY_MEDIUM: clutter_texture_set_filter_quality (actor, CLUTTER_TEXTURE_QUALITY_HIGH); g_print ("Setting texture rendering quality to high\n"); break; case CLUTTER_TEXTURE_QUALITY_HIGH: clutter_texture_set_filter_quality (actor, CLUTTER_TEXTURE_QUALITY_LOW); g_print ("Setting texture rendering quality to low\n"); break; } return TRUE; } G_MODULE_EXPORT gint test_texture_quality_main (int argc, char *argv[]) { ClutterTimeline *timeline; ClutterAlpha *alpha; ClutterBehaviour *depth_behavior; ClutterActor *stage; ClutterActor *image; ClutterColor stage_color = { 0x12, 0x34, 0x56, 0xff }; ClutterFog stage_fog = { 10.0, -50.0 }; GError *error; gchar *file; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_set_background_color (stage, &stage_color); clutter_stage_set_use_fog (CLUTTER_STAGE (stage), TRUE); clutter_stage_set_fog (CLUTTER_STAGE (stage), &stage_fog); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "button-press-event", G_CALLBACK (clutter_main_quit), NULL); if (argc < 2) g_print ("Hint: the redhand.png isn't a good test image for this test.\n" "This test can take any image file as an argument\n"); file = (argc > 1) ? g_strdup (argv[1]) : g_build_filename (TESTS_DATADIR, "redhand.png", NULL); error = NULL; image = clutter_texture_new_from_file (file, &error); if (error) g_error ("Unable to load image: %s", error->message); free (file); /* center the image */ clutter_actor_set_position (image, (clutter_actor_get_width (stage) - clutter_actor_get_width (image))/2, (clutter_actor_get_height (stage) - clutter_actor_get_height (image))/2); clutter_container_add (CLUTTER_CONTAINER (stage), image, NULL); timeline = clutter_timeline_new (5000); g_signal_connect (timeline, "completed", G_CALLBACK (timeline_completed), NULL); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); depth_behavior = clutter_behaviour_depth_new (alpha, -2500, 400); clutter_behaviour_apply (depth_behavior, image); clutter_actor_show (stage); clutter_timeline_start (timeline); clutter_threads_add_timeout (10000, change_filter, image); clutter_main (); g_object_unref (depth_behavior); g_object_unref (timeline); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_texture_quality_describe (void) { return "Change the texture filtering quality."; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-multistage.c��������������������������������������������0000664�0001750�0001750�00000010555�14211404421�023602� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <gmodule.h> #include <clutter/clutter.h> static GList *stages = NULL; static gint n_stages = 1; static gboolean tex_button_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { clutter_actor_hide (actor); return TRUE; } static void on_destroy (ClutterActor *actor) { stages = g_list_remove (stages, actor); } static gboolean on_button_press (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterActor *new_stage; ClutterActor *label, *tex; gint width, height; gchar *stage_label, *stage_name; ClutterTimeline *timeline; ClutterAlpha *alpha; ClutterBehaviour *r_behave; new_stage = clutter_stage_new (); if (new_stage == NULL) return FALSE; stage_name = g_strdup_printf ("Stage [%d]", ++n_stages); clutter_stage_set_title (CLUTTER_STAGE (new_stage), stage_name); clutter_actor_set_background_color (new_stage, CLUTTER_COLOR_DarkScarletRed); clutter_actor_set_size (new_stage, 320, 240); clutter_actor_set_name (new_stage, stage_name); g_signal_connect (new_stage, "destroy", G_CALLBACK (on_destroy), NULL); tex = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL); if (!tex) g_error ("pixbuf load failed"); clutter_actor_set_reactive (tex, TRUE); g_signal_connect (tex, "button-press-event", G_CALLBACK (tex_button_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (new_stage), tex); stage_label = g_strconcat ("<b>", stage_name, "</b>", NULL); label = clutter_text_new_with_text ("Mono 12", stage_label); clutter_text_set_color (CLUTTER_TEXT (label), CLUTTER_COLOR_White); clutter_text_set_use_markup (CLUTTER_TEXT (label), TRUE); width = (clutter_actor_get_width (new_stage) - clutter_actor_get_width (label)) / 2; height = (clutter_actor_get_height (new_stage) - clutter_actor_get_height (label)) / 2; clutter_actor_set_position (label, width, height); clutter_container_add_actor (CLUTTER_CONTAINER (new_stage), label); clutter_actor_show (label); free (stage_label); /* g_signal_connect (new_stage, "button-press-event", G_CALLBACK (clutter_actor_destroy), NULL); */ timeline = clutter_timeline_new (2000); clutter_timeline_set_repeat_count (timeline, -1); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); r_behave = clutter_behaviour_rotate_new (alpha, CLUTTER_Y_AXIS, CLUTTER_ROTATE_CW, 0.0, 360.0); clutter_behaviour_rotate_set_center (CLUTTER_BEHAVIOUR_ROTATE (r_behave), clutter_actor_get_width (label)/2, 0, 0); clutter_behaviour_apply (r_behave, label); clutter_timeline_start (timeline); clutter_actor_show_all (new_stage); stages = g_list_prepend (stages, new_stage); free (stage_name); return TRUE; } G_MODULE_EXPORT int test_multistage_main (int argc, char *argv[]) { ClutterActor *stage_default; ClutterActor *label; gint width, height; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage_default = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage_default), "Default Stage"); clutter_actor_set_name (stage_default, "Default Stage"); g_signal_connect (stage_default, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage_default, "button-press-event", G_CALLBACK (on_button_press), NULL); label = clutter_text_new_with_text ("Mono 16", "Default stage"); width = (clutter_actor_get_width (stage_default) - clutter_actor_get_width (label)) / 2; height = (clutter_actor_get_height (stage_default) - clutter_actor_get_height (label)) / 2; clutter_actor_set_position (label, width, height); clutter_container_add_actor (CLUTTER_CONTAINER (stage_default), label); clutter_actor_show (label); clutter_actor_show (stage_default); clutter_main (); g_list_foreach (stages, (GFunc) clutter_actor_destroy, NULL); g_list_free (stages); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-stage-read-pixels.c�������������������������������������0000664�0001750�0001750�00000010030�14211404421�024726� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <gmodule.h> #include <clutter/clutter.h> #include <string.h> #define DOT_SIZE 2 #define TEX_SIZE 64 typedef struct _CallbackData CallbackData; struct _CallbackData { ClutterActor *stage; ClutterActor *tex; ClutterActor *box; ClutterMotionEvent event; guint idle_source; }; static ClutterActor * make_label (void) { ClutterActor *label; gchar *text; gchar *argv[] = { "ls", "--help", NULL }; label = clutter_text_new (); clutter_text_set_font_name (CLUTTER_TEXT (label), "Sans 10"); if (g_spawn_sync (NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH, NULL, NULL, &text, NULL, NULL, NULL)) { clutter_text_set_text (CLUTTER_TEXT (label), text); free (text); } return label; } static ClutterActor * make_tex (void) { ClutterActor *tex = clutter_texture_new (); clutter_actor_set_size (tex, TEX_SIZE * 2, TEX_SIZE * 2); return tex; } static ClutterActor * make_box (void) { ClutterActor *box; static const ClutterColor blue = { 0x00, 0x00, 0xff, 0xff }; box = clutter_rectangle_new_with_color (&blue); clutter_actor_set_size (box, DOT_SIZE + 2, DOT_SIZE + 2); clutter_actor_hide (box); return box; } static gboolean on_motion_idle (gpointer user_data) { CallbackData *data = (CallbackData *) user_data; guchar *pixels, *p; gfloat stage_width, stage_height; gint x, y; data->idle_source = 0; clutter_actor_get_size (data->stage, &stage_width, &stage_height); x = CLAMP (data->event.x - TEX_SIZE / 2, 0, stage_width - TEX_SIZE); y = CLAMP (data->event.y - TEX_SIZE / 2, 0, stage_height - TEX_SIZE); clutter_actor_set_position (data->box, x + TEX_SIZE / 2 - 1, y + TEX_SIZE / 2 - 1); clutter_actor_show (data->box); /* Redraw so that the layouting will be done and the box will be drawn in the right position */ clutter_stage_ensure_redraw (CLUTTER_STAGE (data->stage)); pixels = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage), x, y, TEX_SIZE, TEX_SIZE); /* Make a red dot in the center */ p = pixels + (TEX_SIZE / 2 - DOT_SIZE / 2) * TEX_SIZE * 4 + (TEX_SIZE / 2 - DOT_SIZE / 2) * 4; for (y = 0; y < DOT_SIZE; y++) { for (x = 0; x < DOT_SIZE; x++) { *(p++) = 255; memset (p, 0, 3); p += 3; } p += TEX_SIZE * 4 - DOT_SIZE * 4; } /* Set all of the alpa values to full */ for (p = pixels + TEX_SIZE * TEX_SIZE * 4; p > pixels; p -= 4) *(p - 1) = 255; clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (data->tex), pixels, TRUE, TEX_SIZE, TEX_SIZE, TEX_SIZE * 4, 4, 0, NULL); free (pixels); return FALSE; } static gboolean on_motion (ClutterActor *stage, ClutterMotionEvent *event, CallbackData *data) { /* Handle the motion event in an idle handler so that multiple events will be combined into one */ if (data->idle_source == 0) data->idle_source = clutter_threads_add_idle (on_motion_idle, data); data->event = *event; return FALSE; } G_MODULE_EXPORT int test_stage_read_pixels_main (int argc, char **argv) { CallbackData data; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; data.idle_source = 0; data.stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (data.stage), "Read Pixels"); g_signal_connect (data.stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); data.tex = make_tex (); data.box = make_box (); clutter_actor_set_position (data.tex, clutter_actor_get_width (data.stage) - clutter_actor_get_width (data.tex), clutter_actor_get_height (data.stage) - clutter_actor_get_height (data.tex)); clutter_container_add (CLUTTER_CONTAINER (data.stage), make_label (), data.tex, data.box, NULL); g_signal_connect (data.stage, "motion-event", G_CALLBACK (on_motion), &data); clutter_actor_show (data.stage); clutter_main (); return 0; } G_MODULE_EXPORT const char * test_stage_read_pixels_describe (void) { return "Read back pixels from a Stage."; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-scale.c�������������������������������������������������0000664�0001750�0001750�00000006474�14211404421�022520� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <gmodule.h> #include <clutter/clutter.h> static const ClutterGravity gravities[] = { CLUTTER_GRAVITY_NORTH_EAST, CLUTTER_GRAVITY_NORTH, CLUTTER_GRAVITY_NORTH_WEST, CLUTTER_GRAVITY_WEST, CLUTTER_GRAVITY_SOUTH_WEST, CLUTTER_GRAVITY_SOUTH, CLUTTER_GRAVITY_SOUTH_EAST, CLUTTER_GRAVITY_EAST, CLUTTER_GRAVITY_CENTER, CLUTTER_GRAVITY_NONE }; static gint gindex = 0; static ClutterActor *label; static void set_next_gravity (ClutterActor *actor) { ClutterGravity gravity = gravities[gindex]; GEnumClass *eclass; GEnumValue *evalue; clutter_actor_move_anchor_point_from_gravity (actor, gravities[gindex]); eclass = g_type_class_ref (CLUTTER_TYPE_GRAVITY); evalue = g_enum_get_value (eclass, gravity); clutter_text_set_text (CLUTTER_TEXT (label), evalue->value_nick); g_type_class_unref (eclass); if (++gindex >= G_N_ELEMENTS (gravities)) gindex = 0; } static gdouble my_ramp_func (ClutterAlpha *alpha, gpointer unused) { ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); return clutter_timeline_get_progress (timeline); } G_MODULE_EXPORT int test_scale_main (int argc, char *argv[]) { ClutterActor *stage, *rect; ClutterColor rect_color = { 0xff, 0xff, 0xff, 0x99 }; ClutterTimeline *timeline; ClutterAlpha *alpha; ClutterBehaviour *behave; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Scaling"); clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black); clutter_actor_set_size (stage, 300, 300); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); rect = clutter_rectangle_new_with_color (&rect_color); clutter_actor_set_size (rect, 100, 100); clutter_actor_set_position (rect, 100, 100); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); label = clutter_text_new_with_text ("Sans 20px", ""); clutter_text_set_color (CLUTTER_TEXT (label), CLUTTER_COLOR_White); clutter_actor_set_position (label, clutter_actor_get_x (rect), clutter_actor_get_y (rect) + clutter_actor_get_height (rect)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); rect_color.alpha = 0xff; rect = clutter_rectangle_new_with_color (&rect_color); clutter_actor_set_position (rect, 100, 100); clutter_actor_set_size (rect, 100, 100); set_next_gravity (rect); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); timeline = clutter_timeline_new (750); alpha = clutter_alpha_new_with_func (timeline, my_ramp_func, NULL, NULL); behave = clutter_behaviour_scale_new (alpha, 0.0, 0.0, /* scale start */ 1.0, 1.0); /* scale end */ clutter_behaviour_apply (behave, rect); clutter_timeline_set_repeat_count (timeline, -1); g_signal_connect_swapped (timeline, "completed", G_CALLBACK (set_next_gravity), rect); clutter_timeline_start (timeline); clutter_actor_show_all (stage); clutter_main(); g_object_unref (timeline); g_object_unref (behave); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_scale_describe (void) { return "Scaling animation and scaling center changes"; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-actors.c������������������������������������������������0000664�0001750�0001750�00000017665�14211404421�022730� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <math.h> #include <errno.h> #include <stdlib.h> #include <glib.h> #include <gmodule.h> #define NHANDS 6 typedef struct SuperOH { ClutterActor **hand; ClutterActor *bgtex; ClutterActor *real_hand; ClutterActor *group; ClutterActor *stage; gint stage_width; gint stage_height; gfloat radius; ClutterBehaviour *scaler_1; ClutterBehaviour *scaler_2; ClutterTimeline *timeline; } SuperOH; static gint n_hands = NHANDS; static GOptionEntry super_oh_entries[] = { { "num-hands", 'n', 0, G_OPTION_ARG_INT, &n_hands, "Number of hands", "HANDS" }, { NULL } }; static void on_group_destroy (ClutterActor *actor, SuperOH *oh) { oh->group = NULL; } static void on_hand_destroy (ClutterActor *actor, SuperOH *oh) { int i; for (i = 0; i < n_hands; i++) { if (oh->hand[i] == actor) oh->hand[i] = NULL; } } static gboolean on_button_press_event (ClutterActor *actor, ClutterEvent *event, SuperOH *oh) { gfloat x, y; clutter_event_get_coords (event, &x, &y); g_print ("*** button press event (button:%d) at %.2f, %.2f on %s ***\n", clutter_event_get_button (event), x, y, clutter_actor_get_name (actor)); clutter_actor_hide (actor); return TRUE; } static gboolean input_cb (ClutterActor *stage, ClutterEvent *event, gpointer data) { SuperOH *oh = data; if (event->type == CLUTTER_KEY_RELEASE) { g_print ("*** key press event (key:%c) ***\n", clutter_event_get_key_symbol (event)); if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_q) { clutter_main_quit (); return TRUE; } else if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_r) { gint i; for (i = 0; i < n_hands; i++) { if (oh->hand[i] != NULL) clutter_actor_show (oh->hand[i]); } return TRUE; } } return FALSE; } /* Timeline handler */ static void frame_cb (ClutterTimeline *timeline, gint msecs, gpointer data) { SuperOH *oh = data; gint i; float rotation = clutter_timeline_get_progress (timeline) * 360.0f; /* Rotate everything clockwise about stage center*/ if (oh->group != NULL) clutter_actor_set_rotation (oh->group, CLUTTER_Z_AXIS, rotation, oh->stage_width / 2, oh->stage_height / 2, 0); for (i = 0; i < n_hands; i++) { /* Rotate each hand around there centers - to get this we need * to take into account any scaling. */ if (oh->hand[i] != NULL) clutter_actor_set_rotation (oh->hand[i], CLUTTER_Z_AXIS, -6.0 * rotation, 0, 0, 0); } } static void stop_and_quit (ClutterActor *stage, SuperOH *data) { clutter_timeline_stop (data->timeline); clutter_main_quit (); } static gdouble my_sine_wave (ClutterAlpha *alpha, gpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); gdouble progress = clutter_timeline_get_progress (timeline); return sin (progress * G_PI); } G_MODULE_EXPORT int test_actors_main (int argc, char *argv[]) { ClutterAlpha *alpha; SuperOH *oh; gint i; GError *error; ClutterActor *real_hand; gchar *file; error = NULL; if (clutter_init_with_args (&argc, &argv, NULL, super_oh_entries, NULL, &error) != CLUTTER_INIT_SUCCESS) { g_warning ("Unable to initialise Clutter:\n%s", error->message); g_error_free (error); return EXIT_FAILURE; } oh = g_new (SuperOH, 1); oh->stage = clutter_stage_new (); clutter_actor_set_size (oh->stage, 800, 600); clutter_actor_set_name (oh->stage, "Default Stage"); clutter_actor_set_background_color (oh->stage, CLUTTER_COLOR_LightSkyBlue); g_signal_connect (oh->stage, "destroy", G_CALLBACK (stop_and_quit), oh); clutter_stage_set_title (CLUTTER_STAGE (oh->stage), "Actors"); clutter_stage_set_user_resizable (CLUTTER_STAGE (oh->stage), TRUE); /* Create a timeline to manage animation */ oh->timeline = clutter_timeline_new (6000); clutter_timeline_set_repeat_count (oh->timeline, -1); /* fire a callback for frame change */ g_signal_connect (oh->timeline, "new-frame", G_CALLBACK (frame_cb), oh); /* Set up some behaviours to handle scaling */ alpha = clutter_alpha_new_with_func (oh->timeline, my_sine_wave, NULL, NULL); oh->scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, 1.0, 1.0); oh->scaler_2 = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 0.5, 0.5); file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); real_hand = clutter_texture_new_from_file (file, &error); if (real_hand == NULL) g_error ("image load failed: %s", error->message); free (file); /* create a new actor to hold other actors */ oh->group = clutter_actor_new (); clutter_actor_set_layout_manager (oh->group, clutter_fixed_layout_new ()); clutter_actor_set_name (oh->group, "Group"); g_signal_connect (oh->group, "destroy", G_CALLBACK (on_group_destroy), oh); clutter_actor_add_constraint (oh->group, clutter_align_constraint_new (oh->stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_add_constraint (oh->group, clutter_bind_constraint_new (oh->stage, CLUTTER_BIND_SIZE, 0.0f)); oh->hand = g_new (ClutterActor*, n_hands); oh->stage_width = clutter_actor_get_width (oh->stage); oh->stage_height = clutter_actor_get_height (oh->stage); oh->radius = (oh->stage_width + oh->stage_height) / n_hands; for (i = 0; i < n_hands; i++) { gint x, y, w, h; if (i == 0) { oh->hand[i] = real_hand; clutter_actor_set_name (oh->hand[i], "Real Hand"); } else { oh->hand[i] = clutter_clone_new (real_hand); clutter_actor_set_name (oh->hand[i], "Clone Hand"); } clutter_actor_set_reactive (oh->hand[i], TRUE); clutter_actor_set_size (oh->hand[i], 200, 213); /* Place around a circle */ w = clutter_actor_get_width (oh->hand[i]); h = clutter_actor_get_height (oh->hand[i]); x = oh->stage_width / 2 + oh->radius * cos (i * G_PI / (n_hands / 2)) - w / 2; y = oh->stage_height / 2 + oh->radius * sin (i * G_PI / (n_hands / 2)) - h / 2; clutter_actor_set_position (oh->hand[i], x, y); clutter_actor_move_anchor_point_from_gravity (oh->hand[i], CLUTTER_GRAVITY_CENTER); /* Add to our group group */ clutter_container_add_actor (CLUTTER_CONTAINER (oh->group), oh->hand[i]); g_signal_connect (oh->hand[i], "button-press-event", G_CALLBACK (on_button_press_event), oh); g_signal_connect (oh->hand[i], "destroy", G_CALLBACK (on_hand_destroy), oh); if (i % 2) clutter_behaviour_apply (oh->scaler_1, oh->hand[i]); else clutter_behaviour_apply (oh->scaler_2, oh->hand[i]); } /* Add the group to the stage */ clutter_container_add_actor (CLUTTER_CONTAINER (oh->stage), oh->group); /* Show everying */ clutter_actor_show (oh->stage); g_signal_connect (oh->stage, "key-release-event", G_CALLBACK (input_cb), oh); /* and start it */ clutter_timeline_start (oh->timeline); clutter_main (); clutter_timeline_stop (oh->timeline); /* clean up */ g_object_unref (oh->scaler_1); g_object_unref (oh->scaler_2); g_object_unref (oh->timeline); free (oh->hand); free (oh); return EXIT_SUCCESS; } ���������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-main.c��������������������������������������������������0000664�0001750�0001750�00000011364�14211404421�022347� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #include <glib.h> #include <gmodule.h> #include "test-unit-names.h" #define MAX_DESC_SIZE 72 static GModule *module = NULL; static gpointer get_symbol_with_suffix (const char *unit_name, const char *suffix) { char *main_symbol_name; gpointer func; main_symbol_name = g_strconcat (unit_name, "_", suffix, NULL); main_symbol_name = g_strdelimit (main_symbol_name, "-", '_'); g_module_symbol (module, main_symbol_name, &func); free (main_symbol_name); return func; } static gpointer get_unit_name_main (const char *unit_name) { return get_symbol_with_suffix (unit_name, "main"); } static char * get_unit_name_description (const char *unit_name, gssize max_len) { const char *description; gpointer func; char *retval; func = get_symbol_with_suffix (unit_name, "describe"); if (func == NULL) description = "No description found"; else { const char *(* unit_test_describe) (void); unit_test_describe = func; description = unit_test_describe (); } if (max_len > 0 && strlen (description) >= max_len) { GString *buf = g_string_sized_new (max_len); char *newline; newline = strchr (description, '\n'); if (newline != NULL) { g_string_append_len (buf, description, MIN (newline - description - 1, max_len - 3)); } else g_string_append_len (buf, description, max_len - 3); g_string_append (buf, "..."); retval = g_string_free (buf, FALSE); } else retval = g_strdup (description); return retval; } static gboolean list_all = FALSE; static gboolean describe = FALSE; static char **unit_names = NULL; static GOptionEntry entries[] = { { "describe", 'd', 0, G_OPTION_ARG_NONE, &describe, "Describe the interactive unit test", NULL, }, { "list-all", 'l', 0, G_OPTION_ARG_NONE, &list_all, "List all available units", NULL, }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &unit_names, "The interactive unit test", "UNIT_NAME" }, { NULL } }; int main (int argc, char **argv) { int ret, i, n_unit_names; GOptionContext *context; context = g_option_context_new (" - Interactive test suite"); g_option_context_add_main_entries (context, entries, NULL); g_option_context_set_help_enabled (context, TRUE); g_option_context_set_ignore_unknown_options (context, TRUE); if (!g_option_context_parse (context, &argc, &argv, NULL)) { g_print ("Usage: test-interactive <unit_test>\n"); return EXIT_FAILURE; } g_option_context_free (context); module = g_module_open (NULL, 0); if (!module) g_error ("*** Failed to open self for symbol lookup"); ret = EXIT_SUCCESS; if (list_all) { g_print ("* Available unit tests:\n"); for (i = 0; i < G_N_ELEMENTS (test_unit_names); i++) { char *str; gsize len; len = MAX_DESC_SIZE - strlen (test_unit_names[i]); str = get_unit_name_description (test_unit_names[i], len - 2); g_print (" - %s:%*s%s\n", test_unit_names[i], (int) (len - strlen (str)), " ", str); free (str); } ret = EXIT_SUCCESS; goto out; } if (unit_names != NULL) n_unit_names = g_strv_length (unit_names); else { g_print ("Usage: test-interactive <unit_test>\n"); ret = EXIT_FAILURE; goto out; } for (i = 0; i < n_unit_names; i++) { const char *unit_name = unit_names[i]; char *unit_test = NULL; gboolean found; int j; unit_test = g_path_get_basename (unit_name); found = FALSE; for (j = 0; j < G_N_ELEMENTS (test_unit_names); j++) { if (strcmp (test_unit_names[j], unit_test) == 0) { found = TRUE; break; } } if (!found) g_error ("*** Unit '%s' does not exist", unit_test); if (describe) { char *str; str = get_unit_name_description (unit_test, -1); g_print ("* %s:\n%s\n\n", unit_test, str); free (str); ret = EXIT_SUCCESS; } else { int (* unit_test_main) (int argc, char **argv); gpointer func; func = get_unit_name_main (unit_test); if (func == NULL) g_error ("*** Unable to find the main entry point for '%s'", unit_test); unit_test_main = func; ret = unit_test_main (n_unit_names, unit_names); free (unit_test); break; } free (unit_test); } out: g_module_close (module); return ret; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-pixmap.c������������������������������������������������0000664�0001750�0001750�00000022320�14211404421�022713� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #include <gmodule.h> #include <cairo.h> #ifdef CAIRO_HAS_XLIB_SURFACE #include <cairo-xlib.h> #endif #include <clutter/clutter.h> #ifdef CLUTTER_WINDOWING_X11 #include <X11/Xlib.h> #include <X11/extensions/Xcomposite.h> #include <clutter/x11/clutter-x11.h> #include <clutter/x11/clutter-x11-texture-pixmap.h> #endif #define IMAGE TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png" static gboolean disable_x11 = FALSE; static gboolean disable_animation = FALSE; static GOptionEntry g_options[] = { { "disable-x11", 0, 0, G_OPTION_ARG_NONE, &disable_x11, "Disable redirection through X11 pixmap", NULL }, { "disable-animation", 0, 0, G_OPTION_ARG_NONE, &disable_animation, "Disable the animations", NULL }, { NULL } }; static void toggle_texture_quality (ClutterActor *actor) { if (CLUTTER_IS_CONTAINER (actor)) clutter_container_foreach (CLUTTER_CONTAINER (actor), (ClutterCallback) toggle_texture_quality, NULL); if (CLUTTER_IS_TEXTURE (actor)) { ClutterTextureQuality quality; quality = clutter_texture_get_filter_quality (CLUTTER_TEXTURE (actor)); if (quality == CLUTTER_TEXTURE_QUALITY_HIGH) quality = CLUTTER_TEXTURE_QUALITY_MEDIUM; else quality = CLUTTER_TEXTURE_QUALITY_HIGH; g_print ("switching to quality %s for %p\n", quality == CLUTTER_TEXTURE_QUALITY_HIGH ? "high" : "medium", actor); clutter_texture_set_filter_quality (CLUTTER_TEXTURE (actor), quality); } } static gboolean stage_key_release_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { switch (clutter_event_get_key_symbol (event)) { case CLUTTER_KEY_q: case CLUTTER_KEY_Q: clutter_main_quit (); break; case CLUTTER_KEY_m: toggle_texture_quality (actor); break; } return FALSE; } static gboolean draw_arc (gpointer data) { Pixmap pixmap = GPOINTER_TO_UINT (data); Display *dpy = clutter_x11_get_default_display (); static GC gc = None; static int x = 100, y = 100; if (gc == None) { XGCValues gc_values = { 0 }; gc_values.line_width = 12; /* This is an attempt to get a black pixel will full opacity. Seemingly the BlackPixel macro and the default GC value are a fully transparent color */ gc_values.foreground = 0xff000000; gc = XCreateGC (dpy, pixmap, GCLineWidth | GCForeground, &gc_values); } XDrawArc (dpy, pixmap, gc, x, y, 100, 100, 0, 360 * 64); x -= 5; y -= 5; return G_SOURCE_CONTINUE; } static gboolean stage_button_press_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { draw_arc (data); return CLUTTER_EVENT_STOP; } Pixmap create_pixmap (guint *width, guint *height, guint *depth) { Display *dpy = clutter_x11_get_default_display (); cairo_surface_t *image; Pixmap pixmap; XVisualInfo xvisinfo; XVisualInfo *xvisinfos; int n; cairo_surface_t *xlib_surface; cairo_t *cr; guint w, h; image = cairo_image_surface_create_from_png (IMAGE); if (cairo_surface_status (image) != CAIRO_STATUS_SUCCESS) g_error ("Failed to load %s", IMAGE); w = cairo_image_surface_get_width (image); h = cairo_image_surface_get_height (image); pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), w, h, 32); xvisinfo.depth = 32; xvisinfos = XGetVisualInfo (dpy, VisualDepthMask, &xvisinfo, &n); if (!xvisinfos) g_error ("Failed to find a 32bit X Visual"); xlib_surface = cairo_xlib_surface_create (dpy, pixmap, xvisinfos->visual, w, h); XFree (xvisinfos); cr = cairo_create (xlib_surface); cairo_set_source_surface (cr, image, 0, 0); cairo_paint (cr); cairo_surface_destroy (image); if (width) *width = w; if (height) *height = h; if (depth) *depth = 32; return pixmap; } /* each time the timeline animating the label completes, swap the direction */ static void timeline_completed (ClutterTimeline *timeline, gpointer user_data) { clutter_timeline_set_direction (timeline, !clutter_timeline_get_direction (timeline)); clutter_timeline_start (timeline); } G_MODULE_EXPORT int test_pixmap_main (int argc, char **argv) { GOptionContext *context; Display *xdpy; int screen; ClutterActor *group = NULL, *label, *stage, *tex; Pixmap pixmap; const ClutterColor gry = { 0x99, 0x99, 0x99, 0xFF }; Window win_remote; guint w, h, d; GC gc; ClutterTimeline *timeline; ClutterAlpha *alpha; ClutterBehaviour *depth_behavior; int i; int row_height; #ifdef CLUTTER_WINDOWING_X11 clutter_set_windowing_backend (CLUTTER_WINDOWING_X11); #endif if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; #ifdef CLUTTER_WINDOWING_X11 if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11)) g_error ("test-pixmap requires the X11 Clutter backend."); #endif xdpy = clutter_x11_get_default_display (); XSynchronize (xdpy, True); context = g_option_context_new (" - test-pixmap options"); g_option_context_add_main_entries (context, g_options, NULL); g_option_context_parse (context, &argc, &argv, NULL); pixmap = create_pixmap (&w, &h, &d); screen = DefaultScreen(xdpy); win_remote = XCreateSimpleWindow (xdpy, DefaultRootWindow(xdpy), 0, 0, 200, 200, 0, WhitePixel(xdpy, screen), WhitePixel(xdpy, screen)); XMapWindow (xdpy, win_remote); stage = clutter_stage_new (); clutter_actor_set_position (stage, 0, 150); clutter_actor_set_background_color (stage, &gry); clutter_stage_set_title (CLUTTER_STAGE (stage), "X11 Texture from Pixmap"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); timeline = clutter_timeline_new (5000); g_signal_connect (timeline, "completed", G_CALLBACK (timeline_completed), NULL); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); depth_behavior = clutter_behaviour_depth_new (alpha, -2500, 400); if (!disable_x11) { group = clutter_group_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); label = clutter_text_new_with_text ("fixed", "ClutterX11Texture (Window)"); clutter_container_add_actor (CLUTTER_CONTAINER (group), label); tex = clutter_x11_texture_pixmap_new_with_window (win_remote); clutter_container_add_actor (CLUTTER_CONTAINER (group), tex); clutter_actor_set_position (tex, 0, 20); clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex), TRUE); clutter_texture_set_filter_quality (CLUTTER_TEXTURE (tex), CLUTTER_TEXTURE_QUALITY_HIGH); clutter_actor_set_position (group, 0, 0); if (!disable_animation) clutter_behaviour_apply (depth_behavior, group); } if (group) row_height = clutter_actor_get_height (group); else row_height = 0; /* NB: We only draw on the window after being redirected, so we dont * have to worry about handling expose events... */ gc = XCreateGC (xdpy, win_remote, 0, NULL); XSetForeground (xdpy, gc, BlackPixel (xdpy, screen)); XSetLineAttributes(xdpy, gc, 5, LineSolid, CapButt, JoinMiter); for (i = 0; i < 10; i++) XDrawLine (xdpy, win_remote, gc, 0+i*20, 0, 10+i*20+i, 200); group = clutter_group_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); label = clutter_text_new_with_text ("fixed", "ClutterX11Texture (Pixmap)"); clutter_container_add_actor (CLUTTER_CONTAINER (group), label); tex = clutter_x11_texture_pixmap_new_with_pixmap (pixmap); clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex), TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (group), tex); clutter_actor_set_position (tex, 0, 20); clutter_texture_set_filter_quality (CLUTTER_TEXTURE (tex), CLUTTER_TEXTURE_QUALITY_HIGH); /* oddly, the actor's size is 0 until it is realized, even though pixmap-height is set */ clutter_actor_set_position (group, 0, row_height); if (!disable_animation) clutter_behaviour_apply (depth_behavior, group); g_signal_connect (stage, "key-release-event", G_CALLBACK (stage_key_release_cb), (gpointer)pixmap); g_signal_connect (stage, "button-press-event", G_CALLBACK (stage_button_press_cb), (gpointer)pixmap); clutter_actor_show (stage); if (!disable_animation) clutter_timeline_start (timeline); clutter_threads_add_timeout (1000, draw_arc, GUINT_TO_POINTER (pixmap)); clutter_main (); return EXIT_SUCCESS; } G_MODULE_EXPORT const char * test_pixmap_describe (void) { return "GLX Texture from pixmap extension support."; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-scrolling.c���������������������������������������������0000664�0001750�0001750�00000010232�14211404421�023410� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> #define RECT_WIDTH 400 #define RECT_HEIGHT 300 #define N_RECTS 7 static const gchar *rect_color[N_RECTS] = { "#edd400", "#f57900", "#c17d11", "#73d216", "#3465a4", "#75507b", "#cc0000" }; static ClutterActor *rectangle[N_RECTS]; static ClutterActor *viewport = NULL; static void on_drag_end (ClutterDragAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y, ClutterModifierType modifiers) { gfloat viewport_x = clutter_actor_get_x (viewport); gfloat offset_x; gint child_visible; /* check if we're at the viewport edges */ if (viewport_x > 0) { clutter_actor_save_easing_state (viewport); clutter_actor_set_easing_mode (viewport, CLUTTER_EASE_OUT_BOUNCE); clutter_actor_set_x (viewport, 0); clutter_actor_restore_easing_state (viewport); return; } if (viewport_x < (-1.0f * (RECT_WIDTH * (N_RECTS - 1)))) { clutter_actor_save_easing_state (viewport); clutter_actor_set_easing_mode (viewport, CLUTTER_EASE_OUT_BOUNCE); clutter_actor_set_x (viewport, -1.0f * (RECT_WIDTH * (N_RECTS - 1))); clutter_actor_restore_easing_state (viewport); return; } /* animate the viewport to fully show the child once we pass * a certain threshold with the dragging action */ offset_x = fabsf (viewport_x) / RECT_WIDTH + 0.5f; if (offset_x > (RECT_WIDTH * 0.33)) child_visible = (int) offset_x + 1; else child_visible = (int) offset_x; /* sanity check on the children number */ child_visible = CLAMP (child_visible, 0, N_RECTS); clutter_actor_save_easing_state (viewport); clutter_actor_set_x (viewport, -1.0f * RECT_WIDTH * child_visible); clutter_actor_restore_easing_state (viewport); } G_MODULE_EXPORT int test_scrolling_main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *scroll; ClutterAction *action; gint i; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Scrolling"); clutter_actor_set_size (stage, 800, 600); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* scroll: the group that contains the scrolling viewport; we set its * size to be the same as one rectangle, position it in the middle of * the stage and set it to clip its contents to the allocated size */ scroll = clutter_actor_new (); clutter_actor_add_child (stage, scroll); clutter_actor_set_size (scroll, RECT_WIDTH, RECT_HEIGHT); clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5)); clutter_actor_set_clip_to_allocation (scroll, TRUE); /* viewport: the actual container for the children; we scroll it using * the Drag action constrained to the horizontal axis, and every time * the dragging ends we check whether we're dragging past the end of * the viewport */ viewport = clutter_actor_new (); clutter_actor_set_layout_manager (viewport, clutter_box_layout_new ()); clutter_actor_add_child (scroll, viewport); /* add dragging capabilities to the viewport; the heavy lifting is * all done by the DragAction itself, plus the ::drag-end signal * handler in our code */ action = clutter_drag_action_new (); clutter_actor_add_action (viewport, action); clutter_drag_action_set_drag_axis (CLUTTER_DRAG_ACTION (action), CLUTTER_DRAG_X_AXIS); g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL); clutter_actor_set_reactive (viewport, TRUE); /* children of the viewport */ for (i = 0; i < N_RECTS; i++) { ClutterColor color; clutter_color_from_string (&color, rect_color[i]); rectangle[i] = clutter_actor_new (); clutter_actor_set_background_color (rectangle[i], &color); clutter_actor_add_child (viewport, rectangle[i]); clutter_actor_set_size (rectangle[i], RECT_WIDTH, RECT_HEIGHT); } clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/wrapper.sh.in������������������������������������������������0000775�0001750�0001750�00000000605�14211404421�022722� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh UNIT_TEST=$1 shift echo "Running ./test-interactive $UNIT_TEST $@" echo "" echo "NOTE: For debugging purposes, you can run this single test as follows:" echo "$ libtool --mode=execute \\" echo " gdb --eval-command=\"b `echo $UNIT_TEST|tr '-' '_'`_main\" \\" echo " --args ./test-interactive $UNIT_TEST" @abs_builddir@/test-interactive $UNIT_TEST "$@" ���������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/interactive/test-grab.c��������������������������������������������������0000664�0001750�0001750�00000017100�14211404421�022330� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <gmodule.h> #include <clutter/clutter.h> static void stage_state_cb (ClutterStage *stage, gpointer data) { gchar *detail = (gchar*)data; printf("[stage signal] %s\n", detail); } static gboolean debug_event_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { gchar keybuf[9], *source = (gchar*)data; int len = 0; switch (event->type) { case CLUTTER_KEY_PRESS: len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval), keybuf); keybuf[len] = '\0'; printf ("[%s] KEY PRESS '%s'", source, keybuf); break; case CLUTTER_KEY_RELEASE: len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval), keybuf); keybuf[len] = '\0'; printf ("[%s] KEY RELEASE '%s'", source, keybuf); break; case CLUTTER_MOTION: printf("[%s] MOTION", source); break; case CLUTTER_ENTER: printf("[%s] ENTER", source); break; case CLUTTER_LEAVE: printf("[%s] LEAVE", source); break; case CLUTTER_BUTTON_PRESS: printf("[%s] BUTTON PRESS (click count:%i)", source, event->button.click_count); break; case CLUTTER_BUTTON_RELEASE: printf("[%s] BUTTON RELEASE", source); break; case CLUTTER_SCROLL: printf("[%s] BUTTON SCROLL", source); break; case CLUTTER_STAGE_STATE: printf("[%s] STAGE STATE", source); break; case CLUTTER_DESTROY_NOTIFY: printf("[%s] DESTROY NOTIFY", source); break; case CLUTTER_CLIENT_MESSAGE: printf("[%s] CLIENT MESSAGE\n", source); break; case CLUTTER_DELETE: printf("[%s] DELETE", source); break; case CLUTTER_NOTHING: return FALSE; } if (clutter_event_get_source (event) == actor) printf(" *source*"); printf("\n"); return FALSE; } static gboolean grab_pointer_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { clutter_grab_pointer (actor); return FALSE; } static gboolean red_release_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { clutter_ungrab_pointer (); return FALSE; } static gboolean blue_release_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { clutter_actor_destroy (actor); return FALSE; } static gboolean green_press_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterActor *stage; gboolean enabled; stage = clutter_actor_get_stage (actor); enabled = !clutter_stage_get_motion_events_enabled (CLUTTER_STAGE (stage)); clutter_stage_set_motion_events_enabled (CLUTTER_STAGE (stage), enabled); g_print ("per actor motion events are now %s\n", enabled ? "enabled" : "disabled"); return FALSE; } static gboolean toggle_grab_pointer_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { /* we only deal with the event if the source is ourself */ if (event->button.source == actor) { if (clutter_get_pointer_grab () != NULL) clutter_ungrab_pointer (); else clutter_grab_pointer (actor); } return FALSE; } static gboolean cyan_press_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { if (clutter_get_keyboard_grab () != NULL) clutter_ungrab_keyboard (); else clutter_grab_keyboard (actor); return FALSE; } G_MODULE_EXPORT int test_grab_main (int argc, char *argv[]) { ClutterActor *stage, *actor; ClutterColor rcol = { 0xff, 0, 0, 0xff}, bcol = { 0, 0, 0xff, 0xff }, gcol = { 0, 0xff, 0, 0xff }, ccol = { 0, 0xff, 0xff, 0xff }, ycol = { 0xff, 0xff, 0, 0xff }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; g_print ("Red box: aquire grab on press, releases it on next button release\n"); g_print ("Blue box: aquire grab on press, destroys the blue box actor on release\n"); g_print ("Yellow box: aquire grab on press, releases grab on next press on yellow box\n"); g_print ("Green box: toggle per actor motion events.\n\n"); g_print ("Cyan box: toggle grab (from cyan box) for keyboard events.\n\n"); stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Grabs"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "event", G_CALLBACK (debug_event_cb), "stage"); g_signal_connect (stage, "fullscreen", G_CALLBACK (stage_state_cb), "fullscreen"); g_signal_connect (stage, "unfullscreen", G_CALLBACK (stage_state_cb), "unfullscreen"); g_signal_connect (stage, "activate", G_CALLBACK (stage_state_cb), "activate"); g_signal_connect (stage, "deactivate", G_CALLBACK (stage_state_cb), "deactivate"); actor = clutter_rectangle_new_with_color (&rcol); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 100, 100); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (debug_event_cb), "red box"); g_signal_connect (actor, "button-press-event", G_CALLBACK (grab_pointer_cb), NULL); g_signal_connect (actor, "button-release-event", G_CALLBACK (red_release_cb), NULL); actor = clutter_rectangle_new_with_color (&ycol); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 100, 300); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (debug_event_cb), "yellow box"); g_signal_connect (actor, "button-press-event", G_CALLBACK (toggle_grab_pointer_cb), NULL); actor = clutter_rectangle_new_with_color (&bcol); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 300, 100); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (debug_event_cb), "blue box"); g_signal_connect (actor, "button-press-event", G_CALLBACK (grab_pointer_cb), NULL); g_signal_connect (actor, "button-release-event", G_CALLBACK (blue_release_cb), NULL); actor = clutter_rectangle_new_with_color (&gcol); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 300, 300); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (debug_event_cb), "green box"); g_signal_connect (actor, "button-press-event", G_CALLBACK (green_press_cb), NULL); actor = clutter_rectangle_new_with_color (&ccol); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 500, 100); clutter_actor_set_reactive (actor, TRUE); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL); g_signal_connect (actor, "event", G_CALLBACK (debug_event_cb), "cyan box"); g_signal_connect (actor, "button-press-event", G_CALLBACK (cyan_press_cb), NULL); clutter_actor_show_all (CLUTTER_ACTOR (stage)); clutter_main(); return 0; } G_MODULE_EXPORT const char * test_grab_describe (void) { return "Examples of using actor grabs"; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/clutter-1.0.suppressions�������������������������������������������������0000664�0001750�0001750�00000004012�14211404421�022432� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ioctl_1 Memcheck:Param ioctl(generic) fun:ioctl fun:driDrawableInitVBlank fun:intelMakeCurrent fun:glXMakeContextCurrent } { ioctl_2 Memcheck:Param ioctl(generic) fun:ioctl fun:driDrawableGetMSC32 fun:clutter_backend_glx_redraw } { ioctl_3 Memcheck:Param ioctl(generic) fun:ioctl fun:driWaitForMSC32 fun:clutter_backend_glx_redraw } { mesa_init_context Memcheck:Leak fun:*alloc ... fun:glXCreateNewContext } { type_register Memcheck:Leak fun:*alloc ... fun:g_type_register_* } { type_ref Memcheck:Leak fun:*alloc ... fun:g_type_class_ref } { type_interface_prereq Memcheck:Leak fun:*alloc ... fun:g_type_interface_add_prerequisite } { get_charset Memcheck:Leak fun:*alloc ... fun:g_get_charset } { cogl_features Memcheck:Leak fun:*alloc ... fun:cogl_get_features } { glx_query_version Memcheck:Leak fun:*alloc ... fun:glXQueryVersion } { glx_create_context Memcheck:Leak fun:*alloc ... fun:glXCreateNewContext } { glx_make_current Memcheck:Leak fun:*alloc ... fun:glXMakeContextCurrent } { gl_draw_arrays Memcheck:Leak fun:*malloc ... fun:glDrawArrays } { cogl_clear Memcheck:Leak fun:*alloc ... fun:cogl_clear } { default_font Memcheck:Leak fun:*alloc ... fun:clutter_backend_get_font_name } { id_pool Memcheck:Leak fun:*alloc ... fun:clutter_id_pool_new } { x_open_display Memcheck:Leak fun:*alloc ... fun:XOpenDisplay } # ... and font descriptions from every "sans 12" type string { pango_font_description_from_string Memcheck:Leak fun:*alloc ... fun:pango_font_description_from_string } # other lib init { fontconfig_init Memcheck:Leak fun:*alloc ... fun:FcConfigParseAndLoad } { freetype_init Memcheck:Leak fun:*alloc ... fun:FT_Open_Face } { x_init_ext Memcheck:Leak fun:*alloc ... fun:XInitExtension } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/�������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�020261� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/test-state-interactive.c�������������������������������������0000664�0001750�0001750�00000015027�14211404421�025042� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> #include "test-common.h" #define STAGE_WIDTH 800 #define STAGE_HEIGHT 600 #define ACTOR_WIDTH 64 #define ACTOR_HEIGHT 64 #define COLS (STAGE_WIDTH/ACTOR_WIDTH) #define ROWS (STAGE_HEIGHT/ACTOR_HEIGHT) #define TOTAL (ROWS*COLS) static gboolean press_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "right"); return TRUE; } static gboolean release_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "active"); return TRUE; } static gboolean enter_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "hover"); return TRUE; } static gboolean leave_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterState *state = CLUTTER_STATE (user_data); clutter_state_set_state (state, "normal"); return TRUE; } static void completed (ClutterState *state, gpointer data) { g_print ("Completed transitioning to state: %s\n", clutter_state_get_state (state)); if (g_str_equal (clutter_state_get_state (state), "right")) { /* skip straight to left state when reaching right */ clutter_state_warp_to_state (state, "left"); } } static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { GError *error = NULL; ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *group = clutter_group_new (); ClutterActor *rectangle = clutter_rectangle_new_with_color (color); ClutterActor *hand = NULL; gchar *file = g_build_filename (TESTS_DATA_DIR, "redhand.png", NULL); hand = clutter_texture_new_from_file (file, &error); if (rectangle == NULL) g_error ("image load failed: %s", error->message); free (file); clutter_actor_set_size (hand, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_actor_set_size (rectangle, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_color_free (color); clutter_container_add (CLUTTER_CONTAINER (group), rectangle, hand, NULL); return group; } gint main (gint argc, gchar **argv) { ClutterActor *stage; ClutterState *layout_state; gint i; clutter_perf_fps_init (); if (CLUTTER_INIT_SUCCESS != clutter_init (&argc, &argv)) g_error ("Failed to initialize Clutter"); stage = clutter_stage_new (); layout_state = clutter_state_new (); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "State Performance [interactive]"); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); g_signal_connect (stage, "button-press-event", G_CALLBACK (press_event), layout_state); g_signal_connect (stage, "button-release-event", G_CALLBACK (release_event), layout_state); for (i=0; i<TOTAL; i++) { ClutterActor *actor; ClutterState *a_state; int row = i/COLS; int col = i%COLS; actor = new_rect (255 * ( 1.0*col/COLS), 50, 255 * ( 1.0*row/ROWS), 255); clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor); clutter_actor_set_position (actor, 320.0, 240.0); clutter_actor_set_reactive (actor, TRUE); clutter_state_set (layout_state, NULL, "active", actor, "delayed::x", CLUTTER_LINEAR, ACTOR_WIDTH * 1.0 * ((TOTAL-1-i) % COLS), ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, ACTOR_HEIGHT * 1.0 * ((TOTAL-1-i) / COLS), ((row*1.0/ROWS))/2, 0.0, actor, "rotation-angle-x", CLUTTER_LINEAR, 0.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (layout_state, NULL, "right", actor, "delayed::x", CLUTTER_LINEAR, STAGE_WIDTH * 1.0, ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, STAGE_HEIGHT * 1.0, ((row*1.0/ROWS))/2, 0.0, NULL); clutter_state_set (layout_state, NULL, "left", actor, "rotation-angle-x", CLUTTER_LINEAR, 45.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 5.0, actor, "x", CLUTTER_LINEAR, 0-64.0, actor, "y", CLUTTER_LINEAR, 0-64.0, NULL); a_state = clutter_state_new (); g_object_set_data_full (G_OBJECT (actor), "hover-state-machine", a_state, g_object_unref); g_signal_connect (actor, "enter-event", G_CALLBACK (enter_event), a_state); g_signal_connect (actor, "leave-event", G_CALLBACK (leave_event), a_state); clutter_state_set (a_state, NULL, "normal", actor, "opacity", CLUTTER_LINEAR, 0x77, actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (a_state, NULL, "hover", actor, "opacity", CLUTTER_LINEAR, 0xff, actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0, NULL); clutter_actor_set_opacity (actor, 0x77); clutter_state_set_duration (a_state, NULL, NULL, 500); } clutter_state_set_duration (layout_state, NULL, NULL, 1000); clutter_state_set_duration (layout_state, "active", "left", 1400); g_signal_connect (layout_state, "completed", G_CALLBACK (completed), NULL); clutter_actor_show (stage); clutter_state_warp_to_state (layout_state, "left"); clutter_state_set_state (layout_state, "active"); clutter_perf_fake_mouse (CLUTTER_STAGE (stage)); clutter_perf_fps_start (CLUTTER_STAGE (stage)); clutter_main (); clutter_perf_fps_report ("test-state-interactive"); g_object_unref (layout_state); return EXIT_SUCCESS; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/Makefile.am��������������������������������������������������0000664�0001750�0001750�00000002313�14211404421�022314� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������check_PROGRAMS = \ test-picking \ test-text-perf \ test-state \ test-state-interactive \ test-state-hidden \ test-state-mini \ test-state-pick common_ldadd = $(top_builddir)/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la LDADD = $(common_ldadd) $(CLUTTER_LIBS) $(LIBM) AM_CFLAGS = $(CLUTTER_CFLAGS) AM_CPPFLAGS = \ -DG_DISABLE_SINGLE_INCLUDES \ -DGLIB_DISABLE_DEPRECATION_WARNINGS \ -DCOGL_DISABLE_DEPRECATION_WARNINGS \ -DCLUTTER_DISABLE_DEPRECATION_WARNINGS \ -DTESTS_DATA_DIR=\""$(top_srcdir)/tests/data/"\" \ -I$(top_srcdir)/../cogl \ -I$(top_builddir)/../cogl \ -I$(top_builddir)/../cogl/cogl \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(top_srcdir)/clutter \ -I$(top_builddir)/clutter perf-report: check check: for a in $(noinst_PROGRAMS);do ./$$a;done;true test_picking_SOURCES = test-picking.c test_text_perf_SOURCES = test-text-perf.c test_state_SOURCES = test-state.c test_state_hidden_SOURCES = test-state-hidden.c test_state_pick_SOURCES = test-state-pick.c test_state_interactive_SOURCES = test-state-interactive.c test_state_mini_SOURCES = test-state-mini.c EXTRA_DIST = Makefile-retrospect Makefile-tests create-report.rb test-common.h ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/test-state.c�������������������������������������������������0000664�0001750�0001750�00000012314�14211404421�022523� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> #include "test-common.h" static gint times = 16; #define STAGE_WIDTH 800 #define STAGE_HEIGHT 600 #define ACTOR_WIDTH 64 #define ACTOR_HEIGHT 64 #define COLS (STAGE_WIDTH/ACTOR_WIDTH) #define ROWS (STAGE_HEIGHT/ACTOR_HEIGHT) #define TOTAL (ROWS*COLS) static void completed (ClutterState *state, gpointer data) { if (g_str_equal (clutter_state_get_state (state), "right")) { /* skip straight to left state when reaching right */ clutter_state_warp_to_state (state, "left"); } else if (g_str_equal (clutter_state_get_state (state), "active")) clutter_state_set_state (state, "right"); else { clutter_state_set_state (state, "active"); } times --; if (times <=0) clutter_main_quit (); } static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { GError *error = NULL; ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *group = clutter_group_new (); ClutterActor *rectangle = clutter_rectangle_new_with_color (color); ClutterActor *hand = NULL; gchar *file = g_build_filename (TESTS_DATA_DIR, "redhand.png", NULL); hand = clutter_texture_new_from_file (file, &error); if (rectangle == NULL) g_error ("image load failed: %s", error->message); free (file); clutter_actor_set_size (hand, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_actor_set_size (rectangle, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_color_free (color); clutter_container_add (CLUTTER_CONTAINER (group), rectangle, hand, NULL); return group; } gint main (gint argc, gchar **argv) { ClutterActor *stage; ClutterState *layout_state; gint i; clutter_perf_fps_init (); if (CLUTTER_INIT_SUCCESS != clutter_init (&argc, &argv)) g_error ("Failed to initialize Clutter"); stage = clutter_stage_new (); layout_state = clutter_state_new (); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "State Performance"); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); for (i=0; i<TOTAL; i++) { ClutterActor *actor; ClutterState *a_state; int row = i/COLS; int col = i%COLS; actor = new_rect (255 * ( 1.0*col/COLS), 50, 255 * ( 1.0*row/ROWS), 255); clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor); clutter_actor_set_position (actor, 320.0, 240.0); clutter_actor_set_reactive (actor, TRUE); clutter_state_set (layout_state, NULL, "active", actor, "delayed::x", CLUTTER_LINEAR, ACTOR_WIDTH * 1.0 * ((TOTAL-1-i) % COLS), ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, ACTOR_HEIGHT * 1.0 * ((TOTAL-1-i) / COLS), ((row*1.0/ROWS))/2, 0.0, actor, "rotation-angle-x", CLUTTER_LINEAR, 0.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (layout_state, NULL, "right", actor, "delayed::x", CLUTTER_LINEAR, STAGE_WIDTH * 1.0, ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, STAGE_HEIGHT * 1.0, ((row*1.0/ROWS))/2, 0.0, NULL); clutter_state_set (layout_state, NULL, "left", actor, "rotation-angle-x", CLUTTER_LINEAR, 45.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 5.0, actor, "x", CLUTTER_LINEAR, 0-64.0, actor, "y", CLUTTER_LINEAR, 0-64.0, NULL); a_state = clutter_state_new (); g_object_set_data_full (G_OBJECT (actor), "hover-state-machine", a_state, g_object_unref); clutter_state_set (a_state, NULL, "normal", actor, "opacity", CLUTTER_LINEAR, 0x77, actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (a_state, NULL, "hover", actor, "opacity", CLUTTER_LINEAR, 0xff, actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0, NULL); clutter_actor_set_opacity (actor, 0x77); clutter_state_set_duration (a_state, NULL, NULL, 500); } clutter_state_set_duration (layout_state, NULL, NULL, 1000); clutter_state_set_duration (layout_state, "active", "left", 1400); g_signal_connect (layout_state, "completed", G_CALLBACK (completed), NULL); clutter_actor_show (stage); clutter_state_warp_to_state (layout_state, "left"); clutter_state_set_state (layout_state, "active"); clutter_perf_fps_start (CLUTTER_STAGE (stage)); clutter_main (); clutter_perf_fps_report ("test-state"); g_object_unref (layout_state); return EXIT_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/Makefile-retrospect������������������������������������������0000664�0001750�0001750�00000003611�14211404421�024112� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# A makefile based framework for testing performance commits in retrospect, # based on work done by pippin@gimp.org done for GEGL, original code placed in the public domain. SELF = Makefile-retrospect MAKE_FLAGS = -j3 -k CC = "ccache gcc" # if you do not have ccache replace with just gcc PROJECT_PATH = ../../ # mute makes echoing of commands .SILENT: # replace sequential with random to build a random subset all: reset sequential #all: reset random retry: rm -rf reports/`cat jobs | tail -n1`* make -f $(SELF) prepare: # uncomment these to make sure cpu is in high performance mode #sudo sh -c 'echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor || true' #sudo sh -c 'echo performance > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor || true' reset: rm -rf jobs jobs # remove checkout dir to have a full reset on each invokation rm -rf checkout # create clone git clone -s $(PROJECT_PATH) checkout mkdir reports > /dev/null 2>&1 || true make -f $(SELF) jobs make -f $(SELF) prepare jobs: joblist ./makejobs.rb joblist > jobs sequential: for a in `cat jobs`;do make -f $(SELF) reports/$$a;done random: for a in `cat jobs|sort`;do make -f $(SELF) reports/$$a;done reports/%: # check out revision (cd checkout; git checkout `echo $@|sed s:reports/::`) # write header for report git log -1 `echo $@|sed s:reports/::` > $@ || true # clean previous build rm -rf install; mkdir install # build revision (cd checkout; if [ ! -f Makefile ]; then CC=$(CC) ./autogen.sh --disable-introspection --prefix=`pwd`/../install; fi ; \ make $(MAKE_FLAGS) ; make -k install ) > $@.log 2>&1 || true # testing make -f Makefile-tests clean;\ make -f Makefile-tests; sync;\ make -f Makefile-tests check >> $@ || true # update report.pdf / report.png ./create-report.rb echo clean: rm -rf reports jobs report.pdf report.png checkout install make -f Makefile-tests clean �����������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/test-state-hidden.c������������������������������������������0000664�0001750�0001750�00000012055�14211404421�023756� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> #include "test-common.h" #define STAGE_WIDTH 160 #define STAGE_HEIGHT 120 #define ACTOR_WIDTH 8 #define ACTOR_HEIGHT 8 #define COLS (STAGE_WIDTH/ACTOR_WIDTH) #define ROWS (STAGE_HEIGHT/ACTOR_HEIGHT) #define TOTAL (ROWS*COLS) static void completed (ClutterState *state, gpointer data) { if (g_str_equal (clutter_state_get_state (state), "right")) { /* skip straight to left state when reaching right */ clutter_state_warp_to_state (state, "left"); } else if (g_str_equal (clutter_state_get_state (state), "active")) clutter_state_set_state (state, "right"); else { clutter_state_set_state (state, "active"); } } static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *group = clutter_group_new (); ClutterActor *rectangle = clutter_rectangle_new_with_color (color); gchar *file = g_build_filename (TESTS_DATA_DIR, "redhand.png", NULL); free (file); clutter_actor_set_size (rectangle, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_color_free (color); clutter_container_add (CLUTTER_CONTAINER (group), rectangle, NULL); return group; } gint main (gint argc, gchar **argv) { ClutterActor *stage; ClutterActor *group; ClutterState *layout_state; gint i; clutter_perf_fps_init (); if (CLUTTER_INIT_SUCCESS != clutter_init (&argc, &argv)) g_error ("Failed to initialize Clutter"); stage = clutter_stage_new (); group = clutter_group_new (); layout_state = clutter_state_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "State Performance [hidden]"); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); for (i=0; i<TOTAL; i++) { ClutterActor *actor; ClutterState *a_state; int row = i/COLS; int col = i%COLS; actor = new_rect (255 * ( 1.0*col/COLS), 50, 255 * ( 1.0*row/ROWS), 255); clutter_container_add_actor (CLUTTER_CONTAINER (group), actor); clutter_actor_set_position (actor, 320.0, 240.0); clutter_actor_set_reactive (actor, TRUE); clutter_state_set (layout_state, NULL, "active", actor, "delayed::x", CLUTTER_LINEAR, ACTOR_WIDTH * 1.0 * ((TOTAL-1-i) % COLS), ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, ACTOR_HEIGHT * 1.0 * ((TOTAL-1-i) / COLS), ((row*1.0/ROWS))/2, 0.0, actor, "rotation-angle-x", CLUTTER_LINEAR, 0.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (layout_state, NULL, "right", actor, "delayed::x", CLUTTER_LINEAR, STAGE_WIDTH * 1.0, ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, STAGE_HEIGHT * 1.0, ((row*1.0/ROWS))/2, 0.0, NULL); clutter_state_set (layout_state, NULL, "left", actor, "rotation-angle-x", CLUTTER_LINEAR, 45.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 5.0, actor, "x", CLUTTER_LINEAR, 0-64.0, actor, "y", CLUTTER_LINEAR, 0-64.0, NULL); a_state = clutter_state_new (); g_object_set_data_full (G_OBJECT (actor), "hover-state-machine", a_state, g_object_unref); clutter_state_set (a_state, NULL, "normal", actor, "opacity", CLUTTER_LINEAR, 0x77, actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (a_state, NULL, "hover", actor, "opacity", CLUTTER_LINEAR, 0xff, actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0, NULL); clutter_actor_set_opacity (actor, 0x77); clutter_state_set_duration (a_state, NULL, NULL, 500); } clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); clutter_actor_set_opacity (group, 0); clutter_state_set_duration (layout_state, NULL, NULL, 1000); clutter_state_set_duration (layout_state, "active", "left", 1400); g_signal_connect (layout_state, "completed", G_CALLBACK (completed), NULL); clutter_actor_show (stage); clutter_state_warp_to_state (layout_state, "left"); clutter_state_set_state (layout_state, "active"); clutter_perf_fps_start (CLUTTER_STAGE (stage)); clutter_main (); clutter_perf_fps_report ("test-state-hidden"); g_object_unref (layout_state); return EXIT_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/makejobs.rb��������������������������������������������������0000775�0001750�0001750�00000001120�14211404421�022376� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env ruby # this ruby script generates a chronologically sorted res = "" input = File.read(ARGV[0]) input = input.gsub(/#.*/, "") input.split("\n").each {|a| if a =~ /([^ ]*)\.\.([^ ]*) %(.*)/ res += `git log #{$1}..#{$2} | grep '^commit' | sed 's/commit //' | sed -n '0~#{$3}p'` elsif a =~ /([^ ]*)\.\.([^ ]*)/ res += `git log #{$1}..#{$2} | grep '^commit' | sed 's/commit //'` else res += `echo #{a}` end } all = `git log | grep '^commit' | sed 's/commit//' ` all.split("\n").reverse.each {|a| if res.match(a.strip) != nil puts "#{a.strip}" end } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/Makefile-tests�����������������������������������������������0000664�0001750�0001750�00000000553�14211404421�023064� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������CFILES = $(wildcard *.c) bins = $(subst ,,$(CFILES:.c=)) all: $(bins) %: %.c PKG_CONFIG_PATH=install/lib/pkgconfig:$(PKG_CONFIG_PATH) $(CC) -DTESTS_DATA_DIR=\"../data/\" `pkg-config clutter-1.0 --cflags --libs` -Wall -O2 -o $@ $< check: $(bins) for a in $(bins); do \ LD_LIBRARY_PATH=install/lib:$(LD_LIBRARY_PATH) ./$$a;\ done clean: rm -f $(bins) �����������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/joblist������������������������������������������������������0000664�0001750�0001750�00000001546�14211404421�021660� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This file lists the commits that we want to do retrospective testing # of, aborting the retrospective testing and adjusting this file will # add the commit range to be tested without having to redo the initial one # thus allowing a sparse distributed range to first be tested, with # detailed ranges added in later. master~500..master % 32 # every 32th commit, to provide context # various spans of commits around which "interesting things happen" #eeac7~1..985a4 #6c6e93d~1..3142b15 #0486c56..88b026 #732eecf..8cfb158 #b499696..b77d9a6 #ba09e9c..7bdbbe6 #b424bd7..c1878 #bc58de4..d03c3a6 #5640a6..a29623e #6fd2663..6ec9c32 # 012e4ab..1a8d577 # #120d759~4..2235e70 # ef8be9e25ebe77fc63055191cc48af53d731c108 - actor: Use paint volumes to always queue clipped redraws # 5d16000 going up, and 3b78949 going down,. was a case of clipped redraws being broken ����������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/.gitignore���������������������������������������������������0000664�0001750�0001750�00000000167�14211404421�022255� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/test-picking /test-state /test-state-hidden /test-state-interactive /test-state-mini /test-state-pick /test-text-perf ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/test-common.h������������������������������������������������0000664�0001750�0001750�00000006727�14211404421�022713� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <clutter/clutter.h> static GTimer *testtimer = NULL; static gint testframes = 0; static float testmaxtime = 1.0; /* initialize environment to be suitable for fps testing */ void clutter_perf_fps_init (void) { /* Force not syncing to vblank, we want free-running maximum FPS */ g_setenv ("vblank_mode", "0", FALSE); g_setenv ("CLUTTER_VBLANK", "none", FALSE); /* also overrride internal default FPS */ g_setenv ("CLUTTER_DEFAULT_FPS", "1000", FALSE); if (g_getenv ("CLUTTER_PERFORMANCE_TEST_DURATION")) testmaxtime = atof(g_getenv("CLUTTER_PERFORMANCE_TEST_DURATION")); else testmaxtime = 10.0; g_random_set_seed (12345678); } static void perf_stage_paint_cb (ClutterStage *stage, gpointer *data); static gboolean perf_fake_mouse_cb (gpointer stage); void clutter_perf_fps_start (ClutterStage *stage) { g_signal_connect (stage, "paint", G_CALLBACK (perf_stage_paint_cb), NULL); } void clutter_perf_fake_mouse (ClutterStage *stage) { clutter_threads_add_timeout (1000/60, perf_fake_mouse_cb, stage); } void clutter_perf_fps_report (const gchar *id) { g_print ("\n@ %s: %.2f fps \n", id, testframes / g_timer_elapsed (testtimer, NULL)); } static void perf_stage_paint_cb (ClutterStage *stage, gpointer *data) { if (!testtimer) testtimer = g_timer_new (); testframes ++; if (g_timer_elapsed (testtimer, NULL) > testmaxtime) { clutter_main_quit (); } } static void wrap (gfloat *value, gfloat min, gfloat max) { if (*value > max) *value = min; else if (*value < min) *value = max; } static gboolean perf_fake_mouse_cb (gpointer stage) { ClutterEvent *event = clutter_event_new (CLUTTER_MOTION); static ClutterInputDevice *device = NULL; int i; static float x = 0.0; static float y = 0.0; static float xd = 0.0; static float yd = 0.0; static gboolean inited = FALSE; gfloat w, h; if (!inited) /* XXX: force clutter to do handle our motion events, by forcibly updating the input device's state this shoudl be possible to do in a better manner in the future, a versioning check will have to be added when this is possible without a hack... and the means to do the hack is deprecated */ { ClutterEvent *event2 = clutter_event_new (CLUTTER_ENTER); device = clutter_device_manager_get_core_device (clutter_device_manager_get_default (), CLUTTER_POINTER_DEVICE); event2->crossing.stage = stage; event2->crossing.source = stage; event2->crossing.x = 10; event2->crossing.y = 10; event2->crossing.device = device; event2->crossing.related = NULL; clutter_input_device_update_from_event (device, event2, TRUE); clutter_event_put (event2); clutter_event_free (event2); inited = TRUE; } clutter_actor_get_size (stage, &w, &h); event->motion.stage = stage; event->motion.device = device; /* called about every 60fps, and do 10 picks per stage */ for (i = 0; i < 10; i++) { event->motion.x = x; event->motion.y = y; clutter_event_put (event); x += xd; y += yd; xd += g_random_double_range (-0.1, 0.1); yd += g_random_double_range (-0.1, 0.1); wrap (&x, 0, w); wrap (&y, 0, h); xd = CLAMP(xd, -1.3, 1.3); yd = CLAMP(yd, -1.3, 1.3); } clutter_event_free (event); return G_SOURCE_CONTINUE; } �����������������������������������������muffin-5.2.1/clutter/tests/performance/test-state-pick.c��������������������������������������������0000664�0001750�0001750�00000012413�14211404421�023447� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> #include "test-common.h" static gint times = 16; #define STAGE_WIDTH 800 #define STAGE_HEIGHT 600 #define ACTOR_WIDTH 64 #define ACTOR_HEIGHT 64 #define COLS (STAGE_WIDTH/ACTOR_WIDTH) #define ROWS (STAGE_HEIGHT/ACTOR_HEIGHT) #define TOTAL (ROWS*COLS) static void completed (ClutterState *state, gpointer data) { if (g_str_equal (clutter_state_get_state (state), "right")) { /* skip straight to left state when reaching right */ clutter_state_warp_to_state (state, "left"); } else if (g_str_equal (clutter_state_get_state (state), "active")) clutter_state_set_state (state, "right"); else { clutter_state_set_state (state, "active"); } times --; if (times <=0) clutter_main_quit (); } static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { GError *error = NULL; ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *group = clutter_group_new (); ClutterActor *rectangle = clutter_rectangle_new_with_color (color); ClutterActor *hand = NULL; gchar *file = g_build_filename (TESTS_DATA_DIR, "redhand.png", NULL); hand = clutter_texture_new_from_file (file, &error); if (rectangle == NULL) g_error ("image load failed: %s", error->message); free (file); clutter_actor_set_size (hand, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_actor_set_size (rectangle, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_color_free (color); clutter_container_add (CLUTTER_CONTAINER (group), rectangle, hand, NULL); return group; } gint main (gint argc, gchar **argv) { ClutterActor *stage; ClutterState *layout_state; gint i; clutter_perf_fps_init (); if (CLUTTER_INIT_SUCCESS != clutter_init (&argc, &argv)) g_error ("Failed to initialize Clutter"); stage = clutter_stage_new (); layout_state = clutter_state_new (); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "State Performance [pick]"); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); for (i=0; i<TOTAL; i++) { ClutterActor *actor; ClutterState *a_state; int row = i/COLS; int col = i%COLS; actor = new_rect (255 * ( 1.0*col/COLS), 50, 255 * ( 1.0*row/ROWS), 255); clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor); clutter_actor_set_position (actor, 320.0, 240.0); clutter_actor_set_reactive (actor, TRUE); clutter_state_set (layout_state, NULL, "active", actor, "delayed::x", CLUTTER_LINEAR, ACTOR_WIDTH * 1.0 * ((TOTAL-1-i) % COLS), ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, ACTOR_HEIGHT * 1.0 * ((TOTAL-1-i) / COLS), ((row*1.0/ROWS))/2, 0.0, actor, "rotation-angle-x", CLUTTER_LINEAR, 0.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (layout_state, NULL, "right", actor, "delayed::x", CLUTTER_LINEAR, STAGE_WIDTH * 1.0, ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, STAGE_HEIGHT * 1.0, ((row*1.0/ROWS))/2, 0.0, NULL); clutter_state_set (layout_state, NULL, "left", actor, "rotation-angle-x", CLUTTER_LINEAR, 45.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 5.0, actor, "x", CLUTTER_LINEAR, 0-64.0, actor, "y", CLUTTER_LINEAR, 0-64.0, NULL); a_state = clutter_state_new (); g_object_set_data_full (G_OBJECT (actor), "hover-state-machine", a_state, g_object_unref); clutter_state_set (a_state, NULL, "normal", actor, "opacity", CLUTTER_LINEAR, 0x77, actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (a_state, NULL, "hover", actor, "opacity", CLUTTER_LINEAR, 0xff, actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0, NULL); clutter_actor_set_opacity (actor, 0x77); clutter_state_set_duration (a_state, NULL, NULL, 500); } clutter_state_set_duration (layout_state, NULL, NULL, 1000); clutter_state_set_duration (layout_state, "active", "left", 1400); g_signal_connect (layout_state, "completed", G_CALLBACK (completed), NULL); clutter_actor_show (stage); clutter_state_warp_to_state (layout_state, "left"); clutter_state_set_state (layout_state, "active"); clutter_perf_fake_mouse (CLUTTER_STAGE (stage)); clutter_perf_fps_start (CLUTTER_STAGE (stage)); clutter_main (); clutter_perf_fps_report ("test-state-pick"); g_object_unref (layout_state); return EXIT_SUCCESS; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/test-picking.c�����������������������������������������������0000664�0001750�0001750�00000007124�14211404421�023032� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <math.h> #include <stdlib.h> #include <clutter/clutter.h> #include "test-common.h" #define N_ACTORS 100 #define N_EVENTS 5 static gint n_actors = N_ACTORS; static gint n_events = N_EVENTS; static GOptionEntry entries[] = { { "num-actors", 'a', 0, G_OPTION_ARG_INT, &n_actors, "Number of actors", "ACTORS" }, { "num-events", 'e', 0, G_OPTION_ARG_INT, &n_events, "Number of events", "EVENTS" }, { NULL } }; static gboolean motion_event_cb (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { return FALSE; } static void do_events (ClutterActor *stage) { glong i; static gdouble angle = 0; for (i = 0; i < n_events; i++) { angle += (2.0 * G_PI) / (gdouble)n_actors; while (angle > G_PI * 2.0) angle -= G_PI * 2.0; /* If we synthesized events, they would be motion compressed; * calling get_actor_at_position() doesn't have that problem */ clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage), CLUTTER_PICK_REACTIVE, 256.0 + 206.0 * cos (angle), 256.0 + 206.0 * sin (angle)); } } static gboolean queue_redraw (gpointer data) { ClutterActor *stage = CLUTTER_ACTOR (data); clutter_actor_queue_redraw (stage); do_events (stage); return TRUE; } int main (int argc, char **argv) { glong i; gdouble angle; ClutterColor color = { 0x00, 0x00, 0x00, 0xff }; ClutterActor *stage, *rect; clutter_perf_fps_init (); if (CLUTTER_INIT_SUCCESS != clutter_init_with_args (&argc, &argv, NULL, entries, NULL, NULL)) { g_warning ("Failed to initialize clutter"); return -1; } stage = clutter_stage_new (); clutter_actor_set_size (stage, 512, 512); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "Picking Performance"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); printf ("Picking performance test with " "%d actors and %d events per frame\n", n_actors, n_events); for (i = n_actors - 1; i >= 0; i--) { angle = ((2.0 * G_PI) / (gdouble) n_actors) * i; color.red = (1.0 - ABS ((MAX (0, MIN (n_actors/2.0 + 0, i))) / (gdouble)(n_actors/4.0) - 1.0)) * 255.0; color.green = (1.0 - ABS ((MAX (0, MIN (n_actors/2.0 + 0, fmod (i + (n_actors/3.0)*2, n_actors)))) / (gdouble)(n_actors/4) - 1.0)) * 255.0; color.blue = (1.0 - ABS ((MAX (0, MIN (n_actors/2.0 + 0, fmod ((i + (n_actors/3.0)), n_actors)))) / (gdouble)(n_actors/4.0) - 1.0)) * 255.0; rect = clutter_rectangle_new_with_color (&color); clutter_actor_set_size (rect, 100, 100); clutter_actor_set_anchor_point_from_gravity (rect, CLUTTER_GRAVITY_CENTER); clutter_actor_set_position (rect, 256 + 206 * cos (angle), 256 + 206 * sin (angle)); clutter_actor_set_reactive (rect, TRUE); g_signal_connect (rect, "motion-event", G_CALLBACK (motion_event_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); } clutter_actor_show (stage); clutter_perf_fps_start (CLUTTER_STAGE (stage)); clutter_threads_add_idle (queue_redraw, stage); clutter_main (); clutter_perf_fps_report ("test-picking"); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/create-report.rb���������������������������������������������0000775�0001750�0001750�00000010634�14211404421�023371� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env ruby # # ruby program to generate a performance report in PDF/png over git revisions, based on work # originally done for gegl by pippin@gimp.org, the original program is in the public domain. require 'cairo' def cairo_surface(w,h) surface = Cairo::PDFSurface.new("report.pdf", w,h) cr = Cairo::Context.new(surface) yield(cr) end class Database def initialize() @vals = Hash.new @runs = Array.new @colors = [ [0,1,0, 0.8], [0,1,1, 0.8], [1,0,0, 0.8], [1,0,1, 0.8], [1,1,0, 0.8], #[0.5,0.5,0.5,0.8], # gray doesnt have sufficient contrast against background [0.5,0.5,1, 0.8], [0.5,1,0.5, 0.8], [0.5,1,1, 0.8], [1,0.5,0.5, 0.8], [1,0.5,1, 0.8], [1,1,0.5, 0.8], [1,1,1, 0.8], ] @width = 1800 @height = 500 @marginlx = 10 @marginrx = 180 @rgap = 40 @marginy = 10 end def val_max(key) max=0 @runs.each { |run| val = @vals[key][run] if val and val > max max = val end } max end def val_min(key) min=9999990 @runs.each { |run| val = @vals[key][run] min = val if val and val < min } #min 0 # this shows the relative noise in measurements better end def add_run(run) @runs = @runs + [run] end def add_entry(run, name, val) if !@vals[name] @vals[name]=Hash.new end # check if there is an existing value, # and perhaps have different behaviors # associated with @vals[name][run] = val.to_f end def drawbg cr cr.set_source_rgba(0.2, 0.2, 0.2, 1) cr.paint i=0 @runs.each { |run| if i % 2 == 1 cr.move_to 1.0 * i / @runs.length * (@width - @marginlx-@marginrx) + @marginlx, 0 * (@height - @marginy*2) + @marginy cr.line_to 1.0 * i / @runs.length * (@width - @marginlx-@marginrx) + @marginlx, 1.0 * (@height - @marginy*2) + @marginy cr.rel_line_to(1.0 / @runs.length * (@width - @marginlx-@marginrx), 0) cr.rel_line_to(0, -(@height - @marginy*2)) cr.set_source_rgba([0.25,0.25,0.25,1]) cr.fill end i+=1 } end def drawtext cr i = 0 @runs.each { |run| y = i * 10 + 20 while y > @height - @marginy y = y - @height + @marginy + 10 end cr.move_to 1.0 * i / @runs.length * (@width - @marginlx-@marginrx) + @marginlx, y cr.set_source_rgba(0.6,0.6,0.6,1) cr.show_text(run[0..6]) i+=1 } end def draw_limits cr, key cr.move_to @width - @marginrx + @rgap, 20 cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) cr.show_text(" #{val_max(key)} ") cr.move_to @width - @marginrx + @rgap, @height - @marginy cr.show_text(" #{val_min(key)} ") end def draw_val cr, key, valno min = val_min(key) max = val_max(key) cr.set_source_rgba(@colors[valno]) cr.move_to(@width - @marginrx + @rgap, valno * 14 + @marginy + 20) cr.show_text(key) cr.line_width = 2 cr.new_path i = 0 @runs.each { |run| val = @vals[key][run] if val cr.line_to 1.0 * (i+0.5) / @runs.length * (@width - @marginlx-@marginrx) + @marginlx, (1.0 - ((val-min) * 1.0 / (max - min))) * (@height - @marginy*2) + @marginy end i = i + 1 } cr.stroke end def create_report cairo_surface(@width, @height) { |cr| drawbg cr valno = 0 @vals.each { |key, value| draw_val cr, key, valno valno += 1 } drawtext cr cr.target.write_to_png("report.png") valno = 0 @vals.each { |key, value| cr.show_page drawbg cr draw_val cr, key, valno drawtext cr draw_limits cr, key valno += 1 } } end end generator = Database.new items = File.open('jobs').each { |rev| rev.strip! generator.add_run(rev) filename = "reports/" + rev; if File.exist?(filename) File.open(filename).each { |line| if line =~ /^@ (.*):(.*)/ generator.add_entry(rev, $1, $2) end } end } generator.create_report ����������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/test-text-perf.c���������������������������������������������0000664�0001750�0001750�00000007517�14211404421�023332� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <stdlib.h> #include <string.h> #include "test-common.h" #define STAGE_WIDTH 800 #define STAGE_HEIGHT 600 static int font_size; static int n_chars; static int rows, cols; static gboolean queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return G_SOURCE_CONTINUE; } static gunichar get_character (int ch) { int total_letters = 0; int i; static const struct { gunichar first_letter; int n_letters; } ranges[] = { { 'a', 26 }, /* lower case letters */ { 'A', 26 }, /* upper case letters */ { '0', 10 }, /* digits */ { 0x410, 0x40 }, /* cyrillic alphabet */ { 0x3b1, 18 } /* greek alphabet */ }; for (i = 0; i < G_N_ELEMENTS (ranges); i++) total_letters += ranges[i].n_letters; ch %= total_letters; for (i = 0; i < G_N_ELEMENTS (ranges) - 1; i++) if (ch < ranges[i].n_letters) return ch + ranges[i].first_letter; else ch -= ranges[i].n_letters; return ch + ranges[i].first_letter; } static ClutterActor * create_label (void) { ClutterColor label_color = { 0xff, 0xff, 0xff, 0xff }; ClutterActor *label; char *font_name; GString *str; int i; font_name = g_strdup_printf ("Monospace %dpx", font_size); str = g_string_new (NULL); for (i = 0; i < n_chars; i++) g_string_append_unichar (str, get_character (i)); label = clutter_text_new_with_text (font_name, str->str); clutter_text_set_color (CLUTTER_TEXT (label), &label_color); free (font_name); g_string_free (str, TRUE); return label; } int main (int argc, char *argv[]) { ClutterActor *stage; ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; ClutterActor *label; int w, h; int row, col; float scale = 1.0f; clutter_perf_fps_init (); if (CLUTTER_INIT_SUCCESS != clutter_init (&argc, &argv)) g_error ("Failed to initialize Clutter"); if (argc != 3) { //g_printerr ("Usage test-text-perf FONT_SIZE N_CHARS\n"); //exit (1); font_size = 30; n_chars = 400; } else { font_size = atoi (argv[1]); n_chars = atoi (argv[2]); } g_print ("Monospace %dpx, string length = %d\n", font_size, n_chars); stage = clutter_stage_new (); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); clutter_stage_set_title (CLUTTER_STAGE (stage), "Text Performance"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); label = create_label (); w = clutter_actor_get_width (label); h = clutter_actor_get_height (label); /* If the label is too big to fit on the stage then scale it so that it will fit */ if (w > STAGE_WIDTH || h > STAGE_HEIGHT) { float x_scale = STAGE_WIDTH / (float) w; float y_scale = STAGE_HEIGHT / (float) h; if (x_scale < y_scale) { scale = x_scale; cols = 1; rows = STAGE_HEIGHT / (h * scale); } else { scale = y_scale; cols = STAGE_WIDTH / (w * scale); rows = 1; } g_print ("Text scaled by %f to fit on the stage\n", scale); } else { cols = STAGE_WIDTH / w; rows = STAGE_HEIGHT / h; } clutter_actor_destroy (label); for (row=0; row<rows; row++) for (col=0; col<cols; col++) { label = create_label(); clutter_actor_set_scale (label, scale, scale); clutter_actor_set_position (label, w * col * scale, h * row * scale); clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); } clutter_actor_show_all (stage); clutter_perf_fps_start (CLUTTER_STAGE (stage)); clutter_threads_add_idle (queue_redraw, stage); clutter_main (); clutter_perf_fps_report ("test-text-perf"); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/performance/test-state-mini.c��������������������������������������������0000664�0001750�0001750�00000012206�14211404421�023455� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <math.h> #include <gmodule.h> #include <clutter/clutter.h> #include "test-common.h" #define STAGE_WIDTH 160 #define STAGE_HEIGHT 120 #define ACTOR_WIDTH 8 #define ACTOR_HEIGHT 8 #define COLS (STAGE_WIDTH/ACTOR_WIDTH) #define ROWS (STAGE_HEIGHT/ACTOR_HEIGHT) #define TOTAL (ROWS*COLS) static void completed (ClutterState *state, gpointer data) { if (g_str_equal (clutter_state_get_state (state), "right")) { /* skip straight to left state when reaching right */ clutter_state_warp_to_state (state, "left"); } else if (g_str_equal (clutter_state_get_state (state), "active")) clutter_state_set_state (state, "right"); else { clutter_state_set_state (state, "active"); } } static ClutterActor *new_rect (gint r, gint g, gint b, gint a) { GError *error = NULL; ClutterColor *color = clutter_color_new (r, g, b, a); ClutterActor *group = clutter_group_new (); ClutterActor *rectangle = clutter_rectangle_new_with_color (color); ClutterActor *hand = NULL; gchar *file = g_build_filename (TESTS_DATA_DIR, "redhand.png", NULL); hand = clutter_texture_new_from_file (file, &error); if (rectangle == NULL) g_error ("image load failed: %s", error->message); free (file); clutter_actor_set_size (hand, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_actor_set_size (rectangle, ACTOR_WIDTH,ACTOR_HEIGHT); clutter_color_free (color); clutter_container_add (CLUTTER_CONTAINER (group), rectangle, hand, NULL); return group; } gint main (gint argc, gchar **argv) { ClutterActor *stage; ClutterState *layout_state; gint i; clutter_perf_fps_init (); if (CLUTTER_INIT_SUCCESS != clutter_init (&argc, &argv)) g_error ("Failed to initialize Clutter"); stage = clutter_stage_new (); layout_state = clutter_state_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "State Performance [mini]"); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); for (i=0; i<TOTAL; i++) { ClutterActor *actor; ClutterState *a_state; int row = i/COLS; int col = i%COLS; actor = new_rect (255 * ( 1.0*col/COLS), 50, 255 * ( 1.0*row/ROWS), 255); clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor); clutter_actor_set_position (actor, 320.0, 240.0); clutter_actor_set_reactive (actor, TRUE); clutter_state_set (layout_state, NULL, "active", actor, "delayed::x", CLUTTER_LINEAR, ACTOR_WIDTH * 1.0 * ((TOTAL-1-i) % COLS), ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, ACTOR_HEIGHT * 1.0 * ((TOTAL-1-i) / COLS), ((row*1.0/ROWS))/2, 0.0, actor, "rotation-angle-x", CLUTTER_LINEAR, 0.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (layout_state, NULL, "right", actor, "delayed::x", CLUTTER_LINEAR, STAGE_WIDTH * 1.0, ((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2, actor, "delayed::y", CLUTTER_LINEAR, STAGE_HEIGHT * 1.0, ((row*1.0/ROWS))/2, 0.0, NULL); clutter_state_set (layout_state, NULL, "left", actor, "rotation-angle-x", CLUTTER_LINEAR, 45.0, actor, "rotation-angle-y", CLUTTER_LINEAR, 5.0, actor, "x", CLUTTER_LINEAR, 0-64.0, actor, "y", CLUTTER_LINEAR, 0-64.0, NULL); a_state = clutter_state_new (); g_object_set_data_full (G_OBJECT (actor), "hover-state-machine", a_state, g_object_unref); clutter_state_set (a_state, NULL, "normal", actor, "opacity", CLUTTER_LINEAR, 0x77, actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0, NULL); clutter_state_set (a_state, NULL, "hover", actor, "opacity", CLUTTER_LINEAR, 0xff, actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0, NULL); clutter_actor_set_opacity (actor, 0x77); clutter_state_set_duration (a_state, NULL, NULL, 500); } clutter_state_set_duration (layout_state, NULL, NULL, 1000); clutter_state_set_duration (layout_state, "active", "left", 1400); g_signal_connect (layout_state, "completed", G_CALLBACK (completed), NULL); clutter_actor_show (stage); clutter_state_warp_to_state (layout_state, "left"); clutter_state_set_state (layout_state, "active"); clutter_perf_fps_start (CLUTTER_STAGE (stage)); clutter_main (); clutter_perf_fps_report ("test-state-mini"); g_object_unref (layout_state); return EXIT_SUCCESS; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/micro-bench/�������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�020146� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/micro-bench/Makefile.am��������������������������������������������������0000664�0001750�0001750�00000001774�14211404421�022213� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������common_ldadd = \ $(top_builddir)/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl/libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la check_PROGRAMS = \ test-text \ test-picking \ test-text-perf \ test-random-text \ test-cogl-perf AM_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) AM_CPPFLAGS = \ -DG_DISABLE_SINGLE_INCLUDES \ -DGLIB_DISABLE_DEPRECATION_WARNINGS \ -DCOGL_DISABLE_DEPRECATION_WARNINGS \ -DCLUTTER_DISABLE_DEPRECATION_WARNINGS \ -DTESTS_DATA_DIR=\""$(top_srcdir)/tests/data/"\" \ -I$(top_srcdir)/../cogl \ -I$(top_builddir)/../cogl \ -I$(top_builddir)/../cogl/cogl \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(top_srcdir)/clutter \ -I$(top_builddir)/clutter LDADD = $(common_ldadd) $(CLUTTER_LIBS) $(LIBM) test_text_SOURCES = test-text.c test_picking_SOURCES = test-picking.c test_text_perf_SOURCES = test-text-perf.c test_random_text_SOURCES = test-random-text.c test_cogl_perf_SOURCES = test-cogl-perf.c ����muffin-5.2.1/clutter/tests/micro-bench/test-cogl-perf.c���������������������������������������������0000664�0001750�0001750�00000010066�14211404421�023150� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter-build-config.h> #include <glib.h> #include <gmodule.h> #include <stdlib.h> #include <clutter/clutter.h> #include <cogl/cogl.h> #include <math.h> #define STAGE_WIDTH 800 #define STAGE_HEIGHT 600 gboolean run_all = FALSE; static GOptionEntry entries[] = { { "run-all", 'a', 0, G_OPTION_ARG_NONE, &run_all, "Run all tests", "" }, { NULL } }; typedef struct _TestState { ClutterActor *stage; int current_test; } TestState; typedef void (*TestCallback) (TestState *state); static void test_rectangles (TestState *state) { #define RECT_WIDTH 5 #define RECT_HEIGHT 5 int x; int y; /* Should the rectangles be randomly positioned/colored/rotated? * * It could be good to develop equivalent GL and Cairo tests so we can * have a sanity check for our Cogl performance. * * The color should vary to check that we correctly batch color changes * The use of alpha should vary so we have a variation of which rectangles * require blending. * Should this be a random variation? * It could be good to experiment with focibly enabling blending for * rectangles that don't technically need it for the sake of extending * batching. E.g. if you a long run of interleved rectangles with every * other rectangle needing blending then it may be worth enabling blending * for all the rectangles to avoid the state changes. * The modelview should change between rectangles to check the software * transform codepath. * Should we group some rectangles under the same modelview? Potentially * we could avoid software transform for long runs of rectangles with the * same modelview. * */ for (y = 0; y < STAGE_HEIGHT; y += RECT_HEIGHT) { for (x = 0; x < STAGE_WIDTH; x += RECT_WIDTH) { cogl_push_matrix (); cogl_translate (x, y, 0); cogl_rotate (45, 0, 0, 1); cogl_set_source_color4f (1, (1.0f/STAGE_WIDTH)*y, (1.0f/STAGE_HEIGHT)*x, 1); cogl_rectangle (0, 0, RECT_WIDTH, RECT_HEIGHT); cogl_pop_matrix (); } } for (y = 0; y < STAGE_HEIGHT; y += RECT_HEIGHT) { for (x = 0; x < STAGE_WIDTH; x += RECT_WIDTH) { cogl_push_matrix (); cogl_translate (x, y, 0); cogl_rotate (0, 0, 0, 1); cogl_set_source_color4f (1, (1.0f/STAGE_WIDTH)*x, (1.0f/STAGE_HEIGHT)*y, (1.0f/STAGE_WIDTH)*x); cogl_rectangle (0, 0, RECT_WIDTH, RECT_HEIGHT); cogl_pop_matrix (); } } } TestCallback tests[] = { test_rectangles }; static void on_paint (ClutterActor *actor, TestState *state) { tests[state->current_test] (state); } static gboolean queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } int main (int argc, char *argv[]) { TestState state; ClutterActor *stage; GError *error = NULL; g_setenv ("CLUTTER_VBLANK", "none", FALSE); g_setenv ("CLUTTER_SHOW_FPS", "1", FALSE); if (clutter_init_with_args (&argc, &argv, NULL, entries, NULL, &error) != CLUTTER_INIT_SUCCESS) { g_warning ("Unable to initialise Clutter:\n%s", error->message); g_error_free (error); return EXIT_FAILURE; } state.current_test = 0; state.stage = stage = clutter_stage_new (); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_White); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Performance Test"); /* We want continuous redrawing of the stage... */ clutter_threads_add_idle (queue_redraw, stage); g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), &state); clutter_actor_show (stage); clutter_main (); clutter_actor_destroy (stage); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/micro-bench/test-text.c��������������������������������������������������0000664�0001750�0001750�00000006020�14211404421�022251� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <stdlib.h> #include <string.h> #define STAGE_WIDTH 640 #define STAGE_HEIGHT 480 #define COLS 18 #define ROWS 20 static void on_paint (ClutterActor *actor, gconstpointer *data) { static GTimer *timer = NULL; static int fps = 0; if (!timer) { timer = g_timer_new (); g_timer_start (timer); } if (g_timer_elapsed (timer, NULL) >= 1) { printf ("fps: %d\n", fps); g_timer_start (timer); fps = 0; } ++fps; } static gboolean queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return G_SOURCE_CONTINUE; } int main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *group; g_setenv ("CLUTTER_VBLANK", "none", FALSE); g_setenv ("CLUTTER_DEFAULT_FPS", "1000", FALSE); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "Text"); group = clutter_group_new (); clutter_actor_set_size (group, STAGE_WIDTH, STAGE_WIDTH); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); clutter_threads_add_idle (queue_redraw, stage); g_signal_connect (group, "paint", G_CALLBACK (on_paint), NULL); { gint row, col; for (row=0; row<ROWS; row++) for (col=0; col<COLS; col++) { ClutterActor *label; gchar font_name[64]; gchar text[64]; gint font_size = row+10; gdouble scale = 0.17 + (1.5 * col / COLS); sprintf (font_name, "Sans %ipx", font_size); sprintf (text, "OH"); if (row==0) { sprintf (font_name, "Sans 10px"); sprintf (text, "%1.2f", scale); font_size = 10; scale = 1.0; } if (col==0) { sprintf (font_name, "Sans 10px"); sprintf (text, "%ipx", font_size); if (row == 0) strcpy (text, ""); font_size = 10; scale = 1.0; } label = clutter_text_new_with_text (font_name, text); clutter_text_set_color (CLUTTER_TEXT (label), CLUTTER_COLOR_White); clutter_actor_set_position (label, (1.0*STAGE_WIDTH/COLS)*col, (1.0*STAGE_HEIGHT/ROWS)*row); /*clutter_actor_set_clip (label, 0,0, (1.0*STAGE_WIDTH/COLS), (1.0*STAGE_HEIGHT/ROWS));*/ clutter_actor_set_scale (label, scale, scale); clutter_text_set_line_wrap (CLUTTER_TEXT (label), FALSE); clutter_container_add_actor (CLUTTER_CONTAINER (group), label); } } clutter_actor_show_all (stage); g_signal_connect (stage, "key-press-event", G_CALLBACK (clutter_main_quit), NULL); clutter_main(); clutter_actor_destroy (stage); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/micro-bench/test-random-text.c�������������������������������������������0000664�0001750�0001750�00000005115�14211404421�023533� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <gmodule.h> #include <clutter/clutter.h> #include <stdlib.h> #define MAX_TEXT_LEN 10 #define MIN_FONT_SIZE 10 #define MAX_FONT_SIZE 30 static const char * const font_names[] = { "Sans", "Sans Italic", "Serif", "Serif Bold", "Times", "Monospace" }; #define FONT_NAME_COUNT 6 static gboolean on_idle (gpointer data) { ClutterActor *stage = CLUTTER_ACTOR (data); int line_height = 0, xpos = 0, ypos = 0; int stage_width = clutter_actor_get_width (stage); int stage_height = clutter_actor_get_height (stage); char text[MAX_TEXT_LEN + 1]; char font_name[64]; int i; GList *children, *node; static GTimer *timer = NULL; static int frame_count = 0; /* Remove all of the children of the stage */ children = clutter_container_get_children (CLUTTER_CONTAINER (stage)); for (node = children; node; node = node->next) clutter_container_remove_actor (CLUTTER_CONTAINER (stage), CLUTTER_ACTOR (node->data)); g_list_free (children); /* Fill the stage with new random labels */ while (ypos < stage_height) { int text_len = rand () % MAX_TEXT_LEN + 1; ClutterActor *label; for (i = 0; i < text_len; i++) text[i] = rand () % (128 - 32) + 32; text[text_len] = '\0'; sprintf (font_name, "%s %i", font_names[rand () % FONT_NAME_COUNT], rand () % (MAX_FONT_SIZE - MIN_FONT_SIZE) + MIN_FONT_SIZE); label = clutter_text_new_with_text (font_name, text); if (clutter_actor_get_height (label) > line_height) line_height = clutter_actor_get_height (label); if (xpos + clutter_actor_get_width (label) > stage_width) { xpos = 0; ypos += line_height; line_height = 0; } clutter_actor_set_position (label, xpos, ypos); clutter_container_add (CLUTTER_CONTAINER (stage), label, NULL); xpos += clutter_actor_get_width (label); } if (timer == NULL) timer = g_timer_new (); else { if (++frame_count >= 10) { printf ("10 frames in %f seconds\n", g_timer_elapsed (timer, NULL)); g_timer_start (timer); frame_count = 0; } } return TRUE; } int main (int argc, char *argv[]) { ClutterActor *stage; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Random Text"); clutter_actor_show (stage); clutter_threads_add_idle (on_idle, stage); clutter_main (); clutter_actor_destroy (stage); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/micro-bench/.gitignore���������������������������������������������������0000664�0001750�0001750�00000000113�14211404421�022131� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/test-cogl-perf /test-picking /test-random-text /test-text /test-text-perf �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/micro-bench/test-picking.c�����������������������������������������������0000664�0001750�0001750�00000007116�14211404421�022720� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <math.h> #include <stdlib.h> #include <clutter/clutter.h> #define N_ACTORS 100 #define N_EVENTS 5 static gint n_actors = N_ACTORS; static gint n_events = N_EVENTS; static GOptionEntry entries[] = { { "num-actors", 'a', 0, G_OPTION_ARG_INT, &n_actors, "Number of actors", "ACTORS" }, { "num-events", 'e', 0, G_OPTION_ARG_INT, &n_events, "Number of events", "EVENTS" }, { NULL } }; static gboolean motion_event_cb (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { return FALSE; } static void do_events (ClutterActor *stage) { glong i; static gdouble angle = 0; for (i = 0; i < n_events; i++) { angle += (2.0 * G_PI) / (gdouble)n_actors; while (angle > G_PI * 2.0) angle -= G_PI * 2.0; /* If we synthesized events, they would be motion compressed; * calling get_actor_at_position() doesn't have that problem */ clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage), CLUTTER_PICK_REACTIVE, 256.0 + 206.0 * cos (angle), 256.0 + 206.0 * sin (angle)); } } static void on_paint (ClutterActor *stage, gconstpointer *data) { do_events (stage); } static gboolean queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } int main (int argc, char **argv) { glong i; gdouble angle; ClutterColor color = { 0x00, 0x00, 0x00, 0xff }; ClutterActor *stage, *rect; GError *error = NULL; g_setenv ("CLUTTER_VBLANK", "none", FALSE); g_setenv ("CLUTTER_DEFAULT_FPS", "1000", FALSE); g_setenv ("CLUTTER_SHOW_FPS", "1", FALSE); if (clutter_init_with_args (&argc, &argv, NULL, entries, NULL, &error) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_set_size (stage, 512, 512); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "Picking"); printf ("Picking performance test with " "%d actors and %d events per frame\n", n_actors, n_events); for (i = n_actors - 1; i >= 0; i--) { angle = ((2.0 * G_PI) / (gdouble) n_actors) * i; color.red = (1.0 - ABS ((MAX (0, MIN (n_actors/2.0 + 0, i))) / (gdouble)(n_actors/4.0) - 1.0)) * 255.0; color.green = (1.0 - ABS ((MAX (0, MIN (n_actors/2.0 + 0, fmod (i + (n_actors/3.0)*2, n_actors)))) / (gdouble)(n_actors/4) - 1.0)) * 255.0; color.blue = (1.0 - ABS ((MAX (0, MIN (n_actors/2.0 + 0, fmod ((i + (n_actors/3.0)), n_actors)))) / (gdouble)(n_actors/4.0) - 1.0)) * 255.0; rect = clutter_rectangle_new_with_color (&color); clutter_actor_set_size (rect, 100, 100); clutter_actor_set_anchor_point_from_gravity (rect, CLUTTER_GRAVITY_CENTER); clutter_actor_set_position (rect, 256 + 206 * cos (angle), 256 + 206 * sin (angle)); clutter_actor_set_reactive (rect, TRUE); g_signal_connect (rect, "motion-event", G_CALLBACK (motion_event_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); } clutter_actor_show (stage); clutter_threads_add_idle (queue_redraw, stage); g_signal_connect (stage, "paint", G_CALLBACK (on_paint), NULL); clutter_main (); clutter_actor_destroy (stage); return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/micro-bench/test-text-perf.c���������������������������������������������0000664�0001750�0001750�00000010063�14211404421�023205� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <stdlib.h> #include <string.h> #define STAGE_WIDTH 800 #define STAGE_HEIGHT 600 static int font_size; static int n_chars; static int rows, cols; static void on_paint (ClutterActor *actor, gconstpointer *data) { static GTimer *timer = NULL; static int fps = 0; if (!timer) { timer = g_timer_new (); g_timer_start (timer); } if (g_timer_elapsed (timer, NULL) >= 1) { printf ("fps=%d, strings/sec=%d, chars/sec=%d\n", fps, fps * rows * cols, fps * rows * cols * n_chars); g_timer_start (timer); fps = 0; } ++fps; } static gboolean queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return G_SOURCE_CONTINUE; } static gunichar get_character (int ch) { int total_letters = 0; int i; static const struct { gunichar first_letter; int n_letters; } ranges[] = { { 'a', 26 }, /* lower case letters */ { 'A', 26 }, /* upper case letters */ { '0', 10 }, /* digits */ { 0x410, 0x40 }, /* cyrillic alphabet */ { 0x3b1, 18 } /* greek alphabet */ }; for (i = 0; i < G_N_ELEMENTS (ranges); i++) total_letters += ranges[i].n_letters; ch %= total_letters; for (i = 0; i < G_N_ELEMENTS (ranges) - 1; i++) if (ch < ranges[i].n_letters) return ch + ranges[i].first_letter; else ch -= ranges[i].n_letters; return ch + ranges[i].first_letter; } static ClutterActor * create_label (void) { ClutterColor label_color = { 0xff, 0xff, 0xff, 0xff }; ClutterActor *label; char *font_name; GString *str; int i; font_name = g_strdup_printf ("Monospace %dpx", font_size); str = g_string_new (NULL); for (i = 0; i < n_chars; i++) g_string_append_unichar (str, get_character (i)); label = clutter_text_new_with_text (font_name, str->str); clutter_text_set_color (CLUTTER_TEXT (label), &label_color); free (font_name); g_string_free (str, TRUE); return label; } int main (int argc, char *argv[]) { ClutterActor *stage; ClutterActor *label; int w, h; int row, col; float scale = 1.0f; g_setenv ("CLUTTER_VBLANK", "none", FALSE); g_setenv ("CLUTTER_DEFAULT_FPS", "1000", FALSE); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; if (argc != 3) { g_printerr ("Usage test-text-perf FONT_SIZE N_CHARS\n"); exit (1); } font_size = atoi (argv[1]); n_chars = atoi (argv[2]); g_print ("Monospace %dpx, string length = %d\n", font_size, n_chars); stage = clutter_stage_new (); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); clutter_stage_set_title (CLUTTER_STAGE (stage), "Text Performance"); g_signal_connect (stage, "paint", G_CALLBACK (on_paint), NULL); label = create_label (); w = clutter_actor_get_width (label); h = clutter_actor_get_height (label); /* If the label is too big to fit on the stage then scale it so that it will fit */ if (w > STAGE_WIDTH || h > STAGE_HEIGHT) { float x_scale = STAGE_WIDTH / (float) w; float y_scale = STAGE_HEIGHT / (float) h; if (x_scale < y_scale) { scale = x_scale; cols = 1; rows = STAGE_HEIGHT / (h * scale); } else { scale = y_scale; cols = STAGE_WIDTH / (w * scale); rows = 1; } g_print ("Text scaled by %f to fit on the stage\n", scale); } else { cols = STAGE_WIDTH / w; rows = STAGE_HEIGHT / h; } clutter_actor_destroy (label); for (row=0; row<rows; row++) for (col=0; col<cols; col++) { label = create_label(); clutter_actor_set_scale (label, scale, scale); clutter_actor_set_position (label, w * col * scale, h * row * scale); clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); } clutter_actor_show_all (stage); clutter_threads_add_idle (queue_redraw, stage); clutter_main (); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/�����������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�020607� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/cally-atktext-example.c������������������������������������0000664�0001750�0001750�00000022130�14211404421�025170� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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. */ #include <atk/atk.h> #include <clutter/clutter.h> #include "cally-examples-util.h" #define WIDTH 800 #define HEIGHT 600 static ClutterActor *text_actor = NULL; static ClutterActor *text_editable_actor = NULL; /* * Test AtkText interface */ static void test_atk_text (ClutterActor *actor) { gchar *text = NULL; AtkObject *object = NULL; AtkText *cally_text = NULL; gboolean bool = FALSE; gunichar unichar; gint count = -1; gint start = -1; gint end = -1; gint pos = -1; AtkAttributeSet *at_set = NULL; GSList *attrs; gchar *buf; gint x, y, width, height; object = atk_gobject_accessible_for_object (G_OBJECT (actor)); cally_text = ATK_TEXT (object); if (!cally_text) return; text = atk_text_get_text (cally_text, 0, -1); g_print ("atk_text_get_text output: %s\n", text); unichar = atk_text_get_character_at_offset (cally_text, 5); buf = g_ucs4_to_utf8 (&unichar, 1, NULL, NULL, NULL); g_print ("atk_text_get_character_at_offset(5): '%s' vs '%c'\n", buf, text[5]); free (text); text = NULL; free (buf); buf = NULL; text = atk_text_get_text_before_offset (cally_text, 5, ATK_TEXT_BOUNDARY_WORD_END, &start, &end); g_print ("atk_text_get_text_before_offset: %s, %i, %i\n", text, start, end); free (text); text = NULL; text = atk_text_get_text_at_offset (cally_text, 5, ATK_TEXT_BOUNDARY_WORD_END, &start, &end); g_print ("atk_text_get_text_at_offset: %s, %i, %i\n", text, start, end); free (text); text = NULL; text = atk_text_get_text_after_offset (cally_text, 5, ATK_TEXT_BOUNDARY_WORD_END, &start, &end); g_print ("atk_text_get_text_after_offset: %s, %i, %i\n", text, start, end); free (text); text = NULL; pos = atk_text_get_caret_offset (cally_text); g_print ("atk_text_get_caret_offset: %i\n", pos); atk_text_set_caret_offset (cally_text, 5); count = atk_text_get_character_count (cally_text); g_print ("atk_text_get_character_count: %i\n", count); count = atk_text_get_n_selections (cally_text); g_print ("atk_text_get_n_selections: %i\n", count); text = atk_text_get_selection (cally_text, 0, &start, &end); g_print ("atk_text_get_selection: %s, %i, %i\n", text, start, end); free(text); text = NULL; bool = atk_text_remove_selection (cally_text, 0); g_print ("atk_text_remove_selection (0): %i\n", bool); bool = atk_text_remove_selection (cally_text, 1); g_print ("atk_text_remove_selection (1): %i\n", bool); bool = atk_text_add_selection (cally_text, 5, 10); g_print ("atk_text_add_selection: %i\n", bool); bool = atk_text_set_selection (cally_text, 0, 6, 10); g_print ("atk_text_set_selection: %i\n", bool); at_set = atk_text_get_run_attributes (cally_text, 0, &start, &end); g_print ("atk_text_get_run_attributes: %i, %i\n", start, end); attrs = (GSList*) at_set; while (attrs) { AtkAttribute *at = (AtkAttribute *) attrs->data; g_print ("text run %s = %s\n", at->name, at->value); attrs = g_slist_next (attrs); } atk_text_get_character_extents (cally_text, 0, &x, &y, &width, &height, ATK_XY_WINDOW); g_print ("atk_text_get_character_extents (0, window): x=%i y=%i width=%i height=%i\n", x, y, width, height); atk_text_get_character_extents (cally_text, 0, &x, &y, &width, &height, ATK_XY_SCREEN); g_print ("atk_text_get_character_extents (0, screen): x=%i y=%i width=%i height=%i\n", x, y, width, height); pos = atk_text_get_offset_at_point (cally_text, 200, 10, ATK_XY_WINDOW); g_print ("atk_text_get_offset_at_point (200, 10, window): %i\n", pos); pos = atk_text_get_offset_at_point (cally_text, 200, 100, ATK_XY_SCREEN); g_print ("atk_text_get_offset_at_point (200, 100, screen): %i\n", pos); } static void dump_actor_default_atk_attributes (ClutterActor *actor) { AtkObject *object = NULL; AtkText *cally_text = NULL; AtkAttributeSet *at_set = NULL; GSList *attrs; const gchar *text_value = NULL; object = atk_gobject_accessible_for_object (G_OBJECT (actor)); cally_text = ATK_TEXT (object); if (!cally_text) return; text_value = clutter_text_get_text (CLUTTER_TEXT (actor)); g_print ("text value = %s\n", text_value); at_set = atk_text_get_default_attributes (cally_text); attrs = (GSList*) at_set; while (attrs) { AtkAttribute *at = (AtkAttribute *) attrs->data; g_print ("text default %s = %s\n", at->name, at->value); attrs = g_slist_next (attrs); } } static gboolean button_press_cb (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { test_atk_text (text_actor); test_atk_text (text_editable_actor); return TRUE; } static void make_ui (ClutterActor *stage) { ClutterColor color_stage = { 0x00, 0x00, 0x00, 0xff }; ClutterColor color_text = { 0xff, 0x00, 0x00, 0xff }; ClutterColor color_sel = { 0x00, 0xff, 0x00, 0x55 }; ClutterColor color_rect = { 0x00, 0xff, 0xff, 0xff }; ClutterColor color_label = { 0x00, 0x00, 0x00, 0xff }; ClutterActor *button = NULL; ClutterActor *rectangle = NULL; ClutterActor *label = NULL; clutter_stage_set_color (CLUTTER_STAGE (stage), &color_stage); clutter_actor_set_size (stage, WIDTH, HEIGHT); /* text */ text_actor = clutter_text_new_full ("Sans Bold 32px", "", &color_text); clutter_text_set_markup (CLUTTER_TEXT(text_actor), "<span fgcolor=\"#FFFF00\" bgcolor=\"#00FF00\"><s>Lorem ipsum dolor sit amet</s></span>"); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_actor); dump_actor_default_atk_attributes (text_actor); /* text_editable */ text_editable_actor = clutter_text_new_full ("Sans Bold 32px", "consectetur adipisicing elit", &color_text); clutter_actor_set_position (text_editable_actor, 20, 100); clutter_text_set_editable (CLUTTER_TEXT (text_editable_actor), TRUE); clutter_text_set_selectable (CLUTTER_TEXT (text_editable_actor), TRUE); clutter_text_set_selection_color (CLUTTER_TEXT (text_editable_actor), &color_sel); clutter_text_set_line_wrap (CLUTTER_TEXT (text_editable_actor), TRUE); clutter_actor_grab_key_focus (text_editable_actor); clutter_actor_set_reactive (text_editable_actor, TRUE); dump_actor_default_atk_attributes (text_editable_actor); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_editable_actor); /* test button */ button = clutter_group_new (); rectangle = clutter_rectangle_new_with_color (&color_rect); clutter_actor_set_size (rectangle, 75, 35); label = clutter_text_new_full ("Sans Bold 32px", "Test", &color_label); clutter_actor_set_position (button, 100, 200); clutter_container_add_actor (CLUTTER_CONTAINER (button), rectangle); clutter_container_add_actor (CLUTTER_CONTAINER (button), label); clutter_actor_set_reactive (button, TRUE); g_signal_connect_after (button, "button-press-event", G_CALLBACK (button_press_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button); } int main (int argc, char *argv[]) { ClutterActor *stage; g_set_application_name ("AtkText"); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; cally_util_a11y_init (&argc, &argv); stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkText Test"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); make_ui (stage); clutter_actor_show_all (stage); test_atk_text (text_actor); test_atk_text (text_editable_actor); clutter_main (); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/Makefile.am������������������������������������������������0000664�0001750�0001750�00000002332�14211404421�022643� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������common_ldadd = \ $(top_builddir)/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la common_sources = \ cally-examples-util.c \ cally-examples-util.h AM_CPPFLAGS = \ -DPREFIXDIR=\"$(libdir)\" \ -DCLUTTER_DISABLE_DEPRECATION_WARNINGS \ -DGLIB_DISABLE_DEPRECATION_WARNINGS \ -I$(top_srcdir)/../cogl \ -I$(top_builddir)/../cogl \ -I$(top_builddir)/../cogl/cogl \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(top_srcdir)/clutter \ -I$(top_builddir)/clutter \ -I$(top_srcdir)/tests/accessibility AM_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) LDADD = $(common_ldadd) $(CLUTTER_LIBS) check_PROGRAMS = \ cally-atkcomponent-example \ cally-atkeditabletext-example \ cally-atkevents-example \ cally-atktext-example \ cally-clone-example cally_atkcomponent_example_SOURCES = $(common_sources) cally-atkcomponent-example.c cally_atktext_example_SOURCES = $(common_sources) cally-atktext-example.c cally_atkevents_example_SOURCES = $(common_sources) cally-atkevents-example.c cally_atkeditabletext_example_SOURCES = $(common_sources) cally-atkeditabletext-example.c cally_clone_example_SOURCES = $(common_sources) cally-clone-example.c DISTCLEANFILES = ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/cally-atkcomponent-example.c�������������������������������0000664�0001750�0001750�00000006142�14211404421�026213� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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. */ #include <clutter/clutter.h> #include "cally-examples-util.h" #define WIDTH 300 #define HEIGHT 300 #define SIZE 50 #define DEPTH -100 int main (int argc, char *argv[]) { ClutterActor *stage = NULL; ClutterActor *button1 = NULL; ClutterActor *button2 = NULL; ClutterActor *button3 = NULL; ClutterActor *button4 = NULL; ClutterActor *group[4]; int i = 0; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; cally_util_a11y_init (&argc, &argv); stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkComponent Test"); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_White); clutter_actor_set_size (stage, WIDTH, HEIGHT); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); button1 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Yellow); clutter_actor_set_size (button1, SIZE, SIZE); button2 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Green); clutter_actor_set_position (button2, 2 * SIZE, 0); clutter_actor_set_size (button2, SIZE, SIZE); button3 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Blue); clutter_actor_set_position (button3, 0, 2 * SIZE); clutter_actor_set_size (button3, SIZE, SIZE); clutter_actor_set_depth( button3, DEPTH); /* a nested hierarchy, to check that the relative positions are computed properly */ button4 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Magenta); clutter_actor_set_position (button4, SIZE / 2, SIZE / 2); clutter_actor_set_size (button4, SIZE, SIZE); for (i = 0; i < 4; i++) { group[i] = clutter_group_new (); clutter_actor_set_position (group[i], SIZE / 2, SIZE / 2); clutter_actor_set_size (group[i], SIZE, SIZE); if (i > 0) clutter_container_add_actor (CLUTTER_CONTAINER (group[i]), group [i - 1]); } clutter_container_add_actor (CLUTTER_CONTAINER (stage), button1); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button2); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button3); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group[3]); clutter_container_add_actor (CLUTTER_CONTAINER (group[0]), button4); clutter_actor_show (stage); clutter_main (); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/cally-examples-util.h��������������������������������������0000664�0001750�0001750�00000001706�14211404421�024657� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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. */ gboolean cally_util_a11y_init (int *argc, char ***argv); ����������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/cally-clone-example.c��������������������������������������0000664�0001750�0001750�00000007774�14211404421�024625� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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. */ #include <atk/atk.h> #include <clutter/clutter.h> #include "cally-examples-util.h" #define WIDTH 800 #define HEIGHT 600 #define HEIGHT_STEP 100 #define NUM_ENTRIES 3 static void make_ui (ClutterActor *stage) { ClutterActor *editable = NULL; ClutterActor *rectangle = NULL; ClutterActor *label = NULL; ClutterColor color_stage = { 0x00, 0x00, 0x00, 0xff }; ClutterColor color_text = { 0xff, 0x00, 0x00, 0xff }; ClutterColor color_sel = { 0x00, 0xff, 0x00, 0x55 }; ClutterColor color_label = { 0x00, 0xff, 0x55, 0xff }; ClutterColor color_rect = { 0x00, 0xff, 0xff, 0x55 }; ClutterActor *full_entry = NULL; ClutterActor *cloned_entry = NULL; clutter_stage_set_color (CLUTTER_STAGE (stage), &color_stage); clutter_actor_set_size (stage, WIDTH, HEIGHT); label = clutter_text_new_full ("Sans Bold 32px", "Entry", &color_label); clutter_actor_set_position (label, 0, 50); /* editable */ editable = clutter_text_new_full ("Sans Bold 32px", "ddd", &color_text); clutter_actor_set_position (editable, 150, 50); clutter_text_set_editable (CLUTTER_TEXT (editable), TRUE); clutter_text_set_selectable (CLUTTER_TEXT (editable), TRUE); clutter_text_set_selection_color (CLUTTER_TEXT (editable), &color_sel); clutter_actor_grab_key_focus (editable); clutter_actor_set_reactive (editable, TRUE); /* rectangle: to create a entry "feeling" */ rectangle = clutter_rectangle_new_with_color (&color_rect); clutter_actor_set_position (rectangle, 150, 50); clutter_actor_add_constraint (rectangle, clutter_bind_constraint_new (editable, CLUTTER_BIND_SIZE, 0)); full_entry = clutter_group_new (); clutter_actor_set_position (full_entry, 0, 50); clutter_actor_set_size (full_entry, 100, 75); clutter_container_add_actor (CLUTTER_CONTAINER (full_entry), label); clutter_container_add_actor (CLUTTER_CONTAINER (full_entry), editable); clutter_container_add_actor (CLUTTER_CONTAINER (full_entry), rectangle); clutter_actor_show_all (full_entry); clutter_actor_set_scale (full_entry, 2, 1); clutter_container_add_actor (CLUTTER_CONTAINER (stage), full_entry); /* Cloning! */ cloned_entry = clutter_clone_new (full_entry); clutter_actor_set_position (cloned_entry, 50, 200); clutter_actor_set_scale (cloned_entry, 1, 2); clutter_actor_show_all (cloned_entry); clutter_actor_set_reactive (cloned_entry, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), cloned_entry); } int main (int argc, char *argv[]) { ClutterActor *stage; g_set_application_name ("Clone Example"); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; cally_util_a11y_init (&argc, &argv); stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - Clone Test"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); make_ui (stage); clutter_actor_show_all (stage); clutter_main (); return 0; } ����muffin-5.2.1/clutter/tests/accessibility/cally-atkeditabletext-example.c����������������������������0000664�0001750�0001750�00000020455�14211404421�026672� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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. */ #include <atk/atk.h> #include <clutter/clutter.h> #include "cally-examples-util.h" #define WIDTH 800 #define HEIGHT 600 static ClutterActor *text_actor = NULL; static ClutterActor *text_editable_actor = NULL; /* * Test AtkText interface */ static void test_atk_text (ClutterActor *actor) { AtkObject *object = NULL; AtkEditableText *cally_editable_text = NULL; gint pos = 0; object = atk_gobject_accessible_for_object (G_OBJECT (actor)); cally_editable_text = ATK_EDITABLE_TEXT (object); if (cally_editable_text != NULL) { atk_editable_text_set_text_contents (cally_editable_text, "New text"); atk_editable_text_delete_text (cally_editable_text, 0, 3); pos = 3; atk_editable_text_insert_text (cally_editable_text, "New", 0, &pos); /* Not implemented in cally, just checking that we can call this functions */ atk_editable_text_copy_text (cally_editable_text, 0, -1); atk_editable_text_paste_text (cally_editable_text, 5); atk_editable_text_cut_text (cally_editable_text, 0, -1); } } static gboolean insert_text_press_cb (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { AtkObject *object = NULL; AtkEditableText *cally_editable_text = NULL; gint pos = 0; object = atk_gobject_accessible_for_object (G_OBJECT (text_editable_actor)); cally_editable_text = ATK_EDITABLE_TEXT (object); pos = 3; atk_editable_text_insert_text (cally_editable_text, "New", 0, &pos); return TRUE; } static gboolean delete_text_press_cb (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { AtkObject *object = NULL; AtkEditableText *cally_editable_text = NULL; object = atk_gobject_accessible_for_object (G_OBJECT (text_editable_actor)); cally_editable_text = ATK_EDITABLE_TEXT (object); atk_editable_text_delete_text (cally_editable_text, 0, 3); return TRUE; } static gboolean set_text_press_cb (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { AtkObject *object = NULL; AtkEditableText *cally_editable_text = NULL; object = atk_gobject_accessible_for_object (G_OBJECT (text_editable_actor)); cally_editable_text = ATK_EDITABLE_TEXT (object); atk_editable_text_set_text_contents (cally_editable_text, "New text"); return TRUE; } static gboolean activate_deactivate_press_cb (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { gboolean active = FALSE; active = clutter_text_get_activatable (CLUTTER_TEXT (text_editable_actor)); clutter_text_set_activatable (CLUTTER_TEXT (text_editable_actor), !active); return TRUE; } static gboolean print_cursor_position_press_cb (ClutterActor *actor, ClutterButtonEvent *event, gpointer data) { gint pos = 0; pos = clutter_text_get_cursor_position (CLUTTER_TEXT (text_editable_actor)); g_print ("current cursor position %i\n", pos); return TRUE; } static void activate_cb (ClutterActor *actor, gpointer data) { g_print ("Actor activated\n"); } static ClutterActor* _create_button (const gchar *text) { ClutterActor *button = NULL; ClutterActor *rectangle = NULL; ClutterActor *label = NULL; button = clutter_group_new (); rectangle = clutter_rectangle_new_with_color (CLUTTER_COLOR_Magenta); clutter_actor_set_size (rectangle, 375, 35); label = clutter_text_new_full ("Sans Bold 32px", text, CLUTTER_COLOR_Black); clutter_container_add_actor (CLUTTER_CONTAINER (button), rectangle); clutter_container_add_actor (CLUTTER_CONTAINER (button), label); clutter_actor_set_reactive (button, TRUE); return button; } static void make_ui (ClutterActor *stage) { ClutterActor *button = NULL; clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkEditable Test"); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_White); clutter_actor_set_size (stage, WIDTH, HEIGHT); /* text */ text_actor = clutter_text_new_full ("Sans Bold 32px", "Lorem ipsum dolor sit amet", CLUTTER_COLOR_Red); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_actor); /* text_editable */ text_editable_actor = clutter_text_new_full ("Sans Bold 32px", "consectetur adipisicing elit", CLUTTER_COLOR_Red); clutter_actor_set_position (text_editable_actor, 0, 100); clutter_text_set_editable (CLUTTER_TEXT (text_editable_actor), TRUE); clutter_text_set_selectable (CLUTTER_TEXT (text_editable_actor), TRUE); clutter_text_set_selection_color (CLUTTER_TEXT (text_editable_actor), CLUTTER_COLOR_Green); clutter_text_set_activatable (CLUTTER_TEXT (text_editable_actor), TRUE); clutter_text_set_line_wrap (CLUTTER_TEXT (text_editable_actor), TRUE); clutter_actor_grab_key_focus (text_editable_actor); clutter_actor_set_reactive (text_editable_actor, TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_editable_actor); g_signal_connect (text_editable_actor, "activate", G_CALLBACK (activate_cb), NULL); /* test buttons */ button = _create_button ("Set"); clutter_actor_set_position (button, 100, 200); g_signal_connect_after (button, "button-press-event", G_CALLBACK (set_text_press_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button); button = _create_button ("Delete"); clutter_actor_set_position (button, 100, 250); g_signal_connect_after (button, "button-press-event", G_CALLBACK (delete_text_press_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button); button = _create_button ("Insert"); clutter_actor_set_position (button, 100, 300); g_signal_connect_after (button, "button-press-event", G_CALLBACK (insert_text_press_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button); button = _create_button ("Activate/Deactivate"); clutter_actor_set_position (button, 100, 350); g_signal_connect_after (button, "button-press-event", G_CALLBACK (activate_deactivate_press_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button); button = _create_button ("Cursor position"); clutter_actor_set_position (button, 100, 450); g_signal_connect_after (button, "button-press-event", G_CALLBACK (print_cursor_position_press_cb), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), button); } int main (int argc, char *argv[]) { ClutterActor *stage = NULL; g_set_application_name ("AtkEditableText"); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; cally_util_a11y_init (&argc, &argv); stage = clutter_stage_new (); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); make_ui (stage); clutter_actor_show_all (stage); test_atk_text (text_actor); test_atk_text (text_editable_actor); clutter_main (); return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/.gitignore�������������������������������������������������0000664�0001750�0001750�00000000200�14211404421�022567� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/cally-atkcomponent-example /cally-atkeditabletext-example /cally-atkevents-example /cally-atktext-example /cally-clone-example ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/cally-atkevents-example.c����������������������������������0000664�0001750�0001750�00000014354�14211404421�025521� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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. */ /* * The purpose of this example is test key event and global event * implementation, specifically: * * atk_add_global_event_listener * atk_remove_global_event_listener * atk_add_key_event_listener * atk_remove_key_event_listener */ #include <atk/atk.h> #include <clutter/clutter.h> #include <cally/cally.h> #include "cally-examples-util.h" #define WIDTH 800 #define HEIGHT 600 #define HEIGHT_STEP 100 #define NUM_ENTRIES 3 struct _Data{ gint value; }; typedef struct _Data Data; static gboolean atk_key_listener (AtkKeyEventStruct *event, gpointer data) { Data *my_data = (Data*) data; g_print ("atk_listener: 0x%x ", event->keyval); if (my_data != NULL) { g_print ("\t Data value: %i\n", my_data->value); } else { g_print ("\tNo data!!\n"); } return FALSE; } static gboolean window_event_listener (GSignalInvocationHint * signal_hint, guint n_param_values, const GValue * param_values, gpointer data) { AtkObject *accessible; GSignalQuery signal_query; const gchar *name, *s; g_signal_query (signal_hint->signal_id, &signal_query); name = signal_query.signal_name; accessible = ATK_OBJECT (g_value_get_object (¶m_values[0])); s = atk_object_get_name (accessible); g_print ("Detected window event \"%s\" from object \"%p\" named \"%s\"\n", name, accessible, s); return TRUE; } static void make_ui (ClutterActor *stage) { gint i = 0; ClutterActor *editable = NULL; ClutterActor *rectangle = NULL; ClutterActor *label = NULL; ClutterColor color_sel = { 0x00, 0xff, 0x00, 0x55 }; ClutterColor color_label = { 0x00, 0xff, 0x55, 0xff }; ClutterColor color_rect = { 0x00, 0xff, 0xff, 0x55 }; float label_geom_y, editable_geom_y; clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_White); clutter_actor_set_size (stage, WIDTH, HEIGHT); label_geom_y = 50; editable_geom_y = 50; for (i = 0; i < NUM_ENTRIES; i++) { /* label */ label = clutter_text_new_full ("Sans Bold 32px", "Entry", &color_label); clutter_actor_set_position (label, 0, label_geom_y); /* editable */ editable = clutter_text_new_full ("Sans Bold 32px", "ddd", CLUTTER_COLOR_Red); clutter_actor_set_position (editable, 150, editable_geom_y); clutter_actor_set_size (editable, 500, 75); clutter_text_set_editable (CLUTTER_TEXT (editable), TRUE); clutter_text_set_selectable (CLUTTER_TEXT (editable), TRUE); clutter_text_set_selection_color (CLUTTER_TEXT (editable), &color_sel); clutter_actor_grab_key_focus (editable); clutter_actor_set_reactive (editable, TRUE); /* rectangle: to create a entry "feeling" */ rectangle = clutter_rectangle_new_with_color (&color_rect); clutter_actor_set_position (rectangle, 150, editable_geom_y); clutter_actor_set_size (rectangle, 500, 75); clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); clutter_container_add_actor (CLUTTER_CONTAINER (stage), editable); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle); label_geom_y += HEIGHT_STEP; editable_geom_y += HEIGHT_STEP; } } int main (int argc, char *argv[]) { ClutterActor *stage, *stage_main; Data data1, data2, data3; guint id_1 = 0, id_2 = 0, id_3 = 0; g_set_application_name ("AtkText"); if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; if (cally_util_a11y_init (&argc, &argv) == FALSE) { g_error ("This example requires the accessibility support, " "especifically AtkUtil implementation loaded, " "as it tries to register and remove event listeners"); } data1.value = 10; data2.value = 20; data3.value = 30; /* key event listeners */ id_1 = atk_add_key_event_listener ((AtkKeySnoopFunc)atk_key_listener, &data1); atk_remove_key_event_listener (id_1); id_2 = atk_add_key_event_listener ((AtkKeySnoopFunc)atk_key_listener, &data2); id_3 = atk_add_key_event_listener ((AtkKeySnoopFunc)atk_key_listener, &data3); atk_remove_key_event_listener (id_2); g_print ("key event listener ids registered: (%i, %i, %i)\n", id_1, id_2, id_3); /* event listeners */ atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:create"); atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:destroy"); atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:activate"); atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:deactivate"); stage_main = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage_main), "Cally - AtkEvents/1"); g_signal_connect (stage_main, "destroy", G_CALLBACK (clutter_main_quit), NULL); make_ui (stage_main); clutter_actor_show_all (stage_main); if (clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE)) { stage = clutter_stage_new (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkEvents/2"); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); make_ui (stage); clutter_actor_show_all (stage); } clutter_main (); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/accessibility/cally-examples-util.c��������������������������������������0000664�0001750�0001750�00000007755�14211404421�024664� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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. */ #include <gmodule.h> #include <stdlib.h> #include <clutter/clutter.h> #include "cally-examples-util.h" /* Checking the at-spi sources, the module directory is * $(libdir)/gtk-2.0/modules * * It is supposed cally would be installed on the same libdir. * * You could use the option atk-bridge-dir to use other directory. */ #define ATK_BRIDGE_DEFAULT_MODULE_DIRECTORY PREFIXDIR"/gtk-2.0/modules" static gchar * _search_for_bridge_module (const gchar *module_name) { /* We simplify the search for the atk bridge, see see the definition * of the macro for more information*/ return g_strdup (ATK_BRIDGE_DEFAULT_MODULE_DIRECTORY); } static gchar* _a11y_check_custom_bridge (int *argc, char ***argv) { GError *error = NULL; GOptionContext *context; static gchar *bridge_dir = NULL; static GOptionEntry entries [] = { {"atk-bridge-dir", 'd', 0, G_OPTION_ARG_STRING, &bridge_dir, "atk-bridge module directory", NULL} }; context = g_option_context_new ("- cally examples"); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, argc, argv, &error)) { g_print ("%s\n", error->message); g_print ("Use --help for more information.\n"); exit (0); } return bridge_dir; } static gboolean _a11y_invoke_module (const gchar *module_path, gboolean init) { GModule *handle; void (*invoke_fn) (void); const char *method; if (init) method = "gnome_accessibility_module_init"; else method = "gnome_accessibility_module_shutdown"; if (!module_path) return FALSE; if (!(handle = g_module_open (module_path, G_MODULE_BIND_LAZY))) { g_warning ("Accessibility: failed to load module '%s': '%s'", module_path, g_module_error ()); return FALSE; } if (!g_module_symbol (handle, method, (gpointer *)&invoke_fn)) { g_warning ("Accessibility: error library '%s' does not include " "method '%s' required for accessibility support", module_path, method); g_module_close (handle); return FALSE; } g_debug ("Module %s loaded successfully", module_path); invoke_fn (); return TRUE; } /** * This method will initialize the accessibility support provided by cally. * * Basically it will load the cally module using gmodule functions. * * Returns if it was able to init the a11y support or not. */ gboolean cally_util_a11y_init (int *argc, char ***argv) { gchar *bridge_dir = NULL; gchar *bridge_path = NULL; gboolean result = FALSE; if (clutter_get_accessibility_enabled () == FALSE) { g_warning ("Accessibility: clutter has no accessibility enabled" " skipping the atk-bridge load"); return FALSE; } bridge_dir = _a11y_check_custom_bridge (argc, argv); if (bridge_dir == NULL) bridge_dir = _search_for_bridge_module ("atk-bridge"); bridge_path = g_module_build_path (bridge_dir, "libatk-bridge"); result = _a11y_invoke_module (bridge_path, TRUE); free (bridge_dir); free (bridge_path); return result; } �������������������muffin-5.2.1/clutter/tests/conform/�����������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�017423� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/score.c����������������������������������������������������������0000664�0001750�0001750�00000006734�14211404421�020714� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <clutter/clutter.h> #include "test-conform-common.h" static guint level = 0; static void on_score_started (ClutterScore *score) { if (g_test_verbose ()) g_print ("Score started\n"); } static void on_score_completed (ClutterScore *score) { if (g_test_verbose ()) g_print ("Score completed\n"); } static void on_timeline_started (ClutterScore *score, ClutterTimeline *timeline) { if (g_test_verbose ()) g_print ("Started timeline: '%s'\n", (gchar *) g_object_get_data (G_OBJECT (timeline), "timeline-name")); level += 1; } static void on_timeline_completed (ClutterScore *score, ClutterTimeline *timeline) { if (g_test_verbose ()) g_print ("Completed timeline: '%s'\n", (gchar *) g_object_get_data (G_OBJECT (timeline), "timeline-name")); level -= 1; } void score_base (TestConformSimpleFixture *fixture, gconstpointer data) { ClutterScore *score; ClutterTimeline *timeline_1; ClutterTimeline *timeline_2; ClutterTimeline *timeline_3; ClutterTimeline *timeline_4; ClutterTimeline *timeline_5; GSList *timelines; /* FIXME - this is necessary to make the master clock spin */ ClutterActor *stage = clutter_stage_new (); timeline_1 = clutter_timeline_new (100); g_object_set_data_full (G_OBJECT (timeline_1), "timeline-name", g_strdup ("Timeline 1"), free); timeline_2 = clutter_timeline_new (100); clutter_timeline_add_marker_at_time (timeline_2, "foo", 50); g_object_set_data_full (G_OBJECT (timeline_2), "timeline-name", g_strdup ("Timeline 2"), free); timeline_3 = clutter_timeline_new (100); g_object_set_data_full (G_OBJECT (timeline_3), "timeline-name", g_strdup ("Timeline 3"), free); timeline_4 = clutter_timeline_new (100); g_object_set_data_full (G_OBJECT (timeline_4), "timeline-name", g_strdup ("Timeline 4"), free); timeline_5 = clutter_timeline_new (100); g_object_set_data_full (G_OBJECT (timeline_5), "timeline-name", g_strdup ("Timeline 5"), free); score = clutter_score_new(); g_signal_connect (score, "started", G_CALLBACK (on_score_started), NULL); g_signal_connect (score, "timeline-started", G_CALLBACK (on_timeline_started), NULL); g_signal_connect (score, "timeline-completed", G_CALLBACK (on_timeline_completed), NULL); g_signal_connect (score, "completed", G_CALLBACK (on_score_completed), NULL); clutter_score_append (score, NULL, timeline_1); clutter_score_append (score, timeline_1, timeline_2); clutter_score_append (score, timeline_1, timeline_3); clutter_score_append (score, timeline_3, timeline_4); clutter_score_append_at_marker (score, timeline_2, "foo", timeline_5); timelines = clutter_score_list_timelines (score); g_assert (5 == g_slist_length (timelines)); g_slist_free (timelines); clutter_score_start (score); clutter_actor_destroy (stage); g_object_unref (timeline_1); g_object_unref (timeline_2); g_object_unref (timeline_3); g_object_unref (timeline_4); g_object_unref (timeline_5); g_object_unref (score); } ������������������������������������muffin-5.2.1/clutter/tests/conform/actor-layout.c���������������������������������������������������0000664�0001750�0001750�00000006201�14211404421�022211� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> static void actor_basic_layout (void) { ClutterActor *stage = clutter_test_get_stage (); ClutterActor *vase; ClutterActor *flower[3]; ClutterPoint p; vase = clutter_actor_new (); clutter_actor_set_name (vase, "Vase"); clutter_actor_set_layout_manager (vase, clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL)); clutter_actor_add_child (stage, vase); flower[0] = clutter_actor_new (); clutter_actor_set_background_color (flower[0], CLUTTER_COLOR_Red); clutter_actor_set_size (flower[0], 100, 100); clutter_actor_set_name (flower[0], "Red Flower"); clutter_actor_add_child (vase, flower[0]); flower[1] = clutter_actor_new (); clutter_actor_set_background_color (flower[1], CLUTTER_COLOR_Yellow); clutter_actor_set_size (flower[1], 100, 100); clutter_actor_set_name (flower[1], "Yellow Flower"); clutter_actor_add_child (vase, flower[1]); flower[2] = clutter_actor_new (); clutter_actor_set_background_color (flower[2], CLUTTER_COLOR_Green); clutter_actor_set_size (flower[2], 100, 100); clutter_actor_set_name (flower[2], "Green Flower"); clutter_actor_add_child (vase, flower[2]); clutter_point_init (&p, 50, 50); clutter_test_assert_actor_at_point (stage, &p, flower[0]); clutter_point_init (&p, 150, 50); clutter_test_assert_actor_at_point (stage, &p, flower[1]); clutter_point_init (&p, 250, 50); clutter_test_assert_actor_at_point (stage, &p, flower[2]); } static void actor_margin_layout (void) { ClutterActor *stage = clutter_test_get_stage (); ClutterActor *vase; ClutterActor *flower[3]; ClutterPoint p; vase = clutter_actor_new (); clutter_actor_set_name (vase, "Vase"); clutter_actor_set_layout_manager (vase, clutter_box_layout_new ()); clutter_actor_add_child (stage, vase); flower[0] = clutter_actor_new (); clutter_actor_set_background_color (flower[0], CLUTTER_COLOR_Red); clutter_actor_set_size (flower[0], 100, 100); clutter_actor_set_name (flower[0], "Red Flower"); clutter_actor_add_child (vase, flower[0]); flower[1] = clutter_actor_new (); clutter_actor_set_background_color (flower[1], CLUTTER_COLOR_Yellow); clutter_actor_set_size (flower[1], 100, 100); clutter_actor_set_name (flower[1], "Yellow Flower"); clutter_actor_set_margin_right (flower[1], 6); clutter_actor_set_margin_left (flower[1], 6); clutter_actor_add_child (vase, flower[1]); flower[2] = clutter_actor_new (); clutter_actor_set_background_color (flower[2], CLUTTER_COLOR_Green); clutter_actor_set_size (flower[2], 100, 100); clutter_actor_set_name (flower[2], "Green Flower"); clutter_actor_set_margin_top (flower[2], 6); clutter_actor_set_margin_bottom (flower[2], 6); clutter_actor_add_child (vase, flower[2]); clutter_point_init (&p, 0, 7); clutter_test_assert_actor_at_point (stage, &p, flower[0]); clutter_point_init (&p, 106, 50); clutter_test_assert_actor_at_point (stage, &p, flower[1]); clutter_point_init (&p, 212, 7); clutter_test_assert_actor_at_point (stage, &p, flower[2]); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/layout/basic", actor_basic_layout) CLUTTER_TEST_UNIT ("/actor/layout/margin", actor_margin_layout) ) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/cally-text.c�����������������������������������������������������0000664�0001750�0001750�00000022443�14211404421�021662� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <string.h> #include <stdlib.h> #include "test-conform-common.h" #define TEST_FONT "Sans 10" typedef struct _CallbackData CallbackData; struct _CallbackData { ClutterActor *stage; ClutterActor *label; gint offset; gboolean test_failed; gint extents_x; gint extents_y; gint extents_width; gint extents_height; GSList *run_attributes; GSList *default_attributes; CallbackData *next; }; static gint attribute_lookup_func (gconstpointer data, gconstpointer user_data) { AtkAttribute *lookup_attr = (AtkAttribute*) user_data; AtkAttribute *at = (AtkAttribute *) data; if (!data) return -1; if (!g_strcmp0 (at->name, lookup_attr->name)) return g_strcmp0 (at->value, lookup_attr->value); return -1; } /* check l1 is a sub-set of l2 */ static gboolean compare_lists (GSList* l1, GSList* l2) { gboolean fail = FALSE; if (l2 && !l1) return TRUE; while (l1) { AtkAttribute *at = (AtkAttribute *) l1->data; GSList* result = g_slist_find_custom ((GSList*) l2, (gconstpointer) at, attribute_lookup_func); if (!result) { fail = TRUE; break; } l1 = g_slist_next (l1); } return fail; } static void dump_attribute_set (AtkAttributeSet *at_set) { GSList *attrs = (GSList*) at_set; while (attrs) { AtkAttribute *at = (AtkAttribute *) attrs->data; g_print ("text attribute %s = %s\n", at->name, at->value); attrs = g_slist_next (attrs); } } static gboolean check_result (CallbackData *data) { gboolean fail = FALSE; gchar *text = NULL; const gchar *expected_text = NULL; AtkObject *object = NULL; AtkText *cally_text = NULL; gunichar unichar; gunichar expected_char; gint x, y, width, height; gint pos; AtkAttributeSet *at_set = NULL; GSList *attrs; gint start = -1; gint end = -1; object = atk_gobject_accessible_for_object (G_OBJECT (data->label)); cally_text = ATK_TEXT (object); if (!cally_text) { g_print("no text\n"); return TRUE; } text = atk_text_get_text (cally_text, 0, -1); expected_text = clutter_text_get_text (CLUTTER_TEXT (data->label)); if (g_strcmp0 (expected_text, text) != 0) { if (g_test_verbose ()) g_print ("text value differs %s vs %s\n", expected_text, text); fail = TRUE; } unichar = atk_text_get_character_at_offset (cally_text, data->offset); expected_char = g_utf8_get_char (g_utf8_offset_to_pointer (text, data->offset)); if (expected_char != unichar) { if (g_test_verbose ()) g_print ("text af offset differs\n"); fail = TRUE; } atk_text_get_character_extents (cally_text, data->offset, &x, &y, &width, &height, ATK_XY_WINDOW); if (x != data->extents_x) { if (g_test_verbose ()) g_print ("extents x position at index 0 differs (current value=%d)\n", x); fail = TRUE; } if (y != data->extents_y) { if (g_test_verbose ()) g_print ("extents y position at index 0 differs (current value=%d)\n", y); fail = TRUE; } if (width != data->extents_width) { if (g_test_verbose ()) g_print ("extents width at index 0 differs (current value=%d)\n", width); fail = TRUE; } if (height != data->extents_height) { if (g_test_verbose ()) g_print ("extents height at index 0 differs (current value=%d)\n", height); fail = TRUE; } pos = atk_text_get_offset_at_point (cally_text, x, y, ATK_XY_WINDOW); if (pos != data->offset) { if (g_test_verbose ()) g_print ("offset at position (%d, %d) differs (current value=%d)\n", x, y, pos); fail = TRUE; } at_set = atk_text_get_run_attributes (cally_text, 0, &start, &end); if (start != 0) { if (g_test_verbose ()) g_print ("run attributes start offset is not 0: %d\n", start); fail = TRUE; } if (end != g_utf8_strlen (text, -1)) { if (g_test_verbose ()) g_print ("run attributes end offset is not text length: %d\n", end); fail = TRUE; } attrs = (GSList*) at_set; fail = compare_lists (attrs, data->run_attributes); if (fail && g_test_verbose ()) { g_print ("run attributes mismatch\n"); dump_attribute_set (attrs); } at_set = atk_text_get_default_attributes (cally_text); attrs = (GSList*) at_set; fail = compare_lists (attrs, data->default_attributes); if (fail && g_test_verbose ()) { g_print ("default attributes mismatch\n"); dump_attribute_set (attrs); } free (text); text = NULL; if (fail) { if (g_test_verbose ()) g_print ("FAIL\n"); data->test_failed = TRUE; } else if (g_test_verbose ()) g_print ("pass\n"); return fail; } static gboolean do_tests (CallbackData *data) { while (data) { gboolean result = check_result (data); g_assert (result == FALSE); data = data->next; } clutter_main_quit (); return FALSE; } static GSList* build_attribute_set (const gchar* first_attribute, ...) { AtkAttributeSet *return_set = g_slist_alloc (); va_list args; const gchar *name; const gchar *value; gint i = 0; value = first_attribute; va_start (args, first_attribute); while (value) { if ((i> 0) && (i % 2 != 0)) { AtkAttribute *at = malloc (sizeof (AtkAttribute)); at->name = g_strdup (name); at->value = g_strdup (value); return_set = g_slist_prepend (return_set, at); } i++; name = g_strdup (value); value = va_arg (args, gchar*); } va_end (args); return return_set; } void cally_text (void) { CallbackData data; CallbackData data1; GSList* default_attributes = build_attribute_set ("left-margin", "0", "right-margin", "0", "indent", "0", "invisible", "false", "editable", "false", "pixels-above-lines", "0", "pixels-below-lines", "0", "pixels-inside-wrap", "0", "bg-full-height", "0", "bg-stipple", "false", "fg-stipple", "false", "fg-color", "0,0,0", "wrap-mode", "word", "justification", "left", "size", "10", "weight", "400", "family-name", "Sans", "stretch", "normal", "variant", "normal", "style", "normal", "language", "en-us", "direction", "ltr", NULL); memset (&data, 0, sizeof (data)); data.stage = clutter_stage_new (); data.default_attributes = default_attributes; data.run_attributes = build_attribute_set ("fg-color", "0,0,0", NULL); data.label = clutter_text_new_with_text (TEST_FONT, "Lorem ipsum dolor sit amet"); clutter_container_add (CLUTTER_CONTAINER (data.stage), data.label, NULL); data.offset = 6; data.extents_x = 64; data.extents_y = 99; data.extents_width = 3; data.extents_height = 17; clutter_actor_set_position (data.label, 20, 100); memset (&data1, 0, sizeof (data1)); data1.stage = data.stage; data1.default_attributes = default_attributes; data1.run_attributes = build_attribute_set ("bg-color", "0,65535,0", "fg-color", "65535,65535,0", "strikethrough", "true", NULL); data1.label = clutter_text_new_with_text (TEST_FONT, ""); clutter_text_set_markup (CLUTTER_TEXT(data1.label), "<span fgcolor=\"#FFFF00\" bgcolor=\"#00FF00\"><s>Lorem ipsum dolor sit amet</s></span>"); clutter_container_add (CLUTTER_CONTAINER (data1.stage), data1.label, NULL); data1.offset = 10; data1.extents_x = 90; data1.extents_y = 199; data1.extents_width = 13; data1.extents_height = 17; clutter_actor_set_position (data1.label, 20, 200); data.next = &data1; clutter_actor_show (data.stage); clutter_threads_add_idle ((GSourceFunc) do_tests, &data); clutter_main (); clutter_actor_destroy (data.stage); if (g_test_verbose ()) g_print ("\nOverall result: "); if (g_test_verbose ()) { if (data.test_failed) g_print ("FAIL\n"); else g_print ("pass\n"); } else { g_assert (data.test_failed != TRUE); g_assert (data1.test_failed != TRUE); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/Makefile.am������������������������������������������������������0000664�0001750�0001750�00000004716�14211404421�021467� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������installed_test_metadir = $(datadir)/installed-tests/muffin-clutter installed_testdir = $(libexecdir)/installed-tests/muffin-clutter include $(top_srcdir)/build/autotools/glib-tap.mk AM_CFLAGS = -g $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) LDADD = $(top_builddir)/../cogl/cogl/libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la $(top_builddir)/clutter/libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la $(CLUTTER_LIBS) $(LIBM) AM_LDFLAGS = -export-dynamic AM_CPPFLAGS = \ -DG_LOG_DOMAIN=\"Clutter-Conform\" \ -I$(top_srcdir)/../cogl \ -I$(top_builddir)/../cogl \ -I$(top_builddir)/../cogl/cogl \ -I$(top_srcdir) \ -I$(top_builddir) \ -DCOGL_DISABLE_DEPRECATION_WARNINGS \ $(CLUTTER_DEPRECATED_CFLAGS) \ $(CLUTTER_DEBUG_CFLAGS) # Basic actor API actor_tests = \ actor-anchors \ actor-destroy \ actor-graph \ actor-invariants \ actor-iter \ actor-layout \ actor-meta \ actor-paint-opacity \ actor-pick \ actor-shader-effect \ actor-size \ $(NULL) # Disabled for offscreen-effect fix # actor-offscreen-redirect # actor-offscreen-limit-max-size # Actor classes classes_tests = \ text \ $(NULL) # General API general_tests = \ binding-pool \ color \ events-touch \ interval \ model \ script-parser \ units \ $(NULL) # Test for deprecated functionality deprecated_tests = \ animator \ behaviours \ group \ rectangle \ texture \ $(NULL) test_programs = $(actor_tests) $(general_tests) $(classes_tests) $(deprecated_tests) dist_test_data = $(script_ui_files) script_ui_files = $(addprefix scripts/,$(script_tests)) script_tests = \ test-animator-1.json \ test-animator-2.json \ test-animator-3.json \ test-script-animation.json \ test-script-child.json \ test-script-implicit-alpha.json \ test-script-interval.json \ test-script-layout-property.json \ test-script-margin.json \ test-script-model.json \ test-script-named-object.json \ test-script-object-property.json \ test-script-single.json \ test-script-timeline-markers.json \ test-state-1.json TESTS_ENVIRONMENT += G_ENABLE_DIAGNOSTIC=0 CLUTTER_ENABLE_DIAGNOSTIC=0 CLUTTER_SCALE=1 # simple rules for generating a Git ignore file for the conformance test suite $(srcdir)/.gitignore: Makefile $(AM_V_GEN)( echo "/*.trs" ; \ echo "/*.log" ; \ echo "/*.test" ; \ echo "/.gitignore" ; \ for p in $(test_programs); do \ echo "/$$p" ; \ done ) > $(@F) gitignore: $(srcdir)/.gitignore all-am: gitignore DISTCLEANFILES += .gitignore ��������������������������������������������������muffin-5.2.1/clutter/tests/conform/timeline-interpolate.c�������������������������������������������0000664�0001750�0001750�00000010051�14211404421�023716� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <clutter/clutter.h> #include "test-conform-common.h" /* We ask for 1 frame per millisecond. * Whenever this rate can't be achieved then the timeline * will interpolate the number frames that should have * passed between timeouts. */ #define TEST_TIMELINE_FPS 1000 #define TEST_TIMELINE_DURATION 5000 /* We are at the mercy of the system scheduler so this * may not be a very reliable tolerance. */ #define TEST_ERROR_TOLERANCE 20 typedef struct _TestState { ClutterTimeline *timeline; GTimeVal start_time; guint new_frame_counter; gint expected_frame; gint completion_count; gboolean passed; } TestState; static void new_frame_cb (ClutterTimeline *timeline, gint frame_num, TestState *state) { GTimeVal current_time; gint current_frame; glong msec_diff; gint loop_overflow = 0; static gint step = 1; g_get_current_time (¤t_time); current_frame = clutter_timeline_get_elapsed_time (state->timeline); msec_diff = (current_time.tv_sec - state->start_time.tv_sec) * 1000; msec_diff += (current_time.tv_usec - state->start_time.tv_usec)/1000; /* If we expect to have interpolated past the end of the timeline * we keep track of the overflow so we can determine when * the next timeout will happen. We then clip expected_frames * to TEST_TIMELINE_DURATION since clutter-timeline * semantics guaranty this frame is always signaled before * looping */ if (state->expected_frame > TEST_TIMELINE_DURATION) { loop_overflow = state->expected_frame - TEST_TIMELINE_DURATION; state->expected_frame = TEST_TIMELINE_DURATION; } if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE) && current_frame <= (state->expected_frame+TEST_ERROR_TOLERANCE)) { g_test_message ("elapsed milliseconds=%-5li " "expected frame=%-4i actual frame=%-4i (OK)", msec_diff, state->expected_frame, current_frame); } else { g_test_message ("elapsed milliseconds=%-5li " "expected frame=%-4i actual frame=%-4i (FAILED)", msec_diff, state->expected_frame, current_frame); state->passed = FALSE; } if (step>0) { state->expected_frame = current_frame + (TEST_TIMELINE_FPS / 4); g_test_message ("Sleeping for 250ms " "so next frame should be (%i + %i) = %i", current_frame, (TEST_TIMELINE_FPS / 4), state->expected_frame); g_usleep (250000); } else { state->expected_frame = current_frame + TEST_TIMELINE_FPS; g_test_message ("Sleeping for 1sec " "so next frame should be (%i + %i) = %i", current_frame, TEST_TIMELINE_FPS, state->expected_frame); g_usleep (1000000); } if (current_frame >= TEST_TIMELINE_DURATION) { state->expected_frame += loop_overflow; state->expected_frame -= TEST_TIMELINE_DURATION; g_test_message ("End of timeline reached: " "Wrapping expected frame too %i", state->expected_frame); } state->new_frame_counter++; step = -step; } static void completed_cb (ClutterTimeline *timeline, TestState *state) { state->completion_count++; if (state->completion_count == 2) { if (state->passed) { g_test_message ("Passed\n"); clutter_main_quit (); } else { g_test_message ("Failed\n"); exit (EXIT_FAILURE); } } } void timeline_interpolation (void) { TestState state; state.timeline = clutter_timeline_new (TEST_TIMELINE_DURATION); clutter_timeline_set_loop (state.timeline, TRUE); g_signal_connect (G_OBJECT(state.timeline), "new-frame", G_CALLBACK(new_frame_cb), &state); g_signal_connect (G_OBJECT(state.timeline), "completed", G_CALLBACK(completed_cb), &state); state.completion_count = 0; state.new_frame_counter = 0; state.passed = TRUE; state.expected_frame = 0; g_get_current_time (&state.start_time); clutter_timeline_start (state.timeline); clutter_main(); g_object_unref (state.timeline); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/script-parser.c��������������������������������������������������0000664�0001750�0001750�00000032145�14211404421�022372� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> #define TEST_TYPE_GROUP (test_group_get_type ()) #define TEST_TYPE_GROUP_META (test_group_meta_get_type ()) #define TEST_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_GROUP, TestGroup)) #define TEST_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_GROUP)) #define TEST_GROUP_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_GROUP_META, TestGroupMeta)) #define TEST_IS_GROUP_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_GROUP_META)) typedef struct _ClutterActor TestGroup; typedef struct _ClutterActorClass TestGroupClass; typedef struct _TestGroupMeta { ClutterChildMeta parent_instance; guint is_focus : 1; } TestGroupMeta; typedef struct _ClutterChildMetaClass TestGroupMetaClass; GType test_group_meta_get_type (void); G_DEFINE_TYPE (TestGroupMeta, test_group_meta, CLUTTER_TYPE_CHILD_META) enum { PROP_META_0, PROP_META_FOCUS }; static void test_group_meta_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { TestGroupMeta *self = TEST_GROUP_META (gobject); switch (prop_id) { case PROP_META_FOCUS: self->is_focus = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void test_group_meta_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { TestGroupMeta *self = TEST_GROUP_META (gobject); switch (prop_id) { case PROP_META_FOCUS: g_value_set_boolean (value, self->is_focus); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void test_group_meta_class_init (TestGroupMetaClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = test_group_meta_set_property; gobject_class->get_property = test_group_meta_get_property; pspec = g_param_spec_boolean ("focus", "Focus", "Focus", FALSE, G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_META_FOCUS, pspec); } static void test_group_meta_init (TestGroupMeta *meta) { meta->is_focus = FALSE; } static void clutter_container_iface_init (ClutterContainerIface *iface) { iface->child_meta_type = TEST_TYPE_GROUP_META; } GType test_group_get_type (void); G_DEFINE_TYPE_WITH_CODE (TestGroup, test_group, CLUTTER_TYPE_ACTOR, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER, clutter_container_iface_init)) static void test_group_class_init (TestGroupClass *klass) { } static void test_group_init (TestGroup *self) { } static void script_child (void) { ClutterScript *script = clutter_script_new (); GObject *container, *actor; GError *error = NULL; gboolean focus_ret; gchar *test_file; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-child.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); container = actor = NULL; clutter_script_get_objects (script, "test-group", &container, "test-rect-1", &actor, NULL); g_assert (TEST_IS_GROUP (container)); g_assert (CLUTTER_IS_RECTANGLE (actor)); focus_ret = FALSE; clutter_container_child_get (CLUTTER_CONTAINER (container), CLUTTER_ACTOR (actor), "focus", &focus_ret, NULL); g_assert (focus_ret); actor = clutter_script_get_object (script, "test-rect-2"); g_assert (CLUTTER_IS_RECTANGLE (actor)); focus_ret = FALSE; clutter_container_child_get (CLUTTER_CONTAINER (container), CLUTTER_ACTOR (actor), "focus", &focus_ret, NULL); g_assert (!focus_ret); g_object_unref (script); free (test_file); } static void script_single (void) { ClutterScript *script = clutter_script_new (); ClutterColor color = { 0, }; GObject *actor = NULL; GError *error = NULL; ClutterActor *rect; gchar *test_file; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-single.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); actor = clutter_script_get_object (script, "test"); g_assert (CLUTTER_IS_RECTANGLE (actor)); rect = CLUTTER_ACTOR (actor); g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 50.0); g_assert_cmpfloat (clutter_actor_get_y (rect), ==, 100.0); clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color); g_assert_cmpint (color.red, ==, 255); g_assert_cmpint (color.green, ==, 0xcc); g_assert_cmpint (color.alpha, ==, 0xff); g_object_unref (script); free (test_file); } static void script_implicit_alpha (void) { ClutterScript *script = clutter_script_new (); ClutterTimeline *timeline; GObject *behaviour = NULL; GError *error = NULL; ClutterAlpha *alpha; gchar *test_file; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-implicit-alpha.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); #if GLIB_CHECK_VERSION (2, 20, 0) g_assert_no_error (error); #else g_assert (error == NULL); #endif behaviour = clutter_script_get_object (script, "test"); g_assert (CLUTTER_IS_BEHAVIOUR (behaviour)); alpha = clutter_behaviour_get_alpha (CLUTTER_BEHAVIOUR (behaviour)); g_assert (CLUTTER_IS_ALPHA (alpha)); g_assert_cmpint (clutter_alpha_get_mode (alpha), ==, CLUTTER_EASE_OUT_CIRC); timeline = clutter_alpha_get_timeline (alpha); g_assert (CLUTTER_IS_TIMELINE (timeline)); g_assert_cmpint (clutter_timeline_get_duration (timeline), ==, 500); g_object_unref (script); free (test_file); } static void script_object_property (void) { ClutterScript *script = clutter_script_new (); ClutterLayoutManager *manager; GObject *actor = NULL; GError *error = NULL; gchar *test_file; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-object-property.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); actor = clutter_script_get_object (script, "test"); g_assert (CLUTTER_IS_BOX (actor)); manager = clutter_box_get_layout_manager (CLUTTER_BOX (actor)); g_assert (CLUTTER_IS_BIN_LAYOUT (manager)); g_object_unref (script); free (test_file); } static void script_named_object (void) { ClutterScript *script = clutter_script_new (); ClutterLayoutManager *manager; GObject *actor = NULL; GError *error = NULL; gchar *test_file; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-named-object.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); actor = clutter_script_get_object (script, "test"); g_assert (CLUTTER_IS_BOX (actor)); manager = clutter_box_get_layout_manager (CLUTTER_BOX (actor)); g_assert (CLUTTER_IS_BOX_LAYOUT (manager)); g_assert (clutter_box_layout_get_vertical (CLUTTER_BOX_LAYOUT (manager))); g_object_unref (script); free (test_file); } static void script_animation (void) { ClutterScript *script = clutter_script_new (); GObject *animation = NULL; GError *error = NULL; gchar *test_file; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-animation.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); animation = clutter_script_get_object (script, "test"); g_assert (CLUTTER_IS_ANIMATION (animation)); g_object_unref (script); free (test_file); } static void script_layout_property (void) { ClutterScript *script = clutter_script_new (); GObject *manager, *container, *actor1, *actor2; GError *error = NULL; gchar *test_file; gboolean x_fill, expand; ClutterBoxAlignment y_align; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-layout-property.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); manager = container = actor1 = actor2 = NULL; clutter_script_get_objects (script, "manager", &manager, "container", &container, "actor-1", &actor1, "actor-2", &actor2, NULL); g_assert (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_assert (CLUTTER_IS_CONTAINER (container)); g_assert (CLUTTER_IS_ACTOR (actor1)); g_assert (CLUTTER_IS_ACTOR (actor2)); x_fill = FALSE; y_align = CLUTTER_BOX_ALIGNMENT_START; expand = FALSE; clutter_layout_manager_child_get (CLUTTER_LAYOUT_MANAGER (manager), CLUTTER_CONTAINER (container), CLUTTER_ACTOR (actor1), "x-fill", &x_fill, "y-align", &y_align, "expand", &expand, NULL); g_assert (x_fill); g_assert (y_align == CLUTTER_BOX_ALIGNMENT_CENTER); g_assert (expand); x_fill = TRUE; y_align = CLUTTER_BOX_ALIGNMENT_START; expand = TRUE; clutter_layout_manager_child_get (CLUTTER_LAYOUT_MANAGER (manager), CLUTTER_CONTAINER (container), CLUTTER_ACTOR (actor2), "x-fill", &x_fill, "y-align", &y_align, "expand", &expand, NULL); g_assert (x_fill == FALSE); g_assert (y_align == CLUTTER_BOX_ALIGNMENT_END); g_assert (expand == FALSE); g_object_unref (script); } static void script_margin (void) { ClutterScript *script = clutter_script_new (); ClutterActor *actor; gchar *test_file; GError *error = NULL; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-margin.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-1")); g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f); g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 10.0f); g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 10.0f); g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 10.0f); actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-2")); g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f); g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 20.0f); g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 10.0f); g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 20.0f); actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-3")); g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f); g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 20.0f); g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 30.0f); g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 20.0f); actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-4")); g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f); g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 20.0f); g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 30.0f); g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 40.0f); g_object_unref (script); free (test_file); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/script/single-object", script_single) CLUTTER_TEST_UNIT ("/script/container-child", script_child) CLUTTER_TEST_UNIT ("/script/named-object", script_named_object) CLUTTER_TEST_UNIT ("/script/animation", script_animation) CLUTTER_TEST_UNIT ("/script/implicit-alpha", script_implicit_alpha) CLUTTER_TEST_UNIT ("/script/object-property", script_object_property) CLUTTER_TEST_UNIT ("/script/layout-property", script_layout_property) CLUTTER_TEST_UNIT ("/script/actor-margin", script_margin) ) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-shader-effect.c��������������������������������������������0000664�0001750�0001750�00000016705�14211404421�023406� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_ENABLE_EXPERIMENTAL_API #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> /**************************************************************** Old style shader effect This uses clutter_shader_effect_set_source ****************************************************************/ static const gchar old_shader_effect_source[] = "uniform vec3 override_color;\n" "\n" "void\n" "main ()\n" "{\n" " cogl_color_out = vec4 (override_color, 1.0);\n" "}"; typedef struct _FooOldShaderEffectClass { ClutterShaderEffectClass parent_class; } FooOldShaderEffectClass; typedef struct _FooOldShaderEffect { ClutterShaderEffect parent; } FooOldShaderEffect; GType foo_old_shader_effect_get_type (void); G_DEFINE_TYPE (FooOldShaderEffect, foo_old_shader_effect, CLUTTER_TYPE_SHADER_EFFECT); static void foo_old_shader_effect_paint_target (ClutterOffscreenEffect *effect) { clutter_shader_effect_set_shader_source (CLUTTER_SHADER_EFFECT (effect), old_shader_effect_source); clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect), "override_color", G_TYPE_FLOAT, 3, 1.0f, 0.0f, 0.0f); CLUTTER_OFFSCREEN_EFFECT_CLASS (foo_old_shader_effect_parent_class)-> paint_target (effect); } static void foo_old_shader_effect_class_init (FooOldShaderEffectClass *klass) { ClutterOffscreenEffectClass *offscreen_effect_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_effect_class->paint_target = foo_old_shader_effect_paint_target; } static void foo_old_shader_effect_init (FooOldShaderEffect *self) { } /**************************************************************** New style shader effect This overrides get_static_shader_source() ****************************************************************/ static const gchar new_shader_effect_source[] = "uniform vec3 override_color;\n" "\n" "void\n" "main ()\n" "{\n" " cogl_color_out = (vec4 (override_color, 1.0) +\n" " vec4 (0.0, 0.0, 1.0, 0.0));\n" "}"; typedef struct _FooNewShaderEffectClass { ClutterShaderEffectClass parent_class; } FooNewShaderEffectClass; typedef struct _FooNewShaderEffect { ClutterShaderEffect parent; } FooNewShaderEffect; GType foo_new_shader_effect_get_type (void); G_DEFINE_TYPE (FooNewShaderEffect, foo_new_shader_effect, CLUTTER_TYPE_SHADER_EFFECT); static gchar * foo_new_shader_effect_get_static_source (ClutterShaderEffect *effect) { static gboolean already_called = FALSE; /* This should only be called once even though we have two actors using this effect */ g_assert (!already_called); already_called = TRUE; return g_strdup (new_shader_effect_source); } static void foo_new_shader_effect_paint_target (ClutterOffscreenEffect *effect) { clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect), "override_color", G_TYPE_FLOAT, 3, 0.0f, 1.0f, 0.0f); CLUTTER_OFFSCREEN_EFFECT_CLASS (foo_new_shader_effect_parent_class)-> paint_target (effect); } static void foo_new_shader_effect_class_init (FooNewShaderEffectClass *klass) { ClutterOffscreenEffectClass *offscreen_effect_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); ClutterShaderEffectClass *shader_effect_class = CLUTTER_SHADER_EFFECT_CLASS (klass); offscreen_effect_class->paint_target = foo_new_shader_effect_paint_target; shader_effect_class->get_static_shader_source = foo_new_shader_effect_get_static_source; } static void foo_new_shader_effect_init (FooNewShaderEffect *self) { } /**************************************************************** Another new style shader effect This is the same but with a different shader. This is just sanity check that each class gets its own copy of the private data ****************************************************************/ static const gchar another_new_shader_effect_source[] = "\n" "void\n" "main ()\n" "{\n" " cogl_color_out = vec4 (1.0, 0.0, 1.0, 1.0);\n" "}"; typedef struct _FooAnotherNewShaderEffectClass { ClutterShaderEffectClass parent_class; } FooAnotherNewShaderEffectClass; typedef struct _FooAnotherNewShaderEffect { ClutterShaderEffect parent; } FooAnotherNewShaderEffect; GType foo_another_new_shader_effect_get_type (void); G_DEFINE_TYPE (FooAnotherNewShaderEffect, foo_another_new_shader_effect, CLUTTER_TYPE_SHADER_EFFECT); static gchar * foo_another_new_shader_effect_get_static_source (ClutterShaderEffect *effect) { return g_strdup (another_new_shader_effect_source); } static void foo_another_new_shader_effect_class_init (FooAnotherNewShaderEffectClass *klass) { ClutterShaderEffectClass *shader_effect_class = CLUTTER_SHADER_EFFECT_CLASS (klass); shader_effect_class->get_static_shader_source = foo_another_new_shader_effect_get_static_source; } static void foo_another_new_shader_effect_init (FooAnotherNewShaderEffect *self) { } /****************************************************************/ static ClutterActor * make_actor (GType shader_type) { ClutterActor *rect; const ClutterColor white = { 0xff, 0xff, 0xff, 0xff }; rect = clutter_rectangle_new (); clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &white); clutter_actor_set_size (rect, 50, 50); clutter_actor_add_effect (rect, g_object_new (shader_type, NULL)); return rect; } static guint32 get_pixel (int x, int y) { guint8 data[4]; cogl_read_pixels (x, y, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, data); return (((guint32) data[0] << 16) | ((guint32) data[1] << 8) | data[2]); } static void paint_cb (ClutterStage *stage, gpointer data) { gboolean *was_painted = data; /* old shader effect */ g_assert_cmpint (get_pixel (50, 50), ==, 0xff0000); /* new shader effect */ g_assert_cmpint (get_pixel (150, 50), ==, 0x00ffff); /* another new shader effect */ g_assert_cmpint (get_pixel (250, 50), ==, 0xff00ff); /* new shader effect */ g_assert_cmpint (get_pixel (350, 50), ==, 0x00ffff); *was_painted = TRUE; } static void actor_shader_effect (void) { ClutterActor *stage; ClutterActor *rect; gboolean was_painted; if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) return; stage = clutter_stage_new (); rect = make_actor (foo_old_shader_effect_get_type ()); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); rect = make_actor (foo_new_shader_effect_get_type ()); clutter_actor_set_x (rect, 100); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); rect = make_actor (foo_another_new_shader_effect_get_type ()); clutter_actor_set_x (rect, 200); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); rect = make_actor (foo_new_shader_effect_get_type ()); clutter_actor_set_x (rect, 300); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect); clutter_actor_show (stage); was_painted = FALSE; g_signal_connect (stage, "after-paint", G_CALLBACK (paint_cb), &was_painted); while (!was_painted) g_main_context_iteration (NULL, FALSE); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/shader-effect", actor_shader_effect) ) �����������������������������������������������������������muffin-5.2.1/clutter/tests/conform/texture.c��������������������������������������������������������0000664�0001750�0001750�00000005211�14211404421�021266� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> #include <string.h> static CoglHandle make_texture (void) { guint32 *data = malloc (100 * 100 * 4); int x; int y; for (y = 0; y < 100; y ++) for (x = 0; x < 100; x++) { if (x < 50 && y < 50) data[y * 100 + x] = 0xff00ff00; else data[y * 100 + x] = 0xff00ffff; } return cogl_texture_new_from_data (100, 100, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_ARGB_8888, COGL_PIXEL_FORMAT_ARGB_8888, 400, (guchar *)data); } static void texture_pick_with_alpha (void) { ClutterTexture *tex = CLUTTER_TEXTURE (clutter_texture_new ()); ClutterStage *stage = CLUTTER_STAGE (clutter_test_get_stage ()); ClutterActor *actor; clutter_texture_set_cogl_texture (tex, make_texture ()); clutter_actor_add_child (CLUTTER_ACTOR (stage), CLUTTER_ACTOR (tex)); clutter_actor_show (CLUTTER_ACTOR (stage)); if (g_test_verbose ()) { g_print ("\nstage = %p\n", stage); g_print ("texture = %p\n\n", tex); } clutter_texture_set_pick_with_alpha (tex, TRUE); if (g_test_verbose ()) g_print ("Testing with pick-with-alpha enabled:\n"); /* This should fall through and hit the stage: */ actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10); if (g_test_verbose ()) g_print ("actor @ (10, 10) = %p\n", actor); g_assert (actor == CLUTTER_ACTOR (stage)); /* The rest should hit the texture */ actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 10); if (g_test_verbose ()) g_print ("actor @ (90, 10) = %p\n", actor); g_assert (actor == CLUTTER_ACTOR (tex)); actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 90); if (g_test_verbose ()) g_print ("actor @ (90, 90) = %p\n", actor); g_assert (actor == CLUTTER_ACTOR (tex)); actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 90); if (g_test_verbose ()) g_print ("actor @ (10, 90) = %p\n", actor); g_assert (actor == CLUTTER_ACTOR (tex)); clutter_texture_set_pick_with_alpha (tex, FALSE); if (g_test_verbose ()) g_print ("Testing with pick-with-alpha disabled:\n"); actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10); if (g_test_verbose ()) g_print ("actor @ (10, 10) = %p\n", actor); g_assert (actor == CLUTTER_ACTOR (tex)); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/texture/pick-with-alpha", texture_pick_with_alpha) ) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/text.c�����������������������������������������������������������0000664�0001750�0001750�00000035304�14211404421�020560� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <clutter/clutter.h> #include <string.h> typedef struct { gunichar unichar; const char bytes[6]; gint nbytes; } TestData; static const TestData test_text_data[] = { { 0xe4, "\xc3\xa4", 2 }, /* LATIN SMALL LETTER A WITH DIAERESIS */ { 0x2665, "\xe2\x99\xa5", 3 } /* BLACK HEART SUIT */ }; static void text_utf8_validation (void) { int i; for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; gunichar unichar; char bytes[6]; int nbytes; g_assert (g_unichar_validate (t->unichar)); nbytes = g_unichar_to_utf8 (t->unichar, bytes); bytes[nbytes] = '\0'; g_assert_cmpint (nbytes, ==, t->nbytes); g_assert (memcmp (t->bytes, bytes, nbytes) == 0); unichar = g_utf8_get_char_validated (bytes, nbytes); g_assert_cmpint (unichar, ==, t->unichar); } } static int get_nbytes (ClutterText *text) { const char *s = clutter_text_get_text (text); return strlen (s); } static int get_nchars (ClutterText *text) { const char *s = clutter_text_get_text (text); g_assert (g_utf8_validate (s, -1, NULL)); return g_utf8_strlen (s, -1); } #define DONT_MOVE_CURSOR (-2) static void insert_unichar (ClutterText *text, gunichar unichar, int position) { if (position > DONT_MOVE_CURSOR) { clutter_text_set_cursor_position (text, position); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, position); } clutter_text_insert_unichar (text, unichar); } static void text_set_empty (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); g_object_ref_sink (text); g_assert_cmpstr (clutter_text_get_text (text), ==, ""); g_assert_cmpint (*clutter_text_get_text (text), ==, '\0'); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); clutter_text_set_text (text, ""); g_assert_cmpint (get_nchars (text), ==, 0); g_assert_cmpint (get_nbytes (text), ==, 0); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_set_text (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); g_object_ref_sink (text); clutter_text_set_text (text, "abcdef"); g_assert_cmpint (get_nchars (text), ==, 6); g_assert_cmpint (get_nbytes (text), ==, 6); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); clutter_text_set_cursor_position (text, 5); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 5); /* FIXME: cursor position should be -1? clutter_text_set_text (text, ""); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); */ clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_append_some (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); int i; g_object_ref_sink (text); for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; int j; for (j = 1; j <= 4; j++) { insert_unichar (text, t->unichar, DONT_MOVE_CURSOR); g_assert_cmpint (get_nchars (text), ==, j); g_assert_cmpint (get_nbytes (text), ==, j * t->nbytes); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); } clutter_text_set_text (text, ""); } clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_prepend_some (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); int i; g_object_ref_sink (text); for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; int j; clutter_text_insert_unichar (text, t->unichar); g_assert_cmpint (get_nchars (text), ==, 1); g_assert_cmpint (get_nbytes (text), ==, 1 * t->nbytes); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); for (j = 2; j <= 4; j++) { insert_unichar (text, t->unichar, 0); g_assert_cmpint (get_nchars (text), ==, j); g_assert_cmpint (get_nbytes (text), ==, j * t->nbytes); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1); } clutter_text_set_text (text, ""); } clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_insert (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); int i; g_object_ref_sink (text); for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; clutter_text_insert_unichar (text, t->unichar); clutter_text_insert_unichar (text, t->unichar); insert_unichar (text, t->unichar, 1); g_assert_cmpint (get_nchars (text), ==, 3); g_assert_cmpint (get_nbytes (text), ==, 3 * t->nbytes); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 2); clutter_text_set_text (text, ""); } clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_delete_chars (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); int i; g_object_ref_sink (text); for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; int j; for (j = 0; j < 4; j++) clutter_text_insert_unichar (text, t->unichar); if (g_test_verbose ()) g_print ("text: %s\n", clutter_text_get_text (text)); clutter_text_set_cursor_position (text, 2); clutter_text_delete_chars (text, 1); if (g_test_verbose ()) g_print ("text: %s (cursor at: %d)\n", clutter_text_get_text (text), clutter_text_get_cursor_position (text)); g_assert_cmpint (get_nchars (text), ==, 3); g_assert_cmpint (get_nbytes (text), ==, 3 * t->nbytes); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1); clutter_text_set_cursor_position (text, 2); clutter_text_delete_chars (text, 1); if (g_test_verbose ()) g_print ("text: %s (cursor at: %d)\n", clutter_text_get_text (text), clutter_text_get_cursor_position (text)); g_assert_cmpint (get_nchars (text), ==, 2); g_assert_cmpint (get_nbytes (text), ==, 2 * t->nbytes); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1); clutter_text_set_text (text, ""); } clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_get_chars (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); gchar *chars; g_object_ref_sink (text); clutter_text_set_text (text, "00abcdef11"); g_assert_cmpint (get_nchars (text), ==, 10); g_assert_cmpint (get_nbytes (text), ==, 10); g_assert_cmpstr (clutter_text_get_text (text), ==, "00abcdef11"); chars = clutter_text_get_chars (text, 2, -1); g_assert_cmpstr (chars, ==, "abcdef11"); free (chars); chars = clutter_text_get_chars (text, 0, 8); g_assert_cmpstr (chars, ==, "00abcdef"); free (chars); chars = clutter_text_get_chars (text, 2, 8); g_assert_cmpstr (chars, ==, "abcdef"); free (chars); chars = clutter_text_get_chars (text, 8, 12); g_assert_cmpstr (chars, ==, "11"); free (chars); clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_delete_text (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); int i; g_object_ref_sink (text); for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; int j; for (j = 0; j < 4; j++) clutter_text_insert_unichar (text, t->unichar); clutter_text_set_cursor_position (text, 3); clutter_text_delete_text (text, 2, 4); g_assert_cmpint (get_nchars (text), ==, 2); g_assert_cmpint (get_nbytes (text), ==, 2 * t->nbytes); /* FIXME: cursor position should be -1? g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); */ clutter_text_set_text (text, ""); } clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_password_char (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); g_object_ref_sink (text); g_assert_cmpint (clutter_text_get_password_char (text), ==, 0); clutter_text_set_text (text, "hello"); g_assert_cmpstr (clutter_text_get_text (text), ==, "hello"); clutter_text_set_password_char (text, '*'); g_assert_cmpint (clutter_text_get_password_char (text), ==, '*'); g_assert_cmpstr (clutter_text_get_text (text), ==, "hello"); clutter_actor_destroy (CLUTTER_ACTOR (text)); } static ClutterEvent * init_event (void) { ClutterEvent *retval = clutter_event_new (CLUTTER_KEY_PRESS); clutter_event_set_time (retval, CLUTTER_CURRENT_TIME); clutter_event_set_flags (retval, CLUTTER_EVENT_FLAG_SYNTHETIC); return retval; } static void send_keyval (ClutterText *text, int keyval) { ClutterEvent *event = init_event (); /* Unicode should be ignored for cursor keys etc. */ clutter_event_set_key_unicode (event, 0); clutter_event_set_key_symbol (event, keyval); clutter_actor_event (CLUTTER_ACTOR (text), event, FALSE); clutter_event_free (event); } static void send_unichar (ClutterText *text, gunichar unichar) { ClutterEvent *event = init_event (); /* Key symbol should be ignored for printable characters */ clutter_event_set_key_symbol (event, 0); clutter_event_set_key_unicode (event, unichar); clutter_actor_event (CLUTTER_ACTOR (text), event, FALSE); clutter_event_free (event); } static void text_cursor (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); int i; g_object_ref_sink (text); /* only editable entries listen to events */ clutter_text_set_editable (text, TRUE); for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; int j; for (j = 0; j < 4; ++j) clutter_text_insert_unichar (text, t->unichar); clutter_text_set_cursor_position (text, 2); /* test cursor moves and is clamped */ send_keyval (text, CLUTTER_KEY_Left); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1); send_keyval (text, CLUTTER_KEY_Left); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 0); send_keyval (text, CLUTTER_KEY_Left); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 0); /* delete text containing the cursor */ clutter_text_set_cursor_position (text, 3); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 3); clutter_text_delete_text (text, 2, 4); send_keyval (text, CLUTTER_KEY_Left); /* FIXME: cursor position should be -1? g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); */ clutter_text_set_text (text, ""); } clutter_actor_destroy (CLUTTER_ACTOR (text)); } static void text_event (void) { ClutterText *text = CLUTTER_TEXT (clutter_text_new ()); int i; g_object_ref_sink (text); /* only editable entries listen to events */ clutter_text_set_editable (text, TRUE); for (i = 0; i < G_N_ELEMENTS (test_text_data); i++) { const TestData *t = &test_text_data[i]; send_unichar (text, t->unichar); g_assert_cmpint (get_nchars (text), ==, 1); g_assert_cmpint (get_nbytes (text), ==, 1 * t->nbytes); g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1); clutter_text_set_text (text, ""); } clutter_actor_destroy (CLUTTER_ACTOR (text)); } static inline void validate_markup_attributes (ClutterText *text, PangoAttrType attr_type, int start_index, int end_index) { PangoLayout *layout; PangoAttrList *attrs; PangoAttrIterator *iter; layout = clutter_text_get_layout (text); g_assert (layout != NULL); attrs = pango_layout_get_attributes (layout); g_assert (attrs != NULL); iter = pango_attr_list_get_iterator (attrs); while (pango_attr_iterator_next (iter)) { GSList *attributes = pango_attr_iterator_get_attrs (iter); PangoAttribute *a; if (attributes == NULL) break; g_assert (attributes->data != NULL); a = attributes->data; g_assert (a->klass->type == attr_type); g_assert_cmpint (a->start_index, ==, start_index); g_assert_cmpint (a->end_index, ==, end_index); g_slist_free_full (attributes, (GDestroyNotify) pango_attribute_destroy); } pango_attr_iterator_destroy (iter); } static void text_idempotent_use_markup (void) { ClutterText *text; const char *contents = "foo <b>bar</b>"; const char *display = "foo bar"; int bar_start_index = strstr (display, "bar") - display; int bar_end_index = bar_start_index + strlen ("bar"); /* case 1: text -> use_markup */ if (g_test_verbose ()) g_print ("text: '%s' -> use-markup: TRUE\n", contents); text = g_object_new (CLUTTER_TYPE_TEXT, "text", contents, "use-markup", TRUE, NULL); g_object_ref_sink (text); if (g_test_verbose ()) g_print ("Contents: '%s' (expected: '%s')\n", clutter_text_get_text (text), display); g_assert_cmpstr (clutter_text_get_text (text), ==, display); validate_markup_attributes (text, PANGO_ATTR_WEIGHT, bar_start_index, bar_end_index); clutter_actor_destroy (CLUTTER_ACTOR (text)); /* case 2: use_markup -> text */ if (g_test_verbose ()) g_print ("use-markup: TRUE -> text: '%s'\n", contents); text = g_object_new (CLUTTER_TYPE_TEXT, "use-markup", TRUE, "text", contents, NULL); if (g_test_verbose ()) g_print ("Contents: '%s' (expected: '%s')\n", clutter_text_get_text (text), display); g_assert_cmpstr (clutter_text_get_text (text), ==, display); validate_markup_attributes (text, PANGO_ATTR_WEIGHT, bar_start_index, bar_end_index); clutter_actor_destroy (CLUTTER_ACTOR (text)); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/text/utf8-validation", text_utf8_validation) CLUTTER_TEST_UNIT ("/text/set-empty", text_set_empty) CLUTTER_TEST_UNIT ("/text/set-text", text_set_text) CLUTTER_TEST_UNIT ("/text/append-some", text_append_some) CLUTTER_TEST_UNIT ("/text/prepend-some", text_prepend_some) CLUTTER_TEST_UNIT ("/text/insert", text_insert) CLUTTER_TEST_UNIT ("/text/delete-chars", text_delete_chars) CLUTTER_TEST_UNIT ("/text/get-chars", text_get_chars) CLUTTER_TEST_UNIT ("/text/delete-text", text_delete_text) CLUTTER_TEST_UNIT ("/text/password-char", text_password_char) CLUTTER_TEST_UNIT ("/text/cursor", text_cursor) CLUTTER_TEST_UNIT ("/text/event", text_event) CLUTTER_TEST_UNIT ("/text/idempotent-use-markup", text_idempotent_use_markup) ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-destroy.c��������������������������������������������������0000664�0001750�0001750�00000012165�14211404421�022373� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> #define TEST_TYPE_DESTROY (test_destroy_get_type ()) #define TEST_DESTROY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_DESTROY, TestDestroy)) #define TEST_IS_DESTROY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_DESTROY)) typedef struct _TestDestroy TestDestroy; typedef struct _TestDestroyClass TestDestroyClass; struct _TestDestroy { ClutterActor parent_instance; ClutterActor *bg; ClutterActor *label; ClutterActor *tex; GList *children; }; struct _TestDestroyClass { ClutterActorClass parent_class; }; static void clutter_container_init (ClutterContainerIface *iface); GType test_destroy_get_type (void); G_DEFINE_TYPE_WITH_CODE (TestDestroy, test_destroy, CLUTTER_TYPE_ACTOR, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER, clutter_container_init)); static void test_destroy_add (ClutterContainer *container, ClutterActor *actor) { TestDestroy *self = TEST_DESTROY (container); if (g_test_verbose ()) g_print ("Adding '%s' (type:%s)\n", clutter_actor_get_name (actor), G_OBJECT_TYPE_NAME (actor)); self->children = g_list_prepend (self->children, actor); clutter_actor_set_parent (actor, CLUTTER_ACTOR (container)); } static void test_destroy_remove (ClutterContainer *container, ClutterActor *actor) { TestDestroy *self = TEST_DESTROY (container); if (g_test_verbose ()) g_print ("Removing '%s' (type:%s)\n", clutter_actor_get_name (actor), G_OBJECT_TYPE_NAME (actor)); g_assert (actor != self->bg); g_assert (actor != self->label); if (!g_list_find (self->children, actor)) g_assert (actor == self->tex); else self->children = g_list_remove (self->children, actor); clutter_actor_unparent (actor); } static void clutter_container_init (ClutterContainerIface *iface) { iface->add = test_destroy_add; iface->remove = test_destroy_remove; } static void test_destroy_destroy (ClutterActor *self) { TestDestroy *test = TEST_DESTROY (self); if (test->bg != NULL) { if (g_test_verbose ()) g_print ("Destroying '%s' (type:%s)\n", clutter_actor_get_name (test->bg), G_OBJECT_TYPE_NAME (test->bg)); clutter_actor_destroy (test->bg); test->bg = NULL; } if (test->label != NULL) { if (g_test_verbose ()) g_print ("Destroying '%s' (type:%s)\n", clutter_actor_get_name (test->label), G_OBJECT_TYPE_NAME (test->label)); clutter_actor_destroy (test->label); test->label = NULL; } if (test->tex != NULL) { if (g_test_verbose ()) g_print ("Destroying '%s' (type:%s)\n", clutter_actor_get_name (test->tex), G_OBJECT_TYPE_NAME (test->tex)); clutter_actor_destroy (test->tex); test->tex = NULL; } g_list_foreach (test->children, (GFunc) clutter_actor_destroy, NULL); g_list_free (test->children); test->children = NULL; if (CLUTTER_ACTOR_CLASS (test_destroy_parent_class)->destroy) CLUTTER_ACTOR_CLASS (test_destroy_parent_class)->destroy (self); } static void test_destroy_class_init (TestDestroyClass *klass) { ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); actor_class->destroy = test_destroy_destroy; } static void test_destroy_init (TestDestroy *self) { clutter_actor_push_internal (CLUTTER_ACTOR (self)); if (g_test_verbose ()) g_print ("Adding internal children...\n"); self->bg = clutter_rectangle_new (); clutter_actor_set_parent (self->bg, CLUTTER_ACTOR (self)); clutter_actor_set_name (self->bg, "Background"); self->label = clutter_text_new (); clutter_actor_set_parent (self->label, CLUTTER_ACTOR (self)); clutter_actor_set_name (self->label, "Label"); clutter_actor_pop_internal (CLUTTER_ACTOR (self)); self->tex = clutter_texture_new (); clutter_actor_set_parent (self->tex, CLUTTER_ACTOR (self)); clutter_actor_set_name (self->tex, "Texture"); } static void on_destroy (ClutterActor *actor, gpointer data) { gboolean *destroy_called = data; *destroy_called = TRUE; } static void actor_destruction (void) { ClutterActor *test = g_object_new (TEST_TYPE_DESTROY, NULL); ClutterActor *child = clutter_rectangle_new (); gboolean destroy_called = FALSE; g_object_ref_sink (test); g_object_add_weak_pointer (G_OBJECT (test), (gpointer *) &test); g_object_add_weak_pointer (G_OBJECT (child), (gpointer *) &child); if (g_test_verbose ()) g_print ("Adding external child...\n"); clutter_actor_set_name (child, "Child"); clutter_container_add_actor (CLUTTER_CONTAINER (test), child); g_signal_connect (child, "destroy", G_CALLBACK (on_destroy), &destroy_called); if (g_test_verbose ()) g_print ("Calling destroy()...\n"); clutter_actor_destroy (test); g_assert (destroy_called); g_assert_null (child); g_assert_null (test); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/destruction", actor_destruction) ) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/text-cache.c�����������������������������������������������������0000664�0001750�0001750�00000022312�14211404421�021614� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <string.h> #include <stdlib.h> #include "test-conform-common.h" #define TEST_FONT "Sans 10" static const char long_text[] = "<b>This</b> <i>is</i> some <span size=\"x-large\">REALLY</span> " "long text that contains markup for testing the <tt>use_markup</tt> " "property and to test word-wrapping, justification and alignment."; typedef struct _CallbackData CallbackData; struct _CallbackData { ClutterActor *stage; ClutterActor *label; PangoLayout *old_layout; gboolean layout_changed; PangoRectangle label_extents; PangoLayout *test_layout; gboolean test_failed; }; static void on_paint (ClutterActor *stage, CallbackData *data) { PangoLayout *new_layout; /* Check whether the layout used for this paint is different from the layout used for the last paint */ new_layout = clutter_text_get_layout (CLUTTER_TEXT (data->label)); data->layout_changed = data->old_layout != new_layout; if (data->old_layout) g_object_unref (data->old_layout); /* Keep a reference to the old layout so we can be sure it won't just reallocate a new layout with the same address */ data->old_layout = g_object_ref (new_layout); pango_layout_get_extents (new_layout, NULL, &data->label_extents); } static void force_redraw (CallbackData *data) { /* XXX - this is fugly; we force a paint on the stage, which * will then paint the Text actor. inside the Text actor we * check for a Layout with the allocation size. if the allocation * has changed it will cause a relayout in the middle of the * paint, which is expensive and broken. this will ensure that * the test passes, though */ clutter_actor_paint (clutter_actor_get_stage (data->label)); } static gboolean check_result (CallbackData *data, const char *note, gboolean layout_should_change) { PangoRectangle test_extents; gboolean fail = FALSE; if (g_test_verbose ()) g_print ("%s: ", note); /* Force a redraw to get the on_paint handler to run */ force_redraw (data); /* Compare the extents from the label with the extents from our test layout */ pango_layout_get_extents (data->test_layout, NULL, &test_extents); if (memcmp (&test_extents, &data->label_extents, sizeof (PangoRectangle))) { if (g_test_verbose ()) g_print ("extents are different: expected: %d, %d, %d, %d " "-> text: %d, %d, %d, %d\n", test_extents.x / 1024, test_extents.y / 1024, test_extents.width / 1024, test_extents.height / 1024, data->label_extents.x / 1024, data->label_extents.y / 1024, data->label_extents.width / 1024, data->label_extents.height / 1024); fail = TRUE; } else { if (g_test_verbose ()) g_print ("extents are the same, "); } if (data->layout_changed) { if (g_test_verbose ()) g_print ("layout changed, "); } else { if (g_test_verbose ()) g_print ("layout did not change, "); } if (data->layout_changed != layout_should_change) fail = TRUE; if (fail) { if (g_test_verbose ()) g_print ("FAIL\n"); data->test_failed = TRUE; } else { if (g_test_verbose ()) g_print ("pass\n"); } return fail; } static gboolean do_tests (CallbackData *data) { PangoFontDescription *fd; static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff }; PangoAttrList *attr_list, *attr_list_copy; PangoAttribute *attr; /* TEST 1: change the text */ clutter_text_set_text (CLUTTER_TEXT (data->label), "Counter 0"); pango_layout_set_text (data->test_layout, "Counter 0", -1); g_assert (check_result (data, "Change text", TRUE) == FALSE); /* TEST 2: change a single character */ clutter_text_set_text (CLUTTER_TEXT (data->label), "Counter 1"); pango_layout_set_text (data->test_layout, "Counter 1", -1); g_assert (check_result (data, "Change a single character", TRUE) == FALSE); /* TEST 3: move the label */ clutter_actor_set_position (data->label, 10, 0); g_assert (check_result (data, "Move the label", FALSE) == FALSE); /* TEST 4: change the font */ clutter_text_set_font_name (CLUTTER_TEXT (data->label), "Serif 15"); fd = pango_font_description_from_string ("Serif 15"); pango_layout_set_font_description (data->test_layout, fd); pango_font_description_free (fd); g_assert (check_result (data, "Change the font", TRUE) == FALSE); /* TEST 5: change the color */ clutter_text_set_color (CLUTTER_TEXT (data->label), &red); g_assert (check_result (data, "Change the color", FALSE) == FALSE); /* TEST 6: change the attributes */ attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); attr->start_index = 0; attr->end_index = 2; attr_list = pango_attr_list_new (); pango_attr_list_insert (attr_list, attr); attr_list_copy = pango_attr_list_copy (attr_list); clutter_text_set_attributes (CLUTTER_TEXT (data->label), attr_list); pango_layout_set_attributes (data->test_layout, attr_list_copy); pango_attr_list_unref (attr_list_copy); pango_attr_list_unref (attr_list); g_assert (check_result (data, "Change the attributes", TRUE) == FALSE); /* TEST 7: change the text again */ clutter_text_set_attributes (CLUTTER_TEXT (data->label), NULL); clutter_text_set_text (CLUTTER_TEXT (data->label), long_text); pango_layout_set_attributes (data->test_layout, NULL); pango_layout_set_text (data->test_layout, long_text, -1); g_assert (check_result (data, "Change the text again", TRUE) == FALSE); /* TEST 8: enable markup */ clutter_text_set_use_markup (CLUTTER_TEXT (data->label), TRUE); pango_layout_set_markup (data->test_layout, long_text, -1); g_assert (check_result (data, "Enable markup", TRUE) == FALSE); /* This part can't be a test because Clutter won't restrict the width if wrapping and ellipsizing is disabled so the extents will be different, but we still want to do it for the later tests */ clutter_actor_set_width (data->label, 200); pango_layout_set_width (data->test_layout, 200 * PANGO_SCALE); /* Force a redraw so that changing the width won't affect the results */ force_redraw (data); /* TEST 9: enable ellipsize */ clutter_text_set_ellipsize (CLUTTER_TEXT (data->label), PANGO_ELLIPSIZE_END); pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_END); g_assert (check_result (data, "Enable ellipsize", TRUE) == FALSE); clutter_text_set_ellipsize (CLUTTER_TEXT (data->label), PANGO_ELLIPSIZE_NONE); pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_NONE); force_redraw (data); /* TEST 10: enable line wrap */ clutter_text_set_line_wrap (CLUTTER_TEXT (data->label), TRUE); pango_layout_set_wrap (data->test_layout, PANGO_WRAP_WORD); g_assert (check_result (data, "Enable line wrap", TRUE) == FALSE); /* TEST 11: change wrap mode * FIXME - broken */ clutter_text_set_line_wrap_mode (CLUTTER_TEXT (data->label), PANGO_WRAP_CHAR); pango_layout_set_wrap (data->test_layout, PANGO_WRAP_CHAR); g_assert (check_result (data, "Change wrap mode", TRUE) == FALSE); /* TEST 12: enable justify */ clutter_text_set_justify (CLUTTER_TEXT (data->label), TRUE); pango_layout_set_justify (data->test_layout, TRUE); /* Pango appears to have a bug which means that you can't change the justification after setting the text but this fixes it. See http://bugzilla.gnome.org/show_bug.cgi?id=551865 */ pango_layout_context_changed (data->test_layout); g_assert (check_result (data, "Enable justify", TRUE) == FALSE); /* TEST 13: change alignment */ clutter_text_set_line_alignment (CLUTTER_TEXT (data->label), PANGO_ALIGN_RIGHT); pango_layout_set_alignment (data->test_layout, PANGO_ALIGN_RIGHT); g_assert (check_result (data, "Change alignment", TRUE) == FALSE); clutter_main_quit (); return FALSE; } static PangoLayout * make_layout_like_label (ClutterText *label) { PangoLayout *label_layout, *new_layout; PangoContext *context; PangoFontDescription *fd; /* Make another layout using the same context as the layout from the label */ label_layout = clutter_text_get_layout (label); context = pango_layout_get_context (label_layout); new_layout = pango_layout_new (context); fd = pango_font_description_from_string (TEST_FONT); pango_layout_set_font_description (new_layout, fd); pango_font_description_free (fd); return new_layout; } void text_cache (void) { CallbackData data; memset (&data, 0, sizeof (data)); data.stage = clutter_stage_new (); data.label = clutter_text_new_with_text (TEST_FONT, ""); data.test_layout = make_layout_like_label (CLUTTER_TEXT (data.label)); g_signal_connect (data.stage, "paint", G_CALLBACK (on_paint), &data); clutter_container_add (CLUTTER_CONTAINER (data.stage), data.label, NULL); clutter_actor_show (data.stage); clutter_threads_add_idle ((GSourceFunc) do_tests, &data); clutter_main (); clutter_actor_destroy (data.stage); if (g_test_verbose ()) g_print ("\nOverall result: "); if (g_test_verbose ()) { if (data.test_failed) g_print ("FAIL\n"); else g_print ("pass\n"); } else g_assert (data.test_failed != TRUE); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-offscreen-redirect.c���������������������������������������0000664�0001750�0001750�00000022613�14211404421�024452� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> typedef struct _FooActor FooActor; typedef struct _FooActorClass FooActorClass; struct _FooActorClass { ClutterActorClass parent_class; }; struct _FooActor { ClutterActor parent; guint8 last_paint_opacity; int paint_count; }; typedef struct { ClutterActor *stage; FooActor *foo_actor; ClutterActor *parent_container; ClutterActor *container; ClutterActor *child; ClutterActor *unrelated_actor; gboolean was_painted; } Data; GType foo_actor_get_type (void) G_GNUC_CONST; G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR); static gboolean group_has_overlaps; static void foo_actor_paint (ClutterActor *actor) { FooActor *foo_actor = (FooActor *) actor; ClutterActorBox allocation; foo_actor->last_paint_opacity = clutter_actor_get_paint_opacity (actor); foo_actor->paint_count++; clutter_actor_get_allocation_box (actor, &allocation); /* Paint a red rectangle with the right opacity */ cogl_set_source_color4ub (255, 0, 0, foo_actor->last_paint_opacity); cogl_rectangle (allocation.x1, allocation.y1, allocation.x2, allocation.y2); } static gboolean foo_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { return clutter_paint_volume_set_from_allocation (volume, actor); } static gboolean foo_actor_has_overlaps (ClutterActor *actor) { return FALSE; } static void foo_actor_class_init (FooActorClass *klass) { ClutterActorClass *actor_class = (ClutterActorClass *) klass; actor_class->paint = foo_actor_paint; actor_class->get_paint_volume = foo_actor_get_paint_volume; actor_class->has_overlaps = foo_actor_has_overlaps; } static void foo_actor_init (FooActor *self) { } typedef struct _FooGroup FooGroup; typedef struct _FooGroupClass FooGroupClass; struct _FooGroupClass { ClutterActorClass parent_class; }; struct _FooGroup { ClutterActor parent; }; GType foo_group_get_type (void); G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_ACTOR) static gboolean foo_group_has_overlaps (ClutterActor *actor) { return group_has_overlaps; } static void foo_group_class_init (FooGroupClass *klass) { ClutterActorClass *actor_class = (ClutterActorClass *) klass; actor_class->has_overlaps = foo_group_has_overlaps; } static void foo_group_init (FooGroup *self) { } static void verify_results (Data *data, guint8 expected_color_red, guint8 expected_color_green, guint8 expected_color_blue, int expected_paint_count, int expected_paint_opacity) { guchar *pixel; data->foo_actor->paint_count = 0; /* Read a pixel at the center of the to determine what color it painted. This should cause a redraw */ pixel = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage), 50, 50, /* x/y */ 1, 1 /* width/height */); g_assert_cmpint (expected_paint_count, ==, data->foo_actor->paint_count); g_assert_cmpint (expected_paint_opacity, ==, data->foo_actor->last_paint_opacity); g_assert_cmpint (ABS ((int) expected_color_red - (int) pixel[0]), <=, 2); g_assert_cmpint (ABS ((int) expected_color_green - (int) pixel[1]), <=, 2); g_assert_cmpint (ABS ((int) expected_color_blue - (int) pixel[2]), <=, 2); free (pixel); } static void verify_redraw (Data *data, int expected_paint_count) { GMainLoop *main_loop = g_main_loop_new (NULL, TRUE); guint paint_handler; paint_handler = g_signal_connect_data (data->stage, "paint", G_CALLBACK (g_main_loop_quit), main_loop, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER); /* Queue a redraw on the stage */ clutter_actor_queue_redraw (data->stage); data->foo_actor->paint_count = 0; /* Wait for it to paint */ g_main_loop_run (main_loop); g_signal_handler_disconnect (data->stage, paint_handler); g_assert_cmpint (data->foo_actor->paint_count, ==, expected_paint_count); } static gboolean verify_redraws (gpointer user_data) { Data *data = user_data; /* Queueing a redraw on the actor should cause a redraw */ clutter_actor_queue_redraw (data->container); verify_redraw (data, 1); /* Queueing a redraw on a child should cause a redraw */ clutter_actor_queue_redraw (data->child); verify_redraw (data, 1); /* Modifying the transformation on the parent should cause a redraw */ clutter_actor_set_anchor_point (data->parent_container, 0, 1); verify_redraw (data, 1); /* Redrawing an unrelated actor shouldn't cause a redraw */ clutter_actor_set_position (data->unrelated_actor, 0, 1); verify_redraw (data, 0); data->was_painted = TRUE; return G_SOURCE_REMOVE; } static gboolean run_verify (gpointer user_data) { Data *data = user_data; group_has_overlaps = FALSE; /* By default the actor shouldn't be redirected so the redraw should cause the actor to be painted */ verify_results (data, 255, 0, 0, 1, 255); /* Make the actor semi-transparent and verify the paint opacity */ clutter_actor_set_opacity (data->container, 127); verify_results (data, 255, 127, 127, 1, 127); /* With automatic redirect for opacity it shouldn't redirect if * has_overlaps returns FALSE; */ clutter_actor_set_offscreen_redirect (data->container, CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY); verify_results (data, 255, 127, 127, 1, 127); /* We do a double check here to verify that the actor wasn't cached * during the last check. If it was cached then this check wouldn't * result in any foo-actor re-paint. */ verify_results (data, 255, 127, 127, 1, 127); /* With automatic redirect for opacity it should redirect if * has_overlaps returns TRUE. * The first paint will still cause the actor to draw because * it needs to fill the cache first. It should be painted with full * opacity */ group_has_overlaps = TRUE; verify_results (data, 255, 127, 127, 1, 255); /* The second time the actor is painted it should be cached */ verify_results (data, 255, 127, 127, 0, 255); /* We should be able to change the opacity without causing the actor to redraw */ clutter_actor_set_opacity (data->container, 64); verify_results (data, 255, 191, 191, 0, 255); /* Changing it back to fully opaque should cause it not to go through the FBO so it will draw */ clutter_actor_set_opacity (data->container, 255); verify_results (data, 255, 0, 0, 1, 255); /* Tell it to always redirect through the FBO. This should cause a paint of the actor because the last draw didn't go through the FBO */ clutter_actor_set_offscreen_redirect (data->container, CLUTTER_OFFSCREEN_REDIRECT_ALWAYS); verify_results (data, 255, 0, 0, 1, 255); /* We should be able to change the opacity without causing the actor to redraw */ clutter_actor_set_opacity (data->container, 64); verify_results (data, 255, 191, 191, 0, 255); /* Even changing it back to fully opaque shouldn't cause a redraw */ clutter_actor_set_opacity (data->container, 255); verify_results (data, 255, 0, 0, 0, 255); /* Check redraws */ g_idle_add (verify_redraws, data); return G_SOURCE_REMOVE; } static void actor_offscreen_redirect (void) { Data data = { 0 }; if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) return; data.stage = clutter_test_get_stage (); data.parent_container = clutter_actor_new (); data.container = g_object_new (foo_group_get_type (), NULL); data.foo_actor = g_object_new (foo_actor_get_type (), NULL); clutter_actor_set_size (CLUTTER_ACTOR (data.foo_actor), 100, 100); clutter_actor_add_child (data.container, CLUTTER_ACTOR (data.foo_actor)); clutter_actor_add_child (data.parent_container, data.container); clutter_actor_add_child (data.stage, data.parent_container); data.child = clutter_actor_new (); clutter_actor_set_size (data.child, 1, 1); clutter_actor_add_child (data.container, data.child); data.unrelated_actor = clutter_actor_new (); clutter_actor_set_size (data.child, 1, 1); clutter_actor_add_child (data.stage, data.unrelated_actor); clutter_actor_show (data.stage); clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT, run_verify, &data, NULL); while (!data.was_painted) g_main_context_iteration (NULL, FALSE); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/offscreen/redirect", actor_offscreen_redirect) ) ���������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-paint-opacity.c��������������������������������������������0000664�0001750�0001750�00000011034�14211404421�023455� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <stdlib.h> static void opacity_label (void) { ClutterActor *stage; ClutterActor *label; ClutterColor label_color = { 255, 0, 0, 128 }; ClutterColor color_check = { 0, }; stage = clutter_test_get_stage (); label = clutter_text_new_with_text ("Sans 18px", "Label, 50% opacity"); clutter_text_set_color (CLUTTER_TEXT (label), &label_color); if (g_test_verbose ()) g_print ("label 50%%.get_color()/1\n"); clutter_text_get_color (CLUTTER_TEXT (label), &color_check); g_assert (color_check.alpha == label_color.alpha); clutter_actor_add_child (stage, label); clutter_actor_set_position (label, 10, 10); if (g_test_verbose ()) g_print ("label 50%%.get_color()/2\n"); clutter_text_get_color (CLUTTER_TEXT (label), &color_check); g_assert (color_check.alpha == label_color.alpha); if (g_test_verbose ()) g_print ("label 50%%.get_paint_opacity()/1\n"); g_assert (clutter_actor_get_paint_opacity (label) == 255); if (g_test_verbose ()) g_print ("label 50%%.get_paint_opacity()/2\n"); clutter_actor_set_opacity (label, 128); g_assert (clutter_actor_get_paint_opacity (label) == 128); } G_GNUC_BEGIN_IGNORE_DEPRECATIONS static void opacity_rectangle (void) { ClutterActor *stage; ClutterActor *rect; ClutterColor rect_color = { 0, 0, 255, 255 }; ClutterColor color_check = { 0, }; stage = clutter_test_get_stage (); rect = clutter_rectangle_new_with_color (&rect_color); clutter_actor_set_size (rect, 128, 128); clutter_actor_set_position (rect, 150, 90); if (g_test_verbose ()) g_print ("rect 100%%.get_color()/1\n"); clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check); g_assert (color_check.alpha == rect_color.alpha); clutter_actor_add_child (stage, rect); if (g_test_verbose ()) g_print ("rect 100%%.get_color()/2\n"); clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check); g_assert (color_check.alpha == rect_color.alpha); if (g_test_verbose ()) g_print ("rect 100%%.get_paint_opacity()\n"); g_assert (clutter_actor_get_paint_opacity (rect) == 255); } G_GNUC_END_IGNORE_DEPRECATIONS G_GNUC_BEGIN_IGNORE_DEPRECATIONS static void opacity_paint (void) { ClutterActor *stage, *group1, *group2; ClutterActor *label, *rect; ClutterColor label_color = { 255, 0, 0, 128 }; ClutterColor rect_color = { 0, 0, 255, 255 }; ClutterColor color_check = { 0, }; stage = clutter_test_get_stage (); group1 = clutter_group_new (); clutter_actor_set_opacity (group1, 128); clutter_container_add (CLUTTER_CONTAINER (stage), group1, NULL); clutter_actor_set_position (group1, 10, 30); clutter_actor_show (group1); label = clutter_text_new_with_text ("Sans 18px", "Label+Group, 25% opacity"); clutter_text_set_color (CLUTTER_TEXT (label), &label_color); if (g_test_verbose ()) g_print ("label 50%% + group 50%%.get_color()/1\n"); clutter_text_get_color (CLUTTER_TEXT (label), &color_check); g_assert (color_check.alpha == label_color.alpha); clutter_container_add (CLUTTER_CONTAINER (group1), label, NULL); if (g_test_verbose ()) g_print ("label 50%% + group 50%%.get_color()/2\n"); clutter_text_get_color (CLUTTER_TEXT (label), &color_check); g_assert (color_check.alpha == label_color.alpha); if (g_test_verbose ()) g_print ("label 50%% + group 50%%.get_paint_opacity() = 128\n"); g_assert (clutter_actor_get_paint_opacity (label) == 128); clutter_actor_destroy (label); group2 = clutter_group_new (); clutter_container_add (CLUTTER_CONTAINER (group1), group2, NULL); clutter_actor_set_position (group2, 10, 60); rect = clutter_rectangle_new_with_color (&rect_color); clutter_actor_set_size (rect, 128, 128); if (g_test_verbose ()) g_print ("rect 100%% + group 100%% + group 50%%.get_color()/1\n"); clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check); g_assert (color_check.alpha == rect_color.alpha); clutter_container_add (CLUTTER_CONTAINER (group2), rect, NULL); if (g_test_verbose ()) g_print ("rect 100%% + group 100%% + group 50%%.get_color()/2\n"); clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check); g_assert (color_check.alpha == rect_color.alpha); if (g_test_verbose ()) g_print ("rect 100%%.get_paint_opacity()\n"); g_assert (clutter_actor_get_paint_opacity (rect) == 128); } G_GNUC_END_IGNORE_DEPRECATIONS CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/opacity/text", opacity_label) CLUTTER_TEST_UNIT ("/actor/opacity/rectangle", opacity_rectangle) CLUTTER_TEST_UNIT ("/actor/opacity/paint", opacity_paint) ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-anchors.c��������������������������������������������������0000664�0001750�0001750�00000065430�14211404421�022342� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> #define NOTIFY_ANCHOR_X (1 << 0) #define NOTIFY_ANCHOR_Y (1 << 1) #define NOTIFY_ANCHOR_GRAVITY (1 << 2) #define NOTIFY_SCALE_X (1 << 3) #define NOTIFY_SCALE_Y (1 << 4) #define NOTIFY_SCALE_CENTER_X (1 << 5) #define NOTIFY_SCALE_CENTER_Y (1 << 6) #define NOTIFY_SCALE_GRAVITY (1 << 7) #define NOTIFY_ROTATION_ANGLE_X (1 << 8) #define NOTIFY_ROTATION_ANGLE_Y (1 << 9) #define NOTIFY_ROTATION_ANGLE_Z (1 << 10) #define NOTIFY_ROTATION_CENTER_X (1 << 11) #define NOTIFY_ROTATION_CENTER_Y (1 << 12) #define NOTIFY_ROTATION_CENTER_Z (1 << 13) #define NOTIFY_ROTATION_CENTER_Z_GRAVITY (1 << 14) #define RECT_WIDTH 100.0 #define RECT_HEIGHT 80.0 /* Allow the transformed position by off by a certain number of pixels */ #define POSITION_TOLERANCE 2 typedef struct _TestState { gulong notifications; ClutterActor *rect; } TestState; static const struct { ClutterGravity gravity; gfloat x_pos; gfloat y_pos; } gravities[] = { { CLUTTER_GRAVITY_NORTH, RECT_WIDTH / 2, 0 }, { CLUTTER_GRAVITY_NORTH_EAST, RECT_WIDTH, 0 }, { CLUTTER_GRAVITY_EAST, RECT_WIDTH, RECT_HEIGHT / 2 }, { CLUTTER_GRAVITY_SOUTH_EAST, RECT_WIDTH, RECT_HEIGHT }, { CLUTTER_GRAVITY_SOUTH, RECT_WIDTH / 2, RECT_HEIGHT }, { CLUTTER_GRAVITY_SOUTH_WEST, 0, RECT_HEIGHT }, { CLUTTER_GRAVITY_WEST, 0, RECT_HEIGHT / 2 }, { CLUTTER_GRAVITY_NORTH_WEST, 0, 0 }, { CLUTTER_GRAVITY_CENTER, RECT_WIDTH / 2, RECT_HEIGHT / 2 } }; static const char * const properties[] = { "anchor-x", "anchor-y", "anchor-gravity", "scale-x", "scale-y", "scale-center-x", "scale-center-y", "scale-gravity", "rotation-angle-x", "rotation-angle-y", "rotation-angle-z", "rotation-center-x", "rotation-center-y", "rotation-center-z", "rotation-center-z-gravity" }; static const int n_properties = G_N_ELEMENTS (properties); static void notify_cb (GObject *object, GParamSpec *pspec, TestState *state) { int i; int new_flags = 0; int flag = 1; for (i = 0; i < n_properties; i++) { if (!strcmp (properties[i], pspec->name)) new_flags |= flag; flag <<= 1; } g_assert ((new_flags & state->notifications) == 0); state->notifications |= new_flags; } #define assert_notifications(flags) G_STMT_START { \ g_assert (state->notifications == (flags)); \ state->notifications = 0; } G_STMT_END /* Helper macro to assert the transformed position. This needs to be a macro so that the assertion failure will report the right line number */ #define assert_coords(state, x_1, y_1, x_2, y_2) G_STMT_START { \ ClutterVertex verts[4]; \ clutter_actor_get_abs_allocation_vertices ((state)->rect, verts); \ check_coords ((state), (x_1), (y_1), (x_2), (y_2), verts); \ g_assert (approx_equal ((x_1), verts[0].x)); \ g_assert (approx_equal ((y_1), verts[0].y)); \ g_assert (approx_equal ((x_2), verts[3].x)); \ g_assert (approx_equal ((y_2), verts[3].y)); } G_STMT_END #define assert_position(state, x, y) \ assert_coords((state), (x), (y), (x) + RECT_WIDTH, (y) + RECT_HEIGHT) #define assert_vertex_and_free(v, xc, yc, zc) G_STMT_START { \ g_assert (approx_equal (v->x, xc) && \ approx_equal (v->y, yc) && \ approx_equal (v->z, zc)); \ g_boxed_free (CLUTTER_TYPE_VERTEX, v); } G_STMT_END static inline gboolean approx_equal (int a, int b) { return abs (a - b) <= POSITION_TOLERANCE; } static void check_coords (TestState *state, gint x_1, gint y_1, gint x_2, gint y_2, const ClutterVertex *verts) { if (g_test_verbose ()) g_print ("checking that (%i,%i,%i,%i) \xe2\x89\x88 (%i,%i,%i,%i): %s\n", x_1, y_1, x_2, y_2, (int) (verts[0].x), (int) (verts[0].y), (int) (verts[3].x), (int) (verts[3].y), approx_equal (x_1, verts[0].x) && approx_equal (y_1, verts[0].y) && approx_equal (x_2, verts[3].x) && approx_equal (y_2, verts[3].y) ? "yes" : "NO"); } static void test_anchor_point (TestState *state) { ClutterActor *rect = state->rect; gfloat anchor_x, anchor_y; ClutterGravity anchor_gravity; int i; /* Assert the default settings */ g_assert (clutter_actor_get_x (rect) == 100); g_assert (clutter_actor_get_y (rect) == 200); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "anchor-x", &anchor_x, "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 0); g_assert (anchor_y == 0); g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE); /* Change the anchor point */ clutter_actor_set_anchor_point (rect, 20, 30); g_object_get (rect, "anchor-x", &anchor_x, "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 20); g_assert (anchor_y == 30); g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE); assert_position (state, 80, 170); assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y); /* Move the anchor point */ clutter_actor_move_anchor_point (rect, 40, 50); g_object_get (rect, "anchor-x", &anchor_x, "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 40); g_assert (anchor_y == 50); g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE); assert_position (state, 80, 170); assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y); /* Put the actor back to its default position */ clutter_actor_set_position (rect, 100, 200); /* Change the anchor point with each of the gravities */ for (i = 0; i < G_N_ELEMENTS (gravities); i++) { if (g_test_verbose ()) { GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY); GEnumValue *value = g_enum_get_value (gravity_class, gravities[i].gravity); g_print ("Setting gravity to %s\n", value ? value->value_name : "?"); g_type_class_unref (gravity_class); } g_object_set (rect, "anchor-gravity", gravities[i].gravity, NULL); g_object_get (rect, "anchor-x", &anchor_x, "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == gravities[i].x_pos); g_assert (anchor_y == gravities[i].y_pos); g_assert (anchor_gravity == gravities[i].gravity); assert_position (state, 100 - gravities[i].x_pos, 200 - gravities[i].y_pos); assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y | NOTIFY_ANCHOR_GRAVITY); } /* Verify that the anchor point moves if the actor changes size when it is set from the gravity */ clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2); g_object_get (rect, "anchor-x", &anchor_x, "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == RECT_WIDTH); g_assert (anchor_y == RECT_HEIGHT); g_assert (anchor_gravity == CLUTTER_GRAVITY_CENTER); assert_coords (state, 100 - RECT_WIDTH, 200 - RECT_HEIGHT, 100 + RECT_WIDTH, 200 + RECT_HEIGHT); assert_notifications (0); clutter_actor_set_size (rect, RECT_WIDTH, RECT_HEIGHT); /* Change the anchor point using units again to assert that the gravity property changes */ clutter_actor_set_anchor_point (rect, 20, 30); g_object_get (rect, "anchor-x", &anchor_x, "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 20); g_assert (anchor_y == 30); g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE); assert_position (state, 80, 170); assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y | NOTIFY_ANCHOR_GRAVITY); /* Verify that the anchor point doesn't move if the actor changes size when it is set from units */ clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2); g_object_get (rect, "anchor-x", &anchor_x, "anchor-y", &anchor_y, "anchor-gravity", &anchor_gravity, NULL); g_assert (anchor_x == 20); g_assert (anchor_y == 30); g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE); assert_coords (state, 80, 170, 80 + RECT_WIDTH * 2, 170 + RECT_HEIGHT * 2); assert_notifications (0); clutter_actor_set_size (rect, RECT_WIDTH, RECT_HEIGHT); /* Put the anchor back */ clutter_actor_set_anchor_point_from_gravity (rect, CLUTTER_GRAVITY_NONE); assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y); } static void test_scale_center (TestState *state) { ClutterActor *rect = state->rect; gdouble scale_x, scale_y; gfloat center_x, center_y; ClutterGravity gravity; int i; /* Assert the default settings */ g_assert (clutter_actor_get_x (rect) == 100); g_assert (clutter_actor_get_y (rect) == 200); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, "scale-x", &scale_x, "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == 0); g_assert (center_y == 0); g_assert (scale_x == 1.0); g_assert (scale_y == 1.0); g_assert (gravity == CLUTTER_GRAVITY_NONE); /* Try changing the scale without affecting the center */ g_object_set (rect, "scale-x", 2.0, "scale-y", 3.0, NULL); g_assert (clutter_actor_get_x (rect) == 100); g_assert (clutter_actor_get_y (rect) == 200); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, "scale-x", &scale_x, "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == 0); g_assert (center_y == 0); g_assert (scale_x == 2.0); g_assert (scale_y == 3.0); g_assert (gravity == CLUTTER_GRAVITY_NONE); assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y); assert_coords (state, 100, 200, 100 + RECT_WIDTH * 2, 200 + RECT_HEIGHT * 3); /* Change the scale and center */ g_object_set (rect, "scale-x", 4.0, "scale-y", 2.0, "scale-center-x", 10.0, "scale-center-y", 20.0, NULL); g_assert (clutter_actor_get_x (rect) == 100); g_assert (clutter_actor_get_y (rect) == 200); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, "scale-x", &scale_x, "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == 10); g_assert (center_y == 20); g_assert (scale_x == 4.0); g_assert (scale_y == 2.0); g_assert (gravity == CLUTTER_GRAVITY_NONE); assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y | NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y); assert_coords (state, 100 + 10 - 10 * 4, 200 + 20 - 20 * 2, 100 + 10 + (RECT_WIDTH - 10) * 4, 200 + 20 + (RECT_HEIGHT - 20) * 2); /* Change the anchor point with each of the gravities */ for (i = 0; i < G_N_ELEMENTS (gravities); i++) { if (g_test_verbose ()) { GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY); GEnumValue *value = g_enum_get_value (gravity_class, gravities[i].gravity); g_print ("Setting scale center to %s\n", value ? value->value_name : "?"); g_type_class_unref (gravity_class); } g_object_set (rect, "scale-gravity", gravities[i].gravity, NULL); g_assert (clutter_actor_get_x (rect) == 100); g_assert (clutter_actor_get_y (rect) == 200); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, "scale-x", &scale_x, "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == gravities[i].x_pos); g_assert (center_y == gravities[i].y_pos); g_assert (scale_x == 4.0); g_assert (scale_y == 2.0); g_assert (gravity == gravities[i].gravity); assert_notifications (NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y | NOTIFY_SCALE_GRAVITY); assert_coords (state, 100 - gravities[i].x_pos * 3, 200 - gravities[i].y_pos, 100 + (gravities[i].x_pos + (RECT_WIDTH - gravities[i].x_pos) * 4), 200 + (gravities[i].y_pos + (RECT_HEIGHT - gravities[i].y_pos) * 2)); } /* Change the scale center using units again to assert that the gravity property changes */ clutter_actor_set_scale_full (rect, 4, 2, 10, 20); g_object_get (rect, "scale-center-x", ¢er_x, "scale-center-y", ¢er_y, "scale-x", &scale_x, "scale-y", &scale_y, "scale-gravity", &gravity, NULL); g_assert (center_x == 10); g_assert (center_y == 20); g_assert (scale_x == 4.0); g_assert (scale_y == 2.0); g_assert (gravity == CLUTTER_GRAVITY_NONE); assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y | NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y | NOTIFY_SCALE_GRAVITY); assert_coords (state, 100 + 10 - 10 * 4, 200 + 20 - 20 * 2, 100 + 10 + (RECT_WIDTH - 10) * 4, 200 + 20 + (RECT_HEIGHT - 20) * 2); /* Put the scale back to normal */ clutter_actor_set_scale_full (rect, 1, 1, 0, 0); assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y | NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y); } static void test_rotate_center (TestState *state) { ClutterActor *rect = state->rect; gdouble angle_x, angle_y, angle_z; ClutterVertex *center_x, *center_y, *center_z; ClutterGravity z_center_gravity; gfloat stage_width, stage_height; gfloat rect_x, rect_y; int i; /* Position the rectangle at the center of the stage so that rotations by 90° along the X or Y axis will cause the actor to be appear as a flat line. This makes verifying the transformations easier */ clutter_actor_get_size (clutter_actor_get_stage (rect), &stage_width, &stage_height); rect_x = stage_width / 2; rect_y = stage_height / 2; clutter_actor_set_position (rect, rect_x, rect_y); /* Assert the default settings */ g_assert_cmpfloat (clutter_actor_get_x (rect), ==, rect_x); g_assert_cmpfloat (clutter_actor_get_y (rect), ==, rect_y); g_assert_cmpfloat (clutter_actor_get_width (rect), ==, RECT_WIDTH); g_assert_cmpfloat (clutter_actor_get_height (rect), ==, RECT_HEIGHT); g_object_get (rect, "rotation-angle-x", &angle_x, "rotation-angle-y", &angle_y, "rotation-angle-z", &angle_z, "rotation-center-x", ¢er_x, "rotation-center-y", ¢er_y, "rotation-center-z", ¢er_z, "rotation-center-z-gravity", &z_center_gravity, NULL); g_assert (angle_x == 0.0); g_assert (angle_y == 0.0); g_assert (angle_z == 0.0); assert_vertex_and_free (center_x, 0, 0, 0); assert_vertex_and_free (center_y, 0, 0, 0); assert_vertex_and_free (center_z, 0, 0, 0); g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE); /* Change each of the rotation angles without affecting the center point */ for (i = CLUTTER_X_AXIS; i <= CLUTTER_Z_AXIS; i++) { char prop_name[] = "rotation-angle- "; prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x'; if (g_test_verbose ()) g_print ("Setting %s to 90 degrees\n", prop_name); g_object_set (rect, prop_name, 90.0, NULL); assert_notifications (NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS)); g_assert (clutter_actor_get_x (rect) == rect_x); g_assert (clutter_actor_get_y (rect) == rect_y); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "rotation-angle-x", &angle_x, "rotation-angle-y", &angle_y, "rotation-angle-z", &angle_z, "rotation-center-x", ¢er_x, "rotation-center-y", ¢er_y, "rotation-center-z", ¢er_z, "rotation-center-z-gravity", &z_center_gravity, NULL); if (i == CLUTTER_X_AXIS) { g_assert (angle_x == 90.0); assert_coords (state, rect_x, rect_y, verts[3].x, rect_y); } else g_assert (angle_x == 0.0); if (i == CLUTTER_Y_AXIS) { g_assert (angle_y == 90.0); assert_coords (state, rect_x, rect_y, rect_x, verts[3].y); } else g_assert (angle_y == 0.0); if (i == CLUTTER_Z_AXIS) { g_assert (angle_z == 90.0); assert_coords (state, rect_x, rect_y, rect_x - RECT_HEIGHT, rect_y + RECT_WIDTH); } else g_assert (angle_z == 0.0); assert_vertex_and_free (center_x, 0, 0, 0); assert_vertex_and_free (center_y, 0, 0, 0); assert_vertex_and_free (center_z, 0, 0, 0); g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE); g_object_set (rect, prop_name, 0.0, NULL); assert_notifications (NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS)); } clutter_actor_set_position (rect, rect_x -= 10, rect_y -= 20); /* Same test but also change the center position */ for (i = CLUTTER_X_AXIS; i <= CLUTTER_Z_AXIS; i++) { char prop_name[] = "rotation-angle- "; prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x'; if (g_test_verbose ()) g_print ("Setting %s to 90 degrees with center 10,20,0\n", prop_name); clutter_actor_set_rotation (rect, i, 90.0, 10, 20, 0); assert_notifications ((NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS)) | (NOTIFY_ROTATION_CENTER_X << (i - CLUTTER_X_AXIS))); g_assert (clutter_actor_get_x (rect) == rect_x); g_assert (clutter_actor_get_y (rect) == rect_y); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "rotation-angle-x", &angle_x, "rotation-angle-y", &angle_y, "rotation-angle-z", &angle_z, "rotation-center-x", ¢er_x, "rotation-center-y", ¢er_y, "rotation-center-z", ¢er_z, "rotation-center-z-gravity", &z_center_gravity, NULL); if (i == CLUTTER_X_AXIS) { g_assert (angle_x == 90.0); assert_coords (state, verts[0].x, rect_y + 20, verts[3].x, rect_y + 20); assert_vertex_and_free (center_x, 10, 20, 0); } else { g_assert (angle_x == 0.0); assert_vertex_and_free (center_x, 0, 0, 0); } if (i == CLUTTER_Y_AXIS) { g_assert (angle_y == 90.0); assert_coords (state, rect_x + 10, verts[0].y, rect_x + 10, verts[3].y); assert_vertex_and_free (center_y, 10, 20, 0); } else { g_assert (angle_y == 0.0); assert_vertex_and_free (center_y, 0, 0, 0); } if (i == CLUTTER_Z_AXIS) { g_assert (angle_z == 90.0); assert_coords (state, rect_x + 10 + 20, rect_y + 20 - 10, rect_x + 10 + 20 - RECT_HEIGHT, rect_y + 20 + RECT_WIDTH - 10); assert_vertex_and_free (center_z, 10, 20, 0); } else { g_assert (angle_z == 0.0); assert_vertex_and_free (center_z, 0, 0, 0); } g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE); clutter_actor_set_rotation (rect, i, 0, 0, 0, 0); assert_notifications ((NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS)) | (NOTIFY_ROTATION_CENTER_X << (i - CLUTTER_X_AXIS))); } /* Try rotating the z with all of the gravities */ for (i = 0; i < G_N_ELEMENTS (gravities); i++) { if (g_test_verbose ()) { GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY); GEnumValue *value = g_enum_get_value (gravity_class, gravities[i].gravity); g_print ("Setting z rotation to 90 degrees with center at %s\n", value ? value->value_name : "?"); g_type_class_unref (gravity_class); } clutter_actor_set_z_rotation_from_gravity (rect, 90, gravities[i].gravity); assert_notifications (NOTIFY_ROTATION_ANGLE_Z | NOTIFY_ROTATION_CENTER_Z | NOTIFY_ROTATION_CENTER_Z_GRAVITY); g_assert (clutter_actor_get_x (rect) == rect_x); g_assert (clutter_actor_get_y (rect) == rect_y); g_assert (clutter_actor_get_width (rect) == RECT_WIDTH); g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT); g_object_get (rect, "rotation-angle-x", &angle_x, "rotation-angle-y", &angle_y, "rotation-angle-z", &angle_z, "rotation-center-x", ¢er_x, "rotation-center-y", ¢er_y, "rotation-center-z", ¢er_z, "rotation-center-z-gravity", &z_center_gravity, NULL); g_assert (angle_x == 0.0); g_assert (angle_y == 0.0); g_assert (angle_z == 90.0); assert_vertex_and_free (center_x, 0, 0, 0); assert_vertex_and_free (center_y, 0, 0, 0); assert_vertex_and_free (center_z, gravities[i].x_pos, gravities[i].y_pos, 0); assert_coords (state, rect_x + gravities[i].x_pos + gravities[i].y_pos, rect_y + gravities[i].y_pos - gravities[i].x_pos, rect_x + gravities[i].x_pos + gravities[i].y_pos - RECT_HEIGHT, rect_y + gravities[i].y_pos + RECT_WIDTH - gravities[i].x_pos); g_assert (z_center_gravity == gravities[i].gravity); g_assert (clutter_actor_get_z_rotation_gravity (rect) == gravities[i].gravity); /* Put the rotation back */ clutter_actor_set_z_rotation_from_gravity (rect, 0, CLUTTER_GRAVITY_NONE); assert_notifications (NOTIFY_ROTATION_ANGLE_Z | NOTIFY_ROTATION_CENTER_Z | NOTIFY_ROTATION_CENTER_Z_GRAVITY); } } static gboolean idle_cb (gpointer data) { test_anchor_point (data); test_scale_center (data); test_rotate_center (data); clutter_main_quit (); return G_SOURCE_REMOVE; } static void actor_anchors (void) { TestState state; ClutterActor *stage; stage = clutter_test_get_stage (); state.rect = clutter_actor_new (); clutter_actor_add_child (stage, state.rect); clutter_actor_set_position (state.rect, 100, 200); clutter_actor_set_size (state.rect, RECT_WIDTH, RECT_HEIGHT); /* Record notifications on the actor properties */ state.notifications = 0; g_signal_connect (state.rect, "notify", G_CALLBACK (notify_cb), &state); /* Run the tests in a low priority idle function so that we can be sure the stage is correctly setup */ clutter_threads_add_idle_full (G_PRIORITY_LOW, idle_cb, &state, NULL); clutter_actor_show (stage); clutter_main (); } static void actor_pivot (void) { ClutterActor *stage, *actor_implicit, *actor_explicit; ClutterMatrix transform, result_implicit, result_explicit; ClutterActorBox allocation = CLUTTER_ACTOR_BOX_INIT (0, 0, 90, 30); gfloat angle = 30; stage = clutter_test_get_stage (); actor_implicit = clutter_actor_new (); actor_explicit = clutter_actor_new (); clutter_actor_add_child (stage, actor_implicit); clutter_actor_add_child (stage, actor_explicit); /* Fake allocation or pivot-point will not have any effect */ clutter_actor_allocate (actor_implicit, &allocation, CLUTTER_ALLOCATION_NONE); clutter_actor_allocate (actor_explicit, &allocation, CLUTTER_ALLOCATION_NONE); clutter_actor_set_pivot_point (actor_implicit, 0.5, 0.5); clutter_actor_set_pivot_point (actor_explicit, 0.5, 0.5); /* Implict transformation */ clutter_actor_set_rotation_angle (actor_implicit, CLUTTER_Z_AXIS, angle); /* Explict transformation */ clutter_matrix_init_identity(&transform); cogl_matrix_rotate (&transform, angle, 0, 0, 1.0); clutter_actor_set_transform (actor_explicit, &transform); clutter_actor_get_transform (actor_implicit, &result_implicit); clutter_actor_get_transform (actor_explicit, &result_explicit); g_assert (cogl_matrix_equal (&result_implicit, &result_explicit)); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/transforms/anchor-point", actor_anchors) CLUTTER_TEST_UNIT ("/actor/transforms/pivot-point", actor_pivot) ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-iter.c�����������������������������������������������������0000664�0001750�0001750�00000012335�14211404421�021644� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <clutter/clutter.h> static void actor_iter_traverse_children (void) { ClutterActorIter iter; ClutterActor *actor; ClutterActor *child; int i, n_actors; actor = clutter_actor_new (); clutter_actor_set_name (actor, "root"); g_object_ref_sink (actor); n_actors = g_random_int_range (10, 50); for (i = 0; i < n_actors; i++) { char *name; name = g_strdup_printf ("actor%d", i); child = clutter_actor_new (); clutter_actor_set_name (child, name); clutter_actor_add_child (actor, child); free (name); } g_assert_cmpint (clutter_actor_get_n_children (actor), ==, n_actors); i = 0; clutter_actor_iter_init (&iter, actor); g_assert (clutter_actor_iter_is_valid (&iter)); while (clutter_actor_iter_next (&iter, &child)) { g_assert (CLUTTER_IS_ACTOR (child)); g_assert (clutter_actor_get_parent (child) == actor); if (g_test_verbose ()) g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child)); if (i == 0) g_assert (child == clutter_actor_get_first_child (actor)); if (i == (n_actors - 1)) g_assert (child == clutter_actor_get_last_child (actor)); i += 1; } g_assert_cmpint (i, ==, n_actors); i = 0; clutter_actor_iter_init (&iter, actor); g_assert (clutter_actor_iter_is_valid (&iter)); while (clutter_actor_iter_prev (&iter, &child)) { g_assert (CLUTTER_IS_ACTOR (child)); g_assert (clutter_actor_get_parent (child) == actor); if (g_test_verbose ()) g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child)); if (i == 0) g_assert (child == clutter_actor_get_last_child (actor)); if (i == (n_actors - 1)) g_assert (child == clutter_actor_get_first_child (actor)); i += 1; } g_object_unref (actor); } static void actor_iter_traverse_remove (void) { ClutterActorIter iter; ClutterActor *actor; ClutterActor *child; int i, n_actors; actor = clutter_actor_new (); clutter_actor_set_name (actor, "root"); g_object_ref_sink (actor); n_actors = g_random_int_range (10, 50); for (i = 0; i < n_actors; i++) { char *name; name = g_strdup_printf ("actor%d", i); child = clutter_actor_new (); clutter_actor_set_name (child, name); clutter_actor_add_child (actor, child); free (name); } g_assert_cmpint (clutter_actor_get_n_children (actor), ==, n_actors); i = 0; clutter_actor_iter_init (&iter, actor); g_assert (clutter_actor_iter_is_valid (&iter)); while (clutter_actor_iter_next (&iter, &child)) { g_assert (CLUTTER_IS_ACTOR (child)); g_assert (clutter_actor_get_parent (child) == actor); if (g_test_verbose ()) g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child)); if (i == 0) g_assert (child == clutter_actor_get_first_child (actor)); if (i == (n_actors - 1)) g_assert (child == clutter_actor_get_last_child (actor)); clutter_actor_iter_remove (&iter); g_assert (clutter_actor_iter_is_valid (&iter)); i += 1; } g_assert_cmpint (i, ==, n_actors); g_assert_cmpint (0, ==, clutter_actor_get_n_children (actor)); } static void actor_iter_assignment (void) { ClutterActorIter iter_a, iter_b; ClutterActor *actor; ClutterActor *child; int i, n_actors; actor = clutter_actor_new (); clutter_actor_set_name (actor, "root"); g_object_ref_sink (actor); n_actors = g_random_int_range (10, 50); for (i = 0; i < n_actors; i++) { char *name; name = g_strdup_printf ("actor[%02d]", i); child = clutter_actor_new (); clutter_actor_set_name (child, name); clutter_actor_add_child (actor, child); free (name); } g_assert_cmpint (clutter_actor_get_n_children (actor), ==, n_actors); i = 0; clutter_actor_iter_init (&iter_a, actor); iter_b = iter_a; g_assert (clutter_actor_iter_is_valid (&iter_a)); g_assert (clutter_actor_iter_is_valid (&iter_b)); while (clutter_actor_iter_next (&iter_a, &child)) { g_assert (CLUTTER_IS_ACTOR (child)); g_assert (clutter_actor_get_parent (child) == actor); if (g_test_verbose ()) g_print ("actor %2d = '%s'\n", i, clutter_actor_get_name (child)); if (i == 0) g_assert (child == clutter_actor_get_first_child (actor)); if (i == (n_actors - 1)) g_assert (child == clutter_actor_get_last_child (actor)); i += 1; } g_assert_cmpint (i, ==, n_actors); i = n_actors - 1; while (clutter_actor_iter_prev (&iter_b, &child)) { g_assert (clutter_actor_get_parent (child) == actor); if (g_test_verbose ()) g_print ("actor %2d = '%s'\n", i, clutter_actor_get_name (child)); if (i == n_actors - 1) g_assert (child == clutter_actor_get_last_child (actor)); if (i == 0) g_assert (child == clutter_actor_get_first_child (actor)); i -= 1; } g_assert_cmpint (i, ==, -1); g_object_unref (actor); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/iter/traverse-children", actor_iter_traverse_children) CLUTTER_TEST_UNIT ("/actor/iter/traverse-remove", actor_iter_traverse_remove) CLUTTER_TEST_UNIT ("/actor/iter/assignment", actor_iter_assignment) ) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/events-touch.c���������������������������������������������������0000664�0001750�0001750�00000022352�14211404421�022217� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2009 Red Hat, Inc. * Copyright (C) 2012 Collabora Ltd. * * 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 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 program; if not, write to the Free Software Foundation, * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * Boston, MA 02111-1307, USA. * */ #include <clutter/clutter.h> #if defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <math.h> #include <linux/input.h> #include <linux/uinput.h> #include <dlfcn.h> #include <clutter/x11/clutter-x11.h> #define ABS_MAX_X 32768 #define ABS_MAX_Y 32768 #define TOUCH_POINTS 10 static ClutterPoint gesture_points[] = { { 100., 100. }, { 110., 100. }, { 120., 100. }, { 130., 100. }, { 140., 100. }, { 150., 100. }, { 160., 100. }, { 170., 100. }, { 180., 100. }, { 190., 100. }, }; typedef struct _State State; struct _State { gboolean pass; ClutterPoint gesture_points_to_check[TOUCH_POINTS]; int gesture_points; }; static int fd = -1; static void send_event(int fd, int type, int code, int value, int sec, int usec) { static int sec_offset = -1; static long last_time = -1; long newtime; struct input_event event; event.type = type; event.code = code; event.value = value; if (sec_offset == -1) sec_offset = sec; sec -= sec_offset; newtime = sec * 1000000 + usec; if (last_time > 0) usleep(newtime - last_time); gettimeofday(&event.time, NULL); if (write(fd, &event, sizeof(event)) < sizeof(event)) perror("Send event failed."); last_time = newtime; } static gboolean event_cb (ClutterActor *actor, ClutterEvent *event, State *state) { int i; if (event->type != CLUTTER_TOUCH_BEGIN && event->type != CLUTTER_TOUCH_UPDATE) return FALSE; state->gesture_points_to_check[state->gesture_points].x = ceil (event->touch.x); state->gesture_points_to_check[state->gesture_points].y = ceil (event->touch.y); state->gesture_points++; if (state->gesture_points == TOUCH_POINTS) { for (i = 0; i < TOUCH_POINTS; i++) { if (state->gesture_points_to_check[i].x != gesture_points[i].x || state->gesture_points_to_check[i].y != gesture_points[i].y) { if (g_test_verbose ()) g_print ("error: expected (%d, %d) but found (%d, %d) at position %d\n", (int) gesture_points[i].x, (int) gesture_points[i].y, (int) state->gesture_points_to_check[i].x, (int) state->gesture_points_to_check[i].y, i); state->pass = FALSE; break; } } clutter_main_quit (); } return TRUE; } static void screen_coords_to_device (int screen_x, int screen_y, int *device_x, int *device_y) { int display_width = DisplayWidth (clutter_x11_get_default_display (), clutter_x11_get_default_screen ()); int display_height = DisplayHeight (clutter_x11_get_default_display (), clutter_x11_get_default_screen ()); *device_x = (screen_x * ABS_MAX_X) / display_width; *device_y = (screen_y * ABS_MAX_Y) / display_height; } static gboolean perform_gesture (gpointer data) { int i; for (i = 0; i < TOUCH_POINTS; i++) { int x = gesture_points[i].x; int y = gesture_points[i].y; screen_coords_to_device (x, y, &x, &y); send_event(fd, EV_ABS, ABS_MT_SLOT, 0, 1, i * 100); send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, 1, 1, i * 100 + 10); send_event(fd, EV_ABS, ABS_MT_POSITION_X, x, 1, i * 100 + 20); send_event(fd, EV_ABS, ABS_MT_POSITION_Y, y, 1, i * 100 + 30); send_event(fd, EV_SYN, SYN_MT_REPORT, 0, 1, i * 100 + 40); send_event(fd, EV_SYN, SYN_REPORT, 0, 1, i * 100 + 50); } send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1, 1, TOUCH_POINTS * 100 + 10); send_event(fd, EV_SYN, SYN_MT_REPORT, 0, 1, TOUCH_POINTS * 100 + 20); send_event(fd, EV_SYN, SYN_REPORT, 0, 1, TOUCH_POINTS * 100 + 30); return G_SOURCE_REMOVE; } static int setup (struct uinput_user_dev *dev, int fd) { strcpy (dev->name, "eGalax Touch Screen"); dev->id.bustype = 0x18; dev->id.vendor = 0xeef; dev->id.product = 0x20; dev->id.version = 0x1; if (ioctl (fd, UI_SET_EVBIT, EV_SYN) == -1) goto error; if (ioctl (fd, UI_SET_EVBIT, EV_KEY) == -1) goto error; if (ioctl (fd, UI_SET_KEYBIT, BTN_TOUCH) == -1) goto error; if (ioctl (fd, UI_SET_EVBIT, EV_ABS) == -1) goto error; if (ioctl (fd, UI_SET_ABSBIT, ABS_X) == -1) goto error; else { int idx = ABS_X; dev->absmin[idx] = 0; dev->absmax[idx] = ABS_MAX_X; dev->absfuzz[idx] = 1; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } if (ioctl (fd, UI_SET_ABSBIT, ABS_Y) == -1) goto error; else { int idx = ABS_Y; dev->absmin[idx] = 0; dev->absmax[idx] = ABS_MAX_Y; dev->absfuzz[idx] = 1; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } if (ioctl (fd, UI_SET_ABSBIT, ABS_PRESSURE) == -1) goto error; else { int idx = ABS_PRESSURE; dev->absmin[idx] = 0; dev->absmax[idx] = 0; dev->absfuzz[idx] = 0; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR) == -1) goto error; else { int idx = ABS_MT_TOUCH_MAJOR; dev->absmin[idx] = 0; dev->absmax[idx] = 255; dev->absfuzz[idx] = 1; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_WIDTH_MAJOR) == -1) goto error; else { int idx = ABS_MT_WIDTH_MAJOR; dev->absmin[idx] = 0; dev->absmax[idx] = 255; dev->absfuzz[idx] = 1; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_POSITION_X) == -1) goto error; else { int idx = ABS_MT_POSITION_X; dev->absmin[idx] = 0; dev->absmax[idx] = ABS_MAX_X; dev->absfuzz[idx] = 1; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y) == -1) goto error; else { int idx = ABS_MT_POSITION_Y; dev->absmin[idx] = 0; dev->absmax[idx] = ABS_MAX_Y; dev->absfuzz[idx] = 1; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID) == -1) goto error; else { int idx = ABS_MT_TRACKING_ID; dev->absmin[idx] = 0; dev->absmax[idx] = 5; dev->absfuzz[idx] = 0; dev->absflat[idx] = 0; if (dev->absmin[idx] == dev->absmax[idx]) dev->absmax[idx]++; } return 0; error: perror ("ioctl failed."); return -1; } static int init_uinput (void) { struct uinput_user_dev dev; fd = open ("/dev/uinput", O_RDWR); if (fd < 0 && errno == ENODEV) fd = open ("/dev/input/uinput", O_RDWR); if (fd < 0) { if (g_test_verbose ()) perror ("open"); return 0; }; memset (&dev, 0, sizeof (dev)); setup (&dev, fd); if (write (fd, &dev, sizeof (dev)) < sizeof (dev)) { if (g_test_verbose ()) perror ("write"); goto error; } if (ioctl (fd, UI_DEV_CREATE, NULL) == -1) { if (g_test_verbose ()) perror ("ioctl"); goto error; } return 1; error: if (fd != -1) close (fd); return 0; } #endif /* defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 */ static void events_touch (void) { #if defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 ClutterActor *stage; State state; /* bail out if we could not initialize evdev */ if (!init_uinput ()) return; state.pass = TRUE; state.gesture_points = 0; stage = clutter_test_get_stage (); g_signal_connect (stage, "event", G_CALLBACK (event_cb), &state); clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), TRUE); clutter_actor_show (stage); clutter_threads_add_timeout (500, perform_gesture, &state); clutter_main (); if (g_test_verbose ()) g_print ("end result: %s\n", state.pass ? "pass" : "FAIL"); g_assert (state.pass); #endif /* defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 */ } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/events/touch", events_touch) ) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/model.c����������������������������������������������������������0000664�0001750�0001750�00000032176�14211404421�020700� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> typedef struct _ModelData { ClutterModel *model; guint n_row; } ModelData; typedef struct _ChangedData { ClutterModel *model; ClutterModelIter *iter; guint row; guint n_emissions; gint value_check; } ChangedData; enum { COLUMN_FOO, /* G_TYPE_STRING */ COLUMN_BAR, /* G_TYPE_INT */ N_COLUMNS }; static const struct { const gchar *expected_foo; gint expected_bar; } base_model[] = { { "String 1", 1 }, { "String 2", 2 }, { "String 3", 3 }, { "String 4", 4 }, { "String 5", 5 }, { "String 6", 6 }, { "String 7", 7 }, { "String 8", 8 }, { "String 9", 9 }, }; static const struct { const gchar *expected_foo; gint expected_bar; } forward_base[] = { { "String 1", 1 }, { "String 2", 2 }, { "String 3", 3 }, { "String 4", 4 }, { "String 5", 5 }, { "String 6", 6 }, { "String 7", 7 }, { "String 8", 8 }, { "String 9", 9 }, }; static const struct { const gchar *expected_foo; gint expected_bar; } backward_base[] = { { "String 9", 9 }, { "String 8", 8 }, { "String 7", 7 }, { "String 6", 6 }, { "String 5", 5 }, { "String 4", 4 }, { "String 3", 3 }, { "String 2", 2 }, { "String 1", 1 }, }; static const struct { const gchar *expected_foo; gint expected_bar; } filter_odd[] = { { "String 1", 1 }, { "String 3", 3 }, { "String 5", 5 }, { "String 7", 7 }, { "String 9", 9 }, }; static const struct { const gchar *expected_foo; gint expected_bar; } filter_even[] = { { "String 8", 8 }, { "String 6", 6 }, { "String 4", 4 }, { "String 2", 2 }, }; static inline void compare_iter (ClutterModelIter *iter, const gint expected_row, const gchar *expected_foo, const gint expected_bar) { gchar *foo = NULL; gint bar = 0; gint row = 0; row = clutter_model_iter_get_row (iter); clutter_model_iter_get (iter, COLUMN_FOO, &foo, COLUMN_BAR, &bar, -1); if (g_test_verbose ()) g_print ("Row %d => %d: Got [ '%s', '%d' ], expected [ '%s', '%d' ]\n", row, expected_row, foo, bar, expected_foo, expected_bar); g_assert_cmpint (row, ==, expected_row); g_assert_cmpstr (foo, ==, expected_foo); g_assert_cmpint (bar, ==, expected_bar); free (foo); } static void on_row_added (ClutterModel *model, ClutterModelIter *iter, gpointer data) { ModelData *model_data = data; compare_iter (iter, model_data->n_row, base_model[model_data->n_row].expected_foo, base_model[model_data->n_row].expected_bar); model_data->n_row += 1; } static gboolean filter_even_rows (ClutterModel *model, ClutterModelIter *iter, gpointer dummy G_GNUC_UNUSED) { gint bar_value; clutter_model_iter_get (iter, COLUMN_BAR, &bar_value, -1); if (bar_value % 2 == 0) return TRUE; return FALSE; } static gboolean filter_odd_rows (ClutterModel *model, ClutterModelIter *iter, gpointer dummy G_GNUC_UNUSED) { gint bar_value; clutter_model_iter_get (iter, COLUMN_BAR, &bar_value, -1); if (bar_value % 2 != 0) return TRUE; return FALSE; } static void list_model_filter (void) { ModelData test_data = { NULL, 0 }; ClutterModelIter *iter; gint i; test_data.model = clutter_list_model_new (N_COLUMNS, G_TYPE_STRING, "Foo", G_TYPE_INT, "Bar"); test_data.n_row = 0; for (i = 1; i < 10; i++) { gchar *foo = g_strdup_printf ("String %d", i); clutter_model_append (test_data.model, COLUMN_FOO, foo, COLUMN_BAR, i, -1); free (foo); } if (g_test_verbose ()) g_print ("Forward iteration (filter odd)...\n"); clutter_model_set_filter (test_data.model, filter_odd_rows, NULL, NULL); iter = clutter_model_get_first_iter (test_data.model); g_assert (iter != NULL); i = 0; while (!clutter_model_iter_is_last (iter)) { compare_iter (iter, i, filter_odd[i].expected_foo, filter_odd[i].expected_bar); iter = clutter_model_iter_next (iter); i += 1; } g_object_unref (iter); if (g_test_verbose ()) g_print ("Backward iteration (filter even)...\n"); clutter_model_set_filter (test_data.model, filter_even_rows, NULL, NULL); iter = clutter_model_get_last_iter (test_data.model); g_assert (iter != NULL); i = 0; do { compare_iter (iter, G_N_ELEMENTS (filter_even) - i - 1, filter_even[i].expected_foo, filter_even[i].expected_bar); iter = clutter_model_iter_prev (iter); i += 1; } while (!clutter_model_iter_is_first (iter)); g_object_unref (iter); if (g_test_verbose ()) g_print ("get_iter_at_row...\n"); clutter_model_set_filter (test_data.model, filter_odd_rows, NULL, NULL); for (i = 0; i < 5; i++) { iter = clutter_model_get_iter_at_row (test_data.model, i); compare_iter (iter, i , filter_odd[i].expected_foo, filter_odd[i].expected_bar); g_object_unref (iter); } iter = clutter_model_get_iter_at_row (test_data.model, 5); g_assert (iter == NULL); g_object_unref (test_data.model); } static void list_model_iterate (void) { ModelData test_data = { NULL, 0 }; ClutterModelIter *iter; gint i; test_data.model = clutter_list_model_new (N_COLUMNS, G_TYPE_STRING, "Foo", G_TYPE_INT, "Bar"); test_data.n_row = 0; g_signal_connect (test_data.model, "row-added", G_CALLBACK (on_row_added), &test_data); for (i = 1; i < 10; i++) { gchar *foo = g_strdup_printf ("String %d", i); clutter_model_append (test_data.model, COLUMN_FOO, foo, COLUMN_BAR, i, -1); free (foo); } if (g_test_verbose ()) g_print ("Forward iteration...\n"); iter = clutter_model_get_first_iter (test_data.model); g_assert (iter != NULL); i = 0; while (!clutter_model_iter_is_last (iter)) { compare_iter (iter, i, forward_base[i].expected_foo, forward_base[i].expected_bar); iter = clutter_model_iter_next (iter); i += 1; } g_object_unref (iter); if (g_test_verbose ()) g_print ("Backward iteration...\n"); iter = clutter_model_get_last_iter (test_data.model); g_assert (iter != NULL); i = 0; do { compare_iter (iter, G_N_ELEMENTS (backward_base) - i - 1, backward_base[i].expected_foo, backward_base[i].expected_bar); iter = clutter_model_iter_prev (iter); i += 1; } while (!clutter_model_iter_is_first (iter)); compare_iter (iter, G_N_ELEMENTS (backward_base) - i - 1, backward_base[i].expected_foo, backward_base[i].expected_bar); g_object_unref (iter); g_object_unref (test_data.model); } static void list_model_populate (void) { ModelData test_data = { NULL, 0 }; gint i; test_data.model = clutter_list_model_new (N_COLUMNS, G_TYPE_STRING, "Foo", G_TYPE_INT, "Bar"); test_data.n_row = 0; g_signal_connect (test_data.model, "row-added", G_CALLBACK (on_row_added), &test_data); for (i = 1; i < 10; i++) { gchar *foo = g_strdup_printf ("String %d", i); clutter_model_append (test_data.model, COLUMN_FOO, foo, COLUMN_BAR, i, -1); free (foo); } g_object_unref (test_data.model); } static void list_model_from_script (void) { ClutterScript *script = clutter_script_new (); GObject *model; GError *error = NULL; gchar *test_file; const gchar *name; GType type; ClutterModelIter *iter; GValue value = { 0, }; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-model.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); model = clutter_script_get_object (script, "test-model"); g_assert (CLUTTER_IS_MODEL (model)); g_assert (clutter_model_get_n_columns (CLUTTER_MODEL (model)) == 3); name = clutter_model_get_column_name (CLUTTER_MODEL (model), 0); type = clutter_model_get_column_type (CLUTTER_MODEL (model), 0); if (g_test_verbose ()) g_print ("column[0]: %s, type: %s\n", name, g_type_name (type)); g_assert (strcmp (name, "text-column") == 0); g_assert (type == G_TYPE_STRING); name = clutter_model_get_column_name (CLUTTER_MODEL (model), 2); type = clutter_model_get_column_type (CLUTTER_MODEL (model), 2); if (g_test_verbose ()) g_print ("column[2]: %s, type: %s\n", name, g_type_name (type)); g_assert (strcmp (name, "actor-column") == 0); g_assert (g_type_is_a (type, CLUTTER_TYPE_ACTOR)); g_assert (clutter_model_get_n_rows (CLUTTER_MODEL (model)) == 3); iter = clutter_model_get_iter_at_row (CLUTTER_MODEL (model), 0); clutter_model_iter_get_value (iter, 0, &value); g_assert (G_VALUE_HOLDS_STRING (&value)); g_assert (strcmp (g_value_get_string (&value), "text-row-1") == 0); g_value_unset (&value); clutter_model_iter_get_value (iter, 1, &value); g_assert (G_VALUE_HOLDS_INT (&value)); g_assert (g_value_get_int (&value) == 1); g_value_unset (&value); clutter_model_iter_get_value (iter, 2, &value); g_assert (G_VALUE_HOLDS_OBJECT (&value)); g_assert (g_value_get_object (&value) == NULL); g_value_unset (&value); iter = clutter_model_iter_next (iter); clutter_model_iter_get_value (iter, 2, &value); g_assert (G_VALUE_HOLDS_OBJECT (&value)); g_assert (CLUTTER_IS_ACTOR (g_value_get_object (&value))); g_value_unset (&value); iter = clutter_model_iter_next (iter); clutter_model_iter_get_value (iter, 2, &value); g_assert (G_VALUE_HOLDS_OBJECT (&value)); g_assert (CLUTTER_IS_ACTOR (g_value_get_object (&value))); g_assert (strcmp (clutter_actor_get_name (g_value_get_object (&value)), "actor-row-3") == 0); g_value_unset (&value); g_object_unref (iter); } static void on_row_changed (ClutterModel *model, ClutterModelIter *iter, ChangedData *data) { gint value = -1; clutter_model_iter_get (iter, COLUMN_BAR, &value, -1); if (g_test_verbose ()) g_print ("row-changed value-check: %d, expected: %d\n", value, data->value_check); g_assert_cmpint (value, ==, data->value_check); data->n_emissions += 1; } static void list_model_row_changed (void) { ChangedData test_data = { NULL, NULL, 0, 0 }; GValue value = { 0, }; gint i; test_data.model = clutter_list_model_new (N_COLUMNS, G_TYPE_STRING, "Foo", G_TYPE_INT, "Bar"); for (i = 1; i < 10; i++) { gchar *foo = g_strdup_printf ("String %d", i); clutter_model_append (test_data.model, COLUMN_FOO, foo, COLUMN_BAR, i, -1); free (foo); } g_signal_connect (test_data.model, "row-changed", G_CALLBACK (on_row_changed), &test_data); test_data.row = g_random_int_range (0, 9); test_data.iter = clutter_model_get_iter_at_row (test_data.model, test_data.row); g_assert (CLUTTER_IS_MODEL_ITER (test_data.iter)); test_data.value_check = 47; g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, test_data.value_check); clutter_model_iter_set_value (test_data.iter, COLUMN_BAR, &value); g_value_unset (&value); if (g_test_verbose ()) g_print ("iter.set_value() emissions: %d, expected: 1\n", test_data.n_emissions); g_assert_cmpint (test_data.n_emissions, ==, 1); test_data.n_emissions = 0; test_data.value_check = 42; clutter_model_iter_set (test_data.iter, COLUMN_FOO, "changed", COLUMN_BAR, test_data.value_check, -1); if (g_test_verbose ()) g_print ("iter.set() emissions: %d, expected: 1\n", test_data.n_emissions); g_assert_cmpint (test_data.n_emissions, ==, 1); g_object_unref (test_data.iter); g_object_unref (test_data.model); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/list-model/populate", list_model_populate) CLUTTER_TEST_UNIT ("/list-model/iterate", list_model_iterate) CLUTTER_TEST_UNIT ("/list-model/filter", list_model_filter) CLUTTER_TEST_UNIT ("/list-model/row-changed", list_model_row_changed) CLUTTER_TEST_UNIT ("/list-model/from-script", list_model_from_script) ) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/���������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�021112� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-model.json�����������������������������������0000664�0001750�0001750�00000000654�14211404421�025371� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "id" : "test-model", "type" : "ClutterListModel", "columns" : [ [ "text-column", "gchararray" ], [ "int-column", "gint" ], [ "actor-column", "ClutterRectangle" ] ], "rows" : [ [ "text-row-1", 1, null ], [ "text-row-2", 2, { "type" : "ClutterRectangle", "color" : "blue" } ], { "int-column" : 3, "actor-column" : { "type" : "ClutterRectangle", "name" : "actor-row-3" } } ] } ������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-child.json�����������������������������������0000664�0001750�0001750�00000000640�14211404421�025347� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "type" : "TestGroup", "id" : "test-group", "children" : [ { "type" : "ClutterRectangle", "id" : "test-rect-1", "width" : 100.0, "height" : 100.0, "color" : [ 255, 0, 0, 255 ], "child::focus" : true }, { "type" : "ClutterRectangle", "id" : "test-rect-2", "width" : 100.0, "height" : 100.0, "color" : [ 0, 255, 0, 255 ] } ] } ������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-implicit-alpha.json��������������������������0000664�0001750�0001750�00000000217�14211404421�027161� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "id" : "test", "type" : "ClutterBehaviourOpacity", "alpha" : { "mode" : "easeOutCirc", "timeline" : { "duration" : 500 } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-animator-3.json�������������������������������������0000664�0001750�0001750�00000001443�14211404421�024736� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "type" : "ClutterRectangle", "id" : "foo", "x" : 0, "y" : 0, "width" : 100, "height" : 100 }, { "type" : "ClutterAnimator", "id" : "animator", "duration" : 1000, "properties" : [ { "object" : "foo", "name" : "x", "ease-in" : true, "interpolation" : "linear", "keys" : [ [ 0.0, "easeInCubic", 100.0 ], [ 0.2, "easeOutCubic", 150.0 ], [ 0.8, "linear", 200.0 ] ] }, { "object" : "foo", "name" : "y", "ease-in" : true, "interpolation" : "linear", "keys" : [ [ 0.0, "easeInCubic", 100.0 ], [ 0.2, "easeOutCubic", 150.0 ], [ 0.8, "linear", 200.0 ] ] } ] } ] �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-animator-1.json�������������������������������������0000664�0001750�0001750�00000000113�14211404421�024725� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "type" : "ClutterAnimator", "id" : "animator", "duration" : 1000 } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-object-property.json�������������������������0000664�0001750�0001750�00000000401�14211404421�027407� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "id" : "test", "type" : "ClutterBox", "layout-manager" : { "id" : "layout", "type" : "ClutterBinLayout" }, "children" : [ { "id" : "child-1", "type" : "ClutterRectangle", "width" : "3 em", "height" : "3 em" } ] } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-state-1.json����������������������������������������0000664�0001750�0001750�00000001036�14211404421�024240� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "type" : "ClutterRectangle", "id" : "rect", "width" : 100, "height" : 100 }, { "type" : "ClutterState", "id" : "state", "transitions" : [ { "source" : "base", "target" : "clicked", "duration" : 250, "keys" : [ [ "rect", "opacity", "linear", 128 ] ] }, { "source" : "clicked", "target" : "base", "duration" : 150, "keys" : [ [ "rect", "opacity", "linear", 255 ] ] } ] } ] ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-animator-2.json�������������������������������������0000664�0001750�0001750�00000001012�14211404421�024725� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "type" : "ClutterRectangle", "id" : "foo", "x" : 0, "y" : 0, "width" : 100, "height" : 100 }, { "type" : "ClutterAnimator", "id" : "animator", "duration" : 1000, "properties" : [ { "object" : "foo", "name" : "x", "ease-in" : true, "interpolation" : "linear", "keys" : [ [ 0.0, "easeInCubic", 100.0 ], [ 0.2, "easeOutCubic", 150.0 ], [ 0.8, "linear", 200.0 ] ] } ] } ] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-timeline-markers.json������������������������0000664�0001750�0001750�00000000415�14211404421�027534� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "id" : "timeline0", "type" : "ClutterTimeline", "duration" : 1000, "markers" : [ { "name" : "marker0", "time" : 250 }, { "name" : "marker1", "time" : 500 }, { "name" : "marker2", "time" : 750 }, { "name" : "marker3", "progress" : 0.5 } ] } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-animation.json�������������������������������0000664�0001750�0001750�00000000372�14211404421�026245� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "type" : "ClutterAnimation", "id" : "test", "mode" : "easeInCubic", "duration" : 500, "object" : { "type" : "ClutterRectangle", "id" : "rect", "opacity" : 128, "width" : 100, "height" : 16, "color" : "white" } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-named-object.json����������������������������0000664�0001750�0001750�00000001714�14211404421�026617� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "id" : "layout", "type" : "ClutterBoxLayout", "orientation" : "vertical", "spacing" : 12, "pack-start" : false }, { "type" : "ClutterStage", "id" : "main-stage", "children" : [ { "id" : "test", "type" : "ClutterBox", "layout-manager" : "layout", "children" : [ { "id" : "child-1", "type" : "ClutterRectangle", "width" : "3 em", "height" : "3 em" } ], "constraints" : [ { "type" : "ClutterAlignConstraint", "name" : "x-align", "factor" : 0.5, "align-axis" : "x-axis", "source" : "main-stage" }, { "type" : "ClutterAlignConstraint", "name" : "y-align", "factor" : 0.5, "align-axis" : "y-axis", "source" : "main-stage" } ] } ] } ] ����������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-layout-property.json�������������������������0000664�0001750�0001750�00000001002�14211404421�027454� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "id" : "manager", "type" : "ClutterBoxLayout" }, { "id" : "container", "type" : "ClutterBox", "layout-manager" : "manager", "children" : [ { "id" : "actor-1", "type" : "ClutterRectangle", "layout::x-fill" : true, "layout::y-align" : "center", "layout::expand" : true }, { "id" : "actor-2", "type" : "ClutterRectangle", "layout::x-fill" : false, "layout::y-align" : "end", "layout::expand" : false } ] } ] ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-margin.json����������������������������������0000664�0001750�0001750�00000000542�14211404421�025542� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "id" : "actor-1", "type" : "ClutterActor", "margin" : [ 10 ] }, { "id" : "actor-2", "type" : "ClutterActor", "margin" : [ 10, 20 ] }, { "id" : "actor-3", "type" : "ClutterActor", "margin" : [ 10, 20, 30 ] }, { "id" : "actor-4", "type" : "ClutterActor", "margin" : [ 10, 20, 30, 40] } ] ��������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-interval.json��������������������������������0000664�0001750�0001750�00000000422�14211404421�026106� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[ { "id" : "int-1", "type" : "ClutterInterval", "value-type" : "gfloat", "initial" : 23.3, "final" : 42.2 }, { "id" : "int-2", "type" : "ClutterInterval", "value-type" : "ClutterColor", "initial" : "red", "final" : "blue" } ] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/scripts/test-script-single.json����������������������������������0000664�0001750�0001750�00000000253�14211404421�025545� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "type" : "ClutterRectangle", "id" : "test", "width" : 50.0, "height" : 100.0, "x" : 100.0, "y" : 100.0, "color" : "#ffccdd", "name" : "Test Rectangle" } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-graph.c����������������������������������������������������0000664�0001750�0001750�00000051113�14211404421�021777� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> static void actor_add_child (void) { ClutterActor *actor = clutter_actor_new (); ClutterActor *iter; g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "baz", NULL)); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3); iter = clutter_actor_get_first_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); iter = clutter_actor_get_next_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); iter = clutter_actor_get_next_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz"); g_assert (iter == clutter_actor_get_last_child (actor)); g_assert (clutter_actor_get_next_sibling (iter) == NULL); iter = clutter_actor_get_last_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz"); iter = clutter_actor_get_previous_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); iter = clutter_actor_get_previous_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); g_assert (iter == clutter_actor_get_first_child (actor)); g_assert (clutter_actor_get_previous_sibling (iter) == NULL); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_insert_child (void) { ClutterActor *actor = clutter_actor_new (); ClutterActor *iter; g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_insert_child_at_index (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", NULL), 0); iter = clutter_actor_get_first_child (actor); g_assert (iter != NULL); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); g_assert (iter == clutter_actor_get_child_at_index (actor, 0)); clutter_actor_insert_child_below (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", NULL), iter); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 2); iter = clutter_actor_get_first_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); iter = clutter_actor_get_next_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); g_assert (iter == clutter_actor_get_child_at_index (actor, 1)); iter = clutter_actor_get_first_child (actor); clutter_actor_insert_child_above (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "baz", NULL), iter); iter = clutter_actor_get_last_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); iter = clutter_actor_get_previous_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz"); iter = clutter_actor_get_previous_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); clutter_actor_remove_all_children (actor); clutter_actor_insert_child_at_index (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "1", NULL), 0); iter = clutter_actor_get_child_at_index (actor, 0); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "1"); g_assert (clutter_actor_get_first_child (actor) == iter); g_assert (clutter_actor_get_last_child (actor) == iter); clutter_actor_insert_child_at_index (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "2", NULL), 0); iter = clutter_actor_get_child_at_index (actor, 0); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "2"); g_assert (clutter_actor_get_first_child (actor) == iter); iter = clutter_actor_get_child_at_index (actor, 1); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "1"); g_assert (clutter_actor_get_last_child (actor) == iter); clutter_actor_insert_child_at_index (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "3", NULL), -1); iter = clutter_actor_get_child_at_index (actor, 2); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "3"); g_assert (clutter_actor_get_last_child (actor) == iter); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_remove_child (void) { ClutterActor *actor = clutter_actor_new (); ClutterActor *iter; g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", NULL)); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 2); g_assert (clutter_actor_get_first_child (actor) != clutter_actor_get_last_child (actor)); iter = clutter_actor_get_first_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); iter = clutter_actor_get_last_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); clutter_actor_remove_child (actor, clutter_actor_get_first_child (actor)); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 1); iter = clutter_actor_get_first_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); g_assert (clutter_actor_get_first_child (actor) == clutter_actor_get_last_child (actor)); clutter_actor_remove_child (actor, clutter_actor_get_first_child (actor)); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 0); g_assert (clutter_actor_get_first_child (actor) == NULL); g_assert (clutter_actor_get_last_child (actor) == NULL); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_raise_child (void) { ClutterActor *actor = clutter_actor_new (); ClutterActor *iter; gboolean show_on_set_parent; g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", "visible", FALSE, NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", "visible", FALSE, NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "baz", "visible", FALSE, NULL)); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3); iter = clutter_actor_get_child_at_index (actor, 1); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); clutter_actor_set_child_above_sibling (actor, iter, clutter_actor_get_child_at_index (actor, 2)); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)), ==, "foo"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)), ==, "baz"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)), ==, "bar"); g_assert (!clutter_actor_is_visible (iter)); g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!show_on_set_parent); iter = clutter_actor_get_child_at_index (actor, 0); clutter_actor_set_child_above_sibling (actor, iter, NULL); g_object_add_weak_pointer (G_OBJECT (iter), (gpointer *) &iter); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)), ==, "baz"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)), ==, "bar"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)), ==, "foo"); g_assert (!clutter_actor_is_visible (iter)); g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!show_on_set_parent); clutter_actor_destroy (actor); g_assert (actor == NULL); g_assert (iter == NULL); } static void actor_lower_child (void) { ClutterActor *actor = clutter_actor_new (); ClutterActor *iter; gboolean show_on_set_parent; g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", "visible", FALSE, NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", "visible", FALSE, NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "baz", "visible", FALSE, NULL)); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3); iter = clutter_actor_get_child_at_index (actor, 1); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); clutter_actor_set_child_below_sibling (actor, iter, clutter_actor_get_child_at_index (actor, 0)); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)), ==, "bar"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)), ==, "foo"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)), ==, "baz"); g_assert (!clutter_actor_is_visible (iter)); g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!show_on_set_parent); iter = clutter_actor_get_child_at_index (actor, 2); clutter_actor_set_child_below_sibling (actor, iter, NULL); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)), ==, "baz"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)), ==, "bar"); g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)), ==, "foo"); g_assert (!clutter_actor_is_visible (iter)); g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!show_on_set_parent); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_replace_child (void) { ClutterActor *actor = clutter_actor_new (); ClutterActor *iter; g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", NULL)); iter = clutter_actor_get_child_at_index (actor, 0); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); clutter_actor_replace_child (actor, iter, g_object_new (CLUTTER_TYPE_ACTOR, "name", "baz", NULL)); iter = clutter_actor_get_child_at_index (actor, 0); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz"); iter = clutter_actor_get_child_at_index (actor, 1); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); clutter_actor_replace_child (actor, iter, g_object_new (CLUTTER_TYPE_ACTOR, "name", "qux", NULL)); iter = clutter_actor_get_child_at_index (actor, 0); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz"); iter = clutter_actor_get_child_at_index (actor, 1); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "qux"); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", NULL)); clutter_actor_replace_child (actor, iter, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", NULL)); iter = clutter_actor_get_last_child (actor); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo"); iter = clutter_actor_get_previous_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar"); iter = clutter_actor_get_previous_sibling (iter); g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz"); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_remove_all (void) { ClutterActor *actor = clutter_actor_new (); g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", NULL)); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "baz", NULL)); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3); clutter_actor_remove_all_children (actor); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 0); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_added (ClutterContainer *container, ClutterActor *child, gpointer data) { ClutterActor *actor = CLUTTER_ACTOR (container); int *counter = data; ClutterActor *old_child; if (g_test_verbose ()) g_print ("Adding actor '%s'\n", clutter_actor_get_name (child)); old_child = clutter_actor_get_child_at_index (actor, 0); if (old_child != child) clutter_actor_remove_child (actor, old_child); *counter += 1; } static void actor_removed (ClutterContainer *container, ClutterActor *child, gpointer data) { int *counter = data; if (g_test_verbose ()) g_print ("Removing actor '%s'\n", clutter_actor_get_name (child)); *counter += 1; } static void actor_container_signals (void) { ClutterActor *actor = clutter_actor_new (); int add_count, remove_count; g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); add_count = remove_count = 0; g_signal_connect (actor, "actor-added", G_CALLBACK (actor_added), &add_count); g_signal_connect (actor, "actor-removed", G_CALLBACK (actor_removed), &remove_count); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "foo", NULL)); g_assert_cmpint (add_count, ==, 1); g_assert_cmpint (remove_count, ==, 0); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 1); clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR, "name", "bar", NULL)); g_assert_cmpint (add_count, ==, 2); g_assert_cmpint (remove_count, ==, 1); g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 1); g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (actor_added), &add_count); g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (actor_removed), &remove_count); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_contains (void) { /* This build up the following tree: * * a * ╱ │ ╲ * ╱ │ ╲ * b c d * ╱ ╲ ╱ ╲ ╱ ╲ * e f g h i j */ struct { ClutterActor *actor_a, *actor_b, *actor_c, *actor_d, *actor_e; ClutterActor *actor_f, *actor_g, *actor_h, *actor_i, *actor_j; } d; int x, y; ClutterActor **actor_array = &d.actor_a; /* Matrix of expected results */ static const gboolean expected_results[] = { /* a, b, c, d, e, f, g, h, i, j */ /* a */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, /* c */ 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, /* d */ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, /* e */ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* f */ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* g */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, /* h */ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* i */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* j */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; d.actor_a = clutter_actor_new (); d.actor_b = clutter_actor_new (); d.actor_c = clutter_actor_new (); d.actor_d = clutter_actor_new (); d.actor_e = clutter_actor_new (); d.actor_f = clutter_actor_new (); d.actor_g = clutter_actor_new (); d.actor_h = clutter_actor_new (); d.actor_i = clutter_actor_new (); d.actor_j = clutter_actor_new (); clutter_actor_add_child (d.actor_a, d.actor_b); clutter_actor_add_child (d.actor_a, d.actor_c); clutter_actor_add_child (d.actor_a, d.actor_d); clutter_actor_add_child (d.actor_b, d.actor_e); clutter_actor_add_child (d.actor_b, d.actor_f); clutter_actor_add_child (d.actor_c, d.actor_g); clutter_actor_add_child (d.actor_c, d.actor_h); clutter_actor_add_child (d.actor_d, d.actor_i); clutter_actor_add_child (d.actor_d, d.actor_j); for (y = 0; y < 10; y++) for (x = 0; x < 10; x++) g_assert_cmpint (clutter_actor_contains (actor_array[x], actor_array[y]), ==, expected_results[x * 10 + y]); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/graph/add-child", actor_add_child) CLUTTER_TEST_UNIT ("/actor/graph/insert-child", actor_insert_child) CLUTTER_TEST_UNIT ("/actor/graph/remove-child", actor_remove_child) CLUTTER_TEST_UNIT ("/actor/graph/raise-child", actor_raise_child) CLUTTER_TEST_UNIT ("/actor/graph/lower-child", actor_lower_child) CLUTTER_TEST_UNIT ("/actor/graph/replace-child", actor_replace_child) CLUTTER_TEST_UNIT ("/actor/graph/remove-all", actor_remove_all) CLUTTER_TEST_UNIT ("/actor/graph/container-signals", actor_container_signals) CLUTTER_TEST_UNIT ("/actor/graph/contains", actor_contains) ) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/texture-fbo.c����������������������������������������������������0000664�0001750�0001750�00000016247�14211404421�022045� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <cogl/cogl.h> #include "test-conform-common.h" #define SOURCE_SIZE 32 #define SOURCE_DIVISIONS_X 2 #define SOURCE_DIVISIONS_Y 2 #define DIVISION_WIDTH (SOURCE_SIZE / SOURCE_DIVISIONS_X) #define DIVISION_HEIGHT (SOURCE_SIZE / SOURCE_DIVISIONS_Y) static const ClutterColor corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] = { { 0xff, 0x00, 0x00, 0xff }, /* red top left */ { 0x00, 0xff, 0x00, 0xff }, /* green top right */ { 0x00, 0x00, 0xff, 0xff }, /* blue bottom left */ { 0xff, 0x00, 0xff, 0xff } /* purple bottom right */ }; static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; typedef struct _TestState { ClutterActor *stage; guint frame; gboolean was_painted; } TestState; static ClutterActor * create_source (void) { int x, y; ClutterActor *group = clutter_group_new (); /* Create a group with a different coloured rectangle at each corner */ for (y = 0; y < SOURCE_DIVISIONS_Y; y++) for (x = 0; x < SOURCE_DIVISIONS_X; x++) { ClutterActor *rect = clutter_rectangle_new (); clutter_actor_set_size (rect, DIVISION_WIDTH, DIVISION_HEIGHT); clutter_actor_set_position (rect, DIVISION_WIDTH * x, DIVISION_HEIGHT * y); clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), corner_colors + (y * SOURCE_DIVISIONS_X + x)); clutter_container_add (CLUTTER_CONTAINER (group), rect, NULL); } return group; } static void pre_paint_clip_cb (void) { /* Generate a clip path that clips out the top left division */ cogl_path_move_to (DIVISION_WIDTH, 0); cogl_path_line_to (SOURCE_SIZE, 0); cogl_path_line_to (SOURCE_SIZE, SOURCE_SIZE); cogl_path_line_to (0, SOURCE_SIZE); cogl_path_line_to (0, DIVISION_HEIGHT); cogl_path_line_to (DIVISION_WIDTH, DIVISION_HEIGHT); cogl_path_close (); cogl_clip_push_from_path (); } static void post_paint_clip_cb (void) { cogl_clip_pop (); } static void validate_part (TestState *state, int xpos, int ypos, int clip_flags) { int x, y; /* Check whether the center of each division is the right color */ for (y = 0; y < SOURCE_DIVISIONS_Y; y++) for (x = 0; x < SOURCE_DIVISIONS_X; x++) { guchar *pixels; const ClutterColor *correct_color; /* Read the center pixels of this division */ pixels = clutter_stage_read_pixels (CLUTTER_STAGE (state->stage), x * DIVISION_WIDTH + DIVISION_WIDTH / 2 + xpos, y * DIVISION_HEIGHT + DIVISION_HEIGHT / 2 + ypos, 1, 1); /* If this division is clipped then it should be the stage color */ if ((clip_flags & (1 << ((y * SOURCE_DIVISIONS_X) + x)))) correct_color = &stage_color; else /* Otherwise it should be the color for this division */ correct_color = corner_colors + (y * SOURCE_DIVISIONS_X) + x; g_assert (pixels != NULL); g_assert_cmpint (pixels[0], ==, correct_color->red); g_assert_cmpint (pixels[1], ==, correct_color->green); g_assert_cmpint (pixels[2], ==, correct_color->blue); free (pixels); } } static void validate_result (TestState *state) { int ypos = 0; if (g_test_verbose ()) g_print ("Testing onscreen clone...\n"); validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 0); ypos++; #if 0 /* this doesn't work */ if (g_test_verbose ()) g_print ("Testing offscreen clone...\n"); validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 0); #endif ypos++; if (g_test_verbose ()) g_print ("Testing onscreen clone with rectangular clip...\n"); validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, ~1); ypos++; if (g_test_verbose ()) g_print ("Testing onscreen clone with path clip...\n"); validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 1); ypos++; } static gboolean on_paint (gpointer data) { TestState *state = data; int frame_num; /* XXX: validate_result calls clutter_stage_read_pixels which will result in * another paint run so to avoid infinite recursion we only aim to validate * the first frame. */ frame_num = state->frame++; if (frame_num == 1) validate_result (state); state->was_painted = TRUE; return G_SOURCE_REMOVE; } void texture_fbo (TestConformSimpleFixture *fixture, gconstpointer data) { TestState state; ClutterActor *actor; int ypos = 0; if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) { if (g_test_verbose ()) g_print ("Offscreen buffers are not available, skipping.\n"); return; } state.frame = 0; state.stage = clutter_stage_new (); clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color); /* Onscreen source with clone next to it */ actor = create_source (); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); clutter_actor_set_position (actor, 0, ypos * SOURCE_SIZE); actor = clutter_texture_new_from_actor (actor); clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); ypos++; /* Offscreen source with clone */ #if 0 /* this doesn't work */ actor = create_source (); actor = clutter_texture_new_from_actor (actor); clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); #endif ypos++; /* Source clipped to the top left division */ actor = create_source (); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); clutter_actor_set_position (actor, 0, ypos * SOURCE_SIZE); clutter_actor_set_clip (actor, 0, 0, DIVISION_WIDTH, DIVISION_HEIGHT); actor = clutter_texture_new_from_actor (actor); clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); ypos++; /* Source clipped to everything but top left division using a path */ actor = create_source (); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); clutter_actor_set_position (actor, 0, ypos * SOURCE_SIZE); g_signal_connect (actor, "paint", G_CALLBACK (pre_paint_clip_cb), NULL); g_signal_connect_after (actor, "paint", G_CALLBACK (post_paint_clip_cb), NULL); actor = clutter_texture_new_from_actor (actor); clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); ypos++; clutter_actor_show (state.stage); clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT, on_paint, &state, NULL); while (!state.was_painted) g_main_context_iteration (NULL, FALSE); clutter_actor_destroy (state.stage); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-size.c�����������������������������������������������������0000664�0001750�0001750�00000013707�14211404421�021657� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #include <clutter/clutter.h> #define TEST_TYPE_ACTOR (test_actor_get_type ()) typedef struct _TestActor TestActor; typedef struct _ClutterActorClass TestActorClass; struct _TestActor { ClutterActor parent_instance; guint preferred_width_called : 1; guint preferred_height_called : 1; }; GType test_actor_get_type (void); G_DEFINE_TYPE (TestActor, test_actor, CLUTTER_TYPE_ACTOR); static void test_actor_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { TestActor *test = (TestActor *) self; test->preferred_width_called = TRUE; if (for_height == 10) { *min_width_p = 10; *nat_width_p = 100; } else { *min_width_p = 100; *nat_width_p = 100; } } static void test_actor_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { TestActor *test = (TestActor *) self; test->preferred_height_called = TRUE; if (for_width == 10) { *min_height_p = 50; *nat_height_p = 100; } else { *min_height_p = 100; *nat_height_p = 100; } } static void test_actor_class_init (TestActorClass *klass) { ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); actor_class->get_preferred_width = test_actor_get_preferred_width; actor_class->get_preferred_height = test_actor_get_preferred_height; } static void test_actor_init (TestActor *self) { } static void actor_preferred_size (void) { ClutterActor *test; TestActor *self; gfloat min_width, min_height; gfloat nat_width, nat_height; test = g_object_new (TEST_TYPE_ACTOR, NULL); self = (TestActor *) test; if (g_test_verbose ()) g_print ("Preferred size\n"); clutter_actor_get_preferred_size (test, &min_width, &min_height, &nat_width, &nat_height); g_assert (self->preferred_width_called); g_assert (self->preferred_height_called); g_assert_cmpfloat (min_width, ==, 100); g_assert_cmpfloat (min_height, ==, 100); g_assert_cmpfloat (nat_width, ==, min_width); g_assert_cmpfloat (nat_height, ==, min_height); if (g_test_verbose ()) g_print ("Preferred width\n"); self->preferred_width_called = FALSE; clutter_actor_get_preferred_width (test, 10, &min_width, &nat_width); g_assert (self->preferred_width_called); g_assert_cmpfloat (min_width, ==, 10); g_assert_cmpfloat (nat_width, ==, 100); if (g_test_verbose ()) g_print ("Preferred height\n"); self->preferred_height_called = FALSE; clutter_actor_get_preferred_height (test, 200, &min_height, &nat_height); g_assert (self->preferred_height_called); g_assert_cmpfloat (min_height, !=, 10); g_assert_cmpfloat (nat_height, ==, 100); if (g_test_verbose ()) g_print ("Preferred width (cached)\n"); self->preferred_width_called = FALSE; clutter_actor_get_preferred_width (test, 10, &min_width, &nat_width); g_assert (!self->preferred_width_called); g_assert_cmpfloat (min_width, ==, 10); g_assert_cmpfloat (nat_width, ==, 100); if (g_test_verbose ()) g_print ("Preferred height (cache eviction)\n"); self->preferred_height_called = FALSE; clutter_actor_get_preferred_height (test, 10, &min_height, &nat_height); g_assert (self->preferred_height_called); g_assert_cmpfloat (min_height, ==, 50); g_assert_cmpfloat (nat_height, ==, 100); clutter_actor_destroy (test); } static void actor_fixed_size (void) { ClutterActor *rect; gboolean min_width_set, nat_width_set; gboolean min_height_set, nat_height_set; gfloat min_width, min_height; gfloat nat_width, nat_height; rect = clutter_actor_new (); g_object_ref_sink (rect); if (g_test_verbose ()) g_print ("Initial size is 0\n"); g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 0); g_assert_cmpfloat (clutter_actor_get_height (rect), ==, 0); clutter_actor_set_size (rect, 100, 100); if (g_test_verbose ()) g_print ("Explicit size set\n"); g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 100); g_assert_cmpfloat (clutter_actor_get_height (rect), ==, 100); g_object_get (G_OBJECT (rect), "min-width-set", &min_width_set, "min-height-set", &min_height_set, "natural-width-set", &nat_width_set, "natural-height-set", &nat_height_set, NULL); if (g_test_verbose ()) g_print ("Notification properties\n"); g_assert (min_width_set && nat_width_set); g_assert (min_height_set && nat_height_set); clutter_actor_get_preferred_size (rect, &min_width, &min_height, &nat_width, &nat_height); if (g_test_verbose ()) g_print ("Preferred size\n"); g_assert_cmpfloat (min_width, ==, 100); g_assert_cmpfloat (min_height, ==, 100); g_assert_cmpfloat (min_width, ==, nat_width); g_assert_cmpfloat (min_height, ==, nat_height); clutter_actor_set_size (rect, -1, -1); if (g_test_verbose ()) g_print ("Explicit size unset\n"); g_object_get (G_OBJECT (rect), "min-width-set", &min_width_set, "min-height-set", &min_height_set, "natural-width-set", &nat_width_set, "natural-height-set", &nat_height_set, NULL); g_assert (!min_width_set && !nat_width_set); g_assert (!min_height_set && !nat_height_set); g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 0); g_assert_cmpfloat (clutter_actor_get_height (rect), ==, 0); clutter_actor_destroy (rect); g_object_unref (rect); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/size/preferred", actor_preferred_size) CLUTTER_TEST_UNIT ("/actor/size/fixed", actor_fixed_size) ) ���������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-invariants.c�����������������������������������������������0000664�0001750�0001750�00000024756�14211404421�023071� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> static void actor_initial_state (void) { ClutterActor *actor; actor = clutter_actor_new (); g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); if (g_test_verbose ()) g_print ("initial state - visible: %s, realized: %s, mapped: %s\n", CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no"); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor))); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_shown_not_parented (void) { ClutterActor *actor; actor = clutter_actor_new (); g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_show (actor); if (g_test_verbose ()) g_print ("show without a parent - visible: %s, realized: %s, mapped: %s\n", CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no"); g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor)); g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); clutter_actor_destroy (actor); g_assert (actor == NULL); } static void actor_realized (void) { ClutterActor *actor; ClutterActor *stage; stage = clutter_test_get_stage (); actor = clutter_actor_new (); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); clutter_actor_hide (actor); /* don't show, so won't map */ clutter_actor_add_child (stage, actor); clutter_actor_realize (actor); g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor))); } static void actor_mapped (void) { ClutterActor *actor; ClutterActor *stage; stage = clutter_test_get_stage (); clutter_actor_show (stage); actor = clutter_actor_new (); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); clutter_actor_add_child (stage, actor); if (g_test_verbose ()) g_print ("adding to a container should map - " "visible: %s, realized: %s, mapped: %s\n", CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no"); g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (CLUTTER_ACTOR_IS_MAPPED (actor)); g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); clutter_actor_hide (actor); if (g_test_verbose ()) g_print ("hiding should unmap - " "visible: %s, realized: %s, mapped: %s\n", CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no", CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no"); g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor)); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor)); } static void actor_visibility_not_recursive (void) { ClutterActor *actor, *group; ClutterActor *stage; stage = clutter_test_get_stage (); group = clutter_actor_new (); actor = clutter_actor_new (); clutter_actor_hide (group); /* don't show, so won't map */ clutter_actor_hide (actor); /* don't show, so won't map */ g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (stage))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor))); clutter_actor_add_child (stage, group); clutter_actor_add_child (group, actor); clutter_actor_show (actor); g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (group)); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (stage)); clutter_actor_show (stage); g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (group)); g_assert (CLUTTER_ACTOR_IS_VISIBLE (stage)); clutter_actor_hide (actor); clutter_actor_hide (group); clutter_actor_hide (stage); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor)); clutter_actor_show (stage); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor)); } static void actor_realize_not_recursive (void) { ClutterActor *actor, *group; ClutterActor *stage; stage = clutter_test_get_stage (); clutter_actor_show (stage); group = clutter_actor_new (); actor = clutter_actor_new (); clutter_actor_hide (group); /* don't show, so won't map */ clutter_actor_hide (actor); /* don't show, so won't map */ g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group))); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); clutter_actor_add_child (stage, group); clutter_actor_add_child (group, actor); clutter_actor_realize (group); g_assert (CLUTTER_ACTOR_IS_REALIZED (group)); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); /* realizing group did not realize the child */ g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor))); } static void actor_map_recursive (void) { ClutterActor *actor, *group; ClutterActor *stage; stage = clutter_test_get_stage (); clutter_actor_show (stage); group = clutter_actor_new (); actor = clutter_actor_new (); clutter_actor_hide (group); /* hide at first */ clutter_actor_show (actor); /* show at first */ g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group))); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); g_assert ((CLUTTER_ACTOR_IS_VISIBLE (actor))); clutter_actor_add_child (stage, group); clutter_actor_add_child (group, actor); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group))); g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); g_assert ((CLUTTER_ACTOR_IS_VISIBLE (actor))); /* show group, which should map and realize both * group and child. */ clutter_actor_show (group); g_assert (CLUTTER_ACTOR_IS_REALIZED (group)); g_assert (CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (CLUTTER_ACTOR_IS_MAPPED (group)); g_assert (CLUTTER_ACTOR_IS_MAPPED (actor)); g_assert (CLUTTER_ACTOR_IS_VISIBLE (group)); g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); } static void actor_show_on_set_parent (void) { ClutterActor *actor, *group; gboolean show_on_set_parent; ClutterActor *stage; stage = clutter_test_get_stage (); group = clutter_actor_new (); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group))); clutter_actor_add_child (stage, group); actor = clutter_actor_new (); g_object_get (actor, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor))); g_assert (show_on_set_parent); clutter_actor_add_child (group, actor); g_object_get (actor, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); g_assert (show_on_set_parent); g_object_ref (actor); clutter_actor_remove_child (group, actor); g_object_get (actor, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor)); g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor)); g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor)); g_assert (show_on_set_parent); clutter_actor_destroy (actor); clutter_actor_destroy (group); actor = clutter_actor_new (); clutter_actor_add_child (stage, actor); clutter_actor_hide (actor); g_object_get (actor, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor)); g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor)); g_assert (show_on_set_parent); clutter_actor_destroy (actor); actor = clutter_actor_new (); clutter_actor_hide (actor); clutter_actor_add_child (stage, actor); g_object_get (actor, "show-on-set-parent", &show_on_set_parent, NULL); g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor)); g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor)); g_assert (!show_on_set_parent); clutter_actor_destroy (actor); } static void clone_no_map (void) { ClutterActor *stage; ClutterActor *group; ClutterActor *actor; ClutterActor *clone; stage = clutter_test_get_stage (); clutter_actor_show (stage); group = clutter_actor_new (); actor = clutter_actor_new (); clutter_actor_hide (group); clutter_actor_add_child (group, actor); clutter_actor_add_child (stage, group); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); clone = clutter_clone_new (group); clutter_actor_add_child (stage, clone); g_assert (CLUTTER_ACTOR_IS_MAPPED (clone)); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group))); g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor))); clutter_actor_destroy (CLUTTER_ACTOR (clone)); clutter_actor_destroy (CLUTTER_ACTOR (group)); } G_GNUC_BEGIN_IGNORE_DEPRECATIONS static void default_stage (void) { ClutterActor *stage, *def_stage; stage = clutter_test_get_stage (); def_stage = clutter_stage_get_default (); if (clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE)) g_assert (stage != def_stage); else g_assert (stage == def_stage); g_assert (CLUTTER_ACTOR_IS_REALIZED (def_stage)); } G_GNUC_END_IGNORE_DEPRECATIONS CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/invariants/initial-state", actor_initial_state) CLUTTER_TEST_UNIT ("/actor/invariants/show-not-parented", actor_shown_not_parented) CLUTTER_TEST_UNIT ("/actor/invariants/realized", actor_realized) CLUTTER_TEST_UNIT ("/actor/invariants/mapped", actor_mapped) CLUTTER_TEST_UNIT ("/actor/invariants/visibility-not-recursive", actor_visibility_not_recursive) CLUTTER_TEST_UNIT ("/actor/invariants/realize-not-recursive", actor_realize_not_recursive) CLUTTER_TEST_UNIT ("/actor/invariants/map-recursive", actor_map_recursive) CLUTTER_TEST_UNIT ("/actor/invariants/show-on-set-parent", actor_show_on_set_parent) CLUTTER_TEST_UNIT ("/actor/invariants/clone-no-map", clone_no_map) CLUTTER_TEST_UNIT ("/actor/invariants/default-stage", default_stage) ) ������������������muffin-5.2.1/clutter/tests/conform/timeline-progress.c����������������������������������������������0000664�0001750�0001750�00000007526�14211404421�023251� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <glib.h> #include <clutter/clutter.h> #include "test-conform-common.h" void timeline_progress_step (TestConformSimpleFixture *fixture G_GNUC_UNUSED, gconstpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline; timeline = clutter_timeline_new (1000); if (g_test_verbose ()) g_print ("mode: step(3, end)\n"); clutter_timeline_rewind (timeline); clutter_timeline_set_step_progress (timeline, 3, CLUTTER_STEP_MODE_END); g_assert_cmpint (clutter_timeline_get_progress (timeline), ==, 0); clutter_timeline_advance (timeline, 1000 / 3 - 1); g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 0); clutter_timeline_advance (timeline, 1000 / 3 + 1); g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 333); clutter_timeline_advance (timeline, 1000 / 3 * 2 - 1); g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 333); clutter_timeline_advance (timeline, 1000 / 3 * 2 + 1); g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 666); clutter_timeline_rewind (timeline); clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_START); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); clutter_timeline_advance (timeline, 1); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); clutter_timeline_advance (timeline, 500); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); clutter_timeline_advance (timeline, 999); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); clutter_timeline_advance (timeline, 1000); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); if (g_test_verbose ()) g_print ("mode: step-start\n"); clutter_timeline_rewind (timeline); clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_START); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); clutter_timeline_advance (timeline, 1); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); clutter_timeline_advance (timeline, 500); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); clutter_timeline_advance (timeline, 999); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); clutter_timeline_advance (timeline, 1000); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); if (g_test_verbose ()) g_print ("mode: step-end\n"); clutter_timeline_rewind (timeline); clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_END); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); clutter_timeline_advance (timeline, 1); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); clutter_timeline_advance (timeline, 500); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); clutter_timeline_advance (timeline, 999); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); clutter_timeline_advance (timeline, 1000); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); g_object_unref (timeline); } void timeline_progress_mode (TestConformSimpleFixture *fixture G_GNUC_UNUSED, gconstpointer dummy G_GNUC_UNUSED) { ClutterTimeline *timeline; timeline = clutter_timeline_new (1000); g_assert (clutter_timeline_get_progress_mode (timeline) == CLUTTER_LINEAR); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); clutter_timeline_advance (timeline, 500); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.5); clutter_timeline_advance (timeline, 1000); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0); clutter_timeline_rewind (timeline); g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0); g_object_unref (timeline); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/color.c����������������������������������������������������������0000664�0001750�0001750�00000023503�14211404421�020710� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> static void color_hls_roundtrip (void) { ClutterColor color; gfloat hue, luminance, saturation; /* test luminance only */ clutter_color_from_string (&color, "#7f7f7f"); g_assert_cmpuint (color.red, ==, 0x7f); g_assert_cmpuint (color.green, ==, 0x7f); g_assert_cmpuint (color.blue, ==, 0x7f); clutter_color_to_hls (&color, &hue, &luminance, &saturation); g_assert_cmpfloat (hue, ==, 0.0); g_assert (luminance >= 0.0 && luminance <= 1.0); g_assert_cmpfloat (saturation, ==, 0.0); if (g_test_verbose ()) { g_print ("RGB = { %x, %x, %x }, HLS = { %.2f, %.2f, %.2f }\n", color.red, color.green, color.blue, hue, luminance, saturation); } color.red = color.green = color.blue = 0; clutter_color_from_hls (&color, hue, luminance, saturation); g_assert_cmpuint (color.red, ==, 0x7f); g_assert_cmpuint (color.green, ==, 0x7f); g_assert_cmpuint (color.blue, ==, 0x7f); /* full conversion */ clutter_color_from_string (&color, "#7f8f7f"); color.alpha = 255; g_assert_cmpuint (color.red, ==, 0x7f); g_assert_cmpuint (color.green, ==, 0x8f); g_assert_cmpuint (color.blue, ==, 0x7f); clutter_color_to_hls (&color, &hue, &luminance, &saturation); g_assert (hue >= 0.0 && hue < 360.0); g_assert (luminance >= 0.0 && luminance <= 1.0); g_assert (saturation >= 0.0 && saturation <= 1.0); if (g_test_verbose ()) { g_print ("RGB = { %x, %x, %x }, HLS = { %.2f, %.2f, %.2f }\n", color.red, color.green, color.blue, hue, luminance, saturation); } color.red = color.green = color.blue = 0; clutter_color_from_hls (&color, hue, luminance, saturation); g_assert_cmpuint (color.red, ==, 0x7f); g_assert_cmpuint (color.green, ==, 0x8f); g_assert_cmpuint (color.blue, ==, 0x7f); /* the alpha channel should be untouched */ g_assert_cmpuint (color.alpha, ==, 255); } static void color_from_string_invalid (void) { ClutterColor color; g_assert (!clutter_color_from_string (&color, "ff0000ff")); g_assert (!clutter_color_from_string (&color, "#decaffbad")); g_assert (!clutter_color_from_string (&color, "ponies")); g_assert (!clutter_color_from_string (&color, "rgb(255, 0, 0, 0)")); g_assert (!clutter_color_from_string (&color, "rgba(1.0, 0, 0)")); g_assert (!clutter_color_from_string (&color, "hsl(100, 0, 0)")); g_assert (!clutter_color_from_string (&color, "hsla(10%, 0%, 50%)")); g_assert (!clutter_color_from_string (&color, "hsla(100%, 0%, 50%, 20%)")); g_assert (!clutter_color_from_string (&color, "hsla(0.5, 0.9, 0.2, 0.4)")); } static void color_from_string_valid (void) { ClutterColor color; g_assert (clutter_color_from_string (&color, "#ff0000ff")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 0xff, 0, 0, 0xff }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 0xff); g_assert_cmpuint (color.green, ==, 0); g_assert_cmpuint (color.blue, ==, 0); g_assert_cmpuint (color.alpha, ==, 0xff); g_assert (clutter_color_from_string (&color, "#0f0f")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0xff, 0, 0xff }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 0); g_assert_cmpuint (color.green, ==, 0xff); g_assert_cmpuint (color.blue, ==, 0); g_assert_cmpuint (color.alpha, ==, 0xff); g_assert (clutter_color_from_string (&color, "#0000ff")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0, 0xff, 0xff }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 0); g_assert_cmpuint (color.green, ==, 0); g_assert_cmpuint (color.blue, ==, 0xff); g_assert_cmpuint (color.alpha, ==, 0xff); g_assert (clutter_color_from_string (&color, "#abc")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 0xaa, 0xbb, 0xcc, 0xff }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 0xaa); g_assert_cmpuint (color.green, ==, 0xbb); g_assert_cmpuint (color.blue, ==, 0xcc); g_assert_cmpuint (color.alpha, ==, 0xff); g_assert (clutter_color_from_string (&color, "#123abc")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 0x12, 0x3a, 0xbc, 0xff }\n", color.red, color.green, color.blue, color.alpha); } g_assert (color.red == 0x12); g_assert (color.green == 0x3a); g_assert (color.blue == 0xbc); g_assert (color.alpha == 0xff); g_assert (clutter_color_from_string (&color, "rgb(255, 128, 64)")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 255, 128, 64, 255 }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 255); g_assert_cmpuint (color.green, ==, 128); g_assert_cmpuint (color.blue, ==, 64); g_assert_cmpuint (color.alpha, ==, 255); g_assert (clutter_color_from_string (&color, "rgba ( 30%, 0, 25%, 0.5 ) ")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { %.1f, 0, %.1f, 128 }\n", color.red, color.green, color.blue, color.alpha, CLAMP (255.0 / 100.0 * 30.0, 0, 255), CLAMP (255.0 / 100.0 * 25.0, 0, 255)); } g_assert_cmpuint (color.red, ==, (255.0 / 100.0 * 30.0)); g_assert_cmpuint (color.green, ==, 0); g_assert_cmpuint (color.blue, ==, (255.0 / 100.0 * 25.0)); g_assert_cmpuint (color.alpha, ==, 127); g_assert (clutter_color_from_string (&color, "rgb( 50%, -50%, 150% )")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 127, 0, 255, 255 }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 127); g_assert_cmpuint (color.green, ==, 0); g_assert_cmpuint (color.blue, ==, 255); g_assert_cmpuint (color.alpha, ==, 255); g_assert (clutter_color_from_string (&color, "hsl( 0, 100%, 50% )")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 255, 0, 0, 255 }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 255); g_assert_cmpuint (color.green, ==, 0); g_assert_cmpuint (color.blue, ==, 0); g_assert_cmpuint (color.alpha, ==, 255); g_assert (clutter_color_from_string (&color, "hsl( 0, 100%, 50% )")); g_assert (clutter_color_from_string (&color, "hsla( 0, 100%, 50%, 0.5 )")); if (g_test_verbose ()) { g_print ("color = { %x, %x, %x, %x }, expected = { 255, 0, 0, 127 }\n", color.red, color.green, color.blue, color.alpha); } g_assert_cmpuint (color.red, ==, 255); g_assert_cmpuint (color.green, ==, 0); g_assert_cmpuint (color.blue, ==, 0); g_assert_cmpuint (color.alpha, ==, 127); g_test_bug ("662818"); g_assert (clutter_color_from_string (&color, "hsla(0,100%,50% , 0.5)")); } static void color_to_string (void) { ClutterColor color; gchar *str; color.red = 0xcc; color.green = 0xcc; color.blue = 0xcc; color.alpha = 0x22; str = clutter_color_to_string (&color); g_assert_cmpstr (str, ==, "#cccccc22"); free (str); } static void color_operators (void) { ClutterColor op1, op2; ClutterColor res; clutter_color_from_pixel (&op1, 0xff0000ff); g_assert_cmpuint (op1.red, ==, 0xff); g_assert_cmpuint (op1.green, ==, 0); g_assert_cmpuint (op1.blue, ==, 0); g_assert_cmpuint (op1.alpha, ==, 0xff); clutter_color_from_pixel (&op2, 0x00ff00ff); g_assert_cmpuint (op2.red, ==, 0); g_assert_cmpuint (op2.green, ==, 0xff); g_assert_cmpuint (op2.blue, ==, 0); g_assert_cmpuint (op2.alpha, ==, 0xff); if (g_test_verbose ()) g_print ("Adding %x, %x; expected result: %x\n", clutter_color_to_pixel (&op1), clutter_color_to_pixel (&op2), 0xffff00ff); clutter_color_add (&op1, &op2, &res); g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0xffff00ff); if (g_test_verbose ()) g_print ("Checking alpha channel on color add\n"); op1.alpha = 0xdd; op2.alpha = 0xcc; clutter_color_add (&op1, &op2, &res); g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0xffff00dd); clutter_color_from_pixel (&op1, 0xffffffff); clutter_color_from_pixel (&op2, 0xff00ffff); if (g_test_verbose ()) g_print ("Subtracting %x, %x; expected result: %x\n", clutter_color_to_pixel (&op1), clutter_color_to_pixel (&op2), 0x00ff00ff); clutter_color_subtract (&op1, &op2, &res); g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0x00ff00ff); if (g_test_verbose ()) g_print ("Checking alpha channel on color subtract\n"); op1.alpha = 0xdd; op2.alpha = 0xcc; clutter_color_subtract (&op1, &op2, &res); g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0x00ff00cc); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/color/hls-roundtrip", color_hls_roundtrip) CLUTTER_TEST_UNIT ("/color/from-string/invalid", color_from_string_invalid) CLUTTER_TEST_UNIT ("/color/from-string/valid", color_from_string_valid) CLUTTER_TEST_UNIT ("/color/to-string", color_to_string) CLUTTER_TEST_UNIT ("/color/operators", color_operators) ) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/rectangle.c������������������������������������������������������0000664�0001750�0001750�00000003020�14211404421�021526� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> static void rectangle_set_size (void) { ClutterActor *rect = clutter_rectangle_new (); /* initial positioning */ g_assert_cmpint (clutter_actor_get_x (rect), ==, 0); g_assert_cmpint (clutter_actor_get_y (rect), ==, 0); clutter_actor_set_size (rect, 100, 100); /* make sure that changing the size does not affect the * rest of the bounding box */ g_assert_cmpint (clutter_actor_get_x (rect), ==, 0); g_assert_cmpint (clutter_actor_get_y (rect), ==, 0); g_assert_cmpint (clutter_actor_get_width (rect), ==, 100); g_assert_cmpint (clutter_actor_get_height (rect), ==, 100); clutter_actor_destroy (rect); } static void rectangle_set_color (void) { ClutterActor *rect = clutter_rectangle_new (); ClutterColor white = { 255, 255, 255, 255 }; ClutterColor black = { 0, 0, 0, 255 }; ClutterColor check = { 0, }; clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &black); clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &check); g_assert_cmpint (check.blue, ==, black.blue); clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &white); clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &check); g_assert_cmpint (check.green, ==, white.green); g_assert_cmpint (clutter_actor_get_opacity (rect), ==, white.alpha); clutter_actor_destroy (rect); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/rectangle/set-size", rectangle_set_size) CLUTTER_TEST_UNIT ("/rectangle/set-color", rectangle_set_color) ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/interval.c�������������������������������������������������������0000664�0001750�0001750�00000007451�14211404421�021422� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> static void interval_initial_state (void) { ClutterInterval *interval; int initial, final; const GValue *value; interval = clutter_interval_new (G_TYPE_INT, 0, 100); g_assert (CLUTTER_IS_INTERVAL (interval)); g_assert (clutter_interval_get_value_type (interval) == G_TYPE_INT); clutter_interval_get_interval (interval, &initial, &final); g_assert_cmpint (initial, ==, 0); g_assert_cmpint (final, ==, 100); value = clutter_interval_compute (interval, 0); g_assert (G_VALUE_HOLDS_INT (value)); g_assert_cmpint (g_value_get_int (value), ==, 0); value = clutter_interval_compute (interval, 1); g_assert (G_VALUE_HOLDS_INT (value)); g_assert_cmpint (g_value_get_int (value), ==, 100); value = clutter_interval_compute (interval, 0.5); g_assert (G_VALUE_HOLDS_INT (value)); g_assert_cmpint (g_value_get_int (value), ==, 50); clutter_interval_set_final (interval, 200); value = clutter_interval_peek_final_value (interval); g_assert (G_VALUE_HOLDS_INT (value)); g_assert_cmpint (g_value_get_int (value), ==, 200); g_object_unref (interval); } static void interval_transform (void) { ClutterInterval *interval; GValue value = G_VALUE_INIT; const GValue *value_p = NULL; interval = clutter_interval_new_with_values (G_TYPE_FLOAT, NULL, NULL); g_value_init (&value, G_TYPE_DOUBLE); g_value_set_double (&value, 0.0); clutter_interval_set_initial_value (interval, &value); g_value_set_double (&value, 100.0); clutter_interval_set_final_value (interval, &value); g_value_unset (&value); value_p = clutter_interval_peek_initial_value (interval); g_assert (G_VALUE_HOLDS_FLOAT (value_p)); g_assert_cmpfloat (g_value_get_float (value_p), ==, 0.f); value_p = clutter_interval_peek_final_value (interval); g_assert (G_VALUE_HOLDS_FLOAT (value_p)); g_assert_cmpfloat (g_value_get_float (value_p), ==, 100.f); g_object_unref (interval); } static void interval_from_script (void) { ClutterScript *script = clutter_script_new (); ClutterInterval *interval; gchar *test_file; GError *error = NULL; GValue *initial, *final; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-interval.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_printerr ("\tError: %s", error->message); g_assert_no_error (error); interval = CLUTTER_INTERVAL (clutter_script_get_object (script, "int-1")); initial = clutter_interval_peek_initial_value (interval); if (g_test_verbose ()) g_test_message ("\tinitial ['%s'] = '%.2f'", g_type_name (G_VALUE_TYPE (initial)), g_value_get_float (initial)); g_assert (G_VALUE_HOLDS (initial, G_TYPE_FLOAT)); g_assert_cmpfloat (g_value_get_float (initial), ==, 23.3f); final = clutter_interval_peek_final_value (interval); if (g_test_verbose ()) g_test_message ("\tfinal ['%s'] = '%.2f'", g_type_name (G_VALUE_TYPE (final)), g_value_get_float (final)); g_assert (G_VALUE_HOLDS (final, G_TYPE_FLOAT)); g_assert_cmpfloat (g_value_get_float (final), ==, 42.2f); interval = CLUTTER_INTERVAL (clutter_script_get_object (script, "int-2")); initial = clutter_interval_peek_initial_value (interval); g_assert (G_VALUE_HOLDS (initial, CLUTTER_TYPE_COLOR)); final = clutter_interval_peek_final_value (interval); g_assert (G_VALUE_HOLDS (final, CLUTTER_TYPE_COLOR)); g_object_unref (script); free (test_file); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/interval/initial-state", interval_initial_state) CLUTTER_TEST_UNIT ("/interval/transform", interval_transform) CLUTTER_TEST_UNIT ("/interval/from-script", interval_from_script) ) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/timeline-rewind.c������������������������������������������������0000664�0001750�0001750�00000004130�14211404421�022661� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <clutter/clutter.h> #include "test-conform-common.h" #define TEST_TIMELINE_DURATION 500 #define TEST_WATCHDOG_KICK_IN_SECONDS 10 typedef struct _TestState { ClutterTimeline *timeline; gint rewind_count; } TestState; static gboolean watchdog_timeout (gpointer data) { TestState *state = data; g_test_message ("Watchdog timer kicking in"); g_test_message ("rewind_count=%i", state->rewind_count); if (state->rewind_count <= 3) { /* The test has hung */ g_test_message ("Failed (This test shouldn't have hung!)"); exit (EXIT_FAILURE); } else { g_test_message ("Passed"); clutter_main_quit (); } return G_SOURCE_REMOVE; } static void new_frame_cb (ClutterTimeline *timeline, gint elapsed_time, TestState *state) { if (elapsed_time == TEST_TIMELINE_DURATION) { g_test_message ("new-frame signal received (end of timeline)"); g_test_message ("Rewinding timeline"); clutter_timeline_rewind (timeline); state->rewind_count++; } else { if (elapsed_time == 0) { g_test_message ("new-frame signal received (start of timeline)"); } else { g_test_message ("new-frame signal received (mid frame)"); } if (state->rewind_count >= 2) { g_test_message ("Sleeping for 1 second"); g_usleep (1000000); } } } void timeline_rewind (void) { TestState state; state.timeline = clutter_timeline_new (TEST_TIMELINE_DURATION); g_signal_connect (G_OBJECT(state.timeline), "new-frame", G_CALLBACK(new_frame_cb), &state); g_test_message ("Installing a watchdog timeout " "to determine if this test hangs"); clutter_threads_add_timeout (TEST_WATCHDOG_KICK_IN_SECONDS * 1000, watchdog_timeout, &state); state.rewind_count = 0; clutter_timeline_start (state.timeline); clutter_main(); g_object_unref (state.timeline); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/units.c����������������������������������������������������������0000664�0001750�0001750�00000011474�14211404421�020740� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> static void units_cache (void) { ClutterUnits units; ClutterSettings *settings; gfloat pixels; gint old_dpi; settings = clutter_settings_get_default (); g_object_get (settings, "font-dpi", &old_dpi, NULL); g_object_set (settings, "font-dpi", 96 * 1024, NULL); clutter_units_from_em (&units, 1.0); pixels = clutter_units_to_pixels (&units); g_object_set (settings, "font-dpi", ((96 * 2) * 1024), NULL); g_assert_cmpfloat (clutter_units_to_pixels (&units), !=, pixels); g_object_set (settings, "font-dpi", (96 * 1024), NULL); g_assert_cmpfloat (clutter_units_to_pixels (&units), ==, pixels); g_object_set (settings, "font-dpi", old_dpi, NULL); } static void units_constructors (void) { ClutterUnits units, units_cm; clutter_units_from_pixels (&units, 100); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 100.0); g_assert_cmpfloat (clutter_units_to_pixels (&units), ==, 100.0); clutter_units_from_em (&units, 5.0); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5.0); g_assert_cmpfloat (clutter_units_to_pixels (&units), !=, 5.0); clutter_units_from_cm (&units_cm, 5.0); g_assert (clutter_units_get_unit_type (&units_cm) == CLUTTER_UNIT_CM); g_assert_cmpfloat (clutter_units_get_unit_value (&units_cm), ==, 5.0); g_assert_cmpfloat (clutter_units_to_pixels (&units_cm), !=, 5.0); clutter_units_from_mm (&units, 50.0); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM); g_assert_cmpfloat (clutter_units_to_pixels (&units), ==, clutter_units_to_pixels (&units_cm)); } static void units_string (void) { ClutterUnits units; gchar *string; g_assert (clutter_units_from_string (&units, "") == FALSE); g_assert (clutter_units_from_string (&units, "10") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 10); g_assert (clutter_units_from_string (&units, "10 px") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL); g_assert (clutter_units_from_string (&units, "10 mm") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM); g_assert (clutter_units_from_string (&units, "10 cm") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_CM); g_assert (clutter_units_from_string (&units, "10 ") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 10); g_assert (clutter_units_from_string (&units, "5 em") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5); g_assert (clutter_units_from_string (&units, "5 emeralds") == FALSE); g_assert (clutter_units_from_string (&units, " 16 mm") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 16); g_assert (clutter_units_from_string (&units, " 24 pt ") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_POINT); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 24); g_assert (clutter_units_from_string (&units, " 32 em garbage") == FALSE); g_assert (clutter_units_from_string (&units, "5.1cm") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_CM); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5.1f); g_assert (clutter_units_from_string (&units, "5,mm") == FALSE); g_assert (clutter_units_from_string (&units, ".5pt") == TRUE); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_POINT); g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 0.5f); g_assert (clutter_units_from_string (&units, "1 omg!!pony") == FALSE); clutter_units_from_pt (&units, 24.0); string = clutter_units_to_string (&units); g_assert_cmpstr (string, ==, "24.0 pt"); free (string); clutter_units_from_em (&units, 3.0); string = clutter_units_to_string (&units); g_assert_cmpstr (string, ==, "3.00 em"); units.unit_type = CLUTTER_UNIT_PIXEL; units.value = 0; g_assert (clutter_units_from_string (&units, string) == TRUE); g_assert (clutter_units_get_unit_type (&units) != CLUTTER_UNIT_PIXEL); g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); g_assert_cmpint ((int) clutter_units_get_unit_value (&units), ==, 3); free (string); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/units/string", units_string) CLUTTER_TEST_UNIT ("/units/cache", units_cache) CLUTTER_TEST_UNIT ("/units/constructors", units_constructors) ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/path.c�����������������������������������������������������������0000664�0001750�0001750�00000043615�14211404421�020534� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <cairo.h> #include <string.h> #include <math.h> #include "test-conform-common.h" #define MAX_NODES 128 #define FLOAT_FUZZ_AMOUNT 5.0f typedef struct _CallbackData CallbackData; typedef gboolean (* PathTestFunc) (CallbackData *data); static void compare_node (const ClutterPathNode *node, gpointer data_p); struct _CallbackData { ClutterPath *path; guint n_nodes; ClutterPathNode nodes[MAX_NODES]; gboolean nodes_different; guint nodes_found; }; static const char path_desc[] = "M 21 22 " "L 25 26 " "C 29 30 31 32 33 34 " "m 23 24 " "l 27 28 " "c 35 36 37 38 39 40 " "z"; static const ClutterPathNode path_nodes[] = { { CLUTTER_PATH_MOVE_TO, { { 21, 22 }, { 0, 0 }, { 0, 0 } } }, { CLUTTER_PATH_LINE_TO, { { 25, 26 }, { 0, 0 }, { 0, 0 } } }, { CLUTTER_PATH_CURVE_TO, { { 29, 30 }, { 31, 32 }, { 33, 34 } } }, { CLUTTER_PATH_REL_MOVE_TO, { { 23, 24 }, { 0, 0 }, { 0, 0 } } }, { CLUTTER_PATH_REL_LINE_TO, { { 27, 28 }, { 0, 0 }, { 0, 0 } } }, { CLUTTER_PATH_REL_CURVE_TO, { { 35, 36 }, { 37, 38 }, { 39, 40 } } }, { CLUTTER_PATH_CLOSE, { { 0, 0 }, { 0, 0 }, { 0, 0 } } } }; static gboolean path_test_add_move_to (CallbackData *data) { ClutterPathNode node = { 0, }; node.type = CLUTTER_PATH_MOVE_TO; node.points[0].x = 1; node.points[0].y = 2; clutter_path_add_move_to (data->path, node.points[0].x, node.points[0].y); data->nodes[data->n_nodes++] = node; return TRUE; } static gboolean path_test_add_line_to (CallbackData *data) { ClutterPathNode node = { 0, }; node.type = CLUTTER_PATH_LINE_TO; node.points[0].x = 3; node.points[0].y = 4; clutter_path_add_line_to (data->path, node.points[0].x, node.points[0].y); data->nodes[data->n_nodes++] = node; return TRUE; } static gboolean path_test_add_curve_to (CallbackData *data) { ClutterPathNode node = { 0, }; node.type = CLUTTER_PATH_CURVE_TO; node.points[0].x = 5; node.points[0].y = 6; node.points[1].x = 7; node.points[1].y = 8; node.points[2].x = 9; node.points[2].y = 10; clutter_path_add_curve_to (data->path, node.points[0].x, node.points[0].y, node.points[1].x, node.points[1].y, node.points[2].x, node.points[2].y); data->nodes[data->n_nodes++] = node; return TRUE; } static gboolean path_test_add_close (CallbackData *data) { ClutterPathNode node = { 0, }; node.type = CLUTTER_PATH_CLOSE; clutter_path_add_close (data->path); data->nodes[data->n_nodes++] = node; return TRUE; } static gboolean path_test_add_rel_move_to (CallbackData *data) { ClutterPathNode node = { 0, }; node.type = CLUTTER_PATH_REL_MOVE_TO; node.points[0].x = 11; node.points[0].y = 12; clutter_path_add_rel_move_to (data->path, node.points[0].x, node.points[0].y); data->nodes[data->n_nodes++] = node; return TRUE; } static gboolean path_test_add_rel_line_to (CallbackData *data) { ClutterPathNode node = { 0, }; node.type = CLUTTER_PATH_REL_LINE_TO; node.points[0].x = 13; node.points[0].y = 14; clutter_path_add_rel_line_to (data->path, node.points[0].x, node.points[0].y); data->nodes[data->n_nodes++] = node; return TRUE; } static gboolean path_test_add_rel_curve_to (CallbackData *data) { ClutterPathNode node = { 0, }; node.type = CLUTTER_PATH_REL_CURVE_TO; node.points[0].x = 15; node.points[0].y = 16; node.points[1].x = 17; node.points[1].y = 18; node.points[2].x = 19; node.points[2].y = 20; clutter_path_add_rel_curve_to (data->path, node.points[0].x, node.points[0].y, node.points[1].x, node.points[1].y, node.points[2].x, node.points[2].y); data->nodes[data->n_nodes++] = node; return TRUE; } static gboolean path_test_add_string (CallbackData *data) { int i; for (i = 0; i < G_N_ELEMENTS (path_nodes); i++) data->nodes[data->n_nodes++] = path_nodes[i]; clutter_path_add_string (data->path, path_desc); return TRUE; } static gboolean path_test_add_node_by_struct (CallbackData *data) { int i; for (i = 0; i < G_N_ELEMENTS (path_nodes); i++) { data->nodes[data->n_nodes++] = path_nodes[i]; clutter_path_add_node (data->path, path_nodes + i); } return TRUE; } static gboolean path_test_get_n_nodes (CallbackData *data) { return clutter_path_get_n_nodes (data->path) == data->n_nodes; } static gboolean path_test_get_node (CallbackData *data) { int i; data->nodes_found = 0; data->nodes_different = FALSE; for (i = 0; i < data->n_nodes; i++) { ClutterPathNode node; clutter_path_get_node (data->path, i, &node); compare_node (&node, data); } return !data->nodes_different; } static gboolean path_test_get_nodes (CallbackData *data) { GSList *list, *node; data->nodes_found = 0; data->nodes_different = FALSE; list = clutter_path_get_nodes (data->path); for (node = list; node; node = node->next) compare_node (node->data, data); g_slist_free (list); return !data->nodes_different && data->nodes_found == data->n_nodes; } static gboolean path_test_insert_beginning (CallbackData *data) { ClutterPathNode node; node.type = CLUTTER_PATH_LINE_TO; node.points[0].x = 41; node.points[0].y = 42; memmove (data->nodes + 1, data->nodes, data->n_nodes++ * sizeof (ClutterPathNode)); data->nodes[0] = node; clutter_path_insert_node (data->path, 0, &node); return TRUE; } static gboolean path_test_insert_end (CallbackData *data) { ClutterPathNode node; node.type = CLUTTER_PATH_LINE_TO; node.points[0].x = 43; node.points[0].y = 44; data->nodes[data->n_nodes++] = node; clutter_path_insert_node (data->path, -1, &node); return TRUE; } static gboolean path_test_insert_middle (CallbackData *data) { ClutterPathNode node; int pos = data->n_nodes / 2; node.type = CLUTTER_PATH_LINE_TO; node.points[0].x = 45; node.points[0].y = 46; memmove (data->nodes + pos + 1, data->nodes + pos, (data->n_nodes - pos) * sizeof (ClutterPathNode)); data->nodes[pos] = node; data->n_nodes++; clutter_path_insert_node (data->path, pos, &node); return TRUE; } static gboolean path_test_clear (CallbackData *data) { clutter_path_clear (data->path); data->n_nodes = 0; return TRUE; } static gboolean path_test_clear_insert (CallbackData *data) { return path_test_clear (data) && path_test_insert_middle (data); } static gboolean path_test_remove_beginning (CallbackData *data) { memmove (data->nodes, data->nodes + 1, --data->n_nodes * sizeof (ClutterPathNode)); clutter_path_remove_node (data->path, 0); return TRUE; } static gboolean path_test_remove_end (CallbackData *data) { clutter_path_remove_node (data->path, --data->n_nodes); return TRUE; } static gboolean path_test_remove_middle (CallbackData *data) { int pos = data->n_nodes / 2; memmove (data->nodes + pos, data->nodes + pos + 1, (--data->n_nodes - pos) * sizeof (ClutterPathNode)); clutter_path_remove_node (data->path, pos); return TRUE; } static gboolean path_test_remove_only (CallbackData *data) { return path_test_clear (data) && path_test_add_line_to (data) && path_test_remove_beginning (data); } static gboolean path_test_replace (CallbackData *data) { ClutterPathNode node; int pos = data->n_nodes / 2; node.type = CLUTTER_PATH_LINE_TO; node.points[0].x = 47; node.points[0].y = 48; data->nodes[pos] = node; clutter_path_replace_node (data->path, pos, &node); return TRUE; } static gboolean path_test_set_description (CallbackData *data) { data->n_nodes = G_N_ELEMENTS (path_nodes); memcpy (data->nodes, path_nodes, sizeof (path_nodes)); return clutter_path_set_description (data->path, path_desc); } static gboolean path_test_get_description (CallbackData *data) { char *desc1, *desc2; gboolean ret = TRUE; desc1 = clutter_path_get_description (data->path); clutter_path_clear (data->path); if (!clutter_path_set_description (data->path, desc1)) ret = FALSE; desc2 = clutter_path_get_description (data->path); if (strcmp (desc1, desc2)) ret = FALSE; free (desc1); free (desc2); return ret; } static gboolean path_test_convert_to_cairo_path (CallbackData *data) { cairo_surface_t *surface; cairo_t *cr; cairo_path_t *cpath; guint i, j; ClutterKnot path_start = { 0, 0 }, last_point = { 0, 0 }; /* Create a temporary image surface and context to hold the cairo path */ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10); cr = cairo_create (surface); /* Convert to a cairo path */ clutter_path_to_cairo_path (data->path, cr); /* Get a copy of the cairo path data */ cpath = cairo_copy_path (cr); /* Convert back to a clutter path */ clutter_path_clear (data->path); clutter_path_add_cairo_path (data->path, cpath); /* The relative nodes will have been converted to absolute so we need to reflect this in the node array for comparison */ for (i = 0; i < data->n_nodes; i++) { switch (data->nodes[i].type) { case CLUTTER_PATH_MOVE_TO: path_start = last_point = data->nodes[i].points[0]; break; case CLUTTER_PATH_LINE_TO: last_point = data->nodes[i].points[0]; break; case CLUTTER_PATH_CURVE_TO: last_point = data->nodes[i].points[2]; break; case CLUTTER_PATH_REL_MOVE_TO: last_point.x += data->nodes[i].points[0].x; last_point.y += data->nodes[i].points[0].y; data->nodes[i].points[0] = last_point; data->nodes[i].type = CLUTTER_PATH_MOVE_TO; path_start = last_point; break; case CLUTTER_PATH_REL_LINE_TO: last_point.x += data->nodes[i].points[0].x; last_point.y += data->nodes[i].points[0].y; data->nodes[i].points[0] = last_point; data->nodes[i].type = CLUTTER_PATH_LINE_TO; break; case CLUTTER_PATH_REL_CURVE_TO: for (j = 0; j < 3; j++) { data->nodes[i].points[j].x += last_point.x; data->nodes[i].points[j].y += last_point.y; } last_point = data->nodes[i].points[2]; data->nodes[i].type = CLUTTER_PATH_CURVE_TO; break; case CLUTTER_PATH_CLOSE: last_point = path_start; /* Cairo always adds a move to after every close so we need to insert one here. Since Cairo commit 166453c1abf2 it doesn't seem to do this anymore so will assume that if Cairo's minor version is >= 11 then it includes that commit */ if (cairo_version () < CAIRO_VERSION_ENCODE (1, 11, 0)) { memmove (data->nodes + i + 2, data->nodes + i + 1, (data->n_nodes - i - 1) * sizeof (ClutterPathNode)); data->nodes[i + 1].type = CLUTTER_PATH_MOVE_TO; data->nodes[i + 1].points[0] = last_point; data->n_nodes++; } break; } } /* Free the cairo resources */ cairo_path_destroy (cpath); cairo_destroy (cr); cairo_surface_destroy (surface); return TRUE; } static gboolean float_fuzzy_equals (float fa, float fb) { return fabs (fa - fb) <= FLOAT_FUZZ_AMOUNT; } static void set_triangle_path (CallbackData *data) { /* Triangular shaped path hitting (0,0), (64,64) and (128,0) in four parts. The two curves are actually straight lines */ static const ClutterPathNode nodes[] = { { CLUTTER_PATH_MOVE_TO, { { 0, 0 } } }, { CLUTTER_PATH_LINE_TO, { { 32, 32 } } }, { CLUTTER_PATH_CURVE_TO, { { 40, 40 }, { 56, 56 }, { 64, 64 } } }, { CLUTTER_PATH_REL_CURVE_TO, { { 8, -8 }, { 24, -24 }, { 32, -32 } } }, { CLUTTER_PATH_REL_LINE_TO, { { 32, -32 } } } }; gint i; clutter_path_clear (data->path); for (i = 0; i < G_N_ELEMENTS (nodes); i++) clutter_path_add_node (data->path, nodes + i); memcpy (data->nodes, nodes, sizeof (nodes)); data->n_nodes = G_N_ELEMENTS (nodes); } static gboolean path_test_get_position (CallbackData *data) { static const float values[] = { 0.125f, 16.0f, 16.0f, 0.375f, 48.0f, 48.0f, 0.625f, 80.0f, 48.0f, 0.875f, 112.0f, 16.0f }; gint i; set_triangle_path (data); for (i = 0; i < G_N_ELEMENTS (values); i += 3) { ClutterKnot pos; clutter_path_get_position (data->path, values[i], &pos); if (!float_fuzzy_equals (values[i + 1], pos.x) || !float_fuzzy_equals (values[i + 2], pos.y)) return FALSE; } return TRUE; } static gboolean path_test_get_length (CallbackData *data) { const float actual_length /* sqrt(64**2 + 64**2) * 2 */ = 181.019336f; guint approx_length; clutter_path_set_description (data->path, "M 0 0 L 46340 0"); g_object_get (data->path, "length", &approx_length, NULL); if (!(fabs (approx_length - 46340.f) / 46340.f <= 0.15f)) { if (g_test_verbose ()) g_print ("M 0 0 L 46340 0 - Expected 46340, got %d instead.", approx_length); return FALSE; } clutter_path_set_description (data->path, "M 0 0 L 46341 0"); g_object_get (data->path, "length", &approx_length, NULL); if (!(fabs (approx_length - 46341.f) / 46341.f <= 0.15f)) { if (g_test_verbose ()) g_print ("M 0 0 L 46341 0 - Expected 46341, got %d instead.", approx_length); return FALSE; } set_triangle_path (data); g_object_get (data->path, "length", &approx_length, NULL); /* Allow 15% margin of error */ if (!(fabs (approx_length - actual_length) / (float) actual_length <= 0.15f)) { if (g_test_verbose ()) g_print ("Expected %g, got %d instead.\n", actual_length, approx_length); return FALSE; } return TRUE; } static gboolean path_test_boxed_type (CallbackData *data) { gboolean ret = TRUE; GSList *nodes, *l; GValue value; nodes = clutter_path_get_nodes (data->path); memset (&value, 0, sizeof (value)); for (l = nodes; l; l = l->next) { g_value_init (&value, CLUTTER_TYPE_PATH_NODE); g_value_set_boxed (&value, l->data); if (!clutter_path_node_equal (l->data, g_value_get_boxed (&value))) ret = FALSE; g_value_unset (&value); } g_slist_free (nodes); return ret; } static const struct { const char *desc; PathTestFunc func; } path_tests[] = { { "Add line to", path_test_add_line_to }, { "Add move to", path_test_add_move_to }, { "Add curve to", path_test_add_curve_to }, { "Add close", path_test_add_close }, { "Add relative line to", path_test_add_rel_line_to }, { "Add relative move to", path_test_add_rel_move_to }, { "Add relative curve to", path_test_add_rel_curve_to }, { "Add string", path_test_add_string }, { "Add node by struct", path_test_add_node_by_struct }, { "Get number of nodes", path_test_get_n_nodes }, { "Get a node", path_test_get_node }, { "Get all nodes", path_test_get_nodes }, { "Insert at beginning", path_test_insert_beginning }, { "Insert at end", path_test_insert_end }, { "Insert at middle", path_test_insert_middle }, { "Add after insert", path_test_add_line_to }, { "Clear then insert", path_test_clear_insert }, { "Add string again", path_test_add_string }, { "Remove from beginning", path_test_remove_beginning }, { "Remove from end", path_test_remove_end }, { "Remove from middle", path_test_remove_middle }, { "Add after remove", path_test_add_line_to }, { "Remove only node", path_test_remove_only }, { "Add after remove again", path_test_add_line_to }, { "Replace a node", path_test_replace }, { "Set description", path_test_set_description }, { "Get description", path_test_get_description }, { "Convert to cairo path and back", path_test_convert_to_cairo_path }, { "Clear", path_test_clear }, { "Get position", path_test_get_position }, { "Check node boxed type", path_test_boxed_type }, { "Get length", path_test_get_length } }; static void compare_node (const ClutterPathNode *node, gpointer data_p) { CallbackData *data = data_p; if (data->nodes_found >= data->n_nodes) data->nodes_different = TRUE; else { guint n_points = 0, i; const ClutterPathNode *onode = data->nodes + data->nodes_found; if (node->type != onode->type) data->nodes_different = TRUE; switch (node->type & ~CLUTTER_PATH_RELATIVE) { case CLUTTER_PATH_MOVE_TO: n_points = 1; break; case CLUTTER_PATH_LINE_TO: n_points = 1; break; case CLUTTER_PATH_CURVE_TO: n_points = 3; break; case CLUTTER_PATH_CLOSE: n_points = 0; break; default: data->nodes_different = TRUE; break; } for (i = 0; i < n_points; i++) if (node->points[i].x != onode->points[i].x || node->points[i].y != onode->points[i].y) { data->nodes_different = TRUE; break; } } data->nodes_found++; } static gboolean compare_nodes (CallbackData *data) { data->nodes_different = FALSE; data->nodes_found = 0; clutter_path_foreach (data->path, compare_node, data); return !data->nodes_different && data->nodes_found == data->n_nodes; } void path_base (TestConformSimpleFixture *fixture, gconstpointer _data) { CallbackData data; gint i; memset (&data, 0, sizeof (data)); data.path = clutter_path_new (); for (i = 0; i < G_N_ELEMENTS (path_tests); i++) { gboolean succeeded; if (g_test_verbose ()) g_print ("%s... ", path_tests[i].desc); succeeded = path_tests[i].func (&data) && compare_nodes (&data); if (g_test_verbose ()) g_print ("%s\n", succeeded ? "ok" : "FAIL"); g_assert (succeeded); } g_object_unref (data.path); } �������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/animator.c�������������������������������������������������������0000664�0001750�0001750�00000014604�14211404421�021406� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> static void animator_multi_properties (void) { ClutterScript *script = clutter_script_new (); GObject *animator = NULL, *foo = NULL; GError *error = NULL; gchar *test_file; GList *keys; ClutterAnimatorKey *key; GValue value = { 0, }; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-animator-3.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); foo = clutter_script_get_object (script, "foo"); g_assert (G_IS_OBJECT (foo)); animator = clutter_script_get_object (script, "animator"); g_assert (CLUTTER_IS_ANIMATOR (animator)); /* get all the keys for foo:x */ keys = clutter_animator_get_keys (CLUTTER_ANIMATOR (animator), foo, "x", -1.0); g_assert_cmpint (g_list_length (keys), ==, 3); key = g_list_nth_data (keys, 1); g_assert (key != NULL); if (g_test_verbose ()) { g_print ("(foo, x).keys[1] = \n" ".object = %s\n" ".progress = %.2f\n" ".name = '%s'\n" ".type = '%s'\n", clutter_get_script_id (clutter_animator_key_get_object (key)), clutter_animator_key_get_progress (key), clutter_animator_key_get_property_name (key), g_type_name (clutter_animator_key_get_property_type (key))); } g_assert (clutter_animator_key_get_object (key) != NULL); g_assert_cmpfloat (clutter_animator_key_get_progress (key), ==, 0.2); g_assert_cmpstr (clutter_animator_key_get_property_name (key), ==, "x"); g_assert (clutter_animator_key_get_property_type (key) == G_TYPE_FLOAT); g_value_init (&value, G_TYPE_FLOAT); g_assert (clutter_animator_key_get_value (key, &value)); g_assert_cmpfloat (g_value_get_float (&value), ==, 150.0); g_value_unset (&value); g_list_free (keys); /* get all the keys for foo:y */ keys = clutter_animator_get_keys (CLUTTER_ANIMATOR (animator), foo, "y", -1.0); g_assert_cmpint (g_list_length (keys), ==, 3); key = g_list_nth_data (keys, 2); g_assert (key != NULL); if (g_test_verbose ()) { g_print ("(foo, y).keys[2] = \n" ".object = %s\n" ".progress = %.2f\n" ".name = '%s'\n" ".type = '%s'\n", clutter_get_script_id (clutter_animator_key_get_object (key)), clutter_animator_key_get_progress (key), clutter_animator_key_get_property_name (key), g_type_name (clutter_animator_key_get_property_type (key))); } g_assert (clutter_animator_key_get_object (key) != NULL); g_assert_cmpfloat (clutter_animator_key_get_progress (key), ==, 0.8); g_assert_cmpstr (clutter_animator_key_get_property_name (key), ==, "y"); g_assert (clutter_animator_key_get_property_type (key) == G_TYPE_FLOAT); g_value_init (&value, G_TYPE_FLOAT); g_assert (clutter_animator_key_get_value (key, &value)); g_assert_cmpfloat (g_value_get_float (&value), ==, 200.0); g_value_unset (&value); g_list_free (keys); g_object_unref (script); free (test_file); } static void animator_properties (void) { ClutterScript *script = clutter_script_new (); GObject *animator = NULL; GError *error = NULL; gchar *test_file; GList *keys; ClutterAnimatorKey *key; GValue value = { 0, }; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-animator-2.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); animator = clutter_script_get_object (script, "animator"); g_assert (CLUTTER_IS_ANIMATOR (animator)); /* get all the keys */ keys = clutter_animator_get_keys (CLUTTER_ANIMATOR (animator), NULL, NULL, -1.0); g_assert_cmpint (g_list_length (keys), ==, 3); key = g_list_nth_data (keys, 1); g_assert (key != NULL); if (g_test_verbose ()) { g_print ("keys[1] = \n" ".object = %s\n" ".progress = %.2f\n" ".name = '%s'\n" ".type = '%s'\n", clutter_get_script_id (clutter_animator_key_get_object (key)), clutter_animator_key_get_progress (key), clutter_animator_key_get_property_name (key), g_type_name (clutter_animator_key_get_property_type (key))); } g_assert (clutter_animator_key_get_object (key) != NULL); g_assert_cmpfloat (clutter_animator_key_get_progress (key), ==, 0.2); g_assert_cmpstr (clutter_animator_key_get_property_name (key), ==, "x"); g_assert (clutter_animator_key_get_property_type (key) == G_TYPE_FLOAT); g_value_init (&value, G_TYPE_FLOAT); g_assert (clutter_animator_key_get_value (key, &value)); g_assert_cmpfloat (g_value_get_float (&value), ==, 150.0); g_value_unset (&value); g_list_free (keys); g_object_unref (script); free (test_file); } static void animator_base (void) { ClutterScript *script = clutter_script_new (); GObject *animator = NULL; GError *error = NULL; guint duration = 0; gchar *test_file; test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-animator-1.json", NULL); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s", error->message); g_assert_no_error (error); animator = clutter_script_get_object (script, "animator"); g_assert (CLUTTER_IS_ANIMATOR (animator)); duration = clutter_animator_get_duration (CLUTTER_ANIMATOR (animator)); g_assert_cmpint (duration, ==, 1000); g_object_unref (script); free (test_file); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/script/animator/base", animator_base) CLUTTER_TEST_UNIT ("/script/animator/properties", animator_properties) CLUTTER_TEST_UNIT ("/script/animator/multi-properties", animator_multi_properties) ) ����������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/binding-pool.c���������������������������������������������������0000664�0001750�0001750�00000021605�14211404421�022154� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string.h> #include <clutter/clutter.h> #define TYPE_KEY_GROUP (key_group_get_type ()) #define KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_KEY_GROUP, KeyGroup)) #define IS_KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_KEY_GROUP)) #define KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_KEY_GROUP, KeyGroupClass)) #define IS_KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_KEY_GROUP)) typedef struct _KeyGroup KeyGroup; typedef struct _KeyGroupClass KeyGroupClass; struct _KeyGroup { ClutterActor parent_instance; gint selected_index; }; struct _KeyGroupClass { ClutterActorClass parent_class; void (* activate) (KeyGroup *group, ClutterActor *child); }; GType key_group_get_type (void); G_DEFINE_TYPE (KeyGroup, key_group, CLUTTER_TYPE_ACTOR) enum { ACTIVATE, LAST_SIGNAL }; static guint group_signals[LAST_SIGNAL] = { 0, }; static gboolean key_group_action_move_left (KeyGroup *self, const gchar *action_name, guint key_val, ClutterModifierType modifiers) { gint n_children; g_assert_cmpstr (action_name, ==, "move-left"); g_assert_cmpint (key_val, ==, CLUTTER_KEY_Left); n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self)); self->selected_index -= 1; if (self->selected_index < 0) self->selected_index = n_children - 1; return TRUE; } static gboolean key_group_action_move_right (KeyGroup *self, const gchar *action_name, guint key_val, ClutterModifierType modifiers) { gint n_children; g_assert_cmpstr (action_name, ==, "move-right"); g_assert_cmpint (key_val, ==, CLUTTER_KEY_Right); n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self)); self->selected_index += 1; if (self->selected_index >= n_children) self->selected_index = 0; return TRUE; } static gboolean key_group_action_activate (KeyGroup *self, const gchar *action_name, guint key_val, ClutterModifierType modifiers) { ClutterActor *child = NULL; g_assert_cmpstr (action_name, ==, "activate"); g_assert (key_val == CLUTTER_KEY_Return || key_val == CLUTTER_KEY_KP_Enter || key_val == CLUTTER_KEY_ISO_Enter); if (self->selected_index == -1) return FALSE; child = clutter_actor_get_child_at_index (CLUTTER_ACTOR (self), self->selected_index); if (child != NULL) { g_signal_emit (self, group_signals[ACTIVATE], 0, child); return TRUE; } else return FALSE; } static gboolean key_group_key_press (ClutterActor *actor, ClutterKeyEvent *event) { ClutterBindingPool *pool; gboolean res; pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor)); g_assert (pool != NULL); res = clutter_binding_pool_activate (pool, event->keyval, event->modifier_state, G_OBJECT (actor)); /* if we activate a key binding, redraw the actor */ if (res) clutter_actor_queue_redraw (actor); return res; } static void key_group_paint (ClutterActor *actor) { KeyGroup *self = KEY_GROUP (actor); ClutterActorIter iter; ClutterActor *child; gint i = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { /* paint the selection rectangle */ if (i == self->selected_index) { ClutterActorBox box = { 0, }; clutter_actor_get_allocation_box (child, &box); box.x1 -= 2; box.y1 -= 2; box.x2 += 2; box.y2 += 2; cogl_set_source_color4ub (255, 255, 0, 224); cogl_rectangle (box.x1, box.y1, box.x2, box.y2); } clutter_actor_paint (child); } } static void key_group_class_init (KeyGroupClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); ClutterBindingPool *binding_pool; actor_class->paint = key_group_paint; actor_class->key_press_event = key_group_key_press; group_signals[ACTIVATE] = g_signal_new (g_intern_static_string ("activate"), G_OBJECT_CLASS_TYPE (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (KeyGroupClass, activate), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); binding_pool = clutter_binding_pool_get_for_class (klass); clutter_binding_pool_install_action (binding_pool, "move-right", CLUTTER_KEY_Right, 0, G_CALLBACK (key_group_action_move_right), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "move-left", CLUTTER_KEY_Left, 0, G_CALLBACK (key_group_action_move_left), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_Return, 0, G_CALLBACK (key_group_action_activate), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_KP_Enter, 0, G_CALLBACK (key_group_action_activate), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_ISO_Enter, 0, G_CALLBACK (key_group_action_activate), NULL, NULL); } static void key_group_init (KeyGroup *self) { self->selected_index = -1; } static void init_event (ClutterKeyEvent *event) { event->type = CLUTTER_KEY_PRESS; event->time = 0; /* not needed */ event->flags = CLUTTER_EVENT_FLAG_SYNTHETIC; event->stage = NULL; /* not needed */ event->source = NULL; /* not needed */ event->modifier_state = 0; event->hardware_keycode = 0; /* not needed */ } static void send_keyval (KeyGroup *group, int keyval) { ClutterKeyEvent event; init_event (&event); event.keyval = keyval; event.unicode_value = 0; /* should be ignored for cursor keys etc. */ clutter_actor_event (CLUTTER_ACTOR (group), (ClutterEvent *) &event, FALSE); } static void on_activate (KeyGroup *key_group, ClutterActor *child, gpointer data) { gint _index = GPOINTER_TO_INT (data); g_assert_cmpint (key_group->selected_index, ==, _index); } static void binding_pool (void) { KeyGroup *key_group = g_object_new (TYPE_KEY_GROUP, NULL); g_object_ref_sink (key_group); clutter_actor_add_child (CLUTTER_ACTOR (key_group), g_object_new (CLUTTER_TYPE_ACTOR, "width", 50.0, "height", 50.0, "x", 0.0, "y", 0.0, NULL)); clutter_actor_add_child (CLUTTER_ACTOR (key_group), g_object_new (CLUTTER_TYPE_ACTOR, "width", 50.0, "height", 50.0, "x", 75.0, "y", 0.0, NULL)); clutter_actor_add_child (CLUTTER_ACTOR (key_group), g_object_new (CLUTTER_TYPE_ACTOR, "width", 50.0, "height", 50.0, "x", 150.0, "y", 0.0, NULL)); g_assert_cmpint (key_group->selected_index, ==, -1); send_keyval (key_group, CLUTTER_KEY_Left); g_assert_cmpint (key_group->selected_index, ==, 2); send_keyval (key_group, CLUTTER_KEY_Left); g_assert_cmpint (key_group->selected_index, ==, 1); send_keyval (key_group, CLUTTER_KEY_Right); g_assert_cmpint (key_group->selected_index, ==, 2); send_keyval (key_group, CLUTTER_KEY_Right); g_assert_cmpint (key_group->selected_index, ==, 0); g_signal_connect (key_group, "activate", G_CALLBACK (on_activate), GINT_TO_POINTER (0)); send_keyval (key_group, CLUTTER_KEY_Return); clutter_actor_destroy (CLUTTER_ACTOR (key_group)); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/binding-pool", binding_pool) ) ���������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-meta.c�����������������������������������������������������0000664�0001750�0001750�00000002125�14211404421�021623� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #include <clutter/clutter.h> static void actor_meta_clear (void) { ClutterActor *actor, *stage; stage = clutter_test_get_stage (); actor = clutter_actor_new (); g_object_ref_sink (actor); g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); clutter_actor_add_action (actor, clutter_click_action_new ()); clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_ALL, 0)); clutter_actor_add_effect (actor, clutter_blur_effect_new ()); g_assert (clutter_actor_has_actions (actor)); g_assert (clutter_actor_has_constraints (actor)); g_assert (clutter_actor_has_effects (actor)); clutter_actor_clear_actions (actor); g_assert (!clutter_actor_has_actions (actor)); clutter_actor_clear_constraints (actor); g_assert (!clutter_actor_has_constraints (actor)); clutter_actor_clear_effects (actor); g_assert (!clutter_actor_has_effects (actor)); clutter_actor_destroy (actor); g_assert (actor == NULL); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/meta/clear", actor_meta_clear) ) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-pick.c�����������������������������������������������������0000664�0001750�0001750�00000021635�14211404421�021632� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> #define STAGE_WIDTH 640 #define STAGE_HEIGHT 480 #define ACTORS_X 12 #define ACTORS_Y 16 #define SHIFT_STEP STAGE_WIDTH / ACTORS_X typedef struct _State State; struct _State { ClutterActor *stage; int y, x; ClutterActor *actors[ACTORS_X * ACTORS_Y]; guint actor_width, actor_height; guint failed_pass; guint failed_idx; gboolean pass; }; struct _ShiftEffect { ClutterShaderEffect parent_instance; }; struct _ShiftEffectClass { ClutterShaderEffectClass parent_class; }; typedef struct _ShiftEffect ShiftEffect; typedef struct _ShiftEffectClass ShiftEffectClass; #define TYPE_SHIFT_EFFECT (shift_effect_get_type ()) GType shift_effect_get_type (void); G_DEFINE_TYPE (ShiftEffect, shift_effect, CLUTTER_TYPE_SHADER_EFFECT); static void shader_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags) { ClutterShaderEffect *shader = CLUTTER_SHADER_EFFECT (effect); float tex_width; ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); if (g_test_verbose ()) g_debug ("shader_paint"); clutter_shader_effect_set_shader_source (shader, "uniform sampler2D tex;\n" "uniform float step;\n" "void main (void)\n" "{\n" " cogl_color_out = texture2D(tex, vec2 (cogl_tex_coord_in[0].s + step,\n" " cogl_tex_coord_in[0].t));\n" "}\n"); tex_width = clutter_actor_get_width (actor); clutter_shader_effect_set_uniform (shader, "tex", G_TYPE_INT, 1, 0); clutter_shader_effect_set_uniform (shader, "step", G_TYPE_FLOAT, 1, SHIFT_STEP / tex_width); CLUTTER_EFFECT_CLASS (shift_effect_parent_class)->paint (effect, flags); } static void shader_pick (ClutterEffect *effect, ClutterEffectPaintFlags flags) { shader_paint (effect, flags); } static void shift_effect_class_init (ShiftEffectClass *klass) { ClutterEffectClass *shader_class = CLUTTER_EFFECT_CLASS (klass); shader_class->paint = shader_paint; shader_class->pick = shader_pick; } static void shift_effect_init (ShiftEffect *self) { } static const char *test_passes[] = { "No covering actor", "Invisible covering actor", "Clipped covering actor", "Blur effect", "Shift effect", }; static gboolean on_timeout (gpointer data) { State *state = data; int test_num = 0; int y, x; ClutterActor *over_actor = NULL; /* This will cause an unclipped pick redraw that will get buffered. We'll check below that this buffer is discarded because we also need to pick non-reactive actors */ clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage), CLUTTER_PICK_REACTIVE, 10, 10); clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage), CLUTTER_PICK_REACTIVE, 10, 10); for (test_num = 0; test_num < G_N_ELEMENTS (test_passes); test_num++) { if (test_num == 0) { if (g_test_verbose ()) g_print ("No covering actor:\n"); } if (test_num == 1) { static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff }; /* Create an actor that covers the whole stage but that isn't visible so it shouldn't affect the picking */ over_actor = clutter_rectangle_new_with_color (&red); clutter_actor_set_size (over_actor, STAGE_WIDTH, STAGE_HEIGHT); clutter_actor_add_child (state->stage, over_actor); clutter_actor_hide (over_actor); if (g_test_verbose ()) g_print ("Invisible covering actor:\n"); } else if (test_num == 2) { /* Make the actor visible but set a clip so that only some of the actors are accessible */ clutter_actor_show (over_actor); clutter_actor_set_clip (over_actor, state->actor_width * 2, state->actor_height * 2, state->actor_width * (ACTORS_X - 4), state->actor_height * (ACTORS_Y - 4)); if (g_test_verbose ()) g_print ("Clipped covering actor:\n"); } else if (test_num == 3) { if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) continue; clutter_actor_hide (over_actor); clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage), "blur", clutter_blur_effect_new ()); if (g_test_verbose ()) g_print ("With blur effect:\n"); } else if (test_num == 4) { if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) continue; clutter_actor_hide (over_actor); clutter_actor_remove_effect_by_name (CLUTTER_ACTOR (state->stage), "blur"); clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage), "shift", g_object_new (TYPE_SHIFT_EFFECT, NULL)); if (g_test_verbose ()) g_print ("With shift effect:\n"); } for (y = 0; y < ACTORS_Y; y++) { if (test_num == 4) x = 1; else x = 0; for (; x < ACTORS_X; x++) { gboolean pass = FALSE; gfloat pick_x; ClutterActor *actor; pick_x = x * state->actor_width + state->actor_width / 2; if (test_num == 4) pick_x -= SHIFT_STEP; actor = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage), CLUTTER_PICK_ALL, pick_x, y * state->actor_height + state->actor_height / 2); if (g_test_verbose ()) g_print ("% 3i,% 3i / %p -> ", x, y, state->actors[y * ACTORS_X + x]); if (actor == NULL) { if (g_test_verbose ()) g_print ("NULL: FAIL\n"); } else if (actor == over_actor) { if (test_num == 2 && x >= 2 && x < ACTORS_X - 2 && y >= 2 && y < ACTORS_Y - 2) pass = TRUE; if (g_test_verbose ()) g_print ("over_actor: %s\n", pass ? "pass" : "FAIL"); } else { if (actor == state->actors[y * ACTORS_X + x] && (test_num != 2 || x < 2 || x >= ACTORS_X - 2 || y < 2 || y >= ACTORS_Y - 2)) pass = TRUE; if (g_test_verbose ()) g_print ("%p: %s\n", actor, pass ? "pass" : "FAIL"); } if (!pass) { state->failed_pass = test_num; state->failed_idx = y * ACTORS_X + x; state->pass = FALSE; } } } } clutter_main_quit (); return G_SOURCE_REMOVE; } static void actor_pick (void) { int y, x; State state; state.pass = TRUE; state.stage = clutter_test_get_stage (); state.actor_width = STAGE_WIDTH / ACTORS_X; state.actor_height = STAGE_HEIGHT / ACTORS_Y; for (y = 0; y < ACTORS_Y; y++) for (x = 0; x < ACTORS_X; x++) { ClutterColor color = { x * 255 / (ACTORS_X - 1), y * 255 / (ACTORS_Y - 1), 128, 255 }; ClutterActor *rect = clutter_rectangle_new_with_color (&color); clutter_actor_set_position (rect, x * state.actor_width, y * state.actor_height); clutter_actor_set_size (rect, state.actor_width, state.actor_height); clutter_actor_add_child (state.stage, rect); state.actors[y * ACTORS_X + x] = rect; } clutter_actor_show (state.stage); clutter_threads_add_idle (on_timeout, &state); clutter_main (); if (g_test_verbose ()) { if (!state.pass) g_test_message ("Failed pass: %s[%d], actor index: %d [%p]\n", test_passes[state.failed_pass], state.failed_pass, state.failed_idx, state.actors[state.failed_idx]); } g_assert (state.pass); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/pick", actor_pick) ) ���������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/group.c����������������������������������������������������������0000664�0001750�0001750�00000003525�14211404421�020730� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> static void group_depth_sorting (void) { ClutterActor *group; ClutterActor *child, *test; ClutterGroup *g; GList *children; group = clutter_group_new (); g = CLUTTER_GROUP (group); child = clutter_rectangle_new (); clutter_actor_set_size (child, 20, 20); clutter_actor_set_depth (child, 0); clutter_actor_set_name (child, "zero"); clutter_container_add_actor (CLUTTER_CONTAINER (group), child); children = clutter_container_get_children (CLUTTER_CONTAINER (group)); g_assert (children->data == child); g_assert (children->next == NULL); g_list_free (children); child = clutter_rectangle_new (); clutter_actor_set_size (child, 20, 20); clutter_actor_set_depth (child, 10); clutter_actor_set_name (child, "plus-ten"); clutter_container_add_actor (CLUTTER_CONTAINER (group), child); test = clutter_group_get_nth_child (g, 0); g_assert_cmpstr (clutter_actor_get_name (test), ==, "zero"); test = clutter_group_get_nth_child (g, 1); g_assert_cmpstr (clutter_actor_get_name (test), ==, "plus-ten"); child = clutter_rectangle_new (); clutter_actor_set_size (child, 20, 20); clutter_actor_set_depth (child, -10); clutter_actor_set_name (child, "minus-ten"); clutter_container_add_actor (CLUTTER_CONTAINER (group), child); g_assert_cmpint (clutter_group_get_n_children (g), ==, 3); test = clutter_group_get_nth_child (g, 0); g_assert_cmpstr (clutter_actor_get_name (test), ==, "minus-ten"); test = clutter_group_get_nth_child (g, 1); g_assert_cmpstr (clutter_actor_get_name (test), ==, "zero"); test = clutter_group_get_nth_child (g, 2); g_assert_cmpstr (clutter_actor_get_name (test), ==, "plus-ten"); clutter_actor_destroy (group); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/group/depth-sorting", group_depth_sorting) ) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/timeline.c�������������������������������������������������������0000664�0001750�0001750�00000026111�14211404421�021376� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <string.h> #include <clutter/clutter.h> #include "test-conform-common.h" /* This test runs three timelines at 30 fps with 10 frames. Some of the timelines have markers. Once the timelines are run it then checks that all of the frames were hit, all of the markers were hit and that the completed signal was fired. The timelines are then run again but this time with a timeout source that introduces a delay. This should cause some frames to be skipped. The test is run again but only the markers and the completed signal is checked for. */ #define FRAME_COUNT 10 #define FPS 30 typedef struct _TimelineData TimelineData; struct _TimelineData { int timeline_num; guint frame_hit_count[FRAME_COUNT + 1]; GSList *markers_hit; guint completed_count; }; static void timeline_data_init (TimelineData *data, int timeline_num) { memset (data, 0, sizeof (TimelineData)); data->timeline_num = timeline_num; } static void timeline_data_destroy (TimelineData *data) { g_slist_foreach (data->markers_hit, (GFunc) free, NULL); g_slist_free (data->markers_hit); } static void timeline_complete_cb (ClutterTimeline *timeline, TimelineData *data) { if (g_test_verbose ()) g_print ("%i: Completed\n", data->timeline_num); data->completed_count++; } static void timeline_new_frame_cb (ClutterTimeline *timeline, gint msec, TimelineData *data) { /* Calculate an approximate frame number from the duration with rounding */ int frame_no = ((msec * FRAME_COUNT + (FRAME_COUNT * 1000 / FPS) / 2) / (FRAME_COUNT * 1000 / FPS)); if (g_test_verbose ()) g_print ("%i: Doing frame %d, delta = %i\n", data->timeline_num, frame_no, clutter_timeline_get_delta (timeline)); g_assert (frame_no >= 0 && frame_no <= FRAME_COUNT); data->frame_hit_count[frame_no]++; } static void timeline_marker_reached_cb (ClutterTimeline *timeline, const gchar *marker_name, guint frame_num, TimelineData *data) { if (g_test_verbose ()) g_print ("%i: Marker '%s' (%d) reached, delta = %i\n", data->timeline_num, marker_name, frame_num, clutter_timeline_get_delta (timeline)); data->markers_hit = g_slist_prepend (data->markers_hit, g_strdup (marker_name)); } static gboolean check_timeline (ClutterTimeline *timeline, TimelineData *data, gboolean check_missed_frames) { gchar **markers; gsize n_markers; guint *marker_reached_count; gboolean succeeded = TRUE; GSList *node; int i; int missed_frame_count = 0; int frame_offset; if (clutter_timeline_get_direction (timeline) == CLUTTER_TIMELINE_BACKWARD) frame_offset = 0; else frame_offset = 1; markers = clutter_timeline_list_markers (timeline, -1, &n_markers); marker_reached_count = g_new0 (guint, n_markers); for (node = data->markers_hit; node; node = node->next) { for (i = 0; i < n_markers; i++) if (!strcmp (node->data, markers[i])) break; if (i < n_markers) marker_reached_count[i]++; else { if (g_test_verbose ()) g_print ("FAIL: unknown marker '%s' hit for timeline %i\n", (char *) node->data, data->timeline_num); succeeded = FALSE; } } for (i = 0; i < n_markers; i++) if (marker_reached_count[i] != 1) { if (g_test_verbose ()) g_print ("FAIL: marker '%s' hit %i times for timeline %i\n", markers[i], marker_reached_count[i], data->timeline_num); succeeded = FALSE; } if (check_missed_frames) { for (i = 0; i < FRAME_COUNT; i++) if (data->frame_hit_count[i + frame_offset] < 1) missed_frame_count++; if (missed_frame_count) { if (g_test_verbose ()) g_print ("FAIL: missed %i frame%s for timeline %i\n", missed_frame_count, missed_frame_count == 1 ? "" : "s", data->timeline_num); succeeded = FALSE; } } if (data->completed_count != 1) { if (g_test_verbose ()) g_print ("FAIL: timeline %i completed %i times\n", data->timeline_num, data->completed_count); succeeded = FALSE; } g_strfreev (markers); free (marker_reached_count); return succeeded; } static gboolean timeout_cb (gpointer data G_GNUC_UNUSED) { clutter_main_quit (); return FALSE; } static gboolean delay_cb (gpointer data) { /* Waste a bit of time so that it will skip frames */ g_usleep (G_USEC_PER_SEC * 66 / 1000); return TRUE; } void timeline_base (TestConformSimpleFixture *fixture, gconstpointer data) { ClutterTimeline *timeline_1; TimelineData data_1; ClutterTimeline *timeline_2; TimelineData data_2; ClutterTimeline *timeline_3; TimelineData data_3; gchar **markers; gsize n_markers; guint delay_tag; /* NB: We have to ensure a stage is instantiated else the master * clock wont run... */ ClutterActor *stage = clutter_stage_new (); timeline_data_init (&data_1, 1); timeline_1 = clutter_timeline_new (FRAME_COUNT * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_1, "start-marker", 0 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_1, "foo", 5 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_1, "bar", 5 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_1, "baz", 5 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_1, "near-end-marker", 9 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_1, "end-marker", 10 * 1000 / FPS); markers = clutter_timeline_list_markers (timeline_1, 5 * 1000 / FPS, &n_markers); g_assert (markers != NULL); g_assert (n_markers == 3); g_strfreev (markers); timeline_data_init (&data_2, 2); timeline_2 = clutter_timeline_clone (timeline_1); clutter_timeline_add_marker_at_time (timeline_2, "bar", 2 * 1000 / FPS); markers = clutter_timeline_list_markers (timeline_2, -1, &n_markers); g_assert (markers != NULL); g_assert (n_markers == 1); g_assert (strcmp (markers[0], "bar") == 0); g_strfreev (markers); timeline_data_init (&data_3, 3); timeline_3 = clutter_timeline_clone (timeline_1); clutter_timeline_set_direction (timeline_3, CLUTTER_TIMELINE_BACKWARD); clutter_timeline_add_marker_at_time (timeline_3, "start-marker", FRAME_COUNT * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_3, "foo", 5 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_3, "baz", 8 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_3, "near-end-marker", 1 * 1000 / FPS); clutter_timeline_add_marker_at_time (timeline_3, "end-marker", 0 * 1000 / FPS); g_signal_connect (timeline_1, "marker-reached", G_CALLBACK (timeline_marker_reached_cb), &data_1); g_signal_connect (timeline_1, "new-frame", G_CALLBACK (timeline_new_frame_cb), &data_1); g_signal_connect (timeline_1, "completed", G_CALLBACK (timeline_complete_cb), &data_1); g_signal_connect (timeline_2, "marker-reached::bar", G_CALLBACK (timeline_marker_reached_cb), &data_2); g_signal_connect (timeline_2, "new-frame", G_CALLBACK (timeline_new_frame_cb), &data_2); g_signal_connect (timeline_2, "completed", G_CALLBACK (timeline_complete_cb), &data_2); g_signal_connect (timeline_3, "marker-reached", G_CALLBACK (timeline_marker_reached_cb), &data_3); g_signal_connect (timeline_3, "new-frame", G_CALLBACK (timeline_new_frame_cb), &data_3); g_signal_connect (timeline_3, "completed", G_CALLBACK (timeline_complete_cb), &data_3); if (g_test_verbose ()) g_print ("Without delay...\n"); clutter_timeline_start (timeline_1); clutter_timeline_start (timeline_2); clutter_timeline_start (timeline_3); clutter_threads_add_timeout (2000, timeout_cb, NULL); clutter_main (); g_assert (check_timeline (timeline_1, &data_1, TRUE)); g_assert (check_timeline (timeline_2, &data_2, TRUE)); g_assert (check_timeline (timeline_3, &data_3, TRUE)); if (g_test_verbose ()) g_print ("With delay...\n"); timeline_data_destroy (&data_1); timeline_data_init (&data_1, 1); timeline_data_destroy (&data_2); timeline_data_init (&data_2, 2); timeline_data_destroy (&data_3); timeline_data_init (&data_3, 3); clutter_timeline_start (timeline_1); clutter_timeline_start (timeline_2); clutter_timeline_start (timeline_3); clutter_threads_add_timeout (2000, timeout_cb, NULL); delay_tag = clutter_threads_add_timeout (99, delay_cb, NULL); clutter_main (); g_assert (check_timeline (timeline_1, &data_1, FALSE)); g_assert (check_timeline (timeline_2, &data_2, FALSE)); g_assert (check_timeline (timeline_3, &data_3, FALSE)); g_object_unref (timeline_1); g_object_unref (timeline_2); g_object_unref (timeline_3); timeline_data_destroy (&data_1); timeline_data_destroy (&data_2); timeline_data_destroy (&data_3); g_source_remove (delay_tag); clutter_actor_destroy (stage); } void timeline_markers_from_script (TestConformSimpleFixture *fixture, gconstpointer data) { ClutterScript *script = clutter_script_new (); ClutterTimeline *timeline; GError *error = NULL; gchar *test_file; gchar **markers; gsize n_markers; test_file = clutter_test_get_data_file ("test-script-timeline-markers.json"); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error != NULL) g_print ("Error: %s", error->message); g_assert_no_error (error); timeline = CLUTTER_TIMELINE (clutter_script_get_object (script, "timeline0")); g_assert (clutter_timeline_has_marker (timeline, "marker0")); g_assert (clutter_timeline_has_marker (timeline, "marker1")); g_assert (!clutter_timeline_has_marker (timeline, "foo")); g_assert (clutter_timeline_has_marker (timeline, "marker2")); g_assert (clutter_timeline_has_marker (timeline, "marker3")); markers = clutter_timeline_list_markers (timeline, -1, &n_markers); g_assert_cmpint (n_markers, ==, 4); g_strfreev (markers); markers = clutter_timeline_list_markers (timeline, 500, &n_markers); g_assert_cmpint (n_markers, ==, 2); g_assert (markers != NULL); g_assert_cmpstr (markers[0], ==, "marker3"); g_assert_cmpstr (markers[1], ==, "marker1"); g_strfreev (markers); g_object_unref (script); free (test_file); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/state.c����������������������������������������������������������0000664�0001750�0001750�00000005413�14211404421�020712� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include "test-conform-common.h" void state_base (TestConformSimpleFixture *fixture G_GNUC_UNUSED, gconstpointer dummy G_GNUC_UNUSED) { ClutterScript *script = clutter_script_new (); GObject *state = NULL; GError *error = NULL; gchar *test_file; GList *states, *keys; ClutterStateKey *state_key; guint duration; test_file = clutter_test_get_data_file ("test-state-1.json"); clutter_script_load_from_file (script, test_file, &error); if (g_test_verbose () && error) g_print ("Error: %s\n", error->message); free (test_file); #if GLIB_CHECK_VERSION (2, 20, 0) g_assert_no_error (error); #else g_assert (error == NULL); #endif state = clutter_script_get_object (script, "state"); g_assert (CLUTTER_IS_STATE (state)); states = clutter_state_get_states (CLUTTER_STATE (state)); g_assert (states != NULL); g_assert (g_list_find (states, g_intern_static_string ("clicked"))); g_list_free (states); duration = clutter_state_get_duration (CLUTTER_STATE (state), "base", "clicked"); g_assert_cmpint (duration, ==, 250); duration = clutter_state_get_duration (CLUTTER_STATE (state), "clicked", "base"); g_assert_cmpint (duration, ==, 150); keys = clutter_state_get_keys (CLUTTER_STATE (state), "base", "clicked", clutter_script_get_object (script, "rect"), "opacity"); g_assert (keys != NULL); g_assert_cmpint (g_list_length (keys), ==, 1); state_key = keys->data; g_assert (clutter_state_key_get_object (state_key) == clutter_script_get_object (script, "rect")); g_assert (clutter_state_key_get_mode (state_key) == CLUTTER_LINEAR); g_assert_cmpstr (clutter_state_key_get_property_name (state_key), ==, "opacity"); g_list_free (keys); keys = clutter_state_get_keys (CLUTTER_STATE (state), NULL, NULL, NULL, NULL); g_assert_cmpint (g_list_length (keys), ==, 2); g_list_free (keys); clutter_state_set (CLUTTER_STATE (state), "base", "clicked", state, "state", CLUTTER_LINEAR, "foo", NULL); keys = clutter_state_get_keys (CLUTTER_STATE (state), "base", "clicked", NULL, NULL); g_assert (keys != NULL); g_assert_cmpint (g_list_length (keys), ==, 2); g_list_free (keys); states = clutter_state_get_states (CLUTTER_STATE (state)); g_assert_cmpint (g_list_length (states), ==, 2); g_list_free (states); clutter_state_remove_key (CLUTTER_STATE (state), NULL, "clicked", NULL, NULL); states = clutter_state_get_states (CLUTTER_STATE (state)); /* removing the "clicked" state, will also cause the "base" state to be removed * since in the .json there is no default source state */ g_assert_cmpint (g_list_length (states), ==, 0); g_list_free (states); g_object_unref (script); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/actor-offscreen-limit-max-size.c���������������������������������0000664�0001750�0001750�00000007334�14211404421�025525� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_ENABLE_EXPERIMENTAL_API #include <clutter/clutter.h> #define STAGE_WIDTH (300) #define STAGE_HEIGHT (300) typedef struct { ClutterActor *stage; ClutterActor *actor_group1; ClutterEffect *blur_effect1; ClutterActor *actor_group2; ClutterEffect *blur_effect2; } Data; static void check_results (ClutterStage *stage, gpointer user_data) { Data *data = user_data; gfloat width, height; ClutterRect rect; clutter_offscreen_effect_get_target_rect (CLUTTER_OFFSCREEN_EFFECT (data->blur_effect1), &rect); width = clutter_rect_get_width (&rect); height = clutter_rect_get_height (&rect); if (g_test_verbose ()) g_print ("Checking effect1 size: %.2f x %.2f\n", clutter_rect_get_width (&rect), clutter_rect_get_height (&rect)); g_assert_cmpint (width, <, STAGE_WIDTH); g_assert_cmpint (height, <, STAGE_HEIGHT); clutter_offscreen_effect_get_target_rect (CLUTTER_OFFSCREEN_EFFECT (data->blur_effect2), &rect); width = clutter_rect_get_width (&rect); height = clutter_rect_get_height (&rect); if (g_test_verbose ()) g_print ("Checking effect2 size: %.2f x %.2f\n", width, height); g_assert_cmpint (width, ==, STAGE_WIDTH); g_assert_cmpint (height, ==, STAGE_HEIGHT); clutter_main_quit (); } static ClutterActor * create_actor (gfloat x, gfloat y, gfloat width, gfloat height, const ClutterColor *color) { return g_object_new (CLUTTER_TYPE_ACTOR, "x", x, "y", y, "width", width, "height", height, "background-color", color, NULL); } static void actor_offscreen_limit_max_size (void) { Data data; if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) return; data.stage = clutter_test_get_stage (); g_signal_connect (data.stage, "after-paint", G_CALLBACK (check_results), &data); clutter_actor_set_size (data.stage, STAGE_WIDTH, STAGE_HEIGHT); data.actor_group1 = clutter_actor_new (); clutter_actor_add_child (data.stage, data.actor_group1); data.blur_effect1 = clutter_blur_effect_new (); clutter_actor_add_effect (data.actor_group1, data.blur_effect1); clutter_actor_add_child (data.actor_group1, create_actor (10, 10, 100, 100, CLUTTER_COLOR_Blue)); clutter_actor_add_child (data.actor_group1, create_actor (100, 100, 100, 100, CLUTTER_COLOR_Gray)); data.actor_group2 = clutter_actor_new (); clutter_actor_add_child (data.stage, data.actor_group2); data.blur_effect2 = clutter_blur_effect_new (); clutter_actor_add_effect (data.actor_group2, data.blur_effect2); clutter_actor_add_child (data.actor_group2, create_actor (-10, -10, 100, 100, CLUTTER_COLOR_Yellow)); clutter_actor_add_child (data.actor_group2, create_actor (250, 10, 100, 100, CLUTTER_COLOR_ScarletRed)); clutter_actor_add_child (data.actor_group2, create_actor (10, 250, 100, 100, CLUTTER_COLOR_Yellow)); clutter_actor_show (data.stage); clutter_main (); } CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/actor/offscreen/limit-max-size", actor_offscreen_limit_max_size) ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/behaviours.c�����������������������������������������������������0000664�0001750�0001750�00000004221�14211404421�021735� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include <clutter/clutter.h> static void behaviour_opacity (void) { ClutterBehaviour *behaviour; ClutterTimeline *timeline; ClutterAlpha *alpha; guint8 start, end; guint starti; timeline = clutter_timeline_new (500); alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR); behaviour = clutter_behaviour_opacity_new (alpha, 0, 255); g_assert (CLUTTER_IS_BEHAVIOUR_OPACITY (behaviour)); g_object_add_weak_pointer (G_OBJECT (behaviour), (gpointer *) &behaviour); g_object_add_weak_pointer (G_OBJECT (timeline), (gpointer *) &timeline); clutter_behaviour_opacity_get_bounds (CLUTTER_BEHAVIOUR_OPACITY (behaviour), &start, &end); if (g_test_verbose ()) g_print ("BehaviourOpacity:bounds = %d, %d (expected: 0, 255)\n", start, end); g_assert_cmpint (start, ==, 0); g_assert_cmpint (end, ==, 255); clutter_behaviour_opacity_set_bounds (CLUTTER_BEHAVIOUR_OPACITY (behaviour), 255, 0); /* XXX: The gobject property is actually a unsigned int not unsigned char * property so we have to be careful not to corrupt the stack by passing * a guint8 pointer here... */ starti = 0; g_object_get (G_OBJECT (behaviour), "opacity-start", &starti, NULL); if (g_test_verbose ()) g_print ("BehaviourOpacity:start = %d (expected: 255)\n", start); g_assert_cmpint (starti, ==, 255); g_object_unref (behaviour); g_object_unref (timeline); g_assert_null (behaviour); g_assert_null (timeline); } static struct { const gchar *path; GTestFunc func; } behaviour_tests[] = { { "opacity", behaviour_opacity }, }; static const int n_behaviour_tests = G_N_ELEMENTS (behaviour_tests); int main (int argc, char *argv[]) { int i; clutter_test_init (&argc, &argv); for (i = 0; i < n_behaviour_tests; i++) { char *path = g_strconcat ("/behaviours/", behaviour_tests[i].path, NULL); clutter_test_add (path, behaviour_tests[i].func); free (path); } return clutter_test_run (); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/tests/conform/cairo-texture.c��������������������������������������������������0000664�0001750�0001750�00000012617�14211404421�022371� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <clutter/clutter.h> #include <cogl/cogl.h> #include "test-conform-common.h" #define BLOCK_SIZE 16 /* Number of pixels at the border of a block to skip when verifying */ #define TEST_INSET 1 static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; typedef enum { /* The first frame is drawn using clutter_cairo_texture_create. The second frame is an update of the first frame using clutter_cairo_texture_create_region. The states are stored like this because the cairo drawing is done on idle and the validation is done during paint and we need to synchronize the two */ TEST_BEFORE_DRAW_FIRST_FRAME, TEST_BEFORE_VALIDATE_FIRST_FRAME, TEST_BEFORE_DRAW_SECOND_FRAME, TEST_BEFORE_VALIDATE_SECOND_FRAME, TEST_DONE } TestProgress; typedef struct _TestState { ClutterActor *stage; ClutterActor *ct; guint frame; TestProgress progress; } TestState; static void validate_part (int block_x, int block_y, const ClutterColor *color) { guint8 data[BLOCK_SIZE * BLOCK_SIZE * 4]; int x, y; cogl_read_pixels (block_x * BLOCK_SIZE, block_y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, data); for (x = 0; x < BLOCK_SIZE - TEST_INSET * 2; x++) for (y = 0; y < BLOCK_SIZE - TEST_INSET * 2; y++) { const guint8 *p = data + ((x + TEST_INSET) * 4 + (y + TEST_INSET) * BLOCK_SIZE * 4); g_assert_cmpint (p[0], ==, color->red); g_assert_cmpint (p[1], ==, color->green); g_assert_cmpint (p[2], ==, color->blue); } } static void paint_cb (ClutterActor *actor, TestState *state) { static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff }; static const ClutterColor green = { 0x00, 0xff, 0x00, 0xff }; static const ClutterColor blue = { 0x00, 0x00, 0xff, 0xff }; if (state->frame++ < 2) return; switch (state->progress) { case TEST_BEFORE_DRAW_FIRST_FRAME: case TEST_BEFORE_DRAW_SECOND_FRAME: case TEST_DONE: /* Handled by the idle callback */ break; case TEST_BEFORE_VALIDATE_FIRST_FRAME: /* In the first frame there is a red rectangle next to a green rectangle */ validate_part (0, 0, &red); validate_part (1, 0, &green); state->progress = TEST_BEFORE_DRAW_SECOND_FRAME; break; case TEST_BEFORE_VALIDATE_SECOND_FRAME: /* The second frame is the same except the green rectangle is replaced with a blue one */ validate_part (0, 0, &red); validate_part (1, 0, &blue); state->progress = TEST_DONE; break; } } static gboolean idle_cb (gpointer data) { TestState *state = data; cairo_t *cr; if (state->frame < 2) clutter_actor_queue_redraw (CLUTTER_ACTOR (state->stage)); else switch (state->progress) { case TEST_BEFORE_DRAW_FIRST_FRAME: /* Draw two different colour rectangles */ cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (state->ct)); cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_save (cr); cairo_rectangle (cr, 0, 0, BLOCK_SIZE, BLOCK_SIZE); cairo_clip (cr); cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); cairo_paint (cr); cairo_restore (cr); cairo_rectangle (cr, BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE); cairo_clip (cr); cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); cairo_paint (cr); cairo_restore (cr); cairo_destroy (cr); state->progress = TEST_BEFORE_VALIDATE_FIRST_FRAME; break; case TEST_BEFORE_DRAW_SECOND_FRAME: /* Replace the second rectangle with a blue one */ cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (state->ct)); cairo_rectangle (cr, BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE); cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); cairo_fill (cr); cairo_destroy (cr); state->progress = TEST_BEFORE_VALIDATE_SECOND_FRAME; break; case TEST_BEFORE_VALIDATE_FIRST_FRAME: case TEST_BEFORE_VALIDATE_SECOND_FRAME: /* Handled by the paint callback */ break; case TEST_DONE: clutter_main_quit (); break; } return G_SOURCE_CONTINUE; } void texture_cairo (TestConformSimpleFixture *fixture, gconstpointer data) { TestState state; unsigned int idle_source; unsigned int paint_handler; state.frame = 0; state.stage = clutter_stage_new (); state.progress = TEST_BEFORE_DRAW_FIRST_FRAME; state.ct = clutter_cairo_texture_new (BLOCK_SIZE * 2, BLOCK_SIZE); clutter_container_add_actor (CLUTTER_CONTAINER (state.stage), state.ct); clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color); /* We force continuous redrawing of the stage, since we need to skip * the first few frames, and we wont be doing anything else that * will trigger redrawing. */ idle_source = clutter_threads_add_idle (idle_cb, &state); paint_handler = g_signal_connect_after (state.stage, "paint", G_CALLBACK (paint_cb), &state); clutter_actor_show (state.stage); clutter_main (); g_signal_handler_disconnect (state.stage, paint_handler); g_source_remove (idle_source); if (g_test_verbose ()) g_print ("OK\n"); clutter_actor_destroy (state.stage); } �����������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/.gitignore���������������������������������������������������������������������0000664�0001750�0001750�00000003116�14211404421�016607� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ABOUT-NLS INSTALL Makefile Makefile.in aclocal.m4 autom4te.cache compile *.pc .deps .libs *.o *.lo *.la *.gcov .dirstamp README stamp-enum-types stamp-marshal tags /ChangeLog* clutter-build-config.h clutter-build-config.h.in clutter-config.h clutter-enum-types.[ch] clutter-marshal.[ch] clutter-version.h gcov-report.txt clutter-json.h clutter-lcov.info clutter-lcov !/build/autotools/introspection.m4 !/build/autotools/as-linguas.m4 !/build/autotools/as-compiler-flag.m4 !/build/autotools/glibtests.m4 /build/autotools/*.m4 /build/test-driver *.gir *.typelib *.gcda *.gcno config.* configure depcomp /doc/cookbook/*.pdf /doc/cookbook/html /doc/cookbook/*.stamp /doc/cookbook/clutter-cookbook.xml /doc/cookbook/clutter-cookbook.html doc/reference/clutter-*.txt !/doc/reference/clutter-sections.txt doc/reference/html doc/reference/tmpl doc/reference/xml doc/reference/clutter.args doc/reference/clutter.hierarchy doc/reference/clutter.interfaces doc/reference/clutter.prerequisites doc/reference/clutter.signals doc/reference/clutter-docs.xml doc/reference/*.stamp doc/reference/*.bak doc/reference/*.log doc/reference/gtkdoc-check.* gtk-doc.make install-sh libtool ltmain.sh missing mkinstalldirs stamp-h1 TAGS /tests/tools/disable-npots.sh /tests/conform/test-launcher.sh /tests/interactive/wrapper.sh /po/POTFILES /po/clutter-1.0.pot /po/*.gmo /po/Makefile.in.in /po/Makevars.template /po/Rules-quot /po/boldquot.sed /po/en@boldquot.header /po/en@quot.header /po/insert-header.sin /po/quot.sed /po/remove-potcdate.sin /po/remove-potcdate.sed /po/stamp-po *.swn *.swo *.swp *~ *.orig *.rej .DS_Store .testlogs-* ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/�����������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�016300� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-constraint.c���������������������������������������������������0000664�0001750�0001750�00000023410�14211404421�022310� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-constraint * @Title: ClutterConstraint * @Short_Description: Abstract class for constraints on position or size * @See_Also: #ClutterAction * * #ClutterConstraint is a base abstract class for modifiers of a #ClutterActor * position or size. * * A #ClutterConstraint sub-class should contain the logic for modifying * the position or size of the #ClutterActor to which it is applied, by * updating the actor's allocation. Each #ClutterConstraint can change the * allocation of the actor to which they are applied by overriding the * #ClutterConstraintClass.update_allocation() virtual function. * * #ClutterConstraint is available since Clutter 1.4 * * ## Using Constraints * * Constraints can be used with fixed layout managers, like * #ClutterFixedLayout, or with actors implicitly using a fixed layout * manager, like #ClutterGroup and #ClutterStage. * * Constraints provide a way to build user interfaces by using * relations between #ClutterActors, without explicit fixed * positioning and sizing, similarly to how fluid layout managers like * #ClutterBoxLayout and #ClutterTableLayout lay out their children. * * Constraints are attached to a #ClutterActor, and are available * for inspection using clutter_actor_get_constraints(). * * Clutter provides different implementation of the #ClutterConstraint * abstract class, for instance: * * - #ClutterAlignConstraint, a constraint that can be used to align * an actor to another one on either the horizontal or the vertical * axis, using a normalized value between 0 and 1. * - #ClutterBindConstraint, a constraint binds the X, Y, width or height * of an actor to the corresponding position or size of a source actor, * with or without an offset. * - #ClutterSnapConstraint, a constraint that "snaps" together the edges * of two #ClutterActors; if an actor uses two constraints on both its * horizontal or vertical edges then it can also expand to fit the empty * space. * * The [constraints example](https://git.gnome.org/browse/clutter/tree/examples/constraints.c?h=clutter-1.18) * uses various types of #ClutterConstraints to lay out three actors on a * resizable stage. Only the central actor has an explicit size, and no * actor has an explicit position. * * - The #ClutterActor with #ClutterActor:name `layerA` is explicitly * sized to 100 pixels by 25 pixels, and it's added to the #ClutterStage * - two #ClutterAlignConstraints are used to anchor `layerA` to the * center of the stage, by using 0.5 as the alignment #ClutterAlignConstraint:factor on * both the X and Y axis * - the #ClutterActor with #ClutterActor:name `layerB` is added to the * #ClutterStage with no explicit size * - the #ClutterActor:x and #ClutterActor:width of `layerB` are bound * to the same properties of `layerA` using two #ClutterBindConstraint * objects, thus keeping `layerB` aligned to `layerA` * - the top edge of `layerB` is snapped together with the bottom edge * of `layerA`; the bottom edge of `layerB` is also snapped together with * the bottom edge of the #ClutterStage; an offset is given to the two * #ClutterSnapConstraintss to allow for some padding; since `layerB` is * snapped between two different #ClutterActors, its height is stretched * to match the gap * - the #ClutterActor with #ClutterActor:name `layerC` mirrors `layerB`, * snapping the top edge of the #ClutterStage to the top edge of `layerC` * and the top edge of `layerA` to the bottom edge of `layerC` * * You can try resizing interactively the #ClutterStage and verify * that the three #ClutterActors maintain the same position and * size relative to each other, and to the #ClutterStage. * * It is important to note that Clutter does not avoid loops or * competing constraints; if two or more #ClutterConstraints * are operating on the same positional or dimensional attributes of an * actor, or if the constraints on two different actors depend on each * other, then the behavior is undefined. * * ## Implementing a ClutterConstraint * * Creating a sub-class of #ClutterConstraint requires the * implementation of the #ClutterConstraintClass.update_allocation() * virtual function. * * The `update_allocation()` virtual function is called during the * allocation sequence of a #ClutterActor, and allows any #ClutterConstraint * attached to that actor to modify the allocation before it is passed to * the actor's #ClutterActorClass.allocate() implementation. * * The #ClutterActorBox passed to the `update_allocation()` implementation * contains the original allocation of the #ClutterActor, plus the eventual * modifications applied by the other #ClutterConstraints, in the same order * the constraints have been applied to the actor. * * It is not necessary for a #ClutterConstraint sub-class to chain * up to the parent's implementation. * * If a #ClutterConstraint is parametrized - i.e. if it contains * properties that affect the way the constraint is implemented - it should * call clutter_actor_queue_relayout() on the actor to which it is attached * to whenever any parameter is changed. The actor to which it is attached * can be recovered at any point using clutter_actor_meta_get_actor(). */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <string.h> #include "clutter-constraint-private.h" #include "clutter-actor.h" #include "clutter-actor-meta-private.h" #include "clutter-private.h" G_DEFINE_ABSTRACT_TYPE (ClutterConstraint, clutter_constraint, CLUTTER_TYPE_ACTOR_META); static void constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation) { } static void constraint_update_preferred_size (ClutterConstraint *constraint, ClutterActor *actor, ClutterOrientation direction, float for_size, float *minimum_size, float *natural_size) { } static void clutter_constraint_notify (GObject *gobject, GParamSpec *pspec) { if (strcmp (pspec->name, "enabled") == 0) { ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject); ClutterActor *actor = clutter_actor_meta_get_actor (meta); if (actor != NULL) clutter_actor_queue_relayout (actor); } if (G_OBJECT_CLASS (clutter_constraint_parent_class)->notify != NULL) G_OBJECT_CLASS (clutter_constraint_parent_class)->notify (gobject, pspec); } static void clutter_constraint_class_init (ClutterConstraintClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->notify = clutter_constraint_notify; klass->update_allocation = constraint_update_allocation; klass->update_preferred_size = constraint_update_preferred_size; } static void clutter_constraint_init (ClutterConstraint *self) { } /*< private > * clutter_constraint_update_allocation: * @constraint: a #ClutterConstraint * @actor: a #ClutterActor * @allocation: (inout): the allocation to modify * * Asks the @constraint to update the @allocation of a #ClutterActor. * * Returns: %TRUE if the allocation was updated */ gboolean clutter_constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation) { ClutterActorBox old_alloc; g_return_val_if_fail (CLUTTER_IS_CONSTRAINT (constraint), FALSE); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); g_return_val_if_fail (allocation != NULL, FALSE); old_alloc = *allocation; CLUTTER_CONSTRAINT_GET_CLASS (constraint)->update_allocation (constraint, actor, allocation); return !clutter_actor_box_equal (allocation, &old_alloc); } void clutter_constraint_update_preferred_size (ClutterConstraint *constraint, ClutterActor *actor, ClutterOrientation direction, float for_size, float *minimum_size, float *natural_size) { g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); CLUTTER_CONSTRAINT_GET_CLASS (constraint)->update_preferred_size (constraint, actor, direction, for_size, minimum_size, natural_size); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-shader-effect.h������������������������������������������������0000664�0001750�0001750�00000011000�14211404421�022621� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_SHADER_EFFECT_H__ #define __CLUTTER_SHADER_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-offscreen-effect.h> G_BEGIN_DECLS #define CLUTTER_TYPE_SHADER_EFFECT (clutter_shader_effect_get_type ()) #define CLUTTER_SHADER_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SHADER_EFFECT, ClutterShaderEffect)) #define CLUTTER_IS_SHADER_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SHADER_EFFECT)) #define CLUTTER_SHADER_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SHADER_EFFECT, ClutterShaderEffectClass)) #define CLUTTER_IS_SHADER_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SHADER_EFFECT)) #define CLUTTER_SHADER_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SHADER_EFFECT, ClutterShaderEffectClass)) typedef struct _ClutterShaderEffect ClutterShaderEffect; typedef struct _ClutterShaderEffectPrivate ClutterShaderEffectPrivate; typedef struct _ClutterShaderEffectClass ClutterShaderEffectClass; /** * ClutterShaderEffect: * * The #ClutterShaderEffect structure contains * only private data and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterShaderEffect { /*< private >*/ ClutterOffscreenEffect parent_instance; ClutterShaderEffectPrivate *priv; }; /** * ClutterShaderEffectClass: * @get_static_shader_source: Returns the GLSL source code to use for * instances of this shader effect. Note that this function is only * called once per subclass of #ClutterShaderEffect regardless of how * many instances are used. It is expected that subclasses will return * a copy of a static string from this function. * * The #ClutterShaderEffectClass structure contains * only private data * * Since: 1.4 */ struct _ClutterShaderEffectClass { /*< private >*/ ClutterOffscreenEffectClass parent_class; /*< public >*/ gchar * (* get_static_shader_source) (ClutterShaderEffect *effect); /*< private >*/ /* padding */ void (*_clutter_shader1) (void); void (*_clutter_shader2) (void); void (*_clutter_shader3) (void); void (*_clutter_shader4) (void); void (*_clutter_shader5) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_shader_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterEffect * clutter_shader_effect_new (ClutterShaderType shader_type); CLUTTER_AVAILABLE_IN_1_4 gboolean clutter_shader_effect_set_shader_source (ClutterShaderEffect *effect, const gchar *source); CLUTTER_AVAILABLE_IN_1_4 void clutter_shader_effect_set_uniform (ClutterShaderEffect *effect, const gchar *name, GType gtype, gsize n_values, ...); CLUTTER_AVAILABLE_IN_1_4 void clutter_shader_effect_set_uniform_value (ClutterShaderEffect *effect, const gchar *name, const GValue *value); CLUTTER_AVAILABLE_IN_1_4 CoglHandle clutter_shader_effect_get_shader (ClutterShaderEffect *effect); CLUTTER_AVAILABLE_IN_1_4 CoglHandle clutter_shader_effect_get_program (ClutterShaderEffect *effect); G_END_DECLS #endif /* __CLUTTER_SHADER_EFFECT_H__ */ muffin-5.2.1/clutter/clutter/clutter-gesture-action.h�����������������������������������������������0000664�0001750�0001750�00000021561�14211404421�023067� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> */ #ifndef __CLUTTER_GESTURE_ACTION_H__ #define __CLUTTER_GESTURE_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-action.h> G_BEGIN_DECLS #define CLUTTER_TYPE_GESTURE_ACTION (clutter_gesture_action_get_type ()) #define CLUTTER_GESTURE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_GESTURE_ACTION, ClutterGestureAction)) #define CLUTTER_IS_GESTURE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_GESTURE_ACTION)) #define CLUTTER_GESTURE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_GESTURE_ACTION, ClutterGestureActionClass)) #define CLUTTER_IS_GESTURE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_GESTURE_ACTION)) #define CLUTTER_GESTURE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_GESTURE_ACTION, ClutterGestureActionClass)) typedef struct _ClutterGestureAction ClutterGestureAction; typedef struct _ClutterGestureActionPrivate ClutterGestureActionPrivate; typedef struct _ClutterGestureActionClass ClutterGestureActionClass; /** * ClutterGestureAction: * * The #ClutterGestureAction structure contains * only private data and should be accessed using the provided API * * Since: 1.8 */ struct _ClutterGestureAction { /*< private >*/ ClutterAction parent_instance; ClutterGestureActionPrivate *priv; }; /** * ClutterGestureActionClass: * @gesture_begin: class handler for the #ClutterGestureAction::gesture-begin signal * @gesture_progress: class handler for the #ClutterGestureAction::gesture-progress signal * @gesture_end: class handler for the #ClutterGestureAction::gesture-end signal * @gesture_cancel: class handler for the #ClutterGestureAction::gesture-cancel signal * @gesture_prepare: virtual function called before emitting the * #ClutterGestureAction::gesture-cancel signal * * The #ClutterGestureClass structure contains only * private data. * * Since: 1.8 */ struct _ClutterGestureActionClass { /*< private >*/ ClutterActionClass parent_class; /*< public >*/ gboolean (* gesture_begin) (ClutterGestureAction *action, ClutterActor *actor); gboolean (* gesture_progress) (ClutterGestureAction *action, ClutterActor *actor); void (* gesture_end) (ClutterGestureAction *action, ClutterActor *actor); void (* gesture_cancel) (ClutterGestureAction *action, ClutterActor *actor); gboolean (* gesture_prepare) (ClutterGestureAction *action, ClutterActor *actor); /*< private >*/ void (* _clutter_gesture_action1) (void); void (* _clutter_gesture_action2) (void); void (* _clutter_gesture_action3) (void); void (* _clutter_gesture_action4) (void); void (* _clutter_gesture_action5) (void); void (* _clutter_gesture_action6) (void); }; CLUTTER_AVAILABLE_IN_1_8 GType clutter_gesture_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_8 ClutterAction * clutter_gesture_action_new (void); CLUTTER_AVAILABLE_IN_1_8 gint clutter_gesture_action_get_n_touch_points (ClutterGestureAction *action); CLUTTER_AVAILABLE_IN_1_8 void clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action, gint nb_points); CLUTTER_AVAILABLE_IN_1_8 void clutter_gesture_action_get_press_coords (ClutterGestureAction *action, guint point, gfloat *press_x, gfloat *press_y); CLUTTER_AVAILABLE_IN_1_8 void clutter_gesture_action_get_motion_coords (ClutterGestureAction *action, guint point, gfloat *motion_x, gfloat *motion_y); CLUTTER_AVAILABLE_IN_1_12 gfloat clutter_gesture_action_get_motion_delta (ClutterGestureAction *action, guint point, gfloat *delta_x, gfloat *delta_y); CLUTTER_AVAILABLE_IN_1_8 void clutter_gesture_action_get_release_coords (ClutterGestureAction *action, guint point, gfloat *release_x, gfloat *release_y); CLUTTER_AVAILABLE_IN_1_12 gfloat clutter_gesture_action_get_velocity (ClutterGestureAction *action, guint point, gfloat *velocity_x, gfloat *velocity_y); CLUTTER_AVAILABLE_IN_1_12 guint clutter_gesture_action_get_n_current_points (ClutterGestureAction *action); CLUTTER_AVAILABLE_IN_1_12 ClutterEventSequence * clutter_gesture_action_get_sequence (ClutterGestureAction *action, guint point); CLUTTER_AVAILABLE_IN_1_12 ClutterInputDevice * clutter_gesture_action_get_device (ClutterGestureAction *action, guint point); CLUTTER_AVAILABLE_IN_1_14 const ClutterEvent * clutter_gesture_action_get_last_event (ClutterGestureAction *action, guint point); CLUTTER_AVAILABLE_IN_1_12 void clutter_gesture_action_cancel (ClutterGestureAction *action); CLUTTER_AVAILABLE_IN_1_18 void clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction *action, ClutterGestureTriggerEdge edge); CLUTTER_DEPRECATED_IN_1_20_FOR(clutter_gesture_action_get_threshold_trigger_edge) ClutterGestureTriggerEdge clutter_gesture_action_get_threshold_trigger_egde (ClutterGestureAction *action); CLUTTER_AVAILABLE_IN_1_20 ClutterGestureTriggerEdge clutter_gesture_action_get_threshold_trigger_edge (ClutterGestureAction *action); CLUTTER_AVAILABLE_IN_1_18 void clutter_gesture_action_set_threshold_trigger_distance (ClutterGestureAction *action, float x, float y); CLUTTER_AVAILABLE_IN_1_18 void clutter_gesture_action_get_threshold_trigger_distance (ClutterGestureAction *action, float *x, float *y); G_END_DECLS #endif /* __CLUTTER_GESTURE_ACTION_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-paint-nodes.c��������������������������������������������������0000664�0001750�0001750�00000102372�14211404421�022352� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-paint-nodes * @Title: Paint Nodes * @Short_Description: ClutterPaintNode implementations * * Clutter provides a set of predefined #ClutterPaintNode implementations * that cover all the state changes available. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-paint-node-private.h" #include <pango/pango.h> #include <cogl/cogl.h> #include "clutter-actor-private.h" #include "clutter-color.h" #include "clutter-debug.h" #include "clutter-private.h" #include "clutter-paint-nodes.h" static CoglPipeline *default_color_pipeline = NULL; static CoglPipeline *default_texture_pipeline = NULL; /*< private > * _clutter_paint_node_init_types: * * Initializes the required types for ClutterPaintNode subclasses */ void _clutter_paint_node_init_types (void) { CoglContext *ctx; CoglColor cogl_color; GType node_type G_GNUC_UNUSED; if (G_LIKELY (default_color_pipeline != NULL)) return; ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); node_type = clutter_paint_node_get_type (); cogl_color_init_from_4f (&cogl_color, 1.0, 1.0, 1.0, 1.0); default_color_pipeline = cogl_pipeline_new (ctx); cogl_pipeline_set_color (default_color_pipeline, &cogl_color); default_texture_pipeline = cogl_pipeline_new (ctx); cogl_pipeline_set_layer_null_texture (default_texture_pipeline, 0, COGL_TEXTURE_TYPE_2D); cogl_pipeline_set_color (default_texture_pipeline, &cogl_color); cogl_pipeline_set_layer_wrap_mode (default_texture_pipeline, 0, COGL_PIPELINE_WRAP_MODE_AUTOMATIC); } /* * Root node, private * * any frame can only have a since RootNode instance for each * top-level actor. */ #define clutter_root_node_get_type _clutter_root_node_get_type typedef struct _ClutterRootNode ClutterRootNode; typedef struct _ClutterPaintNodeClass ClutterRootNodeClass; struct _ClutterRootNode { ClutterPaintNode parent_instance; CoglFramebuffer *framebuffer; CoglBufferBit clear_flags; CoglColor clear_color; }; G_DEFINE_TYPE (ClutterRootNode, clutter_root_node, CLUTTER_TYPE_PAINT_NODE) static gboolean clutter_root_node_pre_draw (ClutterPaintNode *node) { ClutterRootNode *rnode = (ClutterRootNode *) node; cogl_framebuffer_clear (rnode->framebuffer, rnode->clear_flags, &rnode->clear_color); return TRUE; } static void clutter_root_node_post_draw (ClutterPaintNode *node) { } static void clutter_root_node_finalize (ClutterPaintNode *node) { ClutterRootNode *rnode = (ClutterRootNode *) node; cogl_object_unref (rnode->framebuffer); CLUTTER_PAINT_NODE_CLASS (clutter_root_node_parent_class)->finalize (node); } static CoglFramebuffer * clutter_root_node_get_framebuffer (ClutterPaintNode *node) { ClutterRootNode *rnode = (ClutterRootNode *) node; return rnode->framebuffer; } static void clutter_root_node_class_init (ClutterRootNodeClass *klass) { ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass); node_class->pre_draw = clutter_root_node_pre_draw; node_class->post_draw = clutter_root_node_post_draw; node_class->finalize = clutter_root_node_finalize; node_class->get_framebuffer = clutter_root_node_get_framebuffer; } static void clutter_root_node_init (ClutterRootNode *self) { } ClutterPaintNode * _clutter_root_node_new (CoglFramebuffer *framebuffer, const ClutterColor *clear_color, CoglBufferBit clear_flags) { ClutterRootNode *res; res = _clutter_paint_node_create (_clutter_root_node_get_type ()); cogl_color_init_from_4ub (&res->clear_color, clear_color->red, clear_color->green, clear_color->blue, clear_color->alpha); cogl_color_premultiply (&res->clear_color); if (G_LIKELY (framebuffer != NULL)) res->framebuffer = cogl_object_ref (framebuffer); else res->framebuffer = cogl_object_ref (cogl_get_draw_framebuffer ()); res->clear_flags = clear_flags; return (ClutterPaintNode *) res; } /* * Transform node * * A private PaintNode, that changes the modelview of its child * nodes. */ #define clutter_transform_node_get_type _clutter_transform_node_get_type typedef struct _ClutterTransformNode { ClutterPaintNode parent_instance; CoglMatrix modelview; } ClutterTransformNode; typedef struct _ClutterPaintNodeClass ClutterTransformNodeClass; G_DEFINE_TYPE (ClutterTransformNode, clutter_transform_node, CLUTTER_TYPE_PAINT_NODE) static gboolean clutter_transform_node_pre_draw (ClutterPaintNode *node) { ClutterTransformNode *tnode = (ClutterTransformNode *) node; CoglMatrix matrix; cogl_push_matrix (); cogl_get_modelview_matrix (&matrix); cogl_matrix_multiply (&matrix, &matrix, &tnode->modelview); cogl_set_modelview_matrix (&matrix); return TRUE; } static void clutter_transform_node_post_draw (ClutterPaintNode *node) { cogl_pop_matrix (); } static void clutter_transform_node_class_init (ClutterTransformNodeClass *klass) { ClutterPaintNodeClass *node_class; node_class = CLUTTER_PAINT_NODE_CLASS (klass); node_class->pre_draw = clutter_transform_node_pre_draw; node_class->post_draw = clutter_transform_node_post_draw; } static void clutter_transform_node_init (ClutterTransformNode *self) { cogl_matrix_init_identity (&self->modelview); } ClutterPaintNode * _clutter_transform_node_new (const CoglMatrix *modelview) { ClutterTransformNode *res; res = _clutter_paint_node_create (_clutter_transform_node_get_type ()); if (modelview != NULL) res->modelview = *modelview; return (ClutterPaintNode *) res; } /* * Dummy node, private * * an empty node, used temporarily until we can drop API compatibility, * and we'll be able to build a full render tree for each frame. */ #define clutter_dummy_node_get_type _clutter_dummy_node_get_type typedef struct _ClutterDummyNode ClutterDummyNode; typedef struct _ClutterPaintNodeClass ClutterDummyNodeClass; struct _ClutterDummyNode { ClutterPaintNode parent_instance; ClutterActor *actor; CoglFramebuffer *framebuffer; }; G_DEFINE_TYPE (ClutterDummyNode, clutter_dummy_node, CLUTTER_TYPE_PAINT_NODE) static gboolean clutter_dummy_node_pre_draw (ClutterPaintNode *node) { return TRUE; } static JsonNode * clutter_dummy_node_serialize (ClutterPaintNode *node) { ClutterDummyNode *dnode = (ClutterDummyNode *) node; JsonBuilder *builder; JsonNode *res; if (dnode->actor == NULL) return json_node_new (JSON_NODE_NULL); builder = json_builder_new (); json_builder_begin_object (builder); json_builder_set_member_name (builder, "actor"); json_builder_add_string_value (builder, _clutter_actor_get_debug_name (dnode->actor)); json_builder_end_object (builder); res = json_builder_get_root (builder); g_object_unref (builder); return res; } static CoglFramebuffer * clutter_dummy_node_get_framebuffer (ClutterPaintNode *node) { ClutterDummyNode *dnode = (ClutterDummyNode *) node; return dnode->framebuffer; } static void clutter_dummy_node_class_init (ClutterDummyNodeClass *klass) { ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass); node_class->pre_draw = clutter_dummy_node_pre_draw; node_class->serialize = clutter_dummy_node_serialize; node_class->get_framebuffer = clutter_dummy_node_get_framebuffer; } static void clutter_dummy_node_init (ClutterDummyNode *self) { } ClutterPaintNode * _clutter_dummy_node_new (ClutterActor *actor) { ClutterPaintNode *res; ClutterDummyNode *dnode; res = _clutter_paint_node_create (_clutter_dummy_node_get_type ()); dnode = (ClutterDummyNode *) res; dnode->actor = actor; dnode->framebuffer = _clutter_actor_get_active_framebuffer (actor); return res; } /* * Pipeline node */ struct _ClutterPipelineNode { ClutterPaintNode parent_instance; CoglPipeline *pipeline; }; /** * ClutterPipelineNodeClass: * * The `ClutterPipelineNodeClass` structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ struct _ClutterPipelineNodeClass { ClutterPaintNodeClass parent_class; }; G_DEFINE_TYPE (ClutterPipelineNode, clutter_pipeline_node, CLUTTER_TYPE_PAINT_NODE) static void clutter_pipeline_node_finalize (ClutterPaintNode *node) { ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node); if (pnode->pipeline != NULL) cogl_object_unref (pnode->pipeline); CLUTTER_PAINT_NODE_CLASS (clutter_pipeline_node_parent_class)->finalize (node); } static gboolean clutter_pipeline_node_pre_draw (ClutterPaintNode *node) { ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node); if (node->operations != NULL && pnode->pipeline != NULL) { cogl_push_source (pnode->pipeline); return TRUE; } return FALSE; } static void clutter_pipeline_node_draw (ClutterPaintNode *node) { ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node); CoglFramebuffer *fb; guint i; if (pnode->pipeline == NULL) return; if (node->operations == NULL) return; fb = clutter_paint_node_get_framebuffer (node); for (i = 0; i < node->operations->len; i++) { const ClutterPaintOperation *op; op = &g_array_index (node->operations, ClutterPaintOperation, i); switch (op->opcode) { case PAINT_OP_INVALID: break; case PAINT_OP_TEX_RECT: cogl_rectangle_with_texture_coords (op->op.texrect[0], op->op.texrect[1], op->op.texrect[2], op->op.texrect[3], op->op.texrect[4], op->op.texrect[5], op->op.texrect[6], op->op.texrect[7]); break; case PAINT_OP_PATH: cogl_path_fill (op->op.path); break; case PAINT_OP_PRIMITIVE: cogl_framebuffer_draw_primitive (fb, pnode->pipeline, op->op.primitive); break; } } } static void clutter_pipeline_node_post_draw (ClutterPaintNode *node) { cogl_pop_source (); } static JsonNode * clutter_pipeline_node_serialize (ClutterPaintNode *node) { ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (node); JsonBuilder *builder; CoglColor color; JsonNode *res; if (pnode->pipeline == NULL) return json_node_new (JSON_NODE_NULL); builder = json_builder_new (); json_builder_begin_object (builder); cogl_pipeline_get_color (pnode->pipeline, &color); json_builder_set_member_name (builder, "color"); json_builder_begin_array (builder); json_builder_add_double_value (builder, cogl_color_get_red (&color)); json_builder_add_double_value (builder, cogl_color_get_green (&color)); json_builder_add_double_value (builder, cogl_color_get_blue (&color)); json_builder_add_double_value (builder, cogl_color_get_alpha (&color)); json_builder_end_array (builder); #if 0 json_builder_set_member_name (builder, "layers"); json_builder_begin_array (builder); cogl_pipeline_foreach_layer (pnode->pipeline, clutter_pipeline_node_serialize_layer, builder); json_builder_end_array (builder); #endif json_builder_end_object (builder); res = json_builder_get_root (builder); g_object_unref (builder); return res; } static void clutter_pipeline_node_class_init (ClutterPipelineNodeClass *klass) { ClutterPaintNodeClass *node_class; node_class = CLUTTER_PAINT_NODE_CLASS (klass); node_class->pre_draw = clutter_pipeline_node_pre_draw; node_class->draw = clutter_pipeline_node_draw; node_class->post_draw = clutter_pipeline_node_post_draw; node_class->finalize = clutter_pipeline_node_finalize; node_class->serialize = clutter_pipeline_node_serialize; } static void clutter_pipeline_node_init (ClutterPipelineNode *self) { } /** * clutter_pipeline_node_new: (skip) * @pipeline: (allow-none): a Cogl pipeline state object, or %NULL * * Creates a new #ClutterPaintNode that will use the @pipeline to * paint its contents. * * This function will acquire a reference on the passed @pipeline, * so it is safe to call cogl_object_unref() when it returns. * * Return value: (transfer full): the newly created #ClutterPaintNode. * Use clutter_paint_node_unref() when done. * * Since: 1.10 */ ClutterPaintNode * clutter_pipeline_node_new (CoglPipeline *pipeline) { ClutterPipelineNode *res; g_return_val_if_fail (pipeline == NULL || cogl_is_pipeline (pipeline), NULL); res = _clutter_paint_node_create (CLUTTER_TYPE_PIPELINE_NODE); if (pipeline != NULL) res->pipeline = cogl_object_ref (pipeline); return (ClutterPaintNode *) res; } /* * Color node */ struct _ClutterColorNode { ClutterPipelineNode parent_instance; }; /** * ClutterColorNodeClass: * * The `ClutterColorNodeClass` structure is an * opaque type whose members cannot be directly accessed. * * Since: 1.10 */ struct _ClutterColorNodeClass { ClutterPipelineNodeClass parent_class; }; G_DEFINE_TYPE (ClutterColorNode, clutter_color_node, CLUTTER_TYPE_PIPELINE_NODE) static void clutter_color_node_class_init (ClutterColorNodeClass *klass) { } static void clutter_color_node_init (ClutterColorNode *cnode) { ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (cnode); g_assert (default_color_pipeline != NULL); pnode->pipeline = cogl_pipeline_copy (default_color_pipeline); } /** * clutter_color_node_new: * @color: (allow-none): the color to paint, or %NULL * * Creates a new #ClutterPaintNode that will paint a solid color * fill using @color. * * Return value: (transfer full): the newly created #ClutterPaintNode. Use * clutter_paint_node_unref() when done * * Since: 1.10 */ ClutterPaintNode * clutter_color_node_new (const ClutterColor *color) { ClutterPipelineNode *cnode; cnode = _clutter_paint_node_create (CLUTTER_TYPE_COLOR_NODE); if (color != NULL) { CoglColor cogl_color; cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); cogl_color_premultiply (&cogl_color); cogl_pipeline_set_color (cnode->pipeline, &cogl_color); } return (ClutterPaintNode *) cnode; } /* * Texture node */ struct _ClutterTextureNode { ClutterPipelineNode parent_instance; }; /** * ClutterTextureNodeClass: * * The `ClutterTextureNodeClass` structure is an * opaque type whose members cannot be directly accessed. * * Since: 1.10 */ struct _ClutterTextureNodeClass { ClutterPipelineNodeClass parent_class; }; G_DEFINE_TYPE (ClutterTextureNode, clutter_texture_node, CLUTTER_TYPE_PIPELINE_NODE) static void clutter_texture_node_class_init (ClutterTextureNodeClass *klass) { } static void clutter_texture_node_init (ClutterTextureNode *self) { ClutterPipelineNode *pnode = CLUTTER_PIPELINE_NODE (self); g_assert (default_texture_pipeline != NULL); pnode->pipeline = cogl_pipeline_copy (default_texture_pipeline); } static CoglPipelineFilter clutter_scaling_filter_to_cogl_pipeline_filter (ClutterScalingFilter filter) { switch (filter) { case CLUTTER_SCALING_FILTER_NEAREST: return COGL_PIPELINE_FILTER_NEAREST; case CLUTTER_SCALING_FILTER_LINEAR: return COGL_PIPELINE_FILTER_LINEAR; case CLUTTER_SCALING_FILTER_TRILINEAR: return COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR; } return COGL_PIPELINE_FILTER_LINEAR; } /** * clutter_texture_node_new: * @texture: a #CoglTexture * @color: (allow-none): a #ClutterColor used for blending, or %NULL * @min_filter: the minification filter for the texture * @mag_filter: the magnification filter for the texture * * Creates a new #ClutterPaintNode that will paint the passed @texture. * * This function will take a reference on @texture, so it is safe to * call cogl_object_unref() on @texture when it returns. * * The @color must not be pre-multiplied with its #ClutterColor.alpha * channel value; if @color is %NULL, a fully opaque white color will * be used for blending. * * Return value: (transfer full): the newly created #ClutterPaintNode. * Use clutter_paint_node_unref() when done * * Since: 1.10 */ ClutterPaintNode * clutter_texture_node_new (CoglTexture *texture, const ClutterColor *color, ClutterScalingFilter min_filter, ClutterScalingFilter mag_filter) { ClutterPipelineNode *tnode; CoglColor cogl_color; CoglPipelineFilter min_f, mag_f; g_return_val_if_fail (cogl_is_texture (texture), NULL); tnode = _clutter_paint_node_create (CLUTTER_TYPE_TEXTURE_NODE); cogl_pipeline_set_layer_texture (tnode->pipeline, 0, texture); min_f = clutter_scaling_filter_to_cogl_pipeline_filter (min_filter); mag_f = clutter_scaling_filter_to_cogl_pipeline_filter (mag_filter); cogl_pipeline_set_layer_filters (tnode->pipeline, 0, min_f, mag_f); if (color != NULL) { cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); cogl_color_premultiply (&cogl_color); } else cogl_color_init_from_4ub (&cogl_color, 255, 255, 255, 255); cogl_pipeline_set_color (tnode->pipeline, &cogl_color); return (ClutterPaintNode *) tnode; } /* * Text node */ struct _ClutterTextNode { ClutterPaintNode parent_instance; PangoLayout *layout; CoglColor color; }; /** * ClutterTextNodeClass: * * The `ClutterTextNodeClass` structure is an opaque * type whose contents cannot be directly accessed. * * Since: 1.10 */ struct _ClutterTextNodeClass { ClutterPaintNodeClass parent_class; }; G_DEFINE_TYPE (ClutterTextNode, clutter_text_node, CLUTTER_TYPE_PAINT_NODE) static void clutter_text_node_finalize (ClutterPaintNode *node) { ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node); if (tnode->layout != NULL) g_object_unref (tnode->layout); CLUTTER_PAINT_NODE_CLASS (clutter_text_node_parent_class)->finalize (node); } static gboolean clutter_text_node_pre_draw (ClutterPaintNode *node) { ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node); return tnode->layout != NULL; } static void clutter_text_node_draw (ClutterPaintNode *node) { ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node); PangoRectangle extents; CoglFramebuffer *fb; guint i; if (node->operations == NULL) return; fb = clutter_paint_node_get_framebuffer (node); pango_layout_get_pixel_extents (tnode->layout, NULL, &extents); for (i = 0; i < node->operations->len; i++) { const ClutterPaintOperation *op; float op_width, op_height; gboolean clipped = FALSE; op = &g_array_index (node->operations, ClutterPaintOperation, i); switch (op->opcode) { case PAINT_OP_TEX_RECT: op_width = op->op.texrect[2] - op->op.texrect[0]; op_height = op->op.texrect[3] - op->op.texrect[1]; /* if the primitive size was smaller than the layout, * we clip the layout when drawin, to avoid spilling * it out */ if (extents.width > op_width || extents.height > op_height) { cogl_framebuffer_push_rectangle_clip (fb, op->op.texrect[0], op->op.texrect[1], op->op.texrect[2], op->op.texrect[3]); clipped = TRUE; } cogl_pango_render_layout (tnode->layout, op->op.texrect[0], op->op.texrect[1], &tnode->color, 0); if (clipped) cogl_framebuffer_pop_clip (fb); break; case PAINT_OP_PATH: case PAINT_OP_PRIMITIVE: case PAINT_OP_INVALID: break; } } } static JsonNode * clutter_text_node_serialize (ClutterPaintNode *node) { ClutterTextNode *tnode = CLUTTER_TEXT_NODE (node); JsonBuilder *builder; JsonNode *res; builder = json_builder_new (); json_builder_begin_object (builder); json_builder_set_member_name (builder, "layout"); if (pango_layout_get_character_count (tnode->layout) > 12) { const char *text = pango_layout_get_text (tnode->layout); char *str; str = g_strndup (text, 12); json_builder_add_string_value (builder, str); free (str); } else json_builder_add_string_value (builder, pango_layout_get_text (tnode->layout)); json_builder_set_member_name (builder, "color"); json_builder_begin_array (builder); json_builder_add_double_value (builder, cogl_color_get_red (&tnode->color)); json_builder_add_double_value (builder, cogl_color_get_green (&tnode->color)); json_builder_add_double_value (builder, cogl_color_get_blue (&tnode->color)); json_builder_add_double_value (builder, cogl_color_get_alpha (&tnode->color)); json_builder_end_array (builder); json_builder_end_object (builder); res = json_builder_get_root (builder); g_object_unref (builder); return res; } static void clutter_text_node_class_init (ClutterTextNodeClass *klass) { ClutterPaintNodeClass *node_class = CLUTTER_PAINT_NODE_CLASS (klass); node_class->pre_draw = clutter_text_node_pre_draw; node_class->draw = clutter_text_node_draw; node_class->finalize = clutter_text_node_finalize; node_class->serialize = clutter_text_node_serialize; } static void clutter_text_node_init (ClutterTextNode *self) { cogl_color_init_from_4f (&self->color, 0.0, 0.0, 0.0, 1.0); } /** * clutter_text_node_new: * @layout: (allow-none): a #PangoLayout, or %NULL * @color: (allow-none): the color used to paint the layout, * or %NULL * * Creates a new #ClutterPaintNode that will paint a #PangoLayout * with the given color. * * This function takes a reference on the passed @layout, so it * is safe to call g_object_unref() after it returns. * * Return value: (transfer full): the newly created #ClutterPaintNode. * Use clutter_paint_node_unref() when done * * Since: 1.10 */ ClutterPaintNode * clutter_text_node_new (PangoLayout *layout, const ClutterColor *color) { ClutterTextNode *res; g_return_val_if_fail (layout == NULL || PANGO_IS_LAYOUT (layout), NULL); res = _clutter_paint_node_create (CLUTTER_TYPE_TEXT_NODE); if (layout != NULL) res->layout = g_object_ref (layout); if (color != NULL) { cogl_color_init_from_4ub (&res->color, color->red, color->green, color->blue, color->alpha); } return (ClutterPaintNode *) res; } /* * Clip node */ struct _ClutterClipNode { ClutterPaintNode parent_instance; }; /** * ClutterClipNodeClass: * * The `ClutterClipNodeClass` structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ struct _ClutterClipNodeClass { ClutterPaintNodeClass parent_class; }; G_DEFINE_TYPE (ClutterClipNode, clutter_clip_node, CLUTTER_TYPE_PAINT_NODE) static gboolean clutter_clip_node_pre_draw (ClutterPaintNode *node) { gboolean retval = FALSE; CoglFramebuffer *fb; guint i; if (node->operations == NULL) return FALSE; fb = clutter_paint_node_get_framebuffer (node); for (i = 0; i < node->operations->len; i++) { const ClutterPaintOperation *op; op = &g_array_index (node->operations, ClutterPaintOperation, i); switch (op->opcode) { case PAINT_OP_TEX_RECT: cogl_framebuffer_push_rectangle_clip (fb, op->op.texrect[0], op->op.texrect[1], op->op.texrect[2], op->op.texrect[3]); retval = TRUE; break; case PAINT_OP_PATH: cogl_framebuffer_push_path_clip (fb, op->op.path); retval = TRUE; break; case PAINT_OP_PRIMITIVE: case PAINT_OP_INVALID: break; } } return retval; } static void clutter_clip_node_post_draw (ClutterPaintNode *node) { CoglFramebuffer *fb; guint i; if (node->operations == NULL) return; fb = clutter_paint_node_get_framebuffer (node); for (i = 0; i < node->operations->len; i++) { const ClutterPaintOperation *op; op = &g_array_index (node->operations, ClutterPaintOperation, i); switch (op->opcode) { case PAINT_OP_PATH: case PAINT_OP_TEX_RECT: cogl_framebuffer_pop_clip (fb); break; case PAINT_OP_PRIMITIVE: case PAINT_OP_INVALID: break; } } } static void clutter_clip_node_class_init (ClutterClipNodeClass *klass) { ClutterPaintNodeClass *node_class; node_class = CLUTTER_PAINT_NODE_CLASS (klass); node_class->pre_draw = clutter_clip_node_pre_draw; node_class->post_draw = clutter_clip_node_post_draw; } static void clutter_clip_node_init (ClutterClipNode *self) { } /** * clutter_clip_node_new: * * Creates a new #ClutterPaintNode that will clip its child * nodes to the 2D regions added to it. * * Return value: (transfer full): the newly created #ClutterPaintNode. * Use clutter_paint_node_unref() when done. * * Since: 1.10 */ ClutterPaintNode * clutter_clip_node_new (void) { return _clutter_paint_node_create (CLUTTER_TYPE_CLIP_NODE); } /* * ClutterLayerNode (private) */ #define clutter_layer_node_get_type _clutter_layer_node_get_type struct _ClutterLayerNode { ClutterPaintNode parent_instance; cairo_rectangle_t viewport; CoglMatrix projection; float fbo_width; float fbo_height; CoglPipeline *state; CoglFramebuffer *offscreen; CoglTexture *texture; guint8 opacity; }; struct _ClutterLayerNodeClass { ClutterPaintNodeClass parent_class; }; G_DEFINE_TYPE (ClutterLayerNode, clutter_layer_node, CLUTTER_TYPE_PAINT_NODE) static gboolean clutter_layer_node_pre_draw (ClutterPaintNode *node) { ClutterLayerNode *lnode = (ClutterLayerNode *) node; CoglMatrix matrix; /* if we were unable to create an offscreen buffer for this node, then * we simply ignore it */ if (lnode->offscreen == NULL) return FALSE; /* if no geometry was submitted for this node then we simply ignore it */ if (node->operations == NULL) return FALSE; /* copy the same modelview from the current framebuffer to the one we * are going to use */ cogl_get_modelview_matrix (&matrix); cogl_push_framebuffer (lnode->offscreen); cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix); cogl_framebuffer_set_viewport (lnode->offscreen, lnode->viewport.x, lnode->viewport.y, lnode->viewport.width, lnode->viewport.height); cogl_framebuffer_set_projection_matrix (lnode->offscreen, &lnode->projection); /* clear out the target framebuffer */ cogl_framebuffer_clear4f (lnode->offscreen, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH, 0.f, 0.f, 0.f, 0.f); cogl_push_matrix (); /* every draw operation after this point will happen an offscreen * framebuffer */ return TRUE; } static void clutter_layer_node_post_draw (ClutterPaintNode *node) { ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node); CoglFramebuffer *fb; guint i; /* switch to the previous framebuffer */ cogl_pop_matrix (); cogl_pop_framebuffer (); fb = cogl_get_draw_framebuffer (); for (i = 0; i < node->operations->len; i++) { const ClutterPaintOperation *op; op = &g_array_index (node->operations, ClutterPaintOperation, i); switch (op->opcode) { case PAINT_OP_INVALID: break; case PAINT_OP_TEX_RECT: /* now we need to paint the texture */ cogl_push_source (lnode->state); cogl_rectangle_with_texture_coords (op->op.texrect[0], op->op.texrect[1], op->op.texrect[2], op->op.texrect[3], op->op.texrect[4], op->op.texrect[5], op->op.texrect[6], op->op.texrect[7]); cogl_pop_source (); break; case PAINT_OP_PATH: cogl_push_source (lnode->state); cogl_path_fill (op->op.path); cogl_pop_source (); break; case PAINT_OP_PRIMITIVE: cogl_framebuffer_draw_primitive (fb, lnode->state, op->op.primitive); break; } } } static void clutter_layer_node_finalize (ClutterPaintNode *node) { ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node); if (lnode->state != NULL) cogl_object_unref (lnode->state); if (lnode->offscreen != NULL) cogl_object_unref (lnode->offscreen); CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node); } static void clutter_layer_node_class_init (ClutterLayerNodeClass *klass) { ClutterPaintNodeClass *node_class; node_class = CLUTTER_PAINT_NODE_CLASS (klass); node_class->pre_draw = clutter_layer_node_pre_draw; node_class->post_draw = clutter_layer_node_post_draw; node_class->finalize = clutter_layer_node_finalize; } static void clutter_layer_node_init (ClutterLayerNode *self) { cogl_matrix_init_identity (&self->projection); } /* * clutter_layer_node_new: * @projection: the projection matrix to use to set up the layer * @viewport: (type cairo.Rectangle): the viewport to use to set up the layer * @width: the width of the layer * @height: the height of the layer * @opacity: the opacity to be used when drawing the layer * * Creates a new #ClutterLayerNode. * * All children of this node will be painted inside a separate * framebuffer; the framebuffer will then be painted using the * given @opacity. * * Return value: (transfer full): the newly created #ClutterLayerNode. * Use clutter_paint_node_unref() when done. * * Since: 1.10 */ ClutterPaintNode * _clutter_layer_node_new (const CoglMatrix *projection, const cairo_rectangle_t *viewport, float width, float height, guint8 opacity) { ClutterLayerNode *res; CoglColor color; res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE); res->projection = *projection; res->viewport = *viewport; res->fbo_width = width; res->fbo_height = height; res->opacity = opacity; /* the texture backing the FBO */ res->texture = cogl_texture_new_with_size (MAX (res->fbo_width, 1), MAX (res->fbo_height, 1), COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888_PRE); res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (res->texture)); if (res->offscreen == NULL) { g_critical ("%s: Unable to create an offscreen buffer", G_STRLOC); cogl_object_unref (res->texture); res->texture = NULL; goto out; } cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity); /* the pipeline used to paint the texture; we use nearest * interpolation filters because the texture is always * going to be painted at a 1:1 texel:pixel ratio */ res->state = cogl_pipeline_copy (default_texture_pipeline); cogl_pipeline_set_layer_filters (res->state, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_layer_texture (res->state, 0, res->texture); cogl_pipeline_set_color (res->state, &color); cogl_object_unref (res->texture); out: return (ClutterPaintNode *) res; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-flow-layout.c��������������������������������������������������0000664�0001750�0001750�00000127114�14211404421�022414� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-flow-layout * @short_description: A reflowing layout manager * * #ClutterFlowLayout is a layout manager which implements the following * policy: * * - the preferred natural size depends on the value * of the #ClutterFlowLayout:orientation property; the layout will try * to maintain all its children on a single row or * column; * - if either the width or the height allocated are * smaller than the preferred ones, the layout will wrap; in this case, * the preferred height or width, respectively, will take into account * the amount of columns and rows; * - each line (either column or row) in reflowing will * have the size of the biggest cell on that line; if the * #ClutterFlowLayout:homogeneous property is set to %FALSE the actor * will be allocated within that area, and if set to %TRUE instead the * actor will be given exactly that area; * - the size of the columns or rows can be controlled * for both minimum and maximum; the spacing can also be controlled * in both columns and rows. * * The [flow-layout example](https://git.gnome.org/browse/clutter/tree/examples/flow-layout.c?h=clutter-1.18) * shows how to use the #ClutterFlowLayout. * * #ClutterFlowLayout is available since Clutter 1.2 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "clutter-actor.h" #include "clutter-animatable.h" #include "clutter-child-meta.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-flow-layout.h" #include "clutter-layout-meta.h" #include "clutter-private.h" struct _ClutterFlowLayoutPrivate { ClutterContainer *container; ClutterFlowOrientation orientation; gfloat col_spacing; gfloat row_spacing; gfloat min_col_width; gfloat max_col_width; gfloat col_width; gfloat min_row_height; gfloat max_row_height; gfloat row_height; /* per-line size */ GArray *line_min; GArray *line_natural; gfloat req_width; gfloat req_height; guint line_count; guint is_homogeneous : 1; guint snap_to_grid : 1; }; enum { PROP_0, PROP_ORIENTATION, PROP_HOMOGENEOUS, PROP_COLUMN_SPACING, PROP_ROW_SPACING, PROP_MIN_COLUMN_WIDTH, PROP_MAX_COLUMN_WIDTH, PROP_MIN_ROW_HEGHT, PROP_MAX_ROW_HEIGHT, PROP_SNAP_TO_GRID, N_PROPERTIES }; static GParamSpec *flow_properties[N_PROPERTIES] = { NULL, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterFlowLayout, clutter_flow_layout, CLUTTER_TYPE_LAYOUT_MANAGER) static gint get_columns (ClutterFlowLayout *self, gfloat for_width) { ClutterFlowLayoutPrivate *priv = self->priv; gint n_columns; if (for_width < 0) return 1; if (priv->col_width == 0) return 1; n_columns = (gint) (for_width + priv->col_spacing) / (priv->col_width + priv->col_spacing); if (n_columns == 0) return 1; return n_columns; } static gint get_rows (ClutterFlowLayout *self, gfloat for_height) { ClutterFlowLayoutPrivate *priv = self->priv; gint n_rows; if (for_height < 0) return 1; if (priv->row_height == 0) return 1; n_rows = (gint) (for_height + priv->row_spacing) / (priv->row_height + priv->row_spacing); if (n_rows == 0) return 1; return n_rows; } static gint compute_lines (ClutterFlowLayout *self, gfloat avail_width, gfloat avail_height) { ClutterFlowLayoutPrivate *priv = self->priv; if (priv->orientation == CLUTTER_FLOW_HORIZONTAL) return get_columns (self, avail_width); else return get_rows (self, avail_height); } static void clutter_flow_layout_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv; gint n_rows, line_item_count, line_count; gfloat total_min_width, total_natural_width; gfloat line_min_width, line_natural_width; gfloat max_min_width, max_natural_width; ClutterActor *actor, *child; ClutterActorIter iter; gfloat item_y; n_rows = get_rows (CLUTTER_FLOW_LAYOUT (manager), for_height); total_min_width = 0; total_natural_width = 0; line_min_width = 0; line_natural_width = 0; line_item_count = 0; line_count = 0; item_y = 0; actor = CLUTTER_ACTOR (container); /* clear the line width arrays */ if (priv->line_min != NULL) g_array_free (priv->line_min, TRUE); if (priv->line_natural != NULL) g_array_free (priv->line_natural, TRUE); priv->line_min = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); priv->line_natural = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); if (clutter_actor_get_n_children (actor) != 0) line_count = 1; max_min_width = max_natural_width = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_min, child_natural; gfloat new_y, item_height; if (!clutter_actor_is_visible (child)) continue; if (priv->orientation == CLUTTER_FLOW_VERTICAL && for_height > 0) { clutter_actor_get_preferred_height (child, -1, &child_min, &child_natural); if ((priv->snap_to_grid && line_item_count == n_rows) || (!priv->snap_to_grid && item_y + child_natural > for_height)) { total_min_width += line_min_width; total_natural_width += line_natural_width; g_array_append_val (priv->line_min, line_min_width); g_array_append_val (priv->line_natural, line_natural_width); line_min_width = line_natural_width = 0; line_item_count = 0; line_count += 1; item_y = 0; } if (priv->snap_to_grid) { new_y = ((line_item_count + 1) * (for_height + priv->row_spacing)) / n_rows; item_height = new_y - item_y - priv->row_spacing; } else { new_y = item_y + child_natural + priv->row_spacing; item_height = child_natural; } clutter_actor_get_preferred_width (child, item_height, &child_min, &child_natural); line_min_width = MAX (line_min_width, child_min); line_natural_width = MAX (line_natural_width, child_natural); item_y = new_y; line_item_count += 1; max_min_width = MAX (max_min_width, line_min_width); max_natural_width = MAX (max_natural_width, line_natural_width); } else { clutter_actor_get_preferred_width (child, for_height, &child_min, &child_natural); max_min_width = MAX (max_min_width, child_min); max_natural_width = MAX (max_natural_width, child_natural); total_min_width += max_min_width; total_natural_width += max_natural_width; line_count += 1; } } priv->col_width = max_natural_width; if (priv->max_col_width > 0 && priv->col_width > priv->max_col_width) priv->col_width = MAX (priv->max_col_width, max_min_width); if (priv->col_width < priv->min_col_width) priv->col_width = priv->min_col_width; if (priv->orientation == CLUTTER_FLOW_VERTICAL && for_height > 0) { /* if we have a non-full row we need to add it */ if (line_item_count > 0) { total_min_width += line_min_width; total_natural_width += line_natural_width; g_array_append_val (priv->line_min, line_min_width); g_array_append_val (priv->line_natural, line_natural_width); } priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->col_spacing * (priv->line_count - 1); total_min_width += total_spacing; total_natural_width += total_spacing; } } else { g_array_append_val (priv->line_min, line_min_width); g_array_append_val (priv->line_natural, line_natural_width); priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->col_spacing * (priv->line_count - 1); total_min_width += total_spacing; total_natural_width += total_spacing; } } CLUTTER_NOTE (LAYOUT, "Flow[w]: %d lines (%d per line): w [ %.2f, %.2f ] for h %.2f", n_rows, priv->line_count, total_min_width, total_natural_width, for_height); priv->req_height = for_height; if (min_width_p) *min_width_p = max_min_width; if (nat_width_p) *nat_width_p = total_natural_width; } static void clutter_flow_layout_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv; gint n_columns, line_item_count, line_count; gfloat total_min_height, total_natural_height; gfloat line_min_height, line_natural_height; gfloat max_min_height, max_natural_height; ClutterActor *actor, *child; ClutterActorIter iter; gfloat item_x; n_columns = get_columns (CLUTTER_FLOW_LAYOUT (manager), for_width); total_min_height = 0; total_natural_height = 0; line_min_height = 0; line_natural_height = 0; line_item_count = 0; line_count = 0; item_x = 0; actor = CLUTTER_ACTOR (container); /* clear the line height arrays */ if (priv->line_min != NULL) g_array_free (priv->line_min, TRUE); if (priv->line_natural != NULL) g_array_free (priv->line_natural, TRUE); priv->line_min = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); priv->line_natural = g_array_sized_new (FALSE, FALSE, sizeof (gfloat), 16); if (clutter_actor_get_n_children (actor) != 0) line_count = 1; max_min_height = max_natural_height = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_min, child_natural; gfloat new_x, item_width; if (!clutter_actor_is_visible (child)) continue; if (priv->orientation == CLUTTER_FLOW_HORIZONTAL && for_width > 0) { clutter_actor_get_preferred_width (child, -1, &child_min, &child_natural); if ((priv->snap_to_grid && line_item_count == n_columns) || (!priv->snap_to_grid && item_x + child_natural > for_width)) { total_min_height += line_min_height; total_natural_height += line_natural_height; g_array_append_val (priv->line_min, line_min_height); g_array_append_val (priv->line_natural, line_natural_height); line_min_height = line_natural_height = 0; line_item_count = 0; line_count += 1; item_x = 0; } if (priv->snap_to_grid) { new_x = ((line_item_count + 1) * (for_width + priv->col_spacing)) / n_columns; item_width = new_x - item_x - priv->col_spacing; } else { new_x = item_x + child_natural + priv->col_spacing; item_width = child_natural; } clutter_actor_get_preferred_height (child, item_width, &child_min, &child_natural); line_min_height = MAX (line_min_height, child_min); line_natural_height = MAX (line_natural_height, child_natural); item_x = new_x; line_item_count += 1; max_min_height = MAX (max_min_height, line_min_height); max_natural_height = MAX (max_natural_height, line_natural_height); } else { clutter_actor_get_preferred_height (child, for_width, &child_min, &child_natural); max_min_height = MAX (max_min_height, child_min); max_natural_height = MAX (max_natural_height, child_natural); total_min_height += max_min_height; total_natural_height += max_natural_height; line_count += 1; } } priv->row_height = max_natural_height; if (priv->max_row_height > 0 && priv->row_height > priv->max_row_height) priv->row_height = MAX (priv->max_row_height, max_min_height); if (priv->row_height < priv->min_row_height) priv->row_height = priv->min_row_height; if (priv->orientation == CLUTTER_FLOW_HORIZONTAL && for_width > 0) { /* if we have a non-full row we need to add it */ if (line_item_count > 0) { total_min_height += line_min_height; total_natural_height += line_natural_height; g_array_append_val (priv->line_min, line_min_height); g_array_append_val (priv->line_natural, line_natural_height); } priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->row_spacing * (priv->line_count - 1); total_min_height += total_spacing; total_natural_height += total_spacing; } } else { g_array_append_val (priv->line_min, line_min_height); g_array_append_val (priv->line_natural, line_natural_height); priv->line_count = line_count; if (priv->line_count > 0) { gfloat total_spacing; total_spacing = priv->col_spacing * priv->line_count; total_min_height += total_spacing; total_natural_height += total_spacing; } } CLUTTER_NOTE (LAYOUT, "Flow[h]: %d lines (%d per line): w [ %.2f, %.2f ] for h %.2f", n_columns, priv->line_count, total_min_height, total_natural_height, for_width); priv->req_width = for_width; if (min_height_p) *min_height_p = max_min_height; if (nat_height_p) *nat_height_p = total_natural_height; } static void clutter_flow_layout_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv; ClutterActor *actor, *child; ClutterActorIter iter; gfloat x_off, y_off; gfloat avail_width, avail_height; gfloat item_x, item_y; gint line_item_count; gint items_per_line; gint line_index; actor = CLUTTER_ACTOR (container); if (clutter_actor_get_n_children (actor) == 0) return; clutter_actor_box_get_origin (allocation, &x_off, &y_off); clutter_actor_box_get_size (allocation, &avail_width, &avail_height); /* blow the cached preferred size and re-compute with the given * available size in case the FlowLayout wasn't given the exact * size it requested */ if ((priv->req_width >= 0 && avail_width != priv->req_width) || (priv->req_height >= 0 && avail_height != priv->req_height)) { clutter_flow_layout_get_preferred_width (manager, container, avail_height, NULL, NULL); clutter_flow_layout_get_preferred_height (manager, container, avail_width, NULL, NULL); } items_per_line = compute_lines (CLUTTER_FLOW_LAYOUT (manager), avail_width, avail_height); item_x = x_off; item_y = y_off; line_item_count = 0; line_index = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { ClutterActorBox child_alloc; gfloat item_width, item_height; gfloat new_x, new_y; gfloat child_min, child_natural; if (!clutter_actor_is_visible (child)) continue; new_x = new_y = 0; if (!priv->snap_to_grid) clutter_actor_get_preferred_size (child, NULL, NULL, &item_width, &item_height); if (priv->orientation == CLUTTER_FLOW_HORIZONTAL) { if ((priv->snap_to_grid && line_item_count == items_per_line && line_item_count > 0) || (!priv->snap_to_grid && item_x + item_width > avail_width)) { item_y += g_array_index (priv->line_natural, gfloat, line_index); if (line_index >= 0) item_y += priv->row_spacing; line_item_count = 0; line_index += 1; item_x = x_off; } if (priv->snap_to_grid) { new_x = x_off + ((line_item_count + 1) * (avail_width + priv->col_spacing)) / items_per_line; item_width = new_x - item_x - priv->col_spacing; } else { new_x = item_x + item_width + priv->col_spacing; } item_height = g_array_index (priv->line_natural, gfloat, line_index); } else { if ((priv->snap_to_grid && line_item_count == items_per_line && line_item_count > 0) || (!priv->snap_to_grid && item_y + item_height > avail_height)) { item_x += g_array_index (priv->line_natural, gfloat, line_index); if (line_index >= 0) item_x += priv->col_spacing; line_item_count = 0; line_index += 1; item_y = y_off; } if (priv->snap_to_grid) { new_y = y_off + ((line_item_count + 1) * (avail_height + priv->row_spacing)) / items_per_line; item_height = new_y - item_y - priv->row_spacing; } else { new_y = item_y + item_height + priv->row_spacing; } item_width = g_array_index (priv->line_natural, gfloat, line_index); } if (!priv->is_homogeneous && !clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL)) { clutter_actor_get_preferred_width (child, item_height, &child_min, &child_natural); item_width = MIN (item_width, child_natural); } if (!priv->is_homogeneous && !clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL)) { clutter_actor_get_preferred_height (child, item_width, &child_min, &child_natural); item_height = MIN (item_height, child_natural); } CLUTTER_NOTE (LAYOUT, "flow[line:%d, item:%d/%d] =" "{ %.2f, %.2f, %.2f, %.2f }", line_index, line_item_count + 1, items_per_line, item_x, item_y, item_width, item_height); child_alloc.x1 = ceil (item_x); child_alloc.y1 = ceil (item_y); child_alloc.x2 = ceil (child_alloc.x1 + item_width); child_alloc.y2 = ceil (child_alloc.y1 + item_height); clutter_actor_allocate (child, &child_alloc, flags); if (priv->orientation == CLUTTER_FLOW_HORIZONTAL) item_x = new_x; else item_y = new_y; line_item_count += 1; } } static void clutter_flow_layout_set_container (ClutterLayoutManager *manager, ClutterContainer *container) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv; ClutterLayoutManagerClass *parent_class; priv->container = container; if (priv->container != NULL) { ClutterRequestMode request_mode; /* we need to change the :request-mode of the container * to match the orientation */ request_mode = (priv->orientation == CLUTTER_FLOW_HORIZONTAL) ? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH : CLUTTER_REQUEST_WIDTH_FOR_HEIGHT; clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container), request_mode); } parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_flow_layout_parent_class); parent_class->set_container (manager, container); } static void clutter_flow_layout_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterFlowLayout *self = CLUTTER_FLOW_LAYOUT (gobject); switch (prop_id) { case PROP_ORIENTATION: clutter_flow_layout_set_orientation (self, g_value_get_enum (value)); break; case PROP_HOMOGENEOUS: clutter_flow_layout_set_homogeneous (self, g_value_get_boolean (value)); break; case PROP_COLUMN_SPACING: clutter_flow_layout_set_column_spacing (self, g_value_get_float (value)); break; case PROP_ROW_SPACING: clutter_flow_layout_set_row_spacing (self, g_value_get_float (value)); break; case PROP_MIN_COLUMN_WIDTH: clutter_flow_layout_set_column_width (self, g_value_get_float (value), self->priv->max_col_width); break; case PROP_MAX_COLUMN_WIDTH: clutter_flow_layout_set_column_width (self, self->priv->min_col_width, g_value_get_float (value)); break; case PROP_MIN_ROW_HEGHT: clutter_flow_layout_set_row_height (self, g_value_get_float (value), self->priv->max_row_height); break; case PROP_MAX_ROW_HEIGHT: clutter_flow_layout_set_row_height (self, self->priv->min_row_height, g_value_get_float (value)); break; case PROP_SNAP_TO_GRID: clutter_flow_layout_set_snap_to_grid (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_flow_layout_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (gobject)->priv; switch (prop_id) { case PROP_ORIENTATION: g_value_set_enum (value, priv->orientation); break; case PROP_HOMOGENEOUS: g_value_set_boolean (value, priv->is_homogeneous); break; case PROP_COLUMN_SPACING: g_value_set_float (value, priv->col_spacing); break; case PROP_ROW_SPACING: g_value_set_float (value, priv->row_spacing); break; case PROP_MIN_COLUMN_WIDTH: g_value_set_float (value, priv->min_col_width); break; case PROP_MAX_COLUMN_WIDTH: g_value_set_float (value, priv->max_col_width); break; case PROP_MIN_ROW_HEGHT: g_value_set_float (value, priv->min_row_height); break; case PROP_MAX_ROW_HEIGHT: g_value_set_float (value, priv->max_row_height); break; case PROP_SNAP_TO_GRID: g_value_set_boolean (value, priv->snap_to_grid); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_flow_layout_finalize (GObject *gobject) { ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (gobject)->priv; if (priv->line_min != NULL) g_array_free (priv->line_min, TRUE); if (priv->line_natural != NULL) g_array_free (priv->line_natural, TRUE); G_OBJECT_CLASS (clutter_flow_layout_parent_class)->finalize (gobject); } static void clutter_flow_layout_class_init (ClutterFlowLayoutClass *klass) { GObjectClass *gobject_class; ClutterLayoutManagerClass *layout_class; gobject_class = G_OBJECT_CLASS (klass); layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass); layout_class->get_preferred_width = clutter_flow_layout_get_preferred_width; layout_class->get_preferred_height = clutter_flow_layout_get_preferred_height; layout_class->allocate = clutter_flow_layout_allocate; layout_class->set_container = clutter_flow_layout_set_container; /** * ClutterFlowLayout:orientation: * * The orientation of the #ClutterFlowLayout. The children * of the layout will be layed out following the orientation. * * This property also controls the overflowing directions * * Since: 1.2 */ flow_properties[PROP_ORIENTATION] = g_param_spec_enum ("orientation", P_("Orientation"), P_("The orientation of the layout"), CLUTTER_TYPE_FLOW_ORIENTATION, CLUTTER_FLOW_HORIZONTAL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterFlowLayout:homogeneous: * * Whether each child inside the #ClutterFlowLayout should receive * the same allocation * * Since: 1.2 */ flow_properties[PROP_HOMOGENEOUS] = g_param_spec_boolean ("homogeneous", P_("Homogeneous"), P_("Whether each item should receive the same allocation"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterFlowLayout:column-spacing: * * The spacing between columns, in pixels; the value of this * property is honoured by horizontal non-overflowing layouts * and by vertical overflowing layouts * * Since: 1.2 */ flow_properties[PROP_COLUMN_SPACING] = g_param_spec_float ("column-spacing", P_("Column Spacing"), P_("The spacing between columns"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterFlowLayout:row-spacing: * * The spacing between rows, in pixels; the value of this * property is honoured by vertical non-overflowing layouts and * by horizontal overflowing layouts * * Since: 1.2 */ flow_properties[PROP_ROW_SPACING] = g_param_spec_float ("row-spacing", P_("Row Spacing"), P_("The spacing between rows"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterFlowLayout:min-column-width: * * Minimum width for each column in the layout, in pixels * * Since: 1.2 */ flow_properties[PROP_MIN_COLUMN_WIDTH] = g_param_spec_float ("min-column-width", P_("Minimum Column Width"), P_("Minimum width for each column"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterFlowLayout:max-column-width: * * Maximum width for each column in the layout, in pixels. If * set to -1 the width will be the maximum child width * * Since: 1.2 */ flow_properties[PROP_MAX_COLUMN_WIDTH] = g_param_spec_float ("max-column-width", P_("Maximum Column Width"), P_("Maximum width for each column"), -1.0, G_MAXFLOAT, -1.0, CLUTTER_PARAM_READWRITE); /** * ClutterFlowLayout:min-row-height: * * Minimum height for each row in the layout, in pixels * * Since: 1.2 */ flow_properties[PROP_MIN_ROW_HEGHT] = g_param_spec_float ("min-row-height", P_("Minimum Row Height"), P_("Minimum height for each row"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterFlowLayout:max-row-height: * * Maximum height for each row in the layout, in pixels. If * set to -1 the width will be the maximum child height * * Since: 1.2 */ flow_properties[PROP_MAX_ROW_HEIGHT] = g_param_spec_float ("max-row-height", P_("Maximum Row Height"), P_("Maximum height for each row"), -1.0, G_MAXFLOAT, -1.0, CLUTTER_PARAM_READWRITE); /** * ClutterFlowLayout:snap-to-grid: * * Whether the #ClutterFlowLayout should arrange its children * on a grid * * Since: 1.16 */ flow_properties[PROP_SNAP_TO_GRID] = g_param_spec_boolean ("snap-to-grid", P_("Snap to grid"), P_("Snap to grid"), TRUE, CLUTTER_PARAM_READWRITE); gobject_class->finalize = clutter_flow_layout_finalize; gobject_class->set_property = clutter_flow_layout_set_property; gobject_class->get_property = clutter_flow_layout_get_property; g_object_class_install_properties (gobject_class, N_PROPERTIES, flow_properties); } static void clutter_flow_layout_init (ClutterFlowLayout *self) { ClutterFlowLayoutPrivate *priv; self->priv = priv = clutter_flow_layout_get_instance_private (self); priv->orientation = CLUTTER_FLOW_HORIZONTAL; priv->col_spacing = 0; priv->row_spacing = 0; priv->min_col_width = priv->min_row_height = 0; priv->max_col_width = priv->max_row_height = -1; priv->line_min = NULL; priv->line_natural = NULL; priv->snap_to_grid = TRUE; } /** * clutter_flow_layout_new: * @orientation: the orientation of the flow layout * * Creates a new #ClutterFlowLayout with the given @orientation * * Return value: the newly created #ClutterFlowLayout * * Since: 1.2 */ ClutterLayoutManager * clutter_flow_layout_new (ClutterFlowOrientation orientation) { return g_object_new (CLUTTER_TYPE_FLOW_LAYOUT, "orientation", orientation, NULL); } /** * clutter_flow_layout_set_orientation: * @layout: a #ClutterFlowLayout * @orientation: the orientation of the layout * * Sets the orientation of the flow layout * * The orientation controls the direction used to allocate * the children: either horizontally or vertically. The * orientation also controls the direction of the overflowing * * Since: 1.2 */ void clutter_flow_layout_set_orientation (ClutterFlowLayout *layout, ClutterFlowOrientation orientation) { ClutterFlowLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); priv = layout->priv; if (priv->orientation != orientation) { ClutterLayoutManager *manager; priv->orientation = orientation; if (priv->container != NULL) { ClutterRequestMode request_mode; /* we need to change the :request-mode of the container * to match the orientation */ request_mode = (priv->orientation == CLUTTER_FLOW_HORIZONTAL) ? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH : CLUTTER_REQUEST_WIDTH_FOR_HEIGHT; clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container), request_mode); } manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_ORIENTATION]); } } /** * clutter_flow_layout_get_orientation: * @layout: a #ClutterFlowLayout * * Retrieves the orientation of the @layout * * Return value: the orientation of the #ClutterFlowLayout * * Since: 1.2 */ ClutterFlowOrientation clutter_flow_layout_get_orientation (ClutterFlowLayout *layout) { g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), CLUTTER_FLOW_HORIZONTAL); return layout->priv->orientation; } /** * clutter_flow_layout_set_homogeneous: * @layout: a #ClutterFlowLayout * @homogeneous: whether the layout should be homogeneous or not * * Sets whether the @layout should allocate the same space for * each child * * Since: 1.2 */ void clutter_flow_layout_set_homogeneous (ClutterFlowLayout *layout, gboolean homogeneous) { ClutterFlowLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); priv = layout->priv; if (priv->is_homogeneous != homogeneous) { ClutterLayoutManager *manager; priv->is_homogeneous = homogeneous; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_HOMOGENEOUS]); } } /** * clutter_flow_layout_get_homogeneous: * @layout: a #ClutterFlowLayout * * Retrieves whether the @layout is homogeneous * * Return value: %TRUE if the #ClutterFlowLayout is homogeneous * * Since: 1.2 */ gboolean clutter_flow_layout_get_homogeneous (ClutterFlowLayout *layout) { g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), FALSE); return layout->priv->is_homogeneous; } /** * clutter_flow_layout_set_column_spacing: * @layout: a #ClutterFlowLayout * @spacing: the space between columns * * Sets the space between columns, in pixels * * Since: 1.2 */ void clutter_flow_layout_set_column_spacing (ClutterFlowLayout *layout, gfloat spacing) { ClutterFlowLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); priv = layout->priv; if (priv->col_spacing != spacing) { ClutterLayoutManager *manager; priv->col_spacing = spacing; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_COLUMN_SPACING]); } } /** * clutter_flow_layout_get_column_spacing: * @layout: a #ClutterFlowLayout * * Retrieves the spacing between columns * * Return value: the spacing between columns of the #ClutterFlowLayout, * in pixels * * Since: 1.2 */ gfloat clutter_flow_layout_get_column_spacing (ClutterFlowLayout *layout) { g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), 0.0); return layout->priv->col_spacing; } /** * clutter_flow_layout_set_row_spacing: * @layout: a #ClutterFlowLayout * @spacing: the space between rows * * Sets the spacing between rows, in pixels * * Since: 1.2 */ void clutter_flow_layout_set_row_spacing (ClutterFlowLayout *layout, gfloat spacing) { ClutterFlowLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); priv = layout->priv; if (priv->row_spacing != spacing) { ClutterLayoutManager *manager; priv->row_spacing = spacing; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_ROW_SPACING]); } } /** * clutter_flow_layout_get_row_spacing: * @layout: a #ClutterFlowLayout * * Retrieves the spacing between rows * * Return value: the spacing between rows of the #ClutterFlowLayout, * in pixels * * Since: 1.2 */ gfloat clutter_flow_layout_get_row_spacing (ClutterFlowLayout *layout) { g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), 0.0); return layout->priv->row_spacing; } /** * clutter_flow_layout_set_column_width: * @layout: a #ClutterFlowLayout * @min_width: minimum width of a column * @max_width: maximum width of a column * * Sets the minimum and maximum widths that a column can have * * Since: 1.2 */ void clutter_flow_layout_set_column_width (ClutterFlowLayout *layout, gfloat min_width, gfloat max_width) { ClutterFlowLayoutPrivate *priv; gboolean notify_min = FALSE, notify_max = FALSE; g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); priv = layout->priv; if (priv->min_col_width != min_width) { priv->min_col_width = min_width; notify_min = TRUE; } if (priv->max_col_width != max_width) { priv->max_col_width = max_width; notify_max = TRUE; } g_object_freeze_notify (G_OBJECT (layout)); if (notify_min || notify_max) { ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); } if (notify_min) g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_MIN_COLUMN_WIDTH]); if (notify_max) g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_MAX_COLUMN_WIDTH]); g_object_thaw_notify (G_OBJECT (layout)); } /** * clutter_flow_layout_get_column_width: * @layout: a #ClutterFlowLayout * @min_width: (out): return location for the minimum column width, or %NULL * @max_width: (out): return location for the maximum column width, or %NULL * * Retrieves the minimum and maximum column widths * * Since: 1.2 */ void clutter_flow_layout_get_column_width (ClutterFlowLayout *layout, gfloat *min_width, gfloat *max_width) { g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); if (min_width) *min_width = layout->priv->min_col_width; if (max_width) *max_width = layout->priv->max_col_width; } /** * clutter_flow_layout_set_row_height: * @layout: a #ClutterFlowLayout * @min_height: the minimum height of a row * @max_height: the maximum height of a row * * Sets the minimum and maximum heights that a row can have * * Since: 1.2 */ void clutter_flow_layout_set_row_height (ClutterFlowLayout *layout, gfloat min_height, gfloat max_height) { ClutterFlowLayoutPrivate *priv; gboolean notify_min = FALSE, notify_max = FALSE; g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); priv = layout->priv; if (priv->min_row_height != min_height) { priv->min_row_height = min_height; notify_min = TRUE; } if (priv->max_row_height != max_height) { priv->max_row_height = max_height; notify_max = TRUE; } g_object_freeze_notify (G_OBJECT (layout)); if (notify_min || notify_max) { ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); } if (notify_min) g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_MIN_ROW_HEGHT]); if (notify_max) g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_MAX_ROW_HEIGHT]); g_object_thaw_notify (G_OBJECT (layout)); } /** * clutter_flow_layout_get_row_height: * @layout: a #ClutterFlowLayout * @min_height: (out): return location for the minimum row height, or %NULL * @max_height: (out): return location for the maximum row height, or %NULL * * Retrieves the minimum and maximum row heights * * Since: 1.2 */ void clutter_flow_layout_get_row_height (ClutterFlowLayout *layout, gfloat *min_height, gfloat *max_height) { g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); if (min_height) *min_height = layout->priv->min_row_height; if (max_height) *max_height = layout->priv->max_row_height; } /** * clutter_flow_layout_set_snap_to_grid: * @layout: a #ClutterFlowLayout * @snap_to_grid: %TRUE if @layout should place its children on a grid * * Whether the @layout should place its children on a grid. * * Since: 1.16 */ void clutter_flow_layout_set_snap_to_grid (ClutterFlowLayout *layout, gboolean snap_to_grid) { ClutterFlowLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout)); priv = layout->priv; if (priv->snap_to_grid != snap_to_grid) { priv->snap_to_grid = snap_to_grid; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); g_object_notify_by_pspec (G_OBJECT (layout), flow_properties[PROP_SNAP_TO_GRID]); } } /** * clutter_flow_layout_get_snap_to_grid: * @layout: a #ClutterFlowLayout * * Retrieves the value of #ClutterFlowLayout:snap-to-grid property * * Return value: %TRUE if the @layout is placing its children on a grid * * Since: 1.16 */ gboolean clutter_flow_layout_get_snap_to_grid (ClutterFlowLayout *layout) { g_return_val_if_fail (CLUTTER_IS_FLOW_LAYOUT (layout), FALSE); return layout->priv->snap_to_grid; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-master-clock.c�������������������������������������������������0000664�0001750�0001750�00000010263�14211404421�022512� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Emmanuele Bassi <ebassi@linux.intel.com> * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ /* * SECTION:clutter-master-clock * @short_description: The master clock for all animations * * The #ClutterMasterClock class is responsible for advancing all * #ClutterTimelines when a stage is being redrawn. The master clock * makes sure that the scenegraph is always integrally updated before * painting it. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-master-clock.h" #include "clutter-master-clock-default.h" #include "clutter-private.h" #define clutter_master_clock_get_type _clutter_master_clock_get_type typedef ClutterMasterClockIface ClutterMasterClockInterface; G_DEFINE_INTERFACE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT) static void clutter_master_clock_default_init (ClutterMasterClockInterface *iface) { } ClutterMasterClock * _clutter_master_clock_get_default (void) { ClutterMainContext *context = _clutter_context_get_default (); if (G_UNLIKELY (context->master_clock == NULL)) context->master_clock = g_object_new (CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, NULL); return context->master_clock; } /* * _clutter_master_clock_add_timeline: * @master_clock: a #ClutterMasterClock * @timeline: a #ClutterTimeline * * Adds @timeline to the list of playing timelines held by the master * clock. */ void _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock, ClutterTimeline *timeline) { g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->add_timeline (master_clock, timeline); } /* * _clutter_master_clock_remove_timeline: * @master_clock: a #ClutterMasterClock * @timeline: a #ClutterTimeline * * Removes @timeline from the list of playing timelines held by the * master clock. */ void _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, ClutterTimeline *timeline) { g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->remove_timeline (master_clock, timeline); } /* * _clutter_master_clock_start_running: * @master_clock: a #ClutterMasterClock * * Called when we have events or redraws to process; if the clock * is stopped, does the processing necessary to wake it up again. */ void _clutter_master_clock_start_running (ClutterMasterClock *master_clock) { g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->start_running (master_clock); } /** * _clutter_master_clock_ensure_next_iteration: * @master_clock: a #ClutterMasterClock * * Ensures that the master clock will run at least one iteration */ void _clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock) { g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->ensure_next_iteration (master_clock); } void _clutter_master_clock_set_paused (ClutterMasterClock *master_clock, gboolean paused) { g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->set_paused (master_clock, !!paused); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-blur-effect.c��������������������������������������������������0000664�0001750�0001750�00000020370�14211404421�022324� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-blur-effect * @short_description: A blur effect * @see_also: #ClutterEffect, #ClutterOffscreenEffect * * #ClutterBlurEffect is a sub-class of #ClutterEffect that allows blurring a * actor and its contents. * * #ClutterBlurEffect is available since Clutter 1.4 */ #define CLUTTER_BLUR_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BLUR_EFFECT, ClutterBlurEffectClass)) #define CLUTTER_IS_BLUR_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BLUR_EFFECT)) #define CLUTTER_BLUR_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BLUR_EFFECT, ClutterBlurEffectClass)) #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-blur-effect.h" #include "cogl/cogl.h" #include "clutter-debug.h" #include "clutter-offscreen-effect.h" #include "clutter-private.h" #define BLUR_PADDING 2 /* FIXME - lame shader; we should really have a decoupled * horizontal/vertical two pass shader for the gaussian blur */ static const gchar *box_blur_glsl_declarations = "uniform vec2 pixel_step;\n"; #define SAMPLE(offx, offy) \ "cogl_texel += texture2D (cogl_sampler, cogl_tex_coord.st + pixel_step * " \ "vec2 (" G_STRINGIFY (offx) ", " G_STRINGIFY (offy) "));\n" static const gchar *box_blur_glsl_shader = " cogl_texel = texture2D (cogl_sampler, cogl_tex_coord.st);\n" SAMPLE (-1.0, -1.0) SAMPLE ( 0.0, -1.0) SAMPLE (+1.0, -1.0) SAMPLE (-1.0, 0.0) SAMPLE (+1.0, 0.0) SAMPLE (-1.0, +1.0) SAMPLE ( 0.0, +1.0) SAMPLE (+1.0, +1.0) " cogl_texel /= 9.0;\n"; #undef SAMPLE struct _ClutterBlurEffect { ClutterOffscreenEffect parent_instance; /* a back pointer to our actor, so that we can query it */ ClutterActor *actor; gint pixel_step_uniform; gint tex_width; gint tex_height; CoglPipeline *pipeline; }; struct _ClutterBlurEffectClass { ClutterOffscreenEffectClass parent_class; CoglPipeline *base_pipeline; }; G_DEFINE_TYPE (ClutterBlurEffect, clutter_blur_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT); static gboolean clutter_blur_effect_pre_paint (ClutterEffect *effect) { ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect); ClutterEffectClass *parent_class; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) return FALSE; self->actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); if (self->actor == NULL) return FALSE; if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) { /* if we don't have support for GLSL shaders then we * forcibly disable the ActorMeta */ g_warning ("Unable to use the ShaderEffect: the graphics hardware " "or the current GL driver does not implement support " "for the GLSL shading language."); clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE); return FALSE; } parent_class = CLUTTER_EFFECT_CLASS (clutter_blur_effect_parent_class); if (parent_class->pre_paint (effect)) { ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect); CoglHandle texture; texture = clutter_offscreen_effect_get_texture (offscreen_effect); self->tex_width = cogl_texture_get_width (texture); self->tex_height = cogl_texture_get_height (texture); if (self->pixel_step_uniform > -1) { gfloat pixel_step[2]; pixel_step[0] = 1.0f / self->tex_width; pixel_step[1] = 1.0f / self->tex_height; cogl_pipeline_set_uniform_float (self->pipeline, self->pixel_step_uniform, 2, /* n_components */ 1, /* count */ pixel_step); } cogl_pipeline_set_layer_texture (self->pipeline, 0, texture); return TRUE; } else return FALSE; } static void clutter_blur_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect); guint8 paint_opacity; paint_opacity = clutter_actor_get_paint_opacity (self->actor); cogl_pipeline_set_color4ub (self->pipeline, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_push_source (self->pipeline); cogl_rectangle (0, 0, self->tex_width, self->tex_height); cogl_pop_source (); } static gboolean clutter_blur_effect_get_paint_volume (ClutterEffect *effect, ClutterPaintVolume *volume) { gfloat cur_width, cur_height; ClutterVertex origin; clutter_paint_volume_get_origin (volume, &origin); cur_width = clutter_paint_volume_get_width (volume); cur_height = clutter_paint_volume_get_height (volume); origin.x -= BLUR_PADDING; origin.y -= BLUR_PADDING; cur_width += 2 * BLUR_PADDING; cur_height += 2 * BLUR_PADDING; clutter_paint_volume_set_origin (volume, &origin); clutter_paint_volume_set_width (volume, cur_width); clutter_paint_volume_set_height (volume, cur_height); return TRUE; } static void clutter_blur_effect_dispose (GObject *gobject) { ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (gobject); if (self->pipeline != NULL) { cogl_object_unref (self->pipeline); self->pipeline = NULL; } G_OBJECT_CLASS (clutter_blur_effect_parent_class)->dispose (gobject); } static void clutter_blur_effect_class_init (ClutterBlurEffectClass *klass) { ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterOffscreenEffectClass *offscreen_class; gobject_class->dispose = clutter_blur_effect_dispose; effect_class->pre_paint = clutter_blur_effect_pre_paint; effect_class->get_paint_volume = clutter_blur_effect_get_paint_volume; offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class->paint_target = clutter_blur_effect_paint_target; } static void clutter_blur_effect_init (ClutterBlurEffect *self) { ClutterBlurEffectClass *klass = CLUTTER_BLUR_EFFECT_GET_CLASS (self); if (G_UNLIKELY (klass->base_pipeline == NULL)) { CoglSnippet *snippet; CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); klass->base_pipeline = cogl_pipeline_new (ctx); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, box_blur_glsl_declarations, NULL); cogl_snippet_set_replace (snippet, box_blur_glsl_shader); cogl_pipeline_add_layer_snippet (klass->base_pipeline, 0, snippet); cogl_object_unref (snippet); cogl_pipeline_set_layer_null_texture (klass->base_pipeline, 0, /* layer number */ COGL_TEXTURE_TYPE_2D); } self->pipeline = cogl_pipeline_copy (klass->base_pipeline); self->pixel_step_uniform = cogl_pipeline_get_uniform_location (self->pipeline, "pixel_step"); } /** * clutter_blur_effect_new: * * Creates a new #ClutterBlurEffect to be used with * clutter_actor_add_effect() * * Return value: the newly created #ClutterBlurEffect or %NULL * * Since: 1.4 */ ClutterEffect * clutter_blur_effect_new (void) { return g_object_new (CLUTTER_TYPE_BLUR_EFFECT, NULL); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-drop-action.h��������������������������������������������������0000664�0001750�0001750�00000007645�14211404421�022364� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_DROP_ACTION_H__ #define __CLUTTER_DROP_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be directly included." #endif #include <clutter/clutter-action.h> G_BEGIN_DECLS #define CLUTTER_TYPE_DROP_ACTION (clutter_drop_action_get_type ()) #define CLUTTER_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropAction)) #define CLUTTER_IS_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DROP_ACTION)) #define CLUTTER_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass)) #define CLUTTER_IS_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DROP_ACTION)) #define CLUTTER_DROP_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass)) typedef struct _ClutterDropAction ClutterDropAction; typedef struct _ClutterDropActionPrivate ClutterDropActionPrivate; typedef struct _ClutterDropActionClass ClutterDropActionClass; /** * ClutterDropAction: * * The #ClutterDropAction structure contains only * private data and should be accessed using the provided API. * * Since: 1.8 */ struct _ClutterDropAction { /*< private >*/ ClutterAction parent_instance; ClutterDropActionPrivate *priv; }; /** * ClutterDropActionClass: * @can_drop: class handler for the #ClutterDropAction::can-drop signal * @over_in: class handler for the #ClutterDropAction::over-in signal * @over_out: class handler for the #ClutterDropAction::over-out signal * @drop: class handler for the #ClutterDropAction::drop signal * * The #ClutterDropActionClass structure contains * only private data. * * Since: 1.8 */ struct _ClutterDropActionClass { /*< private >*/ ClutterActionClass parent_class; /*< public >*/ gboolean (* can_drop) (ClutterDropAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y); void (* over_in) (ClutterDropAction *action, ClutterActor *actor); void (* over_out) (ClutterDropAction *action, ClutterActor *actor); void (* drop) (ClutterDropAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y); /*< private >*/ void (*_clutter_drop_action1) (void); void (*_clutter_drop_action2) (void); void (*_clutter_drop_action3) (void); void (*_clutter_drop_action4) (void); void (*_clutter_drop_action5) (void); void (*_clutter_drop_action6) (void); void (*_clutter_drop_action7) (void); void (*_clutter_drop_action8) (void); }; CLUTTER_AVAILABLE_IN_1_8 GType clutter_drop_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_8 ClutterAction * clutter_drop_action_new (void); G_END_DECLS #endif /* __CLUTTER_DROP_ACTION_H__ */ �������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-stage-manager-private.h����������������������������������������0000664�0001750�0001750�00000003142�14211404421�024314� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_STAGE_MANAGER_PRIVATE_H__ #define __CLUTTER_STAGE_MANAGER_PRIVATE_H__ #include <clutter/clutter-stage-manager.h> G_BEGIN_DECLS struct _ClutterStageManager { GObject parent_instance; GSList *stages; }; /* stage manager */ void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager, ClutterStage *stage); void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager, ClutterStage *stage); void _clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manager, ClutterStage *stage); G_END_DECLS #endif /* __CLUTTER_STAGE_MANAGER_PRIVATE_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-actor.h��������������������������������������������������������0000664�0001750�0001750�00000164523�14211404421�021254� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_ACTOR_H__ #define __CLUTTER_ACTOR_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif /* clutter-actor.h */ #include <gio/gio.h> #include <pango/pango.h> #include <atk/atk.h> #include <cogl/cogl.h> #include <clutter/clutter-types.h> #include <clutter/clutter-event.h> G_BEGIN_DECLS #define CLUTTER_TYPE_ACTOR (clutter_actor_get_type ()) #define CLUTTER_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTOR, ClutterActor)) #define CLUTTER_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTOR, ClutterActorClass)) #define CLUTTER_IS_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTOR)) #define CLUTTER_IS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTOR)) #define CLUTTER_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTOR, ClutterActorClass)) /** * CLUTTER_ACTOR_SET_FLAGS: * @a: a #ClutterActor * @f: the #ClutterActorFlags to set * * Sets the given flags on a #ClutterActor * * Deprecated: 1.24: Changing flags directly is heavily discouraged in * newly written code. #ClutterActor will take care of setting the * internal state. */ #define CLUTTER_ACTOR_SET_FLAGS(a,f) \ CLUTTER_MACRO_DEPRECATED_IN_1_24 \ (((ClutterActor*)(a))->flags |= (f)) /** * CLUTTER_ACTOR_UNSET_FLAGS: * @a: a #ClutterActor * @f: the #ClutterActorFlags to unset * * Unsets the given flags on a #ClutterActor * * Deprecated: 1.24: Changing flags directly is heavily discouraged in * newly written code. #ClutterActor will take care of unsetting the * internal state. */ #define CLUTTER_ACTOR_UNSET_FLAGS(a,f) \ CLUTTER_MACRO_DEPRECATED_IN_1_24 \ (((ClutterActor*)(a))->flags &= ~(f)) #define CLUTTER_ACTOR_IS_MAPPED(a) \ CLUTTER_MACRO_DEPRECATED_IN_1_24_FOR ("Deprecated macro. Use clutter_actor_is_mapped instead") \ ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_MAPPED) != FALSE) #define CLUTTER_ACTOR_IS_REALIZED(a) \ CLUTTER_MACRO_DEPRECATED_IN_1_24_FOR ("Deprecated macro. Use clutter_actor_is_realized instead") \ ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_REALIZED) != FALSE) #define CLUTTER_ACTOR_IS_VISIBLE(a) \ CLUTTER_MACRO_DEPRECATED_IN_1_24_FOR ("Deprecated macro. Use clutter_actor_is_visible instead") \ ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_VISIBLE) != FALSE) #define CLUTTER_ACTOR_IS_REACTIVE(a) \ CLUTTER_MACRO_DEPRECATED_IN_1_24_FOR ("Deprecated macro. Use clutter_actor_get_reactive instead") \ ((((ClutterActor*)(a))->flags & CLUTTER_ACTOR_REACTIVE) != FALSE) typedef struct _ClutterActorClass ClutterActorClass; typedef struct _ClutterActorPrivate ClutterActorPrivate; /** * ClutterCallback: * @actor: a #ClutterActor * @data: (closure): user data * * Generic callback */ typedef void (*ClutterCallback) (ClutterActor *actor, gpointer data); /** * CLUTTER_CALLBACK: * @f: a function * * Convenience macro to cast a function to #ClutterCallback */ #define CLUTTER_CALLBACK(f) ((ClutterCallback) (f)) /** * ClutterActor: * @flags: #ClutterActorFlags * * Base class for actors. */ struct _ClutterActor { /*< private >*/ GInitiallyUnowned parent_instance; /*< public >*/ guint32 flags; /*< private >*/ guint32 private_flags; ClutterActorPrivate *priv; }; /** * ClutterActorClass: * @show: signal class handler for #ClutterActor::show; it must chain * up to the parent's implementation * @show_all: virtual function for containers and composite actors, to * determine which children should be shown when calling * clutter_actor_show_all() on the actor. Defaults to calling * clutter_actor_show(). This virtual function is deprecated and it * should not be overridden. * @hide: signal class handler for #ClutterActor::hide; it must chain * up to the parent's implementation * @hide_all: virtual function for containers and composite actors, to * determine which children should be shown when calling * clutter_actor_hide_all() on the actor. Defaults to calling * clutter_actor_hide(). This virtual function is deprecated and it * should not be overridden. * @realize: virtual function, used to allocate resources for the actor; * it should chain up to the parent's implementation. This virtual * function is deprecated and should not be overridden in newly * written code. * @unrealize: virtual function, used to deallocate resources allocated * in ::realize; it should chain up to the parent's implementation. This * function is deprecated and should not be overridden in newly * written code. * @map: virtual function for containers and composite actors, to * map their children; it must chain up to the parent's implementation. * Overriding this function is optional. * @unmap: virtual function for containers and composite actors, to * unmap their children; it must chain up to the parent's implementation. * Overriding this function is optional. * @paint: virtual function, used to paint the actor * @get_preferred_width: virtual function, used when querying the minimum * and natural widths of an actor for a given height; it is used by * clutter_actor_get_preferred_width() * @get_preferred_height: virtual function, used when querying the minimum * and natural heights of an actor for a given width; it is used by * clutter_actor_get_preferred_height() * @allocate: virtual function, used when settings the coordinates of an * actor; it is used by clutter_actor_allocate(); it must chain up to * the parent's implementation, or call clutter_actor_set_allocation() * @apply_transform: virtual function, used when applying the transformations * to an actor before painting it or when transforming coordinates or * the allocation; it must chain up to the parent's implementation * @parent_set: signal class handler for the #ClutterActor::parent-set * @destroy: signal class handler for #ClutterActor::destroy. It must * chain up to the parent's implementation * @pick: virtual function, used to draw an outline of the actor with * the given color * @queue_redraw: class handler for #ClutterActor::queue-redraw * @event: class handler for #ClutterActor::event * @button_press_event: class handler for #ClutterActor::button-press-event * @button_release_event: class handler for * #ClutterActor::button-release-event * @scroll_event: signal class closure for #ClutterActor::scroll-event * @key_press_event: signal class closure for #ClutterActor::key-press-event * @key_release_event: signal class closure for * #ClutterActor::key-release-event * @motion_event: signal class closure for #ClutterActor::motion-event * @enter_event: signal class closure for #ClutterActor::enter-event * @leave_event: signal class closure for #ClutterActor::leave-event * @captured_event: signal class closure for #ClutterActor::captured-event * @key_focus_in: signal class closure for #ClutterActor::key-focus-in * @key_focus_out: signal class closure for #ClutterActor::key-focus-out * @queue_relayout: class handler for #ClutterActor::queue-relayout * @get_accessible: virtual function, returns the accessible object that * describes the actor to an assistive technology. * @get_paint_volume: virtual function, for sub-classes to define their * #ClutterPaintVolume * @has_overlaps: virtual function for * sub-classes to advertise whether they need an offscreen redirect * to get the correct opacity. See * clutter_actor_set_offscreen_redirect() for details. * @paint_node: virtual function for creating paint nodes and attaching * them to the render tree * @touch_event: signal class closure for #ClutterActor::touch-event * * Base class for actors. */ struct _ClutterActorClass { /*< private >*/ GInitiallyUnownedClass parent_class; /*< public >*/ void (* show) (ClutterActor *self); void (* show_all) (ClutterActor *self); void (* hide) (ClutterActor *self); void (* hide_all) (ClutterActor *self); void (* realize) (ClutterActor *self); void (* unrealize) (ClutterActor *self); void (* map) (ClutterActor *self); void (* unmap) (ClutterActor *self); void (* paint) (ClutterActor *self); void (* parent_set) (ClutterActor *actor, ClutterActor *old_parent); void (* destroy) (ClutterActor *self); void (* pick) (ClutterActor *actor, const ClutterColor *color); void (* queue_redraw) (ClutterActor *actor, ClutterActor *leaf_that_queued); /* size negotiation */ void (* get_preferred_width) (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p); void (* get_preferred_height) (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p); void (* allocate) (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags); /* transformations */ void (* apply_transform) (ClutterActor *actor, ClutterMatrix *matrix); /* event signals */ gboolean (* event) (ClutterActor *actor, ClutterEvent *event); gboolean (* button_press_event) (ClutterActor *actor, ClutterButtonEvent *event); gboolean (* button_release_event) (ClutterActor *actor, ClutterButtonEvent *event); gboolean (* scroll_event) (ClutterActor *actor, ClutterScrollEvent *event); gboolean (* key_press_event) (ClutterActor *actor, ClutterKeyEvent *event); gboolean (* key_release_event) (ClutterActor *actor, ClutterKeyEvent *event); gboolean (* motion_event) (ClutterActor *actor, ClutterMotionEvent *event); gboolean (* enter_event) (ClutterActor *actor, ClutterCrossingEvent *event); gboolean (* leave_event) (ClutterActor *actor, ClutterCrossingEvent *event); gboolean (* captured_event) (ClutterActor *actor, ClutterEvent *event); void (* key_focus_in) (ClutterActor *actor); void (* key_focus_out) (ClutterActor *actor); void (* queue_relayout) (ClutterActor *self); /* accessibility support */ AtkObject * (* get_accessible) (ClutterActor *self); gboolean (* get_paint_volume) (ClutterActor *actor, ClutterPaintVolume *volume); gboolean (* has_overlaps) (ClutterActor *self); void (* paint_node) (ClutterActor *self, ClutterPaintNode *root); gboolean (* touch_event) (ClutterActor *self, ClutterTouchEvent *event); /*< private >*/ /* padding for future expansion */ gpointer _padding_dummy[26]; }; /** * ClutterActorIter: * * An iterator structure that allows to efficiently iterate over a * section of the scene graph. * * The contents of the #ClutterActorIter structure * are private and should only be accessed using the provided API. * * Since: 1.10 */ struct _ClutterActorIter { /*< private >*/ gpointer CLUTTER_PRIVATE_FIELD (dummy1); gpointer CLUTTER_PRIVATE_FIELD (dummy2); gpointer CLUTTER_PRIVATE_FIELD (dummy3); gint CLUTTER_PRIVATE_FIELD (dummy4); gpointer CLUTTER_PRIVATE_FIELD (dummy5); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_actor_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_actor_new (void); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_flags (ClutterActor *self, ClutterActorFlags flags); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_unset_flags (ClutterActor *self, ClutterActorFlags flags); CLUTTER_AVAILABLE_IN_ALL ClutterActorFlags clutter_actor_get_flags (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_show (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_hide (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_realize (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_unrealize (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_map (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_unmap (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_paint (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_continue_paint (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_queue_redraw (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_queue_redraw_with_clip (ClutterActor *self, const cairo_rectangle_int_t *clip); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_queue_relayout (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_destroy (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_name (ClutterActor *self, const gchar *name); CLUTTER_AVAILABLE_IN_ALL const gchar * clutter_actor_get_name (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL AtkObject * clutter_actor_get_accessible (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_24 gboolean clutter_actor_is_visible (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_24 gboolean clutter_actor_is_mapped (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_24 gboolean clutter_actor_is_realized (ClutterActor *self); /* Size negotiation */ CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_request_mode (ClutterActor *self, ClutterRequestMode mode); CLUTTER_AVAILABLE_IN_ALL ClutterRequestMode clutter_actor_get_request_mode (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_preferred_size (ClutterActor *self, gfloat *min_width_p, gfloat *min_height_p, gfloat *natural_width_p, gfloat *natural_height_p); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_allocate_preferred_size (ClutterActor *self, ClutterAllocationFlags flags); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_allocate_available_size (ClutterActor *self, gfloat x, gfloat y, gfloat available_width, gfloat available_height, ClutterAllocationFlags flags); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_allocate_align_fill (ClutterActor *self, const ClutterActorBox *box, gdouble x_align, gdouble y_align, gboolean x_fill, gboolean y_fill, ClutterAllocationFlags flags); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_allocation (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_allocation_box (ClutterActor *self, ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_allocation_vertices (ClutterActor *self, ClutterActor *ancestor, ClutterVertex verts[]); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_has_allocation (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_size (ClutterActor *self, gfloat width, gfloat height); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_size (ClutterActor *self, gfloat *width, gfloat *height); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_position (ClutterActor *self, gfloat x, gfloat y); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_position (ClutterActor *self, gfloat *x, gfloat *y); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_get_fixed_position_set (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_fixed_position_set (ClutterActor *self, gboolean is_set); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_move_by (ClutterActor *self, gfloat dx, gfloat dy); /* Actor geometry */ CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_get_width (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_get_height (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_width (ClutterActor *self, gfloat width); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_height (ClutterActor *self, gfloat height); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_get_x (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_get_y (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_x (ClutterActor *self, gfloat x); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_y (ClutterActor *self, gfloat y); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_z_position (ClutterActor *self, gfloat z_position); CLUTTER_AVAILABLE_IN_1_12 gfloat clutter_actor_get_z_position (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_layout_manager (ClutterActor *self, ClutterLayoutManager *manager); CLUTTER_AVAILABLE_IN_1_10 ClutterLayoutManager * clutter_actor_get_layout_manager (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_x_align (ClutterActor *self, ClutterActorAlign x_align); CLUTTER_AVAILABLE_IN_1_10 ClutterActorAlign clutter_actor_get_x_align (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_y_align (ClutterActor *self, ClutterActorAlign y_align); CLUTTER_AVAILABLE_IN_1_10 ClutterActorAlign clutter_actor_get_y_align (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_margin_top (ClutterActor *self, gfloat margin); CLUTTER_AVAILABLE_IN_1_10 gfloat clutter_actor_get_margin_top (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_margin_bottom (ClutterActor *self, gfloat margin); CLUTTER_AVAILABLE_IN_1_10 gfloat clutter_actor_get_margin_bottom (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_margin_left (ClutterActor *self, gfloat margin); CLUTTER_AVAILABLE_IN_1_10 gfloat clutter_actor_get_margin_left (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_margin_right (ClutterActor *self, gfloat margin); CLUTTER_AVAILABLE_IN_1_10 gfloat clutter_actor_get_margin_right (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_margin (ClutterActor *self, const ClutterMargin *margin); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_get_margin (ClutterActor *self, ClutterMargin *margin); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_x_expand (ClutterActor *self, gboolean expand); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_actor_get_x_expand (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_y_expand (ClutterActor *self, gboolean expand); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_actor_get_y_expand (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_actor_needs_expand (ClutterActor *self, ClutterOrientation orientation); /* Paint */ CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_clip (ClutterActor *self, gfloat xoff, gfloat yoff, gfloat width, gfloat height); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_remove_clip (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_has_clip (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_clip (ClutterActor *self, gfloat *xoff, gfloat *yoff, gfloat *width, gfloat *height); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_clip_to_allocation (ClutterActor *self, gboolean clip_set); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_get_clip_to_allocation (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_opacity (ClutterActor *self, guint8 opacity); CLUTTER_AVAILABLE_IN_ALL guint8 clutter_actor_get_opacity (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL guint8 clutter_actor_get_paint_opacity (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_get_paint_visibility (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_8 void clutter_actor_set_offscreen_redirect (ClutterActor *self, ClutterOffscreenRedirect redirect); CLUTTER_AVAILABLE_IN_1_8 ClutterOffscreenRedirect clutter_actor_get_offscreen_redirect (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_should_pick_paint (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_is_in_clone_paint (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_get_paint_box (ClutterActor *self, ClutterActorBox *box); CLUTTER_AVAILABLE_IN_1_8 gboolean clutter_actor_has_overlaps (ClutterActor *self); /* Content */ CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_content (ClutterActor *self, ClutterContent *content); CLUTTER_AVAILABLE_IN_1_10 ClutterContent * clutter_actor_get_content (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_content_gravity (ClutterActor *self, ClutterContentGravity gravity); CLUTTER_AVAILABLE_IN_1_10 ClutterContentGravity clutter_actor_get_content_gravity (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_content_scaling_filters (ClutterActor *self, ClutterScalingFilter min_filter, ClutterScalingFilter mag_filter); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_get_content_scaling_filters (ClutterActor *self, ClutterScalingFilter *min_filter, ClutterScalingFilter *mag_filter); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_content_repeat (ClutterActor *self, ClutterContentRepeat repeat); CLUTTER_AVAILABLE_IN_1_12 ClutterContentRepeat clutter_actor_get_content_repeat (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_get_content_box (ClutterActor *self, ClutterActorBox *box); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_background_color (ClutterActor *self, const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_get_background_color (ClutterActor *self, ClutterColor *color); CLUTTER_AVAILABLE_IN_1_6 const ClutterPaintVolume * clutter_actor_get_paint_volume (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_6 const ClutterPaintVolume * clutter_actor_get_transformed_paint_volume (ClutterActor *self, ClutterActor *relative_to_ancestor); CLUTTER_AVAILABLE_IN_1_10 const ClutterPaintVolume * clutter_actor_get_default_paint_volume (ClutterActor *self); /* Events */ CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_reactive (ClutterActor *actor, gboolean reactive); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_get_reactive (ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_has_key_focus (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_grab_key_focus (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_event (ClutterActor *actor, const ClutterEvent *event, gboolean capture); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_has_pointer (ClutterActor *self); /* Text */ CLUTTER_AVAILABLE_IN_ALL PangoContext * clutter_actor_get_pango_context (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL PangoContext * clutter_actor_create_pango_context (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL PangoLayout * clutter_actor_create_pango_layout (ClutterActor *self, const gchar *text); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_text_direction (ClutterActor *self, ClutterTextDirection text_dir); CLUTTER_AVAILABLE_IN_ALL ClutterTextDirection clutter_actor_get_text_direction (ClutterActor *self); /* Actor hierarchy */ CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_add_child (ClutterActor *self, ClutterActor *child); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_insert_child_at_index (ClutterActor *self, ClutterActor *child, gint index_); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_insert_child_above (ClutterActor *self, ClutterActor *child, ClutterActor *sibling); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_insert_child_below (ClutterActor *self, ClutterActor *child, ClutterActor *sibling); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_replace_child (ClutterActor *self, ClutterActor *old_child, ClutterActor *new_child); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_remove_child (ClutterActor *self, ClutterActor *child); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_remove_all_children (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_destroy_all_children (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 GList * clutter_actor_get_children (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 gint clutter_actor_get_n_children (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_actor_get_child_at_index (ClutterActor *self, gint index_); CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_actor_get_previous_sibling (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_actor_get_next_sibling (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_actor_get_first_child (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_actor_get_last_child (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_actor_get_parent (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_4 gboolean clutter_actor_contains (ClutterActor *self, ClutterActor *descendant); CLUTTER_AVAILABLE_IN_ALL ClutterActor* clutter_actor_get_stage (ClutterActor *actor); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_child_below_sibling (ClutterActor *self, ClutterActor *child, ClutterActor *sibling); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_child_above_sibling (ClutterActor *self, ClutterActor *child, ClutterActor *sibling); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_child_at_index (ClutterActor *self, ClutterActor *child, gint index_); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_iter_init (ClutterActorIter *iter, ClutterActor *root); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_actor_iter_next (ClutterActorIter *iter, ClutterActor **child); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_actor_iter_prev (ClutterActorIter *iter, ClutterActor **child); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_iter_remove (ClutterActorIter *iter); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_iter_destroy (ClutterActorIter *iter); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_actor_iter_is_valid (const ClutterActorIter *iter); /* Transformations */ CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_is_rotated (ClutterActor *self); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_is_scaled (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_pivot_point (ClutterActor *self, gfloat pivot_x, gfloat pivot_y); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_get_pivot_point (ClutterActor *self, gfloat *pivot_x, gfloat *pivot_y); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_pivot_point_z (ClutterActor *self, gfloat pivot_z); CLUTTER_AVAILABLE_IN_1_12 gfloat clutter_actor_get_pivot_point_z (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_rotation_angle (ClutterActor *self, ClutterRotateAxis axis, gdouble angle); CLUTTER_AVAILABLE_IN_1_12 gdouble clutter_actor_get_rotation_angle (ClutterActor *self, ClutterRotateAxis axis); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_set_scale (ClutterActor *self, gdouble scale_x, gdouble scale_y); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_scale (ClutterActor *self, gdouble *scale_x, gdouble *scale_y); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_scale_z (ClutterActor *self, gdouble scale_z); CLUTTER_AVAILABLE_IN_1_12 gdouble clutter_actor_get_scale_z (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_translation (ClutterActor *self, gfloat translate_x, gfloat translate_y, gfloat translate_z); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_get_translation (ClutterActor *self, gfloat *translate_x, gfloat *translate_y, gfloat *translate_z); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_transform (ClutterActor *self, const ClutterMatrix *transform); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_get_transform (ClutterActor *self, ClutterMatrix *transform); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_set_child_transform (ClutterActor *self, const ClutterMatrix *transform); CLUTTER_AVAILABLE_IN_1_12 void clutter_actor_get_child_transform (ClutterActor *self, ClutterMatrix *transform); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_transformed_position (ClutterActor *self, gfloat *x, gfloat *y); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_transformed_size (ClutterActor *self, gfloat *width, gfloat *height); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_transform_stage_point (ClutterActor *self, gfloat x, gfloat y, gfloat *x_out, gfloat *y_out); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_get_abs_allocation_vertices (ClutterActor *self, ClutterVertex verts[]); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_apply_transform_to_point (ClutterActor *self, const ClutterVertex *point, ClutterVertex *vertex); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_apply_relative_transform_to_point (ClutterActor *self, ClutterActor *ancestor, const ClutterVertex *point, ClutterVertex *vertex); /* Implicit animations */ CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_save_easing_state (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_restore_easing_state (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_easing_mode (ClutterActor *self, ClutterAnimationMode mode); CLUTTER_AVAILABLE_IN_1_10 ClutterAnimationMode clutter_actor_get_easing_mode (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_easing_duration (ClutterActor *self, guint msecs); CLUTTER_AVAILABLE_IN_1_10 guint clutter_actor_get_easing_duration (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_set_easing_delay (ClutterActor *self, guint msecs); CLUTTER_AVAILABLE_IN_1_10 guint clutter_actor_get_easing_delay (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 ClutterTransition * clutter_actor_get_transition (ClutterActor *self, const char *name); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_add_transition (ClutterActor *self, const char *name, ClutterTransition *transition); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_remove_transition (ClutterActor *self, const char *name); CLUTTER_AVAILABLE_IN_1_10 void clutter_actor_remove_all_transitions (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_16 gboolean clutter_actor_has_mapped_clones (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_22 void clutter_actor_set_opacity_override (ClutterActor *self, gint opacity); CLUTTER_AVAILABLE_IN_1_22 gint clutter_actor_get_opacity_override (ClutterActor *self); /** * ClutterActorCreateChildFunc: * @item: (type GObject): the item in the model * @user_data: Data passed to clutter_actor_bind_model() * * Creates a #ClutterActor using the @item in the model. * * The usual way to implement this function is to create a #ClutterActor * instance and then bind the #GObject properties to the actor properties * of interest, using g_object_bind_property(). This way, when the @item * in the #GListModel changes, the #ClutterActor changes as well. * * Returns: (transfer full): The newly created child #ClutterActor * * Since: 1.24 */ typedef ClutterActor * (* ClutterActorCreateChildFunc) (gpointer item, gpointer user_data); CLUTTER_AVAILABLE_IN_1_24 void clutter_actor_bind_model (ClutterActor *self, GListModel *model, ClutterActorCreateChildFunc create_child_func, gpointer user_data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_24 void clutter_actor_bind_model_with_properties (ClutterActor *self, GListModel *model, GType child_type, const char *first_model_property, ...); G_END_DECLS #endif /* __CLUTTER_ACTOR_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-zoom-action.c��������������������������������������������������0000664�0001750�0001750�00000036450�14211404421�022373� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com> */ /** * SECTION:clutter-zoom-action * @Title: ClutterZoomAction * @Short_Description: Action enabling zooming on actors * * #ClutterZoomAction is a sub-class of #ClutterGestureAction that * implements all the necessary logic for zooming actors using a "pinch" * gesture between two touch points. * * The simplest usage of #ClutterZoomAction consists in adding it to * a #ClutterActor and setting it as reactive; for instance, the following * code: * * |[ * clutter_actor_add_action (actor, clutter_zoom_action_new ()); * clutter_actor_set_reactive (actor, TRUE); * ]| * * will automatically result in the actor to be scale according to the * distance between two touch points. * * Since: 1.12 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter-zoom-action.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-gesture-action-private.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-stage-private.h" typedef struct { gfloat start_x; gfloat start_y; gfloat transformed_start_x; gfloat transformed_start_y; gfloat update_x; gfloat update_y; gfloat transformed_update_x; gfloat transformed_update_y; } ZoomPoint; struct _ClutterZoomActionPrivate { ClutterStage *stage; ClutterZoomAxis zoom_axis; ZoomPoint points[2]; ClutterPoint initial_focal_point; ClutterPoint focal_point; ClutterPoint transformed_focal_point; gfloat initial_x; gfloat initial_y; gfloat initial_z; gdouble initial_scale_x; gdouble initial_scale_y; gdouble zoom_initial_distance; }; enum { PROP_0, PROP_ZOOM_AXIS, PROP_LAST }; static GParamSpec *zoom_props[PROP_LAST] = { NULL, }; enum { ZOOM, LAST_SIGNAL }; static guint zoom_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterZoomAction, clutter_zoom_action, CLUTTER_TYPE_GESTURE_ACTION) static void capture_point_initial_position (ClutterGestureAction *action, ClutterActor *actor, gint index, ZoomPoint *point) { clutter_gesture_action_get_motion_coords (action, index, &point->start_x, &point->start_y); point->transformed_start_x = point->update_x = point->start_x; point->transformed_start_y = point->update_x = point->start_y; clutter_actor_transform_stage_point (actor, point->start_x, point->start_y, &point->transformed_start_x, &point->transformed_start_y); point->transformed_update_x = point->transformed_start_x; point->transformed_update_y = point->transformed_start_y; } static void capture_point_update_position (ClutterGestureAction *action, ClutterActor *actor, gint index, ZoomPoint *point) { clutter_gesture_action_get_motion_coords (action, index, &point->update_x, &point->update_y); point->transformed_update_x = point->update_x; point->transformed_update_y = point->update_y; clutter_actor_transform_stage_point (actor, point->update_x, point->update_y, &point->transformed_update_x, &point->transformed_update_y); } static gboolean clutter_zoom_action_gesture_begin (ClutterGestureAction *action, ClutterActor *actor) { ClutterZoomActionPrivate *priv = ((ClutterZoomAction *) action)->priv; gfloat dx, dy; capture_point_initial_position (action, actor, 0, &priv->points[0]); capture_point_initial_position (action, actor, 1, &priv->points[1]); dx = priv->points[1].transformed_start_x - priv->points[0].transformed_start_x; dy = priv->points[1].transformed_start_y - priv->points[0].transformed_start_y; priv->zoom_initial_distance = sqrt (dx * dx + dy * dy); clutter_actor_get_translation (actor, &priv->initial_x, &priv->initial_y, &priv->initial_z); clutter_actor_get_scale (actor, &priv->initial_scale_x, &priv->initial_scale_y); priv->initial_focal_point.x = (priv->points[0].start_x + priv->points[1].start_x) / 2; priv->initial_focal_point.y = (priv->points[0].start_y + priv->points[1].start_y) / 2; clutter_actor_transform_stage_point (actor, priv->initial_focal_point.x, priv->initial_focal_point.y, &priv->transformed_focal_point.x, &priv->transformed_focal_point.y); clutter_actor_set_pivot_point (actor, priv->transformed_focal_point.x / clutter_actor_get_width (actor), priv->transformed_focal_point.y / clutter_actor_get_height (actor)); return TRUE; } static gboolean clutter_zoom_action_gesture_progress (ClutterGestureAction *action, ClutterActor *actor) { ClutterZoomActionPrivate *priv = ((ClutterZoomAction *) action)->priv; gdouble distance, new_scale; gfloat dx, dy; gboolean retval; capture_point_update_position (action, actor, 0, &priv->points[0]); capture_point_update_position (action, actor, 1, &priv->points[1]); dx = priv->points[1].update_x - priv->points[0].update_x; dy = priv->points[1].update_y - priv->points[0].update_y; distance = sqrt (dx * dx + dy * dy); if (distance == 0) return TRUE; priv->focal_point.x = (priv->points[0].update_x + priv->points[1].update_x) / 2; priv->focal_point.y = (priv->points[0].update_y + priv->points[1].update_y) / 2; new_scale = distance / priv->zoom_initial_distance; g_signal_emit (action, zoom_signals[ZOOM], 0, actor, &priv->focal_point, new_scale, &retval); return TRUE; } static void clutter_zoom_action_gesture_cancel (ClutterGestureAction *action, ClutterActor *actor) { ClutterZoomActionPrivate *priv = ((ClutterZoomAction *) action)->priv; clutter_actor_set_translation (actor, priv->initial_x, priv->initial_y, priv->initial_z); clutter_actor_set_scale (actor, priv->initial_scale_x, priv->initial_scale_y); } static gboolean clutter_zoom_action_real_zoom (ClutterZoomAction *action, ClutterActor *actor, ClutterPoint *focal_point, gdouble factor) { ClutterZoomActionPrivate *priv = action->priv; gfloat x, y, z; gdouble scale_x, scale_y; ClutterVertex out, in; in.x = priv->transformed_focal_point.x; in.y = priv->transformed_focal_point.y; in.z = 0; clutter_actor_apply_transform_to_point (actor, &in, &out); clutter_actor_get_scale (actor, &scale_x, &scale_y); switch (priv->zoom_axis) { case CLUTTER_ZOOM_BOTH: clutter_actor_set_scale (actor, factor, factor); break; case CLUTTER_ZOOM_X_AXIS: clutter_actor_set_scale (actor, factor, scale_y); break; case CLUTTER_ZOOM_Y_AXIS: clutter_actor_set_scale (actor, scale_x, factor); break; default: break; } x = priv->initial_x + priv->focal_point.x - priv->initial_focal_point.x; y = priv->initial_y + priv->focal_point.y - priv->initial_focal_point.y; clutter_actor_get_translation (actor, NULL, NULL, &z); clutter_actor_set_translation (actor, x, y, z); return TRUE; } static void clutter_zoom_action_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterZoomAction *action = CLUTTER_ZOOM_ACTION (gobject); switch (prop_id) { case PROP_ZOOM_AXIS: clutter_zoom_action_set_zoom_axis (action, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_zoom_action_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterZoomActionPrivate *priv = CLUTTER_ZOOM_ACTION (gobject)->priv; switch (prop_id) { case PROP_ZOOM_AXIS: g_value_set_enum (value, priv->zoom_axis); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_zoom_action_dispose (GObject *gobject) { G_OBJECT_CLASS (clutter_zoom_action_parent_class)->dispose (gobject); } static void clutter_zoom_action_constructed (GObject *gobject) { ClutterGestureAction *gesture; gesture = CLUTTER_GESTURE_ACTION (gobject); clutter_gesture_action_set_threshold_trigger_edge (gesture, CLUTTER_GESTURE_TRIGGER_EDGE_NONE); } static void clutter_zoom_action_class_init (ClutterZoomActionClass *klass) { ClutterGestureActionClass *gesture_class = CLUTTER_GESTURE_ACTION_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructed = clutter_zoom_action_constructed; gobject_class->set_property = clutter_zoom_action_set_property; gobject_class->get_property = clutter_zoom_action_get_property; gobject_class->dispose = clutter_zoom_action_dispose; gesture_class->gesture_begin = clutter_zoom_action_gesture_begin; gesture_class->gesture_progress = clutter_zoom_action_gesture_progress; gesture_class->gesture_cancel = clutter_zoom_action_gesture_cancel; klass->zoom = clutter_zoom_action_real_zoom; /** * ClutterZoomAction:zoom-axis: * * Constraints the zooming action to the specified axis * * Since: 1.12 */ zoom_props[PROP_ZOOM_AXIS] = g_param_spec_enum ("zoom-axis", P_("Zoom Axis"), P_("Constraints the zoom to an axis"), CLUTTER_TYPE_ZOOM_AXIS, CLUTTER_ZOOM_BOTH, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, zoom_props); /** * ClutterZoomAction::zoom: * @action: the #ClutterZoomAction that emitted the signal * @actor: the #ClutterActor attached to the action * @focal_point: the focal point of the zoom * @factor: the initial distance between the 2 touch points * * The ::zoom signal is emitted for each series of touch events that * change the distance and focal point between the touch points. * * The default handler of the signal will call * clutter_actor_set_scale() on @actor using the ratio of the first * distance between the touch points and the current distance. To * override the default behaviour, connect to this signal and return * %FALSE. * * Return value: %TRUE if the zoom should continue, and %FALSE if * the zoom should be cancelled. * * Since: 1.12 */ zoom_signals[ZOOM] = g_signal_new (I_("zoom"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterZoomActionClass, zoom), _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT_BOXED_DOUBLE, G_TYPE_BOOLEAN, 3, CLUTTER_TYPE_ACTOR, CLUTTER_TYPE_POINT, G_TYPE_DOUBLE); } static void clutter_zoom_action_init (ClutterZoomAction *self) { ClutterGestureAction *gesture; self->priv = clutter_zoom_action_get_instance_private (self); self->priv->zoom_axis = CLUTTER_ZOOM_BOTH; gesture = CLUTTER_GESTURE_ACTION (self); clutter_gesture_action_set_n_touch_points (gesture, 2); } /** * clutter_zoom_action_new: * * Creates a new #ClutterZoomAction instance * * Return value: the newly created #ClutterZoomAction * * Since: 1.12 */ ClutterAction * clutter_zoom_action_new (void) { return g_object_new (CLUTTER_TYPE_ZOOM_ACTION, NULL); } /** * clutter_zoom_action_set_zoom_axis: * @action: a #ClutterZoomAction * @axis: the axis to constraint the zooming to * * Restricts the zooming action to a specific axis * * Since: 1.12 */ void clutter_zoom_action_set_zoom_axis (ClutterZoomAction *action, ClutterZoomAxis axis) { g_return_if_fail (CLUTTER_IS_ZOOM_ACTION (action)); g_return_if_fail (axis >= CLUTTER_ZOOM_X_AXIS && axis <= CLUTTER_ZOOM_BOTH); if (action->priv->zoom_axis == axis) return; action->priv->zoom_axis = axis; g_object_notify_by_pspec (G_OBJECT (action), zoom_props[PROP_ZOOM_AXIS]); } /** * clutter_zoom_action_get_zoom_axis: * @action: a #ClutterZoomAction * * Retrieves the axis constraint set by clutter_zoom_action_set_zoom_axis() * * Return value: the axis constraint * * Since: 1.12 */ ClutterZoomAxis clutter_zoom_action_get_zoom_axis (ClutterZoomAction *action) { g_return_val_if_fail (CLUTTER_IS_ZOOM_ACTION (action), CLUTTER_ZOOM_BOTH); return action->priv->zoom_axis; } /** * clutter_zoom_action_get_focal_point: * @action: a #ClutterZoomAction * @point: (out): a #ClutterPoint * * Retrieves the focal point of the current zoom * * Since: 1.12 */ void clutter_zoom_action_get_focal_point (ClutterZoomAction *action, ClutterPoint *point) { g_return_if_fail (CLUTTER_IS_ZOOM_ACTION (action)); g_return_if_fail (point != NULL); *point = action->priv->focal_point; } /** * clutter_zoom_action_get_transformed_focal_point: * @action: a #ClutterZoomAction * @point: (out): a #ClutterPoint * * Retrieves the focal point relative to the actor's coordinates of * the current zoom * * Since: 1.12 */ void clutter_zoom_action_get_transformed_focal_point (ClutterZoomAction *action, ClutterPoint *point) { g_return_if_fail (CLUTTER_IS_ZOOM_ACTION (action)); g_return_if_fail (point != NULL); *point = action->priv->transformed_focal_point; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-offscreen-effect.h���������������������������������������������0000664�0001750�0001750�00000011120�14211404421�023330� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_OFFSCREEN_EFFECT_H__ #define __CLUTTER_OFFSCREEN_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <cogl/cogl.h> #include <clutter/clutter-effect.h> G_BEGIN_DECLS #define CLUTTER_TYPE_OFFSCREEN_EFFECT (clutter_offscreen_effect_get_type ()) #define CLUTTER_OFFSCREEN_EFFECT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLUTTER_TYPE_OFFSCREEN_EFFECT, ClutterOffscreenEffect)) #define CLUTTER_IS_OFFSCREEN_EFFECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLUTTER_TYPE_OFFSCREEN_EFFECT)) #define CLUTTER_OFFSCREEN_EFFECT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CLUTTER_TYPE_OFFSCREEN_EFFECT, ClutterOffscreenEffectClass)) #define CLUTTER_IS_OFFSCREEN_EFFECT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_OFFSCREEN_EFFECT)) #define CLUTTER_OFFSCREEN_EFFECT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_OFFSCREEN_EFFECT, ClutterOffscreenEffectClass)) typedef struct _ClutterOffscreenEffect ClutterOffscreenEffect; typedef struct _ClutterOffscreenEffectPrivate ClutterOffscreenEffectPrivate; typedef struct _ClutterOffscreenEffectClass ClutterOffscreenEffectClass; /** * ClutterOffscreenEffect: * * The #ClutterOffscreenEffect structure contains only private data * and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterOffscreenEffect { /*< private >*/ ClutterEffect parent_instance; ClutterOffscreenEffectPrivate *priv; }; /** * ClutterOffscreenEffectClass: * @create_texture: virtual function * @paint_target: virtual function * * The #ClutterOffscreenEffectClass structure contains only private data * * Since: 1.4 */ struct _ClutterOffscreenEffectClass { /*< private >*/ ClutterEffectClass parent_class; /*< public >*/ CoglHandle (* create_texture) (ClutterOffscreenEffect *effect, gfloat width, gfloat height); void (* paint_target) (ClutterOffscreenEffect *effect); /*< private >*/ void (* _clutter_offscreen1) (void); void (* _clutter_offscreen2) (void); void (* _clutter_offscreen3) (void); void (* _clutter_offscreen4) (void); void (* _clutter_offscreen5) (void); void (* _clutter_offscreen6) (void); void (* _clutter_offscreen7) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_offscreen_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 CoglMaterial * clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect); CLUTTER_AVAILABLE_IN_1_10 CoglHandle clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect); CLUTTER_AVAILABLE_IN_1_4 void clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect); CLUTTER_AVAILABLE_IN_1_4 CoglHandle clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect, gfloat width, gfloat height); CLUTTER_DEPRECATED_IN_1_14_FOR (clutter_offscreen_effect_get_target_rect) gboolean clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect, gfloat *width, gfloat *height); CLUTTER_AVAILABLE_IN_1_14 gboolean clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect, ClutterRect *rect); G_END_DECLS #endif /* __CLUTTER_OFFSCREEN_EFFECT_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-container.h����������������������������������������������������0000664�0001750�0001750�00000023116�14211404421�022116� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * ClutterContainer: Generic actor container interface. * Author: Emmanuele Bassi <ebassi@openedhand.com> */ #ifndef __CLUTTER_CONTAINER_H__ #define __CLUTTER_CONTAINER_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-actor.h> #include <clutter/clutter-child-meta.h> #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_CONTAINER (clutter_container_get_type ()) #define CLUTTER_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONTAINER, ClutterContainer)) #define CLUTTER_IS_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONTAINER)) #define CLUTTER_CONTAINER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_CONTAINER, ClutterContainerIface)) typedef struct _ClutterContainerIface ClutterContainerIface; /** * ClutterContainer: * * #ClutterContainer is an opaque structure whose members cannot be directly * accessed * * Since: 0.4 */ /** * ClutterContainerIface: * @add: virtual function for adding an actor to the container. This virtual * function is deprecated, and it should not be overridden. * @remove: virtual function for removing an actor from the container. This * virtual function is deprecated, and it should not be overridden. * @foreach: virtual function for iterating over the container's children. * This virtual function is deprecated, and it should not be overridden. * @foreach_with_internals: virtual functions for iterating over the * container's children, both added using the #ClutterContainer API * and internal children. The implementation of this virtual function * is required only if the #ClutterContainer implementation has * internal children. This virtual function is deprecated, and it should * not be overridden. * @raise: virtual function for raising a child. This virtual function is * deprecated and it should not be overridden. * @lower: virtual function for lowering a child. This virtual function is * deprecated and it should not be overridden. * @sort_depth_order: virtual function for sorting the children of a * container depending on their depth. This virtual function is deprecated * and it should not be overridden. * @child_meta_type: The GType used for storing auxiliary information about * each of the containers children. * @create_child_meta: virtual function that gets called for each added * child, the function should instantiate an object of type * #ClutterContainerIface::child_meta_type, set the container and actor * fields in the instance and add the record to a data structure for * subsequent access for #ClutterContainerIface::get_child_meta * @destroy_child_meta: virtual function that gets called when a child is * removed; it shuld release all resources held by the record * @get_child_meta: return the record for a container child * @actor_added: class handler for #ClutterContainer::actor-added * @actor_removed: class handler for #ClutterContainer::actor-removed * @child_notify: class handler for #ClutterContainer::child-notify * * Base interface for container actors. The @add, @remove and @foreach * virtual functions must be provided by any implementation; the other * virtual functions are optional. * * Since: 0.4 */ struct _ClutterContainerIface { /*< private >*/ GTypeInterface g_iface; /*< public >*/ void (* add) (ClutterContainer *container, ClutterActor *actor); void (* remove) (ClutterContainer *container, ClutterActor *actor); void (* foreach) (ClutterContainer *container, ClutterCallback callback, gpointer user_data); void (* foreach_with_internals) (ClutterContainer *container, ClutterCallback callback, gpointer user_data); /* child stacking */ void (* raise) (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling); void (* lower) (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling); void (* sort_depth_order) (ClutterContainer *container); /* ClutterChildMeta management */ GType child_meta_type; void (* create_child_meta) (ClutterContainer *container, ClutterActor *actor); void (* destroy_child_meta) (ClutterContainer *container, ClutterActor *actor); ClutterChildMeta *(* get_child_meta) (ClutterContainer *container, ClutterActor *actor); /* signals */ void (* actor_added) (ClutterContainer *container, ClutterActor *actor); void (* actor_removed) (ClutterContainer *container, ClutterActor *actor); void (* child_notify) (ClutterContainer *container, ClutterActor *child, GParamSpec *pspec); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_container_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_container_find_child_by_name (ClutterContainer *container, const gchar *child_name); CLUTTER_AVAILABLE_IN_ALL GParamSpec * clutter_container_class_find_child_property (GObjectClass *klass, const gchar *property_name); CLUTTER_AVAILABLE_IN_ALL GParamSpec ** clutter_container_class_list_child_properties (GObjectClass *klass, guint *n_properties); CLUTTER_AVAILABLE_IN_ALL void clutter_container_create_child_meta (ClutterContainer *container, ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL void clutter_container_destroy_child_meta (ClutterContainer *container, ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL ClutterChildMeta * clutter_container_get_child_meta (ClutterContainer *container, ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL void clutter_container_child_set_property (ClutterContainer *container, ClutterActor *child, const gchar * property, const GValue *value); CLUTTER_AVAILABLE_IN_ALL void clutter_container_child_get_property (ClutterContainer *container, ClutterActor *child, const gchar *property, GValue *value); CLUTTER_AVAILABLE_IN_ALL void clutter_container_child_set (ClutterContainer *container, ClutterActor *actor, const gchar *first_prop, ...) G_GNUC_NULL_TERMINATED; CLUTTER_AVAILABLE_IN_ALL void clutter_container_child_get (ClutterContainer *container, ClutterActor *actor, const gchar *first_prop, ...) G_GNUC_NULL_TERMINATED; CLUTTER_AVAILABLE_IN_ALL void clutter_container_child_notify (ClutterContainer *container, ClutterActor *child, GParamSpec *pspec); G_END_DECLS #endif /* __CLUTTER_CONTAINER_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-master-clock-default.h�����������������������������������������0000664�0001750�0001750�00000003541�14211404421�024142� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com> * * Copyright (C) 2015 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_MASTER_CLOCK_DEFAULT_H__ #define __CLUTTER_MASTER_CLOCK_DEFAULT_H__ #include <clutter/clutter-timeline.h> G_BEGIN_DECLS #define CLUTTER_TYPE_MASTER_CLOCK_DEFAULT (_clutter_master_clock_default_get_type ()) #define CLUTTER_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefault)) #define CLUTTER_IS_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT)) #define CLUTTER_MASTER_CLOCK_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefaultClass)) typedef struct _ClutterMasterClockDefault ClutterMasterClockDefault; typedef struct _ClutterMasterClockDefaultClass ClutterMasterClockDefaultClass; struct _ClutterMasterClockDefaultClass { GObjectClass parent_class; }; GType _clutter_master_clock_default_get_type (void) G_GNUC_CONST; G_END_DECLS #endif /* __CLUTTER_MASTER_CLOCK_DEFAULT_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-feature.h������������������������������������������������������0000664�0001750�0001750�00000002454�14211404421�021571� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_FEATURE_H__ #define __CLUTTER_FEATURE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS CLUTTER_AVAILABLE_IN_ALL gboolean clutter_feature_available (ClutterFeatureFlags feature); CLUTTER_AVAILABLE_IN_ALL ClutterFeatureFlags clutter_feature_get_all (void); G_END_DECLS #endif /* __CLUTTER_FEATURE_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-pan-action.h���������������������������������������������������0000664�0001750�0001750�00000015170�14211404421�022166� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * Copyright (C) 2012 Collabora Ltd. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emanuele Aina <emanuele.aina@collabora.com> * * Based on ClutterDragAction, ClutterSwipeAction, and MxKineticScrollView, * written by: * Emmanuele Bassi <ebassi@linux.intel.com> * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> * Chris Lord <chris@linux.intel.com> */ #ifndef __CLUTTER_PAN_ACTION_H__ #define __CLUTTER_PAN_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-gesture-action.h> G_BEGIN_DECLS #define CLUTTER_TYPE_PAN_ACTION (clutter_pan_action_get_type ()) #define CLUTTER_PAN_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PAN_ACTION, ClutterPanAction)) #define CLUTTER_IS_PAN_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PAN_ACTION)) #define CLUTTER_PAN_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_PAN_ACTION, ClutterPanActionClass)) #define CLUTTER_IS_PAN_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_PAN_ACTION)) #define CLUTTER_PAN_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_PAN_ACTION, ClutterPanActionClass)) typedef struct _ClutterPanAction ClutterPanAction; typedef struct _ClutterPanActionPrivate ClutterPanActionPrivate; typedef struct _ClutterPanActionClass ClutterPanActionClass; /** * ClutterPanAction: * * The #ClutterPanAction structure contains * only private data and should be accessed using the provided API * * Since: 1.12 */ struct _ClutterPanAction { /*< private >*/ ClutterGestureAction parent_instance; ClutterPanActionPrivate *priv; }; /** * ClutterPanActionClass: * @pan: class handler for the #ClutterPanAction::pan signal * @pan_stopped: class handler for the #ClutterPanAction::pan-stopped signal * * The #ClutterPanActionClass structure contains * only private data. * * Since: 1.12 */ struct _ClutterPanActionClass { /*< private >*/ ClutterGestureActionClass parent_class; /*< public >*/ gboolean (* pan) (ClutterPanAction *action, ClutterActor *actor, gboolean is_interpolated); void (* pan_stopped) (ClutterPanAction *action, ClutterActor *actor); /*< private >*/ void (* _clutter_pan_action1) (void); void (* _clutter_pan_action2) (void); void (* _clutter_pan_action3) (void); void (* _clutter_pan_action4) (void); void (* _clutter_pan_action5) (void); void (* _clutter_pan_action6) (void); }; CLUTTER_AVAILABLE_IN_1_12 GType clutter_pan_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterAction * clutter_pan_action_new (void); CLUTTER_AVAILABLE_IN_1_12 void clutter_pan_action_set_pan_axis (ClutterPanAction *self, ClutterPanAxis axis); CLUTTER_AVAILABLE_IN_1_12 ClutterPanAxis clutter_pan_action_get_pan_axis (ClutterPanAction *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_pan_action_set_interpolate (ClutterPanAction *self, gboolean should_interpolate); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_pan_action_get_interpolate (ClutterPanAction *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_pan_action_set_deceleration (ClutterPanAction *self, gdouble rate); CLUTTER_AVAILABLE_IN_1_12 gdouble clutter_pan_action_get_deceleration (ClutterPanAction *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_pan_action_set_acceleration_factor (ClutterPanAction *self, gdouble factor); CLUTTER_AVAILABLE_IN_1_12 gdouble clutter_pan_action_get_acceleration_factor (ClutterPanAction *self); CLUTTER_AVAILABLE_IN_1_12 void clutter_pan_action_get_interpolated_coords (ClutterPanAction *self, gfloat *interpolated_x, gfloat *interpolated_y); CLUTTER_AVAILABLE_IN_1_12 gfloat clutter_pan_action_get_interpolated_delta (ClutterPanAction *self, gfloat *delta_x, gfloat *delta_y); CLUTTER_AVAILABLE_IN_1_14 gfloat clutter_pan_action_get_motion_delta (ClutterPanAction *self, guint point, gfloat *delta_x, gfloat *delta_y); CLUTTER_AVAILABLE_IN_1_14 void clutter_pan_action_get_motion_coords (ClutterPanAction *self, guint point, gfloat *motion_x, gfloat *motion_y); CLUTTER_AVAILABLE_IN_1_24 gfloat clutter_pan_action_get_constrained_motion_delta (ClutterPanAction *self, guint point, gfloat *delta_x, gfloat *delta_y); G_END_DECLS #endif /* __CLUTTER_PAN_ACTION_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-cairo.c��������������������������������������������������������0000664�0001750�0001750�00000004651�14211404421�021227� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-cairo * @Title: Cairo integration * @Short_Description: Functions for interoperating with Cairo * * Clutter provides some utility functions for using Cairo. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-cairo.h" #include "clutter-color.h" /** * clutter_cairo_set_source_color: * @cr: a Cairo context * @color: a #ClutterColor * * Utility function for setting the source color of @cr using * a #ClutterColor. This function is the equivalent of: * * |[ * cairo_set_source_rgba (cr, * color->red / 255.0, * color->green / 255.0, * color->blue / 255.0, * color->alpha / 255.0); * ]| * * Since: 1.0 */ void clutter_cairo_set_source_color (cairo_t *cr, const ClutterColor *color) { g_return_if_fail (cr != NULL); g_return_if_fail (color != NULL); if (color->alpha == 0xff) cairo_set_source_rgb (cr, color->red / 255.0, color->green / 255.0, color->blue / 255.0); else cairo_set_source_rgba (cr, color->red / 255.0, color->green / 255.0, color->blue / 255.0, color->alpha / 255.0); } /** * clutter_cairo_clear: * @cr: a Cairo context * * Utility function to clear a Cairo context. * * Since: 1.12 */ void clutter_cairo_clear (cairo_t *cr) { cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); } ���������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-constraint-private.h�������������������������������������������0000664�0001750�0001750�00000003217�14211404421�023770� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_CONSTRAINT_PRIVATE_H__ #define __CLUTTER_CONSTRAINT_PRIVATE_H__ #include "clutter-constraint.h" G_BEGIN_DECLS gboolean clutter_constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation); void clutter_constraint_update_preferred_size (ClutterConstraint *constraint, ClutterActor *actor, ClutterOrientation direction, float for_size, float *minimum_size, float *natural_size); G_END_DECLS #endif /* __CLUTTER_CONSTRAINT_PRIVATE_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-main.h���������������������������������������������������������0000664�0001750�0001750�00000017162�14211404421�021064� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_MAIN_H__ #define __CLUTTER_MAIN_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-actor.h> #include <clutter/clutter-stage.h> #include <pango/pango.h> G_BEGIN_DECLS /** * CLUTTER_INIT_ERROR: * * #GError domain for #ClutterInitError */ #define CLUTTER_INIT_ERROR (clutter_init_error_quark ()) /** * ClutterInitError: * @CLUTTER_INIT_SUCCESS: Initialisation successful * @CLUTTER_INIT_ERROR_UNKNOWN: Unknown error * @CLUTTER_INIT_ERROR_THREADS: Thread initialisation failed * @CLUTTER_INIT_ERROR_BACKEND: Backend initialisation failed * @CLUTTER_INIT_ERROR_INTERNAL: Internal error * * Error conditions returned by clutter_init() and clutter_init_with_args(). * * Since: 0.2 */ typedef enum { CLUTTER_INIT_SUCCESS = 1, CLUTTER_INIT_ERROR_UNKNOWN = 0, CLUTTER_INIT_ERROR_THREADS = -1, CLUTTER_INIT_ERROR_BACKEND = -2, CLUTTER_INIT_ERROR_INTERNAL = -3 } ClutterInitError; CLUTTER_AVAILABLE_IN_ALL GQuark clutter_init_error_quark (void); /** * CLUTTER_PRIORITY_REDRAW: * * Priority of the redraws. This is chosen to be lower than the GTK+ * redraw and resize priorities, because in application with both * GTK+ and Clutter it's more likely that the Clutter part will be * continually animating (and thus able to starve GTK+) than * vice-versa. * * Since: 0.8 */ #define CLUTTER_PRIORITY_REDRAW (G_PRIORITY_HIGH_IDLE + 50) /* Initialisation */ CLUTTER_AVAILABLE_IN_ALL void clutter_base_init (void); CLUTTER_AVAILABLE_IN_ALL ClutterInitError clutter_init (int *argc, char ***argv) G_GNUC_WARN_UNUSED_RESULT; CLUTTER_AVAILABLE_IN_ALL ClutterInitError clutter_init_with_args (int *argc, char ***argv, const char *parameter_string, GOptionEntry *entries, const char *translation_domain, GError **error) G_GNUC_WARN_UNUSED_RESULT; CLUTTER_AVAILABLE_IN_ALL GOptionGroup * clutter_get_option_group (void); CLUTTER_AVAILABLE_IN_ALL GOptionGroup * clutter_get_option_group_without_init (void); /* Mainloop */ CLUTTER_AVAILABLE_IN_ALL void clutter_main (void); CLUTTER_AVAILABLE_IN_ALL void clutter_main_quit (void); CLUTTER_AVAILABLE_IN_ALL gint clutter_main_level (void); CLUTTER_AVAILABLE_IN_ALL void clutter_do_event (ClutterEvent *event); /* Debug utility functions */ CLUTTER_AVAILABLE_IN_1_4 gboolean clutter_get_accessibility_enabled (void); CLUTTER_AVAILABLE_IN_1_14 void clutter_disable_accessibility (void); /* Threading functions */ CLUTTER_AVAILABLE_IN_ALL void clutter_threads_set_lock_functions (GCallback enter_fn, GCallback leave_fn); CLUTTER_AVAILABLE_IN_ALL guint clutter_threads_add_idle (GSourceFunc func, gpointer data); CLUTTER_AVAILABLE_IN_ALL guint clutter_threads_add_idle_full (gint priority, GSourceFunc func, gpointer data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_ALL guint clutter_threads_add_timeout (guint interval, GSourceFunc func, gpointer data); CLUTTER_AVAILABLE_IN_ALL guint clutter_threads_add_timeout_full (gint priority, guint interval, GSourceFunc func, gpointer data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_0 guint clutter_threads_add_repaint_func (GSourceFunc func, gpointer data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_10 guint clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags, GSourceFunc func, gpointer data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_0 void clutter_threads_remove_repaint_func (guint handle_id); CLUTTER_AVAILABLE_IN_ALL void clutter_grab_pointer (ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL void clutter_ungrab_pointer (void); CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_get_pointer_grab (void); CLUTTER_AVAILABLE_IN_ALL void clutter_grab_keyboard (ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL void clutter_ungrab_keyboard (void); CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_get_keyboard_grab (void); CLUTTER_AVAILABLE_IN_ALL PangoFontMap * clutter_get_font_map (void); CLUTTER_AVAILABLE_IN_ALL ClutterTextDirection clutter_get_default_text_direction (void); CLUTTER_AVAILABLE_IN_ALL guint clutter_get_default_frame_rate (void); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_check_version (guint major, guint minor, guint micro); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_check_windowing_backend (const char *backend_type); G_END_DECLS #endif /* _CLUTTER_MAIN_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-drag-action.h��������������������������������������������������0000664�0001750�0001750�00000015025�14211404421�022324� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_DRAG_ACTION_H__ #define __CLUTTER_DRAG_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-action.h> #include <clutter/clutter-event.h> G_BEGIN_DECLS #define CLUTTER_TYPE_DRAG_ACTION (clutter_drag_action_get_type ()) #define CLUTTER_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragAction)) #define CLUTTER_IS_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DRAG_ACTION)) #define CLUTTER_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass)) #define CLUTTER_IS_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DRAG_ACTION)) #define CLUTTER_DRAG_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass)) typedef struct _ClutterDragAction ClutterDragAction; typedef struct _ClutterDragActionPrivate ClutterDragActionPrivate; typedef struct _ClutterDragActionClass ClutterDragActionClass; /** * ClutterDragAction: * * The #ClutterDragAction structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterDragAction { /*< private >*/ ClutterAction parent_instance; ClutterDragActionPrivate *priv; }; /** * ClutterDragActionClass: * @drag_begin: class handler of the #ClutterDragAction::drag-begin signal * @drag_motion: class handler of the #ClutterDragAction::drag-motion signal * @drag_end: class handler of the #ClutterDragAction::drag-end signal * @drag_progress: class handler of the #ClutterDragAction::drag-progress signal * * The #ClutterDragActionClass structure contains * only private data * * Since: 1.4 */ struct _ClutterDragActionClass { /*< private >*/ ClutterActionClass parent_class; /*< public >*/ void (* drag_begin) (ClutterDragAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y, ClutterModifierType modifiers); void (* drag_motion) (ClutterDragAction *action, ClutterActor *actor, gfloat delta_x, gfloat delta_y); void (* drag_end) (ClutterDragAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y, ClutterModifierType modifiers); gboolean (* drag_progress) (ClutterDragAction *action, ClutterActor *actor, gfloat delta_x, gfloat delta_y); /*< private >*/ void (* _clutter_drag_action1) (void); void (* _clutter_drag_action2) (void); void (* _clutter_drag_action3) (void); void (* _clutter_drag_action4) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_drag_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterAction * clutter_drag_action_new (void); CLUTTER_AVAILABLE_IN_1_4 void clutter_drag_action_set_drag_threshold (ClutterDragAction *action, gint x_threshold, gint y_threshold); CLUTTER_AVAILABLE_IN_1_4 void clutter_drag_action_get_drag_threshold (ClutterDragAction *action, guint *x_threshold, guint *y_threshold); CLUTTER_AVAILABLE_IN_1_4 void clutter_drag_action_set_drag_handle (ClutterDragAction *action, ClutterActor *handle); CLUTTER_AVAILABLE_IN_1_4 ClutterActor * clutter_drag_action_get_drag_handle (ClutterDragAction *action); CLUTTER_AVAILABLE_IN_1_4 void clutter_drag_action_set_drag_axis (ClutterDragAction *action, ClutterDragAxis axis); CLUTTER_AVAILABLE_IN_1_4 ClutterDragAxis clutter_drag_action_get_drag_axis (ClutterDragAction *action); CLUTTER_AVAILABLE_IN_1_4 void clutter_drag_action_get_press_coords (ClutterDragAction *action, gfloat *press_x, gfloat *press_y); CLUTTER_AVAILABLE_IN_1_4 void clutter_drag_action_get_motion_coords (ClutterDragAction *action, gfloat *motion_x, gfloat *motion_y); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_drag_action_get_drag_area (ClutterDragAction *action, ClutterRect *drag_area); CLUTTER_AVAILABLE_IN_1_12 void clutter_drag_action_set_drag_area (ClutterDragAction *action, const ClutterRect *drag_area); G_END_DECLS #endif /* __CLUTTER_DRAG_ACTION_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-event-private.h������������������������������������������������0000664�0001750�0001750�00000002742�14211404421�022727� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_EVENT_PRIVATE_H__ #define __CLUTTER_EVENT_PRIVATE_H__ #include <clutter/clutter-event.h> G_BEGIN_DECLS void _clutter_event_set_pointer_emulated (ClutterEvent *event, gboolean is_emulated); /* Reinjecting queued events for processing */ void _clutter_process_event (ClutterEvent *event); gboolean _clutter_event_process_filters (ClutterEvent *event); /* clears the event queue inside the main context */ void _clutter_clear_events_queue (void); void _clutter_clear_events_queue_for_stage (ClutterStage *stage); void _clutter_event_set_platform_data (ClutterEvent *event, gpointer data); gpointer _clutter_event_get_platform_data (const ClutterEvent *event); void _clutter_event_set_state_full (ClutterEvent *event, ClutterModifierType button_state, ClutterModifierType base_state, ClutterModifierType latched_state, ClutterModifierType locked_state, ClutterModifierType effective_state); void _clutter_event_push (const ClutterEvent *event, gboolean do_copy); G_END_DECLS #endif /* __CLUTTER_EVENT_PRIVATE_H__ */ ������������������������������muffin-5.2.1/clutter/clutter/clutter-util.c���������������������������������������������������������0000664�0001750�0001750�00000050156�14211404421�021110� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * */ /** * SECTION:clutter-util * @short_description: Utility functions * * Various miscellaneous utilility functions. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter-debug.h" #include "clutter-main.h" #include "clutter-interval.h" #include "clutter-private.h" #include "deprecated/clutter-util.h" /** * clutter_util_next_p2: * @a: Value to get the next power * * Calculates the nearest power of two, greater than or equal to @a. * * Return value: The nearest power of two, greater or equal to @a. * * Deprecated: 1.2 */ gint clutter_util_next_p2 (gint a) { int rval = 1; while (rval < a) rval <<= 1; return rval; } /* Help macros to scale from OpenGL <-1,1> coordinates system to * window coordinates ranging [0,window-size] */ #define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) #define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) #define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2))) void _clutter_util_fully_transform_vertices (const CoglMatrix *modelview, const CoglMatrix *projection, const float *viewport, const ClutterVertex *vertices_in, ClutterVertex *vertices_out, int n_vertices) { CoglMatrix modelview_projection; ClutterVertex4 *vertices_tmp; int i; vertices_tmp = g_alloca (sizeof (ClutterVertex4) * n_vertices); if (n_vertices >= 4) { /* XXX: we should find a way to cache this per actor */ cogl_matrix_multiply (&modelview_projection, projection, modelview); cogl_matrix_project_points (&modelview_projection, 3, sizeof (ClutterVertex), vertices_in, sizeof (ClutterVertex4), vertices_tmp, n_vertices); } else { cogl_matrix_transform_points (modelview, 3, sizeof (ClutterVertex), vertices_in, sizeof (ClutterVertex4), vertices_tmp, n_vertices); cogl_matrix_project_points (projection, 3, sizeof (ClutterVertex4), vertices_tmp, sizeof (ClutterVertex4), vertices_tmp, n_vertices); } for (i = 0; i < n_vertices; i++) { ClutterVertex4 vertex_tmp = vertices_tmp[i]; ClutterVertex *vertex_out = &vertices_out[i]; /* Finally translate from OpenGL coords to window coords */ vertex_out->x = MTX_GL_SCALE_X (vertex_tmp.x, vertex_tmp.w, viewport[2], viewport[0]); vertex_out->y = MTX_GL_SCALE_Y (vertex_tmp.y, vertex_tmp.w, viewport[3], viewport[1]); } } /*< private > * _clutter_util_rectangle_union: * @src1: first rectangle to union * @src2: second rectangle to union * @dest: (out): return location for the unioned rectangle * * Calculates the union of two rectangles. * * The union of rectangles @src1 and @src2 is the smallest rectangle which * includes both @src1 and @src2 within it. * * It is allowed for @dest to be the same as either @src1 or @src2. * * This function should really be in Cairo. */ void _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1, const cairo_rectangle_int_t *src2, cairo_rectangle_int_t *dest) { int dest_x, dest_y; dest_x = MIN (src1->x, src2->x); dest_y = MIN (src1->y, src2->y); dest->width = MAX (src1->x + src1->width, src2->x + src2->width) - dest_x; dest->height = MAX (src1->y + src1->height, src2->y + src2->height) - dest_y; dest->x = dest_x; dest->y = dest_y; } gboolean _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1, const cairo_rectangle_int_t *src2, cairo_rectangle_int_t *dest) { int x1, y1, x2, y2; x1 = MAX (src1->x, src2->x); y1 = MAX (src1->y, src2->y); x2 = MIN (src1->x + (int) src1->width, src2->x + (int) src2->width); y2 = MIN (src1->y + (int) src1->height, src2->y + (int) src2->height); if (x1 >= x2 || y1 >= y2) { dest->x = 0; dest->y = 0; dest->width = 0; dest->height = 0; return FALSE; } else { dest->x = x1; dest->y = y1; dest->width = x2 - x1; dest->height = y2 - y1; return TRUE; } } float _clutter_util_matrix_determinant (const ClutterMatrix *matrix) { return matrix->xw * matrix->yz * matrix->zy * matrix->wz - matrix->xz * matrix->yw * matrix->zy * matrix->wz - matrix->xw * matrix->yy * matrix->zz * matrix->wz + matrix->xy * matrix->yw * matrix->zz * matrix->wz + matrix->xz * matrix->yy * matrix->zw * matrix->wz - matrix->xy * matrix->yz * matrix->zw * matrix->wz - matrix->xw * matrix->yz * matrix->zx * matrix->wy + matrix->xz * matrix->yw * matrix->zx * matrix->wy + matrix->xw * matrix->yx * matrix->zz * matrix->wy - matrix->xx * matrix->yw * matrix->zz * matrix->wy - matrix->xz * matrix->yx * matrix->zw * matrix->wy + matrix->xx * matrix->yz * matrix->zw * matrix->wy + matrix->xw * matrix->yy * matrix->zx * matrix->wz - matrix->xy * matrix->yw * matrix->zx * matrix->wz - matrix->xw * matrix->yx * matrix->zy * matrix->wz + matrix->xx * matrix->yw * matrix->zy * matrix->wz + matrix->xy * matrix->yx * matrix->zw * matrix->wz - matrix->xx * matrix->yy * matrix->zw * matrix->wz - matrix->xz * matrix->yy * matrix->zx * matrix->ww + matrix->xy * matrix->yz * matrix->zx * matrix->ww + matrix->xz * matrix->yx * matrix->zy * matrix->ww - matrix->xx * matrix->yz * matrix->zy * matrix->ww - matrix->xy * matrix->yx * matrix->zz * matrix->ww + matrix->xx * matrix->yy * matrix->zz * matrix->ww; } static void _clutter_util_matrix_transpose_vector4_transform (const ClutterMatrix *matrix, const ClutterVertex4 *point, ClutterVertex4 *res) { res->x = matrix->xx * point->x + matrix->xy * point->y + matrix->xz * point->z + matrix->xw * point->w; res->y = matrix->yx * point->x + matrix->yy * point->y + matrix->yz * point->z + matrix->yw * point->w; res->z = matrix->zx * point->x + matrix->zy * point->y + matrix->zz * point->z + matrix->zw * point->w; res->w = matrix->wz * point->x + matrix->wy * point->w + matrix->wz * point->z + matrix->ww * point->w; } void _clutter_util_matrix_skew_xy (ClutterMatrix *matrix, float factor) { matrix->yx += matrix->xx * factor; matrix->yy += matrix->xy * factor; matrix->yz += matrix->xz * factor; matrix->yw += matrix->xw * factor; } void _clutter_util_matrix_skew_xz (ClutterMatrix *matrix, float factor) { matrix->zx += matrix->xx * factor; matrix->zy += matrix->xy * factor; matrix->zz += matrix->xz * factor; matrix->zw += matrix->xw * factor; } void _clutter_util_matrix_skew_yz (ClutterMatrix *matrix, float factor) { matrix->zx += matrix->yx * factor; matrix->zy += matrix->yy * factor; matrix->zz += matrix->yz * factor; matrix->zw += matrix->yw * factor; } static float _clutter_util_vertex_length (const ClutterVertex *vertex) { return sqrtf (vertex->x * vertex->x + vertex->y * vertex->y + vertex->z * vertex->z); } static void _clutter_util_vertex_normalize (ClutterVertex *vertex) { float factor = _clutter_util_vertex_length (vertex); if (factor == 0.f) return; vertex->x /= factor; vertex->y /= factor; vertex->z /= factor; } static float _clutter_util_vertex_dot (const ClutterVertex *v1, const ClutterVertex *v2) { return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z; } static void _clutter_util_vertex_cross (const ClutterVertex *v1, const ClutterVertex *v2, ClutterVertex *res) { res->x = v1->y * v2->z - v2->y * v1->z; res->y = v1->z * v2->x - v2->z * v1->x; res->z = v1->x * v2->y - v2->x * v1->y; } static void _clutter_util_vertex_combine (const ClutterVertex *a, const ClutterVertex *b, double ascl, double bscl, ClutterVertex *res) { res->x = (ascl * a->x) + (bscl * b->x); res->y = (ascl * a->y) + (bscl * b->y); res->z = (ascl * a->z) + (bscl * b->z); } void _clutter_util_vertex4_interpolate (const ClutterVertex4 *a, const ClutterVertex4 *b, double progress, ClutterVertex4 *res) { res->x = a->x + (b->x - a->x) * progress; res->y = a->y + (b->y - a->y) * progress; res->z = a->z + (b->z - a->z) * progress; res->w = a->w + (b->w - a->w) * progress; } /*< private > * clutter_util_matrix_decompose: * @src: the matrix to decompose * @scale_p: (out caller-allocates): return location for a vertex containing * the scaling factors * @shear_p: (out) (array length=3): return location for an array of 3 * elements containing the skew factors (XY, XZ, and YZ respectively) * @rotate_p: (out caller-allocates): return location for a vertex containing * the Euler angles * @translate_p: (out caller-allocates): return location for a vertex * containing the translation vector * @perspective_p: (out caller-allocates: return location for a 4D vertex * containing the perspective * * Decomposes a #ClutterMatrix into the transformations that compose it. * * This code is based on the matrix decomposition algorithm as published in * the CSS Transforms specification by the W3C CSS working group, available * at http://www.w3.org/TR/css3-transforms/. * * The algorithm, in turn, is based on the "unmatrix" method published in * "Graphics Gems II, edited by Jim Arvo", which is available at: * http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c * * Return value: %TRUE if the decomposition was successful, and %FALSE * if the matrix is singular */ gboolean _clutter_util_matrix_decompose (const ClutterMatrix *src, ClutterVertex *scale_p, float shear_p[3], ClutterVertex *rotate_p, ClutterVertex *translate_p, ClutterVertex4 *perspective_p) { CoglMatrix matrix = *src; CoglMatrix perspective; ClutterVertex4 vertex_tmp; ClutterVertex row[3], pdum; int i, j; #define XY_SHEAR 0 #define XZ_SHEAR 1 #define YZ_SHEAR 2 #define MAT(m,r,c) ((float *)(m))[(c) * 4 + (r)] /* normalize the matrix */ if (matrix.ww == 0.f) return FALSE; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { MAT (&matrix, j, i) /= MAT (&matrix, 3, 3); } } /* perspective is used to solve for perspective, but it also provides * an easy way to test for singularity of the upper 3x3 component */ perspective = matrix; /* transpose */ MAT (&perspective, 3, 0) = 0.f; MAT (&perspective, 3, 1) = 0.f; MAT (&perspective, 3, 2) = 0.f; MAT (&perspective, 3, 3) = 1.f; if (_clutter_util_matrix_determinant (&perspective) == 0.f) return FALSE; if (MAT (&matrix, 3, 0) != 0.f || MAT (&matrix, 3, 1) != 0.f || MAT (&matrix, 3, 2) != 0.f) { CoglMatrix perspective_inv; ClutterVertex4 p; vertex_tmp.x = MAT (&matrix, 3, 0); vertex_tmp.y = MAT (&matrix, 3, 1); vertex_tmp.z = MAT (&matrix, 3, 2); vertex_tmp.w = MAT (&matrix, 3, 3); /* solve the equation by inverting perspective... */ cogl_matrix_get_inverse (&perspective, &perspective_inv); /* ... and multiplying vertex_tmp by the inverse */ _clutter_util_matrix_transpose_vector4_transform (&perspective_inv, &vertex_tmp, &p); *perspective_p = p; /* clear the perspective part */ MAT (&matrix, 3, 0) = 0.0f; MAT (&matrix, 3, 1) = 0.0f; MAT (&matrix, 3, 2) = 0.0f; MAT (&matrix, 3, 3) = 1.0f; } else { /* no perspective */ perspective_p->x = 0.0f; perspective_p->y = 0.0f; perspective_p->z = 0.0f; perspective_p->w = 1.0f; } /* translation */ translate_p->x = MAT (&matrix, 0, 3); MAT (&matrix, 0, 3) = 0.f; translate_p->y = MAT (&matrix, 1, 3); MAT (&matrix, 1, 3) = 0.f; translate_p->z = MAT (&matrix, 2, 3); MAT (&matrix, 2, 3) = 0.f; /* scale and shear; we split the upper 3x3 matrix into rows */ for (i = 0; i < 3; i++) { row[i].x = MAT (&matrix, i, 0); row[i].y = MAT (&matrix, i, 1); row[i].z = MAT (&matrix, i, 2); } /* compute scale.x and normalize the first row */ scale_p->x = _clutter_util_vertex_length (&row[0]); _clutter_util_vertex_normalize (&row[0]); /* compute XY shear and make the second row orthogonal to the first */ shear_p[XY_SHEAR] = _clutter_util_vertex_dot (&row[0], &row[1]); _clutter_util_vertex_combine (&row[1], &row[0], 1.0, -shear_p[XY_SHEAR], &row[1]); /* compute the Y scale and normalize the second row */ scale_p->y = _clutter_util_vertex_length (&row[1]); _clutter_util_vertex_normalize (&row[1]); shear_p[XY_SHEAR] /= scale_p->y; /* compute XZ and YZ shears, orthogonalize the third row */ shear_p[XZ_SHEAR] = _clutter_util_vertex_dot (&row[0], &row[2]); _clutter_util_vertex_combine (&row[2], &row[0], 1.0, -shear_p[XZ_SHEAR], &row[2]); shear_p[YZ_SHEAR] = _clutter_util_vertex_dot (&row[1], &row[2]); _clutter_util_vertex_combine (&row[2], &row[1], 1.0, -shear_p[YZ_SHEAR], &row[2]); /* get the Z scale and normalize the third row*/ scale_p->z = _clutter_util_vertex_length (&row[2]); _clutter_util_vertex_normalize (&row[2]); shear_p[XZ_SHEAR] /= scale_p->z; shear_p[YZ_SHEAR] /= scale_p->z; /* at this point, the matrix (inside row[]) is orthonormal. * check for a coordinate system flip; if the determinant * is -1, then negate the matrix and scaling factors */ _clutter_util_vertex_cross (&row[1], &row[2], &pdum); if (_clutter_util_vertex_dot (&row[0], &pdum) < 0.f) { scale_p->x *= -1.f; for (i = 0; i < 3; i++) { row[i].x *= -1.f; row[i].y *= -1.f; row[i].z *= -1.f; } } /* now get the rotations out */ rotate_p->y = asinf (-row[0].z); if (cosf (rotate_p->y) != 0.f) { rotate_p->x = atan2f (row[1].z, row[2].z); rotate_p->z = atan2f (row[0].y, row[0].x); } else { rotate_p->x = atan2f (-row[2].x, row[1].y); rotate_p->z = 0.f; } #undef XY_SHEAR #undef XZ_SHEAR #undef YZ_SHEAR #undef MAT return TRUE; } typedef struct { GType value_type; ClutterProgressFunc func; } ProgressData; G_LOCK_DEFINE_STATIC (progress_funcs); static GHashTable *progress_funcs = NULL; gboolean _clutter_has_progress_function (GType gtype) { const char *type_name = g_type_name (gtype); if (progress_funcs == NULL) return FALSE; return g_hash_table_lookup (progress_funcs, type_name) != NULL; } gboolean _clutter_run_progress_function (GType gtype, const GValue *initial, const GValue *final, gdouble progress, GValue *retval) { ProgressData *pdata; gboolean res; G_LOCK (progress_funcs); if (G_UNLIKELY (progress_funcs == NULL)) { res = FALSE; goto out; } pdata = g_hash_table_lookup (progress_funcs, g_type_name (gtype)); if (G_UNLIKELY (pdata == NULL)) { res = FALSE; goto out; } res = pdata->func (initial, final, progress, retval); out: G_UNLOCK (progress_funcs); return res; } static void progress_data_destroy (gpointer data_) { g_slice_free (ProgressData, data_); } /** * clutter_interval_register_progress_func: (skip) * @value_type: a #GType * @func: a #ClutterProgressFunc, or %NULL to unset a previously * set progress function * * Sets the progress function for a given @value_type, like: * * |[ * clutter_interval_register_progress_func (MY_TYPE_FOO, * my_foo_progress); * ]| * * Whenever a #ClutterInterval instance using the default * #ClutterInterval::compute_value implementation is set as an * interval between two #GValue of type @value_type, it will call * @func to establish the value depending on the given progress, * for instance: * * |[ * static gboolean * my_int_progress (const GValue *a, * const GValue *b, * gdouble progress, * GValue *retval) * { * gint ia = g_value_get_int (a); * gint ib = g_value_get_int (b); * gint res = factor * (ib - ia) + ia; * * g_value_set_int (retval, res); * * return TRUE; * } * * clutter_interval_register_progress_func (G_TYPE_INT, my_int_progress); * ]| * * To unset a previously set progress function of a #GType, pass %NULL * for @func. * * Since: 1.0 */ void clutter_interval_register_progress_func (GType value_type, ClutterProgressFunc func) { ProgressData *progress_func; const char *type_name; g_return_if_fail (value_type != G_TYPE_INVALID); type_name = g_type_name (value_type); G_LOCK (progress_funcs); if (G_UNLIKELY (progress_funcs == NULL)) progress_funcs = g_hash_table_new_full (NULL, NULL, NULL, progress_data_destroy); progress_func = g_hash_table_lookup (progress_funcs, type_name); if (G_UNLIKELY (progress_func)) { if (func == NULL) { g_hash_table_remove (progress_funcs, type_name); g_slice_free (ProgressData, progress_func); } else progress_func->func = func; } else { progress_func = g_slice_new (ProgressData); progress_func->value_type = value_type; progress_func->func = func; g_hash_table_replace (progress_funcs, (gpointer) type_name, progress_func); } G_UNLOCK (progress_funcs); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-keyframe-transition.c������������������������������������������0000664�0001750�0001750�00000053007�14211404421�024124� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-keyframe-transition * @Title: ClutterKeyframeTransition * @Short_Description: Keyframe property transition * * #ClutterKeyframeTransition allows animating a property by defining * "key frames": values at a normalized position on the transition * duration. * * The #ClutterKeyframeTransition interpolates the value of the property * to which it's bound across these key values. * * Setting up a #ClutterKeyframeTransition means providing the times, * values, and easing modes between these key frames, for instance: * * |[ * ClutterTransition *keyframe; * * keyframe = clutter_keyframe_transition_new ("opacity"); * clutter_transition_set_from (keyframe, G_TYPE_UINT, 255); * clutter_transition_set_to (keyframe, G_TYPE_UINT, 0); * clutter_keyframe_transition_set (CLUTTER_KEYFRAME_TRANSITION (keyframe), * G_TYPE_UINT, * 1, /* number of key frames */ * 0.5, 128, CLUTTER_EASE_IN_OUT_CUBIC); * ]| * * The example above sets up a keyframe transition for the #ClutterActor:opacity * property of a #ClutterActor; the transition starts and sets the value of the * property to fully transparent; between the start of the transition and its mid * point, it will animate the property to half opacity, using an easy in/easy out * progress. Once the transition reaches the mid point, it will linearly fade the * actor out until it reaches the end of the transition. * * The #ClutterKeyframeTransition will add an implicit key frame between the last * and the 1.0 value, to interpolate to the final value of the transition's * interval. * * #ClutterKeyframeTransition is available since Clutter 1.12. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-keyframe-transition.h" #include "clutter-debug.h" #include "clutter-easing.h" #include "clutter-interval.h" #include "clutter-private.h" #include "clutter-timeline.h" #include <math.h> #include <gobject/gvaluecollector.h> typedef struct _KeyFrame { double key; double start; double end; ClutterAnimationMode mode; ClutterInterval *interval; } KeyFrame; struct _ClutterKeyframeTransitionPrivate { GArray *frames; gint current_frame; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterKeyframeTransition, clutter_keyframe_transition, CLUTTER_TYPE_PROPERTY_TRANSITION) static void key_frame_free (gpointer data) { if (data != NULL) { KeyFrame *key = data; g_object_unref (key->interval); } } static int sort_by_key (gconstpointer a, gconstpointer b) { const KeyFrame *k_a = a; const KeyFrame *k_b = b; if (fabs (k_a->key - k_b->key) < 0.0001) return 0; if (k_a->key > k_a->key) return 1; return -1; } static inline void clutter_keyframe_transition_sort_frames (ClutterKeyframeTransition *transition) { if (transition->priv->frames != NULL) g_array_sort (transition->priv->frames, sort_by_key); } static inline void clutter_keyframe_transition_init_frames (ClutterKeyframeTransition *transition, gssize n_key_frames) { ClutterKeyframeTransitionPrivate *priv = transition->priv; guint i; priv->frames = g_array_sized_new (FALSE, FALSE, sizeof (KeyFrame), n_key_frames); g_array_set_clear_func (priv->frames, key_frame_free); /* we add an implicit key frame that goes to 1.0, so that the * user doesn't have to do that an can simply add key frames * in between 0.0 and 1.0 */ for (i = 0; i < n_key_frames + 1; i++) { KeyFrame frame; if (i == n_key_frames) frame.key = 1.0; else frame.key = 0.0; frame.mode = CLUTTER_LINEAR; frame.interval = NULL; g_array_insert_val (priv->frames, i, frame); } } static inline void clutter_keyframe_transition_update_frames (ClutterKeyframeTransition *transition) { ClutterKeyframeTransitionPrivate *priv = transition->priv; guint i; if (priv->frames == NULL) return; for (i = 0; i < priv->frames->len; i++) { KeyFrame *cur_frame = &g_array_index (priv->frames, KeyFrame, i); KeyFrame *prev_frame; if (i > 0) prev_frame = &g_array_index (priv->frames, KeyFrame, i - 1); else prev_frame = NULL; if (prev_frame != NULL) { cur_frame->start = prev_frame->key; if (prev_frame->interval != NULL) { const GValue *value; value = clutter_interval_peek_final_value (prev_frame->interval); if (cur_frame->interval != NULL) clutter_interval_set_initial_value (cur_frame->interval, value); else { cur_frame->interval = clutter_interval_new_with_values (G_VALUE_TYPE (value), value, NULL); } } } else cur_frame->start = 0.0; cur_frame->end = cur_frame->key; } } static void clutter_keyframe_transition_compute_value (ClutterTransition *transition, ClutterAnimatable *animatable, ClutterInterval *interval, gdouble progress) { ClutterKeyframeTransition *self = CLUTTER_KEYFRAME_TRANSITION (transition); ClutterTimeline *timeline = CLUTTER_TIMELINE (transition); ClutterKeyframeTransitionPrivate *priv = self->priv; ClutterTransitionClass *parent_class; ClutterTimelineDirection direction; ClutterInterval *real_interval; gdouble real_progress; double t, d, p; KeyFrame *cur_frame = NULL; real_interval = interval; real_progress = progress; /* if we don't have any keyframe, we behave like our parent class */ if (priv->frames == NULL) goto out; direction = clutter_timeline_get_direction (timeline); /* we need a normalized linear value */ t = clutter_timeline_get_elapsed_time (timeline); d = clutter_timeline_get_duration (timeline); p = t / d; if (priv->current_frame < 0) { if (direction == CLUTTER_TIMELINE_FORWARD) priv->current_frame = 0; else priv->current_frame = priv->frames->len - 1; } cur_frame = &g_array_index (priv->frames, KeyFrame, priv->current_frame); /* skip to the next key frame, depending on the direction of the timeline */ if (direction == CLUTTER_TIMELINE_FORWARD) { if (p > cur_frame->end) { priv->current_frame = MIN (priv->current_frame + 1, priv->frames->len - 1); cur_frame = &g_array_index (priv->frames, KeyFrame, priv->current_frame); } } else { if (p < cur_frame->start) { priv->current_frame = MAX (priv->current_frame - 1, 0); cur_frame = &g_array_index (priv->frames, KeyFrame, priv->current_frame); } } /* if we are at the boundaries of the transition, use the from and to * value from the transition */ if (priv->current_frame == 0) { const GValue *value; value = clutter_interval_peek_initial_value (interval); clutter_interval_set_initial_value (cur_frame->interval, value); } else if (priv->current_frame == priv->frames->len - 1) { const GValue *value; cur_frame->mode = clutter_timeline_get_progress_mode (timeline); value = clutter_interval_peek_final_value (interval); clutter_interval_set_final_value (cur_frame->interval, value); } /* update the interval to be used to interpolate the property */ real_interval = cur_frame->interval; /* normalize the progress and apply the easing mode */ real_progress = clutter_easing_for_mode ( cur_frame->mode, (p - cur_frame->start), (cur_frame->end - cur_frame->start)); #ifdef CLUTTER_ENABLE_DEBUG if (CLUTTER_HAS_DEBUG (ANIMATION)) { char *from, *to; const GValue *value; value = clutter_interval_peek_initial_value (cur_frame->interval); from = g_strdup_value_contents (value); value = clutter_interval_peek_final_value (cur_frame->interval); to = g_strdup_value_contents (value); CLUTTER_NOTE (ANIMATION, "cur_frame [%d] => { %g, %s, %s %s %s } - " "progress: %g, sub-progress: %g\n", priv->current_frame, cur_frame->key, clutter_get_easing_name_for_mode (cur_frame->mode), from, direction == CLUTTER_TIMELINE_FORWARD ? "->" : "<-", to, p, real_progress); free (from); free (to); } #endif /* CLUTTER_ENABLE_DEBUG */ out: parent_class = CLUTTER_TRANSITION_CLASS (clutter_keyframe_transition_parent_class); parent_class->compute_value (transition, animatable, real_interval, real_progress); } static void clutter_keyframe_transition_started (ClutterTimeline *timeline) { ClutterKeyframeTransition *transition; transition = CLUTTER_KEYFRAME_TRANSITION (timeline); transition->priv->current_frame = -1; clutter_keyframe_transition_sort_frames (transition); clutter_keyframe_transition_update_frames (transition); } static void clutter_keyframe_transition_completed (ClutterTimeline *timeline) { ClutterKeyframeTransitionPrivate *priv; priv = CLUTTER_KEYFRAME_TRANSITION (timeline)->priv; priv->current_frame = -1; } static void clutter_keyframe_transition_finalize (GObject *gobject) { ClutterKeyframeTransitionPrivate *priv; priv = CLUTTER_KEYFRAME_TRANSITION (gobject)->priv; if (priv->frames != NULL) g_array_unref (priv->frames); G_OBJECT_CLASS (clutter_keyframe_transition_parent_class)->finalize (gobject); } static void clutter_keyframe_transition_class_init (ClutterKeyframeTransitionClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterTimelineClass *timeline_class = CLUTTER_TIMELINE_CLASS (klass); ClutterTransitionClass *transition_class = CLUTTER_TRANSITION_CLASS (klass); gobject_class->finalize = clutter_keyframe_transition_finalize; timeline_class->started = clutter_keyframe_transition_started; timeline_class->completed = clutter_keyframe_transition_completed; transition_class->compute_value = clutter_keyframe_transition_compute_value; } static void clutter_keyframe_transition_init (ClutterKeyframeTransition *self) { self->priv = clutter_keyframe_transition_get_instance_private (self); } /** * clutter_keyframe_transition_new: * @property_name: the property to animate * * Creates a new #ClutterKeyframeTransition for @property_name. * * Return value: (transfer full): the newly allocated * #ClutterKeyframeTransition instance. Use g_object_unref() when * done to free its resources. * * Since: 1.12 */ ClutterTransition * clutter_keyframe_transition_new (const char *property_name) { return g_object_new (CLUTTER_TYPE_KEYFRAME_TRANSITION, "property-name", property_name, NULL); } /** * clutter_keyframe_transition_set_key_frames: * @transition: a #ClutterKeyframeTransition * @n_key_frames: the number of values * @key_frames: (array length=n_key_frames): an array of keys between 0.0 * and 1.0, one for each key frame * * Sets the keys for each key frame inside @transition. * * If @transition does not hold any key frame, @n_key_frames key frames * will be created; if @transition already has key frames, @key_frames must * have at least as many elements as the number of key frames. * * Since: 1.12 */ void clutter_keyframe_transition_set_key_frames (ClutterKeyframeTransition *transition, guint n_key_frames, const double *key_frames) { ClutterKeyframeTransitionPrivate *priv; guint i; g_return_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition)); g_return_if_fail (n_key_frames > 0); g_return_if_fail (key_frames != NULL); priv = transition->priv; if (priv->frames == NULL) clutter_keyframe_transition_init_frames (transition, n_key_frames); else g_return_if_fail (n_key_frames == priv->frames->len - 1); for (i = 0; i < n_key_frames; i++) { KeyFrame *frame = &g_array_index (priv->frames, KeyFrame, i); frame->key = key_frames[i]; } } /** * clutter_keyframe_transition_set_values: * @transition: a #ClutterKeyframeTransition * @n_values: the number of values * @values: (array length=n_values): an array of values, one for each * key frame * * Sets the values for each key frame inside @transition. * * If @transition does not hold any key frame, @n_values key frames will * be created; if @transition already has key frames, @values must have * at least as many elements as the number of key frames. * * Since: 1.12 */ void clutter_keyframe_transition_set_values (ClutterKeyframeTransition *transition, guint n_values, const GValue *values) { ClutterKeyframeTransitionPrivate *priv; guint i; g_return_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition)); g_return_if_fail (n_values > 0); g_return_if_fail (values != NULL); priv = transition->priv; if (priv->frames == NULL) clutter_keyframe_transition_init_frames (transition, n_values); else g_return_if_fail (n_values == priv->frames->len - 1); for (i = 0; i < n_values; i++) { KeyFrame *frame = &g_array_index (priv->frames, KeyFrame, i); if (frame->interval) clutter_interval_set_final_value (frame->interval, &values[i]); else frame->interval = clutter_interval_new_with_values (G_VALUE_TYPE (&values[i]), NULL, &values[i]); } } /** * clutter_keyframe_transition_set_modes: * @transition: a #ClutterKeyframeTransition * @n_modes: the number of easing modes * @modes: (array length=n_modes): an array of easing modes, one for * each key frame * * Sets the easing modes for each key frame inside @transition. * * If @transition does not hold any key frame, @n_modes key frames will * be created; if @transition already has key frames, @modes must have * at least as many elements as the number of key frames. * * Since: 1.12 */ void clutter_keyframe_transition_set_modes (ClutterKeyframeTransition *transition, guint n_modes, const ClutterAnimationMode *modes) { ClutterKeyframeTransitionPrivate *priv; guint i; g_return_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition)); g_return_if_fail (n_modes > 0); g_return_if_fail (modes != NULL); priv = transition->priv; if (priv->frames == NULL) clutter_keyframe_transition_init_frames (transition, n_modes); else g_return_if_fail (n_modes == priv->frames->len - 1); for (i = 0; i < n_modes; i++) { KeyFrame *frame = &g_array_index (priv->frames, KeyFrame, i); frame->mode = modes[i]; } } /** * clutter_keyframe_transition_set: (skip) * @transition: a #ClutterKeyframeTransition * @gtype: the type of the values to use for the key frames * @n_key_frames: the number of key frames between the initial * and final values * @...: a list of tuples, containing the key frame index, the value * at the key frame, and the animation mode * * Sets the key frames of the @transition. * * This variadic arguments function is a convenience for C developers; * language bindings should use clutter_keyframe_transition_set_key_frames(), * clutter_keyframe_transition_set_modes(), and * clutter_keyframe_transition_set_values() instead. * * Since: 1.12 */ void clutter_keyframe_transition_set (ClutterKeyframeTransition *transition, GType gtype, guint n_key_frames, ...) { ClutterKeyframeTransitionPrivate *priv; va_list args; guint i; g_return_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition)); g_return_if_fail (gtype != G_TYPE_INVALID); g_return_if_fail (n_key_frames > 0); priv = transition->priv; if (priv->frames == NULL) clutter_keyframe_transition_init_frames (transition, n_key_frames); else g_return_if_fail (n_key_frames == priv->frames->len - 1); va_start (args, n_key_frames); for (i = 0; i < n_key_frames; i++) { KeyFrame *frame = &g_array_index (priv->frames, KeyFrame, i); GValue value = G_VALUE_INIT; char *error = NULL; frame->key = va_arg (args, double); G_VALUE_COLLECT_INIT (&value, gtype, args, 0, &error); if (error != NULL) { g_warning ("%s: %s", G_STRLOC, error); free (error); break; } frame->mode = va_arg (args, ClutterAnimationMode); g_clear_object (&frame->interval); frame->interval = clutter_interval_new_with_values (gtype, NULL, &value); g_value_unset (&value); } va_end (args); } /** * clutter_keyframe_transition_clear: * @transition: a #ClutterKeyframeTransition * * Removes all key frames from @transition. * * Since: 1.12 */ void clutter_keyframe_transition_clear (ClutterKeyframeTransition *transition) { g_return_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition)); if (transition->priv->frames != NULL) { g_array_unref (transition->priv->frames); transition->priv->frames = NULL; } } /** * clutter_keyframe_transition_get_n_key_frames: * @transition: a #ClutterKeyframeTransition * * Retrieves the number of key frames inside @transition. * * Return value: the number of key frames * * Since: 1.12 */ guint clutter_keyframe_transition_get_n_key_frames (ClutterKeyframeTransition *transition) { g_return_val_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition), 0); if (transition->priv->frames == NULL) return 0; return transition->priv->frames->len - 1; } /** * clutter_keyframe_transition_set_key_frame: * @transition: a #ClutterKeyframeTransition * @index_: the index of the key frame * @key: the key of the key frame * @mode: the easing mode of the key frame * @value: a #GValue containing the value of the key frame * * Sets the details of the key frame at @index_ inside @transition. * * The @transition must already have a key frame at @index_, and @index_ * must be smaller than the number of key frames inside @transition. * * Since: 1.12 */ void clutter_keyframe_transition_set_key_frame (ClutterKeyframeTransition *transition, guint index_, double key, ClutterAnimationMode mode, const GValue *value) { ClutterKeyframeTransitionPrivate *priv; KeyFrame *frame; g_return_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition)); priv = transition->priv; g_return_if_fail (priv->frames != NULL); g_return_if_fail (index_ < priv->frames->len - 1); frame = &g_array_index (priv->frames, KeyFrame, index_); frame->key = key; frame->mode = mode; clutter_interval_set_final_value (frame->interval, value); } /** * clutter_keyframe_transition_get_key_frame: * @transition: a #ClutterKeyframeTransition * @index_: the index of the key frame * @key: (out) (allow-none): return location for the key, or %NULL * @mode: (out) (allow-none): return location for the easing mode, or %NULL * @value: (out caller-allocates): a #GValue initialized with the type of * the values * * Retrieves the details of the key frame at @index_ inside @transition. * * The @transition must already have key frames set, and @index_ must be * smaller than the number of key frames. * * Since: 1.12 */ void clutter_keyframe_transition_get_key_frame (ClutterKeyframeTransition *transition, guint index_, double *key, ClutterAnimationMode *mode, GValue *value) { ClutterKeyframeTransitionPrivate *priv; const KeyFrame *frame; g_return_if_fail (CLUTTER_IS_KEYFRAME_TRANSITION (transition)); priv = transition->priv; g_return_if_fail (priv->frames != NULL); g_return_if_fail (index_ < priv->frames->len - 1); frame = &g_array_index (priv->frames, KeyFrame, index_); if (key != NULL) *key = frame->key; if (mode != NULL) *mode = frame->mode; if (value != NULL) clutter_interval_get_final_value (frame->interval, value); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-deform-effect.c������������������������������������������������0000664�0001750�0001750�00000060264�14211404421�022642� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> * * Based on the MxDeformTexture class, written by: * Chris Lord <chris@linux.intel.com> */ /** * SECTION:clutter-deform-effect * @Title: ClutterDeformEffect * @Short_Description: A base class for effects deforming the geometry * of an actor * * #ClutterDeformEffect is an abstract class providing all the plumbing * for creating effects that result in the deformation of an actor's * geometry. * * #ClutterDeformEffect uses offscreen buffers to render the contents of * a #ClutterActor and then the Cogl vertex buffers API to submit the * geometry to the GPU. * * #ClutterDeformEffect is available since Clutter 1.4 * * ## Implementing ClutterDeformEffect * * Sub-classes of #ClutterDeformEffect should override the * #ClutterDeformEffectClass.deform_vertex() virtual function; this function * is called on every vertex that needs to be deformed by the effect. * Each passed vertex is an in-out parameter that initially contains the * position of the vertex and should be modified according to a specific * deformation algorithm. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-deform-effect.h" #include <cogl/cogl.h> #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-offscreen-effect-private.h" #include "clutter-private.h" #define DEFAULT_N_TILES 32 struct _ClutterDeformEffectPrivate { CoglPipeline *back_pipeline; gint x_tiles; gint y_tiles; CoglAttributeBuffer *buffer; CoglPrimitive *primitive; CoglPrimitive *lines_primitive; gint n_vertices; gulong allocation_id; guint is_dirty : 1; }; enum { PROP_0, PROP_X_TILES, PROP_Y_TILES, PROP_BACK_MATERIAL, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterDeformEffect, clutter_deform_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT) static void clutter_deform_effect_real_deform_vertex (ClutterDeformEffect *effect, gfloat width, gfloat height, CoglTextureVertex *vertex) { g_warning ("%s: Deformation effect of type '%s' does not implement " "the required ClutterDeformEffect::deform_vertex virtual " "function.", G_STRLOC, G_OBJECT_TYPE_NAME (effect)); } static void clutter_deform_effect_deform_vertex (ClutterDeformEffect *effect, gfloat width, gfloat height, CoglTextureVertex *vertex) { CLUTTER_DEFORM_EFFECT_GET_CLASS (effect)->deform_vertex (effect, width, height, vertex); } static void vbo_invalidate (ClutterActor *actor, const ClutterActorBox *allocation, ClutterAllocationFlags flags, ClutterDeformEffect *effect) { effect->priv->is_dirty = TRUE; } static void clutter_deform_effect_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (meta)->priv; if (priv->allocation_id != 0) { ClutterActor *old_actor = clutter_actor_meta_get_actor (meta); if (old_actor != NULL) g_signal_handler_disconnect (old_actor, priv->allocation_id); priv->allocation_id = 0; } /* we need to invalidate the VBO whenever the allocation of the actor * changes */ if (actor != NULL) priv->allocation_id = g_signal_connect (actor, "allocation-changed", G_CALLBACK (vbo_invalidate), meta); priv->is_dirty = TRUE; CLUTTER_ACTOR_META_CLASS (clutter_deform_effect_parent_class)->set_actor (meta, actor); } static void clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect); ClutterDeformEffectPrivate *priv = self->priv; CoglHandle material; CoglPipeline *pipeline; CoglDepthState depth_state; CoglFramebuffer *fb = cogl_get_draw_framebuffer (); if (priv->is_dirty) { ClutterRect rect; gboolean mapped_buffer; CoglVertexP3T2C4 *verts; ClutterActor *actor; gfloat width, height; guint opacity; gint i, j; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); opacity = clutter_actor_get_paint_opacity (actor); /* if we don't have a target size, fall back to the actor's * allocation, though wrong it might be */ if (clutter_offscreen_effect_get_target_rect (effect, &rect)) { width = clutter_rect_get_width (&rect); height = clutter_rect_get_height (&rect); } else clutter_actor_get_size (actor, &width, &height); /* XXX ideally, the sub-classes should tell us what they * changed in the texture vertices; we then would be able to * avoid resubmitting the same data, if it did not change. for * the time being, we resubmit everything */ verts = cogl_buffer_map (COGL_BUFFER (priv->buffer), COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD); /* If the map failed then we'll resort to allocating a temporary buffer */ if (verts == NULL) { mapped_buffer = FALSE; verts = malloc (sizeof (*verts) * priv->n_vertices); } else mapped_buffer = TRUE; for (i = 0; i < priv->y_tiles + 1; i++) { for (j = 0; j < priv->x_tiles + 1; j++) { CoglVertexP3T2C4 *vertex_out; CoglTextureVertex vertex; /* CoglTextureVertex isn't an ideal structure to use for this because it contains a CoglColor. The internal layout of CoglColor is mean to be private so Clutter can not pass a pointer to it as a vertex attribute. Also it contains padding so we end up storing more data in the vertex buffer than we need to. Instead we let the application modify a dummy vertex and then copy the details back out to a more well-defined struct */ vertex.tx = (float) j / priv->x_tiles; vertex.ty = (float) i / priv->y_tiles; vertex.x = width * vertex.tx; vertex.y = height * vertex.ty; vertex.z = 0.0f; cogl_color_init_from_4ub (&vertex.color, 255, 255, 255, opacity); clutter_deform_effect_deform_vertex (self, width, height, &vertex); vertex_out = verts + i * (priv->x_tiles + 1) + j; vertex_out->x = vertex.x; vertex_out->y = vertex.y; vertex_out->z = vertex.z; vertex_out->s = vertex.tx; vertex_out->t = vertex.ty; vertex_out->r = cogl_color_get_red_byte (&vertex.color); vertex_out->g = cogl_color_get_green_byte (&vertex.color); vertex_out->b = cogl_color_get_blue_byte (&vertex.color); vertex_out->a = cogl_color_get_alpha_byte (&vertex.color); } } if (mapped_buffer) cogl_buffer_unmap (COGL_BUFFER (priv->buffer)); else { cogl_buffer_set_data (COGL_BUFFER (priv->buffer), 0, /* offset */ verts, sizeof (*verts) * priv->n_vertices); free (verts); } priv->is_dirty = FALSE; } material = clutter_offscreen_effect_get_target (effect); pipeline = COGL_PIPELINE (material); /* enable depth testing */ cogl_depth_state_init (&depth_state); cogl_depth_state_set_test_enabled (&depth_state, TRUE); cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL); /* enable backface culling if we have a back material */ if (priv->back_pipeline != NULL) cogl_pipeline_set_cull_face_mode (pipeline, COGL_PIPELINE_CULL_FACE_MODE_BACK); /* draw the front */ if (material != NULL) cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive); /* draw the back */ if (priv->back_pipeline != NULL) { CoglPipeline *back_pipeline; /* We probably shouldn't be modifying the user's material so instead we make a temporary copy */ back_pipeline = cogl_pipeline_copy (priv->back_pipeline); cogl_pipeline_set_depth_state (back_pipeline, &depth_state, NULL); cogl_pipeline_set_cull_face_mode (back_pipeline, COGL_PIPELINE_CULL_FACE_MODE_FRONT); cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive); cogl_object_unref (back_pipeline); } if (G_UNLIKELY (priv->lines_primitive != NULL)) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); CoglPipeline *lines_pipeline = cogl_pipeline_new (ctx); cogl_pipeline_set_color4f (lines_pipeline, 1.0, 0, 0, 1.0); cogl_framebuffer_draw_primitive (fb, lines_pipeline, priv->lines_primitive); cogl_object_unref (lines_pipeline); } } static inline void clutter_deform_effect_free_arrays (ClutterDeformEffect *self) { ClutterDeformEffectPrivate *priv = self->priv; if (priv->buffer) { cogl_object_unref (priv->buffer); priv->buffer = NULL; } if (priv->primitive) { cogl_object_unref (priv->primitive); priv->primitive = NULL; } if (priv->lines_primitive) { cogl_object_unref (priv->lines_primitive); priv->lines_primitive = NULL; } } static void clutter_deform_effect_init_arrays (ClutterDeformEffect *self) { ClutterDeformEffectPrivate *priv = self->priv; gint x, y, direction, n_indices; CoglAttribute *attributes[3]; guint16 *static_indices; CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); CoglIndices *indices; guint16 *idx; int i; clutter_deform_effect_free_arrays (self); n_indices = ((2 + 2 * priv->x_tiles) * priv->y_tiles + (priv->y_tiles - 1)); static_indices = g_new (guint16, n_indices); #define MESH_INDEX(x,y) ((y) * (priv->x_tiles + 1) + (x)) /* compute all the triangles from the various tiles */ direction = 1; idx = static_indices; idx[0] = MESH_INDEX (0, 0); idx[1] = MESH_INDEX (0, 1); idx += 2; for (y = 0; y < priv->y_tiles; y++) { for (x = 0; x < priv->x_tiles; x++) { if (direction) { idx[0] = MESH_INDEX (x + 1, y); idx[1] = MESH_INDEX (x + 1, y + 1); } else { idx[0] = MESH_INDEX (priv->x_tiles - x - 1, y); idx[1] = MESH_INDEX (priv->x_tiles - x - 1, y + 1); } idx += 2; } if (y == (priv->y_tiles - 1)) break; if (direction) { idx[0] = MESH_INDEX (priv->x_tiles, y + 1); idx[1] = MESH_INDEX (priv->x_tiles, y + 1); idx[2] = MESH_INDEX (priv->x_tiles, y + 2); } else { idx[0] = MESH_INDEX (0, y + 1); idx[1] = MESH_INDEX (0, y + 1); idx[2] = MESH_INDEX (0, y + 2); } idx += 3; direction = !direction; } #undef MESH_INDEX indices = cogl_indices_new (ctx, COGL_INDICES_TYPE_UNSIGNED_SHORT, static_indices, n_indices); free (static_indices); priv->n_vertices = (priv->x_tiles + 1) * (priv->y_tiles + 1); priv->buffer = cogl_attribute_buffer_new (ctx, sizeof (CoglVertexP3T2C4) * priv->n_vertices, NULL); /* The application is expected to continuously modify the vertices so we should give a hint to Cogl about that */ cogl_buffer_set_update_hint (COGL_BUFFER (priv->buffer), COGL_BUFFER_UPDATE_HINT_DYNAMIC); attributes[0] = cogl_attribute_new (priv->buffer, "cogl_position_in", sizeof (CoglVertexP3T2C4), G_STRUCT_OFFSET (CoglVertexP3T2C4, x), 3, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (priv->buffer, "cogl_tex_coord0_in", sizeof (CoglVertexP3T2C4), G_STRUCT_OFFSET (CoglVertexP3T2C4, s), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); attributes[2] = cogl_attribute_new (priv->buffer, "cogl_color_in", sizeof (CoglVertexP3T2C4), G_STRUCT_OFFSET (CoglVertexP3T2C4, r), 4, /* n_components */ COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); priv->primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLE_STRIP, priv->n_vertices, attributes, 3 /* n_attributes */); cogl_primitive_set_indices (priv->primitive, indices, n_indices); if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DEFORM_TILES)) { priv->lines_primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_LINE_STRIP, priv->n_vertices, attributes, 2 /* n_attributes */); cogl_primitive_set_indices (priv->lines_primitive, indices, n_indices); } cogl_object_unref (indices); for (i = 0; i < 3; i++) cogl_object_unref (attributes[i]); priv->is_dirty = TRUE; } static inline void clutter_deform_effect_free_back_pipeline (ClutterDeformEffect *self) { ClutterDeformEffectPrivate *priv = self->priv; if (priv->back_pipeline != NULL) { cogl_object_unref (priv->back_pipeline); priv->back_pipeline = NULL; } } static void clutter_deform_effect_finalize (GObject *gobject) { ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject); clutter_deform_effect_free_arrays (self); clutter_deform_effect_free_back_pipeline (self); G_OBJECT_CLASS (clutter_deform_effect_parent_class)->finalize (gobject); } static void clutter_deform_effect_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject); switch (prop_id) { case PROP_X_TILES: clutter_deform_effect_set_n_tiles (self, g_value_get_uint (value), self->priv->y_tiles); break; case PROP_Y_TILES: clutter_deform_effect_set_n_tiles (self, self->priv->x_tiles, g_value_get_uint (value)); break; case PROP_BACK_MATERIAL: clutter_deform_effect_set_back_material (self, g_value_get_boxed (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_deform_effect_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (gobject)->priv; switch (prop_id) { case PROP_X_TILES: g_value_set_uint (value, priv->x_tiles); break; case PROP_Y_TILES: g_value_set_uint (value, priv->y_tiles); break; case PROP_BACK_MATERIAL: g_value_set_boxed (value, priv->back_pipeline); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_deform_effect_class_init (ClutterDeformEffectClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); ClutterOffscreenEffectClass *offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); klass->deform_vertex = clutter_deform_effect_real_deform_vertex; /** * ClutterDeformEffect:x-tiles: * * The number of horizontal tiles. The bigger the number, the * smaller the tiles * * Since: 1.4 */ obj_props[PROP_X_TILES] = g_param_spec_uint ("x-tiles", P_("Horizontal Tiles"), P_("The number of horizontal tiles"), 1, G_MAXUINT, DEFAULT_N_TILES, CLUTTER_PARAM_READWRITE); /** * ClutterDeformEffect:y-tiles: * * The number of vertical tiles. The bigger the number, the * smaller the tiles * * Since: 1.4 */ obj_props[PROP_Y_TILES] = g_param_spec_uint ("y-tiles", P_("Vertical Tiles"), P_("The number of vertical tiles"), 1, G_MAXUINT, DEFAULT_N_TILES, CLUTTER_PARAM_READWRITE); /** * ClutterDeformEffect:back-material: * * A material to be used when painting the back of the actor * to which this effect has been applied * * By default, no material will be used * * Since: 1.4 */ obj_props[PROP_BACK_MATERIAL] = g_param_spec_boxed ("back-material", P_("Back Material"), P_("The material to be used when painting the back of the actor"), COGL_TYPE_HANDLE, CLUTTER_PARAM_READWRITE); gobject_class->finalize = clutter_deform_effect_finalize; gobject_class->set_property = clutter_deform_effect_set_property; gobject_class->get_property = clutter_deform_effect_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); meta_class->set_actor = clutter_deform_effect_set_actor; offscreen_class->paint_target = clutter_deform_effect_paint_target; } static void clutter_deform_effect_init (ClutterDeformEffect *self) { self->priv = clutter_deform_effect_get_instance_private (self); self->priv->x_tiles = self->priv->y_tiles = DEFAULT_N_TILES; self->priv->back_pipeline = NULL; clutter_deform_effect_init_arrays (self); } /** * clutter_deform_effect_set_back_material: * @effect: a #ClutterDeformEffect * @material: (allow-none): a handle to a Cogl material * * Sets the material that should be used when drawing the back face * of the actor during a deformation * * The #ClutterDeformEffect will take a reference on the material's * handle * * Since: 1.4 */ void clutter_deform_effect_set_back_material (ClutterDeformEffect *effect, CoglHandle material) { ClutterDeformEffectPrivate *priv; CoglPipeline *pipeline = COGL_PIPELINE (material); g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect)); g_return_if_fail (pipeline == NULL || cogl_is_pipeline (pipeline)); priv = effect->priv; clutter_deform_effect_free_back_pipeline (effect); priv->back_pipeline = material; if (priv->back_pipeline != NULL) cogl_object_ref (priv->back_pipeline); clutter_deform_effect_invalidate (effect); } /** * clutter_deform_effect_get_back_material: * @effect: a #ClutterDeformEffect * * Retrieves the handle to the back face material used by @effect * * Return value: (transfer none): a handle for the material, or %NULL. * The returned material is owned by the #ClutterDeformEffect and it * should not be freed directly * * Since: 1.4 */ CoglHandle clutter_deform_effect_get_back_material (ClutterDeformEffect *effect) { g_return_val_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect), NULL); return effect->priv->back_pipeline; } /** * clutter_deform_effect_set_n_tiles: * @effect: a #ClutterDeformEffect * @x_tiles: number of horizontal tiles * @y_tiles: number of vertical tiles * * Sets the number of horizontal and vertical tiles to be used * when applying the effect * * More tiles allow a finer grained deformation at the expenses * of computation * * Since: 1.4 */ void clutter_deform_effect_set_n_tiles (ClutterDeformEffect *effect, guint x_tiles, guint y_tiles) { ClutterDeformEffectPrivate *priv; gboolean tiles_changed = FALSE; g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect)); g_return_if_fail (x_tiles > 0 && y_tiles > 0); priv = effect->priv; g_object_freeze_notify (G_OBJECT (effect)); if (priv->x_tiles != x_tiles) { priv->x_tiles = x_tiles; g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_X_TILES]); tiles_changed = TRUE; } if (priv->y_tiles != y_tiles) { priv->y_tiles = y_tiles; g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_Y_TILES]); tiles_changed = TRUE; } if (tiles_changed) { clutter_deform_effect_init_arrays (effect); clutter_deform_effect_invalidate (effect); } g_object_thaw_notify (G_OBJECT (effect)); } /** * clutter_deform_effect_get_n_tiles: * @effect: a #ClutterDeformEffect * @x_tiles: (out): return location for the number of horizontal tiles, * or %NULL * @y_tiles: (out): return location for the number of vertical tiles, * or %NULL * * Retrieves the number of horizontal and vertical tiles used to sub-divide * the actor's geometry during the effect * * Since: 1.4 */ void clutter_deform_effect_get_n_tiles (ClutterDeformEffect *effect, guint *x_tiles, guint *y_tiles) { g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect)); if (x_tiles != NULL) *x_tiles = effect->priv->x_tiles; if (y_tiles != NULL) *y_tiles = effect->priv->y_tiles; } /** * clutter_deform_effect_invalidate: * @effect: a #ClutterDeformEffect * * Invalidates the @effect<!-- -->'s vertices and, if it is associated * to an actor, it will queue a redraw * * Since: 1.4 */ void clutter_deform_effect_invalidate (ClutterDeformEffect *effect) { ClutterActor *actor; g_return_if_fail (CLUTTER_IS_DEFORM_EFFECT (effect)); if (effect->priv->is_dirty) return; effect->priv->is_dirty = TRUE; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); if (actor != NULL) clutter_effect_queue_repaint (CLUTTER_EFFECT (effect)); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-clone.c��������������������������������������������������������0000664�0001750�0001750�00000032166�14211404421�021234� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * Authored By: Robert Bragg <robert@linux.intel.com> * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-clone * @short_description: An actor that displays a clone of a source actor * * #ClutterClone is a #ClutterActor which draws with the paint * function of another actor, scaled to fit its own allocation. * * #ClutterClone can be used to efficiently clone any other actor. * * Unlike clutter_texture_new_from_actor(), #ClutterClone does not require * the presence of support for FBOs in the underlying GL or GLES * implementation. * * #ClutterClone is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-actor-private.h" #include "clutter-clone.h" #include "clutter-debug.h" #include "clutter-main.h" #include "clutter-paint-volume-private.h" #include "clutter-private.h" #include "cogl/cogl.h" struct _ClutterClonePrivate { ClutterActor *clone_source; gulong source_destroy_id; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterClone, clutter_clone, CLUTTER_TYPE_ACTOR) enum { PROP_0, PROP_SOURCE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; static void clutter_clone_set_source_internal (ClutterClone *clone, ClutterActor *source); static void clutter_clone_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActor *clone_source = priv->clone_source; if (clone_source == NULL) { if (min_width_p) *min_width_p = 0; if (natural_width_p) *natural_width_p = 0; } else clutter_actor_get_preferred_width (clone_source, for_height, min_width_p, natural_width_p); } static void clutter_clone_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActor *clone_source = priv->clone_source; if (clone_source == NULL) { if (min_height_p) *min_height_p = 0; if (natural_height_p) *natural_height_p = 0; } else clutter_actor_get_preferred_height (clone_source, for_width, min_height_p, natural_height_p); } static void clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActorBox box, source_box; gfloat x_scale, y_scale; /* First chain up and apply all the standard ClutterActor * transformations... */ CLUTTER_ACTOR_CLASS (clutter_clone_parent_class)->apply_transform (self, matrix); /* if we don't have a source, nothing else to do */ if (priv->clone_source == NULL) return; /* get our allocated size */ clutter_actor_get_allocation_box (self, &box); /* and get the allocated size of the source */ clutter_actor_get_allocation_box (priv->clone_source, &source_box); /* We need to scale what the clone-source actor paints to fill our own * allocation... */ x_scale = clutter_actor_box_get_width (&box) / clutter_actor_box_get_width (&source_box); y_scale = clutter_actor_box_get_height (&box) / clutter_actor_box_get_height (&source_box); cogl_matrix_scale (matrix, x_scale, y_scale, x_scale); } static void clutter_clone_paint (ClutterActor *actor) { ClutterClone *self = CLUTTER_CLONE (actor); ClutterClonePrivate *priv = self->priv; gboolean was_unmapped = FALSE; if (priv->clone_source == NULL) return; CLUTTER_NOTE (PAINT, "painting clone actor '%s'", _clutter_actor_get_debug_name (actor)); /* The final bits of magic: * - We need to override the paint opacity of the actor with our own * opacity. * - We need to inform the actor that it's in a clone paint (for the function * clutter_actor_is_in_clone_paint()) * - We need to stop clutter_actor_paint applying the model view matrix of * the clone source actor. */ _clutter_actor_set_in_clone_paint (priv->clone_source, TRUE); clutter_actor_set_opacity_override (priv->clone_source, clutter_actor_get_paint_opacity (actor)); _clutter_actor_set_enable_model_view_transform (priv->clone_source, FALSE); if (!clutter_actor_is_mapped (priv->clone_source)) { _clutter_actor_set_enable_paint_unmapped (priv->clone_source, TRUE); was_unmapped = TRUE; } /* If the source isn't ultimately parented to a toplevel, it can't be * realized or painted. */ if (clutter_actor_is_realized (priv->clone_source)) { _clutter_actor_push_clone_paint (); clutter_actor_paint (priv->clone_source); _clutter_actor_pop_clone_paint (); } if (was_unmapped) _clutter_actor_set_enable_paint_unmapped (priv->clone_source, FALSE); _clutter_actor_set_enable_model_view_transform (priv->clone_source, TRUE); clutter_actor_set_opacity_override (priv->clone_source, -1); _clutter_actor_set_in_clone_paint (priv->clone_source, FALSE); } static gboolean clutter_clone_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { ClutterClonePrivate *priv = CLUTTER_CLONE (actor)->priv; const ClutterPaintVolume *source_volume; /* if the source is not set the paint volume is defined to be empty */ if (priv->clone_source == NULL) return TRUE; /* query the volume of the source actor and simply masquarade it as * the clones volume... */ source_volume = clutter_actor_get_paint_volume (priv->clone_source); if (source_volume == NULL) return FALSE; _clutter_paint_volume_set_from_volume (volume, source_volume); _clutter_paint_volume_set_reference_actor (volume, actor); return TRUE; } static gboolean clutter_clone_has_overlaps (ClutterActor *actor) { ClutterClonePrivate *priv = CLUTTER_CLONE (actor)->priv; /* The clone has overlaps iff the source has overlaps */ if (priv->clone_source == NULL) return FALSE; return clutter_actor_has_overlaps (priv->clone_source); } static void clutter_clone_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActorClass *parent_class; /* chain up */ parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class); parent_class->allocate (self, box, flags); if (priv->clone_source == NULL) return; #if 0 /* XXX - this is wrong: ClutterClone cannot clone unparented * actors, as it will break all invariants */ /* we act like a "foster parent" for the source we are cloning; * if the source has not been parented we have to force an * allocation on it, so that we can paint it correctly from * within our paint() implementation. since the actor does not * have a parent, and thus it won't be painted by the usual * paint cycle, we can safely give it as much size as it requires */ if (clutter_actor_get_parent (priv->clone_source) == NULL) clutter_actor_allocate_preferred_size (priv->clone_source, flags); #endif } static void clutter_clone_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterClone *self = CLUTTER_CLONE (gobject); switch (prop_id) { case PROP_SOURCE: clutter_clone_set_source (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_clone_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterClonePrivate *priv = CLUTTER_CLONE (gobject)->priv; switch (prop_id) { case PROP_SOURCE: g_value_set_object (value, priv->clone_source); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_clone_dispose (GObject *gobject) { clutter_clone_set_source_internal (CLUTTER_CLONE (gobject), NULL); G_OBJECT_CLASS (clutter_clone_parent_class)->dispose (gobject); } static void clutter_clone_class_init (ClutterCloneClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); actor_class->apply_transform = clutter_clone_apply_transform; actor_class->paint = clutter_clone_paint; actor_class->get_paint_volume = clutter_clone_get_paint_volume; actor_class->get_preferred_width = clutter_clone_get_preferred_width; actor_class->get_preferred_height = clutter_clone_get_preferred_height; actor_class->allocate = clutter_clone_allocate; actor_class->has_overlaps = clutter_clone_has_overlaps; gobject_class->dispose = clutter_clone_dispose; gobject_class->set_property = clutter_clone_set_property; gobject_class->get_property = clutter_clone_get_property; /** * ClutterClone:source: * * This property specifies the source actor being cloned. * * Since: 1.0 */ obj_props[PROP_SOURCE] = g_param_spec_object ("source", P_("Source"), P_("Specifies the actor to be cloned"), CLUTTER_TYPE_ACTOR, G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_clone_init (ClutterClone *self) { self->priv = clutter_clone_get_instance_private (self); } /** * clutter_clone_new: * @source: a #ClutterActor, or %NULL * * Creates a new #ClutterActor which clones @source/ * * Return value: the newly created #ClutterClone * * Since: 1.0 */ ClutterActor * clutter_clone_new (ClutterActor *source) { return g_object_new (CLUTTER_TYPE_CLONE, "source", source, NULL); } static void on_source_destroyed (ClutterActor *source, ClutterClone *self) { clutter_clone_set_source_internal (self, NULL); } static void clutter_clone_set_source_internal (ClutterClone *self, ClutterActor *source) { ClutterClonePrivate *priv = self->priv; if (priv->clone_source == source) return; if (priv->clone_source != NULL) { g_signal_handler_disconnect (priv->clone_source, priv->source_destroy_id); priv->source_destroy_id = 0; _clutter_actor_detach_clone (priv->clone_source, CLUTTER_ACTOR (self)); g_object_unref (priv->clone_source); priv->clone_source = NULL; } if (source != NULL) { priv->clone_source = g_object_ref (source); _clutter_actor_attach_clone (priv->clone_source, CLUTTER_ACTOR (self)); priv->source_destroy_id = g_signal_connect (priv->clone_source, "destroy", G_CALLBACK (on_source_destroyed), self); } g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SOURCE]); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); } /** * clutter_clone_set_source: * @self: a #ClutterClone * @source: (allow-none): a #ClutterActor, or %NULL * * Sets @source as the source actor to be cloned by @self. * * Since: 1.0 */ void clutter_clone_set_source (ClutterClone *self, ClutterActor *source) { g_return_if_fail (CLUTTER_IS_CLONE (self)); g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source)); clutter_clone_set_source_internal (self, source); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); } /** * clutter_clone_get_source: * @self: a #ClutterClone * * Retrieves the source #ClutterActor being cloned by @self. * * Return value: (transfer none): the actor source for the clone * * Since: 1.0 */ ClutterActor * clutter_clone_get_source (ClutterClone *self) { g_return_val_if_fail (CLUTTER_IS_CLONE (self), NULL); return self->priv->clone_source; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-timeline.c�����������������������������������������������������0000664�0001750�0001750�00000215721�14211404421�021742� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-timeline * @short_description: A class for time-based events * @see_also: #ClutterAnimation, #ClutterAnimator, #ClutterState * * #ClutterTimeline is a base class for managing time-based event that cause * Clutter to redraw a stage, such as animations. * * Each #ClutterTimeline instance has a duration: once a timeline has been * started, using clutter_timeline_start(), it will emit a signal that can * be used to update the state of the actors. * * It is important to note that #ClutterTimeline is not a generic API for * calling closures after an interval; each Timeline is tied into the master * clock used to drive the frame cycle. If you need to schedule a closure * after an interval, see clutter_threads_add_timeout() instead. * * Users of #ClutterTimeline should connect to the #ClutterTimeline::new-frame * signal, which is emitted each time a timeline is advanced during the maste * clock iteration. The #ClutterTimeline::new-frame signal provides the time * elapsed since the beginning of the timeline, in milliseconds. A normalized * progress value can be obtained by calling clutter_timeline_get_progress(). * By using clutter_timeline_get_delta() it is possible to obtain the wallclock * time elapsed since the last emission of the #ClutterTimeline::new-frame * signal. * * Initial state can be set up by using the #ClutterTimeline::started signal, * while final state can be set up by using the #ClutterTimeline::stopped * signal. The #ClutterTimeline guarantees the emission of at least a single * #ClutterTimeline::new-frame signal, as well as the emission of the * #ClutterTimeline::completed signal every time the #ClutterTimeline reaches * its #ClutterTimeline:duration. * * It is possible to connect to specific points in the timeline progress by * adding markers using clutter_timeline_add_marker_at_time() and connecting * to the #ClutterTimeline::marker-reached signal. * * Timelines can be made to loop once they reach the end of their duration, by * using clutter_timeline_set_repeat_count(); a looping timeline will still * emit the #ClutterTimeline::completed signal once it reaches the end of its * duration at each repeat. If you want to be notified of the end of the last * repeat, use the #ClutterTimeline::stopped signal. * * Timelines have a #ClutterTimeline:direction: the default direction is * %CLUTTER_TIMELINE_FORWARD, and goes from 0 to the duration; it is possible * to change the direction to %CLUTTER_TIMELINE_BACKWARD, and have the timeline * go from the duration to 0. The direction can be automatically reversed * when reaching completion by using the #ClutterTimeline:auto-reverse property. * * Timelines are used in the Clutter animation framework by classes like * #ClutterAnimation, #ClutterAnimator, and #ClutterState. * * ## Defining Timelines in ClutterScript * * A #ClutterTimeline can be described in #ClutterScript like any * other object. Additionally, it is possible to define markers directly * inside the JSON definition by using the `markers` JSON object member, * such as: * * |[ { "type" : "ClutterTimeline", "duration" : 1000, "markers" : [ { "name" : "quarter", "time" : 250 }, { "name" : "half-time", "time" : 500 }, { "name" : "three-quarters", "time" : 750 } ] } * ]| */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-timeline.h" #include "clutter-debug.h" #include "clutter-easing.h" #include "clutter-enum-types.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-master-clock.h" #include "clutter-private.h" #include "clutter-scriptable.h" #include "deprecated/clutter-timeline.h" struct _ClutterTimelinePrivate { ClutterTimelineDirection direction; guint delay_id; /* The total length in milliseconds of this timeline */ guint duration; guint delay; /* The current amount of elapsed time */ gint64 elapsed_time; /* The elapsed time since the last frame was fired */ gint64 msecs_delta; GHashTable *markers_by_name; /* Time we last advanced the elapsed time and showed a frame */ gint64 last_frame_time; /* How many times the timeline should repeat */ gint repeat_count; /* The number of times the timeline has repeated */ gint current_repeat; ClutterTimelineProgressFunc progress_func; gpointer progress_data; GDestroyNotify progress_notify; ClutterAnimationMode progress_mode; /* step() parameters */ gint n_steps; ClutterStepMode step_mode; /* cubic-bezier() parameters */ ClutterPoint cb_1; ClutterPoint cb_2; guint is_playing : 1; /* If we've just started playing and haven't yet gotten * a tick from the master clock */ guint waiting_first_tick : 1; guint auto_reverse : 1; }; typedef struct { gchar *name; GQuark quark; union { guint msecs; gdouble progress; } data; guint is_relative : 1; } TimelineMarker; enum { PROP_0, PROP_LOOP, PROP_DELAY, PROP_DURATION, PROP_DIRECTION, PROP_AUTO_REVERSE, PROP_REPEAT_COUNT, PROP_PROGRESS_MODE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; enum { NEW_FRAME, STARTED, PAUSED, COMPLETED, MARKER_REACHED, STOPPED, LAST_SIGNAL }; static guint timeline_signals[LAST_SIGNAL] = { 0, }; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterTimeline) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)) static TimelineMarker * timeline_marker_new_time (const gchar *name, guint msecs) { TimelineMarker *marker = g_slice_new (TimelineMarker); marker->name = g_strdup (name); marker->quark = g_quark_from_string (marker->name); marker->is_relative = FALSE; marker->data.msecs = msecs; return marker; } static TimelineMarker * timeline_marker_new_progress (const gchar *name, gdouble progress) { TimelineMarker *marker = g_slice_new (TimelineMarker); marker->name = g_strdup (name); marker->quark = g_quark_from_string (marker->name); marker->is_relative = TRUE; marker->data.progress = CLAMP (progress, 0.0, 1.0); return marker; } static void timeline_marker_free (gpointer data) { if (G_LIKELY (data)) { TimelineMarker *marker = data; free (marker->name); g_slice_free (TimelineMarker, marker); } } /*< private > * clutter_timeline_add_marker_internal: * @timeline: a #ClutterTimeline * @marker: a TimelineMarker * * Adds @marker into the hash table of markers for @timeline. * * The TimelineMarker will either be added or, in case of collisions * with another existing marker, freed. In any case, this function * assumes the ownership of the passed @marker. */ static inline void clutter_timeline_add_marker_internal (ClutterTimeline *timeline, TimelineMarker *marker) { ClutterTimelinePrivate *priv = timeline->priv; TimelineMarker *old_marker; /* create the hash table that will hold the markers */ if (G_UNLIKELY (priv->markers_by_name == NULL)) priv->markers_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, timeline_marker_free); old_marker = g_hash_table_lookup (priv->markers_by_name, marker->name); if (old_marker != NULL) { guint msecs; if (old_marker->is_relative) msecs = old_marker->data.progress * priv->duration; else msecs = old_marker->data.msecs; g_warning ("A marker named '%s' already exists at time %d", old_marker->name, msecs); timeline_marker_free (marker); return; } g_hash_table_insert (priv->markers_by_name, marker->name, marker); } static inline void clutter_timeline_set_loop_internal (ClutterTimeline *timeline, gboolean loop) { gint old_repeat_count; old_repeat_count = timeline->priv->repeat_count; if (loop) clutter_timeline_set_repeat_count (timeline, -1); else clutter_timeline_set_repeat_count (timeline, 0); if (old_repeat_count != timeline->priv->repeat_count) g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_LOOP]); } /* Scriptable */ typedef struct _ParseClosure { ClutterTimeline *timeline; ClutterScript *script; GValue *value; gboolean result; } ParseClosure; static void parse_timeline_markers (JsonArray *array, guint index_, JsonNode *element, gpointer data) { ParseClosure *clos = data; JsonObject *object; TimelineMarker *marker; GList *markers; if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT) { g_warning ("The 'markers' member of a ClutterTimeline description " "should be an array of objects, but the element %d of the " "array is of type '%s'. The element will be ignored.", index_, json_node_type_name (element)); return; } object = json_node_get_object (element); if (!(json_object_has_member (object, "name") && (json_object_has_member (object, "time") || json_object_has_member (object, "progress")))) { g_warning ("The marker definition in a ClutterTimeline description " "must be an object with the 'name' and either the 'time' " "or the 'progress' members, but the element %d of the " "'markers' array does not have any of them.", index_); return; } if (G_IS_VALUE (clos->value)) markers = g_value_get_pointer (clos->value); else { g_value_init (clos->value, G_TYPE_POINTER); markers = NULL; } if (json_object_has_member (object, "time")) marker = timeline_marker_new_time (json_object_get_string_member (object, "name"), json_object_get_int_member (object, "time")); else marker = timeline_marker_new_progress (json_object_get_string_member (object, "name"), json_object_get_double_member (object, "progress")); markers = g_list_prepend (markers, marker); g_value_set_pointer (clos->value, markers); clos->result = TRUE; } static gboolean clutter_timeline_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { ParseClosure clos; if (strcmp (name, "markers") != 0) return FALSE; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) return FALSE; clos.timeline = CLUTTER_TIMELINE (scriptable); clos.script = script; clos.value = value; clos.result = FALSE; json_array_foreach_element (json_node_get_array (node), parse_timeline_markers, &clos); return clos.result; } static void clutter_timeline_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { if (strcmp (name, "markers") == 0) { ClutterTimeline *timeline = CLUTTER_TIMELINE (scriptable); GList *markers = g_value_get_pointer (value); GList *m; /* the list was created through prepend() */ markers = g_list_reverse (markers); for (m = markers; m != NULL; m = m->next) clutter_timeline_add_marker_internal (timeline, m->data); g_list_free (markers); } else g_object_set_property (G_OBJECT (scriptable), name, value); } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_timeline_parse_custom_node; iface->set_custom_property = clutter_timeline_set_custom_property; } /* Object */ static void clutter_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterTimeline *timeline = CLUTTER_TIMELINE (object); switch (prop_id) { case PROP_LOOP: clutter_timeline_set_loop_internal (timeline, g_value_get_boolean (value)); break; case PROP_DELAY: clutter_timeline_set_delay (timeline, g_value_get_uint (value)); break; case PROP_DURATION: clutter_timeline_set_duration (timeline, g_value_get_uint (value)); break; case PROP_DIRECTION: clutter_timeline_set_direction (timeline, g_value_get_enum (value)); break; case PROP_AUTO_REVERSE: clutter_timeline_set_auto_reverse (timeline, g_value_get_boolean (value)); break; case PROP_REPEAT_COUNT: clutter_timeline_set_repeat_count (timeline, g_value_get_int (value)); break; case PROP_PROGRESS_MODE: clutter_timeline_set_progress_mode (timeline, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterTimeline *timeline = CLUTTER_TIMELINE (object); ClutterTimelinePrivate *priv = timeline->priv; switch (prop_id) { case PROP_LOOP: g_value_set_boolean (value, priv->repeat_count != 0); break; case PROP_DELAY: g_value_set_uint (value, priv->delay); break; case PROP_DURATION: g_value_set_uint (value, clutter_timeline_get_duration (timeline)); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; case PROP_AUTO_REVERSE: g_value_set_boolean (value, priv->auto_reverse); break; case PROP_REPEAT_COUNT: g_value_set_int (value, priv->repeat_count); break; case PROP_PROGRESS_MODE: g_value_set_enum (value, priv->progress_mode); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_timeline_finalize (GObject *object) { ClutterTimeline *self = CLUTTER_TIMELINE (object); ClutterTimelinePrivate *priv = self->priv; ClutterMasterClock *master_clock; if (priv->markers_by_name) g_hash_table_destroy (priv->markers_by_name); if (priv->is_playing) { master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_remove_timeline (master_clock, self); } G_OBJECT_CLASS (clutter_timeline_parent_class)->finalize (object); } static void clutter_timeline_dispose (GObject *object) { ClutterTimeline *self = CLUTTER_TIMELINE(object); ClutterTimelinePrivate *priv; priv = self->priv; if (priv->delay_id) { g_source_remove (priv->delay_id); priv->delay_id = 0; } if (priv->progress_notify != NULL) { priv->progress_notify (priv->progress_data); priv->progress_func = NULL; priv->progress_data = NULL; priv->progress_notify = NULL; } G_OBJECT_CLASS (clutter_timeline_parent_class)->dispose (object); } static void clutter_timeline_class_init (ClutterTimelineClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /** * ClutterTimeline:loop: * * Whether the timeline should automatically rewind and restart. * * As a side effect, setting this property to %TRUE will set the * #ClutterTimeline:repeat-count property to -1, while setting this * property to %FALSE will set the #ClutterTimeline:repeat-count * property to 0. * * Deprecated: 1.10: Use the #ClutterTimeline:repeat-count property instead. */ obj_props[PROP_LOOP] = g_param_spec_boolean ("loop", P_("Loop"), P_("Should the timeline automatically restart"), FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); /** * ClutterTimeline:delay: * * A delay, in milliseconds, that should be observed by the * timeline before actually starting. * * Since: 0.4 */ obj_props[PROP_DELAY] = g_param_spec_uint ("delay", P_("Delay"), P_("Delay before start"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterTimeline:duration: * * Duration of the timeline in milliseconds, depending on the * ClutterTimeline:fps value. * * Since: 0.6 */ obj_props[PROP_DURATION] = g_param_spec_uint ("duration", P_("Duration"), P_("Duration of the timeline in milliseconds"), 0, G_MAXUINT, 1000, CLUTTER_PARAM_READWRITE); /** * ClutterTimeline:direction: * * The direction of the timeline, either %CLUTTER_TIMELINE_FORWARD or * %CLUTTER_TIMELINE_BACKWARD. * * Since: 0.6 */ obj_props[PROP_DIRECTION] = g_param_spec_enum ("direction", P_("Direction"), P_("Direction of the timeline"), CLUTTER_TYPE_TIMELINE_DIRECTION, CLUTTER_TIMELINE_FORWARD, CLUTTER_PARAM_READWRITE); /** * ClutterTimeline:auto-reverse: * * If the direction of the timeline should be automatically reversed * when reaching the end. * * Since: 1.6 */ obj_props[PROP_AUTO_REVERSE] = g_param_spec_boolean ("auto-reverse", P_("Auto Reverse"), P_("Whether the direction should be reversed when reaching the end"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterTimeline:repeat-count: * * Defines how many times the timeline should repeat. * * If the repeat count is 0, the timeline does not repeat. * * If the repeat count is set to -1, the timeline will repeat until it is * stopped. * * Since: 1.10 */ obj_props[PROP_REPEAT_COUNT] = g_param_spec_int ("repeat-count", P_("Repeat Count"), P_("How many times the timeline should repeat"), -1, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterTimeline:progress-mode: * * Controls the way a #ClutterTimeline computes the normalized progress. * * Since: 1.10 */ obj_props[PROP_PROGRESS_MODE] = g_param_spec_enum ("progress-mode", P_("Progress Mode"), P_("How the timeline should compute the progress"), CLUTTER_TYPE_ANIMATION_MODE, CLUTTER_LINEAR, CLUTTER_PARAM_READWRITE); object_class->dispose = clutter_timeline_dispose; object_class->finalize = clutter_timeline_finalize; object_class->set_property = clutter_timeline_set_property; object_class->get_property = clutter_timeline_get_property; g_object_class_install_properties (object_class, PROP_LAST, obj_props); /** * ClutterTimeline::new-frame: * @timeline: the timeline which received the signal * @msecs: the elapsed time between 0 and duration * * The ::new-frame signal is emitted for each timeline running * timeline before a new frame is drawn to give animations a chance * to update the scene. */ timeline_signals[NEW_FRAME] = g_signal_new (I_("new-frame"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTimelineClass, new_frame), NULL, NULL, _clutter_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); /** * ClutterTimeline::completed: * @timeline: the #ClutterTimeline which received the signal * * The #ClutterTimeline::completed signal is emitted when the timeline's * elapsed time reaches the value of the #ClutterTimeline:duration * property. * * This signal will be emitted even if the #ClutterTimeline is set to be * repeating. * * If you want to get notification on whether the #ClutterTimeline has * been stopped or has finished its run, including its eventual repeats, * you should use the #ClutterTimeline::stopped signal instead. */ timeline_signals[COMPLETED] = g_signal_new (I_("completed"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTimelineClass, completed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterTimeline::started: * @timeline: the #ClutterTimeline which received the signal * * The ::started signal is emitted when the timeline starts its run. * This might be as soon as clutter_timeline_start() is invoked or * after the delay set in the ClutterTimeline:delay property has * expired. */ timeline_signals[STARTED] = g_signal_new (I_("started"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTimelineClass, started), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterTimeline::paused: * @timeline: the #ClutterTimeline which received the signal * * The ::paused signal is emitted when clutter_timeline_pause() is invoked. */ timeline_signals[PAUSED] = g_signal_new (I_("paused"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTimelineClass, paused), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterTimeline::marker-reached: * @timeline: the #ClutterTimeline which received the signal * @marker_name: the name of the marker reached * @msecs: the elapsed time * * The ::marker-reached signal is emitted each time a timeline * reaches a marker set with * clutter_timeline_add_marker_at_time(). This signal is detailed * with the name of the marker as well, so it is possible to connect * a callback to the ::marker-reached signal for a specific marker * with: * * <informalexample><programlisting> * clutter_timeline_add_marker_at_time (timeline, "foo", 500); * clutter_timeline_add_marker_at_time (timeline, "bar", 750); * * g_signal_connect (timeline, "marker-reached", * G_CALLBACK (each_marker_reached), NULL); * g_signal_connect (timeline, "marker-reached::foo", * G_CALLBACK (foo_marker_reached), NULL); * g_signal_connect (timeline, "marker-reached::bar", * G_CALLBACK (bar_marker_reached), NULL); * </programlisting></informalexample> * * In the example, the first callback will be invoked for both * the "foo" and "bar" marker, while the second and third callbacks * will be invoked for the "foo" or "bar" markers, respectively. * * Since: 0.8 */ timeline_signals[MARKER_REACHED] = g_signal_new (I_("marker-reached"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (ClutterTimelineClass, marker_reached), NULL, NULL, _clutter_marshal_VOID__STRING_INT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); /** * ClutterTimeline::stopped: * @timeline: the #ClutterTimeline that emitted the signal * @is_finished: %TRUE if the signal was emitted at the end of the * timeline. * * The #ClutterTimeline::stopped signal is emitted when the timeline * has been stopped, either because clutter_timeline_stop() has been * called, or because it has been exhausted. * * This is different from the #ClutterTimeline::completed signal, * which gets emitted after every repeat finishes. * * If the #ClutterTimeline has is marked as infinitely repeating, * this signal will never be emitted. * * Since: 1.12 */ timeline_signals[STOPPED] = g_signal_new (I_("stopped"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTimelineClass, stopped), NULL, NULL, _clutter_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); } static void clutter_timeline_init (ClutterTimeline *self) { self->priv = clutter_timeline_get_instance_private (self); self->priv->progress_mode = CLUTTER_LINEAR; /* default steps() parameters are 1, end */ self->priv->n_steps = 1; self->priv->step_mode = CLUTTER_STEP_MODE_END; /* default cubic-bezier() paramereters are (0, 0, 1, 1) */ clutter_point_init (&self->priv->cb_1, 0, 0); clutter_point_init (&self->priv->cb_2, 1, 1); } struct CheckIfMarkerHitClosure { ClutterTimeline *timeline; ClutterTimelineDirection direction; gint new_time; gint duration; gint delta; }; static gboolean have_passed_time (const struct CheckIfMarkerHitClosure *data, gint msecs) { /* Ignore markers that are outside the duration of the timeline */ if (msecs < 0 || msecs > data->duration) return FALSE; if (data->direction == CLUTTER_TIMELINE_FORWARD) { /* We need to special case when a marker is added at the beginning of the timeline */ if (msecs == 0 && data->delta > 0 && data->new_time - data->delta <= 0) return TRUE; /* Otherwise it's just a simple test if the time is in range of the previous time and the new time */ return (msecs > data->new_time - data->delta && msecs <= data->new_time); } else { /* We need to special case when a marker is added at the end of the timeline */ if (msecs == data->duration && data->delta > 0 && data->new_time + data->delta >= data->duration) return TRUE; /* Otherwise it's just a simple test if the time is in range of the previous time and the new time */ return (msecs >= data->new_time && msecs < data->new_time + data->delta); } } static void check_if_marker_hit (const gchar *name, TimelineMarker *marker, struct CheckIfMarkerHitClosure *data) { gint msecs; if (marker->is_relative) msecs = (gdouble) data->duration * marker->data.progress; else msecs = marker->data.msecs; if (have_passed_time (data, msecs)) { CLUTTER_NOTE (SCHEDULER, "Marker '%s' reached", name); g_signal_emit (data->timeline, timeline_signals[MARKER_REACHED], marker->quark, name, msecs); } } static void check_markers (ClutterTimeline *timeline, gint delta) { ClutterTimelinePrivate *priv = timeline->priv; struct CheckIfMarkerHitClosure data; /* shortcircuit here if we don't have any marker installed */ if (priv->markers_by_name == NULL) return; /* store the details of the timeline so that changing them in a marker signal handler won't affect which markers are hit */ data.timeline = timeline; data.direction = priv->direction; data.new_time = priv->elapsed_time; data.duration = priv->duration; data.delta = delta; g_hash_table_foreach (priv->markers_by_name, (GHFunc) check_if_marker_hit, &data); } static void emit_frame_signal (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv = timeline->priv; /* see bug https://bugzilla.gnome.org/show_bug.cgi?id=654066 */ gint elapsed = (gint) priv->elapsed_time; CLUTTER_NOTE (SCHEDULER, "Emitting ::new-frame signal on timeline[%p]", timeline); g_signal_emit (timeline, timeline_signals[NEW_FRAME], 0, elapsed); } static gboolean is_complete (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv = timeline->priv; return (priv->direction == CLUTTER_TIMELINE_FORWARD ? priv->elapsed_time >= priv->duration : priv->elapsed_time <= 0); } static void set_is_playing (ClutterTimeline *timeline, gboolean is_playing) { ClutterTimelinePrivate *priv = timeline->priv; ClutterMasterClock *master_clock; is_playing = !!is_playing; if (is_playing == priv->is_playing) return; priv->is_playing = is_playing; master_clock = _clutter_master_clock_get_default (); if (priv->is_playing) { priv->waiting_first_tick = TRUE; priv->current_repeat = 0; _clutter_master_clock_add_timeline (master_clock, timeline); } else _clutter_master_clock_remove_timeline (master_clock, timeline); } static gboolean clutter_timeline_do_frame (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; priv = timeline->priv; g_object_ref (timeline); CLUTTER_NOTE (SCHEDULER, "Timeline [%p] activated (elapsed time: %ld, " "duration: %ld, msecs_delta: %ld)\n", timeline, (long) priv->elapsed_time, (long) priv->duration, (long) priv->msecs_delta); /* Advance time */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) priv->elapsed_time += priv->msecs_delta; else priv->elapsed_time -= priv->msecs_delta; /* If we have not reached the end of the timeline: */ if (!is_complete (timeline)) { /* Emit the signal */ emit_frame_signal (timeline); check_markers (timeline, priv->msecs_delta); g_object_unref (timeline); return priv->is_playing; } else { /* Handle loop or stop */ ClutterTimelineDirection saved_direction = priv->direction; gint elapsed_time_delta = priv->msecs_delta; guint overflow_msecs = priv->elapsed_time; gint end_msecs; /* Update the current elapsed time in case the signal handlers * want to take a peek. If we clamp elapsed time, then we need * to correpondingly reduce elapsed_time_delta to reflect the correct * range of times */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) { elapsed_time_delta -= (priv->elapsed_time - priv->duration); priv->elapsed_time = priv->duration; } else if (priv->direction == CLUTTER_TIMELINE_BACKWARD) { elapsed_time_delta -= - priv->elapsed_time; priv->elapsed_time = 0; } end_msecs = priv->elapsed_time; /* Emit the signal */ emit_frame_signal (timeline); check_markers (timeline, elapsed_time_delta); /* Did the signal handler modify the elapsed time? */ if (priv->elapsed_time != end_msecs) { g_object_unref (timeline); return TRUE; } /* Note: If the new-frame signal handler paused the timeline * on the last frame we will still go ahead and send the * completed signal */ CLUTTER_NOTE (SCHEDULER, "Timeline [%p] completed (cur: %ld, tot: %ld)", timeline, (long) priv->elapsed_time, (long) priv->msecs_delta); if (priv->is_playing && (priv->repeat_count == 0 || priv->repeat_count == priv->current_repeat)) { /* We stop the timeline now, so that the completed signal handler * may choose to re-start the timeline * * XXX Perhaps we should do this earlier, and regardless of * priv->repeat_count. Are we limiting the things that could be * done in the above new-frame signal handler? */ set_is_playing (timeline, FALSE); g_signal_emit (timeline, timeline_signals[COMPLETED], 0); g_signal_emit (timeline, timeline_signals[STOPPED], 0, TRUE); } else g_signal_emit (timeline, timeline_signals[COMPLETED], 0); priv->current_repeat += 1; if (priv->auto_reverse) { /* :auto-reverse changes the direction of the timeline */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) priv->direction = CLUTTER_TIMELINE_BACKWARD; else priv->direction = CLUTTER_TIMELINE_FORWARD; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_DIRECTION]); } /* Again check to see if the user has manually played with * the elapsed time, before we finally stop or loop the timeline */ if (priv->elapsed_time != end_msecs && !(/* Except allow changing time from 0 -> duration (or vice-versa) since these are considered equivalent */ (priv->elapsed_time == 0 && end_msecs == priv->duration) || (priv->elapsed_time == priv->duration && end_msecs == 0) )) { g_object_unref (timeline); return TRUE; } if (priv->repeat_count != 0) { /* We try and interpolate smoothly around a loop */ if (saved_direction == CLUTTER_TIMELINE_FORWARD) priv->elapsed_time = overflow_msecs - priv->duration; else priv->elapsed_time = priv->duration + overflow_msecs; /* Or if the direction changed, we try and bounce */ if (priv->direction != saved_direction) priv->elapsed_time = priv->duration - priv->elapsed_time; /* If we have overflowed then we are changing the elapsed time without emitting the new frame signal so we need to check for markers again */ check_markers (timeline, priv->direction == CLUTTER_TIMELINE_FORWARD ? priv->elapsed_time : priv->duration - priv->elapsed_time); g_object_unref (timeline); return TRUE; } else { clutter_timeline_rewind (timeline); g_object_unref (timeline); return FALSE; } } } static gboolean delay_timeout_func (gpointer data) { ClutterTimeline *timeline = data; ClutterTimelinePrivate *priv = timeline->priv; priv->delay_id = 0; priv->msecs_delta = 0; set_is_playing (timeline, TRUE); g_signal_emit (timeline, timeline_signals[STARTED], 0); return FALSE; } /** * clutter_timeline_start: * @timeline: A #ClutterTimeline * * Starts the #ClutterTimeline playing. **/ void clutter_timeline_start (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->delay_id || priv->is_playing) return; if (priv->duration == 0) return; if (priv->delay) priv->delay_id = clutter_threads_add_timeout (priv->delay, delay_timeout_func, timeline); else { priv->msecs_delta = 0; set_is_playing (timeline, TRUE); g_signal_emit (timeline, timeline_signals[STARTED], 0); } } /** * clutter_timeline_pause: * @timeline: A #ClutterTimeline * * Pauses the #ClutterTimeline on current frame **/ void clutter_timeline_pause (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->delay_id == 0 && !priv->is_playing) return; if (priv->delay_id) { g_source_remove (priv->delay_id); priv->delay_id = 0; } priv->msecs_delta = 0; set_is_playing (timeline, FALSE); g_signal_emit (timeline, timeline_signals[PAUSED], 0); } /** * clutter_timeline_stop: * @timeline: A #ClutterTimeline * * Stops the #ClutterTimeline and moves to frame 0 **/ void clutter_timeline_stop (ClutterTimeline *timeline) { gboolean was_playing; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); /* we check the is_playing here because pause() will return immediately * if the timeline wasn't playing, so we don't know if it was actually * stopped, and yet we still don't want to emit a ::stopped signal if * the timeline was not playing in the first place. */ was_playing = timeline->priv->is_playing; clutter_timeline_pause (timeline); clutter_timeline_rewind (timeline); if (was_playing) g_signal_emit (timeline, timeline_signals[STOPPED], 0, FALSE); } /** * clutter_timeline_set_loop: * @timeline: a #ClutterTimeline * @loop: %TRUE for enable looping * * Sets whether @timeline should loop. * * This function is equivalent to calling clutter_timeline_set_repeat_count() * with -1 if @loop is %TRUE, and with 0 if @loop is %FALSE. * * Deprecated: 1.10: Use clutter_timeline_set_repeat_count() instead. */ void clutter_timeline_set_loop (ClutterTimeline *timeline, gboolean loop) { g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); clutter_timeline_set_loop_internal (timeline, loop); } /** * clutter_timeline_get_loop: * @timeline: a #ClutterTimeline * * Gets whether @timeline is looping * * Return value: %TRUE if the timeline is looping * * Deprecated: 1.10: Use clutter_timeline_get_repeat_count() instead. */ gboolean clutter_timeline_get_loop (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); return timeline->priv->repeat_count != 0; } /** * clutter_timeline_rewind: * @timeline: A #ClutterTimeline * * Rewinds #ClutterTimeline to the first frame if its direction is * %CLUTTER_TIMELINE_FORWARD and the last frame if it is * %CLUTTER_TIMELINE_BACKWARD. */ void clutter_timeline_rewind (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->direction == CLUTTER_TIMELINE_FORWARD) clutter_timeline_advance (timeline, 0); else if (priv->direction == CLUTTER_TIMELINE_BACKWARD) clutter_timeline_advance (timeline, priv->duration); } /** * clutter_timeline_skip: * @timeline: A #ClutterTimeline * @msecs: Amount of time to skip * * Advance timeline by the requested time in milliseconds */ void clutter_timeline_skip (ClutterTimeline *timeline, guint msecs) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->direction == CLUTTER_TIMELINE_FORWARD) { priv->elapsed_time += msecs; if (priv->elapsed_time > priv->duration) priv->elapsed_time = 1; } else if (priv->direction == CLUTTER_TIMELINE_BACKWARD) { priv->elapsed_time -= msecs; if (priv->elapsed_time < 1) priv->elapsed_time = priv->duration - 1; } priv->msecs_delta = 0; } /** * clutter_timeline_advance: * @timeline: A #ClutterTimeline * @msecs: Time to advance to * * Advance timeline to the requested point. The point is given as a * time in milliseconds since the timeline started. * * The @timeline will not emit the #ClutterTimeline::new-frame * signal for the given time. The first ::new-frame signal after the call to * clutter_timeline_advance() will be emit the skipped markers. */ void clutter_timeline_advance (ClutterTimeline *timeline, guint msecs) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; priv->elapsed_time = CLAMP (msecs, 0, priv->duration); } /** * clutter_timeline_get_elapsed_time: * @timeline: A #ClutterTimeline * * Request the current time position of the timeline. * * Return value: current elapsed time in milliseconds. */ guint clutter_timeline_get_elapsed_time (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); return timeline->priv->elapsed_time; } /** * clutter_timeline_is_playing: * @timeline: A #ClutterTimeline * * Queries state of a #ClutterTimeline. * * Return value: %TRUE if timeline is currently playing */ gboolean clutter_timeline_is_playing (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); return timeline->priv->is_playing; } /** * clutter_timeline_clone: * @timeline: #ClutterTimeline to duplicate. * * Create a new #ClutterTimeline instance which has property values * matching that of supplied timeline. The cloned timeline will not * be started and will not be positioned to the current position of * the original @timeline: you will have to start it with * clutter_timeline_start(). * * The only cloned properties are: * * - #ClutterTimeline:duration * - #ClutterTimeline:loop * - #ClutterTimeline:delay * - #ClutterTimeline:direction * * Return value: (transfer full): a new #ClutterTimeline, cloned * from @timeline * * Since: 0.4 * * Deprecated: 1.10: Use clutter_timeline_new() or g_object_new() * instead */ ClutterTimeline * clutter_timeline_clone (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL); return g_object_new (CLUTTER_TYPE_TIMELINE, "duration", timeline->priv->duration, "loop", timeline->priv->repeat_count != 0, "delay", timeline->priv->delay, "direction", timeline->priv->direction, NULL); } /** * clutter_timeline_new: * @msecs: Duration of the timeline in milliseconds * * Creates a new #ClutterTimeline with a duration of @msecs. * * Return value: the newly created #ClutterTimeline instance. Use * g_object_unref() when done using it * * Since: 0.6 */ ClutterTimeline * clutter_timeline_new (guint msecs) { return g_object_new (CLUTTER_TYPE_TIMELINE, "duration", msecs, NULL); } /** * clutter_timeline_get_delay: * @timeline: a #ClutterTimeline * * Retrieves the delay set using clutter_timeline_set_delay(). * * Return value: the delay in milliseconds. * * Since: 0.4 */ guint clutter_timeline_get_delay (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); return timeline->priv->delay; } /** * clutter_timeline_set_delay: * @timeline: a #ClutterTimeline * @msecs: delay in milliseconds * * Sets the delay, in milliseconds, before @timeline should start. * * Since: 0.4 */ void clutter_timeline_set_delay (ClutterTimeline *timeline, guint msecs) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->delay != msecs) { priv->delay = msecs; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_DELAY]); } } /** * clutter_timeline_get_duration: * @timeline: a #ClutterTimeline * * Retrieves the duration of a #ClutterTimeline in milliseconds. * See clutter_timeline_set_duration(). * * Return value: the duration of the timeline, in milliseconds. * * Since: 0.6 */ guint clutter_timeline_get_duration (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); priv = timeline->priv; return priv->duration; } /** * clutter_timeline_set_duration: * @timeline: a #ClutterTimeline * @msecs: duration of the timeline in milliseconds * * Sets the duration of the timeline, in milliseconds. The speed * of the timeline depends on the ClutterTimeline:fps setting. * * Since: 0.6 */ void clutter_timeline_set_duration (ClutterTimeline *timeline, guint msecs) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (msecs > 0); priv = timeline->priv; if (priv->duration != msecs) { priv->duration = msecs; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_DURATION]); } } /** * clutter_timeline_get_progress: * @timeline: a #ClutterTimeline * * The position of the timeline in a normalized [-1, 2] interval. * * The return value of this function is determined by the progress * mode set using clutter_timeline_set_progress_mode(), or by the * progress function set using clutter_timeline_set_progress_func(). * * Return value: the normalized current position in the timeline. * * Since: 0.6 */ gdouble clutter_timeline_get_progress (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0.0); priv = timeline->priv; /* short-circuit linear progress */ if (priv->progress_func == NULL) return (gdouble) priv->elapsed_time / (gdouble) priv->duration; else return priv->progress_func (timeline, (gdouble) priv->elapsed_time, (gdouble) priv->duration, priv->progress_data); } /** * clutter_timeline_get_direction: * @timeline: a #ClutterTimeline * * Retrieves the direction of the timeline set with * clutter_timeline_set_direction(). * * Return value: the direction of the timeline * * Since: 0.6 */ ClutterTimelineDirection clutter_timeline_get_direction (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), CLUTTER_TIMELINE_FORWARD); return timeline->priv->direction; } /** * clutter_timeline_set_direction: * @timeline: a #ClutterTimeline * @direction: the direction of the timeline * * Sets the direction of @timeline, either %CLUTTER_TIMELINE_FORWARD or * %CLUTTER_TIMELINE_BACKWARD. * * Since: 0.6 */ void clutter_timeline_set_direction (ClutterTimeline *timeline, ClutterTimelineDirection direction) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->direction != direction) { priv->direction = direction; if (priv->elapsed_time == 0) priv->elapsed_time = priv->duration; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_DIRECTION]); } } /** * clutter_timeline_get_delta: * @timeline: a #ClutterTimeline * * Retrieves the amount of time elapsed since the last * ClutterTimeline::new-frame signal. * * This function is only useful inside handlers for the ::new-frame * signal, and its behaviour is undefined if the timeline is not * playing. * * Return value: the amount of time in milliseconds elapsed since the * last frame * * Since: 0.6 */ guint clutter_timeline_get_delta (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); if (!clutter_timeline_is_playing (timeline)) return 0; return timeline->priv->msecs_delta; } void _clutter_timeline_advance (ClutterTimeline *timeline, gint64 tick_time) { ClutterTimelinePrivate *priv = timeline->priv; g_object_ref (timeline); CLUTTER_NOTE (SCHEDULER, "Timeline [%p] advancing (cur: %ld, tot: %ld, " "tick_time: %lu)", timeline, (long) priv->elapsed_time, (long) priv->msecs_delta, (long) tick_time); priv->msecs_delta = tick_time; priv->is_playing = TRUE; clutter_timeline_do_frame (timeline); priv->is_playing = FALSE; g_object_unref (timeline); } /*< private > * clutter_timeline_do_tick * @timeline: a #ClutterTimeline * @tick_time: time of advance * * Advances @timeline based on the time passed in @tick_time. This * function is called by the master clock. The @timeline will use this * interval to emit the #ClutterTimeline::new-frame signal and * eventually skip frames. */ void _clutter_timeline_do_tick (ClutterTimeline *timeline, gint64 tick_time) { ClutterTimelinePrivate *priv; priv = timeline->priv; CLUTTER_NOTE (SCHEDULER, "Timeline [%p] ticked (elapsed_time: %ld, msecs_delta: %ld, " "last_frame_time: %ld, tick_time: %ld)", timeline, (long) priv->elapsed_time, (long) priv->msecs_delta, (long) priv->last_frame_time, (long) tick_time); /* Check the is_playing variable before performing the timeline tick. * This is necessary, as if a timeline is stopped in response to a * master-clock generated signal of a different timeline, this code can * still be reached. */ if (!priv->is_playing) return; if (priv->waiting_first_tick) { priv->last_frame_time = tick_time; priv->msecs_delta = 0; priv->waiting_first_tick = FALSE; clutter_timeline_do_frame (timeline); } else { gint64 msecs; msecs = tick_time - priv->last_frame_time; /* if the clock rolled back between ticks we need to * account for it; the best course of action, since the * clock roll back can happen by any arbitrary amount * of milliseconds, is to drop a frame here */ if (msecs < 0) { priv->last_frame_time = tick_time; return; } if (msecs != 0) { /* Avoid accumulating error */ priv->last_frame_time += msecs; priv->msecs_delta = msecs; clutter_timeline_do_frame (timeline); } } } /** * clutter_timeline_add_marker: * @timeline: a #ClutterTimeline * @marker_name: the unique name for this marker * @progress: the normalized value of the position of the martke * * Adds a named marker that will be hit when the timeline has reached * the specified @progress. * * Markers are unique string identifiers for a given position on the * timeline. Once @timeline reaches the given @progress of its duration, * if will emit a ::marker-reached signal for each marker attached to * that particular point. * * A marker can be removed with clutter_timeline_remove_marker(). The * timeline can be advanced to a marker using * clutter_timeline_advance_to_marker(). * * See also: clutter_timeline_add_marker_at_time() * * Since: 1.14 */ void clutter_timeline_add_marker (ClutterTimeline *timeline, const gchar *marker_name, gdouble progress) { TimelineMarker *marker; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); marker = timeline_marker_new_progress (marker_name, progress); clutter_timeline_add_marker_internal (timeline, marker); } /** * clutter_timeline_add_marker_at_time: * @timeline: a #ClutterTimeline * @marker_name: the unique name for this marker * @msecs: position of the marker in milliseconds * * Adds a named marker that will be hit when the timeline has been * running for @msecs milliseconds. * * Markers are unique string identifiers for a given position on the * timeline. Once @timeline reaches the given @msecs, it will emit * a ::marker-reached signal for each marker attached to that position. * * A marker can be removed with clutter_timeline_remove_marker(). The * timeline can be advanced to a marker using * clutter_timeline_advance_to_marker(). * * See also: clutter_timeline_add_marker() * * Since: 0.8 */ void clutter_timeline_add_marker_at_time (ClutterTimeline *timeline, const gchar *marker_name, guint msecs) { TimelineMarker *marker; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); g_return_if_fail (msecs <= clutter_timeline_get_duration (timeline)); marker = timeline_marker_new_time (marker_name, msecs); clutter_timeline_add_marker_internal (timeline, marker); } struct CollectMarkersClosure { guint duration; guint msecs; GArray *markers; }; static void collect_markers (const gchar *key, TimelineMarker *marker, struct CollectMarkersClosure *data) { guint msecs; if (marker->is_relative) msecs = marker->data.progress * data->duration; else msecs = marker->data.msecs; if (msecs == data->msecs) { gchar *name_copy = g_strdup (key); g_array_append_val (data->markers, name_copy); } } /** * clutter_timeline_list_markers: * @timeline: a #ClutterTimeline * @msecs: the time to check, or -1 * @n_markers: the number of markers returned * * Retrieves the list of markers at time @msecs. If @msecs is a * negative integer, all the markers attached to @timeline will be * returned. * * Return value: (transfer full) (array zero-terminated=1 length=n_markers): * a newly allocated, %NULL terminated string array containing the names * of the markers. Use g_strfreev() when done. * * Since: 0.8 */ gchar ** clutter_timeline_list_markers (ClutterTimeline *timeline, gint msecs, gsize *n_markers) { ClutterTimelinePrivate *priv; gchar **retval = NULL; gsize i; g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL); priv = timeline->priv; if (G_UNLIKELY (priv->markers_by_name == NULL)) { if (n_markers) *n_markers = 0; return NULL; } if (msecs < 0) { GList *markers, *l; markers = g_hash_table_get_keys (priv->markers_by_name); retval = g_new0 (gchar*, g_list_length (markers) + 1); for (i = 0, l = markers; l != NULL; i++, l = l->next) retval[i] = g_strdup (l->data); g_list_free (markers); } else { struct CollectMarkersClosure data; data.duration = priv->duration; data.msecs = msecs; data.markers = g_array_new (TRUE, FALSE, sizeof (gchar *)); g_hash_table_foreach (priv->markers_by_name, (GHFunc) collect_markers, &data); i = data.markers->len; retval = (gchar **) (void *) g_array_free (data.markers, FALSE); } if (n_markers) *n_markers = i; return retval; } /** * clutter_timeline_advance_to_marker: * @timeline: a #ClutterTimeline * @marker_name: the name of the marker * * Advances @timeline to the time of the given @marker_name. * * Like clutter_timeline_advance(), this function will not * emit the #ClutterTimeline::new-frame for the time where @marker_name * is set, nor it will emit #ClutterTimeline::marker-reached for * @marker_name. * * Since: 0.8 */ void clutter_timeline_advance_to_marker (ClutterTimeline *timeline, const gchar *marker_name) { ClutterTimelinePrivate *priv; TimelineMarker *marker; guint msecs; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); priv = timeline->priv; if (G_UNLIKELY (priv->markers_by_name == NULL)) { g_warning ("No marker named '%s' found.", marker_name); return; } marker = g_hash_table_lookup (priv->markers_by_name, marker_name); if (marker == NULL) { g_warning ("No marker named '%s' found.", marker_name); return; } if (marker->is_relative) msecs = marker->data.progress * priv->duration; else msecs = marker->data.msecs; clutter_timeline_advance (timeline, msecs); } /** * clutter_timeline_remove_marker: * @timeline: a #ClutterTimeline * @marker_name: the name of the marker to remove * * Removes @marker_name, if found, from @timeline. * * Since: 0.8 */ void clutter_timeline_remove_marker (ClutterTimeline *timeline, const gchar *marker_name) { ClutterTimelinePrivate *priv; TimelineMarker *marker; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); priv = timeline->priv; if (G_UNLIKELY (priv->markers_by_name == NULL)) { g_warning ("No marker named '%s' found.", marker_name); return; } marker = g_hash_table_lookup (priv->markers_by_name, marker_name); if (!marker) { g_warning ("No marker named '%s' found.", marker_name); return; } /* this will take care of freeing the marker as well */ g_hash_table_remove (priv->markers_by_name, marker_name); } /** * clutter_timeline_has_marker: * @timeline: a #ClutterTimeline * @marker_name: the name of the marker * * Checks whether @timeline has a marker set with the given name. * * Return value: %TRUE if the marker was found * * Since: 0.8 */ gboolean clutter_timeline_has_marker (ClutterTimeline *timeline, const gchar *marker_name) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); g_return_val_if_fail (marker_name != NULL, FALSE); if (G_UNLIKELY (timeline->priv->markers_by_name == NULL)) return FALSE; return NULL != g_hash_table_lookup (timeline->priv->markers_by_name, marker_name); } /** * clutter_timeline_set_auto_reverse: * @timeline: a #ClutterTimeline * @reverse: %TRUE if the @timeline should reverse the direction * * Sets whether @timeline should reverse the direction after the * emission of the #ClutterTimeline::completed signal. * * Setting the #ClutterTimeline:auto-reverse property to %TRUE is the * equivalent of connecting a callback to the #ClutterTimeline::completed * signal and changing the direction of the timeline from that callback; * for instance, this code: * * |[ * static void * reverse_timeline (ClutterTimeline *timeline) * { * ClutterTimelineDirection dir = clutter_timeline_get_direction (timeline); * * if (dir == CLUTTER_TIMELINE_FORWARD) * dir = CLUTTER_TIMELINE_BACKWARD; * else * dir = CLUTTER_TIMELINE_FORWARD; * * clutter_timeline_set_direction (timeline, dir); * } * ... * timeline = clutter_timeline_new (1000); * clutter_timeline_set_repeat_count (timeline, -1); * g_signal_connect (timeline, "completed", * G_CALLBACK (reverse_timeline), * NULL); * ]| * * can be effectively replaced by: * * |[ * timeline = clutter_timeline_new (1000); * clutter_timeline_set_repeat_count (timeline, -1); * clutter_timeline_set_auto_reverse (timeline); * ]| * * Since: 1.6 */ void clutter_timeline_set_auto_reverse (ClutterTimeline *timeline, gboolean reverse) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); reverse = !!reverse; priv = timeline->priv; if (priv->auto_reverse != reverse) { priv->auto_reverse = reverse; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_AUTO_REVERSE]); } } /** * clutter_timeline_get_auto_reverse: * @timeline: a #ClutterTimeline * * Retrieves the value set by clutter_timeline_set_auto_reverse(). * * Return value: %TRUE if the timeline should automatically reverse, and * %FALSE otherwise * * Since: 1.6 */ gboolean clutter_timeline_get_auto_reverse (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); return timeline->priv->auto_reverse; } /** * clutter_timeline_set_repeat_count: * @timeline: a #ClutterTimeline * @count: the number of times the timeline should repeat * * Sets the number of times the @timeline should repeat. * * If @count is 0, the timeline never repeats. * * If @count is -1, the timeline will always repeat until * it's stopped. * * Since: 1.10 */ void clutter_timeline_set_repeat_count (ClutterTimeline *timeline, gint count) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (count >= -1); priv = timeline->priv; if (priv->repeat_count != count) { priv->repeat_count = count; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_REPEAT_COUNT]); } } /** * clutter_timeline_get_repeat_count: * @timeline: a #ClutterTimeline * * Retrieves the number set using clutter_timeline_set_repeat_count(). * * Return value: the number of repeats * * Since: 1.10 */ gint clutter_timeline_get_repeat_count (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); return timeline->priv->repeat_count; } /** * clutter_timeline_set_progress_func: * @timeline: a #ClutterTimeline * @func: (scope notified) (allow-none): a progress function, or %NULL * @data: (closure): data to pass to @func * @notify: a function to be called when the progress function is removed * or the timeline is disposed * * Sets a custom progress function for @timeline. The progress function will * be called by clutter_timeline_get_progress() and will be used to compute * the progress value based on the elapsed time and the total duration of the * timeline. * * If @func is not %NULL, the #ClutterTimeline:progress-mode property will * be set to %CLUTTER_CUSTOM_MODE. * * If @func is %NULL, any previously set progress function will be unset, and * the #ClutterTimeline:progress-mode property will be set to %CLUTTER_LINEAR. * * Since: 1.10 */ void clutter_timeline_set_progress_func (ClutterTimeline *timeline, ClutterTimelineProgressFunc func, gpointer data, GDestroyNotify notify) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->progress_notify != NULL) priv->progress_notify (priv->progress_data); priv->progress_func = func; priv->progress_data = data; priv->progress_notify = notify; if (priv->progress_func != NULL) priv->progress_mode = CLUTTER_CUSTOM_MODE; else priv->progress_mode = CLUTTER_LINEAR; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_PROGRESS_MODE]); } static gdouble clutter_timeline_progress_func (ClutterTimeline *timeline, gdouble elapsed, gdouble duration, gpointer user_data G_GNUC_UNUSED) { ClutterTimelinePrivate *priv = timeline->priv; /* parametrized easing functions need to be handled separately */ switch (priv->progress_mode) { case CLUTTER_STEPS: if (priv->step_mode == CLUTTER_STEP_MODE_START) return clutter_ease_steps_start (elapsed, duration, priv->n_steps); else if (priv->step_mode == CLUTTER_STEP_MODE_END) return clutter_ease_steps_end (elapsed, duration, priv->n_steps); else g_assert_not_reached (); break; case CLUTTER_STEP_START: return clutter_ease_steps_start (elapsed, duration, 1); case CLUTTER_STEP_END: return clutter_ease_steps_end (elapsed, duration, 1); case CLUTTER_CUBIC_BEZIER: return clutter_ease_cubic_bezier (elapsed, duration, priv->cb_1.x, priv->cb_1.y, priv->cb_2.x, priv->cb_2.y); case CLUTTER_EASE: return clutter_ease_cubic_bezier (elapsed, duration, 0.25, 0.1, 0.25, 1.0); case CLUTTER_EASE_IN: return clutter_ease_cubic_bezier (elapsed, duration, 0.42, 0.0, 1.0, 1.0); case CLUTTER_EASE_OUT: return clutter_ease_cubic_bezier (elapsed, duration, 0.0, 0.0, 0.58, 1.0); case CLUTTER_EASE_IN_OUT: return clutter_ease_cubic_bezier (elapsed, duration, 0.42, 0.0, 0.58, 1.0); default: break; } return clutter_easing_for_mode (priv->progress_mode, elapsed, duration); } /** * clutter_timeline_set_progress_mode: * @timeline: a #ClutterTimeline * @mode: the progress mode, as a #ClutterAnimationMode * * Sets the progress function using a value from the #ClutterAnimationMode * enumeration. The @mode cannot be %CLUTTER_CUSTOM_MODE or bigger than * %CLUTTER_ANIMATION_LAST. * * Since: 1.10 */ void clutter_timeline_set_progress_mode (ClutterTimeline *timeline, ClutterAnimationMode mode) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (mode < CLUTTER_ANIMATION_LAST); g_return_if_fail (mode != CLUTTER_CUSTOM_MODE); priv = timeline->priv; if (priv->progress_mode == mode) return; if (priv->progress_notify != NULL) priv->progress_notify (priv->progress_data); priv->progress_mode = mode; /* short-circuit linear progress */ if (priv->progress_mode != CLUTTER_LINEAR) priv->progress_func = clutter_timeline_progress_func; else priv->progress_func = NULL; priv->progress_data = NULL; priv->progress_notify = NULL; g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_PROGRESS_MODE]); } /** * clutter_timeline_get_progress_mode: * @timeline: a #ClutterTimeline * * Retrieves the progress mode set using clutter_timeline_set_progress_mode() * or clutter_timeline_set_progress_func(). * * Return value: a #ClutterAnimationMode * * Since: 1.10 */ ClutterAnimationMode clutter_timeline_get_progress_mode (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), CLUTTER_LINEAR); return timeline->priv->progress_mode; } /** * clutter_timeline_get_duration_hint: * @timeline: a #ClutterTimeline * * Retrieves the full duration of the @timeline, taking into account the * current value of the #ClutterTimeline:repeat-count property. * * If the #ClutterTimeline:repeat-count property is set to -1, this function * will return %G_MAXINT64. * * The returned value is to be considered a hint, and it's only valid * as long as the @timeline hasn't been changed. * * Return value: the full duration of the #ClutterTimeline * * Since: 1.10 */ gint64 clutter_timeline_get_duration_hint (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); priv = timeline->priv; if (priv->repeat_count == 0) return priv->duration; else if (priv->repeat_count < 0) return G_MAXINT64; else return priv->repeat_count * priv->duration; } /** * clutter_timeline_get_current_repeat: * @timeline: a #ClutterTimeline * * Retrieves the current repeat for a timeline. * * Repeats start at 0. * * Return value: the current repeat * * Since: 1.10 */ gint clutter_timeline_get_current_repeat (ClutterTimeline *timeline) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); return timeline->priv->current_repeat; } /** * clutter_timeline_set_step_progress: * @timeline: a #ClutterTimeline * @n_steps: the number of steps * @step_mode: whether the change should happen at the start * or at the end of the step * * Sets the #ClutterTimeline:progress-mode of the @timeline to %CLUTTER_STEPS * and provides the parameters of the step function. * * Since: 1.12 */ void clutter_timeline_set_step_progress (ClutterTimeline *timeline, gint n_steps, ClutterStepMode step_mode) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (n_steps > 0); priv = timeline->priv; if (priv->progress_mode == CLUTTER_STEPS && priv->n_steps == n_steps && priv->step_mode == step_mode) return; priv->n_steps = n_steps; priv->step_mode = step_mode; clutter_timeline_set_progress_mode (timeline, CLUTTER_STEPS); } /** * clutter_timeline_get_step_progress: * @timeline: a #ClutterTimeline * @n_steps: (out): return location for the number of steps, or %NULL * @step_mode: (out): return location for the value change policy, * or %NULL * * Retrieves the parameters of the step progress mode used by @timeline. * * Return value: %TRUE if the @timeline is using a step progress * mode, and %FALSE otherwise * * Since: 1.12 */ gboolean clutter_timeline_get_step_progress (ClutterTimeline *timeline, gint *n_steps, ClutterStepMode *step_mode) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); if (!(timeline->priv->progress_mode == CLUTTER_STEPS || timeline->priv->progress_mode == CLUTTER_STEP_START || timeline->priv->progress_mode == CLUTTER_STEP_END)) return FALSE; if (n_steps != NULL) *n_steps = timeline->priv->n_steps; if (step_mode != NULL) *step_mode = timeline->priv->step_mode; return TRUE; } /** * clutter_timeline_set_cubic_bezier_progress: * @timeline: a #ClutterTimeline * @c_1: the first control point for the cubic bezier * @c_2: the second control point for the cubic bezier * * Sets the #ClutterTimeline:progress-mode of @timeline * to %CLUTTER_CUBIC_BEZIER, and sets the two control * points for the cubic bezier. * * The cubic bezier curve is between (0, 0) and (1, 1). The X coordinate * of the two control points must be in the [ 0, 1 ] range, while the * Y coordinate of the two control points can exceed this range. * * Since: 1.12 */ void clutter_timeline_set_cubic_bezier_progress (ClutterTimeline *timeline, const ClutterPoint *c_1, const ClutterPoint *c_2) { ClutterTimelinePrivate *priv; g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (c_1 != NULL && c_2 != NULL); priv = timeline->priv; priv->cb_1 = *c_1; priv->cb_2 = *c_2; /* ensure the range on the X coordinate */ priv->cb_1.x = CLAMP (priv->cb_1.x, 0.f, 1.f); priv->cb_2.x = CLAMP (priv->cb_2.x, 0.f, 1.f); clutter_timeline_set_progress_mode (timeline, CLUTTER_CUBIC_BEZIER); } /** * clutter_timeline_get_cubic_bezier_progress: * @timeline: a #ClutterTimeline * @c_1: (out caller-allocates): return location for the first control * point of the cubic bezier, or %NULL * @c_2: (out caller-allocates): return location for the second control * point of the cubic bezier, or %NULL * * Retrieves the control points for the cubic bezier progress mode. * * Return value: %TRUE if the @timeline is using a cubic bezier progress * more, and %FALSE otherwise * * Since: 1.12 */ gboolean clutter_timeline_get_cubic_bezier_progress (ClutterTimeline *timeline, ClutterPoint *c_1, ClutterPoint *c_2) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE); if (!(timeline->priv->progress_mode == CLUTTER_CUBIC_BEZIER || timeline->priv->progress_mode == CLUTTER_EASE || timeline->priv->progress_mode == CLUTTER_EASE_IN || timeline->priv->progress_mode == CLUTTER_EASE_OUT || timeline->priv->progress_mode == CLUTTER_EASE_IN_OUT)) return FALSE; if (c_1 != NULL) *c_1 = timeline->priv->cb_1; if (c_2 != NULL) *c_2 = timeline->priv->cb_2; return TRUE; } �����������������������������������������������muffin-5.2.1/clutter/clutter/muffin-clutter.pc.in���������������������������������������������������0000664�0001750�0001750�00000001261�14211404421�022175� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@/muffin includedir=@includedir@/muffin apiversion=@MUFFIN_PLUGIN_API_VERSION@ requires=@CLUTTER_REQUIRES@ muffin-cogl-@MUFFIN_PLUGIN_API_VERSION@ requires_private=@CLUTTER_REQUIRES_PRIVATE@ backends=@CLUTTER_BACKENDS@ # only kept for backward compatibility soname_infix=@CLUTTER_SONAME_INFIX@ winsys=@CLUTTER_WINSYS@ backend=@CLUTTER_WINSYS@ cogl=deprecated cogl_driver=deprecated Name: Muffin Clutter Description: Muffin's Clutter Private Library Version: @MUFFIN_VERSION@ Libs: -L${libdir} -lmuffin-clutter-${apiversion} Cflags: -I${includedir}/clutter-${apiversion} Requires: ${requires} Requires.private: ${requires_private} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-paint-nodes.h��������������������������������������������������0000664�0001750�0001750�00000012634�14211404421�022360� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_PAINT_NODES_H__ #define __CLUTTER_PAINT_NODES_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <cogl/cogl.h> #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_COLOR_NODE (clutter_color_node_get_type ()) #define CLUTTER_COLOR_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_COLOR_NODE, ClutterColorNode)) #define CLUTTER_IS_COLOR_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_COLOR_NODE)) /** * ClutterColorNode: * * The #ClutterTextNode structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ typedef struct _ClutterColorNode ClutterColorNode; typedef struct _ClutterColorNodeClass ClutterColorNodeClass; CLUTTER_AVAILABLE_IN_1_10 GType clutter_color_node_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterPaintNode * clutter_color_node_new (const ClutterColor *color); #define CLUTTER_TYPE_TEXTURE_NODE (clutter_texture_node_get_type ()) #define CLUTTER_TEXTURE_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXTURE_NODE, ClutterTextureNode)) #define CLUTTER_IS_TEXTURE_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXTURE_NODE)) /** * ClutterTextureNode: * * The #ClutterTextNode structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ typedef struct _ClutterTextureNode ClutterTextureNode; typedef struct _ClutterTextureNodeClass ClutterTextureNodeClass; CLUTTER_AVAILABLE_IN_1_10 GType clutter_texture_node_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterPaintNode * clutter_texture_node_new (CoglTexture *texture, const ClutterColor *color, ClutterScalingFilter min_filter, ClutterScalingFilter mag_filter); #define CLUTTER_TYPE_CLIP_NODE (clutter_clip_node_get_type ()) #define CLUTTER_CLIP_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CLIP_NODE, ClutterClipNode)) #define CLUTTER_IS_CLIP_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CLIP_NODE)) /** * ClutterClipNode: * * The #ClutterTextNode structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ typedef struct _ClutterClipNode ClutterClipNode; typedef struct _ClutterClipNodeClass ClutterClipNodeClass; CLUTTER_AVAILABLE_IN_1_10 GType clutter_clip_node_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterPaintNode * clutter_clip_node_new (void); #define CLUTTER_TYPE_PIPELINE_NODE (clutter_pipeline_node_get_type ()) #define CLUTTER_PIPELINE_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PIPELINE_NODE, ClutterPipelineNode)) #define CLUTTER_IS_PIPELINE_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PIPELINE_NODE)) /** * ClutterPipelineNode: * * The #ClutterTextNode structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ typedef struct _ClutterPipelineNode ClutterPipelineNode; typedef struct _ClutterPipelineNodeClass ClutterPipelineNodeClass; CLUTTER_AVAILABLE_IN_1_10 GType clutter_pipeline_node_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterPaintNode * clutter_pipeline_node_new (CoglPipeline *pipeline); #define CLUTTER_TYPE_TEXT_NODE (clutter_text_node_get_type ()) #define CLUTTER_TEXT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXT_NODE, ClutterTextNode)) #define CLUTTER_IS_TEXT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXT_NODE)) /** * ClutterTextNode: * * The #ClutterTextNode structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ typedef struct _ClutterTextNode ClutterTextNode; typedef struct _ClutterTextNodeClass ClutterTextNodeClass; CLUTTER_AVAILABLE_IN_1_10 GType clutter_text_node_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterPaintNode * clutter_text_node_new (PangoLayout *layout, const ClutterColor *color); G_END_DECLS #endif /* __CLUTTER_PAINT_NODES_H__ */ ����������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/Makefile.am������������������������������������������������������������0000664�0001750�0001750�00000053432�14211404421�020343� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������AUTOMAKE_OPTIONS = subdir-objects # preamble NULL = # common definitions CLEANFILES = DISTCLEANFILES = EXTRA_DIST = BUILT_SOURCES = AM_CPPFLAGS = \ -DCLUTTER_PREFIX=\""$(prefix)"\" \ -DCLUTTER_LIBDIR=\""$(libdir)"\" \ -DCLUTTER_DATADIR=\""$(datadir)"\" \ -DCLUTTER_LOCALEDIR=\""$(localedir)"\" \ -DCLUTTER_SYSCONFDIR=\""$(sysconfdir)"\" \ -DCLUTTER_COMPILATION=1 \ -DCOGL_DISABLE_DEPRECATION_WARNINGS \ -DG_LOG_DOMAIN=\"Clutter\" \ -I$(top_srcdir) \ -I$(top_srcdir)/clutter \ -I$(top_srcdir)/clutter/cally \ -I$(top_builddir) \ -I$(top_builddir)/clutter \ -I$(top_srcdir)/../cogl \ -I$(top_builddir)/../cogl \ -I$(top_builddir)/../cogl/cogl \ $(CLUTTER_DEPRECATED_CFLAGS) \ $(CLUTTER_DEBUG_CFLAGS) \ $(CLUTTER_HIDDEN_VISIBILITY_CFLAGS) \ $(NULL) AM_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) # these are the gir files we generate using g-ir-scanner INTROSPECTION_GIRS = # the base include path for headers clutter_base_includedir = $(includedir)/muffin/clutter-$(MUFFIN_PLUGIN_API_VERSION) clutter_includedir = $(clutter_base_includedir)/clutter clutter_deprecateddir = $(clutter_base_includedir)/clutter/deprecated # pkg-config files pc_files = # common sources - please, keep these sorted alphabetically source_h = \ clutter-action.h \ clutter-actor-meta.h \ clutter-actor.h \ clutter-align-constraint.h \ clutter-animatable.h \ clutter-backend.h \ clutter-bind-constraint.h \ clutter-binding-pool.h \ clutter-bin-layout.h \ clutter-blur-effect.h \ clutter-box-layout.h \ clutter-brightness-contrast-effect.h \ clutter-cairo.h \ clutter-canvas.h \ clutter-child-meta.h \ clutter-click-action.h \ clutter-clone.h \ clutter-color-static.h \ clutter-color.h \ clutter-colorize-effect.h \ clutter-constraint.h \ clutter-container.h \ clutter-content.h \ clutter-deform-effect.h \ clutter-deprecated.h \ clutter-desaturate-effect.h \ clutter-device-manager.h \ clutter-drag-action.h \ clutter-drop-action.h \ clutter-effect.h \ clutter-enums.h \ clutter-event.h \ clutter-feature.h \ clutter-fixed-layout.h \ clutter-flow-layout.h \ clutter-gesture-action.h \ clutter-grid-layout.h \ clutter-group.h \ clutter-image.h \ clutter-input-device.h \ clutter-input-device-tool.h \ clutter-input-focus.h \ clutter-input-method.h \ clutter-interval.h \ clutter-keyframe-transition.h \ clutter-keysyms.h \ clutter-layout-manager.h \ clutter-layout-meta.h \ clutter-macros.h \ clutter-main.h \ clutter-offscreen-effect.h \ clutter-page-turn-effect.h \ clutter-paint-nodes.h \ clutter-paint-node.h \ clutter-pan-action.h \ clutter-path-constraint.h \ clutter-path.h \ clutter-property-transition.h \ clutter-rotate-action.h \ clutter-script.h \ clutter-scriptable.h \ clutter-scroll-actor.h \ clutter-settings.h \ clutter-shader-effect.h \ clutter-shader-types.h \ clutter-swipe-action.h \ clutter-snap-constraint.h \ clutter-stage.h \ clutter-stage-manager.h \ clutter-tap-action.h \ clutter-test-utils.h \ clutter-texture.h \ clutter-text.h \ clutter-text-buffer.h \ clutter-timeline.h \ clutter-transition-group.h \ clutter-transition.h \ clutter-types.h \ clutter-units.h \ clutter-virtual-input-device.h \ clutter-zoom-action.h \ $(NULL) source_c = \ clutter-action.c \ clutter-actor-box.c \ clutter-actor-meta.c \ clutter-actor.c \ clutter-align-constraint.c \ clutter-animatable.c \ clutter-backend.c \ clutter-base-types.c \ clutter-bezier.c \ clutter-bind-constraint.c \ clutter-binding-pool.c \ clutter-bin-layout.c \ clutter-blur-effect.c \ clutter-box-layout.c \ clutter-brightness-contrast-effect.c \ clutter-cairo.c \ clutter-canvas.c \ clutter-child-meta.c \ clutter-click-action.c \ clutter-clone.c \ clutter-color.c \ clutter-colorize-effect.c \ clutter-constraint.c \ clutter-container.c \ clutter-content.c \ clutter-deform-effect.c \ clutter-desaturate-effect.c \ clutter-device-manager.c \ clutter-drag-action.c \ clutter-drop-action.c \ clutter-effect.c \ clutter-event.c \ clutter-feature.c \ clutter-fixed-layout.c \ clutter-flatten-effect.c \ clutter-flow-layout.c \ clutter-gesture-action.c \ clutter-grid-layout.c \ clutter-image.c \ clutter-input-device.c \ clutter-input-device-tool.c \ clutter-input-focus.c \ clutter-input-method.c \ clutter-virtual-input-device.c \ clutter-interval.c \ clutter-keyframe-transition.c \ clutter-keysyms-table.c \ clutter-layout-manager.c \ clutter-layout-meta.c \ clutter-main.c \ clutter-master-clock.c \ clutter-master-clock-default.c \ clutter-offscreen-effect.c \ clutter-page-turn-effect.c \ clutter-paint-nodes.c \ clutter-paint-node.c \ clutter-pan-action.c \ clutter-path-constraint.c \ clutter-path.c \ clutter-property-transition.c \ clutter-rotate-action.c \ clutter-script.c \ clutter-script-parser.c \ clutter-scriptable.c \ clutter-scroll-actor.c \ clutter-settings.c \ clutter-shader-effect.c \ clutter-shader-types.c \ clutter-swipe-action.c \ clutter-snap-constraint.c \ clutter-stage.c \ clutter-stage-manager.c \ clutter-stage-window.c \ clutter-tap-action.c \ clutter-test-utils.c \ clutter-text.c \ clutter-text-buffer.c \ clutter-transition-group.c \ clutter-transition.c \ clutter-timeline.c \ clutter-units.c \ clutter-util.c \ clutter-paint-volume.c \ clutter-zoom-action.c \ $(NULL) # private headers; these should not be distributed or introspected source_h_priv = \ clutter-actor-meta-private.h \ clutter-actor-private.h \ clutter-backend-private.h \ clutter-bezier.h \ clutter-constraint-private.h \ clutter-content-private.h \ clutter-debug.h \ clutter-device-manager-private.h \ clutter-easing.h \ clutter-effect-private.h \ clutter-event-translator.h \ clutter-event-private.h \ clutter-flatten-effect.h \ clutter-gesture-action-private.h \ clutter-id-pool.h \ clutter-input-focus-private.h \ clutter-input-method-private.h \ clutter-master-clock.h \ clutter-master-clock-default.h \ clutter-offscreen-effect-private.h \ clutter-paint-node-private.h \ clutter-paint-volume-private.h \ clutter-private.h \ clutter-script-private.h \ clutter-settings-private.h \ clutter-stage-manager-private.h \ clutter-stage-private.h \ clutter-stage-view.h \ clutter-stage-window.h \ $(NULL) # private source code; these should not be introspected source_c_priv = \ clutter-easing.c \ clutter-event-translator.c \ clutter-id-pool.c \ clutter-stage-view.c \ $(NULL) # deprecated installed headers deprecated_h = \ deprecated/clutter-actor.h \ deprecated/clutter-alpha.h \ deprecated/clutter-animatable.h \ deprecated/clutter-animation.h \ deprecated/clutter-animator.h \ deprecated/clutter-backend.h \ deprecated/clutter-behaviour.h \ deprecated/clutter-behaviour-depth.h \ deprecated/clutter-behaviour-ellipse.h \ deprecated/clutter-behaviour-opacity.h \ deprecated/clutter-behaviour-path.h \ deprecated/clutter-behaviour-rotate.h \ deprecated/clutter-behaviour-scale.h \ deprecated/clutter-bin-layout.h \ deprecated/clutter-box.h \ deprecated/clutter-cairo-texture.h \ deprecated/clutter-container.h \ deprecated/clutter-frame-source.h \ deprecated/clutter-group.h \ deprecated/clutter-input-device.h \ deprecated/clutter-keysyms.h \ deprecated/clutter-list-model.h \ deprecated/clutter-main.h \ deprecated/clutter-media.h \ deprecated/clutter-model.h \ deprecated/clutter-rectangle.h \ deprecated/clutter-score.h \ deprecated/clutter-shader.h \ deprecated/clutter-stage-manager.h \ deprecated/clutter-stage.h \ deprecated/clutter-state.h \ deprecated/clutter-table-layout.h \ deprecated/clutter-texture.h \ deprecated/clutter-timeline.h \ deprecated/clutter-timeout-pool.h \ deprecated/clutter-util.h \ $(NULL) # deprecated source code deprecated_c = \ deprecated/clutter-actor-deprecated.c \ deprecated/clutter-alpha.c \ deprecated/clutter-animation.c \ deprecated/clutter-animator.c \ deprecated/clutter-behaviour.c \ deprecated/clutter-behaviour-depth.c \ deprecated/clutter-behaviour-ellipse.c \ deprecated/clutter-behaviour-opacity.c \ deprecated/clutter-behaviour-path.c \ deprecated/clutter-behaviour-rotate.c \ deprecated/clutter-behaviour-scale.c \ deprecated/clutter-box.c \ deprecated/clutter-cairo-texture.c \ deprecated/clutter-frame-source.c \ deprecated/clutter-group.c \ deprecated/clutter-input-device-deprecated.c \ deprecated/clutter-layout-manager-deprecated.c \ deprecated/clutter-list-model.c \ deprecated/clutter-media.c \ deprecated/clutter-model.c \ deprecated/clutter-rectangle.c \ deprecated/clutter-score.c \ deprecated/clutter-shader.c \ deprecated/clutter-state.c \ deprecated/clutter-table-layout.c \ deprecated/clutter-texture.c \ deprecated/clutter-timeout-pool.c \ $(NULL) # deprecated private headers; these should not be installed deprecated_h_priv = \ deprecated/clutter-model-private.h \ deprecated/clutter-timeout-interval.h \ $(NULL) # deprecated private source code; these should not be introspected deprecated_c_priv = \ deprecated/clutter-timeout-interval.c \ $(NULL) # built sources built_source_c = \ clutter-enum-types.c \ clutter-marshal.c \ $(NULL) # built headers built_source_h = \ clutter-enum-types.h \ clutter-marshal.h \ $(NULL) # config header DISTCLEANFILES += clutter-config.h EXTRA_DIST += clutter-config.h.in # version header DISTCLEANFILES += clutter-version.h EXTRA_DIST += clutter-version.h.in clutter-version.h # key symbol update script EXTRA_DIST += clutter-keysyms-update.pl pc_files += muffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).pc # in order to be compatible with Clutter < 1.10, when we shipped a single # shared library whose name was determined by the single backend it # supported, we need to install symbolic links so that existing applications # using Clutter won't break in the Brave New World of multi-backend support # in the same shared object. compat_libs = # backends source listings # # backend_source_c := source code # backend_source_h := installed public headers # backend_source_c_priv := source that should not be scanned by g-i # backend_source_h_priv := private headers # backend_source_built := built sources # backend_source_c = backend_source_h = backend_source_c_priv = backend_source_h_priv = backend_source_built = # X11 backend rules x11_source_c = \ x11/clutter-backend-x11.c \ x11/clutter-device-manager-core-x11.c \ x11/clutter-event-x11.c \ x11/clutter-input-device-core-x11.c \ x11/clutter-keymap-x11.c \ x11/clutter-stage-x11.c \ x11/clutter-x11-texture-pixmap.c \ x11/clutter-xkb-a11y-x11.c \ $(NULL) x11_source_h = \ x11/clutter-x11.h \ x11/clutter-x11-texture-pixmap.h \ $(NULL) x11_source_h_priv = \ x11/clutter-backend-x11.h \ x11/clutter-device-manager-core-x11.h \ x11/clutter-input-device-core-x11.h \ x11/clutter-keymap-x11.h \ x11/clutter-settings-x11.h \ x11/clutter-stage-x11.h \ x11/clutter-xkb-a11y-x11.h \ $(NULL) x11_source_c_priv = \ x11/xsettings/xsettings-client.c \ x11/xsettings/xsettings-client.h \ x11/xsettings/xsettings-common.c \ x11/xsettings/xsettings-common.h \ $(NULL) x11_source_c += \ x11/clutter-device-manager-xi2.c \ x11/clutter-input-device-xi2.c \ x11/clutter-input-device-tool-xi2.c \ $(NULL) x11_source_h_priv += \ x11/clutter-device-manager-xi2.h \ x11/clutter-input-device-xi2.h \ x11/clutter-input-device-tool-xi2.h \ $(NULL) x11_source_c += \ x11/clutter-virtual-input-device-x11.c \ $(NULL) x11_source_h_priv += \ x11/clutter-virtual-input-device-x11.h \ $(NULL) backend_source_h += $(x11_source_h) backend_source_c += $(x11_source_c) backend_source_h_priv += $(x11_source_h_priv) backend_source_c_priv += $(x11_source_c_priv) # the list of files we want to introspect on X11 x11_introspection = $(x11_source_c) $(x11_source_h) clutterx11_includedir = $(clutter_includedir)/x11 clutterx11_include_HEADERS = $(x11_source_h) muffin-clutter-x11-@MUFFIN_PLUGIN_API_VERSION@.pc: muffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).pc $(QUIET_GEN)cp -f $< $(@F) pc_files += muffin-clutter-x11-$(MUFFIN_PLUGIN_API_VERSION).pc # Shared cogl backend files cogl_source_h = cogl_source_c = \ cogl/clutter-stage-cogl.c \ $(NULL) cogl_source_h_priv = \ cogl/clutter-stage-cogl.h \ $(NULL) cogl_source_c_priv = backend_source_h += $(cogl_source_h) backend_source_c += $(cogl_source_c) backend_source_h_priv += $(cogl_source_h_priv) backend_source_c_priv += $(cogl_source_c_priv) backend_source_h += $(glx_source_h) backend_source_c += $(glx_source_c) evdev_c_priv = \ evdev/clutter-device-manager-evdev.c \ evdev/clutter-input-device-evdev.c \ evdev/clutter-seat-evdev.c \ evdev/clutter-virtual-input-device-evdev.c \ evdev/clutter-event-evdev.c \ evdev/clutter-input-device-tool-evdev.c \ $(NULL) evdev_h_priv = \ evdev/clutter-device-manager-evdev.h \ evdev/clutter-input-device-evdev.h \ evdev/clutter-seat-evdev.h \ evdev/clutter-input-device-tool-evdev.h \ evdev/clutter-virtual-input-device-evdev.h \ $(NULL) evdev_h = evdev/clutter-evdev.h if SUPPORT_WAYLAND backend_source_c_priv += $(evdev_c_priv) backend_source_h_priv += $(evdev_h_priv) backend_source_h += $(evdev_h) clutterevdev_includedir = $(clutter_includedir)/evdev clutterevdev_include_HEADERS = $(evdev_h) backend_source_c += evdev/clutter-xkb-utils.c backend_source_h_priv += evdev/clutter-xkb-utils.h # EGL backend rules egl_source_h = \ egl/clutter-egl-headers.h \ egl/clutter-egl.h \ $(NULL) egl_source_h_priv = egl/clutter-backend-eglnative.h egl_source_c = egl/clutter-backend-eglnative.c wayland_compositor_source_h = \ wayland/clutter-wayland-compositor.h \ wayland/clutter-wayland-surface.h backend_source_h += $(wayland_compositor_source_h) backend_source_c += \ wayland/clutter-wayland-surface.c wayland_compositor_includedir = $(clutter_includedir)/wayland wayland_compositor_include_HEADERS = $(wayland_compositor_source_h) backend_source_h += $(egl_source_h) backend_source_c += $(egl_source_c) backend_source_h_priv += $(egl_source_h_priv) clutteregl_includedir = $(clutter_includedir)/egl clutteregl_include_HEADERS = $(egl_source_h) endif # SUPPORT_WAYLAND # cally cally_sources_h = \ cally/cally-actor.h \ cally/cally-clone.h \ cally/cally-factory.h \ cally/cally-group.h \ cally/cally.h \ cally/cally-main.h \ cally/cally-rectangle.h \ cally/cally-root.h \ cally/cally-stage.h \ cally/cally-text.h \ cally/cally-texture.h \ cally/cally-util.h \ $(NULL) cally_sources_c = \ cally/cally-actor.c \ cally/cally.c \ cally/cally-clone.c \ cally/cally-group.c \ cally/cally-rectangle.c \ cally/cally-root.c \ cally/cally-stage.c \ cally/cally-text.c \ cally/cally-texture.c \ cally/cally-util.c \ $(NULL) cally_sources_private = \ cally/cally-actor-private.h \ $(NULL) cally_includedir = $(clutter_base_includedir)/cally cally_include_HEADERS = $(cally_sources_h) # general build rules: # you should not need to modify anything below this point # glib-genmarshal rules glib_marshal_list = clutter-marshal.list glib_marshal_prefix = _clutter_marshal include $(srcdir)/Makefile.am.marshal # glib-mkenums rules glib_enum_h = clutter-enum-types.h glib_enum_c = clutter-enum-types.c glib_enum_headers = $(source_h) $(deprecated_h) include $(srcdir)/Makefile.am.enums pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pc_files) DISTCLEANFILES += $(pc_files) clutter_include_HEADERS = $(source_h) clutter.h clutter-version.h clutter-autocleanups.h clutter-muffin.h nodist_clutter_include_HEADERS = clutter-config.h $(built_source_h) clutter_deprecated_HEADERS = $(deprecated_h) muffinlibdir = $(libdir)/muffin muffinlib_LTLIBRARIES = libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la libmuffin_clutter_@MUFFIN_PLUGIN_API_VERSION@_la_LIBADD = \ $(LIBM) \ $(CLUTTER_LIBS) \ $(top_builddir)/../cogl/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la \ $(top_builddir)/../cogl/cogl-pango/libmuffin-cogl-pango-$(MUFFIN_PLUGIN_API_VERSION).la \ $(top_builddir)/../cogl/cogl-path/libmuffin-cogl-path-$(MUFFIN_PLUGIN_API_VERSION).la \ $(NULL) libmuffin_clutter_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = \ $(backend_source_c) \ $(backend_source_h) \ $(backend_source_c_priv) \ $(backend_source_h_priv) \ $(source_c) \ $(source_h) \ $(source_c_priv) \ $(source_h_priv) \ $(deprecated_c) \ $(deprecated_h) \ $(deprecated_c_priv) \ $(deprecated_h_priv) \ $(cally_sources_c) \ $(cally_sources_h) \ $(cally_sources_private) \ $(NULL) nodist_libmuffin_clutter_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = \ $(backend_source_built) \ $(built_source_c) \ $(built_source_h) libmuffin_clutter_@MUFFIN_PLUGIN_API_VERSION@_la_LDFLAGS = \ $(CLUTTER_LINK_FLAGS) \ $(CLUTTER_LT_LDFLAGS) \ -export-dynamic \ -rpath $(muffinlibdir) \ $(NULL) install-exec-local: test -z "$(muffinlibdir)" || $(MKDIR_P) "$(DESTDIR)$(muffinlibdir)" for lib in `echo $(compat_libs)`; do \ (cd $(DESTDIR)$(muffinlibdir) && \ rm -f $$lib.0.$(CLUTTER_LT_CURRENT).$(CLUTTER_LT_REVISION); \ ) ; \ (cd $(DESTDIR)$(muffinlibdir) && \ { ln -s -f libmuffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).so.0.$(CLUTTER_LT_CURRENT).$(CLUTTER_LT_REVISION) $$lib.0 || \ { rm -f $$lib.0 && ln -s libmuffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).so.0.$(CLUTTER_LT_CURRENT).$(CLUTTER_LT_REVISION) $$lib.0; }; \ } \ ) ; \ (cd $(DESTDIR)$(muffinlibdir) && \ { ln -s -f libmuffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).so.0.$(CLUTTER_LT_CURRENT).$(CLUTTER_LT_REVISION) $$lib || \ { rm -f $$lib && ln -s libmuffin-clutter-$(MUFFIN_PLUGIN_API_VERSION).so.0.$(CLUTTER_LT_CURRENT).$(CLUTTER_LT_REVISION) $$lib; }; \ } \ ) ; \ done if HAVE_INTROSPECTION # gobject-introspection rules -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_SCANNER_ARGS = \ --add-include-path=$(top_builddir)/../cogl/cogl \ --add-include-path=$(top_builddir)/../cogl/cogl-pango INTROSPECTION_COMPILER_ARGS = \ --includedir=$(top_builddir)/../cogl/cogl \ --includedir=$(top_builddir)/../cogl/cogl-pango INTROSPECTION_SCANNER_ENV = \ PKG_CONFIG_PATH=$(top_builddir)/../cogl/cogl/:$(top_builddir)/../cogl/cogl-pango/:$${PKG_CONFIG_PATH} Clutter-@MUFFIN_PLUGIN_API_VERSION@.gir: libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la Makefile Clutter_@MUFFIN_PLUGIN_API_VERSION@_gir_NAMESPACE = Clutter Clutter_@MUFFIN_PLUGIN_API_VERSION@_gir_VERSION = @MUFFIN_PLUGIN_API_VERSION@ Clutter_@MUFFIN_PLUGIN_API_VERSION@_gir_LIBS = \ libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl/libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl-pango/libmuffin-cogl-pango-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl-path/libmuffin-cogl-path-@MUFFIN_PLUGIN_API_VERSION@.la Clutter_@MUFFIN_PLUGIN_API_VERSION@_gir_FILES = \ $(clutter_include_HEADERS) \ $(clutter_deprecated_HEADERS) \ $(nodist_clutter_include_HEADERS) \ $(source_c) \ $(deprecated_c) \ $(built_source_c) Clutter_@MUFFIN_PLUGIN_API_VERSION@_gir_CFLAGS = $(AM_CPPFLAGS) $(CLUTTER_CFLAGS) Clutter_@MUFFIN_PLUGIN_API_VERSION@_gir_INCLUDES = GL-1.0 GObject-2.0 cairo-1.0 Cogl-@MUFFIN_PLUGIN_API_VERSION@ CoglPango-@MUFFIN_PLUGIN_API_VERSION@ Atk-1.0 Json-1.0 Clutter_@MUFFIN_PLUGIN_API_VERSION@_gir_SCANNERFLAGS = \ --warn-all \ --c-include='clutter/clutter.h' \ --pkg-export=muffin-clutter-@MUFFIN_PLUGIN_API_VERSION@ INTROSPECTION_GIRS += Clutter-@MUFFIN_PLUGIN_API_VERSION@.gir Cally-@MUFFIN_PLUGIN_API_VERSION@.gir: Makefile Clutter-@MUFFIN_PLUGIN_API_VERSION@.gir Cally_@MUFFIN_PLUGIN_API_VERSION@_gir_NAMESPACE = Cally Cally_@MUFFIN_PLUGIN_API_VERSION@_gir_VERSION = @MUFFIN_PLUGIN_API_VERSION@ Cally_@MUFFIN_PLUGIN_API_VERSION@_gir_LIBS = \ libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl/libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl-pango/libmuffin-cogl-pango-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl-path/libmuffin-cogl-path-@MUFFIN_PLUGIN_API_VERSION@.la Cally_@MUFFIN_PLUGIN_API_VERSION@_gir_FILES = $(cally_sources_h) $(cally_sources_c) Cally_@MUFFIN_PLUGIN_API_VERSION@_gir_CFLAGS = $(AM_CPPFLAGS) $(CLUTTER_CFLAGS) Cally_@MUFFIN_PLUGIN_API_VERSION@_gir_SCANNERFLAGS = \ --warn-all \ --c-include='cally/cally.h' \ --pkg-export=muffin-clutter-@MUFFIN_PLUGIN_API_VERSION@ \ --include-uninstalled=$(top_builddir)/clutter/Clutter-@MUFFIN_PLUGIN_API_VERSION@.gir INTROSPECTION_GIRS += Cally-@MUFFIN_PLUGIN_API_VERSION@.gir ClutterX11-@MUFFIN_PLUGIN_API_VERSION@.gir: Makefile Clutter-@MUFFIN_PLUGIN_API_VERSION@.gir ClutterX11_@MUFFIN_PLUGIN_API_VERSION@_gir_NAMESPACE = ClutterX11 ClutterX11_@MUFFIN_PLUGIN_API_VERSION@_gir_INCLUDES = xlib-2.0 ClutterX11_@MUFFIN_PLUGIN_API_VERSION@_gir_LIBS = \ libmuffin-clutter-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl/libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl-pango/libmuffin-cogl-pango-@MUFFIN_PLUGIN_API_VERSION@.la \ $(top_builddir)/../cogl/cogl-path/libmuffin-cogl-path-@MUFFIN_PLUGIN_API_VERSION@.la ClutterX11_@MUFFIN_PLUGIN_API_VERSION@_gir_FILES = $(x11_introspection) ClutterX11_@MUFFIN_PLUGIN_API_VERSION@_gir_CFLAGS = $(AM_CPPFLAGS) $(CLUTTER_CFLAGS) ClutterX11_@MUFFIN_PLUGIN_API_VERSION@_gir_SCANNERFLAGS = \ --warn-all \ --c-include='clutter/x11/clutter-x11.h' \ --pkg-export=muffin-clutter-x11-@MUFFIN_PLUGIN_API_VERSION@ \ --include-uninstalled=$(top_builddir)/clutter/Clutter-@MUFFIN_PLUGIN_API_VERSION@.gir INTROSPECTION_GIRS += ClutterX11-@MUFFIN_PLUGIN_API_VERSION@.gir # INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to # install anything - we need to install inside our prefix. girdir = $(muffinlibdir) gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(muffinlibdir) typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) endif EXTRA_DIST += \ Makefile.am.marshal \ Makefile.am.enums ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-content-private.h����������������������������������������������0000664�0001750�0001750�00000003120�14211404421�023247� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_CONTENT_PRIVATE_H__ #define __CLUTTER_CONTENT_PRIVATE_H__ #include <clutter/clutter-content.h> G_BEGIN_DECLS void _clutter_content_attached (ClutterContent *content, ClutterActor *actor); void _clutter_content_detached (ClutterContent *content, ClutterActor *actor); void _clutter_content_paint_content (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *node); G_END_DECLS #endif /* __CLUTTER_CONTENT_PRIVATE_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-actor-box-private.h��������������������������������������������0000664�0001750�0001750�00000000403�14211404421�023474� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_ACTOR_BOX_PRIVATE_H__ #define __CLUTTER_ACTOR_BOX_PRIVATE_H__ #include <clutter/clutter-types.h> G_BEGIN_DECLS void _clutter_actor_box_enlarge_for_effects (ClutterActorBox *box); G_END_DECLS #endif /* __CLUTTER_ACTOR_BOX_PRIVATE_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/�������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�016711� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-keymap-x11.h�����������������������������������������������0000664�0001750�0001750�00000004473�14211404421�022447� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_KEYMAP_X11_H__ #define __CLUTTER_KEYMAP_X11_H__ #include <glib-object.h> #include <pango/pango.h> #include <clutter/clutter-event.h> G_BEGIN_DECLS #define CLUTTER_TYPE_KEYMAP_X11 (_clutter_keymap_x11_get_type ()) #define CLUTTER_KEYMAP_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_KEYMAP_X11, ClutterKeymapX11)) #define CLUTTER_IS_KEYMAP_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_KEYMAP_X11)) typedef struct _ClutterKeymapX11 ClutterKeymapX11; GType _clutter_keymap_x11_get_type (void) G_GNUC_CONST; gint _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap, ClutterModifierType state); gboolean _clutter_keymap_x11_get_num_lock_state (ClutterKeymapX11 *keymap); gboolean _clutter_keymap_x11_get_caps_lock_state (ClutterKeymapX11 *keymap); gint _clutter_keymap_x11_translate_key_state (ClutterKeymapX11 *keymap, guint hardware_keycode, ClutterModifierType *modifier_state_p, ClutterModifierType *mods_p); gboolean _clutter_keymap_x11_get_is_modifier (ClutterKeymapX11 *keymap, gint keycode); PangoDirection _clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap); G_END_DECLS #endif /* __CLUTTER_KEYMAP_X11_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-keymap-x11.c�����������������������������������������������0000664�0001750�0001750�00000044202�14211404421�022434� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #include "clutter-build-config.h" #include "clutter-keymap-x11.h" #include "clutter-backend-x11.h" #include "clutter-debug.h" #include "clutter-event-translator.h" #include "clutter-private.h" #include <X11/Xatom.h> #ifdef HAVE_XKB #include <X11/XKBlib.h> #endif typedef struct _ClutterKeymapX11Class ClutterKeymapX11Class; typedef struct _DirectionCacheEntry DirectionCacheEntry; struct _DirectionCacheEntry { guint serial; Atom group_atom; PangoDirection direction; }; struct _ClutterKeymapX11 { GObject parent_instance; ClutterBackend *backend; int min_keycode; int max_keycode; ClutterModifierType modmap[8]; ClutterModifierType num_lock_mask; ClutterModifierType scroll_lock_mask; PangoDirection current_direction; #ifdef HAVE_XKB XkbDescPtr xkb_desc; int xkb_event_base; guint xkb_map_serial; Atom current_group_atom; guint current_cache_serial; DirectionCacheEntry group_direction_cache[4]; #endif guint caps_lock_state : 1; guint num_lock_state : 1; guint has_direction : 1; }; struct _ClutterKeymapX11Class { GObjectClass parent_class; }; enum { PROP_0, PROP_BACKEND, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface); #define clutter_keymap_x11_get_type _clutter_keymap_x11_get_type G_DEFINE_TYPE_WITH_CODE (ClutterKeymapX11, clutter_keymap_x11, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR, clutter_event_translator_iface_init)); #ifdef HAVE_XKB /* code adapted from gdk/x11/gdkkeys-x11.c - update_modmap */ static void update_modmap (Display *display, ClutterKeymapX11 *keymap_x11) { static struct { const gchar *name; Atom atom; ClutterModifierType mask; } vmods[] = { { "Meta", 0, CLUTTER_META_MASK }, { "Super", 0, CLUTTER_SUPER_MASK }, { "Hyper", 0, CLUTTER_HYPER_MASK }, { NULL, 0, 0 } }; int i, j, k; if (vmods[0].atom == 0) for (i = 0; vmods[i].name; i++) vmods[i].atom = XInternAtom (display, vmods[i].name, FALSE); for (i = 0; i < 8; i++) keymap_x11->modmap[i] = 1 << i; for (i = 0; i < XkbNumVirtualMods; i++) { for (j = 0; vmods[j].atom; j++) { if (keymap_x11->xkb_desc->names->vmods[i] == vmods[j].atom) { for (k = 0; k < 8; k++) { if (keymap_x11->xkb_desc->server->vmods[i] & (1 << k)) keymap_x11->modmap[k] |= vmods[j].mask; } } } } } static XkbDescPtr get_xkb (ClutterKeymapX11 *keymap_x11) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend); if (keymap_x11->max_keycode == 0) XDisplayKeycodes (backend_x11->xdpy, &keymap_x11->min_keycode, &keymap_x11->max_keycode); if (keymap_x11->xkb_desc == NULL) { int flags = XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask; keymap_x11->xkb_desc = XkbGetMap (backend_x11->xdpy, flags, XkbUseCoreKbd); if (G_UNLIKELY (keymap_x11->xkb_desc == NULL)) { g_error ("Failed to get the keymap from XKB"); return NULL; } flags = XkbGroupNamesMask | XkbVirtualModNamesMask; XkbGetNames (backend_x11->xdpy, flags, keymap_x11->xkb_desc); update_modmap (backend_x11->xdpy, keymap_x11); } else if (keymap_x11->xkb_map_serial != backend_x11->keymap_serial) { int flags = XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask; CLUTTER_NOTE (BACKEND, "Updating XKB keymap"); XkbGetUpdatedMap (backend_x11->xdpy, flags, keymap_x11->xkb_desc); flags = XkbGroupNamesMask | XkbVirtualModNamesMask; XkbGetNames (backend_x11->xdpy, flags, keymap_x11->xkb_desc); update_modmap (backend_x11->xdpy, keymap_x11); keymap_x11->xkb_map_serial = backend_x11->keymap_serial; } if (keymap_x11->num_lock_mask == 0) keymap_x11->num_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy, XK_Num_Lock); if (keymap_x11->scroll_lock_mask == 0) keymap_x11->scroll_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy, XK_Scroll_Lock); return keymap_x11->xkb_desc; } #endif /* HAVE_XKB */ #ifdef HAVE_XKB static void update_locked_mods (ClutterKeymapX11 *keymap_x11, gint locked_mods) { #if 0 gboolean old_caps_lock_state, old_num_lock_state; old_caps_lock_state = keymap_x11->caps_lock_state; old_num_lock_state = keymap_x11->num_lock_state; #endif keymap_x11->caps_lock_state = (locked_mods & CLUTTER_LOCK_MASK) != 0; keymap_x11->num_lock_state = (locked_mods & keymap_x11->num_lock_mask) != 0; CLUTTER_NOTE (BACKEND, "Locks state changed - Num: %s, Caps: %s", keymap_x11->num_lock_state ? "set" : "unset", keymap_x11->caps_lock_state ? "set" : "unset"); #if 0 /* Add signal to ClutterBackend? */ if ((keymap_x11->caps_lock_state != old_caps_lock_state) || (keymap_x11->num_lock_state != old_num_lock_state)) g_signal_emit_by_name (keymap_x11->backend, "key-lock-changed"); #endif } #endif /* HAVE_XKB */ #ifdef HAVE_XKB /* the code to retrieve the keymap direction and cache it * is taken from GDK: * gdk/x11/gdkkeys-x11.c */ static PangoDirection get_direction (XkbDescPtr xkb, int group) { int rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */ int code; for (code = xkb->min_key_code; code <= xkb->max_key_code; code += 1) { int level = 0; KeySym sym = XkbKeySymEntry (xkb, code, level, group); PangoDirection dir = pango_unichar_direction (clutter_keysym_to_unicode (sym)); switch (dir) { case PANGO_DIRECTION_RTL: rtl_minus_ltr++; break; case PANGO_DIRECTION_LTR: rtl_minus_ltr--; break; default: break; } } if (rtl_minus_ltr > 0) return PANGO_DIRECTION_RTL; return PANGO_DIRECTION_LTR; } static PangoDirection get_direction_from_cache (ClutterKeymapX11 *keymap_x11, XkbDescPtr xkb, int group) { Atom group_atom = xkb->names->groups[group]; gboolean cache_hit = FALSE; DirectionCacheEntry *cache = keymap_x11->group_direction_cache; PangoDirection direction = PANGO_DIRECTION_NEUTRAL; int i; if (keymap_x11->has_direction) { /* look up in the cache */ for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++) { if (cache[i].group_atom == group_atom) { cache_hit = TRUE; cache[i].serial = keymap_x11->current_cache_serial++; direction = cache[i].direction; group_atom = cache[i].group_atom; break; } } } else { /* initialize the cache */ for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++) { cache[i].group_atom = 0; cache[i].direction = PANGO_DIRECTION_NEUTRAL; cache[i].serial = keymap_x11->current_cache_serial; } keymap_x11->current_cache_serial += 1; } /* insert the new entry in the cache */ if (!cache_hit) { int oldest = 0; direction = get_direction (xkb, group); /* replace the oldest entry */ for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++) { if (cache[i].serial < cache[oldest].serial) oldest = i; } cache[oldest].group_atom = group_atom; cache[oldest].direction = direction; cache[oldest].serial = keymap_x11->current_cache_serial++; } return direction; } #endif /* HAVE_XKB */ static void update_direction (ClutterKeymapX11 *keymap_x11, int group) { #ifdef HAVE_XKB XkbDescPtr xkb = get_xkb (keymap_x11); Atom group_atom; group_atom = xkb->names->groups[group]; if (!keymap_x11->has_direction || keymap_x11->current_group_atom != group_atom) { keymap_x11->current_direction = get_direction_from_cache (keymap_x11, xkb, group); keymap_x11->current_group_atom = group_atom; keymap_x11->has_direction = TRUE; } #endif /* HAVE_XKB */ } static void clutter_keymap_x11_constructed (GObject *gobject) { ClutterKeymapX11 *keymap_x11 = CLUTTER_KEYMAP_X11 (gobject); ClutterBackendX11 *backend_x11; g_assert (keymap_x11->backend != NULL); backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend); #ifdef HAVE_XKB { gint xkb_major = XkbMajorVersion; gint xkb_minor = XkbMinorVersion; if (XkbLibraryVersion (&xkb_major, &xkb_minor)) { xkb_major = XkbMajorVersion; xkb_minor = XkbMinorVersion; if (XkbQueryExtension (backend_x11->xdpy, NULL, &keymap_x11->xkb_event_base, NULL, &xkb_major, &xkb_minor)) { Bool detectable_autorepeat_supported; backend_x11->use_xkb = TRUE; XkbSelectEvents (backend_x11->xdpy, XkbUseCoreKbd, XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask, XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask); XkbSelectEventDetails (backend_x11->xdpy, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupLockMask | XkbModifierLockMask); /* enable XKB autorepeat */ XkbSetDetectableAutoRepeat (backend_x11->xdpy, True, &detectable_autorepeat_supported); backend_x11->have_xkb_autorepeat = detectable_autorepeat_supported; CLUTTER_NOTE (BACKEND, "Detectable autorepeat: %s", backend_x11->have_xkb_autorepeat ? "supported" : "not supported"); } } } #endif /* HAVE_XKB */ } static void clutter_keymap_x11_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterKeymapX11 *keymap = CLUTTER_KEYMAP_X11 (gobject); switch (prop_id) { case PROP_BACKEND: keymap->backend = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_keymap_x11_finalize (GObject *gobject) { ClutterKeymapX11 *keymap; ClutterEventTranslator *translator; keymap = CLUTTER_KEYMAP_X11 (gobject); translator = CLUTTER_EVENT_TRANSLATOR (keymap); #ifdef HAVE_XKB _clutter_backend_remove_event_translator (keymap->backend, translator); if (keymap->xkb_desc != NULL) XkbFreeKeyboard (keymap->xkb_desc, XkbAllComponentsMask, True); #endif G_OBJECT_CLASS (clutter_keymap_x11_parent_class)->finalize (gobject); } static void clutter_keymap_x11_class_init (ClutterKeymapX11Class *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); obj_props[PROP_BACKEND] = g_param_spec_object ("backend", P_("Backend"), P_("The Clutter backend"), CLUTTER_TYPE_BACKEND, CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); gobject_class->constructed = clutter_keymap_x11_constructed; gobject_class->set_property = clutter_keymap_x11_set_property; gobject_class->finalize = clutter_keymap_x11_finalize; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_keymap_x11_init (ClutterKeymapX11 *keymap) { keymap->current_direction = PANGO_DIRECTION_NEUTRAL; } static ClutterTranslateReturn clutter_keymap_x11_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *event) { ClutterKeymapX11 *keymap_x11 = CLUTTER_KEYMAP_X11 (translator); ClutterBackendX11 *backend_x11; ClutterTranslateReturn retval; XEvent *xevent; backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend); if (!backend_x11->use_xkb) return CLUTTER_TRANSLATE_CONTINUE; xevent = native; retval = CLUTTER_TRANSLATE_CONTINUE; #ifdef HAVE_XKB if (xevent->type == keymap_x11->xkb_event_base) { XkbEvent *xkb_event = (XkbEvent *) xevent; switch (xkb_event->any.xkb_type) { case XkbStateNotify: CLUTTER_NOTE (EVENT, "Updating keyboard state"); update_direction (keymap_x11, XkbStateGroup (&xkb_event->state)); update_locked_mods (keymap_x11, xkb_event->state.locked_mods); retval = CLUTTER_TRANSLATE_REMOVE; break; case XkbNewKeyboardNotify: case XkbMapNotify: CLUTTER_NOTE (EVENT, "Updating keyboard mapping"); XkbRefreshKeyboardMapping (&xkb_event->map); backend_x11->keymap_serial += 1; retval = CLUTTER_TRANSLATE_REMOVE; break; default: break; } } #endif /* HAVE_XKB */ return retval; } static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface) { iface->translate_event = clutter_keymap_x11_translate_event; } gint _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap, ClutterModifierType state) { #ifdef HAVE_XKB return XkbGroupForCoreState (state); #else return 0; #endif /* HAVE_XKB */ } gboolean _clutter_keymap_x11_get_num_lock_state (ClutterKeymapX11 *keymap) { g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), FALSE); return keymap->num_lock_state; } gboolean _clutter_keymap_x11_get_caps_lock_state (ClutterKeymapX11 *keymap) { g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), FALSE); return keymap->caps_lock_state; } G_GNUC_BEGIN_IGNORE_DEPRECATIONS /* XXX - yes, I know that XKeycodeToKeysym() has been deprecated; hopefully, * this code will never get run on any decent system that is also able to * run Clutter. I just don't want to copy the implementation inside GDK for * a fallback path. */ static int translate_keysym (ClutterKeymapX11 *keymap, guint hardware_keycode) { ClutterBackendX11 *backend_x11; gint retval; backend_x11 = CLUTTER_BACKEND_X11 (keymap->backend); retval = XKeycodeToKeysym (backend_x11->xdpy, hardware_keycode, 0); return retval; } G_GNUC_END_IGNORE_DEPRECATIONS gint _clutter_keymap_x11_translate_key_state (ClutterKeymapX11 *keymap, guint hardware_keycode, ClutterModifierType *modifier_state_p, ClutterModifierType *mods_p) { ClutterBackendX11 *backend_x11; ClutterModifierType unconsumed_modifiers = 0; ClutterModifierType modifier_state = *modifier_state_p; gint retval; g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), 0); backend_x11 = CLUTTER_BACKEND_X11 (keymap->backend); #ifdef HAVE_XKB if (backend_x11->use_xkb) { XkbDescRec *xkb = get_xkb (keymap); KeySym tmp_keysym; if (XkbTranslateKeyCode (xkb, hardware_keycode, modifier_state, &unconsumed_modifiers, &tmp_keysym)) { retval = tmp_keysym; } else retval = 0; } else #endif /* HAVE_XKB */ retval = translate_keysym (keymap, hardware_keycode); if (mods_p) *mods_p = unconsumed_modifiers; *modifier_state_p = modifier_state & ~(keymap->num_lock_mask | keymap->scroll_lock_mask | LockMask); return retval; } gboolean _clutter_keymap_x11_get_is_modifier (ClutterKeymapX11 *keymap, gint keycode) { g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), FALSE); if (keycode < keymap->min_keycode || keycode > keymap->max_keycode) return FALSE; #ifdef HAVE_XKB if (CLUTTER_BACKEND_X11 (keymap->backend)->use_xkb) { XkbDescRec *xkb = get_xkb (keymap); if (xkb->map->modmap && xkb->map->modmap[keycode] != 0) return TRUE; } #endif /* HAVE_XKB */ return FALSE; } PangoDirection _clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap) { g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), PANGO_DIRECTION_NEUTRAL); #ifdef HAVE_XKB if (CLUTTER_BACKEND_X11 (keymap->backend)->use_xkb) { if (!keymap->has_direction) { Display *xdisplay = CLUTTER_BACKEND_X11 (keymap->backend)->xdpy; XkbStateRec state_rec; XkbGetState (xdisplay, XkbUseCoreKbd, &state_rec); update_direction (keymap, XkbStateGroup (&state_rec)); } return keymap->current_direction; } else #endif return PANGO_DIRECTION_NEUTRAL; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-input-device-tool-xi2.c������������������������������������0000664�0001750�0001750�00000003045�14211404421�024606� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2016 Red Hat * * 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, see <http://www.gnu.org/licenses/>. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-input-device-tool-xi2.h" G_DEFINE_TYPE (ClutterInputDeviceToolXI2, clutter_input_device_tool_xi2, CLUTTER_TYPE_INPUT_DEVICE_TOOL) static void clutter_input_device_tool_xi2_class_init (ClutterInputDeviceToolXI2Class *klass) { } static void clutter_input_device_tool_xi2_init (ClutterInputDeviceToolXI2 *tool) { } ClutterInputDeviceTool * clutter_input_device_tool_xi2_new (guint serial, ClutterInputDeviceToolType type) { return g_object_new (CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2, "type", type, "serial", serial, NULL); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-device-manager-core-x11.c����������������������������������0000664�0001750�0001750�00000045446�14211404421�024756� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #include "clutter-build-config.h" #include "clutter-device-manager-core-x11.h" #include "clutter-backend-x11.h" #include "clutter-input-device-core-x11.h" #include "clutter-stage-x11.h" #include "clutter-virtual-input-device-x11.h" #include "clutter-backend.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-event-private.h" #include "clutter-event-translator.h" #include "clutter-stage-private.h" #include "clutter-private.h" #include "clutter-xkb-a11y-x11.h" enum { PROP_0, PROP_EVENT_BASE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface); #define clutter_device_manager_x11_get_type _clutter_device_manager_x11_get_type G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerX11, clutter_device_manager_x11, CLUTTER_TYPE_DEVICE_MANAGER, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR, clutter_event_translator_iface_init)); static inline void translate_key_event (ClutterBackendX11 *backend_x11, ClutterDeviceManagerX11 *manager_x11, ClutterEvent *event, XEvent *xevent) { ClutterEventX11 *event_x11; char buffer[256 + 1]; int n; event->key.type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE; event->key.time = xevent->xkey.time; clutter_event_set_device (event, manager_x11->core_keyboard); /* KeyEvents have platform specific data associated to them */ event_x11 = _clutter_event_x11_new (); _clutter_event_set_platform_data (event, event_x11); event->key.modifier_state = (ClutterModifierType) xevent->xkey.state; event->key.hardware_keycode = xevent->xkey.keycode; /* keyval is the key ignoring all modifiers ('1' vs. '!') */ event->key.keyval = _clutter_keymap_x11_translate_key_state (backend_x11->keymap, event->key.hardware_keycode, &event->key.modifier_state, NULL); event_x11->key_group = _clutter_keymap_x11_get_key_group (backend_x11->keymap, event->key.modifier_state); event_x11->key_is_modifier = _clutter_keymap_x11_get_is_modifier (backend_x11->keymap, event->key.hardware_keycode); event_x11->num_lock_set = _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap); event_x11->caps_lock_set = _clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap); /* unicode_value is the printable representation */ n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL); if (n != NoSymbol) { event->key.unicode_value = g_utf8_get_char_validated (buffer, n); if ((event->key.unicode_value != (gunichar) -1) && (event->key.unicode_value != (gunichar) -2)) goto out; } else event->key.unicode_value = (gunichar)'\0'; out: CLUTTER_NOTE (EVENT, "%s: win:0x%x, key: %12s (%d)", event->any.type == CLUTTER_KEY_PRESS ? "key press " : "key release", (unsigned int) xevent->xkey.window, event->key.keyval ? buffer : "(none)", event->key.keyval); return; } static ClutterTranslateReturn clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *event) { ClutterDeviceManagerX11 *manager_x11; ClutterBackendX11 *backend_x11; ClutterStageX11 *stage_x11; ClutterTranslateReturn res; ClutterStage *stage; XEvent *xevent; manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (translator); backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); xevent = native; stage = clutter_x11_get_stage_from_window (xevent->xany.window); if (stage == NULL) return CLUTTER_TRANSLATE_CONTINUE; if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return CLUTTER_TRANSLATE_CONTINUE; stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage)); event->any.stage = stage; res = CLUTTER_TRANSLATE_CONTINUE; switch (xevent->type) { case KeyPress: translate_key_event (backend_x11, manager_x11, event, xevent); _clutter_stage_x11_set_user_time (stage_x11, xevent->xkey.time); res = CLUTTER_TRANSLATE_QUEUE; break; case KeyRelease: /* old-style X11 terminals require that even modern X11 send * KeyPress/KeyRelease pairs when auto-repeating. for this * reason modern(-ish) API like XKB has a way to detect * auto-repeat and do a single KeyRelease at the end of a * KeyPress sequence. * * this check emulates XKB's detectable auto-repeat; we peek * the next event and check if it's a KeyPress for the same key * and timestamp - and then ignore it if it matches the * KeyRelease * * if we have XKB, and autorepeat is enabled, then this becomes * a no-op */ if (!backend_x11->have_xkb_autorepeat && XPending (xevent->xkey.display)) { XEvent next_event; XPeekEvent (xevent->xkey.display, &next_event); if (next_event.type == KeyPress && next_event.xkey.keycode == xevent->xkey.keycode && next_event.xkey.time == xevent->xkey.time) { res = CLUTTER_TRANSLATE_REMOVE; break; } } translate_key_event (backend_x11, manager_x11, event, xevent); res = CLUTTER_TRANSLATE_QUEUE; break; case ButtonPress: CLUTTER_NOTE (EVENT, "button press: win: 0x%x, coords: %d, %d, button: %d", (unsigned int) stage_x11->xwin, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button); switch (xevent->xbutton.button) { case 4: /* up */ case 5: /* down */ case 6: /* left */ case 7: /* right */ event->scroll.type = CLUTTER_SCROLL; if (xevent->xbutton.button == 4) event->scroll.direction = CLUTTER_SCROLL_UP; else if (xevent->xbutton.button == 5) event->scroll.direction = CLUTTER_SCROLL_DOWN; else if (xevent->xbutton.button == 6) event->scroll.direction = CLUTTER_SCROLL_LEFT; else event->scroll.direction = CLUTTER_SCROLL_RIGHT; event->scroll.time = xevent->xbutton.time; event->scroll.x = xevent->xbutton.x; event->scroll.y = xevent->xbutton.y; event->scroll.modifier_state = xevent->xbutton.state; event->scroll.axes = NULL; break; default: event->button.type = event->type = CLUTTER_BUTTON_PRESS; event->button.time = xevent->xbutton.time; event->button.x = xevent->xbutton.x; event->button.y = xevent->xbutton.y; event->button.modifier_state = xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.axes = NULL; break; } clutter_event_set_device (event, manager_x11->core_pointer); _clutter_stage_x11_set_user_time (stage_x11, xevent->xbutton.time); res = CLUTTER_TRANSLATE_QUEUE; break; case ButtonRelease: CLUTTER_NOTE (EVENT, "button press: win: 0x%x, coords: %d, %d, button: %d", (unsigned int) stage_x11->xwin, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button); /* scroll events don't have a corresponding release */ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 || xevent->xbutton.button == 6 || xevent->xbutton.button == 7) { res = CLUTTER_TRANSLATE_REMOVE; break; } event->button.type = event->type = CLUTTER_BUTTON_RELEASE; event->button.time = xevent->xbutton.time; event->button.x = xevent->xbutton.x; event->button.y = xevent->xbutton.y; event->button.modifier_state = xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.axes = NULL; clutter_event_set_device (event, manager_x11->core_pointer); res = CLUTTER_TRANSLATE_QUEUE; break; case MotionNotify: CLUTTER_NOTE (EVENT, "motion: win: 0x%x, coords: %d, %d", (unsigned int) stage_x11->xwin, xevent->xmotion.x, xevent->xmotion.y); event->motion.type = event->type = CLUTTER_MOTION; event->motion.time = xevent->xmotion.time; event->motion.x = xevent->xmotion.x; event->motion.y = xevent->xmotion.y; event->motion.modifier_state = xevent->xmotion.state; event->motion.axes = NULL; clutter_event_set_device (event, manager_x11->core_pointer); res = CLUTTER_TRANSLATE_QUEUE; break; case EnterNotify: CLUTTER_NOTE (EVENT, "Entering the stage (time:%u)", (unsigned int) xevent->xcrossing.time); event->crossing.type = CLUTTER_ENTER; event->crossing.time = xevent->xcrossing.time; event->crossing.x = xevent->xcrossing.x; event->crossing.y = xevent->xcrossing.y; event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.related = NULL; clutter_event_set_device (event, manager_x11->core_pointer); _clutter_input_device_set_stage (manager_x11->core_pointer, stage); res = CLUTTER_TRANSLATE_QUEUE; break; case LeaveNotify: if (manager_x11->core_pointer->stage == NULL) { CLUTTER_NOTE (EVENT, "Discarding LeaveNotify for " "ButtonRelease event off-stage"); res = CLUTTER_TRANSLATE_REMOVE; break; } /* we know that we are leaving the stage here */ CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)", (unsigned int) xevent->xcrossing.time); event->crossing.type = CLUTTER_LEAVE; event->crossing.time = xevent->xcrossing.time; event->crossing.x = xevent->xcrossing.x; event->crossing.y = xevent->xcrossing.y; event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.related = NULL; clutter_event_set_device (event, manager_x11->core_pointer); _clutter_input_device_set_stage (manager_x11->core_pointer, NULL); res = CLUTTER_TRANSLATE_QUEUE; break; default: break; } return res; } static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface) { iface->translate_event = clutter_device_manager_x11_translate_event; } static void clutter_device_manager_x11_constructed (GObject *gobject) { ClutterDeviceManagerX11 *manager_x11; ClutterDeviceManager *manager; ClutterBackendX11 *backend_x11; manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject); manager = CLUTTER_DEVICE_MANAGER (gobject); g_object_get (gobject, "backend", &backend_x11, NULL); g_assert (backend_x11 != NULL); manager_x11->core_pointer = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11, "name", "Core Pointer", "has-cursor", TRUE, "device-type", CLUTTER_POINTER_DEVICE, "device-manager", manager_x11, "device-mode", CLUTTER_INPUT_MODE_MASTER, "backend", backend_x11, "enabled", TRUE, NULL); CLUTTER_NOTE (BACKEND, "Added core pointer device"); manager_x11->core_keyboard = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11, "name", "Core Keyboard", "has-cursor", FALSE, "device-type", CLUTTER_KEYBOARD_DEVICE, "device-manager", manager_x11, "device-mode", CLUTTER_INPUT_MODE_MASTER, "backend", backend_x11, "enabled", TRUE, NULL); CLUTTER_NOTE (BACKEND, "Added core keyboard device"); /* associate core devices */ _clutter_input_device_set_associated_device (manager_x11->core_pointer, manager_x11->core_keyboard); _clutter_input_device_set_associated_device (manager_x11->core_keyboard, manager_x11->core_pointer); clutter_device_manager_x11_a11y_init (manager); if (G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed) G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed (gobject); } static void clutter_device_manager_x11_add_device (ClutterDeviceManager *manager, ClutterInputDevice *device) { ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager); manager_x11->devices = g_slist_prepend (manager_x11->devices, device); g_hash_table_replace (manager_x11->devices_by_id, GINT_TO_POINTER (device->id), device); /* blow the cache */ g_slist_free (manager_x11->all_devices); manager_x11->all_devices = NULL; } static void clutter_device_manager_x11_remove_device (ClutterDeviceManager *manager, ClutterInputDevice *device) { ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager); g_hash_table_remove (manager_x11->devices_by_id, GINT_TO_POINTER (device->id)); manager_x11->devices = g_slist_remove (manager_x11->devices, device); /* blow the cache */ g_slist_free (manager_x11->all_devices); manager_x11->all_devices = NULL; } static const GSList * clutter_device_manager_x11_get_devices (ClutterDeviceManager *manager) { ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager); /* cache the devices list so that we can keep the core pointer * and keyboard outside of the ManagerX11:devices list */ if (manager_x11->all_devices == NULL) { GSList *all_devices = manager_x11->devices; all_devices = g_slist_prepend (all_devices, manager_x11->core_keyboard); all_devices = g_slist_prepend (all_devices, manager_x11->core_pointer); manager_x11->all_devices = all_devices; } return CLUTTER_DEVICE_MANAGER_X11 (manager)->all_devices; } static ClutterInputDevice * clutter_device_manager_x11_get_core_device (ClutterDeviceManager *manager, ClutterInputDeviceType type) { ClutterDeviceManagerX11 *manager_x11; manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager); switch (type) { case CLUTTER_POINTER_DEVICE: return manager_x11->core_pointer; case CLUTTER_KEYBOARD_DEVICE: return manager_x11->core_keyboard; default: return NULL; } return NULL; } static ClutterInputDevice * clutter_device_manager_x11_get_device (ClutterDeviceManager *manager, gint id) { ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager); return g_hash_table_lookup (manager_x11->devices_by_id, GINT_TO_POINTER (id)); } static ClutterVirtualInputDevice * clutter_device_manager_x11_create_virtual_device (ClutterDeviceManager *device_manager, ClutterInputDeviceType device_type) { return g_object_new (CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_X11, NULL); } static ClutterVirtualDeviceType clutter_device_manager_x11_get_supported_virtual_device_types (ClutterDeviceManager *device_manager) { return (CLUTTER_VIRTUAL_DEVICE_TYPE_KEYBOARD | CLUTTER_VIRTUAL_DEVICE_TYPE_POINTER); } static void clutter_device_manager_x11_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject); switch (prop_id) { case PROP_EVENT_BASE: manager_x11->xi_event_base = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_device_manager_x11_class_init (ClutterDeviceManagerX11Class *klass) { ClutterDeviceManagerClass *manager_class; GObjectClass *gobject_class; obj_props[PROP_EVENT_BASE] = g_param_spec_int ("event-base", "Event Base", "The first XI event", -1, G_MAXINT, -1, CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructed = clutter_device_manager_x11_constructed; gobject_class->set_property = clutter_device_manager_x11_set_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass); manager_class->add_device = clutter_device_manager_x11_add_device; manager_class->remove_device = clutter_device_manager_x11_remove_device; manager_class->get_devices = clutter_device_manager_x11_get_devices; manager_class->get_core_device = clutter_device_manager_x11_get_core_device; manager_class->get_device = clutter_device_manager_x11_get_device; manager_class->create_virtual_device = clutter_device_manager_x11_create_virtual_device; manager_class->get_supported_virtual_device_types = clutter_device_manager_x11_get_supported_virtual_device_types; manager_class->apply_kbd_a11y_settings = clutter_device_manager_x11_apply_kbd_a11y_settings; } static void clutter_device_manager_x11_init (ClutterDeviceManagerX11 *self) { self->devices_by_id = g_hash_table_new (NULL, NULL); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-virtual-input-device-x11.c���������������������������������0000664�0001750�0001750�00000017747�14211404421�025244� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <glib-object.h> #include "clutter-x11.h" #include "X11/extensions/XTest.h" #include "clutter-virtual-input-device.h" #include "x11/clutter-virtual-input-device-x11.h" struct _ClutterVirtualInputDeviceX11 { ClutterVirtualInputDevice parent; }; G_DEFINE_TYPE (ClutterVirtualInputDeviceX11, clutter_virtual_input_device_x11, CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE) static void clutter_virtual_input_device_x11_notify_relative_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy) { XTestFakeRelativeMotionEvent (clutter_x11_get_default_display (), (int) dx, (int) dy, 0); } static void clutter_virtual_input_device_x11_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double x, double y) { XTestFakeMotionEvent (clutter_x11_get_default_display (), clutter_x11_get_default_screen (), (int) x, (int) y, 0); } static void clutter_virtual_input_device_x11_notify_button (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t button, ClutterButtonState button_state) { XTestFakeButtonEvent (clutter_x11_get_default_display (), button, button_state == CLUTTER_BUTTON_STATE_PRESSED, 0); } static void clutter_virtual_input_device_x11_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, ClutterScrollDirection direction, ClutterScrollSource scroll_source) { Display *xdisplay = clutter_x11_get_default_display (); int button; switch (direction) { case CLUTTER_SCROLL_UP: button = 4; break; case CLUTTER_SCROLL_DOWN: button = 5; break; case CLUTTER_SCROLL_LEFT: button = 6; break; case CLUTTER_SCROLL_RIGHT: button = 7; break; default: g_warn_if_reached (); return; } XTestFakeButtonEvent (xdisplay, button, True, 0); XTestFakeButtonEvent (xdisplay, button, False, 0); } static void clutter_virtual_input_device_x11_notify_scroll_continuous (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy, ClutterScrollSource scroll_source, ClutterScrollFinishFlags finish_flags) { } static void clutter_virtual_input_device_x11_notify_key (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t key, ClutterKeyState key_state) { XTestFakeKeyEvent (clutter_x11_get_default_display (), key, key_state == CLUTTER_KEY_STATE_PRESSED, 0); } static void clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t keyval, ClutterKeyState key_state) { KeyCode keycode; keycode = XKeysymToKeycode (clutter_x11_get_default_display (), keyval); XTestFakeKeyEvent (clutter_x11_get_default_display (), keycode, key_state == CLUTTER_KEY_STATE_PRESSED, 0); } static void clutter_virtual_input_device_x11_notify_touch_down (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int device_slot, double x, double y) { g_warning ("Virtual touch motion not implemented under X11"); } static void clutter_virtual_input_device_x11_notify_touch_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int device_slot, double x, double y) { g_warning ("Virtual touch motion not implemented under X11"); } static void clutter_virtual_input_device_x11_notify_touch_up (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int device_slot) { g_warning ("Virtual touch motion not implemented under X11"); } static void clutter_virtual_input_device_x11_init (ClutterVirtualInputDeviceX11 *virtual_device_x11) { } static void clutter_virtual_input_device_x11_class_init (ClutterVirtualInputDeviceX11Class *klass) { ClutterVirtualInputDeviceClass *virtual_input_device_class = CLUTTER_VIRTUAL_INPUT_DEVICE_CLASS (klass); virtual_input_device_class->notify_relative_motion = clutter_virtual_input_device_x11_notify_relative_motion; virtual_input_device_class->notify_absolute_motion = clutter_virtual_input_device_x11_notify_absolute_motion; virtual_input_device_class->notify_button = clutter_virtual_input_device_x11_notify_button; virtual_input_device_class->notify_discrete_scroll = clutter_virtual_input_device_x11_notify_discrete_scroll; virtual_input_device_class->notify_scroll_continuous = clutter_virtual_input_device_x11_notify_scroll_continuous; virtual_input_device_class->notify_key = clutter_virtual_input_device_x11_notify_key; virtual_input_device_class->notify_keyval = clutter_virtual_input_device_x11_notify_keyval; virtual_input_device_class->notify_touch_down = clutter_virtual_input_device_x11_notify_touch_down; virtual_input_device_class->notify_touch_motion = clutter_virtual_input_device_x11_notify_touch_motion; virtual_input_device_class->notify_touch_up = clutter_virtual_input_device_x11_notify_touch_up; } �������������������������muffin-5.2.1/clutter/clutter/x11/clutter-input-device-tool-xi2.h������������������������������������0000664�0001750�0001750�00000004674�14211404421�024624� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2016 Red Hat * * 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, see <http://www.gnu.org/licenses/>. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifndef __CLUTTER_INPUT_DEVICE_XI2_TOOL_H__ #define __CLUTTER_INPUT_DEVICE_XI2_TOOL_H__ #include <clutter/clutter-input-device-tool.h> G_BEGIN_DECLS #define CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2 (clutter_input_device_tool_xi2_get_type ()) #define CLUTTER_INPUT_DEVICE_TOOL_XI2(o) \ (G_TYPE_CHECK_INSTANCE_CAST ((o), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2, ClutterInputDeviceToolXI2)) #define CLUTTER_IS_INPUT_DEVICE_TOOL_XI2(o) \ (G_TYPE_CHECK_INSTANCE_TYPE ((o), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2)) #define CLUTTER_INPUT_DEVICE_TOOL_XI2_CLASS(c) \ (G_TYPE_CHECK_CLASS_CAST ((c), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2, ClutterInputDeviceToolXI2Class)) #define CLUTTER_IS_INPUT_DEVICE_TOOL_XI2_CLASS(c) \ (G_TYPE_CHECK_CLASS_TYPE ((c), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2)) #define CLUTTER_INPUT_DEVICE_TOOL_XI2_GET_CLASS(o) \ (G_TYPE_INSTANCE_GET_CLASS ((o), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2, ClutterInputDeviceToolXI2Class)) typedef struct _ClutterInputDeviceToolXI2 ClutterInputDeviceToolXI2; typedef struct _ClutterInputDeviceToolXI2Class ClutterInputDeviceToolXI2Class; struct _ClutterInputDeviceToolXI2 { ClutterInputDeviceTool parent_instance; struct libinput_tablet_tool *tool; }; struct _ClutterInputDeviceToolXI2Class { ClutterInputDeviceToolClass parent_class; }; GType clutter_input_device_tool_xi2_get_type (void) G_GNUC_CONST; ClutterInputDeviceTool * clutter_input_device_tool_xi2_new (guint serial, ClutterInputDeviceToolType type); G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_XI2_TOOL_H__ */ ��������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-stage-x11.h������������������������������������������������0000664�0001750�0001750�00000006307�14211404421�022262� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * Authored By Matthew Allum <mallum@openedhand.com> * Copyright (C) 2006-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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_STAGE_X11_H__ #define __CLUTTER_STAGE_X11_H__ #include <clutter/clutter-group.h> #include <clutter/clutter-stage.h> #include <X11/Xlib.h> #include <X11/Xatom.h> #include "clutter-backend-x11.h" #include "cogl/clutter-stage-cogl.h" G_BEGIN_DECLS #define CLUTTER_TYPE_STAGE_X11 (_clutter_stage_x11_get_type ()) #define CLUTTER_STAGE_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_X11, ClutterStageX11)) #define CLUTTER_IS_STAGE_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_X11)) #define CLUTTER_STAGE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_X11, ClutterStageX11Class)) #define CLUTTER_IS_STAGE_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_X11)) #define CLUTTER_STAGE_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_X11, ClutterStageX11Class)) typedef struct _ClutterStageX11 ClutterStageX11; typedef struct _ClutterStageX11Class ClutterStageX11Class; G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterStageX11, g_object_unref) typedef enum { STAGE_X11_WITHDRAWN = 1 << 1 } ClutterStageX11State; struct _ClutterStageX11 { ClutterStageCogl parent_instance; CoglOnscreen *onscreen; Window xwin; gint xwin_width; gint xwin_height; /* FIXME target_width / height */ ClutterStageView *legacy_view; GList *legacy_views; CoglFrameClosure *frame_closure; gchar *title; guint clipped_redraws_cool_off; ClutterStageX11State wm_state; guint is_foreign_xwin : 1; guint fullscreening : 1; guint is_cursor_visible : 1; guint viewport_initialized : 1; guint accept_focus : 1; guint fullscreen_on_realize : 1; }; struct _ClutterStageX11Class { ClutterStageCoglClass parent_class; }; CLUTTER_AVAILABLE_IN_MUFFIN GType _clutter_stage_x11_get_type (void) G_GNUC_CONST; void _clutter_stage_x11_events_device_changed (ClutterStageX11 *stage_x11, ClutterInputDevice *device, ClutterDeviceManager *device_manager); /* Private to subclasses */ void _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11, guint32 user_time); G_END_DECLS #endif /* __CLUTTER_STAGE_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-backend-x11.h����������������������������������������������0000664�0001750�0001750�00000011213�14211404421�022536� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * Authored By Matthew Allum <mallum@openedhand.com> * Copyright (C) 2006-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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_BACKEND_X11_H__ #define __CLUTTER_BACKEND_X11_H__ #include <glib-object.h> #include <clutter/clutter-event.h> #include <X11/Xlib.h> #include <X11/Xatom.h> #include "clutter-x11.h" #include "clutter-backend-private.h" #include "clutter-keymap-x11.h" #include "xsettings/xsettings-client.h" G_BEGIN_DECLS #define CLUTTER_TYPE_BACKEND_X11 (clutter_backend_x11_get_type ()) #define CLUTTER_BACKEND_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11)) #define CLUTTER_IS_BACKEND_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_X11)) #define CLUTTER_BACKEND_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11Class)) #define CLUTTER_IS_BACKEND_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_X11)) #define CLUTTER_BACKEND_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11Class)) typedef struct _ClutterBackendX11 ClutterBackendX11; typedef struct _ClutterBackendX11Class ClutterBackendX11Class; typedef struct _ClutterEventX11 ClutterEventX11; typedef struct _ClutterX11EventFilter ClutterX11EventFilter; G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBackendX11, g_object_unref) struct _ClutterX11EventFilter { ClutterX11FilterFunc func; gpointer data; }; struct _ClutterEventX11 { /* additional fields for Key events */ gint key_group; guint key_is_modifier : 1; guint num_lock_set : 1; guint caps_lock_set : 1; }; struct _ClutterBackendX11 { ClutterBackend parent_instance; Display *xdpy; gchar *display_name; Screen *xscreen; int xscreen_num; int xscreen_width; int xscreen_height; Window xwin_root; /* event source */ GSource *event_source; GSList *event_filters; /* props */ Atom atom_NET_WM_PID; Atom atom_NET_WM_PING; Atom atom_NET_WM_STATE; Atom atom_NET_WM_STATE_FULLSCREEN; Atom atom_NET_WM_USER_TIME; Atom atom_WM_PROTOCOLS; Atom atom_WM_DELETE_WINDOW; Atom atom_XEMBED; Atom atom_XEMBED_INFO; Atom atom_NET_WM_NAME; Atom atom_UTF8_STRING; Time last_event_time; ClutterDeviceManager *device_manager; gboolean has_xinput; int xi_minor; XSettingsClient *xsettings; Window xsettings_xwin; ClutterKeymapX11 *keymap; gboolean use_xkb; gboolean have_xkb_autorepeat; guint keymap_serial; }; struct _ClutterBackendX11Class { ClutterBackendClass parent_class; }; CLUTTER_AVAILABLE_IN_MUFFIN GType clutter_backend_x11_get_type (void) G_GNUC_CONST; ClutterBackend *clutter_backend_x11_new (void); void _clutter_backend_x11_events_init (ClutterBackend *backend); GSource * _clutter_x11_event_source_new (ClutterBackendX11 *backend_x11); /* Private to glx/eglx backends */ XVisualInfo * _clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11); void _clutter_x11_select_events (Window xwin); ClutterEventX11 * _clutter_event_x11_new (void); ClutterEventX11 * _clutter_event_x11_copy (ClutterEventX11 *event_x11); void _clutter_event_x11_free (ClutterEventX11 *event_x11); gboolean _clutter_x11_input_device_translate_screen_coord (ClutterInputDevice *device, gint stage_root_x, gint stage_root_y, guint index_, gdouble value, gdouble *axis_value); G_END_DECLS #endif /* __CLUTTER_BACKEND_X11_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-glx-texture-pixmap.c���������������������������������������0000664�0001750�0001750�00000011333�14211404421�024322� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Johan Bilien <johan.bilien@nokia.com> * Matthew Allum <mallum@o-hand.com> * Robert Bragg <bob@o-hand.com> * Neil Roberts <neil@linux.intel.com> * * Copyright (C) 2007 OpenedHand * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * */ /** * SECTION:clutter-glx-texture-pixmap * @Title: ClutterGLXTexturePixmap * @short_description: A texture which displays the content of an X Pixmap * @Deprecated: 1.4: Use #ClutterX11TexturePixmap instead. * * #ClutterGLXTexturePixmap is a class for displaying the content of an * X Pixmap as a ClutterActor. Used together with the X Composite extension, * it allows to display the content of X Windows inside Clutter. * * This class used to be necessary to use the * GLX_EXT_texture_from_pixmap extension to get fast texture * updates. However since Clutter 1.4 the handling of this extension * has moved down to Cogl. ClutterX11TexturePixmap and * ClutterGLXTexturePixmap are now equivalent and either one of them * may use the extension if it is possible. */ #include "clutter-build-config.h" #include <string.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "x11/clutter-x11-texture-pixmap.h" #include <cogl/cogl-texture-pixmap-x11.h> #include "clutter-glx-texture-pixmap.h" G_DEFINE_TYPE (ClutterGLXTexturePixmap, \ clutter_glx_texture_pixmap, \ CLUTTER_X11_TYPE_TEXTURE_PIXMAP); static void clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self) { } static void clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass) { } /** * clutter_glx_texture_pixmap_using_extension: * @texture: A #ClutterGLXTexturePixmap * * Checks whether @texture is using the GLX_EXT_texture_from_pixmap * extension; this extension can be optionally (though it is strongly * encouraged) implemented as a zero-copy between a GLX pixmap and * a GL texture. * * Return value: %TRUE if the texture is using the * GLX_EXT_texture_from_pixmap OpenGL extension or falling back to the * slower software mechanism. * * Deprecated: 1.6: Use cogl_texture_pixmap_x11_is_using_tfp_extension() * on the texture handle instead. * * Since: 0.8 */ gboolean clutter_glx_texture_pixmap_using_extension (ClutterGLXTexturePixmap *texture) { CoglHandle cogl_texture; g_return_val_if_fail (CLUTTER_GLX_IS_TEXTURE_PIXMAP (texture), FALSE); cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture)); return (cogl_is_texture_pixmap_x11 (cogl_texture) && cogl_texture_pixmap_x11_is_using_tfp_extension (cogl_texture)); } /** * clutter_glx_texture_pixmap_new_with_pixmap: * @pixmap: the X Pixmap to which this texture should be bound * * Creates a new #ClutterGLXTexturePixmap for @pixmap * * Return value: A new #ClutterGLXTexturePixmap bound to the given X Pixmap * * Since: 0.8 * * Deprecated: 1.6: Use clutter_x11_texture_pixmap_new_with_pixmap() instead */ ClutterActor * clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap) { return g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, "pixmap", pixmap, NULL); } /** * clutter_glx_texture_pixmap_new_with_window: * @window: the X window to which this texture should be bound * * Creates a new #ClutterGLXTexturePixmap for @window * * Return value: A new #ClutterGLXTexturePixmap bound to the given X window * * Since: 0.8 * * Deprecated: 1.6: Use clutter_x11_texture_pixmap_new_with_window() instead */ ClutterActor * clutter_glx_texture_pixmap_new_with_window (Window window) { return g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, "window", window, NULL); } /** * clutter_glx_texture_pixmap_new: * * Creates a new, empty #ClutterGLXTexturePixmap * * Return value: A new #ClutterGLXTexturePixmap * * Since: 0.8 * * Deprecated: 1.6: Use clutter_x11_texture_pixmap_new() instead */ ClutterActor * clutter_glx_texture_pixmap_new (void) { return g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, NULL); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-input-device-xi2.c�����������������������������������������0000664�0001750�0001750�00000024613�14211404421�023637� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #include "clutter-build-config.h" #include "clutter-input-device-xi2.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-event-private.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-backend-x11.h" #include "clutter-stage-x11.h" #include <X11/extensions/XInput2.h> typedef struct _ClutterInputDeviceClass ClutterInputDeviceXI2Class; /* a specific XI2 input device */ struct _ClutterInputDeviceXI2 { ClutterInputDevice device; gint device_id; ClutterInputDeviceTool *current_tool; #ifdef HAVE_LIBWACOM WacomDevice *wacom_device; GArray *group_modes; #endif }; #define N_BUTTONS 5 #define clutter_input_device_xi2_get_type _clutter_input_device_xi2_get_type G_DEFINE_TYPE (ClutterInputDeviceXI2, clutter_input_device_xi2, CLUTTER_TYPE_INPUT_DEVICE); static void clutter_input_device_xi2_constructed (GObject *gobject) { ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (gobject); g_object_get (gobject, "id", &device_xi2->device_id, NULL); if (G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed) G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed (gobject); #ifdef HAVE_LIBWACOM if (clutter_input_device_get_device_type (CLUTTER_INPUT_DEVICE (gobject)) == CLUTTER_PAD_DEVICE) { device_xi2->group_modes = g_array_new (FALSE, TRUE, sizeof (guint)); g_array_set_size (device_xi2->group_modes, clutter_input_device_get_n_mode_groups (CLUTTER_INPUT_DEVICE (gobject))); } #endif } static gboolean clutter_input_device_xi2_keycode_to_evdev (ClutterInputDevice *device, guint hardware_keycode, guint *evdev_keycode) { /* When using evdev under X11 the hardware keycodes are the evdev keycodes plus 8. I haven't been able to find any documentation to know what the +8 is for. FIXME: This should probably verify that X server is using evdev. */ *evdev_keycode = hardware_keycode - 8; return TRUE; } static gboolean clutter_input_device_xi2_is_grouped (ClutterInputDevice *device, ClutterInputDevice *other_device) { return FALSE; } static void clutter_input_device_xi2_finalize (GObject *object) { #ifdef HAVE_LIBWACOM ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (object); if (device_xi2->wacom_device) libwacom_destroy (device_xi2->wacom_device); if (device_xi2->group_modes) g_array_unref (device_xi2->group_modes); #endif G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->finalize (object); } static gint clutter_input_device_xi2_get_group_n_modes (ClutterInputDevice *device, gint group) { #ifdef HAVE_LIBWACOM ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device); if (device_xi2->wacom_device) { if (group == 0) { if (libwacom_has_ring (device_xi2->wacom_device)) return libwacom_get_ring_num_modes (device_xi2->wacom_device); else if (libwacom_get_num_strips (device_xi2->wacom_device) >= 1) return libwacom_get_strips_num_modes (device_xi2->wacom_device); } else if (group == 1) { if (libwacom_has_ring2 (device_xi2->wacom_device)) return libwacom_get_ring2_num_modes (device_xi2->wacom_device); else if (libwacom_get_num_strips (device_xi2->wacom_device) >= 2) return libwacom_get_strips_num_modes (device_xi2->wacom_device); } } #endif return -1; } #ifdef HAVE_LIBWACOM static int clutter_input_device_xi2_get_button_group (ClutterInputDevice *device, guint button) { ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device); if (device_xi2->wacom_device) { if (button >= libwacom_get_num_buttons (device_xi2->wacom_device)) return -1; return libwacom_get_button_led_group (device_xi2->wacom_device, 'A' + button); } else return -1; } #endif static gboolean clutter_input_device_xi2_is_mode_switch_button (ClutterInputDevice *device, guint group, guint button) { int button_group = -1; #ifdef HAVE_LIBWACOM button_group = clutter_input_device_xi2_get_button_group (device, button); #endif return button_group == (int) group; } static void clutter_input_device_xi2_class_init (ClutterInputDeviceXI2Class *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass); gobject_class->constructed = clutter_input_device_xi2_constructed; gobject_class->finalize = clutter_input_device_xi2_finalize; device_class->keycode_to_evdev = clutter_input_device_xi2_keycode_to_evdev; device_class->is_grouped = clutter_input_device_xi2_is_grouped; device_class->get_group_n_modes = clutter_input_device_xi2_get_group_n_modes; device_class->is_mode_switch_button = clutter_input_device_xi2_is_mode_switch_button; } static void clutter_input_device_xi2_init (ClutterInputDeviceXI2 *self) { } static ClutterModifierType get_modifier_for_button (int i) { switch (i) { case 1: return CLUTTER_BUTTON1_MASK; case 2: return CLUTTER_BUTTON2_MASK; case 3: return CLUTTER_BUTTON3_MASK; case 4: return CLUTTER_BUTTON4_MASK; case 5: return CLUTTER_BUTTON5_MASK; default: return 0; } } void _clutter_input_device_xi2_translate_state (ClutterEvent *event, XIModifierState *modifiers_state, XIButtonState *buttons_state, XIGroupState *group_state) { guint button = 0; guint base = 0; guint latched = 0; guint locked = 0; guint effective; if (modifiers_state) { base = (guint) modifiers_state->base; latched = (guint) modifiers_state->latched; locked = (guint) modifiers_state->locked; } if (buttons_state) { int len, i; len = MIN (N_BUTTONS, buttons_state->mask_len * 8); for (i = 0; i < len; i++) { if (!XIMaskIsSet (buttons_state->mask, i)) continue; button |= get_modifier_for_button (i); } } /* The XIButtonState sent in the event specifies the * state of the buttons before the event. In order to * get the current state of the buttons, we need to * filter out the current button. */ switch (event->type) { case CLUTTER_BUTTON_PRESS: button |= (get_modifier_for_button (event->button.button)); break; case CLUTTER_BUTTON_RELEASE: button &= ~(get_modifier_for_button (event->button.button)); break; default: break; } effective = button | base | latched | locked; if (group_state) effective |= (group_state->effective) << 13; _clutter_event_set_state_full (event, button, base, latched, locked, effective); } void clutter_input_device_xi2_update_tool (ClutterInputDevice *device, ClutterInputDeviceTool *tool) { ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device); g_set_object (&device_xi2->current_tool, tool); } ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device) { ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device); return device_xi2->current_tool; } #ifdef HAVE_LIBWACOM void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device, WacomDeviceDatabase *wacom_db) { ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device); const gchar *node_path; node_path = clutter_input_device_get_device_node (device); device_xi2->wacom_device = libwacom_new_from_path (wacom_db, node_path, WFALLBACK_NONE, NULL); } guint clutter_input_device_xi2_get_pad_group_mode (ClutterInputDevice *device, guint group) { ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device); if (group >= device_xi2->group_modes->len) return 0; return g_array_index (device_xi2->group_modes, guint, group); } void clutter_input_device_xi2_update_pad_state (ClutterInputDevice *device, guint button, guint state, guint *group, guint *mode) { ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device); guint button_group, *group_mode; gboolean is_mode_switch = FALSE; button_group = clutter_input_device_xi2_get_button_group (device, button); is_mode_switch = button_group >= 0; /* Assign all non-mode-switch buttons to group 0 so far */ button_group = MAX (0, button_group); if (button_group >= device_xi2->group_modes->len) return; group_mode = &g_array_index (device_xi2->group_modes, guint, button_group); if (is_mode_switch && state) { guint next, n_modes; n_modes = clutter_input_device_get_group_n_modes (device, button_group); next = (*group_mode + 1) % n_modes; *group_mode = next; } if (group) *group = button_group; if (mode) *mode = *group_mode; } #endif ���������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-glx.h������������������������������������������������������0000664�0001750�0001750�00000002104�14211404421�021331� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_GLX_H__ #define __CLUTTER_GLX_H__ #include <glib.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #include <clutter/clutter.h> #include <clutter/glx/clutter-glx-texture-pixmap.h> #endif /* __CLUTTER_GLX_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-input-device-core-x11.c������������������������������������0000664�0001750�0001750�00000004522�14211404421�024471� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #include "clutter-build-config.h" #include "clutter-input-device-core-x11.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-backend-x11.h" #include "clutter-stage-x11.h" typedef struct _ClutterInputDeviceClass ClutterInputDeviceX11Class; /* a specific X11 input device */ struct _ClutterInputDeviceX11 { ClutterInputDevice device; int min_keycode; int max_keycode; }; #define clutter_input_device_x11_get_type _clutter_input_device_x11_get_type G_DEFINE_TYPE (ClutterInputDeviceX11, clutter_input_device_x11, CLUTTER_TYPE_INPUT_DEVICE); static gboolean clutter_input_device_x11_keycode_to_evdev (ClutterInputDevice *device, guint hardware_keycode, guint *evdev_keycode) { /* When using evdev under X11 the hardware keycodes are the evdev keycodes plus 8. I haven't been able to find any documentation to know what the +8 is for. FIXME: This should probably verify that X server is using evdev. */ *evdev_keycode = hardware_keycode - 8; return TRUE; } static void clutter_input_device_x11_class_init (ClutterInputDeviceX11Class *klass) { ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass); device_class->keycode_to_evdev = clutter_input_device_x11_keycode_to_evdev; } static void clutter_input_device_x11_init (ClutterInputDeviceX11 *self) { } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-device-manager-xi2.h���������������������������������������0000664�0001750�0001750�00000004644�14211404421�024121� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_DEVICE_MANAGER_XI2_H__ #define __CLUTTER_DEVICE_MANAGER_XI2_H__ #include <clutter/clutter-device-manager.h> #ifdef HAVE_LIBWACOM #include <libwacom/libwacom.h> #endif G_BEGIN_DECLS #define CLUTTER_TYPE_DEVICE_MANAGER_XI2 (_clutter_device_manager_xi2_get_type ()) #define CLUTTER_DEVICE_MANAGER_XI2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2)) #define CLUTTER_IS_DEVICE_MANAGER_XI2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2)) #define CLUTTER_DEVICE_MANAGER_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2Class)) #define CLUTTER_IS_DEVICE_MANAGER_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_XI2)) #define CLUTTER_DEVICE_MANAGER_XI2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2Class)) typedef struct _ClutterDeviceManagerXI2 ClutterDeviceManagerXI2; typedef struct _ClutterDeviceManagerXI2Class ClutterDeviceManagerXI2Class; struct _ClutterDeviceManagerXI2 { ClutterDeviceManager parent_instance; GHashTable *devices_by_id; GHashTable *tools_by_serial; GSList *all_devices; GList *master_devices; GList *slave_devices; int opcode; #ifdef HAVE_LIBWACOM WacomDeviceDatabase *wacom_db; #endif }; struct _ClutterDeviceManagerXI2Class { ClutterDeviceManagerClass parent_class; }; GType _clutter_device_manager_xi2_get_type (void) G_GNUC_CONST; G_END_DECLS #endif /* __CLUTTER_DEVICE_MANAGER_XI2_H__ */ ��������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-x11-texture-pixmap.c���������������������������������������0000664�0001750�0001750�00000116215�14211404421�024146� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2007 OpenedHand * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Authors: * Johan Bilien <johan.bilien@nokia.com> * Neil Roberts <neil@linux.intel.com> */ /** * SECTION:clutter-x11-texture-pixmap * @Title: ClutterX11TexturePixmap * @short_description: A texture which displays the content of an X Pixmap. * * #ClutterX11TexturePixmap is a class for displaying the content of an * X Pixmap as a ClutterActor. Used together with the X Composite extension, * it allows to display the content of X Windows inside Clutter. * * The class uses the GLX_EXT_texture_from_pixmap OpenGL extension * (http://people.freedesktop.org/~davidr/GLX_EXT_texture_from_pixmap.txt) * if available */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-x11-texture-pixmap.h" #include "clutter-x11.h" #include "clutter-backend-x11.h" #include "clutter-actor-private.h" #include "clutter-marshal.h" #include "clutter-paint-volume-private.h" #include "clutter-private.h" #include <cogl/cogl.h> #include <cogl/winsys/cogl-texture-pixmap-x11.h> #include <X11/extensions/Xdamage.h> #if HAVE_XCOMPOSITE #include <X11/extensions/Xcomposite.h> #endif enum { PROP_PIXMAP = 1, PROP_PIXMAP_WIDTH, PROP_PIXMAP_HEIGHT, PROP_DEPTH, PROP_AUTO, PROP_WINDOW, PROP_WINDOW_REDIRECT_AUTOMATIC, PROP_WINDOW_MAPPED, PROP_DESTROYED, PROP_WINDOW_X, PROP_WINDOW_Y, PROP_WINDOW_OVERRIDE_REDIRECT }; enum { UPDATE_AREA, QUEUE_DAMAGE_REDRAW, /* FIXME: Pixmap lost signal? */ LAST_SIGNAL }; static ClutterX11FilterReturn on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data); static void clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, gint x, gint y, gint width, gint height); static void clutter_x11_texture_pixmap_sync_window_internal (ClutterX11TexturePixmap *texture, int x, int y, int width, int height, gboolean override_redirect); static void clutter_x11_texture_pixmap_set_mapped (ClutterX11TexturePixmap *texture, gboolean mapped); static void clutter_x11_texture_pixmap_destroyed (ClutterX11TexturePixmap *texture); static guint signals[LAST_SIGNAL] = { 0, }; struct _ClutterX11TexturePixmapPrivate { Window window; Pixmap pixmap; guint pixmap_width, pixmap_height; guint depth; Damage damage; gint window_x, window_y; gint window_width, window_height; guint window_redirect_automatic : 1; /* FIXME: this is inconsistently either whether the window is mapped or whether * it is viewable, and isn't updated correctly. */ guint window_mapped : 1; guint destroyed : 1; guint owns_pixmap : 1; guint override_redirect : 1; guint automatic_updates : 1; }; static int _damage_event_base = 0; G_DEFINE_TYPE_WITH_PRIVATE (ClutterX11TexturePixmap, clutter_x11_texture_pixmap, CLUTTER_TYPE_TEXTURE) static gboolean check_extensions (ClutterX11TexturePixmap *texture) { int damage_error; Display *dpy; if (_damage_event_base) return TRUE; dpy = clutter_x11_get_default_display(); if (!XDamageQueryExtension (dpy, &_damage_event_base, &damage_error)) { g_warning ("No Damage extension"); return FALSE; } return TRUE; } static void process_damage_event (ClutterX11TexturePixmap *texture, XDamageNotifyEvent *damage_event) { /* Cogl will deal with updating the texture and subtracting from the damage region so we only need to queue a redraw */ g_signal_emit (texture, signals[QUEUE_DAMAGE_REDRAW], 0, damage_event->area.x, damage_event->area.y, damage_event->area.width, damage_event->area.height); } static ClutterX11FilterReturn on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data) { ClutterX11TexturePixmap *texture; ClutterX11TexturePixmapPrivate *priv; texture = CLUTTER_X11_TEXTURE_PIXMAP (data); g_return_val_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture), \ CLUTTER_X11_FILTER_CONTINUE); priv = texture->priv; if (xev->type == _damage_event_base + XDamageNotify) { XDamageNotifyEvent *dev = (XDamageNotifyEvent*)xev; if (dev->damage != priv->damage) return CLUTTER_X11_FILTER_CONTINUE; process_damage_event (texture, dev); } return CLUTTER_X11_FILTER_CONTINUE; } static ClutterX11FilterReturn on_x_event_filter_too (XEvent *xev, ClutterEvent *cev, gpointer data) { ClutterX11TexturePixmap *texture; ClutterX11TexturePixmapPrivate *priv; texture = CLUTTER_X11_TEXTURE_PIXMAP (data); g_return_val_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture), \ CLUTTER_X11_FILTER_CONTINUE); priv = texture->priv; if (xev->xany.window != priv->window) return CLUTTER_X11_FILTER_CONTINUE; switch (xev->type) { case MapNotify: clutter_x11_texture_pixmap_sync_window_internal (texture, priv->window_x, priv->window_y, priv->window_width, priv->window_height, priv->override_redirect); break; case ConfigureNotify: clutter_x11_texture_pixmap_sync_window_internal (texture, xev->xconfigure.x, xev->xconfigure.y, xev->xconfigure.width, xev->xconfigure.height, xev->xconfigure.override_redirect); break; case UnmapNotify: clutter_x11_texture_pixmap_set_mapped (texture, FALSE); break; case DestroyNotify: clutter_x11_texture_pixmap_destroyed (texture); break; default: break; } return CLUTTER_X11_FILTER_CONTINUE; } static void update_pixmap_damage_object (ClutterX11TexturePixmap *texture) { ClutterX11TexturePixmapPrivate *priv = texture->priv; CoglHandle cogl_texture; /* If we already have a CoglTexturePixmapX11 then update its damage object */ cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture)); if (cogl_texture && cogl_is_texture_pixmap_x11 (cogl_texture)) { if (priv->damage) { const CoglTexturePixmapX11ReportLevel report_level = COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX; cogl_texture_pixmap_x11_set_damage_object (cogl_texture, priv->damage, report_level); } else cogl_texture_pixmap_x11_set_damage_object (cogl_texture, 0, 0); } } static void create_damage_resources (ClutterX11TexturePixmap *texture) { ClutterX11TexturePixmapPrivate *priv; Display *dpy; priv = texture->priv; dpy = clutter_x11_get_default_display(); if (!priv->pixmap) return; clutter_x11_trap_x_errors (); priv->damage = XDamageCreate (dpy, priv->pixmap, XDamageReportBoundingBox); /* Errors here might occur if the window is already destroyed, we * simply skip processing damage and assume that the texture pixmap * will be cleaned up by the app when it gets a DestroyNotify. */ XSync (dpy, FALSE); clutter_x11_untrap_x_errors (); if (priv->damage) { clutter_x11_add_filter (on_x_event_filter, (gpointer)texture); update_pixmap_damage_object (texture); } } static void free_damage_resources (ClutterX11TexturePixmap *texture) { ClutterX11TexturePixmapPrivate *priv; Display *dpy; priv = texture->priv; dpy = clutter_x11_get_default_display(); if (priv->damage) { clutter_x11_trap_x_errors (); XDamageDestroy (dpy, priv->damage); XSync (dpy, FALSE); clutter_x11_untrap_x_errors (); priv->damage = None; clutter_x11_remove_filter (on_x_event_filter, (gpointer)texture); update_pixmap_damage_object (texture); } } static gboolean clutter_x11_texture_pixmap_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { return clutter_paint_volume_set_from_allocation (volume, self); } static void clutter_x11_texture_pixmap_real_queue_damage_redraw ( ClutterX11TexturePixmap *texture, gint x, gint y, gint width, gint height) { ClutterX11TexturePixmapPrivate *priv = texture->priv; ClutterActor *self = CLUTTER_ACTOR (texture); ClutterActorBox allocation; float scale_x, scale_y; cairo_rectangle_int_t clip; /* NB: clutter_actor_queue_clipped_redraw expects a box in the actor's * coordinate space so we need to convert from pixmap coordinates to * actor coordinates... */ /* Calling clutter_actor_get_allocation_box() is enormously expensive * if the actor has an out-of-date allocation, since it triggers * a full redraw. clutter_actor_queue_clipped_redraw() would redraw * the whole stage anyways in that case, so just go ahead and do * it here. */ if (!clutter_actor_has_allocation (self)) { clutter_actor_queue_redraw (self); return; } if (priv->pixmap_width == 0 || priv->pixmap_height == 0) return; clutter_actor_get_allocation_box (self, &allocation); scale_x = (allocation.x2 - allocation.x1) / priv->pixmap_width; scale_y = (allocation.y2 - allocation.y1) / priv->pixmap_height; clip.x = x * scale_x; clip.y = y * scale_y; clip.width = width * scale_x; clip.height = height * scale_y; clutter_actor_queue_redraw_with_clip (self, &clip); } static void clutter_x11_texture_pixmap_init (ClutterX11TexturePixmap *self) { self->priv = clutter_x11_texture_pixmap_get_instance_private (self); if (!check_extensions (self)) { /* FIMXE: means display lacks needed extensions for at least auto. * - a _can_autoupdate() method ? */ } self->priv->automatic_updates = FALSE; self->priv->damage = None; self->priv->window = None; self->priv->pixmap = None; self->priv->pixmap_height = 0; self->priv->pixmap_width = 0; self->priv->window_redirect_automatic = TRUE; self->priv->window_mapped = FALSE; self->priv->destroyed = FALSE; self->priv->override_redirect = FALSE; self->priv->window_x = 0; self->priv->window_y = 0; } static void clutter_x11_texture_pixmap_dispose (GObject *object) { ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); free_damage_resources (texture); clutter_x11_remove_filter (on_x_event_filter_too, (gpointer)texture); clutter_x11_texture_pixmap_set_pixmap (texture, None); G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->dispose (object); } static void clutter_x11_texture_pixmap_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); ClutterX11TexturePixmapPrivate *priv = texture->priv; switch (prop_id) { case PROP_PIXMAP: clutter_x11_texture_pixmap_set_pixmap (texture, g_value_get_ulong (value)); break; case PROP_AUTO: clutter_x11_texture_pixmap_set_automatic (texture, g_value_get_boolean (value)); break; case PROP_WINDOW: clutter_x11_texture_pixmap_set_window (texture, g_value_get_ulong (value), priv->window_redirect_automatic); break; case PROP_WINDOW_REDIRECT_AUTOMATIC: { gboolean new; new = g_value_get_boolean (value); /* Change the update mode.. */ if (new != priv->window_redirect_automatic && priv->window) clutter_x11_texture_pixmap_set_window (texture, priv->window, new); priv->window_redirect_automatic = new; } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_x11_texture_pixmap_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); ClutterX11TexturePixmapPrivate *priv = texture->priv; switch (prop_id) { case PROP_PIXMAP: g_value_set_ulong (value, priv->pixmap); break; case PROP_PIXMAP_WIDTH: g_value_set_uint (value, priv->pixmap_width); break; case PROP_PIXMAP_HEIGHT: g_value_set_uint (value, priv->pixmap_height); break; case PROP_DEPTH: g_value_set_uint (value, priv->depth); break; case PROP_AUTO: g_value_set_boolean (value, priv->automatic_updates); break; case PROP_WINDOW: g_value_set_ulong (value, priv->window); break; case PROP_WINDOW_REDIRECT_AUTOMATIC: g_value_set_boolean (value, priv->window_redirect_automatic); break; case PROP_WINDOW_MAPPED: g_value_set_boolean (value, priv->window_mapped); break; case PROP_DESTROYED: g_value_set_boolean (value, priv->destroyed); break; case PROP_WINDOW_X: g_value_set_int (value, priv->window_x); break; case PROP_WINDOW_Y: g_value_set_int (value, priv->window_y); break; case PROP_WINDOW_OVERRIDE_REDIRECT: g_value_set_boolean (value, priv->override_redirect); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GParamSpec *pspec; actor_class->get_paint_volume = clutter_x11_texture_pixmap_get_paint_volume; object_class->dispose = clutter_x11_texture_pixmap_dispose; object_class->set_property = clutter_x11_texture_pixmap_set_property; object_class->get_property = clutter_x11_texture_pixmap_get_property; klass->update_area = clutter_x11_texture_pixmap_update_area_real; pspec = g_param_spec_ulong ("pixmap", P_("Pixmap"), P_("The X11 Pixmap to be bound"), 0, G_MAXULONG, None, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_PIXMAP, pspec); pspec = g_param_spec_uint ("pixmap-width", P_("Pixmap width"), P_("The width of the pixmap bound to this texture"), 0, G_MAXUINT, 0, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_PIXMAP_WIDTH, pspec); pspec = g_param_spec_uint ("pixmap-height", P_("Pixmap height"), P_("The height of the pixmap bound to this texture"), 0, G_MAXUINT, 0, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_PIXMAP_HEIGHT, pspec); pspec = g_param_spec_uint ("pixmap-depth", P_("Pixmap Depth"), P_("The depth (in number of bits) of the pixmap bound to this texture"), 0, G_MAXUINT, 0, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_DEPTH, pspec); pspec = g_param_spec_boolean ("automatic-updates", P_("Automatic Updates"), P_("If the texture should be kept in " "sync with any pixmap changes."), FALSE, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_AUTO, pspec); pspec = g_param_spec_ulong ("window", P_("Window"), P_("The X11 Window to be bound"), 0, G_MAXULONG, None, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_WINDOW, pspec); pspec = g_param_spec_boolean ("window-redirect-automatic", P_("Window Redirect Automatic"), P_("If composite window redirects are set to " "Automatic (or Manual if false)"), TRUE, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_WINDOW_REDIRECT_AUTOMATIC, pspec); pspec = g_param_spec_boolean ("window-mapped", P_("Window Mapped"), P_("If window is mapped"), FALSE, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_WINDOW_MAPPED, pspec); pspec = g_param_spec_boolean ("destroyed", P_("Destroyed"), P_("If window has been destroyed"), FALSE, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_DESTROYED, pspec); pspec = g_param_spec_int ("window-x", P_("Window X"), P_("X position of window on screen according to X11"), G_MININT, G_MAXINT, 0, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_WINDOW_X, pspec); pspec = g_param_spec_int ("window-y", P_("Window Y"), P_("Y position of window on screen according to X11"), G_MININT, G_MAXINT, 0, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_WINDOW_Y, pspec); pspec = g_param_spec_boolean ("window-override-redirect", P_("Window Override Redirect"), P_("If this is an override-redirect window"), FALSE, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_WINDOW_OVERRIDE_REDIRECT, pspec); /** * ClutterX11TexturePixmap::update-area: * @texture: the object which received the signal * @x: X coordinate of the area to update * @y: Y coordinate of the area to update * @width: width of the area to update * @height: height of the area to update * * The ::update-area signal is emitted to ask the texture to update its * content from its source pixmap. * * Since: 0.8 */ signals[UPDATE_AREA] = g_signal_new (g_intern_static_string ("update-area"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterX11TexturePixmapClass, \ update_area), NULL, NULL, _clutter_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); /** * ClutterX11TexturePixmap::queue-damage-redraw: * @texture: the object which received the signal * @x: The top left x position of the damage region * @y: The top left y position of the damage region * @width: The width of the damage region * @height: The height of the damage region * * ::queue-damage-redraw is emitted to notify that some sub-region * of the texture has been changed (either by an automatic damage * update or by an explicit call to * clutter_x11_texture_pixmap_update_area). This usually means a * redraw needs to be queued for the actor. * * The default handler will queue a clipped redraw in response to * the damage, using the assumption that the pixmap is being painted * to a rectangle covering the transformed allocation of the actor. * If you sub-class and change the paint method so this isn't true * then you must also provide your own damage signal handler to * queue a redraw that blocks this default behaviour. * * Since: 1.2 */ signals[QUEUE_DAMAGE_REDRAW] = g_signal_new (g_intern_static_string ("queue-damage-redraw"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, _clutter_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); g_signal_override_class_handler ("queue-damage-redraw", CLUTTER_X11_TYPE_TEXTURE_PIXMAP, G_CALLBACK (clutter_x11_texture_pixmap_real_queue_damage_redraw)); } static void clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, gint x, gint y, gint width, gint height) { CoglHandle cogl_texture; cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture)); if (cogl_texture) cogl_texture_pixmap_x11_update_area (cogl_texture, x, y, width, height); } /** * clutter_x11_texture_pixmap_new: * * Creates a new #ClutterX11TexturePixmap which can be used to display the * contents of an X11 Pixmap inside a Clutter scene graph * * Return value: A new #ClutterX11TexturePixmap * * Since: 0.8 */ ClutterActor * clutter_x11_texture_pixmap_new (void) { ClutterActor *actor; actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP, NULL); return actor; } /** * clutter_x11_texture_pixmap_new_with_pixmap: * @pixmap: the X Pixmap to which this texture should be bound * * Creates a new #ClutterX11TexturePixmap for @pixmap * * Return value: A new #ClutterX11TexturePixmap bound to the given X Pixmap * * Since: 0.8 */ ClutterActor * clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap) { ClutterActor *actor; actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP, "pixmap", pixmap, NULL); return actor; } /** * clutter_x11_texture_pixmap_new_with_window: * @window: the X window to which this texture should be bound * * Creates a new #ClutterX11TexturePixmap for @window * * Return value: A new #ClutterX11TexturePixmap bound to the given X window. * * Since: 0.8 **/ ClutterActor * clutter_x11_texture_pixmap_new_with_window (Window window) { ClutterActor *actor; actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP, "window", window, NULL); return actor; } /** * clutter_x11_texture_pixmap_set_pixmap: * @texture: the texture to bind * @pixmap: the X Pixmap to which the texture should be bound * * Sets the X Pixmap to which the texture should be bound. * * Since: 0.8 */ void clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, Pixmap pixmap) { Window root; int x, y; unsigned int width, height, border_width, depth; Status status = 0; gboolean new_pixmap = FALSE, new_pixmap_width = FALSE; gboolean new_pixmap_height = FALSE, new_pixmap_depth = FALSE; CoglPipeline *pipeline; ClutterX11TexturePixmapPrivate *priv; g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); priv = texture->priv; /* Get rid of the existing Cogl texture early because it may try to use the pixmap which we might destroy */ pipeline = (CoglPipeline *) clutter_texture_get_cogl_material (CLUTTER_TEXTURE (texture)); if (pipeline) cogl_pipeline_set_layer_texture (pipeline, 0, NULL); if (pixmap != None) { clutter_x11_trap_x_errors (); status = XGetGeometry (clutter_x11_get_default_display(), (Drawable)pixmap, &root, &x, &y, &width, &height, &border_width, &depth); if (clutter_x11_untrap_x_errors () || status == 0) { g_warning ("Unable to query pixmap: %lx", pixmap); pixmap = None; width = height = depth = 0; } } else { width = height = depth = 0; } if (priv->pixmap != pixmap) { if (priv->pixmap && priv->owns_pixmap) XFreePixmap (clutter_x11_get_default_display (), priv->pixmap); priv->pixmap = pixmap; new_pixmap = TRUE; /* The damage object is created on the pixmap, so it needs to be * recreated with a change in pixmap. */ if (priv->automatic_updates) { free_damage_resources (texture); create_damage_resources (texture); } } if (priv->pixmap_width != width) { priv->pixmap_width = width; new_pixmap_width = TRUE; } if (priv->pixmap_height != height) { priv->pixmap_height = height; new_pixmap_height = TRUE; } if (priv->depth != depth) { priv->depth = depth; new_pixmap_depth = TRUE; } /* NB: We defer sending the signals until updating all the * above members so the values are all available to the * signal handlers. */ g_object_ref (texture); if (new_pixmap) g_object_notify (G_OBJECT (texture), "pixmap"); if (new_pixmap_width) g_object_notify (G_OBJECT (texture), "pixmap-width"); if (new_pixmap_height) g_object_notify (G_OBJECT (texture), "pixmap-height"); if (new_pixmap_depth) g_object_notify (G_OBJECT (texture), "pixmap-depth"); if (pixmap) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); GError *error = NULL; CoglTexturePixmapX11 *texture_pixmap = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error); if (texture_pixmap) { clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (texture), COGL_TEXTURE (texture_pixmap)); cogl_object_unref (texture_pixmap); update_pixmap_damage_object (texture); } else { g_warning ("Failed to create CoglTexturePixmapX11: %s", error->message); g_error_free (error); } } /* * Keep ref until here in case a notify causes removal from the scene; can't * lower the notifies because glx's notify handler needs to run before * update_area */ g_object_unref (texture); } /** * clutter_x11_texture_pixmap_set_window: * @texture: the texture to bind * @window: the X window to which the texture should be bound * @automatic: %TRUE for automatic window updates, %FALSE for manual. * * Sets up a suitable pixmap for the window, using the composite and damage * extensions if possible, and then calls * clutter_x11_texture_pixmap_set_pixmap(). * * If you want to display a window in a #ClutterTexture, you probably want * this function, or its older sister, clutter_glx_texture_pixmap_set_window(). * * This function has no effect unless the XComposite extension is available. * * Since: 0.8 */ void clutter_x11_texture_pixmap_set_window (ClutterX11TexturePixmap *texture, Window window, gboolean automatic) { ClutterX11TexturePixmapPrivate *priv; XWindowAttributes attr; Display *dpy; g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); if (!clutter_x11_has_composite_extension ()) return; dpy = clutter_x11_get_default_display (); if (dpy == NULL) return; #if HAVE_XCOMPOSITE priv = texture->priv; if (priv->window == window && automatic == priv->window_redirect_automatic) return; if (priv->window) { clutter_x11_remove_filter (on_x_event_filter_too, (gpointer)texture); clutter_x11_trap_x_errors (); XCompositeUnredirectWindow(clutter_x11_get_default_display (), priv->window, priv->window_redirect_automatic ? CompositeRedirectAutomatic : CompositeRedirectManual); XSync (clutter_x11_get_default_display (), False); clutter_x11_untrap_x_errors (); clutter_x11_texture_pixmap_set_pixmap (texture, None); } priv->window = window; priv->window_redirect_automatic = automatic; priv->window_mapped = FALSE; priv->destroyed = FALSE; if (window == None) return; clutter_x11_trap_x_errors (); { if (!XGetWindowAttributes (dpy, window, &attr)) { XSync (dpy, False); clutter_x11_untrap_x_errors (); g_warning ("bad window 0x%x", (guint32)window); priv->window = None; return; } XCompositeRedirectWindow (dpy, window, automatic ? CompositeRedirectAutomatic : CompositeRedirectManual); XSync (dpy, False); } clutter_x11_untrap_x_errors (); XSelectInput (dpy, priv->window, attr.your_event_mask | StructureNotifyMask); clutter_x11_add_filter (on_x_event_filter_too, (gpointer)texture); g_object_ref (texture); g_object_notify (G_OBJECT (texture), "window"); clutter_x11_texture_pixmap_set_mapped (texture, attr.map_state == IsViewable); clutter_x11_texture_pixmap_sync_window_internal (texture, attr.x, attr.y, attr.width, attr.height, attr.override_redirect); g_object_unref (texture); #endif /* HAVE_XCOMPOSITE */ } static void clutter_x11_texture_pixmap_sync_window_internal (ClutterX11TexturePixmap *texture, int x, int y, int width, int height, gboolean override_redirect) { ClutterX11TexturePixmapPrivate *priv; Pixmap pixmap = None; gboolean mapped = FALSE; gboolean notify_x = FALSE; gboolean notify_y = FALSE; gboolean notify_override_redirect = FALSE; priv = texture->priv; if (priv->destroyed) return; notify_x = x != priv->window_x; notify_y = y != priv->window_y; notify_override_redirect = override_redirect != priv->override_redirect; priv->window_x = x; priv->window_y = y; priv->window_width = width; priv->window_height = height; priv->override_redirect = override_redirect; if (!clutter_x11_has_composite_extension ()) { /* FIXME: this should just be an error, this is unlikely to work worth anything */ clutter_x11_texture_pixmap_set_pixmap (texture, priv->window); return; } if (priv->pixmap == None || width != priv->pixmap_width || height != priv->pixmap_height) { /* Note that we're checking the size from the event against the size we obtained * from the last XCompositeNameWindowPixmap/XGetGeometry pair. This will always * end up right in the end, but we can have a series like: * * Window sized to 100x100 * Window sized to 110x110 * Window sized to 120x120 * Configure received for 100x100 - NameWindowPixmap * Configure received for 110x110 - NameWindowPixmap * Configure received for 120x120 - last size OK * * Where we NameWindowPixmap several times in a row. (Using pixmap_width/pixmap_height * rather than window_width/window_height saves the last one.) */ Display *dpy = clutter_x11_get_default_display (); /* NB: It's only valid to name a pixmap if the window is viewable. * * We don't explicitly check this though since there would be a race * between checking and naming unless we use a server grab which is * undesireable. * * Instead we gracefully handle any error with naming the pixmap. */ clutter_x11_trap_x_errors (); pixmap = XCompositeNameWindowPixmap (dpy, priv->window); /* Possible improvement: combine with the XGetGeometry in * clutter_x11_texture_pixmap_set_pixmap() */ XSync(dpy, False); if (clutter_x11_untrap_x_errors ()) pixmap = None; } g_object_ref (texture); /* guard against unparent */ g_object_freeze_notify (G_OBJECT (texture)); /* FIXME: mapped is always FALSE */ clutter_x11_texture_pixmap_set_mapped (texture, mapped); if (pixmap) { clutter_x11_texture_pixmap_set_pixmap (texture, pixmap); priv->owns_pixmap = TRUE; } if (notify_override_redirect) g_object_notify (G_OBJECT (texture), "window-override-redirect"); if (notify_x) g_object_notify (G_OBJECT (texture), "window-x"); if (notify_y) g_object_notify (G_OBJECT (texture), "window-y"); g_object_thaw_notify (G_OBJECT (texture)); g_object_unref (texture); } /** * clutter_x11_texture_pixmap_sync_window: * @texture: the texture to bind * * Resets the texture's pixmap from its window, perhaps in response to the * pixmap's invalidation as the window changed size. * * Since: 0.8 */ void clutter_x11_texture_pixmap_sync_window (ClutterX11TexturePixmap *texture) { ClutterX11TexturePixmapPrivate *priv; g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); priv = texture->priv; if (priv->destroyed) return; if (priv->window != None) { Display *dpy = clutter_x11_get_default_display (); XWindowAttributes attr; Status status; if (dpy == NULL) return; clutter_x11_trap_x_errors (); status = XGetWindowAttributes (dpy, priv->window, &attr); if (status != 0) clutter_x11_texture_pixmap_sync_window_internal (texture, attr.x, attr.y, attr.width, attr.height, attr.override_redirect); clutter_x11_untrap_x_errors (); } } static void clutter_x11_texture_pixmap_set_mapped (ClutterX11TexturePixmap *texture, gboolean mapped) { ClutterX11TexturePixmapPrivate *priv; priv = texture->priv; if (mapped != priv->window_mapped) { priv->window_mapped = mapped; g_object_notify (G_OBJECT (texture), "window-mapped"); } } static void clutter_x11_texture_pixmap_destroyed (ClutterX11TexturePixmap *texture) { ClutterX11TexturePixmapPrivate *priv; priv = texture->priv; if (!priv->destroyed) { priv->destroyed = TRUE; g_object_notify (G_OBJECT (texture), "destroyed"); } /* * Don't set window to None, that would destroy the pixmap, which might still * be useful e.g. for destroy animations -- app's responsibility. */ } /** * clutter_x11_texture_pixmap_update_area: * @texture: The texture whose content shall be updated. * @x: the X coordinate of the area to update * @y: the Y coordinate of the area to update * @width: the width of the area to update * @height: the height of the area to update * * Performs the actual binding of texture to the current content of * the pixmap. Can be called to update the texture if the pixmap * content has changed. * * Since: 0.8 **/ void clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, gint x, gint y, gint width, gint height) { g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); g_signal_emit (texture, signals[UPDATE_AREA], 0, x, y, width, height); /* The default handler for the "queue-damage-redraw" signal is * clutter_x11_texture_pixmap_real_queue_damage_redraw which will queue a * clipped redraw. */ g_signal_emit (texture, signals[QUEUE_DAMAGE_REDRAW], 0, x, y, width, height); } /** * clutter_x11_texture_pixmap_set_automatic: * @texture: a #ClutterX11TexturePixmap * @setting: %TRUE to enable automatic updates * * Enables or disables the automatic updates ot @texture in case the backing * pixmap or window is damaged * * Since: 0.8 */ void clutter_x11_texture_pixmap_set_automatic (ClutterX11TexturePixmap *texture, gboolean setting) { ClutterX11TexturePixmapPrivate *priv; g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); priv = texture->priv; setting = !!setting; if (setting == priv->automatic_updates) return; if (setting) create_damage_resources (texture); else free_damage_resources (texture); priv->automatic_updates = setting; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-x11-texture-pixmap.h���������������������������������������0000664�0001750�0001750�00000011036�14211404421�024146� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Johan Bilien <johan.bilien@nokia.com> * * 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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_X11_TEXTURE_PIXMAP_H__ #define __CLUTTER_X11_TEXTURE_PIXMAP_H__ #include <glib.h> #include <glib-object.h> #include <clutter/clutter.h> #include <X11/Xlib.h> G_BEGIN_DECLS #define CLUTTER_X11_TYPE_TEXTURE_PIXMAP (clutter_x11_texture_pixmap_get_type ()) #define CLUTTER_X11_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_X11_TYPE_TEXTURE_PIXMAP, ClutterX11TexturePixmap)) #define CLUTTER_X11_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_X11_TYPE_TEXTURE_PIXMAP, ClutterX11TexturePixmapClass)) #define CLUTTER_X11_IS_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_X11_TYPE_TEXTURE_PIXMAP)) #define CLUTTER_X11_IS_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_X11_TYPE_TEXTURE_PIXMAP)) #define CLUTTER_X11_TEXTURE_PIXMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_X11_TYPE_TEXTURE_PIXMAP, ClutterX11TexturePixmapClass)) typedef struct _ClutterX11TexturePixmap ClutterX11TexturePixmap; typedef struct _ClutterX11TexturePixmapClass ClutterX11TexturePixmapClass; typedef struct _ClutterX11TexturePixmapPrivate ClutterX11TexturePixmapPrivate; /** * ClutterX11TexturePixmap: * * The #ClutterX11TexturePixmap structure contains only private data * * Since: 0.8 */ struct _ClutterX11TexturePixmap { /*< private >*/ ClutterTexture parent; ClutterX11TexturePixmapPrivate *priv; }; /** * ClutterX11TexturePixmapClass: * @update_area: virtual function for updating the area of the texture * * The #ClutterX11TexturePixmapClass structure contains only private data * * Since: 0.8 */ struct _ClutterX11TexturePixmapClass { /*< private >*/ ClutterTextureClass parent_class; /*< public >*/ void (* update_area) (ClutterX11TexturePixmap *texture, gint x, gint y, gint width, gint height); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_x11_texture_pixmap_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterActor *clutter_x11_texture_pixmap_new (void); CLUTTER_AVAILABLE_IN_ALL ClutterActor *clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap); CLUTTER_AVAILABLE_IN_ALL ClutterActor *clutter_x11_texture_pixmap_new_with_window (Window window); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_texture_pixmap_set_automatic (ClutterX11TexturePixmap *texture, gboolean setting); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, Pixmap pixmap); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_texture_pixmap_set_window (ClutterX11TexturePixmap *texture, Window window, gboolean automatic); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_texture_pixmap_sync_window (ClutterX11TexturePixmap *texture); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, gint x, gint y, gint width, gint height); G_END_DECLS #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-xkb-a11y-x11.c���������������������������������������������0000664�0001750�0001750�00000026750�14211404421�022513� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * * Copyright © 2001 Ximian, Inc. * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> * Copyright (C) 2017 Red Hat * * 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 "clutter-device-manager-private.h" #include "clutter-xkb-a11y-x11.h" #include <X11/XKBlib.h> #include <X11/extensions/XKBstr.h> #define DEFAULT_XKB_SET_CONTROLS_MASK XkbSlowKeysMask | \ XkbBounceKeysMask | \ XkbStickyKeysMask | \ XkbMouseKeysMask | \ XkbMouseKeysAccelMask | \ XkbAccessXKeysMask | \ XkbAccessXTimeoutMask | \ XkbAccessXFeedbackMask | \ XkbControlsEnabledMask static int _xkb_event_base; static XkbDescRec * get_xkb_desc_rec (ClutterBackendX11 *backend_x11) { XkbDescRec *desc; Status status = Success; clutter_x11_trap_x_errors (); desc = XkbGetMap (backend_x11->xdpy, XkbAllMapComponentsMask, XkbUseCoreKbd); if (desc != NULL) { desc->ctrls = NULL; status = XkbGetControls (backend_x11->xdpy, XkbAllControlsMask, desc); } clutter_x11_untrap_x_errors (); g_return_val_if_fail (desc != NULL, NULL); g_return_val_if_fail (desc->ctrls != NULL, NULL); g_return_val_if_fail (status == Success, NULL); return desc; } static void set_xkb_desc_rec (ClutterBackendX11 *backend_x11, XkbDescRec *desc) { clutter_x11_trap_x_errors (); XkbSetControls (backend_x11->xdpy, DEFAULT_XKB_SET_CONTROLS_MASK, desc); XSync (backend_x11->xdpy, FALSE); clutter_x11_untrap_x_errors (); } static void check_settings_changed (ClutterDeviceManager *device_manager) { ClutterBackendX11 *backend_x11; ClutterKbdA11ySettings kbd_a11y_settings; ClutterKeyboardA11yFlags what_changed = 0; XkbDescRec *desc; backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); desc = get_xkb_desc_rec (backend_x11); if (!desc) return; clutter_device_manager_get_kbd_a11y_settings (device_manager, &kbd_a11y_settings); if (desc->ctrls->enabled_ctrls & XkbSlowKeysMask && !(kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED)) { what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; kbd_a11y_settings.controls |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; } else if (!(desc->ctrls->enabled_ctrls & XkbSlowKeysMask) && kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED) { what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; kbd_a11y_settings.controls &= ~CLUTTER_A11Y_SLOW_KEYS_ENABLED; } if (desc->ctrls->enabled_ctrls & XkbStickyKeysMask && !(kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED)) { what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; kbd_a11y_settings.controls |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; } else if (!(desc->ctrls->enabled_ctrls & XkbStickyKeysMask) && kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED) { what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; kbd_a11y_settings.controls &= ~CLUTTER_A11Y_STICKY_KEYS_ENABLED; } if (what_changed) g_signal_emit_by_name (device_manager, "kbd-a11y-flags-changed", kbd_a11y_settings.controls, what_changed); XkbFreeKeyboard (desc, XkbAllComponentsMask, TRUE); } static ClutterX11FilterReturn xkb_a11y_event_filter (XEvent *xevent, ClutterEvent *clutter_event, gpointer data) { ClutterDeviceManager *device_manager = CLUTTER_DEVICE_MANAGER (data); XkbEvent *xkbev = (XkbEvent *) xevent; /* 'event_type' is set to zero on notifying us of updates in * response to client requests (including our own) and non-zero * to notify us of key/mouse events causing changes (like * pressing shift 5 times to enable sticky keys). * * We only want to update out settings when it's in response to an * explicit user input event, so require a non-zero event_type. */ if (xevent->xany.type == (_xkb_event_base + XkbEventCode) && xkbev->any.xkb_type == XkbControlsNotify && xkbev->ctrls.event_type != 0) check_settings_changed (device_manager); return CLUTTER_X11_FILTER_CONTINUE; } static gboolean is_xkb_available (ClutterBackendX11 *backend_x11) { gint opcode, error_base, event_base, major, minor; if (_xkb_event_base) return TRUE; if (!XkbQueryExtension (backend_x11->xdpy, &opcode, &event_base, &error_base, &major, &minor)) return FALSE; if (!XkbUseExtension (backend_x11->xdpy, &major, &minor)) return FALSE; _xkb_event_base = event_base; return TRUE; } static unsigned long set_value_mask (gboolean flag, unsigned long value, unsigned long mask) { if (flag) return value | mask; return value & ~mask; } static gboolean set_xkb_ctrl (XkbDescRec *desc, ClutterKeyboardA11yFlags settings, ClutterKeyboardA11yFlags flag, unsigned long mask) { gboolean result = (settings & flag) == flag; desc->ctrls->enabled_ctrls = set_value_mask (result, desc->ctrls->enabled_ctrls, mask); return result; } void clutter_device_manager_x11_apply_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *kbd_a11y_settings) { ClutterBackendX11 *backend_x11; XkbDescRec *desc; gboolean enable_accessX; backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); desc = get_xkb_desc_rec (backend_x11); if (!desc) return; /* general */ enable_accessX = kbd_a11y_settings->controls & CLUTTER_A11Y_KEYBOARD_ENABLED; desc->ctrls->enabled_ctrls = set_value_mask (enable_accessX, desc->ctrls->enabled_ctrls, XkbAccessXKeysMask); if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_TIMEOUT_ENABLED, XkbAccessXTimeoutMask)) { desc->ctrls->ax_timeout = kbd_a11y_settings->timeout_delay; /* disable only the master flag via the server we will disable * the rest on the rebound without affecting settings state * don't change the option flags at all. */ desc->ctrls->axt_ctrls_mask = XkbAccessXKeysMask | XkbAccessXFeedbackMask; desc->ctrls->axt_ctrls_values = 0; desc->ctrls->axt_opts_mask = 0; } desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask); /* bounce keys */ if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_BOUNCE_KEYS_ENABLED, XkbBounceKeysMask)) { desc->ctrls->debounce_delay = kbd_a11y_settings->debounce_delay; desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_BKRejectFBMask); } /* mouse keys */ if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask)) { gint mk_max_speed; gint mk_accel_time; desc->ctrls->mk_interval = 100; /* msec between mousekey events */ desc->ctrls->mk_curve = 50; /* We store pixels / sec, XKB wants pixels / event */ mk_max_speed = kbd_a11y_settings->mousekeys_max_speed; desc->ctrls->mk_max_speed = mk_max_speed / (1000 / desc->ctrls->mk_interval); if (desc->ctrls->mk_max_speed <= 0) desc->ctrls->mk_max_speed = 1; mk_accel_time = kbd_a11y_settings->mousekeys_accel_time; desc->ctrls->mk_time_to_max = mk_accel_time / desc->ctrls->mk_interval; if (desc->ctrls->mk_time_to_max <= 0) desc->ctrls->mk_time_to_max = 1; desc->ctrls->mk_delay = kbd_a11y_settings->mousekeys_init_delay; } /* slow keys */ if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_SLOW_KEYS_ENABLED, XkbSlowKeysMask)) { desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKPressFBMask); desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKAcceptFBMask); desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKRejectFBMask); desc->ctrls->slow_keys_delay = kbd_a11y_settings->slowkeys_delay; /* anything larger than 500 seems to loose all keyboard input */ if (desc->ctrls->slow_keys_delay > 500) desc->ctrls->slow_keys_delay = 500; } /* sticky keys */ if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_STICKY_KEYS_ENABLED, XkbStickyKeysMask)) { desc->ctrls->ax_options |= XkbAX_LatchToLockMask; desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_TwoKeysMask); desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_BEEP, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_StickyKeysFBMask); } /* toggle keys */ desc->ctrls->ax_options = set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_TOGGLE_KEYS_ENABLED, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_IndicatorFBMask); set_xkb_desc_rec (backend_x11, desc); XkbFreeKeyboard (desc, XkbAllComponentsMask, TRUE); } gboolean clutter_device_manager_x11_a11y_init (ClutterDeviceManager *device_manager) { ClutterBackendX11 *backend_x11; guint event_mask; backend_x11 = CLUTTER_BACKEND_X11 (_clutter_device_manager_get_backend (device_manager)); if (!is_xkb_available (backend_x11)) return FALSE; event_mask = XkbControlsNotifyMask | XkbAccessXNotifyMask; XkbSelectEvents (backend_x11->xdpy, XkbUseCoreKbd, event_mask, event_mask); clutter_x11_add_filter (xkb_a11y_event_filter, device_manager); return TRUE; } ������������������������muffin-5.2.1/clutter/clutter/x11/clutter-stage-x11.c������������������������������������������������0000664�0001750�0001750�00000150611�14211404421�022253� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * Authored By Matthew Allum <mallum@openedhand.com> * Copyright (C) 2006-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, see <http://www.gnu.org/licenses/>. * * */ #include "clutter-build-config.h" #include <math.h> #include <stdlib.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <cogl/cogl.h> #include "clutter-backend-x11.h" #include "clutter-stage-x11.h" #include "clutter-x11.h" #include "clutter-actor-private.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-enum-types.h" #include "clutter-event-translator.h" #include "clutter-event-private.h" #include "clutter-feature.h" #include "clutter-main.h" #include "clutter-muffin.h" #include "clutter-paint-volume-private.h" #include "clutter-private.h" #include "clutter-stage-private.h" #define STAGE_X11_IS_MAPPED(s) ((((ClutterStageX11 *) (s))->wm_state & STAGE_X11_WITHDRAWN) == 0) static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL; static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface); static ClutterStageCogl *clutter_x11_get_stage_window_from_window (Window win); static GHashTable *clutter_stages_by_xid = NULL; #define clutter_stage_x11_get_type _clutter_stage_x11_get_type G_DEFINE_TYPE_WITH_CODE (ClutterStageX11, clutter_stage_x11, CLUTTER_TYPE_STAGE_COGL, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, clutter_stage_window_iface_init) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR, clutter_event_translator_iface_init)); #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ #define _NET_WM_STATE_ADD 1 /* add/set property */ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ #define CLUTTER_STAGE_X11_EVENT_MASK \ StructureNotifyMask | \ FocusChangeMask | \ ExposureMask | \ PropertyChangeMask | \ EnterWindowMask | \ LeaveWindowMask | \ KeyPressMask | \ KeyReleaseMask | \ ButtonPressMask | \ ButtonReleaseMask | \ PointerMotionMask static void send_wmspec_change_state (ClutterBackendX11 *backend_x11, Window window, Atom state, gboolean add) { XClientMessageEvent xclient; CLUTTER_NOTE (BACKEND, "%s NET_WM state", add ? "adding" : "removing"); memset (&xclient, 0, sizeof (xclient)); xclient.type = ClientMessage; xclient.window = window; xclient.message_type = backend_x11->atom_NET_WM_STATE; xclient.format = 32; xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; xclient.data.l[1] = state; xclient.data.l[2] = 0; xclient.data.l[3] = 0; xclient.data.l[4] = 0; XSendEvent (backend_x11->xdpy, DefaultRootWindow (backend_x11->xdpy), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient); } static void update_state (ClutterStageX11 *stage_x11, ClutterBackendX11 *backend_x11, Atom *state, gboolean add) { if (add) { /* FIXME: This wont work if we support more states */ XChangeProperty (backend_x11->xdpy, stage_x11->xwin, backend_x11->atom_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) state, 1); } else { /* FIXME: This wont work if we support more states */ XDeleteProperty (backend_x11->xdpy, stage_x11->xwin, backend_x11->atom_NET_WM_STATE); } } static void clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11, gint new_width, gint new_height) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin) { guint min_width, min_height; XSizeHints *size_hints; gboolean resize; resize = clutter_stage_get_user_resizable (stage_cogl->wrapper); size_hints = XAllocSizeHints(); clutter_stage_get_minimum_size (stage_cogl->wrapper, &min_width, &min_height); if (new_width <= 0) new_width = min_width; if (new_height <= 0) new_height = min_height; size_hints->flags = 0; /* If we are going fullscreen then we don't want any restrictions on the window size */ if (!stage_x11->fullscreening) { if (resize) { size_hints->min_width = min_width; size_hints->min_height = min_height; size_hints->flags = PMinSize; } else { size_hints->min_width = new_width; size_hints->min_height = new_height; size_hints->max_width = new_width; size_hints->max_height = new_height; size_hints->flags = PMinSize | PMaxSize; } } XSetWMNormalHints (backend_x11->xdpy, stage_x11->xwin, size_hints); XFree(size_hints); } } static void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); Atom protocols[2]; int n = 0; protocols[n++] = backend_x11->atom_WM_DELETE_WINDOW; protocols[n++] = backend_x11->atom_NET_WM_PING; XSetWMProtocols (backend_x11->xdpy, stage_x11->xwin, protocols, n); } static void clutter_stage_x11_get_geometry (ClutterStageWindow *stage_window, cairo_rectangle_int_t *geometry) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); geometry->x = geometry->y = 0; /* If we're fullscreen, return the size of the display. * * FIXME - this is utterly broken for anything that is not a single * head set up; the window manager will give us the right size in a * ConfigureNotify, but between the fullscreen signal emission on the * stage and the following frame, the size returned by the stage will * be wrong. */ if (_clutter_stage_is_fullscreen (stage_cogl->wrapper) && stage_x11->fullscreening) { geometry->width = DisplayWidth (backend_x11->xdpy, backend_x11->xscreen_num); geometry->height = DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num); return; } geometry->width = stage_x11->xwin_width; geometry->height = stage_x11->xwin_height; } static void clutter_stage_x11_resize (ClutterStageWindow *stage_window, gint width, gint height) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); if (stage_x11->is_foreign_xwin) { /* If this is a foreign window we won't get a ConfigureNotify, * so we need to manually set the size and queue a relayout on the * stage here (as is normally done in response to ConfigureNotify). */ stage_x11->xwin_width = width; stage_x11->xwin_height = height; clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_cogl->wrapper)); return; } /* If we're going fullscreen, don't mess with the size */ if (stage_x11->fullscreening) return; if (width == 0 || height == 0) { /* Should not happen, if this turns up we need to debug it and * determine the cleanest way to fix. */ g_warning ("X11 stage not allowed to have 0 width or height"); width = 1; height = 1; } CLUTTER_NOTE (BACKEND, "New size received: (%d, %d)", width, height); if (stage_x11->xwin != None) { clutter_stage_x11_fix_window_size (stage_x11, width, height); if (width != stage_x11->xwin_width || height != stage_x11->xwin_height) { CLUTTER_NOTE (BACKEND, "%s: XResizeWindow[%x] (%d, %d)", G_STRLOC, (unsigned int) stage_x11->xwin, width, height); /* XXX: in this case we can rely on a subsequent * ConfigureNotify that will result in the stage * being reallocated so we don't actively do anything * to affect the stage allocation here. */ XResizeWindow (backend_x11->xdpy, stage_x11->xwin, width, height); } } else { /* if the backing window hasn't been created yet, we just * need to store the new window size */ stage_x11->xwin_width = width; stage_x11->xwin_height = height; } } static inline void set_wm_pid (ClutterStageX11 *stage_x11) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); long pid; if (stage_x11->xwin == None || stage_x11->is_foreign_xwin) return; /* this will take care of WM_CLIENT_MACHINE and WM_LOCALE_NAME */ XSetWMProperties (backend_x11->xdpy, stage_x11->xwin, NULL, NULL, NULL, 0, NULL, NULL, NULL); pid = getpid (); XChangeProperty (backend_x11->xdpy, stage_x11->xwin, backend_x11->atom_NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, (guchar *) &pid, 1); } static inline void set_wm_title (ClutterStageX11 *stage_x11) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); if (stage_x11->xwin == None || stage_x11->is_foreign_xwin) return; if (stage_x11->title == NULL) { XDeleteProperty (backend_x11->xdpy, stage_x11->xwin, backend_x11->atom_NET_WM_NAME); } else { XChangeProperty (backend_x11->xdpy, stage_x11->xwin, backend_x11->atom_NET_WM_NAME, backend_x11->atom_UTF8_STRING, 8, PropModeReplace, (unsigned char *) stage_x11->title, (int) strlen (stage_x11->title)); } } static inline void set_cursor_visible (ClutterStageX11 *stage_x11) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); if (stage_x11->xwin == None) return; CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)", stage_x11->is_cursor_visible ? "visible" : "invisible", (unsigned int) stage_x11->xwin); if (stage_x11->is_cursor_visible) { XUndefineCursor (backend_x11->xdpy, stage_x11->xwin); } else { XColor col; Pixmap pix; Cursor curs; pix = XCreatePixmap (backend_x11->xdpy, stage_x11->xwin, 1, 1, 1); memset (&col, 0, sizeof (col)); curs = XCreatePixmapCursor (backend_x11->xdpy, pix, pix, &col, &col, 1, 1); XFreePixmap (backend_x11->xdpy, pix); XDefineCursor (backend_x11->xdpy, stage_x11->xwin, curs); } } static void clutter_stage_x11_unrealize (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); if (clutter_stages_by_xid != NULL) { CLUTTER_NOTE (BACKEND, "Removing X11 stage 0x%x [%p]", (unsigned int) stage_x11->xwin, stage_x11); g_hash_table_remove (clutter_stages_by_xid, GINT_TO_POINTER (stage_x11->xwin)); } /* Clutter still uses part of the deprecated stateful API of Cogl * (in particulart cogl_set_framebuffer). It means Cogl can keep an * internal reference to the onscreen object we rendered to. In the * case of foreign window, we want to avoid this, as we don't know * what's going to happen to that window. * * The following call sets the current Cogl framebuffer to a dummy * 1x1 one if we're unrealizing the current one, so Cogl doesn't * keep any reference to the foreign window. */ if (cogl_get_draw_framebuffer () == COGL_FRAMEBUFFER (stage_x11->onscreen)) _clutter_backend_reset_cogl_framebuffer (stage_cogl->backend); if (stage_x11->frame_closure) { cogl_onscreen_remove_frame_callback (stage_x11->onscreen, stage_x11->frame_closure); stage_x11->frame_closure = NULL; } clutter_stage_window_parent_iface->unrealize (stage_window); g_list_free (stage_x11->legacy_views); g_clear_object (&stage_x11->legacy_view); g_clear_pointer (&stage_x11->onscreen, cogl_object_unref); } static void _clutter_stage_x11_update_foreign_event_mask (CoglOnscreen *onscreen, guint32 event_mask, void *user_data) { ClutterStageX11 *stage_x11 = user_data; ClutterStageCogl *stage_cogl = user_data; ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); XSetWindowAttributes attrs; attrs.event_mask = event_mask | CLUTTER_STAGE_X11_EVENT_MASK; XChangeWindowAttributes (backend_x11->xdpy, stage_x11->xwin, CWEventMask, &attrs); } static void clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window, gboolean is_fullscreen) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); ClutterStage *stage = stage_cogl->wrapper; gboolean was_fullscreen; if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; was_fullscreen = _clutter_stage_is_fullscreen (stage); is_fullscreen = !!is_fullscreen; if (was_fullscreen == is_fullscreen) return; CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un"); if (is_fullscreen) { #if 0 int width, height; /* FIXME: this will do the wrong thing for dual-headed displays. This will return the size of the combined display but Metacity (at least) will fullscreen to only one of the displays. This will cause the actor to report the wrong size until the ConfigureNotify for the correct size is received */ width = DisplayWidth (backend_x11->xdpy, backend_x11->xscreen_num); height = DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num); #endif /* Set the fullscreen hint so we can retain the old size of the window. */ stage_x11->fullscreening = TRUE; if (stage_x11->xwin != None) { /* if the actor is not mapped we resize the stage window to match * the size of the screen; this is useful for e.g. EGLX to avoid * a resize when calling clutter_stage_fullscreen() before showing * the stage */ if (!STAGE_X11_IS_MAPPED (stage_x11)) { CLUTTER_NOTE (BACKEND, "Fullscreening unmapped stage"); update_state (stage_x11, backend_x11, &backend_x11->atom_NET_WM_STATE_FULLSCREEN, TRUE); } else { CLUTTER_NOTE (BACKEND, "Fullscreening mapped stage"); /* We need to fix the window size so that it will remove the maximum and minimum window hints. Otherwise metacity will honour the restrictions and not fullscreen correctly. */ clutter_stage_x11_fix_window_size (stage_x11, -1, -1); send_wmspec_change_state (backend_x11, stage_x11->xwin, backend_x11->atom_NET_WM_STATE_FULLSCREEN, TRUE); } } else stage_x11->fullscreen_on_realize = TRUE; } else { stage_x11->fullscreening = FALSE; if (stage_x11->xwin != None) { if (!STAGE_X11_IS_MAPPED (stage_x11)) { CLUTTER_NOTE (BACKEND, "Un-fullscreening unmapped stage"); update_state (stage_x11, backend_x11, &backend_x11->atom_NET_WM_STATE_FULLSCREEN, FALSE); } else { CLUTTER_NOTE (BACKEND, "Un-fullscreening mapped stage"); send_wmspec_change_state (backend_x11, stage_x11->xwin, backend_x11->atom_NET_WM_STATE_FULLSCREEN, FALSE); /* Fix the window size to restore the minimum/maximum restriction */ clutter_stage_x11_fix_window_size (stage_x11, stage_x11->xwin_width, stage_x11->xwin_height); } } else stage_x11->fullscreen_on_realize = FALSE; } /* XXX: Note we rely on the ConfigureNotify mechanism as the common * mechanism to handle notifications of new X window sizes from the * X server so we don't actively change the stage viewport here or * queue a relayout etc. */ } void _clutter_stage_x11_events_device_changed (ClutterStageX11 *stage_x11, ClutterInputDevice *device, ClutterDeviceManager *device_manager) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_FLOATING) _clutter_device_manager_select_stage_events (device_manager, stage_cogl->wrapper); } static void stage_events_device_added (ClutterDeviceManager *device_manager, ClutterInputDevice *device, gpointer user_data) { ClutterStageWindow *stage_window = user_data; ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_FLOATING) _clutter_device_manager_select_stage_events (device_manager, stage_cogl->wrapper); } static void frame_cb (CoglOnscreen *onscreen, CoglFrameEvent frame_event, CoglFrameInfo *frame_info, void *user_data) { ClutterStageCogl *stage_cogl = user_data; ClutterFrameInfo clutter_frame_info = { .frame_counter = cogl_frame_info_get_frame_counter (frame_info), .presentation_time = cogl_frame_info_get_presentation_time (frame_info), .refresh_rate = cogl_frame_info_get_refresh_rate (frame_info) }; _clutter_stage_cogl_presented (stage_cogl, frame_event, &clutter_frame_info); } void clutter_stage_x11_update_sync_state (ClutterStage *stage, SyncMethod method) { ClutterStageWindow *stage_window; ClutterStageX11 *stage_x11; gboolean state; g_return_if_fail (stage != NULL); stage_window = CLUTTER_STAGE_WINDOW (_clutter_stage_get_window (CLUTTER_STAGE (stage))); stage_x11 = CLUTTER_STAGE_X11 (stage_window); g_return_if_fail (stage_x11->onscreen != NULL); state = method != SYNC_NONE; _clutter_set_sync_to_vblank (state); cogl_onscreen_set_swap_throttled (stage_x11->onscreen, state); clutter_master_clock_set_sync_method (method); } static gboolean clutter_stage_x11_realize (ClutterStageWindow *stage_window) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); ClutterBackend *backend = CLUTTER_BACKEND (stage_cogl->backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterDeviceManager *device_manager; gfloat width, height; SyncMethod sync_method = _clutter_get_sync_method(); GError *error = NULL; clutter_actor_get_size (CLUTTER_ACTOR (stage_cogl->wrapper), &width, &height); CLUTTER_NOTE (BACKEND, "Wrapper size: %.2f x %.2f", width, height); CLUTTER_NOTE (BACKEND, "Creating a new Cogl onscreen surface: %.2f x %.2f", width, height); stage_x11->onscreen = cogl_onscreen_new (backend->cogl_context, width, height); cogl_onscreen_set_swap_throttled (stage_x11->onscreen, sync_method != SYNC_NONE); stage_x11->frame_closure = cogl_onscreen_add_frame_callback (stage_x11->onscreen, frame_cb, stage_cogl, NULL); if (stage_x11->legacy_view) g_object_set (G_OBJECT (stage_x11->legacy_view), "framebuffer", stage_x11->onscreen, NULL); /* We just created a window of the size of the actor. No need to fix the size of the stage, just update it. */ stage_x11->xwin_width = width; stage_x11->xwin_height = height; if (stage_x11->xwin != None) { cogl_x11_onscreen_set_foreign_window_xid (stage_x11->onscreen, stage_x11->xwin, _clutter_stage_x11_update_foreign_event_mask, stage_x11); } if (!cogl_framebuffer_allocate (stage_x11->onscreen, &error)) { g_warning ("Failed to allocate stage: %s", error->message); g_error_free (error); cogl_object_unref (stage_x11->onscreen); abort(); } if (!(clutter_stage_window_parent_iface->realize (stage_window))) return FALSE; if (stage_x11->xwin == None) stage_x11->xwin = cogl_x11_onscreen_get_window_xid (stage_x11->onscreen); if (clutter_stages_by_xid == NULL) clutter_stages_by_xid = g_hash_table_new (NULL, NULL); g_hash_table_insert (clutter_stages_by_xid, GINT_TO_POINTER (stage_x11->xwin), stage_x11); set_wm_pid (stage_x11); set_wm_title (stage_x11); set_cursor_visible (stage_x11); /* we unconditionally select input events even with event retrieval * disabled because we need to guarantee that the Clutter internal * state is maintained when calling clutter_x11_handle_event() without * requiring applications or embedding toolkits to select events * themselves. if we did that, we'd have to document the events to be * selected, and also update applications and embedding toolkits each * time we added a new mask, or a new class of events. * * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=998 * for the rationale of why we did conditional selection. it is now * clear that a compositor should clear out the input region, since * it cannot assume a perfectly clean slate coming from us. * * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=2228 * for an example of things that break if we do conditional event * selection. */ XSelectInput (backend_x11->xdpy, stage_x11->xwin, CLUTTER_STAGE_X11_EVENT_MASK); /* input events also depent on the actual device, so we need to * use the device manager to let every device select them, using * the event mask we passed to XSelectInput as the template */ device_manager = clutter_device_manager_get_default (); if (G_UNLIKELY (device_manager != NULL)) { _clutter_device_manager_select_stage_events (device_manager, stage_cogl->wrapper); g_signal_connect (device_manager, "device-added", G_CALLBACK (stage_events_device_added), stage_window); } clutter_stage_x11_fix_window_size (stage_x11, stage_x11->xwin_width, stage_x11->xwin_height); clutter_stage_x11_set_wm_protocols (stage_x11); if (stage_x11->fullscreen_on_realize) { stage_x11->fullscreen_on_realize = FALSE; clutter_stage_x11_set_fullscreen (stage_window, TRUE); } CLUTTER_NOTE (BACKEND, "Successfully realized stage"); return TRUE; } static void clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window, gboolean cursor_visible) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); stage_x11->is_cursor_visible = !!cursor_visible; set_cursor_visible (stage_x11); } static void clutter_stage_x11_set_title (ClutterStageWindow *stage_window, const gchar *title) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); free (stage_x11->title); stage_x11->title = g_strdup (title); set_wm_title (stage_x11); } static void clutter_stage_x11_set_user_resizable (ClutterStageWindow *stage_window, gboolean is_resizable) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); clutter_stage_x11_fix_window_size (stage_x11, stage_x11->xwin_width, stage_x11->xwin_height); } static inline void update_wm_hints (ClutterStageX11 *stage_x11) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); XWMHints wm_hints; if (stage_x11->wm_state & STAGE_X11_WITHDRAWN) return; if (stage_x11->is_foreign_xwin) return; wm_hints.flags = StateHint | InputHint; wm_hints.initial_state = NormalState; wm_hints.input = stage_x11->accept_focus ? True : False; XSetWMHints (backend_x11->xdpy, stage_x11->xwin, &wm_hints); } static void clutter_stage_x11_set_accept_focus (ClutterStageWindow *stage_window, gboolean accept_focus) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); stage_x11->accept_focus = !!accept_focus; update_wm_hints (stage_x11); } static void set_stage_x11_state (ClutterStageX11 *stage_x11, ClutterStageX11State unset_flags, ClutterStageX11State set_flags) { ClutterStageX11State new_stage_state, old_stage_state; old_stage_state = stage_x11->wm_state; new_stage_state = old_stage_state; new_stage_state |= set_flags; new_stage_state &= ~unset_flags; if (new_stage_state == old_stage_state) return; stage_x11->wm_state = new_stage_state; } static void clutter_stage_x11_show (ClutterStageWindow *stage_window, gboolean do_raise) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); if (stage_x11->xwin != None) { if (do_raise && !stage_x11->is_foreign_xwin) { CLUTTER_NOTE (BACKEND, "Raising stage[%lu]", (unsigned long) stage_x11->xwin); XRaiseWindow (backend_x11->xdpy, stage_x11->xwin); } if (!STAGE_X11_IS_MAPPED (stage_x11)) { CLUTTER_NOTE (BACKEND, "Mapping stage[%lu]", (unsigned long) stage_x11->xwin); set_stage_x11_state (stage_x11, STAGE_X11_WITHDRAWN, 0); update_wm_hints (stage_x11); if (stage_x11->fullscreening) clutter_stage_x11_set_fullscreen (stage_window, TRUE); else clutter_stage_x11_set_fullscreen (stage_window, FALSE); } g_assert (STAGE_X11_IS_MAPPED (stage_x11)); clutter_actor_map (CLUTTER_ACTOR (stage_cogl->wrapper)); if (!stage_x11->is_foreign_xwin) XMapWindow (backend_x11->xdpy, stage_x11->xwin); } } static void clutter_stage_x11_hide (ClutterStageWindow *stage_window) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); if (stage_x11->xwin != None) { if (STAGE_X11_IS_MAPPED (stage_x11)) set_stage_x11_state (stage_x11, 0, STAGE_X11_WITHDRAWN); g_assert (!STAGE_X11_IS_MAPPED (stage_x11)); clutter_actor_unmap (CLUTTER_ACTOR (stage_cogl->wrapper)); if (!stage_x11->is_foreign_xwin) XWithdrawWindow (backend_x11->xdpy, stage_x11->xwin, 0); } } static gboolean clutter_stage_x11_can_clip_redraws (ClutterStageWindow *stage_window) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); /* while resizing a window, clipped redraws are disabled in order to * avoid artefacts. */ return stage_x11->clipped_redraws_cool_off == 0; } static void ensure_legacy_view (ClutterStageWindow *stage_window) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); cairo_rectangle_int_t view_layout; CoglFramebuffer *framebuffer; if (stage_x11->legacy_view) return; _clutter_stage_window_get_geometry (stage_window, &view_layout); framebuffer = COGL_FRAMEBUFFER (stage_x11->onscreen); stage_x11->legacy_view = g_object_new (CLUTTER_TYPE_STAGE_VIEW_COGL, "layout", &view_layout, "framebuffer", framebuffer, NULL); stage_x11->legacy_views = g_list_append (stage_x11->legacy_views, stage_x11->legacy_view); } static GList * clutter_stage_x11_get_views (ClutterStageWindow *stage_window) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ensure_legacy_view (stage_window); return stage_x11->legacy_views; } static int64_t clutter_stage_x11_get_frame_counter (ClutterStageWindow *stage_window) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); return cogl_onscreen_get_frame_counter (stage_x11->onscreen); } static void clutter_stage_x11_finalize (GObject *gobject) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject); free (stage_x11->title); G_OBJECT_CLASS (clutter_stage_x11_parent_class)->finalize (gobject); } static void clutter_stage_x11_dispose (GObject *gobject) { ClutterEventTranslator *translator = CLUTTER_EVENT_TRANSLATOR (gobject); ClutterBackend *backend = CLUTTER_STAGE_COGL (gobject)->backend; _clutter_backend_remove_event_translator (backend, translator); G_OBJECT_CLASS (clutter_stage_x11_parent_class)->dispose (gobject); } static void clutter_stage_x11_class_init (ClutterStageX11Class *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = clutter_stage_x11_finalize; gobject_class->dispose = clutter_stage_x11_dispose; } static void clutter_stage_x11_init (ClutterStageX11 *stage) { stage->xwin = None; stage->xwin_width = 640; stage->xwin_height = 480; stage->wm_state = STAGE_X11_WITHDRAWN; stage->is_foreign_xwin = FALSE; stage->fullscreening = FALSE; stage->is_cursor_visible = TRUE; stage->accept_focus = TRUE; stage->title = NULL; } static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface) { clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface); iface->set_title = clutter_stage_x11_set_title; iface->set_fullscreen = clutter_stage_x11_set_fullscreen; iface->set_cursor_visible = clutter_stage_x11_set_cursor_visible; iface->set_user_resizable = clutter_stage_x11_set_user_resizable; iface->set_accept_focus = clutter_stage_x11_set_accept_focus; iface->show = clutter_stage_x11_show; iface->hide = clutter_stage_x11_hide; iface->resize = clutter_stage_x11_resize; iface->get_geometry = clutter_stage_x11_get_geometry; iface->realize = clutter_stage_x11_realize; iface->unrealize = clutter_stage_x11_unrealize; iface->can_clip_redraws = clutter_stage_x11_can_clip_redraws; iface->get_views = clutter_stage_x11_get_views; iface->get_frame_counter = clutter_stage_x11_get_frame_counter; } static inline void set_user_time (ClutterBackendX11 *backend_x11, ClutterStageX11 *stage_x11, long timestamp) { if (timestamp != CLUTTER_CURRENT_TIME) { XChangeProperty (backend_x11->xdpy, stage_x11->xwin, backend_x11->atom_NET_WM_USER_TIME, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) ×tamp, 1); } } static gboolean handle_wm_protocols_event (ClutterBackendX11 *backend_x11, ClutterStageX11 *stage_x11, XEvent *xevent) { Atom atom = (Atom) xevent->xclient.data.l[0]; if (atom == backend_x11->atom_WM_DELETE_WINDOW && xevent->xany.window == stage_x11->xwin) { #ifdef CLUTTER_ENABLE_DEBUG ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); /* the WM_DELETE_WINDOW is a request: we do not destroy * the window right away, as it might contain vital data; * we relay the event to the application and we let it * handle the request */ CLUTTER_NOTE (EVENT, "Delete stage %s[%p], win:0x%x", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage_cogl->wrapper)), stage_cogl->wrapper, (unsigned int) stage_x11->xwin); #endif /* CLUTTER_ENABLE_DEBUG */ set_user_time (backend_x11, stage_x11, xevent->xclient.data.l[1]); return TRUE; } else if (atom == backend_x11->atom_NET_WM_PING && xevent->xany.window == stage_x11->xwin) { XClientMessageEvent xclient = xevent->xclient; xclient.window = backend_x11->xwin_root; XSendEvent (backend_x11->xdpy, xclient.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *) &xclient); return FALSE; } /* do not send any of the WM_PROTOCOLS events to the queue */ return FALSE; } static gboolean clipped_redraws_cool_off_cb (void *data) { ClutterStageX11 *stage_x11 = data; stage_x11->clipped_redraws_cool_off = 0; return G_SOURCE_REMOVE; } static ClutterTranslateReturn clutter_stage_x11_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *event) { ClutterStageX11 *stage_x11; ClutterStageCogl *stage_cogl; ClutterTranslateReturn res = CLUTTER_TRANSLATE_CONTINUE; ClutterBackendX11 *backend_x11; Window stage_xwindow; XEvent *xevent = native; ClutterStage *stage; stage_cogl = clutter_x11_get_stage_window_from_window (xevent->xany.window); if (stage_cogl == NULL) return CLUTTER_TRANSLATE_CONTINUE; stage = stage_cogl->wrapper; stage_x11 = CLUTTER_STAGE_X11 (stage_cogl); backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); stage_xwindow = stage_x11->xwin; switch (xevent->type) { case ConfigureNotify: if (!stage_x11->is_foreign_xwin) { gboolean size_changed = FALSE; int stage_width; int stage_height; CLUTTER_NOTE (BACKEND, "ConfigureNotify[%x] (%d, %d)", (unsigned int) stage_x11->xwin, xevent->xconfigure.width, xevent->xconfigure.height); /* When fullscreen, we'll keep the xwin_width/height variables to track the old size of the window and we'll assume all ConfigureNotifies constitute a size change */ if (_clutter_stage_is_fullscreen (stage)) size_changed = TRUE; else if ((stage_x11->xwin_width != xevent->xconfigure.width) || (stage_x11->xwin_height != xevent->xconfigure.height)) { size_changed = TRUE; stage_x11->xwin_width = xevent->xconfigure.width; stage_x11->xwin_height = xevent->xconfigure.height; } stage_width = xevent->xconfigure.width; stage_height = xevent->xconfigure.height; clutter_actor_set_size (CLUTTER_ACTOR (stage), stage_width, stage_height); if (size_changed) { /* XXX: This is a workaround for a race condition when * resizing windows while there are in-flight * glXCopySubBuffer blits happening. * * The problem stems from the fact that rectangles for the * blits are described relative to the bottom left of the * window and because we can't guarantee control over the X * window gravity used when resizing so the gravity is * typically NorthWest not SouthWest. * * This means if you grow a window vertically the server * will make sure to place the old contents of the window * at the top-left/north-west of your new larger window, but * that may happen asynchronous to GLX preparing to do a * blit specified relative to the bottom-left/south-west of * the window (based on the old smaller window geometry). * * When the GLX issued blit finally happens relative to the * new bottom of your window, the destination will have * shifted relative to the top-left where all the pixels you * care about are so it will result in a nasty artefact * making resizing look very ugly! * * We can't currently fix this completely, in-part because * the window manager tends to trample any gravity we might * set. This workaround instead simply disables blits for a * while if we are notified of any resizes happening so if * the user is resizing a window via the window manager then * they may see an artefact for one frame but then we will * fallback to redrawing the full stage until the cooling * off period is over. */ if (stage_x11->clipped_redraws_cool_off) g_source_remove (stage_x11->clipped_redraws_cool_off); stage_x11->clipped_redraws_cool_off = clutter_threads_add_timeout (1000, clipped_redraws_cool_off_cb, stage_x11); /* Queue a relayout - we want glViewport to be called * with the correct values, and this is done in ClutterStage * via cogl_onscreen_clutter_backend_set_size (). * * We queue a relayout, because if this ConfigureNotify is * in response to a size we set in the application, the * set_size() call above is essentially a null-op. * * Make sure we do this only when the size has changed, * otherwise we end up relayouting on window moves. */ clutter_actor_queue_relayout (CLUTTER_ACTOR (stage)); /* the resize process is complete, so we can ask the stage * to set up the GL viewport with the new size */ clutter_stage_ensure_viewport (stage); /* If this was a result of the Xrandr change when running as a * X11 compositing manager, we need to reset the legacy * stage view, now that it has a new size. */ if (stage_x11->legacy_view) { cairo_rectangle_int_t view_layout = { .width = stage_width, .height = stage_height }; g_object_set (G_OBJECT (stage_x11->legacy_view), "layout", &view_layout, NULL); } } } break; case PropertyNotify: if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE && xevent->xproperty.window == stage_xwindow && !stage_x11->is_foreign_xwin) { Atom type; gint format; gulong n_items, bytes_after; guchar *data = NULL; gboolean fullscreen_set = FALSE; clutter_x11_trap_x_errors (); XGetWindowProperty (backend_x11->xdpy, stage_xwindow, backend_x11->atom_NET_WM_STATE, 0, G_MAXLONG, False, XA_ATOM, &type, &format, &n_items, &bytes_after, &data); clutter_x11_untrap_x_errors (); if (type != None && data != NULL) { gboolean is_fullscreen = FALSE; Atom *atoms = (Atom *) data; gulong i; for (i = 0; i < n_items; i++) { if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN) fullscreen_set = TRUE; } is_fullscreen = _clutter_stage_is_fullscreen (stage_cogl->wrapper); if (fullscreen_set != is_fullscreen) { if (fullscreen_set) _clutter_stage_update_state (stage_cogl->wrapper, 0, CLUTTER_STAGE_STATE_FULLSCREEN); else _clutter_stage_update_state (stage_cogl->wrapper, CLUTTER_STAGE_STATE_FULLSCREEN, 0); } XFree (data); } } break; case FocusIn: if (!_clutter_stage_is_activated (stage_cogl->wrapper)) { _clutter_stage_update_state (stage_cogl->wrapper, 0, CLUTTER_STAGE_STATE_ACTIVATED); } break; case FocusOut: if (_clutter_stage_is_activated (stage_cogl->wrapper)) { _clutter_stage_update_state (stage_cogl->wrapper, CLUTTER_STAGE_STATE_ACTIVATED, 0); } break; case Expose: { XExposeEvent *expose = (XExposeEvent *) xevent; cairo_rectangle_int_t clip; CLUTTER_NOTE (EVENT, "expose for stage: %s[%p], win:0x%x - " "redrawing area (x: %d, y: %d, width: %d, height: %d)", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), stage, (unsigned int) stage_xwindow, expose->x, expose->y, expose->width, expose->height); clip.x = expose->x; clip.y = expose->y; clip.width = expose->width; clip.height = expose->height; clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip); } break; case DestroyNotify: CLUTTER_NOTE (EVENT, "Destroy notification received for stage %s[%p], win:0x%x", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), stage, (unsigned int) stage_xwindow); event->any.type = CLUTTER_DESTROY_NOTIFY; event->any.stage = stage; res = CLUTTER_TRANSLATE_QUEUE; break; case ClientMessage: CLUTTER_NOTE (EVENT, "Client message for stage %s[%p], win:0x%x", _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)), stage, (unsigned int) stage_xwindow); if (handle_wm_protocols_event (backend_x11, stage_x11, xevent)) { event->any.type = CLUTTER_DELETE; event->any.stage = stage; res = CLUTTER_TRANSLATE_QUEUE; } break; case MappingNotify: CLUTTER_NOTE (EVENT, "Refresh keyboard mapping"); XRefreshKeyboardMapping (&xevent->xmapping); backend_x11->keymap_serial += 1; res = CLUTTER_TRANSLATE_REMOVE; break; default: res = CLUTTER_TRANSLATE_CONTINUE; break; } return res; } static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface) { iface->translate_event = clutter_stage_x11_translate_event; } /** * clutter_x11_get_stage_window: (skip) * @stage: a #ClutterStage * * Gets the stages X Window. * * Return value: An XID for the stage window. * * Since: 0.4 */ Window clutter_x11_get_stage_window (ClutterStage *stage) { ClutterStageWindow *impl; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), None); impl = _clutter_stage_get_window (stage); g_assert (CLUTTER_IS_STAGE_X11 (impl)); return CLUTTER_STAGE_X11 (impl)->xwin; } static ClutterStageCogl * clutter_x11_get_stage_window_from_window (Window win) { if (clutter_stages_by_xid == NULL) return NULL; return g_hash_table_lookup (clutter_stages_by_xid, GINT_TO_POINTER (win)); } /** * clutter_x11_get_stage_from_window: * @win: an X Window ID * * Gets the stage for a particular X window. * * Return value: (transfer none): A #ClutterStage, or% NULL if a stage * does not exist for the window * * Since: 0.8 */ ClutterStage * clutter_x11_get_stage_from_window (Window win) { ClutterStageCogl *stage_cogl; stage_cogl = clutter_x11_get_stage_window_from_window (win); if (stage_cogl != NULL) return stage_cogl->wrapper; return NULL; } /** * clutter_x11_get_stage_visual: (skip) * @stage: a #ClutterStage * * Returns an XVisualInfo suitable for creating a foreign window for the given * stage. NOTE: It doesn't do as the name may suggest, which is return the * XVisualInfo that was used to create an existing window for the given stage. * * XXX: It might be best to deprecate this function and replace with something * along the lines of clutter_backend_x11_get_foreign_visual () or perhaps * clutter_stage_x11_get_foreign_visual () * * Return value: (transfer full): An XVisualInfo suitable for creating a * foreign stage. Use XFree() to free the returned value instead * * Deprecated: 1.2: Use clutter_x11_get_visual_info() instead * * Since: 0.4 */ XVisualInfo * clutter_x11_get_stage_visual (ClutterStage *stage) { ClutterBackend *backend = clutter_get_default_backend (); ClutterBackendX11 *backend_x11; g_return_val_if_fail (CLUTTER_IS_BACKEND_X11 (backend), NULL); backend_x11 = CLUTTER_BACKEND_X11 (backend); return _clutter_backend_x11_get_visual_info (backend_x11); } typedef struct { ClutterStageX11 *stage_x11; cairo_rectangle_int_t geom; Window xwindow; guint destroy_old_xwindow : 1; } ForeignWindowData; static void set_foreign_window_callback (ClutterActor *actor, void *data) { ForeignWindowData *fwd = data; ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (fwd->stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)", (unsigned int) fwd->xwindow); if (fwd->destroy_old_xwindow && fwd->stage_x11->xwin != None) { CLUTTER_NOTE (BACKEND, "Destroying previous window (0x%x)", (unsigned int) fwd->xwindow); XDestroyWindow (backend_x11->xdpy, fwd->stage_x11->xwin); } fwd->stage_x11->xwin = fwd->xwindow; fwd->stage_x11->is_foreign_xwin = TRUE; fwd->stage_x11->xwin_width = fwd->geom.width; fwd->stage_x11->xwin_height = fwd->geom.height; clutter_actor_set_size (actor, fwd->geom.width, fwd->geom.height); if (clutter_stages_by_xid == NULL) clutter_stages_by_xid = g_hash_table_new (NULL, NULL); g_hash_table_insert (clutter_stages_by_xid, GINT_TO_POINTER (fwd->stage_x11->xwin), fwd->stage_x11); } /** * clutter_x11_set_stage_foreign: * @stage: a #ClutterStage * @xwindow: an existing X Window id * * Target the #ClutterStage to use an existing external X Window * * Return value: %TRUE if foreign window is valid * * Since: 0.4 */ gboolean clutter_x11_set_stage_foreign (ClutterStage *stage, Window xwindow) { ClutterBackendX11 *backend_x11; ClutterStageX11 *stage_x11; ClutterStageCogl *stage_cogl; ClutterStageWindow *impl; ClutterActor *actor; gint x, y; guint width, height, border, depth; Window root_return; Status status; ForeignWindowData fwd; XVisualInfo *xvisinfo; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (!CLUTTER_ACTOR_IN_DESTRUCTION (stage), FALSE); g_return_val_if_fail (xwindow != None, FALSE); impl = _clutter_stage_get_window (stage); stage_x11 = CLUTTER_STAGE_X11 (impl); stage_cogl = CLUTTER_STAGE_COGL (impl); backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); xvisinfo = _clutter_backend_x11_get_visual_info (backend_x11); g_return_val_if_fail (xvisinfo != NULL, FALSE); clutter_x11_trap_x_errors (); status = XGetGeometry (backend_x11->xdpy, xwindow, &root_return, &x, &y, &width, &height, &border, &depth); if (clutter_x11_untrap_x_errors () || !status) { g_critical ("Unable to retrieve the geometry of the foreign window: " "XGetGeometry() failed (status code: %d)", status); return FALSE; } if (width == 0 || height == 0) { g_warning ("The size of the foreign window is 0x0"); return FALSE; } if (depth != xvisinfo->depth) { g_warning ("The depth of the visual of the foreign window is %d, but " "Clutter has been initialized to require a visual depth " "of %d", depth, xvisinfo->depth); return FALSE; } fwd.stage_x11 = stage_x11; fwd.xwindow = xwindow; /* destroy the old Window, if we have one and it's ours */ if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin) fwd.destroy_old_xwindow = TRUE; else fwd.destroy_old_xwindow = FALSE; fwd.geom.x = x; fwd.geom.y = y; fwd.geom.width = width; fwd.geom.height = height; actor = CLUTTER_ACTOR (stage); _clutter_actor_rerealize (actor, set_foreign_window_callback, &fwd); /* Queue a relayout - so the stage will be allocated the new * window size. * * Note also that when the stage gets allocated the new * window size that will result in the stage's * priv->viewport being changed, which will in turn result * in the Cogl viewport changing when _clutter_do_redraw * calls _clutter_stage_maybe_setup_viewport(). */ clutter_actor_queue_relayout (actor); return TRUE; } void _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11, guint32 user_time) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); set_user_time (backend_x11, stage_x11, user_time); } �����������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-device-manager-xi2.c���������������������������������������0000664�0001750�0001750�00000205455�14211404421�024117� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #include "clutter-build-config.h" #include <stdint.h> #include "clutter-device-manager-xi2.h" #include "clutter-backend-x11.h" #include "clutter-input-device-xi2.h" #include "clutter-input-device-tool-xi2.h" #include "clutter-virtual-input-device-x11.h" #include "clutter-stage-x11.h" #include "clutter-backend.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-event-private.h" #include "clutter-event-translator.h" #include "clutter-stage-private.h" #include "clutter-private.h" #include "clutter-xkb-a11y-x11.h" #include <X11/extensions/XInput2.h> enum { PROP_0, PROP_OPCODE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static const char *clutter_input_axis_atom_names[] = { "Abs X", /* CLUTTER_INPUT_AXIS_X */ "Abs Y", /* CLUTTER_INPUT_AXIS_Y */ "Abs Pressure", /* CLUTTER_INPUT_AXIS_PRESSURE */ "Abs Tilt X", /* CLUTTER_INPUT_AXIS_XTILT */ "Abs Tilt Y", /* CLUTTER_INPUT_AXIS_YTILT */ "Abs Wheel", /* CLUTTER_INPUT_AXIS_WHEEL */ "Abs Distance", /* CLUTTER_INPUT_AXIS_DISTANCE */ }; #define N_AXIS_ATOMS G_N_ELEMENTS (clutter_input_axis_atom_names) enum { PAD_AXIS_FIRST = 3, /* First axes are always x/y/pressure, ignored in pads */ PAD_AXIS_STRIP1 = PAD_AXIS_FIRST, PAD_AXIS_STRIP2, PAD_AXIS_RING1, PAD_AXIS_RING2, }; static Atom clutter_input_axis_atoms[N_AXIS_ATOMS] = { 0, }; static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface); static void clutter_event_extender_iface_init (ClutterEventExtenderInterface *iface); #define clutter_device_manager_xi2_get_type _clutter_device_manager_xi2_get_type G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerXI2, clutter_device_manager_xi2, CLUTTER_TYPE_DEVICE_MANAGER, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR, clutter_event_translator_iface_init) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_EXTENDER, clutter_event_extender_iface_init)) static void clutter_device_manager_x11_copy_event_data (ClutterEventExtender *event_extender, const ClutterEvent *src, ClutterEvent *dest) { gpointer event_x11; event_x11 = _clutter_event_get_platform_data (src); if (event_x11 != NULL) _clutter_event_set_platform_data (dest, _clutter_event_x11_copy (event_x11)); } static void clutter_device_manager_x11_free_event_data (ClutterEventExtender *event_extender, ClutterEvent *event) { gpointer event_x11; event_x11 = _clutter_event_get_platform_data (event); if (event_x11 != NULL) _clutter_event_x11_free (event_x11); } static void clutter_event_extender_iface_init (ClutterEventExtenderInterface *iface) { iface->copy_event_data = clutter_device_manager_x11_copy_event_data; iface->free_event_data = clutter_device_manager_x11_free_event_data; } static void translate_valuator_class (Display *xdisplay, ClutterInputDevice *device, XIValuatorClassInfo *class) { static gboolean atoms_initialized = FALSE; ClutterInputAxis i, axis = CLUTTER_INPUT_AXIS_IGNORE; if (G_UNLIKELY (!atoms_initialized)) { XInternAtoms (xdisplay, (char **) clutter_input_axis_atom_names, N_AXIS_ATOMS, False, clutter_input_axis_atoms); atoms_initialized = TRUE; } for (i = 0; i < N_AXIS_ATOMS; i += 1) { if (clutter_input_axis_atoms[i] == class->label) { axis = i + 1; break; } } _clutter_input_device_add_axis (device, axis, class->min, class->max, class->resolution); CLUTTER_NOTE (BACKEND, "Added axis '%s' (min:%.2f, max:%.2fd, res:%d) of device %d", clutter_input_axis_atom_names[axis], class->min, class->max, class->resolution, device->id); } static void translate_device_classes (Display *xdisplay, ClutterInputDevice *device, XIAnyClassInfo **classes, guint n_classes) { gint i; for (i = 0; i < n_classes; i++) { XIAnyClassInfo *class_info = classes[i]; switch (class_info->type) { case XIKeyClass: { XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info; gint j; _clutter_input_device_set_n_keys (device, key_info->num_keycodes); for (j = 0; j < key_info->num_keycodes; j++) { clutter_input_device_set_key (device, j, key_info->keycodes[i], 0); } } break; case XIValuatorClass: translate_valuator_class (xdisplay, device, (XIValuatorClassInfo *) class_info); break; #ifdef HAVE_XINPUT_2_2 case XIScrollClass: { XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info; ClutterScrollDirection direction; if (scroll_info->scroll_type == XIScrollTypeVertical) direction = CLUTTER_SCROLL_DOWN; else direction = CLUTTER_SCROLL_RIGHT; CLUTTER_NOTE (BACKEND, "Scroll valuator %d: %s, increment: %f", scroll_info->number, scroll_info->scroll_type == XIScrollTypeVertical ? "vertical" : "horizontal", scroll_info->increment); _clutter_input_device_add_scroll_info (device, scroll_info->number, direction, scroll_info->increment); } break; #endif /* HAVE_XINPUT_2_2 */ default: break; } } } static gboolean is_touch_device (XIAnyClassInfo **classes, guint n_classes, ClutterInputDeviceType *device_type, guint *n_touch_points) { #ifdef HAVE_XINPUT_2_2 guint i; for (i = 0; i < n_classes; i++) { XITouchClassInfo *class = (XITouchClassInfo *) classes[i]; if (class->type != XITouchClass) continue; if (class->num_touches > 0) { if (class->mode == XIDirectTouch) *device_type = CLUTTER_TOUCHSCREEN_DEVICE; else if (class->mode == XIDependentTouch) *device_type = CLUTTER_TOUCHPAD_DEVICE; else continue; *n_touch_points = class->num_touches; return TRUE; } } #endif return FALSE; } static gboolean is_touchpad_device (ClutterBackendX11 *backend_x11, XIDeviceInfo *info) { gulong nitems, bytes_after; guint32 *data = NULL; int rc, format; Atom type; Atom prop; prop = XInternAtom (backend_x11->xdpy, "libinput Tapping Enabled", True); if (prop == None) return FALSE; clutter_x11_trap_x_errors (); rc = XIGetProperty (backend_x11->xdpy, info->deviceid, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, (guchar **) &data); clutter_x11_untrap_x_errors (); /* We don't care about the data */ XFree (data); if (rc != Success || type != XA_INTEGER || format != 8 || nitems != 1) return FALSE; return TRUE; } static gboolean get_device_ids (ClutterBackendX11 *backend_x11, XIDeviceInfo *info, gchar **vendor_id, gchar **product_id) { gulong nitems, bytes_after; guint32 *data = NULL; int rc, format; Atom type; clutter_x11_trap_x_errors (); rc = XIGetProperty (backend_x11->xdpy, info->deviceid, XInternAtom (backend_x11->xdpy, "Device Product ID", False), 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, (guchar **) &data); clutter_x11_untrap_x_errors (); if (rc != Success || type != XA_INTEGER || format != 32 || nitems != 2) { XFree (data); return FALSE; } if (vendor_id) *vendor_id = g_strdup_printf ("%.4x", data[0]); if (product_id) *product_id = g_strdup_printf ("%.4x", data[1]); XFree (data); return TRUE; } static gchar * get_device_node_path (ClutterBackendX11 *backend_x11, XIDeviceInfo *info) { gulong nitems, bytes_after; guchar *data; int rc, format; Atom prop, type; gchar *node_path; prop = XInternAtom (backend_x11->xdpy, "Device Node", False); if (prop == None) return NULL; clutter_x11_trap_x_errors (); rc = XIGetProperty (backend_x11->xdpy, info->deviceid, prop, 0, 1024, False, XA_STRING, &type, &format, &nitems, &bytes_after, (guchar **) &data); if (clutter_x11_untrap_x_errors ()) return NULL; if (rc != Success || type != XA_STRING || format != 8) { XFree (data); return FALSE; } node_path = g_strdup ((char *) data); XFree (data); return node_path; } static void get_pad_features (XIDeviceInfo *info, guint *n_rings, guint *n_strips) { gint i, rings = 0, strips = 0; for (i = PAD_AXIS_FIRST; i < info->num_classes; i++) { XIValuatorClassInfo *valuator = (XIValuatorClassInfo*) info->classes[i]; int axis = valuator->number; if (valuator->type != XIValuatorClass) continue; if (valuator->max <= 1) continue; /* Ring/strip axes are fixed in pad devices as handled by the * wacom driver. Match those to detect pad features. */ if (axis == PAD_AXIS_STRIP1 || axis == PAD_AXIS_STRIP2) strips++; else if (axis == PAD_AXIS_RING1 || axis == PAD_AXIS_RING2) rings++; } *n_rings = rings; *n_strips = strips; } static ClutterInputDevice * create_device (ClutterDeviceManagerXI2 *manager_xi2, ClutterBackendX11 *backend_x11, XIDeviceInfo *info) { ClutterInputDeviceType source, touch_source; ClutterInputDevice *retval; ClutterInputMode mode; gboolean is_enabled; guint num_touches = 0, num_rings = 0, num_strips = 0; gchar *vendor_id = NULL, *product_id = NULL, *node_path = NULL; if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard) { source = CLUTTER_KEYBOARD_DEVICE; } else if (is_touchpad_device (backend_x11, info)) { source = CLUTTER_TOUCHPAD_DEVICE; } else if (info->use == XISlavePointer && is_touch_device (info->classes, info->num_classes, &touch_source, &num_touches)) { source = touch_source; } else { gchar *name; name = g_ascii_strdown (info->name, -1); if (strstr (name, "eraser") != NULL) source = CLUTTER_ERASER_DEVICE; else if (strstr (name, "cursor") != NULL) source = CLUTTER_CURSOR_DEVICE; else if (strstr (name, " pad") != NULL) source = CLUTTER_PAD_DEVICE; else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL) source = CLUTTER_PEN_DEVICE; else if (strstr (name, "touchpad") != NULL) source = CLUTTER_TOUCHPAD_DEVICE; else source = CLUTTER_POINTER_DEVICE; free (name); } switch (info->use) { case XIMasterKeyboard: case XIMasterPointer: mode = CLUTTER_INPUT_MODE_MASTER; is_enabled = TRUE; break; case XISlaveKeyboard: case XISlavePointer: mode = CLUTTER_INPUT_MODE_SLAVE; is_enabled = FALSE; break; case XIFloatingSlave: default: mode = CLUTTER_INPUT_MODE_FLOATING; is_enabled = FALSE; break; } if (info->use != XIMasterKeyboard && info->use != XIMasterPointer) { get_device_ids (backend_x11, info, &vendor_id, &product_id); node_path = get_device_node_path (backend_x11, info); } if (source == CLUTTER_PAD_DEVICE) { is_enabled = TRUE; get_pad_features (info, &num_rings, &num_strips); } retval = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_XI2, "name", info->name, "id", info->deviceid, "has-cursor", (info->use == XIMasterPointer), "device-manager", manager_xi2, "device-type", source, "device-mode", mode, "backend", backend_x11, "enabled", is_enabled, "vendor-id", vendor_id, "product-id", product_id, "device-node", node_path, "n-rings", num_rings, "n-strips", num_strips, "n-mode-groups", MAX (num_rings, num_strips), NULL); translate_device_classes (backend_x11->xdpy, retval, info->classes, info->num_classes); #ifdef HAVE_LIBWACOM if (source == CLUTTER_PAD_DEVICE) clutter_input_device_xi2_ensure_wacom_info (retval, manager_xi2->wacom_db); #endif free (vendor_id); free (product_id); free (node_path); CLUTTER_NOTE (BACKEND, "Created device '%s' (id: %d, has-cursor: %s)", info->name, info->deviceid, info->use == XIMasterPointer ? "yes" : "no"); return retval; } static void pad_passive_button_grab (ClutterInputDevice *device) { XIGrabModifiers xi_grab_mods = { XIAnyModifier, }; XIEventMask xi_event_mask; gint device_id, rc; device_id = clutter_input_device_get_device_id (device); xi_event_mask.deviceid = device_id; xi_event_mask.mask_len = XIMaskLen (XI_LASTEVENT); xi_event_mask.mask = g_new0 (unsigned char, xi_event_mask.mask_len); XISetMask (xi_event_mask.mask, XI_Motion); XISetMask (xi_event_mask.mask, XI_ButtonPress); XISetMask (xi_event_mask.mask, XI_ButtonRelease); clutter_x11_trap_x_errors (); rc = XIGrabButton (clutter_x11_get_default_display (), device_id, XIAnyButton, clutter_x11_get_root_window (), None, XIGrabModeSync, XIGrabModeSync, True, &xi_event_mask, 1, &xi_grab_mods); if (rc != 0) { g_warning ("Could not passively grab pad device: %s", clutter_input_device_get_device_name (device)); } else { XIAllowEvents (clutter_x11_get_default_display (), device_id, XIAsyncDevice, CLUTTER_CURRENT_TIME); } clutter_x11_untrap_x_errors (); free (xi_event_mask.mask); } static ClutterInputDevice * add_device (ClutterDeviceManagerXI2 *manager_xi2, ClutterBackendX11 *backend_x11, XIDeviceInfo *info, gboolean in_construction) { ClutterInputDevice *device; device = create_device (manager_xi2, backend_x11, info); /* we don't go through the DeviceManager::add_device() vfunc because * that emits the signal, and we only do it conditionally */ g_hash_table_replace (manager_xi2->devices_by_id, GINT_TO_POINTER (info->deviceid), device); if (info->use == XIMasterPointer || info->use == XIMasterKeyboard) { manager_xi2->master_devices = g_list_prepend (manager_xi2->master_devices, device); } else if (info->use == XISlavePointer || info->use == XISlaveKeyboard || info->use == XIFloatingSlave) { manager_xi2->slave_devices = g_list_prepend (manager_xi2->slave_devices, device); } else g_warning ("Unhandled device: %s", clutter_input_device_get_device_name (device)); if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE) pad_passive_button_grab (device); /* relationships between devices and signal emissions are not * necessary while we're constructing the device manager instance */ if (!in_construction) { if (info->use == XISlavePointer || info->use == XISlaveKeyboard) { ClutterInputDevice *master; master = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (info->attachment)); _clutter_input_device_set_associated_device (device, master); _clutter_input_device_add_slave (master, device); } /* blow the cache */ g_slist_free (manager_xi2->all_devices); manager_xi2->all_devices = NULL; g_signal_emit_by_name (manager_xi2, "device-added", device); } return device; } static void remove_device (ClutterDeviceManagerXI2 *manager_xi2, gint device_id) { ClutterInputDevice *device; device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (device_id)); if (device != NULL) { manager_xi2->master_devices = g_list_remove (manager_xi2->master_devices, device); manager_xi2->slave_devices = g_list_remove (manager_xi2->slave_devices, device); /* blow the cache */ g_slist_free (manager_xi2->all_devices); manager_xi2->all_devices = NULL; g_signal_emit_by_name (manager_xi2, "device-removed", device); g_object_run_dispose (G_OBJECT (device)); g_hash_table_remove (manager_xi2->devices_by_id, GINT_TO_POINTER (device_id)); } } static void translate_hierarchy_event (ClutterBackendX11 *backend_x11, ClutterDeviceManagerXI2 *manager_xi2, XIHierarchyEvent *ev) { int i; for (i = 0; i < ev->num_info; i++) { if (ev->info[i].flags & XIDeviceEnabled && !g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (ev->info[i].deviceid))) { XIDeviceInfo *info; int n_devices; CLUTTER_NOTE (EVENT, "Hierarchy event: device enabled"); clutter_x11_trap_x_errors (); info = XIQueryDevice (backend_x11->xdpy, ev->info[i].deviceid, &n_devices); clutter_x11_untrap_x_errors (); if (info != NULL) { add_device (manager_xi2, backend_x11, &info[0], FALSE); XIFreeDeviceInfo (info); } } else if (ev->info[i].flags & XIDeviceDisabled) { CLUTTER_NOTE (EVENT, "Hierarchy event: device disabled"); remove_device (manager_xi2, ev->info[i].deviceid); } else if ((ev->info[i].flags & XISlaveAttached) || (ev->info[i].flags & XISlaveDetached)) { ClutterInputDevice *master, *slave; XIDeviceInfo *info; int n_devices; gboolean send_changed = FALSE; CLUTTER_NOTE (EVENT, "Hierarchy event: slave %s", (ev->info[i].flags & XISlaveAttached) ? "attached" : "detached"); slave = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (ev->info[i].deviceid)); master = clutter_input_device_get_associated_device (slave); /* detach the slave in both cases */ if (master != NULL) { _clutter_input_device_remove_slave (master, slave); _clutter_input_device_set_associated_device (slave, NULL); send_changed = TRUE; } /* and attach the slave to the new master if needed */ if (ev->info[i].flags & XISlaveAttached) { clutter_x11_trap_x_errors (); info = XIQueryDevice (backend_x11->xdpy, ev->info[i].deviceid, &n_devices); clutter_x11_untrap_x_errors (); if (info != NULL) { master = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (info->attachment)); if (master != NULL) { _clutter_input_device_set_associated_device (slave, master); _clutter_input_device_add_slave (master, slave); send_changed = TRUE; } XIFreeDeviceInfo (info); } } if (send_changed) { ClutterStage *stage = _clutter_input_device_get_stage (master); if (stage != NULL) _clutter_stage_x11_events_device_changed (CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage)), master, CLUTTER_DEVICE_MANAGER (manager_xi2)); } } } } static void clutter_device_manager_xi2_select_events (ClutterDeviceManager *manager, Window xwindow, XIEventMask *event_mask) { Display *xdisplay; xdisplay = clutter_x11_get_default_display (); XISelectEvents (xdisplay, xwindow, event_mask, 1); } static ClutterStage * get_event_stage (ClutterEventTranslator *translator, XIEvent *xi_event) { Window xwindow = None; switch (xi_event->evtype) { case XI_KeyPress: case XI_KeyRelease: case XI_ButtonPress: case XI_ButtonRelease: case XI_Motion: #ifdef HAVE_XINPUT_2_2 case XI_TouchBegin: case XI_TouchUpdate: case XI_TouchEnd: #endif /* HAVE_XINPUT_2_2 */ { XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; xwindow = xev->event; } break; case XI_Enter: case XI_Leave: case XI_FocusIn: case XI_FocusOut: { XIEnterEvent *xev = (XIEnterEvent *) xi_event; xwindow = xev->event; } break; default: break; } if (xwindow == None) return NULL; return clutter_x11_get_stage_from_window (xwindow); } /* * print_key_sym: Translate a symbol to its printable form if any * @symbol: the symbol to translate * @buffer: the buffer where to put the translated string * @len: size of the buffer * * Translates @symbol into a printable representation in @buffer, if possible. * * Return value: The number of bytes of the translated string, 0 if the * symbol can't be printed * * Note: The code is derived from libX11's src/KeyBind.c * Copyright 1985, 1987, 1998 The Open Group * * Note: This code works for Latin-1 symbols. clutter_keysym_to_unicode() * does the work for the other keysyms. */ static int print_keysym (uint32_t symbol, char *buffer, int len) { unsigned long high_bytes; unsigned char c; high_bytes = symbol >> 8; if (!(len && ((high_bytes == 0) || ((high_bytes == 0xFF) && (((symbol >= CLUTTER_KEY_BackSpace) && (symbol <= CLUTTER_KEY_Clear)) || (symbol == CLUTTER_KEY_Return) || (symbol == CLUTTER_KEY_Escape) || (symbol == CLUTTER_KEY_KP_Space) || (symbol == CLUTTER_KEY_KP_Tab) || (symbol == CLUTTER_KEY_KP_Enter) || ((symbol >= CLUTTER_KEY_KP_Multiply) && (symbol <= CLUTTER_KEY_KP_9)) || (symbol == CLUTTER_KEY_KP_Equal) || (symbol == CLUTTER_KEY_Delete)))))) return 0; /* if X keysym, convert to ascii by grabbing low 7 bits */ if (symbol == CLUTTER_KEY_KP_Space) c = CLUTTER_KEY_space & 0x7F; /* patch encoding botch */ else if (high_bytes == 0xFF) c = symbol & 0x7F; else c = symbol & 0xFF; buffer[0] = c; return 1; } static gdouble * translate_axes (ClutterInputDevice *device, gdouble x, gdouble y, XIValuatorState *valuators) { guint n_axes = clutter_input_device_get_n_axes (device); guint i; gdouble *retval; double *values; retval = g_new0 (gdouble, n_axes); values = valuators->values; for (i = 0; i < valuators->mask_len * 8; i++) { ClutterInputAxis axis; gdouble val; if (!XIMaskIsSet (valuators->mask, i)) continue; axis = clutter_input_device_get_axis (device, i); val = *values++; switch (axis) { case CLUTTER_INPUT_AXIS_X: retval[i] = x; break; case CLUTTER_INPUT_AXIS_Y: retval[i] = y; break; default: _clutter_input_device_translate_axis (device, i, val, &retval[i]); break; } } return retval; } static gboolean translate_pad_axis (ClutterInputDevice *device, XIValuatorState *valuators, ClutterEventType *evtype, guint *number, gdouble *value) { double *values; gint i; values = valuators->values; for (i = PAD_AXIS_FIRST; i < valuators->mask_len * 8; i++) { gdouble val; guint axis_number = 0; if (!XIMaskIsSet (valuators->mask, i)) continue; val = *values++; if (val <= 0) continue; _clutter_input_device_translate_axis (device, i, val, value); if (i == PAD_AXIS_RING1 || i == PAD_AXIS_RING2) { *evtype = CLUTTER_PAD_RING; (*value) *= 360.0; } else if (i == PAD_AXIS_STRIP1 || i == PAD_AXIS_STRIP2) { *evtype = CLUTTER_PAD_STRIP; } else continue; if (i == PAD_AXIS_STRIP2 || i == PAD_AXIS_RING2) axis_number++; *number = axis_number; return TRUE; } return FALSE; } static void translate_coords (ClutterStageX11 *stage_x11, gdouble event_x, gdouble event_y, gfloat *x_out, gfloat *y_out) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterActor *stage = CLUTTER_ACTOR (stage_cogl->wrapper); gfloat stage_width; gfloat stage_height; clutter_actor_get_size (stage, &stage_width, &stage_height); *x_out = CLAMP (event_x, 0, stage_width); *y_out = CLAMP (event_y, 0, stage_height); } static gdouble scroll_valuators_changed (ClutterInputDevice *device, XIValuatorState *valuators, gdouble *dx_p, gdouble *dy_p) { gboolean retval = FALSE; guint n_axes, n_val, i; double *values; n_axes = clutter_input_device_get_n_axes (device); values = valuators->values; *dx_p = *dy_p = 0.0; n_val = 0; for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++) { ClutterScrollDirection direction; gdouble delta; if (!XIMaskIsSet (valuators->mask, i)) continue; if (_clutter_input_device_get_scroll_delta (device, i, values[n_val], &direction, &delta)) { retval = TRUE; if (direction == CLUTTER_SCROLL_UP || direction == CLUTTER_SCROLL_DOWN) *dy_p = delta; else *dx_p = delta; } n_val += 1; } return retval; } static void clutter_device_manager_xi2_select_stage_events (ClutterDeviceManager *manager, ClutterStage *stage) { ClutterBackendX11 *backend_x11; ClutterStageX11 *stage_x11; XIEventMask xi_event_mask; unsigned char *mask; int len; backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage)); len = XIMaskLen (XI_LASTEVENT); mask = g_new0 (unsigned char, len); XISetMask (mask, XI_Motion); XISetMask (mask, XI_ButtonPress); XISetMask (mask, XI_ButtonRelease); XISetMask (mask, XI_KeyPress); XISetMask (mask, XI_KeyRelease); XISetMask (mask, XI_Enter); XISetMask (mask, XI_Leave); #ifdef HAVE_XINPUT_2_2 /* enable touch event support if we're running on XInput 2.2 */ if (backend_x11->xi_minor >= 2) { XISetMask (mask, XI_TouchBegin); XISetMask (mask, XI_TouchUpdate); XISetMask (mask, XI_TouchEnd); } #endif /* HAVE_XINPUT_2_2 */ xi_event_mask.deviceid = XIAllMasterDevices; xi_event_mask.mask = mask; xi_event_mask.mask_len = len; XISelectEvents (backend_x11->xdpy, stage_x11->xwin, &xi_event_mask, 1); free (mask); } static guint device_get_tool_serial (ClutterBackendX11 *backend_x11, ClutterInputDevice *device) { gulong nitems, bytes_after; guint32 *data = NULL; guint serial_id = 0; int rc, format; Atom type; Atom prop; prop = XInternAtom (backend_x11->xdpy, "Wacom Serial IDs", True); if (prop == None) return 0; clutter_x11_trap_x_errors (); rc = XIGetProperty (backend_x11->xdpy, clutter_input_device_get_device_id (device), prop, 0, 4, FALSE, XA_INTEGER, &type, &format, &nitems, &bytes_after, (guchar **) &data); clutter_x11_untrap_x_errors (); if (rc == Success && type == XA_INTEGER && format == 32 && nitems >= 4) serial_id = data[3]; XFree (data); return serial_id; } static void handle_property_event (ClutterDeviceManagerXI2 *manager_xi2, XIEvent *event) { XIPropertyEvent *xev = (XIPropertyEvent *) event; ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); Atom serial_ids_prop = XInternAtom (backend_x11->xdpy, "Wacom Serial IDs", True); ClutterInputDevice *device; device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); if (!device) return; if (xev->property == serial_ids_prop) { ClutterInputDeviceTool *tool = NULL; ClutterInputDeviceToolType type; guint serial_id; serial_id = device_get_tool_serial (backend_x11, device); if (serial_id != 0) { tool = g_hash_table_lookup (manager_xi2->tools_by_serial, GUINT_TO_POINTER (serial_id)); if (!tool) { type = clutter_input_device_get_device_type (device) == CLUTTER_ERASER_DEVICE ? CLUTTER_INPUT_DEVICE_TOOL_ERASER : CLUTTER_INPUT_DEVICE_TOOL_PEN; tool = clutter_input_device_tool_xi2_new (serial_id, type); g_hash_table_insert (manager_xi2->tools_by_serial, GUINT_TO_POINTER (serial_id), tool); } } clutter_input_device_xi2_update_tool (device, tool); g_signal_emit_by_name (manager_xi2, "tool-changed", device, tool); } } static gboolean translate_pad_event (ClutterEvent *event, XIDeviceEvent *xev, ClutterInputDevice *device) { gdouble value; guint number, mode = 0; if (!translate_pad_axis (device, &xev->valuators, &event->any.type, &number, &value)) return FALSE; /* When touching a ring/strip a first XI_Motion event * is generated. Use it to reset the pad state, so * later events actually have a directionality. */ if (xev->evtype == XI_Motion) value = -1; #ifdef HAVE_LIBWACOM mode = clutter_input_device_xi2_get_pad_group_mode (device, number); #endif if (event->any.type == CLUTTER_PAD_RING) { event->pad_ring.ring_number = number; event->pad_ring.angle = value; event->pad_ring.mode = mode; } else { event->pad_strip.strip_number = number; event->pad_strip.value = value; event->pad_strip.mode = mode; } event->any.time = xev->time; clutter_event_set_device (event, device); clutter_event_set_source_device (event, device); CLUTTER_NOTE (EVENT, "%s: win:0x%x, device:%d '%s', time:%d " "(value:%f)", event->any.type == CLUTTER_PAD_RING ? "pad ring " : "pad strip", (unsigned int) xev->event, device->id, device->device_name, event->any.time, value); return TRUE; } static ClutterTranslateReturn clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *event) { ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (translator); ClutterTranslateReturn retval = CLUTTER_TRANSLATE_CONTINUE; ClutterBackendX11 *backend_x11; ClutterStageX11 *stage_x11 = NULL; ClutterStage *stage = NULL; ClutterInputDevice *device, *source_device; XGenericEventCookie *cookie; XIEvent *xi_event; XEvent *xevent; backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); xevent = native; cookie = &xevent->xcookie; if (cookie->type != GenericEvent || cookie->extension != manager_xi2->opcode) return CLUTTER_TRANSLATE_CONTINUE; xi_event = (XIEvent *) cookie->data; if (!xi_event) return CLUTTER_TRANSLATE_REMOVE; if (!(xi_event->evtype == XI_HierarchyChanged || xi_event->evtype == XI_DeviceChanged || xi_event->evtype == XI_PropertyEvent)) { stage = get_event_stage (translator, xi_event); if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return CLUTTER_TRANSLATE_CONTINUE; else stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage)); } event->any.stage = stage; switch (xi_event->evtype) { case XI_HierarchyChanged: { XIHierarchyEvent *xev = (XIHierarchyEvent *) xi_event; translate_hierarchy_event (backend_x11, manager_xi2, xev); } retval = CLUTTER_TRANSLATE_REMOVE; break; case XI_DeviceChanged: { XIDeviceChangedEvent *xev = (XIDeviceChangedEvent *) xi_event; device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); source_device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->sourceid)); if (device) { _clutter_input_device_reset_axes (device); translate_device_classes (backend_x11->xdpy, device, xev->classes, xev->num_classes); } if (source_device) _clutter_input_device_reset_scroll_info (source_device); } retval = CLUTTER_TRANSLATE_REMOVE; break; case XI_KeyPress: case XI_KeyRelease: { XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; ClutterEventX11 *event_x11; char buffer[7] = { 0, }; gunichar n; event->key.type = event->type = (xev->evtype == XI_KeyPress) ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE; event->key.time = xev->time; event->key.stage = stage; _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group); event->key.hardware_keycode = xev->detail; /* keyval is the key ignoring all modifiers ('1' vs. '!') */ event->key.keyval = _clutter_keymap_x11_translate_key_state (backend_x11->keymap, event->key.hardware_keycode, &event->key.modifier_state, NULL); /* KeyEvents have platform specific data associated to them */ event_x11 = _clutter_event_x11_new (); _clutter_event_set_platform_data (event, event_x11); event_x11->key_group = _clutter_keymap_x11_get_key_group (backend_x11->keymap, event->key.modifier_state); event_x11->key_is_modifier = _clutter_keymap_x11_get_is_modifier (backend_x11->keymap, event->key.hardware_keycode); event_x11->num_lock_set = _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap); event_x11->caps_lock_set = _clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap); source_device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->sourceid)); clutter_event_set_source_device (event, source_device); device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); clutter_event_set_device (event, device); /* XXX keep this in sync with the evdev device manager */ n = print_keysym (event->key.keyval, buffer, sizeof (buffer)); if (n == 0) { /* not printable */ event->key.unicode_value = (gunichar) '\0'; } else { event->key.unicode_value = g_utf8_get_char_validated (buffer, n); if (event->key.unicode_value == -1 || event->key.unicode_value == -2) event->key.unicode_value = (gunichar) '\0'; } CLUTTER_NOTE (EVENT, "%s: win:0x%x device:%d source:%d, key: %12s (%d)", event->any.type == CLUTTER_KEY_PRESS ? "key press " : "key release", (unsigned int) stage_x11->xwin, xev->deviceid, xev->sourceid, event->key.keyval ? buffer : "(none)", event->key.keyval); if (xi_event->evtype == XI_KeyPress) _clutter_stage_x11_set_user_time (stage_x11, event->key.time); retval = CLUTTER_TRANSLATE_QUEUE; } break; case XI_ButtonPress: case XI_ButtonRelease: { XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; source_device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->sourceid)); device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); /* Set the stage for core events coming out of nowhere (see bug #684509) */ if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER && clutter_input_device_get_pointer_stage (device) == NULL && stage != NULL) _clutter_input_device_set_stage (device, stage); if (clutter_input_device_get_device_type (source_device) == CLUTTER_PAD_DEVICE) { /* We got these events because of the passive button grab */ XIAllowEvents (clutter_x11_get_default_display (), xev->sourceid, XIAsyncDevice, xev->time); event->any.stage = stage; if (xev->detail >= 4 && xev->detail <= 7) { retval = CLUTTER_TRANSLATE_REMOVE; if (xi_event->evtype == XI_ButtonPress && translate_pad_event (event, xev, source_device)) retval = CLUTTER_TRANSLATE_QUEUE; break; } event->any.type = (xi_event->evtype == XI_ButtonPress) ? CLUTTER_PAD_BUTTON_PRESS : CLUTTER_PAD_BUTTON_RELEASE; event->any.time = xev->time; /* The 4-7 button range is taken as non-existent on pad devices, * let the buttons above that take over this range. */ if (xev->detail > 7) xev->detail -= 4; /* Pad buttons are 0-indexed */ event->pad_button.button = xev->detail - 1; #ifdef HAVE_LIBWACOM clutter_input_device_xi2_update_pad_state (device, event->pad_button.button, (xi_event->evtype == XI_ButtonPress), &event->pad_button.group, &event->pad_button.mode); #endif clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); CLUTTER_NOTE (EVENT, "%s: win:0x%x, device:%d '%s', time:%d " "(button:%d)", event->any.type == CLUTTER_BUTTON_PRESS ? "pad button press " : "pad button release", (unsigned int) stage_x11->xwin, device->id, device->device_name, event->any.time, event->pad_button.button); retval = CLUTTER_TRANSLATE_QUEUE; break; } switch (xev->detail) { case 4: case 5: case 6: case 7: /* we only generate Scroll events on ButtonPress */ if (xi_event->evtype == XI_ButtonRelease) return CLUTTER_TRANSLATE_REMOVE; event->scroll.type = event->type = CLUTTER_SCROLL; if (xev->detail == 4) event->scroll.direction = CLUTTER_SCROLL_UP; else if (xev->detail == 5) event->scroll.direction = CLUTTER_SCROLL_DOWN; else if (xev->detail == 6) event->scroll.direction = CLUTTER_SCROLL_LEFT; else event->scroll.direction = CLUTTER_SCROLL_RIGHT; event->scroll.stage = stage; event->scroll.time = xev->time; translate_coords (stage_x11, xev->event_x, xev->event_y, &event->scroll.x, &event->scroll.y); _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group); clutter_event_set_source_device (event, source_device); clutter_event_set_device (event, device); event->scroll.axes = translate_axes (event->scroll.device, event->scroll.x, event->scroll.y, &xev->valuators); CLUTTER_NOTE (EVENT, "scroll: win:0x%x, device:%d '%s', time:%d " "(direction:%s, " "x:%.2f, y:%.2f, " "emulated:%s)", (unsigned int) stage_x11->xwin, device->id, device->device_name, event->any.time, event->scroll.direction == CLUTTER_SCROLL_UP ? "up" : event->scroll.direction == CLUTTER_SCROLL_DOWN ? "down" : event->scroll.direction == CLUTTER_SCROLL_LEFT ? "left" : event->scroll.direction == CLUTTER_SCROLL_RIGHT ? "right" : "invalid", event->scroll.x, event->scroll.y, #ifdef HAVE_XINPUT_2_2 (xev->flags & XIPointerEmulated) ? "yes" : "no" #else "no" #endif ); break; default: event->button.type = event->type = (xi_event->evtype == XI_ButtonPress) ? CLUTTER_BUTTON_PRESS : CLUTTER_BUTTON_RELEASE; event->button.stage = stage; event->button.time = xev->time; translate_coords (stage_x11, xev->event_x, xev->event_y, &event->button.x, &event->button.y); event->button.button = xev->detail; _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group); clutter_event_set_source_device (event, source_device); clutter_event_set_device (event, device); clutter_event_set_device_tool (event, clutter_input_device_xi2_get_current_tool (source_device)); event->button.axes = translate_axes (event->button.device, event->button.x, event->button.y, &xev->valuators); CLUTTER_NOTE (EVENT, "%s: win:0x%x, device:%d '%s', time:%d " "(button:%d, " "x:%.2f, y:%.2f, " "axes:%s, " "emulated:%s)", event->any.type == CLUTTER_BUTTON_PRESS ? "button press " : "button release", (unsigned int) stage_x11->xwin, device->id, device->device_name, event->any.time, event->button.button, event->button.x, event->button.y, event->button.axes != NULL ? "yes" : "no", #ifdef HAVE_XINPUT_2_2 (xev->flags & XIPointerEmulated) ? "yes" : "no" #else "no" #endif ); break; } if (source_device != NULL && device->stage != NULL) _clutter_input_device_set_stage (source_device, device->stage); #ifdef HAVE_XINPUT_2_2 if (xev->flags & XIPointerEmulated) _clutter_event_set_pointer_emulated (event, TRUE); #endif /* HAVE_XINPUT_2_2 */ if (xi_event->evtype == XI_ButtonPress) _clutter_stage_x11_set_user_time (stage_x11, event->button.time); retval = CLUTTER_TRANSLATE_QUEUE; } break; case XI_Motion: { XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; gdouble delta_x, delta_y; source_device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->sourceid)); device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); if (clutter_input_device_get_device_type (source_device) == CLUTTER_PAD_DEVICE) { event->any.stage = stage; if (translate_pad_event (event, xev, source_device)) retval = CLUTTER_TRANSLATE_QUEUE; break; } /* Set the stage for core events coming out of nowhere (see bug #684509) */ if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER && clutter_input_device_get_pointer_stage (device) == NULL && stage != NULL) _clutter_input_device_set_stage (device, stage); if (scroll_valuators_changed (source_device, &xev->valuators, &delta_x, &delta_y)) { event->scroll.type = event->type = CLUTTER_SCROLL; event->scroll.direction = CLUTTER_SCROLL_SMOOTH; event->scroll.stage = stage; event->scroll.time = xev->time; translate_coords (stage_x11, xev->event_x, xev->event_y, &event->scroll.x, &event->scroll.y); _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group); clutter_event_set_scroll_delta (event, delta_x, delta_y); clutter_event_set_source_device (event, source_device); clutter_event_set_device (event, device); CLUTTER_NOTE (EVENT, "smooth scroll: win:0x%x device:%d '%s' (x:%.2f, y:%.2f, delta:%f, %f)", (unsigned int) stage_x11->xwin, event->scroll.device->id, event->scroll.device->device_name, event->scroll.x, event->scroll.y, delta_x, delta_y); retval = CLUTTER_TRANSLATE_QUEUE; break; } event->motion.type = event->type = CLUTTER_MOTION; event->motion.stage = stage; event->motion.time = xev->time; translate_coords (stage_x11, xev->event_x, xev->event_y, &event->motion.x, &event->motion.y); _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group); clutter_event_set_source_device (event, source_device); clutter_event_set_device (event, device); clutter_event_set_device_tool (event, clutter_input_device_xi2_get_current_tool (source_device)); event->motion.axes = translate_axes (event->motion.device, event->motion.x, event->motion.y, &xev->valuators); if (source_device != NULL && device->stage != NULL) _clutter_input_device_set_stage (source_device, device->stage); #ifdef HAVE_XINPUT_2_2 if (xev->flags & XIPointerEmulated) _clutter_event_set_pointer_emulated (event, TRUE); #endif /* HAVE_XINPUT_2_2 */ CLUTTER_NOTE (EVENT, "motion: win:0x%x device:%d '%s' (x:%.2f, y:%.2f, axes:%s)", (unsigned int) stage_x11->xwin, event->motion.device->id, event->motion.device->device_name, event->motion.x, event->motion.y, event->motion.axes != NULL ? "yes" : "no"); retval = CLUTTER_TRANSLATE_QUEUE; } break; #ifdef HAVE_XINPUT_2_2 case XI_TouchBegin: { XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); if (!_clutter_input_device_get_stage (device)) _clutter_input_device_set_stage (device, stage); } /* Fall through */ case XI_TouchEnd: { XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; source_device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->sourceid)); if (xi_event->evtype == XI_TouchBegin) event->touch.type = event->type = CLUTTER_TOUCH_BEGIN; else event->touch.type = event->type = CLUTTER_TOUCH_END; event->touch.stage = stage; event->touch.time = xev->time; translate_coords (stage_x11, xev->event_x, xev->event_y, &event->touch.x, &event->touch.y); _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group); clutter_event_set_source_device (event, source_device); device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); clutter_event_set_device (event, device); event->touch.axes = translate_axes (event->touch.device, event->motion.x, event->motion.y, &xev->valuators); if (xi_event->evtype == XI_TouchBegin) { event->touch.modifier_state |= CLUTTER_BUTTON1_MASK; _clutter_stage_x11_set_user_time (stage_x11, event->touch.time); } event->touch.sequence = GUINT_TO_POINTER (xev->detail); if (xev->flags & XITouchEmulatingPointer) _clutter_event_set_pointer_emulated (event, TRUE); CLUTTER_NOTE (EVENT, "touch %s: win:0x%x device:%d '%s' (seq:%d, x:%.2f, y:%.2f, axes:%s)", event->type == CLUTTER_TOUCH_BEGIN ? "begin" : "end", (unsigned int) stage_x11->xwin, event->touch.device->id, event->touch.device->device_name, GPOINTER_TO_UINT (event->touch.sequence), event->touch.x, event->touch.y, event->touch.axes != NULL ? "yes" : "no"); retval = CLUTTER_TRANSLATE_QUEUE; } break; case XI_TouchUpdate: { XIDeviceEvent *xev = (XIDeviceEvent *) xi_event; source_device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->sourceid)); event->touch.type = event->type = CLUTTER_TOUCH_UPDATE; event->touch.stage = stage; event->touch.time = xev->time; event->touch.sequence = GUINT_TO_POINTER (xev->detail); translate_coords (stage_x11, xev->event_x, xev->event_y, &event->touch.x, &event->touch.y); clutter_event_set_source_device (event, source_device); device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); clutter_event_set_device (event, device); event->touch.axes = translate_axes (event->touch.device, event->motion.x, event->motion.y, &xev->valuators); _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group); event->touch.modifier_state |= CLUTTER_BUTTON1_MASK; if (xev->flags & XITouchEmulatingPointer) _clutter_event_set_pointer_emulated (event, TRUE); CLUTTER_NOTE (EVENT, "touch update: win:0x%x device:%d '%s' (seq:%d, x:%.2f, y:%.2f, axes:%s)", (unsigned int) stage_x11->xwin, event->touch.device->id, event->touch.device->device_name, GPOINTER_TO_UINT (event->touch.sequence), event->touch.x, event->touch.y, event->touch.axes != NULL ? "yes" : "no"); retval = CLUTTER_TRANSLATE_QUEUE; } break; #endif /* HAVE_XINPUT_2_2 */ case XI_Enter: case XI_Leave: { XIEnterEvent *xev = (XIEnterEvent *) xi_event; device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->deviceid)); source_device = g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (xev->sourceid)); if (xi_event->evtype == XI_Enter) { event->crossing.type = event->type = CLUTTER_ENTER; event->crossing.stage = stage; event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.related = NULL; event->crossing.time = xev->time; translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y); _clutter_input_device_set_stage (device, stage); } else { if (device->stage == NULL) { CLUTTER_NOTE (EVENT, "Discarding Leave for ButtonRelease " "event off-stage"); retval = CLUTTER_TRANSLATE_REMOVE; break; } event->crossing.type = event->type = CLUTTER_LEAVE; event->crossing.stage = stage; event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.related = NULL; event->crossing.time = xev->time; translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y); _clutter_input_device_set_stage (device, NULL); } _clutter_input_device_reset_scroll_info (source_device); clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); retval = CLUTTER_TRANSLATE_QUEUE; } break; case XI_FocusIn: case XI_FocusOut: retval = CLUTTER_TRANSLATE_CONTINUE; break; case XI_PropertyEvent: handle_property_event (manager_xi2, xi_event); retval = CLUTTER_TRANSLATE_CONTINUE; break; } return retval; } static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface) { iface->translate_event = clutter_device_manager_xi2_translate_event; } static void clutter_device_manager_xi2_add_device (ClutterDeviceManager *manager, ClutterInputDevice *device) { /* XXX implement */ } static void clutter_device_manager_xi2_remove_device (ClutterDeviceManager *manager, ClutterInputDevice *device) { /* XXX implement */ } static const GSList * clutter_device_manager_xi2_get_devices (ClutterDeviceManager *manager) { ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager); GSList *all_devices = NULL; GList *l; if (manager_xi2->all_devices != NULL) return manager_xi2->all_devices; for (l = manager_xi2->master_devices; l != NULL; l = l->next) all_devices = g_slist_prepend (all_devices, l->data); for (l = manager_xi2->slave_devices; l != NULL; l = l->next) all_devices = g_slist_prepend (all_devices, l->data); manager_xi2->all_devices = g_slist_reverse (all_devices); return manager_xi2->all_devices; } static ClutterInputDevice * clutter_device_manager_xi2_get_device (ClutterDeviceManager *manager, gint id) { ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager); return g_hash_table_lookup (manager_xi2->devices_by_id, GINT_TO_POINTER (id)); } static ClutterInputDevice * clutter_device_manager_xi2_get_core_device (ClutterDeviceManager *manager, ClutterInputDeviceType device_type) { ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager); ClutterInputDevice *pointer = NULL; GList *l; for (l = manager_xi2->master_devices; l != NULL ; l = l->next) { ClutterInputDevice *device = l->data; if (clutter_input_device_get_device_type (device) == CLUTTER_POINTER_DEVICE) { pointer = device; break; } } if (pointer == NULL) return NULL; switch (device_type) { case CLUTTER_POINTER_DEVICE: return pointer; case CLUTTER_KEYBOARD_DEVICE: return clutter_input_device_get_associated_device (pointer); default: break; } return NULL; } static void relate_masters (gpointer key, gpointer value, gpointer data) { ClutterDeviceManagerXI2 *manager_xi2 = data; ClutterInputDevice *device, *relative; device = g_hash_table_lookup (manager_xi2->devices_by_id, key); relative = g_hash_table_lookup (manager_xi2->devices_by_id, value); _clutter_input_device_set_associated_device (device, relative); _clutter_input_device_set_associated_device (relative, device); } static void relate_slaves (gpointer key, gpointer value, gpointer data) { ClutterDeviceManagerXI2 *manager_xi2 = data; ClutterInputDevice *master, *slave; slave = g_hash_table_lookup (manager_xi2->devices_by_id, key); master = g_hash_table_lookup (manager_xi2->devices_by_id, value); _clutter_input_device_set_associated_device (slave, master); _clutter_input_device_add_slave (master, slave); } static void clutter_device_manager_xi2_constructed (GObject *gobject) { ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (gobject); ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (gobject); ClutterBackendX11 *backend_x11; GHashTable *masters, *slaves; XIDeviceInfo *info; XIEventMask event_mask; unsigned char mask[2] = { 0, }; int n_devices, i; backend_x11 = CLUTTER_BACKEND_X11 (_clutter_device_manager_get_backend (manager)); masters = g_hash_table_new (NULL, NULL); slaves = g_hash_table_new (NULL, NULL); info = XIQueryDevice (backend_x11->xdpy, XIAllDevices, &n_devices); for (i = 0; i < n_devices; i++) { XIDeviceInfo *xi_device = &info[i]; if (!xi_device->enabled) continue; add_device (manager_xi2, backend_x11, xi_device, TRUE); if (xi_device->use == XIMasterPointer || xi_device->use == XIMasterKeyboard) { g_hash_table_insert (masters, GINT_TO_POINTER (xi_device->deviceid), GINT_TO_POINTER (xi_device->attachment)); } else if (xi_device->use == XISlavePointer || xi_device->use == XISlaveKeyboard) { g_hash_table_insert (slaves, GINT_TO_POINTER (xi_device->deviceid), GINT_TO_POINTER (xi_device->attachment)); } } XIFreeDeviceInfo (info); g_hash_table_foreach (masters, relate_masters, manager_xi2); g_hash_table_destroy (masters); g_hash_table_foreach (slaves, relate_slaves, manager_xi2); g_hash_table_destroy (slaves); XISetMask (mask, XI_HierarchyChanged); XISetMask (mask, XI_DeviceChanged); XISetMask (mask, XI_PropertyEvent); event_mask.deviceid = XIAllDevices; event_mask.mask_len = sizeof (mask); event_mask.mask = mask; clutter_device_manager_xi2_select_events (manager, clutter_x11_get_root_window (), &event_mask); XSync (backend_x11->xdpy, False); clutter_device_manager_x11_a11y_init (manager); if (G_OBJECT_CLASS (clutter_device_manager_xi2_parent_class)->constructed) G_OBJECT_CLASS (clutter_device_manager_xi2_parent_class)->constructed (gobject); } static void clutter_device_manager_xi2_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (gobject); switch (prop_id) { case PROP_OPCODE: manager_xi2->opcode = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static ClutterVirtualInputDevice * clutter_device_manager_xi2_create_virtual_device (ClutterDeviceManager *manager, ClutterInputDeviceType device_type) { return g_object_new (CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_X11, "device-manager", manager, "device-type", device_type, NULL); } static ClutterVirtualDeviceType clutter_device_manager_xi2_get_supported_virtual_device_types (ClutterDeviceManager *device_manager) { return (CLUTTER_VIRTUAL_DEVICE_TYPE_KEYBOARD | CLUTTER_VIRTUAL_DEVICE_TYPE_POINTER); } static void clutter_device_manager_xi2_class_init (ClutterDeviceManagerXI2Class *klass) { ClutterDeviceManagerClass *manager_class; GObjectClass *gobject_class; obj_props[PROP_OPCODE] = g_param_spec_int ("opcode", "Opcode", "The XI2 opcode", -1, G_MAXINT, -1, CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructed = clutter_device_manager_xi2_constructed; gobject_class->set_property = clutter_device_manager_xi2_set_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass); manager_class->add_device = clutter_device_manager_xi2_add_device; manager_class->remove_device = clutter_device_manager_xi2_remove_device; manager_class->get_devices = clutter_device_manager_xi2_get_devices; manager_class->get_core_device = clutter_device_manager_xi2_get_core_device; manager_class->get_device = clutter_device_manager_xi2_get_device; manager_class->select_stage_events = clutter_device_manager_xi2_select_stage_events; manager_class->create_virtual_device = clutter_device_manager_xi2_create_virtual_device; manager_class->get_supported_virtual_device_types = clutter_device_manager_xi2_get_supported_virtual_device_types; manager_class->apply_kbd_a11y_settings = clutter_device_manager_x11_apply_kbd_a11y_settings; } static void clutter_device_manager_xi2_init (ClutterDeviceManagerXI2 *self) { self->devices_by_id = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); self->tools_by_serial = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); #ifdef HAVE_LIBWACOM self->wacom_db = libwacom_database_new (); #endif } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-device-manager-core-x11.h����������������������������������0000664�0001750�0001750�00000004744�14211404421�024757� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_DEVICE_MANAGER_X11_H__ #define __CLUTTER_DEVICE_MANAGER_X11_H__ #include <clutter/clutter-device-manager.h> G_BEGIN_DECLS #define CLUTTER_TYPE_DEVICE_MANAGER_X11 (_clutter_device_manager_x11_get_type ()) #define CLUTTER_DEVICE_MANAGER_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_X11, ClutterDeviceManagerX11)) #define CLUTTER_IS_DEVICE_MANAGER_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_X11)) #define CLUTTER_DEVICE_MANAGER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_X11, ClutterDeviceManagerX11Class)) #define CLUTTER_IS_DEVICE_MANAGER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_X11)) #define CLUTTER_DEVICE_MANAGER_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_X11, ClutterDeviceManagerX11Class)) typedef struct _ClutterDeviceManagerX11 ClutterDeviceManagerX11; typedef struct _ClutterDeviceManagerX11Class ClutterDeviceManagerX11Class; struct _ClutterDeviceManagerX11 { ClutterDeviceManager parent_instance; GHashTable *devices_by_id; /* the list of transient devices */ GSList *devices; /* the list of all devices, transient and core; this can be * NULL-ified when adding or removing devices */ GSList *all_devices; ClutterInputDevice *core_pointer; ClutterInputDevice *core_keyboard; int xi_event_base; }; struct _ClutterDeviceManagerX11Class { ClutterDeviceManagerClass parent_class; }; GType _clutter_device_manager_x11_get_type (void) G_GNUC_CONST; G_END_DECLS #endif /* __CLUTTER_DEVICE_MANAGER_X11_H__ */ ����������������������������muffin-5.2.1/clutter/clutter/x11/clutter-x11.h������������������������������������������������������0000664�0001750�0001750�00000012007�14211404421�021153� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * */ /** * SECTION:clutter-x11 * @short_description: X11 specific API * * The X11 backend for Clutter provides some specific API, allowing * integration with the Xlibs API for embedding and manipulating the * stage window, or for trapping X errors. * * The ClutterX11 API is available since Clutter 0.6 */ #ifndef __CLUTTER_X11_H__ #define __CLUTTER_X11_H__ #include <glib.h> #include <X11/Xlib.h> #include <X11/Xatom.h> #include <X11/Xutil.h> #include <clutter/clutter.h> #include <clutter/x11/clutter-x11-texture-pixmap.h> G_BEGIN_DECLS /** * ClutterX11FilterReturn: * @CLUTTER_X11_FILTER_CONTINUE: The event was not handled, continues the * processing * @CLUTTER_X11_FILTER_TRANSLATE: Native event translated into a Clutter * event, stops the processing * @CLUTTER_X11_FILTER_REMOVE: Remove the event, stops the processing * * Return values for the #ClutterX11FilterFunc function. * * Since: 0.6 */ typedef enum { CLUTTER_X11_FILTER_CONTINUE, CLUTTER_X11_FILTER_TRANSLATE, CLUTTER_X11_FILTER_REMOVE } ClutterX11FilterReturn; CLUTTER_AVAILABLE_IN_ALL GType clutter_x11_filter_return_get_type (void) G_GNUC_CONST; /* * This is not used any more */ typedef struct _ClutterX11XInputDevice ClutterX11XInputDevice; /** * ClutterX11FilterFunc: * @xev: Native X11 event structure * @cev: Clutter event structure * @data: (closure): user data passed to the filter function * * Filter function for X11 native events. * * Return value: the result of the filtering * * Since: 0.6 */ typedef ClutterX11FilterReturn (*ClutterX11FilterFunc) (XEvent *xev, ClutterEvent *cev, gpointer data); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_trap_x_errors (void); CLUTTER_AVAILABLE_IN_ALL gint clutter_x11_untrap_x_errors (void); CLUTTER_AVAILABLE_IN_ALL Display *clutter_x11_get_default_display (void); CLUTTER_AVAILABLE_IN_ALL int clutter_x11_get_default_screen (void); CLUTTER_AVAILABLE_IN_ALL Window clutter_x11_get_root_window (void); CLUTTER_AVAILABLE_IN_ALL XVisualInfo *clutter_x11_get_visual_info (void); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_set_display (Display * xdpy); CLUTTER_DEPRECATED_FOR(clutter_x11_get_visual_info) XVisualInfo *clutter_x11_get_stage_visual (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL Window clutter_x11_get_stage_window (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_x11_set_stage_foreign (ClutterStage *stage, Window xwindow); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_add_filter (ClutterX11FilterFunc func, gpointer data); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_remove_filter (ClutterX11FilterFunc func, gpointer data); CLUTTER_AVAILABLE_IN_ALL ClutterX11FilterReturn clutter_x11_handle_event (XEvent *xevent); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_disable_event_retrieval (void); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_x11_has_event_retrieval (void); CLUTTER_AVAILABLE_IN_ALL ClutterStage *clutter_x11_get_stage_from_window (Window win); CLUTTER_DEPRECATED_FOR(clutter_device_manager_peek_devices) const GSList* clutter_x11_get_input_devices (void); CLUTTER_DEPRECATED_IN_1_14 void clutter_x11_enable_xinput (void); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_x11_has_xinput (void); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_x11_has_composite_extension (void); CLUTTER_AVAILABLE_IN_ALL void clutter_x11_set_use_argb_visual (gboolean use_argb); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_x11_get_use_argb_visual (void); CLUTTER_AVAILABLE_IN_1_22 void clutter_x11_set_use_stereo_stage (gboolean use_stereo); CLUTTER_AVAILABLE_IN_1_22 gboolean clutter_x11_get_use_stereo_stage (void); CLUTTER_AVAILABLE_IN_ALL Time clutter_x11_get_current_event_time (void); CLUTTER_AVAILABLE_IN_ALL gint clutter_x11_event_get_key_group (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL guint clutter_x11_event_sequence_get_touch_detail (const ClutterEventSequence *sequence); G_END_DECLS #endif /* __CLUTTER_X11_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/xsettings/���������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�020741� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/xsettings/xsettings-common.c���������������������������������������0000664�0001750�0001750�00000013273�14211404421�024431� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright © 2001 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #include "clutter-build-config.h" #include "string.h" #include "stdlib.h" #include <X11/Xlib.h> #include <X11/Xmd.h> /* For CARD32 */ #include "xsettings-common.h" XSettingsSetting * xsettings_setting_copy (XSettingsSetting *setting) { XSettingsSetting *result; size_t str_len; result = malloc (sizeof *result); if (!result) return NULL; str_len = strlen (setting->name); result->name = malloc (str_len + 1); if (!result->name) goto err; memcpy (result->name, setting->name, str_len + 1); result->type = setting->type; switch (setting->type) { case XSETTINGS_TYPE_INT: result->data.v_int = setting->data.v_int; break; case XSETTINGS_TYPE_COLOR: result->data.v_color = setting->data.v_color; break; case XSETTINGS_TYPE_STRING: str_len = strlen (setting->data.v_string); result->data.v_string = malloc (str_len + 1); if (!result->data.v_string) goto err; memcpy (result->data.v_string, setting->data.v_string, str_len + 1); break; } result->last_change_serial = setting->last_change_serial; return result; err: if (result->name) free (result->name); free (result); return NULL; } XSettingsList * xsettings_list_copy (XSettingsList *list) { XSettingsList *new = NULL; XSettingsList *old_iter = list; XSettingsList *new_iter = NULL; while (old_iter) { XSettingsList *new_node; new_node = malloc (sizeof *new_node); if (!new_node) goto error; new_node->setting = xsettings_setting_copy (old_iter->setting); if (!new_node->setting) { free (new_node); goto error; } if (new_iter) new_iter->next = new_node; else new = new_node; new_iter = new_node; old_iter = old_iter->next; } return new; error: xsettings_list_free (new); return NULL; } int xsettings_setting_equal (XSettingsSetting *setting_a, XSettingsSetting *setting_b) { if (setting_a->type != setting_b->type) return 0; if (strcmp (setting_a->name, setting_b->name) != 0) return 0; switch (setting_a->type) { case XSETTINGS_TYPE_INT: return setting_a->data.v_int == setting_b->data.v_int; case XSETTINGS_TYPE_COLOR: return (setting_a->data.v_color.red == setting_b->data.v_color.red && setting_a->data.v_color.green == setting_b->data.v_color.green && setting_a->data.v_color.blue == setting_b->data.v_color.blue && setting_a->data.v_color.alpha == setting_b->data.v_color.alpha); case XSETTINGS_TYPE_STRING: return strcmp (setting_a->data.v_string, setting_b->data.v_string) == 0; } return 0; } void xsettings_setting_free (XSettingsSetting *setting) { if (setting->type == XSETTINGS_TYPE_STRING) free (setting->data.v_string); if (setting->name) free (setting->name); free (setting); } void xsettings_list_free (XSettingsList *list) { while (list) { XSettingsList *next = list->next; xsettings_setting_free (list->setting); free (list); list = next; } } XSettingsResult xsettings_list_insert (XSettingsList **list, XSettingsSetting *setting) { XSettingsList *node; XSettingsList *iter; XSettingsList *last = NULL; node = malloc (sizeof *node); if (!node) return XSETTINGS_NO_MEM; node->setting = setting; iter = *list; while (iter) { int cmp = strcmp (setting->name, iter->setting->name); if (cmp < 0) break; else if (cmp == 0) { free (node); return XSETTINGS_DUPLICATE_ENTRY; } last = iter; iter = iter->next; } if (last) last->next = node; else *list = node; node->next = iter; return XSETTINGS_SUCCESS; } XSettingsResult xsettings_list_delete (XSettingsList **list, const char *name) { XSettingsList *iter; XSettingsList *last = NULL; iter = *list; while (iter) { if (strcmp (name, iter->setting->name) == 0) { if (last) last->next = iter->next; else *list = iter->next; xsettings_setting_free (iter->setting); free (iter); return XSETTINGS_SUCCESS; } last = iter; iter = iter->next; } return XSETTINGS_FAILED; } XSettingsSetting * xsettings_list_lookup (XSettingsList *list, const char *name) { XSettingsList *iter; iter = list; while (iter) { if (strcmp (name, iter->setting->name) == 0) return iter->setting; iter = iter->next; } return NULL; } char xsettings_byte_order (void) { CARD32 myint = 0x01020304; return (*(char *)&myint == 1) ? MSBFirst : LSBFirst; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/xsettings/xsettings-client.h���������������������������������������0000664�0001750�0001750�00000006251�14211404421�024422� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright © 2001, 2007 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #ifndef XSETTINGS_CLIENT_H #define XSETTINGS_CLIENT_H #include <X11/Xlib.h> #include "xsettings-common.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct _XSettingsClient XSettingsClient; typedef enum { XSETTINGS_ACTION_NEW, XSETTINGS_ACTION_CHANGED, XSETTINGS_ACTION_DELETED } XSettingsAction; typedef void (*XSettingsNotifyFunc) (const char *name, XSettingsAction action, XSettingsSetting *setting, void *cb_data); typedef Bool (*XSettingsWatchFunc) (Window window, Bool is_start, long mask, void *cb_data); typedef void (*XSettingsGrabFunc) (Display *display); XSettingsClient *xsettings_client_new (Display *display, int screen, XSettingsNotifyFunc notify, XSettingsWatchFunc watch, void *cb_data); XSettingsClient *xsettings_client_new_with_grab_funcs (Display *display, int screen, XSettingsNotifyFunc notify, XSettingsWatchFunc watch, void *cb_data, XSettingsGrabFunc grab, XSettingsGrabFunc ungrab); void xsettings_client_set_grab_func (XSettingsClient *client, XSettingsGrabFunc grab); void xsettings_client_set_ungrab_func (XSettingsClient *client, XSettingsGrabFunc ungrab); void xsettings_client_destroy (XSettingsClient *client); Bool xsettings_client_process_event (XSettingsClient *client, XEvent *xev); XSettingsResult xsettings_client_get_setting (XSettingsClient *client, const char *name, XSettingsSetting **setting); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* XSETTINGS_CLIENT_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/xsettings/xsettings-client.c���������������������������������������0000664�0001750�0001750�00000034470�14211404421�024421� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright © 2001, 2007 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #include "clutter-build-config.h" #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <X11/Xlib.h> #include <X11/Xmd.h> /* For CARD16 */ #include "xsettings-client.h" struct _XSettingsClient { Display *display; int screen; XSettingsNotifyFunc notify; XSettingsWatchFunc watch; void *cb_data; XSettingsGrabFunc grab; XSettingsGrabFunc ungrab; Window manager_window; Atom manager_atom; Atom selection_atom; Atom xsettings_atom; XSettingsList *settings; }; static void notify_changes (XSettingsClient *client, XSettingsList *old_list) { XSettingsList *old_iter = old_list; XSettingsList *new_iter = client->settings; if (!client->notify) return; while (old_iter || new_iter) { int cmp; if (old_iter && new_iter) cmp = strcmp (old_iter->setting->name, new_iter->setting->name); else if (old_iter) cmp = -1; else cmp = 1; if (cmp < 0) { client->notify (old_iter->setting->name, XSETTINGS_ACTION_DELETED, NULL, client->cb_data); } else if (cmp == 0) { if (!xsettings_setting_equal (old_iter->setting, new_iter->setting)) client->notify (old_iter->setting->name, XSETTINGS_ACTION_CHANGED, new_iter->setting, client->cb_data); } else { client->notify (new_iter->setting->name, XSETTINGS_ACTION_NEW, new_iter->setting, client->cb_data); } if (old_iter) old_iter = old_iter->next; if (new_iter) new_iter = new_iter->next; } } static int ignore_errors (Display *display, XErrorEvent *event) { return True; } static char local_byte_order = '\0'; #define BYTES_LEFT(buffer) ((buffer)->data + (buffer)->len - (buffer)->pos) static XSettingsResult fetch_card16 (XSettingsBuffer *buffer, CARD16 *result) { CARD16 x; if (BYTES_LEFT (buffer) < 2) return XSETTINGS_ACCESS; x = *(CARD16 *)buffer->pos; buffer->pos += 2; if (buffer->byte_order == local_byte_order) *result = x; else *result = (x << 8) | (x >> 8); return XSETTINGS_SUCCESS; } static XSettingsResult fetch_ushort (XSettingsBuffer *buffer, unsigned short *result) { CARD16 x; XSettingsResult r; r = fetch_card16 (buffer, &x); if (r == XSETTINGS_SUCCESS) *result = x; return r; } static XSettingsResult fetch_card32 (XSettingsBuffer *buffer, CARD32 *result) { CARD32 x; if (BYTES_LEFT (buffer) < 4) return XSETTINGS_ACCESS; x = *(CARD32 *)buffer->pos; buffer->pos += 4; if (buffer->byte_order == local_byte_order) *result = x; else *result = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24); return XSETTINGS_SUCCESS; } static XSettingsResult fetch_card8 (XSettingsBuffer *buffer, CARD8 *result) { if (BYTES_LEFT (buffer) < 1) return XSETTINGS_ACCESS; *result = *(CARD8 *)buffer->pos; buffer->pos += 1; return XSETTINGS_SUCCESS; } #define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1))) static XSettingsList * parse_settings (unsigned char *data, size_t len) { XSettingsBuffer buffer; XSettingsResult result = XSETTINGS_SUCCESS; XSettingsList *settings = NULL; CARD32 serial; CARD32 n_entries; CARD32 i; XSettingsSetting *setting = NULL; local_byte_order = xsettings_byte_order (); buffer.pos = buffer.data = data; buffer.len = len; result = fetch_card8 (&buffer, (unsigned char *)&buffer.byte_order); if (buffer.byte_order != MSBFirst && buffer.byte_order != LSBFirst) { fprintf (stderr, "Invalid byte order in XSETTINGS property\n"); result = XSETTINGS_FAILED; goto out; } buffer.pos += 3; result = fetch_card32 (&buffer, &serial); if (result != XSETTINGS_SUCCESS) goto out; result = fetch_card32 (&buffer, &n_entries); if (result != XSETTINGS_SUCCESS) goto out; for (i = 0; i < n_entries; i++) { CARD8 type; CARD16 name_len; CARD32 v_int; size_t pad_len; result = fetch_card8 (&buffer, &type); if (result != XSETTINGS_SUCCESS) goto out; buffer.pos += 1; result = fetch_card16 (&buffer, &name_len); if (result != XSETTINGS_SUCCESS) goto out; pad_len = XSETTINGS_PAD(name_len, 4); if (BYTES_LEFT (&buffer) < pad_len) { result = XSETTINGS_ACCESS; goto out; } setting = malloc (sizeof *setting); if (!setting) { result = XSETTINGS_NO_MEM; goto out; } setting->type = XSETTINGS_TYPE_INT; /* No allocated memory */ setting->name = malloc (name_len + 1); if (!setting->name) { result = XSETTINGS_NO_MEM; goto out; } memcpy (setting->name, buffer.pos, name_len); setting->name[name_len] = '\0'; buffer.pos += pad_len; result = fetch_card32 (&buffer, &v_int); if (result != XSETTINGS_SUCCESS) goto out; setting->last_change_serial = v_int; switch (type) { case XSETTINGS_TYPE_INT: result = fetch_card32 (&buffer, &v_int); if (result != XSETTINGS_SUCCESS) goto out; setting->data.v_int = (INT32)v_int; break; case XSETTINGS_TYPE_STRING: result = fetch_card32 (&buffer, &v_int); if (result != XSETTINGS_SUCCESS) goto out; pad_len = XSETTINGS_PAD (v_int, 4); if (v_int + 1 == 0 || /* Guard against wrap-around */ BYTES_LEFT (&buffer) < pad_len) { result = XSETTINGS_ACCESS; goto out; } setting->data.v_string = malloc (v_int + 1); if (!setting->data.v_string) { result = XSETTINGS_NO_MEM; goto out; } memcpy (setting->data.v_string, buffer.pos, v_int); setting->data.v_string[v_int] = '\0'; buffer.pos += pad_len; break; case XSETTINGS_TYPE_COLOR: result = fetch_ushort (&buffer, &setting->data.v_color.red); if (result != XSETTINGS_SUCCESS) goto out; result = fetch_ushort (&buffer, &setting->data.v_color.green); if (result != XSETTINGS_SUCCESS) goto out; result = fetch_ushort (&buffer, &setting->data.v_color.blue); if (result != XSETTINGS_SUCCESS) goto out; result = fetch_ushort (&buffer, &setting->data.v_color.alpha); if (result != XSETTINGS_SUCCESS) goto out; break; default: /* Quietly ignore unknown types */ break; } setting->type = type; result = xsettings_list_insert (&settings, setting); if (result != XSETTINGS_SUCCESS) goto out; setting = NULL; } out: if (result != XSETTINGS_SUCCESS) { switch (result) { case XSETTINGS_NO_MEM: fprintf(stderr, "Out of memory reading XSETTINGS property\n"); break; case XSETTINGS_ACCESS: fprintf(stderr, "Invalid XSETTINGS property (read off end)\n"); break; case XSETTINGS_DUPLICATE_ENTRY: fprintf (stderr, "Duplicate XSETTINGS entry for '%s'\n", setting->name); case XSETTINGS_FAILED: case XSETTINGS_SUCCESS: case XSETTINGS_NO_ENTRY: break; } if (setting) xsettings_setting_free (setting); xsettings_list_free (settings); settings = NULL; } return settings; } static void read_settings (XSettingsClient *client) { Atom type; int format; unsigned long n_items; unsigned long bytes_after; unsigned char *data; int result; int (*old_handler) (Display *, XErrorEvent *); XSettingsList *old_list = client->settings; client->settings = NULL; if (client->manager_window) { old_handler = XSetErrorHandler (ignore_errors); result = XGetWindowProperty (client->display, client->manager_window, client->xsettings_atom, 0, LONG_MAX, False, client->xsettings_atom, &type, &format, &n_items, &bytes_after, &data); XSetErrorHandler (old_handler); if (result == Success && type != None) { if (type != client->xsettings_atom) { fprintf (stderr, "Invalid type for XSETTINGS property"); } else if (format != 8) { fprintf (stderr, "Invalid format for XSETTINGS property %d", format); } else client->settings = parse_settings (data, n_items); XFree (data); } } notify_changes (client, old_list); xsettings_list_free (old_list); } static void add_events (Display *display, Window window, long mask) { XWindowAttributes attr; XGetWindowAttributes (display, window, &attr); XSelectInput (display, window, attr.your_event_mask | mask); } static void check_manager_window (XSettingsClient *client) { if (client->manager_window && client->watch) client->watch (client->manager_window, False, 0, client->cb_data); if (client->grab) client->grab (client->display); else XGrabServer (client->display); client->manager_window = XGetSelectionOwner (client->display, client->selection_atom); if (client->manager_window) XSelectInput (client->display, client->manager_window, PropertyChangeMask | StructureNotifyMask); if (client->ungrab) client->ungrab (client->display); else XUngrabServer (client->display); XFlush (client->display); if (client->manager_window && client->watch) { if (!client->watch (client->manager_window, True, PropertyChangeMask | StructureNotifyMask, client->cb_data)) { /* Inability to watch the window probably means that it was destroyed * after we ungrabbed */ client->manager_window = None; return; } } read_settings (client); } XSettingsClient * xsettings_client_new (Display *display, int screen, XSettingsNotifyFunc notify, XSettingsWatchFunc watch, void *cb_data) { return xsettings_client_new_with_grab_funcs (display, screen, notify, watch, cb_data, NULL, NULL); } XSettingsClient * xsettings_client_new_with_grab_funcs (Display *display, int screen, XSettingsNotifyFunc notify, XSettingsWatchFunc watch, void *cb_data, XSettingsGrabFunc grab, XSettingsGrabFunc ungrab) { XSettingsClient *client; char buffer[256]; char *atom_names[3]; Atom atoms[3]; client = malloc (sizeof *client); if (!client) return NULL; client->display = display; client->screen = screen; client->notify = notify; client->watch = watch; client->cb_data = cb_data; client->grab = grab; client->ungrab = ungrab; client->manager_window = None; client->settings = NULL; sprintf(buffer, "_XSETTINGS_S%d", screen); atom_names[0] = buffer; atom_names[1] = "_XSETTINGS_SETTINGS"; atom_names[2] = "MANAGER"; #ifdef HAVE_XINTERNATOMS XInternAtoms (display, atom_names, 3, False, atoms); #else atoms[0] = XInternAtom (display, atom_names[0], False); atoms[1] = XInternAtom (display, atom_names[1], False); atoms[2] = XInternAtom (display, atom_names[2], False); #endif client->selection_atom = atoms[0]; client->xsettings_atom = atoms[1]; client->manager_atom = atoms[2]; /* Select on StructureNotify so we get MANAGER events */ add_events (display, RootWindow (display, screen), StructureNotifyMask); if (client->watch) client->watch (RootWindow (display, screen), True, StructureNotifyMask, client->cb_data); check_manager_window (client); return client; } void xsettings_client_set_grab_func (XSettingsClient *client, XSettingsGrabFunc grab) { client->grab = grab; } void xsettings_client_set_ungrab_func (XSettingsClient *client, XSettingsGrabFunc ungrab) { client->ungrab = ungrab; } void xsettings_client_destroy (XSettingsClient *client) { if (client->watch) client->watch (RootWindow (client->display, client->screen), False, 0, client->cb_data); if (client->manager_window && client->watch) client->watch (client->manager_window, False, 0, client->cb_data); xsettings_list_free (client->settings); free (client); } XSettingsResult xsettings_client_get_setting (XSettingsClient *client, const char *name, XSettingsSetting **setting) { XSettingsSetting *search = xsettings_list_lookup (client->settings, name); if (search) { *setting = xsettings_setting_copy (search); return *setting ? XSETTINGS_SUCCESS : XSETTINGS_NO_MEM; } else return XSETTINGS_NO_ENTRY; } Bool xsettings_client_process_event (XSettingsClient *client, XEvent *xev) { /* The checks here will not unlikely cause us to reread * the properties from the manager window a number of * times when the manager changes from A->B. But manager changes * are going to be pretty rare. */ if (xev->xany.window == RootWindow (client->display, client->screen)) { if (xev->xany.type == ClientMessage && xev->xclient.message_type == client->manager_atom && xev->xclient.data.l[1] == client->selection_atom) { check_manager_window (client); return True; } } else if (xev->xany.window == client->manager_window) { if (xev->xany.type == DestroyNotify) { check_manager_window (client); /* let GDK do its cleanup */ return False; } else if (xev->xany.type == PropertyNotify) { read_settings (client); return True; } } return False; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/xsettings/xsettings-common.h���������������������������������������0000664�0001750�0001750�00000010547�14211404421�024437� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright © 2001 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. * * Modified by: Emmanuele Bassi, Intel Corp. */ #ifndef XSETTINGS_COMMON_H #define XSETTINGS_COMMON_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Renames for Clutter inclusion */ #define xsettings_byte_order _clutter_xsettings_byte_order #define xsettings_client_destroy _clutter_xsettings_client_destroy #define xsettings_client_get_setting _clutter_xsettings_client_get_setting #define xsettings_client_new _clutter_xsettings_client_new #define xsettings_client_new_with_grab_funcs _clutter_xsettings_client_new_with_grab_funcs #define xsettings_client_set_grab_func _clutter_xsettings_client_set_grab_func #define xsettings_client_set_ungrab_func _clutter_xsettings_client_set_ungrab_func #define xsettings_client_process_event _clutter_xsettings_client_process_event #define xsettings_list_copy _clutter_xsettings_list_copy #define xsettings_list_delete _clutter_xsettings_list_delete #define xsettings_list_free _clutter_xsettings_list_free #define xsettings_list_insert _clutter_xsettings_list_insert #define xsettings_list_lookup _clutter_xsettings_list_lookup #define xsettings_setting_copy _clutter_xsettings_setting_copy #define xsettings_setting_equal _clutter_xsettings_setting_equal #define xsettings_setting_free _clutter_xsettings_setting_free typedef struct _XSettingsBuffer XSettingsBuffer; typedef struct _XSettingsColor XSettingsColor; typedef struct _XSettingsList XSettingsList; typedef struct _XSettingsSetting XSettingsSetting; /* Types of settings possible. Enum values correspond to * protocol values. */ typedef enum { XSETTINGS_TYPE_INT = 0, XSETTINGS_TYPE_STRING = 1, XSETTINGS_TYPE_COLOR = 2 } XSettingsType; typedef enum { XSETTINGS_SUCCESS, XSETTINGS_NO_MEM, XSETTINGS_ACCESS, XSETTINGS_FAILED, XSETTINGS_NO_ENTRY, XSETTINGS_DUPLICATE_ENTRY } XSettingsResult; struct _XSettingsBuffer { char byte_order; size_t len; unsigned char *data; unsigned char *pos; }; struct _XSettingsColor { unsigned short red, green, blue, alpha; }; struct _XSettingsList { XSettingsSetting *setting; XSettingsList *next; }; struct _XSettingsSetting { char *name; XSettingsType type; union { int v_int; char *v_string; XSettingsColor v_color; } data; unsigned long last_change_serial; }; XSettingsSetting *xsettings_setting_copy (XSettingsSetting *setting); void xsettings_setting_free (XSettingsSetting *setting); int xsettings_setting_equal (XSettingsSetting *setting_a, XSettingsSetting *setting_b); void xsettings_list_free (XSettingsList *list); XSettingsList *xsettings_list_copy (XSettingsList *list); XSettingsResult xsettings_list_insert (XSettingsList **list, XSettingsSetting *setting); XSettingsSetting *xsettings_list_lookup (XSettingsList *list, const char *name); XSettingsResult xsettings_list_delete (XSettingsList **list, const char *name); char xsettings_byte_order (void); #define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1))) #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* XSETTINGS_COMMON_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-glx-texture-pixmap.h���������������������������������������0000664�0001750�0001750�00000006444�14211404421�024336� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Johan Bilien <johan.bilien@nokia.com> * * 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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_GLX_TEXTURE_PIXMAP_H__ #define __CLUTTER_GLX_TEXTURE_PIXMAP_H__ #include <clutter/x11/clutter-x11-texture-pixmap.h> G_BEGIN_DECLS #define CLUTTER_GLX_TYPE_TEXTURE_PIXMAP (clutter_glx_texture_pixmap_get_type ()) #define CLUTTER_GLX_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, ClutterGLXTexturePixmap)) #define CLUTTER_GLX_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, ClutterGLXTexturePixmapClass)) #define CLUTTER_GLX_IS_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP)) #define CLUTTER_GLX_IS_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP)) #define CLUTTER_GLX_TEXTURE_PIXMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, ClutterGLXTexturePixmapClass)) typedef struct _ClutterGLXTexturePixmap ClutterGLXTexturePixmap; typedef struct _ClutterGLXTexturePixmapClass ClutterGLXTexturePixmapClass; typedef struct _ClutterGLXTexturePixmapPrivate ClutterGLXTexturePixmapPrivate; /** * ClutterGLXTexturePixmapClass: * * The #ClutterGLXTexturePixmapClass structure contains only private data * * Since: 0.8 * * Deprecated: 1.6: Use #ClutterX11TexturePixmapClass instead */ struct _ClutterGLXTexturePixmapClass { /*< private >*/ ClutterX11TexturePixmapClass parent_class; }; /** * ClutterGLXTexturePixmap: * * The #ClutterGLXTexturePixmap structure contains only private data * * Since: 0.8 * * Deprecated: 1.6: Use #ClutterX11TexturePixmap instead */ struct _ClutterGLXTexturePixmap { /*< private >*/ ClutterX11TexturePixmap parent; ClutterGLXTexturePixmapPrivate *priv; }; CLUTTER_DEPRECATED_FOR(clutter_x11_texture_pixmap_get_type) GType clutter_glx_texture_pixmap_get_type (void); CLUTTER_DEPRECATED_FOR(clutter_x11_texture_pixmap_new) ClutterActor * clutter_glx_texture_pixmap_new (void); CLUTTER_DEPRECATED_FOR(clutter_x11_texture_pixmap_new_with_pixmap) ClutterActor * clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap); CLUTTER_DEPRECATED_FOR(clutter_x11_texture_pixmap_new_with_window) ClutterActor * clutter_glx_texture_pixmap_new_with_window (Window window); CLUTTER_DEPRECATED_FOR(cogl_texture_pixmap_x11_is_using_tfp_extension) gboolean clutter_glx_texture_pixmap_using_extension (ClutterGLXTexturePixmap *texture); G_END_DECLS #endif /* __CLUTTER_GLX_TEXTURE_PIXMAP_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-event-x11.c������������������������������������������������0000664�0001750�0001750�00000024436�14211404421�022276� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see <http://www.gnu.org/licenses/>. * * * * Authored by: * Matthew Allum <mallum@openedhand.com> * Emmanuele Bassi <ebassi@linux.intel.com> */ #include "clutter-build-config.h" #include "clutter-backend-x11.h" #include "clutter-x11.h" #include "clutter-backend-private.h" #include "clutter-debug.h" #include "clutter-event-private.h" #include "clutter-main.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include <string.h> #include <glib.h> #if 0 /* XEMBED protocol support for toolkit embedding */ #define XEMBED_MAPPED (1 << 0) #define MAX_SUPPORTED_XEMBED_VERSION 1 #define XEMBED_EMBEDDED_NOTIFY 0 #define XEMBED_WINDOW_ACTIVATE 1 #define XEMBED_WINDOW_DEACTIVATE 2 #define XEMBED_REQUEST_FOCUS 3 #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 #define XEMBED_FOCUS_NEXT 6 #define XEMBED_FOCUS_PREV 7 /* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */ #define XEMBED_MODALITY_ON 10 #define XEMBED_MODALITY_OFF 11 #define XEMBED_REGISTER_ACCELERATOR 12 #define XEMBED_UNREGISTER_ACCELERATOR 13 #define XEMBED_ACTIVATE_ACCELERATOR 14 static Window ParentEmbedderWin = None; #endif typedef struct _ClutterEventSource ClutterEventSource; struct _ClutterEventSource { GSource source; ClutterBackendX11 *backend; GPollFD event_poll_fd; }; ClutterEventX11 * _clutter_event_x11_new (void) { return g_slice_new0 (ClutterEventX11); } ClutterEventX11 * _clutter_event_x11_copy (ClutterEventX11 *event_x11) { if (event_x11 != NULL) return g_slice_dup (ClutterEventX11, event_x11); return NULL; } void _clutter_event_x11_free (ClutterEventX11 *event_x11) { if (event_x11 != NULL) g_slice_free (ClutterEventX11, event_x11); } static gboolean clutter_event_prepare (GSource *source, gint *timeout); static gboolean clutter_event_check (GSource *source); static gboolean clutter_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data); static GSourceFuncs event_funcs = { clutter_event_prepare, clutter_event_check, clutter_event_dispatch, NULL }; GSource * _clutter_x11_event_source_new (ClutterBackendX11 *backend_x11) { ClutterEventSource *event_source; int connection_number; GSource *source; gchar *name; connection_number = ConnectionNumber (backend_x11->xdpy); CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number); source = g_source_new (&event_funcs, sizeof (ClutterEventSource)); event_source = (ClutterEventSource *) source; name = g_strdup_printf ("Clutter X11 Event (connection: %d)", connection_number); g_source_set_name (source, name); free (name); event_source->backend = backend_x11; event_source->event_poll_fd.fd = connection_number; event_source->event_poll_fd.events = G_IO_IN; g_source_add_poll (source, &event_source->event_poll_fd); g_source_set_can_recurse (source, TRUE); return source; } /** * clutter_x11_handle_event: * @xevent: pointer to XEvent structure * * This function processes a single X event; it can be used to hook * into external X11 event processing (for example, a GDK filter * function). * * If clutter_x11_disable_event_retrieval() has been called, you must * let this function process events to update Clutter's internal state. * * Return value: #ClutterX11FilterReturn. %CLUTTER_X11_FILTER_REMOVE * indicates that Clutter has internally handled the event and the * caller should do no further processing. %CLUTTER_X11_FILTER_CONTINUE * indicates that Clutter is either not interested in the event, * or has used the event to update internal state without taking * any exclusive action. %CLUTTER_X11_FILTER_TRANSLATE will not * occur. * * Since: 0.8 */ ClutterX11FilterReturn clutter_x11_handle_event (XEvent *xevent) { ClutterX11FilterReturn result; ClutterBackend *backend; ClutterEvent *event; gint spin = 1; #ifdef HAVE_XGE ClutterBackendX11 *backend_x11; Display *xdisplay; gboolean allocated_event; #endif /* The return values here are someone approximate; we return * CLUTTER_X11_FILTER_REMOVE if a clutter event is * generated for the event. This mostly, but not entirely, * corresponds to whether other event processing should be * excluded. As long as the stage window is not shared with another * toolkit it should be safe, and never return * %CLUTTER_X11_FILTER_REMOVE when more processing is needed. */ result = CLUTTER_X11_FILTER_CONTINUE; _clutter_threads_acquire_lock (); backend = clutter_get_default_backend (); event = clutter_event_new (CLUTTER_NOTHING); #ifdef HAVE_XGE backend_x11 = CLUTTER_BACKEND_X11 (backend); xdisplay = backend_x11->xdpy; allocated_event = XGetEventData (xdisplay, &xevent->xcookie); #endif if (_clutter_backend_translate_event (backend, xevent, event)) { _clutter_event_push (event, FALSE); result = CLUTTER_X11_FILTER_REMOVE; } else { clutter_event_free (event); goto out; } /* * Motion events can generate synthetic enter and leave events, so if we * are processing a motion event, we need to spin the event loop at least * two extra times to pump the enter/leave events through (otherwise they * just get pushed down the queue and never processed). */ if (event->type == CLUTTER_MOTION) spin += 2; while (spin > 0 && (event = clutter_event_get ())) { /* forward the event into clutter for emission etc. */ _clutter_stage_queue_event (event->any.stage, event, FALSE); --spin; } out: #ifdef HAVE_XGE if (allocated_event) XFreeEventData (xdisplay, &xevent->xcookie); #endif _clutter_threads_release_lock (); return result; } static gboolean clutter_event_prepare (GSource *source, gint *timeout) { ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend; gboolean retval; _clutter_threads_acquire_lock (); *timeout = -1; retval = (clutter_events_pending () || XPending (backend->xdpy)); _clutter_threads_release_lock (); return retval; } static gboolean clutter_event_check (GSource *source) { ClutterEventSource *event_source = (ClutterEventSource *) source; ClutterBackendX11 *backend = event_source->backend; gboolean retval; _clutter_threads_acquire_lock (); if (event_source->event_poll_fd.revents & G_IO_IN) retval = (clutter_events_pending () || XPending (backend->xdpy)); else retval = FALSE; _clutter_threads_release_lock (); return retval; } static void events_queue (ClutterBackendX11 *backend_x11) { ClutterBackend *backend = CLUTTER_BACKEND (backend_x11); Display *xdisplay = backend_x11->xdpy; ClutterEvent *event; XEvent xevent; while (!clutter_events_pending () && XPending (xdisplay)) { XNextEvent (xdisplay, &xevent); event = clutter_event_new (CLUTTER_NOTHING); #ifdef HAVE_XGE XGetEventData (xdisplay, &xevent.xcookie); #endif if (_clutter_backend_translate_event (backend, &xevent, event)) _clutter_event_push (event, FALSE); else clutter_event_free (event); #ifdef HAVE_XGE XFreeEventData (xdisplay, &xevent.xcookie); #endif } } static gboolean clutter_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterBackendX11 *backend = ((ClutterEventSource *) source)->backend; ClutterEvent *event; _clutter_threads_acquire_lock (); /* Grab the event(s), translate and figure out double click. * The push onto queue (stack) if valid. */ events_queue (backend); /* Pop an event off the queue if any */ event = clutter_event_get (); if (event != NULL) { /* forward the event into clutter for emission etc. */ _clutter_stage_queue_event (event->any.stage, event, FALSE); } _clutter_threads_release_lock (); return TRUE; } /** * clutter_x11_get_current_event_time: (skip) * * Retrieves the timestamp of the last X11 event processed by * Clutter. This might be different from the timestamp returned * by clutter_get_current_event_time(), as Clutter may synthesize * or throttle events. * * Return value: a timestamp, in milliseconds * * Since: 1.0 */ Time clutter_x11_get_current_event_time (void) { ClutterBackend *backend = clutter_get_default_backend (); return CLUTTER_BACKEND_X11 (backend)->last_event_time; } /** * clutter_x11_event_get_key_group: * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS or %CLUTTER_KEY_RELEASE * * Retrieves the group for the modifiers set in @event * * Return value: the group id * * Since: 1.4 */ gint clutter_x11_event_get_key_group (const ClutterEvent *event) { ClutterEventX11 *event_x11; g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE, 0); event_x11 = _clutter_event_get_platform_data (event); if (event_x11 == NULL) return 0; return event_x11->key_group; } /** * clutter_x11_event_sequence_get_touch_detail: * @sequence: a #ClutterEventSequence * * Retrieves the touch detail froma #ClutterEventSequence. * * Return value: the touch detail * * Since: 1.12 */ guint clutter_x11_event_sequence_get_touch_detail (const ClutterEventSequence *sequence) { g_return_val_if_fail (sequence != NULL, 0); return GPOINTER_TO_UINT (sequence); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-input-device-xi2.h�����������������������������������������0000664�0001750�0001750�00000005332�14211404421�023641� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_INPUT_DEVICE_XI2_H__ #define __CLUTTER_INPUT_DEVICE_XI2_H__ #include <clutter/clutter-input-device.h> #include <X11/extensions/XInput2.h> #ifdef HAVE_LIBWACOM #include <libwacom/libwacom.h> #endif G_BEGIN_DECLS #define CLUTTER_TYPE_INPUT_DEVICE_XI2 (_clutter_input_device_xi2_get_type ()) #define CLUTTER_INPUT_DEVICE_XI2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_XI2, ClutterInputDeviceXI2)) #define CLUTTER_IS_INPUT_DEVICE_XI2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_XI2)) typedef struct _ClutterInputDeviceXI2 ClutterInputDeviceXI2; GType _clutter_input_device_xi2_get_type (void) G_GNUC_CONST; void _clutter_input_device_xi2_translate_state (ClutterEvent *event, XIModifierState *modifiers_state, XIButtonState *buttons_state, XIGroupState *group_state); void clutter_input_device_xi2_update_tool (ClutterInputDevice *device, ClutterInputDeviceTool *tool); ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device); #ifdef HAVE_LIBWACOM void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device, WacomDeviceDatabase *wacom_db); guint clutter_input_device_xi2_get_pad_group_mode (ClutterInputDevice *device, guint group); void clutter_input_device_xi2_update_pad_state (ClutterInputDevice *device, guint button, guint state, guint *group, guint *mode); #endif G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_XI2_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-backend-x11.c����������������������������������������������0000664�0001750�0001750�00000117164�14211404421�022545� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * Authored By Matthew Allum <mallum@openedhand.com> * Copyright (C) 2006-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, see <http://www.gnu.org/licenses/>. * * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <errno.h> #include "clutter-backend-x11.h" #include "clutter-device-manager-core-x11.h" #include "clutter-device-manager-xi2.h" #include "clutter-settings-x11.h" #include "clutter-stage-x11.h" #include "clutter-x11.h" #include "xsettings/xsettings-common.h" #if HAVE_XCOMPOSITE #include <X11/extensions/Xcomposite.h> #endif #if HAVE_XINPUT_2 #include <X11/extensions/XInput2.h> #endif #include <cogl/cogl.h> #include <cogl/cogl-xlib.h> #include "clutter-backend.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-event-private.h" #include "clutter-main.h" #include "clutter-private.h" #include "clutter-settings-private.h" G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND) GType clutter_x11_filter_return_get_type (void) { static volatile gsize g_define_type__volatile; if (g_once_init_enter (&g_define_type__volatile)) { static const GEnumValue values[] = { { CLUTTER_X11_FILTER_CONTINUE, "CLUTTER_X11_FILTER_CONTINUE", "continue" }, { CLUTTER_X11_FILTER_TRANSLATE, "CLUTTER_X11_FILTER_TRANSLATE", "translate" }, { CLUTTER_X11_FILTER_REMOVE, "CLUTTER_X11_FILTER_REMOVE", "remove" }, { 0, NULL, NULL }, }; GType g_define_type = g_enum_register_static (g_intern_static_string ("ClutterX11FilterReturn"), values); g_once_init_leave (&g_define_type__volatile, g_define_type); } return g_define_type__volatile; } /* atoms; remember to add the code that assigns the atom value to * the member of the ClutterBackendX11 structure if you add an * atom name here. do not change the order! */ static const gchar *atom_names[] = { "_NET_WM_PID", "_NET_WM_PING", "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_USER_TIME", "WM_PROTOCOLS", "WM_DELETE_WINDOW", "_XEMBED", "_XEMBED_INFO", "_NET_WM_NAME", "UTF8_STRING", }; #define N_ATOM_NAMES G_N_ELEMENTS (atom_names) /* various flags corresponding to pre init setup calls */ static gboolean _no_xevent_retrieval = FALSE; static gboolean clutter_enable_xinput = TRUE; static gboolean clutter_enable_argb = FALSE; static gboolean clutter_enable_stereo = FALSE; static Display *_foreign_dpy = NULL; /* options */ static gchar *clutter_display_name = NULL; static gint clutter_screen = -1; static gboolean clutter_synchronise = FALSE; /* X error trap */ static int TrappedErrorCode = 0; static int (* old_error_handler) (Display *, XErrorEvent *); static ClutterX11FilterReturn xsettings_filter (XEvent *xevent, ClutterEvent *event, gpointer data) { ClutterBackendX11 *backend_x11 = data; _clutter_xsettings_client_process_event (backend_x11->xsettings, xevent); /* we always want the rest of the stack to get XSettings events, even * if Clutter already handled them */ return CLUTTER_X11_FILTER_CONTINUE; } static ClutterX11FilterReturn cogl_xlib_filter (XEvent *xevent, ClutterEvent *event, gpointer data) { ClutterBackend *backend = data; ClutterX11FilterReturn retval; CoglFilterReturn ret; ret = cogl_xlib_renderer_handle_event (backend->cogl_renderer, xevent); switch (ret) { case COGL_FILTER_REMOVE: retval = CLUTTER_X11_FILTER_REMOVE; break; case COGL_FILTER_CONTINUE: default: retval = CLUTTER_X11_FILTER_CONTINUE; break; } return retval; } static void clutter_backend_x11_xsettings_notify (const char *name, XSettingsAction action, XSettingsSetting *setting, void *cb_data) { ClutterSettings *settings = clutter_settings_get_default (); gint i; if (name == NULL || *name == '\0') return; if (setting == NULL) return; g_object_freeze_notify (G_OBJECT (settings)); for (i = 0; i < _n_clutter_settings_map; i++) { if (g_strcmp0 (name, CLUTTER_SETTING_X11_NAME (i)) == 0) { GValue value = G_VALUE_INIT; switch (setting->type) { case XSETTINGS_TYPE_INT: g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, setting->data.v_int); break; case XSETTINGS_TYPE_STRING: g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, setting->data.v_string); break; case XSETTINGS_TYPE_COLOR: { ClutterColor color; color.red = (guint8) ((float) setting->data.v_color.red / 65535.0 * 255); color.green = (guint8) ((float) setting->data.v_color.green / 65535.0 * 255); color.blue = (guint8) ((float) setting->data.v_color.blue / 65535.0 * 255); color.alpha = (guint8) ((float) setting->data.v_color.alpha / 65535.0 * 255); g_value_init (&value, G_TYPE_BOXED); clutter_value_set_color (&value, &color); } break; } CLUTTER_NOTE (BACKEND, "Mapping XSETTING '%s' to 'ClutterSettings:%s'", CLUTTER_SETTING_X11_NAME (i), CLUTTER_SETTING_PROPERTY (i)); clutter_settings_set_property_internal (settings, CLUTTER_SETTING_PROPERTY (i), &value); g_value_unset (&value); break; } } g_object_thaw_notify (G_OBJECT (settings)); } static void clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11) { ClutterEventTranslator *translator; ClutterBackend *backend; #ifdef HAVE_XINPUT_2 if (clutter_enable_xinput) { int event_base, first_event, first_error; if (XQueryExtension (backend_x11->xdpy, "XInputExtension", &event_base, &first_event, &first_error)) { int major = 2; int minor = 3; if (XIQueryVersion (backend_x11->xdpy, &major, &minor) != BadRequest) { CLUTTER_NOTE (BACKEND, "Creating XI2 device manager"); backend_x11->has_xinput = TRUE; backend_x11->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_XI2, "backend", backend_x11, "opcode", event_base, NULL); backend_x11->xi_minor = minor; } } } if (backend_x11->device_manager == NULL) #endif /* HAVE_XINPUT_2 */ { CLUTTER_NOTE (BACKEND, "Creating Core device manager"); backend_x11->has_xinput = FALSE; backend_x11->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11, "backend", backend_x11, NULL); backend_x11->xi_minor = -1; } backend = CLUTTER_BACKEND (backend_x11); backend->device_manager = backend_x11->device_manager; translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->device_manager); _clutter_backend_add_event_translator (backend, translator); } static void clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11) { if (backend_x11->keymap == NULL) { ClutterEventTranslator *translator; ClutterBackend *backend; backend_x11->keymap = g_object_new (CLUTTER_TYPE_KEYMAP_X11, "backend", backend_x11, NULL); backend = CLUTTER_BACKEND (backend_x11); translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->keymap); _clutter_backend_add_event_translator (backend, translator); } } static gboolean clutter_backend_x11_pre_parse (ClutterBackend *backend, GError **error) { const gchar *env_string; /* we don't fail here if DISPLAY is not set, as the user * might pass the --display command line switch */ env_string = g_getenv ("DISPLAY"); if (env_string) { clutter_display_name = g_strdup (env_string); env_string = NULL; } env_string = g_getenv ("CLUTTER_DISABLE_ARGB_VISUAL"); if (env_string) { clutter_enable_argb = FALSE; env_string = NULL; } env_string = g_getenv ("CLUTTER_DISABLE_XINPUT"); if (env_string) { clutter_enable_xinput = FALSE; env_string = NULL; } return TRUE; } static gboolean clutter_backend_x11_post_parse (ClutterBackend *backend, GError **error) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterSettings *settings; Atom atoms[N_ATOM_NAMES]; double dpi; if (_foreign_dpy) backend_x11->xdpy = _foreign_dpy; /* Only open connection if not already set by prior call to * clutter_x11_set_display() */ if (backend_x11->xdpy == NULL) { if (clutter_display_name != NULL && *clutter_display_name != '\0') { CLUTTER_NOTE (BACKEND, "XOpenDisplay on '%s'", clutter_display_name); backend_x11->xdpy = XOpenDisplay (clutter_display_name); if (backend_x11->xdpy == NULL) { g_set_error (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_BACKEND, "Unable to open display '%s'", clutter_display_name); return FALSE; } } else { g_set_error_literal (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_BACKEND, "Unable to open display. You have to set the " "DISPLAY environment variable, or use the " "--display command line argument"); return FALSE; } } g_assert (backend_x11->xdpy != NULL); CLUTTER_NOTE (BACKEND, "Getting the X screen"); settings = clutter_settings_get_default (); /* add event filter for Cogl events */ clutter_x11_add_filter (cogl_xlib_filter, backend); if (clutter_screen == -1) backend_x11->xscreen = DefaultScreenOfDisplay (backend_x11->xdpy); else backend_x11->xscreen = ScreenOfDisplay (backend_x11->xdpy, clutter_screen); backend_x11->xscreen_num = XScreenNumberOfScreen (backend_x11->xscreen); backend_x11->xscreen_width = WidthOfScreen (backend_x11->xscreen); backend_x11->xscreen_height = HeightOfScreen (backend_x11->xscreen); backend_x11->xwin_root = RootWindow (backend_x11->xdpy, backend_x11->xscreen_num); backend_x11->display_name = g_strdup (clutter_display_name); dpi = (((double) DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num) * 25.4) / (double) DisplayHeightMM (backend_x11->xdpy, backend_x11->xscreen_num)); g_object_set (settings, "font-dpi", (int) dpi * 1024, NULL); /* create XSETTINGS client */ backend_x11->xsettings = _clutter_xsettings_client_new (backend_x11->xdpy, backend_x11->xscreen_num, clutter_backend_x11_xsettings_notify, NULL, backend_x11); /* add event filter for XSETTINGS events */ clutter_x11_add_filter (xsettings_filter, backend_x11); if (clutter_synchronise) XSynchronize (backend_x11->xdpy, True); XInternAtoms (backend_x11->xdpy, (char **) atom_names, N_ATOM_NAMES, False, atoms); backend_x11->atom_NET_WM_PID = atoms[0]; backend_x11->atom_NET_WM_PING = atoms[1]; backend_x11->atom_NET_WM_STATE = atoms[2]; backend_x11->atom_NET_WM_STATE_FULLSCREEN = atoms[3]; backend_x11->atom_NET_WM_USER_TIME = atoms[4]; backend_x11->atom_WM_PROTOCOLS = atoms[5]; backend_x11->atom_WM_DELETE_WINDOW = atoms[6]; backend_x11->atom_XEMBED = atoms[7]; backend_x11->atom_XEMBED_INFO = atoms[8]; backend_x11->atom_NET_WM_NAME = atoms[9]; backend_x11->atom_UTF8_STRING = atoms[10]; free (clutter_display_name); CLUTTER_NOTE (BACKEND, "X Display '%s'[%p] opened (screen:%d, root:%u, dpi:%f)", backend_x11->display_name, backend_x11->xdpy, backend_x11->xscreen_num, (unsigned int) backend_x11->xwin_root, clutter_backend_get_resolution (backend)); return TRUE; } void _clutter_backend_x11_events_init (ClutterBackend *backend) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); CLUTTER_NOTE (EVENT, "initialising the event loop"); /* the event source is optional */ if (!_no_xevent_retrieval) { GSource *source; source = _clutter_x11_event_source_new (backend_x11); /* default priority for events * * XXX - at some point we'll have a common EventSource API that * is created by the backend, and this code will most likely go * into the default implementation of ClutterBackend */ g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); /* attach the source to the default context, and transfer the * ownership to the GMainContext itself */ g_source_attach (source, NULL); g_source_unref (source); backend_x11->event_source = source; } /* create the device manager; we need this because we can effectively * choose between core+XI1 and XI2 input events */ clutter_backend_x11_create_device_manager (backend_x11); /* register keymap; unless we create a generic Keymap object, I'm * afraid this will have to stay */ clutter_backend_x11_create_keymap (backend_x11); } static const GOptionEntry entries[] = { { "display", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &clutter_display_name, N_("X display to use"), "DISPLAY" }, { "screen", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &clutter_screen, N_("X screen to use"), "SCREEN" }, { "synch", 0, 0, G_OPTION_ARG_NONE, &clutter_synchronise, N_("Make X calls synchronous"), NULL }, #ifdef HAVE_XINPUT_2 { "disable-xinput", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &clutter_enable_xinput, N_("Disable XInput support"), NULL }, #endif /* HAVE_XINPUT_2 */ { NULL } }; static void clutter_backend_x11_add_options (ClutterBackend *backend, GOptionGroup *group) { g_option_group_add_entries (group, entries); } static void clutter_backend_x11_finalize (GObject *gobject) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject); free (backend_x11->display_name); clutter_x11_remove_filter (cogl_xlib_filter, gobject); clutter_x11_remove_filter (xsettings_filter, backend_x11); _clutter_xsettings_client_destroy (backend_x11->xsettings); XCloseDisplay (backend_x11->xdpy); G_OBJECT_CLASS (clutter_backend_x11_parent_class)->finalize (gobject); } static void clutter_backend_x11_dispose (GObject *gobject) { G_OBJECT_CLASS (clutter_backend_x11_parent_class)->dispose (gobject); } static ClutterFeatureFlags clutter_backend_x11_get_features (ClutterBackend *backend) { ClutterFeatureFlags flags = CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR; flags |= CLUTTER_BACKEND_CLASS (clutter_backend_x11_parent_class)->get_features (backend); return flags; } static void update_last_event_time (ClutterBackendX11 *backend_x11, XEvent *xevent) { Time current_time = CurrentTime; Time last_time = backend_x11->last_event_time; switch (xevent->type) { case KeyPress: case KeyRelease: current_time = xevent->xkey.time; break; case ButtonPress: case ButtonRelease: current_time = xevent->xbutton.time; break; case MotionNotify: current_time = xevent->xmotion.time; break; case EnterNotify: case LeaveNotify: current_time = xevent->xcrossing.time; break; case PropertyNotify: current_time = xevent->xproperty.time; break; default: break; } /* only change the current event time if it's after the previous event * time, or if it is at least 30 seconds earlier - in case the system * clock was changed */ if ((current_time != CurrentTime) && (current_time > last_time || (last_time - current_time > (30 * 1000)))) backend_x11->last_event_time = current_time; } static gboolean clutter_backend_x11_translate_event (ClutterBackend *backend, gpointer native, ClutterEvent *event) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterBackendClass *parent_class; XEvent *xevent = native; /* X11 filter functions have a higher priority */ if (backend_x11->event_filters != NULL) { GSList *node = backend_x11->event_filters; while (node != NULL) { ClutterX11EventFilter *filter = node->data; switch (filter->func (xevent, event, filter->data)) { case CLUTTER_X11_FILTER_CONTINUE: break; case CLUTTER_X11_FILTER_TRANSLATE: return TRUE; case CLUTTER_X11_FILTER_REMOVE: return FALSE; default: break; } node = node->next; } } /* we update the event time only for events that can * actually reach Clutter's event queue */ update_last_event_time (backend_x11, xevent); /* chain up to the parent implementation, which will handle * event translators */ parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_x11_parent_class); return parent_class->translate_event (backend, native, event); } static CoglRenderer * clutter_backend_x11_get_renderer (ClutterBackend *backend, GError **error) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); Display *xdisplay = backend_x11->xdpy; CoglRenderer *renderer; CLUTTER_NOTE (BACKEND, "Creating a new Xlib renderer"); renderer = cogl_renderer_new (); cogl_renderer_add_constraint (renderer, COGL_RENDERER_CONSTRAINT_USES_X11); /* set the display object we're using */ cogl_xlib_renderer_set_foreign_display (renderer, xdisplay); return renderer; } static gboolean check_onscreen_template (CoglRenderer *renderer, CoglSwapChain *swap_chain, CoglOnscreenTemplate *onscreen_template, CoglBool enable_argb, CoglBool enable_stereo, GError **error) { GError *internal_error = NULL; cogl_swap_chain_set_has_alpha (swap_chain, enable_argb); cogl_onscreen_template_set_stereo_enabled (onscreen_template, clutter_enable_stereo); /* cogl_renderer_check_onscreen_template() is actually just a * shorthand for creating a CoglDisplay, and calling * cogl_display_setup() on it, then throwing the display away. If we * could just return that display, then it would be more efficient * not to use cogl_renderer_check_onscreen_template(). However, the * backend API requires that we return an CoglDisplay that has not * yet been setup, so one way or the other we'll have to discard the * first display and make a new fresh one. */ if (cogl_renderer_check_onscreen_template (renderer, onscreen_template, &internal_error)) { clutter_enable_argb = enable_argb; clutter_enable_stereo = enable_stereo; return TRUE; } else { if (enable_argb || enable_stereo) /* More possibilities to try */ CLUTTER_NOTE (BACKEND, "Creation of a CoglDisplay with alpha=%s, stereo=%s failed: %s", enable_argb ? "enabled" : "disabled", enable_stereo ? "enabled" : "disabled", internal_error != NULL ? internal_error->message : "Unknown reason"); else g_set_error_literal (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_BACKEND, internal_error != NULL ? internal_error->message : "Creation of a CoglDisplay failed"); g_clear_error (&internal_error); return FALSE; } } static CoglDisplay * clutter_backend_x11_get_display (ClutterBackend *backend, CoglRenderer *renderer, CoglSwapChain *swap_chain, GError **error) { CoglOnscreenTemplate *onscreen_template; CoglDisplay *display = NULL; gboolean res = FALSE; CLUTTER_NOTE (BACKEND, "Creating CoglDisplay, alpha=%s, stereo=%s", clutter_enable_argb ? "enabled" : "disabled", clutter_enable_stereo ? "enabled" : "disabled"); onscreen_template = cogl_onscreen_template_new (swap_chain); /* It's possible that the current renderer doesn't support transparency * or doesn't support stereo, so we try the different combinations. */ if (clutter_enable_argb && clutter_enable_stereo) res = check_onscreen_template (renderer, swap_chain, onscreen_template, TRUE, TRUE, error); /* Prioritize stereo over alpha */ if (!res && clutter_enable_stereo) res = check_onscreen_template (renderer, swap_chain, onscreen_template, FALSE, TRUE, error); if (!res && clutter_enable_argb) res = check_onscreen_template (renderer, swap_chain, onscreen_template, TRUE, FALSE, error); if (!res) res = check_onscreen_template (renderer, swap_chain, onscreen_template, FALSE, FALSE, error); if (res) display = cogl_display_new (renderer, onscreen_template); cogl_object_unref (onscreen_template); return display; } static ClutterStageWindow * clutter_backend_x11_create_stage (ClutterBackend *backend, ClutterStage *wrapper, GError **error) { ClutterEventTranslator *translator; ClutterStageWindow *stage; stage = g_object_new (CLUTTER_TYPE_STAGE_X11, "backend", backend, "wrapper", wrapper, NULL); /* the X11 stage does event translation */ translator = CLUTTER_EVENT_TRANSLATOR (stage); _clutter_backend_add_event_translator (backend, translator); CLUTTER_NOTE (BACKEND, "X11 stage created (display:%p, screen:%d, root:%u)", CLUTTER_BACKEND_X11 (backend)->xdpy, CLUTTER_BACKEND_X11 (backend)->xscreen_num, (unsigned int) CLUTTER_BACKEND_X11 (backend)->xwin_root); return stage; } static PangoDirection clutter_backend_x11_get_keymap_direction (ClutterBackend *backend) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); if (G_UNLIKELY (backend_x11->keymap == NULL)) return PANGO_DIRECTION_NEUTRAL; return _clutter_keymap_x11_get_direction (backend_x11->keymap); } static void clutter_backend_x11_class_init (ClutterBackendX11Class *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass); gobject_class->dispose = clutter_backend_x11_dispose; gobject_class->finalize = clutter_backend_x11_finalize; backend_class->create_stage = clutter_backend_x11_create_stage; backend_class->pre_parse = clutter_backend_x11_pre_parse; backend_class->post_parse = clutter_backend_x11_post_parse; backend_class->add_options = clutter_backend_x11_add_options; backend_class->get_features = clutter_backend_x11_get_features; backend_class->translate_event = clutter_backend_x11_translate_event; backend_class->get_renderer = clutter_backend_x11_get_renderer; backend_class->get_display = clutter_backend_x11_get_display; backend_class->get_keymap_direction = clutter_backend_x11_get_keymap_direction; } static void clutter_backend_x11_init (ClutterBackendX11 *backend_x11) { backend_x11->last_event_time = CurrentTime; } ClutterBackend * clutter_backend_x11_new (void) { return g_object_new (CLUTTER_TYPE_BACKEND_X11, NULL); } static int error_handler(Display *xdpy, XErrorEvent *error) { TrappedErrorCode = error->error_code; return 0; } /** * clutter_x11_trap_x_errors: * * Traps every X error until clutter_x11_untrap_x_errors() is called. * * Since: 0.6 */ void clutter_x11_trap_x_errors (void) { TrappedErrorCode = 0; old_error_handler = XSetErrorHandler (error_handler); } /** * clutter_x11_untrap_x_errors: * * Removes the X error trap and returns the current status. * * Return value: the trapped error code, or 0 for success * * Since: 0.4 */ gint clutter_x11_untrap_x_errors (void) { XSetErrorHandler (old_error_handler); return TrappedErrorCode; } /** * clutter_x11_get_default_display: * * Retrieves the pointer to the default display. * * Return value: (transfer none): the default display * * Since: 0.6 */ Display * clutter_x11_get_default_display (void) { ClutterBackend *backend = clutter_get_default_backend (); if (backend == NULL) { g_critical ("The Clutter backend has not been initialised"); return NULL; } if (!CLUTTER_IS_BACKEND_X11 (backend)) { g_critical ("The Clutter backend is not a X11 backend"); return NULL; } return CLUTTER_BACKEND_X11 (backend)->xdpy; } /** * clutter_x11_set_display: * @xdpy: pointer to a X display connection. * * Sets the display connection Clutter should use; must be called * before clutter_init(), clutter_init_with_args() or other functions * pertaining Clutter's initialization process. * * If you are parsing the command line arguments by retrieving Clutter's * #GOptionGroup with clutter_get_option_group() and calling * g_option_context_parse() yourself, you should also call * clutter_x11_set_display() before g_option_context_parse(). * * Since: 0.8 */ void clutter_x11_set_display (Display *xdpy) { if (_clutter_context_is_initialized ()) { g_warning ("%s() can only be used before calling clutter_init()", G_STRFUNC); return; } _foreign_dpy= xdpy; } /** * clutter_x11_enable_xinput: * * Enables the use of the XInput extension if present on connected * XServer and support built into Clutter. XInput allows for multiple * pointing devices to be used. * * This function must be called before clutter_init(). * * Since XInput might not be supported by the X server, you might * want to use clutter_x11_has_xinput() to see if support was enabled. * * Since: 0.8 * * Deprecated: 1.14: This function does not do anything; XInput support * is enabled by default in Clutter. Use the CLUTTER_DISABLE_XINPUT * environment variable to disable XInput support and use Xlib core * events instead. */ void clutter_x11_enable_xinput (void) { } /** * clutter_x11_disable_event_retrieval: * * Disables the internal polling of X11 events in the main loop. * * Libraries or applications calling this function will be responsible of * polling all X11 events. * * You also must call clutter_x11_handle_event() to let Clutter process * events and maintain its internal state. * * This function can only be called before calling clutter_init(). * * Even with event handling disabled, Clutter will still select * all the events required to maintain its internal state on the stage * Window; compositors using Clutter and input regions to pass events * through to application windows should not rely on an empty input * region, and should instead clear it themselves explicitly using the * XFixes extension. * * This function should not be normally used by applications. * * Since: 0.8 */ void clutter_x11_disable_event_retrieval (void) { if (_clutter_context_is_initialized ()) { g_warning ("%s() can only be used before calling clutter_init()", G_STRFUNC); return; } _no_xevent_retrieval = TRUE; } /** * clutter_x11_has_event_retrieval: * * Queries the X11 backend to check if event collection has been disabled. * * Return value: TRUE if event retrival has been disabled. FALSE otherwise. * * Since: 0.8 */ gboolean clutter_x11_has_event_retrieval (void) { return !_no_xevent_retrieval; } /** * clutter_x11_get_default_screen: * * Gets the number of the default X Screen object. * * Return value: the number of the default screen * * Since: 0.6 */ int clutter_x11_get_default_screen (void) { ClutterBackend *backend = clutter_get_default_backend (); if (backend == NULL) { g_critical ("The Clutter backend has not been initialised"); return 0; } if (!CLUTTER_IS_BACKEND_X11 (backend)) { g_critical ("The Clutter backend is not a X11 backend"); return 0; } return CLUTTER_BACKEND_X11 (backend)->xscreen_num; } /** * clutter_x11_get_root_window: (skip) * * Retrieves the root window. * * Return value: the id of the root window * * Since: 0.6 */ Window clutter_x11_get_root_window (void) { ClutterBackend *backend = clutter_get_default_backend (); if (backend == NULL) { g_critical ("The Clutter backend has not been initialised"); return None; } if (!CLUTTER_IS_BACKEND_X11 (backend)) { g_critical ("The Clutter backend is not a X11 backend"); return None; } return CLUTTER_BACKEND_X11 (backend)->xwin_root; } /** * clutter_x11_add_filter: (skip) * @func: a filter function * @data: user data to be passed to the filter function, or %NULL * * Adds an event filter function. * * Since: 0.6 */ void clutter_x11_add_filter (ClutterX11FilterFunc func, gpointer data) { ClutterX11EventFilter *filter; ClutterBackend *backend = clutter_get_default_backend (); ClutterBackendX11 *backend_x11; g_return_if_fail (func != NULL); if (backend == NULL) { g_critical ("The Clutter backend has not been initialised"); return; } if (!CLUTTER_IS_BACKEND_X11 (backend)) { g_critical ("The Clutter backend is not a X11 backend"); return; } backend_x11 = CLUTTER_BACKEND_X11 (backend); filter = g_new0 (ClutterX11EventFilter, 1); filter->func = func; filter->data = data; backend_x11->event_filters = g_slist_append (backend_x11->event_filters, filter); return; } /** * clutter_x11_remove_filter: (skip) * @func: a filter function * @data: user data to be passed to the filter function, or %NULL * * Removes the given filter function. * * Since: 0.6 */ void clutter_x11_remove_filter (ClutterX11FilterFunc func, gpointer data) { GSList *tmp_list, *this; ClutterX11EventFilter *filter; ClutterBackend *backend = clutter_get_default_backend (); ClutterBackendX11 *backend_x11; g_return_if_fail (func != NULL); if (backend == NULL) { g_critical ("The Clutter backend has not been initialised"); return; } if (!CLUTTER_IS_BACKEND_X11 (backend)) { g_critical ("The Clutter backend is not a X11 backend"); return; } backend_x11 = CLUTTER_BACKEND_X11 (backend); tmp_list = backend_x11->event_filters; while (tmp_list) { filter = tmp_list->data; this = tmp_list; tmp_list = tmp_list->next; if (filter->func == func && filter->data == data) { backend_x11->event_filters = g_slist_remove_link (backend_x11->event_filters, this); g_slist_free_1 (this); free (filter); return; } } } /** * clutter_x11_get_input_devices: * * Retrieves a pointer to the list of input devices * * Deprecated: 1.2: Use clutter_device_manager_peek_devices() instead * * Since: 0.8 * * Return value: (transfer none) (element-type Clutter.InputDevice): a * pointer to the internal list of input devices; the returned list is * owned by Clutter and should not be modified or freed */ const GSList * clutter_x11_get_input_devices (void) { ClutterDeviceManager *manager; manager = clutter_device_manager_get_default (); if (manager == NULL) return NULL; return clutter_device_manager_peek_devices (manager); } /** * clutter_x11_has_xinput: * * Gets whether Clutter has XInput support. * * Return value: %TRUE if Clutter was compiled with XInput support * and XInput support is available at run time. * * Since: 0.8 */ gboolean clutter_x11_has_xinput (void) { #ifdef HAVE_XINPUT_2 ClutterBackend *backend = clutter_get_default_backend (); if (backend == NULL) { g_critical ("The Clutter backend has not been initialised"); return FALSE; } if (!CLUTTER_IS_BACKEND_X11 (backend)) { g_critical ("The Clutter backend is not a X11 backend."); return FALSE; } return CLUTTER_BACKEND_X11 (backend)->has_xinput; #else return FALSE; #endif } /** * clutter_x11_has_composite_extension: * * Retrieves whether Clutter is running on an X11 server with the * XComposite extension * * Return value: %TRUE if the XComposite extension is available */ gboolean clutter_x11_has_composite_extension (void) { #if HAVE_XCOMPOSITE static gboolean have_composite = FALSE, done_check = FALSE; int error = 0, event = 0; Display *dpy; if (done_check) return have_composite; if (!_clutter_context_is_initialized ()) { g_critical ("X11 backend has not been initialised"); return FALSE; } dpy = clutter_x11_get_default_display(); if (dpy == NULL) return FALSE; if (XCompositeQueryExtension (dpy, &event, &error)) { int major = 0, minor = 0; if (XCompositeQueryVersion (dpy, &major, &minor)) { if (major >= 0 && minor >= 3) have_composite = TRUE; } } done_check = TRUE; return have_composite; #else return FALSE; #endif /* HAVE_XCOMPOSITE */ } /** * clutter_x11_set_use_argb_visual: * @use_argb: %TRUE if ARGB visuals should be requested by default * * Sets whether the Clutter X11 backend should request ARGB visuals by default * or not. * * By default, Clutter requests RGB visuals. * * If no ARGB visuals are found, the X11 backend will fall back to * requesting a RGB visual instead. * * ARGB visuals are required for the #ClutterStage:use-alpha property to work. * * This function can only be called once, and before clutter_init() is * called. * * Since: 1.2 */ void clutter_x11_set_use_argb_visual (gboolean use_argb) { if (_clutter_context_is_initialized ()) { g_warning ("%s() can only be used before calling clutter_init()", G_STRFUNC); return; } CLUTTER_NOTE (BACKEND, "ARGB visuals are %s", use_argb ? "enabled" : "disabled"); clutter_enable_argb = use_argb; } /** * clutter_x11_get_use_argb_visual: * * Retrieves whether the Clutter X11 backend is using ARGB visuals by default * * Return value: %TRUE if ARGB visuals are queried by default * * Since: 1.2 */ gboolean clutter_x11_get_use_argb_visual (void) { return clutter_enable_argb; } /** * clutter_x11_set_use_stereo_stage: * @use_stereo: %TRUE if the stereo stages should be used if possible. * * Sets whether the backend object for Clutter stages, will, * if possible, be created with the ability to support stereo drawing * (drawing separate images for the left and right eyes). * * This function must be called before clutter_init() is called. * During paint callbacks, cogl_framebuffer_is_stereo() can be called * on the framebuffer retrieved by cogl_get_draw_framebuffer() to * determine if stereo support was successfully enabled, and * cogl_framebuffer_set_stereo_mode() to determine which buffers * will be drawn to. * * Note that this function *does not* cause the stage to be drawn * multiple times with different perspective transformations and thus * appear in 3D, it simply enables individual ClutterActors to paint * different images for the left and and right eye. * * Since: 1.22 */ void clutter_x11_set_use_stereo_stage (gboolean use_stereo) { if (_clutter_context_is_initialized ()) { g_warning ("%s() can only be used before calling clutter_init()", G_STRFUNC); return; } CLUTTER_NOTE (BACKEND, "STEREO stages are %s", use_stereo ? "enabled" : "disabled"); clutter_enable_stereo = use_stereo; } /** * clutter_x11_get_use_stereo_stage: * * Retrieves whether the Clutter X11 backend will create stereo * stages if possible. * * Return value: %TRUE if stereo stages are used if possible * * Since: 1.22 */ gboolean clutter_x11_get_use_stereo_stage (void) { return clutter_enable_stereo; } XVisualInfo * _clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11) { return cogl_clutter_winsys_xlib_get_visual_info (); } /** * clutter_x11_get_visual_info: (skip) * * Retrieves the `XVisualInfo` used by the Clutter X11 backend. * * Return value: (transfer full): a `XVisualInfo`, or `None`. * The returned value should be freed using `XFree()` when done * * Since: 1.2 */ XVisualInfo * clutter_x11_get_visual_info (void) { ClutterBackendX11 *backend_x11; ClutterBackend *backend; backend = clutter_get_default_backend (); if (!CLUTTER_IS_BACKEND_X11 (backend)) { g_critical ("The Clutter backend is not a X11 backend."); return NULL; } backend_x11 = CLUTTER_BACKEND_X11 (backend); return _clutter_backend_x11_get_visual_info (backend_x11); } gboolean _clutter_x11_input_device_translate_screen_coord (ClutterInputDevice *device, gint stage_root_x, gint stage_root_y, guint index_, gdouble value, gdouble *axis_value) { ClutterAxisInfo *info; ClutterBackendX11 *backend_x11; gdouble width, scale, offset; backend_x11 = CLUTTER_BACKEND_X11 (device->backend); if (device->axes == NULL || index_ >= device->axes->len) return FALSE; info = &g_array_index (device->axes, ClutterAxisInfo, index_); if (!(info->axis == CLUTTER_INPUT_AXIS_X || info->axis == CLUTTER_INPUT_AXIS_Y)) return FALSE; width = info->max_value - info->min_value; if (info->axis == CLUTTER_INPUT_AXIS_X) { if (width > 0) scale = backend_x11->xscreen_width / width; else scale = 1; offset = - stage_root_x; } else { if (width > 0) scale = backend_x11->xscreen_height / width; else scale = 1; offset = - stage_root_y; } if (axis_value) *axis_value = offset + scale * (value - info->min_value); return TRUE; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-xkb-a11y-x11.h���������������������������������������������0000664�0001750�0001750�00000002507�14211404421�022512� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * * Copyright © 2001 Ximian, Inc. * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> * Copyright (C) 2017 Red Hat * * 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 CLUTTER_XKB_A11Y_X11_H #define CLUTTER_XKB_A11Y_X11_H #include "clutter-device-manager-private.h" #include "clutter-backend-x11.h" #include <X11/Xlib.h> void clutter_device_manager_x11_apply_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *kbd_a11y_settings); gboolean clutter_device_manager_x11_a11y_init (ClutterDeviceManager *device_manager); #endif /* CLUTTER_XKB_A11Y_X11_H */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-input-device-core-x11.h������������������������������������0000664�0001750�0001750�00000003036�14211404421�024475� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_INPUT_DEVICE_X11_H__ #define __CLUTTER_INPUT_DEVICE_X11_H__ #include <clutter/clutter-input-device.h> #include <X11/Xlib.h> #include "clutter-stage-x11.h" G_BEGIN_DECLS #define CLUTTER_TYPE_INPUT_DEVICE_X11 (_clutter_input_device_x11_get_type ()) #define CLUTTER_INPUT_DEVICE_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11, ClutterInputDeviceX11)) #define CLUTTER_IS_INPUT_DEVICE_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11)) typedef struct _ClutterInputDeviceX11 ClutterInputDeviceX11; GType _clutter_input_device_x11_get_type (void) G_GNUC_CONST; G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_X11_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-virtual-input-device-x11.h���������������������������������0000664�0001750�0001750�00000002454�14211404421�025236� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifndef __CLUTTER_VIRTUAL_INPUT_DEVICE_X11_H__ #define __CLUTTER_VIRTUAL_INPUT_DEVICE_X11_H__ #include "clutter-virtual-input-device.h" #define CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_X11 (clutter_virtual_input_device_x11_get_type ()) G_DECLARE_FINAL_TYPE (ClutterVirtualInputDeviceX11, clutter_virtual_input_device_x11, CLUTTER, VIRTUAL_INPUT_DEVICE_X11, ClutterVirtualInputDevice) #endif /* __CLUTTER_VIRTUAL_INPUT_DEVICE_X11_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/x11/clutter-settings-x11.h���������������������������������������������0000664�0001750�0001750�00000001705�14211404421�023014� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_SETTINGS_X11_H__ #define __CLUTTER_SETTINGS_X11_H__ /* XSETTINGS key names to ClutterSettings properties */ static const struct { const char *xsetting_name; const char *settings_property; } _clutter_settings_map[] = { { "Net/DoubleClickDistance", "double-click-distance" }, { "Net/DndDragThreshold", "dnd-drag-threshold" }, { "Gtk/FontName", "font-name" }, { "Xft/Antialias", "font-antialias" }, { "Xft/Hinting", "font-hinting" }, { "Xft/HintStyle", "font-hint-style" }, { "Xft/RGBA", "font-subpixel-order" }, { "Fontconfig/Timestamp", "fontconfig-timestamp" }, }; static const gint _n_clutter_settings_map = G_N_ELEMENTS (_clutter_settings_map); #define CLUTTER_SETTING_X11_NAME(id) (_clutter_settings_map[(id)].xsetting_name) #define CLUTTER_SETTING_PROPERTY(id) (_clutter_settings_map[(id)].settings_property) #endif /* __CLUTTER_SETTINGS_X11_H__ */ �����������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-property-transition.c������������������������������������������0000664�0001750�0001750�00000026045�14211404421�024207� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-property-transition * @Title: ClutterPropertyTransition * @Short_Description: Property transitions * * #ClutterPropertyTransition is a specialized #ClutterTransition that * can be used to tween a property of a #ClutterAnimatable instance. * * #ClutterPropertyTransition is available since Clutter 1.10 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-property-transition.h" #include "clutter-animatable.h" #include "clutter-debug.h" #include "clutter-interval.h" #include "clutter-private.h" #include "clutter-transition.h" struct _ClutterPropertyTransitionPrivate { char *property_name; GParamSpec *pspec; }; enum { PROP_0, PROP_PROPERTY_NAME, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterPropertyTransition, clutter_property_transition, CLUTTER_TYPE_TRANSITION) static inline void clutter_property_transition_ensure_interval (ClutterPropertyTransition *transition, ClutterAnimatable *animatable, ClutterInterval *interval) { ClutterPropertyTransitionPrivate *priv = transition->priv; GValue *value_p; if (clutter_interval_is_valid (interval)) return; /* if no initial value has been set, use the current value */ value_p = clutter_interval_peek_initial_value (interval); if (!G_IS_VALUE (value_p)) { g_value_init (value_p, clutter_interval_get_value_type (interval)); clutter_animatable_get_initial_state (animatable, priv->property_name, value_p); } /* if no final value has been set, use the current value */ value_p = clutter_interval_peek_final_value (interval); if (!G_IS_VALUE (value_p)) { g_value_init (value_p, clutter_interval_get_value_type (interval)); clutter_animatable_get_initial_state (animatable, priv->property_name, value_p); } } static void clutter_property_transition_attached (ClutterTransition *transition, ClutterAnimatable *animatable) { ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition); ClutterPropertyTransitionPrivate *priv = self->priv; ClutterInterval *interval; if (priv->property_name == NULL) return; priv->pspec = clutter_animatable_find_property (animatable, priv->property_name); if (priv->pspec == NULL) return; interval = clutter_transition_get_interval (transition); if (interval == NULL) return; clutter_property_transition_ensure_interval (self, animatable, interval); } static void clutter_property_transition_detached (ClutterTransition *transition, ClutterAnimatable *animatable) { ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition); ClutterPropertyTransitionPrivate *priv = self->priv; priv->pspec = NULL; } static void clutter_property_transition_compute_value (ClutterTransition *transition, ClutterAnimatable *animatable, ClutterInterval *interval, gdouble progress) { ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (transition); ClutterPropertyTransitionPrivate *priv = self->priv; GValue value = G_VALUE_INIT; GType p_type, i_type; gboolean res; /* if we have a GParamSpec we also have an animatable instance */ if (priv->pspec == NULL) return; clutter_property_transition_ensure_interval (self, animatable, interval); p_type = G_PARAM_SPEC_VALUE_TYPE (priv->pspec); i_type = clutter_interval_get_value_type (interval); g_value_init (&value, i_type); res = clutter_animatable_interpolate_value (animatable, priv->property_name, interval, progress, &value); if (res) { if (i_type != p_type || g_type_is_a (i_type, p_type)) { if (g_value_type_transformable (i_type, p_type)) { GValue transform = G_VALUE_INIT; g_value_init (&transform, p_type); if (g_value_transform (&value, &transform)) { clutter_animatable_set_final_state (animatable, priv->property_name, &transform); } else g_warning ("%s: Unable to convert a value of type '%s' from " "the value type '%s' of the interval.", G_STRLOC, g_type_name (p_type), g_type_name (i_type)); g_value_unset (&transform); } } else clutter_animatable_set_final_state (animatable, priv->property_name, &value); } g_value_unset (&value); } static void clutter_property_transition_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterPropertyTransition *self = CLUTTER_PROPERTY_TRANSITION (gobject); switch (prop_id) { case PROP_PROPERTY_NAME: clutter_property_transition_set_property_name (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_property_transition_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterPropertyTransitionPrivate *priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv; switch (prop_id) { case PROP_PROPERTY_NAME: g_value_set_string (value, priv->property_name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_property_transition_finalize (GObject *gobject) { ClutterPropertyTransitionPrivate *priv; priv = CLUTTER_PROPERTY_TRANSITION (gobject)->priv; free (priv->property_name); G_OBJECT_CLASS (clutter_property_transition_parent_class)->finalize (gobject); } static void clutter_property_transition_class_init (ClutterPropertyTransitionClass *klass) { ClutterTransitionClass *transition_class = CLUTTER_TRANSITION_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); transition_class->attached = clutter_property_transition_attached; transition_class->detached = clutter_property_transition_detached; transition_class->compute_value = clutter_property_transition_compute_value; gobject_class->set_property = clutter_property_transition_set_property; gobject_class->get_property = clutter_property_transition_get_property; gobject_class->finalize = clutter_property_transition_finalize; /** * ClutterPropertyTransition:property-name: * * The name of the property of a #ClutterAnimatable to animate. * * Since: 1.10 */ obj_props[PROP_PROPERTY_NAME] = g_param_spec_string ("property-name", P_("Property Name"), P_("The name of the property to animate"), NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_property_transition_init (ClutterPropertyTransition *self) { self->priv = clutter_property_transition_get_instance_private (self); } /** * clutter_property_transition_new: * @property_name: (allow-none): a property of @animatable, or %NULL * * Creates a new #ClutterPropertyTransition. * * Return value: (transfer full): the newly created #ClutterPropertyTransition. * Use g_object_unref() when done * * Since: 1.10 */ ClutterTransition * clutter_property_transition_new (const char *property_name) { return g_object_new (CLUTTER_TYPE_PROPERTY_TRANSITION, "property-name", property_name, NULL); } /** * clutter_property_transition_set_property_name: * @transition: a #ClutterPropertyTransition * @property_name: (allow-none): a property name * * Sets the #ClutterPropertyTransition:property-name property of @transition. * * Since: 1.10 */ void clutter_property_transition_set_property_name (ClutterPropertyTransition *transition, const char *property_name) { ClutterPropertyTransitionPrivate *priv; ClutterAnimatable *animatable; g_return_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition)); priv = transition->priv; if (g_strcmp0 (priv->property_name, property_name) == 0) return; free (priv->property_name); priv->property_name = g_strdup (property_name); priv->pspec = NULL; animatable = clutter_transition_get_animatable (CLUTTER_TRANSITION (transition)); if (animatable != NULL) { priv->pspec = clutter_animatable_find_property (animatable, priv->property_name); } g_object_notify_by_pspec (G_OBJECT (transition), obj_props[PROP_PROPERTY_NAME]); } /** * clutter_property_transition_get_property_name: * @transition: a #ClutterPropertyTransition * * Retrieves the value of the #ClutterPropertyTransition:property-name * property. * * Return value: the name of the property being animated, or %NULL if * none is set. The returned string is owned by the @transition and * it should not be freed. * * Since: 1.10 */ const char * clutter_property_transition_get_property_name (ClutterPropertyTransition *transition) { g_return_val_if_fail (CLUTTER_IS_PROPERTY_TRANSITION (transition), NULL); return transition->priv->property_name; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-device-manager.h�����������������������������������������������0000664�0001750�0001750�00000014721�14211404421�023005� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_DEVICE_MANAGER_H__ #define __CLUTTER_DEVICE_MANAGER_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-input-device.h> #include <clutter/clutter-stage.h> G_BEGIN_DECLS #define CLUTTER_TYPE_DEVICE_MANAGER (clutter_device_manager_get_type ()) #define CLUTTER_DEVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManager)) #define CLUTTER_IS_DEVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER)) #define CLUTTER_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManagerClass)) #define CLUTTER_IS_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER)) #define CLUTTER_DEVICE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManagerClass)) typedef struct _ClutterDeviceManager ClutterDeviceManager; typedef struct _ClutterDeviceManagerPrivate ClutterDeviceManagerPrivate; typedef struct _ClutterDeviceManagerClass ClutterDeviceManagerClass; /** * ClutterVirtualDeviceType: */ typedef enum _ClutterVirtualDeviceType { CLUTTER_VIRTUAL_DEVICE_TYPE_NONE = 0, CLUTTER_VIRTUAL_DEVICE_TYPE_KEYBOARD = 1 << 0, CLUTTER_VIRTUAL_DEVICE_TYPE_POINTER = 1 << 1, CLUTTER_VIRTUAL_DEVICE_TYPE_TOUCHSCREEN = 1 << 2, } ClutterVirtualDeviceType; /** * ClutterKbdA11ySettings: * * The #ClutterKbdA11ySettings structure contains keyboard accessibility * settings * */ typedef struct _ClutterKbdA11ySettings { ClutterKeyboardA11yFlags controls; gint slowkeys_delay; gint debounce_delay; gint timeout_delay; gint mousekeys_init_delay; gint mousekeys_max_speed; gint mousekeys_accel_time; } ClutterKbdA11ySettings; /** * ClutterDeviceManager: * * The #ClutterDeviceManager structure contains only private data * * Since: 1.2 */ struct _ClutterDeviceManager { /*< private >*/ GObject parent_instance; ClutterDeviceManagerPrivate *priv; }; /** * ClutterDeviceManagerClass: * * The #ClutterDeviceManagerClass structure contains only private data * * Since: 1.2 */ struct _ClutterDeviceManagerClass { /*< private >*/ GObjectClass parent_class; const GSList * (* get_devices) (ClutterDeviceManager *device_manager); ClutterInputDevice *(* get_core_device) (ClutterDeviceManager *device_manager, ClutterInputDeviceType device_type); ClutterInputDevice *(* get_device) (ClutterDeviceManager *device_manager, gint device_id); void (* add_device) (ClutterDeviceManager *manager, ClutterInputDevice *device); void (* remove_device) (ClutterDeviceManager *manager, ClutterInputDevice *device); void (* select_stage_events) (ClutterDeviceManager *manager, ClutterStage *stage); ClutterVirtualInputDevice *(* create_virtual_device) (ClutterDeviceManager *device_manager, ClutterInputDeviceType device_type); ClutterVirtualDeviceType (* get_supported_virtual_device_types) (ClutterDeviceManager *device_manager); void (* compress_motion) (ClutterDeviceManager *device_manger, ClutterEvent *event, const ClutterEvent *to_discard); /* Keyboard accessbility */ void (* apply_kbd_a11y_settings) (ClutterDeviceManager *device_manger, ClutterKbdA11ySettings *settings); /* padding */ gpointer _padding[6]; }; CLUTTER_AVAILABLE_IN_1_2 GType clutter_device_manager_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 ClutterDeviceManager *clutter_device_manager_get_default (void); CLUTTER_AVAILABLE_IN_1_2 GSList * clutter_device_manager_list_devices (ClutterDeviceManager *device_manager); CLUTTER_AVAILABLE_IN_1_2 const GSList * clutter_device_manager_peek_devices (ClutterDeviceManager *device_manager); CLUTTER_AVAILABLE_IN_1_2 ClutterInputDevice * clutter_device_manager_get_device (ClutterDeviceManager *device_manager, gint device_id); CLUTTER_AVAILABLE_IN_1_2 ClutterInputDevice * clutter_device_manager_get_core_device (ClutterDeviceManager *device_manager, ClutterInputDeviceType device_type); CLUTTER_AVAILABLE_IN_ALL ClutterVirtualInputDevice *clutter_device_manager_create_virtual_device (ClutterDeviceManager *device_manager, ClutterInputDeviceType device_type); CLUTTER_AVAILABLE_IN_ALL ClutterVirtualDeviceType clutter_device_manager_get_supported_virtual_device_types (ClutterDeviceManager *device_manager); CLUTTER_AVAILABLE_IN_ALL void clutter_device_manager_set_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *settings); CLUTTER_AVAILABLE_IN_ALL void clutter_device_manager_get_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *settings); G_END_DECLS #endif /* __CLUTTER_DEVICE_MANAGER_H__ */ �����������������������������������������������muffin-5.2.1/clutter/clutter/clutter-layout-manager.c�����������������������������������������������0000664�0001750�0001750�00000106152�14211404421�023056� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-layout-manager * @short_description: Layout managers base class * * #ClutterLayoutManager is a base abstract class for layout managers. A * layout manager implements the layouting policy for a composite or a * container actor: it controls the preferred size of the actor to which * it has been paired, and it controls the allocation of its children. * * Any composite or container #ClutterActor subclass can delegate the * layouting of its children to a #ClutterLayoutManager. Clutter provides * a generic container using #ClutterLayoutManager called #ClutterBox. * * Clutter provides some simple #ClutterLayoutManager sub-classes, like * #ClutterFlowLayout and #ClutterBinLayout. * * ## Implementing a ClutterLayoutManager * The implementation of a layout manager does not differ from the * implementation of the size requisition and allocation bits of * #ClutterActor, so you should read the relative documentation * forr subclassing #ClutterActor. * * The layout manager implementation can hold a back pointer to the * #ClutterContainer by implementing the #ClutterLayoutManagerClass.set_container() * virtual function. The layout manager should not hold a real reference (i.e. * call g_object_ref()) on the container actor, to avoid reference cycles. * * If a layout manager has properties affecting the layout policies then it should * emit the #ClutterLayoutManager::layout-changed signal on itself by using the * clutter_layout_manager_layout_changed() function whenever one of these properties * changes. * * ## Layout Properties * * If a layout manager has layout properties, that is properties that * should exist only as the result of the presence of a specific (layout * manager, container actor, child actor) combination, and it wishes to store * those properties inside a #ClutterLayoutMeta, then it should override the * #ClutterLayoutManagerClass.get_child_meta_type() virtual function to return * the #GType of the #ClutterLayoutMeta sub-class used to store the layout * properties; optionally, the #ClutterLayoutManager sub-class might also * override the #ClutterLayoutManagerClass.create_child_meta() virtual function * to control how the #ClutterLayoutMeta instance is created, otherwise the * default implementation will be equivalent to: * * |[ * ClutterLayoutManagerClass *klass; * GType meta_type; * * klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); * meta_type = klass->get_child_meta_type (manager); * * return g_object_new (meta_type, * "manager", manager, * "container", container, * "actor", actor, * NULL); * ]| * * Where `manager` is the #ClutterLayoutManager, `container` is the * #ClutterContainer using the #ClutterLayoutManager, and `actor` is * the #ClutterActor child of the #ClutterContainer. * * ## Using ClutterLayoutManager with ClutterScript * * #ClutterLayoutManager instances can be created in the same way * as other objects in #ClutterScript; properties can be set using the * common syntax. * * Layout properties can be set on children of a container with * a #ClutterLayoutManager using the `layout::` modifier on the property * name, for instance: * * |[ * { * "type" : "ClutterBox", * "layout-manager" : { "type" : "ClutterTableLayout" }, * "children" : [ * { * "type" : "ClutterTexture", * "filename" : "image-00.png", * * "layout::row" : 0, * "layout::column" : 0, * "layout::x-align" : "left", * "layout::y-align" : "center", * "layout::x-expand" : true, * "layout::y-expand" : true * }, * { * "type" : "ClutterTexture", * "filename" : "image-01.png", * * "layout::row" : 0, * "layout::column" : 1, * "layout::x-align" : "right", * "layout::y-align" : "center", * "layout::x-expand" : true, * "layout::y-expand" : true * } * ] * } * ]| * * #ClutterLayoutManager is available since Clutter 1.2 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <glib-object.h> #include <gobject/gvaluecollector.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "deprecated/clutter-alpha.h" #include "clutter-debug.h" #include "clutter-layout-manager.h" #include "clutter-layout-meta.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-timeline.h" #define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \ GObject *_obj = G_OBJECT (m); \ g_warning ("Layout managers of type %s do not implement " \ "the ClutterLayoutManager::%s method", \ G_OBJECT_TYPE_NAME (_obj), \ (method)); } G_STMT_END enum { LAYOUT_CHANGED, LAST_SIGNAL }; G_DEFINE_ABSTRACT_TYPE (ClutterLayoutManager, clutter_layout_manager, G_TYPE_INITIALLY_UNOWNED) static GQuark quark_layout_meta = 0; static GQuark quark_layout_alpha = 0; static guint manager_signals[LAST_SIGNAL] = { 0, }; static void layout_manager_freeze_layout_change (ClutterLayoutManager *manager) { gpointer is_frozen; CLUTTER_NOTE (LAYOUT, "Freezing changes for manager '%s'[%p]", G_OBJECT_TYPE_NAME (manager), manager); is_frozen = g_object_get_data (G_OBJECT (manager), "freeze-change"); if (is_frozen == NULL) g_object_set_data (G_OBJECT (manager), "freeze-change", GUINT_TO_POINTER (1)); else { guint level = GPOINTER_TO_UINT (is_frozen) + 1; g_object_set_data (G_OBJECT (manager), "freeze-change", GUINT_TO_POINTER (level)); } } static void layout_manager_thaw_layout_change (ClutterLayoutManager *manager) { gpointer is_frozen; is_frozen = g_object_get_data (G_OBJECT (manager), "freeze-change"); if (is_frozen == NULL) g_critical (G_STRLOC ": Mismatched thaw; you have to call " "clutter_layout_manager_freeze_layout_change() prior to " "calling clutter_layout_manager_thaw_layout_change()"); else { guint level = GPOINTER_TO_UINT (is_frozen); g_assert (level > 0); CLUTTER_NOTE (LAYOUT, "Thawing changes for manager '%s'[%p]", G_OBJECT_TYPE_NAME (manager), manager); level -= 1; if (level == 0) g_object_set_data (G_OBJECT (manager), "freeze-change", NULL); else g_object_set_data (G_OBJECT (manager), "freeze-change", GUINT_TO_POINTER (level)); } } static void layout_manager_real_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "get_preferred_width"); if (min_width_p) *min_width_p = 0.0; if (nat_width_p) *nat_width_p = 0.0; } static void layout_manager_real_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "get_preferred_height"); if (min_height_p) *min_height_p = 0.0; if (nat_height_p) *nat_height_p = 0.0; } static void layout_manager_real_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "allocate"); } static void layout_manager_real_set_container (ClutterLayoutManager *manager, ClutterContainer *container) { if (container != NULL) g_object_set_data (G_OBJECT (container), "clutter-layout-manager", manager); } static ClutterLayoutMeta * layout_manager_real_create_child_meta (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor) { ClutterLayoutManagerClass *klass; GType meta_type; klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); meta_type = klass->get_child_meta_type (manager); /* provide a default implementation to reduce common code */ if (meta_type != G_TYPE_INVALID) { g_assert (g_type_is_a (meta_type, CLUTTER_TYPE_LAYOUT_META)); return g_object_new (meta_type, "manager", manager, "container", container, "actor", actor, NULL); } return NULL; } static GType layout_manager_real_get_child_meta_type (ClutterLayoutManager *manager) { return G_TYPE_INVALID; } /* XXX:2.0 - Remove */ static ClutterAlpha * layout_manager_real_begin_animation (ClutterLayoutManager *manager, guint duration, gulong mode) { ClutterTimeline *timeline; ClutterAlpha *alpha; alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha); if (alpha != NULL) { clutter_alpha_set_mode (alpha, mode); timeline = clutter_alpha_get_timeline (alpha); clutter_timeline_set_duration (timeline, duration); clutter_timeline_rewind (timeline); return alpha; }; timeline = clutter_timeline_new (duration); alpha = clutter_alpha_new_full (timeline, mode); /* let the alpha take ownership of the timeline */ g_object_unref (timeline); g_signal_connect_swapped (timeline, "completed", G_CALLBACK (clutter_layout_manager_end_animation), manager); g_signal_connect_swapped (timeline, "new-frame", G_CALLBACK (clutter_layout_manager_layout_changed), manager); g_object_set_qdata_full (G_OBJECT (manager), quark_layout_alpha, alpha, (GDestroyNotify) g_object_unref); clutter_timeline_start (timeline); return alpha; } /* XXX:2.0 - Remove */ static gdouble layout_manager_real_get_animation_progress (ClutterLayoutManager *manager) { ClutterAlpha *alpha; alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha); if (alpha == NULL) return 1.0; return clutter_alpha_get_alpha (alpha); } /* XXX:2.0 - Remove */ static void layout_manager_real_end_animation (ClutterLayoutManager *manager) { ClutterTimeline *timeline; ClutterAlpha *alpha; alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha); if (alpha == NULL) return; timeline = clutter_alpha_get_timeline (alpha); g_assert (timeline != NULL); if (clutter_timeline_is_playing (timeline)) clutter_timeline_stop (timeline); g_signal_handlers_disconnect_by_func (timeline, G_CALLBACK (clutter_layout_manager_end_animation), manager); g_signal_handlers_disconnect_by_func (timeline, G_CALLBACK (clutter_layout_manager_layout_changed), manager); g_object_set_qdata (G_OBJECT (manager), quark_layout_alpha, NULL); clutter_layout_manager_layout_changed (manager); } static void clutter_layout_manager_class_init (ClutterLayoutManagerClass *klass) { quark_layout_meta = g_quark_from_static_string ("clutter-layout-manager-child-meta"); /* XXX:2.0 - Remove */ quark_layout_alpha = g_quark_from_static_string ("clutter-layout-manager-alpha"); klass->get_preferred_width = layout_manager_real_get_preferred_width; klass->get_preferred_height = layout_manager_real_get_preferred_height; klass->allocate = layout_manager_real_allocate; klass->create_child_meta = layout_manager_real_create_child_meta; klass->get_child_meta_type = layout_manager_real_get_child_meta_type; /* XXX:2.0 - Remove */ klass->begin_animation = layout_manager_real_begin_animation; klass->get_animation_progress = layout_manager_real_get_animation_progress; klass->end_animation = layout_manager_real_end_animation; klass->set_container = layout_manager_real_set_container; /** * ClutterLayoutManager::layout-changed: * @manager: the #ClutterLayoutManager that emitted the signal * * The ::layout-changed signal is emitted each time a layout manager * has been changed. Every #ClutterActor using the @manager instance * as a layout manager should connect a handler to the ::layout-changed * signal and queue a relayout on themselves: * * |[ * static void layout_changed (ClutterLayoutManager *manager, * ClutterActor *self) * { * clutter_actor_queue_relayout (self); * } * ... * self->manager = g_object_ref_sink (manager); * g_signal_connect (self->manager, "layout-changed", * G_CALLBACK (layout_changed), * self); * ]| * * Sub-classes of #ClutterLayoutManager that implement a layout that * can be controlled or changed using parameters should emit the * ::layout-changed signal whenever one of the parameters changes, * by using clutter_layout_manager_layout_changed(). * * Since: 1.2 */ manager_signals[LAYOUT_CHANGED] = g_signal_new (I_("layout-changed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterLayoutManagerClass, layout_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void clutter_layout_manager_init (ClutterLayoutManager *manager) { } /** * clutter_layout_manager_get_preferred_width: * @manager: a #ClutterLayoutManager * @container: the #ClutterContainer using @manager * @for_height: the height for which the width should be computed, or -1 * @min_width_p: (out) (allow-none): return location for the minimum width * of the layout, or %NULL * @nat_width_p: (out) (allow-none): return location for the natural width * of the layout, or %NULL * * Computes the minimum and natural widths of the @container according * to @manager. * * See also clutter_actor_get_preferred_width() * * Since: 1.2 */ void clutter_layout_manager_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { ClutterLayoutManagerClass *klass; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (CLUTTER_IS_CONTAINER (container)); klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); klass->get_preferred_width (manager, container, for_height, min_width_p, nat_width_p); } /** * clutter_layout_manager_get_preferred_height: * @manager: a #ClutterLayoutManager * @container: the #ClutterContainer using @manager * @for_width: the width for which the height should be computed, or -1 * @min_height_p: (out) (allow-none): return location for the minimum height * of the layout, or %NULL * @nat_height_p: (out) (allow-none): return location for the natural height * of the layout, or %NULL * * Computes the minimum and natural heights of the @container according * to @manager. * * See also clutter_actor_get_preferred_height() * * Since: 1.2 */ void clutter_layout_manager_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { ClutterLayoutManagerClass *klass; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (CLUTTER_IS_CONTAINER (container)); klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); klass->get_preferred_height (manager, container, for_width, min_height_p, nat_height_p); } /** * clutter_layout_manager_allocate: * @manager: a #ClutterLayoutManager * @container: the #ClutterContainer using @manager * @allocation: the #ClutterActorBox containing the allocated area * of @container * @flags: the allocation flags * * Allocates the children of @container given an area * * See also clutter_actor_allocate() * * Since: 1.2 */ void clutter_layout_manager_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterLayoutManagerClass *klass; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (allocation != NULL); klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); klass->allocate (manager, container, allocation, flags); } /** * clutter_layout_manager_layout_changed: * @manager: a #ClutterLayoutManager * * Emits the #ClutterLayoutManager::layout-changed signal on @manager * * This function should only be called by implementations of the * #ClutterLayoutManager class * * Since: 1.2 */ void clutter_layout_manager_layout_changed (ClutterLayoutManager *manager) { gpointer is_frozen; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); is_frozen = g_object_get_data (G_OBJECT (manager), "freeze-change"); if (is_frozen == NULL) g_signal_emit (manager, manager_signals[LAYOUT_CHANGED], 0); else CLUTTER_NOTE (LAYOUT, "Layout manager '%s'[%p] has been frozen", G_OBJECT_TYPE_NAME (manager), manager); } /** * clutter_layout_manager_set_container: * @manager: a #ClutterLayoutManager * @container: (allow-none): a #ClutterContainer using @manager * * If the #ClutterLayoutManager sub-class allows it, allow * adding a weak reference of the @container using @manager * from within the layout manager * * The layout manager should not increase the reference * count of the @container * * Since: 1.2 */ void clutter_layout_manager_set_container (ClutterLayoutManager *manager, ClutterContainer *container) { ClutterLayoutManagerClass *klass; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (container == NULL || CLUTTER_IS_CONTAINER (container)); klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); if (klass->set_container) klass->set_container (manager, container); } GType _clutter_layout_manager_get_child_meta_type (ClutterLayoutManager *manager) { return CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager)->get_child_meta_type (manager); } static inline ClutterLayoutMeta * create_child_meta (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor) { ClutterLayoutManagerClass *klass; ClutterLayoutMeta *meta = NULL; layout_manager_freeze_layout_change (manager); klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); if (klass->get_child_meta_type (manager) != G_TYPE_INVALID) meta = klass->create_child_meta (manager, container, actor); layout_manager_thaw_layout_change (manager); return meta; } static inline ClutterLayoutMeta * get_child_meta (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor) { ClutterLayoutMeta *layout = NULL; layout = g_object_get_qdata (G_OBJECT (actor), quark_layout_meta); if (layout != NULL) { ClutterChildMeta *child = CLUTTER_CHILD_META (layout); if (layout->manager == manager && child->container == container && child->actor == actor) return layout; /* if the LayoutMeta referenced is not attached to the * layout manager then we simply ask the layout manager * to replace it with the right one */ } layout = create_child_meta (manager, container, actor); if (layout != NULL) { g_assert (CLUTTER_IS_LAYOUT_META (layout)); g_object_set_qdata_full (G_OBJECT (actor), quark_layout_meta, layout, (GDestroyNotify) g_object_unref); return layout; } return NULL; } /** * clutter_layout_manager_get_child_meta: * @manager: a #ClutterLayoutManager * @container: a #ClutterContainer using @manager * @actor: a #ClutterActor child of @container * * Retrieves the #ClutterLayoutMeta that the layout @manager associated * to the @actor child of @container, eventually by creating one if the * #ClutterLayoutManager supports layout properties * * Return value: (transfer none): a #ClutterLayoutMeta, or %NULL if the * #ClutterLayoutManager does not have layout properties. The returned * layout meta instance is owned by the #ClutterLayoutManager and it * should not be unreferenced * * Since: 1.0 */ ClutterLayoutMeta * clutter_layout_manager_get_child_meta (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor) { g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), NULL); g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); return get_child_meta (manager, container, actor); } static inline gboolean layout_set_property_internal (ClutterLayoutManager *manager, GObject *gobject, GParamSpec *pspec, const GValue *value) { if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) { g_warning ("%s: Child property '%s' of the layout manager of " "type '%s' is constructor-only", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager)); return FALSE; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("%s: Child property '%s' of the layout manager of " "type '%s' is not writable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager)); return FALSE; } g_object_set_property (gobject, pspec->name, value); return TRUE; } static inline gboolean layout_get_property_internal (ClutterLayoutManager *manager, GObject *gobject, GParamSpec *pspec, GValue *value) { if (!(pspec->flags & G_PARAM_READABLE)) { g_warning ("%s: Child property '%s' of the layout manager of " "type '%s' is not readable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager)); return FALSE; } g_object_get_property (gobject, pspec->name, value); return TRUE; } /** * clutter_layout_manager_child_set: * @manager: a #ClutterLayoutManager * @container: a #ClutterContainer using @manager * @actor: a #ClutterActor child of @container * @first_property: the first property name * @...: a list of property name and value pairs * * Sets a list of properties and their values on the #ClutterLayoutMeta * associated by @manager to a child of @container * * Languages bindings should use clutter_layout_manager_child_set_property() * instead * * Since: 1.2 */ void clutter_layout_manager_child_set (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *first_property, ...) { ClutterLayoutMeta *meta; GObjectClass *klass; const gchar *pname; va_list var_args; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (first_property != NULL); meta = get_child_meta (manager, container, actor); if (meta == NULL) { g_warning ("Layout managers of type '%s' do not support " "layout metadata", g_type_name (G_OBJECT_TYPE (manager))); return; } klass = G_OBJECT_GET_CLASS (meta); va_start (var_args, first_property); pname = first_property; while (pname) { GValue value = G_VALUE_INIT; GParamSpec *pspec; gchar *error; gboolean res; pspec = g_object_class_find_property (klass, pname); if (pspec == NULL) { g_warning ("%s: Layout managers of type '%s' have no layout " "property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (manager), pname); break; } G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec), var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); break; } res = layout_set_property_internal (manager, G_OBJECT (meta), pspec, &value); g_value_unset (&value); if (!res) break; pname = va_arg (var_args, gchar*); } va_end (var_args); } /** * clutter_layout_manager_child_set_property: * @manager: a #ClutterLayoutManager * @container: a #ClutterContainer using @manager * @actor: a #ClutterActor child of @container * @property_name: the name of the property to set * @value: a #GValue with the value of the property to set * * Sets a property on the #ClutterLayoutMeta created by @manager and * attached to a child of @container * * Since: 1.2 */ void clutter_layout_manager_child_set_property (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *property_name, const GValue *value) { ClutterLayoutMeta *meta; GObjectClass *klass; GParamSpec *pspec; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (property_name != NULL); g_return_if_fail (value != NULL); meta = get_child_meta (manager, container, actor); if (meta == NULL) { g_warning ("Layout managers of type '%s' do not support " "layout metadata", g_type_name (G_OBJECT_TYPE (manager))); return; } klass = G_OBJECT_GET_CLASS (meta); pspec = g_object_class_find_property (klass, property_name); if (pspec == NULL) { g_warning ("%s: Layout managers of type '%s' have no layout " "property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (manager), property_name); return; } layout_set_property_internal (manager, G_OBJECT (meta), pspec, value); } /** * clutter_layout_manager_child_get: * @manager: a #ClutterLayoutManager * @container: a #ClutterContainer using @manager * @actor: a #ClutterActor child of @container * @first_property: the name of the first property * @...: a list of property name and return location for the value pairs * * Retrieves the values for a list of properties out of the * #ClutterLayoutMeta created by @manager and attached to the * child of a @container * * Since: 1.2 */ void clutter_layout_manager_child_get (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *first_property, ...) { ClutterLayoutMeta *meta; GObjectClass *klass; const gchar *pname; va_list var_args; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (first_property != NULL); meta = get_child_meta (manager, container, actor); if (meta == NULL) { g_warning ("Layout managers of type '%s' do not support " "layout metadata", g_type_name (G_OBJECT_TYPE (manager))); return; } klass = G_OBJECT_GET_CLASS (meta); va_start (var_args, first_property); pname = first_property; while (pname) { GValue value = G_VALUE_INIT; GParamSpec *pspec; gchar *error; gboolean res; pspec = g_object_class_find_property (klass, pname); if (pspec == NULL) { g_warning ("%s: Layout managers of type '%s' have no layout " "property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (manager), pname); break; } g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); res = layout_get_property_internal (manager, G_OBJECT (meta), pspec, &value); if (!res) { g_value_unset (&value); break; } G_VALUE_LCOPY (&value, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); g_value_unset (&value); break; } g_value_unset (&value); pname = va_arg (var_args, gchar*); } va_end (var_args); } /** * clutter_layout_manager_child_get_property: * @manager: a #ClutterLayoutManager * @container: a #ClutterContainer using @manager * @actor: a #ClutterActor child of @container * @property_name: the name of the property to get * @value: a #GValue with the value of the property to get * * Gets a property on the #ClutterLayoutMeta created by @manager and * attached to a child of @container * * The #GValue must already be initialized to the type of the property * and has to be unset with g_value_unset() after extracting the real * value out of it * * Since: 1.2 */ void clutter_layout_manager_child_get_property (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *property_name, GValue *value) { ClutterLayoutMeta *meta; GObjectClass *klass; GParamSpec *pspec; g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (property_name != NULL); g_return_if_fail (value != NULL); meta = get_child_meta (manager, container, actor); if (meta == NULL) { g_warning ("Layout managers of type %s do not support " "layout metadata", g_type_name (G_OBJECT_TYPE (manager))); return; } klass = G_OBJECT_GET_CLASS (meta); pspec = g_object_class_find_property (klass, property_name); if (pspec == NULL) { g_warning ("%s: Layout managers of type '%s' have no layout " "property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (manager), property_name); return; } layout_get_property_internal (manager, G_OBJECT (meta), pspec, value); } /** * clutter_layout_manager_find_child_property: * @manager: a #ClutterLayoutManager * @name: the name of the property * * Retrieves the #GParamSpec for the layout property @name inside * the #ClutterLayoutMeta sub-class used by @manager * * Return value: (transfer none): a #GParamSpec describing the property, * or %NULL if no property with that name exists. The returned * #GParamSpec is owned by the layout manager and should not be * modified or freed * * Since: 1.2 */ GParamSpec * clutter_layout_manager_find_child_property (ClutterLayoutManager *manager, const gchar *name) { ClutterLayoutManagerClass *klass; GObjectClass *meta_klass; GParamSpec *pspec; GType meta_type; klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); meta_type = klass->get_child_meta_type (manager); if (meta_type == G_TYPE_INVALID) return NULL; meta_klass = g_type_class_ref (meta_type); pspec = g_object_class_find_property (meta_klass, name); g_type_class_unref (meta_klass); return pspec; } /** * clutter_layout_manager_list_child_properties: * @manager: a #ClutterLayoutManager * @n_pspecs: (out): return location for the number of returned * #GParamSpec<!-- -->s * * Retrieves all the #GParamSpec<!-- -->s for the layout properties * stored inside the #ClutterLayoutMeta sub-class used by @manager * * Return value: (transfer full) (array length=n_pspecs): the newly-allocated, * %NULL-terminated array of #GParamSpec<!-- -->s. Use free() to free the * resources allocated for the array * * Since: 1.2 */ GParamSpec ** clutter_layout_manager_list_child_properties (ClutterLayoutManager *manager, guint *n_pspecs) { ClutterLayoutManagerClass *klass; GObjectClass *meta_klass; GParamSpec **pspecs; GType meta_type; klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); meta_type = klass->get_child_meta_type (manager); if (meta_type == G_TYPE_INVALID) return NULL; meta_klass = g_type_class_ref (meta_type); pspecs = g_object_class_list_properties (meta_klass, n_pspecs); g_type_class_unref (meta_klass); return pspecs; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-animatable.h���������������������������������������������������0000664�0001750�0001750�00000012054�14211404421�022230� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_ANIMATABLE_H__ #define __CLUTTER_ANIMATABLE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_ANIMATABLE (clutter_animatable_get_type ()) #define CLUTTER_ANIMATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ANIMATABLE, ClutterAnimatable)) #define CLUTTER_IS_ANIMATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ANIMATABLE)) #define CLUTTER_ANIMATABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_ANIMATABLE, ClutterAnimatableIface)) typedef struct _ClutterAnimatableIface ClutterAnimatableIface; /** * ClutterAnimatable: * * #ClutterAnimatable is an opaque structure whose members cannot be directly * accessed * * Since: 1.0 */ /** * ClutterAnimatableIface: * @animate_property: virtual function for custom interpolation of a * property. This virtual function is deprecated * @find_property: virtual function for retrieving the #GParamSpec of * an animatable property * @get_initial_state: virtual function for retrieving the initial * state of an animatable property * @set_final_state: virtual function for setting the state of an * animatable property * @interpolate_value: virtual function for interpolating the progress * of a property * * Base interface for #GObject<!-- -->s that can be animated by a * a #ClutterAnimation. * * Since: 1.0 */ struct _ClutterAnimatableIface { /*< private >*/ GTypeInterface parent_iface; /*< public >*/ gboolean (* animate_property) (ClutterAnimatable *animatable, ClutterAnimation *animation, const gchar *property_name, const GValue *initial_value, const GValue *final_value, gdouble progress, GValue *value); GParamSpec *(* find_property) (ClutterAnimatable *animatable, const gchar *property_name); void (* get_initial_state) (ClutterAnimatable *animatable, const gchar *property_name, GValue *value); void (* set_final_state) (ClutterAnimatable *animatable, const gchar *property_name, const GValue *value); gboolean (* interpolate_value) (ClutterAnimatable *animatable, const gchar *property_name, ClutterInterval *interval, gdouble progress, GValue *value); }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_animatable_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 GParamSpec *clutter_animatable_find_property (ClutterAnimatable *animatable, const gchar *property_name); CLUTTER_AVAILABLE_IN_1_0 void clutter_animatable_get_initial_state (ClutterAnimatable *animatable, const gchar *property_name, GValue *value); CLUTTER_AVAILABLE_IN_1_0 void clutter_animatable_set_final_state (ClutterAnimatable *animatable, const gchar *property_name, const GValue *value); CLUTTER_AVAILABLE_IN_1_8 gboolean clutter_animatable_interpolate_value (ClutterAnimatable *animatable, const gchar *property_name, ClutterInterval *interval, gdouble progress, GValue *value); G_END_DECLS #endif /* __CLUTTER_ANIMATABLE_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-device-manager-private.h���������������������������������������0000664�0001750�0001750�00000030276�14211404421�024460� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_DEVICE_MANAGER_PRIVATE_H__ #define __CLUTTER_DEVICE_MANAGER_PRIVATE_H__ #include <clutter/clutter-backend.h> #include <clutter/clutter-device-manager.h> #include <clutter/clutter-event.h> G_BEGIN_DECLS typedef struct _ClutterAxisInfo { ClutterInputAxis axis; gdouble min_axis; gdouble max_axis; gdouble min_value; gdouble max_value; gdouble resolution; } ClutterAxisInfo; typedef struct _ClutterKeyInfo { guint keyval; ClutterModifierType modifiers; } ClutterKeyInfo; typedef struct _ClutterScrollInfo { guint axis_id; ClutterScrollDirection direction; gdouble increment; gdouble last_value; guint last_value_valid : 1; } ClutterScrollInfo; typedef struct _ClutterTouchInfo { ClutterEventSequence *sequence; ClutterActor *actor; gfloat current_x; gfloat current_y; } ClutterTouchInfo; struct _ClutterInputDevice { GObject parent_instance; gint id; ClutterInputDeviceType device_type; ClutterInputMode device_mode; gchar *device_name; ClutterDeviceManager *device_manager; ClutterBackend *backend; /* the associated device */ ClutterInputDevice *associated; GList *slaves; /* the actor underneath the pointer */ ClutterActor *cursor_actor; GHashTable *inv_touch_sequence_actors; /* the actor that has a grab in place for the device */ ClutterActor *pointer_grab_actor; ClutterActor *keyboard_grab_actor; GHashTable *sequence_grab_actors; GHashTable *inv_sequence_grab_actors; /* the current click count */ gint click_count; /* the stage the device is on */ ClutterStage *stage; /* the current state */ gfloat current_x; gfloat current_y; guint32 current_time; gint current_button_number; ClutterModifierType current_state; /* the current touch points states */ GHashTable *touch_sequences_info; /* the previous state, used for click count generation */ gint previous_x; gint previous_y; guint32 previous_time; gint previous_button_number; ClutterModifierType previous_state; GArray *axes; guint n_keys; GArray *keys; GArray *scroll_info; gchar *vendor_id; gchar *product_id; gchar *node_path; GPtrArray *tools; gint n_rings; gint n_strips; gint n_mode_groups; ClutterInputDeviceMapping mapping_mode; guint has_cursor : 1; guint is_enabled : 1; }; typedef void (*ClutterEmitInputDeviceEvent) (ClutterEvent *event, ClutterInputDevice *device); struct _ClutterInputDeviceClass { GObjectClass parent_class; gboolean (* keycode_to_evdev) (ClutterInputDevice *device, guint hardware_keycode, guint *evdev_keycode); void (* update_from_tool) (ClutterInputDevice *device, ClutterInputDeviceTool *tool); gboolean (* is_mode_switch_button) (ClutterInputDevice *device, guint group, guint button); gint (* get_group_n_modes) (ClutterInputDevice *device, gint group); gboolean (* is_grouped) (ClutterInputDevice *device, ClutterInputDevice *other_device); /* Keyboard accessbility */ void (* process_kbd_a11y_event) (ClutterEvent *event, ClutterInputDevice *device, ClutterEmitInputDeviceEvent emit_event_func); }; /* Platform-dependent interface */ typedef struct _ClutterEventExtender ClutterEventExtender; typedef struct _ClutterEventExtenderInterface ClutterEventExtenderInterface; #define CLUTTER_TYPE_EVENT_EXTENDER (clutter_event_extender_get_type ()) #define CLUTTER_EVENT_EXTENDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLUTTER_TYPE_EVENT_EXTENDER, ClutterEventExtender)) #define CLUTTER_IS_EVENT_EXTENDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLUTTER_TYPE_EVENT_EXTENDER)) #define CLUTTER_EVENT_EXTENDER_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), CLUTTER_TYPE_EVENT_EXTENDER, ClutterEventExtenderInterface)) struct _ClutterEventExtenderInterface { GTypeInterface g_iface; void (* copy_event_data) (ClutterEventExtender *event_extender, const ClutterEvent *src, ClutterEvent *dest); void (* free_event_data) (ClutterEventExtender *event_extender, ClutterEvent *event); }; GType clutter_event_extender_get_type (void) G_GNUC_CONST; /* device manager */ void _clutter_device_manager_add_device (ClutterDeviceManager *device_manager, ClutterInputDevice *device); void _clutter_device_manager_remove_device (ClutterDeviceManager *device_manager, ClutterInputDevice *device); void _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager); void _clutter_device_manager_select_stage_events (ClutterDeviceManager *device_manager, ClutterStage *stage); ClutterBackend *_clutter_device_manager_get_backend (ClutterDeviceManager *device_manager); void _clutter_device_manager_compress_motion (ClutterDeviceManager *device_manger, ClutterEvent *event, const ClutterEvent *to_discard); /* input device */ gboolean _clutter_input_device_has_sequence (ClutterInputDevice *device, ClutterEventSequence *sequence); void _clutter_input_device_add_event_sequence (ClutterInputDevice *device, ClutterEvent *event); void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device, ClutterEvent *event); void _clutter_input_device_set_coords (ClutterInputDevice *device, ClutterEventSequence *sequence, gfloat x, gfloat y, ClutterStage *stage); void _clutter_input_device_set_state (ClutterInputDevice *device, ClutterModifierType state); void _clutter_input_device_set_time (ClutterInputDevice *device, guint32 time_); void _clutter_input_device_set_stage (ClutterInputDevice *device, ClutterStage *stage); ClutterStage * _clutter_input_device_get_stage (ClutterInputDevice *device); void _clutter_input_device_set_actor (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterActor *actor, gboolean emit_crossing); ClutterActor * _clutter_input_device_update (ClutterInputDevice *device, ClutterEventSequence *sequence, gboolean emit_crossing); void _clutter_input_device_set_n_keys (ClutterInputDevice *device, guint n_keys); guint _clutter_input_device_add_axis (ClutterInputDevice *device, ClutterInputAxis axis, gdouble min_value, gdouble max_value, gdouble resolution); void _clutter_input_device_reset_axes (ClutterInputDevice *device); void _clutter_input_device_set_associated_device (ClutterInputDevice *device, ClutterInputDevice *associated); void _clutter_input_device_add_slave (ClutterInputDevice *master, ClutterInputDevice *slave); void _clutter_input_device_remove_slave (ClutterInputDevice *master, ClutterInputDevice *slave); gboolean _clutter_input_device_translate_axis (ClutterInputDevice *device, guint index_, gdouble value, gdouble *axis_value); void _clutter_input_device_add_scroll_info (ClutterInputDevice *device, guint index_, ClutterScrollDirection direction, gdouble increment); void _clutter_input_device_reset_scroll_info (ClutterInputDevice *device); gboolean _clutter_input_device_get_scroll_delta (ClutterInputDevice *device, guint index_, gdouble value, ClutterScrollDirection *direction_p, gdouble *delta_p); ClutterInputDeviceTool * clutter_input_device_lookup_tool (ClutterInputDevice *device, guint64 serial, ClutterInputDeviceToolType type); void clutter_input_device_add_tool (ClutterInputDevice *device, ClutterInputDeviceTool *tool); void clutter_input_device_update_from_tool (ClutterInputDevice *device, ClutterInputDeviceTool *tool); G_END_DECLS #endif /* __CLUTTER_DEVICE_MANAGER_PRIVATE_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-input-device-tool.c��������������������������������������������0000664�0001750�0001750�00000013240�14211404421�023473� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-input-device-tool.h" #include "clutter-private.h" typedef struct _ClutterInputDeviceToolPrivate ClutterInputDeviceToolPrivate; struct _ClutterInputDeviceToolPrivate { ClutterInputDeviceToolType type; guint64 serial; guint64 id; }; enum { PROP_0, PROP_TYPE, PROP_SERIAL, PROP_ID, PROP_LAST }; static GParamSpec *props[PROP_LAST] = { NULL, }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputDeviceTool, clutter_input_device_tool, G_TYPE_OBJECT) static void clutter_input_device_tool_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterInputDeviceTool *tool = CLUTTER_INPUT_DEVICE_TOOL (object); ClutterInputDeviceToolPrivate *priv; priv = clutter_input_device_tool_get_instance_private (tool); switch (prop_id) { case PROP_TYPE: priv->type = g_value_get_enum (value); break; case PROP_SERIAL: priv->serial = g_value_get_uint64 (value); break; case PROP_ID: priv->id = g_value_get_uint64 (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clutter_input_device_tool_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterInputDeviceTool *tool = CLUTTER_INPUT_DEVICE_TOOL (object); ClutterInputDeviceToolPrivate *priv; priv = clutter_input_device_tool_get_instance_private (tool); switch (prop_id) { case PROP_TYPE: g_value_set_enum (value, priv->type); break; case PROP_SERIAL: g_value_set_uint64 (value, priv->serial); break; case PROP_ID: g_value_set_uint64 (value, priv->id); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clutter_input_device_tool_class_init (ClutterInputDeviceToolClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_input_device_tool_set_property; gobject_class->get_property = clutter_input_device_tool_get_property; props[PROP_TYPE] = g_param_spec_enum ("type", P_("Tool type"), P_("Tool type"), CLUTTER_TYPE_INPUT_DEVICE_TOOL_TYPE, CLUTTER_INPUT_DEVICE_TOOL_NONE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_SERIAL] = g_param_spec_uint64 ("serial", P_("Tool serial"), P_("Tool serial"), 0, G_MAXUINT64, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_ID] = g_param_spec_uint64 ("id", P_("Tool ID"), P_("Tool ID"), 0, G_MAXUINT64, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (gobject_class, PROP_LAST, props); } static void clutter_input_device_tool_init (ClutterInputDeviceTool *tool) { } /** * clutter_input_device_tool_get_serial: * @tool: a #ClutterInputDeviceTool * * Gets the serial of this tool, this value can be used to identify a * physical tool (eg. a tablet pen) across program executions. * * Returns: The serial ID for this tool * * Since: 1.28 **/ guint64 clutter_input_device_tool_get_serial (ClutterInputDeviceTool *tool) { ClutterInputDeviceToolPrivate *priv; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), 0); priv = clutter_input_device_tool_get_instance_private (tool); return priv->serial; } /** * clutter_input_device_tool_get_tool_type: * @tool: a #ClutterInputDeviceTool * * Gets the tool type of this tool. * * Returns: The tool type of this tool * * Since: 1.28 **/ ClutterInputDeviceToolType clutter_input_device_tool_get_tool_type (ClutterInputDeviceTool *tool) { ClutterInputDeviceToolPrivate *priv; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), 0); priv = clutter_input_device_tool_get_instance_private (tool); return priv->type; } /** * clutter_input_device_tool_get_id: * @tool: a #ClutterInputDeviceTool * * Gets the ID of this tool, this value can be used to identify a * physical tool (eg. a tablet pen) across program executions. * * Returns: The tool ID for this tool **/ guint64 clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool) { ClutterInputDeviceToolPrivate *priv; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), 0); priv = clutter_input_device_tool_get_instance_private (tool); return priv->id; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-master-clock.h�������������������������������������������������0000664�0001750�0001750�00000007272�14211404421�022525� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Emmanuele Bassi <ebassi@linux.intel.com> * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_MASTER_CLOCK_H__ #define __CLUTTER_MASTER_CLOCK_H__ #include <clutter/clutter-timeline.h> G_BEGIN_DECLS #define CLUTTER_TYPE_MASTER_CLOCK (_clutter_master_clock_get_type ()) #define CLUTTER_MASTER_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClock)) #define CLUTTER_IS_MASTER_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MASTER_CLOCK)) #define CLUTTER_MASTER_CLOCK_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_MASTER_CLOCK, ClutterMasterClockIface)) typedef struct _ClutterMasterClock ClutterMasterClock; /* dummy */ typedef struct _ClutterMasterClockIface ClutterMasterClockIface; struct _ClutterMasterClockIface { /*< private >*/ GTypeInterface parent_iface; void (* add_timeline) (ClutterMasterClock *master_clock, ClutterTimeline *timeline); void (* remove_timeline) (ClutterMasterClock *master_clock, ClutterTimeline *timeline); void (* start_running) (ClutterMasterClock *master_clock); void (* ensure_next_iteration) (ClutterMasterClock *master_clock); void (* set_paused) (ClutterMasterClock *master_clock, gboolean paused); }; GType _clutter_master_clock_get_type (void) G_GNUC_CONST; ClutterMasterClock * _clutter_master_clock_get_default (void); void _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock, ClutterTimeline *timeline); void _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock, ClutterTimeline *timeline); void _clutter_master_clock_start_running (ClutterMasterClock *master_clock); void _clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock); void _clutter_master_clock_set_paused (ClutterMasterClock *master_clock, gboolean paused); void _clutter_timeline_advance (ClutterTimeline *timeline, gint64 tick_time); gint64 _clutter_timeline_get_delta (ClutterTimeline *timeline); void _clutter_timeline_do_tick (ClutterTimeline *timeline, gint64 tick_time); G_END_DECLS #endif /* __CLUTTER_MASTER_CLOCK_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-path.c���������������������������������������������������������0000664�0001750�0001750�00000121324�14211404421�021063� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2008 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-path * @short_description: An object describing a path with straight lines * and bezier curves. * * A #ClutterPath contains a description of a path consisting of * straight lines and bezier curves. This can be used in a * #ClutterBehaviourPath to animate an actor moving along the path. * * The path consists of a series of nodes. Each node is one of the * following four types: * * - %CLUTTER_PATH_MOVE_TO, changes the position of the path to the * given pair of coordinates. This is usually used as the first node * of a path to mark the start position. If it is used in the middle * of a path then the path will be disjoint and the actor will appear * to jump to the new position when animated. * - %CLUTTER_PATH_LINE_TO, creates a straight line from the previous * point to the given point. * - %CLUTTER_PATH_CURVE_TO, creates a bezier curve. The end of the * last node is used as the first control point and the three * subsequent coordinates given in the node as used as the other three. * -%CLUTTER_PATH_CLOSE, creates a straight line from the last node to * the last %CLUTTER_PATH_MOVE_TO node. This can be used to close a * path so that it will appear as a loop when animated. * * The first three types have the corresponding relative versions * %CLUTTER_PATH_REL_MOVE_TO, %CLUTTER_PATH_REL_LINE_TO and * %CLUTTER_PATH_REL_CURVE_TO. These are exactly the same except the * coordinates are given relative to the previous node instead of as * direct screen positions. * * You can build a path using the node adding functions such as * clutter_path_add_line_to(). Alternatively the path can be described * in a string using a subset of the SVG path syntax. See * clutter_path_add_string() for details. * * #ClutterPath is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <string.h> #include <stdarg.h> #include <math.h> #include <glib-object.h> #include "clutter-path.h" #include "clutter-types.h" #include "clutter-bezier.h" #include "clutter-private.h" #define CLUTTER_PATH_NODE_TYPE_IS_VALID(t) \ ((((t) & ~CLUTTER_PATH_RELATIVE) >= CLUTTER_PATH_MOVE_TO \ && ((t) & ~CLUTTER_PATH_RELATIVE) <= CLUTTER_PATH_CURVE_TO) \ || (t) == CLUTTER_PATH_CLOSE) enum { PROP_0, PROP_DESCRIPTION, PROP_LENGTH, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; typedef struct _ClutterPathNodeFull ClutterPathNodeFull; struct _ClutterPathNodeFull { ClutterPathNode k; ClutterBezier *bezier; guint length; }; struct _ClutterPathPrivate { GSList *nodes, *nodes_tail; gboolean nodes_dirty; guint total_length; }; /* Character tests that don't pay attention to the locale */ #define clutter_path_isspace(ch) memchr (" \f\n\r\t\v", (ch), 6) #define clutter_path_isdigit(ch) ((ch) >= '0' && (ch) <= '9') static ClutterPathNodeFull *clutter_path_node_full_new (void); static void clutter_path_node_full_free (ClutterPathNodeFull *node); static void clutter_path_finalize (GObject *object); static void clutter_value_transform_path_string (const GValue *src, GValue *dest); static void clutter_value_transform_string_path (const GValue *src, GValue *dest); G_DEFINE_BOXED_TYPE (ClutterPathNode, clutter_path_node, clutter_path_node_copy, clutter_path_node_free); G_DEFINE_TYPE_WITH_CODE (ClutterPath, clutter_path, G_TYPE_INITIALLY_UNOWNED, G_ADD_PRIVATE (ClutterPath) CLUTTER_REGISTER_VALUE_TRANSFORM_TO (G_TYPE_STRING, clutter_value_transform_path_string) CLUTTER_REGISTER_VALUE_TRANSFORM_FROM (G_TYPE_STRING, clutter_value_transform_string_path)); static void clutter_path_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterPath *path = CLUTTER_PATH (gobject); switch (prop_id) { case PROP_DESCRIPTION: g_value_take_string (value, clutter_path_get_description (path)); break; case PROP_LENGTH: g_value_set_uint (value, clutter_path_get_length (path)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_path_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterPath *path = CLUTTER_PATH (gobject); switch (prop_id) { case PROP_DESCRIPTION: if (!clutter_path_set_description (path, g_value_get_string (value))) g_warning ("Invalid path description"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_path_class_init (ClutterPathClass *klass) { GObjectClass *gobject_class = (GObjectClass *) klass; GParamSpec *pspec; gobject_class->get_property = clutter_path_get_property; gobject_class->set_property = clutter_path_set_property; gobject_class->finalize = clutter_path_finalize; pspec = g_param_spec_string ("description", "Description", "SVG-style description of the path", "", CLUTTER_PARAM_READWRITE); obj_props[PROP_DESCRIPTION] = pspec; g_object_class_install_property (gobject_class, PROP_DESCRIPTION, pspec); pspec = g_param_spec_uint ("length", "Length", "An approximation of the total length " "of the path.", 0, G_MAXUINT, 0, CLUTTER_PARAM_READABLE); obj_props[PROP_LENGTH] = pspec; g_object_class_install_property (gobject_class, PROP_LENGTH, pspec); } static void clutter_path_init (ClutterPath *self) { self->priv = clutter_path_get_instance_private (self); } static void clutter_value_transform_path_string (const GValue *src, GValue *dest) { gchar *string = clutter_path_get_description (src->data[0].v_pointer); g_value_take_string (dest, string); } static void clutter_value_transform_string_path (const GValue *src, GValue *dest) { ClutterPath *new_path; new_path = clutter_path_new_with_description (g_value_get_string (src)); g_value_take_object (dest, new_path); } static void clutter_path_finalize (GObject *object) { ClutterPath *self = (ClutterPath *) object; clutter_path_clear (self); G_OBJECT_CLASS (clutter_path_parent_class)->finalize (object); } /** * clutter_path_new: * * Creates a new #ClutterPath instance with no nodes. * * The object has a floating reference so if you add it to a * #ClutterBehaviourPath then you do not need to unref it. * * Return value: the newly created #ClutterPath * * Since: 1.0 */ ClutterPath * clutter_path_new (void) { ClutterPath *self = g_object_new (CLUTTER_TYPE_PATH, NULL); return self; } /** * clutter_path_new_with_description: * @desc: a string describing the path * * Creates a new #ClutterPath instance with the nodes described in * @desc. See clutter_path_add_string() for details of the format of * the string. * * The object has a floating reference so if you add it to a * #ClutterBehaviourPath then you do not need to unref it. * * Return value: the newly created #ClutterPath * * Since: 1.0 */ ClutterPath * clutter_path_new_with_description (const gchar *desc) { return g_object_new (CLUTTER_TYPE_PATH, "description", desc, NULL); } /** * clutter_path_clear: * @path: a #ClutterPath * * Removes all nodes from the path. * * Since: 1.0 */ void clutter_path_clear (ClutterPath *path) { ClutterPathPrivate *priv = path->priv; g_slist_foreach (priv->nodes, (GFunc) clutter_path_node_full_free, NULL); g_slist_free (priv->nodes); priv->nodes = priv->nodes_tail = NULL; priv->nodes_dirty = TRUE; } /* Takes ownership of the node */ static void clutter_path_add_node_full (ClutterPath *path, ClutterPathNodeFull *node) { ClutterPathPrivate *priv = path->priv; GSList *new_node; new_node = g_slist_prepend (NULL, node); if (priv->nodes_tail == NULL) priv->nodes = new_node; else priv->nodes_tail->next = new_node; priv->nodes_tail = new_node; priv->nodes_dirty = TRUE; } /* Helper function to make the rest of teh add_* functions shorter */ static void clutter_path_add_node_helper (ClutterPath *path, ClutterPathNodeType type, int num_coords, ...) { ClutterPathNodeFull *node; int i; va_list ap; node = clutter_path_node_full_new (); node->k.type = type; va_start (ap, num_coords); for (i = 0; i < num_coords; i++) { node->k.points[i].x = va_arg (ap, gint); node->k.points[i].y = va_arg (ap, gint); } va_end (ap); clutter_path_add_node_full (path, node); } /** * clutter_path_add_move_to: * @path: a #ClutterPath * @x: the x coordinate * @y: the y coordinate * * Adds a %CLUTTER_PATH_MOVE_TO type node to the path. This is usually * used as the first node in a path. It can also be used in the middle * of the path to cause the actor to jump to the new coordinate. * * Since: 1.0 */ void clutter_path_add_move_to (ClutterPath *path, gint x, gint y) { g_return_if_fail (CLUTTER_IS_PATH (path)); clutter_path_add_node_helper (path, CLUTTER_PATH_MOVE_TO, 1, x, y); } /** * clutter_path_add_rel_move_to: * @path: a #ClutterPath * @x: the x coordinate * @y: the y coordinate * * Same as clutter_path_add_move_to() except the coordinates are * relative to the previous node. * * Since: 1.0 */ void clutter_path_add_rel_move_to (ClutterPath *path, gint x, gint y) { g_return_if_fail (CLUTTER_IS_PATH (path)); clutter_path_add_node_helper (path, CLUTTER_PATH_REL_MOVE_TO, 1, x, y); } /** * clutter_path_add_line_to: * @path: a #ClutterPath * @x: the x coordinate * @y: the y coordinate * * Adds a %CLUTTER_PATH_LINE_TO type node to the path. This causes the * actor to move to the new coordinates in a straight line. * * Since: 1.0 */ void clutter_path_add_line_to (ClutterPath *path, gint x, gint y) { g_return_if_fail (CLUTTER_IS_PATH (path)); clutter_path_add_node_helper (path, CLUTTER_PATH_LINE_TO, 1, x, y); } /** * clutter_path_add_rel_line_to: * @path: a #ClutterPath * @x: the x coordinate * @y: the y coordinate * * Same as clutter_path_add_line_to() except the coordinates are * relative to the previous node. * * Since: 1.0 */ void clutter_path_add_rel_line_to (ClutterPath *path, gint x, gint y) { g_return_if_fail (CLUTTER_IS_PATH (path)); clutter_path_add_node_helper (path, CLUTTER_PATH_REL_LINE_TO, 1, x, y); } /** * clutter_path_add_curve_to: * @path: a #ClutterPath * @x_1: the x coordinate of the first control point * @y_1: the y coordinate of the first control point * @x_2: the x coordinate of the second control point * @y_2: the y coordinate of the second control point * @x_3: the x coordinate of the third control point * @y_3: the y coordinate of the third control point * * Adds a %CLUTTER_PATH_CURVE_TO type node to the path. This causes * the actor to follow a bezier from the last node to (@x_3, @y_3) using * (@x_1, @y_1) and (@x_2,@y_2) as control points. * * Since: 1.0 */ void clutter_path_add_curve_to (ClutterPath *path, gint x_1, gint y_1, gint x_2, gint y_2, gint x_3, gint y_3) { g_return_if_fail (CLUTTER_IS_PATH (path)); clutter_path_add_node_helper (path, CLUTTER_PATH_CURVE_TO, 3, x_1, y_1, x_2, y_2, x_3, y_3); } /** * clutter_path_add_rel_curve_to: * @path: a #ClutterPath * @x_1: the x coordinate of the first control point * @y_1: the y coordinate of the first control point * @x_2: the x coordinate of the second control point * @y_2: the y coordinate of the second control point * @x_3: the x coordinate of the third control point * @y_3: the y coordinate of the third control point * * Same as clutter_path_add_curve_to() except the coordinates are * relative to the previous node. * * Since: 1.0 */ void clutter_path_add_rel_curve_to (ClutterPath *path, gint x_1, gint y_1, gint x_2, gint y_2, gint x_3, gint y_3) { g_return_if_fail (CLUTTER_IS_PATH (path)); clutter_path_add_node_helper (path, CLUTTER_PATH_REL_CURVE_TO, 3, x_1, y_1, x_2, y_2, x_3, y_3); } /** * clutter_path_add_close: * @path: a #ClutterPath * * Adds a %CLUTTER_PATH_CLOSE type node to the path. This creates a * straight line from the last node to the last %CLUTTER_PATH_MOVE_TO * type node. * * Since: 1.0 */ void clutter_path_add_close (ClutterPath *path) { g_return_if_fail (CLUTTER_IS_PATH (path)); clutter_path_add_node_helper (path, CLUTTER_PATH_CLOSE, 0); } static gboolean clutter_path_parse_number (const gchar **pin, gboolean allow_comma, gint *ret) { gint val = 0; gboolean negative = FALSE; gint digit_count = 0; const gchar *p = *pin; /* Skip leading spaces */ while (clutter_path_isspace (*p)) p++; /* Optional comma */ if (allow_comma && *p == ',') { p++; while (clutter_path_isspace (*p)) p++; } /* Optional sign */ if (*p == '+') p++; else if (*p == '-') { negative = TRUE; p++; } /* Some digits */ while (clutter_path_isdigit (*p)) { val = val * 10 + *p - '0'; digit_count++; p++; } /* We need at least one digit */ if (digit_count < 1) return FALSE; /* Optional fractional part which we ignore */ if (*p == '.') { p++; digit_count = 0; while (clutter_path_isdigit (*p)) { digit_count++; p++; } /* If there is a fractional part then it also needs at least one digit */ if (digit_count < 1) return FALSE; } *pin = p; *ret = negative ? -val : val; return TRUE; } static gboolean clutter_path_parse_description (const gchar *p, GSList **ret) { ClutterPathNodeFull *node; GSList *nodes = NULL; if (p == NULL || *p == '\0') return FALSE; while (TRUE) { /* Skip leading whitespace */ while (clutter_path_isspace (*p)) p++; /* It is not an error to end now */ if (*p == '\0') break; switch (*p) { case 'M': case 'm': case 'L': case 'l': node = clutter_path_node_full_new (); nodes = g_slist_prepend (nodes, node); node->k.type = (*p == 'M' ? CLUTTER_PATH_MOVE_TO : *p == 'm' ? CLUTTER_PATH_REL_MOVE_TO : *p == 'L' ? CLUTTER_PATH_LINE_TO : CLUTTER_PATH_REL_LINE_TO); p++; if (!clutter_path_parse_number (&p, FALSE, &node->k.points[0].x) || !clutter_path_parse_number (&p, TRUE, &node->k.points[0].y)) goto fail; break; case 'C': case 'c': node = clutter_path_node_full_new (); nodes = g_slist_prepend (nodes, node); node->k.type = (*p == 'C' ? CLUTTER_PATH_CURVE_TO : CLUTTER_PATH_REL_CURVE_TO); p++; if (!clutter_path_parse_number (&p, FALSE, &node->k.points[0].x) || !clutter_path_parse_number (&p, TRUE, &node->k.points[0].y) || !clutter_path_parse_number (&p, TRUE, &node->k.points[1].x) || !clutter_path_parse_number (&p, TRUE, &node->k.points[1].y) || !clutter_path_parse_number (&p, TRUE, &node->k.points[2].x) || !clutter_path_parse_number (&p, TRUE, &node->k.points[2].y)) goto fail; break; case 'Z': case 'z': node = clutter_path_node_full_new (); nodes = g_slist_prepend (nodes, node); p++; node->k.type = CLUTTER_PATH_CLOSE; break; default: goto fail; } } *ret = g_slist_reverse (nodes); return TRUE; fail: g_slist_foreach (nodes, (GFunc) clutter_path_node_full_free, NULL); g_slist_free (nodes); return FALSE; } /* Takes ownership of the node list */ static void clutter_path_add_nodes (ClutterPath *path, GSList *nodes) { ClutterPathPrivate *priv = path->priv; if (priv->nodes_tail == NULL) priv->nodes = nodes; else priv->nodes_tail->next = nodes; while (nodes) { priv->nodes_tail = nodes; nodes = nodes->next; } priv->nodes_dirty = TRUE; } /** * clutter_path_add_string: * @path: a #ClutterPath * @str: a string describing the new nodes * * Adds new nodes to the end of the path as described in @str. The * format is a subset of the SVG path format. Each node is represented * by a letter and is followed by zero, one or three pairs of * coordinates. The coordinates can be separated by spaces or a * comma. The types are: * * - `M`: Adds a %CLUTTER_PATH_MOVE_TO node. Takes one pair of coordinates. * - `L`: Adds a %CLUTTER_PATH_LINE_TO node. Takes one pair of coordinates. * - `C`: Adds a %CLUTTER_PATH_CURVE_TO node. Takes three pairs of coordinates. * - `z`: Adds a %CLUTTER_PATH_CLOSE node. No coordinates are needed. * * The M, L and C commands can also be specified in lower case which * means the coordinates are relative to the previous node. * * For example, to move an actor in a 100 by 100 pixel square centered * on the point 300,300 you could use the following path: * * |[ * M 250,350 l 0 -100 L 350,250 l 0 100 z * ]| * * If the path description isn't valid %FALSE will be returned and no * nodes will be added. * * Return value: %TRUE is the path description was valid or %FALSE * otherwise. * * Since: 1.0 */ gboolean clutter_path_add_string (ClutterPath *path, const gchar *str) { GSList *nodes; g_return_val_if_fail (CLUTTER_IS_PATH (path), FALSE); g_return_val_if_fail (str != NULL, FALSE); if (clutter_path_parse_description (str, &nodes)) { clutter_path_add_nodes (path, nodes); return TRUE; } else return FALSE; } /** * clutter_path_add_node: * @path: a #ClutterPath * @node: a #ClutterPathNode * * Adds @node to the end of the path. * * Since: 1.0 */ void clutter_path_add_node (ClutterPath *path, const ClutterPathNode *node) { ClutterPathNodeFull *node_full; g_return_if_fail (CLUTTER_IS_PATH (path)); g_return_if_fail (node != NULL); g_return_if_fail (CLUTTER_PATH_NODE_TYPE_IS_VALID (node->type)); node_full = clutter_path_node_full_new (); node_full->k = *node; clutter_path_add_node_full (path, node_full); } /** * clutter_path_add_cairo_path: * @path: a #ClutterPath * @cpath: a Cairo path * * Add the nodes of the Cairo path to the end of @path. * * Since: 1.0 */ void clutter_path_add_cairo_path (ClutterPath *path, const cairo_path_t *cpath) { int num_data; const cairo_path_data_t *p; g_return_if_fail (CLUTTER_IS_PATH (path)); g_return_if_fail (cpath != NULL); /* Iterate over each command in the cairo path */ for (num_data = cpath->num_data, p = cpath->data; num_data > 0; num_data -= p->header.length, p += p->header.length) { switch (p->header.type) { case CAIRO_PATH_MOVE_TO: g_assert (p->header.length >= 2); clutter_path_add_move_to (path, p[1].point.x, p[1].point.y); break; case CAIRO_PATH_LINE_TO: g_assert (p->header.length >= 2); clutter_path_add_line_to (path, p[1].point.x, p[1].point.y); break; case CAIRO_PATH_CURVE_TO: g_assert (p->header.length >= 4); clutter_path_add_curve_to (path, p[1].point.x, p[1].point.y, p[2].point.x, p[2].point.y, p[3].point.x, p[3].point.y); break; case CAIRO_PATH_CLOSE_PATH: clutter_path_add_close (path); } } } static void clutter_path_add_node_to_cairo_path (const ClutterPathNode *node, gpointer data) { cairo_t *cr = data; switch (node->type) { case CLUTTER_PATH_MOVE_TO: cairo_move_to (cr, node->points[0].x, node->points[0].y); break; case CLUTTER_PATH_LINE_TO: cairo_line_to (cr, node->points[0].x, node->points[0].y); break; case CLUTTER_PATH_CURVE_TO: cairo_curve_to (cr, node->points[0].x, node->points[0].y, node->points[1].x, node->points[1].y, node->points[2].x, node->points[2].y); break; case CLUTTER_PATH_REL_MOVE_TO: cairo_rel_move_to (cr, node->points[0].x, node->points[0].y); break; case CLUTTER_PATH_REL_LINE_TO: cairo_rel_line_to (cr, node->points[0].x, node->points[0].y); break; case CLUTTER_PATH_REL_CURVE_TO: cairo_rel_curve_to (cr, node->points[0].x, node->points[0].y, node->points[1].x, node->points[1].y, node->points[2].x, node->points[2].y); break; case CLUTTER_PATH_CLOSE: cairo_close_path (cr); } } /** * clutter_path_to_cairo_path: * @path: a #ClutterPath * @cr: a Cairo context * * Add the nodes of the ClutterPath to the path in the Cairo context. * * Since: 1.0 */ void clutter_path_to_cairo_path (ClutterPath *path, cairo_t *cr) { g_return_if_fail (CLUTTER_IS_PATH (path)); g_return_if_fail (cr != NULL); clutter_path_foreach (path, clutter_path_add_node_to_cairo_path, cr); } /** * clutter_path_get_n_nodes: * @path: a #ClutterPath * * Retrieves the number of nodes in the path. * * Return value: the number of nodes. * * Since: 1.0 */ guint clutter_path_get_n_nodes (ClutterPath *path) { ClutterPathPrivate *priv; g_return_val_if_fail (CLUTTER_IS_PATH (path), 0); priv = path->priv; return g_slist_length (priv->nodes); } /** * clutter_path_get_node: * @path: a #ClutterPath * @index_: the node number to retrieve * @node: (out): a location to store a copy of the node * * Retrieves the node of the path indexed by @index. * * Since: 1.0 */ void clutter_path_get_node (ClutterPath *path, guint index_, ClutterPathNode *node) { ClutterPathNodeFull *node_full; ClutterPathPrivate *priv; g_return_if_fail (CLUTTER_IS_PATH (path)); priv = path->priv; node_full = g_slist_nth_data (priv->nodes, index_); g_return_if_fail (node_full != NULL); *node = node_full->k; } /** * clutter_path_get_nodes: * @path: a #ClutterPath * * Returns a #GSList of #ClutterPathNode<!-- -->s. The list should be * freed with g_slist_free(). The nodes are owned by the path and * should not be freed. Altering the path may cause the nodes in the * list to become invalid so you should copy them if you want to keep * the list. * * Return value: (transfer container) (element-type Clutter.PathNode): a * list of nodes in the path. * * Since: 1.0 */ GSList * clutter_path_get_nodes (ClutterPath *path) { ClutterPathPrivate *priv; g_return_val_if_fail (CLUTTER_IS_PATH (path), NULL); priv = path->priv; return g_slist_copy (priv->nodes); } /** * clutter_path_foreach: * @path: a #ClutterPath * @callback: (scope call): the function to call with each node * @user_data: user data to pass to the function * * Calls a function for each node of the path. * * Since: 1.0 */ void clutter_path_foreach (ClutterPath *path, ClutterPathCallback callback, gpointer user_data) { ClutterPathPrivate *priv; g_return_if_fail (CLUTTER_IS_PATH (path)); priv = path->priv; g_slist_foreach (priv->nodes, (GFunc) callback, user_data); } /** * clutter_path_insert_node: * @path: a #ClutterPath * @index_: offset of where to insert the node * @node: the node to insert * * Inserts @node into the path before the node at the given offset. If * @index_ is negative it will append the node to the end of the path. * * Since: 1.0 */ void clutter_path_insert_node (ClutterPath *path, gint index_, const ClutterPathNode *node) { ClutterPathPrivate *priv; ClutterPathNodeFull *node_full; g_return_if_fail (CLUTTER_IS_PATH (path)); g_return_if_fail (node != NULL); g_return_if_fail (CLUTTER_PATH_NODE_TYPE_IS_VALID (node->type)); priv = path->priv; node_full = clutter_path_node_full_new (); node_full->k = *node; priv->nodes = g_slist_insert (priv->nodes, node_full, index_); if (priv->nodes_tail == NULL) priv->nodes_tail = priv->nodes; else if (priv->nodes_tail->next) priv->nodes_tail = priv->nodes_tail->next; priv->nodes_dirty = TRUE; } /** * clutter_path_remove_node: * @path: a #ClutterPath * @index_: index of the node to remove * * Removes the node at the given offset from the path. * * Since: 1.0 */ void clutter_path_remove_node (ClutterPath *path, guint index_) { ClutterPathPrivate *priv; GSList *node, *prev = NULL; g_return_if_fail (CLUTTER_IS_PATH (path)); priv = path->priv; for (node = priv->nodes; node && index_--; node = node->next) prev = node; if (node) { clutter_path_node_full_free (node->data); if (prev) prev->next = node->next; else priv->nodes = node->next; if (node == priv->nodes_tail) priv->nodes_tail = prev; g_slist_free_1 (node); priv->nodes_dirty = TRUE; } } /** * clutter_path_replace_node: * @path: a #ClutterPath * @index_: index to the existing node * @node: the replacement node * * Replaces the node at offset @index_ with @node. * * Since: 1.0 */ void clutter_path_replace_node (ClutterPath *path, guint index_, const ClutterPathNode *node) { ClutterPathPrivate *priv; ClutterPathNodeFull *node_full; g_return_if_fail (CLUTTER_IS_PATH (path)); g_return_if_fail (node != NULL); g_return_if_fail (CLUTTER_PATH_NODE_TYPE_IS_VALID (node->type)); priv = path->priv; if ((node_full = g_slist_nth_data (priv->nodes, index_))) { node_full->k = *node; priv->nodes_dirty = TRUE; } } /** * clutter_path_set_description: * @path: a #ClutterPath * @str: a string describing the path * * Replaces all of the nodes in the path with nodes described by * @str. See clutter_path_add_string() for details of the format. * * If the string is invalid then %FALSE is returned and the path is * unaltered. * * Return value: %TRUE is the path was valid, %FALSE otherwise. * * Since: 1.0 */ gboolean clutter_path_set_description (ClutterPath *path, const gchar *str) { GSList *nodes; g_return_val_if_fail (CLUTTER_IS_PATH (path), FALSE); g_return_val_if_fail (str != NULL, FALSE); if (clutter_path_parse_description (str, &nodes)) { clutter_path_clear (path); clutter_path_add_nodes (path, nodes); return TRUE; } else return FALSE; } /** * clutter_path_get_description: * @path: a #ClutterPath * * Returns a newly allocated string describing the path in the same * format as used by clutter_path_add_string(). * * Return value: a string description of the path. Free with free(). * * Since: 1.0 */ gchar * clutter_path_get_description (ClutterPath *path) { ClutterPathPrivate *priv; GString *str; GSList *l; g_return_val_if_fail (CLUTTER_IS_PATH (path), NULL); priv = path->priv; str = g_string_new (""); for (l = priv->nodes; l; l = l->next) { ClutterPathNodeFull *node = l->data; gchar letter = '?'; gint params = 0; gint i; switch (node->k.type) { case CLUTTER_PATH_MOVE_TO: letter = 'M'; params = 1; break; case CLUTTER_PATH_REL_MOVE_TO: letter = 'm'; params = 1; break; case CLUTTER_PATH_LINE_TO: letter = 'L'; params = 1; break; case CLUTTER_PATH_REL_LINE_TO: letter = 'l'; params = 1; break; case CLUTTER_PATH_CURVE_TO: letter = 'C'; params = 3; break; case CLUTTER_PATH_REL_CURVE_TO: letter = 'c'; params = 3; break; case CLUTTER_PATH_CLOSE: letter = 'z'; params = 0; break; } if (str->len > 0) g_string_append_c (str, ' '); g_string_append_c (str, letter); for (i = 0; i < params; i++) g_string_append_printf (str, " %i %i", node->k.points[i].x, node->k.points[i].y); } return g_string_free (str, FALSE); } static guint clutter_path_node_distance (const ClutterKnot *start, const ClutterKnot *end) { gint64 x_d, y_d; float t; g_return_val_if_fail (start != NULL, 0); g_return_val_if_fail (end != NULL, 0); if (clutter_knot_equal (start, end)) return 0; x_d = end->x - start->x; y_d = end->y - start->y; t = floorf (sqrtf ((x_d * x_d) + (y_d * y_d))); return (guint) t; } static void clutter_path_ensure_node_data (ClutterPath *path) { ClutterPathPrivate *priv = path->priv; /* Recalculate the nodes data if has changed */ if (priv->nodes_dirty) { GSList *l; ClutterKnot last_position = { 0, 0 }; ClutterKnot loop_start = { 0, 0 }; ClutterKnot points[3]; priv->total_length = 0; for (l = priv->nodes; l; l = l->next) { ClutterPathNodeFull *node = l->data; gboolean relative = (node->k.type & CLUTTER_PATH_RELATIVE) != 0; switch (node->k.type & ~CLUTTER_PATH_RELATIVE) { case CLUTTER_PATH_MOVE_TO: node->length = 0; /* Store the actual position in point[1] */ if (relative) { node->k.points[1].x = last_position.x + node->k.points[0].x; node->k.points[1].y = last_position.y + node->k.points[0].y; } else node->k.points[1] = node->k.points[0]; last_position = node->k.points[1]; loop_start = node->k.points[1]; break; case CLUTTER_PATH_LINE_TO: /* Use point[1] as the start point and point[2] as the end point */ node->k.points[1] = last_position; if (relative) { node->k.points[2].x = (node->k.points[1].x + node->k.points[0].x); node->k.points[2].y = (node->k.points[1].y + node->k.points[0].y); } else node->k.points[2] = node->k.points[0]; last_position = node->k.points[2]; node->length = clutter_path_node_distance (node->k.points + 1, node->k.points + 2); break; case CLUTTER_PATH_CURVE_TO: /* Convert to a bezier curve */ if (node->bezier == NULL) node->bezier = _clutter_bezier_new (); if (relative) { int i; for (i = 0; i < 3; i++) { points[i].x = last_position.x + node->k.points[i].x; points[i].y = last_position.y + node->k.points[i].y; } } else memcpy (points, node->k.points, sizeof (ClutterKnot) * 3); _clutter_bezier_init (node->bezier, last_position.x, last_position.y, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); last_position = points[2]; node->length = _clutter_bezier_get_length (node->bezier); break; case CLUTTER_PATH_CLOSE: /* Convert to a line to from last_point to loop_start */ node->k.points[1] = last_position; node->k.points[2] = loop_start; last_position = node->k.points[2]; node->length = clutter_path_node_distance (node->k.points + 1, node->k.points + 2); break; } priv->total_length += node->length; } priv->nodes_dirty = FALSE; } } /** * clutter_path_get_position: * @path: a #ClutterPath * @progress: a position along the path as a fraction of its length * @position: (out): location to store the position * * The value in @progress represents a position along the path where * 0.0 is the beginning and 1.0 is the end of the path. An * interpolated position is then stored in @position. * * Return value: index of the node used to calculate the position. * * Since: 1.0 */ guint clutter_path_get_position (ClutterPath *path, gdouble progress, ClutterKnot *position) { ClutterPathPrivate *priv; GSList *l; guint point_distance, length = 0, node_num = 0; ClutterPathNodeFull *node; g_return_val_if_fail (CLUTTER_IS_PATH (path), 0); g_return_val_if_fail (progress >= 0.0 && progress <= 1.0, 0); priv = path->priv; clutter_path_ensure_node_data (path); /* Special case if the path is empty, just return 0,0 for want of something better */ if (priv->nodes == NULL) { memset (position, 0, sizeof (ClutterKnot)); return 0; } /* Convert the progress to a length along the path */ point_distance = progress * priv->total_length; /* Find the node that covers this point */ for (l = priv->nodes; l->next && point_distance >= (((ClutterPathNodeFull *) l->data)->length + length); l = l->next) { length += ((ClutterPathNodeFull *) l->data)->length; node_num++; } node = l->data; /* Convert the point distance to a distance along the node */ point_distance -= length; if (point_distance > node->length) point_distance = node->length; switch (node->k.type & ~CLUTTER_PATH_RELATIVE) { case CLUTTER_PATH_MOVE_TO: *position = node->k.points[1]; break; case CLUTTER_PATH_LINE_TO: case CLUTTER_PATH_CLOSE: if (node->length == 0) *position = node->k.points[1]; else { position->x = (node->k.points[1].x + ((node->k.points[2].x - node->k.points[1].x) * (gint) point_distance / (gint) node->length)); position->y = (node->k.points[1].y + ((node->k.points[2].y - node->k.points[1].y) * (gint) point_distance / (gint) node->length)); } break; case CLUTTER_PATH_CURVE_TO: if (node->length == 0) *position = node->k.points[2]; else { _clutter_bezier_advance (node->bezier, point_distance * CLUTTER_BEZIER_MAX_LENGTH / node->length, position); } break; } return node_num; } /** * clutter_path_get_length: * @path: a #ClutterPath * * Retrieves an approximation of the total length of the path. * * Return value: the length of the path. * * Since: 1.0 */ guint clutter_path_get_length (ClutterPath *path) { g_return_val_if_fail (CLUTTER_IS_PATH (path), 0); clutter_path_ensure_node_data (path); return path->priv->total_length; } static ClutterPathNodeFull * clutter_path_node_full_new (void) { return g_slice_new0 (ClutterPathNodeFull); } static void clutter_path_node_full_free (ClutterPathNodeFull *node) { if (node->bezier) _clutter_bezier_free (node->bezier); g_slice_free (ClutterPathNodeFull, node); } /** * clutter_path_node_copy: * @node: a #ClutterPathNode * * Makes an allocated copy of a node. * * Return value: the copied node. * * Since: 1.0 */ ClutterPathNode * clutter_path_node_copy (const ClutterPathNode *node) { return g_slice_dup (ClutterPathNode, node); } /** * clutter_path_node_free: * @node: a #ClutterPathNode * * Frees the memory of an allocated node. * * Since: 1.0 */ void clutter_path_node_free (ClutterPathNode *node) { if (G_LIKELY (node)) g_slice_free (ClutterPathNode, node); } /** * clutter_path_node_equal: * @node_a: First node * @node_b: Second node * * Compares two nodes and checks if they are the same type with the * same coordinates. * * Return value: %TRUE if the nodes are the same. * * Since: 1.0 */ gboolean clutter_path_node_equal (const ClutterPathNode *node_a, const ClutterPathNode *node_b) { guint n_points, i; g_return_val_if_fail (node_a != NULL, FALSE); g_return_val_if_fail (node_b != NULL, FALSE); if (node_a->type != node_b->type) return FALSE; switch (node_a->type & ~CLUTTER_PATH_RELATIVE) { case CLUTTER_PATH_MOVE_TO: n_points = 1; break; case CLUTTER_PATH_LINE_TO: n_points = 1; break; case CLUTTER_PATH_CURVE_TO: n_points = 3; break; case CLUTTER_PATH_CLOSE: n_points = 0; break; default: return FALSE; } for (i = 0; i < n_points; i++) if (node_a->points[i].x != node_b->points[i].x || node_a->points[i].y != node_b->points[i].y) return FALSE; return TRUE; } G_DEFINE_BOXED_TYPE (ClutterKnot, clutter_knot, clutter_knot_copy, clutter_knot_free); /** * clutter_knot_copy: * @knot: a #ClutterKnot * * Makes an allocated copy of a knot. * * Return value: the copied knot. * * Since: 0.2 */ ClutterKnot * clutter_knot_copy (const ClutterKnot *knot) { if (G_UNLIKELY (knot == NULL)) return NULL; return g_slice_dup (ClutterKnot, knot); } /** * clutter_knot_free: * @knot: a #ClutterKnot * * Frees the memory of an allocated knot. * * Since: 0.2 */ void clutter_knot_free (ClutterKnot *knot) { if (G_LIKELY (knot != NULL)) g_slice_free (ClutterKnot, knot); } /** * clutter_knot_equal: * @knot_a: First knot * @knot_b: Second knot * * Compares to knot and checks if the point to the same location. * * Return value: %TRUE if the knots point to the same location. * * Since: 0.2 */ gboolean clutter_knot_equal (const ClutterKnot *knot_a, const ClutterKnot *knot_b) { g_return_val_if_fail (knot_a != NULL, FALSE); g_return_val_if_fail (knot_b != NULL, FALSE); if (knot_a == knot_b) return TRUE; return knot_a->x == knot_b->x && knot_a->y == knot_b->y; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-binding-pool.h�������������������������������������������������0000664�0001750�0001750�00000014667�14211404421�022530� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * Authored By: Emmanuele Bassi <ebassi@linux.intel.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_BINDING_POOL_H__ #define __CLUTTER_BINDING_POOL_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <glib-object.h> #include <clutter/clutter-event.h> G_BEGIN_DECLS #define CLUTTER_TYPE_BINDING_POOL (clutter_binding_pool_get_type ()) #define CLUTTER_BINDING_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BINDING_POOL, ClutterBindingPool)) #define CLUTTER_IS_BINDING_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BINDING_POOL)) /** * ClutterBindingPool: * * Container of key bindings. The #ClutterBindingPool struct is * private. * * Since: 1.0 */ typedef struct _ClutterBindingPool ClutterBindingPool; typedef struct _ClutterBindingPoolClass ClutterBindingPoolClass; /** * ClutterBindingActionFunc: * @gobject: a #GObject * @action_name: the name of the action * @key_val: the key symbol * @modifiers: bitmask of the modifier flags * @user_data: data passed to the function * * The prototype for the callback function registered with * clutter_binding_pool_install_action() and invoked by * clutter_binding_pool_activate(). * * Return value: the function should return %TRUE if the key * binding has been handled, and return %FALSE otherwise * * Since: 1.0 */ typedef gboolean (* ClutterBindingActionFunc) (GObject *gobject, const gchar *action_name, guint key_val, ClutterModifierType modifiers, gpointer user_data); CLUTTER_AVAILABLE_IN_1_0 GType clutter_binding_pool_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterBindingPool * clutter_binding_pool_new (const gchar *name); CLUTTER_AVAILABLE_IN_1_0 ClutterBindingPool * clutter_binding_pool_get_for_class (gpointer klass); CLUTTER_AVAILABLE_IN_1_0 ClutterBindingPool * clutter_binding_pool_find (const gchar *name); CLUTTER_AVAILABLE_IN_1_0 void clutter_binding_pool_install_action (ClutterBindingPool *pool, const gchar *action_name, guint key_val, ClutterModifierType modifiers, GCallback callback, gpointer data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_0 void clutter_binding_pool_install_closure (ClutterBindingPool *pool, const gchar *action_name, guint key_val, ClutterModifierType modifiers, GClosure *closure); CLUTTER_AVAILABLE_IN_1_0 void clutter_binding_pool_override_action (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers, GCallback callback, gpointer data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_0 void clutter_binding_pool_override_closure (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers, GClosure *closure); CLUTTER_AVAILABLE_IN_1_0 const gchar * clutter_binding_pool_find_action (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers); CLUTTER_AVAILABLE_IN_1_0 void clutter_binding_pool_remove_action (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_binding_pool_activate (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers, GObject *gobject); CLUTTER_AVAILABLE_IN_1_0 void clutter_binding_pool_block_action (ClutterBindingPool *pool, const gchar *action_name); CLUTTER_AVAILABLE_IN_1_0 void clutter_binding_pool_unblock_action (ClutterBindingPool *pool, const gchar *action_name); G_END_DECLS #endif /* __CLUTTER_BINDING_POOL_H__ */ �������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-device-manager.c�����������������������������������������������0000664�0001750�0001750�00000043730�14211404421�023002� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-device-manager * @short_description: Maintains the list of input devices * * #ClutterDeviceManager is a singleton object, owned by Clutter, which * maintains the list of #ClutterInputDevice<!-- -->s. * * Depending on the backend used by Clutter it is possible to use the * #ClutterDeviceManager::device-added and * #ClutterDeviceManager::device-removed to monitor addition and removal * of devices. * * #ClutterDeviceManager is available since Clutter 1.2 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-backend-private.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-virtual-input-device.h" #include "clutter-input-device-tool.h" struct _ClutterDeviceManagerPrivate { /* back-pointer to the backend */ ClutterBackend *backend; /* Keyboard a11y */ ClutterKbdA11ySettings kbd_a11y_settings; }; enum { PROP_0, PROP_BACKEND, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { DEVICE_ADDED, DEVICE_REMOVED, TOOL_CHANGED, KBD_A11Y_MASK_CHANGED, KBD_A11Y_FLAGS_CHANGED, LAST_SIGNAL }; static guint manager_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterDeviceManager, clutter_device_manager, G_TYPE_OBJECT) G_DEFINE_INTERFACE (ClutterEventExtender, clutter_event_extender, CLUTTER_TYPE_DEVICE_MANAGER) static void clutter_event_extender_default_init (ClutterEventExtenderInterface *iface) { } static void clutter_device_manager_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterDeviceManagerPrivate *priv = CLUTTER_DEVICE_MANAGER (gobject)->priv; switch (prop_id) { case PROP_BACKEND: priv->backend = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_device_manager_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterDeviceManagerPrivate *priv = CLUTTER_DEVICE_MANAGER (gobject)->priv; switch (prop_id) { case PROP_BACKEND: g_value_set_object (value, priv->backend); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_device_manager_class_init (ClutterDeviceManagerClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); obj_props[PROP_BACKEND] = g_param_spec_object ("backend", P_("Backend"), P_("The ClutterBackend of the device manager"), CLUTTER_TYPE_BACKEND, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); gobject_class->set_property = clutter_device_manager_set_property; gobject_class->get_property = clutter_device_manager_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); /** * ClutterDeviceManager::device-added: * @manager: the #ClutterDeviceManager that emitted the signal * @device: the newly added #ClutterInputDevice * * The ::device-added signal is emitted each time a device has been * added to the #ClutterDeviceManager * * Since: 1.2 */ manager_signals[DEVICE_ADDED] = g_signal_new (I_("device-added"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_INPUT_DEVICE); /** * ClutterDeviceManager::device-removed: * @manager: the #ClutterDeviceManager that emitted the signal * @device: the removed #ClutterInputDevice * * The ::device-removed signal is emitted each time a device has been * removed from the #ClutterDeviceManager * * Since: 1.2 */ manager_signals[DEVICE_REMOVED] = g_signal_new (I_("device-removed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_INPUT_DEVICE); manager_signals[TOOL_CHANGED] = g_signal_new (I_("tool-changed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, CLUTTER_TYPE_INPUT_DEVICE, CLUTTER_TYPE_INPUT_DEVICE_TOOL); /** * ClutterDeviceManager::kbd-a11y-mods-state-changed: * @manager: the #ClutterDeviceManager that emitted the signal * @latched_mask: the latched modifier mask from stickykeys * @locked_mask: the locked modifier mask from stickykeys * * The ::kbd-a11y-mods-state-changed signal is emitted each time either the * latched modifiers mask or locked modifiers mask are changed as the * result of keyboard accessibilty's sticky keys operations. */ manager_signals[KBD_A11Y_MASK_CHANGED] = g_signal_new (I_("kbd-a11y-mods-state-changed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); /** * ClutterDeviceManager::kbd-a11y-flags-changed: * @manager: the #ClutterDeviceManager that emitted the signal * @settings_flags: the new ClutterKeyboardA11yFlags configuration * @changed_mask: the ClutterKeyboardA11yFlags changed * * The ::kbd-a11y-flags-changed signal is emitted each time the * ClutterKeyboardA11yFlags configuration is changed as the result of * keyboard accessibilty operations. */ manager_signals[KBD_A11Y_FLAGS_CHANGED] = g_signal_new (I_("kbd-a11y-flags-changed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); } static void clutter_device_manager_init (ClutterDeviceManager *self) { self->priv = clutter_device_manager_get_instance_private (self); } /** * clutter_device_manager_get_default: * * Retrieves the device manager singleton * * Return value: (transfer none): the #ClutterDeviceManager singleton. * The returned instance is owned by Clutter and it should not be * modified or freed * * Since: 1.2 */ ClutterDeviceManager * clutter_device_manager_get_default (void) { ClutterBackend *backend = clutter_get_default_backend (); return backend->device_manager; } /** * clutter_device_manager_list_devices: * @device_manager: a #ClutterDeviceManager * * Lists all currently registered input devices * * Return value: (transfer container) (element-type Clutter.InputDevice): * a newly allocated list of #ClutterInputDevice objects. Use * g_slist_free() to deallocate it when done * * Since: 1.2 */ GSList * clutter_device_manager_list_devices (ClutterDeviceManager *device_manager) { const GSList *devices; g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL); devices = clutter_device_manager_peek_devices (device_manager); return g_slist_copy ((GSList *) devices); } /** * clutter_device_manager_peek_devices: * @device_manager: a #ClutterDeviceManager * * Lists all currently registered input devices * * Return value: (transfer none) (element-type Clutter.InputDevice): * a pointer to the internal list of #ClutterInputDevice objects. The * returned list is owned by the #ClutterDeviceManager and should never * be modified or freed * * Since: 1.2 */ const GSList * clutter_device_manager_peek_devices (ClutterDeviceManager *device_manager) { ClutterDeviceManagerClass *manager_class; g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); return manager_class->get_devices (device_manager); } /** * clutter_device_manager_get_device: * @device_manager: a #ClutterDeviceManager * @device_id: the integer id of a device * * Retrieves the #ClutterInputDevice with the given @device_id * * Return value: (transfer none): a #ClutterInputDevice or %NULL. The * returned device is owned by the #ClutterDeviceManager and should * never be modified or freed * * Since: 1.2 */ ClutterInputDevice * clutter_device_manager_get_device (ClutterDeviceManager *device_manager, gint device_id) { ClutterDeviceManagerClass *manager_class; g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); return manager_class->get_device (device_manager, device_id); } /** * clutter_device_manager_get_core_device: * @device_manager: a #ClutterDeviceManager * @device_type: the type of the core device * * Retrieves the core #ClutterInputDevice of type @device_type * * Core devices are devices created automatically by the default * Clutter backend * * Return value: (transfer none): a #ClutterInputDevice or %NULL. The * returned device is owned by the #ClutterDeviceManager and should * not be modified or freed * * Since: 1.2 */ ClutterInputDevice * clutter_device_manager_get_core_device (ClutterDeviceManager *device_manager, ClutterInputDeviceType device_type) { ClutterDeviceManagerClass *manager_class; g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); return manager_class->get_core_device (device_manager, device_type); } void _clutter_device_manager_select_stage_events (ClutterDeviceManager *device_manager, ClutterStage *stage) { ClutterDeviceManagerClass *manager_class; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager)); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); if (manager_class->select_stage_events) manager_class->select_stage_events (device_manager, stage); } /* * _clutter_device_manager_add_device: * @device_manager: a #ClutterDeviceManager * @device: a #ClutterInputDevice * * Adds @device to the list of #ClutterInputDevice<!-- -->s maintained * by @device_manager * * The reference count of @device is not increased * * The #ClutterDeviceManager::device-added signal is emitted after * adding @device to the list */ void _clutter_device_manager_add_device (ClutterDeviceManager *device_manager, ClutterInputDevice *device) { ClutterDeviceManagerClass *manager_class; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager)); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); g_assert (manager_class->add_device != NULL); manager_class->add_device (device_manager, device); g_signal_emit (device_manager, manager_signals[DEVICE_ADDED], 0, device); } /* * _clutter_device_manager_remove_device: * @device_manager: a #ClutterDeviceManager * @device: a #ClutterInputDevice * * Removes @device from the list of #ClutterInputDevice<!-- -->s * maintained by @device_manager * * The reference count of @device is not decreased * * The #ClutterDeviceManager::device-removed signal is emitted after * removing @device from the list */ void _clutter_device_manager_remove_device (ClutterDeviceManager *device_manager, ClutterInputDevice *device) { ClutterDeviceManagerClass *manager_class; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager)); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); g_assert (manager_class->remove_device != NULL); /* The subclass remove_device() method will likely unref it but we have to keep it alive during the signal emission. */ g_object_ref (device); manager_class->remove_device (device_manager, device); g_signal_emit (device_manager, manager_signals[DEVICE_REMOVED], 0, device); g_object_unref (device); } /* * _clutter_device_manager_update_devices: * @device_manager: a #ClutterDeviceManager * * Updates every #ClutterInputDevice handled by @device_manager * by performing a pick paint at the coordinates of each pointer * device */ void _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager) { const GSList *d; for (d = clutter_device_manager_peek_devices (device_manager); d != NULL; d = d->next) { ClutterInputDevice *device = d->data; ClutterInputDeviceType device_type; /* we only care about pointer devices */ device_type = clutter_input_device_get_device_type (device); if (device_type != CLUTTER_POINTER_DEVICE) continue; /* out of stage */ if (device->stage == NULL) continue; /* the user disabled motion events delivery on actors for * the stage the device is on; we don't perform any picking * since the source of the events will always be set to be * the stage */ if (!clutter_stage_get_motion_events_enabled (device->stage)) continue; _clutter_input_device_update (device, NULL, TRUE); } } ClutterBackend * _clutter_device_manager_get_backend (ClutterDeviceManager *manager) { g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (manager), NULL); return manager->priv->backend; } /** * clutter_device_manager_create_virtual_device: * @device_manager: a #ClutterDeviceManager * @device_type: the type of the virtual device * * Creates a virtual input device. * * Returns: (transfer full): a newly created virtual device **/ ClutterVirtualInputDevice * clutter_device_manager_create_virtual_device (ClutterDeviceManager *device_manager, ClutterInputDeviceType device_type) { ClutterDeviceManagerClass *manager_class; g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); return manager_class->create_virtual_device (device_manager, device_type); } /** * clutter_device_manager_supported_virtua_device_types: (skip) */ ClutterVirtualDeviceType clutter_device_manager_get_supported_virtual_device_types (ClutterDeviceManager *device_manager) { ClutterDeviceManagerClass *manager_class; g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), CLUTTER_VIRTUAL_DEVICE_TYPE_NONE); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); return manager_class->get_supported_virtual_device_types (device_manager); } void _clutter_device_manager_compress_motion (ClutterDeviceManager *device_manager, ClutterEvent *event, const ClutterEvent *to_discard) { ClutterDeviceManagerClass *manager_class; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager)); manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); if (!manager_class->compress_motion) return; manager_class->compress_motion (device_manager, event, to_discard); } static gboolean are_kbd_a11y_settings_equal (ClutterKbdA11ySettings *a, ClutterKbdA11ySettings *b) { return (a->controls == b->controls && a->slowkeys_delay == b->slowkeys_delay && a->debounce_delay == b->debounce_delay && a->timeout_delay == b->timeout_delay && a->mousekeys_init_delay == b->mousekeys_init_delay && a->mousekeys_max_speed == b->mousekeys_max_speed && a->mousekeys_accel_time == b->mousekeys_accel_time); } void clutter_device_manager_set_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *settings) { ClutterDeviceManagerClass *manager_class; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager)); if (are_kbd_a11y_settings_equal (&device_manager->priv->kbd_a11y_settings, settings)) return; device_manager->priv->kbd_a11y_settings = *settings; manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager); if (manager_class->apply_kbd_a11y_settings) manager_class->apply_kbd_a11y_settings (device_manager, settings); } void clutter_device_manager_get_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *settings) { g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager)); *settings = device_manager->priv->kbd_a11y_settings; } ����������������������������������������muffin-5.2.1/clutter/clutter/clutter-marshal.list���������������������������������������������������0000664�0001750�0001750�00000001321�14211404421�022301� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BOOLEAN:BOXED BOOLEAN:BOXED,INT,INT BOOLEAN:OBJECT,BOOLEAN BOOLEAN:OBJECT,BOXED,DOUBLE BOOLEAN:OBJECT,DOUBLE BOOLEAN:OBJECT,ENUM BOOLEAN:OBJECT,FLAGS BOOLEAN:STRING,UINT,FLAGS BOOLEAN:OBJECT BOOLEAN:OBJECT,FLOAT,FLOAT BOXED:UINT,UINT DOUBLE:VOID UINT:VOID VOID:BOOLEAN VOID:BOXED VOID:BOXED,FLAGS VOID:INT VOID:INT64,INT64,FLOAT,BOOLEAN VOID:INT,INT VOID:INT,POINTER VOID:FLOAT,FLOAT VOID:INT,INT,INT,INT VOID:OBJECT VOID:OBJECT,FLAGS VOID:OBJECT,FLOAT,FLOAT VOID:OBJECT,FLOAT,FLOAT,FLAGS VOID:OBJECT,OBJECT VOID:OBJECT,PARAM VOID:OBJECT,POINTER VOID:OBJECT,UINT VOID:POINTER VOID:STRING,BOOLEAN VOID:STRING,BOOLEAN,BOOLEAN VOID:STRING,INT VOID:UINT VOID:UINT,STRING,UINT VOID:UINT,UINT VOID:VOID VOID:STRING,INT,POINTER ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/Makefile.am.marshal����������������������������������������������������0000664�0001750�0001750�00000002631�14211404421�021764� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Rules for generating marshal files using glib-genmarshal # # Define: # glib_marshal_list = marshal list file # glib_marshal_prefix = prefix for marshal functions # # before including Makefile.am.marshal. You will also need to have # the following targets already defined: # # CLEANFILES # DISTCLEANFILES # BUILT_SOURCES # EXTRA_DIST # # Author: Emmanuele Bassi <ebassi@linux.intel.com> # Basic sanity checks $(if $(GLIB_GENMARSHAL),,$(error Need to define GLIB_GENMARSHAL)) $(if $(or $(glib_marshal_list), \ $(glib_marshal_prefix)),, \ $(error Need to define glib_marshal_list and glib_marshal_prefix)) marshal_h = $(glib_marshal_list:.list=.h) marshal_c = $(glib_marshal_list:.list=.c) marshal_list = $(addprefix $(srcdir)/, $(glib_marshal_list)) CLEANFILES += stamp-marshal DISTCLEANFILES += $(marshal_h) $(marshal_c) BUILT_SOURCES += $(marshal_h) $(marshal_c) EXTRA_DIST += $(marshal_list) stamp-marshal: $(marshal_list) $(AM_V_GEN)$(GLIB_GENMARSHAL) \ --prefix=$(glib_marshal_prefix) \ --header \ $(marshal_list) > xgen-mh \ && (cmp -s xgen-mh $(marshal_h) || cp -f xgen-mh $(marshal_h)) \ && rm -f xgen-mh \ && echo timestamp > $(@F) $(marshal_h): stamp-marshal @true $(marshal_c): $(marshal_h) $(AM_V_GEN)(echo "#include \"$(marshal_h)\"" ; \ $(GLIB_GENMARSHAL) \ --prefix=$(glib_marshal_prefix) \ --body \ $(marshal_list)) > xgen-mc \ && cp xgen-mc $(marshal_c) \ && rm -f xgen-mc �������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-tap-action.h���������������������������������������������������0000664�0001750�0001750�00000006625�14211404421�022201� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * Copyright (C) 2012 Collabora Ltd. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emanuele Aina <emanuele.aina@collabora.com> * * Based on ClutterPanAction * Based on ClutterDragAction, ClutterSwipeAction, and MxKineticScrollView, * written by: * Emmanuele Bassi <ebassi@linux.intel.com> * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> * Chris Lord <chris@linux.intel.com> */ #ifndef __CLUTTER_TAP_ACTION_H__ #define __CLUTTER_TAP_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-gesture-action.h> G_BEGIN_DECLS #define CLUTTER_TYPE_TAP_ACTION (clutter_tap_action_get_type ()) #define CLUTTER_TAP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TAP_ACTION, ClutterTapAction)) #define CLUTTER_IS_TAP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TAP_ACTION)) #define CLUTTER_TAP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TAP_ACTION, ClutterTapActionClass)) #define CLUTTER_IS_TAP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TAP_ACTION)) #define CLUTTER_TAP_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TAP_ACTION, ClutterTapActionClass)) typedef struct _ClutterTapAction ClutterTapAction; typedef struct _ClutterTapActionPrivate ClutterTapActionPrivate; typedef struct _ClutterTapActionClass ClutterTapActionClass; /** * ClutterTapAction: * * The #ClutterTapAction structure contains * only private data and should be accessed using the provided API * * Since: 1.14 */ struct _ClutterTapAction { /*< private >*/ ClutterGestureAction parent_instance; }; /** * ClutterTapActionClass: * @tap: class handler for the #ClutterTapAction::tap signal * * The #ClutterTapActionClass structure contains * only private data. */ struct _ClutterTapActionClass { /*< private >*/ ClutterGestureActionClass parent_class; /*< public >*/ gboolean (* tap) (ClutterTapAction *action, ClutterActor *actor); /*< private >*/ void (* _clutter_tap_action1) (void); void (* _clutter_tap_action2) (void); void (* _clutter_tap_action3) (void); void (* _clutter_tap_action4) (void); void (* _clutter_tap_action5) (void); void (* _clutter_tap_action6) (void); }; CLUTTER_AVAILABLE_IN_1_14 GType clutter_tap_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_14 ClutterAction * clutter_tap_action_new (void); G_END_DECLS #endif /* __CLUTTER_TAP_ACTION_H__ */ �����������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-layout-meta.h��������������������������������������������������0000664�0001750�0001750�00000006226�14211404421�022400� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_LAYOUT_META_H__ #define __CLUTTER_LAYOUT_META_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-child-meta.h> #include <clutter/clutter-layout-manager.h> G_BEGIN_DECLS #define CLUTTER_TYPE_LAYOUT_META (clutter_layout_meta_get_type ()) #define CLUTTER_LAYOUT_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYOUT_META, ClutterLayoutMeta)) #define CLUTTER_IS_LAYOUT_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYOUT_META)) #define CLUTTER_LAYOUT_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_LAYOUT_META, ClutterLayoutMetaClass)) #define CLUTTER_IS_LAYOUT_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_LAYOUT_META)) #define CLUTTER_LAYOUT_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_LAYOUT_META, ClutterLayoutMetaClass)) /* ClutterLayoutMeta is defined in clutter-types.h */ typedef struct _ClutterLayoutMetaClass ClutterLayoutMetaClass; /** * ClutterLayoutMeta: * @manager: the layout manager handling this data * * Sub-class of #ClutterChildMeta specific for layout managers * * A #ClutterLayoutManager sub-class should create a #ClutterLayoutMeta * instance by overriding the #ClutterLayoutManager::create_child_meta() * virtual function * * Since: 1.2 */ struct _ClutterLayoutMeta { /*< private >*/ ClutterChildMeta parent_instance; /*< public >*/ ClutterLayoutManager *manager; /*< private >*/ /* padding */ gint32 dummy0; gpointer dummy1; }; /** * ClutterLayoutMetaClass: * * The #ClutterLayoutMetaClass contains only private data and * should never be accessed directly * * Since: 1.2 */ struct _ClutterLayoutMetaClass { /*< private >*/ ClutterChildMetaClass parent_class; /* padding, for expansion */ void (*_clutter_padding1) (void); void (*_clutter_padding2) (void); void (*_clutter_padding3) (void); void (*_clutter_padding4) (void); }; CLUTTER_AVAILABLE_IN_1_2 GType clutter_layout_meta_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 ClutterLayoutManager *clutter_layout_meta_get_manager (ClutterLayoutMeta *data); G_END_DECLS #endif /* __CLUTTER_LAYOUT_META_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-text.h���������������������������������������������������������0000664�0001750�0001750�00000040554�14211404421�021125� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * Authored By: Øyvind Kolås <pippin@o-hand.com> * Emmanuele Bassi <ebassi@linux.intel.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_TEXT_H__ #define __CLUTTER_TEXT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-actor.h> #include <clutter/clutter-text-buffer.h> #include <pango/pango.h> G_BEGIN_DECLS #define CLUTTER_TYPE_TEXT (clutter_text_get_type ()) #define CLUTTER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXT, ClutterText)) #define CLUTTER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TEXT, ClutterTextClass)) #define CLUTTER_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXT)) #define CLUTTER_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TEXT)) #define CLUTTER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TEXT, ClutterTextClass)) typedef struct _ClutterText ClutterText; typedef struct _ClutterTextPrivate ClutterTextPrivate; typedef struct _ClutterTextClass ClutterTextClass; /** * ClutterText: * * The #ClutterText struct contains only private data. * * Since: 1.0 */ struct _ClutterText { /*< private >*/ ClutterActor parent_instance; ClutterTextPrivate *priv; }; /** * ClutterTextClass: * @text_changed: class handler for the #ClutterText::text-changed signal * @activate: class handler for the #ClutterText::activate signal * @cursor_event: class handler for the #ClutterText::cursor-event signal * @cursor_changed: class handler for the #ClutterText::cursor-changed signal * * The #ClutterTextClass struct contains only private data. * * Since: 1.0 */ struct _ClutterTextClass { /*< private >*/ ClutterActorClass parent_class; /*< public >*/ /* signals, not vfuncs */ void (* text_changed) (ClutterText *self); void (* activate) (ClutterText *self); void (* cursor_event) (ClutterText *self, const ClutterGeometry *geometry); void (* cursor_changed) (ClutterText *self); /*< private >*/ /* padding for future expansion */ void (* _clutter_reserved1) (void); void (* _clutter_reserved2) (void); void (* _clutter_reserved3) (void); void (* _clutter_reserved4) (void); void (* _clutter_reserved5) (void); void (* _clutter_reserved6) (void); void (* _clutter_reserved7) (void); }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_text_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterActor * clutter_text_new (void); CLUTTER_AVAILABLE_IN_1_0 ClutterActor * clutter_text_new_full (const gchar *font_name, const gchar *text, const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 ClutterActor * clutter_text_new_with_text (const gchar *font_name, const gchar *text); CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_text_new_with_buffer (ClutterTextBuffer *buffer); CLUTTER_AVAILABLE_IN_1_10 ClutterTextBuffer * clutter_text_get_buffer (ClutterText *self); CLUTTER_AVAILABLE_IN_1_10 void clutter_text_set_buffer (ClutterText *self, ClutterTextBuffer *buffer); CLUTTER_AVAILABLE_IN_1_0 const gchar * clutter_text_get_text (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_text (ClutterText *self, const gchar *text); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_markup (ClutterText *self, const gchar *markup); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_color (ClutterText *self, const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_get_color (ClutterText *self, ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_font_name (ClutterText *self, const gchar *font_name); CLUTTER_AVAILABLE_IN_1_0 const gchar * clutter_text_get_font_name (ClutterText *self); CLUTTER_AVAILABLE_IN_1_2 void clutter_text_set_font_description (ClutterText *self, PangoFontDescription *font_desc); CLUTTER_AVAILABLE_IN_1_2 PangoFontDescription *clutter_text_get_font_description (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_ellipsize (ClutterText *self, PangoEllipsizeMode mode); CLUTTER_AVAILABLE_IN_1_0 PangoEllipsizeMode clutter_text_get_ellipsize (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_line_wrap (ClutterText *self, gboolean line_wrap); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_line_wrap (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_line_wrap_mode (ClutterText *self, PangoWrapMode wrap_mode); CLUTTER_AVAILABLE_IN_1_0 PangoWrapMode clutter_text_get_line_wrap_mode (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 PangoLayout * clutter_text_get_layout (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_attributes (ClutterText *self, PangoAttrList *attrs); CLUTTER_AVAILABLE_IN_1_0 PangoAttrList * clutter_text_get_attributes (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_use_markup (ClutterText *self, gboolean setting); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_use_markup (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_line_alignment (ClutterText *self, PangoAlignment alignment); CLUTTER_AVAILABLE_IN_1_0 PangoAlignment clutter_text_get_line_alignment (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_justify (ClutterText *self, gboolean justify); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_justify (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_insert_unichar (ClutterText *self, gunichar wc); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_delete_chars (ClutterText *self, guint n_chars); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_insert_text (ClutterText *self, const gchar *text, gssize position); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_delete_text (ClutterText *self, gssize start_pos, gssize end_pos); CLUTTER_AVAILABLE_IN_1_0 gchar * clutter_text_get_chars (ClutterText *self, gssize start_pos, gssize end_pos); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_editable (ClutterText *self, gboolean editable); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_editable (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_activatable (ClutterText *self, gboolean activatable); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_activatable (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 gint clutter_text_get_cursor_position (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_cursor_position (ClutterText *self, gint position); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_cursor_visible (ClutterText *self, gboolean cursor_visible); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_cursor_visible (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_cursor_color (ClutterText *self, const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_get_cursor_color (ClutterText *self, ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_cursor_size (ClutterText *self, gint size); CLUTTER_AVAILABLE_IN_1_0 guint clutter_text_get_cursor_size (ClutterText *self); CLUTTER_AVAILABLE_IN_1_16 void clutter_text_get_cursor_rect (ClutterText *self, ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_selectable (ClutterText *self, gboolean selectable); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_selectable (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_selection_bound (ClutterText *self, gint selection_bound); CLUTTER_AVAILABLE_IN_1_0 gint clutter_text_get_selection_bound (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_selection (ClutterText *self, gssize start_pos, gssize end_pos); CLUTTER_AVAILABLE_IN_1_0 gchar * clutter_text_get_selection (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_selection_color (ClutterText *self, const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_get_selection_color (ClutterText *self, ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_delete_selection (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_password_char (ClutterText *self, gunichar wc); CLUTTER_AVAILABLE_IN_1_0 gunichar clutter_text_get_password_char (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_max_length (ClutterText *self, gint max); CLUTTER_AVAILABLE_IN_1_0 gint clutter_text_get_max_length (ClutterText *self); CLUTTER_AVAILABLE_IN_1_0 void clutter_text_set_single_line_mode (ClutterText *self, gboolean single_line); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_get_single_line_mode (ClutterText *self); CLUTTER_AVAILABLE_IN_1_8 void clutter_text_set_selected_text_color (ClutterText *self, const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_8 void clutter_text_get_selected_text_color (ClutterText *self, ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_activate (ClutterText *self); CLUTTER_AVAILABLE_IN_1_10 gint clutter_text_coords_to_position (ClutterText *self, gfloat x, gfloat y); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_text_position_to_coords (ClutterText *self, gint position, gfloat *x, gfloat *y, gfloat *line_height); CLUTTER_AVAILABLE_IN_1_2 void clutter_text_set_preedit_string (ClutterText *self, const gchar *preedit_str, PangoAttrList *preedit_attrs, guint cursor_pos); CLUTTER_AVAILABLE_IN_1_8 void clutter_text_get_layout_offsets (ClutterText *self, gint *x, gint *y); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_text_set_input_hints (ClutterText *self, ClutterInputContentHintFlags hints); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_text_set_input_purpose (ClutterText *self, ClutterInputContentPurpose purpose); CLUTTER_AVAILABLE_IN_MUFFIN ClutterInputContentHintFlags clutter_text_get_input_hints (ClutterText *self); CLUTTER_AVAILABLE_IN_MUFFIN ClutterInputContentPurpose clutter_text_get_input_purpose (ClutterText *self); CLUTTER_AVAILABLE_IN_MUFFIN gboolean clutter_text_has_preedit (ClutterText *self); G_END_DECLS #endif /* __CLUTTER_TEXT_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-main.c���������������������������������������������������������0000664�0001750�0001750�00000317704�14211404421�021064� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-main * @short_description: Various 'global' Clutter functions. * * Functions to retrieve various global Clutter resources and other utility * functions for mainloops, events and threads * * ## The Clutter Threading Model * * Clutter is *thread-aware*: all operations performed by Clutter are assumed * to be under the Big Clutter Lock, which is created when the threading is * initialized through clutter_init(), and entered when calling user-related * code during event handling and actor drawing. * * The only safe and portable way to use the Clutter API in a multi-threaded * environment is to only access the Clutter API from a thread that did called * clutter_init() and clutter_main(). * * The common pattern for using threads with Clutter is to use worker threads * to perform blocking operations and then install idle or timeout sources with * the result when the thread finishes, and update the UI from those callbacks. * * For a working example of how to use a worker thread to update the UI, see * [threads.c](https://git.gnome.org/browse/clutter/tree/examples/threads.c?h=clutter-1.18) */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <stdlib.h> #include "clutter-actor-private.h" #include "clutter-backend-private.h" #include "clutter-config.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-event-private.h" #include "clutter-feature.h" #include "clutter-main.h" #include "clutter-master-clock.h" #include "clutter-muffin.h" #include "clutter-private.h" #include "clutter-settings-private.h" #include "clutter-stage-manager.h" #include "clutter-stage-private.h" #include "clutter-version.h" /* For flavour define */ #ifdef CLUTTER_WINDOWING_X11 #include "x11/clutter-backend-x11.h" #endif #ifdef CLUTTER_WINDOWING_EGL #include "egl/clutter-backend-eglnative.h" #endif #include <cogl/cogl.h> #include <cogl-pango/cogl-pango.h> #include "cally.h" /* For accessibility support */ /* main context */ static ClutterMainContext *ClutterCntx = NULL; G_LOCK_DEFINE_STATIC (ClutterCntx); /* main lock and locking/unlocking functions */ static GMutex clutter_threads_mutex; static GCallback clutter_threads_lock = NULL; static GCallback clutter_threads_unlock = NULL; /* command line options */ static gboolean clutter_is_initialized = FALSE; static gboolean clutter_show_fps = FALSE; static gboolean clutter_fatal_warnings = FALSE; static gboolean clutter_disable_mipmap_text = FALSE; static gboolean clutter_use_fuzzy_picking = FALSE; static gboolean clutter_enable_accessibility = TRUE; static gboolean clutter_sync_to_vblank = TRUE; SyncMethod clutter_sync_method = SYNC_PRESENTATION_TIME; static guint clutter_default_fps = 60; static ClutterTextDirection clutter_text_direction = CLUTTER_TEXT_DIRECTION_LTR; static guint clutter_main_loop_level = 0; static GSList *main_loops = NULL; /* debug flags */ guint clutter_debug_flags = 0; guint clutter_paint_debug_flags = 0; guint clutter_pick_debug_flags = 0; const guint clutter_major_version = CLUTTER_MAJOR_VERSION; const guint clutter_minor_version = CLUTTER_MINOR_VERSION; const guint clutter_micro_version = CLUTTER_MICRO_VERSION; #ifdef CLUTTER_ENABLE_DEBUG static const GDebugKey clutter_debug_keys[] = { { "misc", CLUTTER_DEBUG_MISC }, { "actor", CLUTTER_DEBUG_ACTOR }, { "texture", CLUTTER_DEBUG_TEXTURE }, { "event", CLUTTER_DEBUG_EVENT }, { "paint", CLUTTER_DEBUG_PAINT }, { "pick", CLUTTER_DEBUG_PICK }, { "pango", CLUTTER_DEBUG_PANGO }, { "backend", CLUTTER_DEBUG_BACKEND }, { "scheduler", CLUTTER_DEBUG_SCHEDULER }, { "script", CLUTTER_DEBUG_SCRIPT }, { "shader", CLUTTER_DEBUG_SHADER }, { "animation", CLUTTER_DEBUG_ANIMATION }, { "layout", CLUTTER_DEBUG_LAYOUT }, { "clipping", CLUTTER_DEBUG_CLIPPING }, { "oob-transforms", CLUTTER_DEBUG_OOB_TRANSFORMS }, }; #endif /* CLUTTER_ENABLE_DEBUG */ static const GDebugKey clutter_pick_debug_keys[] = { { "nop-picking", CLUTTER_DEBUG_NOP_PICKING }, { "dump-pick-buffers", CLUTTER_DEBUG_DUMP_PICK_BUFFERS }, }; static const GDebugKey clutter_paint_debug_keys[] = { { "disable-swap-events", CLUTTER_DEBUG_DISABLE_SWAP_EVENTS }, { "disable-clipped-redraws", CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS }, { "redraws", CLUTTER_DEBUG_REDRAWS }, { "paint-volumes", CLUTTER_DEBUG_PAINT_VOLUMES }, { "disable-culling", CLUTTER_DEBUG_DISABLE_CULLING }, { "disable-offscreen-redirect", CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT }, { "continuous-redraw", CLUTTER_DEBUG_CONTINUOUS_REDRAW }, { "paint-deform-tiles", CLUTTER_DEBUG_PAINT_DEFORM_TILES }, }; static void clutter_threads_impl_lock (void) { g_mutex_lock (&clutter_threads_mutex); } static void clutter_threads_impl_unlock (void) { /* we need to trylock here, in case the lock hasn't been acquired; on * various systems trying to release a mutex that hasn't been acquired * will cause a run-time error. trylock() will either fail, in which * case we can release the lock we own; or it will succeeds, in which * case we need to release the lock we just acquired. so we ignore the * returned value. * * see: https://bugs.gnome.org/679439 */ g_mutex_trylock (&clutter_threads_mutex); g_mutex_unlock (&clutter_threads_mutex); } static inline void clutter_threads_init_default (void) { g_mutex_init (&clutter_threads_mutex); if (clutter_threads_lock == NULL) clutter_threads_lock = clutter_threads_impl_lock; if (clutter_threads_unlock == NULL) clutter_threads_unlock = clutter_threads_impl_unlock; } #define ENVIRONMENT_GROUP "Environment" #define DEBUG_GROUP "Debug" static void clutter_config_read_from_key_file (GKeyFile *keyfile) { GError *key_error = NULL; gboolean bool_value; gint int_value; gchar *str_value; if (!g_key_file_has_group (keyfile, ENVIRONMENT_GROUP)) return; str_value = g_key_file_get_string (keyfile, ENVIRONMENT_GROUP, "Backends", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_try_set_windowing_backend (str_value); free (str_value); str_value = g_key_file_get_string (keyfile, ENVIRONMENT_GROUP, "Drivers", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_set_allowed_drivers (str_value); free (str_value); bool_value = g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP, "ShowFps", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_show_fps = bool_value; bool_value = g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP, "DisableMipmappedText", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_disable_mipmap_text = bool_value; bool_value = g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP, "UseFuzzyPicking", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_use_fuzzy_picking = bool_value; bool_value = g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP, "EnableAccessibility", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_enable_accessibility = bool_value; bool_value = g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP, "SyncToVblank", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_sync_to_vblank = bool_value; int_value = g_key_file_get_integer (keyfile, ENVIRONMENT_GROUP, "DefaultFps", &key_error); if (key_error != NULL) g_clear_error (&key_error); else clutter_default_fps = int_value; str_value = g_key_file_get_string (keyfile, ENVIRONMENT_GROUP, "TextDirection", &key_error); if (key_error != NULL) g_clear_error (&key_error); else { if (g_strcmp0 (str_value, "rtl") == 0) clutter_text_direction = CLUTTER_TEXT_DIRECTION_RTL; else clutter_text_direction = CLUTTER_TEXT_DIRECTION_LTR; } free (str_value); } #ifdef CLUTTER_ENABLE_DEBUG static void clutter_debug_read_from_key_file (GKeyFile *keyfile) { GError *key_error = NULL; gchar *value; if (!g_key_file_has_group (keyfile, DEBUG_GROUP)) return; value = g_key_file_get_value (keyfile, DEBUG_GROUP, "Debug", &key_error); if (key_error == NULL) { clutter_debug_flags |= g_parse_debug_string (value, clutter_debug_keys, G_N_ELEMENTS (clutter_debug_keys)); } else g_clear_error (&key_error); free (value); value = g_key_file_get_value (keyfile, DEBUG_GROUP, "PaintDebug", &key_error); if (key_error == NULL) { clutter_paint_debug_flags |= g_parse_debug_string (value, clutter_paint_debug_keys, G_N_ELEMENTS (clutter_paint_debug_keys)); } else g_clear_error (&key_error); free (value); value = g_key_file_get_value (keyfile, DEBUG_GROUP, "PickDebug", &key_error); if (key_error == NULL) { clutter_pick_debug_flags |= g_parse_debug_string (value, clutter_pick_debug_keys, G_N_ELEMENTS (clutter_pick_debug_keys)); } else g_clear_error (&key_error); free (value); } #endif static void clutter_config_read_from_file (const gchar *config_path) { ClutterSettings *settings = clutter_settings_get_default (); GKeyFile *key_file = g_key_file_new (); GError *error = NULL; g_key_file_load_from_file (key_file, config_path, G_KEY_FILE_NONE, &error); if (error == NULL) { CLUTTER_NOTE (MISC, "Reading configuration from '%s'", config_path); clutter_config_read_from_key_file (key_file); #ifdef CLUTTER_ENABLE_DEBUG clutter_debug_read_from_key_file (key_file); #endif _clutter_settings_read_from_key_file (settings, key_file); } else { g_warning ("Unable to read configuration settings from '%s': %s", config_path, error->message); g_error_free (error); } g_key_file_free (key_file); } static void clutter_config_read (void) { gchar *config_path; config_path = g_build_filename (CLUTTER_SYSCONFDIR, "clutter-1.0", "settings.ini", NULL); if (g_file_test (config_path, G_FILE_TEST_EXISTS)) clutter_config_read_from_file (config_path); free (config_path); config_path = g_build_filename (g_get_user_config_dir (), "clutter-1.0", "settings.ini", NULL); if (g_file_test (config_path, G_FILE_TEST_EXISTS)) clutter_config_read_from_file (config_path); free (config_path); } /** * clutter_get_show_fps: * * Returns whether Clutter should print out the frames per second on the * console. You can enable this setting either using the * <literal>CLUTTER_SHOW_FPS</literal> environment variable or passing * the <literal>--clutter-show-fps</literal> command line argument. * * * Return value: %TRUE if Clutter should show the FPS. * * Since: 0.4 * * Deprecated: 1.10: This function does not do anything. Use the environment * variable or the configuration file to determine whether Clutter should * print out the FPS counter on the console. */ gboolean clutter_get_show_fps (void) { return FALSE; } gboolean _clutter_context_get_show_fps (void) { ClutterMainContext *context = _clutter_context_get_default (); return context->show_fps; } /** * clutter_get_accessibility_enabled: * * Returns whether Clutter has accessibility support enabled. As * least, a value of TRUE means that there are a proper AtkUtil * implementation available * * Return value: %TRUE if Clutter has accessibility support enabled * * Since: 1.4 */ gboolean clutter_get_accessibility_enabled (void) { return cally_get_cally_initialized (); } /** * clutter_disable_accessibility: * * Disable loading the accessibility support. It has the same effect * as setting the environment variable * CLUTTER_DISABLE_ACCESSIBILITY. For the same reason, this method * should be called before clutter_init(). * * Since: 1.14 */ void clutter_disable_accessibility (void) { if (clutter_is_initialized) { g_warning ("clutter_disable_accessibility() can only be called before " "initializing Clutter."); return; } clutter_enable_accessibility = FALSE; } /** * clutter_redraw: * * Forces a redraw of the entire stage. Applications should never use this * function, but queue a redraw using clutter_actor_queue_redraw(). * * This function should only be used by libraries integrating Clutter from * within another toolkit. * * Deprecated: 1.10: Use clutter_stage_ensure_redraw() instead. */ void clutter_redraw (ClutterStage *stage) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); clutter_stage_ensure_redraw (stage); } /** * clutter_set_motion_events_enabled: * @enable: %TRUE to enable per-actor motion events * * Sets whether per-actor motion events should be enabled or not on * all #ClutterStage<!-- -->s managed by Clutter. * * If @enable is %FALSE the following events will not work: * * - ClutterActor::motion-event, except on the #ClutterStage * - ClutterActor::enter-event * - ClutterActor::leave-event * * Since: 0.6 * * Deprecated: 1.8: Use clutter_stage_set_motion_events_enabled() instead. */ void clutter_set_motion_events_enabled (gboolean enable) { ClutterStageManager *stage_manager; ClutterMainContext *context; const GSList *l; enable = !!enable; context = _clutter_context_get_default (); if (context->motion_events_per_actor == enable) return; /* store the flag for later query and for newly created stages */ context->motion_events_per_actor = enable; /* propagate the change to all stages */ stage_manager = clutter_stage_manager_get_default (); for (l = clutter_stage_manager_peek_stages (stage_manager); l != NULL; l = l->next) { clutter_stage_set_motion_events_enabled (l->data, enable); } } /** * clutter_get_motion_events_enabled: * * Gets whether the per-actor motion events are enabled. * * Return value: %TRUE if the motion events are enabled * * Since: 0.6 * * Deprecated: 1.8: Use clutter_stage_get_motion_events_enabled() instead. */ gboolean clutter_get_motion_events_enabled (void) { return _clutter_context_get_motion_events_enabled (); } void _clutter_id_to_color (guint id_, ClutterColor *col) { ClutterMainContext *ctx; gint red, green, blue; ctx = _clutter_context_get_default (); if (ctx->fb_g_mask == 0) { /* Figure out framebuffer masks used for pick */ cogl_get_bitmasks (&ctx->fb_r_mask, &ctx->fb_g_mask, &ctx->fb_b_mask, NULL); ctx->fb_r_mask_used = ctx->fb_r_mask; ctx->fb_g_mask_used = ctx->fb_g_mask; ctx->fb_b_mask_used = ctx->fb_b_mask; /* XXX - describe what "fuzzy picking" is */ if (clutter_use_fuzzy_picking) { ctx->fb_r_mask_used--; ctx->fb_g_mask_used--; ctx->fb_b_mask_used--; } } /* compute the numbers we'll store in the components */ red = (id_ >> (ctx->fb_g_mask_used+ctx->fb_b_mask_used)) & (0xff >> (8-ctx->fb_r_mask_used)); green = (id_ >> ctx->fb_b_mask_used) & (0xff >> (8-ctx->fb_g_mask_used)); blue = (id_) & (0xff >> (8-ctx->fb_b_mask_used)); /* shift left bits a bit and add one, this circumvents * at least some potential rounding errors in GL/GLES * driver / hw implementation. */ if (ctx->fb_r_mask_used != ctx->fb_r_mask) red = red * 2; if (ctx->fb_g_mask_used != ctx->fb_g_mask) green = green * 2; if (ctx->fb_b_mask_used != ctx->fb_b_mask) blue = blue * 2; /* shift up to be full 8bit values */ red = (red << (8 - ctx->fb_r_mask)) | (0x7f >> (ctx->fb_r_mask_used)); green = (green << (8 - ctx->fb_g_mask)) | (0x7f >> (ctx->fb_g_mask_used)); blue = (blue << (8 - ctx->fb_b_mask)) | (0x7f >> (ctx->fb_b_mask_used)); col->red = red; col->green = green; col->blue = blue; col->alpha = 0xff; /* XXX: We rotate the nibbles of the colors here so that there is a * visible variation between colors of sequential actor identifiers; * otherwise pick buffers dumped to an image will pretty much just look * black. */ if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)) { col->red = (col->red << 4) | (col->red >> 4); col->green = (col->green << 4) | (col->green >> 4); col->blue = (col->blue << 4) | (col->blue >> 4); } } guint _clutter_pixel_to_id (guchar pixel[4]) { ClutterMainContext *ctx; gint red, green, blue; guint retval; ctx = _clutter_context_get_default (); /* reduce the pixel components to the number of bits actually used of the * 8bits. */ if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)) { guchar tmp; /* XXX: In _clutter_id_to_color we rotated the nibbles of the colors so * that there is a visible variation between colors of sequential actor * identifiers (otherwise pick buffers dumped to an image will pretty * much just look black.) Here we reverse that rotation. */ tmp = ((pixel[0] << 4) | (pixel[0] >> 4)); red = tmp >> (8 - ctx->fb_r_mask); tmp = ((pixel[1] << 4) | (pixel[1] >> 4)); green = tmp >> (8 - ctx->fb_g_mask); tmp = ((pixel[2] << 4) | (pixel[2] >> 4)); blue = tmp >> (8 - ctx->fb_b_mask); } else { red = pixel[0] >> (8 - ctx->fb_r_mask); green = pixel[1] >> (8 - ctx->fb_g_mask); blue = pixel[2] >> (8 - ctx->fb_b_mask); } /* divide potentially by two if 'fuzzy' */ red = red >> (ctx->fb_r_mask - ctx->fb_r_mask_used); green = green >> (ctx->fb_g_mask - ctx->fb_g_mask_used); blue = blue >> (ctx->fb_b_mask - ctx->fb_b_mask_used); /* combine the correct per component values into the final id */ retval = blue + (green << ctx->fb_b_mask_used) + (red << (ctx->fb_b_mask_used + ctx->fb_g_mask_used)); return retval; } static CoglPangoFontMap * clutter_context_get_pango_fontmap (void) { ClutterMainContext *self; CoglPangoFontMap *font_map; gdouble resolution; gboolean use_mipmapping; self = _clutter_context_get_default (); if (G_LIKELY (self->font_map != NULL)) return self->font_map; font_map = COGL_PANGO_FONT_MAP (cogl_pango_font_map_new ()); resolution = clutter_backend_get_resolution (self->backend); cogl_pango_font_map_set_resolution (font_map, resolution); use_mipmapping = !clutter_disable_mipmap_text; cogl_pango_font_map_set_use_mipmapping (font_map, use_mipmapping); self->font_map = font_map; return self->font_map; } static ClutterTextDirection clutter_get_text_direction (void) { ClutterTextDirection dir = CLUTTER_TEXT_DIRECTION_LTR; const gchar *direction; direction = g_getenv ("CLUTTER_TEXT_DIRECTION"); if (direction && *direction != '\0') { if (strcmp (direction, "rtl") == 0) dir = CLUTTER_TEXT_DIRECTION_RTL; else if (strcmp (direction, "ltr") == 0) dir = CLUTTER_TEXT_DIRECTION_LTR; } else { /* Re-use GTK+'s LTR/RTL handling */ const char *e = g_dgettext ("gtk30", "default:LTR"); if (strcmp (e, "default:RTL") == 0) dir = CLUTTER_TEXT_DIRECTION_RTL; else if (strcmp (e, "default:LTR") == 0) dir = CLUTTER_TEXT_DIRECTION_LTR; else g_warning ("Whoever translated default:LTR did so wrongly."); } CLUTTER_NOTE (MISC, "Text direction: %s", dir == CLUTTER_TEXT_DIRECTION_RTL ? "rtl" : "ltr"); return dir; } /** * clutter_main_quit: * * Terminates the Clutter mainloop. */ void clutter_main_quit (void) { if (main_loops == NULL) { g_critical ("Calling clutter_main_quit() without calling clutter_main() " "is not allowed. If you are using another main loop, use the " "appropriate API to terminate it."); return; } CLUTTER_NOTE (MISC, "Terminating main loop level %d", clutter_main_loop_level); g_main_loop_quit (main_loops->data); } /** * clutter_main_level: * * Retrieves the depth of the Clutter mainloop. * * Return value: The level of the mainloop. */ gint clutter_main_level (void) { return clutter_main_loop_level; } /** * clutter_main: * * Starts the Clutter mainloop. */ void clutter_main (void) { GMainLoop *loop; if (!_clutter_context_is_initialized ()) { g_warning ("Called clutter_main() but Clutter wasn't initialised. " "You must call clutter_init() first."); return; } clutter_main_loop_level++; CLUTTER_NOTE (MISC, "Entering main loop level %d", clutter_main_loop_level); loop = g_main_loop_new (NULL, TRUE); main_loops = g_slist_prepend (main_loops, loop); if (g_main_loop_is_running (main_loops->data)) { _clutter_threads_release_lock (); g_main_loop_run (loop); _clutter_threads_acquire_lock (); } main_loops = g_slist_remove (main_loops, loop); g_main_loop_unref (loop); CLUTTER_NOTE (MISC, "Leaving main loop level %d", clutter_main_loop_level); clutter_main_loop_level--; } /** * clutter_threads_init: * * Initialises the Clutter threading mechanism, so that Clutter API can be * called by multiple threads, using clutter_threads_enter() and * clutter_threads_leave() to mark the critical sections. * * You must call g_thread_init() before this function. * * This function must be called before clutter_init(). * * It is safe to call this function multiple times. * * Since: 0.4 * * Deprecated: 1.10: This function does not do anything. Threading support * is initialized when Clutter is initialized. */ void clutter_threads_init (void) { } /** * clutter_threads_set_lock_functions: (skip) * @enter_fn: function called when aquiring the Clutter main lock * @leave_fn: function called when releasing the Clutter main lock * * Allows the application to replace the standard method that * Clutter uses to protect its data structures. Normally, Clutter * creates a single #GMutex that is locked by clutter_threads_enter(), * and released by clutter_threads_leave(); using this function an * application provides, instead, a function @enter_fn that is * called by clutter_threads_enter() and a function @leave_fn that is * called by clutter_threads_leave(). * * The functions must provide at least same locking functionality * as the default implementation, but can also do extra application * specific processing. * * As an example, consider an application that has its own recursive * lock that when held, holds the Clutter lock as well. When Clutter * unlocks the Clutter lock when entering a recursive main loop, the * application must temporarily release its lock as well. * * Most threaded Clutter apps won't need to use this method. * * This method must be called before clutter_init(), and cannot * be called multiple times. * * Since: 0.4 */ void clutter_threads_set_lock_functions (GCallback enter_fn, GCallback leave_fn) { g_return_if_fail (clutter_threads_lock == NULL && clutter_threads_unlock == NULL); clutter_threads_lock = enter_fn; clutter_threads_unlock = leave_fn; } gboolean _clutter_threads_dispatch (gpointer data) { ClutterThreadsDispatch *dispatch = data; gboolean ret = FALSE; _clutter_threads_acquire_lock (); if (!g_source_is_destroyed (g_main_current_source ())) ret = dispatch->func (dispatch->data); _clutter_threads_release_lock (); return ret; } void _clutter_threads_dispatch_free (gpointer data) { ClutterThreadsDispatch *dispatch = data; /* XXX - we cannot hold the thread lock here because the main loop * might destroy a source while still in the dispatcher function; so * knowing whether the lock is being held or not is not known a priori. * * see bug: http://bugzilla.gnome.org/show_bug.cgi?id=459555 */ if (dispatch->notify) dispatch->notify (dispatch->data); g_slice_free (ClutterThreadsDispatch, dispatch); } /** * clutter_threads_add_idle_full: (rename-to clutter_threads_add_idle) * @priority: the priority of the timeout source. Typically this will be in the * range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE * @func: function to call * @data: data to pass to the function * @notify: functio to call when the idle source is removed * * Adds a function to be called whenever there are no higher priority * events pending. If the function returns %FALSE it is automatically * removed from the list of event sources and will not be called again. * * This function can be considered a thread-safe variant of g_idle_add_full(): * it will call @function while holding the Clutter lock. It is logically * equivalent to the following implementation: * * |[ * static gboolean * idle_safe_callback (gpointer data) * { * SafeClosure *closure = data; * gboolean res = FALSE; * * // mark the critical section // * * clutter_threads_enter(); * * // the callback does not need to acquire the Clutter * / lock itself, as it is held by the this proxy handler * // * res = closure->callback (closure->data); * * clutter_threads_leave(); * * return res; * } * static gulong * add_safe_idle (GSourceFunc callback, * gpointer data) * { * SafeClosure *closure = g_new0 (SafeClosure, 1); * * closure->callback = callback; * closure->data = data; * * return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, * idle_safe_callback, * closure, * free) * } *]| * * This function should be used by threaded applications to make sure * that @func is emitted under the Clutter threads lock and invoked * from the same thread that started the Clutter main loop. For instance, * it can be used to update the UI using the results from a worker * thread: * * |[ * static gboolean * update_ui (gpointer data) * { * SomeClosure *closure = data; * * // it is safe to call Clutter API from this function because * / it is invoked from the same thread that started the main * / loop and under the Clutter thread lock * // * clutter_label_set_text (CLUTTER_LABEL (closure->label), * closure->text); * * g_object_unref (closure->label); * free (closure); * * return FALSE; * } * * // within another thread // * closure = g_new0 (SomeClosure, 1); * // always take a reference on GObject instances // * closure->label = g_object_ref (my_application->label); * closure->text = g_strdup (processed_text_to_update_the_label); * * clutter_threads_add_idle_full (G_PRIORITY_HIGH_IDLE, * update_ui, * closure, * NULL); * ]| * * Return value: the ID (greater than 0) of the event source. * * Since: 0.4 */ guint clutter_threads_add_idle_full (gint priority, GSourceFunc func, gpointer data, GDestroyNotify notify) { ClutterThreadsDispatch *dispatch; g_return_val_if_fail (func != NULL, 0); dispatch = g_slice_new (ClutterThreadsDispatch); dispatch->func = func; dispatch->data = data; dispatch->notify = notify; return g_idle_add_full (priority, _clutter_threads_dispatch, dispatch, _clutter_threads_dispatch_free); } /** * clutter_threads_add_idle: (skip) * @func: function to call * @data: data to pass to the function * * Simple wrapper around clutter_threads_add_idle_full() using the * default priority. * * Return value: the ID (greater than 0) of the event source. * * Since: 0.4 */ guint clutter_threads_add_idle (GSourceFunc func, gpointer data) { g_return_val_if_fail (func != NULL, 0); return clutter_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE, func, data, NULL); } /** * clutter_threads_add_timeout_full: (rename-to clutter_threads_add_timeout) * @priority: the priority of the timeout source. Typically this will be in the * range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH. * @interval: the time between calls to the function, in milliseconds * @func: function to call * @data: data to pass to the function * @notify: function to call when the timeout source is removed * * Sets a function to be called at regular intervals holding the Clutter * threads lock, with the given priority. The function is called repeatedly * until it returns %FALSE, at which point the timeout is automatically * removed and the function will not be called again. The @notify function * is called when the timeout is removed. * * The first call to the function will be at the end of the first @interval. * * It is important to note that, due to how the Clutter main loop is * implemented, the timing will not be accurate and it will not try to * "keep up" with the interval. * * See also clutter_threads_add_idle_full(). * * Return value: the ID (greater than 0) of the event source. * * Since: 0.4 */ guint clutter_threads_add_timeout_full (gint priority, guint interval, GSourceFunc func, gpointer data, GDestroyNotify notify) { ClutterThreadsDispatch *dispatch; g_return_val_if_fail (func != NULL, 0); dispatch = g_slice_new (ClutterThreadsDispatch); dispatch->func = func; dispatch->data = data; dispatch->notify = notify; return g_timeout_add_full (priority, interval, _clutter_threads_dispatch, dispatch, _clutter_threads_dispatch_free); } /** * clutter_threads_add_timeout: (skip) * @interval: the time between calls to the function, in milliseconds * @func: function to call * @data: data to pass to the function * * Simple wrapper around clutter_threads_add_timeout_full(). * * Return value: the ID (greater than 0) of the event source. * * Since: 0.4 */ guint clutter_threads_add_timeout (guint interval, GSourceFunc func, gpointer data) { g_return_val_if_fail (func != NULL, 0); return clutter_threads_add_timeout_full (G_PRIORITY_DEFAULT, interval, func, data, NULL); } void _clutter_threads_acquire_lock (void) { if (clutter_threads_lock != NULL) (* clutter_threads_lock) (); } void _clutter_threads_release_lock (void) { if (clutter_threads_unlock != NULL) (* clutter_threads_unlock) (); } /** * clutter_threads_enter: * * Locks the Clutter thread lock. * * Since: 0.4 * * Deprecated: 1.12: This function should not be used by application * code; marking critical sections is not portable on various * platforms. Instead of acquiring the Clutter lock, schedule UI * updates from the main loop using clutter_threads_add_idle() or * clutter_threads_add_timeout(). */ void clutter_threads_enter (void) { _clutter_threads_acquire_lock (); } /** * clutter_threads_leave: * * Unlocks the Clutter thread lock. * * Since: 0.4 * * Deprecated: 1.12: This function should not be used by application * code; marking critical sections is not portable on various * platforms. Instead of acquiring the Clutter lock, schedule UI * updates from the main loop using clutter_threads_add_idle() or * clutter_threads_add_timeout(). */ void clutter_threads_leave (void) { _clutter_threads_release_lock (); } /** * clutter_get_debug_enabled: * * Check if Clutter has debugging enabled. * * Return value: %FALSE * * Deprecated: 1.10: This function does not do anything. */ gboolean clutter_get_debug_enabled (void) { return FALSE; } void _clutter_context_lock (void) { G_LOCK (ClutterCntx); } void _clutter_context_unlock (void) { G_UNLOCK (ClutterCntx); } gboolean _clutter_context_is_initialized (void) { if (ClutterCntx == NULL) return FALSE; return ClutterCntx->is_initialized; } static ClutterMainContext * clutter_context_get_default_unlocked (void) { if (G_UNLIKELY (ClutterCntx == NULL)) { ClutterMainContext *ctx; /* Read the configuration file, if any, before we set up the * whole thing, so that we can override things like the backend * and the driver */ clutter_config_read (); ClutterCntx = ctx = g_new0 (ClutterMainContext, 1); ctx->is_initialized = FALSE; /* create the windowing system backend */ ctx->backend = _clutter_create_backend (); /* create the default settings object, and store a back pointer to * the backend singleton */ ctx->settings = clutter_settings_get_default (); _clutter_settings_set_backend (ctx->settings, ctx->backend); ctx->motion_events_per_actor = TRUE; ctx->last_repaint_id = 1; } return ClutterCntx; } ClutterMainContext * _clutter_context_get_default (void) { ClutterMainContext *retval; _clutter_context_lock (); retval = clutter_context_get_default_unlocked (); _clutter_context_unlock (); return retval; } /** * clutter_get_timestamp: * * Returns the approximate number of microseconds passed since Clutter was * intialised. * * This function shdould not be used by application code. * * The output of this function depends on whether Clutter was configured to * enable its debugging code paths, so it's less useful than intended. * * Since Clutter 1.10, this function is an alias to g_get_monotonic_time() * if Clutter was configured to enable the debugging code paths. * * Return value: Number of microseconds since clutter_init() was called, or * zero if Clutter was not configured with debugging code paths. * * Deprecated: 1.10: Use #GTimer or g_get_monotonic_time() for a proper * timing source */ gulong clutter_get_timestamp (void) { #ifdef CLUTTER_ENABLE_DEBUG return (gulong) g_get_monotonic_time (); #else return 0L; #endif } static gboolean clutter_arg_direction_cb (const char *key, const char *value, gpointer user_data) { clutter_text_direction = (strcmp (value, "rtl") == 0) ? CLUTTER_TEXT_DIRECTION_RTL : CLUTTER_TEXT_DIRECTION_LTR; return TRUE; } #ifdef CLUTTER_ENABLE_DEBUG static gboolean clutter_arg_debug_cb (const char *key, const char *value, gpointer user_data) { clutter_debug_flags |= g_parse_debug_string (value, clutter_debug_keys, G_N_ELEMENTS (clutter_debug_keys)); return TRUE; } static gboolean clutter_arg_no_debug_cb (const char *key, const char *value, gpointer user_data) { clutter_debug_flags &= ~g_parse_debug_string (value, clutter_debug_keys, G_N_ELEMENTS (clutter_debug_keys)); return TRUE; } #endif /* CLUTTER_ENABLE_DEBUG */ GQuark clutter_init_error_quark (void) { return g_quark_from_static_string ("clutter-init-error-quark"); } static ClutterInitError clutter_init_real (GError **error) { ClutterMainContext *ctx; ClutterBackend *backend; /* Note, creates backend if not already existing, though parse args will * have likely created it */ ctx = _clutter_context_get_default (); backend = ctx->backend; if (!ctx->options_parsed) { if (error) g_set_error (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_INTERNAL, "When using clutter_get_option_group_without_init() " "you must parse options before calling clutter_init()"); else g_critical ("When using clutter_get_option_group_without_init() " "you must parse options before calling clutter_init()"); return CLUTTER_INIT_ERROR_INTERNAL; } /* * Call backend post parse hooks. */ if (!_clutter_backend_post_parse (backend, error)) return CLUTTER_INIT_ERROR_BACKEND; /* If we are displaying the regions that would get redrawn with clipped * redraws enabled we actually have to disable the clipped redrawing * because otherwise we end up with nasty trails of rectangles everywhere. */ if (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS) clutter_paint_debug_flags |= CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS; /* The same is true when drawing the outlines of paint volumes... */ if (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES) { clutter_paint_debug_flags |= CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS | CLUTTER_DEBUG_DISABLE_CULLING; } /* this will take care of initializing Cogl's state and * query the GL machinery for features */ if (!_clutter_feature_init (error)) return CLUTTER_INIT_ERROR_BACKEND; clutter_text_direction = clutter_get_text_direction (); /* Initiate event collection */ _clutter_backend_init_events (ctx->backend); clutter_is_initialized = TRUE; ctx->is_initialized = TRUE; /* Initialize a11y */ if (clutter_enable_accessibility) cally_accessibility_init (); return CLUTTER_INIT_SUCCESS; } static GOptionEntry clutter_args[] = { { "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps, N_("Show frames per second"), NULL }, { "clutter-default-fps", 0, 0, G_OPTION_ARG_INT, &clutter_default_fps, N_("Default frame rate"), "FPS" }, { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &clutter_fatal_warnings, N_("Make all warnings fatal"), NULL }, { "clutter-text-direction", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_direction_cb, N_("Direction for the text"), "DIRECTION" }, { "clutter-disable-mipmapped-text", 0, 0, G_OPTION_ARG_NONE, &clutter_disable_mipmap_text, N_("Disable mipmapping on text"), NULL }, { "clutter-use-fuzzy-picking", 0, 0, G_OPTION_ARG_NONE, &clutter_use_fuzzy_picking, N_("Use 'fuzzy' picking"), NULL }, #ifdef CLUTTER_ENABLE_DEBUG { "clutter-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_debug_cb, N_("Clutter debugging flags to set"), "FLAGS" }, { "clutter-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_no_debug_cb, N_("Clutter debugging flags to unset"), "FLAGS" }, #endif /* CLUTTER_ENABLE_DEBUG */ { "clutter-enable-accessibility", 0, 0, G_OPTION_ARG_NONE, &clutter_enable_accessibility, N_("Enable accessibility"), NULL }, { NULL, }, }; /* pre_parse_hook: initialise variables depending on environment * variables; these variables might be overridden by the command * line arguments that are going to be parsed after. */ static gboolean pre_parse_hook (GOptionContext *context, GOptionGroup *group, gpointer data, GError **error) { ClutterMainContext *clutter_context; ClutterBackend *backend; const char *env_string; if (clutter_is_initialized) return TRUE; clutter_context = _clutter_context_get_default (); backend = clutter_context->backend; g_assert (CLUTTER_IS_BACKEND (backend)); #ifdef CLUTTER_ENABLE_DEBUG env_string = g_getenv ("CLUTTER_DEBUG"); if (env_string != NULL) { clutter_debug_flags = g_parse_debug_string (env_string, clutter_debug_keys, G_N_ELEMENTS (clutter_debug_keys)); env_string = NULL; } #endif /* CLUTTER_ENABLE_DEBUG */ env_string = g_getenv ("CLUTTER_PICK"); if (env_string != NULL) { clutter_pick_debug_flags = g_parse_debug_string (env_string, clutter_pick_debug_keys, G_N_ELEMENTS (clutter_pick_debug_keys)); env_string = NULL; } env_string = g_getenv ("CLUTTER_PAINT"); if (env_string != NULL) { clutter_paint_debug_flags = g_parse_debug_string (env_string, clutter_paint_debug_keys, G_N_ELEMENTS (clutter_paint_debug_keys)); env_string = NULL; } env_string = g_getenv ("CLUTTER_SHOW_FPS"); if (env_string) clutter_show_fps = TRUE; env_string = g_getenv ("CLUTTER_DEFAULT_FPS"); if (env_string) { gint default_fps = g_ascii_strtoll (env_string, NULL, 10); clutter_default_fps = CLAMP (default_fps, 1, 1000); } env_string = g_getenv ("CLUTTER_DISABLE_MIPMAPPED_TEXT"); if (env_string) clutter_disable_mipmap_text = TRUE; env_string = g_getenv ("CLUTTER_FUZZY_PICK"); if (env_string) clutter_use_fuzzy_picking = TRUE; env_string = g_getenv ("CLUTTER_VBLANK"); if (g_strcmp0 (env_string, "none") == 0) clutter_sync_to_vblank = FALSE; return _clutter_backend_pre_parse (backend, error); } /* post_parse_hook: initialise the context and data structures * and opens the X display */ static gboolean post_parse_hook (GOptionContext *context, GOptionGroup *group, gpointer data, GError **error) { ClutterMainContext *clutter_context; ClutterBackend *backend; if (clutter_is_initialized) return TRUE; clutter_context = _clutter_context_get_default (); backend = clutter_context->backend; g_assert (CLUTTER_IS_BACKEND (backend)); if (clutter_fatal_warnings) { GLogLevelFlags fatal_mask; fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; g_log_set_always_fatal (fatal_mask); } clutter_context->frame_rate = clutter_default_fps; clutter_context->show_fps = clutter_show_fps; clutter_context->options_parsed = TRUE; /* If not asked to defer display setup, call clutter_init_real(), * which in turn calls the backend post parse hooks. */ if (!clutter_context->defer_display_setup) return clutter_init_real (error) == CLUTTER_INIT_SUCCESS; return TRUE; } /** * clutter_get_option_group: (skip) * * Returns a #GOptionGroup for the command line arguments recognized * by Clutter. You should add this group to your #GOptionContext with * g_option_context_add_group(), if you are using g_option_context_parse() * to parse your commandline arguments. * * Calling g_option_context_parse() with Clutter's #GOptionGroup will result * in Clutter's initialization. That is, the following code: * * |[ * g_option_context_set_main_group (context, clutter_get_option_group ()); * res = g_option_context_parse (context, &argc, &argc, NULL); * ]| * * is functionally equivalent to: * * |[ * clutter_init (&argc, &argv); * ]| * * After g_option_context_parse() on a #GOptionContext containing the * Clutter #GOptionGroup has returned %TRUE, Clutter is guaranteed to be * initialized. * * Return value: (transfer full): a #GOptionGroup for the commandline arguments * recognized by Clutter * * Since: 0.2 */ GOptionGroup * clutter_get_option_group (void) { ClutterMainContext *context; GOptionGroup *group; clutter_base_init (); context = _clutter_context_get_default (); group = g_option_group_new ("clutter", _("Clutter Options"), _("Show Clutter Options"), NULL, NULL); g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook); g_option_group_add_entries (group, clutter_args); /* add backend-specific options */ _clutter_backend_add_options (context->backend, group); return group; } /** * clutter_get_option_group_without_init: (skip) * * Returns a #GOptionGroup for the command line arguments recognized * by Clutter. You should add this group to your #GOptionContext with * g_option_context_add_group(), if you are using g_option_context_parse() * to parse your commandline arguments. * * Unlike clutter_get_option_group(), calling g_option_context_parse() with * the #GOptionGroup returned by this function requires a subsequent explicit * call to clutter_init(); use this function when needing to set foreign * display connection with clutter_x11_set_display(), or with * `gtk_clutter_init()`. * * Return value: (transfer full): a #GOptionGroup for the commandline arguments * recognized by Clutter * * Since: 0.8 */ GOptionGroup * clutter_get_option_group_without_init (void) { ClutterMainContext *context; GOptionGroup *group; clutter_base_init (); context = _clutter_context_get_default (); context->defer_display_setup = TRUE; group = clutter_get_option_group (); return group; } /* Note that the gobject-introspection annotations for the argc/argv * parameters do not produce the right result; however, they do * allow the common case of argc=NULL, argv=NULL to work. */ /** * clutter_init_with_args: * @argc: (inout): a pointer to the number of command line arguments * @argv: (array length=argc) (inout) (allow-none): a pointer to the array * of command line arguments * @parameter_string: (allow-none): a string which is displayed in the * first line of <option>--help</option> output, after * <literal><replaceable>programname</replaceable> [OPTION...]</literal> * @entries: (array) (allow-none): a %NULL terminated array of * #GOptionEntry<!-- -->s describing the options of your program * @translation_domain: (allow-none): a translation domain to use for * translating the <option>--help</option> output for the options in * @entries with gettext(), or %NULL * @error: (allow-none): a return location for a #GError * * This function does the same work as clutter_init(). Additionally, * it allows you to add your own command line options, and it * automatically generates nicely formatted <option>--help</option> * output. Note that your program will be terminated after writing * out the help output. Also note that, in case of error, the * error message will be placed inside @error instead of being * printed on the display. * * Just like clutter_init(), if this function returns an error code then * any subsequent call to any other Clutter API will result in undefined * behaviour - including segmentation faults. * * Return value: %CLUTTER_INIT_SUCCESS if Clutter has been successfully * initialised, or other values or #ClutterInitError in case of * error. * * Since: 0.2 */ ClutterInitError clutter_init_with_args (int *argc, char ***argv, const char *parameter_string, GOptionEntry *entries, const char *translation_domain, GError **error) { GOptionContext *context; GOptionGroup *group; gboolean res; ClutterMainContext *ctx; if (clutter_is_initialized) return CLUTTER_INIT_SUCCESS; clutter_base_init (); ctx = _clutter_context_get_default (); if (!ctx->defer_display_setup) { #if 0 if (argc && *argc > 0 && *argv) g_set_prgname ((*argv)[0]); #endif context = g_option_context_new (parameter_string); group = clutter_get_option_group (); g_option_context_add_group (context, group); group = cogl_get_option_group (); g_option_context_add_group (context, group); if (entries) g_option_context_add_main_entries (context, entries, translation_domain); res = g_option_context_parse (context, argc, argv, error); g_option_context_free (context); /* if res is FALSE, the error is filled for * us by g_option_context_parse() */ if (!res) { /* if there has been an error in the initialization, the * error id will be preserved inside the GError code */ if (error && *error) return (*error)->code; else return CLUTTER_INIT_ERROR_INTERNAL; } return CLUTTER_INIT_SUCCESS; } else return clutter_init_real (error); } static gboolean clutter_parse_args (int *argc, char ***argv, GError **error) { GOptionContext *option_context; GOptionGroup *clutter_group, *cogl_group; GError *internal_error = NULL; gboolean ret = TRUE; if (clutter_is_initialized) return TRUE; option_context = g_option_context_new (NULL); g_option_context_set_ignore_unknown_options (option_context, TRUE); g_option_context_set_help_enabled (option_context, FALSE); /* Initiate any command line options from the backend */ clutter_group = clutter_get_option_group (); g_option_context_set_main_group (option_context, clutter_group); cogl_group = cogl_get_option_group (); g_option_context_add_group (option_context, cogl_group); if (!g_option_context_parse (option_context, argc, argv, &internal_error)) { g_propagate_error (error, internal_error); ret = FALSE; } g_option_context_free (option_context); return ret; } /** * clutter_init: * @argc: (inout): The number of arguments in @argv * @argv: (array length=argc) (inout) (allow-none): A pointer to an array * of arguments. * * Initialises everything needed to operate with Clutter and parses some * standard command line options; @argc and @argv are adjusted accordingly * so your own code will never see those standard arguments. * * It is safe to call this function multiple times. * * This function will not abort in case of errors during * initialization; clutter_init() will print out the error message on * stderr, and will return an error code. It is up to the application * code to handle this case. If you need to display the error message * yourself, you can use clutter_init_with_args(), which takes a #GError * pointer. * * If this function fails, and returns an error code, any subsequent * Clutter API will have undefined behaviour - including segmentation * faults and assertion failures. Make sure to handle the returned * #ClutterInitError enumeration value. * * Return value: a #ClutterInitError value */ ClutterInitError clutter_init (int *argc, char ***argv) { ClutterMainContext *ctx; GError *error = NULL; ClutterInitError res; if (clutter_is_initialized) return CLUTTER_INIT_SUCCESS; clutter_base_init (); ctx = _clutter_context_get_default (); if (!ctx->defer_display_setup) { #if 0 if (argc && *argc > 0 && *argv) g_set_prgname ((*argv)[0]); #endif /* parse_args will trigger backend creation and things like * DISPLAY connection etc. */ if (!clutter_parse_args (argc, argv, &error)) { g_critical ("Unable to initialize Clutter: %s", error->message); g_error_free (error); res = CLUTTER_INIT_ERROR_INTERNAL; } else res = CLUTTER_INIT_SUCCESS; } else { res = clutter_init_real (&error); if (error != NULL) { g_critical ("Unable to initialize Clutter: %s", error->message); g_error_free (error); } } return res; } gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer dummy) { gboolean continue_emission; gboolean signal_handled; signal_handled = g_value_get_boolean (handler_return); g_value_set_boolean (return_accu, signal_handled); continue_emission = !signal_handled; return continue_emission; } gboolean _clutter_boolean_continue_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer dummy) { gboolean continue_emission; continue_emission = g_value_get_boolean (handler_return); g_value_set_boolean (return_accu, continue_emission); return continue_emission; } static void event_click_count_generate (ClutterEvent *event) { /* multiple button click detection */ static gint click_count = 0; static gint previous_x = -1; static gint previous_y = -1; static guint32 previous_time = 0; static gint previous_button_number = -1; ClutterInputDevice *device = NULL; ClutterSettings *settings; guint double_click_time; guint double_click_distance; settings = clutter_settings_get_default (); g_object_get (settings, "double-click-distance", &double_click_distance, "double-click-time", &double_click_time, NULL); device = clutter_event_get_device (event); if (device != NULL) { click_count = device->click_count; previous_x = device->previous_x; previous_y = device->previous_y; previous_time = device->previous_time; previous_button_number = device->previous_button_number; CLUTTER_NOTE (EVENT, "Restoring previous click count:%d (device:%d, time:%u)", click_count, clutter_input_device_get_device_id (device), previous_time); } else { CLUTTER_NOTE (EVENT, "Restoring previous click count:%d (time:%u)", click_count, previous_time); } switch (clutter_event_type (event)) { case CLUTTER_BUTTON_PRESS: /* check if we are in time and within distance to increment an * existing click count */ if (event->button.button == previous_button_number && event->button.time < (previous_time + double_click_time) && (ABS (event->button.x - previous_x) <= double_click_distance) && (ABS (event->button.y - previous_y) <= double_click_distance)) { CLUTTER_NOTE (EVENT, "Increase click count (button: %d, time: %u)", event->button.button, event->button.time); click_count += 1; } else /* start a new click count*/ { CLUTTER_NOTE (EVENT, "Reset click count (button: %d, time: %u)", event->button.button, event->button.time); click_count = 1; previous_button_number = event->button.button; } previous_x = event->button.x; previous_y = event->button.y; previous_time = event->button.time; /* fallthrough */ case CLUTTER_BUTTON_RELEASE: event->button.click_count = click_count; break; default: g_assert_not_reached (); break; } if (event->type == CLUTTER_BUTTON_PRESS && device != NULL) { CLUTTER_NOTE (EVENT, "Storing click count: %d (device:%d, time:%u)", click_count, clutter_input_device_get_device_id (device), previous_time); device->click_count = click_count; device->previous_x = previous_x; device->previous_y = previous_y; device->previous_time = previous_time; device->previous_button_number = previous_button_number; } } static inline void emit_event_chain (ClutterEvent *event) { static gboolean lock = FALSE; if (event->any.source == NULL) { CLUTTER_NOTE (EVENT, "No source set, discarding event"); return; } /* reentrancy check */ if (lock != FALSE) { g_warning ("Tried emitting event during event delivery, bailing out."); return; } lock = TRUE; _clutter_actor_handle_event (event->any.source, event); lock = FALSE; } /* * Emits a pointer event after having prepared the event for delivery (setting * source, computing click_count, generating enter/leave etc.). */ static inline void emit_pointer_event (ClutterEvent *event, ClutterInputDevice *device) { ClutterMainContext *context = _clutter_context_get_default (); if (_clutter_event_process_filters (event)) return; if (context->pointer_grab_actor == NULL && (device == NULL || device->pointer_grab_actor == NULL)) { /* no grab, time to capture and bubble */ emit_event_chain (event); } else { if (context->pointer_grab_actor != NULL) { /* global grab */ clutter_actor_event (context->pointer_grab_actor, event, FALSE); } else if (device != NULL && device->pointer_grab_actor != NULL) { /* per device grab */ clutter_actor_event (device->pointer_grab_actor, event, FALSE); } } } static inline void emit_touch_event (ClutterEvent *event, ClutterInputDevice *device) { ClutterActor *grab_actor = NULL; if (_clutter_event_process_filters (event)) return; if (device->sequence_grab_actors != NULL) { grab_actor = g_hash_table_lookup (device->sequence_grab_actors, event->touch.sequence); } if (grab_actor != NULL) { /* per-device sequence grab */ clutter_actor_event (grab_actor, event, FALSE); } else { /* no grab, time to capture and bubble */ emit_event_chain (event); } } static inline void emit_keyboard_event (ClutterEvent *event, ClutterInputDevice *device) { ClutterMainContext *context = _clutter_context_get_default (); if (_clutter_event_process_filters (event)) return; if (context->keyboard_grab_actor == NULL && (device == NULL || device->keyboard_grab_actor == NULL)) { /* no grab, time to capture and bubble */ emit_event_chain (event); } else { if (context->keyboard_grab_actor != NULL) { /* global key grab */ clutter_actor_event (context->keyboard_grab_actor, event, FALSE); } else if (device != NULL && device->keyboard_grab_actor != NULL) { /* per-device key grab */ clutter_actor_event (context->keyboard_grab_actor, event, FALSE); } } } static inline void process_key_event (ClutterEvent *event, ClutterInputDevice *device) { ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (device_class->process_kbd_a11y_event) { device_class->process_kbd_a11y_event (event, device, emit_keyboard_event); return; } emit_keyboard_event (event, device); } static gboolean is_off_stage (ClutterActor *stage, gfloat x, gfloat y) { gfloat width, height; clutter_actor_get_size (stage, &width, &height); return (x < 0 || y < 0 || x >= width || y >= height); } /** * clutter_do_event: * @event: a #ClutterEvent. * * Processes an event. * * The @event must be a valid #ClutterEvent and have a #ClutterStage * associated to it. * * This function is only useful when embedding Clutter inside another * toolkit, and it should never be called by applications. * * Since: 0.4 */ void clutter_do_event (ClutterEvent *event) { /* we need the stage for the event */ if (event->any.stage == NULL) { g_warning ("%s: Event does not have a stage: discarding.", G_STRFUNC); return; } /* stages in destruction do not process events */ if (CLUTTER_ACTOR_IN_DESTRUCTION (event->any.stage)) return; /* Instead of processing events when received, we queue them up to * handle per-frame before animations, layout, and drawing. * * This gives us the chance to reliably compress motion events * because we've "looked ahead" and know all motion events that * will occur before drawing the frame. */ _clutter_stage_queue_event (event->any.stage, event, TRUE); } static void _clutter_process_event_details (ClutterActor *stage, ClutterMainContext *context, ClutterEvent *event) { ClutterInputDevice *device = clutter_event_get_device (event); switch (event->type) { case CLUTTER_NOTHING: event->any.source = stage; break; case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: case CLUTTER_PAD_STRIP: case CLUTTER_PAD_RING: { ClutterActor *actor = NULL; /* check that we're not a synthetic event with source set */ if (event->any.source == NULL) { actor = clutter_stage_get_key_focus (CLUTTER_STAGE (stage)); event->any.source = actor; if (G_UNLIKELY (actor == NULL)) { g_warning ("No key focus set, discarding"); return; } } process_key_event (event, device); } break; case CLUTTER_ENTER: /* if we're entering from outside the stage we need * to check whether the pointer is actually on another * actor, and emit an additional pointer event */ if (event->any.source == stage && event->crossing.related == NULL) { ClutterActor *actor = NULL; emit_pointer_event (event, device); actor = _clutter_input_device_update (device, NULL, FALSE); if (actor != stage) { ClutterEvent *crossing; /* we emit the exact same event on the actor */ crossing = clutter_event_copy (event); crossing->crossing.related = stage; crossing->crossing.source = actor; emit_pointer_event (crossing, device); clutter_event_free (crossing); } } else emit_pointer_event (event, device); break; case CLUTTER_LEAVE: /* same as CLUTTER_ENTER above: when leaving the stage * we need to also emit a CLUTTER_LEAVE event on the * actor currently underneath the device, unless it's the * stage */ if (event->any.source == stage && event->crossing.related == NULL && device->cursor_actor != stage) { ClutterEvent *crossing; crossing = clutter_event_copy (event); crossing->crossing.related = stage; crossing->crossing.source = device->cursor_actor; emit_pointer_event (crossing, device); clutter_event_free (crossing); } emit_pointer_event (event, device); break; case CLUTTER_DESTROY_NOTIFY: case CLUTTER_DELETE: event->any.source = stage; if (_clutter_event_process_filters (event)) break; /* the stage did not handle the event, so we just quit */ clutter_stage_event (CLUTTER_STAGE (stage), event); break; case CLUTTER_MOTION: /* only the stage gets motion events if they are enabled */ if (!clutter_stage_get_motion_events_enabled (CLUTTER_STAGE (stage)) && event->any.source == NULL) { /* Only stage gets motion events */ event->any.source = stage; if (_clutter_event_process_filters (event)) break; /* global grabs */ if (context->pointer_grab_actor != NULL) { clutter_actor_event (context->pointer_grab_actor, event, FALSE); break; } else if (device != NULL && device->pointer_grab_actor != NULL) { clutter_actor_event (device->pointer_grab_actor, event, FALSE); break; } /* Trigger handlers on stage in both capture .. */ if (!clutter_actor_event (stage, event, TRUE)) { /* and bubbling phase */ clutter_actor_event (stage, event, FALSE); } break; } /* fallthrough from motion */ case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: case CLUTTER_SCROLL: case CLUTTER_TOUCHPAD_PINCH: case CLUTTER_TOUCHPAD_SWIPE: { ClutterActor *actor; gfloat x, y; clutter_event_get_coords (event, &x, &y); /* Only do a pick to find the source if source is not already set * (as it could be in a synthetic event) */ if (event->any.source == NULL) { /* emulate X11 the implicit soft grab; the implicit soft grab * keeps relaying motion events when the stage is left with a * pointer button pressed. since this is what happens when we * disable per-actor motion events we need to maintain the same * behaviour when the per-actor motion events are enabled as * well */ if (is_off_stage (stage, x, y)) { if (event->type == CLUTTER_BUTTON_RELEASE) { CLUTTER_NOTE (EVENT, "Release off stage received at %.2f, %.2f", x, y); event->button.source = stage; event->button.click_count = 1; emit_pointer_event (event, device); } else if (event->type == CLUTTER_MOTION) { CLUTTER_NOTE (EVENT, "Motion off stage received at %.2f, %2.f", x, y); event->motion.source = stage; emit_pointer_event (event, device); } break; } /* if the backend provides a device then we should * already have everything we need to update it and * get the actor underneath */ if (device != NULL) actor = _clutter_input_device_update (device, NULL, TRUE); else { CLUTTER_NOTE (EVENT, "No device found: picking"); actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage), x, y, CLUTTER_PICK_REACTIVE); } if (actor == NULL) break; event->any.source = actor; } else { /* use the source already set in the synthetic event */ actor = event->any.source; } CLUTTER_NOTE (EVENT, "Reactive event received at %.2f, %.2f - actor: %p", x, y, actor); /* button presses and releases need a click count */ if (event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_BUTTON_RELEASE) { /* Generate click count */ event_click_count_generate (event); } emit_pointer_event (event, device); break; } case CLUTTER_TOUCH_UPDATE: /* only the stage gets motion events if they are enabled */ if (!clutter_stage_get_motion_events_enabled (CLUTTER_STAGE (stage)) && event->any.source == NULL) { ClutterActor *grab_actor = NULL; /* Only stage gets motion events */ event->any.source = stage; if (_clutter_event_process_filters (event)) break; /* global grabs */ if (device->sequence_grab_actors != NULL) { grab_actor = g_hash_table_lookup (device->sequence_grab_actors, event->touch.sequence); } if (grab_actor != NULL) { clutter_actor_event (grab_actor, event, FALSE); break; } /* Trigger handlers on stage in both capture .. */ if (!clutter_actor_event (stage, event, TRUE)) { /* and bubbling phase */ clutter_actor_event (stage, event, FALSE); } break; } /* fallthrough from motion */ case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_CANCEL: case CLUTTER_TOUCH_END: { ClutterActor *actor; ClutterEventSequence *sequence; gfloat x, y; sequence = clutter_event_get_event_sequence (event); if (event->type == CLUTTER_TOUCH_BEGIN) _clutter_input_device_add_event_sequence (device, event); clutter_event_get_coords (event, &x, &y); /* Only do a pick to find the source if source is not already set * (as it could be in a synthetic event) */ if (event->any.source == NULL) { /* same as the mouse events above, emulate the X11 implicit * soft grab */ if (is_off_stage (stage, x, y)) { CLUTTER_NOTE (EVENT, "Touch %s off stage received at %.2f, %.2f", event->type == CLUTTER_TOUCH_UPDATE ? "update" : event->type == CLUTTER_TOUCH_END ? "end" : event->type == CLUTTER_TOUCH_CANCEL ? "cancel" : "?", x, y); event->touch.source = stage; emit_touch_event (event, device); if (event->type == CLUTTER_TOUCH_END) _clutter_input_device_remove_event_sequence (device, event); break; } if (device != NULL) actor = _clutter_input_device_update (device, sequence, TRUE); else { CLUTTER_NOTE (EVENT, "No device found: picking"); actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage), x, y, CLUTTER_PICK_REACTIVE); } if (actor == NULL) break; event->any.source = actor; } else { /* use the source already set in the synthetic event */ actor = event->any.source; } CLUTTER_NOTE (EVENT, "Reactive event received at %.2f, %.2f - actor: %p", x, y, actor); emit_touch_event (event, device); if (event->type == CLUTTER_TOUCH_END) _clutter_input_device_remove_event_sequence (device, event); break; } case CLUTTER_PROXIMITY_IN: case CLUTTER_PROXIMITY_OUT: clutter_input_device_update_from_tool (clutter_event_get_source_device (event), clutter_event_get_device_tool (event)); if (_clutter_event_process_filters (event)) break; if (!clutter_actor_event (stage, event, TRUE)) { /* and bubbling phase */ clutter_actor_event (stage, event, FALSE); } break; case CLUTTER_STAGE_STATE: /* fullscreen / focus - forward to stage */ event->any.source = stage; if (!_clutter_event_process_filters (event)) clutter_stage_event (CLUTTER_STAGE (stage), event); break; case CLUTTER_CLIENT_MESSAGE: break; case CLUTTER_EVENT_LAST: break; } } /* * _clutter_process_event * @event: a #ClutterEvent. * * Does the actual work of processing an event that was queued earlier * out of clutter_do_event(). */ void _clutter_process_event (ClutterEvent *event) { ClutterMainContext *context; ClutterActor *stage; context = _clutter_context_get_default (); stage = CLUTTER_ACTOR (event->any.stage); if (stage == NULL) { CLUTTER_NOTE (EVENT, "Discarding event without a stage set"); return; } /* push events on a stack, so that we don't need to * add an event parameter to all signals that can be emitted within * an event chain */ context->current_event = g_slist_prepend (context->current_event, event); _clutter_process_event_details (stage, context, event); context->current_event = g_slist_delete_link (context->current_event, context->current_event); } /** * clutter_get_actor_by_gid: * @id_: a #ClutterActor unique id. * * Retrieves the #ClutterActor with @id_. * * Return value: (transfer none): the actor with the passed id or %NULL. * The returned actor does not have its reference count increased. * * Since: 0.6 * * Deprecated: 1.8: The id is deprecated, and this function always returns * %NULL. Use the proper scene graph API in #ClutterActor to find a child * of the stage. */ ClutterActor * clutter_get_actor_by_gid (guint32 id_) { return NULL; } void clutter_base_init (void) { static gboolean initialised = FALSE; if (!initialised) { initialised = TRUE; #if !GLIB_CHECK_VERSION (2, 35, 1) /* initialise GLib type system */ g_type_init (); #endif /* initialise the Big Clutter Lock™ if necessary */ clutter_threads_init_default (); } } /** * clutter_get_default_frame_rate: * * Retrieves the default frame rate. See clutter_set_default_frame_rate(). * * Return value: the default frame rate * * Since: 0.6 */ guint clutter_get_default_frame_rate (void) { ClutterMainContext *context; context = _clutter_context_get_default (); return context->frame_rate; } /** * clutter_set_default_frame_rate: * @frames_per_sec: the new default frame rate * * Sets the default frame rate. This frame rate will be used to limit * the number of frames drawn if Clutter is not able to synchronize * with the vertical refresh rate of the display. When synchronization * is possible, this value is ignored. * * Since: 0.6 * * Deprecated: 1.10: This function does not do anything any more. */ void clutter_set_default_frame_rate (guint frames_per_sec) { } static void on_grab_actor_destroy (ClutterActor *actor, ClutterInputDevice *device) { if (device == NULL) { ClutterMainContext *context = _clutter_context_get_default (); if (context->pointer_grab_actor == actor) clutter_ungrab_pointer (); if (context->keyboard_grab_actor == actor) clutter_ungrab_keyboard (); return; } switch (device->device_type) { case CLUTTER_POINTER_DEVICE: device->pointer_grab_actor = NULL; break; case CLUTTER_KEYBOARD_DEVICE: device->keyboard_grab_actor = NULL; break; default: g_assert_not_reached (); } } /** * clutter_grab_pointer: * @actor: a #ClutterActor * * Grabs pointer events, after the grab is done all pointer related events * (press, motion, release, enter, leave and scroll) are delivered to this * actor directly without passing through both capture and bubble phases of * the event delivery chain. The source set in the event will be the actor * that would have received the event if the pointer grab was not in effect. * * Grabs completely override the entire event delivery chain * done by Clutter. Pointer grabs should only be used as a last resource; * using the #ClutterActor::captured-event signal should always be the * preferred way to intercept event delivery to reactive actors. * * This function should rarely be used. * * If a grab is required, you are strongly encouraged to use a specific * input device by calling clutter_input_device_grab(). * * Since: 0.6 */ void clutter_grab_pointer (ClutterActor *actor) { ClutterMainContext *context; g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); context = _clutter_context_get_default (); if (context->pointer_grab_actor == actor) return; if (context->pointer_grab_actor != NULL) { g_signal_handlers_disconnect_by_func (context->pointer_grab_actor, G_CALLBACK (on_grab_actor_destroy), NULL); context->pointer_grab_actor = NULL; } if (actor != NULL) { context->pointer_grab_actor = actor; g_signal_connect (context->pointer_grab_actor, "destroy", G_CALLBACK (on_grab_actor_destroy), NULL); } } /** * clutter_input_device_grab: * @device: a #ClutterInputDevice * @actor: a #ClutterActor * * Acquires a grab on @actor for the given @device. * * Any event coming from @device will be delivered to @actor, bypassing * the usual event delivery mechanism, until the grab is released by * calling clutter_input_device_ungrab(). * * The grab is client-side: even if the windowing system used by the Clutter * backend has the concept of "device grabs", Clutter will not use them. * * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE and * %CLUTTER_KEYBOARD_DEVICE can hold a grab. * * Since: 1.10 */ void clutter_input_device_grab (ClutterInputDevice *device, ClutterActor *actor) { ClutterActor **grab_actor; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); switch (device->device_type) { case CLUTTER_POINTER_DEVICE: grab_actor = &(device->pointer_grab_actor); break; case CLUTTER_KEYBOARD_DEVICE: grab_actor = &(device->keyboard_grab_actor); break; default: g_critical ("Only pointer and keyboard devices can grab an actor"); return; } if (*grab_actor != NULL) { g_signal_handlers_disconnect_by_func (*grab_actor, G_CALLBACK (on_grab_actor_destroy), device); } *grab_actor = actor; g_signal_connect (*grab_actor, "destroy", G_CALLBACK (on_grab_actor_destroy), device); } /** * clutter_input_device_ungrab: * @device: a #ClutterInputDevice * * Releases the grab on the @device, if one is in place. * * Since: 1.10 */ void clutter_input_device_ungrab (ClutterInputDevice *device) { ClutterActor **grab_actor; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); switch (device->device_type) { case CLUTTER_POINTER_DEVICE: grab_actor = &(device->pointer_grab_actor); break; case CLUTTER_KEYBOARD_DEVICE: grab_actor = &(device->keyboard_grab_actor); break; default: return; } if (*grab_actor == NULL) return; g_signal_handlers_disconnect_by_func (*grab_actor, G_CALLBACK (on_grab_actor_destroy), device); *grab_actor = NULL; } /** * clutter_input_device_get_grabbed_actor: * @device: a #ClutterInputDevice * * Retrieves a pointer to the #ClutterActor currently grabbing all * the events coming from @device. * * Return value: (transfer none): a #ClutterActor, or %NULL * * Since: 1.10 */ ClutterActor * clutter_input_device_get_grabbed_actor (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); switch (device->device_type) { case CLUTTER_POINTER_DEVICE: return device->pointer_grab_actor; case CLUTTER_KEYBOARD_DEVICE: return device->keyboard_grab_actor; default: g_critical ("Only pointer and keyboard devices can grab an actor"); } return NULL; } /** * clutter_grab_pointer_for_device: * @actor: a #ClutterActor * @id_: a device id, or -1 * * Grabs all the pointer events coming from the device @id for @actor. * * If @id is -1 then this function is equivalent to clutter_grab_pointer(). * * Since: 0.8 * * Deprecated: 1.10: Use clutter_input_device_grab() instead. */ void clutter_grab_pointer_for_device (ClutterActor *actor, gint id_) { ClutterDeviceManager *manager; ClutterInputDevice *dev; g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); /* essentially a global grab */ if (id_ == -1) { if (actor == NULL) clutter_ungrab_pointer (); else clutter_grab_pointer (actor); return; } manager = clutter_device_manager_get_default (); if (manager == NULL) return; dev = clutter_device_manager_get_device (manager, id_); if (dev == NULL) return; if (dev->device_type != CLUTTER_POINTER_DEVICE) return; if (actor == NULL) clutter_input_device_ungrab (dev); else clutter_input_device_grab (dev, actor); } /** * clutter_ungrab_pointer: * * Removes an existing grab of the pointer. * * Since: 0.6 */ void clutter_ungrab_pointer (void) { clutter_grab_pointer (NULL); } /** * clutter_ungrab_pointer_for_device: * @id_: a device id * * Removes an existing grab of the pointer events for device @id_. * * Since: 0.8 * * Deprecated: 1.10: Use clutter_input_device_ungrab() instead. */ void clutter_ungrab_pointer_for_device (gint id_) { ClutterDeviceManager *manager; ClutterInputDevice *device; manager = clutter_device_manager_get_default (); if (manager == NULL) return; device = clutter_device_manager_get_device (manager, id_); if (device != NULL) clutter_input_device_ungrab (device); } /** * clutter_get_pointer_grab: * * Queries the current pointer grab of clutter. * * Return value: (transfer none): the actor currently holding the pointer grab, or NULL if there is no grab. * * Since: 0.6 */ ClutterActor * clutter_get_pointer_grab (void) { ClutterMainContext *context; context = _clutter_context_get_default (); return context->pointer_grab_actor; } /** * clutter_grab_keyboard: * @actor: a #ClutterActor * * Grabs keyboard events, after the grab is done keyboard * events (#ClutterActor::key-press-event and #ClutterActor::key-release-event) * are delivered to this actor directly. The source set in the event will be * the actor that would have received the event if the keyboard grab was not * in effect. * * Like pointer grabs, keyboard grabs should only be used as a last * resource. * * See also clutter_stage_set_key_focus() and clutter_actor_grab_key_focus() * to perform a "soft" key grab and assign key focus to a specific actor. * * Since: 0.6 */ void clutter_grab_keyboard (ClutterActor *actor) { ClutterMainContext *context; g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); context = _clutter_context_get_default (); if (context->keyboard_grab_actor == actor) return; if (context->keyboard_grab_actor != NULL) { g_signal_handlers_disconnect_by_func (context->keyboard_grab_actor, G_CALLBACK (on_grab_actor_destroy), NULL); context->keyboard_grab_actor = NULL; } if (actor != NULL) { context->keyboard_grab_actor = actor; g_signal_connect (context->keyboard_grab_actor, "destroy", G_CALLBACK (on_grab_actor_destroy), NULL); } } /** * clutter_ungrab_keyboard: * * Removes an existing grab of the keyboard. * * Since: 0.6 */ void clutter_ungrab_keyboard (void) { clutter_grab_keyboard (NULL); } /** * clutter_get_keyboard_grab: * * Queries the current keyboard grab of clutter. * * Return value: (transfer none): the actor currently holding the keyboard grab, or NULL if there is no grab. * * Since: 0.6 */ ClutterActor * clutter_get_keyboard_grab (void) { ClutterMainContext *context; context = _clutter_context_get_default (); return context->keyboard_grab_actor; } /** * clutter_clear_glyph_cache: * * Clears the internal cache of glyphs used by the Pango * renderer. This will free up some memory and GL texture * resources. The cache will be automatically refilled as more text is * drawn. * * Since: 0.8 * * Deprecated: 1.10: Use clutter_get_font_map() and * cogl_pango_font_map_clear_glyph_cache() instead. */ void clutter_clear_glyph_cache (void) { CoglPangoFontMap *font_map; font_map = clutter_context_get_pango_fontmap (); cogl_pango_font_map_clear_glyph_cache (font_map); } /** * clutter_set_font_flags: * @flags: The new flags * * Sets the font quality options for subsequent text rendering * operations. * * Using mipmapped textures will improve the quality for scaled down * text but will use more texture memory. * * Enabling hinting improves text quality for static text but may * introduce some artifacts if the text is animated. * * Since: 1.0 * * Deprecated: 1.10: Use clutter_backend_set_font_options() and the * #cairo_font_option_t API. */ void clutter_set_font_flags (ClutterFontFlags flags) { CoglPangoFontMap *font_map; ClutterFontFlags old_flags, changed_flags; const cairo_font_options_t *font_options; cairo_font_options_t *new_font_options; cairo_hint_style_t hint_style; gboolean use_mipmapping; ClutterBackend *backend; backend = clutter_get_default_backend (); font_map = clutter_context_get_pango_fontmap (); font_options = clutter_backend_get_font_options (backend); old_flags = 0; if (cogl_pango_font_map_get_use_mipmapping (font_map)) old_flags |= CLUTTER_FONT_MIPMAPPING; hint_style = cairo_font_options_get_hint_style (font_options); if (hint_style != CAIRO_HINT_STYLE_DEFAULT && hint_style != CAIRO_HINT_STYLE_NONE) old_flags |= CLUTTER_FONT_HINTING; if (old_flags == flags) return; new_font_options = cairo_font_options_copy (font_options); /* Only set the font options that have actually changed so we don't override a detailed setting from the backend */ changed_flags = old_flags ^ flags; if ((changed_flags & CLUTTER_FONT_MIPMAPPING)) { use_mipmapping = (changed_flags & CLUTTER_FONT_MIPMAPPING) != 0; cogl_pango_font_map_set_use_mipmapping (font_map, use_mipmapping); } if ((changed_flags & CLUTTER_FONT_HINTING)) { hint_style = (flags & CLUTTER_FONT_HINTING) ? CAIRO_HINT_STYLE_FULL : CAIRO_HINT_STYLE_NONE; cairo_font_options_set_hint_style (new_font_options, hint_style); } clutter_backend_set_font_options (backend, new_font_options); cairo_font_options_destroy (new_font_options); } /** * clutter_get_font_flags: * * Gets the current font flags for rendering text. See * clutter_set_font_flags(). * * Return value: The font flags * * Since: 1.0 * * Deprecated: 1.10: Use clutter_backend_get_font_options() and the * #cairo_font_options_t API. */ ClutterFontFlags clutter_get_font_flags (void) { CoglPangoFontMap *font_map = NULL; const cairo_font_options_t *font_options; ClutterFontFlags flags = 0; cairo_hint_style_t hint_style; font_map = clutter_context_get_pango_fontmap (); if (cogl_pango_font_map_get_use_mipmapping (font_map)) flags |= CLUTTER_FONT_MIPMAPPING; font_options = clutter_backend_get_font_options (clutter_get_default_backend ()); hint_style = cairo_font_options_get_hint_style (font_options); if (hint_style != CAIRO_HINT_STYLE_DEFAULT && hint_style != CAIRO_HINT_STYLE_NONE) flags |= CLUTTER_FONT_HINTING; return flags; } /** * clutter_get_input_device_for_id: * @id_: the unique id for a device * * Retrieves the #ClutterInputDevice from its @id_. This is a convenience * wrapper for clutter_device_manager_get_device() and it is functionally * equivalent to: * * |[ * ClutterDeviceManager *manager; * ClutterInputDevice *device; * * manager = clutter_device_manager_get_default (); * device = clutter_device_manager_get_device (manager, id); * ]| * * Return value: (transfer none): a #ClutterInputDevice, or %NULL * * Since: 0.8 * * Deprecated: 1.10: Use clutter_device_manager_get_device() instead. */ ClutterInputDevice * clutter_get_input_device_for_id (gint id_) { ClutterDeviceManager *manager; manager = clutter_device_manager_get_default (); if (manager == NULL) return NULL; return clutter_device_manager_get_device (manager, id_); } /** * clutter_get_font_map: * * Retrieves the #PangoFontMap instance used by Clutter. * You can use the global font map object with the COGL * Pango API. * * Return value: (transfer none): the #PangoFontMap instance. The returned * value is owned by Clutter and it should never be unreferenced. * * Since: 1.0 */ PangoFontMap * clutter_get_font_map (void) { return PANGO_FONT_MAP (clutter_context_get_pango_fontmap ()); } typedef struct _ClutterRepaintFunction { guint id; ClutterRepaintFlags flags; GSourceFunc func; gpointer data; GDestroyNotify notify; } ClutterRepaintFunction; /** * clutter_threads_remove_repaint_func: * @handle_id: an unsigned integer greater than zero * * Removes the repaint function with @handle_id as its id * * Since: 1.0 */ void clutter_threads_remove_repaint_func (guint handle_id) { ClutterRepaintFunction *repaint_func; ClutterMainContext *context; GList *l; g_return_if_fail (handle_id > 0); _clutter_context_lock (); context = clutter_context_get_default_unlocked (); l = context->repaint_funcs; while (l != NULL) { repaint_func = l->data; if (repaint_func->id == handle_id) { context->repaint_funcs = g_list_remove_link (context->repaint_funcs, l); g_list_free (l); if (repaint_func->notify) repaint_func->notify (repaint_func->data); g_slice_free (ClutterRepaintFunction, repaint_func); break; } l = l->next; } _clutter_context_unlock (); } /** * clutter_threads_add_repaint_func: * @func: the function to be called within the paint cycle * @data: data to be passed to the function, or %NULL * @notify: function to be called when removing the repaint * function, or %NULL * * Adds a function to be called whenever Clutter is processing a new * frame. * * If the function returns %FALSE it is automatically removed from the * list of repaint functions and will not be called again. * * This function is guaranteed to be called from within the same thread * that called clutter_main(), and while the Clutter lock is being held; * the function will be called within the main loop, so it is imperative * that it does not block, otherwise the frame time budget may be lost. * * A repaint function is useful to ensure that an update of the scenegraph * is performed before the scenegraph is repainted; for instance, uploading * a frame from a video into a #ClutterTexture. By default, a repaint * function added using this function will be invoked prior to the frame * being processed. * * Adding a repaint function does not automatically ensure that a new * frame will be queued. * * When the repaint function is removed (either because it returned %FALSE * or because clutter_threads_remove_repaint_func() has been called) the * @notify function will be called, if any is set. * * See also: clutter_threads_add_repaint_func_full() * * Return value: the ID (greater than 0) of the repaint function. You * can use the returned integer to remove the repaint function by * calling clutter_threads_remove_repaint_func(). * * Since: 1.0 */ guint clutter_threads_add_repaint_func (GSourceFunc func, gpointer data, GDestroyNotify notify) { return clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT, func, data, notify); } /** * clutter_threads_add_repaint_func_full: * @flags: flags for the repaint function * @func: the function to be called within the paint cycle * @data: data to be passed to the function, or %NULL * @notify: function to be called when removing the repaint * function, or %NULL * * Adds a function to be called whenever Clutter is processing a new * frame. * * If the function returns %FALSE it is automatically removed from the * list of repaint functions and will not be called again. * * This function is guaranteed to be called from within the same thread * that called clutter_main(), and while the Clutter lock is being held; * the function will be called within the main loop, so it is imperative * that it does not block, otherwise the frame time budget may be lost. * * A repaint function is useful to ensure that an update of the scenegraph * is performed before the scenegraph is repainted; for instance, uploading * a frame from a video into a #ClutterTexture. The @flags passed to this * function will determine the section of the frame processing that will * result in @func being called. * * Adding a repaint function does not automatically ensure that a new * frame will be queued. * * When the repaint function is removed (either because it returned %FALSE * or because clutter_threads_remove_repaint_func() has been called) the * @notify function will be called, if any is set. * * Return value: the ID (greater than 0) of the repaint function. You * can use the returned integer to remove the repaint function by * calling clutter_threads_remove_repaint_func(). * * Since: 1.10 */ guint clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags, GSourceFunc func, gpointer data, GDestroyNotify notify) { ClutterMainContext *context; ClutterRepaintFunction *repaint_func; g_return_val_if_fail (func != NULL, 0); _clutter_context_lock (); context = clutter_context_get_default_unlocked (); repaint_func = g_slice_new (ClutterRepaintFunction); repaint_func->id = context->last_repaint_id++; /* mask out QUEUE_REDRAW_ON_ADD, since we're going to consume it */ repaint_func->flags = flags & ~CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD; repaint_func->func = func; repaint_func->data = data; repaint_func->notify = notify; context->repaint_funcs = g_list_prepend (context->repaint_funcs, repaint_func); _clutter_context_unlock (); if ((flags & CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD) != 0) { ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_ensure_next_iteration (master_clock); } return repaint_func->id; } /* * _clutter_run_repaint_functions: * @flags: only run the repaint functions matching the passed flags * * Executes the repaint functions added using the * clutter_threads_add_repaint_func() function. * * Must be called with the Clutter thread lock held. */ void _clutter_run_repaint_functions (ClutterRepaintFlags flags) { ClutterMainContext *context = _clutter_context_get_default (); ClutterRepaintFunction *repaint_func; GList *invoke_list, *reinvoke_list, *l; if (context->repaint_funcs == NULL) return; /* steal the list */ invoke_list = context->repaint_funcs; context->repaint_funcs = NULL; reinvoke_list = NULL; /* consume the whole list while we execute the functions */ while (invoke_list != NULL) { gboolean res = FALSE; repaint_func = invoke_list->data; l = invoke_list; invoke_list = g_list_remove_link (invoke_list, invoke_list); g_list_free (l); if ((repaint_func->flags & flags) != 0) res = repaint_func->func (repaint_func->data); else res = TRUE; if (res) reinvoke_list = g_list_prepend (reinvoke_list, repaint_func); else { if (repaint_func->notify != NULL) repaint_func->notify (repaint_func->data); g_slice_free (ClutterRepaintFunction, repaint_func); } } if (context->repaint_funcs != NULL) { context->repaint_funcs = g_list_concat (context->repaint_funcs, g_list_reverse (reinvoke_list)); } else context->repaint_funcs = g_list_reverse (reinvoke_list); } /** * clutter_check_version: * @major: major version, like 1 in 1.2.3 * @minor: minor version, like 2 in 1.2.3 * @micro: micro version, like 3 in 1.2.3 * * Run-time version check, to check the version the Clutter library * that an application is currently linked against * * This is the run-time equivalent of the compile-time %CLUTTER_CHECK_VERSION * pre-processor macro * * Return value: %TRUE if the version of the Clutter library is * greater than (@major, @minor, @micro), and %FALSE otherwise * * Since: 1.2 */ gboolean clutter_check_version (guint major, guint minor, guint micro) { return (clutter_major_version > major || (clutter_major_version == major && clutter_minor_version > minor) || (clutter_major_version == major && clutter_minor_version == minor && clutter_micro_version >= micro)); } /** * clutter_get_default_text_direction: * * Retrieves the default direction for the text. The text direction is * determined by the locale and/or by the `CLUTTER_TEXT_DIRECTION` * environment variable. * * The default text direction can be overridden on a per-actor basis by using * clutter_actor_set_text_direction(). * * Return value: the default text direction * * Since: 1.2 */ ClutterTextDirection clutter_get_default_text_direction (void) { return clutter_text_direction; } /*< private > * clutter_clear_events_queue: * * Clears the events queue stored in the main context. */ void _clutter_clear_events_queue (void) { ClutterMainContext *context = _clutter_context_get_default (); if (context->events_queue != NULL) { g_queue_foreach (context->events_queue, (GFunc) clutter_event_free, NULL); g_queue_free (context->events_queue); context->events_queue = NULL; } } void _clutter_clear_events_queue_for_stage (ClutterStage *stage) { ClutterMainContext *context = _clutter_context_get_default (); GList *l, *next; if (context->events_queue == NULL) return; /* Remove any pending events for this stage from the event queue */ for (l = context->events_queue->head; l; l = next) { ClutterEvent *event = l->data; next = l->next; if (event->any.stage == stage) { g_queue_delete_link (context->events_queue, l); clutter_event_free (event); } } } ClutterPickMode _clutter_context_get_pick_mode (void) { ClutterMainContext *context = _clutter_context_get_default (); return context->pick_mode; } void _clutter_context_push_shader_stack (ClutterActor *actor) { ClutterMainContext *context = _clutter_context_get_default (); context->shaders = g_slist_prepend (context->shaders, actor); } ClutterActor * _clutter_context_peek_shader_stack (void) { ClutterMainContext *context = _clutter_context_get_default (); if (context->shaders != NULL) return context->shaders->data; return NULL; } ClutterActor * _clutter_context_pop_shader_stack (ClutterActor *actor) { ClutterMainContext *context = _clutter_context_get_default (); context->shaders = g_slist_remove (context->shaders, actor); return _clutter_context_peek_shader_stack (); } gboolean _clutter_context_get_motion_events_enabled (void) { ClutterMainContext *context = _clutter_context_get_default (); return context->motion_events_per_actor; } /** * clutter_check_windowing_backend: * @backend_type: the name of the backend to check * * Checks the run-time name of the Clutter windowing system backend, using * the symbolic macros like %CLUTTER_WINDOWING_X11. * * This function should be used in conjuction with the compile-time macros * inside applications and libraries that are using the platform-specific * windowing system API, to ensure that they are running on the correct * windowing system; for instance: * * |[ * #ifdef CLUTTER_WINDOWING_X11 * if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11)) * { * // it is safe to use the clutter_x11_* API * } * else * #endif * g_error ("Unknown Clutter backend."); * ]| * * Return value: %TRUE if the current Clutter windowing system backend is * the one checked, and %FALSE otherwise * * Since: 1.10 */ gboolean clutter_check_windowing_backend (const char *backend_type) { ClutterMainContext *context = _clutter_context_get_default (); g_return_val_if_fail (backend_type != NULL, FALSE); backend_type = g_intern_string (backend_type); #ifdef CLUTTER_WINDOWING_EGL if (backend_type == I_(CLUTTER_WINDOWING_EGL) && CLUTTER_IS_BACKEND_EGL_NATIVE (context->backend)) return TRUE; else #endif #ifdef CLUTTER_WINDOWING_X11 if (backend_type == I_(CLUTTER_WINDOWING_X11) && CLUTTER_IS_BACKEND_X11 (context->backend)) return TRUE; else #endif return FALSE; } void _clutter_set_sync_to_vblank (gboolean sync_to_vblank) { clutter_sync_to_vblank = !!sync_to_vblank; } gboolean _clutter_get_sync_to_vblank (void) { return clutter_sync_to_vblank; } void _clutter_set_sync_method (SyncMethod sync_method) { clutter_sync_method = sync_method; } SyncMethod _clutter_get_sync_method (void) { return clutter_sync_method; } void _clutter_debug_messagev (const char *format, va_list var_args) { static gint64 last_debug_stamp; gchar *stamp, *fmt; gint64 cur_time, debug_stamp; cur_time = g_get_monotonic_time (); /* if the last debug message happened less than a second ago, just * show the increments instead of the full timestamp */ if (last_debug_stamp == 0 || cur_time - last_debug_stamp >= G_USEC_PER_SEC) { debug_stamp = cur_time; last_debug_stamp = debug_stamp; stamp = g_strdup_printf ("[%16" G_GINT64_FORMAT "]", debug_stamp); } else { debug_stamp = cur_time - last_debug_stamp; stamp = g_strdup_printf ("[%+16" G_GINT64_FORMAT "]", debug_stamp); } fmt = g_strconcat (stamp, ":", format, NULL); free (stamp); g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, var_args); free (fmt); } void _clutter_debug_message (const char *format, ...) { va_list args; va_start (args, format); _clutter_debug_messagev (format, args); va_end (args); } gboolean _clutter_diagnostic_enabled (void) { static const char *clutter_enable_diagnostic = NULL; if (G_UNLIKELY (clutter_enable_diagnostic == NULL)) { clutter_enable_diagnostic = g_getenv ("CLUTTER_ENABLE_DIAGNOSTIC"); if (clutter_enable_diagnostic == NULL) clutter_enable_diagnostic = "0"; } return *clutter_enable_diagnostic != '0'; } void _clutter_diagnostic_message (const char *format, ...) { va_list args; char *fmt; fmt = g_strconcat ("[DIAGNOSTIC]: ", format, NULL); va_start (args, format); g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, args); va_end (args); free (fmt); } ������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-deform-effect.h������������������������������������������������0000664�0001750�0001750�00000010424�14211404421�022640� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_DEFORM_EFFECT_H__ #define __CLUTTER_DEFORM_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <cogl/cogl.h> #include <clutter/clutter-offscreen-effect.h> G_BEGIN_DECLS #define CLUTTER_TYPE_DEFORM_EFFECT (clutter_deform_effect_get_type ()) #define CLUTTER_DEFORM_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEFORM_EFFECT, ClutterDeformEffect)) #define CLUTTER_IS_DEFORM_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEFORM_EFFECT)) #define CLUTTER_DEFORM_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEFORM_EFFECT, ClutterDeformEffectClass)) #define CLUTTER_IS_DEFORM_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEFORM_EFFECT)) #define CLUTTER_DEFORM_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEFORM_EFFECT, ClutterDeformEffectClass)) typedef struct _ClutterDeformEffect ClutterDeformEffect; typedef struct _ClutterDeformEffectPrivate ClutterDeformEffectPrivate; typedef struct _ClutterDeformEffectClass ClutterDeformEffectClass; /** * ClutterDeformEffect: * * The #ClutterDeformEffect structure contains * only private data and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterDeformEffect { /*< private >*/ ClutterOffscreenEffect parent_instance; ClutterDeformEffectPrivate *priv; }; /** * ClutterDeformEffectClass: * @deform_vertex: virtual function; sub-classes should override this * function to compute the deformation of each vertex * * The #ClutterDeformEffectClass structure contains * only private data * * Since: 1.4 */ struct _ClutterDeformEffectClass { /*< private >*/ ClutterOffscreenEffectClass parent_class; /*< public >*/ void (* deform_vertex) (ClutterDeformEffect *effect, gfloat width, gfloat height, CoglTextureVertex *vertex); /*< private >*/ void (*_clutter_deform1) (void); void (*_clutter_deform2) (void); void (*_clutter_deform3) (void); void (*_clutter_deform4) (void); void (*_clutter_deform5) (void); void (*_clutter_deform6) (void); void (*_clutter_deform7) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_deform_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 void clutter_deform_effect_set_back_material (ClutterDeformEffect *effect, CoglHandle material); CLUTTER_AVAILABLE_IN_1_4 CoglHandle clutter_deform_effect_get_back_material (ClutterDeformEffect *effect); CLUTTER_AVAILABLE_IN_1_4 void clutter_deform_effect_set_n_tiles (ClutterDeformEffect *effect, guint x_tiles, guint y_tiles); CLUTTER_AVAILABLE_IN_1_4 void clutter_deform_effect_get_n_tiles (ClutterDeformEffect *effect, guint *x_tiles, guint *y_tiles); CLUTTER_AVAILABLE_IN_1_4 void clutter_deform_effect_invalidate (ClutterDeformEffect *effect); G_END_DECLS #endif /* __CLUTTER_DEFORM_EFFECT_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-action.c�������������������������������������������������������0000664�0001750�0001750�00000003613�14211404421�021404� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-action * @Title: ClutterAction * @Short_Description: Abstract class for event-related logic * @See_Also: #ClutterConstraint * * #ClutterAction is an abstract base class for event-related actions that * modify the user interaction of a #ClutterActor, just like * #ClutterConstraint is an abstract class for modifiers of an actor's * position or size. * * Implementations of #ClutterAction are associated to an actor and can * provide behavioral changes when dealing with user input - for instance * drag and drop capabilities, or scrolling, or panning - by using the * various event-related signals provided by #ClutterActor itself. * * #ClutterAction is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-action.h" #include "clutter-debug.h" #include "clutter-private.h" G_DEFINE_ABSTRACT_TYPE (ClutterAction, clutter_action, CLUTTER_TYPE_ACTOR_META); static void clutter_action_class_init (ClutterActionClass *klass) { } static void clutter_action_init (ClutterAction *self) { } ���������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-click-action.h�������������������������������������������������0000664�0001750�0001750�00000010275�14211404421�022476� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> * * Inspired by the StClickable class in GNOME Shell, written by: * Colin Walters <walters@verbum.org> */ #ifndef __CLUTTER_CLICK_ACTION_H__ #define __CLUTTER_CLICK_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-action.h> #include <clutter/clutter-event.h> G_BEGIN_DECLS #define CLUTTER_TYPE_CLICK_ACTION (clutter_click_action_get_type ()) #define CLUTTER_CLICK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CLICK_ACTION, ClutterClickAction)) #define CLUTTER_IS_CLICK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CLICK_ACTION)) #define CLUTTER_CLICK_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CLICK_ACTION, ClutterClickActionClass)) #define CLUTTER_IS_CLICK_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CLICK_ACTION)) #define CLUTTER_CLICK_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CLICK_ACTION, ClutterClickActionClass)) typedef struct _ClutterClickAction ClutterClickAction; typedef struct _ClutterClickActionPrivate ClutterClickActionPrivate; typedef struct _ClutterClickActionClass ClutterClickActionClass; /** * ClutterClickAction: * * The #ClutterClickAction structure contains * only private data and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterClickAction { /*< private >*/ ClutterAction parent_instance; ClutterClickActionPrivate *priv; }; /** * ClutterClickActionClass: * @clicked: class handler for the #ClutterClickAction::clicked signal * @long_press: class handler for the #ClutterClickAction::long-press signal * * The #ClutterClickActionClass structure * contains only private data * * Since: 1.4 */ struct _ClutterClickActionClass { /*< private >*/ ClutterActionClass parent_class; /*< public >*/ void (* clicked) (ClutterClickAction *action, ClutterActor *actor); gboolean (* long_press) (ClutterClickAction *action, ClutterActor *actor, ClutterLongPressState state); /*< private >*/ void (* _clutter_click_action1) (void); void (* _clutter_click_action2) (void); void (* _clutter_click_action3) (void); void (* _clutter_click_action4) (void); void (* _clutter_click_action5) (void); void (* _clutter_click_action6) (void); void (* _clutter_click_action7) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_click_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterAction * clutter_click_action_new (void); CLUTTER_AVAILABLE_IN_1_4 guint clutter_click_action_get_button (ClutterClickAction *action); CLUTTER_AVAILABLE_IN_1_4 ClutterModifierType clutter_click_action_get_state (ClutterClickAction *action); CLUTTER_AVAILABLE_IN_1_8 void clutter_click_action_get_coords (ClutterClickAction *action, gfloat *press_x, gfloat *press_y); CLUTTER_AVAILABLE_IN_1_4 void clutter_click_action_release (ClutterClickAction *action); G_END_DECLS #endif /* __CLUTTER_CLICK_ACTION_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-interval.c�����������������������������������������������������0000664�0001750�0001750�00000100270�14211404421�021750� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-interval * @short_description: An object holding an interval of two values * * #ClutterInterval is a simple object that can hold two values * defining an interval. #ClutterInterval can hold any value that * can be enclosed inside a #GValue. * * Once a #ClutterInterval for a specific #GType has been instantiated * the #ClutterInterval:value-type property cannot be changed anymore. * * #ClutterInterval starts with a floating reference; this means that * any object taking a reference on a #ClutterInterval instance should * also take ownership of the interval by using g_object_ref_sink(). * * #ClutterInterval is used by #ClutterAnimation to define the * interval of values that an implicit animation should tween over. * * #ClutterInterval can be subclassed to override the validation * and value computation. * * #ClutterInterval is available since Clutter 1.0 */ #include "clutter-build-config.h" #include <stdlib.h> #include <string.h> #include <glib.h> #include <glib-object.h> #include <gobject/gvaluecollector.h> #include "clutter-color.h" #include "clutter-interval.h" #include "clutter-private.h" #include "clutter-units.h" #include "clutter-scriptable.h" #include "clutter-script-private.h" enum { PROP_0, PROP_VALUE_TYPE, PROP_INITIAL, PROP_FINAL, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { INITIAL = 0, FINAL, RESULT, N_VALUES }; struct _ClutterIntervalPrivate { GType value_type; GValue *values; }; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterInterval, clutter_interval, G_TYPE_INITIALLY_UNOWNED, G_ADD_PRIVATE (ClutterInterval) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)); static gboolean clutter_interval_real_validate (ClutterInterval *interval, GParamSpec *pspec) { GType pspec_gtype = G_PARAM_SPEC_VALUE_TYPE (pspec); /* then check the fundamental types */ switch (G_TYPE_FUNDAMENTAL (pspec_gtype)) { case G_TYPE_INT: { GParamSpecInt *pspec_int = G_PARAM_SPEC_INT (pspec); gint a, b; a = b = 0; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_int->minimum && a <= pspec_int->maximum) && (b >= pspec_int->minimum && b <= pspec_int->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_INT64: { GParamSpecInt64 *pspec_int = G_PARAM_SPEC_INT64 (pspec); gint64 a, b; a = b = 0; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_int->minimum && a <= pspec_int->maximum) && (b >= pspec_int->minimum && b <= pspec_int->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_UINT: { GParamSpecUInt *pspec_uint = G_PARAM_SPEC_UINT (pspec); guint a, b; a = b = 0; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_uint->minimum && a <= pspec_uint->maximum) && (b >= pspec_uint->minimum && b <= pspec_uint->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_UINT64: { GParamSpecUInt64 *pspec_int = G_PARAM_SPEC_UINT64 (pspec); guint64 a, b; a = b = 0; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_int->minimum && a <= pspec_int->maximum) && (b >= pspec_int->minimum && b <= pspec_int->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_CHAR: { GParamSpecChar *pspec_char = G_PARAM_SPEC_CHAR (pspec); guchar a, b; a = b = 0; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_char->minimum && a <= pspec_char->maximum) && (b >= pspec_char->minimum && b <= pspec_char->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_UCHAR: { GParamSpecUChar *pspec_uchar = G_PARAM_SPEC_UCHAR (pspec); guchar a, b; a = b = 0; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_uchar->minimum && a <= pspec_uchar->maximum) && (b >= pspec_uchar->minimum && b <= pspec_uchar->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_FLOAT: { GParamSpecFloat *pspec_flt = G_PARAM_SPEC_FLOAT (pspec); float a, b; a = b = 0.f; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_flt->minimum && a <= pspec_flt->maximum) && (b >= pspec_flt->minimum && b <= pspec_flt->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_DOUBLE: { GParamSpecDouble *pspec_flt = G_PARAM_SPEC_DOUBLE (pspec); double a, b; a = b = 0; clutter_interval_get_interval (interval, &a, &b); if ((a >= pspec_flt->minimum && a <= pspec_flt->maximum) && (b >= pspec_flt->minimum && b <= pspec_flt->maximum)) return TRUE; else return FALSE; } break; case G_TYPE_BOOLEAN: return TRUE; default: break; } return TRUE; } static gboolean clutter_interval_real_compute_value (ClutterInterval *interval, gdouble factor, GValue *value) { GValue *initial, *final; GType value_type; gboolean retval = FALSE; initial = clutter_interval_peek_initial_value (interval); final = clutter_interval_peek_final_value (interval); value_type = clutter_interval_get_value_type (interval); if (_clutter_has_progress_function (value_type)) { retval = _clutter_run_progress_function (value_type, initial, final, factor, value); if (retval) return TRUE; } switch (G_TYPE_FUNDAMENTAL (value_type)) { case G_TYPE_INT: { gint ia, ib, res; ia = g_value_get_int (initial); ib = g_value_get_int (final); res = (factor * (ib - ia)) + ia; g_value_set_int (value, res); retval = TRUE; } break; case G_TYPE_CHAR: { gchar ia, ib, res; ia = g_value_get_schar (initial); ib = g_value_get_schar (final); res = (factor * (ib - (gdouble) ia)) + ia; g_value_set_schar (value, res); retval = TRUE; } break; case G_TYPE_UINT: { guint ia, ib, res; ia = g_value_get_uint (initial); ib = g_value_get_uint (final); res = (factor * (ib - (gdouble) ia)) + ia; g_value_set_uint (value, res); retval = TRUE; } break; case G_TYPE_UCHAR: { guchar ia, ib, res; ia = g_value_get_uchar (initial); ib = g_value_get_uchar (final); res = (factor * (ib - (gdouble) ia)) + ia; g_value_set_uchar (value, res); retval = TRUE; } break; case G_TYPE_FLOAT: case G_TYPE_DOUBLE: { gdouble ia, ib, res; if (value_type == G_TYPE_DOUBLE) { ia = g_value_get_double (initial); ib = g_value_get_double (final); } else { ia = g_value_get_float (initial); ib = g_value_get_float (final); } res = (factor * (ib - ia)) + ia; if (value_type == G_TYPE_DOUBLE) g_value_set_double (value, res); else g_value_set_float (value, res); retval = TRUE; } break; case G_TYPE_BOOLEAN: if (factor > 0.5) g_value_set_boolean (value, TRUE); else g_value_set_boolean (value, FALSE); retval = TRUE; break; case G_TYPE_BOXED: break; default: break; } /* We're trying to animate a property without knowing how to do that. Issue * a warning with a hint to what could be done to fix that */ if (G_UNLIKELY (retval == FALSE)) { g_warning ("%s: Could not compute progress between two %s. You can " "register a progress function to instruct ClutterInterval " "how to deal with this GType", G_STRLOC, g_type_name (value_type)); } return retval; } static void clutter_interval_finalize (GObject *gobject) { ClutterIntervalPrivate *priv = CLUTTER_INTERVAL (gobject)->priv; if (G_IS_VALUE (&priv->values[INITIAL])) g_value_unset (&priv->values[INITIAL]); if (G_IS_VALUE (&priv->values[FINAL])) g_value_unset (&priv->values[FINAL]); if (G_IS_VALUE (&priv->values[RESULT])) g_value_unset (&priv->values[RESULT]); free (priv->values); G_OBJECT_CLASS (clutter_interval_parent_class)->finalize (gobject); } static void clutter_interval_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterInterval *self = CLUTTER_INTERVAL (gobject); ClutterIntervalPrivate *priv = clutter_interval_get_instance_private (self); switch (prop_id) { case PROP_VALUE_TYPE: priv->value_type = g_value_get_gtype (value); break; case PROP_INITIAL: if (g_value_get_boxed (value) != NULL) clutter_interval_set_initial_value (self, g_value_get_boxed (value)); else if (G_IS_VALUE (&priv->values[INITIAL])) g_value_unset (&priv->values[INITIAL]); break; case PROP_FINAL: if (g_value_get_boxed (value) != NULL) clutter_interval_set_final_value (self, g_value_get_boxed (value)); else if (G_IS_VALUE (&priv->values[FINAL])) g_value_unset (&priv->values[FINAL]); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_interval_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterIntervalPrivate *priv; priv = clutter_interval_get_instance_private (CLUTTER_INTERVAL (gobject)); switch (prop_id) { case PROP_VALUE_TYPE: g_value_set_gtype (value, priv->value_type); break; case PROP_INITIAL: if (G_IS_VALUE (&priv->values[INITIAL])) g_value_set_boxed (value, &priv->values[INITIAL]); break; case PROP_FINAL: if (G_IS_VALUE (&priv->values[FINAL])) g_value_set_boxed (value, &priv->values[FINAL]); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static gboolean clutter_interval_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { ClutterIntervalPrivate *priv = CLUTTER_INTERVAL (scriptable)->priv; if ((strcmp (name, "initial") == 0) || (strcmp (name, "final") == 0)) { g_value_init (value, priv->value_type); return _clutter_script_parse_node (script, value, name, node, NULL); } return FALSE; } static void clutter_interval_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { ClutterInterval *self = CLUTTER_INTERVAL (scriptable); if (strcmp (name, "initial") == 0) clutter_interval_set_initial_value (self, value); else if (strcmp (name, "final") == 0) clutter_interval_set_final_value (self, value); else g_object_set_property (G_OBJECT (scriptable), name, value); } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_interval_parse_custom_node; iface->set_custom_property = clutter_interval_set_custom_property; } static void clutter_interval_class_init (ClutterIntervalClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); klass->validate = clutter_interval_real_validate; klass->compute_value = clutter_interval_real_compute_value; gobject_class->set_property = clutter_interval_set_property, gobject_class->get_property = clutter_interval_get_property; gobject_class->finalize = clutter_interval_finalize; /** * ClutterInterval:value-type: * * The type of the values in the interval. * * Since: 1.0 */ obj_props[PROP_VALUE_TYPE] = g_param_spec_gtype ("value-type", P_("Value Type"), P_("The type of the values in the interval"), G_TYPE_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); /** * ClutterInterval:initial: * * The initial value of the interval. * * Since: 1.12 */ obj_props[PROP_INITIAL] = g_param_spec_boxed ("initial", P_("Initial Value"), P_("Initial value of the interval"), G_TYPE_VALUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterInterval:final: * * The final value of the interval. * * Since: 1.12 */ obj_props[PROP_FINAL] = g_param_spec_boxed ("final", P_("Final Value"), P_("Final value of the interval"), G_TYPE_VALUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_interval_init (ClutterInterval *self) { self->priv = clutter_interval_get_instance_private (self); self->priv->value_type = G_TYPE_INVALID; self->priv->values = calloc (1, sizeof (GValue) * N_VALUES); } static inline void clutter_interval_set_value_internal (ClutterInterval *interval, gint index_, const GValue *value) { ClutterIntervalPrivate *priv = interval->priv; GType value_type; g_assert (index_ >= INITIAL && index_ <= RESULT); if (G_IS_VALUE (&priv->values[index_])) g_value_unset (&priv->values[index_]); g_value_init (&priv->values[index_], priv->value_type); value_type = G_VALUE_TYPE (value); if (value_type != priv->value_type || !g_type_is_a (value_type, priv->value_type)) { if (g_value_type_compatible (value_type, priv->value_type)) { g_value_copy (value, &priv->values[index_]); return; } if (g_value_type_transformable (value_type, priv->value_type)) { GValue transform = G_VALUE_INIT; g_value_init (&transform, priv->value_type); if (g_value_transform (value, &transform)) g_value_copy (&transform, &priv->values[index_]); else { g_warning ("%s: Unable to convert a value of type '%s' into " "the value type '%s' of the interval.", G_STRLOC, g_type_name (value_type), g_type_name (priv->value_type)); } g_value_unset (&transform); } } else g_value_copy (value, &priv->values[index_]); } static inline void clutter_interval_get_value_internal (ClutterInterval *interval, gint index_, GValue *value) { ClutterIntervalPrivate *priv = interval->priv; g_assert (index_ >= INITIAL && index_ <= RESULT); g_value_copy (&priv->values[index_], value); } static gboolean clutter_interval_set_initial_internal (ClutterInterval *interval, va_list *args) { GType gtype = interval->priv->value_type; GValue value = G_VALUE_INIT; gchar *error; /* initial value */ G_VALUE_COLLECT_INIT (&value, gtype, *args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); /* we leak the value here as it might not be in a valid state * given the error and calling g_value_unset() might lead to * undefined behaviour */ free (error); return FALSE; } clutter_interval_set_value_internal (interval, INITIAL, &value); g_value_unset (&value); return TRUE; } static gboolean clutter_interval_set_final_internal (ClutterInterval *interval, va_list *args) { GType gtype = interval->priv->value_type; GValue value = G_VALUE_INIT; gchar *error; /* initial value */ G_VALUE_COLLECT_INIT (&value, gtype, *args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); /* we leak the value here as it might not be in a valid state * given the error and calling g_value_unset() might lead to * undefined behaviour */ free (error); return FALSE; } clutter_interval_set_value_internal (interval, FINAL, &value); g_value_unset (&value); return TRUE; } static void clutter_interval_get_interval_valist (ClutterInterval *interval, va_list var_args) { GType gtype = interval->priv->value_type; GValue value = G_VALUE_INIT; gchar *error; /* initial value */ g_value_init (&value, gtype); clutter_interval_get_initial_value (interval, &value); G_VALUE_LCOPY (&value, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); g_value_unset (&value); return; } g_value_unset (&value); /* final value */ g_value_init (&value, gtype); clutter_interval_get_final_value (interval, &value); G_VALUE_LCOPY (&value, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); g_value_unset (&value); return; } g_value_unset (&value); } /** * clutter_interval_new: * @gtype: the type of the values in the interval * @...: the initial value and the final value of the interval * * Creates a new #ClutterInterval holding values of type @gtype. * * This function avoids using a #GValue for the initial and final values * of the interval: * * |[ * interval = clutter_interval_new (G_TYPE_FLOAT, 0.0, 1.0); * interval = clutter_interval_new (G_TYPE_BOOLEAN, FALSE, TRUE); * interval = clutter_interval_new (G_TYPE_INT, 0, 360); * ]| * * Return value: the newly created #ClutterInterval * * Since: 1.0 */ ClutterInterval * clutter_interval_new (GType gtype, ...) { ClutterInterval *retval; va_list args; g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL); retval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", gtype, NULL); va_start (args, gtype); if (!clutter_interval_set_initial_internal (retval, &args)) goto out; clutter_interval_set_final_internal (retval, &args); out: va_end (args); return retval; } /** * clutter_interval_new_with_values: * @gtype: the type of the values in the interval * @initial: (allow-none): a #GValue holding the initial value of the interval * @final: (allow-none): a #GValue holding the final value of the interval * * Creates a new #ClutterInterval of type @gtype, between @initial * and @final. * * This function is useful for language bindings. * * Return value: the newly created #ClutterInterval * * Since: 1.0 */ ClutterInterval * clutter_interval_new_with_values (GType gtype, const GValue *initial, const GValue *final) { g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL); g_return_val_if_fail (initial == NULL || G_VALUE_TYPE (initial) == gtype, NULL); g_return_val_if_fail (final == NULL || G_VALUE_TYPE (final) == gtype, NULL); return g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", gtype, "initial", initial, "final", final, NULL); } /** * clutter_interval_clone: * @interval: a #ClutterInterval * * Creates a copy of @interval. * * Return value: (transfer full): the newly created #ClutterInterval * * Since: 1.0 */ ClutterInterval * clutter_interval_clone (ClutterInterval *interval) { ClutterInterval *retval; GType gtype; GValue *tmp; g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL); g_return_val_if_fail (interval->priv->value_type != G_TYPE_INVALID, NULL); gtype = interval->priv->value_type; retval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", gtype, NULL); tmp = clutter_interval_peek_initial_value (interval); clutter_interval_set_initial_value (retval, tmp); tmp = clutter_interval_peek_final_value (interval); clutter_interval_set_final_value (retval, tmp); return retval; } /** * clutter_interval_get_value_type: * @interval: a #ClutterInterval * * Retrieves the #GType of the values inside @interval. * * Return value: the type of the value, or G_TYPE_INVALID * * Since: 1.0 */ GType clutter_interval_get_value_type (ClutterInterval *interval) { g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), G_TYPE_INVALID); return interval->priv->value_type; } /** * clutter_interval_set_initial_value: (rename-to clutter_interval_set_initial) * @interval: a #ClutterInterval * @value: a #GValue * * Sets the initial value of @interval to @value. The value is copied * inside the #ClutterInterval. * * Since: 1.0 */ void clutter_interval_set_initial_value (ClutterInterval *interval, const GValue *value) { g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); g_return_if_fail (value != NULL); clutter_interval_set_value_internal (interval, INITIAL, value); } /** * clutter_interval_set_initial: (skip) * @interval: a #ClutterInterval * @...: the initial value of the interval. * * Variadic arguments version of clutter_interval_set_initial_value(). * * This function is meant as a convenience for the C API. * * Language bindings should use clutter_interval_set_initial_value() * instead. * * Since: 1.10 */ void clutter_interval_set_initial (ClutterInterval *interval, ...) { va_list args; g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); va_start (args, interval); clutter_interval_set_initial_internal (interval, &args); va_end (args); } /** * clutter_interval_get_initial_value: * @interval: a #ClutterInterval * @value: (out caller-allocates): a #GValue * * Retrieves the initial value of @interval and copies * it into @value. * * The passed #GValue must be initialized to the value held by * the #ClutterInterval. * * Since: 1.0 */ void clutter_interval_get_initial_value (ClutterInterval *interval, GValue *value) { g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); g_return_if_fail (value != NULL); clutter_interval_get_value_internal (interval, INITIAL, value); } /** * clutter_interval_peek_initial_value: * @interval: a #ClutterInterval * * Gets the pointer to the initial value of @interval * * Return value: (transfer none): the initial value of the interval. * The value is owned by the #ClutterInterval and it should not be * modified or freed * * Since: 1.0 */ GValue * clutter_interval_peek_initial_value (ClutterInterval *interval) { g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL); return interval->priv->values + INITIAL; } /** * clutter_interval_set_final_value: (rename-to clutter_interval_set_final) * @interval: a #ClutterInterval * @value: a #GValue * * Sets the final value of @interval to @value. The value is * copied inside the #ClutterInterval. * * Since: 1.0 */ void clutter_interval_set_final_value (ClutterInterval *interval, const GValue *value) { g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); g_return_if_fail (value != NULL); clutter_interval_set_value_internal (interval, FINAL, value); } /** * clutter_interval_get_final_value: * @interval: a #ClutterInterval * @value: (out caller-allocates): a #GValue * * Retrieves the final value of @interval and copies * it into @value. * * The passed #GValue must be initialized to the value held by * the #ClutterInterval. * * Since: 1.0 */ void clutter_interval_get_final_value (ClutterInterval *interval, GValue *value) { g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); g_return_if_fail (value != NULL); clutter_interval_get_value_internal (interval, FINAL, value); } /** * clutter_interval_set_final: (skip) * @interval: a #ClutterInterval * @...: the final value of the interval * * Variadic arguments version of clutter_interval_set_final_value(). * * This function is meant as a convenience for the C API. * * Language bindings should use clutter_interval_set_final_value() instead. * * Since: 1.10 */ void clutter_interval_set_final (ClutterInterval *interval, ...) { va_list args; g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); va_start (args, interval); clutter_interval_set_final_internal (interval, &args); va_end (args); } /** * clutter_interval_peek_final_value: * @interval: a #ClutterInterval * * Gets the pointer to the final value of @interval * * Return value: (transfer none): the final value of the interval. * The value is owned by the #ClutterInterval and it should not be * modified or freed * * Since: 1.0 */ GValue * clutter_interval_peek_final_value (ClutterInterval *interval) { g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL); return interval->priv->values + FINAL; } /** * clutter_interval_set_interval: * @interval: a #ClutterInterval * @...: the initial and final values of the interval * * Variable arguments wrapper for clutter_interval_set_initial_value() * and clutter_interval_set_final_value() that avoids using the * #GValue arguments: * * |[ * clutter_interval_set_interval (interval, 0, 50); * clutter_interval_set_interval (interval, 1.0, 0.0); * clutter_interval_set_interval (interval, FALSE, TRUE); * ]| * * This function is meant for the convenience of the C API; bindings * should reimplement this function using the #GValue-based API. * * Since: 1.0 */ void clutter_interval_set_interval (ClutterInterval *interval, ...) { va_list args; g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); g_return_if_fail (interval->priv->value_type != G_TYPE_INVALID); va_start (args, interval); if (!clutter_interval_set_initial_internal (interval, &args)) goto out; clutter_interval_set_final_internal (interval, &args); out: va_end (args); } /** * clutter_interval_get_interval: * @interval: a #ClutterInterval * @...: return locations for the initial and final values of * the interval * * Variable arguments wrapper for clutter_interval_get_initial_value() * and clutter_interval_get_final_value() that avoids using the * #GValue arguments: * * |[ * gint a = 0, b = 0; * clutter_interval_get_interval (interval, &a, &b); * ]| * * This function is meant for the convenience of the C API; bindings * should reimplement this function using the #GValue-based API. * * Since: 1.0 */ void clutter_interval_get_interval (ClutterInterval *interval, ...) { va_list args; g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); g_return_if_fail (interval->priv->value_type != G_TYPE_INVALID); va_start (args, interval); clutter_interval_get_interval_valist (interval, args); va_end (args); } /** * clutter_interval_validate: * @interval: a #ClutterInterval * @pspec: a #GParamSpec * * Validates the initial and final values of @interval against * a #GParamSpec. * * Return value: %TRUE if the #ClutterInterval is valid, %FALSE otherwise * * Since: 1.0 */ gboolean clutter_interval_validate (ClutterInterval *interval, GParamSpec *pspec) { g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE); g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); return CLUTTER_INTERVAL_GET_CLASS (interval)->validate (interval, pspec); } /** * clutter_interval_compute_value: * @interval: a #ClutterInterval * @factor: the progress factor, between 0 and 1 * @value: (out caller-allocates): return location for an initialized #GValue * * Computes the value between the @interval boundaries given the * progress @factor and copies it into @value. * * Return value: %TRUE if the operation was successful * * Since: 1.0 */ gboolean clutter_interval_compute_value (ClutterInterval *interval, gdouble factor, GValue *value) { g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE); g_return_val_if_fail (value != NULL, FALSE); return CLUTTER_INTERVAL_GET_CLASS (interval)->compute_value (interval, factor, value); } /** * clutter_interval_compute: * @interval: a #ClutterInterval * @factor: the progress factor, between 0 and 1 * * Computes the value between the @interval boundaries given the * progress @factor * * Unlike clutter_interval_compute_value(), this function will * return a const pointer to the computed value * * You should use this function if you immediately pass the computed * value to another function that makes a copy of it, like * g_object_set_property() * * Return value: (transfer none): a pointer to the computed value, * or %NULL if the computation was not successfull * * Since: 1.4 */ const GValue * clutter_interval_compute (ClutterInterval *interval, gdouble factor) { GValue *value; gboolean res; g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL); value = &(interval->priv->values[RESULT]); if (G_VALUE_TYPE (value) == G_TYPE_INVALID) g_value_init (value, interval->priv->value_type); res = CLUTTER_INTERVAL_GET_CLASS (interval)->compute_value (interval, factor, value); if (res) return interval->priv->values + RESULT; return NULL; } /** * clutter_interval_is_valid: * @interval: a #ClutterInterval * * Checks if the @interval has a valid initial and final values. * * Return value: %TRUE if the #ClutterInterval has an initial and * final values, and %FALSE otherwise * * Since: 1.12 */ gboolean clutter_interval_is_valid (ClutterInterval *interval) { ClutterIntervalPrivate *priv; g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE); priv = interval->priv; return G_IS_VALUE (&priv->values[INITIAL]) && G_IS_VALUE (&priv->values[FINAL]); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-stage-window.h�������������������������������������������������0000664�0001750�0001750�00000017774�14211404421�022561� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_STAGE_WINDOW_H__ #define __CLUTTER_STAGE_WINDOW_H__ #include <cogl/cogl.h> #include <clutter/clutter-types.h> #include "clutter/clutter-stage-view.h" G_BEGIN_DECLS #define CLUTTER_TYPE_STAGE_WINDOW (_clutter_stage_window_get_type ()) #define CLUTTER_STAGE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_WINDOW, ClutterStageWindow)) #define CLUTTER_IS_STAGE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_WINDOW)) #define CLUTTER_STAGE_WINDOW_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_STAGE_WINDOW, ClutterStageWindowIface)) /* * ClutterStageWindow: (skip) * * #ClutterStageWindow is an opaque structure * whose members should not be accessed directly * * Since: 0.8 */ typedef struct _ClutterStageWindow ClutterStageWindow; /* dummy */ typedef struct _ClutterStageWindowIface ClutterStageWindowIface; /* * ClutterStageWindowIface: (skip) * * The interface implemented by backends for stage windows * * Since: 0.8 */ struct _ClutterStageWindowIface { /*< private >*/ GTypeInterface parent_iface; ClutterActor *(* get_wrapper) (ClutterStageWindow *stage_window); void (* set_title) (ClutterStageWindow *stage_window, const gchar *title); void (* set_fullscreen) (ClutterStageWindow *stage_window, gboolean is_fullscreen); void (* set_cursor_visible) (ClutterStageWindow *stage_window, gboolean cursor_visible); void (* set_user_resizable) (ClutterStageWindow *stage_window, gboolean is_resizable); gboolean (* realize) (ClutterStageWindow *stage_window); void (* unrealize) (ClutterStageWindow *stage_window); void (* show) (ClutterStageWindow *stage_window, gboolean do_raise); void (* hide) (ClutterStageWindow *stage_window); void (* resize) (ClutterStageWindow *stage_window, gint width, gint height); void (* get_geometry) (ClutterStageWindow *stage_window, cairo_rectangle_int_t *geometry); void (* schedule_update) (ClutterStageWindow *stage_window, int sync_delay); gint64 (* get_update_time) (ClutterStageWindow *stage_window); void (* clear_update_time) (ClutterStageWindow *stage_window); void (* add_redraw_clip) (ClutterStageWindow *stage_window, cairo_rectangle_int_t *stage_rectangle); gboolean (* has_redraw_clips) (ClutterStageWindow *stage_window); gboolean (* ignoring_redraw_clips) (ClutterStageWindow *stage_window); gboolean (* get_redraw_clip_bounds) (ClutterStageWindow *stage_window, cairo_rectangle_int_t *clip); void (* set_accept_focus) (ClutterStageWindow *stage_window, gboolean accept_focus); void (* redraw) (ClutterStageWindow *stage_window); void (* get_dirty_pixel) (ClutterStageWindow *stage_window, ClutterStageView *view, int *x, int *y); gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window); GList *(* get_views) (ClutterStageWindow *stage_window); int64_t (* get_frame_counter) (ClutterStageWindow *stage_window); void (* finish_frame) (ClutterStageWindow *stage_window); }; CLUTTER_AVAILABLE_IN_MUFFIN GType _clutter_stage_window_get_type (void) G_GNUC_CONST; ClutterActor * _clutter_stage_window_get_wrapper (ClutterStageWindow *window); void _clutter_stage_window_set_title (ClutterStageWindow *window, const gchar *title); void _clutter_stage_window_set_fullscreen (ClutterStageWindow *window, gboolean is_fullscreen); void _clutter_stage_window_set_cursor_visible (ClutterStageWindow *window, gboolean is_visible); void _clutter_stage_window_set_user_resizable (ClutterStageWindow *window, gboolean is_resizable); gboolean _clutter_stage_window_realize (ClutterStageWindow *window); void _clutter_stage_window_unrealize (ClutterStageWindow *window); void _clutter_stage_window_show (ClutterStageWindow *window, gboolean do_raise); void _clutter_stage_window_hide (ClutterStageWindow *window); void _clutter_stage_window_resize (ClutterStageWindow *window, gint width, gint height); void _clutter_stage_window_get_geometry (ClutterStageWindow *window, cairo_rectangle_int_t *geometry); void _clutter_stage_window_schedule_update (ClutterStageWindow *window, int sync_delay); gint64 _clutter_stage_window_get_update_time (ClutterStageWindow *window); void _clutter_stage_window_clear_update_time (ClutterStageWindow *window); void _clutter_stage_window_add_redraw_clip (ClutterStageWindow *window, cairo_rectangle_int_t *stage_clip); gboolean _clutter_stage_window_has_redraw_clips (ClutterStageWindow *window); gboolean _clutter_stage_window_ignoring_redraw_clips (ClutterStageWindow *window); gboolean _clutter_stage_window_get_redraw_clip_bounds (ClutterStageWindow *window, cairo_rectangle_int_t *clip); void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window, gboolean accept_focus); void _clutter_stage_window_redraw (ClutterStageWindow *window); void _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window, ClutterStageView *view, int *x, int *y); gboolean _clutter_stage_window_can_clip_redraws (ClutterStageWindow *window); GList * _clutter_stage_window_get_views (ClutterStageWindow *window); void _clutter_stage_window_finish_frame (ClutterStageWindow *window); int64_t _clutter_stage_window_get_frame_counter (ClutterStageWindow *window); G_END_DECLS #endif /* __CLUTTER_STAGE_WINDOW_H__ */ ����muffin-5.2.1/clutter/clutter/wayland/���������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�017737� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/wayland/clutter-wayland-surface.c��������������������������������������0000664�0001750�0001750�00000045753�14211404421�024666� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see * <http://www.gnu.org/licenses/>. * * Authors: * Robert Bragg <robert@linux.intel.com> */ /** * SECTION:clutter-wayland-surface * @Title: ClutterWaylandSurface * @short_description: An actor which displays the content of a client surface * * #ClutterWaylandSurface is an actor for displaying the contents of a client * surface. It is intended to support developers implementing Clutter based * wayland compositors. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-wayland-surface.h" #include "clutter-actor-private.h" #include "clutter-marshal.h" #include "clutter-paint-volume-private.h" #include "clutter-private.h" #include "clutter-backend.h" #include <cogl/cogl.h> #include <cogl/cogl-wayland-server.h> enum { PROP_SURFACE = 1, PROP_SURFACE_WIDTH, PROP_SURFACE_HEIGHT, PROP_COGL_TEXTURE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { QUEUE_DAMAGE_REDRAW, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0, }; struct _ClutterWaylandSurfacePrivate { struct wl_surface *surface; CoglTexture2D *buffer; int width, height; CoglPipeline *pipeline; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterWaylandSurface, clutter_wayland_surface, CLUTTER_TYPE_ACTOR) static gboolean clutter_wayland_surface_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { return clutter_paint_volume_set_from_allocation (volume, self); } static void clutter_wayland_surface_queue_damage_redraw (ClutterWaylandSurface *texture, gint x, gint y, gint width, gint height) { ClutterWaylandSurfacePrivate *priv = texture->priv; ClutterActor *self = CLUTTER_ACTOR (texture); ClutterActorBox allocation; float scale_x; float scale_y; cairo_rectangle_int_t clip; /* NB: clutter_actor_queue_redraw_with_clip expects a box in the actor's * coordinate space so we need to convert from surface coordinates to * actor coordinates... */ /* Calling clutter_actor_get_allocation_box() is enormously expensive * if the actor has an out-of-date allocation, since it triggers * a full redraw. clutter_actor_queue_redraw_with_clip() would redraw * the whole stage anyways in that case, so just go ahead and do * it here. */ if (!clutter_actor_has_allocation (self)) { clutter_actor_queue_redraw (self); return; } if (priv->width == 0 || priv->height == 0) return; clutter_actor_get_allocation_box (self, &allocation); scale_x = (allocation.x2 - allocation.x1) / priv->width; scale_y = (allocation.y2 - allocation.y1) / priv->height; clip.x = x * scale_x; clip.y = y * scale_y; clip.width = width * scale_x; clip.height = height * scale_y; clutter_actor_queue_redraw_with_clip (self, &clip); } static void free_pipeline (ClutterWaylandSurface *self) { ClutterWaylandSurfacePrivate *priv = self->priv; if (priv->pipeline) { cogl_object_unref (priv->pipeline); priv->pipeline = NULL; } } static void opacity_change_cb (ClutterWaylandSurface *self) { free_pipeline (self); } static void clutter_wayland_surface_init (ClutterWaylandSurface *self) { ClutterWaylandSurfacePrivate *priv; priv = clutter_wayland_surface_get_instance_private (self); priv->surface = NULL; priv->width = 0; priv->height = 0; self->priv = priv; g_signal_connect (self, "notify::opacity", G_CALLBACK (opacity_change_cb), NULL); } static void free_surface_buffers (ClutterWaylandSurface *self) { ClutterWaylandSurfacePrivate *priv = self->priv; if (priv->buffer) { cogl_object_unref (priv->buffer); priv->buffer = NULL; free_pipeline (self); } } static void clutter_wayland_surface_dispose (GObject *object) { ClutterWaylandSurface *self = CLUTTER_WAYLAND_SURFACE (object); ClutterWaylandSurfacePrivate *priv = self->priv; free_pipeline (self); free_surface_buffers (self); priv->surface = NULL; G_OBJECT_CLASS (clutter_wayland_surface_parent_class)->dispose (object); } static void set_size (ClutterWaylandSurface *self, int width, int height) { ClutterWaylandSurfacePrivate *priv = self->priv; if (priv->width != width) { priv->width = width; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SURFACE_WIDTH]); } if (priv->height != height) { priv->height = height; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SURFACE_HEIGHT]); } clutter_actor_set_size (CLUTTER_ACTOR (self), priv->width, priv->height); } /** * clutter_wayland_surface_get_surface: * @self: a #ClutterWaylandSurface * * Retrieves a point to the Wayland surface used by the actor. * * Return value: (transfer none): a wl_surface pointer, or %NULL * * Since: 1.10 */ struct wl_surface * clutter_wayland_surface_get_surface (ClutterWaylandSurface *self) { ClutterWaylandSurfacePrivate *priv = self->priv; return priv->surface; } /** * clutter_wayland_surface_set_surface: * @self: a #ClutterWaylandSurface * @surface: a Wayland wl_surface pointer * * Sets the Wayland surface to be used by the actor. * * Since: 1.10 */ void clutter_wayland_surface_set_surface (ClutterWaylandSurface *self, struct wl_surface *surface) { ClutterWaylandSurfacePrivate *priv; g_return_if_fail (CLUTTER_WAYLAND_IS_SURFACE (self)); priv = self->priv; if (priv->surface == surface) return; if (priv->surface) { free_pipeline (self); free_surface_buffers (self); g_signal_emit (self, signals[QUEUE_DAMAGE_REDRAW], 0, 0, 0, priv->width, priv->height); } priv->surface = surface; /* XXX: should we freeze/thaw notifications? */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SURFACE]); /* We have to wait until the next attach event to find out the surface * geometry... */ set_size (self, 0, 0); } static void clutter_wayland_surface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterWaylandSurface *self = CLUTTER_WAYLAND_SURFACE (object); switch (prop_id) { case PROP_SURFACE: clutter_wayland_surface_set_surface (self, g_value_get_pointer (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_wayland_surface_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterWaylandSurface *self = CLUTTER_WAYLAND_SURFACE (object); ClutterWaylandSurfacePrivate *priv = self->priv; switch (prop_id) { case PROP_SURFACE: g_value_set_pointer (value, priv->surface); break; case PROP_SURFACE_WIDTH: g_value_set_uint (value, priv->width); break; case PROP_SURFACE_HEIGHT: g_value_set_uint (value, priv->height); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_wayland_surface_paint (ClutterActor *self) { ClutterWaylandSurfacePrivate *priv; ClutterActorBox box; g_return_if_fail (CLUTTER_WAYLAND_IS_SURFACE (self)); priv = CLUTTER_WAYLAND_SURFACE (self)->priv; if (G_UNLIKELY (priv->pipeline == NULL)) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); guint8 paint_opacity = clutter_actor_get_paint_opacity (self); priv->pipeline = cogl_pipeline_new (ctx); cogl_pipeline_set_color4ub (priv->pipeline, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (priv->buffer)); } cogl_set_source (priv->pipeline); clutter_actor_get_allocation_box (self, &box); cogl_rectangle (0, 0, box.x2 - box.x1, box.y2 - box.y1); } static void clutter_wayland_surface_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterWaylandSurfacePrivate *priv; g_return_if_fail (CLUTTER_WAYLAND_IS_SURFACE (self)); priv = CLUTTER_WAYLAND_SURFACE (self)->priv; if (min_width_p) *min_width_p = 0; if (natural_width_p) *natural_width_p = priv->width; } static void clutter_wayland_surface_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterWaylandSurfacePrivate *priv; g_return_if_fail (CLUTTER_WAYLAND_IS_SURFACE (self)); priv = CLUTTER_WAYLAND_SURFACE (self)->priv; if (min_height_p) *min_height_p = 0; if (natural_height_p) *natural_height_p = priv->height; } static gboolean clutter_wayland_surface_has_overlaps (ClutterActor *self) { /* Rectangles never need an offscreen redirect because there are never any overlapping primitives */ return FALSE; } static void clutter_wayland_surface_class_init (ClutterWaylandSurfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GParamSpec *pspec; actor_class->get_paint_volume = clutter_wayland_surface_get_paint_volume; actor_class->paint = clutter_wayland_surface_paint; actor_class->get_preferred_width = clutter_wayland_surface_get_preferred_width; actor_class->get_preferred_height = clutter_wayland_surface_get_preferred_height; actor_class->has_overlaps = clutter_wayland_surface_has_overlaps; object_class->dispose = clutter_wayland_surface_dispose; object_class->set_property = clutter_wayland_surface_set_property; object_class->get_property = clutter_wayland_surface_get_property; pspec = g_param_spec_pointer ("surface", P_("Surface"), P_("The underlying wayland surface"), CLUTTER_PARAM_READWRITE| G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_SURFACE] = pspec; g_object_class_install_property (object_class, PROP_SURFACE, pspec); pspec = g_param_spec_uint ("surface-width", P_("Surface width"), P_("The width of the underlying wayland surface"), 0, G_MAXUINT, 0, G_PARAM_READABLE); obj_props[PROP_SURFACE_WIDTH] = pspec; g_object_class_install_property (object_class, PROP_SURFACE_WIDTH, pspec); pspec = g_param_spec_uint ("surface-height", P_("Surface height"), P_("The height of the underlying wayland surface"), 0, G_MAXUINT, 0, G_PARAM_READABLE); obj_props[PROP_SURFACE_HEIGHT] = pspec; g_object_class_install_property (object_class, PROP_SURFACE_HEIGHT, pspec); pspec = g_param_spec_boxed ("cogl-texture", P_("Cogl Texture"), P_("The underlying Cogl texture handle used to draw this actor"), COGL_TYPE_HANDLE, CLUTTER_PARAM_READWRITE); obj_props[PROP_COGL_TEXTURE] = pspec; g_object_class_install_property (object_class, PROP_COGL_TEXTURE, pspec); /** * ClutterWaylandSurface::queue-damage-redraw: * @texture: the object which received the signal * @x: The top left x position of the damage region * @y: The top left y position of the damage region * @width: The width of the damage region * @height: The height of the damage region * * ::queue-damage-redraw is emitted to notify that some sub-region * of the texture has been changed. This usually means a redraw * needs to be queued for the actor. * * The default handler will queue a clipped redraw in response to * the damage, using the assumption that the pixmap is being painted * to a rectangle covering the transformed allocation of the actor. * If you sub-class and change the paint method so this isn't true * then you must also provide your own damage signal handler to * queue a redraw that blocks this default behaviour. * * Since: 1.10 */ signals[QUEUE_DAMAGE_REDRAW] = g_signal_new (g_intern_static_string ("queue-damage-redraw"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterWaylandSurfaceClass, queue_damage_redraw), NULL, NULL, _clutter_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); klass->queue_damage_redraw = clutter_wayland_surface_queue_damage_redraw; } /** * clutter_wayland_surface_new: * @surface: the Wayland surface this actor should represent * * Creates a new #ClutterWaylandSurface for @surface * * Return value: A new #ClutterWaylandSurface representing @surface * * Since: 1.8 * Stability: unstable */ ClutterActor * clutter_wayland_surface_new (struct wl_surface *surface) { ClutterActor *actor; actor = g_object_new (CLUTTER_WAYLAND_TYPE_SURFACE, "surface", surface, NULL); return actor; } /** * clutter_wayland_surface_attach_buffer: * @self: A #ClutterWaylandSurface actor * @buffer: A compositor side resource representing a wl_buffer * @error: A #GError * * This associates a client's buffer with the #ClutterWaylandSurface * actor @self. This will automatically result in @self being re-drawn * with the new buffer contents. * * Since: 1.8 * Stability: unstable */ gboolean clutter_wayland_surface_attach_buffer (ClutterWaylandSurface *self, struct wl_resource *buffer, GError **error) { ClutterWaylandSurfacePrivate *priv; ClutterBackend *backend = clutter_get_default_backend (); CoglContext *context = clutter_backend_get_cogl_context (backend); g_return_val_if_fail (CLUTTER_WAYLAND_IS_SURFACE (self), TRUE); priv = self->priv; free_surface_buffers (self); priv->buffer = cogl_wayland_texture_2d_new_from_buffer (context, buffer, error); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_COGL_TEXTURE]); /* NB: We don't queue a redraw of the actor here because we don't * know how much of the buffer has changed with respect to the * previous buffer. We only ever queue a redraw in response to * surface damage. */ if (!priv->buffer) return FALSE; set_size (self, cogl_texture_get_width (COGL_TEXTURE (priv->buffer)), cogl_texture_get_height (COGL_TEXTURE (priv->buffer))); return TRUE; } /** * clutter_wayland_surface_damage_buffer: * @self: A #ClutterWaylandSurface actor * @buffer: A wayland resource for a buffer * @x: The x coordinate of the damaged rectangle * @y: The y coordinate of the damaged rectangle * @width: The width of the damaged rectangle * @height: The height of the damaged rectangle * * This marks a region of the given @buffer has having been changed by * the client. This will automatically result in the corresponding damaged * region of the actor @self being redrawn. * * If multiple regions are changed then this should be called multiple * times with different damage rectangles. * * Since: 1.8 * Stability: unstable */ void clutter_wayland_surface_damage_buffer (ClutterWaylandSurface *self, struct wl_resource *buffer, gint32 x, gint32 y, gint32 width, gint32 height) { ClutterWaylandSurfacePrivate *priv; struct wl_shm_buffer *shm_buffer; g_return_if_fail (CLUTTER_WAYLAND_IS_SURFACE (self)); priv = self->priv; shm_buffer = wl_shm_buffer_get (buffer); if (priv->buffer && shm_buffer) { CoglPixelFormat format; switch (wl_shm_buffer_get_format (shm_buffer)) { #if G_BYTE_ORDER == G_BIG_ENDIAN case WL_SHM_FORMAT_ARGB8888: format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; break; case WL_SHM_FORMAT_XRGB8888: format = COGL_PIXEL_FORMAT_ARGB_8888; break; #elif G_BYTE_ORDER == G_LITTLE_ENDIAN case WL_SHM_FORMAT_ARGB8888: format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; break; case WL_SHM_FORMAT_XRGB8888: format = COGL_PIXEL_FORMAT_BGRA_8888; break; #endif default: g_warn_if_reached (); format = COGL_PIXEL_FORMAT_ARGB_8888; } cogl_texture_set_region (COGL_TEXTURE (priv->buffer), x, y, x, y, width, height, width, height, format, wl_shm_buffer_get_stride (shm_buffer), wl_shm_buffer_get_data (shm_buffer)); } g_signal_emit (self, signals[QUEUE_DAMAGE_REDRAW], 0, x, y, width, height); } /** * clutter_wayland_surface_get_cogl_texture: * @self: a #ClutterWaylandSurface * * Retrieves the Cogl texture with the contents of the Wayland surface. * * Return value: (transfer none): a Cogl texture, or %NULL * * Since: 1.10 */ CoglTexture * clutter_wayland_surface_get_cogl_texture (ClutterWaylandSurface *self) { g_return_val_if_fail (CLUTTER_WAYLAND_IS_SURFACE (self), NULL); return COGL_TEXTURE (self->priv->buffer); } ���������������������muffin-5.2.1/clutter/clutter/wayland/clutter-wayland-surface.h��������������������������������������0000664�0001750�0001750�00000010402�14211404421�024652� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see * <http://www.gnu.org/licenses/>. * * Authors: * Robert Bragg <robert@linux.intel.com> * */ #ifndef __CLUTTER_WAYLAND_SURFACE_H__ #define __CLUTTER_WAYLAND_SURFACE_H__ #include <glib.h> #include <glib-object.h> #include <clutter/clutter.h> #include <wayland-server.h> G_BEGIN_DECLS #define CLUTTER_WAYLAND_TYPE_SURFACE (clutter_wayland_surface_get_type ()) #define CLUTTER_WAYLAND_SURFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_WAYLAND_TYPE_SURFACE, ClutterWaylandSurface)) #define CLUTTER_WAYLAND_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_WAYLAND_TYPE_SURFACE, ClutterWaylandSurfaceClass)) #define CLUTTER_WAYLAND_IS_SURFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_WAYLAND_TYPE_SURFACE)) #define CLUTTER_WAYLAND_IS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_WAYLAND_TYPE_SURFACE)) #define CLUTTER_WAYLAND_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_WAYLAND_TYPE_SURFACE, ClutterWaylandSurfaceClass)) typedef struct _ClutterWaylandSurface ClutterWaylandSurface; typedef struct _ClutterWaylandSurfaceClass ClutterWaylandSurfaceClass; typedef struct _ClutterWaylandSurfacePrivate ClutterWaylandSurfacePrivate; /** * ClutterWaylandSurface: * * The #ClutterWaylandSurface structure contains only private data * * Since: 1.10 * Stability: unstable */ struct _ClutterWaylandSurface { /*< private >*/ ClutterActor parent; ClutterWaylandSurfacePrivate *priv; }; /** * ClutterWaylandSurfaceClass: * @queue_damage_redraw: class handler of the #ClutterWaylandSurface::queue-damage-redraw signal * * The #ClutterWaylandSurfaceClass structure contains only private data * * Since: 1.10 * Stability: unstable */ struct _ClutterWaylandSurfaceClass { /*< private >*/ ClutterActorClass parent_class; /*< public >*/ void (*queue_damage_redraw) (ClutterWaylandSurface *texture, gint x, gint y, gint width, gint height); /*< private >*/ /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_AVAILABLE_IN_1_10 GType clutter_wayland_surface_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_8 ClutterActor *clutter_wayland_surface_new (struct wl_surface *surface); CLUTTER_AVAILABLE_IN_1_10 void clutter_wayland_surface_set_surface (ClutterWaylandSurface *self, struct wl_surface *surface); CLUTTER_AVAILABLE_IN_1_10 struct wl_surface *clutter_wayland_surface_get_surface (ClutterWaylandSurface *self); CLUTTER_AVAILABLE_IN_1_8 gboolean clutter_wayland_surface_attach_buffer (ClutterWaylandSurface *self, struct wl_resource *buffer, GError **error); CLUTTER_AVAILABLE_IN_1_8 void clutter_wayland_surface_damage_buffer (ClutterWaylandSurface *self, struct wl_resource *buffer, gint32 x, gint32 y, gint32 width, gint32 height); CLUTTER_AVAILABLE_IN_1_10 CoglTexture *clutter_wayland_surface_get_cogl_texture (ClutterWaylandSurface *self); G_END_DECLS #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/wayland/clutter-wayland-compositor.h�����������������������������������0000664�0001750�0001750�00000002524�14211404421�025426� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Authors: * Robert Bragg <robert@linux.intel.com> */ /** * SECTION:clutter-wayland-compositor * @short_description: Wayland compositor specific APIs * * Clutter provides some Wayland specific APIs to aid in writing * Clutter based compositors. * * The Clutter Wayland compositor API is available since Clutter 1.8 */ #ifndef __CLUTTER_WAYLAND_COMPOSITOR_H__ #define __CLUTTER_WAYLAND_COMPOSITOR_H__ G_BEGIN_DECLS CLUTTER_AVAILABLE_IN_1_10 void clutter_wayland_set_compositor_display (void *display); G_END_DECLS #endif /* __CLUTTER_WAYLAND_COMPOSITOR_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-transition-group.h���������������������������������������������0000664�0001750�0001750�00000006714�14211404421�023465� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_TRANSITION_GROUP_H__ #define __CLUTTER_TRANSITION_GROUP_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-transition.h> G_BEGIN_DECLS #define CLUTTER_TYPE_TRANSITION_GROUP (clutter_transition_group_get_type ()) #define CLUTTER_TRANSITION_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TRANSITION_GROUP, ClutterTransitionGroup)) #define CLUTTER_IS_TRANSITION_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TRANSITION_GROUP)) #define CLUTTER_TRANSITION_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TRANSITION_GROUP, ClutterTransitionGroupClass)) #define CLUTTER_IS_TRANSITION_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TRANSITION_GROUP)) #define CLUTTER_TRANSITION_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TRANSITION_GROUP, ClutterTransitionGroup)) typedef struct _ClutterTransitionGroupPrivate ClutterTransitionGroupPrivate; typedef struct _ClutterTransitionGroupClass ClutterTransitionGroupClass; /** * ClutterTransitionGroup: * * The #ClutterTransitionGroup structure contains * private data and should only be accessed using the provided API. * * Since: 1.12 */ struct _ClutterTransitionGroup { /*< private >*/ ClutterTransition parent_instance; ClutterTransitionGroupPrivate *priv; }; /** * ClutterTransitionGroupClass: * * The #ClutterTransitionGroupClass structure * contains only private data. * * Since: 1.12 */ struct _ClutterTransitionGroupClass { /*< private >*/ ClutterTransitionClass parent_class; gpointer _padding[8]; }; CLUTTER_AVAILABLE_IN_1_12 GType clutter_transition_group_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterTransition * clutter_transition_group_new (void); CLUTTER_AVAILABLE_IN_1_12 void clutter_transition_group_add_transition (ClutterTransitionGroup *group, ClutterTransition *transition); CLUTTER_AVAILABLE_IN_1_12 void clutter_transition_group_remove_transition (ClutterTransitionGroup *group, ClutterTransition *transition); CLUTTER_AVAILABLE_IN_1_12 void clutter_transition_group_remove_all (ClutterTransitionGroup *group); G_END_DECLS #endif /* __CLUTTER_TRANSITION_GROUP_H__ */ ����������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-transition-group.c���������������������������������������������0000664�0001750�0001750�00000016073�14211404421�023457� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-transition-group * @Title: ClutterTransitionGroup * @Short_Description: Group transitions together * * The #ClutterTransitionGroup allows running multiple #ClutterTransition * instances concurrently. * * The transitions inside a group will run within the boundaries of the * group; for instance, if a transition has a duration of 10 seconds, and * the group that contains it has a duration of 5 seconds, only the first * 5 seconds of the transition will be played. * * #ClutterTransitionGroup is available since Clutter 1.12 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-transition-group.h" #include "clutter-debug.h" #include "clutter-private.h" struct _ClutterTransitionGroupPrivate { GHashTable *transitions; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterTransitionGroup, clutter_transition_group, CLUTTER_TYPE_TRANSITION) static void clutter_transition_group_new_frame (ClutterTimeline *timeline, gint elapsed) { ClutterTransitionGroupPrivate *priv; GHashTableIter iter; gpointer element; gint64 msecs; priv = CLUTTER_TRANSITION_GROUP (timeline)->priv; /* get the time elapsed since the last ::new-frame... */ msecs = clutter_timeline_get_delta (timeline); g_hash_table_iter_init (&iter, priv->transitions); while (g_hash_table_iter_next (&iter, &element, NULL)) { ClutterTimeline *t = element; /* ... and advance every timeline */ clutter_timeline_set_direction (t, clutter_timeline_get_direction (timeline)); clutter_timeline_set_duration (t, clutter_timeline_get_duration (timeline)); _clutter_timeline_advance (t, msecs); } } static void clutter_transition_group_attached (ClutterTransition *transition, ClutterAnimatable *animatable) { ClutterTransitionGroupPrivate *priv; GHashTableIter iter; gpointer element; priv = CLUTTER_TRANSITION_GROUP (transition)->priv; g_hash_table_iter_init (&iter, priv->transitions); while (g_hash_table_iter_next (&iter, &element, NULL)) { ClutterTransition *t = element; clutter_transition_set_animatable (t, animatable); } } static void clutter_transition_group_detached (ClutterTransition *transition, ClutterAnimatable *animatable) { ClutterTransitionGroupPrivate *priv; GHashTableIter iter; gpointer element; priv = CLUTTER_TRANSITION_GROUP (transition)->priv; g_hash_table_iter_init (&iter, priv->transitions); while (g_hash_table_iter_next (&iter, &element, NULL)) { ClutterTransition *t = element; clutter_transition_set_animatable (t, NULL); } } static void clutter_transition_group_started (ClutterTimeline *timeline) { ClutterTransitionGroupPrivate *priv; GHashTableIter iter; gpointer element; priv = CLUTTER_TRANSITION_GROUP (timeline)->priv; g_hash_table_iter_init (&iter, priv->transitions); while (g_hash_table_iter_next (&iter, &element, NULL)) { ClutterTransition *t = element; g_signal_emit_by_name (t, "started"); } } static void clutter_transition_group_finalize (GObject *gobject) { ClutterTransitionGroupPrivate *priv; priv = CLUTTER_TRANSITION_GROUP (gobject)->priv; g_hash_table_unref (priv->transitions); G_OBJECT_CLASS (clutter_transition_group_parent_class)->finalize (gobject); } static void clutter_transition_group_class_init (ClutterTransitionGroupClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterTimelineClass *timeline_class = CLUTTER_TIMELINE_CLASS (klass); ClutterTransitionClass *transition_class = CLUTTER_TRANSITION_CLASS (klass); gobject_class->finalize = clutter_transition_group_finalize; timeline_class->started = clutter_transition_group_started; timeline_class->new_frame = clutter_transition_group_new_frame; transition_class->attached = clutter_transition_group_attached; transition_class->detached = clutter_transition_group_detached; } static void clutter_transition_group_init (ClutterTransitionGroup *self) { self->priv = clutter_transition_group_get_instance_private (self); self->priv->transitions = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) g_object_unref, NULL); } /** * clutter_transition_group_new: * * Creates a new #ClutterTransitionGroup instance. * * Return value: the newly created #ClutterTransitionGroup. Use * g_object_unref() when done to deallocate the resources it * uses * * Since: 1.12 */ ClutterTransition * clutter_transition_group_new (void) { return g_object_new (CLUTTER_TYPE_TRANSITION_GROUP, NULL); } /** * clutter_transition_group_add_transition: * @group: a #ClutterTransitionGroup * @transition: a #ClutterTransition * * Adds @transition to @group. * * This function acquires a reference on @transition that will be released * when calling clutter_transition_group_remove_transition(). * * Since: 1.12 */ void clutter_transition_group_add_transition (ClutterTransitionGroup *group, ClutterTransition *transition) { g_return_if_fail (CLUTTER_IS_TRANSITION_GROUP (group)); g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_hash_table_add (group->priv->transitions, g_object_ref (transition)); } /** * clutter_transition_group_remove_transition: * @group: a #ClutterTransitionGroup * @transition: a #ClutterTransition * * Removes @transition from @group. * * This function releases the reference acquired on @transition when * calling clutter_transition_group_add_transition(). * * Since: 1.12 */ void clutter_transition_group_remove_transition (ClutterTransitionGroup *group, ClutterTransition *transition) { g_return_if_fail (CLUTTER_IS_TRANSITION_GROUP (group)); g_hash_table_remove (group->priv->transitions, transition); } /** * clutter_transition_group_remove_all: * @group: a #ClutterTransitionGroup * * Removes all transitions from @group. * * This function releases the reference acquired when calling * clutter_transition_group_add_transition(). * * Since: 1.12 */ void clutter_transition_group_remove_all (ClutterTransitionGroup *group) { g_return_if_fail (CLUTTER_IS_TRANSITION_GROUP (group)); g_hash_table_remove_all (group->priv->transitions); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-fixed-layout.c�������������������������������������������������0000664�0001750�0001750�00000012121�14211404421�022533� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> * * Based on the fixed layout code inside clutter-group.c */ /** * SECTION:clutter-fixed-layout * @short_description: A fixed layout manager * * #ClutterFixedLayout is a layout manager implementing the same * layout policies as #ClutterGroup. * * #ClutterFixedLayout is available since Clutter 1.2 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-debug.h" #include "clutter-fixed-layout.h" #include "clutter-private.h" G_DEFINE_TYPE (ClutterFixedLayout, clutter_fixed_layout, CLUTTER_TYPE_LAYOUT_MANAGER); static void clutter_fixed_layout_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { ClutterActor *actor, *child; gdouble min_right; gdouble natural_right; min_right = 0; natural_right = 0; actor = CLUTTER_ACTOR (container); for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { gfloat child_x, child_min, child_natural; child_x = clutter_actor_get_x (child); clutter_actor_get_preferred_size (child, &child_min, NULL, &child_natural, NULL); if (child_x + child_min > min_right) min_right = child_x + child_min; if (child_x + child_natural > natural_right) natural_right = child_x + child_natural; } if (min_width_p) *min_width_p = min_right; if (nat_width_p) *nat_width_p = natural_right; } static void clutter_fixed_layout_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { ClutterActor *actor, *child; gdouble min_bottom; gdouble natural_bottom; min_bottom = 0; natural_bottom = 0; actor = CLUTTER_ACTOR (container); for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { gfloat child_y, child_min, child_natural; child_y = clutter_actor_get_y (child); clutter_actor_get_preferred_size (child, NULL, &child_min, NULL, &child_natural); if (child_y + child_min > min_bottom) min_bottom = child_y + child_min; if (child_y + child_natural > natural_bottom) natural_bottom = child_y + child_natural; } if (min_height_p) *min_height_p = min_bottom; if (nat_height_p) *nat_height_p = natural_bottom; } static void clutter_fixed_layout_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterActor *child; for (child = clutter_actor_get_first_child (CLUTTER_ACTOR (container)); child != NULL; child = clutter_actor_get_next_sibling (child)) { clutter_actor_allocate_preferred_size (child, flags); } } static void clutter_fixed_layout_class_init (ClutterFixedLayoutClass *klass) { ClutterLayoutManagerClass *manager_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass); manager_class->get_preferred_width = clutter_fixed_layout_get_preferred_width; manager_class->get_preferred_height = clutter_fixed_layout_get_preferred_height; manager_class->allocate = clutter_fixed_layout_allocate; } static void clutter_fixed_layout_init (ClutterFixedLayout *self) { } /** * clutter_fixed_layout_new: * * Creates a new #ClutterFixedLayout * * Return value: the newly created #ClutterFixedLayout * * Since: 1.2 */ ClutterLayoutManager * clutter_fixed_layout_new (void) { return g_object_new (CLUTTER_TYPE_FIXED_LAYOUT, NULL); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-animatable.c���������������������������������������������������0000664�0001750�0001750�00000023720�14211404421�022225� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-animatable * @short_description: Interface for animatable classes * * #ClutterAnimatable is an interface that allows a #GObject class * to control how a #ClutterAnimation will animate a property. * * Each #ClutterAnimatable should implement the * #ClutterAnimatableIface.interpolate_property() virtual function of the * interface to compute the animation state between two values of an interval * depending on a progress factor, expressed as a floating point value. * * If a #ClutterAnimatable is animated by a #ClutterAnimation * instance, the #ClutterAnimation will call * clutter_animatable_interpolate_property() passing the name of the * currently animated property; the values interval; and the progress factor. * The #ClutterAnimatable implementation should return the computed value for * the animated * property. * * #ClutterAnimatable is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-animatable.h" #include "clutter-interval.h" #include "clutter-debug.h" #include "clutter-private.h" #include "deprecated/clutter-animatable.h" #include "deprecated/clutter-animation.h" typedef ClutterAnimatableIface ClutterAnimatableInterface; G_DEFINE_INTERFACE (ClutterAnimatable, clutter_animatable, G_TYPE_OBJECT); static void clutter_animatable_default_init (ClutterAnimatableInterface *iface) { } /** * clutter_animatable_animate_property: * @animatable: a #ClutterAnimatable * @animation: a #ClutterAnimation * @property_name: the name of the animated property * @initial_value: the initial value of the animation interval * @final_value: the final value of the animation interval * @progress: the progress factor * @value: return location for the animation value * * Calls the animate_property() virtual function for @animatable. * * The @initial_value and @final_value #GValue<!-- -->s must contain * the same type; @value must have been initialized to the same * type of @initial_value and @final_value. * * All implementation of the #ClutterAnimatable interface must * implement this function. * * Return value: %TRUE if the value has been validated and can * be applied to the #ClutterAnimatable, and %FALSE otherwise * * Since: 1.0 * * Deprecated: 1.8: Use clutter_animatable_interpolate_value() * instead */ gboolean clutter_animatable_animate_property (ClutterAnimatable *animatable, ClutterAnimation *animation, const gchar *property_name, const GValue *initial_value, const GValue *final_value, gdouble progress, GValue *value) { ClutterAnimatableIface *iface; gboolean res; g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), FALSE); g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE); g_return_val_if_fail (property_name != NULL, FALSE); g_return_val_if_fail (initial_value != NULL && final_value != NULL, FALSE); g_return_val_if_fail (G_VALUE_TYPE (initial_value) != G_TYPE_INVALID, FALSE); g_return_val_if_fail (G_VALUE_TYPE (final_value) != G_TYPE_INVALID, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (G_VALUE_TYPE (value) == G_VALUE_TYPE (initial_value) && G_VALUE_TYPE (value) == G_VALUE_TYPE (final_value), FALSE); iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); if (iface->animate_property == NULL) { ClutterInterval *interval; interval = clutter_animation_get_interval (animation, property_name); if (interval == NULL) return FALSE; res = clutter_animatable_interpolate_value (animatable, property_name, interval, progress, value); } else res = iface->animate_property (animatable, animation, property_name, initial_value, final_value, progress, value); return res; } /** * clutter_animatable_find_property: * @animatable: a #ClutterAnimatable * @property_name: the name of the animatable property to find * * Finds the #GParamSpec for @property_name * * Return value: (transfer none): The #GParamSpec for the given property * or %NULL * * Since: 1.4 */ GParamSpec * clutter_animatable_find_property (ClutterAnimatable *animatable, const gchar *property_name) { ClutterAnimatableIface *iface; g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), NULL); g_return_val_if_fail (property_name != NULL, NULL); CLUTTER_NOTE (ANIMATION, "Looking for property '%s'", property_name); iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); if (iface->find_property != NULL) return iface->find_property (animatable, property_name); return g_object_class_find_property (G_OBJECT_GET_CLASS (animatable), property_name); } /** * clutter_animatable_get_initial_state: * @animatable: a #ClutterAnimatable * @property_name: the name of the animatable property to retrieve * @value: a #GValue initialized to the type of the property to retrieve * * Retrieves the current state of @property_name and sets @value with it * * Since: 1.4 */ void clutter_animatable_get_initial_state (ClutterAnimatable *animatable, const gchar *property_name, GValue *value) { ClutterAnimatableIface *iface; g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable)); g_return_if_fail (property_name != NULL); CLUTTER_NOTE (ANIMATION, "Getting initial state of '%s'", property_name); iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); if (iface->get_initial_state != NULL) iface->get_initial_state (animatable, property_name, value); else g_object_get_property (G_OBJECT (animatable), property_name, value); } /** * clutter_animatable_set_final_state: * @animatable: a #ClutterAnimatable * @property_name: the name of the animatable property to set * @value: the value of the animatable property to set * * Sets the current state of @property_name to @value * * Since: 1.4 */ void clutter_animatable_set_final_state (ClutterAnimatable *animatable, const gchar *property_name, const GValue *value) { ClutterAnimatableIface *iface; g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable)); g_return_if_fail (property_name != NULL); CLUTTER_NOTE (ANIMATION, "Setting state of property '%s'", property_name); iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); if (iface->set_final_state != NULL) iface->set_final_state (animatable, property_name, value); else g_object_set_property (G_OBJECT (animatable), property_name, value); } /** * clutter_animatable_interpolate_value: * @animatable: a #ClutterAnimatable * @property_name: the name of the property to interpolate * @interval: a #ClutterInterval with the animation range * @progress: the progress to use to interpolate between the * initial and final values of the @interval * @value: (out): return location for an initialized #GValue * using the same type of the @interval * * Asks a #ClutterAnimatable implementation to interpolate a * a named property between the initial and final values of * a #ClutterInterval, using @progress as the interpolation * value, and store the result inside @value. * * This function should be used for every property animation * involving #ClutterAnimatable<!-- -->s. * * This function replaces clutter_animatable_animate_property(). * * Return value: %TRUE if the interpolation was successful, * and %FALSE otherwise * * Since: 1.8 */ gboolean clutter_animatable_interpolate_value (ClutterAnimatable *animatable, const gchar *property_name, ClutterInterval *interval, gdouble progress, GValue *value) { ClutterAnimatableIface *iface; g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), FALSE); g_return_val_if_fail (property_name != NULL, FALSE); g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE); g_return_val_if_fail (value != NULL, FALSE); CLUTTER_NOTE (ANIMATION, "Interpolating '%s' (progress: %.3f)", property_name, progress); iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable); if (iface->interpolate_value != NULL) { return iface->interpolate_value (animatable, property_name, interval, progress, value); } else return clutter_interval_compute_value (interval, progress, value); } ������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-flow-layout.h��������������������������������������������������0000664�0001750�0001750�00000013300�14211404421�022410� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_FLOW_LAYOUT_H__ #define __CLUTTER_FLOW_LAYOUT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-layout-manager.h> G_BEGIN_DECLS #define CLUTTER_TYPE_FLOW_LAYOUT (clutter_flow_layout_get_type ()) #define CLUTTER_FLOW_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayout)) #define CLUTTER_IS_FLOW_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_FLOW_LAYOUT)) #define CLUTTER_FLOW_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayoutClass)) #define CLUTTER_IS_FLOW_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_FLOW_LAYOUT)) #define CLUTTER_FLOW_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_FLOW_LAYOUT, ClutterFlowLayoutClass)) typedef struct _ClutterFlowLayout ClutterFlowLayout; typedef struct _ClutterFlowLayoutPrivate ClutterFlowLayoutPrivate; typedef struct _ClutterFlowLayoutClass ClutterFlowLayoutClass; /** * ClutterFlowLayout: * * The #ClutterFlowLayout structure contains only private data * and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterFlowLayout { /*< private >*/ ClutterLayoutManager parent_instance; ClutterFlowLayoutPrivate *priv; }; /** * ClutterFlowLayoutClass: * * The #ClutterFlowLayoutClass structure contains only private data * and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterFlowLayoutClass { /*< private >*/ ClutterLayoutManagerClass parent_class; }; CLUTTER_AVAILABLE_IN_1_2 GType clutter_flow_layout_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 ClutterLayoutManager * clutter_flow_layout_new (ClutterFlowOrientation orientation); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_set_orientation (ClutterFlowLayout *layout, ClutterFlowOrientation orientation); CLUTTER_AVAILABLE_IN_1_2 ClutterFlowOrientation clutter_flow_layout_get_orientation (ClutterFlowLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_set_homogeneous (ClutterFlowLayout *layout, gboolean homogeneous); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_flow_layout_get_homogeneous (ClutterFlowLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_set_column_spacing (ClutterFlowLayout *layout, gfloat spacing); CLUTTER_AVAILABLE_IN_1_2 gfloat clutter_flow_layout_get_column_spacing (ClutterFlowLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_set_row_spacing (ClutterFlowLayout *layout, gfloat spacing); CLUTTER_AVAILABLE_IN_1_2 gfloat clutter_flow_layout_get_row_spacing (ClutterFlowLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_set_column_width (ClutterFlowLayout *layout, gfloat min_width, gfloat max_width); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_get_column_width (ClutterFlowLayout *layout, gfloat *min_width, gfloat *max_width); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_set_row_height (ClutterFlowLayout *layout, gfloat min_height, gfloat max_height); CLUTTER_AVAILABLE_IN_1_2 void clutter_flow_layout_get_row_height (ClutterFlowLayout *layout, gfloat *min_height, gfloat *max_height); CLUTTER_AVAILABLE_IN_1_16 void clutter_flow_layout_set_snap_to_grid (ClutterFlowLayout *layout, gboolean snap_to_grid); CLUTTER_AVAILABLE_IN_1_16 gboolean clutter_flow_layout_get_snap_to_grid (ClutterFlowLayout *layout); G_END_DECLS #endif /* __CLUTTER_FLOW_LAYOUT_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-brightness-contrast-effect.h�����������������������������������0000664�0001750�0001750�00000011321�14211404421�025364� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010-2012 Inclusive Design Research Centre, OCAD University. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Joseph Scheuhammer <clown@alum.mit.edu> */ #ifndef __CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_H__ #define __CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-color.h> #include <clutter/clutter-effect.h> G_BEGIN_DECLS #define CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT (clutter_brightness_contrast_effect_get_type ()) #define CLUTTER_BRIGHTNESS_CONTRAST_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT, ClutterBrightnessContrastEffect)) #define CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT)) /** * ClutterBrightnessContrastEffect: * * #ClutterBrightnessContrastEffect is an opaque structure * whose members cannot be directly accessed * * Since: 1.10 */ typedef struct _ClutterBrightnessContrastEffect ClutterBrightnessContrastEffect; typedef struct _ClutterBrightnessContrastEffectClass ClutterBrightnessContrastEffectClass; CLUTTER_AVAILABLE_IN_1_10 GType clutter_brightness_contrast_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterEffect * clutter_brightness_contrast_effect_new (void); CLUTTER_AVAILABLE_IN_1_10 void clutter_brightness_contrast_effect_set_brightness_full (ClutterBrightnessContrastEffect *effect, float red, float green, float blue); CLUTTER_AVAILABLE_IN_1_10 void clutter_brightness_contrast_effect_set_brightness (ClutterBrightnessContrastEffect *effect, float brightness); CLUTTER_AVAILABLE_IN_1_10 void clutter_brightness_contrast_effect_get_brightness (ClutterBrightnessContrastEffect *effect, float *red, float *green, float *blue); CLUTTER_AVAILABLE_IN_1_10 void clutter_brightness_contrast_effect_set_contrast_full (ClutterBrightnessContrastEffect *effect, float red, float green, float blue); CLUTTER_AVAILABLE_IN_1_10 void clutter_brightness_contrast_effect_set_contrast (ClutterBrightnessContrastEffect *effect, float contrast); CLUTTER_AVAILABLE_IN_1_10 void clutter_brightness_contrast_effect_get_contrast (ClutterBrightnessContrastEffect *effect, float *red, float *green, float *blue); G_END_DECLS #endif /* __CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-flatten-effect.h�����������������������������������������������0000664�0001750�0001750�00000005471�14211404421�023027� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Authors: * Neil Roberts <neil@linux.intel.com> */ #ifndef __CLUTTER_FLATTEN_EFFECT_H__ #define __CLUTTER_FLATTEN_EFFECT_H__ #include <clutter/clutter-offscreen-effect.h> G_BEGIN_DECLS #define CLUTTER_TYPE_FLATTEN_EFFECT \ (_clutter_flatten_effect_get_type()) #define CLUTTER_FLATTEN_EFFECT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ CLUTTER_TYPE_FLATTEN_EFFECT, \ ClutterFlattenEffect)) #define CLUTTER_FLATTEN_EFFECT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ CLUTTER_TYPE_FLATTEN_EFFECT, \ ClutterFlattenEffectClass)) #define CLUTTER_IS_FLATTEN_EFFECT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ CLUTTER_TYPE_FLATTEN_EFFECT)) #define CLUTTER_IS_FLATTEN_EFFECT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ CLUTTER_TYPE_FLATTEN_EFFECT)) #define CLUTTER_FLATTEN_EFFECT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ CLUTTER_FLATTEN_EFFECT, \ ClutterFlattenEffectClass)) typedef struct _ClutterFlattenEffect ClutterFlattenEffect; typedef struct _ClutterFlattenEffectClass ClutterFlattenEffectClass; typedef struct _ClutterFlattenEffectPrivate ClutterFlattenEffectPrivate; struct _ClutterFlattenEffectClass { ClutterOffscreenEffectClass parent_class; }; struct _ClutterFlattenEffect { ClutterOffscreenEffect parent; }; GType _clutter_flatten_effect_get_type (void) G_GNUC_CONST; ClutterEffect *_clutter_flatten_effect_new (void); G_END_DECLS #endif /* __CLUTTER_FLATTEN_EFFECT_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-scriptable.h���������������������������������������������������0000664�0001750�0001750�00000011245�14211404421�022264� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * Emmanuele Bassi <ebassi@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_SCRIPTABLE_H__ #define __CLUTTER_SCRIPTABLE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <glib-object.h> #include <json-glib/json-glib.h> #include <clutter/clutter-script.h> G_BEGIN_DECLS #define CLUTTER_TYPE_SCRIPTABLE (clutter_scriptable_get_type ()) #define CLUTTER_SCRIPTABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SCRIPTABLE, ClutterScriptable)) #define CLUTTER_IS_SCRIPTABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SCRIPTABLE)) #define CLUTTER_SCRIPTABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_SCRIPTABLE, ClutterScriptableIface)) typedef struct _ClutterScriptable ClutterScriptable; typedef struct _ClutterScriptableIface ClutterScriptableIface; /** * ClutterScriptable: * * #ClutterScriptable is an opaque structure whose members cannot be directly * accessed * * Since: 0.6 */ /** * ClutterScriptableIface: * @set_id: virtual function for setting the id of a scriptable object * @get_id: virtual function for getting the id of a scriptable object * @parse_custom_node: virtual function for parsing complex data containers * into GObject properties * @set_custom_property: virtual function for setting a custom property * * Interface for implementing "scriptable" objects. An object implementing * this interface can override the parsing and properties setting sequence * when loading a UI definition data with #ClutterScript * * Since: 0.6 */ struct _ClutterScriptableIface { /*< private >*/ GTypeInterface g_iface; /*< public >*/ void (* set_id) (ClutterScriptable *scriptable, const gchar *id_); const gchar *(* get_id) (ClutterScriptable *scriptable); gboolean (* parse_custom_node) (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node); void (* set_custom_property) (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_scriptable_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL void clutter_scriptable_set_id (ClutterScriptable *scriptable, const gchar *id_); CLUTTER_AVAILABLE_IN_ALL const gchar * clutter_scriptable_get_id (ClutterScriptable *scriptable); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_scriptable_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node); CLUTTER_AVAILABLE_IN_ALL void clutter_scriptable_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value); G_END_DECLS #endif /* __CLUTTER_SCRIPTABLE_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-rotate-action.c������������������������������������������������0000664�0001750�0001750�00000016513�14211404421�022703� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com> */ /** * SECTION:clutter-rotate-action * @Title: ClutterRotateAction * @Short_Description: Action to rotate an actor * * #ClutterRotateAction is a sub-class of #ClutterGestureAction that implements * the logic for recognizing rotate gestures using two touch points. * * Since: 1.12 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter-rotate-action.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-gesture-action-private.h" #include "clutter-marshal.h" #include "clutter-private.h" struct _ClutterRotateActionPrivate { gfloat initial_vector[2]; gdouble initial_vector_norm; gdouble initial_rotation; }; enum { ROTATE, LAST_SIGNAL }; static guint rotate_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterRotateAction, clutter_rotate_action, CLUTTER_TYPE_GESTURE_ACTION) static gboolean clutter_rotate_action_real_rotate (ClutterRotateAction *action, ClutterActor *actor, gdouble angle) { clutter_actor_set_rotation_angle (actor, CLUTTER_Z_AXIS, action->priv->initial_rotation + angle); return TRUE; } static gboolean clutter_rotate_action_gesture_begin (ClutterGestureAction *action, ClutterActor *actor) { ClutterRotateActionPrivate *priv = CLUTTER_ROTATE_ACTION (action)->priv; gfloat p1[2], p2[2]; /* capture initial vector */ clutter_gesture_action_get_motion_coords (action, 0, &p1[0], &p1[1]); clutter_gesture_action_get_motion_coords (action, 1, &p2[0], &p2[1]); priv->initial_vector[0] = p2[0] - p1[0]; priv->initial_vector[1] = p2[1] - p1[1]; priv->initial_vector_norm = sqrt (priv->initial_vector[0] * priv->initial_vector[0] + priv->initial_vector[1] * priv->initial_vector[1]); priv->initial_rotation = clutter_actor_get_rotation_angle (actor, CLUTTER_Z_AXIS); return TRUE; } static gboolean clutter_rotate_action_gesture_progress (ClutterGestureAction *action, ClutterActor *actor) { ClutterRotateActionPrivate *priv = CLUTTER_ROTATE_ACTION (action)->priv; gfloat p1[2], p2[2]; gfloat vector[2]; gboolean retval; /* capture current vector */ clutter_gesture_action_get_motion_coords (action, 0, &p1[0], &p1[1]); clutter_gesture_action_get_motion_coords (action, 1, &p2[0], &p2[1]); vector[0] = p2[0] - p1[0]; vector[1] = p2[1] - p1[1]; if ((vector[0] == priv->initial_vector[0]) && (vector[1] == priv->initial_vector[1])) { g_signal_emit (action, rotate_signals[ROTATE], 0, actor, (gdouble) 0.0, &retval); } else { gfloat mult[2]; gfloat norm; gdouble angle; /* Computes angle between the 2 initial touch points and the current position of the 2 touch points. */ norm = sqrt (vector[0] * vector[0] + vector[1] * vector[1]); norm = (priv->initial_vector[0] * vector[0] + priv->initial_vector[1] * vector[1]) / (priv->initial_vector_norm * norm); if ((norm >= -1.0) && (norm <= 1.0)) angle = acos (norm); else angle = 0; /* The angle given is comprise between 0 and 180 degrees, we need some logic on top to get a value between 0 and 360. */ mult[0] = priv->initial_vector[0] * vector[1] - priv->initial_vector[1] * vector[0]; mult[1] = priv->initial_vector[1] * vector[0] - priv->initial_vector[0] * vector[1]; if (mult[0] < 0) angle = -angle; /* Convert radians to degrees */ angle = angle * 180.0 / G_PI; g_signal_emit (action, rotate_signals[ROTATE], 0, actor, angle, &retval); } return TRUE; } static void clutter_rotate_action_gesture_cancel (ClutterGestureAction *action, ClutterActor *actor) { gboolean retval; g_signal_emit (action, rotate_signals[ROTATE], 0, actor, (gdouble) 0.0, &retval); } static void clutter_rotate_action_constructed (GObject *gobject) { ClutterGestureAction *gesture; gesture = CLUTTER_GESTURE_ACTION (gobject); clutter_gesture_action_set_threshold_trigger_edge (gesture, CLUTTER_GESTURE_TRIGGER_EDGE_NONE); } static void clutter_rotate_action_class_init (ClutterRotateActionClass *klass) { ClutterGestureActionClass *gesture_class = CLUTTER_GESTURE_ACTION_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); klass->rotate = clutter_rotate_action_real_rotate; object_class->constructed = clutter_rotate_action_constructed; gesture_class->gesture_begin = clutter_rotate_action_gesture_begin; gesture_class->gesture_progress = clutter_rotate_action_gesture_progress; gesture_class->gesture_cancel = clutter_rotate_action_gesture_cancel; /** * ClutterRotateAction::rotate: * @action: the #ClutterRotateAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @angle: the difference of angle of rotation between the initial * rotation and the current rotation * * The ::rotate signal is emitted when a rotate gesture is * recognized on the attached actor and when the gesture is * cancelled (in this case with an angle value of 0). * * Return value: %TRUE if the rotation should continue, and %FALSE if * the rotation should be cancelled. * * Since: 1.12 */ rotate_signals[ROTATE] = g_signal_new (I_("rotate"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterRotateActionClass, rotate), _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT_DOUBLE, G_TYPE_BOOLEAN, 2, CLUTTER_TYPE_ACTOR, G_TYPE_DOUBLE); } static void clutter_rotate_action_init (ClutterRotateAction *self) { ClutterGestureAction *gesture; self->priv = clutter_rotate_action_get_instance_private (self); gesture = CLUTTER_GESTURE_ACTION (self); clutter_gesture_action_set_n_touch_points (gesture, 2); } /** * clutter_rotate_action_new: * * Creates a new #ClutterRotateAction instance * * Return value: the newly created #ClutterRotateAction * * Since: 1.12 */ ClutterAction * clutter_rotate_action_new (void) { return g_object_new (CLUTTER_TYPE_ROTATE_ACTION, NULL); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-colorize-effect.h����������������������������������������������0000664�0001750�0001750�00000004503�14211404421�023213� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_COLORIZE_EFFECT_H__ #define __CLUTTER_COLORIZE_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-color.h> #include <clutter/clutter-effect.h> G_BEGIN_DECLS #define CLUTTER_TYPE_COLORIZE_EFFECT (clutter_colorize_effect_get_type ()) #define CLUTTER_COLORIZE_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_COLORIZE_EFFECT, ClutterColorizeEffect)) #define CLUTTER_IS_COLORIZE_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_COLORIZE_EFFECT)) /** * ClutterColorizeEffect: * * #ClutterColorizeEffect is an opaque structure * whose members cannot be directly accessed * * Since: 1.4 */ typedef struct _ClutterColorizeEffect ClutterColorizeEffect; typedef struct _ClutterColorizeEffectClass ClutterColorizeEffectClass; CLUTTER_AVAILABLE_IN_1_4 GType clutter_colorize_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterEffect *clutter_colorize_effect_new (const ClutterColor *tint); CLUTTER_AVAILABLE_IN_1_4 void clutter_colorize_effect_set_tint (ClutterColorizeEffect *effect, const ClutterColor *tint); CLUTTER_AVAILABLE_IN_1_4 void clutter_colorize_effect_get_tint (ClutterColorizeEffect *effect, ClutterColor *tint); G_END_DECLS #endif /* __CLUTTER_COLORIZE_EFFECT_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-stage-window.c�������������������������������������������������0000664�0001750�0001750�00000022135�14211404421�022537� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <glib-object.h> #include "clutter-actor.h" #include "clutter-stage-window.h" #include "clutter-private.h" #define clutter_stage_window_get_type _clutter_stage_window_get_type typedef ClutterStageWindowIface ClutterStageWindowInterface; G_DEFINE_INTERFACE (ClutterStageWindow, clutter_stage_window, G_TYPE_OBJECT); static void clutter_stage_window_default_init (ClutterStageWindowInterface *iface) { GParamSpec *pspec; pspec = g_param_spec_object ("backend", "Backend", "Back pointer to the Backend instance", CLUTTER_TYPE_BACKEND, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (iface, pspec); pspec = g_param_spec_object ("wrapper", "Wrapper", "Back pointer to the Stage actor", CLUTTER_TYPE_STAGE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (iface, pspec); } ClutterActor * _clutter_stage_window_get_wrapper (ClutterStageWindow *window) { return CLUTTER_STAGE_WINDOW_GET_IFACE (window)->get_wrapper (window); } void _clutter_stage_window_set_title (ClutterStageWindow *window, const gchar *title) { ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->set_title) iface->set_title (window, title); } void _clutter_stage_window_set_fullscreen (ClutterStageWindow *window, gboolean is_fullscreen) { ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->set_fullscreen) iface->set_fullscreen (window, is_fullscreen); } void _clutter_stage_window_set_cursor_visible (ClutterStageWindow *window, gboolean is_visible) { ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->set_cursor_visible) iface->set_cursor_visible (window, is_visible); } void _clutter_stage_window_set_user_resizable (ClutterStageWindow *window, gboolean is_resizable) { CLUTTER_STAGE_WINDOW_GET_IFACE (window)->set_user_resizable (window, is_resizable); } gboolean _clutter_stage_window_realize (ClutterStageWindow *window) { return CLUTTER_STAGE_WINDOW_GET_IFACE (window)->realize (window); } void _clutter_stage_window_unrealize (ClutterStageWindow *window) { CLUTTER_STAGE_WINDOW_GET_IFACE (window)->unrealize (window); } void _clutter_stage_window_show (ClutterStageWindow *window, gboolean do_raise) { CLUTTER_STAGE_WINDOW_GET_IFACE (window)->show (window, do_raise); } void _clutter_stage_window_hide (ClutterStageWindow *window) { CLUTTER_STAGE_WINDOW_GET_IFACE (window)->hide (window); } void _clutter_stage_window_resize (ClutterStageWindow *window, gint width, gint height) { CLUTTER_STAGE_WINDOW_GET_IFACE (window)->resize (window, width, height); } void _clutter_stage_window_get_geometry (ClutterStageWindow *window, cairo_rectangle_int_t *geometry) { CLUTTER_STAGE_WINDOW_GET_IFACE (window)->get_geometry (window, geometry); } void _clutter_stage_window_schedule_update (ClutterStageWindow *window, int sync_delay) { ClutterStageWindowIface *iface; g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->schedule_update == NULL) { g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)); return; } iface->schedule_update (window, sync_delay); } gint64 _clutter_stage_window_get_update_time (ClutterStageWindow *window) { ClutterStageWindowIface *iface; g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), 0); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->get_update_time == NULL) { g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)); return 0; } return iface->get_update_time (window); } void _clutter_stage_window_clear_update_time (ClutterStageWindow *window) { ClutterStageWindowIface *iface; g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->clear_update_time == NULL) { g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)); return; } iface->clear_update_time (window); } void _clutter_stage_window_add_redraw_clip (ClutterStageWindow *window, cairo_rectangle_int_t *stage_clip) { ClutterStageWindowIface *iface; g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->add_redraw_clip != NULL) iface->add_redraw_clip (window, stage_clip); } /* Determines if the backend will clip the rendering of the next * frame. * * Note: at the start of each new frame there is an implied clip that * clips everything (i.e. nothing would be drawn) so this function * will return True at the start of a new frame if the backend * supports clipped redraws. */ gboolean _clutter_stage_window_has_redraw_clips (ClutterStageWindow *window) { ClutterStageWindowIface *iface; g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->has_redraw_clips != NULL) return iface->has_redraw_clips (window); return FALSE; } /* Determines if the backend will discard any additional redraw clips * and instead promote them to a full stage redraw. * * The ideas is that backend may have some heuristics that cause it to * give up tracking redraw clips so this can be used to avoid the cost * of calculating a redraw clip when we know it's going to be ignored * anyway. */ gboolean _clutter_stage_window_ignoring_redraw_clips (ClutterStageWindow *window) { ClutterStageWindowIface *iface; g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->ignoring_redraw_clips != NULL) return iface->ignoring_redraw_clips (window); return TRUE; } gboolean _clutter_stage_window_get_redraw_clip_bounds (ClutterStageWindow *window, cairo_rectangle_int_t *stage_clip) { ClutterStageWindowIface *iface; g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->get_redraw_clip_bounds != NULL) return iface->get_redraw_clip_bounds (window, stage_clip); return FALSE; } void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window, gboolean accept_focus) { ClutterStageWindowIface *iface; g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->set_accept_focus) iface->set_accept_focus (window, accept_focus); } void _clutter_stage_window_redraw (ClutterStageWindow *window) { ClutterStageWindowIface *iface; g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->redraw) iface->redraw (window); } void _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window, ClutterStageView *view, int *x, int *y) { ClutterStageWindowIface *iface; *x = 0; *y = 0; g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->get_dirty_pixel) iface->get_dirty_pixel (window, view, x, y); } gboolean _clutter_stage_window_can_clip_redraws (ClutterStageWindow *window) { ClutterStageWindowIface *iface; g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), FALSE); iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->can_clip_redraws != NULL) return iface->can_clip_redraws (window); return FALSE; } GList * _clutter_stage_window_get_views (ClutterStageWindow *window) { ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); return iface->get_views (window); } void _clutter_stage_window_finish_frame (ClutterStageWindow *window) { ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->finish_frame) iface->finish_frame (window); } int64_t _clutter_stage_window_get_frame_counter (ClutterStageWindow *window) { ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window); if (iface->get_frame_counter) return iface->get_frame_counter (window); else return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-paint-node.c���������������������������������������������������0000664�0001750�0001750�00000070310�14211404421�022163� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-paint-node * @Title: ClutterPaintNode * @Short_Description: Paint objects * * #ClutterPaintNode is an element in the render graph. * * The render graph contains all the elements that need to be painted by * Clutter when submitting a frame to the graphics system. * * The render graph is distinct from the scene graph: the scene graph is * composed by actors, which can be visible or invisible; the scene graph * elements also respond to events. The render graph, instead, is only * composed by nodes that will be painted. * * Each #ClutterActor can submit multiple #ClutterPaintNode<!-- -->s to * the render graph. */ /** * ClutterPaintNode: (ref-func clutter_paint_node_ref) (unref-func clutter_paint_node_unref) (set-value-func clutter_value_set_paint_node) (get-value-func clutter_value_get_paint_node) * * The `ClutterPaintNode` structure contains only private data * and it should be accessed using the provided API. * * Since: 1.10 */ /** * ClutterPaintNodeClass: * * The `ClutterPaintNodeClass` structure contains only private data. * * Since: 1.10 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include <pango/pango.h> #include <cogl/cogl.h> #include <json-glib/json-glib.h> #include "clutter-paint-node-private.h" #include "clutter-debug.h" #include "clutter-private.h" #include <gobject/gvaluecollector.h> static inline void clutter_paint_operation_clear (ClutterPaintOperation *op); static void value_paint_node_init (GValue *value) { value->data[0].v_pointer = NULL; } static void value_paint_node_free_value (GValue *value) { if (value->data[0].v_pointer != NULL) clutter_paint_node_unref (value->data[0].v_pointer); } static void value_paint_node_copy_value (const GValue *src, GValue *dst) { if (src->data[0].v_pointer != NULL) dst->data[0].v_pointer = clutter_paint_node_ref (src->data[0].v_pointer); else dst->data[0].v_pointer = NULL; } static gpointer value_paint_node_peek_pointer (const GValue *value) { return value->data[0].v_pointer; } static gchar * value_paint_node_collect_value (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { ClutterPaintNode *node; node = collect_values[0].v_pointer; if (node == NULL) { value->data[0].v_pointer = NULL; return NULL; } if (node->parent_instance.g_class == NULL) return g_strconcat ("invalid unclassed ClutterPaintNode pointer for " "value type '", G_VALUE_TYPE_NAME (value), "'", NULL); value->data[0].v_pointer = clutter_paint_node_ref (node); return NULL; } static gchar * value_paint_node_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { ClutterPaintNode **node_p = collect_values[0].v_pointer; if (node_p == NULL) return g_strconcat ("value location for '", G_VALUE_TYPE_NAME (value), "' passed as NULL", NULL); if (value->data[0].v_pointer == NULL) *node_p = NULL; else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) *node_p = value->data[0].v_pointer; else *node_p = clutter_paint_node_ref (value->data[0].v_pointer); return NULL; } static void clutter_paint_node_class_base_init (ClutterPaintNodeClass *klass) { } static void clutter_paint_node_class_base_finalize (ClutterPaintNodeClass *klass) { } static void clutter_paint_node_real_finalize (ClutterPaintNode *node) { ClutterPaintNode *iter; free (node->name); if (node->operations != NULL) { guint i; for (i = 0; i < node->operations->len; i++) { ClutterPaintOperation *op; op = &g_array_index (node->operations, ClutterPaintOperation, i); clutter_paint_operation_clear (op); } g_array_unref (node->operations); } iter = node->first_child; while (iter != NULL) { ClutterPaintNode *next = iter->next_sibling; clutter_paint_node_remove_child (node, iter); iter = next; } g_type_free_instance ((GTypeInstance *) node); } static gboolean clutter_paint_node_real_pre_draw (ClutterPaintNode *node) { return FALSE; } static void clutter_paint_node_real_draw (ClutterPaintNode *node) { } static void clutter_paint_node_real_post_draw (ClutterPaintNode *node) { } static void clutter_paint_node_class_init (ClutterPaintNodeClass *klass) { klass->pre_draw = clutter_paint_node_real_pre_draw; klass->draw = clutter_paint_node_real_draw; klass->post_draw = clutter_paint_node_real_post_draw; klass->finalize = clutter_paint_node_real_finalize; } static void clutter_paint_node_init (ClutterPaintNode *self) { self->ref_count = 1; } GType clutter_paint_node_get_type (void) { static volatile gsize paint_node_type_id__volatile = 0; if (g_once_init_enter (&paint_node_type_id__volatile)) { static const GTypeFundamentalInfo finfo = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE), }; static const GTypeValueTable value_table = { value_paint_node_init, value_paint_node_free_value, value_paint_node_copy_value, value_paint_node_peek_pointer, "p", value_paint_node_collect_value, "p", value_paint_node_lcopy_value, }; const GTypeInfo node_info = { sizeof (ClutterPaintNodeClass), (GBaseInitFunc) clutter_paint_node_class_base_init, (GBaseFinalizeFunc) clutter_paint_node_class_base_finalize, (GClassInitFunc) clutter_paint_node_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (ClutterPaintNode), 0, (GInstanceInitFunc) clutter_paint_node_init, &value_table, }; GType paint_node_type_id = g_type_register_fundamental (g_type_fundamental_next (), I_("ClutterPaintNode"), &node_info, &finfo, G_TYPE_FLAG_ABSTRACT); g_once_init_leave (&paint_node_type_id__volatile, paint_node_type_id); } return paint_node_type_id__volatile; } /** * clutter_paint_node_set_name: * @node: a #ClutterPaintNode * @name: a string annotating the @node * * Sets a user-readable @name for @node. * * The @name will be used for debugging purposes. * * The @node will copy the passed string. * * Since: 1.10 */ void clutter_paint_node_set_name (ClutterPaintNode *node, const char *name) { g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); free (node->name); node->name = g_strdup (name); } /** * clutter_paint_node_ref: * @node: a #ClutterPaintNode * * Acquires a reference on @node. * * Return value: (transfer full): the #ClutterPaintNode * * Since: 1.10 */ ClutterPaintNode * clutter_paint_node_ref (ClutterPaintNode *node) { g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); g_atomic_int_inc (&node->ref_count); return node; } /** * clutter_paint_node_unref: * @node: a #ClutterPaintNode * * Releases a reference on @node. * * Since: 1.10 */ void clutter_paint_node_unref (ClutterPaintNode *node) { g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); if (g_atomic_int_dec_and_test (&node->ref_count)) { ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node); klass->finalize (node); } } /** * clutter_paint_node_add_child: * @node: a #ClutterPaintNode * @child: the child #ClutterPaintNode to add * * Adds @child to the list of children of @node. * * This function will acquire a reference on @child. * * Since: 1.10 */ void clutter_paint_node_add_child (ClutterPaintNode *node, ClutterPaintNode *child) { g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); g_return_if_fail (CLUTTER_IS_PAINT_NODE (child)); g_return_if_fail (node != child); g_return_if_fail (child->parent == NULL); child->parent = node; clutter_paint_node_ref (child); node->n_children += 1; child->prev_sibling = node->last_child; if (node->last_child != NULL) { ClutterPaintNode *tmp = node->last_child; tmp->next_sibling = child; } if (child->prev_sibling == NULL) node->first_child = child; if (child->next_sibling == NULL) node->last_child = child; } /** * clutter_paint_node_remove_child: * @node: a #ClutterPaintNode * @child: the #ClutterPaintNode to remove * * Removes @child from the list of children of @node. * * This function will release the reference on @child acquired by * using clutter_paint_node_add_child(). * * Since: 1.10 */ void clutter_paint_node_remove_child (ClutterPaintNode *node, ClutterPaintNode *child) { ClutterPaintNode *prev, *next; g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); g_return_if_fail (CLUTTER_IS_PAINT_NODE (child)); g_return_if_fail (node != child); g_return_if_fail (child->parent == node); node->n_children -= 1; prev = child->prev_sibling; next = child->next_sibling; if (prev != NULL) prev->next_sibling = next; if (next != NULL) next->prev_sibling = prev; if (node->first_child == child) node->first_child = next; if (node->last_child == child) node->last_child = prev; child->prev_sibling = NULL; child->next_sibling = NULL; child->parent = NULL; clutter_paint_node_unref (child); } /** * clutter_paint_node_replace_child: * @node: a #ClutterPaintNode * @old_child: the child replaced by @new_child * @new_child: the child that replaces @old_child * * Atomically replaces @old_child with @new_child in the list of * children of @node. * * This function will release the reference on @old_child acquired * by @node, and will acquire a new reference on @new_child. * * Since: 1.10 */ void clutter_paint_node_replace_child (ClutterPaintNode *node, ClutterPaintNode *old_child, ClutterPaintNode *new_child) { ClutterPaintNode *prev, *next; g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); g_return_if_fail (CLUTTER_IS_PAINT_NODE (old_child)); g_return_if_fail (old_child->parent == node); g_return_if_fail (CLUTTER_IS_PAINT_NODE (new_child)); g_return_if_fail (new_child->parent == NULL); prev = old_child->prev_sibling; next = old_child->next_sibling; new_child->parent = node; new_child->prev_sibling = prev; new_child->next_sibling = next; clutter_paint_node_ref (new_child); if (prev != NULL) prev->next_sibling = new_child; if (next != NULL) next->prev_sibling = new_child; if (node->first_child == old_child) node->first_child = new_child; if (node->last_child == old_child) node->last_child = new_child; old_child->prev_sibling = NULL; old_child->next_sibling = NULL; old_child->parent = NULL; clutter_paint_node_unref (old_child); } /** * clutter_paint_node_remove_all: * @node: a #ClutterPaintNode * * Removes all children of @node. * * This function releases the reference acquired by @node on its * children. * * Since: 1.10 */ void clutter_paint_node_remove_all (ClutterPaintNode *node) { ClutterPaintNode *iter; g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); iter = node->first_child; while (iter != NULL) { ClutterPaintNode *next = iter->next_sibling; clutter_paint_node_remove_child (node, iter); iter = next; } } /** * clutter_paint_node_get_first_child: * @node: a #ClutterPaintNode * * Retrieves the first child of the @node. * * Return value: (transfer none): a pointer to the first child of * the #ClutterPaintNode. * * Since: 1.10 */ ClutterPaintNode * clutter_paint_node_get_first_child (ClutterPaintNode *node) { g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); return node->first_child; } /** * clutter_paint_node_get_previous_sibling: * @node: a #ClutterPaintNode * * Retrieves the previous sibling of @node. * * Return value: (transfer none): a pointer to the previous sibling * of the #ClutterPaintNode. * * Since: 1.10 */ ClutterPaintNode * clutter_paint_node_get_previous_sibling (ClutterPaintNode *node) { g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); return node->prev_sibling; } /** * clutter_paint_node_get_next_sibling: * @node: a #ClutterPaintNode * * Retrieves the next sibling of @node. * * Return value: (transfer none): a pointer to the next sibling * of a #ClutterPaintNode * * Since: 1.10 */ ClutterPaintNode * clutter_paint_node_get_next_sibling (ClutterPaintNode *node) { g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); return node->next_sibling; } /** * clutter_paint_node_get_last_child: * @node: a #ClutterPaintNode * * Retrieves the last child of @node. * * Return value: (transfer none): a pointer to the last child * of a #ClutterPaintNode * * Since: 1.10 */ ClutterPaintNode * clutter_paint_node_get_last_child (ClutterPaintNode *node) { g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); return node->last_child; } /** * clutter_paint_node_get_parent: * @node: a #ClutterPaintNode * * Retrieves the parent of @node. * * Return value: (transfer none): a pointer to the parent of * a #ClutterPaintNode * * Since: 1.10 */ ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node) { g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), NULL); return node->parent; } /** * clutter_paint_node_get_n_children: * @node: a #ClutterPaintNode * * Retrieves the number of children of @node. * * Return value: the number of children of a #ClutterPaintNode * * Since: 1.10 */ guint clutter_paint_node_get_n_children (ClutterPaintNode *node) { g_return_val_if_fail (CLUTTER_IS_PAINT_NODE (node), 0); return node->n_children; } /** * clutter_value_set_paint_node: * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE * @node: (type Clutter.PaintNode) (allow-none): a #ClutterPaintNode, or %NULL * * Sets the contents of a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE. * * This function increased the reference count of @node; if you do not wish * to increase the reference count, use clutter_value_take_paint_node() * instead. The reference count will be released by g_value_unset(). * * Since: 1.10 */ void clutter_value_set_paint_node (GValue *value, gpointer node) { ClutterPaintNode *old_node; g_return_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value)); old_node = value->data[0].v_pointer; if (node != NULL) { g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); value->data[0].v_pointer = clutter_paint_node_ref (node); } else value->data[0].v_pointer = NULL; if (old_node != NULL) clutter_paint_node_unref (old_node); } /** * clutter_value_take_paint_node: * @value: a #GValue, initialized with %CLUTTER_TYPE_PAINT_NODE * @node: (type Clutter.PaintNode) (allow-none): a #ClutterPaintNode, or %NULL * * Sets the contents of a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE. * * Unlike clutter_value_set_paint_node(), this function will not take a * reference on the passed @node: instead, it will take ownership of the * current reference count. * * Since: 1.10 */ void clutter_value_take_paint_node (GValue *value, gpointer node) { ClutterPaintNode *old_node; g_return_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value)); old_node = value->data[0].v_pointer; if (node != NULL) { g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); /* take over ownership */ value->data[0].v_pointer = node; } else value->data[0].v_pointer = NULL; if (old_node != NULL) clutter_paint_node_unref (old_node); } /** * clutter_value_get_paint_node: * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE * * Retrieves a pointer to the #ClutterPaintNode contained inside * the passed #GValue. * * Return value: (transfer none) (type Clutter.PaintNode): a pointer to * a #ClutterPaintNode, or %NULL * * Since: 1.10 */ gpointer clutter_value_get_paint_node (const GValue *value) { g_return_val_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value), NULL); return value->data[0].v_pointer; } /** * clutter_value_dup_paint_node: * @value: a #GValue initialized with %CLUTTER_TYPE_PAINT_NODE * * Retrieves a pointer to the #ClutterPaintNode contained inside * the passed #GValue, and if not %NULL it will increase the * reference count. * * Return value: (transfer full) (type Clutter.PaintNode): a pointer * to the #ClutterPaintNode, with its reference count increased, * or %NULL * * Since: 1.10 */ gpointer clutter_value_dup_paint_node (const GValue *value) { g_return_val_if_fail (CLUTTER_VALUE_HOLDS_PAINT_NODE (value), NULL); if (value->data[0].v_pointer != NULL) return clutter_paint_node_ref (value->data[0].v_pointer); return NULL; } static inline void clutter_paint_operation_clear (ClutterPaintOperation *op) { switch (op->opcode) { case PAINT_OP_INVALID: break; case PAINT_OP_TEX_RECT: break; case PAINT_OP_PATH: if (op->op.path != NULL) cogl_object_unref (op->op.path); break; case PAINT_OP_PRIMITIVE: if (op->op.primitive != NULL) cogl_object_unref (op->op.primitive); break; } } static inline void clutter_paint_op_init_tex_rect (ClutterPaintOperation *op, const ClutterActorBox *rect, float x_1, float y_1, float x_2, float y_2) { clutter_paint_operation_clear (op); op->opcode = PAINT_OP_TEX_RECT; op->op.texrect[0] = rect->x1; op->op.texrect[1] = rect->y1; op->op.texrect[2] = rect->x2; op->op.texrect[3] = rect->y2; op->op.texrect[4] = x_1; op->op.texrect[5] = y_1; op->op.texrect[6] = x_2; op->op.texrect[7] = y_2; } static inline void clutter_paint_op_init_path (ClutterPaintOperation *op, CoglPath *path) { clutter_paint_operation_clear (op); op->opcode = PAINT_OP_PATH; op->op.path = cogl_object_ref (path); } static inline void clutter_paint_op_init_primitive (ClutterPaintOperation *op, CoglPrimitive *primitive) { clutter_paint_operation_clear (op); op->opcode = PAINT_OP_PRIMITIVE; op->op.primitive = cogl_object_ref (primitive); } static inline void clutter_paint_node_maybe_init_operations (ClutterPaintNode *node) { if (node->operations != NULL) return; node->operations = g_array_new (FALSE, FALSE, sizeof (ClutterPaintOperation)); } /** * clutter_paint_node_add_rectangle: * @node: a #ClutterPaintNode * @rect: a #ClutterActorBox * * Adds a rectangle region to the @node, as described by the * passed @rect. * * Since: 1.10 */ void clutter_paint_node_add_rectangle (ClutterPaintNode *node, const ClutterActorBox *rect) { ClutterPaintOperation operation = PAINT_OP_INIT; g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); g_return_if_fail (rect != NULL); clutter_paint_node_maybe_init_operations (node); clutter_paint_op_init_tex_rect (&operation, rect, 0.0, 0.0, 1.0, 1.0); g_array_append_val (node->operations, operation); } /** * clutter_paint_node_add_texture_rectangle: * @node: a #ClutterPaintNode * @rect: a #ClutterActorBox * @x_1: the left X coordinate of the texture * @y_1: the top Y coordinate of the texture * @x_2: the right X coordinate of the texture * @y_2: the bottom Y coordinate of the texture * * Adds a rectangle region to the @node, with texture coordinates. * * Since: 1.10 */ void clutter_paint_node_add_texture_rectangle (ClutterPaintNode *node, const ClutterActorBox *rect, float x_1, float y_1, float x_2, float y_2) { ClutterPaintOperation operation = PAINT_OP_INIT; g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); g_return_if_fail (rect != NULL); clutter_paint_node_maybe_init_operations (node); clutter_paint_op_init_tex_rect (&operation, rect, x_1, y_1, x_2, y_2); g_array_append_val (node->operations, operation); } /** * clutter_paint_node_add_path: (skip) * @node: a #ClutterPaintNode * @path: a Cogl path * * Adds a region described as a path to the @node. * * This function acquires a reference on the passed @path, so it * is safe to call cogl_object_unref() when it returns. * * Since: 1.10 * Stability: unstable */ void clutter_paint_node_add_path (ClutterPaintNode *node, CoglPath *path) { ClutterPaintOperation operation = PAINT_OP_INIT; g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); g_return_if_fail (cogl_is_path (path)); clutter_paint_node_maybe_init_operations (node); clutter_paint_op_init_path (&operation, path); g_array_append_val (node->operations, operation); } /** * clutter_paint_node_add_primitive: (skip) * @node: a #ClutterPaintNode * @primitive: a Cogl primitive * * Adds a region described by a Cogl primitive to the @node. * * This function acquires a reference on @primitive, so it is safe * to call cogl_object_unref() when it returns. * * Since: 1.10 */ void clutter_paint_node_add_primitive (ClutterPaintNode *node, CoglPrimitive *primitive) { ClutterPaintOperation operation = PAINT_OP_INIT; g_return_if_fail (CLUTTER_IS_PAINT_NODE (node)); g_return_if_fail (cogl_is_primitive (primitive)); clutter_paint_node_maybe_init_operations (node); clutter_paint_op_init_primitive (&operation, primitive); g_array_append_val (node->operations, operation); } /*< private > * _clutter_paint_node_paint: * @node: a #ClutterPaintNode * * Paints the @node using the class implementation, traversing * its children, if any. */ void _clutter_paint_node_paint (ClutterPaintNode *node) { ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node); ClutterPaintNode *iter; gboolean res; res = klass->pre_draw (node); if (res) { klass->draw (node); } for (iter = node->first_child; iter != NULL; iter = iter->next_sibling) { _clutter_paint_node_paint (iter); } if (res) { klass->post_draw (node); } } #ifdef CLUTTER_ENABLE_DEBUG static JsonNode * clutter_paint_node_serialize (ClutterPaintNode *node) { ClutterPaintNodeClass *klass = CLUTTER_PAINT_NODE_GET_CLASS (node); if (klass->serialize != NULL) return klass->serialize (node); return json_node_new (JSON_NODE_NULL); } static JsonNode * clutter_paint_node_to_json (ClutterPaintNode *node) { JsonBuilder *builder; JsonNode *res; builder = json_builder_new (); json_builder_begin_object (builder); json_builder_set_member_name (builder, "type"); json_builder_add_string_value (builder, g_type_name (G_TYPE_FROM_INSTANCE (node))); json_builder_set_member_name (builder, "name"); json_builder_add_string_value (builder, node->name); json_builder_set_member_name (builder, "node-data"); json_builder_add_value (builder, clutter_paint_node_serialize (node)); json_builder_set_member_name (builder, "operations"); json_builder_begin_array (builder); if (node->operations != NULL) { guint i; for (i = 0; i < node->operations->len; i++) { const ClutterPaintOperation *op; op = &g_array_index (node->operations, ClutterPaintOperation, i); json_builder_begin_object (builder); switch (op->opcode) { case PAINT_OP_TEX_RECT: json_builder_set_member_name (builder, "texrect"); json_builder_begin_array (builder); json_builder_add_double_value (builder, op->op.texrect[0]); json_builder_add_double_value (builder, op->op.texrect[1]); json_builder_add_double_value (builder, op->op.texrect[2]); json_builder_add_double_value (builder, op->op.texrect[3]); json_builder_add_double_value (builder, op->op.texrect[4]); json_builder_add_double_value (builder, op->op.texrect[5]); json_builder_add_double_value (builder, op->op.texrect[6]); json_builder_add_double_value (builder, op->op.texrect[7]); json_builder_end_array (builder); break; case PAINT_OP_PATH: json_builder_set_member_name (builder, "path"); json_builder_add_int_value (builder, (gint64) op->op.path); break; case PAINT_OP_PRIMITIVE: json_builder_set_member_name (builder, "primitive"); json_builder_add_int_value (builder, (gint64) op->op.primitive); break; case PAINT_OP_INVALID: break; } json_builder_end_object (builder); } } json_builder_end_array (builder); json_builder_set_member_name (builder, "children"); json_builder_begin_array (builder); if (node->first_child != NULL) { ClutterPaintNode *child; for (child = node->first_child; child != NULL; child = child->next_sibling) { JsonNode *n = clutter_paint_node_to_json (child); json_builder_add_value (builder, n); } } json_builder_end_array (builder); json_builder_end_object (builder); res = json_builder_get_root (builder); g_object_unref (builder); return res; } #endif /* CLUTTER_ENABLE_DEBUG */ void _clutter_paint_node_dump_tree (ClutterPaintNode *node) { #ifdef CLUTTER_ENABLE_DEBUG JsonGenerator *gen = json_generator_new (); char *str; gsize len; json_generator_set_root (gen, clutter_paint_node_to_json (node)); str = json_generator_to_data (gen, &len); g_print ("Render tree starting from %p:\n%s\n", node, str); free (str); #endif /* CLUTTER_ENABLE_DEBUG */ } /*< private > * _clutter_paint_node_create: * @gtype: a #ClutterPaintNode type * * Creates a new #ClutterPaintNode instance using @gtype * * Return value: (transfer full): the newly created #ClutterPaintNode * sub-class instance; use clutter_paint_node_unref() when done */ gpointer _clutter_paint_node_create (GType gtype) { g_return_val_if_fail (g_type_is_a (gtype, CLUTTER_TYPE_PAINT_NODE), NULL); _clutter_paint_node_init_types (); return (gpointer) g_type_create_instance (gtype); } static ClutterPaintNode * clutter_paint_node_get_root (ClutterPaintNode *node) { ClutterPaintNode *iter; iter = node; while (iter != NULL && iter->parent != NULL) iter = iter->parent; return iter; } CoglFramebuffer * clutter_paint_node_get_framebuffer (ClutterPaintNode *node) { ClutterPaintNode *root = clutter_paint_node_get_root (node); ClutterPaintNodeClass *klass; if (root == NULL) return NULL; klass = CLUTTER_PAINT_NODE_GET_CLASS (root); if (klass->get_framebuffer != NULL) return klass->get_framebuffer (root); return cogl_get_draw_framebuffer (); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-input-device.c�������������������������������������������������0000664�0001750�0001750�00000200667�14211404421�022533� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-input-device * @short_description: An input device managed by Clutter * * #ClutterInputDevice represents an input device known to Clutter. * * The #ClutterInputDevice class holds the state of the device, but * its contents are usually defined by the Clutter backend in use. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-input-device.h" #include "clutter-actor-private.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-enum-types.h" #include "clutter-event-private.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-input-device-tool.h" #include <math.h> enum { PROP_0, PROP_BACKEND, PROP_ID, PROP_NAME, PROP_DEVICE_TYPE, PROP_DEVICE_MANAGER, PROP_DEVICE_MODE, PROP_HAS_CURSOR, PROP_ENABLED, PROP_N_AXES, PROP_VENDOR_ID, PROP_PRODUCT_ID, PROP_N_STRIPS, PROP_N_RINGS, PROP_N_MODE_GROUPS, PROP_DEVICE_NODE, PROP_MAPPING_MODE, PROP_LAST }; static void _clutter_input_device_free_touch_info (gpointer data); static void on_cursor_actor_destroy (ClutterActor *actor, ClutterInputDevice *device); static void on_cursor_actor_reactive_changed (ClutterActor *actor, GParamSpec *pspec, ClutterInputDevice *device); static GParamSpec *obj_props[PROP_LAST] = { NULL, }; G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT); static void clutter_input_device_dispose (GObject *gobject) { ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject); g_clear_pointer (&device->device_name, free); g_clear_pointer (&device->vendor_id, free); g_clear_pointer (&device->product_id, free); if (device->associated != NULL) { if (device->device_mode == CLUTTER_INPUT_MODE_SLAVE) _clutter_input_device_remove_slave (device->associated, device); _clutter_input_device_set_associated_device (device->associated, NULL); g_object_unref (device->associated); device->associated = NULL; } g_clear_pointer (&device->axes, g_array_unref); g_clear_pointer (&device->keys, g_array_unref); g_clear_pointer (&device->scroll_info, g_array_unref); g_clear_pointer (&device->touch_sequences_info, g_hash_table_unref); if (device->cursor_actor) { g_signal_handlers_disconnect_by_func (device->cursor_actor, G_CALLBACK (on_cursor_actor_destroy), device); g_signal_handlers_disconnect_by_func (device->cursor_actor, G_CALLBACK (on_cursor_actor_reactive_changed), device); _clutter_actor_set_has_pointer (device->cursor_actor, FALSE); device->cursor_actor = NULL; } if (device->inv_touch_sequence_actors) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, device->inv_touch_sequence_actors); while (g_hash_table_iter_next (&iter, &key, &value)) { g_signal_handlers_disconnect_by_func (key, G_CALLBACK (on_cursor_actor_destroy), device); g_signal_handlers_disconnect_by_func (device->cursor_actor, G_CALLBACK (on_cursor_actor_reactive_changed), device); _clutter_actor_set_has_pointer (key, FALSE); g_list_free (value); } g_hash_table_unref (device->inv_touch_sequence_actors); device->inv_touch_sequence_actors = NULL; } G_OBJECT_CLASS (clutter_input_device_parent_class)->dispose (gobject); } static void clutter_input_device_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject); switch (prop_id) { case PROP_ID: self->id = g_value_get_int (value); break; case PROP_DEVICE_TYPE: self->device_type = g_value_get_enum (value); break; case PROP_DEVICE_MANAGER: self->device_manager = g_value_get_object (value); break; case PROP_DEVICE_MODE: self->device_mode = g_value_get_enum (value); break; case PROP_BACKEND: self->backend = g_value_get_object (value); break; case PROP_NAME: self->device_name = g_value_dup_string (value); break; case PROP_HAS_CURSOR: self->has_cursor = g_value_get_boolean (value); break; case PROP_ENABLED: clutter_input_device_set_enabled (self, g_value_get_boolean (value)); break; case PROP_VENDOR_ID: self->vendor_id = g_value_dup_string (value); break; case PROP_PRODUCT_ID: self->product_id = g_value_dup_string (value); break; case PROP_N_RINGS: self->n_rings = g_value_get_int (value); break; case PROP_N_STRIPS: self->n_strips = g_value_get_int (value); break; case PROP_N_MODE_GROUPS: self->n_mode_groups = g_value_get_int (value); break; case PROP_DEVICE_NODE: self->node_path = g_value_dup_string (value); break; case PROP_MAPPING_MODE: self->mapping_mode = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_input_device_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject); switch (prop_id) { case PROP_ID: g_value_set_int (value, self->id); break; case PROP_DEVICE_TYPE: g_value_set_enum (value, self->device_type); break; case PROP_DEVICE_MANAGER: g_value_set_object (value, self->device_manager); break; case PROP_DEVICE_MODE: g_value_set_enum (value, self->device_mode); break; case PROP_BACKEND: g_value_set_object (value, self->backend); break; case PROP_NAME: g_value_set_string (value, self->device_name); break; case PROP_HAS_CURSOR: g_value_set_boolean (value, self->has_cursor); break; case PROP_N_AXES: g_value_set_uint (value, clutter_input_device_get_n_axes (self)); break; case PROP_ENABLED: g_value_set_boolean (value, self->is_enabled); break; case PROP_VENDOR_ID: g_value_set_string (value, self->vendor_id); break; case PROP_PRODUCT_ID: g_value_set_string (value, self->product_id); break; case PROP_N_RINGS: g_value_set_int (value, self->n_rings); break; case PROP_N_STRIPS: g_value_set_int (value, self->n_strips); break; case PROP_N_MODE_GROUPS: g_value_set_int (value, self->n_mode_groups); break; case PROP_DEVICE_NODE: g_value_set_string (value, self->node_path); break; case PROP_MAPPING_MODE: g_value_set_enum (value, self->mapping_mode); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_input_device_class_init (ClutterInputDeviceClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); /** * ClutterInputDevice:id: * * The unique identifier of the device * * Since: 1.2 */ obj_props[PROP_ID] = g_param_spec_int ("id", P_("Id"), P_("Unique identifier of the device"), -1, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:name: * * The name of the device * * Since: 1.2 */ obj_props[PROP_NAME] = g_param_spec_string ("name", P_("Name"), P_("The name of the device"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:device-type: * * The type of the device * * Since: 1.2 */ obj_props[PROP_DEVICE_TYPE] = g_param_spec_enum ("device-type", P_("Device Type"), P_("The type of the device"), CLUTTER_TYPE_INPUT_DEVICE_TYPE, CLUTTER_POINTER_DEVICE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:device-manager: * * The #ClutterDeviceManager instance which owns the device * * Since: 1.6 */ obj_props[PROP_DEVICE_MANAGER] = g_param_spec_object ("device-manager", P_("Device Manager"), P_("The device manager instance"), CLUTTER_TYPE_DEVICE_MANAGER, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:mode: * * The mode of the device. * * Since: 1.6 */ obj_props[PROP_DEVICE_MODE] = g_param_spec_enum ("device-mode", P_("Device Mode"), P_("The mode of the device"), CLUTTER_TYPE_INPUT_MODE, CLUTTER_INPUT_MODE_FLOATING, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:has-cursor: * * Whether the device has an on screen cursor following its movement. * * Since: 1.6 */ obj_props[PROP_HAS_CURSOR] = g_param_spec_boolean ("has-cursor", P_("Has Cursor"), P_("Whether the device has a cursor"), FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:enabled: * * Whether the device is enabled. * * A device with the #ClutterInputDevice:device-mode property set * to %CLUTTER_INPUT_MODE_MASTER cannot be disabled. * * A device must be enabled in order to receive events from it. * * Since: 1.6 */ obj_props[PROP_ENABLED] = g_param_spec_boolean ("enabled", P_("Enabled"), P_("Whether the device is enabled"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterInputDevice:n-axes: * * The number of axes of the device. * * Since: 1.6 */ obj_props[PROP_N_AXES] = g_param_spec_uint ("n-axes", P_("Number of Axes"), P_("The number of axes on the device"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READABLE); /** * ClutterInputDevice:backend: * * The #ClutterBackend that created the device. * * Since: 1.6 */ obj_props[PROP_BACKEND] = g_param_spec_object ("backend", P_("Backend"), P_("The backend instance"), CLUTTER_TYPE_BACKEND, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:vendor-id: * * Vendor ID of this device. * * Since: 1.22 */ obj_props[PROP_VENDOR_ID] = g_param_spec_string ("vendor-id", P_("Vendor ID"), P_("Vendor ID"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:product-id: * * Product ID of this device. * * Since: 1.22 */ obj_props[PROP_PRODUCT_ID] = g_param_spec_string ("product-id", P_("Product ID"), P_("Product ID"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_N_RINGS] = g_param_spec_int ("n-rings", P_("Number of rings"), P_("Number of rings (circular sliders) in this device"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_N_STRIPS] = g_param_spec_int ("n-strips", P_("Number of strips"), P_("Number of strips (linear sliders) in this device"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_N_MODE_GROUPS] = g_param_spec_int ("n-mode-groups", P_("Number of mode groups"), P_("Number of mode groups"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_DEVICE_NODE] = g_param_spec_string ("device-node", P_("Device node path"), P_("Device node path"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_MAPPING_MODE] = g_param_spec_enum ("mapping-mode", P_("Device mapping mode"), P_("Device mapping mode"), CLUTTER_TYPE_INPUT_DEVICE_MAPPING, CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE, CLUTTER_PARAM_READWRITE); gobject_class->dispose = clutter_input_device_dispose; gobject_class->set_property = clutter_input_device_set_property; gobject_class->get_property = clutter_input_device_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_input_device_init (ClutterInputDevice *self) { self->id = -1; self->device_type = CLUTTER_POINTER_DEVICE; self->click_count = 0; self->current_time = self->previous_time = CLUTTER_CURRENT_TIME; self->current_x = self->previous_x = -1; self->current_y = self->previous_y = -1; self->current_button_number = self->previous_button_number = -1; self->current_state = self->previous_state = 0; self->touch_sequences_info = g_hash_table_new_full (NULL, NULL, NULL, _clutter_input_device_free_touch_info); self->inv_touch_sequence_actors = g_hash_table_new (NULL, NULL); } static ClutterTouchInfo * _clutter_input_device_ensure_touch_info (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterStage *stage) { ClutterTouchInfo *info; info = g_hash_table_lookup (device->touch_sequences_info, sequence); if (info == NULL) { info = g_slice_new0 (ClutterTouchInfo); info->sequence = sequence; g_hash_table_insert (device->touch_sequences_info, sequence, info); if (g_hash_table_size (device->touch_sequences_info) == 1) _clutter_input_device_set_stage (device, stage); } return info; } /*< private > * clutter_input_device_set_coords: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence or NULL * @x: X coordinate of the device * @y: Y coordinate of the device * * Stores the last known coordinates of the device */ void _clutter_input_device_set_coords (ClutterInputDevice *device, ClutterEventSequence *sequence, gfloat x, gfloat y, ClutterStage *stage) { g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); if (sequence == NULL) { if (device->current_x != x) device->current_x = x; if (device->current_y != y) device->current_y = y; } else { ClutterTouchInfo *info; info = _clutter_input_device_ensure_touch_info (device, sequence, stage); info->current_x = x; info->current_y = y; } } /*< private > * clutter_input_device_set_state: * @device: a #ClutterInputDevice * @state: a bitmask of modifiers * * Stores the last known modifiers state of the device */ void _clutter_input_device_set_state (ClutterInputDevice *device, ClutterModifierType state) { g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); device->current_state = state; } /** * clutter_input_device_get_modifier_state: * @device: a #ClutterInputDevice * * Retrieves the current modifiers state of the device, as seen * by the last event Clutter processed. * * Return value: the last known modifier state * * Since: 1.16 */ ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); return device->current_state; } /*< private > * clutter_input_device_set_time: * @device: a #ClutterInputDevice * @time_: the time * * Stores the last known event time of the device */ void _clutter_input_device_set_time (ClutterInputDevice *device, guint32 time_) { g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); if (device->current_time != time_) device->current_time = time_; } /*< private > * clutter_input_device_set_stage: * @device: a #ClutterInputDevice * @stage: a #ClutterStage or %NULL * * Stores the stage under the device */ void _clutter_input_device_set_stage (ClutterInputDevice *device, ClutterStage *stage) { if (device->stage == stage) return; device->stage = stage; /* we leave the ->cursor_actor in place in order to check * if we left the stage without crossing it again; this way * we can emit a leave event on the cursor actor right before * we emit the leave event on the stage. */ } /*< private > * clutter_input_device_get_stage: * @device: a #ClutterInputDevice * * Retrieves the stage currently associated with @device. * * Return value: The stage currently associated with @device. */ ClutterStage * _clutter_input_device_get_stage (ClutterInputDevice *device) { return device->stage; } static void _clutter_input_device_free_touch_info (gpointer data) { g_slice_free (ClutterTouchInfo, data); } static ClutterActor * _clutter_input_device_get_actor (ClutterInputDevice *device, ClutterEventSequence *sequence) { ClutterTouchInfo *info; if (sequence == NULL) return device->cursor_actor; info = g_hash_table_lookup (device->touch_sequences_info, sequence); return info->actor; } static void _clutter_input_device_associate_actor (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterActor *actor) { if (sequence == NULL) device->cursor_actor = actor; else { GList *sequences = g_hash_table_lookup (device->inv_touch_sequence_actors, actor); ClutterTouchInfo *info; ClutterStage *stage = CLUTTER_STAGE (clutter_actor_get_stage (actor)); info = _clutter_input_device_ensure_touch_info (device, sequence, stage); info->actor = actor; g_hash_table_insert (device->inv_touch_sequence_actors, actor, g_list_prepend (sequences, sequence)); } g_signal_connect (actor, "destroy", G_CALLBACK (on_cursor_actor_destroy), device); g_signal_connect (actor, "notify::reactive", G_CALLBACK (on_cursor_actor_reactive_changed), device); _clutter_actor_set_has_pointer (actor, TRUE); } static void _clutter_input_device_unassociate_actor (ClutterInputDevice *device, ClutterActor *actor, gboolean destroyed) { if (device->cursor_actor == actor) device->cursor_actor = NULL; else { GList *l, *sequences = g_hash_table_lookup (device->inv_touch_sequence_actors, actor); for (l = sequences; l != NULL; l = l->next) { ClutterTouchInfo *info = g_hash_table_lookup (device->touch_sequences_info, l->data); if (info) info->actor = NULL; } g_list_free (sequences); g_hash_table_remove (device->inv_touch_sequence_actors, actor); } if (destroyed == FALSE) { g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (on_cursor_actor_destroy), device); g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (on_cursor_actor_reactive_changed), device); _clutter_actor_set_has_pointer (actor, FALSE); } } static void on_cursor_actor_destroy (ClutterActor *actor, ClutterInputDevice *device) { _clutter_input_device_unassociate_actor (device, actor, TRUE); } static void on_cursor_actor_reactive_changed (ClutterActor *actor, GParamSpec *pspec, ClutterInputDevice *device) { if (!clutter_actor_get_reactive (actor)) _clutter_input_device_unassociate_actor (device, actor, FALSE); } /*< private > * clutter_input_device_set_actor: * @device: a #ClutterInputDevice * @actor: a #ClutterActor * @emit_crossing: %TRUE to emit crossing events * * Sets the actor under the pointer coordinates of @device * * This function is called by _clutter_input_device_update() * and it will: * * - queue a %CLUTTER_LEAVE event on the previous pointer actor * of @device, if any * - set to %FALSE the :has-pointer property of the previous * pointer actor of @device, if any * - queue a %CLUTTER_ENTER event on the new pointer actor * - set to %TRUE the :has-pointer property of the new pointer * actor */ void _clutter_input_device_set_actor (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterActor *actor, gboolean emit_crossing) { ClutterActor *old_actor = _clutter_input_device_get_actor (device, sequence); if (old_actor == actor) return; if (old_actor != NULL) { ClutterActor *tmp_old_actor; if (emit_crossing) { ClutterEvent *event; event = clutter_event_new (CLUTTER_LEAVE); event->crossing.time = device->current_time; event->crossing.flags = 0; event->crossing.stage = device->stage; event->crossing.source = old_actor; event->crossing.x = device->current_x; event->crossing.y = device->current_y; event->crossing.related = actor; clutter_event_set_device (event, device); /* we need to make sure that this event is processed * before any other event we might have queued up until * now, so we go on, and synthesize the event emission * ourselves */ _clutter_process_event (event); clutter_event_free (event); } /* processing the event might have destroyed the actor */ tmp_old_actor = _clutter_input_device_get_actor (device, sequence); _clutter_input_device_unassociate_actor (device, old_actor, tmp_old_actor == NULL); old_actor = tmp_old_actor; } if (actor != NULL) { _clutter_input_device_associate_actor (device, sequence, actor); if (emit_crossing) { ClutterEvent *event; event = clutter_event_new (CLUTTER_ENTER); event->crossing.time = device->current_time; event->crossing.flags = 0; event->crossing.stage = device->stage; event->crossing.x = device->current_x; event->crossing.y = device->current_y; event->crossing.source = actor; event->crossing.related = old_actor; clutter_event_set_device (event, device); /* see above */ _clutter_process_event (event); clutter_event_free (event); } } } /** * clutter_input_device_get_device_type: * @device: a #ClutterInputDevice * * Retrieves the type of @device * * Return value: the type of the device * * Since: 1.0 */ ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_POINTER_DEVICE); return device->device_type; } /** * clutter_input_device_get_device_id: * @device: a #ClutterInputDevice * * Retrieves the unique identifier of @device * * Return value: the identifier of the device * * Since: 1.0 */ gint clutter_input_device_get_device_id (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1); return device->id; } /** * clutter_input_device_set_enabled: * @device: a #ClutterInputDevice * @enabled: %TRUE to enable the @device * * Enables or disables a #ClutterInputDevice. * * Only devices with a #ClutterInputDevice:device-mode property set * to %CLUTTER_INPUT_MODE_SLAVE or %CLUTTER_INPUT_MODE_FLOATING can * be disabled. * * Since: 1.6 */ void clutter_input_device_set_enabled (ClutterInputDevice *device, gboolean enabled) { g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); enabled = !!enabled; if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_MASTER) return; if (device->is_enabled == enabled) return; device->is_enabled = enabled; g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]); } /** * clutter_input_device_get_enabled: * @device: a #ClutterInputDevice * * Retrieves whether @device is enabled. * * Return value: %TRUE if the device is enabled * * Since: 1.6 */ gboolean clutter_input_device_get_enabled (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); return device->is_enabled; } /** * clutter_input_device_get_coords: * @device: a #ClutterInputDevice * @sequence: (allow-none): a #ClutterEventSequence, or %NULL if * the device is not touch-based * @point: (out caller-allocates): return location for the pointer * or touch point * * Retrieves the latest coordinates of a pointer or touch point of * @device. * * Return value: %FALSE if the device's sequence hasn't been found, * and %TRUE otherwise. * * Since: 1.12 */ gboolean clutter_input_device_get_coords (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterPoint *point) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); g_return_val_if_fail (point != NULL, FALSE); if (sequence == NULL) { point->x = device->current_x; point->y = device->current_y; } else { ClutterTouchInfo *info = g_hash_table_lookup (device->touch_sequences_info, sequence); if (info == NULL) return FALSE; point->x = info->current_x; point->y = info->current_y; } return TRUE; } /* * _clutter_input_device_update: * @device: a #ClutterInputDevice * * Updates the input @device by determining the #ClutterActor underneath the * pointer's cursor * * This function calls _clutter_input_device_set_actor() if needed. * * This function only works for #ClutterInputDevice of type * %CLUTTER_POINTER_DEVICE. * * Since: 1.2 */ ClutterActor * _clutter_input_device_update (ClutterInputDevice *device, ClutterEventSequence *sequence, gboolean emit_crossing) { ClutterStage *stage; ClutterActor *new_cursor_actor; ClutterActor *old_cursor_actor; ClutterPoint point = { -1, -1 }; if (device->device_type == CLUTTER_KEYBOARD_DEVICE) return NULL; stage = device->stage; if (G_UNLIKELY (stage == NULL)) { CLUTTER_NOTE (EVENT, "No stage defined for device %d '%s'", clutter_input_device_get_device_id (device), clutter_input_device_get_device_name (device)); return NULL; } clutter_input_device_get_coords (device, sequence, &point); old_cursor_actor = _clutter_input_device_get_actor (device, sequence); new_cursor_actor = _clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE); /* if the pick could not find an actor then we do not update the * input device, to avoid ghost enter/leave events; the pick should * never fail, except for bugs in the glReadPixels() implementation * in which case this is the safest course of action anyway */ if (new_cursor_actor == NULL) return NULL; CLUTTER_NOTE (EVENT, "Actor under cursor (device %d, at %.2f, %.2f): %s", clutter_input_device_get_device_id (device), point.x, point.y, _clutter_actor_get_debug_name (new_cursor_actor)); /* short-circuit here */ if (new_cursor_actor == old_cursor_actor) return old_cursor_actor; _clutter_input_device_set_actor (device, sequence, new_cursor_actor, emit_crossing); return new_cursor_actor; } /** * clutter_input_device_get_pointer_actor: * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE * * Retrieves the #ClutterActor underneath the pointer of @device * * Return value: (transfer none): a pointer to the #ClutterActor or %NULL * * Since: 1.2 */ ClutterActor * clutter_input_device_get_pointer_actor (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL); return device->cursor_actor; } /** * clutter_input_device_get_pointer_stage: * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE * * Retrieves the #ClutterStage underneath the pointer of @device * * Return value: (transfer none): a pointer to the #ClutterStage or %NULL * * Since: 1.2 */ ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL); return device->stage; } /** * clutter_input_device_get_device_name: * @device: a #ClutterInputDevice * * Retrieves the name of the @device * * Return value: the name of the device, or %NULL. The returned string * is owned by the #ClutterInputDevice and should never be modified * or freed * * Since: 1.2 */ const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); return device->device_name; } /** * clutter_input_device_get_has_cursor: * @device: a #ClutterInputDevice * * Retrieves whether @device has a pointer that follows the * device motion. * * Return value: %TRUE if the device has a cursor * * Since: 1.6 */ gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); return device->has_cursor; } /** * clutter_input_device_get_device_mode: * @device: a #ClutterInputDevice * * Retrieves the #ClutterInputMode of @device. * * Return value: the device mode * * Since: 1.6 */ ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_INPUT_MODE_FLOATING); return device->device_mode; } /** * clutter_input_device_update_from_event: * @device: a #ClutterInputDevice * @event: a #ClutterEvent * @update_stage: whether to update the #ClutterStage of the @device * using the stage of the event * * Forcibly updates the state of the @device using a #ClutterEvent * * This function should never be used by applications: it is meant * for integration with embedding toolkits, like clutter-gtk * * Embedding toolkits that disable the event collection inside Clutter * need to use this function to update the state of input devices depending * on a #ClutterEvent that they are going to submit to the event handling code * in Clutter though clutter_do_event(). Since the input devices hold the state * that is going to be used to fill in fields like the #ClutterButtonEvent * click count, or to emit synthesized events like %CLUTTER_ENTER and * %CLUTTER_LEAVE, it is necessary for embedding toolkits to also be * responsible of updating the input device state. * * For instance, this might be the code to translate an embedding toolkit * native motion notification into a Clutter #ClutterMotionEvent and ask * Clutter to process it: * * |[ * ClutterEvent c_event; * * translate_native_event_to_clutter (native_event, &c_event); * * clutter_do_event (&c_event); * ]| * * Before letting clutter_do_event() process the event, it is necessary to call * clutter_input_device_update_from_event(): * * |[ * ClutterEvent c_event; * ClutterDeviceManager *manager; * ClutterInputDevice *device; * * translate_native_event_to_clutter (native_event, &c_event); * * // get the device manager * manager = clutter_device_manager_get_default (); * * // use the default Core Pointer that Clutter backends register by default * device = clutter_device_manager_get_core_device (manager, %CLUTTER_POINTER_DEVICE); * * // update the state of the input device * clutter_input_device_update_from_event (device, &c_event, FALSE); * * clutter_do_event (&c_event); * ]| * * The @update_stage boolean argument should be used when the input device * enters and leaves a #ClutterStage; it will use the #ClutterStage field * of the passed @event to update the stage associated to the input device. * * Since: 1.2 */ void clutter_input_device_update_from_event (ClutterInputDevice *device, ClutterEvent *event, gboolean update_stage) { ClutterModifierType event_state; ClutterEventSequence *sequence; ClutterStage *event_stage; gfloat event_x, event_y; guint32 event_time; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (event != NULL); event_state = clutter_event_get_state (event); event_time = clutter_event_get_time (event); event_stage = clutter_event_get_stage (event); sequence = clutter_event_get_event_sequence (event); clutter_event_get_coords (event, &event_x, &event_y); _clutter_input_device_set_coords (device, sequence, event_x, event_y, event_stage); _clutter_input_device_set_state (device, event_state); _clutter_input_device_set_time (device, event_time); if (update_stage) _clutter_input_device_set_stage (device, event_stage); } /*< private > * clutter_input_device_reset_axes: * @device: a #ClutterInputDevice * * Resets the axes on @device */ void _clutter_input_device_reset_axes (ClutterInputDevice *device) { if (device->axes != NULL) { g_array_free (device->axes, TRUE); device->axes = NULL; g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]); } } /*< private > * clutter_input_device_add_axis: * @device: a #ClutterInputDevice * @axis: the axis type * @minimum: the minimum axis value * @maximum: the maximum axis value * @resolution: the axis resolution * * Adds an axis of type @axis on @device. */ guint _clutter_input_device_add_axis (ClutterInputDevice *device, ClutterInputAxis axis, gdouble minimum, gdouble maximum, gdouble resolution) { ClutterAxisInfo info; guint pos; if (device->axes == NULL) device->axes = g_array_new (FALSE, TRUE, sizeof (ClutterAxisInfo)); info.axis = axis; info.min_value = minimum; info.max_value = maximum; info.resolution = resolution; switch (axis) { case CLUTTER_INPUT_AXIS_X: case CLUTTER_INPUT_AXIS_Y: info.min_axis = 0; info.max_axis = 0; break; case CLUTTER_INPUT_AXIS_XTILT: case CLUTTER_INPUT_AXIS_YTILT: info.min_axis = -1; info.max_axis = 1; break; default: info.min_axis = 0; info.max_axis = 1; break; } device->axes = g_array_append_val (device->axes, info); pos = device->axes->len - 1; g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]); return pos; } /*< private > * clutter_input_translate_axis: * @device: a #ClutterInputDevice * @index_: the index of the axis * @gint: the absolute value of the axis * @axis_value: (out): the translated value of the axis * * Performs a conversion from the absolute value of the axis * to a relative value. * * The axis at @index_ must not be %CLUTTER_INPUT_AXIS_X or * %CLUTTER_INPUT_AXIS_Y. * * Return value: %TRUE if the conversion was successful */ gboolean _clutter_input_device_translate_axis (ClutterInputDevice *device, guint index_, gdouble value, gdouble *axis_value) { ClutterAxisInfo *info; gdouble width; gdouble real_value; if (device->axes == NULL || index_ >= device->axes->len) return FALSE; info = &g_array_index (device->axes, ClutterAxisInfo, index_); if (info->axis == CLUTTER_INPUT_AXIS_X || info->axis == CLUTTER_INPUT_AXIS_Y) return FALSE; if (fabs (info->max_value - info->min_value) < 0.0000001) return FALSE; width = info->max_value - info->min_value; real_value = (info->max_axis * (value - info->min_value) + info->min_axis * (info->max_value - value)) / width; if (axis_value) *axis_value = real_value; return TRUE; } /** * clutter_input_device_get_axis: * @device: a #ClutterInputDevice * @index_: the index of the axis * * Retrieves the type of axis on @device at the given index. * * Return value: the axis type * * Since: 1.6 */ ClutterInputAxis clutter_input_device_get_axis (ClutterInputDevice *device, guint index_) { ClutterAxisInfo *info; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_INPUT_AXIS_IGNORE); if (device->axes == NULL) return CLUTTER_INPUT_AXIS_IGNORE; if (index_ >= device->axes->len) return CLUTTER_INPUT_AXIS_IGNORE; info = &g_array_index (device->axes, ClutterAxisInfo, index_); return info->axis; } /** * clutter_input_device_get_axis_value: * @device: a #ClutterInputDevice * @axes: (array): an array of axes values, typically * coming from clutter_event_get_axes() * @axis: the axis to extract * @value: (out): return location for the axis value * * Extracts the value of the given @axis of a #ClutterInputDevice from * an array of axis values. * * An example of typical usage for this function is: * * |[ * ClutterInputDevice *device = clutter_event_get_device (event); * gdouble *axes = clutter_event_get_axes (event, NULL); * gdouble pressure_value = 0; * * clutter_input_device_get_axis_value (device, axes, * CLUTTER_INPUT_AXIS_PRESSURE, * &pressure_value); * ]| * * Return value: %TRUE if the value was set, and %FALSE otherwise * * Since: 1.6 */ gboolean clutter_input_device_get_axis_value (ClutterInputDevice *device, gdouble *axes, ClutterInputAxis axis, gdouble *value) { gint i; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); g_return_val_if_fail (device->axes != NULL, FALSE); for (i = 0; i < device->axes->len; i++) { ClutterAxisInfo *info; info = &g_array_index (device->axes, ClutterAxisInfo, i); if (info->axis == axis) { if (value) *value = axes[i]; return TRUE; } } return FALSE; } /** * clutter_input_device_get_n_axes: * @device: a #ClutterInputDevice * * Retrieves the number of axes available on @device. * * Return value: the number of axes on the device * * Since: 1.6 */ guint clutter_input_device_get_n_axes (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); if (device->axes != NULL) return device->axes->len; return 0; } /*< private > * clutter_input_device_set_n_keys: * @device: a #ClutterInputDevice * @n_keys: the number of keys of the device * * Initializes the keys of @device. * * Call clutter_input_device_set_key() on each key to set the keyval * and modifiers. */ void _clutter_input_device_set_n_keys (ClutterInputDevice *device, guint n_keys) { if (device->keys != NULL) g_array_free (device->keys, TRUE); device->n_keys = n_keys; device->keys = g_array_sized_new (FALSE, TRUE, sizeof (ClutterKeyInfo), n_keys); } /** * clutter_input_device_get_n_keys: * @device: a #ClutterInputDevice * * Retrieves the number of keys registered for @device. * * Return value: the number of registered keys * * Since: 1.6 */ guint clutter_input_device_get_n_keys (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); return device->n_keys; } /** * clutter_input_device_set_key: * @device: a #ClutterInputDevice * @index_: the index of the key * @keyval: the keyval * @modifiers: a bitmask of modifiers * * Sets the keyval and modifiers at the given @index_ for @device. * * Clutter will use the keyval and modifiers set when filling out * an event coming from the same input device. * * Since: 1.6 */ void clutter_input_device_set_key (ClutterInputDevice *device, guint index_, guint keyval, ClutterModifierType modifiers) { ClutterKeyInfo *key_info; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (index_ < device->n_keys); key_info = &g_array_index (device->keys, ClutterKeyInfo, index_); key_info->keyval = keyval; key_info->modifiers = modifiers; } /** * clutter_input_device_get_key: * @device: a #ClutterInputDevice * @index_: the index of the key * @keyval: (out): return location for the keyval at @index_ * @modifiers: (out): return location for the modifiers at @index_ * * Retrieves the key set using clutter_input_device_set_key() * * Return value: %TRUE if a key was set at the given index * * Since: 1.6 */ gboolean clutter_input_device_get_key (ClutterInputDevice *device, guint index_, guint *keyval, ClutterModifierType *modifiers) { ClutterKeyInfo *key_info; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); if (device->keys == NULL) return FALSE; if (index_ > device->keys->len) return FALSE; key_info = &g_array_index (device->keys, ClutterKeyInfo, index_); if (!key_info->keyval && !key_info->modifiers) return FALSE; if (keyval) *keyval = key_info->keyval; if (modifiers) *modifiers = key_info->modifiers; return TRUE; } /*< private > * clutter_input_device_add_slave: * @master: a #ClutterInputDevice * @slave: a #ClutterInputDevice * * Adds @slave to the list of slave devices of @master * * This function does not increase the reference count of either @master * or @slave. */ void _clutter_input_device_add_slave (ClutterInputDevice *master, ClutterInputDevice *slave) { if (g_list_find (master->slaves, slave) == NULL) master->slaves = g_list_prepend (master->slaves, slave); } /*< private > * clutter_input_device_remove_slave: * @master: a #ClutterInputDevice * @slave: a #ClutterInputDevice * * Removes @slave from the list of slave devices of @master. * * This function does not decrease the reference count of either @master * or @slave. */ void _clutter_input_device_remove_slave (ClutterInputDevice *master, ClutterInputDevice *slave) { if (g_list_find (master->slaves, slave) != NULL) master->slaves = g_list_remove (master->slaves, slave); } /*< private > * clutter_input_device_add_sequence: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * * Start tracking informations related to a touch point (position, * actor underneath the touch point). */ void _clutter_input_device_add_event_sequence (ClutterInputDevice *device, ClutterEvent *event) { ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); ClutterStage *stage; if (sequence == NULL) return; stage = clutter_event_get_stage (event); if (stage == NULL) return; _clutter_input_device_ensure_touch_info (device, sequence, stage); } /*< private > * clutter_input_device_remove_sequence: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * * Stop tracking informations related to a touch point. */ void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device, ClutterEvent *event) { ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); ClutterTouchInfo *info = g_hash_table_lookup (device->touch_sequences_info, sequence); if (info == NULL) return; if (info->actor != NULL) { GList *sequences = g_hash_table_lookup (device->inv_touch_sequence_actors, info->actor); sequences = g_list_remove (sequences, sequence); g_hash_table_replace (device->inv_touch_sequence_actors, info->actor, sequences); _clutter_input_device_set_actor (device, sequence, NULL, TRUE); } g_hash_table_remove (device->touch_sequences_info, sequence); } /** * clutter_input_device_get_slave_devices: * @device: a #ClutterInputDevice * * Retrieves the slave devices attached to @device. * * Return value: (transfer container) (element-type Clutter.InputDevice): a * list of #ClutterInputDevice, or %NULL. The contents of the list are * owned by the device. Use g_list_free() when done * * Since: 1.6 */ GList * clutter_input_device_get_slave_devices (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); return g_list_copy (device->slaves); } /*< internal > * clutter_input_device_set_associated_device: * @device: a #ClutterInputDevice * @associated: (allow-none): a #ClutterInputDevice, or %NULL * * Sets the associated device for @device. * * This function keeps a reference on the associated device. */ void _clutter_input_device_set_associated_device (ClutterInputDevice *device, ClutterInputDevice *associated) { if (device->associated == associated) return; if (device->associated != NULL) g_object_unref (device->associated); device->associated = associated; if (device->associated != NULL) g_object_ref (device->associated); CLUTTER_NOTE (MISC, "Associating device %d '%s' to device %d '%s'", clutter_input_device_get_device_id (device), clutter_input_device_get_device_name (device), device->associated != NULL ? clutter_input_device_get_device_id (device->associated) : -1, device->associated != NULL ? clutter_input_device_get_device_name (device->associated) : "(none)"); if (device->device_mode != CLUTTER_INPUT_MODE_MASTER) { if (device->associated != NULL) device->device_mode = CLUTTER_INPUT_MODE_SLAVE; else device->device_mode = CLUTTER_INPUT_MODE_FLOATING; g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_DEVICE_MODE]); } } /** * clutter_input_device_get_associated_device: * @device: a #ClutterInputDevice * * Retrieves a pointer to the #ClutterInputDevice that has been * associated to @device. * * If the #ClutterInputDevice:device-mode property of @device is * set to %CLUTTER_INPUT_MODE_MASTER, this function will return * %NULL. * * Return value: (transfer none): a #ClutterInputDevice, or %NULL * * Since: 1.6 */ ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); return device->associated; } /** * clutter_input_device_keycode_to_evdev: * @device: A #ClutterInputDevice * @hardware_keycode: The hardware keycode from a #ClutterKeyEvent * @evdev_keycode: The return location for the evdev keycode * * Translates a hardware keycode from a #ClutterKeyEvent to the * equivalent evdev keycode. Note that depending on the input backend * used by Clutter this function can fail if there is no obvious * mapping between the key codes. The hardware keycode can be taken * from the #ClutterKeyEvent.hardware_keycode member of #ClutterKeyEvent. * * Return value: %TRUE if the conversion succeeded, %FALSE otherwise. * * Since: 1.10 */ gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device, guint hardware_keycode, guint *evdev_keycode) { ClutterInputDeviceClass *device_class; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (device_class->keycode_to_evdev == NULL) return FALSE; else return device_class->keycode_to_evdev (device, hardware_keycode, evdev_keycode); } void _clutter_input_device_add_scroll_info (ClutterInputDevice *device, guint index_, ClutterScrollDirection direction, gdouble increment) { ClutterScrollInfo info; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (index_ < clutter_input_device_get_n_axes (device)); info.axis_id = index_; info.direction = direction; info.increment = increment; info.last_value_valid = FALSE; if (device->scroll_info == NULL) { device->scroll_info = g_array_new (FALSE, FALSE, sizeof (ClutterScrollInfo)); } g_array_append_val (device->scroll_info, info); } gboolean _clutter_input_device_get_scroll_delta (ClutterInputDevice *device, guint index_, gdouble value, ClutterScrollDirection *direction_p, gdouble *delta_p) { guint i; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); g_return_val_if_fail (index_ < clutter_input_device_get_n_axes (device), FALSE); if (device->scroll_info == NULL) return FALSE; for (i = 0; i < device->scroll_info->len; i++) { ClutterScrollInfo *info = &g_array_index (device->scroll_info, ClutterScrollInfo, i); if (info->axis_id == index_) { if (direction_p != NULL) *direction_p = info->direction; if (delta_p != NULL) *delta_p = 0.0; if (info->last_value_valid) { if (delta_p != NULL) { *delta_p = (value - info->last_value) / info->increment; } info->last_value = value; } else { info->last_value = value; info->last_value_valid = TRUE; } return TRUE; } } return FALSE; } void _clutter_input_device_reset_scroll_info (ClutterInputDevice *device) { guint i; if (device->scroll_info == NULL) return; for (i = 0; i < device->scroll_info->len; i++) { ClutterScrollInfo *info = &g_array_index (device->scroll_info, ClutterScrollInfo, i); info->last_value_valid = FALSE; } } static void on_grab_sequence_actor_destroy (ClutterActor *actor, ClutterInputDevice *device) { ClutterEventSequence *sequence = g_hash_table_lookup (device->inv_sequence_grab_actors, actor); if (sequence != NULL) { g_hash_table_remove (device->sequence_grab_actors, sequence); g_hash_table_remove (device->inv_sequence_grab_actors, actor); } } /** * clutter_input_device_sequence_grab: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * @actor: a #ClutterActor * * Acquires a grab on @actor for the given @device and the given touch * @sequence. * * Any touch event coming from @device and from @sequence will be * delivered to @actor, bypassing the usual event delivery mechanism, * until the grab is released by calling * clutter_input_device_sequence_ungrab(). * * The grab is client-side: even if the windowing system used by the Clutter * backend has the concept of "device grabs", Clutter will not use them. * * Since: 1.12 */ void clutter_input_device_sequence_grab (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterActor *actor) { ClutterActor *grab_actor; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); if (device->sequence_grab_actors == NULL) { grab_actor = NULL; device->sequence_grab_actors = g_hash_table_new (NULL, NULL); device->inv_sequence_grab_actors = g_hash_table_new (NULL, NULL); } else { grab_actor = g_hash_table_lookup (device->sequence_grab_actors, sequence); } if (grab_actor != NULL) { g_signal_handlers_disconnect_by_func (grab_actor, G_CALLBACK (on_grab_sequence_actor_destroy), device); g_hash_table_remove (device->sequence_grab_actors, sequence); g_hash_table_remove (device->inv_sequence_grab_actors, grab_actor); } g_hash_table_insert (device->sequence_grab_actors, sequence, actor); g_hash_table_insert (device->inv_sequence_grab_actors, actor, sequence); g_signal_connect (actor, "destroy", G_CALLBACK (on_grab_sequence_actor_destroy), device); } /** * clutter_input_device_sequence_ungrab: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * * Releases the grab on the @device for the given @sequence, if one is * in place. * * Since: 1.12 */ void clutter_input_device_sequence_ungrab (ClutterInputDevice *device, ClutterEventSequence *sequence) { ClutterActor *grab_actor; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); if (device->sequence_grab_actors == NULL) return; grab_actor = g_hash_table_lookup (device->sequence_grab_actors, sequence); if (grab_actor == NULL) return; g_signal_handlers_disconnect_by_func (grab_actor, G_CALLBACK (on_grab_sequence_actor_destroy), device); g_hash_table_remove (device->sequence_grab_actors, sequence); g_hash_table_remove (device->inv_sequence_grab_actors, grab_actor); if (g_hash_table_size (device->sequence_grab_actors) == 0) { g_hash_table_destroy (device->sequence_grab_actors); device->sequence_grab_actors = NULL; g_hash_table_destroy (device->inv_sequence_grab_actors); device->inv_sequence_grab_actors = NULL; } } /** * clutter_input_device_sequence_get_grabbed_actor: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * * Retrieves a pointer to the #ClutterActor currently grabbing the * touch events coming from @device given the @sequence. * * Return value: (transfer none): a #ClutterActor, or %NULL * * Since: 1.12 */ ClutterActor * clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice *device, ClutterEventSequence *sequence) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); if (device->sequence_grab_actors == NULL) return NULL; return g_hash_table_lookup (device->sequence_grab_actors, sequence); } /** * clutter_input_device_get_vendor_id: * @device: a slave #ClutterInputDevice * * Gets the vendor ID of this device. * * Returns: the vendor ID * * Since: 1.22 */ const gchar * clutter_input_device_get_vendor_id (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER, NULL); return device->vendor_id; } /** * clutter_input_device_get_product_id: * @device: a slave #ClutterInputDevice * * Gets the product ID of this device. * * Returns: the product ID * * Since: 1.22 */ const gchar * clutter_input_device_get_product_id (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER, NULL); return device->product_id; } void clutter_input_device_add_tool (ClutterInputDevice *device, ClutterInputDeviceTool *tool) { g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER); g_return_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool)); if (!device->tools) device->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_ptr_array_add (device->tools, tool); } ClutterInputDeviceTool * clutter_input_device_lookup_tool (ClutterInputDevice *device, guint64 serial, ClutterInputDeviceToolType type) { ClutterInputDeviceTool *tool; guint i; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER, NULL); if (!device->tools) return NULL; for (i = 0; i < device->tools->len; i++) { tool = g_ptr_array_index (device->tools, i); if (serial == clutter_input_device_tool_get_serial (tool) && type == clutter_input_device_tool_get_tool_type (tool)) return tool; } return NULL; } void clutter_input_device_update_from_tool (ClutterInputDevice *device, ClutterInputDeviceTool *tool) { ClutterInputDeviceClass *device_class; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (device_class->update_from_tool) device_class->update_from_tool (device, tool); } gint clutter_input_device_get_n_rings (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); return device->n_rings; } gint clutter_input_device_get_n_strips (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); return device->n_strips; } gint clutter_input_device_get_n_mode_groups (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, 0); return device->n_mode_groups; } gint clutter_input_device_get_group_n_modes (ClutterInputDevice *device, gint group) { ClutterInputDeviceClass *device_class; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, 0); g_return_val_if_fail (group >= 0, 0); device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (device_class->get_group_n_modes) return device_class->get_group_n_modes (device, group); return 0; } gboolean clutter_input_device_is_mode_switch_button (ClutterInputDevice *device, guint group, guint button) { ClutterInputDeviceClass *device_class; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, FALSE); device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (device_class->is_mode_switch_button) return device_class->is_mode_switch_button (device, group, button); return FALSE; } gint clutter_input_device_get_mode_switch_button_group (ClutterInputDevice *device, guint button) { gint group; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, -1); for (group = 0; group < device->n_mode_groups; group++) { if (clutter_input_device_is_mode_switch_button (device, group, button)) return group; } return -1; } const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); return device->node_path; } ClutterInputDeviceMapping clutter_input_device_get_mapping_mode (ClutterInputDevice *device) { ClutterInputDeviceType device_type; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE); device_type = clutter_input_device_get_device_type (device); g_return_val_if_fail (device_type == CLUTTER_TABLET_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_ERASER_DEVICE, CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE); return device->mapping_mode; } void clutter_input_device_set_mapping_mode (ClutterInputDevice *device, ClutterInputDeviceMapping mapping) { ClutterInputDeviceType device_type; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); device_type = clutter_input_device_get_device_type (device); g_return_if_fail (device_type == CLUTTER_TABLET_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_ERASER_DEVICE); if (device->mapping_mode == mapping) return; device->mapping_mode = mapping; g_object_notify (G_OBJECT (device), "mapping-mode"); } gboolean clutter_input_device_is_grouped (ClutterInputDevice *device, ClutterInputDevice *other_device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (other_device), FALSE); return CLUTTER_INPUT_DEVICE_GET_CLASS (device)->is_grouped (device, other_device); } �������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-input-device-tool.h��������������������������������������������0000664�0001750�0001750�00000005140�14211404421�023500� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifndef __CLUTTER_INPUT_DEVICE_TOOL_H__ #define __CLUTTER_INPUT_DEVICE_TOOL_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include "clutter-enum-types.h" G_BEGIN_DECLS #define CLUTTER_TYPE_INPUT_DEVICE_TOOL (clutter_input_device_tool_get_type ()) #define CLUTTER_INPUT_DEVICE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_TOOL, ClutterInputDeviceTool)) #define CLUTTER_IS_INPUT_DEVICE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_TOOL)) #define CLUTTER_INPUT_DEVICE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_INPUT_DEVICE_TOOL, ClutterInputDeviceToolClass)) #define CLUTTER_IS_INPUT_DEVICE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_INPUT_DEVICE_TOOL)) #define CLUTTER_INPUT_DEVICE_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_INPUT_DEVICE_TOOL, ClutterInputDeviceToolClass)) typedef struct _ClutterInputDeviceToolClass ClutterInputDeviceToolClass; struct _ClutterInputDeviceTool { GObject parent_instance; }; struct _ClutterInputDeviceToolClass { GObjectClass parent_class; }; CLUTTER_AVAILABLE_IN_ALL GType clutter_input_device_tool_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL guint64 clutter_input_device_tool_get_serial (ClutterInputDeviceTool *tool); CLUTTER_AVAILABLE_IN_ALL ClutterInputDeviceToolType clutter_input_device_tool_get_tool_type (ClutterInputDeviceTool *tool); CLUTTER_AVAILABLE_IN_ALL guint64 clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool); G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_TOOL_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-offscreen-effect-private.h�������������������������������������0000664�0001750�0001750�00000000336�14211404421�025007� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_OFFSCREEN_EFFECT_PRIVATE_H__ #define __CLUTTER_OFFSCREEN_EFFECT_PRIVATE_H__ #include <clutter/clutter-offscreen-effect.h> G_BEGIN_DECLS G_END_DECLS #endif /* __CLUTTER_OFFSCREEN_EFFECT_PRIVATE_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-color-static.h�������������������������������������������������0000664�0001750�0001750�00000010603�14211404421�022534� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_COLOR_STATIC_H__ #define __CLUTTER_COLOR_STATIC_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #define __CLUTTER_COLOR_SYM(x) (clutter_color_get_static (CLUTTER_COLOR_##x)) #define CLUTTER_COLOR_White (__CLUTTER_COLOR_SYM (WHITE)) #define CLUTTER_COLOR_Black (__CLUTTER_COLOR_SYM (BLACK)) #define CLUTTER_COLOR_Red (__CLUTTER_COLOR_SYM (RED)) #define CLUTTER_COLOR_DarkRed (__CLUTTER_COLOR_SYM (DARK_RED)) #define CLUTTER_COLOR_Green (__CLUTTER_COLOR_SYM (GREEN)) #define CLUTTER_COLOR_DarkGreen (__CLUTTER_COLOR_SYM (DARK_GREEN)) #define CLUTTER_COLOR_Blue (__CLUTTER_COLOR_SYM (BLUE)) #define CLUTTER_COLOR_DarkBlue (__CLUTTER_COLOR_SYM (DARK_BLUE)) #define CLUTTER_COLOR_Cyan (__CLUTTER_COLOR_SYM (CYAN)) #define CLUTTER_COLOR_DarkCyan (__CLUTTER_COLOR_SYM (DARK_CYAN)) #define CLUTTER_COLOR_Magenta (__CLUTTER_COLOR_SYM (MAGENTA)) #define CLUTTER_COLOR_DarkMagenta (__CLUTTER_COLOR_SYM (DARK_MAGENTA)) #define CLUTTER_COLOR_Yellow (__CLUTTER_COLOR_SYM (YELLOW)) #define CLUTTER_COLOR_DarkYellow (__CLUTTER_COLOR_SYM (DARK_YELLOW)) #define CLUTTER_COLOR_Gray (__CLUTTER_COLOR_SYM (GRAY)) #define CLUTTER_COLOR_DarkGray (__CLUTTER_COLOR_SYM (DARK_GRAY)) #define CLUTTER_COLOR_LightGray (__CLUTTER_COLOR_SYM (LIGHT_GRAY)) #define CLUTTER_COLOR_Butter (__CLUTTER_COLOR_SYM (BUTTER)) #define CLUTTER_COLOR_LightButter (__CLUTTER_COLOR_SYM (BUTTER_LIGHT)) #define CLUTTER_COLOR_DarkButter (__CLUTTER_COLOR_SYM (BUTTER_DARK)) #define CLUTTER_COLOR_Orange (__CLUTTER_COLOR_SYM (ORANGE)) #define CLUTTER_COLOR_LightOrange (__CLUTTER_COLOR_SYM (ORANGE_LIGHT)) #define CLUTTER_COLOR_DarkOrange (__CLUTTER_COLOR_SYM (ORANGE_DARK)) #define CLUTTER_COLOR_Chocolate (__CLUTTER_COLOR_SYM (CHOCOLATE)) #define CLUTTER_COLOR_LightChocolate (__CLUTTER_COLOR_SYM (CHOCOLATE_LIGHT)) #define CLUTTER_COLOR_DarkChocolate (__CLUTTER_COLOR_SYM (CHOCOLATE_DARK)) #define CLUTTER_COLOR_Chameleon (__CLUTTER_COLOR_SYM (CHAMELEON)) #define CLUTTER_COLOR_LightChameleon (__CLUTTER_COLOR_SYM (CHAMELEON_LIGHT)) #define CLUTTER_COLOR_DarkChameleon (__CLUTTER_COLOR_SYM (CHAMELEON_DARK)) #define CLUTTER_COLOR_SkyBlue (__CLUTTER_COLOR_SYM (SKY_BLUE)) #define CLUTTER_COLOR_LightSkyBlue (__CLUTTER_COLOR_SYM (SKY_BLUE_LIGHT)) #define CLUTTER_COLOR_DarkSkyBlue (__CLUTTER_COLOR_SYM (SKY_BLUE_DARK)) #define CLUTTER_COLOR_Plum (__CLUTTER_COLOR_SYM (PLUM)) #define CLUTTER_COLOR_LightPlum (__CLUTTER_COLOR_SYM (PLUM_LIGHT)) #define CLUTTER_COLOR_DarkPlum (__CLUTTER_COLOR_SYM (PLUM_DARK)) #define CLUTTER_COLOR_ScarletRed (__CLUTTER_COLOR_SYM (SCARLET_RED)) #define CLUTTER_COLOR_LightScarletRed (__CLUTTER_COLOR_SYM (SCARLET_RED_LIGHT)) #define CLUTTER_COLOR_DarkScarletRed (__CLUTTER_COLOR_SYM (SCARLET_RED_DARK)) #define CLUTTER_COLOR_Aluminium1 (__CLUTTER_COLOR_SYM (ALUMINIUM_1)) #define CLUTTER_COLOR_Aluminium2 (__CLUTTER_COLOR_SYM (ALUMINIUM_2)) #define CLUTTER_COLOR_Aluminium3 (__CLUTTER_COLOR_SYM (ALUMINIUM_3)) #define CLUTTER_COLOR_Aluminium4 (__CLUTTER_COLOR_SYM (ALUMINIUM_4)) #define CLUTTER_COLOR_Aluminium5 (__CLUTTER_COLOR_SYM (ALUMINIUM_5)) #define CLUTTER_COLOR_Aluminium6 (__CLUTTER_COLOR_SYM (ALUMINIUM_6)) #define CLUTTER_COLOR_Transparent (__CLUTTER_COLOR_SYM (TRANSPARENT)) #endif /* __CLUTTER_COLOR_STATIC_H__ */ �����������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-colorize-effect.c����������������������������������������������0000664�0001750�0001750�00000024511�14211404421�023207� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-colorize-effect * @short_description: A colorization effect * @see_also: #ClutterEffect, #ClutterOffscreenEffect * * #ClutterColorizeEffect is a sub-class of #ClutterEffect that * colorizes an actor with the given tint. * * #ClutterColorizeEffect is available since Clutter 1.4 */ #define CLUTTER_COLORIZE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_COLORIZE_EFFECT, ClutterColorizeEffectClass)) #define CLUTTER_IS_COLORIZE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_COLORIZE_EFFECT)) #define CLUTTER_COLORIZE_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_COLORIZE_EFFECT, ClutterColorizeEffectClass)) #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-colorize-effect.h" #include "cogl/cogl.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-offscreen-effect.h" #include "clutter-private.h" struct _ClutterColorizeEffect { ClutterOffscreenEffect parent_instance; /* the tint of the colorization */ ClutterColor tint; gint tint_uniform; gint tex_width; gint tex_height; CoglPipeline *pipeline; }; struct _ClutterColorizeEffectClass { ClutterOffscreenEffectClass parent_class; CoglPipeline *base_pipeline; }; /* the magic gray vec3 has been taken from the NTSC conversion weights * as defined by: * * "OpenGL Superbible, 4th Edition" * -- Richard S. Wright Jr, Benjamin Lipchak, Nicholas Haemel * Addison-Wesley */ static const gchar *colorize_glsl_declarations = "uniform vec3 tint;\n"; static const gchar *colorize_glsl_source = "float gray = dot (cogl_color_out.rgb, vec3 (0.299, 0.587, 0.114));\n" "cogl_color_out.rgb = gray * tint;\n"; /* a lame sepia */ static const ClutterColor default_tint = { 255, 204, 153, 255 }; enum { PROP_0, PROP_TINT, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterColorizeEffect, clutter_colorize_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT); static gboolean clutter_colorize_effect_pre_paint (ClutterEffect *effect) { ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect); ClutterEffectClass *parent_class; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) return FALSE; if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) { /* if we don't have support for GLSL shaders then we * forcibly disable the ActorMeta */ g_warning ("Unable to use the ShaderEffect: the graphics hardware " "or the current GL driver does not implement support " "for the GLSL shading language."); clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE); return FALSE; } parent_class = CLUTTER_EFFECT_CLASS (clutter_colorize_effect_parent_class); if (parent_class->pre_paint (effect)) { ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect); CoglHandle texture; texture = clutter_offscreen_effect_get_texture (offscreen_effect); self->tex_width = cogl_texture_get_width (texture); self->tex_height = cogl_texture_get_height (texture); cogl_pipeline_set_layer_texture (self->pipeline, 0, texture); return TRUE; } else return FALSE; } static void clutter_colorize_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect); ClutterActor *actor; guint8 paint_opacity; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); paint_opacity = clutter_actor_get_paint_opacity (actor); cogl_pipeline_set_color4ub (self->pipeline, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_push_source (self->pipeline); cogl_rectangle (0, 0, self->tex_width, self->tex_height); cogl_pop_source (); } static void clutter_colorize_effect_dispose (GObject *gobject) { ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (gobject); if (self->pipeline != NULL) { cogl_object_unref (self->pipeline); self->pipeline = NULL; } G_OBJECT_CLASS (clutter_colorize_effect_parent_class)->dispose (gobject); } static void clutter_colorize_effect_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterColorizeEffect *effect = CLUTTER_COLORIZE_EFFECT (gobject); switch (prop_id) { case PROP_TINT: clutter_colorize_effect_set_tint (effect, clutter_value_get_color (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_colorize_effect_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterColorizeEffect *effect = CLUTTER_COLORIZE_EFFECT (gobject); switch (prop_id) { case PROP_TINT: clutter_value_set_color (value, &effect->tint); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_colorize_effect_class_init (ClutterColorizeEffectClass *klass) { ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterOffscreenEffectClass *offscreen_class; offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class->paint_target = clutter_colorize_effect_paint_target; effect_class->pre_paint = clutter_colorize_effect_pre_paint; gobject_class->set_property = clutter_colorize_effect_set_property; gobject_class->get_property = clutter_colorize_effect_get_property; gobject_class->dispose = clutter_colorize_effect_dispose; /** * ClutterColorizeEffect:tint: * * The tint to apply to the actor * * Since: 1.4 */ obj_props[PROP_TINT] = clutter_param_spec_color ("tint", P_("Tint"), P_("The tint to apply"), &default_tint, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void update_tint_uniform (ClutterColorizeEffect *self) { if (self->tint_uniform > -1) { float tint[3] = { self->tint.red / 255.0, self->tint.green / 255.0, self->tint.blue / 255.0 }; cogl_pipeline_set_uniform_float (self->pipeline, self->tint_uniform, 3, /* n_components */ 1, /* count */ tint); } } static void clutter_colorize_effect_init (ClutterColorizeEffect *self) { ClutterColorizeEffectClass *klass = CLUTTER_COLORIZE_EFFECT_GET_CLASS (self); if (G_UNLIKELY (klass->base_pipeline == NULL)) { CoglSnippet *snippet; CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); klass->base_pipeline = cogl_pipeline_new (ctx); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, colorize_glsl_declarations, colorize_glsl_source); cogl_pipeline_add_snippet (klass->base_pipeline, snippet); cogl_object_unref (snippet); cogl_pipeline_set_layer_null_texture (klass->base_pipeline, 0, /* layer number */ COGL_TEXTURE_TYPE_2D); } self->pipeline = cogl_pipeline_copy (klass->base_pipeline); self->tint_uniform = cogl_pipeline_get_uniform_location (self->pipeline, "tint"); self->tint = default_tint; update_tint_uniform (self); } /** * clutter_colorize_effect_new: * @tint: the color to be used * * Creates a new #ClutterColorizeEffect to be used with * clutter_actor_add_effect() * * Return value: the newly created #ClutterColorizeEffect or %NULL * * Since: 1.4 */ ClutterEffect * clutter_colorize_effect_new (const ClutterColor *tint) { return g_object_new (CLUTTER_TYPE_COLORIZE_EFFECT, "tint", tint, NULL); } /** * clutter_colorize_effect_set_tint: * @effect: a #ClutterColorizeEffect * @tint: the color to be used * * Sets the tint to be used when colorizing * * Since: 1.4 */ void clutter_colorize_effect_set_tint (ClutterColorizeEffect *effect, const ClutterColor *tint) { g_return_if_fail (CLUTTER_IS_COLORIZE_EFFECT (effect)); effect->tint = *tint; update_tint_uniform (effect); clutter_effect_queue_repaint (CLUTTER_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_TINT]); } /** * clutter_colorize_effect_get_tint: * @effect: a #ClutterColorizeEffect * @tint: (out caller-allocates): return location for the color used * * Retrieves the tint used by @effect * * Since: 1.4 */ void clutter_colorize_effect_get_tint (ClutterColorizeEffect *effect, ClutterColor *tint) { g_return_if_fail (CLUTTER_IS_COLORIZE_EFFECT (effect)); g_return_if_fail (tint != NULL); *tint = effect->tint; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-swipe-action.h�������������������������������������������������0000664�0001750�0001750�00000007160�14211404421�022537� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> * * Based on ClutterDragAction, written by: * Emmanuele Bassi <ebassi@linux.intel.com> */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #ifndef __CLUTTER_SWIPE_ACTION_H__ #define __CLUTTER_SWIPE_ACTION_H__ #include <clutter/clutter-gesture-action.h> G_BEGIN_DECLS #define CLUTTER_TYPE_SWIPE_ACTION (clutter_swipe_action_get_type ()) #define CLUTTER_SWIPE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SWIPE_ACTION, ClutterSwipeAction)) #define CLUTTER_IS_SWIPE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SWIPE_ACTION)) #define CLUTTER_SWIPE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SWIPE_ACTION, ClutterSwipeActionClass)) #define CLUTTER_IS_SWIPE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SWIPE_ACTION)) #define CLUTTER_SWIPE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SWIPE_ACTION, ClutterSwipeActionClass)) typedef struct _ClutterSwipeAction ClutterSwipeAction; typedef struct _ClutterSwipeActionPrivate ClutterSwipeActionPrivate; typedef struct _ClutterSwipeActionClass ClutterSwipeActionClass; /** * ClutterSwipeAction: * * The #ClutterSwipeAction structure contains * only private data and should be accessed using the provided API * * Since: 1.8 */ struct _ClutterSwipeAction { /*< private >*/ ClutterGestureAction parent_instance; ClutterSwipeActionPrivate *priv; }; /** * ClutterSwipeActionClass: * @swept: class handler for the #ClutterSwipeAction::swept signal; * deprecated since 1.14 * @swipe: class handler for the #ClutterSwipeAction::swipe signal * * The #ClutterSwipeActionClass structure contains * only private data. * * Since: 1.8 */ struct _ClutterSwipeActionClass { /*< private >*/ ClutterGestureActionClass parent_class; /*< public >*/ void (* swept) (ClutterSwipeAction *action, ClutterActor *actor, ClutterSwipeDirection direction); gboolean (* swipe) (ClutterSwipeAction *action, ClutterActor *actor, ClutterSwipeDirection direction); /*< private >*/ void (* _clutter_swipe_action1) (void); void (* _clutter_swipe_action2) (void); void (* _clutter_swipe_action3) (void); void (* _clutter_swipe_action4) (void); void (* _clutter_swipe_action5) (void); void (* _clutter_swipe_action6) (void); }; CLUTTER_AVAILABLE_IN_1_8 GType clutter_swipe_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_8 ClutterAction * clutter_swipe_action_new (void); G_END_DECLS #endif /* __CLUTTER_SWIPE_ACTION_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-keyframe-transition.h������������������������������������������0000664�0001750�0001750�00000013555�14211404421�024135� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_KEYFRAME_TRANSITION_H__ #define __CLUTTER_KEYFRAME_TRANSITION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-property-transition.h> G_BEGIN_DECLS #define CLUTTER_TYPE_KEYFRAME_TRANSITION (clutter_keyframe_transition_get_type ()) #define CLUTTER_KEYFRAME_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_KEYFRAME_TRANSITION, ClutterKeyframeTransition)) #define CLUTTER_IS_KEYFRAME_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_KEYFRAME_TRANSITION)) #define CLUTTER_KEYFRAME_TRANSITION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_KEYFRAME_TRANSITION, ClutterKeyframeTransitionClass)) #define CLUTTER_IS_KEYFRAME_TRANSITION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_KEYFRAME_TRANSITION)) #define CLUTTER_KEYFRAME_TRANSITION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_KEYFRAME_TRANSITION, ClutterKeyframeTransitionClass)) typedef struct _ClutterKeyframeTransitionPrivate ClutterKeyframeTransitionPrivate; typedef struct _ClutterKeyframeTransitionClass ClutterKeyframeTransitionClass; /** * ClutterKeyframeTransition: * * The `ClutterKeyframeTransition` structure contains only private * data and should be accessed using the provided API. * * Since: 1.12 */ struct _ClutterKeyframeTransition { /*< private >*/ ClutterPropertyTransition parent_instance; ClutterKeyframeTransitionPrivate *priv; }; /** * ClutterKeyframeTransitionClass: * * The `ClutterKeyframeTransitionClass` structure contains only * private data. * * Since: 1.12 */ struct _ClutterKeyframeTransitionClass { /*< private >*/ ClutterPropertyTransitionClass parent_class; gpointer _padding[8]; }; CLUTTER_AVAILABLE_IN_1_12 GType clutter_keyframe_transition_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterTransition * clutter_keyframe_transition_new (const char *property_name); CLUTTER_AVAILABLE_IN_1_12 void clutter_keyframe_transition_set_key_frames (ClutterKeyframeTransition *transition, guint n_key_frames, const double *key_frames); CLUTTER_AVAILABLE_IN_1_12 void clutter_keyframe_transition_set_values (ClutterKeyframeTransition *transition, guint n_values, const GValue *values); CLUTTER_AVAILABLE_IN_1_12 void clutter_keyframe_transition_set_modes (ClutterKeyframeTransition *transition, guint n_modes, const ClutterAnimationMode *modes); CLUTTER_AVAILABLE_IN_1_12 void clutter_keyframe_transition_set (ClutterKeyframeTransition *transition, GType gtype, guint n_key_frames, ...); CLUTTER_AVAILABLE_IN_1_12 void clutter_keyframe_transition_set_key_frame (ClutterKeyframeTransition *transition, guint index_, double key, ClutterAnimationMode mode, const GValue *value); CLUTTER_AVAILABLE_IN_1_12 void clutter_keyframe_transition_get_key_frame (ClutterKeyframeTransition *transition, guint index_, double *key, ClutterAnimationMode *mode, GValue *value); CLUTTER_AVAILABLE_IN_1_12 guint clutter_keyframe_transition_get_n_key_frames (ClutterKeyframeTransition *transition); CLUTTER_AVAILABLE_IN_1_12 void clutter_keyframe_transition_clear (ClutterKeyframeTransition *transition); G_END_DECLS #endif /* __CLUTTER_KEYFRAME_TRANSITION_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-settings-private.h���������������������������������������������0000664�0001750�0001750�00000001357�14211404421�023447� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_SETTINGS_PRIVATE_H__ #define __CLUTTER_SETTINGS_PRIVATE_H__ #include <clutter/clutter-backend-private.h> #include <clutter/clutter-settings.h> G_BEGIN_DECLS void _clutter_settings_set_backend (ClutterSettings *settings, ClutterBackend *backend); void _clutter_settings_read_from_key_file (ClutterSettings *settings, GKeyFile *key_file); void clutter_settings_set_property_internal (ClutterSettings *settings, const char *property, GValue *value); G_END_DECLS #endif /* __CLUTTER_SETTINGS_PRIVATE_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-event-translator.h���������������������������������������������0000664�0001750�0001750�00000003230�14211404421�023437� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_EVENT_TRANSLATOR_H__ #define __CLUTTER_EVENT_TRANSLATOR_H__ #include <glib-object.h> #include <clutter/clutter-event.h> G_BEGIN_DECLS #define CLUTTER_TYPE_EVENT_TRANSLATOR (_clutter_event_translator_get_type ()) #define CLUTTER_EVENT_TRANSLATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR, ClutterEventTranslator)) #define CLUTTER_IS_EVENT_TRANSLATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR)) #define CLUTTER_EVENT_TRANSLATOR_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR, ClutterEventTranslatorIface)) typedef struct _ClutterEventTranslator ClutterEventTranslator; typedef struct _ClutterEventTranslatorIface ClutterEventTranslatorIface; typedef enum { CLUTTER_TRANSLATE_CONTINUE, CLUTTER_TRANSLATE_REMOVE, CLUTTER_TRANSLATE_QUEUE } ClutterTranslateReturn; struct _ClutterEventTranslatorIface { GTypeInterface g_iface; ClutterTranslateReturn (* translate_event) (ClutterEventTranslator *translator, gpointer native, ClutterEvent *translated); }; CLUTTER_AVAILABLE_IN_MUFFIN GType _clutter_event_translator_get_type (void) G_GNUC_CONST; ClutterTranslateReturn _clutter_event_translator_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *translated); G_END_DECLS #endif /* __CLUTTER_EVENT_TRANSLATOR_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-autocleanups.h�������������������������������������������������0000664�0001750�0001750�00000013101�14211404421�022630� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright 2015 Emmanuele Bassi * * 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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_AUTO_CLEANUPS_H__ #define __CLUTTER_AUTO_CLEANUPS_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #ifndef __GI_SCANNER__ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterActor, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterActorMeta, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterAlignConstraint, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterAnimatable, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBackend, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBindConstraint, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBindingPool, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBinLayout, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBlurEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBoxLayout, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBrightnessContrastEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterCanvas, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterChildMeta, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterClickAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterClone, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterColorizeEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterConstraint, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterContainer, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterContent, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDeformEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDesaturateEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDeviceManager, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDragAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDropAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFixedLayout, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFlowLayout, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterGestureAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterGridLayout, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterImage, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterInputDevice, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterInterval, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterKeyframeTransition, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterLayoutManager, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterLayoutMeta, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterOffscreenEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPageTurnEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPanAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPathConstraint, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPath, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPropertyTransition, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterRotateAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterScriptable, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterScript, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterScrollActor, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterSettings, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterShaderEffect, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterSnapConstraint, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterStage, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterSwipeAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterTapAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterTextBuffer, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterText, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterTimeline, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterTransitionGroup, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterTransition, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterZoomAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterActorBox, clutter_actor_box_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterColor, clutter_color_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterMargin, clutter_margin_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterMatrix, clutter_matrix_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPaintNode, clutter_paint_node_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPaintVolume, clutter_paint_volume_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPathNode, clutter_path_node_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPoint, clutter_point_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterRect, clutter_rect_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterSize, clutter_size_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterVertex, clutter_vertex_free) #endif /* __GI_SCANNER__ */ #endif /* __CLUTTER_AUTO_CLEANUPS_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-enum-types.c.in������������������������������������������������0000664�0001750�0001750�00000001670�14211404421�022643� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** BEGIN file-header ***/ #include "clutter-build-config.h" #include "clutter-enum-types.h" /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ #include "@filename@" /*** END file-production ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) { static volatile gsize g_enum_type_id__volatile = 0; if (g_once_init_enter (&g_enum_type_id__volatile)) { static const G@Type@Value values[] = { /*** END value-header ***/ /*** BEGIN value-production ***/ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, /*** END value-production ***/ /*** BEGIN value-tail ***/ { 0, NULL, NULL } }; GType g_enum_type_id; g_enum_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id); } return g_enum_type_id__volatile; } /*** END value-tail ***/ ������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-event.h��������������������������������������������������������0000664�0001750�0001750�00000064625�14211404421�021267� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_EVENT_H__ #define __CLUTTER_EVENT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-input-device.h> G_BEGIN_DECLS #define CLUTTER_TYPE_EVENT (clutter_event_get_type ()) #define CLUTTER_TYPE_EVENT_SEQUENCE (clutter_event_sequence_get_type ()) /** * CLUTTER_PRIORITY_EVENTS: * * Priority for event handling. * * Since: 0.4 */ #define CLUTTER_PRIORITY_EVENTS (G_PRIORITY_DEFAULT) /** * CLUTTER_CURRENT_TIME: * * Default value for "now". * * Since: 0.4 */ #define CLUTTER_CURRENT_TIME (0L) /** * CLUTTER_EVENT_PROPAGATE: * * Continues the propagation of an event; this macro should be * used in event-related signals. * * Since: 1.10 */ #define CLUTTER_EVENT_PROPAGATE (FALSE) /** * CLUTTER_EVENT_STOP: * * Stops the propagation of an event; this macro should be used * in event-related signals. * * Since: 1.10 */ #define CLUTTER_EVENT_STOP (TRUE) /** * CLUTTER_BUTTON_PRIMARY: * * The primary button of a pointer device. * * This is typically the left mouse button in a right-handed * mouse configuration. * * Since: 1.10 */ #define CLUTTER_BUTTON_PRIMARY (1) /** * CLUTTER_BUTTON_MIDDLE: * * The middle button of a pointer device. * * Since: 1.10 */ #define CLUTTER_BUTTON_MIDDLE (2) /** * CLUTTER_BUTTON_SECONDARY: * * The secondary button of a pointer device. * * This is typically the right mouse button in a right-handed * mouse configuration. * * Since: 1.10 */ #define CLUTTER_BUTTON_SECONDARY (3) typedef struct _ClutterAnyEvent ClutterAnyEvent; typedef struct _ClutterButtonEvent ClutterButtonEvent; typedef struct _ClutterKeyEvent ClutterKeyEvent; typedef struct _ClutterMotionEvent ClutterMotionEvent; typedef struct _ClutterScrollEvent ClutterScrollEvent; typedef struct _ClutterStageStateEvent ClutterStageStateEvent; typedef struct _ClutterCrossingEvent ClutterCrossingEvent; typedef struct _ClutterTouchEvent ClutterTouchEvent; typedef struct _ClutterTouchpadPinchEvent ClutterTouchpadPinchEvent; typedef struct _ClutterTouchpadSwipeEvent ClutterTouchpadSwipeEvent; typedef struct _ClutterProximityEvent ClutterProximityEvent; typedef struct _ClutterPadButtonEvent ClutterPadButtonEvent; typedef struct _ClutterPadStripEvent ClutterPadStripEvent; typedef struct _ClutterPadRingEvent ClutterPadRingEvent; /** * ClutterAnyEvent: * @type: event type * @time: event time * @flags: event flags * @source: event source actor * * Common members for a #ClutterEvent * * Since: 0.2 */ struct _ClutterAnyEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; }; /** * ClutterKeyEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor * @modifier_state: key modifiers * @keyval: raw key value * @hardware_keycode: raw hardware key value * @unicode_value: Unicode representation * @device: the device that originated the event. If you want the physical * device the event originated from, use clutter_event_get_source_device() * * Key event * * Since: 0.2 */ struct _ClutterKeyEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; ClutterModifierType modifier_state; guint keyval; guint16 hardware_keycode; gunichar unicode_value; ClutterInputDevice *device; }; /** * ClutterButtonEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor * @x: event X coordinate, relative to the stage * @y: event Y coordinate, relative to the stage * @modifier_state: button modifiers * @button: event button * @click_count: number of button presses within the default time * and radius * @axes: reserved for future use * @device: the device that originated the event. If you want the physical * device the event originated from, use clutter_event_get_source_device() * * Button event. * * The event coordinates are relative to the stage that received the * event, and can be transformed into actor-relative coordinates by * using clutter_actor_transform_stage_point(). * * Since: 0.2 */ struct _ClutterButtonEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; gfloat x; gfloat y; ClutterModifierType modifier_state; guint32 button; guint click_count; gdouble *axes; /* Future use */ ClutterInputDevice *device; }; /** * ClutterProximityEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor * @device: the device that originated the event. If you want the physical * device the event originated from, use clutter_event_get_source_device() * * Event for tool proximity in tablet devices * * Since: 1.28 */ struct _ClutterProximityEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; ClutterInputDevice *device; }; /** * ClutterCrossingEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor * @x: event X coordinate * @y: event Y coordinate * @related: actor related to the crossing * @device: the device that originated the event. If you want the physical * device the event originated from, use clutter_event_get_source_device() * * Event for the movement of the pointer across different actors * * Since: 0.2 */ struct _ClutterCrossingEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; gfloat x; gfloat y; ClutterInputDevice *device; ClutterActor *related; }; /** * ClutterMotionEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor * @x: event X coordinate * @y: event Y coordinate * @modifier_state: button modifiers * @axes: reserved for future use * @device: the device that originated the event. If you want the physical * device the event originated from, use clutter_event_get_source_device() * * Event for the pointer motion * * Since: 0.2 */ struct _ClutterMotionEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; gfloat x; gfloat y; ClutterModifierType modifier_state; gdouble *axes; /* Future use */ ClutterInputDevice *device; }; /** * ClutterScrollEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor * @x: event X coordinate * @y: event Y coordinate * @direction: direction of the scrolling * @modifier_state: button modifiers * @axes: reserved for future use * @device: the device that originated the event. If you want the physical * device the event originated from, use clutter_event_get_source_device() * @scroll_source: the source of scroll events. This field is available since 1.26 * @finish_flags: the axes that were stopped in this event. This field is available since 1.26 * * Scroll wheel (or similar device) event * * Since: 0.2 */ struct _ClutterScrollEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; gfloat x; gfloat y; ClutterScrollDirection direction; ClutterModifierType modifier_state; gdouble *axes; /* future use */ ClutterInputDevice *device; ClutterScrollSource scroll_source; ClutterScrollFinishFlags finish_flags; }; /** * ClutterStageStateEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor (unused) * @changed_mask: bitwise OR of the changed flags * @new_state: bitwise OR of the current state flags * * Event signalling a change in the #ClutterStage state. * * Since: 0.2 */ struct _ClutterStageStateEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; /* XXX: should probably be the stage itself */ ClutterStageState changed_mask; ClutterStageState new_state; }; /** * ClutterTouchEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor (unused) * @x: the X coordinate of the pointer, relative to the stage * @y: the Y coordinate of the pointer, relative to the stage * @sequence: the event sequence that this event belongs to * @modifier_state: (type ClutterModifierType): a bit-mask representing the state * of modifier keys (e.g. Control, Shift, and Alt) and the pointer * buttons. See #ClutterModifierType * @axes: reserved * @device: the device that originated the event. If you want the physical * device the event originated from, use clutter_event_get_source_device() * * Used for touch events. * * The @type field will be one of %CLUTTER_TOUCH_BEGIN, %CLUTTER_TOUCH_END, * %CLUTTER_TOUCH_UPDATE, or %CLUTTER_TOUCH_CANCEL. * * Touch events are grouped into sequences; each touch sequence will begin * with a %CLUTTER_TOUCH_BEGIN event, progress with %CLUTTER_TOUCH_UPDATE * events, and end either with a %CLUTTER_TOUCH_END event or with a * %CLUTTER_TOUCH_CANCEL event. * * With multi-touch capable devices there can be multiple event sequence * running at the same time. * * Since: 1.10 */ struct _ClutterTouchEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; gfloat x; gfloat y; ClutterEventSequence *sequence; ClutterModifierType modifier_state; gdouble *axes; /* reserved */ ClutterInputDevice *device; }; /** * ClutterTouchpadPinchEvent: * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor (unused) * @phase: the current phase of the gesture * @x: the X coordinate of the pointer, relative to the stage * @y: the Y coordinate of the pointer, relative to the stage * @dx: movement delta of the pinch focal point in the X axis * @dy: movement delta of the pinch focal point in the Y axis * @angle_delta: angle delta in degrees, clockwise rotations are * represented by positive deltas * @scale: the current scale * * Used for touchpad pinch gesture events. The current state of the * gesture will be determined by the @phase field. * * Each event with phase %CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN * will report a @scale of 1.0, all later phases in the gesture * report the current scale relative to the initial 1.0 value * (eg. 0.5 being half the size, 2.0 twice as big). * * Since: 1.24 */ struct _ClutterTouchpadPinchEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; ClutterTouchpadGesturePhase phase; gfloat x; gfloat y; gfloat dx; gfloat dy; gfloat angle_delta; gfloat scale; guint n_fingers; }; /** * ClutterTouchpadSwipeEvent * @type: event type * @time: event time * @flags: event flags * @stage: event source stage * @source: event source actor (unused) * @phase: the current phase of the gesture * @n_fingers: the number of fingers triggering the swipe * @x: the X coordinate of the pointer, relative to the stage * @y: the Y coordinate of the pointer, relative to the stage * @dx: movement delta of the pinch focal point in the X axis * @dy: movement delta of the pinch focal point in the Y axis * * Used for touchpad swipe gesture events. The current state of the * gesture will be determined by the @phase field. * * Since: 1.24 */ struct _ClutterTouchpadSwipeEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; ClutterTouchpadGesturePhase phase; guint n_fingers; gfloat x; gfloat y; gfloat dx; gfloat dy; }; struct _ClutterPadButtonEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; guint32 button; guint32 group; ClutterInputDevice *device; guint32 mode; }; struct _ClutterPadStripEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; ClutterInputDevice *device; ClutterInputDevicePadSource strip_source; guint32 strip_number; guint32 group; gdouble value; guint32 mode; }; struct _ClutterPadRingEvent { ClutterEventType type; guint32 time; ClutterEventFlags flags; ClutterStage *stage; ClutterActor *source; ClutterInputDevice *device; ClutterInputDevicePadSource ring_source; guint32 ring_number; guint32 group; gdouble angle; guint32 mode; }; /** * ClutterEvent: * * Generic event wrapper. * * Since: 0.2 */ union _ClutterEvent { /*< private >*/ ClutterEventType type; ClutterAnyEvent any; ClutterButtonEvent button; ClutterKeyEvent key; ClutterMotionEvent motion; ClutterScrollEvent scroll; ClutterStageStateEvent stage_state; ClutterCrossingEvent crossing; ClutterTouchEvent touch; ClutterTouchpadPinchEvent touchpad_pinch; ClutterTouchpadSwipeEvent touchpad_swipe; ClutterProximityEvent proximity; ClutterPadButtonEvent pad_button; ClutterPadStripEvent pad_strip; ClutterPadRingEvent pad_ring; }; /** * ClutterEventFilterFunc: * @event: the event that is going to be emitted * @user_data: the data pointer passed to clutter_event_add_filter() * * A function pointer type used by event filters that are added with * clutter_event_add_filter(). * * Return value: %CLUTTER_EVENT_STOP to indicate that the event * has been handled or %CLUTTER_EVENT_PROPAGATE otherwise. * Returning %CLUTTER_EVENT_STOP skips any further filter * functions and prevents the signal emission for the event. * * Since: 1.18 */ typedef gboolean (* ClutterEventFilterFunc) (const ClutterEvent *event, gpointer user_data); CLUTTER_AVAILABLE_IN_ALL GType clutter_event_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_20 GType clutter_event_sequence_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL gboolean clutter_events_pending (void); CLUTTER_AVAILABLE_IN_ALL ClutterEvent * clutter_event_get (void); CLUTTER_AVAILABLE_IN_ALL ClutterEvent * clutter_event_peek (void); CLUTTER_AVAILABLE_IN_ALL void clutter_event_put (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_18 guint clutter_event_add_filter (ClutterStage *stage, ClutterEventFilterFunc func, GDestroyNotify notify, gpointer user_data); CLUTTER_AVAILABLE_IN_1_18 void clutter_event_remove_filter (guint id); CLUTTER_AVAILABLE_IN_ALL ClutterEvent * clutter_event_new (ClutterEventType type); CLUTTER_AVAILABLE_IN_ALL ClutterEvent * clutter_event_copy (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL void clutter_event_free (ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL ClutterEventType clutter_event_type (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_flags (ClutterEvent *event, ClutterEventFlags flags); CLUTTER_AVAILABLE_IN_1_0 ClutterEventFlags clutter_event_get_flags (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_time (ClutterEvent *event, guint32 time_); CLUTTER_AVAILABLE_IN_ALL guint32 clutter_event_get_time (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_state (ClutterEvent *event, ClutterModifierType state); CLUTTER_AVAILABLE_IN_ALL ClutterModifierType clutter_event_get_state (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_16 void clutter_event_get_state_full (const ClutterEvent *event, ClutterModifierType *button_state, ClutterModifierType *base_state, ClutterModifierType *latched_state, ClutterModifierType *locked_state, ClutterModifierType *effective_state); CLUTTER_AVAILABLE_IN_1_6 void clutter_event_set_device (ClutterEvent *event, ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_6 ClutterInputDevice * clutter_event_get_device (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_6 void clutter_event_set_source_device (ClutterEvent *event, ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_6 ClutterInputDevice * clutter_event_get_source_device (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL void clutter_event_set_device_tool (ClutterEvent *event, ClutterInputDeviceTool *tool); CLUTTER_AVAILABLE_IN_ALL ClutterInputDeviceTool *clutter_event_get_device_tool (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_source (ClutterEvent *event, ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_event_get_source (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_stage (ClutterEvent *event, ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL ClutterStage * clutter_event_get_stage (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL gint clutter_event_get_device_id (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_0 ClutterInputDeviceType clutter_event_get_device_type (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_coords (ClutterEvent *event, gfloat x, gfloat y); CLUTTER_AVAILABLE_IN_ALL void clutter_event_get_coords (const ClutterEvent *event, gfloat *x, gfloat *y); CLUTTER_AVAILABLE_IN_1_12 void clutter_event_get_position (const ClutterEvent *event, ClutterPoint *position); CLUTTER_AVAILABLE_IN_1_12 float clutter_event_get_distance (const ClutterEvent *source, const ClutterEvent *target); CLUTTER_AVAILABLE_IN_1_12 double clutter_event_get_angle (const ClutterEvent *source, const ClutterEvent *target); CLUTTER_AVAILABLE_IN_1_6 gdouble * clutter_event_get_axes (const ClutterEvent *event, guint *n_axes); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_event_has_shift_modifier (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_event_has_control_modifier (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_event_is_pointer_emulated (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_key_symbol (ClutterEvent *event, guint key_sym); CLUTTER_AVAILABLE_IN_1_0 guint clutter_event_get_key_symbol (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_key_code (ClutterEvent *event, guint16 key_code); CLUTTER_AVAILABLE_IN_1_0 guint16 clutter_event_get_key_code (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_key_unicode (ClutterEvent *event, gunichar key_unicode); CLUTTER_AVAILABLE_IN_1_0 gunichar clutter_event_get_key_unicode (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_button (ClutterEvent *event, guint32 button); CLUTTER_AVAILABLE_IN_1_0 guint32 clutter_event_get_button (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_0 guint clutter_event_get_click_count (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_related (ClutterEvent *event, ClutterActor *actor); CLUTTER_AVAILABLE_IN_1_0 ClutterActor * clutter_event_get_related (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_8 void clutter_event_set_scroll_direction (ClutterEvent *event, ClutterScrollDirection direction); CLUTTER_AVAILABLE_IN_1_0 ClutterScrollDirection clutter_event_get_scroll_direction (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_10 void clutter_event_set_scroll_delta (ClutterEvent *event, gdouble dx, gdouble dy); CLUTTER_AVAILABLE_IN_1_10 void clutter_event_get_scroll_delta (const ClutterEvent *event, gdouble *dx, gdouble *dy); CLUTTER_AVAILABLE_IN_1_10 ClutterEventSequence * clutter_event_get_event_sequence (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL guint32 clutter_keysym_to_unicode (guint keyval); CLUTTER_AVAILABLE_IN_1_10 guint clutter_unicode_to_keysym (guint32 wc); CLUTTER_AVAILABLE_IN_1_0 guint32 clutter_get_current_event_time (void); CLUTTER_AVAILABLE_IN_1_2 const ClutterEvent * clutter_get_current_event (void); CLUTTER_AVAILABLE_IN_1_24 guint clutter_event_get_touchpad_gesture_finger_count (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_24 gdouble clutter_event_get_gesture_pinch_angle_delta (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_24 gdouble clutter_event_get_gesture_pinch_scale (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_24 ClutterTouchpadGesturePhase clutter_event_get_gesture_phase (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_24 void clutter_event_get_gesture_motion_delta (const ClutterEvent *event, gdouble *dx, gdouble *dy); ClutterScrollSource clutter_event_get_scroll_source (const ClutterEvent *event); ClutterScrollFinishFlags clutter_event_get_scroll_finish_flags (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL guint clutter_event_get_mode_group (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_MUFFIN gboolean clutter_event_get_pad_event_details (const ClutterEvent *event, guint *number, guint *mode, gdouble *value); G_END_DECLS #endif /* __CLUTTER_EVENT_H__ */ �����������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-gesture-action-private.h���������������������������������������0000664�0001750�0001750�00000001745�14211404421�024541� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Collabora Ltd.. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_GESTURE_ACTION_PRIVATE_H__ #define __CLUTTER_GESTURE_ACTION_PRIVATE_H__ #include <clutter/clutter-gesture-action.h> G_BEGIN_DECLS G_END_DECLS #endif /* __CLUTTER_GESTURE_ACTION_PRIVATE_H__ */ ���������������������������muffin-5.2.1/clutter/clutter/clutter-test-utils.h���������������������������������������������������0000664�0001750�0001750�00000013136�14211404421�022252� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2013 Emmanuele Bassi <ebassi@gnome.org> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_TEST_UTILS_H__ #define __CLUTTER_TEST_UTILS_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-actor.h> #include <clutter/clutter-color.h> G_BEGIN_DECLS /** * CLUTTER_TEST_UNIT: * @path: the GTest path for the test function * @func: the GTestFunc function * * Adds @func at the given @path in the test suite. * * Since: 1.18 */ #define CLUTTER_TEST_UNIT(path,func) \ clutter_test_add (path, func); /** * CLUTTER_TEST_SUITE: * @units: a list of %CLUTTER_TEST_UNIT definitions * * Defines the entry point and initializes a Clutter test unit, e.g.: * * |[ * CLUTTER_TEST_SUITE ( * CLUTTER_TEST_UNIT ("/foobarize", foobarize) * CLUTTER_TEST_UNIT ("/bar-enabled", bar_enabled) * ) * ]| * * Expands to: * * |[ * int * main (int argc, * char *argv[]) * { * clutter_test_init (&argc, &argv); * * clutter_test_add ("/foobarize", foobarize); * clutter_test_add ("/bar-enabled", bar_enabled); * * return clutter_test_run (); * } * ]| * * Since: 1.18 */ #define CLUTTER_TEST_SUITE(units) \ int \ main (int argc, char *argv[]) \ { \ clutter_test_init (&argc, &argv); \ \ { \ units \ } \ \ return clutter_test_run (); \ } CLUTTER_AVAILABLE_IN_1_18 void clutter_test_init (int *argc, char ***argv); CLUTTER_AVAILABLE_IN_1_18 int clutter_test_run (void); CLUTTER_AVAILABLE_IN_1_18 void clutter_test_add (const char *test_path, GTestFunc test_func); CLUTTER_AVAILABLE_IN_1_18 void clutter_test_add_data (const char *test_path, GTestDataFunc test_func, gpointer test_data); CLUTTER_AVAILABLE_IN_1_18 void clutter_test_add_data_full (const char *test_path, GTestDataFunc test_func, gpointer test_data, GDestroyNotify test_notify); CLUTTER_AVAILABLE_IN_1_18 ClutterActor * clutter_test_get_stage (void); #define clutter_test_assert_actor_at_point(stage,point,actor) \ G_STMT_START { \ const ClutterPoint *__p = (point); \ ClutterActor *__actor = (actor); \ ClutterActor *__stage = (stage); \ ClutterActor *__res; \ if (clutter_test_check_actor_at_point (__stage, __p, actor, &__res)) ; else { \ const char *__str1 = clutter_actor_get_name (__actor) != NULL \ ? clutter_actor_get_name (__actor) \ : G_OBJECT_TYPE_NAME (__actor); \ const char *__str2 = clutter_actor_get_name (__res) != NULL \ ? clutter_actor_get_name (__res) \ : G_OBJECT_TYPE_NAME (__res); \ char *__msg = g_strdup_printf ("assertion failed (actor %s at %.2f,%.2f): found actor %s", \ __str1, __p->x, __p->y, __str2); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \ free (__msg); \ } \ } G_STMT_END #define clutter_test_assert_color_at_point(stage,point,color) \ G_STMT_START { \ const ClutterPoint *__p = (point); \ const ClutterColor *__c = (color); \ ClutterActor *__stage = (stage); \ ClutterColor __res; \ if (clutter_test_check_color_at_point (__stage, __p, __c, &__res)) ; else { \ char *__str1 = clutter_color_to_string (__c); \ char *__str2 = clutter_color_to_string (&__res); \ char *__msg = g_strdup_printf ("assertion failed (color %s at %.2f,%.2f): found color %s", \ __str1, __p->x, __p->y, __str2); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \ free (__msg); \ free (__str1); \ free (__str2); \ } \ } G_STMT_END CLUTTER_AVAILABLE_IN_1_18 gboolean clutter_test_check_actor_at_point (ClutterActor *stage, const ClutterPoint *point, ClutterActor *actor, ClutterActor **result); CLUTTER_AVAILABLE_IN_1_18 gboolean clutter_test_check_color_at_point (ClutterActor *stage, const ClutterPoint *point, const ClutterColor *color, ClutterColor *result); G_END_DECLS #endif /* __CLUTTER_TEST_UTILS_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-keysyms-table.c������������������������������������������������0000664�0001750�0001750�00000400532�14211404421�022721� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "clutter-build-config.h" #include <glib.h> #include "clutter-event.h" /* Code below from GDK, which contains following comment: * * Thanks to Markus G. Kuhn <mkuhn@acm.org> for the ksysym<->Unicode * mapping functions, from the xterm sources. */ static const struct { unsigned short keysym; unsigned short ucs; } clutter_keysym_to_unicode_tab[] = { { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ { 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ { 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ { 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */ { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ { 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ { 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ { 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ { 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ { 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ { 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ { 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ { 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ { 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ { 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ { 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ { 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ { 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ { 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ { 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ { 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ { 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ { 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ { 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ { 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ { 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */ { 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ { 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */ { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ { 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */ { 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */ { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ { 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */ { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ { 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */ { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ { 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */ { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ { 0x06ad, 0x0491 }, /* Ukrainian_ghe_with_upturn ґ CYRILLIC SMALL LETTER GHE WITH UPTURN */ { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ { 0x06bd, 0x0490 }, /* Ukrainian_GHE_WITH_UPTURN Ґ CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ { 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ { 0x07a5, 0x03aa }, /* Greek_IOTAdieresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ { 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ /* 0x08a1 leftradical ? ??? */ /* 0x08a2 topleftradical ? ??? */ /* 0x08a3 horizconnector ? ??? */ { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ /* 0x08a7 topleftsqbracket ? ??? */ /* 0x08a8 botleftsqbracket ? ??? */ /* 0x08a9 toprightsqbracket ? ??? */ /* 0x08aa botrightsqbracket ? ??? */ /* 0x08ab topleftparens ? ??? */ /* 0x08ac botleftparens ? ??? */ /* 0x08ad toprightparens ? ??? */ /* 0x08ae botrightparens ? ??? */ /* 0x08af leftmiddlecurlybrace ? ??? */ /* 0x08b0 rightmiddlecurlybrace ? ??? */ /* 0x08b1 topleftsummation ? ??? */ /* 0x08b2 botleftsummation ? ??? */ /* 0x08b3 topvertsummationconnector ? ??? */ /* 0x08b4 botvertsummationconnector ? ??? */ /* 0x08b5 toprightsummation ? ??? */ /* 0x08b6 botrightsummation ? ??? */ /* 0x08b7 rightmiddlesummation ? ??? */ { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ { 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */ /* 0x08c9 similarequal ? ??? */ { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ { 0x08dd, 0x222a }, /* union ∪ UNION */ { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ { 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */ { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ /* 0x09ef horizlinescan1 ? ??? */ /* 0x09f0 horizlinescan3 ? ??? */ { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ /* 0x09f2 horizlinescan7 ? ??? */ /* 0x09f3 horizlinescan9 ? ??? */ { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ { 0x0aaa, 0x2013 }, /* endash – EN DASH */ /* 0x0aac signifblank ? ??? */ { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ /* 0x0aaf doubbaselinedot ? ??? */ { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ /* 0x0abf marker ? ??? */ { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ /* 0x0acb trademarkincircle ? ??? */ { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ { 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */ { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ /* 0x0ada hexagram ? ??? */ { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ { 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */ { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ { 0x0af1, 0x2020 }, /* dagger † DAGGER */ { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ { 0x0afc, 0x2038 }, /* caret ‸ CARET */ { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ /* 0x0aff cursor ? ??? */ { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ { 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */ { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */ { 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */ { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ { 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */ { 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */ { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ { 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */ { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ { 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */ { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ { 0x0dde, 0x0e3e }, /* Thai_maihanakat_maitho ฾ ??? */ { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ /* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */ { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ /* 0x0ef9 Hangul_J_KkogjiDalrinIeung ? ??? */ { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ { 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */ { 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */ { 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */ { 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */ { 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */ { 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */ { 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */ { 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */ { 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */ { 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */ { 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */ { 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */ { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ /* Following items added to GTK, not in the xterm table */ /* Numeric keypad */ { 0xFF80 /* Space */, ' ' }, { 0xFFAA /* Multiply */, '*' }, { 0xFFAB /* Add */, '+' }, { 0xFFAC /* Separator */, ',' }, { 0xFFAD /* Subtract */, '-' }, { 0xFFAE /* Decimal */, '.' }, { 0xFFAF /* Divide */, '/' }, { 0xFFB0 /* 0 */, '0' }, { 0xFFB1 /* 1 */, '1' }, { 0xFFB2 /* 2 */, '2' }, { 0xFFB3 /* 3 */, '3' }, { 0xFFB4 /* 4 */, '4' }, { 0xFFB5 /* 5 */, '5' }, { 0xFFB6 /* 6 */, '6' }, { 0xFFB7 /* 7 */, '7' }, { 0xFFB8 /* 8 */, '8' }, { 0xFFB9 /* 9 */, '9' }, { 0xFFBD /* Equal */, '=' }, /* End numeric keypad */ }; static const int clutter_keysym_to_unicode_tab_size = G_N_ELEMENTS (clutter_keysym_to_unicode_tab); /** * clutter_keysym_to_unicode: * @keyval: a key symbol * * Converts @keyval from a Clutter key symbol to the corresponding * ISO10646 (Unicode) character. * * Return value: a Unicode character, or 0 if there is no corresponding * character. */ guint32 clutter_keysym_to_unicode (guint keyval) { int min = 0; int max = clutter_keysym_to_unicode_tab_size - 1; int mid; /* First check for Latin-1 characters (1:1 mapping) */ if ((keyval >= 0x0020 && keyval <= 0x007e) || (keyval >= 0x00a0 && keyval <= 0x00ff)) return keyval; /* Also check for directly encoded 24-bit UCS characters: */ if ((keyval & 0xff000000) == 0x01000000) return keyval & 0x00ffffff; /* binary search in table */ while (max >= min) { mid = (min + max) / 2; if (clutter_keysym_to_unicode_tab[mid].keysym < keyval) min = mid + 1; else if (clutter_keysym_to_unicode_tab[mid].keysym > keyval) max = mid - 1; else { /* found it */ return clutter_keysym_to_unicode_tab[mid].ucs; } } /* No matching Unicode value found */ return 0; } static const struct { unsigned short keysym; unsigned short ucs; } clutter_unicode_to_keysym_tab[] = { { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ { 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ { 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ { 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ { 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ { 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ { 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ { 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ { 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ { 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ { 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ { 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ { 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ { 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ { 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */ { 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ { 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ { 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ { 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ { 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ { 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ { 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ { 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ { 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ { 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ { 0x07a5, 0x03aa }, /* Greek_IOTAdieresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ { 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ { 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */ { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ { 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */ { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ { 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */ { 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ { 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */ { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ { 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */ { 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */ { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ { 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */ { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ { 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */ { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ { 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */ { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ { 0x0aaa, 0x2013 }, /* endash – EN DASH */ { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ { 0x0af1, 0x2020 }, /* dagger † DAGGER */ { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ { 0x0afc, 0x2038 }, /* caret ‸ CARET */ { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ { 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */ { 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */ { 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */ { 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */ { 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */ { 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */ { 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */ { 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */ { 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */ { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ { 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */ { 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */ { 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */ { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ { 0x08dd, 0x222a }, /* union ∪ UNION */ { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ { 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */ { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ { 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */ { 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */ { 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */ { 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */ { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */ { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ { 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */ { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ { 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */ { 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */ { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ }; static const int clutter_unicode_to_keysym_tab_size = G_N_ELEMENTS (clutter_unicode_to_keysym_tab); /** * clutter_unicode_to_keysym: * @wc: a ISO10646 encoded character * * Convert from a ISO10646 character to a key symbol. * * Return value: the corresponding Clutter key symbol, if one exists. * or, if there is no corresponding symbol, wc | 0x01000000 * * Since: 1.10 */ guint clutter_unicode_to_keysym (guint32 wc) { int min = 0; int max = clutter_unicode_to_keysym_tab_size - 1; int mid; /* First check for Latin-1 characters (1:1 mapping) */ if ((wc >= 0x0020 && wc <= 0x007e) || (wc >= 0x00a0 && wc <= 0x00ff)) return wc; /* Binary search in table */ while (max >= min) { mid = (min + max) / 2; if (clutter_unicode_to_keysym_tab[mid].ucs < wc) min = mid + 1; else if (clutter_unicode_to_keysym_tab[mid].ucs > wc) max = mid - 1; else { /* found it */ return clutter_unicode_to_keysym_tab[mid].keysym; } } /* No matching keysym value found, return Unicode value plus 0x01000000 * (a convention introduced in the UTF-8 work on xterm). */ return wc | 0x01000000; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/Makefile.am.enums������������������������������������������������������0000664�0001750�0001750�00000003010�14211404421�021454� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Rules for generating enumeration types using glib-mkenums # # Define: # glib_enum_h = header template file # glib_enum_c = source template file # glib_enum_headers = list of headers to parse # # before including Makefile.am.enums. You will also need to have # the following targets already defined: # # CLEANFILES # DISTCLEANFILES # BUILT_SOURCES # EXTRA_DIST # # Author: Emmanuele Bassi <ebassi@linux.intel.com> # Basic sanity checks $(if $(GLIB_MKENUMS),,$(error Need to define GLIB_MKENUMS)) $(if $(or $(glib_enum_h), \ $(glib_enum_c)),, \ $(error Need to define glib_enum_h and glib_enum_c)) $(if $(glib_enum_headers),,$(error Need to define glib_enum_headers)) enum_tmpl_h=$(addprefix $(srcdir)/, $(glib_enum_h:.h=.h.in)) enum_tmpl_c=$(addprefix $(srcdir)/, $(glib_enum_c:.c=.c.in)) enum_headers=$(addprefix $(srcdir)/, $(glib_enum_headers)) CLEANFILES += stamp-enum-types DISTCLEANFILES += $(glib_enum_h) $(glib_enum_c) BUILT_SOURCES += $(glib_enum_h) $(glib_enum_c) EXTRA_DIST += $(enum_tmpl_h) $(enum_tmpl_c) stamp-enum-types: $(enum_headers) $(enum_tmpl_h) $(AM_V_GEN)$(GLIB_MKENUMS) \ --template $(enum_tmpl_h) \ $(enum_headers) > xgen-eh \ && (cmp -s xgen-eh $(glib_enum_h) || cp -f xgen-eh $(glib_enum_h)) \ && rm -f xgen-eh \ && echo timestamp > $(@F) $(glib_enum_h): stamp-enum-types @true $(glib_enum_c): $(enum_headers) $(enum_tmpl_h) $(enum_tmpl_c) $(AM_V_GEN)$(GLIB_MKENUMS) \ --template $(enum_tmpl_c) \ $(enum_headers) > xgen-ec \ && cp -f xgen-ec $(glib_enum_c) \ && rm -f xgen-ec ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-transition.c���������������������������������������������������0000664�0001750�0001750�00000047631�14211404421�022331� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-transition * @Title: ClutterTransition * @Short_Description: Transition between two values * * #ClutterTransition is an abstract subclass of #ClutterTimeline that * computes the interpolation between two values, stored by a #ClutterInterval. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-transition.h" #include "clutter-animatable.h" #include "clutter-debug.h" #include "clutter-interval.h" #include "clutter-private.h" #include "clutter-timeline.h" #include <gobject/gvaluecollector.h> struct _ClutterTransitionPrivate { ClutterInterval *interval; ClutterAnimatable *animatable; guint remove_on_complete : 1; }; enum { PROP_0, PROP_INTERVAL, PROP_ANIMATABLE, PROP_REMOVE_ON_COMPLETE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static GQuark quark_animatable_set = 0; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterTransition, clutter_transition, CLUTTER_TYPE_TIMELINE) static void clutter_transition_attach (ClutterTransition *transition, ClutterAnimatable *animatable) { CLUTTER_TRANSITION_GET_CLASS (transition)->attached (transition, animatable); } static void clutter_transition_detach (ClutterTransition *transition, ClutterAnimatable *animatable) { CLUTTER_TRANSITION_GET_CLASS (transition)->detached (transition, animatable); } static void clutter_transition_real_compute_value (ClutterTransition *transition, ClutterAnimatable *animatable, ClutterInterval *interval, gdouble progress) { } static void clutter_transition_real_attached (ClutterTransition *transition, ClutterAnimatable *animatable) { } static void clutter_transition_real_detached (ClutterTransition *transition, ClutterAnimatable *animatable) { } static void clutter_transition_new_frame (ClutterTimeline *timeline, gint elapsed G_GNUC_UNUSED) { ClutterTransition *transition = CLUTTER_TRANSITION (timeline); ClutterTransitionPrivate *priv = transition->priv; gdouble progress; if (priv->interval == NULL || priv->animatable == NULL) return; progress = clutter_timeline_get_progress (timeline); CLUTTER_TRANSITION_GET_CLASS (timeline)->compute_value (transition, priv->animatable, priv->interval, progress); } static void clutter_transition_stopped (ClutterTimeline *timeline, gboolean is_finished) { ClutterTransitionPrivate *priv = CLUTTER_TRANSITION (timeline)->priv; if (is_finished && priv->animatable != NULL && priv->remove_on_complete) { clutter_transition_detach (CLUTTER_TRANSITION (timeline), priv->animatable); g_clear_object (&priv->animatable); g_object_unref (timeline); } } static void clutter_transition_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterTransition *transition = CLUTTER_TRANSITION (gobject); switch (prop_id) { case PROP_INTERVAL: clutter_transition_set_interval (transition, g_value_get_object (value)); break; case PROP_ANIMATABLE: clutter_transition_set_animatable (transition, g_value_get_object (value)); break; case PROP_REMOVE_ON_COMPLETE: clutter_transition_set_remove_on_complete (transition, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_transition_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterTransitionPrivate *priv = CLUTTER_TRANSITION (gobject)->priv; switch (prop_id) { case PROP_INTERVAL: g_value_set_object (value, priv->interval); break; case PROP_ANIMATABLE: g_value_set_object (value, priv->animatable); break; case PROP_REMOVE_ON_COMPLETE: g_value_set_boolean (value, priv->remove_on_complete); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_transition_dispose (GObject *gobject) { ClutterTransitionPrivate *priv = CLUTTER_TRANSITION (gobject)->priv; if (priv->animatable != NULL) clutter_transition_detach (CLUTTER_TRANSITION (gobject), priv->animatable); g_clear_object (&priv->interval); g_clear_object (&priv->animatable); G_OBJECT_CLASS (clutter_transition_parent_class)->dispose (gobject); } static void clutter_transition_class_init (ClutterTransitionClass *klass) { ClutterTimelineClass *timeline_class = CLUTTER_TIMELINE_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); quark_animatable_set = g_quark_from_static_string ("-clutter-transition-animatable-set"); klass->compute_value = clutter_transition_real_compute_value; klass->attached = clutter_transition_real_attached; klass->detached = clutter_transition_real_detached; timeline_class->new_frame = clutter_transition_new_frame; timeline_class->stopped = clutter_transition_stopped; gobject_class->set_property = clutter_transition_set_property; gobject_class->get_property = clutter_transition_get_property; gobject_class->dispose = clutter_transition_dispose; /** * ClutterTransition:interval: * * The #ClutterInterval used to describe the initial and final states * of the transition. * * Since: 1.10 */ obj_props[PROP_INTERVAL] = g_param_spec_object ("interval", P_("Interval"), P_("The interval of values to transition"), CLUTTER_TYPE_INTERVAL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterTransition:animatable: * * The #ClutterAnimatable instance currently being animated. * * Since: 1.10 */ obj_props[PROP_ANIMATABLE] = g_param_spec_object ("animatable", P_("Animatable"), P_("The animatable object"), CLUTTER_TYPE_ANIMATABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterTransition:remove-on-complete: * * Whether the #ClutterTransition should be automatically detached * from the #ClutterTransition:animatable instance whenever the * #ClutterTimeline::stopped signal is emitted. * * The #ClutterTransition:remove-on-complete property takes into * account the value of the #ClutterTimeline:repeat-count property, * and it only detaches the transition if the transition is not * repeating. * * Since: 1.10 */ obj_props[PROP_REMOVE_ON_COMPLETE] = g_param_spec_boolean ("remove-on-complete", P_("Remove on Complete"), P_("Detach the transition when completed"), FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_transition_init (ClutterTransition *self) { self->priv = clutter_transition_get_instance_private (self); } /** * clutter_transition_set_interval: * @transition: a #ClutterTransition * @interval: (allow-none): a #ClutterInterval, or %NULL * * Sets the #ClutterTransition:interval property using @interval. * * The @transition will acquire a reference on the @interval, sinking * the floating flag on it if necessary. * * Since: 1.10 */ void clutter_transition_set_interval (ClutterTransition *transition, ClutterInterval *interval) { ClutterTransitionPrivate *priv; g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_return_if_fail (interval == NULL || CLUTTER_IS_INTERVAL (interval)); priv = transition->priv; if (priv->interval == interval) return; g_clear_object (&priv->interval); if (interval != NULL) priv->interval = g_object_ref_sink (interval); g_object_notify_by_pspec (G_OBJECT (transition), obj_props[PROP_INTERVAL]); } /** * clutter_transition_get_interval: * @transition: a #ClutterTransition * * Retrieves the interval set using clutter_transition_set_interval() * * Return value: (transfer none): a #ClutterInterval, or %NULL; the returned * interval is owned by the #ClutterTransition and it should not be freed * directly * * Since: 1.10 */ ClutterInterval * clutter_transition_get_interval (ClutterTransition *transition) { g_return_val_if_fail (CLUTTER_IS_TRANSITION (transition), NULL); return transition->priv->interval; } /** * clutter_transition_set_animatable: * @transition: a #ClutterTransition * @animatable: (allow-none): a #ClutterAnimatable, or %NULL * * Sets the #ClutterTransition:animatable property. * * The @transition will acquire a reference to the @animatable instance, * and will call the #ClutterTransitionClass.attached() virtual function. * * If an existing #ClutterAnimatable is attached to @transition, the * reference will be released, and the #ClutterTransitionClass.detached() * virtual function will be called. * * Since: 1.10 */ void clutter_transition_set_animatable (ClutterTransition *transition, ClutterAnimatable *animatable) { ClutterTransitionPrivate *priv; g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_return_if_fail (animatable == NULL || CLUTTER_IS_ANIMATABLE (animatable)); priv = transition->priv; if (priv->animatable == animatable) return; if (priv->animatable != NULL) clutter_transition_detach (transition, priv->animatable); g_clear_object (&priv->animatable); if (animatable != NULL) { priv->animatable = g_object_ref (animatable); clutter_transition_attach (transition, priv->animatable); } } /** * clutter_transition_get_animatable: * @transition: a #ClutterTransition * * Retrieves the #ClutterAnimatable set using clutter_transition_set_animatable(). * * Return value: (transfer none): a #ClutterAnimatable, or %NULL; the returned * animatable is owned by the #ClutterTransition, and it should not be freed * directly. * * Since: 1.10 */ ClutterAnimatable * clutter_transition_get_animatable (ClutterTransition *transition) { g_return_val_if_fail (CLUTTER_IS_TRANSITION (transition), NULL); return transition->priv->animatable; } /** * clutter_transition_set_remove_on_complete: * @transition: a #ClutterTransition * @remove_complete: whether to detach @transition when complete * * Sets whether @transition should be detached from the #ClutterAnimatable * set using clutter_transition_set_animatable() when the * #ClutterTimeline::completed signal is emitted. * * Since: 1.10 */ void clutter_transition_set_remove_on_complete (ClutterTransition *transition, gboolean remove_complete) { g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); remove_complete = !!remove_complete; if (transition->priv->remove_on_complete == remove_complete) return; transition->priv->remove_on_complete = remove_complete; g_object_notify_by_pspec (G_OBJECT (transition), obj_props[PROP_REMOVE_ON_COMPLETE]); } /** * clutter_transition_get_remove_on_complete: * @transition: a #ClutterTransition * * Retrieves the value of the #ClutterTransition:remove-on-complete property. * * Return value: %TRUE if the @transition should be detached when complete, * and %FALSE otherwise * * Since: 1.10 */ gboolean clutter_transition_get_remove_on_complete (ClutterTransition *transition) { g_return_val_if_fail (CLUTTER_IS_TRANSITION (transition), FALSE); return transition->priv->remove_on_complete; } typedef void (* IntervalSetFunc) (ClutterInterval *interval, const GValue *value); static inline void clutter_transition_set_value (ClutterTransition *transition, IntervalSetFunc interval_set_func, const GValue *value) { ClutterTransitionPrivate *priv = transition->priv; GType interval_type; if (priv->interval == NULL) { priv->interval = clutter_interval_new_with_values (G_VALUE_TYPE (value), NULL, NULL); g_object_ref_sink (priv->interval); } interval_type = clutter_interval_get_value_type (priv->interval); if (!g_type_is_a (G_VALUE_TYPE (value), interval_type)) { if (g_value_type_compatible (G_VALUE_TYPE (value), interval_type)) { interval_set_func (priv->interval, value); return; } if (g_value_type_transformable (G_VALUE_TYPE (value), interval_type)) { GValue transform = G_VALUE_INIT; g_value_init (&transform, interval_type); if (g_value_transform (value, &transform)) interval_set_func (priv->interval, &transform); else { g_warning ("%s: Unable to convert a value of type '%s' into " "the value type '%s' of the interval used by the " "transition.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)), g_type_name (interval_type)); } g_value_unset (&transform); } } else interval_set_func (priv->interval, value); } /** * clutter_transition_set_from_value: (rename-to clutter_transition_set_from) * @transition: a #ClutterTransition * @value: a #GValue with the initial value of the transition * * Sets the initial value of the transition. * * This is a convenience function that will either create the * #ClutterInterval used by @transition, or will update it if * the #ClutterTransition:interval is already set. * * This function will copy the contents of @value, so it is * safe to call g_value_unset() after it returns. * * If @transition already has a #ClutterTransition:interval set, * then @value must hold the same type, or a transformable type, * as the interval's #ClutterInterval:value-type property. * * This function is meant to be used by language bindings. * * Since: 1.12 */ void clutter_transition_set_from_value (ClutterTransition *transition, const GValue *value) { g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_return_if_fail (G_IS_VALUE (value)); clutter_transition_set_value (transition, clutter_interval_set_initial_value, value); } /** * clutter_transition_set_to_value: (rename-to clutter_transition_set_to) * @transition: a #ClutterTransition * @value: a #GValue with the final value of the transition * * Sets the final value of the transition. * * This is a convenience function that will either create the * #ClutterInterval used by @transition, or will update it if * the #ClutterTransition:interval is already set. * * This function will copy the contents of @value, so it is * safe to call g_value_unset() after it returns. * * If @transition already has a #ClutterTransition:interval set, * then @value must hold the same type, or a transformable type, * as the interval's #ClutterInterval:value-type property. * * This function is meant to be used by language bindings. * * Since: 1.12 */ void clutter_transition_set_to_value (ClutterTransition *transition, const GValue *value) { g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_return_if_fail (G_IS_VALUE (value)); clutter_transition_set_value (transition, clutter_interval_set_final_value, value); } /** * clutter_transition_set_from: (skip) * @transition: a #ClutterTransition * @value_type: the type of the value to set * @...: the initial value * * Sets the initial value of the transition. * * This is a convenience function that will either create the * #ClutterInterval used by @transition, or will update it if * the #ClutterTransition:interval is already set. * * If @transition already has a #ClutterTransition:interval set, * then @value must hold the same type, or a transformable type, * as the interval's #ClutterInterval:value-type property. * * This is a convenience function for the C API; language bindings * should use clutter_transition_set_from_value() instead. * * Since: 1.12 */ void clutter_transition_set_from (ClutterTransition *transition, GType value_type, ...) { GValue value = G_VALUE_INIT; gchar *error = NULL; va_list args; g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_return_if_fail (value_type != G_TYPE_INVALID); va_start (args, value_type); G_VALUE_COLLECT_INIT (&value, value_type, args, 0, &error); va_end (args); if (error != NULL) { g_warning ("%s: %s", G_STRLOC, error); free (error); return; } clutter_transition_set_value (transition, clutter_interval_set_initial_value, &value); g_value_unset (&value); } /** * clutter_transition_set_to: (skip) * @transition: a #ClutterTransition * @value_type: the type of the value to set * @...: the final value * * Sets the final value of the transition. * * This is a convenience function that will either create the * #ClutterInterval used by @transition, or will update it if * the #ClutterTransition:interval is already set. * * If @transition already has a #ClutterTransition:interval set, * then @value must hold the same type, or a transformable type, * as the interval's #ClutterInterval:value-type property. * * This is a convenience function for the C API; language bindings * should use clutter_transition_set_to_value() instead. * * Since: 1.12 */ void clutter_transition_set_to (ClutterTransition *transition, GType value_type, ...) { GValue value = G_VALUE_INIT; gchar *error = NULL; va_list args; g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_return_if_fail (value_type != G_TYPE_INVALID); va_start (args, value_type); G_VALUE_COLLECT_INIT (&value, value_type, args, 0, &error); va_end (args); if (error != NULL) { g_warning ("%s: %s", G_STRLOC, error); free (error); return; } clutter_transition_set_value (transition, clutter_interval_set_final_value, &value); g_value_unset (&value); } �������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-grid-layout.h��������������������������������������������������0000664�0001750�0001750�00000015475�14211404421�022405� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Red Hat, Inc. * Copyright (C) 2012 Bastian Winkler <buz@netbuz.org> * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Bastian Winkler <buz@netbuz.org> * * Based on GtkGrid widget by: * Matthias Clasen */ #ifndef __CLUTTER_GRID_LAYOUT_H__ #define __CLUTTER_GRID_LAYOUT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-layout-manager.h> G_BEGIN_DECLS #define CLUTTER_TYPE_GRID_LAYOUT (clutter_grid_layout_get_type ()) #define CLUTTER_GRID_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_GRID_LAYOUT, ClutterGridLayout)) #define CLUTTER_IS_GRID_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_GRID_LAYOUT)) #define CLUTTER_GRID_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_GRID_LAYOUT, ClutterGridLayoutClass)) #define CLUTTER_IS_GRID_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_GRID_LAYOUT)) #define CLUTTER_GRID_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_GRID_LAYOUT, ClutterGridLayoutClass)) typedef struct _ClutterGridLayout ClutterGridLayout; typedef struct _ClutterGridLayoutPrivate ClutterGridLayoutPrivate; typedef struct _ClutterGridLayoutClass ClutterGridLayoutClass; /** * ClutterGridLayout: * * The #ClutterGridLayout structure contains only private data * and should be accessed using the provided API * * Since: 1.12 */ struct _ClutterGridLayout { /*< private >*/ ClutterLayoutManager parent_instance; ClutterGridLayoutPrivate *priv; }; /** * ClutterGridLayoutClass: * * The #ClutterGridLayoutClass structure contains only private * data and should be accessed using the provided API * * Since: 1.12 */ struct _ClutterGridLayoutClass { /*< private >*/ ClutterLayoutManagerClass parent_class; gpointer _padding[8]; }; CLUTTER_AVAILABLE_IN_1_12 GType clutter_grid_layout_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterLayoutManager * clutter_grid_layout_new (void); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_attach (ClutterGridLayout *layout, ClutterActor *child, gint left, gint top, gint width, gint height); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_attach_next_to (ClutterGridLayout *layout, ClutterActor *child, ClutterActor *sibling, ClutterGridPosition side, gint width, gint height); CLUTTER_AVAILABLE_IN_1_12 ClutterActor * clutter_grid_layout_get_child_at (ClutterGridLayout *layout, gint left, gint top); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_insert_row (ClutterGridLayout *layout, gint position); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_insert_column (ClutterGridLayout *layout, gint position); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_insert_next_to (ClutterGridLayout *layout, ClutterActor *sibling, ClutterGridPosition side); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_set_orientation (ClutterGridLayout *layout, ClutterOrientation orientation); CLUTTER_AVAILABLE_IN_1_12 ClutterOrientation clutter_grid_layout_get_orientation (ClutterGridLayout *layout); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_set_column_spacing (ClutterGridLayout *layout, guint spacing); CLUTTER_AVAILABLE_IN_1_12 guint clutter_grid_layout_get_column_spacing (ClutterGridLayout *layout); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_set_row_spacing (ClutterGridLayout *layout, guint spacing); CLUTTER_AVAILABLE_IN_1_12 guint clutter_grid_layout_get_row_spacing (ClutterGridLayout *layout); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_set_column_homogeneous (ClutterGridLayout *layout, gboolean homogeneous); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_grid_layout_get_column_homogeneous (ClutterGridLayout *layout); CLUTTER_AVAILABLE_IN_1_12 void clutter_grid_layout_set_row_homogeneous (ClutterGridLayout *layout, gboolean homogeneous); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_grid_layout_get_row_homogeneous (ClutterGridLayout *layout); G_END_DECLS #endif /* __CLUTTER_GRID_LAYOUT_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-actor-meta.c���������������������������������������������������0000664�0001750�0001750�00000041162�14211404421�022164� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-actor-meta * @Title: ClutterActorMeta * @Short_Description: Base class of actor modifiers * @See_Also: #ClutterAction, #ClutterConstraint * * #ClutterActorMeta is an abstract class providing a common API for * modifiers of #ClutterActor behaviour, appearance or layout. * * A #ClutterActorMeta can only be owned by a single #ClutterActor at * any time. * * Every sub-class of #ClutterActorMeta should check if the * #ClutterActorMeta:enabled property is set to %TRUE before applying * any kind of modification. * * #ClutterActorMeta is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-actor-meta-private.h" #include "clutter-debug.h" #include "clutter-private.h" struct _ClutterActorMetaPrivate { ClutterActor *actor; guint destroy_id; gchar *name; guint is_enabled : 1; gint priority; }; enum { PROP_0, PROP_ACTOR, PROP_NAME, PROP_ENABLED, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterActorMeta, clutter_actor_meta, G_TYPE_INITIALLY_UNOWNED) static void on_actor_destroy (ClutterActor *actor, ClutterActorMeta *meta) { meta->priv->actor = NULL; } static void clutter_actor_meta_real_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { if (meta->priv->actor == actor) return; if (meta->priv->destroy_id != 0) { g_signal_handler_disconnect (meta->priv->actor, meta->priv->destroy_id); meta->priv->destroy_id = 0; } meta->priv->actor = actor; if (meta->priv->actor != NULL) meta->priv->destroy_id = g_signal_connect (meta->priv->actor, "destroy", G_CALLBACK (on_actor_destroy), meta); } static void clutter_actor_meta_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject); switch (prop_id) { case PROP_NAME: clutter_actor_meta_set_name (meta, g_value_get_string (value)); break; case PROP_ENABLED: clutter_actor_meta_set_enabled (meta, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_actor_meta_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject); switch (prop_id) { case PROP_ACTOR: g_value_set_object (value, meta->priv->actor); break; case PROP_NAME: g_value_set_string (value, meta->priv->name); break; case PROP_ENABLED: g_value_set_boolean (value, meta->priv->is_enabled); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_actor_meta_finalize (GObject *gobject) { ClutterActorMetaPrivate *priv = CLUTTER_ACTOR_META (gobject)->priv; if (priv->destroy_id != 0 && priv->actor != NULL) g_signal_handler_disconnect (priv->actor, priv->destroy_id); free (priv->name); G_OBJECT_CLASS (clutter_actor_meta_parent_class)->finalize (gobject); } void clutter_actor_meta_class_init (ClutterActorMetaClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); klass->set_actor = clutter_actor_meta_real_set_actor; /** * ClutterActorMeta:actor: * * The #ClutterActor attached to the #ClutterActorMeta instance * * Since: 1.4 */ obj_props[PROP_ACTOR] = g_param_spec_object ("actor", P_("Actor"), P_("The actor attached to the meta"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READABLE); /** * ClutterActorMeta:name: * * The unique name to access the #ClutterActorMeta * * Since: 1.4 */ obj_props[PROP_NAME] = g_param_spec_string ("name", P_("Name"), P_("The name of the meta"), NULL, CLUTTER_PARAM_READWRITE); /** * ClutterActorMeta:enabled: * * Whether or not the #ClutterActorMeta is enabled * * Since: 1.4 */ obj_props[PROP_ENABLED] = g_param_spec_boolean ("enabled", P_("Enabled"), P_("Whether the meta is enabled"), TRUE, CLUTTER_PARAM_READWRITE); gobject_class->finalize = clutter_actor_meta_finalize; gobject_class->set_property = clutter_actor_meta_set_property; gobject_class->get_property = clutter_actor_meta_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } void clutter_actor_meta_init (ClutterActorMeta *self) { self->priv = clutter_actor_meta_get_instance_private (self); self->priv->is_enabled = TRUE; self->priv->priority = CLUTTER_ACTOR_META_PRIORITY_DEFAULT; } /** * clutter_actor_meta_set_name: * @meta: a #ClutterActorMeta * @name: the name of @meta * * Sets the name of @meta * * The name can be used to identify the #ClutterActorMeta instance * * Since: 1.4 */ void clutter_actor_meta_set_name (ClutterActorMeta *meta, const gchar *name) { g_return_if_fail (CLUTTER_IS_ACTOR_META (meta)); if (g_strcmp0 (meta->priv->name, name) == 0) return; free (meta->priv->name); meta->priv->name = g_strdup (name); g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_NAME]); } /** * clutter_actor_meta_get_name: * @meta: a #ClutterActorMeta * * Retrieves the name set using clutter_actor_meta_set_name() * * Return value: (transfer none): the name of the #ClutterActorMeta * instance, or %NULL if none was set. The returned string is owned * by the #ClutterActorMeta instance and it should not be modified * or freed * * Since: 1.4 */ const gchar * clutter_actor_meta_get_name (ClutterActorMeta *meta) { g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL); return meta->priv->name; } /** * clutter_actor_meta_set_enabled: * @meta: a #ClutterActorMeta * @is_enabled: whether @meta is enabled * * Sets whether @meta should be enabled or not * * Since: 1.4 */ void clutter_actor_meta_set_enabled (ClutterActorMeta *meta, gboolean is_enabled) { g_return_if_fail (CLUTTER_IS_ACTOR_META (meta)); is_enabled = !!is_enabled; if (meta->priv->is_enabled == is_enabled) return; meta->priv->is_enabled = is_enabled; g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ENABLED]); } /** * clutter_actor_meta_get_enabled: * @meta: a #ClutterActorMeta * * Retrieves whether @meta is enabled * * Return value: %TRUE if the #ClutterActorMeta instance is enabled * * Since: 1.4 */ gboolean clutter_actor_meta_get_enabled (ClutterActorMeta *meta) { g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), FALSE); return meta->priv->is_enabled; } /* * _clutter_actor_meta_set_actor * @meta: a #ClutterActorMeta * @actor: a #ClutterActor or %NULL * * Sets or unsets a back pointer to the #ClutterActor that owns * the @meta * * Since: 1.4 */ void _clutter_actor_meta_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { g_return_if_fail (CLUTTER_IS_ACTOR_META (meta)); g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); CLUTTER_ACTOR_META_GET_CLASS (meta)->set_actor (meta, actor); } /** * clutter_actor_meta_get_actor: * @meta: a #ClutterActorMeta * * Retrieves a pointer to the #ClutterActor that owns @meta * * Return value: (transfer none): a pointer to a #ClutterActor or %NULL * * Since: 1.4 */ ClutterActor * clutter_actor_meta_get_actor (ClutterActorMeta *meta) { g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL); return meta->priv->actor; } void _clutter_actor_meta_set_priority (ClutterActorMeta *meta, gint priority) { g_return_if_fail (CLUTTER_IS_ACTOR_META (meta)); /* This property shouldn't be modified after the actor meta is in use because ClutterMetaGroup doesn't resort the list when it changes. If we made the priority public then we could either make the priority a construct-only property or listen for notifications on the property from the ClutterMetaGroup and resort. */ g_return_if_fail (meta->priv->actor == NULL); meta->priv->priority = priority; } gint _clutter_actor_meta_get_priority (ClutterActorMeta *meta) { g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), 0); return meta->priv->priority; } gboolean _clutter_actor_meta_is_internal (ClutterActorMeta *meta) { gint priority = meta->priv->priority; return (priority <= CLUTTER_ACTOR_META_PRIORITY_INTERNAL_LOW || priority >= CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH); } /* * ClutterMetaGroup: a collection of ClutterActorMeta instances */ G_DEFINE_TYPE (ClutterMetaGroup, _clutter_meta_group, G_TYPE_OBJECT); static void _clutter_meta_group_dispose (GObject *gobject) { _clutter_meta_group_clear_metas (CLUTTER_META_GROUP (gobject)); G_OBJECT_CLASS (_clutter_meta_group_parent_class)->dispose (gobject); } static void _clutter_meta_group_class_init (ClutterMetaGroupClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = _clutter_meta_group_dispose; } static void _clutter_meta_group_init (ClutterMetaGroup *self) { } /* * _clutter_meta_group_add_meta: * @group: a #ClutterMetaGroup * @meta: a #ClutterActorMeta to add * * Adds @meta to @group * * This function will remove the floating reference of @meta or, if the * floating reference has already been sunk, add a reference to it */ void _clutter_meta_group_add_meta (ClutterMetaGroup *group, ClutterActorMeta *meta) { GList *prev = NULL, *l; if (meta->priv->actor != NULL) { g_warning ("The meta of type '%s' with name '%s' is " "already attached to actor '%s'", G_OBJECT_TYPE_NAME (meta), meta->priv->name != NULL ? meta->priv->name : "<unknown>", clutter_actor_get_name (meta->priv->actor) != NULL ? clutter_actor_get_name (meta->priv->actor) : G_OBJECT_TYPE_NAME (meta->priv->actor)); return; } /* Find a meta that has lower priority and insert before that */ for (l = group->meta; l; l = l->next) if (_clutter_actor_meta_get_priority (l->data) < _clutter_actor_meta_get_priority (meta)) break; else prev = l; if (prev == NULL) group->meta = g_list_prepend (group->meta, meta); else { prev->next = g_list_prepend (prev->next, meta); prev->next->prev = prev; } g_object_ref_sink (meta); _clutter_actor_meta_set_actor (meta, group->actor); } /* * _clutter_meta_group_remove_meta: * @group: a #ClutterMetaGroup * @meta: a #ClutterActorMeta to remove * * Removes @meta from @group and releases the reference being held on it */ void _clutter_meta_group_remove_meta (ClutterMetaGroup *group, ClutterActorMeta *meta) { if (meta->priv->actor != group->actor) { g_warning ("The meta of type '%s' with name '%s' is not " "attached to the actor '%s'", G_OBJECT_TYPE_NAME (meta), meta->priv->name != NULL ? meta->priv->name : "<unknown>", clutter_actor_get_name (group->actor) != NULL ? clutter_actor_get_name (group->actor) : G_OBJECT_TYPE_NAME (group->actor)); return; } _clutter_actor_meta_set_actor (meta, NULL); group->meta = g_list_remove (group->meta, meta); g_object_unref (meta); } /* * _clutter_meta_group_peek_metas: * @group: a #ClutterMetaGroup * * Returns a pointer to the #ClutterActorMeta list * * Return value: a const pointer to the #GList of #ClutterActorMeta */ const GList * _clutter_meta_group_peek_metas (ClutterMetaGroup *group) { return group->meta; } /* * _clutter_meta_group_get_metas_no_internal: * @group: a #ClutterMetaGroup * * Returns a new allocated list containing all of the metas that don't * have an internal priority. * * Return value: A GList containing non-internal metas. Free with * g_list_free. */ GList * _clutter_meta_group_get_metas_no_internal (ClutterMetaGroup *group) { GList *ret = NULL; GList *l; /* Build a new list filtering out the internal metas */ for (l = group->meta; l; l = l->next) if (!_clutter_actor_meta_is_internal (l->data)) ret = g_list_prepend (ret, l->data); return g_list_reverse (ret); } /* * _clutter_meta_group_has_metas_no_internal: * @group: a #ClutterMetaGroup * * Returns whether the group has any metas that don't have an internal priority. * * Return value: %TRUE if metas without internal priority exist * %FALSE otherwise */ gboolean _clutter_meta_group_has_metas_no_internal (ClutterMetaGroup *group) { GList *l; for (l = group->meta; l; l = l->next) if (!_clutter_actor_meta_is_internal (l->data)) return TRUE; return FALSE; } /* * _clutter_meta_group_clear_metas: * @group: a #ClutterMetaGroup * * Clears @group of all #ClutterActorMeta instances and releases * the reference on them */ void _clutter_meta_group_clear_metas (ClutterMetaGroup *group) { g_list_foreach (group->meta, (GFunc) _clutter_actor_meta_set_actor, NULL); g_list_foreach (group->meta, (GFunc) g_object_unref, NULL); g_list_free (group->meta); group->meta = NULL; } /* * _clutter_meta_group_clear_metas_no_internal: * @group: a #ClutterMetaGroup * * Clears @group of all #ClutterActorMeta instances that don't have an * internal priority and releases the reference on them */ void _clutter_meta_group_clear_metas_no_internal (ClutterMetaGroup *group) { GList *internal_list = NULL; GList *l, *next; for (l = group->meta; l; l = next) { next = l->next; if (_clutter_actor_meta_is_internal (l->data)) { if (internal_list) internal_list->prev = l; l->next = internal_list; l->prev = NULL; internal_list = l; } else { _clutter_actor_meta_set_actor (l->data, NULL); g_object_unref (l->data); g_list_free_1 (l); } } group->meta = g_list_reverse (internal_list); } /* * _clutter_meta_group_get_meta: * @group: a #ClutterMetaGroup * @name: the name of the #ClutterActorMeta to retrieve * * Retrieves a named #ClutterActorMeta from @group * * Return value: a #ClutterActorMeta for the given name, or %NULL */ ClutterActorMeta * _clutter_meta_group_get_meta (ClutterMetaGroup *group, const gchar *name) { GList *l; for (l = group->meta; l != NULL; l = l->next) { ClutterActorMeta *meta = l->data; if (g_strcmp0 (meta->priv->name, name) == 0) return meta; } return NULL; } /*< private > * clutter_actor_meta_get_debug_name: * @meta: a #ClutterActorMeta * * Retrieves the name of the @meta for debugging purposes. * * Return value: (transfer none): the name of the @meta. The returned * string is owned by the @meta instance and it should not be * modified or freed */ const gchar * _clutter_actor_meta_get_debug_name (ClutterActorMeta *meta) { return meta->priv->name != NULL ? meta->priv->name : G_OBJECT_TYPE_NAME (meta); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/egl/�������������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�017047� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/egl/clutter-backend-eglnative.c����������������������������������������0000664�0001750�0001750�00000025646�14211404421�024253� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010,2011 Intel Corporation. * 2011 Giovanni Campagna <scampa.giovanni@gmail.com> * * 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, see <http://www.gnu.org/licenses/>. * Authors: * Matthew Allum * Emmanuele Bassi * Robert Bragg * Neil Roberts */ #include "clutter-build-config.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include "clutter-backend-eglnative.h" /* This is a Cogl based backend */ #include "cogl/clutter-stage-cogl.h" #ifdef HAVE_EVDEV #include "evdev/clutter-device-manager-evdev.h" #endif #include "clutter-debug.h" #include "clutter-private.h" #include "clutter-main.h" #include "clutter-stage-private.h" #include "clutter-settings-private.h" #ifdef COGL_HAS_EGL_SUPPORT #include "clutter-egl.h" #endif G_DEFINE_TYPE (ClutterBackendEglNative, clutter_backend_egl_native, CLUTTER_TYPE_BACKEND); static void clutter_backend_egl_native_dispose (GObject *gobject) { ClutterBackendEglNative *backend_egl_native = CLUTTER_BACKEND_EGL_NATIVE (gobject); g_clear_object (&backend_egl_native->xsettings); if (backend_egl_native->event_timer != NULL) { g_timer_destroy (backend_egl_native->event_timer); backend_egl_native->event_timer = NULL; } G_OBJECT_CLASS (clutter_backend_egl_native_parent_class)->dispose (gobject); } static void clutter_backend_egl_native_class_init (ClutterBackendEglNativeClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = clutter_backend_egl_native_dispose; } typedef struct { cairo_antialias_t cairo_antialias; gint clutter_font_antialias; cairo_hint_style_t cairo_hint_style; const char *clutter_font_hint_style; cairo_subpixel_order_t cairo_subpixel_order; const char *clutter_font_subpixel_order; } FontSettings; static void get_font_gsettings (GSettings *xsettings, FontSettings *output) { /* org.gnome.settings-daemon.GsdFontAntialiasingMode */ static const struct { cairo_antialias_t cairo_antialias; gint clutter_font_antialias; } antialiasings[] = { /* none=0 */ {CAIRO_ANTIALIAS_NONE, 0}, /* grayscale=1 */ {CAIRO_ANTIALIAS_GRAY, 1}, /* rgba=2 */ {CAIRO_ANTIALIAS_SUBPIXEL, 1}, }; /* org.gnome.settings-daemon.GsdFontHinting */ static const struct { cairo_hint_style_t cairo_hint_style; const char *clutter_font_hint_style; } hintings[] = { /* none=0 */ {CAIRO_HINT_STYLE_NONE, "hintnone"}, /* slight=1 */ {CAIRO_HINT_STYLE_SLIGHT, "hintslight"}, /* medium=2 */ {CAIRO_HINT_STYLE_MEDIUM, "hintmedium"}, /* full=3 */ {CAIRO_HINT_STYLE_FULL, "hintfull"}, }; /* org.gnome.settings-daemon.GsdFontRgbaOrder */ static const struct { cairo_subpixel_order_t cairo_subpixel_order; const char *clutter_font_subpixel_order; } rgba_orders[] = { /* rgba=0 */ {CAIRO_SUBPIXEL_ORDER_RGB, "rgb"}, /* XXX what is 'rgba'? */ /* rgb=1 */ {CAIRO_SUBPIXEL_ORDER_RGB, "rgb"}, /* bgr=2 */ {CAIRO_SUBPIXEL_ORDER_BGR, "bgr"}, /* vrgb=3 */ {CAIRO_SUBPIXEL_ORDER_VRGB, "vrgb"}, /* vbgr=4 */ {CAIRO_SUBPIXEL_ORDER_VBGR, "vbgr"}, }; guint i; i = g_settings_get_enum (xsettings, "hinting"); if (i < G_N_ELEMENTS (hintings)) { output->cairo_hint_style = hintings[i].cairo_hint_style; output->clutter_font_hint_style = hintings[i].clutter_font_hint_style; } else { output->cairo_hint_style = CAIRO_HINT_STYLE_DEFAULT; output->clutter_font_hint_style = NULL; } i = g_settings_get_enum (xsettings, "antialiasing"); if (i < G_N_ELEMENTS (antialiasings)) { output->cairo_antialias = antialiasings[i].cairo_antialias; output->clutter_font_antialias = antialiasings[i].clutter_font_antialias; } else { output->cairo_antialias = CAIRO_ANTIALIAS_DEFAULT; output->clutter_font_antialias = -1; } i = g_settings_get_enum (xsettings, "rgba-order"); if (i < G_N_ELEMENTS (rgba_orders)) { output->cairo_subpixel_order = rgba_orders[i].cairo_subpixel_order; output->clutter_font_subpixel_order = rgba_orders[i].clutter_font_subpixel_order; } else { output->cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; output->clutter_font_subpixel_order = NULL; } if (output->cairo_antialias == CAIRO_ANTIALIAS_GRAY) output->clutter_font_subpixel_order = "none"; } static void init_font_options (ClutterBackendEglNative *backend_egl_native) { GSettings *xsettings = backend_egl_native->xsettings; cairo_font_options_t *options = cairo_font_options_create (); FontSettings fs; get_font_gsettings (xsettings, &fs); cairo_font_options_set_hint_style (options, fs.cairo_hint_style); cairo_font_options_set_antialias (options, fs.cairo_antialias); cairo_font_options_set_subpixel_order (options, fs.cairo_subpixel_order); clutter_backend_set_font_options (CLUTTER_BACKEND (backend_egl_native), options); cairo_font_options_destroy (options); } static gboolean on_xsettings_change_event (GSettings *xsettings, gpointer keys, gint n_keys, gpointer user_data) { /* * A simpler alternative to this function that does not update the screen * immediately (like macOS :P): * * init_font_options (CLUTTER_BACKEND_EGL_NATIVE (user_data)); * * which has the added benefit of eliminating the need for all the * FontSettings.clutter_ fields. However the below approach is better for * testing settings and more consistent with the existing x11 backend... */ ClutterSettings *csettings = clutter_settings_get_default (); FontSettings fs; gint hinting; get_font_gsettings (xsettings, &fs); hinting = fs.cairo_hint_style == CAIRO_HINT_STYLE_NONE ? 0 : 1; g_object_set (csettings, "font-hinting", hinting, "font-hint-style", fs.clutter_font_hint_style, "font-antialias", fs.clutter_font_antialias, "font-subpixel-order", fs.clutter_font_subpixel_order, NULL); return FALSE; } static void clutter_backend_egl_native_init (ClutterBackendEglNative *backend_egl_native) { static const gchar xsettings_path[] = "org.gnome.settings-daemon.plugins.xsettings"; GSettingsSchemaSource *source = g_settings_schema_source_get_default (); GSettingsSchema *schema = g_settings_schema_source_lookup (source, xsettings_path, FALSE); if (!schema) { g_warning ("Failed to find schema: %s", xsettings_path); } else { backend_egl_native->xsettings = g_settings_new_full (schema, NULL, NULL); if (backend_egl_native->xsettings) { init_font_options (backend_egl_native); g_signal_connect (backend_egl_native->xsettings, "change-event", G_CALLBACK (on_xsettings_change_event), backend_egl_native); } } backend_egl_native->event_timer = g_timer_new (); } ClutterBackend * clutter_backend_egl_native_new (void) { return g_object_new (CLUTTER_TYPE_BACKEND_EGL_NATIVE, NULL); } /** * clutter_eglx_display: * * Retrieves the EGL display used by Clutter. * * Return value: the EGL display, or 0 * * Since: 0.6 * * Deprecated: 1.6: Use clutter_egl_get_egl_display() instead. */ EGLDisplay clutter_eglx_display (void) { return clutter_egl_get_egl_display (); } /** * clutter_egl_display: * * Retrieves the EGL display used by Clutter. * * Return value: the EGL display used by Clutter, or 0 * * Since: 0.6 * * Deprecated: 1.6: Use clutter_egl_get_egl_display() instead. */ EGLDisplay clutter_egl_display (void) { return clutter_egl_get_egl_display (); } /** * clutter_egl_get_egl_display: * * Retrieves the EGL display used by Clutter, if it supports the * EGL windowing system and if it is running using an EGL backend. * * Return value: the EGL display used by Clutter, or 0 * * Since: 1.6 */ EGLDisplay clutter_egl_get_egl_display (void) { ClutterBackend *backend; if (!_clutter_context_is_initialized ()) { g_critical ("The Clutter backend has not been initialized yet"); return 0; } backend = clutter_get_default_backend (); if (!CLUTTER_IS_BACKEND_EGL_NATIVE (backend)) { g_critical ("The Clutter backend is not an EGL backend"); return 0; } #if COGL_HAS_EGL_SUPPORT return cogl_egl_context_get_egl_display (backend->cogl_context); #else return 0; #endif } /** * clutter_egl_freeze_master_clock: * * Freezing the master clock makes Clutter stop processing events, * redrawing, and advancing timelines. This is necessary when implementing * a display server, to ensure that Clutter doesn't keep trying to page * flip when DRM master has been dropped, e.g. when VT switched away. * * The master clock starts out running, so if you are VT switched away on * startup, you need to call this immediately. * * If you're also using the evdev backend, make sure to also use * clutter_evdev_release_devices() to make sure that Clutter doesn't also * access revoked evdev devices when VT switched away. * * To unthaw a frozen master clock, use clutter_egl_thaw_master_clock(). * * Since: 1.20 */ void clutter_egl_freeze_master_clock (void) { ClutterMasterClock *master_clock; g_return_if_fail (CLUTTER_IS_BACKEND_EGL_NATIVE (clutter_get_default_backend ())); master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_set_paused (master_clock, TRUE); } /** * clutter_egl_thaw_master_clock: * * Thaws a master clock that has previously been frozen with * clutter_egl_freeze_master_clock(), and start pumping the master clock * again at the next iteration. Note that if you're switching back to your * own VT, you should probably also queue a stage redraw with * clutter_stage_ensure_redraw(). * * Since: 1.20 */ void clutter_egl_thaw_master_clock (void) { ClutterMasterClock *master_clock; g_return_if_fail (CLUTTER_IS_BACKEND_EGL_NATIVE (clutter_get_default_backend ())); master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_set_paused (master_clock, FALSE); _clutter_master_clock_start_running (master_clock); } ������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/egl/clutter-egl.h������������������������������������������������������0000664�0001750�0001750�00000004763�14211404421�021461� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * */ /** * SECTION:clutter-egl * @short_description: EGL specific API * * The EGL backend for Clutter provides some EGL specific API * * You need to include `clutter-egl.h` to have access to the functions documented here. */ #ifndef __CLUTTER_EGL_H__ #define __CLUTTER_EGL_H__ #include <glib.h> #ifdef COGL_HAS_XLIB_SUPPORT #include <X11/Xlib.h> #include <X11/Xatom.h> #include <X11/Xutil.h> #endif #include "clutter-egl-headers.h" #include <clutter/clutter.h> G_BEGIN_DECLS /** * clutter_eglx_display: * * Retrieves the #EGLDisplay used by Clutter, * if Clutter has been compiled with EGL and X11 support. * * Return value: the EGL display * * Since: 0.4 * * Deprecated: 1.6: Use clutter_egl_get_egl_display() instead */ CLUTTER_DEPRECATED_FOR(clutter_egl_get_egl_display) EGLDisplay clutter_eglx_display (void); /** * clutter_egl_display: * * Retrieves the #EGLDisplay used by Clutter * * Return value: the EGL display * * Deprecated: 1.6: Use clutter_egl_get_egl_display() instead */ CLUTTER_DEPRECATED_FOR(clutter_egl_get_egl_display) EGLDisplay clutter_egl_display (void); /** * clutter_egl_get_egl_display: * * Retrieves the #EGLDisplay used by Clutter. * * Return value: the EGL display * * Since: 1.6 */ CLUTTER_AVAILABLE_IN_1_6 EGLDisplay clutter_egl_get_egl_display (void); #ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT CLUTTER_AVAILABLE_IN_1_18 void clutter_egl_set_kms_fd (int fd); #endif CLUTTER_AVAILABLE_IN_1_20 void clutter_egl_freeze_master_clock (void); CLUTTER_AVAILABLE_IN_1_20 void clutter_egl_thaw_master_clock (void); G_END_DECLS #endif /* __CLUTTER_EGL_H__ */ �������������muffin-5.2.1/clutter/clutter/egl/clutter-egl-headers.h����������������������������������������������0000664�0001750�0001750�00000002727�14211404421�023070� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * Authored By Matthew Allum <mallum@openedhand.com> * Copyright (C) 2006-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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_EGL_HEADERS_H__ #define __CLUTTER_EGL_HEADERS_H__ /* Clutter relies on Cogl to abstract GLES1/2/OpenGL and GLX/EGL etc * so we simply include the Cogl header to pull in the appropriate EGL * header. */ #include <cogl/cogl.h> /* Since Cogl 1.11.2, the EGL headers are no longer included from * cogl.h when the experimental 2.0 API is requested. Clutter requests * this in its configure script so we need to switch the header we * include in that case. COGL_VERSION_CHECK is also new in 1.11.2 */ #ifdef COGL_VERSION_CHECK #if COGL_VERSION_CHECK (1, 11, 2) #include <cogl/cogl-egl.h> #endif #endif #endif /* __CLUTTER_EGL_HEADERS_H__ */ �����������������������������������������muffin-5.2.1/clutter/clutter/egl/clutter-backend-eglnative.h����������������������������������������0000664�0001750�0001750�00000005537�14211404421�024255� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2006, 2007 OpenedHand * Copyright (C) 2010 Intel Corp * 2011 Giovanni Campagna <scampa.giovanni@gmail.com> * * 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, see <http://www.gnu.org/licenses/>. * * Authors: * Matthew Allum * Robert Bragg */ #ifndef __CLUTTER_BACKEND_EGL_NATIVE_H__ #define __CLUTTER_BACKEND_EGL_NATIVE_H__ #include <glib-object.h> #include <cogl/cogl.h> #include <cogl/cogl-egl.h> #include <clutter/clutter-event.h> #include <clutter/clutter-backend.h> #include <clutter/clutter-device-manager.h> #include "clutter-backend-private.h" G_BEGIN_DECLS #define CLUTTER_TYPE_BACKEND_EGL_NATIVE (clutter_backend_egl_native_get_type ()) #define CLUTTER_BACKEND_EGL_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_EGL_NATIVE, ClutterBackendEglNative)) #define CLUTTER_IS_BACKEND_EGL_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_EGL_NATIVE)) #define CLUTTER_BACKEND_EGL_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_EGL_NATIVE, ClutterBackendEglNativeClass)) #define CLUTTER_IS_BACKEND_EGL_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_EGL_NATIVE)) #define CLUTTER_BACKEND_EGL_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_EGL_NATIVE, ClutterBackendEglNativeClass)) typedef struct _ClutterBackendEglNative ClutterBackendEglNative; typedef struct _ClutterBackendEglNativeClass ClutterBackendEglNativeClass; G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBackendEglNative, g_object_unref) struct _ClutterBackendEglNative { ClutterBackend parent_instance; /* device manager (ie evdev) */ ClutterDeviceManager *device_manager; /* event source */ GSource *event_source; /* event timer */ GTimer *event_timer; /* "xsettings" is still the defacto place for Xft settings, even in Wayland */ GSettings *xsettings; }; struct _ClutterBackendEglNativeClass { ClutterBackendClass parent_class; }; CLUTTER_AVAILABLE_IN_MUFFIN GType clutter_backend_egl_native_get_type (void) G_GNUC_CONST; ClutterBackend *clutter_backend_egl_native_new (void); G_END_DECLS #endif /* __CLUTTER_BACKEND_EGL_NATIVE_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-paint-node.h���������������������������������������������������0000664�0001750�0001750�00000011230�14211404421�022164� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_PAINT_NODE_H__ #define __CLUTTER_PAINT_NODE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <cogl/cogl.h> #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_PAINT_NODE (clutter_paint_node_get_type ()) #define CLUTTER_PAINT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PAINT_NODE, ClutterPaintNode)) #define CLUTTER_IS_PAINT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PAINT_NODE)) typedef struct _ClutterPaintNodePrivate ClutterPaintNodePrivate; typedef struct _ClutterPaintNodeClass ClutterPaintNodeClass; CLUTTER_AVAILABLE_IN_1_10 GType clutter_paint_node_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterPaintNode * clutter_paint_node_ref (ClutterPaintNode *node); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_node_unref (ClutterPaintNode *node); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_node_set_name (ClutterPaintNode *node, const char *name); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_node_add_child (ClutterPaintNode *node, ClutterPaintNode *child); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_node_add_rectangle (ClutterPaintNode *node, const ClutterActorBox *rect); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_node_add_texture_rectangle (ClutterPaintNode *node, const ClutterActorBox *rect, float x_1, float y_1, float x_2, float y_2); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_node_add_path (ClutterPaintNode *node, CoglPath *path); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_node_add_primitive (ClutterPaintNode *node, CoglPrimitive *primitive); /** * CLUTTER_VALUE_HOLDS_PAINT_NODE: * @value: a #GValue * * Evaluates to %TRUE if the @value has been initialized to hold * a #ClutterPaintNode. * * Since: 1.10 */ #define CLUTTER_VALUE_HOLDS_PAINT_NODE(value) (G_VALUE_HOLDS (value, CLUTTER_TYPE_PAINT_NODE)) CLUTTER_AVAILABLE_IN_1_10 void clutter_value_set_paint_node (GValue *value, gpointer node); CLUTTER_AVAILABLE_IN_1_10 void clutter_value_take_paint_node (GValue *value, gpointer node); CLUTTER_AVAILABLE_IN_1_10 gpointer clutter_value_get_paint_node (const GValue *value); CLUTTER_AVAILABLE_IN_1_10 gpointer clutter_value_dup_paint_node (const GValue *value); G_END_DECLS #endif /* __CLUTTER_PAINT_NODE_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-settings.c�����������������������������������������������������0000664�0001750�0001750�00000057055�14211404421�022000� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** * SECTION:clutter-settings * @Title: ClutterSettings * @Short_Description: Settings configuration * * Clutter depends on some settings to perform operations like detecting * multiple button press events, or font options to render text. * * Usually, Clutter will strive to use the platform's settings in order * to be as much integrated as possible. It is, however, possible to * change these settings on a per-application basis, by using the * #ClutterSettings singleton object and setting its properties. It is * also possible, for toolkit developers, to retrieve the settings from * the #ClutterSettings properties when implementing new UI elements, * for instance the default font name. * * #ClutterSettings is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-settings.h" #ifdef HAVE_PANGO_FT2 /* for pango_fc_font_map_cache_clear() */ #define PANGO_ENABLE_BACKEND #include <pango/pangofc-fontmap.h> #endif /* HAVE_PANGO_FT2 */ #include "clutter-debug.h" #include "clutter-settings-private.h" #include "clutter-stage-private.h" #include "clutter-private.h" #include <stdlib.h> #define DEFAULT_FONT_NAME "Sans 12" #define CLUTTER_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass)) #define CLUTTER_IS_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SETTINGS)) #define CLUTTER_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass)) /** * ClutterSettings: * * `ClutterSettings` is an opaque structure whose * members cannot be directly accessed. * * Since: 1.4 */ struct _ClutterSettings { GObject parent_instance; ClutterBackend *backend; gint double_click_time; gint double_click_distance; gint dnd_drag_threshold; gdouble resolution; gchar *font_name; gint font_dpi; gint xft_hinting; gint xft_antialias; gchar *xft_hint_style; gchar *xft_rgba; gint long_press_duration; guint last_fontconfig_timestamp; guint password_hint_time; gint unscaled_font_dpi; }; struct _ClutterSettingsClass { GObjectClass parent_class; }; enum { PROP_0, PROP_BACKEND, PROP_DOUBLE_CLICK_TIME, PROP_DOUBLE_CLICK_DISTANCE, PROP_DND_DRAG_THRESHOLD, PROP_FONT_NAME, PROP_FONT_ANTIALIAS, PROP_FONT_DPI, PROP_FONT_HINTING, PROP_FONT_HINT_STYLE, PROP_FONT_RGBA, PROP_LONG_PRESS_DURATION, PROP_FONTCONFIG_TIMESTAMP, PROP_PASSWORD_HINT_TIME, PROP_UNSCALED_FONT_DPI, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterSettings, clutter_settings, G_TYPE_OBJECT); static inline void settings_update_font_options (ClutterSettings *self) { cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_NONE; cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_GRAY; cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; cairo_font_options_t *options; if (self->backend == NULL) return; options = cairo_font_options_create (); cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); if (self->xft_hinting >= 0 && self->xft_hint_style == NULL) { hint_style = CAIRO_HINT_STYLE_NONE; } else if (self->xft_hint_style != NULL) { if (strcmp (self->xft_hint_style, "hintnone") == 0) hint_style = CAIRO_HINT_STYLE_NONE; else if (strcmp (self->xft_hint_style, "hintslight") == 0) hint_style = CAIRO_HINT_STYLE_SLIGHT; else if (strcmp (self->xft_hint_style, "hintmedium") == 0) hint_style = CAIRO_HINT_STYLE_MEDIUM; else if (strcmp (self->xft_hint_style, "hintfull") == 0) hint_style = CAIRO_HINT_STYLE_FULL; } cairo_font_options_set_hint_style (options, hint_style); if (self->xft_rgba) { if (strcmp (self->xft_rgba, "rgb") == 0) subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; else if (strcmp (self->xft_rgba, "bgr") == 0) subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; else if (strcmp (self->xft_rgba, "vrgb") == 0) subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; else if (strcmp (self->xft_rgba, "vbgr") == 0) subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; } cairo_font_options_set_subpixel_order (options, subpixel_order); if (self->xft_antialias >= 0 && !self->xft_antialias) antialias_mode = CAIRO_ANTIALIAS_NONE; else if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) antialias_mode = CAIRO_ANTIALIAS_SUBPIXEL; else if (self->xft_antialias >= 0) antialias_mode = CAIRO_ANTIALIAS_GRAY; cairo_font_options_set_antialias (options, antialias_mode); CLUTTER_NOTE (BACKEND, "New font options:\n" " - font-name: %s\n" " - antialias: %d\n" " - hinting: %d\n" " - hint-style: %s\n" " - rgba: %s\n", self->font_name != NULL ? self->font_name : DEFAULT_FONT_NAME, self->xft_antialias, self->xft_hinting, self->xft_hint_style != NULL ? self->xft_hint_style : "<null>", self->xft_rgba != NULL ? self->xft_rgba : "<null>"); clutter_backend_set_font_options (self->backend, options); cairo_font_options_destroy (options); } static void settings_update_font_name (ClutterSettings *self) { CLUTTER_NOTE (BACKEND, "New font-name: %s", self->font_name); if (self->backend != NULL) g_signal_emit_by_name (self->backend, "font-changed"); } static void settings_update_resolution (ClutterSettings *self) { const char *scale_env = NULL; if (self->font_dpi > 0) self->resolution = (gdouble) self->font_dpi / 1024.0; else self->resolution = 96.0; scale_env = g_getenv ("GDK_DPI_SCALE"); if (scale_env != NULL) { double scale = g_ascii_strtod (scale_env, NULL); if (scale != 0 && self->resolution > 0) self->resolution *= scale; } CLUTTER_NOTE (BACKEND, "New resolution: %.2f (%s)", self->resolution, self->unscaled_font_dpi > 0 ? "unscaled" : "scaled"); if (self->backend != NULL) g_signal_emit_by_name (self->backend, "resolution-changed"); } static void settings_update_fontmap (ClutterSettings *self, guint stamp) { if (self->backend == NULL) return; #ifdef HAVE_PANGO_FT2 CLUTTER_NOTE (BACKEND, "Update fontmaps (stamp: %d)", stamp); if (self->last_fontconfig_timestamp != stamp) { ClutterMainContext *context; gboolean update_needed = FALSE; context = _clutter_context_get_default (); /* If there is no font map yet then we don't need to do anything * because the config for fontconfig will be read when it is * created */ if (context->font_map) { PangoFontMap *fontmap = PANGO_FONT_MAP (context->font_map); if (PANGO_IS_FC_FONT_MAP (fontmap) && !FcConfigUptoDate (NULL)) { pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (fontmap)); if (FcInitReinitialize ()) update_needed = TRUE; } } self->last_fontconfig_timestamp = stamp; if (update_needed) g_signal_emit_by_name (self->backend, "font-changed"); } #endif /* HAVE_PANGO_FT2 */ } static void clutter_settings_finalize (GObject *gobject) { ClutterSettings *self = CLUTTER_SETTINGS (gobject); free (self->font_name); free (self->xft_hint_style); free (self->xft_rgba); G_OBJECT_CLASS (clutter_settings_parent_class)->finalize (gobject); } static void clutter_settings_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterSettings *self = CLUTTER_SETTINGS (gobject); switch (prop_id) { case PROP_BACKEND: self->backend = g_value_get_object (value); break; case PROP_DOUBLE_CLICK_TIME: self->double_click_time = g_value_get_int (value); break; case PROP_DOUBLE_CLICK_DISTANCE: self->double_click_distance = g_value_get_int (value); break; case PROP_DND_DRAG_THRESHOLD: self->dnd_drag_threshold = g_value_get_int (value); break; case PROP_FONT_NAME: free (self->font_name); self->font_name = g_value_dup_string (value); settings_update_font_name (self); break; case PROP_FONT_ANTIALIAS: self->xft_antialias = g_value_get_int (value); settings_update_font_options (self); break; case PROP_FONT_DPI: self->font_dpi = g_value_get_int (value); settings_update_resolution (self); break; case PROP_FONT_HINTING: self->xft_hinting = g_value_get_int (value); settings_update_font_options (self); break; case PROP_FONT_HINT_STYLE: free (self->xft_hint_style); self->xft_hint_style = g_value_dup_string (value); settings_update_font_options (self); break; case PROP_FONT_RGBA: free (self->xft_rgba); self->xft_rgba = g_value_dup_string (value); settings_update_font_options (self); break; case PROP_LONG_PRESS_DURATION: self->long_press_duration = g_value_get_int (value); break; case PROP_FONTCONFIG_TIMESTAMP: settings_update_fontmap (self, g_value_get_uint (value)); break; case PROP_PASSWORD_HINT_TIME: self->password_hint_time = g_value_get_uint (value); break; case PROP_UNSCALED_FONT_DPI: self->font_dpi = g_value_get_int (value); settings_update_resolution (self); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } void clutter_settings_set_property_internal (ClutterSettings *self, const char *property, GValue *value) { property = g_intern_string (property); g_object_set_property (G_OBJECT (self), property, value); } static void clutter_settings_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterSettings *self = CLUTTER_SETTINGS (gobject); switch (prop_id) { case PROP_DOUBLE_CLICK_TIME: g_value_set_int (value, self->double_click_time); break; case PROP_DOUBLE_CLICK_DISTANCE: g_value_set_int (value, self->double_click_distance); break; case PROP_DND_DRAG_THRESHOLD: g_value_set_int (value, self->dnd_drag_threshold); break; case PROP_FONT_NAME: g_value_set_string (value, self->font_name); break; case PROP_FONT_ANTIALIAS: g_value_set_int (value, self->xft_antialias); break; case PROP_FONT_DPI: g_value_set_int (value, self->resolution * 1024); break; case PROP_FONT_HINTING: g_value_set_int (value, self->xft_hinting); break; case PROP_FONT_HINT_STYLE: g_value_set_string (value, self->xft_hint_style); break; case PROP_FONT_RGBA: g_value_set_string (value, self->xft_rgba); break; case PROP_LONG_PRESS_DURATION: g_value_set_int (value, self->long_press_duration); break; case PROP_PASSWORD_HINT_TIME: g_value_set_uint (value, self->password_hint_time); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_settings_dispatch_properties_changed (GObject *gobject, guint n_pspecs, GParamSpec **pspecs) { ClutterSettings *self = CLUTTER_SETTINGS (gobject); GObjectClass *klass; /* chain up to emit ::notify */ klass = G_OBJECT_CLASS (clutter_settings_parent_class); klass->dispatch_properties_changed (gobject, n_pspecs, pspecs); /* emit settings-changed just once for multiple properties */ if (self->backend != NULL) g_signal_emit_by_name (self->backend, "settings-changed"); } static void clutter_settings_class_init (ClutterSettingsClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); /** * ClutterSettings:backend: * * A back pointer to the #ClutterBackend * * Since: 1.4 * * Deprecated: 1.10 */ obj_props[PROP_BACKEND] = g_param_spec_object ("backend", "Backend", "A pointer to the backend", CLUTTER_TYPE_BACKEND, CLUTTER_PARAM_WRITABLE | G_PARAM_DEPRECATED | G_PARAM_CONSTRUCT_ONLY); /** * ClutterSettings:double-click-time: * * The time, in milliseconds, that should elapse between button-press * events in order to increase the click count by 1. * * Since: 1.4 */ obj_props[PROP_DOUBLE_CLICK_TIME] = g_param_spec_int ("double-click-time", P_("Double Click Time"), P_("The time between clicks necessary to detect a multiple click"), 0, G_MAXINT, 250, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:double-click-distance: * * The maximum distance, in pixels, between button-press events that * determines whether or not to increase the click count by 1. * * Since: 1.4 */ obj_props[PROP_DOUBLE_CLICK_DISTANCE] = g_param_spec_int ("double-click-distance", P_("Double Click Distance"), P_("The distance between clicks necessary to detect a multiple click"), 0, G_MAXINT, 5, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:dnd-drag-threshold: * * The default distance that the cursor of a pointer device * should travel before a drag operation should start. * * Since: 1.8 */ obj_props[PROP_DND_DRAG_THRESHOLD] = g_param_spec_int ("dnd-drag-threshold", P_("Drag Threshold"), P_("The distance the cursor should travel before starting to drag"), 1, G_MAXINT, 8, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:font-name: * * The default font name that should be used by text actors, as * a string that can be passed to pango_font_description_from_string(). * * Since: 1.4 */ obj_props[PROP_FONT_NAME] = g_param_spec_string ("font-name", P_("Font Name"), P_("The description of the default font, as one that could be parsed by Pango"), NULL, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:font-antialias: * * Whether or not to use antialiasing when rendering text; a value * of 1 enables it unconditionally; a value of 0 disables it * unconditionally; and -1 will use the system's default. * * Since: 1.4 */ obj_props[PROP_FONT_ANTIALIAS] = g_param_spec_int ("font-antialias", P_("Font Antialias"), P_("Whether to use antialiasing (1 to enable, 0 to disable, and -1 to use the default)"), -1, 1, -1, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:font-dpi: * * The DPI used when rendering text, as a value of 1024 * dots/inch. * * If set to -1, the system's default will be used instead * * Since: 1.4 */ obj_props[PROP_FONT_DPI] = g_param_spec_int ("font-dpi", P_("Font DPI"), P_("The resolution of the font, in 1024 * dots/inch, or -1 to use the default"), -1, 1024 * 1024, -1, CLUTTER_PARAM_READWRITE); obj_props[PROP_UNSCALED_FONT_DPI] = g_param_spec_int ("unscaled-font-dpi", P_("Font DPI"), P_("The resolution of the font, in 1024 * dots/inch, or -1 to use the default"), -1, 1024 * 1024, -1, CLUTTER_PARAM_WRITABLE); /** * ClutterSettings:font-hinting: * * Whether or not to use hinting when rendering text; a value of 1 * unconditionally enables it; a value of 0 unconditionally disables * it; and a value of -1 will use the system's default. * * Since: 1.4 */ obj_props[PROP_FONT_HINTING] = g_param_spec_int ("font-hinting", P_("Font Hinting"), P_("Whether to use hinting (1 to enable, 0 to disable and -1 to use the default)"), -1, 1, -1, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:font-hint-style: * * The style of the hinting used when rendering text. Valid values * are: * * - hintnone * - hintslight * - hintmedium * - hintfull * * Since: 1.4 */ obj_props[PROP_FONT_HINT_STYLE] = g_param_spec_string ("font-hint-style", P_("Font Hint Style"), P_("The style of hinting (hintnone, hintslight, hintmedium, hintfull)"), NULL, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:font-subpixel-order: * * The type of sub-pixel antialiasing used when rendering text. Valid * values are: * * - none * - rgb * - bgr * - vrgb * - vbgr * * Since: 1.4 */ obj_props[PROP_FONT_RGBA] = g_param_spec_string ("font-subpixel-order", P_("Font Subpixel Order"), P_("The type of subpixel antialiasing (none, rgb, bgr, vrgb, vbgr)"), NULL, CLUTTER_PARAM_READWRITE); /** * ClutterSettings:long-press-duration: * * Sets the minimum duration for a press to be recognized as a long press * gesture. The duration is expressed in milliseconds. * * See also #ClutterClickAction:long-press-duration. * * Since: 1.8 */ obj_props[PROP_LONG_PRESS_DURATION] = g_param_spec_int ("long-press-duration", P_("Long Press Duration"), P_("The minimum duration for a long press gesture to be recognized"), 0, G_MAXINT, 500, CLUTTER_PARAM_READWRITE); obj_props[PROP_FONTCONFIG_TIMESTAMP] = g_param_spec_uint ("fontconfig-timestamp", P_("Fontconfig configuration timestamp"), P_("Timestamp of the current fontconfig configuration"), 0, G_MAXUINT, 0, CLUTTER_PARAM_WRITABLE); /** * ClutterText:password-hint-time: * * How long should Clutter show the last input character in editable * ClutterText actors. The value is in milliseconds. A value of 0 * disables showing the password hint. 600 is a good value for * enabling the hint. * * Since: 1.10 */ obj_props[PROP_PASSWORD_HINT_TIME] = g_param_spec_uint ("password-hint-time", P_("Password Hint Time"), P_("How long to show the last input character in hidden entries"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE); gobject_class->set_property = clutter_settings_set_property; gobject_class->get_property = clutter_settings_get_property; gobject_class->dispatch_properties_changed = clutter_settings_dispatch_properties_changed; gobject_class->finalize = clutter_settings_finalize; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_settings_init (ClutterSettings *self) { self->resolution = -1.0; self->font_dpi = -1; self->unscaled_font_dpi = -1; self->double_click_time = 250; self->double_click_distance = 5; self->dnd_drag_threshold = 8; self->font_name = g_strdup (DEFAULT_FONT_NAME); self->xft_antialias = -1; self->xft_hinting = -1; self->xft_hint_style = NULL; self->xft_rgba = NULL; self->long_press_duration = 500; } /** * clutter_settings_get_default: * * Retrieves the singleton instance of #ClutterSettings * * Return value: (transfer none): the instance of #ClutterSettings. The * returned object is owned by Clutter and it should not be unreferenced * directly * * Since: 1.4 */ ClutterSettings * clutter_settings_get_default (void) { static ClutterSettings *settings = NULL; if (G_UNLIKELY (settings == NULL)) settings = g_object_new (CLUTTER_TYPE_SETTINGS, NULL); return settings; } void _clutter_settings_set_backend (ClutterSettings *settings, ClutterBackend *backend) { g_assert (CLUTTER_IS_SETTINGS (settings)); g_assert (CLUTTER_IS_BACKEND (backend)); settings->backend = backend; } #define SETTINGS_GROUP "Settings" void _clutter_settings_read_from_key_file (ClutterSettings *settings, GKeyFile *keyfile) { GObjectClass *settings_class; GObject *settings_obj; GParamSpec **pspecs; guint n_pspecs, i; if (!g_key_file_has_group (keyfile, SETTINGS_GROUP)) return; settings_obj = G_OBJECT (settings); settings_class = G_OBJECT_GET_CLASS (settings); pspecs = g_object_class_list_properties (settings_class, &n_pspecs); for (i = 0; i < n_pspecs; i++) { GParamSpec *pspec = pspecs[i]; const gchar *p_name = pspec->name; GType p_type = G_TYPE_FUNDAMENTAL (pspec->value_type); GValue value = G_VALUE_INIT; GError *key_error = NULL; g_value_init (&value, p_type); switch (p_type) { case G_TYPE_INT: case G_TYPE_UINT: { gint val; val = g_key_file_get_integer (keyfile, SETTINGS_GROUP, p_name, &key_error); if (p_type == G_TYPE_INT) g_value_set_int (&value, val); else g_value_set_uint (&value, val); } break; case G_TYPE_BOOLEAN: { gboolean val; val = g_key_file_get_boolean (keyfile, SETTINGS_GROUP, p_name, &key_error); g_value_set_boolean (&value, val); } break; case G_TYPE_FLOAT: case G_TYPE_DOUBLE: { gdouble val; val = g_key_file_get_double (keyfile, SETTINGS_GROUP, p_name, &key_error); if (p_type == G_TYPE_FLOAT) g_value_set_float (&value, val); else g_value_set_double (&value, val); } break; case G_TYPE_STRING: { gchar *val; val = g_key_file_get_string (keyfile, SETTINGS_GROUP, p_name, &key_error); g_value_take_string (&value, val); } break; } if (key_error != NULL && key_error->domain != G_KEY_FILE_ERROR && key_error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { g_critical ("Unable to read the value for setting '%s': %s", p_name, key_error->message); } if (key_error == NULL) g_object_set_property (settings_obj, p_name, &value); else g_error_free (key_error); g_value_unset (&value); } free (pspecs); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-align-constraint.h���������������������������������������������0000664�0001750�0001750�00000006157�14211404421�023416� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_ALIGN_CONSTRAINT_H__ #define __CLUTTER_ALIGN_CONSTRAINT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-constraint.h> G_BEGIN_DECLS #define CLUTTER_TYPE_ALIGN_CONSTRAINT (clutter_align_constraint_get_type ()) #define CLUTTER_ALIGN_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraint)) #define CLUTTER_IS_ALIGN_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT)) /** * ClutterAlignConstraint: * * #ClutterAlignConstraint is an opaque structure * whose members cannot be directly accesses * * Since: 1.4 */ typedef struct _ClutterAlignConstraint ClutterAlignConstraint; typedef struct _ClutterAlignConstraintClass ClutterAlignConstraintClass; CLUTTER_AVAILABLE_IN_1_4 GType clutter_align_constraint_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterConstraint *clutter_align_constraint_new (ClutterActor *source, ClutterAlignAxis axis, gfloat factor); CLUTTER_AVAILABLE_IN_1_4 void clutter_align_constraint_set_source (ClutterAlignConstraint *align, ClutterActor *source); CLUTTER_AVAILABLE_IN_1_4 ClutterActor * clutter_align_constraint_get_source (ClutterAlignConstraint *align); CLUTTER_AVAILABLE_IN_1_4 void clutter_align_constraint_set_align_axis (ClutterAlignConstraint *align, ClutterAlignAxis axis); CLUTTER_AVAILABLE_IN_1_4 ClutterAlignAxis clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align); CLUTTER_AVAILABLE_IN_1_4 void clutter_align_constraint_set_factor (ClutterAlignConstraint *align, gfloat factor); CLUTTER_AVAILABLE_IN_1_4 gfloat clutter_align_constraint_get_factor (ClutterAlignConstraint *align); G_END_DECLS #endif /* __CLUTTER_ALIGN_CONSTRAINT_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-page-turn-effect.c���������������������������������������������0000664�0001750�0001750�00000027412�14211404421�023266� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> * * Based on MxDeformPageTurn, written by: * Chris Lord <chris@linux.intel.com> */ /** * SECTION:clutter-page-turn-effect * @Title: ClutterPageTurnEffect * @Short_Description: A page turning effect * * A simple page turning effect * * #ClutterPageTurnEffect is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter-page-turn-effect.h" #include "clutter-debug.h" #include "clutter-private.h" #define CLUTTER_PAGE_TURN_EFFECT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CLUTTER_TYPE_PAGE_TURN_EFFECT, ClutterPageTurnEffectClass)) #define CLUTTER_IS_PAGE_TURN_EFFECT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_PAGE_TURN_EFFECT)) #define CLUTTER_PAGE_TURN_EFFECT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_PAGE_TURN_EFFECT, ClutterPageTurnEffectClass)) struct _ClutterPageTurnEffect { ClutterDeformEffect parent_instance; gdouble period; gdouble angle; gfloat radius; }; struct _ClutterPageTurnEffectClass { ClutterDeformEffectClass parent_class; }; enum { PROP_0, PROP_PERIOD, PROP_ANGLE, PROP_RADIUS, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterPageTurnEffect, clutter_page_turn_effect, CLUTTER_TYPE_DEFORM_EFFECT); static void clutter_page_turn_effect_deform_vertex (ClutterDeformEffect *effect, gfloat width, gfloat height, CoglTextureVertex *vertex) { ClutterPageTurnEffect *self = CLUTTER_PAGE_TURN_EFFECT (effect); gfloat cx, cy, rx, ry, radians, turn_angle; guint shade; if (self->period == 0.0) return; radians = self->angle / (180.0f / G_PI); /* Rotate the point around the centre of the page-curl ray to align it with * the y-axis. */ cx = (1.f - self->period) * width; cy = (1.f - self->period) * height; rx = ((vertex->x - cx) * cos (- radians)) - ((vertex->y - cy) * sin (- radians)) - self->radius; ry = ((vertex->x - cx) * sin (- radians)) + ((vertex->y - cy) * cos (- radians)); turn_angle = 0.f; if (rx > self->radius * -2.0f) { /* Calculate the curl angle as a function from the distance of the curl * ray (i.e. the page crease) */ turn_angle = (rx / self->radius * G_PI_2) - G_PI_2; shade = (sin (turn_angle) * 96.0f) + 159.0f; /* Add a gradient that makes it look like lighting and hides the switch * between textures. */ cogl_color_init_from_4ub (&vertex->color, shade, shade, shade, 0xff); } if (rx > 0) { /* Make the curl radius smaller as more circles are formed (stops * z-fighting and looks cool). Note that 10 is a semi-arbitrary * number here - divide it by two and it's the amount of space * between curled layers of the texture, in pixels. */ gfloat small_radius; small_radius = self->radius - MIN (self->radius, (turn_angle * 10) / G_PI); /* Calculate a point on a cylinder (maybe make this a cone at some * point) and rotate it by the specified angle. */ rx = (small_radius * cos (turn_angle)) + self->radius; vertex->x = (rx * cos (radians)) - (ry * sin (radians)) + cx; vertex->y = (rx * sin (radians)) + (ry * cos (radians)) + cy; vertex->z = (small_radius * sin (turn_angle)) + self->radius; } } static void clutter_page_turn_effect_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterPageTurnEffect *effect = CLUTTER_PAGE_TURN_EFFECT (gobject); switch (prop_id) { case PROP_PERIOD: clutter_page_turn_effect_set_period (effect, g_value_get_double (value)); break; case PROP_ANGLE: clutter_page_turn_effect_set_angle (effect, g_value_get_double (value)); break; case PROP_RADIUS: clutter_page_turn_effect_set_radius (effect, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_page_turn_effect_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterPageTurnEffect *effect = CLUTTER_PAGE_TURN_EFFECT (gobject); switch (prop_id) { case PROP_PERIOD: g_value_set_double (value, effect->period); break; case PROP_ANGLE: g_value_set_double (value, effect->angle); break; case PROP_RADIUS: g_value_set_float (value, effect->radius); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_page_turn_effect_class_init (ClutterPageTurnEffectClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterDeformEffectClass *deform_class = CLUTTER_DEFORM_EFFECT_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = clutter_page_turn_effect_set_property; gobject_class->get_property = clutter_page_turn_effect_get_property; /** * ClutterPageTurnEffect:period: * * The period of the page turn, between 0.0 (no curling) and * 1.0 (fully curled) * * Since: 1.4 */ pspec = g_param_spec_double ("period", "Period", "The period of the page turn", 0.0, 1.0, 0.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_PERIOD] = pspec; g_object_class_install_property (gobject_class, PROP_PERIOD, pspec); /** * ClutterPageTurnEffect:angle: * * The angle of the page rotation, in degrees, between 0.0 and 360.0 * * Since: 1.4 */ pspec = g_param_spec_double ("angle", "Angle", "The angle of the page rotation, in degrees", 0.0, 360.0, 0.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE] = pspec; g_object_class_install_property (gobject_class, PROP_ANGLE, pspec); /** * ClutterPageTurnEffect:radius: * * The radius of the page curl, in pixels * * Since: 1.4 */ pspec = g_param_spec_float ("radius", "Radius", "The radius of the page curl", -G_MAXFLOAT, G_MAXFLOAT, 24.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_RADIUS] = pspec; g_object_class_install_property (gobject_class, PROP_RADIUS, pspec); deform_class->deform_vertex = clutter_page_turn_effect_deform_vertex; } static void clutter_page_turn_effect_init (ClutterPageTurnEffect *self) { self->period = 0.0; self->angle = 0.0; self->radius = 24.0f; } /** * clutter_page_turn_effect_new: * @period: the period of the page curl, between 0.0 and 1.0 * @angle: the angle of the page curl, between 0.0 and 360.0 * @radius: the radius of the page curl, in pixels * * Creates a new #ClutterPageTurnEffect instance with the given parameters * * Return value: the newly created #ClutterPageTurnEffect * * Since: 1.4 */ ClutterEffect * clutter_page_turn_effect_new (gdouble period, gdouble angle, gfloat radius) { g_return_val_if_fail (period >= 0.0 && period <= 1.0, NULL); g_return_val_if_fail (angle >= 0.0 && angle <= 360.0, NULL); return g_object_new (CLUTTER_TYPE_PAGE_TURN_EFFECT, "period", period, "angle", angle, "radius", radius, NULL); } /** * clutter_page_turn_effect_set_period: * @effect: a #ClutterPageTurnEffect * @period: the period of the page curl, between 0.0 and 1.0 * * Sets the period of the page curling, between 0.0 (no curling) * and 1.0 (fully curled) * * Since: 1.4 */ void clutter_page_turn_effect_set_period (ClutterPageTurnEffect *effect, gdouble period) { g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect)); g_return_if_fail (period >= 0.0 && period <= 1.0); effect->period = period; clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_PERIOD]); } /** * clutter_page_turn_effect_get_period: * @effect: a #ClutterPageTurnEffect * * Retrieves the value set using clutter_page_turn_effect_get_period() * * Return value: the period of the page curling * * Since: 1.4 */ gdouble clutter_page_turn_effect_get_period (ClutterPageTurnEffect *effect) { g_return_val_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect), 0.0); return effect->period; } /** * clutter_page_turn_effect_set_angle: * @effect: #ClutterPageTurnEffect * @angle: the angle of the page curl, in degrees * * Sets the angle of the page curling, in degrees * * Since: 1.4 */ void clutter_page_turn_effect_set_angle (ClutterPageTurnEffect *effect, gdouble angle) { g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect)); g_return_if_fail (angle >= 0.0 && angle <= 360.0); effect->angle = angle; clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_ANGLE]); } /** * clutter_page_turn_effect_get_angle: * @effect: a #ClutterPageTurnEffect: * * Retrieves the value set using clutter_page_turn_effect_get_angle() * * Return value: the angle of the page curling * * Since: 1.4 */ gdouble clutter_page_turn_effect_get_angle (ClutterPageTurnEffect *effect) { g_return_val_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect), 0.0); return effect->angle; } /** * clutter_page_turn_effect_set_radius: * @effect: a #ClutterPageTurnEffect: * @radius: the radius of the page curling, in pixels * * Sets the radius of the page curling * * Since: 1.4 */ void clutter_page_turn_effect_set_radius (ClutterPageTurnEffect *effect, gfloat radius) { g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect)); effect->radius = radius; clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_RADIUS]); } /** * clutter_page_turn_effect_get_radius: * @effect: a #ClutterPageTurnEffect * * Retrieves the value set using clutter_page_turn_effect_set_radius() * * Return value: the radius of the page curling * * Since: 1.4 */ gfloat clutter_page_turn_effect_get_radius (ClutterPageTurnEffect *effect) { g_return_val_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect), 0.0); return effect->radius; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-types.h��������������������������������������������������������0000664�0001750�0001750�00000071724�14211404421�021310� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_TYPES_H__ #define __CLUTTER_TYPES_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <stdlib.h> #include <cairo.h> #include <cogl/cogl.h> #include <clutter/clutter-macros.h> #include <clutter/clutter-enums.h> G_BEGIN_DECLS #define CLUTTER_TYPE_ACTOR_BOX (clutter_actor_box_get_type ()) #define CLUTTER_TYPE_FOG (clutter_fog_get_type ()) #define CLUTTER_TYPE_GEOMETRY (clutter_geometry_get_type ()) #define CLUTTER_TYPE_KNOT (clutter_knot_get_type ()) #define CLUTTER_TYPE_MARGIN (clutter_margin_get_type ()) #define CLUTTER_TYPE_MATRIX (clutter_matrix_get_type ()) #define CLUTTER_TYPE_PAINT_VOLUME (clutter_paint_volume_get_type ()) #define CLUTTER_TYPE_PERSPECTIVE (clutter_perspective_get_type ()) #define CLUTTER_TYPE_VERTEX (clutter_vertex_get_type ()) #define CLUTTER_TYPE_POINT (clutter_point_get_type ()) #define CLUTTER_TYPE_SIZE (clutter_size_get_type ()) #define CLUTTER_TYPE_RECT (clutter_rect_get_type ()) typedef struct _ClutterActor ClutterActor; typedef struct _ClutterStage ClutterStage; typedef struct _ClutterFrameInfo ClutterFrameInfo; typedef struct _ClutterContainer ClutterContainer; /* dummy */ typedef struct _ClutterChildMeta ClutterChildMeta; typedef struct _ClutterLayoutMeta ClutterLayoutMeta; typedef struct _ClutterActorMeta ClutterActorMeta; typedef struct _ClutterLayoutManager ClutterLayoutManager; typedef struct _ClutterActorIter ClutterActorIter; typedef struct _ClutterPaintNode ClutterPaintNode; typedef struct _ClutterContent ClutterContent; /* dummy */ typedef struct _ClutterScrollActor ClutterScrollActor; typedef struct _ClutterInterval ClutterInterval; typedef struct _ClutterAnimatable ClutterAnimatable; /* dummy */ typedef struct _ClutterTimeline ClutterTimeline; typedef struct _ClutterTransition ClutterTransition; typedef struct _ClutterPropertyTransition ClutterPropertyTransition; typedef struct _ClutterKeyframeTransition ClutterKeyframeTransition; typedef struct _ClutterTransitionGroup ClutterTransitionGroup; typedef struct _ClutterAction ClutterAction; typedef struct _ClutterConstraint ClutterConstraint; typedef struct _ClutterEffect ClutterEffect; typedef struct _ClutterPath ClutterPath; typedef struct _ClutterPathNode ClutterPathNode; typedef struct _ClutterActorBox ClutterActorBox; typedef struct _ClutterColor ClutterColor; typedef struct _ClutterGeometry ClutterGeometry; /* XXX:2.0 - remove */ typedef struct _ClutterKnot ClutterKnot; typedef struct _ClutterMargin ClutterMargin; typedef struct _ClutterPerspective ClutterPerspective; typedef struct _ClutterPoint ClutterPoint; typedef struct _ClutterRect ClutterRect; typedef struct _ClutterSize ClutterSize; typedef struct _ClutterVertex ClutterVertex; typedef struct _ClutterAlpha ClutterAlpha; typedef struct _ClutterAnimation ClutterAnimation; typedef struct _ClutterAnimator ClutterAnimator; typedef struct _ClutterState ClutterState; typedef struct _ClutterInputDeviceTool ClutterInputDeviceTool; typedef struct _ClutterInputDevice ClutterInputDevice; typedef struct _ClutterVirtualInputDevice ClutterVirtualInputDevice; typedef struct _ClutterInputMethod ClutterInputMethod; typedef struct _ClutterInputFocus ClutterInputFocus; typedef CoglMatrix ClutterMatrix; typedef union _ClutterEvent ClutterEvent; /** * ClutterEventSequence: * * The #ClutterEventSequence structure is an opaque * type used to denote the event sequence of a touch event. * * Since: 1.12 */ typedef struct _ClutterEventSequence ClutterEventSequence; typedef struct _ClutterFog ClutterFog; /* deprecated */ typedef struct _ClutterBehaviour ClutterBehaviour; /* deprecated */ typedef struct _ClutterShader ClutterShader; /* deprecated */ /** * ClutterPaintVolume: * * #ClutterPaintVolume is an opaque structure * whose members cannot be directly accessed. * * A #ClutterPaintVolume represents an * a bounding volume whose internal representation isn't defined but * can be set and queried in terms of an axis aligned bounding box. * * A #ClutterPaintVolume for a #ClutterActor * is defined to be relative from the current actor modelview matrix. * * Other internal representation and methods for describing the * bounding volume may be added in the future. * * Since: 1.4 */ typedef struct _ClutterPaintVolume ClutterPaintVolume; /** * ClutterPoint: * @x: X coordinate, in pixels * @y: Y coordinate, in pixels * * A point in 2D space. * * Since: 1.12 */ struct _ClutterPoint { float x; float y; }; /** * CLUTTER_POINT_INIT: * @x: X coordinate * @y: Y coordinate * * A simple macro for initializing a #ClutterPoint when declaring it, e.g.: * * |[ * ClutterPoint p = CLUTTER_POINT_INIT (100, 100); * ]| * * Since: 1.12 */ #define CLUTTER_POINT_INIT(x,y) { (x), (y) } /** * CLUTTER_POINT_INIT_ZERO: * * A simple macro for initializing a #ClutterPoint to (0, 0) when * declaring it. * * Since: 1.12 */ #define CLUTTER_POINT_INIT_ZERO CLUTTER_POINT_INIT (0.f, 0.f) CLUTTER_AVAILABLE_IN_1_12 GType clutter_point_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 const ClutterPoint * clutter_point_zero (void); CLUTTER_AVAILABLE_IN_1_12 ClutterPoint * clutter_point_alloc (void); CLUTTER_AVAILABLE_IN_1_12 ClutterPoint * clutter_point_init (ClutterPoint *point, float x, float y); CLUTTER_AVAILABLE_IN_1_12 ClutterPoint * clutter_point_copy (const ClutterPoint *point); CLUTTER_AVAILABLE_IN_1_12 void clutter_point_free (ClutterPoint *point); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_point_equals (const ClutterPoint *a, const ClutterPoint *b); CLUTTER_AVAILABLE_IN_1_12 float clutter_point_distance (const ClutterPoint *a, const ClutterPoint *b, float *x_distance, float *y_distance); /** * ClutterSize: * @width: the width, in pixels * @height: the height, in pixels * * A size, in 2D space. * * Since: 1.12 */ struct _ClutterSize { float width; float height; }; /** * CLUTTER_SIZE_INIT: * @width: the width * @height: the height * * A simple macro for initializing a #ClutterSize when declaring it, e.g.: * * |[ * ClutterSize s = CLUTTER_SIZE_INIT (200, 200); * ]| * * Since: 1.12 */ #define CLUTTER_SIZE_INIT(width,height) { (width), (height) } /** * CLUTTER_SIZE_INIT_ZERO: * * A simple macro for initializing a #ClutterSize to (0, 0) when * declaring it. * * Since: 1.12 */ #define CLUTTER_SIZE_INIT_ZERO CLUTTER_SIZE_INIT (0.f, 0.f) CLUTTER_AVAILABLE_IN_1_12 GType clutter_size_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterSize * clutter_size_alloc (void); CLUTTER_AVAILABLE_IN_1_12 ClutterSize * clutter_size_init (ClutterSize *size, float width, float height); CLUTTER_AVAILABLE_IN_1_12 ClutterSize * clutter_size_copy (const ClutterSize *size); CLUTTER_AVAILABLE_IN_1_12 void clutter_size_free (ClutterSize *size); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_size_equals (const ClutterSize *a, const ClutterSize *b); /** * ClutterRect: * @origin: the origin of the rectangle * @size: the size of the rectangle * * The location and size of a rectangle. * * The width and height of a #ClutterRect can be negative; Clutter considers * a rectangle with an origin of [ 0.0, 0.0 ] and a size of [ 10.0, 10.0 ] to * be equivalent to a rectangle with origin of [ 10.0, 10.0 ] and size of * [ -10.0, -10.0 ]. * * Application code can normalize rectangles using clutter_rect_normalize(): * this function will ensure that the width and height of a #ClutterRect are * positive values. All functions taking a #ClutterRect as an argument will * implicitly normalize it before computing eventual results. For this reason * it is safer to access the contents of a #ClutterRect by using the provided * API at all times, instead of directly accessing the structure members. * * Since: 1.12 */ struct _ClutterRect { ClutterPoint origin; ClutterSize size; }; /** * CLUTTER_RECT_INIT: * @x: the X coordinate * @y: the Y coordinate * @width: the width * @height: the height * * A simple macro for initializing a #ClutterRect when declaring it, e.g.: * * |[ * ClutterRect r = CLUTTER_RECT_INIT (100, 100, 200, 200); * ]| * * Since: 1.12 */ #define CLUTTER_RECT_INIT(x,y,width,height) { { (x), (y) }, { (width), (height) } } /** * CLUTTER_RECT_INIT_ZERO: * * A simple macro for initializing a #ClutterRect to (0, 0, 0, 0) when * declaring it. * * Since: 1.12 */ #define CLUTTER_RECT_INIT_ZERO CLUTTER_RECT_INIT (0.f, 0.f, 0.f, 0.f) CLUTTER_AVAILABLE_IN_1_12 GType clutter_rect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 const ClutterRect * clutter_rect_zero (void); CLUTTER_AVAILABLE_IN_1_12 ClutterRect * clutter_rect_alloc (void); CLUTTER_AVAILABLE_IN_1_12 ClutterRect * clutter_rect_init (ClutterRect *rect, float x, float y, float width, float height); CLUTTER_AVAILABLE_IN_1_12 ClutterRect * clutter_rect_copy (const ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_12 void clutter_rect_free (ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_rect_equals (ClutterRect *a, ClutterRect *b); CLUTTER_AVAILABLE_IN_1_12 ClutterRect * clutter_rect_normalize (ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_12 void clutter_rect_get_center (ClutterRect *rect, ClutterPoint *center); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_rect_contains_point (ClutterRect *rect, ClutterPoint *point); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_rect_contains_rect (ClutterRect *a, ClutterRect *b); CLUTTER_AVAILABLE_IN_1_12 void clutter_rect_union (ClutterRect *a, ClutterRect *b, ClutterRect *res); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_rect_intersection (ClutterRect *a, ClutterRect *b, ClutterRect *res); CLUTTER_AVAILABLE_IN_1_12 void clutter_rect_offset (ClutterRect *rect, float d_x, float d_y); CLUTTER_AVAILABLE_IN_1_12 void clutter_rect_inset (ClutterRect *rect, float d_x, float d_y); CLUTTER_AVAILABLE_IN_1_12 void clutter_rect_clamp_to_pixel (ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_12 float clutter_rect_get_x (ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_12 float clutter_rect_get_y (ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_12 float clutter_rect_get_width (ClutterRect *rect); CLUTTER_AVAILABLE_IN_1_12 float clutter_rect_get_height (ClutterRect *rect); /** * ClutterVertex: * @x: X coordinate of the vertex * @y: Y coordinate of the vertex * @z: Z coordinate of the vertex * * A point in 3D space, expressed in pixels * * Since: 0.4 */ struct _ClutterVertex { gfloat x; gfloat y; gfloat z; }; /** * CLUTTER_VERTEX_INIT: * @x: the X coordinate of the vertex * @y: the Y coordinate of the vertex * @z: the Z coordinate of the vertex * * A simple macro for initializing a #ClutterVertex when declaring it, e.g.: * * |[ * ClutterVertex v = CLUTTER_VERTEX_INIT (x, y, z); * ]| * * Since: 1.10 */ #define CLUTTER_VERTEX_INIT(x,y,z) { (x), (y), (z) } /** * CLUTTER_VERTEX_INIT_ZERO: * * A simple macro for initializing a #ClutterVertex to (0, 0, 0). * * Since: 1.12 */ #define CLUTTER_VERTEX_INIT_ZERO CLUTTER_VERTEX_INIT (0.f, 0.f, 0.f) CLUTTER_AVAILABLE_IN_ALL GType clutter_vertex_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterVertex *clutter_vertex_new (gfloat x, gfloat y, gfloat z); CLUTTER_AVAILABLE_IN_1_12 ClutterVertex *clutter_vertex_alloc (void); CLUTTER_AVAILABLE_IN_ALL ClutterVertex *clutter_vertex_init (ClutterVertex *vertex, gfloat x, gfloat y, gfloat z); CLUTTER_AVAILABLE_IN_ALL ClutterVertex *clutter_vertex_copy (const ClutterVertex *vertex); CLUTTER_AVAILABLE_IN_ALL void clutter_vertex_free (ClutterVertex *vertex); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_vertex_equal (const ClutterVertex *vertex_a, const ClutterVertex *vertex_b); /** * ClutterActorBox: * @x1: X coordinate of the top left corner * @y1: Y coordinate of the top left corner * @x2: X coordinate of the bottom right corner * @y2: Y coordinate of the bottom right corner * * Bounding box of an actor. The coordinates of the top left and right bottom * corners of an actor. The coordinates of the two points are expressed in * pixels with sub-pixel precision */ struct _ClutterActorBox { gfloat x1; gfloat y1; gfloat x2; gfloat y2; }; /** * CLUTTER_ACTOR_BOX_INIT: * @x_1: the X coordinate of the top left corner * @y_1: the Y coordinate of the top left corner * @x_2: the X coordinate of the bottom right corner * @y_2: the Y coordinate of the bottom right corner * * A simple macro for initializing a #ClutterActorBox when declaring * it, e.g.: * * |[ * ClutterActorBox box = CLUTTER_ACTOR_BOX_INIT (0, 0, 400, 600); * ]| * * Since: 1.10 */ #define CLUTTER_ACTOR_BOX_INIT(x_1,y_1,x_2,y_2) { (x_1), (y_1), (x_2), (y_2) } /** * CLUTTER_ACTOR_BOX_INIT_ZERO: * * A simple macro for initializing a #ClutterActorBox to 0 when * declaring it, e.g.: * * |[ * ClutterActorBox box = CLUTTER_ACTOR_BOX_INIT_ZERO; * ]| * * Since: 1.12 */ #define CLUTTER_ACTOR_BOX_INIT_ZERO CLUTTER_ACTOR_BOX_INIT (0.f, 0.f, 0.f, 0.f) CLUTTER_AVAILABLE_IN_ALL GType clutter_actor_box_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterActorBox *clutter_actor_box_new (gfloat x_1, gfloat y_1, gfloat x_2, gfloat y_2); CLUTTER_AVAILABLE_IN_1_12 ClutterActorBox *clutter_actor_box_alloc (void); CLUTTER_AVAILABLE_IN_ALL ClutterActorBox *clutter_actor_box_init (ClutterActorBox *box, gfloat x_1, gfloat y_1, gfloat x_2, gfloat y_2); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_init_rect (ClutterActorBox *box, gfloat x, gfloat y, gfloat width, gfloat height); CLUTTER_AVAILABLE_IN_ALL ClutterActorBox *clutter_actor_box_copy (const ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_free (ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_box_equal (const ClutterActorBox *box_a, const ClutterActorBox *box_b); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_box_get_x (const ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_box_get_y (const ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_box_get_width (const ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_box_get_height (const ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_get_origin (const ClutterActorBox *box, gfloat *x, gfloat *y); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_get_size (const ClutterActorBox *box, gfloat *width, gfloat *height); CLUTTER_AVAILABLE_IN_ALL gfloat clutter_actor_box_get_area (const ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_actor_box_contains (const ClutterActorBox *box, gfloat x, gfloat y); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_from_vertices (ClutterActorBox *box, const ClutterVertex verts[]); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_interpolate (const ClutterActorBox *initial, const ClutterActorBox *final, gdouble progress, ClutterActorBox *result); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_clamp_to_pixel (ClutterActorBox *box); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_union (const ClutterActorBox *a, const ClutterActorBox *b, ClutterActorBox *result); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_set_origin (ClutterActorBox *box, gfloat x, gfloat y); CLUTTER_AVAILABLE_IN_ALL void clutter_actor_box_set_size (ClutterActorBox *box, gfloat width, gfloat height); /** * ClutterGeometry: * @x: X coordinate of the top left corner of an actor * @y: Y coordinate of the top left corner of an actor * @width: width of an actor * @height: height of an actor * * The rectangle containing an actor's bounding box, measured in pixels. * * You should not use #ClutterGeometry, or operate on its fields * directly; you should use #cairo_rectangle_int_t or #ClutterRect if you * need a rectangle type, depending on the precision required. * * Deprecated: 1.16 */ struct _ClutterGeometry { /*< public >*/ gint x; gint y; guint width; guint height; }; CLUTTER_AVAILABLE_IN_ALL GType clutter_geometry_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_16 void clutter_geometry_union (const ClutterGeometry *geometry_a, const ClutterGeometry *geometry_b, ClutterGeometry *result); CLUTTER_DEPRECATED_IN_1_16 gboolean clutter_geometry_intersects (const ClutterGeometry *geometry0, const ClutterGeometry *geometry1); /** * ClutterKnot: * @x: X coordinate of the knot * @y: Y coordinate of the knot * * Point in a path behaviour. * * Since: 0.2 */ struct _ClutterKnot { gint x; gint y; }; CLUTTER_AVAILABLE_IN_ALL GType clutter_knot_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterKnot *clutter_knot_copy (const ClutterKnot *knot); CLUTTER_AVAILABLE_IN_ALL void clutter_knot_free (ClutterKnot *knot); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_knot_equal (const ClutterKnot *knot_a, const ClutterKnot *knot_b); /** * ClutterPathNode: * @type: the node's type * @points: the coordinates of the node * * Represents a single node of a #ClutterPath. * * Some of the coordinates in @points may be unused for some node * types. %CLUTTER_PATH_MOVE_TO and %CLUTTER_PATH_LINE_TO use only one * pair of coordinates, %CLUTTER_PATH_CURVE_TO uses all three and * %CLUTTER_PATH_CLOSE uses none. * * Since: 1.0 */ struct _ClutterPathNode { ClutterPathNodeType type; ClutterKnot points[3]; }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_path_node_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterPathNode *clutter_path_node_copy (const ClutterPathNode *node); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_node_free (ClutterPathNode *node); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_path_node_equal (const ClutterPathNode *node_a, const ClutterPathNode *node_b); /* * ClutterPaintVolume */ CLUTTER_AVAILABLE_IN_1_2 GType clutter_paint_volume_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 ClutterPaintVolume *clutter_paint_volume_copy (const ClutterPaintVolume *pv); CLUTTER_AVAILABLE_IN_1_2 void clutter_paint_volume_free (ClutterPaintVolume *pv); CLUTTER_AVAILABLE_IN_1_2 void clutter_paint_volume_set_origin (ClutterPaintVolume *pv, const ClutterVertex *origin); CLUTTER_AVAILABLE_IN_1_2 void clutter_paint_volume_get_origin (const ClutterPaintVolume *pv, ClutterVertex *vertex); CLUTTER_AVAILABLE_IN_1_2 void clutter_paint_volume_set_width (ClutterPaintVolume *pv, gfloat width); CLUTTER_AVAILABLE_IN_1_2 gfloat clutter_paint_volume_get_width (const ClutterPaintVolume *pv); CLUTTER_AVAILABLE_IN_1_2 void clutter_paint_volume_set_height (ClutterPaintVolume *pv, gfloat height); CLUTTER_AVAILABLE_IN_1_2 gfloat clutter_paint_volume_get_height (const ClutterPaintVolume *pv); CLUTTER_AVAILABLE_IN_1_2 void clutter_paint_volume_set_depth (ClutterPaintVolume *pv, gfloat depth); CLUTTER_AVAILABLE_IN_1_2 gfloat clutter_paint_volume_get_depth (const ClutterPaintVolume *pv); CLUTTER_AVAILABLE_IN_1_2 void clutter_paint_volume_union (ClutterPaintVolume *pv, const ClutterPaintVolume *another_pv); CLUTTER_AVAILABLE_IN_1_10 void clutter_paint_volume_union_box (ClutterPaintVolume *pv, const ClutterActorBox *box); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_paint_volume_set_from_allocation (ClutterPaintVolume *pv, ClutterActor *actor); /** * ClutterMargin: * @left: the margin from the left * @right: the margin from the right * @top: the margin from the top * @bottom: the margin from the bottom * * A representation of the components of a margin. * * Since: 1.10 */ struct _ClutterMargin { float left; float right; float top; float bottom; }; CLUTTER_AVAILABLE_IN_1_10 GType clutter_margin_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterMargin * clutter_margin_new (void) G_GNUC_MALLOC; CLUTTER_AVAILABLE_IN_1_10 ClutterMargin * clutter_margin_copy (const ClutterMargin *margin_); CLUTTER_AVAILABLE_IN_1_10 void clutter_margin_free (ClutterMargin *margin_); /** * ClutterProgressFunc: * @a: the initial value of an interval * @b: the final value of an interval * @progress: the progress factor, between 0 and 1 * @retval: the value used to store the progress * * Prototype of the progress function used to compute the value * between the two ends @a and @b of an interval depending on * the value of @progress. * * The #GValue in @retval is already initialized with the same * type as @a and @b. * * This function will be called by #ClutterInterval if the * type of the values of the interval was registered using * clutter_interval_register_progress_func(). * * Return value: %TRUE if the function successfully computed * the value and stored it inside @retval * * Since: 1.0 */ typedef gboolean (* ClutterProgressFunc) (const GValue *a, const GValue *b, gdouble progress, GValue *retval); CLUTTER_AVAILABLE_IN_1_0 void clutter_interval_register_progress_func (GType value_type, ClutterProgressFunc func); CLUTTER_AVAILABLE_IN_1_12 GType clutter_matrix_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterMatrix * clutter_matrix_alloc (void); CLUTTER_AVAILABLE_IN_1_12 ClutterMatrix * clutter_matrix_init_identity (ClutterMatrix *matrix); CLUTTER_AVAILABLE_IN_1_12 ClutterMatrix * clutter_matrix_init_from_array (ClutterMatrix *matrix, const float values[16]); CLUTTER_AVAILABLE_IN_1_12 ClutterMatrix * clutter_matrix_init_from_matrix (ClutterMatrix *a, const ClutterMatrix *b); CLUTTER_AVAILABLE_IN_1_12 void clutter_matrix_free (ClutterMatrix *matrix); G_END_DECLS #endif /* __CLUTTER_TYPES_H__ */ ��������������������������������������������muffin-5.2.1/clutter/clutter/clutter-paint-node-private.h�������������������������������������������0000664�0001750�0001750�00000015276�14211404421�023652� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_PAINT_NODE_PRIVATE_H__ #define __CLUTTER_PAINT_NODE_PRIVATE_H__ #include <glib-object.h> #include <json-glib/json-glib.h> #include <clutter/clutter-paint-node.h> G_BEGIN_DECLS #define CLUTTER_PAINT_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_PAINT_NODE, ClutterPaintNodeClass)) #define CLUTTER_IS_PAINT_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_PAINT_NODE)) #define CLUTTER_PAINT_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_PAINT_NODE, ClutterPaintNodeClass)) typedef struct _ClutterPaintOperation ClutterPaintOperation; struct _ClutterPaintNode { GTypeInstance parent_instance; ClutterPaintNode *parent; ClutterPaintNode *first_child; ClutterPaintNode *prev_sibling; ClutterPaintNode *next_sibling; ClutterPaintNode *last_child; guint n_children; GArray *operations; gchar *name; volatile int ref_count; }; struct _ClutterPaintNodeClass { GTypeClass base_class; void (* finalize) (ClutterPaintNode *node); gboolean (* pre_draw) (ClutterPaintNode *node); void (* draw) (ClutterPaintNode *node); void (* post_draw) (ClutterPaintNode *node); JsonNode*(* serialize) (ClutterPaintNode *node); CoglFramebuffer *(* get_framebuffer) (ClutterPaintNode *node); }; #define PAINT_OP_INIT { PAINT_OP_INVALID } typedef enum { PAINT_OP_INVALID = 0, PAINT_OP_TEX_RECT, PAINT_OP_PATH, PAINT_OP_PRIMITIVE } PaintOpCode; struct _ClutterPaintOperation { PaintOpCode opcode; union { float texrect[8]; CoglPath *path; CoglPrimitive *primitive; } op; }; GType _clutter_root_node_get_type (void) G_GNUC_CONST; GType _clutter_transform_node_get_type (void) G_GNUC_CONST; GType _clutter_dummy_node_get_type (void) G_GNUC_CONST; void _clutter_paint_operation_paint_rectangle (const ClutterPaintOperation *op); void _clutter_paint_operation_clip_rectangle (const ClutterPaintOperation *op); void _clutter_paint_operation_paint_path (const ClutterPaintOperation *op); void _clutter_paint_operation_clip_path (const ClutterPaintOperation *op); void _clutter_paint_operation_paint_primitive (const ClutterPaintOperation *op); void _clutter_paint_node_init_types (void); gpointer _clutter_paint_node_create (GType gtype); ClutterPaintNode * _clutter_root_node_new (CoglFramebuffer *framebuffer, const ClutterColor *clear_color, CoglBufferBit clear_flags); ClutterPaintNode * _clutter_transform_node_new (const CoglMatrix *matrix); ClutterPaintNode * _clutter_dummy_node_new (ClutterActor *actor); void _clutter_paint_node_paint (ClutterPaintNode *root); void _clutter_paint_node_dump_tree (ClutterPaintNode *root); G_GNUC_INTERNAL void clutter_paint_node_remove_child (ClutterPaintNode *node, ClutterPaintNode *child); G_GNUC_INTERNAL void clutter_paint_node_replace_child (ClutterPaintNode *node, ClutterPaintNode *old_child, ClutterPaintNode *new_child); G_GNUC_INTERNAL void clutter_paint_node_remove_all (ClutterPaintNode *node); G_GNUC_INTERNAL guint clutter_paint_node_get_n_children (ClutterPaintNode *node); G_GNUC_INTERNAL ClutterPaintNode * clutter_paint_node_get_first_child (ClutterPaintNode *node); G_GNUC_INTERNAL ClutterPaintNode * clutter_paint_node_get_previous_sibling (ClutterPaintNode *node); G_GNUC_INTERNAL ClutterPaintNode * clutter_paint_node_get_next_sibling (ClutterPaintNode *node); G_GNUC_INTERNAL ClutterPaintNode * clutter_paint_node_get_last_child (ClutterPaintNode *node); G_GNUC_INTERNAL ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node); G_GNUC_INTERNAL CoglFramebuffer * clutter_paint_node_get_framebuffer (ClutterPaintNode *node); #define CLUTTER_TYPE_LAYER_NODE (_clutter_layer_node_get_type ()) #define CLUTTER_LAYER_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYER_NODE, ClutterLayerNode)) #define CLUTTER_IS_LAYER_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYER_NODE)) /* * ClutterLayerNode: * * The #ClutterLayerNode structure is an opaque * type whose members cannot be directly accessed. * * Since: 1.10 */ typedef struct _ClutterLayerNode ClutterLayerNode; typedef struct _ClutterLayerNodeClass ClutterLayerNodeClass; GType _clutter_layer_node_get_type (void) G_GNUC_CONST; ClutterPaintNode * _clutter_layer_node_new (const CoglMatrix *projection, const cairo_rectangle_t *viewport, float width, float height, guint8 opacity); G_END_DECLS #endif /* __CLUTTER_PAINT_NODE_PRIVATE_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-paint-volume-private.h�����������������������������������������0000664�0001750�0001750�00000013466�14211404421�024233� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_PAINT_VOLUME_PRIVATE_H__ #define __CLUTTER_PAINT_VOLUME_PRIVATE_H__ #include <clutter/clutter-types.h> #include <clutter/clutter-private.h> G_BEGIN_DECLS struct _ClutterPaintVolume { /* A paint volume represents a volume in a given actors private * coordinate system. */ ClutterActor *actor; /* cuboid for the volume: * * 4━━━━━━━┓5 * ┏━━━━━━━━┓╱┃ * ┃0 ┊7 1┃ ┃ * ┃ ┄┄┄┄┄┃┄┃6 * ┃3 2┃╱ * ┗━━━━━━━━┛ * * 0: top, left (origin) : always valid * 1: top, right : always valid * 2: bottom, right : updated lazily * 3: bottom, left : always valid * * 4: top, left, back : always valid * 5: top, right, back : updated lazily * 6: bottom, right, back : updated lazily * 7: bottom, left, back : updated lazily * * Elements 0, 1, 3 and 4 are filled in by the PaintVolume setters * * Note: the reason for this ordering is that we can simply ignore * elements 4, 5, 6 and 7 most of the time for 2D actors when * calculating the projected paint box. */ ClutterVertex vertices[8]; /* As an optimization for internally managed PaintVolumes we allow * initializing ClutterPaintVolume variables allocated on the stack * so we can avoid hammering the slice allocator. */ guint is_static:1; /* A newly initialized PaintVolume is considered empty as it is * degenerate on all three axis. * * We consider this carefully when we union an empty volume with * another so that the union simply results in a copy of the other * volume instead of also bounding the origin of the empty volume. * * For example this is a convenient property when calculating the * volume of a container as the union of the volume of its children * where the initial volume passed to the containers * ->get_paint_volume method will be empty. */ guint is_empty:1; /* TRUE when we've updated the values we calculate lazily */ guint is_complete:1; /* TRUE if vertices 4-7 can be ignored. (Only valid if complete is * TRUE) */ guint is_2d:1; /* Set to TRUE initialy but cleared if the paint volume is * transfomed by a matrix. */ guint is_axis_aligned:1; /* Note: There is a precedence to the above bitfields that should be * considered whenever we implement code that manipulates * PaintVolumes... * * Firstly if ->is_empty == TRUE then the values for ->is_complete * and ->is_2d are undefined, so you should typically check * ->is_empty as the first priority. * * XXX: document other invariables... */ }; void _clutter_paint_volume_init_static (ClutterPaintVolume *pv, ClutterActor *actor); ClutterPaintVolume *_clutter_paint_volume_new (ClutterActor *actor); void _clutter_paint_volume_copy_static (const ClutterPaintVolume *src_pv, ClutterPaintVolume *dst_pv); void _clutter_paint_volume_set_from_volume (ClutterPaintVolume *pv, const ClutterPaintVolume *src); void _clutter_paint_volume_complete (ClutterPaintVolume *pv); void _clutter_paint_volume_transform (ClutterPaintVolume *pv, const CoglMatrix *matrix); void _clutter_paint_volume_project (ClutterPaintVolume *pv, const CoglMatrix *modelview, const CoglMatrix *projection, const float *viewport); void _clutter_paint_volume_get_bounding_box (ClutterPaintVolume *pv, ClutterActorBox *box); void _clutter_paint_volume_axis_align (ClutterPaintVolume *pv); void _clutter_paint_volume_set_reference_actor (ClutterPaintVolume *pv, ClutterActor *actor); ClutterCullResult _clutter_paint_volume_cull (ClutterPaintVolume *pv, const ClutterPlane *planes); void _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolume *pv, ClutterStage *stage, ClutterActorBox *box); void _clutter_paint_volume_transform_relative (ClutterPaintVolume *pv, ClutterActor *relative_to_ancestor); G_END_DECLS #endif /* __CLUTTER_PAINT_VOLUME_PRIVATE_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-backend.c������������������������������������������������������0000664�0001750�0001750�00000113541�14211404421�021520� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: * Matthew Allum <mallum@openedhand.com> * Emmanuele Bassi <ebassi@linux.intel.com> * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-backend * @short_description: Backend abstraction * * Clutter can be compiled against different backends. Each backend * has to implement a set of functions, in order to be used by Clutter. * * #ClutterBackend is the base class abstracting the various implementation; * it provides a basic API to query the backend for generic information * and settings. * * #ClutterBackend is available since Clutter 0.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-backend-private.h" #include "clutter-debug.h" #include "clutter-event-private.h" #include "clutter-marshal.h" #include "clutter-muffin.h" #include "clutter-private.h" #include "clutter-stage-manager-private.h" #include "clutter-stage-private.h" #include "clutter-stage-window.h" #include "clutter-version.h" #include "clutter-device-manager-private.h" #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-backend.h" #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT #include "wayland/clutter-wayland-compositor.h" #endif #include <cogl/cogl.h> #ifdef CLUTTER_INPUT_X11 #include "x11/clutter-backend-x11.h" #endif #ifdef CLUTTER_INPUT_EVDEV #include "evdev/clutter-device-manager-evdev.h" #endif #ifdef CLUTTER_WINDOWING_EGL #include "egl/clutter-backend-eglnative.h" #endif #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT #include <cogl/cogl-wayland-server.h> #include <wayland-server.h> #include "wayland/clutter-wayland-compositor.h" #endif #define DEFAULT_FONT_NAME "Sans 10" enum { RESOLUTION_CHANGED, FONT_CHANGED, SETTINGS_CHANGED, LAST_SIGNAL }; G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT) static guint backend_signals[LAST_SIGNAL] = { 0, }; /* Global for being able to specify a compositor side wayland display * pointer before clutter initialization */ #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT static struct wl_display *_wayland_compositor_display; #endif static void clutter_backend_dispose (GObject *gobject) { ClutterBackend *backend = CLUTTER_BACKEND (gobject); /* clear the events still in the queue of the main context */ _clutter_clear_events_queue (); /* remove all event translators */ g_clear_pointer (&backend->event_translators, g_list_free); g_clear_pointer (&backend->dummy_onscreen, cogl_object_unref); G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject); } static void clutter_backend_finalize (GObject *gobject) { ClutterBackend *backend = CLUTTER_BACKEND (gobject); g_source_destroy (backend->cogl_source); free (backend->font_name); clutter_backend_set_font_options (backend, NULL); g_clear_object (&backend->input_method); G_OBJECT_CLASS (clutter_backend_parent_class)->finalize (gobject); } static gfloat get_units_per_em (ClutterBackend *backend, PangoFontDescription *font_desc) { gfloat units_per_em = -1.0; gboolean free_font_desc = FALSE; gdouble dpi; dpi = clutter_backend_get_resolution (backend); if (font_desc == NULL) { ClutterSettings *settings; gchar *font_name = NULL; settings = clutter_settings_get_default (); g_object_get (settings, "font-name", &font_name, NULL); if (G_LIKELY (font_name != NULL && *font_name != '\0')) { font_desc = pango_font_description_from_string (font_name); free_font_desc = TRUE; free (font_name); } } if (font_desc != NULL) { gdouble font_size = 0; gint pango_size; gboolean is_absolute; pango_size = pango_font_description_get_size (font_desc); is_absolute = pango_font_description_get_size_is_absolute (font_desc); /* "absolute" means "device units" (usually, pixels); otherwise, * it means logical units (points) */ if (is_absolute) font_size = (gdouble) pango_size / PANGO_SCALE; else font_size = dpi * ((gdouble) pango_size / PANGO_SCALE) / 72.0f; /* 10 points at 96 DPI is 13.3 pixels */ units_per_em = (1.2f * font_size) * dpi / 96.0f; } else units_per_em = -1.0f; if (free_font_desc) pango_font_description_free (font_desc); return units_per_em; } static void clutter_backend_real_resolution_changed (ClutterBackend *backend) { ClutterMainContext *context; ClutterSettings *settings; gdouble resolution; gint dpi; settings = clutter_settings_get_default (); g_object_get (settings, "font-dpi", &dpi, NULL); if (dpi < 0) resolution = 96.0; else resolution = dpi / 1024.0; context = _clutter_context_get_default (); if (context->font_map != NULL) cogl_pango_font_map_set_resolution (context->font_map, resolution); backend->units_per_em = get_units_per_em (backend, NULL); backend->units_serial += 1; CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->units_per_em); } static void clutter_backend_real_font_changed (ClutterBackend *backend) { backend->units_per_em = get_units_per_em (backend, NULL); backend->units_serial += 1; CLUTTER_NOTE (BACKEND, "Units per em: %.2f", backend->units_per_em); } static gboolean clutter_backend_do_real_create_context (ClutterBackend *backend, CoglDriver driver_id, GError **error) { ClutterBackendClass *klass; CoglSwapChain *swap_chain; GError *internal_error; klass = CLUTTER_BACKEND_GET_CLASS (backend); swap_chain = NULL; internal_error = NULL; CLUTTER_NOTE (BACKEND, "Creating Cogl renderer"); backend->cogl_renderer = klass->get_renderer (backend, &internal_error); if (backend->cogl_renderer == NULL) goto error; CLUTTER_NOTE (BACKEND, "Connecting the renderer"); cogl_renderer_set_driver (backend->cogl_renderer, driver_id); if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error)) goto error; CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain"); swap_chain = cogl_swap_chain_new (); CLUTTER_NOTE (BACKEND, "Creating Cogl display"); if (klass->get_display != NULL) { backend->cogl_display = klass->get_display (backend, backend->cogl_renderer, swap_chain, &internal_error); } else { CoglOnscreenTemplate *tmpl; gboolean res; tmpl = cogl_onscreen_template_new (swap_chain); /* XXX: I have some doubts that this is a good design. * * Conceptually should we be able to check an onscreen_template * without more details about the CoglDisplay configuration? */ res = cogl_renderer_check_onscreen_template (backend->cogl_renderer, tmpl, &internal_error); if (!res) goto error; backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl); /* the display owns the template */ cogl_object_unref (tmpl); } if (backend->cogl_display == NULL) goto error; #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT cogl_wayland_display_set_compositor_display (backend->cogl_display, _wayland_compositor_display); #endif CLUTTER_NOTE (BACKEND, "Setting up the display"); if (!cogl_display_setup (backend->cogl_display, &internal_error)) goto error; CLUTTER_NOTE (BACKEND, "Creating the Cogl context"); backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error); if (backend->cogl_context == NULL) goto error; /* the display owns the renderer and the swap chain */ cogl_object_unref (backend->cogl_renderer); cogl_object_unref (swap_chain); return TRUE; error: if (backend->cogl_display != NULL) { cogl_object_unref (backend->cogl_display); backend->cogl_display = NULL; } if (backend->cogl_renderer != NULL) { cogl_object_unref (backend->cogl_renderer); backend->cogl_renderer = NULL; } if (swap_chain != NULL) cogl_object_unref (swap_chain); return FALSE; } static const struct { const char *driver_name; const char *driver_desc; CoglDriver driver_id; } all_known_drivers[] = { { "gl3", "OpenGL 3.2 core profile", COGL_DRIVER_GL3 }, { "gl", "OpenGL legacy profile", COGL_DRIVER_GL }, { "gles2", "OpenGL ES 2.0", COGL_DRIVER_GLES2 }, { "any", "Default Cogl driver", COGL_DRIVER_ANY }, }; static const char *allowed_drivers; static gboolean clutter_backend_real_create_context (ClutterBackend *backend, GError **error) { GError *internal_error = NULL; const char *drivers_list; char **known_drivers; gboolean allow_any; int i; if (backend->cogl_context != NULL) return TRUE; if (allowed_drivers == NULL) allowed_drivers = CLUTTER_DRIVERS; allow_any = strstr (allowed_drivers, "*") != NULL; drivers_list = g_getenv ("CLUTTER_DRIVER"); if (drivers_list == NULL) drivers_list = allowed_drivers; known_drivers = g_strsplit (drivers_list, ",", 0); for (i = 0; backend->cogl_context == NULL && known_drivers[i] != NULL; i++) { const char *driver_name = known_drivers[i]; gboolean is_any = g_str_equal (driver_name, "*"); int j; for (j = 0; j < G_N_ELEMENTS (all_known_drivers); j++) { if (!allow_any && !is_any && !strstr (driver_name, all_known_drivers[j].driver_name)) continue; if ((allow_any && is_any) || (is_any && strstr (allowed_drivers, all_known_drivers[j].driver_name)) || g_str_equal (all_known_drivers[j].driver_name, driver_name)) { CLUTTER_NOTE (BACKEND, "Checking for the %s driver", all_known_drivers[j].driver_desc); if (clutter_backend_do_real_create_context (backend, all_known_drivers[j].driver_id, &internal_error)) break; if (internal_error) { CLUTTER_NOTE (BACKEND, "Unable to use the %s driver: %s", all_known_drivers[j].driver_desc, internal_error->message); g_clear_error (&internal_error); } } } } g_strfreev (known_drivers); if (backend->cogl_context == NULL) { if (internal_error != NULL) g_propagate_error (error, internal_error); else g_set_error_literal (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_BACKEND, _("Unable to initialize the Clutter backend: no available drivers found.")); return FALSE; } backend->cogl_source = cogl_glib_source_new (backend->cogl_context, G_PRIORITY_DEFAULT); g_source_attach (backend->cogl_source, NULL); return TRUE; } static ClutterFeatureFlags clutter_backend_real_get_features (ClutterBackend *backend) { ClutterFeatureFlags flags = 0; if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN)) { CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers"); flags |= CLUTTER_FEATURE_STAGE_MULTIPLE; } else { CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer"); flags |= CLUTTER_FEATURE_STAGE_STATIC; } if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE)) { CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling"); flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK; } else CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling"); if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT)) { CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events"); flags |= CLUTTER_FEATURE_SWAP_EVENTS; } return flags; } static const char *allowed_backends; static ClutterBackend * (* custom_backend_func) (void); static const struct { const char *name; ClutterBackend * (* create_backend) (void); } available_backends[] = { #ifdef CLUTTER_WINDOWING_X11 { CLUTTER_WINDOWING_X11, clutter_backend_x11_new }, #endif #ifdef CLUTTER_WINDOWING_EGL { CLUTTER_WINDOWING_EGL, clutter_backend_egl_native_new }, #endif { NULL, NULL }, }; void clutter_set_custom_backend_func (ClutterBackend *(* func) (void)) { custom_backend_func = func; } ClutterBackend * _clutter_create_backend (void) { const char *backends_list; ClutterBackend *retval; gboolean allow_any; char **backends; int i; if (custom_backend_func) { retval = custom_backend_func (); if (!retval) g_error ("Failed to create custom backend."); return retval; } if (allowed_backends == NULL) allowed_backends = "*"; allow_any = strstr (allowed_backends, "*") != NULL; backends_list = g_getenv ("CLUTTER_BACKEND"); if (backends_list == NULL) backends_list = allowed_backends; backends = g_strsplit (backends_list, ",", 0); retval = NULL; for (i = 0; retval == NULL && backends[i] != NULL; i++) { const char *backend = backends[i]; gboolean is_any = g_str_equal (backend, "*"); int j; for (j = 0; available_backends[j].name != NULL; j++) { if ((is_any && allow_any) || (is_any && strstr (allowed_backends, available_backends[j].name)) || g_str_equal (backend, available_backends[j].name)) { retval = available_backends[j].create_backend (); if (retval != NULL) break; } } } g_strfreev (backends); if (retval == NULL) g_error ("No default Clutter backend found."); return retval; } static void clutter_backend_real_init_events (ClutterBackend *backend) { const char *input_backend = NULL; input_backend = g_getenv ("CLUTTER_INPUT_BACKEND"); if (input_backend != NULL) input_backend = g_intern_string (input_backend); #ifdef CLUTTER_INPUT_X11 if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) && (input_backend == NULL || input_backend == I_(CLUTTER_INPUT_X11))) { _clutter_backend_x11_events_init (backend); } else #endif #ifdef CLUTTER_INPUT_EVDEV /* Evdev can be used regardless of the windowing system */ if ((input_backend != NULL && strcmp (input_backend, CLUTTER_INPUT_EVDEV) == 0) #ifdef CLUTTER_WINDOWING_EGL /* but we do want to always use it for EGL native */ || clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL) #endif ) { _clutter_events_evdev_init (backend); } else #endif if (input_backend != NULL) { if (input_backend != I_(CLUTTER_INPUT_NULL)) g_error ("Unrecognized input backend '%s'", input_backend); } else g_error ("Unknown input backend"); } static ClutterDeviceManager * clutter_backend_real_get_device_manager (ClutterBackend *backend) { if (G_UNLIKELY (backend->device_manager == NULL)) { g_critical ("No device manager available, expect broken input"); return NULL; } return backend->device_manager; } static gboolean clutter_backend_real_translate_event (ClutterBackend *backend, gpointer native, ClutterEvent *event) { GList *l; for (l = backend->event_translators; l != NULL; l = l->next) { ClutterEventTranslator *translator = l->data; ClutterTranslateReturn retval; retval = _clutter_event_translator_translate_event (translator, native, event); if (retval == CLUTTER_TRANSLATE_QUEUE) return TRUE; if (retval == CLUTTER_TRANSLATE_REMOVE) return FALSE; } return FALSE; } static void clutter_backend_class_init (ClutterBackendClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = clutter_backend_dispose; gobject_class->finalize = clutter_backend_finalize; /** * ClutterBackend::resolution-changed: * @backend: the #ClutterBackend that emitted the signal * * The ::resolution-changed signal is emitted each time the font * resolutions has been changed through #ClutterSettings. * * Since: 1.0 */ backend_signals[RESOLUTION_CHANGED] = g_signal_new (I_("resolution-changed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterBackendClass, resolution_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterBackend::font-changed: * @backend: the #ClutterBackend that emitted the signal * * The ::font-changed signal is emitted each time the font options * have been changed through #ClutterSettings. * * Since: 1.0 */ backend_signals[FONT_CHANGED] = g_signal_new (I_("font-changed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterBackendClass, font_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterBackend::settings-changed: * @backend: the #ClutterBackend that emitted the signal * * The ::settings-changed signal is emitted each time the #ClutterSettings * properties have been changed. * * Since: 1.4 */ backend_signals[SETTINGS_CHANGED] = g_signal_new (I_("settings-changed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterBackendClass, settings_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); klass->resolution_changed = clutter_backend_real_resolution_changed; klass->font_changed = clutter_backend_real_font_changed; klass->init_events = clutter_backend_real_init_events; klass->get_device_manager = clutter_backend_real_get_device_manager; klass->translate_event = clutter_backend_real_translate_event; klass->create_context = clutter_backend_real_create_context; klass->get_features = clutter_backend_real_get_features; } static void clutter_backend_init (ClutterBackend *self) { self->units_per_em = -1.0; self->units_serial = 1; self->dummy_onscreen = COGL_INVALID_HANDLE; } void _clutter_backend_add_options (ClutterBackend *backend, GOptionGroup *group) { ClutterBackendClass *klass; g_assert (CLUTTER_IS_BACKEND (backend)); klass = CLUTTER_BACKEND_GET_CLASS (backend); if (klass->add_options) klass->add_options (backend, group); } gboolean _clutter_backend_pre_parse (ClutterBackend *backend, GError **error) { ClutterBackendClass *klass; g_assert (CLUTTER_IS_BACKEND (backend)); klass = CLUTTER_BACKEND_GET_CLASS (backend); if (klass->pre_parse) return klass->pre_parse (backend, error); return TRUE; } gboolean _clutter_backend_post_parse (ClutterBackend *backend, GError **error) { ClutterBackendClass *klass; g_assert (CLUTTER_IS_BACKEND (backend)); klass = CLUTTER_BACKEND_GET_CLASS (backend); if (klass->post_parse) return klass->post_parse (backend, error); return TRUE; } ClutterStageWindow * _clutter_backend_create_stage (ClutterBackend *backend, ClutterStage *wrapper, GError **error) { ClutterBackendClass *klass; ClutterStageWindow *stage_window; g_assert (CLUTTER_IS_BACKEND (backend)); g_assert (CLUTTER_IS_STAGE (wrapper)); klass = CLUTTER_BACKEND_GET_CLASS (backend); if (klass->create_stage != NULL) stage_window = klass->create_stage (backend, wrapper, error); else stage_window = NULL; if (stage_window == NULL) return NULL; g_assert (CLUTTER_IS_STAGE_WINDOW (stage_window)); return stage_window; } gboolean _clutter_backend_create_context (ClutterBackend *backend, GError **error) { ClutterBackendClass *klass; klass = CLUTTER_BACKEND_GET_CLASS (backend); return klass->create_context (backend, error); } ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend) { ClutterBackendClass *klass; GError *error; g_assert (CLUTTER_IS_BACKEND (backend)); klass = CLUTTER_BACKEND_GET_CLASS (backend); /* we need to have a context here; so we create the * GL context first and the ask for features. if the * context already exists this should be a no-op */ error = NULL; if (klass->create_context != NULL) { gboolean res; res = klass->create_context (backend, &error); if (!res) { if (error) { g_critical ("Unable to create a context: %s", error->message); g_error_free (error); } else g_critical ("Unable to create a context: unknown error"); return 0; } } if (klass->get_features) return klass->get_features (backend); return 0; } void _clutter_backend_init_events (ClutterBackend *backend) { ClutterBackendClass *klass; g_assert (CLUTTER_IS_BACKEND (backend)); klass = CLUTTER_BACKEND_GET_CLASS (backend); klass->init_events (backend); } gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend, PangoFontDescription *font_desc) { /* recompute for the font description, but do not cache the result */ if (font_desc != NULL) return get_units_per_em (backend, font_desc); if (backend->units_per_em < 0) backend->units_per_em = get_units_per_em (backend, NULL); return backend->units_per_em; } void _clutter_backend_copy_event_data (ClutterBackend *backend, const ClutterEvent *src, ClutterEvent *dest) { ClutterEventExtenderInterface *iface; ClutterBackendClass *klass; klass = CLUTTER_BACKEND_GET_CLASS (backend); if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager)) { iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager); iface->copy_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager), src, dest); } else if (klass->copy_event_data != NULL) klass->copy_event_data (backend, src, dest); } void _clutter_backend_free_event_data (ClutterBackend *backend, ClutterEvent *event) { ClutterEventExtenderInterface *iface; ClutterBackendClass *klass; klass = CLUTTER_BACKEND_GET_CLASS (backend); if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager)) { iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager); iface->free_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager), event); } else if (klass->free_event_data != NULL) klass->free_event_data (backend, event); } /** * clutter_get_default_backend: * * Retrieves the default #ClutterBackend used by Clutter. The * #ClutterBackend holds backend-specific configuration options. * * Return value: (transfer none): the default backend. You should * not ref or unref the returned object. Applications should rarely * need to use this. * * Since: 0.4 */ ClutterBackend * clutter_get_default_backend (void) { ClutterMainContext *clutter_context; clutter_context = _clutter_context_get_default (); return clutter_context->backend; } /** * clutter_backend_set_double_click_time: * @backend: a #ClutterBackend * @msec: milliseconds between two button press events * * Sets the maximum time between two button press events, used to * verify whether it's a double click event or not. * * Since: 0.4 * * Deprecated: 1.4: Use #ClutterSettings:double-click-time instead */ void clutter_backend_set_double_click_time (ClutterBackend *backend, guint msec) { ClutterSettings *settings = clutter_settings_get_default (); g_object_set (settings, "double-click-time", msec, NULL); } /** * clutter_backend_get_double_click_time: * @backend: a #ClutterBackend * * Gets the maximum time between two button press events, as set * by clutter_backend_set_double_click_time(). * * Return value: a time in milliseconds * * Since: 0.4 * * Deprecated: 1.4: Use #ClutterSettings:double-click-time instead */ guint clutter_backend_get_double_click_time (ClutterBackend *backend) { ClutterSettings *settings = clutter_settings_get_default (); gint retval; g_object_get (settings, "double-click-time", &retval, NULL); return retval; } /** * clutter_backend_set_double_click_distance: * @backend: a #ClutterBackend * @distance: a distance, in pixels * * Sets the maximum distance used to verify a double click event. * * Since: 0.4 * * Deprecated: 1.4: Use #ClutterSettings:double-click-distance instead */ void clutter_backend_set_double_click_distance (ClutterBackend *backend, guint distance) { ClutterSettings *settings = clutter_settings_get_default (); g_object_set (settings, "double-click-distance", distance, NULL); } /** * clutter_backend_get_double_click_distance: * @backend: a #ClutterBackend * * Retrieves the distance used to verify a double click event * * Return value: a distance, in pixels. * * Since: 0.4 * * Deprecated: 1.4: Use #ClutterSettings:double-click-distance instead */ guint clutter_backend_get_double_click_distance (ClutterBackend *backend) { ClutterSettings *settings = clutter_settings_get_default (); gint retval; g_object_get (settings, "double-click-distance", &retval, NULL); return retval; } /** * clutter_backend_set_resolution: * @backend: a #ClutterBackend * @dpi: the resolution in "dots per inch" (Physical inches aren't * actually involved; the terminology is conventional). * * Sets the resolution for font handling on the screen. This is a * scale factor between points specified in a #PangoFontDescription * and cairo units. The default value is 96, meaning that a 10 point * font will be 13 units high. (10 * 96. / 72. = 13.3). * * Applications should never need to call this function. * * Since: 0.4 * * Deprecated: 1.4: Use #ClutterSettings:font-dpi instead */ void clutter_backend_set_resolution (ClutterBackend *backend, gdouble dpi) { ClutterSettings *settings; gint resolution; g_return_if_fail (CLUTTER_IS_BACKEND (backend)); if (dpi < 0) resolution = -1; else resolution = dpi * 1024; settings = clutter_settings_get_default (); g_object_set (settings, "font-dpi", resolution, NULL); } /** * clutter_backend_get_resolution: * @backend: a #ClutterBackend * * Gets the resolution for font handling on the screen. * * The resolution is a scale factor between points specified in a * #PangoFontDescription and cairo units. The default value is 96.0, * meaning that a 10 point font will be 13 units * high (10 * 96. / 72. = 13.3). * * Clutter will set the resolution using the current backend when * initializing; the resolution is also stored in the * #ClutterSettings:font-dpi property. * * Return value: the current resolution, or -1 if no resolution * has been set. * * Since: 0.4 */ gdouble clutter_backend_get_resolution (ClutterBackend *backend) { ClutterSettings *settings; gint resolution; g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), -1.0); settings = clutter_settings_get_default (); g_object_get (settings, "font-dpi", &resolution, NULL); if (resolution < 0) return 96.0; return resolution / 1024.0; } /** * clutter_backend_set_font_options: * @backend: a #ClutterBackend * @options: Cairo font options for the backend, or %NULL * * Sets the new font options for @backend. The #ClutterBackend will * copy the #cairo_font_options_t. * * If @options is %NULL, the first following call to * clutter_backend_get_font_options() will return the default font * options for @backend. * * This function is intended for actors creating a Pango layout * using the PangoCairo API. * * Since: 0.8 */ void clutter_backend_set_font_options (ClutterBackend *backend, const cairo_font_options_t *options) { g_return_if_fail (CLUTTER_IS_BACKEND (backend)); if (backend->font_options != options) { if (backend->font_options) cairo_font_options_destroy (backend->font_options); if (options) backend->font_options = cairo_font_options_copy (options); else backend->font_options = NULL; g_signal_emit (backend, backend_signals[FONT_CHANGED], 0); } } /** * clutter_backend_get_font_options: * @backend: a #ClutterBackend * * Retrieves the font options for @backend. * * Return value: (transfer none): the font options of the #ClutterBackend. * The returned #cairo_font_options_t is owned by the backend and should * not be modified or freed * * Since: 0.8 */ const cairo_font_options_t * clutter_backend_get_font_options (ClutterBackend *backend) { g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL); if (G_LIKELY (backend->font_options)) return backend->font_options; backend->font_options = cairo_font_options_create (); cairo_font_options_set_hint_style (backend->font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_subpixel_order (backend->font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT); cairo_font_options_set_antialias (backend->font_options, CAIRO_ANTIALIAS_DEFAULT); g_signal_emit (backend, backend_signals[FONT_CHANGED], 0); return backend->font_options; } /** * clutter_backend_set_font_name: * @backend: a #ClutterBackend * @font_name: the name of the font * * Sets the default font to be used by Clutter. The @font_name string * must either be %NULL, which means that the font name from the * default #ClutterBackend will be used; or be something that can * be parsed by the pango_font_description_from_string() function. * * Since: 1.0 * * Deprecated: 1.4: Use #ClutterSettings:font-name instead */ void clutter_backend_set_font_name (ClutterBackend *backend, const gchar *font_name) { ClutterSettings *settings = clutter_settings_get_default (); g_object_set (settings, "font-name", font_name, NULL); } /** * clutter_backend_get_font_name: * @backend: a #ClutterBackend * * Retrieves the default font name as set by * clutter_backend_set_font_name(). * * Return value: the font name for the backend. The returned string is * owned by the #ClutterBackend and should never be modified or freed * * Since: 1.0 * * Deprecated: 1.4: Use #ClutterSettings:font-name instead */ const gchar * clutter_backend_get_font_name (ClutterBackend *backend) { ClutterSettings *settings; g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL); settings = clutter_settings_get_default (); /* XXX yuck. but we return a const pointer, so we need to * store it in the backend */ free (backend->font_name); g_object_get (settings, "font-name", &backend->font_name, NULL); return backend->font_name; } gint32 _clutter_backend_get_units_serial (ClutterBackend *backend) { return backend->units_serial; } gboolean _clutter_backend_translate_event (ClutterBackend *backend, gpointer native, ClutterEvent *event) { return CLUTTER_BACKEND_GET_CLASS (backend)->translate_event (backend, native, event); } void _clutter_backend_add_event_translator (ClutterBackend *backend, ClutterEventTranslator *translator) { if (g_list_find (backend->event_translators, translator) != NULL) return; backend->event_translators = g_list_prepend (backend->event_translators, translator); } void _clutter_backend_remove_event_translator (ClutterBackend *backend, ClutterEventTranslator *translator) { if (g_list_find (backend->event_translators, translator) == NULL) return; backend->event_translators = g_list_remove (backend->event_translators, translator); } /** * clutter_backend_get_cogl_context: (skip) * @backend: a #ClutterBackend * * Retrieves the #CoglContext associated with the given clutter * @backend. A #CoglContext is required when using some of the * experimental 2.0 Cogl API. * * Since CoglContext is itself experimental API this API should * be considered experimental too. * * This API is not yet supported on OSX because OSX still * uses the stub Cogl winsys and the Clutter backend doesn't * explicitly create a CoglContext. * * Return value: (transfer none): The #CoglContext associated with @backend. * * Since: 1.8 * Stability: unstable */ CoglContext * clutter_backend_get_cogl_context (ClutterBackend *backend) { return backend->cogl_context; } #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT /** * clutter_wayland_set_compositor_display: * @display: A compositor side struct wl_display pointer * * This informs Clutter of your compositor side Wayland display * object. This must be called before calling clutter_init(). * * Since: 1.8 * Stability: unstable */ void clutter_wayland_set_compositor_display (void *display) { if (_clutter_context_is_initialized ()) { g_warning ("%s() can only be used before calling clutter_init()", G_STRFUNC); return; } _wayland_compositor_display = display; } #endif /** * clutter_set_windowing_backend: * @backend_type: a comma separated list of windowing backends * * Restricts Clutter to only use the specified backend or list of backends. * * You can use one of the `CLUTTER_WINDOWING_*` symbols, e.g. * * |[<!-- language="C" --> * clutter_set_windowing_backend (CLUTTER_WINDOWING_X11); * ]| * * Will force Clutter to use the X11 windowing and input backend, and terminate * if the X11 backend could not be initialized successfully. * * Since Clutter 1.26, you can also use a comma-separated list of windowing * system backends to provide a fallback in case backends are not available or * enabled, e.g.: * * |[<!-- language="C" --> * clutter_set_windowing_backend ("gdk,wayland,x11"); * ]| * * Will make Clutter test for the GDK, Wayland, and X11 backends in that order. * * You can use the `*` special value to ask Clutter to use the internally * defined list of backends. For instance: * * |[<!-- language="C" --> * clutter_set_windowing_backend ("x11,wayland,*"); * ]| * * Will make Clutter test the X11 and Wayland backends, and then fall back * to the internal list of available backends. * * This function must be called before the first API call to Clutter, including * clutter_get_option_context() * * Since: 1.16 */ void clutter_set_windowing_backend (const char *backend_type) { g_return_if_fail (backend_type != NULL); allowed_backends = g_strdup (backend_type); } void clutter_try_set_windowing_backend (const char *backend_type) { if (allowed_backends == NULL) clutter_set_windowing_backend (backend_type); } PangoDirection _clutter_backend_get_keymap_direction (ClutterBackend *backend) { ClutterBackendClass *klass; klass = CLUTTER_BACKEND_GET_CLASS (backend); if (klass->get_keymap_direction != NULL) return klass->get_keymap_direction (backend); return PANGO_DIRECTION_NEUTRAL; } void _clutter_backend_reset_cogl_framebuffer (ClutterBackend *backend) { if (backend->dummy_onscreen == COGL_INVALID_HANDLE) { CoglError *internal_error = NULL; backend->dummy_onscreen = cogl_onscreen_new (backend->cogl_context, 1, 1); if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (backend->dummy_onscreen), &internal_error)) { g_critical ("Unable to create dummy onscreen: %s", internal_error->message); cogl_error_free (internal_error); return; } } cogl_set_framebuffer (COGL_FRAMEBUFFER (backend->dummy_onscreen)); } void clutter_set_allowed_drivers (const char *drivers) { if (_clutter_context_is_initialized ()) { g_warning ("Clutter has already been initialized.\n"); return; } allowed_drivers = g_strdup (drivers); } void clutter_backend_bell_notify (ClutterBackend *backend) { ClutterBackendClass *klass; klass = CLUTTER_BACKEND_GET_CLASS (backend); if (klass->bell_notify) klass->bell_notify (backend); } /** * clutter_backend_get_input_method: * @backend: the #CLutterBackend * * Returns the input method used by Clutter * * Returns: (transfer none): the input method **/ ClutterInputMethod * clutter_backend_get_input_method (ClutterBackend *backend) { return backend->input_method; } /** * clutter_backend_set_input_method: * @backend: the #ClutterBackend * @method: the input method * * Sets the input method to be used by Clutter **/ void clutter_backend_set_input_method (ClutterBackend *backend, ClutterInputMethod *method) { g_set_object (&backend->input_method, method); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-bin-layout.h���������������������������������������������������0000664�0001750�0001750�00000005475�14211404421�022227� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_BIN_LAYOUT_H__ #define __CLUTTER_BIN_LAYOUT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-layout-manager.h> G_BEGIN_DECLS #define CLUTTER_TYPE_BIN_LAYOUT (clutter_bin_layout_get_type ()) #define CLUTTER_BIN_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayout)) #define CLUTTER_IS_BIN_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYOUT)) #define CLUTTER_BIN_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutClass)) #define CLUTTER_IS_BIN_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BIN_LAYOUT)) #define CLUTTER_BIN_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutClass)) typedef struct _ClutterBinLayout ClutterBinLayout; typedef struct _ClutterBinLayoutPrivate ClutterBinLayoutPrivate; typedef struct _ClutterBinLayoutClass ClutterBinLayoutClass; /** * ClutterBinLayout: * * The #ClutterBinLayout structure contains only private data * and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterBinLayout { /*< private >*/ ClutterLayoutManager parent_instance; ClutterBinLayoutPrivate *priv; }; /** * ClutterBinLayoutClass: * * The #ClutterBinLayoutClass structure contains only private * data and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterBinLayoutClass { /*< private >*/ ClutterLayoutManagerClass parent_class; }; CLUTTER_AVAILABLE_IN_1_2 GType clutter_bin_layout_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 ClutterLayoutManager * clutter_bin_layout_new (ClutterBinAlignment x_align, ClutterBinAlignment y_align); G_END_DECLS #endif /* __CLUTTER_BIN_LAYOUT_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-base-types.c���������������������������������������������������0000664�0001750�0001750�00000105347�14211404421�022212� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-geometric-types * @Title: Base geometric types * @Short_Description: Common geometric data types used by Clutter * * Clutter defines a set of geometric data structures that are commonly used * across the whole API. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-types.h" #include "clutter-private.h" #include <math.h> #define FLOAT_EPSILON (1e-15) /* * ClutterGeometry */ static ClutterGeometry* clutter_geometry_copy (const ClutterGeometry *geometry) { return g_slice_dup (ClutterGeometry, geometry); } static void clutter_geometry_free (ClutterGeometry *geometry) { if (G_LIKELY (geometry != NULL)) g_slice_free (ClutterGeometry, geometry); } /** * clutter_geometry_union: * @geometry_a: a #ClutterGeometry * @geometry_b: another #ClutterGeometry * @result: (out): location to store the result * * Find the union of two rectangles represented as #ClutterGeometry. * * Since: 1.4 * * Deprecated: 1.16: Use #ClutterRect and clutter_rect_union() */ void clutter_geometry_union (const ClutterGeometry *geometry_a, const ClutterGeometry *geometry_b, ClutterGeometry *result) { /* We don't try to handle rectangles that can't be represented * as a signed integer box */ gint x_1 = MIN (geometry_a->x, geometry_b->x); gint y_1 = MIN (geometry_a->y, geometry_b->y); gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width, geometry_b->x + (gint)geometry_b->width); gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height, geometry_b->y + (gint)geometry_b->height); result->x = x_1; result->y = y_1; result->width = x_2 - x_1; result->height = y_2 - y_1; } /** * clutter_geometry_intersects: * @geometry0: The first geometry to test * @geometry1: The second geometry to test * * Determines if @geometry0 and geometry1 intersect returning %TRUE if * they do else %FALSE. * * Return value: %TRUE of @geometry0 and geometry1 intersect else * %FALSE. * * Since: 1.4 * * Deprecated: 1.16: Use #ClutterRect and clutter_rect_intersection() */ gboolean clutter_geometry_intersects (const ClutterGeometry *geometry0, const ClutterGeometry *geometry1) { if (geometry1->x >= (geometry0->x + (gint)geometry0->width) || geometry1->y >= (geometry0->y + (gint)geometry0->height) || (geometry1->x + (gint)geometry1->width) <= geometry0->x || (geometry1->y + (gint)geometry1->height) <= geometry0->y) return FALSE; else return TRUE; } static gboolean clutter_geometry_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterGeometry *a_geom = g_value_get_boxed (a); const ClutterGeometry *b_geom = g_value_get_boxed (b); ClutterGeometry res = { 0, }; gint a_width = a_geom->width; gint b_width = b_geom->width; gint a_height = a_geom->height; gint b_height = b_geom->height; res.x = a_geom->x + (b_geom->x - a_geom->x) * progress; res.y = a_geom->y + (b_geom->y - a_geom->y) * progress; res.width = a_width + (b_width - a_width) * progress; res.height = a_height + (b_height - a_height) * progress; g_value_set_boxed (retval, &res); return TRUE; } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry, clutter_geometry_copy, clutter_geometry_free, CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress)); /* * ClutterVertices */ /** * clutter_vertex_new: * @x: X coordinate * @y: Y coordinate * @z: Z coordinate * * Creates a new #ClutterVertex for the point in 3D space * identified by the 3 coordinates @x, @y, @z. * * This function is the logical equivalent of: * * |[ * clutter_vertex_init (clutter_vertex_alloc (), x, y, z); * ]| * * Return value: (transfer full): the newly allocated #ClutterVertex. * Use clutter_vertex_free() to free the resources * * Since: 1.0 */ ClutterVertex * clutter_vertex_new (gfloat x, gfloat y, gfloat z) { return clutter_vertex_init (clutter_vertex_alloc (), x, y, z); } /** * clutter_vertex_alloc: (constructor) * * Allocates a new, empty #ClutterVertex. * * Return value: (transfer full): the newly allocated #ClutterVertex. * Use clutter_vertex_free() to free its resources * * Since: 1.12 */ ClutterVertex * clutter_vertex_alloc (void) { return g_slice_new0 (ClutterVertex); } /** * clutter_vertex_init: * @vertex: a #ClutterVertex * @x: X coordinate * @y: Y coordinate * @z: Z coordinate * * Initializes @vertex with the given coordinates. * * Return value: (transfer none): the initialized #ClutterVertex * * Since: 1.10 */ ClutterVertex * clutter_vertex_init (ClutterVertex *vertex, gfloat x, gfloat y, gfloat z) { g_return_val_if_fail (vertex != NULL, NULL); vertex->x = x; vertex->y = y; vertex->z = z; return vertex; } /** * clutter_vertex_copy: * @vertex: a #ClutterVertex * * Copies @vertex * * Return value: (transfer full): a newly allocated copy of #ClutterVertex. * Use clutter_vertex_free() to free the allocated resources * * Since: 1.0 */ ClutterVertex * clutter_vertex_copy (const ClutterVertex *vertex) { if (G_LIKELY (vertex != NULL)) return g_slice_dup (ClutterVertex, vertex); return NULL; } /** * clutter_vertex_free: * @vertex: a #ClutterVertex * * Frees a #ClutterVertex allocated using clutter_vertex_alloc() or * clutter_vertex_copy(). * * Since: 1.0 */ void clutter_vertex_free (ClutterVertex *vertex) { if (G_UNLIKELY (vertex != NULL)) g_slice_free (ClutterVertex, vertex); } /** * clutter_vertex_equal: * @vertex_a: a #ClutterVertex * @vertex_b: a #ClutterVertex * * Compares @vertex_a and @vertex_b for equality * * Return value: %TRUE if the passed #ClutterVertex are equal * * Since: 1.0 */ gboolean clutter_vertex_equal (const ClutterVertex *vertex_a, const ClutterVertex *vertex_b) { g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE); if (vertex_a == vertex_b) return TRUE; return fabsf (vertex_a->x - vertex_b->x) < FLOAT_EPSILON && fabsf (vertex_a->y - vertex_b->y) < FLOAT_EPSILON && fabsf (vertex_a->z - vertex_b->z) < FLOAT_EPSILON; } static void clutter_vertex_interpolate (const ClutterVertex *a, const ClutterVertex *b, double progress, ClutterVertex *res) { res->x = a->x + (b->x - a->x) * progress; res->y = a->y + (b->y - a->y) * progress; res->z = a->z + (b->z - a->z) * progress; } static gboolean clutter_vertex_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterVertex *av = g_value_get_boxed (a); const ClutterVertex *bv = g_value_get_boxed (b); ClutterVertex res; clutter_vertex_interpolate (av, bv, progress, &res); g_value_set_boxed (retval, &res); return TRUE; } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex, clutter_vertex_copy, clutter_vertex_free, CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress)); /* * ClutterMargin */ /** * clutter_margin_new: * * Creates a new #ClutterMargin. * * Return value: (transfer full): a newly allocated #ClutterMargin. Use * clutter_margin_free() to free the resources associated with it when * done. * * Since: 1.10 */ ClutterMargin * clutter_margin_new (void) { return g_slice_new0 (ClutterMargin); } /** * clutter_margin_copy: * @margin_: a #ClutterMargin * * Creates a new #ClutterMargin and copies the contents of @margin_ into * the newly created structure. * * Return value: (transfer full): a copy of the #ClutterMargin. * * Since: 1.10 */ ClutterMargin * clutter_margin_copy (const ClutterMargin *margin_) { if (G_LIKELY (margin_ != NULL)) return g_slice_dup (ClutterMargin, margin_); return NULL; } /** * clutter_margin_free: * @margin_: a #ClutterMargin * * Frees the resources allocated by clutter_margin_new() and * clutter_margin_copy(). * * Since: 1.10 */ void clutter_margin_free (ClutterMargin *margin_) { if (G_LIKELY (margin_ != NULL)) g_slice_free (ClutterMargin, margin_); } G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin, clutter_margin_copy, clutter_margin_free) /* * ClutterPoint */ static const ClutterPoint _clutter_point_zero = CLUTTER_POINT_INIT_ZERO; /** * clutter_point_zero: * * A point centered at (0, 0). * * The returned value can be used as a guard. * * Return value: a point centered in (0, 0); the returned #ClutterPoint * is owned by Clutter and it should not be modified or freed. * * Since: 1.12 */ const ClutterPoint * clutter_point_zero (void) { return &_clutter_point_zero; } /** * clutter_point_alloc: (constructor) * * Allocates a new #ClutterPoint. * * Return value: (transfer full): the newly allocated #ClutterPoint. * Use clutter_point_free() to free its resources. * * Since: 1.12 */ ClutterPoint * clutter_point_alloc (void) { return g_slice_new0 (ClutterPoint); } /** * clutter_point_init: * @point: a #ClutterPoint * @x: the X coordinate of the point * @y: the Y coordinate of the point * * Initializes @point with the given coordinates. * * Return value: (transfer none): the initialized #ClutterPoint * * Since: 1.12 */ ClutterPoint * clutter_point_init (ClutterPoint *point, float x, float y) { g_return_val_if_fail (point != NULL, NULL); point->x = x; point->y = y; return point; } /** * clutter_point_copy: * @point: a #ClutterPoint * * Creates a new #ClutterPoint with the same coordinates of @point. * * Return value: (transfer full): a newly allocated #ClutterPoint. * Use clutter_point_free() to free its resources. * * Since: 1.12 */ ClutterPoint * clutter_point_copy (const ClutterPoint *point) { return g_slice_dup (ClutterPoint, point); } /** * clutter_point_free: * @point: a #ClutterPoint * * Frees the resources allocated for @point. * * Since: 1.12 */ void clutter_point_free (ClutterPoint *point) { if (point != NULL && point != &_clutter_point_zero) g_slice_free (ClutterPoint, point); } /** * clutter_point_equals: * @a: the first #ClutterPoint to compare * @b: the second #ClutterPoint to compare * * Compares two #ClutterPoint for equality. * * Return value: %TRUE if the #ClutterPoints are equal * * Since: 1.12 */ gboolean clutter_point_equals (const ClutterPoint *a, const ClutterPoint *b) { if (a == b) return TRUE; if (a == NULL || b == NULL) return FALSE; return fabsf (a->x - b->x) < FLOAT_EPSILON && fabsf (a->y - b->y) < FLOAT_EPSILON; } /** * clutter_point_distance: * @a: a #ClutterPoint * @b: a #ClutterPoint * @x_distance: (out) (allow-none): return location for the horizontal * distance between the points * @y_distance: (out) (allow-none): return location for the vertical * distance between the points * * Computes the distance between two #ClutterPoint. * * Return value: the distance between the points. * * Since: 1.12 */ float clutter_point_distance (const ClutterPoint *a, const ClutterPoint *b, float *x_distance, float *y_distance) { float x_d, y_d; g_return_val_if_fail (a != NULL, 0.f); g_return_val_if_fail (b != NULL, 0.f); if (clutter_point_equals (a, b)) return 0.f; x_d = (a->x - b->x); y_d = (a->y - b->y); if (x_distance != NULL) *x_distance = fabsf (x_d); if (y_distance != NULL) *y_distance = fabsf (y_d); return sqrt ((x_d * x_d) + (y_d * y_d)); } static gboolean clutter_point_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterPoint *ap = g_value_get_boxed (a); const ClutterPoint *bp = g_value_get_boxed (b); ClutterPoint res = CLUTTER_POINT_INIT (0, 0); res.x = ap->x + (bp->x - ap->x) * progress; res.y = ap->y + (bp->y - ap->y) * progress; g_value_set_boxed (retval, &res); return TRUE; } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterPoint, clutter_point, clutter_point_copy, clutter_point_free, CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_point_progress)) /* * ClutterSize */ /** * clutter_size_alloc: (constructor) * * Allocates a new #ClutterSize. * * Return value: (transfer full): the newly allocated #ClutterSize. * Use clutter_size_free() to free its resources. * * Since: 1.12 */ ClutterSize * clutter_size_alloc (void) { return g_slice_new0 (ClutterSize); } /** * clutter_size_init: * @size: a #ClutterSize * @width: the width * @height: the height * * Initializes a #ClutterSize with the given dimensions. * * Return value: (transfer none): the initialized #ClutterSize * * Since: 1.12 */ ClutterSize * clutter_size_init (ClutterSize *size, float width, float height) { g_return_val_if_fail (size != NULL, NULL); size->width = width; size->height = height; return size; } /** * clutter_size_copy: * @size: a #ClutterSize * * Creates a new #ClutterSize and duplicates @size. * * Return value: (transfer full): the newly allocated #ClutterSize. * Use clutter_size_free() to free its resources. * * Since: 1.12 */ ClutterSize * clutter_size_copy (const ClutterSize *size) { return g_slice_dup (ClutterSize, size); } /** * clutter_size_free: * @size: a #ClutterSize * * Frees the resources allocated for @size. * * Since: 1.12 */ void clutter_size_free (ClutterSize *size) { if (size != NULL) g_slice_free (ClutterSize, size); } /** * clutter_size_equals: * @a: a #ClutterSize to compare * @b: a #ClutterSize to compare * * Compares two #ClutterSize for equality. * * Return value: %TRUE if the two #ClutterSize are equal * * Since: 1.12 */ gboolean clutter_size_equals (const ClutterSize *a, const ClutterSize *b) { if (a == b) return TRUE; if (a == NULL || b == NULL) return FALSE; return fabsf (a->width - b->width) < FLOAT_EPSILON && fabsf (a->height - b->height) < FLOAT_EPSILON; } static gboolean clutter_size_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterSize *as = g_value_get_boxed (a); const ClutterSize *bs = g_value_get_boxed (b); ClutterSize res = CLUTTER_SIZE_INIT (0, 0); res.width = as->width + (bs->width - as->width) * progress; res.height = as->height + (bs->height - as->height) * progress; g_value_set_boxed (retval, &res); return TRUE; } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterSize, clutter_size, clutter_size_copy, clutter_size_free, CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_size_progress)) /* * ClutterRect */ static const ClutterRect _clutter_rect_zero = CLUTTER_RECT_INIT_ZERO; static gboolean clutter_rect_progress (const GValue *a, const GValue *b, gdouble progress, GValue *res); G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterRect, clutter_rect, clutter_rect_copy, clutter_rect_free, CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_rect_progress)) static inline void clutter_rect_normalize_internal (ClutterRect *rect) { if (rect->size.width >= 0.f && rect->size.height >= 0.f) return; if (rect->size.width < 0.f) { float size = fabsf (rect->size.width); rect->origin.x -= size; rect->size.width = size; } if (rect->size.height < 0.f) { float size = fabsf (rect->size.height); rect->origin.y -= size; rect->size.height = size; } } /** * clutter_rect_zero: * * A #ClutterRect with #ClutterRect.origin set at (0, 0) and a size * of 0. * * The returned value can be used as a guard. * * Return value: a rectangle with origin in (0, 0) and a size of 0. * The returned #ClutterRect is owned by Clutter and it should not * be modified or freed. * * Since: 1.12 */ const ClutterRect * clutter_rect_zero (void) { return &_clutter_rect_zero; } /** * clutter_rect_alloc: (constructor) * * Creates a new, empty #ClutterRect. * * You can use clutter_rect_init() to initialize the returned rectangle, * for instance: * * |[ * rect = clutter_rect_init (clutter_rect_alloc (), x, y, width, height); * ]| * * Return value: (transfer full): the newly allocated #ClutterRect. * Use clutter_rect_free() to free its resources * * Since: 1.12 */ ClutterRect * clutter_rect_alloc (void) { return g_slice_new0 (ClutterRect); } /** * clutter_rect_init: * @rect: a #ClutterRect * @x: X coordinate of the origin * @y: Y coordinate of the origin * @width: width of the rectangle * @height: height of the rectangle * * Initializes a #ClutterRect with the given origin and size. * * Return value: (transfer none): the updated rectangle * * Since: 1.12 */ ClutterRect * clutter_rect_init (ClutterRect *rect, float x, float y, float width, float height) { g_return_val_if_fail (rect != NULL, NULL); rect->origin.x = x; rect->origin.y = y; rect->size.width = width; rect->size.height = height; return rect; } /** * clutter_rect_copy: * @rect: a #ClutterRect * * Copies @rect into a new #ClutterRect instance. * * Return value: (transfer full): the newly allocate copy of @rect. * Use clutter_rect_free() to free the associated resources * * Since: 1.12 */ ClutterRect * clutter_rect_copy (const ClutterRect *rect) { if (rect != NULL) { ClutterRect *res; res = g_slice_dup (ClutterRect, rect); clutter_rect_normalize_internal (res); return res; } return NULL; } /** * clutter_rect_free: * @rect: a #ClutterRect * * Frees the resources allocated by @rect. * * Since: 1.12 */ void clutter_rect_free (ClutterRect *rect) { if (rect != NULL && rect != &_clutter_rect_zero) g_slice_free (ClutterRect, rect); } /** * clutter_rect_equals: * @a: a #ClutterRect * @b: a #ClutterRect * * Checks whether @a and @b are equals. * * This function will normalize both @a and @b before comparing * their origin and size. * * Return value: %TRUE if the rectangles match in origin and size. * * Since: 1.12 */ gboolean clutter_rect_equals (ClutterRect *a, ClutterRect *b) { if (a == b) return TRUE; if (a == NULL || b == NULL) return FALSE; clutter_rect_normalize_internal (a); clutter_rect_normalize_internal (b); return clutter_point_equals (&a->origin, &b->origin) && clutter_size_equals (&a->size, &b->size); } /** * clutter_rect_normalize: * @rect: a #ClutterRect * * Normalizes a #ClutterRect. * * A #ClutterRect is defined by the area covered by its size; this means * that a #ClutterRect with #ClutterRect.origin in [ 0, 0 ] and a * #ClutterRect.size of [ 10, 10 ] is equivalent to a #ClutterRect with * #ClutterRect.origin in [ 10, 10 ] and a #ClutterRect.size of [ -10, -10 ]. * * This function is useful to ensure that a rectangle has positive width * and height; it will modify the passed @rect and normalize its size. * * Since: 1.12 */ ClutterRect * clutter_rect_normalize (ClutterRect *rect) { g_return_val_if_fail (rect != NULL, NULL); clutter_rect_normalize_internal (rect); return rect; } /** * clutter_rect_get_center: * @rect: a #ClutterRect * @center: (out caller-allocates): a #ClutterPoint * * Retrieves the center of @rect, after normalizing the rectangle, * and updates @center with the correct coordinates. * * Since: 1.12 */ void clutter_rect_get_center (ClutterRect *rect, ClutterPoint *center) { g_return_if_fail (rect != NULL); g_return_if_fail (center != NULL); clutter_rect_normalize_internal (rect); center->x = rect->origin.x + (rect->size.width / 2.0f); center->y = rect->origin.y + (rect->size.height / 2.0f); } /** * clutter_rect_contains_point: * @rect: a #ClutterRect * @point: the point to check * * Checks whether @point is contained by @rect, after normalizing the * rectangle. * * Return value: %TRUE if the @point is contained by @rect. * * Since: 1.12 */ gboolean clutter_rect_contains_point (ClutterRect *rect, ClutterPoint *point) { g_return_val_if_fail (rect != NULL, FALSE); g_return_val_if_fail (point != NULL, FALSE); clutter_rect_normalize_internal (rect); return (point->x >= rect->origin.x) && (point->y >= rect->origin.y) && (point->x <= (rect->origin.x + rect->size.width)) && (point->y <= (rect->origin.y + rect->size.height)); } /** * clutter_rect_contains_rect: * @a: a #ClutterRect * @b: a #ClutterRect * * Checks whether @a contains @b. * * The first rectangle contains the second if the union of the * two #ClutterRect is equal to the first rectangle. * * Return value: %TRUE if the first rectangle contains the second. * * Since: 1.12 */ gboolean clutter_rect_contains_rect (ClutterRect *a, ClutterRect *b) { ClutterRect res; g_return_val_if_fail (a != NULL, FALSE); g_return_val_if_fail (b != NULL, FALSE); clutter_rect_union (a, b, &res); return clutter_rect_equals (a, &res); } /** * clutter_rect_union: * @a: a #ClutterRect * @b: a #ClutterRect * @res: (out caller-allocates): a #ClutterRect * * Computes the smallest possible rectangle capable of fully containing * both @a and @b, and places it into @res. * * This function will normalize both @a and @b prior to computing their * union. * * Since: 1.12 */ void clutter_rect_union (ClutterRect *a, ClutterRect *b, ClutterRect *res) { g_return_if_fail (a != NULL); g_return_if_fail (b != NULL); g_return_if_fail (res != NULL); clutter_rect_normalize_internal (a); clutter_rect_normalize_internal (b); res->origin.x = MIN (a->origin.x, b->origin.x); res->origin.y = MIN (a->origin.y, b->origin.y); res->size.width = MAX (a->size.width, b->size.width); res->size.height = MAX (a->size.height, b->size.height); } /** * clutter_rect_intersection: * @a: a #ClutterRect * @b: a #ClutterRect * @res: (out caller-allocates) (allow-none): a #ClutterRect, or %NULL * * Computes the intersection of @a and @b, and places it in @res, if @res * is not %NULL. * * This function will normalize both @a and @b prior to computing their * intersection. * * This function can be used to simply check if the intersection of @a and @b * is not empty, by using %NULL for @res. * * Return value: %TRUE if the intersection of @a and @b is not empty * * Since: 1.12 */ gboolean clutter_rect_intersection (ClutterRect *a, ClutterRect *b, ClutterRect *res) { float x_1, y_1, x_2, y_2; g_return_val_if_fail (a != NULL, FALSE); g_return_val_if_fail (b != NULL, FALSE); clutter_rect_normalize_internal (a); clutter_rect_normalize_internal (b); x_1 = MAX (a->origin.x, b->origin.x); y_1 = MAX (a->origin.y, b->origin.y); x_2 = MIN (a->origin.x + a->size.width, b->origin.x + b->size.width); y_2 = MIN (a->origin.y + a->size.height, b->origin.y + b->size.height); if (x_1 >= x_2 || y_1 >= y_2) { if (res != NULL) clutter_rect_init (res, 0.f, 0.f, 0.f, 0.f); return FALSE; } if (res != NULL) clutter_rect_init (res, x_1, y_1, x_2 - x_1, y_2 - y_1); return TRUE; } /** * clutter_rect_offset: * @rect: a #ClutterRect * @d_x: the horizontal offset value * @d_y: the vertical offset value * * Offsets the origin of @rect by the given values, after normalizing * the rectangle. * * Since: 1.12 */ void clutter_rect_offset (ClutterRect *rect, float d_x, float d_y) { g_return_if_fail (rect != NULL); clutter_rect_normalize_internal (rect); rect->origin.x += d_x; rect->origin.y += d_y; } /** * clutter_rect_inset: * @rect: a #ClutterRect * @d_x: an horizontal value; a positive @d_x will create an inset rectangle, * and a negative value will create a larger rectangle * @d_y: a vertical value; a positive @d_x will create an inset rectangle, * and a negative value will create a larger rectangle * * Normalizes the @rect and offsets its origin by the @d_x and @d_y values; * the size is adjusted by (2 * @d_x, 2 * @d_y). * * If @d_x and @d_y are positive the size of the rectangle is decreased; if * the values are negative, the size of the rectangle is increased. * * If the resulting rectangle has a negative width or height, the size is * set to 0. * * Since: 1.12 */ void clutter_rect_inset (ClutterRect *rect, float d_x, float d_y) { g_return_if_fail (rect != NULL); clutter_rect_normalize_internal (rect); rect->origin.x += d_x; rect->origin.y += d_y; if (d_x >= 0.f) rect->size.width -= (d_x * 2.f); else rect->size.width += (d_x * -2.f); if (d_y >= 0.f) rect->size.height -= (d_y * 2.f); else rect->size.height += (d_y * -2.f); if (rect->size.width < 0.f) rect->size.width = 0.f; if (rect->size.height < 0.f) rect->size.height = 0.f; } /** * clutter_rect_clamp_to_pixel: * @rect: a #ClutterRect * * Rounds the origin of @rect downwards to the nearest integer, and rounds * the size of @rect upwards to the nearest integer, so that @rect is * updated to the smallest rectangle capable of fully containing the * original, fractional rectangle. * * Since: 1.12 */ void clutter_rect_clamp_to_pixel (ClutterRect *rect) { g_return_if_fail (rect != NULL); clutter_rect_normalize_internal (rect); rect->origin.x = floorf (rect->origin.x); rect->origin.y = floorf (rect->origin.y); rect->size.width = ceilf (rect->size.width); rect->size.height = ceilf (rect->size.height); } /** * clutter_rect_get_x: * @rect: a #ClutterRect * * Retrieves the X coordinate of the origin of @rect. * * Return value: the X coordinate of the origin of the rectangle * * Since: 1.12 */ float clutter_rect_get_x (ClutterRect *rect) { g_return_val_if_fail (rect != NULL, 0.f); clutter_rect_normalize_internal (rect); return rect->origin.x; } /** * clutter_rect_get_y: * @rect: a #ClutterRect * * Retrieves the Y coordinate of the origin of @rect. * * Return value: the Y coordinate of the origin of the rectangle * * Since: 1.12 */ float clutter_rect_get_y (ClutterRect *rect) { g_return_val_if_fail (rect != NULL, 0.f); clutter_rect_normalize_internal (rect); return rect->origin.y; } /** * clutter_rect_get_width: * @rect: a #ClutterRect * * Retrieves the width of @rect. * * Return value: the width of the rectangle * * Since: 1.12 */ float clutter_rect_get_width (ClutterRect *rect) { g_return_val_if_fail (rect != NULL, 0.f); clutter_rect_normalize_internal (rect); return rect->size.width; } /** * clutter_rect_get_height: * @rect: a #ClutterRect * * Retrieves the height of @rect. * * Return value: the height of the rectangle * * Since: 1.12 */ float clutter_rect_get_height (ClutterRect *rect) { g_return_val_if_fail (rect != NULL, 0.f); clutter_rect_normalize_internal (rect); return rect->size.height; } static gboolean clutter_rect_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterRect *rect_a = g_value_get_boxed (a); const ClutterRect *rect_b = g_value_get_boxed (b); ClutterRect res = CLUTTER_RECT_INIT_ZERO; #define INTERPOLATE(r_a,r_b,member,field,factor) ((r_a)->member.field + (((r_b)->member.field - ((r_a)->member.field)) * (factor))) res.origin.x = INTERPOLATE (rect_a, rect_b, origin, x, progress); res.origin.y = INTERPOLATE (rect_a, rect_b, origin, y, progress); res.size.width = INTERPOLATE (rect_a, rect_b, size, width, progress); res.size.height = INTERPOLATE (rect_a, rect_b, size, height, progress); #undef INTERPOLATE g_value_set_boxed (retval, &res); return TRUE; } /** * ClutterMatrix: * * A type representing a 4x4 matrix. * * It is identicaly to #CoglMatrix. * * Since: 1.12 */ static gpointer clutter_matrix_copy (gpointer data) { return cogl_matrix_copy (data); } static gboolean clutter_matrix_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterMatrix *matrix1 = g_value_get_boxed (a); const ClutterMatrix *matrix2 = g_value_get_boxed (b); ClutterVertex scale1 = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f); float shear1[3] = { 0.f, 0.f, 0.f }; ClutterVertex rotate1 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex translate1 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex4 perspective1 = { 0.f, 0.f, 0.f, 0.f }; ClutterVertex scale2 = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f); float shear2[3] = { 0.f, 0.f, 0.f }; ClutterVertex rotate2 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex translate2 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex4 perspective2 = { 0.f, 0.f, 0.f, 0.f }; ClutterVertex scale_res = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f); float shear_res = 0.f; ClutterVertex rotate_res = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex translate_res = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex4 perspective_res = { 0.f, 0.f, 0.f, 0.f }; ClutterMatrix res; clutter_matrix_init_identity (&res); _clutter_util_matrix_decompose (matrix1, &scale1, shear1, &rotate1, &translate1, &perspective1); _clutter_util_matrix_decompose (matrix2, &scale2, shear2, &rotate2, &translate2, &perspective2); /* perspective */ _clutter_util_vertex4_interpolate (&perspective1, &perspective2, progress, &perspective_res); res.wx = perspective_res.x; res.wy = perspective_res.y; res.wz = perspective_res.z; res.ww = perspective_res.w; /* translation */ clutter_vertex_interpolate (&translate1, &translate2, progress, &translate_res); cogl_matrix_translate (&res, translate_res.x, translate_res.y, translate_res.z); /* rotation */ clutter_vertex_interpolate (&rotate1, &rotate2, progress, &rotate_res); cogl_matrix_rotate (&res, rotate_res.x, 1.0f, 0.0f, 0.0f); cogl_matrix_rotate (&res, rotate_res.y, 0.0f, 1.0f, 0.0f); cogl_matrix_rotate (&res, rotate_res.z, 0.0f, 0.0f, 1.0f); /* skew */ shear_res = shear1[2] + (shear2[2] - shear1[2]) * progress; /* YZ */ if (shear_res != 0.f) _clutter_util_matrix_skew_yz (&res, shear_res); shear_res = shear1[1] + (shear2[1] - shear1[1]) * progress; /* XZ */ if (shear_res != 0.f) _clutter_util_matrix_skew_xz (&res, shear_res); shear_res = shear1[0] + (shear2[0] - shear1[0]) * progress; /* XY */ if (shear_res != 0.f) _clutter_util_matrix_skew_xy (&res, shear_res); /* scale */ clutter_vertex_interpolate (&scale1, &scale2, progress, &scale_res); cogl_matrix_scale (&res, scale_res.x, scale_res.y, scale_res.z); g_value_set_boxed (retval, &res); return TRUE; } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterMatrix, clutter_matrix, clutter_matrix_copy, clutter_matrix_free, CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_matrix_progress)) /** * clutter_matrix_alloc: * * Allocates enough memory to hold a #ClutterMatrix. * * Return value: (transfer full): the newly allocated #ClutterMatrix * * Since: 1.12 */ ClutterMatrix * clutter_matrix_alloc (void) { return g_new0 (ClutterMatrix, 1); } /** * clutter_matrix_free: * @matrix: (allow-none): a #ClutterMatrix * * Frees the memory allocated by clutter_matrix_alloc(). * * Since: 1.12 */ void clutter_matrix_free (ClutterMatrix *matrix) { cogl_matrix_free (matrix); } /** * clutter_matrix_init_identity: * @matrix: a #ClutterMatrix * * Initializes @matrix with the identity matrix, i.e.: * * |[ * .xx = 1.0, .xy = 0.0, .xz = 0.0, .xw = 0.0 * .yx = 0.0, .yy = 1.0, .yz = 0.0, .yw = 0.0 * .zx = 0.0, .zy = 0.0, .zz = 1.0, .zw = 0.0 * .wx = 0.0, .wy = 0.0, .wz = 0.0, .ww = 1.0 * ]| * * Return value: (transfer none): the initialized #ClutterMatrix * * Since: 1.12 */ ClutterMatrix * clutter_matrix_init_identity (ClutterMatrix *matrix) { cogl_matrix_init_identity (matrix); return matrix; } /** * clutter_matrix_init_from_array: * @matrix: a #ClutterMatrix * @values: (array fixed-size=16): a C array of 16 floating point values, * representing a 4x4 matrix, with column-major order * * Initializes @matrix with the contents of a C array of floating point * values. * * Return value: (transfer none): the initialzed #ClutterMatrix * * Since: 1.12 */ ClutterMatrix * clutter_matrix_init_from_array (ClutterMatrix *matrix, const float values[16]) { cogl_matrix_init_from_array (matrix, values); return matrix; } /** * clutter_matrix_init_from_matrix: * @a: the #ClutterMatrix to initialize * @b: the #ClutterMatrix to copy * * Initializes the #ClutterMatrix @a with the contents of the * #ClutterMatrix @b. * * Return value: (transfer none): the initialized #ClutterMatrix * * Since: 1.12 */ ClutterMatrix * clutter_matrix_init_from_matrix (ClutterMatrix *a, const ClutterMatrix *b) { return memcpy (a, b, sizeof (ClutterMatrix)); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-clone.h��������������������������������������������������������0000664�0001750�0001750�00000005667�14211404421�021247� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * Authored By: Robert Bragg <robert@linux.intel.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_CLONE_H__ #define __CLUTTER_CLONE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-actor.h> G_BEGIN_DECLS #define CLUTTER_TYPE_CLONE (clutter_clone_get_type()) #define CLUTTER_CLONE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CLONE, ClutterClone)) #define CLUTTER_CLONE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CLONE, ClutterCloneClass)) #define CLUTTER_IS_CLONE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CLONE)) #define CLUTTER_IS_CLONE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CLONE)) #define CLUTTER_CLONE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CLONE, ClutterCloneClass)) typedef struct _ClutterClone ClutterClone; typedef struct _ClutterCloneClass ClutterCloneClass; typedef struct _ClutterClonePrivate ClutterClonePrivate; /** * ClutterClone: * * The #ClutterClone structure contains only private data * and should be accessed using the provided API * * Since: 1.0 */ struct _ClutterClone { /*< private >*/ ClutterActor parent_instance; ClutterClonePrivate *priv; }; /** * ClutterCloneClass: * * The #ClutterCloneClass structure contains only private data * * Since: 1.0 */ struct _ClutterCloneClass { /*< private >*/ ClutterActorClass parent_class; /* padding for future expansion */ void (*_clutter_actor_clone1) (void); void (*_clutter_actor_clone2) (void); void (*_clutter_actor_clone3) (void); void (*_clutter_actor_clone4) (void); }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_clone_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterActor * clutter_clone_new (ClutterActor *source); CLUTTER_AVAILABLE_IN_1_0 void clutter_clone_set_source (ClutterClone *self, ClutterActor *source); CLUTTER_AVAILABLE_IN_1_0 ClutterActor * clutter_clone_get_source (ClutterClone *self); G_END_DECLS #endif /* __CLUTTER_CLONE_H__ */ �������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-scroll-actor.c�������������������������������������������������0000664�0001750�0001750�00000031235�14211404421�022534� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-scroll-actor * @Title: ClutterScrollActor * @Short_Description: An actor for displaying a portion of its children * * #ClutterScrollActor is an actor that can be used to display a portion * of the contents of its children. * * The extent of the area of a #ClutterScrollActor is defined by the size * of its children; the visible region of the children of a #ClutterScrollActor * is set by using clutter_scroll_actor_scroll_to_point() or by using * clutter_scroll_actor_scroll_to_rect() to define a point or a rectangle * acting as the origin, respectively. * * #ClutterScrollActor does not provide pointer or keyboard event handling, * nor does it provide visible scroll handles. * * See [scroll-actor.c](https://git.gnome.org/browse/clutter/tree/examples/scroll-actor.c?h=clutter-1.18) * for an example of how to use #ClutterScrollActor. * * #ClutterScrollActor is available since Clutter 1.12. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-scroll-actor.h" #include "clutter-actor-private.h" #include "clutter-animatable.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-private.h" #include "clutter-property-transition.h" #include "clutter-transition.h" struct _ClutterScrollActorPrivate { ClutterPoint scroll_to; ClutterScrollMode scroll_mode; ClutterTransition *transition; }; enum { PROP_0, PROP_SCROLL_MODE, PROP_LAST }; enum { ANIM_PROP_0, ANIM_PROP_SCROLL_TO, ANIM_PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static GParamSpec *animatable_props[ANIM_PROP_LAST] = { NULL, }; static ClutterAnimatableIface *parent_animatable_iface = NULL; static void clutter_animatable_iface_init (ClutterAnimatableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterScrollActor, clutter_scroll_actor, CLUTTER_TYPE_ACTOR, G_ADD_PRIVATE (ClutterScrollActor) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE, clutter_animatable_iface_init)) static void clutter_scroll_actor_set_scroll_to_internal (ClutterScrollActor *self, const ClutterPoint *point) { ClutterScrollActorPrivate *priv = self->priv; ClutterActor *actor = CLUTTER_ACTOR (self); ClutterMatrix m = CLUTTER_MATRIX_INIT_IDENTITY; float dx, dy; if (clutter_point_equals (&priv->scroll_to, point)) return; if (point == NULL) clutter_point_init (&priv->scroll_to, 0.f, 0.f); else priv->scroll_to = *point; if (priv->scroll_mode & CLUTTER_SCROLL_HORIZONTALLY) dx = -priv->scroll_to.x; else dx = 0.f; if (priv->scroll_mode & CLUTTER_SCROLL_VERTICALLY) dy = -priv->scroll_to.y; else dy = 0.f; cogl_matrix_translate (&m, dx, dy, 0.f); clutter_actor_set_child_transform (actor, &m); } static void clutter_scroll_actor_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject); switch (prop_id) { case PROP_SCROLL_MODE: clutter_scroll_actor_set_scroll_mode (actor, g_value_get_flags (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_scroll_actor_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterScrollActor *actor = CLUTTER_SCROLL_ACTOR (gobject); switch (prop_id) { case PROP_SCROLL_MODE: g_value_set_flags (value, actor->priv->scroll_mode); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_scroll_actor_class_init (ClutterScrollActorClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_scroll_actor_set_property; gobject_class->get_property = clutter_scroll_actor_get_property; /** * ClutterScrollActor:scroll-mode: * * The scrollin direction. * * Since: 1.12 */ obj_props[PROP_SCROLL_MODE] = g_param_spec_flags ("scroll-mode", P_("Scroll Mode"), P_("The scrolling direction"), CLUTTER_TYPE_SCROLL_MODE, CLUTTER_SCROLL_BOTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_scroll_actor_init (ClutterScrollActor *self) { self->priv = clutter_scroll_actor_get_instance_private (self); self->priv->scroll_mode = CLUTTER_SCROLL_BOTH; clutter_actor_set_clip_to_allocation (CLUTTER_ACTOR (self), TRUE); } static GParamSpec * clutter_scroll_actor_find_property (ClutterAnimatable *animatable, const char *property_name) { if (strcmp (property_name, "scroll-to") == 0) return animatable_props[ANIM_PROP_SCROLL_TO]; return parent_animatable_iface->find_property (animatable, property_name); } static void clutter_scroll_actor_set_final_state (ClutterAnimatable *animatable, const char *property_name, const GValue *value) { if (strcmp (property_name, "scroll-to") == 0) { ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable); const ClutterPoint *point = g_value_get_boxed (value); clutter_scroll_actor_set_scroll_to_internal (self, point); } else parent_animatable_iface->set_final_state (animatable, property_name, value); } static void clutter_scroll_actor_get_initial_state (ClutterAnimatable *animatable, const char *property_name, GValue *value) { if (strcmp (property_name, "scroll-to") == 0) { ClutterScrollActor *self = CLUTTER_SCROLL_ACTOR (animatable); g_value_set_boxed (value, &self->priv->scroll_to); } else parent_animatable_iface->get_initial_state (animatable, property_name, value); } static void clutter_animatable_iface_init (ClutterAnimatableIface *iface) { parent_animatable_iface = g_type_interface_peek_parent (iface); animatable_props[ANIM_PROP_SCROLL_TO] = g_param_spec_boxed ("scroll-to", "Scroll To", "The point to scroll the actor to", CLUTTER_TYPE_POINT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); iface->find_property = clutter_scroll_actor_find_property; iface->get_initial_state = clutter_scroll_actor_get_initial_state; iface->set_final_state = clutter_scroll_actor_set_final_state; } /** * clutter_scroll_actor_new: * * Creates a new #ClutterScrollActor. * * Return value: The newly created #ClutterScrollActor * instance. * * Since: 1.12 */ ClutterActor * clutter_scroll_actor_new (void) { return g_object_new (CLUTTER_TYPE_SCROLL_ACTOR, NULL); } /** * clutter_scroll_actor_set_scroll_mode: * @actor: a #ClutterScrollActor * @mode: a #ClutterScrollMode * * Sets the #ClutterScrollActor:scroll-mode property. * * Since: 1.12 */ void clutter_scroll_actor_set_scroll_mode (ClutterScrollActor *actor, ClutterScrollMode mode) { ClutterScrollActorPrivate *priv; g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor)); priv = actor->priv; if (priv->scroll_mode == mode) return; priv->scroll_mode = mode; g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_SCROLL_MODE]); } /** * clutter_scroll_actor_get_scroll_mode: * @actor: a #ClutterScrollActor * * Retrieves the #ClutterScrollActor:scroll-mode property * * Return value: the scrolling mode * * Since: 1.12 */ ClutterScrollMode clutter_scroll_actor_get_scroll_mode (ClutterScrollActor *actor) { g_return_val_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor), CLUTTER_SCROLL_NONE); return actor->priv->scroll_mode; } /** * clutter_scroll_actor_scroll_to_point: * @actor: a #ClutterScrollActor * @point: a #ClutterPoint * * Scrolls the contents of @actor so that @point is the new origin * of the visible area. * * The coordinates of @point must be relative to the @actor. * * This function will use the currently set easing state of the @actor * to transition from the current scroll origin to the new one. * * Since: 1.12 */ void clutter_scroll_actor_scroll_to_point (ClutterScrollActor *actor, const ClutterPoint *point) { ClutterScrollActorPrivate *priv; const ClutterAnimationInfo *info; g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor)); g_return_if_fail (point != NULL); priv = actor->priv; info = _clutter_actor_get_animation_info (CLUTTER_ACTOR (actor)); /* jump to the end if there is no easing state, or if the easing * state has a duration of 0 msecs */ if (info->cur_state == NULL || info->cur_state->easing_duration == 0) { /* ensure that we remove any currently running transition */ if (priv->transition != NULL) { clutter_actor_remove_transition (CLUTTER_ACTOR (actor), "scroll-to"); priv->transition = NULL; } clutter_scroll_actor_set_scroll_to_internal (actor, point); return; } if (priv->transition == NULL) { priv->transition = clutter_property_transition_new ("scroll-to"); clutter_transition_set_animatable (priv->transition, CLUTTER_ANIMATABLE (actor)); clutter_transition_set_remove_on_complete (priv->transition, TRUE); /* delay only makes sense if the transition has just been created */ clutter_timeline_set_delay (CLUTTER_TIMELINE (priv->transition), info->cur_state->easing_delay); /* we need this to clear the priv->transition pointer */ g_object_add_weak_pointer (G_OBJECT (priv->transition), (gpointer *) &priv->transition); clutter_actor_add_transition (CLUTTER_ACTOR (actor), "scroll-to", priv->transition); /* the actor now owns the transition */ g_object_unref (priv->transition); } /* if a transition already exist, update its bounds */ clutter_transition_set_from (priv->transition, CLUTTER_TYPE_POINT, &priv->scroll_to); clutter_transition_set_to (priv->transition, CLUTTER_TYPE_POINT, point); /* always use the current easing state */ clutter_timeline_set_duration (CLUTTER_TIMELINE (priv->transition), info->cur_state->easing_duration); clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (priv->transition), info->cur_state->easing_mode); /* ensure that we start from the beginning */ clutter_timeline_rewind (CLUTTER_TIMELINE (priv->transition)); clutter_timeline_start (CLUTTER_TIMELINE (priv->transition)); } /** * clutter_scroll_actor_scroll_to_rect: * @actor: a #ClutterScrollActor * @rect: a #ClutterRect * * Scrolls @actor so that @rect is in the visible portion. * * Since: 1.12 */ void clutter_scroll_actor_scroll_to_rect (ClutterScrollActor *actor, const ClutterRect *rect) { ClutterRect n_rect; g_return_if_fail (CLUTTER_IS_SCROLL_ACTOR (actor)); g_return_if_fail (rect != NULL); n_rect = *rect; /* normalize, so that we have a valid origin */ clutter_rect_normalize (&n_rect); clutter_scroll_actor_scroll_to_point (actor, &n_rect.origin); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-stage-private.h������������������������������������������������0000664�0001750�0001750�00000017576�14211404421�022724� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_STAGE_PRIVATE_H__ #define __CLUTTER_STAGE_PRIVATE_H__ #include <clutter/clutter-stage-window.h> #include <clutter/clutter-stage.h> #include <clutter/clutter-input-device.h> #include <clutter/clutter-private.h> #include <cogl/cogl.h> G_BEGIN_DECLS typedef struct _ClutterStageQueueRedrawEntry ClutterStageQueueRedrawEntry; /* stage */ ClutterStageWindow *_clutter_stage_get_default_window (void); void _clutter_stage_paint_view (ClutterStage *stage, ClutterStageView *view, const cairo_rectangle_int_t *clip); void _clutter_stage_set_window (ClutterStage *stage, ClutterStageWindow *stage_window); ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage); void _clutter_stage_get_projection_matrix (ClutterStage *stage, CoglMatrix *projection); void _clutter_stage_dirty_projection (ClutterStage *stage); void _clutter_stage_set_viewport (ClutterStage *stage, float x, float y, float width, float height); void _clutter_stage_get_viewport (ClutterStage *stage, float *x, float *y, float *width, float *height); void _clutter_stage_dirty_viewport (ClutterStage *stage); void _clutter_stage_maybe_setup_viewport (ClutterStage *stage, ClutterStageView *view); void _clutter_stage_maybe_relayout (ClutterActor *stage); gboolean _clutter_stage_needs_update (ClutterStage *stage); gboolean _clutter_stage_do_update (ClutterStage *stage); void _clutter_stage_queue_event (ClutterStage *stage, ClutterEvent *event, gboolean copy_event); gboolean _clutter_stage_has_queued_events (ClutterStage *stage); void _clutter_stage_process_queued_events (ClutterStage *stage); void _clutter_stage_update_input_devices (ClutterStage *stage); void _clutter_stage_schedule_update (ClutterStage *stage); gint64 _clutter_stage_get_update_time (ClutterStage *stage); void _clutter_stage_clear_update_time (ClutterStage *stage); gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage); ClutterActor *_clutter_stage_do_pick (ClutterStage *stage, gint x, gint y, ClutterPickMode mode); ClutterPaintVolume *_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage); void _clutter_stage_paint_volume_stack_free_all (ClutterStage *stage); const ClutterPlane *_clutter_stage_get_clip (ClutterStage *stage); ClutterStageQueueRedrawEntry *_clutter_stage_queue_actor_redraw (ClutterStage *stage, ClutterStageQueueRedrawEntry *entry, ClutterActor *actor, ClutterPaintVolume *clip); void _clutter_stage_queue_redraw_entry_invalidate (ClutterStageQueueRedrawEntry *entry); CoglFramebuffer *_clutter_stage_get_active_framebuffer (ClutterStage *stage); gint32 _clutter_stage_acquire_pick_id (ClutterStage *stage, ClutterActor *actor); void _clutter_stage_release_pick_id (ClutterStage *stage, gint32 pick_id); ClutterActor * _clutter_stage_get_actor_by_pick_id (ClutterStage *stage, gint32 pick_id); void _clutter_stage_add_pointer_drag_actor (ClutterStage *stage, ClutterInputDevice *device, ClutterActor *actor); ClutterActor * _clutter_stage_get_pointer_drag_actor (ClutterStage *stage, ClutterInputDevice *device); void _clutter_stage_remove_pointer_drag_actor (ClutterStage *stage, ClutterInputDevice *device); void _clutter_stage_add_touch_drag_actor (ClutterStage *stage, ClutterEventSequence *sequence, ClutterActor *actor); ClutterActor * _clutter_stage_get_touch_drag_actor (ClutterStage *stage, ClutterEventSequence *sequence); void _clutter_stage_remove_touch_drag_actor (ClutterStage *stage, ClutterEventSequence *sequence); ClutterStageState _clutter_stage_get_state (ClutterStage *stage); gboolean _clutter_stage_is_activated (ClutterStage *stage); gboolean _clutter_stage_is_fullscreen (ClutterStage *stage); gboolean _clutter_stage_update_state (ClutterStage *stage, ClutterStageState unset_state, ClutterStageState set_state); void _clutter_stage_set_scale_factor (ClutterStage *stage, int factor); void _clutter_stage_presented (ClutterStage *stage, CoglFrameEvent frame_event, ClutterFrameInfo *frame_info); G_END_DECLS #endif /* __CLUTTER_STAGE_PRIVATE_H__ */ ����������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-scroll-actor.h�������������������������������������������������0000664�0001750�0001750�00000006577�14211404421�022554� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_SCROLL_ACTOR_H__ #define __CLUTTER_SCROLL_ACTOR_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-actor.h> G_BEGIN_DECLS #define CLUTTER_TYPE_SCROLL_ACTOR (clutter_scroll_actor_get_type ()) #define CLUTTER_SCROLL_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SCROLL_ACTOR, ClutterScrollActor)) #define CLUTTER_IS_SCROLL_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SCROLL_ACTOR)) #define CLUTTER_SCROLL_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SCROLL_ACTOR, ClutterScrollActorClass)) #define CLUTTER_IS_SCROLL_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SCROLL_ACTOR)) #define CLUTTER_SCROLL_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SCROLL_ACTOR, ClutterScrollActorClass)) typedef struct _ClutterScrollActorPrivate ClutterScrollActorPrivate; typedef struct _ClutterScrollActorClass ClutterScrollActorClass; /** * ClutterScrollActor: * * The #ClutterScrollActor structure contains only * private data, and should be accessed using the provided API. * * Since: 1.12 */ struct _ClutterScrollActor { /*< private >*/ ClutterActor parent_instance; ClutterScrollActorPrivate *priv; }; /** * ClutterScrollActorClass: * * The #ClutterScrollActor structure contains only * private data. * * Since: 1.12 */ struct _ClutterScrollActorClass { /*< private >*/ ClutterActorClass parent_instance; gpointer _padding[8]; }; CLUTTER_AVAILABLE_IN_1_12 GType clutter_scroll_actor_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterActor * clutter_scroll_actor_new (void); CLUTTER_AVAILABLE_IN_1_12 void clutter_scroll_actor_set_scroll_mode (ClutterScrollActor *actor, ClutterScrollMode mode); CLUTTER_AVAILABLE_IN_1_12 ClutterScrollMode clutter_scroll_actor_get_scroll_mode (ClutterScrollActor *actor); CLUTTER_AVAILABLE_IN_1_12 void clutter_scroll_actor_scroll_to_point (ClutterScrollActor *actor, const ClutterPoint *point); CLUTTER_AVAILABLE_IN_1_12 void clutter_scroll_actor_scroll_to_rect (ClutterScrollActor *actor, const ClutterRect *rect); G_END_DECLS #endif /* __CLUTTER_SCROLL_ACTOR_H__ */ ���������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-id-pool.h������������������������������������������������������0000664�0001750�0001750�00000003207�14211404421�021476� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2008 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, see <http://www.gnu.org/licenses/>. * * ClutterIDPool: pool of reusable integer ids associated with pointers. * * Author: Øyvind Kolås <pippin@o-hand.com> */ #ifndef __CLUTTER_ID_POOL_H__ #define __CLUTTER_ID_POOL_H__ #include <glib.h> G_BEGIN_DECLS typedef struct _ClutterIDPool ClutterIDPool; ClutterIDPool * _clutter_id_pool_new (guint initial_size); void _clutter_id_pool_free (ClutterIDPool *id_pool); guint32 _clutter_id_pool_add (ClutterIDPool *id_pool, gpointer ptr); void _clutter_id_pool_remove (ClutterIDPool *id_pool, guint32 id_); gpointer _clutter_id_pool_lookup (ClutterIDPool *id_pool, guint32 id_); G_END_DECLS #endif /* __CLUTTER_ID_POOL_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-snap-constraint.c����������������������������������������������0000664�0001750�0001750�00000043373�14211404421�023261� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-snap-constraint * @Title: ClutterSnapConstraint * @Short_Description: A constraint snapping two actors together * * #ClutterSnapConstraint is a constraint the snaps the edges of two * actors together, expanding the actor's allocation if necessary. * * An offset can be applied to the constraint, to provide spacing. * * #ClutterSnapConstraint is available since Clutter 1.6 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter-snap-constraint.h" #include "clutter-actor-private.h" #include "clutter-constraint.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-private.h" #define CLUTTER_SNAP_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SNAP_CONSTRAINT, ClutterSnapConstraintClass)) #define CLUTTER_IS_SNAP_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SNAP_CONSTRAINT)) #define CLUTTER_SNAP_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SNAP_CONSTRAINT, ClutterSnapConstraintClass)) struct _ClutterSnapConstraint { ClutterConstraint parent_instance; ClutterActor *actor; ClutterActor *source; ClutterSnapEdge from_edge; ClutterSnapEdge to_edge; gfloat offset; }; struct _ClutterSnapConstraintClass { ClutterConstraintClass parent_class; }; enum { PROP_0, PROP_SOURCE, PROP_FROM_EDGE, PROP_TO_EDGE, PROP_OFFSET, PROP_LAST }; G_DEFINE_TYPE (ClutterSnapConstraint, clutter_snap_constraint, CLUTTER_TYPE_CONSTRAINT); static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static void source_queue_relayout (ClutterActor *source, ClutterSnapConstraint *constraint) { if (constraint->actor != NULL) _clutter_actor_queue_only_relayout (constraint->actor); } static void source_destroyed (ClutterActor *actor, ClutterSnapConstraint *constraint) { constraint->source = NULL; } static inline void warn_horizontal_edge (const gchar *edge, ClutterActor *actor, ClutterActor *source) { g_warning (G_STRLOC ": the %s edge of actor '%s' can only be snapped " "to either the right or the left edge of actor '%s'", edge, _clutter_actor_get_debug_name (actor), _clutter_actor_get_debug_name (source)); } static inline void warn_vertical_edge (const gchar *edge, ClutterActor *actor, ClutterActor *source) { g_warning (G_STRLOC ": the %s edge of actor '%s' can only " "be snapped to the top or bottom edge of actor '%s'", edge, _clutter_actor_get_debug_name (actor), _clutter_actor_get_debug_name (source)); } static void clutter_snap_constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation) { ClutterSnapConstraint *self = CLUTTER_SNAP_CONSTRAINT (constraint); gfloat source_width, source_height; gfloat source_x, source_y; gfloat actor_width, actor_height; if (self->source == NULL) return; clutter_actor_get_position (self->source, &source_x, &source_y); clutter_actor_get_size (self->source, &source_width, &source_height); clutter_actor_box_get_size (allocation, &actor_width, &actor_height); switch (self->to_edge) { case CLUTTER_SNAP_EDGE_LEFT: if (self->from_edge == CLUTTER_SNAP_EDGE_LEFT) allocation->x1 = source_x + self->offset; else if (self->from_edge == CLUTTER_SNAP_EDGE_RIGHT) allocation->x2 = source_x + self->offset; else warn_horizontal_edge ("left", self->actor, self->source); break; case CLUTTER_SNAP_EDGE_RIGHT: if (self->from_edge == CLUTTER_SNAP_EDGE_RIGHT) allocation->x2 = source_x + source_width + self->offset; else if (self->from_edge == CLUTTER_SNAP_EDGE_LEFT) allocation->x1 = source_x + source_width + self->offset; else warn_horizontal_edge ("right", self->actor, self->source); break; break; case CLUTTER_SNAP_EDGE_TOP: if (self->from_edge == CLUTTER_SNAP_EDGE_TOP) allocation->y1 = source_y + self->offset; else if (self->from_edge == CLUTTER_SNAP_EDGE_BOTTOM) allocation->y2 = source_y + self->offset; else warn_vertical_edge ("top", self->actor, self->source); break; case CLUTTER_SNAP_EDGE_BOTTOM: if (self->from_edge == CLUTTER_SNAP_EDGE_BOTTOM) allocation->y2 = source_y + source_height + self->offset; else if (self->from_edge == CLUTTER_SNAP_EDGE_TOP) allocation->y1 = source_y + source_height + self->offset; else warn_vertical_edge ("bottom", self->actor, self->source); break; default: g_assert_not_reached (); break; } if (allocation->x2 - allocation->x1 < 0) allocation->x2 = allocation->x1; if (allocation->y2 - allocation->y1 < 0) allocation->y2 = allocation->y1; } static void clutter_snap_constraint_set_actor (ClutterActorMeta *meta, ClutterActor *new_actor) { ClutterSnapConstraint *self = CLUTTER_SNAP_CONSTRAINT (meta); ClutterActorMetaClass *parent; /* store the pointer to the actor, for later use */ self->actor = new_actor; parent = CLUTTER_ACTOR_META_CLASS (clutter_snap_constraint_parent_class); parent->set_actor (meta, new_actor); } static void clutter_snap_constraint_dispose (GObject *gobject) { ClutterSnapConstraint *snap = CLUTTER_SNAP_CONSTRAINT (gobject); if (snap->source != NULL) { g_signal_handlers_disconnect_by_func (snap->source, G_CALLBACK (source_destroyed), snap); g_signal_handlers_disconnect_by_func (snap->source, G_CALLBACK (source_queue_relayout), snap); snap->source = NULL; } G_OBJECT_CLASS (clutter_snap_constraint_parent_class)->dispose (gobject); } static void clutter_snap_constraint_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterSnapConstraint *self = CLUTTER_SNAP_CONSTRAINT (gobject); switch (prop_id) { case PROP_SOURCE: clutter_snap_constraint_set_source (self, g_value_get_object (value)); break; case PROP_FROM_EDGE: clutter_snap_constraint_set_edges (self, g_value_get_enum (value), self->to_edge); break; case PROP_TO_EDGE: clutter_snap_constraint_set_edges (self, self->from_edge, g_value_get_enum (value)); break; case PROP_OFFSET: clutter_snap_constraint_set_offset (self, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_snap_constraint_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterSnapConstraint *self = CLUTTER_SNAP_CONSTRAINT (gobject); switch (prop_id) { case PROP_SOURCE: g_value_set_object (value, self->source); break; case PROP_FROM_EDGE: g_value_set_enum (value, self->from_edge); break; case PROP_TO_EDGE: g_value_set_enum (value, self->to_edge); break; case PROP_OFFSET: g_value_set_float (value, self->offset); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_snap_constraint_class_init (ClutterSnapConstraintClass *klass) { ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); ClutterConstraintClass *constraint_class = CLUTTER_CONSTRAINT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); meta_class->set_actor = clutter_snap_constraint_set_actor; constraint_class->update_allocation = clutter_snap_constraint_update_allocation; /** * ClutterSnapConstraint:source: * * The #ClutterActor used as the source for the constraint * * Since: 1.6 */ obj_props[PROP_SOURCE] = g_param_spec_object ("source", P_("Source"), P_("The source of the constraint"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterSnapConstraint:from-edge: * * The edge of the #ClutterActor that should be snapped * * Since: 1.6 */ obj_props[PROP_FROM_EDGE] = g_param_spec_enum ("from-edge", P_("From Edge"), P_("The edge of the actor that should be snapped"), CLUTTER_TYPE_SNAP_EDGE, CLUTTER_SNAP_EDGE_RIGHT, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterSnapConstraint:to-edge: * * The edge of the #ClutterSnapConstraint:source that should be snapped * * Since: 1.6 */ obj_props[PROP_TO_EDGE] = g_param_spec_enum ("to-edge", P_("To Edge"), P_("The edge of the source that should be snapped"), CLUTTER_TYPE_SNAP_EDGE, CLUTTER_SNAP_EDGE_RIGHT, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterSnapConstraint:offset: * * The offset, in pixels, between #ClutterSnapConstraint:from-edge * and #ClutterSnapConstraint:to-edge * * Since: 1.6 */ obj_props[PROP_OFFSET] = g_param_spec_float ("offset", P_("Offset"), P_("The offset in pixels to apply to the constraint"), -G_MAXFLOAT, G_MAXFLOAT, 0.0f, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); gobject_class->dispose = clutter_snap_constraint_dispose; gobject_class->set_property = clutter_snap_constraint_set_property; gobject_class->get_property = clutter_snap_constraint_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_snap_constraint_init (ClutterSnapConstraint *self) { self->actor = NULL; self->source = NULL; self->from_edge = CLUTTER_SNAP_EDGE_RIGHT; self->to_edge = CLUTTER_SNAP_EDGE_RIGHT; self->offset = 0.0f; } /** * clutter_snap_constraint_new: * @source: (allow-none): the #ClutterActor to use as the source of * the constraint, or %NULL * @from_edge: the edge of the actor to use in the constraint * @to_edge: the edge of @source to use in the constraint * @offset: the offset to apply to the constraint, in pixels * * Creates a new #ClutterSnapConstraint that will snap a #ClutterActor * to the @edge of @source, with the given @offset. * * Return value: the newly created #ClutterSnapConstraint * * Since: 1.6 */ ClutterConstraint * clutter_snap_constraint_new (ClutterActor *source, ClutterSnapEdge from_edge, ClutterSnapEdge to_edge, gfloat offset) { g_return_val_if_fail (source == NULL || CLUTTER_IS_ACTOR (source), NULL); return g_object_new (CLUTTER_TYPE_SNAP_CONSTRAINT, "source", source, "from-edge", from_edge, "to-edge", to_edge, "offset", offset, NULL); } /** * clutter_snap_constraint_set_source: * @constraint: a #ClutterSnapConstraint * @source: (allow-none): a #ClutterActor, or %NULL to unset the source * * Sets the source #ClutterActor for the constraint * * Since: 1.6 */ void clutter_snap_constraint_set_source (ClutterSnapConstraint *constraint, ClutterActor *source) { ClutterActor *old_source; g_return_if_fail (CLUTTER_IS_SNAP_CONSTRAINT (constraint)); g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source)); if (constraint->source == source) return; old_source = constraint->source; if (old_source != NULL) { g_signal_handlers_disconnect_by_func (old_source, G_CALLBACK (source_destroyed), constraint); g_signal_handlers_disconnect_by_func (old_source, G_CALLBACK (source_queue_relayout), constraint); } constraint->source = source; if (constraint->source != NULL) { g_signal_connect (constraint->source, "queue-relayout", G_CALLBACK (source_queue_relayout), constraint); g_signal_connect (constraint->source, "destroy", G_CALLBACK (source_destroyed), constraint); if (constraint->actor != NULL) clutter_actor_queue_relayout (constraint->actor); } g_object_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_SOURCE]); } /** * clutter_snap_constraint_get_source: * @constraint: a #ClutterSnapConstraint * * Retrieves the #ClutterActor set using clutter_snap_constraint_set_source() * * Return value: (transfer none): a pointer to the source actor * * Since: 1.6 */ ClutterActor * clutter_snap_constraint_get_source (ClutterSnapConstraint *constraint) { g_return_val_if_fail (CLUTTER_IS_SNAP_CONSTRAINT (constraint), NULL); return constraint->source; } /** * clutter_snap_constraint_set_edges: * @constraint: a #ClutterSnapConstraint * @from_edge: the edge on the actor * @to_edge: the edge on the source * * Sets the edges to be used by the @constraint * * The @from_edge is the edge on the #ClutterActor to which @constraint * has been added. The @to_edge is the edge of the #ClutterActor inside * the #ClutterSnapConstraint:source property. * * Since: 1.6 */ void clutter_snap_constraint_set_edges (ClutterSnapConstraint *constraint, ClutterSnapEdge from_edge, ClutterSnapEdge to_edge) { gboolean from_changed = FALSE, to_changed = FALSE; g_return_if_fail (CLUTTER_IS_SNAP_CONSTRAINT (constraint)); g_object_freeze_notify (G_OBJECT (constraint)); if (constraint->from_edge != from_edge) { constraint->from_edge = from_edge; g_object_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_FROM_EDGE]); from_changed = TRUE; } if (constraint->to_edge != to_edge) { constraint->to_edge = to_edge; g_object_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_TO_EDGE]); to_changed = TRUE; } if ((from_changed || to_changed) && constraint->actor != NULL) { clutter_actor_queue_relayout (constraint->actor); } g_object_thaw_notify (G_OBJECT (constraint)); } /** * clutter_snap_constraint_get_edges: * @constraint: a #ClutterSnapConstraint * @from_edge: (out): return location for the actor's edge, or %NULL * @to_edge: (out): return location for the source's edge, or %NULL * * Retrieves the edges used by the @constraint * * Since: 1.6 */ void clutter_snap_constraint_get_edges (ClutterSnapConstraint *constraint, ClutterSnapEdge *from_edge, ClutterSnapEdge *to_edge) { g_return_if_fail (CLUTTER_IS_SNAP_CONSTRAINT (constraint)); if (from_edge) *from_edge = constraint->from_edge; if (to_edge) *to_edge = constraint->to_edge; } /** * clutter_snap_constraint_set_offset: * @constraint: a #ClutterSnapConstraint * @offset: the offset to apply, in pixels * * Sets the offset to be applied to the constraint * * Since: 1.6 */ void clutter_snap_constraint_set_offset (ClutterSnapConstraint *constraint, gfloat offset) { g_return_if_fail (CLUTTER_IS_SNAP_CONSTRAINT (constraint)); if (fabs (constraint->offset - offset) < 0.00001f) return; constraint->offset = offset; if (constraint->actor != NULL) clutter_actor_queue_relayout (constraint->actor); g_object_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_OFFSET]); } /** * clutter_snap_constraint_get_offset: * @constraint: a #ClutterSnapConstraint * * Retrieves the offset set using clutter_snap_constraint_set_offset() * * Return value: the offset, in pixels * * Since: 1.6 */ gfloat clutter_snap_constraint_get_offset (ClutterSnapConstraint *constraint) { g_return_val_if_fail (CLUTTER_IS_SNAP_CONSTRAINT (constraint), 0.0); return constraint->offset; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-input-method-private.h�����������������������������������������0000664�0001750�0001750�00000004361�14211404421�024222� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2017,2018 Red Hat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifndef __CLUTTER_INPUT_METHOD_PRIVATE_H__ #define __CLUTTER_INPUT_METHOD_PRIVATE_H__ ClutterInputFocus * clutter_input_method_get_focus (ClutterInputMethod *method); void clutter_input_method_reset (ClutterInputMethod *method); void clutter_input_method_set_cursor_location (ClutterInputMethod *method, const ClutterRect *rect); void clutter_input_method_set_surrounding (ClutterInputMethod *method, const gchar *text, guint cursor, guint anchor); void clutter_input_method_set_content_hints (ClutterInputMethod *method, ClutterInputContentHintFlags hints); void clutter_input_method_set_content_purpose (ClutterInputMethod *method, ClutterInputContentPurpose purpose); void clutter_input_method_set_can_show_preedit (ClutterInputMethod *method, gboolean can_show_preedit); gboolean clutter_input_method_filter_key_event (ClutterInputMethod *method, const ClutterKeyEvent *key); void clutter_input_method_toggle_input_panel (ClutterInputMethod *method); #endif /* __CLUTTER_INPUT_METHOD_PRIVATE_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-desaturate-effect.c��������������������������������������������0000664�0001750�0001750�00000026060�14211404421�023523� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-desaturate-effect * @short_description: A desaturation effect * @see_also: #ClutterEffect, #ClutterOffscreenEffect * * #ClutterDesaturateEffect is a sub-class of #ClutterEffect that * desaturates the color of an actor and its contents. The strenght * of the desaturation effect is controllable and animatable through * the #ClutterDesaturateEffect:factor property. * * #ClutterDesaturateEffect is available since Clutter 1.4 */ #define CLUTTER_DESATURATE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffectClass)) #define CLUTTER_IS_DESATURATE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DESATURATE_EFFECT)) #define CLUTTER_DESATURATE_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffectClass)) #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include <math.h> #include "clutter-desaturate-effect.h" #include "cogl/cogl.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-offscreen-effect.h" #include "clutter-private.h" struct _ClutterDesaturateEffect { ClutterOffscreenEffect parent_instance; /* the desaturation factor, also known as "strength" */ gdouble factor; gint factor_uniform; gint tex_width; gint tex_height; CoglPipeline *pipeline; }; struct _ClutterDesaturateEffectClass { ClutterOffscreenEffectClass parent_class; CoglPipeline *base_pipeline; }; /* the magic gray vec3 has been taken from the NTSC conversion weights * as defined by: * * "OpenGL Superbible, 4th edition" * -- Richard S. Wright Jr, Benjamin Lipchak, Nicholas Haemel * Addison-Wesley */ static const gchar *desaturate_glsl_declarations = "uniform float factor;\n" "\n" "vec3 desaturate (const vec3 color, const float desaturation)\n" "{\n" " const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n" " vec3 gray = vec3 (dot (gray_conv, color));\n" " return vec3 (mix (color.rgb, gray, desaturation));\n" "}\n"; static const gchar *desaturate_glsl_source = " cogl_color_out.rgb = desaturate (cogl_color_out.rgb, factor);\n"; enum { PROP_0, PROP_FACTOR, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterDesaturateEffect, clutter_desaturate_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT); static gboolean clutter_desaturate_effect_pre_paint (ClutterEffect *effect) { ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect); ClutterEffectClass *parent_class; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) return FALSE; if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) { /* if we don't have support for GLSL shaders then we * forcibly disable the ActorMeta */ g_warning ("Unable to use the ShaderEffect: the graphics hardware " "or the current GL driver does not implement support " "for the GLSL shading language."); clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE); return FALSE; } parent_class = CLUTTER_EFFECT_CLASS (clutter_desaturate_effect_parent_class); if (parent_class->pre_paint (effect)) { ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect); CoglHandle texture; texture = clutter_offscreen_effect_get_texture (offscreen_effect); self->tex_width = cogl_texture_get_width (texture); self->tex_height = cogl_texture_get_height (texture); cogl_pipeline_set_layer_texture (self->pipeline, 0, texture); return TRUE; } else return FALSE; } static void clutter_desaturate_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect); ClutterActor *actor; CoglHandle texture; guint8 paint_opacity; texture = clutter_offscreen_effect_get_texture (effect); cogl_pipeline_set_layer_texture (self->pipeline, 0, texture); actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); paint_opacity = clutter_actor_get_paint_opacity (actor); cogl_pipeline_set_color4ub (self->pipeline, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_push_source (self->pipeline); cogl_rectangle (0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture)); cogl_pop_source (); } static void clutter_desaturate_effect_dispose (GObject *gobject) { ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (gobject); if (self->pipeline != NULL) { cogl_object_unref (self->pipeline); self->pipeline = NULL; } G_OBJECT_CLASS (clutter_desaturate_effect_parent_class)->dispose (gobject); } static void clutter_desaturate_effect_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterDesaturateEffect *effect = CLUTTER_DESATURATE_EFFECT (gobject); switch (prop_id) { case PROP_FACTOR: clutter_desaturate_effect_set_factor (effect, g_value_get_double (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_desaturate_effect_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterDesaturateEffect *effect = CLUTTER_DESATURATE_EFFECT (gobject); switch (prop_id) { case PROP_FACTOR: g_value_set_double (value, effect->factor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void update_factor_uniform (ClutterDesaturateEffect *self) { if (self->factor_uniform > -1) cogl_pipeline_set_uniform_1f (self->pipeline, self->factor_uniform, self->factor); } static void clutter_desaturate_effect_class_init (ClutterDesaturateEffectClass *klass) { ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterOffscreenEffectClass *offscreen_class; offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class->paint_target = clutter_desaturate_effect_paint_target; effect_class->pre_paint = clutter_desaturate_effect_pre_paint; /** * ClutterDesaturateEffect:factor: * * The desaturation factor, between 0.0 (no desaturation) and 1.0 (full * desaturation). * * Since: 1.4 */ obj_props[PROP_FACTOR] = g_param_spec_double ("factor", P_("Factor"), P_("The desaturation factor"), 0.0, 1.0, 1.0, CLUTTER_PARAM_READWRITE); gobject_class->dispose = clutter_desaturate_effect_dispose; gobject_class->set_property = clutter_desaturate_effect_set_property; gobject_class->get_property = clutter_desaturate_effect_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_desaturate_effect_init (ClutterDesaturateEffect *self) { ClutterDesaturateEffectClass *klass = CLUTTER_DESATURATE_EFFECT_GET_CLASS (self); if (G_UNLIKELY (klass->base_pipeline == NULL)) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); CoglSnippet *snippet; klass->base_pipeline = cogl_pipeline_new (ctx); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, desaturate_glsl_declarations, desaturate_glsl_source); cogl_pipeline_add_snippet (klass->base_pipeline, snippet); cogl_object_unref (snippet); cogl_pipeline_set_layer_null_texture (klass->base_pipeline, 0, /* layer number */ COGL_TEXTURE_TYPE_2D); } self->pipeline = cogl_pipeline_copy (klass->base_pipeline); self->factor_uniform = cogl_pipeline_get_uniform_location (self->pipeline, "factor"); self->factor = 1.0; update_factor_uniform (self); } /** * clutter_desaturate_effect_new: * @factor: the desaturation factor, between 0.0 and 1.0 * * Creates a new #ClutterDesaturateEffect to be used with * clutter_actor_add_effect() * * Return value: the newly created #ClutterDesaturateEffect or %NULL * * Since: 1.4 */ ClutterEffect * clutter_desaturate_effect_new (gdouble factor) { g_return_val_if_fail (factor >= 0.0 && factor <= 1.0, NULL); return g_object_new (CLUTTER_TYPE_DESATURATE_EFFECT, "factor", factor, NULL); } /** * clutter_desaturate_effect_set_factor: * @effect: a #ClutterDesaturateEffect * @factor: the desaturation factor, between 0.0 and 1.0 * * Sets the desaturation factor for @effect, with 0.0 being "do not desaturate" * and 1.0 being "fully desaturate" * * Since: 1.4 */ void clutter_desaturate_effect_set_factor (ClutterDesaturateEffect *effect, gdouble factor) { g_return_if_fail (CLUTTER_IS_DESATURATE_EFFECT (effect)); g_return_if_fail (factor >= 0.0 && factor <= 1.0); if (fabsf (effect->factor - factor) >= 0.00001) { effect->factor = factor; update_factor_uniform (effect); clutter_effect_queue_repaint (CLUTTER_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_FACTOR]); } } /** * clutter_desaturate_effect_get_factor: * @effect: a #ClutterDesaturateEffect * * Retrieves the desaturation factor of @effect * * Return value: the desaturation factor * * Since: 1.4 */ gdouble clutter_desaturate_effect_get_factor (ClutterDesaturateEffect *effect) { g_return_val_if_fail (CLUTTER_IS_DESATURATE_EFFECT (effect), 0.0); return effect->factor; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/�����������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�017411� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-device-manager-evdev.h�����������������������������������0000664�0001750�0001750�00000010737�14211404421�025230� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 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, see <http://www.gnu.org/licenses/>. * * Author: Damien Lespiau <damien.lespiau@intel.com> */ #ifndef __CLUTTER_DEVICE_MANAGER_EVDEV_H__ #define __CLUTTER_DEVICE_MANAGER_EVDEV_H__ #include <clutter/clutter-backend.h> #include <clutter/clutter-device-manager.h> G_BEGIN_DECLS #define CLUTTER_TYPE_DEVICE_MANAGER_EVDEV (clutter_device_manager_evdev_get_type ()) #define CLUTTER_DEVICE_MANAGER_EVDEV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, ClutterDeviceManagerEvdev)) #define CLUTTER_IS_DEVICE_MANAGER_EVDEV(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV)) #define CLUTTER_DEVICE_MANAGER_EVDEV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, ClutterDeviceManagerEvdevClass)) #define CLUTTER_IS_DEVICE_MANAGER_EVDEV_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV)) #define CLUTTER_DEVICE_MANAGER_EVDEV_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, ClutterDeviceManagerEvdevClass)) typedef struct _ClutterDeviceManagerEvdev ClutterDeviceManagerEvdev; typedef struct _ClutterDeviceManagerEvdevClass ClutterDeviceManagerEvdevClass; typedef struct _ClutterDeviceManagerEvdevPrivate ClutterDeviceManagerEvdevPrivate; typedef struct _ClutterSeatEvdev ClutterSeatEvdev; struct _ClutterDeviceManagerEvdev { ClutterDeviceManager parent_instance; ClutterDeviceManagerEvdevPrivate *priv; }; struct _ClutterDeviceManagerEvdevClass { ClutterDeviceManagerClass parent_class; }; GType clutter_device_manager_evdev_get_type (void) G_GNUC_CONST; void _clutter_events_evdev_init (ClutterBackend *backend); void _clutter_events_evdev_uninit (ClutterBackend *backend); gint _clutter_device_manager_evdev_acquire_device_id (ClutterDeviceManagerEvdev *manager_evdev); void _clutter_device_manager_evdev_release_device_id (ClutterDeviceManagerEvdev *manager_evdev, ClutterInputDevice *device); struct xkb_keymap * _clutter_device_manager_evdev_get_keymap (ClutterDeviceManagerEvdev *manager_evdev); ClutterStage * _clutter_device_manager_evdev_get_stage (ClutterDeviceManagerEvdev *manager_evdev); void _clutter_device_manager_evdev_constrain_pointer (ClutterDeviceManagerEvdev *manager_evdev, ClutterInputDevice *core_pointer, uint64_t time_us, float x, float y, float *new_x, float *new_y); void _clutter_device_manager_evdev_filter_relative_motion (ClutterDeviceManagerEvdev *manager_evdev, ClutterInputDevice *device, float x, float y, float *dx, float *dy); void _clutter_device_manager_evdev_dispatch (ClutterDeviceManagerEvdev *manager_evdev); static inline guint64 us (guint64 us) { return us; } static inline guint64 ms2us (guint64 ms) { return us (ms * 1000); } static inline guint32 us2ms (guint64 us) { return (guint32) (us / 1000); } G_END_DECLS #endif /* __CLUTTER_DEVICE_MANAGER_EVDEV_H__ */ ���������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-virtual-input-device-evdev.c�����������������������������0000664�0001750�0001750�00000062014�14211404421�026427� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <glib-object.h> #include <linux/input.h> #include "clutter-private.h" #include "clutter-virtual-input-device.h" #include "evdev/clutter-input-device-evdev.h" #include "evdev/clutter-seat-evdev.h" #include "evdev/clutter-virtual-input-device-evdev.h" enum { PROP_0, PROP_SEAT, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; struct _ClutterVirtualInputDeviceEvdev { ClutterVirtualInputDevice parent; ClutterInputDevice *device; ClutterSeatEvdev *seat; int button_count[KEY_CNT]; }; G_DEFINE_TYPE (ClutterVirtualInputDeviceEvdev, clutter_virtual_input_device_evdev, CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE) typedef enum _EvdevButtonType { EVDEV_BUTTON_TYPE_NONE, EVDEV_BUTTON_TYPE_KEY, EVDEV_BUTTON_TYPE_BUTTON, } EvdevButtonType; static int update_button_count (ClutterVirtualInputDeviceEvdev *virtual_evdev, uint32_t button, uint32_t state) { if (state) return ++virtual_evdev->button_count[button]; else return --virtual_evdev->button_count[button]; } static EvdevButtonType get_button_type (uint16_t code) { switch (code) { case BTN_TOOL_PEN: case BTN_TOOL_RUBBER: case BTN_TOOL_BRUSH: case BTN_TOOL_PENCIL: case BTN_TOOL_AIRBRUSH: case BTN_TOOL_MOUSE: case BTN_TOOL_LENS: case BTN_TOOL_QUINTTAP: case BTN_TOOL_DOUBLETAP: case BTN_TOOL_TRIPLETAP: case BTN_TOOL_QUADTAP: case BTN_TOOL_FINGER: case BTN_TOUCH: return EVDEV_BUTTON_TYPE_NONE; } if (code >= KEY_ESC && code <= KEY_MICMUTE) return EVDEV_BUTTON_TYPE_KEY; if (code >= BTN_MISC && code <= BTN_GEAR_UP) return EVDEV_BUTTON_TYPE_BUTTON; if (code >= KEY_OK && code <= KEY_LIGHTS_TOGGLE) return EVDEV_BUTTON_TYPE_KEY; if (code >= BTN_DPAD_UP && code <= BTN_DPAD_RIGHT) return EVDEV_BUTTON_TYPE_BUTTON; if (code >= KEY_ALS_TOGGLE && code <= KEY_KBDINPUTASSIST_CANCEL) return EVDEV_BUTTON_TYPE_KEY; if (code >= BTN_TRIGGER_HAPPY && code <= BTN_TRIGGER_HAPPY40) return EVDEV_BUTTON_TYPE_BUTTON; return EVDEV_BUTTON_TYPE_NONE; } static void release_pressed_buttons (ClutterVirtualInputDevice *virtual_device) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); int code; uint64_t time_us; time_us = g_get_monotonic_time (); for (code = 0; code < G_N_ELEMENTS (virtual_evdev->button_count); code++) { if (virtual_evdev->button_count[code] == 0) continue; switch (get_button_type (code)) { case EVDEV_BUTTON_TYPE_KEY: clutter_virtual_input_device_notify_key (virtual_device, time_us, code, CLUTTER_KEY_STATE_RELEASED); break; case EVDEV_BUTTON_TYPE_BUTTON: clutter_virtual_input_device_notify_button (virtual_device, time_us, code, CLUTTER_BUTTON_STATE_RELEASED); break; case EVDEV_BUTTON_TYPE_NONE: g_assert_not_reached (); } } } static void clutter_virtual_input_device_evdev_notify_relative_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); clutter_seat_evdev_notify_relative_motion (virtual_evdev->seat, virtual_evdev->device, time_us, dx, dy, dx, dy); } static void clutter_virtual_input_device_evdev_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double x, double y) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); clutter_seat_evdev_notify_absolute_motion (virtual_evdev->seat, virtual_evdev->device, time_us, x, y, NULL); } static void clutter_virtual_input_device_evdev_notify_button (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t button, ClutterButtonState button_state) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); int button_count; if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); if (get_button_type (button) != EVDEV_BUTTON_TYPE_BUTTON) { g_warning ("Unknown/invalid virtual device button 0x%x pressed", button); return; } button_count = update_button_count (virtual_evdev, button, button_state); if (button_count < 0 || button_count > 1) { g_warning ("Received multiple virtual 0x%x button %s (ignoring)", button, button_state == CLUTTER_BUTTON_STATE_PRESSED ? "presses" : "releases"); update_button_count (virtual_evdev, button, 1 - button_state); return; } clutter_seat_evdev_notify_button (virtual_evdev->seat, virtual_evdev->device, time_us, button, button_state); } static void clutter_virtual_input_device_evdev_notify_key (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t key, ClutterKeyState key_state) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); int key_count; if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); if (get_button_type (key) != EVDEV_BUTTON_TYPE_KEY) { g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", key); return; } key_count = update_button_count (virtual_evdev, key, key_state); if (key_count < 0 || key_count > 1) { g_warning ("Received multiple virtual 0x%x key %s (ignoring)", key, key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases"); update_button_count (virtual_evdev, key, 1 - key_state); return; } clutter_seat_evdev_notify_key (virtual_evdev->seat, virtual_evdev->device, time_us, key, key_state, TRUE); } static gboolean pick_keycode_for_keyval_in_current_group (ClutterVirtualInputDevice *virtual_device, guint keyval, guint *keycode_out, guint *level_out) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); ClutterDeviceManager *manager; struct xkb_keymap *xkb_keymap; struct xkb_state *state; guint keycode, layout; xkb_keycode_t min_keycode, max_keycode; manager = clutter_virtual_input_device_get_manager (virtual_device); xkb_keymap = _clutter_device_manager_evdev_get_keymap (CLUTTER_DEVICE_MANAGER_EVDEV (manager)); state = virtual_evdev->seat->xkb; layout = xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE); min_keycode = xkb_keymap_min_keycode (xkb_keymap); max_keycode = xkb_keymap_max_keycode (xkb_keymap); for (keycode = min_keycode; keycode < max_keycode; keycode++) { gint num_levels, level; num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout); for (level = 0; level < num_levels; level++) { const xkb_keysym_t *syms; gint num_syms, sym; num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms); for (sym = 0; sym < num_syms; sym++) { if (syms[sym] == keyval) { *keycode_out = keycode; if (level_out) *level_out = level; return TRUE; } } } } return FALSE; } static void apply_level_modifiers (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t level, uint32_t key_state) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); guint keysym, keycode, evcode; if (level == 0) return; if (level == 1) { keysym = XKB_KEY_Shift_L; } else if (level == 2) { keysym = XKB_KEY_ISO_Level3_Shift; } else { g_warning ("Unhandled level: %d\n", level); return; } if (!pick_keycode_for_keyval_in_current_group (virtual_device, keysym, &keycode, NULL)) return; clutter_input_device_keycode_to_evdev (virtual_evdev->device, keycode, &evcode); clutter_seat_evdev_notify_key (virtual_evdev->seat, virtual_evdev->device, time_us, evcode, key_state, TRUE); } static void clutter_virtual_input_device_evdev_notify_keyval (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t keyval, ClutterKeyState key_state) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); int key_count; guint keycode = 0, level = 0, evcode = 0; if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); if (!pick_keycode_for_keyval_in_current_group (virtual_device, keyval, &keycode, &level)) { g_warning ("No keycode found for keyval %x in current group", keyval); return; } clutter_input_device_keycode_to_evdev (virtual_evdev->device, keycode, &evcode); if (get_button_type (evcode) != EVDEV_BUTTON_TYPE_KEY) { g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", evcode); return; } key_count = update_button_count (virtual_evdev, evcode, key_state); if (key_count < 0 || key_count > 1) { g_warning ("Received multiple virtual 0x%x key %s (ignoring)", keycode, key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases"); update_button_count (virtual_evdev, evcode, 1 - key_state); return; } if (key_state) apply_level_modifiers (virtual_device, time_us, level, key_state); clutter_seat_evdev_notify_key (virtual_evdev->seat, virtual_evdev->device, time_us, evcode, key_state, TRUE); if (!key_state) apply_level_modifiers (virtual_device, time_us, level, key_state); } static void direction_to_discrete (ClutterScrollDirection direction, double *discrete_dx, double *discrete_dy) { switch (direction) { case CLUTTER_SCROLL_UP: *discrete_dx = 0.0; *discrete_dy = -1.0; break; case CLUTTER_SCROLL_DOWN: *discrete_dx = 0.0; *discrete_dy = 1.0; break; case CLUTTER_SCROLL_LEFT: *discrete_dx = -1.0; *discrete_dy = 0.0; break; case CLUTTER_SCROLL_RIGHT: *discrete_dx = 1.0; *discrete_dy = 0.0; break; case CLUTTER_SCROLL_SMOOTH: g_assert_not_reached (); break; } } static void clutter_virtual_input_device_evdev_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, ClutterScrollDirection direction, ClutterScrollSource scroll_source) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); double discrete_dx = 0.0, discrete_dy = 0.0; if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); direction_to_discrete (direction, &discrete_dx, &discrete_dy); clutter_seat_evdev_notify_discrete_scroll (virtual_evdev->seat, virtual_evdev->device, time_us, discrete_dx, discrete_dy, scroll_source); } static void clutter_virtual_input_device_evdev_notify_scroll_continuous (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy, ClutterScrollSource scroll_source, ClutterScrollFinishFlags finish_flags) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); clutter_seat_evdev_notify_scroll_continuous (virtual_evdev->seat, virtual_evdev->device, time_us, dx, dy, scroll_source, CLUTTER_SCROLL_FINISHED_NONE); } static void clutter_virtual_input_device_evdev_notify_touch_down (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int device_slot, double x, double y) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (virtual_evdev->device); ClutterTouchState *touch_state; if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); touch_state = clutter_input_device_evdev_acquire_touch_state (device_evdev, device_slot); if (!touch_state) return; touch_state->coords.x = x; touch_state->coords.y = y; clutter_seat_evdev_notify_touch_event (virtual_evdev->seat, virtual_evdev->device, CLUTTER_TOUCH_BEGIN, time_us, touch_state->seat_slot, touch_state->coords.x, touch_state->coords.y); } static void clutter_virtual_input_device_evdev_notify_touch_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int device_slot, double x, double y) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (virtual_evdev->device); ClutterTouchState *touch_state; if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); touch_state = clutter_input_device_evdev_lookup_touch_state (device_evdev, device_slot); if (!touch_state) return; touch_state->coords.x = x; touch_state->coords.y = y; clutter_seat_evdev_notify_touch_event (virtual_evdev->seat, virtual_evdev->device, CLUTTER_TOUCH_BEGIN, time_us, touch_state->seat_slot, touch_state->coords.x, touch_state->coords.y); } static void clutter_virtual_input_device_evdev_notify_touch_up (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int device_slot) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device); ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (virtual_evdev->device); ClutterTouchState *touch_state; if (time_us == CLUTTER_CURRENT_TIME) time_us = g_get_monotonic_time (); touch_state = clutter_input_device_evdev_lookup_touch_state (device_evdev, device_slot); if (!touch_state) return; clutter_seat_evdev_notify_touch_event (virtual_evdev->seat, virtual_evdev->device, CLUTTER_TOUCH_BEGIN, time_us, touch_state->seat_slot, touch_state->coords.x, touch_state->coords.y); clutter_input_device_evdev_release_touch_state (device_evdev, touch_state); } static void clutter_virtual_input_device_evdev_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object); switch (prop_id) { case PROP_SEAT: g_value_set_pointer (value, virtual_evdev->seat); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_virtual_input_device_evdev_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object); switch (prop_id) { case PROP_SEAT: virtual_evdev->seat = g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_virtual_input_device_evdev_constructed (GObject *object) { ClutterVirtualInputDevice *virtual_device = CLUTTER_VIRTUAL_INPUT_DEVICE (object); ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object); ClutterDeviceManager *manager; ClutterInputDeviceType device_type; ClutterStage *stage; manager = clutter_virtual_input_device_get_manager (virtual_device); device_type = clutter_virtual_input_device_get_device_type (virtual_device); virtual_evdev->device = _clutter_input_device_evdev_new_virtual (manager, virtual_evdev->seat, device_type, CLUTTER_INPUT_MODE_SLAVE); stage = _clutter_device_manager_evdev_get_stage (CLUTTER_DEVICE_MANAGER_EVDEV (manager)); _clutter_input_device_set_stage (virtual_evdev->device, stage); } static void clutter_virtual_input_device_evdev_finalize (GObject *object) { ClutterVirtualInputDevice *virtual_device = CLUTTER_VIRTUAL_INPUT_DEVICE (object); ClutterVirtualInputDeviceEvdev *virtual_evdev = CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object); GObjectClass *object_class; release_pressed_buttons (virtual_device); g_clear_object (&virtual_evdev->device); object_class = G_OBJECT_CLASS (clutter_virtual_input_device_evdev_parent_class); object_class->finalize (object); } static void clutter_virtual_input_device_evdev_init (ClutterVirtualInputDeviceEvdev *virtual_device_evdev) { } static void clutter_virtual_input_device_evdev_class_init (ClutterVirtualInputDeviceEvdevClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterVirtualInputDeviceClass *virtual_input_device_class = CLUTTER_VIRTUAL_INPUT_DEVICE_CLASS (klass); object_class->get_property = clutter_virtual_input_device_evdev_get_property; object_class->set_property = clutter_virtual_input_device_evdev_set_property; object_class->constructed = clutter_virtual_input_device_evdev_constructed; object_class->finalize = clutter_virtual_input_device_evdev_finalize; virtual_input_device_class->notify_relative_motion = clutter_virtual_input_device_evdev_notify_relative_motion; virtual_input_device_class->notify_absolute_motion = clutter_virtual_input_device_evdev_notify_absolute_motion; virtual_input_device_class->notify_button = clutter_virtual_input_device_evdev_notify_button; virtual_input_device_class->notify_key = clutter_virtual_input_device_evdev_notify_key; virtual_input_device_class->notify_keyval = clutter_virtual_input_device_evdev_notify_keyval; virtual_input_device_class->notify_discrete_scroll = clutter_virtual_input_device_evdev_notify_discrete_scroll; virtual_input_device_class->notify_scroll_continuous = clutter_virtual_input_device_evdev_notify_scroll_continuous; virtual_input_device_class->notify_touch_down = clutter_virtual_input_device_evdev_notify_touch_down; virtual_input_device_class->notify_touch_motion = clutter_virtual_input_device_evdev_notify_touch_motion; virtual_input_device_class->notify_touch_up = clutter_virtual_input_device_evdev_notify_touch_up; obj_props[PROP_SEAT] = g_param_spec_pointer ("seat", P_("ClutterSeatEvdev"), P_("ClutterSeatEvdev"), CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (object_class, PROP_LAST, obj_props); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-seat-evdev.c���������������������������������������������0000664�0001750�0001750�00000067251�14211404421�023313� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corp. * Copyright (C) 2014 Jonas Ådahl * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Damien Lespiau <damien.lespiau@intel.com> * Author: Jonas Ådahl <jadahl@gmail.com> */ #include "clutter-build-config.h" #include "clutter-seat-evdev.h" #include <linux/input.h> #include <math.h> #include "clutter-event-private.h" #include "clutter-input-device-evdev.h" #include "clutter-input-device-tool-evdev.h" #include "clutter-main.h" /* Try to keep the pointer inside the stage. Hopefully no one is using * this backend with stages smaller than this. */ #define INITIAL_POINTER_X 16 #define INITIAL_POINTER_Y 16 #define AUTOREPEAT_VALUE 2 #define DISCRETE_SCROLL_STEP 10.0 #ifndef BTN_STYLUS3 #define BTN_STYLUS3 0x149 /* Linux 4.15 */ #endif void clutter_seat_evdev_set_libinput_seat (ClutterSeatEvdev *seat, struct libinput_seat *libinput_seat) { g_assert (seat->libinput_seat == NULL); libinput_seat_ref (libinput_seat); libinput_seat_set_user_data (libinput_seat, seat); seat->libinput_seat = libinput_seat; } void clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat) { GSList *iter; ClutterInputDeviceEvdev *device_evdev; int caps_lock, num_lock, scroll_lock; enum libinput_led leds = 0; caps_lock = xkb_state_led_index_is_active (seat->xkb, seat->caps_lock_led); num_lock = xkb_state_led_index_is_active (seat->xkb, seat->num_lock_led); scroll_lock = xkb_state_led_index_is_active (seat->xkb, seat->scroll_lock_led); if (caps_lock) leds |= LIBINPUT_LED_CAPS_LOCK; if (num_lock) leds |= LIBINPUT_LED_NUM_LOCK; if (scroll_lock) leds |= LIBINPUT_LED_SCROLL_LOCK; for (iter = seat->devices; iter; iter = iter->next) { device_evdev = iter->data; _clutter_input_device_evdev_update_leds (device_evdev, leds); } } static void clutter_touch_state_free (ClutterTouchState *touch_state) { g_slice_free (ClutterTouchState, touch_state); } static void ensure_seat_slot_allocated (ClutterSeatEvdev *seat, int seat_slot) { if (seat_slot >= seat->n_alloc_touch_states) { const int size_increase = 5; int i; seat->n_alloc_touch_states += size_increase; seat->touch_states = realloc (seat->touch_states, seat->n_alloc_touch_states * sizeof (ClutterTouchState *)); for (i = 0; i < size_increase; i++) seat->touch_states[seat->n_alloc_touch_states - (i + 1)] = NULL; } } ClutterTouchState * clutter_seat_evdev_acquire_touch_state (ClutterSeatEvdev *seat, int device_slot) { ClutterTouchState *touch_state; int seat_slot; for (seat_slot = 0; seat_slot < seat->n_alloc_touch_states; seat_slot++) { if (!seat->touch_states[seat_slot]) break; } ensure_seat_slot_allocated (seat, seat_slot); touch_state = g_slice_new0 (ClutterTouchState); *touch_state = (ClutterTouchState) { .seat = seat, .seat_slot = seat_slot, .device_slot = device_slot, }; seat->touch_states[seat_slot] = touch_state; return touch_state; } void clutter_seat_evdev_release_touch_state (ClutterSeatEvdev *seat, ClutterTouchState *touch_state) { g_clear_pointer (&seat->touch_states[touch_state->seat_slot], (GDestroyNotify) clutter_touch_state_free); } ClutterSeatEvdev * clutter_seat_evdev_new (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (manager_evdev); ClutterSeatEvdev *seat; ClutterInputDevice *device; ClutterStage *stage; struct xkb_keymap *keymap; seat = g_new0 (ClutterSeatEvdev, 1); if (!seat) return NULL; seat->manager_evdev = manager_evdev; device = _clutter_input_device_evdev_new_virtual ( manager, seat, CLUTTER_POINTER_DEVICE, CLUTTER_INPUT_MODE_MASTER); stage = _clutter_device_manager_evdev_get_stage (manager_evdev); _clutter_input_device_set_stage (device, stage); seat->pointer_x = INITIAL_POINTER_X; seat->pointer_y = INITIAL_POINTER_Y; _clutter_input_device_set_coords (device, NULL, seat->pointer_x, seat->pointer_y, NULL); _clutter_device_manager_add_device (manager, device); seat->core_pointer = device; device = _clutter_input_device_evdev_new_virtual ( manager, seat, CLUTTER_KEYBOARD_DEVICE, CLUTTER_INPUT_MODE_MASTER); _clutter_input_device_set_stage (device, stage); _clutter_device_manager_add_device (manager, device); seat->core_keyboard = device; seat->repeat = TRUE; seat->repeat_delay = 250; /* ms */ seat->repeat_interval = 33; /* ms */ keymap = _clutter_device_manager_evdev_get_keymap (manager_evdev); if (keymap) { seat->xkb = xkb_state_new (keymap); seat->caps_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_CAPS); seat->num_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_NUM); seat->scroll_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_SCROLL); } return seat; } void clutter_seat_evdev_clear_repeat_timer (ClutterSeatEvdev *seat) { if (seat->repeat_timer) { g_source_remove (seat->repeat_timer); seat->repeat_timer = 0; g_clear_object (&seat->repeat_device); } } static gboolean keyboard_repeat (gpointer data) { ClutterSeatEvdev *seat = data; GSource *source; /* There might be events queued in libinput that could cancel the repeat timer. */ _clutter_device_manager_evdev_dispatch (seat->manager_evdev); if (!seat->repeat_timer) return G_SOURCE_REMOVE; g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE); source = g_main_context_find_source_by_id (NULL, seat->repeat_timer); clutter_seat_evdev_notify_key (seat, seat->repeat_device, g_source_get_time (source), seat->repeat_key, AUTOREPEAT_VALUE, FALSE); return G_SOURCE_CONTINUE; } static void queue_event (ClutterEvent *event) { _clutter_event_push (event, FALSE); } static int update_button_count (ClutterSeatEvdev *seat, uint32_t button, uint32_t state) { if (state) { return ++seat->button_count[button]; } else { /* Handle cases where we newer saw the initial pressed event. */ if (seat->button_count[button] == 0) return 0; return --seat->button_count[button]; } } void clutter_seat_evdev_notify_key (ClutterSeatEvdev *seat, ClutterInputDevice *device, uint64_t time_us, uint32_t key, uint32_t state, gboolean update_keys) { ClutterStage *stage; ClutterEvent *event = NULL; enum xkb_state_component changed_state; if (state != AUTOREPEAT_VALUE) { /* Drop any repeated button press (for example from virtual devices. */ int count = update_button_count (seat, key, state); if (state && count > 1) return; if (!state && count != 0) return; } /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (device); if (stage == NULL) { clutter_seat_evdev_clear_repeat_timer (seat); return; } event = _clutter_key_event_new_from_evdev (device, seat->core_keyboard, stage, seat->xkb, seat->button_state, us2ms (time_us), key, state); _clutter_evdev_event_set_event_code (event, key); /* We must be careful and not pass multiple releases to xkb, otherwise it gets confused and locks the modifiers */ if (state != AUTOREPEAT_VALUE) { changed_state = xkb_state_update_key (seat->xkb, event->key.hardware_keycode, state ? XKB_KEY_DOWN : XKB_KEY_UP); } else { changed_state = 0; clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_SYNTHETIC); } queue_event (event); if (update_keys && (changed_state & XKB_STATE_LEDS)) clutter_seat_evdev_sync_leds (seat); if (state == 0 || /* key release */ !seat->repeat || !xkb_keymap_key_repeats (xkb_state_get_keymap (seat->xkb), event->key.hardware_keycode)) { clutter_seat_evdev_clear_repeat_timer (seat); return; } if (state == 1) /* key press */ seat->repeat_count = 0; seat->repeat_count += 1; seat->repeat_key = key; switch (seat->repeat_count) { case 1: case 2: { guint32 interval; clutter_seat_evdev_clear_repeat_timer (seat); seat->repeat_device = g_object_ref (device); if (seat->repeat_count == 1) interval = seat->repeat_delay; else interval = seat->repeat_interval; seat->repeat_timer = clutter_threads_add_timeout_full (CLUTTER_PRIORITY_EVENTS, interval, keyboard_repeat, seat, NULL); return; } default: return; } } static ClutterEvent * new_absolute_motion_event (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, guint64 time_us, gfloat x, gfloat y, gdouble *axes) { ClutterStage *stage = _clutter_input_device_get_stage (input_device); ClutterEvent *event; event = clutter_event_new (CLUTTER_MOTION); if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) _clutter_device_manager_evdev_constrain_pointer (seat->manager_evdev, seat->core_pointer, time_us, seat->pointer_x, seat->pointer_y, &x, &y); _clutter_evdev_event_set_time_usec (event, time_us); event->motion.time = us2ms (time_us); event->motion.stage = stage; event->motion.device = seat->core_pointer; _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); event->motion.x = x; event->motion.y = y; event->motion.axes = axes; clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) { ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); clutter_event_set_device_tool (event, device_evdev->last_tool); clutter_event_set_device (event, input_device); } else { clutter_event_set_device (event, seat->core_pointer); } _clutter_input_device_set_stage (seat->core_pointer, stage); if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) { seat->pointer_x = x; seat->pointer_y = y; } return event; } void clutter_seat_evdev_notify_relative_motion (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, float dx, float dy, float dx_unaccel, float dy_unaccel) { gfloat new_x, new_y; ClutterEvent *event; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ if (!_clutter_input_device_get_stage (input_device)) return; _clutter_device_manager_evdev_filter_relative_motion (seat->manager_evdev, input_device, seat->pointer_x, seat->pointer_y, &dx, &dy); new_x = seat->pointer_x + dx; new_y = seat->pointer_y + dy; event = new_absolute_motion_event (seat, input_device, time_us, new_x, new_y, NULL); _clutter_evdev_event_set_relative_motion (event, dx, dy, dx_unaccel, dy_unaccel); queue_event (event); } void clutter_seat_evdev_notify_absolute_motion (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, float x, float y, double *axes) { ClutterEvent *event; event = new_absolute_motion_event (seat, input_device, time_us, x, y, axes); queue_event (event); } void clutter_seat_evdev_notify_button (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, uint32_t button, uint32_t state) { ClutterInputDeviceEvdev *device_evdev = (ClutterInputDeviceEvdev *) input_device; ClutterStage *stage; ClutterEvent *event = NULL; gint button_nr; static gint maskmap[8] = { CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON3_MASK, CLUTTER_BUTTON2_MASK, CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK, 0, 0, 0 }; int button_count; /* Drop any repeated button press (for example from virtual devices. */ button_count = update_button_count (seat, button, state); if (state && button_count > 1) return; if (!state && button_count != 0) return; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; /* The evdev button numbers don't map sequentially to clutter button * numbers (the right and middle mouse buttons are in the opposite * order) so we'll map them directly with a switch statement */ switch (button) { case BTN_LEFT: case BTN_TOUCH: button_nr = CLUTTER_BUTTON_PRIMARY; break; case BTN_RIGHT: case BTN_STYLUS: button_nr = CLUTTER_BUTTON_SECONDARY; break; case BTN_MIDDLE: case BTN_STYLUS2: button_nr = CLUTTER_BUTTON_MIDDLE; break; case 0x149: /* BTN_STYLUS3 */ button_nr = 8; break; default: /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */ if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) button_nr = button - BTN_TOOL_PEN + 4; else button_nr = button - (BTN_LEFT - 1) + 4; break; } if (button_nr < 1 || button_nr > 12) { g_warning ("Unhandled button event 0x%x", button); return; } if (state) event = clutter_event_new (CLUTTER_BUTTON_PRESS); else event = clutter_event_new (CLUTTER_BUTTON_RELEASE); if (button_nr < G_N_ELEMENTS (maskmap)) { /* Update the modifiers */ if (state) seat->button_state |= maskmap[button_nr - 1]; else seat->button_state &= ~maskmap[button_nr - 1]; } _clutter_evdev_event_set_time_usec (event, time_us); event->button.time = us2ms (time_us); event->button.stage = CLUTTER_STAGE (stage); _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); event->button.button = button_nr; if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) { ClutterPoint point; clutter_input_device_get_coords (input_device, NULL, &point); event->button.x = point.x; event->button.y = point.y; } else { event->button.x = seat->pointer_x; event->button.y = seat->pointer_y; } clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); if (device_evdev->last_tool) { /* Apply the button event code as per the tool mapping */ guint mapped_button; mapped_button = clutter_input_device_tool_evdev_get_button_code (device_evdev->last_tool, button_nr); if (mapped_button != 0) button = mapped_button; } _clutter_evdev_event_set_event_code (event, button); if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) { clutter_event_set_device_tool (event, device_evdev->last_tool); clutter_event_set_device (event, input_device); } else { clutter_event_set_device (event, seat->core_pointer); } _clutter_input_device_set_stage (seat->core_pointer, stage); queue_event (event); } static void notify_scroll (ClutterInputDevice *input_device, guint64 time_us, gdouble dx, gdouble dy, ClutterScrollSource scroll_source, ClutterScrollFinishFlags flags, gboolean emulated) { ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event = NULL; gdouble scroll_factor; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); event = clutter_event_new (CLUTTER_SCROLL); _clutter_evdev_event_set_time_usec (event, time_us); event->scroll.time = us2ms (time_us); event->scroll.stage = CLUTTER_STAGE (stage); event->scroll.device = seat->core_pointer; _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); /* libinput pointer axis events are in pointer motion coordinate space. * To convert to Xi2 discrete step coordinate space, multiply the factor * 1/10. */ event->scroll.direction = CLUTTER_SCROLL_SMOOTH; scroll_factor = 1.0 / DISCRETE_SCROLL_STEP; clutter_event_set_scroll_delta (event, scroll_factor * dx, scroll_factor * dy); event->scroll.x = seat->pointer_x; event->scroll.y = seat->pointer_y; clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); event->scroll.scroll_source = scroll_source; event->scroll.finish_flags = flags; _clutter_event_set_pointer_emulated (event, emulated); queue_event (event); } static void notify_discrete_scroll (ClutterInputDevice *input_device, uint64_t time_us, ClutterScrollDirection direction, ClutterScrollSource scroll_source, gboolean emulated) { ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event = NULL; if (direction == CLUTTER_SCROLL_SMOOTH) return; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); event = clutter_event_new (CLUTTER_SCROLL); _clutter_evdev_event_set_time_usec (event, time_us); event->scroll.time = us2ms (time_us); event->scroll.stage = CLUTTER_STAGE (stage); event->scroll.device = seat->core_pointer; _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); event->scroll.direction = direction; event->scroll.x = seat->pointer_x; event->scroll.y = seat->pointer_y; clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); event->scroll.scroll_source = scroll_source; _clutter_event_set_pointer_emulated (event, emulated); queue_event (event); } static void check_notify_discrete_scroll (ClutterSeatEvdev *seat, ClutterInputDevice *device, uint64_t time_us, ClutterScrollSource scroll_source) { int i, n_xscrolls, n_yscrolls; n_xscrolls = floor (fabs (seat->accum_scroll_dx) / DISCRETE_SCROLL_STEP); n_yscrolls = floor (fabs (seat->accum_scroll_dy) / DISCRETE_SCROLL_STEP); for (i = 0; i < n_xscrolls; i++) { notify_discrete_scroll (device, time_us, seat->accum_scroll_dx > 0 ? CLUTTER_SCROLL_RIGHT : CLUTTER_SCROLL_LEFT, scroll_source, TRUE); } for (i = 0; i < n_yscrolls; i++) { notify_discrete_scroll (device, time_us, seat->accum_scroll_dy > 0 ? CLUTTER_SCROLL_DOWN : CLUTTER_SCROLL_UP, scroll_source, TRUE); } seat->accum_scroll_dx = fmodf (seat->accum_scroll_dx, DISCRETE_SCROLL_STEP); seat->accum_scroll_dy = fmodf (seat->accum_scroll_dy, DISCRETE_SCROLL_STEP); } void clutter_seat_evdev_notify_scroll_continuous (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, double dx, double dy, ClutterScrollSource scroll_source, ClutterScrollFinishFlags finish_flags) { if (finish_flags & CLUTTER_SCROLL_FINISHED_HORIZONTAL) seat->accum_scroll_dx = 0; else seat->accum_scroll_dx += dx; if (finish_flags & CLUTTER_SCROLL_FINISHED_VERTICAL) seat->accum_scroll_dy = 0; else seat->accum_scroll_dy += dy; notify_scroll (input_device, time_us, dx, dy, scroll_source, finish_flags, FALSE); check_notify_discrete_scroll (seat, input_device, time_us, scroll_source); } static ClutterScrollDirection discrete_to_direction (double discrete_dx, double discrete_dy) { if (discrete_dx > 0) return CLUTTER_SCROLL_RIGHT; else if (discrete_dx < 0) return CLUTTER_SCROLL_LEFT; else if (discrete_dy > 0) return CLUTTER_SCROLL_DOWN; else if (discrete_dy < 0) return CLUTTER_SCROLL_UP; else g_assert_not_reached (); } void clutter_seat_evdev_notify_discrete_scroll (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, double discrete_dx, double discrete_dy, ClutterScrollSource scroll_source) { notify_scroll (input_device, time_us, discrete_dx * DISCRETE_SCROLL_STEP, discrete_dy * DISCRETE_SCROLL_STEP, scroll_source, CLUTTER_SCROLL_FINISHED_NONE, TRUE); notify_discrete_scroll (input_device, time_us, discrete_to_direction (discrete_dx, discrete_dy), scroll_source, FALSE); } void clutter_seat_evdev_notify_touch_event (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, ClutterEventType evtype, uint64_t time_us, int slot, double x, double y) { ClutterStage *stage; ClutterEvent *event = NULL; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; event = clutter_event_new (evtype); _clutter_evdev_event_set_time_usec (event, time_us); event->touch.time = us2ms (time_us); event->touch.stage = CLUTTER_STAGE (stage); event->touch.device = seat->core_pointer; event->touch.x = x; event->touch.y = y; clutter_input_device_evdev_translate_coordinates (input_device, stage, &event->touch.x, &event->touch.y); /* "NULL" sequences are special cased in clutter */ event->touch.sequence = GINT_TO_POINTER (MAX (1, slot + 1)); _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); if (evtype == CLUTTER_TOUCH_BEGIN || evtype == CLUTTER_TOUCH_UPDATE) event->touch.modifier_state |= CLUTTER_BUTTON1_MASK; clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); queue_event (event); } void clutter_seat_evdev_free (ClutterSeatEvdev *seat) { GSList *iter; for (iter = seat->devices; iter; iter = g_slist_next (iter)) { ClutterInputDevice *device = iter->data; g_object_unref (device); } g_slist_free (seat->devices); free (seat->touch_states); xkb_state_unref (seat->xkb); clutter_seat_evdev_clear_repeat_timer (seat); if (seat->libinput_seat) libinput_seat_unref (seat->libinput_seat); free (seat); } ClutterInputDevice * clutter_seat_evdev_get_device (ClutterSeatEvdev *seat, gint id) { ClutterInputDevice *device; GSList *l; for (l = seat->devices; l; l = l->next) { device = l->data; if (clutter_input_device_get_device_id (device) == id) return device; } return NULL; } void clutter_seat_evdev_set_stage (ClutterSeatEvdev *seat, ClutterStage *stage) { GSList *l; _clutter_input_device_set_stage (seat->core_pointer, stage); _clutter_input_device_set_stage (seat->core_keyboard, stage); for (l = seat->devices; l; l = l->next) { ClutterInputDevice *device = l->data; _clutter_input_device_set_stage (device, stage); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-device-manager-evdev.c�����������������������������������0000664�0001750�0001750�00000263202�14211404421�025220� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corp. * Copyright (C) 2014 Jonas Ådahl * * 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, see <http://www.gnu.org/licenses/>. * * Author: Damien Lespiau <damien.lespiau@intel.com> * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include <float.h> #include <linux/input.h> #include <sys/stat.h> #include <sys/types.h> #include <errno.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <glib.h> #include <libinput.h> #include "clutter-backend.h" #include "clutter-debug.h" #include "clutter-device-manager.h" #include "clutter-device-manager-private.h" #include "clutter-event-private.h" #include "clutter-input-device-evdev.h" #include "clutter-seat-evdev.h" #include "clutter-virtual-input-device-evdev.h" #include "clutter-main.h" #include "clutter-private.h" #include "clutter-stage-manager.h" #include "clutter-xkb-utils.h" #include "clutter-backend-private.h" #include "clutter-evdev.h" #include "clutter-stage-private.h" #include "clutter-input-device-tool-evdev.h" #include "clutter-device-manager-evdev.h" /* * Clutter makes the assumption that two core devices have ID's 2 and 3 (core * pointer and core keyboard). * * Since the two first devices that will ever be created will be the virtual * pointer and virtual keyboard of the first seat, we fulfill the made * assumptions by having the first device having ID 2 and following 3. */ #define INITIAL_DEVICE_ID 2 typedef struct _ClutterEventFilter ClutterEventFilter; struct _ClutterEventFilter { ClutterEvdevFilterFunc func; gpointer data; GDestroyNotify destroy_notify; }; typedef struct _ClutterEventSource ClutterEventSource; struct _ClutterDeviceManagerEvdevPrivate { struct libinput *libinput; ClutterStage *stage; gboolean released; ClutterEventSource *event_source; GSList *devices; GSList *seats; ClutterSeatEvdev *main_seat; struct xkb_keymap *keymap; ClutterPointerConstrainCallback constrain_callback; gpointer constrain_data; GDestroyNotify constrain_data_notify; ClutterRelativeMotionFilter relative_motion_filter; gpointer relative_motion_filter_user_data; ClutterStageManager *stage_manager; guint stage_added_handler; guint stage_removed_handler; GSList *event_filters; gint device_id_next; GList *free_device_ids; }; static void clutter_device_manager_evdev_event_extender_init (ClutterEventExtenderInterface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerEvdev, clutter_device_manager_evdev, CLUTTER_TYPE_DEVICE_MANAGER, G_ADD_PRIVATE (ClutterDeviceManagerEvdev) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_EXTENDER, clutter_device_manager_evdev_event_extender_init)) static ClutterOpenDeviceCallback device_open_callback; static ClutterCloseDeviceCallback device_close_callback; static gpointer device_callback_data; static gchar * evdev_seat_id; #ifdef CLUTTER_ENABLE_DEBUG static const char *device_type_str[] = { "pointer", /* CLUTTER_POINTER_DEVICE */ "keyboard", /* CLUTTER_KEYBOARD_DEVICE */ "extension", /* CLUTTER_EXTENSION_DEVICE */ "joystick", /* CLUTTER_JOYSTICK_DEVICE */ "tablet", /* CLUTTER_TABLET_DEVICE */ "touchpad", /* CLUTTER_TOUCHPAD_DEVICE */ "touchscreen", /* CLUTTER_TOUCHSCREEN_DEVICE */ "pen", /* CLUTTER_PEN_DEVICE */ "eraser", /* CLUTTER_ERASER_DEVICE */ "cursor", /* CLUTTER_CURSOR_DEVICE */ "pad", /* CLUTTER_PAD_DEVICE */ }; #endif /* CLUTTER_ENABLE_DEBUG */ /* * ClutterEventSource management * * The device manager is responsible for managing the GSource when devices * appear and disappear from the system. */ static const char *option_xkb_layout = "us"; static const char *option_xkb_variant = ""; static const char *option_xkb_options = ""; static void clutter_device_manager_evdev_copy_event_data (ClutterEventExtender *event_extender, const ClutterEvent *src, ClutterEvent *dest) { ClutterEventEvdev *event_evdev; event_evdev = _clutter_event_get_platform_data (src); if (event_evdev != NULL) _clutter_event_set_platform_data (dest, _clutter_event_evdev_copy (event_evdev)); } static void clutter_device_manager_evdev_free_event_data (ClutterEventExtender *event_extender, ClutterEvent *event) { ClutterEventEvdev *event_evdev; event_evdev = _clutter_event_get_platform_data (event); if (event_evdev != NULL) _clutter_event_evdev_free (event_evdev); } static void clutter_device_manager_evdev_event_extender_init (ClutterEventExtenderInterface *iface) { iface->copy_event_data = clutter_device_manager_evdev_copy_event_data; iface->free_event_data = clutter_device_manager_evdev_free_event_data; } /* * ClutterEventSource for reading input devices */ struct _ClutterEventSource { GSource source; ClutterDeviceManagerEvdev *manager_evdev; GPollFD event_poll_fd; }; static void process_events (ClutterDeviceManagerEvdev *manager_evdev); static gboolean clutter_event_prepare (GSource *source, gint *timeout) { gboolean retval; _clutter_threads_acquire_lock (); *timeout = -1; retval = clutter_events_pending (); _clutter_threads_release_lock (); return retval; } static gboolean clutter_event_check (GSource *source) { ClutterEventSource *event_source = (ClutterEventSource *) source; gboolean retval; _clutter_threads_acquire_lock (); retval = ((event_source->event_poll_fd.revents & G_IO_IN) || clutter_events_pending ()); _clutter_threads_release_lock (); return retval; } static void queue_event (ClutterEvent *event) { _clutter_event_push (event, FALSE); } void _clutter_device_manager_evdev_constrain_pointer (ClutterDeviceManagerEvdev *manager_evdev, ClutterInputDevice *core_pointer, uint64_t time_us, float x, float y, float *new_x, float *new_y) { if (manager_evdev->priv->constrain_callback) { manager_evdev->priv->constrain_callback (core_pointer, us2ms (time_us), x, y, new_x, new_y, manager_evdev->priv->constrain_data); } else { ClutterActor *stage = CLUTTER_ACTOR (manager_evdev->priv->stage); float stage_width = clutter_actor_get_width (stage); float stage_height = clutter_actor_get_height (stage); x = CLAMP (x, 0.f, stage_width - 1); y = CLAMP (y, 0.f, stage_height - 1); } } void _clutter_device_manager_evdev_filter_relative_motion (ClutterDeviceManagerEvdev *manager_evdev, ClutterInputDevice *device, float x, float y, float *dx, float *dy) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; if (!priv->relative_motion_filter) return; priv->relative_motion_filter (device, x, y, dx, dy, priv->relative_motion_filter_user_data); } static ClutterEvent * new_absolute_motion_event (ClutterInputDevice *input_device, guint64 time_us, gfloat x, gfloat y, gdouble *axes) { gfloat stage_width, stage_height; ClutterDeviceManagerEvdev *manager_evdev; ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event = NULL; stage = _clutter_input_device_get_stage (input_device); device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (input_device->device_manager); seat = _clutter_input_device_evdev_get_seat (device_evdev); stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); event = clutter_event_new (CLUTTER_MOTION); if (manager_evdev->priv->constrain_callback && clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) { manager_evdev->priv->constrain_callback (seat->core_pointer, us2ms (time_us), seat->pointer_x, seat->pointer_y, &x, &y, manager_evdev->priv->constrain_data); } else { x = CLAMP (x, 0.f, stage_width - 1); y = CLAMP (y, 0.f, stage_height - 1); } _clutter_evdev_event_set_time_usec (event, time_us); event->motion.time = us2ms (time_us); event->motion.stage = stage; event->motion.device = seat->core_pointer; _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); event->motion.x = x; event->motion.y = y; clutter_input_device_evdev_translate_coordinates (input_device, stage, &event->motion.x, &event->motion.y); event->motion.axes = axes; clutter_event_set_source_device (event, input_device); if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) { clutter_event_set_device_tool (event, device_evdev->last_tool); clutter_event_set_device (event, input_device); } else clutter_event_set_device (event, seat->core_pointer); _clutter_input_device_set_stage (seat->core_pointer, stage); if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) { seat->pointer_x = x; seat->pointer_y = y; } return event; } static void notify_absolute_motion (ClutterInputDevice *input_device, guint64 time_us, gfloat x, gfloat y, gdouble *axes) { ClutterEvent *event; event = new_absolute_motion_event (input_device, time_us, x, y, axes); queue_event (event); } static void notify_relative_tool_motion (ClutterInputDevice *input_device, guint64 time_us, gfloat dx, gfloat dy, gdouble *axes) { ClutterInputDeviceEvdev *device_evdev; ClutterEvent *event; ClutterSeatEvdev *seat; gfloat x, y; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); x = input_device->current_x + dx; y = input_device->current_y + dy; _clutter_device_manager_evdev_filter_relative_motion (seat->manager_evdev, input_device, seat->pointer_x, seat->pointer_y, &dx, &dy); event = new_absolute_motion_event (input_device, time_us, x, y, axes); _clutter_evdev_event_set_relative_motion (event, dx, dy, 0, 0); queue_event (event); } static void notify_pinch_gesture_event (ClutterInputDevice *input_device, ClutterTouchpadGesturePhase phase, guint64 time_us, gdouble dx, gdouble dy, gdouble angle_delta, gdouble scale, guint n_fingers) { ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event = NULL; ClutterPoint pos; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); event = clutter_event_new (CLUTTER_TOUCHPAD_PINCH); clutter_input_device_get_coords (seat->core_pointer, NULL, &pos); _clutter_evdev_event_set_time_usec (event, time_us); event->touchpad_pinch.phase = phase; event->touchpad_pinch.time = us2ms (time_us); event->touchpad_pinch.stage = CLUTTER_STAGE (stage); event->touchpad_pinch.x = pos.x; event->touchpad_pinch.y = pos.y; event->touchpad_pinch.dx = dx; event->touchpad_pinch.dy = dy; event->touchpad_pinch.angle_delta = angle_delta; event->touchpad_pinch.scale = scale; event->touchpad_pinch.n_fingers = n_fingers; _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); queue_event (event); } static void notify_swipe_gesture_event (ClutterInputDevice *input_device, ClutterTouchpadGesturePhase phase, guint64 time_us, guint n_fingers, gdouble dx, gdouble dy) { ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event = NULL; ClutterPoint pos; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); event = clutter_event_new (CLUTTER_TOUCHPAD_SWIPE); _clutter_evdev_event_set_time_usec (event, time_us); event->touchpad_swipe.phase = phase; event->touchpad_swipe.time = us2ms (time_us); event->touchpad_swipe.stage = CLUTTER_STAGE (stage); clutter_input_device_get_coords (seat->core_pointer, NULL, &pos); event->touchpad_swipe.x = pos.x; event->touchpad_swipe.y = pos.y; event->touchpad_swipe.dx = dx; event->touchpad_swipe.dy = dy; event->touchpad_swipe.n_fingers = n_fingers; _clutter_xkb_translate_state (event, seat->xkb, seat->button_state); clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); queue_event (event); } static void notify_proximity (ClutterInputDevice *input_device, guint64 time_us, gboolean in) { ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event = NULL; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); if (in) event = clutter_event_new (CLUTTER_PROXIMITY_IN); else event = clutter_event_new (CLUTTER_PROXIMITY_OUT); _clutter_evdev_event_set_time_usec (event, time_us); event->proximity.time = us2ms (time_us); event->proximity.stage = CLUTTER_STAGE (stage); event->proximity.device = seat->core_pointer; clutter_event_set_device_tool (event, device_evdev->last_tool); clutter_event_set_device (event, seat->core_pointer); clutter_event_set_source_device (event, input_device); _clutter_input_device_set_stage (seat->core_pointer, stage); queue_event (event); } static void notify_pad_button (ClutterInputDevice *input_device, guint64 time_us, guint32 button, guint32 mode_group, guint32 mode, guint32 pressed) { ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; if (pressed) event = clutter_event_new (CLUTTER_PAD_BUTTON_PRESS); else event = clutter_event_new (CLUTTER_PAD_BUTTON_RELEASE); device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); _clutter_evdev_event_set_time_usec (event, time_us); event->pad_button.stage = stage; event->pad_button.button = button; event->pad_button.group = mode_group; event->pad_button.mode = mode; clutter_event_set_device (event, input_device); clutter_event_set_source_device (event, input_device); clutter_event_set_time (event, us2ms (time_us)); _clutter_input_device_set_stage (seat->core_pointer, stage); queue_event (event); } static void notify_pad_strip (ClutterInputDevice *input_device, guint64 time_us, guint32 strip_number, guint32 strip_source, guint32 mode_group, guint32 mode, gdouble value) { ClutterInputDeviceEvdev *device_evdev; ClutterInputDevicePadSource source; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; if (strip_source == LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER) source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER; else source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); event = clutter_event_new (CLUTTER_PAD_STRIP); _clutter_evdev_event_set_time_usec (event, time_us); event->pad_strip.strip_source = source; event->pad_strip.stage = stage; event->pad_strip.strip_number = strip_number; event->pad_strip.value = value; event->pad_strip.group = mode_group; event->pad_strip.mode = mode; clutter_event_set_device (event, input_device); clutter_event_set_source_device (event, input_device); clutter_event_set_time (event, us2ms (time_us)); _clutter_input_device_set_stage (seat->core_pointer, stage); queue_event (event); } static void notify_pad_ring (ClutterInputDevice *input_device, guint64 time_us, guint32 ring_number, guint32 ring_source, guint32 mode_group, guint32 mode, gdouble angle) { ClutterInputDeviceEvdev *device_evdev; ClutterInputDevicePadSource source; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterEvent *event; /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (input_device); if (stage == NULL) return; if (ring_source == LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER) source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER; else source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); seat = _clutter_input_device_evdev_get_seat (device_evdev); event = clutter_event_new (CLUTTER_PAD_RING); _clutter_evdev_event_set_time_usec (event, time_us); event->pad_ring.ring_source = source; event->pad_ring.stage = stage; event->pad_ring.ring_number = ring_number; event->pad_ring.angle = angle; event->pad_ring.group = mode_group; event->pad_ring.mode = mode; clutter_event_set_device (event, input_device); clutter_event_set_source_device (event, input_device); clutter_event_set_time (event, us2ms (time_us)); _clutter_input_device_set_stage (seat->core_pointer, stage); queue_event (event); } static void dispatch_libinput (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; libinput_dispatch (priv->libinput); process_events (manager_evdev); } static gboolean clutter_event_dispatch (GSource *g_source, GSourceFunc callback, gpointer user_data) { ClutterEventSource *source = (ClutterEventSource *) g_source; ClutterDeviceManagerEvdev *manager_evdev; ClutterEvent *event; _clutter_threads_acquire_lock (); manager_evdev = source->manager_evdev; /* Don't queue more events if we haven't finished handling the previous batch */ if (clutter_events_pending ()) goto queue_event; dispatch_libinput (manager_evdev); queue_event: event = clutter_event_get (); if (event) { ClutterModifierType event_state; ClutterInputDevice *input_device = clutter_event_get_source_device (event); ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device); ClutterSeatEvdev *seat = _clutter_input_device_evdev_get_seat (device_evdev); /* Drop events if we don't have any stage to forward them to */ if (!_clutter_input_device_get_stage (input_device)) goto out; /* forward the event into clutter for emission etc. */ _clutter_stage_queue_event (event->any.stage, event, FALSE); /* update the device states *after* the event */ event_state = seat->button_state | xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_EFFECTIVE); _clutter_input_device_set_state (seat->core_pointer, event_state); _clutter_input_device_set_state (seat->core_keyboard, event_state); } out: _clutter_threads_release_lock (); return TRUE; } static GSourceFuncs event_funcs = { clutter_event_prepare, clutter_event_check, clutter_event_dispatch, NULL }; static ClutterEventSource * clutter_event_source_new (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; GSource *source; ClutterEventSource *event_source; gint fd; source = g_source_new (&event_funcs, sizeof (ClutterEventSource)); event_source = (ClutterEventSource *) source; /* setup the source */ event_source->manager_evdev = manager_evdev; fd = libinput_get_fd (priv->libinput); event_source->event_poll_fd.fd = fd; event_source->event_poll_fd.events = G_IO_IN; /* and finally configure and attach the GSource */ g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); g_source_add_poll (source, &event_source->event_poll_fd); g_source_set_can_recurse (source, TRUE); g_source_attach (source, NULL); return event_source; } static void clutter_event_source_free (ClutterEventSource *source) { GSource *g_source = (GSource *) source; CLUTTER_NOTE (EVENT, "Removing GSource for evdev device manager"); /* ignore the return value of close, it's not like we can do something * about it */ close (source->event_poll_fd.fd); g_source_destroy (g_source); g_source_unref (g_source); } static void evdev_add_device (ClutterDeviceManagerEvdev *manager_evdev, struct libinput_device *libinput_device) { ClutterDeviceManager *manager = (ClutterDeviceManager *) manager_evdev; ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; ClutterInputDeviceType type; struct libinput_seat *libinput_seat; ClutterSeatEvdev *seat; ClutterInputDevice *device; libinput_seat = libinput_device_get_seat (libinput_device); seat = libinput_seat_get_user_data (libinput_seat); if (seat == NULL) { /* Clutter has the notion of global "core" pointers and keyboard devices, * which are located on the main seat. Make whatever seat comes first the * main seat. */ if (priv->main_seat->libinput_seat == NULL) seat = priv->main_seat; else { seat = clutter_seat_evdev_new (manager_evdev); priv->seats = g_slist_append (priv->seats, seat); } clutter_seat_evdev_set_libinput_seat (seat, libinput_seat); } device = _clutter_input_device_evdev_new (manager, seat, libinput_device); _clutter_input_device_set_stage (device, manager_evdev->priv->stage); _clutter_device_manager_add_device (manager, device); /* Clutter assumes that device types are exclusive in the * ClutterInputDevice API */ type = _clutter_input_device_evdev_determine_type (libinput_device); if (type == CLUTTER_KEYBOARD_DEVICE) { _clutter_input_device_set_associated_device (device, seat->core_keyboard); _clutter_input_device_add_slave (seat->core_keyboard, device); } else if (type == CLUTTER_POINTER_DEVICE) { _clutter_input_device_set_associated_device (device, seat->core_pointer); _clutter_input_device_add_slave (seat->core_pointer, device); } CLUTTER_NOTE (EVENT, "Added physical device '%s', type %s", clutter_input_device_get_device_name (device), device_type_str[type]); } static void evdev_remove_device (ClutterDeviceManagerEvdev *manager_evdev, ClutterInputDeviceEvdev *device_evdev) { ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (manager_evdev); ClutterInputDevice *input_device = CLUTTER_INPUT_DEVICE (device_evdev); _clutter_device_manager_remove_device (manager, input_device); } /* * ClutterDeviceManager implementation */ static void clutter_device_manager_evdev_add_device (ClutterDeviceManager *manager, ClutterInputDevice *device) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); priv = manager_evdev->priv; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); seat = _clutter_input_device_evdev_get_seat (device_evdev); seat->devices = g_slist_prepend (seat->devices, device); priv->devices = g_slist_prepend (priv->devices, device); } static void clutter_device_manager_evdev_remove_device (ClutterDeviceManager *manager, ClutterInputDevice *device) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; ClutterInputDeviceEvdev *device_evdev; ClutterSeatEvdev *seat; device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); seat = _clutter_input_device_evdev_get_seat (device_evdev); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); priv = manager_evdev->priv; /* Remove the device */ seat->devices = g_slist_remove (seat->devices, device); priv->devices = g_slist_remove (priv->devices, device); if (seat->repeat_timer && seat->repeat_device == device) clutter_seat_evdev_clear_repeat_timer (seat); g_object_unref (device); } static const GSList * clutter_device_manager_evdev_get_devices (ClutterDeviceManager *manager) { return CLUTTER_DEVICE_MANAGER_EVDEV (manager)->priv->devices; } static ClutterInputDevice * clutter_device_manager_evdev_get_core_device (ClutterDeviceManager *manager, ClutterInputDeviceType type) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); priv = manager_evdev->priv; switch (type) { case CLUTTER_POINTER_DEVICE: return priv->main_seat->core_pointer; case CLUTTER_KEYBOARD_DEVICE: return priv->main_seat->core_keyboard; case CLUTTER_EXTENSION_DEVICE: default: return NULL; } return NULL; } static ClutterInputDevice * clutter_device_manager_evdev_get_device (ClutterDeviceManager *manager, gint id) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; GSList *l; manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); priv = manager_evdev->priv; for (l = priv->seats; l; l = l->next) { ClutterSeatEvdev *seat = l->data; ClutterInputDevice *device = clutter_seat_evdev_get_device (seat, id); if (device) return device; } return NULL; } static void flush_event_queue (void) { ClutterEvent *event; while ((event = clutter_event_get ()) != NULL) { _clutter_process_event (event); clutter_event_free (event); } } static gboolean process_base_event (ClutterDeviceManagerEvdev *manager_evdev, struct libinput_event *event) { ClutterInputDevice *device; struct libinput_device *libinput_device; gboolean handled = TRUE; switch (libinput_event_get_type (event)) { case LIBINPUT_EVENT_DEVICE_ADDED: libinput_device = libinput_event_get_device (event); evdev_add_device (manager_evdev, libinput_device); break; case LIBINPUT_EVENT_DEVICE_REMOVED: /* Flush all queued events, there * might be some from this device. */ flush_event_queue (); libinput_device = libinput_event_get_device (event); device = libinput_device_get_user_data (libinput_device); evdev_remove_device (manager_evdev, CLUTTER_INPUT_DEVICE_EVDEV (device)); break; default: handled = FALSE; } return handled; } static ClutterScrollSource translate_scroll_source (enum libinput_pointer_axis_source source) { switch (source) { case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: return CLUTTER_SCROLL_SOURCE_WHEEL; case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: return CLUTTER_SCROLL_SOURCE_FINGER; case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: return CLUTTER_SCROLL_SOURCE_CONTINUOUS; default: return CLUTTER_SCROLL_SOURCE_UNKNOWN; } } static ClutterInputDeviceToolType translate_tool_type (struct libinput_tablet_tool *libinput_tool) { enum libinput_tablet_tool_type tool; tool = libinput_tablet_tool_get_type (libinput_tool); switch (tool) { case LIBINPUT_TABLET_TOOL_TYPE_PEN: return CLUTTER_INPUT_DEVICE_TOOL_PEN; case LIBINPUT_TABLET_TOOL_TYPE_ERASER: return CLUTTER_INPUT_DEVICE_TOOL_ERASER; case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: return CLUTTER_INPUT_DEVICE_TOOL_BRUSH; case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: return CLUTTER_INPUT_DEVICE_TOOL_PENCIL; case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: return CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH; case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: return CLUTTER_INPUT_DEVICE_TOOL_MOUSE; case LIBINPUT_TABLET_TOOL_TYPE_LENS: return CLUTTER_INPUT_DEVICE_TOOL_LENS; default: return CLUTTER_INPUT_DEVICE_TOOL_NONE; } } static void input_device_update_tool (ClutterInputDevice *input_device, struct libinput_tablet_tool *libinput_tool) { ClutterInputDeviceEvdev *evdev_device = CLUTTER_INPUT_DEVICE_EVDEV (input_device); ClutterInputDeviceTool *tool = NULL; ClutterInputDeviceToolType tool_type; guint64 tool_serial; if (libinput_tool) { tool_serial = libinput_tablet_tool_get_serial (libinput_tool); tool_type = translate_tool_type (libinput_tool); tool = clutter_input_device_lookup_tool (input_device, tool_serial, tool_type); if (!tool) { tool = clutter_input_device_tool_evdev_new (libinput_tool, tool_serial, tool_type); clutter_input_device_add_tool (input_device, tool); } } if (evdev_device->last_tool != tool) { evdev_device->last_tool = tool; g_signal_emit_by_name (clutter_device_manager_get_default (), "tool-changed", input_device, tool); } } static gdouble * translate_tablet_axes (struct libinput_event_tablet_tool *tablet_event, ClutterInputDeviceTool *tool) { GArray *axes = g_array_new (FALSE, FALSE, sizeof (gdouble)); struct libinput_tablet_tool *libinput_tool; gdouble value; libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event); value = libinput_event_tablet_tool_get_x (tablet_event); g_array_append_val (axes, value); value = libinput_event_tablet_tool_get_y (tablet_event); g_array_append_val (axes, value); if (libinput_tablet_tool_has_distance (libinput_tool)) { value = libinput_event_tablet_tool_get_distance (tablet_event); g_array_append_val (axes, value); } if (libinput_tablet_tool_has_pressure (libinput_tool)) { value = libinput_event_tablet_tool_get_pressure (tablet_event); value = clutter_input_device_tool_evdev_translate_pressure (tool, value); g_array_append_val (axes, value); } if (libinput_tablet_tool_has_tilt (libinput_tool)) { value = libinput_event_tablet_tool_get_tilt_x (tablet_event); g_array_append_val (axes, value); value = libinput_event_tablet_tool_get_tilt_y (tablet_event); g_array_append_val (axes, value); } if (libinput_tablet_tool_has_rotation (libinput_tool)) { value = libinput_event_tablet_tool_get_rotation (tablet_event); g_array_append_val (axes, value); } if (libinput_tablet_tool_has_slider (libinput_tool)) { value = libinput_event_tablet_tool_get_slider_position (tablet_event); g_array_append_val (axes, value); } if (libinput_tablet_tool_has_wheel (libinput_tool)) { value = libinput_event_tablet_tool_get_wheel_delta (tablet_event); g_array_append_val (axes, value); } if (axes->len == 0) { g_array_free (axes, TRUE); return NULL; } else return (gdouble *) g_array_free (axes, FALSE); } static ClutterSeatEvdev * seat_from_device (ClutterInputDevice *device) { ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); return _clutter_input_device_evdev_get_seat (device_evdev); } static void notify_continuous_axis (ClutterSeatEvdev *seat, ClutterInputDevice *device, uint64_t time_us, ClutterScrollSource scroll_source, struct libinput_event_pointer *axis_event) { gdouble dx = 0.0, dy = 0.0; ClutterScrollFinishFlags finish_flags = CLUTTER_SCROLL_FINISHED_NONE; if (libinput_event_pointer_has_axis (axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { dx = libinput_event_pointer_get_axis_value ( axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); if (fabs (dx) < DBL_EPSILON) finish_flags |= CLUTTER_SCROLL_FINISHED_HORIZONTAL; } if (libinput_event_pointer_has_axis (axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { dy = libinput_event_pointer_get_axis_value ( axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); if (fabs (dy) < DBL_EPSILON) finish_flags |= CLUTTER_SCROLL_FINISHED_VERTICAL; } clutter_seat_evdev_notify_scroll_continuous (seat, device, time_us, dx, dy, scroll_source, finish_flags); } static void notify_discrete_axis (ClutterSeatEvdev *seat, ClutterInputDevice *device, uint64_t time_us, ClutterScrollSource scroll_source, struct libinput_event_pointer *axis_event) { gdouble discrete_dx = 0.0, discrete_dy = 0.0; if (libinput_event_pointer_has_axis (axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { discrete_dx = libinput_event_pointer_get_axis_value_discrete ( axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); } if (libinput_event_pointer_has_axis (axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { discrete_dy = libinput_event_pointer_get_axis_value_discrete ( axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); } clutter_seat_evdev_notify_discrete_scroll (seat, device, time_us, discrete_dx, discrete_dy, scroll_source); } static gboolean process_device_event (ClutterDeviceManagerEvdev *manager_evdev, struct libinput_event *event) { gboolean handled = TRUE; struct libinput_device *libinput_device = libinput_event_get_device(event); ClutterInputDevice *device; ClutterInputDeviceEvdev *device_evdev; switch (libinput_event_get_type (event)) { case LIBINPUT_EVENT_KEYBOARD_KEY: { guint32 key, key_state, seat_key_count; guint64 time_us; struct libinput_event_keyboard *key_event = libinput_event_get_keyboard_event (event); device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_keyboard_get_time_usec (key_event); key = libinput_event_keyboard_get_key (key_event); key_state = libinput_event_keyboard_get_key_state (key_event) == LIBINPUT_KEY_STATE_PRESSED; seat_key_count = libinput_event_keyboard_get_seat_key_count (key_event); /* Ignore key events that are not seat wide state changes. */ if ((key_state == LIBINPUT_KEY_STATE_PRESSED && seat_key_count != 1) || (key_state == LIBINPUT_KEY_STATE_RELEASED && seat_key_count != 0)) break; clutter_seat_evdev_notify_key (seat_from_device (device), device, time_us, key, key_state, TRUE); break; } case LIBINPUT_EVENT_POINTER_MOTION: { struct libinput_event_pointer *pointer_event = libinput_event_get_pointer_event (event); uint64_t time_us; double dx; double dy; double dx_unaccel; double dy_unaccel; device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_pointer_get_time_usec (pointer_event); dx = libinput_event_pointer_get_dx (pointer_event); dy = libinput_event_pointer_get_dy (pointer_event); dx_unaccel = libinput_event_pointer_get_dx_unaccelerated (pointer_event); dy_unaccel = libinput_event_pointer_get_dy_unaccelerated (pointer_event); clutter_seat_evdev_notify_relative_motion (seat_from_device (device), device, time_us, dx, dy, dx_unaccel, dy_unaccel); break; } case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: { guint64 time_us; double x, y; gfloat stage_width, stage_height; ClutterStage *stage; struct libinput_event_pointer *motion_event = libinput_event_get_pointer_event (event); device = libinput_device_get_user_data (libinput_device); stage = _clutter_input_device_get_stage (device); if (stage == NULL) break; stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); time_us = libinput_event_pointer_get_time_usec (motion_event); x = libinput_event_pointer_get_absolute_x_transformed (motion_event, stage_width); y = libinput_event_pointer_get_absolute_y_transformed (motion_event, stage_height); clutter_seat_evdev_notify_absolute_motion (seat_from_device (device), device, time_us, x, y, NULL); break; } case LIBINPUT_EVENT_POINTER_BUTTON: { guint32 button, button_state, seat_button_count; guint64 time_us; struct libinput_event_pointer *button_event = libinput_event_get_pointer_event (event); device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_pointer_get_time_usec (button_event); button = libinput_event_pointer_get_button (button_event); button_state = libinput_event_pointer_get_button_state (button_event) == LIBINPUT_BUTTON_STATE_PRESSED; seat_button_count = libinput_event_pointer_get_seat_button_count (button_event); /* Ignore button events that are not seat wide state changes. */ if ((button_state == LIBINPUT_BUTTON_STATE_PRESSED && seat_button_count != 1) || (button_state == LIBINPUT_BUTTON_STATE_RELEASED && seat_button_count != 0)) break; clutter_seat_evdev_notify_button (seat_from_device (device), device, time_us, button, button_state); break; } case LIBINPUT_EVENT_POINTER_AXIS: { guint64 time_us; enum libinput_pointer_axis_source source; struct libinput_event_pointer *axis_event = libinput_event_get_pointer_event (event); ClutterSeatEvdev *seat; ClutterScrollSource scroll_source; device = libinput_device_get_user_data (libinput_device); seat = _clutter_input_device_evdev_get_seat (CLUTTER_INPUT_DEVICE_EVDEV (device)); time_us = libinput_event_pointer_get_time_usec (axis_event); source = libinput_event_pointer_get_axis_source (axis_event); scroll_source = translate_scroll_source (source); /* libinput < 0.8 sent wheel click events with value 10. Since 0.8 the value is the angle of the click in degrees. To keep backwards-compat with existing clients, we just send multiples of the click count. */ switch (scroll_source) { case CLUTTER_SCROLL_SOURCE_WHEEL: notify_discrete_axis (seat, device, time_us, scroll_source, axis_event); break; case CLUTTER_SCROLL_SOURCE_FINGER: case CLUTTER_SCROLL_SOURCE_CONTINUOUS: case CLUTTER_SCROLL_SOURCE_UNKNOWN: notify_continuous_axis (seat, device, time_us, scroll_source, axis_event); break; } break; } case LIBINPUT_EVENT_TOUCH_DOWN: { int device_slot; guint64 time_us; double x, y; gfloat stage_width, stage_height; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterTouchState *touch_state; struct libinput_event_touch *touch_event = libinput_event_get_touch_event (event); device = libinput_device_get_user_data (libinput_device); device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); seat = _clutter_input_device_evdev_get_seat (device_evdev); stage = _clutter_input_device_get_stage (device); if (stage == NULL) break; stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); device_slot = libinput_event_touch_get_slot (touch_event); time_us = libinput_event_touch_get_time_usec (touch_event); x = libinput_event_touch_get_x_transformed (touch_event, stage_width); y = libinput_event_touch_get_y_transformed (touch_event, stage_height); touch_state = clutter_input_device_evdev_acquire_touch_state (device_evdev, device_slot); touch_state->coords.x = x; touch_state->coords.y = y; clutter_seat_evdev_notify_touch_event (seat, device, CLUTTER_TOUCH_BEGIN, time_us, touch_state->seat_slot, touch_state->coords.x, touch_state->coords.y); break; } case LIBINPUT_EVENT_TOUCH_UP: { int device_slot; guint64 time_us; ClutterSeatEvdev *seat; ClutterTouchState *touch_state; struct libinput_event_touch *touch_event = libinput_event_get_touch_event (event); device = libinput_device_get_user_data (libinput_device); device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); seat = _clutter_input_device_evdev_get_seat (device_evdev); device_slot = libinput_event_touch_get_slot (touch_event); time_us = libinput_event_touch_get_time_usec (touch_event); touch_state = clutter_input_device_evdev_lookup_touch_state (device_evdev, device_slot); if (!touch_state) break; clutter_seat_evdev_notify_touch_event (seat, device, CLUTTER_TOUCH_END, time_us, touch_state->seat_slot, touch_state->coords.x, touch_state->coords.y); clutter_input_device_evdev_release_touch_state (device_evdev, touch_state); break; } case LIBINPUT_EVENT_TOUCH_MOTION: { int device_slot; guint64 time_us; double x, y; gfloat stage_width, stage_height; ClutterSeatEvdev *seat; ClutterStage *stage; ClutterTouchState *touch_state; struct libinput_event_touch *touch_event = libinput_event_get_touch_event (event); device = libinput_device_get_user_data (libinput_device); device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); seat = _clutter_input_device_evdev_get_seat (device_evdev); stage = _clutter_input_device_get_stage (device); if (stage == NULL) break; stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); device_slot = libinput_event_touch_get_slot (touch_event); time_us = libinput_event_touch_get_time_usec (touch_event); x = libinput_event_touch_get_x_transformed (touch_event, stage_width); y = libinput_event_touch_get_y_transformed (touch_event, stage_height); touch_state = clutter_input_device_evdev_lookup_touch_state (device_evdev, device_slot); if (!touch_state) break; touch_state->coords.x = x; touch_state->coords.y = y; clutter_seat_evdev_notify_touch_event (seat, device, CLUTTER_TOUCH_UPDATE, time_us, touch_state->seat_slot, touch_state->coords.x, touch_state->coords.y); break; } case LIBINPUT_EVENT_TOUCH_CANCEL: { guint64 time_us; struct libinput_event_touch *touch_event = libinput_event_get_touch_event (event); device = libinput_device_get_user_data (libinput_device); device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); time_us = libinput_event_touch_get_time_usec (touch_event); clutter_input_device_evdev_release_touch_slots (device_evdev, time_us); break; } case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: case LIBINPUT_EVENT_GESTURE_PINCH_END: { struct libinput_event_gesture *gesture_event = libinput_event_get_gesture_event (event); ClutterTouchpadGesturePhase phase; guint n_fingers; guint64 time_us; if (libinput_event_get_type (event) == LIBINPUT_EVENT_GESTURE_PINCH_BEGIN) phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN; else phase = libinput_event_gesture_get_cancelled (gesture_event) ? CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL : CLUTTER_TOUCHPAD_GESTURE_PHASE_END; n_fingers = libinput_event_gesture_get_finger_count (gesture_event); device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_gesture_get_time_usec (gesture_event); notify_pinch_gesture_event (device, phase, time_us, 0, 0, 0, 0, n_fingers); break; } case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: { struct libinput_event_gesture *gesture_event = libinput_event_get_gesture_event (event); gdouble angle_delta, scale, dx, dy; guint n_fingers; guint64 time_us; n_fingers = libinput_event_gesture_get_finger_count (gesture_event); device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_gesture_get_time_usec (gesture_event); angle_delta = libinput_event_gesture_get_angle_delta (gesture_event); scale = libinput_event_gesture_get_scale (gesture_event); dx = libinput_event_gesture_get_dx (gesture_event); dy = libinput_event_gesture_get_dx (gesture_event); notify_pinch_gesture_event (device, CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE, time_us, dx, dy, angle_delta, scale, n_fingers); break; } case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: case LIBINPUT_EVENT_GESTURE_SWIPE_END: { struct libinput_event_gesture *gesture_event = libinput_event_get_gesture_event (event); ClutterTouchpadGesturePhase phase; guint32 n_fingers; guint64 time_us; device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_gesture_get_time_usec (gesture_event); n_fingers = libinput_event_gesture_get_finger_count (gesture_event); if (libinput_event_get_type (event) == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN) phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN; else phase = libinput_event_gesture_get_cancelled (gesture_event) ? CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL : CLUTTER_TOUCHPAD_GESTURE_PHASE_END; notify_swipe_gesture_event (device, phase, time_us, n_fingers, 0, 0); break; } case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: { struct libinput_event_gesture *gesture_event = libinput_event_get_gesture_event (event); guint32 n_fingers; guint64 time_us; gdouble dx, dy; device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_gesture_get_time_usec (gesture_event); n_fingers = libinput_event_gesture_get_finger_count (gesture_event); dx = libinput_event_gesture_get_dx (gesture_event); dy = libinput_event_gesture_get_dy (gesture_event); notify_swipe_gesture_event (device, CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE, time_us, n_fingers, dx, dy); break; } case LIBINPUT_EVENT_TABLET_TOOL_AXIS: { guint64 time; double x, y, dx, dy, *axes; gfloat stage_width, stage_height; ClutterStage *stage; struct libinput_event_tablet_tool *tablet_event = libinput_event_get_tablet_tool_event (event); ClutterInputDeviceEvdev *evdev_device; device = libinput_device_get_user_data (libinput_device); evdev_device = CLUTTER_INPUT_DEVICE_EVDEV (device); stage = _clutter_input_device_get_stage (device); if (!stage) break; axes = translate_tablet_axes (tablet_event, evdev_device->last_tool); if (!axes) break; stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); time = libinput_event_tablet_tool_get_time_usec (tablet_event); if (clutter_input_device_get_mapping_mode (device) == CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE || clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_MOUSE || clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_LENS) { dx = libinput_event_tablet_tool_get_dx (tablet_event); dy = libinput_event_tablet_tool_get_dy (tablet_event); notify_relative_tool_motion (device, time, dx, dy, axes); } else { x = libinput_event_tablet_tool_get_x_transformed (tablet_event, stage_width); y = libinput_event_tablet_tool_get_y_transformed (tablet_event, stage_height); notify_absolute_motion (device, time, x, y, axes); } break; } case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: { guint64 time; struct libinput_event_tablet_tool *tablet_event = libinput_event_get_tablet_tool_event (event); struct libinput_tablet_tool *libinput_tool = NULL; enum libinput_tablet_tool_proximity_state state; state = libinput_event_tablet_tool_get_proximity_state (tablet_event); time = libinput_event_tablet_tool_get_time_usec (tablet_event); device = libinput_device_get_user_data (libinput_device); libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event); if (state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) input_device_update_tool (device, libinput_tool); notify_proximity (device, time, state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN); if (state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) input_device_update_tool (device, NULL); break; } case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: { guint64 time_us; guint32 button_state; struct libinput_event_tablet_tool *tablet_event = libinput_event_get_tablet_tool_event (event); guint tablet_button; device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_tablet_tool_get_time_usec (tablet_event); tablet_button = libinput_event_tablet_tool_get_button (tablet_event); button_state = libinput_event_tablet_tool_get_button_state (tablet_event) == LIBINPUT_BUTTON_STATE_PRESSED; clutter_seat_evdev_notify_button (seat_from_device (device), device, time_us, tablet_button, button_state); break; } case LIBINPUT_EVENT_TABLET_TOOL_TIP: { guint64 time_us; guint32 button_state; struct libinput_event_tablet_tool *tablet_event = libinput_event_get_tablet_tool_event (event); device = libinput_device_get_user_data (libinput_device); time_us = libinput_event_tablet_tool_get_time_usec (tablet_event); button_state = libinput_event_tablet_tool_get_tip_state (tablet_event) == LIBINPUT_TABLET_TOOL_TIP_DOWN; clutter_seat_evdev_notify_button (seat_from_device (device), device, time_us, BTN_TOUCH, button_state); break; } case LIBINPUT_EVENT_TABLET_PAD_BUTTON: { guint64 time; guint32 button_state, button, group, mode; struct libinput_tablet_pad_mode_group *mode_group; struct libinput_event_tablet_pad *pad_event = libinput_event_get_tablet_pad_event (event); device = libinput_device_get_user_data (libinput_device); time = libinput_event_tablet_pad_get_time_usec (pad_event); mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); group = libinput_tablet_pad_mode_group_get_index (mode_group); mode = libinput_event_tablet_pad_get_mode (pad_event); button = libinput_event_tablet_pad_get_button_number (pad_event); button_state = libinput_event_tablet_pad_get_button_state (pad_event) == LIBINPUT_BUTTON_STATE_PRESSED; notify_pad_button (device, time, button, group, mode, button_state); break; } case LIBINPUT_EVENT_TABLET_PAD_STRIP: { guint64 time; guint32 number, source, group, mode; struct libinput_tablet_pad_mode_group *mode_group; struct libinput_event_tablet_pad *pad_event = libinput_event_get_tablet_pad_event (event); gdouble value; device = libinput_device_get_user_data (libinput_device); time = libinput_event_tablet_pad_get_time_usec (pad_event); number = libinput_event_tablet_pad_get_strip_number (pad_event); value = libinput_event_tablet_pad_get_strip_position (pad_event); source = libinput_event_tablet_pad_get_strip_source (pad_event); mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); group = libinput_tablet_pad_mode_group_get_index (mode_group); mode = libinput_event_tablet_pad_get_mode (pad_event); notify_pad_strip (device, time, number, source, group, mode, value); break; } case LIBINPUT_EVENT_TABLET_PAD_RING: { guint64 time; guint32 number, source, group, mode; struct libinput_tablet_pad_mode_group *mode_group; struct libinput_event_tablet_pad *pad_event = libinput_event_get_tablet_pad_event (event); gdouble angle; device = libinput_device_get_user_data (libinput_device); time = libinput_event_tablet_pad_get_time_usec (pad_event); number = libinput_event_tablet_pad_get_ring_number (pad_event); angle = libinput_event_tablet_pad_get_ring_position (pad_event); source = libinput_event_tablet_pad_get_ring_source (pad_event); mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); group = libinput_tablet_pad_mode_group_get_index (mode_group); mode = libinput_event_tablet_pad_get_mode (pad_event); notify_pad_ring (device, time, number, source, group, mode, angle); break; } default: handled = FALSE; } return handled; } static gboolean filter_event (ClutterDeviceManagerEvdev *manager_evdev, struct libinput_event *event) { gboolean retval = CLUTTER_EVENT_PROPAGATE; ClutterEventFilter *filter; GSList *tmp_list; tmp_list = manager_evdev->priv->event_filters; while (tmp_list) { filter = tmp_list->data; retval = filter->func (event, filter->data); tmp_list = tmp_list->next; if (retval != CLUTTER_EVENT_PROPAGATE) break; } return retval; } static void process_event (ClutterDeviceManagerEvdev *manager_evdev, struct libinput_event *event) { gboolean retval; retval = filter_event (manager_evdev, event); if (retval != CLUTTER_EVENT_PROPAGATE) return; if (process_base_event (manager_evdev, event)) return; if (process_device_event (manager_evdev, event)) return; } static void process_events (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; struct libinput_event *event; while ((event = libinput_get_event (priv->libinput))) { process_event(manager_evdev, event); libinput_event_destroy(event); } } static int open_restricted (const char *path, int flags, void *user_data) { gint fd; if (device_open_callback) { GError *error = NULL; fd = device_open_callback (path, flags, device_callback_data, &error); if (fd < 0) { g_warning ("Could not open device %s: %s", path, error->message); g_error_free (error); } } else { fd = open (path, O_RDWR | O_NONBLOCK); if (fd < 0) { g_warning ("Could not open device %s: %s", path, strerror (errno)); } } return fd; } static void close_restricted (int fd, void *user_data) { if (device_close_callback) device_close_callback (fd, device_callback_data); else close (fd); } static const struct libinput_interface libinput_interface = { open_restricted, close_restricted }; static ClutterVirtualInputDevice * clutter_device_manager_evdev_create_virtual_device (ClutterDeviceManager *manager, ClutterInputDeviceType device_type) { ClutterDeviceManagerEvdev *manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; return g_object_new (CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_EVDEV, "device-manager", manager, "seat", priv->main_seat, "device-type", device_type, NULL); } static ClutterVirtualDeviceType clutter_device_manager_evdev_get_supported_virtual_device_types (ClutterDeviceManager *device_manager) { return (CLUTTER_VIRTUAL_DEVICE_TYPE_KEYBOARD | CLUTTER_VIRTUAL_DEVICE_TYPE_POINTER | CLUTTER_VIRTUAL_DEVICE_TYPE_TOUCHSCREEN); } static void clutter_device_manager_evdev_compress_motion (ClutterDeviceManager *device_manger, ClutterEvent *event, const ClutterEvent *to_discard) { double dx, dy; double dx_unaccel, dy_unaccel; double dst_dx = 0.0, dst_dy = 0.0; double dst_dx_unaccel = 0.0, dst_dy_unaccel = 0.0; if (!clutter_evdev_event_get_relative_motion (to_discard, &dx, &dy, &dx_unaccel, &dy_unaccel)) return; clutter_evdev_event_get_relative_motion (event, &dst_dx, &dst_dy, &dst_dx_unaccel, &dst_dy_unaccel); _clutter_evdev_event_set_relative_motion (event, dx + dst_dx, dy + dst_dy, dx_unaccel + dst_dx_unaccel, dy_unaccel + dst_dy_unaccel); } static void clutter_device_manager_evdev_apply_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *settings) { ClutterInputDevice *device; device = clutter_device_manager_evdev_get_core_device (device_manager, CLUTTER_KEYBOARD_DEVICE); if (device) clutter_input_device_evdev_apply_kbd_a11y_settings (CLUTTER_INPUT_DEVICE_EVDEV (device), settings); } /* * GObject implementation */ static void clutter_device_manager_evdev_constructed (GObject *gobject) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; ClutterEventSource *source; struct udev *udev; struct xkb_context *ctx; struct xkb_rule_names names; udev = udev_new (); if (G_UNLIKELY (udev == NULL)) { g_warning ("Failed to create udev object"); return; } manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (gobject); priv = manager_evdev->priv; priv->libinput = libinput_udev_create_context (&libinput_interface, manager_evdev, udev); if (priv->libinput == NULL) { g_critical ("Failed to create the libinput object."); return; } if (libinput_udev_assign_seat (priv->libinput, evdev_seat_id ? evdev_seat_id : "seat0") == -1) { g_critical ("Failed to assign a seat to the libinput object."); libinput_unref (priv->libinput); priv->libinput = NULL; return; } udev_unref (udev); names.rules = "evdev"; names.model = "pc105"; names.layout = option_xkb_layout; names.variant = option_xkb_variant; names.options = option_xkb_options; ctx = xkb_context_new (0); g_assert (ctx); priv->keymap = xkb_keymap_new_from_names (ctx, &names, 0); xkb_context_unref (ctx); priv->main_seat = clutter_seat_evdev_new (manager_evdev); priv->seats = g_slist_append (priv->seats, priv->main_seat); dispatch_libinput (manager_evdev); source = clutter_event_source_new (manager_evdev); priv->event_source = source; } static void clutter_device_manager_evdev_dispose (GObject *object) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (object); priv = manager_evdev->priv; if (priv->stage_added_handler) { g_signal_handler_disconnect (priv->stage_manager, priv->stage_added_handler); priv->stage_added_handler = 0; } if (priv->stage_removed_handler) { g_signal_handler_disconnect (priv->stage_manager, priv->stage_removed_handler); priv->stage_removed_handler = 0; } if (priv->stage_manager) { g_object_unref (priv->stage_manager); priv->stage_manager = NULL; } G_OBJECT_CLASS (clutter_device_manager_evdev_parent_class)->dispose (object); } static void clutter_device_manager_evdev_finalize (GObject *object) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (object); priv = manager_evdev->priv; g_slist_free_full (priv->seats, (GDestroyNotify) clutter_seat_evdev_free); g_slist_free (priv->devices); if (priv->keymap) xkb_keymap_unref (priv->keymap); if (priv->event_source != NULL) clutter_event_source_free (priv->event_source); if (priv->constrain_data_notify != NULL) priv->constrain_data_notify (priv->constrain_data); if (priv->libinput != NULL) libinput_unref (priv->libinput); g_list_free (priv->free_device_ids); G_OBJECT_CLASS (clutter_device_manager_evdev_parent_class)->finalize (object); } static void clutter_device_manager_evdev_class_init (ClutterDeviceManagerEvdevClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterDeviceManagerClass *manager_class; gobject_class->constructed = clutter_device_manager_evdev_constructed; gobject_class->finalize = clutter_device_manager_evdev_finalize; gobject_class->dispose = clutter_device_manager_evdev_dispose; manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass); manager_class->add_device = clutter_device_manager_evdev_add_device; manager_class->remove_device = clutter_device_manager_evdev_remove_device; manager_class->get_devices = clutter_device_manager_evdev_get_devices; manager_class->get_core_device = clutter_device_manager_evdev_get_core_device; manager_class->get_device = clutter_device_manager_evdev_get_device; manager_class->create_virtual_device = clutter_device_manager_evdev_create_virtual_device; manager_class->get_supported_virtual_device_types = clutter_device_manager_evdev_get_supported_virtual_device_types; manager_class->compress_motion = clutter_device_manager_evdev_compress_motion; manager_class->apply_kbd_a11y_settings = clutter_device_manager_evdev_apply_kbd_a11y_settings; } static void clutter_device_manager_evdev_stage_added_cb (ClutterStageManager *manager, ClutterStage *stage, ClutterDeviceManagerEvdev *self) { ClutterDeviceManagerEvdevPrivate *priv = self->priv; GSList *l; /* NB: Currently we can only associate a single stage with all evdev * devices. * * We save a pointer to the stage so if we release/reclaim input * devices due to switching virtual terminals then we know what * stage to re associate the devices with. */ priv->stage = stage; /* Set the stage of any devices that don't already have a stage */ for (l = priv->seats; l; l = l->next) { ClutterSeatEvdev *seat = l->data; clutter_seat_evdev_set_stage (seat, stage); } /* We only want to do this once so we can catch the default stage. If the application has multiple stages then it will need to manage the stage of the input devices itself */ g_signal_handler_disconnect (priv->stage_manager, priv->stage_added_handler); priv->stage_added_handler = 0; } static void clutter_device_manager_evdev_stage_removed_cb (ClutterStageManager *manager, ClutterStage *stage, ClutterDeviceManagerEvdev *self) { ClutterDeviceManagerEvdevPrivate *priv = self->priv; GSList *l; /* Remove the stage of any input devices that were pointing to this stage so we don't send events to invalid stages */ for (l = priv->seats; l; l = l->next) { ClutterSeatEvdev *seat = l->data; clutter_seat_evdev_set_stage (seat, NULL); } } static void clutter_device_manager_evdev_init (ClutterDeviceManagerEvdev *self) { ClutterDeviceManagerEvdevPrivate *priv; priv = self->priv = clutter_device_manager_evdev_get_instance_private (self); priv->stage_manager = clutter_stage_manager_get_default (); g_object_ref (priv->stage_manager); /* evdev doesn't have any way to link an event to a particular stage so we'll have to leave it up to applications to set the corresponding stage for an input device. However to make it easier for applications that are only using one fullscreen stage (which is probably the most frequent use-case for the evdev backend) we'll associate any input devices that don't have a stage with the first stage created. */ priv->stage_added_handler = g_signal_connect (priv->stage_manager, "stage-added", G_CALLBACK (clutter_device_manager_evdev_stage_added_cb), self); priv->stage_removed_handler = g_signal_connect (priv->stage_manager, "stage-removed", G_CALLBACK (clutter_device_manager_evdev_stage_removed_cb), self); priv->device_id_next = INITIAL_DEVICE_ID; } void _clutter_events_evdev_init (ClutterBackend *backend) { CLUTTER_NOTE (EVENT, "Initializing evdev backend"); backend->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_EVDEV, "backend", backend, NULL); } void _clutter_events_evdev_uninit (ClutterBackend *backend) { CLUTTER_NOTE (EVENT, "Uninitializing evdev backend"); } gint _clutter_device_manager_evdev_acquire_device_id (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; GList *first; gint next_id; if (priv->free_device_ids == NULL) { gint i; /* We ran out of free ID's, so append 10 new ones. */ for (i = 0; i < 10; i++) priv->free_device_ids = g_list_append (priv->free_device_ids, GINT_TO_POINTER (priv->device_id_next++)); } first = g_list_first (priv->free_device_ids); next_id = GPOINTER_TO_INT (first->data); priv->free_device_ids = g_list_delete_link (priv->free_device_ids, first); return next_id; } void _clutter_device_manager_evdev_dispatch (ClutterDeviceManagerEvdev *manager_evdev) { dispatch_libinput (manager_evdev); } static int compare_ids (gconstpointer a, gconstpointer b) { return GPOINTER_TO_INT (a) - GPOINTER_TO_INT (b); } void _clutter_device_manager_evdev_release_device_id (ClutterDeviceManagerEvdev *manager_evdev, ClutterInputDevice *device) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; gint device_id; device_id = clutter_input_device_get_device_id (device); priv->free_device_ids = g_list_insert_sorted (priv->free_device_ids, GINT_TO_POINTER (device_id), compare_ids); } struct xkb_keymap * _clutter_device_manager_evdev_get_keymap (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; return priv->keymap; } ClutterStage * _clutter_device_manager_evdev_get_stage (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; return priv->stage; } /** * clutter_evdev_release_devices: * * Releases all the evdev devices that Clutter is currently managing. This api * is typically used when switching away from the Clutter application when * switching tty. The devices can be reclaimed later with a call to * clutter_evdev_reclaim_devices(). * * This function should only be called after clutter has been initialized. * * Since: 1.10 * Stability: unstable */ void clutter_evdev_release_devices (void) { ClutterDeviceManager *manager = clutter_device_manager_get_default (); ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; if (!manager) { g_warning ("clutter_evdev_release_devices shouldn't be called " "before clutter_init()"); return; } g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (manager)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); priv = manager_evdev->priv; if (priv->released) { g_warning ("clutter_evdev_release_devices() shouldn't be called " "multiple times without a corresponding call to " "clutter_evdev_reclaim_devices() first"); return; } libinput_suspend (priv->libinput); process_events (manager_evdev); priv->released = TRUE; } static void clutter_evdev_update_xkb_state (ClutterDeviceManagerEvdev *manager_evdev) { ClutterDeviceManagerEvdevPrivate *priv; GSList *iter; ClutterSeatEvdev *seat; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; priv = manager_evdev->priv; for (iter = priv->seats; iter; iter = iter->next) { seat = iter->data; latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); xkb_state_unref (seat->xkb); seat->xkb = xkb_state_new (priv->keymap); xkb_state_update_mask (seat->xkb, 0, /* depressed */ latched_mods, locked_mods, 0, 0, seat->layout_idx); seat->caps_lock_led = xkb_keymap_led_get_index (priv->keymap, XKB_LED_NAME_CAPS); seat->num_lock_led = xkb_keymap_led_get_index (priv->keymap, XKB_LED_NAME_NUM); seat->scroll_lock_led = xkb_keymap_led_get_index (priv->keymap, XKB_LED_NAME_SCROLL); clutter_seat_evdev_sync_leds (seat); } } /** * clutter_evdev_reclaim_devices: * * This causes Clutter to re-probe for evdev devices. This is must only be * called after a corresponding call to clutter_evdev_release_devices() * was previously used to release all evdev devices. This API is typically * used when a clutter application using evdev has regained focus due to * switching ttys. * * This function should only be called after clutter has been initialized. * * Since: 1.10 * Stability: unstable */ void clutter_evdev_reclaim_devices (void) { ClutterDeviceManager *manager = clutter_device_manager_get_default (); ClutterDeviceManagerEvdev *manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; if (!priv->released) { g_warning ("Spurious call to clutter_evdev_reclaim_devices() without " "previous call to clutter_evdev_release_devices"); return; } libinput_resume (priv->libinput); clutter_evdev_update_xkb_state (manager_evdev); process_events (manager_evdev); priv->released = FALSE; } /** * clutter_evdev_set_device_callbacks: (skip) * @open_callback: the user replacement for open() * @close_callback: the user replacement for close() * @user_data: user data for @callback * * Through this function, the application can set a custom callback * to invoked when Clutter is about to open an evdev device. It can do * so if special handling is needed, for example to circumvent permission * problems. * * Setting @callback to %NULL will reset the default behavior. * * For reliable effects, this function must be called before clutter_init(). * * Since: 1.16 * Stability: unstable */ void clutter_evdev_set_device_callbacks (ClutterOpenDeviceCallback open_callback, ClutterCloseDeviceCallback close_callback, gpointer user_data) { device_open_callback = open_callback; device_close_callback = close_callback; device_callback_data = user_data; } /** * clutter_evdev_set_keyboard_map: (skip) * @evdev: the #ClutterDeviceManager created by the evdev backend * @keymap: the new keymap * * Instructs @evdev to use the speficied keyboard map. This will cause * the backend to drop the state and create a new one with the new * map. To avoid state being lost, callers should ensure that no key * is pressed when calling this function. * * Since: 1.16 * Stability: unstable */ void clutter_evdev_set_keyboard_map (ClutterDeviceManager *evdev, struct xkb_keymap *keymap) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); priv = manager_evdev->priv; if (priv->keymap) xkb_keymap_unref (priv->keymap); priv->keymap = xkb_keymap_ref (keymap); clutter_evdev_update_xkb_state (manager_evdev); } /** * clutter_evdev_get_keyboard_map: (skip) * @evdev: the #ClutterDeviceManager created by the evdev backend * * Retrieves the #xkb_keymap in use by the evdev backend. * * Return value: the #xkb_keymap. * * Since: 1.18 * Stability: unstable */ struct xkb_keymap * clutter_evdev_get_keyboard_map (ClutterDeviceManager *evdev) { ClutterDeviceManagerEvdev *manager_evdev; g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev), NULL); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); return xkb_state_get_keymap (manager_evdev->priv->main_seat->xkb); } /** * clutter_evdev_set_keyboard_layout_index: (skip) * @evdev: the #ClutterDeviceManager created by the evdev backend * @idx: the xkb layout index to set * * Sets the xkb layout index on the backend's #xkb_state . * * Since: 1.20 * Stability: unstable */ void clutter_evdev_set_keyboard_layout_index (ClutterDeviceManager *evdev, xkb_layout_index_t idx) { ClutterDeviceManagerEvdev *manager_evdev; xkb_mod_mask_t depressed_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; struct xkb_state *state; GSList *l; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); state = manager_evdev->priv->main_seat->xkb; depressed_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED); latched_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED); locked_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED); xkb_state_update_mask (state, depressed_mods, latched_mods, locked_mods, 0, 0, idx); for (l = manager_evdev->priv->seats; l; l = l->next) { ClutterSeatEvdev *seat = l->data; seat->layout_idx = idx; } } /** * clutter_evdev_get_keyboard_layout_index: (skip) */ xkb_layout_index_t clutter_evdev_get_keyboard_layout_index (ClutterDeviceManager *evdev) { ClutterDeviceManagerEvdev *manager_evdev; manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); return manager_evdev->priv->main_seat->layout_idx; } /** * clutter_evdev_set_keyboard_numlock: (skip) * @evdev: the #ClutterDeviceManager created by the evdev backend * @numlock_set: TRUE to set NumLock ON, FALSE otherwise. * * Sets the NumLock state on the backend's #xkb_state . * * Stability: unstable */ void clutter_evdev_set_keyboard_numlock (ClutterDeviceManager *evdev, gboolean numlock_state) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; GSList *iter; xkb_mod_mask_t numlock; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); priv = manager_evdev->priv; numlock = (1 << xkb_keymap_mod_get_index(priv->keymap, "Mod2")); for (iter = priv->seats; iter; iter = iter->next) { ClutterSeatEvdev *seat = iter->data; xkb_mod_mask_t depressed_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; xkb_mod_mask_t group_mods; depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); group_mods = xkb_state_serialize_layout (seat->xkb, XKB_STATE_LAYOUT_EFFECTIVE); if (numlock_state) locked_mods |= numlock; else locked_mods &= ~numlock; xkb_state_update_mask (seat->xkb, depressed_mods, latched_mods, locked_mods, 0, 0, group_mods); clutter_seat_evdev_sync_leds (seat); } } /** * clutter_evdev_set_pointer_constrain_callback: * @evdev: the #ClutterDeviceManager created by the evdev backend * @callback: the callback * @user_data: data to pass to the callback * @user_data_notify: function to be called when removing the callback * * Sets a callback to be invoked for every pointer motion. The callback * can then modify the new pointer coordinates to constrain movement within * a specific region. * * Since: 1.16 * Stability: unstable */ void clutter_evdev_set_pointer_constrain_callback (ClutterDeviceManager *evdev, ClutterPointerConstrainCallback callback, gpointer user_data, GDestroyNotify user_data_notify) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); priv = manager_evdev->priv; if (priv->constrain_data_notify) priv->constrain_data_notify (priv->constrain_data); priv->constrain_callback = callback; priv->constrain_data = user_data; priv->constrain_data_notify = user_data_notify; } void clutter_evdev_set_relative_motion_filter (ClutterDeviceManager *evdev, ClutterRelativeMotionFilter filter, gpointer user_data) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdevPrivate *priv; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); priv = manager_evdev->priv; priv->relative_motion_filter = filter; priv->relative_motion_filter_user_data = user_data; } /** * clutter_evdev_set_keyboard_repeat: * @evdev: the #ClutterDeviceManager created by the evdev backend * @repeat: whether to enable or disable keyboard repeat events * @delay: the delay in ms between the hardware key press event and * the first synthetic event * @interval: the period in ms between consecutive synthetic key * press events * * Enables or disables sythetic key press events, allowing for initial * delay and interval period to be specified. * * Since: 1.18 * Stability: unstable */ void clutter_evdev_set_keyboard_repeat (ClutterDeviceManager *evdev, gboolean repeat, guint32 delay, guint32 interval) { ClutterDeviceManagerEvdev *manager_evdev; ClutterSeatEvdev *seat; g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); seat = manager_evdev->priv->main_seat; seat->repeat = repeat; seat->repeat_delay = delay; seat->repeat_interval = interval; } /** * clutter_evdev_add_filter: (skip) * @func: (closure data): a filter function * @data: (allow-none): user data to be passed to the filter function, or %NULL * @destroy_notify: (allow-none): function to call on @data when the filter is removed, or %NULL * * Adds an event filter function. * * Since: 1.20 * Stability: unstable */ void clutter_evdev_add_filter (ClutterEvdevFilterFunc func, gpointer data, GDestroyNotify destroy_notify) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManager *manager; ClutterEventFilter *filter; g_return_if_fail (func != NULL); manager = clutter_device_manager_get_default (); if (!CLUTTER_IS_DEVICE_MANAGER_EVDEV (manager)) { g_critical ("The Clutter input backend is not a evdev backend"); return; } manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); filter = g_new0 (ClutterEventFilter, 1); filter->func = func; filter->data = data; filter->destroy_notify = destroy_notify; manager_evdev->priv->event_filters = g_slist_append (manager_evdev->priv->event_filters, filter); } /** * clutter_evdev_remove_filter: (skip) * @func: a filter function * @data: (allow-none): user data to be passed to the filter function, or %NULL * * Removes the given filter function. * * Since: 1.20 * Stability: unstable */ void clutter_evdev_remove_filter (ClutterEvdevFilterFunc func, gpointer data) { ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManager *manager; ClutterEventFilter *filter; GSList *tmp_list; g_return_if_fail (func != NULL); manager = clutter_device_manager_get_default (); if (!CLUTTER_IS_DEVICE_MANAGER_EVDEV (manager)) { g_critical ("The Clutter input backend is not a evdev backend"); return; } manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); tmp_list = manager_evdev->priv->event_filters; while (tmp_list) { filter = tmp_list->data; if (filter->func == func && filter->data == data) { if (filter->destroy_notify) filter->destroy_notify (filter->data); free (filter); manager_evdev->priv->event_filters = g_slist_delete_link (manager_evdev->priv->event_filters, tmp_list); return; } tmp_list = tmp_list->next; } } /** * clutter_evdev_warp_pointer: * @pointer_device: the pointer device to warp * @time: the timestamp for the warp event * @x: the new X position of the pointer * @y: the new Y position of the pointer * * Warps the pointer to a new location. Technically, this is * processed the same way as an absolute motion event from * libinput: it simply generates an absolute motion event that * will be processed on the next iteration of the mainloop. * * The intended use for this is for display servers that need * to warp cursor the cursor to a new location. * * Since: 1.20 * Stability: unstable */ void clutter_evdev_warp_pointer (ClutterInputDevice *pointer_device, guint32 time_, int x, int y) { notify_absolute_motion (pointer_device, ms2us(time_), x, y, NULL); } /** * clutter_evdev_set_seat_id: * @seat_id: The seat ID * * Sets the seat to assign to the libinput context. * * For reliable effects, this function must be called before clutter_init(). */ void clutter_evdev_set_seat_id (const gchar *seat_id) { free (evdev_seat_id); evdev_seat_id = g_strdup (seat_id); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-input-device-evdev.h�������������������������������������0000664�0001750�0001750�00000015034�14211404421�024750� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corp. * Copyright (C) 2014 Jonas Ådahl * * 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, see <http://www.gnu.org/licenses/>. * * Author: Damien Lespiau <damien.lespiau@intel.com> * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifndef __CLUTTER_INPUT_DEVICE_EVDEV_H__ #define __CLUTTER_INPUT_DEVICE_EVDEV_H__ #include <glib-object.h> #include <libinput.h> #include "clutter/clutter-device-manager-private.h" #include "evdev/clutter-seat-evdev.h" G_BEGIN_DECLS #define CLUTTER_TYPE_INPUT_DEVICE_EVDEV _clutter_input_device_evdev_get_type() #define CLUTTER_INPUT_DEVICE_EVDEV(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ CLUTTER_TYPE_INPUT_DEVICE_EVDEV, ClutterInputDeviceEvdev)) #define CLUTTER_INPUT_DEVICE_EVDEV_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ CLUTTER_TYPE_INPUT_DEVICE_EVDEV, ClutterInputDeviceEvdevClass)) #define CLUTTER_IS_INPUT_DEVICE_EVDEV(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ CLUTTER_TYPE_INPUT_DEVICE_EVDEV)) #define CLUTTER_IS_INPUT_DEVICE_EVDEV_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ CLUTTER_TYPE_INPUT_DEVICE_EVDEV)) #define CLUTTER_INPUT_DEVICE_EVDEV_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ CLUTTER_TYPE_INPUT_DEVICE_EVDEV, ClutterInputDeviceEvdevClass)) typedef struct _ClutterInputDeviceEvdev ClutterInputDeviceEvdev; typedef struct _ClutterEventEvdev ClutterEventEvdev; struct _ClutterInputDeviceEvdev { ClutterInputDevice parent; struct libinput_device *libinput_device; ClutterSeatEvdev *seat; ClutterInputDeviceTool *last_tool; cairo_matrix_t device_matrix; gdouble device_aspect_ratio; /* w:h */ gdouble output_ratio; /* w:h */ GHashTable *touches; /* Keyboard a11y */ ClutterKeyboardA11yFlags a11y_flags; GList *slow_keys_list; guint debounce_timer; guint16 debounce_key; xkb_mod_mask_t stickykeys_depressed_mask; xkb_mod_mask_t stickykeys_latched_mask; xkb_mod_mask_t stickykeys_locked_mask; guint toggle_slowkeys_timer; guint16 shift_count; guint32 last_shift_time; gint mousekeys_btn; gboolean mousekeys_btn_states[3]; guint32 mousekeys_first_motion_time; /* ms */ guint32 mousekeys_last_motion_time; /* ms */ guint mousekeys_init_delay; guint mousekeys_accel_time; guint mousekeys_max_speed; gdouble mousekeys_curve_factor; guint move_mousekeys_timer; guint16 last_mousekeys_key; ClutterVirtualInputDevice *mousekeys_virtual_device; }; GType _clutter_input_device_evdev_get_type (void) G_GNUC_CONST; ClutterInputDevice * _clutter_input_device_evdev_new (ClutterDeviceManager *manager, ClutterSeatEvdev *seat, struct libinput_device *libinput_device); ClutterInputDevice * _clutter_input_device_evdev_new_virtual (ClutterDeviceManager *manager, ClutterSeatEvdev *seat, ClutterInputDeviceType type, ClutterInputMode mode); ClutterSeatEvdev * _clutter_input_device_evdev_get_seat (ClutterInputDeviceEvdev *device); void _clutter_input_device_evdev_update_leds (ClutterInputDeviceEvdev *device, enum libinput_led leds); ClutterInputDeviceType _clutter_input_device_evdev_determine_type (struct libinput_device *libinput_device); ClutterEventEvdev * _clutter_event_evdev_copy (ClutterEventEvdev *event_evdev); void _clutter_event_evdev_free (ClutterEventEvdev *event_evdev); void _clutter_evdev_event_set_event_code (ClutterEvent *event, guint32 evcode); void _clutter_evdev_event_set_time_usec (ClutterEvent *event, guint64 time_usec); void _clutter_evdev_event_set_relative_motion (ClutterEvent *event, double dx, double dy, double dx_unaccel, double dy_unaccel); void clutter_input_device_evdev_translate_coordinates (ClutterInputDevice *device, ClutterStage *stage, gfloat *x, gfloat *y); void clutter_input_device_evdev_apply_kbd_a11y_settings (ClutterInputDeviceEvdev *device, ClutterKbdA11ySettings *settings); ClutterTouchState * clutter_input_device_evdev_acquire_touch_state (ClutterInputDeviceEvdev *device, int device_slot); ClutterTouchState * clutter_input_device_evdev_lookup_touch_state (ClutterInputDeviceEvdev *device, int device_slot); void clutter_input_device_evdev_release_touch_state (ClutterInputDeviceEvdev *device, ClutterTouchState *touch_state); void clutter_input_device_evdev_release_touch_slots (ClutterInputDeviceEvdev *device_evdev, uint64_t time_us); G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_EVDEV_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-xkb-utils.c����������������������������������������������0000664�0001750�0001750�00000007161�14211404421�023164� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * Authors: * Kristian Høgsberg * Damien Lespiau <damien.lespiau@intel.com> */ #include "clutter-build-config.h" #include "clutter-keysyms.h" #include "clutter-event-private.h" #include "clutter-xkb-utils.h" /* * _clutter_event_new_from_evdev: Create a new Clutter ClutterKeyEvent * @device: a ClutterInputDevice * @stage: the stage the event should be delivered to * @xkb: XKB rules to translate the event * @_time: timestamp of the event * @key: a key code coming from a Linux input device * @state: TRUE if a press event, FALSE if a release event * @modifer_state: in/out * * Translate @key to a #ClutterKeyEvent using rules from xbbcommon. * * Return value: the new #ClutterEvent */ ClutterEvent * _clutter_key_event_new_from_evdev (ClutterInputDevice *device, ClutterInputDevice *core_device, ClutterStage *stage, struct xkb_state *xkb_state, uint32_t button_state, uint32_t _time, xkb_keycode_t key, uint32_t state) { ClutterEvent *event; xkb_keysym_t sym; const xkb_keysym_t *syms; char buffer[8]; int n; if (state) event = clutter_event_new (CLUTTER_KEY_PRESS); else event = clutter_event_new (CLUTTER_KEY_RELEASE); /* We use a fixed offset of 8 because evdev starts KEY_* numbering from * 0, whereas X11's minimum keycode, for really stupid reasons, is 8. * So the evdev XKB rules are based on the keycodes all being shifted * upwards by 8. */ key += 8; n = xkb_key_get_syms (xkb_state, key, &syms); if (n == 1) sym = syms[0]; else sym = XKB_KEY_NoSymbol; event->key.device = core_device; event->key.stage = stage; event->key.time = _time; _clutter_xkb_translate_state (event, xkb_state, button_state); event->key.hardware_keycode = key; event->key.keyval = sym; clutter_event_set_source_device (event, device); n = xkb_keysym_to_utf8 (sym, buffer, sizeof (buffer)); if (n == 0) { /* not printable */ event->key.unicode_value = (gunichar) '\0'; } else { event->key.unicode_value = g_utf8_get_char_validated (buffer, n); if (event->key.unicode_value == -1 || event->key.unicode_value == -2) event->key.unicode_value = (gunichar) '\0'; } return event; } void _clutter_xkb_translate_state (ClutterEvent *event, struct xkb_state *state, uint32_t button_state) { _clutter_event_set_state_full (event, button_state, xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED), xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED), xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED), xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE) | button_state); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-evdev.h��������������������������������������������������0000664�0001750�0001750�00000016413�14211404421�022360� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_EVDEV_H__ #define __CLUTTER_EVDEV_H__ #include <glib.h> #include <glib-object.h> #include <xkbcommon/xkbcommon.h> #include <clutter/clutter.h> #include <libinput.h> G_BEGIN_DECLS #if !defined(CLUTTER_ENABLE_COMPOSITOR_API) && !defined(CLUTTER_COMPILATION) #error "You need to define CLUTTER_ENABLE_COMPOSITOR_API before including clutter-evdev.h" #endif /** * ClutterOpenDeviceCallback: * @path: the device path * @flags: flags to be passed to open * * This callback will be called when Clutter needs to access an input * device. It should return an open file descriptor for the file at @path, * or -1 if opening failed. */ typedef int (*ClutterOpenDeviceCallback) (const char *path, int flags, gpointer user_data, GError **error); typedef void (*ClutterCloseDeviceCallback) (int fd, gpointer user_data); CLUTTER_AVAILABLE_IN_1_16 void clutter_evdev_set_device_callbacks (ClutterOpenDeviceCallback open_callback, ClutterCloseDeviceCallback close_callback, gpointer user_data); CLUTTER_AVAILABLE_IN_ALL void clutter_evdev_set_seat_id (const gchar *seat_id); CLUTTER_AVAILABLE_IN_1_10 void clutter_evdev_release_devices (void); CLUTTER_AVAILABLE_IN_1_10 void clutter_evdev_reclaim_devices (void); /** * ClutterPointerConstrainCallback: * @device: the core pointer device * @time: the event time in milliseconds * @x: (inout): the new X coordinate * @y: (inout): the new Y coordinate * @user_data: user data passed to this function * * This callback will be called for all pointer motion events, and should * update (@x, @y) to constrain the pointer position appropriately. * The subsequent motion event will use the updated values as the new coordinates. * Note that the coordinates are not clamped to the stage size, and the callback * must make sure that this happens before it returns. * Also note that the event will be emitted even if the pointer is constrained * to be in the same position. * * Since: 1.16 */ typedef void (*ClutterPointerConstrainCallback) (ClutterInputDevice *device, guint32 time, float prev_x, float prev_y, float *x, float *y, gpointer user_data); CLUTTER_AVAILABLE_IN_1_16 void clutter_evdev_set_pointer_constrain_callback (ClutterDeviceManager *evdev, ClutterPointerConstrainCallback callback, gpointer user_data, GDestroyNotify user_data_notify); typedef void (*ClutterRelativeMotionFilter) (ClutterInputDevice *device, float x, float y, float *dx, float *dy, gpointer user_data); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_evdev_set_relative_motion_filter (ClutterDeviceManager *evdev, ClutterRelativeMotionFilter filter, gpointer user_data); CLUTTER_AVAILABLE_IN_1_16 void clutter_evdev_set_keyboard_map (ClutterDeviceManager *evdev, struct xkb_keymap *keymap); CLUTTER_AVAILABLE_IN_1_18 struct xkb_keymap * clutter_evdev_get_keyboard_map (ClutterDeviceManager *evdev); CLUTTER_AVAILABLE_IN_1_20 void clutter_evdev_set_keyboard_layout_index (ClutterDeviceManager *evdev, xkb_layout_index_t idx); CLUTTER_AVAILABLE_IN_MUFFIN xkb_layout_index_t clutter_evdev_get_keyboard_layout_index (ClutterDeviceManager *evdev); CLUTTER_AVAILABLE_IN_1_26 void clutter_evdev_set_keyboard_numlock (ClutterDeviceManager *evdev, gboolean numlock_state); CLUTTER_AVAILABLE_IN_1_18 void clutter_evdev_set_keyboard_repeat (ClutterDeviceManager *evdev, gboolean repeat, guint32 delay, guint32 interval); typedef gboolean (* ClutterEvdevFilterFunc) (struct libinput_event *event, gpointer data); CLUTTER_AVAILABLE_IN_1_20 void clutter_evdev_add_filter (ClutterEvdevFilterFunc func, gpointer data, GDestroyNotify destroy_notify); CLUTTER_AVAILABLE_IN_1_20 void clutter_evdev_remove_filter (ClutterEvdevFilterFunc func, gpointer data); CLUTTER_AVAILABLE_IN_1_20 struct libinput_device * clutter_evdev_input_device_get_libinput_device (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_20 gint32 clutter_evdev_event_sequence_get_slot (const ClutterEventSequence *sequence); CLUTTER_AVAILABLE_IN_1_20 void clutter_evdev_warp_pointer (ClutterInputDevice *pointer_device, guint32 time_, int x, int y); CLUTTER_AVAILABLE_IN_1_26 guint32 clutter_evdev_event_get_event_code (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_26 guint64 clutter_evdev_event_get_time_usec (const ClutterEvent *event); CLUTTER_AVAILABLE_IN_1_26 gboolean clutter_evdev_event_get_relative_motion (const ClutterEvent *event, double *dx, double *dy, double *dx_unaccel, double *dy_unaccel); CLUTTER_AVAILABLE_IN_ALL void clutter_evdev_input_device_tool_set_pressure_curve (ClutterInputDeviceTool *tool, gdouble curve[4]); CLUTTER_AVAILABLE_IN_ALL void clutter_evdev_input_device_tool_set_button_code (ClutterInputDeviceTool *tool, guint button, guint evcode); G_END_DECLS #endif /* __CLUTTER_EVDEV_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-input-device-tool-evdev.c��������������������������������0000664�0001750�0001750�00000012704�14211404421�025717� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-input-device-tool-evdev.h" #include "clutter-evdev.h" G_DEFINE_TYPE (ClutterInputDeviceToolEvdev, clutter_input_device_tool_evdev, CLUTTER_TYPE_INPUT_DEVICE_TOOL) static void clutter_input_device_tool_evdev_finalize (GObject *object) { ClutterInputDeviceToolEvdev *tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (object); g_hash_table_unref (tool->button_map); libinput_tablet_tool_unref (tool->tool); G_OBJECT_CLASS (clutter_input_device_tool_evdev_parent_class)->finalize (object); } static void clutter_input_device_tool_evdev_class_init (ClutterInputDeviceToolEvdevClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = clutter_input_device_tool_evdev_finalize; } static void clutter_input_device_tool_evdev_init (ClutterInputDeviceToolEvdev *tool) { tool->button_map = g_hash_table_new (NULL, NULL); } ClutterInputDeviceTool * clutter_input_device_tool_evdev_new (struct libinput_tablet_tool *tool, guint64 serial, ClutterInputDeviceToolType type) { ClutterInputDeviceToolEvdev *evdev_tool; evdev_tool = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV, "type", type, "serial", serial, "id", libinput_tablet_tool_get_tool_id (tool), NULL); evdev_tool->tool = libinput_tablet_tool_ref (tool); return CLUTTER_INPUT_DEVICE_TOOL (evdev_tool); } void clutter_evdev_input_device_tool_set_pressure_curve (ClutterInputDeviceTool *tool, gdouble curve[4]) { ClutterInputDeviceToolEvdev *evdev_tool; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL_EVDEV (tool)); g_return_if_fail (curve[0] >= 0 && curve[0] <= 1 && curve[1] >= 0 && curve[1] <= 1 && curve[2] >= 0 && curve[2] <= 1 && curve[3] >= 0 && curve[3] <= 1); evdev_tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (tool); evdev_tool->pressure_curve[0] = curve[0]; evdev_tool->pressure_curve[1] = curve[1]; evdev_tool->pressure_curve[2] = curve[2]; evdev_tool->pressure_curve[3] = curve[3]; } void clutter_evdev_input_device_tool_set_button_code (ClutterInputDeviceTool *tool, guint button, guint evcode) { ClutterInputDeviceToolEvdev *evdev_tool; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL_EVDEV (tool)); evdev_tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (tool); if (evcode == 0) { g_hash_table_remove (evdev_tool->button_map, GUINT_TO_POINTER (button)); } else { g_hash_table_insert (evdev_tool->button_map, GUINT_TO_POINTER (button), GUINT_TO_POINTER (evcode)); } } static gdouble calculate_bezier_position (gdouble pos, gdouble x1, gdouble y1, gdouble x2, gdouble y2) { gdouble int1_y, int2_y; pos = CLAMP (pos, 0, 1); /* Intersection between 0,0 and x1,y1 */ int1_y = pos * y1; /* Intersection between x2,y2 and 1,1 */ int2_y = (pos * (1 - y2)) + y2; /* Find the new position in the line traced by the previous points */ return (pos * (int2_y - int1_y)) + int1_y; } gdouble clutter_input_device_tool_evdev_translate_pressure (ClutterInputDeviceTool *tool, gdouble pressure) { ClutterInputDeviceToolEvdev *evdev_tool; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), pressure); evdev_tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (tool); return calculate_bezier_position (CLAMP (pressure, 0, 1), evdev_tool->pressure_curve[0], evdev_tool->pressure_curve[1], evdev_tool->pressure_curve[2], evdev_tool->pressure_curve[3]); } guint clutter_input_device_tool_evdev_get_button_code (ClutterInputDeviceTool *tool, guint button) { ClutterInputDeviceToolEvdev *evdev_tool; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), 0); evdev_tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (tool); return GPOINTER_TO_UINT (g_hash_table_lookup (evdev_tool->button_map, GUINT_TO_POINTER (button))); } ������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-virtual-input-device-evdev.h�����������������������������0000664�0001750�0001750�00000002474�14211404421�026440� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifndef __CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV_H__ #define __CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV_H__ #include "clutter-virtual-input-device.h" #define CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_EVDEV (clutter_virtual_input_device_evdev_get_type ()) G_DECLARE_FINAL_TYPE (ClutterVirtualInputDeviceEvdev, clutter_virtual_input_device_evdev, CLUTTER, VIRTUAL_INPUT_DEVICE_EVDEV, ClutterVirtualInputDevice) #endif /* __CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-event-evdev.c��������������������������������������������0000664�0001750�0001750�00000011770�14211404421�023473� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Clutter. * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2015 Red Hat * * 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, see <http://www.gnu.org/licenses/>. * * Authored by: * Carlos Garnacho <carlosg@gnome.org> */ #include "clutter-build-config.h" #include "clutter/clutter-device-manager-private.h" #include "clutter/clutter-event-private.h" #include "clutter-input-device-evdev.h" #include "clutter-evdev.h" typedef struct _ClutterEventEvdev ClutterEventEvdev; struct _ClutterEventEvdev { guint32 evcode; guint64 time_usec; gboolean has_relative_motion; double dx; double dy; double dx_unaccel; double dy_unaccel; }; static ClutterEventEvdev * _clutter_event_evdev_new (void) { return g_slice_new0 (ClutterEventEvdev); } ClutterEventEvdev * _clutter_event_evdev_copy (ClutterEventEvdev *event_evdev) { if (event_evdev != NULL) return g_slice_dup (ClutterEventEvdev, event_evdev); return NULL; } void _clutter_event_evdev_free (ClutterEventEvdev *event_evdev) { if (event_evdev != NULL) g_slice_free (ClutterEventEvdev, event_evdev); } static ClutterEventEvdev * clutter_evdev_event_ensure_platform_data (ClutterEvent *event) { ClutterEventEvdev *event_evdev = _clutter_event_get_platform_data (event); if (!event_evdev) { event_evdev = _clutter_event_evdev_new (); _clutter_event_set_platform_data (event, event_evdev); } return event_evdev; } void _clutter_evdev_event_set_event_code (ClutterEvent *event, guint32 evcode) { ClutterEventEvdev *event_evdev; event_evdev = clutter_evdev_event_ensure_platform_data (event); event_evdev->evcode = evcode; } void _clutter_evdev_event_set_time_usec (ClutterEvent *event, guint64 time_usec) { ClutterEventEvdev *event_evdev; event_evdev = clutter_evdev_event_ensure_platform_data (event); event_evdev->time_usec = time_usec; } void _clutter_evdev_event_set_relative_motion (ClutterEvent *event, double dx, double dy, double dx_unaccel, double dy_unaccel) { ClutterEventEvdev *event_evdev; event_evdev = clutter_evdev_event_ensure_platform_data (event); event_evdev->dx = dx; event_evdev->dy = dy; event_evdev->dx_unaccel = dx_unaccel; event_evdev->dy_unaccel = dy_unaccel; event_evdev->has_relative_motion = TRUE; } /** * clutter_evdev_event_get_event_code: * @event: a #ClutterEvent * * Returns the event code of the original event. See linux/input.h for more * information. * * Returns: The event code. **/ guint32 clutter_evdev_event_get_event_code (const ClutterEvent *event) { ClutterEventEvdev *event_evdev = _clutter_event_get_platform_data (event); if (event_evdev) return event_evdev->evcode; return 0; } /** * clutter_evdev_event_get_time_usec: * @event: a #ClutterEvent * * Returns the time in microsecond granularity, or 0 if unavailable. * * Returns: The time in microsecond granularity, or 0 if unavailable. */ guint64 clutter_evdev_event_get_time_usec (const ClutterEvent *event) { ClutterEventEvdev *event_evdev = _clutter_event_get_platform_data (event); if (event_evdev) return event_evdev->time_usec; return 0; } /** * clutter_evdev_event_get_pointer_motion * @event: a #ClutterEvent * * If available, the normal and unaccelerated motion deltas are written * to the dx, dy, dx_unaccel and dy_unaccel and TRUE is returned. * * If unavailable, FALSE is returned. * * Returns: TRUE on success, otherwise FALSE. **/ gboolean clutter_evdev_event_get_relative_motion (const ClutterEvent *event, double *dx, double *dy, double *dx_unaccel, double *dy_unaccel) { ClutterEventEvdev *event_evdev = _clutter_event_get_platform_data (event); if (event_evdev && event_evdev->has_relative_motion) { if (dx) *dx = event_evdev->dx; if (dy) *dy = event_evdev->dy; if (dx_unaccel) *dx_unaccel = event_evdev->dx_unaccel; if (dy_unaccel) *dy_unaccel = event_evdev->dy_unaccel; return TRUE; } else return FALSE; } ��������muffin-5.2.1/clutter/clutter/evdev/clutter-xkb-utils.h����������������������������������������������0000664�0001750�0001750�00000003426�14211404421�023171� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * Authors: * Damien Lespiau <damien.lespiau@intel.com> */ #ifndef __CLUTTER_XKB_UTILS_H__ #define __CLUTTER_XKB_UTILS_H__ #include <xkbcommon/xkbcommon.h> #include "clutter-stage.h" #include "clutter-event.h" #include "clutter-input-device.h" ClutterEvent * _clutter_key_event_new_from_evdev (ClutterInputDevice *device, ClutterInputDevice *core_keyboard, ClutterStage *stage, struct xkb_state *xkb_state, uint32_t button_state, uint32_t _time, uint32_t key, uint32_t state); void _clutter_xkb_translate_state (ClutterEvent *event, struct xkb_state *xkb_state, uint32_t button_state); #endif /* __CLUTTER_XKB_UTILS_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-input-device-tool-evdev.h��������������������������������0000664�0001750�0001750�00000006151�14211404421�025723� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see <http://www.gnu.org/licenses/>. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifndef __CLUTTER_INPUT_DEVICE_EVDEV_TOOL_H__ #define __CLUTTER_INPUT_DEVICE_EVDEV_TOOL_H__ #include <libinput.h> #include <clutter/clutter-input-device-tool.h> G_BEGIN_DECLS #define CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV (clutter_input_device_tool_evdev_get_type ()) #define CLUTTER_INPUT_DEVICE_TOOL_EVDEV(o) \ (G_TYPE_CHECK_INSTANCE_CAST ((o), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV, ClutterInputDeviceToolEvdev)) #define CLUTTER_IS_INPUT_DEVICE_TOOL_EVDEV(o) \ (G_TYPE_CHECK_INSTANCE_TYPE ((o), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV)) #define CLUTTER_INPUT_DEVICE_TOOL_EVDEV_CLASS(c) \ (G_TYPE_CHECK_CLASS_CAST ((c), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV, ClutterInputDeviceToolEvdevClass)) #define CLUTTER_IS_INPUT_DEVICE_TOOL_EVDEV_CLASS(c) \ (G_TYPE_CHECK_CLASS_TYPE ((c), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV)) #define CLUTTER_INPUT_DEVICE_TOOL_EVDEV_GET_CLASS(o) \ (G_TYPE_INSTANCE_GET_CLASS ((o), \ CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV, ClutterInputDeviceToolEvdevClass)) typedef struct _ClutterInputDeviceToolEvdev ClutterInputDeviceToolEvdev; typedef struct _ClutterInputDeviceToolEvdevClass ClutterInputDeviceToolEvdevClass; struct _ClutterInputDeviceToolEvdev { ClutterInputDeviceTool parent_instance; struct libinput_tablet_tool *tool; GHashTable *button_map; gdouble pressure_curve[4]; }; struct _ClutterInputDeviceToolEvdevClass { ClutterInputDeviceToolClass parent_class; }; GType clutter_input_device_tool_evdev_get_type (void) G_GNUC_CONST; ClutterInputDeviceTool * clutter_input_device_tool_evdev_new (struct libinput_tablet_tool *tool, guint64 serial, ClutterInputDeviceToolType type); gdouble clutter_input_device_tool_evdev_translate_pressure (ClutterInputDeviceTool *tool, gdouble pressure); guint clutter_input_device_tool_evdev_get_button_code (ClutterInputDeviceTool *tool, guint button); G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_EVDEV_TOOL_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-seat-evdev.h���������������������������������������������0000664�0001750�0001750�00000015047�14211404421�023314� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corp. * Copyright (C) 2014 Jonas Ådahl * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Damien Lespiau <damien.lespiau@intel.com> * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifndef __CLUTTER_SEAT_EVDEV_H__ #define __CLUTTER_SEAT_EVDEV_H__ #include <libinput.h> #include <linux/input.h> #include "clutter-input-device.h" #include "clutter-device-manager-evdev.h" #include "clutter-xkb-utils.h" typedef struct _ClutterTouchState ClutterTouchState; struct _ClutterTouchState { ClutterSeatEvdev *seat; int device_slot; int seat_slot; ClutterPoint coords; }; struct _ClutterSeatEvdev { struct libinput_seat *libinput_seat; ClutterDeviceManagerEvdev *manager_evdev; GSList *devices; ClutterInputDevice *core_pointer; ClutterInputDevice *core_keyboard; ClutterTouchState **touch_states; int n_alloc_touch_states; struct xkb_state *xkb; xkb_led_index_t caps_lock_led; xkb_led_index_t num_lock_led; xkb_led_index_t scroll_lock_led; xkb_layout_index_t layout_idx; uint32_t button_state; int button_count[KEY_CNT]; /* keyboard repeat */ gboolean repeat; guint32 repeat_delay; guint32 repeat_interval; guint32 repeat_key; guint32 repeat_count; guint32 repeat_timer; ClutterInputDevice *repeat_device; gfloat pointer_x; gfloat pointer_y; /* Emulation of discrete scroll events out of smooth ones */ gfloat accum_scroll_dx; gfloat accum_scroll_dy; }; void clutter_seat_evdev_notify_key (ClutterSeatEvdev *seat, ClutterInputDevice *device, uint64_t time_us, uint32_t key, uint32_t state, gboolean update_keys); void clutter_seat_evdev_notify_relative_motion (ClutterSeatEvdev *seat_evdev, ClutterInputDevice *input_device, uint64_t time_us, float dx, float dy, float dx_unaccel, float dy_unaccel); void clutter_seat_evdev_notify_absolute_motion (ClutterSeatEvdev *seat_evdev, ClutterInputDevice *input_device, uint64_t time_us, float x, float y, double *axes); void clutter_seat_evdev_notify_button (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, uint32_t button, uint32_t state); void clutter_seat_evdev_notify_scroll_continuous (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, double dx, double dy, ClutterScrollSource source, ClutterScrollFinishFlags flags); void clutter_seat_evdev_notify_discrete_scroll (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, uint64_t time_us, double discrete_dx, double discrete_dy, ClutterScrollSource source); void clutter_seat_evdev_notify_touch_event (ClutterSeatEvdev *seat, ClutterInputDevice *input_device, ClutterEventType evtype, uint64_t time_us, int slot, double x, double y); void clutter_seat_evdev_set_libinput_seat (ClutterSeatEvdev *seat, struct libinput_seat *libinput_seat); void clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat); ClutterInputDevice * clutter_seat_evdev_get_device (ClutterSeatEvdev *seat, gint id); ClutterTouchState * clutter_seat_evdev_acquire_touch_state (ClutterSeatEvdev *seat, int device_slot); void clutter_seat_evdev_release_touch_state (ClutterSeatEvdev *seat, ClutterTouchState *touch_state); ClutterTouchState * clutter_seat_evdev_get_touch (ClutterSeatEvdev *seat, guint32 id); void clutter_seat_evdev_set_stage (ClutterSeatEvdev *seat, ClutterStage *stage); void clutter_seat_evdev_clear_repeat_timer (ClutterSeatEvdev *seat); ClutterSeatEvdev * clutter_seat_evdev_new (ClutterDeviceManagerEvdev *manager_evdev); void clutter_seat_evdev_free (ClutterSeatEvdev *seat); #endif /* __CLUTTER_SEAT_EVDEV_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/evdev/clutter-input-device-evdev.c�������������������������������������0000664�0001750�0001750�00000136311�14211404421�024745� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corp. * Copyright (C) 2014 Jonas Ådahl * * 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, see <http://www.gnu.org/licenses/>. * * Author: Damien Lespiau <damien.lespiau@intel.com> * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter/clutter-device-manager-private.h" #include "clutter/clutter-event-private.h" #include "clutter-private.h" #include "clutter-evdev.h" #include "clutter-input-device-tool-evdev.h" #include "clutter-input-device-evdev.h" #include "clutter-device-manager-evdev.h" #include "cairo-gobject.h" typedef struct _ClutterInputDeviceClass ClutterInputDeviceEvdevClass; #define clutter_input_device_evdev_get_type _clutter_input_device_evdev_get_type G_DEFINE_TYPE (ClutterInputDeviceEvdev, clutter_input_device_evdev, CLUTTER_TYPE_INPUT_DEVICE) enum { PROP_0, PROP_DEVICE_MATRIX, PROP_OUTPUT_ASPECT_RATIO, N_PROPS }; static GParamSpec *obj_props[N_PROPS] = { 0 }; typedef struct _SlowKeysEventPending { ClutterInputDeviceEvdev *device; ClutterEvent *event; ClutterEmitInputDeviceEvent emit_event_func; guint timer; } SlowKeysEventPending; static void clear_slow_keys (ClutterInputDeviceEvdev *device); static void stop_bounce_keys (ClutterInputDeviceEvdev *device); static void stop_toggle_slowkeys (ClutterInputDeviceEvdev *device); static void stop_mousekeys_move (ClutterInputDeviceEvdev *device); static void clutter_input_device_evdev_finalize (GObject *object) { ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (object); ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (object); ClutterDeviceManagerEvdev *manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (device->device_manager); if (device_evdev->libinput_device) libinput_device_unref (device_evdev->libinput_device); clutter_input_device_evdev_release_touch_slots (device_evdev, g_get_monotonic_time ()); _clutter_device_manager_evdev_release_device_id (manager_evdev, device); clear_slow_keys (device_evdev); stop_bounce_keys (device_evdev); stop_toggle_slowkeys (device_evdev); stop_mousekeys_move (device_evdev); G_OBJECT_CLASS (clutter_input_device_evdev_parent_class)->finalize (object); } static void clutter_input_device_evdev_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterInputDeviceEvdev *device = CLUTTER_INPUT_DEVICE_EVDEV (object); switch (prop_id) { case PROP_DEVICE_MATRIX: { const cairo_matrix_t *matrix = g_value_get_boxed (value); cairo_matrix_init_identity (&device->device_matrix); cairo_matrix_multiply (&device->device_matrix, &device->device_matrix, matrix); break; } case PROP_OUTPUT_ASPECT_RATIO: device->output_ratio = g_value_get_double (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clutter_input_device_evdev_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterInputDeviceEvdev *device = CLUTTER_INPUT_DEVICE_EVDEV (object); switch (prop_id) { case PROP_DEVICE_MATRIX: g_value_set_boxed (value, &device->device_matrix); break; case PROP_OUTPUT_ASPECT_RATIO: g_value_set_double (value, device->output_ratio); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean clutter_input_device_evdev_keycode_to_evdev (ClutterInputDevice *device, guint hardware_keycode, guint *evdev_keycode) { /* The hardware keycodes from the evdev backend are almost evdev keycodes: we use the evdev keycode file, but xkb rules have an offset by 8. See the comment in _clutter_key_event_new_from_evdev() */ *evdev_keycode = hardware_keycode - 8; return TRUE; } static void clutter_input_device_evdev_update_from_tool (ClutterInputDevice *device, ClutterInputDeviceTool *tool) { ClutterInputDeviceToolEvdev *evdev_tool; evdev_tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (tool); g_object_freeze_notify (G_OBJECT (device)); _clutter_input_device_reset_axes (device); _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_X, 0, 0, 0); _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_Y, 0, 0, 0); if (libinput_tablet_tool_has_distance (evdev_tool->tool)) _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_DISTANCE, 0, 1, 0); if (libinput_tablet_tool_has_pressure (evdev_tool->tool)) _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_PRESSURE, 0, 1, 0); if (libinput_tablet_tool_has_tilt (evdev_tool->tool)) { _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_XTILT, -90, 90, 0); _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_YTILT, -90, 90, 0); } if (libinput_tablet_tool_has_rotation (evdev_tool->tool)) _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_ROTATION, 0, 360, 0); if (libinput_tablet_tool_has_slider (evdev_tool->tool)) _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_SLIDER, -1, 1, 0); if (libinput_tablet_tool_has_wheel (evdev_tool->tool)) _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_WHEEL, -180, 180, 0); g_object_thaw_notify (G_OBJECT (device)); } static gboolean clutter_input_device_evdev_is_mode_switch_button (ClutterInputDevice *device, guint group, guint button) { struct libinput_device *libinput_device; struct libinput_tablet_pad_mode_group *mode_group; libinput_device = clutter_evdev_input_device_get_libinput_device (device); mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, group); return libinput_tablet_pad_mode_group_button_is_toggle (mode_group, button) != 0; } static gint clutter_input_device_evdev_get_group_n_modes (ClutterInputDevice *device, gint group) { struct libinput_device *libinput_device; struct libinput_tablet_pad_mode_group *mode_group; libinput_device = clutter_evdev_input_device_get_libinput_device (device); mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, group); return libinput_tablet_pad_mode_group_get_num_modes (mode_group); } static gboolean clutter_input_device_evdev_is_grouped (ClutterInputDevice *device, ClutterInputDevice *other_device) { struct libinput_device *libinput_device, *other_libinput_device; libinput_device = clutter_evdev_input_device_get_libinput_device (device); other_libinput_device = clutter_evdev_input_device_get_libinput_device (other_device); return libinput_device_get_device_group (libinput_device) == libinput_device_get_device_group (other_libinput_device); } static void clutter_input_device_evdev_bell_notify (void) { ClutterBackend *backend; backend = clutter_get_default_backend (); clutter_backend_bell_notify (backend); } static void clutter_input_device_evdev_free_pending_slow_key (gpointer data) { SlowKeysEventPending *slow_keys_event = data; clutter_event_free (slow_keys_event->event); if (slow_keys_event->timer) g_source_remove (slow_keys_event->timer); free (slow_keys_event); } static void clear_slow_keys (ClutterInputDeviceEvdev *device) { g_list_free_full (device->slow_keys_list, clutter_input_device_evdev_free_pending_slow_key); g_list_free (device->slow_keys_list); device->slow_keys_list = NULL; } static guint get_slow_keys_delay (ClutterInputDevice *device) { ClutterKbdA11ySettings a11y_settings; clutter_device_manager_get_kbd_a11y_settings (device->device_manager, &a11y_settings); /* Settings use int, we use uint, make sure we dont go negative */ return MAX (0, a11y_settings.slowkeys_delay); } static gboolean trigger_slow_keys (gpointer data) { SlowKeysEventPending *slow_keys_event = data; ClutterInputDeviceEvdev *device = slow_keys_event->device; ClutterKeyEvent *key_event = (ClutterKeyEvent *) slow_keys_event->event; /* Alter timestamp and emit the event */ key_event->time = us2ms (g_get_monotonic_time ()); slow_keys_event->emit_event_func (slow_keys_event->event, CLUTTER_INPUT_DEVICE (device)); /* Then remote the pending event */ device->slow_keys_list = g_list_remove (device->slow_keys_list, slow_keys_event); clutter_input_device_evdev_free_pending_slow_key (slow_keys_event); if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT) clutter_input_device_evdev_bell_notify (); return G_SOURCE_REMOVE; } static gint find_pending_event_by_keycode (gconstpointer a, gconstpointer b) { const SlowKeysEventPending *pa = a; const ClutterKeyEvent *ka = (ClutterKeyEvent *) pa->event; const ClutterKeyEvent *kb = b; return kb->hardware_keycode - ka->hardware_keycode; } static void start_slow_keys (ClutterEvent *event, ClutterInputDeviceEvdev *device, ClutterEmitInputDeviceEvent emit_event_func) { SlowKeysEventPending *slow_keys_event; ClutterKeyEvent *key_event = (ClutterKeyEvent *) event; /* Synthetic key events are for autorepeat, ignore those... */ if (key_event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC) return; slow_keys_event = g_new0 (SlowKeysEventPending, 1); slow_keys_event->device = device; slow_keys_event->event = clutter_event_copy (event); slow_keys_event->emit_event_func = emit_event_func; slow_keys_event->timer = clutter_threads_add_timeout (get_slow_keys_delay (CLUTTER_INPUT_DEVICE (device)), trigger_slow_keys, slow_keys_event); device->slow_keys_list = g_list_append (device->slow_keys_list, slow_keys_event); if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS) clutter_input_device_evdev_bell_notify (); } static void stop_slow_keys (ClutterEvent *event, ClutterInputDeviceEvdev *device, ClutterEmitInputDeviceEvent emit_event_func) { GList *item; /* Check if we have a slow key event queued for this key event */ item = g_list_find_custom (device->slow_keys_list, event, find_pending_event_by_keycode); if (item) { SlowKeysEventPending *slow_keys_event = item->data; device->slow_keys_list = g_list_delete_link (device->slow_keys_list, item); clutter_input_device_evdev_free_pending_slow_key (slow_keys_event); if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT) clutter_input_device_evdev_bell_notify (); return; } /* If no key press event was pending, just emit the key release as-is */ emit_event_func (event, CLUTTER_INPUT_DEVICE (device)); } static guint get_debounce_delay (ClutterInputDevice *device) { ClutterKbdA11ySettings a11y_settings; clutter_device_manager_get_kbd_a11y_settings (device->device_manager, &a11y_settings); /* Settings use int, we use uint, make sure we dont go negative */ return MAX (0, a11y_settings.debounce_delay); } static gboolean clear_bounce_keys (gpointer data) { ClutterInputDeviceEvdev *device = data; device->debounce_key = 0; device->debounce_timer = 0; return G_SOURCE_REMOVE; } static void start_bounce_keys (ClutterEvent *event, ClutterInputDeviceEvdev *device) { stop_bounce_keys (device); device->debounce_key = ((ClutterKeyEvent *) event)->hardware_keycode; device->debounce_timer = clutter_threads_add_timeout (get_debounce_delay (CLUTTER_INPUT_DEVICE (device)), clear_bounce_keys, device); } static void stop_bounce_keys (ClutterInputDeviceEvdev *device) { if (device->debounce_timer) { g_source_remove (device->debounce_timer); device->debounce_timer = 0; } } static void notify_bounce_keys_reject (ClutterInputDeviceEvdev *device) { if (device->a11y_flags & CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT) clutter_input_device_evdev_bell_notify (); } static gboolean debounce_key (ClutterEvent *event, ClutterInputDeviceEvdev *device) { return (device->debounce_key == ((ClutterKeyEvent *) event)->hardware_keycode); } static gboolean key_event_is_modifier (ClutterEvent *event) { switch (event->key.keyval) { case XKB_KEY_Shift_L: case XKB_KEY_Shift_R: case XKB_KEY_Control_L: case XKB_KEY_Control_R: case XKB_KEY_Alt_L: case XKB_KEY_Alt_R: case XKB_KEY_Meta_L: case XKB_KEY_Meta_R: case XKB_KEY_Super_L: case XKB_KEY_Super_R: case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R: case XKB_KEY_Caps_Lock: case XKB_KEY_Shift_Lock: return TRUE; default: return FALSE; } } static void notify_stickykeys_mask (ClutterInputDeviceEvdev *device) { g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->device_manager, "kbd-a11y-mods-state-changed", device->stickykeys_latched_mask, device->stickykeys_locked_mask); } static void update_internal_xkb_state (ClutterInputDeviceEvdev *device, xkb_mod_mask_t new_latched_mask, xkb_mod_mask_t new_locked_mask) { ClutterSeatEvdev *seat = device->seat; xkb_mod_mask_t depressed_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; xkb_mod_mask_t group_mods; depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); latched_mods &= ~device->stickykeys_latched_mask; locked_mods &= ~device->stickykeys_locked_mask; device->stickykeys_latched_mask = new_latched_mask; device->stickykeys_locked_mask = new_locked_mask; latched_mods |= device->stickykeys_latched_mask; locked_mods |= device->stickykeys_locked_mask; group_mods = xkb_state_serialize_layout (seat->xkb, XKB_STATE_LAYOUT_EFFECTIVE); xkb_state_update_mask (seat->xkb, depressed_mods, latched_mods, locked_mods, 0, 0, group_mods); notify_stickykeys_mask (device); } static void update_stickykeys_event (ClutterEvent *event, ClutterInputDeviceEvdev *device, xkb_mod_mask_t new_latched_mask, xkb_mod_mask_t new_locked_mask) { ClutterSeatEvdev *seat = device->seat; xkb_mod_mask_t effective_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; update_internal_xkb_state (device, new_latched_mask, new_locked_mask); effective_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_EFFECTIVE); latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); _clutter_event_set_state_full (event, seat->button_state, device->stickykeys_depressed_mask, latched_mods, locked_mods, effective_mods | seat->button_state); } static void notify_stickykeys_change (ClutterInputDeviceEvdev *device) { /* Everytime sticky keys setting is changed, clear the masks */ device->stickykeys_depressed_mask = 0; update_internal_xkb_state (device, 0, 0); g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->device_manager, "kbd-a11y-flags-changed", device->a11y_flags, CLUTTER_A11Y_STICKY_KEYS_ENABLED); } static void set_stickykeys_off (ClutterInputDeviceEvdev *device) { device->a11y_flags &= ~CLUTTER_A11Y_STICKY_KEYS_ENABLED; notify_stickykeys_change (device); } static void set_stickykeys_on (ClutterInputDeviceEvdev *device) { device->a11y_flags |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; notify_stickykeys_change (device); } static void clear_stickykeys_event (ClutterEvent *event, ClutterInputDeviceEvdev *device) { set_stickykeys_off (device); update_stickykeys_event (event, device, 0, 0); } static void set_slowkeys_off (ClutterInputDeviceEvdev *device) { device->a11y_flags &= ~CLUTTER_A11Y_SLOW_KEYS_ENABLED; g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->device_manager, "kbd-a11y-flags-changed", device->a11y_flags, CLUTTER_A11Y_SLOW_KEYS_ENABLED); } static void set_slowkeys_on (ClutterInputDeviceEvdev *device) { device->a11y_flags |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->device_manager, "kbd-a11y-flags-changed", device->a11y_flags, CLUTTER_A11Y_SLOW_KEYS_ENABLED); } static void handle_stickykeys_press (ClutterEvent *event, ClutterInputDeviceEvdev *device) { ClutterSeatEvdev *seat = device->seat; xkb_mod_mask_t depressed_mods; xkb_mod_mask_t new_latched_mask; xkb_mod_mask_t new_locked_mask; if (!key_event_is_modifier (event)) return; if (device->stickykeys_depressed_mask && (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF)) { clear_stickykeys_event (event, device); return; } depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); /* Ignore the lock modifier mask, that one cannot be sticky, yet the * CAPS_LOCK key itself counts as a modifier as it might be remapped * to some other modifier which can be sticky. */ depressed_mods &= ~CLUTTER_LOCK_MASK; new_latched_mask = device->stickykeys_latched_mask; new_locked_mask = device->stickykeys_locked_mask; device->stickykeys_depressed_mask = depressed_mods; if (new_locked_mask & depressed_mods) { new_locked_mask &= ~depressed_mods; } else if (new_latched_mask & depressed_mods) { new_locked_mask |= depressed_mods; new_latched_mask &= ~depressed_mods; } else { new_latched_mask |= depressed_mods; } update_stickykeys_event (event, device, new_latched_mask, new_locked_mask); } static void handle_stickykeys_release (ClutterEvent *event, ClutterInputDeviceEvdev *device) { ClutterSeatEvdev *seat = device->seat; device->stickykeys_depressed_mask = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); if (key_event_is_modifier (event)) { if (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_BEEP) clutter_input_device_evdev_bell_notify (); return; } if (device->stickykeys_latched_mask == 0) return; update_stickykeys_event (event, device, 0, device->stickykeys_locked_mask); } static gboolean trigger_toggle_slowkeys (gpointer data) { ClutterInputDeviceEvdev *device = data; device->toggle_slowkeys_timer = 0; if (device->a11y_flags & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP) clutter_input_device_evdev_bell_notify (); if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_ENABLED) set_slowkeys_off (device); else set_slowkeys_on (device); return G_SOURCE_REMOVE; } static void start_toggle_slowkeys (ClutterInputDeviceEvdev *device) { if (device->toggle_slowkeys_timer != 0) return; device->toggle_slowkeys_timer = clutter_threads_add_timeout (8 * 1000 /* 8 secs */, trigger_toggle_slowkeys, device); } static void stop_toggle_slowkeys (ClutterInputDeviceEvdev *device) { if (device->toggle_slowkeys_timer) { g_source_remove (device->toggle_slowkeys_timer); device->toggle_slowkeys_timer = 0; } } static void handle_togglekeys_press (ClutterEvent *event, ClutterInputDeviceEvdev *device) { if (event->key.keyval == XKB_KEY_Shift_L || event->key.keyval == XKB_KEY_Shift_R) { start_toggle_slowkeys (device); if (event->key.time > device->last_shift_time + 15 * 1000 /* 15 secs */) device->shift_count = 1; else device->shift_count++; device->last_shift_time = event->key.time; } else { device->shift_count = 0; stop_toggle_slowkeys (device); } } static void handle_togglekeys_release (ClutterEvent *event, ClutterInputDeviceEvdev *device) { if (event->key.keyval == XKB_KEY_Shift_L || event->key.keyval == XKB_KEY_Shift_R) { stop_toggle_slowkeys (device); if (device->shift_count >= 5) { device->shift_count = 0; if (device->a11y_flags & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP) clutter_input_device_evdev_bell_notify (); if (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_ENABLED) set_stickykeys_off (device); else set_stickykeys_on (device); } } } static int get_button_index (gint button) { switch (button) { case BTN_LEFT: return 0; case BTN_MIDDLE: return 1; case BTN_RIGHT: return 2; default: break; } g_warn_if_reached (); return 0; } static void emulate_button_press (ClutterInputDeviceEvdev *device) { gint btn = device->mousekeys_btn; if (device->mousekeys_btn_states[get_button_index (btn)]) return; clutter_virtual_input_device_notify_button (device->mousekeys_virtual_device, g_get_monotonic_time (), btn, CLUTTER_BUTTON_STATE_PRESSED); device->mousekeys_btn_states[get_button_index (btn)] = CLUTTER_BUTTON_STATE_PRESSED; } static void emulate_button_release (ClutterInputDeviceEvdev *device) { gint btn = device->mousekeys_btn; if (device->mousekeys_btn_states[get_button_index (btn)] == CLUTTER_BUTTON_STATE_RELEASED) return; clutter_virtual_input_device_notify_button (device->mousekeys_virtual_device, g_get_monotonic_time (), btn, CLUTTER_BUTTON_STATE_RELEASED); device->mousekeys_btn_states[get_button_index (btn)] = CLUTTER_BUTTON_STATE_RELEASED; } static void emulate_button_click (ClutterInputDeviceEvdev *device) { emulate_button_press (device); emulate_button_release (device); } #define MOUSEKEYS_CURVE (1.0 + (((double) 50.0) * 0.001)) static void update_mousekeys_params (ClutterInputDeviceEvdev *device, ClutterKbdA11ySettings *settings) { /* Prevent us from broken settings values */ device->mousekeys_max_speed = MAX (1, settings->mousekeys_max_speed); device->mousekeys_accel_time = MAX (1, settings->mousekeys_accel_time); device->mousekeys_init_delay = MAX (0, settings->mousekeys_init_delay); device->mousekeys_curve_factor = (((gdouble) device->mousekeys_max_speed) / pow ((gdouble) device->mousekeys_accel_time, MOUSEKEYS_CURVE)); } static gdouble mousekeys_get_speed_factor (ClutterInputDeviceEvdev *device, gint64 time_us) { guint32 time; gint64 delta_t; gint64 init_time; gdouble speed; time = us2ms (time_us); if (device->mousekeys_first_motion_time == 0) { /* Start acceleration _after_ the first move, so take * mousekeys_init_delay into account for t0 */ device->mousekeys_first_motion_time = time + device->mousekeys_init_delay; device->mousekeys_last_motion_time = device->mousekeys_first_motion_time; return 1.0; } init_time = time - device->mousekeys_first_motion_time; delta_t = time - device->mousekeys_last_motion_time; if (delta_t < 0) return 0.0; if (init_time < device->mousekeys_accel_time) speed = (double) (device->mousekeys_curve_factor * pow ((double) init_time, MOUSEKEYS_CURVE) * delta_t / 1000.0); else speed = (double) (device->mousekeys_max_speed * delta_t / 1000.0); device->mousekeys_last_motion_time = time; return speed; } #undef MOUSEKEYS_CURVE static void emulate_pointer_motion (ClutterInputDeviceEvdev *device, gint dx, gint dy) { gdouble dx_motion; gdouble dy_motion; gdouble speed; gint64 time_us; time_us = g_get_monotonic_time (); speed = mousekeys_get_speed_factor (device, time_us); if (dx < 0) dx_motion = floor (((gdouble) dx) * speed); else dx_motion = ceil (((gdouble) dx) * speed); if (dy < 0) dy_motion = floor (((gdouble) dy) * speed); else dy_motion = ceil (((gdouble) dy) * speed); clutter_virtual_input_device_notify_relative_motion (device->mousekeys_virtual_device, time_us, dx_motion, dy_motion); } static void enable_mousekeys (ClutterInputDeviceEvdev *device) { ClutterDeviceManager *manager; device->mousekeys_btn = BTN_LEFT; device->move_mousekeys_timer = 0; device->mousekeys_first_motion_time = 0; device->mousekeys_last_motion_time = 0; device->last_mousekeys_key = 0; if (device->mousekeys_virtual_device) return; manager = CLUTTER_INPUT_DEVICE (device)->device_manager; device->mousekeys_virtual_device = clutter_device_manager_create_virtual_device (manager, CLUTTER_POINTER_DEVICE); } static void disable_mousekeys (ClutterInputDeviceEvdev *device) { stop_mousekeys_move (device); /* Make sure we don't leave button pressed behind... */ if (device->mousekeys_btn_states[get_button_index (BTN_LEFT)]) { device->mousekeys_btn = BTN_LEFT; emulate_button_release (device); } if (device->mousekeys_btn_states[get_button_index (BTN_MIDDLE)]) { device->mousekeys_btn = BTN_MIDDLE; emulate_button_release (device); } if (device->mousekeys_btn_states[get_button_index (BTN_RIGHT)]) { device->mousekeys_btn = BTN_RIGHT; emulate_button_release (device); } if (device->mousekeys_virtual_device) g_clear_object (&device->mousekeys_virtual_device); } static gboolean trigger_mousekeys_move (gpointer data) { ClutterInputDeviceEvdev *device = data; gint dx = 0; gint dy = 0; if (device->mousekeys_first_motion_time == 0) { /* This is the first move, Secdule at mk_init_delay */ device->move_mousekeys_timer = clutter_threads_add_timeout (device->mousekeys_init_delay, trigger_mousekeys_move, device); } else { /* More moves, reschedule at mk_interval */ device->move_mousekeys_timer = clutter_threads_add_timeout (100, /* msec between mousekey events */ trigger_mousekeys_move, device); } /* Pointer motion */ switch (device->last_mousekeys_key) { case XKB_KEY_KP_Home: case XKB_KEY_KP_7: case XKB_KEY_KP_Up: case XKB_KEY_KP_8: case XKB_KEY_KP_Page_Up: case XKB_KEY_KP_9: dy = -1; break; case XKB_KEY_KP_End: case XKB_KEY_KP_1: case XKB_KEY_KP_Down: case XKB_KEY_KP_2: case XKB_KEY_KP_Page_Down: case XKB_KEY_KP_3: dy = 1; break; default: break; } switch (device->last_mousekeys_key) { case XKB_KEY_KP_Home: case XKB_KEY_KP_7: case XKB_KEY_KP_Left: case XKB_KEY_KP_4: case XKB_KEY_KP_End: case XKB_KEY_KP_1: dx = -1; break; case XKB_KEY_KP_Page_Up: case XKB_KEY_KP_9: case XKB_KEY_KP_Right: case XKB_KEY_KP_6: case XKB_KEY_KP_Page_Down: case XKB_KEY_KP_3: dx = 1; break; default: break; } if (dx != 0 || dy != 0) emulate_pointer_motion (device, dx, dy); /* We reschedule each time */ return G_SOURCE_REMOVE; } static void stop_mousekeys_move (ClutterInputDeviceEvdev *device) { device->mousekeys_first_motion_time = 0; device->mousekeys_last_motion_time = 0; if (device->move_mousekeys_timer) { g_source_remove (device->move_mousekeys_timer); device->move_mousekeys_timer = 0; } } static void start_mousekeys_move (ClutterEvent *event, ClutterInputDeviceEvdev *device) { device->last_mousekeys_key = event->key.keyval; if (device->move_mousekeys_timer != 0) return; trigger_mousekeys_move (device); } static gboolean handle_mousekeys_press (ClutterEvent *event, ClutterInputDeviceEvdev *device) { if (!(event->key.flags & CLUTTER_EVENT_FLAG_SYNTHETIC)) stop_mousekeys_move (device); /* Button selection */ switch (event->key.keyval) { case XKB_KEY_KP_Divide: device->mousekeys_btn = BTN_LEFT; return TRUE; case XKB_KEY_KP_Multiply: device->mousekeys_btn = BTN_MIDDLE; return TRUE; case XKB_KEY_KP_Subtract: device->mousekeys_btn = BTN_RIGHT; return TRUE; default: break; } /* Button events */ switch (event->key.keyval) { case XKB_KEY_KP_Begin: case XKB_KEY_KP_5: emulate_button_click (device); return TRUE; case XKB_KEY_KP_Insert: case XKB_KEY_KP_0: emulate_button_press (device); return TRUE; case XKB_KEY_KP_Decimal: case XKB_KEY_KP_Delete: emulate_button_release (device); return TRUE; case XKB_KEY_KP_Add: emulate_button_click (device); emulate_button_click (device); return TRUE; default: break; } /* Pointer motion */ switch (event->key.keyval) { case XKB_KEY_KP_1: case XKB_KEY_KP_2: case XKB_KEY_KP_3: case XKB_KEY_KP_4: case XKB_KEY_KP_6: case XKB_KEY_KP_7: case XKB_KEY_KP_8: case XKB_KEY_KP_9: case XKB_KEY_KP_Down: case XKB_KEY_KP_End: case XKB_KEY_KP_Home: case XKB_KEY_KP_Left: case XKB_KEY_KP_Page_Down: case XKB_KEY_KP_Page_Up: case XKB_KEY_KP_Right: case XKB_KEY_KP_Up: start_mousekeys_move (event, device); return TRUE; default: break; } return FALSE; } static gboolean handle_mousekeys_release (ClutterEvent *event, ClutterInputDeviceEvdev *device) { switch (event->key.keyval) { case XKB_KEY_KP_0: case XKB_KEY_KP_1: case XKB_KEY_KP_2: case XKB_KEY_KP_3: case XKB_KEY_KP_4: case XKB_KEY_KP_5: case XKB_KEY_KP_6: case XKB_KEY_KP_7: case XKB_KEY_KP_8: case XKB_KEY_KP_9: case XKB_KEY_KP_Add: case XKB_KEY_KP_Begin: case XKB_KEY_KP_Decimal: case XKB_KEY_KP_Delete: case XKB_KEY_KP_Divide: case XKB_KEY_KP_Down: case XKB_KEY_KP_End: case XKB_KEY_KP_Home: case XKB_KEY_KP_Insert: case XKB_KEY_KP_Left: case XKB_KEY_KP_Multiply: case XKB_KEY_KP_Page_Down: case XKB_KEY_KP_Page_Up: case XKB_KEY_KP_Right: case XKB_KEY_KP_Subtract: case XKB_KEY_KP_Up: stop_mousekeys_move (device); return TRUE; default: break; } return FALSE; } static void clutter_input_device_evdev_process_kbd_a11y_event (ClutterEvent *event, ClutterInputDevice *device, ClutterEmitInputDeviceEvent emit_event_func) { ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); /* Ignore key events injected from IM */ if (event->key.flags & CLUTTER_EVENT_FLAG_INPUT_METHOD) goto emit_event; if (!(device_evdev->a11y_flags & CLUTTER_A11Y_KEYBOARD_ENABLED)) goto emit_event; if (device_evdev->a11y_flags & CLUTTER_A11Y_MOUSE_KEYS_ENABLED) { if (event->type == CLUTTER_KEY_PRESS && handle_mousekeys_press (event, device_evdev)) return; /* swallow event */ if (event->type == CLUTTER_KEY_RELEASE && handle_mousekeys_release (event, device_evdev)) return; /* swallow event */ } if (device_evdev->a11y_flags & CLUTTER_A11Y_TOGGLE_KEYS_ENABLED) { if (event->type == CLUTTER_KEY_PRESS) handle_togglekeys_press (event, device_evdev); else handle_togglekeys_release (event, device_evdev); } if ((device_evdev->a11y_flags & CLUTTER_A11Y_BOUNCE_KEYS_ENABLED) && (get_debounce_delay (device) != 0)) { if ((event->type == CLUTTER_KEY_PRESS) && debounce_key (event, device_evdev)) { notify_bounce_keys_reject (device_evdev); return; } else if (event->type == CLUTTER_KEY_RELEASE) start_bounce_keys (event, device_evdev); } if ((device_evdev->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_ENABLED) && (get_slow_keys_delay (device) != 0)) { if (event->type == CLUTTER_KEY_PRESS) start_slow_keys (event, device_evdev, emit_event_func); else if (event->type == CLUTTER_KEY_RELEASE) stop_slow_keys (event, device_evdev, emit_event_func); return; } if (device_evdev->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_ENABLED) { if (event->type == CLUTTER_KEY_PRESS) handle_stickykeys_press (event, device_evdev); else if (event->type == CLUTTER_KEY_RELEASE) handle_stickykeys_release (event, device_evdev); } emit_event: emit_event_func (event, device); } void clutter_input_device_evdev_apply_kbd_a11y_settings (ClutterInputDeviceEvdev *device, ClutterKbdA11ySettings *settings) { ClutterKeyboardA11yFlags changed_flags = (device->a11y_flags ^ settings->controls); if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_SLOW_KEYS_ENABLED)) clear_slow_keys (device); if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_BOUNCE_KEYS_ENABLED)) device->debounce_key = 0; if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_STICKY_KEYS_ENABLED)) { device->stickykeys_depressed_mask = 0; update_internal_xkb_state (device, 0, 0); } if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_TOGGLE_KEYS_ENABLED)) { device->toggle_slowkeys_timer = 0; device->shift_count = 0; device->last_shift_time = 0; } if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_MOUSE_KEYS_ENABLED)) { if (settings->controls & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_MOUSE_KEYS_ENABLED)) enable_mousekeys (device); else disable_mousekeys (device); } update_mousekeys_params (device, settings); /* Keep our own copy of keyboard a11y features flags to see what changes */ device->a11y_flags = settings->controls; } static void release_device_touch_slot (gpointer value) { ClutterTouchState *touch_state = value; clutter_seat_evdev_release_touch_state (touch_state->seat, touch_state); } ClutterTouchState * clutter_input_device_evdev_acquire_touch_state (ClutterInputDeviceEvdev *device, int device_slot) { ClutterTouchState *touch_state; touch_state = clutter_seat_evdev_acquire_touch_state (device->seat, device_slot); g_hash_table_insert (device->touches, GINT_TO_POINTER (device_slot), touch_state); return touch_state; } ClutterTouchState * clutter_input_device_evdev_lookup_touch_state (ClutterInputDeviceEvdev *device, int device_slot) { return g_hash_table_lookup (device->touches, GINT_TO_POINTER (device_slot)); } void clutter_input_device_evdev_release_touch_state (ClutterInputDeviceEvdev *device, ClutterTouchState *touch_state) { g_hash_table_remove (device->touches, GINT_TO_POINTER (touch_state->device_slot)); } static void clutter_input_device_evdev_class_init (ClutterInputDeviceEvdevClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = clutter_input_device_evdev_finalize; object_class->set_property = clutter_input_device_evdev_set_property; object_class->get_property = clutter_input_device_evdev_get_property; klass->keycode_to_evdev = clutter_input_device_evdev_keycode_to_evdev; klass->update_from_tool = clutter_input_device_evdev_update_from_tool; klass->is_mode_switch_button = clutter_input_device_evdev_is_mode_switch_button; klass->get_group_n_modes = clutter_input_device_evdev_get_group_n_modes; klass->is_grouped = clutter_input_device_evdev_is_grouped; klass->process_kbd_a11y_event = clutter_input_device_evdev_process_kbd_a11y_event; obj_props[PROP_DEVICE_MATRIX] = g_param_spec_boxed ("device-matrix", P_("Device input matrix"), P_("Device input matrix"), CAIRO_GOBJECT_TYPE_MATRIX, CLUTTER_PARAM_READWRITE); obj_props[PROP_OUTPUT_ASPECT_RATIO] = g_param_spec_double ("output-aspect-ratio", P_("Output aspect ratio"), P_("Output aspect ratio"), 0, G_MAXDOUBLE, 0, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (object_class, N_PROPS, obj_props); } static void clutter_input_device_evdev_init (ClutterInputDeviceEvdev *self) { cairo_matrix_init_identity (&self->device_matrix); self->device_aspect_ratio = 0; self->output_ratio = 0; self->touches = g_hash_table_new_full (NULL, NULL, NULL, release_device_touch_slot); } /* * _clutter_input_device_evdev_new: * @manager: the device manager * @seat: the seat the device will belong to * @libinput_device: the libinput device * * Create a new ClutterInputDevice given a libinput device and associate * it with the provided seat. */ ClutterInputDevice * _clutter_input_device_evdev_new (ClutterDeviceManager *manager, ClutterSeatEvdev *seat, struct libinput_device *libinput_device) { ClutterInputDeviceEvdev *device; ClutterInputDeviceType type; ClutterDeviceManagerEvdev *manager_evdev; gchar *vendor, *product; gint device_id, n_rings = 0, n_strips = 0, n_groups = 1; gchar *node_path; gdouble width, height; type = _clutter_input_device_evdev_determine_type (libinput_device); vendor = g_strdup_printf ("%.4x", libinput_device_get_id_vendor (libinput_device)); product = g_strdup_printf ("%.4x", libinput_device_get_id_product (libinput_device)); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); device_id = _clutter_device_manager_evdev_acquire_device_id (manager_evdev); node_path = g_strdup_printf ("/dev/input/%s", libinput_device_get_sysname (libinput_device)); if (libinput_device_has_capability (libinput_device, LIBINPUT_DEVICE_CAP_TABLET_PAD)) { n_rings = libinput_device_tablet_pad_get_num_rings (libinput_device); n_strips = libinput_device_tablet_pad_get_num_strips (libinput_device); n_groups = libinput_device_tablet_pad_get_num_mode_groups (libinput_device); } device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_EVDEV, "id", device_id, "name", libinput_device_get_name (libinput_device), "device-manager", manager, "device-type", type, "device-mode", CLUTTER_INPUT_MODE_SLAVE, "enabled", TRUE, "vendor-id", vendor, "product-id", product, "n-rings", n_rings, "n-strips", n_strips, "n-mode-groups", n_groups, "device-node", node_path, NULL); device->seat = seat; device->libinput_device = libinput_device; libinput_device_set_user_data (libinput_device, device); libinput_device_ref (libinput_device); free (vendor); free (product); free (node_path); if (libinput_device_get_size (libinput_device, &width, &height) == 0) device->device_aspect_ratio = width / height; return CLUTTER_INPUT_DEVICE (device); } /* * _clutter_input_device_evdev_new_virtual: * @manager: the device manager * @seat: the seat the device will belong to * @type: the input device type * * Create a new virtual ClutterInputDevice of the given type. */ ClutterInputDevice * _clutter_input_device_evdev_new_virtual (ClutterDeviceManager *manager, ClutterSeatEvdev *seat, ClutterInputDeviceType type, ClutterInputMode mode) { ClutterInputDeviceEvdev *device; ClutterDeviceManagerEvdev *manager_evdev; const char *name; gint device_id; switch (type) { case CLUTTER_KEYBOARD_DEVICE: name = "Virtual keyboard device for seat"; break; case CLUTTER_POINTER_DEVICE: name = "Virtual pointer device for seat"; break; case CLUTTER_TOUCHSCREEN_DEVICE: name = "Virtual touchscreen device for seat"; break; default: name = "Virtual device for seat"; break; }; manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager); device_id = _clutter_device_manager_evdev_acquire_device_id (manager_evdev); device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_EVDEV, "id", device_id, "name", name, "device-manager", manager, "device-type", type, "device-mode", mode, "enabled", TRUE, NULL); device->seat = seat; return CLUTTER_INPUT_DEVICE (device); } ClutterSeatEvdev * _clutter_input_device_evdev_get_seat (ClutterInputDeviceEvdev *device) { return device->seat; } void _clutter_input_device_evdev_update_leds (ClutterInputDeviceEvdev *device, enum libinput_led leds) { if (!device->libinput_device) return; libinput_device_led_update (device->libinput_device, leds); } ClutterInputDeviceType _clutter_input_device_evdev_determine_type (struct libinput_device *ldev) { /* This setting is specific to touchpads and alike, only in these * devices there is this additional layer of touch event interpretation. */ if (libinput_device_config_tap_get_finger_count (ldev) > 0) return CLUTTER_TOUCHPAD_DEVICE; else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_TABLET_TOOL)) return CLUTTER_TABLET_DEVICE; else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) return CLUTTER_PAD_DEVICE; else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_POINTER)) return CLUTTER_POINTER_DEVICE; else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_TOUCH)) return CLUTTER_TOUCHSCREEN_DEVICE; else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_KEYBOARD)) return CLUTTER_KEYBOARD_DEVICE; else return CLUTTER_EXTENSION_DEVICE; } /** * clutter_evdev_input_device_get_libinput_device: * @device: a #ClutterInputDevice * * Retrieves the libinput_device struct held in @device. * * Returns: The libinput_device struct * * Since: 1.20 * Stability: unstable **/ struct libinput_device * clutter_evdev_input_device_get_libinput_device (ClutterInputDevice *device) { ClutterInputDeviceEvdev *device_evdev; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_EVDEV (device), NULL); device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); return device_evdev->libinput_device; } /** * clutter_evdev_event_sequence_get_slot: * @sequence: a #ClutterEventSequence * * Retrieves the touch slot triggered by this @sequence * * Returns: the libinput touch slot. * * Since: 1.20 * Stability: unstable **/ gint32 clutter_evdev_event_sequence_get_slot (const ClutterEventSequence *sequence) { if (!sequence) return -1; return GPOINTER_TO_INT (sequence) - 1; } void clutter_input_device_evdev_translate_coordinates (ClutterInputDevice *device, ClutterStage *stage, gfloat *x, gfloat *y) { ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device); double min_x = 0, min_y = 0, max_x = 1, max_y = 1; gdouble stage_width, stage_height; double x_d, y_d; stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); x_d = *x / stage_width; y_d = *y / stage_height; /* Apply aspect ratio */ if (device_evdev->output_ratio > 0 && device_evdev->device_aspect_ratio > 0) { gdouble ratio = device_evdev->device_aspect_ratio / device_evdev->output_ratio; if (ratio > 1) x_d *= ratio; else if (ratio < 1) y_d *= 1 / ratio; } cairo_matrix_transform_point (&device_evdev->device_matrix, &min_x, &min_y); cairo_matrix_transform_point (&device_evdev->device_matrix, &max_x, &max_y); cairo_matrix_transform_point (&device_evdev->device_matrix, &x_d, &y_d); *x = CLAMP (x_d, MIN (min_x, max_x), MAX (min_x, max_x)) * stage_width; *y = CLAMP (y_d, MIN (min_y, max_y), MAX (min_y, max_y)) * stage_height; } void clutter_input_device_evdev_release_touch_slots (ClutterInputDeviceEvdev *device_evdev, uint64_t time_us) { GHashTableIter iter; ClutterTouchState *touch_state; g_hash_table_iter_init (&iter, device_evdev->touches); while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch_state)) { clutter_seat_evdev_notify_touch_event (touch_state->seat, CLUTTER_INPUT_DEVICE (device_evdev), CLUTTER_TOUCH_CANCEL, time_us, touch_state->seat_slot, touch_state->coords.x, touch_state->coords.y); g_hash_table_iter_remove (&iter); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-backend.h������������������������������������������������������0000664�0001750�0001750�00000006302�14211404421�021521� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_BACKEND_H__ #define __CLUTTER_BACKEND_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <cairo.h> #include <pango/pango.h> #include <cogl/cogl.h> #include <clutter/clutter-config.h> #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_BACKEND (clutter_backend_get_type ()) #define CLUTTER_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND, ClutterBackend)) #define CLUTTER_IS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND)) /** * ClutterBackend: * * #ClutterBackend is an opaque structure whose * members cannot be directly accessed. * * Since: 0.4 */ typedef struct _ClutterBackend ClutterBackend; typedef struct _ClutterBackendClass ClutterBackendClass; CLUTTER_AVAILABLE_IN_ALL GType clutter_backend_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterBackend * clutter_get_default_backend (void); CLUTTER_AVAILABLE_IN_1_16 void clutter_set_windowing_backend (const char *backend_type); CLUTTER_AVAILABLE_IN_ALL gdouble clutter_backend_get_resolution (ClutterBackend *backend); CLUTTER_AVAILABLE_IN_ALL void clutter_backend_set_font_options (ClutterBackend *backend, const cairo_font_options_t *options); CLUTTER_AVAILABLE_IN_ALL const cairo_font_options_t * clutter_backend_get_font_options (ClutterBackend *backend); CLUTTER_AVAILABLE_IN_1_8 CoglContext * clutter_backend_get_cogl_context (ClutterBackend *backend); CLUTTER_AVAILABLE_IN_ALL void clutter_backend_bell_notify (ClutterBackend *backend); CLUTTER_AVAILABLE_IN_MUFFIN ClutterInputMethod * clutter_backend_get_input_method (ClutterBackend *backend); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_backend_set_input_method (ClutterBackend *backend, ClutterInputMethod *method); G_END_DECLS #endif /* __CLUTTER_BACKEND_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-event.c��������������������������������������������������������0000664�0001750�0001750�00000153601�14211404421�021253� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-backend-private.h" #include "clutter-debug.h" #include "clutter-event-private.h" #include "clutter-keysyms.h" #include "clutter-private.h" #include <math.h> /** * SECTION:clutter-event * @short_description: User and window system events * * Windowing events handled by Clutter. * * The events usually come from the windowing backend, but can also * be synthesized by Clutter itself or by the application code. */ typedef struct _ClutterEventPrivate { ClutterEvent base; ClutterInputDevice *device; ClutterInputDevice *source_device; gdouble delta_x; gdouble delta_y; ClutterInputDeviceTool *tool; gpointer platform_data; ClutterModifierType button_state; ClutterModifierType base_state; ClutterModifierType latched_state; ClutterModifierType locked_state; guint is_pointer_emulated : 1; } ClutterEventPrivate; typedef struct _ClutterEventFilter { int id; ClutterStage *stage; ClutterEventFilterFunc func; GDestroyNotify notify; gpointer user_data; } ClutterEventFilter; static GHashTable *all_events = NULL; G_DEFINE_BOXED_TYPE (ClutterEvent, clutter_event, clutter_event_copy, clutter_event_free); static ClutterEventSequence * clutter_event_sequence_copy (ClutterEventSequence *sequence) { /* Nothing to copy here */ return sequence; } static void clutter_event_sequence_free (ClutterEventSequence *sequence) { /* Nothing to free here */ } G_DEFINE_BOXED_TYPE (ClutterEventSequence, clutter_event_sequence, clutter_event_sequence_copy, clutter_event_sequence_free); static gboolean is_event_allocated (const ClutterEvent *event) { if (all_events == NULL) return FALSE; return g_hash_table_lookup (all_events, event) != NULL; } /* * _clutter_event_get_platform_data: * @event: a #ClutterEvent * * Retrieves the pointer to platform-specific data inside an event * * Return value: a pointer to platform-specific data * * Since: 1.4 */ gpointer _clutter_event_get_platform_data (const ClutterEvent *event) { if (!is_event_allocated (event)) return NULL; return ((ClutterEventPrivate *) event)->platform_data; } /*< private > * _clutter_event_set_platform_data: * @event: a #ClutterEvent * @data: a pointer to platform-specific data * * Sets the pointer to platform-specific data inside an event * * Since: 1.4 */ void _clutter_event_set_platform_data (ClutterEvent *event, gpointer data) { if (!is_event_allocated (event)) return; ((ClutterEventPrivate *) event)->platform_data = data; } void _clutter_event_set_pointer_emulated (ClutterEvent *event, gboolean is_emulated) { if (!is_event_allocated (event)) return; ((ClutterEventPrivate *) event)->is_pointer_emulated = !!is_emulated; } /** * clutter_event_type: * @event: a #ClutterEvent * * Retrieves the type of the event. * * Return value: a #ClutterEventType */ ClutterEventType clutter_event_type (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, CLUTTER_NOTHING); return event->type; } /** * clutter_event_get_time: * @event: a #ClutterEvent * * Retrieves the time of the event. * * Return value: the time of the event, or %CLUTTER_CURRENT_TIME * * Since: 0.4 */ guint32 clutter_event_get_time (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, CLUTTER_CURRENT_TIME); return event->any.time; } /** * clutter_event_set_time: * @event: a #ClutterEvent * @time_: the time of the event * * Sets the time of the event. * * Since: 1.8 */ void clutter_event_set_time (ClutterEvent *event, guint32 time_) { g_return_if_fail (event != NULL); event->any.time = time_; } /** * clutter_event_get_state: * @event: a #ClutterEvent * * Retrieves the modifier state of the event. In case the window system * supports reporting latched and locked modifiers, this function returns * the effective state. * * Return value: the modifier state parameter, or 0 * * Since: 0.4 */ ClutterModifierType clutter_event_get_state (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); switch (event->type) { case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: return event->key.modifier_state; case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: return event->button.modifier_state; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: return event->touch.modifier_state; case CLUTTER_MOTION: return event->motion.modifier_state; case CLUTTER_SCROLL: return event->scroll.modifier_state; default: break; } return 0; } /** * clutter_event_set_state: * @event: a #ClutterEvent * @state: the modifier state to set * * Sets the modifier state of the event. * * Since: 1.8 */ void clutter_event_set_state (ClutterEvent *event, ClutterModifierType state) { g_return_if_fail (event != NULL); switch (event->type) { case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: event->key.modifier_state = state; break; case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: event->button.modifier_state = state; break; case CLUTTER_MOTION: event->motion.modifier_state = state; break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: event->touch.modifier_state = state; break; case CLUTTER_SCROLL: event->scroll.modifier_state = state; break; default: break; } } void _clutter_event_set_state_full (ClutterEvent *event, ClutterModifierType button_state, ClutterModifierType base_state, ClutterModifierType latched_state, ClutterModifierType locked_state, ClutterModifierType effective_state) { ClutterEventPrivate *private = (ClutterEventPrivate*) event; private->button_state = button_state; private->base_state = base_state; private->latched_state = latched_state; private->locked_state = locked_state; clutter_event_set_state (event, effective_state); } /** * clutter_event_get_state_full: * @event: a #ClutterEvent * @button_state: (out) (allow-none): the pressed buttons as a mask * @base_state: (out) (allow-none): the regular pressed modifier keys * @latched_state: (out) (allow-none): the latched modifier keys (currently released but still valid for one key press/release) * @locked_state: (out) (allow-none): the locked modifier keys (valid until the lock key is pressed and released again) * @effective_state: (out) (allow-none): the logical OR of all the state bits above * * Retrieves the decomposition of the keyboard state into button, base, * latched, locked and effective. This can be used to transmit to other * applications, for example when implementing a wayland compositor. * * Since: 1.16 */ void clutter_event_get_state_full (const ClutterEvent *event, ClutterModifierType *button_state, ClutterModifierType *base_state, ClutterModifierType *latched_state, ClutterModifierType *locked_state, ClutterModifierType *effective_state) { const ClutterEventPrivate *private = (const ClutterEventPrivate*) event; g_return_if_fail (event != NULL); if (button_state) *button_state = private->button_state; if (base_state) *base_state = private->base_state; if (latched_state) *latched_state = private->latched_state; if (locked_state) *locked_state = private->locked_state; if (effective_state) *effective_state = clutter_event_get_state (event); } /** * clutter_event_get_coords: * @event: a #ClutterEvent * @x: (out): return location for the X coordinate, or %NULL * @y: (out): return location for the Y coordinate, or %NULL * * Retrieves the coordinates of @event and puts them into @x and @y. * * Since: 0.4 */ void clutter_event_get_coords (const ClutterEvent *event, gfloat *x, gfloat *y) { ClutterPoint coords; g_return_if_fail (event != NULL); clutter_event_get_position (event, &coords); if (x != NULL) *x = coords.x; if (y != NULL) *y = coords.y; } /** * clutter_event_get_position: * @event: a #ClutterEvent * @position: a #ClutterPoint * * Retrieves the event coordinates as a #ClutterPoint. * * Since: 1.12 */ void clutter_event_get_position (const ClutterEvent *event, ClutterPoint *position) { g_return_if_fail (event != NULL); g_return_if_fail (position != NULL); switch (event->type) { case CLUTTER_NOTHING: case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: case CLUTTER_STAGE_STATE: case CLUTTER_DESTROY_NOTIFY: case CLUTTER_CLIENT_MESSAGE: case CLUTTER_DELETE: case CLUTTER_EVENT_LAST: case CLUTTER_PROXIMITY_IN: case CLUTTER_PROXIMITY_OUT: case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: case CLUTTER_PAD_STRIP: case CLUTTER_PAD_RING: clutter_point_init (position, 0.f, 0.f); break; case CLUTTER_ENTER: case CLUTTER_LEAVE: clutter_point_init (position, event->crossing.x, event->crossing.y); break; case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: clutter_point_init (position, event->button.x, event->button.y); break; case CLUTTER_MOTION: clutter_point_init (position, event->motion.x, event->motion.y); break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: clutter_point_init (position, event->touch.x, event->touch.y); break; case CLUTTER_SCROLL: clutter_point_init (position, event->scroll.x, event->scroll.y); break; case CLUTTER_TOUCHPAD_PINCH: clutter_point_init (position, event->touchpad_pinch.x, event->touchpad_pinch.y); break; case CLUTTER_TOUCHPAD_SWIPE: clutter_point_init (position, event->touchpad_swipe.x, event->touchpad_swipe.y); break; } } /** * clutter_event_set_coords: * @event: a #ClutterEvent * @x: the X coordinate of the event * @y: the Y coordinate of the event * * Sets the coordinates of the @event. * * Since: 1.8 */ void clutter_event_set_coords (ClutterEvent *event, gfloat x, gfloat y) { g_return_if_fail (event != NULL); switch (event->type) { case CLUTTER_NOTHING: case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: case CLUTTER_STAGE_STATE: case CLUTTER_DESTROY_NOTIFY: case CLUTTER_CLIENT_MESSAGE: case CLUTTER_DELETE: case CLUTTER_EVENT_LAST: case CLUTTER_PROXIMITY_IN: case CLUTTER_PROXIMITY_OUT: case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: case CLUTTER_PAD_STRIP: case CLUTTER_PAD_RING: break; case CLUTTER_ENTER: case CLUTTER_LEAVE: event->crossing.x = x; event->crossing.y = y; break; case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: event->button.x = x; event->button.y = y; break; case CLUTTER_MOTION: event->motion.x = x; event->motion.y = y; break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: event->touch.x = x; event->touch.y = y; break; case CLUTTER_SCROLL: event->scroll.x = x; event->scroll.y = y; break; case CLUTTER_TOUCHPAD_PINCH: event->touchpad_pinch.x = x; event->touchpad_pinch.y = y; break; case CLUTTER_TOUCHPAD_SWIPE: event->touchpad_swipe.x = x; event->touchpad_swipe.y = y; break; } } /** * clutter_event_get_source: * @event: a #ClutterEvent * * Retrieves the source #ClutterActor the event originated from, or * NULL if the event has no source. * * Return value: (transfer none): a #ClutterActor * * Since: 0.6 */ ClutterActor * clutter_event_get_source (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, NULL); return event->any.source; } /** * clutter_event_set_source: * @event: a #ClutterEvent * @actor: (allow-none): a #ClutterActor, or %NULL * * Sets the source #ClutterActor of @event. * * Since: 1.8 */ void clutter_event_set_source (ClutterEvent *event, ClutterActor *actor) { g_return_if_fail (event != NULL); g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); event->any.source = actor; } /** * clutter_event_get_stage: * @event: a #ClutterEvent * * Retrieves the source #ClutterStage the event originated for, or * %NULL if the event has no stage. * * Return value: (transfer none): a #ClutterStage * * Since: 0.8 */ ClutterStage * clutter_event_get_stage (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, NULL); return event->any.stage; } /** * clutter_event_set_stage: * @event: a #ClutterEvent * @stage: (allow-none): a #ClutterStage, or %NULL * * Sets the source #ClutterStage of the event. * * Since: 1.8 */ void clutter_event_set_stage (ClutterEvent *event, ClutterStage *stage) { g_return_if_fail (event != NULL); g_return_if_fail (stage == NULL || CLUTTER_IS_STAGE (stage)); if (event->any.stage == stage) return; event->any.stage = stage; } /** * clutter_event_get_flags: * @event: a #ClutterEvent * * Retrieves the #ClutterEventFlags of @event * * Return value: the event flags * * Since: 1.0 */ ClutterEventFlags clutter_event_get_flags (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, CLUTTER_EVENT_NONE); return event->any.flags; } /** * clutter_event_set_flags: * @event: a #ClutterEvent * @flags: a binary OR of #ClutterEventFlags values * * Sets the #ClutterEventFlags of @event * * Since: 1.8 */ void clutter_event_set_flags (ClutterEvent *event, ClutterEventFlags flags) { g_return_if_fail (event != NULL); if (event->any.flags == flags) return; event->any.flags = flags; event->any.flags |= CLUTTER_EVENT_FLAG_SYNTHETIC; } /** * clutter_event_get_related: * @event: a #ClutterEvent of type %CLUTTER_ENTER or of * type %CLUTTER_LEAVE * * Retrieves the related actor of a crossing event. * * Return value: (transfer none): the related #ClutterActor, or %NULL * * Since: 1.0 */ ClutterActor * clutter_event_get_related (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, NULL); g_return_val_if_fail (event->type == CLUTTER_ENTER || event->type == CLUTTER_LEAVE, NULL); return event->crossing.related; } /** * clutter_event_set_related: * @event: a #ClutterEvent of type %CLUTTER_ENTER or %CLUTTER_LEAVE * @actor: (allow-none): a #ClutterActor or %NULL * * Sets the related actor of a crossing event * * Since: 1.8 */ void clutter_event_set_related (ClutterEvent *event, ClutterActor *actor) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_ENTER || event->type == CLUTTER_LEAVE); g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); if (event->crossing.related == actor) return; event->crossing.related = actor; } /** * clutter_event_set_scroll_delta: * @event: a #ClutterEvent of type %CLUTTER_SCROLL * @dx: delta on the horizontal axis * @dy: delta on the vertical axis * * Sets the precise scrolling information of @event. * * Since: 1.10 */ void clutter_event_set_scroll_delta (ClutterEvent *event, gdouble dx, gdouble dy) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_SCROLL); if (!is_event_allocated (event)) return; event->scroll.direction = CLUTTER_SCROLL_SMOOTH; ((ClutterEventPrivate *) event)->delta_x = dx; ((ClutterEventPrivate *) event)->delta_y = dy; } /** * clutter_event_get_scroll_delta: * @event: a #ClutterEvent of type %CLUTTER_SCROLL * @dx: (out): return location for the delta on the horizontal axis * @dy: (out): return location for the delta on the vertical axis * * Retrieves the precise scrolling information of @event. * * The @event has to have a #ClutterScrollEvent.direction value * of %CLUTTER_SCROLL_SMOOTH. * * Since: 1.10 */ void clutter_event_get_scroll_delta (const ClutterEvent *event, gdouble *dx, gdouble *dy) { gdouble delta_x, delta_y; g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_SCROLL); g_return_if_fail (event->scroll.direction == CLUTTER_SCROLL_SMOOTH); delta_x = delta_y = 0; if (is_event_allocated (event)) { delta_x = ((ClutterEventPrivate *) event)->delta_x; delta_y = ((ClutterEventPrivate *) event)->delta_y; } if (dx != NULL) *dx = delta_x; if (dy != NULL) *dy = delta_y; } /** * clutter_event_get_scroll_direction: * @event: a #ClutterEvent of type %CLUTTER_SCROLL * * Retrieves the direction of the scrolling of @event * * Return value: the scrolling direction * * Since: 1.0 */ ClutterScrollDirection clutter_event_get_scroll_direction (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, CLUTTER_SCROLL_UP); g_return_val_if_fail (event->type == CLUTTER_SCROLL, CLUTTER_SCROLL_UP); return event->scroll.direction; } /** * clutter_event_set_scroll_direction: * @event: a #ClutterEvent * @direction: the scrolling direction * * Sets the direction of the scrolling of @event * * Since: 1.8 */ void clutter_event_set_scroll_direction (ClutterEvent *event, ClutterScrollDirection direction) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_SCROLL); event->scroll.direction = direction; } /** * clutter_event_get_button: * @event: a #ClutterEvent of type %CLUTTER_BUTTON_PRESS or * of type %CLUTTER_BUTTON_RELEASE * * Retrieves the button number of @event * * Return value: the button number * * Since: 1.0 */ guint32 clutter_event_get_button (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_BUTTON_RELEASE || event->type == CLUTTER_PAD_BUTTON_PRESS || event->type == CLUTTER_PAD_BUTTON_RELEASE, 0); if (event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_BUTTON_RELEASE) return event->button.button; else return event->pad_button.button; } /** * clutter_event_set_button: * @event: a #ClutterEvent or type %CLUTTER_BUTTON_PRESS or * of type %CLUTTER_BUTTON_RELEASE * @button: the button number * * Sets the button number of @event * * Since: 1.8 */ void clutter_event_set_button (ClutterEvent *event, guint32 button) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_BUTTON_RELEASE); event->button.button = button; } /** * clutter_event_get_click_count: * @event: a #ClutterEvent of type %CLUTTER_BUTTON_PRESS or * of type %CLUTTER_BUTTON_RELEASE * * Retrieves the number of clicks of @event * * Return value: the click count * * Since: 1.0 */ guint32 clutter_event_get_click_count (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_BUTTON_RELEASE, 0); return event->button.click_count; } /* keys */ /** * clutter_event_get_key_symbol: * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS or * of type %CLUTTER_KEY_RELEASE * * Retrieves the key symbol of @event * * Return value: the key symbol representing the key * * Since: 1.0 */ guint clutter_event_get_key_symbol (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE, 0); return event->key.keyval; } /** * clutter_event_set_key_symbol: * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS * or %CLUTTER_KEY_RELEASE * @key_sym: the key symbol representing the key * * Sets the key symbol of @event. * * Since: 1.8 */ void clutter_event_set_key_symbol (ClutterEvent *event, guint key_sym) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE); event->key.keyval = key_sym; } /** * clutter_event_get_key_code: * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS or * of type %CLUTTER_KEY_RELEASE * * Retrieves the keycode of the key that caused @event * * Return value: The keycode representing the key * * Since: 1.0 */ guint16 clutter_event_get_key_code (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE, 0); return event->key.hardware_keycode; } /** * clutter_event_set_key_code: * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS * or %CLUTTER_KEY_RELEASE * @key_code: the keycode representing the key * * Sets the keycode of the @event. * * Since: 1.8 */ void clutter_event_set_key_code (ClutterEvent *event, guint16 key_code) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE); event->key.hardware_keycode = key_code; } /** * clutter_event_get_key_unicode: * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS * or %CLUTTER_KEY_RELEASE * * Retrieves the unicode value for the key that caused @keyev. * * Return value: The unicode value representing the key */ gunichar clutter_event_get_key_unicode (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE, 0); if (event->key.unicode_value) return event->key.unicode_value; else return clutter_keysym_to_unicode (event->key.keyval); } /** * clutter_event_set_key_unicode: * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS * or %CLUTTER_KEY_RELEASE * @key_unicode: the Unicode value representing the key * * Sets the Unicode value of @event. * * Since: 1.8 */ void clutter_event_set_key_unicode (ClutterEvent *event, gunichar key_unicode) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE); event->key.unicode_value = key_unicode; } /** * clutter_event_get_event_sequence: * @event: a #ClutterEvent of type %CLUTTER_TOUCH_BEGIN, * %CLUTTER_TOUCH_UPDATE, %CLUTTER_TOUCH_END, or * %CLUTTER_TOUCH_CANCEL * * Retrieves the #ClutterEventSequence of @event. * * Return value: (transfer none): the event sequence, or %NULL * * Since: 1.10 */ ClutterEventSequence * clutter_event_get_event_sequence (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, NULL); if (event->type == CLUTTER_TOUCH_BEGIN || event->type == CLUTTER_TOUCH_UPDATE || event->type == CLUTTER_TOUCH_END || event->type == CLUTTER_TOUCH_CANCEL) return event->touch.sequence; return NULL; } /** * clutter_event_get_device_id: * @event: a clutter event * * Retrieves the events device id if set. * * Return value: A unique identifier for the device or -1 if the event has * no specific device set. */ gint clutter_event_get_device_id (const ClutterEvent *event) { ClutterInputDevice *device = NULL; g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE); device = clutter_event_get_device (event); if (device != NULL) return clutter_input_device_get_device_id (device); return -1; } /** * clutter_event_get_device_type: * @event: a #ClutterEvent * * Retrieves the type of the device for @event * * Return value: the #ClutterInputDeviceType for the device, if * any is set * * Since: 1.0 */ ClutterInputDeviceType clutter_event_get_device_type (const ClutterEvent *event) { ClutterInputDevice *device = NULL; g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE); device = clutter_event_get_device (event); if (device != NULL) return clutter_input_device_get_device_type (device); return CLUTTER_POINTER_DEVICE; } /** * clutter_event_set_device: * @event: a #ClutterEvent * @device: (allow-none): a #ClutterInputDevice, or %NULL * * Sets the device for @event. * * Since: 1.6 */ void clutter_event_set_device (ClutterEvent *event, ClutterInputDevice *device) { g_return_if_fail (event != NULL); g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device)); if (is_event_allocated (event)) { ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; real_event->device = device; } switch (event->type) { case CLUTTER_NOTHING: case CLUTTER_STAGE_STATE: case CLUTTER_DESTROY_NOTIFY: case CLUTTER_CLIENT_MESSAGE: case CLUTTER_DELETE: case CLUTTER_EVENT_LAST: break; case CLUTTER_ENTER: case CLUTTER_LEAVE: event->crossing.device = device; break; case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: event->button.device = device; break; case CLUTTER_MOTION: event->motion.device = device; break; case CLUTTER_SCROLL: event->scroll.device = device; break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: event->touch.device = device; break; case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: event->key.device = device; break; case CLUTTER_TOUCHPAD_PINCH: case CLUTTER_TOUCHPAD_SWIPE: /* Rely on priv data for these */ break; case CLUTTER_PROXIMITY_IN: case CLUTTER_PROXIMITY_OUT: event->proximity.device = device; break; case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: event->pad_button.device = device; break; case CLUTTER_PAD_STRIP: event->pad_strip.device = device; break; case CLUTTER_PAD_RING: event->pad_ring.device = device; break; } } /** * clutter_event_get_device: * @event: a #ClutterEvent * * Retrieves the #ClutterInputDevice for the event. * If you want the physical device the event originated from, use * clutter_event_get_source_device(). * * The #ClutterInputDevice structure is completely opaque and should * be cast to the platform-specific implementation. * * Return value: (transfer none): the #ClutterInputDevice or %NULL. The * returned device is owned by the #ClutterEvent and it should not * be unreferenced * * Since: 1.0 */ ClutterInputDevice * clutter_event_get_device (const ClutterEvent *event) { ClutterInputDevice *device = NULL; g_return_val_if_fail (event != NULL, NULL); if (is_event_allocated (event)) { ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; if (real_event->device != NULL) return real_event->device; } switch (event->type) { case CLUTTER_NOTHING: case CLUTTER_STAGE_STATE: case CLUTTER_DESTROY_NOTIFY: case CLUTTER_CLIENT_MESSAGE: case CLUTTER_DELETE: case CLUTTER_EVENT_LAST: break; case CLUTTER_ENTER: case CLUTTER_LEAVE: device = event->crossing.device; break; case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: device = event->button.device; break; case CLUTTER_MOTION: device = event->motion.device; break; case CLUTTER_SCROLL: device = event->scroll.device; break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: device = event->touch.device; break; case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: device = event->key.device; break; case CLUTTER_TOUCHPAD_PINCH: case CLUTTER_TOUCHPAD_SWIPE: /* Rely on priv data for these */ break; case CLUTTER_PROXIMITY_IN: case CLUTTER_PROXIMITY_OUT: device = event->proximity.device; break; case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: device = event->pad_button.device; break; case CLUTTER_PAD_STRIP: device = event->pad_strip.device; break; case CLUTTER_PAD_RING: device = event->pad_ring.device; break; } return device; } /** * clutter_event_set_device_tool: * @event: a #ClutterEvent * @tool: (nullable): a #ClutterInputDeviceTool * * Sets the tool in use for this event * * Since: 1.28 **/ void clutter_event_set_device_tool (ClutterEvent *event, ClutterInputDeviceTool *tool) { g_return_if_fail (event != NULL); if (is_event_allocated (event)) { ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; real_event->tool = tool; } } /** * clutter_event_get_device_tool: * @event: a #ClutterEvent * * Returns the device tool that originated this event * * Returns: (transfer none): The tool of this event * * Since: 1.28 **/ ClutterInputDeviceTool * clutter_event_get_device_tool (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, NULL); if (is_event_allocated (event)) { ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; return real_event->tool; } return NULL; } /** * clutter_event_new: * @type: The type of event. * * Creates a new #ClutterEvent of the specified type. * * Return value: (transfer full): A newly allocated #ClutterEvent. */ ClutterEvent * clutter_event_new (ClutterEventType type) { ClutterEvent *new_event; ClutterEventPrivate *priv; priv = g_slice_new0 (ClutterEventPrivate); new_event = (ClutterEvent *) priv; new_event->type = new_event->any.type = type; if (G_UNLIKELY (all_events == NULL)) all_events = g_hash_table_new (NULL, NULL); g_hash_table_replace (all_events, priv, GUINT_TO_POINTER (1)); return new_event; } /** * clutter_event_copy: * @event: A #ClutterEvent. * * Copies @event. * * Return value: (transfer full): A newly allocated #ClutterEvent */ ClutterEvent * clutter_event_copy (const ClutterEvent *event) { ClutterEvent *new_event; ClutterEventPrivate *new_real_event; ClutterInputDevice *device; gint n_axes = 0; g_return_val_if_fail (event != NULL, NULL); new_event = clutter_event_new (CLUTTER_NOTHING); new_real_event = (ClutterEventPrivate *) new_event; *new_event = *event; if (is_event_allocated (event)) { ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; new_real_event->device = real_event->device; new_real_event->source_device = real_event->source_device; new_real_event->delta_x = real_event->delta_x; new_real_event->delta_y = real_event->delta_y; new_real_event->is_pointer_emulated = real_event->is_pointer_emulated; new_real_event->base_state = real_event->base_state; new_real_event->button_state = real_event->button_state; new_real_event->latched_state = real_event->latched_state; new_real_event->locked_state = real_event->locked_state; new_real_event->tool = real_event->tool; } device = clutter_event_get_device (event); if (device != NULL) n_axes = clutter_input_device_get_n_axes (device); switch (event->type) { case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: if (event->button.axes != NULL) new_event->button.axes = g_memdup (event->button.axes, sizeof (gdouble) * n_axes); break; case CLUTTER_SCROLL: if (event->scroll.axes != NULL) new_event->scroll.axes = g_memdup (event->scroll.axes, sizeof (gdouble) * n_axes); break; case CLUTTER_MOTION: if (event->motion.axes != NULL) new_event->motion.axes = g_memdup (event->motion.axes, sizeof (gdouble) * n_axes); break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: if (event->touch.axes != NULL) new_event->touch.axes = g_memdup (event->touch.axes, sizeof (gdouble) * n_axes); break; default: break; } if (is_event_allocated (event)) _clutter_backend_copy_event_data (clutter_get_default_backend (), event, new_event); return new_event; } /** * clutter_event_free: * @event: A #ClutterEvent. * * Frees all resources used by @event. */ void clutter_event_free (ClutterEvent *event) { if (G_LIKELY (event != NULL)) { _clutter_backend_free_event_data (clutter_get_default_backend (), event); switch (event->type) { case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: free (event->button.axes); break; case CLUTTER_MOTION: free (event->motion.axes); break; case CLUTTER_SCROLL: free (event->scroll.axes); break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: free (event->touch.axes); break; default: break; } g_hash_table_remove (all_events, event); g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event); } } /** * clutter_event_get: * * Pops an event off the event queue. Applications should not need to call * this. * * Return value: A #ClutterEvent or NULL if queue empty * * Since: 0.4 */ ClutterEvent * clutter_event_get (void) { ClutterMainContext *context = _clutter_context_get_default (); if (context->events_queue == NULL) return NULL; if (g_queue_is_empty (context->events_queue)) return NULL; return g_queue_pop_tail (context->events_queue); } /** * clutter_event_peek: * * Returns a pointer to the first event from the event queue but * does not remove it. * * Return value: (transfer none): A #ClutterEvent or NULL if queue empty. * * Since: 0.4 */ ClutterEvent * clutter_event_peek (void) { ClutterMainContext *context = _clutter_context_get_default (); g_return_val_if_fail (context != NULL, NULL); if (context->events_queue == NULL) return NULL; if (g_queue_is_empty (context->events_queue)) return NULL; return g_queue_peek_tail (context->events_queue); } void _clutter_event_push (const ClutterEvent *event, gboolean do_copy) { ClutterMainContext *context = _clutter_context_get_default (); ClutterInputDevice *device; g_assert (context != NULL); if (context->events_queue == NULL) context->events_queue = g_queue_new (); /* disabled devices don't propagate events */ device = clutter_event_get_device (event); if (device != NULL) { if (!clutter_input_device_get_enabled (device)) return; } if (do_copy) { ClutterEvent *copy; copy = clutter_event_copy (event); event = copy; } g_queue_push_head (context->events_queue, (gpointer) event); } /** * clutter_event_put: * @event: a #ClutterEvent * * Puts a copy of the event on the back of the event queue. The event will * have the %CLUTTER_EVENT_FLAG_SYNTHETIC flag set. If the source is set * event signals will be emitted for this source and capture/bubbling for * its ancestors. If the source is not set it will be generated by picking * or use the actor that currently has keyboard focus * * Since: 0.6 */ void clutter_event_put (const ClutterEvent *event) { _clutter_event_push (event, TRUE); } /** * clutter_events_pending: * * Checks if events are pending in the event queue. * * Return value: TRUE if there are pending events, FALSE otherwise. * * Since: 0.4 */ gboolean clutter_events_pending (void) { ClutterMainContext *context = _clutter_context_get_default (); g_return_val_if_fail (context != NULL, FALSE); if (context->events_queue == NULL) return FALSE; return g_queue_is_empty (context->events_queue) == FALSE; } /** * clutter_get_current_event_time: * * Retrieves the timestamp of the last event, if there is an * event or if the event has a timestamp. * * Return value: the event timestamp, or %CLUTTER_CURRENT_TIME * * Since: 1.0 */ guint32 clutter_get_current_event_time (void) { const ClutterEvent* event; event = clutter_get_current_event (); if (event != NULL) return clutter_event_get_time (event); return CLUTTER_CURRENT_TIME; } /** * clutter_get_current_event: * * If an event is currently being processed, return that event. * This function is intended to be used to access event state * that might not be exposed by higher-level widgets. For * example, to get the key modifier state from a Button 'clicked' * event. * * Return value: (transfer none): The current ClutterEvent, or %NULL if none * * Since: 1.2 */ const ClutterEvent * clutter_get_current_event (void) { ClutterMainContext *context = _clutter_context_get_default (); g_return_val_if_fail (context != NULL, NULL); return context->current_event != NULL ? context->current_event->data : NULL; } /** * clutter_event_get_source_device: * @event: a #ClutterEvent * * Retrieves the hardware device that originated the event. * * If you need the virtual device, use clutter_event_get_device(). * * If no hardware device originated this event, this function will * return the same device as clutter_event_get_device(). * * Return value: (transfer none): a pointer to a #ClutterInputDevice * or %NULL * * Since: 1.6 */ ClutterInputDevice * clutter_event_get_source_device (const ClutterEvent *event) { ClutterEventPrivate *real_event; if (!is_event_allocated (event)) return NULL; real_event = (ClutterEventPrivate *) event; if (real_event->source_device != NULL) return real_event->source_device; return clutter_event_get_device (event); } /** * clutter_event_set_source_device: * @event: a #ClutterEvent * @device: (allow-none): a #ClutterInputDevice * * Sets the source #ClutterInputDevice for @event. * * The #ClutterEvent must have been created using clutter_event_new(). * * Since: 1.8 */ void clutter_event_set_source_device (ClutterEvent *event, ClutterInputDevice *device) { ClutterEventPrivate *real_event; g_return_if_fail (event != NULL); g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device)); if (!is_event_allocated (event)) return; real_event = (ClutterEventPrivate *) event; real_event->source_device = device; } /** * clutter_event_get_axes: * @event: a #ClutterEvent * @n_axes: (out): return location for the number of axes returned * * Retrieves the array of axes values attached to the event. * * Return value: (transfer none): an array of axis values * * Since: 1.6 */ gdouble * clutter_event_get_axes (const ClutterEvent *event, guint *n_axes) { gdouble *retval = NULL; guint len = 0; switch (event->type) { case CLUTTER_NOTHING: case CLUTTER_STAGE_STATE: case CLUTTER_DESTROY_NOTIFY: case CLUTTER_CLIENT_MESSAGE: case CLUTTER_DELETE: case CLUTTER_ENTER: case CLUTTER_LEAVE: case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: case CLUTTER_EVENT_LAST: case CLUTTER_PROXIMITY_IN: case CLUTTER_PROXIMITY_OUT: break; case CLUTTER_SCROLL: retval = event->scroll.axes; break; case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: retval = event->button.axes; break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: retval = event->touch.axes; break; case CLUTTER_MOTION: retval = event->motion.axes; break; case CLUTTER_TOUCHPAD_PINCH: case CLUTTER_TOUCHPAD_SWIPE: case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: case CLUTTER_PAD_STRIP: case CLUTTER_PAD_RING: break; } if (retval != NULL) { ClutterInputDevice *device; device = clutter_event_get_device (event); if (device != NULL) len = clutter_input_device_get_n_axes (device); else retval = NULL; } if (n_axes) *n_axes = len; return retval; } /** * clutter_event_get_distance: * @source: a #ClutterEvent * @target: a #ClutterEvent * * Retrieves the distance between two events, a @source and a @target. * * Return value: the distance between two #ClutterEvent * * Since: 1.12 */ float clutter_event_get_distance (const ClutterEvent *source, const ClutterEvent *target) { ClutterPoint p0, p1; clutter_event_get_position (source, &p0); clutter_event_get_position (source, &p1); return clutter_point_distance (&p0, &p1, NULL, NULL); } /** * clutter_event_get_angle: * @source: a #ClutterEvent * @target: a #ClutterEvent * * Retrieves the angle relative from @source to @target. * * The direction of the angle is from the position X axis towards * the positive Y axis. * * Return value: the angle between two #ClutterEvent * * Since: 1.12 */ double clutter_event_get_angle (const ClutterEvent *source, const ClutterEvent *target) { ClutterPoint p0, p1; float x_distance, y_distance; double angle; clutter_event_get_position (source, &p0); clutter_event_get_position (target, &p1); if (clutter_point_equals (&p0, &p1)) return 0; clutter_point_distance (&p0, &p1, &x_distance, &y_distance); angle = atan2 (x_distance, y_distance); /* invert the angle, and shift it by 90 degrees */ angle = (2.0 * G_PI) - angle; angle += G_PI / 2.0; /* keep the angle within the [ 0, 360 ] interval */ angle = fmod (angle, 2.0 * G_PI); return angle; } /** * clutter_event_has_shift_modifier: * @event: a #ClutterEvent * * Checks whether @event has the Shift modifier mask set. * * Return value: %TRUE if the event has the Shift modifier mask set * * Since: 1.12 */ gboolean clutter_event_has_shift_modifier (const ClutterEvent *event) { return (clutter_event_get_state (event) & CLUTTER_SHIFT_MASK) != FALSE; } /** * clutter_event_has_control_modifier: * @event: a #ClutterEvent * * Checks whether @event has the Control modifier mask set. * * Return value: %TRUE if the event has the Control modifier mask set * * Since: 1.12 */ gboolean clutter_event_has_control_modifier (const ClutterEvent *event) { return (clutter_event_get_state (event) & CLUTTER_CONTROL_MASK) != FALSE; } /** * clutter_event_is_pointer_emulated: * @event: a #ClutterEvent * * Checks whether a pointer @event has been generated by the windowing * system. The returned value can be used to distinguish between events * synthesized by the windowing system itself (as opposed by Clutter). * * Return value: %TRUE if the event is pointer emulated * * Since: 1.12 */ gboolean clutter_event_is_pointer_emulated (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, FALSE); if (!is_event_allocated (event)) return FALSE; return ((ClutterEventPrivate *) event)->is_pointer_emulated; } gboolean _clutter_event_process_filters (ClutterEvent *event) { ClutterMainContext *context = _clutter_context_get_default (); GList *l, *next; /* Event filters are handled in order from least recently added to * most recently added */ for (l = context->event_filters; l; l = next) { ClutterEventFilter *event_filter = l->data; next = l->next; if (event_filter->stage && event_filter->stage != event->any.stage) continue; if (event_filter->func (event, event_filter->user_data) == CLUTTER_EVENT_STOP) return CLUTTER_EVENT_STOP; } return CLUTTER_EVENT_PROPAGATE; } /** * clutter_event_add_filter: * @stage: (allow-none): The #ClutterStage to capture events for * @func: The callback function which will be passed all events. * @notify: A #GDestroyNotify * @user_data: A data pointer to pass to the function. * * Adds a function which will be called for all events that Clutter * processes. The function will be called before any signals are * emitted for the event and it will take precedence over any grabs. * * Return value: an identifier for the event filter, to be used * with clutter_event_remove_filter(). * * Since: 1.18 */ guint clutter_event_add_filter (ClutterStage *stage, ClutterEventFilterFunc func, GDestroyNotify notify, gpointer user_data) { ClutterMainContext *context = _clutter_context_get_default (); ClutterEventFilter *event_filter = g_slice_new (ClutterEventFilter); static guint event_filter_id = 0; event_filter->stage = stage; event_filter->id = ++event_filter_id; event_filter->func = func; event_filter->notify = notify; event_filter->user_data = user_data; /* The event filters are kept in order from least recently added to * most recently added so we must add it to the end */ context->event_filters = g_list_append (context->event_filters, event_filter); return event_filter->id; } /** * clutter_event_remove_filter: * @id: The ID of the event filter, as returned from clutter_event_add_filter() * * Removes an event filter that was previously added with * clutter_event_add_filter(). * * Since: 1.18 */ void clutter_event_remove_filter (guint id) { ClutterMainContext *context = _clutter_context_get_default (); GList *l; for (l = context->event_filters; l; l = l->next) { ClutterEventFilter *event_filter = l->data; if (event_filter->id == id) { if (event_filter->notify) event_filter->notify (event_filter->user_data); context->event_filters = g_list_delete_link (context->event_filters, l); g_slice_free (ClutterEventFilter, event_filter); return; } } g_warning ("No event filter found for id: %d\n", id); } /** * clutter_event_get_touchpad_gesture_finger_count: * @event: a touchpad swipe/pinch event * * Returns the number of fingers that is triggering the touchpad gesture. * * Returns: the number of fingers in the gesture. * * Since: 1.24 **/ guint clutter_event_get_touchpad_gesture_finger_count (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_TOUCHPAD_SWIPE || event->type == CLUTTER_TOUCHPAD_PINCH, 0); if (event->type == CLUTTER_TOUCHPAD_SWIPE) return event->touchpad_swipe.n_fingers; else if (event->type == CLUTTER_TOUCHPAD_PINCH) return event->touchpad_pinch.n_fingers; return 0; } /** * clutter_event_get_gesture_pinch_angle_delta: * @event: a touchpad pinch event * * Returns the angle delta reported by this specific event. * * Returns: The angle delta relative to the previous event. * * Since: 1.24 **/ gdouble clutter_event_get_gesture_pinch_angle_delta (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH, 0); return event->touchpad_pinch.angle_delta; } /** * clutter_event_get_gesture_pinch_scale: * @event: a touchpad pinch event * * Returns the current scale as reported by @event, 1.0 being the original * distance at the time the corresponding event with phase * %CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN is received. * is received. * * Returns: the current pinch gesture scale * * Since: 1.24 **/ gdouble clutter_event_get_gesture_pinch_scale (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH, 0); return event->touchpad_pinch.scale; } /** * clutter_event_get_gesture_phase: * @event: a touchpad gesture event * * Returns the phase of the event, See #ClutterTouchpadGesturePhase. * * Returns: the phase of the gesture event. **/ ClutterTouchpadGesturePhase clutter_event_get_gesture_phase (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, 0); g_return_val_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH || event->type == CLUTTER_TOUCHPAD_SWIPE, 0); if (event->type == CLUTTER_TOUCHPAD_PINCH) return event->touchpad_pinch.phase; else if (event->type == CLUTTER_TOUCHPAD_SWIPE) return event->touchpad_swipe.phase; /* Shouldn't ever happen */ return CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN; }; /** * clutter_event_get_gesture_motion_delta: * @event: A clutter touchpad gesture event * @dx: (out) (allow-none): the displacement relative to the pointer * position in the X axis, or %NULL * @dy: (out) (allow-none): the displacement relative to the pointer * position in the Y axis, or %NULL * * Returns the gesture motion deltas relative to the current pointer * position. * * Since: 1.24 **/ void clutter_event_get_gesture_motion_delta (const ClutterEvent *event, gdouble *dx, gdouble *dy) { g_return_if_fail (event != NULL); g_return_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH || event->type == CLUTTER_TOUCHPAD_SWIPE); if (event->type == CLUTTER_TOUCHPAD_PINCH) { if (dx) *dx = event->touchpad_pinch.dx; if (dy) *dy = event->touchpad_pinch.dy; } else if (event->type == CLUTTER_TOUCHPAD_SWIPE) { if (dx) *dx = event->touchpad_swipe.dx; if (dy) *dy = event->touchpad_swipe.dy; } } /** * clutter_event_get_scroll_source: * @event: an scroll event * * Returns the #ClutterScrollSource that applies to an scroll event. * * Returns: The source of scroll events * * Since: 1.26 **/ ClutterScrollSource clutter_event_get_scroll_source (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, CLUTTER_SCROLL_SOURCE_UNKNOWN); g_return_val_if_fail (event->type == CLUTTER_SCROLL, CLUTTER_SCROLL_SOURCE_UNKNOWN); return event->scroll.scroll_source; } /** * clutter_event_get_scroll_finish_flags: * @event: an scroll event * * Returns the #ClutterScrollFinishFlags of an scroll event. Those * can be used to determine whether post-scroll effects like kinetic * scrolling should be applied. * * Returns: The scroll finish flags * * Since: 1.26 **/ ClutterScrollFinishFlags clutter_event_get_scroll_finish_flags (const ClutterEvent *event) { g_return_val_if_fail (event != NULL, CLUTTER_SCROLL_SOURCE_UNKNOWN); g_return_val_if_fail (event->type == CLUTTER_SCROLL, CLUTTER_SCROLL_SOURCE_UNKNOWN); return event->scroll.finish_flags; } guint clutter_event_get_mode_group (const ClutterEvent *event) { g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS || event->type == CLUTTER_PAD_BUTTON_RELEASE || event->type == CLUTTER_PAD_RING || event->type == CLUTTER_PAD_STRIP, 0); switch (event->type) { case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: return event->pad_button.group; case CLUTTER_PAD_RING: return event->pad_ring.group; case CLUTTER_PAD_STRIP: return event->pad_strip.group; default: return 0; } } /** * clutter_event_get_pad_event_details: * @event: a pad event * @number: (out) (optional): ring/strip/button number * @mode: (out) (optional): pad mode as per the event * @value: (out) (optional): event axis value * * Returns the details of a pad event. * * Returns: #TRUE if event details could be obtained **/ gboolean clutter_event_get_pad_event_details (const ClutterEvent *event, guint *number, guint *mode, gdouble *value) { guint n, m; gdouble v; g_return_val_if_fail (event != NULL, FALSE); g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS || event->type == CLUTTER_PAD_BUTTON_RELEASE || event->type == CLUTTER_PAD_RING || event->type == CLUTTER_PAD_STRIP, FALSE); switch (event->type) { case CLUTTER_PAD_BUTTON_PRESS: case CLUTTER_PAD_BUTTON_RELEASE: n = event->pad_button.button; m = event->pad_button.mode; v = 0.0; break; case CLUTTER_PAD_RING: n = event->pad_ring.ring_number; m = event->pad_ring.mode; v = event->pad_ring.angle; break; case CLUTTER_PAD_STRIP: n = event->pad_strip.strip_number; m = event->pad_strip.mode; v = event->pad_strip.value; break; default: return FALSE; } if (number) *number = n; if (mode) *mode = m; if (value) *value = v; return TRUE; } �������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-stage-view.h���������������������������������������������������0000664�0001750�0001750�00000006050�14211404421�022205� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_STAGE_VIEW_H__ #define __CLUTTER_STAGE_VIEW_H__ #include <cairo.h> #include <glib-object.h> #include <cogl/cogl.h> #include "clutter-macros.h" #define CLUTTER_TYPE_STAGE_VIEW (clutter_stage_view_get_type ()) CLUTTER_AVAILABLE_IN_MUFFIN G_DECLARE_DERIVABLE_TYPE (ClutterStageView, clutter_stage_view, CLUTTER, STAGE_VIEW, GObject) struct _ClutterStageViewClass { GObjectClass parent_class; void (* setup_offscreen_blit_pipeline) (ClutterStageView *view, CoglPipeline *pipeline); void (* get_offscreen_transformation_matrix) (ClutterStageView *view, CoglMatrix *matrix); }; CLUTTER_AVAILABLE_IN_MUFFIN void clutter_stage_view_get_layout (ClutterStageView *view, cairo_rectangle_int_t *rect); CLUTTER_AVAILABLE_IN_MUFFIN CoglFramebuffer *clutter_stage_view_get_framebuffer (ClutterStageView *view); CLUTTER_AVAILABLE_IN_MUFFIN CoglFramebuffer *clutter_stage_view_get_onscreen (ClutterStageView *view); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_stage_view_transform_to_onscreen (ClutterStageView *view, gfloat *x, gfloat *y); void clutter_stage_view_blit_offscreen (ClutterStageView *view, const cairo_rectangle_int_t *clip); CLUTTER_AVAILABLE_IN_MUFFIN float clutter_stage_view_get_scale (ClutterStageView *view); gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view); void clutter_stage_view_set_dirty_viewport (ClutterStageView *view, gboolean dirty); gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view); void clutter_stage_view_set_dirty_projection (ClutterStageView *view, gboolean dirty); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view, CoglMatrix *matrix); #endif /* __CLUTTER_STAGE_VIEW_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-pan-action.c���������������������������������������������������0000664�0001750�0001750�00000073206�14211404421�022165� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * Copyright (C) 2012, 2014 Collabora Ltd. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emanuele Aina <emanuele.aina@collabora.com> * * Based on ClutterDragAction, ClutterSwipeAction, and MxKineticScrollView, * written by: * Emmanuele Bassi <ebassi@linux.intel.com> * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> * Chris Lord <chris@linux.intel.com> */ /** * SECTION:clutter-pan-action * @Title: ClutterPanAction * @Short_Description: Action for pan gestures * * #ClutterPanAction is a sub-class of #ClutterGestureAction that implements * the logic for recognizing pan gestures. * * The simplest usage of #ClutterPanAction consists in adding it to * a #ClutterActor with a child and setting it as reactive; for instance, * the following code: * * |[ * clutter_actor_add_action (actor, clutter_pan_action_new ()); * clutter_actor_set_reactive (actor, TRUE); * ]| * * will automatically result in the actor children to be moved * when dragging. * * Since: 1.12 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-pan-action.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-gesture-action-private.h" #include "clutter-marshal.h" #include "clutter-private.h" #include <math.h> #define FLOAT_EPSILON (1e-15) static const gfloat min_velocity = 0.1f; // measured in px/ms static const gfloat reference_fps = 60.0f; // the fps assumed for the deceleration rate static const gfloat default_deceleration_rate = 0.95f; static const gfloat default_acceleration_factor = 1.0f; typedef enum { PAN_STATE_INACTIVE, PAN_STATE_PANNING, PAN_STATE_INTERPOLATING } PanState; typedef enum { SCROLL_PINNED_UNKNOWN, SCROLL_PINNED_NONE, SCROLL_PINNED_HORIZONTAL, SCROLL_PINNED_VERTICAL } PinState; struct _ClutterPanActionPrivate { ClutterPanAxis pan_axis; PanState state; /* Variables for storing acceleration information */ ClutterTimeline *deceleration_timeline; gfloat target_x; gfloat target_y; gfloat dx; gfloat dy; gdouble deceleration_rate; gdouble acceleration_factor; /* Inertial motion tracking */ gfloat interpolated_x; gfloat interpolated_y; gfloat release_x; gfloat release_y; guint should_interpolate : 1; PinState pin_state; }; enum { PROP_0, PROP_PAN_AXIS, PROP_INTERPOLATE, PROP_DECELERATION, PROP_ACCELERATION_FACTOR, PROP_LAST }; static GParamSpec *pan_props[PROP_LAST] = { NULL, }; enum { PAN, PAN_STOPPED, LAST_SIGNAL }; static guint pan_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterPanAction, clutter_pan_action, CLUTTER_TYPE_GESTURE_ACTION) static void emit_pan (ClutterPanAction *self, ClutterActor *actor, gboolean is_interpolated) { ClutterPanActionPrivate *priv = self->priv; gboolean retval; if (priv->pin_state == SCROLL_PINNED_UNKNOWN) { priv->pin_state = SCROLL_PINNED_NONE; if (priv->pan_axis == CLUTTER_PAN_AXIS_AUTO) { gfloat delta_x; gfloat delta_y; gfloat scroll_threshold = G_PI_4/2; gfloat drag_angle; clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self), 0, &delta_x, &delta_y); if (delta_x != 0.0f) drag_angle = atanf (delta_y / delta_x); else drag_angle = G_PI_2; if ((drag_angle > -scroll_threshold) && (drag_angle < scroll_threshold)) priv->pin_state = SCROLL_PINNED_HORIZONTAL; else if ((drag_angle > (G_PI_2 - scroll_threshold)) || (drag_angle < -(G_PI_2 - scroll_threshold))) priv->pin_state = SCROLL_PINNED_VERTICAL; } } g_signal_emit (self, pan_signals[PAN], 0, actor, is_interpolated, &retval); } static void emit_pan_stopped (ClutterPanAction *self, ClutterActor *actor) { ClutterPanActionPrivate *priv = self->priv; g_signal_emit (self, pan_signals[PAN_STOPPED], 0, actor); priv->state = PAN_STATE_INACTIVE; } static void on_deceleration_stopped (ClutterTimeline *timeline, gboolean is_finished, ClutterPanAction *self) { ClutterPanActionPrivate *priv = self->priv; ClutterActor *actor; g_object_unref (timeline); priv->deceleration_timeline = NULL; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); emit_pan_stopped (self, actor); } static void on_deceleration_new_frame (ClutterTimeline *timeline, gint elapsed_time, ClutterPanAction *self) { ClutterPanActionPrivate *priv = self->priv; ClutterActor *actor; gdouble progress; gfloat interpolated_x, interpolated_y; progress = clutter_timeline_get_progress (timeline); interpolated_x = priv->target_x * progress; interpolated_y = priv->target_y * progress; priv->dx = interpolated_x - priv->interpolated_x; priv->dy = interpolated_y - priv->interpolated_y; priv->interpolated_x = interpolated_x; priv->interpolated_y = interpolated_y; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); emit_pan (self, actor, TRUE); } static gboolean gesture_prepare (ClutterGestureAction *gesture, ClutterActor *actor) { ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); ClutterPanActionPrivate *priv = self->priv; if (priv->state == PAN_STATE_INTERPOLATING && priv->deceleration_timeline) clutter_timeline_stop (priv->deceleration_timeline); return TRUE; } static gboolean gesture_begin (ClutterGestureAction *gesture, ClutterActor *actor) { ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); ClutterPanActionPrivate *priv = self->priv; priv->pin_state = SCROLL_PINNED_UNKNOWN; priv->state = PAN_STATE_PANNING; priv->interpolated_x = priv->interpolated_y = 0.0f; priv->dx = priv->dy = 0.0f; return TRUE; } static gboolean gesture_progress (ClutterGestureAction *gesture, ClutterActor *actor) { ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); emit_pan (self, actor, FALSE); return TRUE; } static void gesture_cancel (ClutterGestureAction *gesture, ClutterActor *actor) { ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); ClutterPanActionPrivate *priv = self->priv; priv->state = PAN_STATE_INACTIVE; } static void gesture_end (ClutterGestureAction *gesture, ClutterActor *actor) { ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); ClutterPanActionPrivate *priv = self->priv; gfloat velocity, velocity_x, velocity_y; gfloat delta_x, delta_y; gfloat tau; gint duration; clutter_gesture_action_get_release_coords (CLUTTER_GESTURE_ACTION (self), 0, &priv->release_x, &priv->release_y); if (!priv->should_interpolate) { priv->state = PAN_STATE_INACTIVE; return; } priv->state = PAN_STATE_INTERPOLATING; clutter_gesture_action_get_motion_delta (gesture, 0, &delta_x, &delta_y); velocity = clutter_gesture_action_get_velocity (gesture, 0, &velocity_x, &velocity_y); /* Exponential timing constant v(t) = v(0) * exp(-t/tau) * tau = 1000ms / (frame_per_second * - ln(decay_per_frame)) * with frame_per_second = 60 and decay_per_frame = 0.95, tau ~= 325ms * see http://ariya.ofilabs.com/2011/10/flick-list-with-its-momentum-scrolling-and-deceleration.html */ tau = 1000.0f / (reference_fps * - logf (priv->deceleration_rate)); /* See where the decreasing velocity reaches $min_velocity px/ms * v(t) = v(0) * exp(-t/tau) = min_velocity * t = - tau * ln( min_velocity / |v(0)|) */ duration = - tau * logf (min_velocity / (ABS (velocity) * priv->acceleration_factor)); /* Target point: x(t) = v(0) * tau * [1 - exp(-t/tau)] */ priv->target_x = velocity_x * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau)); priv->target_y = velocity_y * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau)); if (ABS (velocity) * priv->acceleration_factor > min_velocity && duration > FLOAT_EPSILON) { priv->interpolated_x = priv->interpolated_y = 0.0f; priv->deceleration_timeline = clutter_timeline_new (duration); clutter_timeline_set_progress_mode (priv->deceleration_timeline, CLUTTER_EASE_OUT_EXPO); g_signal_connect (priv->deceleration_timeline, "new_frame", G_CALLBACK (on_deceleration_new_frame), self); g_signal_connect (priv->deceleration_timeline, "stopped", G_CALLBACK (on_deceleration_stopped), self); clutter_timeline_start (priv->deceleration_timeline); } else { emit_pan_stopped (self, actor); } } static gboolean clutter_pan_action_real_pan (ClutterPanAction *self, ClutterActor *actor, gboolean is_interpolated) { gfloat dx, dy; ClutterMatrix transform; clutter_pan_action_get_constrained_motion_delta (self, 0, &dx, &dy); clutter_actor_get_child_transform (actor, &transform); cogl_matrix_translate (&transform, dx, dy, 0.0f); clutter_actor_set_child_transform (actor, &transform); return TRUE; } static void clutter_pan_action_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterPanAction *self = CLUTTER_PAN_ACTION (gobject); switch (prop_id) { case PROP_PAN_AXIS: clutter_pan_action_set_pan_axis (self, g_value_get_enum (value)); break; case PROP_INTERPOLATE : clutter_pan_action_set_interpolate (self, g_value_get_boolean (value)); break; case PROP_DECELERATION : clutter_pan_action_set_deceleration (self, g_value_get_double (value)); break; case PROP_ACCELERATION_FACTOR : clutter_pan_action_set_acceleration_factor (self, g_value_get_double (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_pan_action_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterPanAction *self = CLUTTER_PAN_ACTION (gobject); ClutterPanActionPrivate *priv = self->priv; switch (prop_id) { case PROP_PAN_AXIS: g_value_set_enum (value, priv->pan_axis); break; case PROP_INTERPOLATE : g_value_set_boolean (value, priv->should_interpolate); break; case PROP_DECELERATION : g_value_set_double (value, priv->deceleration_rate); break; case PROP_ACCELERATION_FACTOR : g_value_set_double (value, priv->acceleration_factor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_pan_action_constructed (GObject *gobject) { ClutterGestureAction *gesture; gesture = CLUTTER_GESTURE_ACTION (gobject); clutter_gesture_action_set_threshold_trigger_edge (gesture, CLUTTER_GESTURE_TRIGGER_EDGE_AFTER); } static void clutter_pan_action_dispose (GObject *gobject) { ClutterPanActionPrivate *priv = CLUTTER_PAN_ACTION (gobject)->priv; g_clear_object (&priv->deceleration_timeline); G_OBJECT_CLASS (clutter_pan_action_parent_class)->dispose (gobject); } static void clutter_pan_action_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterPanAction *self = CLUTTER_PAN_ACTION (meta); ClutterPanActionPrivate *priv = self->priv; ClutterActor *old_actor; old_actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); if (old_actor != actor) { /* make sure we reset the state */ if (priv->state == PAN_STATE_INTERPOLATING) g_clear_object (&priv->deceleration_timeline); } CLUTTER_ACTOR_META_CLASS (clutter_pan_action_parent_class)->set_actor (meta, actor); } static void clutter_pan_action_class_init (ClutterPanActionClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); ClutterGestureActionClass *gesture_class = CLUTTER_GESTURE_ACTION_CLASS (klass); klass->pan = clutter_pan_action_real_pan; gesture_class->gesture_prepare = gesture_prepare; gesture_class->gesture_begin = gesture_begin; gesture_class->gesture_progress = gesture_progress; gesture_class->gesture_cancel = gesture_cancel; gesture_class->gesture_end = gesture_end; meta_class->set_actor = clutter_pan_action_set_actor; /** * ClutterPanAction:pan-axis: * * Constraints the panning action to the specified axis * * Since: 1.12 */ pan_props[PROP_PAN_AXIS] = g_param_spec_enum ("pan-axis", P_("Pan Axis"), P_("Constraints the panning to an axis"), CLUTTER_TYPE_PAN_AXIS, CLUTTER_PAN_AXIS_NONE, CLUTTER_PARAM_READWRITE); /** * ClutterPanAction:interpolate: * * Whether interpolated events emission is enabled. * * Since: 1.12 */ pan_props[PROP_INTERPOLATE] = g_param_spec_boolean ("interpolate", P_("Interpolate"), P_("Whether interpolated events emission is enabled."), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterPanAction:deceleration: * * The rate at which the interpolated panning will decelerate in * * #ClutterPanAction will emit interpolated ::pan events with decreasing * scroll deltas, using the rate specified by this property. * * Since: 1.12 */ pan_props[PROP_DECELERATION] = g_param_spec_double ("deceleration", P_("Deceleration"), P_("Rate at which the interpolated panning will decelerate in"), FLOAT_EPSILON, 1.0, default_deceleration_rate, CLUTTER_PARAM_READWRITE); /** * ClutterPanAction:acceleration-factor: * * The initial acceleration factor * * The kinetic momentum measured at the time of releasing the pointer will * be multiplied by the factor specified by this property before being used * to generate interpolated ::pan events. * * Since: 1.12 */ pan_props[PROP_ACCELERATION_FACTOR] = g_param_spec_double ("acceleration-factor", P_("Initial acceleration factor"), P_("Factor applied to the momentum when starting the interpolated phase"), 1.0, G_MAXDOUBLE, default_acceleration_factor, CLUTTER_PARAM_READWRITE); gobject_class->constructed = clutter_pan_action_constructed; gobject_class->set_property = clutter_pan_action_set_property; gobject_class->get_property = clutter_pan_action_get_property; gobject_class->dispose = clutter_pan_action_dispose; g_object_class_install_properties (gobject_class, PROP_LAST, pan_props); /** * ClutterPanAction::pan: * @action: the #ClutterPanAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @is_interpolated: if the event is the result of interpolating * the motion velocity at the end of the drag * * The ::pan signal is emitted to keep track of the motion during * a pan gesture. @is_interpolated is set to %TRUE during the * interpolation phase of the pan, after the drag has ended and * the :interpolate property was set to %TRUE. * * Return value: %TRUE if the pan should continue, and %FALSE if * the pan should be cancelled. * * Since: 1.12 */ pan_signals[PAN] = g_signal_new (I_("pan"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterPanActionClass, pan), _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT_BOOLEAN, G_TYPE_BOOLEAN, 2, CLUTTER_TYPE_ACTOR, G_TYPE_BOOLEAN); /** * ClutterPanAction::pan-stopped: * @action: the #ClutterPanAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::pan-stopped signal is emitted at the end of the interpolation * phase of the pan action, only when :interpolate is set to %TRUE. * * Since: 1.12 */ pan_signals[PAN_STOPPED] = g_signal_new (I_("pan-stopped"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterPanActionClass, pan_stopped), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); } static void clutter_pan_action_init (ClutterPanAction *self) { self->priv = clutter_pan_action_get_instance_private (self); self->priv->deceleration_rate = default_deceleration_rate; self->priv->acceleration_factor = default_acceleration_factor; self->priv->state = PAN_STATE_INACTIVE; } /** * clutter_pan_action_new: * * Creates a new #ClutterPanAction instance * * Return value: the newly created #ClutterPanAction * * Since: 1.12 */ ClutterAction * clutter_pan_action_new (void) { return g_object_new (CLUTTER_TYPE_PAN_ACTION, NULL); } /** * clutter_pan_action_set_pan_axis: * @self: a #ClutterPanAction * @axis: the axis to constraint the panning to * * Restricts the panning action to a specific axis * * Since: 1.12 */ void clutter_pan_action_set_pan_axis (ClutterPanAction *self, ClutterPanAxis axis) { ClutterPanActionPrivate *priv; g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); g_return_if_fail (axis >= CLUTTER_PAN_AXIS_NONE && axis <= CLUTTER_PAN_AXIS_AUTO); priv = self->priv; if (priv->pan_axis == axis) return; priv->pan_axis = axis; g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_PAN_AXIS]); } /** * clutter_pan_action_get_pan_axis: * @self: a #ClutterPanAction * * Retrieves the axis constraint set by clutter_pan_action_set_pan_axis() * * Return value: the axis constraint * * Since: 1.12 */ ClutterPanAxis clutter_pan_action_get_pan_axis (ClutterPanAction *self) { g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), CLUTTER_PAN_AXIS_NONE); return self->priv->pan_axis; } /** * clutter_pan_action_set_interpolate: * @self: a #ClutterPanAction * @should_interpolate: whether to enable interpolated pan events * * Sets whether the action should emit interpolated ::pan events * after the drag has ended, to emulate the gesture kinetic inertia. * * Since: 1.12 */ void clutter_pan_action_set_interpolate (ClutterPanAction *self, gboolean should_interpolate) { ClutterPanActionPrivate *priv; g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); priv = self->priv; should_interpolate = !!should_interpolate; if (priv->should_interpolate == should_interpolate) return; priv->should_interpolate = should_interpolate; g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_INTERPOLATE]); } /** * clutter_pan_action_get_interpolate: * @self: a #ClutterPanAction * * Checks if the action should emit ::pan events even after releasing * the pointer during a panning gesture, to emulate some kind of * kinetic inertia. * * Return value: %TRUE if interpolated events emission is active. * * Since: 1.12 */ gboolean clutter_pan_action_get_interpolate (ClutterPanAction *self) { g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), FALSE); return self->priv->should_interpolate; } /** * clutter_pan_action_set_deceleration: * @self: A #ClutterPanAction * @rate: The deceleration rate * * Sets the deceleration rate of the interpolated ::pan events generated * after a pan gesture. This is approximately the value that the momentum * at the time of releasing the pointer is divided by every 60th of a second. * * Since: 1.12 */ void clutter_pan_action_set_deceleration (ClutterPanAction *self, gdouble rate) { g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); g_return_if_fail (rate <= 1.0); g_return_if_fail (rate > 0.0); self->priv->deceleration_rate = rate; g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_DECELERATION]); } /** * clutter_pan_action_get_deceleration: * @self: A #ClutterPanAction * * Retrieves the deceleration rate of interpolated ::pan events. * * Return value: The deceleration rate of the interpolated events. * * Since: 1.12 */ gdouble clutter_pan_action_get_deceleration (ClutterPanAction *self) { g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 0.95); return self->priv->deceleration_rate; } /** * clutter_pan_action_set_acceleration_factor: * @self: A #ClutterPanAction * @factor: The acceleration factor * * Factor applied to the momentum velocity at the time of releasing the * pointer when generating interpolated ::pan events. * * Since: 1.12 */ void clutter_pan_action_set_acceleration_factor (ClutterPanAction *self, gdouble factor) { g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); g_return_if_fail (factor >= 0.0); self->priv->acceleration_factor = factor; g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_ACCELERATION_FACTOR]); } /** * clutter_pan_action_get_acceleration_factor: * @self: A #ClutterPanAction * * Retrieves the initial acceleration factor for interpolated ::pan events. * * Return value: The initial acceleration factor for interpolated events. * * Since: 1.12 */ gdouble clutter_pan_action_get_acceleration_factor (ClutterPanAction *self) { g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 1.0); return self->priv->acceleration_factor; } /** * clutter_pan_action_get_interpolated_coords: * @self: A #ClutterPanAction * @interpolated_x: (out) (allow-none): return location for the latest * interpolated event's X coordinate * @interpolated_y: (out) (allow-none): return location for the latest * interpolated event's Y coordinate * * Retrieves the coordinates, in stage space, of the latest interpolated * event, analogous to clutter_gesture_action_get_motion_coords(). * * Since: 1.12 */ void clutter_pan_action_get_interpolated_coords (ClutterPanAction *self, gfloat *interpolated_x, gfloat *interpolated_y) { ClutterPanActionPrivate *priv; g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); priv = self->priv; if (interpolated_x) *interpolated_x = priv->release_x + priv->interpolated_x; if (interpolated_y) *interpolated_y = priv->release_y + priv->interpolated_y; } /** * clutter_pan_action_get_interpolated_delta: * @self: A #ClutterPanAction * @delta_x: (out) (allow-none): return location for the X delta since * the latest interpolated event * @delta_y: (out) (allow-none): return location for the Y delta since * the latest interpolated event * * Retrieves the delta, in stage space, since the latest interpolated * event, analogous to clutter_gesture_action_get_motion_delta(). * * Return value: the distance since the latest interpolated event * * Since: 1.12 */ gfloat clutter_pan_action_get_interpolated_delta (ClutterPanAction *self, gfloat *delta_x, gfloat *delta_y) { ClutterPanActionPrivate *priv; g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 0.0f); priv = self->priv; if (delta_x) *delta_x = priv->dx; if (delta_y) *delta_y = priv->dy; return sqrt ((priv->dx * priv->dx) + (priv->dy * priv->dy)); } /** * clutter_pan_action_get_constrained_motion_delta: * @self: A #ClutterPanAction * @point: the touch point index, with 0 being the first touch * point received by the action * @delta_x: (out) (optional): return location for the X delta * @delta_y: (out) (optional): return location for the Y delta * * Retrieves the delta, in stage space, dependent on the current state * of the #ClutterPanAction, and respecting the constraint specified by the * #ClutterPanAction:pan-axis property. * * Return value: the distance since last motion event * * Since: 1.24 */ gfloat clutter_pan_action_get_constrained_motion_delta (ClutterPanAction *self, guint point, gfloat *out_delta_x, gfloat *out_delta_y) { ClutterPanActionPrivate *priv; gfloat delta_x = 0.f, delta_y = 0.f, distance; g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 0.0f); priv = self->priv; distance = clutter_pan_action_get_motion_delta (self, point, &delta_x, &delta_y); switch (priv->pan_axis) { case CLUTTER_PAN_AXIS_NONE: break; case CLUTTER_PAN_AXIS_AUTO: if (priv->pin_state == SCROLL_PINNED_VERTICAL) delta_x = 0.0f; else if (priv->pin_state == SCROLL_PINNED_HORIZONTAL) delta_y = 0.0f; break; case CLUTTER_PAN_X_AXIS: delta_y = 0.0f; break; case CLUTTER_PAN_Y_AXIS: delta_x = 0.0f; break; } if (out_delta_x) *out_delta_x = delta_x; if (out_delta_y) *out_delta_y = delta_y; return distance; } /** * clutter_pan_action_get_motion_delta: * @self: A #ClutterPanAction * @point: the touch point index, with 0 being the first touch * point received by the action * @delta_x: (out) (allow-none): return location for the X delta * @delta_y: (out) (allow-none): return location for the Y delta * * Retrieves the delta, in stage space, dependent on the current state * of the #ClutterPanAction. If it is inactive, both fields will be * set to 0. If it is panning by user action, the values will be equivalent * to those returned by clutter_gesture_action_get_motion_delta(). * If it is interpolating with some form of kinetic scrolling, the values * will be equivalent to those returned by * clutter_pan_action_get_interpolated_delta(). This is a convenience * method designed to be used in replacement "pan" signal handlers. * * Since: 1.14 */ gfloat clutter_pan_action_get_motion_delta (ClutterPanAction *self, guint point, gfloat *delta_x, gfloat *delta_y) { ClutterPanActionPrivate *priv; g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 0.0f); priv = self->priv; switch (priv->state) { case PAN_STATE_INACTIVE: if (delta_x) *delta_x = 0; if (delta_y) *delta_y = 0; return 0; case PAN_STATE_PANNING: return clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self), point, delta_x, delta_y); case PAN_STATE_INTERPOLATING: return clutter_pan_action_get_interpolated_delta (self, delta_x, delta_y); default: g_assert_not_reached (); } } /** * clutter_pan_action_get_motion_coords: * @self: A #ClutterPanAction * @point: the touch point index, with 0 being the first touch * point received by the action * @motion_x: (out) (allow-none): return location for the X coordinate * @motion_y: (out) (allow-none): return location for the Y coordinate * * Retrieves the coordinates, in stage space, dependent on the current state * of the #ClutterPanAction. If it is inactive, both fields will be * set to 0. If it is panning by user action, the values will be equivalent * to those returned by clutter_gesture_action_get_motion_coords(). * If it is interpolating with some form of kinetic scrolling, the values * will be equivalent to those returned by * clutter_pan_action_get_interpolated_coords(). This is a convenience * method designed to be used in replacement "pan" signal handlers. * * Since: 1.14 */ void clutter_pan_action_get_motion_coords (ClutterPanAction *self, guint point, gfloat *motion_x, gfloat *motion_y) { ClutterPanActionPrivate *priv; g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); priv = self->priv; switch (priv->state) { case PAN_STATE_INACTIVE: if (motion_x) *motion_x = 0; if (motion_y) *motion_y = 0; break; case PAN_STATE_PANNING: clutter_gesture_action_get_motion_coords (CLUTTER_GESTURE_ACTION (self), point, motion_x, motion_y); break; case PAN_STATE_INTERPOLATING: clutter_pan_action_get_interpolated_coords (self, motion_x, motion_y); break; default: g_assert_not_reached (); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-child-meta.c���������������������������������������������������0000664�0001750�0001750�00000011732�14211404421�022137� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * Jorn Baayen <jorn@openedhand.com> * Emmanuele Bassi <ebassi@openedhand.com> * Tomas Frydrych <tf@openedhand.com> * Øyvind Kolås <ok@openedhand.com> * * Copyright (C) 2008 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-child-meta * @short_description: Wrapper for actors inside a container * * #ClutterChildMeta is a wrapper object created by #ClutterContainer * implementations in order to store child-specific data and properties. * * A #ClutterChildMeta wraps a #ClutterActor inside a #ClutterContainer. * * #ClutterChildMeta is available since Clutter 0.8 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-child-meta.h" #include "clutter-container.h" #include "clutter-debug.h" #include "clutter-private.h" G_DEFINE_ABSTRACT_TYPE (ClutterChildMeta, clutter_child_meta, G_TYPE_OBJECT); enum { PROP_0, PROP_CONTAINER, PROP_ACTOR, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; static void clutter_child_meta_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterChildMeta *child_meta = CLUTTER_CHILD_META (object); switch (prop_id) { case PROP_CONTAINER: child_meta->container = g_value_get_object (value); break; case PROP_ACTOR: child_meta->actor = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_child_meta_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterChildMeta *child_meta = CLUTTER_CHILD_META (object); switch (prop_id) { case PROP_CONTAINER: g_value_set_object (value, child_meta->container); break; case PROP_ACTOR: g_value_set_object (value, child_meta->actor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_child_meta_class_init (ClutterChildMetaClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_child_meta_set_property; gobject_class->get_property = clutter_child_meta_get_property; /** * ClutterChildMeta:container: * * The #ClutterContainer that created this #ClutterChildMeta. * * Since: 0.8 */ obj_props[PROP_CONTAINER] = g_param_spec_object ("container", P_("Container"), P_("The container that created this data"), CLUTTER_TYPE_CONTAINER, G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE); /** * ClutterChildMeta:actor: * * The #ClutterActor being wrapped by this #ClutterChildMeta * * Since: 0.8 */ obj_props[PROP_ACTOR] = g_param_spec_object ("actor", P_("Actor"), P_("The actor wrapped by this data"), CLUTTER_TYPE_ACTOR, G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_child_meta_init (ClutterChildMeta *self) { } /** * clutter_child_meta_get_container: * @data: a #ClutterChildMeta * * Retrieves the container using @data * * Return value: (transfer none): a #ClutterContainer * * Since: 0.8 */ ClutterContainer * clutter_child_meta_get_container (ClutterChildMeta *data) { g_return_val_if_fail (CLUTTER_IS_CHILD_META (data), NULL); return data->container; } /** * clutter_child_meta_get_actor: * @data: a #ClutterChildMeta * * Retrieves the actor wrapped by @data * * Return value: (transfer none): a #ClutterActor * * Since: 0.8 */ ClutterActor * clutter_child_meta_get_actor (ClutterChildMeta *data) { g_return_val_if_fail (CLUTTER_IS_CHILD_META (data), NULL); return data->actor; } ��������������������������������������muffin-5.2.1/clutter/clutter/clutter-gesture-action.c�����������������������������������������������0000664�0001750�0001750�00000123335�14211404421�023064� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * Copyright (C) 2012 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> */ /** * SECTION:clutter-gesture-action * @Title: ClutterGestureAction * @Short_Description: Action for gesture gestures * * #ClutterGestureAction is a sub-class of #ClutterAction that implements * the logic for recognizing gesture gestures. It listens for low level events * such as #ClutterButtonEvent and #ClutterMotionEvent on the stage to raise * the #ClutterGestureAction::gesture-begin, #ClutterGestureAction::gesture-progress, * and #ClutterGestureAction::gesture-end signals. * * To use #ClutterGestureAction you just need to apply it to a #ClutterActor * using clutter_actor_add_action() and connect to the signals: * * |[<!-- language="C" --> * ClutterAction *action = clutter_gesture_action_new (); * * clutter_actor_add_action (actor, action); * * g_signal_connect (action, "gesture-begin", G_CALLBACK (on_gesture_begin), NULL); * g_signal_connect (action, "gesture-progress", G_CALLBACK (on_gesture_progress), NULL); * g_signal_connect (action, "gesture-end", G_CALLBACK (on_gesture_end), NULL); * ]| * * ## Creating Gesture actions * * A #ClutterGestureAction provides four separate states that can be * used to recognize or ignore gestures when writing a new action class: * * - Prepare -> Cancel * - Prepare -> Begin -> Cancel * - Prepare -> Begin -> End * - Prepare -> Begin -> Progress -> Cancel * - Prepare -> Begin -> Progress -> End * * Each #ClutterGestureAction starts in the "prepare" state, and calls * the #ClutterGestureActionClass.gesture_prepare() virtual function; this * state can be used to reset the internal state of a #ClutterGestureAction * subclass, but it can also immediately cancel a gesture without going * through the rest of the states. * * The "begin" state follows the "prepare" state, and calls the * #ClutterGestureActionClass.gesture_begin() virtual function. This state * signals the start of a gesture recognizing process. From the "begin" state * the gesture recognition process can successfully end, by going to the * "end" state; it can continue in the "progress" state, in case of a * continuous gesture; or it can be terminated, by moving to the "cancel" * state. * * In case of continuous gestures, the #ClutterGestureAction will use * the "progress" state, calling the #ClutterGestureActionClass.gesture_progress() * virtual function; the "progress" state will continue until the end of the * gesture, in which case the "end" state will be reached, or until the * gesture is cancelled, in which case the "cancel" gesture will be used * instead. * * Since: 1.8 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-gesture-action-private.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" #include <math.h> #define MAX_GESTURE_POINTS (10) #define FLOAT_EPSILON (1e-15) typedef struct { ClutterInputDevice *device; ClutterEventSequence *sequence; ClutterEvent *last_event; gfloat press_x, press_y; gint64 last_motion_time; gfloat last_motion_x, last_motion_y; gint64 last_delta_time; gfloat last_delta_x, last_delta_y; gfloat release_x, release_y; } GesturePoint; struct _ClutterGestureActionPrivate { ClutterActor *stage; gint requested_nb_points; GArray *points; guint actor_capture_id; gulong stage_capture_id; ClutterGestureTriggerEdge edge; float distance_x, distance_y; guint in_gesture : 1; }; enum { PROP_0, PROP_N_TOUCH_POINTS, PROP_THRESHOLD_TRIGGER_EDGE, PROP_THRESHOLD_TRIGGER_DISTANCE_X, PROP_THRESHOLD_TRIGGER_DISTANCE_Y, PROP_LAST }; enum { GESTURE_BEGIN, GESTURE_PROGRESS, GESTURE_END, GESTURE_CANCEL, LAST_SIGNAL }; static GParamSpec *gesture_props[PROP_LAST]; static guint gesture_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterGestureAction, clutter_gesture_action, CLUTTER_TYPE_ACTION) static GesturePoint * gesture_register_point (ClutterGestureAction *action, ClutterEvent *event) { ClutterGestureActionPrivate *priv = action->priv; GesturePoint *point = NULL; if (priv->points->len >= MAX_GESTURE_POINTS) return NULL; g_array_set_size (priv->points, priv->points->len + 1); point = &g_array_index (priv->points, GesturePoint, priv->points->len - 1); point->last_event = clutter_event_copy (event); point->device = clutter_event_get_device (event); clutter_event_get_coords (event, &point->press_x, &point->press_y); point->last_motion_x = point->press_x; point->last_motion_y = point->press_y; point->last_motion_time = clutter_event_get_time (event); point->last_delta_x = point->last_delta_y = 0; point->last_delta_time = 0; if (clutter_event_type (event) != CLUTTER_BUTTON_PRESS) point->sequence = clutter_event_get_event_sequence (event); else point->sequence = NULL; return point; } static GesturePoint * gesture_find_point (ClutterGestureAction *action, ClutterEvent *event, gint *position) { ClutterGestureActionPrivate *priv = action->priv; GesturePoint *point = NULL; ClutterEventType type = clutter_event_type (event); ClutterInputDevice *device = clutter_event_get_device (event); ClutterEventSequence *sequence = NULL; gint i; if ((type != CLUTTER_BUTTON_PRESS) && (type != CLUTTER_BUTTON_RELEASE) && (type != CLUTTER_MOTION)) sequence = clutter_event_get_event_sequence (event); for (i = 0; i < priv->points->len; i++) { if ((g_array_index (priv->points, GesturePoint, i).device == device) && (g_array_index (priv->points, GesturePoint, i).sequence == sequence)) { if (position != NULL) *position = i; point = &g_array_index (priv->points, GesturePoint, i); break; } } return point; } static void gesture_unregister_point (ClutterGestureAction *action, gint position) { ClutterGestureActionPrivate *priv = action->priv; if (action->priv->points->len == 0) return; g_array_remove_index (priv->points, position); } static void gesture_update_motion_point (GesturePoint *point, ClutterEvent *event) { gfloat motion_x, motion_y; gint64 _time; clutter_event_get_coords (event, &motion_x, &motion_y); clutter_event_free (point->last_event); point->last_event = clutter_event_copy (event); point->last_delta_x = motion_x - point->last_motion_x; point->last_delta_y = motion_y - point->last_motion_y; point->last_motion_x = motion_x; point->last_motion_y = motion_y; _time = clutter_event_get_time (event); point->last_delta_time = _time - point->last_motion_time; point->last_motion_time = _time; } static void gesture_update_release_point (GesturePoint *point, ClutterEvent *event) { gint64 _time; clutter_event_get_coords (event, &point->release_x, &point->release_y); clutter_event_free (point->last_event); point->last_event = clutter_event_copy (event); /* Treat the release event as the continuation of the last motion, * in case the user keeps the pointer still for a while before * releasing it. */ _time = clutter_event_get_time (event); point->last_delta_time += _time - point->last_motion_time; } static gint gesture_get_default_threshold (void) { gint threshold; ClutterSettings *settings = clutter_settings_get_default (); g_object_get (settings, "dnd-drag-threshold", &threshold, NULL); return threshold; } static gboolean gesture_point_pass_threshold (ClutterGestureAction *action, GesturePoint *point, ClutterEvent *event) { float threshold_x, threshold_y; gfloat motion_x, motion_y; clutter_event_get_coords (event, &motion_x, &motion_y); clutter_gesture_action_get_threshold_trigger_distance (action, &threshold_x, &threshold_y); if ((fabsf (point->press_y - motion_y) < threshold_y) && (fabsf (point->press_x - motion_x) < threshold_x)) return TRUE; return FALSE; } static void gesture_point_unset (GesturePoint *point) { clutter_event_free (point->last_event); } static void cancel_gesture (ClutterGestureAction *action) { ClutterGestureActionPrivate *priv = action->priv; ClutterActor *actor; priv->in_gesture = FALSE; if (priv->stage_capture_id != 0) { g_signal_handler_disconnect (priv->stage, priv->stage_capture_id); priv->stage_capture_id = 0; } actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); g_signal_emit (action, gesture_signals[GESTURE_CANCEL], 0, actor); g_array_set_size (action->priv->points, 0); } static gboolean begin_gesture (ClutterGestureAction *action, ClutterActor *actor) { ClutterGestureActionPrivate *priv = action->priv; gboolean return_value; priv->in_gesture = TRUE; if (!CLUTTER_GESTURE_ACTION_GET_CLASS (action)->gesture_prepare (action, actor)) { cancel_gesture (action); return FALSE; } /* clutter_gesture_action_cancel() may have been called during * gesture_prepare(), check that the gesture is still active. */ if (!priv->in_gesture) return FALSE; g_signal_emit (action, gesture_signals[GESTURE_BEGIN], 0, actor, &return_value); if (!return_value) { cancel_gesture (action); return FALSE; } return TRUE; } static gboolean stage_captured_event_cb (ClutterActor *stage, ClutterEvent *event, ClutterGestureAction *action) { ClutterGestureActionPrivate *priv = action->priv; ClutterActor *actor; gint position; float threshold_x, threshold_y; gboolean return_value; GesturePoint *point; ClutterEventType event_type; event_type = clutter_event_type (event); if (event_type != CLUTTER_TOUCH_CANCEL && event_type != CLUTTER_TOUCH_UPDATE && event_type != CLUTTER_TOUCH_END && event_type != CLUTTER_MOTION && event_type != CLUTTER_BUTTON_RELEASE) return CLUTTER_EVENT_PROPAGATE; if ((point = gesture_find_point (action, event, &position)) == NULL) return CLUTTER_EVENT_PROPAGATE; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); switch (clutter_event_type (event)) { case CLUTTER_MOTION: { ClutterModifierType mods = clutter_event_get_state (event); /* we might miss a button-release event in case of grabs, * so we need to check whether the button is still down * during a motion event */ if (!(mods & CLUTTER_BUTTON1_MASK)) { cancel_gesture (action); return CLUTTER_EVENT_PROPAGATE; } } /* Follow same code path as a touch event update */ case CLUTTER_TOUCH_UPDATE: if (!priv->in_gesture) { if (priv->points->len < priv->requested_nb_points) { gesture_update_motion_point (point, event); return CLUTTER_EVENT_PROPAGATE; } /* Wait until the drag threshold has been exceeded * before starting _TRIGGER_EDGE_AFTER gestures. */ if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER && gesture_point_pass_threshold (action, point, event)) { gesture_update_motion_point (point, event); return CLUTTER_EVENT_PROPAGATE; } if (!begin_gesture (action, actor)) { if ((point = gesture_find_point (action, event, &position)) != NULL) gesture_update_motion_point (point, event); return CLUTTER_EVENT_PROPAGATE; } if ((point = gesture_find_point (action, event, &position)) == NULL) return CLUTTER_EVENT_PROPAGATE; } gesture_update_motion_point (point, event); g_signal_emit (action, gesture_signals[GESTURE_PROGRESS], 0, actor, &return_value); if (!return_value) { cancel_gesture (action); return CLUTTER_EVENT_PROPAGATE; } /* Check if a _TRIGGER_EDGE_BEFORE gesture needs to be cancelled because * the drag threshold has been exceeded. */ clutter_gesture_action_get_threshold_trigger_distance (action, &threshold_x, &threshold_y); if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE && ((fabsf (point->press_y - point->last_motion_y) > threshold_y) || (fabsf (point->press_x - point->last_motion_x) > threshold_x))) { cancel_gesture (action); return CLUTTER_EVENT_PROPAGATE; } break; case CLUTTER_BUTTON_RELEASE: case CLUTTER_TOUCH_END: { gesture_update_release_point (point, event); if (priv->in_gesture && ((priv->points->len - 1) < priv->requested_nb_points)) { priv->in_gesture = FALSE; g_signal_emit (action, gesture_signals[GESTURE_END], 0, actor); } gesture_unregister_point (action, position); } break; case CLUTTER_TOUCH_CANCEL: { gesture_update_release_point (point, event); if (priv->in_gesture) { priv->in_gesture = FALSE; cancel_gesture (action); } gesture_unregister_point (action, position); } break; default: break; } if (priv->points->len == 0 && priv->stage_capture_id) { g_signal_handler_disconnect (priv->stage, priv->stage_capture_id); priv->stage_capture_id = 0; } return CLUTTER_EVENT_PROPAGATE; } static gboolean actor_captured_event_cb (ClutterActor *actor, ClutterEvent *event, ClutterGestureAction *action) { ClutterGestureActionPrivate *priv = action->priv; GesturePoint *point G_GNUC_UNUSED; if ((clutter_event_type (event) != CLUTTER_BUTTON_PRESS) && (clutter_event_type (event) != CLUTTER_TOUCH_BEGIN)) return CLUTTER_EVENT_PROPAGATE; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) return CLUTTER_EVENT_PROPAGATE; point = gesture_register_point (action, event); if (priv->stage == NULL) priv->stage = clutter_actor_get_stage (actor); if (priv->stage_capture_id == 0) priv->stage_capture_id = g_signal_connect_after (priv->stage, "captured-event", G_CALLBACK (stage_captured_event_cb), action); /* Start the gesture immediately if the gesture has no * _TRIGGER_EDGE_AFTER drag threshold. */ if ((priv->points->len >= priv->requested_nb_points) && (priv->edge != CLUTTER_GESTURE_TRIGGER_EDGE_AFTER)) begin_gesture (action, actor); return CLUTTER_EVENT_PROPAGATE; } static void clutter_gesture_action_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterGestureActionPrivate *priv = CLUTTER_GESTURE_ACTION (meta)->priv; ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (clutter_gesture_action_parent_class); if (priv->actor_capture_id != 0) { ClutterActor *old_actor = clutter_actor_meta_get_actor (meta); if (old_actor != NULL) g_signal_handler_disconnect (old_actor, priv->actor_capture_id); priv->actor_capture_id = 0; } if (priv->stage_capture_id != 0) { if (priv->stage != NULL) g_signal_handler_disconnect (priv->stage, priv->stage_capture_id); priv->stage_capture_id = 0; priv->stage = NULL; } if (actor != NULL) { priv->actor_capture_id = g_signal_connect (actor, "captured-event", G_CALLBACK (actor_captured_event_cb), meta); } meta_class->set_actor (meta, actor); } static gboolean default_event_handler (ClutterGestureAction *action, ClutterActor *actor) { return TRUE; } static void clutter_gesture_action_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterGestureAction *self = CLUTTER_GESTURE_ACTION (gobject); switch (prop_id) { case PROP_N_TOUCH_POINTS: clutter_gesture_action_set_n_touch_points (self, g_value_get_int (value)); break; case PROP_THRESHOLD_TRIGGER_EDGE: clutter_gesture_action_set_threshold_trigger_edge (self, g_value_get_enum (value)); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_X: clutter_gesture_action_set_threshold_trigger_distance (self, g_value_get_float (value), self->priv->distance_y); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_Y: clutter_gesture_action_set_threshold_trigger_distance (self, self->priv->distance_x, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_gesture_action_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterGestureAction *self = CLUTTER_GESTURE_ACTION (gobject); switch (prop_id) { case PROP_N_TOUCH_POINTS: g_value_set_int (value, self->priv->requested_nb_points); break; case PROP_THRESHOLD_TRIGGER_EDGE: g_value_set_enum (value, self->priv->edge); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_X: if (self->priv->distance_x > 0.0) g_value_set_float (value, self->priv->distance_x); else g_value_set_float (value, gesture_get_default_threshold ()); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_Y: if (self->priv->distance_y > 0.0) g_value_set_float (value, self->priv->distance_y); else g_value_set_float (value, gesture_get_default_threshold ()); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_gesture_action_finalize (GObject *gobject) { ClutterGestureActionPrivate *priv = CLUTTER_GESTURE_ACTION (gobject)->priv; g_array_unref (priv->points); G_OBJECT_CLASS (clutter_gesture_action_parent_class)->finalize (gobject); } static void clutter_gesture_action_class_init (ClutterGestureActionClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); gobject_class->finalize = clutter_gesture_action_finalize; gobject_class->set_property = clutter_gesture_action_set_property; gobject_class->get_property = clutter_gesture_action_get_property; meta_class->set_actor = clutter_gesture_action_set_actor; klass->gesture_begin = default_event_handler; klass->gesture_progress = default_event_handler; klass->gesture_prepare = default_event_handler; /** * ClutterGestureAction:n-touch-points: * * Number of touch points to trigger a gesture action. * * Since: 1.16 */ gesture_props[PROP_N_TOUCH_POINTS] = g_param_spec_int ("n-touch-points", P_("Number touch points"), P_("Number of touch points"), 1, G_MAXINT, 1, CLUTTER_PARAM_READWRITE); /** * ClutterGestureAction:threshold-trigger-edge: * * The trigger edge to be used by the action to either emit the * #ClutterGestureAction::gesture-begin signal or to emit the * #ClutterGestureAction::gesture-cancel signal. * * Since: 1.18 */ gesture_props[PROP_THRESHOLD_TRIGGER_EDGE] = g_param_spec_enum ("threshold-trigger-edge", P_("Threshold Trigger Edge"), P_("The trigger edge used by the action"), CLUTTER_TYPE_GESTURE_TRIGGER_EDGE, CLUTTER_GESTURE_TRIGGER_EDGE_NONE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterGestureAction:threshold-trigger-distance-x: * * The horizontal trigger distance to be used by the action to either * emit the #ClutterGestureAction::gesture-begin signal or to emit * the #ClutterGestureAction::gesture-cancel signal. * * A negative value will be interpreted as the default drag threshold. * * Since: 1.18 */ gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_X] = g_param_spec_float ("threshold-trigger-distance-x", P_("Threshold Trigger Horizontal Distance"), P_("The horizontal trigger distance used by the action"), -1.0, G_MAXFLOAT, -1.0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterGestureAction:threshold-trigger-distance-y: * * The vertical trigger distance to be used by the action to either * emit the #ClutterGestureAction::gesture-begin signal or to emit * the #ClutterGestureAction::gesture-cancel signal. * * A negative value will be interpreted as the default drag threshold. * * Since: 1.18 */ gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_Y] = g_param_spec_float ("threshold-trigger-distance-y", P_("Threshold Trigger Vertical Distance"), P_("The vertical trigger distance used by the action"), -1.0, G_MAXFLOAT, -1.0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (gobject_class, PROP_LAST, gesture_props); /** * ClutterGestureAction::gesture-begin: * @action: the #ClutterGestureAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::gesture_begin signal is emitted when the #ClutterActor to which * a #ClutterGestureAction has been applied starts receiving a gesture. * * Return value: %TRUE if the gesture should start, and %FALSE if * the gesture should be ignored. * * Since: 1.8 */ gesture_signals[GESTURE_BEGIN] = g_signal_new (I_("gesture-begin"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_begin), _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_ACTOR); /** * ClutterGestureAction::gesture-progress: * @action: the #ClutterGestureAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::gesture-progress signal is emitted for each motion event after * the #ClutterGestureAction::gesture-begin signal has been emitted. * * Return value: %TRUE if the gesture should continue, and %FALSE if * the gesture should be cancelled. * * Since: 1.8 */ gesture_signals[GESTURE_PROGRESS] = g_signal_new (I_("gesture-progress"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_progress), _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_ACTOR); /** * ClutterGestureAction::gesture-end: * @action: the #ClutterGestureAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::gesture-end signal is emitted at the end of the gesture gesture, * when the pointer's button is released * * This signal is emitted if and only if the #ClutterGestureAction::gesture-begin * signal has been emitted first. * * Since: 1.8 */ gesture_signals[GESTURE_END] = g_signal_new (I_("gesture-end"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_end), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterGestureAction::gesture-cancel: * @action: the #ClutterGestureAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::gesture-cancel signal is emitted when the ongoing gesture gets * cancelled from the #ClutterGestureAction::gesture-progress signal handler. * * This signal is emitted if and only if the #ClutterGestureAction::gesture-begin * signal has been emitted first. * * Since: 1.8 */ gesture_signals[GESTURE_CANCEL] = g_signal_new (I_("gesture-cancel"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_cancel), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); } static void clutter_gesture_action_init (ClutterGestureAction *self) { self->priv = clutter_gesture_action_get_instance_private (self); self->priv->points = g_array_sized_new (FALSE, TRUE, sizeof (GesturePoint), 3); g_array_set_clear_func (self->priv->points, (GDestroyNotify) gesture_point_unset); self->priv->requested_nb_points = 1; self->priv->edge = CLUTTER_GESTURE_TRIGGER_EDGE_NONE; } /** * clutter_gesture_action_new: * * Creates a new #ClutterGestureAction instance. * * Return value: the newly created #ClutterGestureAction * * Since: 1.8 */ ClutterAction * clutter_gesture_action_new (void) { return g_object_new (CLUTTER_TYPE_GESTURE_ACTION, NULL); } /** * clutter_gesture_action_get_press_coords: * @action: a #ClutterGestureAction * @point: the touch point index, with 0 being the first touch * point received by the action * @press_x: (out) (allow-none): return location for the press * event's X coordinate * @press_y: (out) (allow-none): return location for the press * event's Y coordinate * * Retrieves the coordinates, in stage space, of the press event * that started the dragging for a specific touch point. * * Since: 1.8 */ void clutter_gesture_action_get_press_coords (ClutterGestureAction *action, guint point, gfloat *press_x, gfloat *press_y) { g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); g_return_if_fail (action->priv->points->len > point); if (press_x) *press_x = g_array_index (action->priv->points, GesturePoint, point).press_x; if (press_y) *press_y = g_array_index (action->priv->points, GesturePoint, point).press_y; } /** * clutter_gesture_action_get_motion_coords: * @action: a #ClutterGestureAction * @point: the touch point index, with 0 being the first touch * point received by the action * @motion_x: (out) (allow-none): return location for the latest motion * event's X coordinate * @motion_y: (out) (allow-none): return location for the latest motion * event's Y coordinate * * Retrieves the coordinates, in stage space, of the latest motion * event during the dragging. * * Since: 1.8 */ void clutter_gesture_action_get_motion_coords (ClutterGestureAction *action, guint point, gfloat *motion_x, gfloat *motion_y) { g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); g_return_if_fail (action->priv->points->len > point); if (motion_x) *motion_x = g_array_index (action->priv->points, GesturePoint, point).last_motion_x; if (motion_y) *motion_y = g_array_index (action->priv->points, GesturePoint, point).last_motion_y; } /** * clutter_gesture_action_get_motion_delta: * @action: a #ClutterGestureAction * @point: the touch point index, with 0 being the first touch * point received by the action * @delta_x: (out) (allow-none): return location for the X axis * component of the incremental motion delta * @delta_y: (out) (allow-none): return location for the Y axis * component of the incremental motion delta * * Retrieves the incremental delta since the last motion event * during the dragging. * * Return value: the distance since last motion event * * Since: 1.12 */ gfloat clutter_gesture_action_get_motion_delta (ClutterGestureAction *action, guint point, gfloat *delta_x, gfloat *delta_y) { gfloat d_x, d_y; g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); g_return_val_if_fail (action->priv->points->len > point, 0); d_x = g_array_index (action->priv->points, GesturePoint, point).last_delta_x; d_y = g_array_index (action->priv->points, GesturePoint, point).last_delta_y; if (delta_x) *delta_x = d_x; if (delta_y) *delta_y = d_y; return sqrt ((d_x * d_x) + (d_y * d_y)); } /** * clutter_gesture_action_get_release_coords: * @action: a #ClutterGestureAction * @point: the touch point index, with 0 being the first touch * point received by the action * @release_x: (out) (allow-none): return location for the X coordinate of * the last release * @release_y: (out) (allow-none): return location for the Y coordinate of * the last release * * Retrieves the coordinates, in stage space, where the touch point was * last released. * * Since: 1.8 */ void clutter_gesture_action_get_release_coords (ClutterGestureAction *action, guint point, gfloat *release_x, gfloat *release_y) { g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); g_return_if_fail (action->priv->points->len > point); if (release_x) *release_x = g_array_index (action->priv->points, GesturePoint, point).release_x; if (release_y) *release_y = g_array_index (action->priv->points, GesturePoint, point).release_y; } /** * clutter_gesture_action_get_velocity: * @action: a #ClutterGestureAction * @point: the touch point index, with 0 being the first touch * point received by the action * @velocity_x: (out) (allow-none): return location for the latest motion * event's X velocity * @velocity_y: (out) (allow-none): return location for the latest motion * event's Y velocity * * Retrieves the velocity, in stage pixels per millisecond, of the * latest motion event during the dragging. * * Since: 1.12 */ gfloat clutter_gesture_action_get_velocity (ClutterGestureAction *action, guint point, gfloat *velocity_x, gfloat *velocity_y) { gfloat d_x, d_y, distance, velocity; gint64 d_t; g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); g_return_val_if_fail (action->priv->points->len > point, 0); distance = clutter_gesture_action_get_motion_delta (action, point, &d_x, &d_y); d_t = g_array_index (action->priv->points, GesturePoint, point).last_delta_time; if (velocity_x) *velocity_x = d_t > FLOAT_EPSILON ? d_x / d_t : 0; if (velocity_y) *velocity_y = d_t > FLOAT_EPSILON ? d_y / d_t : 0; velocity = d_t > FLOAT_EPSILON ? distance / d_t : 0; return velocity; } /** * clutter_gesture_action_get_n_touch_points: * @action: a #ClutterGestureAction * * Retrieves the number of requested points to trigger the gesture. * * Return value: the number of points to trigger the gesture. * * Since: 1.12 */ gint clutter_gesture_action_get_n_touch_points (ClutterGestureAction *action) { g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); return action->priv->requested_nb_points; } /** * clutter_gesture_action_set_n_touch_points: * @action: a #ClutterGestureAction * @nb_points: a number of points * * Sets the number of points needed to trigger the gesture. * * Since: 1.12 */ void clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action, gint nb_points) { ClutterGestureActionPrivate *priv; g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); g_return_if_fail (nb_points >= 1); priv = action->priv; if (priv->requested_nb_points == nb_points) return; priv->requested_nb_points = nb_points; if (priv->in_gesture) { if (priv->points->len < priv->requested_nb_points) cancel_gesture (action); } else if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER) { if (priv->points->len >= priv->requested_nb_points) { ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); gint i; float threshold_x, threshold_y; clutter_gesture_action_get_threshold_trigger_distance (action, &threshold_x, &threshold_y); for (i = 0; i < priv->points->len; i++) { GesturePoint *point = &g_array_index (priv->points, GesturePoint, i); if ((fabsf (point->press_y - point->last_motion_y) >= threshold_y) || (fabsf (point->press_x - point->last_motion_x) >= threshold_x)) { begin_gesture (action, actor); break; } } } } g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_N_TOUCH_POINTS]); } /** * clutter_gesture_action_get_n_current_points: * @action: a #ClutterGestureAction * * Retrieves the number of points currently active. * * Return value: the number of points currently active. * * Since: 1.12 */ guint clutter_gesture_action_get_n_current_points (ClutterGestureAction *action) { g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); return action->priv->points->len; } /** * clutter_gesture_action_get_sequence: * @action: a #ClutterGestureAction * @point: index of a point currently active * * Retrieves the #ClutterEventSequence of a touch point. * * Return value: (transfer none): the #ClutterEventSequence of a touch point. * * Since: 1.12 */ ClutterEventSequence * clutter_gesture_action_get_sequence (ClutterGestureAction *action, guint point) { g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL); g_return_val_if_fail (action->priv->points->len > point, NULL); return g_array_index (action->priv->points, GesturePoint, point).sequence; } /** * clutter_gesture_action_get_device: * @action: a #ClutterGestureAction * @point: the touch point index, with 0 being the first touch * point received by the action * * Retrieves the #ClutterInputDevice of a touch point. * * Return value: (transfer none): the #ClutterInputDevice of a touch point. * * Since: 1.12 */ ClutterInputDevice * clutter_gesture_action_get_device (ClutterGestureAction *action, guint point) { g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL); g_return_val_if_fail (action->priv->points->len > point, NULL); return g_array_index (action->priv->points, GesturePoint, point).device; } /** * clutter_gesture_action_get_last_event: * @action: a #ClutterGestureAction * @point: index of a point currently active * * Retrieves a reference to the last #ClutterEvent for a touch point. Call * clutter_event_copy() if you need to store the reference somewhere. * * Return value: (transfer none): the last #ClutterEvent for a touch point. * * Since: 1.14 */ const ClutterEvent * clutter_gesture_action_get_last_event (ClutterGestureAction *action, guint point) { GesturePoint *gesture_point; g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL); g_return_val_if_fail (action->priv->points->len > point, NULL); gesture_point = &g_array_index (action->priv->points, GesturePoint, point); return gesture_point->last_event; } /** * clutter_gesture_action_cancel: * @action: a #ClutterGestureAction * * Cancel a #ClutterGestureAction before it begins * * Since: 1.12 */ void clutter_gesture_action_cancel (ClutterGestureAction *action) { g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); cancel_gesture (action); } /** * clutter_gesture_action_set_threshold_trigger_edge: * @action: a #ClutterGestureAction * @edge: the %ClutterGestureTriggerEdge * * Sets the edge trigger for the gesture drag threshold, if any. * * This function should only be called by sub-classes of * #ClutterGestureAction during their construction phase. * * Since: 1.18 */ void clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction *action, ClutterGestureTriggerEdge edge) { g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); if (action->priv->edge == edge) return; action->priv->edge = edge; g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_EDGE]); } /** * clutter_gesture_action_get_threshold_trigger_edge: * @action: a #ClutterGestureAction * * Retrieves the edge trigger of the gesture @action, as set using * clutter_gesture_action_set_threshold_trigger_edge(). * * Return value: the edge trigger * * Since: 1.20 */ ClutterGestureTriggerEdge clutter_gesture_action_get_threshold_trigger_edge (ClutterGestureAction *action) { g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), CLUTTER_GESTURE_TRIGGER_EDGE_NONE); return action->priv->edge; } /** * clutter_gesture_action_get_threshold_trigger_egde: * @action: a #ClutterGestureAction * * Retrieves the edge trigger of the gesture @action, as set using * clutter_gesture_action_set_threshold_trigger_edge(). * * Return value: the edge trigger * * Since: 1.18 * * Deprecated: 1.20: Use clutter_gesture_action_get_threshold_trigger_edge() instead. */ ClutterGestureTriggerEdge clutter_gesture_action_get_threshold_trigger_egde (ClutterGestureAction *action) { return clutter_gesture_action_get_threshold_trigger_edge (action); } /** * clutter_gesture_action_set_threshold_trigger_distance: * @action: a #ClutterGestureAction * @x: the distance on the horizontal axis * @y: the distance on the vertical axis * * Sets the threshold trigger distance for the gesture drag threshold, if any. * * This function should only be called by sub-classes of * #ClutterGestureAction during their construction phase. * * Since: 1.18 */ void clutter_gesture_action_set_threshold_trigger_distance (ClutterGestureAction *action, float x, float y) { g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); if (fabsf (x - action->priv->distance_x) > FLOAT_EPSILON) { action->priv->distance_x = x; g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_X]); } if (fabsf (y - action->priv->distance_y) > FLOAT_EPSILON) { action->priv->distance_y = y; g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_Y]); } } /** * clutter_gesture_action_get_threshold_trigger_distance: * @action: a #ClutterGestureAction * @x: (out) (allow-none): The return location for the horizontal distance, or %NULL * @y: (out) (allow-none): The return location for the vertical distance, or %NULL * * Retrieves the threshold trigger distance of the gesture @action, * as set using clutter_gesture_action_set_threshold_trigger_distance(). * * Since: 1.18 */ void clutter_gesture_action_get_threshold_trigger_distance (ClutterGestureAction *action, float *x, float *y) { g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); if (x != NULL) { if (action->priv->distance_x > 0.0) *x = action->priv->distance_x; else *x = gesture_get_default_threshold (); } if (y != NULL) { if (action->priv->distance_y > 0.0) *y = action->priv->distance_y; else *y = gesture_get_default_threshold (); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-offscreen-effect.c���������������������������������������������0000664�0001750�0001750�00000052055�14211404421�023337� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Authors: * Emmanuele Bassi <ebassi@linux.intel.com> * Robert Bragg <robert@linux.intel.com> */ /** * SECTION:clutter-offscreen-effect * @short_description: Base class for effects using offscreen buffers * @see_also: #ClutterBlurEffect, #ClutterEffect * * #ClutterOffscreenEffect is an abstract class that can be used by * #ClutterEffect sub-classes requiring access to an offscreen buffer. * * Some effects, like the fragment shader based effects, can only use GL * textures, and in order to apply those effects to any kind of actor they * require that all drawing operations are applied to an offscreen framebuffer * that gets redirected to a texture. * * #ClutterOffscreenEffect provides all the heavy-lifting for creating the * offscreen framebuffer, the redirection and the final paint of the texture on * the desired stage. * * #ClutterOffscreenEffect is available since Clutter 1.4 * * ## Implementing a ClutterOffscreenEffect * * Creating a sub-class of #ClutterOffscreenEffect requires, in case * of overriding the #ClutterEffect virtual functions, to chain up to the * #ClutterOffscreenEffect's implementation. * * On top of the #ClutterEffect's virtual functions, * #ClutterOffscreenEffect also provides a #ClutterOffscreenEffectClass.paint_target() * function, which encapsulates the effective painting of the texture that * contains the result of the offscreen redirection. * * The size of the target material is defined to be as big as the * transformed size of the #ClutterActor using the offscreen effect. * Sub-classes of #ClutterOffscreenEffect can change the texture creation * code to provide bigger textures by overriding the * #ClutterOffscreenEffectClass.create_texture() virtual function; no chain up * to the #ClutterOffscreenEffect implementation is required in this * case. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-offscreen-effect.h" #include "cogl/cogl.h" #include "clutter-actor-private.h" #include "clutter-debug.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-paint-volume-private.h" #include "clutter-actor-box-private.h" struct _ClutterOffscreenEffectPrivate { CoglHandle offscreen; CoglPipeline *target; CoglHandle texture; ClutterActor *actor; ClutterActor *stage; ClutterVertex position; int fbo_offset_x; int fbo_offset_y; /* This is the calculated size of the fbo before being passed through create_texture(). This needs to be tracked separately so that we can detect when a different size is calculated and regenerate the fbo */ int fbo_width; int fbo_height; gint old_opacity_override; }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterOffscreenEffect, clutter_offscreen_effect, CLUTTER_TYPE_EFFECT) static void clutter_offscreen_effect_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (meta); ClutterOffscreenEffectPrivate *priv = self->priv; ClutterActorMetaClass *meta_class; meta_class = CLUTTER_ACTOR_META_CLASS (clutter_offscreen_effect_parent_class); meta_class->set_actor (meta, actor); /* clear out the previous state */ if (priv->offscreen != NULL) { cogl_handle_unref (priv->offscreen); priv->offscreen = NULL; } /* we keep a back pointer here, to avoid going through the ActorMeta */ priv->actor = clutter_actor_meta_get_actor (meta); } static CoglHandle clutter_offscreen_effect_real_create_texture (ClutterOffscreenEffect *effect, gfloat width, gfloat height) { return cogl_texture_new_with_size (MAX (width, 1), MAX (height, 1), COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888_PRE); } static gboolean update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height) { ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffectPrivate *priv = self->priv; priv->stage = clutter_actor_get_stage (priv->actor); if (priv->stage == NULL) { CLUTTER_NOTE (MISC, "The actor '%s' is not part of a stage", clutter_actor_get_name (priv->actor) == NULL ? G_OBJECT_TYPE_NAME (priv->actor) : clutter_actor_get_name (priv->actor)); return FALSE; } if (priv->fbo_width == fbo_width && priv->fbo_height == fbo_height && priv->offscreen != NULL) return TRUE; if (priv->target == NULL) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); priv->target = cogl_pipeline_new (ctx); /* We're always going to render the texture at a 1:1 texel:pixel ratio so we can use 'nearest' filtering to decrease the effects of rounding errors in the geometry calculation */ cogl_pipeline_set_layer_filters (priv->target, 0, /* layer_index */ COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); } if (priv->texture != NULL) { cogl_handle_unref (priv->texture); priv->texture = NULL; } if (priv->offscreen != NULL) { cogl_handle_unref (priv->offscreen); priv->offscreen = NULL; } priv->texture = clutter_offscreen_effect_create_texture (self, fbo_width, fbo_height); if (priv->texture == NULL) return FALSE; cogl_pipeline_set_layer_texture (priv->target, 0, priv->texture); priv->fbo_width = fbo_width; priv->fbo_height = fbo_height; priv->offscreen = cogl_offscreen_new_to_texture (priv->texture); if (priv->offscreen == NULL) { g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC); cogl_handle_unref (priv->target); priv->target = NULL; priv->fbo_width = 0; priv->fbo_height = 0; return FALSE; } return TRUE; } static gboolean clutter_offscreen_effect_pre_paint (ClutterEffect *effect) { ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffectPrivate *priv = self->priv; ClutterActorBox raw_box, box; ClutterActor *stage; CoglMatrix projection, old_modelview, modelview; const ClutterPaintVolume *volume; CoglColor transparent; gfloat stage_width, stage_height; gfloat fbo_width = -1, fbo_height = -1; ClutterVertex local_offset = { 0.f, 0.f, 0.f }; gfloat old_viewport[4]; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) return FALSE; if (priv->actor == NULL) return FALSE; stage = _clutter_actor_get_stage_internal (priv->actor); clutter_actor_get_size (stage, &stage_width, &stage_height); /* Get the minimal bounding box for what we want to paint, relative to the * parent of priv->actor. Note that we may actually be painting a clone of * priv->actor so we need to be careful to avoid querying the transformation * of priv->actor (like clutter_actor_get_paint_box would). Just stay in * local coordinates for now... */ volume = clutter_actor_get_paint_volume (priv->actor); if (volume) { ClutterPaintVolume mutable_volume; _clutter_paint_volume_copy_static (volume, &mutable_volume); _clutter_paint_volume_get_bounding_box (&mutable_volume, &raw_box); clutter_paint_volume_free (&mutable_volume); } else { clutter_actor_get_allocation_box (priv->actor, &raw_box); } box = raw_box; _clutter_actor_box_enlarge_for_effects (&box); priv->fbo_offset_x = box.x1 - raw_box.x1; priv->fbo_offset_y = box.y1 - raw_box.y1; clutter_actor_box_get_size (&box, &fbo_width, &fbo_height); /* First assert that the framebuffer is the right size... */ if (!update_fbo (effect, fbo_width, fbo_height)) return FALSE; cogl_get_modelview_matrix (&old_modelview); /* let's draw offscreen */ cogl_push_framebuffer (priv->offscreen); /* We don't want the FBO contents to be transformed. That could waste memory * (e.g. during zoom), or result in something that's not rectangular (clipped * incorrectly). So drop the modelview matrix of the current paint chain. * This is fine since paint_texture runs with the same modelview matrix, * so it will come out correctly whenever that is used to put the FBO * contents on screen... */ clutter_actor_get_transform (priv->stage, &modelview); cogl_matrix_translate (&modelview, -priv->fbo_offset_x, -priv->fbo_offset_y, 0.0f); cogl_set_modelview_matrix (&modelview); /* Save the original viewport for calculating priv->position */ _clutter_stage_get_viewport (CLUTTER_STAGE (priv->stage), &old_viewport[0], &old_viewport[1], &old_viewport[2], &old_viewport[3]); /* Set up the viewport so that it has the same size as the stage. */ cogl_set_viewport (0, 0, stage_width, stage_height); /* Copy the stage's projection matrix across to the framebuffer */ _clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage), &projection); /* Now save the global position of the effect (not just of the actor). * It doesn't appear anyone actually uses this yet, but get_target_rect is * documented as returning it. So we should... */ _clutter_util_fully_transform_vertices (&old_modelview, &projection, old_viewport, &local_offset, &priv->position, 1); cogl_set_projection_matrix (&projection); cogl_color_init_from_4ub (&transparent, 0, 0, 0, 0); cogl_clear (&transparent, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH); cogl_push_matrix (); /* Override the actor's opacity to fully opaque - we paint the offscreen * texture with the actor's paint opacity, so we need to do this to avoid * multiplying the opacity twice. */ priv->old_opacity_override = clutter_actor_get_opacity_override (priv->actor); clutter_actor_set_opacity_override (priv->actor, 0xff); return TRUE; } static void clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect) { ClutterOffscreenEffectPrivate *priv = effect->priv; guint8 paint_opacity; paint_opacity = clutter_actor_get_paint_opacity (priv->actor); cogl_pipeline_set_color4ub (priv->target, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_set_source (priv->target); /* At this point we are in stage coordinates translated so if * we draw our texture using a textured quad the size of the paint * box then we will overlay where the actor would have drawn if it * hadn't been redirected offscreen. */ cogl_rectangle_with_texture_coords (0, 0, cogl_texture_get_width (priv->texture), cogl_texture_get_height (priv->texture), 0.0, 0.0, 1.0, 1.0); } static void clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect) { ClutterOffscreenEffectPrivate *priv = effect->priv; CoglMatrix modelview; cogl_push_matrix (); /* The current modelview matrix is *almost* perfect already. It's only * missing a correction for the expanded FBO and offset rendering within... */ cogl_get_modelview_matrix (&modelview); cogl_matrix_translate (&modelview, priv->fbo_offset_x, priv->fbo_offset_y, 0.0f); cogl_set_modelview_matrix (&modelview); /* paint the target material; this is virtualized for * sub-classes that require special hand-holding */ clutter_offscreen_effect_paint_target (effect); cogl_pop_matrix (); } static void clutter_offscreen_effect_post_paint (ClutterEffect *effect) { ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffectPrivate *priv = self->priv; if (priv->offscreen == NULL || priv->target == NULL || priv->actor == NULL) return; /* Restore the previous opacity override */ clutter_actor_set_opacity_override (priv->actor, priv->old_opacity_override); cogl_pop_matrix (); cogl_pop_framebuffer (); clutter_offscreen_effect_paint_texture (self); } static void clutter_offscreen_effect_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags) { ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffectPrivate *priv = self->priv; CoglMatrix matrix; cogl_get_modelview_matrix (&matrix); /* If we've already got a cached image and the actor hasn't been redrawn * then we can just use the cached image in the FBO. */ if (priv->offscreen == NULL || (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY)) { /* Chain up to the parent paint method which will call the pre and post paint functions to update the image */ CLUTTER_EFFECT_CLASS (clutter_offscreen_effect_parent_class)-> paint (effect, flags); } else clutter_offscreen_effect_paint_texture (self); } static void clutter_offscreen_effect_finalize (GObject *gobject) { ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (gobject); ClutterOffscreenEffectPrivate *priv = self->priv; if (priv->offscreen) cogl_handle_unref (priv->offscreen); if (priv->target) cogl_handle_unref (priv->target); if (priv->texture) cogl_handle_unref (priv->texture); G_OBJECT_CLASS (clutter_offscreen_effect_parent_class)->finalize (gobject); } static void clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass) { ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); klass->create_texture = clutter_offscreen_effect_real_create_texture; klass->paint_target = clutter_offscreen_effect_real_paint_target; meta_class->set_actor = clutter_offscreen_effect_set_actor; effect_class->pre_paint = clutter_offscreen_effect_pre_paint; effect_class->post_paint = clutter_offscreen_effect_post_paint; effect_class->paint = clutter_offscreen_effect_paint; gobject_class->finalize = clutter_offscreen_effect_finalize; } static void clutter_offscreen_effect_init (ClutterOffscreenEffect *self) { self->priv = clutter_offscreen_effect_get_instance_private (self); } /** * clutter_offscreen_effect_get_texture: * @effect: a #ClutterOffscreenEffect * * Retrieves the texture used as a render target for the offscreen * buffer created by @effect * * You should only use the returned texture when painting. The texture * may change after ClutterEffect::pre_paint is called so the effect * implementation should update any references to the texture after * chaining-up to the parent's pre_paint implementation. This can be * used instead of clutter_offscreen_effect_get_target() when the * effect subclass wants to paint using its own material. * * Return value: (transfer none): a #CoglHandle or %COGL_INVALID_HANDLE. The * returned texture is owned by Clutter and it should not be * modified or freed * * Since: 1.10 */ CoglHandle clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect) { g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), NULL); return effect->priv->texture; } /** * clutter_offscreen_effect_get_target: (skip) * @effect: a #ClutterOffscreenEffect * * Retrieves the material used as a render target for the offscreen * buffer created by @effect * * You should only use the returned #CoglMaterial when painting. The * returned material might change between different frames. * * Return value: (transfer none): a #CoglMaterial or %NULL. The * returned material is owned by Clutter and it should not be * modified or freed * * Since: 1.4 */ CoglMaterial * clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect) { g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), NULL); return (CoglMaterial *)effect->priv->target; } /** * clutter_offscreen_effect_paint_target: * @effect: a #ClutterOffscreenEffect * * Calls the paint_target() virtual function of the @effect * * Since: 1.4 */ void clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect) { g_return_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect)); CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect)->paint_target (effect); } /** * clutter_offscreen_effect_create_texture: * @effect: a #ClutterOffscreenEffect * @width: the minimum width of the target texture * @height: the minimum height of the target texture * * Calls the create_texture() virtual function of the @effect * * Return value: (transfer full): a handle to a Cogl texture, or * %COGL_INVALID_HANDLE. The returned handle has its reference * count increased. * * Since: 1.4 */ CoglHandle clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect, gfloat width, gfloat height) { g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), NULL); return CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect)->create_texture (effect, width, height); } /** * clutter_offscreen_effect_get_target_size: * @effect: a #ClutterOffscreenEffect * @width: (out): return location for the target width, or %NULL * @height: (out): return location for the target height, or %NULL * * Retrieves the size of the offscreen buffer used by @effect to * paint the actor to which it has been applied. * * This function should only be called by #ClutterOffscreenEffect * implementations, from within the #ClutterOffscreenEffectClass.paint_target() * virtual function. * * Return value: %TRUE if the offscreen buffer has a valid size, * and %FALSE otherwise * * Since: 1.8 * * Deprecated: 1.14: Use clutter_offscreen_effect_get_target_rect() instead */ gboolean clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect, gfloat *width, gfloat *height) { ClutterOffscreenEffectPrivate *priv; g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), FALSE); priv = effect->priv; if (priv->texture == NULL) return FALSE; if (width) *width = cogl_texture_get_width (priv->texture); if (height) *height = cogl_texture_get_height (priv->texture); return TRUE; } /** * clutter_offscreen_effect_get_target_rect: * @effect: a #ClutterOffscreenEffect * @rect: (out caller-allocates): return location for the target area * * Retrieves the origin and size of the offscreen buffer used by @effect to * paint the actor to which it has been applied. * * This function should only be called by #ClutterOffscreenEffect * implementations, from within the #ClutterOffscreenEffectClass.paint_target() * virtual function. * * Return value: %TRUE if the offscreen buffer has a valid rectangle, * and %FALSE otherwise * * Since: 1.14 */ gboolean clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect, ClutterRect *rect) { ClutterOffscreenEffectPrivate *priv; g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), FALSE); g_return_val_if_fail (rect != NULL, FALSE); priv = effect->priv; if (priv->texture == NULL) return FALSE; clutter_rect_init (rect, priv->position.x, priv->position.y, cogl_texture_get_width (priv->texture), cogl_texture_get_height (priv->texture)); return TRUE; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/�����������������������������������������������������������������0000775�0001750�0001750�00000000000�14211404421�017404� 5����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-rectangle.h������������������������������������������������0000664�0001750�0001750�00000005206�14211404421�022626� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_RECTANGLE_H__ #define __CALLY_RECTANGLE_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <cally/cally-actor.h> #include <clutter/clutter.h> G_BEGIN_DECLS #define CALLY_TYPE_RECTANGLE (cally_rectangle_get_type ()) #define CALLY_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_RECTANGLE, CallyRectangle)) #define CALLY_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_RECTANGLE, CallyRectangleClass)) #define CALLY_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_RECTANGLE)) #define CALLY_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_RECTANGLE)) #define CALLY_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_RECTANGLE, CallyRectangleClass)) typedef struct _CallyRectangle CallyRectangle; typedef struct _CallyRectangleClass CallyRectangleClass; typedef struct _CallyRectanglePrivate CallyRectanglePrivate; /** * CallyRectangle: * * The <structname>CallyRectangle</structname> structure contains only private * data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyRectangle { /*< private >*/ CallyActor parent; CallyRectanglePrivate *priv; }; /** * CallyRectangleClass: * * The <structname>CallyRectangleClass</structname> structure contains * only private data * * Since: 1.4 */ struct _CallyRectangleClass { /*< private >*/ CallyActorClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_rectangle_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject* cally_rectangle_new (ClutterActor *actor); G_END_DECLS #endif /* __CALLY_RECTANGLE_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-text.c�����������������������������������������������������0000664�0001750�0001750�00000230546�14211404421�021650� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Some parts are based on GailLabel, GailEntry, GailTextView from GAIL * GAIL - The GNOME Accessibility Implementation Library * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * Implementation of atk_text_get_text_[before/at/after]_offset * copied from gtkpango.c, part of GTK+ project * Copyright (c) 2010 Red Hat, Inc. * * 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:cally-text * @short_description: Implementation of the ATK interfaces for a #ClutterText * @see_also: #ClutterText * * #CallyText implements the required ATK interfaces of * #ClutterText, #AtkText and #AtkEditableText * * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "cally-text.h" #include "cally-actor-private.h" #include "clutter-color.h" #include "clutter-main.h" #include "clutter-text.h" static void cally_text_finalize (GObject *obj); /* AtkObject */ static void cally_text_real_initialize (AtkObject *obj, gpointer data); static AtkStateSet* cally_text_ref_state_set (AtkObject *obj); /* atkaction */ static void _cally_text_activate_action (CallyActor *cally_actor); static void _check_activate_action (CallyText *cally_text, ClutterText *clutter_text); /* AtkText */ static void cally_text_text_interface_init (AtkTextIface *iface); static gchar* cally_text_get_text (AtkText *text, gint start_offset, gint end_offset); static gunichar cally_text_get_character_at_offset (AtkText *text, gint offset); static gchar* cally_text_get_text_before_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset); static gchar* cally_text_get_text_at_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset); static gchar* cally_text_get_text_after_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset); static gint cally_text_get_caret_offset (AtkText *text); static gboolean cally_text_set_caret_offset (AtkText *text, gint offset); static gint cally_text_get_character_count (AtkText *text); static gint cally_text_get_n_selections (AtkText *text); static gchar* cally_text_get_selection (AtkText *text, gint selection_num, gint *start_offset, gint *end_offset); static gboolean cally_text_add_selection (AtkText *text, gint start_offset, gint end_offset); static gboolean cally_text_remove_selection (AtkText *text, gint selection_num); static gboolean cally_text_set_selection (AtkText *text, gint selection_num, gint start_offset, gint end_offset); static AtkAttributeSet* cally_text_get_run_attributes (AtkText *text, gint offset, gint *start_offset, gint *end_offset); static AtkAttributeSet* cally_text_get_default_attributes (AtkText *text); static void cally_text_get_character_extents (AtkText *text, gint offset, gint *x, gint *y, gint *width, gint *height, AtkCoordType coords); static gint cally_text_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coords); static void _cally_text_get_selection_bounds (ClutterText *clutter_text, gint *start_offset, gint *end_offset); static void _cally_text_insert_text_cb (ClutterText *clutter_text, gchar *new_text, gint new_text_length, gint *position, gpointer data); static void _cally_text_delete_text_cb (ClutterText *clutter_text, gint start_pos, gint end_pos, gpointer data); static gboolean _idle_notify_insert (gpointer data); static void _notify_insert (CallyText *cally_text); static void _notify_delete (CallyText *cally_text); /* AtkEditableText */ static void cally_text_editable_text_interface_init (AtkEditableTextIface *iface); static void cally_text_set_text_contents (AtkEditableText *text, const gchar *string); static void cally_text_insert_text (AtkEditableText *text, const gchar *string, gint length, gint *position); static void cally_text_delete_text (AtkEditableText *text, gint start_pos, gint end_pos); /* CallyActor */ static void cally_text_notify_clutter (GObject *obj, GParamSpec *pspec); static gboolean _check_for_selection_change (CallyText *cally_text, ClutterText *clutter_text); /* Misc functions */ static AtkAttributeSet* _cally_misc_add_attribute (AtkAttributeSet *attrib_set, AtkTextAttribute attr, gchar *value); static AtkAttributeSet* _cally_misc_layout_get_run_attributes (AtkAttributeSet *attrib_set, ClutterText *clutter_text, gint offset, gint *start_offset, gint *end_offset); static AtkAttributeSet* _cally_misc_layout_get_default_attributes (AtkAttributeSet *attrib_set, ClutterText *text); static int _cally_misc_get_index_at_point (ClutterText *clutter_text, gint x, gint y, AtkCoordType coords); struct _CallyTextPrivate { /* Cached ClutterText values*/ gint cursor_position; gint selection_bound; /* text_changed::insert stuff */ const gchar *signal_name_insert; gint position_insert; gint length_insert; guint insert_idle_handler; /* text_changed::delete stuff */ const gchar *signal_name_delete; gint position_delete; gint length_delete; /* action */ guint activate_action_id; }; G_DEFINE_TYPE_WITH_CODE (CallyText, cally_text, CALLY_TYPE_ACTOR, G_ADD_PRIVATE (CallyText) G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, cally_text_text_interface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, cally_text_editable_text_interface_init)); static void cally_text_class_init (CallyTextClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); AtkObjectClass *class = ATK_OBJECT_CLASS (klass); CallyActorClass *cally_class = CALLY_ACTOR_CLASS (klass); gobject_class->finalize = cally_text_finalize; class->initialize = cally_text_real_initialize; class->ref_state_set = cally_text_ref_state_set; cally_class->notify_clutter = cally_text_notify_clutter; } static void cally_text_init (CallyText *cally_text) { CallyTextPrivate *priv = cally_text_get_instance_private (cally_text); cally_text->priv = priv; priv->cursor_position = 0; priv->selection_bound = 0; priv->signal_name_insert = NULL; priv->position_insert = -1; priv->length_insert = -1; priv->insert_idle_handler = 0; priv->signal_name_delete = NULL; priv->position_delete = -1; priv->length_delete = -1; priv->activate_action_id = 0; } static void cally_text_finalize (GObject *obj) { CallyText *cally_text = CALLY_TEXT (obj); /* g_object_unref (cally_text->priv->textutil); */ /* cally_text->priv->textutil = NULL; */ if (cally_text->priv->insert_idle_handler) { g_source_remove (cally_text->priv->insert_idle_handler); cally_text->priv->insert_idle_handler = 0; } G_OBJECT_CLASS (cally_text_parent_class)->finalize (obj); } /** * cally_text_new: * @actor: a #ClutterActor * * Creates a new #CallyText for the given @actor. @actor must be a * #ClutterText. * * Return value: the newly created #AtkObject * * Since: 1.4 */ AtkObject* cally_text_new (ClutterActor *actor) { GObject *object = NULL; AtkObject *accessible = NULL; g_return_val_if_fail (CLUTTER_IS_TEXT (actor), NULL); object = g_object_new (CALLY_TYPE_TEXT, NULL); accessible = ATK_OBJECT (object); atk_object_initialize (accessible, actor); return accessible; } /* atkobject.h */ static void cally_text_real_initialize(AtkObject *obj, gpointer data) { ClutterText *clutter_text = NULL; CallyText *cally_text = NULL; ATK_OBJECT_CLASS (cally_text_parent_class)->initialize (obj, data); g_return_if_fail (CLUTTER_TEXT (data)); cally_text = CALLY_TEXT (obj); clutter_text = CLUTTER_TEXT (data); cally_text->priv->cursor_position = clutter_text_get_cursor_position (clutter_text); cally_text->priv->selection_bound = clutter_text_get_selection_bound (clutter_text); g_signal_connect (clutter_text, "insert-text", G_CALLBACK (_cally_text_insert_text_cb), cally_text); g_signal_connect (clutter_text, "delete-text", G_CALLBACK (_cally_text_delete_text_cb), cally_text); _check_activate_action (cally_text, clutter_text); if (clutter_text_get_password_char (clutter_text) != 0) atk_object_set_role (obj, ATK_ROLE_PASSWORD_TEXT); else atk_object_set_role (obj, ATK_ROLE_TEXT); } static AtkStateSet* cally_text_ref_state_set (AtkObject *obj) { AtkStateSet *result = NULL; ClutterActor *actor = NULL; result = ATK_OBJECT_CLASS (cally_text_parent_class)->ref_state_set (obj); actor = CALLY_GET_CLUTTER_ACTOR (obj); if (actor == NULL) return result; if (clutter_text_get_editable (CLUTTER_TEXT (actor))) atk_state_set_add_state (result, ATK_STATE_EDITABLE); if (clutter_text_get_selectable (CLUTTER_TEXT (actor))) atk_state_set_add_state (result, ATK_STATE_SELECTABLE_TEXT); return result; } /***** pango stuff **** * * FIXME: all this pango related code used to implement * atk_text_get_text_[before/at/after]_offset was copied from GTK, and * should be on a common library (like pango itself). * *********************/ /* * _gtk_pango_move_chars: * @layout: a #PangoLayout * @offset: a character offset in @layout * @count: the number of characters to move from @offset * * Returns the position that is @count characters from the * given @offset. @count may be positive or negative. * * For the purpose of this function, characters are defined * by what Pango considers cursor positions. * * Returns: the new position */ static gint _gtk_pango_move_chars (PangoLayout *layout, gint offset, gint count) { const PangoLogAttr *attrs; gint n_attrs; attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); while (count > 0 && offset < n_attrs - 1) { do offset++; while (offset < n_attrs - 1 && !attrs[offset].is_cursor_position); count--; } while (count < 0 && offset > 0) { do offset--; while (offset > 0 && !attrs[offset].is_cursor_position); count++; } return offset; } /* * _gtk_pango_move_words: * @layout: a #PangoLayout * @offset: a character offset in @layout * @count: the number of words to move from @offset * * Returns the position that is @count words from the * given @offset. @count may be positive or negative. * * If @count is positive, the returned position will * be a word end, otherwise it will be a word start. * See the Pango documentation for details on how * word starts and ends are defined. * * Returns: the new position */ static gint _gtk_pango_move_words (PangoLayout *layout, gint offset, gint count) { const PangoLogAttr *attrs; gint n_attrs; attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); while (count > 0 && offset < n_attrs - 1) { do offset++; while (offset < n_attrs - 1 && !attrs[offset].is_word_end); count--; } while (count < 0 && offset > 0) { do offset--; while (offset > 0 && !attrs[offset].is_word_start); count++; } return offset; } /* * _gtk_pango_move_sentences: * @layout: a #PangoLayout * @offset: a character offset in @layout * @count: the number of sentences to move from @offset * * Returns the position that is @count sentences from the * given @offset. @count may be positive or negative. * * If @count is positive, the returned position will * be a sentence end, otherwise it will be a sentence start. * See the Pango documentation for details on how * sentence starts and ends are defined. * * Returns: the new position */ static gint _gtk_pango_move_sentences (PangoLayout *layout, gint offset, gint count) { const PangoLogAttr *attrs; gint n_attrs; attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); while (count > 0 && offset < n_attrs - 1) { do offset++; while (offset < n_attrs - 1 && !attrs[offset].is_sentence_end); count--; } while (count < 0 && offset > 0) { do offset--; while (offset > 0 && !attrs[offset].is_sentence_start); count++; } return offset; } /* * _gtk_pango_is_inside_word: * @layout: a #PangoLayout * @offset: a character offset in @layout * * Returns whether the given position is inside * a word. * * Returns: %TRUE if @offset is inside a word */ static gboolean _gtk_pango_is_inside_word (PangoLayout *layout, gint offset) { const PangoLogAttr *attrs; gint n_attrs; attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); while (offset >= 0 && !(attrs[offset].is_word_start || attrs[offset].is_word_end)) offset--; if (offset >= 0) return attrs[offset].is_word_start; return FALSE; } /* * _gtk_pango_is_inside_sentence: * @layout: a #PangoLayout * @offset: a character offset in @layout * * Returns whether the given position is inside * a sentence. * * Returns: %TRUE if @offset is inside a sentence */ static gboolean _gtk_pango_is_inside_sentence (PangoLayout *layout, gint offset) { const PangoLogAttr *attrs; gint n_attrs; attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); while (offset >= 0 && !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end)) offset--; if (offset >= 0) return attrs[offset].is_sentence_start; return FALSE; } static void pango_layout_get_line_before (PangoLayout *layout, AtkTextBoundary boundary_type, gint offset, gint *start_offset, gint *end_offset) { PangoLayoutIter *iter; PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL; gint index, start_index, end_index; const gchar *text; gboolean found = FALSE; text = pango_layout_get_text (layout); index = g_utf8_offset_to_pointer (text, offset) - text; iter = pango_layout_get_iter (layout); do { line = pango_layout_iter_get_line (iter); start_index = line->start_index; end_index = start_index + line->length; if (index >= start_index && index <= end_index) { /* Found line for offset */ if (prev_line) { switch (boundary_type) { case ATK_TEXT_BOUNDARY_LINE_START: end_index = start_index; start_index = prev_line->start_index; break; case ATK_TEXT_BOUNDARY_LINE_END: if (prev_prev_line) start_index = prev_prev_line->start_index + prev_prev_line->length; else start_index = 0; end_index = prev_line->start_index + prev_line->length; break; default: g_assert_not_reached(); } } else start_index = end_index = 0; found = TRUE; break; } prev_prev_line = prev_line; prev_line = line; } while (pango_layout_iter_next_line (iter)); if (!found) { start_index = prev_line->start_index + prev_line->length; end_index = start_index; } pango_layout_iter_free (iter); *start_offset = g_utf8_pointer_to_offset (text, text + start_index); *end_offset = g_utf8_pointer_to_offset (text, text + end_index); } static void pango_layout_get_line_at (PangoLayout *layout, AtkTextBoundary boundary_type, gint offset, gint *start_offset, gint *end_offset) { PangoLayoutIter *iter; PangoLayoutLine *line, *prev_line = NULL; gint index, start_index, end_index; const gchar *text; gboolean found = FALSE; text = pango_layout_get_text (layout); index = g_utf8_offset_to_pointer (text, offset) - text; iter = pango_layout_get_iter (layout); do { line = pango_layout_iter_get_line (iter); start_index = line->start_index; end_index = start_index + line->length; if (index >= start_index && index <= end_index) { /* Found line for offset */ switch (boundary_type) { case ATK_TEXT_BOUNDARY_LINE_START: if (pango_layout_iter_next_line (iter)) end_index = pango_layout_iter_get_line (iter)->start_index; break; case ATK_TEXT_BOUNDARY_LINE_END: if (prev_line) start_index = prev_line->start_index + prev_line->length; break; default: g_assert_not_reached(); } found = TRUE; break; } prev_line = line; } while (pango_layout_iter_next_line (iter)); if (!found) { start_index = prev_line->start_index + prev_line->length; end_index = start_index; } pango_layout_iter_free (iter); *start_offset = g_utf8_pointer_to_offset (text, text + start_index); *end_offset = g_utf8_pointer_to_offset (text, text + end_index); } static void pango_layout_get_line_after (PangoLayout *layout, AtkTextBoundary boundary_type, gint offset, gint *start_offset, gint *end_offset) { PangoLayoutIter *iter; PangoLayoutLine *line, *prev_line = NULL; gint index, start_index, end_index; const gchar *text; gboolean found = FALSE; text = pango_layout_get_text (layout); index = g_utf8_offset_to_pointer (text, offset) - text; iter = pango_layout_get_iter (layout); do { line = pango_layout_iter_get_line (iter); start_index = line->start_index; end_index = start_index + line->length; if (index >= start_index && index <= end_index) { /* Found line for offset */ if (pango_layout_iter_next_line (iter)) { line = pango_layout_iter_get_line (iter); switch (boundary_type) { case ATK_TEXT_BOUNDARY_LINE_START: start_index = line->start_index; if (pango_layout_iter_next_line (iter)) end_index = pango_layout_iter_get_line (iter)->start_index; else end_index = start_index + line->length; break; case ATK_TEXT_BOUNDARY_LINE_END: start_index = end_index; end_index = line->start_index + line->length; break; default: g_assert_not_reached(); } } else start_index = end_index; found = TRUE; break; } prev_line = line; } while (pango_layout_iter_next_line (iter)); if (!found) { start_index = prev_line->start_index + prev_line->length; end_index = start_index; } pango_layout_iter_free (iter); *start_offset = g_utf8_pointer_to_offset (text, text + start_index); *end_offset = g_utf8_pointer_to_offset (text, text + end_index); } /* * _gtk_pango_get_text_at: * @layout: a #PangoLayout * @boundary_type: a #AtkTextBoundary * @offset: a character offset in @layout * @start_offset: return location for the start of the returned text * @end_offset: return location for the end of the return text * * Gets a slice of the text from @layout at @offset. * * The @boundary_type determines the size of the returned slice of * text. For the exact semantics of this function, see * atk_text_get_text_after_offset(). * * Returns: a newly allocated string containing a slice of text * from layout. Free with free(). */ static gchar * _gtk_pango_get_text_at (PangoLayout *layout, AtkTextBoundary boundary_type, gint offset, gint *start_offset, gint *end_offset) { const gchar *text; gint start, end; const PangoLogAttr *attrs; gint n_attrs; text = pango_layout_get_text (layout); if (text[0] == 0) { *start_offset = 0; *end_offset = 0; return g_strdup (""); } attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); start = offset; end = start; switch (boundary_type) { case ATK_TEXT_BOUNDARY_CHAR: end = _gtk_pango_move_chars (layout, end, 1); break; case ATK_TEXT_BOUNDARY_WORD_START: if (!attrs[start].is_word_start) start = _gtk_pango_move_words (layout, start, -1); if (_gtk_pango_is_inside_word (layout, end)) end = _gtk_pango_move_words (layout, end, 1); while (!attrs[end].is_word_start && end < n_attrs - 1) end = _gtk_pango_move_chars (layout, end, 1); break; case ATK_TEXT_BOUNDARY_WORD_END: if (_gtk_pango_is_inside_word (layout, start) && !attrs[start].is_word_start) start = _gtk_pango_move_words (layout, start, -1); while (!attrs[start].is_word_end && start > 0) start = _gtk_pango_move_chars (layout, start, -1); end = _gtk_pango_move_words (layout, end, 1); break; case ATK_TEXT_BOUNDARY_SENTENCE_START: if (!attrs[start].is_sentence_start) start = _gtk_pango_move_sentences (layout, start, -1); if (_gtk_pango_is_inside_sentence (layout, end)) end = _gtk_pango_move_sentences (layout, end, 1); while (!attrs[end].is_sentence_start && end < n_attrs - 1) end = _gtk_pango_move_chars (layout, end, 1); break; case ATK_TEXT_BOUNDARY_SENTENCE_END: if (_gtk_pango_is_inside_sentence (layout, start) && !attrs[start].is_sentence_start) start = _gtk_pango_move_sentences (layout, start, -1); while (!attrs[start].is_sentence_end && start > 0) start = _gtk_pango_move_chars (layout, start, -1); end = _gtk_pango_move_sentences (layout, end, 1); break; case ATK_TEXT_BOUNDARY_LINE_START: case ATK_TEXT_BOUNDARY_LINE_END: pango_layout_get_line_at (layout, boundary_type, offset, &start, &end); break; } *start_offset = start; *end_offset = end; g_assert (start <= end); return g_utf8_substring (text, start, end); } /* * _gtk_pango_get_text_before: * @layout: a #PangoLayout * @boundary_type: a #AtkTextBoundary * @offset: a character offset in @layout * @start_offset: return location for the start of the returned text * @end_offset: return location for the end of the return text * * Gets a slice of the text from @layout before @offset. * * The @boundary_type determines the size of the returned slice of * text. For the exact semantics of this function, see * atk_text_get_text_before_offset(). * * Returns: a newly allocated string containing a slice of text * from layout. Free with free(). */ static gchar * _gtk_pango_get_text_before (PangoLayout *layout, AtkTextBoundary boundary_type, gint offset, gint *start_offset, gint *end_offset) { const gchar *text; gint start, end; const PangoLogAttr *attrs; gint n_attrs; text = pango_layout_get_text (layout); if (text[0] == 0) { *start_offset = 0; *end_offset = 0; return g_strdup (""); } attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); start = offset; end = start; switch (boundary_type) { case ATK_TEXT_BOUNDARY_CHAR: start = _gtk_pango_move_chars (layout, start, -1); break; case ATK_TEXT_BOUNDARY_WORD_START: if (!attrs[start].is_word_start) start = _gtk_pango_move_words (layout, start, -1); end = start; start = _gtk_pango_move_words (layout, start, -1); break; case ATK_TEXT_BOUNDARY_WORD_END: if (_gtk_pango_is_inside_word (layout, start) && !attrs[start].is_word_start) start = _gtk_pango_move_words (layout, start, -1); while (!attrs[start].is_word_end && start > 0) start = _gtk_pango_move_chars (layout, start, -1); end = start; start = _gtk_pango_move_words (layout, start, -1); while (!attrs[start].is_word_end && start > 0) start = _gtk_pango_move_chars (layout, start, -1); break; case ATK_TEXT_BOUNDARY_SENTENCE_START: if (!attrs[start].is_sentence_start) start = _gtk_pango_move_sentences (layout, start, -1); end = start; start = _gtk_pango_move_sentences (layout, start, -1); break; case ATK_TEXT_BOUNDARY_SENTENCE_END: if (_gtk_pango_is_inside_sentence (layout, start) && !attrs[start].is_sentence_start) start = _gtk_pango_move_sentences (layout, start, -1); while (!attrs[start].is_sentence_end && start > 0) start = _gtk_pango_move_chars (layout, start, -1); end = start; start = _gtk_pango_move_sentences (layout, start, -1); while (!attrs[start].is_sentence_end && start > 0) start = _gtk_pango_move_chars (layout, start, -1); break; case ATK_TEXT_BOUNDARY_LINE_START: case ATK_TEXT_BOUNDARY_LINE_END: pango_layout_get_line_before (layout, boundary_type, offset, &start, &end); break; } *start_offset = start; *end_offset = end; g_assert (start <= end); return g_utf8_substring (text, start, end); } /* * _gtk_pango_get_text_after: * @layout: a #PangoLayout * @boundary_type: a #AtkTextBoundary * @offset: a character offset in @layout * @start_offset: return location for the start of the returned text * @end_offset: return location for the end of the return text * * Gets a slice of the text from @layout after @offset. * * The @boundary_type determines the size of the returned slice of * text. For the exact semantics of this function, see * atk_text_get_text_after_offset(). * * Returns: a newly allocated string containing a slice of text * from layout. Free with free(). */ static gchar * _gtk_pango_get_text_after (PangoLayout *layout, AtkTextBoundary boundary_type, gint offset, gint *start_offset, gint *end_offset) { const gchar *text; gint start, end; const PangoLogAttr *attrs; gint n_attrs; text = pango_layout_get_text (layout); if (text[0] == 0) { *start_offset = 0; *end_offset = 0; return g_strdup (""); } attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); start = offset; end = start; switch (boundary_type) { case ATK_TEXT_BOUNDARY_CHAR: start = _gtk_pango_move_chars (layout, start, 1); end = start; end = _gtk_pango_move_chars (layout, end, 1); break; case ATK_TEXT_BOUNDARY_WORD_START: if (_gtk_pango_is_inside_word (layout, end)) end = _gtk_pango_move_words (layout, end, 1); while (!attrs[end].is_word_start && end < n_attrs - 1) end = _gtk_pango_move_chars (layout, end, 1); start = end; if (end < n_attrs - 1) { end = _gtk_pango_move_words (layout, end, 1); while (!attrs[end].is_word_start && end < n_attrs - 1) end = _gtk_pango_move_chars (layout, end, 1); } break; case ATK_TEXT_BOUNDARY_WORD_END: end = _gtk_pango_move_words (layout, end, 1); start = end; if (end < n_attrs - 1) end = _gtk_pango_move_words (layout, end, 1); break; case ATK_TEXT_BOUNDARY_SENTENCE_START: if (_gtk_pango_is_inside_sentence (layout, end)) end = _gtk_pango_move_sentences (layout, end, 1); while (!attrs[end].is_sentence_start && end < n_attrs - 1) end = _gtk_pango_move_chars (layout, end, 1); start = end; if (end < n_attrs - 1) { end = _gtk_pango_move_sentences (layout, end, 1); while (!attrs[end].is_sentence_start && end < n_attrs - 1) end = _gtk_pango_move_chars (layout, end, 1); } break; case ATK_TEXT_BOUNDARY_SENTENCE_END: end = _gtk_pango_move_sentences (layout, end, 1); start = end; if (end < n_attrs - 1) end = _gtk_pango_move_sentences (layout, end, 1); break; case ATK_TEXT_BOUNDARY_LINE_START: case ATK_TEXT_BOUNDARY_LINE_END: pango_layout_get_line_after (layout, boundary_type, offset, &start, &end); break; } *start_offset = start; *end_offset = end; g_assert (start <= end); return g_utf8_substring (text, start, end); } /***** atktext.h ******/ static void cally_text_text_interface_init (AtkTextIface *iface) { g_return_if_fail (iface != NULL); iface->get_text = cally_text_get_text; iface->get_character_at_offset = cally_text_get_character_at_offset; iface->get_text_before_offset = cally_text_get_text_before_offset; iface->get_text_at_offset = cally_text_get_text_at_offset; iface->get_text_after_offset = cally_text_get_text_after_offset; iface->get_character_count = cally_text_get_character_count; iface->get_caret_offset = cally_text_get_caret_offset; iface->set_caret_offset = cally_text_set_caret_offset; iface->get_n_selections = cally_text_get_n_selections; iface->get_selection = cally_text_get_selection; iface->add_selection = cally_text_add_selection; iface->remove_selection = cally_text_remove_selection; iface->set_selection = cally_text_set_selection; iface->get_run_attributes = cally_text_get_run_attributes; iface->get_default_attributes = cally_text_get_default_attributes; iface->get_character_extents = cally_text_get_character_extents; iface->get_offset_at_point = cally_text_get_offset_at_point; } static gchar* cally_text_get_text (AtkText *text, gint start_offset, gint end_offset) { ClutterActor *actor = NULL; PangoLayout *layout = NULL; const gchar *string = NULL; gint character_count = 0; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* Object is defunct */ return NULL; /* we use the pango layout instead of clutter_text_get_chars because it take into account password-char */ layout = clutter_text_get_layout (CLUTTER_TEXT (actor)); string = pango_layout_get_text (layout); character_count = pango_layout_get_character_count (layout); if (end_offset == -1 || end_offset > character_count) end_offset = character_count; if (string[0] == 0) return g_strdup(""); else return g_utf8_substring (string, start_offset, end_offset); } static gunichar cally_text_get_character_at_offset (AtkText *text, gint offset) { ClutterActor *actor = NULL; const gchar *string = NULL; gchar *index = NULL; gunichar unichar; PangoLayout *layout = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return '\0'; /* we use the pango layout instead of clutter_text_get_chars because it take into account password-char */ layout = clutter_text_get_layout (CLUTTER_TEXT (actor)); string = pango_layout_get_text (layout); if (offset >= g_utf8_strlen (string, -1)) { unichar = '\0'; } else { index = g_utf8_offset_to_pointer (string, offset); unichar = g_utf8_get_char (index); } return unichar; } static gchar* cally_text_get_text_before_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return NULL; return _gtk_pango_get_text_before (clutter_text_get_layout (CLUTTER_TEXT (actor)), boundary_type, offset, start_offset, end_offset); } static gchar* cally_text_get_text_at_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return NULL; return _gtk_pango_get_text_at (clutter_text_get_layout (CLUTTER_TEXT (actor)), boundary_type, offset, start_offset, end_offset); } static gchar* cally_text_get_text_after_offset (AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return NULL; return _gtk_pango_get_text_after (clutter_text_get_layout (CLUTTER_TEXT (actor)), boundary_type, offset, start_offset, end_offset); } static gint cally_text_get_caret_offset (AtkText *text) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return -1; return clutter_text_get_cursor_position (CLUTTER_TEXT (actor)); } static gboolean cally_text_set_caret_offset (AtkText *text, gint offset) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return FALSE; clutter_text_set_cursor_position (CLUTTER_TEXT (actor), offset); /* like in gailentry, we suppose that this always works, as clutter text doesn't return anything */ return TRUE; } static gint cally_text_get_character_count (AtkText *text) { ClutterActor *actor = NULL; ClutterText *clutter_text = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return 0; clutter_text = CLUTTER_TEXT (actor); return g_utf8_strlen (clutter_text_get_text (clutter_text), -1); } static gint cally_text_get_n_selections (AtkText *text) { ClutterActor *actor = NULL; gint selection_bound = -1; gint cursor_position = -1; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return 0; if (!clutter_text_get_selectable (CLUTTER_TEXT (actor))) return 0; selection_bound = clutter_text_get_selection_bound (CLUTTER_TEXT (actor)); cursor_position = clutter_text_get_cursor_position (CLUTTER_TEXT (actor)); if (selection_bound == cursor_position) return 0; else return 1; } static gchar* cally_text_get_selection (AtkText *text, gint selection_num, gint *start_offset, gint *end_offset) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return NULL; /* As in gailentry, only let the user get the selection if one is set, and if * the selection_num is 0. */ if (selection_num != 0) return NULL; _cally_text_get_selection_bounds (CLUTTER_TEXT (actor), start_offset, end_offset); if (*start_offset != *end_offset) return clutter_text_get_selection (CLUTTER_TEXT (actor)); else return NULL; } /* ClutterText only allows one selection. So this method will set the selection if no selection exists, but as in gailentry, it will not change the current selection */ static gboolean cally_text_add_selection (AtkText *text, gint start_offset, gint end_offset) { ClutterActor *actor; gint select_start, select_end; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return FALSE; _cally_text_get_selection_bounds (CLUTTER_TEXT (actor), &select_start, &select_end); /* Like in gailentry, if there is already a selection, then don't allow another * to be added, since ClutterText only supports one selected region. */ if (select_start == select_end) { clutter_text_set_selection (CLUTTER_TEXT (actor), start_offset, end_offset); return TRUE; } else return FALSE; } static gboolean cally_text_remove_selection (AtkText *text, gint selection_num) { ClutterActor *actor = NULL; gint caret_pos = -1; gint select_start = -1; gint select_end = -1; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return FALSE; /* only one selection is allowed */ if (selection_num != 0) return FALSE; _cally_text_get_selection_bounds (CLUTTER_TEXT (actor), &select_start, &select_end); if (select_start != select_end) { /* Setting the start & end of the selected region to the caret position * turns off the selection. */ caret_pos = clutter_text_get_cursor_position (CLUTTER_TEXT (actor)); clutter_text_set_selection (CLUTTER_TEXT (actor), caret_pos, caret_pos); return TRUE; } else return FALSE; } static gboolean cally_text_set_selection (AtkText *text, gint selection_num, gint start_offset, gint end_offset) { ClutterActor *actor = NULL; gint select_start = -1; gint select_end = -1; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return FALSE; /* Like in gailentry, only let the user move the selection if one is set, * and if the selection_num is 0 */ if (selection_num != 0) return FALSE; _cally_text_get_selection_bounds (CLUTTER_TEXT (actor), &select_start, &select_end); if (select_start != select_end) { clutter_text_set_selection (CLUTTER_TEXT (actor), start_offset, end_offset); return TRUE; } else return FALSE; } static AtkAttributeSet* cally_text_get_run_attributes (AtkText *text, gint offset, gint *start_offset, gint *end_offset) { ClutterActor *actor = NULL; ClutterText *clutter_text = NULL; AtkAttributeSet *at_set = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return NULL; /* Clutter don't have any reference to the direction*/ clutter_text = CLUTTER_TEXT (actor); at_set = _cally_misc_layout_get_run_attributes (at_set, clutter_text, offset, start_offset, end_offset); return at_set; } static AtkAttributeSet* cally_text_get_default_attributes (AtkText *text) { ClutterActor *actor = NULL; ClutterText *clutter_text = NULL; AtkAttributeSet *at_set = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return NULL; clutter_text = CLUTTER_TEXT (actor); at_set = _cally_misc_layout_get_default_attributes (at_set, clutter_text); return at_set; } static void cally_text_get_character_extents (AtkText *text, gint offset, gint *xp, gint *yp, gint *widthp, gint *heightp, AtkCoordType coords) { ClutterActor *actor = NULL; ClutterText *clutter_text = NULL; gint x = 0, y = 0, width = 0, height = 0; gint index, x_window, y_window, x_toplevel, y_toplevel; gint x_layout, y_layout; PangoLayout *layout; PangoRectangle extents; const gchar *text_value; ClutterVertex verts[4]; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ goto done; clutter_text = CLUTTER_TEXT (actor); text_value = clutter_text_get_text (clutter_text); index = g_utf8_offset_to_pointer (text_value, offset) - text_value; layout = clutter_text_get_layout (clutter_text); pango_layout_index_to_pos (layout, index, &extents); /* handle RTL text layout */ if (extents.width < 0) { extents.x += extents.width; extents.width = -extents.width; } clutter_actor_get_abs_allocation_vertices (actor, verts); x_window = verts[0].x; y_window = verts[0].y; clutter_text_get_layout_offsets (clutter_text, &x_layout, &y_layout); x = (extents.x / PANGO_SCALE) + x_layout + x_window; y = (extents.y / PANGO_SCALE) + y_layout + y_window; width = extents.width / PANGO_SCALE; height = extents.height / PANGO_SCALE; if (coords == ATK_XY_SCREEN) { _cally_actor_get_top_level_origin (actor, &x_toplevel, &y_toplevel); x += x_toplevel; y += y_toplevel; } done: if (widthp) *widthp = width; if (heightp) *heightp = height; if (xp) *xp = x; if (yp) *yp = y; } static gint cally_text_get_offset_at_point (AtkText *text, gint x, gint y, AtkCoordType coords) { ClutterActor *actor = NULL; ClutterText *clutter_text = NULL; const gchar *text_value; gint index; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) /* State is defunct */ return -1; clutter_text = CLUTTER_TEXT (actor); index = _cally_misc_get_index_at_point (clutter_text, x, y, coords); text_value = clutter_text_get_text (clutter_text); if (index == -1) return g_utf8_strlen (text_value, -1); else return g_utf8_pointer_to_offset (text_value, text_value + index); } /******** Auxiliar private methods ******/ /* ClutterText only maintains the current cursor position and a extra selection bound, but this could be before or after the cursor. This method returns the start and end positions in a proper order (so start<=end). This is similar to the function gtk_editable_get_selection_bounds */ static void _cally_text_get_selection_bounds (ClutterText *clutter_text, gint *start_offset, gint *end_offset) { gint pos = -1; gint selection_bound = -1; pos = clutter_text_get_cursor_position (clutter_text); selection_bound = clutter_text_get_selection_bound (clutter_text); if (pos < selection_bound) { *start_offset = pos; *end_offset = selection_bound; } else { *start_offset = selection_bound; *end_offset = pos; } } static void _cally_text_delete_text_cb (ClutterText *clutter_text, gint start_pos, gint end_pos, gpointer data) { CallyText *cally_text = NULL; g_return_if_fail (CALLY_IS_TEXT (data)); /* Ignore zero lengh deletions */ if (end_pos - start_pos == 0) return; cally_text = CALLY_TEXT (data); if (!cally_text->priv->signal_name_delete) { cally_text->priv->signal_name_delete = "text_changed::delete"; cally_text->priv->position_delete = start_pos; cally_text->priv->length_delete = end_pos - start_pos; } _notify_delete (cally_text); } static void _cally_text_insert_text_cb (ClutterText *clutter_text, gchar *new_text, gint new_text_length, gint *position, gpointer data) { CallyText *cally_text = NULL; g_return_if_fail (CALLY_IS_TEXT (data)); cally_text = CALLY_TEXT (data); if (!cally_text->priv->signal_name_insert) { cally_text->priv->signal_name_insert = "text_changed::insert"; cally_text->priv->position_insert = *position; cally_text->priv->length_insert = g_utf8_strlen (new_text, new_text_length); } /* * The signal will be emitted when the cursor position is updated, * or in an idle handler if it not updated. */ if (cally_text->priv->insert_idle_handler == 0) cally_text->priv->insert_idle_handler = clutter_threads_add_idle (_idle_notify_insert, cally_text); } /***** atkeditabletext.h ******/ static void cally_text_editable_text_interface_init (AtkEditableTextIface *iface) { g_return_if_fail (iface != NULL); iface->set_text_contents = cally_text_set_text_contents; iface->insert_text = cally_text_insert_text; iface->delete_text = cally_text_delete_text; iface->set_run_attributes = NULL; iface->copy_text = NULL; iface->cut_text = NULL; iface->paste_text = NULL; } static void cally_text_set_text_contents (AtkEditableText *text, const gchar *string) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) return; if (!clutter_text_get_editable (CLUTTER_TEXT (actor))) return; clutter_text_set_text (CLUTTER_TEXT (actor), string); } static void cally_text_insert_text (AtkEditableText *text, const gchar *string, gint length, gint *position) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) return; if (!clutter_text_get_editable (CLUTTER_TEXT (actor))) return; if (length < 0) length = g_utf8_strlen (string, -1); clutter_text_insert_text (CLUTTER_TEXT (actor), string, *position); /* we suppose that the text insertion will be succesful, clutter-text doesn't warn about it. A option would be search for the text, but it seems not really required */ *position += length; } static void cally_text_delete_text (AtkEditableText *text, gint start_pos, gint end_pos) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (text); if (actor == NULL) return; if (!clutter_text_get_editable (CLUTTER_TEXT (actor))) return; clutter_text_delete_text (CLUTTER_TEXT (actor), start_pos, end_pos); } /* CallyActor */ static void cally_text_notify_clutter (GObject *obj, GParamSpec *pspec) { ClutterText *clutter_text = NULL; CallyText *cally_text = NULL; AtkObject *atk_obj = NULL; clutter_text = CLUTTER_TEXT (obj); atk_obj = clutter_actor_get_accessible (CLUTTER_ACTOR (obj)); cally_text = CALLY_TEXT (atk_obj); if (g_strcmp0 (pspec->name, "position") == 0) { /* the selection can change also for the cursor position */ if (_check_for_selection_change (cally_text, clutter_text)) g_signal_emit_by_name (atk_obj, "text_selection_changed"); g_signal_emit_by_name (atk_obj, "text_caret_moved", clutter_text_get_cursor_position (clutter_text)); } else if (g_strcmp0 (pspec->name, "selection-bound") == 0) { if (_check_for_selection_change (cally_text, clutter_text)) g_signal_emit_by_name (atk_obj, "text_selection_changed"); } else if (g_strcmp0 (pspec->name, "editable") == 0) { atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, clutter_text_get_editable (clutter_text)); } else if (g_strcmp0 (pspec->name, "activatable") == 0) { _check_activate_action (cally_text, clutter_text); } else if (g_strcmp0 (pspec->name, "password-char") == 0) { if (clutter_text_get_password_char (clutter_text) != 0) atk_object_set_role (atk_obj, ATK_ROLE_PASSWORD_TEXT); else atk_object_set_role (atk_obj, ATK_ROLE_TEXT); } else { CALLY_ACTOR_CLASS (cally_text_parent_class)->notify_clutter (obj, pspec); } } static gboolean _check_for_selection_change (CallyText *cally_text, ClutterText *clutter_text) { gboolean ret_val = FALSE; gint clutter_pos = -1; gint clutter_bound = -1; clutter_pos = clutter_text_get_cursor_position (clutter_text); clutter_bound = clutter_text_get_selection_bound (clutter_text); if (clutter_pos != clutter_bound) { if (clutter_pos != cally_text->priv->cursor_position || clutter_bound != cally_text->priv->selection_bound) /* * This check is here as this function can be called for * notification of selection_bound and current_pos. The * values of current_pos and selection_bound may be the same * for both notifications and we only want to generate one * text_selection_changed signal. */ ret_val = TRUE; } else { /* We had a selection */ ret_val = (cally_text->priv->cursor_position != cally_text->priv->selection_bound); } cally_text->priv->cursor_position = clutter_pos; cally_text->priv->selection_bound = clutter_bound; return ret_val; } static gboolean _idle_notify_insert (gpointer data) { CallyText *cally_text = NULL; cally_text = CALLY_TEXT (data); cally_text->priv->insert_idle_handler = 0; _notify_insert (cally_text); return FALSE; } static void _notify_insert (CallyText *cally_text) { if (cally_text->priv->signal_name_insert) { g_signal_emit_by_name (cally_text, cally_text->priv->signal_name_insert, cally_text->priv->position_insert, cally_text->priv->length_insert); cally_text->priv->signal_name_insert = NULL; } } static void _notify_delete (CallyText *cally_text) { if (cally_text->priv->signal_name_delete) { g_signal_emit_by_name (cally_text, cally_text->priv->signal_name_delete, cally_text->priv->position_delete, cally_text->priv->length_delete); cally_text->priv->signal_name_delete = NULL; } } /* atkaction */ static void _cally_text_activate_action (CallyActor *cally_actor) { ClutterActor *actor = NULL; actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); clutter_text_activate (CLUTTER_TEXT (actor)); } static void _check_activate_action (CallyText *cally_text, ClutterText *clutter_text) { if (clutter_text_get_activatable (clutter_text)) { if (cally_text->priv->activate_action_id != 0) return; cally_text->priv->activate_action_id = cally_actor_add_action (CALLY_ACTOR (cally_text), "activate", NULL, NULL, _cally_text_activate_action); } else { if (cally_text->priv->activate_action_id == 0) return; if (cally_actor_remove_action (CALLY_ACTOR (cally_text), cally_text->priv->activate_action_id)) { cally_text->priv->activate_action_id = 0; } } } /* GailTextUtil/GailMisc reimplementation methods */ /** * _cally_misc_add_attribute: * * Reimplementation of gail_misc_layout_get_run_attributes (check this * function for more documentation). * * Returns: A pointer to the new #AtkAttributeSet. **/ static AtkAttributeSet* _cally_misc_add_attribute (AtkAttributeSet *attrib_set, AtkTextAttribute attr, gchar *value) { AtkAttributeSet *return_set; AtkAttribute *at = malloc (sizeof (AtkAttribute)); at->name = g_strdup (atk_text_attribute_get_name (attr)); at->value = value; return_set = g_slist_prepend(attrib_set, at); return return_set; } static gint _cally_atk_attribute_lookup_func (gconstpointer data, gconstpointer user_data) { AtkTextAttribute attr = (AtkTextAttribute) user_data; AtkAttribute *at = (AtkAttribute *) data; if (!g_strcmp0 (at->name, atk_text_attribute_get_name (attr))) return 0; return -1; } static gboolean _cally_misc_find_atk_attribute (AtkAttributeSet *attrib_set, AtkTextAttribute attr) { GSList* result = g_slist_find_custom ((GSList*) attrib_set, (gconstpointer) attr, _cally_atk_attribute_lookup_func); return (result != NULL); } /** * _cally_misc_layout_atk_attributes_from_pango: * * Store the pango attributes as their ATK equivalent in an existing * #AtkAttributeSet. * * Returns: A pointer to the updated #AtkAttributeSet. **/ static AtkAttributeSet* _cally_misc_layout_atk_attributes_from_pango (AtkAttributeSet *attrib_set, PangoAttrIterator *iter) { PangoAttrString *pango_string; PangoAttrInt *pango_int; PangoAttrColor *pango_color; PangoAttrLanguage *pango_lang; PangoAttrFloat *pango_float; gchar *value = NULL; if ((pango_string = (PangoAttrString*) pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY)) != NULL) { value = g_strdup_printf("%s", pango_string->value); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FAMILY_NAME, value); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STYLE)) != NULL) { attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STYLE, g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, pango_int->value))); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT)) != NULL) { value = g_strdup_printf("%i", pango_int->value); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_WEIGHT, value); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_VARIANT)) != NULL) { attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_VARIANT, g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, pango_int->value))); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STRETCH)) != NULL) { attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STRETCH, g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, pango_int->value))); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_SIZE)) != NULL) { value = g_strdup_printf("%i", pango_int->value / PANGO_SCALE); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_SIZE, value); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE)) != NULL) { attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_UNDERLINE, g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, pango_int->value))); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH)) != NULL) { attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STRIKETHROUGH, g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, pango_int->value))); } if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_RISE)) != NULL) { value = g_strdup_printf("%i", pango_int->value); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_RISE, value); } if ((pango_lang = (PangoAttrLanguage*) pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE)) != NULL) { value = g_strdup( pango_language_to_string( pango_lang->value)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_LANGUAGE, value); } if ((pango_float = (PangoAttrFloat*) pango_attr_iterator_get (iter, PANGO_ATTR_SCALE)) != NULL) { value = g_strdup_printf("%g", pango_float->value); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_SCALE, value); } if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND)) != NULL) { value = g_strdup_printf ("%u,%u,%u", pango_color->color.red, pango_color->color.green, pango_color->color.blue); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR, value); } if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, PANGO_ATTR_BACKGROUND)) != NULL) { value = g_strdup_printf ("%u,%u,%u", pango_color->color.red, pango_color->color.green, pango_color->color.blue); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_BG_COLOR, value); } return attrib_set; } static AtkAttributeSet* _cally_misc_add_actor_color_to_attribute_set (AtkAttributeSet *attrib_set, ClutterText *clutter_text) { ClutterColor color; gchar *value; clutter_text_get_color (clutter_text, &color); value = g_strdup_printf ("%u,%u,%u", (guint) (color.red * 65535 / 255), (guint) (color.green * 65535 / 255), (guint) (color.blue * 65535 / 255)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR, value); return attrib_set; } /** * _cally_misc_layout_get_run_attributes: * * Reimplementation of gail_misc_layout_get_run_attributes (check this * function for more documentation). * * Returns: A pointer to the #AtkAttributeSet. **/ static AtkAttributeSet* _cally_misc_layout_get_run_attributes (AtkAttributeSet *attrib_set, ClutterText *clutter_text, gint offset, gint *start_offset, gint *end_offset) { PangoAttrIterator *iter; PangoAttrList *attr; gint index, start_index, end_index; gboolean is_next = TRUE; glong len; PangoLayout *layout = clutter_text_get_layout (clutter_text); gchar *text = (gchar*) clutter_text_get_text (clutter_text); len = g_utf8_strlen (text, -1); /* Grab the attributes of the PangoLayout, if any */ if ((attr = pango_layout_get_attributes (layout)) == NULL) { *start_offset = 0; *end_offset = len; _cally_misc_add_actor_color_to_attribute_set (attrib_set, clutter_text); } else { iter = pango_attr_list_get_iterator (attr); /* Get invariant range offsets */ /* If offset out of range, set offset in range */ if (offset > len) offset = len; else if (offset < 0) offset = 0; index = g_utf8_offset_to_pointer (text, offset) - text; pango_attr_iterator_range (iter, &start_index, &end_index); while (is_next) { if (index >= start_index && index < end_index) { *start_offset = g_utf8_pointer_to_offset (text, text + start_index); if (end_index == G_MAXINT) /* Last iterator */ end_index = len; *end_offset = g_utf8_pointer_to_offset (text, text + end_index); break; } is_next = pango_attr_iterator_next (iter); pango_attr_iterator_range (iter, &start_index, &end_index); } /* Get attributes */ attrib_set = _cally_misc_layout_atk_attributes_from_pango (attrib_set, iter); pango_attr_iterator_destroy (iter); } if (!_cally_misc_find_atk_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR)) attrib_set = _cally_misc_add_actor_color_to_attribute_set (attrib_set, clutter_text); return attrib_set; } /** * _cally_misc_layout_get_default_attributes: * * Reimplementation of gail_misc_layout_get_default_attributes (check this * function for more documentation). * * Returns: A pointer to the #AtkAttributeSet. **/ static AtkAttributeSet* _cally_misc_layout_get_default_attributes (AtkAttributeSet *attrib_set, ClutterText *clutter_text) { PangoLayout *layout; PangoContext *context; PangoLanguage* language; PangoFontDescription* font; PangoWrapMode mode; gchar *value = NULL; gint int_value; ClutterTextDirection text_direction; PangoAttrIterator *iter; PangoAttrList *attr; text_direction = clutter_actor_get_text_direction (CLUTTER_ACTOR (clutter_text)); switch (text_direction) { case CLUTTER_TEXT_DIRECTION_DEFAULT: value = g_strdup ("none"); break; case CLUTTER_TEXT_DIRECTION_LTR: value = g_strdup ("ltr"); break; case CLUTTER_TEXT_DIRECTION_RTL: value = g_strdup ("rtl"); break; default: value = g_strdup ("none"); break; } attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_DIRECTION, value); layout = clutter_text_get_layout (clutter_text); context = pango_layout_get_context (layout); if (context) { if ((language = pango_context_get_language (context))) { value = g_strdup (pango_language_to_string (language)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_LANGUAGE, value); } if ((font = pango_context_get_font_description (context))) { value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, pango_font_description_get_style (font))); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STYLE, value); value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, pango_font_description_get_variant (font))); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_VARIANT, value); value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, pango_font_description_get_stretch (font))); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_STRETCH, value); value = g_strdup (pango_font_description_get_family (font)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FAMILY_NAME, value); value = g_strdup_printf ("%d", pango_font_description_get_weight (font)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_WEIGHT, value); value = g_strdup_printf ("%i", pango_font_description_get_size (font) / PANGO_SCALE); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_SIZE, value); } } if (pango_layout_get_justify (layout)) int_value = 3; else { PangoAlignment align; align = pango_layout_get_alignment (layout); if (align == PANGO_ALIGN_LEFT) int_value = 0; else if (align == PANGO_ALIGN_CENTER) int_value = 2; else /* if (align == PANGO_ALIGN_RIGHT) */ int_value = 1; } value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, int_value)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_JUSTIFICATION, value); mode = pango_layout_get_wrap (layout); if (mode == PANGO_WRAP_WORD) int_value = 2; else /* if (mode == PANGO_WRAP_CHAR) */ int_value = 1; value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, int_value)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_WRAP_MODE, value); if ((attr = clutter_text_get_attributes (clutter_text))) { iter = pango_attr_list_get_iterator (attr); /* Get attributes */ attrib_set = _cally_misc_layout_atk_attributes_from_pango (attrib_set, iter); pango_attr_iterator_destroy (iter); } if (!_cally_misc_find_atk_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR)) attrib_set = _cally_misc_add_actor_color_to_attribute_set (attrib_set, clutter_text); value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_FG_STIPPLE, 0)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FG_STIPPLE, value); value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_STIPPLE, 0)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_BG_STIPPLE, value); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_BG_FULL_HEIGHT, g_strdup_printf ("%i", 0)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, g_strdup_printf ("%i", 0)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, g_strdup_printf ("%i", 0)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, g_strdup_printf ("%i", 0)); value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, clutter_text_get_editable (clutter_text))); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_EDITABLE, value); value = g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_INVISIBLE, !clutter_actor_is_visible (CLUTTER_ACTOR (clutter_text)))); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_INVISIBLE, value); value = g_strdup_printf ("%i", pango_layout_get_indent (layout)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_INDENT, value); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_RIGHT_MARGIN, g_strdup_printf ("%i", 0)); attrib_set = _cally_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_LEFT_MARGIN, g_strdup_printf ("%i", 0)); return attrib_set; } static int _cally_misc_get_index_at_point (ClutterText *clutter_text, gint x, gint y, AtkCoordType coords) { gint index, x_window, y_window, x_toplevel, y_toplevel; gint x_temp, y_temp; gboolean ret; ClutterVertex verts[4]; PangoLayout *layout; gint x_layout, y_layout; clutter_text_get_layout_offsets (clutter_text, &x_layout, &y_layout); clutter_actor_get_abs_allocation_vertices (CLUTTER_ACTOR (clutter_text), verts); x_window = verts[0].x; y_window = verts[0].y; x_temp = x - x_layout - x_window; y_temp = y - y_layout - y_window; if (coords == ATK_XY_SCREEN) { _cally_actor_get_top_level_origin (CLUTTER_ACTOR (clutter_text), &x_toplevel, &y_toplevel); x_temp -= x_toplevel; y_temp -= y_toplevel; } layout = clutter_text_get_layout (clutter_text); ret = pango_layout_xy_to_index (layout, x_temp * PANGO_SCALE, y_temp * PANGO_SCALE, &index, NULL); if (!ret) { if (x_temp < 0 || y_temp < 0) index = 0; else index = -1; } return index; } ����������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-factory.h��������������������������������������������������0000664�0001750�0001750�00000007604�14211404421�022335� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Based on gailfactory.h from GAIL * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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 _CALLY_FACTORY_H__ #define _CALLY_FACTORY_H__ #include <glib-object.h> #include <atk/atkobject.h> /** * CALLY_ACCESSIBLE_FACTORY: * @type: GType of the accessible which is created by the factory * @type_as_function: prefix of the accessible object methods * @opt_create_accessible: method to instantiate the accessibility object * * Defines a new #AtkObjectFactory factory to create accessible * objects of a specific GType. It defines the factory GType and also * overrides the proper #AtkObjectFactory methods. * * It assumes that the accessibility object provides a * @opt_create_accessible method in order to create the accessibility * object. It returns a @type GType object. * * Since: 1.4 */ #define CALLY_ACCESSIBLE_FACTORY(type, type_as_function, opt_create_accessible) \ \ static GType \ type_as_function ## _factory_get_accessible_type (void) \ { \ return type; \ } \ \ static AtkObject* \ type_as_function ## _factory_create_accessible (GObject *obj) \ { \ ClutterActor *actor; \ AtkObject *accessible; \ \ g_return_val_if_fail (CLUTTER_ACTOR (obj), NULL); \ \ actor = CLUTTER_ACTOR (obj); \ \ accessible = opt_create_accessible (actor); \ \ return accessible; \ } \ \ static void \ type_as_function ## _factory_class_init (AtkObjectFactoryClass *klass) \ { \ klass->create_accessible = type_as_function ## _factory_create_accessible; \ klass->get_accessible_type = type_as_function ## _factory_get_accessible_type;\ } \ \ static GType \ type_as_function ## _factory_get_type (void) \ { \ static GType t = 0; \ \ if (!t) \ { \ char *name; \ static const GTypeInfo tinfo = \ { \ sizeof (AtkObjectFactoryClass), \ NULL, NULL, (GClassInitFunc) type_as_function ## _factory_class_init, \ NULL, NULL, sizeof (AtkObjectFactory), 0, NULL, NULL \ }; \ \ name = g_strconcat (g_type_name (type), "Factory", NULL); \ t = g_type_register_static ( \ ATK_TYPE_OBJECT_FACTORY, name, &tinfo, 0); \ free (name); \ } \ \ return t; \ } /** * CALLY_ACTOR_SET_FACTORY: * @widget_type: GType of the clutter actor * @type_as_function: prefix of the accessible object methods * * Sets the #AtkObjectFactory to be used in order to instantiate * accessibility objects for the actor which GType is @widget_type. * * Since: 1.4 */ #define CALLY_ACTOR_SET_FACTORY(widget_type, type_as_function) \ atk_registry_set_factory_type (atk_get_default_registry (), \ widget_type, \ type_as_function ## _factory_get_type ()) #endif /* _CALLY_FACTORY_H__ */ ����������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-actor-private.h��������������������������������������������0000664�0001750�0001750�00000003032�14211404421�023435� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Some parts are based on GailWidget from GAIL * GAIL - The GNOME Accessibility Implementation Library * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_ACTOR_PRIVATE_H__ #define __CALLY_ACTOR_PRIVATE_H__ #include "cally-actor.h" /* * Auxiliar define, in order to get the clutter actor from the AtkObject using * AtkGObject methods * */ #define CALLY_GET_CLUTTER_ACTOR(cally_object) \ (CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (cally_object)))) void _cally_actor_get_top_level_origin (ClutterActor *actor, gint *x, gint *y); #endif /* __CALLY_ACTOR_PRIVATE_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/ChangeLog.pre-cally-merge����������������������������������������0000664�0001750�0001750�00000074143�14211404421�024153� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# DO NOT MODIFY THIS FILE # # Clutter uses the Git commit log to generate the ChangeLog files when # creating the tarball for releases and snapshots. This file is maintained # only for historical reasons. 2010-07-05 Alejandro Pieiro <apinheiro@igalia.com> Cleaning ClutterText * Removing superfluous g_return_if_fail * Removing unused ClutterText::text-changed callback 2010-07-05 Alejandro Pieiro <apinheiro@igalia.com> Refactoring "window:create" and "window:destroy" emission code Previously "window:create" and "window:destroy" were emitted on CallyUtil. Although it works, and CallyUtil already have callbacks to stage_added/removed signals, I think that it is more tidy/clear to do that on CallyRoot: * CallyRoot already has code to manage ClutterStage addition/removal * In fact, we can see CallyRoot as the object exposing the a11y information from ClutterStageManager, so it fits better here. * CallyUtil callbacks these signals are related to key event listeners (key snooper simulation). One of the main CallyUtil responsabilities is managing event (connecting, emitting), so I would prefer to not start to add/mix more functionalities here. Ideally it would be better to emit all CallyStage methods from CallyStage, but it is clear that "create" and "destroy" are more easy to emit from a external object. 2010-06-25 Alejandro Pieiro <apinheiro@igalia.com> Cleaning clutter-actor Some cleaning changes: * Using CallyActionFunc instead of ACTION_FUNC * Removing a extra * on cally-actor-private macro documentation, to avoid gtk-doc warnings * Using g_strcmp0 instead of strcmp Changes to be applied on clutter (see CB#2097 and CB#2098), applied also here to maintain the sync. My intention is keep this developing line until the real integration, in order to make a final independent cally release. 2010-06-14 Alejandro Pieiro <apinheiro@igalia.com> Adding -Wshadow option and solving warnings related 2010-06-14 Alejandro Pieiro <apinheiro@igalia.com> Added dummy padding for future vt expasion Added dummy padding on the different classes structures, to allow future expansion of virtual methods. I decided to add this on all the classes, although it would be really unlikely in some cases (ie, CallyGroup) 2010-06-10 Alejandro Pieiro <apinheiro@igalia.com> Adding and emitting "window:xxx" methods on CallyStage Added some window related signals on CallyStage: * window:activate and window:deactivate emitted from CallyStage * window:create and window:destroy emitted from CallyUtil ClutterStage doesn't fulfill 100% the window concept, but some of these signals are important in order to identify the object which could emit global/key events. The current implementation is equivalent to GailWindow one, supposing CallyStage as the only window related window. This likely would change in any clutter-based toolkit implement a real Window object, so a more flexible procedure would be required. But we would solve problems step by step. BTW: as I explain here [1] I really think that the current way to implement "window:xxx" signals (not defined in ATK but expected from the a11y implementation toolkit) somewhat hacky and undocumented (you need to check at-spi2 idls to know that you require to emit this events) Related to bug CB#2147 (Orca doesn't speech out properly non printable chars on some environments), as solves this problem in a specific case. [1] https://bugzilla.gnome.org/show_bug.cgi?id=620977#c1 2010-06-04 Alejandro Pieiro <apinheiro@igalia.com> Avoiding clutter_stage_get_key_focus warning For any reason, in some cases, a clutter actor doesn't have a stage associated. We use the default one as fallback. 2010-06-02 Alejandro Pieiro <apinheiro@igalia.com> Added a defunct check on cally_group_get_n_children Some warnings appeared when we tried to get the number of children of a defunct object. 2010-06-02 Alejandro Pieiro <apinheiro@igalia.com> Update TODO file Use Bugzilla to setting missing features. 2010-06-01 Alejandro Pieiro <apinheiro@igalia.com> Removing heuristics to decide CallyRectable/CallyTexture role Previously CallyRectangle and CallyTexture used some heuristics in order to decide the default role: ATK_ROLE_IMAGE or ATK_PUSH_BUTTON, as in practice most applications using these objects as buttons were not applying the proper role. As this is a hack, and a application responsibility, finally we have decided to remove this, so the default role is ATK_ROLE_IMAGE. Fixes CB#1732 (CallyTexture and CallyRectangle uses some heuristics to decide the role) 2010-05-28 Alejandro Pieiro <apinheiro@igalia.com> Post-release version bump, after release 1.2.0 I wrongly added the last commit on the 1.1 branch, when in fact it requires clutter 1.3.3, and on the README it is explained that cally versioning is tied to clutter versioning. In order to solve that a clutter-1.2 release branch is created, and bumped the version. This versioning tyding will be obsolete when the integration with clutter become a reality, but in the same way, this is the way to tidy this thinking in this integration. 2010-04-13 Alejandro Pieiro <apinheiro@igalia.com> Use clutter_actor_get_accessible The method clutter_actor_get_accessible was added due work on bug 2070, and should be used to get the accessibility object, instead of atk_gobject_accessible_for_object This would allow to implement a11y support directly on any clutter based toolkit object (ie StLabel). 2010-05-13 Alejandro Pieiro <apinheiro@igalia.com> Added CallyClone example 2010-05-13 Alejandro Pieiro <apinheiro@igalia.com> Added a11y support for ClutterClone Resolved in the most simplified way, just as a image and a default description to identify cloned objects. More information: http://lists.o-hand.com/clutter/3797.html 2010-04-14 Alejandro Pieiro <apinheiro@igalia.com> Remove gail dependency Removed to avoid gdk/gtk dependency on cally. Part of bug CB#2072 solution 2010-04-14 Alejandro Pieiro <apinheiro@igalia.com> Avoid gdk functions filling AtkKeyEventStruct Now when AtkKeyEventStruct is filled in order to emit any key event signal, it is not used any gdk function on the keyval or the string fields. event_string is filled with the printable character if possible, if not (Ctrl, Alt, etc) it is set as NULL. Now the AT should take care of that, at least until we define atk key event struct in a more agnostic way (not tied to gdk/gtk). See orca bug bgo#616206 as a example. Part of bug CB#2072 solution. 2010-04-15 Alejandro Pieiro <apinheiro@igalia.com> Added gail_misc_layout_get_run_attributes implementation Part of bug CB#2072 solution 2010-04-14 Alejandro Pieiro <apinheiro@igalia.com> Remove gailutil/gailmisc functions calls This is because gailutil/gailmisc added a gdk/gtk dependency, and this dependency is being removed. New cally-specific implementation are required. Related to bug CB#1733 Part of bug CB#2072 solution 2010-04-13 Alejandro Pieiro <apinheiro@igalia.com> Fixing the libdir directory in some examples 2010-03-26 Alejandro Pieiro <apinheiro@igalia.com> Previous cally.pc.in update was incomplete The previous commit was not tested properly, and it was missing one detail. Sorry for the noise. 2010-03-26 Alejandro Pieiro <apinheiro@igalia.com> Update cally.pc.in after module relocation Previous commit places cally module in a different directory. It also corrects where the include directory is placed. 2010-03-15 Alejandro Pieiro <apinheiro@igalia.com> Use a proper clutter module directory Use a proper clutter module directory, instead of keep being installed on a gtk directory. Improve the cally-examples-util, in order to keep using hardcoded values. Fixes CB#1737 (Wrong cally module directory) 2010-03-15 Alejandro Pieiro <apinheiro@igalia.com> Proper UTF-8 headers 2010-02-25 Alejandro Pieiro <apinheiro@igalia.com> Change "--with-dbus" option for "atk-bridge-dir" on examples The atk-adaptor in the dbus at-spi was renamed to atk-bridge due some apps hardcoding the name. So right now the only difference is the final directory. So the option was removed, and atk-bridge-dir added. This also allows to use the system atk-bridge or the compiled in any developing environment, so it is really more flexible. See the README (updated with this commit) for more information. 2010-02-19 Alejandro Pieiro <apinheiro@igalia.com> Added .gitignore file 2010-02-19 Alejandro Pieiro <apinheiro@igalia.com> Release 1.1.1 2010-02-19 Alejandro Pieiro <apinheiro@igalia.com> Using clutter_threads_idle_add instead of the gdk one The idea is being as less gdk dependent as possible. Right now it is inviable to remove the dependency (gailutil and so on) but hypothetically, the ideal is remove this dependency in the future, and being "clutter pure". 2010-02-15 Alejandro Pieiro <apinheiro@igalia.com> Check if the state is defunct on cally_text_get_name Check if the state is defunct on cally_text_get_name, in order to avoid warnings cally clutter_text_get_text when the clutter object is NULL 2010-01-26 Alejandro Pieiro <apinheiro@igalia.com> Update on configure.ac after autoupdate call 2010-02-02 Alejandro Pieiro <apinheiro@igalia.com> Try to apply the key modifiers to event->keyval like GDK does ClutterKeyEvent defines the keyval without taking into account the modifiers. GDK defines this keyval taking into account the modifiers. AtkKeyEventStruct expects the keyval in a GDK fashion, so a translation is required. This patch tries to do that using using gdk_keymap_translate_keyboard_state. This functions only works correctly if gtk has been initialized, so the fallback is create the AtkKeyEventStruct with the keyval provided by Clutter. More information: http://library.gnome.org/devel/atk/stable/AtkUtil.html#AtkKeyEventStruct http://bugzilla.openedhand.com/show_bug.cgi?id=1961 2010-02-02 Alejandro Pieiro <apinheiro@igalia.com> Filling AtkKeyEventStruct->string used on the atk key event listeners Finally we use directly gdk_keyval_name. Not the ideal solution, but works, and more important, it avoids to reimplement this issue on clutter or cally. More information on Bug 1952 Fixes http://bugzilla.openedhand.com/show_bug.cgi?id=1952 2010-01-22 Alejandro Pieiro <apinheiro@igalia.com> Added AM_PROG_CC_C_O option to avoid a warning running configure 2010-01-22 Alejandro Pieiro <apinheiro@igalia.com> Fix clutter version required on the pc files 2010-01-22 Alejandro Pieiro <apinheiro@igalia.com> Check on configure time if any x11 clutter backend is in use It uses AC_CHECK_LIB in order to check if x11 backend is in use. It also modifies cally-actor in order to use the information retrieved. So now cally has a minimum multi-backend support. It only manages a x11 (glx or eglx) backend, but at least, it checks it, so you can compile cally without this backend. It probably will not work properly, but at least you can compile and execute it. Solves http://bugzilla.openedhand.com/show_bug.cgi?id=1736 2010-01-21 Alejandro Pieiro <apinheiro@igalia.com> Fix the perspective problems computing the on-screen extensions Use clutter_actor_get_abs_allocation_vertices and clutter_actor_get_transformed_size to get the real on-screen position and size, instead of compute that using the geometry and the anchor point. It also update cally-atkcomponent-example, adding a actor inside a nested ClutterGroup hierarchy. Fixes: http://bugzilla.openedhand.com/show_bug.cgi?id=1731 2010-01-13 Alejandro Pieiro <apinheiro@igalia.com> Added extra button on cally-atkeditabletext-example Added a button to print the current cursor position, and also extend the size of the buttons 2010-01-12 Alejandro Pieiro <apinheiro@igalia.com> Remove superfluous g_print on CallyStage 2009-12-03 Alejandro Pieiro <apinheiro@igalia.com> Use clutter_stage_manager_peek_stages to avoid a leak 2009-12-03 Alejandro Pieiro <apinheiro@igalia.com> Added ATK_STATE_SELECTABLE_TEXT management 2009-11-26 Alejandro Pieiro <apinheiro@igalia.com> Manage properly ATK_STATE_ACTIVE on CallyStage * cally/cally-stage.c Added private struct (cally_stage_class_init),(cally_stage_init),(cally_stage_real_initalize): Initialization stuff (cally_stage_activate_cb) (cally_stage_deactivate_cb): new ClutterStage signal callbacks, change the internal value of active, and notify the atk state change (cally_stage_ref_state_set): manage ATK_STATE_ACTIVATE * examples/cally-atktext-example2.c If possible, creates two stage, in order to test ATK_STATE_ACTIVATE 2009-11-24 Alejandro Pieiro <apinheiro@igalia.com> Focused state change and focused object notification * cally/cally-actor.h (focus_clutter): added virtual method for the focus management * cally/cally-actor.c (cally_actor_component_interface_init) (cally_actor_add_focus_handler) (cally_actor_remove_focus_handler): Implementation of the AtkComponent methods add_focus_handler and remove_focus_handler (cally_actor_focus_event): CallyActor specific focus handler, notify the state focused change (cally_actor_focus_clutter) (cally_actor_real_focus_clutter): Handlers for the ClutterActor "key-focus-in" and "key-focus-out" signals. Emit the signal AtkObject "focus_event" and set the focus object with atk_focus_tracker_notify. (cally_actor_initialize): Connect to the signals "key-focus-in" and "key-focus-out", use atk_component_add_focus_handler to add cally_actor_focus_event Note: The focus management is more simplified that the gail one. The main reason is that the focus management in GTK is really more complex that the Clutter one. 2009-11-24 Alejandro Pieiro <apinheiro@igalia.com> Modify cally-atkeditabletext-example.c to manage "activatable" status 2009-11-24 Alejandro Pieiro <apinheiro@igalia.com> Added "activate" action in ClutterText * cally/cally-actor.h * cally/cally-actor.c cally_actor_add_action now returns the action id added. Documentation added in order to explain the return values and others. * cally/cally-text.c Added action "activate". This action is only available if the ClutterText is activatable, so the "activatable" property is tracked in the notify 2009-11-20 Alejandro Pieiro <apinheiro@igalia.com> Signal event emission Emits the signals "text_selection_changed", "text_caret_moved", "text_changed::insert", "text_changed::delete", and notify the ATK_STATE_EDITABLE state change. It also adds the ATK_STATE_EDITABLE in the ref_state_set, includes a finalize to clean the new private data used, and move part of the initialization from the _init to the _real_initialization. 2009-12-03 Alejandro Pieiro <apinheiro@igalia.com> Remove the ATK_STATE_DEFUNCT emission Remove the ATK_STATE_DEFUNCT emission, as this is already made by AtkGObjectAccessible. It also removes the clutter actor from the private structure, as we can use the AtkGObjectAccessible API to obtain it. This makes the code more coherent, with respect of the rest of the Cally classes implementation. 2009-11-26 Alejandro Pieiro <apinheiro@igalia.com> Remove ; from the CALLY_GET_CLUTTER_ACTOR macro 2009-11-25 Alejandro Pieiro <apinheiro@igalia.com> TODO cleanup and more implementation notes * TODO: removed the data that we have in the bugzilla or in the implementation notes on the cally source * cally/cally-actor.c: complete implementations notes * cally/Makefile.am: add a comment related to the public headers, and include Makefile.in in the MAINTAINERCLEANFILES 2009-11-13 Alejandro Pieiro <apinheiro@igalia.com> Adding new tips on CODING_STYLE 2009-11-09 Alejandro Pieiro <apinheiro@igalia.com> AtkEditableText implementation on CallyText * examples/Makefile.am * examples/cally-atkeditabletext-example.c: New example added * cally/cally-text.c Interface AtkEditableText implemented, except some methods: * Missing ClipBoard feature on Clutter: paste_text copy_text cut_text * Missing a equivalent GtkTextTag on Clutter (so the possibility to set run attributes in a range): set_run_attributes Fixes bug CB#1734 2009-11-03 Alejandro Pieiro <apinheiro@igalia.com> Removed DG_DISABLE_CHECKS and DG_DISABLE_CAST_CHECKS from CFLAGS * configure.ac: Removed DG_DISABLE_CHECKS and DG_DISABLE_CAST_CHECKS from the common CFLAGS options * cally/cally-actor.c: fixed cast errors on some return values, not detected previously because of the use of relaxed compilation options Problem detected by Mario Sánchez Prada <msanchez@igalia.com> 2009-10-28 Alejandro Pieiro <apinheiro@igalia.com> Support for multiple stages * cally-root.c * cally-stage.c * cally-util.c Implemented the support for multiple stages, by tracking the signals stage-added and stage-removed of the ClutterStageManager. In the same way CallyRoot has implement properly the atk_object_initialize, and in general now is more tied to ClutterStageManager (CallyRoot is now the a11y object of ClutterStageManager), but factory not required anyway, as it is instanced on the CallyUtil atk_get_root Fixes: CB#1754 (Missing multi-stage support) 2009-10-27 Alejandro Pieiro <apinheiro@igalia.com> Implemented atk_[add/remove]_key_event_listener on CallyUtil * cally/cally-util.c: Implemented atk_[add/remove]_key_event_listener * examples/cally-atktext-example2.c: Modified in order to install and remove key event listeners, for testing purposes Fixes CB#1852 (AtkUtil implementation misses atk_[add/remove]_key_event_listener) 2009-10-21 Alejandro Pieiro <apinheiro@igalia.com> Implemented atk-[add/remove]-global-event-listener on CallyUtil * cally/cally-util.c: Implemented atk-[add/remove]-global-event-listener on CallyUtil * examples/Makefile.am * examples/cally-atktext-example2.c New example in order to test easier the event emission on focus change (not working right now) 2009-10-12 Alejandro Pieiro <apinheiro@igalia.com> Add --with-dbus option executing the examples The replacement for atk-bridge on at-spi-dbus has a different name (atk-adaptor), and it has not defined the method gnome_accessibility_init. The --with-dbus option allow to load the correct library and use the correct hook method if you are using at-spi-dbus. Anyway, take into account that this is just an example, and in a final environment, this should be made in a more general way. More information: CB#1738, CB#1737 2009-09-25 Alejandro Pieiro <apinheiro@igalia.com> Symplifying shave support. 2009-09-25 Alejandro Pieiro <apinheiro@igalia.com> Cleanup on the compilation and installation process * cally/Makefile.am: Added libcallydir and libcally_HEADERS in order to publish all cally headers, as the current policy is use the cally headers as public. * configure.ac: Change API_VERSION_MAJOR for CALLY_API_VERSION, as was the real meaning, and define CALLY_VERSION. Change CALLY_OBJ_CFLAGS and CALLY_OBJ_LIBS, used to compile the tests, as was not required to compile against the cally module (the example only required to compile against Clutter, as the cally module was just a module loaded by GModule). Support for Shave. 2009-07-31 Alejandro Pieiro <apinheiro@igalia.com> Be able to run the examples without installing Cally Before that, the examples searched the cally module from the final installed directory. This means that you should install the library to use the examples. On development this is not desirable. Now it is loaded from ../cally/.libs This is a little hackish, but more useful, and in the end, it is just a example. Probably a best option could be configure that on the command line. $ ./example --cally-dir="mydir" But just a nitpick. 2009-07-29 Alejandro Pieiro <apinheiro@igalia.com> Upgrade to cally-1.0, using clutter-1.0 * NEWS * TODO: removed several items, waiting to be moved to the bugzilla * configure.ac * examples/cally-examples-util.c 2009-07-27 Alejandro Pieiro <apinheiro@igalia.com> Fixed return value of cally_actor_get_index_in_parent Bug and solutiond pointed by Gerd Kohlberger 2009-06-30 Alejandro Pieiro <apinheiro@igalia.com> Added the implementation of most AtkText methods for CluttetText (CallyText) It remains some methods: get_default_attributes get_character_extents get_offset_at_point The current gail implementation delegate on gailmisc, but this is tied to GtkWidget so an equivalent functionality would be implemented (something like callymisc), and in the case of get_character_extents, not sure about the layout position (see gtk_entry_get_layout_offsets). I think that worth manage this in a different commit. In the same way is still missing AtkEditableText support. 2009-07-07 Alejandro Pieiro <apinheiro@igalia.com> Added CALLY_GET_CLUTTER_ACTOR macro This macro was created to simplify how do you get the clutter actor object related to the cally object. On CallyActor a private attributte maintains it (for convenience, as it is heavily used) but outside, atkgobject methods can be used. Note that there is a possibility on the future to change it. Two options: * Add a public method to get the clutter object * Use this method on CallyActor too This macro simplifies this: CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (cally_object))) 2009-06-24 Alejandro Pieiro <apinheiro@igalia.com> Renamed examples/cally-util.[ch] to examples/cally-examples-util.[ch] Renamed examples/cally-util.[ch] to examples/cally-examples-util.[ch] to avoid confusion with cally/cally-util.[ch], implementation of the AtkUtil interface 2009-06-23 Alejandro Pieiro <apinheiro@igalia.com> Adding examples directory * NEWS: Updates * configure.ac * Makefile.am * cally/Makefile.am * examples/Makefile.am: New * examples/cally-util.[ch]: New * examples/example1.c: New Added a directory in order to put examples. In this way we don't require any external clutter app to make the basic a11y functionality checks. At this moment only an example was added, but all the compiling structure is working. By default the examples are not compiled, use "--enable-examples" on configure time in order to enable their compilation. This basic example basically shows several objects, with different depth, in order to check that AtkComponent returns the correct screen position. Other minor changes done on the building infrastructure. 2009-06-23 Alejandro Pieiro <apinheiro@igalia.com> Fix clutter version required 2009-06-23 Alejandro Pieiro <apinheiro@igalia.com> Solve a problem calling clutter_actor_get_anchor_point * cally/cally-actor.c: (_get_actor_extents): use gfloat instead of gint, as now this clutter_actor_get_anchor_point use floats 2009-06-11 Alejandro Pieiro <apinheiro@igalia.com> Minor fixes * Update TODO * Fix .pc files, to use clutter-0.9 version 2009-05-20 Alejandro Pieiro <apinheiro@igalia.com> Library renamed from cail to cally 2009-05-08 Alejandro Pieiro <apinheiro@igalia.com> Removed cail-clone-texture.h from cail.h * cail/cail.h: Removed reference to cail-clone-texture.h 2009-05-08 Alejandro Pieiro <apinheiro@igalia.com> Upgrade to cail-0.9, using clutter-0.9, first compilable version * NEWS: new file with the information of the releases * TODO: updated * configure.ac: updated clutter version to compile against * cail/cail-clone-texture.[ch]: Removed as ClutterCloneTexture was removed on Clutter 0.9.0 * cail/cail-label.[ch]: Removed as ClutterLabel was removed on Clutter 0.9.0 * cail/Makefile.am: updated due the source files removed * cail/cail-actor.c: removed include to <clutter/clutter-actor.h> * cail/cail.c: removed the factories for CailLabel and CailCloneTexture 2009-05-07 Alejandro Pieiro <apinheiro@igalia.com> Reflect change on the version number policy * README: correct some typos and explain that the cail version number is tied to the clutter version number and how * configure.ac Set the version number to 0.8.0 2009-05-07 Alejandro Pieiro <apinheiro@igalia.com> Edit the ChangeLog file, to show that now we are using git * ChangeLog.SVN: new file, with the ChangeLog used while cail was using a Subversion repository * ChangeLog: now is empty, and only maintains a reference to use git log 2009-04-29 Alejandro Pieiro <apinheiro@igalia.com> Coding style review * CODING_STYLE * cail/Makefile.am * cail/cail-actor-private.[ch] * cail/cail-actor.h * cail/cail-clone-texture.[ch] * cail/cail-group.[ch] * cail/cail-label.[ch] * cail/cail-rectangle.[ch] * cail/cail-root.[ch] * cail/cail-stage.[ch] * cail/cail-texture.[ch] * cail/cail-util.[ch] * cail/cail.c 2009-04-28 Alejandro Pieiro <apinheiro@igalia.com> Coding style review: cail-actor.c 2009-04-21 Alejandro Pieiro <apinheiro@igalia.com> 2009-04-21 Alejandro Pinheiro <apinheiro@igalia.com> * TODO: updated TODO file 2009-04-21 Alejandro Pieiro <apinheiro@igalia.com> 2009-03-06 Alejandro Pinheiro <apinheiro@igalia.com> * AUTHORS: update authors file to public release 2009-03-06 Alejandro Pieiro <apinheiro@igalia.com> 2009-03-06 Alejandro Pinheiro <apinheiro@igalia.com> * debian/control Added cdbs dependency, renamed debugging package * debian/libcail-common-dbg.dirs: new file * debian/libcail-common.dirs * debian/libcail-common.install Minor changes 2009-03-05 Alejandro Pieiro <apinheiro@igalia.com> 2009-03-05 Alejandro Pinheiro <apinheiro@igalia.com> * TODO Added TODO file, in order to list the remaining tasks. 2009-03-05 Alejandro Pieiro <apinheiro@igalia.com> 2009-03-05 Alejandro Pinheiro <apinheiro@igalia.com> * configure.ac * cail/cail.c * cail/cail-util.c * Makefile.am Removed all the missing gtk related stuff 2009-03-05 Alejandro Pieiro <apinheiro@igalia.com> 2009-03-05 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-actor.c (_get_actor_extents): managing too the anchor point to compute the position (_get_top_level_origin): reimplemented using x11 functions, removed gtk/gdk related functions, and taking into account the relative position inside the parent (previous position calculation was wrong if a child was not a direct stage child) * cail/clutter-gtk/cail-clutter-embed.[ch] * cail/clutter-gtk/cail-gtk-factory.h Removed, in order to remove any gtk dependency * cail/debian/control: removed gtk dependency 2009-03-03 Alejandro Pieiro <apinheiro@igalia.com> 2009-03-03 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-actor-private.[ch]: new files to private utility functions (_cail_actor_pushable): new function, that checks if a cail actor is pushable by checking if the clutter actor related has a handler for a release event * cail/cail-texture.c * cail/cail-clone-texture.c * cail/cail-rectangle.c Use of new function _cail_actor_pushable * cail-actor.c: Added some documentation related to current implementation * cail-util.c: Code style review 2009-03-02 Alejandro Pieiro <apinheiro@igalia.com> 2009-03-02 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-label.[ch]: new * cail/cail.[ch] (cail_accessibility_module_init) * cail/Makefile.am Added CailLabel, a11y object for ClutterLabel 2009-02-27 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-27 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-actor.c (cail_actor_real_remove_actor) Fixed a typo that causes a crash while removing the actor from a container 2009-02-26 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-26 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-actor.c (cail_actor_remove_actor) (cail_actor_add_actor) Fixed a typo calling klass->add_actor and klass->remove_actor that causes a crash in some (container,actor) combinations (cail_actor_real_add_actor) Additional parameter check 2009-02-25 Alejandro Pieiro <apinheiro@igalia.com> Missing cail-rectangle.[ch] files, according 2009-02-23 entry at Changelog 2009-02-23 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-23 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-rectangle.[ch] * cail/cail.[ch] * cail/Makefile.am Added CailRectangle, a11y object for ClutterRectangle * cail/cail-group.c * cail/cail-texture.c * cail/cail-stage.c Avoid to add a empty private structure, to avoid the glib warning. Anyway the pointer to the private structure is still on the .h, to allow future add-on. 2009-02-20 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-20 Alejandro Pinheiro <apinheiro@igalia.com> * cail-actor.[ch] * cail-group.[ch] Moved most of the ClutterContainer a11y support from cail-group to cail-actor, in order to generalize this support. * cail-stage.[ch] * cail-util.[ch] Normalize the private structure to avoid future problems with missing gaps 2009-02-20 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-20 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-actor.c (cail_actor_connect_actor_destroyed): connects to the clutter actor destroy signal (cail_actor_clutter_actor_destroyed): handler to the clutter actor destroy signal, update the priv->actor pointer and notify a state change This change allows to be sure about the priv->actor correct value, so we can use directly priv->actor instead of atk_gobject_accessible_get_object in the next functions: (cail_actor_get_parent) (cail_actor_get_index_in_parent) (cail_actor_ref_state_set) (cail_actor_get_extents) 2009-02-19 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-19 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-texture.[ch] * cail/cail-clone-texture.[ch] * cail/cail.[ch] * cail/Makefile.am Added CailTexture and CailCloneTexture a11y objects for ClutterTexture and ClutterCloneTexture * cail/cail-util.c Added private structure 2009-02-18 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-18 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-actor.c: (cail_actor_get_parent) Return the accessible object of the clutter actor if accessible_parent is not available. Previously it only took into account the these object as a possible parent to return (you can set it with atk_object_set_parent) 2009-02-18 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-18 Alejandro Pinheiro <apinheiro@igalia.com> * cail/cail-group.[ch]: code style review * cail/cail-actor.[ch]: implemented basic support for ClutterContainer 2009-02-18 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-18 Alejandro Pinheiro <apinheiro@igalia.com> * debian/control: updating dependencies 2009-02-18 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-18 Alejandro Pinheiro <apinheiro@igalia.com> * configure.ac: added aditional compile flags * cail/cail-actor.[ch]: Reimplemented support for AtkAction interface * cail/cail-root.[ch]: code style review 2009-02-16 Alejandro Pieiro <apinheiro@igalia.com> 2009-02-16 Alejandro Pinheiro <apinheiro@igalia.com> * First release. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-util.h�����������������������������������������������������0000664�0001750�0001750�00000004646�14211404421�021646� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_UTIL_H__ #define __CALLY_UTIL_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <clutter/clutter.h> #include <atk/atk.h> G_BEGIN_DECLS #define CALLY_TYPE_UTIL (cally_util_get_type ()) #define CALLY_UTIL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_UTIL, CallyUtil)) #define CALLY_UTIL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_UTIL, CallyUtilClass)) #define CALLY_IS_UTIL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_UTIL)) #define CALLY_IS_UTIL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_UTIL)) #define CALLY_UTIL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_UTIL, CallyUtilClass)) typedef struct _CallyUtil CallyUtil; typedef struct _CallyUtilClass CallyUtilClass; typedef struct _CallyUtilPrivate CallyUtilPrivate; /** * CallyUtil: * * The <structname>CallyUtil</structname> structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyUtil { /*< private >*/ AtkUtil parent; CallyUtilPrivate *priv; }; /** * CallyUtilClass: * * The <structname>CallyUtilClass</structname> structure contains only * private data * * Since: 1.4 */ struct _CallyUtilClass { /*< private >*/ AtkUtilClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_util_get_type (void) G_GNUC_CONST; void _cally_util_override_atk_util (void); G_END_DECLS #endif /* __CALLY_UTIL_H__ */ ������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-main.h�����������������������������������������������������0000664�0001750�0001750�00000002611�14211404421�021603� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Some parts are based on GailWidget from GAIL * GAIL - The GNOME Accessibility Implementation Library * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_MAIN_H__ #define __CALLY_MAIN_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <glib.h> #include <atk/atk.h> G_BEGIN_DECLS CLUTTER_AVAILABLE_IN_1_4 gboolean cally_get_cally_initialized (void); CLUTTER_AVAILABLE_IN_1_4 gboolean cally_accessibility_init (void); G_END_DECLS #endif /* __CALLY_MAIN_H__ */ �����������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally.c����������������������������������������������������������0000664�0001750�0001750�00000006223�14211404421�020657� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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:cally * @Title: Cally * @short_description: Cally initialization methods. * * Cally initialization methods. * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "cally.h" #include "cally-actor.h" #include "cally-group.h" #include "cally-stage.h" #include "cally-text.h" #include "cally-texture.h" #include "cally-rectangle.h" #include "cally-clone.h" #include "cally-factory.h" #include "cally-util.h" #include "clutter.h" #include "clutter-debug.h" #include "clutter-private.h" /* factories initialization*/ CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_ACTOR, cally_actor, cally_actor_new) CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_GROUP, cally_group, cally_group_new) CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_STAGE, cally_stage, cally_stage_new) CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_TEXT, cally_text, cally_text_new) CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_TEXTURE, cally_texture, cally_texture_new) CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_RECTANGLE, cally_rectangle, cally_rectangle_new) CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_CLONE, cally_clone, cally_clone_new) /** * cally_accessibility_init: * * Initializes the accessibility support. * * Return value: %TRUE if accessibility support has been correctly * initialized. * * Since: 1.4 */ gboolean cally_accessibility_init (void) { /* setting the factories */ CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_ACTOR, cally_actor); CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_GROUP, cally_group); CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_STAGE, cally_stage); CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_TEXT, cally_text); CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_TEXTURE, cally_texture); CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_RECTANGLE, cally_rectangle); CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_CLONE, cally_clone); /* Initialize the CallyUtility class */ _cally_util_override_atk_util (); CLUTTER_NOTE (MISC, "Clutter Accessibility initialized"); return TRUE; } /** * cally_get_cally_initialized: * * Returns if the accessibility support using cally is enabled. * * Return value: %TRUE if accessibility support has been correctly * initialized. * * Since: 1.4 */ gboolean cally_get_cally_initialized (void) { return !g_strcmp0 (atk_get_toolkit_name (), "clutter"); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally.h����������������������������������������������������������0000664�0001750�0001750�00000002326�14211404421�020664� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_H__ #define __CALLY_H__ #define __CALLY_H_INSIDE__ #include "cally-actor.h" #include "cally-clone.h" #include "cally-factory.h" #include "cally-group.h" #include "cally-main.h" #include "cally-rectangle.h" #include "cally-root.h" #include "cally-stage.h" #include "cally-text.h" #include "cally-texture.h" #include "cally-util.h" #undef __CALLY_H_INSIDE__ #endif /* __CALLY_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-stage.c����������������������������������������������������0000664�0001750�0001750�00000017033�14211404421�021761� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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:cally-stage * @Title: CallyStage * @short_description: Implementation of the ATK interfaces for a #ClutterStage * @see_also: #ClutterStage * * #CallyStage implements the required ATK interfaces for #ClutterStage * * Some implementation details: at this moment #CallyStage is used as * the most similar Window object in this toolkit (ie: emitting window * related signals), although the real purpose of #ClutterStage is * being a canvas. Anyway, this is required for applications using * just clutter, or directly #ClutterStage */ #include "clutter-build-config.h" #include "cally-stage.h" #include "cally-actor-private.h" /* AtkObject.h */ static void cally_stage_real_initialize (AtkObject *obj, gpointer data); static AtkStateSet* cally_stage_ref_state_set (AtkObject *obj); /* AtkWindow */ static void cally_stage_window_interface_init (AtkWindowIface *iface); /* Auxiliar */ static void cally_stage_activate_cb (ClutterStage *stage, gpointer data); static void cally_stage_deactivate_cb (ClutterStage *stage, gpointer data); struct _CallyStagePrivate { /* NULL means that the stage will receive the focus */ ClutterActor *key_focus; gboolean active; }; G_DEFINE_TYPE_WITH_CODE (CallyStage, cally_stage, CALLY_TYPE_GROUP, G_ADD_PRIVATE (CallyStage) G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW, cally_stage_window_interface_init)); static void cally_stage_class_init (CallyStageClass *klass) { AtkObjectClass *class = ATK_OBJECT_CLASS (klass); /* AtkObject */ class->initialize = cally_stage_real_initialize; class->ref_state_set = cally_stage_ref_state_set; } static void cally_stage_init (CallyStage *cally_stage) { CallyStagePrivate *priv = cally_stage_get_instance_private (cally_stage); cally_stage->priv = priv; priv->active = FALSE; } /** * cally_stage_new: * @actor: a #ClutterActor * * Creates a new #CallyStage for the given @actor. @actor should be a * #ClutterStage. * * Return value: the newly created #AtkObject * * Since: 1.4 */ AtkObject* cally_stage_new (ClutterActor *actor) { GObject *object = NULL; AtkObject *accessible = NULL; g_return_val_if_fail (CLUTTER_IS_STAGE (actor), NULL); object = g_object_new (CALLY_TYPE_STAGE, NULL); accessible = ATK_OBJECT (object); atk_object_initialize (accessible, actor); return accessible; } static void cally_stage_notify_key_focus_cb (ClutterStage *stage, GParamSpec *pspec, CallyStage *self) { ClutterActor *key_focus = NULL; AtkObject *new = NULL; if (self->priv->active == FALSE) return; key_focus = clutter_stage_get_key_focus (stage); if (key_focus != self->priv->key_focus) { AtkObject *old = NULL; if (self->priv->key_focus != NULL) { g_object_remove_weak_pointer (G_OBJECT (self->priv->key_focus), (gpointer *) &self->priv->key_focus); old = clutter_actor_get_accessible (self->priv->key_focus); } else old = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); atk_object_notify_state_change (old, ATK_STATE_FOCUSED, FALSE); } /* we keep notifying the focus gain without checking previous * key-focus to avoid some missing events due timing */ self->priv->key_focus = key_focus; if (key_focus != NULL) { /* ensure that if the key focus goes away, the field inside * CallyStage is reset. see bug: * * https://bugzilla.gnome.org/show_bug.cgi?id=692706 * * we remove the weak pointer above. */ g_object_add_weak_pointer (G_OBJECT (self->priv->key_focus), (gpointer *) &self->priv->key_focus); new = clutter_actor_get_accessible (key_focus); } else new = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); atk_object_notify_state_change (new, ATK_STATE_FOCUSED, TRUE); } static void cally_stage_real_initialize (AtkObject *obj, gpointer data) { ClutterStage *stage = NULL; g_return_if_fail (CALLY_IS_STAGE (obj)); ATK_OBJECT_CLASS (cally_stage_parent_class)->initialize (obj, data); stage = CLUTTER_STAGE (CALLY_GET_CLUTTER_ACTOR (obj)); g_signal_connect (stage, "activate", G_CALLBACK (cally_stage_activate_cb), obj); g_signal_connect (stage, "deactivate", G_CALLBACK (cally_stage_deactivate_cb), obj); g_signal_connect (stage, "notify::key-focus", G_CALLBACK (cally_stage_notify_key_focus_cb), obj); atk_object_set_role (obj, ATK_ROLE_WINDOW); } static AtkStateSet* cally_stage_ref_state_set (AtkObject *obj) { CallyStage *cally_stage = NULL; AtkStateSet *state_set = NULL; ClutterStage *stage = NULL; g_return_val_if_fail (CALLY_IS_STAGE (obj), NULL); cally_stage = CALLY_STAGE (obj); state_set = ATK_OBJECT_CLASS (cally_stage_parent_class)->ref_state_set (obj); stage = CLUTTER_STAGE (CALLY_GET_CLUTTER_ACTOR (cally_stage)); if (stage == NULL) return state_set; if (cally_stage->priv->active) atk_state_set_add_state (state_set, ATK_STATE_ACTIVE); return state_set; } /* AtkWindow */ static void cally_stage_window_interface_init (AtkWindowIface *iface) { /* At this moment AtkWindow is just about signals */ } /* Auxiliar */ static void cally_stage_activate_cb (ClutterStage *stage, gpointer data) { CallyStage *cally_stage = NULL; g_return_if_fail (CALLY_IS_STAGE (data)); cally_stage = CALLY_STAGE (data); cally_stage->priv->active = TRUE; atk_object_notify_state_change (ATK_OBJECT (cally_stage), ATK_STATE_ACTIVE, TRUE); g_signal_emit_by_name (cally_stage, "activate", 0); } static void cally_stage_deactivate_cb (ClutterStage *stage, gpointer data) { CallyStage *cally_stage = NULL; g_return_if_fail (CALLY_IS_STAGE (data)); cally_stage = CALLY_STAGE (data); cally_stage->priv->active = FALSE; atk_object_notify_state_change (ATK_OBJECT (cally_stage), ATK_STATE_ACTIVE, FALSE); g_signal_emit_by_name (cally_stage, "deactivate", 0); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-stage.h����������������������������������������������������0000664�0001750�0001750�00000005000�14211404421�021755� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_STAGE_H__ #define __CALLY_STAGE_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <cally/cally-group.h> #include <clutter/clutter.h> G_BEGIN_DECLS #define CALLY_TYPE_STAGE (cally_stage_get_type ()) #define CALLY_STAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_STAGE, CallyStage)) #define CALLY_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_STAGE, CallyStageClass)) #define CALLY_IS_STAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_STAGE)) #define CALLY_IS_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_STAGE)) #define CALLY_STAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_STAGE, CallyStageClass)) typedef struct _CallyStage CallyStage; typedef struct _CallyStageClass CallyStageClass; typedef struct _CallyStagePrivate CallyStagePrivate; /** * CallyStage: * * The <structname>CallyStage</structname> structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyStage { /*< private >*/ CallyGroup parent; CallyStagePrivate *priv; }; /** * CallyStageClass: * * The <structname>CallyStageClass</structname> structure contains only * private data * * Since: 1.4 */ struct _CallyStageClass { /*< private >*/ CallyGroupClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[16]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_stage_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject *cally_stage_new (ClutterActor *actor); G_END_DECLS #endif /* __CALLY_STAGE_H__ */ muffin-5.2.1/clutter/clutter/cally/cally-texture.c��������������������������������������������������0000664�0001750�0001750�00000005305�14211404421�022355� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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:cally-texture * @Title: CallyTexture * @short_description: Implementation of the ATK interfaces for a #ClutterTexture * @see_also: #ClutterTexture * * #CallyTexture implements the required ATK interfaces of #ClutterTexture * * In particular it sets a proper role for the texture. */ #include "clutter-build-config.h" #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "cally-texture.h" #include "cally-actor-private.h" #include "deprecated/clutter-texture.h" /* AtkObject */ static void cally_texture_real_initialize (AtkObject *obj, gpointer data); G_DEFINE_TYPE (CallyTexture, cally_texture, CALLY_TYPE_ACTOR) static void cally_texture_class_init (CallyTextureClass *klass) { /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */ AtkObjectClass *class = ATK_OBJECT_CLASS (klass); class->initialize = cally_texture_real_initialize; } static void cally_texture_init (CallyTexture *texture) { /* nothing to do yet */ } /** * cally_texture_new: * @actor: a #ClutterActor * * Creates a new #CallyTexture for the given @actor. @actor must be * a #ClutterTexture. * * Return value: the newly created #AtkObject * * Since: 1.4 */ AtkObject* cally_texture_new (ClutterActor *actor) { GObject *object = NULL; AtkObject *accessible = NULL; g_return_val_if_fail (CLUTTER_IS_TEXTURE (actor), NULL); object = g_object_new (CALLY_TYPE_TEXTURE, NULL); accessible = ATK_OBJECT (object); atk_object_initialize (accessible, actor); return accessible; } static void cally_texture_real_initialize (AtkObject *obj, gpointer data) { ATK_OBJECT_CLASS (cally_texture_parent_class)->initialize (obj, data); /* default role */ obj->role = ATK_ROLE_IMAGE; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-actor.c����������������������������������������������������0000664�0001750�0001750�00000107621�14211404421�021771� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Some parts are based on GailWidget from GAIL * GAIL - The GNOME Accessibility Implementation Library * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:cally-actor * @Title: CallyActor * @short_description: Implementation of the ATK interfaces for #ClutterActor * @see_also: #ClutterActor * * #CallyActor implements the required ATK interfaces of #ClutterActor * exposing the common elements on each actor (position, extents, etc). */ /* * * IMPLEMENTATION NOTES: * * #### * * Focus: clutter hasn't got the focus concept in the same way that GTK, but it * has a key focus managed by the stage. Basically any actor can be focused using * clutter_stage_set_key_focus. So, we will use this approach: all actors are * focusable, and we get the currently focused using clutter_stage_get_key_focus * This affects focus related stateset and some atk_componenet focus methods (like * grab focus). * * In the same way, we will manage the focus state change management * on the cally-stage object. The reason is avoid missing a focus * state change event if the object is focused just before the * accessibility object being created. * * #AtkAction implementation: on previous releases ClutterActor added * the actions "press", "release" and "click", as at that time some * general-purpose actors like textures were directly used as buttons. * * But now, new toolkits appeared, providing high-level widgets, like * buttons. So in this environment, it doesn't make sense to keep * adding them as default. * * Anyway, current implementation of AtkAction is done at CallyActor * providing methods to add and remove actions. This is based on the * one used at gailcell, and proposed as a change on #AtkAction * interface: * * https://bugzilla.gnome.org/show_bug.cgi?id=649804 * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <glib.h> #include <clutter/clutter.h> #ifdef CLUTTER_WINDOWING_X11 #include <clutter/x11/clutter-x11.h> #endif #include <math.h> #include "cally-actor.h" #include "cally-actor-private.h" typedef struct _CallyActorActionInfo CallyActorActionInfo; /*< private > * CallyActorActionInfo: * @name: name of the action * @description: description of the action * @keybinding: keybinding related to the action * @do_action_func: callback * @user_data: data to be passed to @do_action_func * @notify: function to be called when removing the action * * Utility structure to maintain the different actions added to the * #CallyActor */ struct _CallyActorActionInfo { gchar *name; gchar *description; gchar *keybinding; CallyActionCallback do_action_func; gpointer user_data; GDestroyNotify notify; }; static void cally_actor_initialize (AtkObject *obj, gpointer data); static void cally_actor_finalize (GObject *obj); /* AtkObject.h */ static AtkObject* cally_actor_get_parent (AtkObject *obj); static gint cally_actor_get_index_in_parent (AtkObject *obj); static AtkStateSet* cally_actor_ref_state_set (AtkObject *obj); static gint cally_actor_get_n_children (AtkObject *obj); static AtkObject* cally_actor_ref_child (AtkObject *obj, gint i); static AtkAttributeSet * cally_actor_get_attributes (AtkObject *obj); /* ClutterContainer */ static gint cally_actor_add_actor (ClutterActor *container, ClutterActor *actor, gpointer data); static gint cally_actor_remove_actor (ClutterActor *container, ClutterActor *actor, gpointer data); static gint cally_actor_real_add_actor (ClutterActor *container, ClutterActor *actor, gpointer data); static gint cally_actor_real_remove_actor (ClutterActor *container, ClutterActor *actor, gpointer data); /* AtkComponent.h */ static void cally_actor_component_interface_init (AtkComponentIface *iface); static void cally_actor_get_extents (AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type); static gint cally_actor_get_mdi_zorder (AtkComponent *component); static gboolean cally_actor_grab_focus (AtkComponent *component); /* AtkAction.h */ static void cally_actor_action_interface_init (AtkActionIface *iface); static gboolean cally_actor_action_do_action (AtkAction *action, gint i); static gboolean idle_do_action (gpointer data); static gint cally_actor_action_get_n_actions (AtkAction *action); static const gchar* cally_actor_action_get_description (AtkAction *action, gint i); static const gchar* cally_actor_action_get_keybinding (AtkAction *action, gint i); static const gchar* cally_actor_action_get_name (AtkAction *action, gint i); static gboolean cally_actor_action_set_description (AtkAction *action, gint i, const gchar *desc); static void _cally_actor_destroy_action_info (gpointer action_info, gpointer user_data); static void _cally_actor_clean_action_list (CallyActor *cally_actor); static CallyActorActionInfo* _cally_actor_get_action_info (CallyActor *cally_actor, gint index); /* Misc functions */ static void cally_actor_notify_clutter (GObject *obj, GParamSpec *pspec); static void cally_actor_real_notify_clutter (GObject *obj, GParamSpec *pspec); struct _CallyActorPrivate { GQueue *action_queue; guint action_idle_handler; GList *action_list; GList *children; }; G_DEFINE_TYPE_WITH_CODE (CallyActor, cally_actor, ATK_TYPE_GOBJECT_ACCESSIBLE, G_ADD_PRIVATE (CallyActor) G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, cally_actor_component_interface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, cally_actor_action_interface_init)); /** * cally_actor_new: * @actor: a #ClutterActor * * Creates a new #CallyActor for the given @actor * * Return value: the newly created #AtkObject * * Since: 1.4 */ AtkObject * cally_actor_new (ClutterActor *actor) { gpointer object; AtkObject *atk_object; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); object = g_object_new (CALLY_TYPE_ACTOR, NULL); atk_object = ATK_OBJECT (object); atk_object_initialize (atk_object, actor); return atk_object; } static void cally_actor_initialize (AtkObject *obj, gpointer data) { CallyActor *self = NULL; CallyActorPrivate *priv = NULL; ClutterActor *actor = NULL; guint handler_id; ATK_OBJECT_CLASS (cally_actor_parent_class)->initialize (obj, data); self = CALLY_ACTOR(obj); priv = self->priv; actor = CLUTTER_ACTOR (data); g_signal_connect (actor, "notify", G_CALLBACK (cally_actor_notify_clutter), NULL); g_object_set_data (G_OBJECT (obj), "atk-component-layer", GINT_TO_POINTER (ATK_LAYER_MDI)); priv->children = clutter_actor_get_children (actor); /* * We store the handler ids for these signals in case some objects * need to remove these handlers. */ handler_id = g_signal_connect (actor, "actor-added", G_CALLBACK (cally_actor_add_actor), obj); g_object_set_data (G_OBJECT (obj), "cally-add-handler-id", GUINT_TO_POINTER (handler_id)); handler_id = g_signal_connect (actor, "actor-removed", G_CALLBACK (cally_actor_remove_actor), obj); g_object_set_data (G_OBJECT (obj), "cally-remove-handler-id", GUINT_TO_POINTER (handler_id)); obj->role = ATK_ROLE_PANEL; /* typically objects implementing ClutterContainer interface would be a panel */ } static void cally_actor_class_init (CallyActorClass *klass) { AtkObjectClass *class = ATK_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); klass->notify_clutter = cally_actor_real_notify_clutter; klass->add_actor = cally_actor_real_add_actor; klass->remove_actor = cally_actor_real_remove_actor; /* GObject */ gobject_class->finalize = cally_actor_finalize; /* AtkObject */ class->get_parent = cally_actor_get_parent; class->get_index_in_parent = cally_actor_get_index_in_parent; class->ref_state_set = cally_actor_ref_state_set; class->initialize = cally_actor_initialize; class->get_n_children = cally_actor_get_n_children; class->ref_child = cally_actor_ref_child; class->get_attributes = cally_actor_get_attributes; } static void cally_actor_init (CallyActor *cally_actor) { CallyActorPrivate *priv = cally_actor_get_instance_private (cally_actor); cally_actor->priv = priv; priv->action_queue = NULL; priv->action_idle_handler = 0; priv->action_list = NULL; priv->children = NULL; } static void cally_actor_finalize (GObject *obj) { CallyActor *cally_actor = NULL; CallyActorPrivate *priv = NULL; cally_actor = CALLY_ACTOR (obj); priv = cally_actor->priv; _cally_actor_clean_action_list (cally_actor); if (priv->action_idle_handler) { g_source_remove (priv->action_idle_handler); priv->action_idle_handler = 0; } if (priv->action_queue) { g_queue_free (priv->action_queue); } if (priv->children) { g_list_free (priv->children); priv->children = NULL; } G_OBJECT_CLASS (cally_actor_parent_class)->finalize (obj); } /* AtkObject */ static AtkObject * cally_actor_get_parent (AtkObject *obj) { ClutterActor *parent_actor = NULL; AtkObject *parent = NULL; ClutterActor *actor = NULL; CallyActor *cally_actor = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL); /* Check if we have and assigned parent */ if (obj->accessible_parent) return obj->accessible_parent; /* Try to get it from the clutter parent */ cally_actor = CALLY_ACTOR (obj); actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); if (actor == NULL) /* Object is defunct */ return NULL; parent_actor = clutter_actor_get_parent (actor); if (parent_actor == NULL) return NULL; parent = clutter_actor_get_accessible (parent_actor); /* FIXME: I need to review the clutter-embed, to check if in this case I * should get the widget accessible */ return parent; } static gint cally_actor_get_index_in_parent (AtkObject *obj) { CallyActor *cally_actor = NULL; ClutterActor *actor = NULL; ClutterActor *parent_actor = NULL; ClutterActor *iter; gint index = -1; g_return_val_if_fail (CALLY_IS_ACTOR (obj), -1); if (obj->accessible_parent) { gint n_children, i; gboolean found = FALSE; n_children = atk_object_get_n_accessible_children (obj->accessible_parent); for (i = 0; i < n_children; i++) { AtkObject *child; child = atk_object_ref_accessible_child (obj->accessible_parent, i); if (child == obj) found = TRUE; g_object_unref (child); if (found) return i; } return -1; } cally_actor = CALLY_ACTOR (obj); actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); if (actor == NULL) /* Object is defunct */ return -1; index = 0; parent_actor = clutter_actor_get_parent (actor); if (parent_actor == NULL) return -1; for (iter = clutter_actor_get_first_child (parent_actor); iter != NULL && iter != actor; iter = clutter_actor_get_next_sibling (iter)) { index += 1; } return index; } static AtkStateSet* cally_actor_ref_state_set (AtkObject *obj) { ClutterActor *actor = NULL; AtkStateSet *state_set = NULL; ClutterStage *stage = NULL; ClutterActor *focus_actor = NULL; CallyActor *cally_actor = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL); cally_actor = CALLY_ACTOR (obj); state_set = ATK_OBJECT_CLASS (cally_actor_parent_class)->ref_state_set (obj); actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); if (actor == NULL) /* Object is defunct */ { atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT); } else { if (clutter_actor_get_reactive (actor)) { atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); atk_state_set_add_state (state_set, ATK_STATE_ENABLED); } if (clutter_actor_is_visible (actor)) { atk_state_set_add_state (state_set, ATK_STATE_VISIBLE); /* It would be good to also check if the actor is on screen, like the old and removed clutter_actor_is_on_stage*/ if (clutter_actor_get_paint_visibility (actor)) atk_state_set_add_state (state_set, ATK_STATE_SHOWING); } /* See focus section on implementation notes */ atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE); stage = CLUTTER_STAGE (clutter_actor_get_stage (actor)); if (stage != NULL) { focus_actor = clutter_stage_get_key_focus (stage); if (focus_actor == actor) atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); } } return state_set; } static gint cally_actor_get_n_children (AtkObject *obj) { ClutterActor *actor = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (obj), 0); actor = CALLY_GET_CLUTTER_ACTOR (obj); if (actor == NULL) /* State is defunct */ return 0; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0); return clutter_actor_get_n_children (actor); } static AtkObject* cally_actor_ref_child (AtkObject *obj, gint i) { ClutterActor *actor = NULL; ClutterActor *child = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (obj), NULL); actor = CALLY_GET_CLUTTER_ACTOR (obj); if (actor == NULL) /* State is defunct */ return NULL; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); if (i >= clutter_actor_get_n_children (actor)) return NULL; child = clutter_actor_get_child_at_index (actor, i); if (child == NULL) return NULL; return g_object_ref (clutter_actor_get_accessible (child)); } static AtkAttributeSet * cally_actor_get_attributes (AtkObject *obj) { AtkAttributeSet *attributes; AtkAttribute *toolkit; toolkit = g_new (AtkAttribute, 1); toolkit->name = g_strdup ("toolkit"); toolkit->value = g_strdup ("clutter"); attributes = g_slist_append (NULL, toolkit); return attributes; } /* ClutterContainer */ static gint cally_actor_add_actor (ClutterActor *container, ClutterActor *actor, gpointer data) { CallyActor *cally_actor = CALLY_ACTOR (data); CallyActorClass *klass = NULL; klass = CALLY_ACTOR_GET_CLASS (cally_actor); if (klass->add_actor) return klass->add_actor (container, actor, data); else return 1; } static gint cally_actor_remove_actor (ClutterActor *container, ClutterActor *actor, gpointer data) { CallyActor *cally_actor = CALLY_ACTOR (data); CallyActorClass *klass = NULL; klass = CALLY_ACTOR_GET_CLASS (cally_actor); if (klass->remove_actor) return klass->remove_actor (container, actor, data); else return 1; } static gint cally_actor_real_add_actor (ClutterActor *container, ClutterActor *actor, gpointer data) { AtkObject *atk_parent = ATK_OBJECT (data); AtkObject *atk_child = clutter_actor_get_accessible (actor); CallyActor *cally_actor = CALLY_ACTOR (atk_parent); CallyActorPrivate *priv = cally_actor->priv; gint index; g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), 0); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0); g_object_notify (G_OBJECT (atk_child), "accessible_parent"); g_list_free (priv->children); priv->children = clutter_actor_get_children (CLUTTER_ACTOR (container)); index = g_list_index (priv->children, actor); g_signal_emit_by_name (atk_parent, "children_changed::add", index, atk_child, NULL); return 1; } static gint cally_actor_real_remove_actor (ClutterActor *container, ClutterActor *actor, gpointer data) { AtkPropertyValues values = { NULL }; AtkObject* atk_parent = NULL; AtkObject *atk_child = NULL; CallyActorPrivate *priv = NULL; gint index; g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), 0); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0); atk_parent = ATK_OBJECT (data); atk_child = clutter_actor_get_accessible (actor); if (atk_child) { g_value_init (&values.old_value, G_TYPE_POINTER); g_value_set_pointer (&values.old_value, atk_parent); values.property_name = "accessible-parent"; g_object_ref (atk_child); g_signal_emit_by_name (atk_child, "property_change::accessible-parent", &values, NULL); g_object_unref (atk_child); } priv = CALLY_ACTOR (atk_parent)->priv; index = g_list_index (priv->children, actor); g_list_free (priv->children); priv->children = clutter_actor_get_children (CLUTTER_ACTOR (container)); if (index >= 0 && index <= g_list_length (priv->children)) g_signal_emit_by_name (atk_parent, "children_changed::remove", index, atk_child, NULL); return 1; } /* AtkComponent implementation */ static void cally_actor_component_interface_init (AtkComponentIface *iface) { g_return_if_fail (iface != NULL); iface->get_extents = cally_actor_get_extents; iface->get_mdi_zorder = cally_actor_get_mdi_zorder; /* focus management */ iface->grab_focus = cally_actor_grab_focus; } static void cally_actor_get_extents (AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type) { CallyActor *cally_actor = NULL; ClutterActor *actor = NULL; gint top_level_x, top_level_y; gfloat f_width, f_height; ClutterVertex verts[4]; ClutterActor *stage = NULL; g_return_if_fail (CALLY_IS_ACTOR (component)); cally_actor = CALLY_ACTOR (component); actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); if (actor == NULL) /* actor is defunct */ return; /* If the actor is not placed in any stage, we can't compute the * extents */ stage = clutter_actor_get_stage (actor); if (stage == NULL) return; clutter_actor_get_abs_allocation_vertices (actor, verts); clutter_actor_get_transformed_size (actor, &f_width, &f_height); *x = verts[0].x; *y = verts[0].y; *width = ceilf (f_width); *height = ceilf (f_height); /* In the ATK_XY_WINDOW case, we consider the stage as the * "top-level-window" * * http://library.gnome.org/devel/atk/stable/AtkUtil.html#AtkCoordType */ if (coord_type == ATK_XY_SCREEN) { _cally_actor_get_top_level_origin (actor, &top_level_x, &top_level_y); *x += top_level_x; *y += top_level_y; } return; } static gint cally_actor_get_mdi_zorder (AtkComponent *component) { CallyActor *cally_actor = NULL; ClutterActor *actor = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (component), G_MININT); cally_actor = CALLY_ACTOR(component); actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); return clutter_actor_get_z_position (actor); } static gboolean cally_actor_grab_focus (AtkComponent *component) { ClutterActor *actor = NULL; ClutterActor *stage = NULL; CallyActor *cally_actor = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (component), FALSE); /* See focus section on implementation notes */ cally_actor = CALLY_ACTOR(component); actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); stage = clutter_actor_get_stage (actor); clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor); return TRUE; } /* * * This gets the top level origin, it is, the position of the stage in * the global screen. You can see it as the absolute display position * of the stage. * * FIXME: only the case with x11 is implemented, other backends are * required * */ void _cally_actor_get_top_level_origin (ClutterActor *actor, gint *xp, gint *yp) { /* default values */ gint x = 0; gint y = 0; #ifdef CLUTTER_WINDOWING_X11 if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11)) { ClutterActor *stage = NULL; Display *display = NULL; Window root_window; Window stage_window; Window child; gint return_val = 0; stage = clutter_actor_get_stage (actor); /* FIXME: what happens if you use another display with clutter_backend_x11_set_display ?*/ display = clutter_x11_get_default_display (); root_window = clutter_x11_get_root_window (); stage_window = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); return_val = XTranslateCoordinates (display, stage_window, root_window, 0, 0, &x, &y, &child); if (!return_val) g_warning ("[x11] We were not able to get proper absolute " "position of the stage"); } else #endif { static gboolean yet_warned = FALSE; if (!yet_warned) { yet_warned = TRUE; g_warning ("The current Clutter backend does not support using " "atk_component_get_extents() with ATK_XY_SCREEN."); } } if (xp) *xp = x; if (yp) *yp = y; } /* AtkAction implementation */ static void cally_actor_action_interface_init (AtkActionIface *iface) { g_return_if_fail (iface != NULL); iface->do_action = cally_actor_action_do_action; iface->get_n_actions = cally_actor_action_get_n_actions; iface->get_description = cally_actor_action_get_description; iface->get_keybinding = cally_actor_action_get_keybinding; iface->get_name = cally_actor_action_get_name; iface->set_description = cally_actor_action_set_description; } static gboolean cally_actor_action_do_action (AtkAction *action, gint index) { CallyActor *cally_actor = NULL; AtkStateSet *set = NULL; CallyActorPrivate *priv = NULL; CallyActorActionInfo *info = NULL; cally_actor = CALLY_ACTOR (action); priv = cally_actor->priv; set = atk_object_ref_state_set (ATK_OBJECT (cally_actor)); if (atk_state_set_contains_state (set, ATK_STATE_DEFUNCT)) return FALSE; if (!atk_state_set_contains_state (set, ATK_STATE_SENSITIVE) || !atk_state_set_contains_state (set, ATK_STATE_SHOWING)) return FALSE; g_object_unref (set); info = _cally_actor_get_action_info (cally_actor, index); if (info == NULL) return FALSE; if (info->do_action_func == NULL) return FALSE; if (!priv->action_queue) priv->action_queue = g_queue_new (); g_queue_push_head (priv->action_queue, info); if (!priv->action_idle_handler) priv->action_idle_handler = g_idle_add (idle_do_action, cally_actor); return TRUE; } static gboolean idle_do_action (gpointer data) { CallyActor *cally_actor = NULL; CallyActorPrivate *priv = NULL; ClutterActor *actor = NULL; cally_actor = CALLY_ACTOR (data); priv = cally_actor->priv; actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); priv->action_idle_handler = 0; if (actor == NULL) /* state is defunct*/ return FALSE; while (!g_queue_is_empty (priv->action_queue)) { CallyActorActionInfo *info = NULL; info = (CallyActorActionInfo *) g_queue_pop_head (priv->action_queue); info->do_action_func (cally_actor, info->user_data); } return FALSE; } static gint cally_actor_action_get_n_actions (AtkAction *action) { CallyActor *cally_actor = NULL; CallyActorPrivate *priv = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (action), 0); cally_actor = CALLY_ACTOR (action); priv = cally_actor->priv; return g_list_length (priv->action_list); } static const gchar* cally_actor_action_get_name (AtkAction *action, gint i) { CallyActor *cally_actor = NULL; CallyActorActionInfo *info = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (action), NULL); cally_actor = CALLY_ACTOR (action); info = _cally_actor_get_action_info (cally_actor, i); if (info == NULL) return NULL; return info->name; } static const gchar* cally_actor_action_get_description (AtkAction *action, gint i) { CallyActor *cally_actor = NULL; CallyActorActionInfo *info = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (action), NULL); cally_actor = CALLY_ACTOR (action); info = _cally_actor_get_action_info (cally_actor, i); if (info == NULL) return NULL; return info->description; } static gboolean cally_actor_action_set_description (AtkAction *action, gint i, const gchar *desc) { CallyActor *cally_actor = NULL; CallyActorActionInfo *info = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (action), FALSE); cally_actor = CALLY_ACTOR (action); info = _cally_actor_get_action_info (cally_actor, i); if (info == NULL) return FALSE; free (info->description); info->description = g_strdup (desc); return TRUE; } static const gchar* cally_actor_action_get_keybinding (AtkAction *action, gint i) { CallyActor *cally_actor = NULL; CallyActorActionInfo *info = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (action), NULL); cally_actor = CALLY_ACTOR (action); info = _cally_actor_get_action_info (cally_actor, i); if (info == NULL) return NULL; return info->keybinding; } /* Misc functions */ /* * This function is a signal handler for notify signal which gets emitted * when a property changes value on the ClutterActor associated with the object. * * It calls a function for the CallyActor type */ static void cally_actor_notify_clutter (GObject *obj, GParamSpec *pspec) { CallyActor *cally_actor = NULL; CallyActorClass *klass = NULL; cally_actor = CALLY_ACTOR (clutter_actor_get_accessible (CLUTTER_ACTOR (obj))); klass = CALLY_ACTOR_GET_CLASS (cally_actor); if (klass->notify_clutter) klass->notify_clutter (obj, pspec); } /* * This function is a signal handler for notify signal which gets emitted * when a property changes value on the ClutterActor associated with a CallyActor * * It constructs an AtkPropertyValues structure and emits a "property_changed" * signal which causes the user specified AtkPropertyChangeHandler * to be called. */ static void cally_actor_real_notify_clutter (GObject *obj, GParamSpec *pspec) { ClutterActor* actor = CLUTTER_ACTOR (obj); AtkObject* atk_obj = clutter_actor_get_accessible (CLUTTER_ACTOR(obj)); AtkState state; gboolean value; if (g_strcmp0 (pspec->name, "visible") == 0) { state = ATK_STATE_VISIBLE; value = clutter_actor_is_visible (actor); } else if (g_strcmp0 (pspec->name, "mapped") == 0) { /* Clones may temporarily map an actor in order to * paint it; we don't want this to generate an ATK * state change */ if (clutter_actor_is_in_clone_paint (actor)) return; state = ATK_STATE_SHOWING; value = clutter_actor_is_mapped (actor); } else if (g_strcmp0 (pspec->name, "reactive") == 0) { state = ATK_STATE_SENSITIVE; value = clutter_actor_get_reactive (actor); } else return; atk_object_notify_state_change (atk_obj, state, value); } static void _cally_actor_clean_action_list (CallyActor *cally_actor) { CallyActorPrivate *priv = NULL; priv = cally_actor->priv; if (priv->action_list) { g_list_foreach (priv->action_list, (GFunc) _cally_actor_destroy_action_info, NULL); g_list_free (priv->action_list); priv->action_list = NULL; } } static CallyActorActionInfo * _cally_actor_get_action_info (CallyActor *cally_actor, gint index) { CallyActorPrivate *priv = NULL; GList *node = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), NULL); priv = cally_actor->priv; if (priv->action_list == NULL) return NULL; node = g_list_nth (priv->action_list, index); if (node == NULL) return NULL; return (CallyActorActionInfo *)(node->data); } /** * cally_actor_add_action: (skip) * @cally_actor: a #CallyActor * @action_name: the action name * @action_description: the action description * @action_keybinding: the action keybinding * @action_func: the callback of the action, to be executed with do_action * * Adds a new action to be accessed with the #AtkAction interface. * * Return value: added action id, or -1 if failure * * Since: 1.4 */ guint cally_actor_add_action (CallyActor *cally_actor, const gchar *action_name, const gchar *action_description, const gchar *action_keybinding, CallyActionFunc action_func) { return cally_actor_add_action_full (cally_actor, action_name, action_description, action_keybinding, (CallyActionCallback) action_func, NULL, NULL); } /** * cally_actor_add_action_full: (rename-to cally_actor_add_action) * @cally_actor: a #CallyActor * @action_name: the action name * @action_description: the action description * @action_keybinding: the action keybinding * @callback: (scope notified): the callback of the action * @user_data: (closure): data to be passed to @callback * @notify: function to be called when removing the action * * Adds a new action to be accessed with the #AtkAction interface. * * Return value: added action id, or -1 if failure * * Since: 1.6 */ guint cally_actor_add_action_full (CallyActor *cally_actor, const gchar *action_name, const gchar *action_description, const gchar *action_keybinding, CallyActionCallback callback, gpointer user_data, GDestroyNotify notify) { CallyActorActionInfo *info = NULL; CallyActorPrivate *priv = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), -1); g_return_val_if_fail (callback != NULL, -1); priv = cally_actor->priv; info = g_slice_new (CallyActorActionInfo); info->name = g_strdup (action_name); info->description = g_strdup (action_description); info->keybinding = g_strdup (action_keybinding); info->do_action_func = callback; info->user_data = user_data; info->notify = notify; priv->action_list = g_list_append (priv->action_list, info); return g_list_length (priv->action_list); } /** * cally_actor_remove_action: * @cally_actor: a #CallyActor * @action_id: the action id * * Removes a action, using the @action_id returned by cally_actor_add_action() * * Return value: %TRUE if the operation was succesful, %FALSE otherwise * * Since: 1.4 */ gboolean cally_actor_remove_action (CallyActor *cally_actor, gint action_id) { GList *list_node = NULL; CallyActorPrivate *priv = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), FALSE); priv = cally_actor->priv; list_node = g_list_nth (priv->action_list, action_id - 1); if (!list_node) return FALSE; _cally_actor_destroy_action_info (list_node->data, NULL); priv->action_list = g_list_remove_link (priv->action_list, list_node); return TRUE; } /** * cally_actor_remove_action_by_name: * @cally_actor: a #CallyActor * @action_name: the name of the action to remove * * Removes an action, using the @action_name used when the action was added * with cally_actor_add_action() * * Return value: %TRUE if the operation was succesful, %FALSE otherwise * * Since: 1.4 */ gboolean cally_actor_remove_action_by_name (CallyActor *cally_actor, const gchar *action_name) { GList *node = NULL; gboolean action_found = FALSE; CallyActorPrivate *priv = NULL; g_return_val_if_fail (CALLY_IS_ACTOR (cally_actor), FALSE); priv = CALLY_ACTOR (cally_actor)->priv; for (node = priv->action_list; node && !action_found; node = node->next) { CallyActorActionInfo *ainfo = node->data; if (!g_ascii_strcasecmp (ainfo->name, action_name)) { action_found = TRUE; break; } } if (!action_found) return FALSE; _cally_actor_destroy_action_info (node->data, NULL); priv->action_list = g_list_remove_link (priv->action_list, node); return TRUE; } static void _cally_actor_destroy_action_info (gpointer action_info, gpointer user_data) { CallyActorActionInfo *info = action_info; g_assert (info != NULL); free (info->name); free (info->description); free (info->keybinding); if (info->notify) info->notify (info->user_data); g_slice_free (CallyActorActionInfo, info); } ���������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-texture.h��������������������������������������������������0000664�0001750�0001750�00000005101�14211404421�022354� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_TEXTURE_H__ #define __CALLY_TEXTURE_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <clutter/clutter.h> #include <cally/cally-actor.h> G_BEGIN_DECLS #define CALLY_TYPE_TEXTURE (cally_texture_get_type ()) #define CALLY_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_TEXTURE, CallyTexture)) #define CALLY_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_TEXTURE, CallyTextureClass)) #define CALLY_IS_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_TEXTURE)) #define CALLY_IS_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_TEXTURE)) #define CALLY_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_TEXTURE, CallyTextureClass)) typedef struct _CallyTexture CallyTexture; typedef struct _CallyTextureClass CallyTextureClass; typedef struct _CallyTexturePrivate CallyTexturePrivate; /** * CallyTexture: * * The <structname>CallyTexture</structname> structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyTexture { /*< private >*/ CallyActor parent; CallyTexturePrivate *priv; }; /** * CallyTextureClass: * * The <structname>CallyTextureClass</structname> structure contains * only private data * * Since: 1.4 */ struct _CallyTextureClass { /*< private >*/ CallyActorClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_texture_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject *cally_texture_new (ClutterActor *actor); G_END_DECLS #endif /* __CALLY_TEXTURE_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-group.h����������������������������������������������������0000664�0001750�0001750�00000005250�14211404421�022015� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Based on GailContainer from GAIL * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_GROUP_H__ #define __CALLY_GROUP_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <cally/cally-actor.h> #include <clutter/clutter.h> G_BEGIN_DECLS #define CALLY_TYPE_GROUP (cally_group_get_type ()) #define CALLY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_GROUP, CallyGroup)) #define CALLY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_GROUP, CallyGroupClass)) #define CALLY_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_GROUP)) #define CALLY_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_GROUP)) #define CALLY_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_GROUP, CallyGroupClass)) typedef struct _CallyGroup CallyGroup; typedef struct _CallyGroupClass CallyGroupClass; typedef struct _CallyGroupPrivate CallyGroupPrivate; /** * CallyGroup: * * The <structname>CallyGroup</structname> structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyGroup { /*< private >*/ CallyActor parent; CallyGroupPrivate *priv; }; /** * CallyGroupClass: * * The <structname>CallyGroupClass</structname> structure contains only * private data * * Since: 1.4 */ struct _CallyGroupClass { /*< private >*/ CallyActorClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_group_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject* cally_group_new (ClutterActor *actor); G_END_DECLS #endif /* __CALLY_GROUP_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-root.h�����������������������������������������������������0000664�0001750�0001750�00000004732�14211404421�021650� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_ROOT_H__ #define __CALLY_ROOT_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <atk/atk.h> #include <clutter/clutter.h> G_BEGIN_DECLS #define CALLY_TYPE_ROOT (cally_root_get_type ()) #define CALLY_ROOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_ROOT, CallyRoot)) #define CALLY_ROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_ROOT, CallyRootClass)) #define CALLY_IS_ROOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_ROOT)) #define CALLY_IS_ROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_ROOT)) #define CALLY_ROOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_ROOT, CallyRootClass)) typedef struct _CallyRoot CallyRoot; typedef struct _CallyRootClass CallyRootClass; typedef struct _CallyRootPrivate CallyRootPrivate; /** * CallyRoot: * * The <structname>CallyRoot</structname> structure contains only private * data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyRoot { /*< private >*/ AtkGObjectAccessible parent; CallyRootPrivate *priv; }; /** * CallyRootClass: * * The <structname>CallyRootClass</structname> structure contains only * private data * * Since: 1.4 */ struct _CallyRootClass { /*< private >*/ AtkGObjectAccessibleClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[16]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_root_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject *cally_root_new (void); G_END_DECLS #endif /* __CALLY_ROOT_H__ */ ��������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-actor.h����������������������������������������������������0000664�0001750�0001750�00000013250�14211404421�021770� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Some parts are based on GailWidget from GAIL * GAIL - The GNOME Accessibility Implementation Library * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_ACTOR_H__ #define __CALLY_ACTOR_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <atk/atk.h> #include <clutter/clutter.h> G_BEGIN_DECLS #define CALLY_TYPE_ACTOR (cally_actor_get_type ()) #define CALLY_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_ACTOR, CallyActor)) #define CALLY_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_ACTOR, CallyActorClass)) #define CALLY_IS_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_ACTOR)) #define CALLY_IS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_ACTOR)) #define CALLY_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_ACTOR, CallyActorClass)) typedef struct _CallyActor CallyActor; typedef struct _CallyActorClass CallyActorClass; typedef struct _CallyActorPrivate CallyActorPrivate; /** * CallyActionFunc: * @cally_actor: a #CallyActor * * Action function, to be used on #AtkAction implementations as a individual * action * * Since: 1.4 */ typedef void (* CallyActionFunc) (CallyActor *cally_actor); /** * CallyActionCallback: * @cally_actor: a #CallyActor * @user_data: user data passed to the function * * Action function, to be used on #AtkAction implementations as * an individual action. Unlike #CallyActionFunc, this function * uses the @user_data argument passed to cally_actor_add_action_full(). * * Since: 1.6 */ typedef void (* CallyActionCallback) (CallyActor *cally_actor, gpointer user_data); /** * CallyActor: * * The <structname>CallyActor</structname> structure contains only private * data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyActor { /*< private >*/ AtkGObjectAccessible parent; CallyActorPrivate *priv; }; /** * CallyActorClass: * @notify_clutter: Signal handler for notify signal on Clutter actor * @focus_clutter: Signal handler for key-focus-in and key-focus-out * signal on Clutter actor. This virtual functions is deprecated. * @add_actor: Signal handler for actor-added signal on * ClutterContainer interface * @remove_actor: Signal handler for actor-added signal on * ClutterContainer interface * * The <structname>CallyActorClass</structname> structure contains * only private data * * Since: 1.4 */ struct _CallyActorClass { /*< private >*/ AtkGObjectAccessibleClass parent_class; /*< public >*/ void (*notify_clutter) (GObject *object, GParamSpec *pspec); gboolean (*focus_clutter) (ClutterActor *actor, gpointer data); gint (*add_actor) (ClutterActor *container, ClutterActor *actor, gpointer data); gint (*remove_actor) (ClutterActor *container, ClutterActor *actor, gpointer data); /*< private >*/ /* padding for future expansion */ gpointer _padding_dummy[32]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_actor_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject* cally_actor_new (ClutterActor *actor); CLUTTER_AVAILABLE_IN_1_4 guint cally_actor_add_action (CallyActor *cally_actor, const gchar *action_name, const gchar *action_description, const gchar *action_keybinding, CallyActionFunc action_func); CLUTTER_AVAILABLE_IN_1_6 guint cally_actor_add_action_full (CallyActor *cally_actor, const gchar *action_name, const gchar *action_description, const gchar *action_keybinding, CallyActionCallback callback, gpointer user_data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_4 gboolean cally_actor_remove_action (CallyActor *cally_actor, gint action_id); CLUTTER_AVAILABLE_IN_1_4 gboolean cally_actor_remove_action_by_name (CallyActor *cally_actor, const gchar *action_name); G_END_DECLS #endif /* __CALLY_ACTOR_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-group.c����������������������������������������������������0000664�0001750�0001750�00000007531�14211404421�022014� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Based on GailContainer from GAIL * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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:cally-group * @Title: CallyGroup * @short_description: Implementation of the ATK interfaces for a #ClutterGroup * @see_also: #ClutterGroup * * #CallyGroup implements the required ATK interfaces of #ClutterGroup * In particular it exposes each of the Clutter actors contained in the * group. */ #include "clutter-build-config.h" #include "cally-group.h" #include "cally-actor-private.h" static gint cally_group_get_n_children (AtkObject *obj); static AtkObject* cally_group_ref_child (AtkObject *obj, gint i); static void cally_group_real_initialize (AtkObject *obj, gpointer data); G_DEFINE_TYPE (CallyGroup, cally_group, CALLY_TYPE_ACTOR) static void cally_group_class_init (CallyGroupClass *klass) { /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */ AtkObjectClass *class = ATK_OBJECT_CLASS (klass); class->get_n_children = cally_group_get_n_children; class->ref_child = cally_group_ref_child; class->initialize = cally_group_real_initialize; } static void cally_group_init (CallyGroup *group) { /* nothing to do yet */ } /** * cally_group_new: * @actor: a #ClutterGroup * * Creates a #CallyGroup for @actor * * Return value: the newly created #CallyGroup * * Since: 1.4 */ AtkObject * cally_group_new (ClutterActor *actor) { GObject *object = NULL; AtkObject *accessible = NULL; g_return_val_if_fail (CLUTTER_IS_GROUP (actor), NULL); object = g_object_new (CALLY_TYPE_GROUP, NULL); accessible = ATK_OBJECT (object); atk_object_initialize (accessible, actor); return accessible; } static gint cally_group_get_n_children (AtkObject *obj) { ClutterActor *actor = NULL; gint count = 0; g_return_val_if_fail (CALLY_IS_GROUP (obj), count); actor = CALLY_GET_CLUTTER_ACTOR (obj); if (actor == NULL) /* defunct */ return 0; g_return_val_if_fail (CLUTTER_IS_GROUP(actor), count); count = clutter_actor_get_n_children (actor); return count; } static AtkObject* cally_group_ref_child (AtkObject *obj, gint i) { AtkObject *accessible = NULL; ClutterActor *actor = NULL; ClutterActor *child = NULL; g_return_val_if_fail (CALLY_IS_GROUP (obj), NULL); g_return_val_if_fail ((i >= 0), NULL); actor = CALLY_GET_CLUTTER_ACTOR (obj); g_return_val_if_fail (CLUTTER_IS_GROUP(actor), NULL); child = clutter_actor_get_child_at_index (actor, i); if (!child) return NULL; accessible = clutter_actor_get_accessible (child); if (accessible != NULL) g_object_ref (accessible); return accessible; } static void cally_group_real_initialize (AtkObject *obj, gpointer data) { ATK_OBJECT_CLASS (cally_group_parent_class)->initialize (obj, data); obj->role = ATK_ROLE_PANEL; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-clone.c����������������������������������������������������0000664�0001750�0001750�00000010364�14211404421�021756� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2010 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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:cally-clone * @Title: CallyClone * @short_description: Implementation of the ATK interfaces for a #ClutterClone * @see_also: #ClutterClone * * #CallyClone implements the required ATK interfaces of #ClutterClone * * In particular it sets a proper role for the clone, as just a image, * as it is the sanest and simplest approach. */ /* Design rationale for CallyClone: * * In the old times, it was just ClutterCloneTexture. So, from a a11y POV * CallyCloneTexture was just another image, like ClutterTexture, and if * it was a clone was irrevelant. So on cally-0.8, CallyCloneTexture * expose a object with role ATK_ROLE_IMAGE. But now, ClutterClone is more * general. You can clone any object, including groups, and made things * like have one text entry, and a clone with different properties in the * same window, updated both at once. * * The question is if the idea is have a ClutterClone as a "first-class" * citizen inside the stage hierarchy (full clone), or it is just supposed * to be a mirror image of the original object. * * In the case of the a11y POV this would mean that if the text changes on * the source, the clone should emit as well the text-changing signals. * * As ClutterClone smartly just paint the same object with different * parameters, this would mean that it should be the cally object the one * that should replicate the source clutter hierarchy to do that, * something that just sound crazy. * * Taking into account that: * * - ClutterClone doesn't re-emit mirrored signals from the source * I think that likely the answer would be "yes, it is just a * mirrored image, not a real full clone". * * - You can't interact directly with the clone (ie: focus, and so on). * Its basic usage (right now) is clone textures. * * Any other solution could be overwhelming. * * I think that the final solution would be that ClutterClone from the * a11y POV should still be managed as a image (with the proper properties, * position, size, etc.). */ #include "clutter-build-config.h" #include "cally-clone.h" #include "cally-actor-private.h" /* AtkObject */ static void cally_clone_real_initialize (AtkObject *obj, gpointer data); G_DEFINE_TYPE (CallyClone, cally_clone, CALLY_TYPE_ACTOR) static void cally_clone_class_init (CallyCloneClass *klass) { /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */ AtkObjectClass *class = ATK_OBJECT_CLASS (klass); class->initialize = cally_clone_real_initialize; } static void cally_clone_init (CallyClone *clone) { /* nothing to do yet */ } /** * cally_clone_new: * @actor: a #ClutterActor * * Creates a new #CallyClone for the given @actor. @actor must be a * #ClutterClone. * * Return value: the newly created #AtkObject * * Since: 1.4 */ AtkObject* cally_clone_new (ClutterActor *actor) { GObject *object = NULL; AtkObject *accessible = NULL; g_return_val_if_fail (CLUTTER_IS_CLONE (actor), NULL); object = g_object_new (CALLY_TYPE_CLONE, NULL); accessible = ATK_OBJECT (object); atk_object_initialize (accessible, actor); return accessible; } static void cally_clone_real_initialize (AtkObject *obj, gpointer data) { ATK_OBJECT_CLASS (cally_clone_parent_class)->initialize (obj, data); obj->role = ATK_ROLE_IMAGE; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-text.h�����������������������������������������������������0000664�0001750�0001750�00000005021�14211404421�021641� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_TEXT_H__ #define __CALLY_TEXT_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <clutter/clutter.h> #include <cally/cally-actor.h> G_BEGIN_DECLS #define CALLY_TYPE_TEXT (cally_text_get_type ()) #define CALLY_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_TEXT, CallyText)) #define CALLY_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_TEXT, CallyTextClass)) #define CALLY_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_TEXT)) #define CALLY_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_TEXT)) #define CALLY_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_TEXT, CallyTextClass)) typedef struct _CallyText CallyText; typedef struct _CallyTextClass CallyTextClass; typedef struct _CallyTextPrivate CallyTextPrivate; /** * CallyText: * * The <structname>CallyText</structname> structure contains only private * data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyText { /*< private >*/ CallyActor parent; CallyTextPrivate *priv; }; /** * CallyTextClass: * * The <structname>CallyTextClass</structname> structure contains only * private data * * Since: 1.4 */ struct _CallyTextClass { /*< private >*/ CallyActorClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_text_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject* cally_text_new (ClutterActor *actor); G_END_DECLS #endif /* __CALLY_TEXT_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-rectangle.c������������������������������������������������0000664�0001750�0001750�00000005354�14211404421�022625� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2009 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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:cally-rectangle * @short_description: Implementation of the ATK interfaces for a #ClutterRectangle * @see_also: #ClutterRectangle * * #CallyRectangle implements the required ATK interfaces of #ClutterRectangle * * In particular it sets a proper role for the rectangle. */ #include "clutter-build-config.h" #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "cally-rectangle.h" #include "cally-actor-private.h" #include "clutter-color.h" #include "deprecated/clutter-rectangle.h" /* AtkObject */ static void cally_rectangle_real_initialize (AtkObject *obj, gpointer data); G_DEFINE_TYPE (CallyRectangle, cally_rectangle, CALLY_TYPE_ACTOR) static void cally_rectangle_class_init (CallyRectangleClass *klass) { /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */ AtkObjectClass *class = ATK_OBJECT_CLASS (klass); class->initialize = cally_rectangle_real_initialize; } static void cally_rectangle_init (CallyRectangle *rectangle) { /* nothing to do yet */ } /** * cally_rectangle_new: * @actor: a #ClutterActor * * Creates a new #CallyRectangle for the given @actor. @actor must be * a #ClutterRectangle. * * Return value: the newly created #AtkObject * * Since: 1.4 */ AtkObject* cally_rectangle_new (ClutterActor *actor) { GObject *object = NULL; AtkObject *accessible = NULL; g_return_val_if_fail (CLUTTER_IS_RECTANGLE (actor), NULL); object = g_object_new (CALLY_TYPE_RECTANGLE, NULL); accessible = ATK_OBJECT (object); atk_object_initialize (accessible, actor); return accessible; } static void cally_rectangle_real_initialize (AtkObject *obj, gpointer data) { ATK_OBJECT_CLASS (cally_rectangle_parent_class)->initialize (obj, data); obj->role = ATK_ROLE_IMAGE; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-root.c�����������������������������������������������������0000664�0001750�0001750�00000021305�14211404421�021636� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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:cally-root * @short_description: Root object for the Cally toolkit * @see_also: #ClutterStage * * #CallyRoot is the root object of the accessibility tree-like * hierarchy, exposing the application level. * * Somewhat equivalent to #GailTopLevel. We consider that this class * expose the a11y information of the #ClutterStageManager, as the * children of this object are the different ClutterStage managed (so * the #GObject used in the atk_object_initialize() is the * #ClutterStageManager). */ #include "clutter-build-config.h" #include "cally-root.h" #include "clutter-actor.h" #include "clutter-stage-private.h" #include "clutter-stage-manager.h" /* GObject */ static void cally_root_finalize (GObject *object); /* AtkObject.h */ static void cally_root_initialize (AtkObject *accessible, gpointer data); static gint cally_root_get_n_children (AtkObject *obj); static AtkObject * cally_root_ref_child (AtkObject *obj, gint i); static AtkObject * cally_root_get_parent (AtkObject *obj); static const char * cally_root_get_name (AtkObject *obj); /* Private */ static void cally_util_stage_added_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data); static void cally_util_stage_removed_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data); struct _CallyRootPrivate { /* We save the CallyStage objects. Other option could save the stage * list, and then just get the a11y object on the ref_child, etc. But * the ref_child is more common that the init and the stage-add, * stage-remove, so we avoid getting the accessible object * constantly */ GSList *stage_list; /* signals id */ guint stage_added_id; guint stage_removed_id; }; G_DEFINE_TYPE_WITH_PRIVATE (CallyRoot, cally_root, ATK_TYPE_GOBJECT_ACCESSIBLE) static void cally_root_class_init (CallyRootClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); AtkObjectClass *class = ATK_OBJECT_CLASS (klass); gobject_class->finalize = cally_root_finalize; /* AtkObject */ class->get_n_children = cally_root_get_n_children; class->ref_child = cally_root_ref_child; class->get_parent = cally_root_get_parent; class->initialize = cally_root_initialize; class->get_name = cally_root_get_name; } static void cally_root_init (CallyRoot *root) { root->priv = cally_root_get_instance_private (root); root->priv->stage_list = NULL; root->priv->stage_added_id = 0; root->priv->stage_removed_id = 0; } /** * cally_root_new: * * Creates a new #CallyRoot object. * * Return value: the newly created #AtkObject * * Since: 1.4 */ AtkObject* cally_root_new (void) { GObject *object = NULL; AtkObject *accessible = NULL; ClutterStageManager *stage_manager = NULL; object = g_object_new (CALLY_TYPE_ROOT, NULL); accessible = ATK_OBJECT (object); stage_manager = clutter_stage_manager_get_default (); atk_object_initialize (accessible, stage_manager); return accessible; } static void cally_root_finalize (GObject *object) { CallyRoot *root = CALLY_ROOT (object); GObject *stage_manager = NULL; g_return_if_fail (CALLY_IS_ROOT (object)); if (root->priv->stage_list) { g_slist_free (root->priv->stage_list); root->priv->stage_list = NULL; } stage_manager = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (root)); g_signal_handler_disconnect (stage_manager, root->priv->stage_added_id); g_signal_handler_disconnect (stage_manager, root->priv->stage_added_id); G_OBJECT_CLASS (cally_root_parent_class)->finalize (object); } /* AtkObject.h */ static void cally_root_initialize (AtkObject *accessible, gpointer data) { ClutterStageManager *stage_manager = NULL; const GSList *iter = NULL; const GSList *stage_list = NULL; ClutterStage *clutter_stage = NULL; AtkObject *cally_stage = NULL; CallyRoot *root = NULL; accessible->role = ATK_ROLE_APPLICATION; accessible->accessible_parent = NULL; /* children initialization */ root = CALLY_ROOT (accessible); stage_manager = CLUTTER_STAGE_MANAGER (data); stage_list = clutter_stage_manager_peek_stages (stage_manager); for (iter = stage_list; iter != NULL; iter = g_slist_next (iter)) { clutter_stage = CLUTTER_STAGE (iter->data); cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (clutter_stage)); atk_object_set_parent (cally_stage, ATK_OBJECT (root)); root->priv->stage_list = g_slist_append (root->priv->stage_list, cally_stage); } root->priv->stage_added_id = g_signal_connect (G_OBJECT (stage_manager), "stage-added", G_CALLBACK (cally_util_stage_added_cb), root); root->priv->stage_removed_id = g_signal_connect (G_OBJECT (stage_manager), "stage-removed", G_CALLBACK (cally_util_stage_removed_cb), root); ATK_OBJECT_CLASS (cally_root_parent_class)->initialize (accessible, data); } static gint cally_root_get_n_children (AtkObject *obj) { CallyRoot *root = CALLY_ROOT (obj); return g_slist_length (root->priv->stage_list); } static AtkObject* cally_root_ref_child (AtkObject *obj, gint i) { CallyRoot *cally_root = NULL; GSList *stage_list = NULL; gint num = 0; AtkObject *item = NULL; cally_root = CALLY_ROOT (obj); stage_list = cally_root->priv->stage_list; num = g_slist_length (stage_list); g_return_val_if_fail ((i < num)&&(i >= 0), NULL); item = g_slist_nth_data (stage_list, i); if (!item) { return NULL; } g_object_ref (item); return item; } static AtkObject* cally_root_get_parent (AtkObject *obj) { return NULL; } static const char * cally_root_get_name (AtkObject *obj) { return g_get_prgname (); } /* -------------------------------- PRIVATE --------------------------------- */ static void cally_util_stage_added_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data) { CallyRoot *root = CALLY_ROOT (data); AtkObject *cally_stage = NULL; gint index = -1; cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); atk_object_set_parent (cally_stage, ATK_OBJECT (root)); root->priv->stage_list = g_slist_append (root->priv->stage_list, cally_stage); index = g_slist_index (root->priv->stage_list, cally_stage); g_signal_emit_by_name (root, "children_changed::add", index, cally_stage, NULL); g_signal_emit_by_name (cally_stage, "create", 0); } static void cally_util_stage_removed_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data) { CallyRoot *root = CALLY_ROOT (data); AtkObject *cally_stage = NULL; gint index = -1; cally_stage = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); index = g_slist_index (root->priv->stage_list, cally_stage); root->priv->stage_list = g_slist_remove (root->priv->stage_list, cally_stage); index = g_slist_index (root->priv->stage_list, cally_stage); g_signal_emit_by_name (root, "children_changed::remove", index, cally_stage, NULL); g_signal_emit_by_name (cally_stage, "destroy", 0); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/cally/cally-clone.h����������������������������������������������������0000664�0001750�0001750�00000004777�14211404421�021776� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2010 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CALLY_CLONE_H__ #define __CALLY_CLONE_H__ #if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <cally/cally.h> can be included directly." #endif #include <clutter/clutter.h> #include <cally/cally-actor.h> G_BEGIN_DECLS #define CALLY_TYPE_CLONE (cally_clone_get_type ()) #define CALLY_CLONE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_CLONE, CallyClone)) #define CALLY_CLONE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_CLONE, CallyCloneClass)) #define CALLY_IS_CLONE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_CLONE)) #define CALLY_IS_CLONE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_CLONE)) #define CALLY_CLONE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_CLONE, CallyCloneClass)) typedef struct _CallyClone CallyClone; typedef struct _CallyCloneClass CallyCloneClass; typedef struct _CallyClonePrivate CallyClonePrivate; /** * CallyClone: * * The <structname>CallyClone</structname> structure contains only private * data and should be accessed using the provided API * * Since: 1.4 */ struct _CallyClone { /*< private >*/ CallyActor parent; CallyClonePrivate *priv; }; /** * CallyCloneClass: * * The <structname>CallyCloneClass</structname> structure contains only * private data * * Since: 1.4 */ struct _CallyCloneClass { /*< private >*/ CallyActorClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_AVAILABLE_IN_1_4 GType cally_clone_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 AtkObject *cally_clone_new (ClutterActor *actor); G_END_DECLS #endif /* __CALLY_CLONE_H__ */ �muffin-5.2.1/clutter/clutter/cally/cally-util.c�����������������������������������������������������0000664�0001750�0001750�00000035302�14211404421�021632� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* CALLY - The Clutter Accessibility Implementation Library * * Copyright (C) 2008 Igalia, S.L. * * Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> * * Based on GailUtil from GAIL * Copyright 2001, 2002, 2003 Sun Microsystems Inc. * * 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:cally-util * @Title: CallyUtil * @short_description: #AtkUtil implementation * @see_also: #ClutterActor * * #CallyUtil implements #AtkUtil abstract methods. Although it * includes the name "Util" it is in fact one of the most important * interfaces to be implemented in any ATK toolkit implementation. * For instance, it defines atk_get_root(), the method that returns * the root object in the hierarchy. Without it, you don't have * available any accessible object. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <stdlib.h> #include <string.h> #include <clutter/clutter.h> #include "cally-util.h" #include "cally-root.h" #include "cally-stage.h" #define DEFAULT_PASSWORD_CHAR '*' /* atkutil.h */ static guint cally_util_add_key_event_listener (AtkKeySnoopFunc listener, gpointer data); static void cally_util_remove_key_event_listener (guint remove_listener); static AtkObject* cally_util_get_root (void); static const gchar * cally_util_get_toolkit_name (void); static const gchar * cally_util_get_toolkit_version (void); /* private */ static void cally_util_simulate_snooper_install (void); static void cally_util_simulate_snooper_remove (void); static gboolean cally_key_snooper (ClutterActor *actor, ClutterEvent *event, gpointer user_data); static void cally_util_stage_added_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data); static void cally_util_stage_removed_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data); static gboolean notify_hf (gpointer key, gpointer value, gpointer data); static void insert_hf (gpointer key, gpointer value, gpointer data); /* This is just a copy of the Gail one, a shared library or place to define it could be a good idea. */ typedef struct _CallyKeyEventInfo CallyKeyEventInfo; struct _CallyKeyEventInfo { AtkKeySnoopFunc listener; gpointer func_data; }; static AtkObject* root = NULL; static GHashTable *key_listener_list = NULL; G_DEFINE_TYPE (CallyUtil, cally_util, ATK_TYPE_UTIL); static void cally_util_class_init (CallyUtilClass *klass) { AtkUtilClass *atk_class; gpointer data; data = g_type_class_peek (ATK_TYPE_UTIL); atk_class = ATK_UTIL_CLASS (data); atk_class->add_key_event_listener = cally_util_add_key_event_listener; atk_class->remove_key_event_listener = cally_util_remove_key_event_listener; atk_class->get_root = cally_util_get_root; atk_class->get_toolkit_name = cally_util_get_toolkit_name; atk_class->get_toolkit_version = cally_util_get_toolkit_version; /* FIXME: Instead of create this on the class, I think that would worth to implement CallyUtil as a singleton instance, so the class methods will access this instance. This will be a good future enhancement, meanwhile, just using the same *working* implementation used on GailUtil */ } static void cally_util_init (CallyUtil *cally_util) { /* instance init: usually not required */ } /* ------------------------------ ATK UTIL METHODS -------------------------- */ static AtkObject* cally_util_get_root (void) { if (!root) root = cally_root_new (); return root; } static const gchar * cally_util_get_toolkit_name (void) { return "clutter"; } static const gchar * cally_util_get_toolkit_version (void) { return CLUTTER_VERSION_S; } static guint cally_util_add_key_event_listener (AtkKeySnoopFunc listener, gpointer data) { static guint key = 1; CallyKeyEventInfo *event_info = NULL; if (!key_listener_list) { key_listener_list = g_hash_table_new_full (NULL, NULL, NULL, free); cally_util_simulate_snooper_install (); } event_info = g_new (CallyKeyEventInfo, 1); event_info->listener = listener; event_info->func_data = data; g_hash_table_insert (key_listener_list, GUINT_TO_POINTER (key++), event_info); /* XXX: we don't check to see if n_listeners > MAXUINT */ return key - 1; } static void cally_util_remove_key_event_listener (guint remove_listener) { if (!g_hash_table_remove (key_listener_list, GUINT_TO_POINTER (remove_listener))) { g_warning ("Not able to remove listener with id %i", remove_listener); } if (g_hash_table_size (key_listener_list) == 0) { g_hash_table_destroy (key_listener_list); key_listener_list = NULL; cally_util_simulate_snooper_remove (); } } /* ------------------------------ PRIVATE FUNCTIONS ------------------------- */ /* Trying to emulate gtk_key_snooper install (a kind of wrapper). This could be implemented without it, but I will maintain it in this way, so if in the future clutter implements it natively it would be easier the transition */ static void cally_util_simulate_snooper_install (void) { ClutterStageManager *stage_manager = NULL; ClutterStage *stage = NULL; GSList *stage_list = NULL; GSList *iter = NULL; stage_manager = clutter_stage_manager_get_default (); stage_list = clutter_stage_manager_list_stages (stage_manager); for (iter = stage_list; iter != NULL; iter = g_slist_next (iter)) { stage = CLUTTER_STAGE (iter->data); g_signal_connect (G_OBJECT (stage), "captured-event", G_CALLBACK (cally_key_snooper), NULL); } g_signal_connect (G_OBJECT (stage_manager), "stage-added", G_CALLBACK (cally_util_stage_added_cb), cally_key_snooper); g_signal_connect (G_OBJECT (stage_manager), "stage-removed", G_CALLBACK (cally_util_stage_removed_cb), cally_key_snooper); g_slist_free (stage_list); } static void cally_util_simulate_snooper_remove (void) { ClutterStageManager *stage_manager = NULL; ClutterStage *stage = NULL; GSList *stage_list = NULL; GSList *iter = NULL; gint num = 0; stage_manager = clutter_stage_manager_get_default (); stage_list = clutter_stage_manager_list_stages (stage_manager); for (iter = stage_list; iter != NULL; iter = g_slist_next (iter)) { stage = CLUTTER_STAGE (iter->data); num += g_signal_handlers_disconnect_by_func (stage, cally_key_snooper, NULL); } g_signal_handlers_disconnect_by_func (G_OBJECT (stage_manager), G_CALLBACK (cally_util_stage_added_cb), cally_key_snooper); g_signal_handlers_disconnect_by_func (G_OBJECT (stage_manager), G_CALLBACK (cally_util_stage_removed_cb), cally_key_snooper); #ifdef CALLY_DEBUG g_print ("Number of snooper callbacks disconnected: %i\n", num); #endif } static AtkKeyEventStruct * atk_key_event_from_clutter_event_key (ClutterKeyEvent *clutter_event, gunichar password_char) { AtkKeyEventStruct *atk_event = g_new0 (AtkKeyEventStruct, 1); gunichar key_unichar; switch (clutter_event->type) { case CLUTTER_KEY_PRESS: atk_event->type = ATK_KEY_EVENT_PRESS; break; case CLUTTER_KEY_RELEASE: atk_event->type = ATK_KEY_EVENT_RELEASE; break; default: g_assert_not_reached (); return NULL; } if (password_char) atk_event->state = 0; else atk_event->state = clutter_event->modifier_state; /* We emit the clutter keyval. This is not exactly the one expected by AtkKeyEventStruct, as it expects a Gdk-like event, with the modifiers applied. But to avoid a dependency to gdk, we delegate that on the AT application. More information: Bug 1952 and bug 2072 */ if (password_char) atk_event->keyval = clutter_unicode_to_keysym (password_char); else atk_event->keyval = clutter_event->keyval; /* It is expected to store a key defining string here (ie "Space" in case you press a space). Anyway, there are no function on clutter to obtain that, and we want to avoid a gdk dependency here, so we delegate on the AT application to obtain that string using the rest of the data on the ATK event struct. More information: Bug 1952 and 2072 */ if (password_char) key_unichar = password_char; else key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) clutter_event); if (g_unichar_validate (key_unichar) && !g_unichar_iscntrl (key_unichar)) { GString *new = NULL; new = g_string_new (""); new = g_string_insert_unichar (new, 0, key_unichar); atk_event->string = new->str; g_string_free (new, FALSE); } else atk_event->string = NULL; atk_event->length = 0; /* Computing the hardware keycode from the password-char is difficult. But we are in a password situation. We are already a unichar that it is not the original one. Providing a "almost real" keycode is irrelevant */ if (password_char) atk_event->keycode = 0; else atk_event->keycode = clutter_event->hardware_keycode; atk_event->timestamp = clutter_event->time; #ifdef CALLY_DEBUG g_debug ("CallyKeyEvent:\tsym 0x%x\n\t\tmods %x\n\t\tcode %u\n\t\ttime %lx \n\t\tstring %s\n", (unsigned int) atk_event->keyval, (unsigned int) atk_event->state, (unsigned int) atk_event->keycode, (unsigned long int) atk_event->timestamp, atk_event->string); #endif return atk_event; } static gboolean notify_hf (gpointer key, gpointer value, gpointer data) { CallyKeyEventInfo *info = (CallyKeyEventInfo *) value; AtkKeyEventStruct *key_event = (AtkKeyEventStruct *)data; return (*(AtkKeySnoopFunc) info->listener) (key_event, info->func_data) ? TRUE : FALSE; } static void insert_hf (gpointer key, gpointer value, gpointer data) { GHashTable *new_table = (GHashTable *) data; g_hash_table_insert (new_table, key, value); } /* * 0 if the key of that event is visible, in other case the password * char */ static gunichar check_key_visibility (ClutterEvent *event) { ClutterKeyEvent *key_event = (ClutterKeyEvent *)event; AtkObject *accessible = clutter_actor_get_accessible (key_event->source); g_return_val_if_fail (accessible != NULL, 0); if (atk_object_get_role (accessible) != ATK_ROLE_PASSWORD_TEXT) return 0; /* If it is a clutter text, we use his password char. Note that although at Clutter toolkit itself, only ClutterText exposes a password role, nothing prevents on any derived toolkit (like st) to create a new actor that can behave like a password entry. And the key event will still be emitted here. Although in that case we would lose any password char from the derived toolkit, it is still better fill this with a default unichar that the original one */ if (CLUTTER_IS_TEXT (key_event->source)) return clutter_text_get_password_char (CLUTTER_TEXT (key_event->source)); else return DEFAULT_PASSWORD_CHAR; } static gboolean cally_key_snooper (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { AtkKeyEventStruct *key_event = NULL; gint consumed = 0; gunichar password_char = 0; /* filter key events */ if ((event->type != CLUTTER_KEY_PRESS) && (event->type != CLUTTER_KEY_RELEASE)) { return FALSE; } password_char = check_key_visibility (event); if (key_listener_list) { GHashTable *new_hash = g_hash_table_new (NULL, NULL); g_hash_table_foreach (key_listener_list, insert_hf, new_hash); key_event = atk_key_event_from_clutter_event_key ((ClutterKeyEvent *)event, password_char); /* func data is inside the hash table */ consumed = g_hash_table_foreach_steal (new_hash, notify_hf, key_event); g_hash_table_destroy (new_hash); free (key_event->string); free (key_event); } return (consumed ? 1 : 0); } static void cally_util_stage_added_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data) { GCallback cally_key_snooper_cb = G_CALLBACK (data); g_signal_connect (G_OBJECT (stage), "captured-event", cally_key_snooper_cb, NULL); } static void cally_util_stage_removed_cb (ClutterStageManager *stage_manager, ClutterStage *stage, gpointer data) { GCallback cally_key_snooper_cb = G_CALLBACK (data); g_signal_handlers_disconnect_by_func (stage, cally_key_snooper_cb, NULL); } void _cally_util_override_atk_util (void) { AtkUtilClass *atk_class = ATK_UTIL_CLASS (g_type_class_ref (ATK_TYPE_UTIL)); atk_class->add_key_event_listener = cally_util_add_key_event_listener; atk_class->remove_key_event_listener = cally_util_remove_key_event_listener; atk_class->get_root = cally_util_get_root; atk_class->get_toolkit_name = cally_util_get_toolkit_name; atk_class->get_toolkit_version = cally_util_get_toolkit_version; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-event-translator.c���������������������������������������������0000664�0001750�0001750�00000002251�14211404421�023434� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "clutter-build-config.h" #include "clutter-event-translator.h" #include "clutter-backend.h" #include "clutter-private.h" #define clutter_event_translator_get_type _clutter_event_translator_get_type typedef ClutterEventTranslatorIface ClutterEventTranslatorInterface; G_DEFINE_INTERFACE (ClutterEventTranslator, clutter_event_translator, G_TYPE_OBJECT); static ClutterTranslateReturn default_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *event) { return CLUTTER_TRANSLATE_CONTINUE; } static void clutter_event_translator_default_init (ClutterEventTranslatorIface *iface) { iface->translate_event = default_translate_event; } ClutterTranslateReturn _clutter_event_translator_translate_event (ClutterEventTranslator *translator, gpointer native, ClutterEvent *translated) { ClutterEventTranslatorIface *iface; iface = CLUTTER_EVENT_TRANSLATOR_GET_IFACE (translator); return iface->translate_event (translator, native, translated); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-content.h������������������������������������������������������0000664�0001750�0001750�00000007164�14211404421�021613� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_CONTENT_H__ #define __CLUTTER_CONTENT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_CONTENT (clutter_content_get_type ()) #define CLUTTER_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONTENT, ClutterContent)) #define CLUTTER_IS_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONTENT)) #define CLUTTER_CONTENT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_CONTENT, ClutterContentIface)) typedef struct _ClutterContentIface ClutterContentIface; /** * ClutterContent: * * The #ClutterContent structure is an opaque type * whose members cannot be acccessed directly. * * Since: 1.10 */ /** * ClutterContentIface: * @get_preferred_size: virtual function; should be overridden by subclasses * of #ClutterContent that have a natural size * @paint_content: virtual function; called each time the content needs to * paint itself * @attached: virtual function; called each time a #ClutterContent is attached * to a #ClutterActor. * @detached: virtual function; called each time a #ClutterContent is detached * from a #ClutterActor. * @invalidate: virtual function; called each time a #ClutterContent state * is changed. * * The #ClutterContentIface structure contains only * private data. * * Since: 1.10 */ struct _ClutterContentIface { /*< private >*/ GTypeInterface g_iface; /*< public >*/ gboolean (* get_preferred_size) (ClutterContent *content, gfloat *width, gfloat *height); void (* paint_content) (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *node); void (* attached) (ClutterContent *content, ClutterActor *actor); void (* detached) (ClutterContent *content, ClutterActor *actor); void (* invalidate) (ClutterContent *content); }; CLUTTER_AVAILABLE_IN_1_10 GType clutter_content_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_content_get_preferred_size (ClutterContent *content, gfloat *width, gfloat *height); CLUTTER_AVAILABLE_IN_1_10 void clutter_content_invalidate (ClutterContent *content); G_END_DECLS #endif /* __CLUTTER_CONTENT_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-script.h�������������������������������������������������������0000664�0001750�0001750�00000022127�14211404421�021441� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_SCRIPT_H__ #define __CLUTTER_SCRIPT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_SCRIPT (clutter_script_get_type ()) #define CLUTTER_SCRIPT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SCRIPT, ClutterScript)) #define CLUTTER_IS_SCRIPT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SCRIPT)) #define CLUTTER_SCRIPT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SCRIPT, ClutterScriptClass)) #define CLUTTER_IS_SCRIPT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SCRIPT)) #define CLUTTER_SCRIPT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SCRIPT, ClutterScriptClass)) typedef struct _ClutterScript ClutterScript; typedef struct _ClutterScriptPrivate ClutterScriptPrivate; typedef struct _ClutterScriptClass ClutterScriptClass; /** * ClutterScriptConnectFunc: * @script: a #ClutterScript * @object: the object to connect * @signal_name: the name of the signal * @handler_name: the name of the signal handler * @connect_object: the object to connect the signal to, or %NULL * @flags: signal connection flags * @user_data: user data to pass to the signal handler * * This is the signature of a function used to connect signals. It is used * by the clutter_script_connect_signals_full() function. It is mainly * intended for interpreted language bindings, but could be useful where the * programmer wants more control over the signal connection process. * * Since: 0.6 */ typedef void (* ClutterScriptConnectFunc) (ClutterScript *script, GObject *object, const gchar *signal_name, const gchar *handler_name, GObject *connect_object, GConnectFlags flags, gpointer user_data); /** * ClutterScriptError: * @CLUTTER_SCRIPT_ERROR_INVALID_TYPE_FUNCTION: Type function not found * or invalid * @CLUTTER_SCRIPT_ERROR_INVALID_PROPERTY: Property not found or invalid * @CLUTTER_SCRIPT_ERROR_INVALID_VALUE: Invalid value * * #ClutterScript error enumeration. * * Since: 0.6 */ typedef enum { CLUTTER_SCRIPT_ERROR_INVALID_TYPE_FUNCTION, CLUTTER_SCRIPT_ERROR_INVALID_PROPERTY, CLUTTER_SCRIPT_ERROR_INVALID_VALUE } ClutterScriptError; /** * CLUTTER_SCRIPT_ERROR: * * Error domain for the #ClutterScript errors * * Since: 0.6 */ #define CLUTTER_SCRIPT_ERROR (clutter_script_error_quark ()) CLUTTER_AVAILABLE_IN_ALL GQuark clutter_script_error_quark (void); /** * ClutterScript: * * The #ClutterScript structure contains only private data * and should be accessed using the provided API * * Since: 0.6 */ struct _ClutterScript { /*< private >*/ GObject parent_instance; ClutterScriptPrivate *priv; }; /** * ClutterScriptClass: * @get_type_from_name: virtual function used to map a type name * to a #GType. This function should only be overridden by * language bindings in order to map native types to #GType. * The default implementation is equivalent to g_type_from_name() * * The #ClutterScriptClass structure contains only private data * * Since: 0.6 */ struct _ClutterScriptClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ GType (* get_type_from_name) (ClutterScript *script, const gchar *type_name); /*< private >*/ /* padding, for future expansion */ void (*_clutter_reserved1) (void); void (*_clutter_reserved2) (void); void (*_clutter_reserved3) (void); void (*_clutter_reserved4) (void); void (*_clutter_reserved5) (void); void (*_clutter_reserved6) (void); void (*_clutter_reserved7) (void); void (*_clutter_reserved8) (void); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_script_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterScript * clutter_script_new (void); CLUTTER_AVAILABLE_IN_ALL guint clutter_script_load_from_file (ClutterScript *script, const gchar *filename, GError **error); CLUTTER_AVAILABLE_IN_ALL guint clutter_script_load_from_data (ClutterScript *script, const gchar *data, gssize length, GError **error); CLUTTER_AVAILABLE_IN_1_10 guint clutter_script_load_from_resource (ClutterScript *script, const gchar *resource_path, GError **error); CLUTTER_AVAILABLE_IN_ALL GObject * clutter_script_get_object (ClutterScript *script, const gchar *name); CLUTTER_AVAILABLE_IN_ALL gint clutter_script_get_objects (ClutterScript *script, const gchar *first_name, ...) G_GNUC_NULL_TERMINATED; CLUTTER_AVAILABLE_IN_ALL GList * clutter_script_list_objects (ClutterScript *script); CLUTTER_AVAILABLE_IN_ALL void clutter_script_unmerge_objects (ClutterScript *script, guint merge_id); CLUTTER_AVAILABLE_IN_ALL void clutter_script_ensure_objects (ClutterScript *script); CLUTTER_DEPRECATED_IN_1_12 void clutter_script_add_states (ClutterScript *script, const gchar *name, ClutterState *state); CLUTTER_DEPRECATED_IN_1_12 ClutterState * clutter_script_get_states (ClutterScript *script, const gchar *name); CLUTTER_AVAILABLE_IN_ALL void clutter_script_connect_signals (ClutterScript *script, gpointer user_data); CLUTTER_AVAILABLE_IN_ALL void clutter_script_connect_signals_full (ClutterScript *script, ClutterScriptConnectFunc func, gpointer user_data); CLUTTER_AVAILABLE_IN_ALL void clutter_script_add_search_paths (ClutterScript *script, const gchar * const paths[], gsize n_paths); CLUTTER_AVAILABLE_IN_ALL gchar * clutter_script_lookup_filename (ClutterScript *script, const gchar *filename) G_GNUC_MALLOC; CLUTTER_AVAILABLE_IN_ALL GType clutter_script_get_type_from_name (ClutterScript *script, const gchar *type_name); CLUTTER_AVAILABLE_IN_1_10 void clutter_script_set_translation_domain (ClutterScript *script, const gchar *domain); CLUTTER_AVAILABLE_IN_1_10 const gchar * clutter_script_get_translation_domain (ClutterScript *script); CLUTTER_AVAILABLE_IN_ALL const gchar * clutter_get_script_id (GObject *gobject); G_END_DECLS #endif /* __CLUTTER_SCRIPT_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-image.h��������������������������������������������������������0000664�0001750�0001750�00000012133�14211404421�021213� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive image' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_IMAGE_H__ #define __CLUTTER_IMAGE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <cogl/cogl.h> #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_IMAGE (clutter_image_get_type ()) #define CLUTTER_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_IMAGE, ClutterImage)) #define CLUTTER_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_IMAGE)) #define CLUTTER_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_IMAGE, ClutterImageClass)) #define CLUTTER_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_IMAGE)) #define CLUTTER_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_IMAGE, ClutterImageClass)) /** * CLUTTER_IMAGE_ERROR: * * Error domain for the #ClutterImageError enumeration. * * Since: 1.10 */ #define CLUTTER_IMAGE_ERROR (clutter_image_error_quark ()) typedef struct _ClutterImage ClutterImage; typedef struct _ClutterImagePrivate ClutterImagePrivate; typedef struct _ClutterImageClass ClutterImageClass; /** * ClutterImageError: * @CLUTTER_IMAGE_ERROR_INVALID_DATA: Invalid data passed to the * clutter_image_set_data() function. * * Error enumeration for #ClutterImage. * * Since: 1.10 */ typedef enum { CLUTTER_IMAGE_ERROR_INVALID_DATA } ClutterImageError; /** * ClutterImage: * * The #ClutterImage structure contains * private data and should only be accessed using the provided * API. * * Since: 1.10 */ struct _ClutterImage { /*< private >*/ GObject parent_instance; ClutterImagePrivate *priv; }; /** * ClutterImageClass: * * The #ClutterImageClass structure contains * private data. * * Since: 1.10 */ struct _ClutterImageClass { /*< private >*/ GObjectClass parent_class; gpointer _padding[16]; }; CLUTTER_AVAILABLE_IN_1_10 GQuark clutter_image_error_quark (void); CLUTTER_AVAILABLE_IN_1_10 GType clutter_image_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterContent * clutter_image_new (void); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_image_set_data (ClutterImage *image, const guint8 *data, CoglPixelFormat pixel_format, guint width, guint height, guint row_stride, GError **error); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_image_set_area (ClutterImage *image, const guint8 *data, CoglPixelFormat pixel_format, const cairo_rectangle_int_t *rect, guint row_stride, GError **error); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_image_set_bytes (ClutterImage *image, GBytes *data, CoglPixelFormat pixel_format, guint width, guint height, guint row_stride, GError **error); CLUTTER_AVAILABLE_IN_1_10 CoglTexture * clutter_image_get_texture (ClutterImage *image); G_END_DECLS #endif /* __CLUTTER_IMAGE_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-flatten-effect.c�����������������������������������������������0000664�0001750�0001750�00000003170�14211404421�023014� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Authors: * Neil Roberts <neil@linux.intel.com> */ /* This is an internal-only effect used to implement the 'offscreen-redirect' property of ClutterActor. It doesn't actually need to do anything on top of the ClutterOffscreenEffect class so it only exists because that class is abstract */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-flatten-effect.h" #include "clutter-private.h" #include "clutter-actor-private.h" G_DEFINE_TYPE (ClutterFlattenEffect, _clutter_flatten_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT); static void _clutter_flatten_effect_class_init (ClutterFlattenEffectClass *klass) { } static void _clutter_flatten_effect_init (ClutterFlattenEffect *self) { } ClutterEffect * _clutter_flatten_effect_new (void) { return g_object_new (CLUTTER_TYPE_FLATTEN_EFFECT, NULL); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-shader-effect.c������������������������������������������������0000664�0001750�0001750�00000066704�14211404421�022641� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-shader-effect * @short_description: Base class for shader effects * @See_Also: #ClutterEffect, #ClutterOffscreenEffect * * #ClutterShaderEffect is a class that implements all the plumbing for * creating #ClutterEffect<!-- -->s using GLSL shaders. * * #ClutterShaderEffect creates an offscreen buffer and then applies the * GLSL shader (after checking whether the compilation and linking were * successfull) to the buffer before painting it on screen. * * #ClutterShaderEffect is available since Clutter 1.4 * * ## Implementing a ClutterShaderEffect * * Creating a sub-class of #ClutterShaderEffect requires the * overriding of the #ClutterOffscreenEffectClass.paint_target() virtual * function from the #ClutterOffscreenEffect class. It is also convenient * to implement the #ClutterShaderEffectClass.get_static_shader_source() * virtual function in case you are planning to create more than one * instance of the effect. * * The #ClutterShaderEffectClass.get_static_shader_source() * function should return a copy of the shader source to use. This * function is only called once per subclass of #ClutterShaderEffect * regardless of how many instances of the effect are created. The * source for the shader is typically stored in a static const * string which is returned from this function via * g_strdup(). * * The #ClutterOffscreenEffectClass.paint_target() should set the * shader's uniforms if any. This is done by calling * clutter_shader_effect_set_uniform_value() or * clutter_shader_effect_set_uniform(). The sub-class should then * chain up to the #ClutterShaderEffect implementation. * * ## Setting uniforms on a ClutterShaderEffect * * The example below shows a typical implementation of the * #ClutterShaderEffectClass.get_static_shader_source() and * #ClutterOffscreenEffectClass.paint_target() virtual functions * for a #ClutterShaderEffect subclass. * * |[<!-- language="C" --> * static gchar * * my_effect_get_static_shader_source (ClutterShaderEffect *effect) * { * // shader_source is set elsewhere * return g_strdup (shader_source); * } * * static gboolean * my_effect_paint_target (ClutterOffscreenEffect *effect) * { * MyEffect *self = MY_EFFECT (effect); * ClutterShaderEffect *shader = CLUTTER_SHADER_EFFECT (effect); * ClutterEffectClass *parent_class; * gfloat component_r, component_g, component_b; * * // the "tex" uniform is declared in the shader as: * // * // uniform int tex; * // * // and it is passed a constant value of 0 * clutter_shader_effect_set_uniform (shader, "tex", G_TYPE_INT, 1, 0); * * // the "component" uniform is declared in the shader as: * // * // uniform vec3 component; * // * // and it's defined to contain the normalized components * // of a #ClutterColor * component_r = self->color.red / 255.0f; * component_g = self->color.green / 255.0f; * component_b = self->color.blue / 255.0f; * clutter_shader_effect_set_uniform (shader, "component", * G_TYPE_FLOAT, 3, * component_r, * component_g, * component_b); * * // chain up to the parent's implementation * parent_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (my_effect_parent_class); * return parent_class->paint_target (effect); * } * ]| */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "cogl/cogl.h" #include "clutter-shader-effect.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-feature.h" #include "clutter-private.h" #include "clutter-shader-types.h" typedef struct _ShaderUniform { gchar *name; GType type; GValue value; int location; } ShaderUniform; struct _ClutterShaderEffectPrivate { ClutterActor *actor; ClutterShaderType shader_type; CoglHandle program; CoglHandle shader; GHashTable *uniforms; }; typedef struct _ClutterShaderEffectClassPrivate { /* These are the per-class pre-compiled shader and program which is used when the class implements get_static_shader_source without calling set_shader_source. They will be shared by all instances of this class */ CoglHandle program; CoglHandle shader; } ClutterShaderEffectClassPrivate; enum { PROP_0, PROP_SHADER_TYPE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE_WITH_CODE (ClutterShaderEffect, clutter_shader_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT, G_ADD_PRIVATE (ClutterShaderEffect) g_type_add_class_private (g_define_type_id, sizeof (ClutterShaderEffectClassPrivate))) static inline void clutter_shader_effect_clear (ClutterShaderEffect *self, gboolean reset_uniforms) { ClutterShaderEffectPrivate *priv = self->priv; if (priv->shader != COGL_INVALID_HANDLE) { cogl_handle_unref (priv->shader); priv->shader = COGL_INVALID_HANDLE; } if (priv->program != COGL_INVALID_HANDLE) { cogl_handle_unref (priv->program); priv->program = COGL_INVALID_HANDLE; } if (reset_uniforms && priv->uniforms != NULL) { g_hash_table_destroy (priv->uniforms); priv->uniforms = NULL; } priv->actor = NULL; } static void clutter_shader_effect_update_uniforms (ClutterShaderEffect *effect) { ClutterShaderEffectPrivate *priv = effect->priv; GHashTableIter iter; gpointer key, value; gsize size; if (priv->program == COGL_INVALID_HANDLE) return; if (priv->uniforms == NULL) return; key = value = NULL; g_hash_table_iter_init (&iter, priv->uniforms); while (g_hash_table_iter_next (&iter, &key, &value)) { ShaderUniform *uniform = value; if (uniform->location == -1) uniform->location = cogl_program_get_uniform_location (priv->program, uniform->name); if (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (&uniform->value)) { const float *floats; floats = clutter_value_get_shader_float (&uniform->value, &size); cogl_program_set_uniform_float (priv->program, uniform->location, size, 1, floats); } else if (CLUTTER_VALUE_HOLDS_SHADER_INT (&uniform->value)) { const int *ints; ints = clutter_value_get_shader_int (&uniform->value, &size); cogl_program_set_uniform_int (priv->program, uniform->location, size, 1, ints); } else if (CLUTTER_VALUE_HOLDS_SHADER_MATRIX (&uniform->value)) { const float *matrix; matrix = clutter_value_get_shader_matrix (&uniform->value, &size); cogl_program_set_uniform_matrix (priv->program, uniform->location, size, 1, FALSE, matrix); } else if (G_VALUE_HOLDS_FLOAT (&uniform->value)) { const float float_val = g_value_get_float (&uniform->value); cogl_program_set_uniform_float (priv->program, uniform->location, 1, 1, &float_val); } else if (G_VALUE_HOLDS_DOUBLE (&uniform->value)) { const float float_val = (float) g_value_get_double (&uniform->value); cogl_program_set_uniform_float (priv->program, uniform->location, 1, 1, &float_val); } else if (G_VALUE_HOLDS_INT (&uniform->value)) { const int int_val = g_value_get_int (&uniform->value); cogl_program_set_uniform_int (priv->program, uniform->location, 1, 1, &int_val); } else g_warning ("Invalid uniform of type '%s' for name '%s'", g_type_name (G_VALUE_TYPE (&uniform->value)), uniform->name); } } static void clutter_shader_effect_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterShaderEffect *self = CLUTTER_SHADER_EFFECT (meta); ClutterShaderEffectPrivate *priv = self->priv; ClutterActorMetaClass *parent; if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) { /* if we don't have support for GLSL shaders then we * forcibly disable the ActorMeta */ g_warning ("Unable to use the ShaderEffect: the graphics hardware " "or the current GL driver does not implement support " "for the GLSL shading language."); clutter_actor_meta_set_enabled (meta, FALSE); return; } parent = CLUTTER_ACTOR_META_CLASS (clutter_shader_effect_parent_class); parent->set_actor (meta, actor); /* we keep a back pointer here */ priv->actor = clutter_actor_meta_get_actor (meta); if (priv->actor == NULL) return; CLUTTER_NOTE (SHADER, "Preparing shader effect of type '%s'", G_OBJECT_TYPE_NAME (meta)); } static CoglHandle clutter_shader_effect_create_shader (ClutterShaderEffect *self) { ClutterShaderEffectPrivate *priv = self->priv; switch (priv->shader_type) { case CLUTTER_FRAGMENT_SHADER: return cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); break; case CLUTTER_VERTEX_SHADER: return cogl_create_shader (COGL_SHADER_TYPE_VERTEX); break; default: g_assert_not_reached (); } } static void clutter_shader_effect_try_static_source (ClutterShaderEffect *self) { ClutterShaderEffectPrivate *priv = self->priv; ClutterShaderEffectClass *shader_effect_class = CLUTTER_SHADER_EFFECT_GET_CLASS (self); if (shader_effect_class->get_static_shader_source != NULL) { ClutterShaderEffectClassPrivate *class_priv; class_priv = G_TYPE_CLASS_GET_PRIVATE (shader_effect_class, CLUTTER_TYPE_SHADER_EFFECT, ClutterShaderEffectClassPrivate); if (class_priv->shader == COGL_INVALID_HANDLE) { gchar *source; class_priv->shader = clutter_shader_effect_create_shader (self); source = shader_effect_class->get_static_shader_source (self); cogl_shader_source (class_priv->shader, source); free (source); CLUTTER_NOTE (SHADER, "Compiling shader effect"); cogl_shader_compile (class_priv->shader); if (cogl_shader_is_compiled (class_priv->shader)) { class_priv->program = cogl_create_program (); cogl_program_attach_shader (class_priv->program, class_priv->shader); cogl_program_link (class_priv->program); } else { gchar *log_buf = cogl_shader_get_info_log (class_priv->shader); g_warning (G_STRLOC ": Unable to compile the GLSL shader: %s", log_buf); free (log_buf); } } priv->shader = cogl_handle_ref (class_priv->shader); if (class_priv->program != COGL_INVALID_HANDLE) priv->program = cogl_handle_ref (class_priv->program); } } static void clutter_shader_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterShaderEffect *self = CLUTTER_SHADER_EFFECT (effect); ClutterShaderEffectPrivate *priv = self->priv; ClutterOffscreenEffectClass *parent; CoglHandle material; /* If the source hasn't been set then we'll try to get it from the static source instead */ if (priv->shader == COGL_INVALID_HANDLE) clutter_shader_effect_try_static_source (self); /* we haven't been prepared or we don't have support for * GLSL shaders in Clutter */ if (priv->program == COGL_INVALID_HANDLE) goto out; CLUTTER_NOTE (SHADER, "Applying the shader effect of type '%s'", G_OBJECT_TYPE_NAME (effect)); clutter_shader_effect_update_uniforms (CLUTTER_SHADER_EFFECT (effect)); /* associate the program to the offscreen target material */ material = clutter_offscreen_effect_get_target (effect); cogl_pipeline_set_user_program (material, priv->program); out: /* paint the offscreen buffer */ parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (clutter_shader_effect_parent_class); parent->paint_target (effect); } static void clutter_shader_effect_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterShaderEffectPrivate *priv = CLUTTER_SHADER_EFFECT (gobject)->priv; switch (prop_id) { case PROP_SHADER_TYPE: priv->shader_type = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_shader_effect_finalize (GObject *gobject) { ClutterShaderEffect *effect = CLUTTER_SHADER_EFFECT (gobject); clutter_shader_effect_clear (effect, TRUE); G_OBJECT_CLASS (clutter_shader_effect_parent_class)->finalize (gobject); } static void clutter_shader_effect_class_init (ClutterShaderEffectClass *klass) { ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterOffscreenEffectClass *offscreen_class; offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); /** * ClutterShaderEffect:shader-type: * * The type of shader that is used by the effect. This property * should be set by the constructor of #ClutterShaderEffect * sub-classes. * * Since: 1.4 */ obj_props[PROP_SHADER_TYPE] = g_param_spec_enum ("shader-type", P_("Shader Type"), P_("The type of shader used"), CLUTTER_TYPE_SHADER_TYPE, CLUTTER_FRAGMENT_SHADER, CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); gobject_class->set_property = clutter_shader_effect_set_property; gobject_class->finalize = clutter_shader_effect_finalize; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); meta_class->set_actor = clutter_shader_effect_set_actor; offscreen_class->paint_target = clutter_shader_effect_paint_target; } static void clutter_shader_effect_init (ClutterShaderEffect *effect) { effect->priv = clutter_shader_effect_get_instance_private (effect); } /** * clutter_shader_effect_new: * @shader_type: the type of the shader, either %CLUTTER_FRAGMENT_SHADER, * or %CLUTTER_VERTEX_SHADER * * Creates a new #ClutterShaderEffect, to be applied to an actor using * clutter_actor_add_effect(). * * The effect will be empty until clutter_shader_effect_set_shader_source() * is called. * * Return value: the newly created #ClutterShaderEffect. * Use g_object_unref() when done. * * Since: 1.8 */ ClutterEffect * clutter_shader_effect_new (ClutterShaderType shader_type) { return g_object_new (CLUTTER_TYPE_SHADER_EFFECT, "shader-type", shader_type, NULL); } /** * clutter_shader_effect_get_shader: * @effect: a #ClutterShaderEffect * * Retrieves a pointer to the shader's handle * * Return value: (transfer none): a pointer to the shader's handle, * or %COGL_INVALID_HANDLE * * Since: 1.4 */ CoglHandle clutter_shader_effect_get_shader (ClutterShaderEffect *effect) { g_return_val_if_fail (CLUTTER_IS_SHADER_EFFECT (effect), COGL_INVALID_HANDLE); return effect->priv->shader; } /** * clutter_shader_effect_get_program: * @effect: a #ClutterShaderEffect * * Retrieves a pointer to the program's handle * * Return value: (transfer none): a pointer to the program's handle, * or %COGL_INVALID_HANDLE * * Since: 1.4 */ CoglHandle clutter_shader_effect_get_program (ClutterShaderEffect *effect) { g_return_val_if_fail (CLUTTER_IS_SHADER_EFFECT (effect), COGL_INVALID_HANDLE); return effect->priv->program; } static void shader_uniform_free (gpointer data) { if (data != NULL) { ShaderUniform *uniform = data; g_value_unset (&uniform->value); free (uniform->name); g_slice_free (ShaderUniform, uniform); } } static ShaderUniform * shader_uniform_new (const gchar *name, const GValue *value) { ShaderUniform *retval; retval = g_slice_new0 (ShaderUniform); retval->name = g_strdup (name); retval->type = G_VALUE_TYPE (value); retval->location = -1; g_value_init (&retval->value, retval->type); g_value_copy (value, &retval->value); return retval; } static void shader_uniform_update (ShaderUniform *uniform, const GValue *value) { g_value_unset (&uniform->value); g_value_init (&uniform->value, G_VALUE_TYPE (value)); g_value_copy (value, &uniform->value); } static inline void clutter_shader_effect_add_uniform (ClutterShaderEffect *effect, const gchar *name, const GValue *value) { ClutterShaderEffectPrivate *priv = effect->priv; ShaderUniform *uniform; if (priv->uniforms == NULL) { priv->uniforms = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, shader_uniform_free); } uniform = g_hash_table_lookup (priv->uniforms, name); if (uniform == NULL) { uniform = shader_uniform_new (name, value); g_hash_table_insert (priv->uniforms, uniform->name, uniform); } else shader_uniform_update (uniform, value); if (priv->actor != NULL && !CLUTTER_ACTOR_IN_PAINT (priv->actor)) clutter_effect_queue_repaint (CLUTTER_EFFECT (effect)); } /** * clutter_shader_effect_set_uniform_value: * @effect: a #ClutterShaderEffect * @name: the name of the uniform to set * @value: a #GValue with the value of the uniform to set * * Sets @value as the payload for the uniform @name inside the shader * effect * * The #GType of the @value must be one of: %G_TYPE_INT, for a single * integer value; %G_TYPE_FLOAT, for a single floating point value; * %CLUTTER_TYPE_SHADER_INT, for an array of integer values; * %CLUTTER_TYPE_SHADER_FLOAT, for an array of floating point values; * and %CLUTTER_TYPE_SHADER_MATRIX, for a matrix of floating point * values. It also accepts %G_TYPE_DOUBLE for compatibility with other * languages than C. * * Since: 1.4 */ void clutter_shader_effect_set_uniform_value (ClutterShaderEffect *effect, const gchar *name, const GValue *value) { g_return_if_fail (CLUTTER_IS_SHADER_EFFECT (effect)); g_return_if_fail (name != NULL); g_return_if_fail (value != NULL); clutter_shader_effect_add_uniform (effect, name, value); } static void clutter_shader_effect_set_uniform_valist (ClutterShaderEffect *effect, const gchar *name, GType value_type, gsize n_values, va_list *args) { GValue value = G_VALUE_INIT; if (value_type == CLUTTER_TYPE_SHADER_INT) { gint *int_values = va_arg (*args, gint*); g_value_init (&value, CLUTTER_TYPE_SHADER_INT); clutter_value_set_shader_int (&value, n_values, int_values); goto add_uniform; } if (value_type == CLUTTER_TYPE_SHADER_FLOAT) { gfloat *float_values = va_arg (*args, gfloat*); g_value_init (&value, CLUTTER_TYPE_SHADER_FLOAT); clutter_value_set_shader_float (&value, n_values, float_values); goto add_uniform; } if (value_type == CLUTTER_TYPE_SHADER_MATRIX) { gfloat *float_values = va_arg (*args, gfloat*); g_value_init (&value, CLUTTER_TYPE_SHADER_MATRIX); clutter_value_set_shader_matrix (&value, n_values, float_values); goto add_uniform; } if (value_type == G_TYPE_INT) { g_return_if_fail (n_values <= 4); /* if we only have one value we can go through the fast path * of using G_TYPE_INT, otherwise we create a vector of integers * from the passed values */ if (n_values == 1) { gint int_val = va_arg (*args, gint); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, int_val); } else { gint *int_values = g_new (gint, n_values); gint i; for (i = 0; i < n_values; i++) int_values[i] = va_arg (*args, gint); g_value_init (&value, CLUTTER_TYPE_SHADER_INT); clutter_value_set_shader_int (&value, n_values, int_values); free (int_values); } goto add_uniform; } if (value_type == G_TYPE_FLOAT) { g_return_if_fail (n_values <= 4); /* if we only have one value we can go through the fast path * of using G_TYPE_FLOAT, otherwise we create a vector of floats * from the passed values */ if (n_values == 1) { gfloat float_val = (gfloat) va_arg (*args, gdouble); g_value_init (&value, G_TYPE_FLOAT); g_value_set_float (&value, float_val); } else { gfloat *float_values = g_new (gfloat, n_values); gint i; for (i = 0; i < n_values; i++) float_values[i] = (gfloat) va_arg (*args, double); g_value_init (&value, CLUTTER_TYPE_SHADER_FLOAT); clutter_value_set_shader_float (&value, n_values, float_values); free (float_values); } goto add_uniform; } g_warning ("Unrecognized type '%s' (values: %d) for uniform name '%s'", g_type_name (value_type), (int) n_values, name); return; add_uniform: clutter_shader_effect_add_uniform (effect, name, &value); g_value_unset (&value); } /** * clutter_shader_effect_set_uniform: * @effect: a #ClutterShaderEffect * @name: the name of the uniform to set * @gtype: the type of the uniform to set * @n_values: the number of values * @...: a list of values * * Sets a list of values as the payload for the uniform @name inside * the shader effect * * The @gtype must be one of: %G_TYPE_INT, for 1 or more integer values; * %G_TYPE_FLOAT, for 1 or more floating point values; * %CLUTTER_TYPE_SHADER_INT, for a pointer to an array of integer values; * %CLUTTER_TYPE_SHADER_FLOAT, for a pointer to an array of floating point * values; and %CLUTTER_TYPE_SHADER_MATRIX, for a pointer to an array of * floating point values mapping a matrix * * The number of values interepreted is defined by the @n_value * argument, and by the @gtype argument. For instance, a uniform named * "sampler0" and containing a single integer value is set using: * * |[<!-- language="C" --> * clutter_shader_effect_set_uniform (effect, "sampler0", * G_TYPE_INT, 1, * 0); * ]| * * While a uniform named "components" and containing a 3-elements vector * of floating point values (a "vec3") can be set using: * * |[<!-- language="C" --> * gfloat component_r, component_g, component_b; * * clutter_shader_effect_set_uniform (effect, "components", * G_TYPE_FLOAT, 3, * component_r, * component_g, * component_b); * ]| * * or can be set using: * * |[<!-- language="C" --> * gfloat component_vec[3]; * * clutter_shader_effect_set_uniform (effect, "components", * CLUTTER_TYPE_SHADER_FLOAT, 3, * component_vec); * ]| * * Finally, a uniform named "map" and containing a matrix can be set using: * * |[<!-- language="C" --> * clutter_shader_effect_set_uniform (effect, "map", * CLUTTER_TYPE_SHADER_MATRIX, 1, * cogl_matrix_get_array (&matrix)); * ]| * * Since: 1.4 */ void clutter_shader_effect_set_uniform (ClutterShaderEffect *effect, const gchar *name, GType gtype, gsize n_values, ...) { va_list args; g_return_if_fail (CLUTTER_IS_SHADER_EFFECT (effect)); g_return_if_fail (name != NULL); g_return_if_fail (gtype != G_TYPE_INVALID); g_return_if_fail (n_values > 0); va_start (args, n_values); clutter_shader_effect_set_uniform_valist (effect, name, gtype, n_values, &args); va_end (args); } /** * clutter_shader_effect_set_shader_source: * @effect: a #ClutterShaderEffect * @source: the source of a GLSL shader * * Sets the source of the GLSL shader used by @effect * * This function should only be called by implementations of * the #ClutterShaderEffect class, and not by application code. * * This function can only be called once; subsequent calls will * yield no result. * * Return value: %TRUE if the source was set * * Since: 1.4 */ gboolean clutter_shader_effect_set_shader_source (ClutterShaderEffect *effect, const gchar *source) { ClutterShaderEffectPrivate *priv; g_return_val_if_fail (CLUTTER_IS_SHADER_EFFECT (effect), FALSE); g_return_val_if_fail (source != NULL && *source != '\0', FALSE); priv = effect->priv; if (priv->shader != COGL_INVALID_HANDLE) return TRUE; priv->shader = clutter_shader_effect_create_shader (effect); cogl_shader_source (priv->shader, source); CLUTTER_NOTE (SHADER, "Compiling shader effect"); cogl_shader_compile (priv->shader); if (cogl_shader_is_compiled (priv->shader)) { priv->program = cogl_create_program (); cogl_program_attach_shader (priv->program, priv->shader); cogl_program_link (priv->program); } else { gchar *log_buf = cogl_shader_get_info_log (priv->shader); g_warning (G_STRLOC ": Unable to compile the GLSL shader: %s", log_buf); free (log_buf); } return TRUE; } ������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-brightness-contrast-effect.c�����������������������������������0000664�0001750�0001750�00000053535�14211404421�025374� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010-2012 Inclusive Design Research Centre, OCAD University. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Joseph Scheuhammer <clown@alum.mit.edu> */ /** * SECTION:clutter-brightness-contrast-effect * @short_description: Increase/decrease brightness and/or contrast of actor. * @see_also: #ClutterEffect, #ClutterOffscreenEffect * * #ClutterBrightnessContrastEffect is a sub-class of #ClutterEffect that * changes the overall brightness of a #ClutterActor. * * #ClutterBrightnessContrastEffect is available since Clutter 1.10 */ #define CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT, ClutterBrightnessContrastEffectClass)) #define CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT)) #define CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT, ClutterBrightnessContrastEffectClass)) #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-brightness-contrast-effect.h" #include <cogl/cogl.h> #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-offscreen-effect.h" #include "clutter-private.h" struct _ClutterBrightnessContrastEffect { ClutterOffscreenEffect parent_instance; /* Brightness and contrast changes. */ gfloat brightness_red; gfloat brightness_green; gfloat brightness_blue; gfloat contrast_red; gfloat contrast_green; gfloat contrast_blue; gint brightness_multiplier_uniform; gint brightness_offset_uniform; gint contrast_uniform; gint tex_width; gint tex_height; CoglPipeline *pipeline; }; struct _ClutterBrightnessContrastEffectClass { ClutterOffscreenEffectClass parent_class; CoglPipeline *base_pipeline; }; /* Brightness effects in GLSL. */ static const gchar *brightness_contrast_decls = "uniform vec3 brightness_multiplier;\n" "uniform vec3 brightness_offset;\n" "uniform vec3 contrast;\n"; static const gchar *brightness_contrast_source = /* Apply the brightness. The brightness_offset is multiplied by the alpha to keep the color pre-multiplied */ "cogl_color_out.rgb = (cogl_color_out.rgb * brightness_multiplier +\n" " brightness_offset * cogl_color_out.a);\n" /* Apply the contrast */ "cogl_color_out.rgb = ((cogl_color_out.rgb - 0.5 * cogl_color_out.a) *\n" " contrast + 0.5 * cogl_color_out.a);\n"; static const ClutterColor no_brightness_change = { 0x7f, 0x7f, 0x7f, 0xff }; static const ClutterColor no_contrast_change = { 0x7f, 0x7f, 0x7f, 0xff }; static const gfloat no_change = 0.0f; enum { PROP_0, PROP_BRIGHTNESS, PROP_CONTRAST, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterBrightnessContrastEffect, clutter_brightness_contrast_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT); static gboolean will_have_no_effect (ClutterBrightnessContrastEffect *self) { return (self->brightness_red == no_change && self->brightness_green == no_change && self->brightness_blue == no_change && self->contrast_red == no_change && self->contrast_green == no_change && self->contrast_blue == no_change); } static gboolean clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect) { ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect); ClutterEffectClass *parent_class; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) return FALSE; if (will_have_no_effect (self)) return FALSE; if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) { /* if we don't have support for GLSL shaders then we * forcibly disable the ActorMeta */ g_warning ("Unable to use the ClutterBrightnessContrastEffect: the " "graphics hardware or the current GL driver does not " "implement support for the GLSL shading language. The " "effect will be disabled."); clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE); return FALSE; } parent_class = CLUTTER_EFFECT_CLASS (clutter_brightness_contrast_effect_parent_class); if (parent_class->pre_paint (effect)) { ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect); CoglHandle texture; texture = clutter_offscreen_effect_get_texture (offscreen_effect); self->tex_width = cogl_texture_get_width (texture); self->tex_height = cogl_texture_get_height (texture); cogl_pipeline_set_layer_texture (self->pipeline, 0, texture); return TRUE; } else return FALSE; } static void clutter_brightness_contrast_effect_paint_target (ClutterOffscreenEffect *effect) { ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect); ClutterActor *actor; guint8 paint_opacity; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); paint_opacity = clutter_actor_get_paint_opacity (actor); cogl_pipeline_set_color4ub (self->pipeline, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_push_source (self->pipeline); cogl_rectangle (0, 0, self->tex_width, self->tex_height); cogl_pop_source (); } static void clutter_brightness_contrast_effect_dispose (GObject *gobject) { ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (gobject); if (self->pipeline != NULL) { cogl_object_unref (self->pipeline); self->pipeline = NULL; } G_OBJECT_CLASS (clutter_brightness_contrast_effect_parent_class)->dispose (gobject); } static void clutter_brightness_contrast_effect_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBrightnessContrastEffect *effect = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (gobject); switch (prop_id) { case PROP_BRIGHTNESS: { const ClutterColor *color = clutter_value_get_color (value); clutter_brightness_contrast_effect_set_brightness_full (effect, color->red / 127.0f - 1.0f, color->green / 127.0f - 1.0f, color->blue / 127.0f - 1.0f); } break; case PROP_CONTRAST: { const ClutterColor *color = clutter_value_get_color (value); clutter_brightness_contrast_effect_set_contrast_full (effect, color->red / 127.0f - 1.0f, color->green / 127.0f - 1.0f, color->blue / 127.0f - 1.0f); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_brightness_contrast_effect_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBrightnessContrastEffect *effect = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (gobject); ClutterColor color; switch (prop_id) { case PROP_BRIGHTNESS: { color.red = (effect->brightness_red + 1.0f) * 127.0f; color.green = (effect->brightness_green + 1.0f) * 127.0f; color.blue = (effect->brightness_blue + 1.0f) * 127.0f; color.alpha = 0xff; clutter_value_set_color (value, &color); } break; case PROP_CONTRAST: { color.red = (effect->contrast_red + 1.0f) * 127.0f; color.green = (effect->contrast_green + 1.0f) * 127.0f; color.blue = (effect->contrast_blue + 1.0f) * 127.0f; color.alpha = 0xff; clutter_value_set_color (value, &color); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_brightness_contrast_effect_class_init (ClutterBrightnessContrastEffectClass *klass) { ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterOffscreenEffectClass *offscreen_class; offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class->paint_target = clutter_brightness_contrast_effect_paint_target; effect_class->pre_paint = clutter_brightness_contrast_effect_pre_paint; gobject_class->set_property = clutter_brightness_contrast_effect_set_property; gobject_class->get_property = clutter_brightness_contrast_effect_get_property; gobject_class->dispose = clutter_brightness_contrast_effect_dispose; /** * ClutterBrightnessContrastEffect:brightness: * * The brightness change to apply to the effect. * * This property uses a #ClutterColor to represent the changes to each * color channel. The range is [ 0, 255 ], with 127 as the value used * to indicate no change; values smaller than 127 indicate a decrease * in brightness, and values larger than 127 indicate an increase in * brightness. * * Since: 1.10 */ obj_props[PROP_BRIGHTNESS] = clutter_param_spec_color ("brightness", P_("Brightness"), P_("The brightness change to apply"), &no_brightness_change, CLUTTER_PARAM_READWRITE); /** * ClutterBrightnessContrastEffect:contrast: * * The contrast change to apply to the effect. * * This property uses a #ClutterColor to represent the changes to each * color channel. The range is [ 0, 255 ], with 127 as the value used * to indicate no change; values smaller than 127 indicate a decrease * in contrast, and values larger than 127 indicate an increase in * contrast. * * Since: 1.10 */ obj_props[PROP_CONTRAST] = clutter_param_spec_color ("contrast", P_("Contrast"), P_("The contrast change to apply"), &no_contrast_change, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void get_brightness_values (gfloat value, gfloat *multiplier, gfloat *offset) { if (value < 0.0f) { *multiplier = 1.0f + value; *offset = 0.0f; } else { *multiplier = 1.0f - value; *offset = value; } } static inline void update_uniforms (ClutterBrightnessContrastEffect *self) { if (self->brightness_multiplier_uniform > -1 && self->brightness_offset_uniform > -1) { float brightness_multiplier[3]; float brightness_offset[3]; get_brightness_values (self->brightness_red, brightness_multiplier + 0, brightness_offset + 0); get_brightness_values (self->brightness_green, brightness_multiplier + 1, brightness_offset + 1); get_brightness_values (self->brightness_blue, brightness_multiplier + 2, brightness_offset + 2); cogl_pipeline_set_uniform_float (self->pipeline, self->brightness_multiplier_uniform, 3, /* n_components */ 1, /* count */ brightness_multiplier); cogl_pipeline_set_uniform_float (self->pipeline, self->brightness_offset_uniform, 3, /* n_components */ 1, /* count */ brightness_offset); } if (self->contrast_uniform > -1) { float contrast[3] = { tan ((self->contrast_red + 1) * G_PI_4), tan ((self->contrast_green + 1) * G_PI_4), tan ((self->contrast_blue + 1) * G_PI_4) }; cogl_pipeline_set_uniform_float (self->pipeline, self->contrast_uniform, 3, /* n_components */ 1, /* count */ contrast); } } static void clutter_brightness_contrast_effect_init (ClutterBrightnessContrastEffect *self) { ClutterBrightnessContrastEffectClass *klass; self->brightness_red = no_change; self->brightness_green = no_change; self->brightness_blue = no_change; self->contrast_red = no_change; self->contrast_green = no_change; self->contrast_blue = no_change; klass = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_GET_CLASS (self); if (G_UNLIKELY (klass->base_pipeline == NULL)) { CoglSnippet *snippet; CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); klass->base_pipeline = cogl_pipeline_new (ctx); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, brightness_contrast_decls, brightness_contrast_source); cogl_pipeline_add_snippet (klass->base_pipeline, snippet); cogl_object_unref (snippet); cogl_pipeline_set_layer_null_texture (klass->base_pipeline, 0, /* layer number */ COGL_TEXTURE_TYPE_2D); } self->pipeline = cogl_pipeline_copy (klass->base_pipeline); self->brightness_multiplier_uniform = cogl_pipeline_get_uniform_location (self->pipeline, "brightness_multiplier"); self->brightness_offset_uniform = cogl_pipeline_get_uniform_location (self->pipeline, "brightness_offset"); self->contrast_uniform = cogl_pipeline_get_uniform_location (self->pipeline, "contrast"); update_uniforms (self); } /** * clutter_brightness_contrast_effect_new: * * Creates a new #ClutterBrightnessContrastEffect to be used with * clutter_actor_add_effect() * * Return value: (transfer full): the newly created * #ClutterBrightnessContrastEffect or %NULL. Use g_object_unref() when * done. * * Since: 1.10 */ ClutterEffect * clutter_brightness_contrast_effect_new (void) { return g_object_new (CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT, NULL); } /** * clutter_brightness_contrast_effect_set_brightness_full: * @effect: a #ClutterBrightnessContrastEffect * @red: red component of the change in brightness * @green: green component of the change in brightness * @blue: blue component of the change in brightness * * The range for each component is [-1.0, 1.0] where 0.0 designates no change, * values below 0.0 mean a decrease in brightness, and values above indicate * an increase. * * Since: 1.10 */ void clutter_brightness_contrast_effect_set_brightness_full (ClutterBrightnessContrastEffect *effect, gfloat red, gfloat green, gfloat blue) { g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect)); if (red == effect->brightness_red && green == effect->brightness_green && blue == effect->brightness_blue) return; effect->brightness_red = red; effect->brightness_green = green; effect->brightness_blue = blue; update_uniforms (effect); clutter_effect_queue_repaint (CLUTTER_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_BRIGHTNESS]); } /** * clutter_brightness_contrast_effect_get_brightness: * @effect: a #ClutterBrightnessContrastEffect * @red: (out) (allow-none): return location for red component of the * change in brightness * @green: (out) (allow-none): return location for green component of the * change in brightness * @blue: (out) (allow-none): return location for blue component of the * change in brightness * * Retrieves the change in brightness used by @effect. * * Since: 1.10 */ void clutter_brightness_contrast_effect_get_brightness (ClutterBrightnessContrastEffect *effect, gfloat *red, gfloat *green, gfloat *blue) { g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect)); if (red != NULL) *red = effect->brightness_red; if (green != NULL) *green = effect->brightness_green; if (blue != NULL) *blue = effect->brightness_blue; } /** * clutter_brightness_contrast_effect_set_brightness: * @effect: a #ClutterBrightnessContrastEffect * @brightness: the brightness change for all three components (r, g, b) * * The range of @brightness is [-1.0, 1.0], where 0.0 designates no change; * a value below 0.0 indicates a decrease in brightness; and a value * above 0.0 indicates an increase of brightness. * * Since: 1.10 */ void clutter_brightness_contrast_effect_set_brightness (ClutterBrightnessContrastEffect *effect, gfloat brightness) { clutter_brightness_contrast_effect_set_brightness_full (effect, brightness, brightness, brightness); } /** * clutter_brightness_contrast_effect_set_contrast_full: * @effect: a #ClutterBrightnessContrastEffect * @red: red component of the change in contrast * @green: green component of the change in contrast * @blue: blue component of the change in contrast * * The range for each component is [-1.0, 1.0] where 0.0 designates no change, * values below 0.0 mean a decrease in contrast, and values above indicate * an increase. * * Since: 1.10 */ void clutter_brightness_contrast_effect_set_contrast_full (ClutterBrightnessContrastEffect *effect, gfloat red, gfloat green, gfloat blue) { g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect)); if (red == effect->contrast_red && green == effect->contrast_green && blue == effect->contrast_blue) return; effect->contrast_red = red; effect->contrast_green = green; effect->contrast_blue = blue; update_uniforms (effect); clutter_effect_queue_repaint (CLUTTER_EFFECT (effect)); g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_CONTRAST]); } /** * clutter_brightness_contrast_effect_get_contrast: * @effect: a #ClutterBrightnessContrastEffect * @red: (out) (allow-none): return location for red component of the * change in contrast * @green: (out) (allow-none): return location for green component of the * change in contrast * @blue: (out) (allow-none): return location for blue component of the * change in contrast * * Retrieves the contrast value used by @effect. * * Since: 1.10 */ void clutter_brightness_contrast_effect_get_contrast (ClutterBrightnessContrastEffect *effect, gfloat *red, gfloat *green, gfloat *blue) { g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect)); if (red != NULL) *red = effect->contrast_red; if (green != NULL) *green = effect->contrast_green; if (blue != NULL) *blue = effect->contrast_blue; } /** * clutter_brightness_contrast_effect_set_contrast: * @effect: a #ClutterBrightnessContrastEffect * @contrast: contrast change for all three channels * * The range for @contrast is [-1.0, 1.0], where 0.0 designates no change; * a value below 0.0 indicates a decrease in contrast; and a value above * 0.0 indicates an increase. * * Since: 1.10 */ void clutter_brightness_contrast_effect_set_contrast (ClutterBrightnessContrastEffect *effect, gfloat contrast) { clutter_brightness_contrast_effect_set_contrast_full (effect, contrast, contrast, contrast); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-click-action.c�������������������������������������������������0000664�0001750�0001750�00000056570�14211404421�022501� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-click-action * @Title: ClutterClickAction * @Short_Description: Action for clickable actors * * #ClutterClickAction is a sub-class of #ClutterAction that implements * the logic for clickable actors, by using the low level events of * #ClutterActor, such as #ClutterActor::button-press-event and * #ClutterActor::button-release-event, to synthesize the high level * #ClutterClickAction::clicked signal. * * To use #ClutterClickAction you just need to apply it to a #ClutterActor * using clutter_actor_add_action() and connect to the * #ClutterClickAction::clicked signal: * * |[ * ClutterAction *action = clutter_click_action_new (); * * clutter_actor_add_action (actor, action); * * g_signal_connect (action, "clicked", G_CALLBACK (on_clicked), NULL); * ]| * * #ClutterClickAction also supports long press gestures: a long press is * activated if the pointer remains pressed within a certain threshold (as * defined by the #ClutterClickAction:long-press-threshold property) for a * minimum amount of time (as the defined by the * #ClutterClickAction:long-press-duration property). * The #ClutterClickAction::long-press signal is emitted multiple times, * using different #ClutterLongPressState values; to handle long presses * you should connect to the #ClutterClickAction::long-press signal and * handle the different states: * * |[ * static gboolean * on_long_press (ClutterClickAction *action, * ClutterActor *actor, * ClutterLongPressState state) * { * switch (state) * { * case CLUTTER_LONG_PRESS_QUERY: * /* return TRUE if the actor should support long press * * gestures, and FALSE otherwise; this state will be * * emitted on button presses * */ * return TRUE; * * case CLUTTER_LONG_PRESS_ACTIVATE: * /* this state is emitted if the minimum duration has * * been reached without the gesture being cancelled. * * the return value is not used * */ * return TRUE; * * case CLUTTER_LONG_PRESS_CANCEL: * /* this state is emitted if the long press was cancelled; * * for instance, the pointer went outside the actor or the * * allowed threshold, or the button was released before * * the minimum duration was reached. the return value is * * not used * */ * return FALSE; * } * } * ]| * * #ClutterClickAction is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-click-action.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" struct _ClutterClickActionPrivate { ClutterActor *stage; guint event_id; guint capture_id; guint long_press_id; gint long_press_threshold; gint long_press_duration; gint drag_threshold; guint press_button; gint press_device_id; ClutterEventSequence *press_sequence; ClutterModifierType modifier_state; gfloat press_x; gfloat press_y; guint is_held : 1; guint is_pressed : 1; }; enum { PROP_0, PROP_HELD, PROP_PRESSED, PROP_LONG_PRESS_THRESHOLD, PROP_LONG_PRESS_DURATION, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; enum { CLICKED, LONG_PRESS, LAST_SIGNAL }; static guint click_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterClickAction, clutter_click_action, CLUTTER_TYPE_ACTION) /* forward declaration */ static gboolean on_captured_event (ClutterActor *stage, ClutterEvent *event, ClutterClickAction *action); static inline void click_action_set_pressed (ClutterClickAction *action, gboolean is_pressed) { ClutterClickActionPrivate *priv = action->priv; is_pressed = !!is_pressed; if (priv->is_pressed == is_pressed) return; priv->is_pressed = is_pressed; g_object_notify_by_pspec (G_OBJECT (action), obj_props[PROP_PRESSED]); } static inline void click_action_set_held (ClutterClickAction *action, gboolean is_held) { ClutterClickActionPrivate *priv = action->priv; is_held = !!is_held; if (priv->is_held == is_held) return; priv->is_held = is_held; g_object_notify_by_pspec (G_OBJECT (action), obj_props[PROP_HELD]); } static gboolean click_action_emit_long_press (gpointer data) { ClutterClickAction *action = data; ClutterClickActionPrivate *priv = action->priv; ClutterActor *actor; gboolean result; priv->long_press_id = 0; actor = clutter_actor_meta_get_actor (data); g_signal_emit (action, click_signals[LONG_PRESS], 0, actor, CLUTTER_LONG_PRESS_ACTIVATE, &result); if (priv->capture_id != 0) { g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; } click_action_set_pressed (action, FALSE); click_action_set_held (action, FALSE); return FALSE; } static inline void click_action_query_long_press (ClutterClickAction *action) { ClutterClickActionPrivate *priv = action->priv; ClutterActor *actor; gboolean result = FALSE; gint timeout; if (priv->long_press_duration < 0) { ClutterSettings *settings = clutter_settings_get_default (); g_object_get (settings, "long-press-duration", &timeout, NULL); } else timeout = priv->long_press_duration; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); g_signal_emit (action, click_signals[LONG_PRESS], 0, actor, CLUTTER_LONG_PRESS_QUERY, &result); if (result) { priv->long_press_id = clutter_threads_add_timeout (timeout, click_action_emit_long_press, action); } } static inline void click_action_cancel_long_press (ClutterClickAction *action) { ClutterClickActionPrivate *priv = action->priv; if (priv->long_press_id != 0) { ClutterActor *actor; gboolean result; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); g_source_remove (priv->long_press_id); priv->long_press_id = 0; g_signal_emit (action, click_signals[LONG_PRESS], 0, actor, CLUTTER_LONG_PRESS_CANCEL, &result); } } static gboolean on_event (ClutterActor *actor, ClutterEvent *event, ClutterClickAction *action) { ClutterClickActionPrivate *priv = action->priv; gboolean has_button = TRUE; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) return CLUTTER_EVENT_PROPAGATE; switch (clutter_event_type (event)) { case CLUTTER_TOUCH_BEGIN: has_button = FALSE; case CLUTTER_BUTTON_PRESS: if (has_button && clutter_event_get_click_count (event) != 1) return CLUTTER_EVENT_PROPAGATE; if (priv->is_held) return CLUTTER_EVENT_STOP; if (!clutter_actor_contains (actor, clutter_event_get_source (event))) return CLUTTER_EVENT_PROPAGATE; priv->press_button = has_button ? clutter_event_get_button (event) : 0; priv->press_device_id = clutter_event_get_device_id (event); priv->press_sequence = clutter_event_get_event_sequence (event); priv->modifier_state = clutter_event_get_state (event); clutter_event_get_coords (event, &priv->press_x, &priv->press_y); if (priv->long_press_threshold < 0) { ClutterSettings *settings = clutter_settings_get_default (); g_object_get (settings, "dnd-drag-threshold", &priv->drag_threshold, NULL); } else priv->drag_threshold = priv->long_press_threshold; if (priv->stage == NULL) priv->stage = clutter_actor_get_stage (actor); priv->capture_id = g_signal_connect_after (priv->stage, "captured-event", G_CALLBACK (on_captured_event), action); click_action_set_pressed (action, TRUE); click_action_set_held (action, TRUE); click_action_query_long_press (action); break; case CLUTTER_ENTER: click_action_set_pressed (action, priv->is_held); break; case CLUTTER_LEAVE: click_action_set_pressed (action, priv->is_held); click_action_cancel_long_press (action); break; default: break; } return CLUTTER_EVENT_PROPAGATE; } static gboolean on_captured_event (ClutterActor *stage, ClutterEvent *event, ClutterClickAction *action) { ClutterClickActionPrivate *priv = action->priv; ClutterActor *actor; ClutterModifierType modifier_state; gboolean has_button = TRUE; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); switch (clutter_event_type (event)) { case CLUTTER_TOUCH_END: has_button = FALSE; case CLUTTER_BUTTON_RELEASE: if (!priv->is_held) return CLUTTER_EVENT_STOP; if ((has_button && clutter_event_get_button (event) != priv->press_button) || (has_button && clutter_event_get_click_count (event) != 1) || clutter_event_get_device_id (event) != priv->press_device_id || clutter_event_get_event_sequence (event) != priv->press_sequence) return CLUTTER_EVENT_PROPAGATE; click_action_set_held (action, FALSE); click_action_cancel_long_press (action); /* disconnect the capture */ if (priv->capture_id != 0) { g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; } if (priv->long_press_id != 0) { g_source_remove (priv->long_press_id); priv->long_press_id = 0; } if (!clutter_actor_contains (actor, clutter_event_get_source (event))) return CLUTTER_EVENT_PROPAGATE; /* exclude any button-mask so that we can compare * the press and release states properly */ modifier_state = clutter_event_get_state (event) & ~(CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK | CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK); /* if press and release states don't match we * simply ignore modifier keys. i.e. modifier keys * are expected to be pressed throughout the whole * click */ if (modifier_state != priv->modifier_state) priv->modifier_state = 0; click_action_set_pressed (action, FALSE); g_signal_emit (action, click_signals[CLICKED], 0, actor); break; case CLUTTER_MOTION: case CLUTTER_TOUCH_UPDATE: { gfloat motion_x, motion_y; gfloat delta_x, delta_y; if (clutter_event_get_device_id (event) != priv->press_device_id || clutter_event_get_event_sequence (event) != priv->press_sequence) return CLUTTER_EVENT_PROPAGATE; if (!priv->is_held) return CLUTTER_EVENT_PROPAGATE; clutter_event_get_coords (event, &motion_x, &motion_y); delta_x = ABS (motion_x - priv->press_x); delta_y = ABS (motion_y - priv->press_y); if (delta_x > priv->drag_threshold || delta_y > priv->drag_threshold) click_action_cancel_long_press (action); } break; default: break; } return CLUTTER_EVENT_STOP; } static void clutter_click_action_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterClickAction *action = CLUTTER_CLICK_ACTION (meta); ClutterClickActionPrivate *priv = action->priv; if (priv->event_id != 0) { ClutterActor *old_actor = clutter_actor_meta_get_actor (meta); if (old_actor != NULL) g_signal_handler_disconnect (old_actor, priv->event_id); priv->event_id = 0; } if (priv->capture_id != 0) { if (priv->stage != NULL) g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; priv->stage = NULL; } if (priv->long_press_id != 0) { g_source_remove (priv->long_press_id); priv->long_press_id = 0; } click_action_set_pressed (action, FALSE); click_action_set_held (action, FALSE); if (actor != NULL) priv->event_id = g_signal_connect (actor, "event", G_CALLBACK (on_event), action); CLUTTER_ACTOR_META_CLASS (clutter_click_action_parent_class)->set_actor (meta, actor); } static void clutter_click_action_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv; switch (prop_id) { case PROP_LONG_PRESS_DURATION: priv->long_press_duration = g_value_get_int (value); break; case PROP_LONG_PRESS_THRESHOLD: priv->long_press_threshold = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_click_action_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv; switch (prop_id) { case PROP_HELD: g_value_set_boolean (value, priv->is_held); break; case PROP_PRESSED: g_value_set_boolean (value, priv->is_pressed); break; case PROP_LONG_PRESS_DURATION: g_value_set_int (value, priv->long_press_duration); break; case PROP_LONG_PRESS_THRESHOLD: g_value_set_int (value, priv->long_press_threshold); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_click_action_dispose (GObject *gobject) { ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv; if (priv->event_id) { g_signal_handler_disconnect (clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gobject)), priv->event_id); priv->event_id = 0; } if (priv->capture_id) { g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; } if (priv->long_press_id) { g_source_remove (priv->long_press_id); priv->long_press_id = 0; } G_OBJECT_CLASS (clutter_click_action_parent_class)->dispose (gobject); } static void clutter_click_action_class_init (ClutterClickActionClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); meta_class->set_actor = clutter_click_action_set_actor; gobject_class->dispose = clutter_click_action_dispose; gobject_class->set_property = clutter_click_action_set_property; gobject_class->get_property = clutter_click_action_get_property; /** * ClutterClickAction:pressed: * * Whether the clickable actor should be in "pressed" state * * Since: 1.4 */ obj_props[PROP_PRESSED] = g_param_spec_boolean ("pressed", P_("Pressed"), P_("Whether the clickable should be in pressed state"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterClickAction:held: * * Whether the clickable actor has the pointer grabbed * * Since: 1.4 */ obj_props[PROP_HELD] = g_param_spec_boolean ("held", P_("Held"), P_("Whether the clickable has a grab"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterClickAction:long-press-duration: * * The minimum duration of a press for it to be recognized as a long * press gesture, in milliseconds. * * A value of -1 will make the #ClutterClickAction use the value of * the #ClutterSettings:long-press-duration property. * * Since: 1.8 */ obj_props[PROP_LONG_PRESS_DURATION] = g_param_spec_int ("long-press-duration", P_("Long Press Duration"), P_("The minimum duration of a long press to recognize the gesture"), -1, G_MAXINT, -1, CLUTTER_PARAM_READWRITE); /** * ClutterClickAction:long-press-threshold: * * The maximum allowed distance that can be covered (on both axes) before * a long press gesture is cancelled, in pixels. * * A value of -1 will make the #ClutterClickAction use the value of * the #ClutterSettings:dnd-drag-threshold property. * * Since: 1.8 */ obj_props[PROP_LONG_PRESS_THRESHOLD] = g_param_spec_int ("long-press-threshold", P_("Long Press Threshold"), P_("The maximum threshold before a long press is cancelled"), -1, G_MAXINT, -1, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); /** * ClutterClickAction::clicked: * @action: the #ClutterClickAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::clicked signal is emitted when the #ClutterActor to which * a #ClutterClickAction has been applied should respond to a * pointer button press and release events * * Since: 1.4 */ click_signals[CLICKED] = g_signal_new (I_("clicked"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterClickActionClass, clicked), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterClickAction::long-press: * @action: the #ClutterClickAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @state: the long press state * * The ::long-press signal is emitted during the long press gesture * handling. * * This signal can be emitted multiple times with different states. * * The %CLUTTER_LONG_PRESS_QUERY state will be emitted on button presses, * and its return value will determine whether the long press handling * should be initiated. If the signal handlers will return %TRUE, the * %CLUTTER_LONG_PRESS_QUERY state will be followed either by a signal * emission with the %CLUTTER_LONG_PRESS_ACTIVATE state if the long press * constraints were respected, or by a signal emission with the * %CLUTTER_LONG_PRESS_CANCEL state if the long press was cancelled. * * It is possible to forcibly cancel a long press detection using * clutter_click_action_release(). * * Return value: Only the %CLUTTER_LONG_PRESS_QUERY state uses the * returned value of the handler; other states will ignore it * * Since: 1.8 */ click_signals[LONG_PRESS] = g_signal_new (I_("long-press"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterClickActionClass, long_press), NULL, NULL, _clutter_marshal_BOOLEAN__OBJECT_ENUM, G_TYPE_BOOLEAN, 2, CLUTTER_TYPE_ACTOR, CLUTTER_TYPE_LONG_PRESS_STATE); } static void clutter_click_action_init (ClutterClickAction *self) { self->priv = clutter_click_action_get_instance_private (self); self->priv->long_press_threshold = -1; self->priv->long_press_duration = -1; } /** * clutter_click_action_new: * * Creates a new #ClutterClickAction instance * * Return value: the newly created #ClutterClickAction * * Since: 1.4 */ ClutterAction * clutter_click_action_new (void) { return g_object_new (CLUTTER_TYPE_CLICK_ACTION, NULL); } /** * clutter_click_action_release: * @action: a #ClutterClickAction * * Emulates a release of the pointer button, which ungrabs the pointer * and unsets the #ClutterClickAction:pressed state. * * This function will also cancel the long press gesture if one was * initiated. * * This function is useful to break a grab, for instance after a certain * amount of time has passed. * * Since: 1.4 */ void clutter_click_action_release (ClutterClickAction *action) { ClutterClickActionPrivate *priv; g_return_if_fail (CLUTTER_IS_CLICK_ACTION (action)); priv = action->priv; if (!priv->is_held) return; /* disconnect the capture */ if (priv->capture_id != 0) { g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; } click_action_cancel_long_press (action); click_action_set_held (action, FALSE); click_action_set_pressed (action, FALSE); } /** * clutter_click_action_get_button: * @action: a #ClutterClickAction * * Retrieves the button that was pressed. * * Return value: the button value * * Since: 1.4 */ guint clutter_click_action_get_button (ClutterClickAction *action) { g_return_val_if_fail (CLUTTER_IS_CLICK_ACTION (action), 0); return action->priv->press_button; } /** * clutter_click_action_get_state: * @action: a #ClutterClickAction * * Retrieves the modifier state of the click action. * * Return value: the modifier state parameter, or 0 * * Since: 1.6 */ ClutterModifierType clutter_click_action_get_state (ClutterClickAction *action) { g_return_val_if_fail (CLUTTER_IS_CLICK_ACTION (action), 0); return action->priv->modifier_state; } /** * clutter_click_action_get_coords: * @action: a #ClutterClickAction * @press_x: (out): return location for the X coordinate, or %NULL * @press_y: (out): return location for the Y coordinate, or %NULL * * Retrieves the screen coordinates of the button press. * * Since: 1.8 */ void clutter_click_action_get_coords (ClutterClickAction *action, gfloat *press_x, gfloat *press_y) { g_return_if_fail (CLUTTER_IS_ACTION (action)); if (press_x != NULL) *press_x = action->priv->press_x; if (press_y != NULL) *press_y = action->priv->press_y; } ����������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-box-layout.c���������������������������������������������������0000664�0001750�0001750�00000206214�14211404421�022234� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> * * Based on the NBTK NbtkBoxLayout actor by: * Thomas Wood <thomas.wood@intel.com> */ /** * SECTION:clutter-box-layout * @short_description: A layout manager arranging children on a single line * * The #ClutterBoxLayout is a #ClutterLayoutManager implementing the * following layout policy: * * - all children are arranged on a single line * - the axis used is controlled by the #ClutterBoxLayout:orientation property * - the order of the packing is determined by the #ClutterBoxLayout:pack-start boolean property * - each child will be allocated to its natural size or, if #ClutterActor:x-expand or * #ClutterActor:y-expand are set, the available size * - honours the #ClutterActor's #ClutterActor:x-align and #ClutterActor:y-align properties * to fill the available size * - if the #ClutterBoxLayout:homogeneous boolean propert is set, then all widgets will * get the same size, ignoring expand settings and the preferred sizes * * It is possible to control the spacing between children of a * #ClutterBoxLayout by using clutter_box_layout_set_spacing(). * * #ClutterBoxLayout is available since Clutter 1.2 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "deprecated/clutter-alpha.h" #include "clutter-box-layout.h" #include "clutter-actor-private.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-layout-meta.h" #include "clutter-private.h" #include "clutter-types.h" #define CLUTTER_TYPE_BOX_CHILD (clutter_box_child_get_type ()) #define CLUTTER_BOX_CHILD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX_CHILD, ClutterBoxChild)) #define CLUTTER_IS_BOX_CHILD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX_CHILD)) typedef struct _ClutterBoxChild ClutterBoxChild; typedef struct _ClutterLayoutMetaClass ClutterBoxChildClass; struct _ClutterBoxLayoutPrivate { ClutterContainer *container; guint spacing; gulong easing_mode; guint easing_duration; ClutterOrientation orientation; guint is_pack_start : 1; guint use_animations : 1; guint is_homogeneous : 1; }; struct _ClutterBoxChild { ClutterLayoutMeta parent_instance; ClutterBoxAlignment x_align; ClutterBoxAlignment y_align; guint x_fill : 1; guint y_fill : 1; guint expand : 1; }; enum { PROP_CHILD_0, PROP_CHILD_X_ALIGN, PROP_CHILD_Y_ALIGN, PROP_CHILD_X_FILL, PROP_CHILD_Y_FILL, PROP_CHILD_EXPAND, PROP_CHILD_LAST }; enum { PROP_0, PROP_SPACING, PROP_VERTICAL, PROP_HOMOGENEOUS, PROP_PACK_START, PROP_USE_ANIMATIONS, PROP_EASING_MODE, PROP_EASING_DURATION, PROP_ORIENTATION, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; GType clutter_box_child_get_type (void); G_DEFINE_TYPE (ClutterBoxChild, clutter_box_child, CLUTTER_TYPE_LAYOUT_META) G_DEFINE_TYPE_WITH_PRIVATE (ClutterBoxLayout, clutter_box_layout, CLUTTER_TYPE_LAYOUT_MANAGER) typedef struct _RequestedSize { ClutterActor *actor; gfloat minimum_size; gfloat natural_size; } RequestedSize; static gint distribute_natural_allocation (gint extra_space, guint n_requested_sizes, RequestedSize *sizes); static void count_expand_children (ClutterLayoutManager *layout, ClutterContainer *container, gint *visible_children, gint *expand_children); /* * ClutterBoxChild */ static void box_child_set_align (ClutterBoxChild *self, ClutterBoxAlignment x_align, ClutterBoxAlignment y_align) { gboolean x_changed = FALSE, y_changed = FALSE; if (self->x_align != x_align) { self->x_align = x_align; x_changed = TRUE; } if (self->y_align != y_align) { self->y_align = y_align; y_changed = TRUE; } if (x_changed || y_changed) { ClutterLayoutManager *layout; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); if (x_changed) g_object_notify (G_OBJECT (self), "x-align"); if (y_changed) g_object_notify (G_OBJECT (self), "y-align"); } } static void box_child_set_fill (ClutterBoxChild *self, gboolean x_fill, gboolean y_fill) { gboolean x_changed = FALSE, y_changed = FALSE; if (self->x_fill != x_fill) { self->x_fill = x_fill; x_changed = TRUE; } if (self->y_fill != y_fill) { self->y_fill = y_fill; y_changed = TRUE; } if (x_changed || y_changed) { ClutterLayoutManager *layout; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); if (x_changed) g_object_notify (G_OBJECT (self), "x-fill"); if (y_changed) g_object_notify (G_OBJECT (self), "y-fill"); } } static void box_child_set_expand (ClutterBoxChild *self, gboolean expand) { if (self->expand != expand) { ClutterLayoutManager *layout; self->expand = expand; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); g_object_notify (G_OBJECT (self), "expand"); } } static void clutter_box_child_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBoxChild *self = CLUTTER_BOX_CHILD (gobject); switch (prop_id) { case PROP_CHILD_X_ALIGN: box_child_set_align (self, g_value_get_enum (value), self->y_align); break; case PROP_CHILD_Y_ALIGN: box_child_set_align (self, self->x_align, g_value_get_enum (value)); break; case PROP_CHILD_X_FILL: box_child_set_fill (self, g_value_get_boolean (value), self->y_fill); break; case PROP_CHILD_Y_FILL: box_child_set_fill (self, self->x_fill, g_value_get_boolean (value)); break; case PROP_CHILD_EXPAND: box_child_set_expand (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_box_child_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBoxChild *self = CLUTTER_BOX_CHILD (gobject); switch (prop_id) { case PROP_CHILD_X_ALIGN: g_value_set_enum (value, self->x_align); break; case PROP_CHILD_Y_ALIGN: g_value_set_enum (value, self->y_align); break; case PROP_CHILD_X_FILL: g_value_set_boolean (value, self->x_fill); break; case PROP_CHILD_Y_FILL: g_value_set_boolean (value, self->y_fill); break; case PROP_CHILD_EXPAND: g_value_set_boolean (value, self->expand); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_box_child_class_init (ClutterBoxChildClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = clutter_box_child_set_property; gobject_class->get_property = clutter_box_child_get_property; pspec = g_param_spec_boolean ("expand", P_("Expand"), P_("Allocate extra space for the child"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_EXPAND, pspec); pspec = g_param_spec_boolean ("x-fill", P_("Horizontal Fill"), P_("Whether the child should receive priority " "when the container is allocating spare space " "on the horizontal axis"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_X_FILL, pspec); pspec = g_param_spec_boolean ("y-fill", P_("Vertical Fill"), P_("Whether the child should receive priority " "when the container is allocating spare space " "on the vertical axis"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_Y_FILL, pspec); pspec = g_param_spec_enum ("x-align", P_("Horizontal Alignment"), P_("Horizontal alignment of the actor within " "the cell"), CLUTTER_TYPE_BOX_ALIGNMENT, CLUTTER_BOX_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_X_ALIGN, pspec); pspec = g_param_spec_enum ("y-align", P_("Vertical Alignment"), P_("Vertical alignment of the actor within " "the cell"), CLUTTER_TYPE_BOX_ALIGNMENT, CLUTTER_BOX_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_Y_ALIGN, pspec); } static void clutter_box_child_init (ClutterBoxChild *self) { self->x_align = CLUTTER_BOX_ALIGNMENT_CENTER; self->y_align = CLUTTER_BOX_ALIGNMENT_CENTER; self->x_fill = self->y_fill = FALSE; self->expand = FALSE; } static gdouble get_box_alignment_factor (ClutterBoxAlignment alignment) { switch (alignment) { case CLUTTER_BOX_ALIGNMENT_CENTER: return 0.5; case CLUTTER_BOX_ALIGNMENT_START: return 0.0; case CLUTTER_BOX_ALIGNMENT_END: return 1.0; } return 0.0; } static GType clutter_box_layout_get_child_meta_type (ClutterLayoutManager *manager) { return CLUTTER_TYPE_BOX_CHILD; } static void clutter_box_layout_set_container (ClutterLayoutManager *layout, ClutterContainer *container) { ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (layout)->priv; ClutterLayoutManagerClass *parent_class; priv->container = container; if (priv->container != NULL) { ClutterRequestMode request_mode; /* we need to change the :request-mode of the container * to match the orientation */ request_mode = priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH : CLUTTER_REQUEST_WIDTH_FOR_HEIGHT; clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container), request_mode); } parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_box_layout_parent_class); parent_class->set_container (layout, container); } static void get_child_size (ClutterActor *actor, ClutterOrientation orientation, gfloat for_size, gfloat *min_size_p, gfloat *natural_size_p) { if (orientation == CLUTTER_ORIENTATION_HORIZONTAL) clutter_actor_get_preferred_width (actor, for_size, min_size_p, natural_size_p); else clutter_actor_get_preferred_height (actor, for_size, min_size_p, natural_size_p); } /* Handle the request in the orientation of the box (i.e. width request of horizontal box) */ static void get_preferred_size_for_orientation (ClutterBoxLayout *self, ClutterActor *container, gfloat for_size, gfloat *min_size_p, gfloat *natural_size_p) { ClutterBoxLayoutPrivate *priv = self->priv; ClutterActorIter iter; ClutterActor *child; gint n_children = 0; gfloat minimum, natural; minimum = natural = 0; clutter_actor_iter_init (&iter, container); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_min = 0, child_nat = 0; if (!clutter_actor_is_visible (child)) continue; n_children++; get_child_size (child, priv->orientation, for_size, &child_min, &child_nat); minimum += child_min; natural += child_nat; } if (n_children > 1) { minimum += priv->spacing * (n_children - 1); natural += priv->spacing * (n_children - 1); } if (min_size_p) *min_size_p = minimum; if (natural_size_p) *natural_size_p = natural; } static void get_base_size_for_opposite_orientation (ClutterBoxLayout *self, ClutterActor *container, gfloat *min_size_p, gfloat *natural_size_p) { ClutterBoxLayoutPrivate *priv = self->priv; ClutterActorIter iter; ClutterActor *child; gint n_children = 0; gfloat minimum, natural; ClutterOrientation opposite_orientation = priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL ? CLUTTER_ORIENTATION_VERTICAL : CLUTTER_ORIENTATION_HORIZONTAL; minimum = natural = 0; clutter_actor_iter_init (&iter, container); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_min = 0, child_nat = 0; if (!clutter_actor_is_visible (child)) continue; n_children++; get_child_size (child, opposite_orientation, -1, &child_min, &child_nat); minimum = MAX (minimum, child_min); natural = MAX (natural, child_nat); } if (min_size_p) *min_size_p = minimum; if (natural_size_p) *natural_size_p = natural; } /* Handle the request in the opposite orientation of the box * (i.e. height request of horizontal box) * * This operation requires a virtual allocation in the natural * orientation of the box, after that each element must be asked * for the size-for-virtually-allocated-size and the maximums of * each child sample will be reported as the overall * "size-for-size-in-opposite-orientation" */ static void get_preferred_size_for_opposite_orientation (ClutterBoxLayout *self, ClutterActor *container, gfloat for_size, gfloat *min_size_p, gfloat *natural_size_p) { ClutterLayoutManager *layout = CLUTTER_LAYOUT_MANAGER (self); ClutterBoxLayoutPrivate *priv = self->priv; ClutterContainer *real_container = CLUTTER_CONTAINER (container); ClutterActor *child; ClutterActorIter iter; gint nvis_children = 0, n_extra_widgets = 0; gint nexpand_children = 0, i; RequestedSize *sizes; gfloat minimum, natural, size, extra = 0; ClutterOrientation opposite_orientation = priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL ? CLUTTER_ORIENTATION_VERTICAL : CLUTTER_ORIENTATION_HORIZONTAL; minimum = natural = 0; count_expand_children (layout, real_container, &nvis_children, &nexpand_children); if (nvis_children < 1) { if (min_size_p) *min_size_p = 0; if (natural_size_p) *natural_size_p = 0; return; } /* First collect the requested sizes in the natural orientation of the box */ sizes = g_newa (RequestedSize, nvis_children); size = for_size; i = 0; clutter_actor_iter_init (&iter, container); while (clutter_actor_iter_next (&iter, &child)) { if (!clutter_actor_is_visible (child)) continue; get_child_size (child, priv->orientation, -1, &sizes[i].minimum_size, &sizes[i].natural_size); size -= sizes[i].minimum_size; i++; } if (priv->is_homogeneous) { size = for_size - (nvis_children - 1) * priv->spacing; extra = size / nvis_children; n_extra_widgets = ((gint)size) % nvis_children; } else { /* Bring children up to size first */ size = distribute_natural_allocation (MAX (0, size), nvis_children, sizes); /* Calculate space which hasn't distributed yet, * and is available for expanding children. */ if (nexpand_children > 0) { extra = size / nexpand_children; n_extra_widgets = ((gint)size) % nexpand_children; } } /* Distribute expand space to children */ i = 0; clutter_actor_iter_init (&iter, container); while (clutter_actor_iter_next (&iter, &child)) { ClutterLayoutMeta *meta; ClutterBoxChild *box_child; /* If widget is not visible, skip it. */ if (!clutter_actor_is_visible (child)) continue; meta = clutter_layout_manager_get_child_meta (layout, real_container, child); box_child = CLUTTER_BOX_CHILD (meta); if (priv->is_homogeneous) { sizes[i].minimum_size = extra; if (n_extra_widgets > 0) { sizes[i].minimum_size++; n_extra_widgets--; } } else { if (clutter_actor_needs_expand (child, priv->orientation) || box_child->expand) { sizes[i].minimum_size += extra; if (n_extra_widgets > 0) { sizes[i].minimum_size++; n_extra_widgets--; } } } i++; } /* Virtual allocation finished, now we can finally ask for the right size-for-size */ i = 0; clutter_actor_iter_init (&iter, container); while (clutter_actor_iter_next (&iter, &child)) { gfloat child_min = 0, child_nat = 0; if (!clutter_actor_is_visible (child)) continue; get_child_size (child, opposite_orientation, sizes[i].minimum_size, &child_min, &child_nat); minimum = MAX (minimum, child_min); natural = MAX (natural, child_nat); i++; } if (min_size_p) *min_size_p = minimum; if (natural_size_p) *natural_size_p = natural; } static void allocate_box_child (ClutterBoxLayout *self, ClutterContainer *container, ClutterActor *child, ClutterActorBox *child_box, ClutterAllocationFlags flags) { ClutterBoxLayoutPrivate *priv = self->priv; ClutterBoxChild *box_child; ClutterLayoutMeta *meta; meta = clutter_layout_manager_get_child_meta (CLUTTER_LAYOUT_MANAGER (self), container, child); box_child = CLUTTER_BOX_CHILD (meta); CLUTTER_NOTE (LAYOUT, "Allocation for %s { %.2f, %.2f, %.2f, %.2f }", _clutter_actor_get_debug_name (child), child_box->x1, child_box->y1, child_box->x2 - child_box->x1, child_box->y2 - child_box->y1); if (priv->use_animations) { clutter_actor_save_easing_state (child); clutter_actor_set_easing_mode (child, priv->easing_mode); clutter_actor_set_easing_duration (child, priv->easing_duration); } /* call allocate() instead of allocate_align_fill() if the actor needs * expand in either direction. this will honour the actors alignment settings */ if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL) || clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL)) clutter_actor_allocate (child, child_box, flags); else clutter_actor_allocate_align_fill (child, child_box, get_box_alignment_factor (box_child->x_align), get_box_alignment_factor (box_child->y_align), box_child->x_fill, box_child->y_fill, flags); if (priv->use_animations) clutter_actor_restore_easing_state (child); } static void clutter_box_layout_get_preferred_width (ClutterLayoutManager *layout, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterBoxLayout *self = CLUTTER_BOX_LAYOUT (layout); ClutterBoxLayoutPrivate *priv = self->priv; if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL) { if (for_height < 0) get_base_size_for_opposite_orientation (self, CLUTTER_ACTOR (container), min_width_p, natural_width_p); else get_preferred_size_for_opposite_orientation (self, CLUTTER_ACTOR (container), for_height, min_width_p, natural_width_p); } else get_preferred_size_for_orientation (self, CLUTTER_ACTOR (container), for_height, min_width_p, natural_width_p); } static void clutter_box_layout_get_preferred_height (ClutterLayoutManager *layout, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterBoxLayout *self = CLUTTER_BOX_LAYOUT (layout); ClutterBoxLayoutPrivate *priv = self->priv; if (priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL) { if (for_width < 0) get_base_size_for_opposite_orientation (self, CLUTTER_ACTOR (container), min_height_p, natural_height_p); else get_preferred_size_for_opposite_orientation (self, CLUTTER_ACTOR (container), for_width, min_height_p, natural_height_p); } else get_preferred_size_for_orientation (self, CLUTTER_ACTOR (container), for_width, min_height_p, natural_height_p); } static void count_expand_children (ClutterLayoutManager *layout, ClutterContainer *container, gint *visible_children, gint *expand_children) { ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (layout)->priv; ClutterActor *actor, *child; ClutterActorIter iter; actor = CLUTTER_ACTOR (container); *visible_children = *expand_children = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { if (clutter_actor_is_visible (child)) { ClutterLayoutMeta *meta; *visible_children += 1; meta = clutter_layout_manager_get_child_meta (layout, container, child); if (clutter_actor_needs_expand (child, priv->orientation) || CLUTTER_BOX_CHILD (meta)->expand) *expand_children += 1; } } } /* Pulled from gtksizerequest.c from Gtk+ */ static gint compare_gap (gconstpointer p1, gconstpointer p2, gpointer data) { RequestedSize *sizes = data; const guint *c1 = p1; const guint *c2 = p2; const gint d1 = MAX (sizes[*c1].natural_size - sizes[*c1].minimum_size, 0); const gint d2 = MAX (sizes[*c2].natural_size - sizes[*c2].minimum_size, 0); gint delta = (d2 - d1); if (0 == delta) delta = (*c2 - *c1); return delta; } /* * distribute_natural_allocation: * @extra_space: Extra space to redistribute among children after subtracting * minimum sizes and any child padding from the overall allocation * @n_requested_sizes: Number of requests to fit into the allocation * @sizes: An array of structs with a client pointer and a minimum/natural size * in the orientation of the allocation. * * Distributes @extra_space to child @sizes by bringing smaller * children up to natural size first. * * The remaining space will be added to the @minimum_size member of the * RequestedSize struct. If all sizes reach their natural size then * the remaining space is returned. * * Returns: The remainder of @extra_space after redistributing space * to @sizes. * * Pulled from gtksizerequest.c from Gtk+ */ static gint distribute_natural_allocation (gint extra_space, guint n_requested_sizes, RequestedSize *sizes) { guint *spreading; gint i; g_return_val_if_fail (extra_space >= 0, 0); spreading = g_newa (guint, n_requested_sizes); for (i = 0; i < n_requested_sizes; i++) spreading[i] = i; /* Distribute the container's extra space c_gap. We want to assign * this space such that the sum of extra space assigned to children * (c^i_gap) is equal to c_cap. The case that there's not enough * space for all children to take their natural size needs some * attention. The goals we want to achieve are: * * a) Maximize number of children taking their natural size. * b) The allocated size of children should be a continuous * function of c_gap. That is, increasing the container size by * one pixel should never make drastic changes in the distribution. * c) If child i takes its natural size and child j doesn't, * child j should have received at least as much gap as child i. * * The following code distributes the additional space by following * these rules. */ /* Sort descending by gap and position. */ g_qsort_with_data (spreading, n_requested_sizes, sizeof (guint), compare_gap, sizes); /* Distribute available space. * This master piece of a loop was conceived by Behdad Esfahbod. */ for (i = n_requested_sizes - 1; extra_space > 0 && i >= 0; --i) { /* Divide remaining space by number of remaining children. * Sort order and reducing remaining space by assigned space * ensures that space is distributed equally. */ gint glue = (extra_space + i) / (i + 1); gint gap = sizes[(spreading[i])].natural_size - sizes[(spreading[i])].minimum_size; gint extra = MIN (glue, gap); sizes[spreading[i]].minimum_size += extra; extra_space -= extra; } return extra_space; } /* Pulled from gtkbox.c from Gtk+ */ static void clutter_box_layout_allocate (ClutterLayoutManager *layout, ClutterContainer *container, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (layout)->priv; ClutterActor *actor, *child; gint nvis_children; gint nexpand_children; gboolean is_rtl; ClutterActorIter iter; ClutterActorBox child_allocation; RequestedSize *sizes; gint size; gint extra; gint n_extra_widgets = 0; /* Number of widgets that receive 1 extra px */ gint x = 0, y = 0, i; gfloat child_size; count_expand_children (layout, container, &nvis_children, &nexpand_children); CLUTTER_NOTE (LAYOUT, "BoxLayout for %s: visible=%d, expand=%d", _clutter_actor_get_debug_name (CLUTTER_ACTOR (container)), nvis_children, nexpand_children); /* If there is no visible child, simply return. */ if (nvis_children <= 0) return; sizes = g_newa (RequestedSize, nvis_children); if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL) size = box->y2 - box->y1 - (nvis_children - 1) * priv->spacing; else size = box->x2 - box->x1 - (nvis_children - 1) * priv->spacing; actor = CLUTTER_ACTOR (container); /* Retrieve desired size for visible children. */ i = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { if (!clutter_actor_is_visible (child)) continue; if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL) clutter_actor_get_preferred_height (child, box->x2 - box->x1, &sizes[i].minimum_size, &sizes[i].natural_size); else clutter_actor_get_preferred_width (child, box->y2 - box->y1, &sizes[i].minimum_size, &sizes[i].natural_size); /* Assert the api is working properly */ if (sizes[i].minimum_size < 0) g_error ("ClutterBoxLayout child %s minimum %s: %f < 0 for %s %f", _clutter_actor_get_debug_name (child), priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? "height" : "width", sizes[i].minimum_size, priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? "width" : "height", priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? box->x2 - box->x1 : box->y2 - box->y1); if (sizes[i].natural_size < sizes[i].minimum_size) g_error ("ClutterBoxLayout child %s natural %s: %f < minimum %f for %s %f", _clutter_actor_get_debug_name (child), priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? "height" : "width", sizes[i].natural_size, sizes[i].minimum_size, priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? "width" : "height", priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? box->x2 - box->x1 : box->y2 - box->y1); size -= sizes[i].minimum_size; sizes[i].actor = child; i += 1; } if (priv->is_homogeneous) { /* If were homogenous we still need to run the above loop to get the * minimum sizes for children that are not going to fill */ if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL) size = box->y2 - box->y1 - (nvis_children - 1) * priv->spacing; else size = box->x2 - box->x1 - (nvis_children - 1) * priv->spacing; extra = size / nvis_children; n_extra_widgets = size % nvis_children; } else { /* Bring children up to size first */ size = distribute_natural_allocation (MAX (0, size), nvis_children, sizes); /* Calculate space which hasn't distributed yet, * and is available for expanding children. */ if (nexpand_children > 0) { extra = size / nexpand_children; n_extra_widgets = size % nexpand_children; } else extra = 0; } if (priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL) { ClutterTextDirection text_dir; text_dir = clutter_actor_get_text_direction (CLUTTER_ACTOR (container)); is_rtl = (text_dir == CLUTTER_TEXT_DIRECTION_RTL) ? TRUE : FALSE; } else is_rtl = FALSE; /* Allocate child positions. */ if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL) { child_allocation.x1 = box->x1; child_allocation.x2 = MAX (1.0, box->x2); if (priv->is_pack_start) y = box->y2 - box->y1; else y = box->y1; } else { child_allocation.y1 = box->y1; child_allocation.y2 = MAX (1.0, box->y2); if (priv->is_pack_start) x = box->x2 - box->x1; else x = box->x1; } i = 0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { ClutterLayoutMeta *meta; ClutterBoxChild *box_child; /* If widget is not visible, skip it. */ if (!clutter_actor_is_visible (child)) continue; meta = clutter_layout_manager_get_child_meta (layout, container, child); box_child = CLUTTER_BOX_CHILD (meta); /* Assign the child's size. */ if (priv->is_homogeneous) { child_size = extra; if (n_extra_widgets > 0) { child_size++; n_extra_widgets--; } } else { child_size = sizes[i].minimum_size; if (clutter_actor_needs_expand (child, priv->orientation) || box_child->expand) { child_size += extra; if (n_extra_widgets > 0) { child_size++; n_extra_widgets--; } } } /* Assign the child's position. */ if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL) { if (clutter_actor_needs_expand (child, priv->orientation) || box_child->expand) { child_allocation.y1 = y; child_allocation.y2 = child_allocation.y1 + MAX (1.0, child_size); } else { child_allocation.y1 = y + (child_size - sizes[i].minimum_size) / 2; child_allocation.y2 = child_allocation.y1 + sizes[i].minimum_size; } if (priv->is_pack_start) { y -= child_size + priv->spacing; child_allocation.y1 -= child_size; child_allocation.y2 -= child_size; } else { y += child_size + priv->spacing; } } else /* CLUTTER_ORIENTATION_HORIZONTAL */ { if (clutter_actor_needs_expand (child, priv->orientation) || box_child->expand) { child_allocation.x1 = x; child_allocation.x2 = child_allocation.x1 + MAX (1.0, child_size); } else { child_allocation.x1 = x + (child_size - sizes[i].minimum_size) / 2; child_allocation.x2 = child_allocation.x1 + sizes[i].minimum_size; } if (priv->is_pack_start) { x -= child_size + priv->spacing; child_allocation.x1 -= child_size; child_allocation.x2 -= child_size; } else { x += child_size + priv->spacing; } if (is_rtl) { gfloat width = child_allocation.x2 - child_allocation.x1; child_allocation.x2 = box->x1 + (box->x2 - child_allocation.x1); child_allocation.x1 = child_allocation.x2 - width; } } allocate_box_child (CLUTTER_BOX_LAYOUT (layout), container, child, &child_allocation, flags); i += 1; } } static void clutter_box_layout_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBoxLayout *self = CLUTTER_BOX_LAYOUT (gobject); switch (prop_id) { case PROP_VERTICAL: clutter_box_layout_set_vertical (self, g_value_get_boolean (value)); break; case PROP_ORIENTATION: clutter_box_layout_set_orientation (self, g_value_get_enum (value)); break; case PROP_HOMOGENEOUS: clutter_box_layout_set_homogeneous (self, g_value_get_boolean (value)); break; case PROP_SPACING: clutter_box_layout_set_spacing (self, g_value_get_uint (value)); break; case PROP_PACK_START: clutter_box_layout_set_pack_start (self, g_value_get_boolean (value)); break; case PROP_USE_ANIMATIONS: clutter_box_layout_set_use_animations (self, g_value_get_boolean (value)); break; case PROP_EASING_MODE: clutter_box_layout_set_easing_mode (self, g_value_get_ulong (value)); break; case PROP_EASING_DURATION: clutter_box_layout_set_easing_duration (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_box_layout_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (gobject)->priv; switch (prop_id) { case PROP_VERTICAL: g_value_set_boolean (value, priv->orientation == CLUTTER_ORIENTATION_VERTICAL); break; case PROP_ORIENTATION: g_value_set_enum (value, priv->orientation); break; case PROP_HOMOGENEOUS: g_value_set_boolean (value, priv->is_homogeneous); break; case PROP_SPACING: g_value_set_uint (value, priv->spacing); break; case PROP_PACK_START: g_value_set_boolean (value, priv->is_pack_start); break; case PROP_USE_ANIMATIONS: g_value_set_boolean (value, priv->use_animations); break; case PROP_EASING_MODE: g_value_set_ulong (value, priv->easing_mode); break; case PROP_EASING_DURATION: g_value_set_uint (value, priv->easing_duration); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_box_layout_class_init (ClutterBoxLayoutClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterLayoutManagerClass *layout_class; layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass); layout_class->get_preferred_width = clutter_box_layout_get_preferred_width; layout_class->get_preferred_height = clutter_box_layout_get_preferred_height; layout_class->allocate = clutter_box_layout_allocate; layout_class->set_container = clutter_box_layout_set_container; layout_class->get_child_meta_type = clutter_box_layout_get_child_meta_type; /** * ClutterBoxLayout:vertical: * * Whether the #ClutterBoxLayout should arrange its children * alongside the Y axis, instead of alongside the X axis * * Since: 1.2 * * Deprecated: 1.12: Use #ClutterBoxLayout:orientation instead. */ obj_props[PROP_VERTICAL] = g_param_spec_boolean ("vertical", P_("Vertical"), P_("Whether the layout should be vertical, " "rather than horizontal"), FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterBoxLayout:orientation: * * The orientation of the #ClutterBoxLayout, either horizontal * or vertical * * Since: 1.12 */ obj_props[PROP_ORIENTATION] = g_param_spec_enum ("orientation", P_("Orientation"), P_("The orientation of the layout"), CLUTTER_TYPE_ORIENTATION, CLUTTER_ORIENTATION_HORIZONTAL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterBoxLayout:homogeneous: * * Whether the #ClutterBoxLayout should arrange its children * homogeneously, i.e. all children get the same size * * Since: 1.4 */ obj_props[PROP_HOMOGENEOUS] = g_param_spec_boolean ("homogeneous", P_("Homogeneous"), P_("Whether the layout should be homogeneous, " "i.e. all children get the same size"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterBoxLayout:pack-start: * * Whether the #ClutterBoxLayout should pack items at the start * or append them at the end * * Since: 1.2 */ obj_props[PROP_PACK_START] = g_param_spec_boolean ("pack-start", P_("Pack Start"), P_("Whether to pack items at the start of the box"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterBoxLayout:spacing: * * The spacing between children of the #ClutterBoxLayout, in pixels * * Since: 1.2 */ obj_props[PROP_SPACING] = g_param_spec_uint ("spacing", P_("Spacing"), P_("Spacing between children"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterBoxLayout:use-animations: * * Whether the #ClutterBoxLayout should animate changes in the * layout, overriding the easing state of the children. * * Since: 1.2 * * Deprecated: 1.12: #ClutterBoxLayout will honour the easing state * of the children when allocating them. */ obj_props[PROP_USE_ANIMATIONS] = g_param_spec_boolean ("use-animations", P_("Use Animations"), P_("Whether layout changes should be animated"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterBoxLayout:easing-mode: * * The easing mode for the animations, in case * #ClutterBoxLayout:use-animations is set to %TRUE. * * The easing mode has the same semantics of #ClutterAnimation:mode: it can * either be a value from the #ClutterAnimationMode enumeration, like * %CLUTTER_EASE_OUT_CUBIC, or a logical id as returned by * clutter_alpha_register_func(). * * The default value is %CLUTTER_EASE_OUT_CUBIC. * * Since: 1.2 * * Deprecated: 1.12: The #ClutterBoxLayout will honour the easing state of * the children when allocating them. */ obj_props[PROP_EASING_MODE] = g_param_spec_ulong ("easing-mode", P_("Easing Mode"), P_("The easing mode of the animations"), 0, G_MAXULONG, CLUTTER_EASE_OUT_CUBIC, CLUTTER_PARAM_READWRITE); /** * ClutterBoxLayout:easing-duration: * * The duration of the animations, in case #ClutterBoxLayout:use-animations * is set to %TRUE. * * The duration is expressed in milliseconds. * * Since: 1.2 * * Deprecated: 1.12: The #ClutterBoxLayout will honour the easing state of * the children when allocating them. */ obj_props[PROP_EASING_DURATION] = g_param_spec_uint ("easing-duration", P_("Easing Duration"), P_("The duration of the animations"), 0, G_MAXUINT, 500, CLUTTER_PARAM_READWRITE); gobject_class->set_property = clutter_box_layout_set_property; gobject_class->get_property = clutter_box_layout_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_box_layout_init (ClutterBoxLayout *self) { self->priv = clutter_box_layout_get_instance_private (self); self->priv->orientation = CLUTTER_ORIENTATION_HORIZONTAL; self->priv->is_homogeneous = FALSE; self->priv->is_pack_start = FALSE; self->priv->spacing = 0; self->priv->use_animations = FALSE; self->priv->easing_mode = CLUTTER_EASE_OUT_CUBIC; self->priv->easing_duration = 500; } /** * clutter_box_layout_new: * * Creates a new #ClutterBoxLayout layout manager * * Return value: the newly created #ClutterBoxLayout * * Since: 1.2 */ ClutterLayoutManager * clutter_box_layout_new (void) { return g_object_new (CLUTTER_TYPE_BOX_LAYOUT, NULL); } /** * clutter_box_layout_set_spacing: * @layout: a #ClutterBoxLayout * @spacing: the spacing between children of the layout, in pixels * * Sets the spacing between children of @layout * * Since: 1.2 */ void clutter_box_layout_set_spacing (ClutterBoxLayout *layout, guint spacing) { ClutterBoxLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); priv = layout->priv; if (priv->spacing != spacing) { ClutterLayoutManager *manager; priv->spacing = spacing; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify (G_OBJECT (layout), "spacing"); } } /** * clutter_box_layout_get_spacing: * @layout: a #ClutterBoxLayout * * Retrieves the spacing set using clutter_box_layout_set_spacing() * * Return value: the spacing between children of the #ClutterBoxLayout * * Since: 1.2 */ guint clutter_box_layout_get_spacing (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), 0); return layout->priv->spacing; } /** * clutter_box_layout_set_vertical: * @layout: a #ClutterBoxLayout * @vertical: %TRUE if the layout should be vertical * * Sets whether @layout should arrange its children vertically alongside * the Y axis, instead of horizontally alongside the X axis * * Since: 1.2 * * Deprecated: 1.12: Use clutter_box_layout_set_orientation() instead. */ void clutter_box_layout_set_vertical (ClutterBoxLayout *layout, gboolean vertical) { ClutterOrientation new_orientation, old_orientation; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); old_orientation = layout->priv->orientation; new_orientation = vertical ? CLUTTER_ORIENTATION_VERTICAL : CLUTTER_ORIENTATION_HORIZONTAL; clutter_box_layout_set_orientation (layout, new_orientation); if (old_orientation != new_orientation) g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_VERTICAL]); } /** * clutter_box_layout_set_orientation: * @layout: a #ClutterBoxLayout * @orientation: the orientation of the #ClutterBoxLayout * * Sets the orientation of the #ClutterBoxLayout layout manager. * * Since: 1.12 */ void clutter_box_layout_set_orientation (ClutterBoxLayout *layout, ClutterOrientation orientation) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); priv = layout->priv; if (priv->orientation == orientation) return; priv->orientation = orientation; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_ORIENTATION]); } /** * clutter_box_layout_get_vertical: * @layout: a #ClutterBoxLayout * * Retrieves the orientation of the @layout as set using the * clutter_box_layout_set_vertical() function * * Return value: %TRUE if the #ClutterBoxLayout is arranging its children * vertically, and %FALSE otherwise * * Since: 1.2 * * Deprecated: 1.12: Use clutter_box_layout_get_orientation() instead */ gboolean clutter_box_layout_get_vertical (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE); return layout->priv->orientation == CLUTTER_ORIENTATION_VERTICAL; } /** * clutter_box_layout_get_orientation: * @layout: a #ClutterBoxLayout * * Retrieves the orientation of the @layout. * * Return value: the orientation of the layout * * Since: 1.12 */ ClutterOrientation clutter_box_layout_get_orientation (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), CLUTTER_ORIENTATION_HORIZONTAL); return layout->priv->orientation; } /** * clutter_box_layout_set_homogeneous: * @layout: a #ClutterBoxLayout * @homogeneous: %TRUE if the layout should be homogeneous * * Sets whether the size of @layout children should be * homogeneous * * Since: 1.4 */ void clutter_box_layout_set_homogeneous (ClutterBoxLayout *layout, gboolean homogeneous) { ClutterBoxLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); priv = layout->priv; if (priv->is_homogeneous != homogeneous) { ClutterLayoutManager *manager; priv->is_homogeneous = !!homogeneous; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify (G_OBJECT (layout), "homogeneous"); } } /** * clutter_box_layout_get_homogeneous: * @layout: a #ClutterBoxLayout * * Retrieves if the children sizes are allocated homogeneously. * * Return value: %TRUE if the #ClutterBoxLayout is arranging its children * homogeneously, and %FALSE otherwise * * Since: 1.4 */ gboolean clutter_box_layout_get_homogeneous (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE); return layout->priv->is_homogeneous; } /** * clutter_box_layout_set_pack_start: * @layout: a #ClutterBoxLayout * @pack_start: %TRUE if the @layout should pack children at the * beginning of the layout * * Sets whether children of @layout should be layed out by appending * them or by prepending them * * Since: 1.2 */ void clutter_box_layout_set_pack_start (ClutterBoxLayout *layout, gboolean pack_start) { ClutterBoxLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); priv = layout->priv; if (priv->is_pack_start != pack_start) { ClutterLayoutManager *manager; priv->is_pack_start = pack_start ? TRUE : FALSE; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify (G_OBJECT (layout), "pack-start"); } } /** * clutter_box_layout_get_pack_start: * @layout: a #ClutterBoxLayout * * Retrieves the value set using clutter_box_layout_set_pack_start() * * Return value: %TRUE if the #ClutterBoxLayout should pack children * at the beginning of the layout, and %FALSE otherwise * * Since: 1.2 */ gboolean clutter_box_layout_get_pack_start (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE); return layout->priv->is_pack_start; } /** * clutter_box_layout_pack: * @layout: a #ClutterBoxLayout * @actor: a #ClutterActor * @expand: whether the @actor should expand * @x_fill: whether the @actor should fill horizontally * @y_fill: whether the @actor should fill vertically * @x_align: the horizontal alignment policy for @actor * @y_align: the vertical alignment policy for @actor * * Packs @actor inside the #ClutterContainer associated to @layout * and sets the layout properties * * Since: 1.2 * Deprecated: 1.12: #ClutterBoxLayout honours #ClutterActor's * align and expand properties. The preferred way is adding * the @actor with clutter_actor_add_child() and setting * #ClutterActor:x-align, #ClutterActor:y-align, * #ClutterActor:x-expand and #ClutterActor:y-expand */ void clutter_box_layout_pack (ClutterBoxLayout *layout, ClutterActor *actor, gboolean expand, gboolean x_fill, gboolean y_fill, ClutterBoxAlignment x_align, ClutterBoxAlignment y_align) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before adding children", G_OBJECT_TYPE_NAME (layout)); return; } clutter_container_add_actor (priv->container, actor); manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); g_assert (CLUTTER_IS_BOX_CHILD (meta)); box_child_set_align (CLUTTER_BOX_CHILD (meta), x_align, y_align); box_child_set_fill (CLUTTER_BOX_CHILD (meta), x_fill, y_fill); box_child_set_expand (CLUTTER_BOX_CHILD (meta), expand); } /** * clutter_box_layout_set_alignment: * @layout: a #ClutterBoxLayout * @actor: a #ClutterActor child of @layout * @x_align: Horizontal alignment policy for @actor * @y_align: Vertical alignment policy for @actor * * Sets the horizontal and vertical alignment policies for @actor * inside @layout * * Since: 1.2 * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's * #ClutterActor:x-align and #ClutterActor:y-align properies */ void clutter_box_layout_set_alignment (ClutterBoxLayout *layout, ClutterActor *actor, ClutterBoxAlignment x_align, ClutterBoxAlignment y_align) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_BOX_CHILD (meta)); box_child_set_align (CLUTTER_BOX_CHILD (meta), x_align, y_align); } /** * clutter_box_layout_get_alignment: * @layout: a #ClutterBoxLayout * @actor: a #ClutterActor child of @layout * @x_align: (out): return location for the horizontal alignment policy * @y_align: (out): return location for the vertical alignment policy * * Retrieves the horizontal and vertical alignment policies for @actor * as set using clutter_box_layout_pack() or clutter_box_layout_set_alignment() * * Since: 1.2 * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's * #ClutterActor:x-align and #ClutterActor:y-align properies */ void clutter_box_layout_get_alignment (ClutterBoxLayout *layout, ClutterActor *actor, ClutterBoxAlignment *x_align, ClutterBoxAlignment *y_align) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_BOX_CHILD (meta)); if (x_align) *x_align = CLUTTER_BOX_CHILD (meta)->x_align; if (y_align) *y_align = CLUTTER_BOX_CHILD (meta)->y_align; } /** * clutter_box_layout_set_fill: * @layout: a #ClutterBoxLayout * @actor: a #ClutterActor child of @layout * @x_fill: whether @actor should fill horizontally the allocated space * @y_fill: whether @actor should fill vertically the allocated space * * Sets the horizontal and vertical fill policies for @actor * inside @layout * * Since: 1.2 * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's * #ClutterActor:x-align and #ClutterActor:y-align properies */ void clutter_box_layout_set_fill (ClutterBoxLayout *layout, ClutterActor *actor, gboolean x_fill, gboolean y_fill) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_BOX_CHILD (meta)); box_child_set_fill (CLUTTER_BOX_CHILD (meta), x_fill, y_fill); } /** * clutter_box_layout_get_fill: * @layout: a #ClutterBoxLayout * @actor: a #ClutterActor child of @layout * @x_fill: (out): return location for the horizontal fill policy * @y_fill: (out): return location for the vertical fill policy * * Retrieves the horizontal and vertical fill policies for @actor * as set using clutter_box_layout_pack() or clutter_box_layout_set_fill() * * Since: 1.2 * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's * #ClutterActor:x-align and #ClutterActor:y-align properies */ void clutter_box_layout_get_fill (ClutterBoxLayout *layout, ClutterActor *actor, gboolean *x_fill, gboolean *y_fill) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_BOX_CHILD (meta)); if (x_fill) *x_fill = CLUTTER_BOX_CHILD (meta)->x_fill; if (y_fill) *y_fill = CLUTTER_BOX_CHILD (meta)->y_fill; } /** * clutter_box_layout_set_expand: * @layout: a #ClutterBoxLayout * @actor: a #ClutterActor child of @layout * @expand: whether @actor should expand * * Sets whether @actor should expand inside @layout * * Since: 1.2 * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's * #ClutterActor:x-expand and #ClutterActor:y-expand properies */ void clutter_box_layout_set_expand (ClutterBoxLayout *layout, ClutterActor *actor, gboolean expand) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_BOX_CHILD (meta)); box_child_set_expand (CLUTTER_BOX_CHILD (meta), expand); } /** * clutter_box_layout_get_expand: * @layout: a #ClutterBoxLayout * @actor: a #ClutterActor child of @layout * * Retrieves whether @actor should expand inside @layout * * Return value: %TRUE if the #ClutterActor should expand, %FALSE otherwise * * Since: 1.2 * Deprecated: 1.12: #ClutterBoxLayout will honour #ClutterActor's * #ClutterActor:x-expand and #ClutterActor:y-expand properies */ gboolean clutter_box_layout_get_expand (ClutterBoxLayout *layout, ClutterActor *actor) { ClutterBoxLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return FALSE; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return FALSE; } g_assert (CLUTTER_IS_BOX_CHILD (meta)); return CLUTTER_BOX_CHILD (meta)->expand; } /** * clutter_box_layout_set_use_animations: * @layout: a #ClutterBoxLayout * @animate: %TRUE if the @layout should use animations * * Sets whether @layout should animate changes in the layout properties * * The duration of the animations is controlled by * clutter_box_layout_set_easing_duration(); the easing mode to be used * by the animations is controlled by clutter_box_layout_set_easing_mode(). * * Enabling animations will override the easing state of each child * of the actor using @layout, and will use the #ClutterBoxLayout:easing-mode * and #ClutterBoxLayout:easing-duration properties instead. * * Since: 1.2 * * Deprecated: 1.12: The layout manager will honour the easing state * of the children when allocating them. */ void clutter_box_layout_set_use_animations (ClutterBoxLayout *layout, gboolean animate) { ClutterBoxLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); priv = layout->priv; if (priv->use_animations != animate) { priv->use_animations = animate; g_object_notify (G_OBJECT (layout), "use-animations"); } } /** * clutter_box_layout_get_use_animations: * @layout: a #ClutterBoxLayout * * Retrieves whether @layout should animate changes in the layout properties. * * Return value: %TRUE if the animations should be used, %FALSE otherwise * * Since: 1.2 * * Deprecated: 1.12 */ gboolean clutter_box_layout_get_use_animations (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE); return layout->priv->use_animations; } /** * clutter_box_layout_set_easing_mode: * @layout: a #ClutterBoxLayout * @mode: an easing mode, either from #ClutterAnimationMode or a logical id * from clutter_alpha_register_func() * * Sets the easing mode to be used by @layout when animating changes in layout * properties. * * Since: 1.2 * * Deprecated: 1.12: The layout manager will honour the easing state * of the children when allocating them. */ void clutter_box_layout_set_easing_mode (ClutterBoxLayout *layout, gulong mode) { ClutterBoxLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); priv = layout->priv; if (priv->easing_mode != mode) { priv->easing_mode = mode; g_object_notify (G_OBJECT (layout), "easing-mode"); } } /** * clutter_box_layout_get_easing_mode: * @layout: a #ClutterBoxLayout * * Retrieves the easing mode set using clutter_box_layout_set_easing_mode() * * Return value: an easing mode * * Since: 1.2 * * Deprecated: 1.12 */ gulong clutter_box_layout_get_easing_mode (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), CLUTTER_EASE_OUT_CUBIC); return layout->priv->easing_mode; } /** * clutter_box_layout_set_easing_duration: * @layout: a #ClutterBoxLayout * @msecs: the duration of the animations, in milliseconds * * Sets the duration of the animations used by @layout when animating changes * in the layout properties. * * Since: 1.2 * * Deprecated: 1.12: The layout manager will honour the easing state * of the children when allocating them. */ void clutter_box_layout_set_easing_duration (ClutterBoxLayout *layout, guint msecs) { ClutterBoxLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout)); priv = layout->priv; if (priv->easing_duration != msecs) { priv->easing_duration = msecs; g_object_notify (G_OBJECT (layout), "easing-duration"); } } /** * clutter_box_layout_get_easing_duration: * @layout: a #ClutterBoxLayout * * Retrieves the duration set using clutter_box_layout_set_easing_duration() * * Return value: the duration of the animations, in milliseconds * * Since: 1.2 * * Deprecated: 1.12 */ guint clutter_box_layout_get_easing_duration (ClutterBoxLayout *layout) { g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), 500); return layout->priv->easing_duration; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-bind-constraint.c����������������������������������������������0000664�0001750�0001750�00000043337�14211404421�023234� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-bind-constraint * @Title: ClutterBindConstraint * @Short_Description: A constraint binding the position or size of an actor * * #ClutterBindConstraint is a #ClutterConstraint that binds the * position or the size of the #ClutterActor to which it is applied * to the the position or the size of another #ClutterActor, or * "source". * * An offset can be applied to the constraint, to avoid overlapping. The offset * can also be animated. For instance, the following code will set up three * actors to be bound to the same origin: * * |[<!-- language="C" --> * // source * rect[0] = clutter_rectangle_new_with_color (&red_color); * clutter_actor_set_position (rect[0], x_pos, y_pos); * clutter_actor_set_size (rect[0], 100, 100); * * // second rectangle * rect[1] = clutter_rectangle_new_with_color (&green_color); * clutter_actor_set_size (rect[1], 100, 100); * clutter_actor_set_opacity (rect[1], 0); * * constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_X, 0.0); * clutter_actor_add_constraint_with_name (rect[1], "green-x", constraint); * constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_Y, 0.0); * clutter_actor_add_constraint_with_name (rect[1], "green-y", constraint); * * // third rectangle * rect[2] = clutter_rectangle_new_with_color (&blue_color); * clutter_actor_set_size (rect[2], 100, 100); * clutter_actor_set_opacity (rect[2], 0); * * constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_X, 0.0); * clutter_actor_add_constraint_with_name (rect[2], "blue-x", constraint); * constraint = clutter_bind_constraint_new (rect[0], CLUTTER_BIND_Y, 0.0); * clutter_actor_add_constraint_with_name (rect[2], "blue-y", constraint); * ]| * * The following code animates the second and third rectangles to "expand" * them horizontally from underneath the first rectangle: * * |[<!-- language="C" --> * clutter_actor_animate (rect[1], CLUTTER_EASE_OUT_CUBIC, 250, * "@constraints.green-x.offset", 100.0, * "opacity", 255, * NULL); * clutter_actor_animate (rect[2], CLUTTER_EASE_OUT_CUBIC, 250, * "@constraints.blue-x.offset", 200.0, * "opacity", 255, * NULL); * ]| * * #ClutterBindConstraint is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter-bind-constraint.h" #include "clutter-actor-meta-private.h" #include "clutter-actor-private.h" #include "clutter-constraint.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-private.h" #define CLUTTER_BIND_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraintClass)) #define CLUTTER_IS_BIND_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BIND_CONSTRAINT)) #define CLUTTER_BIND_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraintClass)) struct _ClutterBindConstraint { ClutterConstraint parent_instance; ClutterActor *actor; ClutterActor *source; ClutterBindCoordinate coordinate; gfloat offset; }; struct _ClutterBindConstraintClass { ClutterConstraintClass parent_class; }; enum { PROP_0, PROP_SOURCE, PROP_COORDINATE, PROP_OFFSET, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterBindConstraint, clutter_bind_constraint, CLUTTER_TYPE_CONSTRAINT); static void source_queue_relayout (ClutterActor *source, ClutterBindConstraint *bind) { if (bind->actor != NULL) _clutter_actor_queue_only_relayout (bind->actor); } static void source_destroyed (ClutterActor *actor, ClutterBindConstraint *bind) { bind->source = NULL; } static void clutter_bind_constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation) { ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (constraint); gfloat source_width, source_height; gfloat actor_width, actor_height; ClutterVertex source_position = { 0., }; if (bind->source == NULL) return; source_position.x = clutter_actor_get_x (bind->source); source_position.y = clutter_actor_get_y (bind->source); clutter_actor_get_size (bind->source, &source_width, &source_height); clutter_actor_box_get_size (allocation, &actor_width, &actor_height); switch (bind->coordinate) { case CLUTTER_BIND_X: allocation->x1 = source_position.x + bind->offset; allocation->x2 = allocation->x1 + actor_width; break; case CLUTTER_BIND_Y: allocation->y1 = source_position.y + bind->offset; allocation->y2 = allocation->y1 + actor_height; break; case CLUTTER_BIND_POSITION: allocation->x1 = source_position.x + bind->offset; allocation->y1 = source_position.y + bind->offset; allocation->x2 = allocation->x1 + actor_width; allocation->y2 = allocation->y1 + actor_height; break; case CLUTTER_BIND_WIDTH: allocation->x2 = allocation->x1 + source_width + bind->offset; break; case CLUTTER_BIND_HEIGHT: allocation->y2 = allocation->y1 + source_height + bind->offset; break; case CLUTTER_BIND_SIZE: allocation->x2 = allocation->x1 + source_width + bind->offset; allocation->y2 = allocation->y1 + source_height + bind->offset; break; case CLUTTER_BIND_ALL: allocation->x1 = source_position.x + bind->offset; allocation->y1 = source_position.y + bind->offset; allocation->x2 = allocation->x1 + source_width + bind->offset; allocation->y2 = allocation->y1 + source_height + bind->offset; break; default: g_assert_not_reached (); break; } clutter_actor_box_clamp_to_pixel (allocation); } static void clutter_bind_constraint_set_actor (ClutterActorMeta *meta, ClutterActor *new_actor) { ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (meta); ClutterActorMetaClass *parent; if (new_actor != NULL && bind->source != NULL && clutter_actor_contains (new_actor, bind->source)) { g_warning (G_STRLOC ": The source actor '%s' is contained " "by the actor '%s' associated to the constraint " "'%s'", _clutter_actor_get_debug_name (bind->source), _clutter_actor_get_debug_name (new_actor), _clutter_actor_meta_get_debug_name (meta)); return; } /* store the pointer to the actor, for later use */ bind->actor = new_actor; parent = CLUTTER_ACTOR_META_CLASS (clutter_bind_constraint_parent_class); parent->set_actor (meta, new_actor); } static void clutter_bind_constraint_dispose (GObject *gobject) { ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (gobject); if (bind->source != NULL) { g_signal_handlers_disconnect_by_func (bind->source, G_CALLBACK (source_destroyed), bind); g_signal_handlers_disconnect_by_func (bind->source, G_CALLBACK (source_queue_relayout), bind); bind->source = NULL; } G_OBJECT_CLASS (clutter_bind_constraint_parent_class)->dispose (gobject); } static void clutter_bind_constraint_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (gobject); switch (prop_id) { case PROP_SOURCE: clutter_bind_constraint_set_source (bind, g_value_get_object (value)); break; case PROP_COORDINATE: clutter_bind_constraint_set_coordinate (bind, g_value_get_enum (value)); break; case PROP_OFFSET: clutter_bind_constraint_set_offset (bind, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_bind_constraint_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (gobject); switch (prop_id) { case PROP_SOURCE: g_value_set_object (value, bind->source); break; case PROP_COORDINATE: g_value_set_enum (value, bind->coordinate); break; case PROP_OFFSET: g_value_set_float (value, bind->offset); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_bind_constraint_class_init (ClutterBindConstraintClass *klass) { ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); ClutterConstraintClass *constraint_class = CLUTTER_CONSTRAINT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_bind_constraint_set_property; gobject_class->get_property = clutter_bind_constraint_get_property; gobject_class->dispose = clutter_bind_constraint_dispose; meta_class->set_actor = clutter_bind_constraint_set_actor; constraint_class->update_allocation = clutter_bind_constraint_update_allocation; /** * ClutterBindConstraint:source: * * The #ClutterActor used as the source for the binding. * * The #ClutterActor must not be contained inside the actor associated * to the constraint. * * Since: 1.4 */ obj_props[PROP_SOURCE] = g_param_spec_object ("source", P_("Source"), P_("The source of the binding"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterBindConstraint:coordinate: * * The coordinate to be bound * * Since: 1.4 */ obj_props[PROP_COORDINATE] = g_param_spec_enum ("coordinate", P_("Coordinate"), P_("The coordinate to bind"), CLUTTER_TYPE_BIND_COORDINATE, CLUTTER_BIND_X, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterBindConstraint:offset: * * The offset, in pixels, to be applied to the binding * * Since: 1.4 */ obj_props[PROP_OFFSET] = g_param_spec_float ("offset", P_("Offset"), P_("The offset in pixels to apply to the binding"), -G_MAXFLOAT, G_MAXFLOAT, 0.0f, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_bind_constraint_init (ClutterBindConstraint *self) { self->actor = NULL; self->source = NULL; self->coordinate = CLUTTER_BIND_X; self->offset = 0.0f; } /** * clutter_bind_constraint_new: * @source: (allow-none): the #ClutterActor to use as the source of * the binding, or %NULL * @coordinate: the coordinate to bind * @offset: the offset to apply to the binding, in pixels * * Creates a new constraint, binding a #ClutterActor's position to * the given @coordinate of the position of @source * * Return value: the newly created #ClutterBindConstraint * * Since: 1.4 */ ClutterConstraint * clutter_bind_constraint_new (ClutterActor *source, ClutterBindCoordinate coordinate, gfloat offset) { g_return_val_if_fail (source == NULL || CLUTTER_IS_ACTOR (source), NULL); return g_object_new (CLUTTER_TYPE_BIND_CONSTRAINT, "source", source, "coordinate", coordinate, "offset", offset, NULL); } /** * clutter_bind_constraint_set_source: * @constraint: a #ClutterBindConstraint * @source: (allow-none): a #ClutterActor, or %NULL to unset the source * * Sets the source #ClutterActor for the constraint * * Since: 1.4 */ void clutter_bind_constraint_set_source (ClutterBindConstraint *constraint, ClutterActor *source) { ClutterActor *old_source, *actor; ClutterActorMeta *meta; g_return_if_fail (CLUTTER_IS_BIND_CONSTRAINT (constraint)); g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source)); if (constraint->source == source) return; meta = CLUTTER_ACTOR_META (constraint); actor = clutter_actor_meta_get_actor (meta); if (source != NULL && actor != NULL) { if (clutter_actor_contains (actor, source)) { g_warning (G_STRLOC ": The source actor '%s' is contained " "by the actor '%s' associated to the constraint " "'%s'", _clutter_actor_get_debug_name (source), _clutter_actor_get_debug_name (actor), _clutter_actor_meta_get_debug_name (meta)); return; } } old_source = constraint->source; if (old_source != NULL) { g_signal_handlers_disconnect_by_func (old_source, G_CALLBACK (source_destroyed), constraint); g_signal_handlers_disconnect_by_func (old_source, G_CALLBACK (source_queue_relayout), constraint); } constraint->source = source; if (constraint->source != NULL) { g_signal_connect (constraint->source, "queue-relayout", G_CALLBACK (source_queue_relayout), constraint); g_signal_connect (constraint->source, "destroy", G_CALLBACK (source_destroyed), constraint); if (constraint->actor != NULL) clutter_actor_queue_relayout (constraint->actor); } g_object_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_SOURCE]); } /** * clutter_bind_constraint_get_source: * @constraint: a #ClutterBindConstraint * * Retrieves the #ClutterActor set using clutter_bind_constraint_set_source() * * Return value: (transfer none): a pointer to the source actor * * Since: 1.4 */ ClutterActor * clutter_bind_constraint_get_source (ClutterBindConstraint *constraint) { g_return_val_if_fail (CLUTTER_IS_BIND_CONSTRAINT (constraint), NULL); return constraint->source; } /** * clutter_bind_constraint_set_coordinate: * @constraint: a #ClutterBindConstraint * @coordinate: the coordinate to bind * * Sets the coordinate to bind in the constraint * * Since: 1.4 */ void clutter_bind_constraint_set_coordinate (ClutterBindConstraint *constraint, ClutterBindCoordinate coordinate) { g_return_if_fail (CLUTTER_IS_BIND_CONSTRAINT (constraint)); if (constraint->coordinate == coordinate) return; constraint->coordinate = coordinate; if (constraint->actor != NULL) clutter_actor_queue_relayout (constraint->actor); g_object_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_COORDINATE]); } /** * clutter_bind_constraint_get_coordinate: * @constraint: a #ClutterBindConstraint * * Retrieves the bound coordinate of the constraint * * Return value: the bound coordinate * * Since: 1.4 */ ClutterBindCoordinate clutter_bind_constraint_get_coordinate (ClutterBindConstraint *constraint) { g_return_val_if_fail (CLUTTER_IS_BIND_CONSTRAINT (constraint), CLUTTER_BIND_X); return constraint->coordinate; } /** * clutter_bind_constraint_set_offset: * @constraint: a #ClutterBindConstraint * @offset: the offset to apply, in pixels * * Sets the offset to be applied to the constraint * * Since: 1.4 */ void clutter_bind_constraint_set_offset (ClutterBindConstraint *constraint, gfloat offset) { g_return_if_fail (CLUTTER_IS_BIND_CONSTRAINT (constraint)); if (fabs (constraint->offset - offset) < 0.00001f) return; constraint->offset = offset; if (constraint->actor != NULL) clutter_actor_queue_relayout (constraint->actor); g_object_notify_by_pspec (G_OBJECT (constraint), obj_props[PROP_OFFSET]); } /** * clutter_bind_constraint_get_offset: * @constraint: a #ClutterBindConstraint * * Retrieves the offset set using clutter_bind_constraint_set_offset() * * Return value: the offset, in pixels * * Since: 1.4 */ gfloat clutter_bind_constraint_get_offset (ClutterBindConstraint *bind) { g_return_val_if_fail (CLUTTER_IS_BIND_CONSTRAINT (bind), 0.0); return bind->offset; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-easing.h�������������������������������������������������������0000664�0001750�0001750�00000012270�14211404421�021401� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_EASING_H__ #define __CLUTTER_EASING_H__ #include <clutter/clutter-types.h> G_BEGIN_DECLS /*< private > * ClutterEasingFunc: * @t: elapsed time * @d: total duration * * Internal type for the easing functions used by Clutter. * * Return value: the interpolated value, between -1.0 and 2.0 */ typedef double (* ClutterEasingFunc) (double t, double d); G_GNUC_INTERNAL ClutterEasingFunc clutter_get_easing_func_for_mode (ClutterAnimationMode mode); G_GNUC_INTERNAL const char * clutter_get_easing_name_for_mode (ClutterAnimationMode mode); G_GNUC_INTERNAL double clutter_easing_for_mode (ClutterAnimationMode mode, double t, double d); G_GNUC_INTERNAL double clutter_linear (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_quad (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_quad (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_quad (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_cubic (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_cubic (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_cubic (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_quart (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_quart (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_quart (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_quint (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_quint (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_quint (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_sine (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_sine (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_sine (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_expo (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_expo (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_expo (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_circ (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_circ (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_circ (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_elastic (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_elastic (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_elastic (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_back (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_back (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_back (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_bounce (double t, double d); G_GNUC_INTERNAL double clutter_ease_out_bounce (double t, double d); G_GNUC_INTERNAL double clutter_ease_in_out_bounce (double t, double d); G_GNUC_INTERNAL double clutter_ease_steps_start (double t, double d, int steps); G_GNUC_INTERNAL double clutter_ease_steps_end (double t, double d, int steps); G_GNUC_INTERNAL double clutter_ease_cubic_bezier (double t, double d, double x_1, double y_1, double x_2, double y_2); G_END_DECLS #endif /* __CLUTTER_EASING_H__ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-effect.h�������������������������������������������������������0000664�0001750�0001750�00000010661�14211404421�021371� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_EFFECT_H__ #define __CLUTTER_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-actor-meta.h> G_BEGIN_DECLS #define CLUTTER_TYPE_EFFECT (clutter_effect_get_type ()) #define CLUTTER_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EFFECT, ClutterEffect)) #define CLUTTER_IS_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EFFECT)) #define CLUTTER_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_EFFECT, ClutterEffectClass)) #define CLUTTER_IS_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_EFFECT)) #define CLUTTER_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_EFFECT, ClutterEffectClass)) typedef struct _ClutterEffectClass ClutterEffectClass; /** * ClutterEffect: * * The #ClutterEffect structure contains only private data and should * be accessed using the provided API * * Since: 1.4 */ struct _ClutterEffect { /*< private >*/ ClutterActorMeta parent_instance; }; /** * ClutterEffectClass: * @pre_paint: virtual function * @post_paint: virtual function * @get_paint_volume: virtual function * @paint: virtual function * @pick: virtual function * * The #ClutterEffectClass structure contains only private data * * Since: 1.4 */ struct _ClutterEffectClass { /*< private >*/ ClutterActorMetaClass parent_class; /*< public >*/ gboolean (* pre_paint) (ClutterEffect *effect); void (* post_paint) (ClutterEffect *effect); gboolean (* get_paint_volume) (ClutterEffect *effect, ClutterPaintVolume *volume); void (* paint) (ClutterEffect *effect, ClutterEffectPaintFlags flags); void (* pick) (ClutterEffect *effect, ClutterEffectPaintFlags flags); /*< private >*/ void (* _clutter_effect4) (void); void (* _clutter_effect5) (void); void (* _clutter_effect6) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_8 void clutter_effect_queue_repaint (ClutterEffect *effect); /* * ClutterActor API */ CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_add_effect (ClutterActor *self, ClutterEffect *effect); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_add_effect_with_name (ClutterActor *self, const gchar *name, ClutterEffect *effect); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_remove_effect (ClutterActor *self, ClutterEffect *effect); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_remove_effect_by_name (ClutterActor *self, const gchar *name); CLUTTER_AVAILABLE_IN_1_4 GList * clutter_actor_get_effects (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_4 ClutterEffect *clutter_actor_get_effect (ClutterActor *self, const gchar *name); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_clear_effects (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_actor_has_effects (ClutterActor *self); G_END_DECLS #endif /* __CLUTTER_EFFECT_H__ */ �������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-actor-private.h������������������������������������������������0000664�0001750�0001750�00000034461�14211404421�022721� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_ACTOR_PRIVATE_H__ #define __CLUTTER_ACTOR_PRIVATE_H__ #include <clutter/clutter-actor.h> G_BEGIN_DECLS /*< private > * ClutterRedrawFlags: * @CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION: Tells clutter the maximum * extents of what needs to be redrawn lies within the actors * current allocation. (Only use this for 2D actors though because * any actor with depth may be projected outside of its allocation) * * Flags passed to the clutter_actor_queue_redraw_with_clip () * function * * Since: 1.6 */ typedef enum { CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION = 1 << 0 } ClutterRedrawFlags; /*< private > * ClutterActorTraverseFlags: * CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST: Traverse the graph in * a depth first order. * CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST: Traverse the graph in a * breadth first order. * * Controls some options for how clutter_actor_traverse() iterates * through the graph. */ typedef enum { CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST = 1L<<0, CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST = 1L<<1 } ClutterActorTraverseFlags; /*< private > * ClutterActorTraverseVisitFlags: * CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE: Continue traversing as * normal * CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN: Don't traverse the * children of the last visited actor. (Not applicable when using * %CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST_POST_ORDER since the children * are visited before having an opportunity to bail out) * CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK: Immediately bail out without * visiting any more actors. * * Each time an actor is visited during a scenegraph traversal the * ClutterTraverseCallback can return a set of flags that may affect * the continuing traversal. It may stop traversal completely, just * skip over children for the current actor or continue as normal. */ typedef enum { CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE = 1L<<0, CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN = 1L<<1, CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK = 1L<<2 } ClutterActorTraverseVisitFlags; /*< private > * ClutterTraverseCallback: * * The callback prototype used with clutter_actor_traverse. The * returned flags can be used to affect the continuing traversal * either by continuing as normal, skipping over children of an * actor or bailing out completely. */ typedef ClutterActorTraverseVisitFlags (*ClutterTraverseCallback) (ClutterActor *actor, gint depth, gpointer user_data); /*< private > * ClutterForeachCallback: * @actor: The actor being iterated * @user_data: The private data specified when starting the iteration * * A generic callback for iterating over actor, such as with * _clutter_actor_foreach_child. The difference when compared to * #ClutterCallback is that it returns a boolean so it is possible to break * out of an iteration early. * * Return value: %TRUE to continue iterating or %FALSE to break iteration * early. */ typedef gboolean (*ClutterForeachCallback) (ClutterActor *actor, gpointer user_data); typedef struct _AnchorCoord AnchorCoord; typedef struct _SizeRequest SizeRequest; typedef struct _ClutterLayoutInfo ClutterLayoutInfo; typedef struct _ClutterTransformInfo ClutterTransformInfo; typedef struct _ClutterAnimationInfo ClutterAnimationInfo; /* Internal helper struct to represent a point that can be stored in either direct pixel coordinates or as a fraction of the actor's size. It is used for the anchor point, scale center and rotation centers. */ struct _AnchorCoord { gboolean is_fractional; union { /* Used when is_fractional == TRUE */ struct { gdouble x; gdouble y; } fraction; /* Use when is_fractional == FALSE */ ClutterVertex units; } v; }; struct _SizeRequest { guint age; gfloat for_size; gfloat min_size; gfloat natural_size; }; /*< private > * ClutterLayoutInfo: * @fixed_pos: the fixed position of the actor * @margin: the composed margin of the actor * @x_align: the horizontal alignment, if the actor expands horizontally * @y_align: the vertical alignment, if the actor expands vertically * @x_expand: whether the actor should expand horizontally * @y_expand: whether the actor should expand vertically * @minimum: the fixed minimum size * @natural: the fixed natural size * * Ancillary layout information for an actor. */ struct _ClutterLayoutInfo { /* fixed position coordinates */ ClutterPoint fixed_pos; ClutterMargin margin; guint x_align : 4; guint y_align : 4; guint x_expand : 1; guint y_expand : 1; ClutterSize minimum; ClutterSize natural; }; const ClutterLayoutInfo * _clutter_actor_get_layout_info_or_defaults (ClutterActor *self); ClutterLayoutInfo * _clutter_actor_get_layout_info (ClutterActor *self); ClutterLayoutInfo * _clutter_actor_peek_layout_info (ClutterActor *self); struct _ClutterTransformInfo { /* rotation (angle and center) */ gdouble rx_angle; AnchorCoord rx_center; gdouble ry_angle; AnchorCoord ry_center; gdouble rz_angle; AnchorCoord rz_center; /* scaling */ gdouble scale_x; gdouble scale_y; gdouble scale_z; AnchorCoord scale_center; /* anchor point */ AnchorCoord anchor; /* translation */ ClutterVertex translation; /* z_position */ gfloat z_position; /* transformation center */ ClutterPoint pivot; gfloat pivot_z; CoglMatrix transform; guint transform_set : 1; CoglMatrix child_transform; guint child_transform_set : 1; }; const ClutterTransformInfo * _clutter_actor_get_transform_info_or_defaults (ClutterActor *self); ClutterTransformInfo * _clutter_actor_get_transform_info (ClutterActor *self); typedef struct _AState { guint easing_duration; guint easing_delay; ClutterAnimationMode easing_mode; } AState; struct _ClutterAnimationInfo { GArray *states; AState *cur_state; GHashTable *transitions; }; const ClutterAnimationInfo * _clutter_actor_get_animation_info_or_defaults (ClutterActor *self); ClutterAnimationInfo * _clutter_actor_get_animation_info (ClutterActor *self); ClutterTransition * _clutter_actor_create_transition (ClutterActor *self, GParamSpec *pspec, ...); ClutterTransition * _clutter_actor_get_transition (ClutterActor *self, GParamSpec *pspec); gboolean _clutter_actor_foreach_child (ClutterActor *self, ClutterForeachCallback callback, gpointer user_data); void _clutter_actor_traverse (ClutterActor *actor, ClutterActorTraverseFlags flags, ClutterTraverseCallback before_children_callback, ClutterTraverseCallback after_children_callback, gpointer user_data); ClutterActor * _clutter_actor_get_stage_internal (ClutterActor *actor); void _clutter_actor_apply_modelview_transform (ClutterActor *self, CoglMatrix *matrix); void _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self, ClutterActor *ancestor, CoglMatrix *matrix); void _clutter_actor_rerealize (ClutterActor *self, ClutterCallback callback, gpointer data); void _clutter_actor_set_in_clone_paint (ClutterActor *self, gboolean is_in_clone_paint); void _clutter_actor_set_enable_model_view_transform (ClutterActor *self, gboolean enable); void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self, gboolean enable); void _clutter_actor_set_has_pointer (ClutterActor *self, gboolean has_pointer); void _clutter_actor_queue_redraw_with_clip (ClutterActor *self, ClutterRedrawFlags flags, ClutterPaintVolume *clip_volume); void _clutter_actor_queue_redraw_full (ClutterActor *self, ClutterRedrawFlags flags, ClutterPaintVolume *volume, ClutterEffect *effect); ClutterPaintVolume * _clutter_actor_get_queue_redraw_clip (ClutterActor *self); void _clutter_actor_set_queue_redraw_clip (ClutterActor *self, ClutterPaintVolume *clip_volume); void _clutter_actor_finish_queue_redraw (ClutterActor *self, ClutterPaintVolume *clip); gboolean _clutter_actor_set_default_paint_volume (ClutterActor *self, GType check_gtype, ClutterPaintVolume *volume); const gchar * _clutter_actor_get_debug_name (ClutterActor *self); void _clutter_actor_push_clone_paint (void); void _clutter_actor_pop_clone_paint (void); guint32 _clutter_actor_get_pick_id (ClutterActor *self); void _clutter_actor_shader_pre_paint (ClutterActor *actor, gboolean repeat); void _clutter_actor_shader_post_paint (ClutterActor *actor); ClutterActorAlign _clutter_actor_get_effective_x_align (ClutterActor *self); void _clutter_actor_handle_event (ClutterActor *actor, const ClutterEvent *event); void _clutter_actor_attach_clone (ClutterActor *actor, ClutterActor *clone); void _clutter_actor_detach_clone (ClutterActor *actor, ClutterActor *clone); void _clutter_actor_queue_redraw_on_clones (ClutterActor *actor); void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor); void _clutter_actor_queue_only_relayout (ClutterActor *actor); CoglFramebuffer * _clutter_actor_get_active_framebuffer (ClutterActor *actor); ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self, CoglTexture *texture); G_END_DECLS #endif /* __CLUTTER_ACTOR_PRIVATE_H__ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-constraint.h���������������������������������������������������0000664�0001750�0001750�00000011742�14211404421�022322� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_CONSTRAINT_H__ #define __CLUTTER_CONSTRAINT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-actor-meta.h> G_BEGIN_DECLS #define CLUTTER_TYPE_CONSTRAINT (clutter_constraint_get_type ()) #define CLUTTER_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONSTRAINT, ClutterConstraint)) #define CLUTTER_IS_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONSTRAINT)) #define CLUTTER_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CONSTRAINT, ClutterConstraintClass)) #define CLUTTER_IS_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CONSTRAINT)) #define CLUTTER_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CONSTRAINT, ClutterConstraintClass)) typedef struct _ClutterConstraintClass ClutterConstraintClass; /** * ClutterConstraint: * * The #ClutterConstraint structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterConstraint { /*< private >*/ ClutterActorMeta parent_instance; }; /** * ClutterConstraintClass: * @update_allocation: virtual function used to update the allocation * of the #ClutterActor using the #ClutterConstraint * @update_preferred_size: virtual function used to update the preferred * size of the #ClutterActor using the #ClutterConstraint; optional, * since 1.22 * * The #ClutterConstraintClass structure contains * only private data * * Since: 1.4 */ struct _ClutterConstraintClass { /*< private >*/ ClutterActorMetaClass parent_class; /*< public >*/ void (* update_allocation) (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation); void (* update_preferred_size) (ClutterConstraint *constraint, ClutterActor *actor, ClutterOrientation direction, float for_size, float *minimum_size, float *natural_size); /*< private >*/ void (* _clutter_constraint1) (void); void (* _clutter_constraint2) (void); void (* _clutter_constraint3) (void); void (* _clutter_constraint4) (void); void (* _clutter_constraint5) (void); void (* _clutter_constraint6) (void); void (* _clutter_constraint7) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_constraint_get_type (void) G_GNUC_CONST; /* ClutterActor API */ CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_add_constraint (ClutterActor *self, ClutterConstraint *constraint); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_add_constraint_with_name (ClutterActor *self, const gchar *name, ClutterConstraint *constraint); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_remove_constraint (ClutterActor *self, ClutterConstraint *constraint); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_remove_constraint_by_name (ClutterActor *self, const gchar *name); CLUTTER_AVAILABLE_IN_1_4 GList * clutter_actor_get_constraints (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_4 ClutterConstraint *clutter_actor_get_constraint (ClutterActor *self, const gchar *name); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_clear_constraints (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_actor_has_constraints (ClutterActor *self); G_END_DECLS #endif /* __CLUTTER_CONSTRAINT_H__ */ ������������������������������muffin-5.2.1/clutter/clutter/clutter-canvas.c�������������������������������������������������������0000664�0001750�0001750�00000035620�14211404421�021405� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-canvas * @Title: ClutterCanvas * @Short_Description: Content for 2D painting * @See_Also: #ClutterContent * * The #ClutterCanvas class is a #ClutterContent implementation that allows * drawing using the Cairo API on a 2D surface. * * In order to draw on a #ClutterCanvas, you should connect a handler to the * #ClutterCanvas::draw signal; the signal will receive a #cairo_t context * that can be used to draw. #ClutterCanvas will emit the #ClutterCanvas::draw * signal when invalidated using clutter_content_invalidate(). * * See [canvas.c](https://git.gnome.org/browse/clutter/tree/examples/canvas.c?h=clutter-1.18) * for an example of how to use #ClutterCanvas. * * #ClutterCanvas is available since Clutter 1.10. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <cogl/cogl.h> #include <cairo-gobject.h> #include "clutter-canvas.h" #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-actor-private.h" #include "clutter-backend.h" #include "clutter-cairo.h" #include "clutter-color.h" #include "clutter-content-private.h" #include "clutter-debug.h" #include "clutter-marshal.h" #include "clutter-paint-node.h" #include "clutter-paint-nodes.h" #include "clutter-private.h" #include "clutter-settings.h" struct _ClutterCanvasPrivate { cairo_t *cr; int width; int height; CoglTexture *texture; gboolean dirty; CoglBitmap *buffer; }; enum { PROP_0, PROP_WIDTH, PROP_HEIGHT, LAST_PROP }; static GParamSpec *obj_props[LAST_PROP] = { NULL, }; enum { DRAW, LAST_SIGNAL }; static guint canvas_signals[LAST_SIGNAL] = { 0, }; static void clutter_content_iface_init (ClutterContentIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterCanvas, clutter_canvas, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterCanvas) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, clutter_content_iface_init)) static void clutter_cairo_context_draw_marshaller (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data) { cairo_t *cr = g_value_get_boxed (¶m_values[1]); cairo_save (cr); _clutter_marshal_BOOLEAN__BOXED_INT_INT (closure, return_value, n_param_values, param_values, invocation_hint, marshal_data); cairo_restore (cr); } static void clutter_canvas_finalize (GObject *gobject) { ClutterCanvasPrivate *priv = CLUTTER_CANVAS (gobject)->priv; if (priv->buffer != NULL) { cogl_object_unref (priv->buffer); priv->buffer = NULL; } g_clear_pointer (&priv->texture, cogl_object_unref); G_OBJECT_CLASS (clutter_canvas_parent_class)->finalize (gobject); } static void clutter_canvas_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterCanvasPrivate *priv = CLUTTER_CANVAS (gobject)->priv; switch (prop_id) { case PROP_WIDTH: { gint new_size = g_value_get_int (value); if (priv->width != new_size) { priv->width = new_size; clutter_content_invalidate (CLUTTER_CONTENT (gobject)); } } break; case PROP_HEIGHT: { gint new_size = g_value_get_int (value); if (priv->height != new_size) { priv->height = new_size; clutter_content_invalidate (CLUTTER_CONTENT (gobject)); } } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_canvas_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterCanvasPrivate *priv = CLUTTER_CANVAS (gobject)->priv; switch (prop_id) { case PROP_WIDTH: g_value_set_int (value, priv->width); break; case PROP_HEIGHT: g_value_set_int (value, priv->height); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_canvas_class_init (ClutterCanvasClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); /** * ClutterCanvas:width: * * The width of the canvas. * * Since: 1.10 */ obj_props[PROP_WIDTH] = g_param_spec_int ("width", P_("Width"), P_("The width of the canvas"), -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterCanvas:height: * * The height of the canvas. * * Since: 1.10 */ obj_props[PROP_HEIGHT] = g_param_spec_int ("height", P_("Height"), P_("The height of the canvas"), -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterCanvas::draw: * @canvas: the #ClutterCanvas that emitted the signal * @cr: the Cairo context used to draw * @width: the width of the @canvas * @height: the height of the @canvas * * The #ClutterCanvas::draw signal is emitted each time a canvas is * invalidated. * * It is safe to connect multiple handlers to this signal: each * handler invocation will be automatically protected by cairo_save() * and cairo_restore() pairs. * * Return value: %TRUE if the signal emission should stop, and * %FALSE otherwise * * Since: 1.10 */ canvas_signals[DRAW] = g_signal_new (I_("draw"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET (ClutterCanvasClass, draw), _clutter_boolean_handled_accumulator, NULL, clutter_cairo_context_draw_marshaller, G_TYPE_BOOLEAN, 3, CAIRO_GOBJECT_TYPE_CONTEXT, G_TYPE_INT, G_TYPE_INT); gobject_class->set_property = clutter_canvas_set_property; gobject_class->get_property = clutter_canvas_get_property; gobject_class->finalize = clutter_canvas_finalize; g_object_class_install_properties (gobject_class, LAST_PROP, obj_props); } static void clutter_canvas_init (ClutterCanvas *self) { self->priv = clutter_canvas_get_instance_private (self); self->priv->width = -1; self->priv->height = -1; } static void clutter_canvas_paint_content (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *root) { ClutterCanvas *self = CLUTTER_CANVAS (content); ClutterCanvasPrivate *priv = self->priv; ClutterPaintNode *node; if (priv->buffer == NULL) return; if (priv->dirty) g_clear_pointer (&priv->texture, cogl_object_unref); if (priv->texture == NULL) priv->texture = cogl_texture_new_from_bitmap (priv->buffer, COGL_TEXTURE_NO_SLICING, CLUTTER_CAIRO_FORMAT_ARGB32); if (priv->texture == NULL) return; node = clutter_actor_create_texture_paint_node (actor, priv->texture); clutter_paint_node_set_name (node, "Canvas Content"); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); priv->dirty = FALSE; } static void clutter_canvas_emit_draw (ClutterCanvas *self) { ClutterCanvasPrivate *priv = self->priv; int real_width, real_height; cairo_surface_t *surface; gboolean mapped_buffer; unsigned char *data; CoglBuffer *buffer; gboolean res; cairo_t *cr; g_assert (priv->height > 0 && priv->width > 0); priv->dirty = TRUE; real_width = priv->width; real_height = priv->height; CLUTTER_NOTE (MISC, "Creating Cairo surface with size %d x %d", priv->width, priv->height); if (priv->buffer == NULL) { CoglContext *ctx; ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); priv->buffer = cogl_bitmap_new_with_size (ctx, real_width, real_height, CLUTTER_CAIRO_FORMAT_ARGB32); } buffer = COGL_BUFFER (cogl_bitmap_get_buffer (priv->buffer)); if (buffer == NULL) return; cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC); data = cogl_buffer_map (buffer, COGL_BUFFER_ACCESS_READ_WRITE, COGL_BUFFER_MAP_HINT_DISCARD); if (data != NULL) { int bitmap_stride = cogl_bitmap_get_rowstride (priv->buffer); surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, real_width, real_height, bitmap_stride); mapped_buffer = TRUE; } else { surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, real_width, real_height); mapped_buffer = FALSE; } self->priv->cr = cr = cairo_create (surface); g_signal_emit (self, canvas_signals[DRAW], 0, cr, priv->width, priv->height, &res); #ifdef CLUTTER_ENABLE_DEBUG if (_clutter_diagnostic_enabled () && cairo_status (cr)) { g_warning ("Drawing failed for <ClutterCanvas>[%p]: %s", self, cairo_status_to_string (cairo_status (cr))); } #endif self->priv->cr = NULL; cairo_destroy (cr); if (mapped_buffer) cogl_buffer_unmap (buffer); else { int size = cairo_image_surface_get_stride (surface) * priv->height; cogl_buffer_set_data (buffer, 0, cairo_image_surface_get_data (surface), size); } cairo_surface_destroy (surface); } static void clutter_canvas_invalidate (ClutterContent *content) { ClutterCanvas *self = CLUTTER_CANVAS (content); ClutterCanvasPrivate *priv = self->priv; if (priv->buffer != NULL) { cogl_object_unref (priv->buffer); priv->buffer = NULL; } if (priv->width <= 0 || priv->height <= 0) return; clutter_canvas_emit_draw (self); } static gboolean clutter_canvas_get_preferred_size (ClutterContent *content, gfloat *width, gfloat *height) { ClutterCanvasPrivate *priv = CLUTTER_CANVAS (content)->priv; if (priv->width < 0 || priv->height < 0) return FALSE; if (width != NULL) *width = priv->width; if (height != NULL) *height = priv->height; return TRUE; } static void clutter_content_iface_init (ClutterContentIface *iface) { iface->invalidate = clutter_canvas_invalidate; iface->paint_content = clutter_canvas_paint_content; iface->get_preferred_size = clutter_canvas_get_preferred_size; } /** * clutter_canvas_new: * * Creates a new instance of #ClutterCanvas. * * You should call clutter_canvas_set_size() to set the size of the canvas. * * You should call clutter_content_invalidate() every time you wish to * draw the contents of the canvas. * * Return value: (transfer full): The newly allocated instance of * #ClutterCanvas. Use g_object_unref() when done. * * Since: 1.10 */ ClutterContent * clutter_canvas_new (void) { return g_object_new (CLUTTER_TYPE_CANVAS, NULL); } static gboolean clutter_canvas_invalidate_internal (ClutterCanvas *canvas, int width, int height) { gboolean width_changed = FALSE, height_changed = FALSE; gboolean res = FALSE; GObject *obj; obj = G_OBJECT (canvas); g_object_freeze_notify (obj); if (canvas->priv->width != width) { canvas->priv->width = width; width_changed = TRUE; g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]); } if (canvas->priv->height != height) { canvas->priv->height = height; height_changed = TRUE; g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]); } if (width_changed || height_changed) { clutter_content_invalidate (CLUTTER_CONTENT (canvas)); res = TRUE; } g_object_thaw_notify (obj); return res; } /** * clutter_canvas_set_size: * @canvas: a #ClutterCanvas * @width: the width of the canvas, in pixels * @height: the height of the canvas, in pixels * * Sets the size of the @canvas, and invalidates the content. * * This function will cause the @canvas to be invalidated only * if the size of the canvas surface has changed. * * If you want to invalidate the contents of the @canvas when setting * the size, you can use the return value of the function to conditionally * call clutter_content_invalidate(): * * |[ * if (!clutter_canvas_set_size (canvas, width, height)) * clutter_content_invalidate (CLUTTER_CONTENT (canvas)); * ]| * * Return value: this function returns %TRUE if the size change * caused a content invalidation, and %FALSE otherwise * * Since: 1.10 */ gboolean clutter_canvas_set_size (ClutterCanvas *canvas, int width, int height) { g_return_val_if_fail (CLUTTER_IS_CANVAS (canvas), FALSE); g_return_val_if_fail (width >= -1 && height >= -1, FALSE); return clutter_canvas_invalidate_internal (canvas, width, height); } ����������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-blur-effect.h��������������������������������������������������0000664�0001750�0001750�00000003522�14211404421�022331� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_BLUR_EFFECT_H__ #define __CLUTTER_BLUR_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-effect.h> G_BEGIN_DECLS #define CLUTTER_TYPE_BLUR_EFFECT (clutter_blur_effect_get_type ()) #define CLUTTER_BLUR_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BLUR_EFFECT, ClutterBlurEffect)) #define CLUTTER_IS_BLUR_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BLUR_EFFECT)) /** * ClutterBlurEffect: * * #ClutterBlurEffect is an opaque structure * whose members cannot be accessed directly * * Since: 1.4 */ typedef struct _ClutterBlurEffect ClutterBlurEffect; typedef struct _ClutterBlurEffectClass ClutterBlurEffectClass; CLUTTER_AVAILABLE_IN_1_4 GType clutter_blur_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterEffect *clutter_blur_effect_new (void); G_END_DECLS #endif /* __CLUTTER_BLUR_EFFECT_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-drop-action.c��������������������������������������������������0000664�0001750�0001750�00000037302�14211404421�022350� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2011 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-drop-action * @Title: ClutterDropAction * @short_description: An action for drop targets * * #ClutterDropAction is a #ClutterAction that allows a #ClutterActor * implementation to control what happens when an actor dragged using * a #ClutterDragAction crosses the target area or when a dragged actor * is released (or "dropped") on the target area. * * A trivial use of #ClutterDropAction consists in connecting to the * #ClutterDropAction::drop signal and handling the drop from there, * for instance: * * |[<!-- language="C" --> * ClutterAction *action = clutter_drop_action (); * * g_signal_connect (action, "drop", G_CALLBACK (on_drop), NULL); * clutter_actor_add_action (an_actor, action); * ]| * * The #ClutterDropAction::can-drop can be used to control whether the * #ClutterDropAction::drop signal is going to be emitted; returning %FALSE * from a handler connected to the #ClutterDropAction::can-drop signal will * cause the #ClutterDropAction::drop signal to be skipped when the input * device button is released. * * It's important to note that #ClutterDropAction will only work with * actors dragged using #ClutterDragAction. * * See [drop-action.c](https://git.gnome.org/browse/clutter/tree/examples/drop-action.c?h=clutter-1.18) * for an example of how to use #ClutterDropAction. * * #ClutterDropAction is available since Clutter 1.8 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-drop-action.h" #include "clutter-actor-meta-private.h" #include "clutter-actor-private.h" #include "clutter-drag-action.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-stage-private.h" struct _ClutterDropActionPrivate { ClutterActor *actor; ClutterActor *stage; gulong mapped_id; }; typedef struct _DropTarget { ClutterActor *stage; gulong capture_id; GHashTable *actions; ClutterDropAction *last_action; } DropTarget; enum { CAN_DROP, OVER_IN, OVER_OUT, DROP, DROP_CANCEL, LAST_SIGNAL }; static guint drop_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterDropAction, clutter_drop_action, CLUTTER_TYPE_ACTION) static void drop_target_free (gpointer _data) { DropTarget *data = _data; g_signal_handler_disconnect (data->stage, data->capture_id); g_hash_table_destroy (data->actions); free (data); } static gboolean on_stage_capture (ClutterStage *stage, ClutterEvent *event, gpointer user_data) { DropTarget *data = user_data; gfloat event_x, event_y; ClutterActor *actor, *drag_actor; ClutterDropAction *drop_action; ClutterInputDevice *device; gboolean was_reactive; switch (clutter_event_type (event)) { case CLUTTER_MOTION: case CLUTTER_BUTTON_RELEASE: if (clutter_event_type (event) == CLUTTER_MOTION && !(clutter_event_get_state (event) & CLUTTER_BUTTON1_MASK)) return CLUTTER_EVENT_PROPAGATE; if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE && clutter_event_get_button (event) != CLUTTER_BUTTON_PRIMARY) return CLUTTER_EVENT_PROPAGATE; device = clutter_event_get_device (event); drag_actor = _clutter_stage_get_pointer_drag_actor (stage, device); if (drag_actor == NULL) return CLUTTER_EVENT_PROPAGATE; break; case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_END: drag_actor = _clutter_stage_get_touch_drag_actor (stage, clutter_event_get_event_sequence (event)); if (drag_actor == NULL) return CLUTTER_EVENT_PROPAGATE; break; default: return CLUTTER_EVENT_PROPAGATE; } clutter_event_get_coords (event, &event_x, &event_y); /* get the actor under the cursor, excluding the dragged actor; we * use reactivity because it won't cause any scene invalidation */ was_reactive = clutter_actor_get_reactive (drag_actor); clutter_actor_set_reactive (drag_actor, FALSE); actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_REACTIVE, event_x, event_y); if (actor == NULL || actor == CLUTTER_ACTOR (stage)) { if (data->last_action != NULL) { ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action); g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0, clutter_actor_meta_get_actor (meta)); data->last_action = NULL; } goto out; } drop_action = g_hash_table_lookup (data->actions, actor); if (drop_action == NULL) { if (data->last_action != NULL) { ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action); g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0, clutter_actor_meta_get_actor (meta)); data->last_action = NULL; } goto out; } else { if (data->last_action != drop_action) { ClutterActorMeta *meta; if (data->last_action != NULL) { meta = CLUTTER_ACTOR_META (data->last_action); g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0, clutter_actor_meta_get_actor (meta)); } meta = CLUTTER_ACTOR_META (drop_action); g_signal_emit (drop_action, drop_signals[OVER_IN], 0, clutter_actor_meta_get_actor (meta)); } data->last_action = drop_action; } out: if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE || clutter_event_type (event) == CLUTTER_TOUCH_END) { if (data->last_action != NULL) { ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action); gboolean can_drop = FALSE; g_signal_emit (data->last_action, drop_signals[CAN_DROP], 0, clutter_actor_meta_get_actor (meta), event_x, event_y, &can_drop); if (can_drop) { g_signal_emit (data->last_action, drop_signals[DROP], 0, clutter_actor_meta_get_actor (meta), event_x, event_y); } else { g_signal_emit (data->last_action, drop_signals[DROP_CANCEL], 0, clutter_actor_meta_get_actor (meta), event_x, event_y); } } data->last_action = NULL; } if (drag_actor != NULL) clutter_actor_set_reactive (drag_actor, was_reactive); return CLUTTER_EVENT_PROPAGATE; } static void drop_action_register (ClutterDropAction *self) { ClutterDropActionPrivate *priv = self->priv; DropTarget *data; g_assert (priv->stage != NULL); data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets"); if (data == NULL) { data = g_new0 (DropTarget, 1); data->stage = priv->stage; data->actions = g_hash_table_new (NULL, NULL); data->capture_id = g_signal_connect (priv->stage, "captured-event", G_CALLBACK (on_stage_capture), data); g_object_set_data_full (G_OBJECT (priv->stage), "__clutter_drop_targets", data, drop_target_free); } g_hash_table_replace (data->actions, priv->actor, self); } static void drop_action_unregister (ClutterDropAction *self) { ClutterDropActionPrivate *priv = self->priv; DropTarget *data = NULL; if (priv->stage != NULL) data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets"); if (data == NULL) return; g_hash_table_remove (data->actions, priv->actor); if (g_hash_table_size (data->actions) == 0) g_object_set_data (G_OBJECT (data->stage), "__clutter_drop_targets", NULL); } static void on_actor_mapped (ClutterActor *actor, GParamSpec *pspec, ClutterDropAction *self) { if (clutter_actor_is_mapped (actor)) { if (self->priv->stage == NULL) self->priv->stage = clutter_actor_get_stage (actor); drop_action_register (self); } else drop_action_unregister (self); } static void clutter_drop_action_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterDropActionPrivate *priv = CLUTTER_DROP_ACTION (meta)->priv; if (priv->actor != NULL) { drop_action_unregister (CLUTTER_DROP_ACTION (meta)); if (priv->mapped_id != 0) g_signal_handler_disconnect (priv->actor, priv->mapped_id); priv->stage = NULL; priv->actor = NULL; priv->mapped_id = 0; } priv->actor = actor; if (priv->actor != NULL) { priv->stage = clutter_actor_get_stage (actor); priv->mapped_id = g_signal_connect (actor, "notify::mapped", G_CALLBACK (on_actor_mapped), meta); if (priv->stage != NULL) drop_action_register (CLUTTER_DROP_ACTION (meta)); } CLUTTER_ACTOR_META_CLASS (clutter_drop_action_parent_class)->set_actor (meta, actor); } static gboolean signal_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer user_data) { gboolean continue_emission; continue_emission = g_value_get_boolean (handler_return); g_value_set_boolean (return_accu, continue_emission); return continue_emission; } static gboolean clutter_drop_action_real_can_drop (ClutterDropAction *action, ClutterActor *actor, gfloat event_x, gfloat event_y) { return TRUE; } static void clutter_drop_action_class_init (ClutterDropActionClass *klass) { ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); meta_class->set_actor = clutter_drop_action_set_actor; klass->can_drop = clutter_drop_action_real_can_drop; /** * ClutterDropAction::can-drop: * @action: the #ClutterDropAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @event_x: the X coordinate (in stage space) of the drop event * @event_y: the Y coordinate (in stage space) of the drop event * * The ::can-drop signal is emitted when the dragged actor is dropped * on @actor. The return value of the ::can-drop signal will determine * whether or not the #ClutterDropAction::drop signal is going to be * emitted on @action. * * The default implementation of #ClutterDropAction returns %TRUE for * this signal. * * Return value: %TRUE if the drop is accepted, and %FALSE otherwise * * Since: 1.8 */ drop_signals[CAN_DROP] = g_signal_new (I_("can-drop"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDropActionClass, can_drop), signal_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT_FLOAT_FLOAT, G_TYPE_BOOLEAN, 3, CLUTTER_TYPE_ACTOR, G_TYPE_FLOAT, G_TYPE_FLOAT); /** * ClutterDropAction::over-in: * @action: the #ClutterDropAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::over-in signal is emitted when the dragged actor crosses * into @actor. * * Since: 1.8 */ drop_signals[OVER_IN] = g_signal_new (I_("over-in"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDropActionClass, over_in), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterDropAction::over-out: * @action: the #ClutterDropAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::over-out signal is emitted when the dragged actor crosses * outside @actor. * * Since: 1.8 */ drop_signals[OVER_OUT] = g_signal_new (I_("over-out"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDropActionClass, over_out), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterDropAction::drop: * @action: the #ClutterDropAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @event_x: the X coordinate (in stage space) of the drop event * @event_y: the Y coordinate (in stage space) of the drop event * * The ::drop signal is emitted when the dragged actor is dropped * on @actor. This signal is only emitted if at least an handler of * #ClutterDropAction::can-drop returns %TRUE. * * Since: 1.8 */ drop_signals[DROP] = g_signal_new (I_("drop"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDropActionClass, drop), NULL, NULL, _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT, G_TYPE_NONE, 3, CLUTTER_TYPE_ACTOR, G_TYPE_FLOAT, G_TYPE_FLOAT); /** * ClutterDropAction::drop-cancel: * @action: the #ClutterDropAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @event_x: the X coordinate (in stage space) of the drop event * @event_y: the Y coordinate (in stage space) of the drop event * * The ::drop-cancel signal is emitted when the drop is refused * by an emission of the #ClutterDropAction::can-drop signal. * * After the ::drop-cancel signal is fired the active drag is * terminated. * * Since: 1.12 */ drop_signals[DROP_CANCEL] = g_signal_new (I_("drop-cancel"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDropActionClass, drop), NULL, NULL, _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT, G_TYPE_NONE, 3, CLUTTER_TYPE_ACTOR, G_TYPE_FLOAT, G_TYPE_FLOAT); } static void clutter_drop_action_init (ClutterDropAction *self) { self->priv = clutter_drop_action_get_instance_private (self); } /** * clutter_drop_action_new: * * Creates a new #ClutterDropAction. * * Use clutter_actor_add_action() to add the action to a #ClutterActor. * * Return value: the newly created #ClutterDropAction * * Since: 1.8 */ ClutterAction * clutter_drop_action_new (void) { return g_object_new (CLUTTER_TYPE_DROP_ACTION, NULL); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-easing.c�������������������������������������������������������0000664�0001750�0001750�00000027217�14211404421�021403� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "clutter-build-config.h" #include "clutter-easing.h" #include <math.h> double clutter_linear (double t, double d) { return t / d; } double clutter_ease_in_quad (double t, double d) { double p = t / d; return p * p; } double clutter_ease_out_quad (double t, double d) { double p = t / d; return -1.0 * p * (p - 2); } double clutter_ease_in_out_quad (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p; p -= 1; return -0.5 * (p * (p - 2) - 1); } double clutter_ease_in_cubic (double t, double d) { double p = t / d; return p * p * p; } double clutter_ease_out_cubic (double t, double d) { double p = t / d - 1; return p * p * p + 1; } double clutter_ease_in_out_cubic (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p * p; p -= 2; return 0.5 * (p * p * p + 2); } double clutter_ease_in_quart (double t, double d) { double p = t / d; return p * p * p * p; } double clutter_ease_out_quart (double t, double d) { double p = t / d - 1; return -1.0 * (p * p * p * p - 1); } double clutter_ease_in_out_quart (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p * p * p; p -= 2; return -0.5 * (p * p * p * p - 2); } double clutter_ease_in_quint (double t, double d) { double p = t / d; return p * p * p * p * p; } double clutter_ease_out_quint (double t, double d) { double p = t / d - 1; return p * p * p * p * p + 1; } double clutter_ease_in_out_quint (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p * p * p * p; p -= 2; return 0.5 * (p * p * p * p * p + 2); } double clutter_ease_in_sine (double t, double d) { return -1.0 * cos (t / d * G_PI_2) + 1.0; } double clutter_ease_out_sine (double t, double d) { return sin (t / d * G_PI_2); } double clutter_ease_in_out_sine (double t, double d) { return -0.5 * (cos (G_PI * t / d) - 1); } double clutter_ease_in_expo (double t, double d) { return (t == 0) ? 0.0 : pow (2, 10 * (t / d - 1)); } double clutter_ease_out_expo (double t, double d) { return (t == d) ? 1.0 : -pow (2, -10 * t / d) + 1; } double clutter_ease_in_out_expo (double t, double d) { double p; if (t == 0) return 0.0; if (t == d) return 1.0; p = t / (d / 2); if (p < 1) return 0.5 * pow (2, 10 * (p - 1)); p -= 1; return 0.5 * (-pow (2, -10 * p) + 2); } double clutter_ease_in_circ (double t, double d) { double p = t / d; return -1.0 * (sqrt (1 - p * p) - 1); } double clutter_ease_out_circ (double t, double d) { double p = t / d - 1; return sqrt (1 - p * p); } double clutter_ease_in_out_circ (double t, double d) { double p = t / (d / 2); if (p < 1) return -0.5 * (sqrt (1 - p * p) - 1); p -= 2; return 0.5 * (sqrt (1 - p * p) + 1); } double clutter_ease_in_elastic (double t, double d) { double p = d * .3; double s = p / 4; double q = t / d; if (q == 1) return 1.0; q -= 1; return -(pow (2, 10 * q) * sin ((q * d - s) * (2 * G_PI) / p)); } double clutter_ease_out_elastic (double t, double d) { double p = d * .3; double s = p / 4; double q = t / d; if (q == 1) return 1.0; return pow (2, -10 * q) * sin ((q * d - s) * (2 * G_PI) / p) + 1.0; } double clutter_ease_in_out_elastic (double t, double d) { double p = d * (.3 * 1.5); double s = p / 4; double q = t / (d / 2); if (q == 2) return 1.0; if (q < 1) { q -= 1; return -.5 * (pow (2, 10 * q) * sin ((q * d - s) * (2 * G_PI) / p)); } else { q -= 1; return pow (2, -10 * q) * sin ((q * d - s) * (2 * G_PI) / p) * .5 + 1.0; } } double clutter_ease_in_back (double t, double d) { double p = t / d; return p * p * ((1.70158 + 1) * p - 1.70158); } double clutter_ease_out_back (double t, double d) { double p = t / d - 1; return p * p * ((1.70158 + 1) * p + 1.70158) + 1; } double clutter_ease_in_out_back (double t, double d) { double p = t / (d / 2); double s = 1.70158 * 1.525; if (p < 1) return 0.5 * (p * p * ((s + 1) * p - s)); p -= 2; return 0.5 * (p * p * ((s + 1) * p + s) + 2); } static inline double ease_out_bounce_internal (double t, double d) { double p = t / d; if (p < (1 / 2.75)) { return 7.5625 * p * p; } else if (p < (2 / 2.75)) { p -= (1.5 / 2.75); return 7.5625 * p * p + .75; } else if (p < (2.5 / 2.75)) { p -= (2.25 / 2.75); return 7.5625 * p * p + .9375; } else { p -= (2.625 / 2.75); return 7.5625 * p * p + .984375; } } static inline double ease_in_bounce_internal (double t, double d) { return 1.0 - ease_out_bounce_internal (d - t, d); } double clutter_ease_in_bounce (double t, double d) { return ease_in_bounce_internal (t, d); } double clutter_ease_out_bounce (double t, double d) { return ease_out_bounce_internal (t, d); } double clutter_ease_in_out_bounce (double t, double d) { if (t < d / 2) return ease_in_bounce_internal (t * 2, d) * 0.5; else return ease_out_bounce_internal (t * 2 - d, d) * 0.5 + 1.0 * 0.5; } static inline double ease_steps_end (double p, int n_steps) { return floor (p * (double) n_steps) / (double) n_steps; } double clutter_ease_steps_start (double t, double d, int n_steps) { return 1.0 - ease_steps_end (1.0 - (t / d), n_steps); } double clutter_ease_steps_end (double t, double d, int n_steps) { return ease_steps_end ((t / d), n_steps); } static inline double x_for_t (double t, double x_1, double x_2) { double omt = 1.0 - t; return 3.0 * omt * omt * t * x_1 + 3.0 * omt * t * t * x_2 + t * t * t; } static inline double y_for_t (double t, double y_1, double y_2) { double omt = 1.0 - t; return 3.0 * omt * omt * t * y_1 + 3.0 * omt * t * t * y_2 + t * t * t; } static inline double t_for_x (double x, double x_1, double x_2) { double min_t = 0, max_t = 1; int i; for (i = 0; i < 30; ++i) { double guess_t = (min_t + max_t) / 2.0; double guess_x = x_for_t (guess_t, x_1, x_2); if (x < guess_x) max_t = guess_t; else min_t = guess_t; } return (min_t + max_t) / 2.0; } double clutter_ease_cubic_bezier (double t, double d, double x_1, double y_1, double x_2, double y_2) { double p = t / d; if (p == 0.0) return 0.0; if (p == 1.0) return 1.0; return y_for_t (t_for_x (p, x_1, x_2), y_1, y_2); } /*< private > * _clutter_animation_modes: * * A mapping of animation modes and easing functions. */ static const struct { ClutterAnimationMode mode; ClutterEasingFunc func; const char *name; } _clutter_animation_modes[] = { { CLUTTER_CUSTOM_MODE, NULL, "custom" }, { CLUTTER_LINEAR, clutter_linear, "linear" }, { CLUTTER_EASE_IN_QUAD, clutter_ease_in_quad, "easeInQuad" }, { CLUTTER_EASE_OUT_QUAD, clutter_ease_out_quad, "easeOutQuad" }, { CLUTTER_EASE_IN_OUT_QUAD, clutter_ease_in_out_quad, "easeInOutQuad" }, { CLUTTER_EASE_IN_CUBIC, clutter_ease_in_cubic, "easeInCubic" }, { CLUTTER_EASE_OUT_CUBIC, clutter_ease_out_cubic, "easeOutCubic" }, { CLUTTER_EASE_IN_OUT_CUBIC, clutter_ease_in_out_cubic, "easeInOutCubic" }, { CLUTTER_EASE_IN_QUART, clutter_ease_in_quart, "easeInQuart" }, { CLUTTER_EASE_OUT_QUART, clutter_ease_out_quart, "easeOutQuart" }, { CLUTTER_EASE_IN_OUT_QUART, clutter_ease_in_out_quart, "easeInOutQuart" }, { CLUTTER_EASE_IN_QUINT, clutter_ease_in_quint, "easeInQuint" }, { CLUTTER_EASE_OUT_QUINT, clutter_ease_out_quint, "easeOutQuint" }, { CLUTTER_EASE_IN_OUT_QUINT, clutter_ease_in_out_quint, "easeInOutQuint" }, { CLUTTER_EASE_IN_SINE, clutter_ease_in_sine, "easeInSine" }, { CLUTTER_EASE_OUT_SINE, clutter_ease_out_sine, "easeOutSine" }, { CLUTTER_EASE_IN_OUT_SINE, clutter_ease_in_out_sine, "easeInOutSine" }, { CLUTTER_EASE_IN_EXPO, clutter_ease_in_expo, "easeInExpo" }, { CLUTTER_EASE_OUT_EXPO, clutter_ease_out_expo, "easeOutExpo" }, { CLUTTER_EASE_IN_OUT_EXPO, clutter_ease_in_out_expo, "easeInOutExpo" }, { CLUTTER_EASE_IN_CIRC, clutter_ease_in_circ, "easeInCirc" }, { CLUTTER_EASE_OUT_CIRC, clutter_ease_out_circ, "easeOutCirc" }, { CLUTTER_EASE_IN_OUT_CIRC, clutter_ease_in_out_circ, "easeInOutCirc" }, { CLUTTER_EASE_IN_ELASTIC, clutter_ease_in_elastic, "easeInElastic" }, { CLUTTER_EASE_OUT_ELASTIC, clutter_ease_out_elastic, "easeOutElastic" }, { CLUTTER_EASE_IN_OUT_ELASTIC, clutter_ease_in_out_elastic, "easeInOutElastic" }, { CLUTTER_EASE_IN_BACK, clutter_ease_in_back, "easeInBack" }, { CLUTTER_EASE_OUT_BACK, clutter_ease_out_back, "easeOutBack" }, { CLUTTER_EASE_IN_OUT_BACK, clutter_ease_in_out_back, "easeInOutBack" }, { CLUTTER_EASE_IN_BOUNCE, clutter_ease_in_bounce, "easeInBounce" }, { CLUTTER_EASE_OUT_BOUNCE, clutter_ease_out_bounce, "easeOutBounce" }, { CLUTTER_EASE_IN_OUT_BOUNCE, clutter_ease_in_out_bounce, "easeInOutBounce" }, /* the parametrized functions need a cast */ { CLUTTER_STEPS, (ClutterEasingFunc) clutter_ease_steps_end, "steps" }, { CLUTTER_STEP_START, (ClutterEasingFunc) clutter_ease_steps_start, "stepStart" }, { CLUTTER_STEP_END, (ClutterEasingFunc) clutter_ease_steps_end, "stepEnd" }, { CLUTTER_CUBIC_BEZIER, (ClutterEasingFunc) clutter_ease_cubic_bezier, "cubicBezier" }, { CLUTTER_EASE, (ClutterEasingFunc) clutter_ease_cubic_bezier, "ease" }, { CLUTTER_EASE_IN, (ClutterEasingFunc) clutter_ease_cubic_bezier, "easeIn" }, { CLUTTER_EASE_OUT, (ClutterEasingFunc) clutter_ease_cubic_bezier, "easeOut" }, { CLUTTER_EASE_IN_OUT, (ClutterEasingFunc) clutter_ease_cubic_bezier, "easeInOut" }, { CLUTTER_ANIMATION_LAST, NULL, "sentinel" }, }; ClutterEasingFunc clutter_get_easing_func_for_mode (ClutterAnimationMode mode) { g_assert (_clutter_animation_modes[mode].mode == mode); g_assert (_clutter_animation_modes[mode].func != NULL); return _clutter_animation_modes[mode].func; } const char * clutter_get_easing_name_for_mode (ClutterAnimationMode mode) { g_assert (_clutter_animation_modes[mode].mode == mode); g_assert (_clutter_animation_modes[mode].func != NULL); return _clutter_animation_modes[mode].name; } double clutter_easing_for_mode (ClutterAnimationMode mode, double t, double d) { g_assert (_clutter_animation_modes[mode].mode == mode); g_assert (_clutter_animation_modes[mode].func != NULL); return _clutter_animation_modes[mode].func (t, d); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-settings.h�����������������������������������������������������0000664�0001750�0001750�00000001543�14211404421�021774� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __CLUTTER_SETTINGS_H__ #define __CLUTTER_SETTINGS_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_SETTINGS (clutter_settings_get_type ()) #define CLUTTER_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SETTINGS, ClutterSettings)) #define CLUTTER_IS_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SETTINGS)) typedef struct _ClutterSettings ClutterSettings; typedef struct _ClutterSettingsClass ClutterSettingsClass; CLUTTER_AVAILABLE_IN_ALL GType clutter_settings_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterSettings *clutter_settings_get_default (void); G_END_DECLS #endif /* __CLUTTER_SETTINGS_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-bezier.c�������������������������������������������������������0000664�0001750�0001750�00000033530�14211404421�021410� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Tomas Frydrych <tf@openedhand.com> * * 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, see <http://www.gnu.org/licenses/>. */ #include "clutter-build-config.h" #include <glib.h> #include <string.h> #include "clutter-bezier.h" #include "clutter-debug.h" /* * We have some experimental code here to allow for constant velocity * movement of actors along the bezier path, this macro enables it. */ #undef CBZ_L2T_INTERPOLATION /**************************************************************************** * ClutterBezier -- represenation of a cubic bezier curve * * (private; a building block for the public bspline object) * ****************************************************************************/ /* * The t parameter of the bezier is from interval <0,1>, so we can use * 14.18 format and special multiplication functions that preserve * more of the least significant bits but would overflow if the value * is > 1 */ #define CBZ_T_Q 18 #define CBZ_T_ONE (1 << CBZ_T_Q) #define CBZ_T_MUL(x,y) ((((x) >> 3) * ((y) >> 3)) >> 12) #define CBZ_T_POW2(x) CBZ_T_MUL (x, x) #define CBZ_T_POW3(x) CBZ_T_MUL (CBZ_T_POW2 (x), x) #define CBZ_T_DIV(x,y) ((((x) << 9)/(y)) << 9) /* * Constants for sampling of the bezier */ #define CBZ_T_SAMPLES 128 #define CBZ_T_STEP (CBZ_T_ONE / CBZ_T_SAMPLES) #define CBZ_L_STEP (CBZ_T_ONE / CBZ_T_SAMPLES) #define FIXED_BITS (32) #define FIXED_Q (FIXED_BITS - 16) #define FIXED_FROM_INT(x) ((x) << FIXED_Q) typedef gint32 _FixedT; /* * This is a private type representing a single cubic bezier */ struct _ClutterBezier { /* * bezier coefficients -- these are calculated using multiplication and * addition from integer input, so these are also integers */ gint ax; gint bx; gint cx; gint dx; gint ay; gint by; gint cy; gint dy; /* length of the bezier */ guint length; #ifdef CBZ_L2T_INTERPOLATION /* * coefficients for the L -> t bezier; these are calculated from fixed * point input, and more specifically numbers that have been normalised * to fit <0,1>, so these are also fixed point, and we can used the * _FixedT type here. */ _FixedT La; _FixedT Lb; _FixedT Lc; /* _FixedT Ld; == 0 */ #endif }; ClutterBezier * _clutter_bezier_new (void) { return g_slice_new0 (ClutterBezier); } void _clutter_bezier_free (ClutterBezier * b) { if (G_LIKELY (b)) { g_slice_free (ClutterBezier, b); } } ClutterBezier * _clutter_bezier_clone_and_move (const ClutterBezier *b, gint x, gint y) { ClutterBezier * b2 = _clutter_bezier_new (); memcpy (b2, b, sizeof (ClutterBezier)); b2->dx += x; b2->dy += y; return b2; } #ifdef CBZ_L2T_INTERPOLATION /* * L is relative advance along the bezier curve from interval <0,1> */ static _FixedT _clutter_bezier_L2t (const ClutterBezier *b, _FixedT L) { _FixedT t = CBZ_T_MUL (b->La, CBZ_T_POW3(L)) + CBZ_T_MUL (b->Lb, CBZ_T_POW2(L)) + CBZ_T_MUL (b->Lc, L); if (t > CBZ_T_ONE) t = CBZ_T_ONE; else if (t < 0) t = 0; return t; } #endif static gint _clutter_bezier_t2x (const ClutterBezier * b, _FixedT t) { /* * NB -- the int coefficients can be at most 8192 for the multiplication * to work in this fashion due to the limits of the 14.18 fixed. */ return ((b->ax*CBZ_T_POW3(t) + b->bx*CBZ_T_POW2(t) + b->cx*t) >> CBZ_T_Q) + b->dx; } static gint _clutter_bezier_t2y (const ClutterBezier * b, _FixedT t) { /* * NB -- the int coefficients can be at most 8192 for the multiplication * to work in this fashion due to the limits of the 14.18 fixed. */ return ((b->ay*CBZ_T_POW3(t) + b->by*CBZ_T_POW2(t) + b->cy*t) >> CBZ_T_Q) + b->dy; } /* * Advances along the bezier to relative length L and returns the coordinances * in knot */ void _clutter_bezier_advance (const ClutterBezier *b, gint L, ClutterKnot * knot) { #ifdef CBZ_L2T_INTERPOLATION _FixedT t = clutter_bezier_L2t (b, L); #else _FixedT t = L; #endif knot->x = _clutter_bezier_t2x (b, t); knot->y = _clutter_bezier_t2y (b, t); CLUTTER_NOTE (MISC, "advancing to relative pt %f: t %f, {%d,%d}", (double) L / (double) CBZ_T_ONE, (double) t / (double) CBZ_T_ONE, knot->x, knot->y); } static int sqrti (int number) { #if defined __SSE2__ /* The GCC built-in with SSE2 (sqrtsd) is up to twice as fast as * the pure integer code below. It is also more accurate. */ return __builtin_sqrt (number); #else /* This is a fixed point implementation of the Quake III sqrt algorithm, * described, for example, at * http://www.codemaestro.com/reviews/review00000105.html * * While the original QIII is extremely fast, the use of floating division * and multiplication makes it perform very on arm processors without FPU. * * The key to successfully replacing the floating point operations with * fixed point is in the choice of the fixed point format. The QIII * algorithm does not calculate the square root, but its reciprocal ('y' * below), which is only at the end turned to the inverse value. In order * for the algorithm to produce satisfactory results, the reciprocal value * must be represented with sufficient precission; the 16.16 we use * elsewhere in clutter is not good enough, and 10.22 is used instead. */ _FixedT x; uint32_t y_1; /* 10.22 fixed point */ uint32_t f = 0x600000; /* '1.5' as 10.22 fixed */ union { float f; uint32_t i; } flt, flt2; flt.f = number; x = FIXED_FROM_INT (number) / 2; /* The QIII initial estimate */ flt.i = 0x5f3759df - ( flt.i >> 1 ); /* Now, we convert the float to 10.22 fixed. We exploit the mechanism * described at http://www.d6.com/users/checker/pdfs/gdmfp.pdf. * * We want 22 bit fraction; a single precission float uses 23 bit * mantisa, so we only need to add 2^(23-22) (no need for the 1.5 * multiplier as we are only dealing with positive numbers). * * Note: we have to use two separate variables here -- for some reason, * if we try to use just the flt variable, gcc on ARM optimises the whole * addition out, and it all goes pear shape, since without it, the bits * in the float will not be correctly aligned. */ flt2.f = flt.f + 2.0; flt2.i &= 0x7FFFFF; /* Now we correct the estimate */ y_1 = (flt2.i >> 11) * (flt2.i >> 11); y_1 = (y_1 >> 8) * (x >> 8); y_1 = f - y_1; flt2.i = (flt2.i >> 11) * (y_1 >> 11); /* If the original argument is less than 342, we do another * iteration to improve precission (for arguments >= 342, the single * iteration produces generally better results). */ if (x < 171) { y_1 = (flt2.i >> 11) * (flt2.i >> 11); y_1 = (y_1 >> 8) * (x >> 8); y_1 = f - y_1; flt2.i = (flt2.i >> 11) * (y_1 >> 11); } /* Invert, round and convert from 10.22 to an integer * 0x1e3c68 is a magical rounding constant that produces slightly * better results than 0x200000. */ return (number * flt2.i + 0x1e3c68) >> 22; #endif } void _clutter_bezier_init (ClutterBezier *b, gint x_0, gint y_0, gint x_1, gint y_1, gint x_2, gint y_2, gint x_3, gint y_3) { _FixedT t; int i; int xp = x_0; int yp = y_0; _FixedT length [CBZ_T_SAMPLES + 1]; #ifdef CBZ_L2T_INTERPOLATION int j, k; _FixedT L; _FixedT t_equalized [CBZ_T_SAMPLES + 1]; #endif #if 0 g_debug ("Initializing bezier at {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}", x0, y0, x1, y1, x2, y2, x3, y3); #endif b->dx = x_0; b->dy = y_0; b->cx = 3 * (x_1 - x_0); b->cy = 3 * (y_1 - y_0); b->bx = 3 * (x_2 - x_1) - b->cx; b->by = 3 * (y_2 - y_1) - b->cy; b->ax = x_3 - 3 * x_2 + 3 * x_1 - x_0; b->ay = y_3 - 3 * y_2 + 3 * y_1 - y_0; #if 0 g_debug ("Cooeficients {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}", b->ax, b->ay, b->bx, b->by, b->cx, b->cy, b->dx, b->dy); #endif /* * Because of the way we do the multiplication in bezeir_t2x,y * these coefficients need to be at most 0x1fff; this should be the case, * I think, but have added this warning to catch any problems -- if it * triggers, we need to change those two functions a bit. */ if (b->ax > 0x1fff || b->bx > 0x1fff || b->cx > 0x1fff) g_warning ("Calculated coefficients will result in multiplication " "overflow in clutter_bezier_t2x and clutter_bezier_t2y."); /* * Sample the bezier with CBZ_T_SAMPLES and calculate length at * each point. * * We are working with integers here, so we use the fast sqrti function. */ length[0] = 0; for (t = CBZ_T_STEP, i = 1; i <= CBZ_T_SAMPLES; ++i, t += CBZ_T_STEP) { int x = _clutter_bezier_t2x (b, t); int y = _clutter_bezier_t2y (b, t); guint l = sqrti ((y - yp)*(y - yp) + (x - xp)*(x - xp)); l += length[i-1]; length[i] = l; xp = x; yp = y; } b->length = length[CBZ_T_SAMPLES]; #if 0 g_debug ("length %d", b->length); #endif #ifdef CBZ_L2T_INTERPOLATION /* * Now normalize the length values, converting them into _FixedT */ for (i = 0; i <= CBZ_T_SAMPLES; ++i) { length[i] = (length[i] << CBZ_T_Q) / b->length; } /* * Now generate a L -> t table such that the L will equidistant * over <0,1> */ t_equalized[0] = 0; for (i = 1, j = 1, L = CBZ_L_STEP; i < CBZ_T_SAMPLES; ++i, L += CBZ_L_STEP) { _FixedT l1, l2; _FixedT d1, d2, d; _FixedT t1, t2; /* find the band for our L */ for (k = j; k < CBZ_T_SAMPLES; ++k) { if (L < length[k]) break; } /* * Now we know that L is from (length[k-1],length[k]> * We remember k-1 in order not to have to iterate over the * whole length array in the next iteration of the main loop */ j = k - 1; /* * Now interpolate equlised t as a weighted average */ l1 = length[k-1]; l2 = length[k]; d1 = l2 - L; d2 = L - l1; d = l2 - l1; t1 = (k - 1) * CBZ_T_STEP; t2 = k * CBZ_T_STEP; t_equalized[i] = (t1*d1 + t2*d2)/d; if (t_equalized[i] < t_equalized[i-1]) g_debug ("wrong t: L %f, l1 %f, l2 %f, t1 %f, t2 %f", (double) (L)/(double)CBZ_T_ONE, (double) (l1)/(double)CBZ_T_ONE, (double) (l2)/(double)CBZ_T_ONE, (double) (t1)/(double)CBZ_T_ONE, (double) (t2)/(double)CBZ_T_ONE); } t_equalized[CBZ_T_SAMPLES] = CBZ_T_ONE; /* We now fit a bezier -- at this stage, do a single fit through our values * at 0, 1/3, 2/3 and 1 * * FIXME -- do we need to use a better fitting approach to choose the best * beziere. The actual curve we acquire this way is not too bad shapwise, * but (probably due to rounding errors) the resulting curve no longer * satisfies the necessary condition that for L2 > L1, t2 > t1, which * causes oscilation. */ #if 0 /* * These are the control points we use to calculate the curve coefficients * for bezier t(L); these are not needed directly, but are implied in the * calculations below. * * (p0 is 0,0, and p3 is 1,1) */ p1 = (18 * t_equalized[CBZ_T_SAMPLES/3] - 9 * t_equalized[2*CBZ_T_SAMPLES/3] + 2 << CBZ_T_Q) / 6; p2 = (18 * t_equalized[2*CBZ_T_SAMPLES/3] - 9 * t_equalized[CBZ_T_SAMPLES/3] - (5 << CBZ_T_Q)) / 6; #endif b->Lc = (18 * t_equalized[CBZ_T_SAMPLES/3] - 9 * t_equalized[2*CBZ_T_SAMPLES/3] + (2 << CBZ_T_Q)) >> 1; b->Lb = (36 * t_equalized[2*CBZ_T_SAMPLES/3] - 45 * t_equalized[CBZ_T_SAMPLES/3] - (9 << CBZ_T_Q)) >> 1; b->La = ((27 * (t_equalized[CBZ_T_SAMPLES/3] - t_equalized[2*CBZ_T_SAMPLES/3]) + (7 << CBZ_T_Q)) >> 1) + CBZ_T_ONE; g_debug ("t(1/3) %f, t(2/3) %f", (double)t_equalized[CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE, (double)t_equalized[2*CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE); g_debug ("L -> t coefficients: %f, %f, %f", (double)b->La/(double)CBZ_T_ONE, (double)b->Lb/(double)CBZ_T_ONE, (double)b->Lc/(double)CBZ_T_ONE); /* * For debugging, you can load these values into a spreadsheet and graph * them to see how well the approximation matches the data */ for (i = 0; i < CBZ_T_SAMPLES; ++i) { g_print ("%f, %f, %f\n", (double)(i*CBZ_T_STEP)/(double)CBZ_T_ONE, (double)(t_equalized[i])/(double)CBZ_T_ONE, (double)(clutter_bezier_L2t(b,i*CBZ_T_STEP))/(double)CBZ_T_ONE); } #endif } /* * Moves a control point at indx to location represented by knot */ void _clutter_bezier_adjust (ClutterBezier * b, ClutterKnot * knot, guint indx) { guint x[4], y[4]; g_assert (indx < 4); x[0] = b->dx; y[0] = b->dy; x[1] = b->cx / 3 + x[0]; y[1] = b->cy / 3 + y[0]; x[2] = b->bx / 3 + b->cx + x[1]; y[2] = b->by / 3 + b->cy + y[1]; x[3] = b->ax + x[0] + b->cx + b->bx; y[3] = b->ay + y[0] + b->cy + b->by; x[indx] = knot->x; y[indx] = knot->y; _clutter_bezier_init (b, x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3]); } guint _clutter_bezier_get_length (const ClutterBezier *b) { return b->length; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-test-utils.c���������������������������������������������������0000664�0001750�0001750�00000026717�14211404421�022256� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "clutter-build-config.h" #include "clutter-test-utils.h" #include <stdlib.h> #include <glib-object.h> #include "clutter-actor.h" #include "clutter-color.h" #include "clutter-event.h" #include "clutter-keysyms.h" #include "clutter-main.h" #include "clutter-private.h" #include "clutter-stage.h" typedef struct { ClutterActor *stage; guint no_display : 1; } ClutterTestEnvironment; static ClutterTestEnvironment *test_environ = NULL; /* * clutter_test_init: * @argc: (inout): number of arguments in @argv * @argv: (inout) (array length=argc) (nullable): array of arguments * * Initializes the Clutter test environment. * * Since: 1.18 */ void clutter_test_init (int *argc, char ***argv) { gboolean no_display = FALSE; if (G_UNLIKELY (test_environ != NULL)) g_error ("Attempting to initialize the test suite more than once, " "aborting...\n"); #ifdef CLUTTER_WINDOWING_X11 /* on X11 backends we need the DISPLAY environment set. * * check_windowing_backend() will pre-initialize the Clutter * backend object. */ if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11)) { const char *display = g_getenv ("DISPLAY"); if (display == NULL || *display == '\0') { g_test_message ("No DISPLAY environment variable found, but we require a " "DISPLAY set in order to run the conformance test suite.\n" "Skipping all tests.\n"); no_display = TRUE; goto out; } } #endif /* we explicitly disable the synchronisation to the vertical refresh * rate, and run the master clock using a 60 fps timer instead. */ _clutter_set_sync_to_vblank (FALSE); /* perform the actual initialization */ g_assert (clutter_init (NULL, NULL) == CLUTTER_INIT_SUCCESS); out: g_test_init (argc, argv, NULL); g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=%s"); /* our global state, accessible from each test unit */ test_environ = g_new0 (ClutterTestEnvironment, 1); test_environ->no_display = no_display; } /** * clutter_test_get_stage: * * Retrieves the #ClutterStage used for testing. * * Return value: (transfer none): the stage used for testing * * Since: 1.18 */ ClutterActor * clutter_test_get_stage (void) { g_assert (test_environ != NULL); if (test_environ->stage == NULL) { /* create a stage, and ensure that it goes away at the end */ test_environ->stage = clutter_stage_new (); clutter_actor_set_name (test_environ->stage, "Test Stage"); g_object_add_weak_pointer (G_OBJECT (test_environ->stage), (gpointer *) &test_environ->stage); } return test_environ->stage; } typedef struct { gpointer test_func; gpointer test_data; GDestroyNotify test_notify; } ClutterTestData; static void clutter_test_func_wrapper (gconstpointer data_) { const ClutterTestData *data = data_; /* ensure that the previous test state has been cleaned up */ g_assert_null (test_environ->stage); if (test_environ->no_display) { g_test_skip ("No DISPLAY set"); goto out; } if (data->test_data != NULL) { GTestDataFunc test_func = data->test_func; test_func (data->test_data); } else { GTestFunc test_func = data->test_func; test_func (); } out: if (data->test_notify != NULL) data->test_notify (data->test_data); if (test_environ->stage != NULL) { clutter_actor_destroy (test_environ->stage); g_assert_null (test_environ->stage); } } /** * clutter_test_add: (skip) * @test_path: unique path for identifying the test * @test_func: function containing the test * * Adds a test unit to the Clutter test environment. * * See also: g_test_add() * * Since: 1.18 */ void clutter_test_add (const char *test_path, GTestFunc test_func) { clutter_test_add_data_full (test_path, (GTestDataFunc) test_func, NULL, NULL); } /** * clutter_test_add_data: (skip) * @test_path: unique path for identifying the test * @test_func: function containing the test * @test_data: data to pass to the test function * * Adds a test unit to the Clutter test environment. * * See also: g_test_add_data_func() * * Since: 1.18 */ void clutter_test_add_data (const char *test_path, GTestDataFunc test_func, gpointer test_data) { clutter_test_add_data_full (test_path, test_func, test_data, NULL); } /** * clutter_test_add_data_full: * @test_path: unique path for identifying the test * @test_func: (scope notified): function containing the test * @test_data: (closure): data to pass to the test function * @test_notify: function called when the test function ends * * Adds a test unit to the Clutter test environment. * * See also: g_test_add_data_func_full() * * Since: 1.18 */ void clutter_test_add_data_full (const char *test_path, GTestDataFunc test_func, gpointer test_data, GDestroyNotify test_notify) { ClutterTestData *data; g_return_if_fail (test_path != NULL); g_return_if_fail (test_func != NULL); g_assert (test_environ != NULL); data = g_new (ClutterTestData, 1); data->test_func = test_func; data->test_data = test_data; data->test_notify = test_notify; g_test_add_data_func_full (test_path, data, clutter_test_func_wrapper, free); } /** * clutter_test_run: * * Runs the test suite using the units added by calling * clutter_test_add(). * * The typical test suite is composed of a list of functions * called by clutter_test_run(), for instance: * * |[ * static void unit_foo (void) { ... } * * static void unit_bar (void) { ... } * * static void unit_baz (void) { ... } * * int * main (int argc, char *argv[]) * { * clutter_test_init (&argc, &argv); * * clutter_test_add ("/unit/foo", unit_foo); * clutter_test_add ("/unit/bar", unit_bar); * clutter_test_add ("/unit/baz", unit_baz); * * return clutter_test_run (); * } * ]| * * Return value: the exit code for the test suite * * Since: 1.18 */ int clutter_test_run (void) { int res; g_assert (test_environ != NULL); res = g_test_run (); free (test_environ); return res; } typedef struct { ClutterActor *stage; ClutterPoint point; gpointer result; guint check_actor : 1; guint check_color : 1; guint was_painted : 1; } ValidateData; static gboolean validate_stage (gpointer data_) { ValidateData *data = data_; if (data->check_actor) { data->result = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (data->stage), CLUTTER_PICK_ALL, data->point.x, data->point.y); } if (data->check_color) { data->result = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage), data->point.x, data->point.y, 1, 1); } if (!g_test_verbose ()) { clutter_actor_hide (data->stage); data->was_painted = TRUE; } return G_SOURCE_REMOVE; } static gboolean on_key_press_event (ClutterActor *stage, ClutterEvent *event, gpointer data_) { ValidateData *data = data_; if (data->stage == stage && clutter_event_get_key_symbol (event) == CLUTTER_KEY_Escape) { clutter_actor_hide (stage); data->was_painted = TRUE; } return CLUTTER_EVENT_PROPAGATE; } /** * clutter_test_check_actor_at_point: * @stage: a #ClutterStage * @point: coordinates to check * @actor: the expected actor at the given coordinates * @result: (out) (nullable): actor at the coordinates * * Checks the given coordinates of the @stage and compares the * actor found there with the given @actor. * * Returns: %TRUE if the actor at the given coordinates matches * * Since: 1.18 */ gboolean clutter_test_check_actor_at_point (ClutterActor *stage, const ClutterPoint *point, ClutterActor *actor, ClutterActor **result) { ValidateData *data; guint press_id = 0; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (point != NULL, FALSE); g_return_val_if_fail (CLUTTER_IS_ACTOR (stage), FALSE); g_return_val_if_fail (result != NULL, FALSE); data = g_new0 (ValidateData, 1); data->stage = stage; data->point = *point; data->check_actor = TRUE; if (g_test_verbose ()) { g_printerr ("Press ESC to close the stage and resume the test\n"); press_id = g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press_event), data); } clutter_actor_show (stage); clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT, validate_stage, data, NULL); while (!data->was_painted) g_main_context_iteration (NULL, TRUE); *result = data->result; if (press_id != 0) g_signal_handler_disconnect (stage, press_id); free (data); return *result == actor; } /** * clutter_test_check_color_at_point: * @stage: a #ClutterStage * @point: coordinates to check * @color: expected color * @result: (out caller-allocates): color at the given coordinates * * Checks the color at the given coordinates on @stage, and matches * it with the red, green, and blue channels of @color. The alpha * component of @color and @result is ignored. * * Returns: %TRUE if the colors match * * Since: 1.18 */ gboolean clutter_test_check_color_at_point (ClutterActor *stage, const ClutterPoint *point, const ClutterColor *color, ClutterColor *result) { ValidateData *data; gboolean retval; guint8 *buffer; guint press_id = 0; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (point != NULL, FALSE); g_return_val_if_fail (color != NULL, FALSE); g_return_val_if_fail (result != NULL, FALSE); data = g_new0 (ValidateData, 1); data->stage = stage; data->point = *point; data->check_color = TRUE; if (g_test_verbose ()) { g_printerr ("Press ESC to close the stage and resume the test\n"); press_id = g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press_event), data); } clutter_actor_show (stage); clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT, validate_stage, data, NULL); while (!data->was_painted) g_main_context_iteration (NULL, TRUE); if (press_id != 0) g_signal_handler_disconnect (stage, press_id); buffer = data->result; clutter_color_init (result, buffer[0], buffer[1], buffer[2], 255); /* we only check the color channels, so we can't use clutter_color_equal() */ retval = buffer[0] == color->red && buffer[1] == color->green && buffer[2] == color->blue; free (data->result); free (data); return retval; } �������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-actor-meta-private.h�������������������������������������������0000664�0001750�0001750�00000007432�14211404421�023643� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_ACTOR_META_PRIVATE_H__ #define __CLUTTER_ACTOR_META_PRIVATE_H__ #include <clutter/clutter-actor-meta.h> G_BEGIN_DECLS #define CLUTTER_TYPE_META_GROUP (_clutter_meta_group_get_type ()) #define CLUTTER_META_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_META_GROUP, ClutterMetaGroup)) #define CLUTTER_IS_META_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_META_GROUP)) typedef struct _ClutterMetaGroup ClutterMetaGroup; typedef struct _ClutterMetaGroupClass ClutterMetaGroupClass; struct _ClutterMetaGroup { GObject parent_instance; ClutterActor *actor; GList *meta; }; struct _ClutterMetaGroupClass { GObjectClass parent_class; }; /* Each actor meta has a priority with zero as a default. A higher number means higher priority. Higher priority metas stay at the beginning of the list. The priority can be negative to give lower priority than the default. */ #define CLUTTER_ACTOR_META_PRIORITY_DEFAULT 0 /* Any value greater than this is considered an 'internal' priority and if we expose the priority property publicly then an application would not be able to use these values. */ #define CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH (G_MAXINT / 2) #define CLUTTER_ACTOR_META_PRIORITY_INTERNAL_LOW (G_MININT / 2) GType _clutter_meta_group_get_type (void) G_GNUC_CONST; void _clutter_meta_group_add_meta (ClutterMetaGroup *group, ClutterActorMeta *meta); void _clutter_meta_group_remove_meta (ClutterMetaGroup *group, ClutterActorMeta *meta); const GList * _clutter_meta_group_peek_metas (ClutterMetaGroup *group); void _clutter_meta_group_clear_metas (ClutterMetaGroup *group); ClutterActorMeta * _clutter_meta_group_get_meta (ClutterMetaGroup *group, const gchar *name); gboolean _clutter_meta_group_has_metas_no_internal (ClutterMetaGroup *group); GList * _clutter_meta_group_get_metas_no_internal (ClutterMetaGroup *group); void _clutter_meta_group_clear_metas_no_internal (ClutterMetaGroup *group); /* ActorMeta */ void _clutter_actor_meta_set_actor (ClutterActorMeta *meta, ClutterActor *actor); const gchar * _clutter_actor_meta_get_debug_name (ClutterActorMeta *meta); void _clutter_actor_meta_set_priority (ClutterActorMeta *meta, gint priority); int _clutter_actor_meta_get_priority (ClutterActorMeta *meta); gboolean _clutter_actor_meta_is_internal (ClutterActorMeta *meta); G_END_DECLS #endif /* __CLUTTER_ACTOR_META_PRIVATE_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-text-buffer.h��������������������������������������������������0000664�0001750�0001750�00000016234�14211404421�022372� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* clutter-text-buffer.h * Copyright (C) 2011 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. * * Author: Stef Walter <stefw@collabora.co.uk> */ #ifndef __CLUTTER_TEXT_BUFFER_H__ #define __CLUTTER_TEXT_BUFFER_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_TEXT_BUFFER (clutter_text_buffer_get_type ()) #define CLUTTER_TEXT_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXT_BUFFER, ClutterTextBuffer)) #define CLUTTER_TEXT_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TEXT_BUFFER, ClutterTextBufferClass)) #define CLUTTER_IS_TEXT_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXT_BUFFER)) #define CLUTTER_IS_TEXT_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TEXT_BUFFER)) #define CLUTTER_TEXT_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TEXT_BUFFER, ClutterTextBufferClass)) /** * CLUTTER_TEXT_BUFFER_MAX_SIZE: * * Maximum size of text buffer, in bytes. * * Since: 1.10 */ #define CLUTTER_TEXT_BUFFER_MAX_SIZE G_MAXUSHORT typedef struct _ClutterTextBuffer ClutterTextBuffer; typedef struct _ClutterTextBufferClass ClutterTextBufferClass; typedef struct _ClutterTextBufferPrivate ClutterTextBufferPrivate; /** * ClutterTextBuffer: * * The #ClutterTextBuffer structure contains private * data and it should only be accessed using the provided API. * * Since: 1.10 */ struct _ClutterTextBuffer { /*< private >*/ GObject parent_instance; ClutterTextBufferPrivate *priv; }; /** * ClutterTextBufferClass: * @inserted_text: default handler for the #ClutterTextBuffer::inserted-text signal * @deleted_text: default hanlder for the #ClutterTextBuffer::deleted-text signal * @get_text: virtual function * @get_length: virtual function * @insert_text: virtual function * @delete_text: virtual function * * The #ClutterTextBufferClass structure contains * only private data. * * Since: 1.10 */ struct _ClutterTextBufferClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ /* Signals */ void (*inserted_text) (ClutterTextBuffer *buffer, guint position, const gchar *chars, guint n_chars); void (*deleted_text) (ClutterTextBuffer *buffer, guint position, guint n_chars); /* Virtual Methods */ const gchar* (*get_text) (ClutterTextBuffer *buffer, gsize *n_bytes); guint (*get_length) (ClutterTextBuffer *buffer); guint (*insert_text) (ClutterTextBuffer *buffer, guint position, const gchar *chars, guint n_chars); guint (*delete_text) (ClutterTextBuffer *buffer, guint position, guint n_chars); /*< private >*/ /* Padding for future expansion */ void (*_clutter_reserved1) (void); void (*_clutter_reserved2) (void); void (*_clutter_reserved3) (void); void (*_clutter_reserved4) (void); void (*_clutter_reserved5) (void); void (*_clutter_reserved6) (void); void (*_clutter_reserved7) (void); void (*_clutter_reserved8) (void); }; CLUTTER_AVAILABLE_IN_1_10 GType clutter_text_buffer_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterTextBuffer* clutter_text_buffer_new (void); CLUTTER_AVAILABLE_IN_1_10 ClutterTextBuffer* clutter_text_buffer_new_with_text (const gchar *text, gssize text_len); CLUTTER_AVAILABLE_IN_1_10 gsize clutter_text_buffer_get_bytes (ClutterTextBuffer *buffer); CLUTTER_AVAILABLE_IN_1_10 guint clutter_text_buffer_get_length (ClutterTextBuffer *buffer); CLUTTER_AVAILABLE_IN_1_10 const gchar* clutter_text_buffer_get_text (ClutterTextBuffer *buffer); CLUTTER_AVAILABLE_IN_1_10 void clutter_text_buffer_set_text (ClutterTextBuffer *buffer, const gchar *chars, gint n_chars); CLUTTER_AVAILABLE_IN_1_10 void clutter_text_buffer_set_max_length (ClutterTextBuffer *buffer, gint max_length); CLUTTER_AVAILABLE_IN_1_10 gint clutter_text_buffer_get_max_length (ClutterTextBuffer *buffer); CLUTTER_AVAILABLE_IN_1_10 guint clutter_text_buffer_insert_text (ClutterTextBuffer *buffer, guint position, const gchar *chars, gint n_chars); CLUTTER_AVAILABLE_IN_1_10 guint clutter_text_buffer_delete_text (ClutterTextBuffer *buffer, guint position, gint n_chars); CLUTTER_AVAILABLE_IN_1_10 void clutter_text_buffer_emit_inserted_text (ClutterTextBuffer *buffer, guint position, const gchar *chars, guint n_chars); CLUTTER_AVAILABLE_IN_1_10 void clutter_text_buffer_emit_deleted_text (ClutterTextBuffer *buffer, guint position, guint n_chars); G_END_DECLS #endif /* __CLUTTER_TEXT_BUFFER_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-zoom-action.h��������������������������������������������������0000664�0001750�0001750�00000010022�14211404421�022363� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com> */ #ifndef __CLUTTER_ZOOM_ACTION_H__ #define __CLUTTER_ZOOM_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-event.h> #include <clutter/clutter-gesture-action.h> #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_ZOOM_ACTION (clutter_zoom_action_get_type ()) #define CLUTTER_ZOOM_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ZOOM_ACTION, ClutterZoomAction)) #define CLUTTER_IS_ZOOM_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ZOOM_ACTION)) #define CLUTTER_ZOOM_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ZOOM_ACTION, ClutterZoomActionClass)) #define CLUTTER_IS_ZOOM_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ZOOM_ACTION)) #define CLUTTER_ZOOM_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ZOOM_ACTION, ClutterZoomActionClass)) typedef struct _ClutterZoomAction ClutterZoomAction; typedef struct _ClutterZoomActionPrivate ClutterZoomActionPrivate; typedef struct _ClutterZoomActionClass ClutterZoomActionClass; /** * ClutterZoomAction: * * The #ClutterZoomAction structure contains only * private data and should be accessed using the provided API * * Since: 1.12 */ struct _ClutterZoomAction { /*< private >*/ ClutterGestureAction parent_instance; ClutterZoomActionPrivate *priv; }; /** * ClutterZoomActionClass: * @zoom: class handler of the #ClutterZoomAction::zoom signal * * The #ClutterZoomActionClass structure contains * only private data * * Since: 1.12 */ struct _ClutterZoomActionClass { /*< private >*/ ClutterGestureActionClass parent_class; /*< public >*/ gboolean (* zoom) (ClutterZoomAction *action, ClutterActor *actor, ClutterPoint *focal_point, gdouble factor); /*< private >*/ void (* _clutter_zoom_action1) (void); void (* _clutter_zoom_action2) (void); void (* _clutter_zoom_action3) (void); void (* _clutter_zoom_action4) (void); void (* _clutter_zoom_action5) (void); }; CLUTTER_AVAILABLE_IN_1_12 GType clutter_zoom_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterAction * clutter_zoom_action_new (void); CLUTTER_AVAILABLE_IN_1_12 void clutter_zoom_action_set_zoom_axis (ClutterZoomAction *action, ClutterZoomAxis axis); CLUTTER_AVAILABLE_IN_1_12 ClutterZoomAxis clutter_zoom_action_get_zoom_axis (ClutterZoomAction *action); CLUTTER_AVAILABLE_IN_1_12 void clutter_zoom_action_get_focal_point (ClutterZoomAction *action, ClutterPoint *point); CLUTTER_AVAILABLE_IN_1_12 void clutter_zoom_action_get_transformed_focal_point (ClutterZoomAction *action, ClutterPoint *point); G_END_DECLS #endif /* __CLUTTER_ZOOM_ACTION_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-align-constraint.c���������������������������������������������0000664�0001750�0001750�00000040025�14211404421�023401� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-align-constraint * @Title: ClutterAlignConstraint * @Short_Description: A constraint aligning the position of an actor * * #ClutterAlignConstraint is a #ClutterConstraint that aligns the position * of the #ClutterActor to which it is applied to the size of another * #ClutterActor using an alignment factor * * #ClutterAlignConstraint is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-align-constraint.h" #include "clutter-actor-meta-private.h" #include "clutter-actor-private.h" #include "clutter-constraint.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-private.h" #include <math.h> #define CLUTTER_ALIGN_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass)) #define CLUTTER_IS_ALIGN_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT)) #define CLUTTER_ALIGN_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass)) struct _ClutterAlignConstraint { ClutterConstraint parent_instance; ClutterActor *actor; ClutterActor *source; ClutterAlignAxis align_axis; gfloat factor; }; struct _ClutterAlignConstraintClass { ClutterConstraintClass parent_class; }; enum { PROP_0, PROP_SOURCE, PROP_ALIGN_AXIS, PROP_FACTOR, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterAlignConstraint, clutter_align_constraint, CLUTTER_TYPE_CONSTRAINT); static void source_position_changed (ClutterActor *actor, const ClutterActorBox *allocation, ClutterAllocationFlags flags, ClutterAlignConstraint *align) { if (align->actor != NULL) clutter_actor_queue_relayout (align->actor); } static void source_destroyed (ClutterActor *actor, ClutterAlignConstraint *align) { align->source = NULL; } static void clutter_align_constraint_set_actor (ClutterActorMeta *meta, ClutterActor *new_actor) { ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (meta); ClutterActorMetaClass *parent; if (new_actor != NULL && align->source != NULL && clutter_actor_contains (new_actor, align->source)) { g_warning (G_STRLOC ": The source actor '%s' is contained " "by the actor '%s' associated to the constraint " "'%s'", _clutter_actor_get_debug_name (align->source), _clutter_actor_get_debug_name (new_actor), _clutter_actor_meta_get_debug_name (meta)); return; } /* store the pointer to the actor, for later use */ align->actor = new_actor; parent = CLUTTER_ACTOR_META_CLASS (clutter_align_constraint_parent_class); parent->set_actor (meta, new_actor); } static void clutter_align_constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation) { ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (constraint); gfloat source_width, source_height; gfloat actor_width, actor_height; gfloat source_x, source_y; if (align->source == NULL) return; clutter_actor_box_get_size (allocation, &actor_width, &actor_height); clutter_actor_get_position (align->source, &source_x, &source_y); clutter_actor_get_size (align->source, &source_width, &source_height); switch (align->align_axis) { case CLUTTER_ALIGN_X_AXIS: allocation->x1 = ((source_width - actor_width) * align->factor) + source_x; allocation->x2 = allocation->x1 + actor_width; break; case CLUTTER_ALIGN_Y_AXIS: allocation->y1 = ((source_height - actor_height) * align->factor) + source_y; allocation->y2 = allocation->y1 + actor_height; break; case CLUTTER_ALIGN_BOTH: allocation->x1 = ((source_width - actor_width) * align->factor) + source_x; allocation->y1 = ((source_height - actor_height) * align->factor) + source_y; allocation->x2 = allocation->x1 + actor_width; allocation->y2 = allocation->y1 + actor_height; break; default: g_assert_not_reached (); break; } clutter_actor_box_clamp_to_pixel (allocation); } static void clutter_align_constraint_dispose (GObject *gobject) { ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (gobject); if (align->source != NULL) { g_signal_handlers_disconnect_by_func (align->source, G_CALLBACK (source_destroyed), align); g_signal_handlers_disconnect_by_func (align->source, G_CALLBACK (source_position_changed), align); align->source = NULL; } G_OBJECT_CLASS (clutter_align_constraint_parent_class)->dispose (gobject); } static void clutter_align_constraint_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (gobject); switch (prop_id) { case PROP_SOURCE: clutter_align_constraint_set_source (align, g_value_get_object (value)); break; case PROP_ALIGN_AXIS: clutter_align_constraint_set_align_axis (align, g_value_get_enum (value)); break; case PROP_FACTOR: clutter_align_constraint_set_factor (align, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_align_constraint_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (gobject); switch (prop_id) { case PROP_SOURCE: g_value_set_object (value, align->source); break; case PROP_ALIGN_AXIS: g_value_set_enum (value, align->align_axis); break; case PROP_FACTOR: g_value_set_float (value, align->factor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); ClutterConstraintClass *constraint_class = CLUTTER_CONSTRAINT_CLASS (klass); meta_class->set_actor = clutter_align_constraint_set_actor; constraint_class->update_allocation = clutter_align_constraint_update_allocation; /** * ClutterAlignConstraint:source: * * The #ClutterActor used as the source for the alignment. * * The #ClutterActor must not be a child or a grandchild of the actor * using the constraint. * * Since: 1.4 */ obj_props[PROP_SOURCE] = g_param_spec_object ("source", P_("Source"), P_("The source of the alignment"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterAlignConstraint:align-axis: * * The axis to be used to compute the alignment * * Since: 1.4 */ obj_props[PROP_ALIGN_AXIS] = g_param_spec_enum ("align-axis", P_("Align Axis"), P_("The axis to align the position to"), CLUTTER_TYPE_ALIGN_AXIS, CLUTTER_ALIGN_X_AXIS, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * ClutterAlignConstraint:factor: * * The alignment factor, as a normalized value between 0.0 and 1.0 * * The factor depends on the #ClutterAlignConstraint:align-axis property: * with an align-axis value of %CLUTTER_ALIGN_X_AXIS, 0.0 means left and * 1.0 means right; with a value of %CLUTTER_ALIGN_Y_AXIS, 0.0 means top * and 1.0 means bottom. * * Since: 1.4 */ obj_props[PROP_FACTOR] = g_param_spec_float ("factor", P_("Factor"), P_("The alignment factor, between 0.0 and 1.0"), 0.0, 1.0, 0.0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); gobject_class->dispose = clutter_align_constraint_dispose; gobject_class->set_property = clutter_align_constraint_set_property; gobject_class->get_property = clutter_align_constraint_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_align_constraint_init (ClutterAlignConstraint *self) { self->actor = NULL; self->source = NULL; self->align_axis = CLUTTER_ALIGN_X_AXIS; self->factor = 0.0f; } /** * clutter_align_constraint_new: * @source: (allow-none): the #ClutterActor to use as the source of the * alignment, or %NULL * @axis: the axis to be used to compute the alignment * @factor: the alignment factor, between 0.0 and 1.0 * * Creates a new constraint, aligning a #ClutterActor's position with * regards of the size of the actor to @source, with the given * alignment @factor * * Return value: the newly created #ClutterAlignConstraint * * Since: 1.4 */ ClutterConstraint * clutter_align_constraint_new (ClutterActor *source, ClutterAlignAxis axis, gfloat factor) { g_return_val_if_fail (source == NULL || CLUTTER_IS_ACTOR (source), NULL); return g_object_new (CLUTTER_TYPE_ALIGN_CONSTRAINT, "source", source, "align-axis", axis, "factor", factor, NULL); } /** * clutter_align_constraint_set_source: * @align: a #ClutterAlignConstraint * @source: (allow-none): a #ClutterActor, or %NULL to unset the source * * Sets the source of the alignment constraint * * Since: 1.4 */ void clutter_align_constraint_set_source (ClutterAlignConstraint *align, ClutterActor *source) { ClutterActor *old_source, *actor; ClutterActorMeta *meta; g_return_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align)); g_return_if_fail (source == NULL || CLUTTER_IS_ACTOR (source)); if (align->source == source) return; meta = CLUTTER_ACTOR_META (align); actor = clutter_actor_meta_get_actor (meta); if (actor != NULL && source != NULL) { if (clutter_actor_contains (actor, source)) { g_warning (G_STRLOC ": The source actor '%s' is contained " "by the actor '%s' associated to the constraint " "'%s'", _clutter_actor_get_debug_name (source), _clutter_actor_get_debug_name (actor), _clutter_actor_meta_get_debug_name (meta)); return; } } old_source = align->source; if (old_source != NULL) { g_signal_handlers_disconnect_by_func (old_source, G_CALLBACK (source_destroyed), align); g_signal_handlers_disconnect_by_func (old_source, G_CALLBACK (source_position_changed), align); } align->source = source; if (align->source != NULL) { g_signal_connect (align->source, "allocation-changed", G_CALLBACK (source_position_changed), align); g_signal_connect (align->source, "destroy", G_CALLBACK (source_destroyed), align); if (align->actor != NULL) clutter_actor_queue_relayout (align->actor); } g_object_notify_by_pspec (G_OBJECT (align), obj_props[PROP_SOURCE]); } /** * clutter_align_constraint_get_source: * @align: a #ClutterAlignConstraint * * Retrieves the source of the alignment * * Return value: (transfer none): the #ClutterActor used as the source * of the alignment * * Since: 1.4 */ ClutterActor * clutter_align_constraint_get_source (ClutterAlignConstraint *align) { g_return_val_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align), NULL); return align->source; } /** * clutter_align_constraint_set_align_axis: * @align: a #ClutterAlignConstraint * @axis: the axis to which the alignment refers to * * Sets the axis to which the alignment refers to * * Since: 1.4 */ void clutter_align_constraint_set_align_axis (ClutterAlignConstraint *align, ClutterAlignAxis axis) { g_return_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align)); if (align->align_axis == axis) return; align->align_axis = axis; if (align->actor != NULL) clutter_actor_queue_relayout (align->actor); g_object_notify_by_pspec (G_OBJECT (align), obj_props[PROP_ALIGN_AXIS]); } /** * clutter_align_constraint_get_align_axis: * @align: a #ClutterAlignConstraint * * Retrieves the value set using clutter_align_constraint_set_align_axis() * * Return value: the alignment axis * * Since: 1.4 */ ClutterAlignAxis clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align) { g_return_val_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align), CLUTTER_ALIGN_X_AXIS); return align->align_axis; } /** * clutter_align_constraint_set_factor: * @align: a #ClutterAlignConstraint * @factor: the alignment factor, between 0.0 and 1.0 * * Sets the alignment factor of the constraint * * The factor depends on the #ClutterAlignConstraint:align-axis property * and it is a value between 0.0 (meaning left, when * #ClutterAlignConstraint:align-axis is set to %CLUTTER_ALIGN_X_AXIS; or * meaning top, when #ClutterAlignConstraint:align-axis is set to * %CLUTTER_ALIGN_Y_AXIS) and 1.0 (meaning right, when * #ClutterAlignConstraint:align-axis is set to %CLUTTER_ALIGN_X_AXIS; or * meaning bottom, when #ClutterAlignConstraint:align-axis is set to * %CLUTTER_ALIGN_Y_AXIS). A value of 0.5 aligns in the middle in either * cases * * Since: 1.4 */ void clutter_align_constraint_set_factor (ClutterAlignConstraint *align, gfloat factor) { g_return_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align)); align->factor = CLAMP (factor, 0.0, 1.0); if (align->actor != NULL) clutter_actor_queue_relayout (align->actor); g_object_notify_by_pspec (G_OBJECT (align), obj_props[PROP_FACTOR]); } /** * clutter_align_constraint_get_factor: * @align: a #ClutterAlignConstraint * * Retrieves the factor set using clutter_align_constraint_set_factor() * * Return value: the alignment factor * * Since: 1.4 */ gfloat clutter_align_constraint_get_factor (ClutterAlignConstraint *align) { g_return_val_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align), 0.0); return align->factor; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-input-method.h�������������������������������������������������0000664�0001750�0001750�00000006767�14211404421�022566� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2017,2018 Red Hat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifndef __CLUTTER_INPUT_METHOD_H__ #define __CLUTTER_INPUT_METHOD_H__ #include <clutter/clutter.h> #define CLUTTER_TYPE_INPUT_METHOD (clutter_input_method_get_type ()) CLUTTER_AVAILABLE_IN_MUFFIN G_DECLARE_DERIVABLE_TYPE (ClutterInputMethod, clutter_input_method, CLUTTER, INPUT_METHOD, GObject) typedef struct _ClutterInputMethodClass ClutterInputMethodClass; struct _ClutterInputMethodClass { GObjectClass parent_class; void (* focus_in) (ClutterInputMethod *im, ClutterInputFocus *actor); void (* focus_out) (ClutterInputMethod *im); void (* reset) (ClutterInputMethod *im); void (* set_cursor_location) (ClutterInputMethod *im, const ClutterRect *rect); void (* set_surrounding) (ClutterInputMethod *im, const gchar *text, guint cursor, guint anchor); void (* update_content_hints) (ClutterInputMethod *im, ClutterInputContentHintFlags hint); void (* update_content_purpose) (ClutterInputMethod *im, ClutterInputContentPurpose purpose); gboolean (* filter_key_event) (ClutterInputMethod *im, const ClutterEvent *key); }; CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_focus_in (ClutterInputMethod *im, ClutterInputFocus *focus); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_focus_out (ClutterInputMethod *im); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_commit (ClutterInputMethod *im, const gchar *text); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_delete_surrounding (ClutterInputMethod *im, guint offset, guint len); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_request_surrounding (ClutterInputMethod *im); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_set_preedit_text (ClutterInputMethod *im, const gchar *preedit, guint cursor); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_notify_key_event (ClutterInputMethod *im, const ClutterEvent *event, gboolean filtered); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_method_request_toggle_input_panel (ClutterInputMethod *im); #endif /* __CLUTTER_INPUT_METHOD_H__ */ ���������muffin-5.2.1/clutter/clutter/clutter-tap-action.c���������������������������������������������������0000664�0001750�0001750�00000010055�14211404421�022164� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * Copyright (C) 2012 Collabora Ltd. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emanuele Aina <emanuele.aina@collabora.com> * * Based on ClutterPanAction * Based on ClutterDragAction, ClutterSwipeAction, and MxKineticScrollView, * written by: * Emmanuele Bassi <ebassi@linux.intel.com> * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> * Chris Lord <chris@linux.intel.com> */ /** * SECTION:clutter-tap-action * @Title: ClutterTapAction * @Short_Description: Action for tap gestures * * #ClutterTapAction is a sub-class of #ClutterGestureAction that implements * the logic for recognizing mouse clicks and touch tap gestures. * * The simplest usage of #ClutterTapAction consists in adding it to * a #ClutterActor, setting it as reactive and connecting a * callback for the #ClutterTapAction::tap signal, along the lines of the * following code: * * |[ * clutter_actor_add_action (actor, clutter_tap_action_new ()); * clutter_actor_set_reactive (actor, TRUE); * g_signal_connect (action, "tap", G_CALLBACK (on_tap_callback), NULL); * ]| * * Since: 1.14 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-tap-action.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-gesture-action-private.h" #include "clutter-marshal.h" #include "clutter-private.h" enum { TAP, LAST_SIGNAL }; static guint tap_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE (ClutterTapAction, clutter_tap_action, CLUTTER_TYPE_GESTURE_ACTION); static void emit_tap (ClutterTapAction *self, ClutterActor *actor) { g_signal_emit (self, tap_signals[TAP], 0, actor); } static void gesture_end (ClutterGestureAction *gesture, ClutterActor *actor) { emit_tap (CLUTTER_TAP_ACTION (gesture), actor); } static void clutter_tap_action_constructed (GObject *object) { clutter_gesture_action_set_threshold_trigger_edge (CLUTTER_GESTURE_ACTION (object), CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE); } static void clutter_tap_action_class_init (ClutterTapActionClass *klass) { ClutterGestureActionClass *gesture_class = CLUTTER_GESTURE_ACTION_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = clutter_tap_action_constructed; gesture_class->gesture_end = gesture_end; /** * ClutterTapAction::tap: * @action: the #ClutterTapAction that emitted the signal * @actor: the #ClutterActor attached to the @action * * The ::tap signal is emitted when the tap gesture is complete. * * Since: 1.14 */ tap_signals[TAP] = g_signal_new (I_("tap"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTapActionClass, tap), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); } static void clutter_tap_action_init (ClutterTapAction *self) { } /** * clutter_tap_action_new: * * Creates a new #ClutterTapAction instance * * Return value: the newly created #ClutterTapAction * * Since: 1.14 */ ClutterAction * clutter_tap_action_new (void) { return g_object_new (CLUTTER_TYPE_TAP_ACTION, NULL); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-property-transition.h������������������������������������������0000664�0001750�0001750�00000006537�14211404421�024220� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_PROPERTY_TRANSITION_H__ #define __CLUTTER_PROPERTY_TRANSITION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-transition.h> G_BEGIN_DECLS #define CLUTTER_TYPE_PROPERTY_TRANSITION (clutter_property_transition_get_type ()) #define CLUTTER_PROPERTY_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PROPERTY_TRANSITION, ClutterPropertyTransition)) #define CLUTTER_IS_PROPERTY_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PROPERTY_TRANSITION)) #define CLUTTER_PROPERTY_TRANSITION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_PROPERTY_TRANSITION, ClutterPropertyTransitionClass)) #define CLUTTER_IS_PROPERTY_TRANSITION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_PROPERTY_TRANSITION)) #define CLUTTER_PROPERTY_TRANSITION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_PROPERTY_TRANSITION, ClutterPropertyTransitionClass)) typedef struct _ClutterPropertyTransitionPrivate ClutterPropertyTransitionPrivate; typedef struct _ClutterPropertyTransitionClass ClutterPropertyTransitionClass; /** * ClutterPropertyTransition: * * The #ClutterPropertyTransition structure contains * private data and should only be accessed using the provided API. * * Since: 1.10 */ struct _ClutterPropertyTransition { /*< private >*/ ClutterTransition parent_instance; ClutterPropertyTransitionPrivate *priv; }; /** * ClutterPropertyTransitionClass: * * The #ClutterPropertyTransitionClass structure * contains private data. * * Since: 1.10 */ struct _ClutterPropertyTransitionClass { /*< private >*/ ClutterTransitionClass parent_class; gpointer _padding[8]; }; CLUTTER_AVAILABLE_IN_1_10 GType clutter_property_transition_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterTransition * clutter_property_transition_new (const char *property_name); CLUTTER_AVAILABLE_IN_1_10 void clutter_property_transition_set_property_name (ClutterPropertyTransition *transition, const char *property_name); CLUTTER_AVAILABLE_IN_1_10 const char * clutter_property_transition_get_property_name (ClutterPropertyTransition *transition); G_END_DECLS #endif /* __CLUTTER_PROPERTY_TRANSITION_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-config.h.in����������������������������������������������������0000664�0001750�0001750�00000000456�14211404421�022010� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #ifndef __CLUTTER_CONFIG_H__ #define __CLUTTER_CONFIG_H__ #include <glib.h> G_BEGIN_DECLS @CLUTTER_CONFIG_DEFINES@ G_END_DECLS #endif /* __CLUTTER_CONFIG_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-input-focus.h��������������������������������������������������0000664�0001750�0001750�00000006560�14211404421�022414� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2017,2018 Red Hat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #ifndef __CLUTTER_INPUT_FOCUS_H__ #define __CLUTTER_INPUT_FOCUS_H__ #include <clutter/clutter.h> #define CLUTTER_TYPE_INPUT_FOCUS (clutter_input_focus_get_type ()) CLUTTER_AVAILABLE_IN_MUFFIN G_DECLARE_DERIVABLE_TYPE (ClutterInputFocus, clutter_input_focus, CLUTTER, INPUT_FOCUS, GObject) struct _ClutterInputFocusClass { GObjectClass parent_class; GTypeInterface iface; void (* focus_in) (ClutterInputFocus *focus, ClutterInputMethod *input_method); void (* focus_out) (ClutterInputFocus *focus); void (* request_surrounding) (ClutterInputFocus *focus); void (* delete_surrounding) (ClutterInputFocus *focus, guint offset, guint len); void (* commit_text) (ClutterInputFocus *focus, const gchar *text); void (* set_preedit_text) (ClutterInputFocus *focus, const gchar *preedit, guint cursor); }; CLUTTER_AVAILABLE_IN_MUFFIN gboolean clutter_input_focus_is_focused (ClutterInputFocus *focus); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_focus_reset (ClutterInputFocus *focus); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_focus_set_cursor_location (ClutterInputFocus *focus, const ClutterRect *rect); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_focus_set_surrounding (ClutterInputFocus *focus, const gchar *text, guint cursor, guint anchor); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_focus_set_content_hints (ClutterInputFocus *focus, ClutterInputContentHintFlags hint); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_focus_set_content_purpose (ClutterInputFocus *focus, ClutterInputContentPurpose purpose); CLUTTER_AVAILABLE_IN_MUFFIN gboolean clutter_input_focus_filter_key_event (ClutterInputFocus *focus, const ClutterKeyEvent *key); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_focus_set_can_show_preedit (ClutterInputFocus *focus, gboolean can_show_preedit); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_input_focus_request_toggle_input_panel (ClutterInputFocus *focus); #endif /* __CLUTTER_INPUT_FOCUS_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-stage-view.c���������������������������������������������������0000664�0001750�0001750�00000025364�14211404421�022211� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. */ #include "clutter-build-config.h" #include "clutter/clutter-stage-view.h" #include <cairo-gobject.h> #include <math.h> enum { PROP_0, PROP_LAYOUT, PROP_FRAMEBUFFER, PROP_OFFSCREEN, PROP_SCALE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; typedef struct _ClutterStageViewPrivate { cairo_rectangle_int_t layout; float scale; CoglFramebuffer *framebuffer; CoglOffscreen *offscreen; CoglPipeline *pipeline; guint dirty_viewport : 1; guint dirty_projection : 1; } ClutterStageViewPrivate; G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageView, clutter_stage_view, G_TYPE_OBJECT) void clutter_stage_view_get_layout (ClutterStageView *view, cairo_rectangle_int_t *rect) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); *rect = priv->layout; } CoglFramebuffer * clutter_stage_view_get_framebuffer (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); if (priv->offscreen) return priv->offscreen; else return priv->framebuffer; } CoglFramebuffer * clutter_stage_view_get_onscreen (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); return priv->framebuffer; } static void clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_GET_CLASS (view); g_assert (priv->offscreen != NULL); if (priv->pipeline) return; priv->pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (priv->offscreen)); cogl_pipeline_set_layer_filters (priv->pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_layer_texture (priv->pipeline, 0, cogl_offscreen_get_texture (priv->offscreen)); cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); if (view_class->setup_offscreen_blit_pipeline) view_class->setup_offscreen_blit_pipeline (view, priv->pipeline); } void clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); g_clear_pointer (&priv->pipeline, cogl_object_unref); } void clutter_stage_view_blit_offscreen (ClutterStageView *view, const cairo_rectangle_int_t *rect) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); CoglMatrix matrix; clutter_stage_view_ensure_offscreen_blit_pipeline (view); cogl_framebuffer_push_matrix (priv->framebuffer); /* Set transform so 0,0 is on the top left corner and 1,1 on * the bottom right corner. */ cogl_matrix_init_identity (&matrix); cogl_matrix_translate (&matrix, -1, 1, 0); cogl_matrix_scale (&matrix, 2, -2, 0); cogl_framebuffer_set_projection_matrix (priv->framebuffer, &matrix); cogl_framebuffer_draw_rectangle (priv->framebuffer, priv->pipeline, 0, 0, 1, 1); cogl_framebuffer_pop_matrix (priv->framebuffer); } float clutter_stage_view_get_scale (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); return priv->scale; } gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); return priv->dirty_viewport; } void clutter_stage_view_set_dirty_viewport (ClutterStageView *view, gboolean dirty) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); priv->dirty_viewport = dirty; } gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); return priv->dirty_projection; } void clutter_stage_view_set_dirty_projection (ClutterStageView *view, gboolean dirty) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); priv->dirty_projection = dirty; } void clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view, CoglMatrix *matrix) { ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_GET_CLASS (view); view_class->get_offscreen_transformation_matrix (view, matrix); } void clutter_stage_view_transform_to_onscreen (ClutterStageView *view, gfloat *x, gfloat *y) { gfloat z = 0, w = 1; CoglMatrix matrix; clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix); cogl_matrix_get_inverse (&matrix, &matrix); cogl_matrix_transform_point (&matrix, x, y, &z, &w); } static void clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *view, CoglMatrix *matrix) { cogl_matrix_init_identity (matrix); } static void clutter_stage_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterStageView *view = CLUTTER_STAGE_VIEW (object); ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); switch (prop_id) { case PROP_LAYOUT: g_value_set_boxed (value, &priv->layout); break; case PROP_FRAMEBUFFER: g_value_set_boxed (value, priv->framebuffer); break; case PROP_OFFSCREEN: g_value_set_boxed (value, priv->offscreen); break; case PROP_SCALE: g_value_set_float (value, priv->scale); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clutter_stage_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterStageView *view = CLUTTER_STAGE_VIEW (object); ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); cairo_rectangle_int_t *layout; switch (prop_id) { case PROP_LAYOUT: layout = g_value_get_boxed (value); priv->layout = *layout; break; case PROP_FRAMEBUFFER: priv->framebuffer = g_value_dup_boxed (value); #ifndef G_DISABLE_CHECKS if (priv->framebuffer) { int fb_width, fb_height; fb_width = cogl_framebuffer_get_width (priv->framebuffer); fb_height = cogl_framebuffer_get_height (priv->framebuffer); g_warn_if_fail (fabsf (roundf (fb_width / priv->scale) - fb_width / priv->scale) < FLT_EPSILON); g_warn_if_fail (fabsf (roundf (fb_height / priv->scale) - fb_height / priv->scale) < FLT_EPSILON); } #endif break; case PROP_OFFSCREEN: priv->offscreen = g_value_dup_boxed (value); break; case PROP_SCALE: priv->scale = g_value_get_float (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clutter_stage_view_dispose (GObject *object) { ClutterStageView *view = CLUTTER_STAGE_VIEW (object); ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); g_clear_pointer (&priv->framebuffer, cogl_object_unref); g_clear_pointer (&priv->offscreen, cogl_object_unref); g_clear_pointer (&priv->pipeline, cogl_object_unref); G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object); } static void clutter_stage_view_init (ClutterStageView *view) { ClutterStageViewPrivate *priv = clutter_stage_view_get_instance_private (view); priv->dirty_viewport = TRUE; priv->dirty_projection = TRUE; priv->scale = 1.0; } static void clutter_stage_view_class_init (ClutterStageViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); klass->get_offscreen_transformation_matrix = clutter_stage_default_get_offscreen_transformation_matrix; object_class->get_property = clutter_stage_view_get_property; object_class->set_property = clutter_stage_view_set_property; object_class->dispose = clutter_stage_view_dispose; obj_props[PROP_LAYOUT] = g_param_spec_boxed ("layout", "View layout", "The view layout on the screen", CAIRO_GOBJECT_TYPE_RECTANGLE_INT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); obj_props[PROP_FRAMEBUFFER] = g_param_spec_boxed ("framebuffer", "View framebuffer", "The front buffer of the view", COGL_TYPE_HANDLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); obj_props[PROP_OFFSCREEN] = g_param_spec_boxed ("offscreen", "Offscreen buffer", "Framebuffer used as intermediate buffer", COGL_TYPE_HANDLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_props[PROP_SCALE] = g_param_spec_float ("scale", "View scale", "The view scale", 0.5, G_MAXFLOAT, 1.0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, PROP_LAST, obj_props); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-binding-pool.c�������������������������������������������������0000664�0001750�0001750�00000065751�14211404421�022523� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * Authored By: Emmanuele Bassi <ebassi@linux.intel.com> * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-binding-pool * @short_description: Pool for key bindings * * #ClutterBindingPool is a data structure holding a set of key bindings. * Each key binding associates a key symbol (eventually with modifiers) * to an action. A callback function is associated to each action. * * For a given key symbol and modifier mask combination there can be only one * action; for each action there can be only one callback. There can be * multiple actions with the same name, and the same callback can be used * to handle multiple key bindings. * * Actors requiring key bindings should create a new #ClutterBindingPool * inside their class initialization function and then install actions * like this: * * |[<!-- language="C" --> * static void * foo_class_init (FooClass *klass) * { * ClutterBindingPool *binding_pool; * * binding_pool = clutter_binding_pool_get_for_class (klass); * * clutter_binding_pool_install_action (binding_pool, "move-up", * CLUTTER_Up, 0, * G_CALLBACK (foo_action_move_up), * NULL, NULL); * clutter_binding_pool_install_action (binding_pool, "move-up", * CLUTTER_KP_Up, 0, * G_CALLBACK (foo_action_move_up), * NULL, NULL); * } * ]| * * The callback has a signature of: * * |[<!-- language="C" --> * gboolean (* callback) (GObject *instance, * const gchar *action_name, * guint key_val, * ClutterModifierType modifiers, * gpointer user_data); * ]| * * The actor should then override the #ClutterActor::key-press-event and * use clutter_binding_pool_activate() to match a #ClutterKeyEvent structure * to one of the actions: * * |[<!-- language="C" --> * ClutterBindingPool *pool; * * // retrieve the binding pool for the type of the actor * pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor)); * * // activate any callback matching the key symbol and modifiers * // mask of the key event. the returned value can be directly * // used to signal that the actor has handled the event. * return clutter_binding_pool_activate (pool, * key_event->keyval, * key_event->modifier_state, * G_OBJECT (actor)); * ]| * * The clutter_binding_pool_activate() function will return %FALSE if * no action for the given key binding was found, if the action was * blocked (using clutter_binding_pool_block_action()) or if the * key binding handler returned %FALSE. * * #ClutterBindingPool is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-binding-pool.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" #define CLUTTER_BINDING_POOL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CLUTTER_TYPE_BINDING_POOL, ClutterBindingPoolClass)) #define CLUTTER_IS_BINDING_POOL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_BINDING_POOL)) #define CLUTTER_BINDING_POOL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_BINDING_POOL, ClutterBindingPoolClass)) #define BINDING_MOD_MASK ((CLUTTER_SHIFT_MASK | \ CLUTTER_CONTROL_MASK | \ CLUTTER_MOD1_MASK | \ CLUTTER_SUPER_MASK | \ CLUTTER_HYPER_MASK | \ CLUTTER_META_MASK) | CLUTTER_RELEASE_MASK) typedef struct _ClutterBindingEntry ClutterBindingEntry; static GSList *clutter_binding_pools = NULL; static GQuark key_class_bindings = 0; struct _ClutterBindingPool { GObject parent_instance; gchar *name; /* interned string, do not free */ GSList *entries; GHashTable *entries_hash; }; struct _ClutterBindingPoolClass { GObjectClass parent_class; }; struct _ClutterBindingEntry { gchar *name; /* interned string, do not free */ guint key_val; ClutterModifierType modifiers; GClosure *closure; guint is_blocked : 1; }; enum { PROP_0, PROP_NAME, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterBindingPool, clutter_binding_pool, G_TYPE_OBJECT); static guint binding_entry_hash (gconstpointer v) { const ClutterBindingEntry *e = v; guint h; h = e->key_val; h ^= e->modifiers; return h; } static gint binding_entry_compare (gconstpointer v1, gconstpointer v2) { const ClutterBindingEntry *e1 = v1; const ClutterBindingEntry *e2 = v2; return (e1->key_val == e2->key_val && e1->modifiers == e2->modifiers); } static ClutterBindingEntry * binding_entry_new (const gchar *name, guint key_val, ClutterModifierType modifiers) { ClutterBindingEntry *entry; modifiers = modifiers & BINDING_MOD_MASK; entry = g_slice_new (ClutterBindingEntry); entry->key_val = key_val; entry->modifiers = modifiers; entry->name = (gchar *) g_intern_string (name); entry->closure = NULL; entry->is_blocked = FALSE; return entry; } static ClutterBindingEntry * binding_pool_lookup_entry (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers) { ClutterBindingEntry lookup_entry = { 0, }; lookup_entry.key_val = key_val; lookup_entry.modifiers = modifiers; return g_hash_table_lookup (pool->entries_hash, &lookup_entry); } static void binding_entry_free (gpointer data) { if (G_LIKELY (data)) { ClutterBindingEntry *entry = data; g_closure_unref (entry->closure); g_slice_free (ClutterBindingEntry, entry); } } static void clutter_binding_pool_finalize (GObject *gobject) { ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject); /* remove from the pools */ clutter_binding_pools = g_slist_remove (clutter_binding_pools, pool); g_hash_table_destroy (pool->entries_hash); g_slist_foreach (pool->entries, (GFunc) binding_entry_free, NULL); g_slist_free (pool->entries); G_OBJECT_CLASS (clutter_binding_pool_parent_class)->finalize (gobject); } static void clutter_binding_pool_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject); switch (prop_id) { case PROP_NAME: pool->name = (gchar *) g_intern_string (g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_binding_pool_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject); switch (prop_id) { case PROP_NAME: g_value_set_string (value, pool->name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_binding_pool_constructed (GObject *gobject) { ClutterBindingPool *pool = CLUTTER_BINDING_POOL (gobject); /* bad monkey! bad, bad monkey! */ if (G_UNLIKELY (pool->name == NULL)) g_critical ("No name set for ClutterBindingPool %p", pool); if (G_OBJECT_CLASS (clutter_binding_pool_parent_class)->constructed) G_OBJECT_CLASS (clutter_binding_pool_parent_class)->constructed (gobject); } static void clutter_binding_pool_class_init (ClutterBindingPoolClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructed = clutter_binding_pool_constructed; gobject_class->set_property = clutter_binding_pool_set_property; gobject_class->get_property = clutter_binding_pool_get_property; gobject_class->finalize = clutter_binding_pool_finalize; /** * ClutterBindingPool:name: * * The unique name of the #ClutterBindingPool. * * Since: 1.0 */ obj_props[PROP_NAME] = g_param_spec_string ("name", P_("Name"), P_("The unique name of the binding pool"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_binding_pool_init (ClutterBindingPool *pool) { pool->name = NULL; pool->entries = NULL; pool->entries_hash = g_hash_table_new (binding_entry_hash, binding_entry_compare); clutter_binding_pools = g_slist_prepend (clutter_binding_pools, pool); } /** * clutter_binding_pool_new: * @name: the name of the binding pool * * Creates a new #ClutterBindingPool that can be used to store * key bindings for an actor. The @name must be a unique identifier * for the binding pool, so that clutter_binding_pool_find() will * be able to return the correct binding pool. * * Return value: the newly created binding pool with the given * name. Use g_object_unref() when done. * * Since: 1.0 */ ClutterBindingPool * clutter_binding_pool_new (const gchar *name) { ClutterBindingPool *pool; g_return_val_if_fail (name != NULL, NULL); pool = clutter_binding_pool_find (name); if (G_UNLIKELY (pool)) { g_warning ("A binding pool named '%s' is already present " "in the binding pools list", pool->name); return NULL; } return g_object_new (CLUTTER_TYPE_BINDING_POOL, "name", name, NULL); } /** * clutter_binding_pool_get_for_class: * @klass: a #GObjectClass pointer * * Retrieves the #ClutterBindingPool for the given #GObject class * and, eventually, creates it. This function is a wrapper around * clutter_binding_pool_new() and uses the class type name as the * unique name for the binding pool. * * Calling this function multiple times will return the same * #ClutterBindingPool. * * A binding pool for a class can also be retrieved using * clutter_binding_pool_find() with the class type name: * * |[ * pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (instance)); * ]| * * Return value: (transfer none): the binding pool for the given class. * The returned #ClutterBindingPool is owned by Clutter and should not * be freed directly * * Since: 1.0 */ ClutterBindingPool * clutter_binding_pool_get_for_class (gpointer klass) { ClutterBindingPool *pool; g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), NULL); if (G_UNLIKELY (key_class_bindings == 0)) key_class_bindings = g_quark_from_static_string ("clutter-bindings-set"); pool = g_dataset_id_get_data (klass, key_class_bindings); if (pool) return pool; pool = clutter_binding_pool_new (G_OBJECT_CLASS_NAME (klass)); g_dataset_id_set_data_full (klass, key_class_bindings, pool, g_object_unref); return pool; } /** * clutter_binding_pool_find: * @name: the name of the binding pool to find * * Finds the #ClutterBindingPool with @name. * * Return value: (transfer none): a pointer to the #ClutterBindingPool, or %NULL * * Since: 1.0 */ ClutterBindingPool * clutter_binding_pool_find (const gchar *name) { GSList *l; g_return_val_if_fail (name != NULL, NULL); for (l = clutter_binding_pools; l != NULL; l = l->next) { ClutterBindingPool *pool = l->data; if (g_str_equal (pool->name, (gpointer) name)) return pool; } return NULL; } /** * clutter_binding_pool_install_action: * @pool: a #ClutterBindingPool * @action_name: the name of the action * @key_val: key symbol * @modifiers: bitmask of modifiers * @callback: (type Clutter.BindingActionFunc): function to be called * when the action is activated * @data: data to be passed to @callback * @notify: function to be called when the action is removed * from the pool * * Installs a new action inside a #ClutterBindingPool. The action * is bound to @key_val and @modifiers. * * The same action name can be used for multiple @key_val, @modifiers * pairs. * * When an action has been activated using clutter_binding_pool_activate() * the passed @callback will be invoked (with @data). * * Actions can be blocked with clutter_binding_pool_block_action() * and then unblocked using clutter_binding_pool_unblock_action(). * * Since: 1.0 */ void clutter_binding_pool_install_action (ClutterBindingPool *pool, const gchar *action_name, guint key_val, ClutterModifierType modifiers, GCallback callback, gpointer data, GDestroyNotify notify) { ClutterBindingEntry *entry; GClosure *closure; g_return_if_fail (pool != NULL); g_return_if_fail (action_name != NULL); g_return_if_fail (key_val != 0); g_return_if_fail (callback != NULL); entry = binding_pool_lookup_entry (pool, key_val, modifiers); if (G_UNLIKELY (entry)) { g_warning ("There already is an action '%s' for the given " "key symbol of %d (modifiers: %d) installed inside " "the binding pool.", entry->name, entry->key_val, entry->modifiers); return; } else entry = binding_entry_new (action_name, key_val, modifiers); closure = g_cclosure_new (callback, data, (GClosureNotify) notify); entry->closure = g_closure_ref (closure); g_closure_sink (closure); if (G_CLOSURE_NEEDS_MARSHAL (closure)) { GClosureMarshal marshal; marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS; g_closure_set_marshal (closure, marshal); } pool->entries = g_slist_prepend (pool->entries, entry); g_hash_table_insert (pool->entries_hash, entry, entry); } /** * clutter_binding_pool_install_closure: * @pool: a #ClutterBindingPool * @action_name: the name of the action * @key_val: key symbol * @modifiers: bitmask of modifiers * @closure: a #GClosure * * A #GClosure variant of clutter_binding_pool_install_action(). * * Installs a new action inside a #ClutterBindingPool. The action * is bound to @key_val and @modifiers. * * The same action name can be used for multiple @key_val, @modifiers * pairs. * * When an action has been activated using clutter_binding_pool_activate() * the passed @closure will be invoked. * * Actions can be blocked with clutter_binding_pool_block_action() * and then unblocked using clutter_binding_pool_unblock_action(). * * Since: 1.0 */ void clutter_binding_pool_install_closure (ClutterBindingPool *pool, const gchar *action_name, guint key_val, ClutterModifierType modifiers, GClosure *closure) { ClutterBindingEntry *entry; g_return_if_fail (pool != NULL); g_return_if_fail (action_name != NULL); g_return_if_fail (key_val != 0); g_return_if_fail (closure != NULL); entry = binding_pool_lookup_entry (pool, key_val, modifiers); if (G_UNLIKELY (entry)) { g_warning ("There already is an action '%s' for the given " "key symbol of %d (modifiers: %d) installed inside " "the binding pool.", entry->name, entry->key_val, entry->modifiers); return; } else entry = binding_entry_new (action_name, key_val, modifiers); entry->closure = g_closure_ref (closure); g_closure_sink (closure); if (G_CLOSURE_NEEDS_MARSHAL (closure)) { GClosureMarshal marshal; marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS; g_closure_set_marshal (closure, marshal); } pool->entries = g_slist_prepend (pool->entries, entry); g_hash_table_insert (pool->entries_hash, entry, entry); } /** * clutter_binding_pool_override_action: * @pool: a #ClutterBindingPool * @key_val: key symbol * @modifiers: bitmask of modifiers * @callback: function to be called when the action is activated * @data: data to be passed to @callback * @notify: function to be called when the action is removed * from the pool * * Allows overriding the action for @key_val and @modifiers inside a * #ClutterBindingPool. See clutter_binding_pool_install_action(). * * When an action has been activated using clutter_binding_pool_activate() * the passed @callback will be invoked (with @data). * * Actions can be blocked with clutter_binding_pool_block_action() * and then unblocked using clutter_binding_pool_unblock_action(). * * Since: 1.0 */ void clutter_binding_pool_override_action (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers, GCallback callback, gpointer data, GDestroyNotify notify) { ClutterBindingEntry *entry; GClosure *closure; g_return_if_fail (pool != NULL); g_return_if_fail (key_val != 0); g_return_if_fail (callback != NULL); entry = binding_pool_lookup_entry (pool, key_val, modifiers); if (G_UNLIKELY (entry == NULL)) { g_warning ("There is no action for the given key symbol " "of %d (modifiers: %d) installed inside the " "binding pool.", key_val, modifiers); return; } if (entry->closure) { g_closure_unref (entry->closure); entry->closure = NULL; } closure = g_cclosure_new (callback, data, (GClosureNotify) notify); entry->closure = g_closure_ref (closure); g_closure_sink (closure); if (G_CLOSURE_NEEDS_MARSHAL (closure)) { GClosureMarshal marshal; marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS; g_closure_set_marshal (closure, marshal); } } /** * clutter_binding_pool_override_closure: * @pool: a #ClutterBindingPool * @key_val: key symbol * @modifiers: bitmask of modifiers * @closure: a #GClosure * * A #GClosure variant of clutter_binding_pool_override_action(). * * Allows overriding the action for @key_val and @modifiers inside a * #ClutterBindingPool. See clutter_binding_pool_install_closure(). * * When an action has been activated using clutter_binding_pool_activate() * the passed @callback will be invoked (with @data). * * Actions can be blocked with clutter_binding_pool_block_action() * and then unblocked using clutter_binding_pool_unblock_action(). * * Since: 1.0 */ void clutter_binding_pool_override_closure (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers, GClosure *closure) { ClutterBindingEntry *entry; g_return_if_fail (pool != NULL); g_return_if_fail (key_val != 0); g_return_if_fail (closure != NULL); entry = binding_pool_lookup_entry (pool, key_val, modifiers); if (G_UNLIKELY (entry == NULL)) { g_warning ("There is no action for the given key symbol " "of %d (modifiers: %d) installed inside the " "binding pool.", key_val, modifiers); return; } if (entry->closure) { g_closure_unref (entry->closure); entry->closure = NULL; } entry->closure = g_closure_ref (closure); g_closure_sink (closure); if (G_CLOSURE_NEEDS_MARSHAL (closure)) { GClosureMarshal marshal; marshal = _clutter_marshal_BOOLEAN__STRING_UINT_FLAGS; g_closure_set_marshal (closure, marshal); } } /** * clutter_binding_pool_find_action: * @pool: a #ClutterBindingPool * @key_val: a key symbol * @modifiers: a bitmask for the modifiers * * Retrieves the name of the action matching the given key symbol * and modifiers bitmask. * * Return value: the name of the action, if found, or %NULL. The * returned string is owned by the binding pool and should never * be modified or freed * * Since: 1.0 */ const gchar * clutter_binding_pool_find_action (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers) { ClutterBindingEntry *entry; g_return_val_if_fail (pool != NULL, NULL); g_return_val_if_fail (key_val != 0, NULL); entry = binding_pool_lookup_entry (pool, key_val, modifiers); if (!entry) return NULL; return entry->name; } /** * clutter_binding_pool_remove_action: * @pool: a #ClutterBindingPool * @key_val: a key symbol * @modifiers: a bitmask for the modifiers * * Removes the action matching the given @key_val, @modifiers pair, * if any exists. * * Since: 1.0 */ void clutter_binding_pool_remove_action (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers) { ClutterBindingEntry remove_entry = { 0, }; GSList *l; g_return_if_fail (pool != NULL); g_return_if_fail (key_val != 0); modifiers = modifiers & BINDING_MOD_MASK; remove_entry.key_val = key_val; remove_entry.modifiers = modifiers; for (l = pool->entries; l != NULL; l = l->data) { ClutterBindingEntry *e = l->data; if (e->key_val == remove_entry.key_val && e->modifiers == remove_entry.modifiers) { pool->entries = g_slist_remove_link (pool->entries, l); break; } } g_hash_table_remove (pool->entries_hash, &remove_entry); } static gboolean clutter_binding_entry_invoke (ClutterBindingEntry *entry, GObject *gobject) { GValue params[4] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT }; GValue result = G_VALUE_INIT; gboolean retval = TRUE; g_value_init (¶ms[0], G_TYPE_OBJECT); g_value_set_object (¶ms[0], gobject); g_value_init (¶ms[1], G_TYPE_STRING); g_value_set_static_string (¶ms[1], entry->name); g_value_init (¶ms[2], G_TYPE_UINT); g_value_set_uint (¶ms[2], entry->key_val); g_value_init (¶ms[3], CLUTTER_TYPE_MODIFIER_TYPE); g_value_set_flags (¶ms[3], entry->modifiers); g_value_init (&result, G_TYPE_BOOLEAN); g_closure_invoke (entry->closure, &result, 4, params, NULL); retval = g_value_get_boolean (&result); g_value_unset (&result); g_value_unset (¶ms[0]); g_value_unset (¶ms[1]); g_value_unset (¶ms[2]); g_value_unset (¶ms[3]); return retval; } /** * clutter_binding_pool_activate: * @pool: a #ClutterBindingPool * @key_val: the key symbol * @modifiers: bitmask for the modifiers * @gobject: a #GObject * * Activates the callback associated to the action that is * bound to the @key_val and @modifiers pair. * * The callback has the following signature: * * |[ * void (* callback) (GObject *gobject, * const gchar *action_name, * guint key_val, * ClutterModifierType modifiers, * gpointer user_data); * ]| * * Where the #GObject instance is @gobject and the user data * is the one passed when installing the action with * clutter_binding_pool_install_action(). * * If the action bound to the @key_val, @modifiers pair has been * blocked using clutter_binding_pool_block_action(), the callback * will not be invoked, and this function will return %FALSE. * * Return value: %TRUE if an action was found and was activated * * Since: 1.0 */ gboolean clutter_binding_pool_activate (ClutterBindingPool *pool, guint key_val, ClutterModifierType modifiers, GObject *gobject) { ClutterBindingEntry *entry = NULL; g_return_val_if_fail (pool != NULL, FALSE); g_return_val_if_fail (key_val != 0, FALSE); g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE); modifiers = (modifiers & BINDING_MOD_MASK); entry = binding_pool_lookup_entry (pool, key_val, modifiers); if (!entry) return FALSE; if (!entry->is_blocked) return clutter_binding_entry_invoke (entry, gobject); return FALSE; } /** * clutter_binding_pool_block_action: * @pool: a #ClutterBindingPool * @action_name: an action name * * Blocks all the actions with name @action_name inside @pool. * * Since: 1.0 */ void clutter_binding_pool_block_action (ClutterBindingPool *pool, const gchar *action_name) { GSList *l; g_return_if_fail (pool != NULL); g_return_if_fail (action_name != NULL); for (l = pool->entries; l != NULL; l = l->next) { ClutterBindingEntry *entry = l->data; if (g_str_equal (entry->name, (gpointer) action_name)) entry->is_blocked = TRUE; } } /** * clutter_binding_pool_unblock_action: * @pool: a #ClutterBindingPool * @action_name: an action name * * Unblockes all the actions with name @action_name inside @pool. * * Unblocking an action does not cause the callback bound to it to * be invoked in case clutter_binding_pool_activate() was called on * an action previously blocked with clutter_binding_pool_block_action(). * * Since: 1.0 */ void clutter_binding_pool_unblock_action (ClutterBindingPool *pool, const gchar *action_name) { GSList *l; g_return_if_fail (pool != NULL); g_return_if_fail (action_name != NULL); for (l = pool->entries; l != NULL; l = l->next) { ClutterBindingEntry *entry = l->data; if (g_str_equal (entry->name, (gpointer) action_name)) entry->is_blocked = FALSE; } } �����������������������muffin-5.2.1/clutter/clutter/clutter-text.c���������������������������������������������������������0000664�0001750�0001750�00000566015�14211404421�021125� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * Authored By: Øyvind Kolås <pippin@o-hand.com> * Emmanuele Bassi <ebassi@linux.intel.com> * * 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, see <http://www.gnu.org/licenses/>. */ /** * SECTION:clutter-text * @short_description: An actor for displaying and editing text * * #ClutterText is an actor that displays custom text using Pango * as the text rendering engine. * * #ClutterText also allows inline editing of the text if the * actor is set editable using clutter_text_set_editable(). * * Selection using keyboard or pointers can be enabled using * clutter_text_set_selectable(). * * #ClutterText is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <string.h> #include <math.h> #include "clutter-text.h" #include "clutter-actor-private.h" #include "clutter-animatable.h" #include "clutter-backend-private.h" #include "clutter-binding-pool.h" #include "clutter-color.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-keysyms.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" /* includes <cogl-pango/cogl-pango.h> */ #include "clutter-property-transition.h" #include "clutter-text-buffer.h" #include "clutter-units.h" #include "clutter-paint-volume-private.h" #include "clutter-scriptable.h" #include "clutter-input-focus.h" /* cursor width in pixels */ #define DEFAULT_CURSOR_SIZE 2 /* vertical padding for the cursor */ #define CURSOR_Y_PADDING 2 /* We need at least three cached layouts to run the allocation without * regenerating a new layout. First the layout will be generated at * full width to get the preferred width, then it will be generated at * the preferred width to get the preferred height and then it might * be regenerated at a different width to get the height for the * actual allocated width * * since we might get multiple queries from layout managers doing a * double-pass allocations, like tabular ones, we should use 6 slots */ #define N_CACHED_LAYOUTS 6 typedef struct _LayoutCache LayoutCache; struct _LayoutCache { /* Cached layout. Pango internally caches the computed extents * when they are requested so there is no need to cache that as * well */ PangoLayout *layout; /* A number representing the age of this cache (so that when a * new layout is needed the last used cache is replaced) */ guint age; }; struct _ClutterTextInputFocus { ClutterInputFocus parent_instance; ClutterText *text; }; struct _ClutterTextPrivate { PangoFontDescription *font_desc; /* the displayed text */ ClutterTextBuffer *buffer; gchar *font_name; gchar *preedit_str; ClutterColor text_color; LayoutCache cached_layouts[N_CACHED_LAYOUTS]; guint cache_age; /* These are the attributes set by the attributes property */ PangoAttrList *attrs; /* These are the attributes derived from the text when the use-markup property is set */ PangoAttrList *markup_attrs; /* This is the combination of the above two lists. It is set to NULL whenever either of them changes and then regenerated by merging the two lists whenever a layout is needed */ PangoAttrList *effective_attrs; /* These are the attributes for the preedit string. These are merged with the effective attributes into a temporary list before creating a layout */ PangoAttrList *preedit_attrs; /* current cursor position */ gint position; /* current 'other end of selection' position */ gint selection_bound; /* the x position in the PangoLayout, used to * avoid drifting when repeatedly moving up|down */ gint x_pos; /* the x position of the PangoLayout when in * single line mode, to scroll the contents of the * text actor */ gint text_x; /* the y position of the PangoLayout, fixed to 0 by * default for now */ gint text_y; /* Where to draw the cursor */ ClutterRect cursor_rect; ClutterColor cursor_color; guint cursor_size; /* Box representing the paint volume. The box is lazily calculated and cached */ ClutterPaintVolume paint_volume; guint preedit_cursor_pos; gint preedit_n_chars; ClutterColor selection_color; ClutterColor selected_text_color; gunichar password_char; guint password_hint_id; guint password_hint_timeout; /* Signal handler for when the backend changes its font settings */ guint settings_changed_id; /* Signal handler for when the :text-direction changes */ guint direction_changed_id; ClutterInputFocus *input_focus; ClutterInputContentHintFlags input_hints; ClutterInputContentPurpose input_purpose; /* bitfields */ guint alignment : 2; guint wrap : 1; guint use_underline : 1; guint use_markup : 1; guint ellipsize : 3; guint single_line_mode : 1; guint wrap_mode : 3; guint justify : 1; guint editable : 1; guint cursor_visible : 1; guint activatable : 1; guint selectable : 1; guint selection_color_set : 1; guint in_select_drag : 1; guint in_select_touch : 1; guint cursor_color_set : 1; guint preedit_set : 1; guint is_default_font : 1; guint has_focus : 1; guint selected_text_color_set : 1; guint paint_volume_valid : 1; guint show_password_hint : 1; guint password_hint_visible : 1; guint resolved_direction : 4; }; enum { PROP_0, PROP_BUFFER, PROP_FONT_NAME, PROP_FONT_DESCRIPTION, PROP_TEXT, PROP_COLOR, PROP_USE_MARKUP, PROP_ATTRIBUTES, PROP_LINE_ALIGNMENT, PROP_LINE_WRAP, PROP_LINE_WRAP_MODE, PROP_JUSTIFY, PROP_ELLIPSIZE, PROP_POSITION, /* XXX:2.0 - remove */ PROP_SELECTION_BOUND, PROP_SELECTION_COLOR, PROP_SELECTION_COLOR_SET, PROP_CURSOR_VISIBLE, PROP_CURSOR_COLOR, PROP_CURSOR_COLOR_SET, PROP_CURSOR_SIZE, PROP_CURSOR_POSITION, PROP_EDITABLE, PROP_SELECTABLE, PROP_ACTIVATABLE, PROP_PASSWORD_CHAR, PROP_MAX_LENGTH, PROP_SINGLE_LINE_MODE, PROP_SELECTED_TEXT_COLOR, PROP_SELECTED_TEXT_COLOR_SET, PROP_INPUT_HINTS, PROP_INPUT_PURPOSE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { TEXT_CHANGED, CURSOR_EVENT, /* XXX:2.0 - remove */ ACTIVATE, INSERT_TEXT, DELETE_TEXT, CURSOR_CHANGED, LAST_SIGNAL }; static guint text_signals[LAST_SIGNAL] = { 0, }; static void clutter_text_settings_changed_cb (ClutterText *text); static void buffer_connect_signals (ClutterText *self); static void buffer_disconnect_signals (ClutterText *self); static ClutterTextBuffer *get_buffer (ClutterText *self); static const ClutterColor default_cursor_color = { 0, 0, 0, 255 }; static const ClutterColor default_selection_color = { 0, 0, 0, 255 }; static const ClutterColor default_text_color = { 0, 0, 0, 255 }; static const ClutterColor default_selected_text_color = { 0, 0, 0, 255 }; static ClutterAnimatableIface *parent_animatable_iface = NULL; static ClutterScriptableIface *parent_scriptable_iface = NULL; /* ClutterTextInputFocus */ #define CLUTTER_TYPE_TEXT_INPUT_FOCUS (clutter_text_input_focus_get_type ()) G_DECLARE_FINAL_TYPE (ClutterTextInputFocus, clutter_text_input_focus, CLUTTER, TEXT_INPUT_FOCUS, ClutterInputFocus) G_DEFINE_TYPE (ClutterTextInputFocus, clutter_text_input_focus, CLUTTER_TYPE_INPUT_FOCUS) static void clutter_text_input_focus_request_surrounding (ClutterInputFocus *focus) { ClutterText *clutter_text = CLUTTER_TEXT_INPUT_FOCUS (focus)->text; ClutterTextBuffer *buffer; const gchar *text; gint anchor_pos, cursor_pos; buffer = clutter_text_get_buffer (clutter_text); text = clutter_text_buffer_get_text (buffer); cursor_pos = clutter_text_get_cursor_position (clutter_text); if (cursor_pos < 0) cursor_pos = clutter_text_buffer_get_length (buffer); anchor_pos = clutter_text_get_selection_bound (clutter_text); if (anchor_pos < 0) anchor_pos = cursor_pos; clutter_input_focus_set_surrounding (focus, text, g_utf8_offset_to_pointer (text, cursor_pos) - text, g_utf8_offset_to_pointer (text, anchor_pos) - text); } static void clutter_text_input_focus_delete_surrounding (ClutterInputFocus *focus, guint offset, guint len) { ClutterText *clutter_text = CLUTTER_TEXT_INPUT_FOCUS (focus)->text; if (clutter_text_get_editable (clutter_text)) clutter_text_delete_text (clutter_text, offset, len); } static void clutter_text_input_focus_commit_text (ClutterInputFocus *focus, const gchar *text) { ClutterText *clutter_text = CLUTTER_TEXT_INPUT_FOCUS (focus)->text; if (clutter_text_get_editable (clutter_text)) { clutter_text_delete_selection (clutter_text); clutter_text_insert_text (clutter_text, text, clutter_text_get_cursor_position (clutter_text)); clutter_text_set_preedit_string (clutter_text, NULL, NULL, 0); } } static void clutter_text_input_focus_set_preedit_text (ClutterInputFocus *focus, const gchar *preedit_text, guint cursor_pos) { ClutterText *clutter_text = CLUTTER_TEXT_INPUT_FOCUS (focus)->text; if (clutter_text_get_editable (clutter_text)) { PangoAttrList *list; list = pango_attr_list_new (); pango_attr_list_insert (list, pango_attr_underline_new (PANGO_UNDERLINE_SINGLE)); clutter_text_set_preedit_string (clutter_text, preedit_text, list, cursor_pos); pango_attr_list_unref (list); } } static void clutter_text_input_focus_class_init (ClutterTextInputFocusClass *klass) { ClutterInputFocusClass *focus_class = CLUTTER_INPUT_FOCUS_CLASS (klass); focus_class->request_surrounding = clutter_text_input_focus_request_surrounding; focus_class->delete_surrounding = clutter_text_input_focus_delete_surrounding; focus_class->commit_text = clutter_text_input_focus_commit_text; focus_class->set_preedit_text = clutter_text_input_focus_set_preedit_text; } static void clutter_text_input_focus_init (ClutterTextInputFocus *focus) { } static ClutterInputFocus * clutter_text_input_focus_new (ClutterText *text) { ClutterTextInputFocus *focus; focus = g_object_new (CLUTTER_TYPE_TEXT_INPUT_FOCUS, NULL); focus->text = text; return CLUTTER_INPUT_FOCUS (focus); } /* ClutterText */ static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); static void clutter_animatable_iface_init (ClutterAnimatableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterText, clutter_text, CLUTTER_TYPE_ACTOR, G_ADD_PRIVATE (ClutterText) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE, clutter_animatable_iface_init)); static inline void clutter_text_dirty_paint_volume (ClutterText *text) { ClutterTextPrivate *priv = text->priv; if (priv->paint_volume_valid) { clutter_paint_volume_free (&priv->paint_volume); priv->paint_volume_valid = FALSE; } } static inline void clutter_text_queue_redraw (ClutterActor *self) { /* This is a wrapper for clutter_actor_queue_redraw that also dirties the cached paint volume. It would be nice if we could just override the default implementation of the queue redraw signal to do this instead but that doesn't work because the signal isn't immediately emitted when queue_redraw is called. Clutter will however immediately call get_paint_volume when queue_redraw is called so we do need to dirty it immediately. */ clutter_text_dirty_paint_volume (CLUTTER_TEXT (self)); clutter_actor_queue_redraw (self); } static gboolean clutter_text_should_draw_cursor (ClutterText *self) { ClutterTextPrivate *priv = self->priv; return (priv->editable || priv->selectable) && priv->cursor_visible && priv->has_focus; } #define clutter_actor_queue_redraw \ Please_use_clutter_text_queue_redraw_instead #define offset_real(t,p) ((p) == -1 ? g_utf8_strlen ((t), -1) : (p)) static gint offset_to_bytes (const gchar *text, gint pos) { const gchar *ptr; if (pos < 0) return strlen (text); /* Loop over each character in the string until we either reach the end or the requested position */ for (ptr = text; *ptr && pos-- > 0; ptr = g_utf8_next_char (ptr)); return ptr - text; } #define bytes_to_offset(t,p) (g_utf8_pointer_to_offset ((t), (t) + (p))) static inline void clutter_text_clear_selection (ClutterText *self) { ClutterTextPrivate *priv = self->priv; if (priv->selection_bound != priv->position) { priv->selection_bound = priv->position; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]); clutter_text_queue_redraw (CLUTTER_ACTOR (self)); } } static gboolean clutter_text_is_empty (ClutterText *self) { if (self->priv->buffer == NULL) return TRUE; if (clutter_text_buffer_get_length (self->priv->buffer) == 0) return TRUE; return FALSE; } static gchar * clutter_text_get_display_text (ClutterText *self) { ClutterTextPrivate *priv = self->priv; ClutterTextBuffer *buffer; const gchar *text; /* short-circuit the case where the buffer is unset or it's empty, * to avoid creating a pointless TextBuffer and emitting * notifications with it */ if (clutter_text_is_empty (self)) return g_strdup (""); buffer = get_buffer (self); text = clutter_text_buffer_get_text (buffer); /* simple short-circuit to avoid going through GString * with an empty text and a password char set */ if (text[0] == '\0') return g_strdup (""); if (G_LIKELY (priv->password_char == 0)) return g_strdup (text); else { GString *str; gunichar invisible_char; gchar buf[7]; gint char_len, i; guint n_chars; n_chars = clutter_text_buffer_get_length (buffer); str = g_string_sized_new (clutter_text_buffer_get_bytes (buffer)); invisible_char = priv->password_char; /* we need to convert the string built of invisible * characters into UTF-8 for it to be fed to the Pango * layout */ memset (buf, 0, sizeof (buf)); char_len = g_unichar_to_utf8 (invisible_char, buf); if (priv->show_password_hint && priv->password_hint_visible) { char *last_char; for (i = 0; i < n_chars - 1; i++) g_string_append_len (str, buf, char_len); last_char = g_utf8_offset_to_pointer (text, n_chars - 1); g_string_append (str, last_char); } else { for (i = 0; i < n_chars; i++) g_string_append_len (str, buf, char_len); } return g_string_free (str, FALSE); } } static inline void clutter_text_ensure_effective_attributes (ClutterText *self) { ClutterTextPrivate *priv = self->priv; /* If we already have the effective attributes then we don't need to do anything */ if (priv->effective_attrs != NULL) return; /* Same as if we don't have any attribute at all. * We also ignore markup attributes for editable. */ if (priv->attrs == NULL && (priv->editable || priv->markup_attrs == NULL)) return; if (priv->attrs != NULL) { /* If there are no markup attributes, or if this is editable (in which * case we ignore markup), then we can just use these attrs directly */ if (priv->editable || priv->markup_attrs == NULL) priv->effective_attrs = pango_attr_list_ref (priv->attrs); else { /* Otherwise we need to merge the two lists */ PangoAttrIterator *iter; GSList *attributes, *l; priv->effective_attrs = pango_attr_list_copy (priv->markup_attrs); iter = pango_attr_list_get_iterator (priv->attrs); do { attributes = pango_attr_iterator_get_attrs (iter); for (l = attributes; l != NULL; l = l->next) { PangoAttribute *attr = l->data; pango_attr_list_insert (priv->effective_attrs, attr); } g_slist_free (attributes); } while (pango_attr_iterator_next (iter)); pango_attr_iterator_destroy (iter); } } else if (priv->markup_attrs != NULL) { /* We can just use the markup attributes directly */ priv->effective_attrs = pango_attr_list_ref (priv->markup_attrs); } } static PangoLayout * clutter_text_create_layout_no_cache (ClutterText *text, gint width, gint height, PangoEllipsizeMode ellipsize) { ClutterTextPrivate *priv = text->priv; PangoLayout *layout; gchar *contents; gsize contents_len; layout = clutter_actor_create_pango_layout (CLUTTER_ACTOR (text), NULL); pango_layout_set_font_description (layout, priv->font_desc); contents = clutter_text_get_display_text (text); contents_len = strlen (contents); if (priv->editable && priv->preedit_set) { GString *tmp = g_string_new (contents); PangoAttrList *tmp_attrs = pango_attr_list_new (); gint cursor_index; if (priv->position == 0) cursor_index = 0; else cursor_index = offset_to_bytes (contents, priv->position); g_string_insert (tmp, cursor_index, priv->preedit_str); pango_layout_set_text (layout, tmp->str, tmp->len); if (priv->preedit_attrs != NULL) { pango_attr_list_splice (tmp_attrs, priv->preedit_attrs, cursor_index, strlen (priv->preedit_str)); pango_layout_set_attributes (layout, tmp_attrs); } g_string_free (tmp, TRUE); pango_attr_list_unref (tmp_attrs); } else { PangoDirection pango_dir; if (priv->password_char != 0) pango_dir = PANGO_DIRECTION_NEUTRAL; else pango_dir = pango_find_base_dir (contents, contents_len); if (pango_dir == PANGO_DIRECTION_NEUTRAL) { ClutterBackend *backend = clutter_get_default_backend (); ClutterTextDirection text_dir; if (clutter_actor_has_key_focus (CLUTTER_ACTOR (text))) pango_dir = _clutter_backend_get_keymap_direction (backend); else { text_dir = clutter_actor_get_text_direction (CLUTTER_ACTOR (text)); if (text_dir == CLUTTER_TEXT_DIRECTION_RTL) pango_dir = PANGO_DIRECTION_RTL; else pango_dir = PANGO_DIRECTION_LTR; } } pango_context_set_base_dir (clutter_actor_get_pango_context (CLUTTER_ACTOR (text)), pango_dir); priv->resolved_direction = pango_dir; pango_layout_set_text (layout, contents, contents_len); } /* This will merge the markup attributes and the attributes * property if needed */ clutter_text_ensure_effective_attributes (text); if (priv->effective_attrs != NULL) pango_layout_set_attributes (layout, priv->effective_attrs); pango_layout_set_alignment (layout, priv->alignment); pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode); pango_layout_set_justify (layout, priv->justify); pango_layout_set_wrap (layout, priv->wrap_mode); pango_layout_set_ellipsize (layout, ellipsize); pango_layout_set_width (layout, width); pango_layout_set_height (layout, height); free (contents); return layout; } static void clutter_text_dirty_cache (ClutterText *text) { ClutterTextPrivate *priv = text->priv; int i; /* Delete the cached layouts so they will be recreated the next time they are needed */ for (i = 0; i < N_CACHED_LAYOUTS; i++) if (priv->cached_layouts[i].layout) { g_object_unref (priv->cached_layouts[i].layout); priv->cached_layouts[i].layout = NULL; } clutter_text_dirty_paint_volume (text); } /* * clutter_text_set_font_description_internal: * @self: a #ClutterText * @desc: a #PangoFontDescription * * Sets @desc as the font description to be used by the #ClutterText * actor. The #PangoFontDescription is copied. * * This function will also set the :font-name field as a side-effect * * This function will evict the layout cache, and queue a relayout if * the #ClutterText actor has contents. */ static inline void clutter_text_set_font_description_internal (ClutterText *self, PangoFontDescription *desc, gboolean is_default_font) { ClutterTextPrivate *priv = self->priv; priv->is_default_font = is_default_font; if (priv->font_desc == desc || pango_font_description_equal (priv->font_desc, desc)) return; if (priv->font_desc != NULL) pango_font_description_free (priv->font_desc); priv->font_desc = pango_font_description_copy (desc); /* update the font name string we use */ free (priv->font_name); priv->font_name = pango_font_description_to_string (priv->font_desc); clutter_text_dirty_cache (self); if (clutter_text_buffer_get_length (get_buffer (self)) != 0) clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_DESCRIPTION]); } static void clutter_text_settings_changed_cb (ClutterText *text) { ClutterTextPrivate *priv = text->priv; guint password_hint_time = 0; ClutterSettings *settings; settings = clutter_settings_get_default (); g_object_get (settings, "password-hint-time", &password_hint_time, NULL); priv->show_password_hint = password_hint_time > 0; priv->password_hint_timeout = password_hint_time; if (priv->is_default_font) { PangoFontDescription *font_desc; gchar *font_name = NULL; g_object_get (settings, "font-name", &font_name, NULL); CLUTTER_NOTE (ACTOR, "Text[%p]: default font changed to '%s'", text, font_name); font_desc = pango_font_description_from_string (font_name); clutter_text_set_font_description_internal (text, font_desc, TRUE); pango_font_description_free (font_desc); free (font_name); } clutter_text_dirty_cache (text); clutter_actor_queue_relayout (CLUTTER_ACTOR (text)); } static void clutter_text_direction_changed_cb (GObject *gobject, GParamSpec *pspec) { clutter_text_dirty_cache (CLUTTER_TEXT (gobject)); /* no need to queue a relayout: set_text_direction() will do that for us */ } /* * clutter_text_create_layout: * @text: a #ClutterText * @allocation_width: the allocation width * @allocation_height: the allocation height * * Like clutter_text_create_layout_no_cache(), but will also ensure * the glyphs cache. If a previously cached layout generated using the * same width is available then that will be used instead of * generating a new one. */ static PangoLayout * clutter_text_create_layout (ClutterText *text, gfloat allocation_width, gfloat allocation_height) { ClutterTextPrivate *priv = text->priv; LayoutCache *oldest_cache = priv->cached_layouts; gboolean found_free_cache = FALSE; gint width = -1; gint height = -1; PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE; int i; /* First determine the width, height, and ellipsize mode that * we need for the layout. The ellipsize mode depends on * allocation_width/allocation_size as follows: * * Cases, assuming ellipsize != NONE on actor: * * Width request: ellipsization can be set or not on layout, * doesn't matter. * * Height request: ellipsization must never be set on layout * if wrap=true, because we need to measure the wrapped * height. It must always be set if wrap=false. * * Allocate: ellipsization must always be set. * * See http://bugzilla.gnome.org/show_bug.cgi?id=560931 */ if (priv->ellipsize != PANGO_ELLIPSIZE_NONE) { if (allocation_height < 0 && priv->wrap) ; /* must not set ellipsization on wrap=true height request */ else { if (!priv->editable) ellipsize = priv->ellipsize; } } /* When painting, we always need to set the width, since * we might need to align to the right. When getting the * height, however, there are some cases where we know that * the width won't affect the width. * * - editable, single-line text actors, since those can * scroll the layout. * - non-wrapping, non-ellipsizing actors. */ if (allocation_width >= 0 && (allocation_height >= 0 || !((priv->editable && priv->single_line_mode) || (priv->ellipsize == PANGO_ELLIPSIZE_NONE && !priv->wrap)))) { width = allocation_width * 1024 + 0.5f; } /* Pango only uses height if ellipsization is enabled, so don't set * height if ellipsize isn't set. Pango implicitly enables wrapping * if height is set, so don't set height if wrapping is disabled. * In other words, only set height if we want to both wrap then * ellipsize and we're not in single line mode. * * See http://bugzilla.gnome.org/show_bug.cgi?id=560931 if this * seems odd. */ if (allocation_height >= 0 && priv->wrap && priv->ellipsize != PANGO_ELLIPSIZE_NONE && !priv->single_line_mode) { height = allocation_height * 1024 + 0.5f; } /* Search for a cached layout with the same width and keep * track of the oldest one */ for (i = 0; i < N_CACHED_LAYOUTS; i++) { if (priv->cached_layouts[i].layout == NULL) { /* Always prefer free cache spaces */ found_free_cache = TRUE; oldest_cache = priv->cached_layouts + i; } else { PangoLayout *cached = priv->cached_layouts[i].layout; gint cached_width = pango_layout_get_width (cached); gint cached_height = pango_layout_get_height (cached); gint cached_ellipsize = pango_layout_get_ellipsize (cached); if (cached_width == width && cached_height == height && cached_ellipsize == ellipsize) { /* If this cached layout is using the same size then we can * just return that directly */ CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache hit for size %.2fx%.2f", text, allocation_width, allocation_height); return priv->cached_layouts[i].layout; } /* When getting the preferred height for a specific width, * we might be able to reuse the layout from getting the * preferred width. If the width that the layout gives * unconstrained is less than the width that we are using * than the height will be unaffected by that width. */ if (allocation_height < 0 && cached_width == -1 && cached_ellipsize == ellipsize) { PangoRectangle logical_rect; pango_layout_get_extents (priv->cached_layouts[i].layout, NULL, &logical_rect); if (logical_rect.width <= width) { /* We've been asked for our height for the width we gave as a result * of a _get_preferred_width call */ CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache hit for size %.2fx%.2f " "(unwrapped width narrower than given width)", text, allocation_width, allocation_height); return priv->cached_layouts[i].layout; } } if (!found_free_cache && (priv->cached_layouts[i].age < oldest_cache->age)) { oldest_cache = priv->cached_layouts + i; } } } CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for size %.2fx%.2f", text, allocation_width, allocation_height); /* If we make it here then we didn't have a cached version so we need to recreate the layout */ if (oldest_cache->layout) g_object_unref (oldest_cache->layout); oldest_cache->layout = clutter_text_create_layout_no_cache (text, width, height, ellipsize); cogl_pango_ensure_glyph_cache_for_layout (oldest_cache->layout); /* Mark the 'time' this cache was created and advance the time */ oldest_cache->age = priv->cache_age++; return oldest_cache->layout; } /** * clutter_text_coords_to_position: * @self: a #ClutterText * @x: the X coordinate, relative to the actor * @y: the Y coordinate, relative to the actor * * Retrieves the position of the character at the given coordinates. * * Return: the position of the character * * Since: 1.10 */ gint clutter_text_coords_to_position (ClutterText *self, gfloat x, gfloat y) { gint index_; gint px, py; gint trailing; g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0); /* Take any offset due to scrolling into account, and normalize * the coordinates to PangoScale units */ px = (x - self->priv->text_x) * PANGO_SCALE; py = (y - self->priv->text_y) * PANGO_SCALE; pango_layout_xy_to_index (clutter_text_get_layout (self), px, py, &index_, &trailing); return index_ + trailing; } /** * clutter_text_position_to_coords: * @self: a #ClutterText * @position: position in characters * @x: (out): return location for the X coordinate, or %NULL * @y: (out): return location for the Y coordinate, or %NULL * @line_height: (out): return location for the line height, or %NULL * * Retrieves the coordinates of the given @position. * * Return value: %TRUE if the conversion was successful * * Since: 1.0 */ gboolean clutter_text_position_to_coords (ClutterText *self, gint position, gfloat *x, gfloat *y, gfloat *line_height) { ClutterTextPrivate *priv; PangoRectangle rect; gint n_chars; gint password_char_bytes = 1; gint index_; gsize n_bytes; g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); priv = self->priv; n_chars = clutter_text_buffer_get_length (get_buffer (self)); if (priv->preedit_set) n_chars += priv->preedit_n_chars; if (position < -1 || position > n_chars) return FALSE; if (priv->password_char != 0) password_char_bytes = g_unichar_to_utf8 (priv->password_char, NULL); if (position == -1) { if (priv->password_char == 0) { n_bytes = clutter_text_buffer_get_bytes (get_buffer (self)); if (priv->editable && priv->preedit_set) index_ = n_bytes + strlen (priv->preedit_str); else index_ = n_bytes; } else index_ = n_chars * password_char_bytes; } else if (position == 0) { index_ = 0; } else { gchar *text = clutter_text_get_display_text (self); GString *tmp = g_string_new (text); gint cursor_index; cursor_index = offset_to_bytes (text, priv->position); if (priv->preedit_str != NULL) g_string_insert (tmp, cursor_index, priv->preedit_str); if (priv->password_char == 0) index_ = offset_to_bytes (tmp->str, position); else index_ = position * password_char_bytes; free (text); g_string_free (tmp, TRUE); } pango_layout_get_cursor_pos (clutter_text_get_layout (self), index_, &rect, NULL); if (x) { *x = (gfloat) rect.x / 1024.0f; /* Take any offset due to scrolling into account */ if (priv->single_line_mode) *x += priv->text_x; } if (y) *y = (gfloat) rect.y / 1024.0f; if (line_height) *line_height = (gfloat) rect.height / 1024.0f; return TRUE; } static inline void update_cursor_location (ClutterText *self) { ClutterTextPrivate *priv = self->priv; ClutterRect rect; float x, y; if (!priv->editable) return; rect = priv->cursor_rect; clutter_actor_get_transformed_position (CLUTTER_ACTOR (self), &x, &y); clutter_rect_offset (&rect, x, y); clutter_input_focus_set_cursor_location (priv->input_focus, &rect); } static inline void clutter_text_ensure_cursor_position (ClutterText *self) { ClutterTextPrivate *priv = self->priv; gfloat x, y, cursor_height; ClutterRect cursor_rect = CLUTTER_RECT_INIT_ZERO; gint position; position = priv->position; if (priv->editable && priv->preedit_set) { if (position == -1) position = clutter_text_buffer_get_length (get_buffer (self)); position += priv->preedit_cursor_pos; } CLUTTER_NOTE (MISC, "Cursor at %d (preedit %s at pos: %d)", position, priv->preedit_set ? "set" : "unset", priv->preedit_set ? priv->preedit_cursor_pos : 0); x = y = cursor_height = 0; clutter_text_position_to_coords (self, position, &x, &y, &cursor_height); clutter_rect_init (&cursor_rect, x, y + CURSOR_Y_PADDING, priv->cursor_size, cursor_height - 2 * CURSOR_Y_PADDING); if (!clutter_rect_equals (&priv->cursor_rect, &cursor_rect)) { ClutterGeometry cursor_pos; priv->cursor_rect = cursor_rect; /* XXX:2.0 - remove */ cursor_pos.x = clutter_rect_get_x (&priv->cursor_rect); cursor_pos.y = clutter_rect_get_y (&priv->cursor_rect); cursor_pos.width = clutter_rect_get_width (&priv->cursor_rect); cursor_pos.height = clutter_rect_get_height (&priv->cursor_rect); g_signal_emit (self, text_signals[CURSOR_EVENT], 0, &cursor_pos); g_signal_emit (self, text_signals[CURSOR_CHANGED], 0); #ifdef __CLUTTER_WAYLAND_COMPOSITOR_H__ update_cursor_location (self); #endif } } /** * clutter_text_delete_selection: * @self: a #ClutterText * * Deletes the currently selected text * * This function is only useful in subclasses of #ClutterText * * Return value: %TRUE if text was deleted or if the text actor * is empty, and %FALSE otherwise * * Since: 1.0 */ gboolean clutter_text_delete_selection (ClutterText *self) { ClutterTextPrivate *priv; gint start_index; gint end_index; gint old_position, old_selection; guint n_chars; g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); priv = self->priv; n_chars = clutter_text_buffer_get_length (get_buffer (self)); if (n_chars == 0) return TRUE; start_index = priv->position == -1 ? n_chars : priv->position; end_index = priv->selection_bound == -1 ? n_chars : priv->selection_bound; if (end_index == start_index) return FALSE; if (end_index < start_index) { gint temp = start_index; start_index = end_index; end_index = temp; } old_position = priv->position; old_selection = priv->selection_bound; clutter_text_delete_text (self, start_index, end_index); priv->position = start_index; priv->selection_bound = start_index; /* Not required to be guarded by g_object_freeze/thaw_notify */ if (priv->position != old_position) { /* XXX:2.0 - remove */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_POSITION]); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_POSITION]); } if (priv->selection_bound != old_selection) g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]); return TRUE; } /* * Utility function to update both cursor position and selection bound * at once */ static inline void clutter_text_set_positions (ClutterText *self, gint new_pos, gint new_bound) { g_object_freeze_notify (G_OBJECT (self)); clutter_text_set_cursor_position (self, new_pos); clutter_text_set_selection_bound (self, new_bound); g_object_thaw_notify (G_OBJECT (self)); } static inline void clutter_text_set_markup_internal (ClutterText *self, const gchar *str) { ClutterTextPrivate *priv = self->priv; GError *error; gchar *text = NULL; PangoAttrList *attrs = NULL; gboolean res; g_assert (str != NULL); error = NULL; res = pango_parse_markup (str, -1, 0, &attrs, &text, NULL, &error); if (!res) { if (G_LIKELY (error != NULL)) { g_warning ("Failed to set the markup of the actor '%s': %s", _clutter_actor_get_debug_name (CLUTTER_ACTOR (self)), error->message); g_error_free (error); } else g_warning ("Failed to set the markup of the actor '%s'", _clutter_actor_get_debug_name (CLUTTER_ACTOR (self))); return; } if (text) { clutter_text_buffer_set_text (get_buffer (self), text, -1); free (text); } /* Store the new markup attributes */ if (priv->markup_attrs != NULL) pango_attr_list_unref (priv->markup_attrs); priv->markup_attrs = attrs; /* Clear the effective attributes so they will be regenerated when a layout is created */ if (priv->effective_attrs != NULL) { pango_attr_list_unref (priv->effective_attrs); priv->effective_attrs = NULL; } } static void clutter_text_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterText *self = CLUTTER_TEXT (gobject); switch (prop_id) { case PROP_BUFFER: clutter_text_set_buffer (self, g_value_get_object (value)); break; case PROP_TEXT: { const char *str = g_value_get_string (value); if (self->priv->use_markup) clutter_text_set_markup_internal (self, str ? str : ""); else clutter_text_buffer_set_text (get_buffer (self), str ? str : "", -1); } break; case PROP_COLOR: clutter_text_set_color (self, clutter_value_get_color (value)); break; case PROP_FONT_NAME: clutter_text_set_font_name (self, g_value_get_string (value)); break; case PROP_FONT_DESCRIPTION: clutter_text_set_font_description (self, g_value_get_boxed (value)); break; case PROP_USE_MARKUP: clutter_text_set_use_markup (self, g_value_get_boolean (value)); break; case PROP_ATTRIBUTES: clutter_text_set_attributes (self, g_value_get_boxed (value)); break; case PROP_LINE_ALIGNMENT: clutter_text_set_line_alignment (self, g_value_get_enum (value)); break; case PROP_LINE_WRAP: clutter_text_set_line_wrap (self, g_value_get_boolean (value)); break; case PROP_LINE_WRAP_MODE: clutter_text_set_line_wrap_mode (self, g_value_get_enum (value)); break; case PROP_JUSTIFY: clutter_text_set_justify (self, g_value_get_boolean (value)); break; case PROP_ELLIPSIZE: clutter_text_set_ellipsize (self, g_value_get_enum (value)); break; case PROP_POSITION: /* XXX:2.0: remove */ case PROP_CURSOR_POSITION: clutter_text_set_cursor_position (self, g_value_get_int (value)); break; case PROP_SELECTION_BOUND: clutter_text_set_selection_bound (self, g_value_get_int (value)); break; case PROP_SELECTION_COLOR: clutter_text_set_selection_color (self, g_value_get_boxed (value)); break; case PROP_CURSOR_VISIBLE: clutter_text_set_cursor_visible (self, g_value_get_boolean (value)); break; case PROP_CURSOR_COLOR: clutter_text_set_cursor_color (self, g_value_get_boxed (value)); break; case PROP_CURSOR_SIZE: clutter_text_set_cursor_size (self, g_value_get_int (value)); break; case PROP_EDITABLE: clutter_text_set_editable (self, g_value_get_boolean (value)); break; case PROP_ACTIVATABLE: clutter_text_set_activatable (self, g_value_get_boolean (value)); break; case PROP_SELECTABLE: clutter_text_set_selectable (self, g_value_get_boolean (value)); break; case PROP_PASSWORD_CHAR: clutter_text_set_password_char (self, g_value_get_uint (value)); break; case PROP_MAX_LENGTH: clutter_text_set_max_length (self, g_value_get_int (value)); break; case PROP_SINGLE_LINE_MODE: clutter_text_set_single_line_mode (self, g_value_get_boolean (value)); break; case PROP_SELECTED_TEXT_COLOR: clutter_text_set_selected_text_color (self, clutter_value_get_color (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_text_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterText *self = CLUTTER_TEXT (gobject); ClutterTextPrivate *priv = self->priv; switch (prop_id) { case PROP_BUFFER: g_value_set_object (value, clutter_text_get_buffer (self)); break; case PROP_TEXT: g_value_set_string (value, clutter_text_buffer_get_text (get_buffer (self))); break; case PROP_FONT_NAME: g_value_set_string (value, priv->font_name); break; case PROP_FONT_DESCRIPTION: g_value_set_boxed (value, priv->font_desc); break; case PROP_USE_MARKUP: g_value_set_boolean (value, priv->use_markup); break; case PROP_COLOR: clutter_value_set_color (value, &priv->text_color); break; case PROP_CURSOR_VISIBLE: g_value_set_boolean (value, priv->cursor_visible); break; case PROP_CURSOR_COLOR: clutter_value_set_color (value, &priv->cursor_color); break; case PROP_CURSOR_COLOR_SET: g_value_set_boolean (value, priv->cursor_color_set); break; case PROP_CURSOR_SIZE: g_value_set_int (value, priv->cursor_size); break; case PROP_POSITION: /* XXX:2.0 - remove */ case PROP_CURSOR_POSITION: g_value_set_int (value, priv->position); break; case PROP_SELECTION_BOUND: g_value_set_int (value, priv->selection_bound); break; case PROP_EDITABLE: g_value_set_boolean (value, priv->editable); break; case PROP_SELECTABLE: g_value_set_boolean (value, priv->selectable); break; case PROP_SELECTION_COLOR: clutter_value_set_color (value, &priv->selection_color); break; case PROP_SELECTION_COLOR_SET: g_value_set_boolean (value, priv->selection_color_set); break; case PROP_ACTIVATABLE: g_value_set_boolean (value, priv->activatable); break; case PROP_PASSWORD_CHAR: g_value_set_uint (value, priv->password_char); break; case PROP_MAX_LENGTH: g_value_set_int (value, clutter_text_buffer_get_max_length (get_buffer (self))); break; case PROP_SINGLE_LINE_MODE: g_value_set_boolean (value, priv->single_line_mode); break; case PROP_ELLIPSIZE: g_value_set_enum (value, priv->ellipsize); break; case PROP_LINE_WRAP: g_value_set_boolean (value, priv->wrap); break; case PROP_LINE_WRAP_MODE: g_value_set_enum (value, priv->wrap_mode); break; case PROP_LINE_ALIGNMENT: g_value_set_enum (value, priv->alignment); break; case PROP_JUSTIFY: g_value_set_boolean (value, priv->justify); break; case PROP_ATTRIBUTES: g_value_set_boxed (value, priv->attrs); break; case PROP_SELECTED_TEXT_COLOR: clutter_value_set_color (value, &priv->selected_text_color); break; case PROP_SELECTED_TEXT_COLOR_SET: g_value_set_boolean (value, priv->selected_text_color_set); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_text_dispose (GObject *gobject) { ClutterText *self = CLUTTER_TEXT (gobject); ClutterTextPrivate *priv = self->priv; /* get rid of the entire cache */ clutter_text_dirty_cache (self); if (priv->direction_changed_id) { g_signal_handler_disconnect (self, priv->direction_changed_id); priv->direction_changed_id = 0; } if (priv->settings_changed_id) { g_signal_handler_disconnect (clutter_get_default_backend (), priv->settings_changed_id); priv->settings_changed_id = 0; } if (priv->password_hint_id) { g_source_remove (priv->password_hint_id); priv->password_hint_id = 0; } clutter_text_set_buffer (self, NULL); G_OBJECT_CLASS (clutter_text_parent_class)->dispose (gobject); } static void clutter_text_finalize (GObject *gobject) { ClutterText *self = CLUTTER_TEXT (gobject); ClutterTextPrivate *priv = self->priv; if (priv->font_desc) pango_font_description_free (priv->font_desc); if (priv->attrs) pango_attr_list_unref (priv->attrs); if (priv->markup_attrs) pango_attr_list_unref (priv->markup_attrs); if (priv->effective_attrs) pango_attr_list_unref (priv->effective_attrs); if (priv->preedit_attrs) pango_attr_list_unref (priv->preedit_attrs); clutter_text_dirty_paint_volume (self); clutter_text_set_buffer (self, NULL); free (priv->font_name); g_clear_object (&priv->input_focus); G_OBJECT_CLASS (clutter_text_parent_class)->finalize (gobject); } typedef void (* ClutterTextSelectionFunc) (ClutterText *text, const ClutterActorBox *box, gpointer user_data); static void clutter_text_foreach_selection_rectangle (ClutterText *self, ClutterTextSelectionFunc func, gpointer user_data) { ClutterTextPrivate *priv = self->priv; PangoLayout *layout = clutter_text_get_layout (self); gchar *utf8 = clutter_text_get_display_text (self); gint lines; gint start_index; gint end_index; gint line_no; if (priv->position == 0) start_index = 0; else start_index = offset_to_bytes (utf8, priv->position); if (priv->selection_bound == 0) end_index = 0; else end_index = offset_to_bytes (utf8, priv->selection_bound); if (start_index > end_index) { gint temp = start_index; start_index = end_index; end_index = temp; } lines = pango_layout_get_line_count (layout); for (line_no = 0; line_no < lines; line_no++) { PangoLayoutLine *line; gint n_ranges; gint *ranges; gint i; gint index_; gint maxindex; ClutterActorBox box; gfloat y, height; line = pango_layout_get_line_readonly (layout, line_no); pango_layout_line_x_to_index (line, G_MAXINT, &maxindex, NULL); if (maxindex < start_index) continue; pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges); pango_layout_line_x_to_index (line, 0, &index_, NULL); clutter_text_position_to_coords (self, bytes_to_offset (utf8, index_), NULL, &y, &height); box.y1 = y; box.y2 = y + height; for (i = 0; i < n_ranges; i++) { gfloat range_x; gfloat range_width; range_x = ranges[i * 2] / PANGO_SCALE; /* Account for any scrolling in single line mode */ if (priv->single_line_mode) range_x += priv->text_x; range_width = ((gfloat) ranges[i * 2 + 1] - (gfloat) ranges[i * 2]) / PANGO_SCALE; box.x1 = range_x; box.x2 = ceilf (range_x + range_width + .5f); func (self, &box, user_data); } free (ranges); } free (utf8); } static void add_selection_rectangle_to_path (ClutterText *text, const ClutterActorBox *box, gpointer user_data) { cogl_path_rectangle (user_data, box->x1, box->y1, box->x2, box->y2); } /* Draws the selected text, its background, and the cursor */ static void selection_paint (ClutterText *self) { ClutterTextPrivate *priv = self->priv; ClutterActor *actor = CLUTTER_ACTOR (self); guint8 paint_opacity = clutter_actor_get_paint_opacity (actor); const ClutterColor *color; if (!clutter_text_should_draw_cursor (self)) return; if (priv->position == priv->selection_bound) { /* No selection, just draw the cursor */ if (priv->cursor_color_set) color = &priv->cursor_color; else color = &priv->text_color; cogl_set_source_color4ub (color->red, color->green, color->blue, paint_opacity * color->alpha / 255); cogl_rectangle (priv->cursor_rect.origin.x, priv->cursor_rect.origin.y, priv->cursor_rect.origin.x + priv->cursor_rect.size.width, priv->cursor_rect.origin.y + priv->cursor_rect.size.height); } else { /* Paint selection background first */ PangoLayout *layout = clutter_text_get_layout (self); CoglPath *selection_path = cogl_path_new (); CoglColor cogl_color = { 0, }; CoglFramebuffer *fb; fb = _clutter_actor_get_active_framebuffer (actor); if (G_UNLIKELY (fb == NULL)) return; /* Paint selection background */ if (priv->selection_color_set) color = &priv->selection_color; else if (priv->cursor_color_set) color = &priv->cursor_color; else color = &priv->text_color; cogl_set_source_color4ub (color->red, color->green, color->blue, paint_opacity * color->alpha / 255); clutter_text_foreach_selection_rectangle (self, add_selection_rectangle_to_path, selection_path); cogl_path_fill (selection_path); /* Paint selected text */ cogl_framebuffer_push_path_clip (fb, selection_path); cogl_object_unref (selection_path); if (priv->selected_text_color_set) color = &priv->selected_text_color; else color = &priv->text_color; cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, paint_opacity * color->alpha / 255); cogl_pango_render_layout (layout, priv->text_x, 0, &cogl_color, 0); cogl_framebuffer_pop_clip (fb); } } static gint clutter_text_move_word_backward (ClutterText *self, gint start) { gint retval = start; if (clutter_text_buffer_get_length (get_buffer (self)) > 0 && start > 0) { PangoLayout *layout = clutter_text_get_layout (self); PangoLogAttr *log_attrs = NULL; gint n_attrs = 0; pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); retval = start - 1; while (retval > 0 && !log_attrs[retval].is_word_start) retval -= 1; free (log_attrs); } return retval; } static gint clutter_text_move_word_forward (ClutterText *self, gint start) { gint retval = start; guint n_chars; n_chars = clutter_text_buffer_get_length (get_buffer (self)); if (n_chars > 0 && start < n_chars) { PangoLayout *layout = clutter_text_get_layout (self); PangoLogAttr *log_attrs = NULL; gint n_attrs = 0; pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); retval = start + 1; while (retval < n_chars && !log_attrs[retval].is_word_end) retval += 1; free (log_attrs); } return retval; } static gint clutter_text_move_line_start (ClutterText *self, gint start) { PangoLayoutLine *layout_line; PangoLayout *layout; gint line_no; gint index_; gint position; const gchar *text; layout = clutter_text_get_layout (self); text = clutter_text_buffer_get_text (get_buffer (self)); if (start == 0) index_ = 0; else index_ = offset_to_bytes (text, start); pango_layout_index_to_line_x (layout, index_, 0, &line_no, NULL); layout_line = pango_layout_get_line_readonly (layout, line_no); if (!layout_line) return FALSE; pango_layout_line_x_to_index (layout_line, 0, &index_, NULL); position = bytes_to_offset (text, index_); return position; } static gint clutter_text_move_line_end (ClutterText *self, gint start) { ClutterTextPrivate *priv = self->priv; PangoLayoutLine *layout_line; PangoLayout *layout; gint line_no; gint index_; gint trailing; gint position; const gchar *text; layout = clutter_text_get_layout (self); text = clutter_text_buffer_get_text (get_buffer (self)); if (start == 0) index_ = 0; else index_ = offset_to_bytes (text, priv->position); pango_layout_index_to_line_x (layout, index_, 0, &line_no, NULL); layout_line = pango_layout_get_line_readonly (layout, line_no); if (!layout_line) return FALSE; pango_layout_line_x_to_index (layout_line, G_MAXINT, &index_, &trailing); index_ += trailing; position = bytes_to_offset (text, index_); return position; } static void clutter_text_select_word (ClutterText *self) { gint cursor_pos = self->priv->position; gint start_pos, end_pos; start_pos = clutter_text_move_word_backward (self, cursor_pos); end_pos = clutter_text_move_word_forward (self, cursor_pos); clutter_text_set_selection (self, start_pos, end_pos); } static void clutter_text_select_line (ClutterText *self) { ClutterTextPrivate *priv = self->priv; gint cursor_pos = priv->position; gint start_pos, end_pos; if (priv->single_line_mode) { start_pos = 0; end_pos = -1; } else { start_pos = clutter_text_move_line_start (self, cursor_pos); end_pos = clutter_text_move_line_end (self, cursor_pos); } clutter_text_set_selection (self, start_pos, end_pos); } static gboolean clutter_text_press (ClutterActor *actor, ClutterEvent *event) { ClutterText *self = CLUTTER_TEXT (actor); ClutterTextPrivate *priv = self->priv; ClutterEventType type = clutter_event_type (event); gboolean res = FALSE; gfloat x, y; gint index_; /* if a ClutterText is just used for display purposes, then we * should ignore the events we receive */ if (!(priv->editable || priv->selectable)) return CLUTTER_EVENT_PROPAGATE; clutter_actor_grab_key_focus (actor); // clutter_input_focus_request_toggle_input_panel (priv->input_focus); /* if the actor is empty we just reset everything and not * set up the dragging of the selection since there's nothing * to select */ if (clutter_text_buffer_get_length (get_buffer (self)) == 0) { clutter_text_set_positions (self, -1, -1); return CLUTTER_EVENT_STOP; } clutter_event_get_coords (event, &x, &y); res = clutter_actor_transform_stage_point (actor, x, y, &x, &y); if (res) { const char *text; int offset; index_ = clutter_text_coords_to_position (self, x, y); text = clutter_text_buffer_get_text (get_buffer (self)); offset = bytes_to_offset (text, index_); /* what we select depends on the number of button clicks we * receive, and whether we are selectable: * * 1: just position the cursor and the selection * 2: select the current word * 3: select the contents of the whole actor */ if (type == CLUTTER_BUTTON_PRESS) { gint click_count = clutter_event_get_click_count (event); if (click_count == 1) { clutter_text_set_positions (self, offset, offset); } else if (priv->selectable && click_count == 2) { clutter_text_select_word (self); } else if (priv->selectable && click_count == 3) { clutter_text_select_line (self); } } else { /* touch events do not have click count */ clutter_text_set_positions (self, offset, offset); } } /* we don't need to go any further if we're not selectable */ if (!priv->selectable) return CLUTTER_EVENT_STOP; /* grab the pointer */ priv->in_select_drag = TRUE; if (type == CLUTTER_BUTTON_PRESS) clutter_grab_pointer (actor); else { clutter_input_device_sequence_grab (clutter_event_get_device (event), clutter_event_get_event_sequence (event), actor); priv->in_select_touch = TRUE; } return CLUTTER_EVENT_STOP; } static gboolean clutter_text_move (ClutterActor *actor, ClutterEvent *event) { ClutterText *self = CLUTTER_TEXT (actor); ClutterTextPrivate *priv = self->priv; gfloat x, y; gint index_, offset; gboolean res; const gchar *text; if (!priv->in_select_drag) return CLUTTER_EVENT_PROPAGATE; clutter_event_get_coords (event, &x, &y); res = clutter_actor_transform_stage_point (actor, x, y, &x, &y); if (!res) return CLUTTER_EVENT_PROPAGATE; index_ = clutter_text_coords_to_position (self, x, y); text = clutter_text_buffer_get_text (get_buffer (self)); offset = bytes_to_offset (text, index_); if (priv->selectable) clutter_text_set_cursor_position (self, offset); else clutter_text_set_positions (self, offset, offset); return CLUTTER_EVENT_STOP; } static gboolean clutter_text_release (ClutterActor *actor, ClutterEvent *event) { ClutterText *self = CLUTTER_TEXT (actor); ClutterTextPrivate *priv = self->priv; ClutterEventType type = clutter_event_type (event); if (priv->in_select_drag) { if (type == CLUTTER_BUTTON_RELEASE) { if (!priv->in_select_touch) { clutter_ungrab_pointer (); priv->in_select_drag = FALSE; return CLUTTER_EVENT_STOP; } } else { if (priv->in_select_touch) { ClutterInputDevice *device = clutter_event_get_device (event); ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); clutter_input_device_sequence_ungrab (device, sequence); priv->in_select_touch = FALSE; priv->in_select_drag = FALSE; return CLUTTER_EVENT_STOP; } } } return CLUTTER_EVENT_PROPAGATE; } static gboolean clutter_text_button_press (ClutterActor *actor, ClutterButtonEvent *event) { return clutter_text_press (actor, (ClutterEvent *) event); } static gboolean clutter_text_motion (ClutterActor *actor, ClutterMotionEvent *event) { return clutter_text_move (actor, (ClutterEvent *) event); } static gboolean clutter_text_button_release (ClutterActor *actor, ClutterButtonEvent *event) { return clutter_text_release (actor, (ClutterEvent *) event); } static gboolean clutter_text_touch_event (ClutterActor *actor, ClutterTouchEvent *event) { switch (event->type) { case CLUTTER_TOUCH_BEGIN: return clutter_text_press (actor, (ClutterEvent *) event); case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: /* TODO: the cancel case probably need a special handler */ return clutter_text_release (actor, (ClutterEvent *) event); case CLUTTER_TOUCH_UPDATE: return clutter_text_move (actor, (ClutterEvent *) event); default: break; } return CLUTTER_EVENT_PROPAGATE; } static gboolean clutter_text_remove_password_hint (gpointer data) { ClutterText *self = data; self->priv->password_hint_visible = FALSE; self->priv->password_hint_id = 0; clutter_text_dirty_cache (data); clutter_text_queue_redraw (data); return G_SOURCE_REMOVE; } static gboolean clutter_text_key_press (ClutterActor *actor, ClutterKeyEvent *event) { ClutterText *self = CLUTTER_TEXT (actor); ClutterTextPrivate *priv = self->priv; ClutterBindingPool *pool; gboolean res; if (!priv->editable) return CLUTTER_EVENT_PROPAGATE; /* we need to use the ClutterText type name to find our own * key bindings; subclasses will override or chain up this * event handler, so they can do whatever they want there */ pool = clutter_binding_pool_find (g_type_name (CLUTTER_TYPE_TEXT)); g_assert (pool != NULL); if (!(event->flags & CLUTTER_EVENT_FLAG_INPUT_METHOD) && clutter_input_focus_is_focused (priv->input_focus) && clutter_input_focus_filter_key_event (priv->input_focus, event)) return CLUTTER_EVENT_STOP; /* we allow passing synthetic events that only contain * the Unicode value and not the key symbol, unless they * contain the input method flag. */ if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC) && !(event->flags & CLUTTER_EVENT_FLAG_INPUT_METHOD)) res = FALSE; else res = clutter_binding_pool_activate (pool, event->keyval, event->modifier_state, G_OBJECT (actor)); /* if the key binding has handled the event we bail out * as fast as we can; otherwise, we try to insert the * Unicode character inside the key event into the text * actor */ if (res) return CLUTTER_EVENT_STOP; else if ((event->modifier_state & CLUTTER_CONTROL_MASK) == 0) { gunichar key_unichar; /* Skip keys when control is pressed */ key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) event); /* return is reported as CR, but we want LF */ if (key_unichar == '\r') key_unichar = '\n'; if ((key_unichar == '\n' && !priv->single_line_mode) || (g_unichar_validate (key_unichar) && !g_unichar_iscntrl (key_unichar))) { /* truncate the eventual selection so that the * Unicode character can replace it */ clutter_text_delete_selection (self); clutter_text_insert_unichar (self, key_unichar); if (priv->show_password_hint) { if (priv->password_hint_id != 0) g_source_remove (priv->password_hint_id); priv->password_hint_visible = TRUE; priv->password_hint_id = clutter_threads_add_timeout (priv->password_hint_timeout, clutter_text_remove_password_hint, self); } return CLUTTER_EVENT_STOP; } } return CLUTTER_EVENT_PROPAGATE; } static gboolean clutter_text_key_release (ClutterActor *actor, ClutterKeyEvent *event) { ClutterText *self = CLUTTER_TEXT (actor); ClutterTextPrivate *priv = self->priv; if (clutter_input_focus_is_focused (priv->input_focus) && clutter_input_focus_filter_key_event (priv->input_focus, event)) return CLUTTER_EVENT_STOP; return CLUTTER_EVENT_PROPAGATE; } static void clutter_text_compute_layout_offsets (ClutterText *self, PangoLayout *layout, const ClutterActorBox *alloc, int *text_x, int *text_y) { ClutterActor *actor = CLUTTER_ACTOR (self); ClutterActorAlign x_align, y_align; PangoRectangle logical_rect; float alloc_width, alloc_height; float x, y; clutter_actor_box_get_size (alloc, &alloc_width, &alloc_height); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); if (clutter_actor_needs_expand (actor, CLUTTER_ORIENTATION_HORIZONTAL)) x_align = _clutter_actor_get_effective_x_align (actor); else x_align = CLUTTER_ACTOR_ALIGN_FILL; if (clutter_actor_needs_expand (actor, CLUTTER_ORIENTATION_VERTICAL)) y_align = clutter_actor_get_y_align (actor); else y_align = CLUTTER_ACTOR_ALIGN_FILL; x = 0.f; switch (x_align) { case CLUTTER_ACTOR_ALIGN_FILL: case CLUTTER_ACTOR_ALIGN_START: break; case CLUTTER_ACTOR_ALIGN_END: if (alloc_width > logical_rect.width) x = alloc_width - logical_rect.width; break; case CLUTTER_ACTOR_ALIGN_CENTER: if (alloc_width > logical_rect.width) x = (alloc_width - logical_rect.width) / 2.f; break; } y = 0.f; switch (y_align) { case CLUTTER_ACTOR_ALIGN_FILL: case CLUTTER_ACTOR_ALIGN_START: break; case CLUTTER_ACTOR_ALIGN_END: if (alloc_height > logical_rect.height) y = alloc_height - logical_rect.height; break; case CLUTTER_ACTOR_ALIGN_CENTER: if (alloc_height > logical_rect.height) y = (alloc_height - logical_rect.height) / 2.f; break; } if (text_x != NULL) *text_x = floorf (x); if (text_y != NULL) *text_y = floorf (y); } #define TEXT_PADDING 2 static void clutter_text_paint (ClutterActor *self) { ClutterText *text = CLUTTER_TEXT (self); ClutterTextPrivate *priv = text->priv; CoglFramebuffer *fb; PangoLayout *layout; ClutterActorBox alloc = { 0, }; CoglColor color = { 0, }; guint8 real_opacity; gint text_x = priv->text_x; gint text_y = priv->text_y; gboolean clip_set = FALSE; gboolean bg_color_set = FALSE; guint n_chars; float alloc_width; float alloc_height; /* FIXME: this should not be needed, but apparently the text-cache * test unit manages to get in a situation where the active frame * buffer is NULL */ fb = _clutter_actor_get_active_framebuffer (self); if (fb == NULL) fb = cogl_get_draw_framebuffer (); /* Note that if anything in this paint method changes it needs to be reflected in the get_paint_volume implementation which is tightly tied to the workings of this function */ n_chars = clutter_text_buffer_get_length (get_buffer (text)); clutter_actor_get_allocation_box (self, &alloc); alloc_width = alloc.x2 - alloc.x1; alloc_height = alloc.y2 - alloc.y1; g_object_get (self, "background-color-set", &bg_color_set, NULL); if (bg_color_set) { ClutterColor bg_color; clutter_actor_get_background_color (self, &bg_color); bg_color.alpha = clutter_actor_get_paint_opacity (self) * bg_color.alpha / 255; cogl_set_source_color4ub (bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha); cogl_rectangle (0, 0, alloc_width, alloc_height); } /* don't bother painting an empty text actor, unless it's * editable, in which case we want to paint at least the * cursor */ if (n_chars == 0 && !clutter_text_should_draw_cursor (text)) return; if (priv->editable && priv->single_line_mode) layout = clutter_text_create_layout (text, -1, -1); else { /* the only time when we create the PangoLayout using the full * width and height of the allocation is when we can both wrap * and ellipsize */ if (priv->wrap && priv->ellipsize) { layout = clutter_text_create_layout (text, alloc_width, alloc_height); } else { /* if we're not wrapping we cannot set the height of the * layout, otherwise Pango will happily wrap the text to * fit in the rectangle - thus making the :wrap property * useless * * see bug: * * http://bugzilla.clutter-project.org/show_bug.cgi?id=2339 * * in order to fix this, we create a layout that would fit * in the assigned width, then we clip the actor if the * logical rectangle overflows the allocation. */ layout = clutter_text_create_layout (text, alloc_width, -1); } } if (clutter_text_should_draw_cursor (text)) clutter_text_ensure_cursor_position (text); if (priv->editable && priv->single_line_mode) { PangoRectangle logical_rect = { 0, }; gint actor_width, text_width; gboolean rtl; pango_layout_get_extents (layout, NULL, &logical_rect); cogl_framebuffer_push_rectangle_clip (fb, 0, 0, alloc_width, alloc_height); clip_set = TRUE; actor_width = alloc_width - 2 * TEXT_PADDING; text_width = logical_rect.width / PANGO_SCALE; rtl = priv->resolved_direction == PANGO_DIRECTION_RTL; if (actor_width < text_width) { gint cursor_x = clutter_rect_get_x (&priv->cursor_rect); if (priv->position == -1) { text_x = rtl ? TEXT_PADDING : actor_width - text_width; } else if (priv->position == 0) { text_x = rtl ? actor_width - text_width : TEXT_PADDING; } else { if (cursor_x < 0) { text_x = text_x - cursor_x - TEXT_PADDING; } else if (cursor_x > actor_width) { text_x = text_x + (actor_width - cursor_x) - TEXT_PADDING; } } } else { text_x = rtl ? actor_width - text_width : TEXT_PADDING; } } else if (!priv->editable && !(priv->wrap && priv->ellipsize)) { PangoRectangle logical_rect = { 0, }; pango_layout_get_pixel_extents (layout, NULL, &logical_rect); /* don't clip if the layout managed to fit inside our allocation */ if (logical_rect.width > alloc_width || logical_rect.height > alloc_height) { cogl_framebuffer_push_rectangle_clip (fb, 0, 0, alloc_width, alloc_height); clip_set = TRUE; } clutter_text_compute_layout_offsets (text, layout, &alloc, &text_x, &text_y); } else clutter_text_compute_layout_offsets (text, layout, &alloc, &text_x, &text_y); if (priv->text_x != text_x || priv->text_y != text_y) { priv->text_x = text_x; priv->text_y = text_y; clutter_text_ensure_cursor_position (text); } real_opacity = clutter_actor_get_paint_opacity (self) * priv->text_color.alpha / 255; CLUTTER_NOTE (PAINT, "painting text (text: '%s')", clutter_text_buffer_get_text (get_buffer (text))); cogl_color_init_from_4ub (&color, priv->text_color.red, priv->text_color.green, priv->text_color.blue, real_opacity); cogl_pango_render_layout (layout, priv->text_x, priv->text_y, &color, 0); selection_paint (text); if (clip_set) cogl_framebuffer_pop_clip (fb); } static void add_selection_to_paint_volume (ClutterText *text, const ClutterActorBox *box, gpointer user_data) { ClutterPaintVolume *total_volume = user_data; ClutterPaintVolume rect_volume; ClutterVertex vertex; _clutter_paint_volume_init_static (&rect_volume, CLUTTER_ACTOR (text)); vertex.x = box->x1; vertex.y = box->y1; vertex.z = 0.0f; clutter_paint_volume_set_origin (&rect_volume, &vertex); clutter_paint_volume_set_width (&rect_volume, box->x2 - box->x1); clutter_paint_volume_set_height (&rect_volume, box->y2 - box->y1); clutter_paint_volume_union (total_volume, &rect_volume); clutter_paint_volume_free (&rect_volume); } static void clutter_text_get_paint_volume_for_cursor (ClutterText *text, ClutterPaintVolume *volume) { ClutterTextPrivate *priv = text->priv; ClutterVertex origin; clutter_text_ensure_cursor_position (text); if (priv->position == priv->selection_bound) { origin.x = priv->cursor_rect.origin.x; origin.y = priv->cursor_rect.origin.y; origin.z = 0; clutter_paint_volume_set_origin (volume, &origin); clutter_paint_volume_set_width (volume, priv->cursor_rect.size.width); clutter_paint_volume_set_height (volume, priv->cursor_rect.size.height); } else { clutter_text_foreach_selection_rectangle (text, add_selection_to_paint_volume, volume); } } static gboolean clutter_text_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { ClutterText *text = CLUTTER_TEXT (self); ClutterTextPrivate *priv = text->priv; /* ClutterText uses the logical layout as the natural size of the actor. This means that it can sometimes paint outside of its allocation for example with italic fonts with serifs. Therefore we should use the ink rectangle of the layout instead */ if (!priv->paint_volume_valid) { PangoLayout *layout; PangoRectangle ink_rect; ClutterVertex origin; /* If the text is single line editable then it gets clipped to the allocation anyway so we can just use that */ if (priv->editable && priv->single_line_mode) return _clutter_actor_set_default_paint_volume (self, CLUTTER_TYPE_TEXT, volume); if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_TEXT) return FALSE; if (!clutter_actor_has_allocation (self)) return FALSE; _clutter_paint_volume_init_static (&priv->paint_volume, self); layout = clutter_text_get_layout (text); pango_layout_get_extents (layout, &ink_rect, NULL); origin.x = ink_rect.x / (float) PANGO_SCALE; origin.y = ink_rect.y / (float) PANGO_SCALE; origin.z = 0; clutter_paint_volume_set_origin (&priv->paint_volume, &origin); clutter_paint_volume_set_width (&priv->paint_volume, ink_rect.width / (float) PANGO_SCALE); clutter_paint_volume_set_height (&priv->paint_volume, ink_rect.height / (float) PANGO_SCALE); /* If the cursor is visible then that will likely be drawn outside of the ink rectangle so we should merge that in */ if (clutter_text_should_draw_cursor (text)) { ClutterPaintVolume cursor_paint_volume; _clutter_paint_volume_init_static (&cursor_paint_volume, self); clutter_text_get_paint_volume_for_cursor (text, &cursor_paint_volume); clutter_paint_volume_union (&priv->paint_volume, &cursor_paint_volume); clutter_paint_volume_free (&cursor_paint_volume); } priv->paint_volume_valid = TRUE; } _clutter_paint_volume_copy_static (&priv->paint_volume, volume); return TRUE; } static void clutter_text_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterText *text = CLUTTER_TEXT (self); ClutterTextPrivate *priv = text->priv; PangoRectangle logical_rect = { 0, }; PangoLayout *layout; gint logical_width; gfloat layout_width; layout = clutter_text_create_layout (text, -1, -1); pango_layout_get_extents (layout, NULL, &logical_rect); /* the X coordinate of the logical rectangle might be non-zero * according to the Pango documentation; hence, we need to offset * the width accordingly */ logical_width = logical_rect.x + logical_rect.width; layout_width = logical_width > 0 ? ceilf (logical_width / 1024.0f) : 1; if (min_width_p) { if (priv->wrap || priv->ellipsize || priv->editable) *min_width_p = 1; else *min_width_p = layout_width; } if (natural_width_p) { if (priv->editable && priv->single_line_mode) *natural_width_p = layout_width + TEXT_PADDING * 2; else *natural_width_p = layout_width; } } static void clutter_text_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv; if (for_width == 0) { if (min_height_p) *min_height_p = 0; if (natural_height_p) *natural_height_p = 0; } else { PangoLayout *layout; PangoRectangle logical_rect = { 0, }; gint logical_height; gfloat layout_height; if (priv->single_line_mode) for_width = -1; layout = clutter_text_create_layout (CLUTTER_TEXT (self), for_width, -1); pango_layout_get_extents (layout, NULL, &logical_rect); /* the Y coordinate of the logical rectangle might be non-zero * according to the Pango documentation; hence, we need to offset * the height accordingly */ logical_height = logical_rect.y + logical_rect.height; layout_height = ceilf (logical_height / 1024.0f); if (min_height_p) { /* if we wrap and ellipsize then the minimum height is * going to be at least the size of the first line */ if ((priv->ellipsize && priv->wrap) && !priv->single_line_mode) { PangoLayoutLine *line; gfloat line_height; line = pango_layout_get_line_readonly (layout, 0); pango_layout_line_get_extents (line, NULL, &logical_rect); logical_height = logical_rect.y + logical_rect.height; line_height = ceilf (logical_height / 1024.0f); *min_height_p = line_height; } else *min_height_p = layout_height; } if (natural_height_p) *natural_height_p = layout_height; } } static void clutter_text_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterText *text = CLUTTER_TEXT (self); ClutterActorClass *parent_class; /* Ensure that there is a cached layout with the right width so * that we don't need to create the text during the paint run * * if the Text is editable and in single line mode we don't want * to have any limit on the layout size, since the paint will clip * it to the allocation of the actor */ if (text->priv->editable && text->priv->single_line_mode) clutter_text_create_layout (text, -1, -1); else clutter_text_create_layout (text, box->x2 - box->x1, box->y2 - box->y1); parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class); parent_class->allocate (self, box, flags); } static gboolean clutter_text_has_overlaps (ClutterActor *self) { return clutter_text_should_draw_cursor ((ClutterText *) self); } static void clutter_text_key_focus_in (ClutterActor *actor) { ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv; ClutterBackend *backend = clutter_get_default_backend (); ClutterInputMethod *method = clutter_backend_get_input_method (backend); if (method && priv->editable) { clutter_input_method_focus_in (method, priv->input_focus); clutter_input_focus_set_content_purpose (priv->input_focus, priv->input_purpose); clutter_input_focus_set_content_hints (priv->input_focus, priv->input_hints); #ifdef __CLUTTER_WAYLAND_COMPOSITOR_H__ update_cursor_location (CLUTTER_TEXT (actor)); #endif } priv->has_focus = TRUE; clutter_text_queue_redraw (actor); } static void clutter_text_key_focus_out (ClutterActor *actor) { ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv; ClutterBackend *backend = clutter_get_default_backend (); ClutterInputMethod *method = clutter_backend_get_input_method (backend); priv->has_focus = FALSE; if (priv->editable && clutter_input_focus_is_focused (priv->input_focus)) { clutter_text_set_preedit_string (CLUTTER_TEXT (actor), NULL, NULL, 0); clutter_input_method_focus_out (method); } clutter_text_queue_redraw (actor); } static gboolean clutter_text_real_move_left (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint pos = priv->position; gint new_pos = 0; gint len; len = clutter_text_buffer_get_length (get_buffer (self)); g_object_freeze_notify (G_OBJECT (self)); if (pos != 0 && len != 0) { if (modifiers & CLUTTER_CONTROL_MASK) { if (pos == -1) new_pos = clutter_text_move_word_backward (self, len); else new_pos = clutter_text_move_word_backward (self, pos); } else { if (pos == -1) new_pos = len - 1; else new_pos = pos - 1; } clutter_text_set_cursor_position (self, new_pos); } if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK))) clutter_text_clear_selection (self); g_object_thaw_notify (G_OBJECT (self)); return TRUE; } static gboolean clutter_text_real_move_right (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint pos = priv->position; gint len = clutter_text_buffer_get_length (get_buffer (self)); gint new_pos = 0; g_object_freeze_notify (G_OBJECT (self)); if (pos != -1 && len !=0) { if (modifiers & CLUTTER_CONTROL_MASK) { if (pos != len) new_pos = clutter_text_move_word_forward (self, pos); } else { if (pos != len) new_pos = pos + 1; } clutter_text_set_cursor_position (self, new_pos); } if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK))) clutter_text_clear_selection (self); g_object_thaw_notify (G_OBJECT (self)); return TRUE; } static gboolean clutter_text_real_move_up (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; PangoLayoutLine *layout_line; PangoLayout *layout; gint line_no; gint index_, trailing; gint pos; gint x; const gchar *text; layout = clutter_text_get_layout (self); text = clutter_text_buffer_get_text (get_buffer (self)); if (priv->position == 0) index_ = 0; else index_ = offset_to_bytes (text, priv->position); pango_layout_index_to_line_x (layout, index_, 0, &line_no, &x); line_no -= 1; if (line_no < 0) return FALSE; if (priv->x_pos != -1) x = priv->x_pos; layout_line = pango_layout_get_line_readonly (layout, line_no); if (!layout_line) return FALSE; pango_layout_line_x_to_index (layout_line, x, &index_, &trailing); g_object_freeze_notify (G_OBJECT (self)); pos = bytes_to_offset (text, index_); clutter_text_set_cursor_position (self, pos + trailing); /* Store the target x position to avoid drifting left and right when moving the cursor up and down */ priv->x_pos = x; if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK))) clutter_text_clear_selection (self); g_object_thaw_notify (G_OBJECT (self)); return TRUE; } static gboolean clutter_text_real_move_down (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; PangoLayoutLine *layout_line; PangoLayout *layout; gint line_no; gint index_, trailing; gint x; gint pos; const gchar *text; layout = clutter_text_get_layout (self); text = clutter_text_buffer_get_text (get_buffer (self)); if (priv->position == 0) index_ = 0; else index_ = offset_to_bytes (text, priv->position); pango_layout_index_to_line_x (layout, index_, 0, &line_no, &x); if (priv->x_pos != -1) x = priv->x_pos; layout_line = pango_layout_get_line_readonly (layout, line_no + 1); if (!layout_line) return FALSE; pango_layout_line_x_to_index (layout_line, x, &index_, &trailing); g_object_freeze_notify (G_OBJECT (self)); pos = bytes_to_offset (text, index_); clutter_text_set_cursor_position (self, pos + trailing); /* Store the target x position to avoid drifting left and right when moving the cursor up and down */ priv->x_pos = x; if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK))) clutter_text_clear_selection (self); g_object_thaw_notify (G_OBJECT (self)); return TRUE; } static gboolean clutter_text_real_line_start (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint position; g_object_freeze_notify (G_OBJECT (self)); position = clutter_text_move_line_start (self, priv->position); clutter_text_set_cursor_position (self, position); if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK))) clutter_text_clear_selection (self); g_object_thaw_notify (G_OBJECT (self)); return TRUE; } static gboolean clutter_text_real_line_end (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint position; g_object_freeze_notify (G_OBJECT (self)); position = clutter_text_move_line_end (self, priv->position); clutter_text_set_cursor_position (self, position); if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK))) clutter_text_clear_selection (self); g_object_thaw_notify (G_OBJECT (self)); return TRUE; } static gboolean clutter_text_real_select_all (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { guint n_chars = clutter_text_buffer_get_length (get_buffer (self)); clutter_text_set_positions (self, 0, n_chars); return TRUE; } static gboolean clutter_text_real_del_next (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint pos; gint len; if (clutter_text_delete_selection (self)) return TRUE; pos = priv->position; len = clutter_text_buffer_get_length (get_buffer (self)); if (len && pos != -1 && pos < len) clutter_text_delete_text (self, pos, pos + 1); return TRUE; } static gboolean clutter_text_real_del_word_next (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint pos; gint len; pos = priv->position; len = clutter_text_buffer_get_length (get_buffer (self)); if (len && pos != -1 && pos < len) { gint end; end = clutter_text_move_word_forward (self, pos); clutter_text_delete_text (self, pos, end); if (priv->selection_bound >= end) { gint new_bound; new_bound = priv->selection_bound - (end - pos); clutter_text_set_selection_bound (self, new_bound); } else if (priv->selection_bound > pos) { clutter_text_set_selection_bound (self, pos); } } return TRUE; } static gboolean clutter_text_real_del_prev (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint pos; gint len; if (clutter_text_delete_selection (self)) return TRUE; pos = priv->position; len = clutter_text_buffer_get_length (get_buffer (self)); if (pos != 0 && len != 0) { if (pos == -1) { clutter_text_delete_text (self, len - 1, len); clutter_text_set_positions (self, -1, -1); } else { clutter_text_delete_text (self, pos - 1, pos); clutter_text_set_positions (self, pos - 1, pos - 1); } } return TRUE; } static gboolean clutter_text_real_del_word_prev (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { ClutterTextPrivate *priv = self->priv; gint pos; gint len; pos = priv->position; len = clutter_text_buffer_get_length (get_buffer (self)); if (pos != 0 && len != 0) { gint new_pos; if (pos == -1) { new_pos = clutter_text_move_word_backward (self, len); clutter_text_delete_text (self, new_pos, len); clutter_text_set_positions (self, -1, -1); } else { new_pos = clutter_text_move_word_backward (self, pos); clutter_text_delete_text (self, new_pos, pos); clutter_text_set_cursor_position (self, new_pos); if (priv->selection_bound >= pos) { gint new_bound; new_bound = priv->selection_bound - (pos - new_pos); clutter_text_set_selection_bound (self, new_bound); } else if (priv->selection_bound >= new_pos) { clutter_text_set_selection_bound (self, new_pos); } } } return TRUE; } static gboolean clutter_text_real_activate (ClutterText *self, const gchar *action, guint keyval, ClutterModifierType modifiers) { return clutter_text_activate (self); } static inline void clutter_text_add_move_binding (ClutterBindingPool *pool, const gchar *action, guint key_val, ClutterModifierType additional_modifiers, GCallback callback) { clutter_binding_pool_install_action (pool, action, key_val, 0, callback, NULL, NULL); clutter_binding_pool_install_action (pool, action, key_val, CLUTTER_SHIFT_MASK, callback, NULL, NULL); if (additional_modifiers != 0) { clutter_binding_pool_install_action (pool, action, key_val, additional_modifiers, callback, NULL, NULL); clutter_binding_pool_install_action (pool, action, key_val, CLUTTER_SHIFT_MASK | additional_modifiers, callback, NULL, NULL); } } static gboolean clutter_text_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { if (strncmp (name, "font-description", 16) == 0) { g_value_init (value, G_TYPE_STRING); g_value_set_string (value, json_node_get_string (node)); return TRUE; } return parent_scriptable_iface->parse_custom_node (scriptable, script, value, name, node); } static void clutter_text_set_color_internal (ClutterText *self, GParamSpec *pspec, const ClutterColor *color) { ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv; GParamSpec *other = NULL; switch (pspec->param_id) { case PROP_COLOR: priv->text_color = *color; break; case PROP_CURSOR_COLOR: if (color) { priv->cursor_color = *color; priv->cursor_color_set = TRUE; } else priv->cursor_color_set = FALSE; other = obj_props[PROP_CURSOR_COLOR_SET]; break; case PROP_SELECTION_COLOR: if (color) { priv->selection_color = *color; priv->selection_color_set = TRUE; } else priv->selection_color_set = FALSE; other = obj_props[PROP_SELECTION_COLOR_SET]; break; case PROP_SELECTED_TEXT_COLOR: if (color) { priv->selected_text_color = *color; priv->selected_text_color_set = TRUE; } else priv->selected_text_color_set = FALSE; other = obj_props[PROP_SELECTED_TEXT_COLOR_SET]; break; default: g_assert_not_reached (); break; } clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), pspec); if (other) g_object_notify_by_pspec (G_OBJECT (self), other); } static void clutter_text_set_color_animated (ClutterText *self, GParamSpec *pspec, const ClutterColor *color) { ClutterActor *actor = CLUTTER_ACTOR (self); ClutterTextPrivate *priv = self->priv; const ClutterAnimationInfo *info; ClutterTransition *transition; info = _clutter_actor_get_animation_info (actor); transition = clutter_actor_get_transition (actor, pspec->name); /* jump to the end if there is no easing state, or if the easing * state has a duration of 0 msecs */ if (info->cur_state == NULL || info->cur_state->easing_duration == 0) { /* ensure that we remove any currently running transition */ if (transition != NULL) { clutter_actor_remove_transition (actor, pspec->name); transition = NULL; } clutter_text_set_color_internal (self, pspec, color); return; } if (transition == NULL) { transition = clutter_property_transition_new (pspec->name); clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self)); clutter_transition_set_remove_on_complete (transition, TRUE); /* delay only makes sense if the transition has just been created */ clutter_timeline_set_delay (CLUTTER_TIMELINE (transition), info->cur_state->easing_delay); clutter_actor_add_transition (actor, pspec->name, transition); /* the actor now owns the transition */ g_object_unref (transition); } /* if a transition already exist, update its bounds */ switch (pspec->param_id) { case PROP_COLOR: clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR, &priv->text_color); break; case PROP_CURSOR_COLOR: clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR, &priv->cursor_color); break; case PROP_SELECTION_COLOR: clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR, &priv->selection_color); break; case PROP_SELECTED_TEXT_COLOR: clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR, &priv->selected_text_color); break; default: g_assert_not_reached (); } clutter_transition_set_to (transition, CLUTTER_TYPE_COLOR, color); /* always use the current easing state */ clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), info->cur_state->easing_duration); clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition), info->cur_state->easing_mode); /* ensure that we start from the beginning */ clutter_timeline_rewind (CLUTTER_TIMELINE (transition)); clutter_timeline_start (CLUTTER_TIMELINE (transition)); } static void clutter_text_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { if (strncmp (name, "font-description", 16) == 0) { g_assert (G_VALUE_HOLDS (value, G_TYPE_STRING)); if (g_value_get_string (value) != NULL) clutter_text_set_font_name (CLUTTER_TEXT (scriptable), g_value_get_string (value)); } else parent_scriptable_iface->set_custom_property (scriptable, script, name, value); } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { parent_scriptable_iface = g_type_interface_peek_parent (iface); iface->parse_custom_node = clutter_text_parse_custom_node; iface->set_custom_property = clutter_text_set_custom_property; } static void clutter_text_set_final_state (ClutterAnimatable *animatable, const char *property_name, const GValue *value) { if (strcmp (property_name, "color") == 0) { const ClutterColor *color = clutter_value_get_color (value); clutter_text_set_color_internal (CLUTTER_TEXT (animatable), obj_props[PROP_COLOR], color); } else if (strcmp (property_name, "cursor-color") == 0) { const ClutterColor *color = clutter_value_get_color (value); clutter_text_set_color_internal (CLUTTER_TEXT (animatable), obj_props[PROP_CURSOR_COLOR], color); } else if (strcmp (property_name, "selected-text-color") == 0) { const ClutterColor *color = clutter_value_get_color (value); clutter_text_set_color_internal (CLUTTER_TEXT (animatable), obj_props[PROP_SELECTED_TEXT_COLOR], color); } else if (strcmp (property_name, "selection-color") == 0) { const ClutterColor *color = clutter_value_get_color (value); clutter_text_set_color_internal (CLUTTER_TEXT (animatable), obj_props[PROP_SELECTION_COLOR], color); } else parent_animatable_iface->set_final_state (animatable, property_name, value); } static void clutter_animatable_iface_init (ClutterAnimatableIface *iface) { parent_animatable_iface = g_type_interface_peek_parent (iface); iface->set_final_state = clutter_text_set_final_state; } static void clutter_text_class_init (ClutterTextClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); ClutterBindingPool *binding_pool; GParamSpec *pspec; gobject_class->set_property = clutter_text_set_property; gobject_class->get_property = clutter_text_get_property; gobject_class->dispose = clutter_text_dispose; gobject_class->finalize = clutter_text_finalize; actor_class->paint = clutter_text_paint; actor_class->get_paint_volume = clutter_text_get_paint_volume; actor_class->get_preferred_width = clutter_text_get_preferred_width; actor_class->get_preferred_height = clutter_text_get_preferred_height; actor_class->allocate = clutter_text_allocate; actor_class->key_press_event = clutter_text_key_press; actor_class->key_release_event = clutter_text_key_release; actor_class->button_press_event = clutter_text_button_press; actor_class->button_release_event = clutter_text_button_release; actor_class->motion_event = clutter_text_motion; actor_class->touch_event = clutter_text_touch_event; actor_class->key_focus_in = clutter_text_key_focus_in; actor_class->key_focus_out = clutter_text_key_focus_out; actor_class->has_overlaps = clutter_text_has_overlaps; /** * ClutterText:buffer: * * The buffer which stores the text for this #ClutterText. * * If set to %NULL, a default buffer will be created. * * Since: 1.8 */ pspec = g_param_spec_object ("buffer", P_("Buffer"), P_("The buffer for the text"), CLUTTER_TYPE_TEXT_BUFFER, CLUTTER_PARAM_READWRITE); obj_props[PROP_BUFFER] = pspec; g_object_class_install_property (gobject_class, PROP_BUFFER, pspec); /** * ClutterText:font-name: * * The font to be used by the #ClutterText, as a string * that can be parsed by pango_font_description_from_string(). * * If set to %NULL, the default system font will be used instead. * * Since: 1.0 */ pspec = g_param_spec_string ("font-name", P_("Font Name"), P_("The font to be used by the text"), NULL, CLUTTER_PARAM_READWRITE); obj_props[PROP_FONT_NAME] = pspec; g_object_class_install_property (gobject_class, PROP_FONT_NAME, pspec); /** * ClutterText:font-description: * * The #PangoFontDescription that should be used by the #ClutterText * * If you have a string describing the font then you should look at * #ClutterText:font-name instead * * Since: 1.2 */ pspec = g_param_spec_boxed ("font-description", P_("Font Description"), P_("The font description to be used"), PANGO_TYPE_FONT_DESCRIPTION, CLUTTER_PARAM_READWRITE); obj_props[PROP_FONT_DESCRIPTION] = pspec; g_object_class_install_property (gobject_class, PROP_FONT_DESCRIPTION, pspec); /** * ClutterText:text: * * The text to render inside the actor. * * Since: 1.0 */ pspec = g_param_spec_string ("text", P_("Text"), P_("The text to render"), "", CLUTTER_PARAM_READWRITE); obj_props[PROP_TEXT] = pspec; g_object_class_install_property (gobject_class, PROP_TEXT, pspec); /** * ClutterText:color: * * The color used to render the text. * * Since: 1.0 */ pspec = clutter_param_spec_color ("color", P_("Font Color"), P_("Color of the font used by the text"), &default_text_color, CLUTTER_PARAM_READWRITE | CLUTTER_PARAM_ANIMATABLE); obj_props[PROP_COLOR] = pspec; g_object_class_install_property (gobject_class, PROP_COLOR, pspec); /** * ClutterText:editable: * * Whether key events delivered to the actor causes editing. * * Since: 1.0 */ pspec = g_param_spec_boolean ("editable", P_("Editable"), P_("Whether the text is editable"), FALSE, G_PARAM_READWRITE); obj_props[PROP_EDITABLE] = pspec; g_object_class_install_property (gobject_class, PROP_EDITABLE, pspec); /** * ClutterText:selectable: * * Whether it is possible to select text, either using the pointer * or the keyboard. * * This property depends on the #ClutterActor:reactive property being * set to %TRUE. * * Since: 1.0 */ pspec = g_param_spec_boolean ("selectable", P_("Selectable"), P_("Whether the text is selectable"), TRUE, G_PARAM_READWRITE); obj_props[PROP_SELECTABLE] = pspec; g_object_class_install_property (gobject_class, PROP_SELECTABLE, pspec); /** * ClutterText:activatable: * * Toggles whether return invokes the activate signal or not. * * Since: 1.0 */ pspec = g_param_spec_boolean ("activatable", P_("Activatable"), P_("Whether pressing return causes the activate signal to be emitted"), TRUE, G_PARAM_READWRITE); obj_props[PROP_ACTIVATABLE] = pspec; g_object_class_install_property (gobject_class, PROP_ACTIVATABLE, pspec); /** * ClutterText:cursor-visible: * * Whether the input cursor is visible or not. * * The cursor will only be visible if this property and either * the #ClutterText:editable or the #ClutterText:selectable properties * are set to %TRUE. * * Since: 1.0 */ pspec = g_param_spec_boolean ("cursor-visible", P_("Cursor Visible"), P_("Whether the input cursor is visible"), TRUE, CLUTTER_PARAM_READWRITE); obj_props[PROP_CURSOR_VISIBLE] = pspec; g_object_class_install_property (gobject_class, PROP_CURSOR_VISIBLE, pspec); /** * ClutterText:cursor-color: * * The color of the cursor. * * Since: 1.0 */ pspec = clutter_param_spec_color ("cursor-color", P_("Cursor Color"), P_("Cursor Color"), &default_cursor_color, CLUTTER_PARAM_READWRITE | CLUTTER_PARAM_ANIMATABLE); obj_props[PROP_CURSOR_COLOR] = pspec; g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR, pspec); /** * ClutterText:cursor-color-set: * * Will be set to %TRUE if #ClutterText:cursor-color has been set. * * Since: 1.0 */ pspec = g_param_spec_boolean ("cursor-color-set", P_("Cursor Color Set"), P_("Whether the cursor color has been set"), FALSE, CLUTTER_PARAM_READABLE); obj_props[PROP_CURSOR_COLOR_SET] = pspec; g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR_SET, pspec); /** * ClutterText:cursor-size: * * The size of the cursor, in pixels. If set to -1 the size used will * be the default cursor size of 2 pixels. * * Since: 1.0 */ pspec = g_param_spec_int ("cursor-size", P_("Cursor Size"), P_("The width of the cursor, in pixels"), -1, G_MAXINT, DEFAULT_CURSOR_SIZE, CLUTTER_PARAM_READWRITE); obj_props[PROP_CURSOR_SIZE] = pspec; g_object_class_install_property (gobject_class, PROP_CURSOR_SIZE, pspec); /** * ClutterText:position: * * The current input cursor position. -1 is taken to be the end of the text * * Since: 1.0 * * Deprecated: 1.12: Use ClutterText:cursor-position instead. */ pspec = g_param_spec_int ("position", P_("Cursor Position"), P_("The cursor position"), -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); obj_props[PROP_POSITION] = pspec; g_object_class_install_property (gobject_class, PROP_POSITION, pspec); /** * ClutterText:cursor-position: * * The current input cursor position. -1 is taken to be the end of the text * * Since: 1.12 */ pspec = g_param_spec_int ("cursor-position", P_("Cursor Position"), P_("The cursor position"), -1, G_MAXINT, -1, CLUTTER_PARAM_READWRITE); obj_props[PROP_CURSOR_POSITION] = pspec; g_object_class_install_property (gobject_class, PROP_CURSOR_POSITION, pspec); /** * ClutterText:selection-bound: * * The current input cursor position. -1 is taken to be the end of the text * * Since: 1.0 */ pspec = g_param_spec_int ("selection-bound", P_("Selection-bound"), P_("The cursor position of the other end of the selection"), -1, G_MAXINT, -1, CLUTTER_PARAM_READWRITE); obj_props[PROP_SELECTION_BOUND] = pspec; g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, pspec); /** * ClutterText:selection-color: * * The color of the selection. * * Since: 1.0 */ pspec = clutter_param_spec_color ("selection-color", P_("Selection Color"), P_("Selection Color"), &default_selection_color, CLUTTER_PARAM_READWRITE | CLUTTER_PARAM_ANIMATABLE); obj_props[PROP_SELECTION_COLOR] = pspec; g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR, pspec); /** * ClutterText:selection-color-set: * * Will be set to %TRUE if #ClutterText:selection-color has been set. * * Since: 1.0 */ pspec = g_param_spec_boolean ("selection-color-set", P_("Selection Color Set"), P_("Whether the selection color has been set"), FALSE, CLUTTER_PARAM_READABLE); obj_props[PROP_SELECTION_COLOR_SET] = pspec; g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR_SET, pspec); /** * ClutterText:attributes: * * A list of #PangoStyleAttribute<!-- -->s to be applied to the * contents of the #ClutterText actor. * * Since: 1.0 */ pspec = g_param_spec_boxed ("attributes", P_("Attributes"), P_("A list of style attributes to apply to the contents of the actor"), PANGO_TYPE_ATTR_LIST, CLUTTER_PARAM_READWRITE); obj_props[PROP_ATTRIBUTES] = pspec; g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, pspec); /** * ClutterText:use-markup: * * Whether the text includes Pango markup. * * For more informations about the Pango markup format, see * pango_layout_set_markup() in the Pango documentation. * * It is not possible to round-trip this property between * %TRUE and %FALSE. Once a string with markup has been set on * a #ClutterText actor with :use-markup set to %TRUE, the markup * is stripped from the string. * * Since: 1.0 */ pspec = g_param_spec_boolean ("use-markup", P_("Use markup"), P_("Whether or not the text includes Pango markup"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_USE_MARKUP] = pspec; g_object_class_install_property (gobject_class, PROP_USE_MARKUP, pspec); /** * ClutterText:line-wrap: * * Whether to wrap the lines of #ClutterText:text if the contents * exceed the available allocation. The wrapping strategy is * controlled by the #ClutterText:line-wrap-mode property. * * Since: 1.0 */ pspec = g_param_spec_boolean ("line-wrap", P_("Line wrap"), P_("If set, wrap the lines if the text becomes too wide"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_LINE_WRAP] = pspec; g_object_class_install_property (gobject_class, PROP_LINE_WRAP, pspec); /** * ClutterText:line-wrap-mode: * * If #ClutterText:line-wrap is set to %TRUE, this property will * control how the text is wrapped. * * Since: 1.0 */ pspec = g_param_spec_enum ("line-wrap-mode", P_("Line wrap mode"), P_("Control how line-wrapping is done"), PANGO_TYPE_WRAP_MODE, PANGO_WRAP_WORD, CLUTTER_PARAM_READWRITE); obj_props[PROP_LINE_WRAP_MODE] = pspec; g_object_class_install_property (gobject_class, PROP_LINE_WRAP_MODE, pspec); /** * ClutterText:ellipsize: * * The preferred place to ellipsize the contents of the #ClutterText actor * * Since: 1.0 */ pspec = g_param_spec_enum ("ellipsize", P_("Ellipsize"), P_("The preferred place to ellipsize the string"), PANGO_TYPE_ELLIPSIZE_MODE, PANGO_ELLIPSIZE_NONE, CLUTTER_PARAM_READWRITE); obj_props[PROP_ELLIPSIZE] = pspec; g_object_class_install_property (gobject_class, PROP_ELLIPSIZE, pspec); /** * ClutterText:line-alignment: * * The preferred alignment for the text. This property controls * the alignment of multi-line paragraphs. * * Since: 1.0 */ pspec = g_param_spec_enum ("line-alignment", P_("Line Alignment"), P_("The preferred alignment for the string, for multi-line text"), PANGO_TYPE_ALIGNMENT, PANGO_ALIGN_LEFT, CLUTTER_PARAM_READWRITE); obj_props[PROP_LINE_ALIGNMENT] = pspec; g_object_class_install_property (gobject_class, PROP_LINE_ALIGNMENT, pspec); /** * ClutterText:justify: * * Whether the contents of the #ClutterText should be justified * on both margins. * * Since: 1.0 */ pspec = g_param_spec_boolean ("justify", P_("Justify"), P_("Whether the text should be justified"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_JUSTIFY] = pspec; g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec); /** * ClutterText:password-char: * * If non-zero, the character that should be used in place of * the actual text in a password text actor. * * Since: 1.0 */ pspec = g_param_spec_unichar ("password-char", P_("Password Character"), P_("If non-zero, use this character to display the actor's contents"), 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_PASSWORD_CHAR] = pspec; g_object_class_install_property (gobject_class, PROP_PASSWORD_CHAR, pspec); /** * ClutterText:max-length: * * The maximum length of the contents of the #ClutterText actor. * * Since: 1.0 */ pspec = g_param_spec_int ("max-length", P_("Max Length"), P_("Maximum length of the text inside the actor"), -1, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_MAX_LENGTH] = pspec; g_object_class_install_property (gobject_class, PROP_MAX_LENGTH, pspec); /** * ClutterText:single-line-mode: * * Whether the #ClutterText actor should be in single line mode * or not. A single line #ClutterText actor will only contain a * single line of text, scrolling it in case its length is bigger * than the allocated size. * * Setting this property will also set the #ClutterText:activatable * property as a side-effect. * * The #ClutterText:single-line-mode property is used only if the * #ClutterText:editable property is set to %TRUE. * * Since: 1.0 */ pspec = g_param_spec_boolean ("single-line-mode", P_("Single Line Mode"), P_("Whether the text should be a single line"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_SINGLE_LINE_MODE] = pspec; g_object_class_install_property (gobject_class, PROP_SINGLE_LINE_MODE, pspec); /** * ClutterText:selected-text-color: * * The color of selected text. * * Since: 1.8 */ pspec = clutter_param_spec_color ("selected-text-color", P_("Selected Text Color"), P_("Selected Text Color"), &default_selected_text_color, CLUTTER_PARAM_READWRITE | CLUTTER_PARAM_ANIMATABLE); obj_props[PROP_SELECTED_TEXT_COLOR] = pspec; g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR, pspec); /** * ClutterText:selected-text-color-set: * * Will be set to %TRUE if #ClutterText:selected-text-color has been set. * * Since: 1.8 */ pspec = g_param_spec_boolean ("selected-text-color-set", P_("Selected Text Color Set"), P_("Whether the selected text color has been set"), FALSE, CLUTTER_PARAM_READABLE); obj_props[PROP_SELECTED_TEXT_COLOR_SET] = pspec; g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR_SET, pspec); pspec = g_param_spec_flags ("input-hints", P_("Input hints"), P_("Input hints"), CLUTTER_TYPE_INPUT_CONTENT_HINT_FLAGS, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_INPUT_HINTS] = pspec; g_object_class_install_property (gobject_class, PROP_INPUT_HINTS, pspec); pspec = g_param_spec_enum ("input-purpose", P_("Input purpose"), P_("Input purpose"), CLUTTER_TYPE_INPUT_CONTENT_PURPOSE, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_INPUT_PURPOSE] = pspec; g_object_class_install_property (gobject_class, PROP_INPUT_PURPOSE, pspec); /** * ClutterText::text-changed: * @self: the #ClutterText that emitted the signal * * The ::text-changed signal is emitted after @actor's text changes * * Since: 1.0 */ text_signals[TEXT_CHANGED] = g_signal_new (I_("text-changed"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTextClass, text_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterText::insert-text: * @self: the #ClutterText that emitted the signal * @new_text: the new text to insert * @new_text_length: the length of the new text, in bytes, or -1 if * new_text is nul-terminated * @position: the position, in characters, at which to insert the * new text. this is an in-out parameter. After the signal * emission is finished, it should point after the newly * inserted text. * * This signal is emitted when text is inserted into the actor by * the user. It is emitted before @self text changes. * * Since: 1.2 */ text_signals[INSERT_TEXT] = g_signal_new (I_("insert-text"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 0, NULL, NULL, _clutter_marshal_VOID__STRING_INT_POINTER, G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_POINTER); /** * ClutterText::delete-text: * @self: the #ClutterText that emitted the signal * @start_pos: the starting position * @end_pos: the end position * * This signal is emitted when text is deleted from the actor by * the user. It is emitted before @self text changes. * * Since: 1.2 */ text_signals[DELETE_TEXT] = g_signal_new (I_("delete-text"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 0, NULL, NULL, _clutter_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); /** * ClutterText::cursor-event: * @self: the #ClutterText that emitted the signal * @geometry: the coordinates of the cursor * * The ::cursor-event signal is emitted whenever the cursor position * changes inside a #ClutterText actor. Inside @geometry it is stored * the current position and size of the cursor, relative to the actor * itself. * * Since: 1.0 * * Deprecated: 1.16: Use the #ClutterText::cursor-changed signal instead */ text_signals[CURSOR_EVENT] = g_signal_new (I_("cursor-event"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_DEPRECATED, G_STRUCT_OFFSET (ClutterTextClass, cursor_event), NULL, NULL, _clutter_marshal_VOID__BOXED, G_TYPE_NONE, 1, CLUTTER_TYPE_GEOMETRY | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterText::cursor-changed: * @self: the #ClutterText that emitted the signal * * The ::cursor-changed signal is emitted whenever the cursor * position or size changes. * * Since: 1.16 */ text_signals[CURSOR_CHANGED] = g_signal_new (I_("cursor-changed"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTextClass, cursor_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterText::activate: * @self: the #ClutterText that emitted the signal * * The ::activate signal is emitted each time the actor is 'activated' * by the user, normally by pressing the 'Enter' key. The signal is * emitted only if #ClutterText:activatable is set to %TRUE. * * Since: 1.0 */ text_signals[ACTIVATE] = g_signal_new (I_("activate"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTextClass, activate), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); binding_pool = clutter_binding_pool_get_for_class (klass); clutter_text_add_move_binding (binding_pool, "move-left", CLUTTER_KEY_Left, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_move_left)); clutter_text_add_move_binding (binding_pool, "move-left", CLUTTER_KEY_KP_Left, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_move_left)); clutter_text_add_move_binding (binding_pool, "move-right", CLUTTER_KEY_Right, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_move_right)); clutter_text_add_move_binding (binding_pool, "move-right", CLUTTER_KEY_KP_Right, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_move_right)); clutter_text_add_move_binding (binding_pool, "move-up", CLUTTER_KEY_Up, 0, G_CALLBACK (clutter_text_real_move_up)); clutter_text_add_move_binding (binding_pool, "move-up", CLUTTER_KEY_KP_Up, 0, G_CALLBACK (clutter_text_real_move_up)); clutter_text_add_move_binding (binding_pool, "move-down", CLUTTER_KEY_Down, 0, G_CALLBACK (clutter_text_real_move_down)); clutter_text_add_move_binding (binding_pool, "move-down", CLUTTER_KEY_KP_Down, 0, G_CALLBACK (clutter_text_real_move_down)); clutter_text_add_move_binding (binding_pool, "line-start", CLUTTER_KEY_Home, 0, G_CALLBACK (clutter_text_real_line_start)); clutter_text_add_move_binding (binding_pool, "line-start", CLUTTER_KEY_KP_Home, 0, G_CALLBACK (clutter_text_real_line_start)); clutter_text_add_move_binding (binding_pool, "line-start", CLUTTER_KEY_Begin, 0, G_CALLBACK (clutter_text_real_line_start)); clutter_text_add_move_binding (binding_pool, "line-end", CLUTTER_KEY_End, 0, G_CALLBACK (clutter_text_real_line_end)); clutter_text_add_move_binding (binding_pool, "line-end", CLUTTER_KEY_KP_End, 0, G_CALLBACK (clutter_text_real_line_end)); clutter_binding_pool_install_action (binding_pool, "select-all", CLUTTER_KEY_a, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_select_all), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "select-all", CLUTTER_KEY_A, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_select_all), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "delete-next", CLUTTER_KEY_Delete, 0, G_CALLBACK (clutter_text_real_del_next), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "delete-next", CLUTTER_KEY_Delete, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_del_word_next), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "delete-next", CLUTTER_KEY_KP_Delete, 0, G_CALLBACK (clutter_text_real_del_next), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "delete-next", CLUTTER_KEY_KP_Delete, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_del_word_next), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "delete-prev", CLUTTER_KEY_BackSpace, 0, G_CALLBACK (clutter_text_real_del_prev), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "delete-prev", CLUTTER_KEY_BackSpace, CLUTTER_SHIFT_MASK, G_CALLBACK (clutter_text_real_del_prev), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "delete-prev", CLUTTER_KEY_BackSpace, CLUTTER_CONTROL_MASK, G_CALLBACK (clutter_text_real_del_word_prev), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_Return, 0, G_CALLBACK (clutter_text_real_activate), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_KP_Enter, 0, G_CALLBACK (clutter_text_real_activate), NULL, NULL); clutter_binding_pool_install_action (binding_pool, "activate", CLUTTER_KEY_ISO_Enter, 0, G_CALLBACK (clutter_text_real_activate), NULL, NULL); } static void clutter_text_init (ClutterText *self) { ClutterSettings *settings; ClutterTextPrivate *priv; gchar *font_name; int i, password_hint_time; self->priv = priv = clutter_text_get_instance_private (self); priv->alignment = PANGO_ALIGN_LEFT; priv->wrap = FALSE; priv->wrap_mode = PANGO_WRAP_WORD; priv->ellipsize = PANGO_ELLIPSIZE_NONE; priv->use_underline = FALSE; priv->use_markup = FALSE; priv->justify = FALSE; for (i = 0; i < N_CACHED_LAYOUTS; i++) priv->cached_layouts[i].layout = NULL; /* default to "" so that clutter_text_get_text() will * return a valid string and we can safely call strlen() * or strcmp() on it */ priv->buffer = NULL; priv->text_color = default_text_color; priv->cursor_color = default_cursor_color; priv->selection_color = default_selection_color; priv->selected_text_color = default_selected_text_color; /* get the default font name from the context; we don't use * set_font_description() here because we are initializing * the Text and we don't need notifications and sanity checks */ settings = clutter_settings_get_default (); g_object_get (settings, "font-name", &font_name, "password-hint-time", &password_hint_time, NULL); priv->font_name = font_name; /* font_name is allocated */ priv->font_desc = pango_font_description_from_string (font_name); priv->is_default_font = TRUE; priv->position = -1; priv->selection_bound = -1; priv->x_pos = -1; priv->cursor_visible = TRUE; priv->editable = FALSE; priv->selectable = TRUE; priv->selection_color_set = FALSE; priv->cursor_color_set = FALSE; priv->selected_text_color_set = FALSE; priv->preedit_set = FALSE; priv->password_char = 0; priv->show_password_hint = password_hint_time > 0; priv->password_hint_timeout = password_hint_time; priv->text_y = 0; priv->cursor_size = DEFAULT_CURSOR_SIZE; priv->settings_changed_id = g_signal_connect_swapped (clutter_get_default_backend (), "settings-changed", G_CALLBACK (clutter_text_settings_changed_cb), self); priv->direction_changed_id = g_signal_connect (self, "notify::text-direction", G_CALLBACK (clutter_text_direction_changed_cb), NULL); priv->input_focus = clutter_text_input_focus_new (self); } /** * clutter_text_new: * * Creates a new #ClutterText actor. This actor can be used to * display and edit text. * * Return value: the newly created #ClutterText actor * * Since: 1.0 */ ClutterActor * clutter_text_new (void) { return g_object_new (CLUTTER_TYPE_TEXT, NULL); } /** * clutter_text_new_full: * @font_name: a string with a font description * @text: the contents of the actor * @color: the color to be used to render @text * * Creates a new #ClutterText actor, using @font_name as the font * description; @text will be used to set the contents of the actor; * and @color will be used as the color to render @text. * * This function is equivalent to calling clutter_text_new(), * clutter_text_set_font_name(), clutter_text_set_text() and * clutter_text_set_color(). * * Return value: the newly created #ClutterText actor * * Since: 1.0 */ ClutterActor * clutter_text_new_full (const gchar *font_name, const gchar *text, const ClutterColor *color) { return g_object_new (CLUTTER_TYPE_TEXT, "font-name", font_name, "text", text, "color", color, NULL); } /** * clutter_text_new_with_text: * @font_name: (allow-none): a string with a font description * @text: the contents of the actor * * Creates a new #ClutterText actor, using @font_name as the font * description; @text will be used to set the contents of the actor. * * This function is equivalent to calling clutter_text_new(), * clutter_text_set_font_name(), and clutter_text_set_text(). * * Return value: the newly created #ClutterText actor * * Since: 1.0 */ ClutterActor * clutter_text_new_with_text (const gchar *font_name, const gchar *text) { return g_object_new (CLUTTER_TYPE_TEXT, "font-name", font_name, "text", text, NULL); } static ClutterTextBuffer* get_buffer (ClutterText *self) { ClutterTextPrivate *priv = self->priv; if (priv->buffer == NULL) { ClutterTextBuffer *buffer; buffer = clutter_text_buffer_new (); clutter_text_set_buffer (self, buffer); g_object_unref (buffer); } return priv->buffer; } /* GtkEntryBuffer signal handlers */ static void buffer_inserted_text (ClutterTextBuffer *buffer, guint position, const gchar *chars, guint n_chars, ClutterText *self) { ClutterTextPrivate *priv; gint new_position; gint new_selection_bound; priv = self->priv; if (priv->position >= 0 || priv->selection_bound >= 0) { new_position = priv->position; new_selection_bound = priv->selection_bound; if (position <= new_position) new_position += n_chars; if (position <= new_selection_bound) new_selection_bound += n_chars; if (priv->position != new_position || priv->selection_bound != new_selection_bound) clutter_text_set_positions (self, new_position, new_selection_bound); } /* TODO: What are we supposed to with the out value of position? */ } static void buffer_deleted_text (ClutterTextBuffer *buffer, guint position, guint n_chars, ClutterText *self) { ClutterTextPrivate *priv; gint new_position; gint new_selection_bound; priv = self->priv; if (priv->position >= 0 || priv->selection_bound >= 0) { new_position = priv->position; new_selection_bound = priv->selection_bound; if (position < new_position) new_position -= n_chars; if (position < new_selection_bound) new_selection_bound -= n_chars; if (priv->position != new_position || priv->selection_bound != new_selection_bound) clutter_text_set_positions (self, new_position, new_selection_bound); } } static void clutter_text_queue_redraw_or_relayout (ClutterText *self) { ClutterActor *actor = CLUTTER_ACTOR (self); gfloat preferred_width; gfloat preferred_height; clutter_text_dirty_cache (self); /* we're using our private implementations here to avoid the caching done by ClutterActor */ clutter_text_get_preferred_width (actor, -1, NULL, &preferred_width); clutter_text_get_preferred_height (actor, preferred_width, NULL, &preferred_height); if (clutter_actor_has_allocation (actor) && (fabsf (preferred_width - clutter_actor_get_width (actor)) > 0.001 || fabsf (preferred_height - clutter_actor_get_height (actor)) > 0.001)) clutter_actor_queue_relayout (actor); else clutter_text_queue_redraw (actor); } static void buffer_notify_text (ClutterTextBuffer *buffer, GParamSpec *spec, ClutterText *self) { g_object_freeze_notify (G_OBJECT (self)); clutter_text_queue_redraw_or_relayout (self); g_signal_emit (self, text_signals[TEXT_CHANGED], 0); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]); g_object_thaw_notify (G_OBJECT (self)); } static void buffer_notify_max_length (ClutterTextBuffer *buffer, GParamSpec *spec, ClutterText *self) { g_object_notify (G_OBJECT (self), "max-length"); } static void buffer_connect_signals (ClutterText *self) { ClutterTextPrivate *priv = self->priv; g_signal_connect (priv->buffer, "inserted-text", G_CALLBACK (buffer_inserted_text), self); g_signal_connect (priv->buffer, "deleted-text", G_CALLBACK (buffer_deleted_text), self); g_signal_connect (priv->buffer, "notify::text", G_CALLBACK (buffer_notify_text), self); g_signal_connect (priv->buffer, "notify::max-length", G_CALLBACK (buffer_notify_max_length), self); } static void buffer_disconnect_signals (ClutterText *self) { ClutterTextPrivate *priv = self->priv; g_signal_handlers_disconnect_by_func (priv->buffer, buffer_inserted_text, self); g_signal_handlers_disconnect_by_func (priv->buffer, buffer_deleted_text, self); g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_text, self); g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_max_length, self); } /** * clutter_text_new_with_buffer: * @buffer: The buffer to use for the new #ClutterText. * * Creates a new entry with the specified text buffer. * * Return value: a new #ClutterText * * Since: 1.10 */ ClutterActor * clutter_text_new_with_buffer (ClutterTextBuffer *buffer) { g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), NULL); return g_object_new (CLUTTER_TYPE_TEXT, "buffer", buffer, NULL); } /** * clutter_text_get_buffer: * @self: a #ClutterText * * Get the #ClutterTextBuffer object which holds the text for * this widget. * * Returns: (transfer none): A #GtkEntryBuffer object. * * Since: 1.10 */ ClutterTextBuffer* clutter_text_get_buffer (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); return get_buffer (self); } /** * clutter_text_set_buffer: * @self: a #ClutterText * @buffer: a #ClutterTextBuffer * * Set the #ClutterTextBuffer object which holds the text for * this widget. * * Since: 1.10 */ void clutter_text_set_buffer (ClutterText *self, ClutterTextBuffer *buffer) { ClutterTextPrivate *priv; GObject *obj; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (buffer) { g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer)); g_object_ref (buffer); } if (priv->buffer) { buffer_disconnect_signals (self); g_object_unref (priv->buffer); } priv->buffer = buffer; if (priv->buffer) buffer_connect_signals (self); obj = G_OBJECT (self); g_object_freeze_notify (obj); g_object_notify (obj, "buffer"); g_object_notify (obj, "text"); g_object_notify (obj, "max-length"); g_object_thaw_notify (obj); } /** * clutter_text_set_editable: * @self: a #ClutterText * @editable: whether the #ClutterText should be editable * * Sets whether the #ClutterText actor should be editable. * * An editable #ClutterText with key focus set using * clutter_actor_grab_key_focus() or clutter_stage_set_key_focus() * will receive key events and will update its contents accordingly. * * Since: 1.0 */ void clutter_text_set_editable (ClutterText *self, gboolean editable) { ClutterBackend *backend = clutter_get_default_backend (); ClutterInputMethod *method = clutter_backend_get_input_method (backend); ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->editable != editable) { priv->editable = editable; if (method) { if (!priv->editable && clutter_input_focus_is_focused (priv->input_focus)) clutter_input_method_focus_out (method); else if (priv->has_focus) clutter_input_method_focus_in (method, priv->input_focus); } clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]); } } /** * clutter_text_get_editable: * @self: a #ClutterText * * Retrieves whether a #ClutterText is editable or not. * * Return value: %TRUE if the actor is editable * * Since: 1.0 */ gboolean clutter_text_get_editable (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); return self->priv->editable; } /** * clutter_text_set_selectable: * @self: a #ClutterText * @selectable: whether the #ClutterText actor should be selectable * * Sets whether a #ClutterText actor should be selectable. * * A selectable #ClutterText will allow selecting its contents using * the pointer or the keyboard. * * Since: 1.0 */ void clutter_text_set_selectable (ClutterText *self, gboolean selectable) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->selectable != selectable) { priv->selectable = selectable; clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTABLE]); } } /** * clutter_text_get_selectable: * @self: a #ClutterText * * Retrieves whether a #ClutterText is selectable or not. * * Return value: %TRUE if the actor is selectable * * Since: 1.0 */ gboolean clutter_text_get_selectable (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE); return self->priv->selectable; } /** * clutter_text_set_activatable: * @self: a #ClutterText * @activatable: whether the #ClutterText actor should be activatable * * Sets whether a #ClutterText actor should be activatable. * * An activatable #ClutterText actor will emit the #ClutterText::activate * signal whenever the 'Enter' (or 'Return') key is pressed; if it is not * activatable, a new line will be appended to the current content. * * An activatable #ClutterText must also be set as editable using * clutter_text_set_editable(). * * Since: 1.0 */ void clutter_text_set_activatable (ClutterText *self, gboolean activatable) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->activatable != activatable) { priv->activatable = activatable; clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]); } } /** * clutter_text_get_activatable: * @self: a #ClutterText * * Retrieves whether a #ClutterText is activatable or not. * * Return value: %TRUE if the actor is activatable * * Since: 1.0 */ gboolean clutter_text_get_activatable (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE); return self->priv->activatable; } /** * clutter_text_activate: * @self: a #ClutterText * * Emits the #ClutterText::activate signal, if @self has been set * as activatable using clutter_text_set_activatable(). * * This function can be used to emit the ::activate signal inside * a #ClutterActor::captured-event or #ClutterActor::key-press-event * signal handlers before the default signal handler for the * #ClutterText is invoked. * * Return value: %TRUE if the ::activate signal has been emitted, * and %FALSE otherwise * * Since: 1.0 */ gboolean clutter_text_activate (ClutterText *self) { ClutterTextPrivate *priv; g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); priv = self->priv; if (priv->activatable) { g_signal_emit (self, text_signals[ACTIVATE], 0); return TRUE; } return FALSE; } /** * clutter_text_set_cursor_visible: * @self: a #ClutterText * @cursor_visible: whether the cursor should be visible * * Sets whether the cursor of a #ClutterText actor should be * visible or not. * * The color of the cursor will be the same as the text color * unless clutter_text_set_cursor_color() has been called. * * The size of the cursor can be set using clutter_text_set_cursor_size(). * * The position of the cursor can be changed programmatically using * clutter_text_set_cursor_position(). * * Since: 1.0 */ void clutter_text_set_cursor_visible (ClutterText *self, gboolean cursor_visible) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; cursor_visible = !!cursor_visible; if (priv->cursor_visible != cursor_visible) { priv->cursor_visible = cursor_visible; clutter_text_queue_redraw_or_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_VISIBLE]); } } /** * clutter_text_get_cursor_visible: * @self: a #ClutterText * * Retrieves whether the cursor of a #ClutterText actor is visible. * * Return value: %TRUE if the cursor is visible * * Since: 1.0 */ gboolean clutter_text_get_cursor_visible (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE); return self->priv->cursor_visible; } /** * clutter_text_set_cursor_color: * @self: a #ClutterText * @color: (allow-none): the color of the cursor, or %NULL to unset it * * Sets the color of the cursor of a #ClutterText actor. * * If @color is %NULL, the cursor color will be the same as the * text color. * * Since: 1.0 */ void clutter_text_set_cursor_color (ClutterText *self, const ClutterColor *color) { g_return_if_fail (CLUTTER_IS_TEXT (self)); clutter_text_set_color_animated (self, obj_props[PROP_CURSOR_COLOR], color); } /** * clutter_text_get_cursor_color: * @self: a #ClutterText * @color: (out): return location for a #ClutterColor * * Retrieves the color of the cursor of a #ClutterText actor. * * Since: 1.0 */ void clutter_text_get_cursor_color (ClutterText *self, ClutterColor *color) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (color != NULL); priv = self->priv; *color = priv->cursor_color; } /** * clutter_text_set_selection: * @self: a #ClutterText * @start_pos: start of the selection, in characters * @end_pos: end of the selection, in characters * * Selects the region of text between @start_pos and @end_pos. * * This function changes the position of the cursor to match * @start_pos and the selection bound to match @end_pos. * * Since: 1.0 */ void clutter_text_set_selection (ClutterText *self, gssize start_pos, gssize end_pos) { guint n_chars; g_return_if_fail (CLUTTER_IS_TEXT (self)); n_chars = clutter_text_buffer_get_length (get_buffer (self)); if (end_pos < 0) end_pos = n_chars; start_pos = MIN (n_chars, start_pos); end_pos = MIN (n_chars, end_pos); clutter_text_set_positions (self, start_pos, end_pos); } /** * clutter_text_get_selection: * @self: a #ClutterText * * Retrieves the currently selected text. * * Return value: a newly allocated string containing the currently * selected text, or %NULL. Use free() to free the returned * string. * * Since: 1.0 */ gchar * clutter_text_get_selection (ClutterText *self) { ClutterTextPrivate *priv; gchar *str; gint len; gint start_index, end_index; gint start_offset, end_offset; const gchar *text; g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); priv = self->priv; start_index = priv->position; end_index = priv->selection_bound; if (end_index == start_index) return g_strdup (""); if ((end_index != -1 && end_index < start_index) || start_index == -1) { gint temp = start_index; start_index = end_index; end_index = temp; } text = clutter_text_buffer_get_text (get_buffer (self)); start_offset = offset_to_bytes (text, start_index); end_offset = offset_to_bytes (text, end_index); len = end_offset - start_offset; str = malloc (len + 1); g_utf8_strncpy (str, text + start_offset, end_index - start_index); return str; } /** * clutter_text_set_selection_bound: * @self: a #ClutterText * @selection_bound: the position of the end of the selection, in characters * * Sets the other end of the selection, starting from the current * cursor position. * * If @selection_bound is -1, the selection unset. * * Since: 1.0 */ void clutter_text_set_selection_bound (ClutterText *self, gint selection_bound) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->selection_bound != selection_bound) { gint len = clutter_text_buffer_get_length (get_buffer (self));; if (selection_bound < 0 || selection_bound >= len) priv->selection_bound = -1; else priv->selection_bound = selection_bound; clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]); } } /** * clutter_text_get_selection_bound: * @self: a #ClutterText * * Retrieves the other end of the selection of a #ClutterText actor, * in characters from the current cursor position. * * Return value: the position of the other end of the selection * * Since: 1.0 */ gint clutter_text_get_selection_bound (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1); return self->priv->selection_bound; } /** * clutter_text_set_selection_color: * @self: a #ClutterText * @color: (allow-none): the color of the selection, or %NULL to unset it * * Sets the color of the selection of a #ClutterText actor. * * If @color is %NULL, the selection color will be the same as the * cursor color, or if no cursor color is set either then it will be * the same as the text color. * * Since: 1.0 */ void clutter_text_set_selection_color (ClutterText *self, const ClutterColor *color) { g_return_if_fail (CLUTTER_IS_TEXT (self)); clutter_text_set_color_animated (self, obj_props[PROP_SELECTION_COLOR], color); } /** * clutter_text_get_selection_color: * @self: a #ClutterText * @color: (out caller-allocates): return location for a #ClutterColor * * Retrieves the color of the selection of a #ClutterText actor. * * Since: 1.0 */ void clutter_text_get_selection_color (ClutterText *self, ClutterColor *color) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (color != NULL); priv = self->priv; *color = priv->selection_color; } /** * clutter_text_set_selected_text_color: * @self: a #ClutterText * @color: (allow-none): the selected text color, or %NULL to unset it * * Sets the selected text color of a #ClutterText actor. * * If @color is %NULL, the selected text color will be the same as the * selection color, which then falls back to cursor, and then text color. * * Since: 1.8 */ void clutter_text_set_selected_text_color (ClutterText *self, const ClutterColor *color) { g_return_if_fail (CLUTTER_IS_TEXT (self)); clutter_text_set_color_animated (self, obj_props[PROP_SELECTED_TEXT_COLOR], color); } /** * clutter_text_get_selected_text_color: * @self: a #ClutterText * @color: (out caller-allocates): return location for a #ClutterColor * * Retrieves the color of selected text of a #ClutterText actor. * * Since: 1.8 */ void clutter_text_get_selected_text_color (ClutterText *self, ClutterColor *color) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (color != NULL); priv = self->priv; *color = priv->selected_text_color; } /** * clutter_text_set_font_description: * @self: a #ClutterText * @font_desc: a #PangoFontDescription * * Sets @font_desc as the font description for a #ClutterText * * The #PangoFontDescription is copied by the #ClutterText actor * so you can safely call pango_font_description_free() on it after * calling this function. * * Since: 1.2 */ void clutter_text_set_font_description (ClutterText *self, PangoFontDescription *font_desc) { g_return_if_fail (CLUTTER_IS_TEXT (self)); clutter_text_set_font_description_internal (self, font_desc, font_desc == NULL); } /** * clutter_text_get_font_description: * @self: a #ClutterText * * Retrieves the #PangoFontDescription used by @self * * Return value: a #PangoFontDescription. The returned value is owned * by the #ClutterText actor and it should not be modified or freed * * Since: 1.2 */ PangoFontDescription * clutter_text_get_font_description (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); return self->priv->font_desc; } /** * clutter_text_get_font_name: * @self: a #ClutterText * * Retrieves the font name as set by clutter_text_set_font_name(). * * Return value: a string containing the font name. The returned * string is owned by the #ClutterText actor and should not be * modified or freed * * Since: 1.0 */ const gchar * clutter_text_get_font_name (ClutterText *text) { g_return_val_if_fail (CLUTTER_IS_TEXT (text), NULL); return text->priv->font_name; } /** * clutter_text_set_font_name: * @self: a #ClutterText * @font_name: (allow-none): a font name, or %NULL to set the default font name * * Sets the font used by a #ClutterText. The @font_name string * must either be %NULL, which means that the font name from the * default #ClutterBackend will be used; or be something that can * be parsed by the pango_font_description_from_string() function, * like: * * |[ * // Set the font to the system's Sans, 10 points * clutter_text_set_font_name (text, "Sans 10"); * * // Set the font to the system's Serif, 16 pixels * clutter_text_set_font_name (text, "Serif 16px"); * * // Set the font to Helvetica, 10 points * clutter_text_set_font_name (text, "Helvetica 10"); * ]| * * Since: 1.0 */ void clutter_text_set_font_name (ClutterText *self, const gchar *font_name) { ClutterTextPrivate *priv; PangoFontDescription *desc; gboolean is_default_font; g_return_if_fail (CLUTTER_IS_TEXT (self)); /* get the default font name from the backend */ if (font_name == NULL || font_name[0] == '\0') { ClutterSettings *settings = clutter_settings_get_default (); gchar *default_font_name = NULL; g_object_get (settings, "font-name", &default_font_name, NULL); if (default_font_name != NULL) font_name = default_font_name; else { /* last fallback */ font_name = g_strdup ("Sans 12"); } is_default_font = TRUE; } else is_default_font = FALSE; priv = self->priv; if (g_strcmp0 (priv->font_name, font_name) == 0) goto out; desc = pango_font_description_from_string (font_name); if (desc == NULL) { g_warning ("Attempting to create a PangoFontDescription for " "font name '%s', but failed.", font_name); goto out; } /* this will set the font_name field as well */ clutter_text_set_font_description_internal (self, desc, is_default_font); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_NAME]); pango_font_description_free (desc); out: if (is_default_font) free ((gchar *) font_name); } /** * clutter_text_get_text: * @self: a #ClutterText * * Retrieves a pointer to the current contents of a #ClutterText * actor. * * If you need a copy of the contents for manipulating, either * use g_strdup() on the returned string, or use: * * |[ * copy = clutter_text_get_chars (text, 0, -1); * ]| * * Which will return a newly allocated string. * * If the #ClutterText actor is empty, this function will return * an empty string, and not %NULL. * * Return value: (transfer none): the contents of the actor. The returned * string is owned by the #ClutterText actor and should never be modified * or freed * * Since: 1.0 */ const gchar * clutter_text_get_text (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); return clutter_text_buffer_get_text (get_buffer (self)); } static inline void clutter_text_set_use_markup_internal (ClutterText *self, gboolean use_markup) { ClutterTextPrivate *priv = self->priv; if (priv->use_markup != use_markup) { priv->use_markup = use_markup; /* reset the attributes lists so that they can be * re-generated */ if (priv->effective_attrs != NULL) { pango_attr_list_unref (priv->effective_attrs); priv->effective_attrs = NULL; } if (priv->markup_attrs) { pango_attr_list_unref (priv->markup_attrs); priv->markup_attrs = NULL; } g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_USE_MARKUP]); } } /** * clutter_text_set_text: * @self: a #ClutterText * @text: (allow-none): the text to set. Passing %NULL is the same * as passing "" (the empty string) * * Sets the contents of a #ClutterText actor. * * If the #ClutterText:use-markup property was set to %TRUE it * will be reset to %FALSE as a side effect. If you want to * maintain the #ClutterText:use-markup you should use the * clutter_text_set_markup() function instead * * Since: 1.0 */ void clutter_text_set_text (ClutterText *self, const gchar *text) { g_return_if_fail (CLUTTER_IS_TEXT (self)); /* if the text is editable (i.e. there is not markup flag to reset) then * changing the contents will result in selection and cursor changes that * we should avoid */ if (self->priv->editable) { if (g_strcmp0 (clutter_text_buffer_get_text (get_buffer (self)), text) == 0) return; } clutter_text_set_use_markup_internal (self, FALSE); clutter_text_buffer_set_text (get_buffer (self), text ? text : "", -1); } /** * clutter_text_set_markup: * @self: a #ClutterText * @markup: (allow-none): a string containing Pango markup. * Passing %NULL is the same as passing "" (the empty string) * * Sets @markup as the contents of a #ClutterText. * * This is a convenience function for setting a string containing * Pango markup, and it is logically equivalent to: * * |[ * /* the order is important */ * clutter_text_set_text (CLUTTER_TEXT (actor), markup); * clutter_text_set_use_markup (CLUTTER_TEXT (actor), TRUE); * ]| * * Since: 1.0 */ void clutter_text_set_markup (ClutterText *self, const gchar *markup) { g_return_if_fail (CLUTTER_IS_TEXT (self)); clutter_text_set_use_markup_internal (self, TRUE); if (markup != NULL && *markup != '\0') clutter_text_set_markup_internal (self, markup); else clutter_text_buffer_set_text (get_buffer (self), "", 0); } /** * clutter_text_get_layout: * @self: a #ClutterText * * Retrieves the current #PangoLayout used by a #ClutterText actor. * * Return value: (transfer none): a #PangoLayout. The returned object is owned by * the #ClutterText actor and should not be modified or freed * * Since: 1.0 */ PangoLayout * clutter_text_get_layout (ClutterText *self) { gfloat width, height; g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); if (self->priv->editable && self->priv->single_line_mode) return clutter_text_create_layout (self, -1, -1); clutter_actor_get_size (CLUTTER_ACTOR (self), &width, &height); return clutter_text_create_layout (self, width, height); } /** * clutter_text_set_color: * @self: a #ClutterText * @color: a #ClutterColor * * Sets the color of the contents of a #ClutterText actor. * * The overall opacity of the #ClutterText actor will be the * result of the alpha value of @color and the composited * opacity of the actor itself on the scenegraph, as returned * by clutter_actor_get_paint_opacity(). * * Since: 1.0 */ void clutter_text_set_color (ClutterText *self, const ClutterColor *color) { g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (color != NULL); clutter_text_set_color_animated (self, obj_props[PROP_COLOR], color); } /** * clutter_text_get_color: * @self: a #ClutterText * @color: (out caller-allocates): return location for a #ClutterColor * * Retrieves the text color as set by clutter_text_set_color(). * * Since: 1.0 */ void clutter_text_get_color (ClutterText *self, ClutterColor *color) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (color != NULL); priv = self->priv; *color = priv->text_color; } /** * clutter_text_set_ellipsize: * @self: a #ClutterText * @mode: a #PangoEllipsizeMode * * Sets the mode used to ellipsize (add an ellipsis: "...") to the * text if there is not enough space to render the entire contents * of a #ClutterText actor * * Since: 1.0 */ void clutter_text_set_ellipsize (ClutterText *self, PangoEllipsizeMode mode) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END); priv = self->priv; if ((PangoEllipsizeMode) priv->ellipsize != mode) { priv->ellipsize = mode; clutter_text_dirty_cache (self); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ELLIPSIZE]); } } /** * clutter_text_get_ellipsize: * @self: a #ClutterText * * Returns the ellipsizing position of a #ClutterText actor, as * set by clutter_text_set_ellipsize(). * * Return value: #PangoEllipsizeMode * * Since: 1.0 */ PangoEllipsizeMode clutter_text_get_ellipsize (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ELLIPSIZE_NONE); return self->priv->ellipsize; } /** * clutter_text_get_line_wrap: * @self: a #ClutterText * * Retrieves the value set using clutter_text_set_line_wrap(). * * Return value: %TRUE if the #ClutterText actor should wrap * its contents * * Since: 1.0 */ gboolean clutter_text_get_line_wrap (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); return self->priv->wrap; } /** * clutter_text_set_line_wrap: * @self: a #ClutterText * @line_wrap: whether the contents should wrap * * Sets whether the contents of a #ClutterText actor should wrap, * if they don't fit the size assigned to the actor. * * Since: 1.0 */ void clutter_text_set_line_wrap (ClutterText *self, gboolean line_wrap) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->wrap != line_wrap) { priv->wrap = line_wrap; clutter_text_dirty_cache (self); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP]); } } /** * clutter_text_set_line_wrap_mode: * @self: a #ClutterText * @wrap_mode: the line wrapping mode * * If line wrapping is enabled (see clutter_text_set_line_wrap()) this * function controls how the line wrapping is performed. The default is * %PANGO_WRAP_WORD which means wrap on word boundaries. * * Since: 1.0 */ void clutter_text_set_line_wrap_mode (ClutterText *self, PangoWrapMode wrap_mode) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->wrap_mode != wrap_mode) { priv->wrap_mode = wrap_mode; clutter_text_dirty_cache (self); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP_MODE]); } } /** * clutter_text_get_line_wrap_mode: * @self: a #ClutterText * * Retrieves the line wrap mode used by the #ClutterText actor. * * See clutter_text_set_line_wrap_mode (). * * Return value: the wrap mode used by the #ClutterText * * Since: 1.0 */ PangoWrapMode clutter_text_get_line_wrap_mode (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_WRAP_WORD); return self->priv->wrap_mode; } /** * clutter_text_set_attributes: * @self: a #ClutterText * @attrs: (allow-none): a #PangoAttrList or %NULL to unset the attributes * * Sets the attributes list that are going to be applied to the * #ClutterText contents. * * The #ClutterText actor will take a reference on the #PangoAttrList * passed to this function. * * Since: 1.0 */ void clutter_text_set_attributes (ClutterText *self, PangoAttrList *attrs) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; /* While we should probably test for equality, Pango doesn't * provide us an easy method to check for AttrList equality. */ if (priv->attrs == attrs) return; if (attrs) pango_attr_list_ref (attrs); if (priv->attrs) pango_attr_list_unref (priv->attrs); priv->attrs = attrs; /* Clear the effective attributes so they will be regenerated when a layout is created */ if (priv->effective_attrs) { pango_attr_list_unref (priv->effective_attrs); priv->effective_attrs = NULL; } clutter_text_dirty_cache (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ATTRIBUTES]); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); } /** * clutter_text_get_attributes: * @self: a #ClutterText * * Gets the attribute list that was set on the #ClutterText actor * clutter_text_set_attributes(), if any. * * Return value: (transfer none): the attribute list, or %NULL if none was set. The * returned value is owned by the #ClutterText and should not be unreferenced. * * Since: 1.0 */ PangoAttrList * clutter_text_get_attributes (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); return self->priv->attrs; } /** * clutter_text_set_line_alignment: * @self: a #ClutterText * @alignment: A #PangoAlignment * * Sets the way that the lines of a wrapped label are aligned with * respect to each other. This does not affect the overall alignment * of the label within its allocated or specified width. * * To align a #ClutterText actor you should add it to a container * that supports alignment, or use the anchor point. * * Since: 1.0 */ void clutter_text_set_line_alignment (ClutterText *self, PangoAlignment alignment) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->alignment != alignment) { priv->alignment = alignment; clutter_text_queue_redraw_or_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_ALIGNMENT]); } } /** * clutter_text_get_line_alignment: * @self: a #ClutterText * * Retrieves the alignment of a #ClutterText, as set by * clutter_text_set_line_alignment(). * * Return value: a #PangoAlignment * * Since: 1.0 */ PangoAlignment clutter_text_get_line_alignment (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ALIGN_LEFT); return self->priv->alignment; } /** * clutter_text_set_use_markup: * @self: a #ClutterText * @setting: %TRUE if the text should be parsed for markup. * * Sets whether the contents of the #ClutterText actor contains markup * in <link linkend="PangoMarkupFormat">Pango's text markup language</link>. * * Setting #ClutterText:use-markup on an editable #ClutterText will * not have any effect except hiding the markup. * * See also #ClutterText:use-markup. * * Since: 1.0 */ void clutter_text_set_use_markup (ClutterText *self, gboolean setting) { const gchar *text; g_return_if_fail (CLUTTER_IS_TEXT (self)); text = clutter_text_buffer_get_text (get_buffer (self)); clutter_text_set_use_markup_internal (self, setting); if (setting) clutter_text_set_markup_internal (self, text); clutter_text_queue_redraw_or_relayout (self); } /** * clutter_text_get_use_markup: * @self: a #ClutterText * * Retrieves whether the contents of the #ClutterText actor should be * parsed for the Pango text markup. * * Return value: %TRUE if the contents will be parsed for markup * * Since: 1.0 */ gboolean clutter_text_get_use_markup (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); return self->priv->use_markup; } /** * clutter_text_set_justify: * @self: a #ClutterText * @justify: whether the text should be justified * * Sets whether the text of the #ClutterText actor should be justified * on both margins. This setting is ignored if Clutter is compiled * against Pango < 1.18. * * Since: 1.0 */ void clutter_text_set_justify (ClutterText *self, gboolean justify) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->justify != justify) { priv->justify = justify; clutter_text_queue_redraw_or_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_JUSTIFY]); } } /** * clutter_text_get_justify: * @self: a #ClutterText * * Retrieves whether the #ClutterText actor should justify its contents * on both margins. * * Return value: %TRUE if the text should be justified * * Since: 0.6 */ gboolean clutter_text_get_justify (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); return self->priv->justify; } /** * clutter_text_get_cursor_position: * @self: a #ClutterText * * Retrieves the cursor position. * * Return value: the cursor position, in characters * * Since: 1.0 */ gint clutter_text_get_cursor_position (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1); return self->priv->position; } /** * clutter_text_set_cursor_position: * @self: a #ClutterText * @position: the new cursor position, in characters * * Sets the cursor of a #ClutterText actor at @position. * * The position is expressed in characters, not in bytes. * * Since: 1.0 */ void clutter_text_set_cursor_position (ClutterText *self, gint position) { ClutterTextPrivate *priv; gint len; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->position == position) return; len = clutter_text_buffer_get_length (get_buffer (self)); if (position < 0 || position >= len) priv->position = -1; else priv->position = position; /* Forget the target x position so that it will be recalculated next time the cursor is moved up or down */ priv->x_pos = -1; clutter_text_queue_redraw (CLUTTER_ACTOR (self)); /* XXX:2.0 - remove */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_POSITION]); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_POSITION]); } /** * clutter_text_set_cursor_size: * @self: a #ClutterText * @size: the size of the cursor, in pixels, or -1 to use the * default value * * Sets the size of the cursor of a #ClutterText. The cursor * will only be visible if the #ClutterText:cursor-visible property * is set to %TRUE. * * Since: 1.0 */ void clutter_text_set_cursor_size (ClutterText *self, gint size) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->cursor_size != size) { if (size < 0) size = DEFAULT_CURSOR_SIZE; priv->cursor_size = size; clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_SIZE]); } } /** * clutter_text_get_cursor_size: * @self: a #ClutterText * * Retrieves the size of the cursor of a #ClutterText actor. * * Return value: the size of the cursor, in pixels * * Since: 1.0 */ guint clutter_text_get_cursor_size (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), DEFAULT_CURSOR_SIZE); return self->priv->cursor_size; } /** * clutter_text_set_password_char: * @self: a #ClutterText * @wc: a Unicode character, or 0 to unset the password character * * Sets the character to use in place of the actual text in a * password text actor. * * If @wc is 0 the text will be displayed as it is entered in the * #ClutterText actor. * * Since: 1.0 */ void clutter_text_set_password_char (ClutterText *self, gunichar wc) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->password_char != wc) { priv->password_char = wc; clutter_text_dirty_cache (self); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PASSWORD_CHAR]); } } /** * clutter_text_get_password_char: * @self: a #ClutterText * * Retrieves the character to use in place of the actual text * as set by clutter_text_set_password_char(). * * Return value: a Unicode character or 0 if the password * character is not set * * Since: 1.0 */ gunichar clutter_text_get_password_char (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0); return self->priv->password_char; } /** * clutter_text_set_max_length: * @self: a #ClutterText * @max: the maximum number of characters allowed in the text actor; 0 * to disable or -1 to set the length of the current string * * Sets the maximum allowed length of the contents of the actor. If the * current contents are longer than the given length, then they will be * truncated to fit. * * Since: 1.0 */ void clutter_text_set_max_length (ClutterText *self, gint max) { g_return_if_fail (CLUTTER_IS_TEXT (self)); clutter_text_buffer_set_max_length (get_buffer (self), max); } /** * clutter_text_get_max_length: * @self: a #ClutterText * * Gets the maximum length of text that can be set into a text actor. * * See clutter_text_set_max_length(). * * Return value: the maximum number of characters. * * Since: 1.0 */ gint clutter_text_get_max_length (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0); return clutter_text_buffer_get_max_length (get_buffer (self)); } static void clutter_text_real_insert_text (ClutterText *self, guint start_pos, const gchar *chars, guint n_chars) { gsize n_bytes; n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars; /* * insert-text is emitted here instead of as part of a * buffer_inserted_text() callback because that should be emitted * before the buffer changes, while ClutterTextBuffer::deleted-text * is emitter after. See BG#722220 for more info. */ g_signal_emit (self, text_signals[INSERT_TEXT], 0, chars, n_bytes, &start_pos); /* * The actual insertion from the buffer. This will end firing the * following signal handlers: buffer_inserted_text(), * buffer_notify_text(), buffer_notify_max_length() */ clutter_text_buffer_insert_text (get_buffer (self), start_pos, chars, n_chars); } /** * clutter_text_insert_unichar: * @self: a #ClutterText * @wc: a Unicode character * * Inserts @wc at the current cursor position of a * #ClutterText actor. * * Since: 1.0 */ void clutter_text_insert_unichar (ClutterText *self, gunichar wc) { ClutterTextPrivate *priv; GString *new; priv = self->priv; new = g_string_new (""); g_string_append_unichar (new, wc); clutter_text_real_insert_text (self, priv->position, new->str, 1); g_string_free (new, TRUE); } /** * clutter_text_insert_text: * @self: a #ClutterText * @text: the text to be inserted * @position: the position of the insertion, or -1 * * Inserts @text into a #ClutterActor at the given position. * * If @position is a negative number, the text will be appended * at the end of the current contents of the #ClutterText. * * The position is expressed in characters, not in bytes. * * Since: 1.0 */ void clutter_text_insert_text (ClutterText *self, const gchar *text, gssize position) { g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (text != NULL); clutter_text_real_insert_text (self, position, text, g_utf8_strlen (text, -1)); } static void clutter_text_real_delete_text (ClutterText *self, gssize start_pos, gssize end_pos) { /* * delete-text is emitted here instead of as part of a * buffer_deleted_text() callback because that should be emitted * before the buffer changes, while ClutterTextBuffer::deleted-text * is emitter after. See BG#722220 for more info. */ g_signal_emit (self, text_signals[DELETE_TEXT], 0, start_pos, end_pos); /* * The actual deletion from the buffer. This will end firing the * following signal handlers: buffer_deleted_text(), * buffer_notify_text(), buffer_notify_max_length() */ clutter_text_buffer_delete_text (get_buffer (self), start_pos, end_pos - start_pos); } /** * clutter_text_delete_text: * @self: a #ClutterText * @start_pos: starting position * @end_pos: ending position * * Deletes the text inside a #ClutterText actor between @start_pos * and @end_pos. * * The starting and ending positions are expressed in characters, * not in bytes. * * Since: 1.0 */ void clutter_text_delete_text (ClutterText *self, gssize start_pos, gssize end_pos) { g_return_if_fail (CLUTTER_IS_TEXT (self)); clutter_text_real_delete_text (self, start_pos, end_pos); } /** * clutter_text_delete_chars: * @self: a #ClutterText * @n_chars: the number of characters to delete * * Deletes @n_chars inside a #ClutterText actor, starting from the * current cursor position. * * Somewhat awkwardly, the cursor position is decremented by the same * number of characters you've deleted. * * Since: 1.0 */ void clutter_text_delete_chars (ClutterText *self, guint n_chars) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; clutter_text_real_delete_text (self, priv->position, priv->position + n_chars); if (priv->position > 0) clutter_text_set_cursor_position (self, priv->position - n_chars); } /** * clutter_text_get_chars: * @self: a #ClutterText * @start_pos: start of text, in characters * @end_pos: end of text, in characters * * Retrieves the contents of the #ClutterText actor between * @start_pos and @end_pos, but not including @end_pos. * * The positions are specified in characters, not in bytes. * * Return value: a newly allocated string with the contents of * the text actor between the specified positions. Use free() * to free the resources when done * * Since: 1.0 */ gchar * clutter_text_get_chars (ClutterText *self, gssize start_pos, gssize end_pos) { gint start_index, end_index; guint n_chars; const gchar *text; g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); n_chars = clutter_text_buffer_get_length (get_buffer (self)); text = clutter_text_buffer_get_text (get_buffer (self)); if (end_pos < 0) end_pos = n_chars; start_pos = MIN (n_chars, start_pos); end_pos = MIN (n_chars, end_pos); start_index = g_utf8_offset_to_pointer (text, start_pos) - text; end_index = g_utf8_offset_to_pointer (text, end_pos) - text; return g_strndup (text + start_index, end_index - start_index); } /** * clutter_text_set_single_line_mode: * @self: a #ClutterText * @single_line: whether to enable single line mode * * Sets whether a #ClutterText actor should be in single line mode * or not. Only editable #ClutterText<!-- -->s can be in single line * mode. * * A text actor in single line mode will not wrap text and will clip * the visible area to the predefined size. The contents of the * text actor will scroll to display the end of the text if its length * is bigger than the allocated width. * * When setting the single line mode the #ClutterText:activatable * property is also set as a side effect. Instead of entering a new * line character, the text actor will emit the #ClutterText::activate * signal. * * Since: 1.0 */ void clutter_text_set_single_line_mode (ClutterText *self, gboolean single_line) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (priv->single_line_mode != single_line) { g_object_freeze_notify (G_OBJECT (self)); priv->single_line_mode = single_line; if (priv->single_line_mode) { priv->activatable = TRUE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]); } clutter_text_dirty_cache (self); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SINGLE_LINE_MODE]); g_object_thaw_notify (G_OBJECT (self)); } } /** * clutter_text_get_single_line_mode: * @self: a #ClutterText * * Retrieves whether the #ClutterText actor is in single line mode. * * Return value: %TRUE if the #ClutterText actor is in single line mode * * Since: 1.0 */ gboolean clutter_text_get_single_line_mode (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); return self->priv->single_line_mode; } /** * clutter_text_set_preedit_string: * @self: a #ClutterText * @preedit_str: (allow-none): the pre-edit string, or %NULL to unset it * @preedit_attrs: (allow-none): the pre-edit string attributes * @cursor_pos: the cursor position for the pre-edit string * * Sets, or unsets, the pre-edit string. This function is useful * for input methods to display a string (with eventual specific * Pango attributes) before it is entered inside the #ClutterText * buffer. * * The preedit string and attributes are ignored if the #ClutterText * actor is not editable. * * This function should not be used by applications * * Since: 1.2 */ void clutter_text_set_preedit_string (ClutterText *self, const gchar *preedit_str, PangoAttrList *preedit_attrs, guint cursor_pos) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; free (priv->preedit_str); priv->preedit_str = NULL; if (priv->preedit_attrs != NULL) { pango_attr_list_unref (priv->preedit_attrs); priv->preedit_attrs = NULL; } priv->preedit_n_chars = 0; priv->preedit_cursor_pos = 0; if (preedit_str == NULL || *preedit_str == '\0') priv->preedit_set = FALSE; else { priv->preedit_str = g_strdup (preedit_str); if (priv->preedit_str != NULL) priv->preedit_n_chars = g_utf8_strlen (priv->preedit_str, -1); else priv->preedit_n_chars = 0; if (preedit_attrs != NULL) priv->preedit_attrs = pango_attr_list_ref (preedit_attrs); priv->preedit_cursor_pos = CLAMP (cursor_pos, 0, priv->preedit_n_chars); priv->preedit_set = TRUE; } clutter_text_queue_redraw_or_relayout (self); } /** * clutter_text_get_layout_offsets: * @self: a #ClutterText * @x: (out): location to store X offset of layout, or %NULL * @y: (out): location to store Y offset of layout, or %NULL * * Obtains the coordinates where the #ClutterText will draw the #PangoLayout * representing the text. * * Since: 1.8 */ void clutter_text_get_layout_offsets (ClutterText *self, gint *x, gint *y) { ClutterTextPrivate *priv; g_return_if_fail (CLUTTER_IS_TEXT (self)); priv = self->priv; if (x != NULL) *x = priv->text_x; if (y != NULL) *y = priv->text_y; } /** * clutter_text_get_cursor_rect: * @self: a #ClutterText * @rect: (out caller-allocates): return location of a #ClutterRect * * Retrieves the rectangle that contains the cursor. * * The coordinates of the rectangle's origin are in actor-relative * coordinates. * * Since: 1.16 */ void clutter_text_get_cursor_rect (ClutterText *self, ClutterRect *rect) { g_return_if_fail (CLUTTER_IS_TEXT (self)); g_return_if_fail (rect != NULL); *rect = self->priv->cursor_rect; } void clutter_text_set_input_hints (ClutterText *self, ClutterInputContentHintFlags hints) { g_return_if_fail (CLUTTER_IS_TEXT (self)); self->priv->input_hints = hints; if (clutter_input_focus_is_focused (self->priv->input_focus)) clutter_input_focus_set_content_hints (self->priv->input_focus, hints); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_INPUT_HINTS]); } ClutterInputContentHintFlags clutter_text_get_input_hints (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0); return self->priv->input_hints; } void clutter_text_set_input_purpose (ClutterText *self, ClutterInputContentPurpose purpose) { g_return_if_fail (CLUTTER_IS_TEXT (self)); self->priv->input_purpose = purpose; if (clutter_input_focus_is_focused (self->priv->input_focus)) clutter_input_focus_set_content_purpose (self->priv->input_focus, purpose); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_INPUT_PURPOSE]); } ClutterInputContentPurpose clutter_text_get_input_purpose (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0); return self->priv->input_purpose; } gboolean clutter_text_has_preedit (ClutterText *self) { g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE); return self->priv->preedit_set; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-shader-types.h�������������������������������������������������0000664�0001750�0001750�00000007156�14211404421�022552� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2008 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_SHADER_TYPES_H__ #define __CLUTTER_SHADER_TYPES_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_SHADER_FLOAT (clutter_shader_float_get_type ()) #define CLUTTER_TYPE_SHADER_INT (clutter_shader_int_get_type ()) #define CLUTTER_TYPE_SHADER_MATRIX (clutter_shader_matrix_get_type ()) typedef struct _ClutterShaderFloat ClutterShaderFloat; typedef struct _ClutterShaderInt ClutterShaderInt; typedef struct _ClutterShaderMatrix ClutterShaderMatrix; /** * CLUTTER_VALUE_HOLDS_SHADER_FLOAT: * @x: a #GValue * * Evaluates to %TRUE if @x holds a #ClutterShaderFloat. * * Since: 1.0 */ #define CLUTTER_VALUE_HOLDS_SHADER_FLOAT(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_SHADER_FLOAT)) /** * CLUTTER_VALUE_HOLDS_SHADER_INT: * @x: a #GValue * * Evaluates to %TRUE if @x holds a #ClutterShaderInt. * * Since: 1.0 */ #define CLUTTER_VALUE_HOLDS_SHADER_INT(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_SHADER_INT)) /** * CLUTTER_VALUE_HOLDS_SHADER_MATRIX: * @x: a #GValue * * Evaluates to %TRUE if @x holds a #ClutterShaderMatrix. * * Since: 1.0 */ #define CLUTTER_VALUE_HOLDS_SHADER_MATRIX(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_SHADER_MATRIX)) CLUTTER_AVAILABLE_IN_1_0 GType clutter_shader_float_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 GType clutter_shader_int_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 GType clutter_shader_matrix_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 void clutter_value_set_shader_float (GValue *value, gint size, const gfloat *floats); CLUTTER_AVAILABLE_IN_1_0 void clutter_value_set_shader_int (GValue *value, gint size, const gint *ints); CLUTTER_AVAILABLE_IN_1_0 void clutter_value_set_shader_matrix (GValue *value, gint size, const gfloat *matrix); CLUTTER_AVAILABLE_IN_1_0 const gfloat * clutter_value_get_shader_float (const GValue *value, gsize *length); CLUTTER_AVAILABLE_IN_1_0 const gint * clutter_value_get_shader_int (const GValue *value, gsize *length); CLUTTER_AVAILABLE_IN_1_0 const gfloat * clutter_value_get_shader_matrix (const GValue *value, gsize *length); G_END_DECLS #endif /* __CLUTTER_SHADER_TYPES_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-enum-types.h.in������������������������������������������������0000664�0001750�0001750�00000001274�14211404421�022650� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** BEGIN file-header ***/ #ifndef __CLUTTER_ENUM_TYPES_H__ #define __CLUTTER_ENUM_TYPES_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> G_BEGIN_DECLS /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ /*** END file-production ***/ /*** BEGIN value-header ***/ CLUTTER_AVAILABLE_IN_ALL GType @enum_name@_get_type (void) G_GNUC_CONST; #define CLUTTER_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) /*** END value-header ***/ /*** BEGIN file-tail ***/ G_END_DECLS #endif /* !__CLUTTER_ENUM_TYPES_H__ */ /*** END file-tail ***/ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-virtual-input-device.h�����������������������������������������0000664�0001750�0001750�00000021366�14211404421�024221� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2016 Red Hat inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifndef __CLUTTER_VIRTUAL_INPUT_DEVICE_H__ #define __CLUTTER_VIRTUAL_INPUT_DEVICE_H__ #include <glib-object.h> #include <stdint.h> #include "clutter-device-manager.h" #define CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE (clutter_virtual_input_device_get_type ()) CLUTTER_AVAILABLE_IN_ALL G_DECLARE_DERIVABLE_TYPE (ClutterVirtualInputDevice, clutter_virtual_input_device, CLUTTER, VIRTUAL_INPUT_DEVICE, GObject) typedef enum _ClutterButtonState { CLUTTER_BUTTON_STATE_RELEASED, CLUTTER_BUTTON_STATE_PRESSED } ClutterButtonState; typedef enum _ClutterKeyState { CLUTTER_KEY_STATE_RELEASED, CLUTTER_KEY_STATE_PRESSED } ClutterKeyState; struct _ClutterVirtualInputDeviceClass { GObjectClass parent_class; void (*notify_relative_motion) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy); void (*notify_absolute_motion) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double x, double y); void (*notify_button) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t button, ClutterButtonState button_state); void (*notify_key) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t key, ClutterKeyState key_state); void (*notify_keyval) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t keyval, ClutterKeyState key_state); void (*notify_discrete_scroll) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, ClutterScrollDirection direction, ClutterScrollSource scroll_source); void (*notify_scroll_continuous) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy, ClutterScrollSource scroll_source, ClutterScrollFinishFlags finish_flags); void (*notify_touch_down) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot, double x, double y); void (*notify_touch_motion) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot, double x, double y); void (*notify_touch_up) (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot); }; CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_relative_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double x, double y); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_button (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t button, ClutterButtonState button_state); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_key (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t key, ClutterKeyState key_state); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_keyval (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t keyval, ClutterKeyState key_state); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, ClutterScrollDirection direction, ClutterScrollSource scroll_source); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_scroll_continuous (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy, ClutterScrollSource scroll_source, ClutterScrollFinishFlags finish_flags); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_touch_down (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot, double x, double y); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_touch_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot, double x, double y); CLUTTER_AVAILABLE_IN_ALL void clutter_virtual_input_device_notify_touch_up (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot); CLUTTER_AVAILABLE_IN_ALL ClutterDeviceManager * clutter_virtual_input_device_get_manager (ClutterVirtualInputDevice *virtual_device); int clutter_virtual_input_device_get_device_type (ClutterVirtualInputDevice *virtual_device); #endif /* __CLUTTER_VIRTUAL_INPUT_DEVICE_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-input-method.c�������������������������������������������������0000664�0001750�0001750�00000032177�14211404421�022553� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2017,2018 Red Hat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #include "clutter-build-config.h" #include "clutter-private.h" #include "clutter/clutter-input-method.h" #include "clutter/clutter-input-method-private.h" #include "clutter/clutter-input-focus-private.h" typedef struct _ClutterInputMethodPrivate ClutterInputMethodPrivate; struct _ClutterInputMethodPrivate { ClutterInputFocus *focus; ClutterInputContentHintFlags content_hints; ClutterInputContentPurpose content_purpose; gboolean can_show_preedit; }; enum { COMMIT, DELETE_SURROUNDING, REQUEST_SURROUNDING, INPUT_PANEL_STATE, CURSOR_LOCATION_CHANGED, N_SIGNALS, }; enum { PROP_0, PROP_CONTENT_HINTS, PROP_CONTENT_PURPOSE, PROP_CAN_SHOW_PREEDIT, N_PROPS }; static guint signals[N_SIGNALS] = { 0 }; static GParamSpec *pspecs[N_PROPS] = { 0 }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputMethod, clutter_input_method, G_TYPE_OBJECT) static void set_content_hints (ClutterInputMethod *im, ClutterInputContentHintFlags content_hints) { ClutterInputMethodPrivate *priv; priv = clutter_input_method_get_instance_private (im); priv->content_hints = content_hints; CLUTTER_INPUT_METHOD_GET_CLASS (im)->update_content_hints (im, content_hints); } static void set_content_purpose (ClutterInputMethod *im, ClutterInputContentPurpose content_purpose) { ClutterInputMethodPrivate *priv; priv = clutter_input_method_get_instance_private (im); priv->content_purpose = content_purpose; CLUTTER_INPUT_METHOD_GET_CLASS (im)->update_content_purpose (im, content_purpose); } static void set_can_show_preedit (ClutterInputMethod *im, gboolean can_show_preedit) { ClutterInputMethodPrivate *priv; priv = clutter_input_method_get_instance_private (im); priv->can_show_preedit = can_show_preedit; } static void clutter_input_method_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_CONTENT_HINTS: set_content_hints (CLUTTER_INPUT_METHOD (object), g_value_get_flags (value)); break; case PROP_CONTENT_PURPOSE: set_content_purpose (CLUTTER_INPUT_METHOD (object), g_value_get_enum (value)); break; case PROP_CAN_SHOW_PREEDIT: set_can_show_preedit (CLUTTER_INPUT_METHOD (object), g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_input_method_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterInputMethodPrivate *priv; ClutterInputMethod *im; im = CLUTTER_INPUT_METHOD (object); priv = clutter_input_method_get_instance_private (im); switch (prop_id) { case PROP_CONTENT_HINTS: g_value_set_flags (value, priv->content_hints); break; case PROP_CONTENT_PURPOSE: g_value_set_enum (value, priv->content_purpose); break; case PROP_CAN_SHOW_PREEDIT: g_value_set_boolean (value, priv->can_show_preedit); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_input_method_class_init (ClutterInputMethodClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = clutter_input_method_set_property; object_class->get_property = clutter_input_method_get_property; signals[COMMIT] = g_signal_new ("commit", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); signals[DELETE_SURROUNDING] = g_signal_new ("delete-surrounding", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); signals[REQUEST_SURROUNDING] = g_signal_new ("request-surrounding", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); signals[INPUT_PANEL_STATE] = g_signal_new ("input-panel-state", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, CLUTTER_TYPE_INPUT_PANEL_STATE); signals[CURSOR_LOCATION_CHANGED] = g_signal_new ("cursor-location-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, CLUTTER_TYPE_RECT); pspecs[PROP_CONTENT_HINTS] = g_param_spec_flags ("content-hints", P_("Content hints"), P_("Content hints"), CLUTTER_TYPE_INPUT_CONTENT_HINT_FLAGS, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); pspecs[PROP_CONTENT_PURPOSE] = g_param_spec_enum ("content-purpose", P_("Content purpose"), P_("Content purpose"), CLUTTER_TYPE_INPUT_CONTENT_PURPOSE, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); pspecs[PROP_CAN_SHOW_PREEDIT] = g_param_spec_boolean ("can-show-preedit", P_("Can show preedit"), P_("Can show preedit"), FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, pspecs); } static void clutter_input_method_init (ClutterInputMethod *im) { } void clutter_input_method_focus_in (ClutterInputMethod *im, ClutterInputFocus *focus) { ClutterInputMethodPrivate *priv; ClutterInputMethodClass *klass; g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); priv = clutter_input_method_get_instance_private (im); if (priv->focus == focus) return; if (priv->focus) clutter_input_method_focus_out (im); g_set_object (&priv->focus, focus); if (focus) { klass = CLUTTER_INPUT_METHOD_GET_CLASS (im); klass->focus_in (im, focus); clutter_input_focus_focus_in (priv->focus, im); } } void clutter_input_method_focus_out (ClutterInputMethod *im) { ClutterInputMethodPrivate *priv; ClutterInputMethodClass *klass; g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); priv = clutter_input_method_get_instance_private (im); if (!priv->focus) return; clutter_input_focus_focus_out (priv->focus); g_clear_object (&priv->focus); klass = CLUTTER_INPUT_METHOD_GET_CLASS (im); klass->focus_out (im); g_signal_emit (im, signals[INPUT_PANEL_STATE], 0, CLUTTER_INPUT_PANEL_STATE_OFF); } ClutterInputFocus * clutter_input_method_get_focus (ClutterInputMethod *im) { ClutterInputMethodPrivate *priv; priv = clutter_input_method_get_instance_private (im); return priv->focus; } void clutter_input_method_commit (ClutterInputMethod *im, const gchar *text) { ClutterInputMethodPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); priv = clutter_input_method_get_instance_private (im); if (priv->focus) clutter_input_focus_commit (priv->focus, text); } void clutter_input_method_delete_surrounding (ClutterInputMethod *im, guint offset, guint len) { ClutterInputMethodPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); priv = clutter_input_method_get_instance_private (im); if (priv->focus) clutter_input_focus_delete_surrounding (priv->focus, offset, len); } void clutter_input_method_request_surrounding (ClutterInputMethod *im) { ClutterInputMethodPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); priv = clutter_input_method_get_instance_private (im); if (priv->focus) clutter_input_focus_request_surrounding (priv->focus); } /** * clutter_input_method_set_preedit_text: * @im: a #ClutterInputMethod * @preedit: (nullable): the preedit text, or %NULL * @cursor: the cursor * * Sets the preedit text on the current input focus. **/ void clutter_input_method_set_preedit_text (ClutterInputMethod *im, const gchar *preedit, guint cursor) { ClutterInputMethodPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); priv = clutter_input_method_get_instance_private (im); if (priv->focus) clutter_input_focus_set_preedit_text (priv->focus, preedit, cursor); } void clutter_input_method_notify_key_event (ClutterInputMethod *im, const ClutterEvent *event, gboolean filtered) { if (!filtered) { ClutterEvent *copy; /* XXX: we rely on the IM implementation to notify back of * key events in the exact same order they were given. */ copy = clutter_event_copy (event); clutter_event_set_flags (copy, clutter_event_get_flags (event) | CLUTTER_EVENT_FLAG_INPUT_METHOD); clutter_event_set_source_device (copy, clutter_event_get_device (copy)); clutter_event_put (copy); clutter_event_free (copy); } } void clutter_input_method_toggle_input_panel (ClutterInputMethod *im) { g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); g_signal_emit (im, signals[INPUT_PANEL_STATE], 0, CLUTTER_INPUT_PANEL_STATE_TOGGLE); } void clutter_input_method_reset (ClutterInputMethod *im) { g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); CLUTTER_INPUT_METHOD_GET_CLASS (im)->reset (im); } void clutter_input_method_set_cursor_location (ClutterInputMethod *im, const ClutterRect *rect) { g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); CLUTTER_INPUT_METHOD_GET_CLASS (im)->set_cursor_location (im, rect); g_signal_emit (im, signals[CURSOR_LOCATION_CHANGED], 0, rect); } void clutter_input_method_set_surrounding (ClutterInputMethod *im, const gchar *text, guint cursor, guint anchor) { g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); CLUTTER_INPUT_METHOD_GET_CLASS (im)->set_surrounding (im, text, cursor, anchor); } void clutter_input_method_set_content_hints (ClutterInputMethod *im, ClutterInputContentHintFlags hints) { g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); g_object_set (G_OBJECT (im), "content-hints", hints, NULL); } void clutter_input_method_set_content_purpose (ClutterInputMethod *im, ClutterInputContentPurpose purpose) { g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); g_object_set (G_OBJECT (im), "content-purpose", purpose, NULL); } void clutter_input_method_set_can_show_preedit (ClutterInputMethod *im, gboolean can_show_preedit) { g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); g_object_set (G_OBJECT (im), "can-show-preedit", can_show_preedit, NULL); } gboolean clutter_input_method_filter_key_event (ClutterInputMethod *im, const ClutterKeyEvent *key) { ClutterInputMethodClass *im_class = CLUTTER_INPUT_METHOD_GET_CLASS (im); g_return_val_if_fail (CLUTTER_IS_INPUT_METHOD (im), FALSE); g_return_val_if_fail (key != NULL, FALSE); if (clutter_event_get_flags ((ClutterEvent *) key) & CLUTTER_EVENT_FLAG_INPUT_METHOD) return FALSE; if (!im_class->filter_key_event) return FALSE; return im_class->filter_key_event (im, (const ClutterEvent *) key); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-path.h���������������������������������������������������������0000664�0001750�0001750�00000017705�14211404421�021077� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2008 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_PATH_H__ #define __CLUTTER_PATH_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <cairo.h> #include <clutter/clutter-types.h> G_BEGIN_DECLS #define CLUTTER_TYPE_PATH (clutter_path_get_type ()) #define CLUTTER_TYPE_PATH_NODE (clutter_path_node_get_type ()) #define CLUTTER_PATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PATH, ClutterPath)) #define CLUTTER_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_PATH, ClutterPathClass)) #define CLUTTER_IS_PATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PATH)) #define CLUTTER_IS_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_PATH)) #define CLUTTER_PATH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_PATH, ClutterPathClass)) typedef struct _ClutterPathClass ClutterPathClass; typedef struct _ClutterPathPrivate ClutterPathPrivate; /** * ClutterPathCallback: * @node: the node * @data: (closure): optional data passed to the function * * This function is passed to clutter_path_foreach() and will be * called for each node contained in the path. * * Since: 1.0 */ typedef void (* ClutterPathCallback) (const ClutterPathNode *node, gpointer data); /** * ClutterPath: * * The #ClutterPath struct contains only private data and should * be accessed with the functions below. * * Since: 1.0 */ struct _ClutterPath { /*< private >*/ GInitiallyUnowned parent; ClutterPathPrivate *priv; }; /** * ClutterPathClass: * * The #ClutterPathClass struct contains only private data. * * Since: 1.0 */ struct _ClutterPathClass { /*< private >*/ GInitiallyUnownedClass parent_class; }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_path_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterPath *clutter_path_new (void); CLUTTER_AVAILABLE_IN_1_0 ClutterPath *clutter_path_new_with_description (const gchar *desc); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_move_to (ClutterPath *path, gint x, gint y); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_rel_move_to (ClutterPath *path, gint x, gint y); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_line_to (ClutterPath *path, gint x, gint y); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_rel_line_to (ClutterPath *path, gint x, gint y); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_curve_to (ClutterPath *path, gint x_1, gint y_1, gint x_2, gint y_2, gint x_3, gint y_3); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_rel_curve_to (ClutterPath *path, gint x_1, gint y_1, gint x_2, gint y_2, gint x_3, gint y_3); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_close (ClutterPath *path); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_path_add_string (ClutterPath *path, const gchar *str); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_node (ClutterPath *path, const ClutterPathNode *node); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_add_cairo_path (ClutterPath *path, const cairo_path_t *cpath); CLUTTER_AVAILABLE_IN_1_0 guint clutter_path_get_n_nodes (ClutterPath *path); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_get_node (ClutterPath *path, guint index_, ClutterPathNode *node); CLUTTER_AVAILABLE_IN_1_0 GSList * clutter_path_get_nodes (ClutterPath *path); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_foreach (ClutterPath *path, ClutterPathCallback callback, gpointer user_data); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_insert_node (ClutterPath *path, gint index_, const ClutterPathNode *node); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_remove_node (ClutterPath *path, guint index_); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_replace_node (ClutterPath *path, guint index_, const ClutterPathNode *node); CLUTTER_AVAILABLE_IN_1_0 gchar * clutter_path_get_description (ClutterPath *path); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_path_set_description (ClutterPath *path, const gchar *str); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_clear (ClutterPath *path); CLUTTER_AVAILABLE_IN_1_0 void clutter_path_to_cairo_path (ClutterPath *path, cairo_t *cr); CLUTTER_AVAILABLE_IN_1_0 guint clutter_path_get_position (ClutterPath *path, gdouble progress, ClutterKnot *position); CLUTTER_AVAILABLE_IN_1_0 guint clutter_path_get_length (ClutterPath *path); G_END_DECLS #endif /* __CLUTTER_PATH_H__ */ �����������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-keysyms-update.pl����������������������������������������������0000775�0001750�0001750�00000014412�14211404421�023306� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env perl # Author : Simos Xenitellis <simos at gnome dot org>. # Authos : Bastien Nocera <hadess@hadess.net> # Version : 1.2 # # Notes : It downloads keysymdef.h from the Internet, if not found locally, # Notes : and creates an updated clutter-keysyms.h use strict; my $update_url = 'http://git.clutter-project.org/clutter/plain/clutter/clutter-keysyms-update.pl'; # Used for reading the keysymdef symbols. my @keysymelements; my $keysymdef_url = 'http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h'; if ( ! -f "keysymdef.h" ) { print "Trying to download keysymdef.h from\n", $keysymdef_url, "\n"; die "Unable to download keysymdef.h: $!" unless system("wget -c -O keysymdef.h \"$keysymdef_url\"") == 0; print " done.\n\n"; } else { print "We are using existing keysymdef.h found in this directory.\n"; print "It is assumed that you took care and it is a recent version\n"; } my $XF86keysym_url = 'http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h'; if ( ! -f "XF86keysym.h" ) { print "Trying to download XF86keysym.h from\n", $XF86keysym_url, "\n"; die "Unable to download keysymdef.h: $!\n" unless system("wget -c -O XF86keysym.h \"$XF86keysym_url\"") == 0; print " done.\n\n"; } else { print "We are using existing XF86keysym.h found in this directory.\n"; print "It is assumed that you took care and it is a recent version\n"; } if ( -f "clutter-keysyms.h" ) { print "There is already a clutter-keysyms.h file in this directory. We are not overwriting it.\n"; print "Please move it somewhere else in order to run this script.\n"; die "Exiting...\n\n"; } die "Could not open file keysymdef.h: $!\n" unless open(IN_KEYSYMDEF, "<:utf8", "keysymdef.h"); # Output: clutter/clutter/clutter-keysyms.h die "Could not open file clutter-keysyms.h: $!\n" unless open(OUT_KEYSYMS, ">:utf8", "clutter-keysyms.h"); # Output: clutter/clutter/deprecated/clutter-keysyms.h die "Could not open file clutter-keysyms-compat.h: $!\n" unless open(OUT_KEYSYMS_COMPAT, ">:utf8", "deprecated/clutter-keysyms.h"); my $LICENSE_HEADER= <<EOF; /* Clutter * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see <http://www.gnu.org/licenses>. */ EOF print OUT_KEYSYMS $LICENSE_HEADER; print OUT_KEYSYMS_COMPAT $LICENSE_HEADER; print OUT_KEYSYMS<<EOF; /* * File auto-generated from script at: * $update_url * * using the input files: * $keysymdef_url * and * $XF86keysym_url */ #ifndef __CLUTTER_KEYSYMS_H__ #define __CLUTTER_KEYSYMS_H__ EOF print OUT_KEYSYMS_COMPAT<<EOF; /* * Compatibility version of clutter-keysyms.h. * * Since Clutter 1.4, the key symbol defines have been changed to have * a KEY_ prefix. This is a compatibility header that is included when * deprecated symbols are enabled. Consider porting to the new names * instead. */ #ifndef __CLUTTER_KEYSYMS_DEPRECATED_H__ #define __CLUTTER_KEYSYMS_DEPRECATED_H__ #ifndef CLUTTER_DISABLE_DEPRECATED EOF while (<IN_KEYSYMDEF>) { next if ( ! /^#define / ); @keysymelements = split(/\s+/); die "Internal error, no \@keysymelements: $_\n" unless @keysymelements; $_ = $keysymelements[1]; die "Internal error, was expecting \"XC_*\", found: $_\n" if ( ! /^XK_/ ); $_ = $keysymelements[2]; die "Internal error, was expecting \"0x*\", found: $_\n" if ( ! /^0x/ ); my $element = $keysymelements[1]; my $binding = $element; $binding =~ s/^XK_/CLUTTER_KEY_/g; my $compat_binding = $element; $compat_binding =~ s/^XK_/CLUTTER_/g; my $deprecation = "CLUTTER_DEPRECATED_MACRO_FOR(\"Deprecated key symbol. Use $binding instead.\")"; printf OUT_KEYSYMS "#define %s 0x%03x\n", $binding, hex($keysymelements[2]); printf OUT_KEYSYMS_COMPAT "#define %s 0x%03x %s\n", $compat_binding, hex($keysymelements[2]), $deprecation; } close IN_KEYSYMDEF; #$cluttersyms{"0"} = "0000"; # Source: http://gitweb.freedesktop.org/?p=xorg/proto/x11proto.git;a=blob;f=XF86keysym.h die "Could not open file XF86keysym.h: $!\n" unless open(IN_XF86KEYSYM, "<:utf8", "XF86keysym.h"); while (<IN_XF86KEYSYM>) { next if ( ! /^#define / ); @keysymelements = split(/\s+/); die "Internal error, no \@keysymelements: $_\n" unless @keysymelements; $_ = $keysymelements[1]; die "Internal error, was expecting \"XF86XK_*\", found: $_\n" if ( ! /^XF86XK_/ ); # Work-around https://bugs.freedesktop.org/show_bug.cgi?id=11193 if ($_ eq "XF86XK_XF86BackForward") { $keysymelements[1] = "XF86XK_AudioForward"; } # XF86XK_Clear could end up a dupe of XK_Clear # XF86XK_Select could end up a dupe of XK_Select if ($_ eq "XF86XK_Clear") { $keysymelements[1] = "XF86XK_WindowClear"; } if ($_ eq "XF86XK_Select") { $keysymelements[1] = "XF86XK_SelectButton"; } # Ignore XF86XK_Q next if ( $_ eq "XF86XK_Q"); # XF86XK_Calculater is misspelled, and a dupe next if ( $_ eq "XF86XK_Calculater"); $_ = $keysymelements[2]; die "Internal error, was expecting \"0x*\", found: $_\n" if ( ! /^0x/ ); my $element = $keysymelements[1]; my $binding = $element; $binding =~ s/^XF86XK_/CLUTTER_KEY_/g; my $compat_binding = $element; $compat_binding =~ s/^XF86XK_/CLUTTER_/g; printf OUT_KEYSYMS "#define %s 0x%03x\n", $binding, hex($keysymelements[2]); printf OUT_KEYSYMS_COMPAT "#define %s 0x%03x\n", $compat_binding, hex($keysymelements[2]); } close IN_XF86KEYSYM; print OUT_KEYSYMS<<EOF; #endif /* __CLUTTER_KEYSYMS_H__ */ EOF print OUT_KEYSYMS_COMPAT<<EOF; #endif /* CLUTTER_DISABLE_DEPRECATED */ #endif /* __CLUTTER_KEYSYMS_DEPRECATED_H__ */ EOF foreach my $f (qw/ keysymdef.h XF86keysym.h /) { unlink $f or die "Unable to delete $f: $!"; } printf "We just finished converting keysymdef.h to clutter-keysyms.h " . "and deprecated/clutter-keysyms.h\nThank you\n"; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-feature.c������������������������������������������������������0000664�0001750�0001750�00000007774�14211404421�021576� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * */ /** * SECTION:clutter-feature * @short_description: Run-time detection of Clutter features * * Parts of Clutter depend on the underlying platform, including the * capabilities of the backend used and the OpenGL features exposed through the * Clutter and COGL API. * * It is possible to ask whether Clutter has support for specific features at * run-time. * * See also cogl_get_features() and #CoglFeatureFlags */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <stdlib.h> #include <string.h> #include <sys/types.h> #include "clutter-backend-private.h" #include "clutter-feature.h" #include "clutter-main.h" #include "clutter-private.h" #include "clutter-debug.h" #include "cogl/cogl.h" typedef struct ClutterFeatures { ClutterFeatureFlags flags; guint features_set : 1; } ClutterFeatures; static ClutterFeatures* __features = NULL; static ClutterFeatureFlags clutter_features_from_cogl (guint cogl_flags) { ClutterFeatureFlags clutter_flags = 0; if (cogl_flags & COGL_FEATURE_TEXTURE_NPOT) clutter_flags |= CLUTTER_FEATURE_TEXTURE_NPOT; if (cogl_flags & COGL_FEATURE_TEXTURE_YUV) clutter_flags |= CLUTTER_FEATURE_TEXTURE_YUV; if (cogl_flags & COGL_FEATURE_TEXTURE_READ_PIXELS) clutter_flags |= CLUTTER_FEATURE_TEXTURE_READ_PIXELS; if (cogl_flags & COGL_FEATURE_SHADERS_GLSL) clutter_flags |= CLUTTER_FEATURE_SHADERS_GLSL; if (cogl_flags & COGL_FEATURE_OFFSCREEN) clutter_flags |= CLUTTER_FEATURE_OFFSCREEN; return clutter_flags; } gboolean _clutter_feature_init (GError **error) { ClutterMainContext *context; CLUTTER_NOTE (MISC, "checking features"); if (!__features) { CLUTTER_NOTE (MISC, "allocating features data"); __features = g_new0 (ClutterFeatures, 1); __features->features_set = FALSE; /* don't rely on zero-ing */ } if (__features->features_set) return TRUE; context = _clutter_context_get_default (); /* makes sure we have a GL context; if we have, this is a no-op */ if (!_clutter_backend_create_context (context->backend, error)) return FALSE; __features->flags = (clutter_features_from_cogl (cogl_get_features ()) | _clutter_backend_get_features (context->backend)); __features->features_set = TRUE; CLUTTER_NOTE (MISC, "features checked"); return TRUE; } /** * clutter_feature_available: * @feature: a #ClutterFeatureFlags * * Checks whether @feature is available. @feature can be a logical * OR of #ClutterFeatureFlags. * * Return value: %TRUE if a feature is available * * Since: 0.2 */ gboolean clutter_feature_available (ClutterFeatureFlags feature) { if (G_UNLIKELY (!__features)) { g_critical ("Unable to check features. Have you initialized Clutter?"); return FALSE; } return (__features->flags & feature); } /** * clutter_feature_get_all: * * Returns all the supported features. * * Return value: a logical OR of all the supported features. * * Since: 0.2 */ ClutterFeatureFlags clutter_feature_get_all (void) { if (G_UNLIKELY (!__features)) { g_critical ("Unable to check features. Have you initialized Clutter?"); return FALSE; } return __features->flags; } ����muffin-5.2.1/clutter/clutter/clutter-virtual-input-device.c�����������������������������������������0000664�0001750�0001750�00000024531�14211404421�024211� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2016 Red Hat Inc. * * 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, see <http://www.gnu.org/licenses/>. * * Author: Jonas Ådahl <jadahl@gmail.com> */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <glib-object.h> #include "clutter-virtual-input-device.h" #include "clutter-device-manager.h" #include "clutter-private.h" #include "clutter-enum-types.h" enum { PROP_0, PROP_DEVICE_MANAGER, PROP_DEVICE_TYPE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; typedef struct _ClutterVirtualInputDevicePrivate { ClutterDeviceManager *manager; ClutterInputDeviceType device_type; } ClutterVirtualInputDevicePrivate; G_DEFINE_TYPE_WITH_PRIVATE (ClutterVirtualInputDevice, clutter_virtual_input_device, G_TYPE_OBJECT) void clutter_virtual_input_device_notify_relative_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_relative_motion (virtual_device, time_us, dx, dy); } void clutter_virtual_input_device_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double x, double y) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_absolute_motion (virtual_device, time_us, x, y); } void clutter_virtual_input_device_notify_button (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t button, ClutterButtonState button_state) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_button (virtual_device, time_us, button, button_state); } void clutter_virtual_input_device_notify_key (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t key, ClutterKeyState key_state) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_key (virtual_device, time_us, key, key_state); } void clutter_virtual_input_device_notify_keyval (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, uint32_t keyval, ClutterKeyState key_state) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_keyval (virtual_device, time_us, keyval, key_state); } void clutter_virtual_input_device_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, ClutterScrollDirection direction, ClutterScrollSource scroll_source) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_discrete_scroll (virtual_device, time_us, direction, scroll_source); } void clutter_virtual_input_device_notify_scroll_continuous (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, double dx, double dy, ClutterScrollSource scroll_source, ClutterScrollFinishFlags finish_flags) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_scroll_continuous (virtual_device, time_us, dx, dy, scroll_source, finish_flags); } void clutter_virtual_input_device_notify_touch_down (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot, double x, double y) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_touch_down (virtual_device, time_us, slot, x, y); } void clutter_virtual_input_device_notify_touch_motion (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot, double x, double y) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_touch_motion (virtual_device, time_us, slot, x, y); } void clutter_virtual_input_device_notify_touch_up (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, int slot) { ClutterVirtualInputDeviceClass *klass = CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device); klass->notify_touch_up (virtual_device, time_us, slot); } /** * clutter_virtual_input_device_get_manager: * @virtual_device: a virtual device * * Gets the device manager of this virtual device. * * Returns: (transfer none): The #ClutterDeviceManager of this virtual device **/ ClutterDeviceManager * clutter_virtual_input_device_get_manager (ClutterVirtualInputDevice *virtual_device) { ClutterVirtualInputDevicePrivate *priv = clutter_virtual_input_device_get_instance_private (virtual_device); return priv->manager; } int clutter_virtual_input_device_get_device_type (ClutterVirtualInputDevice *virtual_device) { ClutterVirtualInputDevicePrivate *priv = clutter_virtual_input_device_get_instance_private (virtual_device); return priv->device_type; } static void clutter_virtual_input_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterVirtualInputDevice *virtual_device = CLUTTER_VIRTUAL_INPUT_DEVICE (object); ClutterVirtualInputDevicePrivate *priv = clutter_virtual_input_device_get_instance_private (virtual_device); switch (prop_id) { case PROP_DEVICE_MANAGER: g_value_set_object (value, priv->manager); break; case PROP_DEVICE_TYPE: g_value_set_enum (value, priv->device_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_virtual_input_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterVirtualInputDevice *virtual_device = CLUTTER_VIRTUAL_INPUT_DEVICE (object); ClutterVirtualInputDevicePrivate *priv = clutter_virtual_input_device_get_instance_private (virtual_device); switch (prop_id) { case PROP_DEVICE_MANAGER: priv->manager = g_value_get_object (value); break; case PROP_DEVICE_TYPE: priv->device_type = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_virtual_input_device_init (ClutterVirtualInputDevice *virtual_device) { } static void clutter_virtual_input_device_class_init (ClutterVirtualInputDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = clutter_virtual_input_device_get_property; object_class->set_property = clutter_virtual_input_device_set_property; obj_props[PROP_DEVICE_MANAGER] = g_param_spec_object ("device-manager", P_("Device Manager"), P_("The device manager instance"), CLUTTER_TYPE_DEVICE_MANAGER, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_DEVICE_TYPE] = g_param_spec_enum ("device-type", P_("Device type"), P_("Device type"), CLUTTER_TYPE_INPUT_DEVICE_TYPE, CLUTTER_POINTER_DEVICE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (object_class, PROP_LAST, obj_props); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-action.h�������������������������������������������������������0000664�0001750�0001750�00000007455�14211404421�021421� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_ACTION_H__ #define __CLUTTER_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-actor-meta.h> G_BEGIN_DECLS #define CLUTTER_TYPE_ACTION (clutter_action_get_type ()) #define CLUTTER_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTION, ClutterAction)) #define CLUTTER_IS_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTION)) #define CLUTTER_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTION, ClutterActionClass)) #define CLUTTER_IS_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTION)) #define CLUTTER_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTION, ClutterActionClass)) typedef struct _ClutterActionClass ClutterActionClass; /** * ClutterAction: * * The #ClutterAction structure contains only private data and * should be accessed using the provided API. * * Since: 1.4 */ struct _ClutterAction { /*< private >*/ ClutterActorMeta parent_instance; }; /** * ClutterActionClass: * * The ClutterActionClass structure contains only private data * * Since: 1.4 */ struct _ClutterActionClass { /*< private >*/ ClutterActorMetaClass parent_class; void (* _clutter_action1) (void); void (* _clutter_action2) (void); void (* _clutter_action3) (void); void (* _clutter_action4) (void); void (* _clutter_action5) (void); void (* _clutter_action6) (void); void (* _clutter_action7) (void); void (* _clutter_action8) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_action_get_type (void) G_GNUC_CONST; /* ClutterActor API */ CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_add_action (ClutterActor *self, ClutterAction *action); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_add_action_with_name (ClutterActor *self, const gchar *name, ClutterAction *action); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_remove_action (ClutterActor *self, ClutterAction *action); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_remove_action_by_name (ClutterActor *self, const gchar *name); CLUTTER_AVAILABLE_IN_1_4 ClutterAction *clutter_actor_get_action (ClutterActor *self, const gchar *name); CLUTTER_AVAILABLE_IN_1_4 GList * clutter_actor_get_actions (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_clear_actions (ClutterActor *self); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_actor_has_actions (ClutterActor *self); G_END_DECLS #endif /* __CLUTTER_ACTION_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-transition.h���������������������������������������������������0000664�0001750�0001750�00000012767�14211404421�022340� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. * * Author: Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_TRANSITION_H__ #define __CLUTTER_TRANSITION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-types.h> #include <clutter/clutter-timeline.h> G_BEGIN_DECLS #define CLUTTER_TYPE_TRANSITION (clutter_transition_get_type ()) #define CLUTTER_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TRANSITION, ClutterTransition)) #define CLUTTER_IS_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TRANSITION)) #define CLUTTER_TRANSITION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TRANSITION, ClutterTransitionClass)) #define CLUTTER_IS_TRANSITION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TRANSITION)) #define CLUTTER_TRANSITION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TRANSITION, ClutterTransitionClass)) typedef struct _ClutterTransitionPrivate ClutterTransitionPrivate; typedef struct _ClutterTransitionClass ClutterTransitionClass; /** * ClutterTransition: * * The #ClutterTransition structure contains private * data and should only be accessed using the provided API. * * Since: 1.10 */ struct _ClutterTransition { /*< private >*/ ClutterTimeline parent_instance; ClutterTransitionPrivate *priv; }; /** * ClutterTransitionClass: * @attached: virtual function; called when a transition is attached to * a #ClutterAnimatable instance * @detached: virtual function; called when a transition is detached from * a #ClutterAnimatable instance * @compute_value: virtual function; called each frame to compute and apply * the interpolation of the interval * * The #ClutterTransitionClass structure contains * private data. * * Since: 1.10 */ struct _ClutterTransitionClass { /*< private >*/ ClutterTimelineClass parent_class; /*< public >*/ void (* attached) (ClutterTransition *transition, ClutterAnimatable *animatable); void (* detached) (ClutterTransition *transition, ClutterAnimatable *animatable); void (* compute_value) (ClutterTransition *transition, ClutterAnimatable *animatable, ClutterInterval *interval, gdouble progress); /*< private >*/ gpointer _padding[8]; }; CLUTTER_AVAILABLE_IN_1_10 GType clutter_transition_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 void clutter_transition_set_interval (ClutterTransition *transition, ClutterInterval *interval); CLUTTER_AVAILABLE_IN_1_10 ClutterInterval * clutter_transition_get_interval (ClutterTransition *transition); CLUTTER_AVAILABLE_IN_1_12 void clutter_transition_set_from_value (ClutterTransition *transition, const GValue *value); CLUTTER_AVAILABLE_IN_1_12 void clutter_transition_set_to_value (ClutterTransition *transition, const GValue *value); CLUTTER_AVAILABLE_IN_1_12 void clutter_transition_set_from (ClutterTransition *transition, GType value_type, ...); CLUTTER_AVAILABLE_IN_1_12 void clutter_transition_set_to (ClutterTransition *transition, GType value_type, ...); CLUTTER_AVAILABLE_IN_1_10 void clutter_transition_set_animatable (ClutterTransition *transition, ClutterAnimatable *animatable); CLUTTER_AVAILABLE_IN_1_10 ClutterAnimatable * clutter_transition_get_animatable (ClutterTransition *transition); CLUTTER_AVAILABLE_IN_1_10 void clutter_transition_set_remove_on_complete (ClutterTransition *transition, gboolean remove_complete); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_transition_get_remove_on_complete (ClutterTransition *transition); G_END_DECLS #endif /* __CLUTTER_TRANSITION_H__ */ ���������muffin-5.2.1/clutter/clutter/clutter-input-focus.c��������������������������������������������������0000664�0001750�0001750�00000015647�14211404421�022415� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2017,2018 Red Hat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Carlos Garnacho <carlosg@gnome.org> */ #include "clutter-build-config.h" #include "clutter/clutter-input-focus.h" #include "clutter/clutter-input-focus-private.h" #include "clutter/clutter-input-method-private.h" typedef struct _ClutterInputFocusPrivate ClutterInputFocusPrivate; struct _ClutterInputFocusPrivate { ClutterInputMethod *im; }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputFocus, clutter_input_focus, G_TYPE_OBJECT) static void clutter_input_focus_real_focus_in (ClutterInputFocus *focus, ClutterInputMethod *im) { ClutterInputFocusPrivate *priv; priv = clutter_input_focus_get_instance_private (focus); priv->im = im; } static void clutter_input_focus_real_focus_out (ClutterInputFocus *focus) { ClutterInputFocusPrivate *priv; priv = clutter_input_focus_get_instance_private (focus); priv->im = NULL; } static void clutter_input_focus_class_init (ClutterInputFocusClass *klass) { klass->focus_in = clutter_input_focus_real_focus_in; klass->focus_out = clutter_input_focus_real_focus_out; } static void clutter_input_focus_init (ClutterInputFocus *focus) { } gboolean clutter_input_focus_is_focused (ClutterInputFocus *focus) { ClutterInputFocusPrivate *priv; priv = clutter_input_focus_get_instance_private (focus); return !!priv->im; } void clutter_input_focus_reset (ClutterInputFocus *focus) { ClutterInputFocusPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (clutter_input_focus_is_focused (focus)); priv = clutter_input_focus_get_instance_private (focus); clutter_input_method_reset (priv->im); } void clutter_input_focus_set_cursor_location (ClutterInputFocus *focus, const ClutterRect *rect) { ClutterInputFocusPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (clutter_input_focus_is_focused (focus)); priv = clutter_input_focus_get_instance_private (focus); clutter_input_method_set_cursor_location (priv->im, rect); } void clutter_input_focus_set_surrounding (ClutterInputFocus *focus, const gchar *text, guint cursor, guint anchor) { ClutterInputFocusPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (clutter_input_focus_is_focused (focus)); priv = clutter_input_focus_get_instance_private (focus); clutter_input_method_set_surrounding (priv->im, text, cursor, anchor); } void clutter_input_focus_set_content_hints (ClutterInputFocus *focus, ClutterInputContentHintFlags hints) { ClutterInputFocusPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (clutter_input_focus_is_focused (focus)); priv = clutter_input_focus_get_instance_private (focus); clutter_input_method_set_content_hints (priv->im, hints); } void clutter_input_focus_set_content_purpose (ClutterInputFocus *focus, ClutterInputContentPurpose purpose) { ClutterInputFocusPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (clutter_input_focus_is_focused (focus)); priv = clutter_input_focus_get_instance_private (focus); clutter_input_method_set_content_purpose (priv->im, purpose); } gboolean clutter_input_focus_filter_key_event (ClutterInputFocus *focus, const ClutterKeyEvent *key) { ClutterInputFocusPrivate *priv; g_return_val_if_fail (CLUTTER_IS_INPUT_FOCUS (focus), FALSE); g_return_val_if_fail (clutter_input_focus_is_focused (focus), FALSE); priv = clutter_input_focus_get_instance_private (focus); return clutter_input_method_filter_key_event (priv->im, key); } void clutter_input_focus_set_can_show_preedit (ClutterInputFocus *focus, gboolean can_show_preedit) { ClutterInputFocusPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (clutter_input_focus_is_focused (focus)); priv = clutter_input_focus_get_instance_private (focus); clutter_input_method_set_can_show_preedit (priv->im, can_show_preedit); } void clutter_input_focus_request_toggle_input_panel (ClutterInputFocus *focus) { ClutterInputFocusPrivate *priv; g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (clutter_input_focus_is_focused (focus)); priv = clutter_input_focus_get_instance_private (focus); clutter_input_method_toggle_input_panel (priv->im); } void clutter_input_focus_focus_in (ClutterInputFocus *focus, ClutterInputMethod *im) { g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im)); CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->focus_in (focus, im); } void clutter_input_focus_focus_out (ClutterInputFocus *focus) { g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->focus_out (focus); } void clutter_input_focus_commit (ClutterInputFocus *focus, const gchar *text) { g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->commit_text (focus, text); } void clutter_input_focus_delete_surrounding (ClutterInputFocus *focus, guint offset, guint len) { g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->delete_surrounding (focus, offset, len); } void clutter_input_focus_request_surrounding (ClutterInputFocus *focus) { g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->request_surrounding (focus); } void clutter_input_focus_set_preedit_text (ClutterInputFocus *focus, const gchar *preedit, guint cursor) { g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus)); CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->set_preedit_text (focus, preedit, cursor); } �����������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-private.h������������������������������������������������������0000664�0001750�0001750�00000026655�14211404421�021621� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 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, see <http://www.gnu.org/licenses/>. * * */ #ifndef __CLUTTER_PRIVATE_H__ #define __CLUTTER_PRIVATE_H__ #include <string.h> #include <glib.h> #include <cogl-pango/cogl-pango.h> #include "clutter-backend.h" #include "clutter-effect.h" #include "clutter-event.h" #include "clutter-feature.h" #include "clutter-id-pool.h" #include "clutter-layout-manager.h" #include "clutter-master-clock.h" #include "clutter-settings.h" #include "clutter-stage-manager.h" #include "clutter-stage.h" G_BEGIN_DECLS typedef struct _ClutterMainContext ClutterMainContext; typedef struct _ClutterVertex4 ClutterVertex4; #define CLUTTER_REGISTER_VALUE_TRANSFORM_TO(TYPE_TO,func) { \ g_value_register_transform_func (g_define_type_id, TYPE_TO, func); \ } #define CLUTTER_REGISTER_VALUE_TRANSFORM_FROM(TYPE_FROM,func) { \ g_value_register_transform_func (TYPE_FROM, g_define_type_id, func); \ } #define CLUTTER_REGISTER_INTERVAL_PROGRESS(func) { \ clutter_interval_register_progress_func (g_define_type_id, func); \ } #define CLUTTER_PRIVATE_FLAGS(a) (((ClutterActor *) (a))->private_flags) #define CLUTTER_SET_PRIVATE_FLAGS(a,f) (CLUTTER_PRIVATE_FLAGS (a) |= (f)) #define CLUTTER_UNSET_PRIVATE_FLAGS(a,f) (CLUTTER_PRIVATE_FLAGS (a) &= ~(f)) #define CLUTTER_ACTOR_IS_TOPLEVEL(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IS_TOPLEVEL) != FALSE) #define CLUTTER_ACTOR_IS_INTERNAL_CHILD(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_INTERNAL_CHILD) != FALSE) #define CLUTTER_ACTOR_IN_DESTRUCTION(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_DESTRUCTION) != FALSE) #define CLUTTER_ACTOR_IN_REPARENT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_REPARENT) != FALSE) #define CLUTTER_ACTOR_IN_PAINT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PAINT) != FALSE) #define CLUTTER_ACTOR_IN_RELAYOUT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_RELAYOUT) != FALSE) #define CLUTTER_PARAM_READABLE (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS) #define CLUTTER_PARAM_WRITABLE (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS) #define CLUTTER_PARAM_READWRITE (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS) #define CLUTTER_PARAM_ANIMATABLE (1 << G_PARAM_USER_SHIFT) /* automagic interning of a static string */ #define I_(str) (g_intern_static_string ((str))) /* keep this for source compatibility with clutter */ #define P_(String) (String) #define N_(String) (String) #define _(String) (String) /* This is a replacement for the nearbyint function which always rounds to the * nearest integer. nearbyint is apparently a C99 function so it might not * always be available but also it seems in glibc it is defined as a function * call so this macro could end up faster anyway. We can't just add 0.5f * because it will break for negative numbers. */ #define CLUTTER_NEARBYINT(x) ((int) ((x) < 0.0f ? (x) - 0.5f : (x) + 0.5f)) typedef enum { CLUTTER_ACTOR_UNUSED_FLAG = 0, CLUTTER_IN_DESTRUCTION = 1 << 0, CLUTTER_IS_TOPLEVEL = 1 << 1, CLUTTER_IN_REPARENT = 1 << 2, /* Used to avoid recursion */ CLUTTER_IN_PAINT = 1 << 3, /* Used to avoid recursion */ CLUTTER_IN_RELAYOUT = 1 << 4, /* a flag for internal children of Containers (DEPRECATED) */ CLUTTER_INTERNAL_CHILD = 1 << 5 } ClutterPrivateFlags; /* * ClutterMainContext: * * The shared state of Clutter */ struct _ClutterMainContext { /* the main windowing system backend */ ClutterBackend *backend; /* the object holding all the stage instances */ ClutterStageManager *stage_manager; /* the clock driving all the frame operations */ ClutterMasterClock *master_clock; /* the main event queue */ GQueue *events_queue; /* the event filters added via clutter_event_add_filter. these are * ordered from least recently added to most recently added */ GList *event_filters; ClutterPickMode pick_mode; /* default FPS; this is only used if we cannot sync to vblank */ guint frame_rate; /* actors with a grab on all devices */ ClutterActor *pointer_grab_actor; ClutterActor *keyboard_grab_actor; /* stack of actors with shaders during paint */ GSList *shaders; /* fb bit masks for col<->id mapping in picking */ gint fb_r_mask; gint fb_g_mask; gint fb_b_mask; gint fb_r_mask_used; gint fb_g_mask_used; gint fb_b_mask_used; CoglPangoFontMap *font_map; /* Global font map */ /* stack of #ClutterEvent */ GSList *current_event; /* list of repaint functions installed through * clutter_threads_add_repaint_func() */ GList *repaint_funcs; guint last_repaint_id; /* main settings singleton */ ClutterSettings *settings; /* boolean flags */ guint is_initialized : 1; guint motion_events_per_actor : 1; guint defer_display_setup : 1; guint options_parsed : 1; guint show_fps : 1; }; /* shared between clutter-main.c and clutter-frame-source.c */ typedef struct { GSourceFunc func; gpointer data; GDestroyNotify notify; } ClutterThreadsDispatch; gboolean _clutter_threads_dispatch (gpointer data); void _clutter_threads_dispatch_free (gpointer data); void _clutter_threads_acquire_lock (void); void _clutter_threads_release_lock (void); ClutterMainContext * _clutter_context_get_default (void); void _clutter_context_lock (void); void _clutter_context_unlock (void); gboolean _clutter_context_is_initialized (void); ClutterPickMode _clutter_context_get_pick_mode (void); void _clutter_context_push_shader_stack (ClutterActor *actor); ClutterActor * _clutter_context_pop_shader_stack (ClutterActor *actor); ClutterActor * _clutter_context_peek_shader_stack (void); gboolean _clutter_context_get_motion_events_enabled (void); gboolean _clutter_context_get_show_fps (void); gboolean _clutter_feature_init (GError **error); /* Diagnostic mode */ gboolean _clutter_diagnostic_enabled (void); void _clutter_diagnostic_message (const char *fmt, ...); /* Picking code */ guint _clutter_pixel_to_id (guchar pixel[4]); void _clutter_id_to_color (guint id, ClutterColor *col); /* use this function as the accumulator if you have a signal with * a G_TYPE_BOOLEAN return value; this will stop the emission as * soon as one handler returns TRUE */ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer dummy); /* use this function as the accumulator if you have a signal with * a G_TYPE_BOOLEAN return value; this will stop the emission as * soon as one handler returns FALSE */ gboolean _clutter_boolean_continue_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer dummy); void _clutter_run_repaint_functions (ClutterRepaintFlags flags); GType _clutter_layout_manager_get_child_meta_type (ClutterLayoutManager *manager); void _clutter_util_fully_transform_vertices (const CoglMatrix *modelview, const CoglMatrix *projection, const float *viewport, const ClutterVertex *vertices_in, ClutterVertex *vertices_out, int n_vertices); void _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1, const cairo_rectangle_int_t *src2, cairo_rectangle_int_t *dest); gboolean _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1, const cairo_rectangle_int_t *src2, cairo_rectangle_int_t *dest); struct _ClutterVertex4 { float x; float y; float z; float w; }; void _clutter_util_vertex4_interpolate (const ClutterVertex4 *a, const ClutterVertex4 *b, double progress, ClutterVertex4 *res); #define CLUTTER_MATRIX_INIT_IDENTITY { \ 1.0f, 0.0f, 0.0f, 0.0f, \ 0.0f, 1.0f, 0.0f, 0.0f, \ 0.0f, 0.0f, 1.0f, 0.0f, \ 0.0f, 0.0f, 0.0f, 1.0f, \ } float _clutter_util_matrix_determinant (const ClutterMatrix *matrix); void _clutter_util_matrix_skew_xy (ClutterMatrix *matrix, float factor); void _clutter_util_matrix_skew_xz (ClutterMatrix *matrix, float factor); void _clutter_util_matrix_skew_yz (ClutterMatrix *matrix, float factor); gboolean _clutter_util_matrix_decompose (const ClutterMatrix *src, ClutterVertex *scale_p, float shear_p[3], ClutterVertex *rotate_p, ClutterVertex *translate_p, ClutterVertex4 *perspective_p); typedef struct _ClutterPlane { float v0[3]; float n[3]; } ClutterPlane; typedef enum _ClutterCullResult { CLUTTER_CULL_RESULT_UNKNOWN, CLUTTER_CULL_RESULT_IN, CLUTTER_CULL_RESULT_OUT, CLUTTER_CULL_RESULT_PARTIAL } ClutterCullResult; gboolean _clutter_has_progress_function (GType gtype); gboolean _clutter_run_progress_function (GType gtype, const GValue *initial, const GValue *final, gdouble progress, GValue *retval); G_END_DECLS #endif /* __CLUTTER_PRIVATE_H__ */ �����������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-actor-box.c����������������������������������������������������0000664�0001750�0001750�00000035102�14211404421�022023� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include <math.h> #include "clutter-types.h" #include "clutter-interval.h" #include "clutter-private.h" #include "clutter-actor-box-private.h" /** * clutter_actor_box_new: * @x_1: X coordinate of the top left point * @y_1: Y coordinate of the top left point * @x_2: X coordinate of the bottom right point * @y_2: Y coordinate of the bottom right point * * Allocates a new #ClutterActorBox using the passed coordinates * for the top left and bottom right points. * * This function is the logical equivalent of: * * |[ * clutter_actor_box_init (clutter_actor_box_alloc (), * x_1, y_1, * x_2, y_2); * ]| * * Return value: (transfer full): the newly allocated #ClutterActorBox. * Use clutter_actor_box_free() to free the resources * * Since: 1.0 */ ClutterActorBox * clutter_actor_box_new (gfloat x_1, gfloat y_1, gfloat x_2, gfloat y_2) { return clutter_actor_box_init (clutter_actor_box_alloc (), x_1, y_1, x_2, y_2); } /** * clutter_actor_box_alloc: * * Allocates a new #ClutterActorBox. * * Return value: (transfer full): the newly allocated #ClutterActorBox. * Use clutter_actor_box_free() to free its resources * * Since: 1.12 */ ClutterActorBox * clutter_actor_box_alloc (void) { return g_slice_new0 (ClutterActorBox); } /** * clutter_actor_box_init: * @box: a #ClutterActorBox * @x_1: X coordinate of the top left point * @y_1: Y coordinate of the top left point * @x_2: X coordinate of the bottom right point * @y_2: Y coordinate of the bottom right point * * Initializes @box with the given coordinates. * * Return value: (transfer none): the initialized #ClutterActorBox * * Since: 1.10 */ ClutterActorBox * clutter_actor_box_init (ClutterActorBox *box, gfloat x_1, gfloat y_1, gfloat x_2, gfloat y_2) { g_return_val_if_fail (box != NULL, NULL); box->x1 = x_1; box->y1 = y_1; box->x2 = x_2; box->y2 = y_2; return box; } /** * clutter_actor_box_init_rect: * @box: a #ClutterActorBox * @x: X coordinate of the origin * @y: Y coordinate of the origin * @width: width of the box * @height: height of the box * * Initializes @box with the given origin and size. * * Since: 1.10 */ void clutter_actor_box_init_rect (ClutterActorBox *box, gfloat x, gfloat y, gfloat width, gfloat height) { g_return_if_fail (box != NULL); box->x1 = x; box->y1 = y; box->x2 = box->x1 + width; box->y2 = box->y1 + height; } /** * clutter_actor_box_copy: * @box: a #ClutterActorBox * * Copies @box * * Return value: a newly allocated copy of #ClutterActorBox. Use * clutter_actor_box_free() to free the allocated resources * * Since: 1.0 */ ClutterActorBox * clutter_actor_box_copy (const ClutterActorBox *box) { if (G_LIKELY (box != NULL)) return g_slice_dup (ClutterActorBox, box); return NULL; } /** * clutter_actor_box_free: * @box: a #ClutterActorBox * * Frees a #ClutterActorBox allocated using clutter_actor_box_new() * or clutter_actor_box_copy() * * Since: 1.0 */ void clutter_actor_box_free (ClutterActorBox *box) { if (G_LIKELY (box != NULL)) g_slice_free (ClutterActorBox, box); } /** * clutter_actor_box_equal: * @box_a: a #ClutterActorBox * @box_b: a #ClutterActorBox * * Checks @box_a and @box_b for equality * * Return value: %TRUE if the passed #ClutterActorBox are equal * * Since: 1.0 */ gboolean clutter_actor_box_equal (const ClutterActorBox *box_a, const ClutterActorBox *box_b) { g_return_val_if_fail (box_a != NULL && box_b != NULL, FALSE); if (box_a == box_b) return TRUE; return box_a->x1 == box_b->x1 && box_a->y1 == box_b->y1 && box_a->x2 == box_b->x2 && box_a->y2 == box_b->y2; } /** * clutter_actor_box_get_x: * @box: a #ClutterActorBox * * Retrieves the X coordinate of the origin of @box * * Return value: the X coordinate of the origin * * Since: 1.0 */ gfloat clutter_actor_box_get_x (const ClutterActorBox *box) { g_return_val_if_fail (box != NULL, 0.); return box->x1; } /** * clutter_actor_box_get_y: * @box: a #ClutterActorBox * * Retrieves the Y coordinate of the origin of @box * * Return value: the Y coordinate of the origin * * Since: 1.0 */ gfloat clutter_actor_box_get_y (const ClutterActorBox *box) { g_return_val_if_fail (box != NULL, 0.); return box->y1; } /** * clutter_actor_box_get_width: * @box: a #ClutterActorBox * * Retrieves the width of the @box * * Return value: the width of the box * * Since: 1.0 */ gfloat clutter_actor_box_get_width (const ClutterActorBox *box) { g_return_val_if_fail (box != NULL, 0.); return box->x2 - box->x1; } /** * clutter_actor_box_get_height: * @box: a #ClutterActorBox * * Retrieves the height of the @box * * Return value: the height of the box * * Since: 1.0 */ gfloat clutter_actor_box_get_height (const ClutterActorBox *box) { g_return_val_if_fail (box != NULL, 0.); return box->y2 - box->y1; } /** * clutter_actor_box_get_origin: * @box: a #ClutterActorBox * @x: (out) (allow-none): return location for the X coordinate, or %NULL * @y: (out) (allow-none): return location for the Y coordinate, or %NULL * * Retrieves the origin of @box * * Since: 1.0 */ void clutter_actor_box_get_origin (const ClutterActorBox *box, gfloat *x, gfloat *y) { g_return_if_fail (box != NULL); if (x) *x = box->x1; if (y) *y = box->y1; } /** * clutter_actor_box_get_size: * @box: a #ClutterActorBox * @width: (out) (allow-none): return location for the width, or %NULL * @height: (out) (allow-none): return location for the height, or %NULL * * Retrieves the size of @box * * Since: 1.0 */ void clutter_actor_box_get_size (const ClutterActorBox *box, gfloat *width, gfloat *height) { g_return_if_fail (box != NULL); if (width) *width = box->x2 - box->x1; if (height) *height = box->y2 - box->y1; } /** * clutter_actor_box_get_area: * @box: a #ClutterActorBox * * Retrieves the area of @box * * Return value: the area of a #ClutterActorBox, in pixels * * Since: 1.0 */ gfloat clutter_actor_box_get_area (const ClutterActorBox *box) { g_return_val_if_fail (box != NULL, 0.); return (box->x2 - box->x1) * (box->y2 - box->y1); } /** * clutter_actor_box_contains: * @box: a #ClutterActorBox * @x: X coordinate of the point * @y: Y coordinate of the point * * Checks whether a point with @x, @y coordinates is contained * withing @box * * Return value: %TRUE if the point is contained by the #ClutterActorBox * * Since: 1.0 */ gboolean clutter_actor_box_contains (const ClutterActorBox *box, gfloat x, gfloat y) { g_return_val_if_fail (box != NULL, FALSE); return (x > box->x1 && x < box->x2) && (y > box->y1 && y < box->y2); } /** * clutter_actor_box_from_vertices: * @box: a #ClutterActorBox * @verts: (array fixed-size=4): array of four #ClutterVertex * * Calculates the bounding box represented by the four vertices; for details * of the vertex array see clutter_actor_get_abs_allocation_vertices(). * * Since: 1.0 */ void clutter_actor_box_from_vertices (ClutterActorBox *box, const ClutterVertex verts[]) { gfloat x_1, x_2, y_1, y_2; g_return_if_fail (box != NULL); g_return_if_fail (verts != NULL); /* 4-way min/max */ x_1 = verts[0].x; y_1 = verts[0].y; if (verts[1].x < x_1) x_1 = verts[1].x; if (verts[2].x < x_1) x_1 = verts[2].x; if (verts[3].x < x_1) x_1 = verts[3].x; if (verts[1].y < y_1) y_1 = verts[1].y; if (verts[2].y < y_1) y_1 = verts[2].y; if (verts[3].y < y_1) y_1 = verts[3].y; x_2 = verts[0].x; y_2 = verts[0].y; if (verts[1].x > x_2) x_2 = verts[1].x; if (verts[2].x > x_2) x_2 = verts[2].x; if (verts[3].x > x_2) x_2 = verts[3].x; if (verts[1].y > y_2) y_2 = verts[1].y; if (verts[2].y > y_2) y_2 = verts[2].y; if (verts[3].y > y_2) y_2 = verts[3].y; box->x1 = x_1; box->x2 = x_2; box->y1 = y_1; box->y2 = y_2; } /** * clutter_actor_box_interpolate: * @initial: the initial #ClutterActorBox * @final: the final #ClutterActorBox * @progress: the interpolation progress * @result: (out): return location for the interpolation * * Interpolates between @initial and @final #ClutterActorBox<!-- -->es * using @progress * * Since: 1.2 */ void clutter_actor_box_interpolate (const ClutterActorBox *initial, const ClutterActorBox *final, gdouble progress, ClutterActorBox *result) { g_return_if_fail (initial != NULL); g_return_if_fail (final != NULL); g_return_if_fail (result != NULL); result->x1 = initial->x1 + (final->x1 - initial->x1) * progress; result->y1 = initial->y1 + (final->y1 - initial->y1) * progress; result->x2 = initial->x2 + (final->x2 - initial->x2) * progress; result->y2 = initial->y2 + (final->y2 - initial->y2) * progress; } /** * clutter_actor_box_clamp_to_pixel: * @box: (inout): the #ClutterActorBox to clamp * * Clamps the components of @box to the nearest integer * * Since: 1.2 */ void clutter_actor_box_clamp_to_pixel (ClutterActorBox *box) { g_return_if_fail (box != NULL); box->x1 = floorf (box->x1); box->y1 = floorf (box->y1); box->x2 = ceilf (box->x2); box->y2 = ceilf (box->y2); } /** * clutter_actor_box_union: * @a: (in): the first #ClutterActorBox * @b: (in): the second #ClutterActorBox * @result: (out): the #ClutterActorBox representing a union * of @a and @b * * Unions the two boxes @a and @b and stores the result in @result. * * Since: 1.4 */ void clutter_actor_box_union (const ClutterActorBox *a, const ClutterActorBox *b, ClutterActorBox *result) { g_return_if_fail (a != NULL); g_return_if_fail (b != NULL); g_return_if_fail (result != NULL); result->x1 = MIN (a->x1, b->x1); result->y1 = MIN (a->y1, b->y1); result->x2 = MAX (a->x2, b->x2); result->y2 = MAX (a->y2, b->y2); } static gboolean clutter_actor_box_progress (const GValue *a, const GValue *b, gdouble factor, GValue *retval) { ClutterActorBox res = { 0, }; clutter_actor_box_interpolate (g_value_get_boxed (a), g_value_get_boxed (b), factor, &res); g_value_set_boxed (retval, &res); return TRUE; } /** * clutter_actor_box_set_origin: * @box: a #ClutterActorBox * @x: the X coordinate of the new origin * @y: the Y coordinate of the new origin * * Changes the origin of @box, maintaining the size of the #ClutterActorBox. * * Since: 1.6 */ void clutter_actor_box_set_origin (ClutterActorBox *box, gfloat x, gfloat y) { gfloat width, height; g_return_if_fail (box != NULL); width = box->x2 - box->x1; height = box->y2 - box->y1; clutter_actor_box_init_rect (box, x, y, width, height); } /** * clutter_actor_box_set_size: * @box: a #ClutterActorBox * @width: the new width * @height: the new height * * Sets the size of @box, maintaining the origin of the #ClutterActorBox. * * Since: 1.6 */ void clutter_actor_box_set_size (ClutterActorBox *box, gfloat width, gfloat height) { g_return_if_fail (box != NULL); box->x2 = box->x1 + width; box->y2 = box->y1 + height; } void _clutter_actor_box_enlarge_for_effects (ClutterActorBox *box) { float width, height; /* The aim here is that for a given rectangle defined with floating point * coordinates we want to determine a stable quantized size in pixels * that doesn't vary due to the original box's sub-pixel position. * * The reason this is important is because effects will use this * API to determine the size of offscreen framebuffers and so for * a fixed-size object that may be animated accross the screen we * want to make sure that the stage paint-box has an equally stable * size so that effects aren't made to continuously re-allocate * a corresponding fbo. * * The other thing we consider is that the calculation of this box is * subject to floating point precision issues that might be slightly * different to the precision issues involved with actually painting the * actor, which might result in painting slightly leaking outside the * user's calculated paint-volume. For this we simply aim to pad out the * paint-volume by at least half a pixel all the way around. */ width = box->x2 - box->x1; height = box->y2 - box->y1; width = CLUTTER_NEARBYINT (width); height = CLUTTER_NEARBYINT (height); /* XXX: NB the width/height may now be up to 0.5px too small so we * must also pad by 0.25px all around to account for this. In total we * must padd by at least 0.75px around all sides. */ /* XXX: The furthest that we can overshoot the bottom right corner by * here is 1.75px in total if you consider that the 0.75 padding could * just cross an integer boundary and so ceil will effectively add 1. */ box->x2 = ceilf (box->x2 + 0.75); box->y2 = ceilf (box->y2 + 0.75); /* Now we redefine the top-left relative to the bottom right based on the * rounded width/height determined above + a constant so that the overall * size of the box will be stable and not dependant on the box's * position. * * Adding 3px to the width/height will ensure we cover the maximum of * 1.75px padding on the bottom/right and still ensure we have > 0.75px * padding on the top/left. */ box->x1 = box->x2 - width - 3; box->y1 = box->y2 - height - 3; } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterActorBox, clutter_actor_box, clutter_actor_box_copy, clutter_actor_box_free, CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_actor_box_progress)); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-fixed-layout.h�������������������������������������������������0000664�0001750�0001750�00000005234�14211404421�022547� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Emmanuele Bassi <ebassi@linux.intel.com> */ #ifndef __CLUTTER_FIXED_LAYOUT_H__ #define __CLUTTER_FIXED_LAYOUT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <clutter/clutter-layout-manager.h> G_BEGIN_DECLS #define CLUTTER_TYPE_FIXED_LAYOUT (clutter_fixed_layout_get_type ()) #define CLUTTER_FIXED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_FIXED_LAYOUT, ClutterFixedLayout)) #define CLUTTER_IS_FIXED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_FIXED_LAYOUT)) #define CLUTTER_FIXED_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_FIXED_LAYOUT, ClutterFixedLayoutClass)) #define CLUTTER_IS_FIXED_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_FIXED_LAYOUT)) #define CLUTTER_FIXED_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_FIXED_LAYOUT, ClutterFixedLayoutClass)) typedef struct _ClutterFixedLayout ClutterFixedLayout; typedef struct _ClutterFixedLayoutClass ClutterFixedLayoutClass; /** * ClutterFixedLayout: * * The #ClutterFixedLayout structure contains only private data and * it should be accessed using the provided API * * Since: 1.2 */ struct _ClutterFixedLayout { /*< private >*/ ClutterLayoutManager parent_instance; }; /** * ClutterFixedLayoutClass: * * The #ClutterFixedLayoutClass structure contains only private data * and it should be accessed using the provided API * * Since: 1.2 */ struct _ClutterFixedLayoutClass { /*< private >*/ ClutterLayoutManagerClass parent_class; }; CLUTTER_AVAILABLE_IN_1_2 GType clutter_fixed_layout_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 ClutterLayoutManager *clutter_fixed_layout_new (void); G_END_DECLS #endif /* __CLUTTER_FIXED_LAYOUT_H__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-swipe-action.c�������������������������������������������������0000664�0001750�0001750�00000020266�14211404421�022534� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. * * 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, see <http://www.gnu.org/licenses/>. * * Author: * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> * * Based on ClutterDragAction, written by: * Emmanuele Bassi <ebassi@linux.intel.com> */ /** * SECTION:clutter-swipe-action * @Title: ClutterSwipeAction * @Short_Description: Action for swipe gestures * * #ClutterSwipeAction is a sub-class of #ClutterGestureAction that implements * the logic for recognizing swipe gestures. * * Since: 1.8 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-swipe-action.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-gesture-action-private.h" #include "clutter-marshal.h" #include "clutter-private.h" struct _ClutterSwipeActionPrivate { ClutterSwipeDirection h_direction; ClutterSwipeDirection v_direction; float distance_x, distance_y; }; enum { SWEPT, SWIPE, LAST_SIGNAL }; static guint swipe_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterSwipeAction, clutter_swipe_action, CLUTTER_TYPE_GESTURE_ACTION) static gboolean gesture_begin (ClutterGestureAction *action, ClutterActor *actor) { ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv; /* reset the state at the beginning of a new gesture */ priv->h_direction = 0; priv->v_direction = 0; g_object_get (action, "threshold-trigger-distance-x", &priv->distance_x, "threshold-trigger-distance-y", &priv->distance_y, NULL); return TRUE; } static gboolean gesture_progress (ClutterGestureAction *action, ClutterActor *actor) { ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv; gfloat press_x, press_y; gfloat motion_x, motion_y; gfloat delta_x, delta_y; ClutterSwipeDirection h_direction = 0, v_direction = 0; clutter_gesture_action_get_press_coords (action, 0, &press_x, &press_y); clutter_gesture_action_get_motion_coords (action, 0, &motion_x, &motion_y); delta_x = press_x - motion_x; delta_y = press_y - motion_y; if (delta_x >= priv->distance_x) h_direction = CLUTTER_SWIPE_DIRECTION_RIGHT; else if (delta_x < -priv->distance_x) h_direction = CLUTTER_SWIPE_DIRECTION_LEFT; if (delta_y >= priv->distance_y) v_direction = CLUTTER_SWIPE_DIRECTION_DOWN; else if (delta_y < -priv->distance_y) v_direction = CLUTTER_SWIPE_DIRECTION_UP; /* cancel gesture on direction reversal */ if (priv->h_direction == 0) priv->h_direction = h_direction; if (priv->v_direction == 0) priv->v_direction = v_direction; if (priv->h_direction != h_direction) return FALSE; if (priv->v_direction != v_direction) return FALSE; return TRUE; } static void gesture_end (ClutterGestureAction *action, ClutterActor *actor) { ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv; gfloat press_x, press_y; gfloat release_x, release_y; ClutterSwipeDirection direction = 0; gboolean can_emit_swipe; const ClutterEvent *last_event; clutter_gesture_action_get_press_coords (action, 0, &press_x, &press_y); /* Check the last event instead of get_release_coords(), this * might not be the sequence that finished on multi-finger swipes. */ last_event = clutter_gesture_action_get_last_event (action, 0); clutter_event_get_coords (last_event, &release_x, &release_y); if (release_x - press_x > priv->distance_x) direction |= CLUTTER_SWIPE_DIRECTION_RIGHT; else if (press_x - release_x > priv->distance_x) direction |= CLUTTER_SWIPE_DIRECTION_LEFT; if (release_y - press_y > priv->distance_y) direction |= CLUTTER_SWIPE_DIRECTION_DOWN; else if (press_y - release_y > priv->distance_y) direction |= CLUTTER_SWIPE_DIRECTION_UP; /* XXX:2.0 remove */ g_signal_emit (action, swipe_signals[SWIPE], 0, actor, direction, &can_emit_swipe); if (can_emit_swipe) g_signal_emit (action, swipe_signals[SWEPT], 0, actor, direction); } /* XXX:2.0 remove */ static gboolean clutter_swipe_action_real_swipe (ClutterSwipeAction *action, ClutterActor *actor, ClutterSwipeDirection direction) { return TRUE; } static void clutter_swipe_action_constructed (GObject *object) { clutter_gesture_action_set_threshold_trigger_edge (CLUTTER_GESTURE_ACTION (object), CLUTTER_GESTURE_TRIGGER_EDGE_AFTER); } static void clutter_swipe_action_class_init (ClutterSwipeActionClass *klass) { ClutterGestureActionClass *gesture_class = CLUTTER_GESTURE_ACTION_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = clutter_swipe_action_constructed; gesture_class->gesture_begin = gesture_begin; gesture_class->gesture_progress = gesture_progress; gesture_class->gesture_end = gesture_end; /* XXX:2.0 remove */ klass->swipe = clutter_swipe_action_real_swipe; /** * ClutterSwipeAction::swept: * @action: the #ClutterSwipeAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @direction: the main direction of the swipe gesture * * The ::swept signal is emitted when a swipe gesture is recognized on the * attached actor. * * Deprecated: 1.14: Use the ::swipe signal instead. * * Since: 1.8 */ swipe_signals[SWEPT] = g_signal_new (I_("swept"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DEPRECATED, G_STRUCT_OFFSET (ClutterSwipeActionClass, swept), NULL, NULL, _clutter_marshal_VOID__OBJECT_FLAGS, G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR, CLUTTER_TYPE_SWIPE_DIRECTION); /** * ClutterSwipeAction::swipe: * @action: the #ClutterSwipeAction that emitted the signal * @actor: the #ClutterActor attached to the @action * @direction: the main direction of the swipe gesture * * The ::swipe signal is emitted when a swipe gesture is recognized on the * attached actor. * * Return value: %TRUE if the swipe should continue, and %FALSE if * the swipe should be cancelled. * * Since: 1.14 */ swipe_signals[SWIPE] = g_signal_new (I_("swipe"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterSwipeActionClass, swipe), _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT_FLAGS, G_TYPE_BOOLEAN, 2, CLUTTER_TYPE_ACTOR, CLUTTER_TYPE_SWIPE_DIRECTION); } static void clutter_swipe_action_init (ClutterSwipeAction *self) { self->priv = clutter_swipe_action_get_instance_private (self); } /** * clutter_swipe_action_new: * * Creates a new #ClutterSwipeAction instance * * Return value: the newly created #ClutterSwipeAction * * Since: 1.8 */ ClutterAction * clutter_swipe_action_new (void) { return g_object_new (CLUTTER_TYPE_SWIPE_ACTION, NULL); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������muffin-5.2.1/clutter/clutter/clutter-enums.h��������������������������������������������������������0000664�0001750�0001750�00000150577�14211404421�021277� 0����������������������������������������������������������������������������������������������������ustar �jpeisach������������������������jpeisach���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation * * 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, see <http://www.gnu.org/licenses/>. */ #ifndef __CLUTTER_ENUMS_H__ #define __CLUTTER_ENUMS_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only <clutter/clutter.h> can be included directly." #endif #include <glib-object.h> G_BEGIN_DECLS /** * ClutterGravity: * @CLUTTER_GRAVITY_NONE: Do not apply any gravity * @CLUTTER_GRAVITY_NORTH: Scale from topmost downwards * @CLUTTER_GRAVITY_NORTH_EAST: Scale from the top right corner * @CLUTTER_GRAVITY_EAST: Scale from the right side * @CLUTTER_GRAVITY_SOUTH_EAST: Scale from the bottom right corner * @CLUTTER_GRAVITY_SOUTH: Scale from the bottom upwards * @CLUTTER_GRAVITY_SOUTH_WEST: Scale from the bottom left corner * @CLUTTER_GRAVITY_WEST: Scale from the left side * @CLUTTER_GRAVITY_NORTH_WEST: Scale from the top left corner * @CLUTTER_GRAVITY_CENTER: Scale from the center. * * Gravity of the scaling operations. When a gravity different than * %CLUTTER_GRAVITY_NONE is used, an actor is scaled keeping the position * of the specified portion at the same coordinates. * * Since: 0.2 * * Deprecated: 1.22: Use the normalized #ClutterActor pivot point instead */ typedef enum { /*< prefix=CLUTTER_GRAVITY >*/ CLUTTER_GRAVITY_NONE = 0, CLUTTER_GRAVITY_NORTH, CLUTTER_GRAVITY_NORTH_EAST, CLUTTER_GRAVITY_EAST, CLUTTER_GRAVITY_SOUTH_EAST, CLUTTER_GRAVITY_SOUTH, CLUTTER_GRAVITY_SOUTH_WEST, CLUTTER_GRAVITY_WEST, CLUTTER_GRAVITY_NORTH_WEST, CLUTTER_GRAVITY_CENTER } ClutterGravity; /** * ClutterRotateAxis: * @CLUTTER_X_AXIS: Rotate around the X axis * @CLUTTER_Y_AXIS: Rotate around the Y axis * @CLUTTER_Z_AXIS: Rotate around the Z axis * * Axis of a rotation. * * Since: 0.4 */ typedef enum { /*< prefix=CLUTTER >*/ CLUTTER_X_AXIS, CLUTTER_Y_AXIS, CLUTTER_Z_AXIS } ClutterRotateAxis; /** * ClutterRotateDirection: * @CLUTTER_ROTATE_CW: Clockwise rotation * @CLUTTER_ROTATE_CCW: Counter-clockwise rotation * * Direction of a rotation. * * Since: 0.4 * * Deprecated: 1.22 */ typedef enum { /*< prefix=CLUTTER_ROTATE >*/ CLUTTER_ROTATE_CW, CLUTTER_ROTATE_CCW } ClutterRotateDirection; /** * ClutterRequestMode: * @CLUTTER_REQUEST_HEIGHT_FOR_WIDTH: Height for width requests * @CLUTTER_REQUEST_WIDTH_FOR_HEIGHT: Width for height requests * @CLUTTER_REQUEST_CONTENT_SIZE: Use the preferred size of the * #ClutterContent, if it has any (available since 1.22) * * Specifies the type of requests for a #ClutterActor. * * Since: 0.8 */ typedef enum { /*< prefix=CLUTTER_REQUEST >*/ CLUTTER_REQUEST_HEIGHT_FOR_WIDTH, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT, CLUTTER_REQUEST_CONTENT_SIZE } ClutterRequestMode; /** * ClutterAnimationMode: * @CLUTTER_CUSTOM_MODE: custom progress function * @CLUTTER_LINEAR: linear tweening * @CLUTTER_EASE_IN_QUAD: quadratic tweening * @CLUTTER_EASE_OUT_QUAD: quadratic tweening, inverse of * %CLUTTER_EASE_IN_QUAD * @CLUTTER_EASE_IN_OUT_QUAD: quadratic tweening, combininig * %CLUTTER_EASE_IN_QUAD and %CLUTTER_EASE_OUT_QUAD * @CLUTTER_EASE_IN_CUBIC: cubic tweening * @CLUTTER_EASE_OUT_CUBIC: cubic tweening, invers of * %CLUTTER_EASE_IN_CUBIC * @CLUTTER_EASE_IN_OUT_CUBIC: cubic tweening, combining * %CLUTTER_EASE_IN_CUBIC and %CLUTTER_EASE_OUT_CUBIC * @CLUTTER_EASE_IN_QUART: quartic tweening * @CLUTTER_EASE_OUT_QUART: quartic tweening, inverse of * %CLUTTER_EASE_IN_QUART * @CLUTTER_EASE_IN_OUT_QUART: quartic tweening, combining * %CLUTTER_EASE_IN_QUART and %CLUTTER_EASE_OUT_QUART * @CLUTTER_EASE_IN_QUINT: quintic tweening * @CLUTTER_EASE_OUT_QUINT: quintic tweening, inverse of * %CLUTTER_EASE_IN_QUINT * @CLUTTER_EASE_IN_OUT_QUINT: fifth power tweening, combining * %CLUTTER_EASE_IN_QUINT and %CLUTTER_EASE_OUT_QUINT * @CLUTTER_EASE_IN_SINE: sinusoidal tweening * @CLUTTER_EASE_OUT_SINE: sinusoidal tweening, inverse of * %CLUTTER_EASE_IN_SINE * @CLUTTER_EASE_IN_OUT_SINE: sine wave tweening, combining * %CLUTTER_EASE_IN_SINE and %CLUTTER_EASE_OUT_SINE * @CLUTTER_EASE_IN_EXPO: exponential tweening * @CLUTTER_EASE_OUT_EXPO: exponential tweening, inverse of * %CLUTTER_EASE_IN_EXPO * @CLUTTER_EASE_IN_OUT_EXPO: exponential tweening, combining * %CLUTTER_EASE_IN_EXPO and %CLUTTER_EASE_OUT_EXPO * @CLUTTER_EASE_IN_CIRC: circular tweening * @CLUTTER_EASE_OUT_CIRC: circular tweening, inverse of * %CLUTTER_EASE_IN_CIRC * @CLUTTER_EASE_IN_OUT_CIRC: circular tweening, combining * %CLUTTER_EASE_IN_CIRC and %CLUTTER_EASE_OUT_CIRC * @CLUTTER_EASE_IN_ELASTIC: elastic tweening, with offshoot on start * @CLUTTER_EASE_OUT_ELASTIC: elastic tweening, with offshoot on end * @CLUTTER_EASE_IN_OUT_ELASTIC: elastic tweening with offshoot on both ends * @CLUTTER_EASE_IN_BACK: overshooting cubic tweening, with * backtracking on start * @CLUTTER_EASE_OUT_BACK: overshooting cubic tweening, with * backtracking on end * @CLUTTER_EASE_IN_OUT_BACK: overshooting cubic tweening, with * backtracking on both ends * @CLUTTER_EASE_IN_BOUNCE: exponentially decaying parabolic (bounce) * tweening, with bounce on start * @CLUTTER_EASE_OUT_BOUNCE: exponentially decaying parabolic (bounce) * tweening, with bounce on end * @CLUTTER_EASE_IN_OUT_BOUNCE: exponentially decaying parabolic (bounce) * tweening, with bounce on both ends * @CLUTTER_STEPS: parametrized step function; see clutter_timeline_set_step_progress() * for further details. (Since 1.12) * @CLUTTER_STEP_START: equivalent to %CLUTTER_STEPS with a number of steps * equal to 1, and a step mode of %CLUTTER_STEP_MODE_START. (Since 1.12) * @CLUTTER_STEP_END: equivalent to %CLUTTER_STEPS with a number of steps * equal to 1, and a step mode of %CLUTTER_STEP_MODE_END. (Since 1.12) * @CLUTTER_CUBIC_BEZIER: cubic bezier between (0, 0) and (1, 1) with two * control points; see clutter_timeline_set_cubic_bezier_progress(). (Since 1.12) * @CLUTTER_EASE: equivalent to %CLUTTER_CUBIC_BEZIER with control points * in (0.25, 0.1) and (0.25, 1.0). (Since 1.12) * @CLUTTER_EASE_IN: equivalent to %CLUTTER_CUBIC_BEZIER with control points * in (0.42, 0) and (1.0, 1.0). (Since 1.12) * @CLUTTER_EASE_OUT: equivalent to %CLUTTER_CUBIC_BEZIER with control points * in (0, 0) and (0.58, 1.0). (Since 1.12) * @CLUTTER_EASE_IN_OUT: equivalent to %CLUTTER_CUBIC_BEZIER with control points * in (0.42, 0) and (0.58, 1.0). (Since 1.12) * @CLUTTER_ANIMATION_LAST: last animation mode, used as a guard for * registered global alpha functions * * The animation modes used by #ClutterAlpha and #ClutterAnimation. This * enumeration can be expanded in later versions of Clutter. * * <figure id="easing-modes"> * <title>Easing modes provided by Clutter * * * * Every global alpha function registered using clutter_alpha_register_func() * or clutter_alpha_register_closure() will have a logical id greater than * %CLUTTER_ANIMATION_LAST. * * Since: 1.0 */ typedef enum { CLUTTER_CUSTOM_MODE = 0, /* linear */ CLUTTER_LINEAR, /* quadratic */ CLUTTER_EASE_IN_QUAD, CLUTTER_EASE_OUT_QUAD, CLUTTER_EASE_IN_OUT_QUAD, /* cubic */ CLUTTER_EASE_IN_CUBIC, CLUTTER_EASE_OUT_CUBIC, CLUTTER_EASE_IN_OUT_CUBIC, /* quartic */ CLUTTER_EASE_IN_QUART, CLUTTER_EASE_OUT_QUART, CLUTTER_EASE_IN_OUT_QUART, /* quintic */ CLUTTER_EASE_IN_QUINT, CLUTTER_EASE_OUT_QUINT, CLUTTER_EASE_IN_OUT_QUINT, /* sinusoidal */ CLUTTER_EASE_IN_SINE, CLUTTER_EASE_OUT_SINE, CLUTTER_EASE_IN_OUT_SINE, /* exponential */ CLUTTER_EASE_IN_EXPO, CLUTTER_EASE_OUT_EXPO, CLUTTER_EASE_IN_OUT_EXPO, /* circular */ CLUTTER_EASE_IN_CIRC, CLUTTER_EASE_OUT_CIRC, CLUTTER_EASE_IN_OUT_CIRC, /* elastic */ CLUTTER_EASE_IN_ELASTIC, CLUTTER_EASE_OUT_ELASTIC, CLUTTER_EASE_IN_OUT_ELASTIC, /* overshooting cubic */ CLUTTER_EASE_IN_BACK, CLUTTER_EASE_OUT_BACK, CLUTTER_EASE_IN_OUT_BACK, /* exponentially decaying parabolic */ CLUTTER_EASE_IN_BOUNCE, CLUTTER_EASE_OUT_BOUNCE, CLUTTER_EASE_IN_OUT_BOUNCE, /* step functions (see css3-transitions) */ CLUTTER_STEPS, CLUTTER_STEP_START, /* steps(1, start) */ CLUTTER_STEP_END, /* steps(1, end) */ /* cubic bezier (see css3-transitions) */ CLUTTER_CUBIC_BEZIER, CLUTTER_EASE, CLUTTER_EASE_IN, CLUTTER_EASE_OUT, CLUTTER_EASE_IN_OUT, /* guard, before registered alpha functions */ CLUTTER_ANIMATION_LAST } ClutterAnimationMode; /** * ClutterFontFlags: * @CLUTTER_FONT_MIPMAPPING: Set to use mipmaps for the glyph cache textures. * @CLUTTER_FONT_HINTING: Set to enable hinting on the glyphs. * * Runtime flags to change the font quality. To be used with * clutter_set_font_flags(). * * Since: 1.0 * * Deprecated: 1.22: Use #cairo_font_options_t instead */ typedef enum { /*< prefix=CLUTTER_FONT >*/ CLUTTER_FONT_MIPMAPPING = (1 << 0), CLUTTER_FONT_HINTING = (1 << 1) } ClutterFontFlags; /** * ClutterTextDirection: * @CLUTTER_TEXT_DIRECTION_DEFAULT: Use the default setting, as returned * by clutter_get_default_text_direction() * @CLUTTER_TEXT_DIRECTION_LTR: Use left-to-right text direction * @CLUTTER_TEXT_DIRECTION_RTL: Use right-to-left text direction * * The text direction to be used by #ClutterActors * * Since: 1.2 */ typedef enum { CLUTTER_TEXT_DIRECTION_DEFAULT, CLUTTER_TEXT_DIRECTION_LTR, CLUTTER_TEXT_DIRECTION_RTL } ClutterTextDirection; /** * ClutterShaderType: * @CLUTTER_VERTEX_SHADER: a vertex shader * @CLUTTER_FRAGMENT_SHADER: a fragment shader * * The type of GLSL shader program * * Since: 1.4 */ typedef enum { CLUTTER_VERTEX_SHADER, CLUTTER_FRAGMENT_SHADER } ClutterShaderType; /** * ClutterModifierType: * @CLUTTER_SHIFT_MASK: Mask applied by the Shift key * @CLUTTER_LOCK_MASK: Mask applied by the Caps Lock key * @CLUTTER_CONTROL_MASK: Mask applied by the Control key * @CLUTTER_MOD1_MASK: Mask applied by the first Mod key * @CLUTTER_MOD2_MASK: Mask applied by the second Mod key * @CLUTTER_MOD3_MASK: Mask applied by the third Mod key * @CLUTTER_MOD4_MASK: Mask applied by the fourth Mod key * @CLUTTER_MOD5_MASK: Mask applied by the fifth Mod key * @CLUTTER_BUTTON1_MASK: Mask applied by the first pointer button * @CLUTTER_BUTTON2_MASK: Mask applied by the second pointer button * @CLUTTER_BUTTON3_MASK: Mask applied by the third pointer button * @CLUTTER_BUTTON4_MASK: Mask applied by the fourth pointer button * @CLUTTER_BUTTON5_MASK: Mask applied by the fifth pointer button * @CLUTTER_SUPER_MASK: Mask applied by the Super key * @CLUTTER_HYPER_MASK: Mask applied by the Hyper key * @CLUTTER_META_MASK: Mask applied by the Meta key * @CLUTTER_RELEASE_MASK: Mask applied during release * @CLUTTER_MODIFIER_MASK: A mask covering all modifier types * * Masks applied to a #ClutterEvent by modifiers. * * Note that Clutter may add internal values to events which include * reserved values such as %CLUTTER_MODIFIER_RESERVED_13_MASK. Your code * should preserve and ignore them. You can use %CLUTTER_MODIFIER_MASK to * remove all reserved values. * * Since: 0.4 */ typedef enum { CLUTTER_SHIFT_MASK = 1 << 0, CLUTTER_LOCK_MASK = 1 << 1, CLUTTER_CONTROL_MASK = 1 << 2, CLUTTER_MOD1_MASK = 1 << 3, CLUTTER_MOD2_MASK = 1 << 4, CLUTTER_MOD3_MASK = 1 << 5, CLUTTER_MOD4_MASK = 1 << 6, CLUTTER_MOD5_MASK = 1 << 7, CLUTTER_BUTTON1_MASK = 1 << 8, CLUTTER_BUTTON2_MASK = 1 << 9, CLUTTER_BUTTON3_MASK = 1 << 10, CLUTTER_BUTTON4_MASK = 1 << 11, CLUTTER_BUTTON5_MASK = 1 << 12, #ifndef __GTK_DOC_IGNORE__ CLUTTER_MODIFIER_RESERVED_13_MASK = 1 << 13, CLUTTER_MODIFIER_RESERVED_14_MASK = 1 << 14, CLUTTER_MODIFIER_RESERVED_15_MASK = 1 << 15, CLUTTER_MODIFIER_RESERVED_16_MASK = 1 << 16, CLUTTER_MODIFIER_RESERVED_17_MASK = 1 << 17, CLUTTER_MODIFIER_RESERVED_18_MASK = 1 << 18, CLUTTER_MODIFIER_RESERVED_19_MASK = 1 << 19, CLUTTER_MODIFIER_RESERVED_20_MASK = 1 << 20, CLUTTER_MODIFIER_RESERVED_21_MASK = 1 << 21, CLUTTER_MODIFIER_RESERVED_22_MASK = 1 << 22, CLUTTER_MODIFIER_RESERVED_23_MASK = 1 << 23, CLUTTER_MODIFIER_RESERVED_24_MASK = 1 << 24, CLUTTER_MODIFIER_RESERVED_25_MASK = 1 << 25, #endif CLUTTER_SUPER_MASK = 1 << 26, CLUTTER_HYPER_MASK = 1 << 27, CLUTTER_META_MASK = 1 << 28, #ifndef __GTK_DOC_IGNORE__ CLUTTER_MODIFIER_RESERVED_29_MASK = 1 << 29, #endif CLUTTER_RELEASE_MASK = 1 << 30, /* Combination of CLUTTER_SHIFT_MASK..CLUTTER_BUTTON5_MASK + CLUTTER_SUPER_MASK + CLUTTER_HYPER_MASK + CLUTTER_META_MASK + CLUTTER_RELEASE_MASK */ CLUTTER_MODIFIER_MASK = 0x5c001fff } ClutterModifierType; /** * ClutterKeyboardA11yFlags: * @CLUTTER_A11Y_KEYBOARD_ENABLED: * @CLUTTER_A11Y_TIMEOUT_ENABLED: * @CLUTTER_A11Y_MOUSE_KEYS_ENABLED: * @CLUTTER_A11Y_SLOW_KEYS_ENABLED: * @CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS: * @CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT: * @CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT: * @CLUTTER_A11Y_BOUNCE_KEYS_ENABLED: * @CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT: * @CLUTTER_A11Y_TOGGLE_KEYS_ENABLED: * @CLUTTER_A11Y_STICKY_KEYS_ENABLED: * @CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF: * @CLUTTER_A11Y_STICKY_KEYS_BEEP: * @CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP: * * Keyboard accessibility features applied to a ClutterInputDevice keyboard. * */ typedef enum { CLUTTER_A11Y_KEYBOARD_ENABLED = 1 << 0, CLUTTER_A11Y_TIMEOUT_ENABLED = 1 << 1, CLUTTER_A11Y_MOUSE_KEYS_ENABLED = 1 << 2, CLUTTER_A11Y_SLOW_KEYS_ENABLED = 1 << 3, CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS = 1 << 4, CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT = 1 << 5, CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT = 1 << 6, CLUTTER_A11Y_BOUNCE_KEYS_ENABLED = 1 << 7, CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT = 1 << 8, CLUTTER_A11Y_TOGGLE_KEYS_ENABLED = 1 << 9, CLUTTER_A11Y_STICKY_KEYS_ENABLED = 1 << 10, CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF = 1 << 11, CLUTTER_A11Y_STICKY_KEYS_BEEP = 1 << 12, CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13, } ClutterKeyboardA11yFlags; /** * ClutterActorFlags: * @CLUTTER_ACTOR_MAPPED: the actor will be painted (is visible, and inside * a toplevel, and all parents visible) * @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been * allocated * @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emmitting event * signals * @CLUTTER_ACTOR_VISIBLE: the actor has been shown by the application program * @CLUTTER_ACTOR_NO_LAYOUT: the actor provides an explicit layout management * policy for its children; this flag will prevent Clutter from automatic * queueing of relayout and will defer all layouting to the actor itself * * Flags used to signal the state of an actor. */ typedef enum { /*< prefix=CLUTTER_ACTOR >*/ CLUTTER_ACTOR_MAPPED = 1 << 1, CLUTTER_ACTOR_REALIZED = 1 << 2, CLUTTER_ACTOR_REACTIVE = 1 << 3, CLUTTER_ACTOR_VISIBLE = 1 << 4, CLUTTER_ACTOR_NO_LAYOUT = 1 << 5 } ClutterActorFlags; /** * ClutterOffscreenRedirect: * @CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY: Only redirect * the actor if it is semi-transparent and its has_overlaps() * virtual returns %TRUE. This is the default. * @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an * offscreen buffer even if it is fully opaque. * * Possible flags to pass to clutter_actor_set_offscreen_redirect(). * * Since: 1.8 */ typedef enum { /*< prefix=CLUTTER_OFFSCREEN_REDIRECT >*/ CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1<<0, CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1<<1 } ClutterOffscreenRedirect; /** * ClutterAllocationFlags: * @CLUTTER_ALLOCATION_NONE: No flag set * @CLUTTER_ABSOLUTE_ORIGIN_CHANGED: Whether the absolute origin of the * actor has changed; this implies that any ancestor of the actor has * been moved. * @CLUTTER_DELEGATE_LAYOUT: Whether the allocation should be delegated * to the #ClutterLayoutManager instance stored inside the * #ClutterActor:layout-manager property of #ClutterActor. This flag * should only be used if you are subclassing #ClutterActor and * overriding the #ClutterActorClass.allocate() virtual function, but * you wish to use the default implementation of the virtual function * inside #ClutterActor. Added in Clutter 1.10. * * Flags passed to the #ClutterActorClass.allocate() virtual function * and to the clutter_actor_allocate() function. * * Since: 1.0 */ typedef enum { CLUTTER_ALLOCATION_NONE = 0, CLUTTER_ABSOLUTE_ORIGIN_CHANGED = 1 << 1, CLUTTER_DELEGATE_LAYOUT = 1 << 2 } ClutterAllocationFlags; /** * ClutterAlignAxis: * @CLUTTER_ALIGN_X_AXIS: Maintain the alignment on the X axis * @CLUTTER_ALIGN_Y_AXIS: Maintain the alignment on the Y axis * @CLUTTER_ALIGN_BOTH: Maintain the alignment on both the X and Y axis * * Specifies the axis on which #ClutterAlignConstraint should maintain * the alignment. * * Since: 1.4 */ typedef enum { /*< prefix=CLUTTER_ALIGN >*/ CLUTTER_ALIGN_X_AXIS, CLUTTER_ALIGN_Y_AXIS, CLUTTER_ALIGN_BOTH } ClutterAlignAxis; /** * ClutterInterpolation: * @CLUTTER_INTERPOLATION_LINEAR: linear interpolation * @CLUTTER_INTERPOLATION_CUBIC: cubic interpolation * * The mode of interpolation between key frames * * Since: 1.2 * * Deprecated: 1.22 */ typedef enum { CLUTTER_INTERPOLATION_LINEAR, CLUTTER_INTERPOLATION_CUBIC } ClutterInterpolation; /** * ClutterBinAlignment: * @CLUTTER_BIN_ALIGNMENT_FIXED: Fixed position alignment; the * #ClutterBinLayout will honour the fixed position provided * by the actors themselves when allocating them * @CLUTTER_BIN_ALIGNMENT_FILL: Fill the allocation size * @CLUTTER_BIN_ALIGNMENT_START: Position the actors at the top * or left side of the container, depending on the axis * @CLUTTER_BIN_ALIGNMENT_END: Position the actors at the bottom * or right side of the container, depending on the axis * @CLUTTER_BIN_ALIGNMENT_CENTER: Position the actors at the * center of the container, depending on the axis * * The alignment policies available on each axis for #ClutterBinLayout * * Since: 1.2 * * Deprecated: 1.12: Use #ClutterActorAlign and the #ClutterActor * API instead */ typedef enum { CLUTTER_BIN_ALIGNMENT_FIXED, CLUTTER_BIN_ALIGNMENT_FILL, CLUTTER_BIN_ALIGNMENT_START, CLUTTER_BIN_ALIGNMENT_END, CLUTTER_BIN_ALIGNMENT_CENTER } ClutterBinAlignment; /** * ClutterBindCoordinate: * @CLUTTER_BIND_X: Bind the X coordinate * @CLUTTER_BIND_Y: Bind the Y coordinate * @CLUTTER_BIND_WIDTH: Bind the width * @CLUTTER_BIND_HEIGHT: Bind the height * @CLUTTER_BIND_POSITION: Equivalent to to %CLUTTER_BIND_X and * %CLUTTER_BIND_Y (added in Clutter 1.6) * @CLUTTER_BIND_SIZE: Equivalent to %CLUTTER_BIND_WIDTH and * %CLUTTER_BIND_HEIGHT (added in Clutter 1.6) * @CLUTTER_BIND_ALL: Equivalent to %CLUTTER_BIND_POSITION and * %CLUTTER_BIND_SIZE (added in Clutter 1.10) * * Specifies which property should be used in a binding * * Since: 1.4 */ typedef enum { /*< prefix=CLUTTER_BIND >*/ CLUTTER_BIND_X, CLUTTER_BIND_Y, CLUTTER_BIND_WIDTH, CLUTTER_BIND_HEIGHT, CLUTTER_BIND_POSITION, CLUTTER_BIND_SIZE, CLUTTER_BIND_ALL } ClutterBindCoordinate; /** * ClutterEffectPaintFlags: * @CLUTTER_EFFECT_PAINT_ACTOR_DIRTY: The actor or one of its children * has queued a redraw before this paint. This implies that the effect * should call clutter_actor_continue_paint() to chain to the next * effect and can not cache any results from a previous paint. * * Flags passed to the ‘paint’ or ‘pick’ method of #ClutterEffect. */ typedef enum { /*< prefix=CLUTTER_EFFECT_PAINT >*/ CLUTTER_EFFECT_PAINT_ACTOR_DIRTY = (1 << 0) } ClutterEffectPaintFlags; /** * ClutterBoxAlignment: * @CLUTTER_BOX_ALIGNMENT_START: Align the child to the top or to * to the left, depending on the used axis * @CLUTTER_BOX_ALIGNMENT_CENTER: Align the child to the center * @CLUTTER_BOX_ALIGNMENT_END: Align the child to the bottom or to * the right, depending on the used axis * * The alignment policies available on each axis of the #ClutterBoxLayout * * Since: 1.2 */ typedef enum { CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_END, CLUTTER_BOX_ALIGNMENT_CENTER } ClutterBoxAlignment; /** * ClutterLongPressState: * @CLUTTER_LONG_PRESS_QUERY: Queries the action whether it supports * long presses * @CLUTTER_LONG_PRESS_ACTIVATE: Activates the action on a long press * @CLUTTER_LONG_PRESS_CANCEL: The long press was cancelled * * The states for the #ClutterClickAction::long-press signal. * * Since: 1.8 */ typedef enum { /*< prefix=CLUTTER_LONG_PRESS >*/ CLUTTER_LONG_PRESS_QUERY, CLUTTER_LONG_PRESS_ACTIVATE, CLUTTER_LONG_PRESS_CANCEL } ClutterLongPressState; /** * ClutterStaticColor: * @CLUTTER_COLOR_WHITE: White color (ffffffff) * @CLUTTER_COLOR_BLACK: Black color (000000ff) * @CLUTTER_COLOR_RED: Red color (ff0000ff) * @CLUTTER_COLOR_DARK_RED: Dark red color (800000ff) * @CLUTTER_COLOR_GREEN: Green color (00ff00ff) * @CLUTTER_COLOR_DARK_GREEN: Dark green color (008000ff) * @CLUTTER_COLOR_BLUE: Blue color (0000ffff) * @CLUTTER_COLOR_DARK_BLUE: Dark blue color (000080ff) * @CLUTTER_COLOR_CYAN: Cyan color (00ffffff) * @CLUTTER_COLOR_DARK_CYAN: Dark cyan color (008080ff) * @CLUTTER_COLOR_MAGENTA: Magenta color (ff00ffff) * @CLUTTER_COLOR_DARK_MAGENTA: Dark magenta color (800080ff) * @CLUTTER_COLOR_YELLOW: Yellow color (ffff00ff) * @CLUTTER_COLOR_DARK_YELLOW: Dark yellow color (808000ff) * @CLUTTER_COLOR_GRAY: Gray color (a0a0a4ff) * @CLUTTER_COLOR_DARK_GRAY: Dark Gray color (808080ff) * @CLUTTER_COLOR_LIGHT_GRAY: Light gray color (c0c0c0ff) * @CLUTTER_COLOR_BUTTER: Butter color (edd400ff) * @CLUTTER_COLOR_BUTTER_LIGHT: Light butter color (fce94fff) * @CLUTTER_COLOR_BUTTER_DARK: Dark butter color (c4a000ff) * @CLUTTER_COLOR_ORANGE: Orange color (f57900ff) * @CLUTTER_COLOR_ORANGE_LIGHT: Light orange color (fcaf3fff) * @CLUTTER_COLOR_ORANGE_DARK: Dark orange color (ce5c00ff) * @CLUTTER_COLOR_CHOCOLATE: Chocolate color (c17d11ff) * @CLUTTER_COLOR_CHOCOLATE_LIGHT: Light chocolate color (e9b96eff) * @CLUTTER_COLOR_CHOCOLATE_DARK: Dark chocolate color (8f5902ff) * @CLUTTER_COLOR_CHAMELEON: Chameleon color (73d216ff) * @CLUTTER_COLOR_CHAMELEON_LIGHT: Light chameleon color (8ae234ff) * @CLUTTER_COLOR_CHAMELEON_DARK: Dark chameleon color (4e9a06ff) * @CLUTTER_COLOR_SKY_BLUE: Sky color (3465a4ff) * @CLUTTER_COLOR_SKY_BLUE_LIGHT: Light sky color (729fcfff) * @CLUTTER_COLOR_SKY_BLUE_DARK: Dark sky color (204a87ff) * @CLUTTER_COLOR_PLUM: Plum color (75507bff) * @CLUTTER_COLOR_PLUM_LIGHT: Light plum color (ad7fa8ff) * @CLUTTER_COLOR_PLUM_DARK: Dark plum color (5c3566ff) * @CLUTTER_COLOR_SCARLET_RED: Scarlet red color (cc0000ff) * @CLUTTER_COLOR_SCARLET_RED_LIGHT: Light scarlet red color (ef2929ff) * @CLUTTER_COLOR_SCARLET_RED_DARK: Dark scarlet red color (a40000ff) * @CLUTTER_COLOR_ALUMINIUM_1: Aluminium, first variant (eeeeecff) * @CLUTTER_COLOR_ALUMINIUM_2: Aluminium, second variant (d3d7cfff) * @CLUTTER_COLOR_ALUMINIUM_3: Aluminium, third variant (babdb6ff) * @CLUTTER_COLOR_ALUMINIUM_4: Aluminium, fourth variant (888a85ff) * @CLUTTER_COLOR_ALUMINIUM_5: Aluminium, fifth variant (555753ff) * @CLUTTER_COLOR_ALUMINIUM_6: Aluminium, sixth variant (2e3436ff) * @CLUTTER_COLOR_TRANSPARENT: Transparent color (00000000) * * Named colors, for accessing global colors defined by Clutter * * Since: 1.6 */ typedef enum { /*< prefix=CLUTTER_COLOR >*/ /* CGA/EGA-like palette */ CLUTTER_COLOR_WHITE = 0, CLUTTER_COLOR_BLACK, CLUTTER_COLOR_RED, CLUTTER_COLOR_DARK_RED, CLUTTER_COLOR_GREEN, CLUTTER_COLOR_DARK_GREEN, CLUTTER_COLOR_BLUE, CLUTTER_COLOR_DARK_BLUE, CLUTTER_COLOR_CYAN, CLUTTER_COLOR_DARK_CYAN, CLUTTER_COLOR_MAGENTA, CLUTTER_COLOR_DARK_MAGENTA, CLUTTER_COLOR_YELLOW, CLUTTER_COLOR_DARK_YELLOW, CLUTTER_COLOR_GRAY, CLUTTER_COLOR_DARK_GRAY, CLUTTER_COLOR_LIGHT_GRAY, /* Tango icon palette */ CLUTTER_COLOR_BUTTER, CLUTTER_COLOR_BUTTER_LIGHT, CLUTTER_COLOR_BUTTER_DARK, CLUTTER_COLOR_ORANGE, CLUTTER_COLOR_ORANGE_LIGHT, CLUTTER_COLOR_ORANGE_DARK, CLUTTER_COLOR_CHOCOLATE, CLUTTER_COLOR_CHOCOLATE_LIGHT, CLUTTER_COLOR_CHOCOLATE_DARK, CLUTTER_COLOR_CHAMELEON, CLUTTER_COLOR_CHAMELEON_LIGHT, CLUTTER_COLOR_CHAMELEON_DARK, CLUTTER_COLOR_SKY_BLUE, CLUTTER_COLOR_SKY_BLUE_LIGHT, CLUTTER_COLOR_SKY_BLUE_DARK, CLUTTER_COLOR_PLUM, CLUTTER_COLOR_PLUM_LIGHT, CLUTTER_COLOR_PLUM_DARK, CLUTTER_COLOR_SCARLET_RED, CLUTTER_COLOR_SCARLET_RED_LIGHT, CLUTTER_COLOR_SCARLET_RED_DARK, CLUTTER_COLOR_ALUMINIUM_1, CLUTTER_COLOR_ALUMINIUM_2, CLUTTER_COLOR_ALUMINIUM_3, CLUTTER_COLOR_ALUMINIUM_4, CLUTTER_COLOR_ALUMINIUM_5, CLUTTER_COLOR_ALUMINIUM_6, /* Fully transparent black */ CLUTTER_COLOR_TRANSPARENT } ClutterStaticColor; /** * ClutterDragAxis: * @CLUTTER_DRAG_AXIS_NONE: No constraint * @CLUTTER_DRAG_X_AXIS: Set a constraint on the X axis * @CLUTTER_DRAG_Y_AXIS: Set a constraint on the Y axis * * The axis of the constraint that should be applied on the * dragging action * * Since: 1.4 */ typedef enum { /*< prefix=CLUTTER_DRAG >*/ CLUTTER_DRAG_AXIS_NONE = 0, CLUTTER_DRAG_X_AXIS, CLUTTER_DRAG_Y_AXIS } ClutterDragAxis; /** * ClutterEventFlags: * @CLUTTER_EVENT_NONE: No flag set * @CLUTTER_EVENT_FLAG_SYNTHETIC: Synthetic event * * Flags for the #ClutterEvent * * Since: 0.6 */ typedef enum { /*< flags prefix=CLUTTER_EVENT >*/ CLUTTER_EVENT_NONE = 0, CLUTTER_EVENT_FLAG_SYNTHETIC = 1 << 0, CLUTTER_EVENT_FLAG_INPUT_METHOD = 1 << 1 } ClutterEventFlags; /** * ClutterEventType: * @CLUTTER_NOTHING: Empty event * @CLUTTER_KEY_PRESS: Key press event * @CLUTTER_KEY_RELEASE: Key release event * @CLUTTER_MOTION: Pointer motion event * @CLUTTER_ENTER: Actor enter event * @CLUTTER_LEAVE: Actor leave event * @CLUTTER_BUTTON_PRESS: Pointer button press event * @CLUTTER_BUTTON_RELEASE: Pointer button release event * @CLUTTER_SCROLL: Pointer scroll event * @CLUTTER_STAGE_STATE: Stage state change event * @CLUTTER_DESTROY_NOTIFY: Destroy notification event * @CLUTTER_CLIENT_MESSAGE: Client message event * @CLUTTER_DELETE: Stage delete event * @CLUTTER_TOUCH_BEGIN: A new touch event sequence has started; * event added in 1.10 * @CLUTTER_TOUCH_UPDATE: A touch event sequence has been updated; * event added in 1.10 * @CLUTTER_TOUCH_END: A touch event sequence has finished; * event added in 1.10 * @CLUTTER_TOUCH_CANCEL: A touch event sequence has been canceled; * event added in 1.10 * @CLUTTER_TOUCHPAD_PINCH: A pinch gesture event, the current state is * determined by its phase field; event added in 1.24 * @CLUTTER_TOUCHPAD_SWIPE: A swipe gesture event, the current state is * determined by its phase field; event added in 1.24 * @CLUTTER_PROXIMITY_IN: A tool entered in proximity to a tablet; * event added in 1.28 * @CLUTTER_PROXIMITY_OUT: A tool left from the proximity area of a tablet; * event added in 1.28 * @CLUTTER_EVENT_LAST: Marks the end of the #ClutterEventType enumeration; * added in 1.10 * * Types of events. * * Since: 0.4 */ typedef enum { /*< prefix=CLUTTER >*/ CLUTTER_NOTHING = 0, CLUTTER_KEY_PRESS, CLUTTER_KEY_RELEASE, CLUTTER_MOTION, CLUTTER_ENTER, CLUTTER_LEAVE, CLUTTER_BUTTON_PRESS, CLUTTER_BUTTON_RELEASE, CLUTTER_SCROLL, CLUTTER_STAGE_STATE, CLUTTER_DESTROY_NOTIFY, CLUTTER_CLIENT_MESSAGE, CLUTTER_DELETE, CLUTTER_TOUCH_BEGIN, CLUTTER_TOUCH_UPDATE, CLUTTER_TOUCH_END, CLUTTER_TOUCH_CANCEL, CLUTTER_TOUCHPAD_PINCH, CLUTTER_TOUCHPAD_SWIPE, CLUTTER_PROXIMITY_IN, CLUTTER_PROXIMITY_OUT, CLUTTER_PAD_BUTTON_PRESS, CLUTTER_PAD_BUTTON_RELEASE, CLUTTER_PAD_STRIP, CLUTTER_PAD_RING, CLUTTER_EVENT_LAST /* helper */ } ClutterEventType; /** * ClutterScrollDirection: * @CLUTTER_SCROLL_UP: Scroll up * @CLUTTER_SCROLL_DOWN: Scroll down * @CLUTTER_SCROLL_LEFT: Scroll left * @CLUTTER_SCROLL_RIGHT: Scroll right * @CLUTTER_SCROLL_SMOOTH: Precise scrolling delta (available in 1.10) * * Direction of a pointer scroll event. * * The %CLUTTER_SCROLL_SMOOTH value implies that the #ClutterScrollEvent * has precise scrolling delta information. * * Since: 0.4 */ typedef enum { /*< prefix=CLUTTER_SCROLL >*/ CLUTTER_SCROLL_UP, CLUTTER_SCROLL_DOWN, CLUTTER_SCROLL_LEFT, CLUTTER_SCROLL_RIGHT, CLUTTER_SCROLL_SMOOTH } ClutterScrollDirection; /** * ClutterStageState: * @CLUTTER_STAGE_STATE_FULLSCREEN: Fullscreen mask * @CLUTTER_STAGE_STATE_OFFSCREEN: Offscreen mask (deprecated) * @CLUTTER_STAGE_STATE_ACTIVATED: Activated mask * * Stage state masks, used by the #ClutterEvent of type %CLUTTER_STAGE_STATE. * * Since: 0.4 */ typedef enum { CLUTTER_STAGE_STATE_FULLSCREEN = (1 << 1), CLUTTER_STAGE_STATE_OFFSCREEN = (1 << 2), CLUTTER_STAGE_STATE_ACTIVATED = (1 << 3) } ClutterStageState; /** * ClutterFeatureFlags: * @CLUTTER_FEATURE_TEXTURE_NPOT: Set if NPOTS textures supported. * @CLUTTER_FEATURE_SYNC_TO_VBLANK: Set if vblank syncing supported. * @CLUTTER_FEATURE_TEXTURE_YUV: Set if YUV based textures supported. * @CLUTTER_FEATURE_TEXTURE_READ_PIXELS: Set if texture pixels can be read. * @CLUTTER_FEATURE_STAGE_STATIC: Set if stage size if fixed (i.e framebuffer) * @CLUTTER_FEATURE_STAGE_USER_RESIZE: Set if stage is able to be user resized. * @CLUTTER_FEATURE_STAGE_CURSOR: Set if stage has a graphical cursor. * @CLUTTER_FEATURE_SHADERS_GLSL: Set if the backend supports GLSL shaders. * @CLUTTER_FEATURE_OFFSCREEN: Set if the backend supports offscreen rendering. * @CLUTTER_FEATURE_STAGE_MULTIPLE: Set if multiple stages are supported. * @CLUTTER_FEATURE_SWAP_EVENTS: Set if the GLX_INTEL_swap_event is supported. * * Runtime flags indicating specific features available via Clutter window * system and graphics backend. * * Since: 0.4 */ typedef enum { CLUTTER_FEATURE_TEXTURE_NPOT = (1 << 2), CLUTTER_FEATURE_SYNC_TO_VBLANK = (1 << 3), CLUTTER_FEATURE_TEXTURE_YUV = (1 << 4), CLUTTER_FEATURE_TEXTURE_READ_PIXELS = (1 << 5), CLUTTER_FEATURE_STAGE_STATIC = (1 << 6), CLUTTER_FEATURE_STAGE_USER_RESIZE = (1 << 7), CLUTTER_FEATURE_STAGE_CURSOR = (1 << 8), CLUTTER_FEATURE_SHADERS_GLSL = (1 << 9), CLUTTER_FEATURE_OFFSCREEN = (1 << 10), CLUTTER_FEATURE_STAGE_MULTIPLE = (1 << 11), CLUTTER_FEATURE_SWAP_EVENTS = (1 << 12) } ClutterFeatureFlags; /** * ClutterFlowOrientation: * @CLUTTER_FLOW_HORIZONTAL: Arrange the children of the flow layout * horizontally first * @CLUTTER_FLOW_VERTICAL: Arrange the children of the flow layout * vertically first * * The direction of the arrangement of the children inside * a #ClutterFlowLayout * * Since: 1.2 */ typedef enum { /*< prefix=CLUTTER_FLOW >*/ CLUTTER_FLOW_HORIZONTAL, CLUTTER_FLOW_VERTICAL } ClutterFlowOrientation; /** * ClutterInputDeviceType: * @CLUTTER_POINTER_DEVICE: A pointer device * @CLUTTER_KEYBOARD_DEVICE: A keyboard device * @CLUTTER_EXTENSION_DEVICE: A generic extension device * @CLUTTER_JOYSTICK_DEVICE: A joystick device * @CLUTTER_TABLET_DEVICE: A tablet device * @CLUTTER_TOUCHPAD_DEVICE: A touchpad device * @CLUTTER_TOUCHSCREEN_DEVICE: A touch screen device * @CLUTTER_PEN_DEVICE: A pen device * @CLUTTER_ERASER_DEVICE: An eraser device * @CLUTTER_CURSOR_DEVICE: A cursor device * @CLUTTER_PAD_DEVICE: A tablet pad * @CLUTTER_N_DEVICE_TYPES: The number of device types * * The types of input devices available. * * The #ClutterInputDeviceType enumeration can be extended at later * date; not every platform supports every input device type. * * Since: 1.0 */ typedef enum { CLUTTER_POINTER_DEVICE, CLUTTER_KEYBOARD_DEVICE, CLUTTER_EXTENSION_DEVICE, CLUTTER_JOYSTICK_DEVICE, CLUTTER_TABLET_DEVICE, CLUTTER_TOUCHPAD_DEVICE, CLUTTER_TOUCHSCREEN_DEVICE, CLUTTER_PEN_DEVICE, CLUTTER_ERASER_DEVICE, CLUTTER_CURSOR_DEVICE, CLUTTER_PAD_DEVICE, CLUTTER_N_DEVICE_TYPES } ClutterInputDeviceType; /** * ClutterInputMode: * @CLUTTER_INPUT_MODE_MASTER: A master, virtual device * @CLUTTER_INPUT_MODE_SLAVE: A slave, physical device, attached to * a master device * @CLUTTER_INPUT_MODE_FLOATING: A slave, physical device, not attached * to a master device * * The mode for input devices available. * * Since: 1.6 */ typedef enum { CLUTTER_INPUT_MODE_MASTER, CLUTTER_INPUT_MODE_SLAVE, CLUTTER_INPUT_MODE_FLOATING } ClutterInputMode; /** * ClutterInputAxis: * @CLUTTER_INPUT_AXIS_IGNORE: Unused axis * @CLUTTER_INPUT_AXIS_X: The position on the X axis * @CLUTTER_INPUT_AXIS_Y: The position of the Y axis * @CLUTTER_INPUT_AXIS_PRESSURE: The pressure information * @CLUTTER_INPUT_AXIS_XTILT: The tilt on the X axis * @CLUTTER_INPUT_AXIS_YTILT: The tile on the Y axis * @CLUTTER_INPUT_AXIS_WHEEL: A wheel * @CLUTTER_INPUT_AXIS_DISTANCE: Distance (Since 1.12) * @CLUTTER_INPUT_AXIS_ROTATION: Rotation along the z-axis (Since 1.28) * @CLUTTER_INPUT_AXIS_SLIDER: A slider (Since 1.28) * @CLUTTER_INPUT_AXIS_LAST: Last value of the enumeration; this value is * useful when iterating over the enumeration values (Since 1.12) * * The type of axes Clutter recognizes on a #ClutterInputDevice * * Since: 1.6 */ typedef enum { CLUTTER_INPUT_AXIS_IGNORE, CLUTTER_INPUT_AXIS_X, CLUTTER_INPUT_AXIS_Y, CLUTTER_INPUT_AXIS_PRESSURE, CLUTTER_INPUT_AXIS_XTILT, CLUTTER_INPUT_AXIS_YTILT, CLUTTER_INPUT_AXIS_WHEEL, CLUTTER_INPUT_AXIS_DISTANCE, CLUTTER_INPUT_AXIS_ROTATION, CLUTTER_INPUT_AXIS_SLIDER, CLUTTER_INPUT_AXIS_LAST } ClutterInputAxis; /** * ClutterSnapEdge: * @CLUTTER_SNAP_EDGE_TOP: the top edge * @CLUTTER_SNAP_EDGE_RIGHT: the right edge * @CLUTTER_SNAP_EDGE_BOTTOM: the bottom edge * @CLUTTER_SNAP_EDGE_LEFT: the left edge * * The edge to snap * * Since: 1.6 */ typedef enum { CLUTTER_SNAP_EDGE_TOP, CLUTTER_SNAP_EDGE_RIGHT, CLUTTER_SNAP_EDGE_BOTTOM, CLUTTER_SNAP_EDGE_LEFT } ClutterSnapEdge; /** * ClutterPickMode: * @CLUTTER_PICK_NONE: Do not paint any actor * @CLUTTER_PICK_REACTIVE: Paint only the reactive actors * @CLUTTER_PICK_ALL: Paint all actors * * Controls the paint cycle of the scene graph when in pick mode * * Since: 1.0 */ typedef enum { CLUTTER_PICK_NONE = 0, CLUTTER_PICK_REACTIVE, CLUTTER_PICK_ALL } ClutterPickMode; /** * ClutterSwipeDirection: * @CLUTTER_SWIPE_DIRECTION_UP: Upwards swipe gesture * @CLUTTER_SWIPE_DIRECTION_DOWN: Downwards swipe gesture * @CLUTTER_SWIPE_DIRECTION_LEFT: Leftwards swipe gesture * @CLUTTER_SWIPE_DIRECTION_RIGHT: Rightwards swipe gesture * * The main direction of the swipe gesture * * Since: 1.8 */ typedef enum { /*< prefix=CLUTTER_SWIPE_DIRECTION >*/ CLUTTER_SWIPE_DIRECTION_UP = 1 << 0, CLUTTER_SWIPE_DIRECTION_DOWN = 1 << 1, CLUTTER_SWIPE_DIRECTION_LEFT = 1 << 2, CLUTTER_SWIPE_DIRECTION_RIGHT = 1 << 3 } ClutterSwipeDirection; /** * ClutterPanAxis: * @CLUTTER_PAN_AXIS_NONE: No constraint * @CLUTTER_PAN_X_AXIS: Set a constraint on the X axis * @CLUTTER_PAN_Y_AXIS: Set a constraint on the Y axis * @CLUTTER_PAN_AXIS_AUTO: Constrain panning automatically based on initial * movement (available since 1.24) * * The axis of the constraint that should be applied on the * panning action * * Since: 1.12 */ typedef enum { /*< prefix=CLUTTER_PAN >*/ CLUTTER_PAN_AXIS_NONE = 0, CLUTTER_PAN_X_AXIS, CLUTTER_PAN_Y_AXIS, CLUTTER_PAN_AXIS_AUTO } ClutterPanAxis; /** * ClutterTableAlignment: * @CLUTTER_TABLE_ALIGNMENT_START: Align the child to the top or to the * left of a cell in the table, depending on the axis * @CLUTTER_TABLE_ALIGNMENT_CENTER: Align the child to the center of * a cell in the table * @CLUTTER_TABLE_ALIGNMENT_END: Align the child to the bottom or to the * right of a cell in the table, depending on the axis * * The alignment policies available on each axis of the #ClutterTableLayout * * Since: 1.4 * * Deprecated: 1.22: Use the alignment properties of #ClutterActor */ typedef enum { CLUTTER_TABLE_ALIGNMENT_START, CLUTTER_TABLE_ALIGNMENT_CENTER, CLUTTER_TABLE_ALIGNMENT_END } ClutterTableAlignment; /** * ClutterTextureFlags: * @CLUTTER_TEXTURE_NONE: No flags * @CLUTTER_TEXTURE_RGB_FLAG_BGR: Unused flag * @CLUTTER_TEXTURE_RGB_FLAG_PREMULT: Unused flag * @CLUTTER_TEXTURE_YUV_FLAG_YUV2: Unused flag * * Flags for clutter_texture_set_from_rgb_data() and * clutter_texture_set_from_yuv_data(). * * Since: 0.4 * * Deprecated: 1.22: The #ClutterTexture class was the only user of * this API */ typedef enum { /*< prefix=CLUTTER_TEXTURE >*/ CLUTTER_TEXTURE_NONE = 0, CLUTTER_TEXTURE_RGB_FLAG_BGR = 1 << 1, CLUTTER_TEXTURE_RGB_FLAG_PREMULT = 1 << 2, /* FIXME: not handled */ CLUTTER_TEXTURE_YUV_FLAG_YUV2 = 1 << 3 } ClutterTextureFlags; /** * ClutterTextureQuality: * @CLUTTER_TEXTURE_QUALITY_LOW: fastest rendering will use nearest neighbour * interpolation when rendering. good setting. * @CLUTTER_TEXTURE_QUALITY_MEDIUM: higher quality rendering without using * extra resources. * @CLUTTER_TEXTURE_QUALITY_HIGH: render the texture with the best quality * available using extra memory. * * Enumaration controlling the texture quality. * * Since: 0.8 * * Deprecated: 1.22: The #ClutterTexture class was the only used ot * this API; use #ClutterImage and clutter_actor_set_content_scaling_filters() * instead. */ typedef enum { /*< prefix=CLUTTER_TEXTURE_QUALITY >*/ CLUTTER_TEXTURE_QUALITY_LOW, CLUTTER_TEXTURE_QUALITY_MEDIUM, CLUTTER_TEXTURE_QUALITY_HIGH } ClutterTextureQuality; /** * ClutterTimelineDirection: * @CLUTTER_TIMELINE_FORWARD: forward direction for a timeline * @CLUTTER_TIMELINE_BACKWARD: backward direction for a timeline * * The direction of a #ClutterTimeline * * Since: 0.6 */ typedef enum { CLUTTER_TIMELINE_FORWARD, CLUTTER_TIMELINE_BACKWARD } ClutterTimelineDirection; /** * ClutterUnitType: * @CLUTTER_UNIT_PIXEL: Unit expressed in pixels (with subpixel precision) * @CLUTTER_UNIT_EM: Unit expressed in em * @CLUTTER_UNIT_MM: Unit expressed in millimeters * @CLUTTER_UNIT_POINT: Unit expressed in points * @CLUTTER_UNIT_CM: Unit expressed in centimeters * * The type of unit in which a value is expressed * * This enumeration might be expanded at later date * * Since: 1.0 */ typedef enum { /*< prefix=CLUTTER_UNIT >*/ CLUTTER_UNIT_PIXEL, CLUTTER_UNIT_EM, CLUTTER_UNIT_MM, CLUTTER_UNIT_POINT, CLUTTER_UNIT_CM } ClutterUnitType; #define CLUTTER_PATH_RELATIVE (32) /** * ClutterPathNodeType: * @CLUTTER_PATH_MOVE_TO: jump to the given position * @CLUTTER_PATH_LINE_TO: create a line from the last node to the * given position * @CLUTTER_PATH_CURVE_TO: bezier curve using the last position and * three control points. * @CLUTTER_PATH_CLOSE: create a line from the last node to the last * %CLUTTER_PATH_MOVE_TO node. * @CLUTTER_PATH_REL_MOVE_TO: same as %CLUTTER_PATH_MOVE_TO but with * coordinates relative to the last node. * @CLUTTER_PATH_REL_LINE_TO: same as %CLUTTER_PATH_LINE_TO but with * coordinates relative to the last node. * @CLUTTER_PATH_REL_CURVE_TO: same as %CLUTTER_PATH_CURVE_TO but with * coordinates relative to the last node. * * Types of nodes in a #ClutterPath. * * Since: 1.0 */ typedef enum { CLUTTER_PATH_MOVE_TO = 0, CLUTTER_PATH_LINE_TO = 1, CLUTTER_PATH_CURVE_TO = 2, CLUTTER_PATH_CLOSE = 3, CLUTTER_PATH_REL_MOVE_TO = CLUTTER_PATH_MOVE_TO | CLUTTER_PATH_RELATIVE, CLUTTER_PATH_REL_LINE_TO = CLUTTER_PATH_LINE_TO | CLUTTER_PATH_RELATIVE, CLUTTER_PATH_REL_CURVE_TO = CLUTTER_PATH_CURVE_TO | CLUTTER_PATH_RELATIVE } ClutterPathNodeType; /** * ClutterActorAlign: * @CLUTTER_ACTOR_ALIGN_FILL: Stretch to cover the whole allocated space * @CLUTTER_ACTOR_ALIGN_START: Snap to left or top side, leaving space * to the right or bottom. For horizontal layouts, in right-to-left * locales this should be reversed. * @CLUTTER_ACTOR_ALIGN_CENTER: Center the actor inside the allocation * @CLUTTER_ACTOR_ALIGN_END: Snap to right or bottom side, leaving space * to the left or top. For horizontal layouts, in right-to-left locales * this should be reversed. * * Controls how a #ClutterActor should align itself inside the extra space * assigned to it during the allocation. * * Alignment only matters if the allocated space given to an actor is * bigger than its natural size; for example, when the #ClutterActor:x-expand * or the #ClutterActor:y-expand properties of #ClutterActor are set to %TRUE. * * Since: 1.10 */ typedef enum { CLUTTER_ACTOR_ALIGN_FILL, CLUTTER_ACTOR_ALIGN_START, CLUTTER_ACTOR_ALIGN_CENTER, CLUTTER_ACTOR_ALIGN_END } ClutterActorAlign; /** * ClutterRepaintFlags: * @CLUTTER_REPAINT_FLAGS_PRE_PAINT: Run the repaint function prior to * painting the stages * @CLUTTER_REPAINT_FLAGS_POST_PAINT: Run the repaint function after * painting the stages * @CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD: Ensure that a new frame * is queued after adding the repaint function * * Flags to pass to clutter_threads_add_repaint_func_full(). * * Since: 1.10 */ typedef enum { CLUTTER_REPAINT_FLAGS_PRE_PAINT = 1 << 0, CLUTTER_REPAINT_FLAGS_POST_PAINT = 1 << 1, CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD = 1 << 2 } ClutterRepaintFlags; /** * ClutterContentGravity: * @CLUTTER_CONTENT_GRAVITY_TOP_LEFT: Align the content to the top left corner * @CLUTTER_CONTENT_GRAVITY_TOP: Align the content to the top edge * @CLUTTER_CONTENT_GRAVITY_TOP_RIGHT: Align the content to the top right corner * @CLUTTER_CONTENT_GRAVITY_LEFT: Align the content to the left edge * @CLUTTER_CONTENT_GRAVITY_CENTER: Align the content to the center * @CLUTTER_CONTENT_GRAVITY_RIGHT: Align the content to the right edge * @CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT: Align the content to the bottom left corner * @CLUTTER_CONTENT_GRAVITY_BOTTOM: Align the content to the bottom edge * @CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT: Align the content to the bottom right corner * @CLUTTER_CONTENT_GRAVITY_RESIZE_FILL: Resize the content to fill the allocation * @CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT: Resize the content to remain within the * allocation, while maintaining the aspect ratio * * Controls the alignment of the #ClutterContent inside a #ClutterActor. * * Since: 1.10 */ typedef enum { CLUTTER_CONTENT_GRAVITY_TOP_LEFT, CLUTTER_CONTENT_GRAVITY_TOP, CLUTTER_CONTENT_GRAVITY_TOP_RIGHT, CLUTTER_CONTENT_GRAVITY_LEFT, CLUTTER_CONTENT_GRAVITY_CENTER, CLUTTER_CONTENT_GRAVITY_RIGHT, CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT, CLUTTER_CONTENT_GRAVITY_BOTTOM, CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT, CLUTTER_CONTENT_GRAVITY_RESIZE_FILL, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT } ClutterContentGravity; /** * ClutterScalingFilter: * @CLUTTER_SCALING_FILTER_LINEAR: Linear interpolation filter * @CLUTTER_SCALING_FILTER_NEAREST: Nearest neighbor interpolation filter * @CLUTTER_SCALING_FILTER_TRILINEAR: Trilinear minification filter, with * mipmap generation; this filter linearly interpolates on every axis, * as well as between mipmap levels. * * The scaling filters to be used with the #ClutterActor:minification-filter * and #ClutterActor:magnification-filter properties. * * Since: 1.10 */ typedef enum { CLUTTER_SCALING_FILTER_LINEAR, CLUTTER_SCALING_FILTER_NEAREST, CLUTTER_SCALING_FILTER_TRILINEAR } ClutterScalingFilter; /** * ClutterOrientation: * @CLUTTER_ORIENTATION_HORIZONTAL: An horizontal orientation * @CLUTTER_ORIENTATION_VERTICAL: A vertical orientation * * Represents the orientation of actors or layout managers. * * Since: 1.12 */ typedef enum { CLUTTER_ORIENTATION_HORIZONTAL, CLUTTER_ORIENTATION_VERTICAL } ClutterOrientation; /** * ClutterScrollMode: * @CLUTTER_SCROLL_NONE: Ignore scrolling * @CLUTTER_SCROLL_HORIZONTALLY: Scroll only horizontally * @CLUTTER_SCROLL_VERTICALLY: Scroll only vertically * @CLUTTER_SCROLL_BOTH: Scroll in both directions * * Scroll modes. * * Since: 1.12 */ typedef enum { /*< prefix=CLUTTER_SCROLL >*/ CLUTTER_SCROLL_NONE = 0, CLUTTER_SCROLL_HORIZONTALLY = 1 << 0, CLUTTER_SCROLL_VERTICALLY = 1 << 1, CLUTTER_SCROLL_BOTH = CLUTTER_SCROLL_HORIZONTALLY | CLUTTER_SCROLL_VERTICALLY } ClutterScrollMode; /** * ClutterGridPosition: * @CLUTTER_GRID_POSITION_LEFT: left position * @CLUTTER_GRID_POSITION_RIGHT: right position * @CLUTTER_GRID_POSITION_TOP: top position * @CLUTTER_GRID_POSITION_BOTTOM: bottom position * * Grid position modes. * * Since: 1.12 */ typedef enum { CLUTTER_GRID_POSITION_LEFT, CLUTTER_GRID_POSITION_RIGHT, CLUTTER_GRID_POSITION_TOP, CLUTTER_GRID_POSITION_BOTTOM } ClutterGridPosition; /** * ClutterContentRepeat: * @CLUTTER_REPEAT_NONE: No repeat * @CLUTTER_REPEAT_X_AXIS: Repeat the content on the X axis * @CLUTTER_REPEAT_Y_AXIS: Repeat the content on the Y axis * @CLUTTER_REPEAT_BOTH: Repeat the content on both axis * * Content repeat modes. * * Since: 1.12 */ typedef enum { CLUTTER_REPEAT_NONE = 0, CLUTTER_REPEAT_X_AXIS = 1 << 0, CLUTTER_REPEAT_Y_AXIS = 1 << 1, CLUTTER_REPEAT_BOTH = CLUTTER_REPEAT_X_AXIS | CLUTTER_REPEAT_Y_AXIS } ClutterContentRepeat; /** * ClutterStepMode: * @CLUTTER_STEP_MODE_START: The change in the value of a * %CLUTTER_STEP progress mode should occur at the start of * the transition * @CLUTTER_STEP_MODE_END: The change in the value of a * %CLUTTER_STEP progress mode should occur at the end of * the transition * * Change the value transition of a step function. * * See clutter_timeline_set_step_progress(). * * Since: 1.12 */ typedef enum { CLUTTER_STEP_MODE_START, CLUTTER_STEP_MODE_END } ClutterStepMode; /** * ClutterZoomAxis: * @CLUTTER_ZOOM_X_AXIS: Scale only on the X axis * @CLUTTER_ZOOM_Y_AXIS: Scale only on the Y axis * @CLUTTER_ZOOM_BOTH: Scale on both axis * * The axis of the constraint that should be applied by the * zooming action. * * Since: 1.12 */ typedef enum { /*< prefix=CLUTTER_ZOOM >*/ CLUTTER_ZOOM_X_AXIS, CLUTTER_ZOOM_Y_AXIS, CLUTTER_ZOOM_BOTH } ClutterZoomAxis; /** * ClutterGestureTriggerEdge: * @CLUTTER_GESTURE_TRIGGER_EDGE_NONE: Tell #ClutterGestureAction that * the gesture must begin immediately and there's no drag limit that * will cause its cancellation; * @CLUTTER_GESTURE_TRIGGER_EDGE_AFTER: Tell #ClutterGestureAction that * it needs to wait until the drag threshold has been exceeded before * considering that the gesture has begun; * @CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE: Tell #ClutterGestureAction that * the gesture must begin immediately and that it must be cancelled * once the drag exceed the configured threshold. * * Enum passed to the clutter_gesture_action_set_threshold_trigger_edge() * function. * * Since: 1.18 */ typedef enum { CLUTTER_GESTURE_TRIGGER_EDGE_NONE = 0, CLUTTER_GESTURE_TRIGGER_EDGE_AFTER, CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE } ClutterGestureTriggerEdge; /** * ClutterTouchpadGesturePhase: * @CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN: The gesture has begun. * @CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE: The gesture has been updated. * @CLUTTER_TOUCHPAD_GESTURE_PHASE_END: The gesture was finished, changes * should be permanently applied. * @CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL: The gesture was cancelled, all * changes should be undone. * * The phase of a touchpad gesture event. All gestures are guaranteed to * begin with an event of type %CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN, * followed by a number of %CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE (possibly 0). * * A finished gesture may have 2 possible outcomes, an event with phase * %CLUTTER_TOUCHPAD_GESTURE_PHASE_END will be emitted when the gesture is * considered successful, this should be used as the hint to perform any * permanent changes. * Cancelled gestures may be so for a variety of reasons, due to hardware, * or due to the gesture recognition layers hinting the gesture did not * finish resolutely (eg. a 3rd finger being added during a pinch gesture). * In these cases, the last event with report the phase * %CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL, this should be used as a hint * to undo any visible/permanent changes that were done throughout the * progress of the gesture. * * See also #ClutterTouchpadPinchEvent and #ClutterTouchpadPinchEvent. * * Since: 1.24 */ typedef enum { CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN, CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE, CLUTTER_TOUCHPAD_GESTURE_PHASE_END, CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL } ClutterTouchpadGesturePhase; /** * ClutterScrollSource: * @CLUTTER_SCROLL_SOURCE_UNKNOWN: Source of scroll events is unknown. * @CLUTTER_SCROLL_SOURCE_WHEEL: The scroll event is originated by a mouse wheel. * @CLUTTER_SCROLL_SOURCE_FINGER: The scroll event is originated by one or more * fingers on the device (eg. touchpads). * @CLUTTER_SCROLL_SOURCE_CONTINUOUS: The scroll event is originated by the * motion of some device (eg. a scroll button is set). * * The scroll source determines the source of the scroll event. Keep in mind * that the source device #ClutterInputDeviceType is not enough to infer * the scroll source. * * Since: 1.26 */ typedef enum { CLUTTER_SCROLL_SOURCE_UNKNOWN, CLUTTER_SCROLL_SOURCE_WHEEL, CLUTTER_SCROLL_SOURCE_FINGER, CLUTTER_SCROLL_SOURCE_CONTINUOUS } ClutterScrollSource; /** * ClutterScrollFinishFlags: * @CLUTTER_SCROLL_FINISHED_NONE: no axis was stopped. * @CLUTTER_SCROLL_FINISHED_HORIZONTAL: The horizontal axis stopped. * @CLUTTER_SCROLL_FINISHED_VERTICAL: The vertical axis stopped. * * Flags used to notify the axes that were stopped in a #ClutterScrollEvent. * These can be used to trigger post-scroll effects like kinetic scrolling. * * Since: 1.26 */ typedef enum { CLUTTER_SCROLL_FINISHED_NONE = 0, CLUTTER_SCROLL_FINISHED_HORIZONTAL = 1 << 0, CLUTTER_SCROLL_FINISHED_VERTICAL = 1 << 1 } ClutterScrollFinishFlags; /** * ClutterInputDeviceToolType: * @CLUTTER_INPUT_DEVICE_TOOL_NONE: No tool * @CLUTTER_INPUT_DEVICE_TOOL_PEN: The tool is a pen * @CLUTTER_INPUT_DEVICE_TOOL_ERASER: The tool is an eraser * @CLUTTER_INPUT_DEVICE_TOOL_BRUSH: The tool is a brush * @CLUTTER_INPUT_DEVICE_TOOL_PENCIL: The tool is a pencil * @CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH: The tool is an airbrush * @CLUTTER_INPUT_DEVICE_TOOL_MOUSE: The tool is a mouse * @CLUTTER_INPUT_DEVICE_TOOL_LENS: The tool is a lens * * Defines the type of tool that a #ClutterInputDeviceTool represents. * * Since: 1.28 */ typedef enum { CLUTTER_INPUT_DEVICE_TOOL_NONE, CLUTTER_INPUT_DEVICE_TOOL_PEN, CLUTTER_INPUT_DEVICE_TOOL_ERASER, CLUTTER_INPUT_DEVICE_TOOL_BRUSH, CLUTTER_INPUT_DEVICE_TOOL_PENCIL, CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH, CLUTTER_INPUT_DEVICE_TOOL_MOUSE, CLUTTER_INPUT_DEVICE_TOOL_LENS } ClutterInputDeviceToolType; typedef enum { CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN, CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER, } ClutterInputDevicePadSource; typedef enum { CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE, CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE, } ClutterInputDeviceMapping; typedef enum { CLUTTER_INPUT_CONTENT_HINT_COMPLETION = 1 << 0, CLUTTER_INPUT_CONTENT_HINT_SPELLCHECK = 1 << 1, CLUTTER_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION = 1 << 2, CLUTTER_INPUT_CONTENT_HINT_LOWERCASE = 1 << 3, CLUTTER_INPUT_CONTENT_HINT_UPPERCASE = 1 << 4, CLUTTER_INPUT_CONTENT_HINT_TITLECASE = 1 << 5, CLUTTER_INPUT_CONTENT_HINT_HIDDEN_TEXT = 1 << 6, CLUTTER_INPUT_CONTENT_HINT_SENSITIVE_DATA = 1 << 7, CLUTTER_INPUT_CONTENT_HINT_LATIN = 1 << 8, CLUTTER_INPUT_CONTENT_HINT_MULTILINE = 1 << 9, } ClutterInputContentHintFlags; typedef enum { CLUTTER_INPUT_CONTENT_PURPOSE_NORMAL, CLUTTER_INPUT_CONTENT_PURPOSE_ALPHA, CLUTTER_INPUT_CONTENT_PURPOSE_DIGITS, CLUTTER_INPUT_CONTENT_PURPOSE_NUMBER, CLUTTER_INPUT_CONTENT_PURPOSE_PHONE, CLUTTER_INPUT_CONTENT_PURPOSE_URL, CLUTTER_INPUT_CONTENT_PURPOSE_EMAIL, CLUTTER_INPUT_CONTENT_PURPOSE_NAME, CLUTTER_INPUT_CONTENT_PURPOSE_PASSWORD, CLUTTER_INPUT_CONTENT_PURPOSE_DATE, CLUTTER_INPUT_CONTENT_PURPOSE_TIME, CLUTTER_INPUT_CONTENT_PURPOSE_DATETIME, CLUTTER_INPUT_CONTENT_PURPOSE_TERMINAL, } ClutterInputContentPurpose; typedef enum { CLUTTER_INPUT_PANEL_STATE_OFF, CLUTTER_INPUT_PANEL_STATE_ON, CLUTTER_INPUT_PANEL_STATE_TOGGLE, } ClutterInputPanelState; G_END_DECLS #endif /* __CLUTTER_ENUMS_H__ */ muffin-5.2.1/clutter/clutter/clutter-stage.c0000664000175000017500000044141714211404421021242 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ /** * SECTION:clutter-stage * @short_description: Top level visual element to which actors are placed. * * #ClutterStage is a top level 'window' on which child actors are placed * and manipulated. * * Backends might provide support for multiple stages. The support for this * feature can be checked at run-time using the clutter_feature_available() * function and the %CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used * supports multiple stages, new #ClutterStage instances can be created * using clutter_stage_new(). These stages must be managed by the developer * using clutter_actor_destroy(), which will take care of destroying all the * actors contained inside them. * * #ClutterStage is a proxy actor, wrapping the backend-specific * implementation of the windowing system. It is possible to subclass * #ClutterStage, as long as every overridden virtual function chains up to * the parent class corresponding function. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-stage.h" #include "deprecated/clutter-stage.h" #include "deprecated/clutter-container.h" #include "clutter-actor-private.h" #include "clutter-backend-private.h" #include "clutter-cairo.h" #include "clutter-color.h" #include "clutter-container.h" #include "clutter-debug.h" #include "clutter-device-manager-private.h" #include "clutter-enum-types.h" #include "clutter-event-private.h" #include "clutter-id-pool.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-master-clock.h" #include "clutter-muffin.h" #include "clutter-paint-volume-private.h" #include "clutter-private.h" #include "clutter-stage-manager-private.h" #include "clutter-stage-private.h" #include "clutter-version.h" /* For flavour */ #include "clutter-private.h" #include "cogl/cogl.h" /* * ClutterStageHint: * @CLUTTER_STAGE_NONE: No hint set * @CLUTTER_STAGE_NO_CLEAR_ON_PAINT: When this hint is set, the stage * should not clear the viewport; this flag is useful when painting * fully opaque actors covering the whole visible area of the stage, * i.e. when no blending with the stage color happens over the whole * stage viewport * * A series of hints that enable or disable behaviours on the stage */ typedef enum { /*< prefix=CLUTTER_STAGE >*/ CLUTTER_STAGE_HINT_NONE = 0, CLUTTER_STAGE_NO_CLEAR_ON_PAINT = 1 << 0 } ClutterStageHint; #define STAGE_NO_CLEAR_ON_PAINT(s) ((((ClutterStage *) (s))->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0) struct _ClutterStageQueueRedrawEntry { ClutterActor *actor; gboolean has_clip; ClutterPaintVolume clip; }; struct _ClutterStagePrivate { /* the stage implementation */ ClutterStageWindow *impl; ClutterPerspective perspective; CoglMatrix projection; CoglMatrix inverse_projection; CoglMatrix view; float viewport[4]; ClutterFog fog; gchar *title; ClutterActor *key_focused_actor; GQueue *event_queue; ClutterStageHint stage_hints; GArray *paint_volume_stack; ClutterPlane current_clip_planes[4]; GList *pending_queue_redraws; CoglFramebuffer *active_framebuffer; gint sync_delay; GTimer *fps_timer; gint32 timer_n_frames; ClutterIDPool *pick_id_pool; #ifdef CLUTTER_ENABLE_DEBUG gulong redraw_count; #endif /* CLUTTER_ENABLE_DEBUG */ ClutterStageState current_state; gpointer paint_data; GDestroyNotify paint_notify; guint relayout_pending : 1; guint redraw_pending : 1; guint is_fullscreen : 1; guint is_cursor_visible : 1; guint is_user_resizable : 1; guint use_fog : 1; guint throttle_motion_events : 1; guint use_alpha : 1; guint min_size_changed : 1; guint accept_focus : 1; guint motion_events_enabled : 1; guint has_custom_perspective : 1; guint stage_was_relayout : 1; }; enum { PROP_0, PROP_COLOR, PROP_FULLSCREEN_SET, PROP_OFFSCREEN, PROP_CURSOR_VISIBLE, PROP_PERSPECTIVE, PROP_TITLE, PROP_USER_RESIZABLE, PROP_USE_FOG, PROP_FOG, PROP_USE_ALPHA, PROP_KEY_FOCUS, PROP_NO_CLEAR_HINT, PROP_ACCEPT_FOCUS }; enum { FULLSCREEN, UNFULLSCREEN, ACTIVATE, DEACTIVATE, DELETE_EVENT, AFTER_PAINT, PRESENTED, LAST_SIGNAL }; static guint stage_signals[LAST_SIGNAL] = { 0, }; static const ClutterColor default_stage_color = { 255, 255, 255, 255 }; static void clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage); static void free_queue_redraw_entry (ClutterStageQueueRedrawEntry *entry); static void clutter_container_iface_init (ClutterContainerIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP, G_ADD_PRIVATE (ClutterStage) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER, clutter_container_iface_init)) static void clutter_stage_real_add (ClutterContainer *container, ClutterActor *child) { clutter_actor_add_child (CLUTTER_ACTOR (container), child); } static void clutter_stage_real_remove (ClutterContainer *container, ClutterActor *child) { clutter_actor_remove_child (CLUTTER_ACTOR (container), child); } static void clutter_stage_real_foreach (ClutterContainer *container, ClutterCallback callback, gpointer user_data) { ClutterActorIter iter; ClutterActor *child; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container)); while (clutter_actor_iter_next (&iter, &child)) callback (child, user_data); } static void clutter_stage_real_raise (ClutterContainer *container, ClutterActor *child, ClutterActor *sibling) { clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (container), child, sibling); } static void clutter_stage_real_lower (ClutterContainer *container, ClutterActor *child, ClutterActor *sibling) { clutter_actor_set_child_below_sibling (CLUTTER_ACTOR (container), child, sibling); } static void clutter_stage_real_sort_depth_order (ClutterContainer *container) { } static void clutter_container_iface_init (ClutterContainerIface *iface) { iface->add = clutter_stage_real_add; iface->remove = clutter_stage_real_remove; iface->foreach = clutter_stage_real_foreach; iface->raise = clutter_stage_real_raise; iface->lower = clutter_stage_real_lower; iface->sort_depth_order = clutter_stage_real_sort_depth_order; } static void clutter_stage_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; cairo_rectangle_int_t geom; if (priv->impl == NULL) return; _clutter_stage_window_get_geometry (priv->impl, &geom); if (min_width_p) *min_width_p = geom.width; if (natural_width_p) *natural_width_p = geom.width; } static void clutter_stage_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; cairo_rectangle_int_t geom; if (priv->impl == NULL) return; _clutter_stage_window_get_geometry (priv->impl, &geom); if (min_height_p) *min_height_p = geom.height; if (natural_height_p) *natural_height_p = geom.height; } static inline void queue_full_redraw (ClutterStage *stage) { ClutterStageWindow *stage_window; if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); /* Just calling clutter_actor_queue_redraw will typically only * redraw the bounding box of the children parented on the stage but * in this case we really need to ensure that the full stage is * redrawn so we add a NULL redraw clip to the stage window. */ stage_window = _clutter_stage_get_window (stage); if (stage_window == NULL) return; _clutter_stage_window_add_redraw_clip (stage_window, NULL); } static gboolean stage_is_default (ClutterStage *stage) { ClutterStageManager *stage_manager; ClutterStageWindow *impl; stage_manager = clutter_stage_manager_get_default (); if (stage != clutter_stage_manager_get_default_stage (stage_manager)) return FALSE; impl = _clutter_stage_get_window (stage); if (impl != _clutter_stage_get_default_window ()) return FALSE; return TRUE; } static void clutter_stage_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterActorBox alloc = CLUTTER_ACTOR_BOX_INIT_ZERO; float old_width, old_height; float new_width, new_height; float width, height; cairo_rectangle_int_t window_size; if (priv->impl == NULL) return; /* our old allocation */ clutter_actor_get_allocation_box (self, &alloc); clutter_actor_box_get_size (&alloc, &old_width, &old_height); /* the current allocation */ clutter_actor_box_get_size (box, &width, &height); /* the current Stage implementation size */ _clutter_stage_window_get_geometry (priv->impl, &window_size); /* if the stage is fixed size (for instance, it's using a EGL framebuffer) * then we simply ignore any allocation request and override the * allocation chain - because we cannot forcibly change the size of the * stage window. */ if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)) { #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (LAYOUT, "Following allocation to %.2fx%.2f (absolute origin %s)", width, height, (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? "changed" : "not changed"); #endif clutter_actor_set_allocation (self, box, flags | CLUTTER_DELEGATE_LAYOUT); /* Ensure the window is sized correctly */ if (!priv->is_fullscreen) { if (priv->min_size_changed) { gfloat min_width, min_height; gboolean min_width_set, min_height_set; g_object_get (G_OBJECT (self), "min-width", &min_width, "min-width-set", &min_width_set, "min-height", &min_height, "min-height-set", &min_height_set, NULL); if (!min_width_set) min_width = 1; if (!min_height_set) min_height = 1; if (width < min_width) width = min_width; if (height < min_height) height = min_height; priv->min_size_changed = FALSE; } if (window_size.width != CLUTTER_NEARBYINT (width) || window_size.height != CLUTTER_NEARBYINT (height)) { _clutter_stage_window_resize (priv->impl, CLUTTER_NEARBYINT (width), CLUTTER_NEARBYINT (height)); } } } else { ClutterActorBox override = { 0, }; /* override the passed allocation */ override.x1 = 0; override.y1 = 0; override.x2 = window_size.width; override.y2 = window_size.height; #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (LAYOUT, "Overriding original allocation of %.2fx%.2f " "with %.2fx%.2f (absolute origin %s)", width, height, override.x2, override.y2, (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? "changed" : "not changed"); #endif /* and store the overridden allocation */ clutter_actor_set_allocation (self, &override, flags | CLUTTER_DELEGATE_LAYOUT); } /* XXX: Until Cogl becomes fully responsible for backend windows * Clutter need to manually keep it informed of the current window * size. We do this after the allocation above so that the stage * window has a chance to update the window size based on the * allocation. */ _clutter_stage_window_get_geometry (priv->impl, &window_size); cogl_onscreen_clutter_backend_set_size (window_size.width, window_size.height); /* reset the viewport if the allocation effectively changed */ clutter_actor_get_allocation_box (self, &alloc); clutter_actor_box_get_size (&alloc, &new_width, &new_height); if (CLUTTER_NEARBYINT (old_width) != CLUTTER_NEARBYINT (new_width) || CLUTTER_NEARBYINT (old_height) != CLUTTER_NEARBYINT (new_height)) { int real_width = CLUTTER_NEARBYINT (new_width); int real_height = CLUTTER_NEARBYINT (new_height); _clutter_stage_set_viewport (CLUTTER_STAGE (self), 0, 0, real_width, real_height); /* Note: we don't assume that set_viewport will queue a full redraw * since it may bail-out early if something preemptively set the * viewport before the stage was really allocated its new size. */ queue_full_redraw (CLUTTER_STAGE (self)); } } typedef struct _Vector4 { float x, y, z, w; } Vector4; static void _cogl_util_get_eye_planes_for_screen_poly (float *polygon, int n_vertices, float *viewport, const CoglMatrix *projection, const CoglMatrix *inverse_project, ClutterPlane *planes) { float Wc; Vector4 *tmp_poly; ClutterPlane *plane; int i; float b[3]; float c[3]; int count; tmp_poly = g_alloca (sizeof (Vector4) * n_vertices * 2); #define DEPTH -50 /* Determine W in clip-space (Wc) for a point (0, 0, DEPTH, 1) * * Note: the depth could be anything except 0. * * We will transform the polygon into clip coordinates using this * depth and then into eye coordinates. Our clip planes will be * defined by triangles that extend between points of the polygon at * DEPTH and corresponding points of the same polygon at DEPTH * 2. * * NB: Wc defines the position of the clip planes in clip * coordinates. Given a screen aligned cross section through the * frustum; coordinates range from [-Wc,Wc] left to right on the * x-axis and [Wc,-Wc] top to bottom on the y-axis. */ Wc = DEPTH * projection->wz + projection->ww; #define CLIP_X(X) ((((float)X - viewport[0]) * (2.0 / viewport[2])) - 1) * Wc #define CLIP_Y(Y) ((((float)Y - viewport[1]) * (2.0 / viewport[3])) - 1) * -Wc for (i = 0; i < n_vertices; i++) { tmp_poly[i].x = CLIP_X (polygon[i * 2]); tmp_poly[i].y = CLIP_Y (polygon[i * 2 + 1]); tmp_poly[i].z = DEPTH; tmp_poly[i].w = Wc; } Wc = DEPTH * 2 * projection->wz + projection->ww; /* FIXME: technically we don't need to project all of the points * twice, it would be enough project every other point since * we can share points in this set to define the plane vectors. */ for (i = 0; i < n_vertices; i++) { tmp_poly[n_vertices + i].x = CLIP_X (polygon[i * 2]); tmp_poly[n_vertices + i].y = CLIP_Y (polygon[i * 2 + 1]); tmp_poly[n_vertices + i].z = DEPTH * 2; tmp_poly[n_vertices + i].w = Wc; } #undef CLIP_X #undef CLIP_Y cogl_matrix_project_points (inverse_project, 4, sizeof (Vector4), tmp_poly, sizeof (Vector4), tmp_poly, n_vertices * 2); /* XXX: It's quite ugly that we end up with these casts between * Vector4 types and CoglVector3s, it might be better if the * cogl_vector APIs just took pointers to floats. */ count = n_vertices - 1; for (i = 0; i < count; i++) { plane = &planes[i]; memcpy (plane->v0, tmp_poly + i, sizeof (float) * 3); memcpy (b, tmp_poly + n_vertices + i, sizeof (float) * 3); memcpy (c, tmp_poly + n_vertices + i + 1, sizeof (float) * 3); cogl_vector3_subtract (b, b, plane->v0); cogl_vector3_subtract (c, c, plane->v0); cogl_vector3_cross_product (plane->n, b, c); cogl_vector3_normalize (plane->n); } plane = &planes[n_vertices - 1]; memcpy (plane->v0, tmp_poly + 0, sizeof (float) * 3); memcpy (b, tmp_poly + (2 * n_vertices - 1), sizeof (float) * 3); memcpy (c, tmp_poly + n_vertices, sizeof (float) * 3); cogl_vector3_subtract (b, b, plane->v0); cogl_vector3_subtract (c, c, plane->v0); cogl_vector3_cross_product (plane->n, b, c); cogl_vector3_normalize (plane->n); } static void _clutter_stage_update_active_framebuffer (ClutterStage *stage, CoglFramebuffer *framebuffer) { ClutterStagePrivate *priv = stage->priv; /* We track the CoglFramebuffer that corresponds to the stage itself * so, for example, we can disable culling when rendering to an * offscreen framebuffer. */ priv->active_framebuffer = framebuffer; } /* XXX: Instead of having a toplevel 2D clip region, it might be * better to have a clip volume within the view frustum. This could * allow us to avoid projecting actors into window coordinates to * be able to cull them. */ static void clutter_stage_do_paint_view (ClutterStage *stage, ClutterStageView *view, const cairo_rectangle_int_t *clip) { ClutterStagePrivate *priv = stage->priv; CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view); cairo_rectangle_int_t view_layout; float clip_poly[8]; float viewport[4]; cairo_rectangle_int_t geom; _clutter_stage_window_get_geometry (priv->impl, &geom); viewport[0] = priv->viewport[0]; viewport[1] = priv->viewport[1]; viewport[2] = priv->viewport[2]; viewport[3] = priv->viewport[3]; if (!clip) { clutter_stage_view_get_layout (view, &view_layout); clip = &view_layout; } clip_poly[0] = MAX (clip->x, 0); clip_poly[1] = MAX (clip->y, 0); clip_poly[2] = MIN (clip->x + clip->width, geom.width); clip_poly[3] = clip_poly[1]; clip_poly[4] = clip_poly[2]; clip_poly[5] = MIN (clip->y + clip->height, geom.height); clip_poly[6] = clip_poly[0]; clip_poly[7] = clip_poly[5]; CLUTTER_NOTE (CLIPPING, "Setting stage clip too: " "x=%f, y=%f, width=%f, height=%f", clip_poly[0], clip_poly[1], clip_poly[2] - clip_poly[0], clip_poly[5] - clip_poly[1]); _cogl_util_get_eye_planes_for_screen_poly (clip_poly, 4, viewport, &priv->projection, &priv->inverse_projection, priv->current_clip_planes); _clutter_stage_paint_volume_stack_free_all (stage); _clutter_stage_update_active_framebuffer (stage, framebuffer); clutter_actor_paint (CLUTTER_ACTOR (stage)); } /* This provides a common point of entry for painting the scenegraph * for picking or painting... */ void _clutter_stage_paint_view (ClutterStage *stage, ClutterStageView *view, const cairo_rectangle_int_t *clip) { ClutterStagePrivate *priv = stage->priv; if (!priv->impl) return; clutter_stage_do_paint_view (stage, view, clip); g_signal_emit (stage, stage_signals[AFTER_PAINT], 0); } /* If we don't implement this here, we get the paint function * from the deprecated clutter-group class, which doesn't * respect the Z order as it uses our empty sort_depth_order. */ static void clutter_stage_paint (ClutterActor *self) { ClutterActorIter iter; ClutterActor *child; clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) clutter_actor_paint (child); } static void clutter_stage_pick (ClutterActor *self, const ClutterColor *color) { ClutterActorIter iter; ClutterActor *child; /* Note: we don't chain up to our parent as we don't want any geometry * emitted for the stage itself. The stage's pick id is effectively handled * by the call to cogl_clear done in clutter-main.c:_clutter_do_pick_async() */ clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) clutter_actor_paint (child); } static gboolean clutter_stage_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { /* Returning False effectively means Clutter has to assume it covers * everything... */ return FALSE; } static void clutter_stage_realize (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; gboolean is_realized; g_assert (priv->impl != NULL); is_realized = _clutter_stage_window_realize (priv->impl); if (!is_realized) CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); } static void clutter_stage_unrealize (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; /* and then unrealize the implementation */ g_assert (priv->impl != NULL); _clutter_stage_window_unrealize (priv->impl); CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); } static void clutter_stage_show_all (ClutterActor *self) { ClutterActorIter iter; ClutterActor *child; /* we don't do a recursive show_all(), to maintain the old * invariants from ClutterGroup */ clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) clutter_actor_show (child); clutter_actor_show (self); } static void clutter_stage_show (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); /* Possibly do an allocation run so that the stage will have the right size before we map it */ _clutter_stage_maybe_relayout (self); g_assert (priv->impl != NULL); _clutter_stage_window_show (priv->impl, TRUE); } static void clutter_stage_hide_all (ClutterActor *self) { ClutterActorIter iter; ClutterActor *child; clutter_actor_hide (self); /* we don't do a recursive hide_all(), to maintain the old invariants * from ClutterGroup */ clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) clutter_actor_hide (child); } static void clutter_stage_hide (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; g_assert (priv->impl != NULL); _clutter_stage_window_hide (priv->impl); CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self); } static void clutter_stage_emit_key_focus_event (ClutterStage *stage, gboolean focus_in) { ClutterStagePrivate *priv = stage->priv; if (priv->key_focused_actor == NULL) return; if (focus_in) g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in"); else g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out"); g_object_notify (G_OBJECT (stage), "key-focus"); } static void clutter_stage_real_activate (ClutterStage *stage) { clutter_stage_emit_key_focus_event (stage, TRUE); } static void clutter_stage_real_deactivate (ClutterStage *stage) { clutter_stage_emit_key_focus_event (stage, FALSE); } static void clutter_stage_real_fullscreen (ClutterStage *stage) { ClutterStagePrivate *priv = stage->priv; cairo_rectangle_int_t geom; ClutterActorBox box; /* we need to force an allocation here because the size * of the stage might have been changed by the backend * * this is a really bad solution to the issues caused by * the fact that fullscreening the stage on the X11 backends * is really an asynchronous operation */ _clutter_stage_window_get_geometry (priv->impl, &geom); box.x1 = 0; box.y1 = 0; box.x2 = geom.width; box.y2 = geom.height; /* we need to blow the caching on the Stage size, given that * we're about to force an allocation, because if anything * ends up querying the size of the stage during the allocate() * call, like constraints or signal handlers, we'll get into an * inconsistent state: the stage will report the old cached size, * but the allocation will be updated anyway. */ clutter_actor_set_size (CLUTTER_ACTOR (stage), -1.0, -1.0); clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, CLUTTER_ALLOCATION_NONE); } void _clutter_stage_queue_event (ClutterStage *stage, ClutterEvent *event, gboolean copy_event) { ClutterStagePrivate *priv; gboolean first_event; ClutterInputDevice *device; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; first_event = priv->event_queue->length == 0; if (copy_event) event = clutter_event_copy (event); g_queue_push_tail (priv->event_queue, event); if (first_event) { ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_start_running (master_clock); _clutter_stage_schedule_update (stage); } /* if needed, update the state of the input device of the event. * we do it here to avoid calling the same code from every backend * event processing function */ device = clutter_event_get_device (event); if (device != NULL && event->type != CLUTTER_PROXIMITY_IN && event->type != CLUTTER_PROXIMITY_OUT) { ClutterModifierType event_state = clutter_event_get_state (event); ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); guint32 event_time = clutter_event_get_time (event); gfloat event_x, event_y; clutter_event_get_coords (event, &event_x, &event_y); _clutter_input_device_set_coords (device, sequence, event_x, event_y, stage); _clutter_input_device_set_state (device, event_state); _clutter_input_device_set_time (device, event_time); } } gboolean _clutter_stage_has_queued_events (ClutterStage *stage) { ClutterStagePrivate *priv; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); priv = stage->priv; return priv->event_queue->length > 0; } void _clutter_stage_process_queued_events (ClutterStage *stage) { ClutterStagePrivate *priv; GList *events, *l; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (priv->event_queue->length == 0) return; /* In case the stage gets destroyed during event processing */ g_object_ref (stage); /* Steal events before starting processing to avoid reentrancy * issues */ events = priv->event_queue->head; priv->event_queue->head = NULL; priv->event_queue->tail = NULL; priv->event_queue->length = 0; for (l = events; l != NULL; l = l->next) { ClutterEvent *event; ClutterEvent *next_event; ClutterInputDevice *device; ClutterInputDevice *next_device; ClutterInputDeviceType device_type; gboolean check_device = FALSE; event = l->data; next_event = l->next ? l->next->data : NULL; device = clutter_event_get_device (event); if (next_event != NULL) next_device = clutter_event_get_device (next_event); else next_device = NULL; if (device != NULL && next_device != NULL) check_device = TRUE; device_type = clutter_input_device_get_device_type (device); /* Skip consecutive motion events coming from the same device, * except those of tablet tools, since users of these events * want no precision loss. */ if (priv->throttle_motion_events && next_event != NULL && device_type != CLUTTER_TABLET_DEVICE && device_type != CLUTTER_PEN_DEVICE && device_type != CLUTTER_ERASER_DEVICE) { if (event->type == CLUTTER_MOTION && (next_event->type == CLUTTER_MOTION || next_event->type == CLUTTER_LEAVE) && (!check_device || (device == next_device))) { CLUTTER_NOTE (EVENT, "Omitting motion event at %d, %d", (int) event->motion.x, (int) event->motion.y); if (next_event->type == CLUTTER_MOTION) { ClutterDeviceManager *device_manager = clutter_device_manager_get_default (); _clutter_device_manager_compress_motion (device_manager, next_event, event); } goto next_event; } else if (event->type == CLUTTER_TOUCH_UPDATE && next_event->type == CLUTTER_TOUCH_UPDATE && event->touch.sequence == next_event->touch.sequence && (!check_device || (device == next_device))) { CLUTTER_NOTE (EVENT, "Omitting touch update event at %d, %d", (int) event->touch.x, (int) event->touch.y); goto next_event; } } _clutter_process_event (event); next_event: clutter_event_free (event); } g_list_free (events); g_object_unref (stage); } /** * _clutter_stage_needs_update: * @stage: A #ClutterStage * * Determines if _clutter_stage_do_update() needs to be called. * * Return value: %TRUE if the stage need layout or painting */ gboolean _clutter_stage_needs_update (ClutterStage *stage) { ClutterStagePrivate *priv; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); priv = stage->priv; return priv->relayout_pending || priv->redraw_pending; } void _clutter_stage_maybe_relayout (ClutterActor *actor) { ClutterStage *stage = CLUTTER_STAGE (actor); ClutterStagePrivate *priv = stage->priv; gfloat natural_width, natural_height; ClutterActorBox box = { 0, }; if (!priv->relayout_pending) return; /* avoid reentrancy */ if (!CLUTTER_ACTOR_IN_RELAYOUT (stage)) { priv->relayout_pending = FALSE; priv->stage_was_relayout = TRUE; #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (ACTOR, "Recomputing layout"); #endif CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT); natural_width = natural_height = 0; clutter_actor_get_preferred_size (CLUTTER_ACTOR (stage), NULL, NULL, &natural_width, &natural_height); box.x1 = 0; box.y1 = 0; box.x2 = natural_width; box.y2 = natural_height; #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage", (int) natural_width, (int) natural_height); #endif clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, CLUTTER_ALLOCATION_NONE); CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT); } } static void clutter_stage_do_redraw (ClutterStage *stage) { ClutterActor *actor = CLUTTER_ACTOR (stage); ClutterStagePrivate *priv = stage->priv; static gboolean show_fps; if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; if (priv->impl == NULL) return; show_fps = _clutter_context_get_show_fps (); #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (PAINT, "Redraw started for stage '%s'[%p]", _clutter_actor_get_debug_name (actor), stage); #endif if (show_fps) { if (priv->fps_timer == NULL) priv->fps_timer = g_timer_new (); _clutter_stage_window_redraw (priv->impl); priv->timer_n_frames += 1; if (g_timer_elapsed (priv->fps_timer, NULL) >= 1.0) { g_print ("*** FPS for %s: %i ***\n", _clutter_actor_get_debug_name (actor), priv->timer_n_frames); priv->timer_n_frames = 0; g_timer_start (priv->fps_timer); } return; } _clutter_stage_window_redraw (priv->impl); #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (PAINT, "Redraw finished for stage '%s'[%p]", _clutter_actor_get_debug_name (actor), stage); #endif } static GSList * _clutter_stage_check_updated_pointers (ClutterStage *stage) { ClutterStagePrivate *priv = stage->priv; ClutterDeviceManager *device_manager; GSList *updating = NULL; const GSList *devices; cairo_rectangle_int_t clip; ClutterPoint point; gboolean has_clip; has_clip = _clutter_stage_window_get_redraw_clip_bounds (priv->impl, &clip); device_manager = clutter_device_manager_get_default (); devices = clutter_device_manager_peek_devices (device_manager); for (; devices != NULL; devices = devices->next) { ClutterInputDevice *dev = devices->data; if (clutter_input_device_get_device_mode (dev) != CLUTTER_INPUT_MODE_MASTER) continue; switch (clutter_input_device_get_device_type (dev)) { case CLUTTER_POINTER_DEVICE: case CLUTTER_TABLET_DEVICE: case CLUTTER_PEN_DEVICE: case CLUTTER_ERASER_DEVICE: case CLUTTER_CURSOR_DEVICE: if (!clutter_input_device_get_coords (dev, NULL, &point)) continue; if (!has_clip || (point.x >= clip.x && point.x < clip.x + clip.width && point.y >= clip.y && point.y < clip.y + clip.height)) updating = g_slist_prepend (updating, dev); break; default: /* Any other devices don't need checking, either because they * don't have x/y coordinates, or because they're implicitly * grabbed on an actor by default as it's the case of * touch(screens). */ break; } } return updating; } /** * _clutter_stage_do_update: * @stage: A #ClutterStage * * Handles per-frame layout and repaint for the stage. * * Return value: %TRUE if the stage was updated */ gboolean _clutter_stage_do_update (ClutterStage *stage) { ClutterStagePrivate *priv = stage->priv; gboolean stage_was_relayout = priv->stage_was_relayout; GSList *pointers = NULL; priv->stage_was_relayout = FALSE; /* if the stage is being destroyed, or if the destruction already * happened and we don't have an StageWindow any more, then we * should bail out */ if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || priv->impl == NULL) return FALSE; if (!CLUTTER_ACTOR_IS_REALIZED (stage)) return FALSE; /* NB: We need to ensure we have an up to date layout *before* we * check or clear the pending redraws flag since a relayout may * queue a redraw. */ _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage)); if (!priv->redraw_pending) return FALSE; if (stage_was_relayout) pointers = _clutter_stage_check_updated_pointers (stage); clutter_stage_maybe_finish_queue_redraws (stage); clutter_stage_do_redraw (stage); /* reset the guard, so that new redraws are possible */ priv->redraw_pending = FALSE; #ifdef CLUTTER_ENABLE_DEBUG if (priv->redraw_count > 0) { CLUTTER_NOTE (SCHEDULER, "Queued %lu redraws during the last cycle", priv->redraw_count); priv->redraw_count = 0; } #endif /* CLUTTER_ENABLE_DEBUG */ while (pointers) { _clutter_input_device_update (pointers->data, NULL, TRUE); pointers = g_slist_delete_link (pointers, pointers); } return TRUE; } static void clutter_stage_real_queue_relayout (ClutterActor *self) { ClutterStage *stage = CLUTTER_STAGE (self); ClutterStagePrivate *priv = stage->priv; ClutterActorClass *parent_class; if (!priv->relayout_pending) { _clutter_stage_schedule_update (stage); priv->relayout_pending = TRUE; } /* chain up */ parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class); parent_class->queue_relayout (self); } static void clutter_stage_real_queue_redraw (ClutterActor *actor, ClutterActor *leaf) { ClutterStage *stage = CLUTTER_STAGE (actor); ClutterStageWindow *stage_window; ClutterPaintVolume *redraw_clip; ClutterActorBox bounding_box; ClutterActorBox intersection_box; cairo_rectangle_int_t geom, stage_clip; if (CLUTTER_ACTOR_IN_DESTRUCTION (actor)) return; /* If the backend can't do anything with redraw clips (e.g. it already knows * it needs to redraw everything anyway) then don't spend time transforming * any clip volume into stage coordinates... */ stage_window = _clutter_stage_get_window (stage); if (stage_window == NULL) return; if (_clutter_stage_window_ignoring_redraw_clips (stage_window)) { _clutter_stage_window_add_redraw_clip (stage_window, NULL); return; } /* Convert the clip volume into stage coordinates and then into an * axis aligned stage coordinates bounding box... */ redraw_clip = _clutter_actor_get_queue_redraw_clip (leaf); if (redraw_clip == NULL) { _clutter_stage_window_add_redraw_clip (stage_window, NULL); return; } if (redraw_clip->is_empty) return; _clutter_paint_volume_get_stage_paint_box (redraw_clip, stage, &bounding_box); _clutter_stage_window_get_geometry (stage_window, &geom); intersection_box.x1 = MAX (bounding_box.x1, 0); intersection_box.y1 = MAX (bounding_box.y1, 0); intersection_box.x2 = MIN (bounding_box.x2, geom.width); intersection_box.y2 = MIN (bounding_box.y2, geom.height); /* There is no need to track degenerate/empty redraw clips */ if (intersection_box.x2 <= intersection_box.x1 || intersection_box.y2 <= intersection_box.y1) return; /* when converting to integer coordinates make sure we round the edges of the * clip rectangle outwards... */ stage_clip.x = intersection_box.x1; stage_clip.y = intersection_box.y1; stage_clip.width = intersection_box.x2 - stage_clip.x; stage_clip.height = intersection_box.y2 - stage_clip.y; _clutter_stage_window_add_redraw_clip (stage_window, &stage_clip); } gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage) { ClutterStageWindow *stage_window = _clutter_stage_get_window (stage); if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || stage_window == NULL) return FALSE; if (stage->priv->redraw_pending && !_clutter_stage_window_has_redraw_clips (stage_window)) return TRUE; else return FALSE; } /** * clutter_stage_get_redraw_clip_bounds: * @stage: A #ClutterStage * @clip: (out caller-allocates): Return location for the clip bounds * * Gets the bounds of the current redraw for @stage in stage pixel * coordinates. E.g., if only a single actor has queued a redraw then * Clutter may redraw the stage with a clip so that it doesn't have to * paint every pixel in the stage. This function would then return the * bounds of that clip. An application can use this information to * avoid some extra work if it knows that some regions of the stage * aren't going to be painted. This should only be called while the * stage is being painted. If there is no current redraw clip then * this function will set @clip to the full extents of the stage. * * Since: 1.8 */ void clutter_stage_get_redraw_clip_bounds (ClutterStage *stage, cairo_rectangle_int_t *clip) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (clip != NULL); priv = stage->priv; if (!_clutter_stage_window_get_redraw_clip_bounds (priv->impl, clip)) { /* Set clip to the full extents of the stage */ _clutter_stage_window_get_geometry (priv->impl, clip); } } static void read_pixels_to_file (char *filename_stem, int x, int y, int width, int height) { guint8 *data; cairo_surface_t *surface; static int read_count = 0; char *filename = g_strdup_printf ("%s-%05d.png", filename_stem, read_count); data = malloc (4 * width * height); cogl_read_pixels (x, y, width, height, COGL_READ_PIXELS_COLOR_BUFFER, CLUTTER_CAIRO_FORMAT_ARGB32, data); surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24, width, height, width * 4); cairo_surface_write_to_png (surface, filename); cairo_surface_destroy (surface); free (data); free (filename); read_count++; } static ClutterActor * _clutter_stage_do_pick_on_view (ClutterStage *stage, gint x, gint y, ClutterPickMode mode, ClutterStageView *view) { ClutterActor *actor = CLUTTER_ACTOR (stage); ClutterStagePrivate *priv = stage->priv; CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view); cairo_rectangle_int_t view_layout; ClutterMainContext *context; guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff }; CoglColor stage_pick_id; gboolean dither_enabled_save; ClutterActor *retval; gint dirty_x; gint dirty_y; gint read_x; gint read_y; float fb_width, fb_height; float fb_scale; float viewport_offset_x; float viewport_offset_y; context = _clutter_context_get_default (); fb_scale = clutter_stage_view_get_scale (view); clutter_stage_view_get_layout (view, &view_layout); fb_width = view_layout.width * fb_scale; fb_height = view_layout.height * fb_scale; cogl_push_framebuffer (fb); /* needed for when a context switch happens */ _clutter_stage_maybe_setup_viewport (stage, view); /* FIXME: For some reason leaving the cogl clip stack empty causes the * picking to not work at all, so setting it the whole framebuffer content * for now. */ cogl_framebuffer_push_scissor_clip (fb, 0, 0, view_layout.width * fb_scale, view_layout.height * fb_scale); _clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y); if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))) { CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1", (int) dirty_x * fb_scale, (int) dirty_y * fb_scale); cogl_framebuffer_push_scissor_clip (fb, dirty_x * fb_scale, dirty_y * fb_scale, 1, 1); } viewport_offset_x = x * fb_scale - dirty_x * fb_scale; viewport_offset_y = y * fb_scale - dirty_y * fb_scale; CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f", priv->viewport[0] * fb_scale - viewport_offset_x, priv->viewport[1] * fb_scale - viewport_offset_y, priv->viewport[2] * fb_scale, priv->viewport[3] * fb_scale); cogl_framebuffer_set_viewport (fb, priv->viewport[0] * fb_scale - viewport_offset_x, priv->viewport[1] * fb_scale - viewport_offset_y, priv->viewport[2] * fb_scale, priv->viewport[3] * fb_scale); read_x = dirty_x * fb_scale; read_y = dirty_y * fb_scale; CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d s: %d", x, y, view_layout.width, view_layout.height, view_layout.x, view_layout.y, fb_scale); cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255); cogl_clear (&stage_pick_id, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH); /* Disable dithering (if any) when doing the painting in pick mode */ dither_enabled_save = cogl_framebuffer_get_dither_enabled (fb); cogl_framebuffer_set_dither_enabled (fb, FALSE); /* Render the entire scence in pick mode - just single colored silhouette's * are drawn offscreen (as we never swap buffers) */ context->pick_mode = mode; /* Paint without emitting AFTER_PAINT */ clutter_stage_do_paint_view (stage, view, NULL); context->pick_mode = CLUTTER_PICK_NONE; /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used even though we don't care about the alpha component because under GLES this is the only format that is guaranteed to work so Cogl will end up having to do a conversion if any other format is used. The format is requested as pre-multiplied because Cogl assumes that all pixels in the framebuffer are premultiplied so it avoids a conversion. */ cogl_framebuffer_read_pixels (fb, read_x, read_y, 1, 1, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)) { char *file_name = g_strdup_printf ("pick-buffer-%s-view-x-%d", _clutter_actor_get_debug_name (actor), view_layout.x); read_pixels_to_file (file_name, 0, 0, fb_width, fb_height); free (file_name); } /* Restore whether GL_DITHER was enabled */ cogl_framebuffer_set_dither_enabled (fb, dither_enabled_save); if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))) cogl_framebuffer_pop_clip (fb); cogl_framebuffer_pop_clip (fb); _clutter_stage_dirty_viewport (stage); if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff) retval = actor; else { guint32 id_ = _clutter_pixel_to_id (pixel); retval = _clutter_stage_get_actor_by_pick_id (stage, id_); CLUTTER_NOTE (PICK, "Picking actor %s with id %u (pixel: 0x%x%x%x%x", G_OBJECT_TYPE_NAME (retval), id_, pixel[0], pixel[1], pixel[2], pixel[3]); } cogl_pop_framebuffer (); return retval; } static ClutterStageView * get_view_at (ClutterStage *stage, int x, int y) { ClutterStagePrivate *priv = stage->priv; GList *l; for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next) { ClutterStageView *view = l->data; cairo_rectangle_int_t view_layout; clutter_stage_view_get_layout (view, &view_layout); if (x >= view_layout.x && x < view_layout.x + view_layout.width && y >= view_layout.y && y < view_layout.y + view_layout.height) return view; } return NULL; } ClutterActor * _clutter_stage_do_pick (ClutterStage *stage, gint x, gint y, ClutterPickMode mode) { ClutterActor *actor = CLUTTER_ACTOR (stage); ClutterStagePrivate *priv = stage->priv; float stage_width, stage_height; ClutterStageView *view = NULL; priv = stage->priv; if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return actor; if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING)) return actor; if (G_UNLIKELY (priv->impl == NULL)) return actor; clutter_actor_get_size (CLUTTER_ACTOR (stage), &stage_width, &stage_height); if (x < 0 || x >= stage_width || y < 0 || y >= stage_height) return actor; view = get_view_at (stage, x, y); if (view) return _clutter_stage_do_pick_on_view (stage, x, y, mode, view); return actor; } static gboolean clutter_stage_real_delete_event (ClutterStage *stage, ClutterEvent *event) { if (stage_is_default (stage)) clutter_main_quit (); else clutter_actor_destroy (CLUTTER_ACTOR (stage)); return CLUTTER_EVENT_STOP; } static void clutter_stage_real_apply_transform (ClutterActor *stage, CoglMatrix *matrix) { ClutterStagePrivate *priv = CLUTTER_STAGE (stage)->priv; /* FIXME: we probably shouldn't be explicitly reseting the matrix * here... */ cogl_matrix_init_identity (matrix); cogl_matrix_multiply (matrix, matrix, &priv->view); } static void clutter_stage_constructed (GObject *gobject) { ClutterStage *self = CLUTTER_STAGE (gobject); ClutterStageManager *stage_manager; stage_manager = clutter_stage_manager_get_default (); /* this will take care to sinking the floating reference */ _clutter_stage_manager_add_stage (stage_manager, self); /* if this stage has been created on a backend that does not * support multiple stages then it becomes the default stage * as well; any other attempt at creating a ClutterStage will * fail. */ if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE)) { if (G_UNLIKELY (clutter_stage_manager_get_default_stage (stage_manager) != NULL)) { g_error ("Unable to create another stage: the backend of " "type '%s' does not support multiple stages. Use " "clutter_stage_manager_get_default_stage() instead " "to access the stage singleton.", G_OBJECT_TYPE_NAME (clutter_get_default_backend ())); } _clutter_stage_manager_set_default_stage (stage_manager, self); } G_OBJECT_CLASS (clutter_stage_parent_class)->constructed (gobject); } static void clutter_stage_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterStage *stage = CLUTTER_STAGE (object); switch (prop_id) { case PROP_COLOR: clutter_actor_set_background_color (CLUTTER_ACTOR (stage), clutter_value_get_color (value)); break; case PROP_OFFSCREEN: if (g_value_get_boolean (value)) g_warning ("Offscreen stages are currently not supported\n"); break; case PROP_CURSOR_VISIBLE: if (g_value_get_boolean (value)) clutter_stage_show_cursor (stage); else clutter_stage_hide_cursor (stage); break; case PROP_PERSPECTIVE: clutter_stage_set_perspective (stage, g_value_get_boxed (value)); break; case PROP_TITLE: clutter_stage_set_title (stage, g_value_get_string (value)); break; case PROP_USER_RESIZABLE: clutter_stage_set_user_resizable (stage, g_value_get_boolean (value)); break; case PROP_USE_FOG: clutter_stage_set_use_fog (stage, g_value_get_boolean (value)); break; case PROP_FOG: clutter_stage_set_fog (stage, g_value_get_boxed (value)); break; case PROP_USE_ALPHA: clutter_stage_set_use_alpha (stage, g_value_get_boolean (value)); break; case PROP_KEY_FOCUS: clutter_stage_set_key_focus (stage, g_value_get_object (value)); break; case PROP_NO_CLEAR_HINT: clutter_stage_set_no_clear_hint (stage, g_value_get_boolean (value)); break; case PROP_ACCEPT_FOCUS: clutter_stage_set_accept_focus (stage, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_stage_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterStagePrivate *priv = CLUTTER_STAGE (gobject)->priv; switch (prop_id) { case PROP_COLOR: { ClutterColor bg_color; clutter_actor_get_background_color (CLUTTER_ACTOR (gobject), &bg_color); clutter_value_set_color (value, &bg_color); } break; case PROP_OFFSCREEN: g_value_set_boolean (value, FALSE); break; case PROP_FULLSCREEN_SET: g_value_set_boolean (value, priv->is_fullscreen); break; case PROP_CURSOR_VISIBLE: g_value_set_boolean (value, priv->is_cursor_visible); break; case PROP_PERSPECTIVE: g_value_set_boxed (value, &priv->perspective); break; case PROP_TITLE: g_value_set_string (value, priv->title); break; case PROP_USER_RESIZABLE: g_value_set_boolean (value, priv->is_user_resizable); break; case PROP_USE_FOG: g_value_set_boolean (value, priv->use_fog); break; case PROP_FOG: g_value_set_boxed (value, &priv->fog); break; case PROP_USE_ALPHA: g_value_set_boolean (value, priv->use_alpha); break; case PROP_KEY_FOCUS: g_value_set_object (value, priv->key_focused_actor); break; case PROP_NO_CLEAR_HINT: { gboolean hint = (priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0; g_value_set_boolean (value, hint); } break; case PROP_ACCEPT_FOCUS: g_value_set_boolean (value, priv->accept_focus); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_stage_dispose (GObject *object) { ClutterStage *stage = CLUTTER_STAGE (object); ClutterStagePrivate *priv = stage->priv; ClutterStageManager *stage_manager; clutter_actor_hide (CLUTTER_ACTOR (object)); _clutter_clear_events_queue_for_stage (stage); if (priv->impl != NULL) { CLUTTER_NOTE (BACKEND, "Disposing of the stage implementation"); if (CLUTTER_ACTOR_IS_REALIZED (object)) _clutter_stage_window_unrealize (priv->impl); g_object_unref (priv->impl); priv->impl = NULL; } clutter_actor_destroy_all_children (CLUTTER_ACTOR (object)); g_list_free_full (priv->pending_queue_redraws, (GDestroyNotify) free_queue_redraw_entry); priv->pending_queue_redraws = NULL; /* this will release the reference on the stage */ stage_manager = clutter_stage_manager_get_default (); _clutter_stage_manager_remove_stage (stage_manager, stage); G_OBJECT_CLASS (clutter_stage_parent_class)->dispose (object); } static void clutter_stage_finalize (GObject *object) { ClutterStage *stage = CLUTTER_STAGE (object); ClutterStagePrivate *priv = stage->priv; g_queue_foreach (priv->event_queue, (GFunc) clutter_event_free, NULL); g_queue_free (priv->event_queue); free (priv->title); g_array_free (priv->paint_volume_stack, TRUE); _clutter_id_pool_free (priv->pick_id_pool); if (priv->fps_timer != NULL) g_timer_destroy (priv->fps_timer); if (priv->paint_notify != NULL) priv->paint_notify (priv->paint_data); G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object); } static void clutter_stage_class_init (ClutterStageClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GParamSpec *pspec; gobject_class->constructed = clutter_stage_constructed; gobject_class->set_property = clutter_stage_set_property; gobject_class->get_property = clutter_stage_get_property; gobject_class->dispose = clutter_stage_dispose; gobject_class->finalize = clutter_stage_finalize; actor_class->allocate = clutter_stage_allocate; actor_class->get_preferred_width = clutter_stage_get_preferred_width; actor_class->get_preferred_height = clutter_stage_get_preferred_height; actor_class->paint = clutter_stage_paint; actor_class->pick = clutter_stage_pick; actor_class->get_paint_volume = clutter_stage_get_paint_volume; actor_class->realize = clutter_stage_realize; actor_class->unrealize = clutter_stage_unrealize; actor_class->show = clutter_stage_show; actor_class->show_all = clutter_stage_show_all; actor_class->hide = clutter_stage_hide; actor_class->hide_all = clutter_stage_hide_all; actor_class->queue_relayout = clutter_stage_real_queue_relayout; actor_class->queue_redraw = clutter_stage_real_queue_redraw; actor_class->apply_transform = clutter_stage_real_apply_transform; /** * ClutterStage:fullscreen: * * Whether the stage should be fullscreen or not. * * This property is set by calling clutter_stage_set_fullscreen() * but since the actual implementation is delegated to the backend * you should connect to the notify::fullscreen-set signal in order * to get notification if the fullscreen state has been successfully * achieved. * * Since: 1.0 */ pspec = g_param_spec_boolean ("fullscreen-set", P_("Fullscreen Set"), P_("Whether the main stage is fullscreen"), FALSE, CLUTTER_PARAM_READABLE); g_object_class_install_property (gobject_class, PROP_FULLSCREEN_SET, pspec); /** * ClutterStage:offscreen: * * Whether the stage should be rendered in an offscreen buffer. * * Deprecated: 1.10: This property does not do anything. */ pspec = g_param_spec_boolean ("offscreen", P_("Offscreen"), P_("Whether the main stage should be rendered offscreen"), FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_class_install_property (gobject_class, PROP_OFFSCREEN, pspec); /** * ClutterStage:cursor-visible: * * Whether the mouse pointer should be visible */ pspec = g_param_spec_boolean ("cursor-visible", P_("Cursor Visible"), P_("Whether the mouse pointer is visible on the main stage"), TRUE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CURSOR_VISIBLE, pspec); /** * ClutterStage:user-resizable: * * Whether the stage is resizable via user interaction. * * Since: 0.4 */ pspec = g_param_spec_boolean ("user-resizable", P_("User Resizable"), P_("Whether the stage is able to be resized via user interaction"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_USER_RESIZABLE, pspec); /** * ClutterStage:color: * * The background color of the main stage. * * Deprecated: 1.10: Use the #ClutterActor:background-color property of * #ClutterActor instead. */ pspec = clutter_param_spec_color ("color", P_("Color"), P_("The color of the stage"), &default_stage_color, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_class_install_property (gobject_class, PROP_COLOR, pspec); /** * ClutterStage:perspective: * * The parameters used for the perspective projection from 3D * coordinates to 2D * * Since: 0.8 */ pspec = g_param_spec_boxed ("perspective", P_("Perspective"), P_("Perspective projection parameters"), CLUTTER_TYPE_PERSPECTIVE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_PERSPECTIVE, pspec); /** * ClutterStage:title: * * The stage's title - usually displayed in stage windows title decorations. * * Since: 0.4 */ pspec = g_param_spec_string ("title", P_("Title"), P_("Stage Title"), NULL, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_TITLE, pspec); /** * ClutterStage:use-fog: * * Whether the stage should use a linear GL "fog" in creating the * depth-cueing effect, to enhance the perception of depth by fading * actors farther from the viewpoint. * * Since: 0.6 * * Deprecated: 1.10: This property does not do anything. */ pspec = g_param_spec_boolean ("use-fog", P_("Use Fog"), P_("Whether to enable depth cueing"), FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_class_install_property (gobject_class, PROP_USE_FOG, pspec); /** * ClutterStage:fog: * * The settings for the GL "fog", used only if #ClutterStage:use-fog * is set to %TRUE * * Since: 1.0 * * Deprecated: 1.10: This property does not do anything. */ pspec = g_param_spec_boxed ("fog", P_("Fog"), P_("Settings for the depth cueing"), CLUTTER_TYPE_FOG, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_class_install_property (gobject_class, PROP_FOG, pspec); /** * ClutterStage:use-alpha: * * Whether the #ClutterStage should honour the alpha component of the * #ClutterStage:color property when painting. If Clutter is run under * a compositing manager this will result in the stage being blended * with the underlying window(s) * * Since: 1.2 */ pspec = g_param_spec_boolean ("use-alpha", P_("Use Alpha"), P_("Whether to honour the alpha component of the stage color"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_USE_ALPHA, pspec); /** * ClutterStage:key-focus: * * The #ClutterActor that will receive key events from the underlying * windowing system. * * If %NULL, the #ClutterStage will receive the events. * * Since: 1.2 */ pspec = g_param_spec_object ("key-focus", P_("Key Focus"), P_("The currently key focused actor"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_KEY_FOCUS, pspec); /** * ClutterStage:no-clear-hint: * * Whether or not the #ClutterStage should clear its contents * before each paint cycle. * * See clutter_stage_set_no_clear_hint() for further information. * * Since: 1.4 */ pspec = g_param_spec_boolean ("no-clear-hint", P_("No Clear Hint"), P_("Whether the stage should clear its contents"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_NO_CLEAR_HINT, pspec); /** * ClutterStage:accept-focus: * * Whether the #ClutterStage should accept key focus when shown. * * Since: 1.6 */ pspec = g_param_spec_boolean ("accept-focus", P_("Accept Focus"), P_("Whether the stage should accept focus on show"), TRUE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_ACCEPT_FOCUS, pspec); /** * ClutterStage::fullscreen: * @stage: the stage which was fullscreened * * The ::fullscreen signal is emitted when the stage is made fullscreen. * * Since: 0.6 */ stage_signals[FULLSCREEN] = g_signal_new (I_("fullscreen"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterStageClass, fullscreen), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterStage::unfullscreen: * @stage: the stage which has left a fullscreen state. * * The ::unfullscreen signal is emitted when the stage leaves a fullscreen * state. * * Since: 0.6 */ stage_signals[UNFULLSCREEN] = g_signal_new (I_("unfullscreen"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterStageClass, unfullscreen), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterStage::activate: * @stage: the stage which was activated * * The ::activate signal is emitted when the stage receives key focus * from the underlying window system. * * Since: 0.6 */ stage_signals[ACTIVATE] = g_signal_new (I_("activate"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterStageClass, activate), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterStage::deactivate: * @stage: the stage which was deactivated * * The ::deactivate signal is emitted when the stage loses key focus * from the underlying window system. * * Since: 0.6 */ stage_signals[DEACTIVATE] = g_signal_new (I_("deactivate"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterStageClass, deactivate), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterStage::delete-event: * @stage: the stage that received the event * @event: a #ClutterEvent of type %CLUTTER_DELETE * * The ::delete-event signal is emitted when the user closes a * #ClutterStage window using the window controls. * * Clutter by default will call clutter_main_quit() if @stage is * the default stage, and clutter_actor_destroy() for any other * stage. * * It is possible to override the default behaviour by connecting * a new handler and returning %TRUE there. * * This signal is emitted only on Clutter backends that * embed #ClutterStage in native windows. It is not emitted for * backends that use a static frame buffer. * * Since: 1.2 */ stage_signals[DELETE_EVENT] = g_signal_new (I_("delete-event"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterStageClass, delete_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterStage::after-paint: * @stage: the stage that received the event * * The ::after-paint signal is emitted after the stage is painted, * but before the results are displayed on the screen. * * Since: 1.20 */ stage_signals[AFTER_PAINT] = g_signal_new (I_("after-paint"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, 0, /* no corresponding vfunc */ NULL, NULL, NULL, G_TYPE_NONE, 0); /** * ClutterStage::presented: (skip) * @stage: the stage that received the event * @frame_event: a #CoglFrameEvent * @frame_info: a #ClutterFrameInfo */ stage_signals[PRESENTED] = g_signal_new (I_("presented"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__INT_POINTER, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER); klass->fullscreen = clutter_stage_real_fullscreen; klass->activate = clutter_stage_real_activate; klass->deactivate = clutter_stage_real_deactivate; klass->delete_event = clutter_stage_real_delete_event; } static void clutter_stage_notify_min_size (ClutterStage *self) { self->priv->min_size_changed = TRUE; } static void clutter_stage_init (ClutterStage *self) { cairo_rectangle_int_t geom = { 0, }; ClutterStagePrivate *priv; ClutterStageWindow *impl; ClutterBackend *backend; GError *error; /* a stage is a top-level object */ CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IS_TOPLEVEL); self->priv = priv = clutter_stage_get_instance_private (self); CLUTTER_NOTE (BACKEND, "Creating stage from the default backend"); backend = clutter_get_default_backend (); error = NULL; impl = _clutter_backend_create_stage (backend, self, &error); if (G_LIKELY (impl != NULL)) { _clutter_stage_set_window (self, impl); _clutter_stage_window_get_geometry (priv->impl, &geom); } else { if (error != NULL) { g_critical ("Unable to create a new stage implementation: %s", error->message); g_error_free (error); } else g_critical ("Unable to create a new stage implementation."); } priv->event_queue = g_queue_new (); priv->is_fullscreen = FALSE; priv->is_user_resizable = FALSE; priv->is_cursor_visible = TRUE; priv->use_fog = FALSE; priv->throttle_motion_events = TRUE; priv->min_size_changed = FALSE; priv->sync_delay = -1; /* XXX - we need to keep the invariant that calling * clutter_set_motion_event_enabled() before the stage creation * will cause motion event delivery to be disabled on any newly * created stage. this can go away when we break API and remove * deprecated functions. */ priv->motion_events_enabled = _clutter_context_get_motion_events_enabled (); clutter_actor_set_background_color (CLUTTER_ACTOR (self), &default_stage_color); priv->perspective.fovy = 60.0; /* 60 Degrees */ priv->perspective.aspect = (float) geom.width / (float) geom.height; priv->perspective.z_near = 0.1; priv->perspective.z_far = 100.0; cogl_matrix_init_identity (&priv->projection); cogl_matrix_perspective (&priv->projection, priv->perspective.fovy, priv->perspective.aspect, priv->perspective.z_near, priv->perspective.z_far); cogl_matrix_get_inverse (&priv->projection, &priv->inverse_projection); cogl_matrix_init_identity (&priv->view); cogl_matrix_view_2d_in_perspective (&priv->view, priv->perspective.fovy, priv->perspective.aspect, priv->perspective.z_near, 50, /* distance to 2d plane */ geom.width, geom.height); /* FIXME - remove for 2.0 */ priv->fog.z_near = 1.0; priv->fog.z_far = 2.0; priv->relayout_pending = TRUE; clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); clutter_stage_set_title (self, g_get_prgname ()); clutter_stage_set_key_focus (self, NULL); g_signal_connect (self, "notify::min-width", G_CALLBACK (clutter_stage_notify_min_size), NULL); g_signal_connect (self, "notify::min-height", G_CALLBACK (clutter_stage_notify_min_size), NULL); _clutter_stage_set_viewport (self, 0, 0, geom.width, geom.height); priv->paint_volume_stack = g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume)); priv->pick_id_pool = _clutter_id_pool_new (256); } /** * clutter_stage_get_default: * * Retrieves a #ClutterStage singleton. * * This function is not as useful as it sounds, and will most likely * by deprecated in the future. Application code should only create * a #ClutterStage instance using clutter_stage_new(), and manage the * lifetime of the stage manually. * * The default stage singleton has a platform-specific behaviour: on * platforms without the %CLUTTER_FEATURE_STAGE_MULTIPLE feature flag * set, the first #ClutterStage instance will also be set to be the * default stage instance, and this function will always return a * pointer to it. * * On platforms with the %CLUTTER_FEATURE_STAGE_MULTIPLE feature flag * set, the default stage will be created by the first call to this * function, and every following call will return the same pointer to * it. * * Return value: (transfer none) (type Clutter.Stage): the main * #ClutterStage. You should never destroy or unref the returned * actor. * * Deprecated: 1.10: Use clutter_stage_new() instead. */ ClutterActor * clutter_stage_get_default (void) { ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); ClutterStage *stage; stage = clutter_stage_manager_get_default_stage (stage_manager); if (G_UNLIKELY (stage == NULL)) { /* This will take care of automatically adding the stage to the * stage manager and setting it as the default. Its floating * reference will be claimed by the stage manager. */ stage = g_object_new (CLUTTER_TYPE_STAGE, NULL); _clutter_stage_manager_set_default_stage (stage_manager, stage); /* the default stage is realized by default */ clutter_actor_realize (CLUTTER_ACTOR (stage)); } return CLUTTER_ACTOR (stage); } /** * clutter_stage_set_color: * @stage: A #ClutterStage * @color: A #ClutterColor * * Sets the stage color. * * Deprecated: 1.10: Use clutter_actor_set_background_color() instead. */ void clutter_stage_set_color (ClutterStage *stage, const ClutterColor *color) { clutter_actor_set_background_color (CLUTTER_ACTOR (stage), color); g_object_notify (G_OBJECT (stage), "color"); } /** * clutter_stage_get_color: * @stage: A #ClutterStage * @color: (out caller-allocates): return location for a #ClutterColor * * Retrieves the stage color. * * Deprecated: 1.10: Use clutter_actor_get_background_color() instead. */ void clutter_stage_get_color (ClutterStage *stage, ClutterColor *color) { clutter_actor_get_background_color (CLUTTER_ACTOR (stage), color); } static void clutter_stage_set_perspective_internal (ClutterStage *stage, ClutterPerspective *perspective) { ClutterStagePrivate *priv = stage->priv; if (priv->perspective.fovy == perspective->fovy && priv->perspective.aspect == perspective->aspect && priv->perspective.z_near == perspective->z_near && priv->perspective.z_far == perspective->z_far) return; priv->perspective = *perspective; cogl_matrix_init_identity (&priv->projection); cogl_matrix_perspective (&priv->projection, priv->perspective.fovy, priv->perspective.aspect, priv->perspective.z_near, priv->perspective.z_far); cogl_matrix_get_inverse (&priv->projection, &priv->inverse_projection); _clutter_stage_dirty_projection (stage); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); } /** * clutter_stage_set_perspective: * @stage: A #ClutterStage * @perspective: A #ClutterPerspective * * Sets the stage perspective. Using this function is not recommended * because it will disable Clutter's attempts to generate an * appropriate perspective based on the size of the stage. */ void clutter_stage_set_perspective (ClutterStage *stage, ClutterPerspective *perspective) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (perspective != NULL); g_return_if_fail (perspective->z_far - perspective->z_near != 0); priv = stage->priv; /* If the application ever calls this function then we'll stop automatically updating the perspective when the stage changes size */ priv->has_custom_perspective = TRUE; clutter_stage_set_perspective_internal (stage, perspective); } /** * clutter_stage_get_perspective: * @stage: A #ClutterStage * @perspective: (out caller-allocates) (allow-none): return location for a * #ClutterPerspective * * Retrieves the stage perspective. */ void clutter_stage_get_perspective (ClutterStage *stage, ClutterPerspective *perspective) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (perspective != NULL); *perspective = stage->priv->perspective; } /* * clutter_stage_get_projection_matrix: * @stage: A #ClutterStage * @projection: return location for a #CoglMatrix representing the * perspective projection applied to actors on the given * @stage. * * Retrieves the @stage's projection matrix. This is derived from the * current perspective set using clutter_stage_set_perspective(). * * Since: 1.6 */ void _clutter_stage_get_projection_matrix (ClutterStage *stage, CoglMatrix *projection) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (projection != NULL); *projection = stage->priv->projection; } /* This simply provides a simple mechanism for us to ensure that * the projection matrix gets re-asserted before painting. * * This is used when switching between multiple stages */ void _clutter_stage_dirty_projection (ClutterStage *stage) { ClutterStagePrivate *priv; GList *l; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next) { ClutterStageView *view = l->data; clutter_stage_view_set_dirty_projection (view, TRUE); } } /* * clutter_stage_set_viewport: * @stage: A #ClutterStage * @x: The X postition to render the stage at, in window coordinates * @y: The Y position to render the stage at, in window coordinates * @width: The width to render the stage at, in window coordinates * @height: The height to render the stage at, in window coordinates * * Sets the stage viewport. The viewport defines a final scale and * translation of your rendered stage and actors. This lets you render * your stage into a subregion of the stage window or you could use it to * pan a subregion of the stage if your stage window is smaller then * the stage. (XXX: currently this isn't possible) * * Unlike a scale and translation done using the modelview matrix this * is done after everything has had perspective projection applied, so * for example if you were to pan across a subregion of the stage using * the viewport then you would not see a change in perspective for the * actors on the stage. * * Normally the stage viewport will automatically track the size of the * stage window with no offset so the stage will fill your window. This * behaviour can be changed with the "viewport-mimics-window" property * which will automatically be set to FALSE if you use this API. If * you want to revert to the original behaviour then you should set * this property back to %TRUE using * clutter_stage_set_viewport_mimics_window(). * (XXX: If we were to make this API public then we might want to do * add that property.) * * Note: currently this interface only support integer precision * offsets and sizes for viewports but the interface takes floats because * OpenGL 4.0 has introduced floating point viewports which we might * want to expose via this API eventually. * * Since: 1.6 */ void _clutter_stage_set_viewport (ClutterStage *stage, float x, float y, float width, float height) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (x == priv->viewport[0] && y == priv->viewport[1] && width == priv->viewport[2] && height == priv->viewport[3]) return; priv->viewport[0] = x; priv->viewport[1] = y; priv->viewport[2] = width; priv->viewport[3] = height; _clutter_stage_dirty_viewport (stage); queue_full_redraw (stage); } /* This simply provides a simple mechanism for us to ensure that * the viewport gets re-asserted before next painting. * * This is used when switching between multiple stages */ void _clutter_stage_dirty_viewport (ClutterStage *stage) { ClutterStagePrivate *priv; GList *l; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next) { ClutterStageView *view = l->data; clutter_stage_view_set_dirty_viewport (view, TRUE); } } /* * clutter_stage_get_viewport: * @stage: A #ClutterStage * @x: A location for the X position where the stage is rendered, * in window coordinates. * @y: A location for the Y position where the stage is rendered, * in window coordinates. * @width: A location for the width the stage is rendered at, * in window coordinates. * @height: A location for the height the stage is rendered at, * in window coordinates. * * Returns the viewport offset and size set using * clutter_stage_set_viewport() or if the "viewport-mimics-window" property * is TRUE then @x and @y will be set to 0 and @width and @height will equal * the width if the stage window. * * Since: 1.6 */ void _clutter_stage_get_viewport (ClutterStage *stage, float *x, float *y, float *width, float *height) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; *x = priv->viewport[0]; *y = priv->viewport[1]; *width = priv->viewport[2]; *height = priv->viewport[3]; } /** * clutter_stage_set_fullscreen: * @stage: a #ClutterStage * @fullscreen: %TRUE to to set the stage fullscreen * * Asks to place the stage window in the fullscreen or unfullscreen * states. * ( Note that you shouldn't assume the window is definitely full screen * afterward, because other entities (e.g. the user or window manager) * could unfullscreen it again, and not all window managers honor * requests to fullscreen windows. * * If you want to receive notification of the fullscreen state you * should either use the #ClutterStage::fullscreen and * #ClutterStage::unfullscreen signals, or use the notify signal * for the #ClutterStage:fullscreen-set property * * Since: 1.0 */ void clutter_stage_set_fullscreen (ClutterStage *stage, gboolean fullscreen) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (priv->is_fullscreen != fullscreen) { ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl); ClutterStageWindowIface *iface; iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl); /* Only set if backend implements. * * Also see clutter_stage_event() for setting priv->is_fullscreen * on state change event. */ if (iface->set_fullscreen) iface->set_fullscreen (impl, fullscreen); } /* If the backend did fullscreen the stage window then we need to resize * the stage and update its viewport so we queue a relayout. Note: if the * fullscreen request is handled asynchronously we can't rely on this * queue_relayout to update the viewport, but for example the X backend * will recieve a ConfigureNotify after a successful resize which is how * we ensure the viewport is updated on X. */ clutter_actor_queue_relayout (CLUTTER_ACTOR (stage)); } /** * clutter_stage_get_fullscreen: * @stage: a #ClutterStage * * Retrieves whether the stage is full screen or not * * Return value: %TRUE if the stage is full screen * * Since: 1.0 */ gboolean clutter_stage_get_fullscreen (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return stage->priv->is_fullscreen; } /** * clutter_stage_set_user_resizable: * @stage: a #ClutterStage * @resizable: whether the stage should be user resizable. * * Sets if the stage is resizable by user interaction (e.g. via * window manager controls) * * Since: 0.4 */ void clutter_stage_set_user_resizable (ClutterStage *stage, gboolean resizable) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (clutter_feature_available (CLUTTER_FEATURE_STAGE_USER_RESIZE) && priv->is_user_resizable != resizable) { ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl); ClutterStageWindowIface *iface; iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl); if (iface->set_user_resizable) { priv->is_user_resizable = resizable; iface->set_user_resizable (impl, resizable); g_object_notify (G_OBJECT (stage), "user-resizable"); } } } /** * clutter_stage_get_user_resizable: * @stage: a #ClutterStage * * Retrieves the value set with clutter_stage_set_user_resizable(). * * Return value: %TRUE if the stage is resizable by the user. * * Since: 0.4 */ gboolean clutter_stage_get_user_resizable (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return stage->priv->is_user_resizable; } /** * clutter_stage_show_cursor: * @stage: a #ClutterStage * * Shows the cursor on the stage window */ void clutter_stage_show_cursor (ClutterStage *stage) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (!priv->is_cursor_visible) { ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl); ClutterStageWindowIface *iface; iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl); if (iface->set_cursor_visible) { priv->is_cursor_visible = TRUE; iface->set_cursor_visible (impl, TRUE); g_object_notify (G_OBJECT (stage), "cursor-visible"); } } } /** * clutter_stage_hide_cursor: * @stage: a #ClutterStage * * Makes the cursor invisible on the stage window * * Since: 0.4 */ void clutter_stage_hide_cursor (ClutterStage *stage) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (priv->is_cursor_visible) { ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl); ClutterStageWindowIface *iface; iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl); if (iface->set_cursor_visible) { priv->is_cursor_visible = FALSE; iface->set_cursor_visible (impl, FALSE); g_object_notify (G_OBJECT (stage), "cursor-visible"); } } } /** * clutter_stage_read_pixels: * @stage: A #ClutterStage * @x: x coordinate of the first pixel that is read from stage * @y: y coordinate of the first pixel that is read from stage * @width: Width dimention of pixels to be read, or -1 for the * entire stage width * @height: Height dimention of pixels to be read, or -1 for the * entire stage height * * Makes a screenshot of the stage in RGBA 8bit data, returns a * linear buffer with @width * 4 as rowstride. * * The alpha data contained in the returned buffer is driver-dependent, * and not guaranteed to hold any sensible value. * * Return value: (transfer full) (array): a pointer to newly allocated memory with the buffer * or %NULL if the read failed. Use free() on the returned data * to release the resources it has allocated. */ guchar * clutter_stage_read_pixels (ClutterStage *stage, gint x, gint y, gint width, gint height) { ClutterStagePrivate *priv; ClutterActorBox box; GList *l; ClutterStageView *view; cairo_region_t *clip; cairo_rectangle_int_t clip_rect; CoglFramebuffer *framebuffer; uint8_t *pixels; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); priv = stage->priv; clutter_actor_get_allocation_box (CLUTTER_ACTOR (stage), &box); if (width < 0) width = ceilf (box.x2 - box.x1); if (height < 0) height = ceilf (box.y2 - box.y1); l = _clutter_stage_window_get_views (priv->impl); if (!l) return NULL; /* XXX: We only read the first view. Needs different API for multi view screen * capture. */ view = l->data; clutter_stage_view_get_layout (view, &clip_rect); clip = cairo_region_create_rectangle (&clip_rect); cairo_region_intersect_rectangle (clip, &(cairo_rectangle_int_t) { .x = x, .y = y, .width = width, .height = height, }); cairo_region_get_extents (clip, &clip_rect); cairo_region_destroy (clip); if (clip_rect.width == 0 || clip_rect.height == 0) return NULL; framebuffer = clutter_stage_view_get_framebuffer (view); cogl_push_framebuffer (framebuffer); clutter_stage_do_paint_view (stage, view, &clip_rect); pixels = calloc (1, clip_rect.width * clip_rect.height * 4); cogl_framebuffer_read_pixels (framebuffer, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height, COGL_PIXEL_FORMAT_RGBA_8888, pixels); cogl_pop_framebuffer (); return pixels; } /** * clutter_stage_get_actor_at_pos: * @stage: a #ClutterStage * @pick_mode: how the scene graph should be painted * @x: X coordinate to check * @y: Y coordinate to check * * Checks the scene at the coordinates @x and @y and returns a pointer * to the #ClutterActor at those coordinates. * * By using @pick_mode it is possible to control which actors will be * painted and thus available. * * Return value: (transfer none): the actor at the specified coordinates, * if any */ ClutterActor * clutter_stage_get_actor_at_pos (ClutterStage *stage, ClutterPickMode pick_mode, gint x, gint y) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); return _clutter_stage_do_pick (stage, x, y, pick_mode); } /** * clutter_stage_event: * @stage: a #ClutterStage * @event: a #ClutterEvent * * This function is used to emit an event on the main stage. * * You should rarely need to use this function, except for * synthetised events. * * Return value: the return value from the signal emission * * Since: 0.4 */ gboolean clutter_stage_event (ClutterStage *stage, ClutterEvent *event) { ClutterStagePrivate *priv; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (event != NULL, FALSE); priv = stage->priv; if (event->type == CLUTTER_DELETE) { gboolean retval = FALSE; g_signal_emit_by_name (stage, "event", event, &retval); if (!retval) g_signal_emit_by_name (stage, "delete-event", event, &retval); return retval; } if (event->type != CLUTTER_STAGE_STATE) return FALSE; /* emit raw event */ if (clutter_actor_event (CLUTTER_ACTOR (stage), event, FALSE)) return TRUE; if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_FULLSCREEN) { if (event->stage_state.new_state & CLUTTER_STAGE_STATE_FULLSCREEN) { priv->is_fullscreen = TRUE; g_signal_emit (stage, stage_signals[FULLSCREEN], 0); g_object_notify (G_OBJECT (stage), "fullscreen-set"); } else { priv->is_fullscreen = FALSE; g_signal_emit (stage, stage_signals[UNFULLSCREEN], 0); g_object_notify (G_OBJECT (stage), "fullscreen-set"); } } if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_ACTIVATED) { if (event->stage_state.new_state & CLUTTER_STAGE_STATE_ACTIVATED) g_signal_emit (stage, stage_signals[ACTIVATE], 0); else g_signal_emit (stage, stage_signals[DEACTIVATE], 0); } return TRUE; } /** * clutter_stage_set_title: * @stage: A #ClutterStage * @title: A utf8 string for the stage windows title. * * Sets the stage title. * * Since: 0.4 **/ void clutter_stage_set_title (ClutterStage *stage, const gchar *title) { ClutterStagePrivate *priv; ClutterStageWindow *impl; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; free (priv->title); priv->title = g_strdup (title); impl = CLUTTER_STAGE_WINDOW (priv->impl); if (CLUTTER_STAGE_WINDOW_GET_IFACE(impl)->set_title != NULL) CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->set_title (impl, priv->title); g_object_notify (G_OBJECT (stage), "title"); } /** * clutter_stage_get_title: * @stage: A #ClutterStage * * Gets the stage title. * * Return value: pointer to the title string for the stage. The * returned string is owned by the actor and should not * be modified or freed. * * Since: 0.4 **/ const gchar * clutter_stage_get_title (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); return stage->priv->title; } static void on_key_focus_destroy (ClutterActor *actor, ClutterStage *stage) { /* unset the key focus */ clutter_stage_set_key_focus (stage, NULL); } /** * clutter_stage_set_key_focus: * @stage: the #ClutterStage * @actor: (allow-none): the actor to set key focus to, or %NULL * * Sets the key focus on @actor. An actor with key focus will receive * all the key events. If @actor is %NULL, the stage will receive * focus. * * Since: 0.6 */ void clutter_stage_set_key_focus (ClutterStage *stage, ClutterActor *actor) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor)); priv = stage->priv; /* normalize the key focus. NULL == stage */ if (actor == CLUTTER_ACTOR (stage)) actor = NULL; /* avoid emitting signals and notifications if we're setting the same * actor as the key focus */ if (priv->key_focused_actor == actor) return; if (priv->key_focused_actor != NULL) { ClutterActor *old_focused_actor; old_focused_actor = priv->key_focused_actor; /* set key_focused_actor to NULL before emitting the signal or someone * might hide the previously focused actor in the signal handler and we'd * get re-entrant call and get glib critical from g_object_weak_unref */ g_signal_handlers_disconnect_by_func (priv->key_focused_actor, G_CALLBACK (on_key_focus_destroy), stage); priv->key_focused_actor = NULL; g_signal_emit_by_name (old_focused_actor, "key-focus-out"); } else g_signal_emit_by_name (stage, "key-focus-out"); /* Note, if someone changes key focus in focus-out signal handler we'd be * overriding the latter call below moving the focus where it was originally * intended. The order of events would be: * 1st focus-out, 2nd focus-out (on stage), 2nd focus-in, 1st focus-in */ if (actor != NULL) { priv->key_focused_actor = actor; g_signal_connect (actor, "destroy", G_CALLBACK (on_key_focus_destroy), stage); g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in"); } else g_signal_emit_by_name (stage, "key-focus-in"); g_object_notify (G_OBJECT (stage), "key-focus"); } /** * clutter_stage_get_key_focus: * @stage: the #ClutterStage * * Retrieves the actor that is currently under key focus. * * Return value: (transfer none): the actor with key focus, or the stage * * Since: 0.6 */ ClutterActor * clutter_stage_get_key_focus (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); if (stage->priv->key_focused_actor) return stage->priv->key_focused_actor; return CLUTTER_ACTOR (stage); } /** * clutter_stage_get_use_fog: * @stage: the #ClutterStage * * Gets whether the depth cueing effect is enabled on @stage. * * Return value: %TRUE if the depth cueing effect is enabled * * Since: 0.6 * * Deprecated: 1.10: This function will always return %FALSE */ gboolean clutter_stage_get_use_fog (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return stage->priv->use_fog; } /** * clutter_stage_set_use_fog: * @stage: the #ClutterStage * @fog: %TRUE for enabling the depth cueing effect * * Sets whether the depth cueing effect on the stage should be enabled * or not. * * Depth cueing is a 3D effect that makes actors farther away from the * viewing point less opaque, by fading them with the stage color. * The parameters of the GL fog used can be changed using the * clutter_stage_set_fog() function. * * Since: 0.6 * * Deprecated: 1.10: Calling this function produces no visible effect */ void clutter_stage_set_use_fog (ClutterStage *stage, gboolean fog) { } /** * clutter_stage_set_fog: * @stage: the #ClutterStage * @fog: a #ClutterFog structure * * Sets the fog (also known as "depth cueing") settings for the @stage. * * A #ClutterStage will only use a linear fog progression, which * depends solely on the distance from the viewer. The cogl_set_fog() * function in COGL exposes more of the underlying implementation, * and allows changing the for progression function. It can be directly * used by disabling the #ClutterStage:use-fog property and connecting * a signal handler to the #ClutterActor::paint signal on the @stage, * like: * * |[ * clutter_stage_set_use_fog (stage, FALSE); * g_signal_connect (stage, "paint", G_CALLBACK (on_stage_paint), NULL); * ]| * * The paint signal handler will call cogl_set_fog() with the * desired settings: * * |[ * static void * on_stage_paint (ClutterActor *actor) * { * ClutterColor stage_color = { 0, }; * CoglColor fog_color = { 0, }; * * // set the fog color to the stage background color * clutter_stage_get_color (CLUTTER_STAGE (actor), &stage_color); * cogl_color_init_from_4ub (&fog_color, * stage_color.red, * stage_color.green, * stage_color.blue, * stage_color.alpha); * * // enable fog // * cogl_set_fog (&fog_color, * COGL_FOG_MODE_EXPONENTIAL, // mode * 0.5, // density * 5.0, 30.0); // z_near and z_far * } * ]| * * The fogging functions only work correctly when the visible actors use * unmultiplied alpha colors. By default Cogl will premultiply textures and * cogl_set_source_color() will premultiply colors, so unless you explicitly * load your textures requesting an unmultiplied internal format and use * cogl_material_set_color() you can only use fogging with fully opaque actors. * Support for premultiplied colors will improve in the future when we can * depend on fragment shaders. * * Since: 0.6 * * Deprecated: 1.10: Fog settings are ignored. */ void clutter_stage_set_fog (ClutterStage *stage, ClutterFog *fog) { } /** * clutter_stage_get_fog: * @stage: the #ClutterStage * @fog: (out): return location for a #ClutterFog structure * * Retrieves the current depth cueing settings from the stage. * * Since: 0.6 * * Deprecated: 1.10: This function will always return the default * values of #ClutterFog */ void clutter_stage_get_fog (ClutterStage *stage, ClutterFog *fog) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (fog != NULL); *fog = stage->priv->fog; } /*** Perspective boxed type ******/ static gpointer clutter_perspective_copy (gpointer data) { if (G_LIKELY (data)) return g_slice_dup (ClutterPerspective, data); return NULL; } static void clutter_perspective_free (gpointer data) { if (G_LIKELY (data)) g_slice_free (ClutterPerspective, data); } G_DEFINE_BOXED_TYPE (ClutterPerspective, clutter_perspective, clutter_perspective_copy, clutter_perspective_free); static gpointer clutter_fog_copy (gpointer data) { if (G_LIKELY (data)) return g_slice_dup (ClutterFog, data); return NULL; } static void clutter_fog_free (gpointer data) { if (G_LIKELY (data)) g_slice_free (ClutterFog, data); } G_DEFINE_BOXED_TYPE (ClutterFog, clutter_fog, clutter_fog_copy, clutter_fog_free); /** * clutter_stage_new: * * Creates a new, non-default stage. A non-default stage is a new * top-level actor which can be used as another container. It works * exactly like the default stage, but while clutter_stage_get_default() * will always return the same instance, you will have to keep a pointer * to any #ClutterStage returned by clutter_stage_new(). * * The ability to support multiple stages depends on the current * backend. Use clutter_feature_available() and * %CLUTTER_FEATURE_STAGE_MULTIPLE to check at runtime whether a * backend supports multiple stages. * * Return value: a new stage, or %NULL if the default backend does * not support multiple stages. Use clutter_actor_destroy() to * programmatically close the returned stage. * * Since: 0.8 */ ClutterActor * clutter_stage_new (void) { return g_object_new (CLUTTER_TYPE_STAGE, NULL); } /** * clutter_stage_ensure_current: * @stage: the #ClutterStage * * This function essentially makes sure the right GL context is * current for the passed stage. It is not intended to * be used by applications. * * Since: 0.8 * Deprecated: muffin: This function does not do anything. */ void clutter_stage_ensure_current (ClutterStage *stage) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); } /** * clutter_stage_ensure_viewport: * @stage: a #ClutterStage * * Ensures that the GL viewport is updated with the current * stage window size. * * This function will queue a redraw of @stage. * * This function should not be called by applications; it is used * when embedding a #ClutterStage into a toolkit with another * windowing system, like GTK+. * * Since: 1.0 */ void clutter_stage_ensure_viewport (ClutterStage *stage) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); _clutter_stage_dirty_viewport (stage); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); } # define _DEG_TO_RAD(d) ((d) * ((float) G_PI / 180.0f)) /* This calculates a distance into the view frustum to position the * stage so there is a decent amount of space to position geometry * between the stage and the near clipping plane. * * Some awkward issues with this problem are: * - It's not possible to have a gap as large as the stage size with * a fov > 53° which is basically always the case since the default * fov is 60°. * - This can be deduced if you consider that this requires a * triangle as wide as it is deep to fit in the frustum in front * of the z_near plane. That triangle will always have an angle * of 53.13° at the point sitting on the z_near plane, but if the * frustum has a wider fov angle the left/right clipping planes * can never converge with the two corners of our triangle no * matter what size the triangle has. * - With a fov > 53° there is a trade off between maximizing the gap * size relative to the stage size but not loosing depth precision. * - Perhaps ideally we wouldn't just consider the fov on the y-axis * that is usually used to define a perspective, we would consider * the fov of the axis with the largest stage size so the gap would * accommodate that size best. * * After going around in circles a few times with how to handle these * issues, we decided in the end to go for the simplest solution to * start with instead of an elaborate function that handles arbitrary * fov angles that we currently have no use-case for. * * The solution assumes a fovy of 60° and for that case gives a gap * that's 85% of the stage height. We can consider more elaborate * functions if necessary later. * * One guide we had to steer the gap size we support is the * interactive test, test-texture-quality which expects to animate an * actor to +400 on the z axis with a stage size of 640x480. A gap * that's 85% of the stage height gives a gap of 408 in that case. */ static float calculate_z_translation (float z_near) { /* This solution uses fairly basic trigonometry, but is seems worth * clarifying the particular geometry we are looking at in-case * anyone wants to develop this further later. Not sure how well an * ascii diagram is going to work :-) * * |--- stage_height ---| * | stage line | * ╲━━━━━━━━━━━━━━━━━━━━━╱------------ * ╲. (2) │ .╱ | | * C ╲ . │ . ╱ gap| | * =0.5°╲ . a │ . ╱ | | * b╲(1). D│ . ╱ | | * ╲ B.│. ╱near plane | | * A= ╲━━━━━━━━━╱------------- | * 120° ╲ c │ ╱ | z_2d * ╲ │ ╱ z_near | * left ╲ │ ╱ | | * clip 60°fovy | | * plane ╳---------------------- * | * | * origin line * * The area of interest is the triangle labeled (1) at the top left * marked with the ... line (a) from where the origin line crosses * the near plane to the top left where the stage line cross the * left clip plane. * * The sides of the triangle are a, b and c and the corresponding * angles opposite those sides are A, B and C. * * The angle of C is what trades off the gap size we have relative * to the stage size vs the depth precision we have. * * As mentioned above we arove at the angle for C is by working * backwards from how much space we want for test-texture-quality. * With a stage_height of 480 we want a gap > 400, ideally we also * wanted a somewhat round number as a percentage of the height for * documentation purposes. ~87% or a gap of ~416 is the limit * because that's where we approach a C angle of 0° and effectively * loose all depth precision. * * So for our test app with a stage_height of 480 if we aim for a * gap of 408 (85% of 480) we can get the angle D as * atan (stage_height/2/408) = 30.5°. * * That gives us the angle for B as 90° - 30.5° = 59.5° * * We can already determine that A has an angle of (fovy/2 + 90°) = * 120° * * Therefore C = 180 - A - B = 0.5° * * The length of c = z_near * tan (30°) * * Now we can use the rule a/SinA = c/SinC to calculate the * length of a. After some rearranging that gives us: * * a c * ---------- = ---------- * sin (120°) sin (0.5°) * * c * sin (120°) * a = -------------- * sin (0.5°) * * And with that we can determine z_2d = cos (D) * a = * cos (30.5°) * a + z_near: * * c * sin (120°) * cos (30.5°) * z_2d = --------------------------- + z_near * sin (0.5°) */ /* We expect the compiler should boil this down to z_near * CONSTANT * already, but just in case we use precomputed constants */ #if 0 # define A tanf (_DEG_TO_RAD (30.f)) # define B sinf (_DEG_TO_RAD (120.f)) # define C cosf (_DEG_TO_RAD (30.5f)) # define D sinf (_DEG_TO_RAD (.5f)) #else # define A 0.57735025882720947265625f # define B 0.866025388240814208984375f # define C 0.86162912845611572265625f # define D 0.00872653536498546600341796875f #endif return z_near * A * B * C / D + z_near; } void _clutter_stage_maybe_setup_viewport (ClutterStage *stage, ClutterStageView *view) { ClutterStagePrivate *priv = stage->priv; CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view); if (clutter_stage_view_is_dirty_viewport (view)) { cairo_rectangle_int_t view_layout; ClutterPerspective perspective; float fb_scale; float viewport_offset_x; float viewport_offset_y; float z_2d; CLUTTER_NOTE (PAINT, "Setting up the viewport { w:%f, h:%f }", priv->viewport[2], priv->viewport[3]); fb_scale = clutter_stage_view_get_scale (view); clutter_stage_view_get_layout (view, &view_layout); viewport_offset_x = view_layout.x * fb_scale; viewport_offset_y = view_layout.y * fb_scale; cogl_framebuffer_set_viewport (fb, priv->viewport[0] * fb_scale - viewport_offset_x, priv->viewport[1] * fb_scale - viewport_offset_y, priv->viewport[2] * fb_scale, priv->viewport[3] * fb_scale); perspective = priv->perspective; /* Ideally we want to regenerate the perspective matrix whenever * the size changes but if the user has provided a custom matrix * then we don't want to override it */ if (!priv->has_custom_perspective) { perspective.aspect = priv->viewport[2] / priv->viewport[3]; z_2d = calculate_z_translation (perspective.z_near); /* NB: z_2d is only enough room for 85% of the stage_height between * the stage and the z_near plane. For behind the stage plane we * want a more consistent gap of 10 times the stage_height before * hitting the far plane so we calculate that relative to the final * height of the stage plane at the z_2d_distance we got... */ perspective.z_far = z_2d + tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f; clutter_stage_set_perspective_internal (stage, &perspective); } else z_2d = calculate_z_translation (perspective.z_near); cogl_matrix_init_identity (&priv->view); cogl_matrix_view_2d_in_perspective (&priv->view, perspective.fovy, perspective.aspect, perspective.z_near, z_2d, priv->viewport[2], priv->viewport[3]); clutter_stage_view_set_dirty_viewport (view, FALSE); } if (clutter_stage_view_is_dirty_projection (view)) { cogl_framebuffer_set_projection_matrix (fb, &priv->projection); clutter_stage_view_set_dirty_projection (view, FALSE); } } #undef _DEG_TO_RAD /** * clutter_stage_ensure_redraw: * @stage: a #ClutterStage * * Ensures that @stage is redrawn * * This function should not be called by applications: it is * used when embedding a #ClutterStage into a toolkit with * another windowing system, like GTK+. * * Since: 1.0 */ void clutter_stage_ensure_redraw (ClutterStage *stage) { ClutterMasterClock *master_clock; ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (!priv->relayout_pending && !priv->redraw_pending) _clutter_stage_schedule_update (stage); priv->relayout_pending = TRUE; priv->redraw_pending = TRUE; master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_start_running (master_clock); } /** * clutter_stage_queue_redraw: * @stage: the #ClutterStage * * Queues a redraw for the passed stage. * * Applications should call clutter_actor_queue_redraw() and not * this function. * * Since: 0.8 * * Deprecated: 1.10: Use clutter_actor_queue_redraw() instead. */ void clutter_stage_queue_redraw (ClutterStage *stage) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); } /** * clutter_stage_is_default: * @stage: a #ClutterStage * * Checks if @stage is the default stage, or an instance created using * clutter_stage_new() but internally using the same implementation. * * Return value: %TRUE if the passed stage is the default one * * Since: 0.8 * * Deprecated: 1.10: Track the stage pointer inside your application * code, or use clutter_actor_get_stage() to retrieve the stage for * a given actor. */ gboolean clutter_stage_is_default (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return stage_is_default (stage); } void _clutter_stage_set_window (ClutterStage *stage, ClutterStageWindow *stage_window) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (stage_window)); if (stage->priv->impl != NULL) g_object_unref (stage->priv->impl); stage->priv->impl = stage_window; } ClutterStageWindow * _clutter_stage_get_window (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); return CLUTTER_STAGE_WINDOW (stage->priv->impl); } ClutterStageWindow * _clutter_stage_get_default_window (void) { ClutterStageManager *manager = clutter_stage_manager_get_default (); ClutterStage *stage; stage = clutter_stage_manager_get_default_stage (manager); if (stage == NULL) return NULL; return _clutter_stage_get_window (stage); } /** * clutter_stage_set_throttle_motion_events: * @stage: a #ClutterStage * @throttle: %TRUE to throttle motion events * * Sets whether motion events received between redraws should * be throttled or not. If motion events are throttled, those * events received by the windowing system between redraws will * be compressed so that only the last event will be propagated * to the @stage and its actors. * * This function should only be used if you want to have all * the motion events delivered to your application code. * * Since: 1.0 */ void clutter_stage_set_throttle_motion_events (ClutterStage *stage, gboolean throttle) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (priv->throttle_motion_events != throttle) priv->throttle_motion_events = throttle; } /** * clutter_stage_get_throttle_motion_events: * @stage: a #ClutterStage * * Retrieves the value set with clutter_stage_set_throttle_motion_events() * * Return value: %TRUE if the motion events are being throttled, * and %FALSE otherwise * * Since: 1.0 */ gboolean clutter_stage_get_throttle_motion_events (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return stage->priv->throttle_motion_events; } /** * clutter_stage_set_use_alpha: * @stage: a #ClutterStage * @use_alpha: whether the stage should honour the opacity or the * alpha channel of the stage color * * Sets whether the @stage should honour the #ClutterActor:opacity and * the alpha channel of the #ClutterStage:color * * Since: 1.2 */ void clutter_stage_set_use_alpha (ClutterStage *stage, gboolean use_alpha) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; if (priv->use_alpha != use_alpha) { priv->use_alpha = use_alpha; clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); g_object_notify (G_OBJECT (stage), "use-alpha"); } } /** * clutter_stage_get_use_alpha: * @stage: a #ClutterStage * * Retrieves the value set using clutter_stage_set_use_alpha() * * Return value: %TRUE if the stage should honour the opacity and the * alpha channel of the stage color * * Since: 1.2 */ gboolean clutter_stage_get_use_alpha (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return stage->priv->use_alpha; } /** * clutter_stage_set_minimum_size: * @stage: a #ClutterStage * @width: width, in pixels * @height: height, in pixels * * Sets the minimum size for a stage window, if the default backend * uses #ClutterStage inside a window * * This is a convenience function, and it is equivalent to setting the * #ClutterActor:min-width and #ClutterActor:min-height on @stage * * If the current size of @stage is smaller than the minimum size, the * @stage will be resized to the new @width and @height * * This function has no effect if @stage is fullscreen * * Since: 1.2 */ void clutter_stage_set_minimum_size (ClutterStage *stage, guint width, guint height) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail ((width > 0) && (height > 0)); g_object_set (G_OBJECT (stage), "min-width", (gfloat) width, "min-height", (gfloat )height, NULL); } /** * clutter_stage_get_minimum_size: * @stage: a #ClutterStage * @width: (out): return location for the minimum width, in pixels, * or %NULL * @height: (out): return location for the minimum height, in pixels, * or %NULL * * Retrieves the minimum size for a stage window as set using * clutter_stage_set_minimum_size(). * * The returned size may not correspond to the actual minimum size and * it is specific to the #ClutterStage implementation inside the * Clutter backend * * Since: 1.2 */ void clutter_stage_get_minimum_size (ClutterStage *stage, guint *width_p, guint *height_p) { gfloat width, height; gboolean width_set, height_set; g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_object_get (G_OBJECT (stage), "min-width", &width, "min-width-set", &width_set, "min-height", &height, "min-height-set", &height_set, NULL); /* if not width or height have been set, then the Stage * minimum size is defined to be 1x1 */ if (!width_set) width = 1; if (!height_set) height = 1; if (width_p) *width_p = (guint) width; if (height_p) *height_p = (guint) height; } void _clutter_stage_schedule_update (ClutterStage *stage) { ClutterStageWindow *stage_window; if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; stage_window = _clutter_stage_get_window (stage); if (stage_window == NULL) return; return _clutter_stage_window_schedule_update (stage_window, stage->priv->sync_delay); } /* Returns the earliest time the stage is ready to update */ gint64 _clutter_stage_get_update_time (ClutterStage *stage) { ClutterStageWindow *stage_window; if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return 0; stage_window = _clutter_stage_get_window (stage); if (stage_window == NULL) return 0; return _clutter_stage_window_get_update_time (stage_window); } void _clutter_stage_clear_update_time (ClutterStage *stage) { ClutterStageWindow *stage_window; stage_window = _clutter_stage_get_window (stage); if (stage_window) _clutter_stage_window_clear_update_time (stage_window); } /** * clutter_stage_set_no_clear_hint: * @stage: a #ClutterStage * @no_clear: %TRUE if the @stage should not clear itself on every * repaint cycle * * Sets whether the @stage should clear itself at the beginning * of each paint cycle or not. * * Clearing the #ClutterStage can be a costly operation, especially * if the stage is always covered - for instance, in a full-screen * video player or in a game with a background texture. * * This setting is a hint; Clutter might discard this hint * depending on its internal state. * * If parts of the stage are visible and you disable clearing you * might end up with visual artifacts while painting the contents of * the stage. * * Since: 1.4 */ void clutter_stage_set_no_clear_hint (ClutterStage *stage, gboolean no_clear) { ClutterStagePrivate *priv; ClutterStageHint new_hints; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; new_hints = priv->stage_hints; if (no_clear) new_hints |= CLUTTER_STAGE_NO_CLEAR_ON_PAINT; else new_hints &= ~CLUTTER_STAGE_NO_CLEAR_ON_PAINT; if (priv->stage_hints == new_hints) return; priv->stage_hints = new_hints; g_object_notify (G_OBJECT (stage), "no-clear-hint"); } /** * clutter_stage_get_no_clear_hint: * @stage: a #ClutterStage * * Retrieves the hint set with clutter_stage_set_no_clear_hint() * * Return value: %TRUE if the stage should not clear itself on every paint * cycle, and %FALSE otherwise * * Since: 1.4 */ gboolean clutter_stage_get_no_clear_hint (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return (stage->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0; } ClutterPaintVolume * _clutter_stage_paint_volume_stack_allocate (ClutterStage *stage) { GArray *paint_volume_stack = stage->priv->paint_volume_stack; g_array_set_size (paint_volume_stack, paint_volume_stack->len+1); return &g_array_index (paint_volume_stack, ClutterPaintVolume, paint_volume_stack->len - 1); } void _clutter_stage_paint_volume_stack_free_all (ClutterStage *stage) { GArray *paint_volume_stack = stage->priv->paint_volume_stack; int i; for (i = 0; i < paint_volume_stack->len; i++) { ClutterPaintVolume *pv = &g_array_index (paint_volume_stack, ClutterPaintVolume, i); clutter_paint_volume_free (pv); } g_array_set_size (paint_volume_stack, 0); } /* The is an out-of-band paramater available while painting that * can be used to cull actors. */ const ClutterPlane * _clutter_stage_get_clip (ClutterStage *stage) { return stage->priv->current_clip_planes; } /* When an actor queues a redraw we add it to a list on the stage that * gets processed once all updates to the stage have been finished. * * This deferred approach to processing queue_redraw requests means * that we can avoid redundant transformations of clip volumes if * something later triggers a full stage redraw anyway. It also means * we can be more sure that all the referenced actors will have valid * allocations improving the chance that we can determine the actors * paint volume so we can clip the redraw request even if the user * didn't explicitly do so. */ ClutterStageQueueRedrawEntry * _clutter_stage_queue_actor_redraw (ClutterStage *stage, ClutterStageQueueRedrawEntry *entry, ClutterActor *actor, ClutterPaintVolume *clip) { ClutterStagePrivate *priv = stage->priv; CLUTTER_NOTE (CLIPPING, "stage_queue_actor_redraw (actor=%s, clip=%p): ", _clutter_actor_get_debug_name (actor), clip); if (!priv->redraw_pending) { ClutterMasterClock *master_clock; #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (PAINT, "First redraw request"); #endif _clutter_stage_schedule_update (stage); priv->redraw_pending = TRUE; master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_start_running (master_clock); } #ifdef CLUTTER_ENABLE_DEBUG else { CLUTTER_NOTE (PAINT, "Redraw request number %lu", priv->redraw_count + 1); priv->redraw_count += 1; } #endif /* CLUTTER_ENABLE_DEBUG */ if (entry) { /* Ignore all requests to queue a redraw for an actor if a full * (non-clipped) redraw of the actor has already been queued. */ if (!entry->has_clip) { CLUTTER_NOTE (CLIPPING, "Bail from stage_queue_actor_redraw (%s): " "Unclipped redraw of actor already queued", _clutter_actor_get_debug_name (actor)); return entry; } /* If queuing a clipped redraw and a clipped redraw has * previously been queued for this actor then combine the latest * clip together with the existing clip */ if (clip) clutter_paint_volume_union (&entry->clip, clip); else { clutter_paint_volume_free (&entry->clip); entry->has_clip = FALSE; } return entry; } else { entry = g_slice_new (ClutterStageQueueRedrawEntry); entry->actor = g_object_ref (actor); if (clip) { entry->has_clip = TRUE; _clutter_paint_volume_init_static (&entry->clip, actor); _clutter_paint_volume_set_from_volume (&entry->clip, clip); } else entry->has_clip = FALSE; stage->priv->pending_queue_redraws = g_list_prepend (stage->priv->pending_queue_redraws, entry); return entry; } } static void free_queue_redraw_entry (ClutterStageQueueRedrawEntry *entry) { if (entry->actor) g_object_unref (entry->actor); if (entry->has_clip) clutter_paint_volume_free (&entry->clip); g_slice_free (ClutterStageQueueRedrawEntry, entry); } void _clutter_stage_queue_redraw_entry_invalidate (ClutterStageQueueRedrawEntry *entry) { if (entry == NULL) return; if (entry->actor != NULL) { g_object_unref (entry->actor); entry->actor = NULL; } if (entry->has_clip) { clutter_paint_volume_free (&entry->clip); entry->has_clip = FALSE; } } static void clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage) { /* Note: we have to repeat until the pending_queue_redraws list is * empty because actors are allowed to queue redraws in response to * the queue-redraw signal. For example Clone actors or * texture_new_from_actor actors will have to queue a redraw if * their source queues a redraw. */ while (stage->priv->pending_queue_redraws) { GList *l; /* XXX: we need to allow stage->priv->pending_queue_redraws to * be updated while we process the current entries in the list * so we steal the list pointer and then reset it to an empty * list before processing... */ GList *stolen_list = stage->priv->pending_queue_redraws; stage->priv->pending_queue_redraws = NULL; for (l = stolen_list; l; l = l->next) { ClutterStageQueueRedrawEntry *entry = l->data; ClutterPaintVolume *clip; /* NB: Entries may be invalidated if the actor gets destroyed */ if (G_LIKELY (entry->actor != NULL)) { clip = entry->has_clip ? &entry->clip : NULL; _clutter_actor_finish_queue_redraw (entry->actor, clip); } free_queue_redraw_entry (entry); } g_list_free (stolen_list); } } /** * clutter_stage_set_accept_focus: * @stage: a #ClutterStage * @accept_focus: %TRUE to accept focus on show * * Sets whether the @stage should accept the key focus when shown. * * This function should be called before showing @stage using * clutter_actor_show(). * * Since: 1.6 */ void clutter_stage_set_accept_focus (ClutterStage *stage, gboolean accept_focus) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); accept_focus = !!accept_focus; priv = stage->priv; if (priv->accept_focus != accept_focus) { _clutter_stage_window_set_accept_focus (priv->impl, accept_focus); g_object_notify (G_OBJECT (stage), "accept-focus"); } } /** * clutter_stage_get_accept_focus: * @stage: a #ClutterStage * * Retrieves the value set with clutter_stage_set_accept_focus(). * * Return value: %TRUE if the #ClutterStage should accept focus, and %FALSE * otherwise * * Since: 1.6 */ gboolean clutter_stage_get_accept_focus (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), TRUE); return stage->priv->accept_focus; } /** * clutter_stage_set_motion_events_enabled: * @stage: a #ClutterStage * @enabled: %TRUE to enable the motion events delivery, and %FALSE * otherwise * * Sets whether per-actor motion events (and relative crossing * events) should be disabled or not. * * The default is %TRUE. * * If @enable is %FALSE the following signals will not be emitted * by the actors children of @stage: * * - #ClutterActor::motion-event * - #ClutterActor::enter-event * - #ClutterActor::leave-event * * The events will still be delivered to the #ClutterStage. * * The main side effect of this function is that disabling the motion * events will disable picking to detect the #ClutterActor underneath * the pointer for each motion event. This is useful, for instance, * when dragging a #ClutterActor across the @stage: the actor underneath * the pointer is not going to change, so it's meaningless to perform * a pick. * * Since: 1.8 */ void clutter_stage_set_motion_events_enabled (ClutterStage *stage, gboolean enabled) { ClutterStagePrivate *priv; g_return_if_fail (CLUTTER_IS_STAGE (stage)); priv = stage->priv; enabled = !!enabled; if (priv->motion_events_enabled != enabled) priv->motion_events_enabled = enabled; } /** * clutter_stage_get_motion_events_enabled: * @stage: a #ClutterStage * * Retrieves the value set using clutter_stage_set_motion_events_enabled(). * * Return value: %TRUE if the per-actor motion event delivery is enabled * and %FALSE otherwise * * Since: 1.8 */ gboolean clutter_stage_get_motion_events_enabled (ClutterStage *stage) { g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); return stage->priv->motion_events_enabled; } /* NB: The presumption shouldn't be that a stage can't be comprised * of multiple internal framebuffers, so instead of simply naming * this function _clutter_stage_get_framebuffer(), the "active" * infix is intended to clarify that it gets the framebuffer that * is currently in use/being painted. */ CoglFramebuffer * _clutter_stage_get_active_framebuffer (ClutterStage *stage) { return stage->priv->active_framebuffer; } gint32 _clutter_stage_acquire_pick_id (ClutterStage *stage, ClutterActor *actor) { ClutterStagePrivate *priv = stage->priv; g_assert (priv->pick_id_pool != NULL); return _clutter_id_pool_add (priv->pick_id_pool, actor); } void _clutter_stage_release_pick_id (ClutterStage *stage, gint32 pick_id) { ClutterStagePrivate *priv = stage->priv; g_assert (priv->pick_id_pool != NULL); _clutter_id_pool_remove (priv->pick_id_pool, pick_id); } ClutterActor * _clutter_stage_get_actor_by_pick_id (ClutterStage *stage, gint32 pick_id) { ClutterStagePrivate *priv = stage->priv; g_assert (priv->pick_id_pool != NULL); return _clutter_id_pool_lookup (priv->pick_id_pool, pick_id); } void _clutter_stage_add_pointer_drag_actor (ClutterStage *stage, ClutterInputDevice *device, ClutterActor *actor) { GHashTable *drag_actors; drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_pointer_drag_actors"); if (drag_actors == NULL) { drag_actors = g_hash_table_new (NULL, NULL); g_object_set_data_full (G_OBJECT (stage), "__clutter_stage_pointer_drag_actors", drag_actors, (GDestroyNotify) g_hash_table_destroy); } g_hash_table_replace (drag_actors, device, actor); } ClutterActor * _clutter_stage_get_pointer_drag_actor (ClutterStage *stage, ClutterInputDevice *device) { GHashTable *drag_actors; drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_pointer_drag_actors"); if (drag_actors == NULL) return NULL; return g_hash_table_lookup (drag_actors, device); } void _clutter_stage_remove_pointer_drag_actor (ClutterStage *stage, ClutterInputDevice *device) { GHashTable *drag_actors; drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_pointer_drag_actors"); if (drag_actors == NULL) return; g_hash_table_remove (drag_actors, device); if (g_hash_table_size (drag_actors) == 0) g_object_set_data (G_OBJECT (stage), "__clutter_stage_pointer_drag_actors", NULL); } void _clutter_stage_add_touch_drag_actor (ClutterStage *stage, ClutterEventSequence *sequence, ClutterActor *actor) { GHashTable *drag_actors; drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_touch_drag_actors"); if (drag_actors == NULL) { drag_actors = g_hash_table_new (NULL, NULL); g_object_set_data_full (G_OBJECT (stage), "__clutter_stage_touch_drag_actors", drag_actors, (GDestroyNotify) g_hash_table_destroy); } g_hash_table_replace (drag_actors, sequence, actor); } ClutterActor * _clutter_stage_get_touch_drag_actor (ClutterStage *stage, ClutterEventSequence *sequence) { GHashTable *drag_actors; drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_touch_drag_actors"); if (drag_actors == NULL) return NULL; return g_hash_table_lookup (drag_actors, sequence); } void _clutter_stage_remove_touch_drag_actor (ClutterStage *stage, ClutterEventSequence *sequence) { GHashTable *drag_actors; drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_touch_drag_actors"); if (drag_actors == NULL) return; g_hash_table_remove (drag_actors, sequence); if (g_hash_table_size (drag_actors) == 0) g_object_set_data (G_OBJECT (stage), "__clutter_stage_touch_drag_actors", NULL); } /*< private > * _clutter_stage_get_state: * @stage: a #ClutterStage * * Retrieves the current #ClutterStageState flags associated to the @stage. * * Return value: a bitwise OR of #ClutterStageState flags */ ClutterStageState _clutter_stage_get_state (ClutterStage *stage) { return stage->priv->current_state; } /*< private > * _clutter_stage_is_activated: * @stage: a #ClutterStage * * Checks whether the @stage state includes %CLUTTER_STAGE_STATE_ACTIVATED. * * Return value: %TRUE if the @stage is active */ gboolean _clutter_stage_is_activated (ClutterStage *stage) { return (stage->priv->current_state & CLUTTER_STAGE_STATE_ACTIVATED) != 0; } /*< private > * _clutter_stage_is_fullscreen: * @stage: a #ClutterStage * * Checks whether the @stage state includes %CLUTTER_STAGE_STATE_FULLSCREEN. * * Return value: %TRUE if the @stage is fullscreen */ gboolean _clutter_stage_is_fullscreen (ClutterStage *stage) { return (stage->priv->current_state & CLUTTER_STAGE_STATE_FULLSCREEN) != 0; } /*< private > * _clutter_stage_update_state: * @stage: a #ClutterStage * @unset_flags: flags to unset * @set_flags: flags to set * * Updates the state of @stage, by unsetting the @unset_flags and setting * the @set_flags. * * If the stage state has been changed, this function will queue a * #ClutterEvent of type %CLUTTER_STAGE_STATE. * * Return value: %TRUE if the state was updated, and %FALSE otherwise */ gboolean _clutter_stage_update_state (ClutterStage *stage, ClutterStageState unset_flags, ClutterStageState set_flags) { ClutterStageState new_state; ClutterEvent event; new_state = stage->priv->current_state; new_state |= set_flags; new_state &= ~unset_flags; if (new_state == stage->priv->current_state) return FALSE; memset (&event, 0, sizeof (event)); event.type = CLUTTER_STAGE_STATE; clutter_event_set_stage (&event, stage); event.stage_state.new_state = new_state; event.stage_state.changed_mask = new_state ^ stage->priv->current_state; stage->priv->current_state = new_state; clutter_stage_event (stage, &event); return TRUE; } /** * clutter_stage_set_sync_delay: * @stage: a #ClutterStage * @sync_delay: number of milliseconds after frame presentation to wait * before painting the next frame. If less than zero, restores the * default behavior where redraw is throttled to the refresh rate but * not synchronized to it. * * This function enables an alternate behavior where Clutter draws at * a fixed point in time after the frame presentation time (also known * as the VBlank time). This is most useful when the application * wants to show incoming data with predictable latency. (The primary * example of this would be a window system compositor.) By synchronizing * to provide new data before Clutter redraws, an external source of * updates (in the compositor, an application) can get a reliable latency. * * The appropriate value of @sync_delay depends on the complexity of * drawing the stage's scene graph - in general a value of between 0 * and 8 ms (up to one-half of a typical 60hz frame rate) is appropriate. * using a larger value will reduce latency but risks skipping a frame if * drawing the stage takes too long. * * Since: 1.14 * Stability: unstable */ void clutter_stage_set_sync_delay (ClutterStage *stage, gint sync_delay) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); stage->priv->sync_delay = sync_delay; } /** * clutter_stage_skip_sync_delay: * @stage: a #ClutterStage * * Causes the next frame for the stage to be drawn as quickly as * possible, ignoring any delay that clutter_stage_set_sync_delay() * would normally cause. * * Since: 1.14 * Stability: unstable */ void clutter_stage_skip_sync_delay (ClutterStage *stage) { ClutterStageWindow *stage_window; stage_window = _clutter_stage_get_window (stage); if (stage_window) _clutter_stage_window_schedule_update (stage_window, -1); } int64_t clutter_stage_get_frame_counter (ClutterStage *stage) { ClutterStageWindow *stage_window; stage_window = _clutter_stage_get_window (stage); return _clutter_stage_window_get_frame_counter (stage_window); } void _clutter_stage_presented (ClutterStage *stage, CoglFrameEvent frame_event, ClutterFrameInfo *frame_info) { g_signal_emit (stage, stage_signals[PRESENTED], 0, (int) frame_event, frame_info); } static void capture_view (ClutterStage *stage, gboolean paint, ClutterStageView *view, cairo_rectangle_int_t *rect, ClutterCapture *capture) { CoglFramebuffer *framebuffer; ClutterBackend *backend; CoglContext *context; cairo_surface_t *image; uint8_t *data; int stride; CoglBitmap *bitmap; cairo_rectangle_int_t view_layout; float view_scale; framebuffer = clutter_stage_view_get_framebuffer (view); if (paint) { cogl_push_framebuffer (framebuffer); _clutter_stage_maybe_setup_viewport (stage, view); clutter_stage_do_paint_view (stage, view, rect); } view_scale = clutter_stage_view_get_scale (view); image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, rect->width * view_scale, rect->height * view_scale); cairo_surface_set_device_scale (image, view_scale, view_scale); data = cairo_image_surface_get_data (image); stride = cairo_image_surface_get_stride (image); backend = clutter_get_default_backend (); context = clutter_backend_get_cogl_context (backend); bitmap = cogl_bitmap_new_for_data (context, rect->width * view_scale, rect->height * view_scale, CLUTTER_CAIRO_FORMAT_ARGB32, stride, data); clutter_stage_view_get_layout (view, &view_layout); cogl_framebuffer_read_pixels_into_bitmap (framebuffer, (rect->x - view_layout.x) * view_scale, (rect->y - view_layout.y) * view_scale, COGL_READ_PIXELS_COLOR_BUFFER, bitmap); if (paint) cogl_pop_framebuffer (); capture->rect = *rect; capture->image = image; cairo_surface_mark_dirty (capture->image); cogl_object_unref (bitmap); } gboolean clutter_stage_capture (ClutterStage *stage, gboolean paint, cairo_rectangle_int_t *rect, ClutterCapture **out_captures, int *out_n_captures) { ClutterStagePrivate *priv = stage->priv; GList *views = _clutter_stage_window_get_views (priv->impl); GList *l; ClutterCapture *captures; int n_captures; captures = g_new0 (ClutterCapture, g_list_length (views)); n_captures = 0; for (l = views; l; l = l->next) { ClutterStageView *view = l->data; cairo_rectangle_int_t view_layout; cairo_region_t *region; cairo_rectangle_int_t view_capture_rect; clutter_stage_view_get_layout (view, &view_layout); region = cairo_region_create_rectangle (&view_layout); cairo_region_intersect_rectangle (region, rect); cairo_region_get_extents (region, &view_capture_rect); cairo_region_destroy (region); if (view_capture_rect.width == 0 || view_capture_rect.height == 0) continue; capture_view (stage, paint, view, &view_capture_rect, &captures[n_captures]); n_captures++; } *out_captures = captures; *out_n_captures = n_captures; return TRUE; } static void capture_view_into (ClutterStage *stage, gboolean paint, ClutterStageView *view, cairo_rectangle_int_t *rect, uint8_t *data, int stride) { CoglFramebuffer *framebuffer; ClutterBackend *backend; CoglContext *context; CoglBitmap *bitmap; cairo_rectangle_int_t view_layout; framebuffer = clutter_stage_view_get_framebuffer (view); if (paint) { cogl_push_framebuffer (framebuffer); _clutter_stage_maybe_setup_viewport (stage, view); clutter_stage_do_paint_view (stage, view, rect); } backend = clutter_get_default_backend (); context = clutter_backend_get_cogl_context (backend); bitmap = cogl_bitmap_new_for_data (context, rect->width, rect->height, CLUTTER_CAIRO_FORMAT_ARGB32, stride, data); clutter_stage_view_get_layout (view, &view_layout); cogl_framebuffer_read_pixels_into_bitmap (framebuffer, rect->x - view_layout.x, rect->y - view_layout.y, COGL_READ_PIXELS_COLOR_BUFFER, bitmap); if (paint) cogl_pop_framebuffer (); cogl_object_unref (bitmap); } static ClutterStageView * get_view_at_rect (ClutterStage *stage, cairo_rectangle_int_t *rect) { ClutterStagePrivate *priv = stage->priv; GList *views = _clutter_stage_window_get_views (priv->impl); GList *l; for (l = views; l; l = l->next) { ClutterStageView *view = l->data; cairo_rectangle_int_t view_layout; cairo_region_t *region; cairo_rectangle_int_t view_capture_rect; clutter_stage_view_get_layout (view, &view_layout); region = cairo_region_create_rectangle (&view_layout); cairo_region_intersect_rectangle (region, rect); cairo_region_get_extents (region, &view_capture_rect); cairo_region_destroy (region); if (view_capture_rect.width == 0 || view_capture_rect.height == 0) continue; g_assert (view_capture_rect.width == rect->width && view_capture_rect.height == rect->height); return view; } return NULL; } void clutter_stage_capture_into (ClutterStage *stage, gboolean paint, cairo_rectangle_int_t *rect, uint8_t *data) { ClutterStageView *view; int bpp = 4; view = get_view_at_rect (stage, rect); capture_view_into (stage, paint, view, rect, data, rect->width * bpp); } muffin-5.2.1/clutter/clutter/clutter-units.c0000664000175000017500000005502014211404421021270 0ustar jpeisachjpeisach/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Tomas Frydrych * Emmanuele Bassi * * 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, see . * * */ /** * SECTION:clutter-units * @short_description: A logical distance unit * * #ClutterUnits is a structure holding a logical distance value along with * its type, expressed as a value of the #ClutterUnitType enumeration. It is * possible to use #ClutterUnits to store a position or a size in units * different than pixels, and convert them whenever needed (for instance * inside the #ClutterActorClass.allocate() virtual function, or inside the * #ClutterActorClass.get_preferred_width() and #ClutterActorClass.get_preferred_height() * virtual functions. * * In order to register a #ClutterUnits property, the #ClutterParamSpecUnits * #GParamSpec sub-class should be used: * * |[ * GParamSpec *pspec; * * pspec = clutter_param_spec_units ("active-width", * "Width", * "Width of the active area, in millimeters", * CLUTTER_UNIT_MM, * 0.0, 12.0, * 12.0, * G_PARAM_READWRITE); * g_object_class_install_property (gobject_class, PROP_WIDTH, pspec); * ]| * * A #GValue holding units can be manipulated using clutter_value_set_units() * and clutter_value_get_units(). #GValues containing a #ClutterUnits * value can also be transformed to #GValues initialized with * %G_TYPE_INT, %G_TYPE_FLOAT and %G_TYPE_STRING through implicit conversion * and using g_value_transform(). * * #ClutterUnits is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #include "clutter-backend-private.h" #include "clutter-interval.h" #include "clutter-private.h" #include "clutter-units.h" #define DPI_FALLBACK (96.0) #define FLOAT_EPSILON (1e-30) static gfloat units_mm_to_pixels (gfloat mm) { ClutterBackend *backend; gdouble dpi; backend = clutter_get_default_backend (); dpi = clutter_backend_get_resolution (backend); if (dpi < 0) dpi = DPI_FALLBACK; return mm * dpi / 25.4; } static gfloat units_cm_to_pixels (gfloat cm) { return units_mm_to_pixels (cm * 10); } static gfloat units_pt_to_pixels (gfloat pt) { ClutterBackend *backend; gdouble dpi; backend = clutter_get_default_backend (); dpi = clutter_backend_get_resolution (backend); if (dpi < 0) dpi = DPI_FALLBACK; return pt * dpi / 72.0; } static gfloat units_em_to_pixels (const gchar *font_name, gfloat em) { ClutterBackend *backend = clutter_get_default_backend (); if (font_name == NULL || *font_name == '\0') return em * _clutter_backend_get_units_per_em (backend, NULL); else { PangoFontDescription *font_desc; gfloat res; font_desc = pango_font_description_from_string (font_name); if (font_desc == NULL) res = -1.0; else { res = em * _clutter_backend_get_units_per_em (backend, font_desc); pango_font_description_free (font_desc); } return res; } } /** * clutter_units_from_mm: * @units: (out caller-allocates): a #ClutterUnits * @mm: millimeters * * Stores a value in millimiters inside @units * * Since: 1.0 */ void clutter_units_from_mm (ClutterUnits *units, gfloat mm) { ClutterBackend *backend; g_return_if_fail (units != NULL); backend = clutter_get_default_backend (); units->unit_type = CLUTTER_UNIT_MM; units->value = mm; units->pixels = units_mm_to_pixels (mm); units->pixels_set = TRUE; units->serial = _clutter_backend_get_units_serial (backend); } /** * clutter_units_from_cm: * @units: (out caller-allocates): a #ClutterUnits * @cm: centimeters * * Stores a value in centimeters inside @units * * Since: 1.2 */ void clutter_units_from_cm (ClutterUnits *units, gfloat cm) { ClutterBackend *backend; g_return_if_fail (units != NULL); backend = clutter_get_default_backend (); units->unit_type = CLUTTER_UNIT_CM; units->value = cm; units->pixels = units_cm_to_pixels (cm); units->pixels_set = TRUE; units->serial = _clutter_backend_get_units_serial (backend); } /** * clutter_units_from_pt: * @units: (out caller-allocates): a #ClutterUnits * @pt: typographic points * * Stores a value in typographic points inside @units * * Since: 1.0 */ void clutter_units_from_pt (ClutterUnits *units, gfloat pt) { ClutterBackend *backend; g_return_if_fail (units != NULL); backend = clutter_get_default_backend (); units->unit_type = CLUTTER_UNIT_POINT; units->value = pt; units->pixels = units_pt_to_pixels (pt); units->pixels_set = TRUE; units->serial = _clutter_backend_get_units_serial (backend); } /** * clutter_units_from_em: * @units: (out caller-allocates): a #ClutterUnits * @em: em * * Stores a value in em inside @units, using the default font * name as returned by clutter_backend_get_font_name() * * Since: 1.0 */ void clutter_units_from_em (ClutterUnits *units, gfloat em) { ClutterBackend *backend; g_return_if_fail (units != NULL); backend = clutter_get_default_backend (); units->unit_type = CLUTTER_UNIT_EM; units->value = em; units->pixels = units_em_to_pixels (NULL, em); units->pixels_set = TRUE; units->serial = _clutter_backend_get_units_serial (backend); } /** * clutter_units_from_em_for_font: * @units: (out caller-allocates): a #ClutterUnits * @font_name: (allow-none): the font name and size * @em: em * * Stores a value in em inside @units using @font_name * * Since: 1.0 */ void clutter_units_from_em_for_font (ClutterUnits *units, const gchar *font_name, gfloat em) { ClutterBackend *backend; g_return_if_fail (units != NULL); backend = clutter_get_default_backend (); units->unit_type = CLUTTER_UNIT_EM; units->value = em; units->pixels = units_em_to_pixels (font_name, em); units->pixels_set = TRUE; units->serial = _clutter_backend_get_units_serial (backend); } /** * clutter_units_from_pixels: * @units: (out caller-allocates): a #ClutterUnits * @px: pixels * * Stores a value in pixels inside @units * * Since: 1.0 */ void clutter_units_from_pixels (ClutterUnits *units, gint px) { ClutterBackend *backend; g_return_if_fail (units != NULL); backend = clutter_get_default_backend (); units->unit_type = CLUTTER_UNIT_PIXEL; units->value = px; units->pixels = px; units->pixels_set = TRUE; units->serial = _clutter_backend_get_units_serial (backend); } /** * clutter_units_get_unit_type: * @units: a #ClutterUnits * * Retrieves the unit type of the value stored inside @units * * Return value: a unit type * * Since: 1.0 */ ClutterUnitType clutter_units_get_unit_type (const ClutterUnits *units) { g_return_val_if_fail (units != NULL, CLUTTER_UNIT_PIXEL); return units->unit_type; } /** * clutter_units_get_unit_value: * @units: a #ClutterUnits * * Retrieves the value stored inside @units * * Return value: the value stored inside a #ClutterUnits * * Since: 1.0 */ gfloat clutter_units_get_unit_value (const ClutterUnits *units) { g_return_val_if_fail (units != NULL, 0.0); return units->value; } /** * clutter_units_copy: * @units: the #ClutterUnits to copy * * Copies @units * * Return value: (transfer full): the newly created copy of a * #ClutterUnits structure. Use clutter_units_free() to free * the allocated resources * * Since: 1.0 */ ClutterUnits * clutter_units_copy (const ClutterUnits *units) { if (units != NULL) return g_slice_dup (ClutterUnits, units); return NULL; } /** * clutter_units_free: * @units: the #ClutterUnits to free * * Frees the resources allocated by @units * * You should only call this function on a #ClutterUnits * created using clutter_units_copy() * * Since: 1.0 */ void clutter_units_free (ClutterUnits *units) { if (units != NULL) g_slice_free (ClutterUnits, units); } /** * clutter_units_to_pixels: * @units: units to convert * * Converts a value in #ClutterUnits to pixels * * Return value: the value in pixels * * Since: 1.0 */ gfloat clutter_units_to_pixels (ClutterUnits *units) { ClutterBackend *backend; g_return_val_if_fail (units != NULL, 0.0); /* if the backend settings changed we evict the cached value */ backend = clutter_get_default_backend (); if (units->serial != _clutter_backend_get_units_serial (backend)) units->pixels_set = FALSE; if (units->pixels_set) return units->pixels; switch (units->unit_type) { case CLUTTER_UNIT_MM: units->pixels = units_mm_to_pixels (units->value); break; case CLUTTER_UNIT_CM: units->pixels = units_cm_to_pixels (units->value); break; case CLUTTER_UNIT_POINT: units->pixels = units_pt_to_pixels (units->value); break; case CLUTTER_UNIT_EM: units->pixels = units_em_to_pixels (NULL, units->value); break; case CLUTTER_UNIT_PIXEL: units->pixels = units->value; break; } units->pixels_set = TRUE; units->serial = _clutter_backend_get_units_serial (backend); return units->pixels; } /** * clutter_units_from_string: * @units: (out caller-allocates): a #ClutterUnits * @str: the string to convert * * Parses a value and updates @units with it * * A #ClutterUnits expressed in string should match: * * |[ * units: wsp* unit-value wsp* unit-name? wsp* * unit-value: number * unit-name: 'px' | 'pt' | 'mm' | 'em' | 'cm' * number: digit+ * | digit* sep digit+ * sep: '.' | ',' * digit: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' * wsp: (#0x20 | #0x9 | #0xA | #0xB | #0xC | #0xD)+ * ]| * * For instance, these are valid strings: * * |[ * 10 px * 5.1 em * 24 pt * 12.6 mm * .3 cm * ]| * * While these are not: * * |[ * 42 cats * omg!1!ponies * ]| * * If no unit is specified, pixels are assumed. * * Return value: %TRUE if the string was successfully parsed, * and %FALSE otherwise * * Since: 1.0 */ gboolean clutter_units_from_string (ClutterUnits *units, const gchar *str) { ClutterBackend *backend; ClutterUnitType unit_type; gfloat value; g_return_val_if_fail (units != NULL, FALSE); g_return_val_if_fail (str != NULL, FALSE); /* strip leading space */ while (g_ascii_isspace (*str)) str++; if (*str == '\0') return FALSE; /* integer part */ value = (gfloat) strtoul (str, (char **) &str, 10); if (*str == '.' || *str == ',') { gfloat divisor = 0.1; /* 5.cm is not a valid number */ if (!g_ascii_isdigit (*++str)) return FALSE; while (g_ascii_isdigit (*str)) { value += (*str - '0') * divisor; divisor *= 0.1; str++; } } while (g_ascii_isspace (*str)) str++; /* assume pixels by default, if no unit is specified */ if (*str == '\0') unit_type = CLUTTER_UNIT_PIXEL; else if (strncmp (str, "em", 2) == 0) { unit_type = CLUTTER_UNIT_EM; str += 2; } else if (strncmp (str, "mm", 2) == 0) { unit_type = CLUTTER_UNIT_MM; str += 2; } else if (strncmp (str, "cm", 2) == 0) { unit_type = CLUTTER_UNIT_CM; str += 2; } else if (strncmp (str, "pt", 2) == 0) { unit_type = CLUTTER_UNIT_POINT; str += 2; } else if (strncmp (str, "px", 2) == 0) { unit_type = CLUTTER_UNIT_PIXEL; str += 2; } else return FALSE; /* ensure the unit is only followed by white space */ while (g_ascii_isspace (*str)) str++; if (*str != '\0') return FALSE; backend = clutter_get_default_backend (); units->unit_type = unit_type; units->value = value; units->pixels_set = FALSE; units->serial = _clutter_backend_get_units_serial (backend); return TRUE; } static const gchar * clutter_unit_type_name (ClutterUnitType unit_type) { switch (unit_type) { case CLUTTER_UNIT_MM: return "mm"; case CLUTTER_UNIT_CM: return "cm"; case CLUTTER_UNIT_POINT: return "pt"; case CLUTTER_UNIT_EM: return "em"; case CLUTTER_UNIT_PIXEL: return "px"; } g_warning ("Invalid unit type %d", (int) unit_type); return ""; } /** * clutter_units_to_string: * @units: a #ClutterUnits * * Converts @units into a string * * See clutter_units_from_string() for the units syntax and for * examples of output * * Fractional values are truncated to the second decimal * position for em, mm and cm, and to the first decimal position for * typographic points. Pixels are integers. * * Return value: a newly allocated string containing the encoded * #ClutterUnits value. Use free() to free the string * * Since: 1.0 */ gchar * clutter_units_to_string (const ClutterUnits *units) { const gchar *unit_name = NULL; const gchar *fmt = NULL; gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; g_return_val_if_fail (units != NULL, NULL); switch (units->unit_type) { /* special case: there is no such thing as "half a pixel", so * we round up to the nearest integer using C default */ case CLUTTER_UNIT_PIXEL: return g_strdup_printf ("%d px", (int) units->value); case CLUTTER_UNIT_MM: unit_name = "mm"; fmt = "%.2f"; break; case CLUTTER_UNIT_CM: unit_name = "cm"; fmt = "%.2f"; break; case CLUTTER_UNIT_POINT: unit_name = "pt"; fmt = "%.1f"; break; case CLUTTER_UNIT_EM: unit_name = "em"; fmt = "%.2f"; break; default: g_assert_not_reached (); break; } g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, fmt, units->value); return g_strconcat (buf, " ", unit_name, NULL); } /* * ClutterInterval integration */ static gboolean clutter_units_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { ClutterUnits *a_units = (ClutterUnits *) clutter_value_get_units (a); ClutterUnits *b_units = (ClutterUnits *) clutter_value_get_units (b); ClutterUnits res; gfloat a_px, b_px, value; a_px = clutter_units_to_pixels (a_units); b_px = clutter_units_to_pixels (b_units); value = progress * (b_px - a_px) + a_px; clutter_units_from_pixels (&res, value); clutter_value_set_units (retval, &res); return TRUE; } /* * GValue and GParamSpec integration */ /* units to integer */ static void clutter_value_transform_units_int (const GValue *src, GValue *dest) { dest->data[0].v_int = clutter_units_to_pixels (src->data[0].v_pointer); } /* integer to units */ static void clutter_value_transform_int_units (const GValue *src, GValue *dest) { clutter_units_from_pixels (dest->data[0].v_pointer, src->data[0].v_int); } /* units to float */ static void clutter_value_transform_units_float (const GValue *src, GValue *dest) { dest->data[0].v_float = clutter_units_to_pixels (src->data[0].v_pointer); } /* float to units */ static void clutter_value_transform_float_units (const GValue *src, GValue *dest) { clutter_units_from_pixels (dest->data[0].v_pointer, src->data[0].v_float); } /* units to string */ static void clutter_value_transform_units_string (const GValue *src, GValue *dest) { gchar *string = clutter_units_to_string (src->data[0].v_pointer); g_value_take_string (dest, string); } /* string to units */ static void clutter_value_transform_string_units (const GValue *src, GValue *dest) { ClutterUnits units = { CLUTTER_UNIT_PIXEL, 0.0f }; clutter_units_from_string (&units, g_value_get_string (src)); clutter_value_set_units (dest, &units); } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterUnits, clutter_units, clutter_units_copy, clutter_units_free, CLUTTER_REGISTER_VALUE_TRANSFORM_TO (G_TYPE_INT, clutter_value_transform_units_int) CLUTTER_REGISTER_VALUE_TRANSFORM_TO (G_TYPE_FLOAT, clutter_value_transform_units_float) CLUTTER_REGISTER_VALUE_TRANSFORM_TO (G_TYPE_STRING, clutter_value_transform_units_string) CLUTTER_REGISTER_VALUE_TRANSFORM_FROM (G_TYPE_INT, clutter_value_transform_int_units) CLUTTER_REGISTER_VALUE_TRANSFORM_FROM (G_TYPE_FLOAT, clutter_value_transform_float_units) CLUTTER_REGISTER_VALUE_TRANSFORM_FROM (G_TYPE_STRING, clutter_value_transform_string_units) CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_units_progress)); /** * clutter_value_set_units: * @value: a #GValue initialized to %CLUTTER_TYPE_UNITS * @units: the units to set * * Sets @value to @units * * Since: 0.8 */ void clutter_value_set_units (GValue *value, const ClutterUnits *units) { g_return_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value)); value->data[0].v_pointer = clutter_units_copy (units); } /** * clutter_value_get_units: * @value: a #GValue initialized to %CLUTTER_TYPE_UNITS * * Gets the #ClutterUnits contained in @value. * * Return value: the units inside the passed #GValue * * Since: 0.8 */ const ClutterUnits * clutter_value_get_units (const GValue *value) { g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value), NULL); return value->data[0].v_pointer; } static void param_units_init (GParamSpec *pspec) { ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); uspec->minimum = -G_MAXFLOAT; uspec->maximum = G_MAXFLOAT; uspec->default_value = 0.0f; uspec->default_type = CLUTTER_UNIT_PIXEL; } static void param_units_set_default (GParamSpec *pspec, GValue *value) { ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); ClutterUnits units; units.unit_type = uspec->default_type; units.value = uspec->default_value; units.pixels_set = FALSE; clutter_value_set_units (value, &units); } static gboolean param_units_validate (GParamSpec *pspec, GValue *value) { ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); ClutterUnits *units = value->data[0].v_pointer; ClutterUnitType otype = units->unit_type; gfloat oval = units->value; g_assert (CLUTTER_IS_PARAM_SPEC_UNITS (pspec)); if (otype != uspec->default_type) { gchar *str = clutter_units_to_string (units); g_warning ("The units value of '%s' does not have the same unit " "type as declared by the ClutterParamSpecUnits of '%s'", str, clutter_unit_type_name (uspec->default_type)); free (str); return FALSE; } units->value = CLAMP (units->value, uspec->minimum, uspec->maximum); return units->value != oval; } static gint param_units_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { ClutterUnits *units1 = value1->data[0].v_pointer; ClutterUnits *units2 = value2->data[0].v_pointer; gfloat v1, v2; if (units1->unit_type == units2->unit_type) { v1 = units1->value; v2 = units2->value; } else { v1 = clutter_units_to_pixels (units1); v2 = clutter_units_to_pixels (units2); } if (v1 < v2) return - (v2 - v1 > FLOAT_EPSILON); else return v1 - v2 > FLOAT_EPSILON; } GType clutter_param_units_get_type (void) { static GType pspec_type = 0; if (G_UNLIKELY (pspec_type == 0)) { const GParamSpecTypeInfo pspec_info = { sizeof (ClutterParamSpecUnits), 16, param_units_init, CLUTTER_TYPE_UNITS, NULL, param_units_set_default, param_units_validate, param_units_values_cmp, }; pspec_type = g_param_type_register_static (I_("ClutterParamSpecUnit"), &pspec_info); } return pspec_type; } /** * clutter_param_spec_units: (skip) * @name: name of the property * @nick: short name * @blurb: description (can be translatable) * @default_type: the default type for the #ClutterUnits * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * @flags: flags for the param spec * * Creates a #GParamSpec for properties using #ClutterUnits. * * Return value: the newly created #GParamSpec * * Since: 1.0 */ GParamSpec * clutter_param_spec_units (const gchar *name, const gchar *nick, const gchar *blurb, ClutterUnitType default_type, gfloat minimum, gfloat maximum, gfloat default_value, GParamFlags flags) { ClutterParamSpecUnits *uspec; g_return_val_if_fail (default_value >= minimum && default_value <= maximum, NULL); uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNITS, name, nick, blurb, flags); uspec->default_type = default_type; uspec->minimum = minimum; uspec->maximum = maximum; uspec->default_value = default_value; return G_PARAM_SPEC (uspec); } muffin-5.2.1/clutter/clutter/clutter-script-private.h0000664000175000017500000001363014211404421023110 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * */ #ifndef __CLUTTER_SCRIPT_PRIVATE_H__ #define __CLUTTER_SCRIPT_PRIVATE_H__ #include #include #include "clutter-color.h" #include "clutter-types.h" #include "clutter-script.h" G_BEGIN_DECLS #define CLUTTER_TYPE_SCRIPT_PARSER (_clutter_script_parser_get_type ()) #define CLUTTER_SCRIPT_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SCRIPT_PARSER, ClutterScriptParser)) #define CLUTTER_IS_SCRIPT_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SCRIPT_PARSER)) typedef struct _ClutterScriptParser ClutterScriptParser; typedef struct _JsonParserClass ClutterScriptParserClass; struct _ClutterScriptParser { JsonParser parent_instance; /* back reference */ ClutterScript *script; }; typedef GType (* GTypeGetFunc) (void); typedef struct { gchar *id; gchar *class_name; gchar *type_func; GList *properties; GList *children; GList *signals; GType gtype; GObject *object; guint merge_id; guint is_actor : 1; guint is_stage : 1; guint is_stage_default : 1; guint has_unresolved : 1; guint is_unmerged : 1; } ObjectInfo; void object_info_free (gpointer data); typedef struct { gchar *name; JsonNode *node; GParamSpec *pspec; guint is_child : 1; guint is_layout : 1; } PropertyInfo; typedef struct { gchar *name; gchar *handler; gchar *object; gchar *state; gchar *target; GConnectFlags flags; guint is_handler : 1; guint warp_to : 1; } SignalInfo; void property_info_free (gpointer data); GType _clutter_script_parser_get_type (void) G_GNUC_CONST; gboolean _clutter_script_parse_node (ClutterScript *script, GValue *value, const gchar *name, JsonNode *node, GParamSpec *pspec); GType _clutter_script_get_type_from_symbol (const gchar *symbol); GType _clutter_script_get_type_from_class (const gchar *name); gulong _clutter_script_resolve_animation_mode (JsonNode *node); gboolean _clutter_script_enum_from_string (GType gtype, const gchar *string, gint *enum_value); gboolean _clutter_script_flags_from_string (GType gtype, const gchar *string, gint *flags_value); gboolean _clutter_script_parse_knot (ClutterScript *script, JsonNode *node, ClutterKnot *knot); gboolean _clutter_script_parse_geometry (ClutterScript *script, JsonNode *node, ClutterGeometry *geometry); gboolean _clutter_script_parse_color (ClutterScript *script, JsonNode *node, ClutterColor *color); GObject *_clutter_script_parse_alpha (ClutterScript *script, JsonNode *node); gboolean _clutter_script_parse_point (ClutterScript *script, JsonNode *node, ClutterPoint *point); gboolean _clutter_script_parse_size (ClutterScript *script, JsonNode *node, ClutterSize *size); gboolean _clutter_script_parse_translatable_string (ClutterScript *script, JsonNode *node, char **str); void _clutter_script_construct_object (ClutterScript *script, ObjectInfo *oinfo); void _clutter_script_apply_properties (ClutterScript *script, ObjectInfo *oinfo); gchar *_clutter_script_generate_fake_id (ClutterScript *script); void _clutter_script_warn_missing_attribute (ClutterScript *script, const gchar *id, const gchar *attribute); void _clutter_script_warn_invalid_value (ClutterScript *script, const gchar *attribute, const gchar *expected, JsonNode *node); ObjectInfo *_clutter_script_get_object_info (ClutterScript *script, const gchar *script_id); guint _clutter_script_get_last_merge_id (ClutterScript *script); void _clutter_script_add_object_info (ClutterScript *script, ObjectInfo *oinfo); const gchar *_clutter_script_get_id_from_node (JsonNode *node); G_END_DECLS #endif /* __CLUTTER_SCRIPT_PRIVATE_H__ */ muffin-5.2.1/clutter/clutter/clutter-effect-private.h0000664000175000017500000000161214211404421023035 0ustar jpeisachjpeisach#ifndef __CLUTTER_EFFECT_PRIVATE_H__ #define __CLUTTER_EFFECT_PRIVATE_H__ #include G_BEGIN_DECLS gboolean _clutter_effect_pre_paint (ClutterEffect *effect); void _clutter_effect_post_paint (ClutterEffect *effect); gboolean _clutter_effect_get_paint_volume (ClutterEffect *effect, ClutterPaintVolume *volume); void _clutter_effect_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags); void _clutter_effect_pick (ClutterEffect *effect, ClutterEffectPaintFlags flags); G_END_DECLS #endif /* __CLUTTER_EFFECT_PRIVATE_H__ */ muffin-5.2.1/clutter/clutter/clutter-color.h0000664000175000017500000001642714211404421021261 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Matthew Allum * Emmanuele Bassi * * Copyright (C) 2006, 2007, 2008 OpenedHand * 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, see . */ #ifndef __CLUTTER_COLOR_H__ #define __CLUTTER_COLOR_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_COLOR (clutter_color_get_type ()) /** * ClutterColor: * @red: red component, between 0 and 255 * @green: green component, between 0 and 255 * @blue: blue component, between 0 and 255 * @alpha: alpha component, between 0 and 255 * * Color representation. */ struct _ClutterColor { /*< public >*/ guint8 red; guint8 green; guint8 blue; guint8 alpha; }; /** * CLUTTER_COLOR_INIT: * @r: value for the red channel, between 0 and 255 * @g: value for the green channel, between 0 and 255 * @b: value for the blue channel, between 0 and 255 * @a: value for the alpha channel, between 0 and 255 * * A macro that initializes a #ClutterColor, to be used when declaring it. * * Since: 1.12 */ #define CLUTTER_COLOR_INIT(r,g,b,a) { (r), (g), (b), (a) } CLUTTER_AVAILABLE_IN_ALL GType clutter_color_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterColor *clutter_color_new (guint8 red, guint8 green, guint8 blue, guint8 alpha); CLUTTER_AVAILABLE_IN_1_12 ClutterColor *clutter_color_alloc (void); CLUTTER_AVAILABLE_IN_1_12 ClutterColor *clutter_color_init (ClutterColor *color, guint8 red, guint8 green, guint8 blue, guint8 alpha); CLUTTER_AVAILABLE_IN_ALL ClutterColor *clutter_color_copy (const ClutterColor *color); CLUTTER_AVAILABLE_IN_ALL void clutter_color_free (ClutterColor *color); CLUTTER_AVAILABLE_IN_ALL void clutter_color_add (const ClutterColor *a, const ClutterColor *b, ClutterColor *result); CLUTTER_AVAILABLE_IN_ALL void clutter_color_subtract (const ClutterColor *a, const ClutterColor *b, ClutterColor *result); CLUTTER_AVAILABLE_IN_ALL void clutter_color_lighten (const ClutterColor *color, ClutterColor *result); CLUTTER_AVAILABLE_IN_ALL void clutter_color_darken (const ClutterColor *color, ClutterColor *result); CLUTTER_AVAILABLE_IN_ALL void clutter_color_shade (const ClutterColor *color, gdouble factor, ClutterColor *result); CLUTTER_AVAILABLE_IN_ALL gchar * clutter_color_to_string (const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_color_from_string (ClutterColor *color, const gchar *str); CLUTTER_AVAILABLE_IN_ALL void clutter_color_to_hls (const ClutterColor *color, gfloat *hue, gfloat *luminance, gfloat *saturation); CLUTTER_AVAILABLE_IN_ALL void clutter_color_from_hls (ClutterColor *color, gfloat hue, gfloat luminance, gfloat saturation); CLUTTER_AVAILABLE_IN_ALL guint32 clutter_color_to_pixel (const ClutterColor *color); CLUTTER_AVAILABLE_IN_ALL void clutter_color_from_pixel (ClutterColor *color, guint32 pixel); CLUTTER_AVAILABLE_IN_1_0 guint clutter_color_hash (gconstpointer v); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_color_equal (gconstpointer v1, gconstpointer v2); CLUTTER_AVAILABLE_IN_1_6 void clutter_color_interpolate (const ClutterColor *initial, const ClutterColor *final, gdouble progress, ClutterColor *result); #define CLUTTER_TYPE_PARAM_COLOR (clutter_param_color_get_type ()) #define CLUTTER_PARAM_SPEC_COLOR(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_COLOR, ClutterParamSpecColor)) #define CLUTTER_IS_PARAM_SPEC_COLOR(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_COLOR)) /** * CLUTTER_VALUE_HOLDS_COLOR: * @x: a #GValue * * Evaluates to %TRUE if @x holds a #ClutterColor. * * Since: 1.0 */ #define CLUTTER_VALUE_HOLDS_COLOR(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_COLOR)) typedef struct _ClutterParamSpecColor ClutterParamSpecColor; /** * ClutterParamSpecColor: (skip) * @default_value: default color value * * A #GParamSpec subclass for defining properties holding * a #ClutterColor. * * Since: 1.0 */ struct _ClutterParamSpecColor { /*< private >*/ GParamSpec parent_instance; /*< public >*/ ClutterColor *default_value; }; CLUTTER_AVAILABLE_IN_1_0 void clutter_value_set_color (GValue *value, const ClutterColor *color); CLUTTER_AVAILABLE_IN_1_0 const ClutterColor * clutter_value_get_color (const GValue *value); CLUTTER_AVAILABLE_IN_1_0 GType clutter_param_color_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 GParamSpec * clutter_param_spec_color (const gchar *name, const gchar *nick, const gchar *blurb, const ClutterColor *default_value, GParamFlags flags); CLUTTER_AVAILABLE_IN_1_6 const ClutterColor *clutter_color_get_static (ClutterStaticColor color); G_END_DECLS #endif /* __CLUTTER_COLOR_H__ */ muffin-5.2.1/clutter/clutter/clutter-macros.h0000664000175000017500000003421514211404421021422 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see . */ #ifndef __CLUTTER_MACROS_H__ #define __CLUTTER_MACROS_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include /** * CLUTTER_FLAVOUR: * * GL Windowing system used * * Since: 0.4 * * Deprecated: 1.10: The macro evaluates to "deprecated" as Clutter can be * compiled with multiple windowing system backends. Use the various * CLUTTER_WINDOWING_* macros to detect the windowing system that Clutter * is being compiled against, and the type check macros for the * #ClutterBackend for a run-time check. */ #define CLUTTER_FLAVOUR "deprecated" /** * CLUTTER_COGL: * * Cogl (internal GL abstraction utility library) backend. Can be "gl" or * "gles" currently * * Since: 0.4 * * Deprecated: 1.10: The macro evaluates to "deprecated" as Cogl can be * compiled against multiple GL implementations. */ #define CLUTTER_COGL "deprecated" /** * CLUTTER_STAGE_TYPE: * * The default GObject type for the Clutter stage. * * Since: 0.8 * * Deprecated: 1.10: The macro evaluates to "deprecated" as Clutter can * be compiled against multiple windowing systems. You can use the * CLUTTER_WINDOWING_* macros for compile-time checks, and the type * check macros for run-time checks. */ #define CLUTTER_STAGE_TYPE "deprecated" /** * CLUTTER_NO_FPU: * * Set to 1 if Clutter was built without FPU (i.e fixed math), 0 otherwise * * Deprecated: 0.6: This macro is no longer defined (identical code is used * regardless the presence of FPU). */ #define CLUTTER_NO_FPU (0) /* some structures are meant to be opaque and still be allocated on the stack; * in order to avoid people poking at their internals, we use this macro to * ensure that users don't accidentally access a struct private members. * * we use the CLUTTER_COMPILATION define to allow us easier access, though. */ #ifdef CLUTTER_COMPILATION #define CLUTTER_PRIVATE_FIELD(x) x #else #define CLUTTER_PRIVATE_FIELD(x) clutter_private_ ## x #endif #ifndef _CLUTTER_EXTERN #define _CLUTTER_EXTERN extern #endif #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || \ __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 4) #define _CLUTTER_GNUC_DO_PRAGMA(x) _Pragma(G_STRINGIFY (x)) #define _CLUTTER_DEPRECATED_MACRO _CLUTTER_GNUC_DO_PRAGMA(GCC warning "Deprecated macro") #define _CLUTTER_DEPRECATED_MACRO_FOR(f) _CLUTTER_GNUC_DO_PRAGMA(GCC warning #f) #else #define _CLUTTER_DEPRECATED_MACRO #define _CLUTTER_DEPRECATED_MACRO_FOR(f) #endif /* these macros are used to mark deprecated functions, and thus have to be * exposed in a public header. * * do *not* use them in other libraries depending on Clutter: use G_DEPRECATED * and G_DEPRECATED_FOR, or use your own wrappers around them. */ #ifdef CLUTTER_DISABLE_DEPRECATION_WARNINGS #define CLUTTER_DEPRECATED _CLUTTER_EXTERN #define CLUTTER_DEPRECATED_FOR(f) _CLUTTER_EXTERN #define CLUTTER_UNAVAILABLE(maj,min) _CLUTTER_EXTERN #define CLUTTER_DEPRECATED_MACRO #define CLUTTER_DEPRECATED_MACRO_FOR(f) #else #define CLUTTER_DEPRECATED G_DEPRECATED _CLUTTER_EXTERN #define CLUTTER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _CLUTTER_EXTERN #define CLUTTER_UNAVAILABLE(maj,min) G_UNAVAILABLE(maj,min) _CLUTTER_EXTERN #define CLUTTER_DEPRECATED_MACRO _CLUTTER_DEPRECATED_MACRO #define CLUTTER_DEPRECATED_MACRO_FOR(f) _CLUTTER_DEPRECATED_MACRO_FOR(f) #endif #define CLUTTER_AVAILABLE_IN_ALL _CLUTTER_EXTERN #define CLUTTER_AVAILABLE_IN_MUFFIN _CLUTTER_EXTERN /** * CLUTTER_VERSION_MIN_REQUIRED: * * A macro that should be defined by the user prior to including the * clutter.h header. * * The definition should be one of the predefined Clutter version macros, * such as: %CLUTTER_VERSION_1_0, %CLUTTER_VERSION_1_2, ... * * This macro defines the lower bound for the Clutter API to be used. * * If a function has been deprecated in a newer version of Clutter, it * is possible to use this symbol to avoid the compiler warnings without * disabling warnings for every deprecated function. * * Since: 1.10 */ #ifndef CLUTTER_VERSION_MIN_REQUIRED # define CLUTTER_VERSION_MIN_REQUIRED (CLUTTER_VERSION_CUR_STABLE) #endif /** * CLUTTER_VERSION_MAX_ALLOWED: * * A macro that should be define by the user prior to including the * clutter.h header. * * The definition should be one of the predefined Clutter version macros, * such as: %CLUTTER_VERSION_1_0, %CLUTTER_VERSION_1_2, ... * * This macro defines the upper bound for the Clutter API to be used. * * If a function has been introduced in a newer version of Clutter, it * is possible to use this symbol to get compiler warnings when trying * to use that function. * * Since: 1.10 */ #ifndef CLUTTER_VERSION_MAX_ALLOWED # if CLUTTER_VERSION_MIN_REQUIRED > CLUTTER_VERSION_PREV_STABLE # define CLUTTER_VERSION_MAX_ALLOWED CLUTTER_VERSION_MIN_REQUIRED # else # define CLUTTER_VERSION_MAX_ALLOWED CLUTTER_VERSION_CUR_STABLE # endif #endif /* sanity checks */ #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_MIN_REQUIRED # error "CLUTTER_VERSION_MAX_ALLOWED must be >= CLUTTER_VERSION_MIN_REQUIRED" #endif #if CLUTTER_VERSION_MIN_REQUIRED < CLUTTER_VERSION_1_0 # error "CLUTTER_VERSION_MIN_REQUIRED must be >= CLUTTER_VERSION_1_0" #endif /* XXX: Every new stable minor release should add a set of macros here */ #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_0 # define CLUTTER_DEPRECATED_IN_1_0 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_0_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_0 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_0_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_0 # define CLUTTER_AVAILABLE_IN_1_0 CLUTTER_UNAVAILABLE(1, 0) #else # define CLUTTER_AVAILABLE_IN_1_0 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_2 # define CLUTTER_DEPRECATED_IN_1_2 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_2_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_2 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_2_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_2 # define CLUTTER_AVAILABLE_IN_1_2 CLUTTER_UNAVAILABLE(1, 2) #else # define CLUTTER_AVAILABLE_IN_1_2 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_4 # define CLUTTER_DEPRECATED_IN_1_4 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_4_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_4 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_4_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_4 # define CLUTTER_AVAILABLE_IN_1_4 CLUTTER_UNAVAILABLE(1, 4) #else # define CLUTTER_AVAILABLE_IN_1_4 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_6 # define CLUTTER_DEPRECATED_IN_1_6 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_6_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_6 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_6_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_6 # define CLUTTER_AVAILABLE_IN_1_6 CLUTTER_UNAVAILABLE(1, 6) #else # define CLUTTER_AVAILABLE_IN_1_6 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_8 # define CLUTTER_DEPRECATED_IN_1_8 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_8_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_8 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_8_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_8 # define CLUTTER_AVAILABLE_IN_1_8 CLUTTER_UNAVAILABLE(1, 8) #else # define CLUTTER_AVAILABLE_IN_1_8 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_10 # define CLUTTER_DEPRECATED_IN_1_10 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_10_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_10 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_10_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_10 # define CLUTTER_AVAILABLE_IN_1_10 CLUTTER_UNAVAILABLE(1, 10) #else # define CLUTTER_AVAILABLE_IN_1_10 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_12 # define CLUTTER_DEPRECATED_IN_1_12 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_12_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_12 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_12_FOR(f) _CLUTTER_EXTERN #endif #define CLUTTER_DEPRECATED_IN_MUFFIN CLUTTER_DEPRECATED #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_12 # define CLUTTER_AVAILABLE_IN_1_12 CLUTTER_UNAVAILABLE(1, 12) #else # define CLUTTER_AVAILABLE_IN_1_12 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_14 # define CLUTTER_DEPRECATED_IN_1_14 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_14_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_14 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_14_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_14 # define CLUTTER_AVAILABLE_IN_1_14 CLUTTER_UNAVAILABLE(1, 14) #else # define CLUTTER_AVAILABLE_IN_1_14 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_16 # define CLUTTER_DEPRECATED_IN_1_16 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_16_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_16 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_16_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_16 # define CLUTTER_AVAILABLE_IN_1_16 CLUTTER_UNAVAILABLE(1, 16) #else # define CLUTTER_AVAILABLE_IN_1_16 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_18 # define CLUTTER_DEPRECATED_IN_1_18 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_18_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_18 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_18_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_18 # define CLUTTER_AVAILABLE_IN_1_18 CLUTTER_UNAVAILABLE(1, 18) #else # define CLUTTER_AVAILABLE_IN_1_18 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_20 # define CLUTTER_DEPRECATED_IN_1_20 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_20_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_20 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_20_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_20 # define CLUTTER_AVAILABLE_IN_1_20 CLUTTER_UNAVAILABLE(1, 20) #else # define CLUTTER_AVAILABLE_IN_1_20 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_22 # define CLUTTER_DEPRECATED_IN_1_22 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_22_FOR(f) CLUTTER_DEPRECATED_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_22 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_22_FOR(f) _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_22 # define CLUTTER_AVAILABLE_IN_1_22 CLUTTER_UNAVAILABLE(1, 22) #else # define CLUTTER_AVAILABLE_IN_1_22 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_24 # define CLUTTER_DEPRECATED_IN_1_24 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_24_FOR(f) CLUTTER_DEPRECATED_FOR(f) # define CLUTTER_MACRO_DEPRECATED_IN_1_24 CLUTTER_DEPRECATED_MACRO # define CLUTTER_MACRO_DEPRECATED_IN_1_24_FOR(f) CLUTTER_DEPRECATED_MACRO_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_24 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_24_FOR(f) _CLUTTER_EXTERN # define CLUTTER_MACRO_DEPRECATED_IN_1_24 # define CLUTTER_MACRO_DEPRECATED_IN_1_24_FOR(f) #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_24 # define CLUTTER_AVAILABLE_IN_1_24 CLUTTER_UNAVAILABLE(1, 24) #else # define CLUTTER_AVAILABLE_IN_1_24 _CLUTTER_EXTERN #endif #if CLUTTER_VERSION_MIN_REQUIRED >= CLUTTER_VERSION_1_26 # define CLUTTER_DEPRECATED_IN_1_26 CLUTTER_DEPRECATED # define CLUTTER_DEPRECATED_IN_1_26_FOR(f) CLUTTER_DEPRECATED_FOR(f) # define CLUTTER_MACRO_DEPRECATED_IN_1_26 CLUTTER_DEPRECATED_MACRO # define CLUTTER_MACRO_DEPRECATED_IN_1_26_FOR(f) CLUTTER_DEPRECATED_MACRO_FOR(f) #else # define CLUTTER_DEPRECATED_IN_1_26 _CLUTTER_EXTERN # define CLUTTER_DEPRECATED_IN_1_26_FOR(f) _CLUTTER_EXTERN # define CLUTTER_MACRO_DEPRECATED_IN_1_26 # define CLUTTER_MACRO_DEPRECATED_IN_1_26_FOR(f) #endif #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_26 # define CLUTTER_AVAILABLE_IN_1_26 CLUTTER_UNAVAILABLE(1, 26) #else # define CLUTTER_AVAILABLE_IN_1_26 _CLUTTER_EXTERN #endif #endif /* __CLUTTER_MACROS_H__ */ muffin-5.2.1/clutter/clutter/clutter-layout-manager.h0000664000175000017500000003023514211404421023061 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_LAYOUT_MANAGER_H__ #define __CLUTTER_LAYOUT_MANAGER_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_LAYOUT_MANAGER (clutter_layout_manager_get_type ()) #define CLUTTER_LAYOUT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYOUT_MANAGER, ClutterLayoutManager)) #define CLUTTER_IS_LAYOUT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYOUT_MANAGER)) #define CLUTTER_LAYOUT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_LAYOUT_MANAGER, ClutterLayoutManagerClass)) #define CLUTTER_IS_LAYOUT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_LAYOUT_MANAGER)) #define CLUTTER_LAYOUT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_LAYOUT_MANAGER, ClutterLayoutManagerClass)) typedef struct _ClutterLayoutManagerClass ClutterLayoutManagerClass; /** * ClutterLayoutManager: * * The #ClutterLayoutManager structure contains only private data * and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterLayoutManager { /*< private >*/ GInitiallyUnowned parent_instance; gpointer CLUTTER_PRIVATE_FIELD (dummy); }; /** * ClutterLayoutManagerClass: * @get_preferred_width: virtual function; override to provide a preferred * width for the layout manager. See also the get_preferred_width() * virtual function in #ClutterActor * @get_preferred_height: virtual function; override to provide a preferred * height for the layout manager. See also the get_preferred_height() * virtual function in #ClutterActor * @allocate: virtual function; override to allocate the children of the * layout manager. See also the allocate() virtual function in * #ClutterActor * @set_container: virtual function; override to set a back pointer * on the #ClutterContainer using the layout manager. The implementation * should not take a reference on the container, but just take a weak * reference, to avoid potential leaks due to reference cycles * @get_child_meta_type: virtual function; override to return the #GType * of the #ClutterLayoutMeta sub-class used by the #ClutterLayoutManager * @create_child_meta: virtual function; override to create a * #ClutterLayoutMeta instance associated to a #ClutterContainer and a * child #ClutterActor, used to maintain layout manager specific properties * @begin_animation: virtual function; override to control the animation * of a #ClutterLayoutManager with the given duration and easing mode. * This virtual function is deprecated, and it should not be overridden * in newly written code. * @end_animation: virtual function; override to end an animation started * by clutter_layout_manager_begin_animation(). This virtual function is * deprecated, and it should not be overriden in newly written code. * @get_animation_progress: virtual function; override to control the * progress of the animation of a #ClutterLayoutManager. This virtual * function is deprecated, and it should not be overridden in newly written * code. * @layout_changed: class handler for the #ClutterLayoutManager::layout-changed * signal * * The #ClutterLayoutManagerClass structure contains only private * data and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterLayoutManagerClass { /*< private >*/ GInitiallyUnownedClass parent_class; /*< public >*/ void (* get_preferred_width) (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p); void (* get_preferred_height) (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p); void (* allocate) (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags); void (* set_container) (ClutterLayoutManager *manager, ClutterContainer *container); GType (* get_child_meta_type) (ClutterLayoutManager *manager); ClutterLayoutMeta *(* create_child_meta) (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor); /* deprecated */ ClutterAlpha * (* begin_animation) (ClutterLayoutManager *manager, guint duration, gulong mode); /* deprecated */ gdouble (* get_animation_progress) (ClutterLayoutManager *manager); /* deprecated */ void (* end_animation) (ClutterLayoutManager *manager); void (* layout_changed) (ClutterLayoutManager *manager); /*< private >*/ /* padding for future expansion */ void (* _clutter_padding_1) (void); void (* _clutter_padding_2) (void); void (* _clutter_padding_3) (void); void (* _clutter_padding_4) (void); void (* _clutter_padding_5) (void); void (* _clutter_padding_6) (void); void (* _clutter_padding_7) (void); void (* _clutter_padding_8) (void); }; CLUTTER_AVAILABLE_IN_1_2 GType clutter_layout_manager_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p); CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p); CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags); CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_set_container (ClutterLayoutManager *manager, ClutterContainer *container); CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_layout_changed (ClutterLayoutManager *manager); CLUTTER_AVAILABLE_IN_1_2 GParamSpec * clutter_layout_manager_find_child_property (ClutterLayoutManager *manager, const gchar *name); CLUTTER_AVAILABLE_IN_1_2 GParamSpec ** clutter_layout_manager_list_child_properties (ClutterLayoutManager *manager, guint *n_pspecs); CLUTTER_AVAILABLE_IN_1_2 ClutterLayoutMeta *clutter_layout_manager_get_child_meta (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor); CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_child_set (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *first_property, ...) G_GNUC_NULL_TERMINATED; CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_child_get (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *first_property, ...) G_GNUC_NULL_TERMINATED; CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_child_set_property (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *property_name, const GValue *value); CLUTTER_AVAILABLE_IN_1_2 void clutter_layout_manager_child_get_property (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor, const gchar *property_name, GValue *value); CLUTTER_DEPRECATED_IN_1_12 ClutterAlpha * clutter_layout_manager_begin_animation (ClutterLayoutManager *manager, guint duration, gulong mode); CLUTTER_DEPRECATED_IN_1_12 void clutter_layout_manager_end_animation (ClutterLayoutManager *manager); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_layout_manager_get_animation_progress (ClutterLayoutManager *manager); G_END_DECLS #endif /* __CLUTTER_LAYOUT_MANAGER_H__ */ muffin-5.2.1/clutter/clutter/clutter-canvas.h0000664000175000017500000000661214211404421021411 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_CANVAS_H__ #define __CLUTTER_CANVAS_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_CANVAS (clutter_canvas_get_type ()) #define CLUTTER_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CANVAS, ClutterCanvas)) #define CLUTTER_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CANVAS)) #define CLUTTER_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CANVAS, ClutterCanvasClass)) #define CLUTTER_IS_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CANVAS)) #define CLUTTER_CANVAS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CANVAS, ClutterCanvasClass)) typedef struct _ClutterCanvas ClutterCanvas; typedef struct _ClutterCanvasPrivate ClutterCanvasPrivate; typedef struct _ClutterCanvasClass ClutterCanvasClass; /** * ClutterCanvas: * * The #ClutterCanvas structure contains * private data and should only be accessed using the provided * API. * * Since: 1.10 */ struct _ClutterCanvas { /*< private >*/ GObject parent_instance; ClutterCanvasPrivate *priv; }; /** * ClutterCanvasClass: * @draw: class handler for the #ClutterCanvas::draw signal * * The #ClutterCanvasClass structure contains * private data. * * Since: 1.10 */ struct _ClutterCanvasClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ gboolean (* draw) (ClutterCanvas *canvas, cairo_t *cr, int width, int height); /*< private >*/ gpointer _padding[16]; }; CLUTTER_AVAILABLE_IN_1_10 GType clutter_canvas_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_10 ClutterContent * clutter_canvas_new (void); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_canvas_set_size (ClutterCanvas *canvas, int width, int height); CLUTTER_AVAILABLE_IN_1_18 void clutter_canvas_set_scale_factor (ClutterCanvas *canvas, int scale); CLUTTER_AVAILABLE_IN_1_18 int clutter_canvas_get_scale_factor (ClutterCanvas *canvas); G_END_DECLS #endif /* __CLUTTER_CANVAS_H__ */ muffin-5.2.1/clutter/clutter/clutter-scriptable.c0000664000175000017500000001312414211404421022255 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Emmanuele Bassi * * Copyright (C) 2006 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, see . * * */ /** * SECTION:clutter-scriptable * @short_description: Override the UI definition parsing * * The #ClutterScriptableIface interface exposes the UI definition parsing * process to external classes. By implementing this interface, a class can * override the UI definition parsing and transform complex data types into * GObject properties, or allow custom properties. * * #ClutterScriptable is available since Clutter 0.6 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #include "clutter-scriptable.h" #include "clutter-script-private.h" #include "clutter-private.h" #include "clutter-debug.h" typedef ClutterScriptableIface ClutterScriptableInterface; G_DEFINE_INTERFACE (ClutterScriptable, clutter_scriptable, G_TYPE_OBJECT); static void clutter_scriptable_default_init (ClutterScriptableInterface *iface) { } /** * clutter_scriptable_set_id: * @scriptable: a #ClutterScriptable * @id_: the #ClutterScript id of the object * * Sets @id_ as the unique Clutter script it for this instance of * #ClutterScriptableIface. * * This name can be used by user interface designer applications to * define a unique name for an object constructable using the UI * definition language parsed by #ClutterScript. * * Since: 0.6 */ void clutter_scriptable_set_id (ClutterScriptable *scriptable, const gchar *id_) { ClutterScriptableIface *iface; g_return_if_fail (CLUTTER_IS_SCRIPTABLE (scriptable)); g_return_if_fail (id_ != NULL); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); if (iface->set_id) iface->set_id (scriptable, id_); else g_object_set_data_full (G_OBJECT (scriptable), "clutter-script-id", g_strdup (id_), free); } /** * clutter_scriptable_get_id: * @scriptable: a #ClutterScriptable * * Retrieves the id of @scriptable set using clutter_scriptable_set_id(). * * Return value: the id of the object. The returned string is owned by * the scriptable object and should never be modified of freed * * Since: 0.6 */ const gchar * clutter_scriptable_get_id (ClutterScriptable *scriptable) { ClutterScriptableIface *iface; g_return_val_if_fail (CLUTTER_IS_SCRIPTABLE (scriptable), NULL); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); if (iface->get_id) return iface->get_id (scriptable); else return g_object_get_data (G_OBJECT (scriptable), "clutter-script-id"); } /** * clutter_scriptable_parse_custom_node: * @scriptable: a #ClutterScriptable * @script: the #ClutterScript creating the scriptable instance * @value: the generic value to be set * @name: the name of the node * @node: the JSON node to be parsed * * Parses the passed JSON node. The implementation must set the type * of the passed #GValue pointer using g_value_init(). * * Return value: %TRUE if the node was successfully parsed, %FALSE otherwise. * * Since: 0.6 */ gboolean clutter_scriptable_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { ClutterScriptableIface *iface; g_return_val_if_fail (CLUTTER_IS_SCRIPTABLE (scriptable), FALSE); g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (node != NULL, FALSE); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); if (iface->parse_custom_node) return iface->parse_custom_node (scriptable, script, value, name, node); return FALSE; } /** * clutter_scriptable_set_custom_property: * @scriptable: a #ClutterScriptable * @script: the #ClutterScript creating the scriptable instance * @name: the name of the property * @value: the value of the property * * Overrides the common properties setting. The underlying virtual * function should be used when implementing custom properties. * * Since: 0.6 */ void clutter_scriptable_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { ClutterScriptableIface *iface; g_return_if_fail (CLUTTER_IS_SCRIPTABLE (scriptable)); g_return_if_fail (CLUTTER_IS_SCRIPT (script)); g_return_if_fail (name != NULL); g_return_if_fail (value != NULL); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); if (iface->set_custom_property) iface->set_custom_property (scriptable, script, name, value); } muffin-5.2.1/clutter/clutter/clutter.h0000664000175000017500000000716014211404421020137 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * */ #ifndef __CLUTTER_H__ #define __CLUTTER_H__ #define __CLUTTER_H_INSIDE__ #include "clutter-config.h" #include "clutter-types.h" #include "clutter-action.h" #include "clutter-actor.h" #include "clutter-actor-meta.h" #include "clutter-align-constraint.h" #include "clutter-animatable.h" #include "clutter-backend.h" #include "clutter-bind-constraint.h" #include "clutter-binding-pool.h" #include "clutter-bin-layout.h" #include "clutter-blur-effect.h" #include "clutter-box-layout.h" #include "clutter-brightness-contrast-effect.h" #include "clutter-cairo.h" #include "clutter-canvas.h" #include "clutter-child-meta.h" #include "clutter-click-action.h" #include "clutter-clone.h" #include "clutter-color.h" #include "clutter-color-static.h" #include "clutter-colorize-effect.h" #include "clutter-constraint.h" #include "clutter-container.h" #include "clutter-content.h" #include "clutter-deform-effect.h" #include "clutter-desaturate-effect.h" #include "clutter-device-manager.h" #include "clutter-drag-action.h" #include "clutter-drop-action.h" #include "clutter-effect.h" #include "clutter-enums.h" #include "clutter-enum-types.h" #include "clutter-event.h" #include "clutter-feature.h" #include "clutter-fixed-layout.h" #include "clutter-flow-layout.h" #include "clutter-gesture-action.h" #include "clutter-grid-layout.h" #include "clutter-group.h" #include "clutter-image.h" #include "clutter-input-device.h" #include "clutter-input-device-tool.h" #include "clutter-input-method.h" #include "clutter-input-focus.h" #include "clutter-interval.h" #include "clutter-keyframe-transition.h" #include "clutter-keysyms.h" #include "clutter-layout-manager.h" #include "clutter-layout-meta.h" #include "clutter-macros.h" #include "clutter-main.h" #include "clutter-offscreen-effect.h" #include "clutter-page-turn-effect.h" #include "clutter-paint-nodes.h" #include "clutter-paint-node.h" #include "clutter-pan-action.h" #include "clutter-path-constraint.h" #include "clutter-path.h" #include "clutter-property-transition.h" #include "clutter-rotate-action.h" #include "clutter-scriptable.h" #include "clutter-script.h" #include "clutter-scroll-actor.h" #include "clutter-settings.h" #include "clutter-shader-effect.h" #include "clutter-shader-types.h" #include "clutter-swipe-action.h" #include "clutter-snap-constraint.h" #include "clutter-stage.h" #include "clutter-stage-manager.h" #include "clutter-tap-action.h" #include "clutter-test-utils.h" #include "clutter-texture.h" #include "clutter-text.h" #include "clutter-timeline.h" #include "clutter-transition-group.h" #include "clutter-transition.h" #include "clutter-units.h" #include "clutter-version.h" #include "clutter-virtual-input-device.h" #include "clutter-zoom-action.h" #include "clutter-deprecated.h" #include "clutter-autocleanups.h" #undef __CLUTTER_H_INSIDE__ #endif /* __CLUTTER_H__ */ muffin-5.2.1/clutter/clutter/cogl/0000775000175000017500000000000014211404421017224 5ustar jpeisachjpeisachmuffin-5.2.1/clutter/clutter/cogl/clutter-stage-cogl.h0000664000175000017500000000531214211404421023103 0ustar jpeisachjpeisach#ifndef __CLUTTER_STAGE_COGL_H__ #define __CLUTTER_STAGE_COGL_H__ #include #include #include #ifdef COGL_HAS_X11_SUPPORT #include #include #include #endif #include "clutter/clutter-stage-window.h" G_BEGIN_DECLS #define CLUTTER_TYPE_STAGE_COGL (_clutter_stage_cogl_get_type ()) #define CLUTTER_STAGE_COGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_COGL, ClutterStageCogl)) #define CLUTTER_IS_STAGE_COGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_COGL)) #define CLUTTER_STAGE_COGL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_COGL, ClutterStageCoglClass)) #define CLUTTER_IS_STAGE_COGL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_COGL)) #define CLUTTER_STAGE_COGL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_COGL, ClutterStageCoglClass)) typedef struct _ClutterStageCogl ClutterStageCogl; typedef struct _ClutterStageCoglClass ClutterStageCoglClass; G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterStageCogl, g_object_unref) #define CLUTTER_TYPE_STAGE_VIEW_COGL (clutter_stage_view_cogl_get_type ()) CLUTTER_AVAILABLE_IN_MUFFIN G_DECLARE_DERIVABLE_TYPE (ClutterStageViewCogl, clutter_stage_view_cogl, CLUTTER, STAGE_VIEW_COGL, ClutterStageView) struct _ClutterStageViewCoglClass { ClutterStageViewClass parent_class; }; struct _ClutterStageCogl { GObject parent_instance; /* the stage wrapper */ ClutterStage *wrapper; /* back pointer to the backend */ ClutterBackend *backend; float refresh_rate; int pending_swaps; int max_buffer_age; gint64 last_update_time; gint64 last_presentation_time; gint64 update_time; /* We only enable clipped redraws after 2 frames, since we've seen * a lot of drivers can struggle to get going and may output some * junk frames to start with. */ unsigned int frame_count; cairo_rectangle_int_t bounding_redraw_clip; guint initialized_redraw_clip : 1; /* TRUE if the current paint cycle has a clipped redraw. In that case bounding_redraw_clip specifies the the bounds. */ guint using_clipped_redraw : 1; }; struct _ClutterStageCoglClass { GObjectClass parent_class; }; CLUTTER_AVAILABLE_IN_MUFFIN GType _clutter_stage_cogl_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_MUFFIN void _clutter_stage_cogl_presented (ClutterStageCogl *stage_cogl, CoglFrameEvent frame_event, ClutterFrameInfo *frame_info); G_END_DECLS #endif /* __CLUTTER_STAGE_COGL_H__ */ muffin-5.2.1/clutter/clutter/cogl/clutter-stage-cogl.c0000664000175000017500000010220414211404421023074 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation. * * 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, see . * Authors: * Matthew Allum * Robert Bragg * Neil Roberts * Emmanuele Bassi */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-config.h" #include "clutter-stage-cogl.h" #include #include #include "clutter-actor-private.h" #include "clutter-backend-private.h" #include "clutter-debug.h" #include "clutter-event.h" #include "clutter-enum-types.h" #include "clutter-feature.h" #include "clutter-main.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-muffin.h" typedef struct _ClutterStageViewCoglPrivate { /* * List of previous damaged areas in stage view framebuffer coordinate space. */ #define DAMAGE_HISTORY_MAX 16 #define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1)) cairo_rectangle_int_t damage_history[DAMAGE_HISTORY_MAX]; unsigned int damage_index; } ClutterStageViewCoglPrivate; G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl, CLUTTER_TYPE_STAGE_VIEW) static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl, _clutter_stage_cogl, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, clutter_stage_window_iface_init)); enum { PROP_0, PROP_WRAPPER, PROP_BACKEND, PROP_LAST }; static void clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window) { CLUTTER_NOTE (BACKEND, "Unrealizing Cogl stage [%p]", stage_window); } void _clutter_stage_cogl_presented (ClutterStageCogl *stage_cogl, CoglFrameEvent frame_event, ClutterFrameInfo *frame_info) { if (frame_event == COGL_FRAME_EVENT_SYNC) { /* Early versions of the swap_event implementation in Mesa * deliver BufferSwapComplete event when not selected for, * so if we get a swap event we aren't expecting, just ignore it. * * https://bugs.freedesktop.org/show_bug.cgi?id=27962 * * FIXME: This issue can be hidden inside Cogl so we shouldn't * need to care about this bug here. */ if (stage_cogl->pending_swaps > 0) stage_cogl->pending_swaps--; } else if (frame_event == COGL_FRAME_EVENT_COMPLETE) { gint64 presentation_time_cogl = frame_info->presentation_time; if (presentation_time_cogl != 0) { ClutterBackend *backend = stage_cogl->backend; CoglContext *context = clutter_backend_get_cogl_context (backend); gint64 current_time_cogl = cogl_get_clock_time (context); gint64 now = g_get_monotonic_time (); stage_cogl->last_presentation_time = now + (presentation_time_cogl - current_time_cogl) / 1000; } stage_cogl->refresh_rate = frame_info->refresh_rate; } _clutter_stage_presented (stage_cogl->wrapper, frame_event, frame_info); } static gboolean clutter_stage_cogl_realize (ClutterStageWindow *stage_window) { ClutterBackend *backend; CLUTTER_NOTE (BACKEND, "Realizing stage '%s' [%p]", G_OBJECT_TYPE_NAME (stage_window), stage_window); backend = clutter_get_default_backend (); if (backend->cogl_context == NULL) { g_warning ("Failed to realize stage: missing Cogl context"); return FALSE; } return TRUE; } static void clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window, gint sync_delay) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); gint64 now; gint64 target_presentation_time; gint64 refresh_interval; /* * want_prerender_frames must be at least 1 (double buffered). * Feel free to try triple buffering: want_prerender_frames = 2 * but it's not a good idea to default to that yet because filling all the * buffers will cause the backend to block and throttle buffer releases even * to unthrottled clients (swap interval 0). */ gint want_prerender_frames = 1; gint can_prerender_frames; gint will_prerender_frames; gint64 prerender_time; if (stage_cogl->update_time != -1) return; now = g_get_monotonic_time (); if (sync_delay < 0 || stage_cogl->last_presentation_time <= 0 || stage_cogl->refresh_rate <= 0.0) { /* -1 now means that hardware presentation times are unsupported and * that the caller needs to find a different way to achieve frame * scheduling. */ stage_cogl->update_time = -1; return; } /* FIXME (?) - On X11 this is performing worse than swap throttling. */ if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION)) refresh_interval = (gint64) (0.5 + 1000000 / stage_cogl->refresh_rate); else refresh_interval = 0; target_presentation_time = stage_cogl->last_presentation_time + stage_cogl->pending_swaps * refresh_interval + refresh_interval; if (target_presentation_time < now) { /* If we missed some frames then find a more current target time that's * in phase with the display hardware. This is logically equivalent to: * * while (target_presentation_time < now) * target_presentation_time += refresh_interval; * * but with a better worst-case execution time... */ target_presentation_time = now - now % refresh_interval + stage_cogl->last_presentation_time % refresh_interval; if (target_presentation_time < now) target_presentation_time += refresh_interval; } can_prerender_frames = MAX (1, stage_cogl->max_buffer_age - 1); will_prerender_frames = MIN (want_prerender_frames, can_prerender_frames); prerender_time = will_prerender_frames * refresh_interval - 1000 * sync_delay; stage_cogl->update_time = target_presentation_time - prerender_time; /* Are we repeating ourselves? If a clear and reschedule occur too close * together while a swap is pending then we will often land on the same * result as last time. That's not useful because it only suggests to the * caller to try and render the same frame twice. */ if (stage_cogl->update_time <= stage_cogl->last_update_time) stage_cogl->update_time = stage_cogl->last_update_time + refresh_interval; } static gint64 clutter_stage_cogl_get_update_time (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); return stage_cogl->update_time; } static void clutter_stage_cogl_clear_update_time (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); stage_cogl->last_update_time = stage_cogl->update_time; stage_cogl->update_time = -1; } static ClutterActor * clutter_stage_cogl_get_wrapper (ClutterStageWindow *stage_window) { return CLUTTER_ACTOR (CLUTTER_STAGE_COGL (stage_window)->wrapper); } static void clutter_stage_cogl_show (ClutterStageWindow *stage_window, gboolean do_raise) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); clutter_actor_map (CLUTTER_ACTOR (stage_cogl->wrapper)); } static void clutter_stage_cogl_hide (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); clutter_actor_unmap (CLUTTER_ACTOR (stage_cogl->wrapper)); } static void clutter_stage_cogl_resize (ClutterStageWindow *stage_window, gint width, gint height) { } static gboolean clutter_stage_cogl_has_redraw_clips (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); /* NB: at the start of each new frame there is an implied clip that * clips everything (i.e. nothing would be drawn) so we need to make * sure we return True in the un-initialized case here. * * NB: a clip width of 0 means a full stage redraw has been queued * so we effectively don't have any redraw clips in that case. */ if (!stage_cogl->initialized_redraw_clip || (stage_cogl->initialized_redraw_clip && stage_cogl->bounding_redraw_clip.width != 0)) return TRUE; else return FALSE; } static gboolean clutter_stage_cogl_ignoring_redraw_clips (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); /* NB: a clip width of 0 means a full stage redraw is required */ if (stage_cogl->initialized_redraw_clip && stage_cogl->bounding_redraw_clip.width == 0) return TRUE; else return FALSE; } /* A redraw clip represents (in stage coordinates) the bounding box of * something that needs to be redraw. Typically they are added to the * StageWindow as a result of clutter_actor_queue_clipped_redraw() by * actors such as ClutterGLXTexturePixmap. All redraw clips are * discarded after the next paint. * * A NULL stage_clip means the whole stage needs to be redrawn. * * What we do with this information: * - we keep track of the bounding box for all redraw clips * - when we come to redraw; we scissor the redraw to that box and use * glBlitFramebuffer to present the redraw to the front * buffer. */ static void clutter_stage_cogl_add_redraw_clip (ClutterStageWindow *stage_window, cairo_rectangle_int_t *stage_clip) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); /* If we are already forced to do a full stage redraw then bail early */ if (clutter_stage_cogl_ignoring_redraw_clips (stage_window)) return; /* A NULL stage clip means a full stage redraw has been queued and * we keep track of this by setting a zero width * stage_cogl->bounding_redraw_clip */ if (stage_clip == NULL) { stage_cogl->bounding_redraw_clip.width = 0; stage_cogl->initialized_redraw_clip = TRUE; return; } /* Ignore requests to add degenerate/empty clip rectangles */ if (stage_clip->width == 0 || stage_clip->height == 0) return; if (!stage_cogl->initialized_redraw_clip) { stage_cogl->bounding_redraw_clip = *stage_clip; } else if (stage_cogl->bounding_redraw_clip.width > 0) { _clutter_util_rectangle_union (&stage_cogl->bounding_redraw_clip, stage_clip, &stage_cogl->bounding_redraw_clip); } stage_cogl->initialized_redraw_clip = TRUE; } static gboolean clutter_stage_cogl_get_redraw_clip_bounds (ClutterStageWindow *stage_window, cairo_rectangle_int_t *stage_clip) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); if (stage_cogl->using_clipped_redraw) { *stage_clip = stage_cogl->bounding_redraw_clip; return TRUE; } return FALSE; } static inline gboolean valid_buffer_age (ClutterStageViewCogl *view_cogl, int age) { ClutterStageViewCoglPrivate *view_priv = clutter_stage_view_cogl_get_instance_private (view_cogl); if (age <= 0) return FALSE; return age < MIN (view_priv->damage_index, DAMAGE_HISTORY_MAX); } static gboolean swap_framebuffer (ClutterStageWindow *stage_window, ClutterStageView *view, cairo_rectangle_int_t *swap_region, gboolean swap_with_damage) { CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view); int damage[4], ndamage; damage[0] = swap_region->x; damage[1] = swap_region->y; damage[2] = swap_region->width; damage[3] = swap_region->height; if (swap_region->width != 0) ndamage = 1; else ndamage = 0; if (cogl_is_onscreen (framebuffer)) { CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); /* push on the screen */ if (ndamage == 1 && !swap_with_damage) { CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_region (onscreen: %p, " "x: %d, y: %d, " "width: %d, height: %d)", onscreen, damage[0], damage[1], damage[2], damage[3]); cogl_onscreen_swap_region (onscreen, damage, ndamage); return FALSE; } else { CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_buffers (onscreen: %p)", onscreen); cogl_onscreen_swap_buffers_with_damage (onscreen, damage, ndamage); return TRUE; } } else { CLUTTER_NOTE (BACKEND, "cogl_framebuffer_finish (framebuffer: %p)", framebuffer); cogl_framebuffer_finish (framebuffer); return FALSE; } } static void paint_stage (ClutterStageCogl *stage_cogl, ClutterStageView *view, const cairo_rectangle_int_t *clip) { ClutterStage *stage = stage_cogl->wrapper; _clutter_stage_maybe_setup_viewport (stage, view); _clutter_stage_paint_view (stage, view, clip); if (clutter_stage_view_get_onscreen (view) != clutter_stage_view_get_framebuffer (view)) { clutter_stage_view_blit_offscreen (view, clip); } } static void fill_current_damage_history_and_step (ClutterStageView *view) { ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view); ClutterStageViewCoglPrivate *view_priv = clutter_stage_view_cogl_get_instance_private (view_cogl); cairo_rectangle_int_t view_rect; float fb_scale; cairo_rectangle_int_t *current_fb_damage; current_fb_damage = &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index)]; clutter_stage_view_get_layout (view, &view_rect); fb_scale = clutter_stage_view_get_scale (view); *current_fb_damage = (cairo_rectangle_int_t) { .x = 0, .y = 0, .width = view_rect.width * fb_scale, .height = view_rect.height * fb_scale }; view_priv->damage_index++; } static void transform_swap_region_to_onscreen (ClutterStageView *view, cairo_rectangle_int_t *swap_region) { CoglFramebuffer *framebuffer; cairo_rectangle_int_t layout; gfloat x1, y1, x2, y2; gint width, height; framebuffer = clutter_stage_view_get_onscreen (view); clutter_stage_view_get_layout (view, &layout); x1 = (float) swap_region->x / layout.width; y1 = (float) swap_region->y / layout.height; x2 = (float) (swap_region->x + swap_region->width) / layout.width; y2 = (float) (swap_region->y + swap_region->height) / layout.height; clutter_stage_view_transform_to_onscreen (view, &x1, &y1); clutter_stage_view_transform_to_onscreen (view, &x2, &y2); width = cogl_framebuffer_get_width (framebuffer); height = cogl_framebuffer_get_height (framebuffer); x1 = floor (x1 * width); y1 = floor (height - (y1 * height)); x2 = ceil (x2 * width); y2 = ceil (height - (y2 * height)); *swap_region = (cairo_rectangle_int_t) { .x = x1, .y = y1, .width = x2 - x1, .height = y2 - y1 }; } static void calculate_scissor_region (cairo_rectangle_int_t *fb_clip_region, int subpixel_compensation, int fb_width, int fb_height, cairo_rectangle_int_t *out_scissor_rect) { int scissor_x; int scissor_y; int scissor_width; int scissor_height; scissor_x = fb_clip_region->x; scissor_y = fb_clip_region->y; scissor_width = fb_clip_region->width; scissor_height = fb_clip_region->height; if (fb_clip_region->x > 0) scissor_x += subpixel_compensation; if (fb_clip_region->y > 0) scissor_y += subpixel_compensation; if (fb_clip_region->x + fb_clip_region->width < fb_width) scissor_width -= 2 * subpixel_compensation; if (fb_clip_region->y + fb_clip_region->height < fb_height) scissor_height -= 2 * subpixel_compensation; *out_scissor_rect = (cairo_rectangle_int_t) { .x = scissor_x, .y = scissor_y, .width = scissor_width, .height = scissor_height }; } static gboolean clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, ClutterStageView *view) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view); ClutterStageViewCoglPrivate *view_priv = clutter_stage_view_cogl_get_instance_private (view_cogl); CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view); cairo_rectangle_int_t view_rect; gboolean have_clip; gboolean may_use_clipped_redraw; gboolean use_clipped_redraw; gboolean can_blit_sub_buffer; gboolean has_buffer_age; gboolean do_swap_buffer; gboolean swap_with_damage; ClutterActor *wrapper; cairo_rectangle_int_t redraw_clip; cairo_rectangle_int_t swap_region; cairo_rectangle_int_t fb_clip_region; gboolean clip_region_empty; float fb_scale; int subpixel_compensation = 0; int fb_width, fb_height; wrapper = CLUTTER_ACTOR (stage_cogl->wrapper); clutter_stage_view_get_layout (view, &view_rect); fb_scale = clutter_stage_view_get_scale (view); fb_width = cogl_framebuffer_get_width (fb); fb_height = cogl_framebuffer_get_height (fb); can_blit_sub_buffer = cogl_is_onscreen (fb) && cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION); has_buffer_age = cogl_is_onscreen (fb) && cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE); /* NB: a zero width redraw clip == full stage redraw */ if (stage_cogl->bounding_redraw_clip.width == 0) have_clip = FALSE; else { redraw_clip = stage_cogl->bounding_redraw_clip; _clutter_util_rectangle_intersection (&redraw_clip, &view_rect, &redraw_clip); have_clip = !(redraw_clip.x == view_rect.x && redraw_clip.y == view_rect.y && redraw_clip.width == view_rect.width && redraw_clip.height == view_rect.height); } may_use_clipped_redraw = FALSE; if (_clutter_stage_window_can_clip_redraws (stage_window) && (can_blit_sub_buffer || has_buffer_age) && have_clip && /* some drivers struggle to get going and produce some junk * frames when starting up... */ cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3) { may_use_clipped_redraw = TRUE; if (fb_scale != floorf (fb_scale)) subpixel_compensation = ceilf (fb_scale); fb_clip_region = (cairo_rectangle_int_t) { .x = (floorf ((redraw_clip.x - view_rect.x) * fb_scale) - subpixel_compensation), .y = (floorf ((redraw_clip.y - view_rect.y) * fb_scale) - subpixel_compensation), .width = (ceilf (redraw_clip.width * fb_scale) + (2 * subpixel_compensation)), .height = (ceilf (redraw_clip.height * fb_scale) + (2 * subpixel_compensation)) }; } else { fb_clip_region = (cairo_rectangle_int_t) { 0 }; } if (may_use_clipped_redraw && G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS))) use_clipped_redraw = TRUE; else use_clipped_redraw = FALSE; clip_region_empty = may_use_clipped_redraw && fb_clip_region.width == 0; swap_with_damage = FALSE; if (has_buffer_age) { if (use_clipped_redraw && !clip_region_empty) { int age, i; cairo_rectangle_int_t *current_fb_damage = &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index++)]; age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb)); if (valid_buffer_age (view_cogl, age)) { cairo_rectangle_int_t damage_region; if (age > stage_cogl->max_buffer_age) stage_cogl->max_buffer_age = age; *current_fb_damage = fb_clip_region; for (i = 1; i <= age; i++) { cairo_rectangle_int_t *fb_damage = &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - i - 1)]; _clutter_util_rectangle_union (&fb_clip_region, fb_damage, &fb_clip_region); } /* Update the bounding redraw clip state with the extra damage. */ damage_region = (cairo_rectangle_int_t) { .x = view_rect.x + floorf (fb_clip_region.x / fb_scale), .y = view_rect.y + floorf (fb_clip_region.y / fb_scale), .width = ceilf (fb_clip_region.width / fb_scale), .height = ceilf (fb_clip_region.height / fb_scale) }; _clutter_util_rectangle_union (&stage_cogl->bounding_redraw_clip, &damage_region, &stage_cogl->bounding_redraw_clip); CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: x=%d, y=%d, width=%d, height=%d\n", age, fb_clip_region.x, fb_clip_region.y, fb_clip_region.width, fb_clip_region.height); swap_with_damage = TRUE; } else { CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age); use_clipped_redraw = FALSE; *current_fb_damage = (cairo_rectangle_int_t) { .x = 0, .y = 0, .width = view_rect.width * fb_scale, .height = view_rect.height * fb_scale }; } } else if (!use_clipped_redraw) { fill_current_damage_history_and_step (view); } } cogl_push_framebuffer (fb); if (use_clipped_redraw && clip_region_empty) { CLUTTER_NOTE (CLIPPING, "Empty stage output paint\n"); } else if (use_clipped_redraw) { cairo_rectangle_int_t scissor_rect; calculate_scissor_region (&fb_clip_region, subpixel_compensation, fb_width, fb_height, &scissor_rect); CLUTTER_NOTE (CLIPPING, "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n", scissor_rect.x, scissor_rect.y, scissor_rect.width, scissor_rect.height); stage_cogl->using_clipped_redraw = TRUE; cogl_framebuffer_push_scissor_clip (fb, scissor_rect.x, scissor_rect.y, scissor_rect.width, scissor_rect.height); paint_stage (stage_cogl, view, &(cairo_rectangle_int_t) { .x = view_rect.x + floorf ((fb_clip_region.x - 0) / fb_scale), .y = view_rect.y + floorf ((fb_clip_region.y - 0) / fb_scale), .width = ceilf ((fb_clip_region.width + 0) / fb_scale), .height = ceilf ((fb_clip_region.height + 0) / fb_scale) }); cogl_framebuffer_pop_clip (fb); stage_cogl->using_clipped_redraw = FALSE; } else { CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n"); /* If we are trying to debug redraw issues then we want to pass * the bounding_redraw_clip so it can be visualized */ if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) && may_use_clipped_redraw && !clip_region_empty) { cairo_rectangle_int_t scissor_rect; calculate_scissor_region (&fb_clip_region, subpixel_compensation, fb_width, fb_height, &scissor_rect); cogl_framebuffer_push_scissor_clip (fb, scissor_rect.x, scissor_rect.y, scissor_rect.width, scissor_rect.height); paint_stage (stage_cogl, view, &(cairo_rectangle_int_t) { .x = view_rect.x + floorf (fb_clip_region.x / fb_scale), .y = view_rect.y + floorf (fb_clip_region.y / fb_scale), .width = ceilf (fb_clip_region.width / fb_scale), .height = ceilf (fb_clip_region.height / fb_scale) }); cogl_framebuffer_pop_clip (fb); } else paint_stage (stage_cogl, view, &view_rect); } cogl_pop_framebuffer (); if (may_use_clipped_redraw && G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))) { CoglContext *ctx = cogl_framebuffer_get_context (fb); static CoglPipeline *outline = NULL; ClutterActor *actor = CLUTTER_ACTOR (wrapper); float x_1 = redraw_clip.x; float x_2 = redraw_clip.x + redraw_clip.width; float y_1 = redraw_clip.y; float y_2 = redraw_clip.y + redraw_clip.height; CoglVertexP2 quad[4] = { { x_1, y_1 }, { x_2, y_1 }, { x_2, y_2 }, { x_1, y_2 } }; CoglPrimitive *prim; CoglMatrix modelview; if (outline == NULL) { outline = cogl_pipeline_new (ctx); cogl_pipeline_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff); } prim = cogl_primitive_new_p2 (ctx, COGL_VERTICES_MODE_LINE_LOOP, 4, /* n_vertices */ quad); cogl_framebuffer_push_matrix (fb); cogl_matrix_init_identity (&modelview); _clutter_actor_apply_modelview_transform (actor, &modelview); cogl_framebuffer_set_modelview_matrix (fb, &modelview); cogl_framebuffer_draw_primitive (fb, outline, prim); cogl_framebuffer_pop_matrix (fb); cogl_object_unref (prim); } /* XXX: It seems there will be a race here in that the stage * window may be resized before the cogl_onscreen_swap_region * is handled and so we may copy the wrong region. I can't * really see how we can handle this with the current state of X * but at least in this case a full redraw should be queued by * the resize anyway so it should only exhibit temporary * artefacts. */ if (use_clipped_redraw) { if (use_clipped_redraw && clip_region_empty) { do_swap_buffer = FALSE; } else if (use_clipped_redraw) { swap_region = fb_clip_region; g_assert (swap_region.width > 0); do_swap_buffer = TRUE; } else { swap_region = (cairo_rectangle_int_t) { .x = 0, .y = 0, .width = view_rect.width * fb_scale, .height = view_rect.height * fb_scale, }; do_swap_buffer = TRUE; } } else { swap_region = (cairo_rectangle_int_t) { 0 }; do_swap_buffer = TRUE; } if (do_swap_buffer) { if (clutter_stage_view_get_onscreen (view) != clutter_stage_view_get_framebuffer (view)) { transform_swap_region_to_onscreen (view, &swap_region); } return swap_framebuffer (stage_window, view, &swap_region, swap_with_damage); } else { return FALSE; } } static void clutter_stage_cogl_redraw (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); gboolean swap_event = FALSE; GList *l; for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next) { ClutterStageView *view = l->data; swap_event = clutter_stage_cogl_redraw_view (stage_window, view) || swap_event; } _clutter_stage_window_finish_frame (stage_window); if (swap_event) { /* If we have swap buffer events then cogl_onscreen_swap_buffers * will return immediately and we need to track that there is a * swap in progress... */ if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) stage_cogl->pending_swaps++; } /* reset the redraw clipping for the next paint... */ stage_cogl->initialized_redraw_clip = FALSE; stage_cogl->frame_count++; } static void clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window, ClutterStageView *view, int *x, int *y) { CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view); gboolean has_buffer_age = cogl_is_onscreen (framebuffer) && cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE); float fb_scale; gboolean scale_is_fractional; fb_scale = clutter_stage_view_get_scale (view); if (fb_scale != floorf (fb_scale)) scale_is_fractional = TRUE; else scale_is_fractional = FALSE; /* * Buffer damage is tracked in the framebuffer coordinate space * using the damage history. When fractional scaling is used, a * coordinate on the stage might not correspond to the exact position of any * physical pixel, which causes issues when painting using the pick mode. * * For now, always use the (0, 0) pixel for picking when using fractional * framebuffer scaling. */ if (!has_buffer_age || scale_is_fractional) { *x = 0; *y = 0; } else { ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view); ClutterStageViewCoglPrivate *view_priv = clutter_stage_view_cogl_get_instance_private (view_cogl); cairo_rectangle_int_t *fb_damage; fb_damage = &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - 1)]; *x = fb_damage->x / fb_scale; *y = fb_damage->y / fb_scale; } } static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface) { iface->realize = clutter_stage_cogl_realize; iface->unrealize = clutter_stage_cogl_unrealize; iface->get_wrapper = clutter_stage_cogl_get_wrapper; iface->resize = clutter_stage_cogl_resize; iface->show = clutter_stage_cogl_show; iface->hide = clutter_stage_cogl_hide; iface->schedule_update = clutter_stage_cogl_schedule_update; iface->get_update_time = clutter_stage_cogl_get_update_time; iface->clear_update_time = clutter_stage_cogl_clear_update_time; iface->add_redraw_clip = clutter_stage_cogl_add_redraw_clip; iface->has_redraw_clips = clutter_stage_cogl_has_redraw_clips; iface->ignoring_redraw_clips = clutter_stage_cogl_ignoring_redraw_clips; iface->get_redraw_clip_bounds = clutter_stage_cogl_get_redraw_clip_bounds; iface->redraw = clutter_stage_cogl_redraw; iface->get_dirty_pixel = clutter_stage_cogl_get_dirty_pixel; } static void clutter_stage_cogl_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterStageCogl *self = CLUTTER_STAGE_COGL (gobject); switch (prop_id) { case PROP_WRAPPER: self->wrapper = g_value_get_object (value); break; case PROP_BACKEND: self->backend = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void _clutter_stage_cogl_class_init (ClutterStageCoglClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_stage_cogl_set_property; g_object_class_override_property (gobject_class, PROP_WRAPPER, "wrapper"); g_object_class_override_property (gobject_class, PROP_BACKEND, "backend"); } static void _clutter_stage_cogl_init (ClutterStageCogl *stage) { stage->last_presentation_time = 0; stage->refresh_rate = 0.0; stage->update_time = -1; } static void clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl) { } static void clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass) { } muffin-5.2.1/clutter/clutter/clutter-actor-meta.h0000664000175000017500000000756214211404421022177 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_ACTOR_META_H__ #define __CLUTTER_ACTOR_META_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_ACTOR_META (clutter_actor_meta_get_type ()) #define CLUTTER_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMeta)) #define CLUTTER_IS_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTOR_META)) #define CLUTTER_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass)) #define CLUTTER_IS_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTOR_META)) #define CLUTTER_ACTOR_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass)) typedef struct _ClutterActorMetaPrivate ClutterActorMetaPrivate; typedef struct _ClutterActorMetaClass ClutterActorMetaClass; /** * ClutterActorMeta: * * The #ClutterActorMeta structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterActorMeta { /*< private >*/ GInitiallyUnowned parent_instance; ClutterActorMetaPrivate *priv; }; /** * ClutterActorMetaClass: * @set_actor: virtual function, invoked when attaching and detaching * a #ClutterActorMeta instance to a #ClutterActor * * The #ClutterActorMetaClass structure contains * only private data * * Since: 1.4 */ struct _ClutterActorMetaClass { /*< private >*/ GInitiallyUnownedClass parent_class; /*< public >*/ /** * ClutterActorMetaClass::set_actor: * @meta: a #ClutterActorMeta * @actor: (allow-none): the actor attached to @meta, or %NULL * * Virtual function, called when @meta is attached or detached * from a #ClutterActor. */ void (* set_actor) (ClutterActorMeta *meta, ClutterActor *actor); /*< private >*/ void (* _clutter_meta1) (void); void (* _clutter_meta2) (void); void (* _clutter_meta3) (void); void (* _clutter_meta4) (void); void (* _clutter_meta5) (void); void (* _clutter_meta6) (void); void (* _clutter_meta7) (void); }; CLUTTER_AVAILABLE_IN_1_4 GType clutter_actor_meta_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_meta_set_name (ClutterActorMeta *meta, const gchar *name); CLUTTER_AVAILABLE_IN_1_4 const gchar * clutter_actor_meta_get_name (ClutterActorMeta *meta); CLUTTER_AVAILABLE_IN_1_4 void clutter_actor_meta_set_enabled (ClutterActorMeta *meta, gboolean is_enabled); CLUTTER_AVAILABLE_IN_1_4 gboolean clutter_actor_meta_get_enabled (ClutterActorMeta *meta); CLUTTER_AVAILABLE_IN_1_4 ClutterActor * clutter_actor_meta_get_actor (ClutterActorMeta *meta); G_END_DECLS #endif /* __CLUTTER_ACTOR_META_H__ */ muffin-5.2.1/clutter/clutter/deprecated/0000775000175000017500000000000014211404421020400 5ustar jpeisachjpeisachmuffin-5.2.1/clutter/clutter/deprecated/clutter-table-layout.h0000664000175000017500000002140114211404421024631 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Jose Dapena Paz * * Based on the MX MxTable actor by: * Thomas Wood */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_TABLE_LAYOUT_H__ #define __CLUTTER_TABLE_LAYOUT_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_TABLE_LAYOUT (clutter_table_layout_get_type ()) #define CLUTTER_TABLE_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TABLE_LAYOUT, ClutterTableLayout)) #define CLUTTER_IS_TABLE_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TABLE_LAYOUT)) #define CLUTTER_TABLE_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TABLE_LAYOUT, ClutterTableLayoutClass)) #define CLUTTER_IS_TABLE_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TABLE_LAYOUT)) #define CLUTTER_TABLE_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TABLE_LAYOUT, ClutterTableLayoutClass)) typedef struct _ClutterTableLayout ClutterTableLayout; typedef struct _ClutterTableLayoutPrivate ClutterTableLayoutPrivate; typedef struct _ClutterTableLayoutClass ClutterTableLayoutClass; /** * ClutterTableLayout: * * The #ClutterTableLayout structure contains only private data * and should be accessed using the provided API * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout instead */ struct _ClutterTableLayout { /*< private >*/ ClutterLayoutManager parent_instance; ClutterTableLayoutPrivate *priv; }; /** * ClutterTableLayoutClass: * * The #ClutterTableLayoutClass structure contains only private * data and should be accessed using the provided API * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout instead */ struct _ClutterTableLayoutClass { /*< private >*/ ClutterLayoutManagerClass parent_class; }; CLUTTER_DEPRECATED_IN_1_18_FOR (clutter_grid_layout_get_type) GType clutter_table_layout_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_18_FOR (clutter_grid_layout_new) ClutterLayoutManager *clutter_table_layout_new (void); CLUTTER_DEPRECATED_IN_1_18_FOR (clutter_grid_layout_attach) void clutter_table_layout_pack (ClutterTableLayout *layout, ClutterActor *actor, gint column, gint row); CLUTTER_DEPRECATED_IN_1_18_FOR (clutter_grid_layout_set_column_spacing) void clutter_table_layout_set_column_spacing (ClutterTableLayout *layout, guint spacing); CLUTTER_DEPRECATED_IN_1_18_FOR (clutter_grid_layout_set_row_spacing) void clutter_table_layout_set_row_spacing (ClutterTableLayout *layout, guint spacing); CLUTTER_DEPRECATED_IN_1_18_FOR (clutter_grid_layout_get_column_spacing) guint clutter_table_layout_get_column_spacing (ClutterTableLayout *layout); CLUTTER_DEPRECATED_IN_1_18_FOR (clutter_grid_layout_get_row_spacing) guint clutter_table_layout_get_row_spacing (ClutterTableLayout *layout); CLUTTER_DEPRECATED_IN_1_18 void clutter_table_layout_set_span (ClutterTableLayout *layout, ClutterActor *actor, gint column_span, gint row_span); CLUTTER_DEPRECATED_IN_1_18 void clutter_table_layout_get_span (ClutterTableLayout *layout, ClutterActor *actor, gint *column_span, gint *row_span); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_set_alignment (ClutterTableLayout *layout, ClutterActor *actor, ClutterTableAlignment x_align, ClutterTableAlignment y_align); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_get_alignment (ClutterTableLayout *layout, ClutterActor *actor, ClutterTableAlignment *x_align, ClutterTableAlignment *y_align); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_set_fill (ClutterTableLayout *layout, ClutterActor *actor, gboolean x_fill, gboolean y_fill); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_get_fill (ClutterTableLayout *layout, ClutterActor *actor, gboolean *x_fill, gboolean *y_fill); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_set_expand (ClutterTableLayout *layout, ClutterActor *actor, gboolean x_expand, gboolean y_expand); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_get_expand (ClutterTableLayout *layout, ClutterActor *actor, gboolean *x_expand, gboolean *y_expand); CLUTTER_DEPRECATED_IN_1_18 gint clutter_table_layout_get_row_count (ClutterTableLayout *layout); CLUTTER_DEPRECATED_IN_1_18 gint clutter_table_layout_get_column_count (ClutterTableLayout *layout); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_set_use_animations (ClutterTableLayout *layout, gboolean animate); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_table_layout_get_use_animations (ClutterTableLayout *layout); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_set_easing_mode (ClutterTableLayout *layout, gulong mode); CLUTTER_DEPRECATED_IN_1_12 gulong clutter_table_layout_get_easing_mode (ClutterTableLayout *layout); CLUTTER_DEPRECATED_IN_1_12 void clutter_table_layout_set_easing_duration (ClutterTableLayout *layout, guint msecs); CLUTTER_DEPRECATED_IN_1_12 guint clutter_table_layout_get_easing_duration (ClutterTableLayout *layout); G_END_DECLS #endif /* __CLUTTER_TABLE_LAYOUT_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-actor.h0000664000175000017500000002264114211404421023346 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_ACTOR_DEPRECATED_H__ #define __CLUTTER_ACTOR_DEPRECATED_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_10 void clutter_actor_set_geometry (ClutterActor *self, const ClutterGeometry *geometry); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_allocation_geometry) void clutter_actor_get_geometry (ClutterActor *self, ClutterGeometry *geometry); CLUTTER_DEPRECATED_IN_1_8 guint32 clutter_actor_get_gid (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_8 ClutterActor * clutter_get_actor_by_gid (guint32 id_); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_remove_child() and clutter_actor_add_child()) void clutter_actor_reparent (ClutterActor *self, ClutterActor *new_parent); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_add_child) void clutter_actor_set_parent (ClutterActor *self, ClutterActor *parent); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_remove_child) void clutter_actor_unparent (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_child_above_sibling) void clutter_actor_raise (ClutterActor *self, ClutterActor *below); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_child_below_sibling) void clutter_actor_lower (ClutterActor *self, ClutterActor *above); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_child_above_sibling() with NULL sibling) void clutter_actor_raise_top (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_child_below_sibling() with NULL sibling) void clutter_actor_lower_bottom (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_10 void clutter_actor_push_internal (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_10 void clutter_actor_pop_internal (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_10 void clutter_actor_show_all (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_10 void clutter_actor_hide_all (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_set_z_position) void clutter_actor_set_depth (ClutterActor *self, gfloat depth); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_get_z_position) gfloat clutter_actor_get_depth (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_set_rotation_angle) void clutter_actor_set_rotation (ClutterActor *self, ClutterRotateAxis axis, gdouble angle, gfloat x, gfloat y, gfloat z); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_set_rotation_angle and clutter_actor_set_pivot_point) void clutter_actor_set_z_rotation_from_gravity (ClutterActor *self, gdouble angle, ClutterGravity gravity); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_get_rotation_angle) gdouble clutter_actor_get_rotation (ClutterActor *self, ClutterRotateAxis axis, gfloat *x, gfloat *y, gfloat *z); CLUTTER_DEPRECATED_IN_1_12 ClutterGravity clutter_actor_get_z_rotation_gravity (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_set_scale and clutter_actor_set_pivot_point) void clutter_actor_set_scale_full (ClutterActor *self, gdouble scale_x, gdouble scale_y, gfloat center_x, gfloat center_y); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_set_scale and clutter_actor_set_pivot_point) void clutter_actor_set_scale_with_gravity (ClutterActor *self, gdouble scale_x, gdouble scale_y, ClutterGravity gravity); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_get_pivot_point) void clutter_actor_get_scale_center (ClutterActor *self, gfloat *center_x, gfloat *center_y); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_actor_get_pivot_point) ClutterGravity clutter_actor_get_scale_gravity (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_12 void clutter_actor_set_anchor_point (ClutterActor *self, gfloat anchor_x, gfloat anchor_y); CLUTTER_DEPRECATED_IN_1_12 void clutter_actor_move_anchor_point (ClutterActor *self, gfloat anchor_x, gfloat anchor_y); CLUTTER_DEPRECATED_IN_1_12 void clutter_actor_get_anchor_point (ClutterActor *self, gfloat *anchor_x, gfloat *anchor_y); CLUTTER_DEPRECATED_IN_1_12 ClutterGravity clutter_actor_get_anchor_point_gravity (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_12 void clutter_actor_set_anchor_point_from_gravity (ClutterActor *self, ClutterGravity gravity); CLUTTER_DEPRECATED_IN_1_12 void clutter_actor_move_anchor_point_from_gravity (ClutterActor *self, ClutterGravity gravity); CLUTTER_DEPRECATED_IN_1_12 void clutter_actor_get_transformation_matrix (ClutterActor *self, ClutterMatrix *matrix); CLUTTER_DEPRECATED_IN_1_12_FOR (clutter_actor_get_allocation_box) void clutter_actor_get_allocation_geometry (ClutterActor *self, ClutterGeometry *geom); G_END_DECLS #endif /* __CLUTTER_ACTOR_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-timeout-pool.c0000664000175000017500000003345714211404421024675 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * * * ClutterTimeoutPool: pool of timeout functions using the same slice of * the GLib main loop * * Author: Emmanuele Bassi * * Based on similar code by Tristan van Berkom */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-main.h" #include "clutter-timeout-pool.h" #include "clutter-debug.h" #include "clutter-timeout-interval.h" typedef struct _ClutterTimeout ClutterTimeout; typedef enum { CLUTTER_TIMEOUT_NONE = 0, CLUTTER_TIMEOUT_READY = 1 << 1 } ClutterTimeoutFlags; struct _ClutterTimeout { guint id; ClutterTimeoutFlags flags; gint refcount; ClutterTimeoutInterval interval; GSourceFunc func; gpointer data; GDestroyNotify notify; }; struct _ClutterTimeoutPool { GSource source; guint next_id; GList *timeouts; GList *dispatched_timeouts; gint ready; guint id; }; #define TIMEOUT_READY(timeout) (timeout->flags & CLUTTER_TIMEOUT_READY) static gboolean clutter_timeout_pool_prepare (GSource *source, gint *next_timeout); static gboolean clutter_timeout_pool_check (GSource *source); static gboolean clutter_timeout_pool_dispatch (GSource *source, GSourceFunc callback, gpointer data); static void clutter_timeout_pool_finalize (GSource *source); static GSourceFuncs clutter_timeout_pool_funcs = { clutter_timeout_pool_prepare, clutter_timeout_pool_check, clutter_timeout_pool_dispatch, clutter_timeout_pool_finalize }; static gint clutter_timeout_sort (gconstpointer a, gconstpointer b) { const ClutterTimeout *t_a = a; const ClutterTimeout *t_b = b; /* Keep 'ready' timeouts at the front */ if (TIMEOUT_READY (t_a)) return -1; if (TIMEOUT_READY (t_b)) return 1; return _clutter_timeout_interval_compare_expiration (&t_a->interval, &t_b->interval); } static gint clutter_timeout_find_by_id (gconstpointer a, gconstpointer b) { const ClutterTimeout *t_a = a; return t_a->id == GPOINTER_TO_UINT (b) ? 0 : 1; } static ClutterTimeout * clutter_timeout_new (guint fps) { ClutterTimeout *timeout; timeout = g_slice_new0 (ClutterTimeout); _clutter_timeout_interval_init (&timeout->interval, fps); timeout->flags = CLUTTER_TIMEOUT_NONE; timeout->refcount = 1; return timeout; } static gboolean clutter_timeout_prepare (ClutterTimeoutPool *pool, ClutterTimeout *timeout, gint *next_timeout) { GSource *source = (GSource *) pool; gint64 now; #if GLIB_CHECK_VERSION (2, 27, 3) now = g_source_get_time (source) / 1000; #else { GTimeVal source_time; g_source_get_current_time (source, &source_time); now = source_time.tv_sec * 1000 + source_time.tv_usec / 1000; } #endif return _clutter_timeout_interval_prepare (now, &timeout->interval, next_timeout); } /* ref and unref are always called under the main Clutter lock, so there * is not need for us to use g_atomic_int_* API. */ static ClutterTimeout * clutter_timeout_ref (ClutterTimeout *timeout) { g_return_val_if_fail (timeout != NULL, timeout); g_return_val_if_fail (timeout->refcount > 0, timeout); timeout->refcount += 1; return timeout; } static void clutter_timeout_unref (ClutterTimeout *timeout) { g_return_if_fail (timeout != NULL); g_return_if_fail (timeout->refcount > 0); timeout->refcount -= 1; if (timeout->refcount == 0) { if (timeout->notify) timeout->notify (timeout->data); g_slice_free (ClutterTimeout, timeout); } } static void clutter_timeout_free (ClutterTimeout *timeout) { if (G_LIKELY (timeout)) { if (timeout->notify) timeout->notify (timeout->data); g_slice_free (ClutterTimeout, timeout); } } static gboolean clutter_timeout_pool_prepare (GSource *source, gint *next_timeout) { ClutterTimeoutPool *pool = (ClutterTimeoutPool *) source; GList *l = pool->timeouts; /* the pool is ready if the first timeout is ready */ if (l && l->data) { ClutterTimeout *timeout = l->data; return clutter_timeout_prepare (pool, timeout, next_timeout); } else { *next_timeout = -1; return FALSE; } } static gboolean clutter_timeout_pool_check (GSource *source) { ClutterTimeoutPool *pool = (ClutterTimeoutPool *) source; GList *l; clutter_threads_enter (); for (l = pool->timeouts; l; l = l->next) { ClutterTimeout *timeout = l->data; /* since the timeouts are sorted by expiration, as soon * as we get a check returning FALSE we know that the * following timeouts are not expiring, so we break as * soon as possible */ if (clutter_timeout_prepare (pool, timeout, NULL)) { timeout->flags |= CLUTTER_TIMEOUT_READY; pool->ready += 1; } else break; } clutter_threads_leave (); return (pool->ready > 0); } static gboolean clutter_timeout_pool_dispatch (GSource *source, GSourceFunc func, gpointer data) { ClutterTimeoutPool *pool = (ClutterTimeoutPool *) source; GList *dispatched_timeouts; /* the main loop might have predicted this, so we repeat the * check for ready timeouts. */ if (!pool->ready) clutter_timeout_pool_check (source); clutter_threads_enter (); /* Iterate by moving the actual start of the list along so that it * can cope with adds and removes while a timeout is being dispatched */ while (pool->timeouts && pool->timeouts->data && pool->ready-- > 0) { ClutterTimeout *timeout = pool->timeouts->data; GList *l; /* One of the ready timeouts may have been removed during dispatch, * in which case pool->ready will be wrong, but the ready timeouts * are always kept at the start of the list so we can stop once * we've reached the first non-ready timeout */ if (!(TIMEOUT_READY (timeout))) break; /* Add a reference to the timeout so it can't disappear * while it's being dispatched */ clutter_timeout_ref (timeout); timeout->flags &= ~CLUTTER_TIMEOUT_READY; /* Move the list node to a list of dispatched timeouts */ l = pool->timeouts; if (l->next) l->next->prev = NULL; pool->timeouts = l->next; if (pool->dispatched_timeouts) pool->dispatched_timeouts->prev = l; l->prev = NULL; l->next = pool->dispatched_timeouts; pool->dispatched_timeouts = l; if (!_clutter_timeout_interval_dispatch (&timeout->interval, timeout->func, timeout->data)) { /* The timeout may have already been removed, but nothing * can be added to the dispatched_timeout list except in this * function so it will always either be at the head of the * dispatched list or have been removed */ if (pool->dispatched_timeouts && pool->dispatched_timeouts->data == timeout) { pool->dispatched_timeouts = g_list_delete_link (pool->dispatched_timeouts, pool->dispatched_timeouts); /* Remove the reference that was held by it being in the list */ clutter_timeout_unref (timeout); } } clutter_timeout_unref (timeout); } /* Re-insert the dispatched timeouts in sorted order */ dispatched_timeouts = pool->dispatched_timeouts; while (dispatched_timeouts) { ClutterTimeout *timeout = dispatched_timeouts->data; GList *next = dispatched_timeouts->next; if (timeout) pool->timeouts = g_list_insert_sorted (pool->timeouts, timeout, clutter_timeout_sort); dispatched_timeouts = next; } g_list_free (pool->dispatched_timeouts); pool->dispatched_timeouts = NULL; pool->ready = 0; clutter_threads_leave (); return TRUE; } static void clutter_timeout_pool_finalize (GSource *source) { ClutterTimeoutPool *pool = (ClutterTimeoutPool *) source; /* force destruction */ g_list_foreach (pool->timeouts, (GFunc) clutter_timeout_free, NULL); g_list_free (pool->timeouts); } /** * clutter_timeout_pool_new: * @priority: the priority of the timeout pool. Typically this will * be #G_PRIORITY_DEFAULT * * Creates a new timeout pool source. A timeout pool should be used when * multiple timeout functions, running at the same priority, are needed and * the g_timeout_add() API might lead to starvation of the time slice of * the main loop. A timeout pool allocates a single time slice of the main * loop and runs every timeout function inside it. The timeout pool is * always sorted, so that the extraction of the next timeout function is * a constant time operation. * * Return value: the newly created #ClutterTimeoutPool. The created pool * is owned by the GLib default context and will be automatically * destroyed when the context is destroyed. It is possible to force * the destruction of the timeout pool using g_source_destroy() * * Since: 0.4 * * Deprecated: 1.6: There is no direct replacement for this API */ ClutterTimeoutPool * clutter_timeout_pool_new (gint priority) { ClutterTimeoutPool *pool; GSource *source; source = g_source_new (&clutter_timeout_pool_funcs, sizeof (ClutterTimeoutPool)); if (!source) return NULL; g_source_set_name (source, "Clutter timeout pool"); if (priority != G_PRIORITY_DEFAULT) g_source_set_priority (source, priority); pool = (ClutterTimeoutPool *) source; pool->next_id = 1; pool->id = g_source_attach (source, NULL); /* let the default GLib context manage the pool */ g_source_unref (source); return pool; } /** * clutter_timeout_pool_add: * @pool: a #ClutterTimeoutPool * @fps: the time between calls to the function, in frames per second * @func: function to call * @data: (closure): data to pass to the function, or %NULL * @notify: function to call when the timeout is removed, or %NULL * * Sets a function to be called at regular intervals, and puts it inside * the @pool. The function is repeatedly called until it returns %FALSE, * at which point the timeout is automatically destroyed and the function * won't be called again. If @notify is not %NULL, the @notify function * will be called. The first call to @func will be at the end of @interval. * * Since Clutter 0.8 this will try to compensate for delays. For * example, if @func takes half the interval time to execute then the * function will be called again half the interval time after it * finished. Before version 0.8 it would not fire until a full * interval after the function completes so the delay between calls * would be @interval * 1.5. This function does not however try to * invoke the function multiple times to catch up missing frames if * @func takes more than @interval ms to execute. * * Return value: the ID (greater than 0) of the timeout inside the pool. * Use clutter_timeout_pool_remove() to stop the timeout. * * Since: 0.4 * * Deprecated: 1.6: There is no direct replacement for this API */ guint clutter_timeout_pool_add (ClutterTimeoutPool *pool, guint fps, GSourceFunc func, gpointer data, GDestroyNotify notify) { ClutterTimeout *timeout; guint retval = 0; timeout = clutter_timeout_new (fps); retval = timeout->id = pool->next_id++; timeout->func = func; timeout->data = data; timeout->notify = notify; pool->timeouts = g_list_insert_sorted (pool->timeouts, timeout, clutter_timeout_sort); return retval; } /** * clutter_timeout_pool_remove: * @pool: a #ClutterTimeoutPool * @id_: the id of the timeout to remove * * Removes a timeout function with @id_ from the timeout pool. The id * is the same returned when adding a function to the timeout pool with * clutter_timeout_pool_add(). * * Since: 0.4 * * Deprecated: 1.6: There is no direct replacement for this API */ void clutter_timeout_pool_remove (ClutterTimeoutPool *pool, guint id_) { GList *l; if ((l = g_list_find_custom (pool->timeouts, GUINT_TO_POINTER (id_), clutter_timeout_find_by_id))) { clutter_timeout_unref (l->data); pool->timeouts = g_list_delete_link (pool->timeouts, l); } else if ((l = g_list_find_custom (pool->dispatched_timeouts, GUINT_TO_POINTER (id_), clutter_timeout_find_by_id))) { clutter_timeout_unref (l->data); pool->dispatched_timeouts = g_list_delete_link (pool->dispatched_timeouts, l); } } muffin-5.2.1/clutter/clutter/deprecated/clutter-container.h0000664000175000017500000001112014211404421024206 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation * * 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, see . * * ClutterContainer: Generic actor container interface. * * Author: Emmanuele Bassi */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_CONTAINER_DEPRECATED_H__ #define __CLUTTER_CONTAINER_DEPRECATED_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_add_child) void clutter_container_add (ClutterContainer *container, ClutterActor *first_actor, ...) G_GNUC_NULL_TERMINATED; CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_add_child) void clutter_container_add_actor (ClutterContainer *container, ClutterActor *actor); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_add_child) void clutter_container_add_valist (ClutterContainer *container, ClutterActor *first_actor, va_list var_args); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_remove_child) void clutter_container_remove (ClutterContainer *container, ClutterActor *first_actor, ...) G_GNUC_NULL_TERMINATED; CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_remove_child) void clutter_container_remove_actor (ClutterContainer *container, ClutterActor *actor); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_remove_child) void clutter_container_remove_valist (ClutterContainer *container, ClutterActor *first_actor, va_list var_args); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_children) GList * clutter_container_get_children (ClutterContainer *container); CLUTTER_DEPRECATED_IN_1_10 void clutter_container_foreach (ClutterContainer *container, ClutterCallback callback, gpointer user_data); CLUTTER_DEPRECATED_IN_1_10 void clutter_container_foreach_with_internals (ClutterContainer *container, ClutterCallback callback, gpointer user_data); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_child_above_sibling) void clutter_container_raise_child (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_child_below_sibling) void clutter_container_lower_child (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling); CLUTTER_DEPRECATED_IN_1_10 void clutter_container_sort_depth_order (ClutterContainer *container); G_END_DECLS #endif /* __CLUTTER_CONTAINER_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-depth.h0000664000175000017500000000727414211404421025331 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BEHAVIOUR_DEPTH__ #define __CLUTTER_BEHAVIOUR_DEPTH__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_BEHAVIOUR_DEPTH (clutter_behaviour_depth_get_type ()) #define CLUTTER_BEHAVIOUR_DEPTH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BEHAVIOUR_DEPTH, ClutterBehaviourDepth)) #define CLUTTER_IS_BEHAVIOUR_DEPTH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BEHAVIOUR_DEPTH)) #define CLUTTER_BEHAVIOUR_DEPTH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BEHAVIOUR_DEPTH, ClutterBehaviourDepthClass)) #define CLUTTER_IS_BEHAVIOUR_DEPTH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BEHAVIOUR_DEPTH)) #define CLUTTER_BEHAVIOUR_DEPTH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BEHAVIOUR_DEPTH, ClutterBehaviourDepthClass)) typedef struct _ClutterBehaviourDepth ClutterBehaviourDepth; typedef struct _ClutterBehaviourDepthPrivate ClutterBehaviourDepthPrivate; typedef struct _ClutterBehaviourDepthClass ClutterBehaviourDepthClass; /** * ClutterBehaviourDepth: * * The #ClutterBehaviourDepth structure contains only private data * and should be accessed using the provided API * * Since: 0.2 * * Deprecated: 1.6: Use clutter_actor_animate() with #ClutterActor:depth * instead. */ struct _ClutterBehaviourDepth { /*< private >*/ ClutterBehaviour parent_instance; ClutterBehaviourDepthPrivate *priv; }; /** * ClutterBehaviourDepthClass: * * The #ClutterBehaviourDepthClass structure contains only private data * * Since: 0.2 * * Deprecated: 1.6 */ struct _ClutterBehaviourDepthClass { /*< private >*/ ClutterBehaviourClass parent_class; }; CLUTTER_DEPRECATED_IN_1_6 GType clutter_behaviour_depth_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_6_FOR(clutter_actor_animate and ClutterActor:depth) ClutterBehaviour *clutter_behaviour_depth_new (ClutterAlpha *alpha, gint depth_start, gint depth_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_depth_set_bounds (ClutterBehaviourDepth *behaviour, gint depth_start, gint depth_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_depth_get_bounds (ClutterBehaviourDepth *behaviour, gint *depth_start, gint *depth_end); G_END_DECLS #endif /* __CLUTTER_BEHAVIOUR_DEPTH__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-main.h0000664000175000017500000000774314211404421023170 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_MAIN_DEPRECATED_H__ #define __CLUTTER_MAIN_DEPRECATED_H__ #include #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_10 void clutter_threads_init (void); CLUTTER_DEPRECATED_IN_1_12 void clutter_threads_enter (void); CLUTTER_DEPRECATED_IN_1_12 void clutter_threads_leave (void); CLUTTER_DEPRECATED_IN_1_6 guint clutter_threads_add_frame_source (guint fps, GSourceFunc func, gpointer data); CLUTTER_DEPRECATED_IN_1_6 guint clutter_threads_add_frame_source_full (gint priority, guint fps, GSourceFunc func, gpointer data, GDestroyNotify notify); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_stage_set_motion_events_enabled) void clutter_set_motion_events_enabled (gboolean enable); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_stage_get_motion_events_enabled) gboolean clutter_get_motion_events_enabled (void); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_stage_ensure_redraw) void clutter_redraw (ClutterStage *stage); CLUTTER_DEPRECATED_IN_1_10_FOR(cogl_pango_font_map_clear_glyph_cache) void clutter_clear_glyph_cache (void); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_backend_set_font_options) void clutter_set_font_flags (ClutterFontFlags flags); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_backend_get_font_options) ClutterFontFlags clutter_get_font_flags (void); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_device_manager_get_device) ClutterInputDevice * clutter_get_input_device_for_id (gint id_); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_input_device_grab) void clutter_grab_pointer_for_device (ClutterActor *actor, gint id_); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_input_device_ungrab) void clutter_ungrab_pointer_for_device (gint id_); CLUTTER_DEPRECATED_IN_1_10 void clutter_set_default_frame_rate (guint frames_per_sec); CLUTTER_DEPRECATED_IN_1_10 gulong clutter_get_timestamp (void); CLUTTER_DEPRECATED_IN_1_10 gboolean clutter_get_debug_enabled (void); CLUTTER_DEPRECATED_IN_1_10 gboolean clutter_get_show_fps (void); G_END_DECLS #endif /* __CLUTTER_MAIN_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-animation.c0000664000175000017500000024407614211404421024220 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-animation * @short_description: Simple implicit animations * @See_Also: #ClutterAnimatable, #ClutterInterval, #ClutterAlpha, * #ClutterTimeline * * #ClutterAnimation is an object providing simple, implicit animations * for #GObjects. * * #ClutterAnimation instances will bind one or more #GObject properties * belonging to a #GObject to a #ClutterInterval, and will then use a * #ClutterAlpha to interpolate the property between the initial and final * values of the interval. * * The duration of the animation is set using clutter_animation_set_duration(). * The easing mode of the animation is set using clutter_animation_set_mode(). * * If you want to control the animation you should retrieve the * #ClutterTimeline using clutter_animation_get_timeline() and then * use #ClutterTimeline functions like clutter_timeline_start(), * clutter_timeline_pause() or clutter_timeline_stop(). * * A #ClutterAnimation will emit the #ClutterAnimation::completed signal * when the #ClutterTimeline used by the animation is completed; unlike * #ClutterTimeline, though, the #ClutterAnimation::completed will not be * emitted if #ClutterAnimation:loop is set to %TRUE - that is, a looping * animation never completes. * * If your animation depends on user control you can force its completion * using clutter_animation_completed(). * * If the #GObject instance bound to a #ClutterAnimation implements the * #ClutterAnimatable interface it is possible for that instance to * control the way the initial and final states are interpolated. * * #ClutterAnimations are distinguished from #ClutterBehaviours * because the former can only control #GObject properties of a single * #GObject instance, while the latter can control multiple properties * using accessor functions inside the #ClutterBehaviour * `alpha_notify` virtual function, and can control multiple #ClutterActors * as well. * * For convenience, it is possible to use the clutter_actor_animate() * function call which will take care of setting up and tearing down * a #ClutterAnimation instance and animate an actor between its current * state and the specified final state. * * #ClutterAnimation is available since Clutter 1.0. * * #ClutterAnimation has been deprecated in Clutter 1.12. You should use * the [implicit animation API][clutter-actor-animation] available inside * #ClutterActor instead. If you require to define explicit transitions for * one or more properties in order to reuse them, see #ClutterTransition * instead. * * ## Defining ClutterAnimationMode inside ClutterScript * * When defining a #ClutterAnimation inside a ClutterScript * file or string the #ClutterAnimation:mode can be defined either * using the #ClutterAnimationMode enumeration values through their * "nick" (the short string used inside #GEnumValue), their numeric * id, or using the following strings: * * - easeInQuad, easeOutQuad, easeInOutQuad * - easeInCubic, easeOutCubic, easeInOutCubic * - easeInQuart, easeOutQuart, easeInOutQuart * - easeInQuint, easeOutQuint, easeInOutQuint * - easeInSine, easeOutSine, easeInOutSine * - easeInExpo, easeOutExpo, easeInOutExpo * - easeInCirc, easeOutCirc, easeInOutCirc * - easeInElastic, easeOutElastic, easeInOutElastic * - easeInBack, easeOutBack, easeInOutBack * - easeInBounce, easeOutBounce, easeInOutBounce */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-alpha.h" #include "clutter-animatable.h" #include "clutter-animation.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-interval.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-scriptable.h" #include "clutter-script-private.h" #include "deprecated/clutter-animation.h" enum { PROP_0, PROP_OBJECT, PROP_MODE, PROP_DURATION, PROP_LOOP, PROP_TIMELINE, PROP_ALPHA, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { STARTED, COMPLETED, LAST_SIGNAL }; struct _ClutterAnimationPrivate { GObject *object; GHashTable *properties; ClutterAlpha *alpha; ClutterTimeline *timeline; guint timeline_started_id; guint timeline_completed_id; guint timeline_frame_id; }; static guint animation_signals[LAST_SIGNAL] = { 0, }; static GQuark quark_object_animation = 0; static void clutter_scriptable_init (ClutterScriptableIface *iface); static void clutter_animation_set_alpha_internal (ClutterAnimation *animation, ClutterAlpha *alpha); static ClutterAlpha * clutter_animation_get_alpha_internal (ClutterAnimation *animation); static ClutterTimeline * clutter_animation_get_timeline_internal (ClutterAnimation *animation); G_DEFINE_TYPE_WITH_CODE (ClutterAnimation, clutter_animation, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterAnimation) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_init)); static ClutterAlpha * clutter_animation_get_alpha_internal (ClutterAnimation *animation) { ClutterAnimationPrivate *priv = animation->priv; if (priv->alpha == NULL) { ClutterAlpha *alpha; alpha = clutter_alpha_new (); clutter_alpha_set_mode (alpha, CLUTTER_LINEAR); priv->alpha = g_object_ref_sink (alpha); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_ALPHA]); } return priv->alpha; } static void on_actor_destroy (ClutterActor *actor, ClutterAnimation *animation) { ClutterAnimationPrivate *priv = animation->priv; GObject *obj = G_OBJECT (actor); if (obj == priv->object) { g_object_set_qdata (priv->object, quark_object_animation, NULL); g_signal_handlers_disconnect_by_func (priv->object, G_CALLBACK (on_actor_destroy), animation); g_object_unref (animation); } } static void clutter_animation_real_completed (ClutterAnimation *self) { ClutterAnimationPrivate *priv = self->priv; ClutterAnimatable *animatable = NULL; ClutterAnimation *animation; ClutterTimeline *timeline; ClutterTimelineDirection direction; gpointer key, value; GHashTableIter iter; timeline = clutter_animation_get_timeline (self); direction = clutter_timeline_get_direction (timeline); if (CLUTTER_IS_ANIMATABLE (priv->object)) animatable = CLUTTER_ANIMATABLE (priv->object); /* explicitly set the final state of the animation */ CLUTTER_NOTE (ANIMATION, "Set final state on object [%p]", priv->object); g_hash_table_iter_init (&iter, priv->properties); while (g_hash_table_iter_next (&iter, &key, &value)) { const gchar *p_name = key; ClutterInterval *interval = value; GValue *p_value; if (direction == CLUTTER_TIMELINE_FORWARD) p_value = clutter_interval_peek_final_value (interval); else p_value = clutter_interval_peek_initial_value (interval); if (animatable != NULL) clutter_animatable_set_final_state (animatable, p_name, p_value); else g_object_set_property (priv->object, p_name, p_value); } /* at this point, if this animation was created by clutter_actor_animate() * and friends, the animation will be attached to the object's data; since * we want to allow developers to use g_signal_connect_after("completed") * to concatenate a new animation, we need to remove the animation back * pointer here, and unref() the animation. FIXME - we might want to * provide a clutter_animation_attach()/clutter_animation_detach() pair * to let the user reattach an animation */ animation = g_object_get_qdata (priv->object, quark_object_animation); if (animation == self) { CLUTTER_NOTE (ANIMATION, "Unsetting animation for actor [%p]", priv->object); g_object_set_qdata (priv->object, quark_object_animation, NULL); g_signal_handlers_disconnect_by_func (priv->object, G_CALLBACK (on_actor_destroy), animation); CLUTTER_NOTE (ANIMATION, "Releasing the reference Animation [%p]", animation); g_object_unref (animation); } } static void clutter_animation_finalize (GObject *gobject) { ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv; CLUTTER_NOTE (ANIMATION, "Destroying properties table for Animation [%p]", gobject); g_hash_table_destroy (priv->properties); G_OBJECT_CLASS (clutter_animation_parent_class)->finalize (gobject); } static void clutter_animation_dispose (GObject *gobject) { ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv; ClutterTimeline *timeline; if (priv->alpha != NULL) timeline = clutter_alpha_get_timeline (priv->alpha); else timeline = priv->timeline; if (timeline != NULL && priv->timeline_started_id != 0) g_signal_handler_disconnect (timeline, priv->timeline_started_id); if (timeline != NULL && priv->timeline_completed_id != 0) g_signal_handler_disconnect (timeline, priv->timeline_completed_id); if (timeline != NULL && priv->timeline_frame_id != 0) g_signal_handler_disconnect (timeline, priv->timeline_frame_id); priv->timeline_started_id = 0; priv->timeline_completed_id = 0; priv->timeline_frame_id = 0; if (priv->timeline != NULL) { g_object_unref (priv->timeline); priv->timeline = NULL; } if (priv->alpha != NULL) { g_object_unref (priv->alpha); priv->alpha = NULL; } if (priv->object != NULL) { g_object_unref (priv->object); priv->object = NULL; } G_OBJECT_CLASS (clutter_animation_parent_class)->dispose (gobject); } static void clutter_animation_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterAnimation *animation = CLUTTER_ANIMATION (gobject); switch (prop_id) { case PROP_OBJECT: clutter_animation_set_object (animation, g_value_get_object (value)); break; case PROP_MODE: clutter_animation_set_mode (animation, g_value_get_ulong (value)); break; case PROP_DURATION: clutter_animation_set_duration (animation, g_value_get_uint (value)); break; case PROP_LOOP: clutter_animation_set_loop (animation, g_value_get_boolean (value)); break; case PROP_TIMELINE: clutter_animation_set_timeline (animation, g_value_get_object (value)); break; case PROP_ALPHA: clutter_animation_set_alpha_internal (animation, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_animation_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterAnimation *animation = CLUTTER_ANIMATION (gobject); ClutterAnimationPrivate *priv = animation->priv; switch (prop_id) { case PROP_OBJECT: g_value_set_object (value, priv->object); break; case PROP_MODE: g_value_set_ulong (value, clutter_animation_get_mode (animation)); break; case PROP_DURATION: g_value_set_uint (value, clutter_animation_get_duration (animation)); break; case PROP_LOOP: g_value_set_boolean (value, clutter_animation_get_loop (animation)); break; case PROP_TIMELINE: g_value_set_object (value, clutter_animation_get_timeline (animation)); break; case PROP_ALPHA: g_value_set_object (value, clutter_animation_get_alpha_internal (animation)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static gboolean clutter_animation_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { if (strncmp (name, "mode", 4) == 0) { gulong mode; mode = _clutter_script_resolve_animation_mode (node); g_value_init (value, G_TYPE_ULONG); g_value_set_ulong (value, mode); return TRUE; } return FALSE; } static void clutter_scriptable_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_animation_parse_custom_node; } static void clutter_animation_class_init (ClutterAnimationClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); quark_object_animation = g_quark_from_static_string ("clutter-actor-animation"); klass->completed = clutter_animation_real_completed; gobject_class->set_property = clutter_animation_set_property; gobject_class->get_property = clutter_animation_get_property; gobject_class->dispose = clutter_animation_dispose; gobject_class->finalize = clutter_animation_finalize; /** * ClutterAnimation:object: * * The #GObject to which the animation applies. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ obj_props[PROP_OBJECT] = g_param_spec_object ("object", P_("Object"), P_("Object to which the animation applies"), G_TYPE_OBJECT, CLUTTER_PARAM_READWRITE); /** * ClutterAnimation:mode: * * The animation mode, either a value from #ClutterAnimationMode * or a value returned by clutter_alpha_register_func(). The * default value is %CLUTTER_LINEAR. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ obj_props[PROP_MODE] = g_param_spec_ulong ("mode", P_("Mode"), P_("The mode of the animation"), 0, G_MAXULONG, CLUTTER_LINEAR, CLUTTER_PARAM_READWRITE); /** * ClutterAnimation:duration: * * The duration of the animation, expressed in milliseconds. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ obj_props[PROP_DURATION] = g_param_spec_uint ("duration", P_("Duration"), P_("Duration of the animation, in milliseconds"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterAnimation:loop: * * Whether the animation should loop. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ obj_props[PROP_LOOP] = g_param_spec_boolean ("loop", P_("Loop"), P_("Whether the animation should loop"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterAnimation:timeline: * * The #ClutterTimeline used by the animation. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ obj_props[PROP_TIMELINE] = g_param_spec_object ("timeline", P_("Timeline"), P_("The timeline used by the animation"), CLUTTER_TYPE_TIMELINE, CLUTTER_PARAM_READWRITE); /** * ClutterAnimation:alpha: * * The #ClutterAlpha used by the animation. * * Since: 1.0 * * Deprecated: 1.10: Use the #ClutterAnimation:timeline property and * the #ClutterTimeline:progress-mode property instead. */ obj_props[PROP_ALPHA] = g_param_spec_object ("alpha", P_("Alpha"), P_("The alpha used by the animation"), CLUTTER_TYPE_ALPHA, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); /** * ClutterAnimation::started: * @animation: the animation that emitted the signal * * The ::started signal is emitted once the animation has been * started * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ animation_signals[STARTED] = g_signal_new (I_("started"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterAnimationClass, started), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterAnimation::completed: * @animation: the animation that emitted the signal * * The ::completed signal is emitted once the animation has * been completed. * * The @animation instance is guaranteed to be valid for the entire * duration of the signal emission chain. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ animation_signals[COMPLETED] = g_signal_new (I_("completed"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterAnimationClass, completed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void clutter_animation_init (ClutterAnimation *self) { self->priv = clutter_animation_get_instance_private (self); self->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) free, (GDestroyNotify) g_object_unref); } static inline void clutter_animation_bind_property_internal (ClutterAnimation *animation, const gchar *property_name, GParamSpec *pspec, ClutterInterval *interval) { ClutterAnimationPrivate *priv = animation->priv; if (!clutter_interval_validate (interval, pspec)) { g_warning ("Cannot bind property '%s': the interval is out " "of bounds", property_name); return; } g_hash_table_insert (priv->properties, g_strdup (property_name), g_object_ref_sink (interval)); } static inline void clutter_animation_update_property_internal (ClutterAnimation *animation, const gchar *property_name, GParamSpec *pspec, ClutterInterval *interval) { ClutterAnimationPrivate *priv = animation->priv; if (!clutter_interval_validate (interval, pspec)) { g_warning ("Cannot bind property '%s': the interval is out " "of bounds", property_name); return; } g_hash_table_replace (priv->properties, g_strdup (property_name), g_object_ref_sink (interval)); } static GParamSpec * clutter_animation_validate_bind (ClutterAnimation *animation, const char *property_name, GType argtype) { ClutterAnimationPrivate *priv; GParamSpec *pspec; GType pspec_type; priv = animation->priv; if (G_UNLIKELY (!priv->object)) { g_warning ("Cannot bind property '%s': the animation has no " "object set. You need to call clutter_animation_set_object() " "first to be able to bind a property", property_name); return NULL; } if (G_UNLIKELY (clutter_animation_has_property (animation, property_name))) { g_warning ("Cannot bind property '%s': the animation already has " "a bound property with the same name", property_name); return NULL; } if (CLUTTER_IS_ANIMATABLE (priv->object)) { ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (priv->object); pspec = clutter_animatable_find_property (animatable, property_name); } else { GObjectClass *klass = G_OBJECT_GET_CLASS (priv->object); pspec = g_object_class_find_property (klass, property_name); } if (pspec == NULL) { g_warning ("Cannot bind property '%s': objects of type '%s' have " "no such property", property_name, g_type_name (G_OBJECT_TYPE (priv->object))); return NULL; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("Cannot bind property '%s': the property is not writable", property_name); return NULL; } pspec_type = G_PARAM_SPEC_VALUE_TYPE (pspec); if (g_value_type_transformable (argtype, pspec_type)) return pspec; else { g_warning ("Cannot bind property '%s': the interval value of " "type '%s' is not compatible with the property value " "of type '%s'", property_name, g_type_name (argtype), g_type_name (pspec_type)); return NULL; } } /** * clutter_animation_bind_interval: * @animation: a #ClutterAnimation * @property_name: the property to control * @interval: (transfer full): a #ClutterInterval * * Binds @interval to the @property_name of the #GObject * attached to @animation. The #ClutterAnimation will take * ownership of the passed #ClutterInterval. For more information * about animations, see clutter_actor_animate(). * * If you need to update the interval instance use * clutter_animation_update_interval() instead. * * Return value: (transfer none): The animation itself. * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ ClutterAnimation * clutter_animation_bind_interval (ClutterAnimation *animation, const gchar *property_name, ClutterInterval *interval) { GParamSpec *pspec; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); g_return_val_if_fail (property_name != NULL, NULL); g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), NULL); pspec = clutter_animation_validate_bind (animation, property_name, clutter_interval_get_value_type (interval)); if (pspec == NULL) return NULL; clutter_animation_bind_property_internal (animation, property_name, pspec, interval); return animation; } /** * clutter_animation_bind: * @animation: a #ClutterAnimation * @property_name: the property to control * @final: The final value of the property * * Adds a single property with name @property_name to the * animation @animation. For more information about animations, * see clutter_actor_animate(). * * This method returns the animation primarily to make chained * calls convenient in language bindings. * * Return value: (transfer none): The animation itself. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ ClutterAnimation * clutter_animation_bind (ClutterAnimation *animation, const gchar *property_name, const GValue *final) { ClutterAnimationPrivate *priv; GParamSpec *pspec; ClutterInterval *interval; GType type; GValue initial = G_VALUE_INIT; GValue real_final = G_VALUE_INIT; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); g_return_val_if_fail (property_name != NULL, NULL); priv = animation->priv; type = G_VALUE_TYPE (final); pspec = clutter_animation_validate_bind (animation, property_name, type); if (pspec == NULL) return NULL; g_value_init (&real_final, G_PARAM_SPEC_VALUE_TYPE (pspec)); if (!g_value_transform (final, &real_final)) { g_value_unset (&real_final); g_warning ("Unable to transform the value of type '%s' to a value " "of '%s' compatible with the property '%s'of the object " "of type '%s'", g_type_name (type), g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), property_name, G_OBJECT_TYPE_NAME (priv->object)); return NULL; } g_value_init (&initial, G_PARAM_SPEC_VALUE_TYPE (pspec)); if (CLUTTER_IS_ANIMATABLE (priv->object)) clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (priv->object), property_name, &initial); else g_object_get_property (priv->object, property_name, &initial); interval = clutter_interval_new_with_values (G_PARAM_SPEC_VALUE_TYPE (pspec), &initial, &real_final); g_value_unset (&initial); g_value_unset (&real_final); clutter_animation_bind_property_internal (animation, property_name, pspec, interval); return animation; } /** * clutter_animation_unbind_property: * @animation: a #ClutterAnimation * @property_name: name of the property * * Removes @property_name from the list of animated properties. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_unbind_property (ClutterAnimation *animation, const gchar *property_name) { ClutterAnimationPrivate *priv; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_return_if_fail (property_name != NULL); priv = animation->priv; if (!clutter_animation_has_property (animation, property_name)) { g_warning ("Cannot unbind property '%s': the animation has " "no bound property with that name", property_name); return; } g_hash_table_remove (priv->properties, property_name); } /** * clutter_animation_has_property: * @animation: a #ClutterAnimation * @property_name: name of the property * * Checks whether @animation is controlling @property_name. * * Return value: %TRUE if the property is animated by the * #ClutterAnimation, %FALSE otherwise * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ gboolean clutter_animation_has_property (ClutterAnimation *animation, const gchar *property_name) { ClutterAnimationPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE); g_return_val_if_fail (property_name != NULL, FALSE); priv = animation->priv; return g_hash_table_lookup (priv->properties, property_name) != NULL; } /** * clutter_animation_update_interval: * @animation: a #ClutterAnimation * @property_name: name of the property * @interval: a #ClutterInterval * * Changes the @interval for @property_name. The #ClutterAnimation * will take ownership of the passed #ClutterInterval. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_update_interval (ClutterAnimation *animation, const gchar *property_name, ClutterInterval *interval) { ClutterAnimationPrivate *priv; GParamSpec *pspec; GType pspec_type, int_type; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_return_if_fail (property_name != NULL); g_return_if_fail (CLUTTER_IS_INTERVAL (interval)); priv = animation->priv; if (!clutter_animation_has_property (animation, property_name)) { g_warning ("Cannot update property '%s': the animation has " "no bound property with that name", property_name); return; } if (CLUTTER_IS_ANIMATABLE (priv->object)) { ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (priv->object); pspec = clutter_animatable_find_property (animatable, property_name); } else { GObjectClass *klass = G_OBJECT_GET_CLASS (priv->object); pspec = g_object_class_find_property (klass, property_name); } if (pspec == NULL) { g_warning ("Cannot update property '%s': objects of type '%s' have " "no such property", property_name, g_type_name (G_OBJECT_TYPE (priv->object))); return; } pspec_type = G_PARAM_SPEC_VALUE_TYPE (pspec); int_type = clutter_interval_get_value_type (interval); if (!g_value_type_compatible (int_type, pspec_type) || !g_value_type_transformable (int_type, pspec_type)) { g_warning ("Cannot update property '%s': the interval value of " "type '%s' is not compatible with the property value " "of type '%s'", property_name, g_type_name (int_type), g_type_name (pspec_type)); return; } clutter_animation_update_property_internal (animation, property_name, pspec, interval); } /** * clutter_animation_update: * @animation: a #ClutterAnimation * @property_name: name of the property * @final: The final value of the property * * Updates the @final value of the interval for @property_name * * Return value: (transfer none): The animation itself. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ ClutterAnimation * clutter_animation_update (ClutterAnimation *animation, const gchar *property_name, const GValue *final) { ClutterInterval *interval; GType int_type; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); g_return_val_if_fail (property_name != NULL, NULL); g_return_val_if_fail (final != NULL, NULL); g_return_val_if_fail (G_VALUE_TYPE (final) != G_TYPE_INVALID, NULL); interval = clutter_animation_get_interval (animation, property_name); if (interval == NULL) { g_warning ("Cannot update property '%s': the animation has " "no bound property with that name", property_name); return NULL; } int_type = clutter_interval_get_value_type (interval); if (!g_value_type_compatible (G_VALUE_TYPE (final), int_type) || !g_value_type_transformable (G_VALUE_TYPE (final), int_type)) { g_warning ("Cannot update property '%s': the interval value of " "type '%s' is not compatible with the property value " "of type '%s'", property_name, g_type_name (int_type), g_type_name (G_VALUE_TYPE (final))); return NULL; } clutter_interval_set_final_value (interval, final); return animation; } /** * clutter_animation_get_interval: * @animation: a #ClutterAnimation * @property_name: name of the property * * Retrieves the #ClutterInterval associated to @property_name * inside @animation. * * Return value: (transfer none): a #ClutterInterval or %NULL if no * property with the same name was found. The returned interval is * owned by the #ClutterAnimation and should not be unreferenced * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ ClutterInterval * clutter_animation_get_interval (ClutterAnimation *animation, const gchar *property_name) { ClutterAnimationPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); g_return_val_if_fail (property_name != NULL, NULL); priv = animation->priv; return g_hash_table_lookup (priv->properties, property_name); } static void on_timeline_started (ClutterTimeline *timeline, ClutterAnimation *animation) { g_signal_emit (animation, animation_signals[STARTED], 0); } static void on_timeline_completed (ClutterTimeline *timeline, ClutterAnimation *animation) { CLUTTER_NOTE (ANIMATION, "Timeline [%p] complete", timeline); if (!clutter_animation_get_loop (animation)) g_signal_emit (animation, animation_signals[COMPLETED], 0); } static void on_timeline_frame (ClutterTimeline *timeline, gint elapsed, ClutterAnimation *animation) { ClutterAnimationPrivate *priv; GList *properties, *p; gdouble alpha_value; gboolean is_animatable = FALSE; ClutterAnimatable *animatable = NULL; /* make sure the animation survives the notification */ g_object_ref (animation); priv = animation->priv; if (priv->alpha != NULL) alpha_value = clutter_alpha_get_alpha (priv->alpha); else alpha_value = clutter_timeline_get_progress (priv->timeline); if (CLUTTER_IS_ANIMATABLE (priv->object)) { animatable = CLUTTER_ANIMATABLE (priv->object); is_animatable = TRUE; } g_object_freeze_notify (priv->object); properties = g_hash_table_get_keys (priv->properties); for (p = properties; p != NULL; p = p->next) { const gchar *p_name = p->data; ClutterInterval *interval; GValue value = G_VALUE_INIT; gboolean apply; interval = g_hash_table_lookup (priv->properties, p_name); g_assert (CLUTTER_IS_INTERVAL (interval)); g_value_init (&value, clutter_interval_get_value_type (interval)); if (is_animatable) { apply = clutter_animatable_interpolate_value (animatable, p_name, interval, alpha_value, &value); } else { apply = clutter_interval_compute_value (interval, alpha_value, &value); } if (apply) { if (is_animatable) clutter_animatable_set_final_state (animatable, p_name, &value); else g_object_set_property (priv->object, p_name, &value); } g_value_unset (&value); } g_list_free (properties); g_object_thaw_notify (priv->object); g_object_unref (animation); } static ClutterTimeline * clutter_animation_get_timeline_internal (ClutterAnimation *animation) { ClutterAnimationPrivate *priv = animation->priv; ClutterTimeline *timeline; if (priv->timeline != NULL) return priv->timeline; if (priv->alpha != NULL) { timeline = clutter_alpha_get_timeline (priv->alpha); if (timeline != NULL) return timeline; } timeline = g_object_new (CLUTTER_TYPE_TIMELINE, NULL); priv->timeline_started_id = g_signal_connect (timeline, "started", G_CALLBACK (on_timeline_started), animation); priv->timeline_completed_id = g_signal_connect (timeline, "completed", G_CALLBACK (on_timeline_completed), animation); priv->timeline_frame_id = g_signal_connect (timeline, "new-frame", G_CALLBACK (on_timeline_frame), animation); if (priv->alpha != NULL) { clutter_alpha_set_timeline (priv->alpha, timeline); /* the alpha owns the timeline now */ g_object_unref (timeline); } priv->timeline = timeline; g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_TIMELINE]); return priv->timeline; } static void clutter_animation_set_alpha_internal (ClutterAnimation *animation, ClutterAlpha *alpha) { ClutterAnimationPrivate *priv; ClutterTimeline *timeline; priv = animation->priv; if (priv->alpha == alpha) return; g_object_freeze_notify (G_OBJECT (animation)); if (priv->alpha != NULL) timeline = clutter_alpha_get_timeline (priv->alpha); else timeline = NULL; /* disconnect the old timeline first */ if (timeline != NULL && priv->timeline_started_id != 0) { g_signal_handler_disconnect (timeline, priv->timeline_started_id); priv->timeline_started_id = 0; } if (timeline != NULL && priv->timeline_completed_id != 0) { g_signal_handler_disconnect (timeline, priv->timeline_completed_id); priv->timeline_completed_id = 0; } /* then we need to disconnect the signal handler from the old alpha */ if (timeline != NULL && priv->timeline_frame_id != 0) { g_signal_handler_disconnect (timeline, priv->timeline_frame_id); priv->timeline_frame_id = 0; } if (priv->alpha != NULL) { /* this will take care of any reference we hold on the timeline */ g_object_unref (priv->alpha); priv->alpha = NULL; } if (alpha == NULL) goto out; priv->alpha = g_object_ref_sink (alpha); /* if the alpha has a timeline then we use it, otherwise we create one */ timeline = clutter_alpha_get_timeline (priv->alpha); if (timeline != NULL) { priv->timeline_started_id = g_signal_connect (timeline, "started", G_CALLBACK (on_timeline_started), animation); priv->timeline_completed_id = g_signal_connect (timeline, "completed", G_CALLBACK (on_timeline_completed), animation); priv->timeline_frame_id = g_signal_connect (timeline, "new-frame", G_CALLBACK (on_timeline_frame), animation); } else { /* FIXME - add a create_timeline_internal() because this does * not look very good */ (void) clutter_animation_get_timeline_internal (animation); } out: /* emit all relevant notifications */ g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_MODE]); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_DURATION]); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_LOOP]); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_ALPHA]); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_TIMELINE]); g_object_thaw_notify (G_OBJECT (animation)); } /** * clutter_animation_new: * * Creates a new #ClutterAnimation instance. You should set the * #GObject to be animated using clutter_animation_set_object(), * set the duration with clutter_animation_set_duration() and the * easing mode using clutter_animation_set_mode(). * * Use clutter_animation_bind() or clutter_animation_bind_interval() * to define the properties to be animated. The interval and the * animated properties can be updated at runtime. * * The clutter_actor_animate() and relative family of functions provide * an easy way to animate a #ClutterActor and automatically manage the * lifetime of a #ClutterAnimation instance, so you should consider using * those functions instead of manually creating an animation. * * Return value: the newly created #ClutterAnimation. Use g_object_unref() * to release the associated resources * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ ClutterAnimation * clutter_animation_new (void) { return g_object_new (CLUTTER_TYPE_ANIMATION, NULL); } /** * clutter_animation_set_object: * @animation: a #ClutterAnimation * @object: a #GObject * * Attaches @animation to @object. The #ClutterAnimation will take a * reference on @object. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_set_object (ClutterAnimation *animation, GObject *object) { ClutterAnimationPrivate *priv; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_return_if_fail (object == NULL || G_IS_OBJECT (object)); priv = animation->priv; if (priv->object != NULL) { g_object_set_qdata (priv->object, quark_object_animation, NULL); g_object_unref (priv->object); priv->object = NULL; } if (object != NULL) priv->object = g_object_ref (object); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_OBJECT]); } /** * clutter_animation_get_object: * @animation: a #ClutterAnimation * * Retrieves the #GObject attached to @animation. * * Return value: (transfer none): a #GObject * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ GObject * clutter_animation_get_object (ClutterAnimation *animation) { g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); return animation->priv->object; } /** * clutter_animation_set_mode: * @animation: a #ClutterAnimation * @mode: an animation mode logical id * * Sets the animation @mode of @animation. The animation @mode is * a logical id, either coming from the #ClutterAnimationMode enumeration * or the return value of clutter_alpha_register_func(). * * This function will also set #ClutterAnimation:alpha if needed. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_set_mode (ClutterAnimation *animation, gulong mode) { g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_object_freeze_notify (G_OBJECT (animation)); if (animation->priv->alpha != NULL || mode > CLUTTER_ANIMATION_LAST) { ClutterAlpha *alpha; if (animation->priv->alpha == NULL) alpha = clutter_animation_get_alpha_internal (animation); else alpha = animation->priv->alpha; clutter_alpha_set_mode (alpha, mode); } else { ClutterTimeline *timeline; timeline = clutter_animation_get_timeline_internal (animation); clutter_timeline_set_progress_mode (timeline, mode); } g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_MODE]); g_object_thaw_notify (G_OBJECT (animation)); } /** * clutter_animation_get_mode: * @animation: a #ClutterAnimation * * Retrieves the animation mode of @animation, as set by * clutter_animation_set_mode(). * * Return value: the mode for the animation * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ gulong clutter_animation_get_mode (ClutterAnimation *animation) { ClutterTimeline *timeline; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), CLUTTER_LINEAR); if (animation->priv->alpha != NULL) return clutter_alpha_get_mode (animation->priv->alpha); timeline = clutter_animation_get_timeline_internal (animation); return clutter_timeline_get_progress_mode (timeline); } /** * clutter_animation_set_duration: * @animation: a #ClutterAnimation * @msecs: the duration in milliseconds * * Sets the duration of @animation in milliseconds. * * This function will set #ClutterAnimation:alpha and * #ClutterAnimation:timeline if needed. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_set_duration (ClutterAnimation *animation, guint msecs) { ClutterTimeline *timeline; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_object_freeze_notify (G_OBJECT (animation)); timeline = clutter_animation_get_timeline_internal (animation); clutter_timeline_set_duration (timeline, msecs); clutter_timeline_rewind (timeline); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_DURATION]); g_object_thaw_notify (G_OBJECT (animation)); } /** * clutter_animation_set_loop: * @animation: a #ClutterAnimation * @loop: %TRUE if the animation should loop * * Sets whether @animation should loop over itself once finished. * * A looping #ClutterAnimation will not emit the #ClutterAnimation::completed * signal when finished. * * This function will set #ClutterAnimation:alpha and * #ClutterAnimation:timeline if needed. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_set_loop (ClutterAnimation *animation, gboolean loop) { ClutterTimeline *timeline; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_object_freeze_notify (G_OBJECT (animation)); timeline = clutter_animation_get_timeline_internal (animation); clutter_timeline_set_repeat_count (timeline, loop ? -1 : 0); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_LOOP]); g_object_thaw_notify (G_OBJECT (animation)); } /** * clutter_animation_get_loop: * @animation: a #ClutterAnimation * * Retrieves whether @animation is looping. * * Return value: %TRUE if the animation is looping * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ gboolean clutter_animation_get_loop (ClutterAnimation *animation) { ClutterTimeline *timeline; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), FALSE); timeline = clutter_animation_get_timeline_internal (animation); return clutter_timeline_get_repeat_count (timeline) != 0; } /** * clutter_animation_get_duration: * @animation: a #ClutterAnimation * * Retrieves the duration of @animation, in milliseconds. * * Return value: the duration of the animation * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ guint clutter_animation_get_duration (ClutterAnimation *animation) { ClutterTimeline *timeline; g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), 0); timeline = clutter_animation_get_timeline_internal (animation); return clutter_timeline_get_duration (timeline); } /** * clutter_animation_set_timeline: * @animation: a #ClutterAnimation * @timeline: (allow-none): a #ClutterTimeline, or %NULL to unset the * current #ClutterTimeline * * Sets the #ClutterTimeline used by @animation. * * This function will take a reference on the passed @timeline. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_set_timeline (ClutterAnimation *animation, ClutterTimeline *timeline) { ClutterAnimationPrivate *priv; ClutterTimeline *cur_timeline; g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_return_if_fail (timeline == NULL || CLUTTER_IS_TIMELINE (timeline)); priv = animation->priv; if (priv->alpha != NULL) cur_timeline = clutter_alpha_get_timeline (priv->alpha); else cur_timeline = priv->timeline; if (cur_timeline == timeline) return; g_object_freeze_notify (G_OBJECT (animation)); if (cur_timeline != NULL && priv->timeline_started_id != 0) g_signal_handler_disconnect (cur_timeline, priv->timeline_started_id); if (cur_timeline != NULL && priv->timeline_completed_id != 0) g_signal_handler_disconnect (cur_timeline, priv->timeline_completed_id); if (cur_timeline != NULL && priv->timeline_frame_id != 0) g_signal_handler_disconnect (cur_timeline, priv->timeline_frame_id); priv->timeline_started_id = 0; priv->timeline_completed_id = 0; priv->timeline_frame_id = 0; /* Release previously set timeline if any */ g_clear_object (&priv->timeline); if (priv->alpha != NULL) clutter_alpha_set_timeline (priv->alpha, timeline); else { /* Hold a reference to the timeline if it's not reffed by the priv->alpha */ priv->timeline = timeline; if (priv->timeline) g_object_ref (priv->timeline); } g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_TIMELINE]); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_DURATION]); g_object_notify_by_pspec (G_OBJECT (animation), obj_props[PROP_LOOP]); if (timeline != NULL) { priv->timeline_started_id = g_signal_connect (timeline, "started", G_CALLBACK (on_timeline_started), animation); priv->timeline_completed_id = g_signal_connect (timeline, "completed", G_CALLBACK (on_timeline_completed), animation); priv->timeline_frame_id = g_signal_connect (timeline, "new-frame", G_CALLBACK (on_timeline_frame), animation); } g_object_thaw_notify (G_OBJECT (animation)); } /** * clutter_animation_get_timeline: * @animation: a #ClutterAnimation * * Retrieves the #ClutterTimeline used by @animation * * Return value: (transfer none): the timeline used by the animation * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ ClutterTimeline * clutter_animation_get_timeline (ClutterAnimation *animation) { g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); return clutter_animation_get_timeline_internal (animation); } /** * clutter_animation_set_alpha: * @animation: a #ClutterAnimation * @alpha: a #ClutterAlpha, or %NULL to unset the current #ClutterAlpha * * Sets @alpha as the #ClutterAlpha used by @animation. * * If @alpha is not %NULL, the #ClutterAnimation will take ownership * of the #ClutterAlpha instance. * * Since: 1.0 * * Deprecated: 1.10: Use clutter_animation_get_timeline() and * clutter_timeline_set_progress_mode() instead. */ void clutter_animation_set_alpha (ClutterAnimation *animation, ClutterAlpha *alpha) { g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_return_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha)); clutter_animation_set_alpha_internal (animation, alpha); } /** * clutter_animation_get_alpha: * @animation: a #ClutterAnimation * * Retrieves the #ClutterAlpha used by @animation. * * Return value: (transfer none): the alpha object used by the animation * * Since: 1.0 * * Deprecated: 1.10: Use clutter_animation_get_timeline() and * clutter_timeline_get_progress_mode() instead. */ ClutterAlpha * clutter_animation_get_alpha (ClutterAnimation *animation) { g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL); return clutter_animation_get_alpha_internal (animation); } /** * clutter_animation_completed: * @animation: a #ClutterAnimation * * Emits the ::completed signal on @animation * * When using this function with a #ClutterAnimation created * by the clutter_actor_animate() family of functions, @animation * will be unreferenced and it will not be valid anymore, * unless g_object_ref() was called before calling this function * or unless a reference was taken inside a handler for the * #ClutterAnimation::completed signal * * Since: 1.0 * Deprecated: 1.12: Use #ClutterPropertyTransition instead */ void clutter_animation_completed (ClutterAnimation *animation) { g_return_if_fail (CLUTTER_IS_ANIMATION (animation)); g_signal_emit (animation, animation_signals[COMPLETED], 0); } /* * starts the timeline */ static void clutter_animation_start (ClutterAnimation *animation) { ClutterTimeline *timeline; timeline = clutter_animation_get_timeline_internal (animation); if (G_LIKELY (timeline != NULL)) clutter_timeline_start (timeline); else { /* sanity check */ g_warning (G_STRLOC ": no timeline found, unable to start the animation"); } } static void clutter_animation_setup_property (ClutterAnimation *animation, const gchar *property_name, const GValue *value, GParamSpec *pspec, gboolean is_fixed) { ClutterAnimationPrivate *priv = animation->priv; GValue real_value = G_VALUE_INIT; if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) { g_warning ("Cannot bind property '%s': the property is " "construct-only", property_name); return; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("Cannot bind property '%s': the property is " "not writable", property_name); return; } /* initialize the real value that will be used to store the * final state of the animation */ g_value_init (&real_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); /* if it's not the same type of the GParamSpec value, try to * convert it using the GValue transformation API, otherwise * just copy it */ if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (&real_value))) { /* are these two types compatible (can be directly copied)? */ if (g_value_type_compatible (G_VALUE_TYPE (value), G_VALUE_TYPE (&real_value))) { g_value_copy (value, &real_value); goto done; } /* are these two type transformable? */ if (g_value_type_transformable (G_VALUE_TYPE (value), G_VALUE_TYPE (&real_value))) { if (g_value_transform (value, &real_value)) goto done; } /* if not compatible and not transformable then we can't do much */ g_warning ("%s: Unable to convert from %s to %s for " "the property '%s' of object %s", G_STRLOC, g_type_name (G_VALUE_TYPE (value)), g_type_name (G_VALUE_TYPE (&real_value)), property_name, G_OBJECT_TYPE_NAME (priv->object)); g_value_unset (&real_value); return; } else g_value_copy (value, &real_value); done: /* create an interval and bind it to the property, in case * it's not a fixed property, otherwise just set it */ if (G_LIKELY (!is_fixed)) { ClutterInterval *interval; GValue cur_value = G_VALUE_INIT; g_value_init (&cur_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); if (CLUTTER_IS_ANIMATABLE (priv->object)) clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (priv->object), property_name, &cur_value); else g_object_get_property (priv->object, property_name, &cur_value); interval = clutter_interval_new_with_values (G_PARAM_SPEC_VALUE_TYPE (pspec), &cur_value, &real_value); if (!clutter_animation_has_property (animation, property_name)) clutter_animation_bind_property_internal (animation, property_name, pspec, interval); else clutter_animation_update_property_internal (animation, property_name, pspec, interval); g_value_unset (&cur_value); } else { if (CLUTTER_IS_ANIMATABLE (priv->object)) clutter_animatable_set_final_state (CLUTTER_ANIMATABLE (priv->object), property_name, &real_value); else g_object_set_property (priv->object, property_name, &real_value); } g_value_unset (&real_value); } static void clutter_animation_setupv (ClutterAnimation *animation, gint n_properties, const gchar * const properties[], const GValue *values) { ClutterAnimationPrivate *priv = animation->priv; ClutterAnimatable *animatable = NULL; GObjectClass *klass = NULL; gint i; if (CLUTTER_IS_ANIMATABLE (priv->object)) animatable = CLUTTER_ANIMATABLE (priv->object); else klass = G_OBJECT_GET_CLASS (priv->object); for (i = 0; i < n_properties; i++) { const gchar *property_name = properties[i]; GParamSpec *pspec; gboolean is_fixed = FALSE; if (g_str_has_prefix (property_name, "fixed::")) { property_name += 7; /* strlen("fixed::") */ is_fixed = TRUE; } if (animatable != NULL) pspec = clutter_animatable_find_property (animatable, property_name); else pspec = g_object_class_find_property (klass, property_name); if (pspec == NULL) { g_warning ("Cannot bind property '%s': objects of type '%s' do " "not have this property", property_name, g_type_name (G_OBJECT_TYPE (priv->object))); break; } clutter_animation_setup_property (animation, property_name, &values[i], pspec, is_fixed); } } static const struct { const gchar *name; GConnectFlags flags; } signal_prefixes[] = { { "::", 0 }, { "-swapped::", G_CONNECT_SWAPPED }, { "-after::", G_CONNECT_AFTER }, { "-swapped-after::", G_CONNECT_SWAPPED | G_CONNECT_AFTER } }; static gboolean clutter_animation_has_signal_prefix (const gchar *property_name, GConnectFlags *flags, int *offset) { int i; if (!g_str_has_prefix (property_name, "signal")) return FALSE; for (i = 0; i < G_N_ELEMENTS (signal_prefixes); i++) if (g_str_has_prefix (property_name + 6, signal_prefixes[i].name)) { *offset = strlen (signal_prefixes[i].name) + 6; *flags = signal_prefixes[i].flags; return TRUE; } return FALSE; } static void clutter_animation_setup_valist (ClutterAnimation *animation, const gchar *first_property_name, va_list var_args) { ClutterAnimationPrivate *priv = animation->priv; ClutterAnimatable *animatable = NULL; GObjectClass *klass = NULL; const gchar *property_name; if (CLUTTER_IS_ANIMATABLE (priv->object)) animatable = CLUTTER_ANIMATABLE (priv->object); else klass = G_OBJECT_GET_CLASS (priv->object); property_name = first_property_name; while (property_name != NULL) { GParamSpec *pspec; GValue final = G_VALUE_INIT; gchar *error = NULL; gboolean is_fixed = FALSE; GConnectFlags flags; int offset; if (clutter_animation_has_signal_prefix (property_name, &flags, &offset)) { const gchar *signal_name = property_name + offset; GCallback callback = va_arg (var_args, GCallback); gpointer userdata = va_arg (var_args, gpointer); g_signal_connect_data (animation, signal_name, callback, userdata, NULL, flags); } else { if (g_str_has_prefix (property_name, "fixed::")) { property_name += 7; /* strlen("fixed::") */ is_fixed = TRUE; } if (animatable != NULL) pspec = clutter_animatable_find_property (animatable, property_name); else pspec = g_object_class_find_property (klass, property_name); if (pspec == NULL) { g_warning ("Cannot bind property '%s': objects of type '%s' do " "not have this property", property_name, g_type_name (G_OBJECT_TYPE (priv->object))); break; } G_VALUE_COLLECT_INIT (&final, G_PARAM_SPEC_VALUE_TYPE (pspec), var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); break; } clutter_animation_setup_property (animation, property_name, &final, pspec, is_fixed); g_value_unset (&final); } property_name = va_arg (var_args, gchar*); } } static ClutterAnimation * animation_create_for_actor (ClutterActor *actor) { ClutterAnimation *animation; GObject *object = G_OBJECT (actor); animation = g_object_get_qdata (object, quark_object_animation); if (animation == NULL) { animation = clutter_animation_new (); clutter_animation_set_object (animation, object); g_object_set_qdata (object, quark_object_animation, animation); /* use the ::destroy signal to get a notification * that the actor went away mid-animation */ g_signal_connect (object, "destroy", G_CALLBACK (on_actor_destroy), animation); CLUTTER_NOTE (ANIMATION, "Created new Animation [%p] for actor [%p]", animation, actor); } else { CLUTTER_NOTE (ANIMATION, "Reusing Animation [%p] for actor [%p]", animation, actor); } return animation; } /** * clutter_actor_animate_with_alpha: * @actor: a #ClutterActor * @alpha: a #ClutterAlpha * @first_property_name: the name of a property * @...: a %NULL terminated list of property names and * property values * * Animates the given list of properties of @actor between the current * value for each property and a new final value. The animation has a * definite behaviour given by the passed @alpha. * * See clutter_actor_animate() for further details. * * This function is useful if you want to use an existing #ClutterAlpha * to animate @actor. * * Return value: (transfer none): a #ClutterAnimation object. The object is owned by the * #ClutterActor and should not be unreferenced with g_object_unref() * * Since: 1.0 * * Deprecated: 1.10: Use the implicit transition for animatable properties * in #ClutterActor instead. See clutter_actor_save_easing_state(), * clutter_actor_set_easing_mode(), clutter_actor_set_easing_duration(), * clutter_actor_set_easing_delay(), and clutter_actor_restore_easing_state(). */ ClutterAnimation * clutter_actor_animate_with_alpha (ClutterActor *actor, ClutterAlpha *alpha, const gchar *first_property_name, ...) { ClutterAnimation *animation; ClutterTimeline *timeline; va_list args; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), NULL); g_return_val_if_fail (first_property_name != NULL, NULL); timeline = clutter_alpha_get_timeline (alpha); if (timeline == NULL) { g_warning ("The passed ClutterAlpha does not have an " "associated ClutterTimeline."); return NULL; } animation = animation_create_for_actor (actor); clutter_animation_set_alpha_internal (animation, alpha); va_start (args, first_property_name); clutter_animation_setup_valist (animation, first_property_name, args); va_end (args); clutter_animation_start (animation); return animation; } /** * clutter_actor_animate_with_timeline: * @actor: a #ClutterActor * @mode: an animation mode logical id * @timeline: a #ClutterTimeline * @first_property_name: the name of a property * @...: a %NULL terminated list of property names and * property values * * Animates the given list of properties of @actor between the current * value for each property and a new final value. The animation has a * definite duration given by @timeline and a speed given by the @mode. * * See clutter_actor_animate() for further details. * * This function is useful if you want to use an existing timeline * to animate @actor. * * Return value: (transfer none): a #ClutterAnimation object. The object is * owned by the #ClutterActor and should not be unreferenced with * g_object_unref() * * Since: 1.0 * Deprecated: 1.12: Use the implicit transition for animatable properties * in #ClutterActor instead. See clutter_actor_save_easing_state(), * clutter_actor_set_easing_mode(), clutter_actor_set_easing_duration(), * clutter_actor_set_easing_delay(), and clutter_actor_restore_easing_state(). */ ClutterAnimation * clutter_actor_animate_with_timeline (ClutterActor *actor, gulong mode, ClutterTimeline *timeline, const gchar *first_property_name, ...) { ClutterAnimation *animation; va_list args; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL); g_return_val_if_fail (first_property_name != NULL, NULL); animation = animation_create_for_actor (actor); clutter_animation_set_mode (animation, mode); clutter_animation_set_timeline (animation, timeline); va_start (args, first_property_name); clutter_animation_setup_valist (animation, first_property_name, args); va_end (args); clutter_animation_start (animation); return animation; } /** * clutter_actor_animate: * @actor: a #ClutterActor * @mode: an animation mode logical id * @duration: duration of the animation, in milliseconds * @first_property_name: the name of a property * @...: a %NULL terminated list of property names and * property values * * Animates the given list of properties of @actor between the current * value for each property and a new final value. The animation has a * definite duration and a speed given by the @mode. * * For example, this: * * |[ * clutter_actor_animate (rectangle, CLUTTER_LINEAR, 250, * "width", 100.0, * "height", 100.0, * NULL); * ]| * * will make width and height properties of the #ClutterActor "rectangle" * grow linearly between the current value and 100 pixels, in 250 milliseconds. * * The animation @mode is a logical id, either from the #ClutterAnimationMode * enumeration of from clutter_alpha_register_func(). * * All the properties specified will be animated between the current value * and the final value. If a property should be set at the beginning of * the animation but not updated during the animation, it should be prefixed * by the "fixed::" string, for instance: * * |[ * clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, 100, * "rotation-angle-z", 360.0, * "fixed::rotation-center-z", ¢er, * NULL); * ]| * * Will animate the "rotation-angle-z" property between the current value * and 360 degrees, and set the "rotation-center-z" property to the fixed * value of the #ClutterVertex "center". * * This function will implicitly create a #ClutterAnimation object which * will be assigned to the @actor and will be returned to the developer * to control the animation or to know when the animation has been * completed. * * If a name argument starts with "signal::", "signal-after::", * "signal-swapped::" or "signal-swapped-after::" the two following arguments * are used as callback function and data for a signal handler installed on * the #ClutterAnimation object for the specified signal name, for instance: * * |[ * static void * on_animation_completed (ClutterAnimation *animation, * ClutterActor *actor) * { * clutter_actor_hide (actor); * } * * clutter_actor_animate (actor, CLUTTER_EASE_IN_CUBIC, 100, * "opacity", 0, * "signal::completed", on_animation_completed, actor, * NULL); * ]| * * or, to automatically destroy an actor at the end of the animation: * * |[ * clutter_actor_animate (actor, CLUTTER_EASE_IN_CUBIC, 100, * "opacity", 0, * "signal-swapped-after::completed", * clutter_actor_destroy, * actor, * NULL); * ]| * * The "signal::" modifier is the equivalent of using g_signal_connect(); * the "signal-after::" modifier is the equivalent of using * g_signal_connect_after() or g_signal_connect_data() with the * %G_CONNECT_AFTER; the "signal-swapped::" modifier is the equivalent * of using g_signal_connect_swapped() or g_signal_connect_data() with the * %G_CONNECT_SWAPPED flah; finally, the "signal-swapped-after::" modifier * is the equivalent of using g_signal_connect_data() with both the * %G_CONNECT_AFTER and %G_CONNECT_SWAPPED flags. The clutter_actor_animate() * function will not keep track of multiple connections to the same signal, * so it is your responsability to avoid them when calling * clutter_actor_animate() multiple times on the same actor. * * Calling this function on an actor that is already being animated * will cause the current animation to change with the new final values, * the new easing mode and the new duration - that is, this code: * * |[ * clutter_actor_animate (actor, CLUTTER_LINEAR, 250, * "width", 100.0, * "height", 100.0, * NULL); * clutter_actor_animate (actor, CLUTTER_EASE_IN_CUBIC, 500, * "x", 100.0, * "y", 100.0, * "width", 200.0, * NULL); * ]| * * is the equivalent of: * * |[ * clutter_actor_animate (actor, CLUTTER_EASE_IN_CUBIC, 500, * "x", 100.0, * "y", 100.0, * "width", 200.0, * "height", 100.0, * NULL); * ]| * * Unless the animation is looping, the #ClutterAnimation created by * clutter_actor_animate() will become invalid as soon as it is * complete. * * Since the created #ClutterAnimation instance attached to @actor * is guaranteed to be valid throughout the #ClutterAnimation::completed * signal emission chain, you will not be able to create a new animation * using clutter_actor_animate() on the same @actor from within the * #ClutterAnimation::completed signal handler unless you use * g_signal_connect_after() to connect the callback function, for instance: * * |[ * static void * on_animation_completed (ClutterAnimation *animation, * ClutterActor *actor) * { * clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 250, * "x", 500.0, * "y", 500.0, * NULL); * } * * ... * animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_CUBIC, 250, * "x", 100.0, * "y", 100.0, * NULL); * g_signal_connect (animation, "completed", * G_CALLBACK (on_animation_completed), * actor); * ... * ]| * * Return value: (transfer none): a #ClutterAnimation object. The object is * owned by the #ClutterActor and should not be unreferenced with * g_object_unref() * * Since: 1.0 * Deprecated: 1.12: Use the implicit transition for animatable properties * in #ClutterActor instead. See clutter_actor_save_easing_state(), * clutter_actor_set_easing_mode(), clutter_actor_set_easing_duration(), * clutter_actor_set_easing_delay(), and clutter_actor_restore_easing_state(). */ ClutterAnimation * clutter_actor_animate (ClutterActor *actor, gulong mode, guint duration, const gchar *first_property_name, ...) { ClutterAnimation *animation; va_list args; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); g_return_val_if_fail (mode != CLUTTER_CUSTOM_MODE, NULL); g_return_val_if_fail (duration > 0, NULL); g_return_val_if_fail (first_property_name != NULL, NULL); animation = animation_create_for_actor (actor); clutter_animation_set_mode (animation, mode); clutter_animation_set_duration (animation, duration); va_start (args, first_property_name); clutter_animation_setup_valist (animation, first_property_name, args); va_end (args); clutter_animation_start (animation); return animation; } /** * clutter_actor_animatev: * @actor: a #ClutterActor * @mode: an animation mode logical id * @duration: duration of the animation, in milliseconds * @n_properties: number of property names and values * @properties: (array length=n_properties) (element-type utf8): a vector * containing the property names to set * @values: (array length=n_properties): a vector containing the * property values to set * * Animates the given list of properties of @actor between the current * value for each property and a new final value. The animation has a * definite duration and a speed given by the @mode. * * This is the vector-based variant of clutter_actor_animate(), useful * for language bindings. * * Unlike clutter_actor_animate(), this function will not * allow you to specify "signal::" names and callbacks. * * Return value: (transfer none): a #ClutterAnimation object. The object is * owned by the #ClutterActor and should not be unreferenced with * g_object_unref() * * Since: 1.0 * Deprecated: 1.12: Use the implicit transition for animatable properties * in #ClutterActor instead. See clutter_actor_save_easing_state(), * clutter_actor_set_easing_mode(), clutter_actor_set_easing_duration(), * clutter_actor_set_easing_delay(), and clutter_actor_restore_easing_state(). */ ClutterAnimation * clutter_actor_animatev (ClutterActor *actor, gulong mode, guint duration, gint n_properties, const gchar * const properties[], const GValue *values) { ClutterAnimation *animation; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); g_return_val_if_fail (mode != CLUTTER_CUSTOM_MODE, NULL); g_return_val_if_fail (duration > 0, NULL); g_return_val_if_fail (properties != NULL, NULL); g_return_val_if_fail (values != NULL, NULL); animation = animation_create_for_actor (actor); clutter_animation_set_mode (animation, mode); clutter_animation_set_duration (animation, duration); clutter_animation_setupv (animation, n_properties, properties, values); clutter_animation_start (animation); return animation; } /** * clutter_actor_animate_with_timelinev: * @actor: a #ClutterActor * @mode: an animation mode logical id * @timeline: a #ClutterTimeline * @n_properties: number of property names and values * @properties: (array length=n_properties) (element-type utf8): a vector * containing the property names to set * @values: (array length=n_properties): a vector containing the * property values to set * * Animates the given list of properties of @actor between the current * value for each property and a new final value. The animation has a * definite duration given by @timeline and a speed given by the @mode. * * See clutter_actor_animate() for further details. * * This function is useful if you want to use an existing timeline * to animate @actor. * * This is the vector-based variant of clutter_actor_animate_with_timeline(), * useful for language bindings. * * Unlike clutter_actor_animate_with_timeline(), this function * will not allow you to specify "signal::" names and callbacks. * * Return value: (transfer none): a #ClutterAnimation object. The object is * owned by the #ClutterActor and should not be unreferenced with * g_object_unref() * * Since: 1.0 * Deprecated: 1.12: Use the implicit transition for animatable properties * in #ClutterActor instead. See clutter_actor_save_easing_state(), * clutter_actor_set_easing_mode(), clutter_actor_set_easing_duration(), * clutter_actor_set_easing_delay(), and clutter_actor_restore_easing_state(). */ ClutterAnimation * clutter_actor_animate_with_timelinev (ClutterActor *actor, gulong mode, ClutterTimeline *timeline, gint n_properties, const gchar * const properties[], const GValue *values) { ClutterAnimation *animation; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL); g_return_val_if_fail (properties != NULL, NULL); g_return_val_if_fail (values != NULL, NULL); animation = animation_create_for_actor (actor); clutter_animation_set_mode (animation, mode); clutter_animation_set_timeline (animation, timeline); clutter_animation_setupv (animation, n_properties, properties, values); clutter_animation_start (animation); return animation; } /** * clutter_actor_animate_with_alphav: * @actor: a #ClutterActor * @alpha: a #ClutterAlpha * @n_properties: number of property names and values * @properties: (array length=n_properties) (element-type utf8): a vector * containing the property names to set * @values: (array length=n_properties): a vector containing the * property values to set * * Animates the given list of properties of @actor between the current * value for each property and a new final value. The animation has a * definite behaviour given by the passed @alpha. * * See clutter_actor_animate() for further details. * * This function is useful if you want to use an existing #ClutterAlpha * to animate @actor. * * This is the vector-based variant of clutter_actor_animate_with_alpha(), * useful for language bindings. * * Unlike clutter_actor_animate_with_alpha(), this function will * not allow you to specify "signal::" names and callbacks. * * Return value: (transfer none): a #ClutterAnimation object. The object is owned by the * #ClutterActor and should not be unreferenced with g_object_unref() * * Since: 1.0 * * Deprecated: 1.10: Use the implicit transition for animatable properties * in #ClutterActor instead. See clutter_actor_save_easing_state(), * clutter_actor_set_easing_mode(), clutter_actor_set_easing_duration(), * clutter_actor_set_easing_delay(), and clutter_actor_restore_easing_state(). */ ClutterAnimation * clutter_actor_animate_with_alphav (ClutterActor *actor, ClutterAlpha *alpha, gint n_properties, const gchar * const properties[], const GValue *values) { ClutterAnimation *animation; ClutterTimeline *timeline; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), NULL); g_return_val_if_fail (properties != NULL, NULL); g_return_val_if_fail (values != NULL, NULL); timeline = clutter_alpha_get_timeline (alpha); if (timeline == NULL) { g_warning ("The passed ClutterAlpha does not have an " "associated ClutterTimeline."); return NULL; } animation = animation_create_for_actor (actor); clutter_animation_set_alpha_internal (animation, alpha); clutter_animation_setupv (animation, n_properties, properties, values); clutter_animation_start (animation); return animation; } /** * clutter_actor_get_animation: * @actor: a #ClutterActor * * Retrieves the #ClutterAnimation used by @actor, if clutter_actor_animate() * has been called on @actor. * * Return value: (transfer none): a #ClutterAnimation, or %NULL * * Since: 1.0 * Deprecated: 1.12: Use the implicit transition for animatable properties * in #ClutterActor instead, and clutter_actor_get_transition() to retrieve * the transition. */ ClutterAnimation * clutter_actor_get_animation (ClutterActor *actor) { g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); return g_object_get_qdata (G_OBJECT (actor), quark_object_animation); } /** * clutter_actor_detach_animation: * @actor: a #ClutterActor * * Detaches the #ClutterAnimation used by @actor, if clutter_actor_animate() * has been called on @actor. * * Once the animation has been detached, it loses a reference. If it was * the only reference then the #ClutterAnimation becomes invalid. * * The #ClutterAnimation::completed signal will not be emitted. * * Since: 1.4 * Deprecated: 1.12: Use the implicit transition for animatable properties * in #ClutterActor instead, and clutter_actor_remove_transition() to * remove the transition. */ void clutter_actor_detach_animation (ClutterActor *actor) { ClutterAnimation *animation; ClutterAnimationPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (actor)); animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation); if (animation == NULL) return; priv = animation->priv; g_assert (priv->object == G_OBJECT (actor)); /* we can't call get_timeline_internal() here because it would be * pointless to create a timeline on an animation we want to detach */ if (priv->alpha != NULL) { ClutterTimeline *timeline; timeline = clutter_alpha_get_timeline (priv->alpha); if (timeline != NULL) clutter_timeline_stop (timeline); } /* disconnect the ::destroy handler added by animation_create_for_actor() */ g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (on_actor_destroy), animation); clutter_animation_set_object (animation, NULL); /* drop the reference on the animation */ g_object_unref (animation); } muffin-5.2.1/clutter/clutter/deprecated/clutter-util.h0000664000175000017500000000224014211404421023204 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_UTIL_H__ #define __CLUTTER_UTIL_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_2 gint clutter_util_next_p2 (gint a); G_END_DECLS #endif /* __CLUTTER_UTIL_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-animatable.h0000664000175000017500000000352214211404421024330 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_ANIMATABLE_DEPRECATED_H__ #define __CLUTTER_ANIMATABLE_DEPRECATED_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_animatable_interpolate_value) gboolean clutter_animatable_animate_property (ClutterAnimatable *animatable, ClutterAnimation *animation, const gchar *property_name, const GValue *initial_value, const GValue *final_value, gdouble progress, GValue *value); G_END_DECLS #endif /* __CLUTTER_ANIMATABLE_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour.h0000664000175000017500000001322614211404421024221 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BEHAVIOUR_H__ #define __CLUTTER_BEHAVIOUR_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_BEHAVIOUR clutter_behaviour_get_type() #define CLUTTER_BEHAVIOUR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ CLUTTER_TYPE_BEHAVIOUR, ClutterBehaviour)) #define CLUTTER_BEHAVIOUR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ CLUTTER_TYPE_BEHAVIOUR, ClutterBehaviourClass)) #define CLUTTER_IS_BEHAVIOUR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ CLUTTER_TYPE_BEHAVIOUR)) #define CLUTTER_IS_BEHAVIOUR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ CLUTTER_TYPE_BEHAVIOUR)) #define CLUTTER_BEHAVIOUR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ CLUTTER_TYPE_BEHAVIOUR, ClutterBehaviourClass)) typedef struct _ClutterBehaviourPrivate ClutterBehaviourPrivate; typedef struct _ClutterBehaviourClass ClutterBehaviourClass; /** * ClutterBehaviourForeachFunc: * @behaviour: the #ClutterBehaviour * @actor: an actor driven by @behaviour * @data: (closure): optional data passed to the function * * This function is passed to clutter_behaviour_actors_foreach() and * will be called for each actor driven by @behaviour. * * Since: 0.2 * * Deprecated: 1.6 */ typedef void (*ClutterBehaviourForeachFunc) (ClutterBehaviour *behaviour, ClutterActor *actor, gpointer data); /** * ClutterBehaviour: * * #ClutterBehaviour-struct contains only private data and should * be accessed with the functions below. * * Since: 0.2 * * Deprecated: 1.6 */ struct _ClutterBehaviour { /*< private >*/ GObject parent; ClutterBehaviourPrivate *priv; }; /** * ClutterBehaviourClass: * @alpha_notify: virtual function, called each time the #ClutterAlpha * computes a new alpha value; the actors to which the behaviour applies * should be changed in this function. Every subclass of #ClutterBehaviour * must implement this virtual function * @applied: signal class handler for the ClutterBehaviour::applied signal * @removed: signal class handler for the ClutterBehaviour::removed signal * * Base class for behaviours. * * Since: 0.2 * * Deprecated: 1.6 */ struct _ClutterBehaviourClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ /* vfunc, not signal */ void (*alpha_notify) (ClutterBehaviour *behave, gdouble alpha_value); /* signals */ void (*applied) (ClutterBehaviour *behave, ClutterActor *actor); void (*removed) (ClutterBehaviour *behave, ClutterActor *actor); /*< private >*/ /* padding, for future expansion */ void (*_clutter_behaviour1) (void); void (*_clutter_behaviour2) (void); void (*_clutter_behaviour3) (void); void (*_clutter_behaviour4) (void); void (*_clutter_behaviour5) (void); void (*_clutter_behaviour6) (void); }; CLUTTER_DEPRECATED_IN_1_6 GType clutter_behaviour_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_apply (ClutterBehaviour *behave, ClutterActor *actor); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_remove (ClutterBehaviour *behave, ClutterActor *actor); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_remove_all (ClutterBehaviour *behave); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_actors_foreach (ClutterBehaviour *behave, ClutterBehaviourForeachFunc func, gpointer data); CLUTTER_DEPRECATED_IN_1_6 gint clutter_behaviour_get_n_actors (ClutterBehaviour *behave); CLUTTER_DEPRECATED_IN_1_6 ClutterActor *clutter_behaviour_get_nth_actor (ClutterBehaviour *behave, gint index_); CLUTTER_DEPRECATED_IN_1_6 GSList * clutter_behaviour_get_actors (ClutterBehaviour *behave); CLUTTER_DEPRECATED_IN_1_6 ClutterAlpha *clutter_behaviour_get_alpha (ClutterBehaviour *behave); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_set_alpha (ClutterBehaviour *behave, ClutterAlpha *alpha); CLUTTER_DEPRECATED_IN_1_6 gboolean clutter_behaviour_is_applied (ClutterBehaviour *behave, ClutterActor *actor); G_END_DECLS #endif /* __CLUTTER_BEHAVIOUR_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-state.c0000664000175000017500000021426014211404421023351 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Øyvind Kolås * * Copyright (C) 2009 Intel Corporation * * 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, see . */ /** * SECTION:clutter-state * @short_description: State machine with animated transitions * * #ClutterState is an object controlling the tweening of properties on * multiple actors between a set of named states. #ClutterStateKeys * define how the properties are animated. If the source_state_name for a key * is NULL it is used for transition to the target state unless a specific key * exists for transitioning from the current state to the requested state. * * #ClutterState is available since Clutter 1.4. * * #ClutterState has been deprecated in Clutter 1.12. There is no direct * replacement for this API, but it's highly suggested you use a combination * of [implicit transitions][clutter-actor-animation] and explicit transitions * using #ClutterTransition and its subclasses. * * ## Using ClutterState * * The following example defines a "base" and a "hover" state in a * #ClutterState instance. * * |[ * ClutterState *state = clutter_state_new (); * ClutterColor color = { 0, }; * * // transition from any state to the "base" state * clutter_color_from_string (&color, "rgb(255, 0, 0)"); * clutter_state_set (state, NULL, "base", * actor, "color", CLUTTER_LINEAR, &color, * actor, "scale-x", CLUTTER_EASE_IN_BOUNCE, 1.0, * actor, "scale-y", CLUTTER_EASE_IN_BOUNCE, 1.0, * NULL); * * // transition from the "base" state to the "hover" state * clutter_color_from_string (&color, "rgb(0, 0, 255)"); * clutter_state_set (state, "base", "hover", * actor, "color", CLUTTER_LINEAR, &color, * actor, "scale-x", CLUTTER_EASE_OUT_BOUNCE, 1.7, * actor, "scale-y", CLUTTER_EASE_OUT_BOUNCE, 1.7, * NULL); * * // the default duration of any transition * clutter_state_set_duration (state, NULL, NULL, 500); * * // set "base" as the initial state * clutter_state_warp_to_state (state, "base"); * ]| * * The actor then uses the #ClutterState to animate through the * two states using callbacks for the #ClutterActor::enter-event and * #ClutterActor::leave-event signals. * * |[ * static gboolean * on_enter (ClutterActor *actor, * ClutterEvent *event, * ClutterState *state) * { * clutter_state_set_state (state, "hover"); * * return CLUTTER_EVENT_STOP; * } * * static gboolean * on_leave (ClutterActor *actor, * ClutterEvent *event, * ClutterState *state) * { * clutter_state_set_state (state, "base"); * * return CLUTTER_EVENT_STOP; * } * * ## ClutterState description for ClutterScript * * #ClutterState defines a custom `transitions` JSON object member which * allows describing the states. * * The `transitions` property has the following syntax: * * |[ * { * "transitions" : [ * { * "source" : "source-state", * "target" : "target-state", * "duration" : milliseconds, * "keys" : [ * [ * "object-id", * "property-name", * "easing-mode", * "final-value", * ], * [ * "object-id", * "property-name", * "easing-mode", * "final-value", * pre-delay, * post-delay; * ], * ... * ] * }, * { * "source" : "source-state", * "target" : "target-state", * "duration" : milliseconds, * "animator" : "animator-definition" * }, * ... * ] * } * ]| * * Each element of the transitions array follows the same rules and order * as clutter_state_set_key() function arguments. * * The source and target values control the source and target state of the * transition. The key and animator properties are mutually exclusive. * * The pre-delay and post-delay values are optional. * * The example below is a translation into a #ClutterScript definition of * the code in the #ClutterState example above. * * |[ * { * "id" : "button-state", * "type" : "ClutterState", * "duration" : 500, * "transitions" : [ * { * "source" : "*", * "target" : "base", * "keys" : [ * [ "button", "color", "linear", "rgb(255, 0, 0)" ], * [ "button", "scale-x", "easeInBounce", 1.0 ], * [ "button", "scale-y", "easeInBounce", 1.0 ] * ] * }, * { * "source" : "base", * "target" : "hover", * "keys" : [ * [ "button", "color", "linear", "rgb(0, 0, 255)" ], * [ "button", "scale-x", "easeOutBounce", 1.7 ], * [ "button", "scale-y", "easeOutBounce", 1.7 ] * ] * } * ] * } * ]| */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-state.h" #include "clutter-alpha.h" #include "clutter-animatable.h" #include "clutter-animator.h" #include "clutter-enum-types.h" #include "clutter-interval.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-scriptable.h" #include "clutter-script-private.h" typedef struct StateAnimator { const gchar *source_state_name; /* interned string identifying entry */ ClutterAnimator *animator; /* pointer to animator itself */ } StateAnimator; typedef struct State { const gchar *name; /* interned string for this state name */ GHashTable *durations; /* durations for transitions from various state names */ GList *keys; /* list of all keys pertaining to transitions from other states to this one */ GArray *animators; /* list of animators for transitioning from * specific source states */ ClutterState *clutter_state; /* the ClutterState object this state belongs to */ } State; struct _ClutterStatePrivate { GHashTable *states; /* contains state objects */ guint duration; /* global fallback duration */ ClutterTimeline *timeline; /* The timeline used for doing the progress */ ClutterTimeline *slave_timeline; /* a slave timeline used to compute alphas */ const gchar *source_state_name; /* current source state */ State *source_state; /* current source_state */ const gchar *target_state_name; /* current target state */ State *target_state; /* target state name */ ClutterAnimator *current_animator; /* !NULL if the current transition is overriden by an animator */ }; #define SLAVE_TIMELINE_LENGTH 10000 /* * ClutterStateKey: * * An opaque data structure with accessor functions. * */ typedef struct _ClutterStateKey { GObject *object; /* an Gobject */ const gchar *property_name;/* the name of a property */ gulong mode; /* alpha to use */ GValue value; /* target value */ gdouble pre_delay; /* fraction of duration to delay before starting */ gdouble pre_pre_delay;/* fraction of duration to add to pre_delay. This is used to set keys during transitions. */ gdouble post_delay; /* fraction of duration to be done in */ State *source_state; /* source state */ State *target_state; /* target state */ ClutterAlpha *alpha; /* The alpha this key uses for interpolation */ ClutterInterval *interval; /* The interval this key uses for interpolation */ guint is_animatable : 1; guint is_inert : 1; /* set if the key is being destroyed due to weak reference */ gint ref_count; /* reference count for boxed life time */ } _ClutterStateKey; enum { PROP_0, PROP_DURATION, PROP_STATE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { COMPLETED, LAST_SIGNAL }; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); static guint state_signals[LAST_SIGNAL] = {0, }; G_DEFINE_TYPE_WITH_CODE (ClutterState, clutter_state, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterState) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)) /** * clutter_state_new: * * Creates a new #ClutterState * * Return value: the newly create #ClutterState instance * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ ClutterState * clutter_state_new (void) { return g_object_new (CLUTTER_TYPE_STATE, NULL); } static gint sort_props_func (gconstpointer a, gconstpointer b) { const ClutterStateKey *pa = a; const ClutterStateKey *pb = b; if (pa->object == pb->object) { gint propnamediff = pa->property_name-pb->property_name; if (propnamediff == 0) return pb->source_state - pa->source_state; return propnamediff; } return pa->object - pb->object; } static State * clutter_state_fetch_state (ClutterState *state, const gchar *state_name, gboolean force_creation); static void object_disappeared (gpointer data, GObject *where_the_object_was); static ClutterStateKey * clutter_state_key_new (State *state, GObject *object, const gchar *property_name, GParamSpec *pspec, guint mode) { ClutterStatePrivate *priv = state->clutter_state->priv; ClutterStateKey *state_key; GValue value = G_VALUE_INIT; state_key = g_slice_new0 (ClutterStateKey); state_key->target_state = state; state_key->object = object; state_key->property_name = g_intern_string (property_name); state_key->mode = mode; state_key->is_animatable = CLUTTER_IS_ANIMATABLE (object); state_key->alpha = clutter_alpha_new (); g_object_ref_sink (state_key->alpha); clutter_alpha_set_mode (state_key->alpha, mode); clutter_alpha_set_timeline (state_key->alpha, priv->slave_timeline); state_key->interval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", G_PARAM_SPEC_VALUE_TYPE (pspec), NULL); g_object_ref_sink (state_key->interval); g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); clutter_interval_set_initial_value (state_key->interval, &value); clutter_interval_set_final_value (state_key->interval, &value); g_value_unset (&value); g_object_weak_ref (object, object_disappeared, state_key->target_state->clutter_state); return state_key; } static void clutter_state_key_free (gpointer clutter_state_key) { ClutterStateKey *key = clutter_state_key; if (key == NULL) return; key->ref_count -= 1; if (key->ref_count > 0) return; if (!key->is_inert) { g_object_weak_unref (key->object, object_disappeared, key->target_state->clutter_state); } g_value_unset (&key->value); g_object_unref (key->alpha); g_object_unref (key->interval); g_slice_free (ClutterStateKey, key); } static inline void clutter_state_remove_key_internal (ClutterState *this, const gchar *source_state_name, const gchar *target_state_name, GObject *object, const gchar *property_name, gboolean is_inert) { GList *s, *state_list; State *source_state = NULL; source_state_name = g_intern_string (source_state_name); target_state_name = g_intern_string (target_state_name); property_name = g_intern_string (property_name); if (source_state_name) source_state = clutter_state_fetch_state (this, source_state_name, FALSE); again_from_start: if (target_state_name != NULL) state_list = g_list_append (NULL, (gpointer) target_state_name); else state_list = clutter_state_get_states (this); for (s = state_list; s != NULL; s = s->next) { State *target_state; target_state = clutter_state_fetch_state (this, s->data, FALSE); /* Go through each TargetState */ if (target_state) { GList *k = target_state->keys; /* Note the safe while() loop, because we modify the list inline */ while (k != NULL) { ClutterStateKey *key = k->data; k = k->next; /* Check if each key matches query */ if ( (object == NULL || (object == key->object)) && (source_state == NULL || (source_state == key->source_state)) && (property_name == NULL || ((property_name == key->property_name)))) { /* Remove matching key */ target_state->keys = g_list_remove (target_state->keys, key); key->is_inert = is_inert; clutter_state_key_free (key); /* no more keys with transitions to this target_state*/ if (target_state->keys == NULL) { /* If this state is the current state, unset the state */ if (target_state == this->priv->target_state) clutter_state_set_state (this, NULL); /* remove any keys that exist that uses this state as a source */ clutter_state_remove_key_internal (this, s->data, NULL, NULL, NULL, is_inert); g_hash_table_remove (this->priv->states, s->data); goto again_from_start; /* we have just freed State *target_state, so need to restart removal */ } } } } } g_list_free (state_list); } static void object_disappeared (gpointer data, GObject *where_the_object_was) { clutter_state_remove_key_internal (data, NULL, NULL, (gpointer) where_the_object_was, NULL, TRUE); } static void state_free (gpointer data) { State *state = data; for (; state->keys; state->keys = g_list_remove (state->keys, state->keys->data)) clutter_state_key_free (state->keys->data); g_array_free (state->animators, TRUE); g_hash_table_destroy (state->durations); free (state); } static State * state_new (ClutterState *clutter_state, const gchar *name) { State *state; state = g_new0 (State, 1); state->clutter_state = clutter_state; state->name = name; state->animators = g_array_new (TRUE, TRUE, sizeof (StateAnimator)); state->durations = g_hash_table_new (g_direct_hash, g_direct_equal); return state; } static void clutter_state_finalize (GObject *object) { ClutterStatePrivate *priv = CLUTTER_STATE (object)->priv; g_hash_table_destroy (priv->states); g_object_unref (priv->timeline); g_object_unref (priv->slave_timeline); G_OBJECT_CLASS (clutter_state_parent_class)->finalize (object); } static void clutter_state_completed (ClutterTimeline *timeline, ClutterState *state) { ClutterStatePrivate *priv = state->priv; if (priv->current_animator) { clutter_animator_set_timeline (priv->current_animator, NULL); priv->current_animator = NULL; } g_signal_emit (state, state_signals[COMPLETED], 0); } static void clutter_state_new_frame (ClutterTimeline *timeline, gint msecs, ClutterState *state) { ClutterStatePrivate *priv = state->priv; GList *k; gdouble progress; const gchar *curprop = NULL; GObject *curobj = NULL; gboolean found_specific = FALSE; if (priv->current_animator) return; progress = clutter_timeline_get_progress (timeline); for (k = priv->target_state->keys; k; k = k->next) { ClutterStateKey *key = k->data; gdouble sub_progress; if ((curprop && !(curprop == key->property_name)) || key->object != curobj) { curprop = key->property_name; curobj = key->object; found_specific = FALSE; } if (!found_specific) { if (key->source_state != NULL && key->source_state->name != NULL && priv->source_state_name != NULL && g_str_equal (priv->source_state_name, key->source_state->name)) { found_specific = TRUE; } if (found_specific || key->source_state == NULL) { gdouble pre_delay = key->pre_delay + key->pre_pre_delay; sub_progress = (progress - pre_delay) / (1.0 - (pre_delay + key->post_delay)); if (sub_progress >= 0.0) { if (sub_progress >= 1.0) sub_progress = 1.0; clutter_timeline_advance (priv->slave_timeline, sub_progress * SLAVE_TIMELINE_LENGTH); sub_progress = clutter_alpha_get_alpha (key->alpha); if (key->is_animatable) { ClutterAnimatable *animatable; GValue value = G_VALUE_INIT; gboolean res; animatable = CLUTTER_ANIMATABLE (key->object); g_value_init (&value, clutter_state_key_get_property_type (key)); res = clutter_animatable_interpolate_value (animatable, key->property_name, key->interval, sub_progress, &value); if (res) clutter_animatable_set_final_state (animatable, key->property_name, &value); g_value_unset (&value); } else { const GValue *value; value = clutter_interval_compute (key->interval, sub_progress); if (value != NULL) g_object_set_property (key->object, key->property_name, value); } } /* XXX: should the target value of the default destination be * used even when found a specific source_state key? */ } } } } static ClutterTimeline * clutter_state_change (ClutterState *state, const gchar *target_state_name, gboolean animate) { ClutterStatePrivate *priv; ClutterAnimator *animator; State *new_state; guint duration; GList *k; g_return_val_if_fail (CLUTTER_IS_STATE (state), NULL); priv = state->priv; /* If we've been asked to change state to NULL, reset the * ClutterState to its initial state, but leave the keys * alone. */ if (!target_state_name) { if (!priv->target_state) return NULL; priv->source_state_name = priv->target_state_name = NULL; priv->source_state = priv->target_state = NULL; clutter_timeline_stop (priv->timeline); clutter_timeline_rewind (priv->timeline); if (priv->current_animator) { clutter_animator_set_timeline (priv->current_animator, NULL); priv->current_animator = NULL; } return NULL; } target_state_name = g_intern_string (target_state_name); if (target_state_name == priv->target_state_name) { /* Avoid transitioning if the desired state is already current, * unless we're warping to it and the state transition is in * progress (in that case, immediately warp to the state). */ if (!clutter_timeline_is_playing (priv->timeline) || animate) return priv->timeline; } if (priv->current_animator != NULL) { clutter_animator_set_timeline (priv->current_animator, NULL); priv->current_animator = NULL; } priv->source_state_name = priv->target_state_name; priv->target_state_name = target_state_name; g_object_notify_by_pspec (G_OBJECT (state), obj_props[PROP_STATE]); duration = clutter_state_get_duration (state, priv->source_state_name, priv->target_state_name); clutter_timeline_set_duration (priv->timeline, duration); new_state = clutter_state_fetch_state (state, target_state_name, FALSE); if (new_state == NULL) { g_warning ("State '%s' not found", target_state_name); return NULL; } animator = clutter_state_get_animator (state, priv->source_state_name, priv->target_state_name); priv->target_state = new_state; if (animator == NULL && new_state->keys == NULL) animator = clutter_state_get_animator (state, NULL, priv->target_state_name); if (animator != NULL) { /* we've got an animator overriding the tweened animation */ priv->current_animator = animator; clutter_animator_set_timeline (animator, priv->timeline); } else { for (k = new_state->keys; k != NULL; k = k->next) { ClutterStateKey *key = k->data; GValue initial = G_VALUE_INIT; /* Reset the pre-pre-delay - this is only used for setting keys * during transitions. */ key->pre_pre_delay = 0; g_value_init (&initial, clutter_interval_get_value_type (key->interval)); if (key->is_animatable) { ClutterAnimatable *animatable; animatable = CLUTTER_ANIMATABLE (key->object); clutter_animatable_get_initial_state (animatable, key->property_name, &initial); } else g_object_get_property (key->object, key->property_name, &initial); if (clutter_alpha_get_mode (key->alpha) != key->mode) clutter_alpha_set_mode (key->alpha, key->mode); clutter_interval_set_initial_value (key->interval, &initial); clutter_interval_set_final_value (key->interval, &key->value); g_value_unset (&initial); } } if (!animate) { clutter_timeline_stop (priv->timeline); clutter_timeline_advance (priv->timeline, duration); /* emit signals, to change properties, and indicate that the * state change is complete */ g_signal_emit_by_name (priv->timeline, "new-frame", GINT_TO_POINTER (duration), NULL); g_signal_emit_by_name (priv->timeline, "completed", NULL); } else { clutter_timeline_stop (priv->timeline); clutter_timeline_rewind (priv->timeline); clutter_timeline_start (priv->timeline); } return priv->timeline; } /** * clutter_state_set_state: * @state: a #ClutterState * @target_state_name: the state to transition to * * Change the current state of #ClutterState to @target_state_name. * * The state will animate during its transition, see * #clutter_state_warp_to_state for animation-free state switching. * * Setting a %NULL state will stop the current animation and unset * the current state, but keys will be left intact. * * Return value: (transfer none): the #ClutterTimeline that drives the * state transition. The returned timeline is owned by the #ClutterState * and it should not be unreferenced * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ ClutterTimeline * clutter_state_set_state (ClutterState *state, const gchar *target_state_name) { return clutter_state_change (state, target_state_name, TRUE); } /** * clutter_state_warp_to_state: * @state: a #ClutterState * @target_state_name: the state to transition to * * Change to the specified target state immediately with no animation. * * See clutter_state_set_state(). * * Return value: (transfer none): the #ClutterTimeline that drives the * state transition. The returned timeline is owned by the #ClutterState * and it should not be unreferenced * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ ClutterTimeline * clutter_state_warp_to_state (ClutterState *state, const gchar *target_state_name) { return clutter_state_change (state, target_state_name, FALSE); } static GParamSpec * get_property_from_object (GObject *gobject, const gchar *property_name) { GParamSpec *pspec; if (CLUTTER_IS_ANIMATABLE (gobject)) { ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (gobject); pspec = clutter_animatable_find_property (animatable, property_name); } else { GObjectClass *klass = G_OBJECT_GET_CLASS (gobject); pspec = g_object_class_find_property (klass, property_name); } if (pspec == NULL) { g_warning ("Cannot bind property '%s': objects of type '%s' " "do not have this property", property_name, G_OBJECT_TYPE_NAME (gobject)); return NULL; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("Cannot bind property '%s' of object of type '%s': " "the property is not writable", property_name, G_OBJECT_TYPE_NAME (gobject)); return NULL; } if (!(pspec->flags & G_PARAM_READABLE)) { g_warning ("Cannot bind property '%s' of object of type '%s': " "the property is not readable", property_name, G_OBJECT_TYPE_NAME (gobject)); return NULL; } if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) { g_warning ("Cannot bind property '%s' of object of type '%s': " "the property is set as constructor-only", property_name, G_OBJECT_TYPE_NAME (gobject)); return NULL; } return pspec; } /** * clutter_state_set: * @state: a #ClutterState instance. * @source_state_name: (allow-none): the name of the source state keys are being added for * @target_state_name: the name of the target state keys are being added for * @first_object: a #GObject * @first_property_name: a property of @first_object to specify a key for * @first_mode: the id of the alpha function to use * @...: the value @first_property_name should have in @target_state_name, * followed by object, property name, mode, value tuples, terminated * by %NULL * * Adds multiple keys to a named state of a #ClutterState instance, specifying * the easing mode and value a given property of an object should have at a * given progress of the animation. * * The mode specified is the easing mode used when going to from the previous * key to the specified key. * * For instance, the code below: * * |[ * clutter_state_set (state, NULL, "hover", * button, "opacity", CLUTTER_LINEAR, 255, * button, "scale-x", CLUTTER_EASE_OUT_CUBIC, 1.2, * button, "scale-y", CLUTTER_EASE_OUT_CUBIC, 1.2, * NULL); * ]| * * will create a transition from any state (a @source_state_name or NULL is * treated as a wildcard) and a state named "hover"; the * button object will have the #ClutterActor:opacity * property animated to a value of 255 using %CLUTTER_LINEAR as the animation * mode, and the #ClutterActor:scale-x and #ClutterActor:scale-y properties * animated to a value of 1.2 using %CLUTTER_EASE_OUT_CUBIC as the animation * mode. To change the state (and start the transition) you can use the * clutter_state_set_state() function: * * |[ * clutter_state_set_state (state, "hover"); * ]| * * If a given object, state_name, property tuple already exist in the * #ClutterState instance, then the mode and value will be replaced with * the new specified values. * * If a property name is prefixed with "delayed::" two additional * arguments per key are expected: a value relative to the full state time * to pause before transitioning and a similar value to pause after * transitioning, e.g.: * * |[ * clutter_state_set (state, "hover", "toggled", * button, "delayed::scale-x", CLUTTER_LINEAR, 1.0, 0.2, 0.2, * button, "delayed::scale-y", CLUTTER_LINEAR, 1.0, 0.2, 0.2, * NULL); * ]| * * will pause for 20% of the duration of the transition before animating, * and 20% of the duration after animating. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ void clutter_state_set (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, gpointer first_object, const gchar *first_property_name, gulong first_mode, ...) { gpointer object; const gchar *property_name; gulong mode; va_list args; g_return_if_fail (CLUTTER_IS_STATE (state)); object = first_object; property_name = first_property_name; mode = first_mode; g_return_if_fail (G_IS_OBJECT (first_object)); g_return_if_fail (first_property_name); va_start (args, first_mode); while (object != NULL) { GParamSpec *pspec; GValue value = G_VALUE_INIT; gchar *error = NULL; gboolean is_delayed = FALSE; if (g_str_has_prefix (property_name, "delayed::")) { property_name = strstr (property_name, "::") + 2; is_delayed = TRUE; } pspec = get_property_from_object (object, property_name); if (pspec == NULL) break; G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec), args, 0, &error); if (error != NULL) { g_warning ("%s: %s", G_STRLOC, error); free (error); break; } if (is_delayed) { gdouble pre_delay = va_arg (args, gdouble); gdouble post_delay = va_arg (args, gdouble); clutter_state_set_key (state, source_state_name, target_state_name, object, property_name, mode, &value, pre_delay, post_delay); } else { clutter_state_set_key (state, source_state_name, target_state_name, object, property_name, mode, &value, 0.0, 0.0); } g_value_unset (&value); object = va_arg (args, gpointer); if (object != NULL) { property_name = va_arg (args, gchar*); mode = va_arg (args, gulong); } } va_end (args); } static void clutter_state_set_key_internal (ClutterState *state, ClutterStateKey *key) { ClutterStatePrivate *priv = state->priv; State *target_state = key->target_state; GList *old_item = NULL; if ((old_item = g_list_find_custom (target_state->keys, key, sort_props_func))) { ClutterStateKey *old_key = old_item->data; target_state->keys = g_list_remove (target_state->keys, old_key); clutter_state_key_free (old_key); } target_state->keys = g_list_insert_sorted (target_state->keys, key, sort_props_func); /* If the current target state is modified, we have some work to do. * * If the animation is running, we add a key to the current animation * with a delay of the current duration so that the new animation will * animate into place. * * If the animation isn't running, but the state is set, we immediately * warp to that state. */ if (key->target_state == priv->target_state) { if (!clutter_timeline_is_playing (priv->timeline)) { /* We can warp to the state by setting a NULL state, then setting * the target state again. */ clutter_state_change (state, NULL, FALSE); clutter_state_change (state, target_state->name, FALSE); } else { /* Set the ClutterInterval associated with the state */ GValue initial = G_VALUE_INIT; gdouble progress = clutter_timeline_get_progress (priv->timeline); g_value_init (&initial, clutter_interval_get_value_type (key->interval)); if (key->is_animatable) { ClutterAnimatable *animatable; animatable = CLUTTER_ANIMATABLE (key->object); clutter_animatable_get_initial_state (animatable, key->property_name, &initial); } else g_object_get_property (key->object, key->property_name, &initial); if (clutter_alpha_get_mode (key->alpha) != key->mode) clutter_alpha_set_mode (key->alpha, key->mode); clutter_interval_set_initial_value (key->interval, &initial); clutter_interval_set_final_value (key->interval, &key->value); g_value_unset (&initial); /* Set the delay as if the interval had just begun */ if (progress > key->pre_delay) key->pre_pre_delay = MIN (progress - key->pre_delay, 1.0 - key->post_delay); } } } /* * clutter_state_fetch_state: * @state: a #ClutterState * @state_name: the name of the state to be retrieved * @create: %TRUE if the state should be instantiated if not found * * Retrieves the #State structure for @state_name inside the given * #ClutterState instance * * If @state_name is %NULL and @create is %TRUE then NULL will * be returned. * * Return value: a #State structure for the given name, or %NULL */ static State * clutter_state_fetch_state (ClutterState *state, const gchar *state_name, gboolean create) { ClutterStatePrivate *priv = state->priv; State *retval; if (state_name == NULL) { return NULL; } else state_name = g_intern_string (state_name); retval = g_hash_table_lookup (priv->states, state_name); if (retval == NULL && create) { retval = state_new (state, state_name); g_hash_table_insert (priv->states, (gpointer) state_name, retval); } return retval; } /** * clutter_state_set_key: * @state: a #ClutterState instance. * @source_state_name: (allow-none): the source transition to specify * transition for, or %NULL to specify the default fallback when a * more specific source state doesn't exist. * @target_state_name: the name of the transition to set a key value for. * @object: the #GObject to set a key for * @property_name: the property to set a key for * @mode: the id of the alpha function to use * @value: the value for property_name of object in state_name * @pre_delay: relative time of the transition to be idle in the beginning * of the transition * @post_delay: relative time of the transition to be idle in the end of * the transition * * Sets one specific end key for a state name, @object, @property_name * combination. * * Return value: (transfer none): the #ClutterState instance, allowing * chaining of multiple calls * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ ClutterState * clutter_state_set_key (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, GObject *object, const gchar *property_name, guint mode, const GValue *value, gdouble pre_delay, gdouble post_delay) { GParamSpec *pspec; ClutterStateKey *state_key; State *source_state = NULL; State *target_state; g_return_val_if_fail (CLUTTER_IS_STATE (state), NULL); g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (property_name, NULL); g_return_val_if_fail (value, NULL); pspec = get_property_from_object (object, property_name); if (pspec == NULL) return state; source_state = clutter_state_fetch_state (state, source_state_name, TRUE); target_state = clutter_state_fetch_state (state, target_state_name, TRUE); property_name = g_intern_string (property_name); state_key = clutter_state_key_new (target_state, object, property_name, pspec, mode); state_key->source_state = source_state; state_key->pre_delay = pre_delay; state_key->post_delay = post_delay; g_value_init (&state_key->value, G_VALUE_TYPE (value)); g_value_copy (value, &state_key->value); clutter_state_set_key_internal (state, state_key); return state; } /** * clutter_state_get_states: * @state: a #ClutterState instance. * * Gets a list of all the state names managed by this #ClutterState. * * Return value: (transfer container) (element-type utf8): a newly allocated * #GList of state names. The contents of the returned #GList are owned * by the #ClutterState and should not be modified or freed. Use * g_list_free() to free the resources allocated by the returned list when * done using it * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ GList * clutter_state_get_states (ClutterState *state) { g_return_val_if_fail (CLUTTER_IS_STATE (state), NULL); return g_hash_table_get_keys (state->priv->states); } /** * clutter_state_get_keys: * @state: a #ClutterState instance. * @source_state_name: (allow-none): the source transition name to query, * or %NULL for all source states * @target_state_name: (allow-none): the target transition name to query, * or %NULL for all target states * @object: (allow-none): the specific object instance to list keys for, * or %NULL for all managed objects * @property_name: (allow-none): the property name to search for, or %NULL * for all properties. * * Returns a list of pointers to opaque structures with accessor functions * that describe the keys added to an animator. * * Return value: (transfer container) (element-type Clutter.StateKey): a * newly allocated #GList of #ClutterStateKeys. The contents of * the returned list are owned by the #ClutterState and should not be * modified or freed. Use g_list_free() to free the resources allocated * by the returned list when done using it * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ GList * clutter_state_get_keys (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, GObject *object, const gchar *property_name) { GList *s, *state_list; GList *targets = NULL; State *source_state = NULL; g_return_val_if_fail (CLUTTER_IS_STATE (state), NULL); source_state_name = g_intern_string (source_state_name); target_state_name = g_intern_string (target_state_name); property_name = g_intern_string (property_name); if (target_state_name != NULL) state_list = g_list_append (NULL, (gpointer) target_state_name); else state_list = clutter_state_get_states (state); if (source_state_name) source_state = clutter_state_fetch_state (state, source_state_name, FALSE); for (s = state_list; s != NULL; s = s->next) { State *target_state; target_state = clutter_state_fetch_state (state, s->data, FALSE); if (target_state != NULL) { GList *k; for (k = target_state->keys; k; k = k->next) { ClutterStateKey *key = k->data; if ((object == NULL || (object == key->object)) && (source_state_name == NULL || source_state == key->source_state) && (property_name == NULL || (property_name == key->property_name))) { targets = g_list_prepend (targets, key); } } } } g_list_free (state_list); return g_list_reverse (targets); } /** * clutter_state_remove_key: * @state: a #ClutterState instance. * @source_state_name: (allow-none): the source state name to query, * or %NULL for all source states * @target_state_name: (allow-none): the target state name to query, * or %NULL for all target states * @object: (allow-none): the specific object instance to list keys for, * or %NULL for all managed objects * @property_name: (allow-none): the property name to search for, * or %NULL for all properties. * * Removes all keys matching the search criteria passed in arguments. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ void clutter_state_remove_key (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, GObject *object, const gchar *property_name) { g_return_if_fail (CLUTTER_IS_STATE (state)); clutter_state_remove_key_internal (state, source_state_name, target_state_name, object, property_name, FALSE); } /** * clutter_state_get_timeline: * @state: a #ClutterState * * Gets the timeline driving the #ClutterState * * Return value: (transfer none): the #ClutterTimeline that drives * the state change animations. The returned timeline is owned * by the #ClutterState and it should not be unreferenced directly * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ ClutterTimeline * clutter_state_get_timeline (ClutterState *state) { g_return_val_if_fail (CLUTTER_IS_STATE (state), NULL); return state->priv->timeline; } static void clutter_state_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterState *state = CLUTTER_STATE (object); switch (prop_id) { case PROP_STATE: clutter_state_set_state (state, g_value_get_string (value)); break; case PROP_DURATION: state->priv->duration = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clutter_state_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterState *state = CLUTTER_STATE (object); switch (prop_id) { case PROP_STATE: g_value_set_string (value, clutter_state_get_state (state)); break; case PROP_DURATION: g_value_set_uint (value, state->priv->duration); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clutter_state_class_init (ClutterStateClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->finalize = clutter_state_finalize; gobject_class->set_property = clutter_state_set_property; gobject_class->get_property = clutter_state_get_property; /** * ClutterState::completed: * @state: the #ClutterState that emitted the signal * * The ::completed signal is emitted when a #ClutterState reaches * the target state specified by clutter_state_set_state() or * clutter_state_warp_to_state(). * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ state_signals[COMPLETED] = g_signal_new (I_("completed"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterStateClass, completed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterState:state: * * The currently set target state, setting it causes the * state machine to transition to the new state, use * clutter_state_warp_to_state() to change state without * a transition. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ pspec = g_param_spec_string ("state", P_("State"), P_("Currently set state, (transition to this state might not be complete)"), NULL, CLUTTER_PARAM_READWRITE); obj_props[PROP_STATE] = pspec; g_object_class_install_property (gobject_class, PROP_STATE, pspec); /** * ClutterState:duration: * * Default duration used if an duration has not been specified for a specific * source/target state pair. The values is in milliseconds. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ pspec = g_param_spec_uint ("duration", P_("Duration"), P_("Default transition duration"), 0, 86400000, 1000, CLUTTER_PARAM_READWRITE); obj_props[PROP_DURATION] = pspec; g_object_class_install_property (gobject_class, PROP_DURATION, pspec); } static void clutter_state_init (ClutterState *self) { ClutterStatePrivate *priv; priv = self->priv = clutter_state_get_instance_private (self); priv->states = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, state_free); self->priv->source_state_name = NULL; self->priv->target_state_name = NULL; self->priv->duration = 1000; priv->timeline = clutter_timeline_new (1000); g_signal_connect (priv->timeline, "new-frame", G_CALLBACK (clutter_state_new_frame), self); g_signal_connect (priv->timeline, "completed", G_CALLBACK (clutter_state_completed), self); priv->slave_timeline = clutter_timeline_new (SLAVE_TIMELINE_LENGTH); } /** * clutter_state_get_animator: * @state: a #ClutterState instance. * @source_state_name: the name of a source state * @target_state_name: the name of a target state * * Retrieves the #ClutterAnimator that is being used for transitioning * between the two states, if any has been set * * Return value: (transfer none): a #ClutterAnimator instance, or %NULL * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ ClutterAnimator * clutter_state_get_animator (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name) { State *target_state; guint i; g_return_val_if_fail (CLUTTER_IS_STATE (state), NULL); source_state_name = g_intern_string (source_state_name); if (source_state_name == g_intern_static_string ("")) source_state_name = NULL; target_state_name = g_intern_string (target_state_name); target_state = clutter_state_fetch_state (state, target_state_name, FALSE); if (target_state == NULL) return NULL; for (i = 0; i < target_state->animators->len; i++) { const StateAnimator *animator; animator = &g_array_index (target_state->animators, StateAnimator, i); if (animator->source_state_name == source_state_name) return animator->animator; } return NULL; } /** * clutter_state_set_animator: * @state: a #ClutterState instance. * @source_state_name: the name of a source state * @target_state_name: the name of a target state * @animator: (allow-none): a #ClutterAnimator instance, or %NULL to * unset an existing #ClutterAnimator * * Specifies a #ClutterAnimator to be used when transitioning between * the two named states. * * The @animator allows specifying a transition between the state that is * more elaborate than the basic transitions allowed by the tweening of * properties defined in the #ClutterState keys. * * If @animator is %NULL it will unset an existing animator. * * #ClutterState will take a reference on the passed @animator, if any * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ void clutter_state_set_animator (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, ClutterAnimator *animator) { State *target_state; guint i; g_return_if_fail (CLUTTER_IS_STATE (state)); source_state_name = g_intern_string (source_state_name); target_state_name = g_intern_string (target_state_name); target_state = clutter_state_fetch_state (state, target_state_name, TRUE); if (target_state == NULL) return; for (i = 0; target_state->animators->len; i++) { StateAnimator *a; a = &g_array_index (target_state->animators, StateAnimator, i); if (a->source_state_name == source_state_name) { g_object_unref (a->animator); if (animator != NULL) a->animator = g_object_ref (animator); else { /* remove the matched animator if passed NULL */ g_array_remove_index (target_state->animators, i); } return; } } if (animator != NULL) { StateAnimator state_animator = { source_state_name, g_object_ref (animator) }; g_array_append_val (target_state->animators, state_animator); } } static gpointer clutter_state_key_copy (gpointer boxed) { if (boxed != NULL) { ClutterStateKey *key = boxed; key->ref_count += 1; } return boxed; } G_DEFINE_BOXED_TYPE (ClutterStateKey, clutter_state_key, clutter_state_key_copy, clutter_state_key_free); /** * clutter_state_key_get_pre_delay: * @state_key: a #ClutterStateKey * * Retrieves the pause before transitioning starts as a fraction of * the total transition time. * * Return value: the pre delay used before starting the transition. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ gdouble clutter_state_key_get_pre_delay (const ClutterStateKey *state_key) { g_return_val_if_fail (state_key != NULL, 0.0); return state_key->pre_delay; } /** * clutter_state_key_get_post_delay: * @state_key: a #ClutterStateKey * * Retrieves the duration of the pause after transitioning is complete * as a fraction of the total transition time. * * Return value: the post delay, used after doing the transition. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ gdouble clutter_state_key_get_post_delay (const ClutterStateKey *state_key) { g_return_val_if_fail (state_key != NULL, 0.0); return state_key->post_delay; } /** * clutter_state_key_get_mode: * @state_key: a #ClutterStateKey * * Retrieves the easing mode used for @state_key. * * Return value: the mode of a #ClutterStateKey * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ gulong clutter_state_key_get_mode (const ClutterStateKey *state_key) { g_return_val_if_fail (state_key != NULL, 0); return state_key->mode; } /** * clutter_state_key_get_value: * @state_key: a #ClutterStateKey * @value: a #GValue initialized with the correct type for the @state_key * * Retrieves a copy of the value for a #ClutterStateKey. * * The #GValue needs to be already initialized for the value type * of the property or to a type that allow transformation from the value * type of the key. * * Use g_value_unset() when done. * * Return value: %TRUE if the value was successfully retrieved, * and %FALSE otherwise * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ gboolean clutter_state_key_get_value (const ClutterStateKey *state_key, GValue *value) { g_return_val_if_fail (state_key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (G_VALUE_TYPE (value) != G_TYPE_INVALID, FALSE); if (!g_type_is_a (G_VALUE_TYPE (&state_key->value), G_VALUE_TYPE (value))) { if (g_value_type_compatible (G_VALUE_TYPE (&state_key->value), G_VALUE_TYPE (value))) { g_value_copy (&state_key->value, value); return TRUE; } if (g_value_type_transformable (G_VALUE_TYPE (&state_key->value), G_VALUE_TYPE (value))) { if (g_value_transform (&state_key->value, value)) return TRUE; } g_warning ("%s: Unable to convert from %s to %s for the " "property '%s' of object %s in the state key", G_STRLOC, g_type_name (G_VALUE_TYPE (&state_key->value)), g_type_name (G_VALUE_TYPE (value)), state_key->property_name, G_OBJECT_TYPE_NAME (state_key->object)); return FALSE; } else g_value_copy (&state_key->value, value); return TRUE; } /** * clutter_state_key_get_object: * @state_key: a #ClutterStateKey * * Retrieves the object instance this #ClutterStateKey applies to. * * Return value: (transfer none): the object this state key applies to. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ GObject * clutter_state_key_get_object (const ClutterStateKey *state_key) { g_return_val_if_fail (state_key, NULL); return state_key->object; } /** * clutter_state_key_get_property_name: * @state_key: a #ClutterStateKey * * Retrieves the name of the property this #ClutterStateKey applies to * * Return value: the name of the property. The returned string is owned * by the #ClutterStateKey and should never be modified or freed * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ const gchar * clutter_state_key_get_property_name (const ClutterStateKey *state_key) { g_return_val_if_fail (state_key, NULL); return state_key->property_name; } /** * clutter_state_key_get_source_state_name: * @state_key: a #ClutterStateKey * * Retrieves the name of the source state of the @state_key * * Return value: the name of the source state for this key, or %NULL * if this is the generic state key for the given property when * transitioning to the target state. The returned string is owned * by the #ClutterStateKey and should never be modified or freed * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ const gchar * clutter_state_key_get_source_state_name (const ClutterStateKey *state_key) { g_return_val_if_fail (state_key, NULL); if (state_key->source_state != NULL) return state_key->source_state->name; return NULL; } /** * clutter_state_key_get_target_state_name: * @state_key: a #ClutterStateKey * * Get the name of the source state this #ClutterStateKey contains, * or NULL if this is the generic state key for the given property * when transitioning to the target state. * * Return value: the name of the source state for this key, or NULL if * the key is generic * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ const gchar * clutter_state_key_get_target_state_name (const ClutterStateKey *state_key) { g_return_val_if_fail (state_key, NULL); return state_key->target_state->name; } /** * clutter_state_key_get_property_type: * @key: a #ClutterStateKey * * Retrieves the #GType of the property a key applies to * * You can use this type to initialize the #GValue to pass to * clutter_state_key_get_value() * * Return value: the #GType of the property * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ GType clutter_state_key_get_property_type (const ClutterStateKey *key) { g_return_val_if_fail (key != NULL, G_TYPE_INVALID); return G_VALUE_TYPE (&key->value); } /** * clutter_state_set_duration: * @state: a #ClutterState * @source_state_name: (allow-none): the name of the source state, or %NULL * @target_state_name: (allow-none): the name of the target state, or %NULL * @duration: the duration of the transition, in milliseconds * * Sets the duration of a transition. * * If both state names are %NULL the default duration for @state is set. * * If only @target_state_name is specified, the passed @duration becomes * the default duration for transitions to the target state. * * If both states names are specified, the passed @duration only applies * to the specified transition. * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ void clutter_state_set_duration (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, guint duration) { State *target_state; g_return_if_fail (CLUTTER_IS_STATE (state)); source_state_name = g_intern_string (source_state_name); if (source_state_name == g_intern_static_string ("")) source_state_name = NULL; target_state_name = g_intern_string (target_state_name); if (target_state_name == g_intern_static_string ("")) target_state_name = NULL; if (target_state_name == NULL) { state->priv->duration = duration; return; } target_state = clutter_state_fetch_state (state, target_state_name, FALSE); if (target_state != NULL) { if (source_state_name != NULL) g_hash_table_insert (target_state->durations, (gpointer) source_state_name, GINT_TO_POINTER (duration)); else g_hash_table_insert (target_state->durations, NULL, GINT_TO_POINTER (duration)); } } /** * clutter_state_get_duration: * @state: a #ClutterState * @source_state_name: (allow-none): the name of the source state to * get the duration of, or %NULL * @target_state_name: (allow-none): the name of the source state to * get the duration of, or %NULL * * Queries the duration used for transitions between a source and * target state pair * * The semantics for the query are the same as the semantics used for * setting the duration with clutter_state_set_duration() * * Return value: the duration, in milliseconds * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ guint clutter_state_get_duration (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name) { State *target_state; guint ret = 0; g_return_val_if_fail (CLUTTER_IS_STATE (state), 0); source_state_name = g_intern_string (source_state_name); if (source_state_name == g_intern_static_string ("")) source_state_name = NULL; target_state_name = g_intern_string (target_state_name); if (target_state_name == g_intern_static_string ("")) target_state_name = NULL; if (target_state_name == NULL) return state->priv->duration; target_state = clutter_state_fetch_state (state, target_state_name, FALSE); if (target_state != NULL) { if (source_state_name) { ret = GPOINTER_TO_INT (g_hash_table_lookup (target_state->durations, source_state_name)); if(!ret) ret = GPOINTER_TO_INT (g_hash_table_lookup (target_state->durations, NULL)); } else ret = GPOINTER_TO_INT (g_hash_table_lookup (target_state->durations, NULL)); } if (!ret) ret = state->priv->duration; return ret; } /** * clutter_state_get_state: * @state: a #ClutterState * * Queries the currently set target state. * * During a transition this function will return the target of the transition. * * This function is useful when called from handlers of the * #ClutterState::completed signal. * * Return value: a string containing the target state. The returned string * is owned by the #ClutterState and should not be modified or freed * * Since: 1.4 * Deprecated: 1.12: Use #ClutterKeyframeTransition and * #ClutterTransitionGroup instead */ const gchar * clutter_state_get_state (ClutterState *state) { g_return_val_if_fail (CLUTTER_IS_STATE (state), NULL); return state->priv->target_state_name; } typedef struct _ParseClosure { ClutterState *state; ClutterScript *script; GValue *value; gboolean result; } ParseClosure; static void parse_state_transition (JsonArray *array, guint index_, JsonNode *element, gpointer data) { ParseClosure *clos = data; JsonObject *object; const gchar *source_name, *target_name; State *source_state, *target_state; JsonArray *keys; GSList *valid_keys = NULL; GList *array_keys, *k; if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT) { g_warning ("The 'transitions' member of a ClutterState description " "should be an array of objects, but the element %d of the " "array is of type '%s'. The element will be ignored.", index_, json_node_type_name (element)); return; } object = json_node_get_object (element); if (!json_object_has_member (object, "source") || !json_object_has_member (object, "target") || !(json_object_has_member (object, "keys") || json_object_has_member (object, "animator"))) { g_warning ("The transition description at index %d is missing one " "of the mandatory members: source, target and keys or " "animator", index_); return; } source_name = json_object_get_string_member (object, "source"); source_state = clutter_state_fetch_state (clos->state, source_name, TRUE); target_name = json_object_get_string_member (object, "target"); target_state = clutter_state_fetch_state (clos->state, target_name, TRUE); if (json_object_has_member (object, "duration")) { guint duration = json_object_get_int_member (object, "duration"); clutter_state_set_duration (clos->state, source_name, target_name, duration); } if (json_object_has_member (object, "animator")) { const gchar *id_ = json_object_get_string_member (object, "animator"); GObject *animator; animator = clutter_script_get_object (clos->script, id_); if (animator == NULL) { g_warning ("No object with id '%s' has been defined.", id_); return; } clutter_state_set_animator (clos->state, source_name, target_name, CLUTTER_ANIMATOR (animator)); } if (!json_object_has_member (object, "keys")) return; keys = json_object_get_array_member (object, "keys"); if (keys == NULL && !json_object_has_member (object, "animator")) { g_warning ("The transition description at index %d has an invalid " "key member of type '%s' when an array was expected.", index_, json_node_type_name (json_object_get_member (object, "keys"))); return; } if (G_IS_VALUE (clos->value)) valid_keys = g_slist_reverse (g_value_get_pointer (clos->value)); else g_value_init (clos->value, G_TYPE_POINTER); array_keys = json_array_get_elements (keys); for (k = array_keys; k != NULL; k = k->next) { JsonNode *node = k->data; JsonArray *key = json_node_get_array (node); ClutterStateKey *state_key; GObject *gobject; GParamSpec *pspec; const gchar *id_; const gchar *property; gulong mode; gboolean res; id_ = json_array_get_string_element (key, 0); gobject = clutter_script_get_object (clos->script, id_); if (gobject == NULL) { g_warning ("No object with id '%s' has been defined.", id_); continue; } property = json_array_get_string_element (key, 1); pspec = get_property_from_object (gobject, property); if (pspec == NULL) { g_warning ("The object of type '%s' and name '%s' has no " "property named '%s'.", G_OBJECT_TYPE_NAME (gobject), id_, property); continue; } mode = _clutter_script_resolve_animation_mode (json_array_get_element (key, 2)); state_key = clutter_state_key_new (target_state, gobject, property, pspec, mode); res = _clutter_script_parse_node (clos->script, &(state_key->value), property, json_array_get_element (key, 3), pspec); if (!res) { g_warning ("Unable to parse the key value for the " "property '%s' of object '%s' at index %d", property, id_, index_); clutter_state_key_free (state_key); continue; } switch (json_array_get_length (key)) { case 5: state_key->pre_delay = json_array_get_double_element (key, 4); state_key->post_delay = 0.0; break; case 6: state_key->pre_delay = json_array_get_double_element (key, 4); state_key->post_delay = json_array_get_double_element (key, 5); break; default: state_key->pre_delay = 0.0; state_key->post_delay = 0.0; break; } state_key->source_state = source_state; valid_keys = g_slist_prepend (valid_keys, state_key); } g_list_free (array_keys); g_value_set_pointer (clos->value, g_slist_reverse (valid_keys)); clos->result = TRUE; } static gboolean clutter_state_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { ParseClosure clos; if (strcmp (name, "transitions") != 0) return FALSE; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) return FALSE; clos.state = CLUTTER_STATE (scriptable); clos.script = script; clos.value = value; clos.result = FALSE; json_array_foreach_element (json_node_get_array (node), parse_state_transition, &clos); return clos.result; } static void clutter_state_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { if (strcmp (name, "transitions") == 0) { ClutterState *state = CLUTTER_STATE (scriptable); GSList *keys = g_value_get_pointer (value); GSList *k; for (k = keys; k != NULL; k = k->next) clutter_state_set_key_internal (state, k->data); g_slist_free (keys); } else g_object_set_property (G_OBJECT (scriptable), name, value); } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_state_parse_custom_node; iface->set_custom_property = clutter_state_set_custom_property; } muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-ellipse.h0000664000175000017500000001365514211404421025662 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Tomas Frydrych * * 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BEHAVIOUR_ELLIPSE_H__ #define __CLUTTER_BEHAVIOUR_ELLIPSE_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_BEHAVIOUR_ELLIPSE (clutter_behaviour_ellipse_get_type ()) #define CLUTTER_BEHAVIOUR_ELLIPSE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ CLUTTER_TYPE_BEHAVIOUR_ELLIPSE, ClutterBehaviourEllipse)) #define CLUTTER_BEHAVIOUR_ELLIPSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ CLUTTER_TYPE_BEHAVIOUR_ELLIPSE, ClutterBehaviourEllipseClass)) #define CLUTTER_IS_BEHAVIOUR_ELLIPSE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ CLUTTER_TYPE_BEHAVIOUR_ELLIPSE)) #define CLUTTER_IS_BEHAVIOUR_ELLIPSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ CLUTTER_TYPE_BEHAVIOUR_ELLIPSE)) #define CLUTTER_BEHAVIOUR_ELLIPSE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ CLUTTER_TYPE_BEHAVIOUR_ELLIPSE, ClutterBehaviourEllipseClass)) typedef struct _ClutterBehaviourEllipse ClutterBehaviourEllipse; typedef struct _ClutterBehaviourEllipsePrivate ClutterBehaviourEllipsePrivate; typedef struct _ClutterBehaviourEllipseClass ClutterBehaviourEllipseClass; /** * ClutterBehaviourEllipse: * * The #ClutterBehaviourEllipse struct contains only private data * and should be accessed using the provided API * * Since: 0.4 * * Deprecated: 1.6 */ struct _ClutterBehaviourEllipse { /*< private >*/ ClutterBehaviour parent_instance; ClutterBehaviourEllipsePrivate *priv; }; /** * ClutterBehaviourEllipseClass: * * The #ClutterBehaviourEllipseClass struct contains only private data * * Since: 0.4 * * Deprecated: 1.6 */ struct _ClutterBehaviourEllipseClass { /*< private >*/ ClutterBehaviourClass parent_class; }; CLUTTER_DEPRECATED_IN_1_8 GType clutter_behaviour_ellipse_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_actor_animate) ClutterBehaviour * clutter_behaviour_ellipse_new (ClutterAlpha *alpha, gint x, gint y, gint width, gint height, ClutterRotateDirection direction, gdouble start, gdouble end); CLUTTER_DEPRECATED_IN_1_8 void clutter_behaviour_ellipse_set_center (ClutterBehaviourEllipse *self, gint x, gint y); CLUTTER_DEPRECATED_IN_1_8 void clutter_behaviour_ellipse_get_center (ClutterBehaviourEllipse *self, gint *x, gint *y); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_set_width (ClutterBehaviourEllipse *self, gint width); CLUTTER_DEPRECATED_IN_1_6 gint clutter_behaviour_ellipse_get_width (ClutterBehaviourEllipse *self); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_set_height (ClutterBehaviourEllipse *self, gint height); CLUTTER_DEPRECATED_IN_1_6 gint clutter_behaviour_ellipse_get_height (ClutterBehaviourEllipse *self); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_set_angle_start (ClutterBehaviourEllipse *self, gdouble angle_start); CLUTTER_DEPRECATED_IN_1_6 gdouble clutter_behaviour_ellipse_get_angle_start (ClutterBehaviourEllipse *self); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_set_angle_end (ClutterBehaviourEllipse *self, gdouble angle_end); CLUTTER_DEPRECATED_IN_1_6 gdouble clutter_behaviour_ellipse_get_angle_end (ClutterBehaviourEllipse *self); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_set_angle_tilt (ClutterBehaviourEllipse *self, ClutterRotateAxis axis, gdouble angle_tilt); CLUTTER_DEPRECATED_IN_1_6 gdouble clutter_behaviour_ellipse_get_angle_tilt (ClutterBehaviourEllipse *self, ClutterRotateAxis axis); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_set_tilt (ClutterBehaviourEllipse *self, gdouble angle_tilt_x, gdouble angle_tilt_y, gdouble angle_tilt_z); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_get_tilt (ClutterBehaviourEllipse *self, gdouble *angle_tilt_x, gdouble *angle_tilt_y, gdouble *angle_tilt_z); CLUTTER_DEPRECATED_IN_1_6 ClutterRotateDirection clutter_behaviour_ellipse_get_direction (ClutterBehaviourEllipse *self); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_ellipse_set_direction (ClutterBehaviourEllipse *self, ClutterRotateDirection direction); G_END_DECLS #endif /* __CLUTTER_BEHAVIOUR_ELLIPSE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-state.h0000664000175000017500000001774114211404421023363 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Øyvind Kolås * * Copyright (C) 2009 Intel Corporation * * 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, see . */ #ifndef __CLUTTER_STATE_H__ #define __CLUTTER_STATE_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_STATE_KEY (clutter_state_key_get_type ()) #define CLUTTER_TYPE_STATE (clutter_state_get_type ()) #define CLUTTER_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STATE, ClutterState)) #define CLUTTER_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STATE, ClutterStateClass)) #define CLUTTER_IS_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STATE)) #define CLUTTER_IS_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STATE)) #define CLUTTER_STATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STATE, ClutterStateClass)) typedef struct _ClutterStatePrivate ClutterStatePrivate; typedef struct _ClutterStateClass ClutterStateClass; /** * ClutterStateKey: * * #ClutterStateKey is an opaque structure whose * members cannot be accessed directly * * Since: 1.4 */ typedef struct _ClutterStateKey ClutterStateKey; /** * ClutterState: * * The #ClutterState structure contains only * private data and should be accessed using the provided API * * Since: 1.4 */ struct _ClutterState { /*< private >*/ GObject parent; ClutterStatePrivate *priv; }; /** * ClutterStateClass: * @completed: class handler for the #ClutterState::completed signal * * The #ClutterStateClass structure contains * only private data * * Since: 1.4 * * Deprecated: 1.12 */ struct _ClutterStateClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ void (* completed) (ClutterState *state); /*< private >*/ /* padding for future expansion */ gpointer _padding_dummy[8]; }; CLUTTER_DEPRECATED_IN_1_12 GType clutter_state_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12 ClutterState *clutter_state_new (void); CLUTTER_DEPRECATED_IN_1_12 ClutterTimeline * clutter_state_set_state (ClutterState *state, const gchar *target_state_name); CLUTTER_DEPRECATED_IN_1_12 ClutterTimeline * clutter_state_warp_to_state (ClutterState *state, const gchar *target_state_name); CLUTTER_DEPRECATED_IN_1_12 ClutterState * clutter_state_set_key (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, GObject *object, const gchar *property_name, guint mode, const GValue *value, gdouble pre_delay, gdouble post_delay); CLUTTER_DEPRECATED_IN_1_12 void clutter_state_set_duration (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, guint duration); CLUTTER_DEPRECATED_IN_1_12 guint clutter_state_get_duration (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name); CLUTTER_DEPRECATED_IN_1_12 void clutter_state_set (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, gpointer first_object, const gchar *first_property_name, gulong first_mode, ...) G_GNUC_NULL_TERMINATED; CLUTTER_DEPRECATED_IN_1_12 GList * clutter_state_get_states (ClutterState *state); CLUTTER_DEPRECATED_IN_1_12 GList * clutter_state_get_keys (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, GObject *object, const gchar *property_name); CLUTTER_DEPRECATED_IN_1_12 void clutter_state_remove_key (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, GObject *object, const gchar *property_name); CLUTTER_DEPRECATED_IN_1_12 ClutterTimeline * clutter_state_get_timeline (ClutterState *state); CLUTTER_DEPRECATED_IN_1_12 void clutter_state_set_animator (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name, ClutterAnimator *animator); CLUTTER_DEPRECATED_IN_1_12 ClutterAnimator * clutter_state_get_animator (ClutterState *state, const gchar *source_state_name, const gchar *target_state_name); CLUTTER_DEPRECATED_IN_1_12 const gchar * clutter_state_get_state (ClutterState *state); /* * ClutterStateKey */ CLUTTER_DEPRECATED_IN_1_12 GType clutter_state_key_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_state_key_get_pre_delay (const ClutterStateKey *state_key); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_state_key_get_post_delay (const ClutterStateKey *state_key); CLUTTER_DEPRECATED_IN_1_12 gulong clutter_state_key_get_mode (const ClutterStateKey *state_key); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_state_key_get_value (const ClutterStateKey *state_key, GValue *value); CLUTTER_DEPRECATED_IN_1_12 GType clutter_state_key_get_property_type (const ClutterStateKey *key); CLUTTER_DEPRECATED_IN_1_12 GObject * clutter_state_key_get_object (const ClutterStateKey *state_key); CLUTTER_DEPRECATED_IN_1_12 const gchar * clutter_state_key_get_property_name (const ClutterStateKey *state_key); CLUTTER_DEPRECATED_IN_1_12 const gchar * clutter_state_key_get_source_state_name (const ClutterStateKey *state_key); CLUTTER_DEPRECATED_IN_1_12 const gchar * clutter_state_key_get_target_state_name (const ClutterStateKey *state_key); G_END_DECLS #endif /* __CLUTTER_STATE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-timeout-interval.c0000664000175000017500000000772714211404421025551 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Neil Roberts * * Copyright (C) 2009 Intel Corporation. * * 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, see . */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS /* This file contains the common code to check whether an interval has expired used in clutter-frame-source and clutter-timeout-pool. */ #include "clutter-timeout-interval.h" void _clutter_timeout_interval_init (ClutterTimeoutInterval *interval, guint fps) { #if GLIB_CHECK_VERSION (2, 27, 3) interval->start_time = g_get_monotonic_time () / 1000; #else { GTimeVal start_time; g_get_current_time (&start_time); interval->start_time = start_time.tv_sec * 1000 + start_time.tv_usec / 1000; } #endif interval->fps = fps; interval->frame_count = 0; } static gint64 _clutter_timeout_interval_get_ticks (gint64 current_time, ClutterTimeoutInterval *interval) { return MAX (current_time - interval->start_time, 0); } gboolean _clutter_timeout_interval_prepare (gint64 current_time, ClutterTimeoutInterval *interval, gint *delay) { gint elapsed_time, new_frame_num; elapsed_time = _clutter_timeout_interval_get_ticks (current_time, interval); new_frame_num = elapsed_time * interval->fps / 1000; /* If time has gone backwards or the time since the last frame is greater than the two frames worth then reset the time and do a frame now */ if (new_frame_num < interval->frame_count || new_frame_num - interval->frame_count > 2) { /* Get the frame time rounded up to the nearest ms */ guint frame_time = (1000 + interval->fps - 1) / interval->fps; /* Reset the start time */ interval->start_time = current_time; /* Move the start time as if one whole frame has elapsed */ interval->start_time -= frame_time; interval->frame_count = 0; if (delay) *delay = 0; return TRUE; } else if (new_frame_num > interval->frame_count) { if (delay) *delay = 0; return TRUE; } else { if (delay) *delay = ((interval->frame_count + 1) * 1000 / interval->fps - elapsed_time); return FALSE; } } gboolean _clutter_timeout_interval_dispatch (ClutterTimeoutInterval *interval, GSourceFunc callback, gpointer user_data) { if ((* callback) (user_data)) { interval->frame_count++; return TRUE; } return FALSE; } gint _clutter_timeout_interval_compare_expiration (const ClutterTimeoutInterval *a, const ClutterTimeoutInterval *b) { guint a_delay = 1000 / a->fps; guint b_delay = 1000 / b->fps; gint64 b_difference; gint comparison; b_difference = a->start_time - b->start_time; comparison = ((gint) ((a->frame_count + 1) * a_delay) - (gint) ((b->frame_count + 1) * b_delay + b_difference)); return (comparison < 0 ? -1 : comparison > 0 ? 1 : 0); } muffin-5.2.1/clutter/clutter/deprecated/clutter-rectangle.h0000664000175000017500000001006414211404421024176 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_RECTANGLE_H__ #define __CLUTTER_RECTANGLE_H__ #include #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_RECTANGLE (clutter_rectangle_get_type()) #define CLUTTER_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_RECTANGLE, ClutterRectangle)) #define CLUTTER_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_RECTANGLE, ClutterRectangleClass)) #define CLUTTER_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_RECTANGLE)) #define CLUTTER_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_RECTANGLE)) #define CLUTTER_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_RECTANGLE, ClutterRectangleClass)) typedef struct _ClutterRectangle ClutterRectangle; typedef struct _ClutterRectangleClass ClutterRectangleClass; typedef struct _ClutterRectanglePrivate ClutterRectanglePrivate; /** * ClutterRectangle: * * The #ClutterRectangle structure contains only private data * and should be accessed using the provided API * * Since: 0.2 */ struct _ClutterRectangle { /*< private >*/ ClutterActor parent; ClutterRectanglePrivate *priv; }; /** * ClutterRectangleClass: * * The #ClutterRectangleClass structure contains only private data * * Since: 0.2 */ struct _ClutterRectangleClass { /*< private >*/ ClutterActorClass parent_class; /* padding for future expansion */ void (*_clutter_rectangle1) (void); void (*_clutter_rectangle2) (void); void (*_clutter_rectangle3) (void); void (*_clutter_rectangle4) (void); }; CLUTTER_DEPRECATED_IN_1_10 GType clutter_rectangle_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_new) ClutterActor *clutter_rectangle_new (void); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_new) ClutterActor *clutter_rectangle_new_with_color (const ClutterColor *color); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_background_color) void clutter_rectangle_get_color (ClutterRectangle *rectangle, ClutterColor *color); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_background_color) void clutter_rectangle_set_color (ClutterRectangle *rectangle, const ClutterColor *color); CLUTTER_DEPRECATED_IN_1_10 guint clutter_rectangle_get_border_width (ClutterRectangle *rectangle); CLUTTER_DEPRECATED_IN_1_10 void clutter_rectangle_set_border_width (ClutterRectangle *rectangle, guint width); CLUTTER_DEPRECATED_IN_1_10 void clutter_rectangle_get_border_color (ClutterRectangle *rectangle, ClutterColor *color); CLUTTER_DEPRECATED_IN_1_10 void clutter_rectangle_set_border_color (ClutterRectangle *rectangle, const ClutterColor *color); G_END_DECLS #endif /* __CLUTTER_RECTANGLE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-timeout-interval.h0000664000175000017500000000407314211404421025545 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Neil Roberts * * Copyright (C) 2009 Intel Corporation. * * 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, see . */ #ifndef __CLUTTER_TIMEOUT_INTERVAL_H__ #define __CLUTTER_TIMEOUT_INTERVAL_H__ #include G_BEGIN_DECLS typedef struct _ClutterTimeoutInterval ClutterTimeoutInterval; struct _ClutterTimeoutInterval { /* milliseconds */ gint64 start_time; guint frame_count; guint fps; }; void _clutter_timeout_interval_init (ClutterTimeoutInterval *interval, guint fps); gboolean _clutter_timeout_interval_prepare (gint64 current_time, ClutterTimeoutInterval *interval, gint *delay); gboolean _clutter_timeout_interval_dispatch (ClutterTimeoutInterval *interval, GSourceFunc callback, gpointer user_data); gint _clutter_timeout_interval_compare_expiration (const ClutterTimeoutInterval *a, const ClutterTimeoutInterval *b); G_END_DECLS #endif /* __CLUTTER_TIMEOUT_INTERVAL_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-rotate.c0000664000175000017500000004460414211404421025514 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * 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, see . */ /** * SECTION:clutter-behaviour-rotate * @short_description: A behaviour controlling rotation * * A #ClutterBehaviourRotate rotate actors between a starting and ending * angle on a given axis. * * The #ClutterBehaviourRotate is available since version 0.4. * * Deprecated: 1.6: Use the #ClutterActor rotation properties and * clutter_actor_animate(), or #ClutterAnimator, or #ClutterState * instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-actor.h" #include "clutter-alpha.h" #include "clutter-behaviour.h" #include "clutter-behaviour-rotate.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-main.h" #include "clutter-private.h" struct _ClutterBehaviourRotatePrivate { gdouble angle_start; gdouble angle_end; ClutterRotateAxis axis; ClutterRotateDirection direction; gint center_x; gint center_y; gint center_z; }; enum { PROP_0, PROP_ANGLE_START, PROP_ANGLE_END, PROP_AXIS, PROP_DIRECTION, PROP_CENTER_X, PROP_CENTER_Y, PROP_CENTER_Z, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE (ClutterBehaviourRotate, clutter_behaviour_rotate, CLUTTER_TYPE_BEHAVIOUR) typedef struct { gdouble angle; } RotateFrameClosure; static void alpha_notify_foreach (ClutterBehaviour *behaviour, ClutterActor *actor, gpointer data) { RotateFrameClosure *closure = data; ClutterBehaviourRotate *rotate_behaviour; ClutterBehaviourRotatePrivate *priv; rotate_behaviour = CLUTTER_BEHAVIOUR_ROTATE (behaviour); priv = rotate_behaviour->priv; clutter_actor_set_rotation (actor, priv->axis, closure->angle, priv->center_x, priv->center_y, priv->center_z); } static inline float clamp_angle (float a) { float a1, a2; gint rounds; rounds = a / 360.0; a1 = rounds * 360.0; a2 = a - a1; return a2; } static void clutter_behaviour_rotate_alpha_notify (ClutterBehaviour *behaviour, gdouble alpha_value) { ClutterBehaviourRotate *rotate_behaviour; ClutterBehaviourRotatePrivate *priv; RotateFrameClosure closure; gdouble start, end; rotate_behaviour = CLUTTER_BEHAVIOUR_ROTATE (behaviour); priv = rotate_behaviour->priv; closure.angle = 0; start = priv->angle_start; end = priv->angle_end; if (priv->direction == CLUTTER_ROTATE_CW && start >= end) end += 360.0; else if (priv->direction == CLUTTER_ROTATE_CCW && start <= end) end -= 360.0; closure.angle = (end - start) * alpha_value + start; clutter_behaviour_actors_foreach (behaviour, alpha_notify_foreach, &closure); } static void clutter_behaviour_rotate_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBehaviourRotate *rotate; ClutterBehaviourRotatePrivate *priv; rotate = CLUTTER_BEHAVIOUR_ROTATE (gobject); priv = rotate->priv; switch (prop_id) { case PROP_ANGLE_START: priv->angle_start = g_value_get_double (value); break; case PROP_ANGLE_END: priv->angle_end = g_value_get_double (value); break; case PROP_AXIS: priv->axis = g_value_get_enum (value); break; case PROP_DIRECTION: priv->direction = g_value_get_enum (value); break; case PROP_CENTER_X: clutter_behaviour_rotate_set_center (rotate, g_value_get_int (value), priv->center_y, priv->center_z); break; case PROP_CENTER_Y: clutter_behaviour_rotate_set_center (rotate, priv->center_x, g_value_get_int (value), priv->center_z); break; case PROP_CENTER_Z: clutter_behaviour_rotate_set_center (rotate, priv->center_x, priv->center_y, g_value_get_int (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_rotate_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBehaviourRotatePrivate *priv; priv = CLUTTER_BEHAVIOUR_ROTATE (gobject)->priv; switch (prop_id) { case PROP_ANGLE_START: g_value_set_double (value, priv->angle_start); break; case PROP_ANGLE_END: g_value_set_double (value, priv->angle_end); break; case PROP_AXIS: g_value_set_enum (value, priv->axis); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; case PROP_CENTER_X: g_value_set_int (value, priv->center_x); break; case PROP_CENTER_Y: g_value_set_int (value, priv->center_y); break; case PROP_CENTER_Z: g_value_set_int (value, priv->center_z); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_rotate_class_init (ClutterBehaviourRotateClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBehaviourClass *behaviour_class = CLUTTER_BEHAVIOUR_CLASS (klass); GParamSpec *pspec = NULL; gobject_class->set_property = clutter_behaviour_rotate_set_property; gobject_class->get_property = clutter_behaviour_rotate_get_property; behaviour_class->alpha_notify = clutter_behaviour_rotate_alpha_notify; /** * ClutterBehaviourRotate:angle-start: * * The initial angle from whence the rotation should start. * * Since: 0.4 */ pspec = g_param_spec_double ("angle-start", P_("Angle Begin"), P_("Initial angle"), 0.0, 360.0, 0.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE_START] = pspec; g_object_class_install_property (gobject_class, PROP_ANGLE_START, pspec); /** * ClutterBehaviourRotate:angle-end: * * The final angle to where the rotation should end. * * Since: 0.4 */ pspec = g_param_spec_double ("angle-end", P_("Angle End"), P_("Final angle"), 0.0, 360.0, 0.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE_END] = pspec; g_object_class_install_property (gobject_class, PROP_ANGLE_END, pspec); /** * ClutterBehaviourRotate:axis: * * The axis of rotation. * * Since: 0.4 */ pspec = g_param_spec_enum ("axis", P_("Axis"), P_("Axis of rotation"), CLUTTER_TYPE_ROTATE_AXIS, CLUTTER_Z_AXIS, CLUTTER_PARAM_READWRITE); obj_props[PROP_AXIS] = pspec; g_object_class_install_property (gobject_class, PROP_AXIS, pspec); /** * ClutterBehaviourRotate:direction: * * The direction of the rotation. * * Since: 0.4 */ pspec = g_param_spec_enum ("direction", P_("Direction"), P_("Direction of rotation"), CLUTTER_TYPE_ROTATE_DIRECTION, CLUTTER_ROTATE_CW, CLUTTER_PARAM_READWRITE); obj_props[PROP_DIRECTION] = pspec; g_object_class_install_property (gobject_class, PROP_DIRECTION, pspec); /** * ClutterBehaviourRotate:center-x: * * The x center of rotation. * * Since: 0.4 */ pspec = g_param_spec_int ("center-x", P_("Center X"), P_("X coordinate of the center of rotation"), -G_MAXINT, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_CENTER_X] = pspec; g_object_class_install_property (gobject_class, PROP_CENTER_X, pspec); /** * ClutterBehaviourRotate:center-y: * * The y center of rotation. * * Since: 0.4 */ pspec = g_param_spec_int ("center-y", P_("Center Y"), P_("Y coordinate of the center of rotation"), -G_MAXINT, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_CENTER_Y] = pspec; g_object_class_install_property (gobject_class, PROP_CENTER_Y, pspec); /** * ClutterBehaviourRotate:center-z: * * The z center of rotation. * * Since: 0.4 */ pspec = g_param_spec_int ("center-z", P_("Center Z"), P_("Z coordinate of the center of rotation"), -G_MAXINT, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_CENTER_Z] = pspec; g_object_class_install_property (gobject_class, PROP_CENTER_Z, pspec); } static void clutter_behaviour_rotate_init (ClutterBehaviourRotate *self) { self->priv = clutter_behaviour_rotate_get_instance_private (self); self->priv->angle_start = 0.0; self->priv->angle_end = 0.0; self->priv->axis = CLUTTER_Z_AXIS; self->priv->direction = CLUTTER_ROTATE_CW; self->priv->center_x = 0; self->priv->center_y = 0; self->priv->center_z = 0; } /** * clutter_behaviour_rotate_new: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @axis: the rotation axis * @direction: the rotation direction * @angle_start: the starting angle in degrees, between 0 and 360. * @angle_end: the final angle in degrees, between 0 and 360. * * Creates a new #ClutterBehaviourRotate. This behaviour will rotate actors * bound to it on @axis, following @direction, between @angle_start and * @angle_end. Angles >= 360 degrees will be clamped to the canonical interval * <0, 360), if angle_start == angle_end, the behaviour will carry out a * single rotation of 360 degrees. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: the newly created #ClutterBehaviourRotate. * * Since: 0.4 */ ClutterBehaviour * clutter_behaviour_rotate_new (ClutterAlpha *alpha, ClutterRotateAxis axis, ClutterRotateDirection direction, gdouble angle_start, gdouble angle_end) { g_return_val_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha), NULL); return g_object_new (CLUTTER_TYPE_BEHAVIOUR_ROTATE, "alpha", alpha, "axis", axis, "direction", direction, "angle-start", angle_start, "angle-end", angle_end, NULL); } /** * clutter_behaviour_rotate_get_axis: * @rotate: a #ClutterBehaviourRotate * * Retrieves the #ClutterRotateAxis used by the rotate behaviour. * * Return value: the rotation axis * * Since: 0.4 */ ClutterRotateAxis clutter_behaviour_rotate_get_axis (ClutterBehaviourRotate *rotate) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate), CLUTTER_Z_AXIS); return rotate->priv->axis; } /** * clutter_behaviour_rotate_set_axis: * @rotate: a #ClutterBehaviourRotate * @axis: a #ClutterRotateAxis * * Sets the axis used by the rotate behaviour. * * Since: 0.4 */ void clutter_behaviour_rotate_set_axis (ClutterBehaviourRotate *rotate, ClutterRotateAxis axis) { ClutterBehaviourRotatePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate)); priv = rotate->priv; if (priv->axis != axis) { priv->axis = axis; g_object_notify_by_pspec (G_OBJECT (rotate), obj_props[PROP_AXIS]); } } /** * clutter_behaviour_rotate_get_direction: * @rotate: a #ClutterBehaviourRotate * * Retrieves the #ClutterRotateDirection used by the rotate behaviour. * * Return value: the rotation direction * * Since: 0.4 */ ClutterRotateDirection clutter_behaviour_rotate_get_direction (ClutterBehaviourRotate *rotate) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate), CLUTTER_ROTATE_CW); return rotate->priv->direction; } /** * clutter_behaviour_rotate_set_direction: * @rotate: a #ClutterBehaviourRotate * @direction: the rotation direction * * Sets the rotation direction used by the rotate behaviour. * * Since: 0.4 */ void clutter_behaviour_rotate_set_direction (ClutterBehaviourRotate *rotate, ClutterRotateDirection direction) { ClutterBehaviourRotatePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate)); priv = rotate->priv; if (priv->direction != direction) { priv->direction = direction; g_object_notify_by_pspec (G_OBJECT (rotate), obj_props[PROP_DIRECTION]); } } /** * clutter_behaviour_rotate_get_bounds: * @rotate: a #ClutterBehaviourRotate * @angle_start: (out): return value for the initial angle * @angle_end: (out): return value for the final angle * * Retrieves the rotation boundaries of the rotate behaviour. * * Since: 0.4 */ void clutter_behaviour_rotate_get_bounds (ClutterBehaviourRotate *rotate, gdouble *angle_start, gdouble *angle_end) { ClutterBehaviourRotatePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate)); priv = rotate->priv; if (angle_start) *angle_start = priv->angle_start; if (angle_end) *angle_end = priv->angle_end; } /** * clutter_behaviour_rotate_set_bounds: * @rotate: a #ClutterBehaviourRotate * @angle_start: initial angle in degrees, between 0 and 360. * @angle_end: final angle in degrees, between 0 and 360. * * Sets the initial and final angles of a rotation behaviour; angles >= 360 * degrees get clamped to the canonical interval <0, 360). * * Since: 0.4 */ void clutter_behaviour_rotate_set_bounds (ClutterBehaviourRotate *rotate, gdouble angle_start, gdouble angle_end) { ClutterBehaviourRotatePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate)); priv = rotate->priv; g_object_freeze_notify (G_OBJECT (rotate)); if (priv->angle_start != angle_start) { priv->angle_start = clamp_angle (angle_start); g_object_notify_by_pspec (G_OBJECT (rotate), obj_props[PROP_ANGLE_START]); } if (priv->angle_end != angle_end) { priv->angle_end = clamp_angle (angle_end); g_object_notify_by_pspec (G_OBJECT (rotate), obj_props[PROP_ANGLE_END]); } g_object_thaw_notify (G_OBJECT (rotate)); } /** * clutter_behaviour_rotate_set_center: * @rotate: a #ClutterBehaviourRotate * @x: X axis center of rotation * @y: Y axis center of rotation * @z: Z axis center of rotation * * Sets the center of rotation. The coordinates are relative to the plane * normal to the rotation axis set with clutter_behaviour_rotate_set_axis(). * * Since: 0.4 */ void clutter_behaviour_rotate_set_center (ClutterBehaviourRotate *rotate, gint x, gint y, gint z) { ClutterBehaviourRotatePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate)); priv = rotate->priv; g_object_freeze_notify (G_OBJECT (rotate)); if (priv->center_x != x) { priv->center_x = x; g_object_notify_by_pspec (G_OBJECT (rotate), obj_props[PROP_CENTER_X]); } if (priv->center_y != y) { priv->center_y = y; g_object_notify_by_pspec (G_OBJECT (rotate), obj_props[PROP_CENTER_Y]); } if (priv->center_z != z) { priv->center_z = z; g_object_notify_by_pspec (G_OBJECT (rotate), obj_props[PROP_CENTER_Z]); } g_object_thaw_notify (G_OBJECT (rotate)); } /** * clutter_behaviour_rotate_get_center: * @rotate: a #ClutterBehaviourRotate * @x: (out): return location for the X center of rotation * @y: (out): return location for the Y center of rotation * @z: (out): return location for the Z center of rotation * * Retrieves the center of rotation set using * clutter_behaviour_rotate_set_center(). * * Since: 0.4 */ void clutter_behaviour_rotate_get_center (ClutterBehaviourRotate *rotate, gint *x, gint *y, gint *z) { ClutterBehaviourRotatePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ROTATE (rotate)); priv = rotate->priv; if (x) *x = priv->center_x; if (y) *y = priv->center_y; if (z) *z = priv->center_z; } muffin-5.2.1/clutter/clutter/deprecated/clutter-alpha.h0000664000175000017500000001247214211404421023324 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * Tomas Frydrych * * Copyright (C) 2006, 2007, 2008 OpenedHand * 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_ALPHA_H__ #define __CLUTTER_ALPHA_H__ #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_ALPHA (clutter_alpha_get_type ()) #define CLUTTER_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ALPHA, ClutterAlpha)) #define CLUTTER_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ALPHA, ClutterAlphaClass)) #define CLUTTER_IS_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ALPHA)) #define CLUTTER_IS_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ALPHA)) #define CLUTTER_ALPHA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ALPHA, ClutterAlphaClass)) typedef struct _ClutterAlphaClass ClutterAlphaClass; typedef struct _ClutterAlphaPrivate ClutterAlphaPrivate; /** * ClutterAlphaFunc: * @alpha: a #ClutterAlpha * @user_data: user data passed to the function * * A function returning a value depending on the position of * the #ClutterTimeline bound to @alpha. * * Return value: a floating point value * * Since: 0.2 * * Deprecated: 1.12: Use #ClutterTimelineProgressFunc instead. */ typedef gdouble (*ClutterAlphaFunc) (ClutterAlpha *alpha, gpointer user_data); /** * ClutterAlpha: * * #ClutterAlpha combines a #ClutterTimeline and a function. * The contents of the #ClutterAlpha structure are private and should * only be accessed using the provided API. * * Since: 0.2 * * Deprecated: 1.12: Use #ClutterTimeline instead */ struct _ClutterAlpha { /*< private >*/ GInitiallyUnowned parent; ClutterAlphaPrivate *priv; }; /** * ClutterAlphaClass: * * Base class for #ClutterAlpha * * Since: 0.2 * * Deprecated: 1.12: Use #ClutterTimeline instead */ struct _ClutterAlphaClass { /*< private >*/ GInitiallyUnownedClass parent_class; void (*_clutter_alpha_1) (void); void (*_clutter_alpha_2) (void); void (*_clutter_alpha_3) (void); void (*_clutter_alpha_4) (void); void (*_clutter_alpha_5) (void); }; CLUTTER_DEPRECATED_IN_1_12 GType clutter_alpha_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12 ClutterAlpha * clutter_alpha_new (void); CLUTTER_DEPRECATED_IN_1_12 ClutterAlpha * clutter_alpha_new_full (ClutterTimeline *timeline, gulong mode); CLUTTER_DEPRECATED_IN_1_12 ClutterAlpha * clutter_alpha_new_with_func (ClutterTimeline *timeline, ClutterAlphaFunc func, gpointer data, GDestroyNotify destroy); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_alpha_get_alpha (ClutterAlpha *alpha); CLUTTER_DEPRECATED_IN_1_12 void clutter_alpha_set_func (ClutterAlpha *alpha, ClutterAlphaFunc func, gpointer data, GDestroyNotify destroy); CLUTTER_DEPRECATED_IN_1_12 void clutter_alpha_set_closure (ClutterAlpha *alpha, GClosure *closure); CLUTTER_DEPRECATED_IN_1_12 void clutter_alpha_set_timeline (ClutterAlpha *alpha, ClutterTimeline *timeline); CLUTTER_DEPRECATED_IN_1_12 ClutterTimeline *clutter_alpha_get_timeline (ClutterAlpha *alpha); CLUTTER_DEPRECATED_IN_1_12 void clutter_alpha_set_mode (ClutterAlpha *alpha, gulong mode); CLUTTER_DEPRECATED_IN_1_12 gulong clutter_alpha_get_mode (ClutterAlpha *alpha); CLUTTER_DEPRECATED_IN_1_12 gulong clutter_alpha_register_func (ClutterAlphaFunc func, gpointer data); CLUTTER_DEPRECATED_IN_1_12 gulong clutter_alpha_register_closure (GClosure *closure); G_END_DECLS #endif /* __CLUTTER_ALPHA_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-depth.c0000664000175000017500000002212514211404421025314 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-actor.h" #include "clutter-alpha.h" #include "clutter-behaviour.h" #include "clutter-behaviour-depth.h" #include "clutter-enum-types.h" #include "clutter-main.h" #include "clutter-debug.h" #include "clutter-private.h" /** * SECTION:clutter-behaviour-depth * @Title: ClutterBehaviourDepth * @short_description: A behaviour controlling the Z position * @Deprecated: 1.6: Use clutter_actor_animate() instead * * #ClutterBehaviourDepth is a simple #ClutterBehaviour controlling the * depth of a set of actors between a start and end depth. * * #ClutterBehaviourDepth is available since Clutter 0.4. * * Deprecated: 1.6: Use the #ClutterActor:depth property and * clutter_actor_animate(), or #ClutterAnimator, or #ClutterState * instead. */ struct _ClutterBehaviourDepthPrivate { gint depth_start; gint depth_end; }; enum { PROP_0, PROP_DEPTH_START, PROP_DEPTH_END }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterBehaviourDepth, clutter_behaviour_depth, CLUTTER_TYPE_BEHAVIOUR) static void alpha_notify_foreach (ClutterBehaviour *behaviour, ClutterActor *actor, gpointer user_data) { clutter_actor_set_depth (actor, GPOINTER_TO_INT (user_data)); } static void clutter_behaviour_depth_alpha_notify (ClutterBehaviour *behaviour, gdouble alpha_value) { ClutterBehaviourDepthPrivate *priv; gint depth; priv = CLUTTER_BEHAVIOUR_DEPTH (behaviour)->priv; /* Need to create factor as to avoid borking signedness */ depth = (alpha_value * (priv->depth_end - priv->depth_start)) + priv->depth_start; CLUTTER_NOTE (ANIMATION, "alpha: %.4f, depth: %d", alpha_value, depth); clutter_behaviour_actors_foreach (behaviour, alpha_notify_foreach, GINT_TO_POINTER (depth)); } static void clutter_behaviour_depth_applied (ClutterBehaviour *behaviour, ClutterActor *actor) { ClutterBehaviourDepth *depth = CLUTTER_BEHAVIOUR_DEPTH (behaviour); clutter_actor_set_depth (actor, depth->priv->depth_start); } static void clutter_behaviour_depth_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBehaviourDepth *depth = CLUTTER_BEHAVIOUR_DEPTH (gobject); switch (prop_id) { case PROP_DEPTH_START: depth->priv->depth_start = g_value_get_int (value); break; case PROP_DEPTH_END: depth->priv->depth_end = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_depth_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBehaviourDepth *depth = CLUTTER_BEHAVIOUR_DEPTH (gobject); switch (prop_id) { case PROP_DEPTH_START: g_value_set_int (value, depth->priv->depth_start); break; case PROP_DEPTH_END: g_value_set_int (value, depth->priv->depth_end); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_depth_class_init (ClutterBehaviourDepthClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBehaviourClass *behaviour_class = CLUTTER_BEHAVIOUR_CLASS (klass); gobject_class->set_property = clutter_behaviour_depth_set_property; gobject_class->get_property = clutter_behaviour_depth_get_property; behaviour_class->alpha_notify = clutter_behaviour_depth_alpha_notify; behaviour_class->applied = clutter_behaviour_depth_applied; /** * ClutterBehaviourDepth:depth-start: * * Start depth level to apply to the actors. * * Since: 0.4 * * Deprecated: 1.6 */ g_object_class_install_property (gobject_class, PROP_DEPTH_START, g_param_spec_int ("depth-start", P_("Start Depth"), P_("Initial depth to apply"), G_MININT, G_MAXINT, 0, CLUTTER_PARAM_READWRITE)); /** * ClutterBehaviourDepth:depth-end: * * End depth level to apply to the actors. * * Since: 0.4 * * Deprecated: 1.6 */ g_object_class_install_property (gobject_class, PROP_DEPTH_END, g_param_spec_int ("depth-end", P_("End Depth"), P_("Final depth to apply"), G_MININT, G_MAXINT, 0, CLUTTER_PARAM_READWRITE)); } static void clutter_behaviour_depth_init (ClutterBehaviourDepth *depth) { depth->priv = clutter_behaviour_depth_get_instance_private (depth); } /** * clutter_behaviour_depth_new: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @depth_start: initial value of the depth * @depth_end: final value of the depth * * Creates a new #ClutterBehaviourDepth which can be used to control * the ClutterActor:depth property of a set of #ClutterActors. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: (transfer full): the newly created behaviour * * Since: 0.4 * * Deprecated: 1.6 */ ClutterBehaviour * clutter_behaviour_depth_new (ClutterAlpha *alpha, gint depth_start, gint depth_end) { g_return_val_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha), NULL); return g_object_new (CLUTTER_TYPE_BEHAVIOUR_DEPTH, "alpha", alpha, "depth-start", depth_start, "depth-end", depth_end, NULL); } /** * clutter_behaviour_depth_set_bounds: * @behaviour: a #ClutterBehaviourDepth * @depth_start: initial value of the depth * @depth_end: final value of the depth * * Sets the boundaries of the @behaviour. * * Since: 0.6 * * Deprecated: 1.6 */ void clutter_behaviour_depth_set_bounds (ClutterBehaviourDepth *behaviour, gint depth_start, gint depth_end) { ClutterBehaviourDepthPrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_DEPTH (behaviour)); priv = behaviour->priv; g_object_freeze_notify (G_OBJECT (behaviour)); if (priv->depth_start != depth_start) { priv->depth_start = depth_start; g_object_notify (G_OBJECT (behaviour), "depth-start"); } if (priv->depth_end != depth_end) { priv->depth_end = depth_end; g_object_notify (G_OBJECT (behaviour), "depth-end"); } g_object_thaw_notify (G_OBJECT (behaviour)); } /** * clutter_behaviour_depth_get_bounds: * @behaviour: a #ClutterBehaviourDepth * @depth_start: (out): return location for the initial depth value, or %NULL * @depth_end: (out): return location for the final depth value, or %NULL * * Gets the boundaries of the @behaviour * * Since: 0.6 * * Deprecated: 1.6 */ void clutter_behaviour_depth_get_bounds (ClutterBehaviourDepth *behaviour, gint *depth_start, gint *depth_end) { g_return_if_fail (CLUTTER_IS_BEHAVIOUR_DEPTH (behaviour)); if (depth_start) *depth_start = behaviour->priv->depth_start; if (depth_end) *depth_end = behaviour->priv->depth_end; } muffin-5.2.1/clutter/clutter/deprecated/clutter-group.c0000664000175000017500000004131414211404421023363 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ /** * SECTION:clutter-group * @short_description: A fixed layout container * * A #ClutterGroup is an Actor which contains multiple child actors positioned * relative to the #ClutterGroup position. Other operations such as scaling, * rotating and clipping of the group will apply to the child actors. * * A #ClutterGroup's size is defined by the size and position of its children; * it will be the smallest non-negative size that covers the right and bottom * edges of all of its children. * * Setting the size on a Group using #ClutterActor methods like * clutter_actor_set_size() will override the natural size of the Group, * however this will not affect the size of the children and they may still * be painted outside of the allocation of the group. One way to constrain * the visible area of a #ClutterGroup to a specified allocation is to * explicitly set the size of the #ClutterGroup and then use the * #ClutterActor:clip-to-allocation property. * * #ClutterGroup as a concrete class has been superceded by #ClutterActor * since Clutter 1.10. The type itself is not deprecated as it is used by * #ClutterStage. You should instantiate #ClutterActor and use its API to * manage child actors. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-group.h" #include "clutter-actor.h" #include "clutter-actor-private.h" #include "clutter-container.h" #include "clutter-fixed-layout.h" #include "clutter-main.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "cogl/cogl.h" struct _ClutterGroupPrivate { GList *children; ClutterLayoutManager *layout; }; static void clutter_container_iface_init (ClutterContainerIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterGroup, clutter_group, CLUTTER_TYPE_ACTOR, G_ADD_PRIVATE (ClutterGroup) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER, clutter_container_iface_init)); static gint sort_by_depth (gconstpointer a, gconstpointer b) { gfloat depth_a = clutter_actor_get_depth (CLUTTER_ACTOR(a)); gfloat depth_b = clutter_actor_get_depth (CLUTTER_ACTOR(b)); if (depth_a < depth_b) return -1; if (depth_a > depth_b) return 1; return 0; } static void clutter_group_real_add (ClutterContainer *container, ClutterActor *actor) { ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv; g_object_ref (actor); priv->children = g_list_append (priv->children, actor); clutter_actor_set_parent (actor, CLUTTER_ACTOR (container)); clutter_actor_queue_relayout (CLUTTER_ACTOR (container)); g_signal_emit_by_name (container, "actor-added", actor); clutter_container_sort_depth_order (container); g_object_unref (actor); } static void clutter_group_real_actor_added (ClutterContainer *container, ClutterActor *actor) { ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv; /* XXX - children added using clutter_actor_add_child() will * cause actor-added to be emitted without going through the * add() virtual function. * * if we get an actor-added for a child that is not in our * list of children already, then we go in compatibility * mode. */ if (g_list_find (priv->children, actor) != NULL) return; priv->children = g_list_append (priv->children, actor); clutter_container_sort_depth_order (container); } static void clutter_group_real_remove (ClutterContainer *container, ClutterActor *actor) { ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv; g_object_ref (actor); priv->children = g_list_remove (priv->children, actor); clutter_actor_unparent (actor); clutter_actor_queue_relayout (CLUTTER_ACTOR (container)); g_signal_emit_by_name (container, "actor-removed", actor); clutter_actor_queue_redraw (CLUTTER_ACTOR (container)); g_object_unref (actor); } static void clutter_group_real_actor_removed (ClutterContainer *container, ClutterActor *actor) { ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv; /* XXX - same compatibility mode of the ::actor-added implementation */ if (g_list_find (priv->children, actor) == NULL) return; priv->children = g_list_remove (priv->children, actor); } static void clutter_group_real_foreach (ClutterContainer *container, ClutterCallback callback, gpointer user_data) { ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv; /* Using g_list_foreach instead of iterating the list manually because it has better protection against the current node being removed. This will happen for example if someone calls clutter_container_foreach(container, clutter_actor_destroy) */ g_list_foreach (priv->children, (GFunc) callback, user_data); } static void clutter_group_real_raise (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling) { ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv; priv->children = g_list_remove (priv->children, actor); /* Raise at the top */ if (!sibling) { GList *last_item; last_item = g_list_last (priv->children); if (last_item) sibling = last_item->data; priv->children = g_list_append (priv->children, actor); } else { gint index_ = g_list_index (priv->children, sibling) + 1; priv->children = g_list_insert (priv->children, actor, index_); } /* set Z ordering a value below, this will then call sort * as values are equal ordering shouldn't change but Z * values will be correct. * * FIXME: get rid of this crap; this is so utterly broken and wrong on * so many levels it's not even funny. sadly, we get to keep this until * we can break API and remove Group for good. */ if (sibling && clutter_actor_get_depth (sibling) != clutter_actor_get_depth (actor)) { clutter_actor_set_depth (actor, clutter_actor_get_depth (sibling)); } clutter_actor_queue_redraw (CLUTTER_ACTOR (container)); } static void clutter_group_real_lower (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling) { ClutterGroup *self = CLUTTER_GROUP (container); ClutterGroupPrivate *priv = self->priv; priv->children = g_list_remove (priv->children, actor); /* Push to bottom */ if (!sibling) { GList *last_item; last_item = g_list_first (priv->children); if (last_item) sibling = last_item->data; priv->children = g_list_prepend (priv->children, actor); } else { gint index_ = g_list_index (priv->children, sibling); priv->children = g_list_insert (priv->children, actor, index_); } /* See comment in group_raise for this */ if (sibling && clutter_actor_get_depth (sibling) != clutter_actor_get_depth (actor)) { clutter_actor_set_depth (actor, clutter_actor_get_depth (sibling)); } clutter_actor_queue_redraw (CLUTTER_ACTOR (container)); } static void clutter_group_real_sort_depth_order (ClutterContainer *container) { ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv; priv->children = g_list_sort (priv->children, sort_by_depth); clutter_actor_queue_redraw (CLUTTER_ACTOR (container)); } static void clutter_container_iface_init (ClutterContainerIface *iface) { iface->add = clutter_group_real_add; iface->actor_added = clutter_group_real_actor_added; iface->remove = clutter_group_real_remove; iface->actor_removed = clutter_group_real_actor_removed; iface->foreach = clutter_group_real_foreach; iface->raise = clutter_group_real_raise; iface->lower = clutter_group_real_lower; iface->sort_depth_order = clutter_group_real_sort_depth_order; } static void clutter_group_real_paint (ClutterActor *actor) { ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv; CLUTTER_NOTE (PAINT, "ClutterGroup paint enter '%s'", _clutter_actor_get_debug_name (actor)); g_list_foreach (priv->children, (GFunc) clutter_actor_paint, NULL); CLUTTER_NOTE (PAINT, "ClutterGroup paint leave '%s'", _clutter_actor_get_debug_name (actor)); } static void clutter_group_real_pick (ClutterActor *actor, const ClutterColor *pick) { ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv; /* Chain up so we get a bounding box pained (if we are reactive) */ CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->pick (actor, pick); g_list_foreach (priv->children, (GFunc) clutter_actor_paint, NULL); } static void clutter_group_real_get_preferred_width (ClutterActor *actor, gfloat for_height, gfloat *min_width, gfloat *natural_width) { ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv; clutter_layout_manager_get_preferred_width (priv->layout, CLUTTER_CONTAINER (actor), for_height, min_width, natural_width); } static void clutter_group_real_get_preferred_height (ClutterActor *actor, gfloat for_width, gfloat *min_height, gfloat *natural_height) { ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv; clutter_layout_manager_get_preferred_height (priv->layout, CLUTTER_CONTAINER (actor), for_width, min_height, natural_height); } static void clutter_group_real_allocate (ClutterActor *actor, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv; ClutterActorClass *klass; klass = CLUTTER_ACTOR_CLASS (clutter_group_parent_class); klass->allocate (actor, allocation, flags); if (priv->children == NULL) return; clutter_layout_manager_allocate (priv->layout, CLUTTER_CONTAINER (actor), allocation, flags); } static void clutter_group_dispose (GObject *object) { ClutterGroup *self = CLUTTER_GROUP (object); ClutterGroupPrivate *priv = self->priv; /* Note: we are careful to consider that destroying children could * have the side-effect of destroying other children so * priv->children may be modified during clutter_actor_destroy. */ while (priv->children != NULL) { ClutterActor *child = priv->children->data; priv->children = g_list_delete_link (priv->children, priv->children); clutter_actor_destroy (child); } if (priv->layout) { clutter_layout_manager_set_container (priv->layout, NULL); g_object_unref (priv->layout); priv->layout = NULL; } G_OBJECT_CLASS (clutter_group_parent_class)->dispose (object); } static void clutter_group_real_show_all (ClutterActor *actor) { clutter_container_foreach (CLUTTER_CONTAINER (actor), CLUTTER_CALLBACK (clutter_actor_show), NULL); clutter_actor_show (actor); } static void clutter_group_real_hide_all (ClutterActor *actor) { clutter_actor_hide (actor); clutter_container_foreach (CLUTTER_CONTAINER (actor), CLUTTER_CALLBACK (clutter_actor_hide), NULL); } static gboolean clutter_group_real_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv; GList *l; if (priv->children == NULL) return TRUE; for (l = priv->children; l != NULL; l = l->next) { ClutterActor *child = l->data; const ClutterPaintVolume *child_volume; /* This gets the paint volume of the child transformed into the * group's coordinate space... */ child_volume = clutter_actor_get_transformed_paint_volume (child, actor); if (!child_volume) return FALSE; clutter_paint_volume_union (volume, child_volume); } return TRUE; } static void clutter_group_class_init (ClutterGroupClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); actor_class->get_preferred_width = clutter_group_real_get_preferred_width; actor_class->get_preferred_height = clutter_group_real_get_preferred_height; actor_class->allocate = clutter_group_real_allocate; actor_class->paint = clutter_group_real_paint; actor_class->pick = clutter_group_real_pick; actor_class->show_all = clutter_group_real_show_all; actor_class->hide_all = clutter_group_real_hide_all; actor_class->get_paint_volume = clutter_group_real_get_paint_volume; gobject_class->dispose = clutter_group_dispose; } static void clutter_group_init (ClutterGroup *self) { ClutterActor *actor = CLUTTER_ACTOR (self); self->priv = clutter_group_get_instance_private (self); /* turn on some optimization * * XXX - these so-called "optimizations" are insane and should have never * been used. they introduce some weird behaviour that breaks invariants * and have to be explicitly worked around. * * this flag was set by the ClutterFixedLayout, but since that layout * manager is now the default for ClutterActor, we set the flag explicitly * here, to avoid breaking perfectly working actors overriding the * allocate() virtual function. * * also, we keep this flag here so that it can die once we get rid of * ClutterGroup. */ clutter_actor_set_flags (actor, CLUTTER_ACTOR_NO_LAYOUT); self->priv->layout = clutter_fixed_layout_new (); g_object_ref_sink (self->priv->layout); clutter_actor_set_layout_manager (actor, self->priv->layout); } /** * clutter_group_new: * * Create a new #ClutterGroup. * * Return value: the newly created #ClutterGroup actor * * Deprecated: 1.10: Use clutter_actor_new() instead. */ ClutterActor * clutter_group_new (void) { return g_object_new (CLUTTER_TYPE_GROUP, NULL); } /** * clutter_group_remove_all: * @self: A #ClutterGroup * * Removes all children actors from the #ClutterGroup. * * Deprecated: 1.10: Use clutter_actor_remove_all_children() instead. */ void clutter_group_remove_all (ClutterGroup *self) { g_return_if_fail (CLUTTER_IS_GROUP (self)); clutter_actor_remove_all_children (CLUTTER_ACTOR (self)); } /** * clutter_group_get_n_children: * @self: A #ClutterGroup * * Gets the number of actors held in the group. * * Return value: The number of child actors held in the group. * * Since: 0.2 * * Deprecated: 1.10: Use clutter_actor_get_n_children() instead. */ gint clutter_group_get_n_children (ClutterGroup *self) { g_return_val_if_fail (CLUTTER_IS_GROUP (self), 0); return clutter_actor_get_n_children (CLUTTER_ACTOR (self)); } /** * clutter_group_get_nth_child: * @self: A #ClutterGroup * @index_: the position of the requested actor. * * Gets a groups child held at @index_ in stack. * * Return value: (transfer none): A Clutter actor, or %NULL if * @index_ is invalid. * * Since: 0.2 * * Deprecated: 1.10: Use clutter_actor_get_child_at_index() instead. */ ClutterActor * clutter_group_get_nth_child (ClutterGroup *self, gint index_) { ClutterActor *actor; g_return_val_if_fail (CLUTTER_IS_GROUP (self), NULL); actor = CLUTTER_ACTOR (self); g_return_val_if_fail (index_ <= clutter_actor_get_n_children (actor), NULL); return clutter_actor_get_child_at_index (actor, index_); } muffin-5.2.1/clutter/clutter/deprecated/clutter-alpha.c0000664000175000017500000006212014211404421023312 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * Tomas Frydrych * * Copyright (C) 2006, 2007, 2008 OpenedHand * Copyright (C) 2009, 2010 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, see . */ /** * SECTION:clutter-alpha * @short_description: A class for calculating a value as a function of time * * #ClutterAlpha is a class for calculating an floating point value * dependent only on the position of a #ClutterTimeline. * * For newly written code, it is recommended to use the * #ClutterTimeline:progress-mode property of #ClutterTimeline, or the * clutter_timeline_set_progress_func() function instead of #ClutterAlpha. * The #ClutterAlpha class will be deprecated in the future, and will not * be available any more in the next major version of Clutter. * * A #ClutterAlpha binds a #ClutterTimeline to a progress function which * translates the time T into an adimensional factor alpha. The factor can * then be used to drive a #ClutterBehaviour, which will translate the * alpha value into something meaningful for a #ClutterActor. * * You should provide a #ClutterTimeline and bind it to the #ClutterAlpha * instance using clutter_alpha_set_timeline(). You should also set an * "animation mode", either by using the #ClutterAnimationMode values that * Clutter itself provides or by registering custom functions using * clutter_alpha_register_func(). * * Instead of a #ClutterAnimationMode you may provide a function returning * the alpha value depending on the progress of the timeline, using * clutter_alpha_set_func() or clutter_alpha_set_closure(). The alpha * function will be executed each time a new frame in the #ClutterTimeline * is reached. * * Since the alpha function is controlled by the timeline instance, you can * pause, stop or resume the #ClutterAlpha from calling the alpha function by * using the appropriate functions of the #ClutterTimeline object. * * #ClutterAlpha is used to "drive" a #ClutterBehaviour instance, and it * is internally used by the #ClutterAnimation API. * * #ClutterAlpha is available since Clutter 0.2. * * #ClutterAlpha is deprecated since Clutter 1.12. #ClutterTimeline and * the #ClutterTimeline:progress-mode property replace this whole class. * * ## ClutterAlpha custom properties for #ClutterScript * * #ClutterAlpha defines a custom `function` property for * #ClutterScript which allows to reference a custom alpha function * available in the source code. Setting the `function` property * is equivalent to calling clutter_alpha_set_func() with the * specified function name. No user data or #GDestroyNotify is * available to be passed. * * The following JSON fragment defines a #ClutterAlpha * using a #ClutterTimeline with id "sine-timeline" and an alpha * function called `my_sine_alpha`. The defined #ClutterAlpha * instance can be reused in multiple #ClutterBehaviour * definitions or for #ClutterAnimation definitions. * * |[ * { * "id" : "sine-alpha", * "timeline" : { * "id" : "sine-timeline", * "duration" : 500, * "loop" : true * }, * "function" : "my_sine_alpha" * } * ]| */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-alpha.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-easing.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-scriptable.h" #include "clutter-script-private.h" struct _ClutterAlphaPrivate { ClutterTimeline *timeline; guint timeline_new_frame_id; gdouble alpha; GClosure *closure; ClutterAlphaFunc func; gpointer user_data; GDestroyNotify notify; gulong mode; }; enum { PROP_0, PROP_TIMELINE, PROP_ALPHA, PROP_MODE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterAlpha, clutter_alpha, G_TYPE_INITIALLY_UNOWNED, G_ADD_PRIVATE (ClutterAlpha) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)); static void timeline_new_frame_cb (ClutterTimeline *timeline, guint msecs, ClutterAlpha *alpha) { ClutterAlphaPrivate *priv = alpha->priv; /* Update alpha value and notify */ priv->alpha = clutter_alpha_get_alpha (alpha); g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_ALPHA]); } static void clutter_alpha_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterAlpha *alpha = CLUTTER_ALPHA (object); switch (prop_id) { case PROP_TIMELINE: clutter_alpha_set_timeline (alpha, g_value_get_object (value)); break; case PROP_MODE: clutter_alpha_set_mode (alpha, g_value_get_ulong (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_alpha_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterAlphaPrivate *priv = CLUTTER_ALPHA (object)->priv; switch (prop_id) { case PROP_TIMELINE: g_value_set_object (value, priv->timeline); break; case PROP_ALPHA: g_value_set_double (value, priv->alpha); break; case PROP_MODE: g_value_set_ulong (value, priv->mode); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_alpha_finalize (GObject *object) { ClutterAlphaPrivate *priv = CLUTTER_ALPHA (object)->priv; if (priv->notify != NULL) priv->notify (priv->user_data); else if (priv->closure != NULL) g_closure_unref (priv->closure); G_OBJECT_CLASS (clutter_alpha_parent_class)->finalize (object); } static void clutter_alpha_dispose (GObject *object) { ClutterAlpha *self = CLUTTER_ALPHA(object); clutter_alpha_set_timeline (self, NULL); G_OBJECT_CLASS (clutter_alpha_parent_class)->dispose (object); } static ClutterAlphaFunc resolve_alpha_func (const gchar *name) { static GModule *module = NULL; ClutterAlphaFunc func; CLUTTER_NOTE (SCRIPT, "Looking up '%s' alpha function", name); if (G_UNLIKELY (module == NULL)) module = g_module_open (NULL, 0); if (g_module_symbol (module, name, (gpointer) &func)) { CLUTTER_NOTE (SCRIPT, "Found '%s' alpha function in the symbols table", name); return func; } return NULL; } static void clutter_alpha_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { if (strncmp (name, "function", 8) == 0) { g_assert (G_VALUE_HOLDS (value, G_TYPE_POINTER)); if (g_value_get_pointer (value) != NULL) { clutter_alpha_set_func (CLUTTER_ALPHA (scriptable), g_value_get_pointer (value), NULL, NULL); } } else g_object_set_property (G_OBJECT (scriptable), name, value); } static gboolean clutter_alpha_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { if (strncmp (name, "function", 8) == 0) { const gchar *func_name = json_node_get_string (node); g_value_init (value, G_TYPE_POINTER); g_value_set_pointer (value, resolve_alpha_func (func_name)); return TRUE; } /* we need to do this because we use gulong in place * of ClutterAnimationMode for ClutterAlpha:mode */ if (strncmp (name, "mode", 4) == 0) { gulong mode; mode = _clutter_script_resolve_animation_mode (node); g_value_init (value, G_TYPE_ULONG); g_value_set_ulong (value, mode); return TRUE; } return FALSE; } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_alpha_parse_custom_node; iface->set_custom_property = clutter_alpha_set_custom_property; } static void clutter_alpha_class_init (ClutterAlphaClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = clutter_alpha_set_property; object_class->get_property = clutter_alpha_get_property; object_class->finalize = clutter_alpha_finalize; object_class->dispose = clutter_alpha_dispose; /** * ClutterAlpha:timeline: * * A #ClutterTimeline instance used to drive the alpha function. * * Since: 0.2 * * Deprecated: 1.12 */ obj_props[PROP_TIMELINE] = g_param_spec_object ("timeline", P_("Timeline"), P_("Timeline used by the alpha"), CLUTTER_TYPE_TIMELINE, CLUTTER_PARAM_READWRITE); /** * ClutterAlpha:alpha: * * The alpha value as computed by the alpha function. The linear * interval is 0.0 to 1.0, but the Alpha allows overshooting by * one unit in each direction, so the valid interval is -1.0 to 2.0. * * Since: 0.2 * Deprecated: 1.12: Use #ClutterTimeline::new-frame and * clutter_timeline_get_progress() instead */ obj_props[PROP_ALPHA] = g_param_spec_double ("alpha", P_("Alpha value"), P_("Alpha value as computed by the alpha"), -1.0, 2.0, 0.0, CLUTTER_PARAM_READABLE); /** * ClutterAlpha:mode: * * The progress function logical id - either a value from the * #ClutterAnimationMode enumeration or a value returned by * clutter_alpha_register_func(). * * If %CLUTTER_CUSTOM_MODE is used then the function set using * clutter_alpha_set_closure() or clutter_alpha_set_func() * will be used. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterTimeline:progress-mode */ obj_props[PROP_MODE] = g_param_spec_ulong ("mode", P_("Mode"), P_("Progress mode"), 0, G_MAXULONG, CLUTTER_CUSTOM_MODE, G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE); g_object_class_install_properties (object_class, PROP_LAST, obj_props); } static void clutter_alpha_init (ClutterAlpha *self) { self->priv = clutter_alpha_get_instance_private (self); self->priv->mode = CLUTTER_CUSTOM_MODE; self->priv->alpha = 0.0; } /** * clutter_alpha_get_alpha: * @alpha: A #ClutterAlpha * * Query the current alpha value. * * Return Value: The current alpha value for the alpha * * Since: 0.2 * * Deprecated: 1.12: Use clutter_timeline_get_progress() */ gdouble clutter_alpha_get_alpha (ClutterAlpha *alpha) { ClutterAlphaPrivate *priv; gdouble retval = 0; g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), 0); priv = alpha->priv; if (G_LIKELY (priv->func)) { return priv->func (alpha, priv->user_data); } else if (priv->closure) { GValue params = G_VALUE_INIT; GValue result_value = G_VALUE_INIT; g_object_ref (alpha); g_value_init (&result_value, G_TYPE_DOUBLE); g_value_init (¶ms, CLUTTER_TYPE_ALPHA); g_value_set_object (¶ms, alpha); g_closure_invoke (priv->closure, &result_value, 1, ¶ms, NULL); retval = g_value_get_double (&result_value); g_value_unset (&result_value); g_value_unset (¶ms); g_object_unref (alpha); } return retval; } /* * clutter_alpha_set_closure_internal: * @alpha: a #ClutterAlpha * @closure: a #GClosure * * Sets the @closure for @alpha. This function does not * set the #ClutterAlpha:mode property and does not emit * the #GObject::notify signal for it. */ static inline void clutter_alpha_set_closure_internal (ClutterAlpha *alpha, GClosure *closure) { ClutterAlphaPrivate *priv = alpha->priv; if (priv->notify != NULL) priv->notify (priv->user_data); else if (priv->closure != NULL) g_closure_unref (priv->closure); priv->func = NULL; priv->user_data = NULL; priv->notify = NULL; if (closure == NULL) return; /* need to take ownership of the closure before sinking it */ priv->closure = g_closure_ref (closure); g_closure_sink (closure); /* set the marshaller */ if (G_CLOSURE_NEEDS_MARSHAL (closure)) { GClosureMarshal marshal = _clutter_marshal_DOUBLE__VOID; g_closure_set_marshal (priv->closure, marshal); } } /** * clutter_alpha_set_closure: * @alpha: A #ClutterAlpha * @closure: A #GClosure * * Sets the #GClosure used to compute the alpha value at each * frame of the #ClutterTimeline bound to @alpha. * * Since: 0.8 * * Deprecated: 1.12: Use clutter_timeline_set_progress_func() */ void clutter_alpha_set_closure (ClutterAlpha *alpha, GClosure *closure) { ClutterAlphaPrivate *priv; g_return_if_fail (CLUTTER_IS_ALPHA (alpha)); g_return_if_fail (closure != NULL); priv = alpha->priv; clutter_alpha_set_closure_internal (alpha, closure); priv->mode = CLUTTER_CUSTOM_MODE; g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_MODE]); } /** * clutter_alpha_set_func: * @alpha: A #ClutterAlpha * @func: A #ClutterAlphaFunc * @data: user data to be passed to the alpha function, or %NULL * @destroy: notify function used when disposing the alpha function * * Sets the #ClutterAlphaFunc function used to compute * the alpha value at each frame of the #ClutterTimeline * bound to @alpha. * * This function will not register @func as a global alpha function. * * Since: 0.2 * * Deprecated: 1.12: Use clutter_timeline_set_progress_func() */ void clutter_alpha_set_func (ClutterAlpha *alpha, ClutterAlphaFunc func, gpointer data, GDestroyNotify destroy) { ClutterAlphaPrivate *priv; g_return_if_fail (CLUTTER_IS_ALPHA (alpha)); g_return_if_fail (func != NULL); priv = alpha->priv; if (priv->notify != NULL) { priv->notify (priv->user_data); } else if (priv->closure != NULL) { g_closure_unref (priv->closure); priv->closure = NULL; } priv->func = func; priv->user_data = data; priv->notify = destroy; priv->mode = CLUTTER_CUSTOM_MODE; g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_MODE]); } /** * clutter_alpha_set_timeline: * @alpha: A #ClutterAlpha * @timeline: A #ClutterTimeline * * Binds @alpha to @timeline. * * Since: 0.2 * * Deprecated: 1.12: Use #ClutterTimeline directly */ void clutter_alpha_set_timeline (ClutterAlpha *alpha, ClutterTimeline *timeline) { ClutterAlphaPrivate *priv; g_return_if_fail (CLUTTER_IS_ALPHA (alpha)); g_return_if_fail (timeline == NULL || CLUTTER_IS_TIMELINE (timeline)); priv = alpha->priv; if (priv->timeline == timeline) return; if (priv->timeline) { g_signal_handlers_disconnect_by_func (priv->timeline, timeline_new_frame_cb, alpha); g_object_unref (priv->timeline); priv->timeline = NULL; } if (timeline) { priv->timeline = g_object_ref (timeline); g_signal_connect (priv->timeline, "new-frame", G_CALLBACK (timeline_new_frame_cb), alpha); } g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_TIMELINE]); } /** * clutter_alpha_get_timeline: * @alpha: A #ClutterAlpha * * Gets the #ClutterTimeline bound to @alpha. * * Return value: (transfer none): a #ClutterTimeline instance * * Since: 0.2 * * Deprecated: 1.12: Use #ClutterTimeline directlry */ ClutterTimeline * clutter_alpha_get_timeline (ClutterAlpha *alpha) { g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), NULL); return alpha->priv->timeline; } /** * clutter_alpha_new: * * Creates a new #ClutterAlpha instance. You must set a function * to compute the alpha value using clutter_alpha_set_func() and * bind a #ClutterTimeline object to the #ClutterAlpha instance * using clutter_alpha_set_timeline(). * * You should use the newly created #ClutterAlpha instance inside * a #ClutterBehaviour object. * * Return value: the newly created empty #ClutterAlpha instance. * * Since: 0.2 * * Deprecated: 1.12: Use #ClutterTimeline instead */ ClutterAlpha * clutter_alpha_new (void) { return g_object_new (CLUTTER_TYPE_ALPHA, NULL); } /** * clutter_alpha_new_full: * @timeline: #ClutterTimeline timeline * @mode: animation mode * * Creates a new #ClutterAlpha instance and sets the timeline * and animation mode. * * See also clutter_alpha_set_timeline() and clutter_alpha_set_mode(). * * Return Value: the newly created #ClutterAlpha * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterTimeline instead */ ClutterAlpha * clutter_alpha_new_full (ClutterTimeline *timeline, gulong mode) { g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL); g_return_val_if_fail (mode != CLUTTER_ANIMATION_LAST, NULL); return g_object_new (CLUTTER_TYPE_ALPHA, "timeline", timeline, "mode", mode, NULL); } /** * clutter_alpha_new_with_func: * @timeline: a #ClutterTimeline * @func: a #ClutterAlphaFunc * @data: data to pass to the function, or %NULL * @destroy: function to call when removing the alpha function, or %NULL * * Creates a new #ClutterAlpha instances and sets the timeline * and the alpha function. * * This function will not register @func as a global alpha function. * * See also clutter_alpha_set_timeline() and clutter_alpha_set_func(). * * Return value: the newly created #ClutterAlpha * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterTimeline instead */ ClutterAlpha * clutter_alpha_new_with_func (ClutterTimeline *timeline, ClutterAlphaFunc func, gpointer data, GDestroyNotify destroy) { ClutterAlpha *retval; g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL); g_return_val_if_fail (func != NULL, NULL); retval = clutter_alpha_new (); clutter_alpha_set_timeline (retval, timeline); clutter_alpha_set_func (retval, func, data, destroy); return retval; } /** * clutter_alpha_get_mode: * @alpha: a #ClutterAlpha * * Retrieves the #ClutterAnimationMode used by @alpha. * * Return value: the animation mode * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterTimeline instead */ gulong clutter_alpha_get_mode (ClutterAlpha *alpha) { g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), CLUTTER_CUSTOM_MODE); return alpha->priv->mode; } typedef struct _AlphaData { guint closure_set : 1; ClutterAlphaFunc func; gpointer data; GClosure *closure; } AlphaData; static GPtrArray *clutter_alphas = NULL; static gdouble clutter_alpha_easing_func (ClutterAlpha *alpha, gpointer data G_GNUC_UNUSED) { ClutterAlphaPrivate *priv = alpha->priv; ClutterTimeline *timeline = priv->timeline; gdouble t, d; if (G_UNLIKELY (priv->timeline == NULL)) return 0.0; t = clutter_timeline_get_elapsed_time (timeline); d = clutter_timeline_get_duration (timeline); return clutter_easing_for_mode (priv->mode, t, d); } /** * clutter_alpha_set_mode: * @alpha: a #ClutterAlpha * @mode: a #ClutterAnimationMode * * Sets the progress function of @alpha using the symbolic value * of @mode, as taken by the #ClutterAnimationMode enumeration or * using the value returned by clutter_alpha_register_func(). * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterTimeline and * clutter_timeline_set_progress_mode() instead */ void clutter_alpha_set_mode (ClutterAlpha *alpha, gulong mode) { ClutterAlphaPrivate *priv; g_return_if_fail (CLUTTER_IS_ALPHA (alpha)); g_return_if_fail (mode != CLUTTER_ANIMATION_LAST); priv = alpha->priv; if (mode == CLUTTER_CUSTOM_MODE) { priv->mode = mode; } else if (mode < CLUTTER_ANIMATION_LAST) { if (priv->mode == mode) return; /* sanity check to avoid getting an out of sync * enum/function mapping */ g_assert (clutter_get_easing_func_for_mode (mode) != NULL); clutter_alpha_set_closure_internal (alpha, NULL); priv->mode = mode; CLUTTER_NOTE (ANIMATION, "New easing mode '%s'[%lu]\n", clutter_get_easing_name_for_mode (priv->mode), priv->mode); priv->func = clutter_alpha_easing_func; priv->user_data = NULL; priv->notify = NULL; } else if (mode > CLUTTER_ANIMATION_LAST) { AlphaData *alpha_data = NULL; gulong real_index = 0; if (priv->mode == mode) return; if (G_UNLIKELY (clutter_alphas == NULL)) { g_warning ("No alpha functions defined for ClutterAlpha to use. " "Use clutter_alpha_register_func() to register an " "alpha function."); return; } real_index = mode - CLUTTER_ANIMATION_LAST - 1; alpha_data = g_ptr_array_index (clutter_alphas, real_index); if (G_UNLIKELY (alpha_data == NULL)) { g_warning ("No alpha function registered for mode %lu.", mode); return; } if (alpha_data->closure_set) clutter_alpha_set_closure (alpha, alpha_data->closure); else { clutter_alpha_set_closure_internal (alpha, NULL); priv->func = alpha_data->func; priv->user_data = alpha_data->data; priv->notify = NULL; } priv->mode = mode; } else g_assert_not_reached (); g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_MODE]); } static gulong register_alpha_internal (AlphaData *alpha_data) { if (G_UNLIKELY (clutter_alphas == NULL)) clutter_alphas = g_ptr_array_new (); g_ptr_array_add (clutter_alphas, alpha_data); return clutter_alphas->len + CLUTTER_ANIMATION_LAST; } /** * clutter_alpha_register_func: (skip) * @func: a #ClutterAlphaFunc * @data: user data to pass to @func, or %NULL * * Registers a global alpha function and returns its logical id * to be used by clutter_alpha_set_mode() or by #ClutterAnimation. * * The logical id is always greater than %CLUTTER_ANIMATION_LAST. * * Return value: the logical id of the alpha function * * Since: 1.0 * * Deprecated: 1.12: There is no direct replacement for this * function. Use clutter_timeline_set_progress_func() on each * specific #ClutterTimeline instance */ gulong clutter_alpha_register_func (ClutterAlphaFunc func, gpointer data) { AlphaData *alpha_data; g_return_val_if_fail (func != NULL, 0); alpha_data = g_slice_new (AlphaData); alpha_data->closure_set = FALSE; alpha_data->func = func; alpha_data->data = data; return register_alpha_internal (alpha_data); } /** * clutter_alpha_register_closure: (rename-to clutter_alpha_register_func) * @closure: a #GClosure * * #GClosure variant of clutter_alpha_register_func(). * * Registers a global alpha function and returns its logical id * to be used by clutter_alpha_set_mode() or by #ClutterAnimation. * * The logical id is always greater than %CLUTTER_ANIMATION_LAST. * * Return value: the logical id of the alpha function * * Since: 1.0 * * Deprecated: 1.12: There is no direct replacement for this * function. Use clutter_timeline_set_progress_func() on each * specific #ClutterTimeline instance */ gulong clutter_alpha_register_closure (GClosure *closure) { AlphaData *alpha_data; g_return_val_if_fail (closure != NULL, 0); alpha_data = g_slice_new (AlphaData); alpha_data->closure_set = TRUE; alpha_data->closure = closure; return register_alpha_internal (alpha_data); } muffin-5.2.1/clutter/clutter/deprecated/clutter-texture.c0000664000175000017500000027314314211404421023736 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * */ /** * SECTION:clutter-texture * @short_description: An actor for displaying and manipulating images. * * #ClutterTexture is a base class for displaying and manipulating pixel * buffer type data. * * The clutter_texture_set_from_rgb_data() and * clutter_texture_set_from_file() functions are used to copy image * data into texture memory and subsequently realize the texture. * * Note: a ClutterTexture will scale its contents to fit the bounding * box requested using clutter_actor_set_size(). To display an area of * a texture without scaling, you should set the clip area using * clutter_actor_set_clip(). * * The #ClutterTexture API is deprecated since Clutter 1.12. It is strongly * recommended to use #ClutterImage instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif /* sadly, we are still using ClutterShader internally */ #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include #include "clutter-texture.h" #include "clutter-actor-private.h" #include "clutter-color.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-feature.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-scriptable.h" #include "clutter-stage-private.h" #include "clutter-backend.h" #include "deprecated/clutter-shader.h" #include "deprecated/clutter-texture.h" #include "deprecated/clutter-util.h" typedef struct _ClutterTextureAsyncData ClutterTextureAsyncData; struct _ClutterTexturePrivate { gint image_width; gint image_height; CoglPipeline *pipeline; ClutterActor *fbo_source; CoglHandle fbo_handle; CoglPipeline *pick_pipeline; gchar *filename; ClutterTextureAsyncData *async_data; guint no_slice : 1; guint sync_actor_size : 1; guint repeat_x : 1; guint repeat_y : 1; guint keep_aspect_ratio : 1; guint load_size_async : 1; guint load_data_async : 1; guint load_async_set : 1; /* used to make load_async possible */ guint pick_with_alpha : 1; guint pick_with_alpha_supported : 1; guint seen_create_pick_pipeline_warning : 1; }; #define ASYNC_STATE_LOCKED 1 #define ASYNC_STATE_CANCELLED 2 #define ASYNC_STATE_QUEUED 3 struct _ClutterTextureAsyncData { /* The texture for which the data is being loaded */ ClutterTexture *texture; gchar *load_filename; CoglHandle load_bitmap; guint load_idle; GError *load_error; gint state; }; static inline void clutter_texture_async_data_lock (ClutterTextureAsyncData *data) { g_bit_lock (&data->state, 0); } static inline void clutter_texture_async_data_unlock (ClutterTextureAsyncData *data) { g_bit_unlock (&data->state, 0); } enum { PROP_0, PROP_NO_SLICE, PROP_MAX_TILE_WASTE, PROP_SYNC_SIZE, PROP_REPEAT_Y, PROP_REPEAT_X, PROP_FILTER_QUALITY, PROP_COGL_TEXTURE, PROP_COGL_MATERIAL, PROP_FILENAME, PROP_KEEP_ASPECT_RATIO, PROP_LOAD_ASYNC, PROP_LOAD_DATA_ASYNC, PROP_PICK_WITH_ALPHA, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { SIZE_CHANGE, PIXBUF_CHANGE, LOAD_SUCCESS, LOAD_FINISHED, LAST_SIGNAL }; static int texture_signals[LAST_SIGNAL] = { 0 }; static GThreadPool *async_thread_pool = NULL; static guint repaint_upload_func = 0; static GList *upload_list = NULL; static GMutex upload_list_mutex; static CoglPipeline *texture_template_pipeline = NULL; static void texture_fbo_free_resources (ClutterTexture *texture); static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterTexture, clutter_texture, CLUTTER_TYPE_ACTOR, G_ADD_PRIVATE (ClutterTexture) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)); GQuark clutter_texture_error_quark (void) { return g_quark_from_static_string ("clutter-texture-error-quark"); } static const struct { gint min_filter; gint mag_filter; } clutter_texture_quality_filters[] = { /* CLUTTER_TEXTURE_QUALITY_LOW */ { COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST }, /* CLUTTER_TEXTURE_QUALITY_MEDIUM */ { COGL_PIPELINE_FILTER_LINEAR, COGL_PIPELINE_FILTER_LINEAR }, /* CLUTTER_TEXTURE_QUALITY_HIGH */ { COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR, COGL_PIPELINE_FILTER_LINEAR } }; static inline void clutter_texture_quality_to_filters (ClutterTextureQuality quality, gint *min_filter_p, gint *mag_filter_p) { g_return_if_fail (quality < G_N_ELEMENTS (clutter_texture_quality_filters)); if (min_filter_p) *min_filter_p = clutter_texture_quality_filters[quality].min_filter; if (mag_filter_p) *mag_filter_p = clutter_texture_quality_filters[quality].mag_filter; } static void texture_free_gl_resources (ClutterTexture *texture) { ClutterTexturePrivate *priv = texture->priv; if (priv->pipeline != NULL) { /* We want to keep the layer so that the filter settings will remain but we want to free its resources so we clear the texture handle */ cogl_pipeline_set_layer_texture (priv->pipeline, 0, NULL); } } static void clutter_texture_unrealize (ClutterActor *actor) { ClutterTexture *texture; ClutterTexturePrivate *priv; texture = CLUTTER_TEXTURE(actor); priv = texture->priv; if (priv->pipeline == NULL) return; if (priv->fbo_source != NULL) { /* Free up our fbo handle and texture resources, realize will recreate */ cogl_object_unref (priv->fbo_handle); priv->fbo_handle = NULL; texture_free_gl_resources (texture); return; } CLUTTER_NOTE (TEXTURE, "Texture unrealized"); } static void clutter_texture_realize (ClutterActor *actor) { ClutterTexture *texture; ClutterTexturePrivate *priv; texture = CLUTTER_TEXTURE(actor); priv = texture->priv; if (priv->fbo_source) { CoglTextureFlags flags = COGL_TEXTURE_NONE; CoglHandle tex; /* Handle FBO's */ if (priv->no_slice) flags |= COGL_TEXTURE_NO_SLICING; tex = cogl_texture_new_with_size (priv->image_width, priv->image_height, flags, COGL_PIXEL_FORMAT_RGBA_8888_PRE); cogl_pipeline_set_layer_texture (priv->pipeline, 0, tex); priv->fbo_handle = cogl_offscreen_new_to_texture (tex); /* The pipeline now has a reference to the texture so it will stick around */ cogl_object_unref (tex); if (priv->fbo_handle == NULL) { g_warning ("%s: Offscreen texture creation failed", G_STRLOC); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); return; } clutter_actor_set_size (actor, priv->image_width, priv->image_height); return; } /* If the texture is not a FBO, then realization is a no-op but we * still want to be in REALIZED state to maintain invariants. * ClutterTexture doesn't need to be realized to have a Cogl texture * because Clutter assumes that a GL context is always current so * there is no need to wait to realization time to create the * texture. Although this is slightly odd it would be wasteful to * redundantly store a copy of the texture data in local memory just * so that we can make a texture during realize. */ CLUTTER_NOTE (TEXTURE, "Texture realized"); } static void clutter_texture_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; /* Min request is always 0 since we can scale down or clip */ if (min_width_p) *min_width_p = 0; if (priv->sync_actor_size) { if (natural_width_p) { if (!priv->keep_aspect_ratio || for_height < 0 || priv->image_height <= 0) { *natural_width_p = priv->image_width; } else { /* Set the natural width so as to preserve the aspect ratio */ gfloat ratio = (gfloat) priv->image_width / (gfloat) priv->image_height; *natural_width_p = ratio * for_height; } } } else { if (natural_width_p) *natural_width_p = 0; } } static void clutter_texture_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; /* Min request is always 0 since we can scale down or clip */ if (min_height_p) *min_height_p = 0; if (priv->sync_actor_size) { if (natural_height_p) { if (!priv->keep_aspect_ratio || for_width < 0 || priv->image_width <= 0) { *natural_height_p = priv->image_height; } else { /* Set the natural height so as to preserve the aspect ratio */ gfloat ratio = (gfloat) priv->image_height / (gfloat) priv->image_width; *natural_height_p = ratio * for_width; } } } else { if (natural_height_p) *natural_height_p = 0; } } static void clutter_texture_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv; /* chain up to set actor->allocation */ CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->allocate (self, box, flags); /* If we adopted the source fbo then allocate that at its preferred size */ if (priv->fbo_source && clutter_actor_get_parent (priv->fbo_source) == self) clutter_actor_allocate_preferred_size (priv->fbo_source, flags); } static gboolean clutter_texture_has_overlaps (ClutterActor *self) { /* Textures never need an offscreen redirect because there are never any overlapping primitives */ return FALSE; } static void set_viewport_with_buffer_under_fbo_source (ClutterActor *fbo_source, int viewport_width, int viewport_height) { ClutterActorBox box = { 0, }; float x_offset, y_offset; if (clutter_actor_get_paint_box (fbo_source, &box)) clutter_actor_box_get_origin (&box, &x_offset, &y_offset); else { /* As a fallback when the paint box can't be determined we use * the transformed allocation to come up with an offset instead. * * FIXME: when we don't have a paint box we should instead be * falling back to a stage sized fbo with an offset of (0,0) */ ClutterVertex verts[4]; float x_min = G_MAXFLOAT, y_min = G_MAXFLOAT; int i; /* Get the actors allocation transformed into screen coordinates. * * XXX: Note: this may not be a bounding box for the actor, since an * actor with depth may escape the box due to its perspective * projection. */ clutter_actor_get_abs_allocation_vertices (fbo_source, verts); for (i = 0; i < G_N_ELEMENTS (verts); ++i) { if (verts[i].x < x_min) x_min = verts[i].x; if (verts[i].y < y_min) y_min = verts[i].y; } /* XXX: It's not good enough to round by simply truncating the fraction here * via a cast, as it results in offscreen rendering being offset by 1 pixel * in many cases... */ #define ROUND(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x) - 0.5)) x_offset = ROUND (x_min); y_offset = ROUND (y_min); #undef ROUND } /* translate the viewport so that the source actor lands on the * sub-region backed by the offscreen framebuffer... */ cogl_set_viewport (-x_offset, -y_offset, viewport_width, viewport_height); } static void update_fbo (ClutterActor *self) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; ClutterActor *head; ClutterShader *shader = NULL; ClutterActor *stage = NULL; CoglMatrix projection; CoglColor transparent_col; head = _clutter_context_peek_shader_stack (); if (head != NULL) shader = clutter_actor_get_shader (head); /* Temporarily turn off the shader on the top of the context's * shader stack, to restore the GL pipeline to it's natural state. */ if (shader != NULL) clutter_shader_set_is_enabled (shader, FALSE); /* Redirect drawing to the fbo */ cogl_push_framebuffer (priv->fbo_handle); if ((stage = clutter_actor_get_stage (self)) != NULL) { gfloat stage_width, stage_height; ClutterActor *source_parent; /* We copy the projection and modelview matrices from the stage to * the offscreen framebuffer and create a viewport larger than the * offscreen framebuffer - the same size as the stage. * * The fbo source actor gets rendered into this stage size viewport at the * same position it normally would after applying all it's usual parent * transforms and it's own scale and rotate transforms etc. * * The viewport is offset such that the offscreen buffer will be positioned * under the actor. */ _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection); /* Set the projection matrix modelview matrix as it is for the * stage... */ cogl_set_projection_matrix (&projection); clutter_actor_get_size (stage, &stage_width, &stage_height); /* Set a negatively offset the viewport so that the offscreen * framebuffer is position underneath the fbo_source actor... */ set_viewport_with_buffer_under_fbo_source (priv->fbo_source, stage_width, stage_height); /* Apply the source's parent transformations to the modelview */ if ((source_parent = clutter_actor_get_parent (priv->fbo_source))) { CoglMatrix modelview; cogl_matrix_init_identity (&modelview); _clutter_actor_apply_relative_transformation_matrix (source_parent, NULL, &modelview); cogl_set_modelview_matrix (&modelview); } } /* cogl_clear is called to clear the buffers */ cogl_color_init_from_4ub (&transparent_col, 0, 0, 0, 0); cogl_clear (&transparent_col, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH); /* Render the actor to the fbo */ clutter_actor_paint (priv->fbo_source); /* Restore drawing to the previous framebuffer */ cogl_pop_framebuffer (); /* If there is a shader on top of the shader stack, turn it back on. */ if (shader != NULL) clutter_shader_set_is_enabled (shader, TRUE); } static void gen_texcoords_and_draw_cogl_rectangle (ClutterActor *self) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; ClutterActorBox box; float t_w, t_h; clutter_actor_get_allocation_box (self, &box); if (priv->repeat_x && priv->image_width > 0) t_w = (box.x2 - box.x1) / (float) priv->image_width; else t_w = 1.0; if (priv->repeat_y && priv->image_height > 0) t_h = (box.y2 - box.y1) / (float) priv->image_height; else t_h = 1.0; cogl_rectangle_with_texture_coords (0, 0, box.x2 - box.x1, box.y2 - box.y1, 0, 0, t_w, t_h); } static CoglPipeline * create_pick_pipeline (ClutterActor *self) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; CoglPipeline *pick_pipeline = cogl_pipeline_copy (texture_template_pipeline); GError *error = NULL; if (!cogl_pipeline_set_layer_combine (pick_pipeline, 0, "RGBA = " " MODULATE (CONSTANT, TEXTURE[A])", &error)) { if (!priv->seen_create_pick_pipeline_warning) g_warning ("Error setting up texture combine for shaped " "texture picking: %s", error->message); priv->seen_create_pick_pipeline_warning = TRUE; g_error_free (error); cogl_object_unref (pick_pipeline); return NULL; } cogl_pipeline_set_blend (pick_pipeline, "RGBA = ADD (SRC_COLOR[RGBA], 0)", NULL); cogl_pipeline_set_alpha_test_function (pick_pipeline, COGL_PIPELINE_ALPHA_FUNC_EQUAL, 1.0); return pick_pipeline; } static void clutter_texture_pick (ClutterActor *self, const ClutterColor *color) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; if (!clutter_actor_should_pick_paint (self)) return; if (G_LIKELY (priv->pick_with_alpha_supported) && priv->pick_with_alpha) { CoglColor pick_color; if (priv->pick_pipeline == NULL) priv->pick_pipeline = create_pick_pipeline (self); if (priv->pick_pipeline == NULL) { priv->pick_with_alpha_supported = FALSE; CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->pick (self, color); return; } if (priv->fbo_handle != NULL) update_fbo (self); cogl_color_init_from_4ub (&pick_color, color->red, color->green, color->blue, 0xff); cogl_pipeline_set_layer_combine_constant (priv->pick_pipeline, 0, &pick_color); cogl_pipeline_set_layer_texture (priv->pick_pipeline, 0, clutter_texture_get_cogl_texture (texture)); cogl_set_source (priv->pick_pipeline); gen_texcoords_and_draw_cogl_rectangle (self); } else CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)->pick (self, color); } static void clutter_texture_paint (ClutterActor *self) { ClutterTexture *texture = CLUTTER_TEXTURE (self); ClutterTexturePrivate *priv = texture->priv; guint8 paint_opacity = clutter_actor_get_paint_opacity (self); CLUTTER_NOTE (PAINT, "painting texture '%s'", clutter_actor_get_name (self) ? clutter_actor_get_name (self) : "unknown"); if (priv->fbo_handle != NULL) update_fbo (self); cogl_pipeline_set_color4ub (priv->pipeline, paint_opacity, paint_opacity, paint_opacity, paint_opacity); cogl_set_source (priv->pipeline); gen_texcoords_and_draw_cogl_rectangle (self); } static gboolean clutter_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { ClutterTexturePrivate *priv; priv = CLUTTER_TEXTURE (self)->priv; if (priv->pipeline == NULL) return FALSE; if (priv->image_width == 0 || priv->image_height == 0) return FALSE; return _clutter_actor_set_default_paint_volume (self, CLUTTER_TYPE_TEXTURE, volume); } static void clutter_texture_async_data_free (ClutterTextureAsyncData *data) { /* This function should only be called either from the main thread once it is known that the load thread has completed or from the load thread/upload function itself if the abort flag is true (in which case the main thread has disowned the data) */ free (data->load_filename); if (data->load_bitmap != NULL) cogl_object_unref (data->load_bitmap); if (data->load_error != NULL) g_error_free (data->load_error); g_slice_free (ClutterTextureAsyncData, data); } /* * clutter_texture_async_load_cancel: * @texture: a #ClutterTexture * * Cancels an asynchronous loading operation, whether done * with threads enabled or just using the main loop */ static void clutter_texture_async_load_cancel (ClutterTexture *texture) { ClutterTexturePrivate *priv = texture->priv; if (priv->async_data != NULL) { ClutterTextureAsyncData *async_data = priv->async_data; priv->async_data = NULL; if (async_data->load_idle != 0) { g_source_remove (async_data->load_idle); async_data->load_idle = 0; clutter_texture_async_data_free (async_data); } else { clutter_texture_async_data_lock (async_data); CLUTTER_NOTE (TEXTURE, "[async] cancelling operation for '%s'", async_data->load_filename); async_data->state |= ASYNC_STATE_CANCELLED; clutter_texture_async_data_unlock (async_data); } } } static void clutter_texture_dispose (GObject *object) { ClutterTexture *texture = CLUTTER_TEXTURE (object); ClutterTexturePrivate *priv = texture->priv; texture_free_gl_resources (texture); texture_fbo_free_resources (texture); clutter_texture_async_load_cancel (texture); if (priv->pipeline != NULL) { cogl_object_unref (priv->pipeline); priv->pipeline = NULL; } if (priv->pick_pipeline != NULL) { cogl_object_unref (priv->pick_pipeline); priv->pick_pipeline = NULL; } G_OBJECT_CLASS (clutter_texture_parent_class)->dispose (object); } static void clutter_texture_finalize (GObject *object) { ClutterTexturePrivate *priv = CLUTTER_TEXTURE (object)->priv; free (priv->filename); G_OBJECT_CLASS (clutter_texture_parent_class)->finalize (object); } static void clutter_texture_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterTexture *texture; ClutterTexturePrivate *priv; texture = CLUTTER_TEXTURE (object); priv = texture->priv; switch (prop_id) { case PROP_SYNC_SIZE: clutter_texture_set_sync_size (texture, g_value_get_boolean (value)); break; case PROP_REPEAT_X: clutter_texture_set_repeat (texture, g_value_get_boolean (value), priv->repeat_y); break; case PROP_REPEAT_Y: clutter_texture_set_repeat (texture, priv->repeat_x, g_value_get_boolean (value)); break; case PROP_FILTER_QUALITY: clutter_texture_set_filter_quality (texture, g_value_get_enum (value)); break; case PROP_COGL_TEXTURE: { CoglHandle hnd = g_value_get_boxed (value); clutter_texture_set_cogl_texture (texture, hnd); } break; case PROP_COGL_MATERIAL: { CoglHandle hnd = g_value_get_boxed (value); clutter_texture_set_cogl_material (texture, hnd); } break; case PROP_FILENAME: clutter_texture_set_from_file (texture, g_value_get_string (value), NULL); break; case PROP_NO_SLICE: priv->no_slice = g_value_get_boolean (value); break; case PROP_KEEP_ASPECT_RATIO: clutter_texture_set_keep_aspect_ratio (texture, g_value_get_boolean (value)); break; case PROP_LOAD_DATA_ASYNC: clutter_texture_set_load_data_async (texture, g_value_get_boolean (value)); break; case PROP_LOAD_ASYNC: clutter_texture_set_load_async (texture, g_value_get_boolean (value)); break; case PROP_PICK_WITH_ALPHA: clutter_texture_set_pick_with_alpha (texture, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_texture_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterTexture *texture; ClutterTexturePrivate *priv; texture = CLUTTER_TEXTURE(object); priv = texture->priv; switch (prop_id) { case PROP_MAX_TILE_WASTE: g_value_set_int (value, clutter_texture_get_max_tile_waste (texture)); break; case PROP_SYNC_SIZE: g_value_set_boolean (value, priv->sync_actor_size); break; case PROP_REPEAT_X: g_value_set_boolean (value, priv->repeat_x); break; case PROP_REPEAT_Y: g_value_set_boolean (value, priv->repeat_y); break; case PROP_FILTER_QUALITY: g_value_set_enum (value, clutter_texture_get_filter_quality (texture)); break; case PROP_COGL_TEXTURE: g_value_set_boxed (value, clutter_texture_get_cogl_texture (texture)); break; case PROP_COGL_MATERIAL: g_value_set_boxed (value, clutter_texture_get_cogl_material (texture)); break; case PROP_NO_SLICE: g_value_set_boolean (value, priv->no_slice); break; case PROP_KEEP_ASPECT_RATIO: g_value_set_boolean (value, priv->keep_aspect_ratio); break; case PROP_PICK_WITH_ALPHA: g_value_set_boolean (value, priv->pick_with_alpha); break; case PROP_FILENAME: g_value_set_string (value, priv->filename); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_texture_class_init (ClutterTextureClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GParamSpec *pspec; actor_class->paint = clutter_texture_paint; actor_class->pick = clutter_texture_pick; actor_class->get_paint_volume = clutter_texture_get_paint_volume; actor_class->realize = clutter_texture_realize; actor_class->unrealize = clutter_texture_unrealize; actor_class->has_overlaps = clutter_texture_has_overlaps; actor_class->get_preferred_width = clutter_texture_get_preferred_width; actor_class->get_preferred_height = clutter_texture_get_preferred_height; actor_class->allocate = clutter_texture_allocate; gobject_class->dispose = clutter_texture_dispose; gobject_class->finalize = clutter_texture_finalize; gobject_class->set_property = clutter_texture_set_property; gobject_class->get_property = clutter_texture_get_property; pspec = g_param_spec_boolean ("sync-size", P_("Sync size of actor"), P_("Auto sync size of actor to underlying pixbuf dimensions"), TRUE, CLUTTER_PARAM_READWRITE); obj_props[PROP_SYNC_SIZE] = pspec; g_object_class_install_property (gobject_class, PROP_SYNC_SIZE, pspec); pspec = g_param_spec_boolean ("disable-slicing", P_("Disable Slicing"), P_("Forces the underlying texture to be singular and not made of smaller space saving " "individual textures"), FALSE, G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE); obj_props[PROP_NO_SLICE] = pspec; g_object_class_install_property (gobject_class, PROP_NO_SLICE, pspec); pspec = g_param_spec_int ("tile-waste", P_("Tile Waste"), P_("Maximum waste area of a sliced texture"), -1, G_MAXINT, COGL_TEXTURE_MAX_WASTE, CLUTTER_PARAM_READABLE); obj_props[PROP_MAX_TILE_WASTE] = pspec; g_object_class_install_property (gobject_class, PROP_MAX_TILE_WASTE, pspec); pspec = g_param_spec_boolean ("repeat-x", P_("Horizontal repeat"), P_("Repeat the contents rather than scaling them horizontally"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_REPEAT_X] = pspec; g_object_class_install_property (gobject_class, PROP_REPEAT_X, pspec); pspec = g_param_spec_boolean ("repeat-y", P_("Vertical repeat"), P_("Repeat the contents rather than scaling them vertically"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_REPEAT_Y] = pspec; g_object_class_install_property (gobject_class, PROP_REPEAT_Y, pspec); pspec = g_param_spec_enum ("filter-quality", P_("Filter Quality"), P_("Rendering quality used when drawing the texture"), CLUTTER_TYPE_TEXTURE_QUALITY, CLUTTER_TEXTURE_QUALITY_MEDIUM, G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE); obj_props[PROP_FILTER_QUALITY] = pspec; g_object_class_install_property (gobject_class, PROP_FILTER_QUALITY, pspec); pspec = g_param_spec_boxed ("cogl-texture", P_("Cogl Texture"), P_("The underlying Cogl texture handle used to draw this actor"), COGL_TYPE_HANDLE, CLUTTER_PARAM_READWRITE); obj_props[PROP_COGL_TEXTURE] = pspec; g_object_class_install_property (gobject_class, PROP_COGL_TEXTURE, pspec); pspec = g_param_spec_boxed ("cogl-material", P_("Cogl Material"), P_("The underlying Cogl material handle used to draw this actor"), COGL_TYPE_HANDLE, CLUTTER_PARAM_READWRITE); obj_props[PROP_COGL_MATERIAL] = pspec; g_object_class_install_property (gobject_class, PROP_COGL_MATERIAL, pspec); /** * ClutterTexture:filename: * * The path of the file containing the image data to be displayed by * the texture. * * This property is unset when using the clutter_texture_set_from_*_data() * family of functions. * * Deprecated: 1.12: Use #ClutterImage and platform-specific image loading * API, like GdkPixbuf */ pspec = g_param_spec_string ("filename", P_("Filename"), P_("The path of the file containing the image data"), NULL, CLUTTER_PARAM_READWRITE); obj_props[PROP_FILENAME] = pspec; g_object_class_install_property (gobject_class, PROP_FILENAME, pspec); pspec = g_param_spec_boolean ("keep-aspect-ratio", P_("Keep Aspect Ratio"), P_("Keep the aspect ratio of the texture when requesting the preferred width or height"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_KEEP_ASPECT_RATIO] = pspec; g_object_class_install_property (gobject_class, PROP_KEEP_ASPECT_RATIO, pspec); /** * ClutterTexture:load-async: * * Tries to load a texture from a filename by using a local thread to perform * the read operations. The initially created texture has dimensions 0x0 when * the true size becomes available the #ClutterTexture::size-change signal is * emitted and when the image has completed loading the * #ClutterTexture::load-finished signal is emitted. * * Threading is only enabled if g_thread_init() has been called prior to * clutter_init(), otherwise #ClutterTexture will use the main loop to load * the image. * * The upload of the texture data on the GL pipeline is not asynchronous, as * it must be performed from within the same thread that called * clutter_main(). * * Since: 1.0 * * Deprecated: 1.12: Use platform-specific image loading API, like GdkPixbuf */ pspec = g_param_spec_boolean ("load-async", P_("Load asynchronously"), P_("Load files inside a thread to avoid blocking when loading images from disk"), FALSE, CLUTTER_PARAM_WRITABLE); obj_props[PROP_LOAD_ASYNC] = pspec; g_object_class_install_property (gobject_class, PROP_LOAD_ASYNC, pspec); /** * ClutterTexture:load-data-async: * * Like #ClutterTexture:load-async but loads the width and height * synchronously causing some blocking. * * Since: 1.0 * * Deprecated: 1.12: Use platform-specific image loading API, like GdkPixbuf */ pspec = g_param_spec_boolean ("load-data-async", P_("Load data asynchronously"), P_("Decode image data files inside a thread to reduce blocking when loading images from disk"), FALSE, CLUTTER_PARAM_WRITABLE); obj_props[PROP_LOAD_DATA_ASYNC] = pspec; g_object_class_install_property (gobject_class, PROP_LOAD_DATA_ASYNC, pspec); /** * ClutterTexture::pick-with-alpha: * * Determines whether a #ClutterTexture should have it's shape defined * by its alpha channel when picking. * * Be aware that this is a bit more costly than the default picking * due to the texture lookup, extra test against the alpha value and * the fact that it will also interrupt the batching of geometry * done internally. * * Also there is currently no control over the threshold used to * determine what value of alpha is considered pickable, and so * only fully opaque parts of the texture will react to picking. * * Since: 1.4 * * Deprecated: 1.12: No replacement is available */ pspec = g_param_spec_boolean ("pick-with-alpha", P_("Pick With Alpha"), P_("Shape actor with alpha channel when picking"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_PICK_WITH_ALPHA] = pspec; g_object_class_install_property (gobject_class, PROP_PICK_WITH_ALPHA, pspec); /** * ClutterTexture::size-change: * @texture: the texture which received the signal * @width: the width of the new texture * @height: the height of the new texture * * The ::size-change signal is emitted each time the size of the * pixbuf used by @texture changes. The new size is given as * argument to the callback. * * Deprecated: 1.12: No replacement is available */ texture_signals[SIZE_CHANGE] = g_signal_new ("size-change", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTextureClass, size_change), NULL, NULL, _clutter_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); /** * ClutterTexture::pixbuf-change: * @texture: the texture which received the signal * * The ::pixbuf-change signal is emitted each time the pixbuf * used by @texture changes. * * Deprecated: 1.12: No replacement is available */ texture_signals[PIXBUF_CHANGE] = g_signal_new ("pixbuf-change", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTextureClass, pixbuf_change), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterTexture::load-finished: * @texture: the texture which received the signal * @error: A set error, or %NULL * * The ::load-finished signal is emitted when a texture load has * completed. If there was an error during loading, @error will * be set, otherwise it will be %NULL * * Since: 1.0 * * Deprecated: 1.12: No replacement is available */ texture_signals[LOAD_FINISHED] = g_signal_new (I_("load-finished"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterTextureClass, load_finished), NULL, NULL, _clutter_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ERROR); } static ClutterScriptableIface *parent_scriptable_iface = NULL; static void clutter_texture_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { ClutterTexture *texture = CLUTTER_TEXTURE (scriptable); if (strcmp ("filename", name) == 0) { const gchar *str = g_value_get_string (value); gchar *path; GError *error; path = clutter_script_lookup_filename (script, str); if (G_UNLIKELY (!path)) { g_warning ("Unable to find image %s", str); return; } error = NULL; clutter_texture_set_from_file (texture, path, &error); if (error) { g_warning ("Unable to open image path at '%s': %s", path, error->message); g_error_free (error); } free (path); } else { /* chain up */ if (parent_scriptable_iface->set_custom_property) parent_scriptable_iface->set_custom_property (scriptable, script, name, value); } } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { parent_scriptable_iface = g_type_interface_peek_parent (iface); if (!parent_scriptable_iface) parent_scriptable_iface = g_type_default_interface_peek (CLUTTER_TYPE_SCRIPTABLE); iface->set_custom_property = clutter_texture_set_custom_property; } static void clutter_texture_init (ClutterTexture *self) { ClutterTexturePrivate *priv; self->priv = priv = clutter_texture_get_instance_private (self); priv->repeat_x = FALSE; priv->repeat_y = FALSE; priv->sync_actor_size = TRUE; priv->fbo_handle = NULL; priv->pick_pipeline = NULL; priv->keep_aspect_ratio = FALSE; priv->pick_with_alpha = FALSE; priv->pick_with_alpha_supported = TRUE; priv->seen_create_pick_pipeline_warning = FALSE; if (G_UNLIKELY (texture_template_pipeline == NULL)) { CoglPipeline *pipeline; CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); texture_template_pipeline = cogl_pipeline_new (ctx); pipeline = COGL_PIPELINE (texture_template_pipeline); cogl_pipeline_set_layer_null_texture (pipeline, 0, /* layer_index */ COGL_TEXTURE_TYPE_2D); } g_assert (texture_template_pipeline != NULL); priv->pipeline = cogl_pipeline_copy (texture_template_pipeline); } /** * clutter_texture_get_cogl_material: * @texture: A #ClutterTexture * * Returns a handle to the underlying COGL material used for drawing * the actor. * * Return value: (transfer none): a handle for a #CoglMaterial. The * material is owned by the #ClutterTexture and it should not be * unreferenced * * Since: 1.0 * * Deprecated: 1.12: No replacement is available; it's not advisable * to modify the Cogl pipeline of an actor. Use a #ClutterContent * implementation and modify the pipeline during the paint sequence */ CoglHandle clutter_texture_get_cogl_material (ClutterTexture *texture) { g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), NULL); return texture->priv->pipeline; } /** * clutter_texture_set_cogl_material: * @texture: A #ClutterTexture * @cogl_material: A CoglHandle for a material * * Replaces the underlying Cogl material drawn by this actor with * @cogl_material. A reference to the material is taken so if the * handle is no longer needed it should be deref'd with * cogl_handle_unref. Texture data is attached to the material so * calling this function also replaces the Cogl * texture. #ClutterTexture requires that the material have a texture * layer so you should set one on the material before calling this * function. * * Since: 0.8 * * Deprecated: 1.12: No replacement is available; it's not advisable * to modify the Cogl pipeline of an actor. Use a #ClutterContent * implementation and modify the pipeline during the paint sequence */ void clutter_texture_set_cogl_material (ClutterTexture *texture, CoglHandle cogl_material) { CoglPipeline *cogl_pipeline = cogl_material; CoglHandle cogl_texture; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); cogl_object_ref (cogl_pipeline); if (texture->priv->pipeline) cogl_object_unref (texture->priv->pipeline); texture->priv->pipeline = cogl_pipeline; /* XXX: We are re-asserting the first layer of the new pipeline to ensure the * priv state is in sync with the contents of the pipeline. */ cogl_texture = clutter_texture_get_cogl_texture (texture); clutter_texture_set_cogl_texture (texture, cogl_texture); /* XXX: If we add support for more pipeline layers, this will need * extending */ } typedef struct _GetLayerState { gboolean has_layer; int first_layer; } GetLayerState; static gboolean layer_cb (CoglPipeline *pipeline, int layer, void *user_data) { GetLayerState *state = user_data; state->has_layer = TRUE; state->first_layer = layer; /* We only care about the first layer. */ return FALSE; } static gboolean get_first_layer_index (CoglPipeline *pipeline, int *layer_index) { GetLayerState state = { FALSE }; cogl_pipeline_foreach_layer (pipeline, layer_cb, &state); if (state.has_layer) *layer_index = state.first_layer; return state.has_layer; } /** * clutter_texture_get_cogl_texture: * @texture: A #ClutterTexture * * Retrieves the handle to the underlying COGL texture used for drawing * the actor. No extra reference is taken so if you need to keep the * handle then you should call cogl_handle_ref() on it. * * The texture handle returned is the first layer of the material * handle used by the #ClutterTexture. If you need to access the other * layers you should use clutter_texture_get_cogl_material() instead * and use the #CoglMaterial API. * * Return value: (transfer none): a #CoglHandle for the texture. The returned * handle is owned by the #ClutterTexture and it should not be unreferenced * * Since: 0.8 * * Deprecated: 1.12: No replacement available; it's not advisable to * modify the Cogl pipeline of an actor. Use a #ClutterContent * implementation and set up the pipeline during the paint sequence * instead. */ CoglHandle clutter_texture_get_cogl_texture (ClutterTexture *texture) { ClutterTexturePrivate *priv; int layer_index; g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), NULL); priv = texture->priv; if (get_first_layer_index (priv->pipeline, &layer_index)) return cogl_pipeline_get_layer_texture (priv->pipeline, layer_index); else return NULL; } /** * clutter_texture_set_cogl_texture: * @texture: A #ClutterTexture * @cogl_tex: A CoglHandle for a texture * * Replaces the underlying COGL texture drawn by this actor with * @cogl_tex. A reference to the texture is taken so if the handle is * no longer needed it should be deref'd with cogl_handle_unref. * * Since: 0.8 * * Deprecated: 1.12: No replacement available; it's not advisable to * modify the Cogl pipeline of an actor. Use a #ClutterContent * implementation and set up the pipeline during the paint sequence * instead. */ void clutter_texture_set_cogl_texture (ClutterTexture *texture, CoglHandle cogl_tex) { ClutterTexturePrivate *priv; gboolean size_changed; guint width, height; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); g_return_if_fail (cogl_is_texture (cogl_tex)); /* This function can set the texture without the actor being realized. This is ok because Clutter requires that the GL context always be current so there is no point in waiting to realization to set the texture. */ priv = texture->priv; width = cogl_texture_get_width (cogl_tex); height = cogl_texture_get_height (cogl_tex); /* Reference the new texture now in case it is the same one we are already using */ cogl_object_ref (cogl_tex); /* Remove FBO if exisiting */ if (priv->fbo_source) texture_fbo_free_resources (texture); /* Remove old texture */ texture_free_gl_resources (texture); /* Use the new texture */ if (priv->pipeline == NULL) priv->pipeline = cogl_pipeline_copy (texture_template_pipeline); g_assert (priv->pipeline != NULL); cogl_pipeline_set_layer_texture (priv->pipeline, 0, cogl_tex); /* The pipeline now holds a reference to the texture so we can safely release the reference we claimed above */ cogl_object_unref (cogl_tex); size_changed = (width != priv->image_width || height != priv->image_height); priv->image_width = width; priv->image_height = height; CLUTTER_NOTE (TEXTURE, "set size (w:%d, h:%d)", priv->image_width, priv->image_height); if (size_changed) { g_signal_emit (texture, texture_signals[SIZE_CHANGE], 0, priv->image_width, priv->image_height); if (priv->sync_actor_size) { ClutterActor *actor = CLUTTER_ACTOR (texture); /* we have been requested to keep the actor size in * sync with the texture data; if we also want to * maintain the aspect ratio we want to change the * requisition mode depending on the orientation of * the texture, so that the parent container can do * the right thing */ if (priv->keep_aspect_ratio) { ClutterRequestMode request; if (priv->image_width >= priv->image_height) request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH; else request = CLUTTER_REQUEST_WIDTH_FOR_HEIGHT; clutter_actor_set_request_mode (actor, request); } clutter_actor_queue_relayout (CLUTTER_ACTOR (texture)); } } /* rename signal */ g_signal_emit (texture, texture_signals[PIXBUF_CHANGE], 0); /* If resized actor may need resizing but paint() will do this */ clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_COGL_TEXTURE]); } static gboolean clutter_texture_set_from_data (ClutterTexture *texture, const guchar *data, CoglPixelFormat source_format, gint width, gint height, gint rowstride, gint bpp, GError **error) { ClutterTexturePrivate *priv = texture->priv; CoglHandle new_texture = NULL; CoglTextureFlags flags = COGL_TEXTURE_NONE; if (priv->no_slice) flags |= COGL_TEXTURE_NO_SLICING; /* FIXME if we are not realized, we should store the data * for future use, instead of creating the texture. */ new_texture = cogl_texture_new_from_data (width, height, flags, source_format, COGL_PIXEL_FORMAT_ANY, rowstride, data); if (G_UNLIKELY (new_texture == NULL)) { GError *inner_error = NULL; g_set_error (&inner_error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, _("Failed to load the image data")); g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, inner_error); if (error != NULL) g_propagate_error (error, inner_error); else g_error_free (inner_error); return FALSE; } free (priv->filename); priv->filename = NULL; clutter_texture_set_cogl_texture (texture, new_texture); cogl_object_unref (new_texture); g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, NULL); return TRUE; } static inline gboolean get_pixel_format_from_texture_flags (gint bpp, gboolean has_alpha, ClutterTextureFlags flags, CoglPixelFormat *source_format) { /* Convert the flags to a CoglPixelFormat */ if (has_alpha) { if (G_UNLIKELY (bpp != 4)) { g_warning ("Unsupported bytes per pixel value '%d': " "Clutter supports only a value of 4 " "for RGBA data", bpp); return FALSE; } *source_format = COGL_PIXEL_FORMAT_RGBA_8888; } else { if (G_UNLIKELY (bpp != 3)) { g_warning ("Unsupported bytes per pixel value '%d': " "Clutter supports only a BPP value of 3 " "for RGB data", bpp); return FALSE; } *source_format = COGL_PIXEL_FORMAT_RGB_888; } if ((flags & CLUTTER_TEXTURE_RGB_FLAG_BGR)) *source_format |= COGL_BGR_BIT; if ((flags & CLUTTER_TEXTURE_RGB_FLAG_PREMULT)) *source_format |= COGL_PREMULT_BIT; return TRUE; } /** * clutter_texture_set_from_rgb_data: * @texture: a #ClutterTexture * @data: (array): image data in RGBA type colorspace. * @has_alpha: set to %TRUE if image data has an alpha channel. * @width: width in pixels of image data. * @height: height in pixels of image data * @rowstride: distance in bytes between row starts. * @bpp: bytes per pixel (currently only 3 and 4 supported, depending * on the value of @has_alpha) * @flags: #ClutterTextureFlags * @error: return location for a #GError, or %NULL. * * Sets #ClutterTexture image data. * * Return value: %TRUE on success, %FALSE on failure. * * Since: 0.4 * * Deprecated: 1.12: Use #ClutterImage and clutter_image_set_data() instead */ gboolean clutter_texture_set_from_rgb_data (ClutterTexture *texture, const guchar *data, gboolean has_alpha, gint width, gint height, gint rowstride, gint bpp, ClutterTextureFlags flags, GError **error) { CoglPixelFormat source_format; g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); if (!get_pixel_format_from_texture_flags (bpp, has_alpha, flags, &source_format)) { return FALSE; } return clutter_texture_set_from_data (texture, data, source_format, width, height, rowstride, bpp, error); } /** * clutter_texture_set_from_yuv_data: * @texture: A #ClutterTexture * @data: (array): Image data in YUV type colorspace. * @width: Width in pixels of image data. * @height: Height in pixels of image data * @flags: #ClutterTextureFlags * @error: Return location for a #GError, or %NULL. * * Sets a #ClutterTexture from YUV image data. If an error occurred, * %FALSE is returned and @error is set. * * The YUV support depends on the driver; the format supported by the * few drivers exposing this capability are not really useful. * * The proper way to convert image data in any YUV colorspace to any * RGB colorspace is to use a fragment shader associated with the * #ClutterTexture material. * * Return value: %TRUE if the texture was successfully updated * * Since: 0.4 * * Deprecated: 1.10: Use a custom #ClutterContent implementation and * set up the Cogl pipeline using a #ClutterPipelineNode with a * fragment shader instead. */ gboolean clutter_texture_set_from_yuv_data (ClutterTexture *texture, const guchar *data, gint width, gint height, ClutterTextureFlags flags, GError **error) { g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); if (!clutter_feature_available (CLUTTER_FEATURE_TEXTURE_YUV)) { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_NO_YUV, _("YUV textures are not supported")); return FALSE; } /* Convert the flags to a CoglPixelFormat */ if ((flags & CLUTTER_TEXTURE_YUV_FLAG_YUV2)) { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, _("YUV2 textures are not supported")); return FALSE; } return clutter_texture_set_from_data (texture, data, COGL_PIXEL_FORMAT_YUV, width, height, width * 3, 3, error); } /* * clutter_texture_async_load_complete: * @self: a #ClutterTexture * @bitmap: a handle to a CoglBitmap * @error: load error * * If @error is %NULL, loads @bitmap into a #CoglTexture. * * This function emits the ::load-finished signal on @self. */ static void clutter_texture_async_load_complete (ClutterTexture *self, CoglHandle bitmap, const GError *error) { ClutterTexturePrivate *priv = self->priv; CoglTextureFlags flags = COGL_TEXTURE_NONE; CoglHandle handle; priv->async_data = NULL; if (error == NULL) { if (priv->no_slice) flags |= COGL_TEXTURE_NO_SLICING; handle = cogl_texture_new_from_bitmap (bitmap, flags, COGL_PIXEL_FORMAT_ANY); clutter_texture_set_cogl_texture (self, handle); if (priv->load_size_async) { g_signal_emit (self, texture_signals[SIZE_CHANGE], 0, cogl_texture_get_width (handle), cogl_texture_get_height (handle)); } cogl_object_unref (handle); } g_signal_emit (self, texture_signals[LOAD_FINISHED], 0, error); clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); } static gboolean texture_repaint_upload_func (gpointer user_data) { g_mutex_lock (&upload_list_mutex); if (upload_list != NULL) { gint64 start_time = g_get_monotonic_time (); /* continue uploading textures as long as we havent spent more * then 5ms doing so this stage redraw cycle. */ do { ClutterTextureAsyncData *async_data = upload_list->data; clutter_texture_async_data_lock (async_data); if (async_data->state & ASYNC_STATE_QUEUED) { CLUTTER_NOTE (TEXTURE, "[async] operation complete for '%s'", async_data->load_filename); clutter_texture_async_load_complete (async_data->texture, async_data->load_bitmap, async_data->load_error); } else CLUTTER_NOTE (TEXTURE, "[async] operation cancelled for '%s'", async_data->load_filename); clutter_texture_async_data_unlock (async_data); upload_list = g_list_remove (upload_list, async_data); clutter_texture_async_data_free (async_data); } while (upload_list != NULL && g_get_monotonic_time () < start_time + 5 * 1000L); } if (upload_list != NULL) { ClutterMasterClock *master_clock; master_clock = _clutter_master_clock_get_default (); _clutter_master_clock_ensure_next_iteration (master_clock); } g_mutex_unlock (&upload_list_mutex); return TRUE; } static void clutter_texture_thread_load (gpointer user_data, gpointer pool_data) { ClutterTextureAsyncData *async_data = user_data; ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); clutter_texture_async_data_lock (async_data); if (~async_data->state & ASYNC_STATE_CANCELLED) { CLUTTER_NOTE (TEXTURE, "[async] loading bitmap from file '%s'", async_data->load_filename); async_data->load_bitmap = cogl_bitmap_new_from_file (async_data->load_filename, &async_data->load_error); g_mutex_lock (&upload_list_mutex); if (repaint_upload_func == 0) { repaint_upload_func = clutter_threads_add_repaint_func (texture_repaint_upload_func, NULL, NULL); } upload_list = g_list_append (upload_list, async_data); async_data->state |= ASYNC_STATE_QUEUED; CLUTTER_NOTE (TEXTURE, "[async] operation queued"); g_mutex_unlock (&upload_list_mutex); } else { clutter_texture_async_data_unlock (async_data); clutter_texture_async_data_free (async_data); return; } clutter_texture_async_data_unlock (async_data); _clutter_master_clock_ensure_next_iteration (master_clock); } static gboolean clutter_texture_idle_load (gpointer data) { ClutterTextureAsyncData *async_data = data; async_data->load_bitmap = cogl_bitmap_new_from_file (async_data->load_filename, &async_data->load_error); clutter_texture_async_load_complete (async_data->texture, async_data->load_bitmap, async_data->load_error); clutter_texture_async_data_free (async_data); return FALSE; } /* * clutter_texture_async_load: * @self: a #ClutterTExture * @filename: name of the file to load * @error: return location for a #GError * * Starts an asynchronous load of the file name stored inside * the load_filename member of @data. * * If threading is enabled we use a GThread to perform the actual * I/O; if threading is not enabled, we use an idle GSource. * * The I/O is the only bit done in a thread -- uploading the * texture data to the GL pipeline must be done from within the * same thread that called clutter_main(). Threaded upload should * be part of the GL implementation. * * This function will block until we get a size from the file * so that we can effectively get the size the texture actor after * clutter_texture_set_from_file(). * * Return value: %TRUE if the asynchronous loading was successfully * initiated, %FALSE otherwise */ static gboolean clutter_texture_async_load (ClutterTexture *self, const gchar *filename, GError **error) { ClutterTexturePrivate *priv = self->priv; ClutterTextureAsyncData *data; gint width, height; gboolean res; /* ask the file for a size; if we cannot get the size then * there's no point in even continuing the asynchronous * loading, so we just stop there */ if (priv->load_size_async) { res = TRUE; width = 0; height = 0; } else res = cogl_bitmap_get_size_from_file (filename, &width, &height); if (!res) { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, _("Failed to load the image data")); return FALSE; } else { priv->image_width = width; priv->image_height = height; } clutter_texture_async_load_cancel (self); data = g_slice_new0 (ClutterTextureAsyncData); data->texture = self; data->load_filename = g_strdup (filename); priv->async_data = data; if (1) { if (G_UNLIKELY (async_thread_pool == NULL)) { /* This apparently can't fail if exclusive == FALSE */ async_thread_pool = g_thread_pool_new (clutter_texture_thread_load, NULL, 1, FALSE, NULL); } g_thread_pool_push (async_thread_pool, data, NULL); } else { data->load_idle = clutter_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE, clutter_texture_idle_load, data, NULL); } return TRUE; } /** * clutter_texture_set_from_file: * @texture: A #ClutterTexture * @filename: The filename of the image in GLib file name encoding * @error: Return location for a #GError, or %NULL * * Sets the #ClutterTexture image data from an image file. In case of * failure, %FALSE is returned and @error is set. * * If #ClutterTexture:load-async is set to %TRUE, this function * will return as soon as possible, and the actual image loading * from disk will be performed asynchronously. #ClutterTexture::size-change * will be emitten when the size of the texture is available and * #ClutterTexture::load-finished will be emitted when the image has been * loaded or if an error occurred. * * Return value: %TRUE if the image was successfully loaded and set * * Since: 0.8 * * Deprecated: 1.12: Use #ClutterImage and platform-specific image * loading API, like GdkPixbuf, instead */ gboolean clutter_texture_set_from_file (ClutterTexture *texture, const gchar *filename, GError **error) { ClutterTexturePrivate *priv; CoglHandle new_texture = NULL; GError *internal_error = NULL; CoglTextureFlags flags = COGL_TEXTURE_NONE; priv = texture->priv; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (priv->load_data_async) return clutter_texture_async_load (texture, filename, error); if (priv->no_slice) flags |= COGL_TEXTURE_NO_SLICING; new_texture = cogl_texture_new_from_file (filename, flags, COGL_PIXEL_FORMAT_ANY, &internal_error); /* If COGL didn't give an error then make one up */ if (internal_error == NULL && new_texture == NULL) { g_set_error (&internal_error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, _("Failed to load the image data")); } if (internal_error != NULL) { g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, internal_error); g_propagate_error (error, internal_error); return FALSE; } free (priv->filename); priv->filename = g_strdup (filename); clutter_texture_set_cogl_texture (texture, new_texture); cogl_object_unref (new_texture); g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, NULL); g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_FILENAME]); return TRUE; } /** * clutter_texture_set_filter_quality: * @texture: a #ClutterTexture * @filter_quality: new filter quality value * * Sets the filter quality when scaling a texture. The quality is an * enumeration currently the following values are supported: * %CLUTTER_TEXTURE_QUALITY_LOW which is fast but only uses nearest neighbour * interpolation. %CLUTTER_TEXTURE_QUALITY_MEDIUM which is computationally a * bit more expensive (bilinear interpolation), and * %CLUTTER_TEXTURE_QUALITY_HIGH which uses extra texture memory resources to * improve scaled down rendering as well (by using mipmaps). The default value * is %CLUTTER_TEXTURE_QUALITY_MEDIUM. * * Since: 0.8 * * Deprecated: 1.12: Use #ClutterImage and clutter_actor_set_content_scaling_filters() * instead */ void clutter_texture_set_filter_quality (ClutterTexture *texture, ClutterTextureQuality filter_quality) { ClutterTexturePrivate *priv; ClutterTextureQuality old_quality; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; old_quality = clutter_texture_get_filter_quality (texture); if (filter_quality != old_quality) { gint min_filter, mag_filter; min_filter = mag_filter = COGL_PIPELINE_FILTER_LINEAR; clutter_texture_quality_to_filters (filter_quality, &min_filter, &mag_filter); cogl_pipeline_set_layer_filters (priv->pipeline, 0, min_filter, mag_filter); clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_FILTER_QUALITY]); } } /** * clutter_texture_get_filter_quality: * @texture: A #ClutterTexture * * Gets the filter quality used when scaling a texture. * * Return value: The filter quality value. * * Since: 0.8 * * Deprecated: 1.12: Use #ClutterImage and clutter_actor_get_content_scaling_filters() * instead */ ClutterTextureQuality clutter_texture_get_filter_quality (ClutterTexture *texture) { ClutterTexturePrivate *priv; int layer_index; CoglPipelineFilter min_filter, mag_filter; int i; g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0); priv = texture->priv; if (get_first_layer_index (priv->pipeline, &layer_index)) { min_filter = cogl_pipeline_get_layer_min_filter (priv->pipeline, layer_index); mag_filter = cogl_pipeline_get_layer_mag_filter (priv->pipeline, layer_index); } else return CLUTTER_TEXTURE_QUALITY_MEDIUM; for (i = 0; i < G_N_ELEMENTS (clutter_texture_quality_filters); i++) if (clutter_texture_quality_filters[i].min_filter == min_filter && clutter_texture_quality_filters[i].mag_filter == mag_filter) return i; /* Unknown filter combination */ return CLUTTER_TEXTURE_QUALITY_LOW; } /** * clutter_texture_get_max_tile_waste: * @texture: A #ClutterTexture * * Gets the maximum waste that will be used when creating a texture or * -1 if slicing is disabled. * * Return value: The maximum waste or -1 if the texture waste is * unlimited. * * Since: 0.8 * * Deprecated: 1.12: No replacement is available */ gint clutter_texture_get_max_tile_waste (ClutterTexture *texture) { ClutterTexturePrivate *priv; CoglHandle cogl_texture; g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0); priv = texture->priv; cogl_texture = clutter_texture_get_cogl_texture (texture); if (cogl_texture == NULL) return priv->no_slice ? -1 : COGL_TEXTURE_MAX_WASTE; else return cogl_texture_get_max_waste (cogl_texture); } /** * clutter_texture_new_from_file: * @filename: The name of an image file to load. * @error: Return locatoin for an error. * * Creates a new ClutterTexture actor to display the image contained a * file. If the image failed to load then NULL is returned and @error * is set. * * Return value: A newly created #ClutterTexture object or NULL on * error. * * Since: 0.8 * * Deprecated: 1.12: No direct replacement is available. Use #ClutterImage * and platform-specific image loading API, like GdkPixbuf, instead */ ClutterActor* clutter_texture_new_from_file (const gchar *filename, GError **error) { ClutterActor *texture = clutter_texture_new (); if (!clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), filename, error)) { g_object_ref_sink (texture); g_object_unref (texture); return NULL; } else return texture; } /** * clutter_texture_new: * * Creates a new empty #ClutterTexture object. * * Return value: A newly created #ClutterTexture object. * * Deprecated: 1.12: Use #ClutterImage instead */ ClutterActor * clutter_texture_new (void) { return g_object_new (CLUTTER_TYPE_TEXTURE, NULL); } /** * clutter_texture_get_base_size: * @texture: a #ClutterTexture * @width: (out): return location for the width, or %NULL * @height: (out): return location for the height, or %NULL * * Gets the size in pixels of the untransformed underlying image * * Deprecated: 1.12: Use #ClutterImage and clutter_content_get_preferred_size() * instead */ void clutter_texture_get_base_size (ClutterTexture *texture, gint *width, gint *height) { g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); if (width) *width = texture->priv->image_width; if (height) *height = texture->priv->image_height; } /** * clutter_texture_set_area_from_rgb_data: * @texture: A #ClutterTexture * @data: (array): Image data in RGB type colorspace. * @has_alpha: Set to TRUE if image data has an alpha channel. * @x: X coordinate of upper left corner of region to update. * @y: Y coordinate of upper left corner of region to update. * @width: Width in pixels of region to update. * @height: Height in pixels of region to update. * @rowstride: Distance in bytes between row starts on source buffer. * @bpp: bytes per pixel (Currently only 3 and 4 supported, * depending on @has_alpha) * @flags: #ClutterTextureFlags * @error: return location for a #GError, or %NULL * * Updates a sub-region of the pixel data in a #ClutterTexture. * * Return value: %TRUE on success, %FALSE on failure. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterImage and clutter_image_set_area() instead */ gboolean clutter_texture_set_area_from_rgb_data (ClutterTexture *texture, const guchar *data, gboolean has_alpha, gint x, gint y, gint width, gint height, gint rowstride, gint bpp, ClutterTextureFlags flags, GError **error) { CoglPixelFormat source_format; CoglHandle cogl_texture; if (!get_pixel_format_from_texture_flags (bpp, has_alpha, flags, &source_format)) { return FALSE; } /* attempt to realize ... */ if (!CLUTTER_ACTOR_IS_REALIZED (texture) && clutter_actor_get_stage (CLUTTER_ACTOR (texture)) != NULL) { clutter_actor_realize (CLUTTER_ACTOR (texture)); } /* due to the fudging of clutter_texture_set_cogl_texture() * which allows setting a texture pre-realize, we may end * up having a texture even if we couldn't realize yet. */ cogl_texture = clutter_texture_get_cogl_texture (texture); if (cogl_texture == NULL) { g_warning ("Failed to realize actor '%s'", _clutter_actor_get_debug_name (CLUTTER_ACTOR (texture))); return FALSE; } if (!cogl_texture_set_region (cogl_texture, 0, 0, x, y, width, height, width, height, source_format, rowstride, data)) { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, _("Failed to load the image data")); return FALSE; } free (texture->priv->filename); texture->priv->filename = NULL; /* rename signal */ g_signal_emit (texture, texture_signals[PIXBUF_CHANGE], 0); clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); return TRUE; } static void on_fbo_source_size_change (GObject *object, GParamSpec *param_spec, ClutterTexture *texture) { ClutterTexturePrivate *priv = texture->priv; gfloat w, h; ClutterActorBox box; gboolean status; status = clutter_actor_get_paint_box (priv->fbo_source, &box); if (status) clutter_actor_box_get_size (&box, &w, &h); /* In the end we will size the framebuffer according to the paint * box, but for code that does: * tex = clutter_texture_new_from_actor (src); * clutter_actor_get_size (tex, &width, &height); * it seems more helpfull to return the src actor size if it has a * degenerate paint box. The most likely reason it will have a * degenerate paint box is simply that the src currently has no * parent. */ if (status == FALSE || w == 0 || h == 0) clutter_actor_get_size (priv->fbo_source, &w, &h); /* We can't create a texture with a width or height of 0... */ w = MAX (1, w); h = MAX (1, h); if (w != priv->image_width || h != priv->image_height) { CoglTextureFlags flags = COGL_TEXTURE_NONE; CoglHandle tex; /* tear down the FBO */ if (priv->fbo_handle != NULL) cogl_object_unref (priv->fbo_handle); texture_free_gl_resources (texture); priv->image_width = w; priv->image_height = h; flags |= COGL_TEXTURE_NO_SLICING; tex = cogl_texture_new_with_size (MAX (priv->image_width, 1), MAX (priv->image_height, 1), flags, COGL_PIXEL_FORMAT_RGBA_8888_PRE); cogl_pipeline_set_layer_texture (priv->pipeline, 0, tex); priv->fbo_handle = cogl_offscreen_new_to_texture (tex); /* The pipeline now has a reference to the texture so it will stick around */ cogl_object_unref (tex); if (priv->fbo_handle == NULL) { g_warning ("%s: Offscreen texture creation failed", G_STRLOC); return; } clutter_actor_set_size (CLUTTER_ACTOR (texture), w, h); } } static void on_fbo_parent_change (ClutterActor *actor, ClutterActor *old_parent, ClutterTexture *texture) { ClutterActor *parent = CLUTTER_ACTOR(texture); while ((parent = clutter_actor_get_parent (parent)) != NULL) { if (parent == actor) { g_warning ("Offscreen texture is ancestor of source!"); /* Desperate but will avoid infinite loops */ clutter_actor_remove_child (parent, actor); } } } static void fbo_source_queue_redraw_cb (ClutterActor *source, ClutterActor *origin, ClutterTexture *texture) { clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); } static void fbo_source_queue_relayout_cb (ClutterActor *source, ClutterTexture *texture) { clutter_actor_queue_relayout (CLUTTER_ACTOR (texture)); } /** * clutter_texture_new_from_actor: * @actor: A source #ClutterActor * * Creates a new #ClutterTexture object with its source a prexisting * actor (and associated children). The textures content will contain * 'live' redirected output of the actors scene. * * Note this function is intented as a utility call for uniformly applying * shaders to groups and other potential visual effects. It requires that * the %CLUTTER_FEATURE_OFFSCREEN feature is supported by the current backend * and the target system. * * Some tips on usage: * * - The source actor must be visible * - The source actor must have a parent in order for it to be * allocated a size from the layouting mechanism. If the source * actor does not have a parent when this function is called then * the ClutterTexture will adopt it and allocate it at its * preferred size. Using this you can clone an actor that is * otherwise not displayed. Because of this feature if you do * intend to display the source actor then you must make sure that * the actor is parented before calling * clutter_texture_new_from_actor() or that you unparent it before * adding it to a container. * - When getting the image for the clone texture, Clutter * will attempt to render the source actor exactly as it would * appear if it was rendered on screen. The source actor's parent * transformations are taken into account. Therefore if your * source actor is rotated along the X or Y axes so that it has * some depth, the texture will appear differently depending on * the on-screen location of the source actor. While painting the * source actor, Clutter will set up a temporary asymmetric * perspective matrix as the projection matrix so that the source * actor will be projected as if a small section of the screen was * being viewed. Before version 0.8.2, an orthogonal identity * projection was used which meant that the source actor would be * clipped if any part of it was not on the zero Z-plane. * - Avoid reparenting the source with the created texture. * - A group can be padded with a transparent rectangle as to * provide a border to contents for shader output (blurring text * for example). * - The texture will automatically resize to contain a further * transformed source. However, this involves overhead and can be * avoided by placing the source actor in a bounding group * sized large enough to contain any child tranformations. * - Uploading pixel data to the texture (e.g by using * clutter_texture_set_from_file()) will destroy the offscreen texture * data and end redirection. * - cogl_texture_get_data() with the handle returned by * clutter_texture_get_cogl_texture() can be used to read the * offscreen texture pixels into a pixbuf. * * Return value: A newly created #ClutterTexture object, or %NULL on failure. * * Since: 0.6 * * Deprecated: 1.8: Use the #ClutterOffscreenEffect and #ClutterShaderEffect * directly on the intended #ClutterActor to replace the functionality of * this function. */ ClutterActor * clutter_texture_new_from_actor (ClutterActor *actor) { ClutterTexture *texture; ClutterTexturePrivate *priv; gfloat w, h; ClutterActorBox box; gboolean status; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); if (clutter_feature_available (CLUTTER_FEATURE_OFFSCREEN) == FALSE) return NULL; if (!CLUTTER_ACTOR_IS_REALIZED (actor)) { clutter_actor_realize (actor); if (!CLUTTER_ACTOR_IS_REALIZED (actor)) return NULL; } status = clutter_actor_get_paint_box (actor, &box); if (status) clutter_actor_box_get_size (&box, &w, &h); /* In the end we will size the framebuffer according to the paint * box, but for code that does: * tex = clutter_texture_new_from_actor (src); * clutter_actor_get_size (tex, &width, &height); * it seems more helpfull to return the src actor size if it has a * degenerate paint box. The most likely reason it will have a * degenerate paint box is simply that the src currently has no * parent. */ if (status == FALSE || w == 0 || h == 0) clutter_actor_get_size (actor, &w, &h); /* We can't create a 0x0 fbo so always bump the size up to at least * 1 */ w = MAX (1, w); h = MAX (1, h); /* Hopefully now were good.. */ texture = g_object_new (CLUTTER_TYPE_TEXTURE, "disable-slicing", TRUE, NULL); priv = texture->priv; priv->fbo_source = g_object_ref_sink (actor); /* If the actor doesn't have a parent then claim it so that it will get a size allocation during layout */ if (clutter_actor_get_parent (actor) == NULL) clutter_actor_add_child (CLUTTER_ACTOR (texture), actor); /* Connect up any signals which could change our underlying size */ g_signal_connect (actor, "notify::width", G_CALLBACK(on_fbo_source_size_change), texture); g_signal_connect (actor, "notify::height", G_CALLBACK(on_fbo_source_size_change), texture); g_signal_connect (actor, "notify::scale-x", G_CALLBACK(on_fbo_source_size_change), texture); g_signal_connect (actor, "notify::scale-y", G_CALLBACK(on_fbo_source_size_change), texture); g_signal_connect (actor, "notify::rotation-angle-x", G_CALLBACK(on_fbo_source_size_change), texture); g_signal_connect (actor, "notify::rotation-angle-y", G_CALLBACK(on_fbo_source_size_change), texture); g_signal_connect (actor, "notify::rotation-angle-z", G_CALLBACK(on_fbo_source_size_change), texture); g_signal_connect (actor, "queue-relayout", G_CALLBACK (fbo_source_queue_relayout_cb), texture); g_signal_connect (actor, "queue-redraw", G_CALLBACK (fbo_source_queue_redraw_cb), texture); /* And a warning if the source becomes a child of the texture */ g_signal_connect (actor, "parent-set", G_CALLBACK(on_fbo_parent_change), texture); priv->image_width = w; priv->image_height = h; clutter_actor_set_size (CLUTTER_ACTOR (texture), priv->image_width, priv->image_height); return CLUTTER_ACTOR (texture); } static void texture_fbo_free_resources (ClutterTexture *texture) { ClutterTexturePrivate *priv; priv = texture->priv; if (priv->fbo_source != NULL) { ClutterActor *parent; parent = clutter_actor_get_parent (priv->fbo_source); /* If we parented the texture then unparent it again so that it will lose the reference */ if (parent == CLUTTER_ACTOR (texture)) clutter_actor_remove_child (parent, priv->fbo_source); g_signal_handlers_disconnect_by_func (priv->fbo_source, G_CALLBACK(on_fbo_parent_change), texture); g_signal_handlers_disconnect_by_func (priv->fbo_source, G_CALLBACK(on_fbo_source_size_change), texture); g_signal_handlers_disconnect_by_func (priv->fbo_source, G_CALLBACK(fbo_source_queue_relayout_cb), texture); g_signal_handlers_disconnect_by_func (priv->fbo_source, G_CALLBACK(fbo_source_queue_redraw_cb), texture); g_object_unref (priv->fbo_source); priv->fbo_source = NULL; } if (priv->fbo_handle != NULL) { cogl_object_unref (priv->fbo_handle); priv->fbo_handle = NULL; } } /** * clutter_texture_set_sync_size: * @texture: a #ClutterTexture * @sync_size: %TRUE if the texture should have the same size of the * underlying image data * * Sets whether @texture should have the same preferred size as the * underlying image data. * * Since: 1.0 * * Deprecated: 1.12: No replacement is available. A #ClutterActor using * #ClutterImage with a %CLUTTER_REQUEST_CONTENT_SIZE request mode * will automatically bind the preferred size of the content to the * preferred size of the actor */ void clutter_texture_set_sync_size (ClutterTexture *texture, gboolean sync_size) { ClutterTexturePrivate *priv; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; if (priv->sync_actor_size != sync_size) { priv->sync_actor_size = sync_size; clutter_actor_queue_relayout (CLUTTER_ACTOR (texture)); g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_SYNC_SIZE]); } } /** * clutter_texture_get_sync_size: * @texture: a #ClutterTexture * * Retrieves the value set with clutter_texture_set_sync_size() * * Return value: %TRUE if the #ClutterTexture should have the same * preferred size of the underlying image data * * Since: 1.0 * * Deprecated: 1.12: There is no direct replacement */ gboolean clutter_texture_get_sync_size (ClutterTexture *texture) { g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); return texture->priv->sync_actor_size; } /** * clutter_texture_set_repeat: * @texture: a #ClutterTexture * @repeat_x: %TRUE if the texture should repeat horizontally * @repeat_y: %TRUE if the texture should repeat vertically * * Sets whether the @texture should repeat horizontally or * vertically when the actor size is bigger than the image size * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterImage and clutter_actor_set_content_repeat() * instead */ void clutter_texture_set_repeat (ClutterTexture *texture, gboolean repeat_x, gboolean repeat_y) { ClutterTexturePrivate *priv; gboolean changed = FALSE; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; g_object_freeze_notify (G_OBJECT (texture)); if (priv->repeat_x != repeat_x) { priv->repeat_x = repeat_x; g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_REPEAT_X]); changed = TRUE; } if (priv->repeat_y != repeat_y) { priv->repeat_y = repeat_y; g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_REPEAT_Y]); changed = TRUE; } if (changed) clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); g_object_thaw_notify (G_OBJECT (texture)); } /** * clutter_texture_get_repeat: * @texture: a #ClutterTexture * @repeat_x: (out): return location for the horizontal repeat * @repeat_y: (out): return location for the vertical repeat * * Retrieves the horizontal and vertical repeat values set * using clutter_texture_set_repeat() * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterImage and clutter_actor_get_content_repeat() * instead */ void clutter_texture_get_repeat (ClutterTexture *texture, gboolean *repeat_x, gboolean *repeat_y) { g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); if (repeat_x != NULL) *repeat_x = texture->priv->repeat_x; if (repeat_y != NULL) *repeat_y = texture->priv->repeat_y; } /** * clutter_texture_set_keep_aspect_ratio: * @texture: a #ClutterTexture * @keep_aspect: %TRUE to maintain aspect ratio * * Sets whether @texture should have a preferred size maintaining * the aspect ratio of the underlying image * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterImage and clutter_actor_set_content_gravity() * with %CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT instead */ void clutter_texture_set_keep_aspect_ratio (ClutterTexture *texture, gboolean keep_aspect) { ClutterTexturePrivate *priv; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; if (priv->keep_aspect_ratio != keep_aspect) { priv->keep_aspect_ratio = keep_aspect; clutter_actor_queue_relayout (CLUTTER_ACTOR (texture)); g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_KEEP_ASPECT_RATIO]); } } /** * clutter_texture_get_keep_aspect_ratio: * @texture: a #ClutterTexture * * Retrieves the value set using clutter_texture_set_keep_aspect_ratio() * * Return value: %TRUE if the #ClutterTexture should maintain the * aspect ratio of the underlying image * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterImage and clutter_actor_get_content_gravity() * instead */ gboolean clutter_texture_get_keep_aspect_ratio (ClutterTexture *texture) { g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); return texture->priv->keep_aspect_ratio; } /** * clutter_texture_set_load_async: * @texture: a #ClutterTexture * @load_async: %TRUE if the texture should asynchronously load data * from a filename * * Sets whether @texture should use a worker thread to load the data * from disk asynchronously. Setting @load_async to %TRUE will make * clutter_texture_set_from_file() return immediately. * * See the #ClutterTexture:load-async property documentation, and * clutter_texture_set_load_data_async(). * * Since: 1.0 * * Deprecated: 1.12: There is no direct replacement for this function. * Use #ClutterImage and platform-specific API for loading image data * asynchronously, like GdkPixbuf */ void clutter_texture_set_load_async (ClutterTexture *texture, gboolean load_async) { ClutterTexturePrivate *priv; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; load_async = !!load_async; if (priv->load_async_set != load_async) { priv->load_data_async = load_async; priv->load_size_async = load_async; priv->load_async_set = load_async; g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_LOAD_ASYNC]); g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_LOAD_DATA_ASYNC]); } } /** * clutter_texture_get_load_async: * @texture: a #ClutterTexture * * Retrieves the value set using clutter_texture_set_load_async() * * Return value: %TRUE if the #ClutterTexture should load the data from * disk asynchronously * * Since: 1.0 * * Deprecated: 1.12: There is no direct replacement for this function */ gboolean clutter_texture_get_load_async (ClutterTexture *texture) { g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); return texture->priv->load_async_set; } /** * clutter_texture_set_load_data_async: * @texture: a #ClutterTexture * @load_async: %TRUE if the texture should asynchronously load data * from a filename * * Sets whether @texture should use a worker thread to load the data * from disk asynchronously. Setting @load_async to %TRUE will make * clutter_texture_set_from_file() block until the #ClutterTexture has * determined the width and height of the image data. * * See the #ClutterTexture:load-async property documentation, and * clutter_texture_set_load_async(). * * Since: 1.0 * * Deprecated: 1.12: There is no direct replacement for this function. * Use #ClutterImage and platform-specific API for loading image data * asynchronously, like GdkPixbuf */ void clutter_texture_set_load_data_async (ClutterTexture *texture, gboolean load_async) { ClutterTexturePrivate *priv; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; if (priv->load_data_async != load_async) { /* load-data-async always unsets load-size-async */ priv->load_data_async = load_async; priv->load_size_async = FALSE; priv->load_async_set = load_async; g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_LOAD_ASYNC]); g_object_notify_by_pspec (G_OBJECT (texture), obj_props[PROP_LOAD_DATA_ASYNC]); } } /** * clutter_texture_get_load_data_async: * @texture: a #ClutterTexture * * Retrieves the value set by clutter_texture_set_load_data_async() * * Return value: %TRUE if the #ClutterTexture should load the image * data from a file asynchronously * * Since: 1.0 * * Deprecated: 1.12: There is no direct replacement for this function */ gboolean clutter_texture_get_load_data_async (ClutterTexture *texture) { g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); return texture->priv->load_async_set && texture->priv->load_data_async; } /** * clutter_texture_set_pick_with_alpha: * @texture: a #ClutterTexture * @pick_with_alpha: %TRUE if the alpha channel should affect the * picking shape * * Sets whether @texture should have it's shape defined by the alpha * channel when picking. * * Be aware that this is a bit more costly than the default picking * due to the texture lookup, extra test against the alpha value and * the fact that it will also interrupt the batching of geometry done * internally. * * Also there is currently no control over the threshold used to * determine what value of alpha is considered pickable, and so only * fully opaque parts of the texture will react to picking. * * Since: 1.4 * * Deprecated: 1.12: There is no direct replacement for this function */ void clutter_texture_set_pick_with_alpha (ClutterTexture *texture, gboolean pick_with_alpha) { ClutterTexturePrivate *priv; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; if (priv->pick_with_alpha == pick_with_alpha) return; if (!pick_with_alpha && priv->pick_pipeline != NULL) { cogl_object_unref (priv->pick_pipeline); priv->pick_pipeline = NULL; } /* NB: the pick pipeline is created lazily when we first pick */ priv->pick_with_alpha = pick_with_alpha; /* NB: actors are expected to call clutter_actor_queue_redraw when * ever some state changes that will affect painting *or picking... */ clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); } /** * clutter_texture_get_pick_with_alpha: * @texture: a #ClutterTexture * * Retrieves the value set by clutter_texture_set_load_data_async() * * Return value: %TRUE if the #ClutterTexture should define its shape * using the alpha channel when picking. * * Since: 1.4 * * Deprecated: 1.12: There is no direct replacement for this function */ gboolean clutter_texture_get_pick_with_alpha (ClutterTexture *texture) { g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), FALSE); return texture->priv->pick_with_alpha ? TRUE : FALSE; } muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-ellipse.c0000664000175000017500000006753514211404421025663 0ustar jpeisachjpeisach /* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Tomas Frydrych * * Copyright (C) 2007 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, see . */ /** * SECTION:clutter-behaviour-ellipse * @Title: ClutterBehaviourEllipse * @short_description: A behaviour interpolating position along an ellipse * @Deprecated: 1.6: Use clutter_actor_animate() instead * * #ClutterBehaviourEllipse interpolates actors along a path defined by * an ellipse. * * When applying an ellipse behaviour to an actor, the * behaviour will update the actor's position and depth and set them * to what is dictated by the ellipses initial position. * * Deprecated: 1.6: Use clutter_actor_animate(), #ClutterPath and a * #ClutterPathConstraint instead. * * Since: 0.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-actor.h" #include "clutter-alpha.h" #include "clutter-behaviour.h" #include "clutter-behaviour-ellipse.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-private.h" enum { PROP_0, PROP_CENTER, PROP_WIDTH, PROP_HEIGHT, PROP_ANGLE_START, PROP_ANGLE_END, PROP_ANGLE_TILT_X, PROP_ANGLE_TILT_Y, PROP_ANGLE_TILT_Z, PROP_DIRECTION, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; struct _ClutterBehaviourEllipsePrivate { ClutterKnot center; /* a = width / 2 */ gint a; /* b = height / 2 */ gint b; gdouble angle_start; gdouble angle_end; gdouble angle_tilt_x; gdouble angle_tilt_y; gdouble angle_tilt_z; ClutterRotateDirection direction; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterBehaviourEllipse, clutter_behaviour_ellipse, CLUTTER_TYPE_BEHAVIOUR) typedef struct _knot3d { gint x; gint y; gint z; } knot3d; static void clutter_behaviour_ellipse_advance (ClutterBehaviourEllipse *e, float angle, knot3d *knot) { ClutterBehaviourEllipsePrivate *priv = e->priv; gint x, y, z; x = priv->a * cosf (angle * (G_PI / 180.0)); y = priv->b * sinf (angle * (G_PI / 180.0)); z = 0; if (priv->angle_tilt_z) { /* * x2 = r * cos (angle + tilt_z) * y2 = r * sin (angle + tilt_z) * * These can be trasformed to the formulas below using properties of * sin (a + b) and cos (a + b) * */ gfloat x2, y2; x2 = x * cosf (priv->angle_tilt_z * (G_PI / 180.0)) - y * sinf (priv->angle_tilt_z * (G_PI / 180.0)); y2 = y * cosf (priv->angle_tilt_z * (G_PI / 180.0)) + x * sinf (priv->angle_tilt_z * (G_PI / 180.0)); x = (x2); y = (y2); } if (priv->angle_tilt_x) { gfloat z2, y2; z2 = - y * sinf (priv->angle_tilt_x * (G_PI / 180.0)); y2 = y * cosf (priv->angle_tilt_x * (G_PI / 180.0)); z = z2; y = y2; } if (priv->angle_tilt_y) { gfloat x2, z2; x2 = x * cosf (priv->angle_tilt_y * (G_PI / 180.0)) - z * sinf (priv->angle_tilt_y * (G_PI / 180.0)); z2 = z * cosf (priv->angle_tilt_y * (G_PI / 180.0)) + x * sinf (priv->angle_tilt_y * (G_PI / 180.0)); x = x2; z = z2; } knot->x = x; knot->y = y; knot->z = z; CLUTTER_NOTE (ANIMATION, "advancing to angle %.2f [%d, %d] (a: %d, b: %d)", angle, knot->x, knot->y, priv->a, priv->b); } static void actor_apply_knot_foreach (ClutterBehaviour *behave, ClutterActor *actor, gpointer data) { ClutterBehaviourEllipsePrivate *priv; knot3d *knot = data; priv = ((ClutterBehaviourEllipse *) behave)->priv; clutter_actor_set_position (actor, knot->x, knot->y); if (priv->angle_tilt_x != 0 || priv->angle_tilt_y != 0) clutter_actor_set_depth (actor, knot->z); } static inline float clamp_angle (float a) { gint rounds; rounds = a / 360; if (a < 0) rounds--; return a - 360 * rounds; } static void clutter_behaviour_ellipse_alpha_notify (ClutterBehaviour *behave, gdouble alpha) { ClutterBehaviourEllipse *self = CLUTTER_BEHAVIOUR_ELLIPSE (behave); ClutterBehaviourEllipsePrivate *priv = self->priv; gfloat start, end; gfloat angle = 0; knot3d knot; /* we do everything in single precision because it's easier, even * though all the parameters are stored in double precision for * consistency with the equivalent ClutterActor API */ start = priv->angle_start; end = priv->angle_end; if (priv->direction == CLUTTER_ROTATE_CW && start >= end) end += 360; else if (priv->direction == CLUTTER_ROTATE_CCW && start <= end) end -= 360; angle = (end - start) * alpha + start; clutter_behaviour_ellipse_advance (self, angle, &knot); knot.x += priv->center.x; knot.y += priv->center.y; clutter_behaviour_actors_foreach (behave, actor_apply_knot_foreach, &knot); } static void clutter_behaviour_ellipse_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBehaviourEllipse *el = CLUTTER_BEHAVIOUR_ELLIPSE (gobject); ClutterBehaviourEllipsePrivate *priv = el->priv; switch (prop_id) { case PROP_ANGLE_START: priv->angle_start = g_value_get_double (value); break; case PROP_ANGLE_END: priv->angle_end = g_value_get_double (value); break; case PROP_ANGLE_TILT_X: priv->angle_tilt_x = g_value_get_double (value); break; case PROP_ANGLE_TILT_Y: priv->angle_tilt_y = g_value_get_double (value); break; case PROP_ANGLE_TILT_Z: priv->angle_tilt_z = g_value_get_double (value); break; case PROP_WIDTH: clutter_behaviour_ellipse_set_width (el, g_value_get_int (value)); break; case PROP_HEIGHT: clutter_behaviour_ellipse_set_height (el, g_value_get_int (value)); break; case PROP_CENTER: { ClutterKnot *knot = g_value_get_boxed (value); if (knot) clutter_behaviour_ellipse_set_center (el, knot->x, knot->y); } break; case PROP_DIRECTION: priv->direction = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_ellipse_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBehaviourEllipsePrivate *priv; priv = CLUTTER_BEHAVIOUR_ELLIPSE (gobject)->priv; switch (prop_id) { case PROP_ANGLE_START: g_value_set_double (value, priv->angle_start); break; case PROP_ANGLE_END: g_value_set_double (value, priv->angle_end); break; case PROP_ANGLE_TILT_X: g_value_set_double (value, priv->angle_tilt_x); break; case PROP_ANGLE_TILT_Y: g_value_set_double (value, priv->angle_tilt_y); break; case PROP_ANGLE_TILT_Z: g_value_set_double (value, priv->angle_tilt_z); break; case PROP_WIDTH: g_value_set_int (value, (priv->a * 2)); break; case PROP_HEIGHT: g_value_set_int (value, (priv->b * 2)); break; case PROP_CENTER: g_value_set_boxed (value, &priv->center); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_ellipse_applied (ClutterBehaviour *behave, ClutterActor *actor) { ClutterBehaviourEllipse *e = CLUTTER_BEHAVIOUR_ELLIPSE (behave); ClutterBehaviourEllipsePrivate *priv = e->priv; knot3d knot = { 0, }; clutter_behaviour_ellipse_advance (e, priv->angle_start, &knot); clutter_actor_set_position (actor, knot.x, knot.y); /* the depth should be changed only if there is a tilt on * any of the X or the Y axis */ if (priv->angle_tilt_x != 0 || priv->angle_tilt_y != 0) clutter_actor_set_depth (actor, knot.z); } static void clutter_behaviour_ellipse_class_init (ClutterBehaviourEllipseClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass); GParamSpec *pspec = NULL; object_class->set_property = clutter_behaviour_ellipse_set_property; object_class->get_property = clutter_behaviour_ellipse_get_property; behave_class->alpha_notify = clutter_behaviour_ellipse_alpha_notify; behave_class->applied = clutter_behaviour_ellipse_applied; /** * ClutterBehaviourEllipse:angle-start: * * The initial angle from where the rotation should start. * * Since: 0.4 */ pspec = g_param_spec_double ("angle-start", P_("Start Angle"), P_("Initial angle"), 0.0, 360.0, 0.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE_START] = pspec; g_object_class_install_property (object_class, PROP_ANGLE_START, pspec); /** * ClutterBehaviourEllipse:angle-end: * * The final angle to where the rotation should end. * * Since: 0.4 */ pspec = g_param_spec_double ("angle-end", P_("End Angle"), P_("Final angle"), 0.0, 360.0, 0.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE_END] = pspec; g_object_class_install_property (object_class, PROP_ANGLE_END, pspec); /** * ClutterBehaviourEllipse:angle-tilt-x: * * The tilt angle for the rotation around center in X axis * * Since: 0.4 */ pspec = g_param_spec_double ("angle-tilt-x", P_("Angle x tilt"), P_("Tilt of the ellipse around x axis"), 0.0, 360.0, 360.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE_TILT_X] = pspec; g_object_class_install_property (object_class, PROP_ANGLE_TILT_X, pspec); /** * ClutterBehaviourEllipse:angle-tilt-y: * * The tilt angle for the rotation around center in Y axis * * Since: 0.4 */ pspec = g_param_spec_double ("angle-tilt-y", P_("Angle y tilt"), P_("Tilt of the ellipse around y axis"), 0.0, 360.0, 360.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE_TILT_Y] = pspec; g_object_class_install_property (object_class, PROP_ANGLE_TILT_Y, pspec); /** * ClutterBehaviourEllipse:angle-tilt-z: * * The tilt angle for the rotation on the Z axis * * Since: 0.4 */ pspec = g_param_spec_double ("angle-tilt-z", P_("Angle z tilt"), P_("Tilt of the ellipse around z axis"), 0.0, 360.0, 360.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_ANGLE_TILT_Z] = pspec; g_object_class_install_property (object_class, PROP_ANGLE_TILT_Z, pspec); /** * ClutterBehaviourEllipse:width: * * Width of the ellipse, in pixels * * Since: 0.4 */ pspec = g_param_spec_int ("width", P_("Width"), P_("Width of the ellipse"), 0, G_MAXINT, 100, CLUTTER_PARAM_READWRITE); obj_props[PROP_WIDTH] = pspec; g_object_class_install_property (object_class, PROP_WIDTH, pspec); /** * ClutterBehaviourEllipse:height: * * Height of the ellipse, in pixels * * Since: 0.4 */ pspec = g_param_spec_int ("height", P_("Height"), P_("Height of ellipse"), 0, G_MAXINT, 50, CLUTTER_PARAM_READWRITE); obj_props[PROP_HEIGHT] = pspec; g_object_class_install_property (object_class, PROP_HEIGHT, pspec); /** * ClutterBehaviourEllipse:center: * * The center of the ellipse. * * Since: 0.4 */ pspec = g_param_spec_boxed ("center", P_("Center"), P_("Center of ellipse"), CLUTTER_TYPE_KNOT, CLUTTER_PARAM_READWRITE); obj_props[PROP_CENTER] = pspec; g_object_class_install_property (object_class, PROP_CENTER, pspec); /** * ClutterBehaviourEllipse:direction: * * The direction of the rotation. * * Since: 0.4 */ pspec = g_param_spec_enum ("direction", P_("Direction"), P_("Direction of rotation"), CLUTTER_TYPE_ROTATE_DIRECTION, CLUTTER_ROTATE_CW, CLUTTER_PARAM_READWRITE); obj_props[PROP_DIRECTION] = pspec; g_object_class_install_property (object_class, PROP_DIRECTION, pspec); } static void clutter_behaviour_ellipse_init (ClutterBehaviourEllipse * self) { ClutterBehaviourEllipsePrivate *priv; self->priv = priv = clutter_behaviour_ellipse_get_instance_private (self); priv->direction = CLUTTER_ROTATE_CW; priv->angle_start = 0; priv->angle_end = 0; priv->a = 50; priv->b = 25; priv->angle_tilt_x = 360; priv->angle_tilt_y = 360; priv->angle_tilt_z = 360; } /** * clutter_behaviour_ellipse_new: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @x: x coordinace of the center * @y: y coordiance of the center * @width: width of the ellipse * @height: height of the ellipse * @direction: #ClutterRotateDirection of rotation * @start: angle in degrees at which movement starts, between 0 and 360 * @end: angle in degrees at which movement ends, between 0 and 360 * * Creates a behaviour that drives actors along an elliptical path with * given center, width and height; the movement starts at @start * degrees (with 0 corresponding to 12 o'clock) and ends at @end * degrees. Angles greated than 360 degrees get clamped to the canonical * interval <0, 360); if @start is equal to @end, the behaviour will * rotate by exacly 360 degrees. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: the newly created #ClutterBehaviourEllipse * * Since: 0.4 */ ClutterBehaviour * clutter_behaviour_ellipse_new (ClutterAlpha *alpha, gint x, gint y, gint width, gint height, ClutterRotateDirection direction, gdouble start, gdouble end) { ClutterKnot center; g_return_val_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha), NULL); center.x = x; center.y = y; return g_object_new (CLUTTER_TYPE_BEHAVIOUR_ELLIPSE, "alpha", alpha, "center", ¢er, "width", width, "height", height, "direction", direction, "angle-start", start, "angle-end", end, NULL); } /** * clutter_behaviour_ellipse_set_center: * @self: a #ClutterBehaviourEllipse * @x: x coordinace of centre * @y: y coordinace of centre * * Sets the center of the elliptical path to the point represented by knot. * * Since: 0.4 */ void clutter_behaviour_ellipse_set_center (ClutterBehaviourEllipse *self, gint x, gint y) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; if (priv->center.x != x || priv->center.y != y) { priv->center.x = x; priv->center.y = y; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CENTER]); } } /** * clutter_behaviour_ellipse_get_center: * @self: a #ClutterBehaviourEllipse * @x: (out): return location for the X coordinate of the center, or %NULL * @y: (out): return location for the Y coordinate of the center, or %NULL * * Gets the center of the elliptical path path. * * Since: 0.4 */ void clutter_behaviour_ellipse_get_center (ClutterBehaviourEllipse *self, gint *x, gint *y) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; if (x) *x = priv->center.x; if (y) *y = priv->center.y; } /** * clutter_behaviour_ellipse_set_width: * @self: a #ClutterBehaviourEllipse * @width: width of the ellipse * * Sets the width of the elliptical path. * * Since: 0.4 */ void clutter_behaviour_ellipse_set_width (ClutterBehaviourEllipse *self, gint width) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; if (priv->a != width / 2) { priv->a = width / 2; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_WIDTH]); } } /** * clutter_behaviour_ellipse_get_width: * @self: a #ClutterBehaviourEllipse * * Gets the width of the elliptical path. * * Return value: the width of the path * * Since: 0.4 */ gint clutter_behaviour_ellipse_get_width (ClutterBehaviourEllipse *self) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self), 0); return self->priv->a * 2; } /** * clutter_behaviour_ellipse_set_height: * @self: a #ClutterBehaviourEllipse * @height: height of the ellipse * * Sets the height of the elliptical path. * * Since: 0.4 */ void clutter_behaviour_ellipse_set_height (ClutterBehaviourEllipse *self, gint height) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; if (priv->b != height / 2) { priv->b = height / 2; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HEIGHT]); } } /** * clutter_behaviour_ellipse_get_height: * @self: a #ClutterBehaviourEllipse * * Gets the height of the elliptical path. * * Return value: the height of the path * * Since: 0.4 */ gint clutter_behaviour_ellipse_get_height (ClutterBehaviourEllipse *self) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self), 0); return self->priv->b * 2; } /** * clutter_behaviour_ellipse_set_angle_start: * @self: a #ClutterBehaviourEllipse * @angle_start: angle at which movement starts in degrees, between 0 and 360. * * Sets the angle at which movement starts; angles >= 360 degress get clamped * to the canonical interval <0, 360). * * Since: 0.6 */ void clutter_behaviour_ellipse_set_angle_start (ClutterBehaviourEllipse *self, gdouble angle_start) { ClutterBehaviourEllipsePrivate *priv; gdouble new_angle; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); new_angle = clamp_angle (angle_start); priv = self->priv; if (priv->angle_start != new_angle) { priv->angle_start = new_angle; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_START]); } } /** * clutter_behaviour_ellipse_get_angle_start: * @self: a #ClutterBehaviourEllipse * * Gets the angle at which movements starts. * * Return value: angle in degrees * * Since: 0.6 */ gdouble clutter_behaviour_ellipse_get_angle_start (ClutterBehaviourEllipse *self) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self), 0.0); return self->priv->angle_start; } /** * clutter_behaviour_ellipse_set_angle_end: * @self: a #ClutterBehaviourEllipse * @angle_end: angle at which movement ends in degrees, between 0 and 360. * * Sets the angle at which movement ends; angles >= 360 degress get clamped * to the canonical interval <0, 360). * * Since: 0.4 */ void clutter_behaviour_ellipse_set_angle_end (ClutterBehaviourEllipse *self, gdouble angle_end) { ClutterBehaviourEllipsePrivate *priv; gdouble new_angle; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); new_angle = clamp_angle (angle_end); priv = self->priv; if (priv->angle_end != new_angle) { priv->angle_end = new_angle; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_END]); } } /** * clutter_behaviour_ellipse_get_angle_end: * @self: a #ClutterBehaviourEllipse * * Gets the at which movements ends. * * Return value: angle in degrees * * Since: 0.4 */ gdouble clutter_behaviour_ellipse_get_angle_end (ClutterBehaviourEllipse *self) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self), 0.0); return self->priv->angle_end; } /** * clutter_behaviour_ellipse_set_angle_tilt: * @self: a #ClutterBehaviourEllipse * @axis: a #ClutterRotateAxis * @angle_tilt: tilt of the elipse around the center in the given axis in * degrees. * * Sets the angle at which the ellipse should be tilted around it's center. * * Since: 0.4 */ void clutter_behaviour_ellipse_set_angle_tilt (ClutterBehaviourEllipse *self, ClutterRotateAxis axis, gdouble angle_tilt) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; switch (axis) { case CLUTTER_X_AXIS: if (priv->angle_tilt_x != angle_tilt) { priv->angle_tilt_x = angle_tilt; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_TILT_X]); } break; case CLUTTER_Y_AXIS: if (priv->angle_tilt_y != angle_tilt) { priv->angle_tilt_y = angle_tilt; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_TILT_Y]); } break; case CLUTTER_Z_AXIS: if (priv->angle_tilt_z != angle_tilt) { priv->angle_tilt_z = angle_tilt; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_TILT_Z]); } break; } } /** * clutter_behaviour_ellipse_get_angle_tilt: * @self: a #ClutterBehaviourEllipse * @axis: a #ClutterRotateAxis * * Gets the tilt of the ellipse around the center in the given axis. * * Return value: angle in degrees. * * Since: 0.4 */ gdouble clutter_behaviour_ellipse_get_angle_tilt (ClutterBehaviourEllipse *self, ClutterRotateAxis axis) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self), 0.0); switch (axis) { case CLUTTER_X_AXIS: return self->priv->angle_tilt_x; case CLUTTER_Y_AXIS: return self->priv->angle_tilt_y; case CLUTTER_Z_AXIS: return self->priv->angle_tilt_z; } return 0.0; } /** * clutter_behaviour_ellipse_set_tilt: * @self: a #ClutterBehaviourEllipse * @angle_tilt_x: tilt of the elipse around the center in X axis in degrees. * @angle_tilt_y: tilt of the elipse around the center in Y axis in degrees. * @angle_tilt_z: tilt of the elipse around the center in Z axis in degrees. * * Sets the angles at which the ellipse should be tilted around it's center. * * Since: 0.4 */ void clutter_behaviour_ellipse_set_tilt (ClutterBehaviourEllipse *self, gdouble angle_tilt_x, gdouble angle_tilt_y, gdouble angle_tilt_z) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); if (priv->angle_tilt_x != angle_tilt_x) { priv->angle_tilt_x = angle_tilt_x; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_TILT_X]); } if (priv->angle_tilt_y != angle_tilt_y) { priv->angle_tilt_y = angle_tilt_y; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_TILT_Y]); } if (priv->angle_tilt_z != angle_tilt_z) { priv->angle_tilt_z = angle_tilt_z; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ANGLE_TILT_Z]); } g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_behaviour_ellipse_get_tilt: * @self: a #ClutterBehaviourEllipse * @angle_tilt_x: (out): return location for tilt angle on the X axis, or %NULL. * @angle_tilt_y: (out): return location for tilt angle on the Y axis, or %NULL. * @angle_tilt_z: (out): return location for tilt angle on the Z axis, or %NULL. * * Gets the tilt of the ellipse around the center in Y axis. * * Since: 0.4 */ void clutter_behaviour_ellipse_get_tilt (ClutterBehaviourEllipse *self, gdouble *angle_tilt_x, gdouble *angle_tilt_y, gdouble *angle_tilt_z) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; if (angle_tilt_x) *angle_tilt_x = priv->angle_tilt_x; if (angle_tilt_y) *angle_tilt_y = priv->angle_tilt_y; if (angle_tilt_z) *angle_tilt_z = priv->angle_tilt_z; } /** * clutter_behaviour_ellipse_get_direction: * @self: a #ClutterBehaviourEllipse * * Retrieves the #ClutterRotateDirection used by the ellipse behaviour. * * Return value: the rotation direction * * Since: 0.4 */ ClutterRotateDirection clutter_behaviour_ellipse_get_direction (ClutterBehaviourEllipse *self) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self), CLUTTER_ROTATE_CW); return self->priv->direction; } /** * clutter_behaviour_ellipse_set_direction: * @self: a #ClutterBehaviourEllipse * @direction: the rotation direction * * Sets the rotation direction used by the ellipse behaviour. * * Since: 0.4 */ void clutter_behaviour_ellipse_set_direction (ClutterBehaviourEllipse *self, ClutterRotateDirection direction) { ClutterBehaviourEllipsePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_ELLIPSE (self)); priv = self->priv; if (priv->direction != direction) { priv->direction = direction; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DIRECTION]); } } muffin-5.2.1/clutter/clutter/deprecated/clutter-score.h0000664000175000017500000001242114211404421023344 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_SCORE_H__ #define __CLUTTER_SCORE_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_SCORE (clutter_score_get_type ()) #define CLUTTER_SCORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SCORE, ClutterScore)) #define CLUTTER_SCORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SCORE, ClutterScoreClass)) #define CLUTTER_IS_SCORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SCORE)) #define CLUTTER_IS_SCORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SCORE)) #define CLUTTER_SCORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SCORE, ClutterScoreClass)) typedef struct _ClutterScore ClutterScore; typedef struct _ClutterScorePrivate ClutterScorePrivate; typedef struct _ClutterScoreClass ClutterScoreClass; /** * ClutterScore: * * The #ClutterScore structure contains only private data * and should be accessed using the provided API * * Since: 0.6 */ struct _ClutterScore { /*< private >*/ GObject parent; ClutterScorePrivate *priv; }; /** * ClutterScoreClass: * @timeline_started: handler for the #ClutterScore::timeline-started signal * @timeline_completed: handler for the #ClutterScore::timeline-completed * signal * @started: handler for the #ClutterScore::started signal * @completed: handler for the #ClutterScore::completed signal * @paused: handler for the #ClutterScore::paused signal * * The #ClutterScoreClass structure contains only private data * * Since: 0.6 */ struct _ClutterScoreClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ void (* timeline_started) (ClutterScore *score, ClutterTimeline *timeline); void (* timeline_completed) (ClutterScore *score, ClutterTimeline *timeline); void (* started) (ClutterScore *score); void (* completed) (ClutterScore *score); void (* paused) (ClutterScore *score); /*< private >*/ /* padding for future expansion */ void (*_clutter_score_1) (void); void (*_clutter_score_2) (void); void (*_clutter_score_3) (void); void (*_clutter_score_4) (void); void (*_clutter_score_5) (void); }; CLUTTER_DEPRECATED_IN_1_8 GType clutter_score_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_8 ClutterScore * clutter_score_new (void); CLUTTER_DEPRECATED_IN_1_8 void clutter_score_set_loop (ClutterScore *score, gboolean loop); CLUTTER_DEPRECATED_IN_1_8 gboolean clutter_score_get_loop (ClutterScore *score); CLUTTER_DEPRECATED_IN_1_8 gulong clutter_score_append (ClutterScore *score, ClutterTimeline *parent, ClutterTimeline *timeline); CLUTTER_DEPRECATED_IN_1_8 gulong clutter_score_append_at_marker (ClutterScore *score, ClutterTimeline *parent, const gchar *marker_name, ClutterTimeline *timeline); CLUTTER_DEPRECATED_IN_1_8 void clutter_score_remove (ClutterScore *score, gulong id_); CLUTTER_DEPRECATED_IN_1_8 void clutter_score_remove_all (ClutterScore *score); CLUTTER_DEPRECATED_IN_1_8 ClutterTimeline *clutter_score_get_timeline (ClutterScore *score, gulong id_); CLUTTER_DEPRECATED_IN_1_8 GSList * clutter_score_list_timelines (ClutterScore *score); CLUTTER_DEPRECATED_IN_1_8 void clutter_score_start (ClutterScore *score); CLUTTER_DEPRECATED_IN_1_8 void clutter_score_stop (ClutterScore *score); CLUTTER_DEPRECATED_IN_1_8 void clutter_score_pause (ClutterScore *score); CLUTTER_DEPRECATED_IN_1_8 void clutter_score_rewind (ClutterScore *score); CLUTTER_DEPRECATED_IN_1_8 gboolean clutter_score_is_playing (ClutterScore *score); G_END_DECLS #endif /* __CLUTTER_SCORE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-bin-layout.h0000664000175000017500000000440114211404421024313 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BIN_LAYOUT_DEPRECATED_H__ #define __CLUTTER_BIN_LAYOUT_DEPRECATED_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_12 void clutter_bin_layout_set_alignment (ClutterBinLayout *self, ClutterActor *child, ClutterBinAlignment x_align, ClutterBinAlignment y_align); CLUTTER_DEPRECATED_IN_1_12 void clutter_bin_layout_get_alignment (ClutterBinLayout *self, ClutterActor *child, ClutterBinAlignment *x_align, ClutterBinAlignment *y_align); CLUTTER_DEPRECATED_IN_1_12 void clutter_bin_layout_add (ClutterBinLayout *self, ClutterActor *child, ClutterBinAlignment x_align, ClutterBinAlignment y_align); G_END_DECLS #endif /* __CLUTTER_BIN_LAYOUT_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-rotate.h0000664000175000017500000001210214211404421025505 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BEHAVIOUR_ROTATE_H__ #define __CLUTTER_BEHAVIOUR_ROTATE_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_BEHAVIOUR_ROTATE (clutter_behaviour_rotate_get_type ()) #define CLUTTER_BEHAVIOUR_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BEHAVIOUR_ROTATE, ClutterBehaviourRotate)) #define CLUTTER_IS_BEHAVIOUR_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BEHAVIOUR_ROTATE)) #define CLUTTER_BEHAVIOUR_ROTATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BEHAVIOUR_ROTATE, ClutterBehaviourRotateClass)) #define CLUTTER_IS_BEHAVIOUR_ROTATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BEHAVIOUR_ROTATE)) #define CLUTTER_BEHAVIOUR_ROTATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((klass), CLUTTER_TYPE_BEHAVIOUR_ROTATE, ClutterBehaviourRotateClass)) typedef struct _ClutterBehaviourRotate ClutterBehaviourRotate; typedef struct _ClutterBehaviourRotatePrivate ClutterBehaviourRotatePrivate; typedef struct _ClutterBehaviourRotateClass ClutterBehaviourRotateClass; /** * ClutterBehaviourRotate: * * The #ClutterBehaviourRotate struct contains only private data and * should be accessed using the provided API * * Since: 0.4 * * Deprecated: 1.6: Use clutter_actor_animate() instead. */ struct _ClutterBehaviourRotate { /*< private >*/ ClutterBehaviour parent_instance; ClutterBehaviourRotatePrivate *priv; }; /** * ClutterBehaviourRotateClass: * * The #ClutterBehaviourRotateClass struct contains only private data * * Since: 0.4 * * Deprecated: 1.6 */ struct _ClutterBehaviourRotateClass { /*< private >*/ ClutterBehaviourClass parent_class; }; CLUTTER_DEPRECATED_IN_1_6 GType clutter_behaviour_rotate_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_6_FOR(clutter_actor_animate) ClutterBehaviour * clutter_behaviour_rotate_new (ClutterAlpha *alpha, ClutterRotateAxis axis, ClutterRotateDirection direction, gdouble angle_start, gdouble angle_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_rotate_get_center (ClutterBehaviourRotate *rotate, gint *x, gint *y, gint *z); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_rotate_set_center (ClutterBehaviourRotate *rotate, gint x, gint y, gint z); CLUTTER_DEPRECATED_IN_1_6 ClutterRotateAxis clutter_behaviour_rotate_get_axis (ClutterBehaviourRotate *rotate); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_rotate_set_axis (ClutterBehaviourRotate *rotate, ClutterRotateAxis axis); CLUTTER_DEPRECATED_IN_1_6 ClutterRotateDirection clutter_behaviour_rotate_get_direction (ClutterBehaviourRotate *rotate); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_rotate_set_direction (ClutterBehaviourRotate *rotate, ClutterRotateDirection direction); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_rotate_get_bounds (ClutterBehaviourRotate *rotate, gdouble *angle_start, gdouble *angle_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_rotate_set_bounds (ClutterBehaviourRotate *rotate, gdouble angle_start, gdouble angle_end); G_END_DECLS #endif /* __CLUTTER_BEHAVIOUR_ROTATE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-model.c0000664000175000017500000020303614211404421023330 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Neil Jagdish Patel * Emmanuele Bassi * * Copyright (C) 2006 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, see . * * NB: Inspiration for column storage taken from GtkListStore */ /** * SECTION:clutter-model * @short_description: A generic model implementation * * #ClutterModel is a generic list model API which can be used to implement * the model-view-controller architectural pattern in Clutter. * * The #ClutterModel class is a list model which can accept most GObject * types as a column type. * * ## Creating a simple ClutterModel * * The example below shows how to create a simple list model. * * |[ * enum * { * COLUMN_INT, * COLUMN_STRING, * * N_COLUMNS * }; * * { * ClutterModel *model; * gint i; * * model = clutter_list_model_new (N_COLUMNS, * // column type, title * G_TYPE_INT, "my integers", * G_TYPE_STRING, "my strings"); * for (i = 0; i < 10; i++) * { * gchar *string = g_strdup_printf ("String %d", i); * clutter_model_append (model, * COLUMN_INT, i, * COLUMN_STRING, string, * -1); * free (string); * } * * * } * ]| * * ## Iterating through a ClutterModel * * Iterating through the model consists of retrieving a new #ClutterModelIter * pointing to the starting row, and calling clutter_model_iter_next() or * clutter_model_iter_prev() to move forward or backwards, repectively. * * A valid #ClutterModelIter represents the position between two rows in the * model. For example, the "first" iterator represents the gap immediately * before the first row, and the "last" iterator represents the gap immediately * after the last row. In an empty sequence, the first and last iterators are * the same. * * |[ * enum * { * COLUMN_INT, * COLUMN_STRING. * * N_COLUMNS * }; * * { * ClutterModel *model; * ClutterModelIter *iter = NULL; * * // fill the model * model = populate_model (); * * // get the iterator for the first row in the model * iter = clutter_model_get_first_iter (model); * while (!clutter_model_iter_is_last (iter)) * { * print_row (iter); * * iter = clutter_model_iter_next (iter); * } * * // Make sure to unref the iter * g_object_unref (iter); * } * ]| * * #ClutterModel is an abstract class. Clutter provides a list model * implementation called #ClutterListModel which has been optimised * for insertion and look up in sorted lists. * * #ClutterModel is available since Clutter 0.6 * * ## ClutterModel custom properties for ClutterScript * * #ClutterModel defines a custom property "columns" for #ClutterScript * which allows defining the column names and types. It also defines a custom * "rows" property which allows filling the #ClutterModel with some * data. * * The definition below will create a #ClutterListModel with three * columns: the first one with name "Name" and containing strings; the * second one with name "Score" and containing integers; the third one with * name "Icon" and containing #ClutterTextures. The model is filled * with three rows. A row can be defined either with an array that holds * all columns of a row, or an object that holds "column-name" : * "column-value" pairs. * * |[ * { * "type" : "ClutterListModel", * "id" : "teams-model", * "columns" : [ * [ "Name", "gchararray" ], * [ "Score", "gint" ], * [ "Icon", "ClutterTexture" ] * ], * "rows" : [ * [ "Team 1", 42, { "type" : "ClutterTexture", "filename" : "team1.png" } ], * [ "Team 2", 23, "team2-icon-script-id" ], * { "Name" : "Team 3", "Icon" : "team3-icon-script-id" } * ] * } * * Deprecated: 1.24: You should implement the #GListModel interface on your * own storage data type instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-model.h" #include "clutter-model-private.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-debug.h" #include "clutter-scriptable.h" #include "clutter-script-private.h" enum { PROP_0, PROP_FILTER_SET }; enum { ROW_ADDED, ROW_REMOVED, ROW_CHANGED, SORT_CHANGED, FILTER_CHANGED, LAST_SIGNAL }; static guint model_signals[LAST_SIGNAL] = { 0, }; struct _ClutterModelPrivate { GType *column_types; gchar **column_names; /* we use an integer here because we want to be able to use -1 as a * guard value, to allow calling set_names() and set_types() from * sub-classes of ClutterModel. see bug: * * http://bugzilla.openedhand.com/show_bug.cgi?id=2032 * * for a reference. */ gint n_columns; ClutterModelFilterFunc filter_func; gpointer filter_data; GDestroyNotify filter_notify; gint sort_column; ClutterModelSortFunc sort_func; gpointer sort_data; GDestroyNotify sort_notify; }; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterModel, clutter_model, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterModel) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)) static GType clutter_model_real_get_column_type (ClutterModel *model, guint column) { ClutterModelPrivate *priv = model->priv; if (column >= clutter_model_get_n_columns (model)) return G_TYPE_INVALID; return priv->column_types[column]; } static const gchar * clutter_model_real_get_column_name (ClutterModel *model, guint column) { ClutterModelPrivate *priv = model->priv; if (column >= clutter_model_get_n_columns (model)) return NULL; if (priv->column_names && priv->column_names[column]) return priv->column_names[column]; return g_type_name (priv->column_types[column]); } static guint clutter_model_real_get_n_columns (ClutterModel *model) { ClutterModelPrivate *priv = model->priv; if (priv->n_columns < 0) return 0; return priv->n_columns; } static guint clutter_model_real_get_n_rows (ClutterModel *model) { ClutterModelIter *iter; guint row_count; g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0); iter = clutter_model_get_first_iter (model); if (iter == NULL) return 0; row_count = 0; while (!clutter_model_iter_is_last (iter)) { if (clutter_model_filter_iter (model, iter)) row_count += 1; iter = clutter_model_iter_next (iter); } g_object_unref (iter); return row_count; } static void clutter_model_finalize (GObject *object) { ClutterModelPrivate *priv = CLUTTER_MODEL (object)->priv; gint i; if (priv->sort_notify) priv->sort_notify (priv->sort_data); if (priv->filter_notify) priv->filter_notify (priv->filter_data); free (priv->column_types); if (priv->column_names != NULL) { /* the column_names vector might have holes in it, so we need * to use the columns number to clear up everything */ for (i = 0; i < priv->n_columns; i++) free (priv->column_names[i]); free (priv->column_names); } G_OBJECT_CLASS (clutter_model_parent_class)->finalize (object); } static void clutter_model_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterModelPrivate *priv = CLUTTER_MODEL (gobject)->priv; switch (prop_id) { case PROP_FILTER_SET: g_value_set_boolean (value, priv->filter_func != NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_model_class_init (ClutterModelClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->get_property = clutter_model_get_property; gobject_class->finalize = clutter_model_finalize; klass->get_column_name = clutter_model_real_get_column_name; klass->get_column_type = clutter_model_real_get_column_type; klass->get_n_columns = clutter_model_real_get_n_columns; klass->get_n_rows = clutter_model_real_get_n_rows; /** * ClutterModel:filter-set: * * Whether the #ClutterModel has a filter set * * This property is set to %TRUE if a filter function has been * set using clutter_model_set_filter() * * Since: 1.0 * * Deprecated: 1.24: Use #GListModel instead */ pspec = g_param_spec_boolean ("filter-set", "Filter Set", "Whether the model has a filter", FALSE, CLUTTER_PARAM_READABLE); g_object_class_install_property (gobject_class, PROP_FILTER_SET, pspec); /** * ClutterModel::row-added: * @model: the #ClutterModel on which the signal is emitted * @iter: a #ClutterModelIter pointing to the new row * * The ::row-added signal is emitted when a new row has been added. * The data on the row has already been set when the ::row-added signal * has been emitted. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ model_signals[ROW_ADDED] = g_signal_new ("row-added", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, row_added), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_MODEL_ITER); /** * ClutterModel::row-removed: * @model: the #ClutterModel on which the signal is emitted * @iter: a #ClutterModelIter pointing to the removed row * * The ::row-removed signal is emitted when a row has been removed. * The data on the row pointed by the passed iterator is still valid * when the ::row-removed signal has been emitted. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ model_signals[ROW_REMOVED] = g_signal_new ("row-removed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, row_removed), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_MODEL_ITER); /** * ClutterModel::row-changed: * @model: the #ClutterModel on which the signal is emitted * @iter: a #ClutterModelIter pointing to the changed row * * The ::row-removed signal is emitted when a row has been changed. * The data on the row has already been updated when the ::row-changed * signal has been emitted. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ model_signals[ROW_CHANGED] = g_signal_new ("row-changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, row_changed), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_MODEL_ITER); /** * ClutterModel::sort-changed: * @model: the #ClutterModel on which the signal is emitted * * The ::sort-changed signal is emitted after the model has been sorted * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ model_signals[SORT_CHANGED] = g_signal_new ("sort-changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, sort_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterModel::filter-changed: * @model: the #ClutterModel on which the signal is emitted * * The ::filter-changed signal is emitted when a new filter has been applied * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ model_signals[FILTER_CHANGED] = g_signal_new ("filter-changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, filter_changed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void clutter_model_init (ClutterModel *self) { ClutterModelPrivate *priv; self->priv = priv = clutter_model_get_instance_private (self); priv->n_columns = -1; priv->column_types = NULL; priv->column_names = NULL; priv->filter_func = NULL; priv->filter_data = NULL; priv->filter_notify = NULL; priv->sort_column = -1; priv->sort_func = NULL; priv->sort_data = NULL; priv->sort_notify = NULL; } /* XXX - is this whitelist really necessary? we accept every fundamental * type. */ gboolean _clutter_model_check_type (GType gtype) { gint i = 0; static const GType type_list[] = { G_TYPE_BOOLEAN, G_TYPE_CHAR, G_TYPE_UCHAR, G_TYPE_INT, G_TYPE_UINT, G_TYPE_LONG, G_TYPE_ULONG, G_TYPE_INT64, G_TYPE_UINT64, G_TYPE_ENUM, G_TYPE_FLAGS, G_TYPE_FLOAT, G_TYPE_DOUBLE, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOXED, G_TYPE_OBJECT, G_TYPE_INVALID }; if (! G_TYPE_IS_VALUE_TYPE (gtype)) return FALSE; while (type_list[i] != G_TYPE_INVALID) { if (g_type_is_a (gtype, type_list[i])) return TRUE; i++; } return FALSE; } typedef struct { gchar *name; GType type; } ColumnInfo; static gboolean clutter_model_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { if (strcmp (name, "columns") == 0) { GSList *columns = NULL; GList *elements, *l; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) return FALSE; elements = json_array_get_elements (json_node_get_array (node)); for (l = elements; l != NULL; l = l->next) { JsonNode *child_node = l->data; JsonArray *array = json_node_get_array (child_node); ColumnInfo *cinfo; const gchar *column_name; const gchar *type_name; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY || json_array_get_length (array) != 2) { g_warning ("A column must be an array of " "[\"column-name\", \"GType-name\"] pairs"); return FALSE; } column_name = json_array_get_string_element (array, 0); type_name = json_array_get_string_element (array, 1); cinfo = g_slice_new0 (ColumnInfo); cinfo->name = g_strdup (column_name); cinfo->type = clutter_script_get_type_from_name (script, type_name); columns = g_slist_prepend (columns, cinfo); } g_list_free (elements); g_value_init (value, G_TYPE_POINTER); g_value_set_pointer (value, g_slist_reverse (columns)); return TRUE; } else if (strcmp (name, "rows") == 0) { GSList *rows = NULL; GList *elements, *l; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) return FALSE; /* * at this point we have no information about the column types, so * we just copy the json elements and resolve them in the * set_custom_property method */ elements = json_array_get_elements (json_node_get_array (node)); for (l = elements; l != NULL; l = l->next) rows = g_slist_prepend (rows, json_node_copy (l->data)); g_list_free (elements); g_value_init (value, G_TYPE_POINTER); g_value_set_pointer (value, g_slist_reverse (rows)); return TRUE; } return FALSE; } static void clutter_model_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { if (strcmp (name, "columns") == 0) { ClutterModel *model = CLUTTER_MODEL (scriptable); GSList *columns, *l; guint n_columns; gint i; columns = g_value_get_pointer (value); n_columns = g_slist_length (columns); _clutter_model_set_n_columns (model, n_columns, TRUE, TRUE); for (i = 0, l = columns; l != NULL; l = l->next, i++) { ColumnInfo *cinfo = l->data; _clutter_model_set_column_name (model, i, cinfo->name); _clutter_model_set_column_type (model, i, cinfo->type); free (cinfo->name); g_slice_free (ColumnInfo, cinfo); } g_slist_free (columns); } else if (strcmp (name, "rows") == 0) { ClutterModel *model = CLUTTER_MODEL (scriptable); GSList *rows, *l; guint n_columns, row = 0; rows = g_value_get_pointer (value); n_columns = clutter_model_get_n_columns (model); for (l = rows; l; l = l->next) { JsonNode *node = l->data; guint *columns = NULL, i, n_values = 0; GValue *values = NULL; if (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY) { JsonArray *array = json_node_get_array (node); if (json_array_get_length (array) != n_columns) { g_warning ("Row %d contains the wrong count of columns", g_slist_position (rows, l) + 1); row += 1; continue; } /* array more requires all columns */ n_values = n_columns; columns = g_new (guint, n_values); values = g_new0 (GValue, n_values); for (i = 0; i < n_values; i++) { GType column_type; const gchar *column_name; column_type = clutter_model_get_column_type (model, i); column_name = clutter_model_get_column_name (model, i); columns[i] = i; g_value_init (&values[i], column_type); _clutter_script_parse_node (script, &values[i], column_name, json_array_get_element (array, i), NULL); } } else if (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT) { JsonObject *object = json_node_get_object (node); GList *members, *m; guint column = 0; /* object mode does not require all columns */ n_values = json_object_get_size (object); columns = g_new (guint, n_values); values = g_new0 (GValue, n_values); members = json_object_get_members (object); for (m = members; m; m = m->next) { const gchar *mname = m->data; for (i = 0; i < clutter_model_get_n_columns (model); i++) { const gchar *cname; cname = clutter_model_get_column_name (model, i); if (strcmp (mname, cname) == 0) { JsonNode *member; GType col_type; const gchar *col_name; member = json_object_get_member (object, mname); col_type = clutter_model_get_column_type (model, i); col_name = clutter_model_get_column_name (model, i); columns[column] = i; g_value_init (&values[column], col_type); _clutter_script_parse_node (script, &values[column], col_name, member, NULL); break; } } column += 1; } } else { row += 1; continue; } clutter_model_insertv (model, row, n_values, columns, values); free (values); free (columns); json_node_free (node); row += 1; } g_slist_free (rows); } } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_model_parse_custom_node; iface->set_custom_property = clutter_model_set_custom_property; } /** * clutter_model_resort: * @model: a #ClutterModel * * Force a resort on the @model. This function should only be * used by subclasses of #ClutterModel. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_resort (ClutterModel *model) { ClutterModelPrivate *priv; ClutterModelClass *klass; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; klass = CLUTTER_MODEL_GET_CLASS (model); if (klass->resort) klass->resort (model, priv->sort_func, priv->sort_data); } /** * clutter_model_filter_row: * @model: a #ClutterModel * @row: the row to filter * * Checks whether @row should be filtered or not using the * filtering function set on @model. * * This function should be used only by subclasses of #ClutterModel. * * Return value: %TRUE if the row should be displayed, * %FALSE otherwise * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ gboolean clutter_model_filter_row (ClutterModel *model, guint row) { ClutterModelPrivate *priv; ClutterModelIter *iter; gboolean res = TRUE; g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE); priv = model->priv; if (!priv->filter_func) return TRUE; iter = clutter_model_get_iter_at_row (model, row); if (iter == NULL) return FALSE; res = priv->filter_func (model, iter, priv->filter_data); g_object_unref (iter); return res; } /** * clutter_model_filter_iter: * @model: a #ClutterModel * @iter: the row to filter * * Checks whether the row pointer by @iter should be filtered or not using * the filtering function set on @model. * * This function should be used only by subclasses of #ClutterModel. * * Return value: %TRUE if the row should be displayed, * %FALSE otherwise * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ gboolean clutter_model_filter_iter (ClutterModel *model, ClutterModelIter *iter) { ClutterModelPrivate *priv; g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE); g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), TRUE); priv = model->priv; if (!priv->filter_func) return TRUE; return priv->filter_func (model, iter, priv->filter_data); } /*< private > * clutter_model_set_n_columns: * @model: a #ClutterModel * @n_columns: number of columns * @set_types: set the columns type * @set_names: set the columns name * * Sets the number of columns in @model to @n_columns. If @set_types * or @set_names are %TRUE, initialises the columns type and name * arrays as well. * * This function can only be called once. * * Deprecated: 1.24: Use #GListModel instead */ void _clutter_model_set_n_columns (ClutterModel *model, gint n_columns, gboolean set_types, gboolean set_names) { ClutterModelPrivate *priv = model->priv; if (priv->n_columns > 0 && priv->n_columns != n_columns) return; priv->n_columns = n_columns; if (set_types && !priv->column_types) priv->column_types = g_new0 (GType, n_columns); if (set_names && !priv->column_names) priv->column_names = g_new0 (gchar*, n_columns); } /*< private > * _clutter_model_set_column_type: * @model: a #ClutterModel * @column: column index * @gtype: type of the column * * Sets the type of @column inside @model */ void _clutter_model_set_column_type (ClutterModel *model, gint column, GType gtype) { ClutterModelPrivate *priv = model->priv; priv->column_types[column] = gtype; } /*< private > * _clutter_model_set_column_name: * @model: a #ClutterModel * @column: column index * @name: name of the column, or %NULL * * Sets the name of @column inside @model */ void _clutter_model_set_column_name (ClutterModel *model, gint column, const gchar *name) { ClutterModelPrivate *priv = model->priv; priv->column_names[column] = g_strdup (name); } /** * clutter_model_set_types: * @model: a #ClutterModel * @n_columns: number of columns for the model * @types: (array length=n_columns): an array of #GType types * * Sets the types of the columns inside a #ClutterModel. * * This function is meant primarily for #GObjects that inherit from * #ClutterModel, and should only be used when contructing a #ClutterModel. * It will not work after the initial creation of the #ClutterModel. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_set_types (ClutterModel *model, guint n_columns, GType *types) { ClutterModelPrivate *priv; gint i; g_return_if_fail (CLUTTER_IS_MODEL (model)); g_return_if_fail (n_columns > 0); priv = model->priv; g_return_if_fail (priv->n_columns < 0 || priv->n_columns == n_columns); g_return_if_fail (priv->column_types == NULL); _clutter_model_set_n_columns (model, n_columns, TRUE, FALSE); for (i = 0; i < n_columns; i++) { if (!_clutter_model_check_type (types[i])) { g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i])); return; } _clutter_model_set_column_type (model, i, types[i]); } } /** * clutter_model_set_names: * @model: a #ClutterModel * @n_columns: the number of column names * @names: (array length=n_columns): an array of strings * * Assigns a name to the columns of a #ClutterModel. * * This function is meant primarily for #GObjects that inherit from * #ClutterModel, and should only be used when contructing a #ClutterModel. * It will not work after the initial creation of the #ClutterModel. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_set_names (ClutterModel *model, guint n_columns, const gchar * const names[]) { ClutterModelPrivate *priv; gint i; g_return_if_fail (CLUTTER_IS_MODEL (model)); g_return_if_fail (n_columns > 0); priv = model->priv; g_return_if_fail (priv->n_columns < 0 || priv->n_columns == n_columns); g_return_if_fail (priv->column_names == NULL); _clutter_model_set_n_columns (model, n_columns, FALSE, TRUE); for (i = 0; i < n_columns; i++) _clutter_model_set_column_name (model, i, names[i]); } /** * clutter_model_get_n_columns: * @model: a #ClutterModel * * Retrieves the number of columns inside @model. * * Return value: the number of columns * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ guint clutter_model_get_n_columns (ClutterModel *model) { g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0); return CLUTTER_MODEL_GET_CLASS (model)->get_n_columns (model); } /** * clutter_model_appendv: * @model: a #ClutterModel * @n_columns: the number of columns and values * @columns: (array length=n_columns): a vector with the columns to set * @values: (array length=n_columns): a vector with the values * * Creates and appends a new row to the #ClutterModel, setting the row * values for the given @columns upon creation. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_appendv (ClutterModel *model, guint n_columns, guint *columns, GValue *values) { ClutterModelPrivate *priv; ClutterModelIter *iter; gint i; gboolean resort = FALSE; g_return_if_fail (CLUTTER_IS_MODEL (model)); g_return_if_fail (n_columns <= clutter_model_get_n_columns (model)); g_return_if_fail (columns != NULL); g_return_if_fail (values != NULL); priv = model->priv; iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1); g_assert (CLUTTER_IS_MODEL_ITER (iter)); for (i = 0; i < n_columns; i++) { if (priv->sort_column == columns[i]) resort = TRUE; clutter_model_iter_set_value (iter, columns[i], &values[i]); } g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); if (resort) clutter_model_resort (model); g_object_unref (iter); } /* forward declaration */ static void clutter_model_iter_set_internal_valist (ClutterModelIter *iter, va_list args); /** * clutter_model_append: * @model: a #ClutterModel * @...: pairs of column number and value, terminated with -1 * * Creates and appends a new row to the #ClutterModel, setting the * row values upon creation. For example, to append a new row where * column 0 is type %G_TYPE_INT and column 1 is of type %G_TYPE_STRING: * * * ClutterModel *model; * model = clutter_model_default_new (2, * G_TYPE_INT, "Score", * G_TYPE_STRING, "Team"); * clutter_model_append (model, 0, 42, 1, "Team #1", -1); * * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_append (ClutterModel *model, ...) { ClutterModelIter *iter; va_list args; g_return_if_fail (CLUTTER_IS_MODEL (model)); iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1); g_assert (CLUTTER_IS_MODEL_ITER (iter)); /* do not emit the ::row-changed signal */ va_start (args, model); clutter_model_iter_set_internal_valist (iter, args); va_end (args); g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); g_object_unref (iter); } /** * clutter_model_prependv: * @model: a #ClutterModel * @n_columns: the number of columns and values to set * @columns: (array length=n_columns): a vector containing the columns to set * @values: (array length=n_columns): a vector containing the values for the cells * * Creates and prepends a new row to the #ClutterModel, setting the row * values for the given @columns upon creation. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_prependv (ClutterModel *model, guint n_columns, guint *columns, GValue *values) { ClutterModelPrivate *priv; ClutterModelIter *iter; gint i; gboolean resort = FALSE; g_return_if_fail (CLUTTER_IS_MODEL (model)); g_return_if_fail (n_columns <= clutter_model_get_n_columns (model)); g_return_if_fail (columns != NULL); g_return_if_fail (values != NULL); priv = model->priv; iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0); g_assert (CLUTTER_IS_MODEL_ITER (iter)); for (i = 0; i < n_columns; i++) { if (priv->sort_column == columns[i]) resort = TRUE; clutter_model_iter_set_value (iter, columns[i], &values[i]); } g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); if (resort) clutter_model_resort (model); g_object_unref (iter); } /** * clutter_model_prepend: * @model: a #ClutterModel * @...: pairs of column number and value, terminated with -1 * * Creates and prepends a new row to the #ClutterModel, setting the row * values upon creation. For example, to prepend a new row where column 0 * is type %G_TYPE_INT and column 1 is of type %G_TYPE_STRING: * * * ClutterModel *model; * model = clutter_model_default_new (2, * G_TYPE_INT, "Score", * G_TYPE_STRING, "Team"); * clutter_model_prepend (model, 0, 42, 1, "Team #1", -1); * * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_prepend (ClutterModel *model, ...) { ClutterModelIter *iter; va_list args; g_return_if_fail (CLUTTER_IS_MODEL (model)); iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0); g_assert (CLUTTER_IS_MODEL_ITER (iter)); va_start (args, model); clutter_model_iter_set_internal_valist (iter, args); va_end (args); g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); g_object_unref (iter); } /** * clutter_model_insert: * @model: a #ClutterModel * @row: the position to insert the new row * @...: pairs of column number and value, terminated with -1 * * Inserts a new row to the #ClutterModel at @row, setting the row * values upon creation. For example, to insert a new row at index 100, * where column 0 is type %G_TYPE_INT and column 1 is of type * %G_TYPE_STRING: * * * ClutterModel *model; * model = clutter_model_default_new (2, * G_TYPE_INT, "Score", * G_TYPE_STRING, "Team"); * clutter_model_insert (model, 3, 0, 42, 1, "Team #1", -1); * * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_insert (ClutterModel *model, guint row, ...) { ClutterModelIter *iter; va_list args; g_return_if_fail (CLUTTER_IS_MODEL (model)); iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, row); g_assert (CLUTTER_IS_MODEL_ITER (iter)); /* set_valist() will call clutter_model_resort() if one of the * passed columns matches the model sorting column index */ va_start (args, row); clutter_model_iter_set_internal_valist (iter, args); va_end (args); g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); g_object_unref (iter); } /** * clutter_model_insertv: * @model: a #ClutterModel * @row: row index * @n_columns: the number of columns and values to set * @columns: (array length=n_columns): a vector containing the columns to set * @values: (array length=n_columns): a vector containing the values for the cells * * Inserts data at @row into the #ClutterModel, setting the row * values for the given @columns upon creation. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_insertv (ClutterModel *model, guint row, guint n_columns, guint *columns, GValue *values) { ClutterModelPrivate *priv; ClutterModelIter *iter; gint i; gboolean resort = FALSE; g_return_if_fail (CLUTTER_IS_MODEL (model)); g_return_if_fail (n_columns <= clutter_model_get_n_columns (model)); g_return_if_fail (columns != NULL); g_return_if_fail (values != NULL); priv = model->priv; iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, row); g_assert (CLUTTER_IS_MODEL_ITER (iter)); for (i = 0; i < n_columns; i++) { if (priv->sort_column == columns[i]) resort = TRUE; clutter_model_iter_set_value (iter, columns[i], &values[i]); } g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); if (resort) clutter_model_resort (model); g_object_unref (iter); } /** * clutter_model_insert_value: * @model: a #ClutterModel * @row: position of the row to modify * @column: column to modify * @value: new value for the cell * * Sets the data in the cell specified by @iter and @column. The type of * @value must be convertable to the type of the column. If the row does * not exist then it is created. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_insert_value (ClutterModel *model, guint row, guint column, const GValue *value) { ClutterModelPrivate *priv; ClutterModelClass *klass; ClutterModelIter *iter; gboolean added = FALSE; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; klass = CLUTTER_MODEL_GET_CLASS (model); iter = klass->get_iter_at_row (model, row); if (!iter) { iter = klass->insert_row (model, row); added = TRUE; } g_assert (CLUTTER_IS_MODEL_ITER (iter)); clutter_model_iter_set_value (iter, column, value); if (added) g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); if (priv->sort_column == column) clutter_model_resort (model); g_object_unref (iter); } /** * clutter_model_remove: * @model: a #ClutterModel * @row: position of row to remove * * Removes the row at the given position from the model. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_remove (ClutterModel *model, guint row) { ClutterModelClass *klass; g_return_if_fail (CLUTTER_IS_MODEL (model)); klass = CLUTTER_MODEL_GET_CLASS (model); if (klass->remove_row) klass->remove_row (model, row); } /** * clutter_model_get_column_name: * @model: #ClutterModel * @column: the column number * * Retrieves the name of the @column * * Return value: the name of the column. The model holds the returned * string, and it should not be modified or freed * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ const gchar * clutter_model_get_column_name (ClutterModel *model, guint column) { ClutterModelClass *klass; g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL); if (column >= clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column); return NULL; } klass = CLUTTER_MODEL_GET_CLASS (model); if (klass->get_column_name) return klass->get_column_name (model, column); return NULL; } /** * clutter_model_get_column_type: * @model: #ClutterModel * @column: the column number * * Retrieves the type of the @column. * * Return value: the type of the column. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ GType clutter_model_get_column_type (ClutterModel *model, guint column) { ClutterModelClass *klass; g_return_val_if_fail (CLUTTER_IS_MODEL (model), G_TYPE_INVALID); if (column >= clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column); return G_TYPE_INVALID; } klass = CLUTTER_MODEL_GET_CLASS (model); if (klass->get_column_type) return klass->get_column_type (model, column); return G_TYPE_INVALID; } /** * clutter_model_get_iter_at_row: * @model: a #ClutterModel * @row: position of the row to retrieve * * Retrieves a #ClutterModelIter representing the row at the given index. * * If a filter function has been set using clutter_model_set_filter() * then the @model implementation will return the first non filtered * row. * * Return value: (transfer full): A new #ClutterModelIter, or %NULL if @row was * out of bounds. When done using the iterator object, call g_object_unref() * to deallocate its resources * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ ClutterModelIter * clutter_model_get_iter_at_row (ClutterModel *model, guint row) { ClutterModelClass *klass; g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL); klass = CLUTTER_MODEL_GET_CLASS (model); if (klass->get_iter_at_row) return klass->get_iter_at_row (model, row); return NULL; } /** * clutter_model_get_first_iter: * @model: a #ClutterModel * * Retrieves a #ClutterModelIter representing the first non-filtered * row in @model. * * Return value: (transfer full): A new #ClutterModelIter. * Call g_object_unref() when done using it * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ ClutterModelIter * clutter_model_get_first_iter (ClutterModel *model) { ClutterModelIter *retval; g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL); retval = clutter_model_get_iter_at_row (model, 0); if (retval != NULL) { g_assert (clutter_model_filter_iter (model, retval) != FALSE); g_assert (clutter_model_iter_get_row (retval) == 0); } return retval; } /** * clutter_model_get_last_iter: * @model: a #ClutterModel * * Retrieves a #ClutterModelIter representing the last non-filtered * row in @model. * * Return value: (transfer full): A new #ClutterModelIter. * Call g_object_unref() when done using it * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ ClutterModelIter * clutter_model_get_last_iter (ClutterModel *model) { ClutterModelIter *retval; guint length; g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL); length = clutter_model_get_n_rows (model); retval = clutter_model_get_iter_at_row (model, length - 1); if (retval != NULL) g_assert (clutter_model_filter_iter (model, retval) != FALSE); return retval; } /** * clutter_model_get_n_rows: * @model: a #ClutterModel * * Retrieves the number of rows inside @model, eventually taking * into account any filtering function set using clutter_model_set_filter(). * * Return value: The length of the @model. If there is a filter set, then * the length of the filtered @model is returned. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ guint clutter_model_get_n_rows (ClutterModel *model) { g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0); return CLUTTER_MODEL_GET_CLASS (model)->get_n_rows (model); } /** * clutter_model_set_sorting_column: * @model: a #ClutterModel * @column: the column of the @model to sort, or -1 * * Sets the model to sort by @column. If @column is a negative value * the sorting column will be unset. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_set_sorting_column (ClutterModel *model, gint column) { ClutterModelPrivate *priv; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; /* The extra comparison for >= 0 is because column gets promoted to unsigned in the second comparison */ if (column >= 0 && column >= clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column); return; } priv->sort_column = column; if (priv->sort_column >= 0) clutter_model_resort (model); g_signal_emit (model, model_signals[SORT_CHANGED], 0); } /** * clutter_model_get_sorting_column: * @model: a #ClutterModel * * Retrieves the number of column used for sorting the @model. * * Return value: a column number, or -1 if the model is not sorted * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ gint clutter_model_get_sorting_column (ClutterModel *model) { g_return_val_if_fail (CLUTTER_IS_MODEL (model), -1); return model->priv->sort_column; } /** * clutter_model_foreach: * @model: a #ClutterModel * @func: (scope call): a #ClutterModelForeachFunc * @user_data: user data to pass to @func * * Calls @func for each row in the model. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_foreach (ClutterModel *model, ClutterModelForeachFunc func, gpointer user_data) { ClutterModelIter *iter; g_return_if_fail (CLUTTER_IS_MODEL (model)); iter = clutter_model_get_first_iter (model); if (!iter) return; while (!clutter_model_iter_is_last (iter)) { if (clutter_model_filter_iter (model, iter)) { if (!func (model, iter, user_data)) break; } iter = clutter_model_iter_next (iter); } g_object_unref (iter); } /** * clutter_model_set_sort: * @model: a #ClutterModel * @column: the column to sort on * @func: (allow-none): a #ClutterModelSortFunc, or #NULL * @user_data: user data to pass to @func, or #NULL * @notify: destroy notifier of @user_data, or #NULL * * Sorts @model using the given sorting function. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_set_sort (ClutterModel *model, gint column, ClutterModelSortFunc func, gpointer user_data, GDestroyNotify notify) { ClutterModelPrivate *priv; g_return_if_fail (CLUTTER_IS_MODEL (model)); g_return_if_fail ((func != NULL && column >= 0) || (func == NULL && column == -1)); priv = model->priv; if (priv->sort_notify) priv->sort_notify (priv->sort_data); priv->sort_func = func; priv->sort_data = user_data; priv->sort_notify = notify; /* This takes care of calling _model_sort & emitting the signal*/ clutter_model_set_sorting_column (model, column); } /** * clutter_model_set_filter: * @model: a #ClutterModel * @func: (allow-none): a #ClutterModelFilterFunc, or #NULL * @user_data: user data to pass to @func, or #NULL * @notify: destroy notifier of @user_data, or #NULL * * Filters the @model using the given filtering function. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_set_filter (ClutterModel *model, ClutterModelFilterFunc func, gpointer user_data, GDestroyNotify notify) { ClutterModelPrivate *priv; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; if (priv->filter_notify) priv->filter_notify (priv->filter_data); priv->filter_func = func; priv->filter_data = user_data; priv->filter_notify = notify; g_signal_emit (model, model_signals[FILTER_CHANGED], 0); g_object_notify (G_OBJECT (model), "filter-set"); } /** * clutter_model_get_filter_set: * @model: a #ClutterModel * * Returns whether the @model has a filter in place, set * using clutter_model_set_filter() * * Return value: %TRUE if a filter is set * * Since: 1.0 * * Deprecated: 1.24: Use #GListModel instead */ gboolean clutter_model_get_filter_set (ClutterModel *model) { g_return_val_if_fail (CLUTTER_IS_MODEL (model), FALSE); return model->priv->filter_func != NULL; } /* * ClutterModelIter Object */ /** * SECTION:clutter-model-iter * @short_description: Iterates through a model * * #ClutterModelIter is an object used for iterating through all the rows * of a #ClutterModel. It allows setting and getting values on the row * which is currently pointing at. * * A #ClutterModelIter represents a position between two elements * of the sequence. For example, the iterator returned by * clutter_model_get_first_iter() represents the gap immediately before * the first row of the #ClutterModel, and the iterator returned by * clutter_model_get_last_iter() represents the gap immediately after the * last row. * * A #ClutterModelIter can only be created by a #ClutterModel implementation * and it is valid as long as the model does not change. * * #ClutterModelIter is available since Clutter 0.6 * * Deprecated: 1.24: Use #GListModel instead */ struct _ClutterModelIterPrivate { ClutterModel *model; gint row; }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterModelIter, clutter_model_iter, G_TYPE_OBJECT) enum { ITER_PROP_0, ITER_PROP_MODEL, ITER_PROP_ROW }; static ClutterModel * clutter_model_iter_real_get_model (ClutterModelIter *iter) { return iter->priv->model; } static guint clutter_model_iter_real_get_row (ClutterModelIter *iter) { return iter->priv->row; } /* private function */ void _clutter_model_iter_set_row (ClutterModelIter *iter, guint row) { iter->priv->row = row; } static void clutter_model_iter_get_value_unimplemented (ClutterModelIter *iter, guint column, GValue *value) { g_warning ("%s: Iterator of type '%s' does not implement the " "ClutterModelIter::get_value() virtual function", G_STRLOC, g_type_name (G_OBJECT_TYPE (iter))); } static void clutter_model_iter_set_value_unimplemented (ClutterModelIter *iter, guint column, const GValue *value) { g_warning ("%s: Iterator of type '%s' does not implement the " "ClutterModelIter::set_value() virtual function", G_STRLOC, g_type_name (G_OBJECT_TYPE (iter))); } static gboolean clutter_model_iter_is_first_unimplemented (ClutterModelIter *iter) { g_warning ("%s: Iterator of type '%s' does not implement the " "ClutterModelIter::is_first() virtual function", G_STRLOC, g_type_name (G_OBJECT_TYPE (iter))); return FALSE; } static gboolean clutter_model_iter_is_last_unimplemented (ClutterModelIter *iter) { g_warning ("%s: Iterator of type '%s' does not implement the " "ClutterModelIter::is_last() virtual function", G_STRLOC, g_type_name (G_OBJECT_TYPE (iter))); return FALSE; } static ClutterModelIter * clutter_model_iter_next_unimplemented (ClutterModelIter *iter) { g_warning ("%s: Iterator of type '%s' does not implement the " "ClutterModelIter::next() virtual function", G_STRLOC, g_type_name (G_OBJECT_TYPE (iter))); return NULL; } static ClutterModelIter * clutter_model_iter_prev_unimplemented (ClutterModelIter *iter) { g_warning ("%s: Iterator of type '%s' does not implement the " "ClutterModelIter::prev() virtual function", G_STRLOC, g_type_name (G_OBJECT_TYPE (iter))); return NULL; } static ClutterModelIter * clutter_model_iter_copy_unimplemented (ClutterModelIter *iter) { g_warning ("%s: Iterator of type '%s' does not implement the " "ClutterModelIter::copy() virtual function", G_STRLOC, g_type_name (G_OBJECT_TYPE (iter))); return NULL; } static void clutter_model_iter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterModelIter *iter = CLUTTER_MODEL_ITER (object); ClutterModelIterPrivate *priv = iter->priv; switch (prop_id) { case ITER_PROP_MODEL: g_value_set_object (value, priv->model); break; case ITER_PROP_ROW: g_value_set_uint (value, priv->row); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_model_iter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterModelIter *iter = CLUTTER_MODEL_ITER (object); ClutterModelIterPrivate *priv = iter->priv; switch (prop_id) { case ITER_PROP_MODEL: priv->model = g_value_get_object (value); break; case ITER_PROP_ROW: priv->row = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_model_iter_class_init (ClutterModelIterClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->get_property = clutter_model_iter_get_property; gobject_class->set_property = clutter_model_iter_set_property; klass->get_model = clutter_model_iter_real_get_model; klass->get_row = clutter_model_iter_real_get_row; klass->is_first = clutter_model_iter_is_first_unimplemented; klass->is_last = clutter_model_iter_is_last_unimplemented; klass->next = clutter_model_iter_next_unimplemented; klass->prev = clutter_model_iter_prev_unimplemented; klass->get_value = clutter_model_iter_get_value_unimplemented; klass->set_value = clutter_model_iter_set_value_unimplemented; klass->copy = clutter_model_iter_copy_unimplemented; /* Properties */ /** * ClutterModelIter:model: * * A reference to the #ClutterModel that this iter belongs to. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ pspec = g_param_spec_object ("model", "Model", "The model to which the iterator belongs to", CLUTTER_TYPE_MODEL, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, ITER_PROP_MODEL, pspec); /** * ClutterModelIter:row: * * The row number to which this iter points to. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ pspec = g_param_spec_uint ("row", "Row", "The row to which the iterator points to", 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, ITER_PROP_ROW, pspec); } static void clutter_model_iter_init (ClutterModelIter *self) { self->priv = clutter_model_iter_get_instance_private (self); } /* * Public functions */ static inline void clutter_model_iter_set_value_internal (ClutterModelIter *iter, guint column, const GValue *value) { CLUTTER_MODEL_ITER_GET_CLASS (iter)->set_value (iter, column, value); } static void clutter_model_iter_set_internal_valist (ClutterModelIter *iter, va_list args) { ClutterModelIterPrivate *priv = iter->priv; ClutterModel *model = priv->model; guint column = 0; gboolean sort = FALSE; g_assert (CLUTTER_IS_MODEL (model)); column = va_arg (args, gint); while (column != -1) { GValue value = G_VALUE_INIT; gchar *error = NULL; GType col_type; if (column >= clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column number %d added to iter " "(remember to end you list of columns with a -1)", G_STRLOC, column); break; } col_type = clutter_model_get_column_type (model, column); G_VALUE_COLLECT_INIT (&value, col_type, args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); /* Leak value as it might not be in a sane state */ break; } clutter_model_iter_set_value_internal (iter, column, &value); g_value_unset (&value); if (column == clutter_model_get_sorting_column (model)) sort = TRUE; column = va_arg (args, gint); } if (sort) clutter_model_resort (model); } static void inline clutter_model_iter_emit_row_changed (ClutterModelIter *iter) { ClutterModelIterPrivate *priv = iter->priv; ClutterModel *model = priv->model; g_assert (CLUTTER_IS_MODEL (model)); g_signal_emit (model, model_signals[ROW_CHANGED], 0, iter); } /** * clutter_model_iter_set_valist: * @iter: a #ClutterModelIter * @args: va_list of column/value pairs, terminiated by -1 * * See clutter_model_iter_set(); this version takes a va_list for language * bindings. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_iter_set_valist (ClutterModelIter *iter, va_list args) { g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); clutter_model_iter_set_internal_valist (iter, args); clutter_model_iter_emit_row_changed (iter); } /** * clutter_model_iter_get: * @iter: a #ClutterModelIter * @...: a list of column/return location pairs, terminated by -1 * * Gets the value of one or more cells in the row referenced by @iter. The * variable argument list should contain integer column numbers, each column * column number followed by a place to store the value being retrieved. The * list is terminated by a -1. * * For example, to get a value from column 0 with type %G_TYPE_STRING use: * * clutter_model_iter_get (iter, 0, &place_string_here, -1); * * * where place_string_here is a gchar* to be filled with the string. If * appropriate, the returned values have to be freed or unreferenced. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_iter_get (ClutterModelIter *iter, ...) { va_list args; g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); va_start (args, iter); clutter_model_iter_get_valist (iter, args); va_end (args); } static inline void clutter_model_iter_get_value_internal (ClutterModelIter *iter, guint column, GValue *value) { CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_value (iter, column, value); } /** * clutter_model_iter_get_value: * @iter: a #ClutterModelIter * @column: column number to retrieve the value from * @value: (out): an empty #GValue to set * * Sets an initializes @value to that at @column. When done with @value, * g_value_unset() needs to be called to free any allocated memory. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_iter_get_value (ClutterModelIter *iter, guint column, GValue *value) { ClutterModel *model; g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); model = iter->priv->model; if (G_VALUE_TYPE (value) == G_TYPE_INVALID) g_value_init (value, clutter_model_get_column_type (model, column)); CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_value (iter, column, value); } /** * clutter_model_iter_get_valist: * @iter: a #ClutterModelIter * @args: a list of column/return location pairs, terminated by -1 * * See clutter_model_iter_get(). This version takes a va_list for language * bindings. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_iter_get_valist (ClutterModelIter *iter, va_list args) { ClutterModelIterPrivate *priv; ClutterModel *model; guint column = 0; g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); priv = iter->priv; model = priv->model; g_assert (CLUTTER_IS_MODEL (model)); column = va_arg (args, gint); while (column != -1) { GValue value = G_VALUE_INIT; gchar *error = NULL; GType col_type; if (column >= clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column number %d added to iter " "(remember to end you list of columns with a -1)", G_STRLOC, column); break; } col_type = clutter_model_get_column_type (model, column); g_value_init (&value, col_type); clutter_model_iter_get_value_internal (iter, column, &value); G_VALUE_LCOPY (&value, args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); /* Leak value as it might not be in a sane state */ break; } g_value_unset (&value); column = va_arg (args, gint); } } /** * clutter_model_iter_set: * @iter: a #ClutterModelIter * @...: a list of column/return location pairs, terminated by -1 * * Sets the value of one or more cells in the row referenced by @iter. The * variable argument list should contain integer column numbers, each column * column number followed by the value to be set. The list is terminated by a * -1. * * For example, to set column 0 with type %G_TYPE_STRING, use: * * clutter_model_iter_set (iter, 0, "foo", -1); * * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_iter_set (ClutterModelIter *iter, ...) { va_list args; g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); va_start (args, iter); clutter_model_iter_set_internal_valist (iter, args); clutter_model_iter_emit_row_changed (iter); va_end (args); } /** * clutter_model_iter_set_value: * @iter: a #ClutterModelIter * @column: column number to retrieve the value from * @value: new value for the cell * * Sets the data in the cell specified by @iter and @column. The type of * @value must be convertable to the type of the column. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ void clutter_model_iter_set_value (ClutterModelIter *iter, guint column, const GValue *value) { g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); clutter_model_iter_set_value_internal (iter, column, value); clutter_model_iter_emit_row_changed (iter); } /** * clutter_model_iter_is_first: * @iter: a #ClutterModelIter * * Gets whether the current iterator is at the beginning of the model * to which it belongs. * * Return value: #TRUE if @iter is the first iter in the filtered model * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ gboolean clutter_model_iter_is_first (ClutterModelIter *iter) { g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE); return CLUTTER_MODEL_ITER_GET_CLASS (iter)->is_first (iter); } /** * clutter_model_iter_is_last: * @iter: a #ClutterModelIter * * Gets whether the iterator is at the end of the model to which it * belongs. * * Return value: #TRUE if @iter is the last iter in the filtered model. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ gboolean clutter_model_iter_is_last (ClutterModelIter *iter) { g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE); return CLUTTER_MODEL_ITER_GET_CLASS (iter)->is_last (iter); } /** * clutter_model_iter_next: * @iter: a #ClutterModelIter * * Updates the @iter to point at the next position in the model. * The model implementation should take into account the presence of * a filter function. * * Return value: (transfer none): The passed iterator, updated to point at the next * row in the model. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ ClutterModelIter * clutter_model_iter_next (ClutterModelIter *iter) { g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); return CLUTTER_MODEL_ITER_GET_CLASS (iter)->next (iter); } /** * clutter_model_iter_prev: * @iter: a #ClutterModelIter * * Sets the @iter to point at the previous position in the model. * The model implementation should take into account the presence of * a filter function. * * Return value: (transfer none): The passed iterator, updated to point at the previous * row in the model. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ ClutterModelIter * clutter_model_iter_prev (ClutterModelIter *iter) { g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); return CLUTTER_MODEL_ITER_GET_CLASS (iter)->prev (iter); } /** * clutter_model_iter_get_model: * @iter: a #ClutterModelIter * * Retrieves a pointer to the #ClutterModel that this iter is part of. * * Return value: (transfer none): a pointer to a #ClutterModel. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ ClutterModel * clutter_model_iter_get_model (ClutterModelIter *iter) { g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); return CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_model (iter); } /** * clutter_model_iter_get_row: * @iter: a #ClutterModelIter * * Retrieves the position of the row that the @iter points to. * * Return value: the position of the @iter in the model * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ guint clutter_model_iter_get_row (ClutterModelIter *iter) { g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), 0); return CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_row (iter); } /** * clutter_model_iter_copy: * @iter: a #ClutterModelIter * * Copies the passed iterator. * * Return value: (transfer full): a copy of the iterator, or %NULL * * Since: 0.8 * * Deprecated: 1.24: Use #GListModel instead */ ClutterModelIter * clutter_model_iter_copy (ClutterModelIter *iter) { g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); return CLUTTER_MODEL_ITER_GET_CLASS (iter)->copy (iter); } muffin-5.2.1/clutter/clutter/deprecated/clutter-media.c0000664000175000017500000003771414211404421023317 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Matthew Allum * Emmanuele Bassi * * Copyright (C) 2006 OpenedHand * 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, see . */ /** * SECTION:clutter-media * @short_description: An interface for controlling playback of media data * * #ClutterMedia is an interface for controlling playback of media sources. * * Clutter core does not provide an implementation of this interface, but * other integration libraries like Clutter-GStreamer implement it to offer * a uniform API for applications. * * #ClutterMedia is available since Clutter 0.2 * * #ClutterMedia is deprecated since Clutter 1.12. Use the Clutter-GStreamer * API directly instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-media.h" #include "clutter-main.h" #include "clutter-private.h" /* for DBG */ enum { EOS_SIGNAL, ERROR_SIGNAL, /* can't be called 'ERROR' otherwise it clashes with wingdi.h */ LAST_SIGNAL }; static guint media_signals[LAST_SIGNAL] = { 0, }; typedef ClutterMediaIface ClutterMediaInterface; G_DEFINE_INTERFACE (ClutterMedia, clutter_media, G_TYPE_OBJECT); static void clutter_media_default_init (ClutterMediaInterface *iface) { GParamSpec *pspec = NULL; /** * ClutterMedia:uri: * * The location of a media file, expressed as a valid URI. * * Since: 0.2 * * Deprecated: 1.12 */ pspec = g_param_spec_string ("uri", P_("URI"), P_("URI of a media file"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:playing: * * Whether the #ClutterMedia actor is playing. * * Since: 0.2 * * Deprecated: 1.12 */ pspec = g_param_spec_boolean ("playing", P_("Playing"), P_("Whether the actor is playing"), FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:progress: * * The current progress of the playback, as a normalized * value between 0.0 and 1.0. * * Since: 1.0 * * Deprecated: 1.12 */ pspec = g_param_spec_double ("progress", P_("Progress"), P_("Current progress of the playback"), 0.0, 1.0, 0.0, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:subtitle-uri: * * The location of a subtitle file, expressed as a valid URI. * * Since: 1.2 * * Deprecated: 1.12 */ pspec = g_param_spec_string ("subtitle-uri", P_("Subtitle URI"), P_("URI of a subtitle file"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:subtitle-font-name: * * The font used to display subtitles. The font description has to * follow the same grammar as the one recognized by * pango_font_description_from_string(). * * Since: 1.2 * * Deprecated: 1.12 */ pspec = g_param_spec_string ("subtitle-font-name", P_("Subtitle Font Name"), P_("The font used to display subtitles"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:audio-volume: * * The volume of the audio, as a normalized value between * 0.0 and 1.0. * * Since: 1.0 * * Deprecated: 1.12 */ pspec = g_param_spec_double ("audio-volume", P_("Audio Volume"), P_("The volume of the audio"), 0.0, 1.0, 0.5, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:can-seek: * * Whether the current stream is seekable. * * Since: 0.2 * * Deprecated: 1.12 */ pspec = g_param_spec_boolean ("can-seek", P_("Can Seek"), P_("Whether the current stream is seekable"), FALSE, CLUTTER_PARAM_READABLE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:buffer-fill: * * The fill level of the buffer for the current stream, * as a value between 0.0 and 1.0. * * Since: 1.0 * * Deprecated: 1.12 */ pspec = g_param_spec_double ("buffer-fill", P_("Buffer Fill"), P_("The fill level of the buffer"), 0.0, 1.0, 0.0, CLUTTER_PARAM_READABLE | G_PARAM_DEPRECATED); g_object_interface_install_property (iface, pspec); /** * ClutterMedia:duration: * * The duration of the current stream, in seconds * * Since: 0.2 * * Deprecated: 1.12 */ pspec = g_param_spec_double ("duration", P_("Duration"), P_("The duration of the stream, in seconds"), 0, G_MAXDOUBLE, 0, CLUTTER_PARAM_READABLE); g_object_interface_install_property (iface, pspec); /** * ClutterMedia::eos: * @media: the #ClutterMedia instance that received the signal * * The ::eos signal is emitted each time the media stream ends. * * Since: 0.2 * * Deprecated: 1.12 */ media_signals[EOS_SIGNAL] = g_signal_new (I_("eos"), CLUTTER_TYPE_MEDIA, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterMediaIface, eos), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterMedia::error: * @media: the #ClutterMedia instance that received the signal * @error: the #GError * * The ::error signal is emitted each time an error occurred. * * Since: 0.2 * * Deprecated: 1.12 */ media_signals[ERROR_SIGNAL] = g_signal_new (I_("error"), CLUTTER_TYPE_MEDIA, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterMediaIface, error), NULL, NULL, _clutter_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_ERROR); } /** * clutter_media_set_uri: * @media: a #ClutterMedia * @uri: the URI of the media stream * * Sets the URI of @media to @uri. * * Since: 0.2 * * Deprecated: 1.12 */ void clutter_media_set_uri (ClutterMedia *media, const gchar *uri) { g_return_if_fail (CLUTTER_IS_MEDIA(media)); g_object_set (G_OBJECT (media), "uri", uri, NULL); } /** * clutter_media_get_uri: * @media: a #ClutterMedia * * Retrieves the URI from @media. * * Return value: the URI of the media stream. Use free() * to free the returned string * * Since: 0.2 * * Deprecated: 1.12 */ gchar * clutter_media_get_uri (ClutterMedia *media) { gchar *retval = NULL; g_return_val_if_fail (CLUTTER_IS_MEDIA(media), NULL); g_object_get (G_OBJECT (media), "uri", &retval, NULL); return retval; } /** * clutter_media_set_playing: * @media: a #ClutterMedia * @playing: %TRUE to start playing * * Starts or stops playing of @media. * The implementation might be asynchronous, so the way to know whether * the actual playing state of the @media is to use the #GObject::notify * signal on the #ClutterMedia:playing property and then retrieve the * current state with clutter_media_get_playing(). ClutterGstVideoTexture * in clutter-gst is an example of such an asynchronous implementation. * * Since: 0.2 * * Deprecated: 1.12 */ void clutter_media_set_playing (ClutterMedia *media, gboolean playing) { g_return_if_fail (CLUTTER_IS_MEDIA(media)); g_object_set (G_OBJECT (media), "playing", playing, NULL); } /** * clutter_media_get_playing: * @media: A #ClutterMedia object * * Retrieves the playing status of @media. * * Return value: %TRUE if playing, %FALSE if stopped. * * Since: 0.2 * * Deprecated: 1.12 */ gboolean clutter_media_get_playing (ClutterMedia *media) { gboolean is_playing = FALSE; g_return_val_if_fail (CLUTTER_IS_MEDIA (media), FALSE); g_object_get (G_OBJECT (media), "playing", &is_playing, NULL); return is_playing; } /** * clutter_media_set_progress: * @media: a #ClutterMedia * @progress: the progress of the playback, between 0.0 and 1.0 * * Sets the playback progress of @media. The @progress is * a normalized value between 0.0 (begin) and 1.0 (end). * * Since: 1.0 * * Deprecated: 1.12 */ void clutter_media_set_progress (ClutterMedia *media, gdouble progress) { g_return_if_fail (CLUTTER_IS_MEDIA (media)); g_object_set (G_OBJECT (media), "progress", progress, NULL); } /** * clutter_media_get_progress: * @media: a #ClutterMedia * * Retrieves the playback progress of @media. * * Return value: the playback progress, between 0.0 and 1.0 * * Since: 1.0 * * Deprecated: 1.12 */ gdouble clutter_media_get_progress (ClutterMedia *media) { gdouble retval = 0.0; g_return_val_if_fail (CLUTTER_IS_MEDIA (media), 0); g_object_get (G_OBJECT (media), "progress", &retval, NULL); return retval; } /** * clutter_media_set_subtitle_uri: * @media: a #ClutterMedia * @uri: the URI of a subtitle file * * Sets the location of a subtitle file to display while playing @media. * * Since: 1.2 * * Deprecated: 1.12 */ void clutter_media_set_subtitle_uri (ClutterMedia *media, const char *uri) { g_return_if_fail (CLUTTER_IS_MEDIA (media)); g_object_set (G_OBJECT (media), "subtitle-uri", uri, NULL); } /** * clutter_media_get_subtitle_uri: * @media: a #ClutterMedia * * Retrieves the URI of the subtitle file in use. * * Return value: the URI of the subtitle file. Use free() * to free the returned string * * Since: 1.2 * * Deprecated: 1.12 */ gchar * clutter_media_get_subtitle_uri (ClutterMedia *media) { gchar *retval = NULL; g_return_val_if_fail (CLUTTER_IS_MEDIA(media), NULL); g_object_get (G_OBJECT (media), "subtitle-uri", &retval, NULL); return retval; } /** * clutter_media_set_subtitle_font_name: * @media: a #ClutterMedia * @font_name: a font name, or %NULL to set the default font name * * Sets the font used by the subtitle renderer. The @font_name string must be * either %NULL, which means that the default font name of the underlying * implementation will be used; or must follow the grammar recognized by * pango_font_description_from_string() like: * * |[ * clutter_media_set_subtitle_font_name (media, "Sans 24pt"); * ]| * * Since: 1.2 * * Deprecated: 1.12 */ void clutter_media_set_subtitle_font_name (ClutterMedia *media, const char *font_name) { g_return_if_fail (CLUTTER_IS_MEDIA (media)); g_object_set (G_OBJECT (media), "subtitle-font-name", font_name, NULL); } /** * clutter_media_get_subtitle_font_name: * @media: a #ClutterMedia * * Retrieves the font name currently used. * * Return value: a string containing the font name. Use free() * to free the returned string * * Since: 1.2 * * Deprecated: 1.12 */ gchar * clutter_media_get_subtitle_font_name (ClutterMedia *media) { gchar *retval = NULL; g_return_val_if_fail (CLUTTER_IS_MEDIA(media), NULL); g_object_get (G_OBJECT (media), "subtitle-font-name", &retval, NULL); return retval; } /** * clutter_media_set_audio_volume: * @media: a #ClutterMedia * @volume: the volume as a double between 0.0 and 1.0 * * Sets the playback volume of @media to @volume. * * Since: 1.0 * * Deprecated: 1.12 */ void clutter_media_set_audio_volume (ClutterMedia *media, gdouble volume) { g_return_if_fail (CLUTTER_IS_MEDIA(media)); g_object_set (G_OBJECT (media), "audio-volume", volume, NULL); } /** * clutter_media_get_audio_volume: * @media: a #ClutterMedia * * Retrieves the playback volume of @media. * * Return value: The playback volume between 0.0 and 1.0 * * Since: 1.0 * * Deprecated: 1.12 */ gdouble clutter_media_get_audio_volume (ClutterMedia *media) { gdouble retval = 0.0; g_return_val_if_fail (CLUTTER_IS_MEDIA (media), 0.0); g_object_get (G_OBJECT (media), "audio-volume", &retval, NULL); return retval; } /** * clutter_media_get_can_seek: * @media: a #ClutterMedia * * Retrieves whether @media is seekable or not. * * Return value: %TRUE if @media can seek, %FALSE otherwise. * * Since: 0.2 * * Deprecated: 1.12 */ gboolean clutter_media_get_can_seek (ClutterMedia *media) { gboolean retval = FALSE; g_return_val_if_fail (CLUTTER_IS_MEDIA (media), FALSE); g_object_get (G_OBJECT (media), "can-seek", &retval, NULL); return retval; } /** * clutter_media_get_buffer_fill: * @media: a #ClutterMedia * * Retrieves the amount of the stream that is buffered. * * Return value: the fill level, between 0.0 and 1.0 * * Since: 1.0 * * Deprecated: 1.12 */ gdouble clutter_media_get_buffer_fill (ClutterMedia *media) { gdouble retval = 0.0; g_return_val_if_fail (CLUTTER_IS_MEDIA (media), 0); g_object_get (G_OBJECT (media), "buffer-fill", &retval, NULL); return retval; } /** * clutter_media_get_duration: * @media: a #ClutterMedia * * Retrieves the duration of the media stream that @media represents. * * Return value: the duration of the media stream, in seconds * * Since: 0.2 * * Deprecated: 1.12 */ gdouble clutter_media_get_duration (ClutterMedia *media) { gdouble retval = 0; g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0); g_object_get (G_OBJECT (media), "duration", &retval, NULL); return retval; } /* helper funcs */ /** * clutter_media_set_filename: * @media: a #ClutterMedia * @filename: A filename * * Sets the source of @media using a file path. * * Since: 0.2 * * Deprecated: 1.12 */ void clutter_media_set_filename (ClutterMedia *media, const gchar *filename) { gchar *uri; GError *uri_error = NULL; if (!g_path_is_absolute (filename)) { gchar *abs_path; abs_path = g_build_filename (g_get_current_dir (), filename, NULL); uri = g_filename_to_uri (abs_path, NULL, &uri_error); free (abs_path); } else uri = g_filename_to_uri (filename, NULL, &uri_error); if (uri_error) { g_signal_emit (media, media_signals[ERROR_SIGNAL], 0, uri_error); g_error_free (uri_error); return; } clutter_media_set_uri (media, uri); free (uri); } muffin-5.2.1/clutter/clutter/deprecated/clutter-animation.h0000664000175000017500000002655414211404421024224 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_ANIMATION_H__ #define __CLUTTER_ANIMATION_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_ANIMATION (clutter_animation_get_type ()) #define CLUTTER_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ANIMATION, ClutterAnimation)) #define CLUTTER_IS_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ANIMATION)) #define CLUTTER_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ANIMATION, ClutterAnimationClass)) #define CLUTTER_IS_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ANIMATION)) #define CLUTTER_ANIMATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ANIMATION, ClutterAnimationClass)) typedef struct _ClutterAnimationPrivate ClutterAnimationPrivate; typedef struct _ClutterAnimationClass ClutterAnimationClass; /** * ClutterAnimation: * * The #ClutterAnimation structure contains only private data and should * be accessed using the provided functions. * * Since: 1.0 * * Deprecated: 1.12: Use the implicit animation on #ClutterActor */ struct _ClutterAnimation { /*< private >*/ GObject parent_instance; ClutterAnimationPrivate *priv; }; /** * ClutterAnimationClass: * @started: class handler for the #ClutterAnimation::started signal * @completed: class handler for the #ClutterAnimation::completed signal * * The #ClutterAnimationClass structure contains only private data and * should be accessed using the provided functions. * * Since: 1.0 * * Deprecated: 1.12: Use the implicit animation on #ClutterActor */ struct _ClutterAnimationClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ void (* started) (ClutterAnimation *animation); void (* completed) (ClutterAnimation *animation); /*< private >*/ /* padding for future expansion */ void (*_clutter_reserved1) (void); void (*_clutter_reserved2) (void); void (*_clutter_reserved3) (void); void (*_clutter_reserved4) (void); void (*_clutter_reserved5) (void); void (*_clutter_reserved6) (void); void (*_clutter_reserved7) (void); void (*_clutter_reserved8) (void); }; CLUTTER_DEPRECATED_IN_1_12 GType clutter_animation_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_property_transition_new) ClutterAnimation * clutter_animation_new (void); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_transition_set_animatable) void clutter_animation_set_object (ClutterAnimation *animation, GObject *object); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_transition_get_animatable) GObject * clutter_animation_get_object (ClutterAnimation *animation); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_timeline_set_progress_mode) void clutter_animation_set_mode (ClutterAnimation *animation, gulong mode); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_timeline_get_progress_mode) gulong clutter_animation_get_mode (ClutterAnimation *animation); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_timeline_set_duration) void clutter_animation_set_duration (ClutterAnimation *animation, guint msecs); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_timeline_get_duration) guint clutter_animation_get_duration (ClutterAnimation *animation); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_timeline_set_repeat_count) void clutter_animation_set_loop (ClutterAnimation *animation, gboolean loop); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_timeline_get_repeat_count) gboolean clutter_animation_get_loop (ClutterAnimation *animation); CLUTTER_DEPRECATED_IN_1_12 void clutter_animation_set_timeline (ClutterAnimation *animation, ClutterTimeline *timeline); CLUTTER_DEPRECATED_IN_1_12 ClutterTimeline * clutter_animation_get_timeline (ClutterAnimation *animation); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_animation_set_timeline) void clutter_animation_set_alpha (ClutterAnimation *animation, ClutterAlpha *alpha); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_animation_get_timeline) ClutterAlpha * clutter_animation_get_alpha (ClutterAnimation *animation); CLUTTER_DEPRECATED_IN_1_12 ClutterAnimation * clutter_animation_bind (ClutterAnimation *animation, const gchar *property_name, const GValue *final); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_transition_set_interval) ClutterAnimation * clutter_animation_bind_interval (ClutterAnimation *animation, const gchar *property_name, ClutterInterval *interval); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_animation_has_property (ClutterAnimation *animation, const gchar *property_name); CLUTTER_DEPRECATED_IN_1_12 ClutterAnimation * clutter_animation_update (ClutterAnimation *animation, const gchar *property_name, const GValue *final); CLUTTER_DEPRECATED_IN_1_12 void clutter_animation_update_interval (ClutterAnimation *animation, const gchar *property_name, ClutterInterval *interval); CLUTTER_DEPRECATED_IN_1_12 void clutter_animation_unbind_property (ClutterAnimation *animation, const gchar *property_name); CLUTTER_DEPRECATED_IN_1_12 ClutterInterval * clutter_animation_get_interval (ClutterAnimation *animation, const gchar *property_name); CLUTTER_DEPRECATED_IN_1_12 void clutter_animation_completed (ClutterAnimation *animation); /* * ClutterActor API */ CLUTTER_DEPRECATED_IN_1_12 ClutterAnimation * clutter_actor_animate (ClutterActor *actor, gulong mode, guint duration, const gchar *first_property_name, ...) G_GNUC_NULL_TERMINATED; CLUTTER_DEPRECATED_IN_1_12 ClutterAnimation * clutter_actor_animate_with_timeline (ClutterActor *actor, gulong mode, ClutterTimeline *timeline, const gchar *first_property_name, ...) G_GNUC_NULL_TERMINATED; CLUTTER_DEPRECATED_IN_1_12 ClutterAnimation * clutter_actor_animatev (ClutterActor *actor, gulong mode, guint duration, gint n_properties, const gchar * const properties[], const GValue *values); CLUTTER_DEPRECATED_IN_1_12 ClutterAnimation * clutter_actor_animate_with_timelinev (ClutterActor *actor, gulong mode, ClutterTimeline *timeline, gint n_properties, const gchar * const properties[], const GValue *values); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_animate_with_timeline) ClutterAnimation * clutter_actor_animate_with_alpha (ClutterActor *actor, ClutterAlpha *alpha, const gchar *first_property_name, ...) G_GNUC_NULL_TERMINATED; CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_animate_with_timelinev) ClutterAnimation * clutter_actor_animate_with_alphav (ClutterActor *actor, ClutterAlpha *alpha, gint n_properties, const gchar * const properties[], const GValue *values); CLUTTER_DEPRECATED_IN_1_12 ClutterAnimation * clutter_actor_get_animation (ClutterActor *actor); CLUTTER_DEPRECATED_IN_1_12 void clutter_actor_detach_animation (ClutterActor *actor); G_END_DECLS #endif /* __CLUTTER_ANIMATION_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-scale.c0000664000175000017500000003115314211404421025300 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ /** * SECTION:clutter-behaviour-scale * @Title: ClutterBehaviourScale * @short_description: A behaviour controlling scale * @Deprecated: 1.6: Use clutter_actor_animate() with #ClutterActor:scale-x * and #ClutterActor:scale-y instead. * * A #ClutterBehaviourScale interpolates actors size between two values. * * Deprecated: 1.6: Use the #ClutterActor:scale-x and #ClutterActor:scale-y * properties, and clutter_actor_animate(), or #ClutterAnimator or * #ClutterState instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-actor.h" #include "clutter-alpha.h" #include "clutter-behaviour.h" #include "clutter-behaviour-scale.h" #include "clutter-debug.h" #include "clutter-main.h" #include "clutter-private.h" struct _ClutterBehaviourScalePrivate { gdouble x_scale_start; gdouble y_scale_start; gdouble x_scale_end; gdouble y_scale_end; }; enum { PROP_0, PROP_X_SCALE_START, PROP_Y_SCALE_START, PROP_X_SCALE_END, PROP_Y_SCALE_END, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE (ClutterBehaviourScale, clutter_behaviour_scale, CLUTTER_TYPE_BEHAVIOUR) typedef struct { gdouble scale_x; gdouble scale_y; } ScaleFrameClosure; static void scale_frame_foreach (ClutterBehaviour *behaviour, ClutterActor *actor, gpointer data) { ScaleFrameClosure *closure = data; clutter_actor_set_scale (actor, closure->scale_x, closure->scale_y); } static void clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave, gdouble alpha_value) { ClutterBehaviourScalePrivate *priv; ScaleFrameClosure closure = { 0, }; priv = CLUTTER_BEHAVIOUR_SCALE (behave)->priv; /* Fix the start/end values, avoids potential rounding errors on large * values. */ if (alpha_value == 1.0) { closure.scale_x = priv->x_scale_end; closure.scale_y = priv->y_scale_end; } else if (alpha_value == 0) { closure.scale_x = priv->x_scale_start; closure.scale_y = priv->y_scale_start; } else { closure.scale_x = (priv->x_scale_end - priv->x_scale_start) * alpha_value + priv->x_scale_start; closure.scale_y = (priv->y_scale_end - priv->y_scale_start) * alpha_value + priv->y_scale_start; } clutter_behaviour_actors_foreach (behave, scale_frame_foreach, &closure); } static void clutter_behaviour_scale_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBehaviourScalePrivate *priv; priv = CLUTTER_BEHAVIOUR_SCALE (gobject)->priv; switch (prop_id) { case PROP_X_SCALE_START: priv->x_scale_start = g_value_get_double (value); break; case PROP_X_SCALE_END: priv->x_scale_end = g_value_get_double (value); break; case PROP_Y_SCALE_START: priv->y_scale_start = g_value_get_double (value); break; case PROP_Y_SCALE_END: priv->y_scale_end = g_value_get_double (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_scale_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBehaviourScalePrivate *priv; priv = CLUTTER_BEHAVIOUR_SCALE (gobject)->priv; switch (prop_id) { case PROP_X_SCALE_START: g_value_set_double (value, priv->x_scale_start); break; case PROP_X_SCALE_END: g_value_set_double (value, priv->x_scale_end); break; case PROP_Y_SCALE_START: g_value_set_double (value, priv->y_scale_start); break; case PROP_Y_SCALE_END: g_value_set_double (value, priv->y_scale_end); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_scale_class_init (ClutterBehaviourScaleClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass); GParamSpec *pspec = NULL; gobject_class->set_property = clutter_behaviour_scale_set_property; gobject_class->get_property = clutter_behaviour_scale_get_property; /** * ClutterBehaviourScale:x-scale-start: * * The initial scaling factor on the X axis for the actors. * * Since: 0.6 * * Deprecated: 1.6 */ pspec = g_param_spec_double ("x-scale-start", P_("X Start Scale"), P_("Initial scale on the X axis"), 0.0, G_MAXDOUBLE, 1.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_X_SCALE_START] = pspec; g_object_class_install_property (gobject_class, PROP_X_SCALE_START, pspec); /** * ClutterBehaviourScale:x-scale-end: * * The final scaling factor on the X axis for the actors. * * Since: 0.6 * * Deprecated: 1.6 */ pspec = g_param_spec_double ("x-scale-end", P_("X End Scale"), P_("Final scale on the X axis"), 0.0, G_MAXDOUBLE, 1.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_X_SCALE_END] = pspec; g_object_class_install_property (gobject_class, PROP_X_SCALE_END, pspec); /** * ClutterBehaviourScale:y-scale-start: * * The initial scaling factor on the Y axis for the actors. * * Since: 0.6 * * Deprecated: 1.6 */ pspec = g_param_spec_double ("y-scale-start", P_("Y Start Scale"), P_("Initial scale on the Y axis"), 0.0, G_MAXDOUBLE, 1.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_Y_SCALE_START] = pspec; g_object_class_install_property (gobject_class, PROP_Y_SCALE_START, pspec); /** * ClutterBehaviourScale:y-scale-end: * * The final scaling factor on the Y axis for the actors. * * Since: 0.6 * * Deprecated: 1.6 */ pspec = g_param_spec_double ("y-scale-end", P_("Y End Scale"), P_("Final scale on the Y axis"), 0.0, G_MAXDOUBLE, 1.0, CLUTTER_PARAM_READWRITE); obj_props[PROP_Y_SCALE_END] = pspec; g_object_class_install_property (gobject_class, PROP_Y_SCALE_END, pspec); behave_class->alpha_notify = clutter_behaviour_scale_alpha_notify; } static void clutter_behaviour_scale_init (ClutterBehaviourScale *self) { ClutterBehaviourScalePrivate *priv; self->priv = priv = clutter_behaviour_scale_get_instance_private (self); priv->x_scale_start = priv->x_scale_end = 1.0; priv->y_scale_start = priv->y_scale_end = 1.0; } /** * clutter_behaviour_scale_new: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @x_scale_start: initial scale factor on the X axis * @y_scale_start: initial scale factor on the Y axis * @x_scale_end: final scale factor on the X axis * @y_scale_end: final scale factor on the Y axis * * Creates a new #ClutterBehaviourScale instance. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: (transfer full): the newly created #ClutterBehaviourScale * * Since: 0.2 * * Deprecated: 1.6 */ ClutterBehaviour * clutter_behaviour_scale_new (ClutterAlpha *alpha, gdouble x_scale_start, gdouble y_scale_start, gdouble x_scale_end, gdouble y_scale_end) { g_return_val_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha), NULL); return g_object_new (CLUTTER_TYPE_BEHAVIOUR_SCALE, "alpha", alpha, "x-scale-start", x_scale_start, "y-scale-start", y_scale_start, "x-scale-end", x_scale_end, "y-scale-end", y_scale_end, NULL); } /** * clutter_behaviour_scale_set_bounds: * @scale: a #ClutterBehaviourScale * @x_scale_start: initial scale factor on the X axis * @y_scale_start: initial scale factor on the Y axis * @x_scale_end: final scale factor on the X axis * @y_scale_end: final scale factor on the Y axis * * Sets the bounds used by scale behaviour. * * Since: 0.6 * * Deprecated: 1.6 */ void clutter_behaviour_scale_set_bounds (ClutterBehaviourScale *scale, gdouble x_scale_start, gdouble y_scale_start, gdouble x_scale_end, gdouble y_scale_end) { ClutterBehaviourScalePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_SCALE (scale)); priv = scale->priv; g_object_freeze_notify (G_OBJECT (scale)); if (priv->x_scale_start != x_scale_start) { priv->x_scale_start = x_scale_start; g_object_notify_by_pspec (G_OBJECT (scale), obj_props[PROP_X_SCALE_START]); } if (priv->y_scale_start != y_scale_start) { priv->y_scale_start = y_scale_start; g_object_notify_by_pspec (G_OBJECT (scale), obj_props[PROP_Y_SCALE_START]); } if (priv->x_scale_end != x_scale_end) { priv->x_scale_end = x_scale_end; g_object_notify_by_pspec (G_OBJECT (scale), obj_props[PROP_X_SCALE_END]); } if (priv->y_scale_end != y_scale_end) { priv->y_scale_end = y_scale_end; g_object_notify_by_pspec (G_OBJECT (scale), obj_props[PROP_Y_SCALE_END]); } g_object_thaw_notify (G_OBJECT (scale)); } /** * clutter_behaviour_scale_get_bounds: * @scale: a #ClutterBehaviourScale * @x_scale_start: (out): return location for the initial scale factor on the X * axis, or %NULL * @y_scale_start: (out): return location for the initial scale factor on the Y * axis, or %NULL * @x_scale_end: (out): return location for the final scale factor on the X axis, * or %NULL * @y_scale_end: (out): return location for the final scale factor on the Y axis, * or %NULL * * Retrieves the bounds used by scale behaviour. * * Since: 0.4 * * Deprecated: 1.6 */ void clutter_behaviour_scale_get_bounds (ClutterBehaviourScale *scale, gdouble *x_scale_start, gdouble *y_scale_start, gdouble *x_scale_end, gdouble *y_scale_end) { ClutterBehaviourScalePrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_SCALE (scale)); priv = scale->priv; if (x_scale_start) *x_scale_start = priv->x_scale_start; if (x_scale_end) *x_scale_end = priv->x_scale_end; if (y_scale_start) *y_scale_start = priv->y_scale_start; if (y_scale_end) *y_scale_end = priv->y_scale_end; } muffin-5.2.1/clutter/clutter/deprecated/clutter-backend.h0000664000175000017500000000514114211404421023621 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BACKEND_DEPRECATED_H__ #define __CLUTTER_BACKEND_DEPRECATED_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_4_FOR(ClutterSettings:font_dpi) void clutter_backend_set_resolution (ClutterBackend *backend, gdouble dpi); CLUTTER_DEPRECATED_IN_1_4_FOR(ClutterSettings:double_click_time) void clutter_backend_set_double_click_time (ClutterBackend *backend, guint msec); CLUTTER_DEPRECATED_IN_1_4_FOR(ClutterSettings:double_click_time) guint clutter_backend_get_double_click_time (ClutterBackend *backend); CLUTTER_DEPRECATED_IN_1_4_FOR(ClutterSettings:double_click_distance) void clutter_backend_set_double_click_distance (ClutterBackend *backend, guint distance); CLUTTER_DEPRECATED_IN_1_4_FOR(ClutterSettings:double_click_distance) guint clutter_backend_get_double_click_distance (ClutterBackend *backend); CLUTTER_DEPRECATED_IN_1_4_FOR(ClutterSettings:font_name) void clutter_backend_set_font_name (ClutterBackend *backend, const gchar *font_name); CLUTTER_DEPRECATED_IN_1_4_FOR(ClutterSettings:font_name) const gchar * clutter_backend_get_font_name (ClutterBackend *backend); G_END_DECLS #endif /* __CLUTTER_BACKEND_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-list-model.h0000664000175000017500000000636214211404421024311 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Neil Jagdish Patel * Emmanuele Bassi * * Copyright (C) 2006 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, see . * * NB: Inspiration for column storage taken from GtkListStore */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_LIST_MODEL_H__ #define __CLUTTER_LIST_MODEL_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_LIST_MODEL (clutter_list_model_get_type ()) #define CLUTTER_LIST_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LIST_MODEL, ClutterListModel)) #define CLUTTER_IS_LIST_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LIST_MODEL)) #define CLUTTER_LIST_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_LIST_MODEL, ClutterListModeClass)) #define CLUTTER_IS_LIST_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_LIST_MODEL)) #define CLUTTER_LIST_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_LIST_MODEL, ClutterListModeClass)) typedef struct _ClutterListModel ClutterListModel; typedef struct _ClutterListModelPrivate ClutterListModelPrivate; typedef struct _ClutterListModelClass ClutterListModelClass; /** * ClutterListModel: * * The #ClutterListModel struct contains only private data. * * Since: 0.6 * * Deprecated: 1.24: Use #GListStore instead */ struct _ClutterListModel { /*< private >*/ ClutterModel parent_instance; ClutterListModelPrivate *priv; }; /** * ClutterListModelClass: * * The #ClutterListModelClass struct contains only private data. * * Since: 0.6 * * Deprecated: 1.24: Use #GListStore instead */ struct _ClutterListModelClass { /*< private >*/ ClutterModelClass parent_class; }; CLUTTER_DEPRECATED_IN_1_24_FOR(g_list_store_get_type) GType clutter_list_model_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_24_FOR(g_list_store_new) ClutterModel *clutter_list_model_new (guint n_columns, ...); CLUTTER_DEPRECATED_IN_1_24_FOR(g_list_store_new) ClutterModel *clutter_list_model_newv (guint n_columns, GType *types, const gchar * const names[]); G_END_DECLS #endif /* __CLUTTER_LIST_MODEL_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-rectangle.c0000664000175000017500000004245414211404421024201 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * */ /** * SECTION:clutter-rectangle * @short_description: An actor that displays a simple rectangle. * * #ClutterRectangle is a #ClutterActor which draws a simple filled rectangle. * * #ClutterRectangle is deprecated since Clutter 1.10. If you want an actor * painting a solid color, you can replace it with #ClutterActor and set the * #ClutterActor:background-color property to the desired #ClutterColor. If * you are drawing more complex shapes, use #ClutterCanvas to draw using the * Cairo 2D API instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-rectangle.h" #include "deprecated/clutter-actor.h" #include "clutter-actor-private.h" #include "clutter-color.h" #include "clutter-debug.h" #include "clutter-main.h" #include "clutter-private.h" #include "cogl/cogl.h" struct _ClutterRectanglePrivate { ClutterColor color; ClutterColor border_color; guint border_width; guint has_border : 1; }; enum { PROP_0, PROP_COLOR, PROP_BORDER_COLOR, PROP_BORDER_WIDTH, PROP_HAS_BORDER /* FIXME: Add gradient, rounded corner props etc */ }; static const ClutterColor default_color = { 255, 255, 255, 255 }; static const ClutterColor default_border_color = { 0, 0, 0, 255 }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterRectangle, clutter_rectangle, CLUTTER_TYPE_ACTOR) static void clutter_rectangle_paint (ClutterActor *self) { ClutterRectanglePrivate *priv = CLUTTER_RECTANGLE (self)->priv; ClutterGeometry geom; guint8 tmp_alpha; CLUTTER_NOTE (PAINT, "painting rect '%s'", clutter_actor_get_name (self) ? clutter_actor_get_name (self) : "unknown"); clutter_actor_get_allocation_geometry (self, &geom); if (priv->has_border) { /* We paint the border and the content only if the rectangle * is big enough to show them */ if ((priv->border_width * 2) < geom.width && (priv->border_width * 2) < geom.height) { /* compute the composited opacity of the actor taking into * account the opacity of the color set by the user */ tmp_alpha = clutter_actor_get_paint_opacity (self) * priv->border_color.alpha / 255; /* paint the border */ cogl_set_source_color4ub (priv->border_color.red, priv->border_color.green, priv->border_color.blue, tmp_alpha); /* this sucks, but it's the only way to make a border */ cogl_rectangle (priv->border_width, 0, geom.width, priv->border_width); cogl_rectangle (geom.width - priv->border_width, priv->border_width, geom.width, geom.height); cogl_rectangle (0, geom.height - priv->border_width, geom.width - priv->border_width, geom.height); cogl_rectangle (0, 0, priv->border_width, geom.height - priv->border_width); tmp_alpha = clutter_actor_get_paint_opacity (self) * priv->color.alpha / 255; /* now paint the rectangle */ cogl_set_source_color4ub (priv->color.red, priv->color.green, priv->color.blue, tmp_alpha); cogl_rectangle (priv->border_width, priv->border_width, geom.width - priv->border_width, geom.height - priv->border_width); } else { /* Otherwise, we draw a rectangle with the same color * as the border, since we can only fit that into the * allocation. */ tmp_alpha = clutter_actor_get_paint_opacity (self) * priv->border_color.alpha / 255; cogl_set_source_color4ub (priv->border_color.red, priv->border_color.green, priv->border_color.blue, tmp_alpha); cogl_rectangle (0, 0, geom.width, geom.height); } } else { /* compute the composited opacity of the actor taking into * account the opacity of the color set by the user */ tmp_alpha = clutter_actor_get_paint_opacity (self) * priv->color.alpha / 255; cogl_set_source_color4ub (priv->color.red, priv->color.green, priv->color.blue, tmp_alpha); cogl_rectangle (0, 0, geom.width, geom.height); } } static gboolean clutter_rectangle_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { return _clutter_actor_set_default_paint_volume (self, CLUTTER_TYPE_RECTANGLE, volume); } static gboolean clutter_rectangle_has_overlaps (ClutterActor *self) { /* Rectangles never need an offscreen redirect because there are never any overlapping primitives */ return FALSE; } static void clutter_rectangle_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterRectangle *rectangle = CLUTTER_RECTANGLE(object); switch (prop_id) { case PROP_COLOR: clutter_rectangle_set_color (rectangle, clutter_value_get_color (value)); break; case PROP_BORDER_COLOR: clutter_rectangle_set_border_color (rectangle, clutter_value_get_color (value)); break; case PROP_BORDER_WIDTH: clutter_rectangle_set_border_width (rectangle, g_value_get_uint (value)); break; case PROP_HAS_BORDER: rectangle->priv->has_border = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_rectangle_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterRectanglePrivate *priv = CLUTTER_RECTANGLE(object)->priv; switch (prop_id) { case PROP_COLOR: clutter_value_set_color (value, &priv->color); break; case PROP_BORDER_COLOR: clutter_value_set_color (value, &priv->border_color); break; case PROP_BORDER_WIDTH: g_value_set_uint (value, priv->border_width); break; case PROP_HAS_BORDER: g_value_set_boolean (value, priv->has_border); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_rectangle_finalize (GObject *object) { G_OBJECT_CLASS (clutter_rectangle_parent_class)->finalize (object); } static void clutter_rectangle_dispose (GObject *object) { G_OBJECT_CLASS (clutter_rectangle_parent_class)->dispose (object); } static void clutter_rectangle_class_init (ClutterRectangleClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GParamSpec *pspec; actor_class->paint = clutter_rectangle_paint; actor_class->get_paint_volume = clutter_rectangle_get_paint_volume; actor_class->has_overlaps = clutter_rectangle_has_overlaps; gobject_class->finalize = clutter_rectangle_finalize; gobject_class->dispose = clutter_rectangle_dispose; gobject_class->set_property = clutter_rectangle_set_property; gobject_class->get_property = clutter_rectangle_get_property; /** * ClutterRectangle:color: * * The color of the rectangle. */ pspec = clutter_param_spec_color ("color", P_("Color"), P_("The color of the rectangle"), &default_color, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_COLOR, pspec); /** * ClutterRectangle:border-color: * * The color of the border of the rectangle. * * Since: 0.2 */ pspec = clutter_param_spec_color ("border-color", P_("Border Color"), P_("The color of the border of the rectangle"), &default_border_color, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_BORDER_COLOR, pspec); /** * ClutterRectangle:border-width: * * The width of the border of the rectangle, in pixels. * * Since: 0.2 */ g_object_class_install_property (gobject_class, PROP_BORDER_WIDTH, g_param_spec_uint ("border-width", P_("Border Width"), P_("The width of the border of the rectangle"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE)); /** * ClutterRectangle:has-border: * * Whether the #ClutterRectangle should be displayed with a border. * * Since: 0.2 */ g_object_class_install_property (gobject_class, PROP_HAS_BORDER, g_param_spec_boolean ("has-border", P_("Has Border"), P_("Whether the rectangle should have a border"), FALSE, CLUTTER_PARAM_READWRITE)); } static void clutter_rectangle_init (ClutterRectangle *self) { ClutterRectanglePrivate *priv; self->priv = priv = clutter_rectangle_get_instance_private (self); priv->color = default_color; priv->border_color = default_border_color; priv->border_width = 0; priv->has_border = FALSE; } /** * clutter_rectangle_new: * * Creates a new #ClutterActor with a rectangular shape. * * Return value: a new #ClutterRectangle * * Deprecated: 1.10: Use clutter_actor_new() instead */ ClutterActor* clutter_rectangle_new (void) { return g_object_new (CLUTTER_TYPE_RECTANGLE, NULL); } /** * clutter_rectangle_new_with_color: * @color: a #ClutterColor * * Creates a new #ClutterActor with a rectangular shape * and of the given @color. * * Return value: a new #ClutterRectangle * * Deprecated: 1.10: Use clutter_actor_new() and * clutter_actor_set_background_color() instead */ ClutterActor * clutter_rectangle_new_with_color (const ClutterColor *color) { return g_object_new (CLUTTER_TYPE_RECTANGLE, "color", color, NULL); } /** * clutter_rectangle_get_color: * @rectangle: a #ClutterRectangle * @color: (out caller-allocates): return location for a #ClutterColor * * Retrieves the color of @rectangle. * * Deprecated: 1.10: Use #ClutterActor and clutter_actor_get_background_color() * instead */ void clutter_rectangle_get_color (ClutterRectangle *rectangle, ClutterColor *color) { ClutterRectanglePrivate *priv; g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle)); g_return_if_fail (color != NULL); priv = rectangle->priv; color->red = priv->color.red; color->green = priv->color.green; color->blue = priv->color.blue; color->alpha = priv->color.alpha; } /** * clutter_rectangle_set_color: * @rectangle: a #ClutterRectangle * @color: a #ClutterColor * * Sets the color of @rectangle. * * Deprecated: 1.10: Use #ClutterActor and clutter_actor_set_background_color() * instead */ void clutter_rectangle_set_color (ClutterRectangle *rectangle, const ClutterColor *color) { ClutterRectanglePrivate *priv; g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle)); g_return_if_fail (color != NULL); g_object_ref (rectangle); priv = rectangle->priv; priv->color.red = color->red; priv->color.green = color->green; priv->color.blue = color->blue; priv->color.alpha = color->alpha; #if 0 /* FIXME - appears to be causing border to always get drawn */ if (clutter_color_equal (&priv->color, &priv->border_color)) priv->has_border = FALSE; else priv->has_border = TRUE; #endif clutter_actor_queue_redraw (CLUTTER_ACTOR (rectangle)); g_object_notify (G_OBJECT (rectangle), "color"); g_object_notify (G_OBJECT (rectangle), "has-border"); g_object_unref (rectangle); } /** * clutter_rectangle_get_border_width: * @rectangle: a #ClutterRectangle * * Gets the width (in pixels) of the border used by @rectangle * * Return value: the border's width * * Since: 0.2 * * Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas content * to draw the border using Cairo */ guint clutter_rectangle_get_border_width (ClutterRectangle *rectangle) { g_return_val_if_fail (CLUTTER_IS_RECTANGLE (rectangle), 0); return rectangle->priv->border_width; } /** * clutter_rectangle_set_border_width: * @rectangle: a #ClutterRectangle * @width: the width of the border * * Sets the width (in pixel) of the border used by @rectangle. * A @width of 0 will unset the border. * * Since: 0.2 * * Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas content * to draw the border using Cairo */ void clutter_rectangle_set_border_width (ClutterRectangle *rectangle, guint width) { ClutterRectanglePrivate *priv; g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle)); priv = rectangle->priv; if (priv->border_width != width) { g_object_ref (rectangle); priv->border_width = width; if (priv->border_width != 0) priv->has_border = TRUE; else priv->has_border = FALSE; clutter_actor_queue_redraw (CLUTTER_ACTOR (rectangle)); g_object_notify (G_OBJECT (rectangle), "border-width"); g_object_notify (G_OBJECT (rectangle), "has-border"); g_object_unref (rectangle); } } /** * clutter_rectangle_get_border_color: * @rectangle: a #ClutterRectangle * @color: (out caller-allocates): return location for a #ClutterColor * * Gets the color of the border used by @rectangle and places * it into @color. * * Since: 0.2 * * Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas to draw * the border with Cairo */ void clutter_rectangle_get_border_color (ClutterRectangle *rectangle, ClutterColor *color) { ClutterRectanglePrivate *priv; g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle)); g_return_if_fail (color != NULL); priv = rectangle->priv; color->red = priv->border_color.red; color->green = priv->border_color.green; color->blue = priv->border_color.blue; color->alpha = priv->border_color.alpha; } /** * clutter_rectangle_set_border_color: * @rectangle: a #ClutterRectangle * @color: the color of the border * * Sets the color of the border used by @rectangle using @color * * Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas to draw * the border with Cairo */ void clutter_rectangle_set_border_color (ClutterRectangle *rectangle, const ClutterColor *color) { ClutterRectanglePrivate *priv; g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle)); g_return_if_fail (color != NULL); priv = rectangle->priv; if (priv->border_color.red != color->red || priv->border_color.green != color->green || priv->border_color.blue != color->blue || priv->border_color.alpha != color->alpha) { g_object_ref (rectangle); priv->border_color.red = color->red; priv->border_color.green = color->green; priv->border_color.blue = color->blue; priv->border_color.alpha = color->alpha; if (clutter_color_equal (&priv->color, &priv->border_color)) priv->has_border = FALSE; else priv->has_border = TRUE; clutter_actor_queue_redraw (CLUTTER_ACTOR (rectangle)); g_object_notify (G_OBJECT (rectangle), "border-color"); g_object_notify (G_OBJECT (rectangle), "has-border"); g_object_unref (rectangle); } } muffin-5.2.1/clutter/clutter/deprecated/clutter-score.c0000664000175000017500000006746714211404421023363 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * 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, see . * * */ /** * SECTION:clutter-score * @short_description: Controller for multiple timelines * * #ClutterScore is a base class for sequencing multiple timelines in order. * Using #ClutterScore it is possible to start multiple timelines at the * same time or launch multiple timelines when a particular timeline has * emitted the ClutterTimeline::completed signal. * * Each time a #ClutterTimeline is started and completed, a signal will be * emitted. * * For example, this code will start two #ClutterTimelines after * a third timeline terminates: * * |[ * ClutterTimeline *timeline_1, *timeline_2, *timeline_3; * ClutterScore *score; * * timeline_1 = clutter_timeline_new_for_duration (1000); * timeline_2 = clutter_timeline_new_for_duration (500); * timeline_3 = clutter_timeline_new_for_duration (500); * * score = clutter_score_new (); * * clutter_score_append (score, NULL, timeline_1); * clutter_score_append (score, timeline_1, timeline_2); * clutter_score_append (score, timeline_1, timeline_3); * * clutter_score_start (score); * ]| * * A #ClutterScore takes a reference on the timelines it manages, * so timelines can be safely unreferenced after being appended. * * New timelines can be appended to the #ClutterScore using * clutter_score_append() and removed using clutter_score_remove(). * * Timelines can also be appended to a specific marker on the * parent timeline, using clutter_score_append_at_marker(). * * The score can be cleared using clutter_score_remove_all(). * * The list of timelines can be retrieved using * clutter_score_list_timelines(). * * The score state is controlled using clutter_score_start(), * clutter_score_pause(), clutter_score_stop() and clutter_score_rewind(). * The state can be queried using clutter_score_is_playing(). * * #ClutterScore is available since Clutter 0.6 * * Deprecated: 1.8: Use #ClutterAnimator or #ClutterState to create * complex animations involving multiple timelines. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-score.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-debug.h" typedef struct _ClutterScoreEntry ClutterScoreEntry; struct _ClutterScoreEntry { /* the entry unique id */ gulong id; ClutterTimeline *timeline; ClutterTimeline *parent; /* the optional marker on the parent */ gchar *marker; /* signal handlers id */ gulong complete_id; gulong marker_id; ClutterScore *score; /* pointer back to the tree structure */ GNode *node; }; struct _ClutterScorePrivate { GNode *root; GHashTable *running_timelines; gulong last_id; guint is_paused : 1; guint loop : 1; }; enum { PROP_0, PROP_LOOP }; enum { TIMELINE_STARTED, TIMELINE_COMPLETED, STARTED, PAUSED, COMPLETED, LAST_SIGNAL }; static inline void clutter_score_clear (ClutterScore *score); G_DEFINE_TYPE_WITH_PRIVATE (ClutterScore, clutter_score, G_TYPE_OBJECT) static int score_signals[LAST_SIGNAL] = { 0 }; /* Object */ static void clutter_score_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterScorePrivate *priv; priv = clutter_score_get_instance_private (CLUTTER_SCORE (gobject)); switch (prop_id) { case PROP_LOOP: priv->loop = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_score_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterScorePrivate *priv; priv = clutter_score_get_instance_private (CLUTTER_SCORE (gobject)); switch (prop_id) { case PROP_LOOP: g_value_set_boolean (value, priv->loop); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_score_finalize (GObject *object) { ClutterScore *score = CLUTTER_SCORE (object); clutter_score_stop (score); clutter_score_clear (score); G_OBJECT_CLASS (clutter_score_parent_class)->finalize (object); } static void clutter_score_class_init (ClutterScoreClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_score_set_property; gobject_class->get_property = clutter_score_get_property; gobject_class->finalize = clutter_score_finalize; /** * ClutterScore:loop: * * Whether the #ClutterScore should restart once finished. * * Since: 0.6 * Deprecated: 1.8 */ g_object_class_install_property (gobject_class, PROP_LOOP, g_param_spec_boolean ("loop", "Loop", "Whether the score should restart once finished", FALSE, CLUTTER_PARAM_READWRITE)); /** * ClutterScore::timeline-started: * @score: the score which received the signal * @timeline: the current timeline * * The ::timeline-started signal is emitted each time a new timeline * inside a #ClutterScore starts playing. * * Since: 0.6 * Deprecated: 1.8 */ score_signals[TIMELINE_STARTED] = g_signal_new ("timeline-started", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterScoreClass, timeline_started), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_TIMELINE); /** * ClutterScore::timeline-completed: * @score: the score which received the signal * @timeline: the completed timeline * * The ::timeline-completed signal is emitted each time a timeline * inside a #ClutterScore terminates. * * Since: 0.6 * Deprecated: 1.8 */ score_signals[TIMELINE_COMPLETED] = g_signal_new ("timeline-completed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterScoreClass, timeline_completed), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_TIMELINE); /** * ClutterScore::completed: * @score: the score which received the signal * * The ::completed signal is emitted each time a #ClutterScore terminates. * * Since: 0.6 * Deprecated: 1.8 */ score_signals[COMPLETED] = g_signal_new ("completed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterScoreClass, completed), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterScore::started: * @score: the score which received the signal * * The ::started signal is emitted each time a #ClutterScore starts playing. * * Since: 0.6 * Deprecated: 1.8 */ score_signals[STARTED] = g_signal_new ("started", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterScoreClass, started), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterScore::paused: * @score: the score which received the signal * * The ::paused signal is emitted each time a #ClutterScore * is paused. * * Since: 0.6 * Deprecated: 1.8 */ score_signals[PAUSED] = g_signal_new ("paused", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterScoreClass, paused), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void clutter_score_init (ClutterScore *self) { ClutterScorePrivate *priv; self->priv = priv = clutter_score_get_instance_private (self); /* sentinel */ priv->root = g_node_new (NULL); priv->running_timelines = NULL; priv->is_paused = FALSE; priv->loop = FALSE; priv->last_id = 1; } /** * clutter_score_new: * * Creates a new #ClutterScore. A #ClutterScore is an object that can * hold multiple #ClutterTimelines in a sequential order. * * Return value: the newly created #ClutterScore. Use g_object_unref() * when done. * * Since: 0.6 * Deprecated: 1.8 */ ClutterScore * clutter_score_new (void) { return g_object_new (CLUTTER_TYPE_SCORE, NULL); } /** * clutter_score_set_loop: * @score: a #ClutterScore * @loop: %TRUE for enable looping * * Sets whether @score should loop. A looping #ClutterScore will start * from its initial state after the ::complete signal has been fired. * * Since: 0.6 * Deprecated: 1.8 */ void clutter_score_set_loop (ClutterScore *score, gboolean loop) { g_return_if_fail (CLUTTER_IS_SCORE (score)); if (score->priv->loop != loop) { score->priv->loop = loop; g_object_notify (G_OBJECT (score), "loop"); } } /** * clutter_score_get_loop: * @score: a #ClutterScore * * Gets whether @score is looping * * Return value: %TRUE if the score is looping * * Since: 0.6 * Deprecated: 1.8 */ gboolean clutter_score_get_loop (ClutterScore *score) { g_return_val_if_fail (CLUTTER_IS_SCORE (score), FALSE); return score->priv->loop; } /** * clutter_score_is_playing: * @score: A #ClutterScore * * Query state of a #ClutterScore instance. * * Return Value: %TRUE if score is currently playing * * Since: 0.6 * Deprecated: 1.8 */ gboolean clutter_score_is_playing (ClutterScore *score) { g_return_val_if_fail (CLUTTER_IS_SCORE (score), FALSE); if (score->priv->is_paused) return FALSE; return score->priv->running_timelines && g_hash_table_size (score->priv->running_timelines) != 0; } /* destroy_entry: * @node: a #GNode * * Frees the #ClutterScoreEntry attached to @node. */ static gboolean destroy_entry (GNode *node, G_GNUC_UNUSED gpointer data) { ClutterScoreEntry *entry = node->data; if (G_LIKELY (entry != NULL)) { if (entry->marker_id) { g_signal_handler_disconnect (entry->parent, entry->marker_id); entry->marker_id = 0; } if (entry->complete_id) { g_signal_handler_disconnect (entry->timeline, entry->complete_id); entry->complete_id = 0; } g_object_unref (entry->timeline); free (entry->marker); g_slice_free (ClutterScoreEntry, entry); node->data = NULL; } /* continue */ return FALSE; } typedef enum { FIND_BY_TIMELINE, FIND_BY_ID, REMOVE_BY_ID, LIST_TIMELINES } TraverseAction; typedef struct { TraverseAction action; ClutterScore *score; /* parameters */ union { ClutterTimeline *timeline; gulong id; ClutterScoreEntry *entry; } d; gpointer result; } TraverseClosure; /* multi-purpose traversal function for the N-ary tree used by the score */ static gboolean traverse_children (GNode *node, gpointer data) { TraverseClosure *closure = data; ClutterScoreEntry *entry = node->data; gboolean retval = FALSE; /* root */ if (!entry) return TRUE; switch (closure->action) { case FIND_BY_TIMELINE: if (closure->d.timeline == entry->timeline) { closure->result = node; retval = TRUE; } break; case FIND_BY_ID: if (closure->d.id == entry->id) { closure->result = node; retval = TRUE; } break; case REMOVE_BY_ID: if (closure->d.id == entry->id) { /* Destroy all the child entries of this node */ g_node_traverse (node, G_POST_ORDER, G_TRAVERSE_ALL, -1, destroy_entry, NULL); /* Keep track of this node so that it will be destroyed further up */ closure->result = node; retval = TRUE; } break; case LIST_TIMELINES: closure->result = g_slist_prepend (closure->result, entry->timeline); retval = FALSE; break; } return retval; } static GNode * find_entry_by_timeline (ClutterScore *score, ClutterTimeline *timeline) { ClutterScorePrivate *priv = score->priv; TraverseClosure closure; closure.action = FIND_BY_TIMELINE; closure.score = score; closure.d.timeline = timeline; closure.result = NULL; g_node_traverse (priv->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, traverse_children, &closure); if (closure.result) return closure.result; return NULL; } static GNode * find_entry_by_id (ClutterScore *score, gulong id_) { ClutterScorePrivate *priv = score->priv; TraverseClosure closure; closure.action = FIND_BY_ID; closure.score = score; closure.d.id = id_; closure.result = NULL; g_node_traverse (priv->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, traverse_children, &closure); if (closure.result) return closure.result; return NULL; } /* forward declaration */ static void start_entry (ClutterScoreEntry *entry); static void start_children_entries (GNode *node, gpointer data) { ClutterScoreEntry *entry = node->data; /* If data is NULL, start all entries that have no marker, otherwise only start entries that have the same marker */ if (data == NULL ? entry->marker == NULL : (entry->marker && !strcmp (data, entry->marker))) start_entry (entry); } static void on_timeline_marker (ClutterTimeline *timeline, const gchar *marker_name, gint frame_num, ClutterScoreEntry *entry) { GNode *parent; CLUTTER_NOTE (SCHEDULER, "timeline [%p] marker ('%s') reached", entry->timeline, entry->marker); parent = find_entry_by_timeline (entry->score, timeline); if (!parent) return; /* start every child */ if (parent->children) { g_node_children_foreach (parent, G_TRAVERSE_ALL, start_children_entries, (gpointer) marker_name); } } static void on_timeline_completed (ClutterTimeline *timeline, ClutterScoreEntry *entry) { ClutterScorePrivate *priv = entry->score->priv; g_hash_table_remove (priv->running_timelines, GUINT_TO_POINTER (entry->id)); g_signal_handler_disconnect (timeline, entry->complete_id); entry->complete_id = 0; CLUTTER_NOTE (SCHEDULER, "timeline [%p] ('%lu') completed", entry->timeline, entry->id); g_signal_emit (entry->score, score_signals[TIMELINE_COMPLETED], 0, entry->timeline); /* start every child */ if (entry->node->children) { g_node_children_foreach (entry->node, G_TRAVERSE_ALL, start_children_entries, NULL); } /* score has finished - fire 'completed' signal */ if (g_hash_table_size (priv->running_timelines) == 0) { CLUTTER_NOTE (SCHEDULER, "looks like we finished"); g_signal_emit (entry->score, score_signals[COMPLETED], 0); clutter_score_stop (entry->score); if (priv->loop) clutter_score_start (entry->score); } } static void start_entry (ClutterScoreEntry *entry) { ClutterScorePrivate *priv = entry->score->priv; /* timelines attached to a marker might already be playing when we * end up here from the ::completed handler, so we need to perform * this check to avoid restarting those timelines */ if (clutter_timeline_is_playing (entry->timeline)) return; entry->complete_id = g_signal_connect (entry->timeline, "completed", G_CALLBACK (on_timeline_completed), entry); CLUTTER_NOTE (SCHEDULER, "timeline [%p] ('%lu') started", entry->timeline, entry->id); if (G_UNLIKELY (priv->running_timelines == NULL)) priv->running_timelines = g_hash_table_new (NULL, NULL); g_hash_table_insert (priv->running_timelines, GUINT_TO_POINTER (entry->id), entry); clutter_timeline_start (entry->timeline); g_signal_emit (entry->score, score_signals[TIMELINE_STARTED], 0, entry->timeline); } enum { ACTION_START, ACTION_PAUSE, ACTION_STOP }; static void foreach_running_timeline (gpointer key, gpointer value, gpointer user_data) { ClutterScoreEntry *entry = value; gint action = GPOINTER_TO_INT (user_data); switch (action) { case ACTION_START: clutter_timeline_start (entry->timeline); break; case ACTION_PAUSE: clutter_timeline_pause (entry->timeline); break; case ACTION_STOP: if (entry->complete_id) { g_signal_handler_disconnect (entry->timeline, entry->complete_id); entry->complete_id = 0; } clutter_timeline_stop (entry->timeline); break; } } /** * clutter_score_start: * @score: A #ClutterScore * * Starts the score. * * Since: 0.6 * Deprecated: 1.8 */ void clutter_score_start (ClutterScore *score) { ClutterScorePrivate *priv; g_return_if_fail (CLUTTER_IS_SCORE (score)); priv = score->priv; if (priv->is_paused) { g_hash_table_foreach (priv->running_timelines, foreach_running_timeline, GINT_TO_POINTER (ACTION_START)); priv->is_paused = FALSE; } else { g_signal_emit (score, score_signals[STARTED], 0); g_node_children_foreach (priv->root, G_TRAVERSE_ALL, start_children_entries, NULL); } } /** * clutter_score_stop: * @score: A #ClutterScore * * Stops and rewinds a playing #ClutterScore instance. * * Since: 0.6 * Deprecated: 1.8 */ void clutter_score_stop (ClutterScore *score) { ClutterScorePrivate *priv; g_return_if_fail (CLUTTER_IS_SCORE (score)); priv = score->priv; if (priv->running_timelines) { g_hash_table_foreach (priv->running_timelines, foreach_running_timeline, GINT_TO_POINTER (ACTION_STOP)); g_hash_table_destroy (priv->running_timelines); priv->running_timelines = NULL; } } /** * clutter_score_pause: * @score: a #ClutterScore * * Pauses a playing score @score. * * Since: 0.6 * Deprecated: 1.8 */ void clutter_score_pause (ClutterScore *score) { ClutterScorePrivate *priv; g_return_if_fail (CLUTTER_IS_SCORE (score)); priv = score->priv; if (!clutter_score_is_playing (score)) return; g_hash_table_foreach (priv->running_timelines, foreach_running_timeline, GINT_TO_POINTER (ACTION_PAUSE)); priv->is_paused = TRUE; g_signal_emit (score, score_signals[PAUSED], 0); } /** * clutter_score_rewind: * @score: A #ClutterScore * * Rewinds a #ClutterScore to its initial state. * * Since: 0.6 * Deprecated: 1.8 */ void clutter_score_rewind (ClutterScore *score) { gboolean was_playing; g_return_if_fail (CLUTTER_IS_SCORE (score)); was_playing = clutter_score_is_playing (score); clutter_score_stop (score); if (was_playing) clutter_score_start (score); } static inline void clutter_score_clear (ClutterScore *score) { ClutterScorePrivate *priv = score->priv; g_node_traverse (priv->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, destroy_entry, NULL); g_node_destroy (priv->root); } /** * clutter_score_append: * @score: a #ClutterScore * @parent: (allow-none): a #ClutterTimeline in the score, or %NULL * @timeline: a #ClutterTimeline * * Appends a timeline to another one existing in the score; the newly * appended timeline will be started when @parent is complete. * * If @parent is %NULL, the new #ClutterTimeline will be started when * clutter_score_start() is called. * * #ClutterScore will take a reference on @timeline. * * Return value: the id of the #ClutterTimeline inside the score, or * 0 on failure. The returned id can be used with clutter_score_remove() * or clutter_score_get_timeline(). * * Since: 0.6 * Deprecated: 1.8 */ gulong clutter_score_append (ClutterScore *score, ClutterTimeline *parent, ClutterTimeline *timeline) { ClutterScorePrivate *priv; ClutterScoreEntry *entry; g_return_val_if_fail (CLUTTER_IS_SCORE (score), 0); g_return_val_if_fail (parent == NULL || CLUTTER_IS_TIMELINE (parent), 0); g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); priv = score->priv; if (!parent) { entry = g_slice_new (ClutterScoreEntry); entry->timeline = g_object_ref (timeline); entry->parent = NULL; entry->id = priv->last_id; entry->marker = NULL; entry->marker_id = 0; entry->complete_id = 0; entry->score = score; entry->node = g_node_append_data (priv->root, entry); } else { GNode *node; node = find_entry_by_timeline (score, parent); if (G_UNLIKELY (!node)) { g_warning ("Unable to find the parent timeline inside the score."); return 0; } entry = g_slice_new (ClutterScoreEntry); entry->timeline = g_object_ref (timeline); entry->parent = parent; entry->id = priv->last_id; entry->marker = NULL; entry->marker_id = 0; entry->complete_id = 0; entry->score = score; entry->node = g_node_append_data (node, entry); } priv->last_id += 1; return entry->id; } /** * clutter_score_append_at_marker: * @score: a #ClutterScore * @parent: the parent #ClutterTimeline * @marker_name: the name of the marker to use * @timeline: the #ClutterTimeline to append * * Appends @timeline at the given @marker_name on the @parent * #ClutterTimeline. * * If you want to append @timeline at the end of @parent, use * clutter_score_append(). * * The #ClutterScore will take a reference on @timeline. * * Return value: the id of the #ClutterTimeline inside the score, or * 0 on failure. The returned id can be used with clutter_score_remove() * or clutter_score_get_timeline(). * * Since: 0.8 * Deprecated: 1.8 */ gulong clutter_score_append_at_marker (ClutterScore *score, ClutterTimeline *parent, const gchar *marker_name, ClutterTimeline *timeline) { ClutterScorePrivate *priv; GNode *node; ClutterScoreEntry *entry; gchar *marker_reached_signal; g_return_val_if_fail (CLUTTER_IS_SCORE (score), 0); g_return_val_if_fail (CLUTTER_IS_TIMELINE (parent), 0); g_return_val_if_fail (marker_name != NULL, 0); g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0); if (!clutter_timeline_has_marker (parent, marker_name)) { g_warning ("The parent timeline has no marker '%s'", marker_name); return 0; } priv = score->priv; node = find_entry_by_timeline (score, parent); if (G_UNLIKELY (!node)) { g_warning ("Unable to find the parent timeline inside the score."); return 0; } entry = g_slice_new (ClutterScoreEntry); entry->timeline = g_object_ref (timeline); entry->parent = parent; entry->marker = g_strdup (marker_name); entry->id = priv->last_id; entry->score = score; entry->complete_id = 0; marker_reached_signal = g_strdup_printf ("marker-reached::%s", marker_name); entry->marker_id = g_signal_connect (entry->parent, marker_reached_signal, G_CALLBACK (on_timeline_marker), entry); entry->node = g_node_append_data (node, entry); free (marker_reached_signal); priv->last_id += 1; return entry->id; } /** * clutter_score_remove: * @score: a #ClutterScore * @id_: the id of the timeline to remove * * Removes the #ClutterTimeline with the given id inside @score. If * the timeline has other timelines attached to it, those are removed * as well. * * Since: 0.6 * Deprecated: 1.8 */ void clutter_score_remove (ClutterScore *score, gulong id_) { ClutterScorePrivate *priv; TraverseClosure closure; g_return_if_fail (CLUTTER_IS_SCORE (score)); g_return_if_fail (id_ > 0); priv = score->priv; closure.action = REMOVE_BY_ID; closure.score = score; closure.d.id = id_; closure.result = NULL; g_node_traverse (priv->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, traverse_children, &closure); if (closure.result) g_node_destroy (closure.result); } /** * clutter_score_remove_all: * @score: a #ClutterScore * * Removes all the timelines inside @score. * * Since: 0.6 * Deprecated: 1.8 */ void clutter_score_remove_all (ClutterScore *score) { ClutterScorePrivate *priv; g_return_if_fail (CLUTTER_IS_SCORE (score)); priv = score->priv; /* this will take care of the running timelines */ clutter_score_stop (score); /* destroy all the contents of the tree */ clutter_score_clear (score); /* recreate the sentinel */ priv->root = g_node_new (NULL); } /** * clutter_score_get_timeline: * @score: a #ClutterScore * @id_: the id of the timeline * * Retrieves the #ClutterTimeline for @id_ inside @score. * * Return value: (transfer none): the requested timeline, or %NULL. This * function does not increase the reference count on the returned * #ClutterTimeline * * Since: 0.6 * Deprecated: 1.8 */ ClutterTimeline * clutter_score_get_timeline (ClutterScore *score, gulong id_) { GNode *node; ClutterScoreEntry *entry; g_return_val_if_fail (CLUTTER_IS_SCORE (score), NULL); g_return_val_if_fail (id_ > 0, NULL); node = find_entry_by_id (score, id_); if (G_UNLIKELY (!node)) return NULL; entry = node->data; return entry->timeline; } /** * clutter_score_list_timelines: * @score: a #ClutterScore * * Retrieves a list of all the #ClutterTimelines managed by @score. * * Return value: (transfer container) (element-type Clutter.Timeline): a * #GSList containing all the timelines in the score. This function does * not increase the reference count of the returned timelines. Use * g_slist_free() on the returned list to deallocate its resources. * * Since: 0.6 * Deprecated: 1.8 */ GSList * clutter_score_list_timelines (ClutterScore *score) { ClutterScorePrivate *priv; TraverseClosure closure; GSList *retval; g_return_val_if_fail (CLUTTER_IS_SCORE (score), NULL); priv = score->priv; closure.action = LIST_TIMELINES; closure.result = NULL; g_node_traverse (priv->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, traverse_children, &closure); retval = closure.result; return retval; } muffin-5.2.1/clutter/clutter/deprecated/clutter-layout-manager-deprecated.c0000664000175000017500000000457414211404421027261 0ustar jpeisachjpeisach#ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-layout-manager.h" /** * clutter_layout_manager_begin_animation: * @manager: a #ClutterLayoutManager * @duration: the duration of the animation, in milliseconds * @mode: the easing mode of the animation * * Begins an animation of @duration milliseconds, using the provided * easing @mode * * The easing mode can be specified either as a #ClutterAnimationMode * or as a logical id returned by clutter_alpha_register_func() * * The result of this function depends on the @manager implementation * * Return value: (transfer none): The #ClutterAlpha created by the * layout manager; the returned instance is owned by the layout * manager and should not be unreferenced * * Since: 1.2 * * Deprecated: 1.12 */ ClutterAlpha * clutter_layout_manager_begin_animation (ClutterLayoutManager *manager, guint duration, gulong mode) { ClutterLayoutManagerClass *klass; g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), NULL); klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); return klass->begin_animation (manager, duration, mode); } /** * clutter_layout_manager_end_animation: * @manager: a #ClutterLayoutManager * * Ends an animation started by clutter_layout_manager_begin_animation() * * The result of this call depends on the @manager implementation * * Since: 1.2 * * Deprecated: 1.12 */ void clutter_layout_manager_end_animation (ClutterLayoutManager *manager) { g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager)); CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager)->end_animation (manager); } /** * clutter_layout_manager_get_animation_progress: * @manager: a #ClutterLayoutManager * * Retrieves the progress of the animation, if one has been started by * clutter_layout_manager_begin_animation() * * The returned value has the same semantics of the #ClutterAlpha:alpha * value * * Return value: the progress of the animation * * Since: 1.2 * * Deprecated: 1.12 */ gdouble clutter_layout_manager_get_animation_progress (ClutterLayoutManager *manager) { ClutterLayoutManagerClass *klass; g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), 1.0); klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); return klass->get_animation_progress (manager); } muffin-5.2.1/clutter/clutter/deprecated/clutter-shader.h0000664000175000017500000001627714211404421023514 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Øyvind Kolås * * 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_SHADER_H__ #define __CLUTTER_SHADER_H__ #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_SHADER (clutter_shader_get_type ()) #define CLUTTER_SHADER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLUTTER_TYPE_SHADER, ClutterShader)) #define CLUTTER_SHADER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CLUTTER_TYPE_SHADER, ClutterShaderClass)) #define CLUTTER_IS_SHADER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLUTTER_TYPE_SHADER)) #define CLUTTER_IS_SHADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_SHADER)) #define CLUTTER_SHADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_SHADER, ClutterShaderClass)) /** * CLUTTER_SHADER_ERROR: * * Error domain for #ClutterShader errors * * Since: 0.6 * * Deprecated: 1.8 */ #define CLUTTER_SHADER_ERROR (clutter_shader_error_quark ()) /** * ClutterShaderError: * @CLUTTER_SHADER_ERROR_NO_ASM: No ASM shaders support * @CLUTTER_SHADER_ERROR_NO_GLSL: No GLSL shaders support * @CLUTTER_SHADER_ERROR_COMPILE: Compilation error * * #ClutterShader error enumeration * * Since: 0.6 * * Deprecated: 1.8 */ typedef enum { CLUTTER_SHADER_ERROR_NO_ASM, CLUTTER_SHADER_ERROR_NO_GLSL, CLUTTER_SHADER_ERROR_COMPILE } ClutterShaderError; typedef struct _ClutterShaderPrivate ClutterShaderPrivate; typedef struct _ClutterShaderClass ClutterShaderClass; /** * ClutterShader: * * The #ClutterShader structure contains only private data * and should be accessed using the provided API * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead */ struct _ClutterShader { /*< private >*/ GObject parent; ClutterShaderPrivate *priv; }; /** * ClutterShaderClass: * * The #ClutterShaderClass structure contains only private data * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffectClass instead */ struct _ClutterShaderClass { /*< private >*/ GObjectClass parent_class; }; CLUTTER_DEPRECATED_IN_1_8 GQuark clutter_shader_error_quark (void); CLUTTER_DEPRECATED_IN_1_8 GType clutter_shader_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) ClutterShader * clutter_shader_new (void); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) void clutter_shader_set_is_enabled (ClutterShader *shader, gboolean enabled); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) gboolean clutter_shader_get_is_enabled (ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) gboolean clutter_shader_compile (ClutterShader *shader, GError **error); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) void clutter_shader_release (ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) gboolean clutter_shader_is_compiled (ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) void clutter_shader_set_vertex_source (ClutterShader *shader, const gchar *data, gssize length); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) void clutter_shader_set_fragment_source (ClutterShader *shader, const gchar *data, gssize length); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) const gchar * clutter_shader_get_vertex_source (ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) const gchar * clutter_shader_get_fragment_source (ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) void clutter_shader_set_uniform (ClutterShader *shader, const gchar *name, const GValue *value); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) CoglHandle clutter_shader_get_cogl_program (ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) CoglHandle clutter_shader_get_cogl_fragment_shader (ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterShaderEffect) CoglHandle clutter_shader_get_cogl_vertex_shader (ClutterShader *shader); /* ClutterActor methods */ CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_actor_add_effect) gboolean clutter_actor_set_shader (ClutterActor *self, ClutterShader *shader); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_actor_get_effect) ClutterShader * clutter_actor_get_shader (ClutterActor *self); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_shader_effect_set_uniform_value) void clutter_actor_set_shader_param (ClutterActor *self, const gchar *param, const GValue *value); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_shader_effect_set_uniform) void clutter_actor_set_shader_param_int (ClutterActor *self, const gchar *param, gint value); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_shader_effect_set_uniform) void clutter_actor_set_shader_param_float (ClutterActor *self, const gchar *param, gfloat value); G_END_DECLS #endif /* __CLUTTER_SHADER_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-input-device-deprecated.c0000664000175000017500000000165114211404421026721 0ustar jpeisachjpeisach#ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-device-manager-private.h" #include "deprecated/clutter-input-device.h" /** * clutter_input_device_get_device_coords: * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE * @x: (out): return location for the X coordinate * @y: (out): return location for the Y coordinate * * Retrieves the latest coordinates of the pointer of @device * * Since: 1.2 * * Deprecated: 1.12: Use clutter_input_device_get_coords() instead. */ void clutter_input_device_get_device_coords (ClutterInputDevice *device, gint *x, gint *y) { ClutterPoint point; clutter_input_device_get_coords (device, NULL, &point); if (x) *x = point.x; if (y) *y = point.y; } muffin-5.2.1/clutter/clutter/deprecated/clutter-model.h0000664000175000017500000004576714211404421023354 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Neil Jagdish Patel * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_MODEL_H__ #define __CLUTTER_MODEL_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_MODEL (clutter_model_get_type ()) #define CLUTTER_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MODEL, ClutterModel)) #define CLUTTER_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_MODEL, ClutterModelClass)) #define CLUTTER_IS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MODEL)) #define CLUTTER_IS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_MODEL)) #define CLUTTER_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MODEL, ClutterModelClass)) typedef struct _ClutterModel ClutterModel; typedef struct _ClutterModelClass ClutterModelClass; typedef struct _ClutterModelPrivate ClutterModelPrivate; typedef struct _ClutterModelIter ClutterModelIter; typedef struct _ClutterModelIterClass ClutterModelIterClass; typedef struct _ClutterModelIterPrivate ClutterModelIterPrivate; /** * ClutterModelFilterFunc: * @model: a #ClutterModel * @iter: the iterator for the row * @user_data: data passed to clutter_model_set_filter() * * Filters the content of a row in the model. * * Return value: If the row should be displayed, return %TRUE * * Since: 0.6 * * Deprecated: 1.24: Implement filters using a custom #GListModel instead */ typedef gboolean (*ClutterModelFilterFunc) (ClutterModel *model, ClutterModelIter *iter, gpointer user_data); /** * ClutterModelSortFunc: * @model: a #ClutterModel * @a: a #GValue representing the contents of the row * @b: a #GValue representing the contents of the second row * @user_data: data passed to clutter_model_set_sort() * * Compares the content of two rows in the model. * * Return value: a positive integer if @a is after @b, a negative integer if * @a is before @b, or 0 if the rows are the same * * Since: 0.6 * * Deprecated: 1.24: Implement sorting using a custom #GListModel instead */ typedef gint (*ClutterModelSortFunc) (ClutterModel *model, const GValue *a, const GValue *b, gpointer user_data); /** * ClutterModelForeachFunc: * @model: a #ClutterModel * @iter: the iterator for the row * @user_data: data passed to clutter_model_foreach() * * Iterates on the content of a row in the model * * Return value: %TRUE if the iteration should continue, %FALSE otherwise * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel */ typedef gboolean (*ClutterModelForeachFunc) (ClutterModel *model, ClutterModelIter *iter, gpointer user_data); /** * ClutterModel: * * Base class for list models. The #ClutterModel structure contains * only private data and should be manipulated using the provided * API. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ struct _ClutterModel { /*< private >*/ GObject parent_instance; ClutterModelPrivate *priv; }; /** * ClutterModelClass: * @row_added: signal class handler for ClutterModel::row-added * @row_removed: signal class handler for ClutterModel::row-removed * @row_changed: signal class handler for ClutterModel::row-changed * @sort_changed: signal class handler for ClutterModel::sort-changed * @filter_changed: signal class handler for ClutterModel::filter-changed * @get_column_name: virtual function for returning the name of a column * @get_column_type: virtual function for returning the type of a column * @get_iter_at_row: virtual function for returning an iterator for the * given row * @get_n_rows: virtual function for returning the number of rows * of the model * @get_n_columns: virtual function for retuning the number of columns * of the model * @resort: virtual function for sorting the model using the passed * sorting function * @insert_row: virtual function for inserting a row at the given index * and returning an iterator pointing to it; if the index is a negative * integer, the row should be appended to the model * @remove_row: virtual function for removing a row at the given index * * Class for #ClutterModel instances. * * Since: 0.6 * * Deprecated: 1.24: Use #GListModel instead */ struct _ClutterModelClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ /* vtable */ guint (* get_n_rows) (ClutterModel *model); guint (* get_n_columns) (ClutterModel *model); const gchar * (* get_column_name) (ClutterModel *model, guint column); GType (* get_column_type) (ClutterModel *model, guint column); ClutterModelIter *(* insert_row) (ClutterModel *model, gint index_); void (* remove_row) (ClutterModel *model, guint row); ClutterModelIter *(* get_iter_at_row) (ClutterModel *model, guint row); void (* resort) (ClutterModel *model, ClutterModelSortFunc func, gpointer data); /* signals */ void (* row_added) (ClutterModel *model, ClutterModelIter *iter); void (* row_removed) (ClutterModel *model, ClutterModelIter *iter); void (* row_changed) (ClutterModel *model, ClutterModelIter *iter); void (* sort_changed) (ClutterModel *model); void (* filter_changed) (ClutterModel *model); /*< private >*/ /* padding for future expansion */ void (*_clutter_model_1) (void); void (*_clutter_model_2) (void); void (*_clutter_model_3) (void); void (*_clutter_model_4) (void); void (*_clutter_model_5) (void); void (*_clutter_model_6) (void); void (*_clutter_model_7) (void); void (*_clutter_model_8) (void); }; CLUTTER_DEPRECATED_IN_1_24_FOR(g_list_model_get_type) GType clutter_model_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_set_types (ClutterModel *model, guint n_columns, GType *types); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_set_names (ClutterModel *model, guint n_columns, const gchar * const names[]); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_append (ClutterModel *model, ...); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_appendv (ClutterModel *model, guint n_columns, guint *columns, GValue *values); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_prepend (ClutterModel *model, ...); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_prependv (ClutterModel *model, guint n_columns, guint *columns, GValue *values); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_insert (ClutterModel *model, guint row, ...); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_insertv (ClutterModel *model, guint row, guint n_columns, guint *columns, GValue *values); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_insert_value (ClutterModel *model, guint row, guint column, const GValue *value); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_remove (ClutterModel *model, guint row); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) guint clutter_model_get_n_rows (ClutterModel *model); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) guint clutter_model_get_n_columns (ClutterModel *model); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) const gchar * clutter_model_get_column_name (ClutterModel *model, guint column); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) GType clutter_model_get_column_type (ClutterModel *model, guint column); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) ClutterModelIter * clutter_model_get_first_iter (ClutterModel *model); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) ClutterModelIter * clutter_model_get_last_iter (ClutterModel *model); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) ClutterModelIter * clutter_model_get_iter_at_row (ClutterModel *model, guint row); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_set_sorting_column (ClutterModel *model, gint column); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) gint clutter_model_get_sorting_column (ClutterModel *model); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_foreach (ClutterModel *model, ClutterModelForeachFunc func, gpointer user_data); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_set_sort (ClutterModel *model, gint column, ClutterModelSortFunc func, gpointer user_data, GDestroyNotify notify); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_set_filter (ClutterModel *model, ClutterModelFilterFunc func, gpointer user_data, GDestroyNotify notify); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) gboolean clutter_model_get_filter_set (ClutterModel *model); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) void clutter_model_resort (ClutterModel *model); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) gboolean clutter_model_filter_row (ClutterModel *model, guint row); CLUTTER_DEPRECATED_IN_1_24_FOR(GListModel) gboolean clutter_model_filter_iter (ClutterModel *model, ClutterModelIter *iter); /* * ClutterModelIter */ #define CLUTTER_TYPE_MODEL_ITER (clutter_model_iter_get_type ()) #define CLUTTER_MODEL_ITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MODEL_ITER, ClutterModelIter)) #define CLUTTER_MODEL_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_MODEL_ITER, ClutterModelIterClass)) #define CLUTTER_IS_MODEL_ITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MODEL_ITER)) #define CLUTTER_IS_MODEL_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_MODEL_ITER)) #define CLUTTER_MODEL_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MODEL_ITER, ClutterModelIterClass)) /** * ClutterModelIter: * * Base class for list models iters. The #ClutterModelIter structure * contains only private data and should be manipulated using the * provided API. * * Since: 0.6 * * Deprecated: 1.24: Use custom iterators for #GListModel */ struct _ClutterModelIter { /*< private >*/ GObject parent_instance; ClutterModelIterPrivate *priv; }; /** * ClutterModelIterClass: * @get_value: Virtual function for retrieving the value at the given * column of the row pointed by the iterator * @set_value: Virtual function for setting the value at the given * column of the row pointer by the iterator * @is_last: Virtual function for knowing whether the iterator points * at the last row in the model * @is_first: Virtual function for knowing whether the iterator points * at the first row in the model * @next: Virtual function for moving the iterator to the following * row in the model * @prev: Virtual function for moving the iterator toe the previous * row in the model * @get_model: Virtual function for getting the model to which the * iterator belongs to * @get_row: Virtual function for getting the row to which the iterator * points * @copy: Virtual function for copying a #ClutterModelIter. * * Class for #ClutterModelIter instances. * * Since: 0.6 * * Deprecated: 1.24: Use custom iterators for #GListModel */ struct _ClutterModelIterClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ /* vtable not signals */ void (* get_value) (ClutterModelIter *iter, guint column, GValue *value); void (* set_value) (ClutterModelIter *iter, guint column, const GValue *value); gboolean (* is_first) (ClutterModelIter *iter); gboolean (* is_last) (ClutterModelIter *iter); ClutterModelIter *(* next) (ClutterModelIter *iter); ClutterModelIter *(* prev) (ClutterModelIter *iter); ClutterModel * (* get_model) (ClutterModelIter *iter); guint (* get_row) (ClutterModelIter *iter); ClutterModelIter *(* copy) (ClutterModelIter *iter); /*< private >*/ /* padding for future expansion */ void (*_clutter_model_iter_1) (void); void (*_clutter_model_iter_2) (void); void (*_clutter_model_iter_3) (void); void (*_clutter_model_iter_4) (void); void (*_clutter_model_iter_5) (void); void (*_clutter_model_iter_6) (void); void (*_clutter_model_iter_7) (void); void (*_clutter_model_iter_8) (void); }; CLUTTER_DEPRECATED_IN_1_24 GType clutter_model_iter_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_24 void clutter_model_iter_get (ClutterModelIter *iter, ...); CLUTTER_DEPRECATED_IN_1_24 void clutter_model_iter_get_valist (ClutterModelIter *iter, va_list args); CLUTTER_DEPRECATED_IN_1_24 void clutter_model_iter_get_value (ClutterModelIter *iter, guint column, GValue *value); CLUTTER_DEPRECATED_IN_1_24 void clutter_model_iter_set (ClutterModelIter *iter, ...); CLUTTER_DEPRECATED_IN_1_24 void clutter_model_iter_set_valist (ClutterModelIter *iter, va_list args); CLUTTER_DEPRECATED_IN_1_24 void clutter_model_iter_set_value (ClutterModelIter *iter, guint column, const GValue *value); CLUTTER_DEPRECATED_IN_1_24 gboolean clutter_model_iter_is_first (ClutterModelIter *iter); CLUTTER_DEPRECATED_IN_1_24 gboolean clutter_model_iter_is_last (ClutterModelIter *iter); CLUTTER_DEPRECATED_IN_1_24 ClutterModelIter *clutter_model_iter_next (ClutterModelIter *iter); CLUTTER_DEPRECATED_IN_1_24 ClutterModelIter *clutter_model_iter_prev (ClutterModelIter *iter); CLUTTER_DEPRECATED_IN_1_24 ClutterModel * clutter_model_iter_get_model (ClutterModelIter *iter); CLUTTER_DEPRECATED_IN_1_24 guint clutter_model_iter_get_row (ClutterModelIter *iter); CLUTTER_DEPRECATED_IN_1_24 ClutterModelIter *clutter_model_iter_copy (ClutterModelIter *iter); G_END_DECLS #endif /* __CLUTTER_MODEL_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-list-model.c0000664000175000017500000005614114211404421024304 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Neil Jagdish Patel * Emmanuele Bassi * * Copyright (C) 2006 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, see . * * */ /** * SECTION:clutter-list-model * @short_description: List model implementation * * #ClutterListModel is a #ClutterModel implementation provided by * Clutter. #ClutterListModel uses a #GSequence for storing the * values for each row, so it's optimized for insertion and look up * in sorted lists. * * #ClutterListModel is available since Clutter 0.6 * * Deprecated: 1.24: Use a #GListStore instance containing a custom * object type with properties for each column instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-list-model.h" #include "clutter-model.h" #include "clutter-model-private.h" #include "clutter-private.h" #include "clutter-debug.h" #define CLUTTER_TYPE_LIST_MODEL_ITER \ (clutter_list_model_iter_get_type()) #define CLUTTER_LIST_MODEL_ITER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ CLUTTER_TYPE_LIST_MODEL_ITER, \ ClutterListModelIter)) #define CLUTTER_IS_LIST_MODEL_ITER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ CLUTTER_TYPE_LIST_MODEL_ITER)) #define CLUTTER_LIST_MODEL_ITER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ CLUTTER_TYPE_LIST_MODEL_ITER, \ ClutterListModelIterClass)) #define CLUTTER_IS_LIST_MODEL_ITER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ CLUTTER_TYPE_LIST_MODEL_ITER)) #define CLUTTER_LIST_MODEL_ITER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ CLUTTER_TYPE_LIST_MODEL_ITER, \ ClutterListModelIterClass)) typedef struct _ClutterListModelIter ClutterListModelIter; typedef struct _ClutterModelIterClass ClutterListModelIterClass; struct _ClutterListModelPrivate { GSequence *sequence; ClutterModelIter *temp_iter; }; struct _ClutterListModelIter { ClutterModelIter parent_instance; GSequenceIter *seq_iter; }; GType clutter_list_model_iter_get_type (void); /* * ClutterListModel */ G_DEFINE_TYPE (ClutterListModelIter, clutter_list_model_iter, CLUTTER_TYPE_MODEL_ITER) static void clutter_list_model_iter_get_value (ClutterModelIter *iter, guint column, GValue *value) { ClutterListModelIter *iter_default; GValue *values; GValue *iter_value; GValue real_value = G_VALUE_INIT; gboolean converted = FALSE; iter_default = CLUTTER_LIST_MODEL_ITER (iter); g_assert (iter_default->seq_iter != NULL); values = g_sequence_get (iter_default->seq_iter); iter_value = &values[column]; g_assert (iter_value != NULL); if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value))) { if (!g_value_type_compatible (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value)) && !g_value_type_compatible (G_VALUE_TYPE (iter_value), G_VALUE_TYPE (value))) { g_warning ("%s: Unable to convert from %s to %s", G_STRLOC, g_type_name (G_VALUE_TYPE (value)), g_type_name (G_VALUE_TYPE (iter_value))); return; } if (!g_value_transform (iter_value, &real_value)) { g_warning ("%s: Unable to make conversion from %s to %s", G_STRLOC, g_type_name (G_VALUE_TYPE (value)), g_type_name (G_VALUE_TYPE (iter_value))); g_value_unset (&real_value); } converted = TRUE; } if (converted) { g_value_copy (&real_value, value); g_value_unset (&real_value); } else g_value_copy (iter_value, value); } static void clutter_list_model_iter_set_value (ClutterModelIter *iter, guint column, const GValue *value) { ClutterListModelIter *iter_default; GValue *values; GValue *iter_value; GValue real_value = G_VALUE_INIT; gboolean converted = FALSE; iter_default = CLUTTER_LIST_MODEL_ITER (iter); g_assert (iter_default->seq_iter != NULL); values = g_sequence_get (iter_default->seq_iter); iter_value = &values[column]; g_assert (iter_value != NULL); if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value))) { if (!g_value_type_compatible (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value)) && !g_value_type_compatible (G_VALUE_TYPE (iter_value), G_VALUE_TYPE (value))) { g_warning ("%s: Unable to convert from %s to %s\n", G_STRLOC, g_type_name (G_VALUE_TYPE (value)), g_type_name (G_VALUE_TYPE (iter_value))); return; } if (!g_value_transform (value, &real_value)) { g_warning ("%s: Unable to make conversion from %s to %s\n", G_STRLOC, g_type_name (G_VALUE_TYPE (value)), g_type_name (G_VALUE_TYPE (iter_value))); g_value_unset (&real_value); } converted = TRUE; } if (converted) { g_value_copy (&real_value, iter_value); g_value_unset (&real_value); } else g_value_copy (value, iter_value); } static gboolean clutter_list_model_iter_is_first (ClutterModelIter *iter) { ClutterListModelIter *iter_default; ClutterModel *model; ClutterModelIter *temp_iter; GSequence *sequence; GSequenceIter *begin, *end; iter_default = CLUTTER_LIST_MODEL_ITER (iter); g_assert (iter_default->seq_iter != NULL); model = clutter_model_iter_get_model (iter); sequence = CLUTTER_LIST_MODEL (model)->priv->sequence; begin = g_sequence_get_begin_iter (sequence); end = iter_default->seq_iter; temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter; while (!g_sequence_iter_is_begin (begin)) { CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = begin; if (clutter_model_filter_iter (model, temp_iter)) { end = begin; break; } begin = g_sequence_iter_next (begin); } /* This is because the 'begin_iter' is always *before* the last valid * iter, otherwise we'd have endless loops */ end = g_sequence_iter_prev (end); return iter_default->seq_iter == end; } static gboolean clutter_list_model_iter_is_last (ClutterModelIter *iter) { ClutterListModelIter *iter_default; ClutterModelIter *temp_iter; ClutterModel *model; GSequence *sequence; GSequenceIter *begin, *end; iter_default = CLUTTER_LIST_MODEL_ITER (iter); g_assert (iter_default->seq_iter != NULL); if (g_sequence_iter_is_end (iter_default->seq_iter)) return TRUE; model = clutter_model_iter_get_model (iter); sequence = CLUTTER_LIST_MODEL (model)->priv->sequence; begin = g_sequence_get_end_iter (sequence); begin = g_sequence_iter_prev (begin); end = iter_default->seq_iter; temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter; while (!g_sequence_iter_is_begin (begin)) { CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = begin; if (clutter_model_filter_iter (model, temp_iter)) { end = begin; break; } begin = g_sequence_iter_prev (begin); } /* This is because the 'end_iter' is always *after* the last valid iter. * Otherwise we'd have endless loops */ end = g_sequence_iter_next (end); return iter_default->seq_iter == end; } static ClutterModelIter * clutter_list_model_iter_next (ClutterModelIter *iter) { ClutterListModelIter *iter_default; ClutterModelIter *temp_iter; ClutterModel *model = NULL; GSequenceIter *filter_next; guint row; iter_default = CLUTTER_LIST_MODEL_ITER (iter); g_assert (iter_default->seq_iter != NULL); model = clutter_model_iter_get_model (iter); row = clutter_model_iter_get_row (iter); filter_next = g_sequence_iter_next (iter_default->seq_iter); g_assert (filter_next != NULL); temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter; while (!g_sequence_iter_is_end (filter_next)) { CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = filter_next; if (clutter_model_filter_iter (model, temp_iter)) { row += 1; break; } filter_next = g_sequence_iter_next (filter_next); } if (g_sequence_iter_is_end (filter_next)) row += 1; /* update the iterator and return it */ _clutter_model_iter_set_row (CLUTTER_MODEL_ITER (iter_default), row); iter_default->seq_iter = filter_next; return CLUTTER_MODEL_ITER (iter_default); } static ClutterModelIter * clutter_list_model_iter_prev (ClutterModelIter *iter) { ClutterListModelIter *iter_default; ClutterModelIter *temp_iter; ClutterModel *model; GSequenceIter *filter_prev; guint row; iter_default = CLUTTER_LIST_MODEL_ITER (iter); g_assert (iter_default->seq_iter != NULL); model = clutter_model_iter_get_model (iter); row = clutter_model_iter_get_row (iter); filter_prev = g_sequence_iter_prev (iter_default->seq_iter); g_assert (filter_prev != NULL); temp_iter = CLUTTER_LIST_MODEL (model)->priv->temp_iter; while (!g_sequence_iter_is_begin (filter_prev)) { CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = filter_prev; if (clutter_model_filter_iter (model, temp_iter)) { row -= 1; break; } filter_prev = g_sequence_iter_prev (filter_prev); } if (g_sequence_iter_is_begin (filter_prev)) row -= 1; /* update the iterator and return it */ _clutter_model_iter_set_row (CLUTTER_MODEL_ITER (iter_default), row); iter_default->seq_iter = filter_prev; return CLUTTER_MODEL_ITER (iter_default); } static ClutterModelIter * clutter_list_model_iter_copy (ClutterModelIter *iter) { ClutterListModelIter *iter_default; ClutterListModelIter *iter_copy; ClutterModel *model; guint row; iter_default = CLUTTER_LIST_MODEL_ITER (iter); model = clutter_model_iter_get_model (iter); row = clutter_model_iter_get_row (iter) - 1; iter_copy = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER, "model", model, "row", row, NULL); /* this is safe, because the seq_iter pointer on the passed * iterator will be always be overwritten in ::next or ::prev */ iter_copy->seq_iter = iter_default->seq_iter; return CLUTTER_MODEL_ITER (iter_copy); } static void clutter_list_model_iter_class_init (ClutterListModelIterClass *klass) { ClutterModelIterClass *iter_class = CLUTTER_MODEL_ITER_CLASS (klass); iter_class->get_value = clutter_list_model_iter_get_value; iter_class->set_value = clutter_list_model_iter_set_value; iter_class->is_first = clutter_list_model_iter_is_first; iter_class->is_last = clutter_list_model_iter_is_last; iter_class->next = clutter_list_model_iter_next; iter_class->prev = clutter_list_model_iter_prev; iter_class->copy = clutter_list_model_iter_copy; } static void clutter_list_model_iter_init (ClutterListModelIter *iter) { iter->seq_iter = NULL; } /* * ClutterListModel */ G_DEFINE_TYPE_WITH_PRIVATE (ClutterListModel, clutter_list_model, CLUTTER_TYPE_MODEL) static ClutterModelIter * clutter_list_model_get_iter_at_row (ClutterModel *model, guint row) { ClutterListModel *model_default = CLUTTER_LIST_MODEL (model); GSequence *sequence = model_default->priv->sequence; GSequenceIter *filter_next; gint seq_length = g_sequence_get_length (sequence); ClutterListModelIter *retval; gint count = -1; if (row >= seq_length) return NULL; retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER, "model", model, "row", row, NULL); /* short-circuit in case we don't have a filter in place */ if (!clutter_model_get_filter_set (model)) { retval->seq_iter = g_sequence_get_iter_at_pos (sequence, row); return CLUTTER_MODEL_ITER (retval); } filter_next = g_sequence_get_begin_iter (sequence); g_assert (filter_next != NULL); while (!g_sequence_iter_is_end (filter_next)) { retval->seq_iter = filter_next; if (clutter_model_filter_iter (model, CLUTTER_MODEL_ITER (retval))) { /* We've found a row that is valid under the filter */ count++; if (count == row) break; } filter_next = g_sequence_iter_next (filter_next); } if (count != row) { g_object_unref (retval); return NULL; } return CLUTTER_MODEL_ITER (retval); } static ClutterModelIter * clutter_list_model_insert_row (ClutterModel *model, gint index_) { ClutterListModel *model_default = CLUTTER_LIST_MODEL (model); GSequence *sequence = model_default->priv->sequence; ClutterListModelIter *retval; guint n_columns, i, pos; GValue *values; GSequenceIter *seq_iter; n_columns = clutter_model_get_n_columns (model); values = g_new0 (GValue, n_columns); for (i = 0; i < n_columns; i++) g_value_init (&values[i], clutter_model_get_column_type (model, i)); if (index_ < 0) { seq_iter = g_sequence_append (sequence, values); pos = g_sequence_get_length (sequence) - 1; } else if (index_ == 0) { seq_iter = g_sequence_prepend (sequence, values); pos = 0; } else { seq_iter = g_sequence_get_iter_at_pos (sequence, index_); seq_iter = g_sequence_insert_before (seq_iter, values); pos = index_; } retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER, "model", model, "row", pos, NULL); retval->seq_iter = seq_iter; return CLUTTER_MODEL_ITER (retval); } static void clutter_list_model_remove_row (ClutterModel *model, guint row) { ClutterListModel *model_default = CLUTTER_LIST_MODEL (model); GSequence *sequence = model_default->priv->sequence; GSequenceIter *seq_iter; guint pos = 0; seq_iter = g_sequence_get_begin_iter (sequence); while (!g_sequence_iter_is_end (seq_iter)) { if (clutter_model_filter_row (model, pos)) { if (pos == row) { ClutterModelIter *iter; iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER, "model", model, "row", pos, NULL); CLUTTER_LIST_MODEL_ITER (iter)->seq_iter = seq_iter; /* the actual row is removed from the sequence inside * the ::row-removed signal class handler, so that every * handler connected to ::row-removed will still get * a valid iterator, and every signal connected to * ::row-removed with the AFTER flag will get an updated * model */ g_signal_emit_by_name (model, "row-removed", iter); g_object_unref (iter); break; } } pos += 1; seq_iter = g_sequence_iter_next (seq_iter); } } typedef struct { ClutterModel *model; guint column; ClutterModelSortFunc func; gpointer data; } SortClosure; static gint sort_model_default (gconstpointer a, gconstpointer b, gpointer data) { const GValue *row_a = a; const GValue *row_b = b; SortClosure *clos = data; return clos->func (clos->model, &row_a[clos->column], &row_b[clos->column], clos->data); } static void clutter_list_model_resort (ClutterModel *model, ClutterModelSortFunc func, gpointer data) { SortClosure sort_closure = { NULL, 0, NULL, NULL }; sort_closure.model = model; sort_closure.column = clutter_model_get_sorting_column (model); sort_closure.func = func; sort_closure.data = data; g_sequence_sort (CLUTTER_LIST_MODEL (model)->priv->sequence, sort_model_default, &sort_closure); } static guint clutter_list_model_get_n_rows (ClutterModel *model) { ClutterListModel *list_model = CLUTTER_LIST_MODEL (model); /* short-circuit in case we don't have a filter in place */ if (!clutter_model_get_filter_set (model)) return g_sequence_get_length (list_model->priv->sequence); return CLUTTER_MODEL_CLASS (clutter_list_model_parent_class)->get_n_rows (model); } static void clutter_list_model_row_removed (ClutterModel *model, ClutterModelIter *iter) { ClutterListModelIter *iter_default; guint i, n_columns; GValue *values; n_columns = clutter_model_get_n_columns (model); iter_default = CLUTTER_LIST_MODEL_ITER (iter); values = g_sequence_get (iter_default->seq_iter); for (i = 0; i < n_columns; i++) g_value_unset (&values[i]); free (values); g_sequence_remove (iter_default->seq_iter); iter_default->seq_iter = NULL; } static void clutter_list_model_finalize (GObject *gobject) { ClutterListModel *model = CLUTTER_LIST_MODEL (gobject); GSequence *sequence = model->priv->sequence; GSequenceIter *iter; guint n_columns, i; n_columns = clutter_model_get_n_columns (CLUTTER_MODEL (gobject)); iter = g_sequence_get_begin_iter (sequence); while (!g_sequence_iter_is_end (iter)) { GValue *values = g_sequence_get (iter); for (i = 0; i < n_columns; i++) g_value_unset (&values[i]); free (values); iter = g_sequence_iter_next (iter); } g_sequence_free (sequence); G_OBJECT_CLASS (clutter_list_model_parent_class)->finalize (gobject); } static void clutter_list_model_dispose (GObject *gobject) { ClutterListModel *model = CLUTTER_LIST_MODEL (gobject); if (model->priv->temp_iter) { g_object_unref (model->priv->temp_iter); model->priv->temp_iter = NULL; } G_OBJECT_CLASS (clutter_list_model_parent_class)->dispose (gobject); } static void clutter_list_model_class_init (ClutterListModelClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterModelClass *model_class = CLUTTER_MODEL_CLASS (klass); gobject_class->finalize = clutter_list_model_finalize; gobject_class->dispose = clutter_list_model_dispose; model_class->get_iter_at_row = clutter_list_model_get_iter_at_row; model_class->insert_row = clutter_list_model_insert_row; model_class->remove_row = clutter_list_model_remove_row; model_class->resort = clutter_list_model_resort; model_class->get_n_rows = clutter_list_model_get_n_rows; model_class->row_removed = clutter_list_model_row_removed; } static void clutter_list_model_init (ClutterListModel *model) { model->priv = clutter_list_model_get_instance_private (model); model->priv->sequence = g_sequence_new (NULL); model->priv->temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER, "model", model, NULL); } /** * clutter_list_model_new: * @n_columns: number of columns in the model * @...: @n_columns number of #GType and string pairs * * Creates a new default model with @n_columns columns with the types * and names passed in. * * For example: * * * model = clutter_list_model_new (3, * G_TYPE_INT, "Score", * G_TYPE_STRING, "Team", * GDK_TYPE_PIXBUF, "Logo"); * * * will create a new #ClutterModel with three columns of type int, * string and #GdkPixbuf respectively. * * Note that the name of the column can be set to %NULL, in which case * the canonical name of the type held by the column will be used as * the title. * * Return value: a new #ClutterListModel * * Since: 0.6 * * Deprecated: 1.24: Use #GListStore instead */ ClutterModel * clutter_list_model_new (guint n_columns, ...) { ClutterModel *model; va_list args; gint i; g_return_val_if_fail (n_columns > 0, NULL); model = g_object_new (CLUTTER_TYPE_LIST_MODEL, NULL); _clutter_model_set_n_columns (model, n_columns, TRUE, TRUE); va_start (args, n_columns); for (i = 0; i < n_columns; i++) { GType type = va_arg (args, GType); const gchar *name = va_arg (args, gchar*); if (!_clutter_model_check_type (type)) { g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type)); g_object_unref (model); model = NULL; goto out; } _clutter_model_set_column_type (model, i, type); _clutter_model_set_column_name (model, i, name); } out: va_end (args); return model; } /** * clutter_list_model_newv: * @n_columns: number of columns in the model * @types: (array length=n_columns): an array of #GType types for the columns, from first to last * @names: (array length=n_columns): an array of names for the columns, from first to last * * Non-vararg version of clutter_list_model_new(). This function is * useful for language bindings. * * Return value: (transfer full): a new default #ClutterModel * * Since: 0.6 * * Deprecated: 1.24: Use #GListStore instead */ ClutterModel * clutter_list_model_newv (guint n_columns, GType *types, const gchar * const names[]) { ClutterModel *model; gint i; g_return_val_if_fail (n_columns > 0, NULL); model = g_object_new (CLUTTER_TYPE_LIST_MODEL, NULL); _clutter_model_set_n_columns (model, n_columns, TRUE, TRUE); for (i = 0; i < n_columns; i++) { if (!_clutter_model_check_type (types[i])) { g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i])); g_object_unref (model); return NULL; } _clutter_model_set_column_type (model, i, types[i]); _clutter_model_set_column_name (model, i, names[i]); } return model; } muffin-5.2.1/clutter/clutter/deprecated/clutter-media.h0000664000175000017500000001053514211404421023314 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Matthew Allum * Emmanuele Bassi * * Copyright (C) 2006 OpenedHand * 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_MEDIA_H__ #define __CLUTTER_MEDIA_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_MEDIA (clutter_media_get_type ()) #define CLUTTER_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MEDIA, ClutterMedia)) #define CLUTTER_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MEDIA)) #define CLUTTER_MEDIA_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_MEDIA, ClutterMediaIface)) typedef struct _ClutterMedia ClutterMedia; /* dummy typedef */ typedef struct _ClutterMediaIface ClutterMediaIface; /** * ClutterMedia: * * #ClutterMedia is an opaque structure whose members cannot be directly * accessed * * Since: 0.2 */ /** * ClutterMediaIface: * @eos: handler for the #ClutterMedia::eos signal * @error: handler for the #ClutterMedia::error signal * * Interface vtable for #ClutterMedia implementations * * Since: 0.2 */ struct _ClutterMediaIface { /*< private >*/ GTypeInterface base_iface; /*< public >*/ /* signals */ void (* eos) (ClutterMedia *media); void (* error) (ClutterMedia *media, const GError *error); }; CLUTTER_DEPRECATED_IN_1_12 GType clutter_media_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12 void clutter_media_set_uri (ClutterMedia *media, const gchar *uri); CLUTTER_DEPRECATED_IN_1_12 gchar * clutter_media_get_uri (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 void clutter_media_set_filename (ClutterMedia *media, const gchar *filename); CLUTTER_DEPRECATED_IN_1_12 void clutter_media_set_playing (ClutterMedia *media, gboolean playing); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_media_get_playing (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 void clutter_media_set_progress (ClutterMedia *media, gdouble progress); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_media_get_progress (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 void clutter_media_set_subtitle_uri (ClutterMedia *media, const gchar *uri); CLUTTER_DEPRECATED_IN_1_12 gchar * clutter_media_get_subtitle_uri (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 void clutter_media_set_subtitle_font_name (ClutterMedia *media, const char *font_name); CLUTTER_DEPRECATED_IN_1_12 gchar * clutter_media_get_subtitle_font_name (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 void clutter_media_set_audio_volume (ClutterMedia *media, gdouble volume); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_media_get_audio_volume (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_media_get_can_seek (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_media_get_buffer_fill (ClutterMedia *media); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_media_get_duration (ClutterMedia *media); G_END_DECLS #endif /* __CLUTTER_MEDIA_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour.c0000664000175000017500000004357714211404421024230 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ /** * SECTION:clutter-behaviour * @Title: ClutterBehaviour * @short_description: Class for providing behaviours to actors * @Deprecated: 1.6: Use clutter_actor_animate(), #ClutterAnimator or * #ClutterState instead * * #ClutterBehaviour is the base class for implementing behaviours. A * behaviour is a controller object for #ClutterActors; you can * use a behaviour to control one or more properties of an actor (such * as its opacity, or its position). A #ClutterBehaviour is driven by * an "alpha function" stored inside a #ClutterAlpha object; an alpha * function is a function depending solely on time. The alpha function * computes a value which is then applied to the properties of the * actors driven by a behaviour. * * Clutter provides some pre-defined behaviours, like #ClutterBehaviourPath, * which controls the position of a set of actors making them "walk" along * a set of nodes; #ClutterBehaviourOpacity, which controls the opacity * of a set of actors; #ClutterBehaviourScale, which controls the width * and height of a set of actors. * * To visualize the effects of different alpha functions on a * #ClutterBehaviour implementation it is possible to take the * #ClutterBehaviourPath as an example: * * ![](path-alpha-func.png) * * The actors position between the path's end points directly correlates * to the #ClutterAlpha's current alpha value driving the behaviour. With * the #ClutterAlpha's function set to a linear ramp the actor * will follow the path at a constant velocity, but when changing to * a sine wave the actor initially accelerates before quickly * decelerating. * * In order to implement a new behaviour you should subclass #ClutterBehaviour * and override the "alpha_notify" virtual function; inside the overridden * function you should obtain the alpha value from the #ClutterAlpha * instance bound to the behaviour and apply it to the desiderd property * (or properties) of every actor controlled by the behaviour. * * #ClutterBehaviour is available since Clutter 0.2. * * #ClutterBehaviour and its sub-classes have been discouraged sing Clutter * 1.0, and formally deprecated since Clutter 1.6. You should use the * [implicit animation][clutter-actor-animation] support inside #ClutterActor * if you still have code using #ClutterBehaviour. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-behaviour.h" #include "clutter-alpha.h" #include "clutter-debug.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-scriptable.h" #include "clutter-script-private.h" struct _ClutterBehaviourPrivate { ClutterAlpha *alpha; guint notify_id; GSList *actors; }; enum { PROP_0, PROP_ALPHA, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { APPLIED, REMOVED, LAST_SIGNAL }; static guint behave_signals[LAST_SIGNAL] = { 0 }; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterBehaviour, clutter_behaviour, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterBehaviour) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)) static gboolean clutter_behaviour_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { if (strncmp (name, "alpha", 5) == 0) { GObject *alpha; alpha = _clutter_script_parse_alpha (script, node); if (alpha != NULL) { g_value_init (value, CLUTTER_TYPE_ALPHA); g_value_set_object (value, alpha); return TRUE; } } return FALSE; } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_behaviour_parse_custom_node; } static void clutter_behaviour_dispose (GObject *gobject) { ClutterBehaviour *self = CLUTTER_BEHAVIOUR (gobject); clutter_behaviour_set_alpha (self, NULL); clutter_behaviour_remove_all (self); G_OBJECT_CLASS (clutter_behaviour_parent_class)->dispose (gobject); } static void clutter_behaviour_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBehaviour *behaviour = CLUTTER_BEHAVIOUR (object); switch (prop_id) { case PROP_ALPHA: clutter_behaviour_set_alpha (behaviour, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_behaviour_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBehaviour *behaviour = CLUTTER_BEHAVIOUR (object); ClutterBehaviourPrivate *priv = behaviour->priv; switch (prop_id) { case PROP_ALPHA: g_value_set_object (value, priv->alpha); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_behaviour_alpha_notify_unimplemented (ClutterBehaviour *behaviour, gdouble alpha_value) { g_warning ("ClutterBehaviourClass::alpha_notify not implemented for '%s'", g_type_name (G_TYPE_FROM_INSTANCE (behaviour))); } static void clutter_behaviour_class_init (ClutterBehaviourClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = clutter_behaviour_dispose; object_class->set_property = clutter_behaviour_set_property; object_class->get_property = clutter_behaviour_get_property; /** * ClutterBehaviour:alpha: * * The #ClutterAlpha object used to drive this behaviour. A #ClutterAlpha * object binds a #ClutterTimeline and a function which computes a value * (the "alpha") depending on the time. Each time the alpha value changes * the alpha-notify virtual function is called. * * Since: 0.2 * * Deprecated: 1.6 */ obj_props[PROP_ALPHA] = g_param_spec_object ("alpha", P_("Alpha"), P_("Alpha Object to drive the behaviour"), CLUTTER_TYPE_ALPHA, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (object_class, PROP_LAST, obj_props); klass->alpha_notify = clutter_behaviour_alpha_notify_unimplemented; /** * ClutterBehaviour::applied: * @behaviour: the #ClutterBehaviour that received the signal * @actor: the actor the behaviour was applied to. * * The ::apply signal is emitted each time the behaviour is applied * to an actor. * * Since: 0.4 * * Deprecated: 1.6 */ behave_signals[APPLIED] = g_signal_new ("applied", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterBehaviourClass, applied), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterBehaviour::removed: * @behaviour: the #ClutterBehaviour that received the signal * @actor: the removed actor * * The ::removed signal is emitted each time a behaviour is not applied * to an actor anymore. * * Since: 0.4 * * Deprecated: 1.6 */ behave_signals[REMOVED] = g_signal_new ("removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterBehaviourClass, removed), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); } static void clutter_behaviour_init (ClutterBehaviour *self) { self->priv = clutter_behaviour_get_instance_private (self); } static void remove_actor_on_destroy (ClutterActor *actor, ClutterBehaviour *behaviour) { clutter_behaviour_remove (behaviour, actor); } /** * clutter_behaviour_apply: * @behave: a #ClutterBehaviour * @actor: a #ClutterActor * * Applies @behave to @actor. This function adds a reference on * the actor. * * Since: 0.2 * * Deprecated: 1.6 */ void clutter_behaviour_apply (ClutterBehaviour *behave, ClutterActor *actor) { ClutterBehaviourPrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = behave->priv; if (g_slist_find (priv->actors, actor)) { g_warning ("The behaviour of type %s already applies " "to the actor of type %s", g_type_name (G_OBJECT_TYPE (behave)), g_type_name (G_OBJECT_TYPE (actor))); return; } priv->actors = g_slist_append (priv->actors, g_object_ref (actor)); g_signal_connect (actor, "destroy", G_CALLBACK (remove_actor_on_destroy), behave); g_signal_emit (behave, behave_signals[APPLIED], 0, actor); } /** * clutter_behaviour_is_applied: * @behave: a #ClutterBehaviour * @actor: a #ClutterActor * * Check if @behave applied to @actor. * * Return value: TRUE if actor has behaviour. FALSE otherwise. * * Since: 0.4 * * Deprecated: 1.6 */ gboolean clutter_behaviour_is_applied (ClutterBehaviour *behave, ClutterActor *actor) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR (behave), FALSE); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); return (g_slist_find (behave->priv->actors, actor) != NULL); } /** * clutter_behaviour_remove: * @behave: a #ClutterBehaviour * @actor: a #ClutterActor * * Removes @actor from the list of #ClutterActors to which * @behave applies. This function removes a reference on the actor. * * Since: 0.2 * * Deprecated: 1.6 */ void clutter_behaviour_remove (ClutterBehaviour *behave, ClutterActor *actor) { ClutterBehaviourPrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = behave->priv; if (!g_slist_find (priv->actors, actor)) { g_warning ("The behaviour of type %s is not applied " "to the actor of type %s", g_type_name (G_OBJECT_TYPE (behave)), g_type_name (G_OBJECT_TYPE (actor))); return; } g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (remove_actor_on_destroy), behave); priv->actors = g_slist_remove (priv->actors, actor); g_signal_emit (behave, behave_signals[REMOVED], 0, actor); g_object_unref (actor); } /** * clutter_behaviour_get_n_actors: * @behave: a #ClutterBehaviour * * Gets the number of actors this behaviour is applied too. * * Return value: The number of applied actors * * Since: 0.2 * * Deprecated: 1.6 */ gint clutter_behaviour_get_n_actors (ClutterBehaviour *behave) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR (behave), 0); return g_slist_length (behave->priv->actors); } /** * clutter_behaviour_get_nth_actor: * @behave: a #ClutterBehaviour * @index_: the index of an actor this behaviour is applied too. * * Gets an actor the behaviour was applied to referenced by index num. * * Return value: (transfer none): A Clutter actor or NULL if @index_ is invalid. * * Since: 0.2 * * Deprecated: 1.6 */ ClutterActor * clutter_behaviour_get_nth_actor (ClutterBehaviour *behave, gint index_) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR (behave), NULL); return g_slist_nth_data (behave->priv->actors, index_); } /** * clutter_behaviour_actors_foreach: * @behave: a #ClutterBehaviour * @func: (scope call): a function called for each actor * @data: optional data to be passed to the function, or %NULL * * Calls @func for every actor driven by @behave. * * Since: 0.2 * * Deprecated: 1.6 */ void clutter_behaviour_actors_foreach (ClutterBehaviour *behave, ClutterBehaviourForeachFunc func, gpointer data) { GSList *l; g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); g_return_if_fail (func != NULL); for (l = behave->priv->actors; l != NULL; l = l->next) { ClutterActor *actor = l->data; g_assert (CLUTTER_IS_ACTOR (actor)); func (behave, actor, data); } } /** * clutter_behaviour_get_alpha: * @behave: a #ClutterBehaviour * * Retrieves the #ClutterAlpha object bound to @behave. * * Return value: (transfer none): a #ClutterAlpha object, or %NULL if no alpha * object has been bound to this behaviour. * * Since: 0.2 * * Deprecated: 1.6 */ ClutterAlpha * clutter_behaviour_get_alpha (ClutterBehaviour *behave) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR (behave), NULL); return behave->priv->alpha; } static void notify_cb (GObject *object, GParamSpec *param_spec, ClutterBehaviour *behave) { ClutterBehaviourClass *klass; klass = CLUTTER_BEHAVIOUR_GET_CLASS (behave); CLUTTER_NOTE (ANIMATION, "notify::alpha"); /* no actors, we can stop right here */ if (behave->priv->actors == NULL) return; if (klass->alpha_notify != NULL) { gdouble alpha_value = clutter_alpha_get_alpha (behave->priv->alpha); CLUTTER_NOTE (ANIMATION, "calling %s::alpha_notify (%p, %.4f)", g_type_name (G_TYPE_FROM_CLASS (klass)), behave, alpha_value); klass->alpha_notify (behave, alpha_value); } } /** * clutter_behaviour_set_alpha: * @behave: a #ClutterBehaviour * @alpha: a #ClutterAlpha or %NULL to unset a previously set alpha * * Binds @alpha to a #ClutterBehaviour. The #ClutterAlpha object * is what makes a behaviour work: for each tick of the timeline * used by #ClutterAlpha a new value of the alpha parameter is * computed by the alpha function; the value should be used by * the #ClutterBehaviour to update one or more properties of the * actors to which the behaviour applies. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. * * Since: 0.2 * * Deprecated: 1.6 */ void clutter_behaviour_set_alpha (ClutterBehaviour *behave, ClutterAlpha *alpha) { ClutterBehaviourPrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); g_return_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha)); priv = behave->priv; if (priv->alpha == alpha) return; if (priv->notify_id) { CLUTTER_NOTE (ANIMATION, "removing previous notify-id (%d)", priv->notify_id); g_signal_handler_disconnect (priv->alpha, priv->notify_id); priv->notify_id = 0; } if (priv->alpha != NULL) { CLUTTER_NOTE (ANIMATION, "removing previous alpha object"); g_object_unref (priv->alpha); priv->alpha = NULL; } if (alpha != NULL) { priv->alpha = g_object_ref_sink (alpha); priv->notify_id = g_signal_connect (priv->alpha, "notify::alpha", G_CALLBACK(notify_cb), behave); CLUTTER_NOTE (ANIMATION, "setting new alpha object (%p, notify:%d)", priv->alpha, priv->notify_id); } g_object_notify_by_pspec (G_OBJECT (behave), obj_props[PROP_ALPHA]); } /** * clutter_behaviour_get_actors: * @behave: a #ClutterBehaviour * * Retrieves all the actors to which @behave applies. It is not recommended * for derived classes to use this in there alpha notify method but use * #clutter_behaviour_actors_foreach as it avoids alot of needless allocations. * * Return value: (transfer container) (element-type Clutter.Actor): a list of * actors. You should free the returned list with g_slist_free() when * finished using it. * * Since: 0.2 * * Deprecated: 1.6 */ GSList * clutter_behaviour_get_actors (ClutterBehaviour *behave) { ClutterBehaviourPrivate *priv; GSList *retval, *l; g_return_val_if_fail (CLUTTER_BEHAVIOUR (behave), NULL); priv = behave->priv; retval = NULL; for (l = priv->actors; l != NULL; l = l->next) retval = g_slist_prepend (retval, l->data); return g_slist_reverse (retval); } /** * clutter_behaviour_remove_all: * @behave: a #ClutterBehaviour * * Removes every actor from the list that @behave holds. * * Since: 0.4 * * Deprecated: 1.6 */ void clutter_behaviour_remove_all (ClutterBehaviour *behave) { ClutterBehaviourPrivate *priv; GSList *l; g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); priv = behave->priv; for (l = priv->actors; l != NULL; l = l->next) { ClutterActor *actor = l->data; g_signal_emit (behave, behave_signals[REMOVED], 0, actor); g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (remove_actor_on_destroy), behave); g_object_unref (actor); } g_slist_free (priv->actors); priv->actors = NULL; } muffin-5.2.1/clutter/clutter/deprecated/clutter-model-private.h0000664000175000017500000000403114211404421024777 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Neil Jagdish Patel * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #ifndef __CLUTTER_MODEL_PRIVATE_H__ #define __CLUTTER_MODEL_PRIVATE_H__ #include "clutter-types.h" #include "clutter-model.h" G_BEGIN_DECLS void _clutter_model_set_n_columns (ClutterModel *model, gint n_columns, gboolean set_types, gboolean set_names); gboolean _clutter_model_check_type (GType gtype); void _clutter_model_set_column_type (ClutterModel *model, gint column, GType gtype); void _clutter_model_set_column_name (ClutterModel *model, gint column, const gchar *name); void _clutter_model_iter_set_row (ClutterModelIter *iter, guint row); G_END_DECLS #endif /* __CLUTTER_MODEL_PRIVATE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-cairo-texture.h0000664000175000017500000001363214211404421025031 0ustar jpeisachjpeisach/* * Clutter * * An OpenGL based 'interactive canvas' library. * * Authored By: Emmanuele Bassi * Matthew Allum * Chris Lord * Iain Holmes * Neil Roberts * * Copyright (C) 2008, 2009, 2010 Intel Corporation. * * 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_CAIRO_TEXTURE_H__ #define __CLUTTER_CAIRO_TEXTURE_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_CAIRO_TEXTURE (clutter_cairo_texture_get_type ()) #define CLUTTER_CAIRO_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CAIRO_TEXTURE, ClutterCairoTexture)) #define CLUTTER_CAIRO_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CAIRO_TEXTURE, ClutterCairoTextureClass)) #define CLUTTER_IS_CAIRO_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CAIRO_TEXTURE)) #define CLUTTER_IS_CAIRO_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CAIRO_TEXTURE)) #define CLUTTER_CAIRO_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CAIRO_TEXTURE, ClutterCairoTextureClass)) typedef struct _ClutterCairoTexture ClutterCairoTexture; typedef struct _ClutterCairoTextureClass ClutterCairoTextureClass; typedef struct _ClutterCairoTexturePrivate ClutterCairoTexturePrivate; /** * ClutterCairoTexture: * * The #ClutterCairoTexture struct contains only private data. * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterCanvas instead */ struct _ClutterCairoTexture { /*< private >*/ ClutterTexture parent_instance; ClutterCairoTexturePrivate *priv; }; /** * ClutterCairoTextureClass: * @create_surface: class handler for the #ClutterCairoTexture::create-surface * signal * @draw: class handler for the #ClutterCairoTexture::draw signal * * The #ClutterCairoTextureClass struct contains only private data. * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterCanvas instead */ struct _ClutterCairoTextureClass { /*< private >*/ ClutterTextureClass parent_class; /*< public >*/ cairo_surface_t *(* create_surface) (ClutterCairoTexture *texture, guint width, guint height); gboolean (* draw) (ClutterCairoTexture *texture, cairo_t *cr); /*< private >*/ void (*_clutter_cairo_3) (void); void (*_clutter_cairo_4) (void); }; CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_canvas_get_type) GType clutter_cairo_texture_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_canvas_new) ClutterActor * clutter_cairo_texture_new (guint width, guint height); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_canvas_set_size) void clutter_cairo_texture_set_surface_size (ClutterCairoTexture *self, guint width, guint height); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_canvas_get_size) void clutter_cairo_texture_get_surface_size (ClutterCairoTexture *self, guint *width, guint *height); CLUTTER_DEPRECATED_IN_1_12 void clutter_cairo_texture_set_auto_resize (ClutterCairoTexture *self, gboolean value); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_cairo_texture_get_auto_resize (ClutterCairoTexture *self); CLUTTER_DEPRECATED_IN_1_12 void clutter_cairo_texture_clear (ClutterCairoTexture *self); CLUTTER_DEPRECATED_IN_1_12 void clutter_cairo_texture_invalidate_rectangle (ClutterCairoTexture *self, cairo_rectangle_int_t *rect); CLUTTER_DEPRECATED_IN_1_12 void clutter_cairo_texture_invalidate (ClutterCairoTexture *self); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_cairo_texture_invalidate_rectangle) cairo_t * clutter_cairo_texture_create_region (ClutterCairoTexture *self, gint x_offset, gint y_offset, gint width, gint height); CLUTTER_DEPRECATED_IN_1_8_FOR(clutter_cairo_texture_invalidate) cairo_t * clutter_cairo_texture_create (ClutterCairoTexture *self); G_END_DECLS #endif /* __CLUTTER_CAIRO_TEXTURE_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-animator.h0000664000175000017500000002133714211404421024051 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation * * 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, see . * * Author: * Øyvind Kolås */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_ANIMATOR_H__ #define __CLUTTER_ANIMATOR_H__ #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_ANIMATOR (clutter_animator_get_type ()) #define CLUTTER_TYPE_ANIMATOR_KEY (clutter_animator_key_get_type ()) #define CLUTTER_ANIMATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ANIMATOR, ClutterAnimator)) #define CLUTTER_ANIMATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ANIMATOR, ClutterAnimatorClass)) #define CLUTTER_IS_ANIMATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ANIMATOR)) #define CLUTTER_IS_ANIMATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ANIMATOR)) #define CLUTTER_ANIMATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ANIMATOR, ClutterAnimatorClass)) /* ClutterAnimator is typedef in clutter-types.h */ typedef struct _ClutterAnimatorClass ClutterAnimatorClass; typedef struct _ClutterAnimatorPrivate ClutterAnimatorPrivate; /** * ClutterAnimatorKey: * * A key frame inside a #ClutterAnimator * * Since: 1.2 * * Deprecated: 1.12 */ typedef struct _ClutterAnimatorKey ClutterAnimatorKey; /** * ClutterAnimator: * * The #ClutterAnimator structure contains only private data and * should be accessed using the provided API * * Since: 1.2 * * Deprecated: 1.12 */ struct _ClutterAnimator { /*< private >*/ GObject parent_instance; ClutterAnimatorPrivate *priv; }; /** * ClutterAnimatorClass: * * The #ClutterAnimatorClass structure contains only private data * * Since: 1.2 * * Deprecated: 1.12 */ struct _ClutterAnimatorClass { /*< private >*/ GObjectClass parent_class; /* padding for future expansion */ gpointer _padding_dummy[16]; }; CLUTTER_DEPRECATED_IN_1_12 GType clutter_animator_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12 ClutterAnimator * clutter_animator_new (void); CLUTTER_DEPRECATED_IN_1_12 ClutterAnimator * clutter_animator_set_key (ClutterAnimator *animator, GObject *object, const gchar *property_name, guint mode, gdouble progress, const GValue *value); CLUTTER_DEPRECATED_IN_1_12 void clutter_animator_set (ClutterAnimator *animator, gpointer first_object, const gchar *first_property_name, guint first_mode, gdouble first_progress, ...) G_GNUC_NULL_TERMINATED; CLUTTER_DEPRECATED_IN_1_12 GList * clutter_animator_get_keys (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress); CLUTTER_DEPRECATED_IN_1_12 void clutter_animator_remove_key (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress); CLUTTER_DEPRECATED_IN_1_12 ClutterTimeline * clutter_animator_start (ClutterAnimator *animator); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_animator_compute_value (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress, GValue *value); CLUTTER_DEPRECATED_IN_1_12 ClutterTimeline * clutter_animator_get_timeline (ClutterAnimator *animator); CLUTTER_DEPRECATED_IN_1_12 void clutter_animator_set_timeline (ClutterAnimator *animator, ClutterTimeline *timeline); CLUTTER_DEPRECATED_IN_1_12 guint clutter_animator_get_duration (ClutterAnimator *animator); CLUTTER_DEPRECATED_IN_1_12 void clutter_animator_set_duration (ClutterAnimator *animator, guint duration); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_animator_property_get_ease_in (ClutterAnimator *animator, GObject *object, const gchar *property_name); CLUTTER_DEPRECATED_IN_1_12 void clutter_animator_property_set_ease_in (ClutterAnimator *animator, GObject *object, const gchar *property_name, gboolean ease_in); CLUTTER_DEPRECATED_IN_1_12 ClutterInterpolation clutter_animator_property_get_interpolation (ClutterAnimator *animator, GObject *object, const gchar *property_name); CLUTTER_DEPRECATED_IN_1_12 void clutter_animator_property_set_interpolation (ClutterAnimator *animator, GObject *object, const gchar *property_name, ClutterInterpolation interpolation); CLUTTER_DEPRECATED_IN_1_12 GType clutter_animator_key_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_12 GObject * clutter_animator_key_get_object (const ClutterAnimatorKey *key); CLUTTER_DEPRECATED_IN_1_12 const gchar * clutter_animator_key_get_property_name (const ClutterAnimatorKey *key); CLUTTER_DEPRECATED_IN_1_12 GType clutter_animator_key_get_property_type (const ClutterAnimatorKey *key); CLUTTER_DEPRECATED_IN_1_12 gulong clutter_animator_key_get_mode (const ClutterAnimatorKey *key); CLUTTER_DEPRECATED_IN_1_12 gdouble clutter_animator_key_get_progress (const ClutterAnimatorKey *key); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_animator_key_get_value (const ClutterAnimatorKey *key, GValue *value); G_END_DECLS #endif /* __CLUTTER_ANIMATOR_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-table-layout.c0000664000175000017500000022551614211404421024641 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see . * * Author: * Jose Dapena Paz * * Based on the MX MxTable actor by: * Thomas Wood * and ClutterBoxLayout by: * Emmanuele Bassi */ /** * SECTION:clutter-table-layout * @title: ClutterTableLayout * @short_description: A layout manager arranging children in rows * and columns * * The #ClutterTableLayout is a #ClutterLayoutManager implementing the * following layout policy: * * - children are arranged in a table * - each child specifies the specific row and column * cell to appear; * - a child can also set a span, and this way, take * more than one cell both horizontally and vertically; * - each child will be allocated to its natural * size or, if set to expand, the available size; * - if a child is set to fill on either (or both) * axis, its allocation will match all the available size; the * fill layout property only makes sense if the expand property is * also set; * - if a child is set to expand but not to fill then * it is possible to control the alignment using the horizontal and * vertical alignment layout properties. * * It is possible to control the spacing between children of a * #ClutterTableLayout by using clutter_table_layout_set_row_spacing() * and clutter_table_layout_set_column_spacing(). * * In order to set the layout properties when packing an actor inside a * #ClutterTableLayout you should use the clutter_table_layout_pack() * function. * * A #ClutterTableLayout can use animations to transition between different * values of the layout management properties; the easing mode and duration * used for the animations are controlled by the * #ClutterTableLayout:easing-mode and #ClutterTableLayout:easing-duration * properties and their accessor functions. * * #ClutterTableLayout is available since Clutter 1.4 * * Since Clutter 1.18 it's recommended to use #ClutterGridLayout instead * of #ClutterTableLayout; the former supports right-to-left text direction, * as well as using the alignment and expansion flags on #ClutterActor. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "deprecated/clutter-alpha.h" #include "clutter-table-layout.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-layout-meta.h" #include "clutter-private.h" #include "clutter-types.h" #define CLUTTER_TYPE_TABLE_CHILD (clutter_table_child_get_type ()) #define CLUTTER_TABLE_CHILD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TABLE_CHILD, ClutterTableChild)) #define CLUTTER_IS_TABLE_CHILD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TABLE_CHILD)) typedef struct _ClutterTableChild ClutterTableChild; typedef struct _ClutterLayoutMetaClass ClutterTableChildClass; typedef struct _DimensionData { gfloat min_size; gfloat pref_size; gfloat final_size; guint expand : 1; guint visible : 1; } DimensionData; struct _ClutterTableLayoutPrivate { ClutterContainer *container; guint col_spacing; guint row_spacing; gint n_rows; gint n_cols; gint active_row; gint active_col; gint visible_rows; gint visible_cols; GArray *columns; GArray *rows; gulong easing_mode; guint easing_duration; guint is_animating : 1; guint use_animations : 1; }; struct _ClutterTableChild { ClutterLayoutMeta parent_instance; gint col; gint row; gint col_span; gint row_span; ClutterTableAlignment x_align; ClutterTableAlignment y_align; guint x_expand : 1; guint y_expand : 1; guint x_fill : 1; guint y_fill : 1; }; enum { PROP_CHILD_0, PROP_CHILD_ROW, PROP_CHILD_COLUMN, PROP_CHILD_ROW_SPAN, PROP_CHILD_COLUMN_SPAN, PROP_CHILD_X_ALIGN, PROP_CHILD_Y_ALIGN, PROP_CHILD_X_FILL, PROP_CHILD_Y_FILL, PROP_CHILD_X_EXPAND, PROP_CHILD_Y_EXPAND }; enum { PROP_0, PROP_ROW_SPACING, PROP_COLUMN_SPACING, PROP_USE_ANIMATIONS, PROP_EASING_MODE, PROP_EASING_DURATION }; GType clutter_table_child_get_type (void); G_DEFINE_TYPE (ClutterTableChild, clutter_table_child, CLUTTER_TYPE_LAYOUT_META) G_DEFINE_TYPE_WITH_PRIVATE (ClutterTableLayout, clutter_table_layout, CLUTTER_TYPE_LAYOUT_MANAGER) /* * ClutterBoxChild */ static void table_child_set_position (ClutterTableChild *self, gint col, gint row) { gboolean row_changed = FALSE, col_changed = FALSE; if (self->col != col) { self->col = col; col_changed = TRUE; } if (self->row != row) { self->row = row; row_changed = TRUE; } if (row_changed || col_changed) { ClutterLayoutManager *layout; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); g_object_freeze_notify (G_OBJECT (self)); if (row_changed) g_object_notify (G_OBJECT (self), "row"); if (col_changed) g_object_notify (G_OBJECT (self), "column"); g_object_thaw_notify (G_OBJECT (self)); } } static void table_child_set_span (ClutterTableChild *self, gint col_span, gint row_span) { gboolean row_changed = FALSE, col_changed = FALSE; if (self->col_span != col_span) { self->col_span = col_span; col_changed = TRUE; } if (self->row_span != row_span) { self->row_span = row_span; row_changed = TRUE; } if (row_changed || col_changed) { ClutterLayoutManager *layout; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); if (row_changed) g_object_notify (G_OBJECT (self), "row-span"); if (col_changed) g_object_notify (G_OBJECT (self), "column-span"); } } static void table_child_set_align (ClutterTableChild *self, ClutterTableAlignment x_align, ClutterTableAlignment y_align) { gboolean x_changed = FALSE, y_changed = FALSE; if (self->x_align != x_align) { self->x_align = x_align; x_changed = TRUE; } if (self->y_align != y_align) { self->y_align = y_align; y_changed = TRUE; } if (x_changed || y_changed) { ClutterLayoutManager *layout; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); g_object_freeze_notify (G_OBJECT (self)); if (x_changed) g_object_notify (G_OBJECT (self), "x-align"); if (y_changed) g_object_notify (G_OBJECT (self), "y-align"); g_object_thaw_notify (G_OBJECT (self)); } } static void table_child_set_fill (ClutterTableChild *self, gboolean x_fill, gboolean y_fill) { gboolean x_changed = FALSE, y_changed = FALSE; x_fill = !!x_fill; y_fill = !!y_fill; if (self->x_fill != x_fill) { self->x_fill = x_fill; x_changed = TRUE; } if (self->y_fill != y_fill) { self->y_fill = y_fill; y_changed = TRUE; } if (x_changed || y_changed) { ClutterLayoutManager *layout; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); g_object_freeze_notify (G_OBJECT (self)); if (x_changed) g_object_notify (G_OBJECT (self), "x-fill"); if (y_changed) g_object_notify (G_OBJECT (self), "y-fill"); g_object_thaw_notify (G_OBJECT (self)); } } static void table_child_set_expand (ClutterTableChild *self, gboolean x_expand, gboolean y_expand) { gboolean x_changed = FALSE, y_changed = FALSE; x_expand = !!x_expand; y_expand = !!y_expand; if (self->x_expand != x_expand) { self->x_expand = x_expand; x_changed = TRUE; } if (self->y_expand != y_expand) { self->y_expand = y_expand; y_changed = TRUE; } if (x_changed || y_changed) { ClutterLayoutManager *layout; layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); clutter_layout_manager_layout_changed (layout); g_object_freeze_notify (G_OBJECT (self)); if (x_changed) g_object_notify (G_OBJECT (self), "x-expand"); if (y_changed) g_object_notify (G_OBJECT (self), "y-expand"); g_object_thaw_notify (G_OBJECT (self)); } } static void clutter_table_child_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterTableChild *self = CLUTTER_TABLE_CHILD (gobject); switch (prop_id) { case PROP_CHILD_COLUMN: table_child_set_position (self, g_value_get_int (value), self->row); break; case PROP_CHILD_ROW: table_child_set_position (self, self->col, g_value_get_int (value)); break; case PROP_CHILD_COLUMN_SPAN: table_child_set_span (self, g_value_get_int (value), self->row_span); break; case PROP_CHILD_ROW_SPAN: table_child_set_span (self, self->col_span, g_value_get_int (value)); break; case PROP_CHILD_X_ALIGN: table_child_set_align (self, g_value_get_enum (value), self->y_align); break; case PROP_CHILD_Y_ALIGN: table_child_set_align (self, self->x_align, g_value_get_enum (value)); break; case PROP_CHILD_X_FILL: table_child_set_fill (self, g_value_get_boolean (value), self->y_fill); break; case PROP_CHILD_Y_FILL: table_child_set_fill (self, self->x_fill, g_value_get_boolean (value)); break; case PROP_CHILD_X_EXPAND: table_child_set_expand (self, g_value_get_boolean (value), self->y_expand); break; case PROP_CHILD_Y_EXPAND: table_child_set_expand (self, self->x_expand, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_table_child_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterTableChild *self = CLUTTER_TABLE_CHILD (gobject); switch (prop_id) { case PROP_CHILD_ROW: g_value_set_int (value, self->row); break; case PROP_CHILD_COLUMN: g_value_set_int (value, self->col); break; case PROP_CHILD_ROW_SPAN: g_value_set_int (value, self->row_span); break; case PROP_CHILD_COLUMN_SPAN: g_value_set_int (value, self->col_span); break; case PROP_CHILD_X_ALIGN: g_value_set_enum (value, self->x_align); break; case PROP_CHILD_Y_ALIGN: g_value_set_enum (value, self->y_align); break; case PROP_CHILD_X_FILL: g_value_set_boolean (value, self->x_fill); break; case PROP_CHILD_Y_FILL: g_value_set_boolean (value, self->y_fill); break; case PROP_CHILD_X_EXPAND: g_value_set_boolean (value, self->x_expand); break; case PROP_CHILD_Y_EXPAND: g_value_set_boolean (value, self->y_expand); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_table_child_class_init (ClutterTableChildClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = clutter_table_child_set_property; gobject_class->get_property = clutter_table_child_get_property; pspec = g_param_spec_int ("column", P_("Column Number"), P_("The column the widget resides in"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_COLUMN, pspec); pspec = g_param_spec_int ("row", P_("Row Number"), P_("The row the widget resides in"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_ROW, pspec); pspec = g_param_spec_int ("column-span", P_("Column Span"), P_("The number of columns the widget should span"), 1, G_MAXINT, 1, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_COLUMN_SPAN, pspec); pspec = g_param_spec_int ("row-span", P_("Row Span"), P_("The number of rows the widget should span"), 1, G_MAXINT, 1, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_ROW_SPAN, pspec); pspec = g_param_spec_boolean ("x-expand", P_("Horizontal Expand"), P_("Allocate extra space for the child in horizontal axis"), TRUE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_X_EXPAND, pspec); pspec = g_param_spec_boolean ("y-expand", P_("Vertical Expand"), P_("Allocate extra space for the child in vertical axis"), TRUE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_Y_EXPAND, pspec); pspec = g_param_spec_boolean ("x-fill", P_("Horizontal Fill"), P_("Whether the child should receive priority when the container is allocating spare space on the horizontal axis"), TRUE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_X_FILL, pspec); pspec = g_param_spec_boolean ("y-fill", P_("Vertical Fill"), P_("Whether the child should receive priority when the container is allocating spare space on the vertical axis"), TRUE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_Y_FILL, pspec); /** * ClutterTableLayout:x-align: * * The horizontal alignment of the actor within the cell * * Since: 1.4 */ pspec = g_param_spec_enum ("x-align", P_("Horizontal Alignment"), P_("Horizontal alignment of the actor within the cell"), CLUTTER_TYPE_TABLE_ALIGNMENT, CLUTTER_TABLE_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_X_ALIGN, pspec); /** * ClutterTableLayout:y-align: * * The vertical alignment of the actor within the cell * * Since: 1.4 */ pspec = g_param_spec_enum ("y-align", P_("Vertical Alignment"), P_("Vertical alignment of the actor within the cell"), CLUTTER_TYPE_TABLE_ALIGNMENT, CLUTTER_TABLE_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_CHILD_Y_ALIGN, pspec); } static void clutter_table_child_init (ClutterTableChild *self) { self->col_span = 1; self->row_span = 1; self->x_align = CLUTTER_TABLE_ALIGNMENT_CENTER; self->y_align = CLUTTER_TABLE_ALIGNMENT_CENTER; self->x_expand = TRUE; self->y_expand = TRUE; self->x_fill = TRUE; self->y_fill = TRUE; } static GType clutter_table_layout_get_child_meta_type (ClutterLayoutManager *manager) { return CLUTTER_TYPE_TABLE_CHILD; } static void clutter_table_layout_set_container (ClutterLayoutManager *layout, ClutterContainer *container) { ClutterTableLayoutPrivate *priv = CLUTTER_TABLE_LAYOUT (layout)->priv; priv->container = container; } static void update_row_col (ClutterTableLayout *layout, ClutterContainer *container) { ClutterTableLayoutPrivate *priv = layout->priv; ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (layout); ClutterActor *actor, *child; gint n_cols, n_rows; n_cols = n_rows = 0; if (container == NULL) goto out; actor = CLUTTER_ACTOR (container); for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { ClutterTableChild *meta; meta = CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager, container, child)); n_cols = MAX (n_cols, meta->col + meta->col_span); n_rows = MAX (n_rows, meta->row + meta->row_span); } out: priv->n_cols = n_cols; priv->n_rows = n_rows; } static void calculate_col_widths (ClutterTableLayout *self, ClutterContainer *container, gint for_width) { ClutterTableLayoutPrivate *priv = self->priv; ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (self); ClutterActor *actor, *child; gint i; DimensionData *columns; ClutterOrientation orientation = CLUTTER_ORIENTATION_HORIZONTAL; update_row_col (self, container); g_array_set_size (priv->columns, 0); g_array_set_size (priv->columns, priv->n_cols); columns = (DimensionData *) (void *) priv->columns->data; /* reset the visibility of all columns */ priv->visible_cols = 0; for (i = 0; i < priv->n_cols; i++) { columns[i].expand = FALSE; columns[i].visible = FALSE; } actor = CLUTTER_ACTOR (container); /* STAGE ONE: calculate column widths for non-spanned children */ for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { ClutterTableChild *meta; DimensionData *col; gfloat c_min, c_pref; if (!clutter_actor_is_visible (child)) continue; meta = CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager, container, child)); if (meta->col_span > 1) continue; col = &columns[meta->col]; if (!col->visible) { col->visible = TRUE; priv->visible_cols += 1; } clutter_actor_get_preferred_width (child, -1, &c_min, &c_pref); col->min_size = MAX (col->min_size, c_min); col->pref_size = MAX (col->pref_size, c_pref); if (!col->expand) { col->expand = clutter_actor_needs_expand (child, orientation) || meta->x_expand; } } /* STAGE TWO: take spanning children into account */ for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { ClutterTableChild *meta; gfloat c_min, c_pref; gfloat min_width, pref_width; gint start_col, end_col; gint n_expand; if (!clutter_actor_is_visible (child)) continue; meta = CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager, container, child)); if (meta->col_span < 2) continue; start_col = meta->col; end_col = meta->col + meta->col_span - 1; clutter_actor_get_preferred_width (child, -1, &c_min, &c_pref); /* check there is enough room for this actor */ min_width = 0; pref_width = 0; n_expand = 0; for (i = start_col; i <= end_col; i++) { min_width += columns[i].min_size; pref_width += columns[i].pref_size; if (columns[i].expand) n_expand++; if (!columns[i].visible) { columns[i].visible = TRUE; priv->visible_cols += 1; } if (!columns[i].expand) { columns[i].expand = clutter_actor_needs_expand (child, orientation) || meta->x_expand; } } min_width += priv->col_spacing * (meta->col_span - 1); pref_width += priv->col_spacing * (meta->col_span - 1); /* see calculate_row_heights() for comments */ /* (1) */ if (c_min > min_width) { /* (2) */ /* we can start from preferred width and decrease */ if (pref_width > c_min) { for (i = start_col; i <= end_col; i++) columns[i].final_size = columns[i].pref_size; while (pref_width > c_min) { for (i = start_col; i <= end_col; i++) { if (columns[i].final_size > columns[i].min_size) { columns[i].final_size--; pref_width--; } } } for (i = start_col; i <= end_col; i++) columns[i].min_size = columns[i].final_size; } else { /* (3) */ /* we can expand from preferred size */ gfloat expand_by; expand_by = c_pref - pref_width; for (i = start_col; i <= end_col; i++) { if (n_expand) { if (columns[i].expand) columns[i].min_size = columns[i].pref_size + expand_by / n_expand; } else columns[i].min_size = columns[i].pref_size + expand_by / meta->col_span; } } } } /* calculate final widths */ if (for_width >= 0) { gfloat min_width, pref_width; gint n_expand; min_width = 0; pref_width = 0; n_expand = 0; for (i = 0; i < self->priv->n_cols; i++) { pref_width += columns[i].pref_size; min_width += columns[i].min_size; if (columns[i].expand) n_expand++; } pref_width += priv->col_spacing * MAX (priv->visible_cols - 1, 0); min_width += priv->col_spacing * MAX (priv->visible_cols - 1, 0); if (for_width <= min_width) { /* erk, we can't shrink this! */ for (i = 0; i < priv->n_cols; i++) columns[i].final_size = columns[i].min_size; return; } if (for_width == pref_width) { /* perfect! */ for (i = 0; i < self->priv->n_cols; i++) columns[i].final_size = columns[i].pref_size; return; } /* for_width is between min_width and pref_width */ if (for_width < pref_width && for_width > min_width) { gfloat width; /* shrink columns until they reach min_width */ /* start with all columns at preferred size */ for (i = 0; i < self->priv->n_cols; i++) columns[i].final_size = columns[i].pref_size; width = pref_width; while (width > for_width) { for (i = 0; i < self->priv->n_cols; i++) { if (columns[i].final_size > columns[i].min_size) { columns[i].final_size--; width--; } } } return; } /* expand columns */ if (for_width > pref_width) { gfloat extra_width = for_width - pref_width; gint remaining; if (n_expand) remaining = (gint) extra_width % n_expand; else remaining = (gint) extra_width % priv->n_cols; for (i = 0; i < self->priv->n_cols; i++) { if (columns[i].expand) { columns[i].final_size = columns[i].pref_size + (extra_width / n_expand); } else columns[i].final_size = columns[i].pref_size; } /* distribute the remainder among children */ i = 0; while (remaining) { columns[i].final_size++; i++; remaining--; } } } } static void calculate_row_heights (ClutterTableLayout *self, ClutterContainer *container, gint for_height) { ClutterTableLayoutPrivate *priv = self->priv; ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (self); ClutterActor *actor, *child; gint i; DimensionData *rows, *columns; ClutterOrientation orientation = CLUTTER_ORIENTATION_VERTICAL; update_row_col (self, container); g_array_set_size (priv->rows, 0); g_array_set_size (priv->rows, self->priv->n_rows); rows = (DimensionData *) (void *) priv->rows->data; columns = (DimensionData *) (void *) priv->columns->data; /* reset the visibility of all rows */ priv->visible_rows = 0; for (i = 0; i < priv->n_rows; i++) { rows[i].expand = FALSE; rows[i].visible = FALSE; } actor = CLUTTER_ACTOR (container); /* STAGE ONE: calculate row heights for non-spanned children */ for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { ClutterTableChild *meta; DimensionData *row; gfloat c_min, c_pref; if (!clutter_actor_is_visible (child)) continue; meta = CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager, container, child)); if (meta->row_span > 1) continue; row = &rows[meta->row]; if (!row->visible) { row->visible = TRUE; priv->visible_rows += 1; } clutter_actor_get_preferred_height (child, columns[meta->col].final_size, &c_min, &c_pref); row->min_size = MAX (row->min_size, c_min); row->pref_size = MAX (row->pref_size, c_pref); if (!row->expand) { row->expand = clutter_actor_needs_expand (child, orientation) || meta->y_expand; } } /* STAGE TWO: take spanning children into account */ for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { ClutterTableChild *meta; gfloat c_min, c_pref; gfloat min_height, pref_height; gint start_row, end_row; gint n_expand; if (!clutter_actor_is_visible (child)) continue; meta = CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (manager, container, child)); if (meta->row_span < 2) continue; start_row = meta->row; end_row = meta->row + meta->row_span - 1; clutter_actor_get_preferred_height (child, columns[meta->col].final_size, &c_min, &c_pref); /* check there is enough room for this actor */ min_height = 0; pref_height = 0; n_expand = 0; for (i = start_row; i <= end_row; i++) { min_height += rows[i].min_size; pref_height += rows[i].pref_size; if (rows[i].expand) n_expand++; if (!rows[i].visible) { rows[i].visible = TRUE; priv->visible_rows += 1; } if (!rows[i].expand) { rows[i].expand = clutter_actor_needs_expand (child, orientation) || meta->y_expand; } } min_height += priv->row_spacing * (meta->row_span - 1); pref_height += priv->row_spacing * (meta->row_span - 1); /* 1) If the minimum height of the rows spanned is less than the * minimum height of the child that is spanning them, then we * must increase the minimum height of the rows spanned. * * 2) If the preferred height of the spanned rows is more than * the minimum height of the spanning child, then we can start * at this size and decrease each row evenly. * * 3) If the preferred height of the rows is more than the minimum * height of the spanned child, then we can start at the preferred * height and expand. */ /* (1) */ if (c_min > min_height) { /* (2) */ /* we can start from preferred height and decrease */ if (pref_height > c_min) { for (i = start_row; i <= end_row; i++) rows[i].final_size = rows[i].pref_size; while (pref_height > c_min) { for (i = start_row; i <= end_row; i++) { if (rows[i].final_size > rows[i].min_size) { rows[i].final_size--; pref_height--; } } } for (i = start_row; i <= end_row; i++) rows[i].min_size = rows[i].final_size; } else { /* (3) */ /* we can expand from preferred size */ gfloat expand_by = c_pref - pref_height; for (i = start_row; i <= end_row; i++) { if (n_expand) { if (rows[i].expand) rows[i].min_size = rows[i].pref_size + expand_by / n_expand; } else rows[i].min_size = rows[i].pref_size + expand_by / meta->row_span; } } } } /* calculate final heights */ if (for_height >= 0) { gfloat min_height, pref_height; gint n_expand; min_height = 0; pref_height = 0; n_expand = 0; for (i = 0; i < self->priv->n_rows; i++) { pref_height += rows[i].pref_size; min_height += rows[i].min_size; if (rows[i].expand) n_expand++; } pref_height += priv->row_spacing * MAX (priv->visible_rows - 1, 0); min_height += priv->row_spacing * MAX (priv->visible_rows - 1, 0); if (for_height <= min_height) { /* erk, we can't shrink this! */ for (i = 0; i < self->priv->n_rows; i++) rows[i].final_size = rows[i].min_size; return; } if (for_height == pref_height) { /* perfect! */ for (i = 0; i < self->priv->n_rows; i++) rows[i].final_size = rows[i].pref_size; return; } /* for_height is between min_height and pref_height */ if (for_height < pref_height && for_height > min_height) { gfloat height; /* shrink rows until they reach min_height */ /* start with all rows at preferred size */ for (i = 0; i < self->priv->n_rows; i++) rows[i].final_size = rows[i].pref_size; height = pref_height; while (height > for_height) { for (i = 0; i < priv->n_rows; i++) { if (rows[i].final_size > rows[i].min_size) { rows[i].final_size--; height--; } } } return; } /* expand rows */ if (for_height > pref_height) { gfloat extra_height = for_height - pref_height; gint remaining; if (n_expand) remaining = (gint) extra_height % n_expand; else remaining = (gint) extra_height % self->priv->n_rows; for (i = 0; i < self->priv->n_rows; i++) { if (rows[i].expand) { rows[i].final_size = rows[i].pref_size + (extra_height / n_expand); } else rows[i].final_size = rows[i].pref_size; } /* distribute the remainder among children */ i = 0; while (remaining) { rows[i].final_size++; i++; remaining--; } } } } static void calculate_table_dimensions (ClutterTableLayout *self, ClutterContainer *container, gfloat for_width, gfloat for_height) { calculate_col_widths (self, container, for_width); calculate_row_heights (self, container, for_height); } static void clutter_table_layout_get_preferred_width (ClutterLayoutManager *layout, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterTableLayout *self = CLUTTER_TABLE_LAYOUT (layout); ClutterTableLayoutPrivate *priv = self->priv; gfloat total_min_width, total_pref_width; DimensionData *columns; gint i; update_row_col (self, container); if (priv->n_cols < 1) { *min_width_p = 0; *natural_width_p = 0; return; } calculate_table_dimensions (self, container, -1, for_height); columns = (DimensionData *) (void *) priv->columns->data; total_min_width = MAX ((priv->visible_cols - 1) * (float) priv->col_spacing, 0); total_pref_width = total_min_width; for (i = 0; i < priv->n_cols; i++) { total_min_width += columns[i].min_size; total_pref_width += columns[i].pref_size; } if (min_width_p) *min_width_p = total_min_width; if (natural_width_p) *natural_width_p = total_pref_width; } static void clutter_table_layout_get_preferred_height (ClutterLayoutManager *layout, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterTableLayout *self = CLUTTER_TABLE_LAYOUT (layout); ClutterTableLayoutPrivate *priv = self->priv; gfloat total_min_height, total_pref_height; DimensionData *rows; gint i; update_row_col (self, container); if (priv->n_rows < 1) { *min_height_p = 0; *natural_height_p = 0; return; } calculate_table_dimensions (self, container, for_width, -1); rows = (DimensionData *) (void *) priv->rows->data; total_min_height = MAX ((priv->visible_rows - 1) * (float) priv->row_spacing, 0); total_pref_height = total_min_height; for (i = 0; i < self->priv->n_rows; i++) { total_min_height += rows[i].min_size; total_pref_height += rows[i].pref_size; } if (min_height_p) *min_height_p = total_min_height; if (natural_height_p) *natural_height_p = total_pref_height; } static gdouble get_table_alignment_factor (ClutterTableAlignment alignment) { switch (alignment) { case CLUTTER_TABLE_ALIGNMENT_START: return 0.0; case CLUTTER_TABLE_ALIGNMENT_CENTER: return 0.5; case CLUTTER_TABLE_ALIGNMENT_END: return 1.0; } return 0.0; } static void clutter_table_layout_allocate (ClutterLayoutManager *layout, ClutterContainer *container, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterTableLayout *self = CLUTTER_TABLE_LAYOUT (layout); ClutterTableLayoutPrivate *priv = self->priv; ClutterActor *actor, *child; gint row_spacing, col_spacing; gint i; DimensionData *rows, *columns; update_row_col (self, container); if (priv->n_cols < 1 || priv->n_rows < 1) return; actor = CLUTTER_ACTOR (container); if (clutter_actor_get_n_children (actor) == 0) return; col_spacing = (priv->col_spacing); row_spacing = (priv->row_spacing); calculate_table_dimensions (self, container, box->x2 - box->x1, box->y2 - box->y1); rows = (DimensionData *) (void *) priv->rows->data; columns = (DimensionData *) (void *) priv->columns->data; for (child = clutter_actor_get_first_child (actor); child != NULL; child = clutter_actor_get_next_sibling (child)) { gint row, col, row_span, col_span; gint col_width, row_height; ClutterTableChild *meta; ClutterActorBox childbox; gint child_x, child_y; gdouble x_align, y_align; gboolean x_fill, y_fill; if (!clutter_actor_is_visible (child)) continue; meta = CLUTTER_TABLE_CHILD (clutter_layout_manager_get_child_meta (layout, container, child)); /* get child properties */ col = meta->col; row = meta->row; row_span = meta->row_span; col_span = meta->col_span; x_align = get_table_alignment_factor (meta->x_align); y_align = get_table_alignment_factor (meta->y_align); x_fill = meta->x_fill; y_fill = meta->y_fill; /* initialise the width and height */ col_width = columns[col].final_size; row_height = rows[row].final_size; /* Add the widths of the spanned columns: * * First check that we have a non-zero span. Then we loop over each of * the columns that we're spanning but we stop short if we go past the * number of columns in the table. This is necessary to avoid accessing * uninitialised memory. We add the spacing in here too since we only * want to add as much spacing as times we successfully span. */ if (col + col_span > priv->n_cols) g_warning (G_STRLOC ": column-span exceeds number of columns"); if (row + row_span > priv->n_rows) g_warning (G_STRLOC ": row-span exceeds number of rows"); if (col_span > 1) { for (i = col + 1; i < col + col_span && i < priv->n_cols; i++) { col_width += columns[i].final_size; col_width += col_spacing; } } /* add the height of the spanned rows */ if (row_span > 1) { for (i = row + 1; i < row + row_span && i < priv->n_rows; i++) { row_height += rows[i].final_size; row_height += row_spacing; } } /* calculate child x */ child_x = clutter_actor_box_get_x (box); for (i = 0; i < col; i++) { if (columns[i].visible) { child_x += columns[i].final_size; child_x += col_spacing; } } /* calculate child y */ child_y = clutter_actor_box_get_y (box); for (i = 0; i < row; i++) { if (rows[i].visible) { child_y += rows[i].final_size; child_y += row_spacing; } } /* set up childbox */ childbox.x1 = (float) child_x; childbox.x2 = (float) MAX (0, child_x + col_width); childbox.y1 = (float) child_y; childbox.y2 = (float) MAX (0, child_y + row_height); if (priv->use_animations) { clutter_actor_save_easing_state (child); clutter_actor_set_easing_mode (child, priv->easing_mode); clutter_actor_set_easing_duration (child, priv->easing_duration); } if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL) || clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL)) clutter_actor_allocate (child, &childbox, flags); else clutter_actor_allocate_align_fill (child, &childbox, x_align, y_align, x_fill, y_fill, flags); if (priv->use_animations) clutter_actor_restore_easing_state (child); } } static void clutter_table_layout_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterTableLayout *self = CLUTTER_TABLE_LAYOUT (gobject); switch (prop_id) { case PROP_COLUMN_SPACING: clutter_table_layout_set_column_spacing (self, g_value_get_uint (value)); break; case PROP_ROW_SPACING: clutter_table_layout_set_row_spacing (self, g_value_get_uint (value)); break; case PROP_USE_ANIMATIONS: clutter_table_layout_set_use_animations (self, g_value_get_boolean (value)); break; case PROP_EASING_MODE: clutter_table_layout_set_easing_mode (self, g_value_get_ulong (value)); break; case PROP_EASING_DURATION: clutter_table_layout_set_easing_duration (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_table_layout_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterTableLayoutPrivate *priv = CLUTTER_TABLE_LAYOUT (gobject)->priv; switch (prop_id) { case PROP_ROW_SPACING: g_value_set_uint (value, priv->row_spacing); break; case PROP_COLUMN_SPACING: g_value_set_uint (value, priv->col_spacing); break; case PROP_USE_ANIMATIONS: g_value_set_boolean (value, priv->use_animations); break; case PROP_EASING_MODE: g_value_set_ulong (value, priv->easing_mode); break; case PROP_EASING_DURATION: g_value_set_uint (value, priv->easing_duration); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_table_layout_finalize (GObject *gobject) { ClutterTableLayoutPrivate *priv = CLUTTER_TABLE_LAYOUT (gobject)->priv; g_array_free (priv->columns, TRUE); g_array_free (priv->rows, TRUE); G_OBJECT_CLASS (clutter_table_layout_parent_class)->finalize (gobject); } static void clutter_table_layout_class_init (ClutterTableLayoutClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterLayoutManagerClass *layout_class; GParamSpec *pspec; layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass); gobject_class->set_property = clutter_table_layout_set_property; gobject_class->get_property = clutter_table_layout_get_property; gobject_class->finalize = clutter_table_layout_finalize; layout_class->get_preferred_width = clutter_table_layout_get_preferred_width; layout_class->get_preferred_height = clutter_table_layout_get_preferred_height; layout_class->allocate = clutter_table_layout_allocate; layout_class->set_container = clutter_table_layout_set_container; layout_class->get_child_meta_type = clutter_table_layout_get_child_meta_type; /** * ClutterTableLayout:column-spacing: * * The spacing between columns of the #ClutterTableLayout, in pixels * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout:column-spacing instead */ pspec = g_param_spec_uint ("column-spacing", P_("Column Spacing"), P_("Spacing between columns"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_COLUMN_SPACING, pspec); /** * ClutterTableLayout:row-spacing: * * The spacing between rows of the #ClutterTableLayout, in pixels * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout:row-spacing instead */ pspec = g_param_spec_uint ("row-spacing", P_("Row Spacing"), P_("Spacing between rows"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_ROW_SPACING, pspec); /** * ClutterTableLayout:use-animations: * * Whether the #ClutterTableLayout should animate changes in the * layout properties. * * By default, #ClutterTableLayout will honour the easing state of * the children when allocating them. Setting this property to * %TRUE will override the easing state with the layout manager's * #ClutterTableLayout:easing-mode and #ClutterTableLayout:easing-duration * properties. * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them */ pspec = g_param_spec_boolean ("use-animations", P_("Use Animations"), P_("Whether layout changes should be animated"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_USE_ANIMATIONS, pspec); /** * ClutterTableLayout:easing-mode: * * The easing mode for the animations, in case * #ClutterTableLayout:use-animations is set to %TRUE. * * The easing mode has the same semantics of #ClutterAnimation:mode: it can * either be a value from the #ClutterAnimationMode enumeration, like * %CLUTTER_EASE_OUT_CUBIC, or a logical id as returned by * clutter_alpha_register_func(). * * The default value is %CLUTTER_EASE_OUT_CUBIC. * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them */ pspec = g_param_spec_ulong ("easing-mode", P_("Easing Mode"), P_("The easing mode of the animations"), 0, G_MAXULONG, CLUTTER_EASE_OUT_CUBIC, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_EASING_MODE, pspec); /** * ClutterTableLayout:easing-duration: * * The duration of the animations, in case #ClutterTableLayout:use-animations * is set to %TRUE. * * The duration is expressed in milliseconds. * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them */ pspec = g_param_spec_uint ("easing-duration", P_("Easing Duration"), P_("The duration of the animations"), 0, G_MAXUINT, 500, CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_EASING_DURATION, pspec); } static void clutter_table_layout_init (ClutterTableLayout *layout) { ClutterTableLayoutPrivate *priv; layout->priv = priv = clutter_table_layout_get_instance_private (layout); priv->row_spacing = 0; priv->col_spacing = 0; priv->use_animations = FALSE; priv->easing_mode = CLUTTER_EASE_OUT_CUBIC; priv->easing_duration = 500; priv->columns = g_array_new (FALSE, TRUE, sizeof (DimensionData)); priv->rows = g_array_new (FALSE, TRUE, sizeof (DimensionData)); } /** * clutter_table_layout_new: * * Creates a new #ClutterTableLayout layout manager * * Return value: the newly created #ClutterTableLayout * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout instead */ ClutterLayoutManager * clutter_table_layout_new (void) { return g_object_new (CLUTTER_TYPE_TABLE_LAYOUT, NULL); } /** * clutter_table_layout_set_column_spacing: * @layout: a #ClutterTableLayout * @spacing: the spacing between columns of the layout, in pixels * * Sets the spacing between columns of @layout * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout:column-spacing instead */ void clutter_table_layout_set_column_spacing (ClutterTableLayout *layout, guint spacing) { ClutterTableLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); priv = layout->priv; if (priv->col_spacing != spacing) { ClutterLayoutManager *manager; priv->col_spacing = spacing; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify (G_OBJECT (layout), "column-spacing"); } } /** * clutter_table_layout_get_column_spacing: * @layout: a #ClutterTableLayout * * Retrieves the spacing set using clutter_table_layout_set_column_spacing() * * Return value: the spacing between columns of the #ClutterTableLayout * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout:column-spacing */ guint clutter_table_layout_get_column_spacing (ClutterTableLayout *layout) { g_return_val_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout), 0); return layout->priv->col_spacing; } /** * clutter_table_layout_set_row_spacing: * @layout: a #ClutterTableLayout * @spacing: the spacing between rows of the layout, in pixels * * Sets the spacing between rows of @layout * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout:row-spacing instead */ void clutter_table_layout_set_row_spacing (ClutterTableLayout *layout, guint spacing) { ClutterTableLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); priv = layout->priv; if (priv->row_spacing != spacing) { ClutterLayoutManager *manager; priv->row_spacing = spacing; manager = CLUTTER_LAYOUT_MANAGER (layout); clutter_layout_manager_layout_changed (manager); g_object_notify (G_OBJECT (layout), "row-spacing"); } } /** * clutter_table_layout_get_row_spacing: * @layout: a #ClutterTableLayout * * Retrieves the spacing set using clutter_table_layout_set_row_spacing() * * Return value: the spacing between rows of the #ClutterTableLayout * * Since: 1.4 * * Deprecated: 1.18: Use #ClutterGridLayout:row-spacing instead */ guint clutter_table_layout_get_row_spacing (ClutterTableLayout *layout) { g_return_val_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout), 0); return layout->priv->row_spacing; } /** * clutter_table_layout_pack: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor * @column: the column the @actor should be put, or -1 to append * @row: the row the @actor should be put, or -1 to append * * Packs @actor inside the #ClutterContainer associated to @layout * at the given row and column. * * Since: 1.4 * * Deprecated: 1.18: Use clutter_grid_layout_attach_child() instead */ void clutter_table_layout_pack (ClutterTableLayout *layout, ClutterActor *actor, gint column, gint row) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before adding children", G_OBJECT_TYPE_NAME (layout)); return; } update_row_col (CLUTTER_TABLE_LAYOUT (layout), priv->container); clutter_container_add_actor (priv->container, actor); manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); g_assert (CLUTTER_IS_TABLE_CHILD (meta)); if (row < 0) row = priv->n_rows; if (column < 0) column = priv->n_cols; table_child_set_position (CLUTTER_TABLE_CHILD (meta), column, row); } /** * clutter_table_layout_set_span: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @column_span: Column span for @actor * @row_span: Row span for @actor * * Sets the row and column span for @actor * inside @layout * * Since: 1.4 * * Deprecated: 1.18: Use the `width` and `height` layout properties * of #ClutterGridLayout instead */ void clutter_table_layout_set_span (ClutterTableLayout *layout, ClutterActor *actor, gint column_span, gint row_span) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); table_child_set_span (CLUTTER_TABLE_CHILD (meta), column_span, row_span); } /** * clutter_table_layout_get_span: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @column_span: (out): return location for the col span * @row_span: (out): return location for the row span * * Retrieves the row and column span for @actor as set using * clutter_table_layout_pack() or clutter_table_layout_set_span() * * Since: 1.4 * * Deprecated: 1.18: Use the `width` and `height` layout properties * of #ClutterGridLayout instead */ void clutter_table_layout_get_span (ClutterTableLayout *layout, ClutterActor *actor, gint *column_span, gint *row_span) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); if (column_span) *column_span = CLUTTER_TABLE_CHILD (meta)->col_span; if (row_span) *row_span = CLUTTER_TABLE_CHILD (meta)->row_span; } /** * clutter_table_layout_set_alignment: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @x_align: Horizontal alignment policy for @actor * @y_align: Vertical alignment policy for @actor * * Sets the horizontal and vertical alignment policies for @actor * inside @layout * * Since: 1.4 * * Deprecated: 1.12: Use clutter_actor_set_x_align() and * clutter_actor_set_y_align() instead. */ void clutter_table_layout_set_alignment (ClutterTableLayout *layout, ClutterActor *actor, ClutterTableAlignment x_align, ClutterTableAlignment y_align) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); table_child_set_align (CLUTTER_TABLE_CHILD (meta), x_align, y_align); } /** * clutter_table_layout_get_alignment: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @x_align: (out): return location for the horizontal alignment policy * @y_align: (out): return location for the vertical alignment policy * * Retrieves the horizontal and vertical alignment policies for @actor * as set using clutter_table_layout_pack() or * clutter_table_layout_set_alignment(). * * Since: 1.4 * * Deprecated: 1.12: Use clutter_actor_get_x_align() and * clutter_actor_get_y_align() instead. */ void clutter_table_layout_get_alignment (ClutterTableLayout *layout, ClutterActor *actor, ClutterTableAlignment *x_align, ClutterTableAlignment *y_align) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); if (x_align) *x_align = CLUTTER_TABLE_CHILD (meta)->x_align; if (y_align) *y_align = CLUTTER_TABLE_CHILD (meta)->y_align; } /** * clutter_table_layout_set_fill: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @x_fill: whether @actor should fill horizontally the allocated space * @y_fill: whether @actor should fill vertically the allocated space * * Sets the horizontal and vertical fill policies for @actor * inside @layout * * Since: 1.4 * * Deprecated: 1.12: Use clutter_actor_set_x_align() and * clutter_actor_set_y_align() instead. */ void clutter_table_layout_set_fill (ClutterTableLayout *layout, ClutterActor *actor, gboolean x_fill, gboolean y_fill) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); table_child_set_fill (CLUTTER_TABLE_CHILD (meta), x_fill, y_fill); } /** * clutter_table_layout_get_fill: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @x_fill: (out): return location for the horizontal fill policy * @y_fill: (out): return location for the vertical fill policy * * Retrieves the horizontal and vertical fill policies for @actor * as set using clutter_table_layout_pack() or clutter_table_layout_set_fill() * * Since: 1.4 * * Deprecated: 1.12: Use clutter_actor_get_x_align() and * clutter_actor_get_y_align() instead. */ void clutter_table_layout_get_fill (ClutterTableLayout *layout, ClutterActor *actor, gboolean *x_fill, gboolean *y_fill) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); if (x_fill) *x_fill = CLUTTER_TABLE_CHILD (meta)->x_fill; if (y_fill) *y_fill = CLUTTER_TABLE_CHILD (meta)->y_fill; } /** * clutter_table_layout_set_expand: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @x_expand: whether @actor should allocate extra space horizontally * @y_expand: whether @actor should allocate extra space vertically * * Sets the horizontal and vertical expand policies for @actor * inside @layout * * Since: 1.4 * * Deprecated: 1.12: Use clutter_actor_set_x_expand() or * clutter_actor_set_y_expand() instead. */ void clutter_table_layout_set_expand (ClutterTableLayout *layout, ClutterActor *actor, gboolean x_expand, gboolean y_expand) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); table_child_set_expand (CLUTTER_TABLE_CHILD (meta), x_expand, y_expand); } /** * clutter_table_layout_get_expand: * @layout: a #ClutterTableLayout * @actor: a #ClutterActor child of @layout * @x_expand: (out): return location for the horizontal expand policy * @y_expand: (out): return location for the vertical expand policy * * Retrieves the horizontal and vertical expand policies for @actor * as set using clutter_table_layout_pack() or clutter_table_layout_set_expand() * * Since: 1.4 * * Deprecated: 1.12: Use clutter_actor_get_x_expand() and * clutter_actor_get_y_expand() instead. */ void clutter_table_layout_get_expand (ClutterTableLayout *layout, ClutterActor *actor, gboolean *x_expand, gboolean *y_expand) { ClutterTableLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); priv = layout->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before querying layout " "properties", G_OBJECT_TYPE_NAME (layout)); return; } manager = CLUTTER_LAYOUT_MANAGER (layout); meta = clutter_layout_manager_get_child_meta (manager, priv->container, actor); if (meta == NULL) { g_warning ("No layout meta found for the child of type '%s' " "inside the layout manager of type '%s'", G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (manager)); return; } g_assert (CLUTTER_IS_TABLE_CHILD (meta)); if (x_expand) *x_expand = CLUTTER_TABLE_CHILD (meta)->x_expand; if (y_expand) *y_expand = CLUTTER_TABLE_CHILD (meta)->y_expand; } /** * clutter_table_layout_set_use_animations: * @layout: a #ClutterTableLayout * @animate: %TRUE if the @layout should use animations * * Sets whether @layout should animate changes in the layout properties * * The duration of the animations is controlled by * clutter_table_layout_set_easing_duration(); the easing mode to be used * by the animations is controlled by clutter_table_layout_set_easing_mode() * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them. See clutter_actor_set_easing_mode() * and clutter_actor_set_easing_duration(). */ void clutter_table_layout_set_use_animations (ClutterTableLayout *layout, gboolean animate) { ClutterTableLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); priv = layout->priv; animate = !!animate; if (priv->use_animations != animate) { priv->use_animations = animate; g_object_notify (G_OBJECT (layout), "use-animations"); } } /** * clutter_table_layout_get_use_animations: * @layout: a #ClutterTableLayout * * Retrieves whether @layout should animate changes in the layout properties * * Since clutter_table_layout_set_use_animations() * * Return value: %TRUE if the animations should be used, %FALSE otherwise * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them. See clutter_actor_set_easing_mode() * and clutter_actor_set_easing_duration(). */ gboolean clutter_table_layout_get_use_animations (ClutterTableLayout *layout) { g_return_val_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout), FALSE); return layout->priv->use_animations; } /** * clutter_table_layout_set_easing_mode: * @layout: a #ClutterTableLayout * @mode: an easing mode, either from #ClutterAnimationMode or a logical id * from clutter_alpha_register_func() * * Sets the easing mode to be used by @layout when animating changes in layout * properties * * Use clutter_table_layout_set_use_animations() to enable and disable the * animations * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them. See clutter_actor_set_easing_mode() * and clutter_actor_set_easing_duration(). */ void clutter_table_layout_set_easing_mode (ClutterTableLayout *layout, gulong mode) { ClutterTableLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); priv = layout->priv; if (priv->easing_mode != mode) { priv->easing_mode = mode; g_object_notify (G_OBJECT (layout), "easing-mode"); } } /** * clutter_table_layout_get_easing_mode: * @layout: a #ClutterTableLayout * * Retrieves the easing mode set using clutter_table_layout_set_easing_mode() * * Return value: an easing mode * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them. See clutter_actor_set_easing_mode() * and clutter_actor_set_easing_duration(). */ gulong clutter_table_layout_get_easing_mode (ClutterTableLayout *layout) { g_return_val_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout), CLUTTER_EASE_OUT_CUBIC); return layout->priv->easing_mode; } /** * clutter_table_layout_set_easing_duration: * @layout: a #ClutterTableLayout * @msecs: the duration of the animations, in milliseconds * * Sets the duration of the animations used by @layout when animating changes * in the layout properties * * Use clutter_table_layout_set_use_animations() to enable and disable the * animations * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them. See clutter_actor_set_easing_mode() * and clutter_actor_set_easing_duration(). */ void clutter_table_layout_set_easing_duration (ClutterTableLayout *layout, guint msecs) { ClutterTableLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout)); priv = layout->priv; if (priv->easing_duration != msecs) { priv->easing_duration = msecs; g_object_notify (G_OBJECT (layout), "easing-duration"); } } /** * clutter_table_layout_get_easing_duration: * @layout: a #ClutterTableLayout * * Retrieves the duration set using clutter_table_layout_set_easing_duration() * * Return value: the duration of the animations, in milliseconds * * Since: 1.4 * * Deprecated: 1.12: #ClutterTableLayout will honour the easing state * of the children when allocating them. See clutter_actor_set_easing_mode() * and clutter_actor_set_easing_duration(). */ guint clutter_table_layout_get_easing_duration (ClutterTableLayout *layout) { g_return_val_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout), 500); return layout->priv->easing_duration; } /** * clutter_table_layout_get_row_count: * @layout: A #ClutterTableLayout * * Retrieve the current number rows in the @layout * * Returns: the number of rows * * Since: 1.4 * * Deprecated: 1.18: No direct replacement is available */ gint clutter_table_layout_get_row_count (ClutterTableLayout *layout) { g_return_val_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout), -1); update_row_col (layout, layout->priv->container); return CLUTTER_TABLE_LAYOUT (layout)->priv->n_rows; } /** * clutter_table_layout_get_column_count: * @layout: A #ClutterTableLayout * * Retrieve the current number of columns in @layout * * Returns: the number of columns * * Since: 1.4 * * Deprecated: 1.18: No direct replacement is available */ gint clutter_table_layout_get_column_count (ClutterTableLayout *layout) { g_return_val_if_fail (CLUTTER_IS_TABLE_LAYOUT (layout), -1); update_row_col (layout, layout->priv->container); return CLUTTER_TABLE_LAYOUT (layout)->priv->n_cols; } muffin-5.2.1/clutter/clutter/deprecated/clutter-frame-source.h0000664000175000017500000000271614211404421024627 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2008 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_FRAME_SOURCE_H__ #define __CLUTTER_FRAME_SOURCE_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_6 guint clutter_frame_source_add (guint fps, GSourceFunc func, gpointer data); CLUTTER_DEPRECATED_IN_1_6 guint clutter_frame_source_add_full (gint priority, guint fps, GSourceFunc func, gpointer data, GDestroyNotify notify); G_END_DECLS #endif /* __CLUTTER_FRAME_SOURCE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-timeout-pool.h0000664000175000017500000000435514211404421024675 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * ClutterTimeoutPool: pool of timeout functions using the same slice of * the GLib main loop * * Author: Emmanuele Bassi * * Based on similar code by Tristan van Berkom */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_TIMEOUT_POOL_H__ #define __CLUTTER_TIMEOUT_POOL_H__ #include G_BEGIN_DECLS /** * ClutterTimeoutPool: (skip) * * #ClutterTimeoutPool is an opaque structure * whose members cannot be directly accessed. * * Since: 0.6 * * Deprecated: 1.6 */ typedef struct _ClutterTimeoutPool ClutterTimeoutPool; CLUTTER_DEPRECATED_IN_1_6 ClutterTimeoutPool *clutter_timeout_pool_new (gint priority); CLUTTER_DEPRECATED_IN_1_6 guint clutter_timeout_pool_add (ClutterTimeoutPool *pool, guint fps, GSourceFunc func, gpointer data, GDestroyNotify notify); CLUTTER_DEPRECATED_IN_1_6 void clutter_timeout_pool_remove (ClutterTimeoutPool *pool, guint id_); G_END_DECLS #endif /* __CLUTTER_TIMEOUT_POOL_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-scale.h0000664000175000017500000001057514211404421025312 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BEHAVIOUR_SCALE_H__ #define __CLUTTER_BEHAVIOUR_SCALE_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_BEHAVIOUR_SCALE (clutter_behaviour_scale_get_type ()) #define CLUTTER_BEHAVIOUR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BEHAVIOUR_SCALE, ClutterBehaviourScale)) #define CLUTTER_BEHAVIOUR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BEHAVIOUR_SCALE, ClutterBehaviourScaleClass)) #define CLUTTER_IS_BEHAVIOUR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BEHAVIOUR_SCALE)) #define CLUTTER_IS_BEHAVIOUR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BEHAVIOUR_SCALE)) #define CLUTTER_BEHAVIOUR_SCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BEHAVIOUR_SCALE, ClutterBehaviourScaleClass)) typedef struct _ClutterBehaviourScale ClutterBehaviourScale; typedef struct _ClutterBehaviourScalePrivate ClutterBehaviourScalePrivate; typedef struct _ClutterBehaviourScaleClass ClutterBehaviourScaleClass; /** * ClutterBehaviourScale: * * The #ClutterBehaviourScale struct contains only private data and * should be accessed using the provided API * * Since: 0.2 * * Deprecated: 1.6: Use clutter_actor_animate() with #ClutterActor:scale-x * and #ClutterActor:scale-y instead. */ struct _ClutterBehaviourScale { /*< private >*/ ClutterBehaviour parent_instance; ClutterBehaviourScalePrivate *priv; }; /** * ClutterBehaviourScaleClass: * * The #ClutterBehaviourScaleClass struct contains only private data * * Since: 0.2 * * Deprecated: 1.6 */ struct _ClutterBehaviourScaleClass { /*< private >*/ ClutterBehaviourClass parent_class; }; CLUTTER_DEPRECATED_IN_1_6 GType clutter_behaviour_scale_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_6_FOR(clutter_actor_animate with ClutterActor:scale-x and ClutterActor:scale-y) ClutterBehaviour *clutter_behaviour_scale_new (ClutterAlpha *alpha, gdouble x_scale_start, gdouble y_scale_start, gdouble x_scale_end, gdouble y_scale_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_scale_set_bounds (ClutterBehaviourScale *scale, gdouble x_scale_start, gdouble y_scale_start, gdouble x_scale_end, gdouble y_scale_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_scale_get_bounds (ClutterBehaviourScale *scale, gdouble *x_scale_start, gdouble *y_scale_start, gdouble *x_scale_end, gdouble *y_scale_end); G_END_DECLS #endif /* __CLUTTER_BEHAVIOUR_SCALE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-box.h0000664000175000017500000001355414211404421023031 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009,2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BOX_H__ #define __CLUTTER_BOX_H__ #include #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_BOX (clutter_box_get_type ()) #define CLUTTER_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX, ClutterBox)) #define CLUTTER_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX)) #define CLUTTER_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BOX, ClutterBoxClass)) #define CLUTTER_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BOX)) #define CLUTTER_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BOX, ClutterBoxClass)) typedef struct _ClutterBox ClutterBox; typedef struct _ClutterBoxPrivate ClutterBoxPrivate; typedef struct _ClutterBoxClass ClutterBoxClass; /** * ClutterBox: * * The #ClutterBox structure contains only private data and should * be accessed using the provided API * * Since: 1.2 */ struct _ClutterBox { /*< private >*/ ClutterActor parent_instance; ClutterBoxPrivate *priv; }; /** * ClutterBoxClass: * * The #ClutterBoxClass structure contains only private data * * Since: 1.2 */ struct _ClutterBoxClass { /*< private >*/ ClutterActorClass parent_class; /* padding, for future expansion */ void (*clutter_padding_1) (void); void (*clutter_padding_2) (void); void (*clutter_padding_3) (void); void (*clutter_padding_4) (void); void (*clutter_padding_5) (void); void (*clutter_padding_6) (void); }; CLUTTER_DEPRECATED_IN_1_10 GType clutter_box_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_new) ClutterActor * clutter_box_new (ClutterLayoutManager *manager); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_layout_manager) void clutter_box_set_layout_manager (ClutterBox *box, ClutterLayoutManager *manager); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_layout_manager) ClutterLayoutManager *clutter_box_get_layout_manager (ClutterBox *box); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_background_color) void clutter_box_set_color (ClutterBox *box, const ClutterColor *color); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_background_color) void clutter_box_get_color (ClutterBox *box, ClutterColor *color); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_add_child) void clutter_box_pack (ClutterBox *box, ClutterActor *actor, const gchar *first_property, ...); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_add_child) void clutter_box_packv (ClutterBox *box, ClutterActor *actor, guint n_properties, const gchar * const properties[], const GValue *values); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_insert_child_above) void clutter_box_pack_after (ClutterBox *box, ClutterActor *actor, ClutterActor *sibling, const gchar *first_property, ...); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_insert_child_below) void clutter_box_pack_before (ClutterBox *box, ClutterActor *actor, ClutterActor *sibling, const gchar *first_property, ...); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_insert_child_at_index) void clutter_box_pack_at (ClutterBox *box, ClutterActor *actor, gint position, const gchar *first_property, ...); G_END_DECLS #endif /* __CLUTTER_BOX_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-group.h0000664000175000017500000000443714211404421023375 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_GROUP_DEPRECATED_H__ #define __CLUTTER_GROUP_DEPRECATED_H__ #include #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_new) ClutterActor * clutter_group_new (void); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_child_at_index) ClutterActor * clutter_group_get_nth_child (ClutterGroup *self, gint index_); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_n_children) gint clutter_group_get_n_children (ClutterGroup *self); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_remove_all_children) void clutter_group_remove_all (ClutterGroup *self); #ifndef CLUTTER_DISABLE_DEPRECATED /* for Mr. Mallum only */ #define clutter_group_add(group,actor) G_STMT_START { \ ClutterActor *_actor = (ClutterActor *) (actor); \ if (CLUTTER_IS_GROUP ((group)) && CLUTTER_IS_ACTOR ((_actor))) \ { \ ClutterContainer *_container = (ClutterContainer *) (group); \ clutter_container_add_actor (_container, _actor); \ } } G_STMT_END #endif /* CLUTTER_DISABLE_DEPRECATED */ G_END_DECLS #endif /* __CLUTTER_GROUP_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-opacity.h0000664000175000017500000000743214211404421025671 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BEHAVIOUR_OPACITY_H__ #define __CLUTTER_BEHAVIOUR_OPACITY_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_BEHAVIOUR_OPACITY (clutter_behaviour_opacity_get_type ()) #define CLUTTER_BEHAVIOUR_OPACITY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ CLUTTER_TYPE_BEHAVIOUR_OPACITY, ClutterBehaviourOpacity)) #define CLUTTER_BEHAVIOUR_OPACITY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ CLUTTER_TYPE_BEHAVIOUR_OPACITY, ClutterBehaviourOpacityClass)) #define CLUTTER_IS_BEHAVIOUR_OPACITY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ CLUTTER_TYPE_BEHAVIOUR_OPACITY)) #define CLUTTER_IS_BEHAVIOUR_OPACITY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ CLUTTER_TYPE_BEHAVIOUR_OPACITY)) #define CLUTTER_BEHAVIOUR_OPACITY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ CLUTTER_TYPE_BEHAVIOUR_OPACITY, ClutterBehaviourOpacityClass)) typedef struct _ClutterBehaviourOpacity ClutterBehaviourOpacity; typedef struct _ClutterBehaviourOpacityPrivate ClutterBehaviourOpacityPrivate; typedef struct _ClutterBehaviourOpacityClass ClutterBehaviourOpacityClass; /** * ClutterBehaviourOpacity: * * The #ClutterBehaviourOpacity structure contains only private data and * should be accessed using the provided API * * Since: 0.2 * * Deprecated: 1.6: Use clutter_actor_animate() and #ClutterActor:opacity * instead. */ struct _ClutterBehaviourOpacity { /*< private >*/ ClutterBehaviour parent; ClutterBehaviourOpacityPrivate *priv; }; /** * ClutterBehaviourOpacityClass: * * The #ClutterBehaviourOpacityClass structure contains only private data * * Since: 0.2 * * Deprecated: 1.6 */ struct _ClutterBehaviourOpacityClass { /*< private >*/ ClutterBehaviourClass parent_class; }; CLUTTER_DEPRECATED_IN_1_6 GType clutter_behaviour_opacity_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_6_FOR(clutter_actor_animate and ClutterActor:opacity) ClutterBehaviour *clutter_behaviour_opacity_new (ClutterAlpha *alpha, guint8 opacity_start, guint8 opacity_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_opacity_set_bounds (ClutterBehaviourOpacity *behaviour, guint8 opacity_start, guint8 opacity_end); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_opacity_get_bounds (ClutterBehaviourOpacity *behaviour, guint8 *opacity_start, guint8 *opacity_end); G_END_DECLS #endif /* __CLUTTER_BEHAVIOUR_OPACITY_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-actor-deprecated.c0000664000175000017500000002543614211404421025444 0ustar jpeisachjpeisach#ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-actor.h" #include "clutter-actor-private.h" #include "clutter-private.h" #include "clutter-shader.h" typedef struct _ShaderData ShaderData; struct _ShaderData { ClutterShader *shader; /* back pointer to the actor */ ClutterActor *actor; /* list of values that should be set on the shader * before each paint cycle */ GHashTable *value_hash; }; static void shader_value_free (gpointer data) { GValue *var = data; g_value_unset (var); g_slice_free (GValue, var); } static void destroy_shader_data (gpointer data) { ShaderData *shader_data = data; if (shader_data == NULL) return; if (shader_data->shader != NULL) { g_object_unref (shader_data->shader); shader_data->shader = NULL; } if (shader_data->value_hash != NULL) { g_hash_table_destroy (shader_data->value_hash); shader_data->value_hash = NULL; } g_slice_free (ShaderData, shader_data); } /** * clutter_actor_get_shader: * @self: a #ClutterActor * * Queries the currently set #ClutterShader on @self. * * Return value: (transfer none): The currently set #ClutterShader * or %NULL if no shader is set. * * Since: 0.6 * * Deprecated: 1.8: Use clutter_actor_get_effect() instead. */ ClutterShader * clutter_actor_get_shader (ClutterActor *self) { ShaderData *shader_data; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); shader_data = g_object_get_data (G_OBJECT (self), "-clutter-actor-shader-data"); if (shader_data != NULL) return shader_data->shader; return NULL; } /** * clutter_actor_set_shader: * @self: a #ClutterActor * @shader: (allow-none): a #ClutterShader or %NULL to unset the shader. * * Sets the #ClutterShader to be used when rendering @self. * * If @shader is %NULL this function will unset any currently set shader * for the actor. * * Any #ClutterEffect applied to @self will take the precedence * over the #ClutterShader set using this function. * * Return value: %TRUE if the shader was successfully applied * or removed * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect and * clutter_actor_add_effect() instead. */ gboolean clutter_actor_set_shader (ClutterActor *self, ClutterShader *shader) { ShaderData *shader_data; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); g_return_val_if_fail (shader == NULL || CLUTTER_IS_SHADER (shader), FALSE); if (shader != NULL) g_object_ref (shader); else { /* if shader passed in is NULL we destroy the shader */ g_object_set_data (G_OBJECT (self), "-clutter-actor-shader-data", NULL); return TRUE; } shader_data = g_object_get_data (G_OBJECT (self), "-clutter-actor-shader-data"); if (shader_data == NULL) { shader_data = g_slice_new (ShaderData); shader_data->actor = self; shader_data->shader = NULL; shader_data->value_hash = g_hash_table_new_full (g_str_hash, g_str_equal, free, shader_value_free); g_object_set_data_full (G_OBJECT (self), "-clutter-actor-shader-data", shader_data, destroy_shader_data); } if (shader_data->shader != NULL) g_object_unref (shader_data->shader); shader_data->shader = shader; clutter_actor_queue_redraw (self); return TRUE; } static void set_each_param (gpointer key, gpointer value, gpointer user_data) { ClutterShader *shader = user_data; const gchar *uniform = key; GValue *var = value; clutter_shader_set_uniform (shader, uniform, var); } void _clutter_actor_shader_pre_paint (ClutterActor *actor, gboolean repeat) { ShaderData *shader_data; ClutterShader *shader; shader_data = g_object_get_data (G_OBJECT (actor), "-clutter-actor-shader-data"); if (shader_data == NULL) return; shader = shader_data->shader; if (shader != NULL) { clutter_shader_set_is_enabled (shader, TRUE); g_hash_table_foreach (shader_data->value_hash, set_each_param, shader); if (!repeat) _clutter_context_push_shader_stack (actor); } } void _clutter_actor_shader_post_paint (ClutterActor *actor) { ShaderData *shader_data; ClutterShader *shader; shader_data = g_object_get_data (G_OBJECT (actor), "-clutter-actor-shader-data"); if (G_LIKELY (shader_data == NULL)) return; shader = shader_data->shader; if (shader != NULL) { ClutterActor *head; clutter_shader_set_is_enabled (shader, FALSE); /* remove the actor from the shaders stack; if there is another * actor inside it, then call pre-paint again to set its shader * but this time with the second argument being TRUE, indicating * that we are re-applying an existing shader and thus should it * not be prepended to the stack */ head = _clutter_context_pop_shader_stack (actor); if (head != NULL) _clutter_actor_shader_pre_paint (head, TRUE); } } static inline void clutter_actor_set_shader_param_internal (ClutterActor *self, const gchar *param, const GValue *value) { ShaderData *shader_data; GValue *var; shader_data = g_object_get_data (G_OBJECT (self), "-clutter-actor-shader-data"); if (shader_data == NULL) return; var = g_slice_new0 (GValue); g_value_init (var, G_VALUE_TYPE (value)); g_value_copy (value, var); g_hash_table_insert (shader_data->value_hash, g_strdup (param), var); clutter_actor_queue_redraw (self); } /** * clutter_actor_set_shader_param: * @self: a #ClutterActor * @param: the name of the parameter * @value: the value of the parameter * * Sets the value for a named parameter of the shader applied * to @actor. * * Since: 1.0 * * Deprecated: 1.8: Use clutter_shader_effect_set_uniform_value() instead */ void clutter_actor_set_shader_param (ClutterActor *self, const gchar *param, const GValue *value) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (param != NULL); g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value) || CLUTTER_VALUE_HOLDS_SHADER_INT (value) || CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value) || G_VALUE_HOLDS_FLOAT (value) || G_VALUE_HOLDS_INT (value)); clutter_actor_set_shader_param_internal (self, param, value); } /** * clutter_actor_set_shader_param_float: * @self: a #ClutterActor * @param: the name of the parameter * @value: the value of the parameter * * Sets the value for a named float parameter of the shader applied * to @actor. * * Since: 0.8 * * Deprecated: 1.8: Use clutter_shader_effect_set_uniform() instead */ void clutter_actor_set_shader_param_float (ClutterActor *self, const gchar *param, gfloat value) { GValue var = { 0, }; g_value_init (&var, G_TYPE_FLOAT); g_value_set_float (&var, value); clutter_actor_set_shader_param_internal (self, param, &var); g_value_unset (&var); } /** * clutter_actor_set_shader_param_int: * @self: a #ClutterActor * @param: the name of the parameter * @value: the value of the parameter * * Sets the value for a named int parameter of the shader applied to * @actor. * * Since: 0.8 * * Deprecated: 1.8: Use clutter_shader_effect_set_uniform() instead */ void clutter_actor_set_shader_param_int (ClutterActor *self, const gchar *param, gint value) { GValue var = { 0, }; g_value_init (&var, G_TYPE_INT); g_value_set_int (&var, value); clutter_actor_set_shader_param_internal (self, param, &var); g_value_unset (&var); } /** * clutter_actor_set_geometry: * @self: A #ClutterActor * @geometry: A #ClutterGeometry * * Sets the actor's fixed position and forces its minimum and natural * size, in pixels. This means the untransformed actor will have the * given geometry. This is the same as calling clutter_actor_set_position() * and clutter_actor_set_size(). * * Deprecated: 1.10: Use clutter_actor_set_position() and * clutter_actor_set_size() instead. */ void clutter_actor_set_geometry (ClutterActor *self, const ClutterGeometry *geometry) { g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_position (self, geometry->x, geometry->y); clutter_actor_set_size (self, geometry->width, geometry->height); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_get_geometry: * @self: A #ClutterActor * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry * * Gets the size and position of an actor relative to its parent * actor. This is the same as calling clutter_actor_get_position() and * clutter_actor_get_size(). It tries to "do what you mean" and get the * requested size and position if the actor's allocation is invalid. * * Deprecated: 1.10: Use clutter_actor_get_position() and * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry() * instead. */ void clutter_actor_get_geometry (ClutterActor *self, ClutterGeometry *geometry) { gfloat x, y, width, height; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (geometry != NULL); clutter_actor_get_position (self, &x, &y); clutter_actor_get_size (self, &width, &height); geometry->x = (int) x; geometry->y = (int) y; geometry->width = (int) width; geometry->height = (int) height; } /** * clutter_actor_get_allocation_geometry: * @self: A #ClutterActor * @geom: (out): allocation geometry in pixels * * Gets the layout box an actor has been assigned. The allocation can * only be assumed valid inside a paint() method; anywhere else, it * may be out-of-date. * * An allocation does not incorporate the actor's scale or anchor point; * those transformations do not affect layout, only rendering. * * The returned rectangle is in pixels. * * Since: 0.8 * * Deprecated: 1.12: Use clutter_actor_get_allocation_box() instead. */ void clutter_actor_get_allocation_geometry (ClutterActor *self, ClutterGeometry *geom) { ClutterActorBox box; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (geom != NULL); clutter_actor_get_allocation_box (self, &box); geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box)); geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box)); geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box)); geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box)); } muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-path.h0000664000175000017500000001063714211404421025156 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_BEHAVIOUR_PATH_H__ #define __CLUTTER_BEHAVIOUR_PATH_H__ #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_BEHAVIOUR_PATH (clutter_behaviour_path_get_type ()) #define CLUTTER_BEHAVIOUR_PATH(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ CLUTTER_TYPE_BEHAVIOUR_PATH, ClutterBehaviourPath)) #define CLUTTER_BEHAVIOUR_PATH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ CLUTTER_TYPE_BEHAVIOUR_PATH, ClutterBehaviourPathClass)) #define CLUTTER_IS_BEHAVIOUR_PATH(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ CLUTTER_TYPE_BEHAVIOUR_PATH)) #define CLUTTER_IS_BEHAVIOUR_PATH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ CLUTTER_TYPE_BEHAVIOUR_PATH)) #define CLUTTER_BEHAVIOUR_PATH_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ CLUTTER_TYPE_BEHAVIOUR_PATH, ClutterBehaviourPathClass)) typedef struct _ClutterBehaviourPath ClutterBehaviourPath; typedef struct _ClutterBehaviourPathPrivate ClutterBehaviourPathPrivate; typedef struct _ClutterBehaviourPathClass ClutterBehaviourPathClass; /** * ClutterBehaviourPath: * * The #ClutterBehaviourPath structure contains only private data * and should be accessed using the provided API * * Since: 0.2 * * Deprecated: 1.6: Use #ClutterPathConstraint and clutter_actor_animate() * instead. */ struct _ClutterBehaviourPath { /*< private >*/ ClutterBehaviour parent; ClutterBehaviourPathPrivate *priv; }; /** * ClutterBehaviourPathClass: * @knot_reached: signal class handler for the * ClutterBehaviourPath::knot_reached signal * * The #ClutterBehaviourPathClass struct contains only private data * * Since: 0.2 * * Deprecated: 1.6 */ struct _ClutterBehaviourPathClass { /*< private >*/ ClutterBehaviourClass parent_class; /*< public >*/ void (*knot_reached) (ClutterBehaviourPath *pathb, guint knot_num); /*< private >*/ void (*_clutter_path_1) (void); void (*_clutter_path_2) (void); void (*_clutter_path_3) (void); void (*_clutter_path_4) (void); }; CLUTTER_DEPRECATED_IN_1_6 GType clutter_behaviour_path_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_6_FOR(clutter_actor_animate) ClutterBehaviour *clutter_behaviour_path_new (ClutterAlpha *alpha, ClutterPath *path); CLUTTER_DEPRECATED_IN_1_6_FOR(clutter_actor_animate) ClutterBehaviour *clutter_behaviour_path_new_with_description (ClutterAlpha *alpha, const gchar *desc); CLUTTER_DEPRECATED_IN_1_6_FOR(clutter_actor_animate) ClutterBehaviour *clutter_behaviour_path_new_with_knots (ClutterAlpha *alpha, const ClutterKnot *knots, guint n_knots); CLUTTER_DEPRECATED_IN_1_6 void clutter_behaviour_path_set_path (ClutterBehaviourPath *pathb, ClutterPath *path); CLUTTER_DEPRECATED_IN_1_6 ClutterPath * clutter_behaviour_path_get_path (ClutterBehaviourPath *pathb); G_END_DECLS #endif /* __CLUTTER_BEHAVIOUR_PATH_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-texture.h0000664000175000017500000002156414211404421023741 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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.1 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_TEXTURE_DEPRECATED_H__ #define __CLUTTER_TEXTURE_DEPRECATED_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_image_new) ClutterActor * clutter_texture_new (void); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and platform-specific image loading) ClutterActor * clutter_texture_new_from_file (const gchar *filename, GError **error); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and platform-specific image loading) gboolean clutter_texture_set_from_file (ClutterTexture *texture, const gchar *filename, GError **error); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_image_set_data) gboolean clutter_texture_set_from_rgb_data (ClutterTexture *texture, const guchar *data, gboolean has_alpha, gint width, gint height, gint rowstride, gint bpp, ClutterTextureFlags flags, GError **error); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_image_set_area) gboolean clutter_texture_set_area_from_rgb_data (ClutterTexture *texture, const guchar *data, gboolean has_alpha, gint x, gint y, gint width, gint height, gint rowstride, gint bpp, ClutterTextureFlags flags, GError **error); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and clutter_content_get_preferred_size) void clutter_texture_get_base_size (ClutterTexture *texture, gint *width, gint *height); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and clutter_actor_set_content_scaling_filters) void clutter_texture_set_filter_quality (ClutterTexture *texture, ClutterTextureQuality filter_quality); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and clutter_actor_get_content_scaling_filters) ClutterTextureQuality clutter_texture_get_filter_quality (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12 CoglHandle clutter_texture_get_cogl_texture (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12 void clutter_texture_set_cogl_texture (ClutterTexture *texture, CoglHandle cogl_tex); CLUTTER_DEPRECATED_IN_1_12 CoglHandle clutter_texture_get_cogl_material (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12 void clutter_texture_set_cogl_material (ClutterTexture *texture, CoglHandle cogl_material); CLUTTER_DEPRECATED_IN_1_12 void clutter_texture_set_sync_size (ClutterTexture *texture, gboolean sync_size); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_texture_get_sync_size (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and clutter_actor_set_content_repeat) void clutter_texture_set_repeat (ClutterTexture *texture, gboolean repeat_x, gboolean repeat_y); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and clutter_actor_get_content_repeat) void clutter_texture_get_repeat (ClutterTexture *texture, gboolean *repeat_x, gboolean *repeat_y); CLUTTER_DEPRECATED_IN_1_12 gint clutter_texture_get_max_tile_waste (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and clutter_actor_set_content_gravity) void clutter_texture_set_keep_aspect_ratio (ClutterTexture *texture, gboolean keep_aspect); CLUTTER_DEPRECATED_IN_1_12_FOR(ClutterImage and clutter_actor_get_content_gravity) gboolean clutter_texture_get_keep_aspect_ratio (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12 void clutter_texture_set_load_async (ClutterTexture *texture, gboolean load_async); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_texture_get_load_async (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12 void clutter_texture_set_load_data_async (ClutterTexture *texture, gboolean load_async); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_texture_get_load_data_async (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_12 void clutter_texture_set_pick_with_alpha (ClutterTexture *texture, gboolean pick_with_alpha); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_texture_get_pick_with_alpha (ClutterTexture *texture); CLUTTER_DEPRECATED_IN_1_8_FOR(ClutterOffscreenEffect) ClutterActor * clutter_texture_new_from_actor (ClutterActor *actor); CLUTTER_DEPRECATED_IN_1_10 gboolean clutter_texture_set_from_yuv_data (ClutterTexture *texture, const guchar *data, gint width, gint height, ClutterTextureFlags flags, GError **error); G_END_DECLS #endif /* __CLUTTER_TEXTURE_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-stage-manager.h0000664000175000017500000000254114211404421024746 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 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, see . * * Author: Emmanuele Bassi */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_STAGE_MANAGER_DEPRECATED_H__ #define __CLUTTER_STAGE_MANAGER_DEPRECATED_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_2 void clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manager, ClutterStage *stage); G_END_DECLS #endif /*__CLUTTER_STAGE_MANAGER_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-stage.h0000664000175000017500000000734414211404421023344 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_STAGE_DEPRECATED_H__ #define __CLUTTER_STAGE_DEPRECATED_H__ #include G_BEGIN_DECLS #ifndef CLUTTER_DISABLE_DEPRECATED /** * CLUTTER_STAGE_WIDTH: * * Macro that evaluates to the width of the default stage * * Since: 0.2 * * Deprecated: 1.2: Use clutter_actor_get_width() instead */ #define CLUTTER_STAGE_WIDTH() (clutter_actor_get_width (clutter_stage_get_default ())) /** * CLUTTER_STAGE_HEIGHT: * * Macro that evaluates to the height of the default stage * * Since: 0.2 * * Deprecated: 1.2: use clutter_actor_get_height() instead */ #define CLUTTER_STAGE_HEIGHT() (clutter_actor_get_height (clutter_stage_get_default ())) /* Commodity macro, for mallum only */ #define clutter_stage_add(stage,actor) G_STMT_START { \ if (CLUTTER_IS_STAGE ((stage)) && CLUTTER_IS_ACTOR ((actor))) \ { \ ClutterContainer *_container = (ClutterContainer *) (stage); \ ClutterActor *_actor = (ClutterActor *) (actor); \ clutter_container_add_actor (_container, _actor); \ } } G_STMT_END #endif /* CLUTTER_DISABLE_DEPRECATED */ CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_stage_new) ClutterActor * clutter_stage_get_default (void); CLUTTER_DEPRECATED_IN_1_10 gboolean clutter_stage_is_default (ClutterStage *stage); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_queue_redraw) void clutter_stage_queue_redraw (ClutterStage *stage); CLUTTER_DEPRECATED_IN_1_10 void clutter_stage_set_use_fog (ClutterStage *stage, gboolean fog); CLUTTER_DEPRECATED_IN_1_10 gboolean clutter_stage_get_use_fog (ClutterStage *stage); CLUTTER_DEPRECATED_IN_1_10 void clutter_stage_set_fog (ClutterStage *stage, ClutterFog *fog); CLUTTER_DEPRECATED_IN_1_10 void clutter_stage_get_fog (ClutterStage *stage, ClutterFog *fog); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_set_background_color) void clutter_stage_set_color (ClutterStage *stage, const ClutterColor *color); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_background_color) void clutter_stage_get_color (ClutterStage *stage, ClutterColor *color); CLUTTER_DEPRECATED_IN_MUFFIN void clutter_stage_ensure_current (ClutterStage *stage); G_END_DECLS #endif /* __CLUTTER_STAGE_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-opacity.c0000664000175000017500000002153414211404421025663 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ /** * SECTION:clutter-behaviour-opacity * @Title: ClutterBehaviourOpacity * @short_description: A behaviour controlling opacity * @Deprecated: 1.6: Use clutter_actor_animate() instead. * * #ClutterBehaviourOpacity controls the opacity of a set of actors. * * Since: 0.2 * * Deprecated: 1.6: Use the #ClutterActor:opacity property and * clutter_actor_animate(), or #ClutterAnimator, or #ClutterState * instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-alpha.h" #include "clutter-behaviour.h" #include "clutter-behaviour-opacity.h" #include "clutter-private.h" #include "clutter-debug.h" struct _ClutterBehaviourOpacityPrivate { guint8 opacity_start; guint8 opacity_end; }; enum { PROP_0, PROP_OPACITY_START, PROP_OPACITY_END, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE (ClutterBehaviourOpacity, clutter_behaviour_opacity, CLUTTER_TYPE_BEHAVIOUR) static void alpha_notify_foreach (ClutterBehaviour *behaviour, ClutterActor *actor, gpointer data) { clutter_actor_set_opacity (actor, GPOINTER_TO_UINT(data)); } static void clutter_behaviour_alpha_notify (ClutterBehaviour *behave, gdouble alpha_value) { ClutterBehaviourOpacityPrivate *priv; guint8 opacity; priv = CLUTTER_BEHAVIOUR_OPACITY (behave)->priv; opacity = alpha_value * (priv->opacity_end - priv->opacity_start) + priv->opacity_start; CLUTTER_NOTE (ANIMATION, "alpha: %.4f, opacity: %u", alpha_value, opacity); clutter_behaviour_actors_foreach (behave, alpha_notify_foreach, GUINT_TO_POINTER ((guint) opacity)); } static void clutter_behaviour_opacity_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBehaviourOpacity *self = CLUTTER_BEHAVIOUR_OPACITY (gobject); switch (prop_id) { case PROP_OPACITY_START: clutter_behaviour_opacity_set_bounds (self, g_value_get_uint (value), self->priv->opacity_end); break; case PROP_OPACITY_END: clutter_behaviour_opacity_set_bounds (self, self->priv->opacity_start, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_opacity_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBehaviourOpacity *self = CLUTTER_BEHAVIOUR_OPACITY (gobject); switch (prop_id) { case PROP_OPACITY_START: g_value_set_uint (value, self->priv->opacity_start); break; case PROP_OPACITY_END: g_value_set_uint (value, self->priv->opacity_end); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_opacity_class_init (ClutterBehaviourOpacityClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = clutter_behaviour_opacity_set_property; gobject_class->get_property = clutter_behaviour_opacity_get_property; /** * ClutterBehaviourOpacity:opacity-start: * * Initial opacity level of the behaviour. * * Since: 0.2 * * Deprecated: 1.6 */ pspec = g_param_spec_uint ("opacity-start", P_("Opacity Start"), P_("Initial opacity level"), 0, 255, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_OPACITY_START] = pspec; g_object_class_install_property (gobject_class, PROP_OPACITY_START, pspec); /** * ClutterBehaviourOpacity:opacity-end: * * Final opacity level of the behaviour. * * Since: 0.2 * * Deprecated: 1.6 */ pspec = g_param_spec_uint ("opacity-end", P_("Opacity End"), P_("Final opacity level"), 0, 255, 0, CLUTTER_PARAM_READWRITE); obj_props[PROP_OPACITY_END] = pspec; g_object_class_install_property (gobject_class, PROP_OPACITY_END, pspec); behave_class->alpha_notify = clutter_behaviour_alpha_notify; } static void clutter_behaviour_opacity_init (ClutterBehaviourOpacity *self) { self->priv = clutter_behaviour_opacity_get_instance_private (self); } /** * clutter_behaviour_opacity_new: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @opacity_start: minimum level of opacity * @opacity_end: maximum level of opacity * * Creates a new #ClutterBehaviourOpacity object, driven by @alpha * which controls the opacity property of every actor, making it * change in the interval between @opacity_start and @opacity_end. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: the newly created #ClutterBehaviourOpacity * * Since: 0.2 * * Deprecated: 1.6 */ ClutterBehaviour * clutter_behaviour_opacity_new (ClutterAlpha *alpha, guint8 opacity_start, guint8 opacity_end) { return g_object_new (CLUTTER_TYPE_BEHAVIOUR_OPACITY, "alpha", alpha, "opacity-start", opacity_start, "opacity-end", opacity_end, NULL); } /** * clutter_behaviour_opacity_set_bounds: * @behaviour: a #ClutterBehaviourOpacity * @opacity_start: minimum level of opacity * @opacity_end: maximum level of opacity * * Sets the initial and final levels of the opacity applied by @behaviour * on each actor it controls. * * Since: 0.6 * * Deprecated: 1.6 */ void clutter_behaviour_opacity_set_bounds (ClutterBehaviourOpacity *behaviour, guint8 opacity_start, guint8 opacity_end) { ClutterBehaviourOpacityPrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_OPACITY (behaviour)); priv = behaviour->priv; g_object_freeze_notify (G_OBJECT (behaviour)); if (priv->opacity_start != opacity_start) { priv->opacity_start = opacity_start; g_object_notify_by_pspec (G_OBJECT (behaviour), obj_props[PROP_OPACITY_START]); } if (priv->opacity_end != opacity_end) { priv->opacity_end = opacity_end; g_object_notify_by_pspec (G_OBJECT (behaviour), obj_props[PROP_OPACITY_END]); } g_object_thaw_notify (G_OBJECT (behaviour)); } /** * clutter_behaviour_opacity_get_bounds: * @behaviour: a #ClutterBehaviourOpacity * @opacity_start: (out): return location for the minimum level of opacity, or %NULL * @opacity_end: (out): return location for the maximum level of opacity, or %NULL * * Gets the initial and final levels of the opacity applied by @behaviour * on each actor it controls. * * Since: 0.6 * * Deprecated: 1.6 */ void clutter_behaviour_opacity_get_bounds (ClutterBehaviourOpacity *behaviour, guint8 *opacity_start, guint8 *opacity_end) { g_return_if_fail (CLUTTER_IS_BEHAVIOUR_OPACITY (behaviour)); if (opacity_start) *opacity_start = behaviour->priv->opacity_start; if (opacity_end) *opacity_end = behaviour->priv->opacity_end; } muffin-5.2.1/clutter/clutter/deprecated/clutter-animator.c0000664000175000017500000020153214211404421024041 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation * * 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, see . * * Author: * Øyvind Kolås */ /** * SECTION:clutter-animator * @short_description: Multi-actor tweener * @See_Also: #ClutterAnimatable, #ClutterInterval, #ClutterAlpha, * #ClutterTimeline * * #ClutterAnimator is an object providing declarative animations for * #GObject properties belonging to one or more #GObjects to * #ClutterIntervals. * * #ClutterAnimator is used to build and describe complex animations * in terms of "key frames". #ClutterAnimator is meant to be used * through the #ClutterScript definition format, but it comes with a * convenience C API. * * #ClutterAnimator is available since Clutter 1.2 * * #ClutterAnimator has been deprecated in Clutter 1.12. If you * want to combine multiple transitions using key frames, use * #ClutterKeyframeTransition and #ClutterTransitionGroup instead. * * ## Key Frames * * Every animation handled by a #ClutterAnimator can be * described in terms of "key frames". For each #GObject property * there can be multiple key frames, each one defined by the end * value for the property to be computed starting from the current * value to a specific point in time, using a given easing * mode. * * The point in time is defined using a value representing * the progress in the normalized interval of [ 0, 1 ]. This maps * the value returned by clutter_timeline_get_duration(). * * ## ClutterAnimator description for ClutterScript * * #ClutterAnimator defines a custom "properties" key * which allows describing the key frames for objects as * an array of key frames. * * The `properties` array has the following syntax: * * |[ * { * "properties" : [ * { * "object" : object_id * "name" : property_name * "ease-in" : true_or_false * "interpolation" : interpolation_value * "keys" : [ * [ progress, easing_mode, final_value ] * ] * ] * } * ]| * * The following JSON fragment defines a #ClutterAnimator * with the duration of 1 second and operating on the x and y * properties of a #ClutterActor named "rect-01", with two frames * for each property. The first frame will linearly move the actor * from its current position to the 100, 100 position in 20 percent * of the duration of the animation; the second will using a cubic * easing to move the actor to the 200, 200 coordinates. * * |[ * { * "type" : "ClutterAnimator", * "duration" : 1000, * "properties" : [ * { * "object" : "rect-01", * "name" : "x", * "ease-in" : true, * "keys" : [ * [ 0.2, "linear", 100.0 ], * [ 1.0, "easeOutCubic", 200.0 ] * ] * }, * { * "object" : "rect-01", * "name" : "y", * "ease-in" : true, * "keys" : [ * [ 0.2, "linear", 100.0 ], * [ 1.0, "easeOutCubic", 200.0 ] * ] * } * ] * } * ]| */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-animator.h" #include "clutter-alpha.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-interval.h" #include "clutter-private.h" #include "clutter-script-private.h" #include "clutter-scriptable.h" /* progress values varying by less than this are considered equal */ #define PROGRESS_EPSILON 0.00001 struct _ClutterAnimatorPrivate { ClutterTimeline *timeline; ClutterTimeline *slave_timeline; GList *score; GHashTable *properties; }; struct _ClutterAnimatorKey { GObject *object; const gchar *property_name; guint mode; GValue value; /* normalized progress, between 0.0 and 1.0 */ gdouble progress; /* back-pointer to the animator which owns the key */ ClutterAnimator *animator; /* interpolation mode */ ClutterInterpolation interpolation; /* ease from the current object state into the animation when it starts */ guint ease_in : 1; /* This key is already being destroyed and shouldn't * trigger additional weak unrefs */ guint is_inert : 1; gint ref_count; }; enum { PROP_0, PROP_DURATION, PROP_TIMELINE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; static void clutter_scriptable_init (ClutterScriptableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterAnimator, clutter_animator, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterAnimator) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_init)); /** * clutter_animator_new: * * Creates a new #ClutterAnimator instance * * Return value: a new #ClutterAnimator. * * Since: 1.2 * * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ ClutterAnimator * clutter_animator_new (void) { return g_object_new (CLUTTER_TYPE_ANIMATOR, NULL); } /***/ typedef struct _PropObjectKey { GObject *object; const gchar *property_name; guint mode; gdouble progress; } PropObjectKey; /* Iterator that walks the keys of a property*/ typedef struct _PropertyIter { PropObjectKey *key; ClutterInterval *interval; ClutterAlpha *alpha; GList *current; gdouble start; /* the progress of current */ gdouble end; /* until which progress it is valid */ ClutterInterpolation interpolation; guint ease_in : 1; } PropertyIter; static PropObjectKey * prop_actor_key_new (GObject *object, const gchar *property_name) { PropObjectKey *key = g_slice_new0 (PropObjectKey); key->object = object; key->property_name = g_intern_string (property_name); return key; } static void prop_actor_key_free (gpointer key) { if (key != NULL) g_slice_free (PropObjectKey, key); } static void property_iter_free (gpointer key) { if (key != NULL) { PropertyIter *property_iter = key; g_object_unref (property_iter->interval); g_object_unref (property_iter->alpha); g_slice_free (PropertyIter, property_iter); } } static PropertyIter * property_iter_new (ClutterAnimator *animator, PropObjectKey *key, GType type) { ClutterAnimatorPrivate *priv = animator->priv; PropertyIter *property_iter = g_slice_new (PropertyIter); ClutterInterval *interval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", type, NULL); /* we own this interval */ g_object_ref_sink (interval); property_iter->interval = interval; property_iter->key = key; property_iter->alpha = clutter_alpha_new (); clutter_alpha_set_timeline (property_iter->alpha, priv->slave_timeline); /* as well as the alpha */ g_object_ref_sink (property_iter->alpha); return property_iter; } static guint prop_actor_hash (gconstpointer value) { const PropObjectKey *info = value; return GPOINTER_TO_INT (info->property_name) ^ GPOINTER_TO_INT (info->object); } static gboolean prop_actor_equal (gconstpointer a, gconstpointer b) { const PropObjectKey *infoa = a; const PropObjectKey *infob = b; /* property name strings are interned so we can just compare pointers */ if (infoa->object == infob->object && (infoa->property_name == infob->property_name)) return TRUE; return FALSE; } static gint sort_actor_prop_progress_func (gconstpointer a, gconstpointer b) { const ClutterAnimatorKey *pa = a; const ClutterAnimatorKey *pb = b; if (pa->object == pb->object) { gint pdiff = pb->property_name - pa->property_name; if (pdiff) return pdiff; if (fabs (pa->progress - pb->progress) < PROGRESS_EPSILON) return 0; if (pa->progress > pb->progress) return 1; return -1; } return pa->object - pb->object; } static gint sort_actor_prop_func (gconstpointer a, gconstpointer b) { const ClutterAnimatorKey *pa = a; const ClutterAnimatorKey *pb = b; if (pa->object == pb->object) return pa->property_name - pb->property_name; return pa->object - pb->object; } static void clutter_animator_remove_key_internal (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress, gboolean is_inert); static void object_disappeared (gpointer data, GObject *where_the_object_was) { clutter_animator_remove_key_internal (data, where_the_object_was, NULL, -1.0, TRUE); } static ClutterAnimatorKey * clutter_animator_key_new (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress, guint mode) { ClutterAnimatorKey *animator_key; animator_key = g_slice_new (ClutterAnimatorKey); animator_key->ref_count = 1; animator_key->animator = animator; animator_key->object = object; animator_key->mode = mode; memset (&(animator_key->value), 0, sizeof (GValue)); animator_key->progress = progress; animator_key->property_name = g_intern_string (property_name); animator_key->interpolation = CLUTTER_INTERPOLATION_LINEAR; animator_key->ease_in = FALSE; animator_key->is_inert = FALSE; /* keep a weak reference on the animator, so that we can release the * back-pointer when needed */ g_object_weak_ref (object, object_disappeared, animator_key->animator); return animator_key; } static gpointer clutter_animator_key_copy (gpointer boxed) { ClutterAnimatorKey *key = boxed; if (key != NULL) key->ref_count += 1; return key; } static void clutter_animator_key_free (gpointer boxed) { ClutterAnimatorKey *key = boxed; if (key == NULL) return; key->ref_count -= 1; if (key->ref_count > 0) return; if (!key->is_inert) g_object_weak_unref (key->object, object_disappeared, key->animator); g_slice_free (ClutterAnimatorKey, key); } static void clutter_animator_dispose (GObject *object) { ClutterAnimator *animator = CLUTTER_ANIMATOR (object); ClutterAnimatorPrivate *priv = animator->priv; clutter_animator_set_timeline (animator, NULL); g_object_unref (priv->slave_timeline); G_OBJECT_CLASS (clutter_animator_parent_class)->dispose (object); } static void clutter_animator_finalize (GObject *object) { ClutterAnimator *animator = CLUTTER_ANIMATOR (object); ClutterAnimatorPrivate *priv = animator->priv; g_list_foreach (priv->score, (GFunc) clutter_animator_key_free, NULL); g_list_free (priv->score); priv->score = NULL; g_hash_table_destroy (priv->properties); G_OBJECT_CLASS (clutter_animator_parent_class)->finalize (object); } /* XXX: this is copied and slightly modified from glib, * there is only one way to do this. */ static GList * list_find_custom_reverse (GList *list, gconstpointer data, GCompareFunc func) { while (list) { if (! func (list->data, data)) return list; list = list->prev; } return NULL; } /* Ensures that the interval provided by the animator is correct * for the requested progress value. */ static void animation_animator_ensure_animator (ClutterAnimator *animator, PropertyIter *property_iter, PropObjectKey *key, gdouble progress) { if (progress > property_iter->end) { while (progress > property_iter->end) { ClutterAnimatorKey *initial_key, *next_key; GList *initial, *next; initial = g_list_find_custom (property_iter->current->next, key, sort_actor_prop_func); if (initial) { initial_key = initial->data; clutter_interval_set_initial_value (property_iter->interval, &initial_key->value); property_iter->current = initial; property_iter->start = initial_key->progress; next = g_list_find_custom (initial->next, key, sort_actor_prop_func); if (next) { next_key = next->data; property_iter->end = next_key->progress; } else { next_key = initial_key; property_iter->end = property_iter->start; } clutter_interval_set_final_value (property_iter->interval, &next_key->value); if ((clutter_alpha_get_mode (property_iter->alpha) != next_key->mode)) clutter_alpha_set_mode (property_iter->alpha, next_key->mode); } else /* no relevant interval */ { ClutterAnimatorKey *current_key = property_iter->current->data; clutter_interval_set_initial_value (property_iter->interval, ¤t_key->value); clutter_interval_set_final_value (property_iter->interval, ¤t_key->value); break; } } } else if (progress < property_iter->start) { while (progress < property_iter->start) { ClutterAnimatorKey *initial_key, *next_key; GList *initial; GList *old = property_iter->current; initial = list_find_custom_reverse (property_iter->current->prev, key, sort_actor_prop_func); if (initial) { initial_key = initial->data; clutter_interval_set_initial_value (property_iter->interval, &initial_key->value); property_iter->current = initial; property_iter->end = property_iter->start; property_iter->start = initial_key->progress; if (old) { next_key = old->data; property_iter->end = next_key->progress; } else { next_key = initial_key; property_iter->end = 1.0; } clutter_interval_set_final_value (property_iter->interval, &next_key->value); if ((clutter_alpha_get_mode (property_iter->alpha) != next_key->mode)) clutter_alpha_set_mode (property_iter->alpha, next_key->mode); } else break; } } } /* XXX - this might be useful as an internal function exposed somewhere */ static gdouble cubic_interpolation (const gdouble dx, const gdouble prev, const gdouble j, const gdouble next, const gdouble nextnext) { return (((( - prev + 3 * j - 3 * next + nextnext ) * dx + ( 2 * prev - 5 * j + 4 * next - nextnext ) ) * dx + ( - prev + next ) ) * dx + (j + j) ) / 2.0; } /* try to get a floating point key value from a key for a property, * failing use the closest key in that direction or the starting point. */ static gfloat list_try_get_rel (GList *list, gint count) { ClutterAnimatorKey *key; GList *iter = list; GList *best = list; if (count > 0) { while (count -- && iter != NULL) { iter = g_list_find_custom (iter->next, list->data, sort_actor_prop_func); if (iter != NULL) best = iter; } } else { while (count ++ < 0 && iter != NULL) { iter = list_find_custom_reverse (iter->prev, list->data, sort_actor_prop_func); if (iter != NULL) best = iter; } } if (best != NULL && best->data != NULL) { key = best->data; return g_value_get_float (&(key->value)); } return 0; } static void animation_animator_new_frame (ClutterTimeline *timeline, gint msecs, ClutterAnimator *animator) { gdouble progress; GHashTableIter iter; gpointer key, value; progress = 1.0 * msecs / clutter_timeline_get_duration (timeline); /* for each property that is managed figure out the GValue to set, * avoid creating new ClutterInterval's for each interval crossed */ g_hash_table_iter_init (&iter, animator->priv->properties); key = value = NULL; while (g_hash_table_iter_next (&iter, &key, &value)) { PropObjectKey *prop_actor_key = key; PropertyIter *property_iter = value; ClutterAnimatorKey *start_key; gdouble sub_progress; animation_animator_ensure_animator (animator, property_iter, key, progress); start_key = property_iter->current->data; if (property_iter->end == property_iter->start) sub_progress = 0.0; /* we're past the final value */ else sub_progress = (progress - property_iter->start) / (property_iter->end - property_iter->start); /* only change values if we active (delayed start) */ if (sub_progress >= 0.0 && sub_progress <= 1.0) { GValue tmp_value = G_VALUE_INIT; GType int_type; g_value_init (&tmp_value, G_VALUE_TYPE (&start_key->value)); clutter_timeline_advance (animator->priv->slave_timeline, sub_progress * 10000); sub_progress = clutter_alpha_get_alpha (property_iter->alpha); int_type = clutter_interval_get_value_type (property_iter->interval); if (property_iter->interpolation == CLUTTER_INTERPOLATION_CUBIC && int_type == G_TYPE_FLOAT) { gdouble prev, current, next, nextnext; gdouble res; if ((property_iter->ease_in == FALSE || (property_iter->ease_in && list_find_custom_reverse (property_iter->current->prev, property_iter->current->data, sort_actor_prop_func)))) { current = g_value_get_float (&start_key->value); prev = list_try_get_rel (property_iter->current, -1); } else { /* interpolated and easing in */ clutter_interval_get_initial_value (property_iter->interval, &tmp_value); prev = current = g_value_get_float (&tmp_value); } next = list_try_get_rel (property_iter->current, 1); nextnext = list_try_get_rel (property_iter->current, 2); res = cubic_interpolation (sub_progress, prev, current, next, nextnext); g_value_set_float (&tmp_value, res); } else clutter_interval_compute_value (property_iter->interval, sub_progress, &tmp_value); g_object_set_property (prop_actor_key->object, prop_actor_key->property_name, &tmp_value); g_value_unset (&tmp_value); } } } static void animation_animator_started (ClutterTimeline *timeline, ClutterAnimator *animator) { GList *k; /* Ensure that animators exist for all involved properties */ for (k = animator->priv->score; k != NULL; k = k->next) { ClutterAnimatorKey *key = k->data; PropertyIter *property_iter; PropObjectKey *prop_actor_key; prop_actor_key = prop_actor_key_new (key->object, key->property_name); property_iter = g_hash_table_lookup (animator->priv->properties, prop_actor_key); if (property_iter) { prop_actor_key_free (prop_actor_key); } else { GObjectClass *klass = G_OBJECT_GET_CLASS (key->object); GParamSpec *pspec; pspec = g_object_class_find_property (klass, key->property_name); property_iter = property_iter_new (animator, prop_actor_key, G_PARAM_SPEC_VALUE_TYPE (pspec)); g_hash_table_insert (animator->priv->properties, prop_actor_key, property_iter); } } /* initialize animator with initial list pointers */ { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, animator->priv->properties); while (g_hash_table_iter_next (&iter, &key, &value)) { PropertyIter *property_iter = value; ClutterAnimatorKey *initial_key, *next_key; GList *initial; GList *next; initial = g_list_find_custom (animator->priv->score, key, sort_actor_prop_func); g_assert (initial != NULL); initial_key = initial->data; clutter_interval_set_initial_value (property_iter->interval, &initial_key->value); property_iter->current = initial; property_iter->start = initial_key->progress; property_iter->ease_in = initial_key->ease_in; property_iter->interpolation = initial_key->interpolation; if (property_iter->ease_in) { GValue tmp_value = G_VALUE_INIT; GType int_type; int_type = clutter_interval_get_value_type (property_iter->interval); g_value_init (&tmp_value, int_type); g_object_get_property (initial_key->object, initial_key->property_name, &tmp_value); clutter_interval_set_initial_value (property_iter->interval, &tmp_value); g_value_unset (&tmp_value); } next = g_list_find_custom (initial->next, key, sort_actor_prop_func); if (next) { next_key = next->data; property_iter->end = next_key->progress; } else { next_key = initial_key; property_iter->end = 1.0; } clutter_interval_set_final_value (property_iter->interval, &next_key->value); if ((clutter_alpha_get_mode (property_iter->alpha) != next_key->mode)) clutter_alpha_set_mode (property_iter->alpha, next_key->mode); } } } /** * clutter_animator_compute_value: * @animator: a #ClutterAnimator * @object: a #GObject * @property_name: the name of the property on object to check * @progress: a value between 0.0 and 1.0 * @value: an initialized value to store the computed result * * Compute the value for a managed property at a given progress. * * If the property is an ease-in property, the current value of the property * on the object will be used as the starting point for computation. * * Return value: %TRUE if the computation yields has a value, otherwise (when * an error occurs or the progress is before any of the keys) %FALSE is * returned and the #GValue is left untouched * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ gboolean clutter_animator_compute_value (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress, GValue *value) { ClutterAnimatorPrivate *priv; ClutterAnimatorKey key; ClutterAnimatorKey *previous; ClutterAnimatorKey *next = NULL; GParamSpec *pspec; GList *initial_l; GList *previous_l; GList *next_l; gboolean ease_in; ClutterInterpolation interpolation; g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), FALSE); g_return_val_if_fail (G_IS_OBJECT (object), FALSE); g_return_val_if_fail (property_name, FALSE); g_return_val_if_fail (value, FALSE); priv = animator->priv; ease_in = clutter_animator_property_get_ease_in (animator, object, property_name); interpolation = clutter_animator_property_get_interpolation (animator, object, property_name); property_name = g_intern_string (property_name); pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name); key.object = object; key.property_name = property_name; initial_l = g_list_find_custom (animator->priv->score, &key, sort_actor_prop_func); if (initial_l == NULL) return FALSE; /* first find the interval we belong in, that is the first interval * existing between keys */ for (previous_l = initial_l, next_l = previous_l->next ; previous_l->next ; previous_l = previous_l->next, next_l = previous_l->next) { previous = previous_l->data; if (next_l) { next = next_l->data; if (next->object != object || next->property_name != property_name) { next_l = NULL; next = NULL; } } else next = NULL; if (progress < previous->progress) { /* we are before the defined values */ /* value has not been set */ return FALSE; } if (!next && previous->progress <= progress) { /* we only had one key for this object/property */ /* and we are past it, that is our value */ g_value_copy (&previous->value, value); return TRUE; } if (next && next->progress >= progress) { ClutterInterval *interval; ClutterAlpha *alpha; gdouble sub_progress = (progress - previous->progress) / (next->progress - previous->progress); /* this should be our interval */ interval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", pspec->value_type, NULL); if (ease_in && previous_l == initial_l) { GValue tmp_value = {0, }; g_value_init (&tmp_value, pspec->value_type); g_object_get_property (object, property_name, &tmp_value); clutter_interval_set_initial_value (interval, &tmp_value); g_value_unset (&tmp_value); } else clutter_interval_set_initial_value (interval, &previous->value); clutter_interval_set_final_value (interval, &next->value); alpha = clutter_alpha_new (); clutter_alpha_set_timeline (alpha, priv->slave_timeline); clutter_alpha_set_mode (alpha, next->mode); clutter_timeline_advance (priv->slave_timeline, sub_progress * 10000); sub_progress = clutter_alpha_get_alpha (alpha); if (interpolation == CLUTTER_INTERPOLATION_CUBIC && pspec->value_type == G_TYPE_FLOAT) { gdouble prev, current, nextv, nextnext; gdouble res; if ((ease_in == FALSE || (ease_in && list_find_custom_reverse (previous_l->prev, previous_l->data, sort_actor_prop_func)))) { current = g_value_get_float (&previous->value); prev = list_try_get_rel (previous_l, -1); } else { /* interpolated and easing in */ GValue tmp_value = {0, }; g_value_init (&tmp_value, pspec->value_type); clutter_interval_get_initial_value (interval, &tmp_value); prev = current = g_value_get_float (&tmp_value); g_value_unset (&tmp_value); } nextv = list_try_get_rel (previous_l, 1); nextnext = list_try_get_rel (previous_l, 2); res = cubic_interpolation (sub_progress, prev, current, nextv, nextnext); g_value_set_float (value, res); } else clutter_interval_compute_value (interval, sub_progress, value); g_object_ref_sink (interval); g_object_unref (interval); g_object_ref_sink (alpha); g_object_unref (alpha); return TRUE; } } if (!next) return FALSE; /* We're at, or past the end, use the last value */ g_value_copy (&next->value, value); return TRUE; } /** * clutter_animator_set_timeline: * @animator: a #ClutterAnimator * @timeline: a #ClutterTimeline * * Sets an external timeline that will be used for driving the animation * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ void clutter_animator_set_timeline (ClutterAnimator *animator, ClutterTimeline *timeline) { ClutterAnimatorPrivate *priv; g_return_if_fail (CLUTTER_IS_ANIMATOR (animator)); priv = animator->priv; if (priv->timeline != NULL) { g_signal_handlers_disconnect_by_func (priv->timeline, animation_animator_new_frame, animator); g_signal_handlers_disconnect_by_func (priv->timeline, animation_animator_started, animator); g_object_unref (priv->timeline); } priv->timeline = timeline; if (timeline != NULL) { g_object_ref (priv->timeline); g_signal_connect (priv->timeline, "new-frame", G_CALLBACK (animation_animator_new_frame), animator); g_signal_connect (priv->timeline, "started", G_CALLBACK (animation_animator_started), animator); } } /** * clutter_animator_get_timeline: * @animator: a #ClutterAnimator * * Get the timeline hooked up for driving the #ClutterAnimator * * Return value: (transfer none): the #ClutterTimeline that drives the animator * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ ClutterTimeline * clutter_animator_get_timeline (ClutterAnimator *animator) { g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL); return animator->priv->timeline; } /** * clutter_animator_start: * @animator: a #ClutterAnimator * * Start the ClutterAnimator, this is a thin wrapper that rewinds * and starts the animators current timeline. * * Return value: (transfer none): the #ClutterTimeline that drives * the animator. The returned timeline is owned by the #ClutterAnimator * and it should not be unreferenced * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ ClutterTimeline * clutter_animator_start (ClutterAnimator *animator) { ClutterAnimatorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL); priv = animator->priv; clutter_timeline_rewind (priv->timeline); clutter_timeline_start (priv->timeline); return priv->timeline; } /** * clutter_animator_set_duration: * @animator: a #ClutterAnimator * @duration: milliseconds a run of the animator should last. * * Runs the timeline of the #ClutterAnimator with a duration in msecs * as specified. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ void clutter_animator_set_duration (ClutterAnimator *animator, guint duration) { g_return_if_fail (CLUTTER_IS_ANIMATOR (animator)); clutter_timeline_set_duration (animator->priv->timeline, duration); } /** * clutter_animator_get_duration: * @animator: a #ClutterAnimator * * Retrieves the current duration of an animator * * Return value: the duration of the animation, in milliseconds * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ guint clutter_animator_get_duration (ClutterAnimator *animator) { g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), 0); return clutter_timeline_get_duration (animator->priv->timeline); } /** * clutter_animator_set: * @animator: a #ClutterAnimator * @first_object: a #GObject * @first_property_name: the property to specify a key for * @first_mode: the id of the alpha function to use * @first_progress: at which stage of the animation this value applies; the * range is a normalized floating point value between 0 and 1 * @...: the value first_property_name should have for first_object * at first_progress, followed by more (object, property_name, mode, * progress, value) tuples, followed by %NULL * * Adds multiple keys to a #ClutterAnimator, specifying the value a given * property should have at a given progress of the animation. The mode * specified is the mode used when going to this key from the previous key of * the @property_name * * If a given (object, property, progress) tuple already exist the mode and * value will be replaced with the new values. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ void clutter_animator_set (ClutterAnimator *animator, gpointer first_object, const gchar *first_property_name, guint first_mode, gdouble first_progress, ...) { GObject *object; const gchar *property_name; guint mode; gdouble progress; va_list args; g_return_if_fail (CLUTTER_IS_ANIMATOR (animator)); object = first_object; property_name = first_property_name; g_return_if_fail (object); g_return_if_fail (property_name); mode = first_mode; progress = first_progress; va_start (args, first_progress); while (object != NULL) { GParamSpec *pspec; GObjectClass *klass; GValue value = G_VALUE_INIT; gchar *error = NULL; klass = G_OBJECT_GET_CLASS (object); pspec = g_object_class_find_property (klass, property_name); if (!pspec) { g_warning ("Cannot bind property '%s': object of type '%s' " "do not have this property", property_name, G_OBJECT_TYPE_NAME (object)); break; } G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec), args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); break; } clutter_animator_set_key (animator, object, property_name, mode, progress, &value); object= va_arg (args, GObject *); if (object) { property_name = va_arg (args, gchar*); if (!property_name) { g_warning ("%s: expected a property name", G_STRLOC); break; } mode = va_arg (args, guint); progress = va_arg (args, gdouble); } } va_end (args); } static inline void clutter_animator_set_key_internal (ClutterAnimator *animator, ClutterAnimatorKey *key) { ClutterAnimatorPrivate *priv = animator->priv; GList *old_item; GList *initial_item; ClutterAnimatorKey *initial_key = NULL; if ((initial_item = g_list_find_custom (animator->priv->score, key, sort_actor_prop_func))) initial_key = initial_item->data; /* The first key for a property specifies ease-in and interpolation, * if we are replacing; or becoming a new first key we should * inherit the old flags. */ if (initial_key && initial_key->progress >= key->progress) { key->interpolation = initial_key->interpolation; key->ease_in = initial_key->ease_in; } old_item = g_list_find_custom (priv->score, key, sort_actor_prop_progress_func); /* replace the key if we already have a similar one */ if (old_item != NULL) { ClutterAnimatorKey *old_key = old_item->data; clutter_animator_key_free (old_key); priv->score = g_list_remove (priv->score, old_key); } priv->score = g_list_insert_sorted (priv->score, key, sort_actor_prop_progress_func); /* if the animator is already running reinitialize internal iterators */ if (clutter_timeline_is_playing (priv->timeline)) animation_animator_started (priv->timeline, animator); } /** * clutter_animator_set_key: * @animator: a #ClutterAnimator * @object: a #GObject * @property_name: the property to specify a key for * @mode: the id of the alpha function to use * @progress: the normalized range at which stage of the animation this * value applies * @value: the value property_name should have at progress. * * Sets a single key in the #ClutterAnimator for the @property_name of * @object at @progress. * * See also: clutter_animator_set() * * Return value: (transfer none): The animator instance * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ ClutterAnimator * clutter_animator_set_key (ClutterAnimator *animator, GObject *object, const gchar *property_name, guint mode, gdouble progress, const GValue *value) { ClutterAnimatorKey *animator_key; g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL); g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (property_name, NULL); g_return_val_if_fail (value, NULL); property_name = g_intern_string (property_name); animator_key = clutter_animator_key_new (animator, object, property_name, progress, mode); g_value_init (&animator_key->value, G_VALUE_TYPE (value)); g_value_copy (value, &animator_key->value); clutter_animator_set_key_internal (animator, animator_key); return animator; } /** * clutter_animator_get_keys: * @animator: a #ClutterAnimator instance * @object: (allow-none): a #GObject to search for, or %NULL for all objects * @property_name: (allow-none): a specific property name to query for, * or %NULL for all properties * @progress: a specific progress to search for, or a negative value for all * progresses * * Returns a list of pointers to opaque structures with accessor functions * that describe the keys added to an animator. * * Return value: (transfer container) (element-type Clutter.AnimatorKey): a * list of #ClutterAnimatorKeys; the contents of the list are owned * by the #ClutterAnimator, but you should free the returned list when done, * using g_list_free() * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ GList * clutter_animator_get_keys (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress) { GList *keys = NULL; GList *k; g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL); g_return_val_if_fail (object == NULL || G_IS_OBJECT (object), NULL); property_name = g_intern_string (property_name); for (k = animator->priv->score; k; k = k->next) { ClutterAnimatorKey *key = k->data; if ((object == NULL || (object == key->object)) && (property_name == NULL || (property_name == key->property_name)) && (progress < 0 || fabs (progress - key->progress) < PROGRESS_EPSILON)) { keys = g_list_prepend (keys, key); } } return g_list_reverse (keys); } static void clutter_animator_remove_key_internal (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress, gboolean is_inert) { ClutterAnimatorPrivate *priv; GList *k; g_return_if_fail (CLUTTER_IS_ANIMATOR (animator)); g_return_if_fail (object == NULL || G_IS_OBJECT (object)); property_name = g_intern_string (property_name); priv = animator->priv; again: for (k = priv->score; k != NULL; k = k->next) { ClutterAnimatorKey *key = k->data; if ((object == NULL || (object == key->object)) && (property_name == NULL || ((property_name == key->property_name))) && (progress < 0 || fabs (progress - key->progress) < PROGRESS_EPSILON) ) { ClutterAnimatorKey *prev_key = NULL; key->is_inert = is_inert; /* FIXME: non performant since we reiterate the list many times */ prev_key = k->prev ? k->prev->data : NULL; if (!prev_key || prev_key->object != key->object || prev_key->property_name != key->property_name) { /* We are removing the first key for a property ... */ ClutterAnimatorKey *next_key = k->next ? k->next->data : NULL; if (next_key && next_key->object == key->object && next_key->property_name == key->property_name) { /* ... and there is a key of our own type following us, * copy interpolation/ease_in flags to the new first key */ next_key->interpolation = key->interpolation; next_key->ease_in = key->ease_in; } } clutter_animator_key_free (key); priv->score = g_list_remove (priv->score, key); goto again; } } /* clear off cached state for all properties, this is regenerated in a * correct state by animation_animator_started */ g_hash_table_remove_all (priv->properties); /* if the animator is already running reinitialize internal iterators */ if (priv->timeline != NULL && clutter_timeline_is_playing (priv->timeline)) animation_animator_started (priv->timeline, animator); } /** * clutter_animator_remove_key: * @animator: a #ClutterAnimator * @object: (allow-none): a #GObject to search for, or %NULL for all * @property_name: (allow-none): a specific property name to query for, * or %NULL for all * @progress: a specific progress to search for or a negative value * for all * * Removes all keys matching the conditions specificed in the arguments. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ void clutter_animator_remove_key (ClutterAnimator *animator, GObject *object, const gchar *property_name, gdouble progress) { clutter_animator_remove_key_internal (animator, object, property_name, progress, FALSE); } typedef struct _ParseClosure { ClutterAnimator *animator; ClutterScript *script; GValue *value; gboolean result; } ParseClosure; static ClutterInterpolation resolve_interpolation (JsonNode *node) { if ((JSON_NODE_TYPE (node) != JSON_NODE_VALUE)) return CLUTTER_INTERPOLATION_LINEAR; if (json_node_get_value_type (node) == G_TYPE_INT64) { return json_node_get_int (node); } else if (json_node_get_value_type (node) == G_TYPE_STRING) { const gchar *str = json_node_get_string (node); gboolean res; gint enum_value; res = _clutter_script_enum_from_string (CLUTTER_TYPE_INTERPOLATION, str, &enum_value); if (res) return enum_value; } return CLUTTER_INTERPOLATION_LINEAR; } static void parse_animator_property (JsonArray *array, guint index_, JsonNode *element, gpointer data) { ParseClosure *clos = data; JsonObject *object; JsonArray *keys; GObject *gobject; const gchar *id_, *pname; GObjectClass *klass; GParamSpec *pspec; GSList *valid_keys = NULL; GList *array_keys, *k; ClutterInterpolation interpolation = CLUTTER_INTERPOLATION_LINEAR; gboolean ease_in = FALSE; if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT) { g_warning ("The 'properties' member of a ClutterAnimator description " "should be an array of objects, but the element %d of the " "array is of type '%s'. The element will be ignored.", index_, json_node_type_name (element)); return; } object = json_node_get_object (element); if (!json_object_has_member (object, "object") || !json_object_has_member (object, "name") || !json_object_has_member (object, "keys")) { g_warning ("The property description at index %d is missing one of " "the mandatory fields: object, name and keys", index_); return; } id_ = json_object_get_string_member (object, "object"); gobject = clutter_script_get_object (clos->script, id_); if (gobject == NULL) { g_warning ("No object with id '%s' has been defined.", id_); return; } pname = json_object_get_string_member (object, "name"); klass = G_OBJECT_GET_CLASS (gobject); pspec = g_object_class_find_property (klass, pname); if (pspec == NULL) { g_warning ("The object of type '%s' and name '%s' has no " "property named '%s'", G_OBJECT_TYPE_NAME (gobject), id_, pname); return; } if (json_object_has_member (object, "ease-in")) ease_in = json_object_get_boolean_member (object, "ease-in"); if (json_object_has_member (object, "interpolation")) { JsonNode *node = json_object_get_member (object, "interpolation"); interpolation = resolve_interpolation (node); } keys = json_object_get_array_member (object, "keys"); if (keys == NULL) { g_warning ("The property description at index %d has an invalid " "key field of type '%s' when an array was expected.", index_, json_node_type_name (json_object_get_member (object, "keys"))); return; } if (G_IS_VALUE (clos->value)) valid_keys = g_slist_reverse (g_value_get_pointer (clos->value)); else g_value_init (clos->value, G_TYPE_POINTER); array_keys = json_array_get_elements (keys); for (k = array_keys; k != NULL; k = k->next) { JsonNode *node = k->data; JsonArray *key = json_node_get_array (node); ClutterAnimatorKey *animator_key; gdouble progress; gulong mode; gboolean res; progress = json_array_get_double_element (key, 0); mode = _clutter_script_resolve_animation_mode (json_array_get_element (key, 1)); animator_key = clutter_animator_key_new (clos->animator, gobject, pname, progress, mode); res = _clutter_script_parse_node (clos->script, &(animator_key->value), pname, json_array_get_element (key, 2), pspec); if (!res) { g_warning ("Unable to parse the key value for the " "property '%s' (progress: %.2f) at index %d", pname, progress, index_); continue; } animator_key->ease_in = ease_in; animator_key->interpolation = interpolation; valid_keys = g_slist_prepend (valid_keys, animator_key); } g_list_free (array_keys); g_value_set_pointer (clos->value, g_slist_reverse (valid_keys)); clos->result = TRUE; } static gboolean clutter_animator_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { ParseClosure parse_closure; if (strcmp (name, "properties") != 0) return FALSE; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) return FALSE; parse_closure.animator = CLUTTER_ANIMATOR (scriptable); parse_closure.script = script; parse_closure.value = value; parse_closure.result = FALSE; json_array_foreach_element (json_node_get_array (node), parse_animator_property, &parse_closure); /* we return TRUE if we had at least one key parsed */ return parse_closure.result; } static void clutter_animator_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { if (strcmp (name, "properties") == 0) { ClutterAnimator *animator = CLUTTER_ANIMATOR (scriptable); GSList *keys = g_value_get_pointer (value); GSList *k; for (k = keys; k != NULL; k = k->next) clutter_animator_set_key_internal (animator, k->data); g_slist_free (keys); } else g_object_set_property (G_OBJECT (scriptable), name, value); } static void clutter_scriptable_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_animator_parse_custom_node; iface->set_custom_property = clutter_animator_set_custom_property; } static void clutter_animator_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterAnimator *self = CLUTTER_ANIMATOR (gobject); switch (prop_id) { case PROP_DURATION: clutter_animator_set_duration (self, g_value_get_uint (value)); break; case PROP_TIMELINE: clutter_animator_set_timeline (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_animator_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterAnimatorPrivate *priv = CLUTTER_ANIMATOR (gobject)->priv; switch (prop_id) { case PROP_DURATION: g_value_set_uint (value, clutter_timeline_get_duration (priv->timeline)); break; case PROP_TIMELINE: g_value_set_object (value, priv->timeline); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_animator_class_init (ClutterAnimatorClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_animator_set_property; gobject_class->get_property = clutter_animator_get_property; gobject_class->dispose = clutter_animator_dispose; gobject_class->finalize = clutter_animator_finalize; /** * ClutterAnimator:duration: * * The duration of the #ClutterTimeline used by the #ClutterAnimator * to drive the animation * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ obj_props[PROP_DURATION] = g_param_spec_uint ("duration", P_("Duration"), P_("The duration of the animation"), 0, G_MAXUINT, 2000, CLUTTER_PARAM_READWRITE); /** * ClutterAnimator:timeline: * * The #ClutterTimeline used by the #ClutterAnimator to drive the * animation * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ obj_props[PROP_TIMELINE] = g_param_spec_object ("timeline", P_("Timeline"), P_("The timeline of the animation"), CLUTTER_TYPE_TIMELINE, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_animator_init (ClutterAnimator *animator) { ClutterAnimatorPrivate *priv; ClutterTimeline *timeline; animator->priv = priv = clutter_animator_get_instance_private (animator); priv->properties = g_hash_table_new_full (prop_actor_hash, prop_actor_equal, prop_actor_key_free, property_iter_free); timeline = clutter_timeline_new (2000); clutter_animator_set_timeline (animator, timeline); g_object_unref (timeline); priv->slave_timeline = clutter_timeline_new (10000); } /** * clutter_animator_property_get_ease_in: * @animator: a #ClutterAnimatorKey * @object: a #GObject * @property_name: the name of a property on object * * Checks if a property value is to be eased into the animation. * * Return value: %TRUE if the property is eased in * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ gboolean clutter_animator_property_get_ease_in (ClutterAnimator *animator, GObject *object, const gchar *property_name) { ClutterAnimatorKey key, *initial_key; GList *initial; g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), FALSE); g_return_val_if_fail (G_IS_OBJECT (object), FALSE); g_return_val_if_fail (property_name, FALSE); key.object = object; key.property_name = g_intern_string (property_name); initial = g_list_find_custom (animator->priv->score, &key, sort_actor_prop_func); if (initial != NULL) { initial_key = initial->data; return initial_key->ease_in; } return FALSE; } /** * clutter_animator_property_set_ease_in: * @animator: a #ClutterAnimatorKey * @object: a #GObject * @property_name: the name of a property on object * @ease_in: we are going to be easing in this property * * Sets whether a property value is to be eased into the animation. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ void clutter_animator_property_set_ease_in (ClutterAnimator *animator, GObject *object, const gchar *property_name, gboolean ease_in) { ClutterAnimatorKey key, *initial_key; GList *initial; g_return_if_fail (CLUTTER_IS_ANIMATOR (animator)); g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (property_name); key.object = object; key.property_name = g_intern_string (property_name); initial = g_list_find_custom (animator->priv->score, &key, sort_actor_prop_func); if (initial) { initial_key = initial->data; initial_key->ease_in = ease_in; } else g_warning ("The animator has no object of type '%s' with a " "property named '%s'", G_OBJECT_TYPE_NAME (object), property_name); } /** * clutter_animator_property_get_interpolation: * @animator: a #ClutterAnimatorKey * @object: a #GObject * @property_name: the name of a property on object * * Get the interpolation used by animator for a property on a particular * object. * * Returns: a ClutterInterpolation value. * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ ClutterInterpolation clutter_animator_property_get_interpolation (ClutterAnimator *animator, GObject *object, const gchar *property_name) { GList *initial; ClutterAnimatorKey key, *initial_key; g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), CLUTTER_INTERPOLATION_LINEAR); g_return_val_if_fail (G_IS_OBJECT (object), CLUTTER_INTERPOLATION_LINEAR); g_return_val_if_fail (property_name, CLUTTER_INTERPOLATION_LINEAR); key.object = object; key.property_name = g_intern_string (property_name); initial = g_list_find_custom (animator->priv->score, &key, sort_actor_prop_func); if (initial) { initial_key = initial->data; return initial_key->interpolation; } return CLUTTER_INTERPOLATION_LINEAR; } /** * clutter_animator_property_set_interpolation: * @animator: a #ClutterAnimatorKey * @object: a #GObject * @property_name: the name of a property on object * @interpolation: the #ClutterInterpolation to use * * Set the interpolation method to use, %CLUTTER_INTERPOLATION_LINEAR causes * the values to linearly change between the values, and * %CLUTTER_INTERPOLATION_CUBIC causes the values to smoothly change between * the values. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ void clutter_animator_property_set_interpolation (ClutterAnimator *animator, GObject *object, const gchar *property_name, ClutterInterpolation interpolation) { GList *initial; ClutterAnimatorKey key, *initial_key; g_return_if_fail (CLUTTER_IS_ANIMATOR (animator)); g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (property_name); key.object = object; key.property_name = g_intern_string (property_name); initial = g_list_find_custom (animator->priv->score, &key, sort_actor_prop_func); if (initial) { initial_key = initial->data; initial_key->interpolation = interpolation; } } G_DEFINE_BOXED_TYPE (ClutterAnimatorKey, clutter_animator_key, clutter_animator_key_copy, clutter_animator_key_free); /** * clutter_animator_key_get_object: * @key: a #ClutterAnimatorKey * * Retrieves the object a key applies to. * * Return value: (transfer none): the object an animator_key exist for. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ GObject * clutter_animator_key_get_object (const ClutterAnimatorKey *key) { g_return_val_if_fail (key != NULL, NULL); return key->object; } /** * clutter_animator_key_get_property_name: * @key: a #ClutterAnimatorKey * * Retrieves the name of the property a key applies to. * * Return value: the name of the property an animator_key exist for. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ const gchar * clutter_animator_key_get_property_name (const ClutterAnimatorKey *key) { g_return_val_if_fail (key != NULL, NULL); return key->property_name; } /** * clutter_animator_key_get_property_type: * @key: a #ClutterAnimatorKey * * Retrieves the #GType of the property a key applies to * * You can use this type to initialize the #GValue to pass to * clutter_animator_key_get_value() * * Return value: the #GType of the property * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ GType clutter_animator_key_get_property_type (const ClutterAnimatorKey *key) { g_return_val_if_fail (key != NULL, G_TYPE_INVALID); return G_VALUE_TYPE (&key->value); } /** * clutter_animator_key_get_mode: * @key: a #ClutterAnimatorKey * * Retrieves the mode of a #ClutterAnimator key, for the first key of a * property for an object this represents the whether the animation is * open ended and or curved for the remainding keys for the property it * represents the easing mode. * * Return value: the mode of a #ClutterAnimatorKey * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ gulong clutter_animator_key_get_mode (const ClutterAnimatorKey *key) { g_return_val_if_fail (key != NULL, 0); return key->mode; } /** * clutter_animator_key_get_progress: * @key: a #ClutterAnimatorKey * * Retrieves the progress of an clutter_animator_key * * Return value: the progress defined for a #ClutterAnimator key. * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ gdouble clutter_animator_key_get_progress (const ClutterAnimatorKey *key) { g_return_val_if_fail (key != NULL, 0.0); return key->progress; } /** * clutter_animator_key_get_value: * @key: a #ClutterAnimatorKey * @value: a #GValue initialized with the correct type for the animator key * * Retrieves a copy of the value for a #ClutterAnimatorKey. * * The passed in #GValue needs to be already initialized for the value * type of the key or to a type that allow transformation from the value * type of the key. * * Use g_value_unset() when done. * * Return value: %TRUE if the passed #GValue was successfully set, and * %FALSE otherwise * * Since: 1.2 * Deprecated: 1.12: Use #ClutterKeyframeTransition instead */ gboolean clutter_animator_key_get_value (const ClutterAnimatorKey *key, GValue *value) { g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (G_VALUE_TYPE (value) != G_TYPE_INVALID, FALSE); if (!g_type_is_a (G_VALUE_TYPE (&key->value), G_VALUE_TYPE (value))) { if (g_value_type_compatible (G_VALUE_TYPE (&key->value), G_VALUE_TYPE (value))) { g_value_copy (&key->value, value); return TRUE; } if (g_value_type_transformable (G_VALUE_TYPE (&key->value), G_VALUE_TYPE (value))) { if (g_value_transform (&key->value, value)) return TRUE; } g_warning ("%s: Unable to convert from %s to %s for the " "property '%s' of object %s in the animator key", G_STRLOC, g_type_name (G_VALUE_TYPE (&key->value)), g_type_name (G_VALUE_TYPE (value)), key->property_name, G_OBJECT_TYPE_NAME (key->object)); return FALSE; } else g_value_copy (&key->value, value); return TRUE; } muffin-5.2.1/clutter/clutter/deprecated/clutter-box.c0000664000175000017500000005306714211404421023027 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009,2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-box * @short_description: A Generic layout container * * #ClutterBox is a #ClutterActor sub-class implementing the #ClutterContainer * interface. A Box delegates the whole size requisition and size allocation to * a #ClutterLayoutManager instance. * * #ClutterBox is available since Clutter 1.2 * * #ClutterBox is deprecated since Clutter 1.10; all its relevant API is provided * by #ClutterActor, via the #ClutterActor:layout-manager property. * * ## Using ClutterBox * * The following code shows how to create a #ClutterBox with * a #ClutterLayoutManager sub-class, and how to add children to * it via clutter_box_pack(). * * |[ * ClutterActor *box; * ClutterLayoutManager *layout; * * // Create the layout manager first * layout = clutter_box_layout_new (); * clutter_box_layout_set_homogeneous (CLUTTER_BOX_LAYOUT (layout), TRUE); * clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout), 12); * * // Then create the ClutterBox actor. The Box will take * // ownership of the ClutterLayoutManager instance by sinking * // its floating reference * box = clutter_box_new (layout); * * // Now add children to the Box using the variadic arguments * // function clutter_box_pack() to set layout properties * clutter_box_pack (CLUTTER_BOX (box), actor, * "x-align", CLUTTER_BOX_ALIGNMENT_CENTER, * "y-align", CLUTTER_BOX_ALIGNMENT_END, * "expand", TRUE, * NULL); * ]| * * #ClutterBox's clutter_box_pack() wraps the generic * clutter_container_add_actor() function, but it also allows setting * layout properties while adding the new child to the box. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "clutter-box.h" #include "clutter-actor-private.h" #include "clutter-color.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" struct _ClutterBoxPrivate { ClutterLayoutManager *manager; guint changed_id; }; enum { PROP_0, PROP_COLOR, PROP_COLOR_SET, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static const ClutterColor default_box_color = { 255, 255, 255, 255 }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterBox, clutter_box, CLUTTER_TYPE_ACTOR) static inline void clutter_box_set_color_internal (ClutterBox *box, const ClutterColor *color) { clutter_actor_set_background_color (CLUTTER_ACTOR (box), color); g_object_notify_by_pspec (G_OBJECT (box), obj_props[PROP_COLOR_SET]); g_object_notify_by_pspec (G_OBJECT (box), obj_props[PROP_COLOR]); } static gboolean clutter_box_real_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { gboolean retval = FALSE; ClutterActorIter iter; ClutterActor *child; /* if we have a background color, and an allocation, then we need to * set it as the base of our paint volume */ retval = clutter_paint_volume_set_from_allocation (volume, actor); /* bail out early if we don't have any child */ if (clutter_actor_get_n_children (actor) == 0) return retval; retval = TRUE; /* otherwise, union the paint volumes of our children, in case * any one of them decides to paint outside the parent's allocation */ clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { const ClutterPaintVolume *child_volume; /* This gets the paint volume of the child transformed into the * group's coordinate space... */ child_volume = clutter_actor_get_transformed_paint_volume (child, actor); if (!child_volume) return FALSE; clutter_paint_volume_union (volume, child_volume); } return retval; } static void clutter_box_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBox *self = CLUTTER_BOX (gobject); switch (prop_id) { case PROP_COLOR: clutter_box_set_color_internal (self, clutter_value_get_color (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_box_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_COLOR: { ClutterColor color; clutter_actor_get_background_color (CLUTTER_ACTOR (gobject), &color); clutter_value_set_color (value, &color); } break; case PROP_COLOR_SET: { gboolean color_set; g_object_get (gobject, "background-color-set", &color_set, NULL); g_value_set_boolean (value, color_set); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_box_real_destroy (ClutterActor *actor) { ClutterActor *iter; iter = clutter_actor_get_first_child (actor); while (iter != NULL) { ClutterActor *next = clutter_actor_get_next_sibling (iter); clutter_actor_destroy (iter); iter = next; } } static void clutter_box_class_init (ClutterBoxClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); actor_class->destroy = clutter_box_real_destroy; actor_class->get_paint_volume = clutter_box_real_get_paint_volume; gobject_class->set_property = clutter_box_set_property; gobject_class->get_property = clutter_box_get_property; /** * ClutterBox:color: * * The color to be used to paint the background of the * #ClutterBox. Setting this property will set the * #ClutterBox:color-set property as a side effect * * This property sets the #ClutterActor:background-color property * internally. * * Since: 1.2 * * Deprecated: 1.10: Use the #ClutterActor:background-color property */ obj_props[PROP_COLOR] = clutter_param_spec_color ("color", P_("Color"), P_("The background color of the box"), &default_box_color, CLUTTER_PARAM_READWRITE); /** * ClutterBox:color-set: * * Whether the #ClutterBox:color property has been set. * * This property reads the #ClutterActor:background-color-set property * internally. * * Since: 1.2 * * Deprecated: 1.10: Use the #ClutterActor:background-color-set property */ obj_props[PROP_COLOR_SET] = g_param_spec_boolean ("color-set", P_("Color Set"), P_("Whether the background color is set"), FALSE, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_box_init (ClutterBox *self) { self->priv = clutter_box_get_instance_private (self); } /** * clutter_box_new: * @manager: a #ClutterLayoutManager * * Creates a new #ClutterBox. The children of the box will be layed * out by the passed @manager * * Return value: the newly created #ClutterBox actor * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_new() instead. */ ClutterActor * clutter_box_new (ClutterLayoutManager *manager) { g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), NULL); return g_object_new (CLUTTER_TYPE_BOX, "layout-manager", manager, NULL); } /** * clutter_box_set_layout_manager: * @box: a #ClutterBox * @manager: a #ClutterLayoutManager * * Sets the #ClutterLayoutManager for @box * * A #ClutterLayoutManager is a delegate object that controls the * layout of the children of @box * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_set_layout_manager() instead. */ void clutter_box_set_layout_manager (ClutterBox *box, ClutterLayoutManager *manager) { clutter_actor_set_layout_manager (CLUTTER_ACTOR (box), manager); } /** * clutter_box_get_layout_manager: * @box: a #ClutterBox * * Retrieves the #ClutterLayoutManager instance used by @box * * Return value: (transfer none): a #ClutterLayoutManager. The returned * #ClutterLayoutManager is owned by the #ClutterBox and it should not * be unreferenced * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_get_layout_manager() instead. */ ClutterLayoutManager * clutter_box_get_layout_manager (ClutterBox *box) { return clutter_actor_get_layout_manager (CLUTTER_ACTOR (box)); } /** * clutter_box_packv: * @box: a #ClutterBox * @actor: a #ClutterActor * @n_properties: the number of properties to set * @properties: (array length=n_properties) (element-type utf8): a vector * containing the property names to set * @values: (array length=n_properties): a vector containing the property * values to set * * Vector-based variant of clutter_box_pack(), intended for language * bindings to use * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_add_child() instead. To set * specific layout properties, use clutter_layout_manager_child_set() */ void clutter_box_packv (ClutterBox *box, ClutterActor *actor, guint n_properties, const gchar * const properties[], const GValue *values) { ClutterLayoutManager *manager; ClutterContainer *container; ClutterLayoutMeta *meta; GObjectClass *klass; gint i; g_return_if_fail (CLUTTER_IS_BOX (box)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); container = CLUTTER_CONTAINER (box); clutter_container_add_actor (container, actor); manager = clutter_actor_get_layout_manager (CLUTTER_ACTOR (box)); if (manager == NULL) return; meta = clutter_layout_manager_get_child_meta (manager, container, actor); if (meta == NULL) return; klass = G_OBJECT_GET_CLASS (meta); for (i = 0; i < n_properties; i++) { const gchar *pname = properties[i]; GParamSpec *pspec; pspec = g_object_class_find_property (klass, pname); if (pspec == NULL) { g_warning ("%s: the layout property '%s' for managers " "of type '%s' (meta type '%s') does not exist", G_STRLOC, pname, G_OBJECT_TYPE_NAME (manager), G_OBJECT_TYPE_NAME (meta)); break; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("%s: the layout property '%s' for managers " "of type '%s' (meta type '%s') is not writable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager), G_OBJECT_TYPE_NAME (meta)); break; } clutter_layout_manager_child_set_property (manager, container, actor, pname, &values[i]); } } static inline void clutter_box_set_property_valist (ClutterBox *box, ClutterActor *actor, const gchar *first_property, va_list var_args) { ClutterContainer *container = CLUTTER_CONTAINER (box); ClutterLayoutManager *manager; ClutterLayoutMeta *meta; GObjectClass *klass; const gchar *pname; manager = clutter_actor_get_layout_manager (CLUTTER_ACTOR (box)); if (manager == NULL) return; meta = clutter_layout_manager_get_child_meta (manager, container, actor); if (meta == NULL) return; klass = G_OBJECT_GET_CLASS (meta); pname = first_property; while (pname) { GValue value = { 0, }; GParamSpec *pspec; gchar *error; pspec = g_object_class_find_property (klass, pname); if (pspec == NULL) { g_warning ("%s: the layout property '%s' for managers " "of type '%s' (meta type '%s') does not exist", G_STRLOC, pname, G_OBJECT_TYPE_NAME (manager), G_OBJECT_TYPE_NAME (meta)); break; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("%s: the layout property '%s' for managers " "of type '%s' (meta type '%s') is not writable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (manager), G_OBJECT_TYPE_NAME (meta)); break; } G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec), var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); break; } clutter_layout_manager_child_set_property (manager, container, actor, pspec->name, &value); g_value_unset (&value); pname = va_arg (var_args, gchar*); } } /** * clutter_box_pack: * @box: a #ClutterBox * @actor: a #ClutterActor * @first_property: the name of the first property to set, or %NULL * @...: a list of property name and value pairs, terminated by %NULL * * Adds @actor to @box and sets layout properties at the same time, * if the #ClutterLayoutManager used by @box has them * * This function is a wrapper around clutter_container_add_actor() * and clutter_layout_manager_child_set() * * Language bindings should use the vector-based clutter_box_packv() * variant instead * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_add_child() instead. To set * specific layout properties, use clutter_layout_manager_child_set() */ void clutter_box_pack (ClutterBox *box, ClutterActor *actor, const gchar *first_property, ...) { va_list var_args; g_return_if_fail (CLUTTER_IS_BOX (box)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); clutter_container_add_actor (CLUTTER_CONTAINER (box), actor); if (first_property == NULL || *first_property == '\0') return; va_start (var_args, first_property); clutter_box_set_property_valist (box, actor, first_property, var_args); va_end (var_args); } /** * clutter_box_pack_after: * @box: a #ClutterBox * @actor: a #ClutterActor * @sibling: (allow-none): a #ClutterActor or %NULL * @first_property: the name of the first property to set, or %NULL * @...: a list of property name and value pairs, terminated by %NULL * * Adds @actor to @box, placing it after @sibling, and sets layout * properties at the same time, if the #ClutterLayoutManager used by * @box supports them * * If @sibling is %NULL then @actor is placed at the end of the * list of children, to be allocated and painted after every other child * * This function is a wrapper around clutter_container_add_actor(), * clutter_container_raise_child() and clutter_layout_manager_child_set() * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_insert_child_above() instead. * To set specific layout properties, use clutter_layout_manager_child_set() */ void clutter_box_pack_after (ClutterBox *box, ClutterActor *actor, ClutterActor *sibling, const gchar *first_property, ...) { va_list var_args; g_return_if_fail (CLUTTER_IS_BOX (box)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling)); clutter_container_add_actor (CLUTTER_CONTAINER (box), actor); clutter_container_raise_child (CLUTTER_CONTAINER (box), actor, sibling); if (first_property == NULL || *first_property == '\0') return; va_start (var_args, first_property); clutter_box_set_property_valist (box, actor, first_property, var_args); va_end (var_args); } /** * clutter_box_pack_before: * @box: a #ClutterBox * @actor: a #ClutterActor * @sibling: (allow-none): a #ClutterActor or %NULL * @first_property: the name of the first property to set, or %NULL * @...: a list of property name and value pairs, terminated by %NULL * * Adds @actor to @box, placing it before @sibling, and sets layout * properties at the same time, if the #ClutterLayoutManager used by * @box supports them * * If @sibling is %NULL then @actor is placed at the beginning of the * list of children, to be allocated and painted below every other child * * This function is a wrapper around clutter_container_add_actor(), * clutter_container_lower_child() and clutter_layout_manager_child_set() * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_insert_child_below() instead. * To set specific layout properties, use clutter_layout_manager_child_set() */ void clutter_box_pack_before (ClutterBox *box, ClutterActor *actor, ClutterActor *sibling, const gchar *first_property, ...) { va_list var_args; g_return_if_fail (CLUTTER_IS_BOX (box)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling)); clutter_container_add_actor (CLUTTER_CONTAINER (box), actor); clutter_container_lower_child (CLUTTER_CONTAINER (box), actor, sibling); if (first_property == NULL || *first_property == '\0') return; va_start (var_args, first_property); clutter_box_set_property_valist (box, actor, first_property, var_args); va_end (var_args); } /** * clutter_box_pack_at: * @box: a #ClutterBox * @actor: a #ClutterActor * @position: the position to insert the @actor at * @first_property: the name of the first property to set, or %NULL * @...: a list of property name and value pairs, terminated by %NULL * * Adds @actor to @box, placing it at @position, and sets layout * properties at the same time, if the #ClutterLayoutManager used by * @box supports them * * If @position is a negative number, or is larger than the number of * children of @box, the new child is added at the end of the list of * children * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_insert_child_at_index() instead. * To set specific layout properties, use clutter_layout_manager_child_set() */ void clutter_box_pack_at (ClutterBox *box, ClutterActor *actor, gint position, const gchar *first_property, ...) { va_list var_args; g_return_if_fail (CLUTTER_IS_BOX (box)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); clutter_actor_insert_child_at_index (CLUTTER_ACTOR (box), actor, position); /* we need to explicitly call this, because we're not going through * the default code paths provided by clutter_container_add() */ clutter_container_create_child_meta (CLUTTER_CONTAINER (box), actor); g_signal_emit_by_name (box, "actor-added", actor); if (first_property == NULL || *first_property == '\0') return; va_start (var_args, first_property); clutter_box_set_property_valist (box, actor, first_property, var_args); va_end (var_args); } /** * clutter_box_set_color: * @box: a #ClutterBox * @color: (allow-none): the background color, or %NULL to unset * * Sets (or unsets) the background color for @box * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_set_background_color() instead. */ void clutter_box_set_color (ClutterBox *box, const ClutterColor *color) { g_return_if_fail (CLUTTER_IS_BOX (box)); clutter_box_set_color_internal (box, color); } /** * clutter_box_get_color: * @box: a #ClutterBox * @color: (out caller-allocates): return location for a #ClutterColor * * Retrieves the background color of @box * * If the #ClutterBox:color-set property is set to %FALSE the * returned #ClutterColor is undefined * * Since: 1.2 * * Deprecated: 1.10: Use clutter_actor_get_background_color() instead. */ void clutter_box_get_color (ClutterBox *box, ClutterColor *color) { g_return_if_fail (CLUTTER_IS_BOX (box)); g_return_if_fail (color != NULL); clutter_actor_get_background_color (CLUTTER_ACTOR (box), color); } muffin-5.2.1/clutter/clutter/deprecated/clutter-behaviour-path.c0000664000175000017500000003272214211404421025150 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: * Matthew Allum * Neil Roberts * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see . */ /** * SECTION:clutter-behaviour-path * @Title: ClutterBehaviourPath * @short_description: A behaviour for moving actors along a #ClutterPath * @Deprecated: 1.6: Use #ClutterPathConstraint and clutter_actor_animate() * with the #ClutterPathConstraint:offset property instead. * * #ClutterBehaviourPath interpolates actors along a defined path. * * A path is described by a #ClutterPath object. The path can contain * straight line parts and bezier curves. If the path contains * %CLUTTER_PATH_MOVE_TO parts then the actors will jump to those * coordinates. This can be used make disjoint paths. * * When creating a path behaviour in a #ClutterScript, you can specify * the path property directly as a string. For example: * * |[ * { * "id" : "spline-path", * "type" : "ClutterBehaviourPath", * "path" : "M 50 50 L 100 100", * "alpha" : { * "timeline" : "main-timeline", * "function" : "ramp * } * } * ]| * * If the alpha function is a periodic function, i.e. it returns to * 0.0 after reaching 1.0, then the actors will walk the path back to the * starting #ClutterKnot. * * #ClutterBehaviourPath is available since Clutter 0.2 * * Deprecated: 1.6: Use #ClutterPath and #ClutterPathConstraint with * clutter_actor_animate() instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-alpha.h" #include "clutter-behaviour.h" #include "clutter-behaviour-path.h" #include "clutter-bezier.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-script-private.h" #include "clutter-scriptable.h" #include struct _ClutterBehaviourPathPrivate { ClutterPath *path; guint last_knot_passed; }; enum { KNOT_REACHED, LAST_SIGNAL }; static guint path_signals[LAST_SIGNAL] = { 0, }; enum { PROP_0, PROP_PATH, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterBehaviourPath, clutter_behaviour_path, CLUTTER_TYPE_BEHAVIOUR, G_ADD_PRIVATE (ClutterBehaviourPath) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init)) static void actor_apply_knot_foreach (ClutterBehaviour *behaviour, ClutterActor *actor, gpointer data) { ClutterKnot *knot = data; CLUTTER_NOTE (ANIMATION, "Setting actor to %ix%i", knot->x, knot->y); clutter_actor_set_position (actor, knot->x, knot->y); } static void clutter_behaviour_path_alpha_notify (ClutterBehaviour *behave, gdouble alpha_value) { ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (behave); ClutterBehaviourPathPrivate *priv = pathb->priv; ClutterKnot position; guint knot_num; if (priv->path) knot_num = clutter_path_get_position (priv->path, alpha_value, &position); else { memset (&position, 0, sizeof (position)); knot_num = 0; } clutter_behaviour_actors_foreach (behave, actor_apply_knot_foreach, &position); if (knot_num != priv->last_knot_passed) { g_signal_emit (behave, path_signals[KNOT_REACHED], 0, knot_num); priv->last_knot_passed = knot_num; } } static void clutter_behaviour_path_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (gobject); switch (prop_id) { case PROP_PATH: g_value_set_object (value, clutter_behaviour_path_get_path (pathb)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_path_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (gobject); switch (prop_id) { case PROP_PATH: clutter_behaviour_path_set_path (pathb, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_behaviour_path_dispose (GObject *gobject) { ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (gobject); clutter_behaviour_path_set_path (pathb, NULL); G_OBJECT_CLASS (clutter_behaviour_path_parent_class)->dispose (gobject); } static void clutter_behaviour_path_class_init (ClutterBehaviourPathClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass); GParamSpec *pspec; gobject_class->get_property = clutter_behaviour_path_get_property; gobject_class->set_property = clutter_behaviour_path_set_property; gobject_class->dispose = clutter_behaviour_path_dispose; pspec = g_param_spec_object ("path", P_("Path"), P_("The ClutterPath object representing the path " "to animate along"), CLUTTER_TYPE_PATH, CLUTTER_PARAM_READWRITE); obj_props[PROP_PATH] = pspec; g_object_class_install_property (gobject_class, PROP_PATH, pspec); /** * ClutterBehaviourPath::knot-reached: * @pathb: the object which received the signal * @knot_num: the index of the #ClutterKnot reached * * This signal is emitted each time a node defined inside the path * is reached. * * Since: 0.2 * * Deprecated: 1.6 */ path_signals[KNOT_REACHED] = g_signal_new ("knot-reached", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterBehaviourPathClass, knot_reached), NULL, NULL, _clutter_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); behave_class->alpha_notify = clutter_behaviour_path_alpha_notify; } static ClutterScriptableIface *parent_scriptable_iface = NULL; static gboolean clutter_behaviour_path_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { if (strcmp ("path", name) == 0) { ClutterPath *path; GValue node_value = { 0 }; path = g_object_ref_sink (clutter_path_new ()); json_node_get_value (node, &node_value); if (!G_VALUE_HOLDS (&node_value, G_TYPE_STRING) || !clutter_path_set_description (path, g_value_get_string (&node_value))) g_warning ("Invalid path description"); g_value_unset (&node_value); g_value_init (value, G_TYPE_OBJECT); g_value_take_object (value, path); return TRUE; } /* chain up */ else if (parent_scriptable_iface->parse_custom_node) return parent_scriptable_iface->parse_custom_node (scriptable, script, value, name, node); else return FALSE; } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { parent_scriptable_iface = g_type_interface_peek_parent (iface); if (!parent_scriptable_iface) parent_scriptable_iface = g_type_default_interface_peek (CLUTTER_TYPE_SCRIPTABLE); iface->parse_custom_node = clutter_behaviour_path_parse_custom_node; } static void clutter_behaviour_path_init (ClutterBehaviourPath *self) { self->priv = clutter_behaviour_path_get_instance_private (self); self->priv->last_knot_passed = G_MAXUINT; } /** * clutter_behaviour_path_new: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @path: a #ClutterPath or %NULL for an empty path * * Creates a new path behaviour. You can use this behaviour to drive * actors along the nodes of a path, described by @path. * * This will claim the floating reference on the #ClutterPath so you * do not need to unref if it. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: (transfer full): a #ClutterBehaviour * * Since: 0.2 * * Deprecated: 1.6 */ ClutterBehaviour * clutter_behaviour_path_new (ClutterAlpha *alpha, ClutterPath *path) { return g_object_new (CLUTTER_TYPE_BEHAVIOUR_PATH, "alpha", alpha, "path", path, NULL); } /** * clutter_behaviour_path_new_with_description: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @desc: a string description of the path * * Creates a new path behaviour using the path described by @desc. See * clutter_path_add_string() for a description of the format. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: (transfer full): a #ClutterBehaviour * * Since: 1.0 * * Deprecated: 1.6 */ ClutterBehaviour * clutter_behaviour_path_new_with_description (ClutterAlpha *alpha, const gchar *desc) { return g_object_new (CLUTTER_TYPE_BEHAVIOUR_PATH, "alpha", alpha, "path", clutter_path_new_with_description (desc), NULL); } /** * clutter_behaviour_path_new_with_knots: * @alpha: (allow-none): a #ClutterAlpha instance, or %NULL * @knots: (array length=n_knots): an array of #ClutterKnots * @n_knots: number of entries in @knots * * Creates a new path behaviour that will make the actors visit all of * the given knots in order with straight lines in between. * * A path will be created where the first knot is used in a * %CLUTTER_PATH_MOVE_TO and the subsequent knots are used in * %CLUTTER_PATH_LINE_TOs. * * If @alpha is not %NULL, the #ClutterBehaviour will take ownership * of the #ClutterAlpha instance. In the case when @alpha is %NULL, * it can be set later with clutter_behaviour_set_alpha(). * * Return value: (transfer full): a #ClutterBehaviour * * Since: 1.0 * * Deprecated: 1.6 */ ClutterBehaviour * clutter_behaviour_path_new_with_knots (ClutterAlpha *alpha, const ClutterKnot *knots, guint n_knots) { ClutterPath *path = clutter_path_new (); guint i; if (n_knots > 0) { clutter_path_add_move_to (path, knots[0].x, knots[0].y); for (i = 1; i < n_knots; i++) clutter_path_add_line_to (path, knots[i].x, knots[i].y); } return g_object_new (CLUTTER_TYPE_BEHAVIOUR_PATH, "alpha", alpha, "path", path, NULL); } /** * clutter_behaviour_path_set_path: * @pathb: the path behaviour * @path: the new path to follow * * Change the path that the actors will follow. This will take the * floating reference on the #ClutterPath so you do not need to unref * it. * * Since: 1.0 * * Deprecated: 1.6 */ void clutter_behaviour_path_set_path (ClutterBehaviourPath *pathb, ClutterPath *path) { ClutterBehaviourPathPrivate *priv; g_return_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb)); priv = pathb->priv; if (path) g_object_ref_sink (path); if (priv->path) g_object_unref (priv->path); priv->path = path; g_object_notify_by_pspec (G_OBJECT (pathb), obj_props[PROP_PATH]); } /** * clutter_behaviour_path_get_path: * @pathb: a #ClutterBehaviourPath instance * * Get the current path of the behaviour * * Return value: (transfer none): the path * * Since: 1.0 * * Deprecated: 1.6 */ ClutterPath * clutter_behaviour_path_get_path (ClutterBehaviourPath *pathb) { g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb), NULL); return pathb->priv->path; } muffin-5.2.1/clutter/clutter/deprecated/clutter-frame-source.c0000664000175000017500000002133514211404421024620 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Neil Roberts * * Copyright (C) 2008 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, see . * * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-main.h" #include "clutter-private.h" #include "deprecated/clutter-frame-source.h" #include "deprecated/clutter-timeout-interval.h" typedef struct _ClutterFrameSource ClutterFrameSource; struct _ClutterFrameSource { GSource source; ClutterTimeoutInterval timeout; }; static gboolean clutter_frame_source_prepare (GSource *source, gint *timeout); static gboolean clutter_frame_source_check (GSource *source); static gboolean clutter_frame_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data); static GSourceFuncs clutter_frame_source_funcs = { clutter_frame_source_prepare, clutter_frame_source_check, clutter_frame_source_dispatch, NULL }; /** * clutter_frame_source_add_full: (rename-to clutter_frame_source_add) * @priority: the priority of the frame source. Typically this will be in the * range between %G_PRIORITY_DEFAULT and %G_PRIORITY_HIGH. * @fps: the number of times per second to call the function * @func: function to call * @data: data to pass to the function * @notify: function to call when the timeout source is removed * * Sets a function to be called at regular intervals with the given * priority. The function is called repeatedly until it returns * %FALSE, at which point the timeout is automatically destroyed and * the function will not be called again. The @notify function is * called when the timeout is destroyed. The first call to the * function will be at the end of the first @interval. * * This function is similar to g_timeout_add_full() except that it * will try to compensate for delays. For example, if @func takes half * the interval time to execute then the function will be called again * half the interval time after it finished. In contrast * g_timeout_add_full() would not fire until a full interval after the * function completes so the delay between calls would be 1.0 / @fps * * 1.5. This function does not however try to invoke the function * multiple times to catch up missing frames if @func takes more than * @interval ms to execute. * * Return value: the ID (greater than 0) of the event source. * * Since: 0.8 * * Deprecated: 1.6: There is no direct replacement for this API. */ guint clutter_frame_source_add_full (gint priority, guint fps, GSourceFunc func, gpointer data, GDestroyNotify notify) { guint ret; GSource *source = g_source_new (&clutter_frame_source_funcs, sizeof (ClutterFrameSource)); ClutterFrameSource *frame_source = (ClutterFrameSource *) source; _clutter_timeout_interval_init (&frame_source->timeout, fps); if (priority != G_PRIORITY_DEFAULT) g_source_set_priority (source, priority); g_source_set_name (source, "Clutter frame timeout"); g_source_set_callback (source, func, data, notify); ret = g_source_attach (source, NULL); g_source_unref (source); return ret; } /** * clutter_frame_source_add: (skip) * @fps: the number of times per second to call the function * @func: function to call * @data: data to pass to the function * * Simple wrapper around clutter_frame_source_add_full(). * * Return value: the ID (greater than 0) of the event source. * * Since: 0.8 * * Deprecated: 1.6: There is no direct replacement for this API */ guint clutter_frame_source_add (guint fps, GSourceFunc func, gpointer data) { return clutter_frame_source_add_full (G_PRIORITY_DEFAULT, fps, func, data, NULL); } static gboolean clutter_frame_source_prepare (GSource *source, gint *delay) { ClutterFrameSource *frame_source = (ClutterFrameSource *) source; gint64 current_time; #if GLIB_CHECK_VERSION (2, 27, 3) current_time = g_source_get_time (source) / 1000; #else { GTimeVal source_time; g_source_get_current_time (source, &source_time); current_time = source_time.tv_sec * 1000 + source_time.tv_usec / 1000; } #endif return _clutter_timeout_interval_prepare (current_time, &frame_source->timeout, delay); } static gboolean clutter_frame_source_check (GSource *source) { return clutter_frame_source_prepare (source, NULL); } static gboolean clutter_frame_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterFrameSource *frame_source = (ClutterFrameSource *) source; return _clutter_timeout_interval_dispatch (&frame_source->timeout, callback, user_data); } /** * clutter_threads_add_frame_source_full: (rename-to clutter_threads_add_frame_source) * @priority: the priority of the frame source. Typically this will be in the * range between %G_PRIORITY_DEFAULT and %G_PRIORITY_HIGH. * @fps: the number of times per second to call the function * @func: function to call * @data: data to pass to the function * @notify: function to call when the timeout source is removed * * Sets a function to be called at regular intervals holding the Clutter * threads lock, with the given priority. The function is called repeatedly * until it returns %FALSE, at which point the timeout is automatically * removed and the function will not be called again. The @notify function * is called when the timeout is removed. * * This function is similar to clutter_threads_add_timeout_full() * except that it will try to compensate for delays. For example, if * @func takes half the interval time to execute then the function * will be called again half the interval time after it finished. In * contrast clutter_threads_add_timeout_full() would not fire until a * full interval after the function completes so the delay between * calls would be @interval * 1.5. This function does not however try * to invoke the function multiple times to catch up missing frames if * @func takes more than @interval ms to execute. * * See also clutter_threads_add_idle_full(). * * Return value: the ID (greater than 0) of the event source. * * Since: 0.8 * * Deprecated: 1.6: There is no direct replacement for this API */ guint clutter_threads_add_frame_source_full (gint priority, guint fps, GSourceFunc func, gpointer data, GDestroyNotify notify) { ClutterThreadsDispatch *dispatch; g_return_val_if_fail (func != NULL, 0); dispatch = g_slice_new (ClutterThreadsDispatch); dispatch->func = func; dispatch->data = data; dispatch->notify = notify; return clutter_frame_source_add_full (priority, fps, _clutter_threads_dispatch, dispatch, _clutter_threads_dispatch_free); } /** * clutter_threads_add_frame_source: (skip) * @fps: the number of times per second to call the function * @func: function to call * @data: data to pass to the function * * Simple wrapper around clutter_threads_add_frame_source_full(). * * Return value: the ID (greater than 0) of the event source. * * Since: 0.8 * * Deprecated: 1.6: There is no direct replacement for this API */ guint clutter_threads_add_frame_source (guint fps, GSourceFunc func, gpointer data) { g_return_val_if_fail (func != NULL, 0); return clutter_threads_add_frame_source_full (G_PRIORITY_DEFAULT, fps, func, data, NULL); } muffin-5.2.1/clutter/clutter/deprecated/clutter-keysyms.h0000664000175000017500000103270414211404421023744 0ustar jpeisachjpeisach/* Clutter * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see . */ /* * Compatibility version of clutter-keysyms.h. * * Since Clutter 1.4, the key symbol defines have been changed to have * a KEY_ prefix. This is a compatibility header that is included when * deprecated symbols are enabled. Consider porting to the new names * instead. */ #ifndef __CLUTTER_KEYSYMS_DEPRECATED_H__ #define __CLUTTER_KEYSYMS_DEPRECATED_H__ #ifndef CLUTTER_DISABLE_DEPRECATED #define CLUTTER_VoidSymbol 0xffffff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_VoidSymbol instead.") #define CLUTTER_BackSpace 0xff08 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_BackSpace instead.") #define CLUTTER_Tab 0xff09 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Tab instead.") #define CLUTTER_Linefeed 0xff0a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Linefeed instead.") #define CLUTTER_Clear 0xff0b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Clear instead.") #define CLUTTER_Return 0xff0d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Return instead.") #define CLUTTER_Pause 0xff13 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pause instead.") #define CLUTTER_Scroll_Lock 0xff14 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Scroll_Lock instead.") #define CLUTTER_Sys_Req 0xff15 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sys_Req instead.") #define CLUTTER_Escape 0xff1b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Escape instead.") #define CLUTTER_Delete 0xffff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Delete instead.") #define CLUTTER_Multi_key 0xff20 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Multi_key instead.") #define CLUTTER_Codeinput 0xff37 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Codeinput instead.") #define CLUTTER_SingleCandidate 0xff3c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_SingleCandidate instead.") #define CLUTTER_MultipleCandidate 0xff3d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_MultipleCandidate instead.") #define CLUTTER_PreviousCandidate 0xff3e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_PreviousCandidate instead.") #define CLUTTER_Kanji 0xff21 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Kanji instead.") #define CLUTTER_Muhenkan 0xff22 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Muhenkan instead.") #define CLUTTER_Henkan_Mode 0xff23 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Henkan_Mode instead.") #define CLUTTER_Henkan 0xff23 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Henkan instead.") #define CLUTTER_Romaji 0xff24 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Romaji instead.") #define CLUTTER_Hiragana 0xff25 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hiragana instead.") #define CLUTTER_Katakana 0xff26 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Katakana instead.") #define CLUTTER_Hiragana_Katakana 0xff27 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hiragana_Katakana instead.") #define CLUTTER_Zenkaku 0xff28 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Zenkaku instead.") #define CLUTTER_Hankaku 0xff29 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hankaku instead.") #define CLUTTER_Zenkaku_Hankaku 0xff2a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Zenkaku_Hankaku instead.") #define CLUTTER_Touroku 0xff2b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Touroku instead.") #define CLUTTER_Massyo 0xff2c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Massyo instead.") #define CLUTTER_Kana_Lock 0xff2d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Kana_Lock instead.") #define CLUTTER_Kana_Shift 0xff2e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Kana_Shift instead.") #define CLUTTER_Eisu_Shift 0xff2f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Eisu_Shift instead.") #define CLUTTER_Eisu_toggle 0xff30 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Eisu_toggle instead.") #define CLUTTER_Kanji_Bangou 0xff37 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Kanji_Bangou instead.") #define CLUTTER_Zen_Koho 0xff3d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Zen_Koho instead.") #define CLUTTER_Mae_Koho 0xff3e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Mae_Koho instead.") #define CLUTTER_Home 0xff50 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Home instead.") #define CLUTTER_Left 0xff51 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Left instead.") #define CLUTTER_Up 0xff52 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Up instead.") #define CLUTTER_Right 0xff53 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Right instead.") #define CLUTTER_Down 0xff54 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Down instead.") #define CLUTTER_Prior 0xff55 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Prior instead.") #define CLUTTER_Page_Up 0xff55 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Page_Up instead.") #define CLUTTER_Next 0xff56 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Next instead.") #define CLUTTER_Page_Down 0xff56 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Page_Down instead.") #define CLUTTER_End 0xff57 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_End instead.") #define CLUTTER_Begin 0xff58 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Begin instead.") #define CLUTTER_Select 0xff60 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Select instead.") #define CLUTTER_Print 0xff61 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Print instead.") #define CLUTTER_Execute 0xff62 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Execute instead.") #define CLUTTER_Insert 0xff63 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Insert instead.") #define CLUTTER_Undo 0xff65 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Undo instead.") #define CLUTTER_Redo 0xff66 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Redo instead.") #define CLUTTER_Menu 0xff67 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Menu instead.") #define CLUTTER_Find 0xff68 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Find instead.") #define CLUTTER_Cancel 0xff69 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cancel instead.") #define CLUTTER_Help 0xff6a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Help instead.") #define CLUTTER_Break 0xff6b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Break instead.") #define CLUTTER_Mode_switch 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Mode_switch instead.") #define CLUTTER_script_switch 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_script_switch instead.") #define CLUTTER_Num_Lock 0xff7f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Num_Lock instead.") #define CLUTTER_KP_Space 0xff80 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Space instead.") #define CLUTTER_KP_Tab 0xff89 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Tab instead.") #define CLUTTER_KP_Enter 0xff8d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Enter instead.") #define CLUTTER_KP_F1 0xff91 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_F1 instead.") #define CLUTTER_KP_F2 0xff92 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_F2 instead.") #define CLUTTER_KP_F3 0xff93 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_F3 instead.") #define CLUTTER_KP_F4 0xff94 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_F4 instead.") #define CLUTTER_KP_Home 0xff95 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Home instead.") #define CLUTTER_KP_Left 0xff96 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Left instead.") #define CLUTTER_KP_Up 0xff97 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Up instead.") #define CLUTTER_KP_Right 0xff98 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Right instead.") #define CLUTTER_KP_Down 0xff99 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Down instead.") #define CLUTTER_KP_Prior 0xff9a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Prior instead.") #define CLUTTER_KP_Page_Up 0xff9a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Page_Up instead.") #define CLUTTER_KP_Next 0xff9b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Next instead.") #define CLUTTER_KP_Page_Down 0xff9b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Page_Down instead.") #define CLUTTER_KP_End 0xff9c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_End instead.") #define CLUTTER_KP_Begin 0xff9d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Begin instead.") #define CLUTTER_KP_Insert 0xff9e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Insert instead.") #define CLUTTER_KP_Delete 0xff9f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Delete instead.") #define CLUTTER_KP_Equal 0xffbd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Equal instead.") #define CLUTTER_KP_Multiply 0xffaa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Multiply instead.") #define CLUTTER_KP_Add 0xffab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Add instead.") #define CLUTTER_KP_Separator 0xffac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Separator instead.") #define CLUTTER_KP_Subtract 0xffad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Subtract instead.") #define CLUTTER_KP_Decimal 0xffae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Decimal instead.") #define CLUTTER_KP_Divide 0xffaf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_Divide instead.") #define CLUTTER_KP_0 0xffb0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_0 instead.") #define CLUTTER_KP_1 0xffb1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_1 instead.") #define CLUTTER_KP_2 0xffb2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_2 instead.") #define CLUTTER_KP_3 0xffb3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_3 instead.") #define CLUTTER_KP_4 0xffb4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_4 instead.") #define CLUTTER_KP_5 0xffb5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_5 instead.") #define CLUTTER_KP_6 0xffb6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_6 instead.") #define CLUTTER_KP_7 0xffb7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_7 instead.") #define CLUTTER_KP_8 0xffb8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_8 instead.") #define CLUTTER_KP_9 0xffb9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_KP_9 instead.") #define CLUTTER_F1 0xffbe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F1 instead.") #define CLUTTER_F2 0xffbf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F2 instead.") #define CLUTTER_F3 0xffc0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F3 instead.") #define CLUTTER_F4 0xffc1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F4 instead.") #define CLUTTER_F5 0xffc2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F5 instead.") #define CLUTTER_F6 0xffc3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F6 instead.") #define CLUTTER_F7 0xffc4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F7 instead.") #define CLUTTER_F8 0xffc5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F8 instead.") #define CLUTTER_F9 0xffc6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F9 instead.") #define CLUTTER_F10 0xffc7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F10 instead.") #define CLUTTER_F11 0xffc8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F11 instead.") #define CLUTTER_L1 0xffc8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L1 instead.") #define CLUTTER_F12 0xffc9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F12 instead.") #define CLUTTER_L2 0xffc9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L2 instead.") #define CLUTTER_F13 0xffca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F13 instead.") #define CLUTTER_L3 0xffca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L3 instead.") #define CLUTTER_F14 0xffcb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F14 instead.") #define CLUTTER_L4 0xffcb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L4 instead.") #define CLUTTER_F15 0xffcc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F15 instead.") #define CLUTTER_L5 0xffcc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L5 instead.") #define CLUTTER_F16 0xffcd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F16 instead.") #define CLUTTER_L6 0xffcd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L6 instead.") #define CLUTTER_F17 0xffce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F17 instead.") #define CLUTTER_L7 0xffce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L7 instead.") #define CLUTTER_F18 0xffcf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F18 instead.") #define CLUTTER_L8 0xffcf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L8 instead.") #define CLUTTER_F19 0xffd0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F19 instead.") #define CLUTTER_L9 0xffd0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L9 instead.") #define CLUTTER_F20 0xffd1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F20 instead.") #define CLUTTER_L10 0xffd1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L10 instead.") #define CLUTTER_F21 0xffd2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F21 instead.") #define CLUTTER_R1 0xffd2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R1 instead.") #define CLUTTER_F22 0xffd3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F22 instead.") #define CLUTTER_R2 0xffd3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R2 instead.") #define CLUTTER_F23 0xffd4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F23 instead.") #define CLUTTER_R3 0xffd4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R3 instead.") #define CLUTTER_F24 0xffd5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F24 instead.") #define CLUTTER_R4 0xffd5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R4 instead.") #define CLUTTER_F25 0xffd6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F25 instead.") #define CLUTTER_R5 0xffd6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R5 instead.") #define CLUTTER_F26 0xffd7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F26 instead.") #define CLUTTER_R6 0xffd7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R6 instead.") #define CLUTTER_F27 0xffd8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F27 instead.") #define CLUTTER_R7 0xffd8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R7 instead.") #define CLUTTER_F28 0xffd9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F28 instead.") #define CLUTTER_R8 0xffd9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R8 instead.") #define CLUTTER_F29 0xffda CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F29 instead.") #define CLUTTER_R9 0xffda CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R9 instead.") #define CLUTTER_F30 0xffdb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F30 instead.") #define CLUTTER_R10 0xffdb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R10 instead.") #define CLUTTER_F31 0xffdc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F31 instead.") #define CLUTTER_R11 0xffdc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R11 instead.") #define CLUTTER_F32 0xffdd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F32 instead.") #define CLUTTER_R12 0xffdd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R12 instead.") #define CLUTTER_F33 0xffde CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F33 instead.") #define CLUTTER_R13 0xffde CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R13 instead.") #define CLUTTER_F34 0xffdf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F34 instead.") #define CLUTTER_R14 0xffdf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R14 instead.") #define CLUTTER_F35 0xffe0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F35 instead.") #define CLUTTER_R15 0xffe0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R15 instead.") #define CLUTTER_Shift_L 0xffe1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Shift_L instead.") #define CLUTTER_Shift_R 0xffe2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Shift_R instead.") #define CLUTTER_Control_L 0xffe3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Control_L instead.") #define CLUTTER_Control_R 0xffe4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Control_R instead.") #define CLUTTER_Caps_Lock 0xffe5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Caps_Lock instead.") #define CLUTTER_Shift_Lock 0xffe6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Shift_Lock instead.") #define CLUTTER_Meta_L 0xffe7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Meta_L instead.") #define CLUTTER_Meta_R 0xffe8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Meta_R instead.") #define CLUTTER_Alt_L 0xffe9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Alt_L instead.") #define CLUTTER_Alt_R 0xffea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Alt_R instead.") #define CLUTTER_Super_L 0xffeb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Super_L instead.") #define CLUTTER_Super_R 0xffec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Super_R instead.") #define CLUTTER_Hyper_L 0xffed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hyper_L instead.") #define CLUTTER_Hyper_R 0xffee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hyper_R instead.") #define CLUTTER_ISO_Lock 0xfe01 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Lock instead.") #define CLUTTER_ISO_Level2_Latch 0xfe02 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Level2_Latch instead.") #define CLUTTER_ISO_Level3_Shift 0xfe03 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Level3_Shift instead.") #define CLUTTER_ISO_Level3_Latch 0xfe04 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Level3_Latch instead.") #define CLUTTER_ISO_Level3_Lock 0xfe05 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Level3_Lock instead.") #define CLUTTER_ISO_Level5_Shift 0xfe11 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Level5_Shift instead.") #define CLUTTER_ISO_Level5_Latch 0xfe12 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Level5_Latch instead.") #define CLUTTER_ISO_Level5_Lock 0xfe13 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Level5_Lock instead.") #define CLUTTER_ISO_Group_Shift 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Group_Shift instead.") #define CLUTTER_ISO_Group_Latch 0xfe06 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Group_Latch instead.") #define CLUTTER_ISO_Group_Lock 0xfe07 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Group_Lock instead.") #define CLUTTER_ISO_Next_Group 0xfe08 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Next_Group instead.") #define CLUTTER_ISO_Next_Group_Lock 0xfe09 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Next_Group_Lock instead.") #define CLUTTER_ISO_Prev_Group 0xfe0a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Prev_Group instead.") #define CLUTTER_ISO_Prev_Group_Lock 0xfe0b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Prev_Group_Lock instead.") #define CLUTTER_ISO_First_Group 0xfe0c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_First_Group instead.") #define CLUTTER_ISO_First_Group_Lock 0xfe0d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_First_Group_Lock instead.") #define CLUTTER_ISO_Last_Group 0xfe0e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Last_Group instead.") #define CLUTTER_ISO_Last_Group_Lock 0xfe0f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Last_Group_Lock instead.") #define CLUTTER_ISO_Left_Tab 0xfe20 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Left_Tab instead.") #define CLUTTER_ISO_Move_Line_Up 0xfe21 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Move_Line_Up instead.") #define CLUTTER_ISO_Move_Line_Down 0xfe22 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Move_Line_Down instead.") #define CLUTTER_ISO_Partial_Line_Up 0xfe23 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Partial_Line_Up instead.") #define CLUTTER_ISO_Partial_Line_Down 0xfe24 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Partial_Line_Down instead.") #define CLUTTER_ISO_Partial_Space_Left 0xfe25 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Partial_Space_Left instead.") #define CLUTTER_ISO_Partial_Space_Right 0xfe26 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Partial_Space_Right instead.") #define CLUTTER_ISO_Set_Margin_Left 0xfe27 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Set_Margin_Left instead.") #define CLUTTER_ISO_Set_Margin_Right 0xfe28 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Set_Margin_Right instead.") #define CLUTTER_ISO_Release_Margin_Left 0xfe29 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Release_Margin_Left instead.") #define CLUTTER_ISO_Release_Margin_Right 0xfe2a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Release_Margin_Right instead.") #define CLUTTER_ISO_Release_Both_Margins 0xfe2b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Release_Both_Margins instead.") #define CLUTTER_ISO_Fast_Cursor_Left 0xfe2c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Fast_Cursor_Left instead.") #define CLUTTER_ISO_Fast_Cursor_Right 0xfe2d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Fast_Cursor_Right instead.") #define CLUTTER_ISO_Fast_Cursor_Up 0xfe2e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Fast_Cursor_Up instead.") #define CLUTTER_ISO_Fast_Cursor_Down 0xfe2f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Fast_Cursor_Down instead.") #define CLUTTER_ISO_Continuous_Underline 0xfe30 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Continuous_Underline instead.") #define CLUTTER_ISO_Discontinuous_Underline 0xfe31 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Discontinuous_Underline instead.") #define CLUTTER_ISO_Emphasize 0xfe32 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Emphasize instead.") #define CLUTTER_ISO_Center_Object 0xfe33 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Center_Object instead.") #define CLUTTER_ISO_Enter 0xfe34 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ISO_Enter instead.") #define CLUTTER_dead_grave 0xfe50 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_grave instead.") #define CLUTTER_dead_acute 0xfe51 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_acute instead.") #define CLUTTER_dead_circumflex 0xfe52 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_circumflex instead.") #define CLUTTER_dead_tilde 0xfe53 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_tilde instead.") #define CLUTTER_dead_perispomeni 0xfe53 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_perispomeni instead.") #define CLUTTER_dead_macron 0xfe54 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_macron instead.") #define CLUTTER_dead_breve 0xfe55 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_breve instead.") #define CLUTTER_dead_abovedot 0xfe56 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_abovedot instead.") #define CLUTTER_dead_diaeresis 0xfe57 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_diaeresis instead.") #define CLUTTER_dead_abovering 0xfe58 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_abovering instead.") #define CLUTTER_dead_doubleacute 0xfe59 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_doubleacute instead.") #define CLUTTER_dead_caron 0xfe5a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_caron instead.") #define CLUTTER_dead_cedilla 0xfe5b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_cedilla instead.") #define CLUTTER_dead_ogonek 0xfe5c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_ogonek instead.") #define CLUTTER_dead_iota 0xfe5d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_iota instead.") #define CLUTTER_dead_voiced_sound 0xfe5e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_voiced_sound instead.") #define CLUTTER_dead_semivoiced_sound 0xfe5f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_semivoiced_sound instead.") #define CLUTTER_dead_belowdot 0xfe60 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowdot instead.") #define CLUTTER_dead_hook 0xfe61 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_hook instead.") #define CLUTTER_dead_horn 0xfe62 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_horn instead.") #define CLUTTER_dead_stroke 0xfe63 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_stroke instead.") #define CLUTTER_dead_abovecomma 0xfe64 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_abovecomma instead.") #define CLUTTER_dead_psili 0xfe64 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_psili instead.") #define CLUTTER_dead_abovereversedcomma 0xfe65 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_abovereversedcomma instead.") #define CLUTTER_dead_dasia 0xfe65 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_dasia instead.") #define CLUTTER_dead_doublegrave 0xfe66 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_doublegrave instead.") #define CLUTTER_dead_belowring 0xfe67 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowring instead.") #define CLUTTER_dead_belowmacron 0xfe68 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowmacron instead.") #define CLUTTER_dead_belowcircumflex 0xfe69 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowcircumflex instead.") #define CLUTTER_dead_belowtilde 0xfe6a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowtilde instead.") #define CLUTTER_dead_belowbreve 0xfe6b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowbreve instead.") #define CLUTTER_dead_belowdiaeresis 0xfe6c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowdiaeresis instead.") #define CLUTTER_dead_invertedbreve 0xfe6d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_invertedbreve instead.") #define CLUTTER_dead_belowcomma 0xfe6e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowcomma instead.") #define CLUTTER_dead_currency 0xfe6f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_currency instead.") #define CLUTTER_dead_lowline 0xfe90 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_lowline instead.") #define CLUTTER_dead_aboveverticalline 0xfe91 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_aboveverticalline instead.") #define CLUTTER_dead_belowverticalline 0xfe92 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_belowverticalline instead.") #define CLUTTER_dead_longsolidusoverlay 0xfe93 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_longsolidusoverlay instead.") #define CLUTTER_dead_a 0xfe80 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_a instead.") #define CLUTTER_dead_A 0xfe81 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_A instead.") #define CLUTTER_dead_e 0xfe82 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_e instead.") #define CLUTTER_dead_E 0xfe83 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_E instead.") #define CLUTTER_dead_i 0xfe84 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_i instead.") #define CLUTTER_dead_I 0xfe85 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_I instead.") #define CLUTTER_dead_o 0xfe86 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_o instead.") #define CLUTTER_dead_O 0xfe87 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_O instead.") #define CLUTTER_dead_u 0xfe88 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_u instead.") #define CLUTTER_dead_U 0xfe89 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_U instead.") #define CLUTTER_dead_small_schwa 0xfe8a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_small_schwa instead.") #define CLUTTER_dead_capital_schwa 0xfe8b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_capital_schwa instead.") #define CLUTTER_dead_greek 0xfe8c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dead_greek instead.") #define CLUTTER_First_Virtual_Screen 0xfed0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_First_Virtual_Screen instead.") #define CLUTTER_Prev_Virtual_Screen 0xfed1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Prev_Virtual_Screen instead.") #define CLUTTER_Next_Virtual_Screen 0xfed2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Next_Virtual_Screen instead.") #define CLUTTER_Last_Virtual_Screen 0xfed4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Last_Virtual_Screen instead.") #define CLUTTER_Terminate_Server 0xfed5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Terminate_Server instead.") #define CLUTTER_AccessX_Enable 0xfe70 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_AccessX_Enable instead.") #define CLUTTER_AccessX_Feedback_Enable 0xfe71 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_AccessX_Feedback_Enable instead.") #define CLUTTER_RepeatKeys_Enable 0xfe72 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_RepeatKeys_Enable instead.") #define CLUTTER_SlowKeys_Enable 0xfe73 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_SlowKeys_Enable instead.") #define CLUTTER_BounceKeys_Enable 0xfe74 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_BounceKeys_Enable instead.") #define CLUTTER_StickyKeys_Enable 0xfe75 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_StickyKeys_Enable instead.") #define CLUTTER_MouseKeys_Enable 0xfe76 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_MouseKeys_Enable instead.") #define CLUTTER_MouseKeys_Accel_Enable 0xfe77 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_MouseKeys_Accel_Enable instead.") #define CLUTTER_Overlay1_Enable 0xfe78 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Overlay1_Enable instead.") #define CLUTTER_Overlay2_Enable 0xfe79 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Overlay2_Enable instead.") #define CLUTTER_AudibleBell_Enable 0xfe7a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_AudibleBell_Enable instead.") #define CLUTTER_Pointer_Left 0xfee0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Left instead.") #define CLUTTER_Pointer_Right 0xfee1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Right instead.") #define CLUTTER_Pointer_Up 0xfee2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Up instead.") #define CLUTTER_Pointer_Down 0xfee3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Down instead.") #define CLUTTER_Pointer_UpLeft 0xfee4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_UpLeft instead.") #define CLUTTER_Pointer_UpRight 0xfee5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_UpRight instead.") #define CLUTTER_Pointer_DownLeft 0xfee6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DownLeft instead.") #define CLUTTER_Pointer_DownRight 0xfee7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DownRight instead.") #define CLUTTER_Pointer_Button_Dflt 0xfee8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Button_Dflt instead.") #define CLUTTER_Pointer_Button1 0xfee9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Button1 instead.") #define CLUTTER_Pointer_Button2 0xfeea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Button2 instead.") #define CLUTTER_Pointer_Button3 0xfeeb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Button3 instead.") #define CLUTTER_Pointer_Button4 0xfeec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Button4 instead.") #define CLUTTER_Pointer_Button5 0xfeed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Button5 instead.") #define CLUTTER_Pointer_DblClick_Dflt 0xfeee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DblClick_Dflt instead.") #define CLUTTER_Pointer_DblClick1 0xfeef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DblClick1 instead.") #define CLUTTER_Pointer_DblClick2 0xfef0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DblClick2 instead.") #define CLUTTER_Pointer_DblClick3 0xfef1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DblClick3 instead.") #define CLUTTER_Pointer_DblClick4 0xfef2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DblClick4 instead.") #define CLUTTER_Pointer_DblClick5 0xfef3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DblClick5 instead.") #define CLUTTER_Pointer_Drag_Dflt 0xfef4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Drag_Dflt instead.") #define CLUTTER_Pointer_Drag1 0xfef5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Drag1 instead.") #define CLUTTER_Pointer_Drag2 0xfef6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Drag2 instead.") #define CLUTTER_Pointer_Drag3 0xfef7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Drag3 instead.") #define CLUTTER_Pointer_Drag4 0xfef8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Drag4 instead.") #define CLUTTER_Pointer_Drag5 0xfefd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Drag5 instead.") #define CLUTTER_Pointer_EnableKeys 0xfef9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_EnableKeys instead.") #define CLUTTER_Pointer_Accelerate 0xfefa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_Accelerate instead.") #define CLUTTER_Pointer_DfltBtnNext 0xfefb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DfltBtnNext instead.") #define CLUTTER_Pointer_DfltBtnPrev 0xfefc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pointer_DfltBtnPrev instead.") #define CLUTTER_ch 0xfea0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ch instead.") #define CLUTTER_Ch 0xfea1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ch instead.") #define CLUTTER_CH 0xfea2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_CH instead.") #define CLUTTER_c_h 0xfea3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_c_h instead.") #define CLUTTER_C_h 0xfea4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_C_h instead.") #define CLUTTER_C_H 0xfea5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_C_H instead.") #define CLUTTER_3270_Duplicate 0xfd01 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Duplicate instead.") #define CLUTTER_3270_FieldMark 0xfd02 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_FieldMark instead.") #define CLUTTER_3270_Right2 0xfd03 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Right2 instead.") #define CLUTTER_3270_Left2 0xfd04 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Left2 instead.") #define CLUTTER_3270_BackTab 0xfd05 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_BackTab instead.") #define CLUTTER_3270_EraseEOF 0xfd06 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_EraseEOF instead.") #define CLUTTER_3270_EraseInput 0xfd07 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_EraseInput instead.") #define CLUTTER_3270_Reset 0xfd08 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Reset instead.") #define CLUTTER_3270_Quit 0xfd09 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Quit instead.") #define CLUTTER_3270_PA1 0xfd0a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_PA1 instead.") #define CLUTTER_3270_PA2 0xfd0b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_PA2 instead.") #define CLUTTER_3270_PA3 0xfd0c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_PA3 instead.") #define CLUTTER_3270_Test 0xfd0d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Test instead.") #define CLUTTER_3270_Attn 0xfd0e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Attn instead.") #define CLUTTER_3270_CursorBlink 0xfd0f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_CursorBlink instead.") #define CLUTTER_3270_AltCursor 0xfd10 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_AltCursor instead.") #define CLUTTER_3270_KeyClick 0xfd11 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_KeyClick instead.") #define CLUTTER_3270_Jump 0xfd12 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Jump instead.") #define CLUTTER_3270_Ident 0xfd13 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Ident instead.") #define CLUTTER_3270_Rule 0xfd14 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Rule instead.") #define CLUTTER_3270_Copy 0xfd15 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Copy instead.") #define CLUTTER_3270_Play 0xfd16 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Play instead.") #define CLUTTER_3270_Setup 0xfd17 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Setup instead.") #define CLUTTER_3270_Record 0xfd18 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Record instead.") #define CLUTTER_3270_ChangeScreen 0xfd19 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_ChangeScreen instead.") #define CLUTTER_3270_DeleteWord 0xfd1a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_DeleteWord instead.") #define CLUTTER_3270_ExSelect 0xfd1b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_ExSelect instead.") #define CLUTTER_3270_CursorSelect 0xfd1c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_CursorSelect instead.") #define CLUTTER_3270_PrintScreen 0xfd1d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_PrintScreen instead.") #define CLUTTER_3270_Enter 0xfd1e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3270_Enter instead.") #define CLUTTER_space 0x020 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_space instead.") #define CLUTTER_exclam 0x021 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_exclam instead.") #define CLUTTER_quotedbl 0x022 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_quotedbl instead.") #define CLUTTER_numbersign 0x023 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_numbersign instead.") #define CLUTTER_dollar 0x024 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dollar instead.") #define CLUTTER_percent 0x025 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_percent instead.") #define CLUTTER_ampersand 0x026 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ampersand instead.") #define CLUTTER_apostrophe 0x027 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_apostrophe instead.") #define CLUTTER_quoteright 0x027 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_quoteright instead.") #define CLUTTER_parenleft 0x028 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_parenleft instead.") #define CLUTTER_parenright 0x029 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_parenright instead.") #define CLUTTER_asterisk 0x02a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_asterisk instead.") #define CLUTTER_plus 0x02b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_plus instead.") #define CLUTTER_comma 0x02c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_comma instead.") #define CLUTTER_minus 0x02d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_minus instead.") #define CLUTTER_period 0x02e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_period instead.") #define CLUTTER_slash 0x02f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_slash instead.") #define CLUTTER_0 0x030 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_0 instead.") #define CLUTTER_1 0x031 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_1 instead.") #define CLUTTER_2 0x032 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_2 instead.") #define CLUTTER_3 0x033 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_3 instead.") #define CLUTTER_4 0x034 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_4 instead.") #define CLUTTER_5 0x035 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_5 instead.") #define CLUTTER_6 0x036 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_6 instead.") #define CLUTTER_7 0x037 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_7 instead.") #define CLUTTER_8 0x038 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_8 instead.") #define CLUTTER_9 0x039 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_9 instead.") #define CLUTTER_colon 0x03a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_colon instead.") #define CLUTTER_semicolon 0x03b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_semicolon instead.") #define CLUTTER_less 0x03c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_less instead.") #define CLUTTER_equal 0x03d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_equal instead.") #define CLUTTER_greater 0x03e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_greater instead.") #define CLUTTER_question 0x03f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_question instead.") #define CLUTTER_at 0x040 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_at instead.") #define CLUTTER_A 0x041 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_A instead.") #define CLUTTER_B 0x042 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_B instead.") #define CLUTTER_C 0x043 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_C instead.") #define CLUTTER_D 0x044 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_D instead.") #define CLUTTER_E 0x045 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_E instead.") #define CLUTTER_F 0x046 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_F instead.") #define CLUTTER_G 0x047 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_G instead.") #define CLUTTER_H 0x048 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_H instead.") #define CLUTTER_I 0x049 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_I instead.") #define CLUTTER_J 0x04a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_J instead.") #define CLUTTER_K 0x04b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_K instead.") #define CLUTTER_L 0x04c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_L instead.") #define CLUTTER_M 0x04d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_M instead.") #define CLUTTER_N 0x04e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_N instead.") #define CLUTTER_O 0x04f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_O instead.") #define CLUTTER_P 0x050 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_P instead.") #define CLUTTER_Q 0x051 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Q instead.") #define CLUTTER_R 0x052 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_R instead.") #define CLUTTER_S 0x053 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_S instead.") #define CLUTTER_T 0x054 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_T instead.") #define CLUTTER_U 0x055 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_U instead.") #define CLUTTER_V 0x056 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_V instead.") #define CLUTTER_W 0x057 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_W instead.") #define CLUTTER_X 0x058 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_X instead.") #define CLUTTER_Y 0x059 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Y instead.") #define CLUTTER_Z 0x05a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Z instead.") #define CLUTTER_bracketleft 0x05b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_bracketleft instead.") #define CLUTTER_backslash 0x05c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_backslash instead.") #define CLUTTER_bracketright 0x05d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_bracketright instead.") #define CLUTTER_asciicircum 0x05e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_asciicircum instead.") #define CLUTTER_underscore 0x05f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_underscore instead.") #define CLUTTER_grave 0x060 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_grave instead.") #define CLUTTER_quoteleft 0x060 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_quoteleft instead.") #define CLUTTER_a 0x061 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_a instead.") #define CLUTTER_b 0x062 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_b instead.") #define CLUTTER_c 0x063 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_c instead.") #define CLUTTER_d 0x064 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_d instead.") #define CLUTTER_e 0x065 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_e instead.") #define CLUTTER_f 0x066 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_f instead.") #define CLUTTER_g 0x067 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_g instead.") #define CLUTTER_h 0x068 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_h instead.") #define CLUTTER_i 0x069 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_i instead.") #define CLUTTER_j 0x06a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_j instead.") #define CLUTTER_k 0x06b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_k instead.") #define CLUTTER_l 0x06c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_l instead.") #define CLUTTER_m 0x06d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_m instead.") #define CLUTTER_n 0x06e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_n instead.") #define CLUTTER_o 0x06f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_o instead.") #define CLUTTER_p 0x070 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_p instead.") #define CLUTTER_q 0x071 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_q instead.") #define CLUTTER_r 0x072 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_r instead.") #define CLUTTER_s 0x073 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_s instead.") #define CLUTTER_t 0x074 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_t instead.") #define CLUTTER_u 0x075 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_u instead.") #define CLUTTER_v 0x076 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_v instead.") #define CLUTTER_w 0x077 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_w instead.") #define CLUTTER_x 0x078 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_x instead.") #define CLUTTER_y 0x079 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_y instead.") #define CLUTTER_z 0x07a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_z instead.") #define CLUTTER_braceleft 0x07b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braceleft instead.") #define CLUTTER_bar 0x07c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_bar instead.") #define CLUTTER_braceright 0x07d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braceright instead.") #define CLUTTER_asciitilde 0x07e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_asciitilde instead.") #define CLUTTER_nobreakspace 0x0a0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_nobreakspace instead.") #define CLUTTER_exclamdown 0x0a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_exclamdown instead.") #define CLUTTER_cent 0x0a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_cent instead.") #define CLUTTER_sterling 0x0a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_sterling instead.") #define CLUTTER_currency 0x0a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_currency instead.") #define CLUTTER_yen 0x0a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_yen instead.") #define CLUTTER_brokenbar 0x0a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_brokenbar instead.") #define CLUTTER_section 0x0a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_section instead.") #define CLUTTER_diaeresis 0x0a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_diaeresis instead.") #define CLUTTER_copyright 0x0a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_copyright instead.") #define CLUTTER_ordfeminine 0x0aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ordfeminine instead.") #define CLUTTER_guillemotleft 0x0ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_guillemotleft instead.") #define CLUTTER_notsign 0x0ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_notsign instead.") #define CLUTTER_hyphen 0x0ad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hyphen instead.") #define CLUTTER_registered 0x0ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_registered instead.") #define CLUTTER_macron 0x0af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_macron instead.") #define CLUTTER_degree 0x0b0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_degree instead.") #define CLUTTER_plusminus 0x0b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_plusminus instead.") #define CLUTTER_twosuperior 0x0b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_twosuperior instead.") #define CLUTTER_threesuperior 0x0b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_threesuperior instead.") #define CLUTTER_acute 0x0b4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_acute instead.") #define CLUTTER_mu 0x0b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_mu instead.") #define CLUTTER_paragraph 0x0b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_paragraph instead.") #define CLUTTER_periodcentered 0x0b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_periodcentered instead.") #define CLUTTER_cedilla 0x0b8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_cedilla instead.") #define CLUTTER_onesuperior 0x0b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_onesuperior instead.") #define CLUTTER_masculine 0x0ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_masculine instead.") #define CLUTTER_guillemotright 0x0bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_guillemotright instead.") #define CLUTTER_onequarter 0x0bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_onequarter instead.") #define CLUTTER_onehalf 0x0bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_onehalf instead.") #define CLUTTER_threequarters 0x0be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_threequarters instead.") #define CLUTTER_questiondown 0x0bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_questiondown instead.") #define CLUTTER_Agrave 0x0c0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Agrave instead.") #define CLUTTER_Aacute 0x0c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Aacute instead.") #define CLUTTER_Acircumflex 0x0c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Acircumflex instead.") #define CLUTTER_Atilde 0x0c3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Atilde instead.") #define CLUTTER_Adiaeresis 0x0c4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Adiaeresis instead.") #define CLUTTER_Aring 0x0c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Aring instead.") #define CLUTTER_AE 0x0c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_AE instead.") #define CLUTTER_Ccedilla 0x0c7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ccedilla instead.") #define CLUTTER_Egrave 0x0c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Egrave instead.") #define CLUTTER_Eacute 0x0c9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Eacute instead.") #define CLUTTER_Ecircumflex 0x0ca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ecircumflex instead.") #define CLUTTER_Ediaeresis 0x0cb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ediaeresis instead.") #define CLUTTER_Igrave 0x0cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Igrave instead.") #define CLUTTER_Iacute 0x0cd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Iacute instead.") #define CLUTTER_Icircumflex 0x0ce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Icircumflex instead.") #define CLUTTER_Idiaeresis 0x0cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Idiaeresis instead.") #define CLUTTER_ETH 0x0d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ETH instead.") #define CLUTTER_Eth 0x0d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Eth instead.") #define CLUTTER_Ntilde 0x0d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ntilde instead.") #define CLUTTER_Ograve 0x0d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ograve instead.") #define CLUTTER_Oacute 0x0d3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Oacute instead.") #define CLUTTER_Ocircumflex 0x0d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ocircumflex instead.") #define CLUTTER_Otilde 0x0d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Otilde instead.") #define CLUTTER_Odiaeresis 0x0d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Odiaeresis instead.") #define CLUTTER_multiply 0x0d7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_multiply instead.") #define CLUTTER_Oslash 0x0d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Oslash instead.") #define CLUTTER_Ooblique 0x0d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ooblique instead.") #define CLUTTER_Ugrave 0x0d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ugrave instead.") #define CLUTTER_Uacute 0x0da CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uacute instead.") #define CLUTTER_Ucircumflex 0x0db CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ucircumflex instead.") #define CLUTTER_Udiaeresis 0x0dc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Udiaeresis instead.") #define CLUTTER_Yacute 0x0dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Yacute instead.") #define CLUTTER_THORN 0x0de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_THORN instead.") #define CLUTTER_Thorn 0x0de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thorn instead.") #define CLUTTER_ssharp 0x0df CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ssharp instead.") #define CLUTTER_agrave 0x0e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_agrave instead.") #define CLUTTER_aacute 0x0e1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_aacute instead.") #define CLUTTER_acircumflex 0x0e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_acircumflex instead.") #define CLUTTER_atilde 0x0e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_atilde instead.") #define CLUTTER_adiaeresis 0x0e4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_adiaeresis instead.") #define CLUTTER_aring 0x0e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_aring instead.") #define CLUTTER_ae 0x0e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ae instead.") #define CLUTTER_ccedilla 0x0e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ccedilla instead.") #define CLUTTER_egrave 0x0e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_egrave instead.") #define CLUTTER_eacute 0x0e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_eacute instead.") #define CLUTTER_ecircumflex 0x0ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ecircumflex instead.") #define CLUTTER_ediaeresis 0x0eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ediaeresis instead.") #define CLUTTER_igrave 0x0ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_igrave instead.") #define CLUTTER_iacute 0x0ed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_iacute instead.") #define CLUTTER_icircumflex 0x0ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_icircumflex instead.") #define CLUTTER_idiaeresis 0x0ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_idiaeresis instead.") #define CLUTTER_eth 0x0f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_eth instead.") #define CLUTTER_ntilde 0x0f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ntilde instead.") #define CLUTTER_ograve 0x0f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ograve instead.") #define CLUTTER_oacute 0x0f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_oacute instead.") #define CLUTTER_ocircumflex 0x0f4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ocircumflex instead.") #define CLUTTER_otilde 0x0f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_otilde instead.") #define CLUTTER_odiaeresis 0x0f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_odiaeresis instead.") #define CLUTTER_division 0x0f7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_division instead.") #define CLUTTER_oslash 0x0f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_oslash instead.") #define CLUTTER_ooblique 0x0f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ooblique instead.") #define CLUTTER_ugrave 0x0f9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ugrave instead.") #define CLUTTER_uacute 0x0fa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uacute instead.") #define CLUTTER_ucircumflex 0x0fb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ucircumflex instead.") #define CLUTTER_udiaeresis 0x0fc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_udiaeresis instead.") #define CLUTTER_yacute 0x0fd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_yacute instead.") #define CLUTTER_thorn 0x0fe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_thorn instead.") #define CLUTTER_ydiaeresis 0x0ff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ydiaeresis instead.") #define CLUTTER_Aogonek 0x1a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Aogonek instead.") #define CLUTTER_breve 0x1a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_breve instead.") #define CLUTTER_Lstroke 0x1a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Lstroke instead.") #define CLUTTER_Lcaron 0x1a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Lcaron instead.") #define CLUTTER_Sacute 0x1a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sacute instead.") #define CLUTTER_Scaron 0x1a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Scaron instead.") #define CLUTTER_Scedilla 0x1aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Scedilla instead.") #define CLUTTER_Tcaron 0x1ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Tcaron instead.") #define CLUTTER_Zacute 0x1ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Zacute instead.") #define CLUTTER_Zcaron 0x1ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Zcaron instead.") #define CLUTTER_Zabovedot 0x1af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Zabovedot instead.") #define CLUTTER_aogonek 0x1b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_aogonek instead.") #define CLUTTER_ogonek 0x1b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ogonek instead.") #define CLUTTER_lstroke 0x1b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lstroke instead.") #define CLUTTER_lcaron 0x1b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lcaron instead.") #define CLUTTER_sacute 0x1b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_sacute instead.") #define CLUTTER_caron 0x1b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_caron instead.") #define CLUTTER_scaron 0x1b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_scaron instead.") #define CLUTTER_scedilla 0x1ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_scedilla instead.") #define CLUTTER_tcaron 0x1bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_tcaron instead.") #define CLUTTER_zacute 0x1bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_zacute instead.") #define CLUTTER_doubleacute 0x1bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_doubleacute instead.") #define CLUTTER_zcaron 0x1be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_zcaron instead.") #define CLUTTER_zabovedot 0x1bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_zabovedot instead.") #define CLUTTER_Racute 0x1c0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Racute instead.") #define CLUTTER_Abreve 0x1c3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Abreve instead.") #define CLUTTER_Lacute 0x1c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Lacute instead.") #define CLUTTER_Cacute 0x1c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cacute instead.") #define CLUTTER_Ccaron 0x1c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ccaron instead.") #define CLUTTER_Eogonek 0x1ca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Eogonek instead.") #define CLUTTER_Ecaron 0x1cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ecaron instead.") #define CLUTTER_Dcaron 0x1cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Dcaron instead.") #define CLUTTER_Dstroke 0x1d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Dstroke instead.") #define CLUTTER_Nacute 0x1d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Nacute instead.") #define CLUTTER_Ncaron 0x1d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ncaron instead.") #define CLUTTER_Odoubleacute 0x1d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Odoubleacute instead.") #define CLUTTER_Rcaron 0x1d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Rcaron instead.") #define CLUTTER_Uring 0x1d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uring instead.") #define CLUTTER_Udoubleacute 0x1db CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Udoubleacute instead.") #define CLUTTER_Tcedilla 0x1de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Tcedilla instead.") #define CLUTTER_racute 0x1e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_racute instead.") #define CLUTTER_abreve 0x1e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abreve instead.") #define CLUTTER_lacute 0x1e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lacute instead.") #define CLUTTER_cacute 0x1e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_cacute instead.") #define CLUTTER_ccaron 0x1e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ccaron instead.") #define CLUTTER_eogonek 0x1ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_eogonek instead.") #define CLUTTER_ecaron 0x1ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ecaron instead.") #define CLUTTER_dcaron 0x1ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dcaron instead.") #define CLUTTER_dstroke 0x1f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dstroke instead.") #define CLUTTER_nacute 0x1f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_nacute instead.") #define CLUTTER_ncaron 0x1f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ncaron instead.") #define CLUTTER_odoubleacute 0x1f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_odoubleacute instead.") #define CLUTTER_rcaron 0x1f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rcaron instead.") #define CLUTTER_uring 0x1f9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uring instead.") #define CLUTTER_udoubleacute 0x1fb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_udoubleacute instead.") #define CLUTTER_tcedilla 0x1fe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_tcedilla instead.") #define CLUTTER_abovedot 0x1ff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abovedot instead.") #define CLUTTER_Hstroke 0x2a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hstroke instead.") #define CLUTTER_Hcircumflex 0x2a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hcircumflex instead.") #define CLUTTER_Iabovedot 0x2a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Iabovedot instead.") #define CLUTTER_Gbreve 0x2ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Gbreve instead.") #define CLUTTER_Jcircumflex 0x2ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Jcircumflex instead.") #define CLUTTER_hstroke 0x2b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hstroke instead.") #define CLUTTER_hcircumflex 0x2b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hcircumflex instead.") #define CLUTTER_idotless 0x2b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_idotless instead.") #define CLUTTER_gbreve 0x2bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_gbreve instead.") #define CLUTTER_jcircumflex 0x2bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_jcircumflex instead.") #define CLUTTER_Cabovedot 0x2c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cabovedot instead.") #define CLUTTER_Ccircumflex 0x2c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ccircumflex instead.") #define CLUTTER_Gabovedot 0x2d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Gabovedot instead.") #define CLUTTER_Gcircumflex 0x2d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Gcircumflex instead.") #define CLUTTER_Ubreve 0x2dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ubreve instead.") #define CLUTTER_Scircumflex 0x2de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Scircumflex instead.") #define CLUTTER_cabovedot 0x2e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_cabovedot instead.") #define CLUTTER_ccircumflex 0x2e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ccircumflex instead.") #define CLUTTER_gabovedot 0x2f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_gabovedot instead.") #define CLUTTER_gcircumflex 0x2f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_gcircumflex instead.") #define CLUTTER_ubreve 0x2fd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ubreve instead.") #define CLUTTER_scircumflex 0x2fe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_scircumflex instead.") #define CLUTTER_kra 0x3a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kra instead.") #define CLUTTER_kappa 0x3a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kappa instead.") #define CLUTTER_Rcedilla 0x3a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Rcedilla instead.") #define CLUTTER_Itilde 0x3a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Itilde instead.") #define CLUTTER_Lcedilla 0x3a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Lcedilla instead.") #define CLUTTER_Emacron 0x3aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Emacron instead.") #define CLUTTER_Gcedilla 0x3ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Gcedilla instead.") #define CLUTTER_Tslash 0x3ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Tslash instead.") #define CLUTTER_rcedilla 0x3b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rcedilla instead.") #define CLUTTER_itilde 0x3b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_itilde instead.") #define CLUTTER_lcedilla 0x3b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lcedilla instead.") #define CLUTTER_emacron 0x3ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emacron instead.") #define CLUTTER_gcedilla 0x3bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_gcedilla instead.") #define CLUTTER_tslash 0x3bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_tslash instead.") #define CLUTTER_ENG 0x3bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ENG instead.") #define CLUTTER_eng 0x3bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_eng instead.") #define CLUTTER_Amacron 0x3c0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Amacron instead.") #define CLUTTER_Iogonek 0x3c7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Iogonek instead.") #define CLUTTER_Eabovedot 0x3cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Eabovedot instead.") #define CLUTTER_Imacron 0x3cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Imacron instead.") #define CLUTTER_Ncedilla 0x3d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ncedilla instead.") #define CLUTTER_Omacron 0x3d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Omacron instead.") #define CLUTTER_Kcedilla 0x3d3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Kcedilla instead.") #define CLUTTER_Uogonek 0x3d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uogonek instead.") #define CLUTTER_Utilde 0x3dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Utilde instead.") #define CLUTTER_Umacron 0x3de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Umacron instead.") #define CLUTTER_amacron 0x3e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_amacron instead.") #define CLUTTER_iogonek 0x3e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_iogonek instead.") #define CLUTTER_eabovedot 0x3ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_eabovedot instead.") #define CLUTTER_imacron 0x3ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_imacron instead.") #define CLUTTER_ncedilla 0x3f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ncedilla instead.") #define CLUTTER_omacron 0x3f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_omacron instead.") #define CLUTTER_kcedilla 0x3f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kcedilla instead.") #define CLUTTER_uogonek 0x3f9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uogonek instead.") #define CLUTTER_utilde 0x3fd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_utilde instead.") #define CLUTTER_umacron 0x3fe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_umacron instead.") #define CLUTTER_Wcircumflex 0x1000174 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Wcircumflex instead.") #define CLUTTER_wcircumflex 0x1000175 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_wcircumflex instead.") #define CLUTTER_Ycircumflex 0x1000176 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ycircumflex instead.") #define CLUTTER_ycircumflex 0x1000177 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ycircumflex instead.") #define CLUTTER_Babovedot 0x1001e02 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Babovedot instead.") #define CLUTTER_babovedot 0x1001e03 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_babovedot instead.") #define CLUTTER_Dabovedot 0x1001e0a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Dabovedot instead.") #define CLUTTER_dabovedot 0x1001e0b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dabovedot instead.") #define CLUTTER_Fabovedot 0x1001e1e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Fabovedot instead.") #define CLUTTER_fabovedot 0x1001e1f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_fabovedot instead.") #define CLUTTER_Mabovedot 0x1001e40 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Mabovedot instead.") #define CLUTTER_mabovedot 0x1001e41 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_mabovedot instead.") #define CLUTTER_Pabovedot 0x1001e56 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Pabovedot instead.") #define CLUTTER_pabovedot 0x1001e57 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_pabovedot instead.") #define CLUTTER_Sabovedot 0x1001e60 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sabovedot instead.") #define CLUTTER_sabovedot 0x1001e61 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_sabovedot instead.") #define CLUTTER_Tabovedot 0x1001e6a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Tabovedot instead.") #define CLUTTER_tabovedot 0x1001e6b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_tabovedot instead.") #define CLUTTER_Wgrave 0x1001e80 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Wgrave instead.") #define CLUTTER_wgrave 0x1001e81 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_wgrave instead.") #define CLUTTER_Wacute 0x1001e82 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Wacute instead.") #define CLUTTER_wacute 0x1001e83 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_wacute instead.") #define CLUTTER_Wdiaeresis 0x1001e84 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Wdiaeresis instead.") #define CLUTTER_wdiaeresis 0x1001e85 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_wdiaeresis instead.") #define CLUTTER_Ygrave 0x1001ef2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ygrave instead.") #define CLUTTER_ygrave 0x1001ef3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ygrave instead.") #define CLUTTER_OE 0x13bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_OE instead.") #define CLUTTER_oe 0x13bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_oe instead.") #define CLUTTER_Ydiaeresis 0x13be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ydiaeresis instead.") #define CLUTTER_overline 0x47e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_overline instead.") #define CLUTTER_kana_fullstop 0x4a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_fullstop instead.") #define CLUTTER_kana_openingbracket 0x4a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_openingbracket instead.") #define CLUTTER_kana_closingbracket 0x4a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_closingbracket instead.") #define CLUTTER_kana_comma 0x4a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_comma instead.") #define CLUTTER_kana_conjunctive 0x4a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_conjunctive instead.") #define CLUTTER_kana_middledot 0x4a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_middledot instead.") #define CLUTTER_kana_WO 0x4a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_WO instead.") #define CLUTTER_kana_a 0x4a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_a instead.") #define CLUTTER_kana_i 0x4a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_i instead.") #define CLUTTER_kana_u 0x4a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_u instead.") #define CLUTTER_kana_e 0x4aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_e instead.") #define CLUTTER_kana_o 0x4ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_o instead.") #define CLUTTER_kana_ya 0x4ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_ya instead.") #define CLUTTER_kana_yu 0x4ad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_yu instead.") #define CLUTTER_kana_yo 0x4ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_yo instead.") #define CLUTTER_kana_tsu 0x4af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_tsu instead.") #define CLUTTER_kana_tu 0x4af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_tu instead.") #define CLUTTER_prolongedsound 0x4b0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_prolongedsound instead.") #define CLUTTER_kana_A 0x4b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_A instead.") #define CLUTTER_kana_I 0x4b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_I instead.") #define CLUTTER_kana_U 0x4b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_U instead.") #define CLUTTER_kana_E 0x4b4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_E instead.") #define CLUTTER_kana_O 0x4b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_O instead.") #define CLUTTER_kana_KA 0x4b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_KA instead.") #define CLUTTER_kana_KI 0x4b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_KI instead.") #define CLUTTER_kana_KU 0x4b8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_KU instead.") #define CLUTTER_kana_KE 0x4b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_KE instead.") #define CLUTTER_kana_KO 0x4ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_KO instead.") #define CLUTTER_kana_SA 0x4bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_SA instead.") #define CLUTTER_kana_SHI 0x4bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_SHI instead.") #define CLUTTER_kana_SU 0x4bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_SU instead.") #define CLUTTER_kana_SE 0x4be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_SE instead.") #define CLUTTER_kana_SO 0x4bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_SO instead.") #define CLUTTER_kana_TA 0x4c0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_TA instead.") #define CLUTTER_kana_CHI 0x4c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_CHI instead.") #define CLUTTER_kana_TI 0x4c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_TI instead.") #define CLUTTER_kana_TSU 0x4c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_TSU instead.") #define CLUTTER_kana_TU 0x4c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_TU instead.") #define CLUTTER_kana_TE 0x4c3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_TE instead.") #define CLUTTER_kana_TO 0x4c4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_TO instead.") #define CLUTTER_kana_NA 0x4c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_NA instead.") #define CLUTTER_kana_NI 0x4c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_NI instead.") #define CLUTTER_kana_NU 0x4c7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_NU instead.") #define CLUTTER_kana_NE 0x4c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_NE instead.") #define CLUTTER_kana_NO 0x4c9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_NO instead.") #define CLUTTER_kana_HA 0x4ca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_HA instead.") #define CLUTTER_kana_HI 0x4cb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_HI instead.") #define CLUTTER_kana_FU 0x4cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_FU instead.") #define CLUTTER_kana_HU 0x4cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_HU instead.") #define CLUTTER_kana_HE 0x4cd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_HE instead.") #define CLUTTER_kana_HO 0x4ce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_HO instead.") #define CLUTTER_kana_MA 0x4cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_MA instead.") #define CLUTTER_kana_MI 0x4d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_MI instead.") #define CLUTTER_kana_MU 0x4d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_MU instead.") #define CLUTTER_kana_ME 0x4d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_ME instead.") #define CLUTTER_kana_MO 0x4d3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_MO instead.") #define CLUTTER_kana_YA 0x4d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_YA instead.") #define CLUTTER_kana_YU 0x4d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_YU instead.") #define CLUTTER_kana_YO 0x4d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_YO instead.") #define CLUTTER_kana_RA 0x4d7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_RA instead.") #define CLUTTER_kana_RI 0x4d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_RI instead.") #define CLUTTER_kana_RU 0x4d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_RU instead.") #define CLUTTER_kana_RE 0x4da CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_RE instead.") #define CLUTTER_kana_RO 0x4db CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_RO instead.") #define CLUTTER_kana_WA 0x4dc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_WA instead.") #define CLUTTER_kana_N 0x4dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_N instead.") #define CLUTTER_voicedsound 0x4de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_voicedsound instead.") #define CLUTTER_semivoicedsound 0x4df CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_semivoicedsound instead.") #define CLUTTER_kana_switch 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_kana_switch instead.") #define CLUTTER_Farsi_0 0x10006f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_0 instead.") #define CLUTTER_Farsi_1 0x10006f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_1 instead.") #define CLUTTER_Farsi_2 0x10006f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_2 instead.") #define CLUTTER_Farsi_3 0x10006f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_3 instead.") #define CLUTTER_Farsi_4 0x10006f4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_4 instead.") #define CLUTTER_Farsi_5 0x10006f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_5 instead.") #define CLUTTER_Farsi_6 0x10006f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_6 instead.") #define CLUTTER_Farsi_7 0x10006f7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_7 instead.") #define CLUTTER_Farsi_8 0x10006f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_8 instead.") #define CLUTTER_Farsi_9 0x10006f9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_9 instead.") #define CLUTTER_Arabic_percent 0x100066a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_percent instead.") #define CLUTTER_Arabic_superscript_alef 0x1000670 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_superscript_alef instead.") #define CLUTTER_Arabic_tteh 0x1000679 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_tteh instead.") #define CLUTTER_Arabic_peh 0x100067e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_peh instead.") #define CLUTTER_Arabic_tcheh 0x1000686 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_tcheh instead.") #define CLUTTER_Arabic_ddal 0x1000688 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_ddal instead.") #define CLUTTER_Arabic_rreh 0x1000691 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_rreh instead.") #define CLUTTER_Arabic_comma 0x5ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_comma instead.") #define CLUTTER_Arabic_fullstop 0x10006d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_fullstop instead.") #define CLUTTER_Arabic_0 0x1000660 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_0 instead.") #define CLUTTER_Arabic_1 0x1000661 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_1 instead.") #define CLUTTER_Arabic_2 0x1000662 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_2 instead.") #define CLUTTER_Arabic_3 0x1000663 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_3 instead.") #define CLUTTER_Arabic_4 0x1000664 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_4 instead.") #define CLUTTER_Arabic_5 0x1000665 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_5 instead.") #define CLUTTER_Arabic_6 0x1000666 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_6 instead.") #define CLUTTER_Arabic_7 0x1000667 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_7 instead.") #define CLUTTER_Arabic_8 0x1000668 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_8 instead.") #define CLUTTER_Arabic_9 0x1000669 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_9 instead.") #define CLUTTER_Arabic_semicolon 0x5bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_semicolon instead.") #define CLUTTER_Arabic_question_mark 0x5bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_question_mark instead.") #define CLUTTER_Arabic_hamza 0x5c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hamza instead.") #define CLUTTER_Arabic_maddaonalef 0x5c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_maddaonalef instead.") #define CLUTTER_Arabic_hamzaonalef 0x5c3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hamzaonalef instead.") #define CLUTTER_Arabic_hamzaonwaw 0x5c4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hamzaonwaw instead.") #define CLUTTER_Arabic_hamzaunderalef 0x5c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hamzaunderalef instead.") #define CLUTTER_Arabic_hamzaonyeh 0x5c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hamzaonyeh instead.") #define CLUTTER_Arabic_alef 0x5c7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_alef instead.") #define CLUTTER_Arabic_beh 0x5c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_beh instead.") #define CLUTTER_Arabic_tehmarbuta 0x5c9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_tehmarbuta instead.") #define CLUTTER_Arabic_teh 0x5ca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_teh instead.") #define CLUTTER_Arabic_theh 0x5cb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_theh instead.") #define CLUTTER_Arabic_jeem 0x5cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_jeem instead.") #define CLUTTER_Arabic_hah 0x5cd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hah instead.") #define CLUTTER_Arabic_khah 0x5ce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_khah instead.") #define CLUTTER_Arabic_dal 0x5cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_dal instead.") #define CLUTTER_Arabic_thal 0x5d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_thal instead.") #define CLUTTER_Arabic_ra 0x5d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_ra instead.") #define CLUTTER_Arabic_zain 0x5d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_zain instead.") #define CLUTTER_Arabic_seen 0x5d3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_seen instead.") #define CLUTTER_Arabic_sheen 0x5d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_sheen instead.") #define CLUTTER_Arabic_sad 0x5d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_sad instead.") #define CLUTTER_Arabic_dad 0x5d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_dad instead.") #define CLUTTER_Arabic_tah 0x5d7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_tah instead.") #define CLUTTER_Arabic_zah 0x5d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_zah instead.") #define CLUTTER_Arabic_ain 0x5d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_ain instead.") #define CLUTTER_Arabic_ghain 0x5da CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_ghain instead.") #define CLUTTER_Arabic_tatweel 0x5e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_tatweel instead.") #define CLUTTER_Arabic_feh 0x5e1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_feh instead.") #define CLUTTER_Arabic_qaf 0x5e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_qaf instead.") #define CLUTTER_Arabic_kaf 0x5e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_kaf instead.") #define CLUTTER_Arabic_lam 0x5e4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_lam instead.") #define CLUTTER_Arabic_meem 0x5e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_meem instead.") #define CLUTTER_Arabic_noon 0x5e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_noon instead.") #define CLUTTER_Arabic_ha 0x5e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_ha instead.") #define CLUTTER_Arabic_heh 0x5e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_heh instead.") #define CLUTTER_Arabic_waw 0x5e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_waw instead.") #define CLUTTER_Arabic_alefmaksura 0x5e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_alefmaksura instead.") #define CLUTTER_Arabic_yeh 0x5ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_yeh instead.") #define CLUTTER_Arabic_fathatan 0x5eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_fathatan instead.") #define CLUTTER_Arabic_dammatan 0x5ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_dammatan instead.") #define CLUTTER_Arabic_kasratan 0x5ed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_kasratan instead.") #define CLUTTER_Arabic_fatha 0x5ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_fatha instead.") #define CLUTTER_Arabic_damma 0x5ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_damma instead.") #define CLUTTER_Arabic_kasra 0x5f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_kasra instead.") #define CLUTTER_Arabic_shadda 0x5f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_shadda instead.") #define CLUTTER_Arabic_sukun 0x5f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_sukun instead.") #define CLUTTER_Arabic_madda_above 0x1000653 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_madda_above instead.") #define CLUTTER_Arabic_hamza_above 0x1000654 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hamza_above instead.") #define CLUTTER_Arabic_hamza_below 0x1000655 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_hamza_below instead.") #define CLUTTER_Arabic_jeh 0x1000698 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_jeh instead.") #define CLUTTER_Arabic_veh 0x10006a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_veh instead.") #define CLUTTER_Arabic_keheh 0x10006a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_keheh instead.") #define CLUTTER_Arabic_gaf 0x10006af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_gaf instead.") #define CLUTTER_Arabic_noon_ghunna 0x10006ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_noon_ghunna instead.") #define CLUTTER_Arabic_heh_doachashmee 0x10006be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_heh_doachashmee instead.") #define CLUTTER_Farsi_yeh 0x10006cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Farsi_yeh instead.") #define CLUTTER_Arabic_farsi_yeh 0x10006cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_farsi_yeh instead.") #define CLUTTER_Arabic_yeh_baree 0x10006d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_yeh_baree instead.") #define CLUTTER_Arabic_heh_goal 0x10006c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_heh_goal instead.") #define CLUTTER_Arabic_switch 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Arabic_switch instead.") #define CLUTTER_Cyrillic_GHE_bar 0x1000492 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_GHE_bar instead.") #define CLUTTER_Cyrillic_ghe_bar 0x1000493 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ghe_bar instead.") #define CLUTTER_Cyrillic_ZHE_descender 0x1000496 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ZHE_descender instead.") #define CLUTTER_Cyrillic_zhe_descender 0x1000497 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_zhe_descender instead.") #define CLUTTER_Cyrillic_KA_descender 0x100049a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_KA_descender instead.") #define CLUTTER_Cyrillic_ka_descender 0x100049b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ka_descender instead.") #define CLUTTER_Cyrillic_KA_vertstroke 0x100049c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_KA_vertstroke instead.") #define CLUTTER_Cyrillic_ka_vertstroke 0x100049d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ka_vertstroke instead.") #define CLUTTER_Cyrillic_EN_descender 0x10004a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_EN_descender instead.") #define CLUTTER_Cyrillic_en_descender 0x10004a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_en_descender instead.") #define CLUTTER_Cyrillic_U_straight 0x10004ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_U_straight instead.") #define CLUTTER_Cyrillic_u_straight 0x10004af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_u_straight instead.") #define CLUTTER_Cyrillic_U_straight_bar 0x10004b0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_U_straight_bar instead.") #define CLUTTER_Cyrillic_u_straight_bar 0x10004b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_u_straight_bar instead.") #define CLUTTER_Cyrillic_HA_descender 0x10004b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_HA_descender instead.") #define CLUTTER_Cyrillic_ha_descender 0x10004b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ha_descender instead.") #define CLUTTER_Cyrillic_CHE_descender 0x10004b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_CHE_descender instead.") #define CLUTTER_Cyrillic_che_descender 0x10004b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_che_descender instead.") #define CLUTTER_Cyrillic_CHE_vertstroke 0x10004b8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_CHE_vertstroke instead.") #define CLUTTER_Cyrillic_che_vertstroke 0x10004b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_che_vertstroke instead.") #define CLUTTER_Cyrillic_SHHA 0x10004ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_SHHA instead.") #define CLUTTER_Cyrillic_shha 0x10004bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_shha instead.") #define CLUTTER_Cyrillic_SCHWA 0x10004d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_SCHWA instead.") #define CLUTTER_Cyrillic_schwa 0x10004d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_schwa instead.") #define CLUTTER_Cyrillic_I_macron 0x10004e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_I_macron instead.") #define CLUTTER_Cyrillic_i_macron 0x10004e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_i_macron instead.") #define CLUTTER_Cyrillic_O_bar 0x10004e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_O_bar instead.") #define CLUTTER_Cyrillic_o_bar 0x10004e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_o_bar instead.") #define CLUTTER_Cyrillic_U_macron 0x10004ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_U_macron instead.") #define CLUTTER_Cyrillic_u_macron 0x10004ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_u_macron instead.") #define CLUTTER_Serbian_dje 0x6a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_dje instead.") #define CLUTTER_Macedonia_gje 0x6a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Macedonia_gje instead.") #define CLUTTER_Cyrillic_io 0x6a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_io instead.") #define CLUTTER_Ukrainian_ie 0x6a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_ie instead.") #define CLUTTER_Ukranian_je 0x6a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukranian_je instead.") #define CLUTTER_Macedonia_dse 0x6a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Macedonia_dse instead.") #define CLUTTER_Ukrainian_i 0x6a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_i instead.") #define CLUTTER_Ukranian_i 0x6a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukranian_i instead.") #define CLUTTER_Ukrainian_yi 0x6a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_yi instead.") #define CLUTTER_Ukranian_yi 0x6a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukranian_yi instead.") #define CLUTTER_Cyrillic_je 0x6a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_je instead.") #define CLUTTER_Serbian_je 0x6a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_je instead.") #define CLUTTER_Cyrillic_lje 0x6a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_lje instead.") #define CLUTTER_Serbian_lje 0x6a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_lje instead.") #define CLUTTER_Cyrillic_nje 0x6aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_nje instead.") #define CLUTTER_Serbian_nje 0x6aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_nje instead.") #define CLUTTER_Serbian_tshe 0x6ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_tshe instead.") #define CLUTTER_Macedonia_kje 0x6ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Macedonia_kje instead.") #define CLUTTER_Ukrainian_ghe_with_upturn 0x6ad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_ghe_with_upturn instead.") #define CLUTTER_Byelorussian_shortu 0x6ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Byelorussian_shortu instead.") #define CLUTTER_Cyrillic_dzhe 0x6af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_dzhe instead.") #define CLUTTER_Serbian_dze 0x6af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_dze instead.") #define CLUTTER_numerosign 0x6b0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_numerosign instead.") #define CLUTTER_Serbian_DJE 0x6b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_DJE instead.") #define CLUTTER_Macedonia_GJE 0x6b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Macedonia_GJE instead.") #define CLUTTER_Cyrillic_IO 0x6b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_IO instead.") #define CLUTTER_Ukrainian_IE 0x6b4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_IE instead.") #define CLUTTER_Ukranian_JE 0x6b4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukranian_JE instead.") #define CLUTTER_Macedonia_DSE 0x6b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Macedonia_DSE instead.") #define CLUTTER_Ukrainian_I 0x6b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_I instead.") #define CLUTTER_Ukranian_I 0x6b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukranian_I instead.") #define CLUTTER_Ukrainian_YI 0x6b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_YI instead.") #define CLUTTER_Ukranian_YI 0x6b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukranian_YI instead.") #define CLUTTER_Cyrillic_JE 0x6b8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_JE instead.") #define CLUTTER_Serbian_JE 0x6b8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_JE instead.") #define CLUTTER_Cyrillic_LJE 0x6b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_LJE instead.") #define CLUTTER_Serbian_LJE 0x6b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_LJE instead.") #define CLUTTER_Cyrillic_NJE 0x6ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_NJE instead.") #define CLUTTER_Serbian_NJE 0x6ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_NJE instead.") #define CLUTTER_Serbian_TSHE 0x6bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_TSHE instead.") #define CLUTTER_Macedonia_KJE 0x6bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Macedonia_KJE instead.") #define CLUTTER_Ukrainian_GHE_WITH_UPTURN 0x6bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ukrainian_GHE_WITH_UPTURN instead.") #define CLUTTER_Byelorussian_SHORTU 0x6be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Byelorussian_SHORTU instead.") #define CLUTTER_Cyrillic_DZHE 0x6bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_DZHE instead.") #define CLUTTER_Serbian_DZE 0x6bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Serbian_DZE instead.") #define CLUTTER_Cyrillic_yu 0x6c0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_yu instead.") #define CLUTTER_Cyrillic_a 0x6c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_a instead.") #define CLUTTER_Cyrillic_be 0x6c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_be instead.") #define CLUTTER_Cyrillic_tse 0x6c3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_tse instead.") #define CLUTTER_Cyrillic_de 0x6c4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_de instead.") #define CLUTTER_Cyrillic_ie 0x6c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ie instead.") #define CLUTTER_Cyrillic_ef 0x6c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ef instead.") #define CLUTTER_Cyrillic_ghe 0x6c7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ghe instead.") #define CLUTTER_Cyrillic_ha 0x6c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ha instead.") #define CLUTTER_Cyrillic_i 0x6c9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_i instead.") #define CLUTTER_Cyrillic_shorti 0x6ca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_shorti instead.") #define CLUTTER_Cyrillic_ka 0x6cb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ka instead.") #define CLUTTER_Cyrillic_el 0x6cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_el instead.") #define CLUTTER_Cyrillic_em 0x6cd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_em instead.") #define CLUTTER_Cyrillic_en 0x6ce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_en instead.") #define CLUTTER_Cyrillic_o 0x6cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_o instead.") #define CLUTTER_Cyrillic_pe 0x6d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_pe instead.") #define CLUTTER_Cyrillic_ya 0x6d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ya instead.") #define CLUTTER_Cyrillic_er 0x6d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_er instead.") #define CLUTTER_Cyrillic_es 0x6d3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_es instead.") #define CLUTTER_Cyrillic_te 0x6d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_te instead.") #define CLUTTER_Cyrillic_u 0x6d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_u instead.") #define CLUTTER_Cyrillic_zhe 0x6d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_zhe instead.") #define CLUTTER_Cyrillic_ve 0x6d7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ve instead.") #define CLUTTER_Cyrillic_softsign 0x6d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_softsign instead.") #define CLUTTER_Cyrillic_yeru 0x6d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_yeru instead.") #define CLUTTER_Cyrillic_ze 0x6da CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ze instead.") #define CLUTTER_Cyrillic_sha 0x6db CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_sha instead.") #define CLUTTER_Cyrillic_e 0x6dc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_e instead.") #define CLUTTER_Cyrillic_shcha 0x6dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_shcha instead.") #define CLUTTER_Cyrillic_che 0x6de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_che instead.") #define CLUTTER_Cyrillic_hardsign 0x6df CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_hardsign instead.") #define CLUTTER_Cyrillic_YU 0x6e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_YU instead.") #define CLUTTER_Cyrillic_A 0x6e1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_A instead.") #define CLUTTER_Cyrillic_BE 0x6e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_BE instead.") #define CLUTTER_Cyrillic_TSE 0x6e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_TSE instead.") #define CLUTTER_Cyrillic_DE 0x6e4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_DE instead.") #define CLUTTER_Cyrillic_IE 0x6e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_IE instead.") #define CLUTTER_Cyrillic_EF 0x6e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_EF instead.") #define CLUTTER_Cyrillic_GHE 0x6e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_GHE instead.") #define CLUTTER_Cyrillic_HA 0x6e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_HA instead.") #define CLUTTER_Cyrillic_I 0x6e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_I instead.") #define CLUTTER_Cyrillic_SHORTI 0x6ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_SHORTI instead.") #define CLUTTER_Cyrillic_KA 0x6eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_KA instead.") #define CLUTTER_Cyrillic_EL 0x6ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_EL instead.") #define CLUTTER_Cyrillic_EM 0x6ed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_EM instead.") #define CLUTTER_Cyrillic_EN 0x6ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_EN instead.") #define CLUTTER_Cyrillic_O 0x6ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_O instead.") #define CLUTTER_Cyrillic_PE 0x6f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_PE instead.") #define CLUTTER_Cyrillic_YA 0x6f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_YA instead.") #define CLUTTER_Cyrillic_ER 0x6f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ER instead.") #define CLUTTER_Cyrillic_ES 0x6f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ES instead.") #define CLUTTER_Cyrillic_TE 0x6f4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_TE instead.") #define CLUTTER_Cyrillic_U 0x6f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_U instead.") #define CLUTTER_Cyrillic_ZHE 0x6f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ZHE instead.") #define CLUTTER_Cyrillic_VE 0x6f7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_VE instead.") #define CLUTTER_Cyrillic_SOFTSIGN 0x6f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_SOFTSIGN instead.") #define CLUTTER_Cyrillic_YERU 0x6f9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_YERU instead.") #define CLUTTER_Cyrillic_ZE 0x6fa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_ZE instead.") #define CLUTTER_Cyrillic_SHA 0x6fb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_SHA instead.") #define CLUTTER_Cyrillic_E 0x6fc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_E instead.") #define CLUTTER_Cyrillic_SHCHA 0x6fd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_SHCHA instead.") #define CLUTTER_Cyrillic_CHE 0x6fe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_CHE instead.") #define CLUTTER_Cyrillic_HARDSIGN 0x6ff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Cyrillic_HARDSIGN instead.") #define CLUTTER_Greek_ALPHAaccent 0x7a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_ALPHAaccent instead.") #define CLUTTER_Greek_EPSILONaccent 0x7a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_EPSILONaccent instead.") #define CLUTTER_Greek_ETAaccent 0x7a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_ETAaccent instead.") #define CLUTTER_Greek_IOTAaccent 0x7a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_IOTAaccent instead.") #define CLUTTER_Greek_IOTAdieresis 0x7a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_IOTAdieresis instead.") #define CLUTTER_Greek_IOTAdiaeresis 0x7a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_IOTAdiaeresis instead.") #define CLUTTER_Greek_OMICRONaccent 0x7a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_OMICRONaccent instead.") #define CLUTTER_Greek_UPSILONaccent 0x7a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_UPSILONaccent instead.") #define CLUTTER_Greek_UPSILONdieresis 0x7a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_UPSILONdieresis instead.") #define CLUTTER_Greek_OMEGAaccent 0x7ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_OMEGAaccent instead.") #define CLUTTER_Greek_accentdieresis 0x7ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_accentdieresis instead.") #define CLUTTER_Greek_horizbar 0x7af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_horizbar instead.") #define CLUTTER_Greek_alphaaccent 0x7b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_alphaaccent instead.") #define CLUTTER_Greek_epsilonaccent 0x7b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_epsilonaccent instead.") #define CLUTTER_Greek_etaaccent 0x7b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_etaaccent instead.") #define CLUTTER_Greek_iotaaccent 0x7b4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_iotaaccent instead.") #define CLUTTER_Greek_iotadieresis 0x7b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_iotadieresis instead.") #define CLUTTER_Greek_iotaaccentdieresis 0x7b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_iotaaccentdieresis instead.") #define CLUTTER_Greek_omicronaccent 0x7b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_omicronaccent instead.") #define CLUTTER_Greek_upsilonaccent 0x7b8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_upsilonaccent instead.") #define CLUTTER_Greek_upsilondieresis 0x7b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_upsilondieresis instead.") #define CLUTTER_Greek_upsilonaccentdieresis 0x7ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_upsilonaccentdieresis instead.") #define CLUTTER_Greek_omegaaccent 0x7bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_omegaaccent instead.") #define CLUTTER_Greek_ALPHA 0x7c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_ALPHA instead.") #define CLUTTER_Greek_BETA 0x7c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_BETA instead.") #define CLUTTER_Greek_GAMMA 0x7c3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_GAMMA instead.") #define CLUTTER_Greek_DELTA 0x7c4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_DELTA instead.") #define CLUTTER_Greek_EPSILON 0x7c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_EPSILON instead.") #define CLUTTER_Greek_ZETA 0x7c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_ZETA instead.") #define CLUTTER_Greek_ETA 0x7c7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_ETA instead.") #define CLUTTER_Greek_THETA 0x7c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_THETA instead.") #define CLUTTER_Greek_IOTA 0x7c9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_IOTA instead.") #define CLUTTER_Greek_KAPPA 0x7ca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_KAPPA instead.") #define CLUTTER_Greek_LAMDA 0x7cb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_LAMDA instead.") #define CLUTTER_Greek_LAMBDA 0x7cb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_LAMBDA instead.") #define CLUTTER_Greek_MU 0x7cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_MU instead.") #define CLUTTER_Greek_NU 0x7cd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_NU instead.") #define CLUTTER_Greek_XI 0x7ce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_XI instead.") #define CLUTTER_Greek_OMICRON 0x7cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_OMICRON instead.") #define CLUTTER_Greek_PI 0x7d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_PI instead.") #define CLUTTER_Greek_RHO 0x7d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_RHO instead.") #define CLUTTER_Greek_SIGMA 0x7d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_SIGMA instead.") #define CLUTTER_Greek_TAU 0x7d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_TAU instead.") #define CLUTTER_Greek_UPSILON 0x7d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_UPSILON instead.") #define CLUTTER_Greek_PHI 0x7d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_PHI instead.") #define CLUTTER_Greek_CHI 0x7d7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_CHI instead.") #define CLUTTER_Greek_PSI 0x7d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_PSI instead.") #define CLUTTER_Greek_OMEGA 0x7d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_OMEGA instead.") #define CLUTTER_Greek_alpha 0x7e1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_alpha instead.") #define CLUTTER_Greek_beta 0x7e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_beta instead.") #define CLUTTER_Greek_gamma 0x7e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_gamma instead.") #define CLUTTER_Greek_delta 0x7e4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_delta instead.") #define CLUTTER_Greek_epsilon 0x7e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_epsilon instead.") #define CLUTTER_Greek_zeta 0x7e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_zeta instead.") #define CLUTTER_Greek_eta 0x7e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_eta instead.") #define CLUTTER_Greek_theta 0x7e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_theta instead.") #define CLUTTER_Greek_iota 0x7e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_iota instead.") #define CLUTTER_Greek_kappa 0x7ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_kappa instead.") #define CLUTTER_Greek_lamda 0x7eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_lamda instead.") #define CLUTTER_Greek_lambda 0x7eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_lambda instead.") #define CLUTTER_Greek_mu 0x7ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_mu instead.") #define CLUTTER_Greek_nu 0x7ed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_nu instead.") #define CLUTTER_Greek_xi 0x7ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_xi instead.") #define CLUTTER_Greek_omicron 0x7ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_omicron instead.") #define CLUTTER_Greek_pi 0x7f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_pi instead.") #define CLUTTER_Greek_rho 0x7f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_rho instead.") #define CLUTTER_Greek_sigma 0x7f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_sigma instead.") #define CLUTTER_Greek_finalsmallsigma 0x7f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_finalsmallsigma instead.") #define CLUTTER_Greek_tau 0x7f4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_tau instead.") #define CLUTTER_Greek_upsilon 0x7f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_upsilon instead.") #define CLUTTER_Greek_phi 0x7f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_phi instead.") #define CLUTTER_Greek_chi 0x7f7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_chi instead.") #define CLUTTER_Greek_psi 0x7f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_psi instead.") #define CLUTTER_Greek_omega 0x7f9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_omega instead.") #define CLUTTER_Greek_switch 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Greek_switch instead.") #define CLUTTER_leftradical 0x8a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftradical instead.") #define CLUTTER_topleftradical 0x8a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_topleftradical instead.") #define CLUTTER_horizconnector 0x8a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_horizconnector instead.") #define CLUTTER_topintegral 0x8a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_topintegral instead.") #define CLUTTER_botintegral 0x8a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botintegral instead.") #define CLUTTER_vertconnector 0x8a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_vertconnector instead.") #define CLUTTER_topleftsqbracket 0x8a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_topleftsqbracket instead.") #define CLUTTER_botleftsqbracket 0x8a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botleftsqbracket instead.") #define CLUTTER_toprightsqbracket 0x8a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_toprightsqbracket instead.") #define CLUTTER_botrightsqbracket 0x8aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botrightsqbracket instead.") #define CLUTTER_topleftparens 0x8ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_topleftparens instead.") #define CLUTTER_botleftparens 0x8ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botleftparens instead.") #define CLUTTER_toprightparens 0x8ad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_toprightparens instead.") #define CLUTTER_botrightparens 0x8ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botrightparens instead.") #define CLUTTER_leftmiddlecurlybrace 0x8af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftmiddlecurlybrace instead.") #define CLUTTER_rightmiddlecurlybrace 0x8b0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightmiddlecurlybrace instead.") #define CLUTTER_topleftsummation 0x8b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_topleftsummation instead.") #define CLUTTER_botleftsummation 0x8b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botleftsummation instead.") #define CLUTTER_topvertsummationconnector 0x8b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_topvertsummationconnector instead.") #define CLUTTER_botvertsummationconnector 0x8b4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botvertsummationconnector instead.") #define CLUTTER_toprightsummation 0x8b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_toprightsummation instead.") #define CLUTTER_botrightsummation 0x8b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_botrightsummation instead.") #define CLUTTER_rightmiddlesummation 0x8b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightmiddlesummation instead.") #define CLUTTER_lessthanequal 0x8bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lessthanequal instead.") #define CLUTTER_notequal 0x8bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_notequal instead.") #define CLUTTER_greaterthanequal 0x8be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_greaterthanequal instead.") #define CLUTTER_integral 0x8bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_integral instead.") #define CLUTTER_therefore 0x8c0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_therefore instead.") #define CLUTTER_variation 0x8c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_variation instead.") #define CLUTTER_infinity 0x8c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_infinity instead.") #define CLUTTER_nabla 0x8c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_nabla instead.") #define CLUTTER_approximate 0x8c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_approximate instead.") #define CLUTTER_similarequal 0x8c9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_similarequal instead.") #define CLUTTER_ifonlyif 0x8cd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ifonlyif instead.") #define CLUTTER_implies 0x8ce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_implies instead.") #define CLUTTER_identical 0x8cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_identical instead.") #define CLUTTER_radical 0x8d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_radical instead.") #define CLUTTER_includedin 0x8da CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_includedin instead.") #define CLUTTER_includes 0x8db CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_includes instead.") #define CLUTTER_intersection 0x8dc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_intersection instead.") #define CLUTTER_union 0x8dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_union instead.") #define CLUTTER_logicaland 0x8de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_logicaland instead.") #define CLUTTER_logicalor 0x8df CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_logicalor instead.") #define CLUTTER_partialderivative 0x8ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_partialderivative instead.") #define CLUTTER_function 0x8f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_function instead.") #define CLUTTER_leftarrow 0x8fb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftarrow instead.") #define CLUTTER_uparrow 0x8fc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uparrow instead.") #define CLUTTER_rightarrow 0x8fd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightarrow instead.") #define CLUTTER_downarrow 0x8fe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_downarrow instead.") #define CLUTTER_blank 0x9df CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_blank instead.") #define CLUTTER_soliddiamond 0x9e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_soliddiamond instead.") #define CLUTTER_checkerboard 0x9e1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_checkerboard instead.") #define CLUTTER_ht 0x9e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ht instead.") #define CLUTTER_ff 0x9e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ff instead.") #define CLUTTER_cr 0x9e4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_cr instead.") #define CLUTTER_lf 0x9e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lf instead.") #define CLUTTER_nl 0x9e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_nl instead.") #define CLUTTER_vt 0x9e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_vt instead.") #define CLUTTER_lowrightcorner 0x9ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lowrightcorner instead.") #define CLUTTER_uprightcorner 0x9eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uprightcorner instead.") #define CLUTTER_upleftcorner 0x9ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_upleftcorner instead.") #define CLUTTER_lowleftcorner 0x9ed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lowleftcorner instead.") #define CLUTTER_crossinglines 0x9ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_crossinglines instead.") #define CLUTTER_horizlinescan1 0x9ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_horizlinescan1 instead.") #define CLUTTER_horizlinescan3 0x9f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_horizlinescan3 instead.") #define CLUTTER_horizlinescan5 0x9f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_horizlinescan5 instead.") #define CLUTTER_horizlinescan7 0x9f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_horizlinescan7 instead.") #define CLUTTER_horizlinescan9 0x9f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_horizlinescan9 instead.") #define CLUTTER_leftt 0x9f4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftt instead.") #define CLUTTER_rightt 0x9f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightt instead.") #define CLUTTER_bott 0x9f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_bott instead.") #define CLUTTER_topt 0x9f7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_topt instead.") #define CLUTTER_vertbar 0x9f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_vertbar instead.") #define CLUTTER_emspace 0xaa1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emspace instead.") #define CLUTTER_enspace 0xaa2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_enspace instead.") #define CLUTTER_em3space 0xaa3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_em3space instead.") #define CLUTTER_em4space 0xaa4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_em4space instead.") #define CLUTTER_digitspace 0xaa5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_digitspace instead.") #define CLUTTER_punctspace 0xaa6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_punctspace instead.") #define CLUTTER_thinspace 0xaa7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_thinspace instead.") #define CLUTTER_hairspace 0xaa8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hairspace instead.") #define CLUTTER_emdash 0xaa9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emdash instead.") #define CLUTTER_endash 0xaaa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_endash instead.") #define CLUTTER_signifblank 0xaac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_signifblank instead.") #define CLUTTER_ellipsis 0xaae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ellipsis instead.") #define CLUTTER_doubbaselinedot 0xaaf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_doubbaselinedot instead.") #define CLUTTER_onethird 0xab0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_onethird instead.") #define CLUTTER_twothirds 0xab1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_twothirds instead.") #define CLUTTER_onefifth 0xab2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_onefifth instead.") #define CLUTTER_twofifths 0xab3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_twofifths instead.") #define CLUTTER_threefifths 0xab4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_threefifths instead.") #define CLUTTER_fourfifths 0xab5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_fourfifths instead.") #define CLUTTER_onesixth 0xab6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_onesixth instead.") #define CLUTTER_fivesixths 0xab7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_fivesixths instead.") #define CLUTTER_careof 0xab8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_careof instead.") #define CLUTTER_figdash 0xabb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_figdash instead.") #define CLUTTER_leftanglebracket 0xabc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftanglebracket instead.") #define CLUTTER_decimalpoint 0xabd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_decimalpoint instead.") #define CLUTTER_rightanglebracket 0xabe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightanglebracket instead.") #define CLUTTER_marker 0xabf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_marker instead.") #define CLUTTER_oneeighth 0xac3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_oneeighth instead.") #define CLUTTER_threeeighths 0xac4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_threeeighths instead.") #define CLUTTER_fiveeighths 0xac5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_fiveeighths instead.") #define CLUTTER_seveneighths 0xac6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_seveneighths instead.") #define CLUTTER_trademark 0xac9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_trademark instead.") #define CLUTTER_signaturemark 0xaca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_signaturemark instead.") #define CLUTTER_trademarkincircle 0xacb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_trademarkincircle instead.") #define CLUTTER_leftopentriangle 0xacc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftopentriangle instead.") #define CLUTTER_rightopentriangle 0xacd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightopentriangle instead.") #define CLUTTER_emopencircle 0xace CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emopencircle instead.") #define CLUTTER_emopenrectangle 0xacf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emopenrectangle instead.") #define CLUTTER_leftsinglequotemark 0xad0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftsinglequotemark instead.") #define CLUTTER_rightsinglequotemark 0xad1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightsinglequotemark instead.") #define CLUTTER_leftdoublequotemark 0xad2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftdoublequotemark instead.") #define CLUTTER_rightdoublequotemark 0xad3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightdoublequotemark instead.") #define CLUTTER_prescription 0xad4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_prescription instead.") #define CLUTTER_permille 0xad5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_permille instead.") #define CLUTTER_minutes 0xad6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_minutes instead.") #define CLUTTER_seconds 0xad7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_seconds instead.") #define CLUTTER_latincross 0xad9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_latincross instead.") #define CLUTTER_hexagram 0xada CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hexagram instead.") #define CLUTTER_filledrectbullet 0xadb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_filledrectbullet instead.") #define CLUTTER_filledlefttribullet 0xadc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_filledlefttribullet instead.") #define CLUTTER_filledrighttribullet 0xadd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_filledrighttribullet instead.") #define CLUTTER_emfilledcircle 0xade CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emfilledcircle instead.") #define CLUTTER_emfilledrect 0xadf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emfilledrect instead.") #define CLUTTER_enopencircbullet 0xae0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_enopencircbullet instead.") #define CLUTTER_enopensquarebullet 0xae1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_enopensquarebullet instead.") #define CLUTTER_openrectbullet 0xae2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_openrectbullet instead.") #define CLUTTER_opentribulletup 0xae3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_opentribulletup instead.") #define CLUTTER_opentribulletdown 0xae4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_opentribulletdown instead.") #define CLUTTER_openstar 0xae5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_openstar instead.") #define CLUTTER_enfilledcircbullet 0xae6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_enfilledcircbullet instead.") #define CLUTTER_enfilledsqbullet 0xae7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_enfilledsqbullet instead.") #define CLUTTER_filledtribulletup 0xae8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_filledtribulletup instead.") #define CLUTTER_filledtribulletdown 0xae9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_filledtribulletdown instead.") #define CLUTTER_leftpointer 0xaea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftpointer instead.") #define CLUTTER_rightpointer 0xaeb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightpointer instead.") #define CLUTTER_club 0xaec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_club instead.") #define CLUTTER_diamond 0xaed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_diamond instead.") #define CLUTTER_heart 0xaee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_heart instead.") #define CLUTTER_maltesecross 0xaf0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_maltesecross instead.") #define CLUTTER_dagger 0xaf1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dagger instead.") #define CLUTTER_doubledagger 0xaf2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_doubledagger instead.") #define CLUTTER_checkmark 0xaf3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_checkmark instead.") #define CLUTTER_ballotcross 0xaf4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ballotcross instead.") #define CLUTTER_musicalsharp 0xaf5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_musicalsharp instead.") #define CLUTTER_musicalflat 0xaf6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_musicalflat instead.") #define CLUTTER_malesymbol 0xaf7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_malesymbol instead.") #define CLUTTER_femalesymbol 0xaf8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_femalesymbol instead.") #define CLUTTER_telephone 0xaf9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_telephone instead.") #define CLUTTER_telephonerecorder 0xafa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_telephonerecorder instead.") #define CLUTTER_phonographcopyright 0xafb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_phonographcopyright instead.") #define CLUTTER_caret 0xafc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_caret instead.") #define CLUTTER_singlelowquotemark 0xafd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_singlelowquotemark instead.") #define CLUTTER_doublelowquotemark 0xafe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_doublelowquotemark instead.") #define CLUTTER_cursor 0xaff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_cursor instead.") #define CLUTTER_leftcaret 0xba3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftcaret instead.") #define CLUTTER_rightcaret 0xba6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightcaret instead.") #define CLUTTER_downcaret 0xba8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_downcaret instead.") #define CLUTTER_upcaret 0xba9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_upcaret instead.") #define CLUTTER_overbar 0xbc0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_overbar instead.") #define CLUTTER_downtack 0xbc2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_downtack instead.") #define CLUTTER_upshoe 0xbc3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_upshoe instead.") #define CLUTTER_downstile 0xbc4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_downstile instead.") #define CLUTTER_underbar 0xbc6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_underbar instead.") #define CLUTTER_jot 0xbca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_jot instead.") #define CLUTTER_quad 0xbcc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_quad instead.") #define CLUTTER_uptack 0xbce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uptack instead.") #define CLUTTER_circle 0xbcf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_circle instead.") #define CLUTTER_upstile 0xbd3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_upstile instead.") #define CLUTTER_downshoe 0xbd6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_downshoe instead.") #define CLUTTER_rightshoe 0xbd8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_rightshoe instead.") #define CLUTTER_leftshoe 0xbda CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_leftshoe instead.") #define CLUTTER_lefttack 0xbdc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lefttack instead.") #define CLUTTER_righttack 0xbfc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_righttack instead.") #define CLUTTER_hebrew_doublelowline 0xcdf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_doublelowline instead.") #define CLUTTER_hebrew_aleph 0xce0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_aleph instead.") #define CLUTTER_hebrew_bet 0xce1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_bet instead.") #define CLUTTER_hebrew_beth 0xce1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_beth instead.") #define CLUTTER_hebrew_gimel 0xce2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_gimel instead.") #define CLUTTER_hebrew_gimmel 0xce2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_gimmel instead.") #define CLUTTER_hebrew_dalet 0xce3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_dalet instead.") #define CLUTTER_hebrew_daleth 0xce3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_daleth instead.") #define CLUTTER_hebrew_he 0xce4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_he instead.") #define CLUTTER_hebrew_waw 0xce5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_waw instead.") #define CLUTTER_hebrew_zain 0xce6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_zain instead.") #define CLUTTER_hebrew_zayin 0xce6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_zayin instead.") #define CLUTTER_hebrew_chet 0xce7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_chet instead.") #define CLUTTER_hebrew_het 0xce7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_het instead.") #define CLUTTER_hebrew_tet 0xce8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_tet instead.") #define CLUTTER_hebrew_teth 0xce8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_teth instead.") #define CLUTTER_hebrew_yod 0xce9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_yod instead.") #define CLUTTER_hebrew_finalkaph 0xcea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_finalkaph instead.") #define CLUTTER_hebrew_kaph 0xceb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_kaph instead.") #define CLUTTER_hebrew_lamed 0xcec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_lamed instead.") #define CLUTTER_hebrew_finalmem 0xced CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_finalmem instead.") #define CLUTTER_hebrew_mem 0xcee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_mem instead.") #define CLUTTER_hebrew_finalnun 0xcef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_finalnun instead.") #define CLUTTER_hebrew_nun 0xcf0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_nun instead.") #define CLUTTER_hebrew_samech 0xcf1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_samech instead.") #define CLUTTER_hebrew_samekh 0xcf1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_samekh instead.") #define CLUTTER_hebrew_ayin 0xcf2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_ayin instead.") #define CLUTTER_hebrew_finalpe 0xcf3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_finalpe instead.") #define CLUTTER_hebrew_pe 0xcf4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_pe instead.") #define CLUTTER_hebrew_finalzade 0xcf5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_finalzade instead.") #define CLUTTER_hebrew_finalzadi 0xcf5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_finalzadi instead.") #define CLUTTER_hebrew_zade 0xcf6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_zade instead.") #define CLUTTER_hebrew_zadi 0xcf6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_zadi instead.") #define CLUTTER_hebrew_qoph 0xcf7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_qoph instead.") #define CLUTTER_hebrew_kuf 0xcf7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_kuf instead.") #define CLUTTER_hebrew_resh 0xcf8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_resh instead.") #define CLUTTER_hebrew_shin 0xcf9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_shin instead.") #define CLUTTER_hebrew_taw 0xcfa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_taw instead.") #define CLUTTER_hebrew_taf 0xcfa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_hebrew_taf instead.") #define CLUTTER_Hebrew_switch 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hebrew_switch instead.") #define CLUTTER_Thai_kokai 0xda1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_kokai instead.") #define CLUTTER_Thai_khokhai 0xda2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_khokhai instead.") #define CLUTTER_Thai_khokhuat 0xda3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_khokhuat instead.") #define CLUTTER_Thai_khokhwai 0xda4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_khokhwai instead.") #define CLUTTER_Thai_khokhon 0xda5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_khokhon instead.") #define CLUTTER_Thai_khorakhang 0xda6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_khorakhang instead.") #define CLUTTER_Thai_ngongu 0xda7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_ngongu instead.") #define CLUTTER_Thai_chochan 0xda8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_chochan instead.") #define CLUTTER_Thai_choching 0xda9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_choching instead.") #define CLUTTER_Thai_chochang 0xdaa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_chochang instead.") #define CLUTTER_Thai_soso 0xdab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_soso instead.") #define CLUTTER_Thai_chochoe 0xdac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_chochoe instead.") #define CLUTTER_Thai_yoying 0xdad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_yoying instead.") #define CLUTTER_Thai_dochada 0xdae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_dochada instead.") #define CLUTTER_Thai_topatak 0xdaf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_topatak instead.") #define CLUTTER_Thai_thothan 0xdb0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_thothan instead.") #define CLUTTER_Thai_thonangmontho 0xdb1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_thonangmontho instead.") #define CLUTTER_Thai_thophuthao 0xdb2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_thophuthao instead.") #define CLUTTER_Thai_nonen 0xdb3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_nonen instead.") #define CLUTTER_Thai_dodek 0xdb4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_dodek instead.") #define CLUTTER_Thai_totao 0xdb5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_totao instead.") #define CLUTTER_Thai_thothung 0xdb6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_thothung instead.") #define CLUTTER_Thai_thothahan 0xdb7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_thothahan instead.") #define CLUTTER_Thai_thothong 0xdb8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_thothong instead.") #define CLUTTER_Thai_nonu 0xdb9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_nonu instead.") #define CLUTTER_Thai_bobaimai 0xdba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_bobaimai instead.") #define CLUTTER_Thai_popla 0xdbb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_popla instead.") #define CLUTTER_Thai_phophung 0xdbc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_phophung instead.") #define CLUTTER_Thai_fofa 0xdbd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_fofa instead.") #define CLUTTER_Thai_phophan 0xdbe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_phophan instead.") #define CLUTTER_Thai_fofan 0xdbf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_fofan instead.") #define CLUTTER_Thai_phosamphao 0xdc0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_phosamphao instead.") #define CLUTTER_Thai_moma 0xdc1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_moma instead.") #define CLUTTER_Thai_yoyak 0xdc2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_yoyak instead.") #define CLUTTER_Thai_rorua 0xdc3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_rorua instead.") #define CLUTTER_Thai_ru 0xdc4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_ru instead.") #define CLUTTER_Thai_loling 0xdc5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_loling instead.") #define CLUTTER_Thai_lu 0xdc6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lu instead.") #define CLUTTER_Thai_wowaen 0xdc7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_wowaen instead.") #define CLUTTER_Thai_sosala 0xdc8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sosala instead.") #define CLUTTER_Thai_sorusi 0xdc9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sorusi instead.") #define CLUTTER_Thai_sosua 0xdca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sosua instead.") #define CLUTTER_Thai_hohip 0xdcb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_hohip instead.") #define CLUTTER_Thai_lochula 0xdcc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lochula instead.") #define CLUTTER_Thai_oang 0xdcd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_oang instead.") #define CLUTTER_Thai_honokhuk 0xdce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_honokhuk instead.") #define CLUTTER_Thai_paiyannoi 0xdcf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_paiyannoi instead.") #define CLUTTER_Thai_saraa 0xdd0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraa instead.") #define CLUTTER_Thai_maihanakat 0xdd1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maihanakat instead.") #define CLUTTER_Thai_saraaa 0xdd2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraaa instead.") #define CLUTTER_Thai_saraam 0xdd3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraam instead.") #define CLUTTER_Thai_sarai 0xdd4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sarai instead.") #define CLUTTER_Thai_saraii 0xdd5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraii instead.") #define CLUTTER_Thai_saraue 0xdd6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraue instead.") #define CLUTTER_Thai_sarauee 0xdd7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sarauee instead.") #define CLUTTER_Thai_sarau 0xdd8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sarau instead.") #define CLUTTER_Thai_sarauu 0xdd9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sarauu instead.") #define CLUTTER_Thai_phinthu 0xdda CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_phinthu instead.") #define CLUTTER_Thai_maihanakat_maitho 0xdde CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maihanakat_maitho instead.") #define CLUTTER_Thai_baht 0xddf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_baht instead.") #define CLUTTER_Thai_sarae 0xde0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sarae instead.") #define CLUTTER_Thai_saraae 0xde1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraae instead.") #define CLUTTER_Thai_sarao 0xde2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_sarao instead.") #define CLUTTER_Thai_saraaimaimuan 0xde3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraaimaimuan instead.") #define CLUTTER_Thai_saraaimaimalai 0xde4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_saraaimaimalai instead.") #define CLUTTER_Thai_lakkhangyao 0xde5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lakkhangyao instead.") #define CLUTTER_Thai_maiyamok 0xde6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maiyamok instead.") #define CLUTTER_Thai_maitaikhu 0xde7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maitaikhu instead.") #define CLUTTER_Thai_maiek 0xde8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maiek instead.") #define CLUTTER_Thai_maitho 0xde9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maitho instead.") #define CLUTTER_Thai_maitri 0xdea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maitri instead.") #define CLUTTER_Thai_maichattawa 0xdeb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_maichattawa instead.") #define CLUTTER_Thai_thanthakhat 0xdec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_thanthakhat instead.") #define CLUTTER_Thai_nikhahit 0xded CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_nikhahit instead.") #define CLUTTER_Thai_leksun 0xdf0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_leksun instead.") #define CLUTTER_Thai_leknung 0xdf1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_leknung instead.") #define CLUTTER_Thai_leksong 0xdf2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_leksong instead.") #define CLUTTER_Thai_leksam 0xdf3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_leksam instead.") #define CLUTTER_Thai_leksi 0xdf4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_leksi instead.") #define CLUTTER_Thai_lekha 0xdf5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lekha instead.") #define CLUTTER_Thai_lekhok 0xdf6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lekhok instead.") #define CLUTTER_Thai_lekchet 0xdf7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lekchet instead.") #define CLUTTER_Thai_lekpaet 0xdf8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lekpaet instead.") #define CLUTTER_Thai_lekkao 0xdf9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Thai_lekkao instead.") #define CLUTTER_Hangul 0xff31 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul instead.") #define CLUTTER_Hangul_Start 0xff32 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Start instead.") #define CLUTTER_Hangul_End 0xff33 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_End instead.") #define CLUTTER_Hangul_Hanja 0xff34 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Hanja instead.") #define CLUTTER_Hangul_Jamo 0xff35 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Jamo instead.") #define CLUTTER_Hangul_Romaja 0xff36 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Romaja instead.") #define CLUTTER_Hangul_Codeinput 0xff37 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Codeinput instead.") #define CLUTTER_Hangul_Jeonja 0xff38 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Jeonja instead.") #define CLUTTER_Hangul_Banja 0xff39 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Banja instead.") #define CLUTTER_Hangul_PreHanja 0xff3a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_PreHanja instead.") #define CLUTTER_Hangul_PostHanja 0xff3b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_PostHanja instead.") #define CLUTTER_Hangul_SingleCandidate 0xff3c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SingleCandidate instead.") #define CLUTTER_Hangul_MultipleCandidate 0xff3d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_MultipleCandidate instead.") #define CLUTTER_Hangul_PreviousCandidate 0xff3e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_PreviousCandidate instead.") #define CLUTTER_Hangul_Special 0xff3f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Special instead.") #define CLUTTER_Hangul_switch 0xff7e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_switch instead.") #define CLUTTER_Hangul_Kiyeog 0xea1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Kiyeog instead.") #define CLUTTER_Hangul_SsangKiyeog 0xea2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SsangKiyeog instead.") #define CLUTTER_Hangul_KiyeogSios 0xea3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_KiyeogSios instead.") #define CLUTTER_Hangul_Nieun 0xea4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Nieun instead.") #define CLUTTER_Hangul_NieunJieuj 0xea5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_NieunJieuj instead.") #define CLUTTER_Hangul_NieunHieuh 0xea6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_NieunHieuh instead.") #define CLUTTER_Hangul_Dikeud 0xea7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Dikeud instead.") #define CLUTTER_Hangul_SsangDikeud 0xea8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SsangDikeud instead.") #define CLUTTER_Hangul_Rieul 0xea9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Rieul instead.") #define CLUTTER_Hangul_RieulKiyeog 0xeaa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulKiyeog instead.") #define CLUTTER_Hangul_RieulMieum 0xeab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulMieum instead.") #define CLUTTER_Hangul_RieulPieub 0xeac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulPieub instead.") #define CLUTTER_Hangul_RieulSios 0xead CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulSios instead.") #define CLUTTER_Hangul_RieulTieut 0xeae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulTieut instead.") #define CLUTTER_Hangul_RieulPhieuf 0xeaf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulPhieuf instead.") #define CLUTTER_Hangul_RieulHieuh 0xeb0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulHieuh instead.") #define CLUTTER_Hangul_Mieum 0xeb1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Mieum instead.") #define CLUTTER_Hangul_Pieub 0xeb2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Pieub instead.") #define CLUTTER_Hangul_SsangPieub 0xeb3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SsangPieub instead.") #define CLUTTER_Hangul_PieubSios 0xeb4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_PieubSios instead.") #define CLUTTER_Hangul_Sios 0xeb5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Sios instead.") #define CLUTTER_Hangul_SsangSios 0xeb6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SsangSios instead.") #define CLUTTER_Hangul_Ieung 0xeb7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Ieung instead.") #define CLUTTER_Hangul_Jieuj 0xeb8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Jieuj instead.") #define CLUTTER_Hangul_SsangJieuj 0xeb9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SsangJieuj instead.") #define CLUTTER_Hangul_Cieuc 0xeba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Cieuc instead.") #define CLUTTER_Hangul_Khieuq 0xebb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Khieuq instead.") #define CLUTTER_Hangul_Tieut 0xebc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Tieut instead.") #define CLUTTER_Hangul_Phieuf 0xebd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Phieuf instead.") #define CLUTTER_Hangul_Hieuh 0xebe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_Hieuh instead.") #define CLUTTER_Hangul_A 0xebf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_A instead.") #define CLUTTER_Hangul_AE 0xec0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_AE instead.") #define CLUTTER_Hangul_YA 0xec1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YA instead.") #define CLUTTER_Hangul_YAE 0xec2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YAE instead.") #define CLUTTER_Hangul_EO 0xec3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_EO instead.") #define CLUTTER_Hangul_E 0xec4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_E instead.") #define CLUTTER_Hangul_YEO 0xec5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YEO instead.") #define CLUTTER_Hangul_YE 0xec6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YE instead.") #define CLUTTER_Hangul_O 0xec7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_O instead.") #define CLUTTER_Hangul_WA 0xec8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_WA instead.") #define CLUTTER_Hangul_WAE 0xec9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_WAE instead.") #define CLUTTER_Hangul_OE 0xeca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_OE instead.") #define CLUTTER_Hangul_YO 0xecb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YO instead.") #define CLUTTER_Hangul_U 0xecc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_U instead.") #define CLUTTER_Hangul_WEO 0xecd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_WEO instead.") #define CLUTTER_Hangul_WE 0xece CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_WE instead.") #define CLUTTER_Hangul_WI 0xecf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_WI instead.") #define CLUTTER_Hangul_YU 0xed0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YU instead.") #define CLUTTER_Hangul_EU 0xed1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_EU instead.") #define CLUTTER_Hangul_YI 0xed2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YI instead.") #define CLUTTER_Hangul_I 0xed3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_I instead.") #define CLUTTER_Hangul_J_Kiyeog 0xed4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Kiyeog instead.") #define CLUTTER_Hangul_J_SsangKiyeog 0xed5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_SsangKiyeog instead.") #define CLUTTER_Hangul_J_KiyeogSios 0xed6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_KiyeogSios instead.") #define CLUTTER_Hangul_J_Nieun 0xed7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Nieun instead.") #define CLUTTER_Hangul_J_NieunJieuj 0xed8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_NieunJieuj instead.") #define CLUTTER_Hangul_J_NieunHieuh 0xed9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_NieunHieuh instead.") #define CLUTTER_Hangul_J_Dikeud 0xeda CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Dikeud instead.") #define CLUTTER_Hangul_J_Rieul 0xedb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Rieul instead.") #define CLUTTER_Hangul_J_RieulKiyeog 0xedc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_RieulKiyeog instead.") #define CLUTTER_Hangul_J_RieulMieum 0xedd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_RieulMieum instead.") #define CLUTTER_Hangul_J_RieulPieub 0xede CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_RieulPieub instead.") #define CLUTTER_Hangul_J_RieulSios 0xedf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_RieulSios instead.") #define CLUTTER_Hangul_J_RieulTieut 0xee0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_RieulTieut instead.") #define CLUTTER_Hangul_J_RieulPhieuf 0xee1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_RieulPhieuf instead.") #define CLUTTER_Hangul_J_RieulHieuh 0xee2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_RieulHieuh instead.") #define CLUTTER_Hangul_J_Mieum 0xee3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Mieum instead.") #define CLUTTER_Hangul_J_Pieub 0xee4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Pieub instead.") #define CLUTTER_Hangul_J_PieubSios 0xee5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_PieubSios instead.") #define CLUTTER_Hangul_J_Sios 0xee6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Sios instead.") #define CLUTTER_Hangul_J_SsangSios 0xee7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_SsangSios instead.") #define CLUTTER_Hangul_J_Ieung 0xee8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Ieung instead.") #define CLUTTER_Hangul_J_Jieuj 0xee9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Jieuj instead.") #define CLUTTER_Hangul_J_Cieuc 0xeea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Cieuc instead.") #define CLUTTER_Hangul_J_Khieuq 0xeeb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Khieuq instead.") #define CLUTTER_Hangul_J_Tieut 0xeec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Tieut instead.") #define CLUTTER_Hangul_J_Phieuf 0xeed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Phieuf instead.") #define CLUTTER_Hangul_J_Hieuh 0xeee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_Hieuh instead.") #define CLUTTER_Hangul_RieulYeorinHieuh 0xeef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_RieulYeorinHieuh instead.") #define CLUTTER_Hangul_SunkyeongeumMieum 0xef0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SunkyeongeumMieum instead.") #define CLUTTER_Hangul_SunkyeongeumPieub 0xef1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SunkyeongeumPieub instead.") #define CLUTTER_Hangul_PanSios 0xef2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_PanSios instead.") #define CLUTTER_Hangul_KkogjiDalrinIeung 0xef3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_KkogjiDalrinIeung instead.") #define CLUTTER_Hangul_SunkyeongeumPhieuf 0xef4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_SunkyeongeumPhieuf instead.") #define CLUTTER_Hangul_YeorinHieuh 0xef5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_YeorinHieuh instead.") #define CLUTTER_Hangul_AraeA 0xef6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_AraeA instead.") #define CLUTTER_Hangul_AraeAE 0xef7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_AraeAE instead.") #define CLUTTER_Hangul_J_PanSios 0xef8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_PanSios instead.") #define CLUTTER_Hangul_J_KkogjiDalrinIeung 0xef9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_KkogjiDalrinIeung instead.") #define CLUTTER_Hangul_J_YeorinHieuh 0xefa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Hangul_J_YeorinHieuh instead.") #define CLUTTER_Korean_Won 0xeff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Korean_Won instead.") #define CLUTTER_Armenian_ligature_ew 0x1000587 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ligature_ew instead.") #define CLUTTER_Armenian_full_stop 0x1000589 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_full_stop instead.") #define CLUTTER_Armenian_verjaket 0x1000589 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_verjaket instead.") #define CLUTTER_Armenian_separation_mark 0x100055d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_separation_mark instead.") #define CLUTTER_Armenian_but 0x100055d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_but instead.") #define CLUTTER_Armenian_hyphen 0x100058a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_hyphen instead.") #define CLUTTER_Armenian_yentamna 0x100058a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_yentamna instead.") #define CLUTTER_Armenian_exclam 0x100055c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_exclam instead.") #define CLUTTER_Armenian_amanak 0x100055c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_amanak instead.") #define CLUTTER_Armenian_accent 0x100055b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_accent instead.") #define CLUTTER_Armenian_shesht 0x100055b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_shesht instead.") #define CLUTTER_Armenian_question 0x100055e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_question instead.") #define CLUTTER_Armenian_paruyk 0x100055e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_paruyk instead.") #define CLUTTER_Armenian_AYB 0x1000531 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_AYB instead.") #define CLUTTER_Armenian_ayb 0x1000561 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ayb instead.") #define CLUTTER_Armenian_BEN 0x1000532 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_BEN instead.") #define CLUTTER_Armenian_ben 0x1000562 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ben instead.") #define CLUTTER_Armenian_GIM 0x1000533 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_GIM instead.") #define CLUTTER_Armenian_gim 0x1000563 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_gim instead.") #define CLUTTER_Armenian_DA 0x1000534 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_DA instead.") #define CLUTTER_Armenian_da 0x1000564 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_da instead.") #define CLUTTER_Armenian_YECH 0x1000535 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_YECH instead.") #define CLUTTER_Armenian_yech 0x1000565 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_yech instead.") #define CLUTTER_Armenian_ZA 0x1000536 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ZA instead.") #define CLUTTER_Armenian_za 0x1000566 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_za instead.") #define CLUTTER_Armenian_E 0x1000537 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_E instead.") #define CLUTTER_Armenian_e 0x1000567 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_e instead.") #define CLUTTER_Armenian_AT 0x1000538 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_AT instead.") #define CLUTTER_Armenian_at 0x1000568 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_at instead.") #define CLUTTER_Armenian_TO 0x1000539 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_TO instead.") #define CLUTTER_Armenian_to 0x1000569 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_to instead.") #define CLUTTER_Armenian_ZHE 0x100053a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ZHE instead.") #define CLUTTER_Armenian_zhe 0x100056a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_zhe instead.") #define CLUTTER_Armenian_INI 0x100053b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_INI instead.") #define CLUTTER_Armenian_ini 0x100056b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ini instead.") #define CLUTTER_Armenian_LYUN 0x100053c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_LYUN instead.") #define CLUTTER_Armenian_lyun 0x100056c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_lyun instead.") #define CLUTTER_Armenian_KHE 0x100053d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_KHE instead.") #define CLUTTER_Armenian_khe 0x100056d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_khe instead.") #define CLUTTER_Armenian_TSA 0x100053e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_TSA instead.") #define CLUTTER_Armenian_tsa 0x100056e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_tsa instead.") #define CLUTTER_Armenian_KEN 0x100053f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_KEN instead.") #define CLUTTER_Armenian_ken 0x100056f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ken instead.") #define CLUTTER_Armenian_HO 0x1000540 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_HO instead.") #define CLUTTER_Armenian_ho 0x1000570 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ho instead.") #define CLUTTER_Armenian_DZA 0x1000541 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_DZA instead.") #define CLUTTER_Armenian_dza 0x1000571 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_dza instead.") #define CLUTTER_Armenian_GHAT 0x1000542 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_GHAT instead.") #define CLUTTER_Armenian_ghat 0x1000572 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ghat instead.") #define CLUTTER_Armenian_TCHE 0x1000543 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_TCHE instead.") #define CLUTTER_Armenian_tche 0x1000573 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_tche instead.") #define CLUTTER_Armenian_MEN 0x1000544 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_MEN instead.") #define CLUTTER_Armenian_men 0x1000574 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_men instead.") #define CLUTTER_Armenian_HI 0x1000545 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_HI instead.") #define CLUTTER_Armenian_hi 0x1000575 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_hi instead.") #define CLUTTER_Armenian_NU 0x1000546 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_NU instead.") #define CLUTTER_Armenian_nu 0x1000576 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_nu instead.") #define CLUTTER_Armenian_SHA 0x1000547 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_SHA instead.") #define CLUTTER_Armenian_sha 0x1000577 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_sha instead.") #define CLUTTER_Armenian_VO 0x1000548 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_VO instead.") #define CLUTTER_Armenian_vo 0x1000578 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_vo instead.") #define CLUTTER_Armenian_CHA 0x1000549 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_CHA instead.") #define CLUTTER_Armenian_cha 0x1000579 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_cha instead.") #define CLUTTER_Armenian_PE 0x100054a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_PE instead.") #define CLUTTER_Armenian_pe 0x100057a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_pe instead.") #define CLUTTER_Armenian_JE 0x100054b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_JE instead.") #define CLUTTER_Armenian_je 0x100057b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_je instead.") #define CLUTTER_Armenian_RA 0x100054c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_RA instead.") #define CLUTTER_Armenian_ra 0x100057c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ra instead.") #define CLUTTER_Armenian_SE 0x100054d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_SE instead.") #define CLUTTER_Armenian_se 0x100057d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_se instead.") #define CLUTTER_Armenian_VEV 0x100054e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_VEV instead.") #define CLUTTER_Armenian_vev 0x100057e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_vev instead.") #define CLUTTER_Armenian_TYUN 0x100054f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_TYUN instead.") #define CLUTTER_Armenian_tyun 0x100057f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_tyun instead.") #define CLUTTER_Armenian_RE 0x1000550 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_RE instead.") #define CLUTTER_Armenian_re 0x1000580 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_re instead.") #define CLUTTER_Armenian_TSO 0x1000551 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_TSO instead.") #define CLUTTER_Armenian_tso 0x1000581 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_tso instead.") #define CLUTTER_Armenian_VYUN 0x1000552 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_VYUN instead.") #define CLUTTER_Armenian_vyun 0x1000582 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_vyun instead.") #define CLUTTER_Armenian_PYUR 0x1000553 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_PYUR instead.") #define CLUTTER_Armenian_pyur 0x1000583 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_pyur instead.") #define CLUTTER_Armenian_KE 0x1000554 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_KE instead.") #define CLUTTER_Armenian_ke 0x1000584 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_ke instead.") #define CLUTTER_Armenian_O 0x1000555 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_O instead.") #define CLUTTER_Armenian_o 0x1000585 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_o instead.") #define CLUTTER_Armenian_FE 0x1000556 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_FE instead.") #define CLUTTER_Armenian_fe 0x1000586 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_fe instead.") #define CLUTTER_Armenian_apostrophe 0x100055a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Armenian_apostrophe instead.") #define CLUTTER_Georgian_an 0x10010d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_an instead.") #define CLUTTER_Georgian_ban 0x10010d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_ban instead.") #define CLUTTER_Georgian_gan 0x10010d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_gan instead.") #define CLUTTER_Georgian_don 0x10010d3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_don instead.") #define CLUTTER_Georgian_en 0x10010d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_en instead.") #define CLUTTER_Georgian_vin 0x10010d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_vin instead.") #define CLUTTER_Georgian_zen 0x10010d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_zen instead.") #define CLUTTER_Georgian_tan 0x10010d7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_tan instead.") #define CLUTTER_Georgian_in 0x10010d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_in instead.") #define CLUTTER_Georgian_kan 0x10010d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_kan instead.") #define CLUTTER_Georgian_las 0x10010da CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_las instead.") #define CLUTTER_Georgian_man 0x10010db CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_man instead.") #define CLUTTER_Georgian_nar 0x10010dc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_nar instead.") #define CLUTTER_Georgian_on 0x10010dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_on instead.") #define CLUTTER_Georgian_par 0x10010de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_par instead.") #define CLUTTER_Georgian_zhar 0x10010df CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_zhar instead.") #define CLUTTER_Georgian_rae 0x10010e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_rae instead.") #define CLUTTER_Georgian_san 0x10010e1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_san instead.") #define CLUTTER_Georgian_tar 0x10010e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_tar instead.") #define CLUTTER_Georgian_un 0x10010e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_un instead.") #define CLUTTER_Georgian_phar 0x10010e4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_phar instead.") #define CLUTTER_Georgian_khar 0x10010e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_khar instead.") #define CLUTTER_Georgian_ghan 0x10010e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_ghan instead.") #define CLUTTER_Georgian_qar 0x10010e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_qar instead.") #define CLUTTER_Georgian_shin 0x10010e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_shin instead.") #define CLUTTER_Georgian_chin 0x10010e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_chin instead.") #define CLUTTER_Georgian_can 0x10010ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_can instead.") #define CLUTTER_Georgian_jil 0x10010eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_jil instead.") #define CLUTTER_Georgian_cil 0x10010ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_cil instead.") #define CLUTTER_Georgian_char 0x10010ed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_char instead.") #define CLUTTER_Georgian_xan 0x10010ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_xan instead.") #define CLUTTER_Georgian_jhan 0x10010ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_jhan instead.") #define CLUTTER_Georgian_hae 0x10010f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_hae instead.") #define CLUTTER_Georgian_he 0x10010f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_he instead.") #define CLUTTER_Georgian_hie 0x10010f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_hie instead.") #define CLUTTER_Georgian_we 0x10010f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_we instead.") #define CLUTTER_Georgian_har 0x10010f4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_har instead.") #define CLUTTER_Georgian_hoe 0x10010f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_hoe instead.") #define CLUTTER_Georgian_fi 0x10010f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Georgian_fi instead.") #define CLUTTER_Xabovedot 0x1001e8a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Xabovedot instead.") #define CLUTTER_Ibreve 0x100012c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ibreve instead.") #define CLUTTER_Zstroke 0x10001b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Zstroke instead.") #define CLUTTER_Gcaron 0x10001e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Gcaron instead.") #define CLUTTER_Ocaron 0x10001d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ocaron instead.") #define CLUTTER_Obarred 0x100019f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Obarred instead.") #define CLUTTER_xabovedot 0x1001e8b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_xabovedot instead.") #define CLUTTER_ibreve 0x100012d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ibreve instead.") #define CLUTTER_zstroke 0x10001b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_zstroke instead.") #define CLUTTER_gcaron 0x10001e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_gcaron instead.") #define CLUTTER_ocaron 0x10001d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ocaron instead.") #define CLUTTER_obarred 0x1000275 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_obarred instead.") #define CLUTTER_SCHWA 0x100018f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_SCHWA instead.") #define CLUTTER_schwa 0x1000259 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_schwa instead.") #define CLUTTER_EZH 0x10001b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_EZH instead.") #define CLUTTER_ezh 0x1000292 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ezh instead.") #define CLUTTER_Lbelowdot 0x1001e36 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Lbelowdot instead.") #define CLUTTER_lbelowdot 0x1001e37 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_lbelowdot instead.") #define CLUTTER_Abelowdot 0x1001ea0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Abelowdot instead.") #define CLUTTER_abelowdot 0x1001ea1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abelowdot instead.") #define CLUTTER_Ahook 0x1001ea2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ahook instead.") #define CLUTTER_ahook 0x1001ea3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ahook instead.") #define CLUTTER_Acircumflexacute 0x1001ea4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Acircumflexacute instead.") #define CLUTTER_acircumflexacute 0x1001ea5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_acircumflexacute instead.") #define CLUTTER_Acircumflexgrave 0x1001ea6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Acircumflexgrave instead.") #define CLUTTER_acircumflexgrave 0x1001ea7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_acircumflexgrave instead.") #define CLUTTER_Acircumflexhook 0x1001ea8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Acircumflexhook instead.") #define CLUTTER_acircumflexhook 0x1001ea9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_acircumflexhook instead.") #define CLUTTER_Acircumflextilde 0x1001eaa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Acircumflextilde instead.") #define CLUTTER_acircumflextilde 0x1001eab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_acircumflextilde instead.") #define CLUTTER_Acircumflexbelowdot 0x1001eac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Acircumflexbelowdot instead.") #define CLUTTER_acircumflexbelowdot 0x1001ead CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_acircumflexbelowdot instead.") #define CLUTTER_Abreveacute 0x1001eae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Abreveacute instead.") #define CLUTTER_abreveacute 0x1001eaf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abreveacute instead.") #define CLUTTER_Abrevegrave 0x1001eb0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Abrevegrave instead.") #define CLUTTER_abrevegrave 0x1001eb1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abrevegrave instead.") #define CLUTTER_Abrevehook 0x1001eb2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Abrevehook instead.") #define CLUTTER_abrevehook 0x1001eb3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abrevehook instead.") #define CLUTTER_Abrevetilde 0x1001eb4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Abrevetilde instead.") #define CLUTTER_abrevetilde 0x1001eb5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abrevetilde instead.") #define CLUTTER_Abrevebelowdot 0x1001eb6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Abrevebelowdot instead.") #define CLUTTER_abrevebelowdot 0x1001eb7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_abrevebelowdot instead.") #define CLUTTER_Ebelowdot 0x1001eb8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ebelowdot instead.") #define CLUTTER_ebelowdot 0x1001eb9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ebelowdot instead.") #define CLUTTER_Ehook 0x1001eba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ehook instead.") #define CLUTTER_ehook 0x1001ebb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ehook instead.") #define CLUTTER_Etilde 0x1001ebc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Etilde instead.") #define CLUTTER_etilde 0x1001ebd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_etilde instead.") #define CLUTTER_Ecircumflexacute 0x1001ebe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ecircumflexacute instead.") #define CLUTTER_ecircumflexacute 0x1001ebf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ecircumflexacute instead.") #define CLUTTER_Ecircumflexgrave 0x1001ec0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ecircumflexgrave instead.") #define CLUTTER_ecircumflexgrave 0x1001ec1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ecircumflexgrave instead.") #define CLUTTER_Ecircumflexhook 0x1001ec2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ecircumflexhook instead.") #define CLUTTER_ecircumflexhook 0x1001ec3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ecircumflexhook instead.") #define CLUTTER_Ecircumflextilde 0x1001ec4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ecircumflextilde instead.") #define CLUTTER_ecircumflextilde 0x1001ec5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ecircumflextilde instead.") #define CLUTTER_Ecircumflexbelowdot 0x1001ec6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ecircumflexbelowdot instead.") #define CLUTTER_ecircumflexbelowdot 0x1001ec7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ecircumflexbelowdot instead.") #define CLUTTER_Ihook 0x1001ec8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ihook instead.") #define CLUTTER_ihook 0x1001ec9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ihook instead.") #define CLUTTER_Ibelowdot 0x1001eca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ibelowdot instead.") #define CLUTTER_ibelowdot 0x1001ecb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ibelowdot instead.") #define CLUTTER_Obelowdot 0x1001ecc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Obelowdot instead.") #define CLUTTER_obelowdot 0x1001ecd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_obelowdot instead.") #define CLUTTER_Ohook 0x1001ece CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ohook instead.") #define CLUTTER_ohook 0x1001ecf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ohook instead.") #define CLUTTER_Ocircumflexacute 0x1001ed0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ocircumflexacute instead.") #define CLUTTER_ocircumflexacute 0x1001ed1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ocircumflexacute instead.") #define CLUTTER_Ocircumflexgrave 0x1001ed2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ocircumflexgrave instead.") #define CLUTTER_ocircumflexgrave 0x1001ed3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ocircumflexgrave instead.") #define CLUTTER_Ocircumflexhook 0x1001ed4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ocircumflexhook instead.") #define CLUTTER_ocircumflexhook 0x1001ed5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ocircumflexhook instead.") #define CLUTTER_Ocircumflextilde 0x1001ed6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ocircumflextilde instead.") #define CLUTTER_ocircumflextilde 0x1001ed7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ocircumflextilde instead.") #define CLUTTER_Ocircumflexbelowdot 0x1001ed8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ocircumflexbelowdot instead.") #define CLUTTER_ocircumflexbelowdot 0x1001ed9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ocircumflexbelowdot instead.") #define CLUTTER_Ohornacute 0x1001eda CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ohornacute instead.") #define CLUTTER_ohornacute 0x1001edb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ohornacute instead.") #define CLUTTER_Ohorngrave 0x1001edc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ohorngrave instead.") #define CLUTTER_ohorngrave 0x1001edd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ohorngrave instead.") #define CLUTTER_Ohornhook 0x1001ede CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ohornhook instead.") #define CLUTTER_ohornhook 0x1001edf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ohornhook instead.") #define CLUTTER_Ohorntilde 0x1001ee0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ohorntilde instead.") #define CLUTTER_ohorntilde 0x1001ee1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ohorntilde instead.") #define CLUTTER_Ohornbelowdot 0x1001ee2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ohornbelowdot instead.") #define CLUTTER_ohornbelowdot 0x1001ee3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ohornbelowdot instead.") #define CLUTTER_Ubelowdot 0x1001ee4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ubelowdot instead.") #define CLUTTER_ubelowdot 0x1001ee5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ubelowdot instead.") #define CLUTTER_Uhook 0x1001ee6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uhook instead.") #define CLUTTER_uhook 0x1001ee7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uhook instead.") #define CLUTTER_Uhornacute 0x1001ee8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uhornacute instead.") #define CLUTTER_uhornacute 0x1001ee9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uhornacute instead.") #define CLUTTER_Uhorngrave 0x1001eea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uhorngrave instead.") #define CLUTTER_uhorngrave 0x1001eeb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uhorngrave instead.") #define CLUTTER_Uhornhook 0x1001eec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uhornhook instead.") #define CLUTTER_uhornhook 0x1001eed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uhornhook instead.") #define CLUTTER_Uhorntilde 0x1001eee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uhorntilde instead.") #define CLUTTER_uhorntilde 0x1001eef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uhorntilde instead.") #define CLUTTER_Uhornbelowdot 0x1001ef0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uhornbelowdot instead.") #define CLUTTER_uhornbelowdot 0x1001ef1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uhornbelowdot instead.") #define CLUTTER_Ybelowdot 0x1001ef4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ybelowdot instead.") #define CLUTTER_ybelowdot 0x1001ef5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ybelowdot instead.") #define CLUTTER_Yhook 0x1001ef6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Yhook instead.") #define CLUTTER_yhook 0x1001ef7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_yhook instead.") #define CLUTTER_Ytilde 0x1001ef8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ytilde instead.") #define CLUTTER_ytilde 0x1001ef9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ytilde instead.") #define CLUTTER_Ohorn 0x10001a0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Ohorn instead.") #define CLUTTER_ohorn 0x10001a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ohorn instead.") #define CLUTTER_Uhorn 0x10001af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Uhorn instead.") #define CLUTTER_uhorn 0x10001b0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_uhorn instead.") #define CLUTTER_EcuSign 0x10020a0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_EcuSign instead.") #define CLUTTER_ColonSign 0x10020a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ColonSign instead.") #define CLUTTER_CruzeiroSign 0x10020a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_CruzeiroSign instead.") #define CLUTTER_FFrancSign 0x10020a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_FFrancSign instead.") #define CLUTTER_LiraSign 0x10020a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_LiraSign instead.") #define CLUTTER_MillSign 0x10020a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_MillSign instead.") #define CLUTTER_NairaSign 0x10020a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_NairaSign instead.") #define CLUTTER_PesetaSign 0x10020a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_PesetaSign instead.") #define CLUTTER_RupeeSign 0x10020a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_RupeeSign instead.") #define CLUTTER_WonSign 0x10020a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_WonSign instead.") #define CLUTTER_NewSheqelSign 0x10020aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_NewSheqelSign instead.") #define CLUTTER_DongSign 0x10020ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_DongSign instead.") #define CLUTTER_EuroSign 0x20ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_EuroSign instead.") #define CLUTTER_zerosuperior 0x1002070 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_zerosuperior instead.") #define CLUTTER_foursuperior 0x1002074 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_foursuperior instead.") #define CLUTTER_fivesuperior 0x1002075 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_fivesuperior instead.") #define CLUTTER_sixsuperior 0x1002076 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_sixsuperior instead.") #define CLUTTER_sevensuperior 0x1002077 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_sevensuperior instead.") #define CLUTTER_eightsuperior 0x1002078 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_eightsuperior instead.") #define CLUTTER_ninesuperior 0x1002079 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ninesuperior instead.") #define CLUTTER_zerosubscript 0x1002080 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_zerosubscript instead.") #define CLUTTER_onesubscript 0x1002081 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_onesubscript instead.") #define CLUTTER_twosubscript 0x1002082 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_twosubscript instead.") #define CLUTTER_threesubscript 0x1002083 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_threesubscript instead.") #define CLUTTER_foursubscript 0x1002084 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_foursubscript instead.") #define CLUTTER_fivesubscript 0x1002085 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_fivesubscript instead.") #define CLUTTER_sixsubscript 0x1002086 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_sixsubscript instead.") #define CLUTTER_sevensubscript 0x1002087 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_sevensubscript instead.") #define CLUTTER_eightsubscript 0x1002088 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_eightsubscript instead.") #define CLUTTER_ninesubscript 0x1002089 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_ninesubscript instead.") #define CLUTTER_partdifferential 0x1002202 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_partdifferential instead.") #define CLUTTER_emptyset 0x1002205 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_emptyset instead.") #define CLUTTER_elementof 0x1002208 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_elementof instead.") #define CLUTTER_notelementof 0x1002209 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_notelementof instead.") #define CLUTTER_containsas 0x100220b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_containsas instead.") #define CLUTTER_squareroot 0x100221a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_squareroot instead.") #define CLUTTER_cuberoot 0x100221b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_cuberoot instead.") #define CLUTTER_fourthroot 0x100221c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_fourthroot instead.") #define CLUTTER_dintegral 0x100222c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_dintegral instead.") #define CLUTTER_tintegral 0x100222d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_tintegral instead.") #define CLUTTER_because 0x1002235 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_because instead.") #define CLUTTER_approxeq 0x1002248 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_approxeq instead.") #define CLUTTER_notapproxeq 0x1002247 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_notapproxeq instead.") #define CLUTTER_notidentical 0x1002262 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_notidentical instead.") #define CLUTTER_stricteq 0x1002263 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_stricteq instead.") #define CLUTTER_braille_dot_1 0xfff1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_1 instead.") #define CLUTTER_braille_dot_2 0xfff2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_2 instead.") #define CLUTTER_braille_dot_3 0xfff3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_3 instead.") #define CLUTTER_braille_dot_4 0xfff4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_4 instead.") #define CLUTTER_braille_dot_5 0xfff5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_5 instead.") #define CLUTTER_braille_dot_6 0xfff6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_6 instead.") #define CLUTTER_braille_dot_7 0xfff7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_7 instead.") #define CLUTTER_braille_dot_8 0xfff8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_8 instead.") #define CLUTTER_braille_dot_9 0xfff9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_9 instead.") #define CLUTTER_braille_dot_10 0xfffa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dot_10 instead.") #define CLUTTER_braille_blank 0x1002800 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_blank instead.") #define CLUTTER_braille_dots_1 0x1002801 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1 instead.") #define CLUTTER_braille_dots_2 0x1002802 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2 instead.") #define CLUTTER_braille_dots_12 0x1002803 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12 instead.") #define CLUTTER_braille_dots_3 0x1002804 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3 instead.") #define CLUTTER_braille_dots_13 0x1002805 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13 instead.") #define CLUTTER_braille_dots_23 0x1002806 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23 instead.") #define CLUTTER_braille_dots_123 0x1002807 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123 instead.") #define CLUTTER_braille_dots_4 0x1002808 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_4 instead.") #define CLUTTER_braille_dots_14 0x1002809 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_14 instead.") #define CLUTTER_braille_dots_24 0x100280a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_24 instead.") #define CLUTTER_braille_dots_124 0x100280b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_124 instead.") #define CLUTTER_braille_dots_34 0x100280c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_34 instead.") #define CLUTTER_braille_dots_134 0x100280d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_134 instead.") #define CLUTTER_braille_dots_234 0x100280e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_234 instead.") #define CLUTTER_braille_dots_1234 0x100280f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1234 instead.") #define CLUTTER_braille_dots_5 0x1002810 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_5 instead.") #define CLUTTER_braille_dots_15 0x1002811 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_15 instead.") #define CLUTTER_braille_dots_25 0x1002812 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_25 instead.") #define CLUTTER_braille_dots_125 0x1002813 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_125 instead.") #define CLUTTER_braille_dots_35 0x1002814 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_35 instead.") #define CLUTTER_braille_dots_135 0x1002815 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_135 instead.") #define CLUTTER_braille_dots_235 0x1002816 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_235 instead.") #define CLUTTER_braille_dots_1235 0x1002817 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1235 instead.") #define CLUTTER_braille_dots_45 0x1002818 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_45 instead.") #define CLUTTER_braille_dots_145 0x1002819 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_145 instead.") #define CLUTTER_braille_dots_245 0x100281a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_245 instead.") #define CLUTTER_braille_dots_1245 0x100281b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1245 instead.") #define CLUTTER_braille_dots_345 0x100281c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_345 instead.") #define CLUTTER_braille_dots_1345 0x100281d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1345 instead.") #define CLUTTER_braille_dots_2345 0x100281e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2345 instead.") #define CLUTTER_braille_dots_12345 0x100281f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12345 instead.") #define CLUTTER_braille_dots_6 0x1002820 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_6 instead.") #define CLUTTER_braille_dots_16 0x1002821 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_16 instead.") #define CLUTTER_braille_dots_26 0x1002822 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_26 instead.") #define CLUTTER_braille_dots_126 0x1002823 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_126 instead.") #define CLUTTER_braille_dots_36 0x1002824 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_36 instead.") #define CLUTTER_braille_dots_136 0x1002825 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_136 instead.") #define CLUTTER_braille_dots_236 0x1002826 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_236 instead.") #define CLUTTER_braille_dots_1236 0x1002827 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1236 instead.") #define CLUTTER_braille_dots_46 0x1002828 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_46 instead.") #define CLUTTER_braille_dots_146 0x1002829 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_146 instead.") #define CLUTTER_braille_dots_246 0x100282a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_246 instead.") #define CLUTTER_braille_dots_1246 0x100282b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1246 instead.") #define CLUTTER_braille_dots_346 0x100282c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_346 instead.") #define CLUTTER_braille_dots_1346 0x100282d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1346 instead.") #define CLUTTER_braille_dots_2346 0x100282e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2346 instead.") #define CLUTTER_braille_dots_12346 0x100282f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12346 instead.") #define CLUTTER_braille_dots_56 0x1002830 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_56 instead.") #define CLUTTER_braille_dots_156 0x1002831 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_156 instead.") #define CLUTTER_braille_dots_256 0x1002832 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_256 instead.") #define CLUTTER_braille_dots_1256 0x1002833 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1256 instead.") #define CLUTTER_braille_dots_356 0x1002834 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_356 instead.") #define CLUTTER_braille_dots_1356 0x1002835 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1356 instead.") #define CLUTTER_braille_dots_2356 0x1002836 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2356 instead.") #define CLUTTER_braille_dots_12356 0x1002837 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12356 instead.") #define CLUTTER_braille_dots_456 0x1002838 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_456 instead.") #define CLUTTER_braille_dots_1456 0x1002839 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1456 instead.") #define CLUTTER_braille_dots_2456 0x100283a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2456 instead.") #define CLUTTER_braille_dots_12456 0x100283b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12456 instead.") #define CLUTTER_braille_dots_3456 0x100283c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3456 instead.") #define CLUTTER_braille_dots_13456 0x100283d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13456 instead.") #define CLUTTER_braille_dots_23456 0x100283e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23456 instead.") #define CLUTTER_braille_dots_123456 0x100283f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123456 instead.") #define CLUTTER_braille_dots_7 0x1002840 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_7 instead.") #define CLUTTER_braille_dots_17 0x1002841 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_17 instead.") #define CLUTTER_braille_dots_27 0x1002842 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_27 instead.") #define CLUTTER_braille_dots_127 0x1002843 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_127 instead.") #define CLUTTER_braille_dots_37 0x1002844 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_37 instead.") #define CLUTTER_braille_dots_137 0x1002845 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_137 instead.") #define CLUTTER_braille_dots_237 0x1002846 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_237 instead.") #define CLUTTER_braille_dots_1237 0x1002847 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1237 instead.") #define CLUTTER_braille_dots_47 0x1002848 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_47 instead.") #define CLUTTER_braille_dots_147 0x1002849 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_147 instead.") #define CLUTTER_braille_dots_247 0x100284a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_247 instead.") #define CLUTTER_braille_dots_1247 0x100284b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1247 instead.") #define CLUTTER_braille_dots_347 0x100284c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_347 instead.") #define CLUTTER_braille_dots_1347 0x100284d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1347 instead.") #define CLUTTER_braille_dots_2347 0x100284e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2347 instead.") #define CLUTTER_braille_dots_12347 0x100284f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12347 instead.") #define CLUTTER_braille_dots_57 0x1002850 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_57 instead.") #define CLUTTER_braille_dots_157 0x1002851 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_157 instead.") #define CLUTTER_braille_dots_257 0x1002852 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_257 instead.") #define CLUTTER_braille_dots_1257 0x1002853 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1257 instead.") #define CLUTTER_braille_dots_357 0x1002854 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_357 instead.") #define CLUTTER_braille_dots_1357 0x1002855 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1357 instead.") #define CLUTTER_braille_dots_2357 0x1002856 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2357 instead.") #define CLUTTER_braille_dots_12357 0x1002857 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12357 instead.") #define CLUTTER_braille_dots_457 0x1002858 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_457 instead.") #define CLUTTER_braille_dots_1457 0x1002859 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1457 instead.") #define CLUTTER_braille_dots_2457 0x100285a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2457 instead.") #define CLUTTER_braille_dots_12457 0x100285b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12457 instead.") #define CLUTTER_braille_dots_3457 0x100285c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3457 instead.") #define CLUTTER_braille_dots_13457 0x100285d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13457 instead.") #define CLUTTER_braille_dots_23457 0x100285e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23457 instead.") #define CLUTTER_braille_dots_123457 0x100285f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123457 instead.") #define CLUTTER_braille_dots_67 0x1002860 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_67 instead.") #define CLUTTER_braille_dots_167 0x1002861 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_167 instead.") #define CLUTTER_braille_dots_267 0x1002862 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_267 instead.") #define CLUTTER_braille_dots_1267 0x1002863 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1267 instead.") #define CLUTTER_braille_dots_367 0x1002864 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_367 instead.") #define CLUTTER_braille_dots_1367 0x1002865 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1367 instead.") #define CLUTTER_braille_dots_2367 0x1002866 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2367 instead.") #define CLUTTER_braille_dots_12367 0x1002867 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12367 instead.") #define CLUTTER_braille_dots_467 0x1002868 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_467 instead.") #define CLUTTER_braille_dots_1467 0x1002869 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1467 instead.") #define CLUTTER_braille_dots_2467 0x100286a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2467 instead.") #define CLUTTER_braille_dots_12467 0x100286b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12467 instead.") #define CLUTTER_braille_dots_3467 0x100286c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3467 instead.") #define CLUTTER_braille_dots_13467 0x100286d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13467 instead.") #define CLUTTER_braille_dots_23467 0x100286e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23467 instead.") #define CLUTTER_braille_dots_123467 0x100286f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123467 instead.") #define CLUTTER_braille_dots_567 0x1002870 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_567 instead.") #define CLUTTER_braille_dots_1567 0x1002871 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1567 instead.") #define CLUTTER_braille_dots_2567 0x1002872 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2567 instead.") #define CLUTTER_braille_dots_12567 0x1002873 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12567 instead.") #define CLUTTER_braille_dots_3567 0x1002874 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3567 instead.") #define CLUTTER_braille_dots_13567 0x1002875 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13567 instead.") #define CLUTTER_braille_dots_23567 0x1002876 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23567 instead.") #define CLUTTER_braille_dots_123567 0x1002877 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123567 instead.") #define CLUTTER_braille_dots_4567 0x1002878 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_4567 instead.") #define CLUTTER_braille_dots_14567 0x1002879 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_14567 instead.") #define CLUTTER_braille_dots_24567 0x100287a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_24567 instead.") #define CLUTTER_braille_dots_124567 0x100287b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_124567 instead.") #define CLUTTER_braille_dots_34567 0x100287c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_34567 instead.") #define CLUTTER_braille_dots_134567 0x100287d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_134567 instead.") #define CLUTTER_braille_dots_234567 0x100287e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_234567 instead.") #define CLUTTER_braille_dots_1234567 0x100287f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1234567 instead.") #define CLUTTER_braille_dots_8 0x1002880 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_8 instead.") #define CLUTTER_braille_dots_18 0x1002881 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_18 instead.") #define CLUTTER_braille_dots_28 0x1002882 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_28 instead.") #define CLUTTER_braille_dots_128 0x1002883 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_128 instead.") #define CLUTTER_braille_dots_38 0x1002884 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_38 instead.") #define CLUTTER_braille_dots_138 0x1002885 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_138 instead.") #define CLUTTER_braille_dots_238 0x1002886 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_238 instead.") #define CLUTTER_braille_dots_1238 0x1002887 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1238 instead.") #define CLUTTER_braille_dots_48 0x1002888 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_48 instead.") #define CLUTTER_braille_dots_148 0x1002889 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_148 instead.") #define CLUTTER_braille_dots_248 0x100288a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_248 instead.") #define CLUTTER_braille_dots_1248 0x100288b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1248 instead.") #define CLUTTER_braille_dots_348 0x100288c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_348 instead.") #define CLUTTER_braille_dots_1348 0x100288d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1348 instead.") #define CLUTTER_braille_dots_2348 0x100288e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2348 instead.") #define CLUTTER_braille_dots_12348 0x100288f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12348 instead.") #define CLUTTER_braille_dots_58 0x1002890 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_58 instead.") #define CLUTTER_braille_dots_158 0x1002891 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_158 instead.") #define CLUTTER_braille_dots_258 0x1002892 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_258 instead.") #define CLUTTER_braille_dots_1258 0x1002893 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1258 instead.") #define CLUTTER_braille_dots_358 0x1002894 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_358 instead.") #define CLUTTER_braille_dots_1358 0x1002895 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1358 instead.") #define CLUTTER_braille_dots_2358 0x1002896 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2358 instead.") #define CLUTTER_braille_dots_12358 0x1002897 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12358 instead.") #define CLUTTER_braille_dots_458 0x1002898 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_458 instead.") #define CLUTTER_braille_dots_1458 0x1002899 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1458 instead.") #define CLUTTER_braille_dots_2458 0x100289a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2458 instead.") #define CLUTTER_braille_dots_12458 0x100289b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12458 instead.") #define CLUTTER_braille_dots_3458 0x100289c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3458 instead.") #define CLUTTER_braille_dots_13458 0x100289d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13458 instead.") #define CLUTTER_braille_dots_23458 0x100289e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23458 instead.") #define CLUTTER_braille_dots_123458 0x100289f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123458 instead.") #define CLUTTER_braille_dots_68 0x10028a0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_68 instead.") #define CLUTTER_braille_dots_168 0x10028a1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_168 instead.") #define CLUTTER_braille_dots_268 0x10028a2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_268 instead.") #define CLUTTER_braille_dots_1268 0x10028a3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1268 instead.") #define CLUTTER_braille_dots_368 0x10028a4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_368 instead.") #define CLUTTER_braille_dots_1368 0x10028a5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1368 instead.") #define CLUTTER_braille_dots_2368 0x10028a6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2368 instead.") #define CLUTTER_braille_dots_12368 0x10028a7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12368 instead.") #define CLUTTER_braille_dots_468 0x10028a8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_468 instead.") #define CLUTTER_braille_dots_1468 0x10028a9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1468 instead.") #define CLUTTER_braille_dots_2468 0x10028aa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2468 instead.") #define CLUTTER_braille_dots_12468 0x10028ab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12468 instead.") #define CLUTTER_braille_dots_3468 0x10028ac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3468 instead.") #define CLUTTER_braille_dots_13468 0x10028ad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13468 instead.") #define CLUTTER_braille_dots_23468 0x10028ae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23468 instead.") #define CLUTTER_braille_dots_123468 0x10028af CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123468 instead.") #define CLUTTER_braille_dots_568 0x10028b0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_568 instead.") #define CLUTTER_braille_dots_1568 0x10028b1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1568 instead.") #define CLUTTER_braille_dots_2568 0x10028b2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2568 instead.") #define CLUTTER_braille_dots_12568 0x10028b3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12568 instead.") #define CLUTTER_braille_dots_3568 0x10028b4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3568 instead.") #define CLUTTER_braille_dots_13568 0x10028b5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13568 instead.") #define CLUTTER_braille_dots_23568 0x10028b6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23568 instead.") #define CLUTTER_braille_dots_123568 0x10028b7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123568 instead.") #define CLUTTER_braille_dots_4568 0x10028b8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_4568 instead.") #define CLUTTER_braille_dots_14568 0x10028b9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_14568 instead.") #define CLUTTER_braille_dots_24568 0x10028ba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_24568 instead.") #define CLUTTER_braille_dots_124568 0x10028bb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_124568 instead.") #define CLUTTER_braille_dots_34568 0x10028bc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_34568 instead.") #define CLUTTER_braille_dots_134568 0x10028bd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_134568 instead.") #define CLUTTER_braille_dots_234568 0x10028be CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_234568 instead.") #define CLUTTER_braille_dots_1234568 0x10028bf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1234568 instead.") #define CLUTTER_braille_dots_78 0x10028c0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_78 instead.") #define CLUTTER_braille_dots_178 0x10028c1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_178 instead.") #define CLUTTER_braille_dots_278 0x10028c2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_278 instead.") #define CLUTTER_braille_dots_1278 0x10028c3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1278 instead.") #define CLUTTER_braille_dots_378 0x10028c4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_378 instead.") #define CLUTTER_braille_dots_1378 0x10028c5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1378 instead.") #define CLUTTER_braille_dots_2378 0x10028c6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2378 instead.") #define CLUTTER_braille_dots_12378 0x10028c7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12378 instead.") #define CLUTTER_braille_dots_478 0x10028c8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_478 instead.") #define CLUTTER_braille_dots_1478 0x10028c9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1478 instead.") #define CLUTTER_braille_dots_2478 0x10028ca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2478 instead.") #define CLUTTER_braille_dots_12478 0x10028cb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12478 instead.") #define CLUTTER_braille_dots_3478 0x10028cc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3478 instead.") #define CLUTTER_braille_dots_13478 0x10028cd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13478 instead.") #define CLUTTER_braille_dots_23478 0x10028ce CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23478 instead.") #define CLUTTER_braille_dots_123478 0x10028cf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123478 instead.") #define CLUTTER_braille_dots_578 0x10028d0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_578 instead.") #define CLUTTER_braille_dots_1578 0x10028d1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1578 instead.") #define CLUTTER_braille_dots_2578 0x10028d2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2578 instead.") #define CLUTTER_braille_dots_12578 0x10028d3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12578 instead.") #define CLUTTER_braille_dots_3578 0x10028d4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3578 instead.") #define CLUTTER_braille_dots_13578 0x10028d5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13578 instead.") #define CLUTTER_braille_dots_23578 0x10028d6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23578 instead.") #define CLUTTER_braille_dots_123578 0x10028d7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123578 instead.") #define CLUTTER_braille_dots_4578 0x10028d8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_4578 instead.") #define CLUTTER_braille_dots_14578 0x10028d9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_14578 instead.") #define CLUTTER_braille_dots_24578 0x10028da CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_24578 instead.") #define CLUTTER_braille_dots_124578 0x10028db CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_124578 instead.") #define CLUTTER_braille_dots_34578 0x10028dc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_34578 instead.") #define CLUTTER_braille_dots_134578 0x10028dd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_134578 instead.") #define CLUTTER_braille_dots_234578 0x10028de CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_234578 instead.") #define CLUTTER_braille_dots_1234578 0x10028df CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1234578 instead.") #define CLUTTER_braille_dots_678 0x10028e0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_678 instead.") #define CLUTTER_braille_dots_1678 0x10028e1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1678 instead.") #define CLUTTER_braille_dots_2678 0x10028e2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2678 instead.") #define CLUTTER_braille_dots_12678 0x10028e3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12678 instead.") #define CLUTTER_braille_dots_3678 0x10028e4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_3678 instead.") #define CLUTTER_braille_dots_13678 0x10028e5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_13678 instead.") #define CLUTTER_braille_dots_23678 0x10028e6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_23678 instead.") #define CLUTTER_braille_dots_123678 0x10028e7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_123678 instead.") #define CLUTTER_braille_dots_4678 0x10028e8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_4678 instead.") #define CLUTTER_braille_dots_14678 0x10028e9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_14678 instead.") #define CLUTTER_braille_dots_24678 0x10028ea CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_24678 instead.") #define CLUTTER_braille_dots_124678 0x10028eb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_124678 instead.") #define CLUTTER_braille_dots_34678 0x10028ec CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_34678 instead.") #define CLUTTER_braille_dots_134678 0x10028ed CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_134678 instead.") #define CLUTTER_braille_dots_234678 0x10028ee CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_234678 instead.") #define CLUTTER_braille_dots_1234678 0x10028ef CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1234678 instead.") #define CLUTTER_braille_dots_5678 0x10028f0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_5678 instead.") #define CLUTTER_braille_dots_15678 0x10028f1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_15678 instead.") #define CLUTTER_braille_dots_25678 0x10028f2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_25678 instead.") #define CLUTTER_braille_dots_125678 0x10028f3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_125678 instead.") #define CLUTTER_braille_dots_35678 0x10028f4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_35678 instead.") #define CLUTTER_braille_dots_135678 0x10028f5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_135678 instead.") #define CLUTTER_braille_dots_235678 0x10028f6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_235678 instead.") #define CLUTTER_braille_dots_1235678 0x10028f7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1235678 instead.") #define CLUTTER_braille_dots_45678 0x10028f8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_45678 instead.") #define CLUTTER_braille_dots_145678 0x10028f9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_145678 instead.") #define CLUTTER_braille_dots_245678 0x10028fa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_245678 instead.") #define CLUTTER_braille_dots_1245678 0x10028fb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1245678 instead.") #define CLUTTER_braille_dots_345678 0x10028fc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_345678 instead.") #define CLUTTER_braille_dots_1345678 0x10028fd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_1345678 instead.") #define CLUTTER_braille_dots_2345678 0x10028fe CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_2345678 instead.") #define CLUTTER_braille_dots_12345678 0x10028ff CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_braille_dots_12345678 instead.") #define CLUTTER_Sinh_ng 0x1000d82 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ng instead.") #define CLUTTER_Sinh_h2 0x1000d83 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_h2 instead.") #define CLUTTER_Sinh_a 0x1000d85 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_a instead.") #define CLUTTER_Sinh_aa 0x1000d86 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_aa instead.") #define CLUTTER_Sinh_ae 0x1000d87 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ae instead.") #define CLUTTER_Sinh_aee 0x1000d88 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_aee instead.") #define CLUTTER_Sinh_i 0x1000d89 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_i instead.") #define CLUTTER_Sinh_ii 0x1000d8a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ii instead.") #define CLUTTER_Sinh_u 0x1000d8b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_u instead.") #define CLUTTER_Sinh_uu 0x1000d8c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_uu instead.") #define CLUTTER_Sinh_ri 0x1000d8d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ri instead.") #define CLUTTER_Sinh_rii 0x1000d8e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_rii instead.") #define CLUTTER_Sinh_lu 0x1000d8f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_lu instead.") #define CLUTTER_Sinh_luu 0x1000d90 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_luu instead.") #define CLUTTER_Sinh_e 0x1000d91 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_e instead.") #define CLUTTER_Sinh_ee 0x1000d92 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ee instead.") #define CLUTTER_Sinh_ai 0x1000d93 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ai instead.") #define CLUTTER_Sinh_o 0x1000d94 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_o instead.") #define CLUTTER_Sinh_oo 0x1000d95 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_oo instead.") #define CLUTTER_Sinh_au 0x1000d96 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_au instead.") #define CLUTTER_Sinh_ka 0x1000d9a CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ka instead.") #define CLUTTER_Sinh_kha 0x1000d9b CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_kha instead.") #define CLUTTER_Sinh_ga 0x1000d9c CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ga instead.") #define CLUTTER_Sinh_gha 0x1000d9d CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_gha instead.") #define CLUTTER_Sinh_ng2 0x1000d9e CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ng2 instead.") #define CLUTTER_Sinh_nga 0x1000d9f CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_nga instead.") #define CLUTTER_Sinh_ca 0x1000da0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ca instead.") #define CLUTTER_Sinh_cha 0x1000da1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_cha instead.") #define CLUTTER_Sinh_ja 0x1000da2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ja instead.") #define CLUTTER_Sinh_jha 0x1000da3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_jha instead.") #define CLUTTER_Sinh_nya 0x1000da4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_nya instead.") #define CLUTTER_Sinh_jnya 0x1000da5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_jnya instead.") #define CLUTTER_Sinh_nja 0x1000da6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_nja instead.") #define CLUTTER_Sinh_tta 0x1000da7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_tta instead.") #define CLUTTER_Sinh_ttha 0x1000da8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ttha instead.") #define CLUTTER_Sinh_dda 0x1000da9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_dda instead.") #define CLUTTER_Sinh_ddha 0x1000daa CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ddha instead.") #define CLUTTER_Sinh_nna 0x1000dab CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_nna instead.") #define CLUTTER_Sinh_ndda 0x1000dac CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ndda instead.") #define CLUTTER_Sinh_tha 0x1000dad CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_tha instead.") #define CLUTTER_Sinh_thha 0x1000dae CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_thha instead.") #define CLUTTER_Sinh_dha 0x1000daf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_dha instead.") #define CLUTTER_Sinh_dhha 0x1000db0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_dhha instead.") #define CLUTTER_Sinh_na 0x1000db1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_na instead.") #define CLUTTER_Sinh_ndha 0x1000db3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ndha instead.") #define CLUTTER_Sinh_pa 0x1000db4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_pa instead.") #define CLUTTER_Sinh_pha 0x1000db5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_pha instead.") #define CLUTTER_Sinh_ba 0x1000db6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ba instead.") #define CLUTTER_Sinh_bha 0x1000db7 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_bha instead.") #define CLUTTER_Sinh_ma 0x1000db8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ma instead.") #define CLUTTER_Sinh_mba 0x1000db9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_mba instead.") #define CLUTTER_Sinh_ya 0x1000dba CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ya instead.") #define CLUTTER_Sinh_ra 0x1000dbb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ra instead.") #define CLUTTER_Sinh_la 0x1000dbd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_la instead.") #define CLUTTER_Sinh_va 0x1000dc0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_va instead.") #define CLUTTER_Sinh_sha 0x1000dc1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_sha instead.") #define CLUTTER_Sinh_ssha 0x1000dc2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ssha instead.") #define CLUTTER_Sinh_sa 0x1000dc3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_sa instead.") #define CLUTTER_Sinh_ha 0x1000dc4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ha instead.") #define CLUTTER_Sinh_lla 0x1000dc5 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_lla instead.") #define CLUTTER_Sinh_fa 0x1000dc6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_fa instead.") #define CLUTTER_Sinh_al 0x1000dca CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_al instead.") #define CLUTTER_Sinh_aa2 0x1000dcf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_aa2 instead.") #define CLUTTER_Sinh_ae2 0x1000dd0 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ae2 instead.") #define CLUTTER_Sinh_aee2 0x1000dd1 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_aee2 instead.") #define CLUTTER_Sinh_i2 0x1000dd2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_i2 instead.") #define CLUTTER_Sinh_ii2 0x1000dd3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ii2 instead.") #define CLUTTER_Sinh_u2 0x1000dd4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_u2 instead.") #define CLUTTER_Sinh_uu2 0x1000dd6 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_uu2 instead.") #define CLUTTER_Sinh_ru2 0x1000dd8 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ru2 instead.") #define CLUTTER_Sinh_e2 0x1000dd9 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_e2 instead.") #define CLUTTER_Sinh_ee2 0x1000dda CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ee2 instead.") #define CLUTTER_Sinh_ai2 0x1000ddb CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ai2 instead.") #define CLUTTER_Sinh_o2 0x1000ddc CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_o2 instead.") #define CLUTTER_Sinh_oo2 0x1000ddd CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_oo2 instead.") #define CLUTTER_Sinh_au2 0x1000dde CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_au2 instead.") #define CLUTTER_Sinh_lu2 0x1000ddf CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_lu2 instead.") #define CLUTTER_Sinh_ruu2 0x1000df2 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_ruu2 instead.") #define CLUTTER_Sinh_luu2 0x1000df3 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_luu2 instead.") #define CLUTTER_Sinh_kunddaliya 0x1000df4 CLUTTER_DEPRECATED_MACRO_FOR("Deprecated key symbol. Use CLUTTER_KEY_Sinh_kunddaliya instead.") #define CLUTTER_ModeLock 0x1008ff01 #define CLUTTER_MonBrightnessUp 0x1008ff02 #define CLUTTER_MonBrightnessDown 0x1008ff03 #define CLUTTER_KbdLightOnOff 0x1008ff04 #define CLUTTER_KbdBrightnessUp 0x1008ff05 #define CLUTTER_KbdBrightnessDown 0x1008ff06 #define CLUTTER_Standby 0x1008ff10 #define CLUTTER_AudioLowerVolume 0x1008ff11 #define CLUTTER_AudioMute 0x1008ff12 #define CLUTTER_AudioRaiseVolume 0x1008ff13 #define CLUTTER_AudioPlay 0x1008ff14 #define CLUTTER_AudioStop 0x1008ff15 #define CLUTTER_AudioPrev 0x1008ff16 #define CLUTTER_AudioNext 0x1008ff17 #define CLUTTER_HomePage 0x1008ff18 #define CLUTTER_Mail 0x1008ff19 #define CLUTTER_Start 0x1008ff1a #define CLUTTER_Search 0x1008ff1b #define CLUTTER_AudioRecord 0x1008ff1c #define CLUTTER_Calculator 0x1008ff1d #define CLUTTER_Memo 0x1008ff1e #define CLUTTER_ToDoList 0x1008ff1f #define CLUTTER_Calendar 0x1008ff20 #define CLUTTER_PowerDown 0x1008ff21 #define CLUTTER_ContrastAdjust 0x1008ff22 #define CLUTTER_RockerUp 0x1008ff23 #define CLUTTER_RockerDown 0x1008ff24 #define CLUTTER_RockerEnter 0x1008ff25 #define CLUTTER_Back 0x1008ff26 #define CLUTTER_Forward 0x1008ff27 #define CLUTTER_Stop 0x1008ff28 #define CLUTTER_Refresh 0x1008ff29 #define CLUTTER_PowerOff 0x1008ff2a #define CLUTTER_WakeUp 0x1008ff2b #define CLUTTER_Eject 0x1008ff2c #define CLUTTER_ScreenSaver 0x1008ff2d #define CLUTTER_WWW 0x1008ff2e #define CLUTTER_Sleep 0x1008ff2f #define CLUTTER_Favorites 0x1008ff30 #define CLUTTER_AudioPause 0x1008ff31 #define CLUTTER_AudioMedia 0x1008ff32 #define CLUTTER_MyComputer 0x1008ff33 #define CLUTTER_VendorHome 0x1008ff34 #define CLUTTER_LightBulb 0x1008ff35 #define CLUTTER_Shop 0x1008ff36 #define CLUTTER_History 0x1008ff37 #define CLUTTER_OpenURL 0x1008ff38 #define CLUTTER_AddFavorite 0x1008ff39 #define CLUTTER_HotLinks 0x1008ff3a #define CLUTTER_BrightnessAdjust 0x1008ff3b #define CLUTTER_Finance 0x1008ff3c #define CLUTTER_Community 0x1008ff3d #define CLUTTER_AudioRewind 0x1008ff3e #define CLUTTER_BackForward 0x1008ff3f #define CLUTTER_Launch0 0x1008ff40 #define CLUTTER_Launch1 0x1008ff41 #define CLUTTER_Launch2 0x1008ff42 #define CLUTTER_Launch3 0x1008ff43 #define CLUTTER_Launch4 0x1008ff44 #define CLUTTER_Launch5 0x1008ff45 #define CLUTTER_Launch6 0x1008ff46 #define CLUTTER_Launch7 0x1008ff47 #define CLUTTER_Launch8 0x1008ff48 #define CLUTTER_Launch9 0x1008ff49 #define CLUTTER_LaunchA 0x1008ff4a #define CLUTTER_LaunchB 0x1008ff4b #define CLUTTER_LaunchC 0x1008ff4c #define CLUTTER_LaunchD 0x1008ff4d #define CLUTTER_LaunchE 0x1008ff4e #define CLUTTER_LaunchF 0x1008ff4f #define CLUTTER_ApplicationLeft 0x1008ff50 #define CLUTTER_ApplicationRight 0x1008ff51 #define CLUTTER_Book 0x1008ff52 #define CLUTTER_CD 0x1008ff53 #define CLUTTER_WindowClear 0x1008ff55 #define CLUTTER_Close 0x1008ff56 #define CLUTTER_Copy 0x1008ff57 #define CLUTTER_Cut 0x1008ff58 #define CLUTTER_Display 0x1008ff59 #define CLUTTER_DOS 0x1008ff5a #define CLUTTER_Documents 0x1008ff5b #define CLUTTER_Excel 0x1008ff5c #define CLUTTER_Explorer 0x1008ff5d #define CLUTTER_Game 0x1008ff5e #define CLUTTER_Go 0x1008ff5f #define CLUTTER_iTouch 0x1008ff60 #define CLUTTER_LogOff 0x1008ff61 #define CLUTTER_Market 0x1008ff62 #define CLUTTER_Meeting 0x1008ff63 #define CLUTTER_MenuKB 0x1008ff65 #define CLUTTER_MenuPB 0x1008ff66 #define CLUTTER_MySites 0x1008ff67 #define CLUTTER_New 0x1008ff68 #define CLUTTER_News 0x1008ff69 #define CLUTTER_OfficeHome 0x1008ff6a #define CLUTTER_Open 0x1008ff6b #define CLUTTER_Option 0x1008ff6c #define CLUTTER_Paste 0x1008ff6d #define CLUTTER_Phone 0x1008ff6e #define CLUTTER_Reply 0x1008ff72 #define CLUTTER_Reload 0x1008ff73 #define CLUTTER_RotateWindows 0x1008ff74 #define CLUTTER_RotationPB 0x1008ff75 #define CLUTTER_RotationKB 0x1008ff76 #define CLUTTER_Save 0x1008ff77 #define CLUTTER_ScrollUp 0x1008ff78 #define CLUTTER_ScrollDown 0x1008ff79 #define CLUTTER_ScrollClick 0x1008ff7a #define CLUTTER_Send 0x1008ff7b #define CLUTTER_Spell 0x1008ff7c #define CLUTTER_SplitScreen 0x1008ff7d #define CLUTTER_Support 0x1008ff7e #define CLUTTER_TaskPane 0x1008ff7f #define CLUTTER_Terminal 0x1008ff80 #define CLUTTER_Tools 0x1008ff81 #define CLUTTER_Travel 0x1008ff82 #define CLUTTER_UserPB 0x1008ff84 #define CLUTTER_User1KB 0x1008ff85 #define CLUTTER_User2KB 0x1008ff86 #define CLUTTER_Video 0x1008ff87 #define CLUTTER_WheelButton 0x1008ff88 #define CLUTTER_Word 0x1008ff89 #define CLUTTER_Xfer 0x1008ff8a #define CLUTTER_ZoomIn 0x1008ff8b #define CLUTTER_ZoomOut 0x1008ff8c #define CLUTTER_Away 0x1008ff8d #define CLUTTER_Messenger 0x1008ff8e #define CLUTTER_WebCam 0x1008ff8f #define CLUTTER_MailForward 0x1008ff90 #define CLUTTER_Pictures 0x1008ff91 #define CLUTTER_Music 0x1008ff92 #define CLUTTER_Battery 0x1008ff93 #define CLUTTER_Bluetooth 0x1008ff94 #define CLUTTER_WLAN 0x1008ff95 #define CLUTTER_UWB 0x1008ff96 #define CLUTTER_AudioForward 0x1008ff97 #define CLUTTER_AudioRepeat 0x1008ff98 #define CLUTTER_AudioRandomPlay 0x1008ff99 #define CLUTTER_Subtitle 0x1008ff9a #define CLUTTER_AudioCycleTrack 0x1008ff9b #define CLUTTER_CycleAngle 0x1008ff9c #define CLUTTER_FrameBack 0x1008ff9d #define CLUTTER_FrameForward 0x1008ff9e #define CLUTTER_Time 0x1008ff9f #define CLUTTER_SelectButton 0x1008ffa0 #define CLUTTER_View 0x1008ffa1 #define CLUTTER_TopMenu 0x1008ffa2 #define CLUTTER_Red 0x1008ffa3 #define CLUTTER_Green 0x1008ffa4 #define CLUTTER_Yellow 0x1008ffa5 #define CLUTTER_Blue 0x1008ffa6 #define CLUTTER_Suspend 0x1008ffa7 #define CLUTTER_Hibernate 0x1008ffa8 #define CLUTTER_TouchpadToggle 0x1008ffa9 #define CLUTTER_TouchpadOn 0x1008ffb0 #define CLUTTER_TouchpadOff 0x1008ffb1 #define CLUTTER_AudioMicMute 0x1008ffb2 #define CLUTTER_Switch_VT_1 0x1008fe01 #define CLUTTER_Switch_VT_2 0x1008fe02 #define CLUTTER_Switch_VT_3 0x1008fe03 #define CLUTTER_Switch_VT_4 0x1008fe04 #define CLUTTER_Switch_VT_5 0x1008fe05 #define CLUTTER_Switch_VT_6 0x1008fe06 #define CLUTTER_Switch_VT_7 0x1008fe07 #define CLUTTER_Switch_VT_8 0x1008fe08 #define CLUTTER_Switch_VT_9 0x1008fe09 #define CLUTTER_Switch_VT_10 0x1008fe0a #define CLUTTER_Switch_VT_11 0x1008fe0b #define CLUTTER_Switch_VT_12 0x1008fe0c #define CLUTTER_Ungrab 0x1008fe20 #define CLUTTER_ClearGrab 0x1008fe21 #define CLUTTER_Next_VMode 0x1008fe22 #define CLUTTER_Prev_VMode 0x1008fe23 #define CLUTTER_LogWindowTree 0x1008fe24 #define CLUTTER_LogGrabInfo 0x1008fe25 #endif /* CLUTTER_DISABLE_DEPRECATED */ #endif /* __CLUTTER_KEYSYMS_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-shader.c0000664000175000017500000006144714211404421023506 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Matthew Allum * Øyvind Kolås * Emmanuele Bassi * * Copyright (C) 2007, 2008 OpenedHand * 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, see . * * */ /** * SECTION:clutter-shader * @short_description: Programmable pipeline abstraction * * #ClutterShader is an object providing an abstraction over the * OpenGL programmable pipeline. By using #ClutterShaders is * possible to override the drawing pipeline by using small programs * also known as "shaders". * * #ClutterShader is available since Clutter 0.6. * * #ClutterShader is deprecated since Clutter 1.8; use #ClutterShaderEffect * in newly written code, instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #ifdef HAVE_UNISTD_H #include #endif #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include #include #include "clutter-shader.h" #include "clutter-debug.h" #include "clutter-private.h" /* global list of shaders */ static GList *clutter_shaders_list = NULL; struct _ClutterShaderPrivate { guint compiled : 1; /* Shader is bound to the GL context */ guint is_enabled : 1; guint vertex_is_glsl : 1; guint fragment_is_glsl : 1; gchar *vertex_source; /* GLSL source for vertex shader */ gchar *fragment_source; /* GLSL source for fragment shader */ CoglHandle program; CoglHandle vertex_shader; CoglHandle fragment_shader; }; enum { PROP_0, PROP_VERTEX_SOURCE, PROP_FRAGMENT_SOURCE, PROP_COMPILED, PROP_ENABLED, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE (ClutterShader, clutter_shader, G_TYPE_OBJECT) static inline void clutter_shader_release_internal (ClutterShader *shader) { ClutterShaderPrivate *priv = shader->priv; if (!priv->compiled) return; g_assert (priv->program != COGL_INVALID_HANDLE); if (priv->vertex_is_glsl && priv->vertex_shader != COGL_INVALID_HANDLE) cogl_handle_unref (priv->vertex_shader); if (priv->fragment_is_glsl && priv->fragment_shader != COGL_INVALID_HANDLE) cogl_handle_unref (priv->fragment_shader); if (priv->program != COGL_INVALID_HANDLE) cogl_handle_unref (priv->program); priv->vertex_shader = COGL_INVALID_HANDLE; priv->fragment_shader = COGL_INVALID_HANDLE; priv->program = COGL_INVALID_HANDLE; priv->compiled = FALSE; } static void clutter_shader_finalize (GObject *object) { ClutterShader *shader; ClutterShaderPrivate *priv; shader = CLUTTER_SHADER (object); priv = shader->priv; clutter_shaders_list = g_list_remove (clutter_shaders_list, object); free (priv->fragment_source); free (priv->vertex_source); G_OBJECT_CLASS (clutter_shader_parent_class)->finalize (object); } static void clutter_shader_dispose (GObject *object) { ClutterShader *shader = CLUTTER_SHADER (object); clutter_shader_release_internal (shader); G_OBJECT_CLASS (clutter_shader_parent_class)->finalize (object); } static void clutter_shader_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterShader *shader = CLUTTER_SHADER(object); switch (prop_id) { case PROP_VERTEX_SOURCE: clutter_shader_set_vertex_source (shader, g_value_get_string (value), -1); break; case PROP_FRAGMENT_SOURCE: clutter_shader_set_fragment_source (shader, g_value_get_string (value), -1); break; case PROP_ENABLED: clutter_shader_set_is_enabled (shader, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_shader_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterShader *shader; ClutterShaderPrivate *priv; shader = CLUTTER_SHADER(object); priv = shader->priv; switch (prop_id) { case PROP_VERTEX_SOURCE: g_value_set_string (value, priv->vertex_source); break; case PROP_FRAGMENT_SOURCE: g_value_set_string (value, priv->fragment_source); break; case PROP_COMPILED: g_value_set_boolean (value, priv->compiled); break; case PROP_ENABLED: g_value_set_boolean (value, priv->is_enabled); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * clutter_shader_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObjectClass *parent_class; GObject *object; parent_class = G_OBJECT_CLASS (clutter_shader_parent_class); object = parent_class->constructor (type, n_params, params); /* add this instance to the global list of shaders */ clutter_shaders_list = g_list_prepend (clutter_shaders_list, object); return object; } static void clutter_shader_class_init (ClutterShaderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec = NULL; object_class->finalize = clutter_shader_finalize; object_class->dispose = clutter_shader_dispose; object_class->set_property = clutter_shader_set_property; object_class->get_property = clutter_shader_get_property; object_class->constructor = clutter_shader_constructor; /** * ClutterShader:vertex-source: * * GLSL source code for the vertex shader part of the shader * program, if any * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ pspec = g_param_spec_string ("vertex-source", P_("Vertex Source"), P_("Source of vertex shader"), NULL, CLUTTER_PARAM_READWRITE); obj_props[PROP_VERTEX_SOURCE] = pspec; g_object_class_install_property (object_class, PROP_VERTEX_SOURCE, pspec); /** * ClutterShader:fragment-source: * * GLSL source code for the fragment shader part of the shader program. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ pspec = g_param_spec_string ("fragment-source", P_("Fragment Source"), P_("Source of fragment shader"), NULL, CLUTTER_PARAM_READWRITE); obj_props[PROP_FRAGMENT_SOURCE] = pspec; g_object_class_install_property (object_class, PROP_FRAGMENT_SOURCE, pspec); /** * ClutterShader:compiled: * * Whether the shader is compiled and linked, ready for use * in the GL context. * * Since: 0.8 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ pspec = g_param_spec_boolean ("compiled", P_("Compiled"), P_("Whether the shader is compiled and linked"), FALSE, CLUTTER_PARAM_READABLE); obj_props[PROP_COMPILED] = pspec; g_object_class_install_property (object_class, PROP_COMPILED, pspec); /** * ClutterShader:enabled: * * Whether the shader is currently used in the GL rendering pipeline. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ pspec = g_param_spec_boolean ("enabled", P_("Enabled"), P_("Whether the shader is enabled"), FALSE, CLUTTER_PARAM_READWRITE); obj_props[PROP_ENABLED] = pspec; g_object_class_install_property (object_class, PROP_ENABLED, pspec); } static void clutter_shader_init (ClutterShader *self) { ClutterShaderPrivate *priv; priv = self->priv = clutter_shader_get_instance_private (self); priv->compiled = FALSE; priv->vertex_source = NULL; priv->fragment_source = NULL; priv->program = COGL_INVALID_HANDLE; priv->vertex_shader = COGL_INVALID_HANDLE; priv->fragment_shader = COGL_INVALID_HANDLE; } /** * clutter_shader_new: * * Create a new #ClutterShader instance. * * Return value: a new #ClutterShader. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ ClutterShader * clutter_shader_new (void) { return g_object_new (CLUTTER_TYPE_SHADER, NULL); } static inline void clutter_shader_set_source (ClutterShader *shader, ClutterShaderType shader_type, const gchar *data, gssize length) { ClutterShaderPrivate *priv = shader->priv; gboolean is_glsl = FALSE; if (length < 0) length = strlen (data); g_object_freeze_notify (G_OBJECT (shader)); /* release shader if bound when changing the source, the shader will * automatically be rebound on the next use. */ if (clutter_shader_is_compiled (shader)) clutter_shader_release (shader); is_glsl = !g_str_has_prefix (data, "!!ARBfp"); CLUTTER_NOTE (SHADER, "setting %s shader (GLSL:%s, len:%" G_GSSIZE_FORMAT ")", shader_type == CLUTTER_VERTEX_SHADER ? "vertex" : "fragment", is_glsl ? "yes" : "no", length); switch (shader_type) { case CLUTTER_FRAGMENT_SHADER: free (priv->fragment_source); priv->fragment_source = g_strndup (data, length); priv->fragment_is_glsl = is_glsl; g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_FRAGMENT_SOURCE]); break; case CLUTTER_VERTEX_SHADER: free (priv->vertex_source); priv->vertex_source = g_strndup (data, length); priv->vertex_is_glsl = is_glsl; g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_VERTEX_SOURCE]); break; } g_object_thaw_notify (G_OBJECT (shader)); } /** * clutter_shader_set_fragment_source: * @shader: a #ClutterShader * @data: GLSL source code. * @length: length of source buffer (currently ignored) * * Sets the GLSL source code to be used by a #ClutterShader for the fragment * program. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ void clutter_shader_set_fragment_source (ClutterShader *shader, const gchar *data, gssize length) { g_return_if_fail (CLUTTER_IS_SHADER (shader)); g_return_if_fail (data != NULL); clutter_shader_set_source (shader, CLUTTER_FRAGMENT_SHADER, data, length); } /** * clutter_shader_set_vertex_source: * @shader: a #ClutterShader * @data: GLSL source code. * @length: length of source buffer (currently ignored) * * Sets the GLSL source code to be used by a #ClutterShader for the vertex * program. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ void clutter_shader_set_vertex_source (ClutterShader *shader, const gchar *data, gssize length) { g_return_if_fail (CLUTTER_IS_SHADER (shader)); g_return_if_fail (data != NULL); clutter_shader_set_source (shader, CLUTTER_VERTEX_SHADER, data, length); } static const gchar * clutter_shader_get_source (ClutterShader *shader, ClutterShaderType shader_type) { switch (shader_type) { case CLUTTER_FRAGMENT_SHADER: return shader->priv->fragment_source; case CLUTTER_VERTEX_SHADER: return shader->priv->vertex_source; } return NULL; } static CoglHandle clutter_shader_get_cogl_shader (ClutterShader *shader, ClutterShaderType shader_type) { switch (shader_type) { case CLUTTER_FRAGMENT_SHADER: return shader->priv->fragment_shader; case CLUTTER_VERTEX_SHADER: return shader->priv->vertex_shader; } return COGL_INVALID_HANDLE; } static gboolean clutter_shader_glsl_bind (ClutterShader *self, ClutterShaderType shader_type, GError **error) { ClutterShaderPrivate *priv = self->priv; CoglHandle shader = COGL_INVALID_HANDLE; switch (shader_type) { case CLUTTER_VERTEX_SHADER: shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX); cogl_shader_source (shader, priv->vertex_source); priv->vertex_shader = shader; break; case CLUTTER_FRAGMENT_SHADER: shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); cogl_shader_source (shader, priv->fragment_source); priv->fragment_shader = shader; break; } g_assert (shader != COGL_INVALID_HANDLE); cogl_shader_compile (shader); if (!cogl_shader_is_compiled (shader)) { gchar *log_buf; log_buf = cogl_shader_get_info_log (shader); /* translators: the first %s is the type of the shader, either * Vertex shader or Fragment shader; the second %s is the actual * error as reported by COGL */ g_set_error (error, CLUTTER_SHADER_ERROR, CLUTTER_SHADER_ERROR_COMPILE, _("%s compilation failed: %s"), shader_type == CLUTTER_VERTEX_SHADER ? _("Vertex shader") : _("Fragment shader"), log_buf); free (log_buf); return FALSE; } cogl_program_attach_shader (priv->program, shader); return TRUE; } static gboolean bind_glsl_shader (ClutterShader *self, GError **error) { ClutterShaderPrivate *priv = self->priv; GError *bind_error = NULL; gboolean res; priv->program = cogl_create_program (); if (priv->vertex_is_glsl && priv->vertex_source != COGL_INVALID_HANDLE) { res = clutter_shader_glsl_bind (self, CLUTTER_VERTEX_SHADER, &bind_error); if (!res) { g_propagate_error (error, bind_error); return FALSE; } } if (priv->fragment_is_glsl && priv->fragment_source != COGL_INVALID_HANDLE) { res = clutter_shader_glsl_bind (self, CLUTTER_FRAGMENT_SHADER, &bind_error); if (!res) { g_propagate_error (error, bind_error); return FALSE; } } cogl_program_link (priv->program); return TRUE; } /** * clutter_shader_compile: * @shader: a #ClutterShader * @error: return location for a #GError, or %NULL * * Compiles and links GLSL sources set for vertex and fragment shaders for * a #ClutterShader. If the compilation fails and a #GError return location is * provided the error will contain the errors from the compiler, if any. * * Return value: returns TRUE if the shader was succesfully compiled. * * Since: 0.8 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ gboolean clutter_shader_compile (ClutterShader *shader, GError **error) { ClutterShaderPrivate *priv; g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE); priv = shader->priv; if (priv->compiled) return priv->compiled; if ((priv->vertex_source != COGL_INVALID_HANDLE && !priv->vertex_is_glsl) || (priv->fragment_source != COGL_INVALID_HANDLE && !priv->fragment_is_glsl)) { /* XXX: Could remove this check, since we only advertise support for GLSL * shaders anyways. */ g_set_error (error, CLUTTER_SHADER_ERROR, CLUTTER_SHADER_ERROR_NO_ASM, "ASM shaders not supported"); priv->compiled = FALSE; return priv->compiled; } if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) { g_set_error (error, CLUTTER_SHADER_ERROR, CLUTTER_SHADER_ERROR_NO_GLSL, "GLSL shaders not supported"); priv->compiled = FALSE; return priv->compiled; } priv->compiled = bind_glsl_shader (shader, error); g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_COMPILED]); return priv->compiled; } /** * clutter_shader_release: * @shader: a #ClutterShader * * Frees up any GL context resources held by the shader. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ void clutter_shader_release (ClutterShader *shader) { g_return_if_fail (CLUTTER_IS_SHADER (shader)); clutter_shader_release_internal (shader); g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_COMPILED]); } /** * clutter_shader_is_compiled: * @shader: a #ClutterShader * * Checks whether @shader is is currently compiled, linked and bound * to the GL context. * * Return value: %TRUE if the shader is compiled, linked and ready for use. * * Since: 0.8 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ gboolean clutter_shader_is_compiled (ClutterShader *shader) { g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE); return shader->priv->compiled; } /** * clutter_shader_set_is_enabled: * @shader: a #ClutterShader * @enabled: The new state of the shader. * * Enables a shader. This function will attempt to compile and link * the shader, if it isn't already. * * When @enabled is %FALSE the default state of the GL pipeline will be * used instead. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ void clutter_shader_set_is_enabled (ClutterShader *shader, gboolean enabled) { ClutterShaderPrivate *priv; g_return_if_fail (CLUTTER_IS_SHADER (shader)); priv = shader->priv; if (priv->is_enabled != enabled) { GError *error = NULL; gboolean res; res = clutter_shader_compile (shader, &error); if (!res) { g_warning ("Unable to bind the shader: %s", error ? error->message : "unknown error"); if (error) g_error_free (error); return; } priv->is_enabled = enabled; if (priv->is_enabled) cogl_program_use (priv->program); else cogl_program_use (COGL_INVALID_HANDLE); g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_ENABLED]); } } /** * clutter_shader_get_is_enabled: * @shader: a #ClutterShader * * Checks whether @shader is enabled. * * Return value: %TRUE if the shader is enabled. * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ gboolean clutter_shader_get_is_enabled (ClutterShader *shader) { g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE); return shader->priv->is_enabled; } /** * clutter_shader_set_uniform: * @shader: a #ClutterShader. * @name: name of uniform in GLSL shader program to set. * @value: a #ClutterShaderFloat, #ClutterShaderInt or #ClutterShaderMatrix * #GValue. * * Sets a user configurable variable in the GLSL shader programs attached to * a #ClutterShader. * * Since: 1.0 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ void clutter_shader_set_uniform (ClutterShader *shader, const gchar *name, const GValue *value) { ClutterShaderPrivate *priv; int location = 0; gsize size; g_return_if_fail (CLUTTER_IS_SHADER (shader)); g_return_if_fail (name != NULL); g_return_if_fail (value != NULL); g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value) || CLUTTER_VALUE_HOLDS_SHADER_INT (value) || CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value) || G_VALUE_HOLDS_FLOAT (value) || G_VALUE_HOLDS_INT (value)); priv = shader->priv; g_return_if_fail (priv->program != COGL_INVALID_HANDLE); location = cogl_program_get_uniform_location (priv->program, name); if (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value)) { const float *floats; floats = clutter_value_get_shader_float (value, &size); cogl_program_set_uniform_float (priv->program, location, size, 1, floats); } else if (CLUTTER_VALUE_HOLDS_SHADER_INT (value)) { const int *ints; ints = clutter_value_get_shader_int (value, &size); cogl_program_set_uniform_int (priv->program, location, size, 1, ints); } else if (CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value)) { const float *matrix; matrix = clutter_value_get_shader_matrix (value, &size); cogl_program_set_uniform_matrix (priv->program, location, size, 1, FALSE, matrix); } else if (G_VALUE_HOLDS_FLOAT (value)) { float float_val = g_value_get_float (value); cogl_program_set_uniform_float (priv->program, location, 1, 1, &float_val); } else if (G_VALUE_HOLDS_INT (value)) { int int_val = g_value_get_int (value); cogl_program_set_uniform_int (priv->program, location, 1, 1, &int_val); } else g_assert_not_reached (); } /** * clutter_shader_get_fragment_source: * @shader: a #ClutterShader * * Query the current GLSL fragment source set on @shader. * * Return value: the source of the fragment shader for this * ClutterShader object or %NULL. The returned string is owned by the * shader object and should never be modified or freed * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ const gchar * clutter_shader_get_fragment_source (ClutterShader *shader) { g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL); return clutter_shader_get_source (shader, CLUTTER_FRAGMENT_SHADER); } /** * clutter_shader_get_vertex_source: * @shader: a #ClutterShader * * Query the current GLSL vertex source set on @shader. * * Return value: the source of the vertex shader for this * ClutterShader object or %NULL. The returned string is owned by the * shader object and should never be modified or freed * * Since: 0.6 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ const gchar * clutter_shader_get_vertex_source (ClutterShader *shader) { g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL); return clutter_shader_get_source (shader, CLUTTER_VERTEX_SHADER); } /** * clutter_shader_get_cogl_program: * @shader: a #ClutterShader * * Retrieves the underlying #CoglHandle for the shader program. * * Return value: (transfer none): A #CoglHandle for the shader program, * or %NULL. The handle is owned by the #ClutterShader and it should * not be unreferenced * * Since: 1.0 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ CoglHandle clutter_shader_get_cogl_program (ClutterShader *shader) { g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL); return shader->priv->program; } /** * clutter_shader_get_cogl_fragment_shader: * @shader: a #ClutterShader * * Retrieves the underlying #CoglHandle for the fragment shader. * * Return value: (transfer none): A #CoglHandle for the fragment * shader, or %NULL. The handle is owned by the #ClutterShader * and it should not be unreferenced * * Since: 1.0 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ CoglHandle clutter_shader_get_cogl_fragment_shader (ClutterShader *shader) { g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL); return clutter_shader_get_cogl_shader (shader, CLUTTER_FRAGMENT_SHADER); } /** * clutter_shader_get_cogl_vertex_shader: * @shader: a #ClutterShader * * Retrieves the underlying #CoglHandle for the vertex shader. * * Return value: (transfer none): A #CoglHandle for the vertex * shader, or %NULL. The handle is owned by the #ClutterShader * and it should not be unreferenced * * Since: 1.0 * * Deprecated: 1.8: Use #ClutterShaderEffect instead. */ CoglHandle clutter_shader_get_cogl_vertex_shader (ClutterShader *shader) { g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL); return clutter_shader_get_cogl_shader (shader, CLUTTER_VERTEX_SHADER); } GQuark clutter_shader_error_quark (void) { return g_quark_from_static_string ("clutter-shader-error"); } muffin-5.2.1/clutter/clutter/deprecated/clutter-cairo-texture.c0000664000175000017500000010406014211404421025020 0ustar jpeisachjpeisach/* * Clutter * * An OpenGL based 'interactive canvas' library. * * Authored By: Emmanuele Bassi * Matthew Allum * Chris Lord * Iain Holmes * Neil Roberts * * Copyright (C) 2008, 2009, 2010, 2011 Intel Corporation. * * 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, see . */ /** * SECTION:clutter-cairo-texture * @short_description: Texture with Cairo integration * * #ClutterCairoTexture is a #ClutterTexture that displays the contents * of a Cairo context. The #ClutterCairoTexture actor will create a * Cairo image surface which will then be uploaded to a GL texture when * needed. * * Since #ClutterCairoTexture uses a Cairo image surface * internally all the drawing operations will be performed in * software and not using hardware acceleration. This can lead to * performance degradation if the contents of the texture change * frequently. * * In order to use a #ClutterCairoTexture you should connect to the * #ClutterCairoTexture::draw signal; the signal is emitted each time * the #ClutterCairoTexture has been told to invalidate its contents, * by using clutter_cairo_texture_invalidate_rectangle() or its * sister function, clutter_cairo_texture_invalidate(). * * Each callback to the #ClutterCairoTexture::draw signal will receive * a #cairo_t context which can be used for drawing; the Cairo context * is owned by the #ClutterCairoTexture and should not be destroyed * explicitly. * * #ClutterCairoTexture is available since Clutter 1.0. * * #ClutterCairoTexture is deprecated since Clutter 1.12. You should * use #ClutterCanvas instead. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-texture.h" #include "deprecated/clutter-cairo-texture.h" #include "clutter-cairo-texture.h" #include "clutter-actor-private.h" #include "clutter-cairo.h" #include "clutter-color.h" #include "clutter-debug.h" #include "clutter-marshal.h" #include "clutter-private.h" struct _ClutterCairoTexturePrivate { cairo_surface_t *cr_surface; guint surface_width; guint surface_height; cairo_t *cr_context; guint auto_resize : 1; }; enum { PROP_0, PROP_SURFACE_WIDTH, PROP_SURFACE_HEIGHT, PROP_AUTO_RESIZE, PROP_LAST }; enum { CREATE_SURFACE, DRAW, LAST_SIGNAL }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; static guint cairo_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterCairoTexture, clutter_cairo_texture, CLUTTER_TYPE_TEXTURE) #ifdef CLUTTER_ENABLE_DEBUG #define clutter_warn_if_paint_fail(obj) G_STMT_START { \ if (CLUTTER_ACTOR_IN_PAINT (obj)) { \ g_warning ("%s should not be called during the paint sequence " \ "of a ClutterCairoTexture as it will likely cause " \ "performance issues.", G_STRFUNC); \ } } G_STMT_END #else #define clutter_warn_if_paint_fail(obj) /* void */ #endif /* CLUTTER_ENABLE_DEBUG */ typedef struct { ClutterCairoTexture *texture; cairo_rectangle_int_t rect; guint is_clipped : 1; } DrawContext; static const cairo_user_data_key_t clutter_cairo_texture_context_key; static DrawContext * draw_context_create (ClutterCairoTexture *texture) { DrawContext *context = g_slice_new0 (DrawContext); context->texture = g_object_ref (texture); return context; } static void draw_context_destroy (gpointer data) { if (G_LIKELY (data != NULL)) { DrawContext *context = data; g_object_unref (context->texture); g_slice_free (DrawContext, data); } } static void clutter_cairo_texture_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterCairoTexturePrivate *priv; priv = CLUTTER_CAIRO_TEXTURE (object)->priv; switch (prop_id) { case PROP_SURFACE_WIDTH: /* we perform the resize on notify to coalesce separate * surface-width/surface-height property set */ priv->surface_width = g_value_get_uint (value); break; case PROP_SURFACE_HEIGHT: priv->surface_height = g_value_get_uint (value); break; case PROP_AUTO_RESIZE: clutter_cairo_texture_set_auto_resize (CLUTTER_CAIRO_TEXTURE (object), g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_cairo_texture_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterCairoTexturePrivate *priv; priv = CLUTTER_CAIRO_TEXTURE (object)->priv; switch (prop_id) { case PROP_SURFACE_WIDTH: g_value_set_uint (value, priv->surface_width); break; case PROP_SURFACE_HEIGHT: g_value_set_uint (value, priv->surface_height); break; case PROP_AUTO_RESIZE: g_value_set_boolean (value, priv->auto_resize); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_cairo_texture_finalize (GObject *object) { ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (object)->priv; if (priv->cr_surface != NULL) { cairo_surface_t *surface = priv->cr_surface; priv->cr_surface = NULL; cairo_surface_finish (surface); cairo_surface_destroy (surface); } G_OBJECT_CLASS (clutter_cairo_texture_parent_class)->finalize (object); } static cairo_surface_t * get_surface (ClutterCairoTexture *self) { ClutterCairoTexturePrivate *priv = self->priv; if (priv->cr_surface == NULL) { g_signal_emit (self, cairo_signals[CREATE_SURFACE], 0, priv->surface_width, priv->surface_height, &priv->cr_surface); } return priv->cr_surface; } static void clutter_cairo_texture_context_destroy (void *data) { DrawContext *ctxt = data; ClutterCairoTexture *cairo = ctxt->texture; ClutterCairoTexturePrivate *priv = cairo->priv; guint8 *cairo_data; gint cairo_width, cairo_height, cairo_stride; gint surface_width, surface_height; CoglHandle cogl_texture; if (priv->cr_surface == NULL) { /* the surface went away before we could use it */ draw_context_destroy (ctxt); return; } /* for any other surface type, we presume that there exists a native * communication between Cairo and GL that is triggered by cairo_destroy(). * * for instance, cairo-drm will flush the outstanding modifications to the * surface upon context destruction and so the texture is automatically * updated. */ if (cairo_surface_get_type (priv->cr_surface) != CAIRO_SURFACE_TYPE_IMAGE) goto out; surface_width = cairo_image_surface_get_width (priv->cr_surface); surface_height = cairo_image_surface_get_height (priv->cr_surface); cairo_width = MIN (ctxt->rect.width, surface_width); cairo_height = MIN (ctxt->rect.height, surface_height); cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (cairo)); if (cairo_width == 0 || cairo_height == 0 || cogl_texture == COGL_INVALID_HANDLE) { draw_context_destroy (ctxt); return; } cairo_stride = cairo_image_surface_get_stride (priv->cr_surface); cairo_data = cairo_image_surface_get_data (priv->cr_surface); cairo_data += cairo_stride * ctxt->rect.y; cairo_data += 4 * ctxt->rect.x; cogl_texture_set_region (cogl_texture, 0, 0, ctxt->rect.x, ctxt->rect.y, cairo_width, cairo_height, cairo_width, cairo_height, CLUTTER_CAIRO_FORMAT_ARGB32, cairo_stride, cairo_data); out: draw_context_destroy (ctxt); clutter_actor_queue_redraw (CLUTTER_ACTOR (cairo)); } static inline void clutter_cairo_texture_emit_draw (ClutterCairoTexture *self, DrawContext *ctxt) { gboolean result; cairo_t *cr; /* 0x0 surfaces don't need a ::draw */ if (self->priv->surface_width == 0 || self->priv->surface_height == 0) return; /* if the size is !0 then we must have a surface */ g_assert (self->priv->cr_surface != NULL); cr = cairo_create (self->priv->cr_surface); if (ctxt->is_clipped) { cairo_rectangle (cr, ctxt->rect.x, ctxt->rect.y, ctxt->rect.width, ctxt->rect.height); cairo_clip (cr); } /* store the cairo_t as a guard */ self->priv->cr_context = cr; g_signal_emit (self, cairo_signals[DRAW], 0, cr, &result); self->priv->cr_context = NULL; clutter_cairo_texture_context_destroy (ctxt); cairo_destroy (cr); } static inline void clutter_cairo_texture_surface_resize_internal (ClutterCairoTexture *cairo) { ClutterCairoTexturePrivate *priv = cairo->priv; if (priv->cr_surface != NULL) { cairo_surface_t *surface = priv->cr_surface; /* if the surface is an image one, and the size is already the * same, then we don't need to do anything */ if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE) { gint surface_width = cairo_image_surface_get_width (surface); gint surface_height = cairo_image_surface_get_height (surface); if (priv->surface_width == surface_width && priv->surface_height == surface_height) return; } cairo_surface_finish (surface); cairo_surface_destroy (surface); priv->cr_surface = NULL; } if (priv->surface_width == 0 || priv->surface_height == 0) return; g_signal_emit (cairo, cairo_signals[CREATE_SURFACE], 0, priv->surface_width, priv->surface_height, &priv->cr_surface); } static void clutter_cairo_texture_notify (GObject *object, GParamSpec *pspec) { /* When the surface width or height changes then resize the cairo surface. This is done here instead of directly in set_property so that if both the width and height properties are set using a single call to g_object_set then the surface will only be resized once because the notifications will be frozen in between */ if (obj_props[PROP_SURFACE_WIDTH]->name == pspec->name || obj_props[PROP_SURFACE_HEIGHT]->name == pspec->name) { ClutterCairoTexture *cairo = CLUTTER_CAIRO_TEXTURE (object); clutter_cairo_texture_surface_resize_internal (cairo); } if (G_OBJECT_CLASS (clutter_cairo_texture_parent_class)->notify) G_OBJECT_CLASS (clutter_cairo_texture_parent_class)->notify (object, pspec); } static void clutter_cairo_texture_get_preferred_width (ClutterActor *actor, gfloat for_height, gfloat *min_width, gfloat *natural_width) { ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (actor)->priv; if (min_width) *min_width = 0; if (natural_width) *natural_width = (gfloat) priv->surface_width; } static void clutter_cairo_texture_get_preferred_height (ClutterActor *actor, gfloat for_width, gfloat *min_height, gfloat *natural_height) { ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (actor)->priv; if (min_height) *min_height = 0; if (natural_height) *natural_height = (gfloat) priv->surface_height; } static void clutter_cairo_texture_allocate (ClutterActor *self, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterCairoTexturePrivate *priv = CLUTTER_CAIRO_TEXTURE (self)->priv; ClutterActorClass *parent_class; parent_class = CLUTTER_ACTOR_CLASS (clutter_cairo_texture_parent_class); parent_class->allocate (self, allocation, flags); if (priv->auto_resize) { ClutterCairoTexture *texture = CLUTTER_CAIRO_TEXTURE (self); gfloat width, height; clutter_actor_box_get_size (allocation, &width, &height); priv->surface_width = ceilf (width); priv->surface_height = ceilf (height); clutter_cairo_texture_surface_resize_internal (texture); clutter_cairo_texture_invalidate (texture); } } static gboolean clutter_cairo_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { return _clutter_actor_set_default_paint_volume (self, CLUTTER_TYPE_CAIRO_TEXTURE, volume); } static cairo_surface_t * clutter_cairo_texture_create_surface (ClutterCairoTexture *self, guint width, guint height) { cairo_surface_t *surface; guint cairo_stride; guint8 *cairo_data; CoglHandle cogl_texture; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cairo_stride = cairo_image_surface_get_stride (surface); cairo_data = cairo_image_surface_get_data (surface); /* create a backing Cogl texture */ cogl_texture = cogl_texture_new_from_data (width, height, COGL_TEXTURE_NONE, CLUTTER_CAIRO_FORMAT_ARGB32, COGL_PIXEL_FORMAT_ANY, cairo_stride, cairo_data); clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (self), cogl_texture); cogl_handle_unref (cogl_texture); return surface; } static gboolean create_surface_accum (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer data) { g_value_copy (handler_return, return_accu); /* stop on the first non-NULL return value */ return g_value_get_boxed (handler_return) == NULL; } static void clutter_cairo_texture_draw_marshaller (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data) { cairo_t *cr = g_value_get_boxed (¶m_values[1]); cairo_save (cr); _clutter_marshal_BOOLEAN__BOXED (closure, return_value, n_param_values, param_values, invocation_hint, marshal_data); cairo_restore (cr); } static void clutter_cairo_texture_class_init (ClutterCairoTextureClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); gobject_class->finalize = clutter_cairo_texture_finalize; gobject_class->set_property = clutter_cairo_texture_set_property; gobject_class->get_property = clutter_cairo_texture_get_property; gobject_class->notify = clutter_cairo_texture_notify; actor_class->get_paint_volume = clutter_cairo_texture_get_paint_volume; actor_class->get_preferred_width = clutter_cairo_texture_get_preferred_width; actor_class->get_preferred_height = clutter_cairo_texture_get_preferred_height; actor_class->allocate = clutter_cairo_texture_allocate; klass->create_surface = clutter_cairo_texture_create_surface; /** * ClutterCairoTexture:surface-width: * * The width of the Cairo surface used by the #ClutterCairoTexture * actor, in pixels. * * Since: 1.0 * * Deprecated: 1.12 */ obj_props[PROP_SURFACE_WIDTH] = g_param_spec_uint ("surface-width", P_("Surface Width"), P_("The width of the Cairo surface"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); /** * ClutterCairoTexture:surface-height: * * The height of the Cairo surface used by the #ClutterCairoTexture * actor, in pixels. * * Since: 1.0 * * Deprecated: 1.12 */ obj_props[PROP_SURFACE_HEIGHT] = g_param_spec_uint ("surface-height", P_("Surface Height"), P_("The height of the Cairo surface"), 0, G_MAXUINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); /** * ClutterCairoTexture:auto-resize: * * Controls whether the #ClutterCairoTexture should automatically * resize the Cairo surface whenever the actor's allocation changes. * If :auto-resize is set to %TRUE the surface contents will also * be invalidated automatically. * * Since: 1.8 * * Deprecated: 1.12 */ obj_props[PROP_AUTO_RESIZE] = g_param_spec_boolean ("auto-resize", P_("Auto Resize"), P_("Whether the surface should match the allocation"), FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); /** * ClutterCairoTexture::create-surface: * @texture: the #ClutterCairoTexture that emitted the signal * @width: the width of the surface to create * @height: the height of the surface to create * * The ::create-surface signal is emitted when a #ClutterCairoTexture * news its surface (re)created, which happens either when the Cairo * context is created with clutter_cairo_texture_create() or * clutter_cairo_texture_create_region(), or when the surface is resized * through clutter_cairo_texture_set_surface_size(). * * The first signal handler that returns a non-%NULL, valid surface will * stop any further signal emission, and the returned surface will be * the one used. * * Return value: the newly created #cairo_surface_t for the texture * * Since: 1.6 * * Deprecated: 1.12 */ cairo_signals[CREATE_SURFACE] = g_signal_new (I_("create-surface"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET (ClutterCairoTextureClass, create_surface), create_surface_accum, NULL, _clutter_marshal_BOXED__UINT_UINT, CAIRO_GOBJECT_TYPE_SURFACE, 2, G_TYPE_UINT, G_TYPE_UINT); /** * ClutterCairoTexture::draw: * @texture: the #ClutterCairoTexture that emitted the signal * @cr: the Cairo context to use to draw * * The ::draw signal is emitted each time a #ClutterCairoTexture has * been invalidated. * * The passed Cairo context passed will be clipped to the invalidated * area. * * It is safe to connect multiple callbacks to this signals; the state * of the Cairo context passed to each callback is automatically saved * and restored, so it's not necessary to call cairo_save() and * cairo_restore(). * * Return value: %TRUE if the signal emission should stop, and %FALSE * to continue * * Since: 1.8 * * Deprecated: 1.12 */ cairo_signals[DRAW] = g_signal_new (I_("draw"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE, G_STRUCT_OFFSET (ClutterCairoTextureClass, draw), _clutter_boolean_handled_accumulator, NULL, clutter_cairo_texture_draw_marshaller, G_TYPE_BOOLEAN, 1, CAIRO_GOBJECT_TYPE_CONTEXT); } static void clutter_cairo_texture_init (ClutterCairoTexture *self) { self->priv = clutter_cairo_texture_get_instance_private (self); /* FIXME - we are hardcoding the format; it would be good to have * a :surface-format construct-only property for creating * textures with a different format and have the cairo surface * match that format * * priv->format = CAIRO_FORMAT_ARGB32; */ /* the Cairo surface is responsible for driving the size of * the texture; if we let sync_size to its default of TRUE, * the Texture will try to queue a relayout every time we * change the size of the Cairo surface - which is not what * we want */ clutter_texture_set_sync_size (CLUTTER_TEXTURE (self), FALSE); } /** * clutter_cairo_texture_new: * @width: the width of the surface * @height: the height of the surface * * Creates a new #ClutterCairoTexture actor, with a surface of @width by * @height pixels. * * Return value: the newly created #ClutterCairoTexture actor * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterCanvas instead */ ClutterActor* clutter_cairo_texture_new (guint width, guint height) { return g_object_new (CLUTTER_TYPE_CAIRO_TEXTURE, "surface-width", width, "surface-height", height, NULL); } static void intersect_rectangles (cairo_rectangle_int_t *a, cairo_rectangle_int_t *b, cairo_rectangle_int_t *inter) { gint dest_x, dest_y; gint dest_width, dest_height; dest_x = MAX (a->x, b->x); dest_y = MAX (a->y, b->y); dest_width = MIN (a->x + a->width, b->x + b->width) - dest_x; dest_height = MIN (a->y + a->height, b->y + b->height) - dest_y; if (dest_width > 0 && dest_height > 0) { inter->x = dest_x; inter->y = dest_y; inter->width = dest_width; inter->height = dest_height; } else { inter->x = 0; inter->y = 0; inter->width = 0; inter->height = 0; } } static cairo_t * clutter_cairo_texture_create_region_internal (ClutterCairoTexture *self, gint x_offset, gint y_offset, gint width, gint height) { ClutterCairoTexturePrivate *priv = self->priv; cairo_rectangle_int_t region, area, inter; cairo_surface_t *surface; DrawContext *ctxt; cairo_t *cr; if (width < 0) width = priv->surface_width; if (height < 0) height = priv->surface_height; if (width == 0 || height == 0) { g_warning ("Unable to create a context for an image surface of " "width %d and height %d. Set the surface size to be " "at least 1 pixel by 1 pixel.", width, height); return NULL; } surface = get_surface (self); ctxt = draw_context_create (self); region.x = x_offset; region.y = y_offset; region.width = width; region.height = height; area.x = 0; area.y = 0; area.width = priv->surface_width; area.height = priv->surface_height; /* Limit the region to the visible rectangle */ intersect_rectangles (&area, ®ion, &inter); ctxt->rect = inter; cr = cairo_create (surface); cairo_set_user_data (cr, &clutter_cairo_texture_context_key, ctxt, clutter_cairo_texture_context_destroy); return cr; } /** * clutter_cairo_texture_create_region: * @self: a #ClutterCairoTexture * @x_offset: offset of the region on the X axis * @y_offset: offset of the region on the Y axis * @width: width of the region, or -1 for the full surface width * @height: height of the region, or -1 for the full surface height * * Creates a new Cairo context that will updat the region defined * by @x_offset, @y_offset, @width and @height. * * Do not call this function within the paint virtual * function or from a callback to the #ClutterActor::paint * signal. * * Return value: a newly created Cairo context. Use cairo_destroy() * to upload the contents of the context when done drawing * * Since: 1.0 * * Deprecated: 1.8: Use the #ClutterCairoTexture::draw signal and * clutter_cairo_texture_invalidate_rectangle() to obtain a * clipped Cairo context for 2D drawing. */ cairo_t * clutter_cairo_texture_create_region (ClutterCairoTexture *self, gint x_offset, gint y_offset, gint width, gint height) { g_return_val_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self), NULL); clutter_warn_if_paint_fail (self); return clutter_cairo_texture_create_region_internal (self, x_offset, y_offset, width, height); } /** * clutter_cairo_texture_invalidate_rectangle: * @self: a #ClutterCairoTexture * @rect: (allow-none): a rectangle with the area to invalida, * or %NULL to perform an unbounded invalidation * * Invalidates a rectangular region of a #ClutterCairoTexture. * * The invalidation will cause the #ClutterCairoTexture::draw signal * to be emitted. * * See also: clutter_cairo_texture_invalidate() * * Since: 1.8 * Deprecated: 1.12: Use #ClutterCanvas instead */ void clutter_cairo_texture_invalidate_rectangle (ClutterCairoTexture *self, cairo_rectangle_int_t *rect) { DrawContext *ctxt = NULL; g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self)); if (self->priv->cr_context != NULL) { g_warning ("It is not possible to invalidate a Cairo texture" "while drawing into it."); return; } ctxt = draw_context_create (self); if (rect != NULL) { cairo_rectangle_int_t area, inter; area.x = 0; area.y = 0; area.width = self->priv->surface_width; area.height = self->priv->surface_height; /* Limit the region to the visible rectangle */ intersect_rectangles (&area, rect, &inter); ctxt->is_clipped = TRUE; ctxt->rect = inter; } else { ctxt->is_clipped = FALSE; ctxt->rect.x = ctxt->rect.y = 0; ctxt->rect.width = self->priv->surface_width; ctxt->rect.height = self->priv->surface_height; } /* XXX - it might be good to move the emission inside the paint cycle * using a repaint function, to avoid blocking inside this function */ clutter_cairo_texture_emit_draw (self, ctxt); } /** * clutter_cairo_texture_invalidate: * @self: a #ClutterCairoTexture * * Invalidates the whole surface of a #ClutterCairoTexture. * * This function will cause the #ClutterCairoTexture::draw signal * to be emitted. * * See also: clutter_cairo_texture_invalidate_rectangle() * * Since: 1.8 * Deprecated: 1.12: Use #ClutterCanvas instead */ void clutter_cairo_texture_invalidate (ClutterCairoTexture *self) { g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self)); clutter_cairo_texture_invalidate_rectangle (self, NULL); } /** * clutter_cairo_texture_create: * @self: a #ClutterCairoTexture * * Creates a new Cairo context for the @cairo texture. It is * similar to using clutter_cairo_texture_create_region() with @x_offset * and @y_offset of 0, @width equal to the @cairo texture surface width * and @height equal to the @cairo texture surface height. * * Do not call this function within the paint virtual * function or from a callback to the #ClutterActor::paint * signal. * * Return value: a newly created Cairo context. Use cairo_destroy() * to upload the contents of the context when done drawing * * Since: 1.0 * * Deprecated: 1.8: Use the #ClutterCairoTexture::draw signal and * the clutter_cairo_texture_invalidate() function to obtain a * Cairo context for 2D drawing. */ cairo_t * clutter_cairo_texture_create (ClutterCairoTexture *self) { g_return_val_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self), NULL); clutter_warn_if_paint_fail (self); return clutter_cairo_texture_create_region_internal (self, 0, 0, -1, -1); } /** * clutter_cairo_texture_set_surface_size: * @self: a #ClutterCairoTexture * @width: the new width of the surface * @height: the new height of the surface * * Resizes the Cairo surface used by @self to @width and @height. * * This function will not invalidate the contents of the Cairo * texture: you will have to explicitly call either * clutter_cairo_texture_invalidate_rectangle() or * clutter_cairo_texture_invalidate(). * * Since: 1.0 * Deprecated: 1.12: Use #ClutterCanvas instead */ void clutter_cairo_texture_set_surface_size (ClutterCairoTexture *self, guint width, guint height) { ClutterCairoTexturePrivate *priv; g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self)); priv = self->priv; if (width == priv->surface_width && height == priv->surface_height) return; g_object_freeze_notify (G_OBJECT (self)); if (priv->surface_width != width) { priv->surface_width = width; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SURFACE_WIDTH]); } if (priv->surface_height != height) { priv->surface_height = height; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SURFACE_HEIGHT]); } clutter_cairo_texture_surface_resize_internal (self); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_cairo_texture_get_surface_size: * @self: a #ClutterCairoTexture * @width: (out): return location for the surface width, or %NULL * @height: (out): return location for the surface height, or %NULL * * Retrieves the surface width and height for @self. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterCanvas instead */ void clutter_cairo_texture_get_surface_size (ClutterCairoTexture *self, guint *width, guint *height) { g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self)); if (width) *width = self->priv->surface_width; if (height) *height = self->priv->surface_height; } /** * clutter_cairo_texture_clear: * @self: a #ClutterCairoTexture * * Clears @self's internal drawing surface, so that the next upload * will replace the previous contents of the #ClutterCairoTexture * rather than adding to it. * * Calling this function from within a #ClutterCairoTexture::draw * signal handler will clear the invalidated area. * * Since: 1.0 * Deprecated: 1.12: Use #ClutterCanvas instead */ void clutter_cairo_texture_clear (ClutterCairoTexture *self) { ClutterCairoTexturePrivate *priv; cairo_t *cr; g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self)); priv = self->priv; /* if we got called outside of a ::draw signal handler * then we clear the whole surface by creating a temporary * cairo_t; otherwise, we clear the current cairo_t, which * will take into account the clip region. */ if (priv->cr_context == NULL) { cairo_surface_t *surface; surface = get_surface (self); cr = cairo_create (surface); } else cr = priv->cr_context; cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); if (priv->cr_context == NULL) cairo_destroy (cr); } /** * clutter_cairo_texture_set_auto_resize: * @self: a #ClutterCairoTexture * @value: %TRUE if the #ClutterCairoTexture should bind the surface * size to the allocation * * Sets whether the #ClutterCairoTexture should ensure that the * backing Cairo surface used matches the allocation assigned to * the actor. If the allocation changes, the contents of the * #ClutterCairoTexture will also be invalidated automatically. * * Since: 1.8 * Deprecated: 1.12: Use #ClutterCanvas instead */ void clutter_cairo_texture_set_auto_resize (ClutterCairoTexture *self, gboolean value) { ClutterCairoTexturePrivate *priv; g_return_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self)); value = !!value; priv = self->priv; if (priv->auto_resize == value) return; priv->auto_resize = value; clutter_actor_queue_relayout (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_AUTO_RESIZE]); } /** * clutter_cairo_texture_get_auto_resize: * @self: a #ClutterCairoTexture * * Retrieves the value set using clutter_cairo_texture_set_auto_resize(). * * Return value: %TRUE if the #ClutterCairoTexture should track the * allocation, and %FALSE otherwise * * Since: 1.8 * Deprecated: 1.12: Use #ClutterCanvas instead */ gboolean clutter_cairo_texture_get_auto_resize (ClutterCairoTexture *self) { g_return_val_if_fail (CLUTTER_IS_CAIRO_TEXTURE (self), FALSE); return self->priv->auto_resize; } muffin-5.2.1/clutter/clutter/deprecated/clutter-timeline.h0000664000175000017500000000306614211404421024044 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 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, see . */ #ifndef __CLUTTER_TIMELINE_PRIVATE_H__ #define __CLUTTER_TIMELINE_PRIVATE_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_timeline_new) ClutterTimeline * clutter_timeline_clone (ClutterTimeline *timeline); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_timeline_set_repeat_count) void clutter_timeline_set_loop (ClutterTimeline *timeline, gboolean loop); CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_timeline_get_repeat_count) gboolean clutter_timeline_get_loop (ClutterTimeline *timeline); G_END_DECLS #endif /* __CLUTTER_TIMELINE_PRIVATE_H__ */ muffin-5.2.1/clutter/clutter/deprecated/clutter-input-device.h0000664000175000017500000000270414211404421024630 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see . * * Author: Emmanuele Bassi */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_INPUT_DEVICE_DEPRECATED_H__ #define __CLUTTER_INPUT_DEVICE_DEPRECATED_H__ #include G_BEGIN_DECLS CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_input_device_get_coords) void clutter_input_device_get_device_coords (ClutterInputDevice *device, gint *x, gint *y); G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/clutter-paint-volume.c0000664000175000017500000010256114211404421022551 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see * . * * Authors: * Robert Bragg * Emmanuele Bassi */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #include "clutter-actor-private.h" #include "clutter-paint-volume-private.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-actor-box-private.h" G_DEFINE_BOXED_TYPE (ClutterPaintVolume, clutter_paint_volume, clutter_paint_volume_copy, clutter_paint_volume_free); /* * _clutter_paint_volume_new: * @actor: a #ClutterActor * * Creates a new #ClutterPaintVolume for the given @actor. * * Return value: the newly allocated #ClutterPaintVolume. Use * clutter_paint_volume_free() to free the resources it uses * * Since: 1.6 */ ClutterPaintVolume * _clutter_paint_volume_new (ClutterActor *actor) { ClutterPaintVolume *pv; g_return_val_if_fail (actor != NULL, NULL); pv = g_slice_new (ClutterPaintVolume); pv->actor = actor; memset (pv->vertices, 0, 8 * sizeof (ClutterVertex)); pv->is_static = FALSE; pv->is_empty = TRUE; pv->is_axis_aligned = TRUE; pv->is_complete = TRUE; pv->is_2d = TRUE; return pv; } /* Since paint volumes are used so heavily in a typical paint * traversal of a Clutter scene graph and since paint volumes often * have a very short life cycle that maps well to stack allocation we * allow initializing a static ClutterPaintVolume variable to avoid * hammering the slice allocator. * * We were seeing slice allocation take about 1% cumulative CPU time * for some very simple clutter tests which although it isn't a *lot* * this is an easy way to basically drop that to 0%. * * The PaintVolume will be internally marked as static and * clutter_paint_volume_free should still be used to "free" static * volumes. This allows us to potentially store dynamically allocated * data inside paint volumes in the future since we would be able to * free it during _paint_volume_free(). */ void _clutter_paint_volume_init_static (ClutterPaintVolume *pv, ClutterActor *actor) { pv->actor = actor; memset (pv->vertices, 0, 8 * sizeof (ClutterVertex)); pv->is_static = TRUE; pv->is_empty = TRUE; pv->is_axis_aligned = TRUE; pv->is_complete = TRUE; pv->is_2d = TRUE; } void _clutter_paint_volume_copy_static (const ClutterPaintVolume *src_pv, ClutterPaintVolume *dst_pv) { g_return_if_fail (src_pv != NULL && dst_pv != NULL); memcpy (dst_pv, src_pv, sizeof (ClutterPaintVolume)); dst_pv->is_static = TRUE; } /** * clutter_paint_volume_copy: * @pv: a #ClutterPaintVolume * * Copies @pv into a new #ClutterPaintVolume * * Return value: a newly allocated copy of a #ClutterPaintVolume * * Since: 1.6 */ ClutterPaintVolume * clutter_paint_volume_copy (const ClutterPaintVolume *pv) { ClutterPaintVolume *copy; g_return_val_if_fail (pv != NULL, NULL); copy = g_slice_dup (ClutterPaintVolume, pv); copy->is_static = FALSE; return copy; } void _clutter_paint_volume_set_from_volume (ClutterPaintVolume *pv, const ClutterPaintVolume *src) { gboolean is_static = pv->is_static; memcpy (pv, src, sizeof (ClutterPaintVolume)); pv->is_static = is_static; } /** * clutter_paint_volume_free: * @pv: a #ClutterPaintVolume * * Frees the resources allocated by @pv * * Since: 1.6 */ void clutter_paint_volume_free (ClutterPaintVolume *pv) { g_return_if_fail (pv != NULL); if (G_LIKELY (pv->is_static)) return; g_slice_free (ClutterPaintVolume, pv); } /** * clutter_paint_volume_set_origin: * @pv: a #ClutterPaintVolume * @origin: a #ClutterVertex * * Sets the origin of the paint volume. * * The origin is defined as the X, Y and Z coordinates of the top-left * corner of an actor's paint volume, in actor coordinates. * * The default is origin is assumed at: (0, 0, 0) * * Since: 1.6 */ void clutter_paint_volume_set_origin (ClutterPaintVolume *pv, const ClutterVertex *origin) { static const int key_vertices[4] = { 0, 1, 3, 4 }; float dx, dy, dz; int i; g_return_if_fail (pv != NULL); dx = origin->x - pv->vertices[0].x; dy = origin->y - pv->vertices[0].y; dz = origin->z - pv->vertices[0].z; /* If we change the origin then all the key vertices of the paint * volume need to be shifted too... */ for (i = 0; i < 4; i++) { pv->vertices[key_vertices[i]].x += dx; pv->vertices[key_vertices[i]].y += dy; pv->vertices[key_vertices[i]].z += dz; } pv->is_complete = FALSE; } /** * clutter_paint_volume_get_origin: * @pv: a #ClutterPaintVolume * @vertex: (out): the return location for a #ClutterVertex * * Retrieves the origin of the #ClutterPaintVolume. * * Since: 1.6 */ void clutter_paint_volume_get_origin (const ClutterPaintVolume *pv, ClutterVertex *vertex) { g_return_if_fail (pv != NULL); g_return_if_fail (vertex != NULL); *vertex = pv->vertices[0]; } static void _clutter_paint_volume_update_is_empty (ClutterPaintVolume *pv) { if (pv->vertices[0].x == pv->vertices[1].x && pv->vertices[0].y == pv->vertices[3].y && pv->vertices[0].z == pv->vertices[4].z) pv->is_empty = TRUE; else pv->is_empty = FALSE; } /** * clutter_paint_volume_set_width: * @pv: a #ClutterPaintVolume * @width: the width of the paint volume, in pixels * * Sets the width of the paint volume. The width is measured along * the x axis in the actor coordinates that @pv is associated with. * * Since: 1.6 */ void clutter_paint_volume_set_width (ClutterPaintVolume *pv, gfloat width) { gfloat right_xpos; g_return_if_fail (pv != NULL); g_return_if_fail (width >= 0.0f); /* If the volume is currently empty then only the origin is * currently valid */ if (pv->is_empty) pv->vertices[1] = pv->vertices[3] = pv->vertices[4] = pv->vertices[0]; if (!pv->is_axis_aligned) _clutter_paint_volume_axis_align (pv); right_xpos = pv->vertices[0].x + width; /* Move the right vertices of the paint box relative to the * origin... */ pv->vertices[1].x = right_xpos; /* pv->vertices[2].x = right_xpos; NB: updated lazily */ /* pv->vertices[5].x = right_xpos; NB: updated lazily */ /* pv->vertices[6].x = right_xpos; NB: updated lazily */ pv->is_complete = FALSE; _clutter_paint_volume_update_is_empty (pv); } /** * clutter_paint_volume_get_width: * @pv: a #ClutterPaintVolume * * Retrieves the width of the volume's, axis aligned, bounding box. * * In other words; this takes into account what actor's coordinate * space @pv belongs too and conceptually fits an axis aligned box * around the volume. It returns the size of that bounding box as * measured along the x-axis. * * If, for example, clutter_actor_get_transformed_paint_volume() * is used to transform a 2D child actor that is 100px wide, 100px * high and 0px deep into container coordinates then the width might * not simply be 100px if the child actor has a 3D rotation applied to * it. * * Remember: if clutter_actor_get_transformed_paint_volume() is * used then a transformed child volume will be defined relative to the * ancestor container actor and so a 2D child actor can have a 3D * bounding volume. * * There are no accuracy guarantees for the reported width, * except that it must always be greater than, or equal to, the * actor's width. This is because actors may report simple, loose * fitting paint volumes for efficiency. * Return value: the width, in units of @pv's local coordinate system. * * Since: 1.6 */ gfloat clutter_paint_volume_get_width (const ClutterPaintVolume *pv) { g_return_val_if_fail (pv != NULL, 0.0); if (pv->is_empty) return 0; else if (!pv->is_axis_aligned) { ClutterPaintVolume tmp; float width; _clutter_paint_volume_copy_static (pv, &tmp); _clutter_paint_volume_axis_align (&tmp); width = tmp.vertices[1].x - tmp.vertices[0].x; clutter_paint_volume_free (&tmp); return width; } else return pv->vertices[1].x - pv->vertices[0].x; } /** * clutter_paint_volume_set_height: * @pv: a #ClutterPaintVolume * @height: the height of the paint volume, in pixels * * Sets the height of the paint volume. The height is measured along * the y axis in the actor coordinates that @pv is associated with. * * Since: 1.6 */ void clutter_paint_volume_set_height (ClutterPaintVolume *pv, gfloat height) { gfloat height_ypos; g_return_if_fail (pv != NULL); g_return_if_fail (height >= 0.0f); /* If the volume is currently empty then only the origin is * currently valid */ if (pv->is_empty) pv->vertices[1] = pv->vertices[3] = pv->vertices[4] = pv->vertices[0]; if (!pv->is_axis_aligned) _clutter_paint_volume_axis_align (pv); height_ypos = pv->vertices[0].y + height; /* Move the bottom vertices of the paint box relative to the * origin... */ /* pv->vertices[2].y = height_ypos; NB: updated lazily */ pv->vertices[3].y = height_ypos; /* pv->vertices[6].y = height_ypos; NB: updated lazily */ /* pv->vertices[7].y = height_ypos; NB: updated lazily */ pv->is_complete = FALSE; _clutter_paint_volume_update_is_empty (pv); } /** * clutter_paint_volume_get_height: * @pv: a #ClutterPaintVolume * * Retrieves the height of the volume's, axis aligned, bounding box. * * In other words; this takes into account what actor's coordinate * space @pv belongs too and conceptually fits an axis aligned box * around the volume. It returns the size of that bounding box as * measured along the y-axis. * * If, for example, clutter_actor_get_transformed_paint_volume() * is used to transform a 2D child actor that is 100px wide, 100px * high and 0px deep into container coordinates then the height might * not simply be 100px if the child actor has a 3D rotation applied to * it. * * Remember: if clutter_actor_get_transformed_paint_volume() is * used then a transformed child volume will be defined relative to the * ancestor container actor and so a 2D child actor * can have a 3D bounding volume. * * There are no accuracy guarantees for the reported height, * except that it must always be greater than, or equal to, the actor's * height. This is because actors may report simple, loose fitting paint * volumes for efficiency. * * Return value: the height, in units of @pv's local coordinate system. * * Since: 1.6 */ gfloat clutter_paint_volume_get_height (const ClutterPaintVolume *pv) { g_return_val_if_fail (pv != NULL, 0.0); if (pv->is_empty) return 0; else if (!pv->is_axis_aligned) { ClutterPaintVolume tmp; float height; _clutter_paint_volume_copy_static (pv, &tmp); _clutter_paint_volume_axis_align (&tmp); height = tmp.vertices[3].y - tmp.vertices[0].y; clutter_paint_volume_free (&tmp); return height; } else return pv->vertices[3].y - pv->vertices[0].y; } /** * clutter_paint_volume_set_depth: * @pv: a #ClutterPaintVolume * @depth: the depth of the paint volume, in pixels * * Sets the depth of the paint volume. The depth is measured along * the z axis in the actor coordinates that @pv is associated with. * * Since: 1.6 */ void clutter_paint_volume_set_depth (ClutterPaintVolume *pv, gfloat depth) { gfloat depth_zpos; g_return_if_fail (pv != NULL); g_return_if_fail (depth >= 0.0f); /* If the volume is currently empty then only the origin is * currently valid */ if (pv->is_empty) pv->vertices[1] = pv->vertices[3] = pv->vertices[4] = pv->vertices[0]; if (!pv->is_axis_aligned) _clutter_paint_volume_axis_align (pv); depth_zpos = pv->vertices[0].z + depth; /* Move the back vertices of the paint box relative to the * origin... */ pv->vertices[4].z = depth_zpos; /* pv->vertices[5].z = depth_zpos; NB: updated lazily */ /* pv->vertices[6].z = depth_zpos; NB: updated lazily */ /* pv->vertices[7].z = depth_zpos; NB: updated lazily */ pv->is_complete = FALSE; pv->is_2d = depth ? FALSE : TRUE; _clutter_paint_volume_update_is_empty (pv); } /** * clutter_paint_volume_get_depth: * @pv: a #ClutterPaintVolume * * Retrieves the depth of the volume's, axis aligned, bounding box. * * In other words; this takes into account what actor's coordinate * space @pv belongs too and conceptually fits an axis aligned box * around the volume. It returns the size of that bounding box as * measured along the z-axis. * * If, for example, clutter_actor_get_transformed_paint_volume() * is used to transform a 2D child actor that is 100px wide, 100px * high and 0px deep into container coordinates then the depth might * not simply be 0px if the child actor has a 3D rotation applied to * it. * * Remember: if clutter_actor_get_transformed_paint_volume() is * used then the transformed volume will be defined relative to the * container actor and in container coordinates a 2D child actor * can have a 3D bounding volume. * * There are no accuracy guarantees for the reported depth, * except that it must always be greater than, or equal to, the actor's * depth. This is because actors may report simple, loose fitting paint * volumes for efficiency. * * Return value: the depth, in units of @pv's local coordinate system. * * Since: 1.6 */ gfloat clutter_paint_volume_get_depth (const ClutterPaintVolume *pv) { g_return_val_if_fail (pv != NULL, 0.0); if (pv->is_empty) return 0; else if (!pv->is_axis_aligned) { ClutterPaintVolume tmp; float depth; _clutter_paint_volume_copy_static (pv, &tmp); _clutter_paint_volume_axis_align (&tmp); depth = tmp.vertices[4].z - tmp.vertices[0].z; clutter_paint_volume_free (&tmp); return depth; } else return pv->vertices[4].z - pv->vertices[0].z; } /** * clutter_paint_volume_union: * @pv: The first #ClutterPaintVolume and destination for resulting * union * @another_pv: A second #ClutterPaintVolume to union with @pv * * Updates the geometry of @pv to encompass @pv and @another_pv. * * There are no guarantees about how precisely the two volumes * will be unioned. * * Since: 1.6 */ void clutter_paint_volume_union (ClutterPaintVolume *pv, const ClutterPaintVolume *another_pv) { ClutterPaintVolume aligned_pv; g_return_if_fail (pv != NULL); g_return_if_fail (another_pv != NULL); /* Both volumes have to belong to the same local coordinate space */ g_return_if_fail (pv->actor == another_pv->actor); /* NB: we only have to update vertices 0, 1, 3 and 4 * (See the ClutterPaintVolume typedef for more details) */ /* We special case empty volumes because otherwise we'd end up * calculating a bounding box that would enclose the origin of * the empty volume which isn't desired. */ if (another_pv->is_empty) return; if (pv->is_empty) { _clutter_paint_volume_set_from_volume (pv, another_pv); goto done; } if (!pv->is_axis_aligned) _clutter_paint_volume_axis_align (pv); if (!another_pv->is_axis_aligned) { _clutter_paint_volume_copy_static (another_pv, &aligned_pv); _clutter_paint_volume_axis_align (&aligned_pv); another_pv = &aligned_pv; } /* grow left*/ /* left vertices 0, 3, 4, 7 */ if (another_pv->vertices[0].x < pv->vertices[0].x) { int min_x = another_pv->vertices[0].x; pv->vertices[0].x = min_x; pv->vertices[3].x = min_x; pv->vertices[4].x = min_x; /* pv->vertices[7].x = min_x; */ } /* grow right */ /* right vertices 1, 2, 5, 6 */ if (another_pv->vertices[1].x > pv->vertices[1].x) { int max_x = another_pv->vertices[1].x; pv->vertices[1].x = max_x; /* pv->vertices[2].x = max_x; */ /* pv->vertices[5].x = max_x; */ /* pv->vertices[6].x = max_x; */ } /* grow up */ /* top vertices 0, 1, 4, 5 */ if (another_pv->vertices[0].y < pv->vertices[0].y) { int min_y = another_pv->vertices[0].y; pv->vertices[0].y = min_y; pv->vertices[1].y = min_y; pv->vertices[4].y = min_y; /* pv->vertices[5].y = min_y; */ } /* grow down */ /* bottom vertices 2, 3, 6, 7 */ if (another_pv->vertices[3].y > pv->vertices[3].y) { int may_y = another_pv->vertices[3].y; /* pv->vertices[2].y = may_y; */ pv->vertices[3].y = may_y; /* pv->vertices[6].y = may_y; */ /* pv->vertices[7].y = may_y; */ } /* grow forward */ /* front vertices 0, 1, 2, 3 */ if (another_pv->vertices[0].z < pv->vertices[0].z) { int min_z = another_pv->vertices[0].z; pv->vertices[0].z = min_z; pv->vertices[1].z = min_z; /* pv->vertices[2].z = min_z; */ pv->vertices[3].z = min_z; } /* grow backward */ /* back vertices 4, 5, 6, 7 */ if (another_pv->vertices[4].z > pv->vertices[4].z) { int maz_z = another_pv->vertices[4].z; pv->vertices[4].z = maz_z; /* pv->vertices[5].z = maz_z; */ /* pv->vertices[6].z = maz_z; */ /* pv->vertices[7].z = maz_z; */ } if (pv->vertices[4].z == pv->vertices[0].z) pv->is_2d = TRUE; else pv->is_2d = FALSE; done: pv->is_empty = FALSE; pv->is_complete = FALSE; } /** * clutter_paint_volume_union_box: * @pv: a #ClutterPaintVolume * @box: a #ClutterActorBox to union to @pv * * Unions the 2D region represented by @box to a #ClutterPaintVolume. * * This function is similar to clutter_paint_volume_union(), but it is * specific for 2D regions. * * Since: 1.10 */ void clutter_paint_volume_union_box (ClutterPaintVolume *pv, const ClutterActorBox *box) { ClutterPaintVolume volume; ClutterVertex origin; g_return_if_fail (pv != NULL); g_return_if_fail (box != NULL); _clutter_paint_volume_init_static (&volume, pv->actor); origin.x = box->x1; origin.y = box->y1; origin.z = 0.f; clutter_paint_volume_set_origin (&volume, &origin); clutter_paint_volume_set_width (&volume, box->x2 - box->x1); clutter_paint_volume_set_height (&volume, box->y2 - box->y1); clutter_paint_volume_union (pv, &volume); clutter_paint_volume_free (&volume); } /* The paint_volume setters only update vertices 0, 1, 3 and * 4 since the others can be drived from them. * * This will set pv->completed = TRUE; */ void _clutter_paint_volume_complete (ClutterPaintVolume *pv) { float dx_l2r, dy_l2r, dz_l2r; float dx_t2b, dy_t2b, dz_t2b; if (pv->is_empty) return; if (pv->is_complete) return; /* Find the vector that takes us from any vertex on the left face to * the corresponding vertex on the right face. */ dx_l2r = pv->vertices[1].x - pv->vertices[0].x; dy_l2r = pv->vertices[1].y - pv->vertices[0].y; dz_l2r = pv->vertices[1].z - pv->vertices[0].z; /* Find the vector that takes us from any vertex on the top face to * the corresponding vertex on the bottom face. */ dx_t2b = pv->vertices[3].x - pv->vertices[0].x; dy_t2b = pv->vertices[3].y - pv->vertices[0].y; dz_t2b = pv->vertices[3].z - pv->vertices[0].z; /* front-bottom-right */ pv->vertices[2].x = pv->vertices[3].x + dx_l2r; pv->vertices[2].y = pv->vertices[3].y + dy_l2r; pv->vertices[2].z = pv->vertices[3].z + dz_l2r; if (G_UNLIKELY (!pv->is_2d)) { /* back-top-right */ pv->vertices[5].x = pv->vertices[4].x + dx_l2r; pv->vertices[5].y = pv->vertices[4].y + dy_l2r; pv->vertices[5].z = pv->vertices[4].z + dz_l2r; /* back-bottom-right */ pv->vertices[6].x = pv->vertices[5].x + dx_t2b; pv->vertices[6].y = pv->vertices[5].y + dy_t2b; pv->vertices[6].z = pv->vertices[5].z + dz_t2b; /* back-bottom-left */ pv->vertices[7].x = pv->vertices[4].x + dx_t2b; pv->vertices[7].y = pv->vertices[4].y + dy_t2b; pv->vertices[7].z = pv->vertices[4].z + dz_t2b; } pv->is_complete = TRUE; } /* * _clutter_paint_volume_get_box: * @pv: a #ClutterPaintVolume * @box: a pixel aligned #ClutterActorBox * * Transforms a 3D paint volume into a 2D bounding box in the * same coordinate space as the 3D paint volume. * * To get an actors "paint box" you should first project * the paint volume into window coordinates before getting * the 2D bounding box. * * The coordinates of the returned box are not clamped to * integer pixel values; if you need them to be rounded to the * nearest integer pixel values, you can use the * clutter_actor_box_clamp_to_pixel() function. * * Since: 1.6 */ void _clutter_paint_volume_get_bounding_box (ClutterPaintVolume *pv, ClutterActorBox *box) { gfloat x_min, y_min, x_max, y_max; ClutterVertex *vertices; int count; gint i; g_return_if_fail (pv != NULL); g_return_if_fail (box != NULL); if (pv->is_empty) { box->x1 = box->x2 = pv->vertices[0].x; box->y1 = box->y2 = pv->vertices[0].y; return; } /* Updates the vertices we calculate lazily * (See ClutterPaintVolume typedef for more details) */ _clutter_paint_volume_complete (pv); vertices = pv->vertices; x_min = x_max = vertices[0].x; y_min = y_max = vertices[0].y; /* Most actors are 2D so we only have to look at the front 4 * vertices of the paint volume... */ if (G_LIKELY (pv->is_2d)) count = 4; else count = 8; for (i = 1; i < count; i++) { if (vertices[i].x < x_min) x_min = vertices[i].x; else if (vertices[i].x > x_max) x_max = vertices[i].x; if (vertices[i].y < y_min) y_min = vertices[i].y; else if (vertices[i].y > y_max) y_max = vertices[i].y; } box->x1 = x_min; box->y1 = y_min; box->x2 = x_max; box->y2 = y_max; } void _clutter_paint_volume_project (ClutterPaintVolume *pv, const CoglMatrix *modelview, const CoglMatrix *projection, const float *viewport) { int transform_count; if (pv->is_empty) { /* Just transform the origin... */ _clutter_util_fully_transform_vertices (modelview, projection, viewport, pv->vertices, pv->vertices, 1); return; } /* All the vertices must be up to date, since after the projection * it wont be trivial to derive the other vertices. */ _clutter_paint_volume_complete (pv); /* Most actors are 2D so we only have to transform the front 4 * vertices of the paint volume... */ if (G_LIKELY (pv->is_2d)) transform_count = 4; else transform_count = 8; _clutter_util_fully_transform_vertices (modelview, projection, viewport, pv->vertices, pv->vertices, transform_count); pv->is_axis_aligned = FALSE; } void _clutter_paint_volume_transform (ClutterPaintVolume *pv, const CoglMatrix *matrix) { int transform_count; if (pv->is_empty) { gfloat w = 1; /* Just transform the origin */ cogl_matrix_transform_point (matrix, &pv->vertices[0].x, &pv->vertices[0].y, &pv->vertices[0].z, &w); return; } /* All the vertices must be up to date, since after the transform * it wont be trivial to derive the other vertices. */ _clutter_paint_volume_complete (pv); /* Most actors are 2D so we only have to transform the front 4 * vertices of the paint volume... */ if (G_LIKELY (pv->is_2d)) transform_count = 4; else transform_count = 8; cogl_matrix_transform_points (matrix, 3, sizeof (ClutterVertex), pv->vertices, sizeof (ClutterVertex), pv->vertices, transform_count); pv->is_axis_aligned = FALSE; } /* Given a paint volume that has been transformed by an arbitrary * modelview and is no longer axis aligned, this derives a replacement * that is axis aligned. */ void _clutter_paint_volume_axis_align (ClutterPaintVolume *pv) { int count; int i; ClutterVertex origin; float max_x; float max_y; float max_z; g_return_if_fail (pv != NULL); if (pv->is_empty) return; if (G_LIKELY (pv->is_axis_aligned)) return; if (G_LIKELY (pv->vertices[0].x == pv->vertices[1].x && pv->vertices[0].y == pv->vertices[3].y && pv->vertices[0].z == pv->vertices[4].z)) { pv->is_axis_aligned = TRUE; return; } if (!pv->is_complete) _clutter_paint_volume_complete (pv); origin = pv->vertices[0]; max_x = pv->vertices[0].x; max_y = pv->vertices[0].y; max_z = pv->vertices[0].z; count = pv->is_2d ? 4 : 8; for (i = 1; i < count; i++) { if (pv->vertices[i].x < origin.x) origin.x = pv->vertices[i].x; else if (pv->vertices[i].x > max_x) max_x = pv->vertices[i].x; if (pv->vertices[i].y < origin.y) origin.y = pv->vertices[i].y; else if (pv->vertices[i].y > max_y) max_y = pv->vertices[i].y; if (pv->vertices[i].z < origin.z) origin.z = pv->vertices[i].z; else if (pv->vertices[i].z > max_z) max_z = pv->vertices[i].z; } pv->vertices[0] = origin; pv->vertices[1].x = max_x; pv->vertices[1].y = origin.y; pv->vertices[1].z = origin.z; pv->vertices[3].x = origin.x; pv->vertices[3].y = max_y; pv->vertices[3].z = origin.z; pv->vertices[4].x = origin.x; pv->vertices[4].y = origin.y; pv->vertices[4].z = max_z; pv->is_complete = FALSE; pv->is_axis_aligned = TRUE; if (pv->vertices[4].z == pv->vertices[0].z) pv->is_2d = TRUE; else pv->is_2d = FALSE; } /* * _clutter_actor_set_default_paint_volume: * @self: a #ClutterActor * @check_gtype: if not %G_TYPE_INVALID, match the type of @self against * this type * @volume: the #ClutterPaintVolume to set * * Sets the default paint volume for @self. * * This function should be called by #ClutterActor sub-classes that follow * the default assumption that their paint volume is defined by their * allocation. * * If @check_gtype is not %G_TYPE_INVALID, this function will check the * type of @self and only compute the paint volume if the type matches; * this can be used to avoid computing the paint volume for sub-classes * of an actor class * * Return value: %TRUE if the paint volume was set, and %FALSE otherwise */ gboolean _clutter_actor_set_default_paint_volume (ClutterActor *self, GType check_gtype, ClutterPaintVolume *volume) { ClutterActorBox box; if (check_gtype != G_TYPE_INVALID) { if (G_OBJECT_TYPE (self) != check_gtype) return FALSE; } /* calling clutter_actor_get_allocation_* can potentially be very * expensive, as it can result in a synchronous full stage relayout * and redraw */ if (!clutter_actor_has_allocation (self)) return FALSE; clutter_actor_get_allocation_box (self, &box); /* we only set the width and height, as the paint volume is defined * to be relative to the actor's modelview, which means that the * allocation's origin has already been applied */ clutter_paint_volume_set_width (volume, box.x2 - box.x1); clutter_paint_volume_set_height (volume, box.y2 - box.y1); return TRUE; } /** * clutter_paint_volume_set_from_allocation: * @pv: a #ClutterPaintVolume * @actor: a #ClutterActor * * Sets the #ClutterPaintVolume from the allocation of @actor. * * This function should be used when overriding the * #ClutterActorClass.get_paint_volume() by #ClutterActor sub-classes * that do not paint outside their allocation. * * A typical example is: * * |[ * static gboolean * my_actor_get_paint_volume (ClutterActor *self, * ClutterPaintVolume *volume) * { * return clutter_paint_volume_set_from_allocation (volume, self); * } * ]| * * Return value: %TRUE if the paint volume was successfully set, and %FALSE * otherwise * * Since: 1.6 */ gboolean clutter_paint_volume_set_from_allocation (ClutterPaintVolume *pv, ClutterActor *actor) { g_return_val_if_fail (pv != NULL, FALSE); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); return _clutter_actor_set_default_paint_volume (actor, G_TYPE_INVALID, pv); } /* Currently paint volumes are defined relative to a given actor, but * in some cases it is desireable to be able to change the actor that * a volume relates too (For instance for ClutterClone actors where we * need to masquarade the source actors volume as the volume for the * clone). */ void _clutter_paint_volume_set_reference_actor (ClutterPaintVolume *pv, ClutterActor *actor) { g_return_if_fail (pv != NULL); pv->actor = actor; } ClutterCullResult _clutter_paint_volume_cull (ClutterPaintVolume *pv, const ClutterPlane *planes) { int vertex_count; ClutterVertex *vertices = pv->vertices; gboolean partial = FALSE; int i; int j; if (pv->is_empty) return CLUTTER_CULL_RESULT_OUT; /* We expect the volume to already be transformed into eye coordinates */ g_return_val_if_fail (pv->is_complete == TRUE, CLUTTER_CULL_RESULT_IN); g_return_val_if_fail (pv->actor == NULL, CLUTTER_CULL_RESULT_IN); /* Most actors are 2D so we only have to transform the front 4 * vertices of the paint volume... */ if (G_LIKELY (pv->is_2d)) vertex_count = 4; else vertex_count = 8; for (i = 0; i < 4; i++) { int out = 0; for (j = 0; j < vertex_count; j++) { ClutterVertex p; float distance; /* XXX: for perspective projections this can be optimized * out because all the planes should pass through the origin * so (0,0,0) is a valid v0. */ p.x = vertices[j].x - planes[i].v0[0]; p.y = vertices[j].y - planes[i].v0[1]; p.z = vertices[j].z - planes[i].v0[2]; distance = (planes[i].n[0] * p.x + planes[i].n[1] * p.y + planes[i].n[2] * p.z); if (distance < 0) out++; } if (out == vertex_count) return CLUTTER_CULL_RESULT_OUT; else if (out != 0) partial = TRUE; } if (partial) return CLUTTER_CULL_RESULT_PARTIAL; else return CLUTTER_CULL_RESULT_IN; } void _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolume *pv, ClutterStage *stage, ClutterActorBox *box) { ClutterPaintVolume projected_pv; CoglMatrix modelview; CoglMatrix projection; float viewport[4]; _clutter_paint_volume_copy_static (pv, &projected_pv); cogl_matrix_init_identity (&modelview); /* If the paint volume isn't already in eye coordinates... */ if (pv->actor) _clutter_actor_apply_relative_transformation_matrix (pv->actor, NULL, &modelview); _clutter_stage_get_projection_matrix (stage, &projection); _clutter_stage_get_viewport (stage, &viewport[0], &viewport[1], &viewport[2], &viewport[3]); _clutter_paint_volume_project (&projected_pv, &modelview, &projection, viewport); _clutter_paint_volume_get_bounding_box (&projected_pv, box); _clutter_actor_box_enlarge_for_effects (box); clutter_paint_volume_free (&projected_pv); } void _clutter_paint_volume_transform_relative (ClutterPaintVolume *pv, ClutterActor *relative_to_ancestor) { CoglMatrix matrix; ClutterActor *actor; actor = pv->actor; g_return_if_fail (actor != NULL); _clutter_paint_volume_set_reference_actor (pv, relative_to_ancestor); cogl_matrix_init_identity (&matrix); _clutter_actor_apply_relative_transformation_matrix (actor, relative_to_ancestor, &matrix); _clutter_paint_volume_transform (pv, &matrix); } muffin-5.2.1/clutter/clutter/clutter-cairo.h0000664000175000017500000000365014211404421021232 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation * * 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, see . */ #ifndef __CLUTTER_CAIRO_H__ #define __CLUTTER_CAIRO_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS /** * CLUTTER_CAIRO_FORMAT_ARGB32: * * The #CoglPixelFormat to be used when uploading image data from * and to a Cairo image surface using %CAIRO_FORMAT_ARGB32 and * %CAIRO_FORMAT_RGB24 as #cairo_format_t. * * Since: 1.8 */ /* Cairo stores the data in native byte order as ARGB but Cogl's pixel * formats specify the actual byte order. Therefore we need to use a * different format depending on the architecture */ #if G_BYTE_ORDER == G_LITTLE_ENDIAN #define CLUTTER_CAIRO_FORMAT_ARGB32 (COGL_PIXEL_FORMAT_BGRA_8888_PRE) #else #define CLUTTER_CAIRO_FORMAT_ARGB32 (COGL_PIXEL_FORMAT_ARGB_8888_PRE) #endif CLUTTER_AVAILABLE_IN_1_12 void clutter_cairo_clear (cairo_t *cr); CLUTTER_AVAILABLE_IN_1_0 void clutter_cairo_set_source_color (cairo_t *cr, const ClutterColor *color); G_END_DECLS #endif /* __CLUTTER_CAIRO_H__ */ muffin-5.2.1/clutter/clutter/clutter-script.c0000664000175000017500000013551614211404421021443 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * */ /** * SECTION:clutter-script * @short_description: Loads a scene from UI definition data * * #ClutterScript is an object used for loading and building parts or a * complete scenegraph from external definition data in forms of string * buffers or files. * * The UI definition format is JSON, the JavaScript Object Notation as * described by RFC 4627. #ClutterScript can load a JSON data stream, * parse it and build all the objects defined into it. Each object must * have an "id" and a "type" properties defining the name to be used * to retrieve it from #ClutterScript with clutter_script_get_object(), * and the class type to be instanciated. Every other attribute will * be mapped to the class properties. * * A #ClutterScript holds a reference on every object it creates from * the definition data, except for the stage. Every non-actor object * will be finalized when the #ClutterScript instance holding it will * be finalized, so they need to be referenced using g_object_ref() in * order for them to survive. * * A simple object might be defined as: * * * * This will produce a red #ClutterRectangle, 100x100 pixels wide, and * with a ClutterScript id of "red-button"; it can be retrieved by calling: * * |[ * ClutterActor *red_button; * * red_button = CLUTTER_ACTOR (clutter_script_get_object (script, "red-button")); * ]| * * and then manipulated with the Clutter API. For every object created * using ClutterScript it is possible to check the id by calling * clutter_get_script_id(). * * Packing can be represented using the "children" member, and passing an * array of objects or ids of objects already defined (but not packed: the * packing rules of Clutter still apply, and an actor cannot be packed * in multiple containers without unparenting it in between). * * Behaviours and timelines can also be defined inside a UI definition * buffer: * * * * And then to apply a defined behaviour to an actor defined inside the * definition of an actor, the "behaviour" member can be used: * * * * A #ClutterAlpha belonging to a #ClutterBehaviour can only be defined * implicitly like in the example above, or explicitly by setting the * "alpha" property to point to a previously defined #ClutterAlpha, e.g.: * * * * Implicitely defined #ClutterAlphas and #ClutterTimelines * can omit the `id`, as well as the `type` members, but will not be available * using clutter_script_get_object() (they can, however, be extracted using the * #ClutterBehaviour and #ClutterAlpha API respectively). * * Signal handlers can be defined inside a Clutter UI definition file and * then autoconnected to their respective signals using the * clutter_script_connect_signals() function: * * * * Signal handler definitions must have a "name" and a "handler" members; * they can also have the "after" and "swapped" boolean members (for the * signal connection flags %G_CONNECT_AFTER and %G_CONNECT_SWAPPED * respectively) and the "object" string member for calling * g_signal_connect_object() instead of g_signal_connect(). * * Signals can also be directly attached to a specific state defined * inside a #ClutterState instance, for instance: * * |[ * ... * "signals" : [ * { * "name" : "enter-event", * "states" : "button-states", * "target-state" : "hover" * }, * { * "name" : "leave-event", * "states" : "button-states", * "target-state" : "base" * }, * { * "name" : "button-press-event", * "states" : "button-states", * "target-state" : "active", * }, * { * "name" : "key-press-event", * "states" : "button-states", * "target-state" : "key-focus", * "warp" : true * } * ], * ... * ]| * * The "states" key defines the #ClutterState instance to be used to * resolve the "target-state" key; it can be either a script id for a * #ClutterState built by the same #ClutterScript instance, or to a * #ClutterState built in code and associated to the #ClutterScript * instance through the clutter_script_add_states() function. If no * "states" key is present, then the default #ClutterState associated to * the #ClutterScript instance will be used; the default #ClutterState * can be set using clutter_script_add_states() using a %NULL name. The * "warp" key can be used to warp to a specific state instead of * animating to it. State changes on signal emission will not affect * the signal emission chain. * * Clutter reserves the following names, so classes defining properties * through the usual GObject registration process should avoid using these * names to avoid collisions: * * * * #ClutterScript is available since Clutter 0.6 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #include #include #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "clutter-actor.h" #include "clutter-stage.h" #include "clutter-texture.h" #include "clutter-script.h" #include "clutter-script-private.h" #include "clutter-scriptable.h" #include "clutter-enum-types.h" #include "clutter-private.h" #include "clutter-debug.h" #include "deprecated/clutter-alpha.h" #include "deprecated/clutter-behaviour.h" #include "deprecated/clutter-container.h" #include "deprecated/clutter-state.h" enum { PROP_0, PROP_FILENAME_SET, PROP_FILENAME, PROP_TRANSLATION_DOMAIN, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; #define CLUTTER_SCRIPT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_SCRIPT, ClutterScriptPrivate)) struct _ClutterScriptPrivate { GHashTable *objects; guint last_merge_id; guint last_unknown; ClutterScriptParser *parser; GHashTable *states; gchar **search_paths; gchar *translation_domain; gchar *filename; guint is_filename : 1; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterScript, clutter_script, G_TYPE_OBJECT) static GType clutter_script_real_get_type_from_name (ClutterScript *script, const gchar *type_name) { GType gtype; gtype = g_type_from_name (type_name); if (gtype != G_TYPE_INVALID) return gtype; return _clutter_script_get_type_from_class (type_name); } void property_info_free (gpointer data) { if (G_LIKELY (data)) { PropertyInfo *pinfo = data; if (pinfo->node) json_node_free (pinfo->node); if (pinfo->pspec) g_param_spec_unref (pinfo->pspec); free (pinfo->name); g_slice_free (PropertyInfo, pinfo); } } static void signal_info_free (gpointer data) { if (G_LIKELY (data)) { SignalInfo *sinfo = data; free (sinfo->name); free (sinfo->handler); free (sinfo->object); free (sinfo->state); free (sinfo->target); g_slice_free (SignalInfo, sinfo); } } void object_info_free (gpointer data) { if (G_LIKELY (data)) { ObjectInfo *oinfo = data; free (oinfo->id); free (oinfo->class_name); free (oinfo->type_func); g_list_foreach (oinfo->properties, (GFunc) property_info_free, NULL); g_list_free (oinfo->properties); g_list_foreach (oinfo->signals, (GFunc) signal_info_free, NULL); g_list_free (oinfo->signals); /* these are ids */ g_list_foreach (oinfo->children, (GFunc) free, NULL); g_list_free (oinfo->children); /* we unref top-level objects and leave the actors alone, * unless we are unmerging in which case we have to destroy * the actor to unparent them */ if (oinfo->object != NULL) { if (oinfo->is_unmerged) { if (oinfo->is_actor && !oinfo->is_stage) clutter_actor_destroy (CLUTTER_ACTOR (oinfo->object)); } g_object_unref (oinfo->object); oinfo->object = NULL; } g_slice_free (ObjectInfo, oinfo); } } static void clutter_script_finalize (GObject *gobject) { ClutterScriptPrivate *priv = CLUTTER_SCRIPT_GET_PRIVATE (gobject); g_object_unref (priv->parser); g_hash_table_destroy (priv->objects); g_strfreev (priv->search_paths); free (priv->filename); g_hash_table_destroy (priv->states); free (priv->translation_domain); G_OBJECT_CLASS (clutter_script_parent_class)->finalize (gobject); } static void clutter_script_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterScript *script = CLUTTER_SCRIPT (gobject); switch (prop_id) { case PROP_TRANSLATION_DOMAIN: clutter_script_set_translation_domain (script, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_script_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterScript *script = CLUTTER_SCRIPT (gobject); switch (prop_id) { case PROP_FILENAME_SET: g_value_set_boolean (value, script->priv->is_filename); break; case PROP_FILENAME: g_value_set_string (value, script->priv->filename); break; case PROP_TRANSLATION_DOMAIN: g_value_set_string (value, script->priv->translation_domain); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_script_class_init (ClutterScriptClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); klass->get_type_from_name = clutter_script_real_get_type_from_name; /** * ClutterScript:filename-set: * * Whether the #ClutterScript:filename property is set. If this property * is %TRUE then the currently parsed data comes from a file, and the * file name is stored inside the #ClutterScript:filename property. * * Since: 0.6 */ obj_props[PROP_FILENAME_SET] = g_param_spec_boolean ("filename-set", P_("Filename Set"), P_("Whether the :filename property is set"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterScript:filename: * * The path of the currently parsed file. If #ClutterScript:filename-set * is %FALSE then the value of this property is undefined. * * Since: 0.6 */ obj_props[PROP_FILENAME] = g_param_spec_string ("filename", P_("Filename"), P_("The path of the currently parsed file"), NULL, CLUTTER_PARAM_READABLE); /** * ClutterScript:translation-domain: * * The translation domain, used to localize strings marked as translatable * inside a UI definition. * * If #ClutterScript:translation-domain is set to %NULL, #ClutterScript * will use gettext(), otherwise g_dgettext() will be used. * * Since: 1.10 */ obj_props[PROP_TRANSLATION_DOMAIN] = g_param_spec_string ("translation-domain", P_("Translation Domain"), P_("The translation domain used to localize string"), NULL, CLUTTER_PARAM_READWRITE); gobject_class->set_property = clutter_script_set_property; gobject_class->get_property = clutter_script_get_property; gobject_class->finalize = clutter_script_finalize; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_script_init (ClutterScript *script) { ClutterScriptPrivate *priv; script->priv = priv = clutter_script_get_instance_private (script); priv->parser = g_object_new (CLUTTER_TYPE_SCRIPT_PARSER, NULL); priv->parser->script = script; priv->is_filename = FALSE; priv->last_merge_id = 0; priv->objects = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, object_info_free); priv->states = g_hash_table_new_full (g_str_hash, g_str_equal, free, (GDestroyNotify) g_object_unref); } /** * clutter_script_new: * * Creates a new #ClutterScript instance. #ClutterScript can be used * to load objects definitions for scenegraph elements, like actors, * or behavioural elements, like behaviours and timelines. The * definitions must be encoded using the JavaScript Object Notation (JSON) * language. * * Return value: the newly created #ClutterScript instance. Use * g_object_unref() when done. * * Since: 0.6 */ ClutterScript * clutter_script_new (void) { return g_object_new (CLUTTER_TYPE_SCRIPT, NULL); } /** * clutter_script_load_from_file: * @script: a #ClutterScript * @filename: the full path to the definition file * @error: return location for a #GError, or %NULL * * Loads the definitions from @filename into @script and merges with * the currently loaded ones, if any. * * Return value: on error, zero is returned and @error is set * accordingly. On success, the merge id for the UI definitions is * returned. You can use the merge id with clutter_script_unmerge_objects(). * * Since: 0.6 */ guint clutter_script_load_from_file (ClutterScript *script, const gchar *filename, GError **error) { ClutterScriptPrivate *priv; GError *internal_error; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), 0); g_return_val_if_fail (filename != NULL, 0); priv = script->priv; free (priv->filename); priv->filename = g_strdup (filename); priv->is_filename = TRUE; priv->last_merge_id += 1; internal_error = NULL; json_parser_load_from_file (JSON_PARSER (priv->parser), filename, &internal_error); if (internal_error) { g_propagate_error (error, internal_error); priv->last_merge_id -= 1; return 0; } return priv->last_merge_id; } /** * clutter_script_load_from_data: * @script: a #ClutterScript * @data: a buffer containing the definitions * @length: the length of the buffer, or -1 if @data is a NUL-terminated * buffer * @error: return location for a #GError, or %NULL * * Loads the definitions from @data into @script and merges with * the currently loaded ones, if any. * * Return value: on error, zero is returned and @error is set * accordingly. On success, the merge id for the UI definitions is * returned. You can use the merge id with clutter_script_unmerge_objects(). * * Since: 0.6 */ guint clutter_script_load_from_data (ClutterScript *script, const gchar *data, gssize length, GError **error) { ClutterScriptPrivate *priv; GError *internal_error; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), 0); g_return_val_if_fail (data != NULL, 0); if (length < 0) length = strlen (data); priv = script->priv; free (priv->filename); priv->filename = NULL; priv->is_filename = FALSE; priv->last_merge_id += 1; internal_error = NULL; json_parser_load_from_data (JSON_PARSER (priv->parser), data, length, &internal_error); if (internal_error) { g_propagate_error (error, internal_error); priv->last_merge_id -= 1; return 0; } return priv->last_merge_id; } /** * clutter_script_load_from_resource: * @script: a #ClutterScript * @resource_path: the resource path of the file to parse * @error: return location for a #GError, or %NULL * * Loads the definitions from a resource file into @script and merges with * the currently loaded ones, if any. * * Return value: on error, zero is returned and @error is set * accordingly. On success, the merge id for the UI definitions is * returned. You can use the merge id with clutter_script_unmerge_objects(). * * Since: 1.10 */ guint clutter_script_load_from_resource (ClutterScript *script, const gchar *resource_path, GError **error) { GBytes *data; guint res; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), 0); data = g_resources_lookup_data (resource_path, 0, error); if (data == NULL) return 0; res = clutter_script_load_from_data (script, g_bytes_get_data (data, NULL), g_bytes_get_size (data), error); g_bytes_unref (data); return res; } /** * clutter_script_get_object: * @script: a #ClutterScript * @name: the name of the object to retrieve * * Retrieves the object bound to @name. This function does not increment * the reference count of the returned object. * * Return value: (transfer none): the named object, or %NULL if no object * with the given name was available * * Since: 0.6 */ GObject * clutter_script_get_object (ClutterScript *script, const gchar *name) { ObjectInfo *oinfo; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL); g_return_val_if_fail (name != NULL, NULL); oinfo = g_hash_table_lookup (script->priv->objects, name); if (!oinfo) return NULL; _clutter_script_construct_object (script, oinfo); _clutter_script_apply_properties (script, oinfo); return oinfo->object; } static gint clutter_script_get_objects_valist (ClutterScript *script, const gchar *first_name, va_list args) { gint retval = 0; const gchar *name; name = first_name; while (name) { GObject **obj = NULL; obj = va_arg (args, GObject**); *obj = clutter_script_get_object (script, name); if (*obj) retval += 1; name = va_arg (args, gchar*); } return retval; } /** * clutter_script_get_objects: * @script: a #ClutterScript * @first_name: the name of the first object to retrieve * @...: return location for a #GObject, then additional names, ending * with %NULL * * Retrieves a list of objects for the given names. After @script, object * names/return location pairs should be listed, with a %NULL pointer * ending the list, like: * * |[ * GObject *my_label, *a_button, *main_timeline; * * clutter_script_get_objects (script, * "my-label", &my_label, * "a-button", &a_button, * "main-timeline", &main_timeline, * NULL); * ]| * * Note: This function does not increment the reference count of the * returned objects. * * Return value: the number of objects returned. * * Since: 0.6 */ gint clutter_script_get_objects (ClutterScript *script, const gchar *first_name, ...) { gint retval; va_list var_args; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), 0); g_return_val_if_fail (first_name != NULL, 0); va_start (var_args, first_name); retval = clutter_script_get_objects_valist (script, first_name, var_args); va_end (var_args); return retval; } typedef struct { ClutterScript *script; guint merge_id; GSList *ids; } UnmergeData; static void remove_by_merge_id (gpointer key, gpointer value, gpointer data) { gchar *name = key; ObjectInfo *oinfo = value; UnmergeData *unmerge_data = data; if (oinfo->merge_id == unmerge_data->merge_id) { CLUTTER_NOTE (SCRIPT, "Unmerging object (id:%s, type:%s, merge-id:%d)", oinfo->id, oinfo->class_name, oinfo->merge_id); unmerge_data->ids = g_slist_prepend (unmerge_data->ids, g_strdup (name)); oinfo->is_unmerged = TRUE; } } /** * clutter_script_unmerge_objects: * @script: a #ClutterScript * @merge_id: merge id returned when loading a UI definition * * Unmerges the objects identified by @merge_id. * * Since: 0.6 */ void clutter_script_unmerge_objects (ClutterScript *script, guint merge_id) { ClutterScriptPrivate *priv; UnmergeData data; GSList *l; g_return_if_fail (CLUTTER_IS_SCRIPT (script)); g_return_if_fail (merge_id > 0); priv = script->priv; data.script = script; data.merge_id = merge_id; data.ids = NULL; g_hash_table_foreach (priv->objects, remove_by_merge_id, &data); for (l = data.ids; l != NULL; l = l->next) g_hash_table_remove (priv->objects, l->data); g_slist_foreach (data.ids, (GFunc) free, NULL); g_slist_free (data.ids); clutter_script_ensure_objects (script); } static void construct_each_objects (gpointer key, gpointer value, gpointer user_data) { ClutterScript *script = user_data; ObjectInfo *oinfo = value; /* we have unfinished business */ if (oinfo->has_unresolved) { /* this should not happen, but resilence is * a good thing in a parser */ if (oinfo->object == NULL) _clutter_script_construct_object (script, oinfo); /* this will take care of setting up properties, * adding children and applying behaviours */ _clutter_script_apply_properties (script, oinfo); } } /** * clutter_script_ensure_objects: * @script: a #ClutterScript * * Ensure that every object defined inside @script is correctly * constructed. You should rarely need to use this function. * * Since: 0.6 */ void clutter_script_ensure_objects (ClutterScript *script) { ClutterScriptPrivate *priv; g_return_if_fail (CLUTTER_IS_SCRIPT (script)); priv = script->priv; g_hash_table_foreach (priv->objects, construct_each_objects, script); } /** * clutter_script_get_type_from_name: * @script: a #ClutterScript * @type_name: name of the type to look up * * Looks up a type by name, using the virtual function that * #ClutterScript has for that purpose. This function should * rarely be used. * * Return value: the type for the requested type name, or * %G_TYPE_INVALID if not corresponding type was found. * * Since: 0.6 */ GType clutter_script_get_type_from_name (ClutterScript *script, const gchar *type_name) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), G_TYPE_INVALID); g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID); return CLUTTER_SCRIPT_GET_CLASS (script)->get_type_from_name (script, type_name); } /** * clutter_get_script_id: * @gobject: a #GObject * * Retrieves the Clutter script id, if any. * * Return value: the script id, or %NULL if @object was not defined inside * a UI definition file. The returned string is owned by the object and * should never be modified or freed. * * Since: 0.6 */ const gchar * clutter_get_script_id (GObject *gobject) { g_return_val_if_fail (G_IS_OBJECT (gobject), NULL); if (CLUTTER_IS_SCRIPTABLE (gobject)) return clutter_scriptable_get_id (CLUTTER_SCRIPTABLE (gobject)); else return g_object_get_data (gobject, "clutter-script-id"); } typedef struct { GModule *module; gpointer data; } ConnectData; /* default signal connection code */ static void clutter_script_default_connect (ClutterScript *script, GObject *gobject, const gchar *signal_name, const gchar *signal_handler, GObject *connect_gobject, GConnectFlags flags, gpointer user_data) { ConnectData *data = user_data; GCallback function; if (!data->module) return; if (!g_module_symbol (data->module, signal_handler, (gpointer) &function)) { g_warning ("Could not find a signal handler '%s' for signal '%s::%s'", signal_handler, connect_gobject ? G_OBJECT_TYPE_NAME (connect_gobject) : G_OBJECT_TYPE_NAME (gobject), signal_name); return; } CLUTTER_NOTE (SCRIPT, "connecting %s::%s to %s (afetr:%s, swapped:%s, object:%s)", (connect_gobject ? G_OBJECT_TYPE_NAME (connect_gobject) : G_OBJECT_TYPE_NAME (gobject)), signal_name, signal_handler, (flags & G_CONNECT_AFTER) ? "true" : "false", (flags & G_CONNECT_SWAPPED) ? "true" : "false", (connect_gobject ? G_OBJECT_TYPE_NAME (connect_gobject) : "")); if (connect_gobject != NULL) g_signal_connect_object (gobject, signal_name, function, connect_gobject, flags); else g_signal_connect_data (gobject, signal_name, function, data->data, NULL, flags); } /** * clutter_script_connect_signals: * @script: a #ClutterScript * @user_data: data to be passed to the signal handlers, or %NULL * * Connects all the signals defined into a UI definition file to their * handlers. * * This method invokes clutter_script_connect_signals_full() internally * and uses #GModule's introspective features (by opening the current * module's scope) to look at the application's symbol table. * * Note that this function will not work if #GModule is not supported by * the platform Clutter is running on. * * Since: 0.6 */ void clutter_script_connect_signals (ClutterScript *script, gpointer user_data) { ConnectData *cd; g_return_if_fail (CLUTTER_IS_SCRIPT (script)); if (!g_module_supported ()) { g_critical ("clutter_script_connect_signals() requires a working " "GModule support from GLib"); return; } cd = g_new (ConnectData, 1); cd->module = g_module_open (NULL, 0); cd->data = user_data; clutter_script_connect_signals_full (script, clutter_script_default_connect, cd); g_module_close (cd->module); free (cd); } typedef struct { ClutterState *state; GObject *emitter; gchar *target; gulong signal_id; gulong hook_id; gboolean warp_to; } HookData; typedef struct { ClutterScript *script; ClutterScriptConnectFunc func; gpointer user_data; } SignalConnectData; static void hook_data_free (gpointer data) { if (G_LIKELY (data != NULL)) { HookData *hook_data = data; free (hook_data->target); g_slice_free (HookData, hook_data); } } static gboolean clutter_script_state_change_hook (GSignalInvocationHint *ihint, guint n_params, const GValue *params, gpointer user_data) { HookData *hook_data = user_data; GObject *emitter; emitter = g_value_get_object (¶ms[0]); if (emitter == hook_data->emitter) { if (hook_data->warp_to) clutter_state_warp_to_state (hook_data->state, hook_data->target); else clutter_state_set_state (hook_data->state, hook_data->target); } return TRUE; } static void clutter_script_remove_state_change_hook (gpointer user_data, GObject *object_p) { HookData *hook_data = user_data; g_signal_remove_emission_hook (hook_data->signal_id, hook_data->hook_id); } static void connect_each_object (gpointer key, gpointer value, gpointer data) { SignalConnectData *connect_data = data; ClutterScript *script = connect_data->script; ObjectInfo *oinfo = value; GObject *object = oinfo->object; GList *unresolved, *l; _clutter_script_construct_object (script, oinfo); unresolved = NULL; for (l = oinfo->signals; l != NULL; l = l->next) { SignalInfo *sinfo = l->data; if (sinfo->is_handler) { GObject *connect_object = NULL; if (sinfo->object) connect_object = clutter_script_get_object (script, sinfo->object); if (sinfo->object && !connect_object) unresolved = g_list_prepend (unresolved, sinfo); else { connect_data->func (script, object, sinfo->name, sinfo->handler, connect_object, sinfo->flags, connect_data->user_data); } } else { GObject *state_object = NULL; const gchar *signal_name, *signal_detail; gchar **components; GQuark signal_quark; guint signal_id; HookData *hook_data; if (sinfo->state == NULL) state_object = (GObject *) clutter_script_get_states (script, NULL); else { state_object = clutter_script_get_object (script, sinfo->state); if (state_object == NULL) state_object = (GObject *) clutter_script_get_states (script, sinfo->state); } if (state_object == NULL) continue; components = g_strsplit (sinfo->name, "::", 2); if (g_strv_length (components) == 2) { signal_name = components[0]; signal_detail = components[1]; } else { signal_name = components[0]; signal_detail = NULL; } signal_id = g_signal_lookup (signal_name, G_OBJECT_TYPE (object)); if (signal_id == 0) { g_strfreev (components); continue; } if (signal_detail != NULL) signal_quark = g_quark_from_string (signal_detail); else signal_quark = 0; hook_data = g_slice_new (HookData); hook_data->emitter = object; hook_data->state = CLUTTER_STATE (state_object); hook_data->target = g_strdup (sinfo->target); hook_data->warp_to = sinfo->warp_to; hook_data->signal_id = signal_id; hook_data->hook_id = g_signal_add_emission_hook (signal_id, signal_quark, clutter_script_state_change_hook, hook_data, hook_data_free); g_object_weak_ref (hook_data->emitter, clutter_script_remove_state_change_hook, hook_data); } signal_info_free (sinfo); } /* keep the unresolved signal handlers around, in case * clutter_script_connect_signals() is called multiple * times (e.g. after a UI definition merge) */ g_list_free (oinfo->signals); oinfo->signals = unresolved; } /** * clutter_script_connect_signals_full: * @script: a #ClutterScript * @func: (scope call): signal connection function * @user_data: data to be passed to the signal handlers, or %NULL * * Connects all the signals defined into a UI definition file to their * handlers. * * This function allows to control how the signal handlers are * going to be connected to their respective signals. It is meant * primarily for language bindings to allow resolving the function * names using the native API, but it can also be used on platforms * that do not support GModule. * * Applications should use clutter_script_connect_signals(). * * Since: 0.6 */ void clutter_script_connect_signals_full (ClutterScript *script, ClutterScriptConnectFunc func, gpointer user_data) { SignalConnectData data; g_return_if_fail (CLUTTER_IS_SCRIPT (script)); g_return_if_fail (func != NULL); data.script = script; data.func = func; data.user_data = user_data; g_hash_table_foreach (script->priv->objects, connect_each_object, &data); } GQuark clutter_script_error_quark (void) { return g_quark_from_static_string ("clutter-script-error"); } /** * clutter_script_add_search_paths: * @script: a #ClutterScript * @paths: (array length=n_paths): an array of strings containing * different search paths * @n_paths: the length of the passed array * * Adds @paths to the list of search paths held by @script. * * The search paths are used by clutter_script_lookup_filename(), which * can be used to define search paths for the textures source file name * or other custom, file-based properties. * * Since: 0.8 */ void clutter_script_add_search_paths (ClutterScript *script, const gchar * const paths[], gsize n_paths) { ClutterScriptPrivate *priv; gchar **old_paths, **new_paths; gsize old_paths_len, i; gsize iter = 0; g_return_if_fail (CLUTTER_IS_SCRIPT (script)); g_return_if_fail (paths != NULL); g_return_if_fail (n_paths > 0); priv = script->priv; if (priv->search_paths) { old_paths = priv->search_paths; old_paths_len = g_strv_length (old_paths); } else { old_paths = NULL; old_paths_len = 0; } new_paths = g_new0 (gchar*, old_paths_len + n_paths + 1); for (i = 0, iter = 0; i < old_paths_len; i++, iter++) new_paths[iter] = g_strdup (old_paths[i]); for (i = 0; i < n_paths; i++, iter++) new_paths[iter] = g_strdup (paths[i]); CLUTTER_NOTE (SCRIPT, "Added %" G_GSIZE_FORMAT " new search paths (new size: %d)", n_paths, g_strv_length (new_paths)); priv->search_paths = new_paths; if (old_paths) g_strfreev (old_paths); } /** * clutter_script_lookup_filename: * @script: a #ClutterScript * @filename: the name of the file to lookup * * Looks up @filename inside the search paths of @script. If @filename * is found, its full path will be returned . * * Return value: the full path of @filename or %NULL if no path was * found. * * Since: 0.8 */ gchar * clutter_script_lookup_filename (ClutterScript *script, const gchar *filename) { ClutterScriptPrivate *priv; gchar *dirname; gchar *retval; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL); g_return_val_if_fail (filename != NULL, NULL); if (g_path_is_absolute (filename)) return g_strdup (filename); priv = script->priv; if (priv->search_paths) { gsize paths_len, i; paths_len = g_strv_length (priv->search_paths); for (i = 0; i < paths_len; i++) { retval = g_build_filename (priv->search_paths[i], filename, NULL); if (g_file_test (retval, G_FILE_TEST_EXISTS)) return retval; else { free (retval); retval = NULL; } } } /* Fall back to assuming relative to our script */ if (priv->is_filename) dirname = g_path_get_dirname (script->priv->filename); else dirname = g_get_current_dir (); retval = g_build_filename (dirname, filename, NULL); if (!g_file_test (retval, G_FILE_TEST_EXISTS)) { free (retval); retval = NULL; } free (dirname); return retval; } /** * clutter_script_list_objects: * @script: a #ClutterScript * * Retrieves all the objects created by @script. * * Note: this function does not increment the reference count of the * objects it returns. * * Return value: (transfer container) (element-type GObject.Object): a list * of #GObjects, or %NULL. The objects are owned by the * #ClutterScript instance. Use g_list_free() on the returned list when * done. * * Since: 0.8 */ GList * clutter_script_list_objects (ClutterScript *script) { GList *objects, *l; GList *retval; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL); clutter_script_ensure_objects (script); if (!script->priv->objects) return NULL; retval = NULL; objects = g_hash_table_get_values (script->priv->objects); for (l = objects; l != NULL; l = l->next) { ObjectInfo *oinfo = l->data; if (oinfo->object) retval = g_list_prepend (retval, oinfo->object); } g_list_free (objects); return retval; } /** * clutter_script_add_states: * @script: a #ClutterScript * @name: (allow-none): a name for the @state, or %NULL to * set the default #ClutterState * @state: a #ClutterState * * Associates a #ClutterState to the #ClutterScript instance using the given * name. * * The #ClutterScript instance will use @state to resolve target states when * connecting signal handlers. * * The #ClutterScript instance will take a reference on the #ClutterState * passed to this function. * * Since: 1.8 * * Deprecated: 1.12 */ void clutter_script_add_states (ClutterScript *script, const gchar *name, ClutterState *state) { g_return_if_fail (CLUTTER_IS_SCRIPT (script)); g_return_if_fail (CLUTTER_IS_STATE (state)); if (name == NULL || *name == '\0') name = "__clutter_script_default_state"; g_hash_table_replace (script->priv->states, g_strdup (name), g_object_ref (state)); } /** * clutter_script_get_states: * @script: a #ClutterScript * @name: (allow-none): the name of the #ClutterState, or %NULL * * Retrieves the #ClutterState for the given @state_name. * * If @name is %NULL, this function will return the default * #ClutterState instance. * * Return value: (transfer none): a pointer to the #ClutterState for the * given name. The #ClutterState is owned by the #ClutterScript instance * and it should not be unreferenced * * Since: 1.8 * * Deprecated: 1.12 */ ClutterState * clutter_script_get_states (ClutterScript *script, const gchar *name) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL); if (name == NULL || *name == '\0') name = "__clutter_script_default_state"; return g_hash_table_lookup (script->priv->states, name); } /** * clutter_script_set_translation_domain: * @script: a #ClutterScript * @domain: (allow-none): the translation domain, or %NULL * * Sets the translation domain for @script. * * Since: 1.10 */ void clutter_script_set_translation_domain (ClutterScript *script, const gchar *domain) { g_return_if_fail (CLUTTER_IS_SCRIPT (script)); if (g_strcmp0 (domain, script->priv->translation_domain) == 0) return; free (script->priv->translation_domain); script->priv->translation_domain = g_strdup (domain); g_object_notify_by_pspec (G_OBJECT (script), obj_props[PROP_TRANSLATION_DOMAIN]); } /** * clutter_script_get_translation_domain: * @script: a #ClutterScript * * Retrieves the translation domain set using * clutter_script_set_translation_domain(). * * Return value: (transfer none): the translation domain, if any is set, * or %NULL * * Since: 1.10 */ const gchar * clutter_script_get_translation_domain (ClutterScript *script) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL); return script->priv->translation_domain; } /* * _clutter_script_generate_fake_id: * @script: a #ClutterScript * * Generates a fake id string for object definitions without * an "id" member * * Return value: a newly-allocated string containing the fake * id. Use free() to free the resources allocated by the * returned value * */ gchar * _clutter_script_generate_fake_id (ClutterScript *script) { ClutterScriptPrivate *priv = script->priv; return g_strdup_printf ("script-%d-%d", priv->last_merge_id, priv->last_unknown++); } /* * _clutter_script_warn_missing_attribute: * @script: a #ClutterScript * @id_: the id of an object definition, or %NULL * @attribute: the expected attribute * * Emits a warning, using GLib's log facilities, for a missing * @attribute in an object definition, pointing to the current * location of the #ClutterScriptParser */ void _clutter_script_warn_missing_attribute (ClutterScript *script, const gchar *id_, const gchar *attribute) { ClutterScriptPrivate *priv = script->priv; JsonParser *parser = JSON_PARSER (priv->parser); gint current_line = json_parser_get_current_line (parser); if (id_ != NULL && *id_ != '\0') { g_warning ("%s:%d: object '%s' has no '%s' attribute", priv->is_filename ? priv->filename : "", current_line, id_, attribute); } else { g_warning ("%s:%d: object has no '%s' attribute", priv->is_filename ? priv->filename : "", current_line, attribute); } } /* * _clutter_script_warn_invalid_value: * @script: a #ClutterScript * @attribute: the attribute with the invalid value * @expected: a string with the expected value * @node: a #JsonNode containing the value * * Emits a warning, using GLib's log facilities, for an invalid * value found when parsing @attribute, pointing to the current * location of the #ClutterScriptParser */ void _clutter_script_warn_invalid_value (ClutterScript *script, const gchar *attribute, const gchar *expected, JsonNode *node) { ClutterScriptPrivate *priv = script->priv; JsonParser *parser = JSON_PARSER (priv->parser); gint current_line = json_parser_get_current_line (parser); if (node != NULL) { g_warning ("%s:%d: invalid value of type '%s' for attribute '%s':" "a value of type '%s' is expected", priv->is_filename ? priv->filename : "", current_line, json_node_type_name (node), attribute, expected); } else { g_warning ("%s:%d: invalid value for attribute '%s':" "a value of type '%s' is expected", priv->is_filename ? priv->filename : "", current_line, attribute, expected); } } /* * _clutter_script_get_object_info: * @script: a #ClutterScript * @script_id: the id of the object definition * * Retrieves the #ObjectInfo for the given @script_id * * Return value: a #ObjectInfo or %NULL */ ObjectInfo * _clutter_script_get_object_info (ClutterScript *script, const gchar *script_id) { ClutterScriptPrivate *priv = script->priv; return g_hash_table_lookup (priv->objects, script_id); } /* * _clutter_script_get_last_merge_id: * @script: a #ClutterScript * * Retrieves the last merge id of @script. The merge id * should be stored inside an #ObjectInfo. If you need * a unique fake id for object definitions with an "id" * member, consider using _clutter_script_generate_fake_id() * instead * * Return value: the last merge id */ guint _clutter_script_get_last_merge_id (ClutterScript *script) { return script->priv->last_merge_id; } /* * _clutter_script_add_object_info: * @script: a #ClutterScript * @oinfo: a #ObjectInfo * * Adds @oinfo inside the objects list held by @script */ void _clutter_script_add_object_info (ClutterScript *script, ObjectInfo *oinfo) { ClutterScriptPrivate *priv = script->priv; g_hash_table_steal (priv->objects, oinfo->id); g_hash_table_insert (priv->objects, oinfo->id, oinfo); } muffin-5.2.1/clutter/clutter/clutter-group.h0000664000175000017500000000566414211404421021300 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ #ifndef __CLUTTER_GROUP_H__ #define __CLUTTER_GROUP_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_GROUP (clutter_group_get_type ()) #define CLUTTER_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_GROUP, ClutterGroup)) #define CLUTTER_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_GROUP, ClutterGroupClass)) #define CLUTTER_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_GROUP)) #define CLUTTER_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_GROUP)) #define CLUTTER_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_GROUP, ClutterGroupClass)) /* XXX - ClutterGroup is to be considered fully deprecated; the only * reason we keep this header is because ClutterStage inherits from * ClutterGroup, and thus we need to have a structure definition for * the Stage object to expand. */ typedef struct _ClutterGroup ClutterGroup; typedef struct _ClutterGroupClass ClutterGroupClass; typedef struct _ClutterGroupPrivate ClutterGroupPrivate; /** * ClutterGroup: * * The #ClutterGroup structure contains only private data * and should be accessed using the provided API * * Since: 0.2 */ struct _ClutterGroup { /*< private >*/ ClutterActor parent_instance; ClutterGroupPrivate *priv; }; /** * ClutterGroupClass: * * The #ClutterGroupClass structure contains only private data * * Since: 0.2 */ struct _ClutterGroupClass { /*< private >*/ ClutterActorClass parent_class; /* padding for future expansion */ void (*_clutter_reserved1) (void); void (*_clutter_reserved2) (void); void (*_clutter_reserved3) (void); void (*_clutter_reserved4) (void); void (*_clutter_reserved5) (void); void (*_clutter_reserved6) (void); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_group_get_type (void) G_GNUC_CONST; G_END_DECLS #endif /* __CLUTTER_GROUP_H__ */ muffin-5.2.1/clutter/clutter/clutter-bind-constraint.h0000664000175000017500000000620114211404421023226 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_BIND_CONSTRAINT_H__ #define __CLUTTER_BIND_CONSTRAINT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_BIND_CONSTRAINT (clutter_bind_constraint_get_type ()) #define CLUTTER_BIND_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraint)) #define CLUTTER_IS_BIND_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIND_CONSTRAINT)) /** * ClutterBindConstraint: * * #ClutterBindConstraint is an opaque structure * whose members cannot be directly accessed * * Since: 1.4 */ typedef struct _ClutterBindConstraint ClutterBindConstraint; typedef struct _ClutterBindConstraintClass ClutterBindConstraintClass; CLUTTER_AVAILABLE_IN_1_4 GType clutter_bind_constraint_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterConstraint * clutter_bind_constraint_new (ClutterActor *source, ClutterBindCoordinate coordinate, gfloat offset); CLUTTER_AVAILABLE_IN_1_4 void clutter_bind_constraint_set_source (ClutterBindConstraint *constraint, ClutterActor *source); CLUTTER_AVAILABLE_IN_1_4 ClutterActor * clutter_bind_constraint_get_source (ClutterBindConstraint *constraint); CLUTTER_AVAILABLE_IN_1_4 void clutter_bind_constraint_set_coordinate (ClutterBindConstraint *constraint, ClutterBindCoordinate coordinate); CLUTTER_AVAILABLE_IN_1_4 ClutterBindCoordinate clutter_bind_constraint_get_coordinate (ClutterBindConstraint *constraint); CLUTTER_AVAILABLE_IN_1_4 void clutter_bind_constraint_set_offset (ClutterBindConstraint *constraint, gfloat offset); CLUTTER_AVAILABLE_IN_1_4 gfloat clutter_bind_constraint_get_offset (ClutterBindConstraint *constraint); G_END_DECLS #endif /* __CLUTTER_BIND_CONSTRAINT_H__ */ muffin-5.2.1/clutter/clutter/clutter-bin-layout.c0000664000175000017500000006167414211404421022225 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-bin-layout * @short_description: A simple layout manager * * #ClutterBinLayout is a layout manager which implements the following * policy: * * - the preferred size is the maximum preferred size * between all the children of the container using the * layout; * - each child is allocated in "layers", on on top * of the other; * - for each layer there are horizontal and vertical * alignment policies. * * The [bin-layout example](https://git.gnome.org/browse/clutter/tree/examples/bin-layout.c?h=clutter-1.18) * shows how to pack actors inside a #ClutterBinLayout. * * #ClutterBinLayout is available since Clutter 1.2 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "deprecated/clutter-bin-layout.h" #include "clutter-actor-private.h" #include "clutter-animatable.h" #include "clutter-child-meta.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-layout-meta.h" #include "clutter-private.h" #define CLUTTER_TYPE_BIN_LAYER (clutter_bin_layer_get_type ()) #define CLUTTER_BIN_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYER, ClutterBinLayer)) #define CLUTTER_IS_BIN_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYER)) typedef struct _ClutterBinLayer ClutterBinLayer; typedef struct _ClutterLayoutMetaClass ClutterBinLayerClass; struct _ClutterBinLayoutPrivate { ClutterBinAlignment x_align; ClutterBinAlignment y_align; ClutterContainer *container; }; struct _ClutterBinLayer { ClutterLayoutMeta parent_instance; ClutterBinAlignment x_align; ClutterBinAlignment y_align; }; enum { PROP_LAYER_0, PROP_LAYER_X_ALIGN, PROP_LAYER_Y_ALIGN, PROP_LAYER_LAST }; enum { PROP_0, PROP_X_ALIGN, PROP_Y_ALIGN, PROP_LAST }; static GParamSpec *layer_props[PROP_LAYER_LAST] = { NULL, }; static GParamSpec *bin_props[PROP_LAST] = { NULL, }; GType clutter_bin_layer_get_type (void); G_DEFINE_TYPE (ClutterBinLayer, clutter_bin_layer, CLUTTER_TYPE_LAYOUT_META) G_DEFINE_TYPE_WITH_PRIVATE (ClutterBinLayout, clutter_bin_layout, CLUTTER_TYPE_LAYOUT_MANAGER) /* * ClutterBinLayer */ static void set_layer_x_align (ClutterBinLayer *self, ClutterBinAlignment alignment) { ClutterLayoutManager *manager; ClutterLayoutMeta *meta; if (self->x_align == alignment) return; self->x_align = alignment; meta = CLUTTER_LAYOUT_META (self); manager = clutter_layout_meta_get_manager (meta); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (self), layer_props[PROP_LAYER_X_ALIGN]); } static void set_layer_y_align (ClutterBinLayer *self, ClutterBinAlignment alignment) { ClutterLayoutManager *manager; ClutterLayoutMeta *meta; if (self->y_align == alignment) return; self->y_align = alignment; meta = CLUTTER_LAYOUT_META (self); manager = clutter_layout_meta_get_manager (meta); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (self), layer_props[PROP_LAYER_Y_ALIGN]); } static void clutter_bin_layer_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject); switch (prop_id) { case PROP_LAYER_X_ALIGN: set_layer_x_align (layer, g_value_get_enum (value)); break; case PROP_LAYER_Y_ALIGN: set_layer_y_align (layer, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_bin_layer_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject); switch (prop_id) { case PROP_LAYER_X_ALIGN: g_value_set_enum (value, layer->x_align); break; case PROP_LAYER_Y_ALIGN: g_value_set_enum (value, layer->y_align); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_bin_layer_class_init (ClutterBinLayerClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_bin_layer_set_property; gobject_class->get_property = clutter_bin_layer_get_property; layer_props[PROP_LAYER_X_ALIGN] = g_param_spec_enum ("x-align", P_("Horizontal Alignment"), P_("Horizontal alignment for the actor " "inside the layout manager"), CLUTTER_TYPE_BIN_ALIGNMENT, CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); layer_props[PROP_LAYER_Y_ALIGN] = g_param_spec_enum ("y-align", P_("Vertical Alignment"), P_("Vertical alignment for the actor " "inside the layout manager"), CLUTTER_TYPE_BIN_ALIGNMENT, CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_LAYER_LAST, layer_props); } static void clutter_bin_layer_init (ClutterBinLayer *layer) { layer->x_align = CLUTTER_BIN_ALIGNMENT_CENTER; layer->y_align = CLUTTER_BIN_ALIGNMENT_CENTER; } /* * ClutterBinLayout */ static void set_x_align (ClutterBinLayout *self, ClutterBinAlignment alignment) { ClutterBinLayoutPrivate *priv = self->priv; if (priv->x_align != alignment) { ClutterLayoutManager *manager; priv->x_align = alignment; manager = CLUTTER_LAYOUT_MANAGER (self); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (self), bin_props[PROP_X_ALIGN]); } } static void set_y_align (ClutterBinLayout *self, ClutterBinAlignment alignment) { ClutterBinLayoutPrivate *priv = self->priv; if (priv->y_align != alignment) { ClutterLayoutManager *manager; priv->y_align = alignment; manager = CLUTTER_LAYOUT_MANAGER (self); clutter_layout_manager_layout_changed (manager); g_object_notify_by_pspec (G_OBJECT (self), bin_props[PROP_Y_ALIGN]); } } static void clutter_bin_layout_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { ClutterActor *actor = CLUTTER_ACTOR (container); ClutterActorIter iter; ClutterActor *child; gfloat min_width, nat_width; min_width = nat_width = 0.0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { gfloat minimum, natural; if (!clutter_actor_is_visible (child)) continue; clutter_actor_get_preferred_width (child, for_height, &minimum, &natural); min_width = MAX (min_width, minimum); nat_width = MAX (nat_width, natural); } if (min_width_p) *min_width_p = min_width; if (nat_width_p) *nat_width_p = nat_width; } static void clutter_bin_layout_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { ClutterActor *actor = CLUTTER_ACTOR (container); ClutterActorIter iter; ClutterActor *child; gfloat min_height, nat_height; min_height = nat_height = 0.0; clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { gfloat minimum, natural; if (!clutter_actor_is_visible (child)) continue; clutter_actor_get_preferred_height (child, for_width, &minimum, &natural); min_height = MAX (min_height, minimum); nat_height = MAX (nat_height, natural); } if (min_height_p) *min_height_p = min_height; if (nat_height_p) *nat_height_p = nat_height; } static gdouble get_bin_alignment_factor (ClutterBinAlignment alignment, ClutterTextDirection text_dir) { switch (alignment) { case CLUTTER_BIN_ALIGNMENT_CENTER: return 0.5; case CLUTTER_BIN_ALIGNMENT_START: return text_dir == CLUTTER_TEXT_DIRECTION_LTR ? 0.0 : 1.0; case CLUTTER_BIN_ALIGNMENT_END: return text_dir == CLUTTER_TEXT_DIRECTION_LTR ? 1.0 : 0.0; case CLUTTER_BIN_ALIGNMENT_FIXED: case CLUTTER_BIN_ALIGNMENT_FILL: return 0.0; } return 0.0; } static gdouble get_actor_align_factor (ClutterActorAlign alignment) { switch (alignment) { case CLUTTER_ACTOR_ALIGN_CENTER: return 0.5; case CLUTTER_ACTOR_ALIGN_START: return 0.0; case CLUTTER_ACTOR_ALIGN_END: return 1.0; case CLUTTER_ACTOR_ALIGN_FILL: return 0.0; } return 0.0; } static void clutter_bin_layout_allocate (ClutterLayoutManager *manager, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { gfloat allocation_x, allocation_y; gfloat available_w, available_h; ClutterActor *actor, *child; ClutterActorIter iter; clutter_actor_box_get_origin (allocation, &allocation_x, &allocation_y); clutter_actor_box_get_size (allocation, &available_w, &available_h); actor = CLUTTER_ACTOR (container); clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, &child)) { ClutterLayoutMeta *meta; ClutterBinLayer *layer; ClutterActorBox child_alloc = { 0, }; gdouble x_align, y_align; gboolean x_fill, y_fill, is_fixed_position_set; float fixed_x, fixed_y; if (!clutter_actor_is_visible (child)) continue; meta = clutter_layout_manager_get_child_meta (manager, container, child); layer = CLUTTER_BIN_LAYER (meta); fixed_x = fixed_y = 0.f; g_object_get (child, "fixed-position-set", &is_fixed_position_set, "fixed-x", &fixed_x, "fixed-y", &fixed_y, NULL); /* XXX:2.0 - remove the FIXED alignment, and just use the fixed position * of the actor if one is set */ if (is_fixed_position_set || layer->x_align == CLUTTER_BIN_ALIGNMENT_FIXED) { if (is_fixed_position_set) child_alloc.x1 = fixed_x; else child_alloc.x1 = clutter_actor_get_x (child); } else child_alloc.x1 = allocation_x; if (is_fixed_position_set || layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED) { if (is_fixed_position_set) child_alloc.y1 = fixed_y; else child_alloc.y1 = clutter_actor_get_y (child); } else child_alloc.y1 = allocation_y; child_alloc.x2 = allocation_x + available_w; child_alloc.y2 = allocation_y + available_h; if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL)) { ClutterActorAlign align; align = clutter_actor_get_x_align (child); x_fill = align == CLUTTER_ACTOR_ALIGN_FILL; x_align = get_actor_align_factor (align); } else { ClutterTextDirection text_dir; x_fill = (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL); text_dir = clutter_actor_get_text_direction (child); if (!is_fixed_position_set) x_align = get_bin_alignment_factor (layer->x_align, text_dir); else x_align = 0.0; } if (clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL)) { ClutterActorAlign align; align = clutter_actor_get_y_align (child); y_fill = align == CLUTTER_ACTOR_ALIGN_FILL; y_align = get_actor_align_factor (align); } else { y_fill = (layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL); if (!is_fixed_position_set) y_align = get_bin_alignment_factor (layer->y_align, CLUTTER_TEXT_DIRECTION_LTR); else y_align = 0.0; } clutter_actor_allocate_align_fill (child, &child_alloc, x_align, y_align, x_fill, y_fill, flags); } } static GType clutter_bin_layout_get_child_meta_type (ClutterLayoutManager *manager) { return CLUTTER_TYPE_BIN_LAYER; } static ClutterLayoutMeta * clutter_bin_layout_create_child_meta (ClutterLayoutManager *manager, ClutterContainer *container, ClutterActor *actor) { ClutterBinLayoutPrivate *priv; priv = CLUTTER_BIN_LAYOUT (manager)->priv; return g_object_new (CLUTTER_TYPE_BIN_LAYER, "container", container, "actor", actor, "manager", manager, "x-align", priv->x_align, "y_align", priv->y_align, NULL); } static void clutter_bin_layout_set_container (ClutterLayoutManager *manager, ClutterContainer *container) { ClutterBinLayoutPrivate *priv; ClutterLayoutManagerClass *parent_class; priv = CLUTTER_BIN_LAYOUT (manager)->priv; priv->container = container; parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_bin_layout_parent_class); parent_class->set_container (manager, container); } static void clutter_bin_layout_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterBinLayout *layout = CLUTTER_BIN_LAYOUT (gobject); switch (prop_id) { case PROP_X_ALIGN: set_x_align (layout, g_value_get_enum (value)); break; case PROP_Y_ALIGN: set_y_align (layout, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_bin_layout_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterBinLayoutPrivate *priv; priv = CLUTTER_BIN_LAYOUT (gobject)->priv; switch (prop_id) { case PROP_X_ALIGN: g_value_set_enum (value, priv->x_align); break; case PROP_Y_ALIGN: g_value_set_enum (value, priv->y_align); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_bin_layout_class_init (ClutterBinLayoutClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterLayoutManagerClass *layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass); /** * ClutterBinLayout:x-align: * * The default horizontal alignment policy for actors managed * by the #ClutterBinLayout * * Since: 1.2 * * Deprecated: 1.12: Use the #ClutterActor:x-expand and the * #ClutterActor:x-align properties on #ClutterActor instead. */ bin_props[PROP_X_ALIGN] = g_param_spec_enum ("x-align", P_("Horizontal Alignment"), P_("Default horizontal alignment for the actors " "inside the layout manager"), CLUTTER_TYPE_BIN_ALIGNMENT, CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); /** * ClutterBinLayout:y-align: * * The default vertical alignment policy for actors managed * by the #ClutterBinLayout * * Since: 1.2 * * Deprecated: 1.12: Use the #ClutterActor:y-expand and the * #ClutterActor:y-align properties on #ClutterActor instead. */ bin_props[PROP_Y_ALIGN] = g_param_spec_enum ("y-align", P_("Vertical Alignment"), P_("Default vertical alignment for the actors " "inside the layout manager"), CLUTTER_TYPE_BIN_ALIGNMENT, CLUTTER_BIN_ALIGNMENT_CENTER, CLUTTER_PARAM_READWRITE); gobject_class->set_property = clutter_bin_layout_set_property; gobject_class->get_property = clutter_bin_layout_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, bin_props); layout_class->get_preferred_width = clutter_bin_layout_get_preferred_width; layout_class->get_preferred_height = clutter_bin_layout_get_preferred_height; layout_class->allocate = clutter_bin_layout_allocate; layout_class->create_child_meta = clutter_bin_layout_create_child_meta; layout_class->get_child_meta_type = clutter_bin_layout_get_child_meta_type; layout_class->set_container = clutter_bin_layout_set_container; } static void clutter_bin_layout_init (ClutterBinLayout *self) { self->priv = clutter_bin_layout_get_instance_private (self); self->priv->x_align = CLUTTER_BIN_ALIGNMENT_CENTER; self->priv->y_align = CLUTTER_BIN_ALIGNMENT_CENTER; } /** * clutter_bin_layout_new: * @x_align: the default alignment policy to be used on the * horizontal axis * @y_align: the default alignment policy to be used on the * vertical axis * * Creates a new #ClutterBinLayout layout manager * * Return value: the newly created layout manager * * Since: 1.2 */ ClutterLayoutManager * clutter_bin_layout_new (ClutterBinAlignment x_align, ClutterBinAlignment y_align) { return g_object_new (CLUTTER_TYPE_BIN_LAYOUT, "x-align", x_align, "y-align", y_align, NULL); } /** * clutter_bin_layout_set_alignment: * @self: a #ClutterBinLayout * @child: (allow-none): a child of @container * @x_align: the horizontal alignment policy to be used for the @child * inside @container * @y_align: the vertical aligment policy to be used on the @child * inside @container * * Sets the horizontal and vertical alignment policies to be applied * to a @child of @self * * If @child is %NULL then the @x_align and @y_align values will * be set as the default alignment policies * * Since: 1.2 * * Deprecated: 1.12: Use the #ClutterActor:x-align and * #ClutterActor:y-align properties of #ClutterActor instead. */ void clutter_bin_layout_set_alignment (ClutterBinLayout *self, ClutterActor *child, ClutterBinAlignment x_align, ClutterBinAlignment y_align) { ClutterBinLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self)); g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child)); priv = self->priv; if (priv->container == NULL) { if (child == NULL) { set_x_align (self, x_align); set_y_align (self, y_align); } else g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before setting the alignment " "on its children", G_OBJECT_TYPE_NAME (self)); return; } manager = CLUTTER_LAYOUT_MANAGER (self); meta = clutter_layout_manager_get_child_meta (manager, priv->container, child); g_assert (CLUTTER_IS_BIN_LAYER (meta)); set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align); set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align); } /** * clutter_bin_layout_get_alignment: * @self: a #ClutterBinLayout * @child: (allow-none): a child of @container * @x_align: (out) (allow-none): return location for the horizontal * alignment policy * @y_align: (out) (allow-none): return location for the vertical * alignment policy * * Retrieves the horizontal and vertical alignment policies for * a child of @self * * If @child is %NULL the default alignment policies will be returned * instead * * Since: 1.2 * * Deprecated: 1.12: Use the #ClutterActor:x-align and the * #ClutterActor:y-align properties of #ClutterActor instead. */ void clutter_bin_layout_get_alignment (ClutterBinLayout *self, ClutterActor *child, ClutterBinAlignment *x_align, ClutterBinAlignment *y_align) { ClutterBinLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; ClutterBinLayer *layer; g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self)); priv = self->priv; if (priv->container == NULL) { if (child == NULL) { if (x_align) *x_align = priv->x_align; if (y_align) *y_align = priv->y_align; } else g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before getting the alignment " "of its children", G_OBJECT_TYPE_NAME (self)); return; } manager = CLUTTER_LAYOUT_MANAGER (self); meta = clutter_layout_manager_get_child_meta (manager, priv->container, child); g_assert (CLUTTER_IS_BIN_LAYER (meta)); layer = CLUTTER_BIN_LAYER (meta); if (x_align) *x_align = layer->x_align; if (y_align) *y_align = layer->y_align; } /** * clutter_bin_layout_add: * @self: a #ClutterBinLayout * @child: a #ClutterActor * @x_align: horizontal alignment policy for @child * @y_align: vertical alignment policy for @child * * Adds a #ClutterActor to the container using @self and * sets the alignment policies for it * * This function is equivalent to clutter_container_add_actor() * and clutter_layout_manager_child_set_property() but it does not * require a pointer to the #ClutterContainer associated to the * #ClutterBinLayout * * Since: 1.2 * * Deprecated: 1.12: Use clutter_actor_add_child() instead. */ void clutter_bin_layout_add (ClutterBinLayout *self, ClutterActor *child, ClutterBinAlignment x_align, ClutterBinAlignment y_align) { ClutterBinLayoutPrivate *priv; ClutterLayoutManager *manager; ClutterLayoutMeta *meta; g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); priv = self->priv; if (priv->container == NULL) { g_warning ("The layout of type '%s' must be associated to " "a ClutterContainer before adding children", G_OBJECT_TYPE_NAME (self)); return; } clutter_container_add_actor (priv->container, child); manager = CLUTTER_LAYOUT_MANAGER (self); meta = clutter_layout_manager_get_child_meta (manager, priv->container, child); g_assert (CLUTTER_IS_BIN_LAYER (meta)); set_layer_x_align (CLUTTER_BIN_LAYER (meta), x_align); set_layer_y_align (CLUTTER_BIN_LAYER (meta), y_align); } muffin-5.2.1/clutter/clutter/clutter-color.c0000664000175000017500000007351414211404421021254 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ /** * SECTION:clutter-color * @short_description: Color management and manipulation. * * #ClutterColor is a simple type for representing colors in Clutter. * * A #ClutterColor is expressed as a 4-tuple of values ranging from * zero to 255, one for each color channel plus one for the alpha. * * The alpha channel is fully opaque at 255 and fully transparent at 0. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include "clutter-interval.h" #include "clutter-main.h" #include "clutter-color.h" #include "clutter-private.h" #include "clutter-debug.h" /* XXX - keep in sync with the ClutterStaticColor enumeration order */ static const ClutterColor static_colors[] = { /* CGA/EGA color palette */ { 0xff, 0xff, 0xff, 0xff }, /* white */ { 0x00, 0x00, 0x00, 0xff }, /* black */ { 0xff, 0x00, 0x00, 0xff }, /* red */ { 0x80, 0x00, 0x00, 0xff }, /* dark red */ { 0x00, 0xff, 0x00, 0xff }, /* green */ { 0x00, 0x80, 0x00, 0xff }, /* dark green */ { 0x00, 0x00, 0xff, 0xff }, /* blue */ { 0x00, 0x00, 0x80, 0xff }, /* dark blue */ { 0x00, 0xff, 0xff, 0xff }, /* cyan */ { 0x00, 0x80, 0x80, 0xff }, /* dark cyan */ { 0xff, 0x00, 0xff, 0xff }, /* magenta */ { 0x80, 0x00, 0x80, 0xff }, /* dark magenta */ { 0xff, 0xff, 0x00, 0xff }, /* yellow */ { 0x80, 0x80, 0x00, 0xff }, /* dark yellow */ { 0xa0, 0xa0, 0xa4, 0xff }, /* gray */ { 0x80, 0x80, 0x80, 0xff }, /* dark gray */ { 0xc0, 0xc0, 0xc0, 0xff }, /* light gray */ /* Tango Icon color palette */ { 0xed, 0xd4, 0x00, 0xff }, /* butter */ { 0xfc, 0xe9, 0x4f, 0xff }, /* butter light */ { 0xc4, 0xa0, 0x00, 0xff }, /* butter dark */ { 0xf5, 0x79, 0x00, 0xff }, /* orange */ { 0xfc, 0xaf, 0x3e, 0xff }, /* orange light */ { 0xce, 0x5c, 0x00, 0xff }, /* orange dark */ { 0xc1, 0x7d, 0x11, 0xff }, /* chocolate */ { 0xe9, 0xb9, 0x6e, 0xff }, /* chocolate light */ { 0x8f, 0x59, 0x02, 0xff }, /* chocolate dark */ { 0x73, 0xd2, 0x16, 0xff }, /* chameleon */ { 0x8a, 0xe2, 0x34, 0xff }, /* chameleon light */ { 0x4e, 0x9a, 0x06, 0xff }, /* chameleon dark */ { 0x34, 0x65, 0xa4, 0xff }, /* sky blue */ { 0x72, 0x9f, 0xcf, 0xff }, /* sky blue light */ { 0x20, 0x4a, 0x87, 0xff }, /* sky blue dark */ { 0x75, 0x50, 0x7b, 0xff }, /* plum */ { 0xad, 0x7f, 0xa8, 0xff }, /* plum light */ { 0x5c, 0x35, 0x66, 0xff }, /* plum dark */ { 0xcc, 0x00, 0x00, 0xff }, /* scarlet red */ { 0xef, 0x29, 0x29, 0xff }, /* scarlet red light */ { 0xa4, 0x00, 0x00, 0xff }, /* scarlet red dark */ { 0xee, 0xee, 0xec, 0xff }, /* aluminium 1 */ { 0xd3, 0xd7, 0xcf, 0xff }, /* aluminium 2 */ { 0xba, 0xbd, 0xb6, 0xff }, /* aluminium 3 */ { 0x88, 0x8a, 0x85, 0xff }, /* aluminium 4 */ { 0x55, 0x57, 0x53, 0xff }, /* aluminium 5 */ { 0x2e, 0x34, 0x36, 0xff }, /* aluminium 6 */ /* last color */ { 0x00, 0x00, 0x00, 0x00 } /* transparent */ }; /** * clutter_color_get_static: * @color: the named global color * * Retrieves a static color for the given @color name * * Static colors are created by Clutter and are guaranteed to always be * available and valid * * Return value: a pointer to a static color; the returned pointer * is owned by Clutter and it should never be modified or freed * * Since: 1.6 */ const ClutterColor * clutter_color_get_static (ClutterStaticColor color) { g_return_val_if_fail (color >= CLUTTER_COLOR_WHITE && color <= CLUTTER_COLOR_TRANSPARENT, NULL); return &static_colors[color]; } /** * clutter_color_add: * @a: a #ClutterColor * @b: a #ClutterColor * @result: (out caller-allocates): return location for the result * * Adds @a to @b and saves the resulting color inside @result. * * The alpha channel of @result is set as as the maximum value * between the alpha channels of @a and @b. */ void clutter_color_add (const ClutterColor *a, const ClutterColor *b, ClutterColor *result) { g_return_if_fail (a != NULL); g_return_if_fail (b != NULL); g_return_if_fail (result != NULL); result->red = CLAMP (a->red + b->red, 0, 255); result->green = CLAMP (a->green + b->green, 0, 255); result->blue = CLAMP (a->blue + b->blue, 0, 255); result->alpha = MAX (a->alpha, b->alpha); } /** * clutter_color_subtract: * @a: a #ClutterColor * @b: a #ClutterColor * @result: (out caller-allocates): return location for the result * * Subtracts @b from @a and saves the resulting color inside @result. * * This function assumes that the components of @a are greater than the * components of @b; the result is, otherwise, undefined. * * The alpha channel of @result is set as the minimum value * between the alpha channels of @a and @b. */ void clutter_color_subtract (const ClutterColor *a, const ClutterColor *b, ClutterColor *result) { g_return_if_fail (a != NULL); g_return_if_fail (b != NULL); g_return_if_fail (result != NULL); result->red = CLAMP (a->red - b->red, 0, 255); result->green = CLAMP (a->green - b->green, 0, 255); result->blue = CLAMP (a->blue - b->blue, 0, 255); result->alpha = MIN (a->alpha, b->alpha); } /** * clutter_color_lighten: * @color: a #ClutterColor * @result: (out caller-allocates): return location for the lighter color * * Lightens @color by a fixed amount, and saves the changed color * in @result. */ void clutter_color_lighten (const ClutterColor *color, ClutterColor *result) { clutter_color_shade (color, 1.3, result); } /** * clutter_color_darken: * @color: a #ClutterColor * @result: (out caller-allocates): return location for the darker color * * Darkens @color by a fixed amount, and saves the changed color * in @result. */ void clutter_color_darken (const ClutterColor *color, ClutterColor *result) { clutter_color_shade (color, 0.7, result); } /** * clutter_color_to_hls: * @color: a #ClutterColor * @hue: (out): return location for the hue value or %NULL * @luminance: (out): return location for the luminance value or %NULL * @saturation: (out): return location for the saturation value or %NULL * * Converts @color to the HLS format. * * The @hue value is in the 0 .. 360 range. The @luminance and * @saturation values are in the 0 .. 1 range. */ void clutter_color_to_hls (const ClutterColor *color, float *hue, float *luminance, float *saturation) { float red, green, blue; float min, max, delta; float h, l, s; g_return_if_fail (color != NULL); red = color->red / 255.0; green = color->green / 255.0; blue = color->blue / 255.0; if (red > green) { if (red > blue) max = red; else max = blue; if (green < blue) min = green; else min = blue; } else { if (green > blue) max = green; else max = blue; if (red < blue) min = red; else min = blue; } l = (max + min) / 2; s = 0; h = 0; if (max != min) { if (l <= 0.5) s = (max - min) / (max + min); else s = (max - min) / (2.0 - max - min); delta = max - min; if (red == max) h = (green - blue) / delta; else if (green == max) h = 2.0 + (blue - red) / delta; else if (blue == max) h = 4.0 + (red - green) / delta; h *= 60; if (h < 0) h += 360.0; } if (hue) *hue = h; if (luminance) *luminance = l; if (saturation) *saturation = s; } /** * clutter_color_from_hls: * @color: (out): return location for a #ClutterColor * @hue: hue value, in the 0 .. 360 range * @luminance: luminance value, in the 0 .. 1 range * @saturation: saturation value, in the 0 .. 1 range * * Converts a color expressed in HLS (hue, luminance and saturation) * values into a #ClutterColor. */ void clutter_color_from_hls (ClutterColor *color, float hue, float luminance, float saturation) { float tmp1, tmp2; float tmp3[3]; float clr[3]; int i; hue /= 360.0; if (saturation == 0) { color->red = color->green = color->blue = (luminance * 255); return; } if (luminance <= 0.5) tmp2 = luminance * (1.0 + saturation); else tmp2 = luminance + saturation - (luminance * saturation); tmp1 = 2.0 * luminance - tmp2; tmp3[0] = hue + 1.0 / 3.0; tmp3[1] = hue; tmp3[2] = hue - 1.0 / 3.0; for (i = 0; i < 3; i++) { if (tmp3[i] < 0) tmp3[i] += 1.0; if (tmp3[i] > 1) tmp3[i] -= 1.0; if (6.0 * tmp3[i] < 1.0) clr[i] = tmp1 + (tmp2 - tmp1) * tmp3[i] * 6.0; else if (2.0 * tmp3[i] < 1.0) clr[i] = tmp2; else if (3.0 * tmp3[i] < 2.0) clr[i] = (tmp1 + (tmp2 - tmp1) * ((2.0 / 3.0) - tmp3[i]) * 6.0); else clr[i] = tmp1; } color->red = floorf (clr[0] * 255.0 + 0.5); color->green = floorf (clr[1] * 255.0 + 0.5); color->blue = floorf (clr[2] * 255.0 + 0.5); } /** * clutter_color_shade: * @color: a #ClutterColor * @factor: the shade factor to apply * @result: (out caller-allocates): return location for the shaded color * * Shades @color by @factor and saves the modified color into @result. */ void clutter_color_shade (const ClutterColor *color, gdouble factor, ClutterColor *result) { float h, l, s; g_return_if_fail (color != NULL); g_return_if_fail (result != NULL); clutter_color_to_hls (color, &h, &l, &s); l = CLAMP (l * factor, 0.0, 1.0); s = CLAMP (s * factor, 0.0, 1.0); clutter_color_from_hls (result, h, l, s); result->alpha = color->alpha; } /** * clutter_color_to_pixel: * @color: a #ClutterColor * * Converts @color into a packed 32 bit integer, containing * all the four 8 bit channels used by #ClutterColor. * * Return value: a packed color */ guint32 clutter_color_to_pixel (const ClutterColor *color) { g_return_val_if_fail (color != NULL, 0); return (color->alpha | color->blue << 8 | color->green << 16 | color->red << 24); } /** * clutter_color_from_pixel: * @color: (out caller-allocates): return location for a #ClutterColor * @pixel: a 32 bit packed integer containing a color * * Converts @pixel from the packed representation of a four 8 bit channel * color to a #ClutterColor. */ void clutter_color_from_pixel (ClutterColor *color, guint32 pixel) { g_return_if_fail (color != NULL); color->red = pixel >> 24; color->green = (pixel >> 16) & 0xff; color->blue = (pixel >> 8) & 0xff; color->alpha = pixel & 0xff; } static inline void skip_whitespace (gchar **str) { while (g_ascii_isspace (**str)) *str += 1; } static inline void parse_rgb_value (gchar *str, guint8 *color, gchar **endp) { gdouble number; gchar *p; skip_whitespace (&str); number = g_ascii_strtod (str, endp); p = *endp; skip_whitespace (&p); if (*p == '%') { *endp = (gchar *) (p + 1); *color = CLAMP (number / 100.0, 0.0, 1.0) * 255; } else *color = CLAMP (number, 0, 255); } static gboolean parse_rgba (ClutterColor *color, gchar *str, gboolean has_alpha) { skip_whitespace (&str); if (*str != '(') return FALSE; str += 1; /* red */ parse_rgb_value (str, &color->red, &str); skip_whitespace (&str); if (*str != ',') return FALSE; str += 1; /* green */ parse_rgb_value (str, &color->green, &str); skip_whitespace (&str); if (*str != ',') return FALSE; str += 1; /* blue */ parse_rgb_value (str, &color->blue, &str); skip_whitespace (&str); /* alpha (optional); since the alpha channel value can only * be between 0 and 1 we don't use the parse_rgb_value() * function */ if (has_alpha) { gdouble number; if (*str != ',') return FALSE; str += 1; skip_whitespace (&str); number = g_ascii_strtod (str, &str); color->alpha = CLAMP (number * 255.0, 0, 255); } else color->alpha = 255; skip_whitespace (&str); if (*str != ')') return FALSE; return TRUE; } static gboolean parse_hsla (ClutterColor *color, gchar *str, gboolean has_alpha) { gdouble number; gdouble h, l, s; skip_whitespace (&str); if (*str != '(') return FALSE; str += 1; /* hue */ skip_whitespace (&str); /* we don't do any angle normalization here because * clutter_color_from_hls() will do it for us */ number = g_ascii_strtod (str, &str); skip_whitespace (&str); if (*str != ',') return FALSE; h = number; str += 1; /* saturation */ skip_whitespace (&str); number = g_ascii_strtod (str, &str); skip_whitespace (&str); if (*str != '%') return FALSE; str += 1; s = CLAMP (number / 100.0, 0.0, 1.0); skip_whitespace (&str); if (*str != ',') return FALSE; str += 1; /* luminance */ skip_whitespace (&str); number = g_ascii_strtod (str, &str); skip_whitespace (&str); if (*str != '%') return FALSE; str += 1; l = CLAMP (number / 100.0, 0.0, 1.0); skip_whitespace (&str); /* alpha (optional); since the alpha channel value can only * be between 0 and 1 we don't use the parse_rgb_value() * function */ if (has_alpha) { if (*str != ',') return FALSE; str += 1; skip_whitespace (&str); number = g_ascii_strtod (str, &str); color->alpha = CLAMP (number * 255.0, 0, 255); } else color->alpha = 255; skip_whitespace (&str); if (*str != ')') return FALSE; clutter_color_from_hls (color, h, l, s); return TRUE; } /** * clutter_color_from_string: * @color: (out caller-allocates): return location for a #ClutterColor * @str: a string specifiying a color * * Parses a string definition of a color, filling the #ClutterColor.red, * #ClutterColor.green, #ClutterColor.blue and #ClutterColor.alpha fields * of @color. * * The @color is not allocated. * * The format of @str can be either one of: * * - a standard name (as taken from the X11 rgb.txt file) * - an hexadecimal value in the form: `#rgb`, `#rrggbb`, `#rgba`, or `#rrggbbaa` * - a RGB color in the form: `rgb(r, g, b)` * - a RGB color in the form: `rgba(r, g, b, a)` * - a HSL color in the form: `hsl(h, s, l)` * -a HSL color in the form: `hsla(h, s, l, a)` * * where 'r', 'g', 'b' and 'a' are (respectively) the red, green, blue color * intensities and the opacity. The 'h', 's' and 'l' are (respectively) the * hue, saturation and luminance values. * * In the rgb() and rgba() formats, the 'r', 'g', and 'b' values are either * integers between 0 and 255, or percentage values in the range between 0% * and 100%; the percentages require the '%' character. The 'a' value, if * specified, can only be a floating point value between 0.0 and 1.0. * * In the hls() and hlsa() formats, the 'h' value (hue) is an angle between * 0 and 360.0 degrees; the 'l' and 's' values (luminance and saturation) are * percentage values in the range between 0% and 100%. The 'a' value, if specified, * can only be a floating point value between 0.0 and 1.0. * * Whitespace inside the definitions is ignored; no leading whitespace * is allowed. * * If the alpha component is not specified then it is assumed to be set to * be fully opaque. * * Return value: %TRUE if parsing succeeded, and %FALSE otherwise * * Since: 1.0 */ gboolean clutter_color_from_string (ClutterColor *color, const gchar *str) { PangoColor pango_color = { 0, }; g_return_val_if_fail (color != NULL, FALSE); g_return_val_if_fail (str != NULL, FALSE); if (strncmp (str, "rgb", 3) == 0) { gchar *s = (gchar *) str; gboolean res; if (strncmp (str, "rgba", 4) == 0) res = parse_rgba (color, s + 4, TRUE); else res = parse_rgba (color, s + 3, FALSE); return res; } if (strncmp (str, "hsl", 3) == 0) { gchar *s = (gchar *) str; gboolean res; if (strncmp (str, "hsla", 4) == 0) res = parse_hsla (color, s + 4, TRUE); else res = parse_hsla (color, s + 3, FALSE); return res; } /* if the string contains a color encoded using the hexadecimal * notations (#rrggbbaa or #rgba) we attempt a rough pass at * parsing the color ourselves, as we need the alpha channel that * Pango can't retrieve. */ if (str[0] == '#' && str[1] != '\0') { gsize length = strlen (str + 1); gint32 result; if (sscanf (str + 1, "%x", &result) == 1) { switch (length) { case 8: /* rrggbbaa */ color->red = (result >> 24) & 0xff; color->green = (result >> 16) & 0xff; color->blue = (result >> 8) & 0xff; color->alpha = result & 0xff; return TRUE; case 6: /* #rrggbb */ color->red = (result >> 16) & 0xff; color->green = (result >> 8) & 0xff; color->blue = result & 0xff; color->alpha = 0xff; return TRUE; case 4: /* #rgba */ color->red = ((result >> 12) & 0xf); color->green = ((result >> 8) & 0xf); color->blue = ((result >> 4) & 0xf); color->alpha = result & 0xf; color->red = (color->red << 4) | color->red; color->green = (color->green << 4) | color->green; color->blue = (color->blue << 4) | color->blue; color->alpha = (color->alpha << 4) | color->alpha; return TRUE; case 3: /* #rgb */ color->red = ((result >> 8) & 0xf); color->green = ((result >> 4) & 0xf); color->blue = result & 0xf; color->red = (color->red << 4) | color->red; color->green = (color->green << 4) | color->green; color->blue = (color->blue << 4) | color->blue; color->alpha = 0xff; return TRUE; default: return FALSE; } } } /* fall back to pango for X11-style named colors; see: * * http://en.wikipedia.org/wiki/X11_color_names * * for a list. at some point we might even ship with our own list generated * from X11/rgb.txt, like we generate the key symbols. */ if (pango_color_parse (&pango_color, str)) { color->red = pango_color.red; color->green = pango_color.green; color->blue = pango_color.blue; color->alpha = 0xff; return TRUE; } return FALSE; } /** * clutter_color_to_string: * @color: a #ClutterColor * * Returns a textual specification of @color in the hexadecimal form * #rrggbbaa, where r, * g, b and a are * hexadecimal digits representing the red, green, blue and alpha components * respectively. * * Return value: (transfer full): a newly-allocated text string * * Since: 0.2 */ gchar * clutter_color_to_string (const ClutterColor *color) { g_return_val_if_fail (color != NULL, NULL); return g_strdup_printf ("#%02x%02x%02x%02x", color->red, color->green, color->blue, color->alpha); } /** * clutter_color_equal: * @v1: (type Clutter.Color): a #ClutterColor * @v2: (type Clutter.Color): a #ClutterColor * * Compares two #ClutterColors and checks if they are the same. * * This function can be passed to g_hash_table_new() as the @key_equal_func * parameter, when using #ClutterColors as keys in a #GHashTable. * * Return value: %TRUE if the two colors are the same. * * Since: 0.2 */ gboolean clutter_color_equal (gconstpointer v1, gconstpointer v2) { const ClutterColor *a, *b; g_return_val_if_fail (v1 != NULL, FALSE); g_return_val_if_fail (v2 != NULL, FALSE); if (v1 == v2) return TRUE; a = v1; b = v2; return (a->red == b->red && a->green == b->green && a->blue == b->blue && a->alpha == b->alpha); } /** * clutter_color_hash: * @v: (type Clutter.Color): a #ClutterColor * * Converts a #ClutterColor to a hash value. * * This function can be passed to g_hash_table_new() as the @hash_func * parameter, when using #ClutterColors as keys in a #GHashTable. * * Return value: a hash value corresponding to the color * * Since: 1.0 */ guint clutter_color_hash (gconstpointer v) { return clutter_color_to_pixel ((const ClutterColor *) v); } /** * clutter_color_interpolate: * @initial: the initial #ClutterColor * @final: the final #ClutterColor * @progress: the interpolation progress * @result: (out): return location for the interpolation * * Interpolates between @initial and @final #ClutterColors * using @progress * * Since: 1.6 */ void clutter_color_interpolate (const ClutterColor *initial, const ClutterColor *final, gdouble progress, ClutterColor *result) { g_return_if_fail (initial != NULL); g_return_if_fail (final != NULL); g_return_if_fail (result != NULL); result->red = initial->red + (final->red - initial->red) * progress; result->green = initial->green + (final->green - initial->green) * progress; result->blue = initial->blue + (final->blue - initial->blue) * progress; result->alpha = initial->alpha + (final->alpha - initial->alpha) * progress; } static gboolean clutter_color_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterColor *a_color = clutter_value_get_color (a); const ClutterColor *b_color = clutter_value_get_color (b); ClutterColor res = { 0, }; clutter_color_interpolate (a_color, b_color, progress, &res); clutter_value_set_color (retval, &res); return TRUE; } /** * clutter_color_copy: * @color: a #ClutterColor * * Makes a copy of the color structure. The result must be * freed using clutter_color_free(). * * Return value: (transfer full): an allocated copy of @color. * * Since: 0.2 */ ClutterColor * clutter_color_copy (const ClutterColor *color) { if (G_LIKELY (color != NULL)) return g_slice_dup (ClutterColor, color); return NULL; } /** * clutter_color_free: * @color: a #ClutterColor * * Frees a color structure created with clutter_color_copy(). * * Since: 0.2 */ void clutter_color_free (ClutterColor *color) { if (G_LIKELY (color != NULL)) g_slice_free (ClutterColor, color); } /** * clutter_color_new: * @red: red component of the color, between 0 and 255 * @green: green component of the color, between 0 and 255 * @blue: blue component of the color, between 0 and 255 * @alpha: alpha component of the color, between 0 and 255 * * Creates a new #ClutterColor with the given values. * * This function is the equivalent of: * * |[ * clutter_color_init (clutter_color_alloc (), red, green, blue, alpha); * ]| * * Return value: (transfer full): the newly allocated color. * Use clutter_color_free() when done * * Since: 0.8 */ ClutterColor * clutter_color_new (guint8 red, guint8 green, guint8 blue, guint8 alpha) { return clutter_color_init (clutter_color_alloc (), red, green, blue, alpha); } /** * clutter_color_alloc: (constructor) * * Allocates a new, transparent black #ClutterColor. * * Return value: (transfer full): the newly allocated #ClutterColor; use * clutter_color_free() to free its resources * * Since: 1.12 */ ClutterColor * clutter_color_alloc (void) { return g_slice_new0 (ClutterColor); } /** * clutter_color_init: * @color: a #ClutterColor * @red: red component of the color, between 0 and 255 * @green: green component of the color, between 0 and 255 * @blue: blue component of the color, between 0 and 255 * @alpha: alpha component of the color, between 0 and 255 * * Initializes @color with the given values. * * Return value: (transfer none): the initialized #ClutterColor * * Since: 1.12 */ ClutterColor * clutter_color_init (ClutterColor *color, guint8 red, guint8 green, guint8 blue, guint8 alpha) { g_return_val_if_fail (color != NULL, NULL); color->red = red; color->green = green; color->blue = blue; color->alpha = alpha; return color; } static void clutter_value_transform_color_string (const GValue *src, GValue *dest) { const ClutterColor *color = g_value_get_boxed (src); if (color) { gchar *string = clutter_color_to_string (color); g_value_take_string (dest, string); } else g_value_set_string (dest, NULL); } static void clutter_value_transform_string_color (const GValue *src, GValue *dest) { const char *str = g_value_get_string (src); if (str) { ClutterColor color = { 0, }; clutter_color_from_string (&color, str); clutter_value_set_color (dest, &color); } else clutter_value_set_color (dest, NULL); } G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterColor, clutter_color, clutter_color_copy, clutter_color_free, CLUTTER_REGISTER_VALUE_TRANSFORM_TO (G_TYPE_STRING, clutter_value_transform_color_string) CLUTTER_REGISTER_VALUE_TRANSFORM_FROM (G_TYPE_STRING, clutter_value_transform_string_color) CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_color_progress)); /** * clutter_value_set_color: * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR * @color: the color to set * * Sets @value to @color. * * Since: 0.8 */ void clutter_value_set_color (GValue *value, const ClutterColor *color) { g_return_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value)); g_value_set_boxed (value, color); } /** * clutter_value_get_color: * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR * * Gets the #ClutterColor contained in @value. * * Return value: (transfer none): the color inside the passed #GValue * * Since: 0.8 */ const ClutterColor * clutter_value_get_color (const GValue *value) { g_return_val_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value), NULL); return g_value_get_boxed (value); } static void param_color_init (GParamSpec *pspec) { ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec); cspec->default_value = NULL; } static void param_color_finalize (GParamSpec *pspec) { ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec); clutter_color_free (cspec->default_value); } static void param_color_set_default (GParamSpec *pspec, GValue *value) { const ClutterColor *default_value = CLUTTER_PARAM_SPEC_COLOR (pspec)->default_value; clutter_value_set_color (value, default_value); } static gint param_color_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { const ClutterColor *color1 = g_value_get_boxed (value1); const ClutterColor *color2 = g_value_get_boxed (value2); int pixel1, pixel2; if (color1 == NULL) return color2 == NULL ? 0 : -1; pixel1 = clutter_color_to_pixel (color1); pixel2 = clutter_color_to_pixel (color2); if (pixel1 < pixel2) return -1; else if (pixel1 == pixel2) return 0; else return 1; } GType clutter_param_color_get_type (void) { static GType pspec_type = 0; if (G_UNLIKELY (pspec_type == 0)) { const GParamSpecTypeInfo pspec_info = { sizeof (ClutterParamSpecColor), 16, param_color_init, CLUTTER_TYPE_COLOR, param_color_finalize, param_color_set_default, NULL, param_color_values_cmp, }; pspec_type = g_param_type_register_static (I_("ClutterParamSpecColor"), &pspec_info); } return pspec_type; } /** * clutter_param_spec_color: (skip) * @name: name of the property * @nick: short name * @blurb: description (can be translatable) * @default_value: default value * @flags: flags for the param spec * * Creates a #GParamSpec for properties using #ClutterColor. * * Return value: the newly created #GParamSpec * * Since: 0.8 */ GParamSpec * clutter_param_spec_color (const gchar *name, const gchar *nick, const gchar *blurb, const ClutterColor *default_value, GParamFlags flags) { ClutterParamSpecColor *cspec; cspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_COLOR, name, nick, blurb, flags); cspec->default_value = clutter_color_copy (default_value); return G_PARAM_SPEC (cspec); } muffin-5.2.1/clutter/clutter/clutter-grid-layout.c0000664000175000017500000017665114211404421022404 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Red Hat, Inc. * Copyright (C) 2012 Bastian Winkler * * 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, see . * * Author: * Bastian Winkler * * Based on GtkGrid widget by: * Matthias Clasen */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include "clutter-grid-layout.h" #include "clutter-actor-private.h" #include "clutter-container.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-layout-meta.h" #include "clutter-private.h" /** * SECTION:clutter-grid-layout * @Short_description: A layout manager for a grid of actors * @Title: ClutterGridLayout * @See_also: #ClutterTableLayout, #ClutterBoxLayout * * #ClutterGridLayout is a layout manager which arranges its child widgets in * rows and columns. It is a very similar to #ClutterTableLayout and * #ClutterBoxLayout, but it consistently uses #ClutterActor's * alignment and expansion flags instead of custom child properties. * * Children are added using clutter_grid_layout_attach(). They can span * multiple rows or columns. It is also possible to add a child next to an * existing child, using clutter_grid_layout_attach_next_to(). The behaviour of * #ClutterGridLayout when several children occupy the same grid cell is undefined. * * #ClutterGridLayout can be used like a #ClutterBoxLayout by just using * clutter_actor_add_child(), which will place children next to each other in * the direction determined by the #ClutterGridLayout:orientation property. */ #define CLUTTER_TYPE_GRID_CHILD (clutter_grid_child_get_type ()) #define CLUTTER_GRID_CHILD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_GRID_CHILD, ClutterGridChild)) #define CLUTTER_IS_GRID_CHILD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_GRID_CHILD)) typedef struct _ClutterGridChild ClutterGridChild; typedef struct _ClutterLayoutMetaClass ClutterGridChildClass; typedef struct _ClutterGridAttach ClutterGridAttach; typedef struct _ClutterGridLine ClutterGridLine; typedef struct _ClutterGridLines ClutterGridLines; typedef struct _ClutterGridLineData ClutterGridLineData; typedef struct _ClutterGridRequest ClutterGridRequest; struct _ClutterGridAttach { gint pos; gint span; }; struct _ClutterGridChild { ClutterLayoutMeta parent_instance; ClutterGridAttach attach[2]; }; #define CHILD_LEFT(child) ((child)->attach[CLUTTER_ORIENTATION_HORIZONTAL].pos) #define CHILD_WIDTH(child) ((child)->attach[CLUTTER_ORIENTATION_HORIZONTAL].span) #define CHILD_TOP(child) ((child)->attach[CLUTTER_ORIENTATION_VERTICAL].pos) #define CHILD_HEIGHT(child) ((child)->attach[CLUTTER_ORIENTATION_VERTICAL].span) /* A ClutterGridLineData struct contains row/column specific parts * of the grid. */ struct _ClutterGridLineData { gfloat spacing; guint homogeneous : 1; }; struct _ClutterGridLayoutPrivate { ClutterContainer *container; ClutterOrientation orientation; ClutterGridLineData linedata[2]; }; #define ROWS(priv) (&(priv)->linedata[CLUTTER_ORIENTATION_HORIZONTAL]) #define COLUMNS(priv) (&(priv)->linedata[CLUTTER_ORIENTATION_VERTICAL]) /* A ClutterGridLine struct represents a single row or column * during size requests */ struct _ClutterGridLine { gfloat minimum; gfloat natural; gfloat position; gfloat allocation; guint need_expand : 1; guint expand : 1; guint empty : 1; }; struct _ClutterGridLines { ClutterGridLine *lines; gint min, max; }; struct _ClutterGridRequest { ClutterGridLayout *grid; ClutterGridLines lines[2]; }; enum { PROP_0, PROP_ORIENTATION, PROP_ROW_SPACING, PROP_COLUMN_SPACING, PROP_ROW_HOMOGENEOUS, PROP_COLUMN_HOMOGENEOUS, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { PROP_CHILD_0, PROP_CHILD_LEFT_ATTACH, PROP_CHILD_TOP_ATTACH, PROP_CHILD_WIDTH, PROP_CHILD_HEIGHT, PROP_CHILD_LAST }; static GParamSpec *child_props[PROP_CHILD_LAST]; GType clutter_grid_child_get_type (void); G_DEFINE_TYPE (ClutterGridChild, clutter_grid_child, CLUTTER_TYPE_LAYOUT_META) G_DEFINE_TYPE_WITH_PRIVATE (ClutterGridLayout, clutter_grid_layout, CLUTTER_TYPE_LAYOUT_MANAGER) #define GET_GRID_CHILD(grid, child) \ (CLUTTER_GRID_CHILD(clutter_layout_manager_get_child_meta \ (CLUTTER_LAYOUT_MANAGER((grid)),\ CLUTTER_GRID_LAYOUT((grid))->priv->container,(child)))) static void grid_attach (ClutterGridLayout *self, ClutterActor *actor, gint left, gint top, gint width, gint height) { ClutterGridChild *grid_child; grid_child = GET_GRID_CHILD (self, actor); CHILD_LEFT (grid_child) = left; CHILD_TOP (grid_child) = top; CHILD_WIDTH (grid_child) = width; CHILD_HEIGHT (grid_child) = height; } /* Find the position 'touching' existing * children. @orientation and @max determine * from which direction to approach (horizontal * + max = right, vertical + !max = top, etc). * @op_pos, @op_span determine the rows/columns * in which the touching has to happen. */ static gint find_attach_position (ClutterGridLayout *self, ClutterOrientation orientation, gint op_pos, gint op_span, gboolean max) { ClutterGridLayoutPrivate *priv = self->priv; ClutterGridChild *grid_child; ClutterGridAttach *attach; ClutterGridAttach *opposite; ClutterActorIter iter; ClutterActor *child; gint pos; gboolean hit; if (max) pos = -G_MAXINT; else pos = G_MAXINT; hit = FALSE; if (!priv->container) return -1; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { grid_child = GET_GRID_CHILD (self, child); attach = &grid_child->attach[orientation]; opposite = &grid_child->attach[1 - orientation]; /* check if the ranges overlap */ if (opposite->pos <= op_pos + op_span && op_pos <= opposite->pos + opposite->span) { hit = TRUE; if (max) pos = MAX (pos, attach->pos + attach->span); else pos = MIN (pos, attach->pos); } } if (!hit) pos = 0; return pos; } static void grid_attach_next_to (ClutterGridLayout *layout, ClutterActor *child, ClutterActor *sibling, ClutterGridPosition side, gint width, gint height) { ClutterGridChild *grid_sibling; gint left, top; if (sibling) { grid_sibling = GET_GRID_CHILD (layout, sibling); switch (side) { case CLUTTER_GRID_POSITION_LEFT: left = CHILD_LEFT (grid_sibling) - width; top = CHILD_TOP (grid_sibling); break; case CLUTTER_GRID_POSITION_RIGHT: left = CHILD_LEFT (grid_sibling) + CHILD_WIDTH (grid_sibling); top = CHILD_TOP (grid_sibling); break; case CLUTTER_GRID_POSITION_TOP: left = CHILD_LEFT (grid_sibling); top = CHILD_TOP (grid_sibling) - height; break; case CLUTTER_GRID_POSITION_BOTTOM: left = CHILD_LEFT (grid_sibling); top = CHILD_TOP (grid_sibling) + CHILD_HEIGHT (grid_sibling); break; default: g_assert_not_reached (); } } else { switch (side) { case CLUTTER_GRID_POSITION_LEFT: left = find_attach_position (layout, CLUTTER_ORIENTATION_HORIZONTAL, 0, height, FALSE); left -= width; top = 0; break; case CLUTTER_GRID_POSITION_RIGHT: left = find_attach_position (layout, CLUTTER_ORIENTATION_HORIZONTAL, 0, height, TRUE); top = 0; break; case CLUTTER_GRID_POSITION_TOP: left = 0; top = find_attach_position (layout, CLUTTER_ORIENTATION_VERTICAL, 0, width, FALSE); top -= height; break; case CLUTTER_GRID_POSITION_BOTTOM: left = 0; top = find_attach_position (layout, CLUTTER_ORIENTATION_VERTICAL, 0, width, TRUE); break; default: g_assert_not_reached (); } } grid_attach (layout, child, left, top, width, height); } static void clutter_grid_request_update_child_attach (ClutterGridRequest *request, ClutterActor *actor) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridChild *grid_child; grid_child = GET_GRID_CHILD (request->grid, actor); if (CHILD_LEFT (grid_child) == -1 || CHILD_TOP (grid_child) == -1) { ClutterGridPosition side; ClutterActor *sibling; if (priv->orientation == CLUTTER_ORIENTATION_HORIZONTAL) { ClutterTextDirection td; gboolean rtl; ClutterActor *container = CLUTTER_ACTOR (priv->container); td = clutter_actor_get_text_direction (container); rtl = (td == CLUTTER_TEXT_DIRECTION_RTL) ? TRUE : FALSE; side = rtl ? CLUTTER_GRID_POSITION_LEFT : CLUTTER_GRID_POSITION_RIGHT; } else { /* XXX: maybe we should also add a :pack-start property to modify * this */ side = CLUTTER_GRID_POSITION_BOTTOM; } sibling = clutter_actor_get_previous_sibling (actor); if (sibling) clutter_grid_layout_insert_next_to (request->grid, sibling, side); grid_attach_next_to (request->grid, actor, sibling, side, CHILD_WIDTH (grid_child), CHILD_HEIGHT (grid_child)); } } static void clutter_grid_request_update_attach (ClutterGridRequest *request) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterActorIter iter; ClutterActor *child; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) clutter_grid_request_update_child_attach (request, child); } /* Calculates the min and max numbers for both orientations. */ static void clutter_grid_request_count_lines (ClutterGridRequest *request) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridChild *grid_child; ClutterGridAttach *attach; ClutterActorIter iter; ClutterActor *child; gint min[2]; gint max[2]; min[0] = min[1] = G_MAXINT; max[0] = max[1] = G_MININT; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { grid_child = GET_GRID_CHILD (request->grid, child); attach = grid_child->attach; min[0] = MIN (min[0], attach[0].pos); max[0] = MAX (max[0], attach[0].pos + attach[0].span); min[1] = MIN (min[1], attach[1].pos); max[1] = MAX (max[1], attach[1].pos + attach[1].span); } request->lines[0].min = min[0]; request->lines[0].max = max[0]; request->lines[1].min = min[1]; request->lines[1].max = max[1]; } /* Sets line sizes to 0 and marks lines as expand * if they have a non-spanning expanding child. */ static void clutter_grid_request_init (ClutterGridRequest *request, ClutterOrientation orientation) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridChild *grid_child; ClutterGridAttach *attach; ClutterGridLines *lines; ClutterActorIter iter; ClutterActor *child; gint i; lines = &request->lines[orientation]; for (i = 0; i < lines->max - lines->min; i++) { lines->lines[i].minimum = 0; lines->lines[i].natural = 0; lines->lines[i].expand = FALSE; } clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { grid_child = GET_GRID_CHILD (request->grid, child); attach = &grid_child->attach[orientation]; if (attach->span == 1 && clutter_actor_needs_expand (child, orientation)) lines->lines[attach->pos - lines->min].expand = TRUE; } } /* Sums allocations for lines spanned by child and their spacing. */ static gfloat compute_allocation_for_child (ClutterGridRequest *request, ClutterActor *child, ClutterOrientation orientation) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridChild *grid_child; ClutterGridLineData *linedata; ClutterGridLines *lines; ClutterGridLine *line; ClutterGridAttach *attach; gfloat size; gint i; grid_child = GET_GRID_CHILD (request->grid, child); linedata = &priv->linedata[orientation]; lines = &request->lines[orientation]; attach = &grid_child->attach[orientation]; size = (attach->span - 1) * linedata->spacing; for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; size += line->allocation; } return size; } static void compute_request_for_child (ClutterGridRequest *request, ClutterActor *child, ClutterOrientation orientation, gboolean contextual, gfloat *minimum, gfloat *natural) { if (contextual) { gfloat size; size = compute_allocation_for_child (request, child, 1 - orientation); if (orientation == CLUTTER_ORIENTATION_HORIZONTAL) clutter_actor_get_preferred_width (child, size, minimum, natural); else clutter_actor_get_preferred_height (child, size, minimum, natural); } else { if (orientation == CLUTTER_ORIENTATION_HORIZONTAL) clutter_actor_get_preferred_width (child, -1, minimum, natural); else clutter_actor_get_preferred_height (child, -1, minimum, natural); } } /* Sets requisition to max. of non-spanning children. * If contextual is TRUE, requires allocations of * lines in the opposite orientation to be set. */ static void clutter_grid_request_non_spanning (ClutterGridRequest *request, ClutterOrientation orientation, gboolean contextual) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridChild *grid_child; ClutterGridAttach *attach; ClutterGridLines *lines; ClutterGridLine *line; ClutterActorIter iter; ClutterActor *child; gfloat minimum; gfloat natural; lines = &request->lines[orientation]; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { if (!clutter_actor_is_visible (child)) continue; grid_child = GET_GRID_CHILD (request->grid, child); attach = &grid_child->attach[orientation]; if (attach->span != 1) continue; compute_request_for_child (request, child, orientation, contextual, &minimum, &natural); line = &lines->lines[attach->pos - lines->min]; line->minimum = MAX (line->minimum, minimum); line->natural = MAX (line->natural, natural); } } /* Enforce homogeneous sizes. */ static void clutter_grid_request_homogeneous (ClutterGridRequest *request, ClutterOrientation orientation) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridLineData *linedata; ClutterGridLines *lines; gfloat minimum, natural; gint i; linedata = &priv->linedata[orientation]; lines = &request->lines[orientation]; if (!linedata->homogeneous) return; minimum = 0.0f; natural = 0.0f; for (i = 0; i < lines->max - lines->min; i++) { minimum = MAX (minimum, lines->lines[i].minimum); natural = MAX (natural, lines->lines[i].natural); } for (i = 0; i < lines->max - lines->min; i++) { lines->lines[i].minimum = minimum; lines->lines[i].natural = natural; } } /* Deals with spanning children. * Requires expand fields of lines to be set for * non-spanning children. */ static void clutter_grid_request_spanning (ClutterGridRequest *request, ClutterOrientation orientation, gboolean contextual) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridChild *grid_child; ClutterActor *child; ClutterActorIter iter; ClutterGridAttach *attach; ClutterGridLineData *linedata; ClutterGridLines *lines; ClutterGridLine *line; gfloat minimum; gfloat natural; gint span_minimum; gint span_natural; gint span_expand; gboolean force_expand; gint extra; gint expand; gint line_extra; gint i; linedata = &priv->linedata[orientation]; lines = &request->lines[orientation]; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { if (!clutter_actor_is_visible (child)) continue; grid_child = GET_GRID_CHILD (request->grid, child); attach = &grid_child->attach[orientation]; if (attach->span == 1) continue; compute_request_for_child (request, child, orientation, contextual, &minimum, &natural); span_minimum = (attach->span - 1) * linedata->spacing; span_natural = (attach->span - 1) * linedata->spacing; span_expand = 0; force_expand = FALSE; for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; span_minimum += line->minimum; span_natural += line->natural; if (line->expand) span_expand += 1; } if (span_expand == 0) { span_expand = attach->span; force_expand = TRUE; } /* If we need to request more space for this child to fill * its requisition, then divide up the needed space amongst the * lines it spans, favoring expandable lines if any. * * When doing homogeneous allocation though, try to keep the * line allocations even, since we're going to force them to * be the same anyway, and we don't want to introduce unnecessary * extra space. */ if (span_minimum < minimum) { if (linedata->homogeneous) { gint total, m; total = minimum - (attach->span - 1) * linedata->spacing; m = total / attach->span + (total % attach->span ? 1 : 0); for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; line->minimum = MAX(line->minimum, m); } } else { extra = minimum - span_minimum; expand = span_expand; for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; if (force_expand || line->expand) { line_extra = extra / expand; line->minimum += line_extra; extra -= line_extra; expand -= 1; } } } } if (span_natural < natural) { if (linedata->homogeneous) { gint total, n; total = natural - (attach->span - 1) * linedata->spacing; n = total / attach->span + (total % attach->span ? 1 : 0); for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; line->natural = MAX(line->natural, n); } } else { extra = natural - span_natural; expand = span_expand; for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; if (force_expand || line->expand) { line_extra = extra / expand; line->natural += line_extra; extra -= line_extra; expand -= 1; } } } } } } /* Marks empty and expanding lines and counts them. */ static void clutter_grid_request_compute_expand (ClutterGridRequest *request, ClutterOrientation orientation, gint *nonempty_lines, gint *expand_lines) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridChild *grid_child; ClutterGridAttach *attach; ClutterActorIter iter; ClutterActor *child; gint i; ClutterGridLines *lines; ClutterGridLine *line; gboolean has_expand; gint expand; gint empty; lines = &request->lines[orientation]; for (i = 0; i < lines->max - lines->min; i++) { lines->lines[i].need_expand = FALSE; lines->lines[i].expand = FALSE; lines->lines[i].empty = TRUE; } clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { if (!clutter_actor_is_visible (child)) continue; grid_child = GET_GRID_CHILD (request->grid, child); attach = &grid_child->attach[orientation]; if (attach->span != 1) continue; line = &lines->lines[attach->pos - lines->min]; line->empty = FALSE; if (clutter_actor_needs_expand (child, orientation)) line->expand = TRUE; } clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { if (!clutter_actor_is_visible (child)) continue; grid_child = GET_GRID_CHILD (request->grid, child); attach = &grid_child->attach[orientation]; if (attach->span == 1) continue; has_expand = FALSE; for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; line->empty = FALSE; if (line->expand) has_expand = TRUE; } if (!has_expand && clutter_actor_needs_expand (child, orientation)) { for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; line->need_expand = TRUE; } } } empty = 0; expand = 0; for (i = 0; i < lines->max - lines->min; i++) { line = &lines->lines[i]; if (line->need_expand) line->expand = TRUE; if (line->empty) empty += 1; if (line->expand) expand += 1; } if (nonempty_lines) *nonempty_lines = lines->max - lines->min - empty; if (expand_lines) *expand_lines = expand; } /* Sums the minimum and natural fields of lines and their spacing. */ static void clutter_grid_request_sum (ClutterGridRequest *request, ClutterOrientation orientation, gfloat *minimum, gfloat *natural) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridLineData *linedata; ClutterGridLines *lines; gint i; gfloat min, nat; gint nonempty; clutter_grid_request_compute_expand (request, orientation, &nonempty, NULL); linedata = &priv->linedata[orientation]; lines = &request->lines[orientation]; min = 0; nat = 0; if (nonempty > 0) { min = (nonempty - 1) * linedata->spacing; nat = (nonempty - 1) * linedata->spacing; } for (i = 0; i < lines->max - lines->min; i++) { min += lines->lines[i].minimum; nat += lines->lines[i].natural; } if (minimum) *minimum = min; if (natural) *natural = nat; } /* Computes minimum and natural fields of lines. * When contextual is TRUE, requires allocation of * lines in the opposite orientation to be set. */ static void clutter_grid_request_run (ClutterGridRequest *request, ClutterOrientation orientation, gboolean contextual) { clutter_grid_request_init (request, orientation); clutter_grid_request_non_spanning (request, orientation, contextual); clutter_grid_request_homogeneous (request, orientation); clutter_grid_request_spanning (request, orientation, contextual); clutter_grid_request_homogeneous (request, orientation); } typedef struct _RequestedSize { gpointer data; gfloat minimum_size; gfloat natural_size; } RequestedSize; /* Pulled from gtksizerequest.c from Gtk+ */ static gint compare_gap (gconstpointer p1, gconstpointer p2, gpointer data) { RequestedSize *sizes = data; const guint *c1 = p1; const guint *c2 = p2; const gint d1 = MAX (sizes[*c1].natural_size - sizes[*c1].minimum_size, 0); const gint d2 = MAX (sizes[*c2].natural_size - sizes[*c2].minimum_size, 0); gint delta = (d2 - d1); if (0 == delta) delta = (*c2 - *c1); return delta; } /* * distribute_natural_allocation: * @extra_space: Extra space to redistribute among children after subtracting * minimum sizes and any child padding from the overall allocation * @n_requested_sizes: Number of requests to fit into the allocation * @sizes: An array of structs with a client pointer and a minimum/natural size * in the orientation of the allocation. * * Distributes @extra_space to child @sizes by bringing smaller * children up to natural size first. * * The remaining space will be added to the @minimum_size member of the * RequestedSize struct. If all sizes reach their natural size then * the remaining space is returned. * * Returns: The remainder of @extra_space after redistributing space * to @sizes. * * Pulled from gtksizerequest.c from Gtk+ */ static gint distribute_natural_allocation (gint extra_space, guint n_requested_sizes, RequestedSize *sizes) { guint *spreading; gint i; g_return_val_if_fail (extra_space >= 0, 0); spreading = g_newa (guint, n_requested_sizes); for (i = 0; i < n_requested_sizes; i++) spreading[i] = i; /* Distribute the container's extra space c_gap. We want to assign * this space such that the sum of extra space assigned to children * (c^i_gap) is equal to c_cap. The case that there's not enough * space for all children to take their natural size needs some * attention. The goals we want to achieve are: * * a) Maximize number of children taking their natural size. * b) The allocated size of children should be a continuous * function of c_gap. That is, increasing the container size by * one pixel should never make drastic changes in the distribution. * c) If child i takes its natural size and child j doesn't, * child j should have received at least as much gap as child i. * * The following code distributes the additional space by following * these rules. */ /* Sort descending by gap and position. */ g_qsort_with_data (spreading, n_requested_sizes, sizeof (guint), compare_gap, sizes); /* Distribute available space. * This master piece of a loop was conceived by Behdad Esfahbod. */ for (i = n_requested_sizes - 1; extra_space > 0 && i >= 0; --i) { /* Divide remaining space by number of remaining children. * Sort order and reducing remaining space by assigned space * ensures that space is distributed equally. */ gint glue = (extra_space + i) / (i + 1); gint gap = sizes[(spreading[i])].natural_size - sizes[(spreading[i])].minimum_size; gint extra = MIN (glue, gap); sizes[spreading[i]].minimum_size += extra; extra_space -= extra; } return extra_space; } /* Requires that the minimum and natural fields of lines * have been set, computes the allocation field of lines * by distributing total_size among lines. */ static void clutter_grid_request_allocate (ClutterGridRequest *request, ClutterOrientation orientation, gfloat total_size) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridLineData *linedata; ClutterGridLines *lines; ClutterGridLine *line; gint nonempty; gint expand; gint i, j; RequestedSize *sizes; gint extra; gint rest; gint size; clutter_grid_request_compute_expand (request, orientation, &nonempty, &expand); if (nonempty == 0) return; linedata = &priv->linedata[orientation]; lines = &request->lines[orientation]; size = total_size - (nonempty - 1) * linedata->spacing; if (linedata->homogeneous) { extra = size / nonempty; rest = size % nonempty; for (i = 0; i < lines->max - lines->min; i++) { line = &lines->lines[i]; if (line->empty) continue; line->allocation = extra; if (rest > 0) { line->allocation += 1; rest -= 1; } } } else { sizes = g_newa (RequestedSize, nonempty); j = 0; for (i = 0; i < lines->max - lines->min; i++) { line = &lines->lines[i]; if (line->empty) continue; size -= line->minimum; sizes[j].minimum_size = line->minimum; sizes[j].natural_size = line->natural; sizes[j].data = line; j++; } size = distribute_natural_allocation (MAX (0, size), nonempty, sizes); if (expand > 0) { extra = size / expand; rest = size % expand; } else { extra = 0; rest = 0; } j = 0; for (i = 0; i < lines->max - lines->min; i++) { line = &lines->lines[i]; if (line->empty) continue; g_assert (line == sizes[j].data); line->allocation = sizes[j].minimum_size; if (line->expand) { line->allocation += extra; if (rest > 0) { line->allocation += 1; rest -= 1; } } j++; } } } /* Computes the position fields from allocation and spacing. */ static void clutter_grid_request_position (ClutterGridRequest *request, ClutterOrientation orientation) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridLineData *linedata; ClutterGridLines *lines; ClutterGridLine *line; gfloat position; gint i; linedata = &priv->linedata[orientation]; lines = &request->lines[orientation]; position = 0.f; for (i = 0; i < lines->max - lines->min; i++) { line = &lines->lines[i]; if (!line->empty) { line->position = position; position += line->allocation + linedata->spacing; } } } static void clutter_grid_child_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterGridChild *grid_child = CLUTTER_GRID_CHILD (gobject); ClutterLayoutManager *manager; manager = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (gobject)); switch (prop_id) { case PROP_CHILD_LEFT_ATTACH: CHILD_LEFT (grid_child) = g_value_get_int (value); clutter_layout_manager_layout_changed (manager); break; case PROP_CHILD_TOP_ATTACH: CHILD_TOP (grid_child) = g_value_get_int (value); clutter_layout_manager_layout_changed (manager); break; case PROP_CHILD_WIDTH: CHILD_WIDTH (grid_child) = g_value_get_int (value); clutter_layout_manager_layout_changed (manager); break; case PROP_CHILD_HEIGHT: CHILD_HEIGHT (grid_child) = g_value_get_int (value); clutter_layout_manager_layout_changed (manager); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_grid_child_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterGridChild *grid_child = CLUTTER_GRID_CHILD (gobject); switch (prop_id) { case PROP_CHILD_LEFT_ATTACH: g_value_set_int (value, CHILD_LEFT (grid_child)); break; case PROP_CHILD_TOP_ATTACH: g_value_set_int (value, CHILD_TOP (grid_child)); break; case PROP_CHILD_WIDTH: g_value_set_int (value, CHILD_WIDTH (grid_child)); break; case PROP_CHILD_HEIGHT: g_value_set_int (value, CHILD_HEIGHT (grid_child)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_grid_child_class_init (ClutterGridChildClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = clutter_grid_child_set_property; gobject_class->get_property = clutter_grid_child_get_property; child_props[PROP_CHILD_LEFT_ATTACH] = g_param_spec_int ("left-attach", P_("Left attachment"), P_("The column number to attach the left side of the " "child to"), -G_MAXINT, G_MAXINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); child_props[PROP_CHILD_TOP_ATTACH] = g_param_spec_int ("top-attach", P_("Top attachment"), P_("The row number to attach the top side of a child " "widget to"), -G_MAXINT, G_MAXINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); child_props[PROP_CHILD_WIDTH] = g_param_spec_int ("width", P_("Width"), P_("The number of columns that a child spans"), -G_MAXINT, G_MAXINT, 1, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); child_props[PROP_CHILD_HEIGHT] = g_param_spec_int ("height", P_("Height"), P_("The number of rows that a child spans"), -G_MAXINT, G_MAXINT, 1, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); g_object_class_install_properties (gobject_class, PROP_CHILD_LAST, child_props); } static void clutter_grid_child_init (ClutterGridChild *self) { CHILD_LEFT (self) = -1; CHILD_TOP (self) = -1; CHILD_WIDTH (self) = 1; CHILD_HEIGHT (self) = 1; } static void clutter_grid_layout_set_container (ClutterLayoutManager *self, ClutterContainer *container) { ClutterGridLayoutPrivate *priv = CLUTTER_GRID_LAYOUT (self)->priv; ClutterLayoutManagerClass *parent_class; priv->container = container; if (priv->container != NULL) { ClutterRequestMode request_mode; /* we need to change the :request-mode of the container * to match the orientation */ request_mode = priv->orientation == CLUTTER_ORIENTATION_VERTICAL ? CLUTTER_REQUEST_HEIGHT_FOR_WIDTH : CLUTTER_REQUEST_WIDTH_FOR_HEIGHT; clutter_actor_set_request_mode (CLUTTER_ACTOR (priv->container), request_mode); } parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_grid_layout_parent_class); parent_class->set_container (self, container); } static void clutter_grid_layout_get_size_for_size (ClutterGridLayout *self, ClutterOrientation orientation, float size, float *minimum, float *natural) { ClutterGridRequest request; ClutterGridLines *lines; float min_size, nat_size; request.grid = self; clutter_grid_request_update_attach (&request); clutter_grid_request_count_lines (&request); lines = &request.lines[0]; lines->lines = g_newa (ClutterGridLine, lines->max - lines->min); memset (lines->lines, 0, (lines->max - lines->min) * sizeof (ClutterGridLine)); lines = &request.lines[1]; lines->lines = g_newa (ClutterGridLine, lines->max - lines->min); memset (lines->lines, 0, (lines->max - lines->min) * sizeof (ClutterGridLine)); clutter_grid_request_run (&request, 1 - orientation, FALSE); clutter_grid_request_sum (&request, 1 - orientation, &min_size, &nat_size); clutter_grid_request_allocate (&request, 1 - orientation, MAX (size, nat_size)); clutter_grid_request_run (&request, orientation, TRUE); clutter_grid_request_sum (&request, orientation, minimum, natural); } static void clutter_grid_layout_get_preferred_width (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_height, gfloat *min_width_p, gfloat *nat_width_p) { ClutterGridLayout *self = CLUTTER_GRID_LAYOUT (manager); if (min_width_p) *min_width_p = 0.0f; if (nat_width_p) *nat_width_p = 0.0f; clutter_grid_layout_get_size_for_size (self, CLUTTER_ORIENTATION_HORIZONTAL, for_height, min_width_p, nat_width_p); } static void clutter_grid_layout_get_preferred_height (ClutterLayoutManager *manager, ClutterContainer *container, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { ClutterGridLayout *self = CLUTTER_GRID_LAYOUT (manager); if (min_height_p) *min_height_p = 0.0f; if (nat_height_p) *nat_height_p = 0.0f; clutter_grid_layout_get_size_for_size (self, CLUTTER_ORIENTATION_VERTICAL, for_width, min_height_p, nat_height_p); } static void allocate_child (ClutterGridRequest *request, ClutterOrientation orientation, ClutterGridChild *child, gfloat *position, gfloat *size) { ClutterGridLayoutPrivate *priv = request->grid->priv; ClutterGridLineData *linedata; ClutterGridLines *lines; ClutterGridLine *line; ClutterGridAttach *attach; gint i; linedata = &priv->linedata[orientation]; lines = &request->lines[orientation]; attach = &child->attach[orientation]; *position = lines->lines[attach->pos - lines->min].position; *size = (attach->span - 1) * linedata->spacing; for (i = 0; i < attach->span; i++) { line = &lines->lines[attach->pos - lines->min + i]; *size += line->allocation; } } #define GET_SIZE(allocation, orientation) \ (orientation == CLUTTER_ORIENTATION_HORIZONTAL \ ? clutter_actor_box_get_width ((allocation)) \ : clutter_actor_box_get_height ((allocation))) static void clutter_grid_layout_allocate (ClutterLayoutManager *layout, ClutterContainer *container, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterGridLayout *self = CLUTTER_GRID_LAYOUT (layout); ClutterOrientation orientation; ClutterGridRequest request; ClutterGridLines *lines; ClutterActorIter iter; ClutterActor *child; request.grid = self; clutter_grid_request_update_attach (&request); clutter_grid_request_count_lines (&request); lines = &request.lines[0]; lines->lines = g_newa (ClutterGridLine, lines->max - lines->min); memset (lines->lines, 0, (lines->max - lines->min) * sizeof (ClutterGridLine)); lines = &request.lines[1]; lines->lines = g_newa (ClutterGridLine, lines->max - lines->min); memset (lines->lines, 0, (lines->max - lines->min) * sizeof (ClutterGridLine)); if (clutter_actor_get_request_mode (CLUTTER_ACTOR (container)) == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) orientation = CLUTTER_ORIENTATION_HORIZONTAL; else orientation = CLUTTER_ORIENTATION_VERTICAL; clutter_grid_request_run (&request, 1 - orientation, FALSE); clutter_grid_request_allocate (&request, 1 - orientation, GET_SIZE (allocation, 1 - orientation)); clutter_grid_request_run (&request, orientation, TRUE); clutter_grid_request_allocate (&request, orientation, GET_SIZE (allocation, orientation)); clutter_grid_request_position (&request, 0); clutter_grid_request_position (&request, 1); clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container)); while (clutter_actor_iter_next (&iter, &child)) { ClutterActorBox child_allocation; gfloat x, y, width, height; ClutterGridChild *grid_child; if (!clutter_actor_is_visible (child)) continue; grid_child = GET_GRID_CHILD (self, child); allocate_child (&request, CLUTTER_ORIENTATION_HORIZONTAL, grid_child, &x, &width); allocate_child (&request, CLUTTER_ORIENTATION_VERTICAL, grid_child, &y, &height); x += allocation->x1; y += allocation->y1; CLUTTER_NOTE (LAYOUT, "Allocation for %s { %.2f, %.2f - %.2f x %.2f }", _clutter_actor_get_debug_name (child), x, y, width, height); child_allocation.x1 = x; child_allocation.y1 = y; child_allocation.x2 = child_allocation.x1 + width; child_allocation.y2 = child_allocation.y1 + height; clutter_actor_allocate (child, &child_allocation, flags); } } static GType clutter_grid_layout_get_child_meta_type (ClutterLayoutManager *self) { return CLUTTER_TYPE_GRID_CHILD; } static void clutter_grid_layout_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterGridLayout *self = CLUTTER_GRID_LAYOUT (gobject); switch (prop_id) { case PROP_ORIENTATION: clutter_grid_layout_set_orientation (self, g_value_get_enum (value)); break; case PROP_ROW_SPACING: clutter_grid_layout_set_row_spacing (self, g_value_get_uint (value)); break; case PROP_COLUMN_SPACING: clutter_grid_layout_set_column_spacing (self, g_value_get_uint (value)); break; case PROP_ROW_HOMOGENEOUS: clutter_grid_layout_set_row_homogeneous (self, g_value_get_boolean (value)); break; case PROP_COLUMN_HOMOGENEOUS: clutter_grid_layout_set_column_homogeneous (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_grid_layout_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterGridLayoutPrivate *priv = CLUTTER_GRID_LAYOUT (gobject)->priv; switch (prop_id) { case PROP_ORIENTATION: g_value_set_enum (value, priv->orientation); break; case PROP_ROW_SPACING: g_value_set_uint (value, COLUMNS (priv)->spacing); break; case PROP_COLUMN_SPACING: g_value_set_uint (value, ROWS (priv)->spacing); break; case PROP_ROW_HOMOGENEOUS: g_value_set_boolean (value, COLUMNS (priv)->homogeneous); break; case PROP_COLUMN_HOMOGENEOUS: g_value_set_boolean (value, ROWS (priv)->homogeneous); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_grid_layout_class_init (ClutterGridLayoutClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterLayoutManagerClass *layout_class; layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass); object_class->set_property = clutter_grid_layout_set_property; object_class->get_property = clutter_grid_layout_get_property; layout_class->set_container = clutter_grid_layout_set_container; layout_class->get_preferred_width = clutter_grid_layout_get_preferred_width; layout_class->get_preferred_height = clutter_grid_layout_get_preferred_height; layout_class->allocate = clutter_grid_layout_allocate; layout_class->get_child_meta_type = clutter_grid_layout_get_child_meta_type; /** * ClutterGridLayout:orientation: * * The orientation of the layout, either horizontal or vertical * * Since: 1.12 */ obj_props[PROP_ORIENTATION] = g_param_spec_enum ("orientation", P_("Orientation"), P_("The orientation of the layout"), CLUTTER_TYPE_ORIENTATION, CLUTTER_ORIENTATION_HORIZONTAL, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); /** * ClutterGridLayout:row-spacing: * * The amount of space in pixels between two consecutive rows * * Since: 1.12 */ obj_props[PROP_ROW_SPACING] = g_param_spec_uint ("row-spacing", P_("Row spacing"), P_("The amount of space between two consecutive rows"), 0, G_MAXUINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); /** * ClutterGridLayout:column-spacing: * * The amount of space in pixels between two consecutive columns * * Since: 1.12 */ obj_props[PROP_COLUMN_SPACING] = g_param_spec_uint ("column-spacing", P_("Column spacing"), P_("The amount of space between two consecutive " "columns"), 0, G_MAXUINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); /** * ClutterGridLayout:row-homogeneous: * * Whether all rows of the layout should have the same height * * Since: 1.12 */ obj_props[PROP_ROW_HOMOGENEOUS] = g_param_spec_boolean ("row-homogeneous", P_("Row Homogeneous"), P_("If TRUE, the rows are all the same height"), FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); /** * ClutterGridLayout:column-homogeneous: * * Whether all columns of the layout should have the same width * * Since: 1.12 */ obj_props[PROP_COLUMN_HOMOGENEOUS] = g_param_spec_boolean ("column-homogeneous", P_("Column Homogeneous"), P_("If TRUE, the columns are all the same width"), FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); g_object_class_install_properties (object_class, PROP_LAST, obj_props); } static void clutter_grid_layout_init (ClutterGridLayout *self) { self->priv = clutter_grid_layout_get_instance_private (self); self->priv->orientation = CLUTTER_ORIENTATION_HORIZONTAL; self->priv->linedata[0].spacing = 0; self->priv->linedata[1].spacing = 0; self->priv->linedata[0].homogeneous = FALSE; self->priv->linedata[1].homogeneous = FALSE; } /** * clutter_grid_layout_new: * * Creates a new #ClutterGridLayout * * Return value: the new #ClutterGridLayout */ ClutterLayoutManager * clutter_grid_layout_new (void) { return g_object_new (CLUTTER_TYPE_GRID_LAYOUT, NULL); } /** * clutter_grid_layout_attach: * @layout: a #ClutterGridLayout * @child: the #ClutterActor to add * @left: the column number to attach the left side of @child to * @top: the row number to attach the top side of @child to * @width: the number of columns that @child will span * @height: the number of rows that @child will span * * Adds a widget to the grid. * * The position of @child is determined by @left and @top. The * number of 'cells' that @child will occupy is determined by * @width and @height. * * Since: 1.12 */ void clutter_grid_layout_attach (ClutterGridLayout *layout, ClutterActor *child, gint left, gint top, gint width, gint height) { ClutterGridLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (!priv->container) return; grid_attach (layout, child, left, top, width, height); clutter_actor_add_child (CLUTTER_ACTOR (priv->container), child); } /** * clutter_grid_layout_attach_next_to: * @layout: a #ClutterGridLayout * @child: the actor to add * @sibling: (allow-none): the child of @layout that @child will be placed * next to, or %NULL to place @child at the beginning or end * @side: the side of @sibling that @child is positioned next to * @width: the number of columns that @child will span * @height: the number of rows that @child will span * * Adds a actor to the grid. * * The actor is placed next to @sibling, on the side determined by * @side. When @sibling is %NULL, the actor is placed in row (for * left or right placement) or column 0 (for top or bottom placement), * at the end indicated by @side. * * Attaching widgets labeled [1], [2], [3] with @sibling == %NULL and * @side == %CLUTTER_GRID_POSITION_LEFT yields a layout of [3][2][1]. * * Since: 1.12 */ void clutter_grid_layout_attach_next_to (ClutterGridLayout *layout, ClutterActor *child, ClutterActor *sibling, ClutterGridPosition side, gint width, gint height) { ClutterGridLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (clutter_actor_get_parent (child) == NULL); g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling)); g_return_if_fail (width > 0); g_return_if_fail (height > 0); priv = layout->priv; if (!priv->container) return; grid_attach_next_to (layout, child, sibling, side, width, height); clutter_actor_add_child (CLUTTER_ACTOR (priv->container), child); } /** * clutter_grid_layout_set_orientation: * @layout: a #ClutterGridLayout * @orientation: the orientation of the #ClutterGridLayout * * Sets the orientation of the @layout. * * #ClutterGridLayout uses the orientation as a hint when adding * children to the #ClutterActor using it as a layout manager via * clutter_actor_add_child(); changing this value will not have * any effect on children that are already part of the layout. * * Since: 1.12 */ void clutter_grid_layout_set_orientation (ClutterGridLayout *layout, ClutterOrientation orientation) { ClutterGridLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (priv->orientation != orientation) { priv->orientation = orientation; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_ORIENTATION]); } } /** * clutter_grid_layout_get_child_at: * @layout: a #ClutterGridLayout * @left: the left edge of the cell * @top: the top edge of the cell * * Gets the child of @layout whose area covers the grid * cell whose upper left corner is at @left, @top. * * Returns: (transfer none): the child at the given position, or %NULL * * Since: 1.12 */ ClutterActor * clutter_grid_layout_get_child_at (ClutterGridLayout *layout, gint left, gint top) { ClutterGridLayoutPrivate *priv; ClutterGridChild *grid_child; ClutterActorIter iter; ClutterActor *child; g_return_val_if_fail (CLUTTER_IS_GRID_LAYOUT (layout), NULL); priv = layout->priv; if (!priv->container) return NULL; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { grid_child = GET_GRID_CHILD (layout, child); if (CHILD_LEFT (grid_child) <= left && CHILD_LEFT (grid_child) + CHILD_WIDTH (grid_child) > left && CHILD_TOP (grid_child) <= top && CHILD_TOP (grid_child) + CHILD_HEIGHT (grid_child) > top) return child; } return NULL; } /** * clutter_grid_layout_insert_row: * @layout: a #ClutterGridLayout * @position: the position to insert the row at * * Inserts a row at the specified position. * * Children which are attached at or below this position * are moved one row down. Children which span across this * position are grown to span the new row. * * Since: 1.12 */ void clutter_grid_layout_insert_row (ClutterGridLayout *layout, gint position) { ClutterGridLayoutPrivate *priv; ClutterGridChild *grid_child; ClutterActorIter iter; ClutterActor *child; gint top, height; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (!priv->container) return; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { grid_child = GET_GRID_CHILD (layout, child); top = CHILD_TOP (grid_child); height = CHILD_HEIGHT (grid_child); if (top >= position) { CHILD_TOP (grid_child) = top + 1; g_object_notify_by_pspec (G_OBJECT (grid_child), child_props[PROP_CHILD_TOP_ATTACH]); } else if (top + height > position) { CHILD_HEIGHT (grid_child) = height + 1; g_object_notify_by_pspec (G_OBJECT (grid_child), child_props[PROP_CHILD_HEIGHT]); } } clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); } /** * clutter_grid_layout_insert_column: * @layout: a #ClutterGridLayout * @position: the position to insert the column at * * Inserts a column at the specified position. * * Children which are attached at or to the right of this position * are moved one column to the right. Children which span across this * position are grown to span the new column. * * Since: 1.12 */ void clutter_grid_layout_insert_column (ClutterGridLayout *layout, gint position) { ClutterGridLayoutPrivate *priv; ClutterGridChild *grid_child; ClutterActorIter iter; ClutterActor *child; gint left, width; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (!priv->container) return; clutter_actor_iter_init (&iter, CLUTTER_ACTOR (priv->container)); while (clutter_actor_iter_next (&iter, &child)) { grid_child = GET_GRID_CHILD (layout, child); left = CHILD_LEFT (grid_child); width = CHILD_WIDTH (grid_child); if (left >= position) { CHILD_LEFT (grid_child) = left + 1; g_object_notify_by_pspec (G_OBJECT (grid_child), child_props[PROP_CHILD_LEFT_ATTACH]); } else if (left + width > position) { CHILD_WIDTH (grid_child) = width + 1; g_object_notify_by_pspec (G_OBJECT (grid_child), child_props[PROP_CHILD_WIDTH]); } } clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); } /** * clutter_grid_layout_insert_next_to: * @layout: a #ClutterGridLayout * @sibling: the child of @layout that the new row or column will be * placed next to * @side: the side of @sibling that @child is positioned next to * * Inserts a row or column at the specified position. * * The new row or column is placed next to @sibling, on the side * determined by @side. If @side is %CLUTTER_GRID_POSITION_LEFT or * %CLUTTER_GRID_POSITION_BOTTOM, a row is inserted. If @side is * %CLUTTER_GRID_POSITION_LEFT of %CLUTTER_GRID_POSITION_RIGHT, * a column is inserted. * * Since: 1.12 */ void clutter_grid_layout_insert_next_to (ClutterGridLayout *layout, ClutterActor *sibling, ClutterGridPosition side) { ClutterGridChild *grid_child; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); g_return_if_fail (CLUTTER_IS_ACTOR (sibling)); grid_child = GET_GRID_CHILD (layout, sibling); switch (side) { case CLUTTER_GRID_POSITION_LEFT: clutter_grid_layout_insert_column (layout, CHILD_LEFT (grid_child)); break; case CLUTTER_GRID_POSITION_RIGHT: clutter_grid_layout_insert_column (layout, CHILD_LEFT (grid_child) + CHILD_WIDTH (grid_child)); break; case CLUTTER_GRID_POSITION_TOP: clutter_grid_layout_insert_row (layout, CHILD_TOP (grid_child)); break; case CLUTTER_GRID_POSITION_BOTTOM: clutter_grid_layout_insert_row (layout, CHILD_TOP (grid_child) + CHILD_HEIGHT (grid_child)); break; default: g_assert_not_reached (); } } /** * clutter_grid_layout_get_orientation: * @layout: a #ClutterGridLayout * * Retrieves the orientation of the @layout. * * Return value: the orientation of the layout * * Since: 1.12 */ ClutterOrientation clutter_grid_layout_get_orientation (ClutterGridLayout *layout) { g_return_val_if_fail (CLUTTER_IS_GRID_LAYOUT (layout), CLUTTER_ORIENTATION_HORIZONTAL); return layout->priv->orientation; } /** * clutter_grid_layout_set_row_spacing: * @layout: a #ClutterGridLayout * @spacing: the spacing between rows of the layout, in pixels * * Sets the spacing between rows of @layout * * Since: 1.12 */ void clutter_grid_layout_set_row_spacing (ClutterGridLayout *layout, guint spacing) { ClutterGridLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (COLUMNS (priv)->spacing != spacing) { COLUMNS (priv)->spacing = spacing; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_ROW_SPACING]); } } /** * clutter_grid_layout_get_row_spacing: * @layout: a #ClutterGridLayout * * Retrieves the spacing set using clutter_grid_layout_set_row_spacing() * * Return value: the spacing between rows of @layout * * Since: 1.12 */ guint clutter_grid_layout_get_row_spacing (ClutterGridLayout *layout) { ClutterGridLayoutPrivate *priv; g_return_val_if_fail (CLUTTER_IS_GRID_LAYOUT (layout), 0); priv = layout->priv; return COLUMNS (priv)->spacing; } /** * clutter_grid_layout_set_column_spacing: * @layout: a #ClutterGridLayout * @spacing: the spacing between columns of the layout, in pixels * * Sets the spacing between columns of @layout * * Since: 1.12 */ void clutter_grid_layout_set_column_spacing (ClutterGridLayout *layout, guint spacing) { ClutterGridLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (ROWS (priv)->spacing != spacing) { ROWS (priv)->spacing = spacing; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_COLUMN_SPACING]); } } /** * clutter_grid_layout_get_column_spacing: * @layout: a #ClutterGridLayout * * Retrieves the spacing set using clutter_grid_layout_set_column_spacing() * * Return value: the spacing between coluns of @layout * * Since: 1.12 */ guint clutter_grid_layout_get_column_spacing (ClutterGridLayout *layout) { ClutterGridLayoutPrivate *priv; g_return_val_if_fail (CLUTTER_IS_GRID_LAYOUT (layout), 0); priv = layout->priv; return ROWS (priv)->spacing; } /** * clutter_grid_layout_set_column_homogeneous: * @layout: a #ClutterGridLayout * @homogeneous: %TRUE to make columns homogeneous * * Sets whether all columns of @layout will have the same width. * * Since: 1.12 */ void clutter_grid_layout_set_column_homogeneous (ClutterGridLayout *layout, gboolean homogeneous) { ClutterGridLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (ROWS (priv)->homogeneous != homogeneous) { ROWS (priv)->homogeneous = homogeneous; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_COLUMN_HOMOGENEOUS]); } } /** * clutter_grid_layout_get_column_homogeneous: * @layout: a #ClutterGridLayout * * Returns whether all columns of @layout have the same width. * * Returns: whether all columns of @layout have the same width. */ gboolean clutter_grid_layout_get_column_homogeneous (ClutterGridLayout *layout) { ClutterGridLayoutPrivate *priv; g_return_val_if_fail (CLUTTER_IS_GRID_LAYOUT (layout), FALSE); priv = layout->priv; return ROWS (priv)->homogeneous; } /** * clutter_grid_layout_set_row_homogeneous: * @layout: a #ClutterGridLayout * @homogeneous: %TRUE to make rows homogeneous * * Sets whether all rows of @layout will have the same height. * * Since: 1.12 */ void clutter_grid_layout_set_row_homogeneous (ClutterGridLayout *layout, gboolean homogeneous) { ClutterGridLayoutPrivate *priv; g_return_if_fail (CLUTTER_IS_GRID_LAYOUT (layout)); priv = layout->priv; if (COLUMNS (priv)->homogeneous != homogeneous) { COLUMNS (priv)->homogeneous = homogeneous; clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (layout)); g_object_notify_by_pspec (G_OBJECT (layout), obj_props[PROP_ROW_HOMOGENEOUS]); } } /** * clutter_grid_layout_get_row_homogeneous: * @layout: a #ClutterGridLayout * * Returns whether all rows of @layout have the same height. * * Returns: whether all rows of @layout have the same height. * * Since: 1.12 */ gboolean clutter_grid_layout_get_row_homogeneous (ClutterGridLayout *layout) { ClutterGridLayoutPrivate *priv; g_return_val_if_fail (CLUTTER_IS_GRID_LAYOUT (layout), FALSE); priv = layout->priv; return COLUMNS (priv)->homogeneous; } muffin-5.2.1/clutter/clutter/clutter-version.h.in0000664000175000017500000002215714211404421022232 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * */ #ifndef __CLUTTER_VERSION_H__ #define __CLUTTER_VERSION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif /** * SECTION:clutter-version * @short_description: Versioning utility macros * * Clutter offers a set of macros for checking the version of the library * at compile time; it also provides a function to perform the same check * at run time. * * Clutter adds version information to both API deprecations and additions; * by definining the macros %CLUTTER_VERSION_MIN_REQUIRED and * %CLUTTER_VERSION_MAX_ALLOWED, you can specify the range of Clutter versions * whose API you want to use. Functions that were deprecated before, or * introduced after, this range will trigger compiler warnings. For instance, * if we define the following symbols: * * |[ * CLUTTER_VERSION_MIN_REQUIRED = CLUTTER_VERSION_1_6 * CLUTTER_VERSION_MAX_ALLOWED = CLUTTER_VERSION_1_8 * ]| * * and we have the following functions annotated in the Clutter headers: * * |[ * void clutter_function_A (void) CLUTTER_DEPRECATED_IN_1_4; * void clutter_function_B (void) CLUTTER_DEPRECATED_IN_1_6; * void clutter_function_C (void) CLUTTER_AVAILABLE_IN_1_8; * void clutter_function_D (void) CLUTTER_AVAILABLE_IN_1_10; * ]| * * then any application code using the functions above will get the output: * * |[ * clutter_function_A: deprecation warning * clutter_function_B: no warning * clutter_function_C: no warning * clutter_function_D: symbol not available warning * ]| * * It is possible to disable the compiler warnings by defining the macro * %CLUTTER_DISABLE_DEPRECATION_WARNINGS before including the clutter.h * header. */ #include G_BEGIN_DECLS /** * CLUTTER_MAJOR_VERSION: * * The major version of the Clutter library (1, if %CLUTTER_VERSION is 1.2.3) */ #define CLUTTER_MAJOR_VERSION (@CLUTTER_MAJOR_VERSION@) /** * CLUTTER_MINOR_VERSION: * * The minor version of the Clutter library (2, if %CLUTTER_VERSION is 1.2.3) */ #define CLUTTER_MINOR_VERSION (@CLUTTER_MINOR_VERSION@) /** * CLUTTER_MICRO_VERSION: * * The micro version of the Clutter library (3, if %CLUTTER_VERSION is 1.2.3) */ #define CLUTTER_MICRO_VERSION (@CLUTTER_MICRO_VERSION@) /** * CLUTTER_VERSION: * * The full version of the Clutter library, like 1.2.3 */ #define CLUTTER_VERSION @CLUTTER_VERSION@ /** * CLUTTER_VERSION_S: * * The full version of the Clutter library, in string form (suited for * string concatenation) */ #define CLUTTER_VERSION_S "@CLUTTER_VERSION@" /** * CLUTTER_VERSION_HEX: * * Numerically encoded version of the Clutter library, like 0x010203 */ #define CLUTTER_VERSION_HEX ((CLUTTER_MAJOR_VERSION << 24) | \ (CLUTTER_MINOR_VERSION << 16) | \ (CLUTTER_MICRO_VERSION << 8)) /* XXX - Every new stable minor release bump should add a macro here */ /** * CLUTTER_VERSION_1_0: * * A macro that evaluates to the 1.0 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.10 */ #define CLUTTER_VERSION_1_0 (G_ENCODE_VERSION (1, 0)) /** * CLUTTER_VERSION_1_2: * * A macro that evaluates to the 1.2 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.10 */ #define CLUTTER_VERSION_1_2 (G_ENCODE_VERSION (1, 2)) /** * CLUTTER_VERSION_1_4: * * A macro that evaluates to the 1.4 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.10 */ #define CLUTTER_VERSION_1_4 (G_ENCODE_VERSION (1, 4)) /** * CLUTTER_VERSION_1_6: * * A macro that evaluates to the 1.6 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.10 */ #define CLUTTER_VERSION_1_6 (G_ENCODE_VERSION (1, 6)) /** * CLUTTER_VERSION_1_8: * * A macro that evaluates to the 1.8 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.10 */ #define CLUTTER_VERSION_1_8 (G_ENCODE_VERSION (1, 8)) /** * CLUTTER_VERSION_1_10: * * A macro that evaluates to the 1.10 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.10 */ #define CLUTTER_VERSION_1_10 (G_ENCODE_VERSION (1, 10)) /** * CLUTTER_VERSION_1_12: * * A macro that evaluates to the 1.12 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.12 */ #define CLUTTER_VERSION_1_12 (G_ENCODE_VERSION (1, 12)) /** * CLUTTER_VERSION_1_14: * * A macro that evaluates to the 1.14 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.14 */ #define CLUTTER_VERSION_1_14 (G_ENCODE_VERSION (1, 14)) /** * CLUTTER_VERSION_1_16: * * A macro that evaluates to the 1.16 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define CLUTTER_VERSION_1_16 (G_ENCODE_VERSION (1, 16)) /** * CLUTTER_VERSION_1_18: * * A macro that evaluates to the 1.18 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.18 */ #define CLUTTER_VERSION_1_18 (G_ENCODE_VERSION (1, 18)) /** * CLUTTER_VERSION_1_20: * * A macro that evaluates to the 1.20 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.20 */ #define CLUTTER_VERSION_1_20 (G_ENCODE_VERSION (1, 20)) /** * CLUTTER_VERSION_1_22: * * A macro that evaluates to the 1.22 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.22 */ #define CLUTTER_VERSION_1_22 (G_ENCODE_VERSION (1, 22)) /** * CLUTTER_VERSION_1_24: * * A macro that evaluates to the 1.24 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.24 */ #define CLUTTER_VERSION_1_24 (G_ENCODE_VERSION (1, 24)) /** * CLUTTER_VERSION_1_26: * * A macro that evaluates to the 1.26 version of Clutter, in a format * that can be used by the C pre-processor. * * Since: 1.26 */ #define CLUTTER_VERSION_1_26 (G_ENCODE_VERSION (1, 26)) /* evaluates to the current stable version; for development cycles, * this means the next stable target */ #if (CLUTTER_MINOR_VERSION % 2) # define CLUTTER_VERSION_CUR_STABLE (G_ENCODE_VERSION (CLUTTER_MAJOR_VERSION, CLUTTER_MINOR_VERSION + 1)) #else # define CLUTTER_VERSION_CUR_STABLE (G_ENCODE_VERSION (CLUTTER_MAJOR_VERSION, CLUTTER_MINOR_VERSION)) #endif /* evaluates to the previous stable version */ #if (CLUTTER_MINOR_VERSION % 2) # define CLUTTER_VERSION_PREV_STABLE (G_ENCODE_VERSION (CLUTTER_MAJOR_VERSION, CLUTTER_MINOR_VERSION - 1)) #else # define CLUTTER_VERSION_PREV_STABLE (G_ENCODE_VERSION (CLUTTER_MAJOR_VERSION, CLUTTER_MINOR_VERSION - 2)) #endif /** * CLUTTER_CHECK_VERSION: * @major: major version, like 1 in 1.2.3 * @minor: minor version, like 2 in 1.2.3 * @micro: micro version, like 3 in 1.2.3 * * Evaluates to %TRUE if the version of the Clutter library is greater * than @major, @minor and @micro */ #define CLUTTER_CHECK_VERSION(major,minor,micro) \ (CLUTTER_MAJOR_VERSION > (major) || \ (CLUTTER_MAJOR_VERSION == (major) && CLUTTER_MINOR_VERSION > (minor)) || \ (CLUTTER_MAJOR_VERSION == (major) && CLUTTER_MINOR_VERSION == (minor) && CLUTTER_MICRO_VERSION >= (micro))) #ifndef _CLUTTER_EXTERN #define _CLUTTER_EXTERN extern #endif #define CLUTTER_VAR _CLUTTER_EXTERN /** * clutter_major_version: * * The major component of the Clutter library version, e.g. 1 if the version * is 1.2.3 * * This value can be used for run-time version checks * * For a compile-time check, use %CLUTTER_MAJOR_VERSION * * Since: 1.2 */ extern const guint clutter_major_version; /** * clutter_minor_version: * * The minor component of the Clutter library version, e.g. 2 if the version * is 1.2.3 * * This value can be used for run-time version checks * * For a compile-time check, use %CLUTTER_MINOR_VERSION * * Since: 1.2 */ extern const guint clutter_minor_version; /** * clutter_micro_version: * * The micro component of the Clutter library version, e.g. 3 if the version * is 1.2.3 * * This value can be used for run-time version checks * * For a compile-time check, use %CLUTTER_MICRO_VERSION * * Since: 1.2 */ extern const guint clutter_micro_version; G_END_DECLS #endif /* __CLUTTER_VERSION_H__ */ muffin-5.2.1/clutter/clutter/clutter-texture.h0000664000175000017500000000771014211404421021636 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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.1 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_TEXTURE_H__ #define __CLUTTER_TEXTURE_H__ #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_TEXTURE (clutter_texture_get_type ()) #define CLUTTER_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXTURE, ClutterTexture)) #define CLUTTER_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TEXTURE, ClutterTextureClass)) #define CLUTTER_IS_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXTURE)) #define CLUTTER_IS_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TEXTURE)) #define CLUTTER_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TEXTURE, ClutterTextureClass)) /** * ClutterTextureError: * @CLUTTER_TEXTURE_ERROR_OUT_OF_MEMORY: OOM condition * @CLUTTER_TEXTURE_ERROR_NO_YUV: YUV operation attempted but no YUV support * found * @CLUTTER_TEXTURE_ERROR_BAD_FORMAT: The requested format for * clutter_texture_set_from_rgb_data or * clutter_texture_set_from_yuv_data is unsupported. * * Error enumeration for #ClutterTexture * * Since: 0.4 */ typedef enum { CLUTTER_TEXTURE_ERROR_OUT_OF_MEMORY, CLUTTER_TEXTURE_ERROR_NO_YUV, CLUTTER_TEXTURE_ERROR_BAD_FORMAT } ClutterTextureError; /** * CLUTTER_TEXTURE_ERROR: * * Error domain for #ClutterTexture errors * * Since: 0.4 */ #define CLUTTER_TEXTURE_ERROR (clutter_texture_error_quark ()) CLUTTER_AVAILABLE_IN_ALL GQuark clutter_texture_error_quark (void); typedef struct _ClutterTexture ClutterTexture; typedef struct _ClutterTextureClass ClutterTextureClass; typedef struct _ClutterTexturePrivate ClutterTexturePrivate; /** * ClutterTexture: * * The #ClutterTexture structure contains only private data * and should be accessed using the provided API * * Since: 0.2 */ struct _ClutterTexture { /*< private >*/ ClutterActor parent; ClutterTexturePrivate *priv; }; /** * ClutterTextureClass: * @size_change: handler for the #ClutterTexture::size-change signal * @pixbuf_change: handler for the #ClutterTexture::pixbuf-change signal * @load_finished: handler for the #ClutterTexture::load-finished signal * * The #ClutterTextureClass structure contains only private data * * Since: 0.2 */ struct _ClutterTextureClass { /*< private >*/ ClutterActorClass parent_class; /*< public >*/ void (* size_change) (ClutterTexture *texture, gint width, gint height); void (* pixbuf_change) (ClutterTexture *texture); void (* load_finished) (ClutterTexture *texture, const GError *error); /*< private >*/ /* padding, for future expansion */ void (*_clutter_texture1) (void); void (*_clutter_texture2) (void); void (*_clutter_texture3) (void); void (*_clutter_texture4) (void); void (*_clutter_texture5) (void); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_texture_get_type (void) G_GNUC_CONST; G_END_DECLS #endif /* __CLUTTER_TEXTURE_H__ */ muffin-5.2.1/clutter/clutter/clutter-deprecated.h0000664000175000017500000000324714211404421022237 0ustar jpeisachjpeisach#ifndef __CLUTTER_DEPRECATED_H__ #define __CLUTTER_DEPRECATED_H__ #define __CLUTTER_DEPRECATED_H_INSIDE__ #include "deprecated/clutter-actor.h" #include "deprecated/clutter-alpha.h" #include "deprecated/clutter-animatable.h" #include "deprecated/clutter-animation.h" #include "deprecated/clutter-animator.h" #include "deprecated/clutter-backend.h" #include "deprecated/clutter-behaviour.h" #include "deprecated/clutter-behaviour-depth.h" #include "deprecated/clutter-behaviour-ellipse.h" #include "deprecated/clutter-behaviour-opacity.h" #include "deprecated/clutter-behaviour-path.h" #include "deprecated/clutter-behaviour-rotate.h" #include "deprecated/clutter-behaviour-scale.h" #include "deprecated/clutter-bin-layout.h" #include "deprecated/clutter-box.h" #include "deprecated/clutter-cairo-texture.h" #include "deprecated/clutter-container.h" #include "deprecated/clutter-frame-source.h" #include "deprecated/clutter-group.h" #include "deprecated/clutter-input-device.h" #include "deprecated/clutter-keysyms.h" #include "deprecated/clutter-list-model.h" #include "deprecated/clutter-main.h" #include "deprecated/clutter-media.h" #include "deprecated/clutter-model.h" #include "deprecated/clutter-rectangle.h" #include "deprecated/clutter-score.h" #include "deprecated/clutter-shader.h" #include "deprecated/clutter-stage-manager.h" #include "deprecated/clutter-stage.h" #include "deprecated/clutter-state.h" #include "deprecated/clutter-table-layout.h" #include "deprecated/clutter-texture.h" #include "deprecated/clutter-timeline.h" #include "deprecated/clutter-timeout-pool.h" #include "deprecated/clutter-util.h" #undef __CLUTTER_DEPRECATED_H_INSIDE__ #endif /* __CLUTTER_DEPRECATED_H__ */ muffin-5.2.1/clutter/clutter/clutter-child-meta.h0000664000175000017500000001024114211404421022136 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Jorn Baayen * Emmanuele Bassi * Tomas Frydrych * Øyvind Kolås * * Copyright (C) 2008 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, see . */ #ifndef __CLUTTER_CHILD_META_H__ #define __CLUTTER_CHILD_META_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_CHILD_META (clutter_child_meta_get_type ()) #define CLUTTER_CHILD_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CHILD_META, ClutterChildMeta)) #define CLUTTER_CHILD_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CHILD_META, ClutterChildMetaClass)) #define CLUTTER_IS_CHILD_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CHILD_META)) #define CLUTTER_IS_CHILD_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CHILD_META)) #define CLUTTER_CHILD_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CHILD_META, ClutterChildMetaClass)) typedef struct _ClutterChildMetaClass ClutterChildMetaClass; /** * ClutterChildMeta: * @container: the container handling this data * @actor: the actor wrapped by this data * * Base interface for container specific state for child actors. A child * data is meant to be used when you need to keep track of information * about each individual child added to a container. * * In order to use it you should create your own subclass of * #ClutterChildMeta and set the #ClutterContainerIface child_meta_type * interface member to your subclass type, like: * * |[ * static void * my_container_iface_init (ClutterContainerIface *iface) * { * // set the rest of the #ClutterContainer vtable * * container_iface->child_meta_type = MY_TYPE_CHILD_META; * } * ]| * * This will automatically create a #ClutterChildMeta of type * `MY_TYPE_CHILD_META` for every actor that is added to the container. * * The child data for an actor can be retrieved using the * clutter_container_get_child_meta() function. * * The properties of the data and your subclass can be manipulated with * clutter_container_child_set() and clutter_container_child_get() which * act like g_object_set() and g_object_get(). * * You can provide hooks for your own storage as well as control the * instantiation by overriding the #ClutterContainerIface virtual functions * #ClutterContainerIface.create_child_meta(), #ClutterContainerIface.destroy_child_meta(), * and #ClutterContainerIface.get_child_meta(). * * Since: 0.8 */ struct _ClutterChildMeta { /*< private >*/ GObject parent_instance; /*< public >*/ ClutterContainer *container; ClutterActor *actor; }; /** * ClutterChildMetaClass: * * The #ClutterChildMetaClass contains only private data * * Since: 0.8 */ struct _ClutterChildMetaClass { /*< private >*/ GObjectClass parent_class; }; CLUTTER_AVAILABLE_IN_ALL GType clutter_child_meta_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterContainer * clutter_child_meta_get_container (ClutterChildMeta *data); CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_child_meta_get_actor (ClutterChildMeta *data); G_END_DECLS #endif /* __CLUTTER_CHILD_META_H__ */ muffin-5.2.1/clutter/clutter/clutter-script-parser.c0000664000175000017500000020042314211404421022723 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009 Intel Corportation * * 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, see . * * Original author: * * Emmanuele Bassi */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "deprecated/clutter-alpha.h" #include "clutter-actor.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-script.h" #include "clutter-script-private.h" #include "clutter-scriptable.h" #include "clutter-stage-manager.h" #include "clutter-private.h" static void clutter_script_parser_object_end (JsonParser *parser, JsonObject *object); static void clutter_script_parser_parse_end (JsonParser *parser); #define clutter_script_parser_get_type _clutter_script_parser_get_type G_DEFINE_TYPE (ClutterScriptParser, clutter_script_parser, JSON_TYPE_PARSER); static void clutter_script_parser_class_init (ClutterScriptParserClass *klass) { JsonParserClass *parser_class = JSON_PARSER_CLASS (klass); parser_class->object_end = clutter_script_parser_object_end; parser_class->parse_end = clutter_script_parser_parse_end; } static void clutter_script_parser_init (ClutterScriptParser *parser) { } GType _clutter_script_get_type_from_symbol (const gchar *symbol) { static GModule *module = NULL; GTypeGetFunc func; GType gtype = G_TYPE_INVALID; if (!module) module = g_module_open (NULL, 0); if (g_module_symbol (module, symbol, (gpointer)&func)) gtype = func (); return gtype; } GType _clutter_script_get_type_from_class (const gchar *name) { static GModule *module = NULL; GString *symbol_name = g_string_sized_new (64); GType gtype = G_TYPE_INVALID; GTypeGetFunc func; gchar *symbol; gint i; if (G_UNLIKELY (!module)) module = g_module_open (NULL, 0); for (i = 0; name[i] != '\0'; i++) { gchar c = name[i]; /* the standard naming policy for GObject-based libraries * is: * * NAME := INITIAL_WORD WORD+ * INITIAL_WORD := [A-Z][a-z0-9]* * WORD := [A-Z]{1,2}[a-z0-9]+ | [A-Z]{2,} * * for instance: * * GString -> g_string * GtkCTree -> gtk_ctree * ClutterX11TexturePixmap -> clutter_x11_texture_pixmap * * see: * * http://mail.gnome.org/archives/gtk-devel-list/2007-June/msg00022.html * * and: * * http://git.gnome.org/cgit/gtk+/plain/gtk/gtkbuilderparser.c */ if ((c == g_ascii_toupper (c) && i > 0 && name[i - 1] != g_ascii_toupper (name[i - 1])) || (i > 2 && name[i] == g_ascii_toupper (name[i]) && name[i - 1] == g_ascii_toupper (name[i - 1]) && name[i - 2] == g_ascii_toupper (name[i - 2]))) g_string_append_c (symbol_name, '_'); g_string_append_c (symbol_name, g_ascii_tolower (c)); } g_string_append (symbol_name, "_get_type"); symbol = g_string_free (symbol_name, FALSE); if (g_module_symbol (module, symbol, (gpointer)&func)) { CLUTTER_NOTE (SCRIPT, "Type function: %s", symbol); gtype = func (); } free (symbol); return gtype; } /* * clutter_script_enum_from_string: * @type: a #GType for an enumeration type * @string: the enumeration value as a string * @enum_value: (out): return location for the enumeration value as an integer * * Converts an enumeration value inside @string into a numeric * value and places it into @enum_value. * * The enumeration value can be an integer, the enumeration nick * or the enumeration name, as part of the #GEnumValue structure. * * Return value: %TRUE if the conversion was successfull. */ gboolean _clutter_script_enum_from_string (GType type, const gchar *string, gint *enum_value) { GEnumClass *eclass; GEnumValue *ev; gchar *endptr; gint value; gboolean retval = TRUE; g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0); g_return_val_if_fail (string != NULL, 0); value = strtoul (string, &endptr, 0); if (endptr != string) /* parsed a number */ *enum_value = value; else { eclass = g_type_class_ref (type); ev = g_enum_get_value_by_name (eclass, string); if (!ev) ev = g_enum_get_value_by_nick (eclass, string); if (ev) *enum_value = ev->value; else retval = FALSE; g_type_class_unref (eclass); } return retval; } gboolean _clutter_script_flags_from_string (GType type, const gchar *string, gint *flags_value) { gchar *endptr, *prevptr; guint i, j, ret, value; gchar *flagstr; GFlagsValue *fv; const gchar *flag; g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0); g_return_val_if_fail (string != NULL, 0); ret = TRUE; value = strtoul (string, &endptr, 0); if (endptr != string) /* parsed a number */ *flags_value = value; else { GFlagsClass *fclass; fclass = g_type_class_ref (type); flagstr = g_strdup (string); for (value = i = j = 0; ; i++) { gboolean eos = (flagstr[i] == '\0') ? TRUE : FALSE; if (!eos && flagstr[i] != '|') continue; flag = &flagstr[j]; endptr = &flagstr[i]; if (!eos) { flagstr[i++] = '\0'; j = i; } /* trim spaces */ for (;;) { gunichar ch = g_utf8_get_char (flag); if (!g_unichar_isspace (ch)) break; flag = g_utf8_next_char (flag); } while (endptr > flag) { gunichar ch; prevptr = g_utf8_prev_char (endptr); ch = g_utf8_get_char (prevptr); if (!g_unichar_isspace (ch)) break; endptr = prevptr; } if (endptr > flag) { *endptr = '\0'; fv = g_flags_get_value_by_name (fclass, flag); if (!fv) fv = g_flags_get_value_by_nick (fclass, flag); if (fv) value |= fv->value; else { ret = FALSE; break; } } if (eos) { *flags_value = value; break; } } free (flagstr); g_type_class_unref (fclass); } return ret; } static gboolean parse_knot_from_array (JsonArray *array, ClutterKnot *knot) { if (json_array_get_length (array) != 2) return FALSE; knot->x = json_array_get_int_element (array, 0); knot->y = json_array_get_int_element (array, 1); return TRUE; } static gboolean parse_knot_from_object (JsonObject *object, ClutterKnot *knot) { if (json_object_has_member (object, "x")) knot->x = json_object_get_int_member (object, "x"); else knot->x = 0; if (json_object_has_member (object, "y")) knot->y = json_object_get_int_member (object, "y"); else knot->y = 0; return TRUE; } gboolean _clutter_script_parse_knot (ClutterScript *script, JsonNode *node, ClutterKnot *knot) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE); g_return_val_if_fail (node != NULL, FALSE); g_return_val_if_fail (knot != NULL, FALSE); switch (JSON_NODE_TYPE (node)) { case JSON_NODE_ARRAY: return parse_knot_from_array (json_node_get_array (node), knot); case JSON_NODE_OBJECT: return parse_knot_from_object (json_node_get_object (node), knot); default: break; } return FALSE; } static gboolean parse_geometry_from_array (JsonArray *array, ClutterGeometry *geometry) { if (json_array_get_length (array) != 4) return FALSE; geometry->x = json_array_get_int_element (array, 0); geometry->y = json_array_get_int_element (array, 1); geometry->width = json_array_get_int_element (array, 2); geometry->height = json_array_get_int_element (array, 3); return TRUE; } static gboolean parse_geometry_from_object (JsonObject *object, ClutterGeometry *geometry) { if (json_object_has_member (object, "x")) geometry->x = json_object_get_int_member (object, "x"); else geometry->x = 0; if (json_object_has_member (object, "y")) geometry->y = json_object_get_int_member (object, "y"); else geometry->y = 0; if (json_object_has_member (object, "width")) geometry->width = json_object_get_int_member (object, "width"); else geometry->width = 0; if (json_object_has_member (object, "height")) geometry->height = json_object_get_int_member (object, "height"); else geometry->height = 0; return TRUE; } gboolean _clutter_script_parse_geometry (ClutterScript *script, JsonNode *node, ClutterGeometry *geometry) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE); g_return_val_if_fail (node != NULL, FALSE); g_return_val_if_fail (geometry != NULL, FALSE); switch (JSON_NODE_TYPE (node)) { case JSON_NODE_ARRAY: return parse_geometry_from_array (json_node_get_array (node), geometry); case JSON_NODE_OBJECT: return parse_geometry_from_object (json_node_get_object (node), geometry); default: break; } return FALSE; } static gboolean parse_color_from_array (JsonArray *array, ClutterColor *color) { if (json_array_get_length (array) != 3 || json_array_get_length (array) != 4) return FALSE; color->red = CLAMP (json_array_get_int_element (array, 0), 0, 255); color->green = CLAMP (json_array_get_int_element (array, 1), 0, 255); color->blue = CLAMP (json_array_get_int_element (array, 2), 0, 255); if (json_array_get_length (array) == 4) color->alpha = CLAMP (json_array_get_int_element (array, 3), 0, 255); else color->alpha = 255; return TRUE; } static gboolean parse_color_from_object (JsonObject *object, ClutterColor *color) { if (json_object_has_member (object, "red")) color->red = CLAMP (json_object_get_int_member (object, "red"), 0, 255); else color->red = 0; if (json_object_has_member (object, "green")) color->green = CLAMP (json_object_get_int_member (object, "green"), 0, 255); else color->green = 0; if (json_object_has_member (object, "blue")) color->blue = CLAMP (json_object_get_int_member (object, "blue"), 0, 255); else color->blue = 0; if (json_object_has_member (object, "alpha")) color->alpha = CLAMP (json_object_get_int_member (object, "alpha"), 0, 255); else color->alpha = 255; return TRUE; } gboolean _clutter_script_parse_color (ClutterScript *script, JsonNode *node, ClutterColor *color) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE); g_return_val_if_fail (node != NULL, FALSE); g_return_val_if_fail (color != NULL, FALSE); switch (JSON_NODE_TYPE (node)) { case JSON_NODE_ARRAY: return parse_color_from_array (json_node_get_array (node), color); case JSON_NODE_OBJECT: return parse_color_from_object (json_node_get_object (node), color); case JSON_NODE_VALUE: return clutter_color_from_string (color, json_node_get_string (node)); default: break; } return FALSE; } static gboolean parse_point_from_array (JsonArray *array, ClutterPoint *point) { if (json_array_get_length (array) != 2) return FALSE; point->x = json_array_get_double_element (array, 0); point->y = json_array_get_double_element (array, 1); return TRUE; } static gboolean parse_point_from_object (JsonObject *object, ClutterPoint *point) { if (json_object_has_member (object, "x")) point->x = json_object_get_double_member (object, "x"); else point->x = 0.f; if (json_object_has_member (object, "y")) point->y = json_object_get_double_member (object, "y"); else point->y = 0.f; return TRUE; } gboolean _clutter_script_parse_point (ClutterScript *script, JsonNode *node, ClutterPoint *point) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE); g_return_val_if_fail (node != NULL, FALSE); g_return_val_if_fail (point != NULL, FALSE); switch (JSON_NODE_TYPE (node)) { case JSON_NODE_ARRAY: return parse_point_from_array (json_node_get_array (node), point); case JSON_NODE_OBJECT: return parse_point_from_object (json_node_get_object (node), point); default: break; } return FALSE; } static gboolean parse_size_from_array (JsonArray *array, ClutterSize *size) { if (json_array_get_length (array) != 2) return FALSE; size->width = json_array_get_double_element (array, 0); size->height = json_array_get_double_element (array, 1); return TRUE; } static gboolean parse_size_from_object (JsonObject *object, ClutterSize *size) { if (json_object_has_member (object, "width")) size->width = json_object_get_double_member (object, "width"); else size->width = 0.f; if (json_object_has_member (object, "height")) size->height = json_object_get_double_member (object, "height"); else size->height = 0.f; return TRUE; } gboolean _clutter_script_parse_size (ClutterScript *script, JsonNode *node, ClutterSize *size) { g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE); g_return_val_if_fail (node != NULL, FALSE); g_return_val_if_fail (size != NULL, FALSE); switch (JSON_NODE_TYPE (node)) { case JSON_NODE_ARRAY: return parse_size_from_array (json_node_get_array (node), size); case JSON_NODE_OBJECT: return parse_size_from_object (json_node_get_object (node), size); default: break; } return FALSE; } const gchar * _clutter_script_get_id_from_node (JsonNode *node) { JsonObject *object; switch (JSON_NODE_TYPE (node)) { case JSON_NODE_OBJECT: object = json_node_get_object (node); if (json_object_has_member (object, "id")) return json_object_get_string_member (object, "id"); break; case JSON_NODE_VALUE: return json_node_get_string (node); default: break; } return NULL; } static GList * parse_children (ObjectInfo *oinfo, JsonNode *node) { JsonArray *array; GList *retval; guint array_len, i; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) return NULL; retval = oinfo->children; array = json_node_get_array (node); array_len = json_array_get_length (array); for (i = 0; i < array_len; i++) { JsonNode *child = json_array_get_element (array, i); const gchar *id_; id_ = _clutter_script_get_id_from_node (child); if (id_ != NULL) retval = g_list_prepend (retval, g_strdup (id_)); } return g_list_reverse (retval); } static GList * parse_signals (ClutterScript *script, ObjectInfo *oinfo, JsonNode *node) { JsonArray *array; GList *retval; guint array_len, i; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) { _clutter_script_warn_invalid_value (script, "signals", "Array", node); return NULL; } retval = oinfo->signals; array = json_node_get_array (node); array_len = json_array_get_length (array); for (i = 0; i < array_len; i++) { JsonNode *val = json_array_get_element (array, i); SignalInfo *sinfo = NULL; JsonObject *object; const gchar *name; if (JSON_NODE_TYPE (val) != JSON_NODE_OBJECT) { _clutter_script_warn_invalid_value (script, "signals array", "Object", node); continue; } object = json_node_get_object (val); /* mandatory: "name" */ if (!json_object_has_member (object, "name")) { _clutter_script_warn_missing_attribute (script, NULL, "name"); continue; } else { name = json_object_get_string_member (object, "name"); if (!name) { _clutter_script_warn_invalid_value (script, "name", "string", val); continue; } } /* mandatory: "target-state" or "handler" */ if (json_object_has_member (object, "target-state")) { const gchar *state = NULL; const gchar *target = NULL; gboolean warp_to = FALSE; target = json_object_get_string_member (object, "target-state"); if (target == NULL) { _clutter_script_warn_invalid_value (script, "target-state", "string", val); continue; } if (json_object_has_member (object, "states")) state = json_object_get_string_member (object, "states"); if (json_object_has_member (object, "warp")) warp_to = json_object_get_boolean_member (object, "warp"); CLUTTER_NOTE (SCRIPT, "Added signal '%s' (states:%s, target-state:%s, warp:%s)", name, state != NULL ? state : "", target, warp_to ? "true" : "false"); sinfo = g_slice_new0 (SignalInfo); sinfo->is_handler = FALSE; sinfo->name = g_strdup (name); sinfo->state = g_strdup (state); sinfo->target = g_strdup (target); sinfo->warp_to = warp_to; } else if (json_object_has_member (object, "handler")) { const gchar *handler; const gchar *connect; GConnectFlags flags = 0; handler = json_object_get_string_member (object, "handler"); if (handler == NULL) { _clutter_script_warn_invalid_value (script, "handler", "string", val); continue; } /* optional: "object" */ if (json_object_has_member (object, "object")) connect = json_object_get_string_member (object, "object"); else connect = NULL; /* optional: "after" */ if (json_object_has_member (object, "after")) { if (json_object_get_boolean_member (object, "after")) flags |= G_CONNECT_AFTER; } /* optional: "swapped" */ if (json_object_has_member (object, "swapped")) { if (json_object_get_boolean_member (object, "swapped")) flags |= G_CONNECT_SWAPPED; } CLUTTER_NOTE (SCRIPT, "Added signal '%s' (handler:%s, object:%s, flags:%d)", name, handler, connect, flags); sinfo = g_slice_new0 (SignalInfo); sinfo->is_handler = TRUE; sinfo->name = g_strdup (name); sinfo->handler = g_strdup (handler); sinfo->object = g_strdup (connect); sinfo->flags = flags; } else _clutter_script_warn_missing_attribute (script, NULL, "handler or state"); if (sinfo != NULL) retval = g_list_prepend (retval, sinfo); } return retval; } static ClutterTimeline * construct_timeline (ClutterScript *script, JsonObject *object) { ClutterTimeline *retval = NULL; ObjectInfo *oinfo; GList *members, *l; /* we fake an ObjectInfo so we can reuse clutter_script_construct_object() * here; we do not save it inside the hash table, because if this had * been a named object then we wouldn't have ended up here in the first * place */ oinfo = g_slice_new0 (ObjectInfo); oinfo->gtype = CLUTTER_TYPE_TIMELINE; oinfo->id = g_strdup ("dummy"); members = json_object_get_members (object); for (l = members; l != NULL; l = l->next) { const gchar *name = l->data; JsonNode *node = json_object_get_member (object, name); PropertyInfo *pinfo = g_slice_new0 (PropertyInfo); pinfo->name = g_strdelimit (g_strdup (name), G_STR_DELIMITERS, '-'); pinfo->node = json_node_copy (node); oinfo->properties = g_list_prepend (oinfo->properties, pinfo); } g_list_free (members); _clutter_script_construct_object (script, oinfo); _clutter_script_apply_properties (script, oinfo); retval = CLUTTER_TIMELINE (oinfo->object); /* we transfer ownership to the alpha function, so we ref before * destroying the ObjectInfo to avoid the timeline going away */ g_object_ref (retval); object_info_free (oinfo); return retval; } /* define the names of the animation modes to match the ones * that developers might be more accustomed to */ static const struct { const gchar *name; ClutterAnimationMode mode; } animation_modes[] = { { "linear", CLUTTER_LINEAR }, { "easeInQuad", CLUTTER_EASE_IN_QUAD }, { "easeOutQuad", CLUTTER_EASE_OUT_QUAD }, { "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD }, { "easeInCubic", CLUTTER_EASE_IN_CUBIC }, { "easeOutCubic", CLUTTER_EASE_OUT_CUBIC }, { "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC }, { "easeInQuart", CLUTTER_EASE_IN_QUART }, { "easeOutQuart", CLUTTER_EASE_OUT_QUART }, { "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART }, { "easeInQuint", CLUTTER_EASE_IN_QUINT }, { "easeOutQuint", CLUTTER_EASE_OUT_QUINT }, { "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT }, { "easeInSine", CLUTTER_EASE_IN_SINE }, { "easeOutSine", CLUTTER_EASE_OUT_SINE }, { "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE }, { "easeInExpo", CLUTTER_EASE_IN_EXPO }, { "easeOutExpo", CLUTTER_EASE_OUT_EXPO }, { "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO }, { "easeInCirc", CLUTTER_EASE_IN_CIRC }, { "easeOutCirc", CLUTTER_EASE_OUT_CIRC }, { "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC }, { "easeInElastic", CLUTTER_EASE_IN_ELASTIC }, { "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC }, { "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC }, { "easeInBack", CLUTTER_EASE_IN_BACK }, { "easeOutBack", CLUTTER_EASE_OUT_BACK }, { "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK }, { "easeInBounce", CLUTTER_EASE_IN_BOUNCE }, { "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE }, { "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE }, }; static const gint n_animation_modes = G_N_ELEMENTS (animation_modes); gulong _clutter_script_resolve_animation_mode (JsonNode *node) { gint i, res = CLUTTER_CUSTOM_MODE; if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE) return CLUTTER_CUSTOM_MODE; if (json_node_get_value_type (node) == G_TYPE_INT64) return json_node_get_int (node); if (json_node_get_value_type (node) == G_TYPE_STRING) { const gchar *name = json_node_get_string (node); /* XXX - we might be able to optimize by changing the ordering * of the animation_modes array, e.g. * - special casing linear * - tokenizing ('ease', 'In', 'Sine') and matching on token * - binary searching? */ for (i = 0; i < n_animation_modes; i++) { if (strcmp (animation_modes[i].name, name) == 0) return animation_modes[i].mode; } if (_clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE, name, &res)) return res; g_warning ("Unable to find the animation mode '%s'", name); } return CLUTTER_CUSTOM_MODE; } static ClutterAlphaFunc resolve_alpha_func (const gchar *name) { static GModule *module = NULL; ClutterAlphaFunc func; CLUTTER_NOTE (SCRIPT, "Looking up '%s' alpha function", name); if (G_UNLIKELY (!module)) module = g_module_open (NULL, 0); if (g_module_symbol (module, name, (gpointer) &func)) { CLUTTER_NOTE (SCRIPT, "Found '%s' alpha function in the symbols table", name); return func; } return NULL; } GObject * _clutter_script_parse_alpha (ClutterScript *script, JsonNode *node) { GObject *retval = NULL; JsonObject *object; ClutterTimeline *timeline = NULL; ClutterAlphaFunc alpha_func = NULL; ClutterAnimationMode mode = CLUTTER_CUSTOM_MODE; JsonNode *val; gboolean unref_timeline = FALSE; if (JSON_NODE_TYPE (node) != JSON_NODE_OBJECT) return NULL; object = json_node_get_object (node); val = json_object_get_member (object, "timeline"); if (val) { if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE && json_node_get_string (val) != NULL) { const gchar *id_ = json_node_get_string (val); timeline = CLUTTER_TIMELINE (clutter_script_get_object (script, id_)); } else if (JSON_NODE_TYPE (val) == JSON_NODE_OBJECT) { timeline = construct_timeline (script, json_node_get_object (val)); unref_timeline = TRUE; } } val = json_object_get_member (object, "mode"); if (val != NULL) mode = _clutter_script_resolve_animation_mode (val); if (mode == CLUTTER_CUSTOM_MODE) { val = json_object_get_member (object, "function"); if (val && json_node_get_string (val) != NULL) { alpha_func = resolve_alpha_func (json_node_get_string (val)); if (!alpha_func) { g_warning ("Unable to find the function '%s' in the " "Clutter alpha functions or the symbols table", json_node_get_string (val)); } } } CLUTTER_NOTE (SCRIPT, "Parsed alpha: %s timeline (%p) (mode:%d, func:%p)", unref_timeline ? "implicit" : "explicit", timeline ? timeline : 0x0, mode != CLUTTER_CUSTOM_MODE ? mode : 0, alpha_func ? alpha_func : 0x0); retval = g_object_new (CLUTTER_TYPE_ALPHA, NULL); if (mode != CLUTTER_CUSTOM_MODE) clutter_alpha_set_mode (CLUTTER_ALPHA (retval), mode); if (alpha_func != NULL) clutter_alpha_set_func (CLUTTER_ALPHA (retval), alpha_func, NULL, NULL); clutter_alpha_set_timeline (CLUTTER_ALPHA (retval), timeline); /* if we created an implicit timeline, the Alpha has full ownership * of it now, since it won't be accessible from ClutterScript */ if (unref_timeline) g_object_unref (timeline); return retval; } static void clutter_script_parser_object_end (JsonParser *json_parser, JsonObject *object) { ClutterScriptParser *parser = CLUTTER_SCRIPT_PARSER (json_parser); ClutterScript *script = parser->script; ObjectInfo *oinfo; JsonNode *val; const gchar *id_; GList *members, *l; /* if the object definition does not have an 'id' field we'll * fake one for it... */ if (!json_object_has_member (object, "id")) { gchar *fake; /* ... unless it doesn't even have a type - in which case * it is an internal object definition and we're not * supposed to touch it */ if (!json_object_has_member (object, "type")) return; fake = _clutter_script_generate_fake_id (script); json_object_set_string_member (object, "id", fake); CLUTTER_NOTE (SCRIPT, "Adding fake id '%s' to object of type '%s'", json_object_get_string_member (object, "id"), json_object_get_string_member (object, "type")); free (fake); } if (!json_object_has_member (object, "type")) { val = json_object_get_member (object, "id"); _clutter_script_warn_missing_attribute (script, json_node_get_string (val), "type"); return; } id_ = json_object_get_string_member (object, "id"); CLUTTER_NOTE (SCRIPT, "Getting object info for object '%s'", id_); oinfo = _clutter_script_get_object_info (script, id_); if (oinfo == NULL) { const gchar *class_name; oinfo = g_slice_new0 (ObjectInfo); oinfo->merge_id = _clutter_script_get_last_merge_id (script); oinfo->id = g_strdup (id_); oinfo->has_unresolved = TRUE; class_name = json_object_get_string_member (object, "type"); oinfo->class_name = g_strdup (class_name); if (json_object_has_member (object, "type_func")) { const gchar *type_func; type_func = json_object_get_string_member (object, "type_func"); oinfo->type_func = g_strdup (type_func); /* remove the type_func member; we don't want it to * pollute the object members */ json_object_remove_member (object, "type_func"); } } if (json_object_has_member (object, "children")) { val = json_object_get_member (object, "children"); oinfo->children = parse_children (oinfo, val); json_object_remove_member (object, "children"); oinfo->has_unresolved = TRUE; } if (json_object_has_member (object, "signals")) { val = json_object_get_member (object, "signals"); oinfo->signals = parse_signals (script, oinfo, val); json_object_remove_member (object, "signals"); oinfo->has_unresolved = TRUE; } if (strcmp (oinfo->class_name, "ClutterStage") == 0 && json_object_has_member (object, "is-default")) { oinfo->is_actor = TRUE; oinfo->is_stage = TRUE; oinfo->is_stage_default = json_object_get_boolean_member (object, "is-default"); json_object_remove_member (object, "is-default"); } else oinfo->is_stage_default = FALSE; members = json_object_get_members (object); for (l = members; l; l = l->next) { const gchar *name = l->data; PropertyInfo *pinfo; JsonNode *node; CLUTTER_NOTE (SCRIPT, "Object '%s' member '%s'", oinfo->id, name); /* we have already parsed these */ if (strcmp (name, "id") == 0 || strcmp (name, "type") == 0) continue; node = json_object_get_member (object, name); /* this should not really happen; we're getting a list of * member names, and if one does not map a real member * value then it's likely that something has gone wrong */ if (G_UNLIKELY (node == NULL)) { CLUTTER_NOTE (SCRIPT, "Empty node for member '%s' of object '%s' (type: %s)", name, oinfo->id, oinfo->class_name); continue; } pinfo = g_slice_new (PropertyInfo); pinfo->name = g_strdup (name); pinfo->node = json_node_copy (node); pinfo->pspec = NULL; pinfo->is_child = g_str_has_prefix (name, "child::") ? TRUE : FALSE; pinfo->is_layout = g_str_has_prefix (name, "layout::") ? TRUE : FALSE; oinfo->properties = g_list_prepend (oinfo->properties, pinfo); oinfo->has_unresolved = TRUE; } g_list_free (members); CLUTTER_NOTE (SCRIPT, "Added object '%s' (type:%s, id:%d, props:%d, signals:%d)", oinfo->id, oinfo->class_name, oinfo->merge_id, g_list_length (oinfo->properties), g_list_length (oinfo->signals)); _clutter_script_add_object_info (script, oinfo); _clutter_script_construct_object (script, oinfo); } static void clutter_script_parser_parse_end (JsonParser *parser) { clutter_script_ensure_objects (CLUTTER_SCRIPT_PARSER (parser)->script); } gboolean _clutter_script_parse_translatable_string (ClutterScript *script, JsonNode *node, char **str) { JsonObject *obj; const char *string, *domain, *context; const char *res; gboolean translatable; if (!JSON_NODE_HOLDS_OBJECT (node)) return FALSE; obj = json_node_get_object (node); if (!(json_object_has_member (obj, "translatable") && json_object_has_member (obj, "string"))) return FALSE; translatable = json_object_get_boolean_member (obj, "translatable"); string = json_object_get_string_member (obj, "string"); if (string == NULL || *string == '\0') return FALSE; if (json_object_has_member (obj, "context")) context = json_object_get_string_member (obj, "context"); else context = NULL; if (json_object_has_member (obj, "domain")) domain = json_object_get_string_member (obj, "domain"); else domain = NULL; if (domain == NULL || *domain == '\0') domain = clutter_script_get_translation_domain (script); if (translatable) { if (context != NULL && *context != '\0') res = g_dpgettext2 (domain, context, string); else res = g_dgettext (domain, string); } else res = string; if (str != NULL) *str = g_strdup (res); return TRUE; } gboolean _clutter_script_parse_node (ClutterScript *script, GValue *value, const gchar *name, JsonNode *node, GParamSpec *pspec) { GValue node_value = G_VALUE_INIT; gboolean retval = FALSE; g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (node != NULL, FALSE); switch (JSON_NODE_TYPE (node)) { case JSON_NODE_OBJECT: /* if we don't have a GParamSpec we can't infer the type * of the property; this usually means that this property * is a custom member that will be parsed by the Scriptable * interface implementantion */ if (pspec == NULL && !G_IS_VALUE (value)) return FALSE; else { GType p_type; ObjectInfo *oinfo; const gchar *id_; if (G_IS_VALUE (value)) p_type = G_VALUE_TYPE (value); else { p_type = G_PARAM_SPEC_VALUE_TYPE (pspec); g_value_init (value, p_type); } if (g_type_is_a (p_type, G_TYPE_OBJECT)) { /* default GObject handling: we get the id and * retrieve the ObjectInfo for it; since the object * definitions are parsed leaf-first we are guaranteed * to have a defined object at this point */ id_ = _clutter_script_get_id_from_node (node); if (id_ == NULL || *id_ == '\0') return FALSE; oinfo = _clutter_script_get_object_info (script, id_); if (oinfo == NULL || oinfo->gtype == G_TYPE_INVALID ) return FALSE; if (g_type_is_a (oinfo->gtype, p_type)) { /* force construction, even though it should * not be necessary; we don't need the properties * to be applied as well: they will when the * ScriptParser finishes */ _clutter_script_construct_object (script, oinfo); g_value_set_object (value, oinfo->object); return TRUE; } } else if (p_type == CLUTTER_TYPE_KNOT) { ClutterKnot knot = { 0, }; /* knot := { "x" : (int), "y" : (int) } */ if (_clutter_script_parse_knot (script, node, &knot)) { g_value_set_boxed (value, &knot); return TRUE; } } else if (p_type == CLUTTER_TYPE_GEOMETRY) { ClutterGeometry geom = { 0, }; /* geometry := { * "x" : (int), * "y" : (int), * "width" : (int), * "height" : (int) * } */ if (_clutter_script_parse_geometry (script, node, &geom)) { g_value_set_boxed (value, &geom); return TRUE; } } else if (p_type == CLUTTER_TYPE_COLOR) { ClutterColor color = { 0, }; /* color := { * "red" : (int), * "green" : (int), * "blue" : (int), * "alpha" : (int) * } */ if (_clutter_script_parse_color (script, node, &color)) { g_value_set_boxed (value, &color); return TRUE; } } else if (p_type == CLUTTER_TYPE_POINT) { ClutterPoint point = CLUTTER_POINT_INIT_ZERO; if (_clutter_script_parse_point (script, node, &point)) { g_value_set_boxed (value, &point); return TRUE; } } else if (p_type == CLUTTER_TYPE_SIZE) { ClutterSize size = CLUTTER_SIZE_INIT_ZERO; if (_clutter_script_parse_size (script, node, &size)) { g_value_set_boxed (value, &size); return TRUE; } } else if (p_type == G_TYPE_STRING) { char *str = NULL; if (_clutter_script_parse_translatable_string (script, node, &str)) { g_value_take_string (value, str); return TRUE; } } } return FALSE; case JSON_NODE_ARRAY: if (!pspec && !G_IS_VALUE (value)) return FALSE; else { if (!G_IS_VALUE (value)) g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); if (G_VALUE_HOLDS (value, CLUTTER_TYPE_KNOT)) { ClutterKnot knot = { 0, }; /* knot := [ (int), (int) ] */ if (_clutter_script_parse_knot (script, node, &knot)) { g_value_set_boxed (value, &knot); return TRUE; } } else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_GEOMETRY)) { ClutterGeometry geom = { 0, }; /* geometry := [ (int), (int), (int), (int) ] */ if (_clutter_script_parse_geometry (script, node, &geom)) { g_value_set_boxed (value, &geom); return TRUE; } } else if (CLUTTER_VALUE_HOLDS_COLOR (value)) { ClutterColor color = { 0, }; /* color := [ (int), (int), (int), (int) ] */ if (_clutter_script_parse_color (script, node, &color)) { g_value_set_boxed (value, &color); return TRUE; } } else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_POINT)) { ClutterPoint point = CLUTTER_POINT_INIT_ZERO; if (_clutter_script_parse_point (script, node, &point)) { g_value_set_boxed (value, &point); return TRUE; } } else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_SIZE)) { ClutterSize size = CLUTTER_SIZE_INIT_ZERO; if (_clutter_script_parse_size (script, node, &size)) { g_value_set_boxed (value, &size); return TRUE; } } else if (G_VALUE_HOLDS (value, G_TYPE_STRV)) { JsonArray *array = json_node_get_array (node); guint i, array_len = json_array_get_length (array); GPtrArray *str_array = g_ptr_array_sized_new (array_len); /* strv := [ (str), (str), ... ] */ for (i = 0; i < array_len; i++) { JsonNode *val = json_array_get_element (array, i); if (JSON_NODE_TYPE (val) != JSON_NODE_VALUE && json_node_get_string (val) == NULL) continue; g_ptr_array_add (str_array, (gpointer) json_node_get_string (val)); } g_value_set_boxed (value, str_array->pdata); g_ptr_array_free (str_array, TRUE); return TRUE; } } return FALSE; case JSON_NODE_NULL: return FALSE; case JSON_NODE_VALUE: json_node_get_value (node, &node_value); if (!pspec && !G_IS_VALUE (value)) g_value_init (value, G_VALUE_TYPE (&node_value)); else if (pspec) g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value))) { /* fundamental JSON types */ case G_TYPE_INT64: case G_TYPE_DOUBLE: case G_TYPE_STRING: case G_TYPE_BOOLEAN: g_value_copy (&node_value, value); retval = TRUE; break; case G_TYPE_INT: g_value_set_int (value, g_value_get_int64 (&node_value)); retval = TRUE; break; case G_TYPE_UINT: g_value_set_uint (value, (guint) g_value_get_int64 (&node_value)); retval = TRUE; break; case G_TYPE_ULONG: g_value_set_ulong (value, (gulong) g_value_get_int64 (&node_value)); retval = TRUE; break; case G_TYPE_UCHAR: g_value_set_uchar (value, (guchar) g_value_get_int64 (&node_value)); retval = TRUE; break; case G_TYPE_FLOAT: if (G_VALUE_HOLDS (&node_value, G_TYPE_DOUBLE)) { g_value_set_float (value, g_value_get_double (&node_value)); retval = TRUE; } else if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64)) { g_value_set_float (value, g_value_get_int64 (&node_value)); retval = TRUE; } break; case G_TYPE_ENUM: if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64)) { g_value_set_enum (value, g_value_get_int64 (&node_value)); retval = TRUE; } else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING)) { gint enum_value; retval = _clutter_script_enum_from_string (G_VALUE_TYPE (value), g_value_get_string (&node_value), &enum_value); if (retval) g_value_set_enum (value, enum_value); } break; case G_TYPE_FLAGS: if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64)) { g_value_set_flags (value, g_value_get_int64 (&node_value)); retval = TRUE; } else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING)) { gint flags_value; retval = _clutter_script_flags_from_string (G_VALUE_TYPE (value), g_value_get_string (&node_value), &flags_value); if (retval) g_value_set_flags (value, flags_value); } break; case G_TYPE_BOXED: if (G_VALUE_HOLDS (value, CLUTTER_TYPE_COLOR)) { ClutterColor color = { 0, }; retval = _clutter_script_parse_color (script, node, &color); if (retval) clutter_value_set_color (value, &color); } break; case G_TYPE_OBJECT: if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING)) { const gchar *str = g_value_get_string (&node_value); GObject *object = clutter_script_get_object (script, str); if (object) { CLUTTER_NOTE (SCRIPT, "Assigning '%s' (%s) to property '%s'", str, G_OBJECT_TYPE_NAME (object), name); g_value_set_object (value, object); retval = TRUE; } } break; default: retval = FALSE; break; } if (G_VALUE_TYPE (value) == G_TYPE_GTYPE && G_VALUE_HOLDS (&node_value, G_TYPE_STRING)) { const gchar *str = g_value_get_string (&node_value); GType type = clutter_script_get_type_from_name (script, str); g_value_set_gtype (value, type); retval = TRUE; } g_value_unset (&node_value); break; } return retval; } static GList * clutter_script_translate_parameters (ClutterScript *script, GObject *object, const gchar *name, GList *properties, GArray **params) { ClutterScriptable *scriptable = NULL; ClutterScriptableIface *iface = NULL; GList *l, *unparsed; gboolean parse_custom = FALSE; *params = g_array_new (FALSE, FALSE, sizeof (GParameter)); if (CLUTTER_IS_SCRIPTABLE (object)) { scriptable = CLUTTER_SCRIPTABLE (object); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); if (iface->parse_custom_node) parse_custom = TRUE; } unparsed = NULL; for (l = properties; l != NULL; l = l->next) { PropertyInfo *pinfo = l->data; GParameter param = { NULL }; gboolean res = FALSE; if (pinfo->is_child || pinfo->is_layout) { CLUTTER_NOTE (SCRIPT, "Skipping %s property '%s'", pinfo->is_child ? "child" : "layout", pinfo->name); unparsed = g_list_prepend (unparsed, pinfo); continue; } CLUTTER_NOTE (SCRIPT, "Parsing %s property (id:%s)", pinfo->pspec ? "regular" : "custom", pinfo->name); if (parse_custom) res = iface->parse_custom_node (scriptable, script, ¶m.value, pinfo->name, pinfo->node); if (!res) res = _clutter_script_parse_node (script, ¶m.value, pinfo->name, pinfo->node, pinfo->pspec); if (!res) { CLUTTER_NOTE (SCRIPT, "Property '%s' ignored", pinfo->name); unparsed = g_list_prepend (unparsed, pinfo); continue; } param.name = g_strdup (pinfo->name); g_array_append_val (*params, param); property_info_free (pinfo); } g_list_free (properties); return unparsed; } static GList * clutter_script_construct_parameters (ClutterScript *script, GType gtype, const gchar *name, GList *properties, GArray **construct_params) { GObjectClass *klass; GList *l, *unparsed; klass = g_type_class_ref (gtype); g_assert (klass != NULL); *construct_params = g_array_new (FALSE, FALSE, sizeof (GParameter)); unparsed = NULL; for (l = properties; l != NULL; l = l->next) { PropertyInfo *pinfo = l->data; GParameter param = { NULL }; GParamSpec *pspec = NULL; /* we allow custom property names for classes, so if we * don't find a corresponding GObject property for this * class we just skip it and let the class itself deal * with it later on */ pspec = g_object_class_find_property (klass, pinfo->name); if (pspec) pinfo->pspec = g_param_spec_ref (pspec); else { pinfo->pspec = NULL; unparsed = g_list_prepend (unparsed, pinfo); continue; } if (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY)) { unparsed = g_list_prepend (unparsed, pinfo); continue; } param.name = g_strdup (pinfo->name); if (!_clutter_script_parse_node (script, ¶m.value, pinfo->name, pinfo->node, pinfo->pspec)) { unparsed = g_list_prepend (unparsed, pinfo); continue; } g_array_append_val (*construct_params, param); property_info_free (pinfo); } g_list_free (properties); g_type_class_unref (klass); return unparsed; } static void apply_layout_properties (ClutterScript *script, ClutterContainer *container, ClutterActor *actor, ObjectInfo *oinfo) { ClutterScriptable *scriptable = NULL; ClutterScriptableIface *iface = NULL; gboolean parse_custom_node = FALSE; GList *l, *unresolved, *properties; ClutterLayoutManager *manager; GType meta_type; manager = g_object_get_data (G_OBJECT (container), "clutter-layout-manager"); if (manager == NULL) return; meta_type = _clutter_layout_manager_get_child_meta_type (manager); if (meta_type == G_TYPE_INVALID) return; CLUTTER_NOTE (SCRIPT, "Layout manager of type '%s' with meta type '%s'", G_OBJECT_TYPE_NAME (manager), g_type_name (meta_type)); /* shortcut, to avoid typechecking every time */ if (CLUTTER_IS_SCRIPTABLE (manager)) { scriptable = CLUTTER_SCRIPTABLE (manager); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); parse_custom_node = iface->parse_custom_node != NULL ? TRUE : FALSE; } properties = oinfo->properties; oinfo->properties = NULL; unresolved = NULL; for (l = properties; l != NULL; l = l->next) { PropertyInfo *pinfo = l->data; GValue value = G_VALUE_INIT; gboolean res = FALSE; const gchar *name; if (!pinfo->is_layout) { unresolved = g_list_prepend (unresolved, pinfo); continue; } name = pinfo->name + strlen ("layout::"); pinfo->pspec = clutter_layout_manager_find_child_property (manager, name); if (pinfo->pspec != NULL) g_param_spec_ref (pinfo->pspec); CLUTTER_NOTE (SCRIPT, "Parsing %s layout property (id:%s)", pinfo->pspec != NULL ? "regular" : "custom", name); if (parse_custom_node) res = iface->parse_custom_node (scriptable, script, &value, name, pinfo->node); if (!res) res = _clutter_script_parse_node (script, &value, name, pinfo->node, pinfo->pspec); if (!res) { CLUTTER_NOTE (SCRIPT, "Layout property '%s' ignored", name); unresolved = g_list_prepend (unresolved, pinfo); continue; } CLUTTER_NOTE (SCRIPT, "Setting %s layout property '%s' (type:%s) to " "object '%s' (id:%s)", iface->set_custom_property != NULL ? "custom" : "regular", name, g_type_name (G_VALUE_TYPE (&value)), g_type_name (oinfo->gtype), oinfo->id); clutter_layout_manager_child_set_property (manager, container, actor, name, &value); g_value_unset (&value); property_info_free (pinfo); } g_list_free (properties); oinfo->properties = unresolved; } static void apply_child_properties (ClutterScript *script, ClutterContainer *container, ClutterActor *actor, ObjectInfo *oinfo) { ClutterScriptable *scriptable = NULL; ClutterScriptableIface *iface = NULL; gboolean parse_custom_node = FALSE; GList *l, *unresolved, *properties; GObjectClass *klass; GType meta_type; meta_type = CLUTTER_CONTAINER_GET_IFACE (container)->child_meta_type; if (meta_type == G_TYPE_INVALID) return; klass = G_OBJECT_GET_CLASS (container); /* shortcut, to avoid typechecking every time */ if (CLUTTER_IS_SCRIPTABLE (container)) { scriptable = CLUTTER_SCRIPTABLE (container); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); parse_custom_node = iface->parse_custom_node != NULL ? TRUE : FALSE; } properties = oinfo->properties; oinfo->properties = NULL; unresolved = NULL; for (l = properties; l != NULL; l = l->next) { PropertyInfo *pinfo = l->data; GValue value = G_VALUE_INIT; gboolean res = FALSE; const gchar *name; if (!pinfo->is_child) { unresolved = g_list_prepend (unresolved, pinfo); continue; } name = pinfo->name + strlen ("child::"); pinfo->pspec = clutter_container_class_find_child_property (klass, name); if (pinfo->pspec != NULL) g_param_spec_ref (pinfo->pspec); CLUTTER_NOTE (SCRIPT, "Parsing %s child property (id:%s)", pinfo->pspec != NULL ? "regular" : "custom", name); if (parse_custom_node) res = iface->parse_custom_node (scriptable, script, &value, name, pinfo->node); if (!res) res = _clutter_script_parse_node (script, &value, name, pinfo->node, pinfo->pspec); if (!res) { CLUTTER_NOTE (SCRIPT, "Child property '%s' ignored", name); unresolved = g_list_prepend (unresolved, pinfo); continue; } CLUTTER_NOTE (SCRIPT, "Setting %s child property '%s' (type:%s) to " "object '%s' (id:%s)", iface->set_custom_property != NULL ? "custom" : "regular", name, g_type_name (G_VALUE_TYPE (&value)), g_type_name (oinfo->gtype), oinfo->id); clutter_container_child_set_property (container, actor, name, &value); g_value_unset (&value); property_info_free (pinfo); } g_list_free (properties); oinfo->properties = unresolved; } static void add_children (ClutterScript *script, ObjectInfo *oinfo) { ClutterContainer *container = CLUTTER_CONTAINER (oinfo->object); GList *l, *unresolved; unresolved = NULL; for (l = oinfo->children; l != NULL; l = l->next) { const gchar *name = l->data; GObject *object = NULL; ObjectInfo *child_info; child_info = _clutter_script_get_object_info (script, name); if (child_info != NULL) { _clutter_script_construct_object (script, child_info); object = child_info->object; } if (object == NULL) { unresolved = g_list_prepend (unresolved, g_strdup (name)); continue; } if (!CLUTTER_IS_ACTOR (object)) { g_warning ("The object definition '%s' (type: %s) is not " "an actor, but it is referenced in the 'children' " "member of the container '%s' (type: %s); skipping.", child_info->id, g_type_name (child_info->gtype), oinfo->id, g_type_name (oinfo->gtype)); continue; } CLUTTER_NOTE (SCRIPT, "Adding children '%s' to actor of type '%s'", name, g_type_name (G_OBJECT_TYPE (container))); clutter_container_add_actor (container, CLUTTER_ACTOR (object)); } g_list_foreach (oinfo->children, (GFunc) free, NULL); g_list_free (oinfo->children); oinfo->children = unresolved; } static inline void _clutter_script_check_unresolved (ClutterScript *script, ObjectInfo *oinfo) { if (oinfo->children != NULL && CLUTTER_IS_CONTAINER (oinfo->object)) add_children (script, oinfo); /* this is a bit *eugh*, but it allows us to effectively make sure * that child and layout properties are parsed and applied to the * right child */ if (oinfo->properties != NULL && CLUTTER_IS_ACTOR (oinfo->object)) { ClutterActor *parent; parent = clutter_actor_get_parent (CLUTTER_ACTOR (oinfo->object)); if (parent != NULL) { ClutterContainer *container = CLUTTER_CONTAINER (parent); ClutterActor *child; for (child = clutter_actor_get_first_child (parent); child != NULL; child = clutter_actor_get_next_sibling (child)) { ObjectInfo *child_info; const gchar *id_; id_ = clutter_get_script_id (G_OBJECT (child)); if (id_ == NULL || *id_ == '\0') continue; child_info = _clutter_script_get_object_info (script, id_); if (child_info == NULL) continue; apply_child_properties (script, container, child, child_info); apply_layout_properties (script, container, child, child_info); } } } if (oinfo->properties || oinfo->children) oinfo->has_unresolved = TRUE; else oinfo->has_unresolved = FALSE; } void _clutter_script_apply_properties (ClutterScript *script, ObjectInfo *oinfo) { ClutterScriptable *scriptable = NULL; ClutterScriptableIface *iface = NULL; gboolean set_custom_property = FALSE; GObject *object = oinfo->object; GList *properties; GArray *params; guint i; if (!oinfo->has_unresolved) return; /* shortcut, to avoid typechecking every time */ if (CLUTTER_IS_SCRIPTABLE (object)) { scriptable = CLUTTER_SCRIPTABLE (object); iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable); if (iface->set_custom_property) set_custom_property = TRUE; } /* then we get the rest of the parameters, asking the object itself * to translate them for us, if we cannot do that */ properties = oinfo->properties; oinfo->properties = clutter_script_translate_parameters (script, object, oinfo->id, properties, ¶ms); /* consume all the properties we could translate in this pass */ for (i = 0; i < params->len; i++) { GParameter *param = &g_array_index (params, GParameter, i); CLUTTER_NOTE (SCRIPT, "Setting %s property '%s' (type:%s) to object '%s' (id:%s)", set_custom_property ? "custom" : "regular", param->name, g_type_name (G_VALUE_TYPE (¶m->value)), g_type_name (oinfo->gtype), oinfo->id); if (set_custom_property) iface->set_custom_property (scriptable, script, param->name, ¶m->value); else g_object_set_property (object, param->name, ¶m->value); free ((gchar *) param->name); g_value_unset (¶m->value); } g_array_free (params, TRUE); _clutter_script_check_unresolved (script, oinfo); } void _clutter_script_construct_object (ClutterScript *script, ObjectInfo *oinfo) { GArray *params = NULL; guint i; /* we have completely updated the object */ if (oinfo->object != NULL) { if (oinfo->has_unresolved) _clutter_script_check_unresolved (script, oinfo); return; } if (oinfo->gtype == G_TYPE_INVALID) { if (G_UNLIKELY (oinfo->type_func)) oinfo->gtype = _clutter_script_get_type_from_symbol (oinfo->type_func); else oinfo->gtype = clutter_script_get_type_from_name (script, oinfo->class_name); if (G_UNLIKELY (oinfo->gtype == G_TYPE_INVALID)) return; } oinfo->is_actor = g_type_is_a (oinfo->gtype, CLUTTER_TYPE_ACTOR); if (oinfo->is_actor) oinfo->is_stage = g_type_is_a (oinfo->gtype, CLUTTER_TYPE_STAGE); if (oinfo->is_stage && oinfo->is_stage_default) { ClutterStageManager *manager = clutter_stage_manager_get_default (); GList *properties = oinfo->properties; ClutterStage *default_stage; /* the default stage is a complex beast: we cannot create it using * g_object_newv() but we need clutter_script_construct_parameters() * to add the GParamSpec to the PropertyInfo pspec member, so * that we don't have to implement every complex property (like * the "color" one) directly inside the ClutterStage class. */ oinfo->properties = clutter_script_construct_parameters (script, oinfo->gtype, oinfo->id, properties, ¶ms); default_stage = clutter_stage_manager_get_default_stage (manager); oinfo->object = G_OBJECT (default_stage); for (i = 0; i < params->len; i++) { GParameter *param = &g_array_index (params, GParameter, i); free ((gchar *) param->name); g_value_unset (¶m->value); } g_array_free (params, TRUE); } else { GList *properties = oinfo->properties; GParameter *parameters; /* every other object: first, we get the construction parameters */ oinfo->properties = clutter_script_construct_parameters (script, oinfo->gtype, oinfo->id, properties, ¶ms); parameters = (GParameter *) (void *) params->data; oinfo->object = g_object_newv (oinfo->gtype, params->len, parameters); /* by sinking the floating reference, we make sure that the reference * count is correct whether the object is referenced from somewhere * else too or only by this ClutterScript object. */ g_object_ref_sink (oinfo->object); for (i = 0; i < params->len; i++) { GParameter *param = &g_array_index (params, GParameter, i); free ((gchar *) param->name); g_value_unset (¶m->value); } g_array_free (params, TRUE); } g_assert (oinfo->object != NULL); if (CLUTTER_IS_SCRIPTABLE (oinfo->object)) clutter_scriptable_set_id (CLUTTER_SCRIPTABLE (oinfo->object), oinfo->id); else g_object_set_data_full (oinfo->object, "clutter-script-id", g_strdup (oinfo->id), free); _clutter_script_check_unresolved (script, oinfo); } muffin-5.2.1/clutter/clutter/clutter-path-constraint.h0000664000175000017500000000525714211404421023260 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_PATH_CONSTRAINT_H__ #define __CLUTTER_PATH_CONSTRAINT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_PATH_CONSTRAINT (clutter_path_constraint_get_type ()) #define CLUTTER_PATH_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PATH_CONSTRAINT, ClutterPathConstraint)) #define CLUTTER_IS_PATH_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PATH_CONSTRAINT)) /** * ClutterPathConstraint: * * #ClutterPathConstraint is an opaque structure * whose members cannot be directly accessed * * Since: 1.6 */ typedef struct _ClutterPathConstraint ClutterPathConstraint; typedef struct _ClutterPathConstraintClass ClutterPathConstraintClass; CLUTTER_AVAILABLE_IN_1_6 GType clutter_path_constraint_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_6 ClutterConstraint *clutter_path_constraint_new (ClutterPath *path, gfloat offset); CLUTTER_AVAILABLE_IN_1_6 void clutter_path_constraint_set_path (ClutterPathConstraint *constraint, ClutterPath *path); CLUTTER_AVAILABLE_IN_1_6 ClutterPath * clutter_path_constraint_get_path (ClutterPathConstraint *constraint); CLUTTER_AVAILABLE_IN_1_6 void clutter_path_constraint_set_offset (ClutterPathConstraint *constraint, gfloat offset); CLUTTER_AVAILABLE_IN_1_6 gfloat clutter_path_constraint_get_offset (ClutterPathConstraint *constraint); G_END_DECLS #endif /* __CLUTTER_PATH_CONSTRAINT_H__ */ muffin-5.2.1/clutter/clutter/clutter-stage-manager.h0000664000175000017500000000613114211404421022645 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 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, see . * * Author: Emmanuele Bassi */ #ifndef __CLUTTER_STAGE_MANAGER_H__ #define __CLUTTER_STAGE_MANAGER_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_STAGE_MANAGER (clutter_stage_manager_get_type ()) #define CLUTTER_STAGE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_MANAGER, ClutterStageManager)) #define CLUTTER_IS_STAGE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_MANAGER)) #define CLUTTER_STAGE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_MANAGER, ClutterStageManagerClass)) #define CLUTTER_IS_STAGE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_MANAGER)) #define CLUTTER_STAGE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_MANAGER, ClutterStageManagerClass)) typedef struct _ClutterStageManager ClutterStageManager; typedef struct _ClutterStageManagerClass ClutterStageManagerClass; /** * ClutterStageManager: * * The #ClutterStageManager structure is private. * * Since: 1.0 */ /** * ClutterStageManagerClass: * * The #ClutterStageManagerClass structure contains only private data * and should be accessed using the provided API * * Since: 1.0 */ struct _ClutterStageManagerClass { /*< private >*/ GObjectClass parent_class; void (* stage_added) (ClutterStageManager *stage_manager, ClutterStage *stage); void (* stage_removed) (ClutterStageManager *stage_manager, ClutterStage *stage); }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_stage_manager_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterStageManager *clutter_stage_manager_get_default (void); CLUTTER_AVAILABLE_IN_1_0 ClutterStage * clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager); CLUTTER_AVAILABLE_IN_1_0 GSList * clutter_stage_manager_list_stages (ClutterStageManager *stage_manager); CLUTTER_AVAILABLE_IN_1_0 const GSList * clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager); G_END_DECLS #endif /* __CLUTTER_STAGE_MANAGER_H__ */ muffin-5.2.1/clutter/clutter/clutter-stage.h0000664000175000017500000002614214211404421021241 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ #ifndef __CLUTTER_STAGE_H__ #define __CLUTTER_STAGE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS #define CLUTTER_TYPE_STAGE (clutter_stage_get_type()) #define CLUTTER_STAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE, ClutterStage)) #define CLUTTER_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE, ClutterStageClass)) #define CLUTTER_IS_STAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE)) #define CLUTTER_IS_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE)) #define CLUTTER_STAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE, ClutterStageClass)) typedef struct _ClutterStageClass ClutterStageClass; typedef struct _ClutterStagePrivate ClutterStagePrivate; /** * ClutterStage: * * The #ClutterStage structure contains only private data * and should be accessed using the provided API * * Since: 0.2 */ struct _ClutterStage { /*< private >*/ ClutterGroup parent_instance; ClutterStagePrivate *priv; }; /** * ClutterStageClass: * @fullscreen: handler for the #ClutterStage::fullscreen signal * @unfullscreen: handler for the #ClutterStage::unfullscreen signal * @activate: handler for the #ClutterStage::activate signal * @deactivate: handler for the #ClutterStage::deactivate signal * @delete_event: handler for the #ClutterStage::delete-event signal * * The #ClutterStageClass structure contains only private data * * Since: 0.2 */ struct _ClutterStageClass { /*< private >*/ ClutterGroupClass parent_class; /*< public >*/ /* signals */ void (* fullscreen) (ClutterStage *stage); void (* unfullscreen) (ClutterStage *stage); void (* activate) (ClutterStage *stage); void (* deactivate) (ClutterStage *stage); gboolean (* delete_event) (ClutterStage *stage, ClutterEvent *event); /*< private >*/ /* padding for future expansion */ gpointer _padding_dummy[31]; }; /** * ClutterPerspective: * @fovy: the field of view angle, in degrees, in the y direction * @aspect: the aspect ratio that determines the field of view in the x * direction. The aspect ratio is the ratio of x (width) to y (height) * @z_near: the distance from the viewer to the near clipping * plane (always positive) * @z_far: the distance from the viewer to the far clipping * plane (always positive) * * Stage perspective definition. #ClutterPerspective is only used by * the fixed point version of clutter_stage_set_perspective(). * * Since: 0.4 */ struct _ClutterPerspective { gfloat fovy; gfloat aspect; gfloat z_near; gfloat z_far; }; /** * ClutterFog: * @z_near: starting distance from the viewer to the near clipping * plane (always positive) * @z_far: final distance from the viewer to the far clipping * plane (always positive) * * Fog settings used to create the depth cueing effect. * * Since: 0.6 * * Deprecated: 1.10: The fog-related API in #ClutterStage has been * deprecated as well. */ struct _ClutterFog { gfloat z_near; gfloat z_far; }; /** * ClutterFrameInfo: (skip) */ struct _ClutterFrameInfo { int64_t frame_counter; int64_t presentation_time; float refresh_rate; }; typedef struct _ClutterCapture { cairo_surface_t *image; cairo_rectangle_int_t rect; } ClutterCapture; CLUTTER_AVAILABLE_IN_ALL GType clutter_perspective_get_type (void) G_GNUC_CONST; CLUTTER_DEPRECATED_IN_1_10 GType clutter_fog_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL GType clutter_stage_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_stage_new (void); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_perspective (ClutterStage *stage, ClutterPerspective *perspective); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_get_perspective (ClutterStage *stage, ClutterPerspective *perspective); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_fullscreen (ClutterStage *stage, gboolean fullscreen); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_get_fullscreen (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_show_cursor (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_hide_cursor (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_title (ClutterStage *stage, const gchar *title); CLUTTER_AVAILABLE_IN_ALL const gchar * clutter_stage_get_title (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_user_resizable (ClutterStage *stage, gboolean resizable); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_get_user_resizable (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_minimum_size (ClutterStage *stage, guint width, guint height); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_get_minimum_size (ClutterStage *stage, guint *width, guint *height); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_no_clear_hint (ClutterStage *stage, gboolean no_clear); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_get_no_clear_hint (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_use_alpha (ClutterStage *stage, gboolean use_alpha); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_get_use_alpha (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_key_focus (ClutterStage *stage, ClutterActor *actor); CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_stage_get_key_focus (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_throttle_motion_events (ClutterStage *stage, gboolean throttle); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_get_throttle_motion_events (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_motion_events_enabled (ClutterStage *stage, gboolean enabled); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_get_motion_events_enabled (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_set_accept_focus (ClutterStage *stage, gboolean accept_focus); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_get_accept_focus (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_stage_event (ClutterStage *stage, ClutterEvent *event); CLUTTER_AVAILABLE_IN_ALL ClutterActor * clutter_stage_get_actor_at_pos (ClutterStage *stage, ClutterPickMode pick_mode, gint x, gint y); CLUTTER_AVAILABLE_IN_ALL guchar * clutter_stage_read_pixels (ClutterStage *stage, gint x, gint y, gint width, gint height); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_get_redraw_clip_bounds (ClutterStage *stage, cairo_rectangle_int_t *clip); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_ensure_viewport (ClutterStage *stage); CLUTTER_AVAILABLE_IN_ALL void clutter_stage_ensure_redraw (ClutterStage *stage); #ifdef CLUTTER_ENABLE_EXPERIMENTAL_API CLUTTER_AVAILABLE_IN_1_14 void clutter_stage_set_sync_delay (ClutterStage *stage, gint sync_delay); CLUTTER_AVAILABLE_IN_1_14 void clutter_stage_skip_sync_delay (ClutterStage *stage); #endif CLUTTER_AVAILABLE_IN_MUFFIN gboolean clutter_stage_capture (ClutterStage *stage, gboolean paint, cairo_rectangle_int_t *rect, ClutterCapture **captures, int *n_captures); G_END_DECLS #endif /* __CLUTTER_STAGE_H__ */ muffin-5.2.1/clutter/clutter/clutter-master-clock-default.c0000664000175000017500000005165714211404421024150 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Emmanuele Bassi * * Copyright (C) 2009 Intel Corporation. * * 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, see . */ /* * SECTION:clutter-master-clock-default * @short_description: The default master clock for all animations * * The #ClutterMasterClockDefault class is the default implementation * of #ClutterMasterClock. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-master-clock.h" #include "clutter-master-clock-default.h" #include "clutter-debug.h" #include "clutter-private.h" #include "clutter-stage-manager-private.h" #include "clutter-stage-private.h" #include "clutter-muffin.h" #ifdef CLUTTER_ENABLE_DEBUG #define clutter_warn_if_over_budget(master_clock,start_time,section) G_STMT_START { \ gint64 __delta = g_get_monotonic_time () - start_time; \ gint64 __budget = master_clock->remaining_budget; \ if (__budget > 0 && __delta >= __budget) { \ _clutter_diagnostic_message ("%s took %" G_GINT64_FORMAT " microseconds " \ "more than the remaining budget of %" G_GINT64_FORMAT \ " microseconds", \ section, __delta - __budget, __budget); \ } } G_STMT_END #else #define clutter_warn_if_over_budget(master_clock,start_time,section) #endif typedef struct _ClutterClockSource ClutterClockSource; struct _ClutterMasterClockDefault { GObject parent_instance; /* the list of timelines handled by the clock */ GSList *timelines; SyncMethod preferred_sync_method, active_sync_method; /* the current state of the clock, in usecs */ gint64 cur_tick; /* the previous state of the clock, in usecs, used to compute the delta */ gint64 prev_tick; #ifdef CLUTTER_ENABLE_DEBUG gint64 frame_budget; gint64 remaining_budget; #endif /* an idle source, used by the Master Clock to queue * a redraw on the stage and drive the animations */ GSource *source; guint ensure_next_iteration : 1; guint paused : 1; guint sync_available : 1; }; struct _ClutterClockSource { GSource source; ClutterMasterClockDefault *master_clock; }; static gboolean clutter_clock_prepare (GSource *source, gint *timeout); static gboolean clutter_clock_check (GSource *source); static gboolean clutter_clock_dispatch (GSource *source, GSourceFunc callback, gpointer user_data); static GSourceFuncs clock_funcs = { clutter_clock_prepare, clutter_clock_check, clutter_clock_dispatch, NULL }; static void clutter_master_clock_iface_init (ClutterMasterClockIface *iface); static gint64 master_clock_next_frame_time (ClutterMasterClockDefault *); #define clutter_master_clock_default_get_type _clutter_master_clock_default_get_type G_DEFINE_TYPE_WITH_CODE (ClutterMasterClockDefault, clutter_master_clock_default, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MASTER_CLOCK, clutter_master_clock_iface_init)); static ClutterMasterClockDefault *master_clock_global = NULL; /* * master_clock_is_running: * @master_clock: a #ClutterMasterClock * * Checks if we should currently be advancing timelines or redrawing * stages. * * Return value: %TRUE if the #ClutterMasterClock has at least * one running timeline */ static gboolean master_clock_is_running (ClutterMasterClockDefault *master_clock) { ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); const GSList *stages, *l; if (master_clock->paused) return FALSE; if (master_clock->timelines) return TRUE; if (master_clock->ensure_next_iteration) { master_clock->ensure_next_iteration = FALSE; return TRUE; } stages = stage_manager->stages; for (l = stages; l; l = l->next) { if (clutter_actor_is_mapped (l->data) && (_clutter_stage_has_queued_events (l->data) || _clutter_stage_needs_update (l->data))) return TRUE; } return FALSE; } static gint64 master_clock_get_hw_update_time (ClutterMasterClockDefault *master_clock) { ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); const GSList *stages, *l; gint64 min_update_time = -1; stages = stage_manager->stages;; for (l = stages; l != NULL; l = l->next) { gint64 update_time = _clutter_stage_get_update_time (l->data); if (min_update_time == -1 || (update_time != -1 && update_time < min_update_time)) min_update_time = update_time; } return min_update_time; } static void master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock) { ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); const GSList *stages, *l; stages = stage_manager->stages; for (l = stages; l != NULL; l = l->next) _clutter_stage_schedule_update (l->data); } static GSList * master_clock_list_ready_stages (ClutterMasterClockDefault *master_clock) { ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); const GSList *stages, *l; GSList *result; stages = stage_manager->stages;; result = NULL; for (l = stages; l != NULL; l = l->next) { gint64 update_time = -1; if (master_clock->active_sync_method == SYNC_PRESENTATION_TIME) update_time = _clutter_stage_get_update_time (l->data); /* We carefully avoid to update stages that aren't mapped, because * they have nothing to render and this could cause a deadlock with * some of the SwapBuffers implementations (in particular * GLX_INTEL_swap_event is not emitted if nothing was rendered). */ if (clutter_actor_is_mapped (l->data) && update_time <= master_clock->cur_tick) result = g_slist_prepend (result, g_object_ref (l->data)); } return g_slist_reverse (result); } static void master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock, GSList *stages) { const GSList *l; for (l = stages; l != NULL; l = l->next) { /* Clear the old update time */ _clutter_stage_clear_update_time (l->data); /* And if there is still work to be done, schedule a new one */ if (master_clock->timelines || _clutter_stage_has_queued_events (l->data) || _clutter_stage_needs_update (l->data)) _clutter_stage_schedule_update (l->data); } } /* * master_clock_next_frame_time: * @master_clock: a #ClutterMasterClock * * Computes the optimal next frame time for dispatching the master clock. * Wherever possible this will be higher than master_clock->prev_tick. * * The goal here is to trigger dispatches as seldom as possible, but often * enough to maintain full frame rate. * * Return value: A valid timestamp in microseconds. Never fails. */ static gint64 master_clock_next_frame_time (ClutterMasterClockDefault *master_clock) { gint64 next, now, interval; if (master_clock->preferred_sync_method >= SYNC_PRESENTATION_TIME) { next = master_clock_get_hw_update_time (master_clock); if (next >= 0) { master_clock->active_sync_method = SYNC_PRESENTATION_TIME; return next; } } now = g_source_get_time (master_clock->source); if (!master_clock->prev_tick || master_clock->preferred_sync_method == SYNC_NONE) { master_clock->active_sync_method = SYNC_NONE; return now; } /* We will usually have backend hardware features available to throttle our * frame rate so no additional delay is needed to start the next frame. */ if (master_clock->preferred_sync_method >= SYNC_SWAP_THROTTLING || master_clock->sync_available) { master_clock->active_sync_method = SYNC_SWAP_THROTTLING; return now; } master_clock->active_sync_method = SYNC_FALLBACK; interval = 1000000 / clutter_get_default_frame_rate (); next = master_clock->prev_tick + interval; if (next < (now - interval)) /* Too old? Must have been sleeping. */ next = now; return next; } /* * master_clock_next_frame_delay: * @master_clock: a #ClutterMasterClock * * Computes the number of delay before we need to draw the next frame. * * Return value: -1 if there is no next frame pending, otherwise the * number of millseconds before the we need to draw the next frame */ static gint master_clock_next_frame_delay (ClutterMasterClockDefault *master_clock) { gint64 now, next; gint delay_ms; if (!master_clock_is_running (master_clock)) return -1; now = g_source_get_time (master_clock->source); next = master_clock_next_frame_time (master_clock); /* Round your microseconds UP to milliseconds! If we were to round down * then we'd spend an entire millisecond per frame continuously * dispatching without any throttling. Thus spinning the CPU at around 6% * for a 60Hz display. */ if (next > now) delay_ms = (next - now + 999) / 1000; /* Always round up! */ else delay_ms = 0; #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (SCHEDULER, "Waiting %d ms", delay_ms); #endif return delay_ms; } static void master_clock_process_events (ClutterMasterClockDefault *master_clock, GSList *stages) { GSList *l; #ifdef CLUTTER_ENABLE_DEBUG gint64 start = g_get_monotonic_time (); #endif /* Process queued events */ for (l = stages; l != NULL; l = l->next) _clutter_stage_process_queued_events (l->data); #ifdef CLUTTER_ENABLE_DEBUG if (_clutter_diagnostic_enabled ()) clutter_warn_if_over_budget (master_clock, start, "Event processing"); master_clock->remaining_budget -= (g_get_monotonic_time () - start); #endif } /* * master_clock_advance_timelines: * @master_clock: a #ClutterMasterClock * * Advances all the timelines held by the master clock. This function * should be called before calling _clutter_stage_do_update() to * make sure that all the timelines are advanced and the scene is updated. */ static void master_clock_advance_timelines (ClutterMasterClockDefault *master_clock) { GSList *timelines, *l; #ifdef CLUTTER_ENABLE_DEBUG gint64 start = g_get_monotonic_time (); #endif /* we protect ourselves from timelines being removed during * the advancement by other timelines by copying the list of * timelines, taking a reference on them, iterating over the * copied list and then releasing the reference. * * we cannot simply take a reference on the timelines and still * use the list held by the master clock because the do_tick() * might result in the creation of a new timeline, which gets * added at the end of the list with no reference increase and * thus gets disposed at the end of the iteration. * * this implies that a newly added timeline will not be advanced * by this clock iteration, which is perfectly fine since we're * in its first cycle. * * we also cannot steal the master clock timelines list because * a timeline might be removed as the direct result of do_tick() * and remove_timeline() would not find the timeline, failing * and leaving a dangling pointer behind. */ timelines = g_slist_copy (master_clock->timelines); g_slist_foreach (timelines, (GFunc) g_object_ref, NULL); for (l = timelines; l != NULL; l = l->next) _clutter_timeline_do_tick (l->data, master_clock->cur_tick / 1000); g_slist_foreach (timelines, (GFunc) g_object_unref, NULL); g_slist_free (timelines); #ifdef CLUTTER_ENABLE_DEBUG if (_clutter_diagnostic_enabled ()) clutter_warn_if_over_budget (master_clock, start, "Animations"); master_clock->remaining_budget -= (g_get_monotonic_time () - start); #endif } static gboolean master_clock_update_stages (ClutterMasterClockDefault *master_clock, GSList *stages) { gboolean stages_updated = FALSE; GSList *l; #ifdef CLUTTER_ENABLE_DEBUG gint64 start = g_get_monotonic_time (); #endif _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT); /* Update any stage that needs redraw/relayout after the clock * is advanced. */ for (l = stages; l != NULL; l = l->next) stages_updated |= _clutter_stage_do_update (l->data); _clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT); #ifdef CLUTTER_ENABLE_DEBUG if (_clutter_diagnostic_enabled ()) clutter_warn_if_over_budget (master_clock, start, "Updating the stage"); master_clock->remaining_budget -= (g_get_monotonic_time () - start); #endif return stages_updated; } /* * clutter_clock_source_new: * @master_clock: a #ClutterMasterClock for the source * * The #ClutterClockSource is an idle GSource that will queue a redraw * if @master_clock has at least a running #ClutterTimeline. The redraw * will cause @master_clock to advance all timelines, thus advancing all * animations as well. * * Return value: the newly created #GSource */ static GSource * clutter_clock_source_new (ClutterMasterClockDefault *master_clock) { GSource *source = g_source_new (&clock_funcs, sizeof (ClutterClockSource)); ClutterClockSource *clock_source = (ClutterClockSource *) source; g_source_set_name (source, "Clutter master clock"); clock_source->master_clock = master_clock; return source; } static gboolean clutter_clock_prepare (GSource *source, gint *timeout) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClockDefault *master_clock = clock_source->master_clock; int delay; if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_CONTINUOUS_REDRAW)) { ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); const GSList *stages, *l; stages = stage_manager->stages;; /* Queue a full redraw on all of the stages */ for (l = stages; l != NULL; l = l->next) clutter_actor_queue_redraw (l->data); } delay = master_clock_next_frame_delay (master_clock); *timeout = delay; return delay == 0; } static gboolean clutter_clock_check (GSource *source) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClockDefault *master_clock = clock_source->master_clock; int delay; delay = master_clock_next_frame_delay (master_clock); return delay == 0; } static gboolean clutter_clock_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClockDefault *master_clock = clock_source->master_clock; GSList *stages; #ifdef CLUTTER_ENABLE_DEBUG CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); #endif /* Get the time to use for this frame */ master_clock->cur_tick = master_clock_next_frame_time (master_clock); #ifdef CLUTTER_ENABLE_DEBUG master_clock->remaining_budget = master_clock->frame_budget; #endif /* We need to protect ourselves against stages being destroyed during * event handling - master_clock_list_ready_stages() returns a * list of referenced that we'll unref afterwards. */ stages = master_clock_list_ready_stages (master_clock); /* Each frame is split into three separate phases: */ /* 1. process all the events; each stage goes through its events queue * and processes each event according to its type, then emits the * various signals that are associated with the event */ master_clock_process_events (master_clock, stages); /* 2. advance the timelines */ master_clock_advance_timelines (master_clock); /* 3. relayout and redraw the stages */ master_clock_update_stages (master_clock, stages); master_clock_reschedule_stage_updates (master_clock, stages); g_slist_foreach (stages, (GFunc) g_object_unref, NULL); g_slist_free (stages); master_clock->prev_tick = master_clock->cur_tick; return TRUE; } static void clutter_master_clock_default_finalize (GObject *gobject) { ClutterMasterClockDefault *master_clock = CLUTTER_MASTER_CLOCK_DEFAULT (gobject); g_slist_free (master_clock->timelines); G_OBJECT_CLASS (clutter_master_clock_default_parent_class)->finalize (gobject); } static void clutter_master_clock_default_class_init (ClutterMasterClockDefaultClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = clutter_master_clock_default_finalize; } void clutter_master_clock_set_sync_method (SyncMethod method) { const GSList *stages, *l; ClutterStageManager *stage_manager = clutter_stage_manager_get_default (); switch (method) { case SYNC_NONE: g_message ("Sync method: NONE"); break; case SYNC_PRESENTATION_TIME: g_message ("Sync method: PRESENTATION TIME"); break; case SYNC_FALLBACK: g_message ("Sync method: FALLBACK"); break; case SYNC_SWAP_THROTTLING: g_message ("Sync method: SWAP THROTTLING"); break; default: g_warning ("Invalid sync state passed to clutter_master_clock_set_sync_method: %i", method); } master_clock_global->preferred_sync_method = method; stages = stage_manager->stages; for (l = stages; l; l = l->next) { _clutter_stage_clear_update_time (l->data); } } static void clutter_master_clock_default_init (ClutterMasterClockDefault *self) { GSource *source = clutter_clock_source_new (self); SyncMethod method = _clutter_get_sync_method (); self->source = source; master_clock_global = self; self->active_sync_method = method; clutter_master_clock_set_sync_method (method); self->ensure_next_iteration = FALSE; self->paused = FALSE; self->sync_available = clutter_feature_available (CLUTTER_FEATURE_SYNC_TO_VBLANK); #ifdef CLUTTER_ENABLE_DEBUG self->frame_budget = G_USEC_PER_SEC / 60; #endif g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW); g_source_set_can_recurse (source, FALSE); g_source_attach (source, NULL); } static void clutter_master_clock_default_add_timeline (ClutterMasterClock *clock, ClutterTimeline *timeline) { ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; gboolean is_first; if (g_slist_find (master_clock->timelines, timeline)) return; is_first = master_clock->timelines == NULL; master_clock->timelines = g_slist_prepend (master_clock->timelines, timeline); if (is_first) { master_clock_schedule_stage_updates (master_clock); _clutter_master_clock_start_running (clock); } } static void clutter_master_clock_default_remove_timeline (ClutterMasterClock *clock, ClutterTimeline *timeline) { ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; master_clock->timelines = g_slist_remove (master_clock->timelines, timeline); } static void clutter_master_clock_default_start_running (ClutterMasterClock *master_clock) { /* If called from a different thread, we need to wake up the * main loop to start running the timelines */ g_main_context_wakeup (NULL); } static void clutter_master_clock_default_ensure_next_iteration (ClutterMasterClock *clock) { ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; master_clock->ensure_next_iteration = TRUE; } static void clutter_master_clock_default_set_paused (ClutterMasterClock *clock, gboolean paused) { ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; master_clock->paused = !!paused; } static void clutter_master_clock_iface_init (ClutterMasterClockIface *iface) { iface->add_timeline = clutter_master_clock_default_add_timeline; iface->remove_timeline = clutter_master_clock_default_remove_timeline; iface->start_running = clutter_master_clock_default_start_running; iface->ensure_next_iteration = clutter_master_clock_default_ensure_next_iteration; iface->set_paused = clutter_master_clock_default_set_paused; } muffin-5.2.1/clutter/clutter/clutter-drag-action.c0000664000175000017500000011716014211404421022322 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-drag-action * @Title: ClutterDragAction * @Short_Description: Action enabling dragging on actors * * #ClutterDragAction is a sub-class of #ClutterAction that implements * all the necessary logic for dragging actors. * * The simplest usage of #ClutterDragAction consists in adding it to * a #ClutterActor and setting it as reactive; for instance, the following * code: * * |[ * clutter_actor_add_action (actor, clutter_drag_action_new ()); * clutter_actor_set_reactive (actor, TRUE); * ]| * * will automatically result in the actor moving to follow the pointer * whenever the pointer's button is pressed over the actor and moved * across the stage. * * The #ClutterDragAction will signal the begin and the end of a dragging * through the #ClutterDragAction::drag-begin and #ClutterDragAction::drag-end * signals, respectively. Each pointer motion during a drag will also result * in the #ClutterDragAction::drag-motion signal to be emitted. * * It is also possible to set another #ClutterActor as the dragged actor * by calling clutter_drag_action_set_drag_handle() from within a handle * of the #ClutterDragAction::drag-begin signal. The drag handle must be * parented and exist between the emission of #ClutterDragAction::drag-begin * and #ClutterDragAction::drag-end. * * The [drag-action example](https://git.gnome.org/browse/clutter/tree/examples/drag-action.c?h=clutter-1.18) * allows dragging the rectangle around the stage using a #ClutterDragAction. * When pressing the `Shift` key the actor that is being dragged will be a * separate rectangle, and when the drag ends, the original rectangle will be * animated to the final drop coordinates. * * #ClutterDragAction is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-drag-action.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-stage-private.h" struct _ClutterDragActionPrivate { ClutterStage *stage; gint x_drag_threshold; gint y_drag_threshold; ClutterActor *drag_handle; ClutterDragAxis drag_axis; ClutterRect drag_area; ClutterInputDevice *device; ClutterEventSequence *sequence; gulong button_press_id; gulong touch_begin_id; gulong capture_id; gfloat press_x; gfloat press_y; ClutterModifierType press_state; gfloat last_motion_x; gfloat last_motion_y; ClutterModifierType last_motion_state; ClutterInputDevice *last_motion_device; gfloat transformed_press_x; gfloat transformed_press_y; guint emit_delayed_press : 1; guint in_drag : 1; guint motion_events_enabled : 1; guint drag_area_set : 1; }; enum { PROP_0, PROP_X_DRAG_THRESHOLD, PROP_Y_DRAG_THRESHOLD, PROP_DRAG_HANDLE, PROP_DRAG_AXIS, PROP_DRAG_AREA, PROP_DRAG_AREA_SET, PROP_LAST }; static GParamSpec *drag_props[PROP_LAST] = { NULL, }; enum { DRAG_BEGIN, DRAG_PROGRESS, DRAG_MOTION, DRAG_END, LAST_SIGNAL }; static guint drag_signals[LAST_SIGNAL] = { 0, }; /* forward declaration */ static gboolean on_captured_event (ClutterActor *stage, ClutterEvent *event, ClutterDragAction *action); G_DEFINE_TYPE_WITH_PRIVATE (ClutterDragAction, clutter_drag_action, CLUTTER_TYPE_ACTION) static void get_drag_threshold (ClutterDragAction *action, gint *x_threshold, gint *y_threshold) { ClutterDragActionPrivate *priv = action->priv; ClutterSettings *settings = clutter_settings_get_default (); gint x_res, y_res, default_threshold; g_object_get (settings, "dnd-drag-threshold", &default_threshold, NULL); if (priv->x_drag_threshold < 0) x_res = default_threshold; else x_res = priv->x_drag_threshold; if (priv->y_drag_threshold < 0) y_res = default_threshold; else y_res = priv->y_drag_threshold; if (x_threshold != NULL) *x_threshold = x_res; if (y_threshold != NULL) *y_threshold = y_res; } static void emit_drag_begin (ClutterDragAction *action, ClutterActor *actor, ClutterEvent *event) { ClutterDragActionPrivate *priv = action->priv; if (priv->stage != NULL) { clutter_stage_set_motion_events_enabled (priv->stage, FALSE); if (clutter_event_type (event) == CLUTTER_TOUCH_BEGIN) _clutter_stage_add_touch_drag_actor (priv->stage, clutter_event_get_event_sequence (event), priv->drag_handle != NULL ? priv->drag_handle : actor); else _clutter_stage_add_pointer_drag_actor (priv->stage, clutter_event_get_device (event), priv->drag_handle != NULL ? priv->drag_handle : actor); } g_signal_emit (action, drag_signals[DRAG_BEGIN], 0, actor, priv->press_x, priv->press_y, priv->press_state); } static void emit_drag_motion (ClutterDragAction *action, ClutterActor *actor, ClutterEvent *event) { ClutterDragActionPrivate *priv = action->priv; ClutterActor *drag_handle = NULL; gfloat delta_x, delta_y; gfloat motion_x, motion_y; gboolean can_emit_drag_motion = TRUE; clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y); priv->last_motion_state = clutter_event_get_state (event); priv->last_motion_device = clutter_event_get_device (event); if (priv->drag_handle != NULL && !priv->emit_delayed_press) drag_handle = priv->drag_handle; else drag_handle = actor; motion_x = motion_y = 0.0f; clutter_actor_transform_stage_point (drag_handle, priv->last_motion_x, priv->last_motion_y, &motion_x, &motion_y); delta_x = delta_y = 0.0f; switch (priv->drag_axis) { case CLUTTER_DRAG_AXIS_NONE: delta_x = motion_x - priv->transformed_press_x; delta_y = motion_y - priv->transformed_press_y; break; case CLUTTER_DRAG_X_AXIS: delta_x = motion_x - priv->transformed_press_x; break; case CLUTTER_DRAG_Y_AXIS: delta_y = motion_y - priv->transformed_press_y; break; default: g_assert_not_reached (); return; } if (priv->emit_delayed_press) { gint x_drag_threshold, y_drag_threshold; get_drag_threshold (action, &x_drag_threshold, &y_drag_threshold); if (ABS (delta_x) >= x_drag_threshold || ABS (delta_y) >= y_drag_threshold) { priv->emit_delayed_press = FALSE; emit_drag_begin (action, actor, event); } else return; } g_signal_emit (action, drag_signals[DRAG_PROGRESS], 0, actor, delta_x, delta_y, &can_emit_drag_motion); if (can_emit_drag_motion) { g_signal_emit (action, drag_signals[DRAG_MOTION], 0, actor, delta_x, delta_y); } } static void emit_drag_end (ClutterDragAction *action, ClutterActor *actor, ClutterEvent *event) { ClutterDragActionPrivate *priv = action->priv; /* ::drag-end may result in the destruction of the actor, which in turn * will lead to the removal and finalization of the action, so we need * to keep the action alive for the entire emission sequence */ g_object_ref (action); /* if we have an event, update our own state, otherwise we'll * just use the currently stored state when emitting the ::drag-end * signal */ if (event != NULL) { clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y); priv->last_motion_state = clutter_event_get_state (event); priv->last_motion_device = clutter_event_get_device (event); } priv->in_drag = FALSE; /* we might not have emitted ::drag-begin yet */ if (!priv->emit_delayed_press) g_signal_emit (action, drag_signals[DRAG_END], 0, actor, priv->last_motion_x, priv->last_motion_y, priv->last_motion_state); if (priv->stage == NULL) goto out; /* disconnect the capture */ if (priv->capture_id != 0) { g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; } clutter_stage_set_motion_events_enabled (priv->stage, priv->motion_events_enabled); if (priv->last_motion_device != NULL && event != NULL) { if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE) _clutter_stage_remove_pointer_drag_actor (priv->stage, priv->last_motion_device); else _clutter_stage_remove_touch_drag_actor (priv->stage, priv->sequence); } out: priv->last_motion_device = NULL; priv->sequence = NULL; g_object_unref (action); } static gboolean on_captured_event (ClutterActor *stage, ClutterEvent *event, ClutterDragAction *action) { ClutterDragActionPrivate *priv = action->priv; ClutterActor *actor; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); if (!priv->in_drag) return CLUTTER_EVENT_PROPAGATE; if (clutter_event_get_device (event) != priv->device || clutter_event_get_event_sequence (event) != priv->sequence) return CLUTTER_EVENT_PROPAGATE; switch (clutter_event_type (event)) { case CLUTTER_TOUCH_UPDATE: emit_drag_motion (action, actor, event); break; case CLUTTER_MOTION: { ClutterModifierType mods = clutter_event_get_state (event); /* we might miss a button-release event in case of grabs, * so we need to check whether the button is still down * during a motion event */ if (mods & CLUTTER_BUTTON1_MASK) emit_drag_motion (action, actor, event); else emit_drag_end (action, actor, event); } break; case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_CANCEL: emit_drag_end (action, actor, event); break; case CLUTTER_BUTTON_RELEASE: if (priv->in_drag) emit_drag_end (action, actor, event); break; case CLUTTER_ENTER: case CLUTTER_LEAVE: if (priv->in_drag) return CLUTTER_EVENT_STOP; break; default: break; } return CLUTTER_EVENT_PROPAGATE; } static gboolean on_drag_begin (ClutterActor *actor, ClutterEvent *event, ClutterDragAction *action) { ClutterDragActionPrivate *priv = action->priv; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) return CLUTTER_EVENT_PROPAGATE; /* dragging is only performed using the primary button */ switch (clutter_event_type (event)) { case CLUTTER_BUTTON_PRESS: if (priv->sequence != NULL) return CLUTTER_EVENT_PROPAGATE; if (clutter_event_get_button (event) != CLUTTER_BUTTON_PRIMARY) return CLUTTER_EVENT_PROPAGATE; break; case CLUTTER_TOUCH_BEGIN: if (priv->sequence != NULL) return CLUTTER_EVENT_PROPAGATE; priv->sequence = clutter_event_get_event_sequence (event); break; default: return CLUTTER_EVENT_PROPAGATE; } if (priv->stage == NULL) priv->stage = CLUTTER_STAGE (clutter_actor_get_stage (actor)); clutter_event_get_coords (event, &priv->press_x, &priv->press_y); priv->press_state = clutter_event_get_state (event); priv->device = clutter_event_get_device (event); priv->last_motion_x = priv->press_x; priv->last_motion_y = priv->press_y; priv->transformed_press_x = priv->press_x; priv->transformed_press_y = priv->press_y; clutter_actor_transform_stage_point (actor, priv->press_x, priv->press_y, &priv->transformed_press_x, &priv->transformed_press_y); priv->motion_events_enabled = clutter_stage_get_motion_events_enabled (priv->stage); if (priv->x_drag_threshold == 0 || priv->y_drag_threshold == 0) emit_drag_begin (action, actor, event); else priv->emit_delayed_press = TRUE; priv->in_drag = TRUE; priv->capture_id = g_signal_connect_after (priv->stage, "captured-event", G_CALLBACK (on_captured_event), action); return CLUTTER_EVENT_PROPAGATE; } static void clutter_drag_action_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (meta)->priv; if (priv->button_press_id != 0) { ClutterActor *old_actor; old_actor = clutter_actor_meta_get_actor (meta); if (old_actor != NULL) { g_signal_handler_disconnect (old_actor, priv->button_press_id); g_signal_handler_disconnect (old_actor, priv->touch_begin_id); } priv->button_press_id = 0; priv->touch_begin_id = 0; } if (priv->capture_id != 0) { if (priv->stage != NULL) g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; priv->stage = NULL; } clutter_drag_action_set_drag_handle (CLUTTER_DRAG_ACTION (meta), NULL); priv->in_drag = FALSE; if (actor != NULL) { priv->button_press_id = g_signal_connect (actor, "button-press-event", G_CALLBACK (on_drag_begin), meta); priv->touch_begin_id = g_signal_connect (actor, "touch-event", G_CALLBACK (on_drag_begin), meta); } CLUTTER_ACTOR_META_CLASS (clutter_drag_action_parent_class)->set_actor (meta, actor); } static gboolean clutter_drag_action_real_drag_progress (ClutterDragAction *action, ClutterActor *actor, gfloat delta_x, gfloat delta_y) { return TRUE; } static void clutter_drag_action_real_drag_motion (ClutterDragAction *action, ClutterActor *actor, gfloat delta_x, gfloat delta_y) { ClutterActor *drag_handle; gfloat x, y; if (action->priv->drag_handle != NULL) drag_handle = action->priv->drag_handle; else drag_handle = actor; clutter_actor_get_position (drag_handle, &x, &y); x += delta_x; y += delta_y; if (action->priv->drag_area_set) { ClutterRect *drag_area = &action->priv->drag_area; x = CLAMP (x, drag_area->origin.x, drag_area->origin.x + drag_area->size.width); y = CLAMP (y, drag_area->origin.y, drag_area->origin.y + drag_area->size.height); } clutter_actor_set_position (drag_handle, x, y); } static void clutter_drag_action_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterDragAction *action = CLUTTER_DRAG_ACTION (gobject); ClutterDragActionPrivate *priv = action->priv; switch (prop_id) { case PROP_X_DRAG_THRESHOLD: clutter_drag_action_set_drag_threshold (action, g_value_get_int (value), priv->y_drag_threshold); break; case PROP_Y_DRAG_THRESHOLD: clutter_drag_action_set_drag_threshold (action, priv->x_drag_threshold, g_value_get_int (value)); break; case PROP_DRAG_HANDLE: clutter_drag_action_set_drag_handle (action, g_value_get_object (value)); break; case PROP_DRAG_AXIS: clutter_drag_action_set_drag_axis (action, g_value_get_enum (value)); break; case PROP_DRAG_AREA: clutter_drag_action_set_drag_area (action, g_value_get_boxed (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_drag_action_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv; switch (prop_id) { case PROP_X_DRAG_THRESHOLD: { gint threshold; get_drag_threshold (CLUTTER_DRAG_ACTION (gobject), &threshold, NULL); g_value_set_int (value, threshold); } break; case PROP_Y_DRAG_THRESHOLD: { gint threshold; get_drag_threshold (CLUTTER_DRAG_ACTION (gobject), NULL, &threshold); g_value_set_int (value, threshold); } break; case PROP_DRAG_HANDLE: g_value_set_object (value, priv->drag_handle); break; case PROP_DRAG_AXIS: g_value_set_enum (value, priv->drag_axis); break; case PROP_DRAG_AREA: g_value_set_boxed (value, &priv->drag_area); break; case PROP_DRAG_AREA_SET: g_value_set_boolean (value, priv->drag_area_set); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_drag_action_dispose (GObject *gobject) { ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv; /* if we're being disposed while a capture is still present, we * need to reset the state we are currently holding */ if (priv->last_motion_device != NULL) { _clutter_stage_remove_pointer_drag_actor (priv->stage, priv->last_motion_device); priv->last_motion_device = NULL; } if (priv->sequence != NULL) { _clutter_stage_remove_touch_drag_actor (priv->stage, priv->sequence); priv->sequence = NULL; } if (priv->capture_id != 0) { clutter_stage_set_motion_events_enabled (priv->stage, priv->motion_events_enabled); if (priv->stage != NULL) g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; priv->stage = NULL; } if (priv->button_press_id != 0) { ClutterActor *actor; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gobject)); if (actor != NULL) { g_signal_handler_disconnect (actor, priv->button_press_id); g_signal_handler_disconnect (actor, priv->touch_begin_id); } priv->button_press_id = 0; priv->touch_begin_id = 0; } clutter_drag_action_set_drag_handle (CLUTTER_DRAG_ACTION (gobject), NULL); clutter_drag_action_set_drag_area (CLUTTER_DRAG_ACTION (gobject), NULL); G_OBJECT_CLASS (clutter_drag_action_parent_class)->dispose (gobject); } static void clutter_drag_action_class_init (ClutterDragActionClass *klass) { ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); meta_class->set_actor = clutter_drag_action_set_actor; klass->drag_progress = clutter_drag_action_real_drag_progress; klass->drag_motion = clutter_drag_action_real_drag_motion; /** * ClutterDragAction:x-drag-threshold: * * The horizontal threshold, in pixels, that the cursor must travel * in order to begin a drag action. * * When set to a positive value, #ClutterDragAction will only emit * #ClutterDragAction::drag-begin if the pointer has moved * horizontally at least of the given amount of pixels since * the button press event. * * When set to -1, #ClutterDragAction will use the default threshold * stored in the #ClutterSettings:dnd-drag-threshold property of * #ClutterSettings. * * When read, this property will always return a valid drag * threshold, either as set or the default one. * * Since: 1.4 */ drag_props[PROP_X_DRAG_THRESHOLD] = g_param_spec_int ("x-drag-threshold", P_("Horizontal Drag Threshold"), P_("The horizontal amount of pixels required to start dragging"), -1, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterDragAction:y-drag-threshold: * * The vertical threshold, in pixels, that the cursor must travel * in order to begin a drag action. * * When set to a positive value, #ClutterDragAction will only emit * #ClutterDragAction::drag-begin if the pointer has moved * vertically at least of the given amount of pixels since * the button press event. * * When set to -1, #ClutterDragAction will use the value stored * in the #ClutterSettings:dnd-drag-threshold property of * #ClutterSettings. * * When read, this property will always return a valid drag * threshold, either as set or the default one. * * Since: 1.4 */ drag_props[PROP_Y_DRAG_THRESHOLD] = g_param_spec_int ("y-drag-threshold", P_("Vertical Drag Threshold"), P_("The vertical amount of pixels required to start dragging"), -1, G_MAXINT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterDragAction:drag-handle: * * The #ClutterActor that is effectively being dragged * * A #ClutterDragAction will, be default, use the #ClutterActor that * has been attached to the action; it is possible to create a * separate #ClutterActor and use it instead. * * Setting this property has no effect on the #ClutterActor argument * passed to the #ClutterDragAction signals * * Since: 1.4 */ drag_props[PROP_DRAG_HANDLE] = g_param_spec_object ("drag-handle", P_("Drag Handle"), P_("The actor that is being dragged"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READWRITE); /** * ClutterDragAction:drag-axis: * * Constraints the dragging action to the specified axis * * Since: 1.4 */ drag_props[PROP_DRAG_AXIS] = g_param_spec_enum ("drag-axis", P_("Drag Axis"), P_("Constraints the dragging to an axis"), CLUTTER_TYPE_DRAG_AXIS, CLUTTER_DRAG_AXIS_NONE, CLUTTER_PARAM_READWRITE); /** * ClutterDragAction:drag-area: * * Constains the dragging action (or in particular, the resulting * actor position) to the specified #ClutterRect, in parent's * coordinates. * * Since: 1.12 */ drag_props[PROP_DRAG_AREA] = g_param_spec_boxed ("drag-area", P_("Drag Area"), P_("Constrains the dragging to a rectangle"), CLUTTER_TYPE_RECT, CLUTTER_PARAM_READWRITE); /** * ClutterDragAction:drag-area-set: * * Whether the #ClutterDragAction:drag-area property has been set. * * Since: 1.12 */ drag_props[PROP_DRAG_AREA_SET] = g_param_spec_boolean ("drag-area-set", P_("Drag Area Set"), P_("Whether the drag area is set"), FALSE, CLUTTER_PARAM_READABLE); gobject_class->set_property = clutter_drag_action_set_property; gobject_class->get_property = clutter_drag_action_get_property; gobject_class->dispose = clutter_drag_action_dispose; g_object_class_install_properties (gobject_class, PROP_LAST, drag_props); /** * ClutterDragAction::drag-begin: * @action: the #ClutterDragAction that emitted the signal * @actor: the #ClutterActor attached to the action * @event_x: the X coordinate (in stage space) of the press event * @event_y: the Y coordinate (in stage space) of the press event * @modifiers: the modifiers of the press event * * The ::drag-begin signal is emitted when the #ClutterDragAction * starts the dragging * * The emission of this signal can be delayed by using the * #ClutterDragAction:x-drag-threshold and * #ClutterDragAction:y-drag-threshold properties * * Since: 1.4 */ drag_signals[DRAG_BEGIN] = g_signal_new (I_("drag-begin"), CLUTTER_TYPE_DRAG_ACTION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDragActionClass, drag_begin), NULL, NULL, _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_FLAGS, G_TYPE_NONE, 4, CLUTTER_TYPE_ACTOR, G_TYPE_FLOAT, G_TYPE_FLOAT, CLUTTER_TYPE_MODIFIER_TYPE); /** * ClutterDragAction::drag-progress: * @action: the #ClutterDragAction that emitted the signal * @actor: the #ClutterActor attached to the action * @delta_x: the X component of the distance between the press event * that began the dragging and the current position of the pointer, * as of the latest motion event * @delta_y: the Y component of the distance between the press event * that began the dragging and the current position of the pointer, * as of the latest motion event * * The ::drag-progress signal is emitted for each motion event after * the #ClutterDragAction::drag-begin signal has been emitted. * * The components of the distance between the press event and the * latest motion event are computed in the actor's coordinate space, * to take into account eventual transformations. If you want the * stage coordinates of the latest motion event you can use * clutter_drag_action_get_motion_coords(). * * The default handler will emit #ClutterDragAction::drag-motion, * if #ClutterDragAction::drag-progress emission returns %TRUE. * * Return value: %TRUE if the drag should continue, and %FALSE * if it should be stopped. * * Since: 1.12 */ drag_signals[DRAG_PROGRESS] = g_signal_new (I_("drag-progress"), CLUTTER_TYPE_DRAG_ACTION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDragActionClass, drag_progress), _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT_FLOAT_FLOAT, G_TYPE_BOOLEAN, 3, CLUTTER_TYPE_ACTOR, G_TYPE_FLOAT, G_TYPE_FLOAT); /** * ClutterDragAction::drag-motion: * @action: the #ClutterDragAction that emitted the signal * @actor: the #ClutterActor attached to the action * @delta_x: the X component of the distance between the press event * that began the dragging and the current position of the pointer, * as of the latest motion event * @delta_y: the Y component of the distance between the press event * that began the dragging and the current position of the pointer, * as of the latest motion event * * The ::drag-motion signal is emitted for each motion event after * the #ClutterDragAction::drag-begin signal has been emitted. * * The components of the distance between the press event and the * latest motion event are computed in the actor's coordinate space, * to take into account eventual transformations. If you want the * stage coordinates of the latest motion event you can use * clutter_drag_action_get_motion_coords(). * * The default handler of the signal will call clutter_actor_move_by() * either on @actor or, if set, of #ClutterDragAction:drag-handle using * the @delta_x and @delta_y components of the dragging motion. If you * want to override the default behaviour, you can connect to the * #ClutterDragAction::drag-progress signal and return %FALSE from the * handler. * * Since: 1.4 */ drag_signals[DRAG_MOTION] = g_signal_new (I_("drag-motion"), CLUTTER_TYPE_DRAG_ACTION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDragActionClass, drag_motion), NULL, NULL, _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT, G_TYPE_NONE, 3, CLUTTER_TYPE_ACTOR, G_TYPE_FLOAT, G_TYPE_FLOAT); /** * ClutterDragAction::drag-end: * @action: the #ClutterDragAction that emitted the signal * @actor: the #ClutterActor attached to the action * @event_x: the X coordinate (in stage space) of the release event * @event_y: the Y coordinate (in stage space) of the release event * @modifiers: the modifiers of the release event * * The ::drag-end signal is emitted at the end of the dragging, * when the pointer button's is released * * This signal is emitted if and only if the #ClutterDragAction::drag-begin * signal has been emitted first * * Since: 1.4 */ drag_signals[DRAG_END] = g_signal_new (I_("drag-end"), CLUTTER_TYPE_DRAG_ACTION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDragActionClass, drag_end), NULL, NULL, _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_FLAGS, G_TYPE_NONE, 4, CLUTTER_TYPE_ACTOR, G_TYPE_FLOAT, G_TYPE_FLOAT, CLUTTER_TYPE_MODIFIER_TYPE); } static void clutter_drag_action_init (ClutterDragAction *self) { self->priv = clutter_drag_action_get_instance_private (self); } /** * clutter_drag_action_new: * * Creates a new #ClutterDragAction instance * * Return value: the newly created #ClutterDragAction * * Since: 1.4 */ ClutterAction * clutter_drag_action_new (void) { return g_object_new (CLUTTER_TYPE_DRAG_ACTION, NULL); } /** * clutter_drag_action_set_drag_threshold: * @action: a #ClutterDragAction * @x_threshold: a distance on the horizontal axis, in pixels, or * -1 to use the default drag threshold from #ClutterSettings * @y_threshold: a distance on the vertical axis, in pixels, or * -1 to use the default drag threshold from #ClutterSettings * * Sets the horizontal and vertical drag thresholds that must be * cleared by the pointer before @action can begin the dragging. * * If @x_threshold or @y_threshold are set to -1 then the default * drag threshold stored in the #ClutterSettings:dnd-drag-threshold * property of #ClutterSettings will be used. * * Since: 1.4 */ void clutter_drag_action_set_drag_threshold (ClutterDragAction *action, gint x_threshold, gint y_threshold) { ClutterDragActionPrivate *priv; GObject *self; g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); self = G_OBJECT (action); priv = action->priv; g_object_freeze_notify (self); if (priv->x_drag_threshold != x_threshold) { priv->x_drag_threshold = x_threshold; g_object_notify_by_pspec (self, drag_props[PROP_X_DRAG_THRESHOLD]); } if (priv->y_drag_threshold != y_threshold) { priv->y_drag_threshold = y_threshold; g_object_notify_by_pspec (self, drag_props[PROP_Y_DRAG_THRESHOLD]); } g_object_thaw_notify (self); } /** * clutter_drag_action_get_drag_threshold: * @action: a #ClutterDragAction * @x_threshold: (out): return location for the horizontal drag * threshold value, in pixels * @y_threshold: (out): return location for the vertical drag * threshold value, in pixels * * Retrieves the values set by clutter_drag_action_set_drag_threshold(). * * If the #ClutterDragAction:x-drag-threshold property or the * #ClutterDragAction:y-drag-threshold property have been set to -1 then * this function will return the default drag threshold value as stored * by the #ClutterSettings:dnd-drag-threshold property of #ClutterSettings. * * Since: 1.4 */ void clutter_drag_action_get_drag_threshold (ClutterDragAction *action, guint *x_threshold, guint *y_threshold) { gint x_res, y_res; g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); get_drag_threshold (action, &x_res, &y_res); if (x_threshold != NULL) *x_threshold = x_res; if (y_threshold != NULL) *y_threshold = y_res; } static void on_drag_handle_destroy (ClutterActor *handle, ClutterDragAction *action) { ClutterDragActionPrivate *priv = action->priv; ClutterActor *actor; /* make sure we reset the state */ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); if (priv->in_drag) emit_drag_end (action, actor, NULL); priv->drag_handle = NULL; } /** * clutter_drag_action_set_drag_handle: * @action: a #ClutterDragAction * @handle: (allow-none): a #ClutterActor, or %NULL to unset * * Sets the actor to be used as the drag handle. * * Since: 1.4 */ void clutter_drag_action_set_drag_handle (ClutterDragAction *action, ClutterActor *handle) { ClutterDragActionPrivate *priv; g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); g_return_if_fail (handle == NULL || CLUTTER_IS_ACTOR (handle)); priv = action->priv; if (priv->drag_handle == handle) return; if (priv->drag_handle != NULL) g_signal_handlers_disconnect_by_func (priv->drag_handle, G_CALLBACK (on_drag_handle_destroy), action); priv->drag_handle = handle; priv->transformed_press_x = priv->press_x; priv->transformed_press_y = priv->press_y; if (priv->drag_handle != NULL) { clutter_actor_transform_stage_point (priv->drag_handle, priv->press_x, priv->press_y, &priv->transformed_press_x, &priv->transformed_press_y); g_signal_connect (priv->drag_handle, "destroy", G_CALLBACK (on_drag_handle_destroy), action); } g_object_notify_by_pspec (G_OBJECT (action), drag_props[PROP_DRAG_HANDLE]); } /** * clutter_drag_action_get_drag_handle: * @action: a #ClutterDragAction * * Retrieves the drag handle set by clutter_drag_action_set_drag_handle() * * Return value: (transfer none): a #ClutterActor, used as the drag * handle, or %NULL if none was set * * Since: 1.4 */ ClutterActor * clutter_drag_action_get_drag_handle (ClutterDragAction *action) { g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), NULL); return action->priv->drag_handle; } /** * clutter_drag_action_set_drag_axis: * @action: a #ClutterDragAction * @axis: the axis to constraint the dragging to * * Restricts the dragging action to a specific axis * * Since: 1.4 */ void clutter_drag_action_set_drag_axis (ClutterDragAction *action, ClutterDragAxis axis) { ClutterDragActionPrivate *priv; g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); g_return_if_fail (axis >= CLUTTER_DRAG_AXIS_NONE && axis <= CLUTTER_DRAG_Y_AXIS); priv = action->priv; if (priv->drag_axis == axis) return; priv->drag_axis = axis; g_object_notify_by_pspec (G_OBJECT (action), drag_props[PROP_DRAG_AXIS]); } /** * clutter_drag_action_get_drag_axis: * @action: a #ClutterDragAction * * Retrieves the axis constraint set by clutter_drag_action_set_drag_axis() * * Return value: the axis constraint * * Since: 1.4 */ ClutterDragAxis clutter_drag_action_get_drag_axis (ClutterDragAction *action) { g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), CLUTTER_DRAG_AXIS_NONE); return action->priv->drag_axis; } /** * clutter_drag_action_get_press_coords: * @action: a #ClutterDragAction * @press_x: (out): return location for the press event's X coordinate * @press_y: (out): return location for the press event's Y coordinate * * Retrieves the coordinates, in stage space, of the press event * that started the dragging * * Since: 1.4 */ void clutter_drag_action_get_press_coords (ClutterDragAction *action, gfloat *press_x, gfloat *press_y) { g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); if (press_x) *press_x = action->priv->press_x; if (press_y) *press_y = action->priv->press_y; } /** * clutter_drag_action_get_motion_coords: * @action: a #ClutterDragAction * @motion_x: (out): return location for the latest motion * event's X coordinate * @motion_y: (out): return location for the latest motion * event's Y coordinate * * Retrieves the coordinates, in stage space, of the latest motion * event during the dragging * * Since: 1.4 */ void clutter_drag_action_get_motion_coords (ClutterDragAction *action, gfloat *motion_x, gfloat *motion_y) { g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); if (motion_x) *motion_x = action->priv->last_motion_x; if (motion_y) *motion_y = action->priv->last_motion_y; } /** * clutter_drag_action_get_drag_area: * @action: a #ClutterDragAction * @drag_area: (out caller-allocates): a #ClutterRect to be filled * * Retrieves the "drag area" associated with @action, that * is a #ClutterRect that constrains the actor movements, * in parents coordinates. * * Returns: %TRUE if the actor is actually constrained (and thus * @drag_area is valid), %FALSE otherwise */ gboolean clutter_drag_action_get_drag_area (ClutterDragAction *action, ClutterRect *drag_area) { g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), FALSE); if (drag_area != NULL) *drag_area = action->priv->drag_area; return action->priv->drag_area_set; } /** * clutter_drag_action_set_drag_area: * @action: a #ClutterDragAction * @drag_area: (allow-none): a #ClutterRect * * Sets @drag_area to constrain the dragging of the actor associated * with @action, so that it position is always within @drag_area, expressed * in parent's coordinates. * If @drag_area is %NULL, the actor is not constrained. */ void clutter_drag_action_set_drag_area (ClutterDragAction *action, const ClutterRect *drag_area) { ClutterDragActionPrivate *priv; g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action)); priv = action->priv; if (drag_area != NULL) { priv->drag_area = *drag_area; priv->drag_area_set = TRUE; } else priv->drag_area_set = FALSE; g_object_notify_by_pspec (G_OBJECT (action), drag_props[PROP_DRAG_AREA_SET]); g_object_notify_by_pspec (G_OBJECT (action), drag_props[PROP_DRAG_AREA]); } muffin-5.2.1/clutter/clutter/clutter-container.c0000664000175000017500000013023714211404421022114 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . * * * * ClutterContainer: Generic actor container interface. * Author: Emmanuele Bassi */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #include "deprecated/clutter-container.h" #include "clutter-actor-private.h" #include "clutter-child-meta.h" #include "clutter-debug.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-enum-types.h" #define CLUTTER_CONTAINER_WARN_NOT_IMPLEMENTED(container,vfunc) \ G_STMT_START { \ g_warning ("Container of type '%s' does not implement " \ "the required ClutterContainer::%s virtual " \ "function.", \ G_OBJECT_TYPE_NAME ((container)), \ (vfunc)); \ } G_STMT_END #define CLUTTER_CONTAINER_NOTE_NOT_IMPLEMENTED(container,vfunc) \ G_STMT_START { \ CLUTTER_NOTE (ACTOR, "Container of type '%s' does not " \ "implement the ClutterContainer::%s " \ "virtual function.", \ G_OBJECT_TYPE_NAME ((container)), \ (vfunc)); \ } G_STMT_END /** * SECTION:clutter-container * @short_description: An interface for container actors * * #ClutterContainer is an interface implemented by #ClutterActor, and * it provides some common API for notifying when a child actor is added * or removed, as well as the infrastructure for accessing child properties * through #ClutterChildMeta. * * Until Clutter 1.10, the #ClutterContainer interface was also the public * API for implementing container actors; this part of the interface has * been deprecated: #ClutterContainer has a default implementation which * defers to #ClutterActor the child addition and removal, as well as the * iteration. See the documentation of #ClutterContainerIface for the list * of virtual functions that should be overridden. */ enum { ACTOR_ADDED, ACTOR_REMOVED, CHILD_NOTIFY, LAST_SIGNAL }; static guint container_signals[LAST_SIGNAL] = { 0, }; static GQuark quark_child_meta = 0; static ClutterChildMeta *get_child_meta (ClutterContainer *container, ClutterActor *actor); static void create_child_meta (ClutterContainer *container, ClutterActor *actor); static void destroy_child_meta (ClutterContainer *container, ClutterActor *actor); static void child_notify (ClutterContainer *container, ClutterActor *child, GParamSpec *pspec); typedef ClutterContainerIface ClutterContainerInterface; G_DEFINE_INTERFACE (ClutterContainer, clutter_container, G_TYPE_OBJECT); static void container_real_add (ClutterContainer *container, ClutterActor *actor) { clutter_actor_add_child (CLUTTER_ACTOR (container), actor); } static void container_real_remove (ClutterContainer *container, ClutterActor *actor) { clutter_actor_remove_child (CLUTTER_ACTOR (container), actor); } typedef struct { ClutterCallback callback; gpointer data; } ForeachClosure; static gboolean foreach_cb (ClutterActor *actor, gpointer data) { ForeachClosure *clos = data; clos->callback (actor, clos->data); return TRUE; } static void container_real_foreach (ClutterContainer *container, ClutterCallback callback, gpointer user_data) { ForeachClosure clos; clos.callback = callback; clos.data = user_data; _clutter_actor_foreach_child (CLUTTER_ACTOR (container), foreach_cb, &clos); } static void container_real_raise (ClutterContainer *container, ClutterActor *child, ClutterActor *sibling) { ClutterActor *self = CLUTTER_ACTOR (container); clutter_actor_set_child_above_sibling (self, child, sibling); } static void container_real_lower (ClutterContainer *container, ClutterActor *child, ClutterActor *sibling) { ClutterActor *self = CLUTTER_ACTOR (container); clutter_actor_set_child_below_sibling (self, child, sibling); } static void container_real_sort_depth_order (ClutterContainer *container) { } static void clutter_container_default_init (ClutterContainerInterface *iface) { GType iface_type = G_TYPE_FROM_INTERFACE (iface); quark_child_meta = g_quark_from_static_string ("clutter-container-child-data"); /** * ClutterContainer::actor-added: * @container: the actor which received the signal * @actor: the new child that has been added to @container * * The ::actor-added signal is emitted each time an actor * has been added to @container. * * Since: 0.4 */ container_signals[ACTOR_ADDED] = g_signal_new (I_("actor-added"), iface_type, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterContainerIface, actor_added), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterContainer::actor-removed: * @container: the actor which received the signal * @actor: the child that has been removed from @container * * The ::actor-removed signal is emitted each time an actor * is removed from @container. * * Since: 0.4 */ container_signals[ACTOR_REMOVED] = g_signal_new (I_("actor-removed"), iface_type, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterContainerIface, actor_removed), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterContainer::child-notify: * @container: the container which received the signal * @actor: the child that has had a property set * @pspec: (type GParamSpec): the #GParamSpec of the property set * * The ::child-notify signal is emitted each time a property is * being set through the clutter_container_child_set() and * clutter_container_child_set_property() calls. * * Since: 0.8 */ container_signals[CHILD_NOTIFY] = g_signal_new (I_("child-notify"), iface_type, G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, G_STRUCT_OFFSET (ClutterContainerIface, child_notify), NULL, NULL, _clutter_marshal_VOID__OBJECT_PARAM, G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR, G_TYPE_PARAM); iface->add = container_real_add; iface->remove = container_real_remove; iface->foreach = container_real_foreach; iface->raise = container_real_raise; iface->lower = container_real_lower; iface->sort_depth_order = container_real_sort_depth_order; iface->child_meta_type = G_TYPE_INVALID; iface->create_child_meta = create_child_meta; iface->destroy_child_meta = destroy_child_meta; iface->get_child_meta = get_child_meta; iface->child_notify = child_notify; } static inline void container_add_actor (ClutterContainer *container, ClutterActor *actor) { ClutterActor *parent; parent = clutter_actor_get_parent (actor); if (G_UNLIKELY (parent != NULL)) { g_warning ("Attempting to add actor of type '%s' to a " "container of type '%s', but the actor has " "already a parent of type '%s'.", g_type_name (G_OBJECT_TYPE (actor)), g_type_name (G_OBJECT_TYPE (container)), g_type_name (G_OBJECT_TYPE (parent))); return; } clutter_container_create_child_meta (container, actor); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) { ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container); if (iface->add != container_real_add) _clutter_diagnostic_message ("The ClutterContainer::add() virtual " "function has been deprecated and it " "should not be overridden by newly " "written code"); } #endif /* CLUTTER_ENABLE_DEBUG */ CLUTTER_CONTAINER_GET_IFACE (container)->add (container, actor); } static inline void container_remove_actor (ClutterContainer *container, ClutterActor *actor) { ClutterActor *parent; parent = clutter_actor_get_parent (actor); if (parent != CLUTTER_ACTOR (container)) { g_warning ("Attempting to remove actor of type '%s' from " "group of class '%s', but the container is not " "the actor's parent.", g_type_name (G_OBJECT_TYPE (actor)), g_type_name (G_OBJECT_TYPE (container))); return; } clutter_container_destroy_child_meta (container, actor); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) { ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container); if (iface->remove != container_real_remove) _clutter_diagnostic_message ("The ClutterContainer::remove() virtual " "function has been deprecated and it " "should not be overridden by newly " "written code"); } #endif /* CLUTTER_ENABLE_DEBUG */ CLUTTER_CONTAINER_GET_IFACE (container)->remove (container, actor); } static inline void container_add_valist (ClutterContainer *container, ClutterActor *first_actor, va_list args) { ClutterActor *actor = first_actor; while (actor != NULL) { container_add_actor (container, actor); actor = va_arg (args, ClutterActor *); } } static inline void container_remove_valist (ClutterContainer *container, ClutterActor *first_actor, va_list args) { ClutterActor *actor = first_actor; while (actor != NULL) { container_remove_actor (container, actor); actor = va_arg (args, ClutterActor *); } } /** * clutter_container_add: (skip) * @container: a #ClutterContainer * @first_actor: the first #ClutterActor to add * @...: %NULL terminated list of actors to add * * Adds a list of #ClutterActors to @container. Each time and * actor is added, the "actor-added" signal is emitted. Each actor should * be parented to @container, which takes a reference on the actor. You * cannot add a #ClutterActor to more than one #ClutterContainer. * * This function will call #ClutterContainerIface.add(), which is a * deprecated virtual function. The default implementation will * call clutter_actor_add_child(). * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_add_child() instead. */ void clutter_container_add (ClutterContainer *container, ClutterActor *first_actor, ...) { va_list args; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); va_start (args, first_actor); container_add_valist (container, first_actor, args); va_end (args); } /** * clutter_container_add_actor: (virtual add) * @container: a #ClutterContainer * @actor: the first #ClutterActor to add * * Adds a #ClutterActor to @container. This function will emit the * "actor-added" signal. The actor should be parented to * @container. You cannot add a #ClutterActor to more than one * #ClutterContainer. * * This function will call #ClutterContainerIface.add(), which is a * deprecated virtual function. The default implementation will * call clutter_actor_add_child(). * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_add_child() instead. */ void clutter_container_add_actor (ClutterContainer *container, ClutterActor *actor) { g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); container_add_actor (container, actor); } /** * clutter_container_add_valist: (skip) * @container: a #ClutterContainer * @first_actor: the first #ClutterActor to add * @var_args: list of actors to add, followed by %NULL * * Alternative va_list version of clutter_container_add(). * * This function will call #ClutterContainerIface.add(), which is a * deprecated virtual function. The default implementation will * call clutter_actor_add_child(). * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_add_child() instead. */ void clutter_container_add_valist (ClutterContainer *container, ClutterActor *first_actor, va_list var_args) { g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); container_add_valist (container, first_actor, var_args); } /** * clutter_container_remove: (skip) * @container: a #ClutterContainer * @first_actor: first #ClutterActor to remove * @...: a %NULL-terminated list of actors to remove * * Removes a %NULL terminated list of #ClutterActors from * @container. Each actor should be unparented, so if you want to keep it * around you must hold a reference to it yourself, using g_object_ref(). * Each time an actor is removed, the "actor-removed" signal is * emitted by @container. * * This function will call #ClutterContainerIface.remove(), which is a * deprecated virtual function. The default implementation will call * clutter_actor_remove_child(). * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_remove_child() instead. */ void clutter_container_remove (ClutterContainer *container, ClutterActor *first_actor, ...) { va_list var_args; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); va_start (var_args, first_actor); container_remove_valist (container, first_actor, var_args); va_end (var_args); } /** * clutter_container_remove_actor: (virtual remove) * @container: a #ClutterContainer * @actor: a #ClutterActor * * Removes @actor from @container. The actor should be unparented, so * if you want to keep it around you must hold a reference to it * yourself, using g_object_ref(). When the actor has been removed, * the "actor-removed" signal is emitted by @container. * * This function will call #ClutterContainerIface.remove(), which is a * deprecated virtual function. The default implementation will call * clutter_actor_remove_child(). * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_remove_child() instead. */ void clutter_container_remove_actor (ClutterContainer *container, ClutterActor *actor) { g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); container_remove_actor (container, actor); } /** * clutter_container_remove_valist: (skip) * @container: a #ClutterContainer * @first_actor: the first #ClutterActor to add * @var_args: list of actors to remove, followed by %NULL * * Alternative va_list version of clutter_container_remove(). * * This function will call #ClutterContainerIface.remove(), which is a * deprecated virtual function. The default implementation will call * clutter_actor_remove_child(). * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_remove_child() instead. */ void clutter_container_remove_valist (ClutterContainer *container, ClutterActor *first_actor, va_list var_args) { g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (first_actor)); container_remove_valist (container, first_actor, var_args); } static void get_children_cb (ClutterActor *child, gpointer data) { GList **children = data; *children = g_list_prepend (*children, child); } /** * clutter_container_get_children: * @container: a #ClutterContainer * * Retrieves all the children of @container. * * Return value: (element-type Clutter.Actor) (transfer container): a list * of #ClutterActors. Use g_list_free() on the returned * list when done. * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_get_children() instead. */ GList * clutter_container_get_children (ClutterContainer *container) { GList *retval; g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL); retval = NULL; clutter_container_foreach (container, get_children_cb, &retval); return g_list_reverse (retval); } /** * clutter_container_foreach: * @container: a #ClutterContainer * @callback: (scope call): a function to be called for each child * @user_data: data to be passed to the function, or %NULL * * Calls @callback for each child of @container that was added * by the application (with clutter_container_add_actor()). Does * not iterate over "internal" children that are part of the * container's own implementation, if any. * * This function calls the #ClutterContainerIface.foreach() * virtual function, which has been deprecated. * * Since: 0.4 * * Deprecated: 1.10: Use clutter_actor_get_first_child() or * clutter_actor_get_last_child() to retrieve the beginning of * the list of children, and clutter_actor_get_next_sibling() * and clutter_actor_get_previous_sibling() to iterate over it; * alternatively, use the #ClutterActorIter API. */ void clutter_container_foreach (ClutterContainer *container, ClutterCallback callback, gpointer user_data) { g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (callback != NULL); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) { ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container); if (iface->foreach != container_real_foreach) _clutter_diagnostic_message ("The ClutterContainer::foreach() " "virtual function has been deprecated " "and it should not be overridden by " "newly written code"); } #endif /* CLUTTER_ENABLE_DEBUG */ CLUTTER_CONTAINER_GET_IFACE (container)->foreach (container, callback, user_data); } /** * clutter_container_foreach_with_internals: * @container: a #ClutterContainer * @callback: (scope call): a function to be called for each child * @user_data: data to be passed to the function, or %NULL * * Calls @callback for each child of @container, including "internal" * children built in to the container itself that were never added * by the application. * * This function calls the #ClutterContainerIface.foreach_with_internals() * virtual function, which has been deprecated. * * Since: 1.0 * * Deprecated: 1.10: See clutter_container_foreach(). */ void clutter_container_foreach_with_internals (ClutterContainer *container, ClutterCallback callback, gpointer user_data) { ClutterContainerIface *iface; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (callback != NULL); iface = CLUTTER_CONTAINER_GET_IFACE (container); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) { if (iface->foreach_with_internals != NULL) _clutter_diagnostic_message ("The ClutterContainer::foreach_with_internals() " "virtual function has been deprecated " "and it should not be overridden by " "newly written code"); } #endif /* CLUTTER_ENABLE_DEBUG */ if (iface->foreach_with_internals != NULL) iface->foreach_with_internals (container, callback, user_data); else iface->foreach (container, callback, user_data); } /** * clutter_container_raise_child: (virtual raise) * @container: a #ClutterContainer * @actor: the actor to raise * @sibling: (allow-none): the sibling to raise to, or %NULL to raise * to the top * * Raises @actor to @sibling level, in the depth ordering. * * This function calls the #ClutterContainerIface.raise() virtual function, * which has been deprecated. The default implementation will call * clutter_actor_set_child_above_sibling(). * * Since: 0.6 * * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead. */ void clutter_container_raise_child (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling) { ClutterContainerIface *iface; ClutterActor *self; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling)); if (actor == sibling) return; self = CLUTTER_ACTOR (container); if (clutter_actor_get_parent (actor) != self) { g_warning ("Actor of type '%s' is not a child of the container " "of type '%s'", g_type_name (G_OBJECT_TYPE (actor)), g_type_name (G_OBJECT_TYPE (container))); return; } if (sibling != NULL && clutter_actor_get_parent (sibling) != self) { g_warning ("Actor of type '%s' is not a child of the container " "of type '%s'", g_type_name (G_OBJECT_TYPE (sibling)), g_type_name (G_OBJECT_TYPE (container))); return; } iface = CLUTTER_CONTAINER_GET_IFACE (container); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) { if (iface->raise != container_real_raise) _clutter_diagnostic_message ("The ClutterContainer::raise() " "virtual function has been deprecated " "and it should not be overridden by " "newly written code"); } #endif /* CLUTTER_ENABLE_DEBUG */ iface->raise (container, actor, sibling); } /** * clutter_container_lower_child: (virtual lower) * @container: a #ClutterContainer * @actor: the actor to raise * @sibling: (allow-none): the sibling to lower to, or %NULL to lower * to the bottom * * Lowers @actor to @sibling level, in the depth ordering. * * This function calls the #ClutterContainerIface.lower() virtual function, * which has been deprecated. The default implementation will call * clutter_actor_set_child_below_sibling(). * * Since: 0.6 * * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead. */ void clutter_container_lower_child (ClutterContainer *container, ClutterActor *actor, ClutterActor *sibling) { ClutterContainerIface *iface; ClutterActor *self; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling)); if (actor == sibling) return; self = CLUTTER_ACTOR (container); if (clutter_actor_get_parent (actor) != self) { g_warning ("Actor of type '%s' is not a child of the container " "of type '%s'", g_type_name (G_OBJECT_TYPE (actor)), g_type_name (G_OBJECT_TYPE (container))); return; } if (sibling != NULL&& clutter_actor_get_parent (sibling) != self) { g_warning ("Actor of type '%s' is not a child of the container " "of type '%s'", g_type_name (G_OBJECT_TYPE (sibling)), g_type_name (G_OBJECT_TYPE (container))); return; } iface = CLUTTER_CONTAINER_GET_IFACE (container); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) { if (iface->lower != container_real_lower) _clutter_diagnostic_message ("The ClutterContainer::lower() " "virtual function has been deprecated " "and it should not be overridden by " "newly written code"); } #endif /* CLUTTER_ENABLE_DEBUG */ iface->lower (container, actor, sibling); } /** * clutter_container_sort_depth_order: * @container: a #ClutterContainer * * Sorts a container's children using their depth. This function should not * be normally used by applications. * * Since: 0.6 * * Deprecated: 1.10: The #ClutterContainerIface.sort_depth_order() virtual * function should not be used any more; the default implementation in * #ClutterContainer does not do anything. */ void clutter_container_sort_depth_order (ClutterContainer *container) { ClutterContainerIface *iface; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); iface = CLUTTER_CONTAINER_GET_IFACE (container); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) { if (iface->sort_depth_order != container_real_sort_depth_order) _clutter_diagnostic_message ("The ClutterContainer::sort_depth_order() " "virtual function has been deprecated " "and it should not be overridden by " "newly written code"); } #endif /* CLUTTER_ENABLE_DEBUG */ iface->sort_depth_order (container); } /** * clutter_container_find_child_by_name: * @container: a #ClutterContainer * @child_name: the name of the requested child. * * Finds a child actor of a container by its name. Search recurses * into any child container. * * Return value: (transfer none): The child actor with the requested name, * or %NULL if no actor with that name was found. * * Since: 0.6 */ ClutterActor * clutter_container_find_child_by_name (ClutterContainer *container, const gchar *child_name) { GList *children; GList *iter; ClutterActor *actor = NULL; g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL); g_return_val_if_fail (child_name != NULL, NULL); children = clutter_container_get_children (container); for (iter = children; iter; iter = g_list_next (iter)) { ClutterActor *a; const gchar *iter_name; a = CLUTTER_ACTOR (iter->data); iter_name = clutter_actor_get_name (a); if (iter_name && !strcmp (iter_name, child_name)) { actor = a; break; } if (CLUTTER_IS_CONTAINER (a)) { ClutterContainer *c = CLUTTER_CONTAINER (a); actor = clutter_container_find_child_by_name (c, child_name); if (actor) break; } } g_list_free (children); return actor; } static ClutterChildMeta * get_child_meta (ClutterContainer *container, ClutterActor *actor) { ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container); ClutterChildMeta *meta; if (iface->child_meta_type == G_TYPE_INVALID) return NULL; meta = g_object_get_qdata (G_OBJECT (actor), quark_child_meta); if (meta != NULL && meta->actor == actor) return meta; return NULL; } static void create_child_meta (ClutterContainer *container, ClutterActor *actor) { ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container); ClutterChildMeta *child_meta = NULL; if (iface->child_meta_type == G_TYPE_INVALID) return; if (!g_type_is_a (iface->child_meta_type, CLUTTER_TYPE_CHILD_META)) { g_warning ("%s: Child data of type '%s' is not a ClutterChildMeta", G_STRLOC, g_type_name (iface->child_meta_type)); return; } child_meta = g_object_new (iface->child_meta_type, "container", container, "actor", actor, NULL); g_object_set_qdata_full (G_OBJECT (actor), quark_child_meta, child_meta, (GDestroyNotify) g_object_unref); } static void destroy_child_meta (ClutterContainer *container, ClutterActor *actor) { ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container); if (iface->child_meta_type == G_TYPE_INVALID) return; g_object_set_qdata (G_OBJECT (actor), quark_child_meta, NULL); } /** * clutter_container_get_child_meta: * @container: a #ClutterContainer * @actor: a #ClutterActor that is a child of @container. * * Retrieves the #ClutterChildMeta which contains the data about the * @container specific state for @actor. * * Return value: (transfer none): the #ClutterChildMeta for the @actor child * of @container or %NULL if the specifiec actor does not exist or the * container is not configured to provide #ClutterChildMetas * * Since: 0.8 */ ClutterChildMeta * clutter_container_get_child_meta (ClutterContainer *container, ClutterActor *actor) { ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container); if (iface->child_meta_type == G_TYPE_INVALID) return NULL; if (G_LIKELY (iface->get_child_meta)) return iface->get_child_meta (container, actor); return NULL; } /** * clutter_container_create_child_meta: * @container: a #ClutterContainer * @actor: a #ClutterActor * * Creates the #ClutterChildMeta wrapping @actor inside the * @container, if the #ClutterContainerIface::child_meta_type * class member is not set to %G_TYPE_INVALID. * * This function is only useful when adding a #ClutterActor to * a #ClutterContainer implementation outside of the * #ClutterContainer::add() virtual function implementation. * * Applications should not call this function. * * Since: 1.2 */ void clutter_container_create_child_meta (ClutterContainer *container, ClutterActor *actor) { ClutterContainerIface *iface; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); iface = CLUTTER_CONTAINER_GET_IFACE (container); if (iface->child_meta_type == G_TYPE_INVALID) return; g_assert (g_type_is_a (iface->child_meta_type, CLUTTER_TYPE_CHILD_META)); if (G_LIKELY (iface->create_child_meta)) iface->create_child_meta (container, actor); } /** * clutter_container_destroy_child_meta: * @container: a #ClutterContainer * @actor: a #ClutterActor * * Destroys the #ClutterChildMeta wrapping @actor inside the * @container, if any. * * This function is only useful when removing a #ClutterActor to * a #ClutterContainer implementation outside of the * #ClutterContainer::add() virtual function implementation. * * Applications should not call this function. * * Since: 1.2 */ void clutter_container_destroy_child_meta (ClutterContainer *container, ClutterActor *actor) { ClutterContainerIface *iface; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); iface = CLUTTER_CONTAINER_GET_IFACE (container); if (iface->child_meta_type == G_TYPE_INVALID) return; if (G_LIKELY (iface->destroy_child_meta)) iface->destroy_child_meta (container, actor); } /** * clutter_container_class_find_child_property: * @klass: a #GObjectClass implementing the #ClutterContainer interface. * @property_name: a property name. * * Looks up the #GParamSpec for a child property of @klass. * * Return value: (transfer none): The #GParamSpec for the property or %NULL * if no such property exist. * * Since: 0.8 */ GParamSpec * clutter_container_class_find_child_property (GObjectClass *klass, const gchar *property_name) { ClutterContainerIface *iface; GObjectClass *child_class; GParamSpec *pspec; g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), NULL); g_return_val_if_fail (property_name != NULL, NULL); g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_CLASS (klass), CLUTTER_TYPE_CONTAINER), NULL); iface = g_type_interface_peek (klass, CLUTTER_TYPE_CONTAINER); g_return_val_if_fail (iface != NULL, NULL); if (iface->child_meta_type == G_TYPE_INVALID) return NULL; child_class = g_type_class_ref (iface->child_meta_type); pspec = g_object_class_find_property (child_class, property_name); g_type_class_unref (child_class); return pspec; } /** * clutter_container_class_list_child_properties: * @klass: a #GObjectClass implementing the #ClutterContainer interface. * @n_properties: return location for length of returned array. * * Returns an array of #GParamSpec for all child properties. * * Return value: (array length=n_properties) (transfer full): an array * of #GParamSpecs which should be freed after use. * * Since: 0.8 */ GParamSpec ** clutter_container_class_list_child_properties (GObjectClass *klass, guint *n_properties) { ClutterContainerIface *iface; GObjectClass *child_class; GParamSpec **retval; g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), NULL); g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_CLASS (klass), CLUTTER_TYPE_CONTAINER), NULL); iface = g_type_interface_peek (klass, CLUTTER_TYPE_CONTAINER); g_return_val_if_fail (iface != NULL, NULL); if (iface->child_meta_type == G_TYPE_INVALID) return NULL; child_class = g_type_class_ref (iface->child_meta_type); retval = g_object_class_list_properties (child_class, n_properties); g_type_class_unref (child_class); return retval; } static void child_notify (ClutterContainer *container, ClutterActor *actor, GParamSpec *pspec) { } static inline void container_set_child_property (ClutterContainer *container, ClutterActor *actor, const GValue *value, GParamSpec *pspec) { ClutterChildMeta *data; data = clutter_container_get_child_meta (container, actor); g_object_set_property (G_OBJECT (data), pspec->name, value); g_signal_emit (container, container_signals[CHILD_NOTIFY], (pspec->flags & G_PARAM_STATIC_NAME) ? g_quark_from_static_string (pspec->name) : g_quark_from_string (pspec->name), actor, pspec); } /** * clutter_container_child_set_property: * @container: a #ClutterContainer * @child: a #ClutterActor that is a child of @container. * @property: the name of the property to set. * @value: the value. * * Sets a container-specific property on a child of @container. * * Since: 0.8 */ void clutter_container_child_set_property (ClutterContainer *container, ClutterActor *child, const gchar *property, const GValue *value) { GObjectClass *klass; GParamSpec *pspec; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (property != NULL); g_return_if_fail (value != NULL); klass = G_OBJECT_GET_CLASS (container); pspec = clutter_container_class_find_child_property (klass, property); if (!pspec) { g_warning ("%s: Containers of type '%s' have no child " "property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (container), property); return; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("%s: Child property '%s' of the container '%s' " "is not writable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container)); return; } container_set_child_property (container, child, value, pspec); } /** * clutter_container_child_set: * @container: a #ClutterContainer * @actor: a #ClutterActor that is a child of @container. * @first_prop: name of the first property to be set. * @...: value for the first property, followed optionally by more name/value * pairs terminated with NULL. * * Sets container specific properties on the child of a container. * * Since: 0.8 */ void clutter_container_child_set (ClutterContainer *container, ClutterActor *actor, const gchar *first_prop, ...) { GObjectClass *klass; const gchar *name; va_list var_args; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); klass = G_OBJECT_GET_CLASS (container); va_start (var_args, first_prop); name = first_prop; while (name) { GValue value = G_VALUE_INIT; gchar *error = NULL; GParamSpec *pspec; pspec = clutter_container_class_find_child_property (klass, name); if (!pspec) { g_warning ("%s: Containers of type '%s' have no child " "property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (container), name); break; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_warning ("%s: Child property '%s' of the container '%s' " "is not writable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container)); break; } G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec), var_args, 0, &error); if (error) { /* we intentionally leak the GValue because it might * be in an undefined state and calling g_value_unset() * on it might crash */ g_warning ("%s: %s", G_STRLOC, error); free (error); break; } container_set_child_property (container, actor, &value, pspec); g_value_unset (&value); name = va_arg (var_args, gchar*); } va_end (var_args); } static inline void container_get_child_property (ClutterContainer *container, ClutterActor *actor, GValue *value, GParamSpec *pspec) { ClutterChildMeta *data; data = clutter_container_get_child_meta (container, actor); g_object_get_property (G_OBJECT (data), pspec->name, value); } /** * clutter_container_child_get_property: * @container: a #ClutterContainer * @child: a #ClutterActor that is a child of @container. * @property: the name of the property to set. * @value: the value. * * Gets a container specific property of a child of @container, In general, * a copy is made of the property contents and the caller is responsible for * freeing the memory by calling g_value_unset(). * * Note that clutter_container_child_set_property() is really intended for * language bindings, clutter_container_child_set() is much more convenient * for C programming. * * Since: 0.8 */ void clutter_container_child_get_property (ClutterContainer *container, ClutterActor *child, const gchar *property, GValue *value) { GObjectClass *klass; GParamSpec *pspec; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (property != NULL); g_return_if_fail (value != NULL); klass = G_OBJECT_GET_CLASS (container); pspec = clutter_container_class_find_child_property (klass, property); if (!pspec) { g_warning ("%s: Containers of type '%s' have no child " "property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (container), property); return; } if (!(pspec->flags & G_PARAM_READABLE)) { g_warning ("%s: Child property '%s' of the container '%s' " "is not writable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container)); return; } container_get_child_property (container, child, value, pspec); } /** * clutter_container_child_get: * @container: a #ClutterContainer * @actor: a #ClutterActor that is a child of @container. * @first_prop: name of the first property to be set. * @...: value for the first property, followed optionally by more name/value * pairs terminated with NULL. * * Gets @container specific properties of an actor. * * In general, a copy is made of the property contents and the caller is * responsible for freeing the memory in the appropriate manner for the type, for * instance by calling free() or g_object_unref(). * * Since: 0.8 */ void clutter_container_child_get (ClutterContainer *container, ClutterActor *actor, const gchar *first_prop, ...) { GObjectClass *klass; const gchar *name; va_list var_args; g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); klass = G_OBJECT_GET_CLASS (container); va_start (var_args, first_prop); name = first_prop; while (name) { GValue value = G_VALUE_INIT; gchar *error = NULL; GParamSpec *pspec; pspec = clutter_container_class_find_child_property (klass, name); if (!pspec) { g_warning ("%s: container '%s' has no child property named '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (container), name); break; } if (!(pspec->flags & G_PARAM_READABLE)) { g_warning ("%s: child property '%s' of container '%s' is not readable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container)); break; } g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); container_get_child_property (container, actor, &value, pspec); G_VALUE_LCOPY (&value, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); free (error); g_value_unset (&value); break; } g_value_unset (&value); name = va_arg (var_args, gchar*); } va_end (var_args); } /** * clutter_container_child_notify: * @container: a #ClutterContainer * @child: a #ClutterActor * @pspec: a #GParamSpec * * Calls the #ClutterContainerIface.child_notify() virtual function * of #ClutterContainer. The default implementation will emit the * #ClutterContainer::child-notify signal. * * Since: 1.6 */ void clutter_container_child_notify (ClutterContainer *container, ClutterActor *child, GParamSpec *pspec) { g_return_if_fail (CLUTTER_IS_CONTAINER (container)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (pspec != NULL); g_return_if_fail (clutter_actor_get_parent (child) == CLUTTER_ACTOR (container)); CLUTTER_CONTAINER_GET_IFACE (container)->child_notify (container, child, pspec); } muffin-5.2.1/clutter/clutter/clutter-desaturate-effect.h0000664000175000017500000000444114211404421023527 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_DESATURATE_EFFECT_H__ #define __CLUTTER_DESATURATE_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_DESATURATE_EFFECT (clutter_desaturate_effect_get_type ()) #define CLUTTER_DESATURATE_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffect)) #define CLUTTER_IS_DESATURATE_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DESATURATE_EFFECT)) /** * ClutterDesaturateEffect: * * #ClutterDesaturateEffect is an opaque structure * whose members cannot be directly accessed * * Since: 1.4 */ typedef struct _ClutterDesaturateEffect ClutterDesaturateEffect; typedef struct _ClutterDesaturateEffectClass ClutterDesaturateEffectClass; CLUTTER_AVAILABLE_IN_1_4 GType clutter_desaturate_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterEffect *clutter_desaturate_effect_new (gdouble factor); CLUTTER_AVAILABLE_IN_1_4 void clutter_desaturate_effect_set_factor (ClutterDesaturateEffect *effect, gdouble factor); CLUTTER_AVAILABLE_IN_1_4 gdouble clutter_desaturate_effect_get_factor (ClutterDesaturateEffect *effect); G_END_DECLS #endif /* __CLUTTER_DESATURATE_EFFECT_H__ */ muffin-5.2.1/clutter/clutter/clutter-stage-manager.c0000664000175000017500000002167414211404421022651 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 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, see . * * Author: Emmanuele Bassi */ /** * SECTION:clutter-stage-manager * @short_description: Maintains the list of stages * * #ClutterStageManager is a singleton object, owned by Clutter, which * maintains the list of currently active stages * * Every newly-created #ClutterStage will cause the emission of the * #ClutterStageManager::stage-added signal; once a #ClutterStage has * been destroyed, the #ClutterStageManager::stage-removed signal will * be emitted * * #ClutterStageManager is available since Clutter 0.8 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-stage-manager-private.h" #include "clutter-marshal.h" #include "clutter-debug.h" #include "clutter-private.h" #include "clutter-version.h" #include "deprecated/clutter-stage-manager.h" enum { PROP_0, PROP_DEFAULT_STAGE }; enum { STAGE_ADDED, STAGE_REMOVED, LAST_SIGNAL }; static guint manager_signals[LAST_SIGNAL] = { 0, }; static ClutterStage *default_stage = NULL; G_DEFINE_TYPE (ClutterStageManager, clutter_stage_manager, G_TYPE_OBJECT); static void clutter_stage_manager_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_DEFAULT_STAGE: g_value_set_object (value, default_stage); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_stage_manager_dispose (GObject *gobject) { ClutterStageManager *stage_manager; stage_manager = CLUTTER_STAGE_MANAGER (gobject); g_slist_foreach (stage_manager->stages, (GFunc) clutter_actor_destroy, NULL); g_slist_free (stage_manager->stages); stage_manager->stages = NULL; G_OBJECT_CLASS (clutter_stage_manager_parent_class)->dispose (gobject); } static void clutter_stage_manager_class_init (ClutterStageManagerClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = clutter_stage_manager_dispose; gobject_class->get_property = clutter_stage_manager_get_property; /** * ClutterStageManager:default-stage: * * The default stage used by Clutter. * * Since: 0.8 */ g_object_class_install_property (gobject_class, PROP_DEFAULT_STAGE, g_param_spec_object ("default-stage", "Default Stage", "The default stage", CLUTTER_TYPE_STAGE, CLUTTER_PARAM_READABLE)); /** * ClutterStageManager::stage-added: * @stage_manager: the object which received the signal * @stage: the added stage * * The ::stage-added signal is emitted each time a new #ClutterStage * has been added to the stage manager. * * Since: 0.8 */ manager_signals[STAGE_ADDED] = g_signal_new ("stage-added", G_OBJECT_CLASS_TYPE (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterStageManagerClass, stage_added), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_STAGE); /** * ClutterStageManager::stage-removed: * @stage_manager: the object which received the signal * @stage: the removed stage * * The ::stage-removed signal is emitted each time a #ClutterStage * has been removed from the stage manager. * * Since: 0.8 */ manager_signals[STAGE_REMOVED] = g_signal_new ("stage-removed", G_OBJECT_CLASS_TYPE (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterStageManagerClass, stage_removed), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_STAGE); } static void clutter_stage_manager_init (ClutterStageManager *stage_manager) { } /** * clutter_stage_manager_get_default: * * Returns the default #ClutterStageManager. * * Return value: (transfer none): the default stage manager instance. The returned * object is owned by Clutter and you should not reference or unreference it. * * Since: 0.8 */ ClutterStageManager * clutter_stage_manager_get_default (void) { ClutterMainContext *context = _clutter_context_get_default (); if (G_UNLIKELY (context->stage_manager == NULL)) context->stage_manager = g_object_new (CLUTTER_TYPE_STAGE_MANAGER, NULL); return context->stage_manager; } /** * clutter_stage_manager_set_default_stage: * @stage_manager: a #ClutterStageManager * @stage: a #ClutterStage * * Sets @stage as the default stage. * * Since: 0.8 * * Deprecated: 1.2: Calling this function has no effect */ void clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manager, ClutterStage *stage) { } /*< private > * _clutter_stage_manager_set_default_stage: * @stage_manager: a #ClutterStageManager * @stage: a #ClutterStage * * Sets @stage as the default stage * * A no-op if there already is a default stage */ void _clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manager, ClutterStage *stage) { if (G_UNLIKELY (default_stage == NULL)) { default_stage = stage; /* the default stage is immediately realized */ clutter_actor_realize (CLUTTER_ACTOR (stage)); g_object_notify (G_OBJECT (stage_manager), "default-stage"); } } /** * clutter_stage_manager_get_default_stage: * @stage_manager: a #ClutterStageManager * * Returns the default #ClutterStage. * * Return value: (transfer none): the default stage. The returned object * is owned by Clutter and you should never reference or unreference it * * Since: 0.8 */ ClutterStage * clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager) { return default_stage; } /** * clutter_stage_manager_list_stages: * @stage_manager: a #ClutterStageManager * * Lists all currently used stages. * * Return value: (transfer container) (element-type Clutter.Stage): a newly * allocated list of #ClutterStage objects. Use g_slist_free() to * deallocate it when done. * * Since: 0.8 */ GSList * clutter_stage_manager_list_stages (ClutterStageManager *stage_manager) { return g_slist_copy (stage_manager->stages); } /** * clutter_stage_manager_peek_stages: * @stage_manager: a #ClutterStageManager * * Lists all currently used stages. * * Return value: (transfer none) (element-type Clutter.Stage): a pointer * to the internal list of #ClutterStage objects. The returned list * is owned by the #ClutterStageManager and should never be modified * or freed * * Since: 1.0 */ const GSList * clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager) { return stage_manager->stages; } void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager, ClutterStage *stage) { if (g_slist_find (stage_manager->stages, stage)) { g_warning ("Trying to add a stage to the list of managed stages, " "but it is already in it, aborting."); return; } g_object_ref_sink (stage); stage_manager->stages = g_slist_append (stage_manager->stages, stage); g_signal_emit (stage_manager, manager_signals[STAGE_ADDED], 0, stage); } void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager, ClutterStage *stage) { /* this might be called multiple times from a ::dispose, so it * needs to just return without warning */ if (!g_slist_find (stage_manager->stages, stage)) return; stage_manager->stages = g_slist_remove (stage_manager->stages, stage); /* if the default stage is being destroyed then we unset the pointer */ if (default_stage == stage) default_stage = NULL; g_signal_emit (stage_manager, manager_signals[STAGE_REMOVED], 0, stage); g_object_unref (stage); } muffin-5.2.1/clutter/clutter/clutter-bezier.h0000664000175000017500000000434414211404421021416 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Tomas Frydrych * * Copyright (C) 2006, 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, see . */ #ifndef __CLUTTER_BEZIER_H__ #define __CLUTTER_BEZIER_H__ #include #include "clutter-types.h" G_BEGIN_DECLS /* This is used in _clutter_bezier_advance to represent the full length of the bezier curve. Anything less than that represents a fraction of the length */ #define CLUTTER_BEZIER_MAX_LENGTH (1 << 18) typedef struct _ClutterBezier ClutterBezier; ClutterBezier *_clutter_bezier_new (); void _clutter_bezier_free (ClutterBezier * b); ClutterBezier *_clutter_bezier_clone_and_move (const ClutterBezier *b, gint x, gint y); void _clutter_bezier_advance (const ClutterBezier *b, gint L, ClutterKnot *knot); void _clutter_bezier_init (ClutterBezier *b, gint x_0, gint y_0, gint x_1, gint y_1, gint x_2, gint y_2, gint x_3, gint y_3); void _clutter_bezier_adjust (ClutterBezier *b, ClutterKnot *knot, guint indx); guint _clutter_bezier_get_length (const ClutterBezier *b); G_END_DECLS #endif /* __CLUTTER_BEZIER_H__ */ muffin-5.2.1/clutter/clutter/clutter-id-pool.c0000664000175000017500000000653314211404421021476 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006-2008 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, see . * * * * ClutterIDPool: pool of reusable integer ids associated with pointers. * * Author: Øyvind Kolås * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-debug.h" #include "clutter-id-pool.h" struct _ClutterIDPool { GArray *array; /* Array of pointers */ GSList *free_ids; /* A stack of freed ids */ }; ClutterIDPool * _clutter_id_pool_new (guint initial_size) { ClutterIDPool *self; self = g_slice_new (ClutterIDPool); self->array = g_array_sized_new (FALSE, FALSE, sizeof (gpointer), initial_size); self->free_ids = NULL; return self; } void _clutter_id_pool_free (ClutterIDPool *id_pool) { g_return_if_fail (id_pool != NULL); g_array_free (id_pool->array, TRUE); g_slist_free (id_pool->free_ids); g_slice_free (ClutterIDPool, id_pool); } guint32 _clutter_id_pool_add (ClutterIDPool *id_pool, gpointer ptr) { gpointer *array; guint32 retval; g_return_val_if_fail (id_pool != NULL, 0); if (id_pool->free_ids) /* There are items on our freelist, reuse one */ { array = (void*) id_pool->array->data; retval = GPOINTER_TO_UINT (id_pool->free_ids->data); id_pool->free_ids = g_slist_remove (id_pool->free_ids, id_pool->free_ids->data); array[retval] = ptr; return retval; } /* Allocate new id */ retval = id_pool->array->len; g_array_append_val (id_pool->array, ptr); return retval; } void _clutter_id_pool_remove (ClutterIDPool *id_pool, guint32 id_) { gpointer *array; g_return_if_fail (id_pool != NULL); array = (void*) id_pool->array->data; array[id_] = NULL; id_pool->free_ids = g_slist_prepend (id_pool->free_ids, GUINT_TO_POINTER (id_)); } gpointer _clutter_id_pool_lookup (ClutterIDPool *id_pool, guint32 id_) { gpointer *array; g_return_val_if_fail (id_pool != NULL, NULL); g_return_val_if_fail (id_pool->array != NULL, NULL); array = (void*) id_pool->array->data; if (id_ >= id_pool->array->len || array[id_] == NULL) { g_warning ("The required ID of %u does not refer to an existing actor; " "this usually implies that the pick() of an actor is not " "correctly implemented or that there is an error in the " "glReadPixels() implementation of the GL driver.", id_); return NULL; } return array[id_]; } muffin-5.2.1/clutter/clutter/clutter-snap-constraint.h0000664000175000017500000000705114211404421023257 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_SNAP_CONSTRAINT_H__ #define __CLUTTER_SNAP_CONSTRAINT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_SNAP_CONSTRAINT (clutter_snap_constraint_get_type ()) #define CLUTTER_SNAP_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SNAP_CONSTRAINT, ClutterSnapConstraint)) #define CLUTTER_IS_SNAP_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SNAP_CONSTRAINT)) /** * ClutterSnapConstraint: * * #ClutterSnapConstraint is an opaque structure * whose members cannot be directly accesses * * Since: 1.6 */ typedef struct _ClutterSnapConstraint ClutterSnapConstraint; typedef struct _ClutterSnapConstraintClass ClutterSnapConstraintClass; CLUTTER_AVAILABLE_IN_1_6 GType clutter_snap_constraint_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_6 ClutterConstraint * clutter_snap_constraint_new (ClutterActor *source, ClutterSnapEdge from_edge, ClutterSnapEdge to_edge, gfloat offset); CLUTTER_AVAILABLE_IN_1_6 void clutter_snap_constraint_set_source (ClutterSnapConstraint *constraint, ClutterActor *source); CLUTTER_AVAILABLE_IN_1_6 ClutterActor * clutter_snap_constraint_get_source (ClutterSnapConstraint *constraint); CLUTTER_AVAILABLE_IN_1_6 void clutter_snap_constraint_set_edges (ClutterSnapConstraint *constraint, ClutterSnapEdge from_edge, ClutterSnapEdge to_edge); CLUTTER_AVAILABLE_IN_1_6 void clutter_snap_constraint_get_edges (ClutterSnapConstraint *constraint, ClutterSnapEdge *from_edge, ClutterSnapEdge *to_edge); CLUTTER_AVAILABLE_IN_1_6 void clutter_snap_constraint_set_offset (ClutterSnapConstraint *constraint, gfloat offset); CLUTTER_AVAILABLE_IN_1_6 gfloat clutter_snap_constraint_get_offset (ClutterSnapConstraint *constraint); G_END_DECLS #endif /* __CLUTTER_SNAP_CONSTRAINT_H__ */ muffin-5.2.1/clutter/clutter/clutter-layout-meta.c0000664000175000017500000000763514211404421022400 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-layout-meta * @short_description: Wrapper for actors inside a layout manager * * #ClutterLayoutMeta is a wrapper object created by #ClutterLayoutManager * implementations in order to store child-specific data and properties. * * A #ClutterLayoutMeta wraps a #ClutterActor inside a #ClutterContainer * using a #ClutterLayoutManager. * * #ClutterLayoutMeta is available since Clutter 1.2 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-layout-meta.h" #include "clutter-debug.h" #include "clutter-private.h" G_DEFINE_ABSTRACT_TYPE (ClutterLayoutMeta, clutter_layout_meta, CLUTTER_TYPE_CHILD_META); enum { PROP_0, PROP_MANAGER, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; static void clutter_layout_meta_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterLayoutMeta *layout_meta = CLUTTER_LAYOUT_META (object); switch (prop_id) { case PROP_MANAGER: layout_meta->manager = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_layout_meta_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterLayoutMeta *layout_meta = CLUTTER_LAYOUT_META (object); switch (prop_id) { case PROP_MANAGER: g_value_set_object (value, layout_meta->manager); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_layout_meta_class_init (ClutterLayoutMetaClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; gobject_class->set_property = clutter_layout_meta_set_property; gobject_class->get_property = clutter_layout_meta_get_property; /** * ClutterLayoutMeta:manager: * * The #ClutterLayoutManager that created this #ClutterLayoutMeta. * * Since: 1.2 */ pspec = g_param_spec_object ("manager", P_("Manager"), P_("The manager that created this data"), CLUTTER_TYPE_LAYOUT_MANAGER, G_PARAM_CONSTRUCT_ONLY | CLUTTER_PARAM_READWRITE); obj_props[PROP_MANAGER] = pspec; g_object_class_install_property (gobject_class, PROP_MANAGER, pspec); } static void clutter_layout_meta_init (ClutterLayoutMeta *self) { } /** * clutter_layout_meta_get_manager: * @data: a #ClutterLayoutMeta * * Retrieves the actor wrapped by @data * * Return value: (transfer none): a #ClutterLayoutManager * * Since: 1.2 */ ClutterLayoutManager * clutter_layout_meta_get_manager (ClutterLayoutMeta *data) { g_return_val_if_fail (CLUTTER_IS_LAYOUT_META (data), NULL); return data->manager; } muffin-5.2.1/clutter/clutter/clutter-effect.c0000664000175000017500000002735714211404421021376 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-effect * @short_description: Base class for actor effects * * The #ClutterEffect class provides a default type and API for creating * effects for generic actors. * * Effects are a #ClutterActorMeta sub-class that modify the way an actor * is painted in a way that is not part of the actor's implementation. * * Effects should be the preferred way to affect the paint sequence of an * actor without sub-classing the actor itself and overriding the * #ClutterActorClass.paint()_ virtual function. * * ## Implementing a ClutterEffect * * Creating a sub-class of #ClutterEffect requires overriding the * #ClutterEffectClass.paint() method. The implementation of the function should look * something like this: * * |[ * void effect_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags) * { * // Set up initialisation of the paint such as binding a * // CoglOffscreen or other operations * * // Chain to the next item in the paint sequence. This will either call * // ‘paint’ on the next effect or just paint the actor if this is * // the last effect. * ClutterActor *actor = * clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); * * clutter_actor_continue_paint (actor); * * // perform any cleanup of state, such as popping the CoglOffscreen * } * ]| * * The effect can optionally avoid calling clutter_actor_continue_paint() to skip any * further stages of the paint sequence. This is useful for example if the effect * contains a cached image of the actor. In that case it can optimise painting by * avoiding the actor paint and instead painting the cached image. * * The %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY flag is useful in this case. Clutter will set * this flag when a redraw has been queued on the actor since it was last painted. The * effect can use this information to decide if the cached image is still valid. * * ## A simple ClutterEffect implementation * * The example below creates two rectangles: one will be painted "behind" the actor, * while another will be painted "on top" of the actor. * * The #ClutterActorMetaClass.set_actor() implementation will create the two materials * used for the two different rectangles; the #ClutterEffectClass.paint() implementation * will paint the first material using cogl_rectangle(), before continuing and then it * will paint paint the second material after. * * |[ * typedef struct { * ClutterEffect parent_instance; * * CoglHandle rect_1; * CoglHandle rect_2; * } MyEffect; * * typedef struct _ClutterEffectClass MyEffectClass; * * G_DEFINE_TYPE (MyEffect, my_effect, CLUTTER_TYPE_EFFECT); * * static void * my_effect_set_actor (ClutterActorMeta *meta, * ClutterActor *actor) * { * MyEffect *self = MY_EFFECT (meta); * * // Clear the previous state // * if (self->rect_1) * { * cogl_handle_unref (self->rect_1); * self->rect_1 = NULL; * } * * if (self->rect_2) * { * cogl_handle_unref (self->rect_2); * self->rect_2 = NULL; * } * * // Maintain a pointer to the actor * self->actor = actor; * * // If we've been detached by the actor then we should just bail out here * if (self->actor == NULL) * return; * * // Create a red material * self->rect_1 = cogl_material_new (); * cogl_material_set_color4f (self->rect_1, 1.0, 0.0, 0.0, 1.0); * * // Create a green material * self->rect_2 = cogl_material_new (); * cogl_material_set_color4f (self->rect_2, 0.0, 1.0, 0.0, 1.0); * } * * static gboolean * my_effect_paint (ClutterEffect *effect) * { * MyEffect *self = MY_EFFECT (effect); * gfloat width, height; * * clutter_actor_get_size (self->actor, &width, &height); * * // Paint the first rectangle in the upper left quadrant * cogl_set_source (self->rect_1); * cogl_rectangle (0, 0, width / 2, height / 2); * * // Continue to the rest of the paint sequence * clutter_actor_continue_paint (self->actor); * * // Paint the second rectangle in the lower right quadrant * cogl_set_source (self->rect_2); * cogl_rectangle (width / 2, height / 2, width, height); * } * * static void * my_effect_class_init (MyEffectClass *klass) * { * ClutterActorMetaClas *meta_class = CLUTTER_ACTOR_META_CLASS (klass); * * meta_class->set_actor = my_effect_set_actor; * * klass->paint = my_effect_paint; * } * ]| * * #ClutterEffect is available since Clutter 1.4 */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-effect.h" #include "clutter-actor-meta-private.h" #include "clutter-debug.h" #include "clutter-effect-private.h" #include "clutter-enum-types.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-actor-private.h" G_DEFINE_ABSTRACT_TYPE (ClutterEffect, clutter_effect, CLUTTER_TYPE_ACTOR_META); static gboolean clutter_effect_real_pre_paint (ClutterEffect *effect) { return TRUE; } static void clutter_effect_real_post_paint (ClutterEffect *effect) { } static gboolean clutter_effect_real_get_paint_volume (ClutterEffect *effect, ClutterPaintVolume *volume) { return TRUE; } static void clutter_effect_real_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags) { ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect); ClutterActor *actor; gboolean pre_paint_succeeded; /* The default implementation provides a compatibility wrapper for effects that haven't migrated to use the 'paint' virtual yet. This just calls the old pre and post virtuals before chaining on */ pre_paint_succeeded = _clutter_effect_pre_paint (effect); actor = clutter_actor_meta_get_actor (actor_meta); clutter_actor_continue_paint (actor); if (pre_paint_succeeded) _clutter_effect_post_paint (effect); } static void clutter_effect_real_pick (ClutterEffect *effect, ClutterEffectPaintFlags flags) { ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect); ClutterActor *actor; actor = clutter_actor_meta_get_actor (actor_meta); clutter_actor_continue_paint (actor); } static void clutter_effect_notify (GObject *gobject, GParamSpec *pspec) { if (strcmp (pspec->name, "enabled") == 0) { ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject); ClutterActor *actor = clutter_actor_meta_get_actor (meta); if (actor != NULL) clutter_actor_queue_redraw (actor); } if (G_OBJECT_CLASS (clutter_effect_parent_class)->notify != NULL) G_OBJECT_CLASS (clutter_effect_parent_class)->notify (gobject, pspec); } static void clutter_effect_class_init (ClutterEffectClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->notify = clutter_effect_notify; klass->pre_paint = clutter_effect_real_pre_paint; klass->post_paint = clutter_effect_real_post_paint; klass->get_paint_volume = clutter_effect_real_get_paint_volume; klass->paint = clutter_effect_real_paint; klass->pick = clutter_effect_real_pick; } static void clutter_effect_init (ClutterEffect *self) { } gboolean _clutter_effect_pre_paint (ClutterEffect *effect) { g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE); return CLUTTER_EFFECT_GET_CLASS (effect)->pre_paint (effect); } void _clutter_effect_post_paint (ClutterEffect *effect) { g_return_if_fail (CLUTTER_IS_EFFECT (effect)); CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect); } void _clutter_effect_paint (ClutterEffect *effect, ClutterEffectPaintFlags flags) { g_return_if_fail (CLUTTER_IS_EFFECT (effect)); CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, flags); } void _clutter_effect_pick (ClutterEffect *effect, ClutterEffectPaintFlags flags) { g_return_if_fail (CLUTTER_IS_EFFECT (effect)); CLUTTER_EFFECT_GET_CLASS (effect)->pick (effect, flags); } gboolean _clutter_effect_get_paint_volume (ClutterEffect *effect, ClutterPaintVolume *volume) { g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE); g_return_val_if_fail (volume != NULL, FALSE); return CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume); } /** * clutter_effect_queue_repaint: * @effect: A #ClutterEffect which needs redrawing * * Queues a repaint of the effect. The effect can detect when the ‘paint’ * method is called as a result of this function because it will not * have the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY flag set. In that case the * effect is free to assume that the actor has not changed its * appearance since the last time it was painted so it doesn't need to * call clutter_actor_continue_paint() if it can draw a cached * image. This is mostly intended for effects that are using a * %CoglOffscreen to redirect the actor (such as * %ClutterOffscreenEffect). In that case the effect can save a bit of * rendering time by painting the cached texture without causing the * entire actor to be painted. * * This function can be used by effects that have their own animatable * parameters. For example, an effect which adds a varying degree of a * red tint to an actor by redirecting it through a CoglOffscreen * might have a property to specify the level of tint. When this value * changes, the underlying actor doesn't need to be redrawn so the * effect can call clutter_effect_queue_repaint() to make sure the * effect is repainted. * * Note however that modifying the position of the parent of an actor * may change the appearance of the actor because its transformation * matrix would change. In this case a redraw wouldn't be queued on * the actor itself so the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY would still * not be set. The effect can detect this case by keeping track of the * last modelview matrix that was used to render the actor and * veryifying that it remains the same in the next paint. * * Any other effects that are layered on top of the passed in effect * will still be passed the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY flag. If * anything queues a redraw on the actor without specifying an effect * or with an effect that is lower in the chain of effects than this * one then that will override this call. In that case this effect * will instead be called with the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY * flag set. * * Since: 1.8 */ void clutter_effect_queue_repaint (ClutterEffect *effect) { ClutterActor *actor; g_return_if_fail (CLUTTER_IS_EFFECT (effect)); actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); /* If the effect has no actor then nothing needs to be done */ if (actor != NULL) _clutter_actor_queue_redraw_full (actor, 0, /* flags */ NULL, /* clip volume */ effect /* effect */); } muffin-5.2.1/clutter/clutter/clutter-input-focus-private.h0000664000175000017500000000333314211404421024057 0ustar jpeisachjpeisach/* * Copyright (C) 2017,2018 Red Hat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Carlos Garnacho */ #ifndef __CLUTTER_INPUT_FOCUS_PRIVATE_H__ #define __CLUTTER_INPUT_FOCUS_PRIVATE_H__ void clutter_input_focus_focus_in (ClutterInputFocus *focus, ClutterInputMethod *method); void clutter_input_focus_focus_out (ClutterInputFocus *focus); void clutter_input_focus_commit (ClutterInputFocus *focus, const gchar *text); void clutter_input_focus_delete_surrounding (ClutterInputFocus *focus, guint offset, guint len); void clutter_input_focus_request_surrounding (ClutterInputFocus *focus); void clutter_input_focus_set_preedit_text (ClutterInputFocus *focus, const gchar *preedit, guint cursor); #endif /* __CLUTTER_INPUT_FOCUS_PRIVATE_H__ */ muffin-5.2.1/clutter/clutter/clutter-shader-types.c0000664000175000017500000003513114211404421022537 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * Chris Lord * * Copyright (C) 2008 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, see . * * */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include #include #include "clutter-shader-types.h" #include "clutter-private.h" static GTypeInfo shader_float_info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, }; static GTypeFundamentalInfo shader_float_finfo = { 0, }; static GTypeInfo shader_int_info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, }; static GTypeFundamentalInfo shader_int_finfo = { 0, }; static GTypeInfo shader_matrix_info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, }; static GTypeFundamentalInfo shader_matrix_finfo = { 0, }; struct _ClutterShaderFloat { gint size; float value[4]; }; struct _ClutterShaderInt { gint size; int value[4]; }; struct _ClutterShaderMatrix { gint size; float value[16]; }; static gpointer clutter_value_peek_pointer (const GValue *value) { return value->data[0].v_pointer; } /* Float */ static void clutter_value_init_shader_float (GValue *value) { value->data[0].v_pointer = g_slice_new0 (ClutterShaderFloat); } static void clutter_value_free_shader_float (GValue *value) { g_slice_free (ClutterShaderFloat, value->data[0].v_pointer); } static void clutter_value_copy_shader_float (const GValue *src, GValue *dest) { dest->data[0].v_pointer = g_slice_dup (ClutterShaderFloat, src->data[0].v_pointer); } static gchar * clutter_value_collect_shader_float (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint float_count = collect_values[0].v_int; const float *floats = collect_values[1].v_pointer; if (!floats) return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); clutter_value_init_shader_float (value); clutter_value_set_shader_float (value, float_count, floats); return NULL; } static gchar * clutter_value_lcopy_shader_float (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint *float_count = collect_values[0].v_pointer; float **floats = collect_values[1].v_pointer; ClutterShaderFloat *shader_float = value->data[0].v_pointer; if (!float_count || !floats) return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); *float_count = shader_float->size; *floats = g_memdup (shader_float->value, shader_float->size * sizeof (float)); return NULL; } static const GTypeValueTable _clutter_shader_float_value_table = { clutter_value_init_shader_float, clutter_value_free_shader_float, clutter_value_copy_shader_float, clutter_value_peek_pointer, "ip", clutter_value_collect_shader_float, "pp", clutter_value_lcopy_shader_float }; GType clutter_shader_float_get_type (void) { static GType _clutter_shader_float_type = 0; if (G_UNLIKELY (_clutter_shader_float_type == 0)) { shader_float_info.value_table = & _clutter_shader_float_value_table; _clutter_shader_float_type = g_type_register_fundamental (g_type_fundamental_next (), I_("ClutterShaderFloat"), &shader_float_info, &shader_float_finfo, 0); } return _clutter_shader_float_type; } /* Integer */ static void clutter_value_init_shader_int (GValue *value) { value->data[0].v_pointer = g_slice_new0 (ClutterShaderInt); } static void clutter_value_free_shader_int (GValue *value) { g_slice_free (ClutterShaderInt, value->data[0].v_pointer); } static void clutter_value_copy_shader_int (const GValue *src, GValue *dest) { dest->data[0].v_pointer = g_slice_dup (ClutterShaderInt, src->data[0].v_pointer); } static gchar * clutter_value_collect_shader_int (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint int_count = collect_values[0].v_int; const int *ints = collect_values[1].v_pointer; if (!ints) return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); clutter_value_init_shader_int (value); clutter_value_set_shader_int (value, int_count, ints); return NULL; } static gchar * clutter_value_lcopy_shader_int (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint *int_count = collect_values[0].v_pointer; int **ints = collect_values[1].v_pointer; ClutterShaderInt *shader_int = value->data[0].v_pointer; if (!int_count || !ints) return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); *int_count = shader_int->size; *ints = g_memdup (shader_int->value, shader_int->size * sizeof (int)); return NULL; } static const GTypeValueTable _clutter_shader_int_value_table = { clutter_value_init_shader_int, clutter_value_free_shader_int, clutter_value_copy_shader_int, clutter_value_peek_pointer, "ip", clutter_value_collect_shader_int, "pp", clutter_value_lcopy_shader_int }; GType clutter_shader_int_get_type (void) { static GType _clutter_shader_int_type = 0; if (G_UNLIKELY (_clutter_shader_int_type == 0)) { shader_int_info.value_table = & _clutter_shader_int_value_table; _clutter_shader_int_type = g_type_register_fundamental (g_type_fundamental_next (), I_("ClutterShaderInt"), &shader_int_info, &shader_int_finfo, 0); } return _clutter_shader_int_type; } /* Matrix */ static void clutter_value_init_shader_matrix (GValue *value) { value->data[0].v_pointer = g_slice_new0 (ClutterShaderMatrix); } static void clutter_value_free_shader_matrix (GValue *value) { g_slice_free (ClutterShaderMatrix, value->data[0].v_pointer); } static void clutter_value_copy_shader_matrix (const GValue *src, GValue *dest) { dest->data[0].v_pointer = g_slice_dup (ClutterShaderMatrix, src->data[0].v_pointer); } static gchar * clutter_value_collect_shader_matrix (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint float_count = collect_values[0].v_int; const float *floats = collect_values[1].v_pointer; if (!floats) return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); clutter_value_init_shader_matrix (value); clutter_value_set_shader_matrix (value, float_count, floats); return NULL; } static gchar * clutter_value_lcopy_shader_matrix (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint *float_count = collect_values[0].v_pointer; float **floats = collect_values[1].v_pointer; ClutterShaderFloat *shader_float = value->data[0].v_pointer; if (!float_count || !floats) return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); *float_count = shader_float->size; *floats = g_memdup (shader_float->value, shader_float->size * shader_float->size * sizeof (float)); return NULL; } static const GTypeValueTable _clutter_shader_matrix_value_table = { clutter_value_init_shader_matrix, clutter_value_free_shader_matrix, clutter_value_copy_shader_matrix, clutter_value_peek_pointer, "ip", clutter_value_collect_shader_matrix, "pp", clutter_value_lcopy_shader_matrix }; GType clutter_shader_matrix_get_type (void) { static GType _clutter_shader_matrix_type = 0; if (G_UNLIKELY (_clutter_shader_matrix_type == 0)) { shader_matrix_info.value_table = & _clutter_shader_matrix_value_table; _clutter_shader_matrix_type = g_type_register_fundamental (g_type_fundamental_next (), I_("ClutterShaderMatrix"), &shader_matrix_info, &shader_matrix_finfo, 0); } return _clutter_shader_matrix_type; } /* Utility functions */ /** * clutter_value_set_shader_float: * @value: a #GValue * @size: number of floating point values in @floats * @floats: (array length=size): an array of floating point values * * Sets @floats as the contents of @value. The passed #GValue * must have been initialized using %CLUTTER_TYPE_SHADER_FLOAT. * * Since: 0.8 */ void clutter_value_set_shader_float (GValue *value, gint size, const gfloat *floats) { ClutterShaderFloat *shader_float; gint i; g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value)); g_return_if_fail (size <= 4); shader_float = value->data[0].v_pointer; shader_float->size = size; for (i = 0; i < size; i++) shader_float->value[i] = floats[i]; } /** * clutter_value_set_shader_int: * @value: a #GValue * @size: number of integer values in @ints * @ints: (array length=size): an array of integer values * * Sets @ints as the contents of @value. The passed #GValue * must have been initialized using %CLUTTER_TYPE_SHADER_INT. * * Since: 0.8 */ void clutter_value_set_shader_int (GValue *value, gint size, const gint *ints) { ClutterShaderInt *shader_int; gint i; g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_INT (value)); g_return_if_fail (size <= 4); shader_int = value->data[0].v_pointer; shader_int->size = size; for (i = 0; i < size; i++) shader_int->value[i] = ints[i]; } /** * clutter_value_set_shader_matrix: * @value: a #GValue * @size: number of floating point values in @floats * @matrix: (array length=size): a matrix of floating point values * * Sets @matrix as the contents of @value. The passed #GValue * must have been initialized using %CLUTTER_TYPE_SHADER_MATRIX. * * Since: 0.8 */ void clutter_value_set_shader_matrix (GValue *value, gint size, const gfloat *matrix) { ClutterShaderMatrix *shader_matrix; gint i; g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value)); g_return_if_fail (size <= 4); shader_matrix = value->data[0].v_pointer; shader_matrix->size = size; for (i = 0; i < size * size; i++) shader_matrix->value[i] = matrix[i]; } /** * clutter_value_get_shader_float: * @value: a #GValue * @length: (out): return location for the number of returned floating * point values, or %NULL * * Retrieves the list of floating point values stored inside * the passed #GValue. @value must have been initialized with * %CLUTTER_TYPE_SHADER_FLOAT. * * Return value: (array length=length): the pointer to a list of * floating point values. The returned value is owned by the * #GValue and should never be modified or freed. * * Since: 0.8 */ const gfloat * clutter_value_get_shader_float (const GValue *value, gsize *length) { ClutterShaderFloat *shader_float; g_return_val_if_fail (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value), NULL); shader_float = value->data[0].v_pointer; if (length) *length = shader_float->size; return shader_float->value; } /** * clutter_value_get_shader_int: * @value: a #GValue * @length: (out): return location for the number of returned integer * values, or %NULL * * Retrieves the list of integer values stored inside the passed * #GValue. @value must have been initialized with * %CLUTTER_TYPE_SHADER_INT. * * Return value: (array length=length): the pointer to a list of * integer values. The returned value is owned by the #GValue and * should never be modified or freed. * * Since: 0.8 */ const gint * clutter_value_get_shader_int (const GValue *value, gsize *length) { ClutterShaderInt *shader_int; g_return_val_if_fail (CLUTTER_VALUE_HOLDS_SHADER_INT (value), NULL); shader_int = value->data[0].v_pointer; if (length) *length = shader_int->size; return shader_int->value; } /** * clutter_value_get_shader_matrix: * @value: a #GValue * @length: (out): return location for the number of returned floating * point values, or %NULL * * Retrieves a matrix of floating point values stored inside * the passed #GValue. @value must have been initialized with * %CLUTTER_TYPE_SHADER_MATRIX. * * Return value: (array length=length) (transfer none): the pointer to a matrix * of floating point values. The returned value is owned by the #GValue and * should never be modified or freed. * * Since: 0.8 */ const gfloat * clutter_value_get_shader_matrix (const GValue *value, gsize *length) { ClutterShaderMatrix *shader_matrix; g_return_val_if_fail (CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value), NULL); shader_matrix = value->data[0].v_pointer; if (length) *length = shader_matrix->size; return shader_matrix->value; } muffin-5.2.1/clutter/clutter/clutter-rotate-action.h0000664000175000017500000000650214211404421022705 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see . * * Author: * Lionel Landwerlin */ #ifndef __CLUTTER_ROTATE_ACTION_H__ #define __CLUTTER_ROTATE_ACTION_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_ROTATE_ACTION (clutter_rotate_action_get_type ()) #define CLUTTER_ROTATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ROTATE_ACTION, ClutterRotateAction)) #define CLUTTER_IS_ROTATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ROTATE_ACTION)) #define CLUTTER_ROTATE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ROTATE_ACTION, ClutterRotateActionClass)) #define CLUTTER_IS_ROTATE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ROTATE_ACTION)) #define CLUTTER_ROTATE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ROTATE_ACTION, ClutterRotateActionClass)) typedef struct _ClutterRotateAction ClutterRotateAction; typedef struct _ClutterRotateActionPrivate ClutterRotateActionPrivate; typedef struct _ClutterRotateActionClass ClutterRotateActionClass; /** * ClutterRotateAction: * * The #ClutterRotateAction structure contains * only private data and should be accessed using the provided API * * Since: 1.12 */ struct _ClutterRotateAction { /*< private >*/ ClutterGestureAction parent_instance; ClutterRotateActionPrivate *priv; }; /** * ClutterRotateActionClass: * @rotate: class handler for the #ClutterRotateAction::rotate signal * * The #ClutterRotateActionClass structure contains * only private data. * * Since: 1.12 */ struct _ClutterRotateActionClass { /*< private >*/ ClutterGestureActionClass parent_class; /*< public >*/ gboolean (* rotate) (ClutterRotateAction *action, ClutterActor *actor, gdouble angle); /*< private >*/ void (* _clutter_rotate_action1) (void); void (* _clutter_rotate_action2) (void); void (* _clutter_rotate_action3) (void); void (* _clutter_rotate_action4) (void); void (* _clutter_rotate_action5) (void); void (* _clutter_rotate_action6) (void); void (* _clutter_rotate_action7) (void); }; CLUTTER_AVAILABLE_IN_1_12 GType clutter_rotate_action_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_12 ClutterAction *clutter_rotate_action_new (void); G_END_DECLS #endif /* __CLUTTER_ROTATE_ACTION_H__ */ muffin-5.2.1/clutter/clutter/clutter-units.h0000664000175000017500000001445614211404421021305 0ustar jpeisachjpeisach/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Tomas Frydrych * Emmanuele Bassu * * Copyright (C) 2007, 2008 OpenedHand * 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, see . */ #ifndef __CLUTTER_UNITS_H__ #define __CLUTTER_UNITS_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS /** * ClutterUnits: * * An opaque structure, to be used to store sizing and positioning * values along with their unit. * * Since: 1.0 */ typedef struct _ClutterUnits ClutterUnits; struct _ClutterUnits { /*< private >*/ ClutterUnitType unit_type; gfloat value; /* pre-filled by the provided constructors */ /* cached pixel value */ gfloat pixels; /* whether the :pixels field is set */ guint pixels_set; /* the serial coming from the backend, used to evict the cache */ gint32 serial; /* padding for eventual expansion */ gint32 __padding_1; gint64 __padding_2; }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_units_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterUnitType clutter_units_get_unit_type (const ClutterUnits *units); CLUTTER_AVAILABLE_IN_1_0 gfloat clutter_units_get_unit_value (const ClutterUnits *units); CLUTTER_AVAILABLE_IN_1_0 ClutterUnits * clutter_units_copy (const ClutterUnits *units); CLUTTER_AVAILABLE_IN_1_0 void clutter_units_free (ClutterUnits *units); CLUTTER_AVAILABLE_IN_1_0 void clutter_units_from_pixels (ClutterUnits *units, gint px); CLUTTER_AVAILABLE_IN_1_0 void clutter_units_from_em (ClutterUnits *units, gfloat em); CLUTTER_AVAILABLE_IN_1_0 void clutter_units_from_em_for_font (ClutterUnits *units, const gchar *font_name, gfloat em); CLUTTER_AVAILABLE_IN_1_0 void clutter_units_from_mm (ClutterUnits *units, gfloat mm); CLUTTER_AVAILABLE_IN_1_0 void clutter_units_from_cm (ClutterUnits *units, gfloat cm); CLUTTER_AVAILABLE_IN_1_0 void clutter_units_from_pt (ClutterUnits *units, gfloat pt); CLUTTER_AVAILABLE_IN_1_0 gfloat clutter_units_to_pixels (ClutterUnits *units); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_units_from_string (ClutterUnits *units, const gchar *str); CLUTTER_AVAILABLE_IN_1_0 gchar * clutter_units_to_string (const ClutterUnits *units); /* shorthands for the constructors */ #define clutter_units_pixels clutter_units_from_pixels #define clutter_units_em clutter_units_from_em #define clutter_units_em_for_font clutter_units_from_em_for_font #define clutter_units_mm clutter_units_from_mm #define clutter_units_cm clutter_units_from_cm #define clutter_units_pt clutter_units_from_pt #define CLUTTER_TYPE_UNITS (clutter_units_get_type ()) #define CLUTTER_TYPE_PARAM_UNITS (clutter_param_units_get_type ()) #define CLUTTER_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNITS, ClutterParamSpecUnits)) #define CLUTTER_IS_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNITS)) /** * CLUTTER_VALUE_HOLDS_UNITS: * @x: a #GValue * * Evaluates to %TRUE if @x holds a #ClutterUnits value * * Since: 0.8 */ #define CLUTTER_VALUE_HOLDS_UNITS(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_UNITS)) typedef struct _ClutterParamSpecUnits ClutterParamSpecUnits; /** * ClutterParamSpecUnits: (skip) * @default_type: default type * @default_value: default value * @minimum: lower boundary * @maximum: higher boundary * * #GParamSpec subclass for unit based properties. * * Since: 1.0 */ struct _ClutterParamSpecUnits { /*< private >*/ GParamSpec parent_instance; /*< public >*/ ClutterUnitType default_type; gfloat default_value; gfloat minimum; gfloat maximum; }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_param_units_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 GParamSpec * clutter_param_spec_units (const gchar *name, const gchar *nick, const gchar *blurb, ClutterUnitType default_type, gfloat minimum, gfloat maximum, gfloat default_value, GParamFlags flags); CLUTTER_AVAILABLE_IN_1_0 void clutter_value_set_units (GValue *value, const ClutterUnits *units); CLUTTER_AVAILABLE_IN_1_0 const ClutterUnits * clutter_value_get_units (const GValue *value); G_END_DECLS #endif /* __CLUTTER_UNITS_H__ */ muffin-5.2.1/clutter/clutter/clutter-path-constraint.c0000664000175000017500000002563214211404421023252 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-path-constraint * @Title: ClutterPathConstraint * @Short_Description: A constraint that follows a path * * #ClutterPathConstraint is a simple constraint that modifies the allocation * of the #ClutterActor to which it has been applied using a #ClutterPath. * * By setting the #ClutterPathConstraint:offset property it is possible to * control how far along the path the #ClutterActor should be. * * ClutterPathConstraint is available since Clutter 1.6. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-path-constraint.h" #include "clutter-debug.h" #include "clutter-marshal.h" #include "clutter-private.h" #define CLUTTER_PATH_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_PATH_CONSTRAINT, ClutterPathConstraintClass)) #define CLUTTER_IS_PATH_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_PATH_CONSTRAINT)) #define CLUTTER_PATH_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_PATH_CONSTRAINT, ClutterPathConstraintClass)) struct _ClutterPathConstraint { ClutterConstraint parent_instance; ClutterPath *path; gfloat offset; ClutterActor *actor; guint current_node; }; struct _ClutterPathConstraintClass { ClutterConstraintClass parent_class; }; enum { PROP_0, PROP_PATH, PROP_OFFSET, LAST_PROPERTY }; enum { NODE_REACHED, LAST_SIGNAL }; G_DEFINE_TYPE (ClutterPathConstraint, clutter_path_constraint, CLUTTER_TYPE_CONSTRAINT); static GParamSpec *path_properties[LAST_PROPERTY] = { NULL, }; static guint path_signals[LAST_SIGNAL] = { 0, }; static void clutter_path_constraint_update_allocation (ClutterConstraint *constraint, ClutterActor *actor, ClutterActorBox *allocation) { ClutterPathConstraint *self = CLUTTER_PATH_CONSTRAINT (constraint); gfloat width, height; ClutterKnot position; guint knot_id; if (self->path == NULL) return; knot_id = clutter_path_get_position (self->path, self->offset, &position); clutter_actor_box_get_size (allocation, &width, &height); allocation->x1 = position.x; allocation->y1 = position.y; allocation->x2 = allocation->x1 + width; allocation->y2 = allocation->y1 + height; if (knot_id != self->current_node) { self->current_node = knot_id; g_signal_emit (self, path_signals[NODE_REACHED], 0, self->actor, self->current_node); } } static void clutter_path_constraint_set_actor (ClutterActorMeta *meta, ClutterActor *new_actor) { ClutterPathConstraint *path = CLUTTER_PATH_CONSTRAINT (meta); ClutterActorMetaClass *parent; /* store the pointer to the actor, for later use */ path->actor = new_actor; parent = CLUTTER_ACTOR_META_CLASS (clutter_path_constraint_parent_class); parent->set_actor (meta, new_actor); } static void clutter_path_constraint_dispose (GObject *gobject) { ClutterPathConstraint *self = CLUTTER_PATH_CONSTRAINT (gobject); if (self->path != NULL) { g_object_unref (self->path); self->path = NULL; } G_OBJECT_CLASS (clutter_path_constraint_parent_class)->dispose (gobject); } static void clutter_path_constraint_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterPathConstraint *self = CLUTTER_PATH_CONSTRAINT (gobject); switch (prop_id) { case PROP_PATH: clutter_path_constraint_set_path (self, g_value_get_object (value)); break; case PROP_OFFSET: clutter_path_constraint_set_offset (self, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_path_constraint_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterPathConstraint *self = CLUTTER_PATH_CONSTRAINT (gobject); switch (prop_id) { case PROP_PATH: g_value_set_object (value, self->path); break; case PROP_OFFSET: g_value_set_float (value, self->offset); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } } static void clutter_path_constraint_class_init (ClutterPathConstraintClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); ClutterConstraintClass *constraint_class = CLUTTER_CONSTRAINT_CLASS (klass); /** * ClutterPathConstraint:path: * * The #ClutterPath used to constrain the position of an actor. * * Since: 1.6 */ path_properties[PROP_PATH] = g_param_spec_object ("path", P_("Path"), P_("The path used to constrain an actor"), CLUTTER_TYPE_PATH, CLUTTER_PARAM_READWRITE); /** * ClutterPathConstraint:offset: * * The offset along the #ClutterPathConstraint:path, between -1.0 and 2.0. * * Since: 1.6 */ path_properties[PROP_OFFSET] = g_param_spec_float ("offset", P_("Offset"), P_("The offset along the path, between -1.0 and 2.0"), -1.0, 2.0, 0.0, CLUTTER_PARAM_READWRITE); gobject_class->set_property = clutter_path_constraint_set_property; gobject_class->get_property = clutter_path_constraint_get_property; gobject_class->dispose = clutter_path_constraint_dispose; g_object_class_install_properties (gobject_class, LAST_PROPERTY, path_properties); meta_class->set_actor = clutter_path_constraint_set_actor; constraint_class->update_allocation = clutter_path_constraint_update_allocation; /** * ClutterPathConstraint::node-reached: * @constraint: the #ClutterPathConstraint that emitted the signal * @actor: the #ClutterActor using the @constraint * @index: the index of the node that has been reached * * The ::node-reached signal is emitted each time a * #ClutterPathConstraint:offset value results in the actor * passing a #ClutterPathNode * * Since: 1.6 */ path_signals[NODE_REACHED] = g_signal_new (I_("node-reached"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__OBJECT_UINT, G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR, G_TYPE_UINT); } static void clutter_path_constraint_init (ClutterPathConstraint *self) { self->offset = 0.0f; self->current_node = G_MAXUINT; } /** * clutter_path_constraint_new: * @path: (allow-none): a #ClutterPath, or %NULL * @offset: the offset along the #ClutterPath * * Creates a new #ClutterPathConstraint with the given @path and @offset * * Return value: the newly created #ClutterPathConstraint * * Since: 1.6 */ ClutterConstraint * clutter_path_constraint_new (ClutterPath *path, gfloat offset) { g_return_val_if_fail (path == NULL || CLUTTER_IS_PATH (path), NULL); return g_object_new (CLUTTER_TYPE_PATH_CONSTRAINT, "path", path, "offset", offset, NULL); } /** * clutter_path_constraint_set_path: * @constraint: a #ClutterPathConstraint * @path: (allow-none): a #ClutterPath * * Sets the @path to be followed by the #ClutterPathConstraint. * * The @constraint will take ownership of the #ClutterPath passed to this * function. * * Since: 1.6 */ void clutter_path_constraint_set_path (ClutterPathConstraint *constraint, ClutterPath *path) { g_return_if_fail (CLUTTER_IS_PATH_CONSTRAINT (constraint)); g_return_if_fail (path == NULL || CLUTTER_IS_PATH (path)); if (constraint->path == path) return; if (constraint->path != NULL) { g_object_unref (constraint->path); constraint->path = NULL; } if (path != NULL) constraint->path = g_object_ref_sink (path); if (constraint->actor != NULL) clutter_actor_queue_relayout (constraint->actor); g_object_notify_by_pspec (G_OBJECT (constraint), path_properties[PROP_PATH]); } /** * clutter_path_constraint_get_path: * @constraint: a #ClutterPathConstraint * * Retrieves a pointer to the #ClutterPath used by @constraint. * * Return value: (transfer none): the #ClutterPath used by the * #ClutterPathConstraint, or %NULL. The returned #ClutterPath is owned * by the constraint and it should not be unreferenced * * Since: 1.6 */ ClutterPath * clutter_path_constraint_get_path (ClutterPathConstraint *constraint) { g_return_val_if_fail (CLUTTER_IS_PATH_CONSTRAINT (constraint), NULL); return constraint->path; } /** * clutter_path_constraint_set_offset: * @constraint: a #ClutterPathConstraint * @offset: the offset along the path * * Sets the offset along the #ClutterPath used by @constraint. * * Since: 1.6 */ void clutter_path_constraint_set_offset (ClutterPathConstraint *constraint, gfloat offset) { g_return_if_fail (CLUTTER_IS_PATH_CONSTRAINT (constraint)); if (constraint->offset == offset) return; constraint->offset = offset; if (constraint->actor != NULL) clutter_actor_queue_relayout (constraint->actor); g_object_notify_by_pspec (G_OBJECT (constraint), path_properties[PROP_OFFSET]); } /** * clutter_path_constraint_get_offset: * @constraint: a #ClutterPathConstraint * * Retrieves the offset along the #ClutterPath used by @constraint. * * Return value: the offset * * Since: 1.6 */ gfloat clutter_path_constraint_get_offset (ClutterPathConstraint *constraint) { g_return_val_if_fail (CLUTTER_IS_PATH_CONSTRAINT (constraint), 0.0); return constraint->offset; } muffin-5.2.1/clutter/clutter/clutter-page-turn-effect.h0000664000175000017500000000575514211404421023301 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi * * Based on MxDeformPageTurn, written by: * Chris Lord */ #ifndef __CLUTTER_PAGE_TURN_EFFECT_H__ #define __CLUTTER_PAGE_TURN_EFFECT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_PAGE_TURN_EFFECT (clutter_page_turn_effect_get_type ()) #define CLUTTER_PAGE_TURN_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_PAGE_TURN_EFFECT, ClutterPageTurnEffect)) #define CLUTTER_IS_PAGE_TURN_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_PAGE_TURN_EFFECT)) /** * ClutterPageTurnEffect: * * #ClutterPageTurnEffect is an opaque structure * whose members can only be accessed using the provided API * * Since: 1.4 */ typedef struct _ClutterPageTurnEffect ClutterPageTurnEffect; typedef struct _ClutterPageTurnEffectClass ClutterPageTurnEffectClass; CLUTTER_AVAILABLE_IN_1_4 GType clutter_page_turn_effect_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_4 ClutterEffect *clutter_page_turn_effect_new (gdouble period, gdouble angle, gfloat radius); CLUTTER_AVAILABLE_IN_1_4 void clutter_page_turn_effect_set_period (ClutterPageTurnEffect *effect, gdouble period); CLUTTER_AVAILABLE_IN_1_4 gdouble clutter_page_turn_effect_get_period (ClutterPageTurnEffect *effect); CLUTTER_AVAILABLE_IN_1_4 void clutter_page_turn_effect_set_angle (ClutterPageTurnEffect *effect, gdouble angle); CLUTTER_AVAILABLE_IN_1_4 gdouble clutter_page_turn_effect_get_angle (ClutterPageTurnEffect *effect); CLUTTER_AVAILABLE_IN_1_4 void clutter_page_turn_effect_set_radius (ClutterPageTurnEffect *effect, gfloat radius); CLUTTER_AVAILABLE_IN_1_4 gfloat clutter_page_turn_effect_get_radius (ClutterPageTurnEffect *effect); G_END_DECLS #endif /* __CLUTTER_PAGE_TURN_EFFECT_H__ */ muffin-5.2.1/clutter/clutter/clutter-text-buffer.c0000664000175000017500000005447114211404421022372 0ustar jpeisachjpeisach/* clutter-text-buffer.c * Copyright (C) 2011 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. * * Author: Stef Walter */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-text-buffer.h" #include "clutter-marshal.h" #include "clutter-private.h" #include /** * SECTION:clutter-text-buffer * @title: ClutterTextBuffer * @short_description: Text buffer for ClutterText * * The #ClutterTextBuffer class contains the actual text displayed in a * #ClutterText widget. * * A single #ClutterTextBuffer object can be shared by multiple #ClutterText * widgets which will then share the same text content, but not the cursor * position, visibility attributes, icon etc. * * #ClutterTextBuffer may be derived from. Such a derived class might allow * text to be stored in an alternate location, such as non-pageable memory, * useful in the case of important passwords. Or a derived class could * integrate with an application's concept of undo/redo. * * Since: 1.10 */ /* Initial size of buffer, in bytes */ #define MIN_SIZE 16 enum { PROP_0, PROP_TEXT, PROP_LENGTH, PROP_MAX_LENGTH, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; enum { INSERTED_TEXT, DELETED_TEXT, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; struct _ClutterTextBufferPrivate { gint max_length; /* Only valid if this class is not derived */ gchar *normal_text; gsize normal_text_size; gsize normal_text_bytes; guint normal_text_chars; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterTextBuffer, clutter_text_buffer, G_TYPE_OBJECT) /* -------------------------------------------------------------------------------- * DEFAULT IMPLEMENTATIONS OF TEXT BUFFER * * These may be overridden by a derived class, behavior may be changed etc... * The normal_text and normal_text_xxxx fields may not be valid when * this class is derived from. */ /* Overwrite a memory that might contain sensitive information. */ static void trash_area (gchar *area, gsize len) { volatile gchar *varea = (volatile gchar *)area; while (len-- > 0) *varea++ = 0; } static const gchar* clutter_text_buffer_normal_get_text (ClutterTextBuffer *buffer, gsize *n_bytes) { if (n_bytes) *n_bytes = buffer->priv->normal_text_bytes; if (!buffer->priv->normal_text) return ""; return buffer->priv->normal_text; } static guint clutter_text_buffer_normal_get_length (ClutterTextBuffer *buffer) { return buffer->priv->normal_text_chars; } static guint clutter_text_buffer_normal_insert_text (ClutterTextBuffer *buffer, guint position, const gchar *chars, guint n_chars) { ClutterTextBufferPrivate *pv = buffer->priv; gsize prev_size; gsize n_bytes; gsize at; n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars; /* Need more memory */ if (n_bytes + pv->normal_text_bytes + 1 > pv->normal_text_size) { gchar *et_new; prev_size = pv->normal_text_size; /* Calculate our new buffer size */ while (n_bytes + pv->normal_text_bytes + 1 > pv->normal_text_size) { if (pv->normal_text_size == 0) pv->normal_text_size = MIN_SIZE; else { if (2 * pv->normal_text_size < CLUTTER_TEXT_BUFFER_MAX_SIZE) pv->normal_text_size *= 2; else { pv->normal_text_size = CLUTTER_TEXT_BUFFER_MAX_SIZE; if (n_bytes > pv->normal_text_size - pv->normal_text_bytes - 1) { n_bytes = pv->normal_text_size - pv->normal_text_bytes - 1; n_bytes = g_utf8_find_prev_char (chars, chars + n_bytes + 1) - chars; n_chars = g_utf8_strlen (chars, n_bytes); } break; } } } /* Could be a password, so can't leave stuff in memory. */ et_new = malloc (pv->normal_text_size); memcpy (et_new, pv->normal_text, MIN (prev_size, pv->normal_text_size)); trash_area (pv->normal_text, prev_size); free (pv->normal_text); pv->normal_text = et_new; } /* Actual text insertion */ at = g_utf8_offset_to_pointer (pv->normal_text, position) - pv->normal_text; g_memmove (pv->normal_text + at + n_bytes, pv->normal_text + at, pv->normal_text_bytes - at); memcpy (pv->normal_text + at, chars, n_bytes); /* Book keeping */ pv->normal_text_bytes += n_bytes; pv->normal_text_chars += n_chars; pv->normal_text[pv->normal_text_bytes] = '\0'; clutter_text_buffer_emit_inserted_text (buffer, position, chars, n_chars); return n_chars; } static guint clutter_text_buffer_normal_delete_text (ClutterTextBuffer *buffer, guint position, guint n_chars) { ClutterTextBufferPrivate *pv = buffer->priv; gsize start, end; if (position > pv->normal_text_chars) position = pv->normal_text_chars; if (position + n_chars > pv->normal_text_chars) n_chars = pv->normal_text_chars - position; if (n_chars > 0) { start = g_utf8_offset_to_pointer (pv->normal_text, position) - pv->normal_text; end = g_utf8_offset_to_pointer (pv->normal_text, position + n_chars) - pv->normal_text; g_memmove (pv->normal_text + start, pv->normal_text + end, pv->normal_text_bytes + 1 - end); pv->normal_text_chars -= n_chars; pv->normal_text_bytes -= (end - start); /* * Could be a password, make sure we don't leave anything sensitive after * the terminating zero. Note, that the terminating zero already trashed * one byte. */ trash_area (pv->normal_text + pv->normal_text_bytes + 1, end - start - 1); clutter_text_buffer_emit_deleted_text (buffer, position, n_chars); } return n_chars; } /* -------------------------------------------------------------------------------- * */ static void clutter_text_buffer_real_inserted_text (ClutterTextBuffer *buffer, guint position, const gchar *chars, guint n_chars) { g_object_notify (G_OBJECT (buffer), "text"); g_object_notify (G_OBJECT (buffer), "length"); } static void clutter_text_buffer_real_deleted_text (ClutterTextBuffer *buffer, guint position, guint n_chars) { g_object_notify (G_OBJECT (buffer), "text"); g_object_notify (G_OBJECT (buffer), "length"); } /* -------------------------------------------------------------------------------- * */ static void clutter_text_buffer_init (ClutterTextBuffer *self) { self->priv = clutter_text_buffer_get_instance_private (self); self->priv->normal_text = NULL; self->priv->normal_text_chars = 0; self->priv->normal_text_bytes = 0; self->priv->normal_text_size = 0; } static void clutter_text_buffer_finalize (GObject *obj) { ClutterTextBuffer *buffer = CLUTTER_TEXT_BUFFER (obj); ClutterTextBufferPrivate *pv = buffer->priv; if (pv->normal_text) { trash_area (pv->normal_text, pv->normal_text_size); free (pv->normal_text); pv->normal_text = NULL; pv->normal_text_bytes = pv->normal_text_size = 0; pv->normal_text_chars = 0; } G_OBJECT_CLASS (clutter_text_buffer_parent_class)->finalize (obj); } static void clutter_text_buffer_set_property (GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterTextBuffer *buffer = CLUTTER_TEXT_BUFFER (obj); switch (prop_id) { case PROP_MAX_LENGTH: clutter_text_buffer_set_max_length (buffer, g_value_get_int (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void clutter_text_buffer_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterTextBuffer *buffer = CLUTTER_TEXT_BUFFER (obj); switch (prop_id) { case PROP_TEXT: g_value_set_string (value, clutter_text_buffer_get_text (buffer)); break; case PROP_LENGTH: g_value_set_uint (value, clutter_text_buffer_get_length (buffer)); break; case PROP_MAX_LENGTH: g_value_set_int (value, clutter_text_buffer_get_max_length (buffer)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } static void clutter_text_buffer_class_init (ClutterTextBufferClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = clutter_text_buffer_finalize; gobject_class->set_property = clutter_text_buffer_set_property; gobject_class->get_property = clutter_text_buffer_get_property; klass->get_text = clutter_text_buffer_normal_get_text; klass->get_length = clutter_text_buffer_normal_get_length; klass->insert_text = clutter_text_buffer_normal_insert_text; klass->delete_text = clutter_text_buffer_normal_delete_text; klass->inserted_text = clutter_text_buffer_real_inserted_text; klass->deleted_text = clutter_text_buffer_real_deleted_text; /** * ClutterTextBuffer:text: * * The contents of the buffer. * * Since: 1.10 */ obj_props[PROP_TEXT] = g_param_spec_string ("text", P_("Text"), P_("The contents of the buffer"), "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * ClutterTextBuffer:length: * * The length (in characters) of the text in buffer. * * Since: 1.10 */ obj_props[PROP_LENGTH] = g_param_spec_uint ("length", P_("Text length"), P_("Length of the text currently in the buffer"), 0, CLUTTER_TEXT_BUFFER_MAX_SIZE, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * ClutterTextBuffer:max-length: * * The maximum length (in characters) of the text in the buffer. * * Since: 1.10 */ obj_props[PROP_MAX_LENGTH] = g_param_spec_int ("max-length", P_("Maximum length"), P_("Maximum number of characters for this entry. Zero if no maximum"), 0, CLUTTER_TEXT_BUFFER_MAX_SIZE, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); /** * ClutterTextBuffer::inserted-text: * @buffer: a #ClutterTextBuffer * @position: the position the text was inserted at. * @chars: The text that was inserted. * @n_chars: The number of characters that were inserted. * * This signal is emitted after text is inserted into the buffer. * * Since: 1.10 */ signals[INSERTED_TEXT] = g_signal_new (I_("inserted-text"), CLUTTER_TYPE_TEXT_BUFFER, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterTextBufferClass, inserted_text), NULL, NULL, _clutter_marshal_VOID__UINT_STRING_UINT, G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT); /** * ClutterTextBuffer::deleted-text: * @buffer: a #ClutterTextBuffer * @position: the position the text was deleted at. * @n_chars: The number of characters that were deleted. * * This signal is emitted after text is deleted from the buffer. * * Since: 1.10 */ signals[DELETED_TEXT] = g_signal_new (I_("deleted-text"), CLUTTER_TYPE_TEXT_BUFFER, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterTextBufferClass, deleted_text), NULL, NULL, _clutter_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); } /* -------------------------------------------------------------------------------- * */ /** * clutter_text_buffer_new: * * Create a new ClutterTextBuffer object. * * Return value: A new ClutterTextBuffer object. * * Since: 1.10 **/ ClutterTextBuffer* clutter_text_buffer_new (void) { return g_object_new (CLUTTER_TYPE_TEXT_BUFFER, NULL); } /** * clutter_text_buffer_new_with_text: * @text: (allow-none): initial buffer text * @text_len: initial buffer text length, or -1 for null-terminated. * * Create a new ClutterTextBuffer object with some text. * * Return value: A new ClutterTextBuffer object. * * Since: 1.10 **/ ClutterTextBuffer* clutter_text_buffer_new_with_text (const gchar *text, gssize text_len) { ClutterTextBuffer *buffer; buffer = clutter_text_buffer_new (); clutter_text_buffer_set_text (buffer, text, text_len); return buffer; } /** * clutter_text_buffer_get_length: * @buffer: a #ClutterTextBuffer * * Retrieves the length in characters of the buffer. * * Return value: The number of characters in the buffer. * * Since: 1.10 **/ guint clutter_text_buffer_get_length (ClutterTextBuffer *buffer) { ClutterTextBufferClass *klass; g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), 0); klass = CLUTTER_TEXT_BUFFER_GET_CLASS (buffer); g_return_val_if_fail (klass->get_length != NULL, 0); return (*klass->get_length) (buffer); } /** * clutter_text_buffer_get_bytes: * @buffer: a #ClutterTextBuffer * * Retrieves the length in bytes of the buffer. * See clutter_text_buffer_get_length(). * * Return value: The byte length of the buffer. * * Since: 1.10 **/ gsize clutter_text_buffer_get_bytes (ClutterTextBuffer *buffer) { ClutterTextBufferClass *klass; gsize bytes = 0; g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), 0); klass = CLUTTER_TEXT_BUFFER_GET_CLASS (buffer); g_return_val_if_fail (klass->get_text != NULL, 0); (*klass->get_text) (buffer, &bytes); return bytes; } /** * clutter_text_buffer_get_text: * @buffer: a #ClutterTextBuffer * * Retrieves the contents of the buffer. * * The memory pointer returned by this call will not change * unless this object emits a signal, or is finalized. * * Return value: a pointer to the contents of the widget as a * string. This string points to internally allocated * storage in the buffer and must not be freed, modified or * stored. * * Since: 1.10 **/ const gchar* clutter_text_buffer_get_text (ClutterTextBuffer *buffer) { ClutterTextBufferClass *klass; g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), NULL); klass = CLUTTER_TEXT_BUFFER_GET_CLASS (buffer); g_return_val_if_fail (klass->get_text != NULL, NULL); return (*klass->get_text) (buffer, NULL); } /** * clutter_text_buffer_set_text: * @buffer: a #ClutterTextBuffer * @chars: the new text * @n_chars: the number of characters in @text, or -1 * * Sets the text in the buffer. * * This is roughly equivalent to calling clutter_text_buffer_delete_text() * and clutter_text_buffer_insert_text(). * * Note that @n_chars is in characters, not in bytes. * * Since: 1.10 **/ void clutter_text_buffer_set_text (ClutterTextBuffer *buffer, const gchar *chars, gint n_chars) { g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer)); g_return_if_fail (chars != NULL); g_object_freeze_notify (G_OBJECT (buffer)); clutter_text_buffer_delete_text (buffer, 0, -1); clutter_text_buffer_insert_text (buffer, 0, chars, n_chars); g_object_thaw_notify (G_OBJECT (buffer)); } /** * clutter_text_buffer_set_max_length: * @buffer: a #ClutterTextBuffer * @max_length: the maximum length of the entry buffer, or 0 for no maximum. * (other than the maximum length of entries.) The value passed in will * be clamped to the range [ 0, %CLUTTER_TEXT_BUFFER_MAX_SIZE ]. * * Sets the maximum allowed length of the contents of the buffer. If * the current contents are longer than the given length, then they * will be truncated to fit. * * Since: 1.10 **/ void clutter_text_buffer_set_max_length (ClutterTextBuffer *buffer, gint max_length) { g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer)); max_length = CLAMP (max_length, 0, CLUTTER_TEXT_BUFFER_MAX_SIZE); if (max_length > 0 && clutter_text_buffer_get_length (buffer) > max_length) clutter_text_buffer_delete_text (buffer, max_length, -1); buffer->priv->max_length = max_length; g_object_notify (G_OBJECT (buffer), "max-length"); } /** * clutter_text_buffer_get_max_length: * @buffer: a #ClutterTextBuffer * * Retrieves the maximum allowed length of the text in * @buffer. See clutter_text_buffer_set_max_length(). * * Return value: the maximum allowed number of characters * in #ClutterTextBuffer, or 0 if there is no maximum. * * Since: 1.10 */ gint clutter_text_buffer_get_max_length (ClutterTextBuffer *buffer) { g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), 0); return buffer->priv->max_length; } /** * clutter_text_buffer_insert_text: * @buffer: a #ClutterTextBuffer * @position: the position at which to insert text. * @chars: the text to insert into the buffer. * @n_chars: the length of the text in characters, or -1 * * Inserts @n_chars characters of @chars into the contents of the * buffer, at position @position. * * If @n_chars is negative, then characters from chars will be inserted * until a null-terminator is found. If @position or @n_chars are out of * bounds, or the maximum buffer text length is exceeded, then they are * coerced to sane values. * * Note that the position and length are in characters, not in bytes. * * Returns: The number of characters actually inserted. * * Since: 1.10 */ guint clutter_text_buffer_insert_text (ClutterTextBuffer *buffer, guint position, const gchar *chars, gint n_chars) { ClutterTextBufferClass *klass; ClutterTextBufferPrivate *pv; guint length; g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), 0); length = clutter_text_buffer_get_length (buffer); pv = buffer->priv; if (n_chars < 0) n_chars = g_utf8_strlen (chars, -1); /* Bring position into bounds */ if (position > length) position = length; /* Make sure not entering too much data */ if (pv->max_length > 0) { if (length >= pv->max_length) n_chars = 0; else if (length + n_chars > pv->max_length) n_chars -= (length + n_chars) - pv->max_length; } klass = CLUTTER_TEXT_BUFFER_GET_CLASS (buffer); g_return_val_if_fail (klass->insert_text != NULL, 0); return (klass->insert_text) (buffer, position, chars, n_chars); } /** * clutter_text_buffer_delete_text: * @buffer: a #ClutterTextBuffer * @position: position at which to delete text * @n_chars: number of characters to delete * * Deletes a sequence of characters from the buffer. @n_chars characters are * deleted starting at @position. If @n_chars is negative, then all characters * until the end of the text are deleted. * * If @position or @n_chars are out of bounds, then they are coerced to sane * values. * * Note that the positions are specified in characters, not bytes. * * Returns: The number of characters deleted. * * Since: 1.10 */ guint clutter_text_buffer_delete_text (ClutterTextBuffer *buffer, guint position, gint n_chars) { ClutterTextBufferClass *klass; guint length; g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), 0); length = clutter_text_buffer_get_length (buffer); if (n_chars < 0) n_chars = length; if (position > length) position = length; if (position + n_chars > length) n_chars = length - position; klass = CLUTTER_TEXT_BUFFER_GET_CLASS (buffer); g_return_val_if_fail (klass->delete_text != NULL, 0); return (klass->delete_text) (buffer, position, n_chars); } /** * clutter_text_buffer_emit_inserted_text: * @buffer: a #ClutterTextBuffer * @position: position at which text was inserted * @chars: text that was inserted * @n_chars: number of characters inserted * * Emits the #ClutterTextBuffer::inserted-text signal on @buffer. * * Used when subclassing #ClutterTextBuffer * * Since: 1.10 */ void clutter_text_buffer_emit_inserted_text (ClutterTextBuffer *buffer, guint position, const gchar *chars, guint n_chars) { g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer)); g_signal_emit (buffer, signals[INSERTED_TEXT], 0, position, chars, n_chars); } /** * clutter_text_buffer_emit_deleted_text: * @buffer: a #ClutterTextBuffer * @position: position at which text was deleted * @n_chars: number of characters deleted * * Emits the #ClutterTextBuffer::deleted-text signal on @buffer. * * Used when subclassing #ClutterTextBuffer * * Since: 1.10 */ void clutter_text_buffer_emit_deleted_text (ClutterTextBuffer *buffer, guint position, guint n_chars) { g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer)); g_signal_emit (buffer, signals[DELETED_TEXT], 0, position, n_chars); } muffin-5.2.1/clutter/clutter/clutter-debug.h0000664000175000017500000000620714211404421021224 0ustar jpeisachjpeisach#ifndef __CLUTTER_DEBUG_H__ #define __CLUTTER_DEBUG_H__ #include #include "clutter-main.h" G_BEGIN_DECLS typedef enum { CLUTTER_DEBUG_MISC = 1 << 0, CLUTTER_DEBUG_ACTOR = 1 << 1, CLUTTER_DEBUG_TEXTURE = 1 << 2, CLUTTER_DEBUG_EVENT = 1 << 3, CLUTTER_DEBUG_PAINT = 1 << 4, CLUTTER_DEBUG_PANGO = 1 << 5, CLUTTER_DEBUG_BACKEND = 1 << 6, CLUTTER_DEBUG_SCHEDULER = 1 << 7, CLUTTER_DEBUG_SCRIPT = 1 << 8, CLUTTER_DEBUG_SHADER = 1 << 9, CLUTTER_DEBUG_MULTISTAGE = 1 << 10, CLUTTER_DEBUG_ANIMATION = 1 << 11, CLUTTER_DEBUG_LAYOUT = 1 << 12, CLUTTER_DEBUG_PICK = 1 << 13, CLUTTER_DEBUG_EVENTLOOP = 1 << 14, CLUTTER_DEBUG_CLIPPING = 1 << 15, CLUTTER_DEBUG_OOB_TRANSFORMS = 1 << 16 } ClutterDebugFlag; typedef enum { CLUTTER_DEBUG_NOP_PICKING = 1 << 0, CLUTTER_DEBUG_DUMP_PICK_BUFFERS = 1 << 1 } ClutterPickDebugFlag; typedef enum { CLUTTER_DEBUG_DISABLE_SWAP_EVENTS = 1 << 0, CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS = 1 << 1, CLUTTER_DEBUG_REDRAWS = 1 << 2, CLUTTER_DEBUG_PAINT_VOLUMES = 1 << 3, CLUTTER_DEBUG_DISABLE_CULLING = 1 << 4, CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT = 1 << 5, CLUTTER_DEBUG_CONTINUOUS_REDRAW = 1 << 6, CLUTTER_DEBUG_PAINT_DEFORM_TILES = 1 << 7 } ClutterDrawDebugFlag; #ifdef CLUTTER_ENABLE_DEBUG #define CLUTTER_HAS_DEBUG(type) ((clutter_debug_flags & CLUTTER_DEBUG_##type) != FALSE) #ifdef __GNUC__ /* Try the GCC extension for valists in macros */ #define CLUTTER_NOTE(type,x,a...) G_STMT_START { \ if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \ _clutter_debug_message ("[" #type "]:" G_STRLOC ": " x, ##a); \ } } G_STMT_END #else /* !__GNUC__ */ /* Try the C99 version; unfortunately, this does not allow us to pass * empty arguments to the macro, which means we have to * do an intemediate printf. */ #define CLUTTER_NOTE(type,...) G_STMT_START { \ if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \ gchar *_fmt = g_strdup_printf (__VA_ARGS__); \ _clutter_debug_message ("[" #type "]:" G_STRLOC ": %s", _fmt); \ free (_fmt); \ } } G_STMT_END #endif #else /* !CLUTTER_ENABLE_DEBUG */ #define CLUTTER_NOTE(type,...) G_STMT_START { } G_STMT_END #define CLUTTER_HAS_DEBUG(type) FALSE #endif /* CLUTTER_ENABLE_DEBUG */ extern guint clutter_debug_flags; extern guint clutter_pick_debug_flags; extern guint clutter_paint_debug_flags; void _clutter_debug_messagev (const char *format, va_list var_args); void _clutter_debug_message (const char *format, ...); G_END_DECLS #endif /* __CLUTTER_DEBUG_H__ */ muffin-5.2.1/clutter/clutter/clutter-content.c0000664000175000017500000002065514211404421021606 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2011 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-content * @Title: ClutterContent * @Short_Description: Delegate for painting the content of an actor * * #ClutterContent is an interface to implement types responsible for * painting the content of a #ClutterActor. * * Multiple actors can use the same #ClutterContent instance, in order * to share the resources associated with painting the same content. * * #ClutterContent is available since Clutter 1.10. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #include "clutter-content-private.h" #include "clutter-debug.h" #include "clutter-marshal.h" #include "clutter-private.h" typedef struct _ClutterContentIface ClutterContentInterface; enum { ATTACHED, DETACHED, LAST_SIGNAL }; static GQuark quark_content_actors = 0; static guint content_signals[LAST_SIGNAL] = { 0, }; G_DEFINE_INTERFACE (ClutterContent, clutter_content, G_TYPE_OBJECT) static gboolean clutter_content_real_get_preferred_size (ClutterContent *content, gfloat *width, gfloat *height) { if (width != NULL) *width = 0.f; if (height != NULL) *height = 0.f; return FALSE; } static void clutter_content_real_attached (ClutterContent *content, ClutterActor *actor) { } static void clutter_content_real_detached (ClutterContent *content, ClutterActor *actor) { } static void clutter_content_real_invalidate (ClutterContent *content) { } static void clutter_content_real_paint_content (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *context) { } static void clutter_content_default_init (ClutterContentInterface *iface) { quark_content_actors = g_quark_from_static_string ("-clutter-content-actors"); iface->get_preferred_size = clutter_content_real_get_preferred_size; iface->paint_content = clutter_content_real_paint_content; iface->attached = clutter_content_real_attached; iface->detached = clutter_content_real_detached; iface->invalidate = clutter_content_real_invalidate; /** * ClutterContent::attached: * @content: the object that emitted the signal * @actor: a #ClutterActor * * This signal is emitted each time a #ClutterContent implementation is * assigned to a #ClutterActor. * * Since: 1.10 */ content_signals[ATTACHED] = g_signal_new (I_("attached"), G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterContentIface, attached), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterContent::detached: * @content: the object that emitted the signal * @actor: a #ClutterActor * * This signal is emitted each time a #ClutterContent implementation is * removed from a #ClutterActor. * * Since: 1.10 */ content_signals[DETACHED] = g_signal_new (I_("detached"), G_TYPE_FROM_INTERFACE (iface), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterContentIface, detached), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); } /** * clutter_content_invalidate: * @content: a #ClutterContent * * Invalidates a #ClutterContent. * * This function should be called by #ClutterContent implementations when * they change the way a the content should be painted regardless of the * actor state. * * Since: 1.10 */ void clutter_content_invalidate (ClutterContent *content) { GHashTable *actors; GHashTableIter iter; gpointer key_p, value_p; g_return_if_fail (CLUTTER_IS_CONTENT (content)); CLUTTER_CONTENT_GET_IFACE (content)->invalidate (content); actors = g_object_get_qdata (G_OBJECT (content), quark_content_actors); if (actors == NULL) return; g_hash_table_iter_init (&iter, actors); while (g_hash_table_iter_next (&iter, &key_p, &value_p)) { ClutterActor *actor = key_p; g_assert (actor != NULL); clutter_actor_queue_redraw (actor); } } /*< private > * _clutter_content_attached: * @content: a #ClutterContent * @actor: a #ClutterActor * * Attaches @actor to the @content. * * This function should be used internally every time a #ClutterActor * is associated to a #ClutterContent, to set up a backpointer from * the @content to the @actor. * * This function will invoke the #ClutterContentIface.attached() virtual * function. */ void _clutter_content_attached (ClutterContent *content, ClutterActor *actor) { GObject *obj = G_OBJECT (content); GHashTable *actors; actors = g_object_get_qdata (obj, quark_content_actors); if (actors == NULL) { actors = g_hash_table_new (NULL, NULL); g_object_set_qdata_full (obj, quark_content_actors, actors, (GDestroyNotify) g_hash_table_unref); } g_hash_table_insert (actors, actor, actor); g_signal_emit (content, content_signals[ATTACHED], 0, actor); } /*< private > * _clutter_content_detached: * @content: a #ClutterContent * @actor: a #ClutterActor * * Detaches @actor from @content. * * This function should be used internally every time a #ClutterActor * removes the association with a #ClutterContent. * * This function will invoke the #ClutterContentIface.detached() virtual * function. */ void _clutter_content_detached (ClutterContent *content, ClutterActor *actor) { GObject *obj = G_OBJECT (content); GHashTable *actors; actors = g_object_get_qdata (obj, quark_content_actors); g_assert (actors != NULL); g_hash_table_remove (actors, actor); if (g_hash_table_size (actors) == 0) g_object_set_qdata (obj, quark_content_actors, NULL); g_signal_emit (content, content_signals[DETACHED], 0, actor); } /*< private > * _clutter_content_paint_content: * @content: a #ClutterContent * @actor: a #ClutterActor * @context: a #ClutterPaintNode * * Creates the render tree for the @content and @actor. * * This function will invoke the #ClutterContentIface.paint_content() * virtual function. */ void _clutter_content_paint_content (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *node) { CLUTTER_CONTENT_GET_IFACE (content)->paint_content (content, actor, node); } /** * clutter_content_get_preferred_size: * @content: a #ClutterContent * @width: (out): return location for the natural width of the content * @height: (out): return location for the natural height of the content * * Retrieves the natural size of the @content, if any. * * The natural size of a #ClutterContent is defined as the size the content * would have regardless of the allocation of the actor that is painting it, * for instance the size of an image data. * * Return value: %TRUE if the content has a preferred size, and %FALSE * otherwise * * Since: 1.10 */ gboolean clutter_content_get_preferred_size (ClutterContent *content, gfloat *width, gfloat *height) { g_return_val_if_fail (CLUTTER_IS_CONTENT (content), FALSE); return CLUTTER_CONTENT_GET_IFACE (content)->get_preferred_size (content, width, height); } muffin-5.2.1/clutter/clutter/clutter-keysyms.h0000664000175000017500000026257614211404421021657 0ustar jpeisachjpeisach/* Clutter * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010 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, see . */ /* * File auto-generated from script at: * http://git.clutter-project.org/clutter/plain/clutter/clutter-keysyms-update.pl * * using the input files: * http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h * and * http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h */ #ifndef __CLUTTER_KEYSYMS_H__ #define __CLUTTER_KEYSYMS_H__ #define CLUTTER_KEY_VoidSymbol 0xffffff #define CLUTTER_KEY_BackSpace 0xff08 #define CLUTTER_KEY_Tab 0xff09 #define CLUTTER_KEY_Linefeed 0xff0a #define CLUTTER_KEY_Clear 0xff0b #define CLUTTER_KEY_Return 0xff0d #define CLUTTER_KEY_Pause 0xff13 #define CLUTTER_KEY_Scroll_Lock 0xff14 #define CLUTTER_KEY_Sys_Req 0xff15 #define CLUTTER_KEY_Escape 0xff1b #define CLUTTER_KEY_Delete 0xffff #define CLUTTER_KEY_Multi_key 0xff20 #define CLUTTER_KEY_Codeinput 0xff37 #define CLUTTER_KEY_SingleCandidate 0xff3c #define CLUTTER_KEY_MultipleCandidate 0xff3d #define CLUTTER_KEY_PreviousCandidate 0xff3e #define CLUTTER_KEY_Kanji 0xff21 #define CLUTTER_KEY_Muhenkan 0xff22 #define CLUTTER_KEY_Henkan_Mode 0xff23 #define CLUTTER_KEY_Henkan 0xff23 #define CLUTTER_KEY_Romaji 0xff24 #define CLUTTER_KEY_Hiragana 0xff25 #define CLUTTER_KEY_Katakana 0xff26 #define CLUTTER_KEY_Hiragana_Katakana 0xff27 #define CLUTTER_KEY_Zenkaku 0xff28 #define CLUTTER_KEY_Hankaku 0xff29 #define CLUTTER_KEY_Zenkaku_Hankaku 0xff2a #define CLUTTER_KEY_Touroku 0xff2b #define CLUTTER_KEY_Massyo 0xff2c #define CLUTTER_KEY_Kana_Lock 0xff2d #define CLUTTER_KEY_Kana_Shift 0xff2e #define CLUTTER_KEY_Eisu_Shift 0xff2f #define CLUTTER_KEY_Eisu_toggle 0xff30 #define CLUTTER_KEY_Kanji_Bangou 0xff37 #define CLUTTER_KEY_Zen_Koho 0xff3d #define CLUTTER_KEY_Mae_Koho 0xff3e #define CLUTTER_KEY_Home 0xff50 #define CLUTTER_KEY_Left 0xff51 #define CLUTTER_KEY_Up 0xff52 #define CLUTTER_KEY_Right 0xff53 #define CLUTTER_KEY_Down 0xff54 #define CLUTTER_KEY_Prior 0xff55 #define CLUTTER_KEY_Page_Up 0xff55 #define CLUTTER_KEY_Next 0xff56 #define CLUTTER_KEY_Page_Down 0xff56 #define CLUTTER_KEY_End 0xff57 #define CLUTTER_KEY_Begin 0xff58 #define CLUTTER_KEY_Select 0xff60 #define CLUTTER_KEY_Print 0xff61 #define CLUTTER_KEY_Execute 0xff62 #define CLUTTER_KEY_Insert 0xff63 #define CLUTTER_KEY_Undo 0xff65 #define CLUTTER_KEY_Redo 0xff66 #define CLUTTER_KEY_Menu 0xff67 #define CLUTTER_KEY_Find 0xff68 #define CLUTTER_KEY_Cancel 0xff69 #define CLUTTER_KEY_Help 0xff6a #define CLUTTER_KEY_Break 0xff6b #define CLUTTER_KEY_Mode_switch 0xff7e #define CLUTTER_KEY_script_switch 0xff7e #define CLUTTER_KEY_Num_Lock 0xff7f #define CLUTTER_KEY_KP_Space 0xff80 #define CLUTTER_KEY_KP_Tab 0xff89 #define CLUTTER_KEY_KP_Enter 0xff8d #define CLUTTER_KEY_KP_F1 0xff91 #define CLUTTER_KEY_KP_F2 0xff92 #define CLUTTER_KEY_KP_F3 0xff93 #define CLUTTER_KEY_KP_F4 0xff94 #define CLUTTER_KEY_KP_Home 0xff95 #define CLUTTER_KEY_KP_Left 0xff96 #define CLUTTER_KEY_KP_Up 0xff97 #define CLUTTER_KEY_KP_Right 0xff98 #define CLUTTER_KEY_KP_Down 0xff99 #define CLUTTER_KEY_KP_Prior 0xff9a #define CLUTTER_KEY_KP_Page_Up 0xff9a #define CLUTTER_KEY_KP_Next 0xff9b #define CLUTTER_KEY_KP_Page_Down 0xff9b #define CLUTTER_KEY_KP_End 0xff9c #define CLUTTER_KEY_KP_Begin 0xff9d #define CLUTTER_KEY_KP_Insert 0xff9e #define CLUTTER_KEY_KP_Delete 0xff9f #define CLUTTER_KEY_KP_Equal 0xffbd #define CLUTTER_KEY_KP_Multiply 0xffaa #define CLUTTER_KEY_KP_Add 0xffab #define CLUTTER_KEY_KP_Separator 0xffac #define CLUTTER_KEY_KP_Subtract 0xffad #define CLUTTER_KEY_KP_Decimal 0xffae #define CLUTTER_KEY_KP_Divide 0xffaf #define CLUTTER_KEY_KP_0 0xffb0 #define CLUTTER_KEY_KP_1 0xffb1 #define CLUTTER_KEY_KP_2 0xffb2 #define CLUTTER_KEY_KP_3 0xffb3 #define CLUTTER_KEY_KP_4 0xffb4 #define CLUTTER_KEY_KP_5 0xffb5 #define CLUTTER_KEY_KP_6 0xffb6 #define CLUTTER_KEY_KP_7 0xffb7 #define CLUTTER_KEY_KP_8 0xffb8 #define CLUTTER_KEY_KP_9 0xffb9 #define CLUTTER_KEY_F1 0xffbe #define CLUTTER_KEY_F2 0xffbf #define CLUTTER_KEY_F3 0xffc0 #define CLUTTER_KEY_F4 0xffc1 #define CLUTTER_KEY_F5 0xffc2 #define CLUTTER_KEY_F6 0xffc3 #define CLUTTER_KEY_F7 0xffc4 #define CLUTTER_KEY_F8 0xffc5 #define CLUTTER_KEY_F9 0xffc6 #define CLUTTER_KEY_F10 0xffc7 #define CLUTTER_KEY_F11 0xffc8 #define CLUTTER_KEY_L1 0xffc8 #define CLUTTER_KEY_F12 0xffc9 #define CLUTTER_KEY_L2 0xffc9 #define CLUTTER_KEY_F13 0xffca #define CLUTTER_KEY_L3 0xffca #define CLUTTER_KEY_F14 0xffcb #define CLUTTER_KEY_L4 0xffcb #define CLUTTER_KEY_F15 0xffcc #define CLUTTER_KEY_L5 0xffcc #define CLUTTER_KEY_F16 0xffcd #define CLUTTER_KEY_L6 0xffcd #define CLUTTER_KEY_F17 0xffce #define CLUTTER_KEY_L7 0xffce #define CLUTTER_KEY_F18 0xffcf #define CLUTTER_KEY_L8 0xffcf #define CLUTTER_KEY_F19 0xffd0 #define CLUTTER_KEY_L9 0xffd0 #define CLUTTER_KEY_F20 0xffd1 #define CLUTTER_KEY_L10 0xffd1 #define CLUTTER_KEY_F21 0xffd2 #define CLUTTER_KEY_R1 0xffd2 #define CLUTTER_KEY_F22 0xffd3 #define CLUTTER_KEY_R2 0xffd3 #define CLUTTER_KEY_F23 0xffd4 #define CLUTTER_KEY_R3 0xffd4 #define CLUTTER_KEY_F24 0xffd5 #define CLUTTER_KEY_R4 0xffd5 #define CLUTTER_KEY_F25 0xffd6 #define CLUTTER_KEY_R5 0xffd6 #define CLUTTER_KEY_F26 0xffd7 #define CLUTTER_KEY_R6 0xffd7 #define CLUTTER_KEY_F27 0xffd8 #define CLUTTER_KEY_R7 0xffd8 #define CLUTTER_KEY_F28 0xffd9 #define CLUTTER_KEY_R8 0xffd9 #define CLUTTER_KEY_F29 0xffda #define CLUTTER_KEY_R9 0xffda #define CLUTTER_KEY_F30 0xffdb #define CLUTTER_KEY_R10 0xffdb #define CLUTTER_KEY_F31 0xffdc #define CLUTTER_KEY_R11 0xffdc #define CLUTTER_KEY_F32 0xffdd #define CLUTTER_KEY_R12 0xffdd #define CLUTTER_KEY_F33 0xffde #define CLUTTER_KEY_R13 0xffde #define CLUTTER_KEY_F34 0xffdf #define CLUTTER_KEY_R14 0xffdf #define CLUTTER_KEY_F35 0xffe0 #define CLUTTER_KEY_R15 0xffe0 #define CLUTTER_KEY_Shift_L 0xffe1 #define CLUTTER_KEY_Shift_R 0xffe2 #define CLUTTER_KEY_Control_L 0xffe3 #define CLUTTER_KEY_Control_R 0xffe4 #define CLUTTER_KEY_Caps_Lock 0xffe5 #define CLUTTER_KEY_Shift_Lock 0xffe6 #define CLUTTER_KEY_Meta_L 0xffe7 #define CLUTTER_KEY_Meta_R 0xffe8 #define CLUTTER_KEY_Alt_L 0xffe9 #define CLUTTER_KEY_Alt_R 0xffea #define CLUTTER_KEY_Super_L 0xffeb #define CLUTTER_KEY_Super_R 0xffec #define CLUTTER_KEY_Hyper_L 0xffed #define CLUTTER_KEY_Hyper_R 0xffee #define CLUTTER_KEY_ISO_Lock 0xfe01 #define CLUTTER_KEY_ISO_Level2_Latch 0xfe02 #define CLUTTER_KEY_ISO_Level3_Shift 0xfe03 #define CLUTTER_KEY_ISO_Level3_Latch 0xfe04 #define CLUTTER_KEY_ISO_Level3_Lock 0xfe05 #define CLUTTER_KEY_ISO_Level5_Shift 0xfe11 #define CLUTTER_KEY_ISO_Level5_Latch 0xfe12 #define CLUTTER_KEY_ISO_Level5_Lock 0xfe13 #define CLUTTER_KEY_ISO_Group_Shift 0xff7e #define CLUTTER_KEY_ISO_Group_Latch 0xfe06 #define CLUTTER_KEY_ISO_Group_Lock 0xfe07 #define CLUTTER_KEY_ISO_Next_Group 0xfe08 #define CLUTTER_KEY_ISO_Next_Group_Lock 0xfe09 #define CLUTTER_KEY_ISO_Prev_Group 0xfe0a #define CLUTTER_KEY_ISO_Prev_Group_Lock 0xfe0b #define CLUTTER_KEY_ISO_First_Group 0xfe0c #define CLUTTER_KEY_ISO_First_Group_Lock 0xfe0d #define CLUTTER_KEY_ISO_Last_Group 0xfe0e #define CLUTTER_KEY_ISO_Last_Group_Lock 0xfe0f #define CLUTTER_KEY_ISO_Left_Tab 0xfe20 #define CLUTTER_KEY_ISO_Move_Line_Up 0xfe21 #define CLUTTER_KEY_ISO_Move_Line_Down 0xfe22 #define CLUTTER_KEY_ISO_Partial_Line_Up 0xfe23 #define CLUTTER_KEY_ISO_Partial_Line_Down 0xfe24 #define CLUTTER_KEY_ISO_Partial_Space_Left 0xfe25 #define CLUTTER_KEY_ISO_Partial_Space_Right 0xfe26 #define CLUTTER_KEY_ISO_Set_Margin_Left 0xfe27 #define CLUTTER_KEY_ISO_Set_Margin_Right 0xfe28 #define CLUTTER_KEY_ISO_Release_Margin_Left 0xfe29 #define CLUTTER_KEY_ISO_Release_Margin_Right 0xfe2a #define CLUTTER_KEY_ISO_Release_Both_Margins 0xfe2b #define CLUTTER_KEY_ISO_Fast_Cursor_Left 0xfe2c #define CLUTTER_KEY_ISO_Fast_Cursor_Right 0xfe2d #define CLUTTER_KEY_ISO_Fast_Cursor_Up 0xfe2e #define CLUTTER_KEY_ISO_Fast_Cursor_Down 0xfe2f #define CLUTTER_KEY_ISO_Continuous_Underline 0xfe30 #define CLUTTER_KEY_ISO_Discontinuous_Underline 0xfe31 #define CLUTTER_KEY_ISO_Emphasize 0xfe32 #define CLUTTER_KEY_ISO_Center_Object 0xfe33 #define CLUTTER_KEY_ISO_Enter 0xfe34 #define CLUTTER_KEY_dead_grave 0xfe50 #define CLUTTER_KEY_dead_acute 0xfe51 #define CLUTTER_KEY_dead_circumflex 0xfe52 #define CLUTTER_KEY_dead_tilde 0xfe53 #define CLUTTER_KEY_dead_perispomeni 0xfe53 #define CLUTTER_KEY_dead_macron 0xfe54 #define CLUTTER_KEY_dead_breve 0xfe55 #define CLUTTER_KEY_dead_abovedot 0xfe56 #define CLUTTER_KEY_dead_diaeresis 0xfe57 #define CLUTTER_KEY_dead_abovering 0xfe58 #define CLUTTER_KEY_dead_doubleacute 0xfe59 #define CLUTTER_KEY_dead_caron 0xfe5a #define CLUTTER_KEY_dead_cedilla 0xfe5b #define CLUTTER_KEY_dead_ogonek 0xfe5c #define CLUTTER_KEY_dead_iota 0xfe5d #define CLUTTER_KEY_dead_voiced_sound 0xfe5e #define CLUTTER_KEY_dead_semivoiced_sound 0xfe5f #define CLUTTER_KEY_dead_belowdot 0xfe60 #define CLUTTER_KEY_dead_hook 0xfe61 #define CLUTTER_KEY_dead_horn 0xfe62 #define CLUTTER_KEY_dead_stroke 0xfe63 #define CLUTTER_KEY_dead_abovecomma 0xfe64 #define CLUTTER_KEY_dead_psili 0xfe64 #define CLUTTER_KEY_dead_abovereversedcomma 0xfe65 #define CLUTTER_KEY_dead_dasia 0xfe65 #define CLUTTER_KEY_dead_doublegrave 0xfe66 #define CLUTTER_KEY_dead_belowring 0xfe67 #define CLUTTER_KEY_dead_belowmacron 0xfe68 #define CLUTTER_KEY_dead_belowcircumflex 0xfe69 #define CLUTTER_KEY_dead_belowtilde 0xfe6a #define CLUTTER_KEY_dead_belowbreve 0xfe6b #define CLUTTER_KEY_dead_belowdiaeresis 0xfe6c #define CLUTTER_KEY_dead_invertedbreve 0xfe6d #define CLUTTER_KEY_dead_belowcomma 0xfe6e #define CLUTTER_KEY_dead_currency 0xfe6f #define CLUTTER_KEY_dead_lowline 0xfe90 #define CLUTTER_KEY_dead_aboveverticalline 0xfe91 #define CLUTTER_KEY_dead_belowverticalline 0xfe92 #define CLUTTER_KEY_dead_longsolidusoverlay 0xfe93 #define CLUTTER_KEY_dead_a 0xfe80 #define CLUTTER_KEY_dead_A 0xfe81 #define CLUTTER_KEY_dead_e 0xfe82 #define CLUTTER_KEY_dead_E 0xfe83 #define CLUTTER_KEY_dead_i 0xfe84 #define CLUTTER_KEY_dead_I 0xfe85 #define CLUTTER_KEY_dead_o 0xfe86 #define CLUTTER_KEY_dead_O 0xfe87 #define CLUTTER_KEY_dead_u 0xfe88 #define CLUTTER_KEY_dead_U 0xfe89 #define CLUTTER_KEY_dead_small_schwa 0xfe8a #define CLUTTER_KEY_dead_capital_schwa 0xfe8b #define CLUTTER_KEY_dead_greek 0xfe8c #define CLUTTER_KEY_First_Virtual_Screen 0xfed0 #define CLUTTER_KEY_Prev_Virtual_Screen 0xfed1 #define CLUTTER_KEY_Next_Virtual_Screen 0xfed2 #define CLUTTER_KEY_Last_Virtual_Screen 0xfed4 #define CLUTTER_KEY_Terminate_Server 0xfed5 #define CLUTTER_KEY_AccessX_Enable 0xfe70 #define CLUTTER_KEY_AccessX_Feedback_Enable 0xfe71 #define CLUTTER_KEY_RepeatKeys_Enable 0xfe72 #define CLUTTER_KEY_SlowKeys_Enable 0xfe73 #define CLUTTER_KEY_BounceKeys_Enable 0xfe74 #define CLUTTER_KEY_StickyKeys_Enable 0xfe75 #define CLUTTER_KEY_MouseKeys_Enable 0xfe76 #define CLUTTER_KEY_MouseKeys_Accel_Enable 0xfe77 #define CLUTTER_KEY_Overlay1_Enable 0xfe78 #define CLUTTER_KEY_Overlay2_Enable 0xfe79 #define CLUTTER_KEY_AudibleBell_Enable 0xfe7a #define CLUTTER_KEY_Pointer_Left 0xfee0 #define CLUTTER_KEY_Pointer_Right 0xfee1 #define CLUTTER_KEY_Pointer_Up 0xfee2 #define CLUTTER_KEY_Pointer_Down 0xfee3 #define CLUTTER_KEY_Pointer_UpLeft 0xfee4 #define CLUTTER_KEY_Pointer_UpRight 0xfee5 #define CLUTTER_KEY_Pointer_DownLeft 0xfee6 #define CLUTTER_KEY_Pointer_DownRight 0xfee7 #define CLUTTER_KEY_Pointer_Button_Dflt 0xfee8 #define CLUTTER_KEY_Pointer_Button1 0xfee9 #define CLUTTER_KEY_Pointer_Button2 0xfeea #define CLUTTER_KEY_Pointer_Button3 0xfeeb #define CLUTTER_KEY_Pointer_Button4 0xfeec #define CLUTTER_KEY_Pointer_Button5 0xfeed #define CLUTTER_KEY_Pointer_DblClick_Dflt 0xfeee #define CLUTTER_KEY_Pointer_DblClick1 0xfeef #define CLUTTER_KEY_Pointer_DblClick2 0xfef0 #define CLUTTER_KEY_Pointer_DblClick3 0xfef1 #define CLUTTER_KEY_Pointer_DblClick4 0xfef2 #define CLUTTER_KEY_Pointer_DblClick5 0xfef3 #define CLUTTER_KEY_Pointer_Drag_Dflt 0xfef4 #define CLUTTER_KEY_Pointer_Drag1 0xfef5 #define CLUTTER_KEY_Pointer_Drag2 0xfef6 #define CLUTTER_KEY_Pointer_Drag3 0xfef7 #define CLUTTER_KEY_Pointer_Drag4 0xfef8 #define CLUTTER_KEY_Pointer_Drag5 0xfefd #define CLUTTER_KEY_Pointer_EnableKeys 0xfef9 #define CLUTTER_KEY_Pointer_Accelerate 0xfefa #define CLUTTER_KEY_Pointer_DfltBtnNext 0xfefb #define CLUTTER_KEY_Pointer_DfltBtnPrev 0xfefc #define CLUTTER_KEY_ch 0xfea0 #define CLUTTER_KEY_Ch 0xfea1 #define CLUTTER_KEY_CH 0xfea2 #define CLUTTER_KEY_c_h 0xfea3 #define CLUTTER_KEY_C_h 0xfea4 #define CLUTTER_KEY_C_H 0xfea5 #define CLUTTER_KEY_3270_Duplicate 0xfd01 #define CLUTTER_KEY_3270_FieldMark 0xfd02 #define CLUTTER_KEY_3270_Right2 0xfd03 #define CLUTTER_KEY_3270_Left2 0xfd04 #define CLUTTER_KEY_3270_BackTab 0xfd05 #define CLUTTER_KEY_3270_EraseEOF 0xfd06 #define CLUTTER_KEY_3270_EraseInput 0xfd07 #define CLUTTER_KEY_3270_Reset 0xfd08 #define CLUTTER_KEY_3270_Quit 0xfd09 #define CLUTTER_KEY_3270_PA1 0xfd0a #define CLUTTER_KEY_3270_PA2 0xfd0b #define CLUTTER_KEY_3270_PA3 0xfd0c #define CLUTTER_KEY_3270_Test 0xfd0d #define CLUTTER_KEY_3270_Attn 0xfd0e #define CLUTTER_KEY_3270_CursorBlink 0xfd0f #define CLUTTER_KEY_3270_AltCursor 0xfd10 #define CLUTTER_KEY_3270_KeyClick 0xfd11 #define CLUTTER_KEY_3270_Jump 0xfd12 #define CLUTTER_KEY_3270_Ident 0xfd13 #define CLUTTER_KEY_3270_Rule 0xfd14 #define CLUTTER_KEY_3270_Copy 0xfd15 #define CLUTTER_KEY_3270_Play 0xfd16 #define CLUTTER_KEY_3270_Setup 0xfd17 #define CLUTTER_KEY_3270_Record 0xfd18 #define CLUTTER_KEY_3270_ChangeScreen 0xfd19 #define CLUTTER_KEY_3270_DeleteWord 0xfd1a #define CLUTTER_KEY_3270_ExSelect 0xfd1b #define CLUTTER_KEY_3270_CursorSelect 0xfd1c #define CLUTTER_KEY_3270_PrintScreen 0xfd1d #define CLUTTER_KEY_3270_Enter 0xfd1e #define CLUTTER_KEY_space 0x020 #define CLUTTER_KEY_exclam 0x021 #define CLUTTER_KEY_quotedbl 0x022 #define CLUTTER_KEY_numbersign 0x023 #define CLUTTER_KEY_dollar 0x024 #define CLUTTER_KEY_percent 0x025 #define CLUTTER_KEY_ampersand 0x026 #define CLUTTER_KEY_apostrophe 0x027 #define CLUTTER_KEY_quoteright 0x027 #define CLUTTER_KEY_parenleft 0x028 #define CLUTTER_KEY_parenright 0x029 #define CLUTTER_KEY_asterisk 0x02a #define CLUTTER_KEY_plus 0x02b #define CLUTTER_KEY_comma 0x02c #define CLUTTER_KEY_minus 0x02d #define CLUTTER_KEY_period 0x02e #define CLUTTER_KEY_slash 0x02f #define CLUTTER_KEY_0 0x030 #define CLUTTER_KEY_1 0x031 #define CLUTTER_KEY_2 0x032 #define CLUTTER_KEY_3 0x033 #define CLUTTER_KEY_4 0x034 #define CLUTTER_KEY_5 0x035 #define CLUTTER_KEY_6 0x036 #define CLUTTER_KEY_7 0x037 #define CLUTTER_KEY_8 0x038 #define CLUTTER_KEY_9 0x039 #define CLUTTER_KEY_colon 0x03a #define CLUTTER_KEY_semicolon 0x03b #define CLUTTER_KEY_less 0x03c #define CLUTTER_KEY_equal 0x03d #define CLUTTER_KEY_greater 0x03e #define CLUTTER_KEY_question 0x03f #define CLUTTER_KEY_at 0x040 #define CLUTTER_KEY_A 0x041 #define CLUTTER_KEY_B 0x042 #define CLUTTER_KEY_C 0x043 #define CLUTTER_KEY_D 0x044 #define CLUTTER_KEY_E 0x045 #define CLUTTER_KEY_F 0x046 #define CLUTTER_KEY_G 0x047 #define CLUTTER_KEY_H 0x048 #define CLUTTER_KEY_I 0x049 #define CLUTTER_KEY_J 0x04a #define CLUTTER_KEY_K 0x04b #define CLUTTER_KEY_L 0x04c #define CLUTTER_KEY_M 0x04d #define CLUTTER_KEY_N 0x04e #define CLUTTER_KEY_O 0x04f #define CLUTTER_KEY_P 0x050 #define CLUTTER_KEY_Q 0x051 #define CLUTTER_KEY_R 0x052 #define CLUTTER_KEY_S 0x053 #define CLUTTER_KEY_T 0x054 #define CLUTTER_KEY_U 0x055 #define CLUTTER_KEY_V 0x056 #define CLUTTER_KEY_W 0x057 #define CLUTTER_KEY_X 0x058 #define CLUTTER_KEY_Y 0x059 #define CLUTTER_KEY_Z 0x05a #define CLUTTER_KEY_bracketleft 0x05b #define CLUTTER_KEY_backslash 0x05c #define CLUTTER_KEY_bracketright 0x05d #define CLUTTER_KEY_asciicircum 0x05e #define CLUTTER_KEY_underscore 0x05f #define CLUTTER_KEY_grave 0x060 #define CLUTTER_KEY_quoteleft 0x060 #define CLUTTER_KEY_a 0x061 #define CLUTTER_KEY_b 0x062 #define CLUTTER_KEY_c 0x063 #define CLUTTER_KEY_d 0x064 #define CLUTTER_KEY_e 0x065 #define CLUTTER_KEY_f 0x066 #define CLUTTER_KEY_g 0x067 #define CLUTTER_KEY_h 0x068 #define CLUTTER_KEY_i 0x069 #define CLUTTER_KEY_j 0x06a #define CLUTTER_KEY_k 0x06b #define CLUTTER_KEY_l 0x06c #define CLUTTER_KEY_m 0x06d #define CLUTTER_KEY_n 0x06e #define CLUTTER_KEY_o 0x06f #define CLUTTER_KEY_p 0x070 #define CLUTTER_KEY_q 0x071 #define CLUTTER_KEY_r 0x072 #define CLUTTER_KEY_s 0x073 #define CLUTTER_KEY_t 0x074 #define CLUTTER_KEY_u 0x075 #define CLUTTER_KEY_v 0x076 #define CLUTTER_KEY_w 0x077 #define CLUTTER_KEY_x 0x078 #define CLUTTER_KEY_y 0x079 #define CLUTTER_KEY_z 0x07a #define CLUTTER_KEY_braceleft 0x07b #define CLUTTER_KEY_bar 0x07c #define CLUTTER_KEY_braceright 0x07d #define CLUTTER_KEY_asciitilde 0x07e #define CLUTTER_KEY_nobreakspace 0x0a0 #define CLUTTER_KEY_exclamdown 0x0a1 #define CLUTTER_KEY_cent 0x0a2 #define CLUTTER_KEY_sterling 0x0a3 #define CLUTTER_KEY_currency 0x0a4 #define CLUTTER_KEY_yen 0x0a5 #define CLUTTER_KEY_brokenbar 0x0a6 #define CLUTTER_KEY_section 0x0a7 #define CLUTTER_KEY_diaeresis 0x0a8 #define CLUTTER_KEY_copyright 0x0a9 #define CLUTTER_KEY_ordfeminine 0x0aa #define CLUTTER_KEY_guillemotleft 0x0ab #define CLUTTER_KEY_notsign 0x0ac #define CLUTTER_KEY_hyphen 0x0ad #define CLUTTER_KEY_registered 0x0ae #define CLUTTER_KEY_macron 0x0af #define CLUTTER_KEY_degree 0x0b0 #define CLUTTER_KEY_plusminus 0x0b1 #define CLUTTER_KEY_twosuperior 0x0b2 #define CLUTTER_KEY_threesuperior 0x0b3 #define CLUTTER_KEY_acute 0x0b4 #define CLUTTER_KEY_mu 0x0b5 #define CLUTTER_KEY_paragraph 0x0b6 #define CLUTTER_KEY_periodcentered 0x0b7 #define CLUTTER_KEY_cedilla 0x0b8 #define CLUTTER_KEY_onesuperior 0x0b9 #define CLUTTER_KEY_masculine 0x0ba #define CLUTTER_KEY_guillemotright 0x0bb #define CLUTTER_KEY_onequarter 0x0bc #define CLUTTER_KEY_onehalf 0x0bd #define CLUTTER_KEY_threequarters 0x0be #define CLUTTER_KEY_questiondown 0x0bf #define CLUTTER_KEY_Agrave 0x0c0 #define CLUTTER_KEY_Aacute 0x0c1 #define CLUTTER_KEY_Acircumflex 0x0c2 #define CLUTTER_KEY_Atilde 0x0c3 #define CLUTTER_KEY_Adiaeresis 0x0c4 #define CLUTTER_KEY_Aring 0x0c5 #define CLUTTER_KEY_AE 0x0c6 #define CLUTTER_KEY_Ccedilla 0x0c7 #define CLUTTER_KEY_Egrave 0x0c8 #define CLUTTER_KEY_Eacute 0x0c9 #define CLUTTER_KEY_Ecircumflex 0x0ca #define CLUTTER_KEY_Ediaeresis 0x0cb #define CLUTTER_KEY_Igrave 0x0cc #define CLUTTER_KEY_Iacute 0x0cd #define CLUTTER_KEY_Icircumflex 0x0ce #define CLUTTER_KEY_Idiaeresis 0x0cf #define CLUTTER_KEY_ETH 0x0d0 #define CLUTTER_KEY_Eth 0x0d0 #define CLUTTER_KEY_Ntilde 0x0d1 #define CLUTTER_KEY_Ograve 0x0d2 #define CLUTTER_KEY_Oacute 0x0d3 #define CLUTTER_KEY_Ocircumflex 0x0d4 #define CLUTTER_KEY_Otilde 0x0d5 #define CLUTTER_KEY_Odiaeresis 0x0d6 #define CLUTTER_KEY_multiply 0x0d7 #define CLUTTER_KEY_Oslash 0x0d8 #define CLUTTER_KEY_Ooblique 0x0d8 #define CLUTTER_KEY_Ugrave 0x0d9 #define CLUTTER_KEY_Uacute 0x0da #define CLUTTER_KEY_Ucircumflex 0x0db #define CLUTTER_KEY_Udiaeresis 0x0dc #define CLUTTER_KEY_Yacute 0x0dd #define CLUTTER_KEY_THORN 0x0de #define CLUTTER_KEY_Thorn 0x0de #define CLUTTER_KEY_ssharp 0x0df #define CLUTTER_KEY_agrave 0x0e0 #define CLUTTER_KEY_aacute 0x0e1 #define CLUTTER_KEY_acircumflex 0x0e2 #define CLUTTER_KEY_atilde 0x0e3 #define CLUTTER_KEY_adiaeresis 0x0e4 #define CLUTTER_KEY_aring 0x0e5 #define CLUTTER_KEY_ae 0x0e6 #define CLUTTER_KEY_ccedilla 0x0e7 #define CLUTTER_KEY_egrave 0x0e8 #define CLUTTER_KEY_eacute 0x0e9 #define CLUTTER_KEY_ecircumflex 0x0ea #define CLUTTER_KEY_ediaeresis 0x0eb #define CLUTTER_KEY_igrave 0x0ec #define CLUTTER_KEY_iacute 0x0ed #define CLUTTER_KEY_icircumflex 0x0ee #define CLUTTER_KEY_idiaeresis 0x0ef #define CLUTTER_KEY_eth 0x0f0 #define CLUTTER_KEY_ntilde 0x0f1 #define CLUTTER_KEY_ograve 0x0f2 #define CLUTTER_KEY_oacute 0x0f3 #define CLUTTER_KEY_ocircumflex 0x0f4 #define CLUTTER_KEY_otilde 0x0f5 #define CLUTTER_KEY_odiaeresis 0x0f6 #define CLUTTER_KEY_division 0x0f7 #define CLUTTER_KEY_oslash 0x0f8 #define CLUTTER_KEY_ooblique 0x0f8 #define CLUTTER_KEY_ugrave 0x0f9 #define CLUTTER_KEY_uacute 0x0fa #define CLUTTER_KEY_ucircumflex 0x0fb #define CLUTTER_KEY_udiaeresis 0x0fc #define CLUTTER_KEY_yacute 0x0fd #define CLUTTER_KEY_thorn 0x0fe #define CLUTTER_KEY_ydiaeresis 0x0ff #define CLUTTER_KEY_Aogonek 0x1a1 #define CLUTTER_KEY_breve 0x1a2 #define CLUTTER_KEY_Lstroke 0x1a3 #define CLUTTER_KEY_Lcaron 0x1a5 #define CLUTTER_KEY_Sacute 0x1a6 #define CLUTTER_KEY_Scaron 0x1a9 #define CLUTTER_KEY_Scedilla 0x1aa #define CLUTTER_KEY_Tcaron 0x1ab #define CLUTTER_KEY_Zacute 0x1ac #define CLUTTER_KEY_Zcaron 0x1ae #define CLUTTER_KEY_Zabovedot 0x1af #define CLUTTER_KEY_aogonek 0x1b1 #define CLUTTER_KEY_ogonek 0x1b2 #define CLUTTER_KEY_lstroke 0x1b3 #define CLUTTER_KEY_lcaron 0x1b5 #define CLUTTER_KEY_sacute 0x1b6 #define CLUTTER_KEY_caron 0x1b7 #define CLUTTER_KEY_scaron 0x1b9 #define CLUTTER_KEY_scedilla 0x1ba #define CLUTTER_KEY_tcaron 0x1bb #define CLUTTER_KEY_zacute 0x1bc #define CLUTTER_KEY_doubleacute 0x1bd #define CLUTTER_KEY_zcaron 0x1be #define CLUTTER_KEY_zabovedot 0x1bf #define CLUTTER_KEY_Racute 0x1c0 #define CLUTTER_KEY_Abreve 0x1c3 #define CLUTTER_KEY_Lacute 0x1c5 #define CLUTTER_KEY_Cacute 0x1c6 #define CLUTTER_KEY_Ccaron 0x1c8 #define CLUTTER_KEY_Eogonek 0x1ca #define CLUTTER_KEY_Ecaron 0x1cc #define CLUTTER_KEY_Dcaron 0x1cf #define CLUTTER_KEY_Dstroke 0x1d0 #define CLUTTER_KEY_Nacute 0x1d1 #define CLUTTER_KEY_Ncaron 0x1d2 #define CLUTTER_KEY_Odoubleacute 0x1d5 #define CLUTTER_KEY_Rcaron 0x1d8 #define CLUTTER_KEY_Uring 0x1d9 #define CLUTTER_KEY_Udoubleacute 0x1db #define CLUTTER_KEY_Tcedilla 0x1de #define CLUTTER_KEY_racute 0x1e0 #define CLUTTER_KEY_abreve 0x1e3 #define CLUTTER_KEY_lacute 0x1e5 #define CLUTTER_KEY_cacute 0x1e6 #define CLUTTER_KEY_ccaron 0x1e8 #define CLUTTER_KEY_eogonek 0x1ea #define CLUTTER_KEY_ecaron 0x1ec #define CLUTTER_KEY_dcaron 0x1ef #define CLUTTER_KEY_dstroke 0x1f0 #define CLUTTER_KEY_nacute 0x1f1 #define CLUTTER_KEY_ncaron 0x1f2 #define CLUTTER_KEY_odoubleacute 0x1f5 #define CLUTTER_KEY_rcaron 0x1f8 #define CLUTTER_KEY_uring 0x1f9 #define CLUTTER_KEY_udoubleacute 0x1fb #define CLUTTER_KEY_tcedilla 0x1fe #define CLUTTER_KEY_abovedot 0x1ff #define CLUTTER_KEY_Hstroke 0x2a1 #define CLUTTER_KEY_Hcircumflex 0x2a6 #define CLUTTER_KEY_Iabovedot 0x2a9 #define CLUTTER_KEY_Gbreve 0x2ab #define CLUTTER_KEY_Jcircumflex 0x2ac #define CLUTTER_KEY_hstroke 0x2b1 #define CLUTTER_KEY_hcircumflex 0x2b6 #define CLUTTER_KEY_idotless 0x2b9 #define CLUTTER_KEY_gbreve 0x2bb #define CLUTTER_KEY_jcircumflex 0x2bc #define CLUTTER_KEY_Cabovedot 0x2c5 #define CLUTTER_KEY_Ccircumflex 0x2c6 #define CLUTTER_KEY_Gabovedot 0x2d5 #define CLUTTER_KEY_Gcircumflex 0x2d8 #define CLUTTER_KEY_Ubreve 0x2dd #define CLUTTER_KEY_Scircumflex 0x2de #define CLUTTER_KEY_cabovedot 0x2e5 #define CLUTTER_KEY_ccircumflex 0x2e6 #define CLUTTER_KEY_gabovedot 0x2f5 #define CLUTTER_KEY_gcircumflex 0x2f8 #define CLUTTER_KEY_ubreve 0x2fd #define CLUTTER_KEY_scircumflex 0x2fe #define CLUTTER_KEY_kra 0x3a2 #define CLUTTER_KEY_kappa 0x3a2 #define CLUTTER_KEY_Rcedilla 0x3a3 #define CLUTTER_KEY_Itilde 0x3a5 #define CLUTTER_KEY_Lcedilla 0x3a6 #define CLUTTER_KEY_Emacron 0x3aa #define CLUTTER_KEY_Gcedilla 0x3ab #define CLUTTER_KEY_Tslash 0x3ac #define CLUTTER_KEY_rcedilla 0x3b3 #define CLUTTER_KEY_itilde 0x3b5 #define CLUTTER_KEY_lcedilla 0x3b6 #define CLUTTER_KEY_emacron 0x3ba #define CLUTTER_KEY_gcedilla 0x3bb #define CLUTTER_KEY_tslash 0x3bc #define CLUTTER_KEY_ENG 0x3bd #define CLUTTER_KEY_eng 0x3bf #define CLUTTER_KEY_Amacron 0x3c0 #define CLUTTER_KEY_Iogonek 0x3c7 #define CLUTTER_KEY_Eabovedot 0x3cc #define CLUTTER_KEY_Imacron 0x3cf #define CLUTTER_KEY_Ncedilla 0x3d1 #define CLUTTER_KEY_Omacron 0x3d2 #define CLUTTER_KEY_Kcedilla 0x3d3 #define CLUTTER_KEY_Uogonek 0x3d9 #define CLUTTER_KEY_Utilde 0x3dd #define CLUTTER_KEY_Umacron 0x3de #define CLUTTER_KEY_amacron 0x3e0 #define CLUTTER_KEY_iogonek 0x3e7 #define CLUTTER_KEY_eabovedot 0x3ec #define CLUTTER_KEY_imacron 0x3ef #define CLUTTER_KEY_ncedilla 0x3f1 #define CLUTTER_KEY_omacron 0x3f2 #define CLUTTER_KEY_kcedilla 0x3f3 #define CLUTTER_KEY_uogonek 0x3f9 #define CLUTTER_KEY_utilde 0x3fd #define CLUTTER_KEY_umacron 0x3fe #define CLUTTER_KEY_Wcircumflex 0x1000174 #define CLUTTER_KEY_wcircumflex 0x1000175 #define CLUTTER_KEY_Ycircumflex 0x1000176 #define CLUTTER_KEY_ycircumflex 0x1000177 #define CLUTTER_KEY_Babovedot 0x1001e02 #define CLUTTER_KEY_babovedot 0x1001e03 #define CLUTTER_KEY_Dabovedot 0x1001e0a #define CLUTTER_KEY_dabovedot 0x1001e0b #define CLUTTER_KEY_Fabovedot 0x1001e1e #define CLUTTER_KEY_fabovedot 0x1001e1f #define CLUTTER_KEY_Mabovedot 0x1001e40 #define CLUTTER_KEY_mabovedot 0x1001e41 #define CLUTTER_KEY_Pabovedot 0x1001e56 #define CLUTTER_KEY_pabovedot 0x1001e57 #define CLUTTER_KEY_Sabovedot 0x1001e60 #define CLUTTER_KEY_sabovedot 0x1001e61 #define CLUTTER_KEY_Tabovedot 0x1001e6a #define CLUTTER_KEY_tabovedot 0x1001e6b #define CLUTTER_KEY_Wgrave 0x1001e80 #define CLUTTER_KEY_wgrave 0x1001e81 #define CLUTTER_KEY_Wacute 0x1001e82 #define CLUTTER_KEY_wacute 0x1001e83 #define CLUTTER_KEY_Wdiaeresis 0x1001e84 #define CLUTTER_KEY_wdiaeresis 0x1001e85 #define CLUTTER_KEY_Ygrave 0x1001ef2 #define CLUTTER_KEY_ygrave 0x1001ef3 #define CLUTTER_KEY_OE 0x13bc #define CLUTTER_KEY_oe 0x13bd #define CLUTTER_KEY_Ydiaeresis 0x13be #define CLUTTER_KEY_overline 0x47e #define CLUTTER_KEY_kana_fullstop 0x4a1 #define CLUTTER_KEY_kana_openingbracket 0x4a2 #define CLUTTER_KEY_kana_closingbracket 0x4a3 #define CLUTTER_KEY_kana_comma 0x4a4 #define CLUTTER_KEY_kana_conjunctive 0x4a5 #define CLUTTER_KEY_kana_middledot 0x4a5 #define CLUTTER_KEY_kana_WO 0x4a6 #define CLUTTER_KEY_kana_a 0x4a7 #define CLUTTER_KEY_kana_i 0x4a8 #define CLUTTER_KEY_kana_u 0x4a9 #define CLUTTER_KEY_kana_e 0x4aa #define CLUTTER_KEY_kana_o 0x4ab #define CLUTTER_KEY_kana_ya 0x4ac #define CLUTTER_KEY_kana_yu 0x4ad #define CLUTTER_KEY_kana_yo 0x4ae #define CLUTTER_KEY_kana_tsu 0x4af #define CLUTTER_KEY_kana_tu 0x4af #define CLUTTER_KEY_prolongedsound 0x4b0 #define CLUTTER_KEY_kana_A 0x4b1 #define CLUTTER_KEY_kana_I 0x4b2 #define CLUTTER_KEY_kana_U 0x4b3 #define CLUTTER_KEY_kana_E 0x4b4 #define CLUTTER_KEY_kana_O 0x4b5 #define CLUTTER_KEY_kana_KA 0x4b6 #define CLUTTER_KEY_kana_KI 0x4b7 #define CLUTTER_KEY_kana_KU 0x4b8 #define CLUTTER_KEY_kana_KE 0x4b9 #define CLUTTER_KEY_kana_KO 0x4ba #define CLUTTER_KEY_kana_SA 0x4bb #define CLUTTER_KEY_kana_SHI 0x4bc #define CLUTTER_KEY_kana_SU 0x4bd #define CLUTTER_KEY_kana_SE 0x4be #define CLUTTER_KEY_kana_SO 0x4bf #define CLUTTER_KEY_kana_TA 0x4c0 #define CLUTTER_KEY_kana_CHI 0x4c1 #define CLUTTER_KEY_kana_TI 0x4c1 #define CLUTTER_KEY_kana_TSU 0x4c2 #define CLUTTER_KEY_kana_TU 0x4c2 #define CLUTTER_KEY_kana_TE 0x4c3 #define CLUTTER_KEY_kana_TO 0x4c4 #define CLUTTER_KEY_kana_NA 0x4c5 #define CLUTTER_KEY_kana_NI 0x4c6 #define CLUTTER_KEY_kana_NU 0x4c7 #define CLUTTER_KEY_kana_NE 0x4c8 #define CLUTTER_KEY_kana_NO 0x4c9 #define CLUTTER_KEY_kana_HA 0x4ca #define CLUTTER_KEY_kana_HI 0x4cb #define CLUTTER_KEY_kana_FU 0x4cc #define CLUTTER_KEY_kana_HU 0x4cc #define CLUTTER_KEY_kana_HE 0x4cd #define CLUTTER_KEY_kana_HO 0x4ce #define CLUTTER_KEY_kana_MA 0x4cf #define CLUTTER_KEY_kana_MI 0x4d0 #define CLUTTER_KEY_kana_MU 0x4d1 #define CLUTTER_KEY_kana_ME 0x4d2 #define CLUTTER_KEY_kana_MO 0x4d3 #define CLUTTER_KEY_kana_YA 0x4d4 #define CLUTTER_KEY_kana_YU 0x4d5 #define CLUTTER_KEY_kana_YO 0x4d6 #define CLUTTER_KEY_kana_RA 0x4d7 #define CLUTTER_KEY_kana_RI 0x4d8 #define CLUTTER_KEY_kana_RU 0x4d9 #define CLUTTER_KEY_kana_RE 0x4da #define CLUTTER_KEY_kana_RO 0x4db #define CLUTTER_KEY_kana_WA 0x4dc #define CLUTTER_KEY_kana_N 0x4dd #define CLUTTER_KEY_voicedsound 0x4de #define CLUTTER_KEY_semivoicedsound 0x4df #define CLUTTER_KEY_kana_switch 0xff7e #define CLUTTER_KEY_Farsi_0 0x10006f0 #define CLUTTER_KEY_Farsi_1 0x10006f1 #define CLUTTER_KEY_Farsi_2 0x10006f2 #define CLUTTER_KEY_Farsi_3 0x10006f3 #define CLUTTER_KEY_Farsi_4 0x10006f4 #define CLUTTER_KEY_Farsi_5 0x10006f5 #define CLUTTER_KEY_Farsi_6 0x10006f6 #define CLUTTER_KEY_Farsi_7 0x10006f7 #define CLUTTER_KEY_Farsi_8 0x10006f8 #define CLUTTER_KEY_Farsi_9 0x10006f9 #define CLUTTER_KEY_Arabic_percent 0x100066a #define CLUTTER_KEY_Arabic_superscript_alef 0x1000670 #define CLUTTER_KEY_Arabic_tteh 0x1000679 #define CLUTTER_KEY_Arabic_peh 0x100067e #define CLUTTER_KEY_Arabic_tcheh 0x1000686 #define CLUTTER_KEY_Arabic_ddal 0x1000688 #define CLUTTER_KEY_Arabic_rreh 0x1000691 #define CLUTTER_KEY_Arabic_comma 0x5ac #define CLUTTER_KEY_Arabic_fullstop 0x10006d4 #define CLUTTER_KEY_Arabic_0 0x1000660 #define CLUTTER_KEY_Arabic_1 0x1000661 #define CLUTTER_KEY_Arabic_2 0x1000662 #define CLUTTER_KEY_Arabic_3 0x1000663 #define CLUTTER_KEY_Arabic_4 0x1000664 #define CLUTTER_KEY_Arabic_5 0x1000665 #define CLUTTER_KEY_Arabic_6 0x1000666 #define CLUTTER_KEY_Arabic_7 0x1000667 #define CLUTTER_KEY_Arabic_8 0x1000668 #define CLUTTER_KEY_Arabic_9 0x1000669 #define CLUTTER_KEY_Arabic_semicolon 0x5bb #define CLUTTER_KEY_Arabic_question_mark 0x5bf #define CLUTTER_KEY_Arabic_hamza 0x5c1 #define CLUTTER_KEY_Arabic_maddaonalef 0x5c2 #define CLUTTER_KEY_Arabic_hamzaonalef 0x5c3 #define CLUTTER_KEY_Arabic_hamzaonwaw 0x5c4 #define CLUTTER_KEY_Arabic_hamzaunderalef 0x5c5 #define CLUTTER_KEY_Arabic_hamzaonyeh 0x5c6 #define CLUTTER_KEY_Arabic_alef 0x5c7 #define CLUTTER_KEY_Arabic_beh 0x5c8 #define CLUTTER_KEY_Arabic_tehmarbuta 0x5c9 #define CLUTTER_KEY_Arabic_teh 0x5ca #define CLUTTER_KEY_Arabic_theh 0x5cb #define CLUTTER_KEY_Arabic_jeem 0x5cc #define CLUTTER_KEY_Arabic_hah 0x5cd #define CLUTTER_KEY_Arabic_khah 0x5ce #define CLUTTER_KEY_Arabic_dal 0x5cf #define CLUTTER_KEY_Arabic_thal 0x5d0 #define CLUTTER_KEY_Arabic_ra 0x5d1 #define CLUTTER_KEY_Arabic_zain 0x5d2 #define CLUTTER_KEY_Arabic_seen 0x5d3 #define CLUTTER_KEY_Arabic_sheen 0x5d4 #define CLUTTER_KEY_Arabic_sad 0x5d5 #define CLUTTER_KEY_Arabic_dad 0x5d6 #define CLUTTER_KEY_Arabic_tah 0x5d7 #define CLUTTER_KEY_Arabic_zah 0x5d8 #define CLUTTER_KEY_Arabic_ain 0x5d9 #define CLUTTER_KEY_Arabic_ghain 0x5da #define CLUTTER_KEY_Arabic_tatweel 0x5e0 #define CLUTTER_KEY_Arabic_feh 0x5e1 #define CLUTTER_KEY_Arabic_qaf 0x5e2 #define CLUTTER_KEY_Arabic_kaf 0x5e3 #define CLUTTER_KEY_Arabic_lam 0x5e4 #define CLUTTER_KEY_Arabic_meem 0x5e5 #define CLUTTER_KEY_Arabic_noon 0x5e6 #define CLUTTER_KEY_Arabic_ha 0x5e7 #define CLUTTER_KEY_Arabic_heh 0x5e7 #define CLUTTER_KEY_Arabic_waw 0x5e8 #define CLUTTER_KEY_Arabic_alefmaksura 0x5e9 #define CLUTTER_KEY_Arabic_yeh 0x5ea #define CLUTTER_KEY_Arabic_fathatan 0x5eb #define CLUTTER_KEY_Arabic_dammatan 0x5ec #define CLUTTER_KEY_Arabic_kasratan 0x5ed #define CLUTTER_KEY_Arabic_fatha 0x5ee #define CLUTTER_KEY_Arabic_damma 0x5ef #define CLUTTER_KEY_Arabic_kasra 0x5f0 #define CLUTTER_KEY_Arabic_shadda 0x5f1 #define CLUTTER_KEY_Arabic_sukun 0x5f2 #define CLUTTER_KEY_Arabic_madda_above 0x1000653 #define CLUTTER_KEY_Arabic_hamza_above 0x1000654 #define CLUTTER_KEY_Arabic_hamza_below 0x1000655 #define CLUTTER_KEY_Arabic_jeh 0x1000698 #define CLUTTER_KEY_Arabic_veh 0x10006a4 #define CLUTTER_KEY_Arabic_keheh 0x10006a9 #define CLUTTER_KEY_Arabic_gaf 0x10006af #define CLUTTER_KEY_Arabic_noon_ghunna 0x10006ba #define CLUTTER_KEY_Arabic_heh_doachashmee 0x10006be #define CLUTTER_KEY_Farsi_yeh 0x10006cc #define CLUTTER_KEY_Arabic_farsi_yeh 0x10006cc #define CLUTTER_KEY_Arabic_yeh_baree 0x10006d2 #define CLUTTER_KEY_Arabic_heh_goal 0x10006c1 #define CLUTTER_KEY_Arabic_switch 0xff7e #define CLUTTER_KEY_Cyrillic_GHE_bar 0x1000492 #define CLUTTER_KEY_Cyrillic_ghe_bar 0x1000493 #define CLUTTER_KEY_Cyrillic_ZHE_descender 0x1000496 #define CLUTTER_KEY_Cyrillic_zhe_descender 0x1000497 #define CLUTTER_KEY_Cyrillic_KA_descender 0x100049a #define CLUTTER_KEY_Cyrillic_ka_descender 0x100049b #define CLUTTER_KEY_Cyrillic_KA_vertstroke 0x100049c #define CLUTTER_KEY_Cyrillic_ka_vertstroke 0x100049d #define CLUTTER_KEY_Cyrillic_EN_descender 0x10004a2 #define CLUTTER_KEY_Cyrillic_en_descender 0x10004a3 #define CLUTTER_KEY_Cyrillic_U_straight 0x10004ae #define CLUTTER_KEY_Cyrillic_u_straight 0x10004af #define CLUTTER_KEY_Cyrillic_U_straight_bar 0x10004b0 #define CLUTTER_KEY_Cyrillic_u_straight_bar 0x10004b1 #define CLUTTER_KEY_Cyrillic_HA_descender 0x10004b2 #define CLUTTER_KEY_Cyrillic_ha_descender 0x10004b3 #define CLUTTER_KEY_Cyrillic_CHE_descender 0x10004b6 #define CLUTTER_KEY_Cyrillic_che_descender 0x10004b7 #define CLUTTER_KEY_Cyrillic_CHE_vertstroke 0x10004b8 #define CLUTTER_KEY_Cyrillic_che_vertstroke 0x10004b9 #define CLUTTER_KEY_Cyrillic_SHHA 0x10004ba #define CLUTTER_KEY_Cyrillic_shha 0x10004bb #define CLUTTER_KEY_Cyrillic_SCHWA 0x10004d8 #define CLUTTER_KEY_Cyrillic_schwa 0x10004d9 #define CLUTTER_KEY_Cyrillic_I_macron 0x10004e2 #define CLUTTER_KEY_Cyrillic_i_macron 0x10004e3 #define CLUTTER_KEY_Cyrillic_O_bar 0x10004e8 #define CLUTTER_KEY_Cyrillic_o_bar 0x10004e9 #define CLUTTER_KEY_Cyrillic_U_macron 0x10004ee #define CLUTTER_KEY_Cyrillic_u_macron 0x10004ef #define CLUTTER_KEY_Serbian_dje 0x6a1 #define CLUTTER_KEY_Macedonia_gje 0x6a2 #define CLUTTER_KEY_Cyrillic_io 0x6a3 #define CLUTTER_KEY_Ukrainian_ie 0x6a4 #define CLUTTER_KEY_Ukranian_je 0x6a4 #define CLUTTER_KEY_Macedonia_dse 0x6a5 #define CLUTTER_KEY_Ukrainian_i 0x6a6 #define CLUTTER_KEY_Ukranian_i 0x6a6 #define CLUTTER_KEY_Ukrainian_yi 0x6a7 #define CLUTTER_KEY_Ukranian_yi 0x6a7 #define CLUTTER_KEY_Cyrillic_je 0x6a8 #define CLUTTER_KEY_Serbian_je 0x6a8 #define CLUTTER_KEY_Cyrillic_lje 0x6a9 #define CLUTTER_KEY_Serbian_lje 0x6a9 #define CLUTTER_KEY_Cyrillic_nje 0x6aa #define CLUTTER_KEY_Serbian_nje 0x6aa #define CLUTTER_KEY_Serbian_tshe 0x6ab #define CLUTTER_KEY_Macedonia_kje 0x6ac #define CLUTTER_KEY_Ukrainian_ghe_with_upturn 0x6ad #define CLUTTER_KEY_Byelorussian_shortu 0x6ae #define CLUTTER_KEY_Cyrillic_dzhe 0x6af #define CLUTTER_KEY_Serbian_dze 0x6af #define CLUTTER_KEY_numerosign 0x6b0 #define CLUTTER_KEY_Serbian_DJE 0x6b1 #define CLUTTER_KEY_Macedonia_GJE 0x6b2 #define CLUTTER_KEY_Cyrillic_IO 0x6b3 #define CLUTTER_KEY_Ukrainian_IE 0x6b4 #define CLUTTER_KEY_Ukranian_JE 0x6b4 #define CLUTTER_KEY_Macedonia_DSE 0x6b5 #define CLUTTER_KEY_Ukrainian_I 0x6b6 #define CLUTTER_KEY_Ukranian_I 0x6b6 #define CLUTTER_KEY_Ukrainian_YI 0x6b7 #define CLUTTER_KEY_Ukranian_YI 0x6b7 #define CLUTTER_KEY_Cyrillic_JE 0x6b8 #define CLUTTER_KEY_Serbian_JE 0x6b8 #define CLUTTER_KEY_Cyrillic_LJE 0x6b9 #define CLUTTER_KEY_Serbian_LJE 0x6b9 #define CLUTTER_KEY_Cyrillic_NJE 0x6ba #define CLUTTER_KEY_Serbian_NJE 0x6ba #define CLUTTER_KEY_Serbian_TSHE 0x6bb #define CLUTTER_KEY_Macedonia_KJE 0x6bc #define CLUTTER_KEY_Ukrainian_GHE_WITH_UPTURN 0x6bd #define CLUTTER_KEY_Byelorussian_SHORTU 0x6be #define CLUTTER_KEY_Cyrillic_DZHE 0x6bf #define CLUTTER_KEY_Serbian_DZE 0x6bf #define CLUTTER_KEY_Cyrillic_yu 0x6c0 #define CLUTTER_KEY_Cyrillic_a 0x6c1 #define CLUTTER_KEY_Cyrillic_be 0x6c2 #define CLUTTER_KEY_Cyrillic_tse 0x6c3 #define CLUTTER_KEY_Cyrillic_de 0x6c4 #define CLUTTER_KEY_Cyrillic_ie 0x6c5 #define CLUTTER_KEY_Cyrillic_ef 0x6c6 #define CLUTTER_KEY_Cyrillic_ghe 0x6c7 #define CLUTTER_KEY_Cyrillic_ha 0x6c8 #define CLUTTER_KEY_Cyrillic_i 0x6c9 #define CLUTTER_KEY_Cyrillic_shorti 0x6ca #define CLUTTER_KEY_Cyrillic_ka 0x6cb #define CLUTTER_KEY_Cyrillic_el 0x6cc #define CLUTTER_KEY_Cyrillic_em 0x6cd #define CLUTTER_KEY_Cyrillic_en 0x6ce #define CLUTTER_KEY_Cyrillic_o 0x6cf #define CLUTTER_KEY_Cyrillic_pe 0x6d0 #define CLUTTER_KEY_Cyrillic_ya 0x6d1 #define CLUTTER_KEY_Cyrillic_er 0x6d2 #define CLUTTER_KEY_Cyrillic_es 0x6d3 #define CLUTTER_KEY_Cyrillic_te 0x6d4 #define CLUTTER_KEY_Cyrillic_u 0x6d5 #define CLUTTER_KEY_Cyrillic_zhe 0x6d6 #define CLUTTER_KEY_Cyrillic_ve 0x6d7 #define CLUTTER_KEY_Cyrillic_softsign 0x6d8 #define CLUTTER_KEY_Cyrillic_yeru 0x6d9 #define CLUTTER_KEY_Cyrillic_ze 0x6da #define CLUTTER_KEY_Cyrillic_sha 0x6db #define CLUTTER_KEY_Cyrillic_e 0x6dc #define CLUTTER_KEY_Cyrillic_shcha 0x6dd #define CLUTTER_KEY_Cyrillic_che 0x6de #define CLUTTER_KEY_Cyrillic_hardsign 0x6df #define CLUTTER_KEY_Cyrillic_YU 0x6e0 #define CLUTTER_KEY_Cyrillic_A 0x6e1 #define CLUTTER_KEY_Cyrillic_BE 0x6e2 #define CLUTTER_KEY_Cyrillic_TSE 0x6e3 #define CLUTTER_KEY_Cyrillic_DE 0x6e4 #define CLUTTER_KEY_Cyrillic_IE 0x6e5 #define CLUTTER_KEY_Cyrillic_EF 0x6e6 #define CLUTTER_KEY_Cyrillic_GHE 0x6e7 #define CLUTTER_KEY_Cyrillic_HA 0x6e8 #define CLUTTER_KEY_Cyrillic_I 0x6e9 #define CLUTTER_KEY_Cyrillic_SHORTI 0x6ea #define CLUTTER_KEY_Cyrillic_KA 0x6eb #define CLUTTER_KEY_Cyrillic_EL 0x6ec #define CLUTTER_KEY_Cyrillic_EM 0x6ed #define CLUTTER_KEY_Cyrillic_EN 0x6ee #define CLUTTER_KEY_Cyrillic_O 0x6ef #define CLUTTER_KEY_Cyrillic_PE 0x6f0 #define CLUTTER_KEY_Cyrillic_YA 0x6f1 #define CLUTTER_KEY_Cyrillic_ER 0x6f2 #define CLUTTER_KEY_Cyrillic_ES 0x6f3 #define CLUTTER_KEY_Cyrillic_TE 0x6f4 #define CLUTTER_KEY_Cyrillic_U 0x6f5 #define CLUTTER_KEY_Cyrillic_ZHE 0x6f6 #define CLUTTER_KEY_Cyrillic_VE 0x6f7 #define CLUTTER_KEY_Cyrillic_SOFTSIGN 0x6f8 #define CLUTTER_KEY_Cyrillic_YERU 0x6f9 #define CLUTTER_KEY_Cyrillic_ZE 0x6fa #define CLUTTER_KEY_Cyrillic_SHA 0x6fb #define CLUTTER_KEY_Cyrillic_E 0x6fc #define CLUTTER_KEY_Cyrillic_SHCHA 0x6fd #define CLUTTER_KEY_Cyrillic_CHE 0x6fe #define CLUTTER_KEY_Cyrillic_HARDSIGN 0x6ff #define CLUTTER_KEY_Greek_ALPHAaccent 0x7a1 #define CLUTTER_KEY_Greek_EPSILONaccent 0x7a2 #define CLUTTER_KEY_Greek_ETAaccent 0x7a3 #define CLUTTER_KEY_Greek_IOTAaccent 0x7a4 #define CLUTTER_KEY_Greek_IOTAdieresis 0x7a5 #define CLUTTER_KEY_Greek_IOTAdiaeresis 0x7a5 #define CLUTTER_KEY_Greek_OMICRONaccent 0x7a7 #define CLUTTER_KEY_Greek_UPSILONaccent 0x7a8 #define CLUTTER_KEY_Greek_UPSILONdieresis 0x7a9 #define CLUTTER_KEY_Greek_OMEGAaccent 0x7ab #define CLUTTER_KEY_Greek_accentdieresis 0x7ae #define CLUTTER_KEY_Greek_horizbar 0x7af #define CLUTTER_KEY_Greek_alphaaccent 0x7b1 #define CLUTTER_KEY_Greek_epsilonaccent 0x7b2 #define CLUTTER_KEY_Greek_etaaccent 0x7b3 #define CLUTTER_KEY_Greek_iotaaccent 0x7b4 #define CLUTTER_KEY_Greek_iotadieresis 0x7b5 #define CLUTTER_KEY_Greek_iotaaccentdieresis 0x7b6 #define CLUTTER_KEY_Greek_omicronaccent 0x7b7 #define CLUTTER_KEY_Greek_upsilonaccent 0x7b8 #define CLUTTER_KEY_Greek_upsilondieresis 0x7b9 #define CLUTTER_KEY_Greek_upsilonaccentdieresis 0x7ba #define CLUTTER_KEY_Greek_omegaaccent 0x7bb #define CLUTTER_KEY_Greek_ALPHA 0x7c1 #define CLUTTER_KEY_Greek_BETA 0x7c2 #define CLUTTER_KEY_Greek_GAMMA 0x7c3 #define CLUTTER_KEY_Greek_DELTA 0x7c4 #define CLUTTER_KEY_Greek_EPSILON 0x7c5 #define CLUTTER_KEY_Greek_ZETA 0x7c6 #define CLUTTER_KEY_Greek_ETA 0x7c7 #define CLUTTER_KEY_Greek_THETA 0x7c8 #define CLUTTER_KEY_Greek_IOTA 0x7c9 #define CLUTTER_KEY_Greek_KAPPA 0x7ca #define CLUTTER_KEY_Greek_LAMDA 0x7cb #define CLUTTER_KEY_Greek_LAMBDA 0x7cb #define CLUTTER_KEY_Greek_MU 0x7cc #define CLUTTER_KEY_Greek_NU 0x7cd #define CLUTTER_KEY_Greek_XI 0x7ce #define CLUTTER_KEY_Greek_OMICRON 0x7cf #define CLUTTER_KEY_Greek_PI 0x7d0 #define CLUTTER_KEY_Greek_RHO 0x7d1 #define CLUTTER_KEY_Greek_SIGMA 0x7d2 #define CLUTTER_KEY_Greek_TAU 0x7d4 #define CLUTTER_KEY_Greek_UPSILON 0x7d5 #define CLUTTER_KEY_Greek_PHI 0x7d6 #define CLUTTER_KEY_Greek_CHI 0x7d7 #define CLUTTER_KEY_Greek_PSI 0x7d8 #define CLUTTER_KEY_Greek_OMEGA 0x7d9 #define CLUTTER_KEY_Greek_alpha 0x7e1 #define CLUTTER_KEY_Greek_beta 0x7e2 #define CLUTTER_KEY_Greek_gamma 0x7e3 #define CLUTTER_KEY_Greek_delta 0x7e4 #define CLUTTER_KEY_Greek_epsilon 0x7e5 #define CLUTTER_KEY_Greek_zeta 0x7e6 #define CLUTTER_KEY_Greek_eta 0x7e7 #define CLUTTER_KEY_Greek_theta 0x7e8 #define CLUTTER_KEY_Greek_iota 0x7e9 #define CLUTTER_KEY_Greek_kappa 0x7ea #define CLUTTER_KEY_Greek_lamda 0x7eb #define CLUTTER_KEY_Greek_lambda 0x7eb #define CLUTTER_KEY_Greek_mu 0x7ec #define CLUTTER_KEY_Greek_nu 0x7ed #define CLUTTER_KEY_Greek_xi 0x7ee #define CLUTTER_KEY_Greek_omicron 0x7ef #define CLUTTER_KEY_Greek_pi 0x7f0 #define CLUTTER_KEY_Greek_rho 0x7f1 #define CLUTTER_KEY_Greek_sigma 0x7f2 #define CLUTTER_KEY_Greek_finalsmallsigma 0x7f3 #define CLUTTER_KEY_Greek_tau 0x7f4 #define CLUTTER_KEY_Greek_upsilon 0x7f5 #define CLUTTER_KEY_Greek_phi 0x7f6 #define CLUTTER_KEY_Greek_chi 0x7f7 #define CLUTTER_KEY_Greek_psi 0x7f8 #define CLUTTER_KEY_Greek_omega 0x7f9 #define CLUTTER_KEY_Greek_switch 0xff7e #define CLUTTER_KEY_leftradical 0x8a1 #define CLUTTER_KEY_topleftradical 0x8a2 #define CLUTTER_KEY_horizconnector 0x8a3 #define CLUTTER_KEY_topintegral 0x8a4 #define CLUTTER_KEY_botintegral 0x8a5 #define CLUTTER_KEY_vertconnector 0x8a6 #define CLUTTER_KEY_topleftsqbracket 0x8a7 #define CLUTTER_KEY_botleftsqbracket 0x8a8 #define CLUTTER_KEY_toprightsqbracket 0x8a9 #define CLUTTER_KEY_botrightsqbracket 0x8aa #define CLUTTER_KEY_topleftparens 0x8ab #define CLUTTER_KEY_botleftparens 0x8ac #define CLUTTER_KEY_toprightparens 0x8ad #define CLUTTER_KEY_botrightparens 0x8ae #define CLUTTER_KEY_leftmiddlecurlybrace 0x8af #define CLUTTER_KEY_rightmiddlecurlybrace 0x8b0 #define CLUTTER_KEY_topleftsummation 0x8b1 #define CLUTTER_KEY_botleftsummation 0x8b2 #define CLUTTER_KEY_topvertsummationconnector 0x8b3 #define CLUTTER_KEY_botvertsummationconnector 0x8b4 #define CLUTTER_KEY_toprightsummation 0x8b5 #define CLUTTER_KEY_botrightsummation 0x8b6 #define CLUTTER_KEY_rightmiddlesummation 0x8b7 #define CLUTTER_KEY_lessthanequal 0x8bc #define CLUTTER_KEY_notequal 0x8bd #define CLUTTER_KEY_greaterthanequal 0x8be #define CLUTTER_KEY_integral 0x8bf #define CLUTTER_KEY_therefore 0x8c0 #define CLUTTER_KEY_variation 0x8c1 #define CLUTTER_KEY_infinity 0x8c2 #define CLUTTER_KEY_nabla 0x8c5 #define CLUTTER_KEY_approximate 0x8c8 #define CLUTTER_KEY_similarequal 0x8c9 #define CLUTTER_KEY_ifonlyif 0x8cd #define CLUTTER_KEY_implies 0x8ce #define CLUTTER_KEY_identical 0x8cf #define CLUTTER_KEY_radical 0x8d6 #define CLUTTER_KEY_includedin 0x8da #define CLUTTER_KEY_includes 0x8db #define CLUTTER_KEY_intersection 0x8dc #define CLUTTER_KEY_union 0x8dd #define CLUTTER_KEY_logicaland 0x8de #define CLUTTER_KEY_logicalor 0x8df #define CLUTTER_KEY_partialderivative 0x8ef #define CLUTTER_KEY_function 0x8f6 #define CLUTTER_KEY_leftarrow 0x8fb #define CLUTTER_KEY_uparrow 0x8fc #define CLUTTER_KEY_rightarrow 0x8fd #define CLUTTER_KEY_downarrow 0x8fe #define CLUTTER_KEY_blank 0x9df #define CLUTTER_KEY_soliddiamond 0x9e0 #define CLUTTER_KEY_checkerboard 0x9e1 #define CLUTTER_KEY_ht 0x9e2 #define CLUTTER_KEY_ff 0x9e3 #define CLUTTER_KEY_cr 0x9e4 #define CLUTTER_KEY_lf 0x9e5 #define CLUTTER_KEY_nl 0x9e8 #define CLUTTER_KEY_vt 0x9e9 #define CLUTTER_KEY_lowrightcorner 0x9ea #define CLUTTER_KEY_uprightcorner 0x9eb #define CLUTTER_KEY_upleftcorner 0x9ec #define CLUTTER_KEY_lowleftcorner 0x9ed #define CLUTTER_KEY_crossinglines 0x9ee #define CLUTTER_KEY_horizlinescan1 0x9ef #define CLUTTER_KEY_horizlinescan3 0x9f0 #define CLUTTER_KEY_horizlinescan5 0x9f1 #define CLUTTER_KEY_horizlinescan7 0x9f2 #define CLUTTER_KEY_horizlinescan9 0x9f3 #define CLUTTER_KEY_leftt 0x9f4 #define CLUTTER_KEY_rightt 0x9f5 #define CLUTTER_KEY_bott 0x9f6 #define CLUTTER_KEY_topt 0x9f7 #define CLUTTER_KEY_vertbar 0x9f8 #define CLUTTER_KEY_emspace 0xaa1 #define CLUTTER_KEY_enspace 0xaa2 #define CLUTTER_KEY_em3space 0xaa3 #define CLUTTER_KEY_em4space 0xaa4 #define CLUTTER_KEY_digitspace 0xaa5 #define CLUTTER_KEY_punctspace 0xaa6 #define CLUTTER_KEY_thinspace 0xaa7 #define CLUTTER_KEY_hairspace 0xaa8 #define CLUTTER_KEY_emdash 0xaa9 #define CLUTTER_KEY_endash 0xaaa #define CLUTTER_KEY_signifblank 0xaac #define CLUTTER_KEY_ellipsis 0xaae #define CLUTTER_KEY_doubbaselinedot 0xaaf #define CLUTTER_KEY_onethird 0xab0 #define CLUTTER_KEY_twothirds 0xab1 #define CLUTTER_KEY_onefifth 0xab2 #define CLUTTER_KEY_twofifths 0xab3 #define CLUTTER_KEY_threefifths 0xab4 #define CLUTTER_KEY_fourfifths 0xab5 #define CLUTTER_KEY_onesixth 0xab6 #define CLUTTER_KEY_fivesixths 0xab7 #define CLUTTER_KEY_careof 0xab8 #define CLUTTER_KEY_figdash 0xabb #define CLUTTER_KEY_leftanglebracket 0xabc #define CLUTTER_KEY_decimalpoint 0xabd #define CLUTTER_KEY_rightanglebracket 0xabe #define CLUTTER_KEY_marker 0xabf #define CLUTTER_KEY_oneeighth 0xac3 #define CLUTTER_KEY_threeeighths 0xac4 #define CLUTTER_KEY_fiveeighths 0xac5 #define CLUTTER_KEY_seveneighths 0xac6 #define CLUTTER_KEY_trademark 0xac9 #define CLUTTER_KEY_signaturemark 0xaca #define CLUTTER_KEY_trademarkincircle 0xacb #define CLUTTER_KEY_leftopentriangle 0xacc #define CLUTTER_KEY_rightopentriangle 0xacd #define CLUTTER_KEY_emopencircle 0xace #define CLUTTER_KEY_emopenrectangle 0xacf #define CLUTTER_KEY_leftsinglequotemark 0xad0 #define CLUTTER_KEY_rightsinglequotemark 0xad1 #define CLUTTER_KEY_leftdoublequotemark 0xad2 #define CLUTTER_KEY_rightdoublequotemark 0xad3 #define CLUTTER_KEY_prescription 0xad4 #define CLUTTER_KEY_permille 0xad5 #define CLUTTER_KEY_minutes 0xad6 #define CLUTTER_KEY_seconds 0xad7 #define CLUTTER_KEY_latincross 0xad9 #define CLUTTER_KEY_hexagram 0xada #define CLUTTER_KEY_filledrectbullet 0xadb #define CLUTTER_KEY_filledlefttribullet 0xadc #define CLUTTER_KEY_filledrighttribullet 0xadd #define CLUTTER_KEY_emfilledcircle 0xade #define CLUTTER_KEY_emfilledrect 0xadf #define CLUTTER_KEY_enopencircbullet 0xae0 #define CLUTTER_KEY_enopensquarebullet 0xae1 #define CLUTTER_KEY_openrectbullet 0xae2 #define CLUTTER_KEY_opentribulletup 0xae3 #define CLUTTER_KEY_opentribulletdown 0xae4 #define CLUTTER_KEY_openstar 0xae5 #define CLUTTER_KEY_enfilledcircbullet 0xae6 #define CLUTTER_KEY_enfilledsqbullet 0xae7 #define CLUTTER_KEY_filledtribulletup 0xae8 #define CLUTTER_KEY_filledtribulletdown 0xae9 #define CLUTTER_KEY_leftpointer 0xaea #define CLUTTER_KEY_rightpointer 0xaeb #define CLUTTER_KEY_club 0xaec #define CLUTTER_KEY_diamond 0xaed #define CLUTTER_KEY_heart 0xaee #define CLUTTER_KEY_maltesecross 0xaf0 #define CLUTTER_KEY_dagger 0xaf1 #define CLUTTER_KEY_doubledagger 0xaf2 #define CLUTTER_KEY_checkmark 0xaf3 #define CLUTTER_KEY_ballotcross 0xaf4 #define CLUTTER_KEY_musicalsharp 0xaf5 #define CLUTTER_KEY_musicalflat 0xaf6 #define CLUTTER_KEY_malesymbol 0xaf7 #define CLUTTER_KEY_femalesymbol 0xaf8 #define CLUTTER_KEY_telephone 0xaf9 #define CLUTTER_KEY_telephonerecorder 0xafa #define CLUTTER_KEY_phonographcopyright 0xafb #define CLUTTER_KEY_caret 0xafc #define CLUTTER_KEY_singlelowquotemark 0xafd #define CLUTTER_KEY_doublelowquotemark 0xafe #define CLUTTER_KEY_cursor 0xaff #define CLUTTER_KEY_leftcaret 0xba3 #define CLUTTER_KEY_rightcaret 0xba6 #define CLUTTER_KEY_downcaret 0xba8 #define CLUTTER_KEY_upcaret 0xba9 #define CLUTTER_KEY_overbar 0xbc0 #define CLUTTER_KEY_downtack 0xbc2 #define CLUTTER_KEY_upshoe 0xbc3 #define CLUTTER_KEY_downstile 0xbc4 #define CLUTTER_KEY_underbar 0xbc6 #define CLUTTER_KEY_jot 0xbca #define CLUTTER_KEY_quad 0xbcc #define CLUTTER_KEY_uptack 0xbce #define CLUTTER_KEY_circle 0xbcf #define CLUTTER_KEY_upstile 0xbd3 #define CLUTTER_KEY_downshoe 0xbd6 #define CLUTTER_KEY_rightshoe 0xbd8 #define CLUTTER_KEY_leftshoe 0xbda #define CLUTTER_KEY_lefttack 0xbdc #define CLUTTER_KEY_righttack 0xbfc #define CLUTTER_KEY_hebrew_doublelowline 0xcdf #define CLUTTER_KEY_hebrew_aleph 0xce0 #define CLUTTER_KEY_hebrew_bet 0xce1 #define CLUTTER_KEY_hebrew_beth 0xce1 #define CLUTTER_KEY_hebrew_gimel 0xce2 #define CLUTTER_KEY_hebrew_gimmel 0xce2 #define CLUTTER_KEY_hebrew_dalet 0xce3 #define CLUTTER_KEY_hebrew_daleth 0xce3 #define CLUTTER_KEY_hebrew_he 0xce4 #define CLUTTER_KEY_hebrew_waw 0xce5 #define CLUTTER_KEY_hebrew_zain 0xce6 #define CLUTTER_KEY_hebrew_zayin 0xce6 #define CLUTTER_KEY_hebrew_chet 0xce7 #define CLUTTER_KEY_hebrew_het 0xce7 #define CLUTTER_KEY_hebrew_tet 0xce8 #define CLUTTER_KEY_hebrew_teth 0xce8 #define CLUTTER_KEY_hebrew_yod 0xce9 #define CLUTTER_KEY_hebrew_finalkaph 0xcea #define CLUTTER_KEY_hebrew_kaph 0xceb #define CLUTTER_KEY_hebrew_lamed 0xcec #define CLUTTER_KEY_hebrew_finalmem 0xced #define CLUTTER_KEY_hebrew_mem 0xcee #define CLUTTER_KEY_hebrew_finalnun 0xcef #define CLUTTER_KEY_hebrew_nun 0xcf0 #define CLUTTER_KEY_hebrew_samech 0xcf1 #define CLUTTER_KEY_hebrew_samekh 0xcf1 #define CLUTTER_KEY_hebrew_ayin 0xcf2 #define CLUTTER_KEY_hebrew_finalpe 0xcf3 #define CLUTTER_KEY_hebrew_pe 0xcf4 #define CLUTTER_KEY_hebrew_finalzade 0xcf5 #define CLUTTER_KEY_hebrew_finalzadi 0xcf5 #define CLUTTER_KEY_hebrew_zade 0xcf6 #define CLUTTER_KEY_hebrew_zadi 0xcf6 #define CLUTTER_KEY_hebrew_qoph 0xcf7 #define CLUTTER_KEY_hebrew_kuf 0xcf7 #define CLUTTER_KEY_hebrew_resh 0xcf8 #define CLUTTER_KEY_hebrew_shin 0xcf9 #define CLUTTER_KEY_hebrew_taw 0xcfa #define CLUTTER_KEY_hebrew_taf 0xcfa #define CLUTTER_KEY_Hebrew_switch 0xff7e #define CLUTTER_KEY_Thai_kokai 0xda1 #define CLUTTER_KEY_Thai_khokhai 0xda2 #define CLUTTER_KEY_Thai_khokhuat 0xda3 #define CLUTTER_KEY_Thai_khokhwai 0xda4 #define CLUTTER_KEY_Thai_khokhon 0xda5 #define CLUTTER_KEY_Thai_khorakhang 0xda6 #define CLUTTER_KEY_Thai_ngongu 0xda7 #define CLUTTER_KEY_Thai_chochan 0xda8 #define CLUTTER_KEY_Thai_choching 0xda9 #define CLUTTER_KEY_Thai_chochang 0xdaa #define CLUTTER_KEY_Thai_soso 0xdab #define CLUTTER_KEY_Thai_chochoe 0xdac #define CLUTTER_KEY_Thai_yoying 0xdad #define CLUTTER_KEY_Thai_dochada 0xdae #define CLUTTER_KEY_Thai_topatak 0xdaf #define CLUTTER_KEY_Thai_thothan 0xdb0 #define CLUTTER_KEY_Thai_thonangmontho 0xdb1 #define CLUTTER_KEY_Thai_thophuthao 0xdb2 #define CLUTTER_KEY_Thai_nonen 0xdb3 #define CLUTTER_KEY_Thai_dodek 0xdb4 #define CLUTTER_KEY_Thai_totao 0xdb5 #define CLUTTER_KEY_Thai_thothung 0xdb6 #define CLUTTER_KEY_Thai_thothahan 0xdb7 #define CLUTTER_KEY_Thai_thothong 0xdb8 #define CLUTTER_KEY_Thai_nonu 0xdb9 #define CLUTTER_KEY_Thai_bobaimai 0xdba #define CLUTTER_KEY_Thai_popla 0xdbb #define CLUTTER_KEY_Thai_phophung 0xdbc #define CLUTTER_KEY_Thai_fofa 0xdbd #define CLUTTER_KEY_Thai_phophan 0xdbe #define CLUTTER_KEY_Thai_fofan 0xdbf #define CLUTTER_KEY_Thai_phosamphao 0xdc0 #define CLUTTER_KEY_Thai_moma 0xdc1 #define CLUTTER_KEY_Thai_yoyak 0xdc2 #define CLUTTER_KEY_Thai_rorua 0xdc3 #define CLUTTER_KEY_Thai_ru 0xdc4 #define CLUTTER_KEY_Thai_loling 0xdc5 #define CLUTTER_KEY_Thai_lu 0xdc6 #define CLUTTER_KEY_Thai_wowaen 0xdc7 #define CLUTTER_KEY_Thai_sosala 0xdc8 #define CLUTTER_KEY_Thai_sorusi 0xdc9 #define CLUTTER_KEY_Thai_sosua 0xdca #define CLUTTER_KEY_Thai_hohip 0xdcb #define CLUTTER_KEY_Thai_lochula 0xdcc #define CLUTTER_KEY_Thai_oang 0xdcd #define CLUTTER_KEY_Thai_honokhuk 0xdce #define CLUTTER_KEY_Thai_paiyannoi 0xdcf #define CLUTTER_KEY_Thai_saraa 0xdd0 #define CLUTTER_KEY_Thai_maihanakat 0xdd1 #define CLUTTER_KEY_Thai_saraaa 0xdd2 #define CLUTTER_KEY_Thai_saraam 0xdd3 #define CLUTTER_KEY_Thai_sarai 0xdd4 #define CLUTTER_KEY_Thai_saraii 0xdd5 #define CLUTTER_KEY_Thai_saraue 0xdd6 #define CLUTTER_KEY_Thai_sarauee 0xdd7 #define CLUTTER_KEY_Thai_sarau 0xdd8 #define CLUTTER_KEY_Thai_sarauu 0xdd9 #define CLUTTER_KEY_Thai_phinthu 0xdda #define CLUTTER_KEY_Thai_maihanakat_maitho 0xdde #define CLUTTER_KEY_Thai_baht 0xddf #define CLUTTER_KEY_Thai_sarae 0xde0 #define CLUTTER_KEY_Thai_saraae 0xde1 #define CLUTTER_KEY_Thai_sarao 0xde2 #define CLUTTER_KEY_Thai_saraaimaimuan 0xde3 #define CLUTTER_KEY_Thai_saraaimaimalai 0xde4 #define CLUTTER_KEY_Thai_lakkhangyao 0xde5 #define CLUTTER_KEY_Thai_maiyamok 0xde6 #define CLUTTER_KEY_Thai_maitaikhu 0xde7 #define CLUTTER_KEY_Thai_maiek 0xde8 #define CLUTTER_KEY_Thai_maitho 0xde9 #define CLUTTER_KEY_Thai_maitri 0xdea #define CLUTTER_KEY_Thai_maichattawa 0xdeb #define CLUTTER_KEY_Thai_thanthakhat 0xdec #define CLUTTER_KEY_Thai_nikhahit 0xded #define CLUTTER_KEY_Thai_leksun 0xdf0 #define CLUTTER_KEY_Thai_leknung 0xdf1 #define CLUTTER_KEY_Thai_leksong 0xdf2 #define CLUTTER_KEY_Thai_leksam 0xdf3 #define CLUTTER_KEY_Thai_leksi 0xdf4 #define CLUTTER_KEY_Thai_lekha 0xdf5 #define CLUTTER_KEY_Thai_lekhok 0xdf6 #define CLUTTER_KEY_Thai_lekchet 0xdf7 #define CLUTTER_KEY_Thai_lekpaet 0xdf8 #define CLUTTER_KEY_Thai_lekkao 0xdf9 #define CLUTTER_KEY_Hangul 0xff31 #define CLUTTER_KEY_Hangul_Start 0xff32 #define CLUTTER_KEY_Hangul_End 0xff33 #define CLUTTER_KEY_Hangul_Hanja 0xff34 #define CLUTTER_KEY_Hangul_Jamo 0xff35 #define CLUTTER_KEY_Hangul_Romaja 0xff36 #define CLUTTER_KEY_Hangul_Codeinput 0xff37 #define CLUTTER_KEY_Hangul_Jeonja 0xff38 #define CLUTTER_KEY_Hangul_Banja 0xff39 #define CLUTTER_KEY_Hangul_PreHanja 0xff3a #define CLUTTER_KEY_Hangul_PostHanja 0xff3b #define CLUTTER_KEY_Hangul_SingleCandidate 0xff3c #define CLUTTER_KEY_Hangul_MultipleCandidate 0xff3d #define CLUTTER_KEY_Hangul_PreviousCandidate 0xff3e #define CLUTTER_KEY_Hangul_Special 0xff3f #define CLUTTER_KEY_Hangul_switch 0xff7e #define CLUTTER_KEY_Hangul_Kiyeog 0xea1 #define CLUTTER_KEY_Hangul_SsangKiyeog 0xea2 #define CLUTTER_KEY_Hangul_KiyeogSios 0xea3 #define CLUTTER_KEY_Hangul_Nieun 0xea4 #define CLUTTER_KEY_Hangul_NieunJieuj 0xea5 #define CLUTTER_KEY_Hangul_NieunHieuh 0xea6 #define CLUTTER_KEY_Hangul_Dikeud 0xea7 #define CLUTTER_KEY_Hangul_SsangDikeud 0xea8 #define CLUTTER_KEY_Hangul_Rieul 0xea9 #define CLUTTER_KEY_Hangul_RieulKiyeog 0xeaa #define CLUTTER_KEY_Hangul_RieulMieum 0xeab #define CLUTTER_KEY_Hangul_RieulPieub 0xeac #define CLUTTER_KEY_Hangul_RieulSios 0xead #define CLUTTER_KEY_Hangul_RieulTieut 0xeae #define CLUTTER_KEY_Hangul_RieulPhieuf 0xeaf #define CLUTTER_KEY_Hangul_RieulHieuh 0xeb0 #define CLUTTER_KEY_Hangul_Mieum 0xeb1 #define CLUTTER_KEY_Hangul_Pieub 0xeb2 #define CLUTTER_KEY_Hangul_SsangPieub 0xeb3 #define CLUTTER_KEY_Hangul_PieubSios 0xeb4 #define CLUTTER_KEY_Hangul_Sios 0xeb5 #define CLUTTER_KEY_Hangul_SsangSios 0xeb6 #define CLUTTER_KEY_Hangul_Ieung 0xeb7 #define CLUTTER_KEY_Hangul_Jieuj 0xeb8 #define CLUTTER_KEY_Hangul_SsangJieuj 0xeb9 #define CLUTTER_KEY_Hangul_Cieuc 0xeba #define CLUTTER_KEY_Hangul_Khieuq 0xebb #define CLUTTER_KEY_Hangul_Tieut 0xebc #define CLUTTER_KEY_Hangul_Phieuf 0xebd #define CLUTTER_KEY_Hangul_Hieuh 0xebe #define CLUTTER_KEY_Hangul_A 0xebf #define CLUTTER_KEY_Hangul_AE 0xec0 #define CLUTTER_KEY_Hangul_YA 0xec1 #define CLUTTER_KEY_Hangul_YAE 0xec2 #define CLUTTER_KEY_Hangul_EO 0xec3 #define CLUTTER_KEY_Hangul_E 0xec4 #define CLUTTER_KEY_Hangul_YEO 0xec5 #define CLUTTER_KEY_Hangul_YE 0xec6 #define CLUTTER_KEY_Hangul_O 0xec7 #define CLUTTER_KEY_Hangul_WA 0xec8 #define CLUTTER_KEY_Hangul_WAE 0xec9 #define CLUTTER_KEY_Hangul_OE 0xeca #define CLUTTER_KEY_Hangul_YO 0xecb #define CLUTTER_KEY_Hangul_U 0xecc #define CLUTTER_KEY_Hangul_WEO 0xecd #define CLUTTER_KEY_Hangul_WE 0xece #define CLUTTER_KEY_Hangul_WI 0xecf #define CLUTTER_KEY_Hangul_YU 0xed0 #define CLUTTER_KEY_Hangul_EU 0xed1 #define CLUTTER_KEY_Hangul_YI 0xed2 #define CLUTTER_KEY_Hangul_I 0xed3 #define CLUTTER_KEY_Hangul_J_Kiyeog 0xed4 #define CLUTTER_KEY_Hangul_J_SsangKiyeog 0xed5 #define CLUTTER_KEY_Hangul_J_KiyeogSios 0xed6 #define CLUTTER_KEY_Hangul_J_Nieun 0xed7 #define CLUTTER_KEY_Hangul_J_NieunJieuj 0xed8 #define CLUTTER_KEY_Hangul_J_NieunHieuh 0xed9 #define CLUTTER_KEY_Hangul_J_Dikeud 0xeda #define CLUTTER_KEY_Hangul_J_Rieul 0xedb #define CLUTTER_KEY_Hangul_J_RieulKiyeog 0xedc #define CLUTTER_KEY_Hangul_J_RieulMieum 0xedd #define CLUTTER_KEY_Hangul_J_RieulPieub 0xede #define CLUTTER_KEY_Hangul_J_RieulSios 0xedf #define CLUTTER_KEY_Hangul_J_RieulTieut 0xee0 #define CLUTTER_KEY_Hangul_J_RieulPhieuf 0xee1 #define CLUTTER_KEY_Hangul_J_RieulHieuh 0xee2 #define CLUTTER_KEY_Hangul_J_Mieum 0xee3 #define CLUTTER_KEY_Hangul_J_Pieub 0xee4 #define CLUTTER_KEY_Hangul_J_PieubSios 0xee5 #define CLUTTER_KEY_Hangul_J_Sios 0xee6 #define CLUTTER_KEY_Hangul_J_SsangSios 0xee7 #define CLUTTER_KEY_Hangul_J_Ieung 0xee8 #define CLUTTER_KEY_Hangul_J_Jieuj 0xee9 #define CLUTTER_KEY_Hangul_J_Cieuc 0xeea #define CLUTTER_KEY_Hangul_J_Khieuq 0xeeb #define CLUTTER_KEY_Hangul_J_Tieut 0xeec #define CLUTTER_KEY_Hangul_J_Phieuf 0xeed #define CLUTTER_KEY_Hangul_J_Hieuh 0xeee #define CLUTTER_KEY_Hangul_RieulYeorinHieuh 0xeef #define CLUTTER_KEY_Hangul_SunkyeongeumMieum 0xef0 #define CLUTTER_KEY_Hangul_SunkyeongeumPieub 0xef1 #define CLUTTER_KEY_Hangul_PanSios 0xef2 #define CLUTTER_KEY_Hangul_KkogjiDalrinIeung 0xef3 #define CLUTTER_KEY_Hangul_SunkyeongeumPhieuf 0xef4 #define CLUTTER_KEY_Hangul_YeorinHieuh 0xef5 #define CLUTTER_KEY_Hangul_AraeA 0xef6 #define CLUTTER_KEY_Hangul_AraeAE 0xef7 #define CLUTTER_KEY_Hangul_J_PanSios 0xef8 #define CLUTTER_KEY_Hangul_J_KkogjiDalrinIeung 0xef9 #define CLUTTER_KEY_Hangul_J_YeorinHieuh 0xefa #define CLUTTER_KEY_Korean_Won 0xeff #define CLUTTER_KEY_Armenian_ligature_ew 0x1000587 #define CLUTTER_KEY_Armenian_full_stop 0x1000589 #define CLUTTER_KEY_Armenian_verjaket 0x1000589 #define CLUTTER_KEY_Armenian_separation_mark 0x100055d #define CLUTTER_KEY_Armenian_but 0x100055d #define CLUTTER_KEY_Armenian_hyphen 0x100058a #define CLUTTER_KEY_Armenian_yentamna 0x100058a #define CLUTTER_KEY_Armenian_exclam 0x100055c #define CLUTTER_KEY_Armenian_amanak 0x100055c #define CLUTTER_KEY_Armenian_accent 0x100055b #define CLUTTER_KEY_Armenian_shesht 0x100055b #define CLUTTER_KEY_Armenian_question 0x100055e #define CLUTTER_KEY_Armenian_paruyk 0x100055e #define CLUTTER_KEY_Armenian_AYB 0x1000531 #define CLUTTER_KEY_Armenian_ayb 0x1000561 #define CLUTTER_KEY_Armenian_BEN 0x1000532 #define CLUTTER_KEY_Armenian_ben 0x1000562 #define CLUTTER_KEY_Armenian_GIM 0x1000533 #define CLUTTER_KEY_Armenian_gim 0x1000563 #define CLUTTER_KEY_Armenian_DA 0x1000534 #define CLUTTER_KEY_Armenian_da 0x1000564 #define CLUTTER_KEY_Armenian_YECH 0x1000535 #define CLUTTER_KEY_Armenian_yech 0x1000565 #define CLUTTER_KEY_Armenian_ZA 0x1000536 #define CLUTTER_KEY_Armenian_za 0x1000566 #define CLUTTER_KEY_Armenian_E 0x1000537 #define CLUTTER_KEY_Armenian_e 0x1000567 #define CLUTTER_KEY_Armenian_AT 0x1000538 #define CLUTTER_KEY_Armenian_at 0x1000568 #define CLUTTER_KEY_Armenian_TO 0x1000539 #define CLUTTER_KEY_Armenian_to 0x1000569 #define CLUTTER_KEY_Armenian_ZHE 0x100053a #define CLUTTER_KEY_Armenian_zhe 0x100056a #define CLUTTER_KEY_Armenian_INI 0x100053b #define CLUTTER_KEY_Armenian_ini 0x100056b #define CLUTTER_KEY_Armenian_LYUN 0x100053c #define CLUTTER_KEY_Armenian_lyun 0x100056c #define CLUTTER_KEY_Armenian_KHE 0x100053d #define CLUTTER_KEY_Armenian_khe 0x100056d #define CLUTTER_KEY_Armenian_TSA 0x100053e #define CLUTTER_KEY_Armenian_tsa 0x100056e #define CLUTTER_KEY_Armenian_KEN 0x100053f #define CLUTTER_KEY_Armenian_ken 0x100056f #define CLUTTER_KEY_Armenian_HO 0x1000540 #define CLUTTER_KEY_Armenian_ho 0x1000570 #define CLUTTER_KEY_Armenian_DZA 0x1000541 #define CLUTTER_KEY_Armenian_dza 0x1000571 #define CLUTTER_KEY_Armenian_GHAT 0x1000542 #define CLUTTER_KEY_Armenian_ghat 0x1000572 #define CLUTTER_KEY_Armenian_TCHE 0x1000543 #define CLUTTER_KEY_Armenian_tche 0x1000573 #define CLUTTER_KEY_Armenian_MEN 0x1000544 #define CLUTTER_KEY_Armenian_men 0x1000574 #define CLUTTER_KEY_Armenian_HI 0x1000545 #define CLUTTER_KEY_Armenian_hi 0x1000575 #define CLUTTER_KEY_Armenian_NU 0x1000546 #define CLUTTER_KEY_Armenian_nu 0x1000576 #define CLUTTER_KEY_Armenian_SHA 0x1000547 #define CLUTTER_KEY_Armenian_sha 0x1000577 #define CLUTTER_KEY_Armenian_VO 0x1000548 #define CLUTTER_KEY_Armenian_vo 0x1000578 #define CLUTTER_KEY_Armenian_CHA 0x1000549 #define CLUTTER_KEY_Armenian_cha 0x1000579 #define CLUTTER_KEY_Armenian_PE 0x100054a #define CLUTTER_KEY_Armenian_pe 0x100057a #define CLUTTER_KEY_Armenian_JE 0x100054b #define CLUTTER_KEY_Armenian_je 0x100057b #define CLUTTER_KEY_Armenian_RA 0x100054c #define CLUTTER_KEY_Armenian_ra 0x100057c #define CLUTTER_KEY_Armenian_SE 0x100054d #define CLUTTER_KEY_Armenian_se 0x100057d #define CLUTTER_KEY_Armenian_VEV 0x100054e #define CLUTTER_KEY_Armenian_vev 0x100057e #define CLUTTER_KEY_Armenian_TYUN 0x100054f #define CLUTTER_KEY_Armenian_tyun 0x100057f #define CLUTTER_KEY_Armenian_RE 0x1000550 #define CLUTTER_KEY_Armenian_re 0x1000580 #define CLUTTER_KEY_Armenian_TSO 0x1000551 #define CLUTTER_KEY_Armenian_tso 0x1000581 #define CLUTTER_KEY_Armenian_VYUN 0x1000552 #define CLUTTER_KEY_Armenian_vyun 0x1000582 #define CLUTTER_KEY_Armenian_PYUR 0x1000553 #define CLUTTER_KEY_Armenian_pyur 0x1000583 #define CLUTTER_KEY_Armenian_KE 0x1000554 #define CLUTTER_KEY_Armenian_ke 0x1000584 #define CLUTTER_KEY_Armenian_O 0x1000555 #define CLUTTER_KEY_Armenian_o 0x1000585 #define CLUTTER_KEY_Armenian_FE 0x1000556 #define CLUTTER_KEY_Armenian_fe 0x1000586 #define CLUTTER_KEY_Armenian_apostrophe 0x100055a #define CLUTTER_KEY_Georgian_an 0x10010d0 #define CLUTTER_KEY_Georgian_ban 0x10010d1 #define CLUTTER_KEY_Georgian_gan 0x10010d2 #define CLUTTER_KEY_Georgian_don 0x10010d3 #define CLUTTER_KEY_Georgian_en 0x10010d4 #define CLUTTER_KEY_Georgian_vin 0x10010d5 #define CLUTTER_KEY_Georgian_zen 0x10010d6 #define CLUTTER_KEY_Georgian_tan 0x10010d7 #define CLUTTER_KEY_Georgian_in 0x10010d8 #define CLUTTER_KEY_Georgian_kan 0x10010d9 #define CLUTTER_KEY_Georgian_las 0x10010da #define CLUTTER_KEY_Georgian_man 0x10010db #define CLUTTER_KEY_Georgian_nar 0x10010dc #define CLUTTER_KEY_Georgian_on 0x10010dd #define CLUTTER_KEY_Georgian_par 0x10010de #define CLUTTER_KEY_Georgian_zhar 0x10010df #define CLUTTER_KEY_Georgian_rae 0x10010e0 #define CLUTTER_KEY_Georgian_san 0x10010e1 #define CLUTTER_KEY_Georgian_tar 0x10010e2 #define CLUTTER_KEY_Georgian_un 0x10010e3 #define CLUTTER_KEY_Georgian_phar 0x10010e4 #define CLUTTER_KEY_Georgian_khar 0x10010e5 #define CLUTTER_KEY_Georgian_ghan 0x10010e6 #define CLUTTER_KEY_Georgian_qar 0x10010e7 #define CLUTTER_KEY_Georgian_shin 0x10010e8 #define CLUTTER_KEY_Georgian_chin 0x10010e9 #define CLUTTER_KEY_Georgian_can 0x10010ea #define CLUTTER_KEY_Georgian_jil 0x10010eb #define CLUTTER_KEY_Georgian_cil 0x10010ec #define CLUTTER_KEY_Georgian_char 0x10010ed #define CLUTTER_KEY_Georgian_xan 0x10010ee #define CLUTTER_KEY_Georgian_jhan 0x10010ef #define CLUTTER_KEY_Georgian_hae 0x10010f0 #define CLUTTER_KEY_Georgian_he 0x10010f1 #define CLUTTER_KEY_Georgian_hie 0x10010f2 #define CLUTTER_KEY_Georgian_we 0x10010f3 #define CLUTTER_KEY_Georgian_har 0x10010f4 #define CLUTTER_KEY_Georgian_hoe 0x10010f5 #define CLUTTER_KEY_Georgian_fi 0x10010f6 #define CLUTTER_KEY_Xabovedot 0x1001e8a #define CLUTTER_KEY_Ibreve 0x100012c #define CLUTTER_KEY_Zstroke 0x10001b5 #define CLUTTER_KEY_Gcaron 0x10001e6 #define CLUTTER_KEY_Ocaron 0x10001d1 #define CLUTTER_KEY_Obarred 0x100019f #define CLUTTER_KEY_xabovedot 0x1001e8b #define CLUTTER_KEY_ibreve 0x100012d #define CLUTTER_KEY_zstroke 0x10001b6 #define CLUTTER_KEY_gcaron 0x10001e7 #define CLUTTER_KEY_ocaron 0x10001d2 #define CLUTTER_KEY_obarred 0x1000275 #define CLUTTER_KEY_SCHWA 0x100018f #define CLUTTER_KEY_schwa 0x1000259 #define CLUTTER_KEY_EZH 0x10001b7 #define CLUTTER_KEY_ezh 0x1000292 #define CLUTTER_KEY_Lbelowdot 0x1001e36 #define CLUTTER_KEY_lbelowdot 0x1001e37 #define CLUTTER_KEY_Abelowdot 0x1001ea0 #define CLUTTER_KEY_abelowdot 0x1001ea1 #define CLUTTER_KEY_Ahook 0x1001ea2 #define CLUTTER_KEY_ahook 0x1001ea3 #define CLUTTER_KEY_Acircumflexacute 0x1001ea4 #define CLUTTER_KEY_acircumflexacute 0x1001ea5 #define CLUTTER_KEY_Acircumflexgrave 0x1001ea6 #define CLUTTER_KEY_acircumflexgrave 0x1001ea7 #define CLUTTER_KEY_Acircumflexhook 0x1001ea8 #define CLUTTER_KEY_acircumflexhook 0x1001ea9 #define CLUTTER_KEY_Acircumflextilde 0x1001eaa #define CLUTTER_KEY_acircumflextilde 0x1001eab #define CLUTTER_KEY_Acircumflexbelowdot 0x1001eac #define CLUTTER_KEY_acircumflexbelowdot 0x1001ead #define CLUTTER_KEY_Abreveacute 0x1001eae #define CLUTTER_KEY_abreveacute 0x1001eaf #define CLUTTER_KEY_Abrevegrave 0x1001eb0 #define CLUTTER_KEY_abrevegrave 0x1001eb1 #define CLUTTER_KEY_Abrevehook 0x1001eb2 #define CLUTTER_KEY_abrevehook 0x1001eb3 #define CLUTTER_KEY_Abrevetilde 0x1001eb4 #define CLUTTER_KEY_abrevetilde 0x1001eb5 #define CLUTTER_KEY_Abrevebelowdot 0x1001eb6 #define CLUTTER_KEY_abrevebelowdot 0x1001eb7 #define CLUTTER_KEY_Ebelowdot 0x1001eb8 #define CLUTTER_KEY_ebelowdot 0x1001eb9 #define CLUTTER_KEY_Ehook 0x1001eba #define CLUTTER_KEY_ehook 0x1001ebb #define CLUTTER_KEY_Etilde 0x1001ebc #define CLUTTER_KEY_etilde 0x1001ebd #define CLUTTER_KEY_Ecircumflexacute 0x1001ebe #define CLUTTER_KEY_ecircumflexacute 0x1001ebf #define CLUTTER_KEY_Ecircumflexgrave 0x1001ec0 #define CLUTTER_KEY_ecircumflexgrave 0x1001ec1 #define CLUTTER_KEY_Ecircumflexhook 0x1001ec2 #define CLUTTER_KEY_ecircumflexhook 0x1001ec3 #define CLUTTER_KEY_Ecircumflextilde 0x1001ec4 #define CLUTTER_KEY_ecircumflextilde 0x1001ec5 #define CLUTTER_KEY_Ecircumflexbelowdot 0x1001ec6 #define CLUTTER_KEY_ecircumflexbelowdot 0x1001ec7 #define CLUTTER_KEY_Ihook 0x1001ec8 #define CLUTTER_KEY_ihook 0x1001ec9 #define CLUTTER_KEY_Ibelowdot 0x1001eca #define CLUTTER_KEY_ibelowdot 0x1001ecb #define CLUTTER_KEY_Obelowdot 0x1001ecc #define CLUTTER_KEY_obelowdot 0x1001ecd #define CLUTTER_KEY_Ohook 0x1001ece #define CLUTTER_KEY_ohook 0x1001ecf #define CLUTTER_KEY_Ocircumflexacute 0x1001ed0 #define CLUTTER_KEY_ocircumflexacute 0x1001ed1 #define CLUTTER_KEY_Ocircumflexgrave 0x1001ed2 #define CLUTTER_KEY_ocircumflexgrave 0x1001ed3 #define CLUTTER_KEY_Ocircumflexhook 0x1001ed4 #define CLUTTER_KEY_ocircumflexhook 0x1001ed5 #define CLUTTER_KEY_Ocircumflextilde 0x1001ed6 #define CLUTTER_KEY_ocircumflextilde 0x1001ed7 #define CLUTTER_KEY_Ocircumflexbelowdot 0x1001ed8 #define CLUTTER_KEY_ocircumflexbelowdot 0x1001ed9 #define CLUTTER_KEY_Ohornacute 0x1001eda #define CLUTTER_KEY_ohornacute 0x1001edb #define CLUTTER_KEY_Ohorngrave 0x1001edc #define CLUTTER_KEY_ohorngrave 0x1001edd #define CLUTTER_KEY_Ohornhook 0x1001ede #define CLUTTER_KEY_ohornhook 0x1001edf #define CLUTTER_KEY_Ohorntilde 0x1001ee0 #define CLUTTER_KEY_ohorntilde 0x1001ee1 #define CLUTTER_KEY_Ohornbelowdot 0x1001ee2 #define CLUTTER_KEY_ohornbelowdot 0x1001ee3 #define CLUTTER_KEY_Ubelowdot 0x1001ee4 #define CLUTTER_KEY_ubelowdot 0x1001ee5 #define CLUTTER_KEY_Uhook 0x1001ee6 #define CLUTTER_KEY_uhook 0x1001ee7 #define CLUTTER_KEY_Uhornacute 0x1001ee8 #define CLUTTER_KEY_uhornacute 0x1001ee9 #define CLUTTER_KEY_Uhorngrave 0x1001eea #define CLUTTER_KEY_uhorngrave 0x1001eeb #define CLUTTER_KEY_Uhornhook 0x1001eec #define CLUTTER_KEY_uhornhook 0x1001eed #define CLUTTER_KEY_Uhorntilde 0x1001eee #define CLUTTER_KEY_uhorntilde 0x1001eef #define CLUTTER_KEY_Uhornbelowdot 0x1001ef0 #define CLUTTER_KEY_uhornbelowdot 0x1001ef1 #define CLUTTER_KEY_Ybelowdot 0x1001ef4 #define CLUTTER_KEY_ybelowdot 0x1001ef5 #define CLUTTER_KEY_Yhook 0x1001ef6 #define CLUTTER_KEY_yhook 0x1001ef7 #define CLUTTER_KEY_Ytilde 0x1001ef8 #define CLUTTER_KEY_ytilde 0x1001ef9 #define CLUTTER_KEY_Ohorn 0x10001a0 #define CLUTTER_KEY_ohorn 0x10001a1 #define CLUTTER_KEY_Uhorn 0x10001af #define CLUTTER_KEY_uhorn 0x10001b0 #define CLUTTER_KEY_EcuSign 0x10020a0 #define CLUTTER_KEY_ColonSign 0x10020a1 #define CLUTTER_KEY_CruzeiroSign 0x10020a2 #define CLUTTER_KEY_FFrancSign 0x10020a3 #define CLUTTER_KEY_LiraSign 0x10020a4 #define CLUTTER_KEY_MillSign 0x10020a5 #define CLUTTER_KEY_NairaSign 0x10020a6 #define CLUTTER_KEY_PesetaSign 0x10020a7 #define CLUTTER_KEY_RupeeSign 0x10020a8 #define CLUTTER_KEY_WonSign 0x10020a9 #define CLUTTER_KEY_NewSheqelSign 0x10020aa #define CLUTTER_KEY_DongSign 0x10020ab #define CLUTTER_KEY_EuroSign 0x20ac #define CLUTTER_KEY_zerosuperior 0x1002070 #define CLUTTER_KEY_foursuperior 0x1002074 #define CLUTTER_KEY_fivesuperior 0x1002075 #define CLUTTER_KEY_sixsuperior 0x1002076 #define CLUTTER_KEY_sevensuperior 0x1002077 #define CLUTTER_KEY_eightsuperior 0x1002078 #define CLUTTER_KEY_ninesuperior 0x1002079 #define CLUTTER_KEY_zerosubscript 0x1002080 #define CLUTTER_KEY_onesubscript 0x1002081 #define CLUTTER_KEY_twosubscript 0x1002082 #define CLUTTER_KEY_threesubscript 0x1002083 #define CLUTTER_KEY_foursubscript 0x1002084 #define CLUTTER_KEY_fivesubscript 0x1002085 #define CLUTTER_KEY_sixsubscript 0x1002086 #define CLUTTER_KEY_sevensubscript 0x1002087 #define CLUTTER_KEY_eightsubscript 0x1002088 #define CLUTTER_KEY_ninesubscript 0x1002089 #define CLUTTER_KEY_partdifferential 0x1002202 #define CLUTTER_KEY_emptyset 0x1002205 #define CLUTTER_KEY_elementof 0x1002208 #define CLUTTER_KEY_notelementof 0x1002209 #define CLUTTER_KEY_containsas 0x100220b #define CLUTTER_KEY_squareroot 0x100221a #define CLUTTER_KEY_cuberoot 0x100221b #define CLUTTER_KEY_fourthroot 0x100221c #define CLUTTER_KEY_dintegral 0x100222c #define CLUTTER_KEY_tintegral 0x100222d #define CLUTTER_KEY_because 0x1002235 #define CLUTTER_KEY_approxeq 0x1002248 #define CLUTTER_KEY_notapproxeq 0x1002247 #define CLUTTER_KEY_notidentical 0x1002262 #define CLUTTER_KEY_stricteq 0x1002263 #define CLUTTER_KEY_braille_dot_1 0xfff1 #define CLUTTER_KEY_braille_dot_2 0xfff2 #define CLUTTER_KEY_braille_dot_3 0xfff3 #define CLUTTER_KEY_braille_dot_4 0xfff4 #define CLUTTER_KEY_braille_dot_5 0xfff5 #define CLUTTER_KEY_braille_dot_6 0xfff6 #define CLUTTER_KEY_braille_dot_7 0xfff7 #define CLUTTER_KEY_braille_dot_8 0xfff8 #define CLUTTER_KEY_braille_dot_9 0xfff9 #define CLUTTER_KEY_braille_dot_10 0xfffa #define CLUTTER_KEY_braille_blank 0x1002800 #define CLUTTER_KEY_braille_dots_1 0x1002801 #define CLUTTER_KEY_braille_dots_2 0x1002802 #define CLUTTER_KEY_braille_dots_12 0x1002803 #define CLUTTER_KEY_braille_dots_3 0x1002804 #define CLUTTER_KEY_braille_dots_13 0x1002805 #define CLUTTER_KEY_braille_dots_23 0x1002806 #define CLUTTER_KEY_braille_dots_123 0x1002807 #define CLUTTER_KEY_braille_dots_4 0x1002808 #define CLUTTER_KEY_braille_dots_14 0x1002809 #define CLUTTER_KEY_braille_dots_24 0x100280a #define CLUTTER_KEY_braille_dots_124 0x100280b #define CLUTTER_KEY_braille_dots_34 0x100280c #define CLUTTER_KEY_braille_dots_134 0x100280d #define CLUTTER_KEY_braille_dots_234 0x100280e #define CLUTTER_KEY_braille_dots_1234 0x100280f #define CLUTTER_KEY_braille_dots_5 0x1002810 #define CLUTTER_KEY_braille_dots_15 0x1002811 #define CLUTTER_KEY_braille_dots_25 0x1002812 #define CLUTTER_KEY_braille_dots_125 0x1002813 #define CLUTTER_KEY_braille_dots_35 0x1002814 #define CLUTTER_KEY_braille_dots_135 0x1002815 #define CLUTTER_KEY_braille_dots_235 0x1002816 #define CLUTTER_KEY_braille_dots_1235 0x1002817 #define CLUTTER_KEY_braille_dots_45 0x1002818 #define CLUTTER_KEY_braille_dots_145 0x1002819 #define CLUTTER_KEY_braille_dots_245 0x100281a #define CLUTTER_KEY_braille_dots_1245 0x100281b #define CLUTTER_KEY_braille_dots_345 0x100281c #define CLUTTER_KEY_braille_dots_1345 0x100281d #define CLUTTER_KEY_braille_dots_2345 0x100281e #define CLUTTER_KEY_braille_dots_12345 0x100281f #define CLUTTER_KEY_braille_dots_6 0x1002820 #define CLUTTER_KEY_braille_dots_16 0x1002821 #define CLUTTER_KEY_braille_dots_26 0x1002822 #define CLUTTER_KEY_braille_dots_126 0x1002823 #define CLUTTER_KEY_braille_dots_36 0x1002824 #define CLUTTER_KEY_braille_dots_136 0x1002825 #define CLUTTER_KEY_braille_dots_236 0x1002826 #define CLUTTER_KEY_braille_dots_1236 0x1002827 #define CLUTTER_KEY_braille_dots_46 0x1002828 #define CLUTTER_KEY_braille_dots_146 0x1002829 #define CLUTTER_KEY_braille_dots_246 0x100282a #define CLUTTER_KEY_braille_dots_1246 0x100282b #define CLUTTER_KEY_braille_dots_346 0x100282c #define CLUTTER_KEY_braille_dots_1346 0x100282d #define CLUTTER_KEY_braille_dots_2346 0x100282e #define CLUTTER_KEY_braille_dots_12346 0x100282f #define CLUTTER_KEY_braille_dots_56 0x1002830 #define CLUTTER_KEY_braille_dots_156 0x1002831 #define CLUTTER_KEY_braille_dots_256 0x1002832 #define CLUTTER_KEY_braille_dots_1256 0x1002833 #define CLUTTER_KEY_braille_dots_356 0x1002834 #define CLUTTER_KEY_braille_dots_1356 0x1002835 #define CLUTTER_KEY_braille_dots_2356 0x1002836 #define CLUTTER_KEY_braille_dots_12356 0x1002837 #define CLUTTER_KEY_braille_dots_456 0x1002838 #define CLUTTER_KEY_braille_dots_1456 0x1002839 #define CLUTTER_KEY_braille_dots_2456 0x100283a #define CLUTTER_KEY_braille_dots_12456 0x100283b #define CLUTTER_KEY_braille_dots_3456 0x100283c #define CLUTTER_KEY_braille_dots_13456 0x100283d #define CLUTTER_KEY_braille_dots_23456 0x100283e #define CLUTTER_KEY_braille_dots_123456 0x100283f #define CLUTTER_KEY_braille_dots_7 0x1002840 #define CLUTTER_KEY_braille_dots_17 0x1002841 #define CLUTTER_KEY_braille_dots_27 0x1002842 #define CLUTTER_KEY_braille_dots_127 0x1002843 #define CLUTTER_KEY_braille_dots_37 0x1002844 #define CLUTTER_KEY_braille_dots_137 0x1002845 #define CLUTTER_KEY_braille_dots_237 0x1002846 #define CLUTTER_KEY_braille_dots_1237 0x1002847 #define CLUTTER_KEY_braille_dots_47 0x1002848 #define CLUTTER_KEY_braille_dots_147 0x1002849 #define CLUTTER_KEY_braille_dots_247 0x100284a #define CLUTTER_KEY_braille_dots_1247 0x100284b #define CLUTTER_KEY_braille_dots_347 0x100284c #define CLUTTER_KEY_braille_dots_1347 0x100284d #define CLUTTER_KEY_braille_dots_2347 0x100284e #define CLUTTER_KEY_braille_dots_12347 0x100284f #define CLUTTER_KEY_braille_dots_57 0x1002850 #define CLUTTER_KEY_braille_dots_157 0x1002851 #define CLUTTER_KEY_braille_dots_257 0x1002852 #define CLUTTER_KEY_braille_dots_1257 0x1002853 #define CLUTTER_KEY_braille_dots_357 0x1002854 #define CLUTTER_KEY_braille_dots_1357 0x1002855 #define CLUTTER_KEY_braille_dots_2357 0x1002856 #define CLUTTER_KEY_braille_dots_12357 0x1002857 #define CLUTTER_KEY_braille_dots_457 0x1002858 #define CLUTTER_KEY_braille_dots_1457 0x1002859 #define CLUTTER_KEY_braille_dots_2457 0x100285a #define CLUTTER_KEY_braille_dots_12457 0x100285b #define CLUTTER_KEY_braille_dots_3457 0x100285c #define CLUTTER_KEY_braille_dots_13457 0x100285d #define CLUTTER_KEY_braille_dots_23457 0x100285e #define CLUTTER_KEY_braille_dots_123457 0x100285f #define CLUTTER_KEY_braille_dots_67 0x1002860 #define CLUTTER_KEY_braille_dots_167 0x1002861 #define CLUTTER_KEY_braille_dots_267 0x1002862 #define CLUTTER_KEY_braille_dots_1267 0x1002863 #define CLUTTER_KEY_braille_dots_367 0x1002864 #define CLUTTER_KEY_braille_dots_1367 0x1002865 #define CLUTTER_KEY_braille_dots_2367 0x1002866 #define CLUTTER_KEY_braille_dots_12367 0x1002867 #define CLUTTER_KEY_braille_dots_467 0x1002868 #define CLUTTER_KEY_braille_dots_1467 0x1002869 #define CLUTTER_KEY_braille_dots_2467 0x100286a #define CLUTTER_KEY_braille_dots_12467 0x100286b #define CLUTTER_KEY_braille_dots_3467 0x100286c #define CLUTTER_KEY_braille_dots_13467 0x100286d #define CLUTTER_KEY_braille_dots_23467 0x100286e #define CLUTTER_KEY_braille_dots_123467 0x100286f #define CLUTTER_KEY_braille_dots_567 0x1002870 #define CLUTTER_KEY_braille_dots_1567 0x1002871 #define CLUTTER_KEY_braille_dots_2567 0x1002872 #define CLUTTER_KEY_braille_dots_12567 0x1002873 #define CLUTTER_KEY_braille_dots_3567 0x1002874 #define CLUTTER_KEY_braille_dots_13567 0x1002875 #define CLUTTER_KEY_braille_dots_23567 0x1002876 #define CLUTTER_KEY_braille_dots_123567 0x1002877 #define CLUTTER_KEY_braille_dots_4567 0x1002878 #define CLUTTER_KEY_braille_dots_14567 0x1002879 #define CLUTTER_KEY_braille_dots_24567 0x100287a #define CLUTTER_KEY_braille_dots_124567 0x100287b #define CLUTTER_KEY_braille_dots_34567 0x100287c #define CLUTTER_KEY_braille_dots_134567 0x100287d #define CLUTTER_KEY_braille_dots_234567 0x100287e #define CLUTTER_KEY_braille_dots_1234567 0x100287f #define CLUTTER_KEY_braille_dots_8 0x1002880 #define CLUTTER_KEY_braille_dots_18 0x1002881 #define CLUTTER_KEY_braille_dots_28 0x1002882 #define CLUTTER_KEY_braille_dots_128 0x1002883 #define CLUTTER_KEY_braille_dots_38 0x1002884 #define CLUTTER_KEY_braille_dots_138 0x1002885 #define CLUTTER_KEY_braille_dots_238 0x1002886 #define CLUTTER_KEY_braille_dots_1238 0x1002887 #define CLUTTER_KEY_braille_dots_48 0x1002888 #define CLUTTER_KEY_braille_dots_148 0x1002889 #define CLUTTER_KEY_braille_dots_248 0x100288a #define CLUTTER_KEY_braille_dots_1248 0x100288b #define CLUTTER_KEY_braille_dots_348 0x100288c #define CLUTTER_KEY_braille_dots_1348 0x100288d #define CLUTTER_KEY_braille_dots_2348 0x100288e #define CLUTTER_KEY_braille_dots_12348 0x100288f #define CLUTTER_KEY_braille_dots_58 0x1002890 #define CLUTTER_KEY_braille_dots_158 0x1002891 #define CLUTTER_KEY_braille_dots_258 0x1002892 #define CLUTTER_KEY_braille_dots_1258 0x1002893 #define CLUTTER_KEY_braille_dots_358 0x1002894 #define CLUTTER_KEY_braille_dots_1358 0x1002895 #define CLUTTER_KEY_braille_dots_2358 0x1002896 #define CLUTTER_KEY_braille_dots_12358 0x1002897 #define CLUTTER_KEY_braille_dots_458 0x1002898 #define CLUTTER_KEY_braille_dots_1458 0x1002899 #define CLUTTER_KEY_braille_dots_2458 0x100289a #define CLUTTER_KEY_braille_dots_12458 0x100289b #define CLUTTER_KEY_braille_dots_3458 0x100289c #define CLUTTER_KEY_braille_dots_13458 0x100289d #define CLUTTER_KEY_braille_dots_23458 0x100289e #define CLUTTER_KEY_braille_dots_123458 0x100289f #define CLUTTER_KEY_braille_dots_68 0x10028a0 #define CLUTTER_KEY_braille_dots_168 0x10028a1 #define CLUTTER_KEY_braille_dots_268 0x10028a2 #define CLUTTER_KEY_braille_dots_1268 0x10028a3 #define CLUTTER_KEY_braille_dots_368 0x10028a4 #define CLUTTER_KEY_braille_dots_1368 0x10028a5 #define CLUTTER_KEY_braille_dots_2368 0x10028a6 #define CLUTTER_KEY_braille_dots_12368 0x10028a7 #define CLUTTER_KEY_braille_dots_468 0x10028a8 #define CLUTTER_KEY_braille_dots_1468 0x10028a9 #define CLUTTER_KEY_braille_dots_2468 0x10028aa #define CLUTTER_KEY_braille_dots_12468 0x10028ab #define CLUTTER_KEY_braille_dots_3468 0x10028ac #define CLUTTER_KEY_braille_dots_13468 0x10028ad #define CLUTTER_KEY_braille_dots_23468 0x10028ae #define CLUTTER_KEY_braille_dots_123468 0x10028af #define CLUTTER_KEY_braille_dots_568 0x10028b0 #define CLUTTER_KEY_braille_dots_1568 0x10028b1 #define CLUTTER_KEY_braille_dots_2568 0x10028b2 #define CLUTTER_KEY_braille_dots_12568 0x10028b3 #define CLUTTER_KEY_braille_dots_3568 0x10028b4 #define CLUTTER_KEY_braille_dots_13568 0x10028b5 #define CLUTTER_KEY_braille_dots_23568 0x10028b6 #define CLUTTER_KEY_braille_dots_123568 0x10028b7 #define CLUTTER_KEY_braille_dots_4568 0x10028b8 #define CLUTTER_KEY_braille_dots_14568 0x10028b9 #define CLUTTER_KEY_braille_dots_24568 0x10028ba #define CLUTTER_KEY_braille_dots_124568 0x10028bb #define CLUTTER_KEY_braille_dots_34568 0x10028bc #define CLUTTER_KEY_braille_dots_134568 0x10028bd #define CLUTTER_KEY_braille_dots_234568 0x10028be #define CLUTTER_KEY_braille_dots_1234568 0x10028bf #define CLUTTER_KEY_braille_dots_78 0x10028c0 #define CLUTTER_KEY_braille_dots_178 0x10028c1 #define CLUTTER_KEY_braille_dots_278 0x10028c2 #define CLUTTER_KEY_braille_dots_1278 0x10028c3 #define CLUTTER_KEY_braille_dots_378 0x10028c4 #define CLUTTER_KEY_braille_dots_1378 0x10028c5 #define CLUTTER_KEY_braille_dots_2378 0x10028c6 #define CLUTTER_KEY_braille_dots_12378 0x10028c7 #define CLUTTER_KEY_braille_dots_478 0x10028c8 #define CLUTTER_KEY_braille_dots_1478 0x10028c9 #define CLUTTER_KEY_braille_dots_2478 0x10028ca #define CLUTTER_KEY_braille_dots_12478 0x10028cb #define CLUTTER_KEY_braille_dots_3478 0x10028cc #define CLUTTER_KEY_braille_dots_13478 0x10028cd #define CLUTTER_KEY_braille_dots_23478 0x10028ce #define CLUTTER_KEY_braille_dots_123478 0x10028cf #define CLUTTER_KEY_braille_dots_578 0x10028d0 #define CLUTTER_KEY_braille_dots_1578 0x10028d1 #define CLUTTER_KEY_braille_dots_2578 0x10028d2 #define CLUTTER_KEY_braille_dots_12578 0x10028d3 #define CLUTTER_KEY_braille_dots_3578 0x10028d4 #define CLUTTER_KEY_braille_dots_13578 0x10028d5 #define CLUTTER_KEY_braille_dots_23578 0x10028d6 #define CLUTTER_KEY_braille_dots_123578 0x10028d7 #define CLUTTER_KEY_braille_dots_4578 0x10028d8 #define CLUTTER_KEY_braille_dots_14578 0x10028d9 #define CLUTTER_KEY_braille_dots_24578 0x10028da #define CLUTTER_KEY_braille_dots_124578 0x10028db #define CLUTTER_KEY_braille_dots_34578 0x10028dc #define CLUTTER_KEY_braille_dots_134578 0x10028dd #define CLUTTER_KEY_braille_dots_234578 0x10028de #define CLUTTER_KEY_braille_dots_1234578 0x10028df #define CLUTTER_KEY_braille_dots_678 0x10028e0 #define CLUTTER_KEY_braille_dots_1678 0x10028e1 #define CLUTTER_KEY_braille_dots_2678 0x10028e2 #define CLUTTER_KEY_braille_dots_12678 0x10028e3 #define CLUTTER_KEY_braille_dots_3678 0x10028e4 #define CLUTTER_KEY_braille_dots_13678 0x10028e5 #define CLUTTER_KEY_braille_dots_23678 0x10028e6 #define CLUTTER_KEY_braille_dots_123678 0x10028e7 #define CLUTTER_KEY_braille_dots_4678 0x10028e8 #define CLUTTER_KEY_braille_dots_14678 0x10028e9 #define CLUTTER_KEY_braille_dots_24678 0x10028ea #define CLUTTER_KEY_braille_dots_124678 0x10028eb #define CLUTTER_KEY_braille_dots_34678 0x10028ec #define CLUTTER_KEY_braille_dots_134678 0x10028ed #define CLUTTER_KEY_braille_dots_234678 0x10028ee #define CLUTTER_KEY_braille_dots_1234678 0x10028ef #define CLUTTER_KEY_braille_dots_5678 0x10028f0 #define CLUTTER_KEY_braille_dots_15678 0x10028f1 #define CLUTTER_KEY_braille_dots_25678 0x10028f2 #define CLUTTER_KEY_braille_dots_125678 0x10028f3 #define CLUTTER_KEY_braille_dots_35678 0x10028f4 #define CLUTTER_KEY_braille_dots_135678 0x10028f5 #define CLUTTER_KEY_braille_dots_235678 0x10028f6 #define CLUTTER_KEY_braille_dots_1235678 0x10028f7 #define CLUTTER_KEY_braille_dots_45678 0x10028f8 #define CLUTTER_KEY_braille_dots_145678 0x10028f9 #define CLUTTER_KEY_braille_dots_245678 0x10028fa #define CLUTTER_KEY_braille_dots_1245678 0x10028fb #define CLUTTER_KEY_braille_dots_345678 0x10028fc #define CLUTTER_KEY_braille_dots_1345678 0x10028fd #define CLUTTER_KEY_braille_dots_2345678 0x10028fe #define CLUTTER_KEY_braille_dots_12345678 0x10028ff #define CLUTTER_KEY_Sinh_ng 0x1000d82 #define CLUTTER_KEY_Sinh_h2 0x1000d83 #define CLUTTER_KEY_Sinh_a 0x1000d85 #define CLUTTER_KEY_Sinh_aa 0x1000d86 #define CLUTTER_KEY_Sinh_ae 0x1000d87 #define CLUTTER_KEY_Sinh_aee 0x1000d88 #define CLUTTER_KEY_Sinh_i 0x1000d89 #define CLUTTER_KEY_Sinh_ii 0x1000d8a #define CLUTTER_KEY_Sinh_u 0x1000d8b #define CLUTTER_KEY_Sinh_uu 0x1000d8c #define CLUTTER_KEY_Sinh_ri 0x1000d8d #define CLUTTER_KEY_Sinh_rii 0x1000d8e #define CLUTTER_KEY_Sinh_lu 0x1000d8f #define CLUTTER_KEY_Sinh_luu 0x1000d90 #define CLUTTER_KEY_Sinh_e 0x1000d91 #define CLUTTER_KEY_Sinh_ee 0x1000d92 #define CLUTTER_KEY_Sinh_ai 0x1000d93 #define CLUTTER_KEY_Sinh_o 0x1000d94 #define CLUTTER_KEY_Sinh_oo 0x1000d95 #define CLUTTER_KEY_Sinh_au 0x1000d96 #define CLUTTER_KEY_Sinh_ka 0x1000d9a #define CLUTTER_KEY_Sinh_kha 0x1000d9b #define CLUTTER_KEY_Sinh_ga 0x1000d9c #define CLUTTER_KEY_Sinh_gha 0x1000d9d #define CLUTTER_KEY_Sinh_ng2 0x1000d9e #define CLUTTER_KEY_Sinh_nga 0x1000d9f #define CLUTTER_KEY_Sinh_ca 0x1000da0 #define CLUTTER_KEY_Sinh_cha 0x1000da1 #define CLUTTER_KEY_Sinh_ja 0x1000da2 #define CLUTTER_KEY_Sinh_jha 0x1000da3 #define CLUTTER_KEY_Sinh_nya 0x1000da4 #define CLUTTER_KEY_Sinh_jnya 0x1000da5 #define CLUTTER_KEY_Sinh_nja 0x1000da6 #define CLUTTER_KEY_Sinh_tta 0x1000da7 #define CLUTTER_KEY_Sinh_ttha 0x1000da8 #define CLUTTER_KEY_Sinh_dda 0x1000da9 #define CLUTTER_KEY_Sinh_ddha 0x1000daa #define CLUTTER_KEY_Sinh_nna 0x1000dab #define CLUTTER_KEY_Sinh_ndda 0x1000dac #define CLUTTER_KEY_Sinh_tha 0x1000dad #define CLUTTER_KEY_Sinh_thha 0x1000dae #define CLUTTER_KEY_Sinh_dha 0x1000daf #define CLUTTER_KEY_Sinh_dhha 0x1000db0 #define CLUTTER_KEY_Sinh_na 0x1000db1 #define CLUTTER_KEY_Sinh_ndha 0x1000db3 #define CLUTTER_KEY_Sinh_pa 0x1000db4 #define CLUTTER_KEY_Sinh_pha 0x1000db5 #define CLUTTER_KEY_Sinh_ba 0x1000db6 #define CLUTTER_KEY_Sinh_bha 0x1000db7 #define CLUTTER_KEY_Sinh_ma 0x1000db8 #define CLUTTER_KEY_Sinh_mba 0x1000db9 #define CLUTTER_KEY_Sinh_ya 0x1000dba #define CLUTTER_KEY_Sinh_ra 0x1000dbb #define CLUTTER_KEY_Sinh_la 0x1000dbd #define CLUTTER_KEY_Sinh_va 0x1000dc0 #define CLUTTER_KEY_Sinh_sha 0x1000dc1 #define CLUTTER_KEY_Sinh_ssha 0x1000dc2 #define CLUTTER_KEY_Sinh_sa 0x1000dc3 #define CLUTTER_KEY_Sinh_ha 0x1000dc4 #define CLUTTER_KEY_Sinh_lla 0x1000dc5 #define CLUTTER_KEY_Sinh_fa 0x1000dc6 #define CLUTTER_KEY_Sinh_al 0x1000dca #define CLUTTER_KEY_Sinh_aa2 0x1000dcf #define CLUTTER_KEY_Sinh_ae2 0x1000dd0 #define CLUTTER_KEY_Sinh_aee2 0x1000dd1 #define CLUTTER_KEY_Sinh_i2 0x1000dd2 #define CLUTTER_KEY_Sinh_ii2 0x1000dd3 #define CLUTTER_KEY_Sinh_u2 0x1000dd4 #define CLUTTER_KEY_Sinh_uu2 0x1000dd6 #define CLUTTER_KEY_Sinh_ru2 0x1000dd8 #define CLUTTER_KEY_Sinh_e2 0x1000dd9 #define CLUTTER_KEY_Sinh_ee2 0x1000dda #define CLUTTER_KEY_Sinh_ai2 0x1000ddb #define CLUTTER_KEY_Sinh_o2 0x1000ddc #define CLUTTER_KEY_Sinh_oo2 0x1000ddd #define CLUTTER_KEY_Sinh_au2 0x1000dde #define CLUTTER_KEY_Sinh_lu2 0x1000ddf #define CLUTTER_KEY_Sinh_ruu2 0x1000df2 #define CLUTTER_KEY_Sinh_luu2 0x1000df3 #define CLUTTER_KEY_Sinh_kunddaliya 0x1000df4 #define CLUTTER_KEY_ModeLock 0x1008ff01 #define CLUTTER_KEY_MonBrightnessUp 0x1008ff02 #define CLUTTER_KEY_MonBrightnessDown 0x1008ff03 #define CLUTTER_KEY_KbdLightOnOff 0x1008ff04 #define CLUTTER_KEY_KbdBrightnessUp 0x1008ff05 #define CLUTTER_KEY_KbdBrightnessDown 0x1008ff06 #define CLUTTER_KEY_Standby 0x1008ff10 #define CLUTTER_KEY_AudioLowerVolume 0x1008ff11 #define CLUTTER_KEY_AudioMute 0x1008ff12 #define CLUTTER_KEY_AudioRaiseVolume 0x1008ff13 #define CLUTTER_KEY_AudioPlay 0x1008ff14 #define CLUTTER_KEY_AudioStop 0x1008ff15 #define CLUTTER_KEY_AudioPrev 0x1008ff16 #define CLUTTER_KEY_AudioNext 0x1008ff17 #define CLUTTER_KEY_HomePage 0x1008ff18 #define CLUTTER_KEY_Mail 0x1008ff19 #define CLUTTER_KEY_Start 0x1008ff1a #define CLUTTER_KEY_Search 0x1008ff1b #define CLUTTER_KEY_AudioRecord 0x1008ff1c #define CLUTTER_KEY_Calculator 0x1008ff1d #define CLUTTER_KEY_Memo 0x1008ff1e #define CLUTTER_KEY_ToDoList 0x1008ff1f #define CLUTTER_KEY_Calendar 0x1008ff20 #define CLUTTER_KEY_PowerDown 0x1008ff21 #define CLUTTER_KEY_ContrastAdjust 0x1008ff22 #define CLUTTER_KEY_RockerUp 0x1008ff23 #define CLUTTER_KEY_RockerDown 0x1008ff24 #define CLUTTER_KEY_RockerEnter 0x1008ff25 #define CLUTTER_KEY_Back 0x1008ff26 #define CLUTTER_KEY_Forward 0x1008ff27 #define CLUTTER_KEY_Stop 0x1008ff28 #define CLUTTER_KEY_Refresh 0x1008ff29 #define CLUTTER_KEY_PowerOff 0x1008ff2a #define CLUTTER_KEY_WakeUp 0x1008ff2b #define CLUTTER_KEY_Eject 0x1008ff2c #define CLUTTER_KEY_ScreenSaver 0x1008ff2d #define CLUTTER_KEY_WWW 0x1008ff2e #define CLUTTER_KEY_Sleep 0x1008ff2f #define CLUTTER_KEY_Favorites 0x1008ff30 #define CLUTTER_KEY_AudioPause 0x1008ff31 #define CLUTTER_KEY_AudioMedia 0x1008ff32 #define CLUTTER_KEY_MyComputer 0x1008ff33 #define CLUTTER_KEY_VendorHome 0x1008ff34 #define CLUTTER_KEY_LightBulb 0x1008ff35 #define CLUTTER_KEY_Shop 0x1008ff36 #define CLUTTER_KEY_History 0x1008ff37 #define CLUTTER_KEY_OpenURL 0x1008ff38 #define CLUTTER_KEY_AddFavorite 0x1008ff39 #define CLUTTER_KEY_HotLinks 0x1008ff3a #define CLUTTER_KEY_BrightnessAdjust 0x1008ff3b #define CLUTTER_KEY_Finance 0x1008ff3c #define CLUTTER_KEY_Community 0x1008ff3d #define CLUTTER_KEY_AudioRewind 0x1008ff3e #define CLUTTER_KEY_BackForward 0x1008ff3f #define CLUTTER_KEY_Launch0 0x1008ff40 #define CLUTTER_KEY_Launch1 0x1008ff41 #define CLUTTER_KEY_Launch2 0x1008ff42 #define CLUTTER_KEY_Launch3 0x1008ff43 #define CLUTTER_KEY_Launch4 0x1008ff44 #define CLUTTER_KEY_Launch5 0x1008ff45 #define CLUTTER_KEY_Launch6 0x1008ff46 #define CLUTTER_KEY_Launch7 0x1008ff47 #define CLUTTER_KEY_Launch8 0x1008ff48 #define CLUTTER_KEY_Launch9 0x1008ff49 #define CLUTTER_KEY_LaunchA 0x1008ff4a #define CLUTTER_KEY_LaunchB 0x1008ff4b #define CLUTTER_KEY_LaunchC 0x1008ff4c #define CLUTTER_KEY_LaunchD 0x1008ff4d #define CLUTTER_KEY_LaunchE 0x1008ff4e #define CLUTTER_KEY_LaunchF 0x1008ff4f #define CLUTTER_KEY_ApplicationLeft 0x1008ff50 #define CLUTTER_KEY_ApplicationRight 0x1008ff51 #define CLUTTER_KEY_Book 0x1008ff52 #define CLUTTER_KEY_CD 0x1008ff53 #define CLUTTER_KEY_WindowClear 0x1008ff55 #define CLUTTER_KEY_Close 0x1008ff56 #define CLUTTER_KEY_Copy 0x1008ff57 #define CLUTTER_KEY_Cut 0x1008ff58 #define CLUTTER_KEY_Display 0x1008ff59 #define CLUTTER_KEY_DOS 0x1008ff5a #define CLUTTER_KEY_Documents 0x1008ff5b #define CLUTTER_KEY_Excel 0x1008ff5c #define CLUTTER_KEY_Explorer 0x1008ff5d #define CLUTTER_KEY_Game 0x1008ff5e #define CLUTTER_KEY_Go 0x1008ff5f #define CLUTTER_KEY_iTouch 0x1008ff60 #define CLUTTER_KEY_LogOff 0x1008ff61 #define CLUTTER_KEY_Market 0x1008ff62 #define CLUTTER_KEY_Meeting 0x1008ff63 #define CLUTTER_KEY_MenuKB 0x1008ff65 #define CLUTTER_KEY_MenuPB 0x1008ff66 #define CLUTTER_KEY_MySites 0x1008ff67 #define CLUTTER_KEY_New 0x1008ff68 #define CLUTTER_KEY_News 0x1008ff69 #define CLUTTER_KEY_OfficeHome 0x1008ff6a #define CLUTTER_KEY_Open 0x1008ff6b #define CLUTTER_KEY_Option 0x1008ff6c #define CLUTTER_KEY_Paste 0x1008ff6d #define CLUTTER_KEY_Phone 0x1008ff6e #define CLUTTER_KEY_Reply 0x1008ff72 #define CLUTTER_KEY_Reload 0x1008ff73 #define CLUTTER_KEY_RotateWindows 0x1008ff74 #define CLUTTER_KEY_RotationPB 0x1008ff75 #define CLUTTER_KEY_RotationKB 0x1008ff76 #define CLUTTER_KEY_Save 0x1008ff77 #define CLUTTER_KEY_ScrollUp 0x1008ff78 #define CLUTTER_KEY_ScrollDown 0x1008ff79 #define CLUTTER_KEY_ScrollClick 0x1008ff7a #define CLUTTER_KEY_Send 0x1008ff7b #define CLUTTER_KEY_Spell 0x1008ff7c #define CLUTTER_KEY_SplitScreen 0x1008ff7d #define CLUTTER_KEY_Support 0x1008ff7e #define CLUTTER_KEY_TaskPane 0x1008ff7f #define CLUTTER_KEY_Terminal 0x1008ff80 #define CLUTTER_KEY_Tools 0x1008ff81 #define CLUTTER_KEY_Travel 0x1008ff82 #define CLUTTER_KEY_UserPB 0x1008ff84 #define CLUTTER_KEY_User1KB 0x1008ff85 #define CLUTTER_KEY_User2KB 0x1008ff86 #define CLUTTER_KEY_Video 0x1008ff87 #define CLUTTER_KEY_WheelButton 0x1008ff88 #define CLUTTER_KEY_Word 0x1008ff89 #define CLUTTER_KEY_Xfer 0x1008ff8a #define CLUTTER_KEY_ZoomIn 0x1008ff8b #define CLUTTER_KEY_ZoomOut 0x1008ff8c #define CLUTTER_KEY_Away 0x1008ff8d #define CLUTTER_KEY_Messenger 0x1008ff8e #define CLUTTER_KEY_WebCam 0x1008ff8f #define CLUTTER_KEY_MailForward 0x1008ff90 #define CLUTTER_KEY_Pictures 0x1008ff91 #define CLUTTER_KEY_Music 0x1008ff92 #define CLUTTER_KEY_Battery 0x1008ff93 #define CLUTTER_KEY_Bluetooth 0x1008ff94 #define CLUTTER_KEY_WLAN 0x1008ff95 #define CLUTTER_KEY_UWB 0x1008ff96 #define CLUTTER_KEY_AudioForward 0x1008ff97 #define CLUTTER_KEY_AudioRepeat 0x1008ff98 #define CLUTTER_KEY_AudioRandomPlay 0x1008ff99 #define CLUTTER_KEY_Subtitle 0x1008ff9a #define CLUTTER_KEY_AudioCycleTrack 0x1008ff9b #define CLUTTER_KEY_CycleAngle 0x1008ff9c #define CLUTTER_KEY_FrameBack 0x1008ff9d #define CLUTTER_KEY_FrameForward 0x1008ff9e #define CLUTTER_KEY_Time 0x1008ff9f #define CLUTTER_KEY_SelectButton 0x1008ffa0 #define CLUTTER_KEY_View 0x1008ffa1 #define CLUTTER_KEY_TopMenu 0x1008ffa2 #define CLUTTER_KEY_Red 0x1008ffa3 #define CLUTTER_KEY_Green 0x1008ffa4 #define CLUTTER_KEY_Yellow 0x1008ffa5 #define CLUTTER_KEY_Blue 0x1008ffa6 #define CLUTTER_KEY_Suspend 0x1008ffa7 #define CLUTTER_KEY_Hibernate 0x1008ffa8 #define CLUTTER_KEY_TouchpadToggle 0x1008ffa9 #define CLUTTER_KEY_TouchpadOn 0x1008ffb0 #define CLUTTER_KEY_TouchpadOff 0x1008ffb1 #define CLUTTER_KEY_AudioMicMute 0x1008ffb2 #define CLUTTER_KEY_Switch_VT_1 0x1008fe01 #define CLUTTER_KEY_Switch_VT_2 0x1008fe02 #define CLUTTER_KEY_Switch_VT_3 0x1008fe03 #define CLUTTER_KEY_Switch_VT_4 0x1008fe04 #define CLUTTER_KEY_Switch_VT_5 0x1008fe05 #define CLUTTER_KEY_Switch_VT_6 0x1008fe06 #define CLUTTER_KEY_Switch_VT_7 0x1008fe07 #define CLUTTER_KEY_Switch_VT_8 0x1008fe08 #define CLUTTER_KEY_Switch_VT_9 0x1008fe09 #define CLUTTER_KEY_Switch_VT_10 0x1008fe0a #define CLUTTER_KEY_Switch_VT_11 0x1008fe0b #define CLUTTER_KEY_Switch_VT_12 0x1008fe0c #define CLUTTER_KEY_Ungrab 0x1008fe20 #define CLUTTER_KEY_ClearGrab 0x1008fe21 #define CLUTTER_KEY_Next_VMode 0x1008fe22 #define CLUTTER_KEY_Prev_VMode 0x1008fe23 #define CLUTTER_KEY_LogWindowTree 0x1008fe24 #define CLUTTER_KEY_LogGrabInfo 0x1008fe25 #endif /* __CLUTTER_KEYSYMS_H__ */ muffin-5.2.1/clutter/clutter/clutter-image.c0000664000175000017500000003176714211404421021224 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive image' library. * * Copyright (C) 2012 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ /** * SECTION:clutter-image * @Title: ClutterImage * @Short_Description: Image data content * * #ClutterImage is a #ClutterContent implementation that displays * image data inside a #ClutterActor. * * See [image.c](https://git.gnome.org/browse/clutter/tree/examples/image-content.c?h=clutter-1.18) * for an example of how to use #ClutterImage. * * #ClutterImage is available since Clutter 1.10. */ #ifdef HAVE_CONFIG_H #include "clutter-build-config.h" #endif #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-image.h" #include "clutter-actor-private.h" #include "clutter-color.h" #include "clutter-content-private.h" #include "clutter-debug.h" #include "clutter-paint-node.h" #include "clutter-paint-nodes.h" #include "clutter-private.h" struct _ClutterImagePrivate { CoglTexture *texture; }; static void clutter_content_iface_init (ClutterContentIface *iface); G_DEFINE_TYPE_WITH_CODE (ClutterImage, clutter_image, G_TYPE_OBJECT, G_ADD_PRIVATE (ClutterImage) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, clutter_content_iface_init)) GQuark clutter_image_error_quark (void) { return g_quark_from_static_string ("clutter-image-error-quark"); } static void clutter_image_finalize (GObject *gobject) { ClutterImagePrivate *priv = CLUTTER_IMAGE (gobject)->priv; if (priv->texture != NULL) { cogl_object_unref (priv->texture); priv->texture = NULL; } G_OBJECT_CLASS (clutter_image_parent_class)->finalize (gobject); } static void clutter_image_class_init (ClutterImageClass *klass) { G_OBJECT_CLASS (klass)->finalize = clutter_image_finalize; } static void clutter_image_init (ClutterImage *self) { self->priv = clutter_image_get_instance_private (self); } static void clutter_image_paint_content (ClutterContent *content, ClutterActor *actor, ClutterPaintNode *root) { ClutterImagePrivate *priv = CLUTTER_IMAGE (content)->priv; ClutterPaintNode *node; if (priv->texture == NULL) return; node = clutter_actor_create_texture_paint_node (actor, priv->texture); clutter_paint_node_set_name (node, "Image Content"); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); } static gboolean clutter_image_get_preferred_size (ClutterContent *content, gfloat *width, gfloat *height) { ClutterImagePrivate *priv = CLUTTER_IMAGE (content)->priv; if (priv->texture == NULL) return FALSE; if (width != NULL) *width = cogl_texture_get_width (priv->texture); if (height != NULL) *height = cogl_texture_get_height (priv->texture); return TRUE; } static void clutter_content_iface_init (ClutterContentIface *iface) { iface->get_preferred_size = clutter_image_get_preferred_size; iface->paint_content = clutter_image_paint_content; } /** * clutter_image_new: * * Creates a new #ClutterImage instance. * * Return value: (transfer full): the newly created #ClutterImage instance. * Use g_object_unref() when done. * * Since: 1.10 */ ClutterContent * clutter_image_new (void) { return g_object_new (CLUTTER_TYPE_IMAGE, NULL); } /** * clutter_image_set_data: * @image: a #ClutterImage * @data: (array): the image data, as an array of bytes * @pixel_format: the Cogl pixel format of the image data * @width: the width of the image data * @height: the height of the image data * @row_stride: the length of each row inside @data * @error: return location for a #GError, or %NULL * * Sets the image data to be displayed by @image. * * If the image data was successfully loaded, the @image will be invalidated. * * In case of error, the @error value will be set, and this function will * return %FALSE. * * The image data is copied in texture memory. * * The image data is expected to be a linear array of RGBA or RGB pixel data; * how to retrieve that data is left to platform specific image loaders. For * instance, if you use the GdkPixbuf library: * * |[ * ClutterContent *image = clutter_image_new (); * * GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL); * * clutter_image_set_data (CLUTTER_IMAGE (image), * gdk_pixbuf_get_pixels (pixbuf), * gdk_pixbuf_get_has_alpha (pixbuf) * ? COGL_PIXEL_FORMAT_RGBA_8888 * : COGL_PIXEL_FORMAT_RGB_888, * gdk_pixbuf_get_width (pixbuf), * gdk_pixbuf_get_height (pixbuf), * gdk_pixbuf_get_rowstride (pixbuf), * &error); * * g_object_unref (pixbuf); * ]| * * Return value: %TRUE if the image data was successfully loaded, * and %FALSE otherwise. * * Since: 1.10 */ gboolean clutter_image_set_data (ClutterImage *image, const guint8 *data, CoglPixelFormat pixel_format, guint width, guint height, guint row_stride, GError **error) { ClutterImagePrivate *priv; CoglTextureFlags flags; g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE); g_return_val_if_fail (data != NULL, FALSE); priv = image->priv; if (priv->texture != NULL) cogl_object_unref (priv->texture); flags = COGL_TEXTURE_NONE; if (width >= 512 && height >= 512) flags |= COGL_TEXTURE_NO_ATLAS; priv->texture = cogl_texture_new_from_data (width, height, flags, pixel_format, COGL_PIXEL_FORMAT_ANY, row_stride, data); if (priv->texture == NULL) { g_set_error_literal (error, CLUTTER_IMAGE_ERROR, CLUTTER_IMAGE_ERROR_INVALID_DATA, _("Unable to load image data")); return FALSE; } clutter_content_invalidate (CLUTTER_CONTENT (image)); return TRUE; } /** * clutter_image_set_bytes: * @image: a #ClutterImage * @data: the image data, as a #GBytes * @pixel_format: the Cogl pixel format of the image data * @width: the width of the image data * @height: the height of the image data * @row_stride: the length of each row inside @data * @error: return location for a #GError, or %NULL * * Sets the image data stored inside a #GBytes to be displayed by @image. * * If the image data was successfully loaded, the @image will be invalidated. * * In case of error, the @error value will be set, and this function will * return %FALSE. * * The image data contained inside the #GBytes is copied in texture memory, * and no additional reference is acquired on the @data. * * Return value: %TRUE if the image data was successfully loaded, * and %FALSE otherwise. * * Since: 1.12 */ gboolean clutter_image_set_bytes (ClutterImage *image, GBytes *data, CoglPixelFormat pixel_format, guint width, guint height, guint row_stride, GError **error) { ClutterImagePrivate *priv; CoglTextureFlags flags; g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE); g_return_val_if_fail (data != NULL, FALSE); priv = image->priv; if (priv->texture != NULL) cogl_object_unref (priv->texture); flags = COGL_TEXTURE_NONE; if (width >= 512 && height >= 512) flags |= COGL_TEXTURE_NO_ATLAS; priv->texture = cogl_texture_new_from_data (width, height, flags, pixel_format, COGL_PIXEL_FORMAT_ANY, row_stride, g_bytes_get_data (data, NULL)); if (priv->texture == NULL) { g_set_error_literal (error, CLUTTER_IMAGE_ERROR, CLUTTER_IMAGE_ERROR_INVALID_DATA, _("Unable to load image data")); return FALSE; } clutter_content_invalidate (CLUTTER_CONTENT (image)); return TRUE; } /** * clutter_image_set_area: * @image: a #ClutterImage * @data: (array): the image data, as an array of bytes * @pixel_format: the Cogl pixel format of the image data * @rect: a rectangle indicating the area that should be set * @row_stride: the length of each row inside @data * @error: return location for a #GError, or %NULL * * Sets the image data to be display by @image, using @rect to indicate * the position and size of the image data to be set. * * If the @image does not have any image data set when this function is * called, a new texture will be created with the size of the width and * height of the rectangle, i.e. calling this function on a newly created * #ClutterImage will be the equivalent of calling clutter_image_set_data(). * * If the image data was successfully loaded, the @image will be invalidated. * * In case of error, the @error value will be set, and this function will * return %FALSE. * * The image data is copied in texture memory. * * Return value: %TRUE if the image data was successfully loaded, * and %FALSE otherwise. * * Since: 1.10 */ gboolean clutter_image_set_area (ClutterImage *image, const guint8 *data, CoglPixelFormat pixel_format, const cairo_rectangle_int_t *area, guint row_stride, GError **error) { ClutterImagePrivate *priv; g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE); g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (area != NULL, FALSE); priv = image->priv; if (priv->texture == NULL) { CoglTextureFlags flags = COGL_TEXTURE_NONE; if (area->width >= 512 && area->height >= 512) flags |= COGL_TEXTURE_NO_ATLAS; priv->texture = cogl_texture_new_from_data (area->width, area->height, flags, pixel_format, COGL_PIXEL_FORMAT_ANY, row_stride, data); } else { gboolean res; res = cogl_texture_set_region (priv->texture, 0, 0, area->x, area->y, area->width, area->height, area->width, area->height, pixel_format, row_stride, data); if (!res) { cogl_object_unref (priv->texture); priv->texture = NULL; } } if (priv->texture == NULL) { g_set_error_literal (error, CLUTTER_IMAGE_ERROR, CLUTTER_IMAGE_ERROR_INVALID_DATA, _("Unable to load image data")); return FALSE; } clutter_content_invalidate (CLUTTER_CONTENT (image)); return TRUE; } /** * clutter_image_get_texture: * @image: a #ClutterImage * * Retrieves a pointer to the Cogl texture used by @image. * * If you change the contents of the returned Cogl texture you will need * to manually invalidate the @image with clutter_content_invalidate() * in order to update the actors using @image as their content. * * Return value: (transfer none): a pointer to the Cogl texture, or %NULL * * Since: 1.10 * Stability: unstable */ CoglTexture * clutter_image_get_texture (ClutterImage *image) { g_return_val_if_fail (CLUTTER_IS_IMAGE (image), NULL); return image->priv->texture; } muffin-5.2.1/clutter/clutter/clutter-box-layout.h0000664000175000017500000002045714211404421022244 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2009 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi * * Based on the NBTK NbtkBoxLayout actor by: * Thomas Wood */ #ifndef __CLUTTER_BOX_LAYOUT_H__ #define __CLUTTER_BOX_LAYOUT_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_BOX_LAYOUT (clutter_box_layout_get_type ()) #define CLUTTER_BOX_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX_LAYOUT, ClutterBoxLayout)) #define CLUTTER_IS_BOX_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX_LAYOUT)) #define CLUTTER_BOX_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BOX_LAYOUT, ClutterBoxLayoutClass)) #define CLUTTER_IS_BOX_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BOX_LAYOUT)) #define CLUTTER_BOX_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BOX_LAYOUT, ClutterBoxLayoutClass)) typedef struct _ClutterBoxLayout ClutterBoxLayout; typedef struct _ClutterBoxLayoutPrivate ClutterBoxLayoutPrivate; typedef struct _ClutterBoxLayoutClass ClutterBoxLayoutClass; /** * ClutterBoxLayout: * * The #ClutterBoxLayout structure contains only private data * and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterBoxLayout { /*< private >*/ ClutterLayoutManager parent_instance; ClutterBoxLayoutPrivate *priv; }; /** * ClutterBoxLayoutClass: * * The #ClutterBoxLayoutClass structure contains only private * data and should be accessed using the provided API * * Since: 1.2 */ struct _ClutterBoxLayoutClass { /*< private >*/ ClutterLayoutManagerClass parent_class; }; CLUTTER_AVAILABLE_IN_1_2 GType clutter_box_layout_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_2 ClutterLayoutManager * clutter_box_layout_new (void); CLUTTER_AVAILABLE_IN_1_12 void clutter_box_layout_set_orientation (ClutterBoxLayout *layout, ClutterOrientation orientation); CLUTTER_AVAILABLE_IN_1_12 ClutterOrientation clutter_box_layout_get_orientation (ClutterBoxLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_box_layout_set_spacing (ClutterBoxLayout *layout, guint spacing); CLUTTER_AVAILABLE_IN_1_2 guint clutter_box_layout_get_spacing (ClutterBoxLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_box_layout_set_homogeneous (ClutterBoxLayout *layout, gboolean homogeneous); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_box_layout_get_homogeneous (ClutterBoxLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_box_layout_set_pack_start (ClutterBoxLayout *layout, gboolean pack_start); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_box_layout_get_pack_start (ClutterBoxLayout *layout); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_box_layout_set_orientation) void clutter_box_layout_set_vertical (ClutterBoxLayout *layout, gboolean vertical); CLUTTER_DEPRECATED_IN_1_12_FOR(clutter_box_layout_get_orientation) gboolean clutter_box_layout_get_vertical (ClutterBoxLayout *layout); CLUTTER_AVAILABLE_IN_1_2 void clutter_box_layout_pack (ClutterBoxLayout *layout, ClutterActor *actor, gboolean expand, gboolean x_fill, gboolean y_fill, ClutterBoxAlignment x_align, ClutterBoxAlignment y_align); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_set_alignment (ClutterBoxLayout *layout, ClutterActor *actor, ClutterBoxAlignment x_align, ClutterBoxAlignment y_align); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_get_alignment (ClutterBoxLayout *layout, ClutterActor *actor, ClutterBoxAlignment *x_align, ClutterBoxAlignment *y_align); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_set_fill (ClutterBoxLayout *layout, ClutterActor *actor, gboolean x_fill, gboolean y_fill); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_get_fill (ClutterBoxLayout *layout, ClutterActor *actor, gboolean *x_fill, gboolean *y_fill); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_set_expand (ClutterBoxLayout *layout, ClutterActor *actor, gboolean expand); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_box_layout_get_expand (ClutterBoxLayout *layout, ClutterActor *actor); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_set_use_animations (ClutterBoxLayout *layout, gboolean animate); CLUTTER_DEPRECATED_IN_1_12 gboolean clutter_box_layout_get_use_animations (ClutterBoxLayout *layout); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_set_easing_mode (ClutterBoxLayout *layout, gulong mode); CLUTTER_DEPRECATED_IN_1_12 gulong clutter_box_layout_get_easing_mode (ClutterBoxLayout *layout); CLUTTER_DEPRECATED_IN_1_12 void clutter_box_layout_set_easing_duration (ClutterBoxLayout *layout, guint msecs); CLUTTER_DEPRECATED_IN_1_12 guint clutter_box_layout_get_easing_duration (ClutterBoxLayout *layout); G_END_DECLS #endif /* __CLUTTER_BOX_LAYOUT_H__ */ muffin-5.2.1/clutter/clutter/clutter-actor.c0000664000175000017500000235554614211404421021260 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd * Copyright (C) 2009, 2010, 2011, 2012 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, see . */ /** * SECTION:clutter-actor * @short_description: The basic element of the scene graph * * The ClutterActor class is the basic element of the scene graph in Clutter, * and it encapsulates the position, size, and transformations of a node in * the graph. * * ## Actor transformations ## {#clutter-actor-transformations} * * Each actor can be transformed using methods like clutter_actor_set_scale() * or clutter_actor_set_rotation(). The order in which the transformations are * applied is decided by Clutter and it is the following: * * 1. translation by the origin of the #ClutterActor:allocation property * 2. translation by the actor's #ClutterActor:z-position property * 3. translation by the actor's #ClutterActor:pivot-point property * 4. scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors * 5. rotation around the #ClutterActor:rotation-angle-x and #ClutterActor:rotation-center-x * 6. rotation around the #ClutterActor:rotation-angle-y and #ClutterActor:rotation-center-y * 7. rotation around the #ClutterActor:rotation-angle-z and #ClutterActor:rotation-center-z * 8. negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point. * 9. negative translation by the actor's #ClutterActor:pivot-point * * ## Modifying an actor's geometry ## {#clutter-actor-geometry} * * Each actor has a bounding box, called #ClutterActor:allocation * which is either set by its parent or explicitly through the * clutter_actor_set_position() and clutter_actor_set_size() methods. * Each actor also has an implicit preferred size. * * An actor’s preferred size can be defined by any subclass by * overriding the #ClutterActorClass.get_preferred_width() and the * #ClutterActorClass.get_preferred_height() virtual functions, or it can * be explicitly set by using clutter_actor_set_width() and * clutter_actor_set_height(). * * An actor’s position can be set explicitly by using * clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are * relative to the origin of the actor’s parent. * * ## Managing actor children ## {#clutter-actor-children} * * Each actor can have multiple children, by calling * clutter_actor_add_child() to add a new child actor, and * clutter_actor_remove_child() to remove an existing child. #ClutterActor * will hold a reference on each child actor, which will be released when * the child is removed from its parent, or destroyed using * clutter_actor_destroy(). * * |[ * ClutterActor *actor = clutter_actor_new (); * * // set the bounding box of the actor * clutter_actor_set_position (actor, 0, 0); * clutter_actor_set_size (actor, 480, 640); * * // set the background color of the actor * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange); * * // set the bounding box of the child, relative to the parent * ClutterActor *child = clutter_actor_new (); * clutter_actor_set_position (child, 20, 20); * clutter_actor_set_size (child, 80, 240); * * // set the background color of the child * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue); * * // add the child to the actor * clutter_actor_add_child (actor, child); * ]| * * Children can be inserted at a given index, or above and below * another child actor. The order of insertion determines the order of the * children when iterating over them. Iterating over children is performed * by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(), * clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is * also possible to retrieve a list of children by using * clutter_actor_get_children(), as well as retrieving a specific child at a * given index by using clutter_actor_get_child_at_index(). * * If you need to track additions of children to a #ClutterActor, use * the #ClutterContainer::actor-added signal; similarly, to track removals * of children from a ClutterActor, use the #ClutterContainer::actor-removed * signal. * * See [basic-actor.c](https://git.gnome.org/browse/clutter/tree/examples/basic-actor.c?h=clutter-1.18). * * ## Painting an actor ## {#clutter-actor-painting} * * There are three ways to paint an actor: * * - set a delegate #ClutterContent as the value for the #ClutterActor:content property of the actor * - subclass #ClutterActor and override the #ClutterActorClass.paint_node() virtual function * - subclass #ClutterActor and override the #ClutterActorClass.paint() virtual function. * * A #ClutterContent is a delegate object that takes over the painting * operations of one, or more actors. The #ClutterContent painting will * be performed on top of the #ClutterActor:background-color of the actor, * and before calling the actor's own implementation of the * #ClutterActorClass.paint_node() virtual function. * * |[ * ClutterActor *actor = clutter_actor_new (); * * // set the bounding box * clutter_actor_set_position (actor, 50, 50); * clutter_actor_set_size (actor, 100, 100); * * // set the content; the image_content variable is set elsewhere * clutter_actor_set_content (actor, image_content); * ]| * * The #ClutterActorClass.paint_node() virtual function is invoked whenever * an actor needs to be painted. The implementation of the virtual function * must only paint the contents of the actor itself, and not the contents of * its children, if the actor has any. * * The #ClutterPaintNode passed to the virtual function is the local root of * the render tree; any node added to it will be rendered at the correct * position, as defined by the actor's #ClutterActor:allocation. * * |[ * static void * my_actor_paint_node (ClutterActor *actor, * ClutterPaintNode *root) * { * ClutterPaintNode *node; * ClutterActorBox box; * * // where the content of the actor should be painted * clutter_actor_get_allocation_box (actor, &box); * * // the cogl_texture variable is set elsewhere * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White, * CLUTTER_SCALING_FILTER_TRILINEAR, * CLUTTER_SCALING_FILTER_LINEAR); * * // paint the content of the node using the allocation * clutter_paint_node_add_rectangle (node, &box); * * // add the node, and transfer ownership * clutter_paint_node_add_child (root, node); * clutter_paint_node_unref (node); * } * * The #ClutterActorClass.paint() virtual function is invoked when the * #ClutterActor::paint signal is emitted, and after the other signal * handlers have been invoked. Overriding the paint virtual function * gives total control to the paint sequence of the actor itself, * including the children of the actor, if any. * * It is strongly discouraged to override the #ClutterActorClass.paint() * virtual function, as well as connecting to the #ClutterActor::paint * signal. These hooks into the paint sequence are considered legacy, and * will be removed when the Clutter API changes. * * ## Handling events on an actor ## {#clutter-actor-event-handling} * * A #ClutterActor can receive and handle input device events, for * instance pointer events and key events, as long as its * #ClutterActor:reactive property is set to %TRUE. * * Once an actor has been determined to be the source of an event, * Clutter will traverse the scene graph from the top-level actor towards the * event source, emitting the #ClutterActor::captured-event signal on each * ancestor until it reaches the source; this phase is also called * the "capture" phase. If the event propagation was not stopped, the graph * is walked backwards, from the source actor to the top-level, and the * #ClutterActor::event signal is emitted, alongside eventual event-specific * signals like #ClutterActor::button-press-event or #ClutterActor::motion-event; * this phase is also called the "bubble" phase. * * At any point of the signal emission, signal handlers can stop the propagation * through the scene graph by returning %CLUTTER_EVENT_STOP; otherwise, they can * continue the propagation by returning %CLUTTER_EVENT_PROPAGATE. * * ## Animation ## {#clutter-actor-animation} * * Animation is a core concept of modern user interfaces; Clutter provides a * complete and powerful animation framework that automatically tweens the * actor's state without requiring direct, frame by frame manipulation from * your application code. You have two models at your disposal: * * - an implicit animation model * - an explicit animation model * * The implicit animation model of Clutter assumes that all the * changes in an actor state should be gradual and asynchronous; Clutter * will automatically transition an actor's property change between the * current state and the desired one without manual intervention, if the * property is defined to be animatable in its documentation. * * By default, in the 1.0 API series, the transition happens with a duration * of zero milliseconds, and the implicit animation is an opt in feature to * retain backwards compatibility. * * Implicit animations depend on the current easing state; in order to use * the default easing state for an actor you should call the * clutter_actor_save_easing_state() function: * * |[ * // assume that the actor is currently positioned at (100, 100) * * // store the current easing state and reset the new easing state to * // its default values * clutter_actor_save_easing_state (actor); * * // change the actor's position * clutter_actor_set_position (actor, 500, 500); * * // restore the previously saved easing state * clutter_actor_restore_easing_state (actor); * ]| * * The example above will trigger an implicit animation of the * actor between its current position to a new position. * * Implicit animations use a default duration of 250 milliseconds, * and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call * clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration() * after changing the easing state of the actor. * * It is possible to animate multiple properties of an actor * at the same time, and you can animate multiple actors at the same * time as well, for instance: * * |[ * clutter_actor_save_easing_state (actor); * * // animate the actor's opacity and depth * clutter_actor_set_opacity (actor, 0); * clutter_actor_set_depth (actor, -100); * * clutter_actor_restore_easing_state (actor); * * clutter_actor_save_easing_state (another_actor); * * // animate another actor's opacity * clutter_actor_set_opacity (another_actor, 255); * clutter_actor_set_depth (another_actor, 100); * * clutter_actor_restore_easing_state (another_actor); * ]| * * Changing the easing state will affect all the following property * transitions, but will not affect existing transitions. * * It is important to note that if you modify the state on an * animatable property while a transition is in flight, the transition's * final value will be updated, as well as its duration and progress * mode by using the current easing state; for instance, in the following * example: * * |[ * clutter_actor_save_easing_state (actor); * clutter_actor_set_easing_duration (actor, 1000); * clutter_actor_set_x (actor, 200); * clutter_actor_restore_easing_state (actor); * * clutter_actor_save_easing_state (actor); * clutter_actor_set_easing_duration (actor, 500); * clutter_actor_set_x (actor, 100); * clutter_actor_restore_easing_state (actor); * ]| * * the first call to clutter_actor_set_x() will begin a transition * of the #ClutterActor:x property from the current value to the value of * 200 over a duration of one second; the second call to clutter_actor_set_x() * will change the transition's final value to 100 and the duration to 500 * milliseconds. * * It is possible to receive a notification of the completion of an * implicit transition by using the #ClutterActor::transition-stopped * signal, decorated with the name of the property. In case you want to * know when all the currently in flight transitions are complete, use * the #ClutterActor::transitions-completed signal instead. * * It is possible to retrieve the #ClutterTransition used by the * animatable properties by using clutter_actor_get_transition() and using * the property name as the transition name. * * The explicit animation model supported by Clutter requires that * you create a #ClutterTransition object, and optionally set the initial * and final values. The transition will not start unless you add it to the * #ClutterActor. * * |[ * ClutterTransition *transition; * * transition = clutter_property_transition_new ("opacity"); * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000); * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2); * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); * clutter_transition_set_from (transition, G_TYPE_UINT, 255); * clutter_transition_set_to (transition, G_TYPE_UINT, 0); * * clutter_actor_add_transition (actor, "animate-opacity", transition); * ]| * * The example above will animate the #ClutterActor:opacity property * of an actor between fully opaque and fully transparent, and back, over * a span of 3 seconds. The animation does not begin until it is added to * the actor. * * The explicit animation API applies to all #GObject properties, * as well as the custom properties defined through the #ClutterAnimatable * interface, regardless of whether they are defined as implicitly * animatable or not. * * The explicit animation API should also be used when using custom * animatable properties for #ClutterAction, #ClutterConstraint, and * #ClutterEffect instances associated to an actor; see the section on * custom animatable properties below for an example. * * Finally, explicit animations are useful for creating animations * that run continuously, for instance: * * |[ * // this animation will pulse the actor's opacity continuously * ClutterTransition *transition; * ClutterInterval *interval; * * transition = clutter_property_transition_new ("opacity"); * * // we want to animate the opacity between 0 and 255 * clutter_transition_set_from (transition, G_TYPE_UINT, 0); * clutter_transition_set_to (transition, G_TYPE_UINT, 255); * * // over a one second duration, running an infinite amount of times * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000); * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1); * * // we want to fade in and out, so we need to auto-reverse the transition * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); * * // and we want to use an easing function that eases both in and out * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition), * CLUTTER_EASE_IN_OUT_CUBIC); * * // add the transition to the desired actor to start it * clutter_actor_add_transition (actor, "opacityAnimation", transition); * ]| * * ## Implementing an actor ## {#clutter-actor-implementing} * * Careful consideration should be given when deciding to implement * a #ClutterActor sub-class. It is generally recommended to implement a * sub-class of #ClutterActor only for actors that should be used as leaf * nodes of a scene graph. * * If your actor should be painted in a custom way, you should * override the #ClutterActor::paint signal class handler. You can either * opt to chain up to the parent class implementation or decide to fully * override the default paint implementation; Clutter will set up the * transformations and clip regions prior to emitting the #ClutterActor::paint * signal. * * By overriding the #ClutterActorClass.get_preferred_width() and * #ClutterActorClass.get_preferred_height() virtual functions it is * possible to change or provide the preferred size of an actor; similarly, * by overriding the #ClutterActorClass.allocate() virtual function it is * possible to control the layout of the children of an actor. Make sure to * always chain up to the parent implementation of the * #ClutterActorClass.allocate() virtual function. * * In general, it is strongly encouraged to use delegation and composition * instead of direct subclassing. * * ## ClutterActor custom properties for ClutterScript ## {#clutter-actor-custom-script} * * #ClutterActor defines a custom "rotation" property which allows a short-hand * description of the rotations to be applied to an actor. * * The syntax of the "rotation" property is the following: * * |[ * "rotation" : [ { "" : [ , [ ] ] } ] * ]| * * where: * * - axis is the name of an enumeration value of type #ClutterRotateAxis * - angle is a floating point value representing the rotation angle on the given axis in degrees * - center-point is an optional array, and if present it must contain the center of rotation as described by two coordinates: * - Y and Z for "x-axis" * - X and Z for "y-axis" * - X and Y for "z-axis". * * #ClutterActor also defines a scriptable "margin" property which follows the CSS "margin" shorthand. * * |[ * // 4 values * "margin" : [ top, right, bottom, left ] * // 3 values * "margin" : [ top, left/right, bottom ] * // 2 values * "margin" : [ top/bottom, left/right ] * // 1 value * "margin" : [ top/right/bottom/left ] * ]| * * #ClutterActor will also parse every positional and dimensional * property defined as a string through clutter_units_from_string(); you * should read the documentation for the #ClutterUnits parser format for * the valid units and syntax. * * ## Custom animatable properties * * #ClutterActor allows accessing properties of #ClutterAction, * #ClutterEffect, and #ClutterConstraint instances associated to an actor * instance for animation purposes. * * In order to access a specific #ClutterAction or a #ClutterConstraint * property it is necessary to set the #ClutterActorMeta:name property on the * given action or constraint. * * The property can be accessed using the following syntax: * * |[ * @
.. * ]| * * - the initial `@` is mandatory * - the `section` fragment can be one between "actions", "constraints" and "effects" * - the `meta-name` fragment is the name of the action, effect, or constraint, as * specified by the #ClutterActorMeta:name property of #ClutterActorMeta * - the `property-name` fragment is the name of the action, effect, or constraint * property to be animated. * * The example below animates a #ClutterBindConstraint applied to an actor * using an explicit transition. The `rect` actor has a binding constraint * on the `origin` actor, and in its initial state is overlapping the actor * to which is bound to. * * |[ * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0); * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x"); * clutter_actor_add_constraint (rect, constraint); * * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0); * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y"); * clutter_actor_add_constraint (rect, constraint); * * clutter_actor_set_reactive (origin, TRUE); * * g_signal_connect (origin, "button-press-event", * G_CALLBACK (on_button_press), * rect); * ]| * * On button press, the rectangle "slides" from behind the actor to * which is bound to, using the #ClutterBindConstraint:offset property to * achieve the effect: * * |[ * gboolean * on_button_press (ClutterActor *origin, * ClutterEvent *event, * ClutterActor *rect) * { * ClutterTransition *transition; * * // the offset that we want to apply; this will make the actor * // slide in from behind the origin and rest at the right of * // the origin, plus a padding value * float new_offset = clutter_actor_get_width (origin) + h_padding; * * // the property we wish to animate; the "@constraints" section * // tells Clutter to check inside the constraints associated * // with the actor; the "bind-x" section is the name of the * // constraint; and the "offset" is the name of the property * // on the constraint * const char *prop = "@constraints.bind-x.offset"; * * // create a new transition for the given property * transition = clutter_property_transition_new (prop); * * // set the easing mode and duration * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition), * CLUTTER_EASE_OUT_CUBIC); * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500); * * // create the interval with the initial and final values * clutter_transition_set_from (transition, G_TYPE_FLOAT, 0.f); * clutter_transition_set_to (transition, G_TYPE_FLOAT, new_offset); * * // add the transition to the actor; this causes the animation * // to start. the name "offsetAnimation" can be used to retrieve * // the transition later * clutter_actor_add_transition (rect, "offsetAnimation", transition); * * // we handled the event * return CLUTTER_EVENT_STOP; * } * ]| */ /** * CLUTTER_ACTOR_IS_MAPPED: * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set. * * The mapped state is set when the actor is visible and all its parents up * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped. * * This check can be used to see if an actor is going to be painted, as only * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted. * * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should * not be checked directly; instead, the recommended usage is to connect a * handler on the #GObject::notify signal for the #ClutterActor:mapped * property of #ClutterActor, and check the presence of * the %CLUTTER_ACTOR_MAPPED flag on state changes. * * It is also important to note that Clutter may delay the changes of * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific * limitations, or during the reparenting of an actor, to optimize * unnecessary (and potentially expensive) state changes. * * Since: 0.2 * * Deprecated: 1.24: Use clutter_actor_is_mapped() or the #ClutterActor:mapped * property instead of this macro. */ /** * CLUTTER_ACTOR_IS_REALIZED: * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set. * * The realized state has an actor-dependant interpretation. If an * actor wants to delay allocating resources until it is attached to a * stage, it may use the realize state to do so. However it is * perfectly acceptable for an actor to allocate Cogl resources before * being realized because there is only one drawing context used by Clutter * so any resources will work on any stage. If an actor is mapped it * must also be realized, but an actor can be realized and unmapped * (this is so hiding an actor temporarily doesn't do an expensive * unrealize/realize). * * To be realized an actor must be inside a stage, and all its parents * must be realized. * * Since: 0.2 * * Deprecated: 1.24: Use clutter_actor_is_realized() or the #ClutterActor:realized * property instead of this macro. */ /** * CLUTTER_ACTOR_IS_VISIBLE: * @a: a #ClutterActor * * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden. * Equivalent to the ClutterActor::visible object property. * * Note that an actor is only painted onscreen if it's mapped, which * means it's visible, and all its parents are visible, and one of the * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED. * * Since: 0.2 * * Deprecated: 1.24: Use clutter_actor_is_visible() or the #ClutterActor:visible * property instead of this macro. */ /** * CLUTTER_ACTOR_IS_REACTIVE: * @a: a #ClutterActor * * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set. * * Only reactive actors will receive event-related signals. * * Since: 0.6 * * Deprecated: 1.24: Use clutter_actor_get_reactive() or the * #ClutterActor:reactive property instead of this macro. */ #include "clutter-build-config.h" #include #include #include #define CLUTTER_DISABLE_DEPRECATION_WARNINGS #define CLUTTER_ENABLE_EXPERIMENTAL_API #include "clutter-actor-private.h" #include "clutter-action.h" #include "clutter-actor-meta-private.h" #include "clutter-animatable.h" #include "clutter-color-static.h" #include "clutter-color.h" #include "clutter-constraint-private.h" #include "clutter-container.h" #include "clutter-content-private.h" #include "clutter-debug.h" #include "clutter-easing.h" #include "clutter-effect-private.h" #include "clutter-enum-types.h" #include "clutter-fixed-layout.h" #include "clutter-flatten-effect.h" #include "clutter-interval.h" #include "clutter-main.h" #include "clutter-marshal.h" #include "clutter-paint-nodes.h" #include "clutter-paint-node-private.h" #include "clutter-paint-volume-private.h" #include "clutter-private.h" #include "clutter-property-transition.h" #include "clutter-scriptable.h" #include "clutter-script-private.h" #include "clutter-stage-private.h" #include "clutter-timeline.h" #include "clutter-transition.h" #include "clutter-units.h" #include "deprecated/clutter-actor.h" #include "deprecated/clutter-behaviour.h" #include "deprecated/clutter-container.h" /* Internal enum used to control mapped state update. This is a hint * which indicates when to do something other than just enforce * invariants. */ typedef enum { MAP_STATE_CHECK, /* just enforce invariants. */ MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants, * used when about to unparent. */ MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met; * used to set mapped on toplevels. */ MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped, * used just before unmapping parent. */ } MapStateChange; /* 3 entries should be a good compromise, few layout managers * will ask for 3 different preferred size in each allocation cycle */ #define N_CACHED_SIZE_REQUESTS 3 struct _ClutterActorPrivate { /* request mode */ ClutterRequestMode request_mode; /* our cached size requests for different width / height */ SizeRequest width_requests[N_CACHED_SIZE_REQUESTS]; SizeRequest height_requests[N_CACHED_SIZE_REQUESTS]; /* An age of 0 means the entry is not set */ guint cached_height_age; guint cached_width_age; /* the bounding box of the actor, relative to the parent's * allocation */ ClutterActorBox allocation; ClutterAllocationFlags allocation_flags; /* clip, in actor coordinates */ ClutterRect clip; /* the cached transformation matrix; see apply_transform() */ CoglMatrix transform; guint8 opacity; gint opacity_override; ClutterOffscreenRedirect offscreen_redirect; /* This is an internal effect used to implement the offscreen-redirect property */ ClutterEffect *flatten_effect; /* scene graph */ ClutterActor *parent; ClutterActor *prev_sibling; ClutterActor *next_sibling; ClutterActor *first_child; ClutterActor *last_child; gint n_children; /* tracks whenever the children of an actor are changed; the * age is incremented by 1 whenever an actor is added or * removed. the age is not incremented when the first or the * last child pointers are changed, or when grandchildren of * an actor are changed. */ gint age; gchar *name; /* a non-unique name, used for debugging */ gint32 pick_id; /* per-stage unique id, used for picking */ /* a back-pointer to the Pango context that we can use * to create pre-configured PangoLayout */ PangoContext *pango_context; /* the text direction configured for this child - either by * application code, or by the actor's parent */ ClutterTextDirection text_direction; /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */ gint internal_child; /* meta classes */ ClutterMetaGroup *actions; ClutterMetaGroup *constraints; ClutterMetaGroup *effects; /* delegate object used to allocate the children of this actor */ ClutterLayoutManager *layout_manager; /* delegate object used to paint the contents of this actor */ ClutterContent *content; ClutterActorBox content_box; ClutterContentGravity content_gravity; ClutterScalingFilter min_filter; ClutterScalingFilter mag_filter; ClutterContentRepeat content_repeat; /* used when painting, to update the paint volume */ ClutterEffect *current_effect; /* This is used to store an effect which needs to be redrawn. A redraw can be queued to start from a particular effect. This is used by parametrised effects that can cache an image of the actor. If a parameter of the effect changes then it only needs to redraw the cached image, not the actual actor. The pointer is only valid if is_dirty == TRUE. If the pointer is NULL then the whole actor is dirty. */ ClutterEffect *effect_to_redraw; /* This is used when painting effects to implement the clutter_actor_continue_paint() function. It points to the node in the list of effects that is next in the chain */ const GList *next_effect_to_paint; ClutterPaintVolume paint_volume; /* NB: This volume isn't relative to this actor, it is in eye * coordinates so that it can remain valid after the actor changes. */ ClutterPaintVolume last_paint_volume; ClutterStageQueueRedrawEntry *queue_redraw_entry; ClutterColor bg_color; #ifdef CLUTTER_ENABLE_DEBUG /* a string used for debugging messages */ gchar *debug_name; #endif /* a set of clones of the actor */ GHashTable *clones; /* whether the actor is inside a cloned branch; this * value is propagated to all the actor's children */ gulong in_cloned_branch; GListModel *child_model; ClutterActorCreateChildFunc create_child_func; gpointer create_child_data; GDestroyNotify create_child_notify; /* bitfields: KEEP AT THE END */ /* fixed position and sizes */ guint position_set : 1; guint min_width_set : 1; guint min_height_set : 1; guint natural_width_set : 1; guint natural_height_set : 1; /* cached request is invalid (implies allocation is too) */ guint needs_width_request : 1; /* cached request is invalid (implies allocation is too) */ guint needs_height_request : 1; /* cached allocation is invalid (request has changed, probably) */ guint needs_allocation : 1; guint show_on_set_parent : 1; guint has_clip : 1; guint clip_to_allocation : 1; guint enable_model_view_transform : 1; guint enable_paint_unmapped : 1; guint has_pointer : 1; guint propagated_one_redraw : 1; guint paint_volume_valid : 1; guint last_paint_volume_valid : 1; guint in_clone_paint : 1; guint transform_valid : 1; /* This is TRUE if anything has queued a redraw since we were last painted. In this case effect_to_redraw will point to an effect the redraw was queued from or it will be NULL if the redraw was queued without an effect. */ guint is_dirty : 1; guint bg_color_set : 1; guint content_box_valid : 1; guint x_expand_set : 1; guint y_expand_set : 1; guint needs_compute_expand : 1; guint needs_x_expand : 1; guint needs_y_expand : 1; guint needs_paint_volume_update : 1; }; enum { PROP_0, PROP_NAME, /* X, Y, WIDTH, HEIGHT are "do what I mean" properties; * when set they force a size request, when gotten they * get the allocation if the allocation is valid, and the * request otherwise */ PROP_X, PROP_Y, PROP_WIDTH, PROP_HEIGHT, PROP_POSITION, PROP_SIZE, /* Then the rest of these size-related properties are the "actual" * underlying properties set or gotten by X, Y, WIDTH, HEIGHT */ PROP_FIXED_X, PROP_FIXED_Y, PROP_FIXED_POSITION_SET, PROP_MIN_WIDTH, PROP_MIN_WIDTH_SET, PROP_MIN_HEIGHT, PROP_MIN_HEIGHT_SET, PROP_NATURAL_WIDTH, PROP_NATURAL_WIDTH_SET, PROP_NATURAL_HEIGHT, PROP_NATURAL_HEIGHT_SET, PROP_REQUEST_MODE, /* Allocation properties are read-only */ PROP_ALLOCATION, PROP_DEPTH, /* XXX:2.0 remove */ PROP_Z_POSITION, PROP_CLIP, /* XXX:2.0 remove */ PROP_CLIP_RECT, PROP_HAS_CLIP, PROP_CLIP_TO_ALLOCATION, PROP_OPACITY, PROP_OFFSCREEN_REDIRECT, PROP_VISIBLE, PROP_MAPPED, PROP_REALIZED, PROP_REACTIVE, PROP_PIVOT_POINT, PROP_PIVOT_POINT_Z, PROP_SCALE_X, PROP_SCALE_Y, PROP_SCALE_Z, PROP_SCALE_CENTER_X, /* XXX:2.0 remove */ PROP_SCALE_CENTER_Y, /* XXX:2.0 remove */ PROP_SCALE_GRAVITY, /* XXX:2.0 remove */ PROP_ROTATION_ANGLE_X, /* XXX:2.0 rename to rotation-x */ PROP_ROTATION_ANGLE_Y, /* XXX:2.0 rename to rotation-y */ PROP_ROTATION_ANGLE_Z, /* XXX:2.0 rename to rotation-z */ PROP_ROTATION_CENTER_X, /* XXX:2.0 remove */ PROP_ROTATION_CENTER_Y, /* XXX:2.0 remove */ PROP_ROTATION_CENTER_Z, /* XXX:2.0 remove */ /* This property only makes sense for the z rotation because the others would depend on the actor having a size along the z-axis */ PROP_ROTATION_CENTER_Z_GRAVITY, /* XXX:2.0 remove */ PROP_ANCHOR_X, /* XXX:2.0 remove */ PROP_ANCHOR_Y, /* XXX:2.0 remove */ PROP_ANCHOR_GRAVITY, /*XXX:2.0 remove */ PROP_TRANSLATION_X, PROP_TRANSLATION_Y, PROP_TRANSLATION_Z, PROP_TRANSFORM, PROP_TRANSFORM_SET, PROP_CHILD_TRANSFORM, PROP_CHILD_TRANSFORM_SET, PROP_SHOW_ON_SET_PARENT, /*XXX:2.0 remove */ PROP_TEXT_DIRECTION, PROP_HAS_POINTER, PROP_ACTIONS, PROP_CONSTRAINTS, PROP_EFFECT, PROP_LAYOUT_MANAGER, PROP_X_EXPAND, PROP_Y_EXPAND, PROP_X_ALIGN, PROP_Y_ALIGN, PROP_MARGIN_TOP, PROP_MARGIN_BOTTOM, PROP_MARGIN_LEFT, PROP_MARGIN_RIGHT, PROP_BACKGROUND_COLOR, PROP_BACKGROUND_COLOR_SET, PROP_FIRST_CHILD, PROP_LAST_CHILD, PROP_CONTENT, PROP_CONTENT_GRAVITY, PROP_CONTENT_BOX, PROP_MINIFICATION_FILTER, PROP_MAGNIFICATION_FILTER, PROP_CONTENT_REPEAT, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST]; enum { SHOW, HIDE, DESTROY, PARENT_SET, KEY_FOCUS_IN, KEY_FOCUS_OUT, PAINT, PICK, REALIZE, UNREALIZE, QUEUE_REDRAW, QUEUE_RELAYOUT, EVENT, CAPTURED_EVENT, BUTTON_PRESS_EVENT, BUTTON_RELEASE_EVENT, SCROLL_EVENT, KEY_PRESS_EVENT, KEY_RELEASE_EVENT, MOTION_EVENT, ENTER_EVENT, LEAVE_EVENT, ALLOCATION_CHANGED, TRANSITIONS_COMPLETED, TOUCH_EVENT, TRANSITION_STOPPED, LAST_SIGNAL }; static guint actor_signals[LAST_SIGNAL] = { 0, }; typedef struct _TransitionClosure { ClutterActor *actor; ClutterTransition *transition; gchar *name; gulong completed_id; guint is_implicit : 1; } TransitionClosure; static void clutter_container_iface_init (ClutterContainerIface *iface); static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); static void clutter_animatable_iface_init (ClutterAnimatableIface *iface); static void atk_implementor_iface_init (AtkImplementorIface *iface); /* These setters are all static for now, maybe they should be in the * public API, but they are perhaps obscure enough to leave only as * properties */ static void clutter_actor_set_min_width (ClutterActor *self, gfloat min_width); static void clutter_actor_set_min_height (ClutterActor *self, gfloat min_height); static void clutter_actor_set_natural_width (ClutterActor *self, gfloat natural_width); static void clutter_actor_set_natural_height (ClutterActor *self, gfloat natural_height); static void clutter_actor_set_min_width_set (ClutterActor *self, gboolean use_min_width); static void clutter_actor_set_min_height_set (ClutterActor *self, gboolean use_min_height); static void clutter_actor_set_natural_width_set (ClutterActor *self, gboolean use_natural_width); static void clutter_actor_set_natural_height_set (ClutterActor *self, gboolean use_natural_height); static void clutter_actor_update_map_state (ClutterActor *self, MapStateChange change); static void clutter_actor_unrealize_not_hiding (ClutterActor *self); /* Helper routines for managing anchor coords */ static void clutter_anchor_coord_get_units (ClutterActor *self, const AnchorCoord *coord, gfloat *x, gfloat *y, gfloat *z); static void clutter_anchor_coord_set_units (AnchorCoord *coord, gfloat x, gfloat y, gfloat z); static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord); static void clutter_anchor_coord_set_gravity (AnchorCoord *coord, ClutterGravity gravity); static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord); static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self, ClutterActor *ancestor, CoglMatrix *matrix); static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self); static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self); static inline void clutter_actor_set_background_color_internal (ClutterActor *self, const ClutterColor *color); static void on_layout_manager_changed (ClutterLayoutManager *manager, ClutterActor *self); static inline void clutter_actor_queue_compute_expand (ClutterActor *self); static inline void clutter_actor_set_margin_internal (ClutterActor *self, gfloat margin, GParamSpec *pspec); static void clutter_actor_set_transform_internal (ClutterActor *self, const ClutterMatrix *transform); static void clutter_actor_set_child_transform_internal (ClutterActor *self, const ClutterMatrix *transform); static void clutter_actor_realize_internal (ClutterActor *self); static void clutter_actor_unrealize_internal (ClutterActor *self); /* Helper macro which translates by the anchor coord, applies the given transformation and then translates back */ #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \ gfloat _tx, _ty, _tz; \ clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \ cogl_matrix_translate ((m), _tx, _ty, _tz); \ { _transform; } \ cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END static GQuark quark_shader_data = 0; static GQuark quark_actor_layout_info = 0; static GQuark quark_actor_transform_info = 0; static GQuark quark_actor_animation_info = 0; G_DEFINE_TYPE_WITH_CODE (ClutterActor, clutter_actor, G_TYPE_INITIALLY_UNOWNED, G_ADD_PRIVATE (ClutterActor) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER, clutter_container_iface_init) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, clutter_scriptable_iface_init) G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE, clutter_animatable_iface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR, atk_implementor_iface_init)); /*< private > * clutter_actor_get_debug_name: * @actor: a #ClutterActor * * Retrieves a printable name of @actor for debugging messages * * Return value: a string with a printable name */ const gchar * _clutter_actor_get_debug_name (ClutterActor *actor) { ClutterActorPrivate *priv = actor->priv; const gchar *retval; #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (priv->debug_name == NULL)) { priv->debug_name = g_strdup_printf ("<%s>[<%s>:%p]", priv->name != NULL ? priv->name : "unnamed", G_OBJECT_TYPE_NAME (actor), actor); } retval = priv->debug_name; #else retval = priv->name != NULL ? priv->name : G_OBJECT_TYPE_NAME (actor); #endif return retval; } #ifdef CLUTTER_ENABLE_DEBUG /* XXX - this is for debugging only, remove once working (or leave * in only in some debug mode). Should leave it for a little while * until we're confident in the new map/realize/visible handling. */ static inline void clutter_actor_verify_map_state (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; if (CLUTTER_ACTOR_IS_REALIZED (self)) { /* all bets are off during reparent when we're potentially realized, * but should not be according to invariants */ if (!CLUTTER_ACTOR_IN_REPARENT (self)) { if (priv->parent == NULL) { if (CLUTTER_ACTOR_IS_TOPLEVEL (self)) { } else g_warning ("Realized non-toplevel actor '%s' should " "have a parent", _clutter_actor_get_debug_name (self)); } else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent)) { g_warning ("Realized actor %s has an unrealized parent %s", _clutter_actor_get_debug_name (self), _clutter_actor_get_debug_name (priv->parent)); } } } if (CLUTTER_ACTOR_IS_MAPPED (self)) { if (!CLUTTER_ACTOR_IS_REALIZED (self)) g_warning ("Actor '%s' is mapped but not realized", _clutter_actor_get_debug_name (self)); /* remaining bets are off during reparent when we're potentially * mapped, but should not be according to invariants */ if (!CLUTTER_ACTOR_IN_REPARENT (self)) { if (priv->parent == NULL) { if (CLUTTER_ACTOR_IS_TOPLEVEL (self)) { if (!CLUTTER_ACTOR_IS_VISIBLE (self) && !CLUTTER_ACTOR_IN_DESTRUCTION (self)) { g_warning ("Toplevel actor '%s' is mapped " "but not visible", _clutter_actor_get_debug_name (self)); } } else { g_warning ("Mapped actor '%s' should have a parent", _clutter_actor_get_debug_name (self)); } } else { ClutterActor *iter = self; /* check for the enable_paint_unmapped flag on the actor * and parents; if the flag is enabled at any point of this * branch of the scene graph then all the later checks * become pointless */ while (iter != NULL) { if (iter->priv->enable_paint_unmapped) return; iter = iter->priv->parent; } if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent)) { g_warning ("Actor '%s' should not be mapped if parent '%s'" "is not visible", _clutter_actor_get_debug_name (self), _clutter_actor_get_debug_name (priv->parent)); } if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent)) { g_warning ("Actor '%s' should not be mapped if parent '%s'" "is not realized", _clutter_actor_get_debug_name (self), _clutter_actor_get_debug_name (priv->parent)); } if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent)) { if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent)) g_warning ("Actor '%s' is mapped but its non-toplevel " "parent '%s' is not mapped", _clutter_actor_get_debug_name (self), _clutter_actor_get_debug_name (priv->parent)); } } } } } #endif /* CLUTTER_ENABLE_DEBUG */ static void clutter_actor_set_mapped (ClutterActor *self, gboolean mapped) { if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped) return; if (mapped) { CLUTTER_ACTOR_GET_CLASS (self)->map (self); g_assert (CLUTTER_ACTOR_IS_MAPPED (self)); } else { CLUTTER_ACTOR_GET_CLASS (self)->unmap (self); g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); } } /* this function updates the mapped and realized states according to * invariants, in the appropriate order. */ static void clutter_actor_update_map_state (ClutterActor *self, MapStateChange change) { gboolean was_mapped; was_mapped = CLUTTER_ACTOR_IS_MAPPED (self); if (CLUTTER_ACTOR_IS_TOPLEVEL (self)) { /* the mapped flag on top-level actors must be set by the * per-backend implementation because it might be asynchronous. * * That is, the MAPPED flag on toplevels currently tracks the X * server mapped-ness of the window, while the expected behavior * (if used to GTK) may be to track WM_STATE!=WithdrawnState. * This creates some weird complexity by breaking the invariant * that if we're visible and all ancestors shown then we are * also mapped - instead, we are mapped if all ancestors * _possibly excepting_ the stage are mapped. The stage * will map/unmap for example when it is minimized or * moved to another workspace. * * So, the only invariant on the stage is that if visible it * should be realized, and that it has to be visible to be * mapped. */ if (CLUTTER_ACTOR_IS_VISIBLE (self)) clutter_actor_realize (self); switch (change) { case MAP_STATE_CHECK: break; case MAP_STATE_MAKE_MAPPED: g_assert (!was_mapped); clutter_actor_set_mapped (self, TRUE); break; case MAP_STATE_MAKE_UNMAPPED: g_assert (was_mapped); clutter_actor_set_mapped (self, FALSE); break; case MAP_STATE_MAKE_UNREALIZED: /* we only use MAKE_UNREALIZED in unparent, * and unparenting a stage isn't possible. * If someone wants to just unrealize a stage * then clutter_actor_unrealize() doesn't * go through this codepath. */ g_warning ("Trying to force unrealize stage is not allowed"); break; } if (CLUTTER_ACTOR_IS_MAPPED (self) && !CLUTTER_ACTOR_IS_VISIBLE (self) && !CLUTTER_ACTOR_IN_DESTRUCTION (self)) { g_warning ("Clutter toplevel of type '%s' is not visible, but " "it is somehow still mapped", _clutter_actor_get_debug_name (self)); } } else { ClutterActorPrivate *priv = self->priv; ClutterActor *parent = priv->parent; gboolean should_be_mapped; gboolean may_be_realized; gboolean must_be_realized; should_be_mapped = FALSE; may_be_realized = TRUE; must_be_realized = FALSE; if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED) { may_be_realized = FALSE; } else { /* Maintain invariant that if parent is mapped, and we are * visible, then we are mapped ... unless parent is a * stage, in which case we map regardless of parent's map * state but do require stage to be visible and realized. * * If parent is realized, that does not force us to be * realized; but if parent is unrealized, that does force * us to be unrealized. * * The reason we don't force children to realize with * parents is _clutter_actor_rerealize(); if we require that * a realized parent means children are realized, then to * unrealize an actor we would have to unrealize its * parents, which would end up meaning unrealizing and * hiding the entire stage. So we allow unrealizing a * child (as long as that child is not mapped) while that * child still has a realized parent. * * Also, if we unrealize from leaf nodes to root, and * realize from root to leaf, the invariants are never * violated if we allow children to be unrealized * while parents are realized. * * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified * to force us to unmap, even though parent is still * mapped. This is because we're unmapping from leaf nodes * up to root nodes. */ if (CLUTTER_ACTOR_IS_VISIBLE (self) && change != MAP_STATE_MAKE_UNMAPPED) { gboolean parent_is_visible_realized_toplevel; parent_is_visible_realized_toplevel = (CLUTTER_ACTOR_IS_TOPLEVEL (parent) && CLUTTER_ACTOR_IS_VISIBLE (parent) && CLUTTER_ACTOR_IS_REALIZED (parent)); if (CLUTTER_ACTOR_IS_MAPPED (parent) || parent_is_visible_realized_toplevel) { must_be_realized = TRUE; should_be_mapped = TRUE; } } /* if the actor has been set to be painted even if unmapped * then we should map it and check for realization as well; * this is an override for the branch of the scene graph * which begins with this node */ if (priv->enable_paint_unmapped) { should_be_mapped = TRUE; must_be_realized = TRUE; } if (!CLUTTER_ACTOR_IS_REALIZED (parent)) may_be_realized = FALSE; } if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped) { if (parent == NULL) g_warning ("Attempting to map a child that does not " "meet the necessary invariants: the actor '%s' " "has no parent", _clutter_actor_get_debug_name (self)); else g_warning ("Attempting to map a child that does not " "meet the necessary invariants: the actor '%s' " "is parented to an unmapped actor '%s'", _clutter_actor_get_debug_name (self), _clutter_actor_get_debug_name (priv->parent)); } /* If in reparent, we temporarily suspend unmap and unrealize. * * We want to go in the order "realize, map" and "unmap, unrealize" */ /* Unmap */ if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self)) clutter_actor_set_mapped (self, FALSE); /* Realize */ if (must_be_realized) clutter_actor_realize (self); /* if we must be realized then we may be, presumably */ g_assert (!(must_be_realized && !may_be_realized)); /* Unrealize */ if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self)) clutter_actor_unrealize_not_hiding (self); /* Map */ if (should_be_mapped) { if (!must_be_realized) g_warning ("Somehow we think actor '%s' should be mapped but " "not realized, which isn't allowed", _clutter_actor_get_debug_name (self)); /* realization is allowed to fail (though I don't know what * an app is supposed to do about that - shouldn't it just * be a g_error? anyway, we have to avoid mapping if this * happens) */ if (CLUTTER_ACTOR_IS_REALIZED (self)) clutter_actor_set_mapped (self, TRUE); } } #ifdef CLUTTER_ENABLE_DEBUG /* check all invariants were kept */ clutter_actor_verify_map_state (self); #endif } static void clutter_actor_real_map (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; ClutterActor *stage, *iter; g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); CLUTTER_NOTE (ACTOR, "Mapping actor '%s'", _clutter_actor_get_debug_name (self)); CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED); self->priv->needs_paint_volume_update = TRUE; stage = _clutter_actor_get_stage_internal (self); priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self); CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'", priv->pick_id, _clutter_actor_get_debug_name (self)); /* notify on parent mapped before potentially mapping * children, so apps see a top-down notification. */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]); for (iter = self->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) { clutter_actor_map (iter); } } /** * clutter_actor_map: * @self: A #ClutterActor * * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps * and realizes its children if they are visible. Does nothing if the * actor is not visible. * * Calling this function is strongly disencouraged: the default * implementation of #ClutterActorClass.map() will map all the children * of an actor when mapping its parent. * * When overriding map, it is mandatory to chain up to the parent * implementation. * * Since: 1.0 */ void clutter_actor_map (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (CLUTTER_ACTOR_IS_MAPPED (self)) return; if (!CLUTTER_ACTOR_IS_VISIBLE (self)) return; clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED); } /** * clutter_actor_is_mapped: * @self: a #ClutterActor * * Checks whether a #ClutterActor has been set as mapped. * * See also %CLUTTER_ACTOR_IS_MAPPED and #ClutterActor:mapped * * Returns: %TRUE if the actor is mapped * * Since: 1.24 */ gboolean clutter_actor_is_mapped (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return CLUTTER_ACTOR_IS_MAPPED (self); } static void clutter_actor_real_unmap (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; ClutterActor *iter; g_assert (CLUTTER_ACTOR_IS_MAPPED (self)); CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'", _clutter_actor_get_debug_name (self)); for (iter = self->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) { clutter_actor_unmap (iter); } CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED); /* clear the contents of the last paint volume, so that hiding + moving + * showing will not result in the wrong area being repainted */ _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL); priv->last_paint_volume_valid = TRUE; /* notify on parent mapped after potentially unmapping * children, so apps see a bottom-up notification. */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]); /* relinquish keyboard focus if we were unmapped while owning it */ if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) { ClutterStage *stage; stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self)); if (stage != NULL) _clutter_stage_release_pick_id (stage, priv->pick_id); priv->pick_id = -1; if (stage != NULL && clutter_stage_get_key_focus (stage) == self) { clutter_stage_set_key_focus (stage, NULL); } } } /** * clutter_actor_unmap: * @self: A #ClutterActor * * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly * unmaps its children if they were mapped. * * Calling this function is not encouraged: the default #ClutterActor * implementation of #ClutterActorClass.unmap() will also unmap any * eventual children by default when their parent is unmapped. * * When overriding #ClutterActorClass.unmap(), it is mandatory to * chain up to the parent implementation. * * It is important to note that the implementation of the * #ClutterActorClass.unmap() virtual function may be called after * the #ClutterActorClass.destroy() or the #GObjectClass.dispose() * implementation, but it is guaranteed to be called before the * #GObjectClass.finalize() implementation. * * Since: 1.0 */ void clutter_actor_unmap (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (!CLUTTER_ACTOR_IS_MAPPED (self)) return; clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED); } static void clutter_actor_real_show (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; if (CLUTTER_ACTOR_IS_VISIBLE (self)) return; CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE); /* we notify on the "visible" flag in the clutter_actor_show() * wrapper so the entire show signal emission completes first, * and the branch of the scene graph is in a stable state */ clutter_actor_update_map_state (self, MAP_STATE_CHECK); /* we queue a relayout unless the actor is inside a * container that explicitly told us not to */ if (priv->parent != NULL && (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT))) { /* While an actor is hidden the parent may not have * allocated/requested so we need to start from scratch * and avoid the short-circuiting in * clutter_actor_queue_relayout(). */ priv->needs_width_request = FALSE; priv->needs_height_request = FALSE; priv->needs_allocation = FALSE; clutter_actor_queue_relayout (self); } } static inline void set_show_on_set_parent (ClutterActor *self, gboolean set_show) { ClutterActorPrivate *priv = self->priv; set_show = !!set_show; if (priv->show_on_set_parent == set_show) return; if (priv->parent == NULL) { priv->show_on_set_parent = set_show; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SHOW_ON_SET_PARENT]); } } /** * clutter_actor_show: * @self: A #ClutterActor * * Flags an actor to be displayed. An actor that isn't shown will not * be rendered on the stage. * * Actors are visible by default. * * If this function is called on an actor without a parent, the * #ClutterActor:show-on-set-parent will be set to %TRUE as a side * effect. */ void clutter_actor_show (ClutterActor *self) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); /* simple optimization */ if (CLUTTER_ACTOR_IS_VISIBLE (self)) { /* we still need to set the :show-on-set-parent property, in * case show() is called on an unparented actor */ set_show_on_set_parent (self, TRUE); return; } #ifdef CLUTTER_ENABLE_DEBUG clutter_actor_verify_map_state (self); #endif priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); set_show_on_set_parent (self, TRUE); /* if we're showing a child that needs to expand, or may * expand, then we need to recompute the expand flags for * its parent as well */ if (priv->needs_compute_expand || priv->needs_x_expand || priv->needs_y_expand) { clutter_actor_queue_compute_expand (self); } g_signal_emit (self, actor_signals[SHOW], 0); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]); if (priv->parent != NULL) clutter_actor_queue_redraw (priv->parent); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_is_visible: * @self: a #ClutterActor * * Checks whether an actor is marked as visible. * * See also %CLUTTER_ACTOR_IS_VISIBLE and #ClutterActor:visible. * * Returns: %TRUE if the actor visible * * Since: 1.24 */ gboolean clutter_actor_is_visible (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return CLUTTER_ACTOR_IS_VISIBLE (self); } /** * clutter_actor_show_all: * @self: a #ClutterActor * * Calls clutter_actor_show() on all children of an actor (if any). * * Since: 0.2 * * Deprecated: 1.10: Actors are visible by default */ void clutter_actor_show_all (ClutterActor *self) { ClutterActorClass *klass; g_return_if_fail (CLUTTER_IS_ACTOR (self)); klass = CLUTTER_ACTOR_GET_CLASS (self); if (klass->show_all) klass->show_all (self); } static void clutter_actor_real_hide (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; if (!CLUTTER_ACTOR_IS_VISIBLE (self)) return; CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE); /* we notify on the "visible" flag in the clutter_actor_hide() * wrapper so the entire hide signal emission completes first, * and the branch of the scene graph is in a stable state */ clutter_actor_update_map_state (self, MAP_STATE_CHECK); /* we queue a relayout unless the actor is inside a * container that explicitly told us not to */ if (priv->parent != NULL && (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT))) clutter_actor_queue_relayout (priv->parent); } /** * clutter_actor_hide: * @self: A #ClutterActor * * Flags an actor to be hidden. A hidden actor will not be * rendered on the stage. * * Actors are visible by default. * * If this function is called on an actor without a parent, the * #ClutterActor:show-on-set-parent property will be set to %FALSE * as a side-effect. */ void clutter_actor_hide (ClutterActor *self) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); /* simple optimization */ if (!CLUTTER_ACTOR_IS_VISIBLE (self)) { /* we still need to set the :show-on-set-parent property, in * case hide() is called on an unparented actor */ set_show_on_set_parent (self, FALSE); return; } #ifdef CLUTTER_ENABLE_DEBUG clutter_actor_verify_map_state (self); #endif priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); set_show_on_set_parent (self, FALSE); /* if we're hiding a child that needs to expand, or may * expand, then we need to recompute the expand flags for * its parent as well */ if (priv->needs_compute_expand || priv->needs_x_expand || priv->needs_y_expand) { clutter_actor_queue_compute_expand (self); } g_signal_emit (self, actor_signals[HIDE], 0); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]); if (priv->parent != NULL) clutter_actor_queue_redraw (priv->parent); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_hide_all: * @self: a #ClutterActor * * Calls clutter_actor_hide() on all child actors (if any). * * Since: 0.2 * * Deprecated: 1.10: Using clutter_actor_hide() on the actor will * prevent its children from being painted as well. */ void clutter_actor_hide_all (ClutterActor *self) { ClutterActorClass *klass; g_return_if_fail (CLUTTER_IS_ACTOR (self)); klass = CLUTTER_ACTOR_GET_CLASS (self); if (klass->hide_all) klass->hide_all (self); } /** * clutter_actor_realize: * @self: A #ClutterActor * * Realization informs the actor that it is attached to a stage. It * can use this to allocate resources if it wanted to delay allocation * until it would be rendered. However it is perfectly acceptable for * an actor to create resources before being realized because Clutter * only ever has a single rendering context so that actor is free to * be moved from one stage to another. * * This function does nothing if the actor is already realized. * * Because a realized actor must have realized parent actors, calling * clutter_actor_realize() will also realize all parents of the actor. * * This function does not realize child actors, except in the special * case that realizing the stage, when the stage is visible, will * suddenly map (and thus realize) the children of the stage. * * Deprecated: 1.16: Actors are automatically realized, and nothing * requires explicit realization. */ void clutter_actor_realize (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); clutter_actor_realize_internal (self); } /** * clutter_actor_is_realized: * @self: a #ClutterActor * * Checks whether a #ClutterActor is realized. * * See also %CLUTTER_ACTOR_IS_REALIZED and #ClutterActor:realized. * * Returns: %TRUE if the actor is realized * * Since: 1.24 */ gboolean clutter_actor_is_realized (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return CLUTTER_ACTOR_IS_REALIZED (self); } static void clutter_actor_realize_internal (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; #ifdef CLUTTER_ENABLE_DEBUG clutter_actor_verify_map_state (self); #endif if (CLUTTER_ACTOR_IS_REALIZED (self)) return; /* To be realized, our parent actors must be realized first. * This will only succeed if we're inside a toplevel. */ if (priv->parent != NULL) clutter_actor_realize (priv->parent); if (CLUTTER_ACTOR_IS_TOPLEVEL (self)) { /* toplevels can be realized at any time */ } else { /* "Fail" the realization if parent is missing or unrealized; * this should really be a g_warning() not some kind of runtime * failure; how can an app possibly recover? Instead it's a bug * in the app and the app should get an explanatory warning so * someone can fix it. But for now it's too hard to fix this * because e.g. ClutterTexture needs reworking. */ if (priv->parent == NULL || !CLUTTER_ACTOR_IS_REALIZED (priv->parent)) return; } CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self)); CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]); g_signal_emit (self, actor_signals[REALIZE], 0); /* Stage actor is allowed to unset the realized flag again in its * default signal handler, though that is a pathological situation. */ /* If realization "failed" we'll have to update child state. */ clutter_actor_update_map_state (self, MAP_STATE_CHECK); } static void clutter_actor_real_unrealize (ClutterActor *self) { /* we must be unmapped (implying our children are also unmapped) */ g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); } /** * clutter_actor_unrealize: * @self: A #ClutterActor * * Unrealization informs the actor that it may be being destroyed or * moved to another stage. The actor may want to destroy any * underlying graphics resources at this point. However it is * perfectly acceptable for it to retain the resources until the actor * is destroyed because Clutter only ever uses a single rendering * context and all of the graphics resources are valid on any stage. * * Because mapped actors must be realized, actors may not be * unrealized if they are mapped. This function hides the actor to be * sure it isn't mapped, an application-visible side effect that you * may not be expecting. * * This function should not be called by application code. * * This function should not really be in the public API, because * there isn't a good reason to call it. ClutterActor will already * unrealize things for you when it's important to do so. * * If you were using clutter_actor_unrealize() in a dispose * implementation, then don't, just chain up to ClutterActor's * dispose. * * If you were using clutter_actor_unrealize() to implement * unrealizing children of your container, then don't, ClutterActor * will already take care of that. * * Deprecated: 1.16: Actors are automatically unrealized, and nothing * requires explicit realization. */ void clutter_actor_unrealize (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self)); clutter_actor_unrealize_internal (self); } /* If you were using clutter_actor_unrealize() to re-realize to * create your resources in a different way, then use * _clutter_actor_rerealize() (inside Clutter) or just call your * code that recreates your resources directly (outside Clutter). */ static void clutter_actor_unrealize_internal (ClutterActor *self) { #ifdef CLUTTER_ENABLE_DEBUG clutter_actor_verify_map_state (self); #endif clutter_actor_hide (self); clutter_actor_unrealize_not_hiding (self); } static ClutterActorTraverseVisitFlags unrealize_actor_before_children_cb (ClutterActor *self, int depth, void *user_data) { /* If an actor is already unrealized we know its children have also * already been unrealized... */ if (!CLUTTER_ACTOR_IS_REALIZED (self)) return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN; g_signal_emit (self, actor_signals[UNREALIZE], 0); return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE; } static ClutterActorTraverseVisitFlags unrealize_actor_after_children_cb (ClutterActor *self, int depth, void *user_data) { /* We want to unset the realized flag only _after_ * child actors are unrealized, to maintain invariants. */ CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]); return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE; } /* * clutter_actor_unrealize_not_hiding: * @self: A #ClutterActor * * Unrealization informs the actor that it may be being destroyed or * moved to another stage. The actor may want to destroy any * underlying graphics resources at this point. However it is * perfectly acceptable for it to retain the resources until the actor * is destroyed because Clutter only ever uses a single rendering * context and all of the graphics resources are valid on any stage. * * Because mapped actors must be realized, actors may not be * unrealized if they are mapped. You must hide the actor or one of * its parents before attempting to unrealize. * * This function is separate from clutter_actor_unrealize() because it * does not automatically hide the actor. * Actors need not be hidden to be unrealized, they just need to * be unmapped. In fact we don't want to mess up the application's * setting of the "visible" flag, so hiding is very undesirable. * * clutter_actor_unrealize() does a clutter_actor_hide() just for * backward compatibility. */ static void clutter_actor_unrealize_not_hiding (ClutterActor *self) { _clutter_actor_traverse (self, CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST, unrealize_actor_before_children_cb, unrealize_actor_after_children_cb, NULL); } /* * _clutter_actor_rerealize: * @self: A #ClutterActor * @callback: Function to call while unrealized * @data: data for callback * * If an actor is already unrealized, this just calls the callback. * * If it is realized, it unrealizes temporarily, calls the callback, * and then re-realizes the actor. * * As a side effect, leaves all children of the actor unrealized if * the actor was realized but not showing. This is because when we * unrealize the actor temporarily we must unrealize its children * (e.g. children of a stage can't be realized if stage window is * gone). And we aren't clever enough to save the realization state of * all children. In most cases this should not matter, because * the children will automatically realize when they next become mapped. */ void _clutter_actor_rerealize (ClutterActor *self, ClutterCallback callback, void *data) { gboolean was_mapped; gboolean was_showing; gboolean was_realized; g_return_if_fail (CLUTTER_IS_ACTOR (self)); #ifdef CLUTTER_ENABLE_DEBUG clutter_actor_verify_map_state (self); #endif was_realized = CLUTTER_ACTOR_IS_REALIZED (self); was_mapped = CLUTTER_ACTOR_IS_MAPPED (self); was_showing = CLUTTER_ACTOR_IS_VISIBLE (self); /* Must be unmapped to unrealize. Note we only have to hide this * actor if it was mapped (if all parents were showing). If actor * is merely visible (but not mapped), then that's fine, we can * leave it visible. */ if (was_mapped) clutter_actor_hide (self); g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); /* unrealize self and all children */ clutter_actor_unrealize_not_hiding (self); if (callback != NULL) { (* callback) (self, data); } if (was_showing) clutter_actor_show (self); /* will realize only if mapping implies it */ else if (was_realized) clutter_actor_realize (self); /* realize self and all parents */ } static void clutter_actor_real_pick (ClutterActor *self, const ClutterColor *color) { /* the default implementation is just to paint a rectangle * with the same size of the actor using the passed color */ if (clutter_actor_should_pick_paint (self)) { ClutterActorBox box = { 0, }; float width, height; clutter_actor_get_allocation_box (self, &box); width = box.x2 - box.x1; height = box.y2 - box.y1; cogl_set_source_color4ub (color->red, color->green, color->blue, color->alpha); cogl_rectangle (0, 0, width, height); } /* XXX - this thoroughly sucks, but we need to maintain compatibility * with existing container classes that override the pick() virtual * and chain up to the default implementation - otherwise we'll end up * painting our children twice. * * this has to go away for 2.0; hopefully along the pick() itself. */ if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick) { ClutterActor *iter; for (iter = self->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) clutter_actor_paint (iter); } } /** * clutter_actor_should_pick_paint: * @self: A #ClutterActor * * Should be called inside the implementation of the * #ClutterActor::pick virtual function in order to check whether * the actor should paint itself in pick mode or not. * * This function should never be called directly by applications. * * Return value: %TRUE if the actor should paint its silhouette, * %FALSE otherwise */ gboolean clutter_actor_should_pick_paint (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); if (CLUTTER_ACTOR_IS_MAPPED (self) && (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL || CLUTTER_ACTOR_IS_REACTIVE (self))) return TRUE; return FALSE; } static void clutter_actor_real_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { ClutterActorPrivate *priv = self->priv; if (priv->n_children != 0 && priv->layout_manager != NULL) { ClutterContainer *container = CLUTTER_CONTAINER (self); CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] " "for the preferred width", G_OBJECT_TYPE_NAME (priv->layout_manager), priv->layout_manager); clutter_layout_manager_get_preferred_width (priv->layout_manager, container, for_height, min_width_p, natural_width_p); return; } /* Default implementation is always 0x0, usually an actor * using this default is relying on someone to set the * request manually */ CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0"); if (min_width_p) *min_width_p = 0; if (natural_width_p) *natural_width_p = 0; } static void clutter_actor_real_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterActorPrivate *priv = self->priv; if (priv->n_children != 0 && priv->layout_manager != NULL) { ClutterContainer *container = CLUTTER_CONTAINER (self); CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] " "for the preferred height", G_OBJECT_TYPE_NAME (priv->layout_manager), priv->layout_manager); clutter_layout_manager_get_preferred_height (priv->layout_manager, container, for_width, min_height_p, natural_height_p); return; } /* Default implementation is always 0x0, usually an actor * using this default is relying on someone to set the * request manually */ CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0"); if (min_height_p) *min_height_p = 0; if (natural_height_p) *natural_height_p = 0; } static void clutter_actor_store_old_geometry (ClutterActor *self, ClutterActorBox *box) { *box = self->priv->allocation; } static inline void clutter_actor_notify_if_geometry_changed (ClutterActor *self, const ClutterActorBox *old) { ClutterActorPrivate *priv = self->priv; GObject *obj = G_OBJECT (self); g_object_freeze_notify (obj); /* to avoid excessive requisition or allocation cycles we * use the cached values. * * - if we don't have an allocation we assume that we need * to notify anyway * - if we don't have a width or a height request we notify * width and height * - if we have a valid allocation then we check the old * bounding box with the current allocation and we notify * the changes */ if (priv->needs_allocation) { g_object_notify_by_pspec (obj, obj_props[PROP_X]); g_object_notify_by_pspec (obj, obj_props[PROP_Y]); g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]); g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]); g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]); g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]); } else if (priv->needs_width_request || priv->needs_height_request) { g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]); g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]); g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]); } else { gfloat x, y; gfloat width, height; x = priv->allocation.x1; y = priv->allocation.y1; width = priv->allocation.x2 - priv->allocation.x1; height = priv->allocation.y2 - priv->allocation.y1; if (x != old->x1) { g_object_notify_by_pspec (obj, obj_props[PROP_X]); g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]); } if (y != old->y1) { g_object_notify_by_pspec (obj, obj_props[PROP_Y]); g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]); } if (width != (old->x2 - old->x1)) { g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]); g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]); } if (height != (old->y2 - old->y1)) { g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]); g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]); } } g_object_thaw_notify (obj); } /*< private > * clutter_actor_set_allocation_internal: * @self: a #ClutterActor * @box: a #ClutterActorBox * @flags: allocation flags * * Stores the allocation of @self. * * This function only performs basic storage and property notification. * * This function should be called by clutter_actor_set_allocation() * and by the default implementation of #ClutterActorClass.allocate(). * * Return value: %TRUE if the allocation of the #ClutterActor has been * changed, and %FALSE otherwise */ static inline gboolean clutter_actor_set_allocation_internal (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterActorPrivate *priv = self->priv; GObject *obj; gboolean x1_changed, y1_changed, x2_changed, y2_changed; gboolean retval; ClutterActorBox old_alloc = { 0, }; obj = G_OBJECT (self); g_object_freeze_notify (obj); clutter_actor_store_old_geometry (self, &old_alloc); x1_changed = priv->allocation.x1 != box->x1; y1_changed = priv->allocation.y1 != box->y1; x2_changed = priv->allocation.x2 != box->x2; y2_changed = priv->allocation.y2 != box->y2; priv->allocation = *box; priv->allocation_flags = flags; /* allocation is authoritative */ priv->needs_width_request = FALSE; priv->needs_height_request = FALSE; priv->needs_allocation = FALSE; if (x1_changed || y1_changed || x2_changed || y2_changed) { CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed", _clutter_actor_get_debug_name (self)); priv->transform_valid = FALSE; g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]); /* if the allocation changes, so does the content box */ if (priv->content != NULL) { priv->content_box_valid = FALSE; g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]); } retval = TRUE; } else retval = FALSE; clutter_actor_notify_if_geometry_changed (self, &old_alloc); g_object_thaw_notify (obj); return retval; } static void clutter_actor_real_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags); static inline void clutter_actor_maybe_layout_children (ClutterActor *self, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterActorPrivate *priv = self->priv; /* this is going to be a bit hard to follow, so let's put an explanation * here. * * we want ClutterActor to have a default layout manager if the actor was * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)". * * we also want any subclass of ClutterActor that does not override the * ::allocate() virtual function to delegate to a layout manager. * * finally, we want to allow people subclassing ClutterActor and overriding * the ::allocate() vfunc to let Clutter delegate to the layout manager. * * on the other hand, we want existing actor subclasses overriding the * ::allocate() virtual function and chaining up to the parent's * implementation to continue working without allocating their children * twice, or without entering an allocation loop. * * for the first two points, we check if the class of the actor is * overridding the ::allocate() virtual function; if it isn't, then we * follow through with checking whether we have children and a layout * manager, and eventually calling clutter_layout_manager_allocate(). * * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the * allocation flags that we got passed, and if it is present, we continue * with the check above. * * if neither of these two checks yields a positive result, we just * assume that the ::allocate() virtual function that resulted in this * function being called will also allocate the children of the actor. */ if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate) goto check_layout; if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0) goto check_layout; return; check_layout: if (priv->n_children != 0 && priv->layout_manager != NULL) { ClutterContainer *container = CLUTTER_CONTAINER (self); ClutterAllocationFlags children_flags; ClutterActorBox children_box; /* normalize the box passed to the layout manager */ children_box.x1 = children_box.y1 = 0.f; children_box.x2 = (allocation->x2 - allocation->x1); children_box.y2 = (allocation->y2 - allocation->y1); /* remove the DELEGATE_LAYOUT flag; this won't be passed to * the actor's children, since it refers only to the current * actor's allocation. */ children_flags = flags; children_flags &= ~CLUTTER_DELEGATE_LAYOUT; CLUTTER_NOTE (LAYOUT, "Allocating %d children of %s " "at { %.2f, %.2f - %.2f x %.2f } " "using %s", priv->n_children, _clutter_actor_get_debug_name (self), allocation->x1, allocation->y1, (allocation->x2 - allocation->x1), (allocation->y2 - allocation->y1), G_OBJECT_TYPE_NAME (priv->layout_manager)); clutter_layout_manager_allocate (priv->layout_manager, container, &children_box, children_flags); } } static void clutter_actor_real_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterActorPrivate *priv = self->priv; gboolean changed; g_object_freeze_notify (G_OBJECT (self)); changed = clutter_actor_set_allocation_internal (self, box, flags); /* we allocate our children before we notify changes in our geometry, * so that people connecting to properties will be able to get valid * data out of the sub-tree of the scene graph that has this actor at * the root. */ clutter_actor_maybe_layout_children (self, box, flags); if (changed) { ClutterActorBox signal_box = priv->allocation; ClutterAllocationFlags signal_flags = priv->allocation_flags; g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0, &signal_box, signal_flags); } g_object_thaw_notify (G_OBJECT (self)); } static void _clutter_actor_signal_queue_redraw (ClutterActor *self, ClutterActor *origin) { /* no point in queuing a redraw on a destroyed actor */ if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) return; /* NB: We can't bail out early here if the actor is hidden in case * the actor bas been cloned. In this case the clone will need to * receive the signal so it can queue its own redraw. */ _clutter_actor_queue_redraw_on_clones (self); /* calls klass->queue_redraw in default handler */ if (g_signal_has_handler_pending (self, actor_signals[QUEUE_REDRAW], 0, TRUE)) { g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin); } else { CLUTTER_ACTOR_GET_CLASS (self)->queue_redraw (self, origin); } } static void clutter_actor_real_queue_redraw (ClutterActor *self, ClutterActor *origin) { ClutterActor *parent; CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')", _clutter_actor_get_debug_name (self), origin != NULL ? _clutter_actor_get_debug_name (origin) : "same actor"); /* no point in queuing a redraw on a destroyed actor */ if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) return; /* If the queue redraw is coming from a child then the actor has become dirty and any queued effect is no longer valid */ if (self != origin) { self->priv->is_dirty = TRUE; self->priv->effect_to_redraw = NULL; } /* If the actor isn't visible, we still had to emit the signal * to allow for a ClutterClone, but the appearance of the parent * won't change so we don't have to propagate up the hierarchy. */ if (!CLUTTER_ACTOR_IS_VISIBLE (self)) return; /* Although we could determine here that a full stage redraw * has already been queued and immediately bail out, we actually * guarantee that we will propagate a queue-redraw signal to our * parent at least once so that it's possible to implement a * container that tracks which of its children have queued a * redraw. */ if (self->priv->propagated_one_redraw) { ClutterActor *stage = _clutter_actor_get_stage_internal (self); if (stage != NULL && _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage))) return; } self->priv->propagated_one_redraw = TRUE; /* notify parents, if they are all visible eventually we'll * queue redraw on the stage, which queues the redraw idle. */ parent = clutter_actor_get_parent (self); if (parent != NULL) { /* this will go up recursively */ _clutter_actor_signal_queue_redraw (parent, origin); } } static void clutter_actor_real_queue_relayout (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; /* no point in queueing a redraw on a destroyed actor */ if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) return; priv->needs_width_request = TRUE; priv->needs_height_request = TRUE; priv->needs_allocation = TRUE; priv->needs_paint_volume_update = TRUE; /* reset the cached size requests */ memset (priv->width_requests, 0, N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest)); memset (priv->height_requests, 0, N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest)); /* We need to go all the way up the hierarchy */ if (priv->parent != NULL) _clutter_actor_queue_only_relayout (priv->parent); } /** * clutter_actor_apply_relative_transform_to_point: * @self: A #ClutterActor * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the * default #ClutterStage * @point: A point as #ClutterVertex * @vertex: (out caller-allocates): The translated #ClutterVertex * * Transforms @point in coordinates relative to the actor into * ancestor-relative coordinates using the relevant transform * stack (i.e. scale, rotation, etc). * * If @ancestor is %NULL the ancestor will be the #ClutterStage. In * this case, the coordinates returned will be the coordinates on * the stage before the projection is applied. This is different from * the behaviour of clutter_actor_apply_transform_to_point(). * * Since: 0.6 */ void clutter_actor_apply_relative_transform_to_point (ClutterActor *self, ClutterActor *ancestor, const ClutterVertex *point, ClutterVertex *vertex) { gfloat w; CoglMatrix matrix; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor)); g_return_if_fail (point != NULL); g_return_if_fail (vertex != NULL); *vertex = *point; w = 1.0; if (ancestor == NULL) ancestor = _clutter_actor_get_stage_internal (self); if (ancestor == NULL) { *vertex = *point; return; } _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix); cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w); } static gboolean _clutter_actor_fully_transform_vertices (ClutterActor *self, const ClutterVertex *vertices_in, ClutterVertex *vertices_out, int n_vertices) { ClutterActor *stage; CoglMatrix modelview; CoglMatrix projection; float viewport[4]; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); stage = _clutter_actor_get_stage_internal (self); /* We really can't do anything meaningful in this case so don't try * to do any transform */ if (stage == NULL) return FALSE; /* Note: we pass NULL as the ancestor because we don't just want the modelview * that gets us to stage coordinates, we want to go all the way to eye * coordinates */ _clutter_actor_get_relative_transformation_matrix (self, NULL, &modelview); /* Fetch the projection and viewport */ _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection); _clutter_stage_get_viewport (CLUTTER_STAGE (stage), &viewport[0], &viewport[1], &viewport[2], &viewport[3]); _clutter_util_fully_transform_vertices (&modelview, &projection, viewport, vertices_in, vertices_out, n_vertices); return TRUE; } /** * clutter_actor_apply_transform_to_point: * @self: A #ClutterActor * @point: A point as #ClutterVertex * @vertex: (out caller-allocates): The translated #ClutterVertex * * Transforms @point in coordinates relative to the actor * into screen-relative coordinates with the current actor * transformation (i.e. scale, rotation, etc) * * Since: 0.4 **/ void clutter_actor_apply_transform_to_point (ClutterActor *self, const ClutterVertex *point, ClutterVertex *vertex) { g_return_if_fail (point != NULL); g_return_if_fail (vertex != NULL); _clutter_actor_fully_transform_vertices (self, point, vertex, 1); } /* * _clutter_actor_get_relative_transformation_matrix: * @self: The actor whose coordinate space you want to transform from. * @ancestor: The ancestor actor whose coordinate space you want to transform too * or %NULL if you want to transform all the way to eye coordinates. * @matrix: A #CoglMatrix to store the transformation * * This gets a transformation @matrix that will transform coordinates from the * coordinate space of @self into the coordinate space of @ancestor. * * For example if you need a matrix that can transform the local actor * coordinates of @self into stage coordinates you would pass the actor's stage * pointer as the @ancestor. * * If you pass %NULL then the transformation will take you all the way through * to eye coordinates. This can be useful if you want to extract the entire * modelview transform that Clutter applies before applying the projection * transformation. If you want to explicitly set a modelview on a CoglFramebuffer * using cogl_set_modelview_matrix() for example then you would want a matrix * that transforms into eye coordinates. * * Note: This function explicitly initializes the given @matrix. If you just * want clutter to multiply a relative transformation with an existing matrix * you can use clutter_actor_apply_relative_transformation_matrix() * instead. * */ /* XXX: We should consider caching the stage relative modelview along with * the actor itself */ static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self, ClutterActor *ancestor, CoglMatrix *matrix) { cogl_matrix_init_identity (matrix); _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix); } /* Project the given @box into stage window coordinates, writing the * transformed vertices to @verts[]. */ static gboolean _clutter_actor_transform_and_project_box (ClutterActor *self, const ClutterActorBox *box, ClutterVertex verts[]) { ClutterVertex box_vertices[4]; box_vertices[0].x = box->x1; box_vertices[0].y = box->y1; box_vertices[0].z = 0; box_vertices[1].x = box->x2; box_vertices[1].y = box->y1; box_vertices[1].z = 0; box_vertices[2].x = box->x1; box_vertices[2].y = box->y2; box_vertices[2].z = 0; box_vertices[3].x = box->x2; box_vertices[3].y = box->y2; box_vertices[3].z = 0; return _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4); } /** * clutter_actor_get_allocation_vertices: * @self: A #ClutterActor * @ancestor: (allow-none): A #ClutterActor to calculate the vertices * against, or %NULL to use the #ClutterStage * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return * location for an array of 4 #ClutterVertex in which to store the result * * Calculates the transformed coordinates of the four corners of the * actor in the plane of @ancestor. The returned vertices relate to * the #ClutterActorBox coordinates as follows: * * - @verts[0] contains (x1, y1) * - @verts[1] contains (x2, y1) * - @verts[2] contains (x1, y2) * - @verts[3] contains (x2, y2) * * If @ancestor is %NULL the ancestor will be the #ClutterStage. In * this case, the coordinates returned will be the coordinates on * the stage before the projection is applied. This is different from * the behaviour of clutter_actor_get_abs_allocation_vertices(). * * Since: 0.6 */ void clutter_actor_get_allocation_vertices (ClutterActor *self, ClutterActor *ancestor, ClutterVertex verts[]) { ClutterActorPrivate *priv; ClutterActorBox box; ClutterVertex vertices[4]; CoglMatrix modelview; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor)); if (ancestor == NULL) ancestor = _clutter_actor_get_stage_internal (self); /* Fallback to a NOP transform if the actor isn't parented under a * stage. */ if (ancestor == NULL) ancestor = self; priv = self->priv; /* if the actor needs to be allocated we force a relayout, so that * we will have valid values to use in the transformations */ if (priv->needs_allocation) { ClutterActor *stage = _clutter_actor_get_stage_internal (self); if (stage) _clutter_stage_maybe_relayout (stage); else { box.x1 = box.y1 = 0; /* The result isn't really meaningful in this case but at * least try to do something *vaguely* reasonable... */ clutter_actor_get_size (self, &box.x2, &box.y2); } } clutter_actor_get_allocation_box (self, &box); vertices[0].x = box.x1; vertices[0].y = box.y1; vertices[0].z = 0; vertices[1].x = box.x2; vertices[1].y = box.y1; vertices[1].z = 0; vertices[2].x = box.x1; vertices[2].y = box.y2; vertices[2].z = 0; vertices[3].x = box.x2; vertices[3].y = box.y2; vertices[3].z = 0; _clutter_actor_get_relative_transformation_matrix (self, ancestor, &modelview); cogl_matrix_transform_points (&modelview, 3, sizeof (ClutterVertex), vertices, sizeof (ClutterVertex), vertices, 4); } /** * clutter_actor_get_abs_allocation_vertices: * @self: A #ClutterActor * @verts: (out) (array fixed-size=4): Pointer to a location of an array * of 4 #ClutterVertex where to store the result. * * Calculates the transformed screen coordinates of the four corners of * the actor; the returned vertices relate to the #ClutterActorBox * coordinates as follows: * * - v[0] contains (x1, y1) * - v[1] contains (x2, y1) * - v[2] contains (x1, y2) * - v[3] contains (x2, y2) * * Since: 0.4 */ void clutter_actor_get_abs_allocation_vertices (ClutterActor *self, ClutterVertex verts[]) { ClutterActorPrivate *priv; ClutterActorBox actor_space_allocation; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; /* if the actor needs to be allocated we force a relayout, so that * the actor allocation box will be valid for * _clutter_actor_transform_and_project_box() */ if (priv->needs_allocation) { ClutterActor *stage = _clutter_actor_get_stage_internal (self); /* There's nothing meaningful we can do now */ if (!stage) return; _clutter_stage_maybe_relayout (stage); } /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's * own coordinate space... */ actor_space_allocation.x1 = 0; actor_space_allocation.y1 = 0; actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1; actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1; _clutter_actor_transform_and_project_box (self, &actor_space_allocation, verts); } static void clutter_actor_real_apply_transform (ClutterActor *self, ClutterMatrix *matrix) { ClutterActorPrivate *priv = self->priv; CoglMatrix *transform = &priv->transform; const ClutterTransformInfo *info; float pivot_x = 0.f, pivot_y = 0.f; /* we already have a cached transformation */ if (priv->transform_valid) goto multiply_and_return; info = _clutter_actor_get_transform_info_or_defaults (self); /* compute the pivot point given the allocated size */ pivot_x = (priv->allocation.x2 - priv->allocation.x1) * info->pivot.x; pivot_y = (priv->allocation.y2 - priv->allocation.y1) * info->pivot.y; CLUTTER_NOTE (PAINT, "Allocation: (%.2f, %2.f), " "pivot: (%.2f, %.2f), " "translation: (%.2f, %.2f) -> " "new origin: (%.2f, %.2f)", priv->allocation.x1, priv->allocation.y1, info->pivot.x, info->pivot.y, info->translation.x, info->translation.y, priv->allocation.x1 + pivot_x + info->translation.x, priv->allocation.y1 + pivot_y + info->translation.y); /* we apply the :child-transform from the parent actor, if we have one */ if (priv->parent != NULL) { const ClutterTransformInfo *parent_info; parent_info = _clutter_actor_get_transform_info_or_defaults (priv->parent); clutter_matrix_init_from_matrix (transform, &(parent_info->child_transform)); } else clutter_matrix_init_identity (transform); /* if we have an overriding transformation, we use that, and get out */ if (info->transform_set) { /* we still need to apply the :allocation's origin and :pivot-point * translations, since :transform is relative to the actor's coordinate * space, and to the pivot point */ cogl_matrix_translate (transform, priv->allocation.x1 + pivot_x, priv->allocation.y1 + pivot_y, info->pivot_z); cogl_matrix_multiply (transform, transform, &info->transform); goto roll_back_pivot; } /* basic translation: :allocation's origin and :z-position; instead * of decomposing the pivot and translation info separate operations, * we just compose everything into a single translation */ cogl_matrix_translate (transform, priv->allocation.x1 + pivot_x + info->translation.x, priv->allocation.y1 + pivot_y + info->translation.y, info->z_position + info->pivot_z + info->translation.z); /* because the rotation involves translations, we must scale * before applying the rotations (if we apply the scale after * the rotations, the translations included in the rotation are * not scaled and so the entire object will move on the screen * as a result of rotating it). * * XXX:2.0 the comment has to be reworded once we remove the * per-transformation centers; we also may want to apply rotation * first and scaling after, to match the matrix decomposition * code we use when interpolating transformations */ if (info->scale_x != 1.0 || info->scale_y != 1.0 || info->scale_z != 1.0) { /* XXX:2.0 remove anchor coord */ TRANSFORM_ABOUT_ANCHOR_COORD (self, transform, &info->scale_center, cogl_matrix_scale (transform, info->scale_x, info->scale_y, info->scale_z)); } if (info->rz_angle) { /* XXX:2.0 remove anchor coord */ TRANSFORM_ABOUT_ANCHOR_COORD (self, transform, &info->rz_center, cogl_matrix_rotate (transform, info->rz_angle, 0, 0, 1.0)); } if (info->ry_angle) { /* XXX:2.0 remove anchor coord */ TRANSFORM_ABOUT_ANCHOR_COORD (self, transform, &info->ry_center, cogl_matrix_rotate (transform, info->ry_angle, 0, 1.0, 0)); } if (info->rx_angle) { /* XXX:2.0 remove anchor coord */ TRANSFORM_ABOUT_ANCHOR_COORD (self, transform, &info->rx_center, cogl_matrix_rotate (transform, info->rx_angle, 1.0, 0, 0)); } /* XXX:2.0 remove anchor point translation */ if (!clutter_anchor_coord_is_zero (&info->anchor)) { gfloat x, y, z; clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z); cogl_matrix_translate (transform, -x, -y, -z); } roll_back_pivot: /* roll back the pivot translation */ if (pivot_x != 0.f || pivot_y != 0.f || info->pivot_z != 0.f) cogl_matrix_translate (transform, -pivot_x, -pivot_y, -info->pivot_z); /* we have a valid modelview */ priv->transform_valid = TRUE; multiply_and_return: cogl_matrix_multiply (matrix, matrix, &priv->transform); } /* Applies the transforms associated with this actor to the given * matrix. */ void _clutter_actor_apply_modelview_transform (ClutterActor *self, ClutterMatrix *matrix) { CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix); } /* * clutter_actor_apply_relative_transformation_matrix: * @self: The actor whose coordinate space you want to transform from. * @ancestor: The ancestor actor whose coordinate space you want to transform too * or %NULL if you want to transform all the way to eye coordinates. * @matrix: A #ClutterMatrix to apply the transformation too. * * This multiplies a transform with @matrix that will transform coordinates * from the coordinate space of @self into the coordinate space of @ancestor. * * For example if you need a matrix that can transform the local actor * coordinates of @self into stage coordinates you would pass the actor's stage * pointer as the @ancestor. * * If you pass %NULL then the transformation will take you all the way through * to eye coordinates. This can be useful if you want to extract the entire * modelview transform that Clutter applies before applying the projection * transformation. If you want to explicitly set a modelview on a CoglFramebuffer * using cogl_set_modelview_matrix() for example then you would want a matrix * that transforms into eye coordinates. * * This function doesn't initialize the given @matrix, it simply * multiplies the requested transformation matrix with the existing contents of * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix * before calling this function, or you can use * clutter_actor_get_relative_transformation_matrix() instead. */ void _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self, ClutterActor *ancestor, CoglMatrix *matrix) { ClutterActor *parent; /* Note we terminate before ever calling stage->apply_transform() * since that would conceptually be relative to the underlying * window OpenGL coordinates so we'd need a special @ancestor * value to represent the fake parent of the stage. */ if (self == ancestor) return; parent = clutter_actor_get_parent (self); if (parent != NULL) _clutter_actor_apply_relative_transformation_matrix (parent, ancestor, matrix); _clutter_actor_apply_modelview_transform (self, matrix); } static void _clutter_actor_draw_paint_volume_full (ClutterActor *self, ClutterPaintVolume *pv, const char *label, const CoglColor *color) { static CoglPipeline *outline = NULL; CoglPrimitive *prim; ClutterVertex line_ends[12 * 2]; int n_vertices; CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); /* XXX: at some point we'll query this from the stage but we can't * do that until the osx backend uses Cogl natively. */ CoglFramebuffer *fb = cogl_get_draw_framebuffer (); if (outline == NULL) outline = cogl_pipeline_new (ctx); _clutter_paint_volume_complete (pv); n_vertices = pv->is_2d ? 4 * 2 : 12 * 2; /* Front face */ line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1]; line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2]; line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3]; line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0]; if (!pv->is_2d) { /* Back face */ line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5]; line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6]; line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7]; line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4]; /* Lines connecting front face to back face */ line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4]; line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5]; line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6]; line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7]; } prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES, n_vertices, (CoglVertexP3 *)line_ends); cogl_pipeline_set_color (outline, color); cogl_framebuffer_draw_primitive (fb, outline, prim); cogl_object_unref (prim); if (label) { PangoLayout *layout; layout = pango_layout_new (clutter_actor_get_pango_context (self)); pango_layout_set_text (layout, label, -1); cogl_pango_render_layout (layout, pv->vertices[0].x, pv->vertices[0].y, color, 0); g_object_unref (layout); } } static void _clutter_actor_draw_paint_volume (ClutterActor *self) { ClutterPaintVolume *pv; CoglColor color; pv = _clutter_actor_get_paint_volume_mutable (self); if (!pv) { gfloat width, height; ClutterPaintVolume fake_pv; ClutterActor *stage = _clutter_actor_get_stage_internal (self); _clutter_paint_volume_init_static (&fake_pv, stage); clutter_actor_get_size (self, &width, &height); clutter_paint_volume_set_width (&fake_pv, width); clutter_paint_volume_set_height (&fake_pv, height); cogl_color_init_from_4f (&color, 0, 0, 1, 1); _clutter_actor_draw_paint_volume_full (self, &fake_pv, _clutter_actor_get_debug_name (self), &color); clutter_paint_volume_free (&fake_pv); } else { cogl_color_init_from_4f (&color, 0, 1, 0, 1); _clutter_actor_draw_paint_volume_full (self, pv, _clutter_actor_get_debug_name (self), &color); } } static void _clutter_actor_paint_cull_result (ClutterActor *self, gboolean success, ClutterCullResult result) { ClutterPaintVolume *pv; CoglColor color; if (success) { if (result == CLUTTER_CULL_RESULT_IN) cogl_color_init_from_4f (&color, 0, 1, 0, 1); else if (result == CLUTTER_CULL_RESULT_OUT) cogl_color_init_from_4f (&color, 0, 0, 1, 1); else cogl_color_init_from_4f (&color, 0, 1, 1, 1); } else cogl_color_init_from_4f (&color, 1, 1, 1, 1); if (success && (pv = _clutter_actor_get_paint_volume_mutable (self))) _clutter_actor_draw_paint_volume_full (self, pv, _clutter_actor_get_debug_name (self), &color); else { PangoLayout *layout; char *label = g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self)); cogl_color_init_from_4f (&color, 1, 1, 1, 1); cogl_set_source_color (&color); layout = pango_layout_new (clutter_actor_get_pango_context (self)); pango_layout_set_text (layout, label, -1); cogl_pango_render_layout (layout, 0, 0, &color, 0); free (label); g_object_unref (layout); } } static int clone_paint_level = 0; void _clutter_actor_push_clone_paint (void) { clone_paint_level++; } void _clutter_actor_pop_clone_paint (void) { clone_paint_level--; } static gboolean in_clone_paint (void) { return clone_paint_level > 0; } /* Returns TRUE if the actor can be ignored */ /* FIXME: we should return a ClutterCullResult, and * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN * means there's no point in trying to cull descendants of the current * node. */ static gboolean cull_actor (ClutterActor *self, ClutterCullResult *result_out) { ClutterActorPrivate *priv = self->priv; ClutterStage *stage; const ClutterPlane *stage_clip; if (!priv->last_paint_volume_valid) { CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): " "->last_paint_volume_valid == FALSE", _clutter_actor_get_debug_name (self)); return FALSE; } if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING)) return FALSE; stage = (ClutterStage *) _clutter_actor_get_stage_internal (self); stage_clip = _clutter_stage_get_clip (stage); if (G_UNLIKELY (!stage_clip)) { CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): " "No stage clip set", _clutter_actor_get_debug_name (self)); return FALSE; } if (cogl_get_draw_framebuffer () != _clutter_stage_get_active_framebuffer (stage)) { CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): " "Current framebuffer doesn't correspond to stage", _clutter_actor_get_debug_name (self)); return FALSE; } *result_out = _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip); return TRUE; } static void _clutter_actor_update_last_paint_volume (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; const ClutterPaintVolume *pv; if (priv->last_paint_volume_valid) { clutter_paint_volume_free (&priv->last_paint_volume); priv->last_paint_volume_valid = FALSE; } pv = clutter_actor_get_paint_volume (self); if (!pv) { CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): " "Actor failed to report a paint volume", _clutter_actor_get_debug_name (self)); return; } _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume); _clutter_paint_volume_transform_relative (&priv->last_paint_volume, NULL); /* eye coordinates */ priv->last_paint_volume_valid = TRUE; } static inline gboolean actor_has_shader_data (ClutterActor *self) { return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL; } guint32 _clutter_actor_get_pick_id (ClutterActor *self) { if (self->priv->pick_id < 0) return 0; return self->priv->pick_id; } /* This is the same as clutter_actor_add_effect except that it doesn't queue a redraw and it doesn't notify on the effect property */ static void _clutter_actor_add_effect_internal (ClutterActor *self, ClutterEffect *effect) { ClutterActorPrivate *priv = self->priv; if (priv->effects == NULL) { priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL); priv->effects->actor = self; } _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect)); } /* This is the same as clutter_actor_remove_effect except that it doesn't queue a redraw and it doesn't notify on the effect property */ static void _clutter_actor_remove_effect_internal (ClutterActor *self, ClutterEffect *effect) { ClutterActorPrivate *priv = self->priv; if (priv->effects == NULL) return; _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect)); if (_clutter_meta_group_peek_metas (priv->effects) == NULL) g_clear_object (&priv->effects); } static gboolean needs_flatten_effect (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT)) return FALSE; if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS) return TRUE; else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY) { if (clutter_actor_get_paint_opacity (self) < 255 && clutter_actor_has_overlaps (self)) return TRUE; } return FALSE; } static void add_or_remove_flatten_effect (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; /* Add or remove the flatten effect depending on the offscreen-redirect property. */ if (needs_flatten_effect (self)) { if (priv->flatten_effect == NULL) { ClutterActorMeta *actor_meta; gint priority; priv->flatten_effect = _clutter_flatten_effect_new (); /* Keep a reference to the effect so that we can queue redraws from it */ g_object_ref_sink (priv->flatten_effect); /* Set the priority of the effect to high so that it will always be applied to the actor first. It uses an internal priority so that it won't be visible to applications */ actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect); priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH; _clutter_actor_meta_set_priority (actor_meta, priority); /* This will add the effect without queueing a redraw */ _clutter_actor_add_effect_internal (self, priv->flatten_effect); } } else { if (priv->flatten_effect != NULL) { /* Destroy the effect so that it will lose its fbo cache of the actor */ _clutter_actor_remove_effect_internal (self, priv->flatten_effect); g_clear_object (&priv->flatten_effect); } } } static void clutter_actor_real_paint (ClutterActor *actor) { ClutterActorPrivate *priv = actor->priv; ClutterActor *iter; for (iter = priv->first_child; iter != NULL; iter = iter->priv->next_sibling) { CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }", _clutter_actor_get_debug_name (iter), _clutter_actor_get_debug_name (actor), iter->priv->allocation.x1, iter->priv->allocation.y1, iter->priv->allocation.x2 - iter->priv->allocation.x1, iter->priv->allocation.y2 - iter->priv->allocation.y1); clutter_actor_paint (iter); } } static gboolean clutter_actor_paint_node (ClutterActor *actor, ClutterPaintNode *root) { ClutterActorPrivate *priv = actor->priv; ClutterActorBox box; ClutterColor bg_color; if (root == NULL) return FALSE; box.x1 = 0.f; box.y1 = 0.f; box.x2 = clutter_actor_box_get_width (&priv->allocation); box.y2 = clutter_actor_box_get_height (&priv->allocation); bg_color = priv->bg_color; if (CLUTTER_ACTOR_IS_TOPLEVEL (actor)) { ClutterPaintNode *node; CoglFramebuffer *fb; CoglBufferBit clear_flags; fb = _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (actor)); if (clutter_stage_get_use_alpha (CLUTTER_STAGE (actor))) { bg_color.alpha = priv->opacity * priv->bg_color.alpha / 255; } else bg_color.alpha = 255; CLUTTER_NOTE (PAINT, "Stage clear color: (%d, %d, %d, %d)", bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha); clear_flags = COGL_BUFFER_BIT_DEPTH; if (!clutter_stage_get_no_clear_hint (CLUTTER_STAGE (actor))) clear_flags |= COGL_BUFFER_BIT_COLOR; node = _clutter_root_node_new (fb, &bg_color, clear_flags); clutter_paint_node_set_name (node, "stageClear"); clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); } else if (priv->bg_color_set && !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent)) { ClutterPaintNode *node; bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor) * priv->bg_color.alpha / 255; node = clutter_color_node_new (&bg_color); clutter_paint_node_set_name (node, "backgroundColor"); clutter_paint_node_add_rectangle (node, &box); clutter_paint_node_add_child (root, node); clutter_paint_node_unref (node); } if (priv->content != NULL) _clutter_content_paint_content (priv->content, actor, root); if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL) CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root); if (clutter_paint_node_get_n_children (root) == 0) return FALSE; #ifdef CLUTTER_ENABLE_DEBUG if (CLUTTER_HAS_DEBUG (PAINT)) { /* dump the tree only if we have one */ _clutter_paint_node_dump_tree (root); } #endif /* CLUTTER_ENABLE_DEBUG */ _clutter_paint_node_paint (root); return TRUE; } /** * clutter_actor_paint: * @self: A #ClutterActor * * Renders the actor to display. * * This function should not be called directly by applications. * Call clutter_actor_queue_redraw() to queue paints, instead. * * This function is context-aware, and will either cause a * regular paint or a pick paint. * * This function will emit the #ClutterActor::paint signal or * the #ClutterActor::pick signal, depending on the context. * * This function does not paint the actor if the actor is set to 0, * unless it is performing a pick paint. */ void clutter_actor_paint (ClutterActor *self) { ClutterActorPrivate *priv; ClutterPickMode pick_mode; gboolean clip_set = FALSE; gboolean shader_applied = FALSE; ClutterStage *stage; g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) return; priv = self->priv; pick_mode = _clutter_context_get_pick_mode (); if (pick_mode == CLUTTER_PICK_NONE) priv->propagated_one_redraw = FALSE; /* It's an important optimization that we consider painting of * actors with 0 opacity to be a NOP... */ if (pick_mode == CLUTTER_PICK_NONE && /* ignore top-levels, since they might be transparent */ !CLUTTER_ACTOR_IS_TOPLEVEL (self) && /* Use the override opacity if its been set */ ((priv->opacity_override >= 0) ? priv->opacity_override : priv->opacity) == 0) return; /* if we aren't paintable (not in a toplevel with all * parents paintable) then do nothing. */ if (!CLUTTER_ACTOR_IS_MAPPED (self)) return; stage = (ClutterStage *) _clutter_actor_get_stage_internal (self); /* mark that we are in the paint process */ CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT); cogl_push_matrix (); if (priv->enable_model_view_transform) { CoglMatrix matrix; /* XXX: It could be better to cache the modelview with the actor * instead of progressively building up the transformations on * the matrix stack every time we paint. */ cogl_get_modelview_matrix (&matrix); _clutter_actor_apply_modelview_transform (self, &matrix); #ifdef CLUTTER_ENABLE_DEBUG /* Catch when out-of-band transforms have been made by actors not as part * of an apply_transform vfunc... */ if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS)) { CoglMatrix expected_matrix; _clutter_actor_get_relative_transformation_matrix (self, NULL, &expected_matrix); if (!cogl_matrix_equal (&matrix, &expected_matrix)) { GString *buf = g_string_sized_new (1024); ClutterActor *parent; parent = self; while (parent != NULL) { g_string_append (buf, _clutter_actor_get_debug_name (parent)); if (parent->priv->parent != NULL) g_string_append (buf, "->"); parent = parent->priv->parent; } g_warning ("Unexpected transform found when painting actor " "\"%s\". This will be caused by one of the actor's " "ancestors (%s) using the Cogl API directly to transform " "children instead of using ::apply_transform().", _clutter_actor_get_debug_name (self), buf->str); g_string_free (buf, TRUE); } } #endif /* CLUTTER_ENABLE_DEBUG */ cogl_set_modelview_matrix (&matrix); } if (priv->has_clip) { CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage); cogl_framebuffer_push_rectangle_clip (fb, priv->clip.origin.x, priv->clip.origin.y, priv->clip.origin.x + priv->clip.size.width, priv->clip.origin.y + priv->clip.size.height); clip_set = TRUE; } else if (priv->clip_to_allocation) { CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage); gfloat width, height; width = priv->allocation.x2 - priv->allocation.x1; height = priv->allocation.y2 - priv->allocation.y1; cogl_framebuffer_push_rectangle_clip (fb, 0, 0, width, height); clip_set = TRUE; } if (pick_mode == CLUTTER_PICK_NONE) { /* We check whether we need to add the flatten effect before each paint so that we can avoid having a mechanism for applications to notify when the value of the has_overlaps virtual changes. */ add_or_remove_flatten_effect (self); } /* We save the current paint volume so that the next time the * actor queues a redraw we can constrain the redraw to just * cover the union of the new bounding box and the old. * * We also fetch the current paint volume to perform culling so * we can avoid painting actors outside the current clip region. * * If we are painting inside a clone, we should neither update * the paint volume or use it to cull painting, since the paint * box represents the location of the source actor on the * screen. * * XXX: We are starting to do a lot of vertex transforms on * the CPU in a typical paint, so at some point we should * audit these and consider caching some things. * * NB: We don't perform culling while picking at this point because * clutter-stage.c doesn't setup the clipping planes appropriately. * * NB: We don't want to update the last-paint-volume during picking * because the last-paint-volume is used to determine the old screen * space location of an actor that has moved so we can know the * minimal region to redraw to clear an old view of the actor. If we * update this during picking then by the time we come around to * paint then the last-paint-volume would likely represent the new * actor position not the old. */ if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE) { gboolean success; /* annoyingly gcc warns if uninitialized even though * the initialization is redundant :-( */ ClutterCullResult result = CLUTTER_CULL_RESULT_IN; if (G_LIKELY ((clutter_paint_debug_flags & (CLUTTER_DEBUG_DISABLE_CULLING | CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) != (CLUTTER_DEBUG_DISABLE_CULLING | CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS))) _clutter_actor_update_last_paint_volume (self); success = cull_actor (self, &result); if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)) _clutter_actor_paint_cull_result (self, success, result); else if (result == CLUTTER_CULL_RESULT_OUT && success) goto done; } if (priv->effects == NULL) { if (pick_mode == CLUTTER_PICK_NONE && actor_has_shader_data (self)) { _clutter_actor_shader_pre_paint (self, FALSE); shader_applied = TRUE; } priv->next_effect_to_paint = NULL; } else priv->next_effect_to_paint = _clutter_meta_group_peek_metas (priv->effects); clutter_actor_continue_paint (self); if (shader_applied) _clutter_actor_shader_post_paint (self); if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES && pick_mode == CLUTTER_PICK_NONE)) _clutter_actor_draw_paint_volume (self); /* If we make it here then the actor has run through a complete paint run including all the effects so it's no longer dirty */ if (pick_mode == CLUTTER_PICK_NONE) priv->is_dirty = FALSE; done: if (clip_set) { CoglFramebuffer *fb = _clutter_stage_get_active_framebuffer (stage); cogl_framebuffer_pop_clip (fb); } cogl_pop_matrix (); /* paint sequence complete */ CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT); } /** * clutter_actor_continue_paint: * @self: A #ClutterActor * * Run the next stage of the paint sequence. This function should only * be called within the implementation of the ‘run’ virtual of a * #ClutterEffect. It will cause the run method of the next effect to * be applied, or it will paint the actual actor if the current effect * is the last effect in the chain. * * Since: 1.8 */ void clutter_actor_continue_paint (ClutterActor *self) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); /* This should only be called from with in the ‘run’ implementation of a ClutterEffect */ g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self)); priv = self->priv; /* Skip any effects that are disabled */ while (priv->next_effect_to_paint && !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data)) priv->next_effect_to_paint = priv->next_effect_to_paint->next; /* If this has come from the last effect then we'll just paint the actual actor */ if (priv->next_effect_to_paint == NULL) { if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE) { ClutterPaintNode *dummy; /* XXX - this will go away in 2.0, when we can get rid of this * stuff and switch to a pure retained render tree of PaintNodes * for the entire frame, starting from the Stage; the paint() * virtual function can then be called directly. */ dummy = _clutter_dummy_node_new (self); clutter_paint_node_set_name (dummy, "Root"); /* XXX - for 1.12, we use the return value of paint_node() to * decide whether we should emit the ::paint signal. */ clutter_actor_paint_node (self, dummy); clutter_paint_node_unref (dummy); /* XXX:2.0 - Call the paint() virtual directly */ if (g_signal_has_handler_pending (self, actor_signals[PAINT], 0, TRUE)) g_signal_emit (self, actor_signals[PAINT], 0); else CLUTTER_ACTOR_GET_CLASS (self)->paint (self); } else { ClutterColor col = { 0, }; _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col); /* Actor will then paint silhouette of itself in supplied * color. See clutter_stage_get_actor_at_pos() for where * picking is enabled. * * XXX:2.0 - Call the pick() virtual directly */ if (g_signal_has_handler_pending (self, actor_signals[PICK], 0, TRUE)) g_signal_emit (self, actor_signals[PICK], 0, &col); else CLUTTER_ACTOR_GET_CLASS (self)->pick (self, &col); } } else { ClutterEffect *old_current_effect; ClutterEffectPaintFlags run_flags = 0; /* Cache the current effect so that we can put it back before returning */ old_current_effect = priv->current_effect; priv->current_effect = priv->next_effect_to_paint->data; priv->next_effect_to_paint = priv->next_effect_to_paint->next; if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE) { if (priv->is_dirty) { /* If there's an effect queued with this redraw then all effects up to that one will be considered dirty. It is expected the queued effect will paint the cached image and not call clutter_actor_continue_paint again (although it should work ok if it does) */ if (priv->effect_to_redraw == NULL || priv->current_effect != priv->effect_to_redraw) run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY; } _clutter_effect_paint (priv->current_effect, run_flags); } else { /* We can't determine when an actor has been modified since its last pick so lets just assume it has always been modified */ run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY; _clutter_effect_pick (priv->current_effect, run_flags); } priv->current_effect = old_current_effect; } } static void _clutter_actor_stop_transitions (ClutterActor *self) { const ClutterAnimationInfo *info; GHashTableIter iter; gpointer value; info = _clutter_actor_get_animation_info_or_defaults (self); if (info->transitions == NULL) return; g_hash_table_iter_init (&iter, info->transitions); while (g_hash_table_iter_next (&iter, NULL, &value)) { TransitionClosure *closure = value; /* implicit transitions, and automatically managed explicit ones, * should be removed at this point */ if (closure->is_implicit || clutter_transition_get_remove_on_complete (closure->transition)) { g_hash_table_iter_remove (&iter); } else { /* otherwise we stop it, and the transition will be removed * later, either by the actor's destruction or by explicit * removal */ clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition)); } } } static ClutterActorTraverseVisitFlags invalidate_queue_redraw_entry (ClutterActor *self, int depth, gpointer user_data) { ClutterActorPrivate *priv = self->priv; if (priv->queue_redraw_entry != NULL) { _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry); priv->queue_redraw_entry = NULL; } return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE; } static inline void remove_child (ClutterActor *self, ClutterActor *child) { ClutterActor *prev_sibling, *next_sibling; prev_sibling = child->priv->prev_sibling; next_sibling = child->priv->next_sibling; if (prev_sibling != NULL) prev_sibling->priv->next_sibling = next_sibling; if (next_sibling != NULL) next_sibling->priv->prev_sibling = prev_sibling; if (self->priv->first_child == child) self->priv->first_child = next_sibling; if (self->priv->last_child == child) self->priv->last_child = prev_sibling; child->priv->parent = NULL; child->priv->prev_sibling = NULL; child->priv->next_sibling = NULL; } typedef enum { REMOVE_CHILD_DESTROY_META = 1 << 0, REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1, REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2, REMOVE_CHILD_CHECK_STATE = 1 << 3, REMOVE_CHILD_FLUSH_QUEUE = 1 << 4, REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5, REMOVE_CHILD_STOP_TRANSITIONS = 1 << 6, /* default flags for public API */ REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS | REMOVE_CHILD_DESTROY_META | REMOVE_CHILD_EMIT_PARENT_SET | REMOVE_CHILD_EMIT_ACTOR_REMOVED | REMOVE_CHILD_CHECK_STATE | REMOVE_CHILD_FLUSH_QUEUE | REMOVE_CHILD_NOTIFY_FIRST_LAST, /* flags for legacy/deprecated API */ REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS | REMOVE_CHILD_CHECK_STATE | REMOVE_CHILD_FLUSH_QUEUE | REMOVE_CHILD_EMIT_PARENT_SET | REMOVE_CHILD_NOTIFY_FIRST_LAST } ClutterActorRemoveChildFlags; /*< private > * clutter_actor_remove_child_internal: * @self: a #ClutterActor * @child: the child of @self that has to be removed * @flags: control the removal operations * * Removes @child from the list of children of @self. */ static void clutter_actor_remove_child_internal (ClutterActor *self, ClutterActor *child, ClutterActorRemoveChildFlags flags) { ClutterActor *old_first, *old_last; gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state; gboolean flush_queue; gboolean notify_first_last; gboolean was_mapped; gboolean stop_transitions; GObject *obj; if (self == child) { g_warning ("Cannot remove actor '%s' from itself.", _clutter_actor_get_debug_name (self)); return; } destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0; emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0; emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0; check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0; flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0; notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0; stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0; obj = G_OBJECT (self); g_object_freeze_notify (obj); if (stop_transitions) _clutter_actor_stop_transitions (child); if (destroy_meta) clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child); if (check_state) { was_mapped = CLUTTER_ACTOR_IS_MAPPED (child); /* we need to unrealize *before* we set parent_actor to NULL, * because in an unrealize method actors are dissociating from the * stage, which means they need to be able to * clutter_actor_get_stage(). * * yhis should unmap and unrealize, unless we're reparenting. */ clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED); } else was_mapped = FALSE; if (flush_queue) { /* We take this opportunity to invalidate any queue redraw entry * associated with the actor and descendants since we won't be able to * determine the appropriate stage after this. * * we do this after we updated the mapped state because actors might * end up queueing redraws inside their mapped/unmapped virtual * functions, and if we invalidate the redraw entry we could end up * with an inconsistent state and weird memory corruption. see * bugs: * * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621 * https://bugzilla.gnome.org/show_bug.cgi?id=652036 */ _clutter_actor_traverse (child, 0, invalidate_queue_redraw_entry, NULL, NULL); } old_first = self->priv->first_child; old_last = self->priv->last_child; remove_child (self, child); self->priv->n_children -= 1; self->priv->age += 1; /* if the child that got removed was visible and set to * expand then we want to reset the parent's state in * case the child was the only thing that was making it * expand. */ if (CLUTTER_ACTOR_IS_VISIBLE (child) && (child->priv->needs_compute_expand || child->priv->needs_x_expand || child->priv->needs_y_expand)) { clutter_actor_queue_compute_expand (self); } /* clutter_actor_reparent() will emit ::parent-set for us */ if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child)) g_signal_emit (child, actor_signals[PARENT_SET], 0, self); /* if the child was mapped then we need to relayout ourselves to account * for the removed child */ if (was_mapped) clutter_actor_queue_relayout (self); /* we need to emit the signal before dropping the reference */ if (emit_actor_removed) g_signal_emit_by_name (self, "actor-removed", child); if (notify_first_last) { if (old_first != self->priv->first_child) g_object_notify_by_pspec (obj, obj_props[PROP_FIRST_CHILD]); if (old_last != self->priv->last_child) g_object_notify_by_pspec (obj, obj_props[PROP_LAST_CHILD]); } g_object_thaw_notify (obj); /* remove the reference we acquired in clutter_actor_add_child() */ g_object_unref (child); } static const ClutterTransformInfo default_transform_info = { 0.0, { 0, }, /* rotation-x */ 0.0, { 0, }, /* rotation-y */ 0.0, { 0, }, /* rotation-z */ 1.0, 1.0, 1.0, { 0, }, /* scale */ { 0, }, /* anchor XXX:2.0 - remove*/ CLUTTER_VERTEX_INIT_ZERO, /* translation */ 0.f, /* z-position */ CLUTTER_POINT_INIT_ZERO, /* pivot */ 0.f, /* pivot-z */ CLUTTER_MATRIX_INIT_IDENTITY, FALSE, /* transform */ CLUTTER_MATRIX_INIT_IDENTITY, FALSE, /* child-transform */ }; /*< private > * _clutter_actor_get_transform_info_or_defaults: * @self: a #ClutterActor * * Retrieves the ClutterTransformInfo structure associated to an actor. * * If the actor does not have a ClutterTransformInfo structure associated * to it, then the default structure will be returned. * * This function should only be used for getters. * * Return value: a const pointer to the ClutterTransformInfo structure */ const ClutterTransformInfo * _clutter_actor_get_transform_info_or_defaults (ClutterActor *self) { ClutterTransformInfo *info; info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info); if (info != NULL) return info; return &default_transform_info; } static void clutter_transform_info_free (gpointer data) { if (data != NULL) g_slice_free (ClutterTransformInfo, data); } /*< private > * _clutter_actor_get_transform_info: * @self: a #ClutterActor * * Retrieves a pointer to the ClutterTransformInfo structure. * * If the actor does not have a ClutterTransformInfo associated to it, one * will be created and initialized to the default values. * * This function should be used for setters. * * For getters, you should use _clutter_actor_get_transform_info_or_defaults() * instead. * * Return value: (transfer none): a pointer to the ClutterTransformInfo * structure */ ClutterTransformInfo * _clutter_actor_get_transform_info (ClutterActor *self) { ClutterTransformInfo *info; info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info); if (info == NULL) { info = g_slice_new (ClutterTransformInfo); *info = default_transform_info; g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info, info, clutter_transform_info_free); } return info; } static inline void clutter_actor_set_pivot_point_internal (ClutterActor *self, const ClutterPoint *pivot) { ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); info->pivot = *pivot; self->priv->transform_valid = FALSE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PIVOT_POINT]); clutter_actor_queue_redraw (self); } static inline void clutter_actor_set_pivot_point_z_internal (ClutterActor *self, float pivot_z) { ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); info->pivot_z = pivot_z; self->priv->transform_valid = FALSE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PIVOT_POINT_Z]); clutter_actor_queue_redraw (self); } /*< private > * clutter_actor_set_translation_internal: * @self: a #ClutterActor * @axis: the axis of the translation to change * @angle: the translation as a value along @axis * * Sets the translation on the given @axis */ static void clutter_actor_set_translation_internal (ClutterActor *self, gfloat value, GParamSpec *pspec) { GObject *obj = G_OBJECT (self); ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); if (pspec == obj_props[PROP_TRANSLATION_X]) info->translation.x = value; else if (pspec == obj_props[PROP_TRANSLATION_Y]) info->translation.y = value; else if (pspec == obj_props[PROP_TRANSLATION_Z]) info->translation.z = value; else g_assert_not_reached (); self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (obj, pspec); } static inline void clutter_actor_set_translation_factor (ClutterActor *self, ClutterRotateAxis axis, gdouble value) { const ClutterTransformInfo *info; const float *translate_p = NULL; GParamSpec *pspec = NULL; info = _clutter_actor_get_transform_info_or_defaults (self); switch (axis) { case CLUTTER_X_AXIS: pspec = obj_props[PROP_TRANSLATION_X]; translate_p = &info->translation.x; break; case CLUTTER_Y_AXIS: pspec = obj_props[PROP_TRANSLATION_Y]; translate_p = &info->translation.y; break; case CLUTTER_Z_AXIS: pspec = obj_props[PROP_TRANSLATION_Z]; translate_p = &info->translation.z; break; } g_assert (pspec != NULL); g_assert (translate_p != NULL); _clutter_actor_create_transition (self, pspec, *translate_p, value); } /** * clutter_actor_set_translation: * @self: a #ClutterActor * @translate_x: the translation along the X axis * @translate_y: the translation along the Y axis * @translate_z: the translation along the Z axis * * Sets an additional translation transformation on a #ClutterActor, * relative to the #ClutterActor:pivot-point. * * Since: 1.12 */ void clutter_actor_set_translation (ClutterActor *self, gfloat translate_x, gfloat translate_y, gfloat translate_z) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_translation_factor (self, CLUTTER_X_AXIS, translate_x); clutter_actor_set_translation_factor (self, CLUTTER_Y_AXIS, translate_y); clutter_actor_set_translation_factor (self, CLUTTER_Z_AXIS, translate_z); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_get_translation: * @self: a #ClutterActor * @translate_x: (out) (allow-none): return location for the X component * of the translation, or %NULL * @translate_y: (out) (allow-none): return location for the Y component * of the translation, or %NULL * @translate_z: (out) (allow-none): return location for the Z component * of the translation, or %NULL * * Retrieves the translation set using clutter_actor_set_translation(). * * Since: 1.12 */ void clutter_actor_get_translation (ClutterActor *self, gfloat *translate_x, gfloat *translate_y, gfloat *translate_z) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); if (translate_x != NULL) *translate_x = info->translation.x; if (translate_y != NULL) *translate_y = info->translation.y; if (translate_z != NULL) *translate_z = info->translation.z; } /*< private > * clutter_actor_set_rotation_angle_internal: * @self: a #ClutterActor * @angle: the angle of rotation * @pspec: the #GParamSpec of the property * * Sets the rotation angle on the given axis without affecting the * rotation center point. */ static inline void clutter_actor_set_rotation_angle_internal (ClutterActor *self, gdouble angle, GParamSpec *pspec) { ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); if (pspec == obj_props[PROP_ROTATION_ANGLE_X]) info->rx_angle = angle; else if (pspec == obj_props[PROP_ROTATION_ANGLE_Y]) info->ry_angle = angle; else if (pspec == obj_props[PROP_ROTATION_ANGLE_Z]) info->rz_angle = angle; else g_assert_not_reached (); self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), pspec); } /** * clutter_actor_set_rotation_angle: * @self: a #ClutterActor * @axis: the axis to set the angle one * @angle: the angle of rotation, in degrees * * Sets the @angle of rotation of a #ClutterActor on the given @axis. * * This function is a convenience for setting the rotation properties * #ClutterActor:rotation-angle-x, #ClutterActor:rotation-angle-y, * and #ClutterActor:rotation-angle-z. * * The center of rotation is established by the #ClutterActor:pivot-point * property. * * Since: 1.12 */ void clutter_actor_set_rotation_angle (ClutterActor *self, ClutterRotateAxis axis, gdouble angle) { const ClutterTransformInfo *info; const double *cur_angle_p = NULL; GParamSpec *pspec = NULL; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); switch (axis) { case CLUTTER_X_AXIS: cur_angle_p = &info->rx_angle; pspec = obj_props[PROP_ROTATION_ANGLE_X]; break; case CLUTTER_Y_AXIS: cur_angle_p = &info->ry_angle; pspec = obj_props[PROP_ROTATION_ANGLE_Y]; break; case CLUTTER_Z_AXIS: cur_angle_p = &info->rz_angle; pspec = obj_props[PROP_ROTATION_ANGLE_Z]; break; } g_assert (pspec != NULL); g_assert (cur_angle_p != NULL); _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle); } /** * clutter_actor_get_rotation_angle: * @self: a #ClutterActor * @axis: the axis of the rotation * * Retrieves the angle of rotation set by clutter_actor_set_rotation_angle(). * * Return value: the angle of rotation, in degrees * * Since: 1.12 */ gdouble clutter_actor_get_rotation_angle (ClutterActor *self, ClutterRotateAxis axis) { const ClutterTransformInfo *info; gdouble retval; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0); info = _clutter_actor_get_transform_info_or_defaults (self); switch (axis) { case CLUTTER_X_AXIS: retval = info->rx_angle; break; case CLUTTER_Y_AXIS: retval = info->ry_angle; break; case CLUTTER_Z_AXIS: retval = info->rz_angle; break; default: g_warn_if_reached (); retval = 0.0; break; } return retval; } /*< private > * clutter_actor_set_rotation_center_internal: * @self: a #ClutterActor * @axis: the axis of the center to change * @center: the coordinates of the rotation center * * Sets the rotation center on the given axis without affecting the * rotation angle. */ static inline void clutter_actor_set_rotation_center_internal (ClutterActor *self, ClutterRotateAxis axis, const ClutterVertex *center) { ClutterVertex v = CLUTTER_VERTEX_INIT_ZERO; GObject *obj = G_OBJECT (self); ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); if (center != NULL) v = *center; g_object_freeze_notify (obj); switch (axis) { case CLUTTER_X_AXIS: clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z); g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]); break; case CLUTTER_Y_AXIS: clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z); g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]); break; case CLUTTER_Z_AXIS: /* if the previously set rotation center was fractional, then * setting explicit coordinates will have to notify the * :rotation-center-z-gravity property as well */ if (info->rz_center.is_fractional) g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]); clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z); g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]); break; } self->priv->transform_valid = FALSE; g_object_thaw_notify (obj); clutter_actor_queue_redraw (self); } static void clutter_actor_set_scale_factor_internal (ClutterActor *self, double factor, GParamSpec *pspec) { GObject *obj = G_OBJECT (self); ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); if (pspec == obj_props[PROP_SCALE_X]) info->scale_x = factor; else if (pspec == obj_props[PROP_SCALE_Y]) info->scale_y = factor; else if (pspec == obj_props[PROP_SCALE_Z]) info->scale_z = factor; else g_assert_not_reached (); self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (obj, pspec); } static inline void clutter_actor_set_scale_factor (ClutterActor *self, ClutterRotateAxis axis, gdouble factor) { const ClutterTransformInfo *info; const double *scale_p = NULL; GParamSpec *pspec = NULL; info = _clutter_actor_get_transform_info_or_defaults (self); switch (axis) { case CLUTTER_X_AXIS: pspec = obj_props[PROP_SCALE_X]; scale_p = &info->scale_x; break; case CLUTTER_Y_AXIS: pspec = obj_props[PROP_SCALE_Y]; scale_p = &info->scale_y; break; case CLUTTER_Z_AXIS: pspec = obj_props[PROP_SCALE_Z]; scale_p = &info->scale_z; break; } g_assert (pspec != NULL); g_assert (scale_p != NULL); _clutter_actor_create_transition (self, pspec, *scale_p, factor); } static inline void clutter_actor_set_scale_center (ClutterActor *self, ClutterRotateAxis axis, gfloat coord) { GObject *obj = G_OBJECT (self); ClutterTransformInfo *info; gfloat center_x, center_y; info = _clutter_actor_get_transform_info (self); g_object_freeze_notify (obj); /* get the current scale center coordinates */ clutter_anchor_coord_get_units (self, &info->scale_center, ¢er_x, ¢er_y, NULL); /* we need to notify this too, because setting explicit coordinates will * change the gravity as a side effect */ if (info->scale_center.is_fractional) g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]); switch (axis) { case CLUTTER_X_AXIS: clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0); g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]); break; case CLUTTER_Y_AXIS: clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0); g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]); break; default: g_assert_not_reached (); } self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_thaw_notify (obj); } static inline void clutter_actor_set_scale_gravity (ClutterActor *self, ClutterGravity gravity) { ClutterTransformInfo *info; GObject *obj; info = _clutter_actor_get_transform_info (self); obj = G_OBJECT (self); if (gravity == CLUTTER_GRAVITY_NONE) clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0); else clutter_anchor_coord_set_gravity (&info->scale_center, gravity); self->priv->transform_valid = FALSE; g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]); g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]); g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]); clutter_actor_queue_redraw (self); } /* XXX:2.0 - remove */ static inline void clutter_actor_set_anchor_coord (ClutterActor *self, ClutterRotateAxis axis, gfloat coord) { GObject *obj = G_OBJECT (self); ClutterTransformInfo *info; gfloat anchor_x, anchor_y; info = _clutter_actor_get_transform_info (self); g_object_freeze_notify (obj); clutter_anchor_coord_get_units (self, &info->anchor, &anchor_x, &anchor_y, NULL); if (info->anchor.is_fractional) g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]); switch (axis) { case CLUTTER_X_AXIS: clutter_anchor_coord_set_units (&info->anchor, coord, anchor_y, 0.0); g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]); break; case CLUTTER_Y_AXIS: clutter_anchor_coord_set_units (&info->anchor, anchor_x, coord, 0.0); g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]); break; default: g_assert_not_reached (); } self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_thaw_notify (obj); } static void clutter_actor_set_clip_rect (ClutterActor *self, const ClutterRect *clip) { ClutterActorPrivate *priv = self->priv; GObject *obj = G_OBJECT (self); if (clip != NULL) { priv->clip = *clip; priv->has_clip = TRUE; } else priv->has_clip = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (obj, obj_props[PROP_CLIP]); /* XXX:2.0 - remove */ g_object_notify_by_pspec (obj, obj_props[PROP_CLIP_RECT]); g_object_notify_by_pspec (obj, obj_props[PROP_HAS_CLIP]); } static void clutter_actor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterActor *actor = CLUTTER_ACTOR (object); ClutterActorPrivate *priv = actor->priv; switch (prop_id) { case PROP_X: clutter_actor_set_x (actor, g_value_get_float (value)); break; case PROP_Y: clutter_actor_set_y (actor, g_value_get_float (value)); break; case PROP_POSITION: { const ClutterPoint *pos = g_value_get_boxed (value); if (pos != NULL) clutter_actor_set_position (actor, pos->x, pos->y); else clutter_actor_set_fixed_position_set (actor, FALSE); } break; case PROP_WIDTH: clutter_actor_set_width (actor, g_value_get_float (value)); break; case PROP_HEIGHT: clutter_actor_set_height (actor, g_value_get_float (value)); break; case PROP_SIZE: { const ClutterSize *size = g_value_get_boxed (value); if (size != NULL) clutter_actor_set_size (actor, size->width, size->height); else clutter_actor_set_size (actor, -1, -1); } break; case PROP_FIXED_X: clutter_actor_set_x (actor, g_value_get_float (value)); break; case PROP_FIXED_Y: clutter_actor_set_y (actor, g_value_get_float (value)); break; case PROP_FIXED_POSITION_SET: clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value)); break; case PROP_MIN_WIDTH: clutter_actor_set_min_width (actor, g_value_get_float (value)); break; case PROP_MIN_HEIGHT: clutter_actor_set_min_height (actor, g_value_get_float (value)); break; case PROP_NATURAL_WIDTH: clutter_actor_set_natural_width (actor, g_value_get_float (value)); break; case PROP_NATURAL_HEIGHT: clutter_actor_set_natural_height (actor, g_value_get_float (value)); break; case PROP_MIN_WIDTH_SET: clutter_actor_set_min_width_set (actor, g_value_get_boolean (value)); break; case PROP_MIN_HEIGHT_SET: clutter_actor_set_min_height_set (actor, g_value_get_boolean (value)); break; case PROP_NATURAL_WIDTH_SET: clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value)); break; case PROP_NATURAL_HEIGHT_SET: clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value)); break; case PROP_REQUEST_MODE: clutter_actor_set_request_mode (actor, g_value_get_enum (value)); break; case PROP_DEPTH: /* XXX:2.0 - remove */ clutter_actor_set_depth (actor, g_value_get_float (value)); break; case PROP_Z_POSITION: clutter_actor_set_z_position (actor, g_value_get_float (value)); break; case PROP_OPACITY: clutter_actor_set_opacity (actor, g_value_get_uint (value)); break; case PROP_OFFSCREEN_REDIRECT: clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value)); break; case PROP_NAME: clutter_actor_set_name (actor, g_value_get_string (value)); break; case PROP_VISIBLE: if (g_value_get_boolean (value) == TRUE) clutter_actor_show (actor); else clutter_actor_hide (actor); break; case PROP_PIVOT_POINT: { const ClutterPoint *pivot = g_value_get_boxed (value); if (pivot == NULL) pivot = clutter_point_zero (); clutter_actor_set_pivot_point (actor, pivot->x, pivot->y); } break; case PROP_PIVOT_POINT_Z: clutter_actor_set_pivot_point_z (actor, g_value_get_float (value)); break; case PROP_TRANSLATION_X: clutter_actor_set_translation_factor (actor, CLUTTER_X_AXIS, g_value_get_float (value)); break; case PROP_TRANSLATION_Y: clutter_actor_set_translation_factor (actor, CLUTTER_Y_AXIS, g_value_get_float (value)); break; case PROP_TRANSLATION_Z: clutter_actor_set_translation_factor (actor, CLUTTER_Z_AXIS, g_value_get_float (value)); break; case PROP_SCALE_X: clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS, g_value_get_double (value)); break; case PROP_SCALE_Y: clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS, g_value_get_double (value)); break; case PROP_SCALE_Z: clutter_actor_set_scale_factor (actor, CLUTTER_Z_AXIS, g_value_get_double (value)); break; case PROP_SCALE_CENTER_X: /* XXX:2.0 - remove */ clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS, g_value_get_float (value)); break; case PROP_SCALE_CENTER_Y: /* XXX:2.0 - remove */ clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS, g_value_get_float (value)); break; case PROP_SCALE_GRAVITY: /* XXX:2.0 - remove */ clutter_actor_set_scale_gravity (actor, g_value_get_enum (value)); break; case PROP_CLIP: /* XXX:2.0 - remove */ { const ClutterGeometry *geom = g_value_get_boxed (value); clutter_actor_set_clip (actor, geom->x, geom->y, geom->width, geom->height); } break; case PROP_CLIP_RECT: clutter_actor_set_clip_rect (actor, g_value_get_boxed (value)); break; case PROP_CLIP_TO_ALLOCATION: clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value)); break; case PROP_REACTIVE: clutter_actor_set_reactive (actor, g_value_get_boolean (value)); break; case PROP_ROTATION_ANGLE_X: clutter_actor_set_rotation_angle (actor, CLUTTER_X_AXIS, g_value_get_double (value)); break; case PROP_ROTATION_ANGLE_Y: clutter_actor_set_rotation_angle (actor, CLUTTER_Y_AXIS, g_value_get_double (value)); break; case PROP_ROTATION_ANGLE_Z: clutter_actor_set_rotation_angle (actor, CLUTTER_Z_AXIS, g_value_get_double (value)); break; case PROP_ROTATION_CENTER_X: /* XXX:2.0 - remove */ clutter_actor_set_rotation_center_internal (actor, CLUTTER_X_AXIS, g_value_get_boxed (value)); break; case PROP_ROTATION_CENTER_Y: /* XXX:2.0 - remove */ clutter_actor_set_rotation_center_internal (actor, CLUTTER_Y_AXIS, g_value_get_boxed (value)); break; case PROP_ROTATION_CENTER_Z: /* XXX:2.0 - remove */ clutter_actor_set_rotation_center_internal (actor, CLUTTER_Z_AXIS, g_value_get_boxed (value)); break; case PROP_ROTATION_CENTER_Z_GRAVITY: /* XXX:2.0 - remove */ { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle, g_value_get_enum (value)); } break; case PROP_ANCHOR_X: /* XXX:2.0 - remove */ clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS, g_value_get_float (value)); break; case PROP_ANCHOR_Y: /* XXX:2.0 - remove */ clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS, g_value_get_float (value)); break; case PROP_ANCHOR_GRAVITY: /* XXX:2.0 - remove */ clutter_actor_set_anchor_point_from_gravity (actor, g_value_get_enum (value)); break; case PROP_TRANSFORM: clutter_actor_set_transform (actor, g_value_get_boxed (value)); break; case PROP_CHILD_TRANSFORM: clutter_actor_set_child_transform (actor, g_value_get_boxed (value)); break; case PROP_SHOW_ON_SET_PARENT: /* XXX:2.0 - remove */ priv->show_on_set_parent = g_value_get_boolean (value); break; case PROP_TEXT_DIRECTION: clutter_actor_set_text_direction (actor, g_value_get_enum (value)); break; case PROP_ACTIONS: clutter_actor_add_action (actor, g_value_get_object (value)); break; case PROP_CONSTRAINTS: clutter_actor_add_constraint (actor, g_value_get_object (value)); break; case PROP_EFFECT: clutter_actor_add_effect (actor, g_value_get_object (value)); break; case PROP_LAYOUT_MANAGER: clutter_actor_set_layout_manager (actor, g_value_get_object (value)); break; case PROP_X_EXPAND: clutter_actor_set_x_expand (actor, g_value_get_boolean (value)); break; case PROP_Y_EXPAND: clutter_actor_set_y_expand (actor, g_value_get_boolean (value)); break; case PROP_X_ALIGN: clutter_actor_set_x_align (actor, g_value_get_enum (value)); break; case PROP_Y_ALIGN: clutter_actor_set_y_align (actor, g_value_get_enum (value)); break; case PROP_MARGIN_TOP: clutter_actor_set_margin_top (actor, g_value_get_float (value)); break; case PROP_MARGIN_BOTTOM: clutter_actor_set_margin_bottom (actor, g_value_get_float (value)); break; case PROP_MARGIN_LEFT: clutter_actor_set_margin_left (actor, g_value_get_float (value)); break; case PROP_MARGIN_RIGHT: clutter_actor_set_margin_right (actor, g_value_get_float (value)); break; case PROP_BACKGROUND_COLOR: clutter_actor_set_background_color (actor, g_value_get_boxed (value)); break; case PROP_CONTENT: clutter_actor_set_content (actor, g_value_get_object (value)); break; case PROP_CONTENT_GRAVITY: clutter_actor_set_content_gravity (actor, g_value_get_enum (value)); break; case PROP_MINIFICATION_FILTER: clutter_actor_set_content_scaling_filters (actor, g_value_get_enum (value), actor->priv->mag_filter); break; case PROP_MAGNIFICATION_FILTER: clutter_actor_set_content_scaling_filters (actor, actor->priv->min_filter, g_value_get_enum (value)); break; case PROP_CONTENT_REPEAT: clutter_actor_set_content_repeat (actor, g_value_get_flags (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_actor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterActor *actor = CLUTTER_ACTOR (object); ClutterActorPrivate *priv = actor->priv; switch (prop_id) { case PROP_X: g_value_set_float (value, clutter_actor_get_x (actor)); break; case PROP_Y: g_value_set_float (value, clutter_actor_get_y (actor)); break; case PROP_POSITION: { ClutterPoint position; clutter_point_init (&position, clutter_actor_get_x (actor), clutter_actor_get_y (actor)); g_value_set_boxed (value, &position); } break; case PROP_WIDTH: g_value_set_float (value, clutter_actor_get_width (actor)); break; case PROP_HEIGHT: g_value_set_float (value, clutter_actor_get_height (actor)); break; case PROP_SIZE: { ClutterSize size; clutter_size_init (&size, clutter_actor_get_width (actor), clutter_actor_get_height (actor)); g_value_set_boxed (value, &size); } break; case PROP_FIXED_X: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->fixed_pos.x); } break; case PROP_FIXED_Y: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->fixed_pos.y); } break; case PROP_FIXED_POSITION_SET: g_value_set_boolean (value, priv->position_set); break; case PROP_MIN_WIDTH: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->minimum.width); } break; case PROP_MIN_HEIGHT: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->minimum.height); } break; case PROP_NATURAL_WIDTH: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->natural.width); } break; case PROP_NATURAL_HEIGHT: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->natural.height); } break; case PROP_MIN_WIDTH_SET: g_value_set_boolean (value, priv->min_width_set); break; case PROP_MIN_HEIGHT_SET: g_value_set_boolean (value, priv->min_height_set); break; case PROP_NATURAL_WIDTH_SET: g_value_set_boolean (value, priv->natural_width_set); break; case PROP_NATURAL_HEIGHT_SET: g_value_set_boolean (value, priv->natural_height_set); break; case PROP_REQUEST_MODE: g_value_set_enum (value, priv->request_mode); break; case PROP_ALLOCATION: g_value_set_boxed (value, &priv->allocation); break; case PROP_DEPTH: /* XXX:2.0 - remove */ g_value_set_float (value, clutter_actor_get_depth (actor)); break; case PROP_Z_POSITION: g_value_set_float (value, clutter_actor_get_z_position (actor)); break; case PROP_OPACITY: g_value_set_uint (value, priv->opacity); break; case PROP_OFFSCREEN_REDIRECT: g_value_set_flags (value, priv->offscreen_redirect); break; case PROP_NAME: g_value_set_string (value, priv->name); break; case PROP_VISIBLE: g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor)); break; case PROP_MAPPED: g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor)); break; case PROP_REALIZED: g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor)); break; case PROP_HAS_CLIP: g_value_set_boolean (value, priv->has_clip); break; case PROP_CLIP: /* XXX:2.0 - remove */ { ClutterGeometry clip; clip.x = CLUTTER_NEARBYINT (priv->clip.origin.x); clip.y = CLUTTER_NEARBYINT (priv->clip.origin.y); clip.width = CLUTTER_NEARBYINT (priv->clip.size.width); clip.height = CLUTTER_NEARBYINT (priv->clip.size.height); g_value_set_boxed (value, &clip); } break; case PROP_CLIP_RECT: g_value_set_boxed (value, &priv->clip); break; case PROP_CLIP_TO_ALLOCATION: g_value_set_boolean (value, priv->clip_to_allocation); break; case PROP_PIVOT_POINT: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_boxed (value, &info->pivot); } break; case PROP_PIVOT_POINT_Z: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_float (value, info->pivot_z); } break; case PROP_TRANSLATION_X: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_float (value, info->translation.x); } break; case PROP_TRANSLATION_Y: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_float (value, info->translation.y); } break; case PROP_TRANSLATION_Z: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_float (value, info->translation.z); } break; case PROP_SCALE_X: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_double (value, info->scale_x); } break; case PROP_SCALE_Y: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_double (value, info->scale_y); } break; case PROP_SCALE_Z: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_double (value, info->scale_z); } break; case PROP_SCALE_CENTER_X: /* XXX:2.0 - remove */ { gfloat center; clutter_actor_get_scale_center (actor, ¢er, NULL); g_value_set_float (value, center); } break; case PROP_SCALE_CENTER_Y: /* XXX:2.0 - remove */ { gfloat center; clutter_actor_get_scale_center (actor, NULL, ¢er); g_value_set_float (value, center); } break; case PROP_SCALE_GRAVITY: /* XXX:2.0 - remove */ g_value_set_enum (value, clutter_actor_get_scale_gravity (actor)); break; case PROP_REACTIVE: g_value_set_boolean (value, clutter_actor_get_reactive (actor)); break; case PROP_ROTATION_ANGLE_X: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_double (value, info->rx_angle); } break; case PROP_ROTATION_ANGLE_Y: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_double (value, info->ry_angle); } break; case PROP_ROTATION_ANGLE_Z: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_double (value, info->rz_angle); } break; case PROP_ROTATION_CENTER_X: /* XXX:2.0 - remove */ { ClutterVertex center; clutter_actor_get_rotation (actor, CLUTTER_X_AXIS, ¢er.x, ¢er.y, ¢er.z); g_value_set_boxed (value, ¢er); } break; case PROP_ROTATION_CENTER_Y: /* XXX:2.0 - remove */ { ClutterVertex center; clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS, ¢er.x, ¢er.y, ¢er.z); g_value_set_boxed (value, ¢er); } break; case PROP_ROTATION_CENTER_Z: /* XXX:2.0 - remove */ { ClutterVertex center; clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS, ¢er.x, ¢er.y, ¢er.z); g_value_set_boxed (value, ¢er); } break; case PROP_ROTATION_CENTER_Z_GRAVITY: /* XXX:2.0 - remove */ g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor)); break; case PROP_ANCHOR_X: /* XXX:2.0 - remove */ { const ClutterTransformInfo *info; gfloat anchor_x; info = _clutter_actor_get_transform_info_or_defaults (actor); clutter_anchor_coord_get_units (actor, &info->anchor, &anchor_x, NULL, NULL); g_value_set_float (value, anchor_x); } break; case PROP_ANCHOR_Y: /* XXX:2.0 - remove */ { const ClutterTransformInfo *info; gfloat anchor_y; info = _clutter_actor_get_transform_info_or_defaults (actor); clutter_anchor_coord_get_units (actor, &info->anchor, NULL, &anchor_y, NULL); g_value_set_float (value, anchor_y); } break; case PROP_ANCHOR_GRAVITY: /* XXX:2.0 - remove */ g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor)); break; case PROP_TRANSFORM: { ClutterMatrix m; clutter_actor_get_transform (actor, &m); g_value_set_boxed (value, &m); } break; case PROP_TRANSFORM_SET: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_boolean (value, info->transform_set); } break; case PROP_CHILD_TRANSFORM: { ClutterMatrix m; clutter_actor_get_child_transform (actor, &m); g_value_set_boxed (value, &m); } break; case PROP_CHILD_TRANSFORM_SET: { const ClutterTransformInfo *info; info = _clutter_actor_get_transform_info_or_defaults (actor); g_value_set_boolean (value, info->child_transform_set); } break; case PROP_SHOW_ON_SET_PARENT: /* XXX:2.0 - remove */ g_value_set_boolean (value, priv->show_on_set_parent); break; case PROP_TEXT_DIRECTION: g_value_set_enum (value, priv->text_direction); break; case PROP_HAS_POINTER: g_value_set_boolean (value, priv->has_pointer); break; case PROP_LAYOUT_MANAGER: g_value_set_object (value, priv->layout_manager); break; case PROP_X_EXPAND: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_boolean (value, info->x_expand); } break; case PROP_Y_EXPAND: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_boolean (value, info->y_expand); } break; case PROP_X_ALIGN: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_enum (value, info->x_align); } break; case PROP_Y_ALIGN: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_enum (value, info->y_align); } break; case PROP_MARGIN_TOP: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->margin.top); } break; case PROP_MARGIN_BOTTOM: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->margin.bottom); } break; case PROP_MARGIN_LEFT: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->margin.left); } break; case PROP_MARGIN_RIGHT: { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (actor); g_value_set_float (value, info->margin.right); } break; case PROP_BACKGROUND_COLOR_SET: g_value_set_boolean (value, priv->bg_color_set); break; case PROP_BACKGROUND_COLOR: g_value_set_boxed (value, &priv->bg_color); break; case PROP_FIRST_CHILD: g_value_set_object (value, priv->first_child); break; case PROP_LAST_CHILD: g_value_set_object (value, priv->last_child); break; case PROP_CONTENT: g_value_set_object (value, priv->content); break; case PROP_CONTENT_GRAVITY: g_value_set_enum (value, priv->content_gravity); break; case PROP_CONTENT_BOX: { ClutterActorBox box = { 0, }; clutter_actor_get_content_box (actor, &box); g_value_set_boxed (value, &box); } break; case PROP_MINIFICATION_FILTER: g_value_set_enum (value, priv->min_filter); break; case PROP_MAGNIFICATION_FILTER: g_value_set_enum (value, priv->mag_filter); break; case PROP_CONTENT_REPEAT: g_value_set_flags (value, priv->content_repeat); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void clutter_actor_dispose (GObject *object) { ClutterActor *self = CLUTTER_ACTOR (object); ClutterActorPrivate *priv = self->priv; CLUTTER_NOTE (MISC, "Dispose actor (name='%s', ref_count:%d) of type '%s'", _clutter_actor_get_debug_name (self), object->ref_count, g_type_name (G_OBJECT_TYPE (self))); g_signal_emit (self, actor_signals[DESTROY], 0); /* avoid recursing when called from clutter_actor_destroy() */ if (priv->parent != NULL) { ClutterActor *parent = priv->parent; /* go through the Container implementation unless this * is an internal child and has been marked as such. * * removing the actor from its parent will reset the * realized and mapped states. */ if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self)) clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self); else clutter_actor_remove_child_internal (parent, self, REMOVE_CHILD_LEGACY_FLAGS); } /* parent must be gone at this point */ g_assert (priv->parent == NULL); if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) { /* can't be mapped or realized with no parent */ g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); g_assert (!CLUTTER_ACTOR_IS_REALIZED (self)); } g_clear_object (&priv->pango_context); g_clear_object (&priv->actions); g_clear_object (&priv->constraints); g_clear_object (&priv->effects); g_clear_object (&priv->flatten_effect); if (priv->child_model != NULL) { if (priv->create_child_notify != NULL) priv->create_child_notify (priv->create_child_data); priv->create_child_func = NULL; priv->create_child_data = NULL; priv->create_child_notify = NULL; g_clear_object (&priv->child_model); } if (priv->layout_manager != NULL) { clutter_layout_manager_set_container (priv->layout_manager, NULL); g_clear_object (&priv->layout_manager); } if (priv->content != NULL) { _clutter_content_detached (priv->content, self); g_clear_object (&priv->content); } if (priv->clones != NULL) { g_hash_table_unref (priv->clones); priv->clones = NULL; } G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object); } static void clutter_actor_finalize (GObject *object) { ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv; CLUTTER_NOTE (MISC, "Finalize actor (name='%s') of type '%s'", _clutter_actor_get_debug_name ((ClutterActor *) object), g_type_name (G_OBJECT_TYPE (object))); free (priv->name); #ifdef CLUTTER_ENABLE_DEBUG free (priv->debug_name); #endif G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object); } /** * clutter_actor_get_accessible: * @self: a #ClutterActor * * Returns the accessible object that describes the actor to an * assistive technology. * * If no class-specific #AtkObject implementation is available for the * actor instance in question, it will inherit an #AtkObject * implementation from the first ancestor class for which such an * implementation is defined. * * The documentation of the ATK * library contains more information about accessible objects and * their uses. * * Returns: (transfer none): the #AtkObject associated with @actor */ AtkObject * clutter_actor_get_accessible (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self); } static AtkObject * clutter_actor_real_get_accessible (ClutterActor *actor) { return atk_gobject_accessible_for_object (G_OBJECT (actor)); } static AtkObject * _clutter_actor_ref_accessible (AtkImplementor *implementor) { AtkObject *accessible; accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor)); if (accessible != NULL) g_object_ref (accessible); return accessible; } static void atk_implementor_iface_init (AtkImplementorIface *iface) { iface->ref_accessible = _clutter_actor_ref_accessible; } static gboolean clutter_actor_update_default_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { ClutterActorPrivate *priv = self->priv; gboolean res = TRUE; /* this should be checked before we call this function, but it's a * good idea to be explicit when it costs us nothing */ if (priv->needs_allocation) return FALSE; /* we start from the allocation */ clutter_paint_volume_set_width (volume, priv->allocation.x2 - priv->allocation.x1); clutter_paint_volume_set_height (volume, priv->allocation.y2 - priv->allocation.y1); /* if the actor has a clip set then we have a pretty definite * size for the paint volume: the actor cannot possibly paint * outside the clip region. */ if (priv->clip_to_allocation) { /* the allocation has already been set, so we just flip the * return value */ res = TRUE; } else { ClutterActor *child; if (priv->has_clip && priv->clip.size.width >= 0 && priv->clip.size.height >= 0) { ClutterVertex origin; origin.x = priv->clip.origin.x; origin.y = priv->clip.origin.y; origin.z = 0; clutter_paint_volume_set_origin (volume, &origin); clutter_paint_volume_set_width (volume, priv->clip.size.width); clutter_paint_volume_set_height (volume, priv->clip.size.height); res = TRUE; } /* if we don't have children we just bail out here... */ if (priv->n_children == 0) return res; /* ...but if we have children then we ask for their paint volume in * our coordinates. if any of our children replies that it doesn't * have a paint volume, we bail out */ for (child = priv->first_child; child != NULL; child = child->priv->next_sibling) { const ClutterPaintVolume *child_volume; /* we ignore unmapped children, since they won't be painted. * * XXX: we also have to ignore mapped children without a valid * allocation, because apparently some code above Clutter allows * them. */ if (!CLUTTER_ACTOR_IS_MAPPED (child) || !clutter_actor_has_allocation (child)) continue; child_volume = clutter_actor_get_transformed_paint_volume (child, self); if (child_volume == NULL) { res = FALSE; break; } clutter_paint_volume_union (volume, child_volume); res = TRUE; } } return res; } static gboolean clutter_actor_real_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume) { ClutterActorClass *klass; gboolean res; klass = CLUTTER_ACTOR_GET_CLASS (self); /* XXX - this thoroughly sucks, but we don't want to penalize users * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage * redraw. This should go away in 2.0. */ if (klass->paint == clutter_actor_real_paint && klass->get_paint_volume == clutter_actor_real_get_paint_volume) { res = TRUE; } else { /* this is the default return value: we cannot know if a class * is going to paint outside its allocation, so we take the * conservative approach. */ res = FALSE; } /* update_default_paint_volume() should only fail if one of the children * reported an invalid, or no, paint volume */ if (!clutter_actor_update_default_paint_volume (self, volume)) return FALSE; return res; } /** * clutter_actor_get_default_paint_volume: * @self: a #ClutterActor * * Retrieves the default paint volume for @self. * * This function provides the same #ClutterPaintVolume that would be * computed by the default implementation inside #ClutterActor of the * #ClutterActorClass.get_paint_volume() virtual function. * * This function should only be used by #ClutterActor subclasses that * cannot chain up to the parent implementation when computing their * paint volume. * * Return value: (transfer none): a pointer to the default * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if * the actor could not compute a valid paint volume. The returned value * is not guaranteed to be stable across multiple frames, so if you * want to retain it, you will need to copy it using * clutter_paint_volume_copy(). * * Since: 1.10 */ const ClutterPaintVolume * clutter_actor_get_default_paint_volume (ClutterActor *self) { ClutterPaintVolume volume; ClutterPaintVolume *res; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); res = NULL; _clutter_paint_volume_init_static (&volume, self); if (clutter_actor_update_default_paint_volume (self, &volume)) { ClutterActor *stage = _clutter_actor_get_stage_internal (self); if (stage != NULL) { res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage)); _clutter_paint_volume_copy_static (&volume, res); } } clutter_paint_volume_free (&volume); return res; } static gboolean clutter_actor_real_has_overlaps (ClutterActor *self) { /* By default we'll assume that all actors need an offscreen redirect to get * the correct opacity. Actors such as ClutterTexture that would never need * an offscreen redirect can override this to return FALSE. */ return TRUE; } static void clutter_actor_real_destroy (ClutterActor *actor) { ClutterActorIter iter; g_object_freeze_notify (G_OBJECT (actor)); clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_next (&iter, NULL)) clutter_actor_iter_destroy (&iter); g_object_thaw_notify (G_OBJECT (actor)); } static GObject * clutter_actor_constructor (GType gtype, guint n_props, GObjectConstructParam *props) { GObjectClass *gobject_class; ClutterActor *self; GObject *retval; gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class); retval = gobject_class->constructor (gtype, n_props, props); self = CLUTTER_ACTOR (retval); if (self->priv->layout_manager == NULL) { ClutterLayoutManager *default_layout; CLUTTER_NOTE (LAYOUT, "Creating default layout manager"); default_layout = clutter_fixed_layout_new (); clutter_actor_set_layout_manager (self, default_layout); } return retval; } static void clutter_actor_class_init (ClutterActorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data"); quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info"); quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info"); quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info"); object_class->constructor = clutter_actor_constructor; object_class->set_property = clutter_actor_set_property; object_class->get_property = clutter_actor_get_property; object_class->dispose = clutter_actor_dispose; object_class->finalize = clutter_actor_finalize; klass->show = clutter_actor_real_show; klass->show_all = clutter_actor_show; klass->hide = clutter_actor_real_hide; klass->hide_all = clutter_actor_hide; klass->map = clutter_actor_real_map; klass->unmap = clutter_actor_real_unmap; klass->unrealize = clutter_actor_real_unrealize; klass->pick = clutter_actor_real_pick; klass->get_preferred_width = clutter_actor_real_get_preferred_width; klass->get_preferred_height = clutter_actor_real_get_preferred_height; klass->allocate = clutter_actor_real_allocate; klass->queue_redraw = clutter_actor_real_queue_redraw; klass->queue_relayout = clutter_actor_real_queue_relayout; klass->apply_transform = clutter_actor_real_apply_transform; klass->get_accessible = clutter_actor_real_get_accessible; klass->get_paint_volume = clutter_actor_real_get_paint_volume; klass->has_overlaps = clutter_actor_real_has_overlaps; klass->paint = clutter_actor_real_paint; klass->destroy = clutter_actor_real_destroy; /** * ClutterActor:x: * * X coordinate of the actor in pixels. If written, forces a fixed * position for the actor. If read, returns the fixed position if any, * otherwise the allocation if available, otherwise 0. * * The #ClutterActor:x property is animatable. */ obj_props[PROP_X] = g_param_spec_float ("x", P_("X coordinate"), P_("X coordinate of the actor"), -G_MAXFLOAT, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:y: * * Y coordinate of the actor in pixels. If written, forces a fixed * position for the actor. If read, returns the fixed position if * any, otherwise the allocation if available, otherwise 0. * * The #ClutterActor:y property is animatable. */ obj_props[PROP_Y] = g_param_spec_float ("y", P_("Y coordinate"), P_("Y coordinate of the actor"), -G_MAXFLOAT, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:position: * * The position of the origin of the actor. * * This property is a shorthand for setting and getting the * #ClutterActor:x and #ClutterActor:y properties at the same * time. * * The #ClutterActor:position property is animatable. * * Since: 1.12 */ obj_props[PROP_POSITION] = g_param_spec_boxed ("position", P_("Position"), P_("The position of the origin of the actor"), CLUTTER_TYPE_POINT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:width: * * Width of the actor (in pixels). If written, forces the minimum and * natural size request of the actor to the given width. If read, returns * the allocated width if available, otherwise the width request. * * The #ClutterActor:width property is animatable. */ obj_props[PROP_WIDTH] = g_param_spec_float ("width", P_("Width"), P_("Width of the actor"), 0.0, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:height: * * Height of the actor (in pixels). If written, forces the minimum and * natural size request of the actor to the given height. If read, returns * the allocated height if available, otherwise the height request. * * The #ClutterActor:height property is animatable. */ obj_props[PROP_HEIGHT] = g_param_spec_float ("height", P_("Height"), P_("Height of the actor"), 0.0, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:size: * * The size of the actor. * * This property is a shorthand for setting and getting the * #ClutterActor:width and #ClutterActor:height at the same time. * * The #ClutterActor:size property is animatable. * * Since: 1.12 */ obj_props[PROP_SIZE] = g_param_spec_boxed ("size", P_("Size"), P_("The size of the actor"), CLUTTER_TYPE_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:fixed-x: * * The fixed X position of the actor in pixels. * * Writing this property sets #ClutterActor:fixed-position-set * property as well, as a side effect * * Since: 0.8 */ obj_props[PROP_FIXED_X] = g_param_spec_float ("fixed-x", P_("Fixed X"), P_("Forced X position of the actor"), -G_MAXFLOAT, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterActor:fixed-y: * * The fixed Y position of the actor in pixels. * * Writing this property sets the #ClutterActor:fixed-position-set * property as well, as a side effect * * Since: 0.8 */ obj_props[PROP_FIXED_Y] = g_param_spec_float ("fixed-y", P_("Fixed Y"), P_("Forced Y position of the actor"), -G_MAXFLOAT, G_MAXFLOAT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterActor:fixed-position-set: * * This flag controls whether the #ClutterActor:fixed-x and * #ClutterActor:fixed-y properties are used * * Since: 0.8 */ obj_props[PROP_FIXED_POSITION_SET] = g_param_spec_boolean ("fixed-position-set", P_("Fixed position set"), P_("Whether to use fixed positioning for the actor"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:min-width: * * A forced minimum width request for the actor, in pixels * * Writing this property sets the #ClutterActor:min-width-set property * as well, as a side effect. * *This property overrides the usual width request of the actor. * * Since: 0.8 */ obj_props[PROP_MIN_WIDTH] = g_param_spec_float ("min-width", P_("Min Width"), P_("Forced minimum width request for the actor"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterActor:min-height: * * A forced minimum height request for the actor, in pixels * * Writing this property sets the #ClutterActor:min-height-set property * as well, as a side effect. This property overrides the usual height * request of the actor. * * Since: 0.8 */ obj_props[PROP_MIN_HEIGHT] = g_param_spec_float ("min-height", P_("Min Height"), P_("Forced minimum height request for the actor"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterActor:natural-width: * * A forced natural width request for the actor, in pixels * * Writing this property sets the #ClutterActor:natural-width-set * property as well, as a side effect. This property overrides the * usual width request of the actor * * Since: 0.8 */ obj_props[PROP_NATURAL_WIDTH] = g_param_spec_float ("natural-width", P_("Natural Width"), P_("Forced natural width request for the actor"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterActor:natural-height: * * A forced natural height request for the actor, in pixels * * Writing this property sets the #ClutterActor:natural-height-set * property as well, as a side effect. This property overrides the * usual height request of the actor * * Since: 0.8 */ obj_props[PROP_NATURAL_HEIGHT] = g_param_spec_float ("natural-height", P_("Natural Height"), P_("Forced natural height request for the actor"), 0.0, G_MAXFLOAT, 0.0, CLUTTER_PARAM_READWRITE); /** * ClutterActor:min-width-set: * * This flag controls whether the #ClutterActor:min-width property * is used * * Since: 0.8 */ obj_props[PROP_MIN_WIDTH_SET] = g_param_spec_boolean ("min-width-set", P_("Minimum width set"), P_("Whether to use the min-width property"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:min-height-set: * * This flag controls whether the #ClutterActor:min-height property * is used * * Since: 0.8 */ obj_props[PROP_MIN_HEIGHT_SET] = g_param_spec_boolean ("min-height-set", P_("Minimum height set"), P_("Whether to use the min-height property"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:natural-width-set: * * This flag controls whether the #ClutterActor:natural-width property * is used * * Since: 0.8 */ obj_props[PROP_NATURAL_WIDTH_SET] = g_param_spec_boolean ("natural-width-set", P_("Natural width set"), P_("Whether to use the natural-width property"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:natural-height-set: * * This flag controls whether the #ClutterActor:natural-height property * is used * * Since: 0.8 */ obj_props[PROP_NATURAL_HEIGHT_SET] = g_param_spec_boolean ("natural-height-set", P_("Natural height set"), P_("Whether to use the natural-height property"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:allocation: * * The allocation for the actor, in pixels * * This is property is read-only, but you might monitor it to know when an * actor moves or resizes * * Since: 0.8 */ obj_props[PROP_ALLOCATION] = g_param_spec_boxed ("allocation", P_("Allocation"), P_("The actor's allocation"), CLUTTER_TYPE_ACTOR_BOX, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:request-mode: * * Request mode for the #ClutterActor. The request mode determines the * type of geometry management used by the actor, either height for width * (the default) or width for height. * * For actors implementing height for width, the parent container should get * the preferred width first, and then the preferred height for that width. * * For actors implementing width for height, the parent container should get * the preferred height first, and then the preferred width for that height. * * For instance: * * |[ * ClutterRequestMode mode; * gfloat natural_width, min_width; * gfloat natural_height, min_height; * * mode = clutter_actor_get_request_mode (child); * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) * { * clutter_actor_get_preferred_width (child, -1, * &min_width, * &natural_width); * clutter_actor_get_preferred_height (child, natural_width, * &min_height, * &natural_height); * } * else if (mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) * { * clutter_actor_get_preferred_height (child, -1, * &min_height, * &natural_height); * clutter_actor_get_preferred_width (child, natural_height, * &min_width, * &natural_width); * } * else if (mode == CLUTTER_REQUEST_CONTENT_SIZE) * { * ClutterContent *content = clutter_actor_get_content (child); * * min_width, min_height = 0; * natural_width = natural_height = 0; * * if (content != NULL) * clutter_content_get_preferred_size (content, &natural_width, &natural_height); * } * ]| * * will retrieve the minimum and natural width and height depending on the * preferred request mode of the #ClutterActor "child". * * The clutter_actor_get_preferred_size() function will implement this * check for you. * * Since: 0.8 */ obj_props[PROP_REQUEST_MODE] = g_param_spec_enum ("request-mode", P_("Request Mode"), P_("The actor's request mode"), CLUTTER_TYPE_REQUEST_MODE, CLUTTER_REQUEST_HEIGHT_FOR_WIDTH, CLUTTER_PARAM_READWRITE); /** * ClutterActor:depth: * * The position of the actor on the Z axis. * * The #ClutterActor:depth property is relative to the parent's * modelview matrix. * * Setting this property will call #ClutterContainerIface.sort_depth_order() * which is usually a no-op, and it's most likely not what you want. * * The #ClutterActor:depth property is animatable. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:z-position instead. */ obj_props[PROP_DEPTH] = g_param_spec_float ("depth", P_("Depth"), P_("Position on the Z axis"), -G_MAXFLOAT, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:z-position: * * The actor's position on the Z axis, relative to the parent's * transformations. * * Positive values will bring the actor's position nearer to the user, * whereas negative values will bring the actor's position farther from * the user. * * The #ClutterActor:z-position does not affect the paint or allocation * order. * * The #ClutterActor:z-position property is animatable. * * Since: 1.12 */ obj_props[PROP_Z_POSITION] = g_param_spec_float ("z-position", P_("Z Position"), P_("The actor's position on the Z axis"), -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:opacity: * * Opacity of an actor, between 0 (fully transparent) and * 255 (fully opaque) * * The #ClutterActor:opacity property is animatable. */ obj_props[PROP_OPACITY] = g_param_spec_uint ("opacity", P_("Opacity"), P_("Opacity of an actor"), 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:offscreen-redirect: * * Determines the conditions in which the actor will be redirected * to an offscreen framebuffer while being painted. For example this * can be used to cache an actor in a framebuffer or for improved * handling of transparent actors. See * clutter_actor_set_offscreen_redirect() for details. * * Since: 1.8 */ obj_props[PROP_OFFSCREEN_REDIRECT] = g_param_spec_flags ("offscreen-redirect", P_("Offscreen redirect"), P_("Flags controlling when to flatten the actor into a single image"), CLUTTER_TYPE_OFFSCREEN_REDIRECT, 0, CLUTTER_PARAM_READWRITE); /** * ClutterActor:visible: * * Whether the actor is set to be visible or not * * See also #ClutterActor:mapped */ obj_props[PROP_VISIBLE] = g_param_spec_boolean ("visible", P_("Visible"), P_("Whether the actor is visible or not"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:mapped: * * Whether the actor is mapped (will be painted when the stage * to which it belongs is mapped) * * Since: 1.0 */ obj_props[PROP_MAPPED] = g_param_spec_boolean ("mapped", P_("Mapped"), P_("Whether the actor will be painted"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterActor:realized: * * Whether the actor has been realized * * Since: 1.0 */ obj_props[PROP_REALIZED] = g_param_spec_boolean ("realized", P_("Realized"), P_("Whether the actor has been realized"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterActor:reactive: * * Whether the actor is reactive to events or not * * Only reactive actors will emit event-related signals * * Since: 0.6 */ obj_props[PROP_REACTIVE] = g_param_spec_boolean ("reactive", P_("Reactive"), P_("Whether the actor is reactive to events"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:has-clip: * * Whether the actor has the #ClutterActor:clip property set or not */ obj_props[PROP_HAS_CLIP] = g_param_spec_boolean ("has-clip", P_("Has Clip"), P_("Whether the actor has a clip set"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterActor:clip: * * The visible region of the actor, in actor-relative coordinates * * Deprecated: 1.12: Use #ClutterActor:clip-rect instead. */ obj_props[PROP_CLIP] = /* XXX:2.0 - remove */ g_param_spec_boxed ("clip", P_("Clip"), P_("The clip region for the actor"), CLUTTER_TYPE_GEOMETRY, CLUTTER_PARAM_READWRITE); /** * ClutterActor:clip-rect: * * The visible region of the actor, in actor-relative coordinates, * expressed as a #ClutterRect. * * Setting this property to %NULL will unset the existing clip. * * Setting this property will change the #ClutterActor:has-clip * property as a side effect. * * Since: 1.12 */ obj_props[PROP_CLIP_RECT] = g_param_spec_boxed ("clip-rect", P_("Clip Rectangle"), P_("The visible region of the actor"), CLUTTER_TYPE_RECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterActor:name: * * The name of the actor * * Since: 0.2 */ obj_props[PROP_NAME] = g_param_spec_string ("name", P_("Name"), P_("Name of the actor"), NULL, CLUTTER_PARAM_READWRITE); /** * ClutterActor:pivot-point: * * The point around which the scaling and rotation transformations occur. * * The pivot point is expressed in normalized coordinates space, with (0, 0) * being the top left corner of the actor and (1, 1) the bottom right corner * of the actor. * * The default pivot point is located at (0, 0). * * The #ClutterActor:pivot-point property is animatable. * * Since: 1.12 */ obj_props[PROP_PIVOT_POINT] = g_param_spec_boxed ("pivot-point", P_("Pivot Point"), P_("The point around which the scaling and rotation occur"), CLUTTER_TYPE_POINT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:pivot-point-z: * * The Z component of the #ClutterActor:pivot-point, expressed as a value * along the Z axis. * * The #ClutterActor:pivot-point-z property is animatable. * * Since: 1.12 */ obj_props[PROP_PIVOT_POINT_Z] = g_param_spec_float ("pivot-point-z", P_("Pivot Point Z"), P_("Z component of the pivot point"), -G_MAXFLOAT, G_MAXFLOAT, 0.f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:scale-x: * * The horizontal scale of the actor. * * The #ClutterActor:scale-x property is animatable. * * Since: 0.6 */ obj_props[PROP_SCALE_X] = g_param_spec_double ("scale-x", P_("Scale X"), P_("Scale factor on the X axis"), -G_MAXDOUBLE, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:scale-y: * * The vertical scale of the actor. * * The #ClutterActor:scale-y property is animatable. * * Since: 0.6 */ obj_props[PROP_SCALE_Y] = g_param_spec_double ("scale-y", P_("Scale Y"), P_("Scale factor on the Y axis"), -G_MAXDOUBLE, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:scale-z: * * The scale factor of the actor along the Z axis. * * The #ClutterActor:scale-y property is animatable. * * Since: 1.12 */ obj_props[PROP_SCALE_Z] = g_param_spec_double ("scale-z", P_("Scale Z"), P_("Scale factor on the Z axis"), -G_MAXDOUBLE, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:scale-center-x: * * The horizontal center point for scaling * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_SCALE_CENTER_X] = /* XXX:2.0 - remove */ g_param_spec_float ("scale-center-x", P_("Scale Center X"), P_("Horizontal scale center"), -G_MAXFLOAT, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:scale-center-y: * * The vertical center point for scaling * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_SCALE_CENTER_Y] = /* XXX:2.0 - remove */ g_param_spec_float ("scale-center-y", P_("Scale Center Y"), P_("Vertical scale center"), -G_MAXFLOAT, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:scale-gravity: * * The center point for scaling expressed as a #ClutterGravity * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_SCALE_GRAVITY] = /* XXX:2.0 - remove */ g_param_spec_enum ("scale-gravity", P_("Scale Gravity"), P_("The center of scaling"), CLUTTER_TYPE_GRAVITY, CLUTTER_GRAVITY_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:rotation-angle-x: * * The rotation angle on the X axis. * * The #ClutterActor:rotation-angle-x property is animatable. * * Since: 0.6 */ obj_props[PROP_ROTATION_ANGLE_X] = g_param_spec_double ("rotation-angle-x", P_("Rotation Angle X"), P_("The rotation angle on the X axis"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:rotation-angle-y: * * The rotation angle on the Y axis * * The #ClutterActor:rotation-angle-y property is animatable. * * Since: 0.6 */ obj_props[PROP_ROTATION_ANGLE_Y] = g_param_spec_double ("rotation-angle-y", P_("Rotation Angle Y"), P_("The rotation angle on the Y axis"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:rotation-angle-z: * * The rotation angle on the Z axis * * The #ClutterActor:rotation-angle-z property is animatable. * * Since: 0.6 */ obj_props[PROP_ROTATION_ANGLE_Z] = g_param_spec_double ("rotation-angle-z", P_("Rotation Angle Z"), P_("The rotation angle on the Z axis"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:rotation-center-x: * * The rotation center on the X axis. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_ROTATION_CENTER_X] = /* XXX:2.0 - remove */ g_param_spec_boxed ("rotation-center-x", P_("Rotation Center X"), P_("The rotation center on the X axis"), CLUTTER_TYPE_VERTEX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:rotation-center-y: * * The rotation center on the Y axis. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_ROTATION_CENTER_Y] = /* XXX:2.0 - remove */ g_param_spec_boxed ("rotation-center-y", P_("Rotation Center Y"), P_("The rotation center on the Y axis"), CLUTTER_TYPE_VERTEX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:rotation-center-z: * * The rotation center on the Z axis. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_ROTATION_CENTER_Z] = /* XXX:2.0 - remove */ g_param_spec_boxed ("rotation-center-z", P_("Rotation Center Z"), P_("The rotation center on the Z axis"), CLUTTER_TYPE_VERTEX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:rotation-center-z-gravity: * * The rotation center on the Z axis expressed as a #ClutterGravity. * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] = /* XXX:2.0 - remove */ g_param_spec_enum ("rotation-center-z-gravity", P_("Rotation Center Z Gravity"), P_("Center point for rotation around the Z axis"), CLUTTER_TYPE_GRAVITY, CLUTTER_GRAVITY_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:anchor-x: * * The X coordinate of an actor's anchor point, relative to * the actor coordinate space, in pixels. * * It is highly recommended not to use #ClutterActor:anchor-x, * #ClutterActor:anchor-y, and #ClutterActor:anchor-gravity in newly * written code; the anchor point adds an additional translation that * will affect the actor's relative position with regards to its * parent, as well as the position of its children. This change needs * to always be taken into account when positioning the actor. It is * recommended to use the #ClutterActor:pivot-point property instead, * as it will affect only the transformations. * * Since: 0.8 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_ANCHOR_X] = /* XXX:2.0 - remove */ g_param_spec_float ("anchor-x", P_("Anchor X"), P_("X coordinate of the anchor point"), -G_MAXFLOAT, G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:anchor-y: * * The Y coordinate of an actor's anchor point, relative to * the actor coordinate space, in pixels * * It is highly recommended not to use #ClutterActor:anchor-x, * #ClutterActor:anchor-y, and #ClutterActor:anchor-gravity in newly * written code; the anchor point adds an additional translation that * will affect the actor's relative position with regards to its * parent, as well as the position of its children. This change needs * to always be taken into account when positioning the actor. It is * recommended to use the #ClutterActor:pivot-point property instead, * as it will affect only the transformations. * * Since: 0.8 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_ANCHOR_Y] = /* XXX:2.0 - remove */ g_param_spec_float ("anchor-y", P_("Anchor Y"), P_("Y coordinate of the anchor point"), -G_MAXFLOAT, G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:anchor-gravity: * * The anchor point expressed as a #ClutterGravity * * It is highly recommended not to use #ClutterActor:anchor-x, * #ClutterActor:anchor-y, and #ClutterActor:anchor-gravity in newly * written code; the anchor point adds an additional translation that * will affect the actor's relative position with regards to its * parent, as well as the position of its children. This change needs * to always be taken into account when positioning the actor. It is * recommended to use the #ClutterActor:pivot-point property instead, * as it will affect only the transformations. * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ obj_props[PROP_ANCHOR_GRAVITY] = /* XXX:2.0 - remove */ g_param_spec_enum ("anchor-gravity", P_("Anchor Gravity"), P_("The anchor point as a ClutterGravity"), CLUTTER_TYPE_GRAVITY, CLUTTER_GRAVITY_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED); /** * ClutterActor:translation-x: * * An additional translation applied along the X axis, relative * to the actor's #ClutterActor:pivot-point. * * The #ClutterActor:translation-x property is animatable. * * Since: 1.12 */ obj_props[PROP_TRANSLATION_X] = g_param_spec_float ("translation-x", P_("Translation X"), P_("Translation along the X axis"), -G_MAXFLOAT, G_MAXFLOAT, 0.f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:translation-y: * * An additional translation applied along the Y axis, relative * to the actor's #ClutterActor:pivot-point. * * The #ClutterActor:translation-y property is animatable. * * Since: 1.12 */ obj_props[PROP_TRANSLATION_Y] = g_param_spec_float ("translation-y", P_("Translation Y"), P_("Translation along the Y axis"), -G_MAXFLOAT, G_MAXFLOAT, 0.f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:translation-z: * * An additional translation applied along the Z axis, relative * to the actor's #ClutterActor:pivot-point. * * The #ClutterActor:translation-z property is animatable. * * Since: 1.12 */ obj_props[PROP_TRANSLATION_Z] = g_param_spec_float ("translation-z", P_("Translation Z"), P_("Translation along the Z axis"), -G_MAXFLOAT, G_MAXFLOAT, 0.f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:transform: * * Overrides the transformations of a #ClutterActor with a custom * matrix. * * The matrix specified by the #ClutterActor:transform property is * applied to the actor and its children relative to the actor's * #ClutterActor:allocation and #ClutterActor:pivot-point. * * Application code should rarely need to use this function directly. * * Setting this property with a #ClutterMatrix will set the * #ClutterActor:transform-set property to %TRUE as a side effect; * setting this property with %NULL will set the * #ClutterActor:transform-set property to %FALSE. * * The #ClutterActor:transform property is animatable. * * Since: 1.12 */ obj_props[PROP_TRANSFORM] = g_param_spec_boxed ("transform", P_("Transform"), P_("Transformation matrix"), CLUTTER_TYPE_MATRIX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:transform-set: * * Whether the #ClutterActor:transform property is set. * * Since: 1.12 */ obj_props[PROP_TRANSFORM_SET] = g_param_spec_boolean ("transform-set", P_("Transform Set"), P_("Whether the transform property is set"), FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * ClutterActor:child-transform: * * Applies a transformation matrix on each child of an actor. * * Setting this property with a #ClutterMatrix will set the * #ClutterActor:child-transform-set property to %TRUE as a side effect; * setting this property with %NULL will set the * #ClutterActor:child-transform-set property to %FALSE. * * The #ClutterActor:child-transform property is animatable. * * Since: 1.12 */ obj_props[PROP_CHILD_TRANSFORM] = g_param_spec_boxed ("child-transform", P_("Child Transform"), P_("Children transformation matrix"), CLUTTER_TYPE_MATRIX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:child-transform-set: * * Whether the #ClutterActor:child-transform property is set. * * Since: 1.12 */ obj_props[PROP_CHILD_TRANSFORM_SET] = g_param_spec_boolean ("child-transform-set", P_("Child Transform Set"), P_("Whether the child-transform property is set"), FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * ClutterActor:show-on-set-parent: * * If %TRUE, the actor is automatically shown when parented. * * Calling clutter_actor_hide() on an actor which has not been * parented will set this property to %FALSE as a side effect. * * Since: 0.8 */ obj_props[PROP_SHOW_ON_SET_PARENT] = /* XXX:2.0 - remove */ g_param_spec_boolean ("show-on-set-parent", P_("Show on set parent"), P_("Whether the actor is shown when parented"), TRUE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:clip-to-allocation: * * Whether the clip region should track the allocated area * of the actor. * * This property is ignored if a clip area has been explicitly * set using clutter_actor_set_clip(). * * Since: 1.0 */ obj_props[PROP_CLIP_TO_ALLOCATION] = g_param_spec_boolean ("clip-to-allocation", P_("Clip to Allocation"), P_("Sets the clip region to track the actor's allocation"), FALSE, CLUTTER_PARAM_READWRITE); /** * ClutterActor:text-direction: * * The direction of the text inside a #ClutterActor. * * Since: 1.0 */ obj_props[PROP_TEXT_DIRECTION] = g_param_spec_enum ("text-direction", P_("Text Direction"), P_("Direction of the text"), CLUTTER_TYPE_TEXT_DIRECTION, CLUTTER_TEXT_DIRECTION_LTR, CLUTTER_PARAM_READWRITE); /** * ClutterActor:has-pointer: * * Whether the actor contains the pointer of a #ClutterInputDevice * or not. * * Since: 1.2 */ obj_props[PROP_HAS_POINTER] = g_param_spec_boolean ("has-pointer", P_("Has Pointer"), P_("Whether the actor contains the pointer of an input device"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterActor:actions: * * Adds a #ClutterAction to the actor * * Since: 1.4 */ obj_props[PROP_ACTIONS] = g_param_spec_object ("actions", P_("Actions"), P_("Adds an action to the actor"), CLUTTER_TYPE_ACTION, CLUTTER_PARAM_WRITABLE); /** * ClutterActor:constraints: * * Adds a #ClutterConstraint to the actor * * Since: 1.4 */ obj_props[PROP_CONSTRAINTS] = g_param_spec_object ("constraints", P_("Constraints"), P_("Adds a constraint to the actor"), CLUTTER_TYPE_CONSTRAINT, CLUTTER_PARAM_WRITABLE); /** * ClutterActor:effect: * * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor * * Since: 1.4 */ obj_props[PROP_EFFECT] = g_param_spec_object ("effect", P_("Effect"), P_("Add an effect to be applied on the actor"), CLUTTER_TYPE_EFFECT, CLUTTER_PARAM_WRITABLE); /** * ClutterActor:layout-manager: * * A delegate object for controlling the layout of the children of * an actor. * * Since: 1.10 */ obj_props[PROP_LAYOUT_MANAGER] = g_param_spec_object ("layout-manager", P_("Layout Manager"), P_("The object controlling the layout of an actor's children"), CLUTTER_TYPE_LAYOUT_MANAGER, CLUTTER_PARAM_READWRITE); /** * ClutterActor:x-expand: * * Whether a layout manager should assign more space to the actor on * the X axis. * * Since: 1.12 */ obj_props[PROP_X_EXPAND] = g_param_spec_boolean ("x-expand", P_("X Expand"), P_("Whether extra horizontal space should be assigned to the actor"), FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterActor:y-expand: * * Whether a layout manager should assign more space to the actor on * the Y axis. * * Since: 1.12 */ obj_props[PROP_Y_EXPAND] = g_param_spec_boolean ("y-expand", P_("Y Expand"), P_("Whether extra vertical space should be assigned to the actor"), FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * ClutterActor:x-align: * * The alignment of an actor on the X axis, if the actor has been given * extra space for its allocation. See also the #ClutterActor:x-expand * property. * * Since: 1.10 */ obj_props[PROP_X_ALIGN] = g_param_spec_enum ("x-align", P_("X Alignment"), P_("The alignment of the actor on the X axis within its allocation"), CLUTTER_TYPE_ACTOR_ALIGN, CLUTTER_ACTOR_ALIGN_FILL, CLUTTER_PARAM_READWRITE); /** * ClutterActor:y-align: * * The alignment of an actor on the Y axis, if the actor has been given * extra space for its allocation. * * Since: 1.10 */ obj_props[PROP_Y_ALIGN] = g_param_spec_enum ("y-align", P_("Y Alignment"), P_("The alignment of the actor on the Y axis within its allocation"), CLUTTER_TYPE_ACTOR_ALIGN, CLUTTER_ACTOR_ALIGN_FILL, CLUTTER_PARAM_READWRITE); /** * ClutterActor:margin-top: * * The margin (in pixels) from the top of the actor. * * This property adds a margin to the actor's preferred size; the margin * will be automatically taken into account when allocating the actor. * * The #ClutterActor:margin-top property is animatable. * * Since: 1.10 */ obj_props[PROP_MARGIN_TOP] = g_param_spec_float ("margin-top", P_("Margin Top"), P_("Extra space at the top"), 0.0, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:margin-bottom: * * The margin (in pixels) from the bottom of the actor. * * This property adds a margin to the actor's preferred size; the margin * will be automatically taken into account when allocating the actor. * * The #ClutterActor:margin-bottom property is animatable. * * Since: 1.10 */ obj_props[PROP_MARGIN_BOTTOM] = g_param_spec_float ("margin-bottom", P_("Margin Bottom"), P_("Extra space at the bottom"), 0.0, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:margin-left: * * The margin (in pixels) from the left of the actor. * * This property adds a margin to the actor's preferred size; the margin * will be automatically taken into account when allocating the actor. * * The #ClutterActor:margin-left property is animatable. * * Since: 1.10 */ obj_props[PROP_MARGIN_LEFT] = g_param_spec_float ("margin-left", P_("Margin Left"), P_("Extra space at the left"), 0.0, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:margin-right: * * The margin (in pixels) from the right of the actor. * * This property adds a margin to the actor's preferred size; the margin * will be automatically taken into account when allocating the actor. * * The #ClutterActor:margin-right property is animatable. * * Since: 1.10 */ obj_props[PROP_MARGIN_RIGHT] = g_param_spec_float ("margin-right", P_("Margin Right"), P_("Extra space at the right"), 0.0, G_MAXFLOAT, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:background-color-set: * * Whether the #ClutterActor:background-color property has been set. * * Since: 1.10 */ obj_props[PROP_BACKGROUND_COLOR_SET] = g_param_spec_boolean ("background-color-set", P_("Background Color Set"), P_("Whether the background color is set"), FALSE, CLUTTER_PARAM_READABLE); /** * ClutterActor:background-color: * * Paints a solid fill of the actor's allocation using the specified * color. * * The #ClutterActor:background-color property is animatable. * * Since: 1.10 */ obj_props[PROP_BACKGROUND_COLOR] = clutter_param_spec_color ("background-color", P_("Background color"), P_("The actor's background color"), CLUTTER_COLOR_Transparent, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); /** * ClutterActor:first-child: * * The actor's first child. * * Since: 1.10 */ obj_props[PROP_FIRST_CHILD] = g_param_spec_object ("first-child", P_("First Child"), P_("The actor's first child"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READABLE); /** * ClutterActor:last-child: * * The actor's last child. * * Since: 1.10 */ obj_props[PROP_LAST_CHILD] = g_param_spec_object ("last-child", P_("Last Child"), P_("The actor's last child"), CLUTTER_TYPE_ACTOR, CLUTTER_PARAM_READABLE); /** * ClutterActor:content: * * The #ClutterContent implementation that controls the content * of the actor. * * Since: 1.10 */ obj_props[PROP_CONTENT] = g_param_spec_object ("content", P_("Content"), P_("Delegate object for painting the actor's content"), CLUTTER_TYPE_CONTENT, CLUTTER_PARAM_READWRITE); /** * ClutterActor:content-gravity: * * The alignment that should be honoured by the #ClutterContent * set with the #ClutterActor:content property. * * Changing the value of this property will change the bounding box of * the content; you can use the #ClutterActor:content-box property to * get the position and size of the content within the actor's * allocation. * * This property is meaningful only for #ClutterContent implementations * that have a preferred size, and if the preferred size is smaller than * the actor's allocation. * * The #ClutterActor:content-gravity property is animatable. * * Since: 1.10 */ obj_props[PROP_CONTENT_GRAVITY] = g_param_spec_enum ("content-gravity", P_("Content Gravity"), P_("Alignment of the actor's content"), CLUTTER_TYPE_CONTENT_GRAVITY, CLUTTER_CONTENT_GRAVITY_RESIZE_FILL, CLUTTER_PARAM_READWRITE); /** * ClutterActor:content-box: * * The bounding box for the #ClutterContent used by the actor. * * The value of this property is controlled by the #ClutterActor:allocation * and #ClutterActor:content-gravity properties of #ClutterActor. * * The bounding box for the content is guaranteed to never exceed the * allocation's of the actor. * * Since: 1.10 */ obj_props[PROP_CONTENT_BOX] = g_param_spec_boxed ("content-box", P_("Content Box"), P_("The bounding box of the actor's content"), CLUTTER_TYPE_ACTOR_BOX, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | CLUTTER_PARAM_ANIMATABLE); obj_props[PROP_MINIFICATION_FILTER] = g_param_spec_enum ("minification-filter", P_("Minification Filter"), P_("The filter used when reducing the size of the content"), CLUTTER_TYPE_SCALING_FILTER, CLUTTER_SCALING_FILTER_LINEAR, CLUTTER_PARAM_READWRITE); obj_props[PROP_MAGNIFICATION_FILTER] = g_param_spec_enum ("magnification-filter", P_("Magnification Filter"), P_("The filter used when increasing the size of the content"), CLUTTER_TYPE_SCALING_FILTER, CLUTTER_SCALING_FILTER_LINEAR, CLUTTER_PARAM_READWRITE); /** * ClutterActor:content-repeat: * * The repeat policy for the actor's #ClutterActor:content. * * Since: 1.12 */ obj_props[PROP_CONTENT_REPEAT] = g_param_spec_flags ("content-repeat", P_("Content Repeat"), P_("The repeat policy for the actor's content"), CLUTTER_TYPE_CONTENT_REPEAT, CLUTTER_REPEAT_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, PROP_LAST, obj_props); /** * ClutterActor::destroy: * @actor: the #ClutterActor which emitted the signal * * The ::destroy signal notifies that all references held on the * actor which emitted it should be released. * * The ::destroy signal should be used by all holders of a reference * on @actor. * * This signal might result in the finalization of the #ClutterActor * if all references are released. * * Composite actors and actors implementing the #ClutterContainer * interface should override the default implementation of the * class handler of this signal and call clutter_actor_destroy() on * their children. When overriding the default class handler, it is * required to chain up to the parent's implementation. * * Since: 0.2 */ actor_signals[DESTROY] = g_signal_new (I_("destroy"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (ClutterActorClass, destroy), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::show: * @actor: the object which received the signal * * The ::show signal is emitted when an actor is visible and * rendered on the stage. * * Since: 0.2 */ actor_signals[SHOW] = g_signal_new (I_("show"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterActorClass, show), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::hide: * @actor: the object which received the signal * * The ::hide signal is emitted when an actor is no longer rendered * on the stage. * * Since: 0.2 */ actor_signals[HIDE] = g_signal_new (I_("hide"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (ClutterActorClass, hide), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::parent-set: * @actor: the object which received the signal * @old_parent: (allow-none): the previous parent of the actor, or %NULL * * This signal is emitted when the parent of the actor changes. * * Since: 0.2 */ actor_signals[PARENT_SET] = g_signal_new (I_("parent-set"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, parent_set), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterActor::queue-redraw: * @actor: the actor we're bubbling the redraw request through * @origin: the actor which initiated the redraw request * * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw() * is called on @origin. * * The default implementation for #ClutterActor chains up to the * parent actor and queues a redraw on the parent, thus "bubbling" * the redraw queue up through the actor graph. The default * implementation for #ClutterStage queues a clutter_stage_ensure_redraw() * in a main loop idle handler. * * Note that the @origin actor may be the stage, or a container; it * does not have to be a leaf node in the actor graph. * * Toolkits embedding a #ClutterStage which require a redraw and * relayout cycle can stop the emission of this signal using the * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw() * themselves, like: * * |[ * static void * on_redraw_complete (gpointer data) * { * ClutterStage *stage = data; * * // execute the Clutter drawing pipeline * clutter_stage_ensure_redraw (stage); * } * * static void * on_stage_queue_redraw (ClutterStage *stage) * { * // this prevents the default handler to run * g_signal_stop_emission_by_name (stage, "queue-redraw"); * * // queue a redraw with the host toolkit and call * // a function when the redraw has been completed * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage); * } * ]| * * Note: This signal is emitted before the Clutter paint * pipeline is executed. If you want to know when the pipeline has * been completed you should use clutter_threads_add_repaint_func() * or clutter_threads_add_repaint_func_full(). * * Since: 1.0 */ actor_signals[QUEUE_REDRAW] = g_signal_new (I_("queue-redraw"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (ClutterActorClass, queue_redraw), NULL, NULL, _clutter_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR); /** * ClutterActor::queue-relayout: * @actor: the actor being queued for relayout * * The ::queue_layout signal is emitted when clutter_actor_queue_relayout() * is called on an actor. * * The default implementation for #ClutterActor chains up to the * parent actor and queues a relayout on the parent, thus "bubbling" * the relayout queue up through the actor graph. * * The main purpose of this signal is to allow relayout to be propagated * properly in the procense of #ClutterClone actors. Applications will * not normally need to connect to this signal. * * Since: 1.2 */ actor_signals[QUEUE_RELAYOUT] = g_signal_new (I_("queue-relayout"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (ClutterActorClass, queue_relayout), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::event: * @actor: the actor which received the event * @event: a #ClutterEvent * * The ::event signal is emitted each time an event is received * by the @actor. This signal will be emitted on every actor, * following the hierarchy chain, until it reaches the top-level * container (the #ClutterStage). * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[EVENT] = g_signal_new (I_("event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::button-press-event: * @actor: the actor which received the event * @event: (type ClutterButtonEvent): a #ClutterButtonEvent * * The ::button-press-event signal is emitted each time a mouse button * is pressed on @actor. * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[BUTTON_PRESS_EVENT] = g_signal_new (I_("button-press-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, button_press_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::button-release-event: * @actor: the actor which received the event * @event: (type ClutterButtonEvent): a #ClutterButtonEvent * * The ::button-release-event signal is emitted each time a mouse button * is released on @actor. * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[BUTTON_RELEASE_EVENT] = g_signal_new (I_("button-release-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, button_release_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::scroll-event: * @actor: the actor which received the event * @event: (type ClutterScrollEvent): a #ClutterScrollEvent * * The ::scroll-event signal is emitted each time the mouse is * scrolled on @actor * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[SCROLL_EVENT] = g_signal_new (I_("scroll-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, scroll_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::key-press-event: * @actor: the actor which received the event * @event: (type ClutterKeyEvent): a #ClutterKeyEvent * * The ::key-press-event signal is emitted each time a keyboard button * is pressed while @actor has key focus (see clutter_stage_set_key_focus()). * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[KEY_PRESS_EVENT] = g_signal_new (I_("key-press-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, key_press_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::key-release-event: * @actor: the actor which received the event * @event: (type ClutterKeyEvent): a #ClutterKeyEvent * * The ::key-release-event signal is emitted each time a keyboard button * is released while @actor has key focus (see * clutter_stage_set_key_focus()). * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[KEY_RELEASE_EVENT] = g_signal_new (I_("key-release-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, key_release_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::motion-event: * @actor: the actor which received the event * @event: (type ClutterMotionEvent): a #ClutterMotionEvent * * The ::motion-event signal is emitted each time the mouse pointer is * moved over @actor. * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[MOTION_EVENT] = g_signal_new (I_("motion-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, motion_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::key-focus-in: * @actor: the actor which now has key focus * * The ::key-focus-in signal is emitted when @actor receives key focus. * * Since: 0.6 */ actor_signals[KEY_FOCUS_IN] = g_signal_new (I_("key-focus-in"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, key_focus_in), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::key-focus-out: * @actor: the actor which now has key focus * * The ::key-focus-out signal is emitted when @actor loses key focus. * * Since: 0.6 */ actor_signals[KEY_FOCUS_OUT] = g_signal_new (I_("key-focus-out"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, key_focus_out), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::enter-event: * @actor: the actor which the pointer has entered. * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent * * The ::enter-event signal is emitted when the pointer enters the @actor * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[ENTER_EVENT] = g_signal_new (I_("enter-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, enter_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::leave-event: * @actor: the actor which the pointer has left * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent * * The ::leave-event signal is emitted when the pointer leaves the @actor. * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[LEAVE_EVENT] = g_signal_new (I_("leave-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, leave_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::captured-event: * @actor: the actor which received the signal * @event: a #ClutterEvent * * The ::captured-event signal is emitted when an event is captured * by Clutter. This signal will be emitted starting from the top-level * container (the #ClutterStage) to the actor which received the event * going down the hierarchy. This signal can be used to intercept every * event before the specialized events (like * ClutterActor::button-press-event or ::key-released-event) are * emitted. * * Return value: %TRUE if the event has been handled by the actor, * or %FALSE to continue the emission. * * Since: 0.6 */ actor_signals[CAPTURED_EVENT] = g_signal_new (I_("captured-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, captured_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::paint: * @actor: the #ClutterActor that received the signal * * The ::paint signal is emitted each time an actor is being painted. * * Subclasses of #ClutterActor should override the #ClutterActorClass.paint * virtual function paint themselves in that function. * * It is strongly discouraged to connect a signal handler to * the #ClutterActor::paint signal; if you want to change the paint * sequence of an existing #ClutterActor instance, either create a new * #ClutterActor class and override the #ClutterActorClass.paint virtual * function, or use a #ClutterEffect. The #ClutterActor::paint signal * will be removed in a future version of Clutter. * * Since: 0.8 * * Deprecated: 1.12: Override the #ClutterActorClass.paint virtual * function, use a #ClutterContent implementation, or a #ClutterEffect * instead of connecting to this signal. */ actor_signals[PAINT] = g_signal_new (I_("paint"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS | G_SIGNAL_DEPRECATED, G_STRUCT_OFFSET (ClutterActorClass, paint), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::realize: * @actor: the #ClutterActor that received the signal * * The ::realize signal is emitted each time an actor is being * realized. * * Since: 0.8 * * Deprecated: 1.16: The signal should not be used in newly * written code */ actor_signals[REALIZE] = g_signal_new (I_("realize"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_DEPRECATED, G_STRUCT_OFFSET (ClutterActorClass, realize), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::unrealize: * @actor: the #ClutterActor that received the signal * * The ::unrealize signal is emitted each time an actor is being * unrealized. * * Since: 0.8 * * Deprecated: 1.16: The signal should not be used in newly * written code */ actor_signals[UNREALIZE] = g_signal_new (I_("unrealize"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_DEPRECATED, G_STRUCT_OFFSET (ClutterActorClass, unrealize), NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::pick: * @actor: the #ClutterActor that received the signal * @color: the #ClutterColor to be used when picking * * The ::pick signal is emitted each time an actor is being painted * in "pick mode". The pick mode is used to identify the actor during * the event handling phase, or by clutter_stage_get_actor_at_pos(). * The actor should paint its shape using the passed @pick_color. * * Subclasses of #ClutterActor should override the class signal handler * and paint themselves in that function. * * It is possible to connect a handler to the ::pick signal in order * to set up some custom aspect of a paint in pick mode. * * Since: 1.0 * Deprecated: 1.12: Override the #ClutterActorClass.pick virtual function * instead. */ actor_signals[PICK] = g_signal_new (I_("pick"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_DEPRECATED, G_STRUCT_OFFSET (ClutterActorClass, pick), NULL, NULL, _clutter_marshal_VOID__BOXED, G_TYPE_NONE, 1, CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE); /** * ClutterActor::allocation-changed: * @actor: the #ClutterActor that emitted the signal * @box: a #ClutterActorBox with the new allocation * @flags: #ClutterAllocationFlags for the allocation * * The ::allocation-changed signal is emitted when the * #ClutterActor:allocation property changes. Usually, application * code should just use the notifications for the :allocation property * but if you want to track the allocation flags as well, for instance * to know whether the absolute origin of @actor changed, then you might * want use this signal instead. * * Since: 1.0 */ actor_signals[ALLOCATION_CHANGED] = g_signal_new (I_("allocation-changed"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__BOXED_FLAGS, G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE, CLUTTER_TYPE_ALLOCATION_FLAGS); /** * ClutterActor::transitions-completed: * @actor: a #ClutterActor * * The ::transitions-completed signal is emitted once all transitions * involving @actor are complete. * * Since: 1.10 */ actor_signals[TRANSITIONS_COMPLETED] = g_signal_new (I_("transitions-completed"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * ClutterActor::transition-stopped: * @actor: a #ClutterActor * @name: the name of the transition * @is_finished: whether the transition was finished, or stopped * * The ::transition-stopped signal is emitted once a transition * is stopped; a transition is stopped once it reached its total * duration (including eventual repeats), it has been stopped * using clutter_timeline_stop(), or it has been removed from the * transitions applied on @actor, using clutter_actor_remove_transition(). * * Since: 1.12 */ actor_signals[TRANSITION_STOPPED] = g_signal_new (I_("transition-stopped"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_DETAILED, 0, NULL, NULL, _clutter_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN); /** * ClutterActor::touch-event: * @actor: a #ClutterActor * @event: a #ClutterEvent * * The ::touch-event signal is emitted each time a touch * begin/end/update/cancel event. * * Return value: %CLUTTER_EVENT_STOP if the event has been handled by * the actor, or %CLUTTER_EVENT_PROPAGATE to continue the emission. * * Since: 1.12 */ actor_signals[TOUCH_EVENT] = g_signal_new (I_("touch-event"), G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterActorClass, touch_event), _clutter_boolean_handled_accumulator, NULL, _clutter_marshal_BOOLEAN__BOXED, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); } static void clutter_actor_init (ClutterActor *self) { ClutterActorPrivate *priv; self->priv = priv = clutter_actor_get_instance_private (self); priv->pick_id = -1; priv->opacity = 0xff; priv->show_on_set_parent = TRUE; priv->needs_width_request = TRUE; priv->needs_height_request = TRUE; priv->needs_allocation = TRUE; priv->needs_paint_volume_update = TRUE; priv->cached_width_age = 1; priv->cached_height_age = 1; priv->opacity_override = -1; priv->enable_model_view_transform = TRUE; /* Initialize an empty paint volume to start with */ _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL); priv->last_paint_volume_valid = TRUE; priv->transform_valid = FALSE; /* the default is to stretch the content, to match the * current behaviour of basically all actors. also, it's * the easiest thing to compute. */ priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL; priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR; priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR; /* this flag will be set to TRUE if the actor gets a child * or if the [xy]-expand flags are explicitly set; until * then, the actor does not need to expand. * * this also allows us to avoid computing the expand flag * when building up a scene. */ priv->needs_compute_expand = FALSE; /* we start with an easing state with duration forcibly set * to 0, for backward compatibility. */ clutter_actor_save_easing_state (self); clutter_actor_set_easing_duration (self, 0); } /** * clutter_actor_new: * * Creates a new #ClutterActor. * * A newly created actor has a floating reference, which will be sunk * when it is added to another actor. * * Return value: the newly created #ClutterActor * * Since: 1.10 */ ClutterActor * clutter_actor_new (void) { return g_object_new (CLUTTER_TYPE_ACTOR, NULL); } /** * clutter_actor_destroy: * @self: a #ClutterActor * * Destroys an actor. When an actor is destroyed, it will break any * references it holds to other objects. If the actor is inside a * container, the actor will be removed. * * When you destroy a container, its children will be destroyed as well. * * Note: you cannot destroy the #ClutterStage returned by * clutter_stage_get_default(). */ void clutter_actor_destroy (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_object_ref (self); /* avoid recursion while destroying */ if (!CLUTTER_ACTOR_IN_DESTRUCTION (self)) { CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION); g_object_run_dispose (G_OBJECT (self)); CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION); } g_object_unref (self); } void _clutter_actor_finish_queue_redraw (ClutterActor *self, ClutterPaintVolume *clip) { ClutterActorPrivate *priv = self->priv; ClutterPaintVolume *pv; gboolean clipped; /* Remove queue entry early in the process, otherwise a new queue_redraw() during signal handling could put back this object in the stage redraw list (but the entry is freed as soon as we return from this function, causing a segfault later) */ priv->queue_redraw_entry = NULL; /* If we've been explicitly passed a clip volume then there's * nothing more to calculate, but otherwise the only thing we know * is that the change is constrained to the given actor. * * The idea is that if we know the paint volume for where the actor * was last drawn (in eye coordinates) and we also have the paint * volume for where it will be drawn next (in actor coordinates) * then if we queue a redraw for both these volumes that will cover * everything that needs to be redrawn to clear the old view and * show the latest view of the actor. * * Don't clip this redraw if we don't know what position we had for * the previous redraw since we don't know where to set the clip so * it will clear the actor as it is currently. */ if (clip) { _clutter_actor_set_queue_redraw_clip (self, clip); clipped = TRUE; } else if (G_LIKELY (priv->last_paint_volume_valid)) { pv = _clutter_actor_get_paint_volume_mutable (self); if (pv) { ClutterActor *stage = _clutter_actor_get_stage_internal (self); /* make sure we redraw the actors old position... */ _clutter_actor_set_queue_redraw_clip (stage, &priv->last_paint_volume); _clutter_actor_signal_queue_redraw (stage, stage); _clutter_actor_set_queue_redraw_clip (stage, NULL); /* XXX: Ideally the redraw signal would take a clip volume * argument, but that would be an ABI break. Until we can * break the ABI we pass the argument out-of-band */ /* setup the clip for the actors new position... */ _clutter_actor_set_queue_redraw_clip (self, pv); clipped = TRUE; } else clipped = FALSE; } else clipped = FALSE; _clutter_actor_signal_queue_redraw (self, self); /* Just in case anyone is manually firing redraw signals without * using the public queue_redraw() API we are careful to ensure that * our out-of-band clip member is cleared before returning... * * Note: A NULL clip denotes a full-stage, un-clipped redraw */ if (G_LIKELY (clipped)) _clutter_actor_set_queue_redraw_clip (self, NULL); } static void _clutter_actor_get_allocation_clip (ClutterActor *self, ClutterActorBox *clip) { ClutterActorBox allocation; /* XXX: we don't care if we get an out of date allocation here * because clutter_actor_queue_redraw_with_clip knows to ignore * the clip if the actor's allocation is invalid. * * This is noted because clutter_actor_get_allocation_box does some * unnecessary work to support buggy code with a comment suggesting * that it could be changed later which would be good for this use * case! */ clutter_actor_get_allocation_box (self, &allocation); /* NB: clutter_actor_queue_redraw_with_clip expects a box in the * actor's own coordinate space but the allocation is in parent * coordinates */ clip->x1 = 0; clip->y1 = 0; clip->x2 = allocation.x2 - allocation.x1; clip->y2 = allocation.y2 - allocation.y1; } void _clutter_actor_queue_redraw_full (ClutterActor *self, ClutterRedrawFlags flags, ClutterPaintVolume *volume, ClutterEffect *effect) { ClutterActorPrivate *priv = self->priv; ClutterPaintVolume allocation_pv; ClutterPaintVolume *pv; gboolean should_free_pv; ClutterActor *stage; /* Here's an outline of the actor queue redraw mechanism: * * The process starts in one of the following two functions which * are wrappers for this function: * * clutter_actor_queue_redraw() * _clutter_actor_queue_redraw_with_clip() * * additionally, an effect can queue a redraw by wrapping this * function in clutter_effect_queue_repaint(). * * This functions queues an entry in a list associated with the * stage which is a list of actors that queued a redraw while * updating the timelines, performing layouting and processing other * mainloop sources before the next paint starts. * * We aim to minimize the processing done at this point because * there is a good chance other events will happen while updating * the scenegraph that would invalidate any expensive work we might * otherwise try to do here. For example we don't try and resolve * the screen space bounding box of an actor at this stage so as to * minimize how much of the screen redraw because it's possible * something else will happen which will force a full redraw anyway. * * When all updates are complete and we come to paint the stage then * we iterate this list and actually emit the "queue-redraw" signals * for each of the listed actors which will bubble up to the stage * for each actor and at that point we will transform the actors * paint volume into screen coordinates to determine the clip region * for what needs to be redrawn in the next paint. * * Besides minimizing redundant work another reason for this * deferred design is that it's more likely we will be able to * determine the paint volume of an actor once we've finished * updating the scenegraph because its allocation should be up to * date. NB: If we can't determine an actors paint volume then we * can't automatically queue a clipped redraw which can make a big * difference to performance. * * So the control flow goes like this: * One of clutter_actor_queue_redraw(), * _clutter_actor_queue_redraw_with_clip(), * or clutter_effect_queue_repaint() * * then control moves to: * _clutter_stage_queue_actor_redraw() * * later during _clutter_stage_do_update(), once relayouting is done * and the scenegraph has been updated we will call: * _clutter_stage_finish_queue_redraws(). * * _clutter_stage_finish_queue_redraws() will call * _clutter_actor_finish_queue_redraw() for each listed actor. * * Note: actors *are* allowed to queue further redraws during this * process (considering clone actors or texture_new_from_actor which * respond to their source queueing a redraw by queuing a redraw * themselves). We repeat the process until the list is empty. * * This will result in the "queue-redraw" signal being fired for * each actor which will pass control to the default signal handler: * clutter_actor_real_queue_redraw() * * This will bubble up to the stages handler: * clutter_stage_real_queue_redraw() * * clutter_stage_real_queue_redraw() will transform the actors paint * volume into screen space and add it as a clip region for the next * paint. */ /* ignore queueing a redraw for actors being destroyed */ if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) return; /* we can ignore unmapped actors, unless they have at least one * mapped clone or they are inside a cloned branch of the scene * graph, as unmapped actors will simply be left unpainted. * * this allows us to ignore redraws queued on leaf nodes when one * of their parents has been hidden */ if (!CLUTTER_ACTOR_IS_MAPPED (self) && self->priv->in_cloned_branch == 0 && !clutter_actor_has_mapped_clones (self)) { CLUTTER_NOTE (PAINT, "Skipping queue_redraw('%s'): mapped=%s, " "mapped_clones=%s, " "in_cloned_branch=%s", _clutter_actor_get_debug_name (self), CLUTTER_ACTOR_IS_MAPPED (self) ? "yes" : "no", clutter_actor_has_mapped_clones (self) ? "yes" : "no", self->priv->in_cloned_branch != 0 ? "yes" : "no"); return; } /* given the check above we could end up queueing a redraw on an * unmapped actor with mapped clones, so we cannot assume that * get_stage() will return a Stage */ stage = _clutter_actor_get_stage_internal (self); if (stage == NULL) return; /* ignore queueing a redraw on stages that are being destroyed */ if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION) { ClutterActorBox allocation_clip; ClutterVertex origin; /* If the actor doesn't have a valid allocation then we will * queue a full stage redraw. */ if (priv->needs_allocation) { /* NB: NULL denotes an undefined clip which will result in a * full redraw... */ _clutter_actor_set_queue_redraw_clip (self, NULL); _clutter_actor_signal_queue_redraw (self, self); return; } _clutter_paint_volume_init_static (&allocation_pv, self); pv = &allocation_pv; _clutter_actor_get_allocation_clip (self, &allocation_clip); origin.x = allocation_clip.x1; origin.y = allocation_clip.y1; origin.z = 0; clutter_paint_volume_set_origin (pv, &origin); clutter_paint_volume_set_width (pv, allocation_clip.x2 - allocation_clip.x1); clutter_paint_volume_set_height (pv, allocation_clip.y2 - allocation_clip.y1); should_free_pv = TRUE; } else { pv = volume; should_free_pv = FALSE; self->priv->needs_paint_volume_update = TRUE; } self->priv->queue_redraw_entry = _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage), priv->queue_redraw_entry, self, pv); if (should_free_pv) clutter_paint_volume_free (pv); /* If this is the first redraw queued then we can directly use the effect parameter */ if (!priv->is_dirty) priv->effect_to_redraw = effect; /* Otherwise we need to merge it with the existing effect parameter */ else if (effect != NULL) { /* If there's already an effect then we need to use whichever is later in the chain of actors. Otherwise a full redraw has already been queued on the actor so we need to ignore the effect parameter */ if (priv->effect_to_redraw != NULL) { if (priv->effects == NULL) g_warning ("Redraw queued with an effect that is " "not applied to the actor"); else { const GList *l; for (l = _clutter_meta_group_peek_metas (priv->effects); l != NULL; l = l->next) { if (l->data == priv->effect_to_redraw || l->data == effect) priv->effect_to_redraw = l->data; } } } } else { /* If no effect is specified then we need to redraw the whole actor */ priv->effect_to_redraw = NULL; } priv->is_dirty = TRUE; } /** * clutter_actor_queue_redraw: * @self: A #ClutterActor * * Queues up a redraw of an actor and any children. The redraw occurs * once the main loop becomes idle (after the current batch of events * has been processed, roughly). * * Applications rarely need to call this, as redraws are handled * automatically by modification functions. * * This function will not do anything if @self is not visible, or * if the actor is inside an invisible part of the scenegraph. * * Also be aware that painting is a NOP for actors with an opacity of * 0 * * When you are implementing a custom actor you must queue a redraw * whenever some private state changes that will affect painting or * picking of your actor. */ void clutter_actor_queue_redraw (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); _clutter_actor_queue_redraw_full (self, 0, /* flags */ NULL, /* clip volume */ NULL /* effect */); } /*< private > * _clutter_actor_queue_redraw_with_clip: * @self: A #ClutterActor * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of * this queue redraw. * @volume: A #ClutterPaintVolume describing the bounds of what needs to be * redrawn or %NULL if you are just using a @flag to state your * desired clipping. * * Queues up a clipped redraw of an actor and any children. The redraw * occurs once the main loop becomes idle (after the current batch of * events has been processed, roughly). * * If no flags are given the clip volume is defined by @volume * specified in actor coordinates and tells Clutter that only content * within this volume has been changed so Clutter can optionally * optimize the redraw. * * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume * should be %NULL and this tells Clutter to use the actor's current * allocation as a clip box. This flag can only be used for 2D actors, * because any actor with depth may be projected outside its * allocation. * * Applications rarely need to call this, as redraws are handled * automatically by modification functions. * * This function will not do anything if @self is not visible, or if * the actor is inside an invisible part of the scenegraph. * * Also be aware that painting is a NOP for actors with an opacity of * 0 * * When you are implementing a custom actor you must queue a redraw * whenever some private state changes that will affect painting or * picking of your actor. */ void _clutter_actor_queue_redraw_with_clip (ClutterActor *self, ClutterRedrawFlags flags, ClutterPaintVolume *volume) { _clutter_actor_queue_redraw_full (self, flags, /* flags */ volume, /* clip volume */ NULL /* effect */); } void _clutter_actor_queue_only_relayout (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) return; if (priv->needs_width_request && priv->needs_height_request && priv->needs_allocation) return; /* save some cpu cycles */ #if CLUTTER_ENABLE_DEBUG if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self)) { g_warning ("The actor '%s' is currently inside an allocation " "cycle; calling clutter_actor_queue_relayout() is " "not recommended", _clutter_actor_get_debug_name (self)); } #endif /* CLUTTER_ENABLE_DEBUG */ _clutter_actor_queue_relayout_on_clones (self); g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0); } /** * clutter_actor_queue_redraw_with_clip: * @self: a #ClutterActor * @clip: (allow-none): a rectangular clip region, or %NULL * * Queues a redraw on @self limited to a specific, actor-relative * rectangular area. * * If @clip is %NULL this function is equivalent to * clutter_actor_queue_redraw(). * * Since: 1.10 */ void clutter_actor_queue_redraw_with_clip (ClutterActor *self, const cairo_rectangle_int_t *clip) { ClutterPaintVolume volume; ClutterVertex origin; g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (clip == NULL) { clutter_actor_queue_redraw (self); return; } _clutter_paint_volume_init_static (&volume, self); origin.x = clip->x; origin.y = clip->y; origin.z = 0.0f; clutter_paint_volume_set_origin (&volume, &origin); clutter_paint_volume_set_width (&volume, clip->width); clutter_paint_volume_set_height (&volume, clip->height); _clutter_actor_queue_redraw_full (self, 0, &volume, NULL); clutter_paint_volume_free (&volume); } /** * clutter_actor_queue_relayout: * @self: A #ClutterActor * * Indicates that the actor's size request or other layout-affecting * properties may have changed. This function is used inside #ClutterActor * subclass implementations, not by applications directly. * * Queueing a new layout automatically queues a redraw as well. * * Since: 0.8 */ void clutter_actor_queue_relayout (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); _clutter_actor_queue_only_relayout (self); clutter_actor_queue_redraw (self); } /** * clutter_actor_get_preferred_size: * @self: a #ClutterActor * @min_width_p: (out) (allow-none): return location for the minimum * width, or %NULL * @min_height_p: (out) (allow-none): return location for the minimum * height, or %NULL * @natural_width_p: (out) (allow-none): return location for the natural * width, or %NULL * @natural_height_p: (out) (allow-none): return location for the natural * height, or %NULL * * Computes the preferred minimum and natural size of an actor, taking into * account the actor's geometry management (either height-for-width * or width-for-height). * * The width and height used to compute the preferred height and preferred * width are the actor's natural ones. * * If you need to control the height for the preferred width, or the width for * the preferred height, you should use clutter_actor_get_preferred_width() * and clutter_actor_get_preferred_height(), and check the actor's preferred * geometry management using the #ClutterActor:request-mode property. * * Since: 0.8 */ void clutter_actor_get_preferred_size (ClutterActor *self, gfloat *min_width_p, gfloat *min_height_p, gfloat *natural_width_p, gfloat *natural_height_p) { ClutterActorPrivate *priv; gfloat min_width, min_height; gfloat natural_width, natural_height; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; min_width = min_height = 0; natural_width = natural_height = 0; if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) { CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)"); clutter_actor_get_preferred_width (self, -1, &min_width, &natural_width); clutter_actor_get_preferred_height (self, natural_width, &min_height, &natural_height); } else if (priv->request_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) { CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)"); clutter_actor_get_preferred_height (self, -1, &min_height, &natural_height); clutter_actor_get_preferred_width (self, natural_height, &min_width, &natural_width); } else if (priv->request_mode == CLUTTER_REQUEST_CONTENT_SIZE) { CLUTTER_NOTE (LAYOUT, "Preferred size (content-size)"); if (priv->content != NULL) clutter_content_get_preferred_size (priv->content, &natural_width, &natural_height); } else { CLUTTER_NOTE (LAYOUT, "Unknown request mode"); } if (min_width_p) *min_width_p = min_width; if (min_height_p) *min_height_p = min_height; if (natural_width_p) *natural_width_p = natural_width; if (natural_height_p) *natural_height_p = natural_height; } /*< private > * effective_align: * @align: a #ClutterActorAlign * @direction: a #ClutterTextDirection * * Retrieves the correct alignment depending on the text direction * * Return value: the effective alignment */ static ClutterActorAlign effective_align (ClutterActorAlign align, ClutterTextDirection direction) { ClutterActorAlign res; switch (align) { case CLUTTER_ACTOR_ALIGN_START: res = (direction == CLUTTER_TEXT_DIRECTION_RTL) ? CLUTTER_ACTOR_ALIGN_END : CLUTTER_ACTOR_ALIGN_START; break; case CLUTTER_ACTOR_ALIGN_END: res = (direction == CLUTTER_TEXT_DIRECTION_RTL) ? CLUTTER_ACTOR_ALIGN_START : CLUTTER_ACTOR_ALIGN_END; break; default: res = align; break; } return res; } /*< private > * _clutter_actor_get_effective_x_align: * @self: a #ClutterActor * * Retrieves the effective horizontal alignment, taking into * consideration the text direction of @self. * * Return value: the effective horizontal alignment */ ClutterActorAlign _clutter_actor_get_effective_x_align (ClutterActor *self) { return effective_align (clutter_actor_get_x_align (self), clutter_actor_get_text_direction (self)); } static inline void adjust_for_margin (float margin_start, float margin_end, float *minimum_size, float *natural_size, float *allocated_start, float *allocated_end) { float min_size = *minimum_size; float nat_size = *natural_size; float start = *allocated_start; float end = *allocated_end; min_size = MAX (min_size - (margin_start + margin_end), 0); nat_size = MAX (nat_size - (margin_start + margin_end), 0); *minimum_size = min_size; *natural_size = nat_size; start += margin_start; end -= margin_end; if (end - start >= 0) { *allocated_start = start; *allocated_end = end; } } static inline void adjust_for_alignment (ClutterActorAlign alignment, float natural_size, float *allocated_start, float *allocated_end) { float allocated_size = *allocated_end - *allocated_start; if (allocated_size <= 0.f) return; switch (alignment) { case CLUTTER_ACTOR_ALIGN_FILL: /* do nothing */ break; case CLUTTER_ACTOR_ALIGN_START: /* keep start */ *allocated_end = *allocated_start + MIN (natural_size, allocated_size); break; case CLUTTER_ACTOR_ALIGN_END: if (allocated_size > natural_size) { *allocated_start += (allocated_size - natural_size); *allocated_end = *allocated_start + natural_size; } break; case CLUTTER_ACTOR_ALIGN_CENTER: if (allocated_size > natural_size) { *allocated_start += floorf ((allocated_size - natural_size) / 2); *allocated_end = *allocated_start + MIN (allocated_size, natural_size); } break; } } /*< private > * clutter_actor_adjust_width: * @self: a #ClutterActor * @minimum_width: (inout): the actor's preferred minimum width, which * will be adjusted depending on the margin * @natural_width: (inout): the actor's preferred natural width, which * will be adjusted depending on the margin * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box * * Adjusts the preferred and allocated position and size of an actor, * depending on the margin and alignment properties. */ static void clutter_actor_adjust_width (ClutterActor *self, gfloat *minimum_width, gfloat *natural_width, gfloat *adjusted_x1, gfloat *adjusted_x2) { ClutterTextDirection text_dir; const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (self); text_dir = clutter_actor_get_text_direction (self); CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width"); /* this will tweak natural_width to remove the margin, so that * adjust_for_alignment() will use the correct size */ adjust_for_margin (info->margin.left, info->margin.right, minimum_width, natural_width, adjusted_x1, adjusted_x2); adjust_for_alignment (effective_align (info->x_align, text_dir), *natural_width, adjusted_x1, adjusted_x2); } /*< private > * clutter_actor_adjust_height: * @self: a #ClutterActor * @minimum_height: (inout): the actor's preferred minimum height, which * will be adjusted depending on the margin * @natural_height: (inout): the actor's preferred natural height, which * will be adjusted depending on the margin * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box * * Adjusts the preferred and allocated position and size of an actor, * depending on the margin and alignment properties. */ static void clutter_actor_adjust_height (ClutterActor *self, gfloat *minimum_height, gfloat *natural_height, gfloat *adjusted_y1, gfloat *adjusted_y2) { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (self); CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height"); /* this will tweak natural_height to remove the margin, so that * adjust_for_alignment() will use the correct size */ adjust_for_margin (info->margin.top, info->margin.bottom, minimum_height, natural_height, adjusted_y1, adjusted_y2); /* we don't use effective_align() here, because text direction * only affects the horizontal axis */ adjust_for_alignment (info->y_align, *natural_height, adjusted_y1, adjusted_y2); } /* looks for a cached size request for this for_size. If not * found, returns the oldest entry so it can be overwritten */ static gboolean _clutter_actor_get_cached_size_request (gfloat for_size, SizeRequest *cached_size_requests, SizeRequest **result) { guint i; *result = &cached_size_requests[0]; for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++) { SizeRequest *sr; sr = &cached_size_requests[i]; if (sr->age > 0 && sr->for_size == for_size) { CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size); *result = sr; return TRUE; } else if (sr->age < (*result)->age) { *result = sr; } } CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size); return FALSE; } static void clutter_actor_update_preferred_size_for_constraints (ClutterActor *self, ClutterOrientation direction, float for_size, float *minimum_size, float *natural_size) { ClutterActorPrivate *priv = self->priv; const GList *constraints, *l; if (priv->constraints == NULL) return; constraints = _clutter_meta_group_peek_metas (priv->constraints); for (l = constraints; l != NULL; l = l->next) { ClutterConstraint *constraint = l->data; ClutterActorMeta *meta = l->data; if (!clutter_actor_meta_get_enabled (meta)) continue; clutter_constraint_update_preferred_size (constraint, self, direction, for_size, minimum_size, natural_size); CLUTTER_NOTE (LAYOUT, "Preferred %s of '%s' after constraint '%s': " "{ min:%.2f, nat:%.2f }", direction == CLUTTER_ORIENTATION_HORIZONTAL ? "width" : "height", _clutter_actor_get_debug_name (self), _clutter_actor_meta_get_debug_name (meta), *minimum_size, *natural_size); } } /** * clutter_actor_get_preferred_width: * @self: A #ClutterActor * @for_height: available height when computing the preferred width, * or a negative value to indicate that no height is defined * @min_width_p: (out) (allow-none): return location for minimum width, * or %NULL * @natural_width_p: (out) (allow-none): return location for the natural * width, or %NULL * * Computes the requested minimum and natural widths for an actor, * optionally depending on the specified height, or if they are * already computed, returns the cached values. * * An actor may not get its request - depending on the layout * manager that's in effect. * * A request should not incorporate the actor's scale or anchor point; * those transformations do not affect layout, only rendering. * * Since: 0.8 */ void clutter_actor_get_preferred_width (ClutterActor *self, gfloat for_height, gfloat *min_width_p, gfloat *natural_width_p) { float request_min_width, request_natural_width; SizeRequest *cached_size_request; const ClutterLayoutInfo *info; ClutterActorPrivate *priv; gboolean found_in_cache; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; info = _clutter_actor_get_layout_info_or_defaults (self); /* we shortcircuit the case of a fixed size set using set_width() */ if (priv->min_width_set && priv->natural_width_set) { if (min_width_p != NULL) *min_width_p = info->minimum.width + (info->margin.left + info->margin.right); if (natural_width_p != NULL) *natural_width_p = info->natural.width + (info->margin.left + info->margin.right); return; } /* the remaining cases are: * * - either min_width or natural_width have been set * - neither min_width or natural_width have been set * * in both cases, we go through the cache (and through the actor in case * of cache misses) and determine the authoritative value depending on * the *_set flags. */ if (!priv->needs_width_request) { found_in_cache = _clutter_actor_get_cached_size_request (for_height, priv->width_requests, &cached_size_request); } else { /* if the actor needs a width request we use the first slot */ found_in_cache = FALSE; cached_size_request = &priv->width_requests[0]; } if (!found_in_cache) { gfloat minimum_width, natural_width; ClutterActorClass *klass; minimum_width = natural_width = 0; /* adjust for the margin */ if (for_height >= 0) { for_height -= (info->margin.top + info->margin.bottom); if (for_height < 0) for_height = 0; } CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height); klass = CLUTTER_ACTOR_GET_CLASS (self); klass->get_preferred_width (self, for_height, &minimum_width, &natural_width); /* adjust for constraints */ clutter_actor_update_preferred_size_for_constraints (self, CLUTTER_ORIENTATION_HORIZONTAL, for_height, &minimum_width, &natural_width); /* adjust for the margin */ minimum_width += (info->margin.left + info->margin.right); natural_width += (info->margin.left + info->margin.right); /* Due to accumulated float errors, it's better not to warn * on this, but just fix it. */ if (natural_width < minimum_width) natural_width = minimum_width; cached_size_request->min_size = minimum_width; cached_size_request->natural_size = natural_width; cached_size_request->for_size = for_height; cached_size_request->age = priv->cached_width_age; priv->cached_width_age += 1; priv->needs_width_request = FALSE; } if (!priv->min_width_set) request_min_width = cached_size_request->min_size; else request_min_width = info->margin.left + info->minimum.width + info->margin.right; if (!priv->natural_width_set) request_natural_width = cached_size_request->natural_size; else request_natural_width = info->margin.left + info->natural.width + info->margin.right; if (min_width_p) *min_width_p = request_min_width; if (natural_width_p) *natural_width_p = request_natural_width; } /** * clutter_actor_get_preferred_height: * @self: A #ClutterActor * @for_width: available width to assume in computing desired height, * or a negative value to indicate that no width is defined * @min_height_p: (out) (allow-none): return location for minimum height, * or %NULL * @natural_height_p: (out) (allow-none): return location for natural * height, or %NULL * * Computes the requested minimum and natural heights for an actor, * or if they are already computed, returns the cached values. * * An actor may not get its request - depending on the layout * manager that's in effect. * * A request should not incorporate the actor's scale or anchor point; * those transformations do not affect layout, only rendering. * * Since: 0.8 */ void clutter_actor_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { float request_min_height, request_natural_height; SizeRequest *cached_size_request; const ClutterLayoutInfo *info; ClutterActorPrivate *priv; gboolean found_in_cache; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; info = _clutter_actor_get_layout_info_or_defaults (self); /* we shortcircuit the case of a fixed size set using set_height() */ if (priv->min_height_set && priv->natural_height_set) { if (min_height_p != NULL) *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom); if (natural_height_p != NULL) *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom); return; } /* the remaining cases are: * * - either min_height or natural_height have been set * - neither min_height or natural_height have been set * * in both cases, we go through the cache (and through the actor in case * of cache misses) and determine the authoritative value depending on * the *_set flags. */ if (!priv->needs_height_request) { found_in_cache = _clutter_actor_get_cached_size_request (for_width, priv->height_requests, &cached_size_request); } else { found_in_cache = FALSE; cached_size_request = &priv->height_requests[0]; } if (!found_in_cache) { gfloat minimum_height, natural_height; ClutterActorClass *klass; minimum_height = natural_height = 0; CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width); /* adjust for margin */ if (for_width >= 0) { for_width -= (info->margin.left + info->margin.right); if (for_width < 0) for_width = 0; } klass = CLUTTER_ACTOR_GET_CLASS (self); klass->get_preferred_height (self, for_width, &minimum_height, &natural_height); /* adjust for constraints */ clutter_actor_update_preferred_size_for_constraints (self, CLUTTER_ORIENTATION_VERTICAL, for_width, &minimum_height, &natural_height); /* adjust for margin */ minimum_height += (info->margin.top + info->margin.bottom); natural_height += (info->margin.top + info->margin.bottom); /* Due to accumulated float errors, it's better not to warn * on this, but just fix it. */ if (natural_height < minimum_height) natural_height = minimum_height; cached_size_request->min_size = minimum_height; cached_size_request->natural_size = natural_height; cached_size_request->for_size = for_width; cached_size_request->age = priv->cached_height_age; priv->cached_height_age += 1; priv->needs_height_request = FALSE; } if (!priv->min_height_set) request_min_height = cached_size_request->min_size; else request_min_height = info->margin.top + info->minimum.height + info->margin.bottom; if (!priv->natural_height_set) request_natural_height = cached_size_request->natural_size; else request_natural_height = info->margin.top + info->natural.height + info->margin.bottom; if (min_height_p) *min_height_p = request_min_height; if (natural_height_p) *natural_height_p = request_natural_height; } /** * clutter_actor_get_allocation_box: * @self: A #ClutterActor * @box: (out): the function fills this in with the actor's allocation * * Gets the layout box an actor has been assigned. The allocation can * only be assumed valid inside a paint() method; anywhere else, it * may be out-of-date. * * An allocation does not incorporate the actor's scale or anchor point; * those transformations do not affect layout, only rendering. * * Do not call any of the clutter_actor_get_allocation_*() family * of functions inside the implementation of the get_preferred_width() * or get_preferred_height() virtual functions. * * Since: 0.8 */ void clutter_actor_get_allocation_box (ClutterActor *self, ClutterActorBox *box) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail, * which limits calling get_allocation to inside paint() basically; or * we can 2) force a layout, which could be expensive if someone calls * get_allocation somewhere silly; or we can 3) just return the latest * value, allowing it to be out-of-date, and assume people know what * they are doing. * * The least-surprises approach that keeps existing code working is * likely to be 2). People can end up doing some inefficient things, * though, and in general code that requires 2) is probably broken. */ /* this implements 2) */ if (G_UNLIKELY (self->priv->needs_allocation)) { ClutterActor *stage = _clutter_actor_get_stage_internal (self); /* do not queue a relayout on an unparented actor */ if (stage) _clutter_stage_maybe_relayout (stage); } /* commenting out the code above and just keeping this assigment * implements 3) */ *box = self->priv->allocation; } static void clutter_actor_update_constraints (ClutterActor *self, ClutterActorBox *allocation) { ClutterActorPrivate *priv = self->priv; const GList *constraints, *l; if (priv->constraints == NULL) return; constraints = _clutter_meta_group_peek_metas (priv->constraints); for (l = constraints; l != NULL; l = l->next) { ClutterConstraint *constraint = l->data; ClutterActorMeta *meta = l->data; gboolean changed = FALSE; if (clutter_actor_meta_get_enabled (meta)) { changed |= clutter_constraint_update_allocation (constraint, self, allocation); CLUTTER_NOTE (LAYOUT, "Allocation of '%s' after constraint '%s': " "{ %.2f, %.2f, %.2f, %.2f } (changed:%s)", _clutter_actor_get_debug_name (self), _clutter_actor_meta_get_debug_name (meta), allocation->x1, allocation->y1, allocation->x2, allocation->y2, changed ? "yes" : "no"); } } } /*< private > * clutter_actor_adjust_allocation: * @self: a #ClutterActor * @allocation: (inout): the allocation to adjust * * Adjusts the passed allocation box taking into account the actor's * layout information, like alignment, expansion, and margin. */ static void clutter_actor_adjust_allocation (ClutterActor *self, ClutterActorBox *allocation) { ClutterActorBox adj_allocation; float alloc_width, alloc_height; float min_width, min_height; float nat_width, nat_height; ClutterRequestMode req_mode; adj_allocation = *allocation; clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height); /* There's no point in trying to adjust a zero-sized actor */ if (alloc_width == 0.f && alloc_height == 0.f) return; /* we want to hit the cache, so we use the public API */ req_mode = clutter_actor_get_request_mode (self); if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) { clutter_actor_get_preferred_width (self, -1, &min_width, &nat_width); clutter_actor_get_preferred_height (self, alloc_width, &min_height, &nat_height); } else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) { clutter_actor_get_preferred_height (self, -1, &min_height, &nat_height); clutter_actor_get_preferred_width (self, alloc_height, &min_width, &nat_width); } else if (req_mode == CLUTTER_REQUEST_CONTENT_SIZE) { min_width = min_height = 0; nat_width = nat_height = 0; if (self->priv->content != NULL) clutter_content_get_preferred_size (self->priv->content, &nat_width, &nat_height); } #ifdef CLUTTER_ENABLE_DEBUG /* warn about underallocations */ if (_clutter_diagnostic_enabled () && (floorf (min_width - alloc_width) > 0 || floorf (min_height - alloc_height) > 0)) { ClutterActor *parent = clutter_actor_get_parent (self); /* the only actors that are allowed to be underallocated are the Stage, * as it doesn't have an implicit size, and Actors that specifically * told us that they want to opt-out from layout control mechanisms * through the NO_LAYOUT escape hatch. */ if (parent != NULL && !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0) { g_warning (G_STRLOC ": The actor '%s' is getting an allocation " "of %.2f x %.2f from its parent actor '%s', but its " "requested minimum size is of %.2f x %.2f", _clutter_actor_get_debug_name (self), alloc_width, alloc_height, _clutter_actor_get_debug_name (parent), min_width, min_height); } } #endif clutter_actor_adjust_width (self, &min_width, &nat_width, &adj_allocation.x1, &adj_allocation.x2); clutter_actor_adjust_height (self, &min_height, &nat_height, &adj_allocation.y1, &adj_allocation.y2); /* we maintain the invariant that an allocation cannot be adjusted * to be outside the parent-given box */ if (adj_allocation.x1 < allocation->x1 || adj_allocation.y1 < allocation->y1 || adj_allocation.x2 > allocation->x2 || adj_allocation.y2 > allocation->y2) { g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation " "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its " "original allocation of { %.2f, %.2f, %.2f, %.2f }", _clutter_actor_get_debug_name (self), adj_allocation.x1, adj_allocation.y1, adj_allocation.x2 - adj_allocation.x1, adj_allocation.y2 - adj_allocation.y1, allocation->x1, allocation->y1, allocation->x2 - allocation->x1, allocation->y2 - allocation->y1); return; } *allocation = adj_allocation; } static void clutter_actor_allocate_internal (ClutterActor *self, const ClutterActorBox *allocation, ClutterAllocationFlags flags) { ClutterActorClass *klass; CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT); CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()", _clutter_actor_get_debug_name (self)); klass = CLUTTER_ACTOR_GET_CLASS (self); klass->allocate (self, allocation, flags); CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT); /* Caller should call clutter_actor_queue_redraw() if needed * for that particular case. */ } /** * clutter_actor_allocate: * @self: A #ClutterActor * @box: new allocation of the actor, in parent-relative coordinates * @flags: flags that control the allocation * * Assigns the size of a #ClutterActor from the given @box. * * This function should only be called on the children of an actor when * overriding the #ClutterActorClass.allocate() virtual function. * * This function will adjust the stored allocation to take into account * the alignment flags set in the #ClutterActor:x-align and * #ClutterActor:y-align properties, as well as the margin values set in * the #ClutterActor:margin-top, #ClutterActor:margin-right, * #ClutterActor:margin-bottom, and #ClutterActor:margin-left properties. * * This function will respect the easing state of the #ClutterActor and * interpolate between the current allocation and the new one if the * easing state duration is a positive value. * * Actors can know from their allocation box whether they have moved * with respect to their parent actor. The @flags parameter describes * additional information about the allocation, for instance whether * the parent has moved with respect to the stage, for example because * a grandparent's origin has moved. * * Since: 0.8 */ void clutter_actor_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterActorBox old_allocation, real_allocation; gboolean origin_changed, child_moved, size_changed; gboolean stage_allocation_changed; ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL)) { g_warning ("Spurious clutter_actor_allocate called for actor %p/%s " "which isn't a descendent of the stage!\n", self, _clutter_actor_get_debug_name (self)); return; } priv = self->priv; old_allocation = priv->allocation; real_allocation = *box; /* constraints are allowed to modify the allocation only here; we do * this prior to all the other checks so that we can bail out if the * allocation did not change */ clutter_actor_update_constraints (self, &real_allocation); /* adjust the allocation depending on the align/margin properties */ clutter_actor_adjust_allocation (self, &real_allocation); if (real_allocation.x2 < real_allocation.x1 || real_allocation.y2 < real_allocation.y1) { g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f", _clutter_actor_get_debug_name (self), real_allocation.x2 - real_allocation.x1, real_allocation.y2 - real_allocation.y1); } /* we allow 0-sized actors, but not negative-sized ones */ real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1); real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1); origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED); child_moved = (real_allocation.x1 != old_allocation.x1 || real_allocation.y1 != old_allocation.y1); size_changed = (real_allocation.x2 != old_allocation.x2 || real_allocation.y2 != old_allocation.y2); if (origin_changed || child_moved || size_changed) stage_allocation_changed = TRUE; else stage_allocation_changed = FALSE; /* If we get an allocation "out of the blue" * (we did not queue relayout), then we want to * ignore it. But if we have needs_allocation set, * we want to guarantee that allocate() virtual * method is always called, i.e. that queue_relayout() * always results in an allocate() invocation on * an actor. * * The optimization here is to avoid re-allocating * actors that did not queue relayout and were * not moved. */ if (!priv->needs_allocation && !stage_allocation_changed) { CLUTTER_NOTE (LAYOUT, "No allocation needed"); return; } if (CLUTTER_ACTOR_IS_MAPPED (self)) self->priv->needs_paint_volume_update = TRUE; if (!stage_allocation_changed) { /* If the actor didn't move but needs_allocation is set, we just * need to allocate the children */ clutter_actor_allocate_internal (self, &real_allocation, flags); return; } /* When ABSOLUTE_ORIGIN_CHANGED is passed in to * clutter_actor_allocate(), it indicates whether the parent has its * absolute origin moved; when passed in to ClutterActor::allocate() * virtual method though, it indicates whether the child has its * absolute origin moved. So we set it when child_moved is TRUE */ if (child_moved) flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED; /* store the flags here, so that they can be propagated by the * transition code */ self->priv->allocation_flags = flags; _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION], &priv->allocation, &real_allocation); } /** * clutter_actor_set_allocation: * @self: a #ClutterActor * @box: a #ClutterActorBox * @flags: allocation flags * * Stores the allocation of @self as defined by @box. * * This function can only be called from within the implementation of * the #ClutterActorClass.allocate() virtual function. * * The allocation should have been adjusted to take into account constraints, * alignment, and margin properties. If you are implementing a #ClutterActor * subclass that provides its own layout management policy for its children * instead of using a #ClutterLayoutManager delegate, you should not call * this function on the children of @self; instead, you should call * clutter_actor_allocate(), which will adjust the allocation box for * you. * * This function should only be used by subclasses of #ClutterActor * that wish to store their allocation but cannot chain up to the * parent's implementation; the default implementation of the * #ClutterActorClass.allocate() virtual function will call this * function. * * It is important to note that, while chaining up was the recommended * behaviour for #ClutterActor subclasses prior to the introduction of * this function, it is recommended to call clutter_actor_set_allocation() * instead. * * If the #ClutterActor is using a #ClutterLayoutManager delegate object * to handle the allocation of its children, this function will call * the clutter_layout_manager_allocate() function only if the * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is * expected that the subclass will call clutter_layout_manager_allocate() * by itself. For instance, the following code: * * |[ * static void * my_actor_allocate (ClutterActor *actor, * const ClutterActorBox *allocation, * ClutterAllocationFlags flags) * { * ClutterActorBox new_alloc; * ClutterAllocationFlags new_flags; * * adjust_allocation (allocation, &new_alloc); * * new_flags = flags | CLUTTER_DELEGATE_LAYOUT; * * // this will use the layout manager set on the actor * clutter_actor_set_allocation (actor, &new_alloc, new_flags); * } * ]| * * is equivalent to this: * * |[ * static void * my_actor_allocate (ClutterActor *actor, * const ClutterActorBox *allocation, * ClutterAllocationFlags flags) * { * ClutterLayoutManager *layout; * ClutterActorBox new_alloc; * * adjust_allocation (allocation, &new_alloc); * * clutter_actor_set_allocation (actor, &new_alloc, flags); * * layout = clutter_actor_get_layout_manager (actor); * clutter_layout_manager_allocate (layout, * CLUTTER_CONTAINER (actor), * &new_alloc, * flags); * } * ]| * * Since: 1.10 */ void clutter_actor_set_allocation (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterActorPrivate *priv; gboolean changed; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (box != NULL); if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self))) { g_critical (G_STRLOC ": The clutter_actor_set_allocation() function " "can only be called from within the implementation of " "the ClutterActor::allocate() virtual function."); return; } priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); changed = clutter_actor_set_allocation_internal (self, box, flags); /* we allocate our children before we notify changes in our geometry, * so that people connecting to properties will be able to get valid * data out of the sub-tree of the scene graph that has this actor at * the root. */ clutter_actor_maybe_layout_children (self, box, flags); if (changed) { ClutterActorBox signal_box = priv->allocation; ClutterAllocationFlags signal_flags = priv->allocation_flags; g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0, &signal_box, signal_flags); } g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_set_position: * @self: A #ClutterActor * @x: New left position of actor in pixels. * @y: New top position of actor in pixels. * * Sets the actor's fixed position in pixels relative to any parent * actor. * * If a layout manager is in use, this position will override the * layout manager and force a fixed position. */ void clutter_actor_set_position (ClutterActor *self, gfloat x, gfloat y) { ClutterPoint new_position; ClutterPoint cur_position; g_return_if_fail (CLUTTER_IS_ACTOR (self)); clutter_point_init (&new_position, x, y); cur_position.x = clutter_actor_get_x (self); cur_position.y = clutter_actor_get_y (self); _clutter_actor_create_transition (self, obj_props[PROP_POSITION], &cur_position, &new_position); } /** * clutter_actor_get_fixed_position_set: * @self: A #ClutterActor * * Checks whether an actor has a fixed position set (and will thus be * unaffected by any layout manager). * * Return value: %TRUE if the fixed position is set on the actor * * Since: 0.8 */ gboolean clutter_actor_get_fixed_position_set (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return self->priv->position_set; } /** * clutter_actor_set_fixed_position_set: * @self: A #ClutterActor * @is_set: whether to use fixed position * * Sets whether an actor has a fixed position set (and will thus be * unaffected by any layout manager). * * Since: 0.8 */ void clutter_actor_set_fixed_position_set (ClutterActor *self, gboolean is_set) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->position_set == (is_set != FALSE)) return; if (!is_set) { ClutterLayoutInfo *info; /* Ensure we set back the default fixed position of 0,0 so that setting just one of x/y always atomically gets 0 for the other */ info = _clutter_actor_peek_layout_info (self); if (info != NULL) { info->fixed_pos.x = 0; info->fixed_pos.y = 0; } } self->priv->position_set = is_set != FALSE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]); clutter_actor_queue_relayout (self); } /** * clutter_actor_move_by: * @self: A #ClutterActor * @dx: Distance to move Actor on X axis. * @dy: Distance to move Actor on Y axis. * * Moves an actor by the specified distance relative to its current * position in pixels. * * This function modifies the fixed position of an actor and thus removes * it from any layout management. Another way to move an actor is with an * anchor point, see clutter_actor_set_anchor_point(), or with an additional * translation, using clutter_actor_set_translation(). * * Since: 0.2 */ void clutter_actor_move_by (ClutterActor *self, gfloat dx, gfloat dy) { const ClutterLayoutInfo *info; gfloat x, y; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_layout_info_or_defaults (self); x = info->fixed_pos.x; y = info->fixed_pos.y; clutter_actor_set_position (self, x + dx, y + dy); } static void clutter_actor_set_min_width (ClutterActor *self, gfloat min_width) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; ClutterLayoutInfo *info; /* if we are setting the size on a top-level actor and the * backend only supports static top-levels (e.g. framebuffers) * then we ignore the passed value and we override it with * the stage implementation's preferred size. */ if (CLUTTER_ACTOR_IS_TOPLEVEL (self) && clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)) return; info = _clutter_actor_get_layout_info (self); if (priv->min_width_set && min_width == info->minimum.width) return; g_object_freeze_notify (G_OBJECT (self)); clutter_actor_store_old_geometry (self, &old); info->minimum.width = min_width; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]); clutter_actor_set_min_width_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); g_object_thaw_notify (G_OBJECT (self)); clutter_actor_queue_relayout (self); } static void clutter_actor_set_min_height (ClutterActor *self, gfloat min_height) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; ClutterLayoutInfo *info; /* if we are setting the size on a top-level actor and the * backend only supports static top-levels (e.g. framebuffers) * then we ignore the passed value and we override it with * the stage implementation's preferred size. */ if (CLUTTER_ACTOR_IS_TOPLEVEL (self) && clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)) return; info = _clutter_actor_get_layout_info (self); if (priv->min_height_set && min_height == info->minimum.height) return; g_object_freeze_notify (G_OBJECT (self)); clutter_actor_store_old_geometry (self, &old); info->minimum.height = min_height; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]); clutter_actor_set_min_height_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); g_object_thaw_notify (G_OBJECT (self)); clutter_actor_queue_relayout (self); } static void clutter_actor_set_natural_width (ClutterActor *self, gfloat natural_width) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; ClutterLayoutInfo *info; /* if we are setting the size on a top-level actor and the * backend only supports static top-levels (e.g. framebuffers) * then we ignore the passed value and we override it with * the stage implementation's preferred size. */ if (CLUTTER_ACTOR_IS_TOPLEVEL (self) && clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)) return; info = _clutter_actor_get_layout_info (self); if (priv->natural_width_set && natural_width == info->natural.width) return; g_object_freeze_notify (G_OBJECT (self)); clutter_actor_store_old_geometry (self, &old); info->natural.width = natural_width; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]); clutter_actor_set_natural_width_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); g_object_thaw_notify (G_OBJECT (self)); clutter_actor_queue_relayout (self); } static void clutter_actor_set_natural_height (ClutterActor *self, gfloat natural_height) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; ClutterLayoutInfo *info; /* if we are setting the size on a top-level actor and the * backend only supports static top-levels (e.g. framebuffers) * then we ignore the passed value and we override it with * the stage implementation's preferred size. */ if (CLUTTER_ACTOR_IS_TOPLEVEL (self) && clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)) return; info = _clutter_actor_get_layout_info (self); if (priv->natural_height_set && natural_height == info->natural.height) return; g_object_freeze_notify (G_OBJECT (self)); clutter_actor_store_old_geometry (self, &old); info->natural.height = natural_height; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]); clutter_actor_set_natural_height_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); g_object_thaw_notify (G_OBJECT (self)); clutter_actor_queue_relayout (self); } static void clutter_actor_set_min_width_set (ClutterActor *self, gboolean use_min_width) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; if (priv->min_width_set == (use_min_width != FALSE)) return; clutter_actor_store_old_geometry (self, &old); priv->min_width_set = use_min_width != FALSE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]); clutter_actor_notify_if_geometry_changed (self, &old); clutter_actor_queue_relayout (self); } static void clutter_actor_set_min_height_set (ClutterActor *self, gboolean use_min_height) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; if (priv->min_height_set == (use_min_height != FALSE)) return; clutter_actor_store_old_geometry (self, &old); priv->min_height_set = use_min_height != FALSE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]); clutter_actor_notify_if_geometry_changed (self, &old); clutter_actor_queue_relayout (self); } static void clutter_actor_set_natural_width_set (ClutterActor *self, gboolean use_natural_width) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; if (priv->natural_width_set == (use_natural_width != FALSE)) return; clutter_actor_store_old_geometry (self, &old); priv->natural_width_set = use_natural_width != FALSE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]); clutter_actor_notify_if_geometry_changed (self, &old); clutter_actor_queue_relayout (self); } static void clutter_actor_set_natural_height_set (ClutterActor *self, gboolean use_natural_height) { ClutterActorPrivate *priv = self->priv; ClutterActorBox old = { 0, }; if (priv->natural_height_set == (use_natural_height != FALSE)) return; clutter_actor_store_old_geometry (self, &old); priv->natural_height_set = use_natural_height != FALSE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]); clutter_actor_notify_if_geometry_changed (self, &old); clutter_actor_queue_relayout (self); } /** * clutter_actor_set_request_mode: * @self: a #ClutterActor * @mode: the request mode * * Sets the geometry request mode of @self. * * The @mode determines the order for invoking * clutter_actor_get_preferred_width() and * clutter_actor_get_preferred_height() * * Since: 1.2 */ void clutter_actor_set_request_mode (ClutterActor *self, ClutterRequestMode mode) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (priv->request_mode == mode) return; priv->request_mode = mode; priv->needs_width_request = TRUE; priv->needs_height_request = TRUE; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]); clutter_actor_queue_relayout (self); } /** * clutter_actor_get_request_mode: * @self: a #ClutterActor * * Retrieves the geometry request mode of @self * * Return value: the request mode for the actor * * Since: 1.2 */ ClutterRequestMode clutter_actor_get_request_mode (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_REQUEST_HEIGHT_FOR_WIDTH); return self->priv->request_mode; } /* variant of set_width() without checks and without notification * freeze+thaw, for internal usage only */ static inline void clutter_actor_set_width_internal (ClutterActor *self, gfloat width) { if (width >= 0) { /* the Stage will use the :min-width to control the minimum * width to be resized to, so we should not be setting it * along with the :natural-width */ if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) clutter_actor_set_min_width (self, width); clutter_actor_set_natural_width (self, width); } else { /* we only unset the :natural-width for the Stage */ if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) clutter_actor_set_min_width_set (self, FALSE); clutter_actor_set_natural_width_set (self, FALSE); } } /* variant of set_height() without checks and without notification * freeze+thaw, for internal usage only */ static inline void clutter_actor_set_height_internal (ClutterActor *self, gfloat height) { if (height >= 0) { /* see the comment above in set_width_internal() */ if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) clutter_actor_set_min_height (self, height); clutter_actor_set_natural_height (self, height); } else { /* see the comment above in set_width_internal() */ if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) clutter_actor_set_min_height_set (self, FALSE); clutter_actor_set_natural_height_set (self, FALSE); } } static void clutter_actor_set_size_internal (ClutterActor *self, const ClutterSize *size) { if (size != NULL) { clutter_actor_set_width_internal (self, size->width); clutter_actor_set_height_internal (self, size->height); } else { clutter_actor_set_width_internal (self, -1); clutter_actor_set_height_internal (self, -1); } } /** * clutter_actor_set_size: * @self: A #ClutterActor * @width: New width of actor in pixels, or -1 * @height: New height of actor in pixels, or -1 * * Sets the actor's size request in pixels. This overrides any * "normal" size request the actor would have. For example * a text actor might normally request the size of the text; * this function would force a specific size instead. * * If @width and/or @height are -1 the actor will use its * "normal" size request instead of overriding it, i.e. * you can "unset" the size with -1. * * This function sets or unsets both the minimum and natural size. */ void clutter_actor_set_size (ClutterActor *self, gfloat width, gfloat height) { ClutterSize new_size; g_return_if_fail (CLUTTER_IS_ACTOR (self)); clutter_size_init (&new_size, width, height); /* minor optimization: if we don't have a duration then we can * skip the get_size() below, to avoid the chance of going through * get_preferred_width() and get_preferred_height() just to jump to * a new desired size */ if (clutter_actor_get_easing_duration (self) == 0) { g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_size_internal (self, &new_size); g_object_thaw_notify (G_OBJECT (self)); return; } else { ClutterSize cur_size; clutter_size_init (&cur_size, clutter_actor_get_width (self), clutter_actor_get_height (self)); _clutter_actor_create_transition (self, obj_props[PROP_SIZE], &cur_size, &new_size); } } /** * clutter_actor_get_size: * @self: A #ClutterActor * @width: (out) (allow-none): return location for the width, or %NULL. * @height: (out) (allow-none): return location for the height, or %NULL. * * This function tries to "do what you mean" and return * the size an actor will have. If the actor has a valid * allocation, the allocation will be returned; otherwise, * the actors natural size request will be returned. * * If you care whether you get the request vs. the allocation, you * should probably call a different function like * clutter_actor_get_allocation_box() or * clutter_actor_get_preferred_width(). * * Since: 0.2 */ void clutter_actor_get_size (ClutterActor *self, gfloat *width, gfloat *height) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (width) *width = clutter_actor_get_width (self); if (height) *height = clutter_actor_get_height (self); } /** * clutter_actor_get_position: * @self: a #ClutterActor * @x: (out) (allow-none): return location for the X coordinate, or %NULL * @y: (out) (allow-none): return location for the Y coordinate, or %NULL * * This function tries to "do what you mean" and tell you where the * actor is, prior to any transformations. Retrieves the fixed * position of an actor in pixels, if one has been set; otherwise, if * the allocation is valid, returns the actor's allocated position; * otherwise, returns 0,0. * * The returned position is in pixels. * * Since: 0.6 */ void clutter_actor_get_position (ClutterActor *self, gfloat *x, gfloat *y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (x) *x = clutter_actor_get_x (self); if (y) *y = clutter_actor_get_y (self); } /** * clutter_actor_get_transformed_position: * @self: A #ClutterActor * @x: (out) (allow-none): return location for the X coordinate, or %NULL * @y: (out) (allow-none): return location for the Y coordinate, or %NULL * * Gets the absolute position of an actor, in pixels relative to the stage. * * Since: 0.8 */ void clutter_actor_get_transformed_position (ClutterActor *self, gfloat *x, gfloat *y) { ClutterVertex v1; ClutterVertex v2; v1.x = v1.y = v1.z = 0; clutter_actor_apply_transform_to_point (self, &v1, &v2); if (x) *x = v2.x; if (y) *y = v2.y; } /** * clutter_actor_get_transformed_size: * @self: A #ClutterActor * @width: (out) (allow-none): return location for the width, or %NULL * @height: (out) (allow-none): return location for the height, or %NULL * * Gets the absolute size of an actor in pixels, taking into account the * scaling factors. * * If the actor has a valid allocation, the allocated size will be used. * If the actor has not a valid allocation then the preferred size will * be transformed and returned. * * If you want the transformed allocation, see * clutter_actor_get_abs_allocation_vertices() instead. * * When the actor (or one of its ancestors) is rotated around the * X or Y axis, it no longer appears as on the stage as a rectangle, but * as a generic quadrangle; in that case this function returns the size * of the smallest rectangle that encapsulates the entire quad. Please * note that in this case no assumptions can be made about the relative * position of this envelope to the absolute position of the actor, as * returned by clutter_actor_get_transformed_position(); if you need this * information, you need to use clutter_actor_get_abs_allocation_vertices() * to get the coords of the actual quadrangle. * * Since: 0.8 */ void clutter_actor_get_transformed_size (ClutterActor *self, gfloat *width, gfloat *height) { ClutterActorPrivate *priv; ClutterVertex v[4]; gfloat x_min, x_max, y_min, y_max; gint i; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; /* if the actor hasn't been allocated yet, get the preferred * size and transform that */ if (priv->needs_allocation) { gfloat natural_width, natural_height; ClutterActorBox box; /* Make a fake allocation to transform. * * NB: _clutter_actor_transform_and_project_box expects a box in * the actor's coordinate space... */ box.x1 = 0; box.y1 = 0; natural_width = natural_height = 0; clutter_actor_get_preferred_size (self, NULL, NULL, &natural_width, &natural_height); box.x2 = natural_width; box.y2 = natural_height; _clutter_actor_transform_and_project_box (self, &box, v); } else clutter_actor_get_abs_allocation_vertices (self, v); x_min = x_max = v[0].x; y_min = y_max = v[0].y; for (i = 1; i < G_N_ELEMENTS (v); ++i) { if (v[i].x < x_min) x_min = v[i].x; if (v[i].x > x_max) x_max = v[i].x; if (v[i].y < y_min) y_min = v[i].y; if (v[i].y > y_max) y_max = v[i].y; } if (width) *width = x_max - x_min; if (height) *height = y_max - y_min; } /** * clutter_actor_get_width: * @self: A #ClutterActor * * Retrieves the width of a #ClutterActor. * * If the actor has a valid allocation, this function will return the * width of the allocated area given to the actor. * * If the actor does not have a valid allocation, this function will * return the actor's natural width, that is the preferred width of * the actor. * * If you care whether you get the preferred width or the width that * has been assigned to the actor, you should probably call a different * function like clutter_actor_get_allocation_box() to retrieve the * allocated size or clutter_actor_get_preferred_width() to retrieve the * preferred width. * * If an actor has a fixed width, for instance a width that has been * assigned using clutter_actor_set_width(), the width returned will * be the same value. * * Return value: the width of the actor, in pixels */ gfloat clutter_actor_get_width (ClutterActor *self) { ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); priv = self->priv; if (priv->needs_allocation) { gfloat natural_width = 0; if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) { clutter_actor_get_preferred_width (self, -1, NULL, &natural_width); } else if (priv->request_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) { gfloat natural_height = 0; clutter_actor_get_preferred_height (self, -1, NULL, &natural_height); clutter_actor_get_preferred_width (self, natural_height, NULL, &natural_width); } else if (priv->request_mode == CLUTTER_REQUEST_CONTENT_SIZE && priv->content != NULL) { clutter_content_get_preferred_size (priv->content, &natural_width, NULL); } return natural_width; } else return priv->allocation.x2 - priv->allocation.x1; } /** * clutter_actor_get_height: * @self: A #ClutterActor * * Retrieves the height of a #ClutterActor. * * If the actor has a valid allocation, this function will return the * height of the allocated area given to the actor. * * If the actor does not have a valid allocation, this function will * return the actor's natural height, that is the preferred height of * the actor. * * If you care whether you get the preferred height or the height that * has been assigned to the actor, you should probably call a different * function like clutter_actor_get_allocation_box() to retrieve the * allocated size or clutter_actor_get_preferred_height() to retrieve the * preferred height. * * If an actor has a fixed height, for instance a height that has been * assigned using clutter_actor_set_height(), the height returned will * be the same value. * * Return value: the height of the actor, in pixels */ gfloat clutter_actor_get_height (ClutterActor *self) { ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); priv = self->priv; if (priv->needs_allocation) { gfloat natural_height = 0; if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) { gfloat natural_width = 0; clutter_actor_get_preferred_width (self, -1, NULL, &natural_width); clutter_actor_get_preferred_height (self, natural_width, NULL, &natural_height); } else if (priv->request_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) { clutter_actor_get_preferred_height (self, -1, NULL, &natural_height); } else if (priv->request_mode == CLUTTER_REQUEST_CONTENT_SIZE && priv->content != NULL) { clutter_content_get_preferred_size (priv->content, NULL, &natural_height); } return natural_height; } else return priv->allocation.y2 - priv->allocation.y1; } /** * clutter_actor_set_width: * @self: A #ClutterActor * @width: Requested new width for the actor, in pixels, or -1 * * Forces a width on an actor, causing the actor's preferred width * and height (if any) to be ignored. * * If @width is -1 the actor will use its preferred width request * instead of overriding it, i.e. you can "unset" the width with -1. * * This function sets both the minimum and natural size of the actor. * * since: 0.2 */ void clutter_actor_set_width (ClutterActor *self, gfloat width) { float cur_size; g_return_if_fail (CLUTTER_IS_ACTOR (self)); /* minor optimization: if we don't have a duration * then we can skip the get_width() below, to avoid * the chance of going through get_preferred_width() * just to jump to a new desired width. */ if (clutter_actor_get_easing_duration (self) == 0) { g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_width_internal (self, width); g_object_thaw_notify (G_OBJECT (self)); return; } else cur_size = clutter_actor_get_width (self); _clutter_actor_create_transition (self, obj_props[PROP_WIDTH], cur_size, width); } /** * clutter_actor_set_height: * @self: A #ClutterActor * @height: Requested new height for the actor, in pixels, or -1 * * Forces a height on an actor, causing the actor's preferred width * and height (if any) to be ignored. * * If @height is -1 the actor will use its preferred height instead of * overriding it, i.e. you can "unset" the height with -1. * * This function sets both the minimum and natural size of the actor. * * since: 0.2 */ void clutter_actor_set_height (ClutterActor *self, gfloat height) { float cur_size; g_return_if_fail (CLUTTER_IS_ACTOR (self)); /* see the comment in clutter_actor_set_width() above */ if (clutter_actor_get_easing_duration (self) == 0) { g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_height_internal (self, height); g_object_thaw_notify (G_OBJECT (self)); return; } else cur_size = clutter_actor_get_height (self); _clutter_actor_create_transition (self, obj_props[PROP_HEIGHT], cur_size, height); } static void _clutter_actor_maybe_queue_relayout (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; ClutterActor *stage = _clutter_actor_get_stage_internal (self); if (priv->parent && (priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT) && CLUTTER_IS_ACTOR (stage)) { clutter_actor_allocate_preferred_size (self, CLUTTER_ALLOCATION_NONE); clutter_actor_queue_redraw (self); } else { clutter_actor_queue_relayout (self); } } static inline void clutter_actor_set_x_internal (ClutterActor *self, float x) { ClutterActorPrivate *priv = self->priv; ClutterLayoutInfo *linfo; ClutterActorBox old = { 0, }; linfo = _clutter_actor_get_layout_info (self); if (priv->position_set && linfo->fixed_pos.x == x) return; clutter_actor_store_old_geometry (self, &old); linfo->fixed_pos.x = x; clutter_actor_set_fixed_position_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); _clutter_actor_maybe_queue_relayout (self); } static inline void clutter_actor_set_y_internal (ClutterActor *self, float y) { ClutterActorPrivate *priv = self->priv; ClutterLayoutInfo *linfo; ClutterActorBox old = { 0, }; linfo = _clutter_actor_get_layout_info (self); if (priv->position_set && linfo->fixed_pos.y == y) return; clutter_actor_store_old_geometry (self, &old); linfo->fixed_pos.y = y; clutter_actor_set_fixed_position_set (self, TRUE); clutter_actor_notify_if_geometry_changed (self, &old); _clutter_actor_maybe_queue_relayout (self); } static void clutter_actor_set_position_internal (ClutterActor *self, const ClutterPoint *position) { ClutterActorPrivate *priv = self->priv; ClutterLayoutInfo *linfo; ClutterActorBox old = { 0, }; linfo = _clutter_actor_get_layout_info (self); if (priv->position_set && clutter_point_equals (position, &linfo->fixed_pos)) return; clutter_actor_store_old_geometry (self, &old); if (position != NULL) { linfo->fixed_pos = *position; clutter_actor_set_fixed_position_set (self, TRUE); } else clutter_actor_set_fixed_position_set (self, FALSE); clutter_actor_notify_if_geometry_changed (self, &old); _clutter_actor_maybe_queue_relayout (self); } /** * clutter_actor_set_x: * @self: a #ClutterActor * @x: the actor's position on the X axis * * Sets the actor's X coordinate, relative to its parent, in pixels. * * Overrides any layout manager and forces a fixed position for * the actor. * * The #ClutterActor:x property is animatable. * * Since: 0.6 */ void clutter_actor_set_x (ClutterActor *self, gfloat x) { float cur_position = clutter_actor_get_x (self); g_return_if_fail (CLUTTER_IS_ACTOR (self)); _clutter_actor_create_transition (self, obj_props[PROP_X], cur_position, x); } /** * clutter_actor_set_y: * @self: a #ClutterActor * @y: the actor's position on the Y axis * * Sets the actor's Y coordinate, relative to its parent, in pixels.# * * Overrides any layout manager and forces a fixed position for * the actor. * * The #ClutterActor:y property is animatable. * * Since: 0.6 */ void clutter_actor_set_y (ClutterActor *self, gfloat y) { float cur_position = clutter_actor_get_y (self); g_return_if_fail (CLUTTER_IS_ACTOR (self)); _clutter_actor_create_transition (self, obj_props[PROP_Y], cur_position, y); } /** * clutter_actor_get_x: * @self: A #ClutterActor * * Retrieves the X coordinate of a #ClutterActor. * * This function tries to "do what you mean", by returning the * correct value depending on the actor's state. * * If the actor has a valid allocation, this function will return * the X coordinate of the origin of the allocation box. * * If the actor has any fixed coordinate set using clutter_actor_set_x(), * clutter_actor_set_position() or clutter_actor_set_geometry(), this * function will return that coordinate. * * If both the allocation and a fixed position are missing, this function * will return 0. * * Return value: the X coordinate, in pixels, ignoring any * transformation (i.e. scaling, rotation) */ gfloat clutter_actor_get_x (ClutterActor *self) { ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); priv = self->priv; if (priv->needs_allocation) { if (priv->position_set) { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (self); return info->fixed_pos.x; } else return 0; } else return priv->allocation.x1; } /** * clutter_actor_get_y: * @self: A #ClutterActor * * Retrieves the Y coordinate of a #ClutterActor. * * This function tries to "do what you mean", by returning the * correct value depending on the actor's state. * * If the actor has a valid allocation, this function will return * the Y coordinate of the origin of the allocation box. * * If the actor has any fixed coordinate set using clutter_actor_set_y(), * clutter_actor_set_position() or clutter_actor_set_geometry(), this * function will return that coordinate. * * If both the allocation and a fixed position are missing, this function * will return 0. * * Return value: the Y coordinate, in pixels, ignoring any * transformation (i.e. scaling, rotation) */ gfloat clutter_actor_get_y (ClutterActor *self) { ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); priv = self->priv; if (priv->needs_allocation) { if (priv->position_set) { const ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info_or_defaults (self); return info->fixed_pos.y; } else return 0; } else return priv->allocation.y1; } /** * clutter_actor_set_scale: * @self: A #ClutterActor * @scale_x: double factor to scale actor by horizontally. * @scale_y: double factor to scale actor by vertically. * * Scales an actor with the given factors. * * The scale transformation is relative the the #ClutterActor:pivot-point. * * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are * animatable. * * Since: 0.2 */ void clutter_actor_set_scale (ClutterActor *self, gdouble scale_x, gdouble scale_y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x); clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_set_scale_z: * @self: a #ClutterActor * @scale_z: the scaling factor along the Z axis * * Scales an actor on the Z axis by the given @scale_z factor. * * The scale transformation is relative the the #ClutterActor:pivot-point. * * The #ClutterActor:scale-z property is animatable. * * Since: 1.12 */ void clutter_actor_set_scale_z (ClutterActor *self, gdouble scale_z) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); clutter_actor_set_scale_factor (self, CLUTTER_Z_AXIS, scale_z); } /** * clutter_actor_set_scale_full: * @self: A #ClutterActor * @scale_x: double factor to scale actor by horizontally. * @scale_y: double factor to scale actor by vertically. * @center_x: X coordinate of the center of the scaling * @center_y: Y coordinate of the center of the scaling * * Scales an actor with the given factors around the given center * point. The center point is specified in pixels relative to the * anchor point (usually the top left corner of the actor). * * The #ClutterActor:scale-x and #ClutterActor:scale-y properties * are animatable. * * Since: 1.0 * * Deprecated: 1.12: Use clutter_actor_set_pivot_point() to control * the scale center */ void clutter_actor_set_scale_full (ClutterActor *self, gdouble scale_x, gdouble scale_y, gfloat center_x, gfloat center_y) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x); clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y); clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x); clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_set_scale_with_gravity: * @self: A #ClutterActor * @scale_x: double factor to scale actor by horizontally. * @scale_y: double factor to scale actor by vertically. * @gravity: the location of the scale center expressed as a compass * direction. * * Scales an actor with the given factors around the given * center point. The center point is specified as one of the compass * directions in #ClutterGravity. For example, setting it to north * will cause the top of the actor to remain unchanged and the rest of * the actor to expand left, right and downwards. * * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are * animatable. * * Since: 1.0 * * Deprecated: 1.12: Use clutter_actor_set_pivot_point() to set the * scale center using normalized coordinates instead. */ void clutter_actor_set_scale_with_gravity (ClutterActor *self, gdouble scale_x, gdouble scale_y, ClutterGravity gravity) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x); clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y); clutter_actor_set_scale_gravity (self, gravity); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_get_scale: * @self: A #ClutterActor * @scale_x: (out) (allow-none): Location to store horizonal * scale factor, or %NULL. * @scale_y: (out) (allow-none): Location to store vertical * scale factor, or %NULL. * * Retrieves an actors scale factors. * * Since: 0.2 */ void clutter_actor_get_scale (ClutterActor *self, gdouble *scale_x, gdouble *scale_y) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); if (scale_x) *scale_x = info->scale_x; if (scale_y) *scale_y = info->scale_y; } /** * clutter_actor_get_scale_z: * @self: A #ClutterActor * * Retrieves the scaling factor along the Z axis, as set using * clutter_actor_set_scale_z(). * * Return value: the scaling factor along the Z axis * * Since: 1.12 */ gdouble clutter_actor_get_scale_z (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 1.0); return _clutter_actor_get_transform_info_or_defaults (self)->scale_z; } /** * clutter_actor_get_scale_center: * @self: A #ClutterActor * @center_x: (out) (allow-none): Location to store the X position * of the scale center, or %NULL. * @center_y: (out) (allow-none): Location to store the Y position * of the scale center, or %NULL. * * Retrieves the scale center coordinate in pixels relative to the top * left corner of the actor. If the scale center was specified using a * #ClutterGravity this will calculate the pixel offset using the * current size of the actor. * * Since: 1.0 * * Deprecated: 1.12: Use clutter_actor_get_pivot_point() instead. */ void clutter_actor_get_scale_center (ClutterActor *self, gfloat *center_x, gfloat *center_y) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); clutter_anchor_coord_get_units (self, &info->scale_center, center_x, center_y, NULL); } /** * clutter_actor_get_scale_gravity: * @self: A #ClutterActor * * Retrieves the scale center as a compass direction. If the scale * center was specified in pixels or units this will return * %CLUTTER_GRAVITY_NONE. * * Return value: the scale gravity * * Since: 1.0 * * Deprecated: 1.12: Use clutter_actor_get_pivot_point() instead. */ ClutterGravity clutter_actor_get_scale_gravity (ClutterActor *self) { const ClutterTransformInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE); info = _clutter_actor_get_transform_info_or_defaults (self); return clutter_anchor_coord_get_gravity (&info->scale_center); } static inline void clutter_actor_set_opacity_internal (ClutterActor *self, guint8 opacity) { ClutterActorPrivate *priv = self->priv; if (priv->opacity != opacity) { priv->opacity = opacity; /* Queue a redraw from the flatten effect so that it can use its cached image if available instead of having to redraw the actual actor. If it doesn't end up using the FBO then the effect is still able to continue the paint anyway. If there is no flatten effect yet then this is equivalent to queueing a full redraw */ _clutter_actor_queue_redraw_full (self, 0, /* flags */ NULL, /* clip */ priv->flatten_effect); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]); } } /** * clutter_actor_set_opacity: * @self: A #ClutterActor * @opacity: New opacity value for the actor. * * Sets the actor's opacity, with zero being completely transparent and * 255 (0xff) being fully opaque. * * The #ClutterActor:opacity property is animatable. */ void clutter_actor_set_opacity (ClutterActor *self, guint8 opacity) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); _clutter_actor_create_transition (self, obj_props[PROP_OPACITY], self->priv->opacity, opacity); } /* * clutter_actor_get_paint_opacity_internal: * @self: a #ClutterActor * * Retrieves the absolute opacity of the actor, as it appears on the stage * * This function does not do type checks * * Return value: the absolute opacity of the actor */ static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; ClutterActor *parent; /* override the top-level opacity to always be 255; even in * case of ClutterStage:use-alpha being TRUE we want the rest * of the scene to be painted */ if (CLUTTER_ACTOR_IS_TOPLEVEL (self)) return 255; if (priv->opacity_override >= 0) return priv->opacity_override; parent = priv->parent; /* Factor in the actual actors opacity with parents */ if (parent != NULL) { guint8 opacity = clutter_actor_get_paint_opacity_internal (parent); if (opacity != 0xff) return (opacity * priv->opacity) / 0xff; } return priv->opacity; } /** * clutter_actor_get_paint_opacity: * @self: A #ClutterActor * * Retrieves the absolute opacity of the actor, as it appears on the stage. * * This function traverses the hierarchy chain and composites the opacity of * the actor with that of its parents. * * This function is intended for subclasses to use in the paint virtual * function, to paint themselves with the correct opacity. * * Return value: The actor opacity value. * * Since: 0.8 */ guint8 clutter_actor_get_paint_opacity (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); return clutter_actor_get_paint_opacity_internal (self); } /** * clutter_actor_get_opacity: * @self: a #ClutterActor * * Retrieves the opacity value of an actor, as set by * clutter_actor_set_opacity(). * * For retrieving the absolute opacity of the actor inside a paint * virtual function, see clutter_actor_get_paint_opacity(). * * Return value: the opacity of the actor */ guint8 clutter_actor_get_opacity (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); return self->priv->opacity; } /** * clutter_actor_set_offscreen_redirect: * @self: A #ClutterActor * @redirect: New offscreen redirect flags for the actor. * * Defines the circumstances where the actor should be redirected into * an offscreen image. The offscreen image is used to flatten the * actor into a single image while painting for two main reasons. * Firstly, when the actor is painted a second time without any of its * contents changing it can simply repaint the cached image without * descending further down the actor hierarchy. Secondly, it will make * the opacity look correct even if there are overlapping primitives * in the actor. * * Caching the actor could in some cases be a performance win and in * some cases be a performance lose so it is important to determine * which value is right for an actor before modifying this value. For * example, there is never any reason to flatten an actor that is just * a single texture (such as a #ClutterTexture) because it is * effectively already cached in an image so the offscreen would be * redundant. Also if the actor contains primitives that are far apart * with a large transparent area in the middle (such as a large * CluterGroup with a small actor in the top left and a small actor in * the bottom right) then the cached image will contain the entire * image of the large area and the paint will waste time blending all * of the transparent pixels in the middle. * * The default method of implementing opacity on a container simply * forwards on the opacity to all of the children. If the children are * overlapping then it will appear as if they are two separate glassy * objects and there will be a break in the color where they * overlap. By redirecting to an offscreen buffer it will be as if the * two opaque objects are combined into one and then made transparent * which is usually what is expected. * * The image below demonstrates the difference between redirecting and * not. The image shows two Clutter groups, each containing a red and * a green rectangle which overlap. The opacity on the group is set to * 128 (which is 50%). When the offscreen redirect is not used, the * red rectangle can be seen through the blue rectangle as if the two * rectangles were separately transparent. When the redirect is used * the group as a whole is transparent instead so the red rectangle is * not visible where they overlap. * *
* Sample of using an offscreen redirect for transparency * *
* * The default value for this property is 0, so we effectively will * never redirect an actor offscreen by default. This means that there * are times that transparent actors may look glassy as described * above. The reason this is the default is because there is a * performance trade off between quality and performance here. In many * cases the default form of glassy opacity looks good enough, but if * it's not you will need to set the * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable * redirection for opacity. * * Custom actors that don't contain any overlapping primitives are * recommended to override the has_overlaps() virtual to return %FALSE * for maximum efficiency. * * Since: 1.8 */ void clutter_actor_set_offscreen_redirect (ClutterActor *self, ClutterOffscreenRedirect redirect) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (priv->offscreen_redirect != redirect) { priv->offscreen_redirect = redirect; /* Queue a redraw from the effect so that it can use its cached image if available instead of having to redraw the actual actor. If it doesn't end up using the FBO then the effect is still able to continue the paint anyway. If there is no effect then this is equivalent to queuing a full redraw */ _clutter_actor_queue_redraw_full (self, 0, /* flags */ NULL, /* clip */ priv->flatten_effect); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OFFSCREEN_REDIRECT]); } } /** * clutter_actor_get_offscreen_redirect: * @self: a #ClutterActor * * Retrieves whether to redirect the actor to an offscreen buffer, as * set by clutter_actor_set_offscreen_redirect(). * * Return value: the value of the offscreen-redirect property of the actor * * Since: 1.8 */ ClutterOffscreenRedirect clutter_actor_get_offscreen_redirect (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); return self->priv->offscreen_redirect; } /** * clutter_actor_set_name: * @self: A #ClutterActor * @name: Textual tag to apply to actor * * Sets the given name to @self. The name can be used to identify * a #ClutterActor. */ void clutter_actor_set_name (ClutterActor *self, const gchar *name) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); free (self->priv->name); self->priv->name = g_strdup (name); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]); } /** * clutter_actor_get_name: * @self: A #ClutterActor * * Retrieves the name of @self. * * Return value: the name of the actor, or %NULL. The returned string is * owned by the actor and should not be modified or freed. */ const gchar * clutter_actor_get_name (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->name; } /** * clutter_actor_get_gid: * @self: A #ClutterActor * * Retrieves the unique id for @self. * * Return value: Globally unique value for this object instance. * * Since: 0.6 * * Deprecated: 1.8: The id is not used any longer, and this function * always returns 0. */ guint32 clutter_actor_get_gid (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); return 0; } static inline void clutter_actor_set_depth_internal (ClutterActor *self, float depth) { ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); if (info->z_position != depth) { /* Sets Z value - XXX 2.0: should we invert? */ info->z_position = depth; self->priv->transform_valid = FALSE; /* FIXME - remove this crap; sadly, there are still containers * in Clutter that depend on this utter brain damage */ clutter_container_sort_depth_order (CLUTTER_CONTAINER (self)); clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]); } } static inline void clutter_actor_set_z_position_internal (ClutterActor *self, float z_position) { ClutterTransformInfo *info; info = _clutter_actor_get_transform_info (self); if (memcmp (&info->z_position, &z_position, sizeof (float)) != 0) { info->z_position = z_position; self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Z_POSITION]); } } /** * clutter_actor_set_z_position: * @self: a #ClutterActor * @z_position: the position on the Z axis * * Sets the actor's position on the Z axis. * * See #ClutterActor:z-position. * * Since: 1.12 */ void clutter_actor_set_z_position (ClutterActor *self, gfloat z_position) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); _clutter_actor_create_transition (self, obj_props[PROP_Z_POSITION], info->z_position, z_position); } /** * clutter_actor_get_z_position: * @self: a #ClutterActor * * Retrieves the actor's position on the Z axis. * * Return value: the position on the Z axis. * * Since: 1.12 */ gfloat clutter_actor_get_z_position (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f); return _clutter_actor_get_transform_info_or_defaults (self)->z_position; } /** * clutter_actor_set_pivot_point: * @self: a #ClutterActor * @pivot_x: the normalized X coordinate of the pivot point * @pivot_y: the normalized Y coordinate of the pivot point * * Sets the position of the #ClutterActor:pivot-point around which the * scaling and rotation transformations occur. * * The pivot point's coordinates are in normalized space, with the (0, 0) * point being the top left corner of the actor, and the (1, 1) point being * the bottom right corner. * * Since: 1.12 */ void clutter_actor_set_pivot_point (ClutterActor *self, gfloat pivot_x, gfloat pivot_y) { ClutterPoint pivot = CLUTTER_POINT_INIT (pivot_x, pivot_y); const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); _clutter_actor_create_transition (self, obj_props[PROP_PIVOT_POINT], &info->pivot, &pivot); } /** * clutter_actor_get_pivot_point: * @self: a #ClutterActor * @pivot_x: (out) (allow-none): return location for the normalized X * coordinate of the pivot point, or %NULL * @pivot_y: (out) (allow-none): return location for the normalized Y * coordinate of the pivot point, or %NULL * * Retrieves the coordinates of the #ClutterActor:pivot-point. * * Since: 1.12 */ void clutter_actor_get_pivot_point (ClutterActor *self, gfloat *pivot_x, gfloat *pivot_y) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); if (pivot_x != NULL) *pivot_x = info->pivot.x; if (pivot_y != NULL) *pivot_y = info->pivot.y; } /** * clutter_actor_set_pivot_point_z: * @self: a #ClutterActor * @pivot_z: the Z coordinate of the actor's pivot point * * Sets the component on the Z axis of the #ClutterActor:pivot-point around * which the scaling and rotation transformations occur. * * The @pivot_z value is expressed as a distance along the Z axis. * * Since: 1.12 */ void clutter_actor_set_pivot_point_z (ClutterActor *self, gfloat pivot_z) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); _clutter_actor_create_transition (self, obj_props[PROP_PIVOT_POINT_Z], info->pivot_z, pivot_z); } /** * clutter_actor_get_pivot_point_z: * @self: a #ClutterActor * * Retrieves the Z component of the #ClutterActor:pivot-point. * * Since: 1.12 */ gfloat clutter_actor_get_pivot_point_z (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f); return _clutter_actor_get_transform_info_or_defaults (self)->pivot_z; } /** * clutter_actor_set_depth: * @self: a #ClutterActor * @depth: Z co-ord * * Sets the Z coordinate of @self to @depth. * * The unit used by @depth is dependant on the perspective setup. See * also clutter_stage_set_perspective(). * * Deprecated: 1.12: Use clutter_actor_set_z_position() instead. */ void clutter_actor_set_depth (ClutterActor *self, gfloat depth) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); _clutter_actor_create_transition (self, obj_props[PROP_DEPTH], info->z_position, depth); } /** * clutter_actor_get_depth: * @self: a #ClutterActor * * Retrieves the depth of @self. * * Return value: the depth of the actor * * Deprecated: 1.12: Use clutter_actor_get_z_position() instead. */ gfloat clutter_actor_get_depth (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0); return _clutter_actor_get_transform_info_or_defaults (self)->z_position; } /** * clutter_actor_set_rotation: * @self: a #ClutterActor * @axis: the axis of rotation * @angle: the angle of rotation * @x: X coordinate of the rotation center * @y: Y coordinate of the rotation center * @z: Z coordinate of the rotation center * * Sets the rotation angle of @self around the given axis. * * The rotation center coordinates used depend on the value of @axis: * * - %CLUTTER_X_AXIS requires @y and @z * - %CLUTTER_Y_AXIS requires @x and @z * - %CLUTTER_Z_AXIS requires @x and @y * * The rotation coordinates are relative to the anchor point of the * actor, set using clutter_actor_set_anchor_point(). If no anchor * point is set, the upper left corner is assumed as the origin. * * Since: 0.8 * * Deprecated: 1.12: Use clutter_actor_set_rotation_angle() and * clutter_actor_set_pivot_point() instead. */ void clutter_actor_set_rotation (ClutterActor *self, ClutterRotateAxis axis, gdouble angle, gfloat x, gfloat y, gfloat z) { ClutterVertex v; g_return_if_fail (CLUTTER_IS_ACTOR (self)); v.x = x; v.y = y; v.z = z; g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_rotation_angle (self, axis, angle); clutter_actor_set_rotation_center_internal (self, axis, &v); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_set_z_rotation_from_gravity: * @self: a #ClutterActor * @angle: the angle of rotation * @gravity: the center point of the rotation * * Sets the rotation angle of @self around the Z axis using the center * point specified as a compass point. For example to rotate such that * the center of the actor remains static you can use * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point * will move accordingly. * * Since: 1.0 * * Deprecated: 1.12: Use clutter_actor_set_rotation_angle() and * clutter_actor_set_pivot_point() instead. */ void clutter_actor_set_z_rotation_from_gravity (ClutterActor *self, gdouble angle, ClutterGravity gravity) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (gravity == CLUTTER_GRAVITY_NONE) clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0); else { GObject *obj = G_OBJECT (self); ClutterTransformInfo *info; GParamSpec *pspec; pspec = obj_props[PROP_ROTATION_ANGLE_Z]; info = _clutter_actor_get_transform_info (self); g_object_freeze_notify (obj); clutter_actor_set_rotation_angle_internal (self, angle, pspec); clutter_anchor_coord_set_gravity (&info->rz_center, gravity); g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]); g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]); g_object_thaw_notify (obj); } } /** * clutter_actor_get_rotation: * @self: a #ClutterActor * @axis: the axis of rotation * @x: (out): return value for the X coordinate of the center of rotation * @y: (out): return value for the Y coordinate of the center of rotation * @z: (out): return value for the Z coordinate of the center of rotation * * Retrieves the angle and center of rotation on the given axis, * set using clutter_actor_set_rotation(). * * Return value: the angle of rotation * * Since: 0.8 * * Deprecated: 1.12: Use clutter_actor_get_rotation_angle() and * clutter_actor_get_pivot_point() instead. */ gdouble clutter_actor_get_rotation (ClutterActor *self, ClutterRotateAxis axis, gfloat *x, gfloat *y, gfloat *z) { const ClutterTransformInfo *info; const AnchorCoord *anchor_coord; gdouble retval = 0; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); info = _clutter_actor_get_transform_info_or_defaults (self); switch (axis) { case CLUTTER_X_AXIS: anchor_coord = &info->rx_center; retval = info->rx_angle; break; case CLUTTER_Y_AXIS: anchor_coord = &info->ry_center; retval = info->ry_angle; break; case CLUTTER_Z_AXIS: anchor_coord = &info->rz_center; retval = info->rz_angle; break; default: anchor_coord = NULL; retval = 0.0; break; } clutter_anchor_coord_get_units (self, anchor_coord, x, y, z); return retval; } /** * clutter_actor_get_z_rotation_gravity: * @self: A #ClutterActor * * Retrieves the center for the rotation around the Z axis as a * compass direction. If the center was specified in pixels or units * this will return %CLUTTER_GRAVITY_NONE. * * Return value: the Z rotation center * * Since: 1.0 * * Deprecated: 1.12: Use the #ClutterActor:pivot-point instead of * a #ClutterGravity */ ClutterGravity clutter_actor_get_z_rotation_gravity (ClutterActor *self) { const ClutterTransformInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE); info = _clutter_actor_get_transform_info_or_defaults (self); return clutter_anchor_coord_get_gravity (&info->rz_center); } /** * clutter_actor_set_clip: * @self: A #ClutterActor * @xoff: X offset of the clip rectangle * @yoff: Y offset of the clip rectangle * @width: Width of the clip rectangle * @height: Height of the clip rectangle * * Sets clip area for @self. The clip area is always computed from the * upper left corner of the actor, even if the anchor point is set * otherwise. * * Since: 0.6 */ void clutter_actor_set_clip (ClutterActor *self, gfloat xoff, gfloat yoff, gfloat width, gfloat height) { ClutterActorPrivate *priv; GObject *obj; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (priv->has_clip && priv->clip.origin.x == xoff && priv->clip.origin.y == yoff && priv->clip.size.width == width && priv->clip.size.height == height) return; obj = G_OBJECT (self); priv->clip.origin.x = xoff; priv->clip.origin.y = yoff; priv->clip.size.width = width; priv->clip.size.height = height; priv->has_clip = TRUE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (obj, obj_props[PROP_CLIP]); g_object_notify_by_pspec (obj, obj_props[PROP_CLIP_RECT]); g_object_notify_by_pspec (obj, obj_props[PROP_HAS_CLIP]); } /** * clutter_actor_remove_clip: * @self: A #ClutterActor * * Removes clip area from @self. */ void clutter_actor_remove_clip (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (!self->priv->has_clip) return; self->priv->has_clip = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]); } /** * clutter_actor_has_clip: * @self: a #ClutterActor * * Determines whether the actor has a clip area set or not. * * Return value: %TRUE if the actor has a clip area set. * * Since: 0.2 */ gboolean clutter_actor_has_clip (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return self->priv->has_clip; } /** * clutter_actor_get_clip: * @self: a #ClutterActor * @xoff: (out) (allow-none): return location for the X offset of * the clip rectangle, or %NULL * @yoff: (out) (allow-none): return location for the Y offset of * the clip rectangle, or %NULL * @width: (out) (allow-none): return location for the width of * the clip rectangle, or %NULL * @height: (out) (allow-none): return location for the height of * the clip rectangle, or %NULL * * Gets the clip area for @self, if any is set. * * Since: 0.6 */ void clutter_actor_get_clip (ClutterActor *self, gfloat *xoff, gfloat *yoff, gfloat *width, gfloat *height) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (!priv->has_clip) return; if (xoff != NULL) *xoff = priv->clip.origin.x; if (yoff != NULL) *yoff = priv->clip.origin.y; if (width != NULL) *width = priv->clip.size.width; if (height != NULL) *height = priv->clip.size.height; } /** * clutter_actor_get_children: * @self: a #ClutterActor * * Retrieves the list of children of @self. * * Return value: (transfer container) (element-type ClutterActor): A newly * allocated #GList of #ClutterActors. Use g_list_free() when * done. * * Since: 1.10 */ GList * clutter_actor_get_children (ClutterActor *self) { ClutterActor *iter; GList *res; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); /* we walk the list backward so that we can use prepend(), * which is O(1) */ for (iter = self->priv->last_child, res = NULL; iter != NULL; iter = iter->priv->prev_sibling) { res = g_list_prepend (res, iter); } return res; } /*< private > * insert_child_at_depth: * @self: a #ClutterActor * @child: a #ClutterActor * * Inserts @child inside the list of children held by @self, using * the depth as the insertion criteria. * * This sadly makes the insertion not O(1), but we can keep the * list sorted so that the painters algorithm we use for painting * the children will work correctly. */ static void insert_child_at_depth (ClutterActor *self, ClutterActor *child, gpointer dummy G_GNUC_UNUSED) { ClutterActor *iter; float child_depth; child->priv->parent = self; child_depth = _clutter_actor_get_transform_info_or_defaults (child)->z_position; /* special-case the first child */ if (self->priv->n_children == 0) { self->priv->first_child = child; self->priv->last_child = child; child->priv->next_sibling = NULL; child->priv->prev_sibling = NULL; return; } /* Find the right place to insert the child so that it will still be sorted and the child will be after all of the actors at the same dept */ for (iter = self->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) { float iter_depth; iter_depth = _clutter_actor_get_transform_info_or_defaults (iter)->z_position; if (iter_depth > child_depth) break; } if (iter != NULL) { ClutterActor *tmp = iter->priv->prev_sibling; if (tmp != NULL) tmp->priv->next_sibling = child; /* Insert the node before the found one */ child->priv->prev_sibling = iter->priv->prev_sibling; child->priv->next_sibling = iter; iter->priv->prev_sibling = child; } else { ClutterActor *tmp = self->priv->last_child; if (tmp != NULL) tmp->priv->next_sibling = child; /* insert the node at the end of the list */ child->priv->prev_sibling = self->priv->last_child; child->priv->next_sibling = NULL; } if (child->priv->prev_sibling == NULL) self->priv->first_child = child; if (child->priv->next_sibling == NULL) self->priv->last_child = child; } static void insert_child_at_index (ClutterActor *self, ClutterActor *child, gpointer data_) { gint index_ = GPOINTER_TO_INT (data_); child->priv->parent = self; if (index_ == 0) { ClutterActor *tmp = self->priv->first_child; if (tmp != NULL) tmp->priv->prev_sibling = child; child->priv->prev_sibling = NULL; child->priv->next_sibling = tmp; } else if (index_ < 0 || index_ >= self->priv->n_children) { ClutterActor *tmp = self->priv->last_child; if (tmp != NULL) tmp->priv->next_sibling = child; child->priv->prev_sibling = tmp; child->priv->next_sibling = NULL; } else { ClutterActor *iter; int i; for (iter = self->priv->first_child, i = 0; iter != NULL; iter = iter->priv->next_sibling, i += 1) { if (index_ == i) { ClutterActor *tmp = iter->priv->prev_sibling; child->priv->prev_sibling = tmp; child->priv->next_sibling = iter; iter->priv->prev_sibling = child; if (tmp != NULL) tmp->priv->next_sibling = child; break; } } } if (child->priv->prev_sibling == NULL) self->priv->first_child = child; if (child->priv->next_sibling == NULL) self->priv->last_child = child; } static void insert_child_above (ClutterActor *self, ClutterActor *child, gpointer data) { ClutterActor *sibling = data; child->priv->parent = self; if (sibling == NULL) sibling = self->priv->last_child; child->priv->prev_sibling = sibling; if (sibling != NULL) { ClutterActor *tmp = sibling->priv->next_sibling; child->priv->next_sibling = tmp; if (tmp != NULL) tmp->priv->prev_sibling = child; sibling->priv->next_sibling = child; } else child->priv->next_sibling = NULL; if (child->priv->prev_sibling == NULL) self->priv->first_child = child; if (child->priv->next_sibling == NULL) self->priv->last_child = child; } static void insert_child_below (ClutterActor *self, ClutterActor *child, gpointer data) { ClutterActor *sibling = data; child->priv->parent = self; if (sibling == NULL) sibling = self->priv->first_child; child->priv->next_sibling = sibling; if (sibling != NULL) { ClutterActor *tmp = sibling->priv->prev_sibling; child->priv->prev_sibling = tmp; if (tmp != NULL) tmp->priv->next_sibling = child; sibling->priv->prev_sibling = child; } else child->priv->prev_sibling = NULL; if (child->priv->prev_sibling == NULL) self->priv->first_child = child; if (child->priv->next_sibling == NULL) self->priv->last_child = child; } typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent, ClutterActor *child, gpointer data); typedef enum { ADD_CHILD_CREATE_META = 1 << 0, ADD_CHILD_EMIT_PARENT_SET = 1 << 1, ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2, ADD_CHILD_CHECK_STATE = 1 << 3, ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4, ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5, /* default flags for public API */ ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META | ADD_CHILD_EMIT_PARENT_SET | ADD_CHILD_EMIT_ACTOR_ADDED | ADD_CHILD_CHECK_STATE | ADD_CHILD_NOTIFY_FIRST_LAST | ADD_CHILD_SHOW_ON_SET_PARENT, /* flags for legacy/deprecated API */ ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET | ADD_CHILD_CHECK_STATE | ADD_CHILD_NOTIFY_FIRST_LAST | ADD_CHILD_SHOW_ON_SET_PARENT } ClutterActorAddChildFlags; /*< private > * clutter_actor_add_child_internal: * @self: a #ClutterActor * @child: a #ClutterActor * @flags: control flags for actions * @add_func: delegate function * @data: (closure): data to pass to @add_func * * Adds @child to the list of children of @self. * * The actual insertion inside the list is delegated to @add_func: this * function will just set up the state, perform basic checks, and emit * signals. * * The @flags argument is used to perform additional operations. */ static inline void clutter_actor_add_child_internal (ClutterActor *self, ClutterActor *child, ClutterActorAddChildFlags flags, ClutterActorAddChildFunc add_func, gpointer data) { ClutterTextDirection text_dir; gboolean create_meta; gboolean emit_parent_set, emit_actor_added; gboolean check_state; gboolean notify_first_last; gboolean show_on_set_parent; ClutterActor *old_first_child, *old_last_child; GObject *obj; if (self == child) { g_warning ("Cannot add the actor '%s' to itself.", _clutter_actor_get_debug_name (self)); return; } if (child->priv->parent != NULL) { g_warning ("The actor '%s' already has a parent, '%s'. You must " "use clutter_actor_remove_child() first.", _clutter_actor_get_debug_name (child), _clutter_actor_get_debug_name (child->priv->parent)); return; } if (CLUTTER_ACTOR_IS_TOPLEVEL (child)) { g_warning ("The actor '%s' is a top-level actor, and cannot be " "a child of another actor.", _clutter_actor_get_debug_name (child)); return; } /* the following check disallows calling methods that change the stacking * order within the destruction sequence, by triggering a critical * warning first, and leaving the actor in an undefined state, which * then ends up being caught by an assertion. * * the reproducible sequence is: * * - actor gets destroyed; * - another actor, linked to the first, will try to change the * stacking order of the first actor; * - changing the stacking order is a composite operation composed * by the following steps: * 1. ref() the child; * 2. remove_child_internal(), which removes the reference; * 3. add_child_internal(), which adds a reference; * - the state of the actor is not changed between (2) and (3), as * it could be an expensive recomputation; * - if (3) bails out, then the actor is in an undefined state, but * still alive; * - the destruction sequence terminates, but the actor is unparented * while its state indicates being parented instead. * - assertion failure. * * the obvious fix would be to decompose each set_child_*_sibling() * method into proper remove_child()/add_child(), with state validation; * this may cause excessive work, though, and trigger a cascade of other * bugs in code that assumes that a change in the stacking order is an * atomic operation. * * another potential fix is to just remove this check here, and let * code doing stacking order changes inside the destruction sequence * of an actor continue doing the stacking changes as before; this * option still performs more work than necessary. * * the third fix is to silently bail out early from every * set_child_*_sibling() and set_child_at_index() method, and avoid * doing stack changes altogether; Clutter implements this last option. * * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647 */ if (CLUTTER_ACTOR_IN_DESTRUCTION (child)) { g_warning ("The actor '%s' is currently being destroyed, and " "cannot be added as a child of another actor.", _clutter_actor_get_debug_name (child)); return; } create_meta = (flags & ADD_CHILD_CREATE_META) != 0; emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0; emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0; check_state = (flags & ADD_CHILD_CHECK_STATE) != 0; notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0; show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0; old_first_child = self->priv->first_child; old_last_child = self->priv->last_child; obj = G_OBJECT (self); g_object_freeze_notify (obj); if (create_meta) clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child); g_object_ref_sink (child); child->priv->parent = NULL; child->priv->next_sibling = NULL; child->priv->prev_sibling = NULL; /* delegate the actual insertion */ add_func (self, child, data); g_assert (child->priv->parent == self); self->priv->n_children += 1; self->priv->age += 1; /* if push_internal() has been called then we automatically set * the flag on the actor */ if (self->priv->internal_child) CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD); /* children may cause their parent to expand, if they are set * to expand; if a child is not expanded then it cannot change * its parent's state. any further change later on will queue * an expand state check. * * this check, with the initial state of the needs_compute_expand * flag set to FALSE, should avoid recomputing the expand flags * state while building the actor tree. */ if (CLUTTER_ACTOR_IS_VISIBLE (child) && (child->priv->needs_compute_expand || child->priv->needs_x_expand || child->priv->needs_y_expand)) { clutter_actor_queue_compute_expand (self); } /* clutter_actor_reparent() will emit ::parent-set for us */ if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child)) g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL); if (check_state) { /* If parent is mapped or realized, we need to also be mapped or * realized once we're inside the parent. */ clutter_actor_update_map_state (child, MAP_STATE_CHECK); /* propagate the parent's text direction to the child */ text_dir = clutter_actor_get_text_direction (self); clutter_actor_set_text_direction (child, text_dir); } /* this may end up queueing a redraw, in case the actor is * not visible but the show-on-set-parent property is still * set. * * XXX:2.0 - remove this check and unconditionally show() the * actor once we remove the show-on-set-parent property */ if (show_on_set_parent && child->priv->show_on_set_parent) clutter_actor_show (child); /* on the other hand, this will catch any other case where * the actor is supposed to be visible when it's added */ if (CLUTTER_ACTOR_IS_MAPPED (child)) clutter_actor_queue_redraw (child); /* maintain the invariant that if an actor needs layout, * its parents do as well */ if (child->priv->needs_width_request || child->priv->needs_height_request || child->priv->needs_allocation) { /* we work around the short-circuiting we do * in clutter_actor_queue_relayout() since we * want to force a relayout */ child->priv->needs_width_request = TRUE; child->priv->needs_height_request = TRUE; child->priv->needs_allocation = TRUE; if (CLUTTER_ACTOR_IS_MAPPED (child)) child->priv->needs_paint_volume_update = TRUE; /* we only queue a relayout here, because any possible * redraw has already been queued either by show() or * by our call to queue_redraw() above */ _clutter_actor_queue_only_relayout (child->priv->parent); } if (emit_actor_added) g_signal_emit_by_name (self, "actor-added", child); if (notify_first_last) { if (old_first_child != self->priv->first_child) g_object_notify_by_pspec (obj, obj_props[PROP_FIRST_CHILD]); if (old_last_child != self->priv->last_child) g_object_notify_by_pspec (obj, obj_props[PROP_LAST_CHILD]); } g_object_thaw_notify (obj); } /** * clutter_actor_add_child: * @self: a #ClutterActor * @child: a #ClutterActor * * Adds @child to the children of @self. * * This function will acquire a reference on @child that will only * be released when calling clutter_actor_remove_child(). * * This function will take into consideration the #ClutterActor:depth * of @child, and will keep the list of children sorted. * * This function will emit the #ClutterContainer::actor-added signal * on @self. * * Since: 1.10 */ void clutter_actor_add_child (ClutterActor *self, ClutterActor *child) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (self != child); g_return_if_fail (child->priv->parent == NULL); clutter_actor_add_child_internal (self, child, ADD_CHILD_DEFAULT_FLAGS, insert_child_at_depth, NULL); } /** * clutter_actor_insert_child_at_index: * @self: a #ClutterActor * @child: a #ClutterActor * @index_: the index * * Inserts @child into the list of children of @self, using the * given @index_. If @index_ is greater than the number of children * in @self, or is less than 0, then the new child is added at the end. * * This function will acquire a reference on @child that will only * be released when calling clutter_actor_remove_child(). * * This function will not take into consideration the #ClutterActor:depth * of @child. * * This function will emit the #ClutterContainer::actor-added signal * on @self. * * Since: 1.10 */ void clutter_actor_insert_child_at_index (ClutterActor *self, ClutterActor *child, gint index_) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (self != child); g_return_if_fail (child->priv->parent == NULL); clutter_actor_add_child_internal (self, child, ADD_CHILD_DEFAULT_FLAGS, insert_child_at_index, GINT_TO_POINTER (index_)); } /** * clutter_actor_insert_child_above: * @self: a #ClutterActor * @child: a #ClutterActor * @sibling: (allow-none): a child of @self, or %NULL * * Inserts @child into the list of children of @self, above another * child of @self or, if @sibling is %NULL, above all the children * of @self. * * This function will acquire a reference on @child that will only * be released when calling clutter_actor_remove_child(). * * This function will not take into consideration the #ClutterActor:depth * of @child. * * This function will emit the #ClutterContainer::actor-added signal * on @self. * * Since: 1.10 */ void clutter_actor_insert_child_above (ClutterActor *self, ClutterActor *child, ClutterActor *sibling) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (self != child); g_return_if_fail (child != sibling); g_return_if_fail (child->priv->parent == NULL); g_return_if_fail (sibling == NULL || (CLUTTER_IS_ACTOR (sibling) && sibling->priv->parent == self)); clutter_actor_add_child_internal (self, child, ADD_CHILD_DEFAULT_FLAGS, insert_child_above, sibling); } /** * clutter_actor_insert_child_below: * @self: a #ClutterActor * @child: a #ClutterActor * @sibling: (allow-none): a child of @self, or %NULL * * Inserts @child into the list of children of @self, below another * child of @self or, if @sibling is %NULL, below all the children * of @self. * * This function will acquire a reference on @child that will only * be released when calling clutter_actor_remove_child(). * * This function will not take into consideration the #ClutterActor:depth * of @child. * * This function will emit the #ClutterContainer::actor-added signal * on @self. * * Since: 1.10 */ void clutter_actor_insert_child_below (ClutterActor *self, ClutterActor *child, ClutterActor *sibling) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (self != child); g_return_if_fail (child != sibling); g_return_if_fail (child->priv->parent == NULL); g_return_if_fail (sibling == NULL || (CLUTTER_IS_ACTOR (sibling) && sibling->priv->parent == self)); clutter_actor_add_child_internal (self, child, ADD_CHILD_DEFAULT_FLAGS, insert_child_below, sibling); } /** * clutter_actor_set_parent: * @self: A #ClutterActor * @parent: A new #ClutterActor parent * * Sets the parent of @self to @parent. * * This function will result in @parent acquiring a reference on @self, * eventually by sinking its floating reference first. The reference * will be released by clutter_actor_unparent(). * * This function should only be called by legacy #ClutterActors * implementing the #ClutterContainer interface. * * Deprecated: 1.10: Use clutter_actor_add_child() instead. */ void clutter_actor_set_parent (ClutterActor *self, ClutterActor *parent) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (parent)); g_return_if_fail (self != parent); g_return_if_fail (self->priv->parent == NULL); /* as this function will be called inside ClutterContainer::add * implementations or when building up a composite actor, we have * to preserve the old behaviour, and not create child meta or * emit the ::actor-added signal, to avoid recursion or double * emissions */ clutter_actor_add_child_internal (parent, self, ADD_CHILD_LEGACY_FLAGS, insert_child_at_depth, NULL); } /** * clutter_actor_get_parent: * @self: A #ClutterActor * * Retrieves the parent of @self. * * Return Value: (transfer none): The #ClutterActor parent, or %NULL * if no parent is set */ ClutterActor * clutter_actor_get_parent (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->parent; } /** * clutter_actor_get_paint_visibility: * @self: A #ClutterActor * * Retrieves the 'paint' visibility of an actor recursively checking for non * visible parents. * * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED. * * Return Value: %TRUE if the actor is visibile and will be painted. * * Since: 0.8 */ gboolean clutter_actor_get_paint_visibility (ClutterActor *actor) { g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); return CLUTTER_ACTOR_IS_MAPPED (actor); } /** * clutter_actor_remove_child: * @self: a #ClutterActor * @child: a #ClutterActor * * Removes @child from the children of @self. * * This function will release the reference added by * clutter_actor_add_child(), so if you want to keep using @child * you will have to acquire a referenced on it before calling this * function. * * This function will emit the #ClutterContainer::actor-removed * signal on @self. * * Since: 1.10 */ void clutter_actor_remove_child (ClutterActor *self, ClutterActor *child) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (self != child); g_return_if_fail (child->priv->parent != NULL); g_return_if_fail (child->priv->parent == self); clutter_actor_remove_child_internal (self, child, REMOVE_CHILD_DEFAULT_FLAGS); } /** * clutter_actor_remove_all_children: * @self: a #ClutterActor * * Removes all children of @self. * * This function releases the reference added by inserting a child actor * in the list of children of @self. * * If the reference count of a child drops to zero, the child will be * destroyed. If you want to ensure the destruction of all the children * of @self, use clutter_actor_destroy_all_children(). * * Since: 1.10 */ void clutter_actor_remove_all_children (ClutterActor *self) { ClutterActorIter iter; g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->n_children == 0) return; g_object_freeze_notify (G_OBJECT (self)); clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, NULL)) clutter_actor_iter_remove (&iter); g_object_thaw_notify (G_OBJECT (self)); /* sanity check */ g_assert (self->priv->first_child == NULL); g_assert (self->priv->last_child == NULL); g_assert (self->priv->n_children == 0); } /** * clutter_actor_destroy_all_children: * @self: a #ClutterActor * * Destroys all children of @self. * * This function releases the reference added by inserting a child * actor in the list of children of @self, and ensures that the * #ClutterActor::destroy signal is emitted on each child of the * actor. * * By default, #ClutterActor will emit the #ClutterActor::destroy signal * when its reference count drops to 0; the default handler of the * #ClutterActor::destroy signal will destroy all the children of an * actor. This function ensures that all children are destroyed, instead * of just removed from @self, unlike clutter_actor_remove_all_children() * which will merely release the reference and remove each child. * * Unless you acquired an additional reference on each child of @self * prior to calling clutter_actor_remove_all_children() and want to reuse * the actors, you should use clutter_actor_destroy_all_children() in * order to make sure that children are destroyed and signal handlers * are disconnected even in cases where circular references prevent this * from automatically happening through reference counting alone. * * Since: 1.10 */ void clutter_actor_destroy_all_children (ClutterActor *self) { ClutterActorIter iter; g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->n_children == 0) return; g_object_freeze_notify (G_OBJECT (self)); clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, NULL)) clutter_actor_iter_destroy (&iter); g_object_thaw_notify (G_OBJECT (self)); /* sanity check */ g_assert (self->priv->first_child == NULL); g_assert (self->priv->last_child == NULL); g_assert (self->priv->n_children == 0); } typedef struct _InsertBetweenData { ClutterActor *prev_sibling; ClutterActor *next_sibling; } InsertBetweenData; static void insert_child_between (ClutterActor *self, ClutterActor *child, gpointer data_) { InsertBetweenData *data = data_; ClutterActor *prev_sibling = data->prev_sibling; ClutterActor *next_sibling = data->next_sibling; child->priv->parent = self; child->priv->prev_sibling = prev_sibling; child->priv->next_sibling = next_sibling; if (prev_sibling != NULL) prev_sibling->priv->next_sibling = child; if (next_sibling != NULL) next_sibling->priv->prev_sibling = child; if (child->priv->prev_sibling == NULL) self->priv->first_child = child; if (child->priv->next_sibling == NULL) self->priv->last_child = child; } /** * clutter_actor_replace_child: * @self: a #ClutterActor * @old_child: the child of @self to replace * @new_child: the #ClutterActor to replace @old_child * * Replaces @old_child with @new_child in the list of children of @self. * * Since: 1.10 */ void clutter_actor_replace_child (ClutterActor *self, ClutterActor *old_child, ClutterActor *new_child) { ClutterActor *prev_sibling, *next_sibling; InsertBetweenData clos; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (old_child)); g_return_if_fail (old_child->priv->parent == self); g_return_if_fail (CLUTTER_IS_ACTOR (new_child)); g_return_if_fail (old_child != new_child); g_return_if_fail (new_child != self); g_return_if_fail (new_child->priv->parent == NULL); prev_sibling = old_child->priv->prev_sibling; next_sibling = old_child->priv->next_sibling; clutter_actor_remove_child_internal (self, old_child, REMOVE_CHILD_DEFAULT_FLAGS); clos.prev_sibling = prev_sibling; clos.next_sibling = next_sibling; clutter_actor_add_child_internal (self, new_child, ADD_CHILD_DEFAULT_FLAGS, insert_child_between, &clos); } /** * clutter_actor_unparent: * @self: a #ClutterActor * * Removes the parent of @self. * * This will cause the parent of @self to release the reference * acquired when calling clutter_actor_set_parent(), so if you * want to keep @self you will have to acquire a reference of * your own, through g_object_ref(). * * This function should only be called by legacy #ClutterActors * implementing the #ClutterContainer interface. * * Since: 0.2 * * Deprecated: 1.10: Use clutter_actor_remove_child() instead. */ void clutter_actor_unparent (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->parent == NULL) return; clutter_actor_remove_child_internal (self->priv->parent, self, REMOVE_CHILD_LEGACY_FLAGS); } /** * clutter_actor_reparent: * @self: a #ClutterActor * @new_parent: the new #ClutterActor parent * * Resets the parent actor of @self. * * This function is logically equivalent to calling clutter_actor_unparent() * and clutter_actor_set_parent(), but more efficiently implemented, as it * ensures the child is not finalized when unparented, and emits the * #ClutterActor::parent-set signal only once. * * In reality, calling this function is less useful than it sounds, as some * application code may rely on changes in the intermediate state between * removal and addition of the actor from its old parent to the @new_parent. * Thus, it is strongly encouraged to avoid using this function in application * code. * * Since: 0.2 * * Deprecated: 1.10: Use clutter_actor_remove_child() and * clutter_actor_add_child() instead; remember to take a reference on * the actor being removed before calling clutter_actor_remove_child() * to avoid the reference count dropping to zero and the actor being * destroyed. */ void clutter_actor_reparent (ClutterActor *self, ClutterActor *new_parent) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (new_parent)); g_return_if_fail (self != new_parent); if (CLUTTER_ACTOR_IS_TOPLEVEL (self)) { g_warning ("Cannot set a parent on a toplevel actor"); return; } if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) { g_warning ("Cannot set a parent currently being destroyed"); return; } priv = self->priv; if (priv->parent != new_parent) { ClutterActor *old_parent; CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT); old_parent = priv->parent; g_object_ref (self); if (old_parent != NULL) { /* go through the Container implementation if this is a regular * child and not an internal one */ if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self)) { ClutterContainer *parent = CLUTTER_CONTAINER (old_parent); /* this will have to call unparent() */ clutter_container_remove_actor (parent, self); } else clutter_actor_remove_child_internal (old_parent, self, REMOVE_CHILD_LEGACY_FLAGS); } /* Note, will call set_parent() */ if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self)) clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self); else clutter_actor_add_child_internal (new_parent, self, ADD_CHILD_LEGACY_FLAGS, insert_child_at_depth, NULL); /* we emit the ::parent-set signal once */ g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent); CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT); /* the IN_REPARENT flag suspends state updates */ clutter_actor_update_map_state (self, MAP_STATE_CHECK); g_object_unref (self); } } /** * clutter_actor_contains: * @self: A #ClutterActor * @descendant: A #ClutterActor, possibly contained in @self * * Determines if @descendant is contained inside @self (either as an * immediate child, or as a deeper descendant). If @self and * @descendant point to the same actor then it will also return %TRUE. * * Return value: whether @descendent is contained within @self * * Since: 1.4 */ gboolean clutter_actor_contains (ClutterActor *self, ClutterActor *descendant) { ClutterActor *actor; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE); for (actor = descendant; actor; actor = actor->priv->parent) if (actor == self) return TRUE; return FALSE; } /** * clutter_actor_set_child_above_sibling: * @self: a #ClutterActor * @child: a #ClutterActor child of @self * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL * * Sets @child to be above @sibling in the list of children of @self. * * If @sibling is %NULL, @child will be the new last child of @self. * * This function is logically equivalent to removing @child and using * clutter_actor_insert_child_above(), but it will not emit signals * or change state on @child. * * Since: 1.10 */ void clutter_actor_set_child_above_sibling (ClutterActor *self, ClutterActor *child, ClutterActor *sibling) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (child->priv->parent == self); g_return_if_fail (child != sibling); g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling)); if (sibling != NULL) g_return_if_fail (sibling->priv->parent == self); if (CLUTTER_ACTOR_IN_DESTRUCTION (self) || CLUTTER_ACTOR_IN_DESTRUCTION (child) || (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling))) return; /* we don't want to change the state of child, or emit signals, or * regenerate ChildMeta instances here, but we still want to follow * the correct sequence of steps encoded in remove_child() and * add_child(), so that correctness is ensured, and we only go * through one known code path. */ g_object_ref (child); clutter_actor_remove_child_internal (self, child, 0); clutter_actor_add_child_internal (self, child, ADD_CHILD_NOTIFY_FIRST_LAST, insert_child_above, sibling); g_object_unref(child); clutter_actor_queue_relayout (self); } /** * clutter_actor_set_child_below_sibling: * @self: a #ClutterActor * @child: a #ClutterActor child of @self * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL * * Sets @child to be below @sibling in the list of children of @self. * * If @sibling is %NULL, @child will be the new first child of @self. * * This function is logically equivalent to removing @self and using * clutter_actor_insert_child_below(), but it will not emit signals * or change state on @child. * * Since: 1.10 */ void clutter_actor_set_child_below_sibling (ClutterActor *self, ClutterActor *child, ClutterActor *sibling) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (child->priv->parent == self); g_return_if_fail (child != sibling); g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling)); if (sibling != NULL) g_return_if_fail (sibling->priv->parent == self); if (CLUTTER_ACTOR_IN_DESTRUCTION (self) || CLUTTER_ACTOR_IN_DESTRUCTION (child) || (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling))) return; /* see the comment in set_child_above_sibling() */ g_object_ref (child); clutter_actor_remove_child_internal (self, child, 0); clutter_actor_add_child_internal (self, child, ADD_CHILD_NOTIFY_FIRST_LAST, insert_child_below, sibling); g_object_unref(child); clutter_actor_queue_relayout (self); } /** * clutter_actor_set_child_at_index: * @self: a #ClutterActor * @child: a #ClutterActor child of @self * @index_: the new index for @child * * Changes the index of @child in the list of children of @self. * * This function is logically equivalent to removing @child and * calling clutter_actor_insert_child_at_index(), but it will not * emit signals or change state on @child. * * Since: 1.10 */ void clutter_actor_set_child_at_index (ClutterActor *self, ClutterActor *child, gint index_) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (child)); g_return_if_fail (child->priv->parent == self); g_return_if_fail (index_ <= self->priv->n_children); if (CLUTTER_ACTOR_IN_DESTRUCTION (self) || CLUTTER_ACTOR_IN_DESTRUCTION (child)) return; g_object_ref (child); clutter_actor_remove_child_internal (self, child, 0); clutter_actor_add_child_internal (self, child, ADD_CHILD_NOTIFY_FIRST_LAST, insert_child_at_index, GINT_TO_POINTER (index_)); g_object_unref (child); clutter_actor_queue_relayout (self); } /** * clutter_actor_raise: * @self: A #ClutterActor * @below: (allow-none): A #ClutterActor to raise above. * * Puts @self above @below. * * Both actors must have the same parent, and the parent must implement * the #ClutterContainer interface * * This function calls clutter_container_raise_child() internally. * * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead. */ void clutter_actor_raise (ClutterActor *self, ClutterActor *below) { ClutterActor *parent; g_return_if_fail (CLUTTER_IS_ACTOR (self)); parent = clutter_actor_get_parent (self); if (parent == NULL) { g_warning ("%s: Actor '%s' is not inside a container", G_STRFUNC, _clutter_actor_get_debug_name (self)); return; } if (below != NULL) { if (parent != clutter_actor_get_parent (below)) { g_warning ("%s Actor '%s' is not in the same container as " "actor '%s'", G_STRFUNC, _clutter_actor_get_debug_name (self), _clutter_actor_get_debug_name (below)); return; } } clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below); } /** * clutter_actor_lower: * @self: A #ClutterActor * @above: (allow-none): A #ClutterActor to lower below * * Puts @self below @above. * * Both actors must have the same parent, and the parent must implement * the #ClutterContainer interface. * * This function calls clutter_container_lower_child() internally. * * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead. */ void clutter_actor_lower (ClutterActor *self, ClutterActor *above) { ClutterActor *parent; g_return_if_fail (CLUTTER_IS_ACTOR (self)); parent = clutter_actor_get_parent (self); if (parent == NULL) { g_warning ("%s: Actor of type %s is not inside a container", G_STRFUNC, _clutter_actor_get_debug_name (self)); return; } if (above) { if (parent != clutter_actor_get_parent (above)) { g_warning ("%s: Actor '%s' is not in the same container as " "actor '%s'", G_STRFUNC, _clutter_actor_get_debug_name (self), _clutter_actor_get_debug_name (above)); return; } } clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above); } /** * clutter_actor_raise_top: * @self: A #ClutterActor * * Raises @self to the top. * * This function calls clutter_actor_raise() internally. * * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with * a %NULL sibling, instead. */ void clutter_actor_raise_top (ClutterActor *self) { clutter_actor_raise (self, NULL); } /** * clutter_actor_lower_bottom: * @self: A #ClutterActor * * Lowers @self to the bottom. * * This function calls clutter_actor_lower() internally. * * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with * a %NULL sibling, instead. */ void clutter_actor_lower_bottom (ClutterActor *self) { clutter_actor_lower (self, NULL); } /* * Event handling */ /** * clutter_actor_event: * @actor: a #ClutterActor * @event: a #ClutterEvent * @capture: %TRUE if event in in capture phase, %FALSE otherwise. * * This function is used to emit an event on the main stage. * You should rarely need to use this function, except for * synthetising events. * * Return value: the return value from the signal emission: %TRUE * if the actor handled the event, or %FALSE if the event was * not handled * * Since: 0.6 */ gboolean clutter_actor_event (ClutterActor *actor, const ClutterEvent *event, gboolean capture) { gboolean retval = FALSE; gint signal_num = -1; g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); g_return_val_if_fail (event != NULL, FALSE); g_object_ref (actor); if (capture) { g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0, event, &retval); goto out; } g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval); if (!retval) { switch (event->type) { case CLUTTER_NOTHING: break; case CLUTTER_BUTTON_PRESS: signal_num = BUTTON_PRESS_EVENT; break; case CLUTTER_BUTTON_RELEASE: signal_num = BUTTON_RELEASE_EVENT; break; case CLUTTER_SCROLL: signal_num = SCROLL_EVENT; break; case CLUTTER_KEY_PRESS: signal_num = KEY_PRESS_EVENT; break; case CLUTTER_KEY_RELEASE: signal_num = KEY_RELEASE_EVENT; break; case CLUTTER_MOTION: signal_num = MOTION_EVENT; break; case CLUTTER_ENTER: signal_num = ENTER_EVENT; break; case CLUTTER_LEAVE: signal_num = LEAVE_EVENT; break; case CLUTTER_TOUCH_BEGIN: case CLUTTER_TOUCH_END: case CLUTTER_TOUCH_UPDATE: case CLUTTER_TOUCH_CANCEL: signal_num = TOUCH_EVENT; break; case CLUTTER_DELETE: case CLUTTER_DESTROY_NOTIFY: case CLUTTER_CLIENT_MESSAGE: default: signal_num = -1; break; } if (signal_num != -1) g_signal_emit (actor, actor_signals[signal_num], 0, event, &retval); } out: g_object_unref (actor); return retval; } /** * clutter_actor_set_reactive: * @actor: a #ClutterActor * @reactive: whether the actor should be reactive to events * * Sets @actor as reactive. Reactive actors will receive events. * * Since: 0.6 */ void clutter_actor_set_reactive (ClutterActor *actor, gboolean reactive) { g_return_if_fail (CLUTTER_IS_ACTOR (actor)); if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor)) return; if (reactive) CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE); else CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE); g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]); } /** * clutter_actor_get_reactive: * @actor: a #ClutterActor * * Checks whether @actor is marked as reactive. * * Return value: %TRUE if the actor is reactive * * Since: 0.6 */ gboolean clutter_actor_get_reactive (ClutterActor *actor) { g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE; } /** * clutter_actor_get_anchor_point: * @self: a #ClutterActor * @anchor_x: (out): return location for the X coordinate of the anchor point * @anchor_y: (out): return location for the Y coordinate of the anchor point * * Gets the current anchor point of the @actor in pixels. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead */ void clutter_actor_get_anchor_point (ClutterActor *self, gfloat *anchor_x, gfloat *anchor_y) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); clutter_anchor_coord_get_units (self, &info->anchor, anchor_x, anchor_y, NULL); } /** * clutter_actor_set_anchor_point: * @self: a #ClutterActor * @anchor_x: X coordinate of the anchor point * @anchor_y: Y coordinate of the anchor point * * Sets an anchor point for @self. The anchor point is a point in the * coordinate space of an actor to which the actor position within its * parent is relative; the default is (0, 0), i.e. the top-left corner * of the actor. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead. */ void clutter_actor_set_anchor_point (ClutterActor *self, gfloat anchor_x, gfloat anchor_y) { ClutterTransformInfo *info; ClutterActorPrivate *priv; gboolean changed = FALSE; gfloat old_anchor_x, old_anchor_y; GObject *obj; g_return_if_fail (CLUTTER_IS_ACTOR (self)); obj = G_OBJECT (self); priv = self->priv; info = _clutter_actor_get_transform_info (self); g_object_freeze_notify (obj); clutter_anchor_coord_get_units (self, &info->anchor, &old_anchor_x, &old_anchor_y, NULL); if (info->anchor.is_fractional) g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]); if (old_anchor_x != anchor_x) { g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]); changed = TRUE; } if (old_anchor_y != anchor_y) { g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]); changed = TRUE; } clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0); if (changed) { priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); } g_object_thaw_notify (obj); } /** * clutter_actor_get_anchor_point_gravity: * @self: a #ClutterActor * * Retrieves the anchor position expressed as a #ClutterGravity. If * the anchor point was specified using pixels or units this will * return %CLUTTER_GRAVITY_NONE. * * Return value: the #ClutterGravity used by the anchor point * * Since: 1.0 * * Deprecated: 1.12: Use #ClutterActor:pivot-point instead. */ ClutterGravity clutter_actor_get_anchor_point_gravity (ClutterActor *self) { const ClutterTransformInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE); info = _clutter_actor_get_transform_info_or_defaults (self); return clutter_anchor_coord_get_gravity (&info->anchor); } /** * clutter_actor_move_anchor_point: * @self: a #ClutterActor * @anchor_x: X coordinate of the anchor point * @anchor_y: Y coordinate of the anchor point * * Sets an anchor point for the actor, and adjusts the actor postion so that * the relative position of the actor toward its parent remains the same. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point and * clutter_actor_set_translation() instead. */ void clutter_actor_move_anchor_point (ClutterActor *self, gfloat anchor_x, gfloat anchor_y) { gfloat old_anchor_x, old_anchor_y; const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info (self); clutter_anchor_coord_get_units (self, &info->anchor, &old_anchor_x, &old_anchor_y, NULL); g_object_freeze_notify (G_OBJECT (self)); clutter_actor_set_anchor_point (self, anchor_x, anchor_y); if (self->priv->position_set) clutter_actor_move_by (self, anchor_x - old_anchor_x, anchor_y - old_anchor_y); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_move_anchor_point_from_gravity: * @self: a #ClutterActor * @gravity: #ClutterGravity. * * Sets an anchor point on the actor based on the given gravity, adjusting the * actor postion so that its relative position within its parent remains * unchanged. * * Since version 1.0 the anchor point will be stored as a gravity so * that if the actor changes size then the anchor point will move. For * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST * and later double the size of the actor, the anchor point will move * to the bottom right. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point and * clutter_actor_set_translation() instead. */ void clutter_actor_move_anchor_point_from_gravity (ClutterActor *self, ClutterGravity gravity) { gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y; const ClutterTransformInfo *info; ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; info = _clutter_actor_get_transform_info (self); g_object_freeze_notify (G_OBJECT (self)); clutter_anchor_coord_get_units (self, &info->anchor, &old_anchor_x, &old_anchor_y, NULL); clutter_actor_set_anchor_point_from_gravity (self, gravity); clutter_anchor_coord_get_units (self, &info->anchor, &new_anchor_x, &new_anchor_y, NULL); if (priv->position_set) clutter_actor_move_by (self, new_anchor_x - old_anchor_x, new_anchor_y - old_anchor_y); g_object_thaw_notify (G_OBJECT (self)); } /** * clutter_actor_set_anchor_point_from_gravity: * @self: a #ClutterActor * @gravity: #ClutterGravity. * * Sets an anchor point on the actor, based on the given gravity (this is a * convenience function wrapping clutter_actor_set_anchor_point()). * * Since version 1.0 the anchor point will be stored as a gravity so * that if the actor changes size then the anchor point will move. For * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST * and later double the size of the actor, the anchor point will move * to the bottom right. * * Since: 0.6 * * Deprecated: 1.12: Use #ClutterActor:pivot-point and * clutter_actor_set_translation() instead. E.g. For %CLUTTER_GRAVITY_CENTER set * pivot_point to (0.5,0.5) and the translation to (width/2,height/2). */ void clutter_actor_set_anchor_point_from_gravity (ClutterActor *self, ClutterGravity gravity) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (gravity == CLUTTER_GRAVITY_NONE) clutter_actor_set_anchor_point (self, 0, 0); else { GObject *obj = G_OBJECT (self); ClutterTransformInfo *info; g_object_freeze_notify (obj); info = _clutter_actor_get_transform_info (self); clutter_anchor_coord_set_gravity (&info->anchor, gravity); g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]); g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]); g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]); self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_thaw_notify (obj); } } static void clutter_actor_store_content_box (ClutterActor *self, const ClutterActorBox *box) { if (box != NULL) { self->priv->content_box = *box; self->priv->content_box_valid = TRUE; } else self->priv->content_box_valid = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]); } static void clutter_container_iface_init (ClutterContainerIface *iface) { /* we don't override anything, as ClutterContainer already has a default * implementation that we can use, and which calls into our own API. */ } typedef enum { PARSE_X, PARSE_Y, PARSE_WIDTH, PARSE_HEIGHT, PARSE_ANCHOR_X, PARSE_ANCHOR_Y } ParseDimension; static gfloat parse_units (ClutterActor *self, ParseDimension dimension, JsonNode *node) { GValue value = G_VALUE_INIT; gfloat retval = 0; if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE) return 0; json_node_get_value (node, &value); if (G_VALUE_HOLDS (&value, G_TYPE_INT64)) { retval = (gfloat) g_value_get_int64 (&value); } else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)) { retval = g_value_get_double (&value); } else if (G_VALUE_HOLDS (&value, G_TYPE_STRING)) { ClutterUnits units; gboolean res; res = clutter_units_from_string (&units, g_value_get_string (&value)); if (res) retval = clutter_units_to_pixels (&units); else { g_warning ("Invalid value '%s': integers, strings or floating point " "values can be used for the x, y, width and height " "properties. Valid modifiers for strings are 'px', 'mm', " "'pt' and 'em'.", g_value_get_string (&value)); retval = 0; } } else { g_warning ("Invalid value of type '%s': integers, strings of floating " "point values can be used for the x, y, width, height " "anchor-x and anchor-y properties.", g_type_name (G_VALUE_TYPE (&value))); } g_value_unset (&value); return retval; } typedef struct { ClutterRotateAxis axis; gdouble angle; gfloat center_x; gfloat center_y; gfloat center_z; } RotationInfo; static inline gboolean parse_rotation_array (ClutterActor *actor, JsonArray *array, RotationInfo *info) { JsonNode *element; if (json_array_get_length (array) != 2) return FALSE; /* angle */ element = json_array_get_element (array, 0); if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE) info->angle = json_node_get_double (element); else return FALSE; /* center */ element = json_array_get_element (array, 1); if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY) { JsonArray *center = json_node_get_array (element); if (json_array_get_length (center) != 2) return FALSE; switch (info->axis) { case CLUTTER_X_AXIS: info->center_y = parse_units (actor, PARSE_Y, json_array_get_element (center, 0)); info->center_z = parse_units (actor, PARSE_Y, json_array_get_element (center, 1)); return TRUE; case CLUTTER_Y_AXIS: info->center_x = parse_units (actor, PARSE_X, json_array_get_element (center, 0)); info->center_z = parse_units (actor, PARSE_X, json_array_get_element (center, 1)); return TRUE; case CLUTTER_Z_AXIS: info->center_x = parse_units (actor, PARSE_X, json_array_get_element (center, 0)); info->center_y = parse_units (actor, PARSE_Y, json_array_get_element (center, 1)); return TRUE; } } return FALSE; } static gboolean parse_rotation (ClutterActor *actor, JsonNode *node, RotationInfo *info) { JsonArray *array; guint len, i; gboolean retval = FALSE; if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) { g_warning ("Invalid node of type '%s' found, expecting an array", json_node_type_name (node)); return FALSE; } array = json_node_get_array (node); len = json_array_get_length (array); for (i = 0; i < len; i++) { JsonNode *element = json_array_get_element (array, i); JsonObject *object; JsonNode *member; if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT) { g_warning ("Invalid node of type '%s' found, expecting an object", json_node_type_name (element)); return FALSE; } object = json_node_get_object (element); if (json_object_has_member (object, "x-axis")) { member = json_object_get_member (object, "x-axis"); info->axis = CLUTTER_X_AXIS; if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE) { info->angle = json_node_get_double (member); retval = TRUE; } else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY) retval = parse_rotation_array (actor, json_node_get_array (member), info); else retval = FALSE; } else if (json_object_has_member (object, "y-axis")) { member = json_object_get_member (object, "y-axis"); info->axis = CLUTTER_Y_AXIS; if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE) { info->angle = json_node_get_double (member); retval = TRUE; } else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY) retval = parse_rotation_array (actor, json_node_get_array (member), info); else retval = FALSE; } else if (json_object_has_member (object, "z-axis")) { member = json_object_get_member (object, "z-axis"); info->axis = CLUTTER_Z_AXIS; if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE) { info->angle = json_node_get_double (member); retval = TRUE; } else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY) retval = parse_rotation_array (actor, json_node_get_array (member), info); else retval = FALSE; } } return retval; } static GSList * parse_actor_metas (ClutterScript *script, ClutterActor *actor, JsonNode *node) { GList *elements, *l; GSList *retval = NULL; if (!JSON_NODE_HOLDS_ARRAY (node)) return NULL; elements = json_array_get_elements (json_node_get_array (node)); for (l = elements; l != NULL; l = l->next) { JsonNode *element = l->data; const gchar *id_ = _clutter_script_get_id_from_node (element); GObject *meta; if (id_ == NULL || *id_ == '\0') continue; meta = clutter_script_get_object (script, id_); if (meta == NULL) continue; retval = g_slist_prepend (retval, meta); } g_list_free (elements); return g_slist_reverse (retval); } static GSList * parse_behaviours (ClutterScript *script, ClutterActor *actor, JsonNode *node) { GList *elements, *l; GSList *retval = NULL; if (!JSON_NODE_HOLDS_ARRAY (node)) return NULL; elements = json_array_get_elements (json_node_get_array (node)); for (l = elements; l != NULL; l = l->next) { JsonNode *element = l->data; const gchar *id_ = _clutter_script_get_id_from_node (element); GObject *behaviour; if (id_ == NULL || *id_ == '\0') continue; behaviour = clutter_script_get_object (script, id_); if (behaviour == NULL) continue; retval = g_slist_prepend (retval, behaviour); } g_list_free (elements); return g_slist_reverse (retval); } static ClutterMargin * parse_margin (ClutterActor *self, JsonNode *node) { ClutterMargin *margin; JsonArray *array; if (!JSON_NODE_HOLDS_ARRAY (node)) { g_warning ("The margin property must be an array of 1 to 4 elements"); return NULL; } margin = clutter_margin_new (); array = json_node_get_array (node); switch (json_array_get_length (array)) { case 1: margin->top = margin->right = margin->bottom = margin->left = parse_units (self, 0, json_array_get_element (array, 0)); break; case 2: margin->top = margin->bottom = parse_units (self, 0, json_array_get_element (array, 0)); margin->right = margin->left = parse_units (self, 0, json_array_get_element (array, 1)); break; case 3: margin->top = parse_units (self, 0, json_array_get_element (array, 0)); margin->right = margin->left = parse_units (self, 0, json_array_get_element (array, 1)); margin->bottom = parse_units (self, 0, json_array_get_element (array, 2)); break; case 4: margin->top = parse_units (self, 0, json_array_get_element (array, 0)); margin->right = parse_units (self, 0, json_array_get_element (array, 1)); margin->bottom = parse_units (self, 0, json_array_get_element (array, 2)); margin->left = parse_units (self, 0, json_array_get_element (array, 3)); break; default: g_warning ("The margin property must be an array of 1 to 4 elements"); clutter_margin_free (margin); return NULL; } return margin; } static gboolean clutter_actor_parse_custom_node (ClutterScriptable *scriptable, ClutterScript *script, GValue *value, const gchar *name, JsonNode *node) { ClutterActor *actor = CLUTTER_ACTOR (scriptable); gboolean retval = FALSE; if ((name[0] == 'x' && name[1] == '\0') || (name[0] == 'y' && name[1] == '\0') || (strcmp (name, "width") == 0) || (strcmp (name, "height") == 0) || (strcmp (name, "anchor_x") == 0) || (strcmp (name, "anchor_y") == 0)) { ParseDimension dimension; gfloat units; if (name[0] == 'x') dimension = PARSE_X; else if (name[0] == 'y') dimension = PARSE_Y; else if (name[0] == 'w') dimension = PARSE_WIDTH; else if (name[0] == 'h') dimension = PARSE_HEIGHT; else if (name[0] == 'a' && name[7] == 'x') dimension = PARSE_ANCHOR_X; else if (name[0] == 'a' && name[7] == 'y') dimension = PARSE_ANCHOR_Y; else return FALSE; units = parse_units (actor, dimension, node); /* convert back to pixels: all properties are pixel-based */ g_value_init (value, G_TYPE_FLOAT); g_value_set_float (value, units); retval = TRUE; } else if (strcmp (name, "rotation") == 0) { RotationInfo *info; info = g_slice_new0 (RotationInfo); retval = parse_rotation (actor, node, info); if (retval) { g_value_init (value, G_TYPE_POINTER); g_value_set_pointer (value, info); } else g_slice_free (RotationInfo, info); } else if (strcmp (name, "behaviours") == 0) { GSList *l; #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (_clutter_diagnostic_enabled ())) _clutter_diagnostic_message ("The 'behaviours' key is deprecated " "and it should not be used in newly " "written ClutterScript definitions."); #endif l = parse_behaviours (script, actor, node); g_value_init (value, G_TYPE_POINTER); g_value_set_pointer (value, l); retval = TRUE; } else if (strcmp (name, "actions") == 0 || strcmp (name, "constraints") == 0 || strcmp (name, "effects") == 0) { GSList *l; l = parse_actor_metas (script, actor, node); g_value_init (value, G_TYPE_POINTER); g_value_set_pointer (value, l); retval = TRUE; } else if (strcmp (name, "margin") == 0) { ClutterMargin *margin = parse_margin (actor, node); if (margin) { g_value_init (value, CLUTTER_TYPE_MARGIN); g_value_set_boxed (value, margin); retval = TRUE; } } return retval; } static void clutter_actor_set_custom_property (ClutterScriptable *scriptable, ClutterScript *script, const gchar *name, const GValue *value) { ClutterActor *actor = CLUTTER_ACTOR (scriptable); #ifdef CLUTTER_ENABLE_DEBUG if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT))) { gchar *tmp = g_strdup_value_contents (value); CLUTTER_NOTE (SCRIPT, "in ClutterActor::set_custom_property('%s') = %s", name, tmp); free (tmp); } #endif /* CLUTTER_ENABLE_DEBUG */ if (strcmp (name, "rotation") == 0) { RotationInfo *info; if (!G_VALUE_HOLDS (value, G_TYPE_POINTER)) return; info = g_value_get_pointer (value); clutter_actor_set_rotation (actor, info->axis, info->angle, info->center_x, info->center_y, info->center_z); g_slice_free (RotationInfo, info); return; } if (strcmp (name, "behaviours") == 0) { GSList *behaviours, *l; if (!G_VALUE_HOLDS (value, G_TYPE_POINTER)) return; behaviours = g_value_get_pointer (value); for (l = behaviours; l != NULL; l = l->next) { ClutterBehaviour *behaviour = l->data; clutter_behaviour_apply (behaviour, actor); } g_slist_free (behaviours); return; } if (strcmp (name, "actions") == 0 || strcmp (name, "constraints") == 0 || strcmp (name, "effects") == 0) { GSList *metas, *l; if (!G_VALUE_HOLDS (value, G_TYPE_POINTER)) return; metas = g_value_get_pointer (value); for (l = metas; l != NULL; l = l->next) { if (name[0] == 'a') clutter_actor_add_action (actor, l->data); if (name[0] == 'c') clutter_actor_add_constraint (actor, l->data); if (name[0] == 'e') clutter_actor_add_effect (actor, l->data); } g_slist_free (metas); return; } if (strcmp (name, "margin") == 0) { clutter_actor_set_margin (actor, g_value_get_boxed (value)); return; } g_object_set_property (G_OBJECT (scriptable), name, value); } static void clutter_scriptable_iface_init (ClutterScriptableIface *iface) { iface->parse_custom_node = clutter_actor_parse_custom_node; iface->set_custom_property = clutter_actor_set_custom_property; } static ClutterActorMeta * get_meta_from_animation_property (ClutterActor *actor, const gchar *name, gchar **name_p) { ClutterActorPrivate *priv = actor->priv; ClutterActorMeta *meta = NULL; gchar **tokens; /* if this is not a special property, fall through */ if (name[0] != '@') return NULL; /* detect the properties named using the following spec: * * @
.. * * where
can be one of the following: * * - actions * - constraints * - effects * * and is the name set on a specific ActorMeta */ tokens = g_strsplit (name + 1, ".", -1); if (tokens == NULL || g_strv_length (tokens) != 3) { CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'", name + 1); g_strfreev (tokens); return NULL; } if (strcmp (tokens[0], "actions") == 0) meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]); if (strcmp (tokens[0], "constraints") == 0) meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]); if (strcmp (tokens[0], "effects") == 0) meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]); if (name_p != NULL) *name_p = g_strdup (tokens[2]); CLUTTER_NOTE (ANIMATION, "Looking for property '%s' of object '%s' in section '%s'", tokens[2], tokens[1], tokens[0]); g_strfreev (tokens); return meta; } static GParamSpec * clutter_actor_find_property (ClutterAnimatable *animatable, const gchar *property_name) { ClutterActorMeta *meta = NULL; GObjectClass *klass = NULL; GParamSpec *pspec = NULL; gchar *p_name = NULL; meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable), property_name, &p_name); if (meta != NULL) { klass = G_OBJECT_GET_CLASS (meta); pspec = g_object_class_find_property (klass, p_name); } else { klass = G_OBJECT_GET_CLASS (animatable); pspec = g_object_class_find_property (klass, property_name); } free (p_name); return pspec; } static void clutter_actor_get_initial_state (ClutterAnimatable *animatable, const gchar *property_name, GValue *initial) { ClutterActorMeta *meta = NULL; gchar *p_name = NULL; meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable), property_name, &p_name); if (meta != NULL) g_object_get_property (G_OBJECT (meta), p_name, initial); else g_object_get_property (G_OBJECT (animatable), property_name, initial); free (p_name); } /* * clutter_actor_set_animatable_property: * @actor: a #ClutterActor * @prop_id: the paramspec id * @value: the value to set * @pspec: the paramspec * * Sets values of animatable properties. * * This is a variant of clutter_actor_set_property() that gets called * by the #ClutterAnimatable implementation of #ClutterActor for the * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their * #GParamSpec. * * Unlike the implementation of #GObjectClass.set_property(), this * function will not update the interval if a transition involving an * animatable property is in progress - this avoids cycles with the * transition API calling the public API. */ static void clutter_actor_set_animatable_property (ClutterActor *actor, guint prop_id, const GValue *value, GParamSpec *pspec) { GObject *obj = G_OBJECT (actor); g_object_freeze_notify (obj); switch (prop_id) { case PROP_X: clutter_actor_set_x_internal (actor, g_value_get_float (value)); break; case PROP_Y: clutter_actor_set_y_internal (actor, g_value_get_float (value)); break; case PROP_POSITION: clutter_actor_set_position_internal (actor, g_value_get_boxed (value)); break; case PROP_WIDTH: clutter_actor_set_width_internal (actor, g_value_get_float (value)); break; case PROP_HEIGHT: clutter_actor_set_height_internal (actor, g_value_get_float (value)); break; case PROP_SIZE: clutter_actor_set_size_internal (actor, g_value_get_boxed (value)); break; case PROP_ALLOCATION: clutter_actor_allocate_internal (actor, g_value_get_boxed (value), actor->priv->allocation_flags); clutter_actor_queue_redraw (actor); break; case PROP_DEPTH: clutter_actor_set_depth_internal (actor, g_value_get_float (value)); break; case PROP_Z_POSITION: clutter_actor_set_z_position_internal (actor, g_value_get_float (value)); break; case PROP_OPACITY: clutter_actor_set_opacity_internal (actor, g_value_get_uint (value)); break; case PROP_BACKGROUND_COLOR: clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value)); break; case PROP_PIVOT_POINT: clutter_actor_set_pivot_point_internal (actor, g_value_get_boxed (value)); break; case PROP_PIVOT_POINT_Z: clutter_actor_set_pivot_point_z_internal (actor, g_value_get_float (value)); break; case PROP_TRANSLATION_X: case PROP_TRANSLATION_Y: case PROP_TRANSLATION_Z: clutter_actor_set_translation_internal (actor, g_value_get_float (value), pspec); break; case PROP_SCALE_X: case PROP_SCALE_Y: case PROP_SCALE_Z: clutter_actor_set_scale_factor_internal (actor, g_value_get_double (value), pspec); break; case PROP_ROTATION_ANGLE_X: case PROP_ROTATION_ANGLE_Y: case PROP_ROTATION_ANGLE_Z: clutter_actor_set_rotation_angle_internal (actor, g_value_get_double (value), pspec); break; case PROP_CONTENT_BOX: clutter_actor_store_content_box (actor, g_value_get_boxed (value)); break; case PROP_MARGIN_TOP: case PROP_MARGIN_BOTTOM: case PROP_MARGIN_LEFT: case PROP_MARGIN_RIGHT: clutter_actor_set_margin_internal (actor, g_value_get_float (value), pspec); break; case PROP_TRANSFORM: clutter_actor_set_transform_internal (actor, g_value_get_boxed (value)); break; case PROP_CHILD_TRANSFORM: clutter_actor_set_child_transform_internal (actor, g_value_get_boxed (value)); break; default: g_object_set_property (obj, pspec->name, value); break; } g_object_thaw_notify (obj); } static void clutter_actor_set_final_state (ClutterAnimatable *animatable, const gchar *property_name, const GValue *final) { ClutterActor *actor = CLUTTER_ACTOR (animatable); ClutterActorMeta *meta = NULL; gchar *p_name = NULL; meta = get_meta_from_animation_property (actor, property_name, &p_name); if (meta != NULL) g_object_set_property (G_OBJECT (meta), p_name, final); else { GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable); GParamSpec *pspec; pspec = g_object_class_find_property (obj_class, property_name); if (pspec != NULL) { if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0) { /* XXX - I'm going to the special hell for this */ clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec); } else g_object_set_property (G_OBJECT (animatable), pspec->name, final); } } free (p_name); } static void clutter_animatable_iface_init (ClutterAnimatableIface *iface) { iface->find_property = clutter_actor_find_property; iface->get_initial_state = clutter_actor_get_initial_state; iface->set_final_state = clutter_actor_set_final_state; } /** * clutter_actor_transform_stage_point: * @self: A #ClutterActor * @x: (in): x screen coordinate of the point to unproject * @y: (in): y screen coordinate of the point to unproject * @x_out: (out): return location for the unprojected x coordinance * @y_out: (out): return location for the unprojected y coordinance * * This function translates screen coordinates (@x, @y) to * coordinates relative to the actor. For example, it can be used to translate * screen events from global screen coordinates into actor-local coordinates. * * The conversion can fail, notably if the transform stack results in the * actor being projected on the screen as a mere line. * * The conversion should not be expected to be pixel-perfect due to the * nature of the operation. In general the error grows when the skewing * of the actor rectangle on screen increases. * * This function can be computationally intensive. * * This function only works when the allocation is up-to-date, i.e. inside of * the #ClutterActorClass.paint() implementation * * Return value: %TRUE if conversion was successful. * * Since: 0.6 */ gboolean clutter_actor_transform_stage_point (ClutterActor *self, gfloat x, gfloat y, gfloat *x_out, gfloat *y_out) { ClutterVertex v[4]; double ST[3][3]; double RQ[3][3]; int du, dv; double px, py; double det; float xf, yf, wf; ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); priv = self->priv; /* This implementation is based on the quad -> quad projection algorithm * described by Paul Heckbert in: * * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf * * and the sample implementation at: * * http://www.cs.cmu.edu/~ph/src/texfund/ * * Our texture is a rectangle with origin [0, 0], so we are mapping from * quad to rectangle only, which significantly simplifies things; the * function calls have been unrolled, and most of the math is done in fixed * point. */ clutter_actor_get_abs_allocation_vertices (self, v); /* Keeping these as ints simplifies the multiplication (no significant * loss of precision here). */ du = ceilf (priv->allocation.x2 - priv->allocation.x1); dv = ceilf (priv->allocation.y2 - priv->allocation.y1); if (du == 0 || dv == 0) return FALSE; #define DET(a,b,c,d) (((a) * (d)) - ((b) * (c))) /* First, find mapping from unit uv square to xy quadrilateral; this * equivalent to the pmap_square_quad() functions in the sample * implementation, which we can simplify, since our target is always * a rectangle. */ px = v[0].x - v[1].x + v[3].x - v[2].x; py = v[0].y - v[1].y + v[3].y - v[2].y; if ((int) px == 0 && (int) py == 0) { /* affine transform */ RQ[0][0] = v[1].x - v[0].x; RQ[1][0] = v[3].x - v[1].x; RQ[2][0] = v[0].x; RQ[0][1] = v[1].y - v[0].y; RQ[1][1] = v[3].y - v[1].y; RQ[2][1] = v[0].y; RQ[0][2] = 0.0; RQ[1][2] = 0.0; RQ[2][2] = 1.0; } else { /* projective transform */ double dx1, dx2, dy1, dy2; dx1 = v[1].x - v[3].x; dx2 = v[2].x - v[3].x; dy1 = v[1].y - v[3].y; dy2 = v[2].y - v[3].y; det = DET (dx1, dx2, dy1, dy2); if (fabs (det) <= DBL_EPSILON) return FALSE; RQ[0][2] = DET (px, dx2, py, dy2) / det; RQ[1][2] = DET (dx1, px, dy1, py) / det; RQ[1][2] = DET (dx1, px, dy1, py) / det; RQ[2][2] = 1.0; RQ[0][0] = v[1].x - v[0].x + (RQ[0][2] * v[1].x); RQ[1][0] = v[2].x - v[0].x + (RQ[1][2] * v[2].x); RQ[2][0] = v[0].x; RQ[0][1] = v[1].y - v[0].y + (RQ[0][2] * v[1].y); RQ[1][1] = v[2].y - v[0].y + (RQ[1][2] * v[2].y); RQ[2][1] = v[0].y; } /* * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit * square. Since our rectangle is based at 0,0 we only need to scale. */ RQ[0][0] /= du; RQ[1][0] /= dv; RQ[0][1] /= du; RQ[1][1] /= dv; RQ[0][2] /= du; RQ[1][2] /= dv; /* * Now RQ is transform from uv rectangle to xy quadrilateral; we need an * inverse of that. */ ST[0][0] = DET (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]); ST[1][0] = DET (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]); ST[2][0] = DET (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]); ST[0][1] = DET (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]); ST[1][1] = DET (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]); ST[2][1] = DET (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]); ST[0][2] = DET (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]); ST[1][2] = DET (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]); ST[2][2] = DET (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]); /* * Check the resulting matrix is OK. */ det = (RQ[0][0] * ST[0][0]) + (RQ[0][1] * ST[0][1]) + (RQ[0][2] * ST[0][2]); if (fabs (det) <= DBL_EPSILON) return FALSE; /* * Now transform our point with the ST matrix; the notional w * coordinate is 1, hence the last part is simply added. */ xf = x * ST[0][0] + y * ST[1][0] + ST[2][0]; yf = x * ST[0][1] + y * ST[1][1] + ST[2][1]; wf = x * ST[0][2] + y * ST[1][2] + ST[2][2]; if (x_out) *x_out = xf / wf; if (y_out) *y_out = yf / wf; #undef DET return TRUE; } /** * clutter_actor_is_rotated: * @self: a #ClutterActor * * Checks whether any rotation is applied to the actor. * * Return value: %TRUE if the actor is rotated. * * Since: 0.6 */ gboolean clutter_actor_is_rotated (ClutterActor *self) { const ClutterTransformInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); info = _clutter_actor_get_transform_info_or_defaults (self); if (info->rx_angle || info->ry_angle || info->rz_angle) return TRUE; return FALSE; } /** * clutter_actor_is_scaled: * @self: a #ClutterActor * * Checks whether the actor is scaled in either dimension. * * Return value: %TRUE if the actor is scaled. * * Since: 0.6 */ gboolean clutter_actor_is_scaled (ClutterActor *self) { const ClutterTransformInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); info = _clutter_actor_get_transform_info_or_defaults (self); if (info->scale_x != 1.0 || info->scale_y != 1.0) return TRUE; return FALSE; } ClutterActor * _clutter_actor_get_stage_internal (ClutterActor *actor) { while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor)) actor = actor->priv->parent; return actor; } /** * clutter_actor_get_stage: * @actor: a #ClutterActor * * Retrieves the #ClutterStage where @actor is contained. * * Return value: (transfer none) (type Clutter.Stage): the stage * containing the actor, or %NULL * * Since: 0.8 */ ClutterActor * clutter_actor_get_stage (ClutterActor *actor) { g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); return _clutter_actor_get_stage_internal (actor); } /** * clutter_actor_allocate_available_size: * @self: a #ClutterActor * @x: the actor's X coordinate * @y: the actor's Y coordinate * @available_width: the maximum available width, or -1 to use the * actor's natural width * @available_height: the maximum available height, or -1 to use the * actor's natural height * @flags: flags controlling the allocation * * Allocates @self taking into account the #ClutterActor's * preferred size, but limiting it to the maximum available width * and height provided. * * This function will do the right thing when dealing with the * actor's request mode. * * The implementation of this function is equivalent to: * * |[ * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) * { * clutter_actor_get_preferred_width (self, available_height, * &min_width, * &natural_width); * width = CLAMP (natural_width, min_width, available_width); * * clutter_actor_get_preferred_height (self, width, * &min_height, * &natural_height); * height = CLAMP (natural_height, min_height, available_height); * } * else if (request_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) * { * clutter_actor_get_preferred_height (self, available_width, * &min_height, * &natural_height); * height = CLAMP (natural_height, min_height, available_height); * * clutter_actor_get_preferred_width (self, height, * &min_width, * &natural_width); * width = CLAMP (natural_width, min_width, available_width); * } * else if (request_mode == CLUTTER_REQUEST_CONTENT_SIZE) * { * clutter_content_get_preferred_size (content, &natural_width, &natural_height); * * width = CLAMP (natural_width, 0, available_width); * height = CLAMP (natural_height, 0, available_height); * } * * box.x1 = x; box.y1 = y; * box.x2 = box.x1 + available_width; * box.y2 = box.y1 + available_height; * clutter_actor_allocate (self, &box, flags); * ]| * * This function can be used by fluid layout managers to allocate * an actor's preferred size without making it bigger than the area * available for the container. * * Since: 1.0 */ void clutter_actor_allocate_available_size (ClutterActor *self, gfloat x, gfloat y, gfloat available_width, gfloat available_height, ClutterAllocationFlags flags) { ClutterActorPrivate *priv; gfloat width, height; gfloat min_width, min_height; gfloat natural_width, natural_height; ClutterActorBox box; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; width = height = 0.0; switch (priv->request_mode) { case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH: clutter_actor_get_preferred_width (self, available_height, &min_width, &natural_width); width = CLAMP (natural_width, min_width, available_width); clutter_actor_get_preferred_height (self, width, &min_height, &natural_height); height = CLAMP (natural_height, min_height, available_height); break; case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT: clutter_actor_get_preferred_height (self, available_width, &min_height, &natural_height); height = CLAMP (natural_height, min_height, available_height); clutter_actor_get_preferred_width (self, height, &min_width, &natural_width); width = CLAMP (natural_width, min_width, available_width); break; case CLUTTER_REQUEST_CONTENT_SIZE: if (priv->content != NULL) { clutter_content_get_preferred_size (priv->content, &natural_width, &natural_height); width = CLAMP (natural_width, 0, available_width); height = CLAMP (natural_height, 0, available_height); } break; } box.x1 = x; box.y1 = y; box.x2 = box.x1 + width; box.y2 = box.y1 + height; clutter_actor_allocate (self, &box, flags); } /** * clutter_actor_allocate_preferred_size: * @self: a #ClutterActor * @flags: flags controlling the allocation * * Allocates the natural size of @self. * * This function is a utility call for #ClutterActor implementations * that allocates the actor's preferred natural size. It can be used * by fixed layout managers (like #ClutterGroup or so called * 'composite actors') inside the ClutterActor::allocate * implementation to give each child exactly how much space it * requires, regardless of the size of the parent. * * This function is not meant to be used by applications. It is also * not meant to be used outside the implementation of the * #ClutterActorClass.allocate virtual function. * * Since: 0.8 */ void clutter_actor_allocate_preferred_size (ClutterActor *self, ClutterAllocationFlags flags) { gfloat actor_x, actor_y; gfloat natural_width, natural_height; ClutterActorBox actor_box; ClutterActorPrivate *priv; const ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (priv->position_set) { info = _clutter_actor_get_layout_info_or_defaults (self); actor_x = info->fixed_pos.x; actor_y = info->fixed_pos.y; } else { actor_x = 0; actor_y = 0; } clutter_actor_get_preferred_size (self, NULL, NULL, &natural_width, &natural_height); actor_box.x1 = actor_x; actor_box.y1 = actor_y; actor_box.x2 = actor_box.x1 + natural_width; actor_box.y2 = actor_box.y1 + natural_height; clutter_actor_allocate (self, &actor_box, flags); } /** * clutter_actor_allocate_align_fill: * @self: a #ClutterActor * @box: a #ClutterActorBox, containing the available width and height * @x_align: the horizontal alignment, between 0 and 1 * @y_align: the vertical alignment, between 0 and 1 * @x_fill: whether the actor should fill horizontally * @y_fill: whether the actor should fill vertically * @flags: allocation flags to be passed to clutter_actor_allocate() * * Allocates @self by taking into consideration the available allocation * area; an alignment factor on either axis; and whether the actor should * fill the allocation on either axis. * * The @box should contain the available allocation width and height; * if the x1 and y1 members of #ClutterActorBox are not set to 0, the * allocation will be offset by their value. * * This function takes into consideration the geometry request specified by * the #ClutterActor:request-mode property, and the text direction. * * This function is useful for fluid layout managers using legacy alignment * flags. Newly written layout managers should use the #ClutterActor:x-align * and #ClutterActor:y-align properties, instead, and just call * clutter_actor_allocate() inside their #ClutterActorClass.allocate() * implementation. * * Since: 1.4 */ void clutter_actor_allocate_align_fill (ClutterActor *self, const ClutterActorBox *box, gdouble x_align, gdouble y_align, gboolean x_fill, gboolean y_fill, ClutterAllocationFlags flags) { ClutterActorPrivate *priv; ClutterActorBox allocation = CLUTTER_ACTOR_BOX_INIT_ZERO; gfloat x_offset, y_offset; gfloat available_width, available_height; gfloat child_width = 0.f, child_height = 0.f; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (box != NULL); g_return_if_fail (x_align >= 0.0 && x_align <= 1.0); g_return_if_fail (y_align >= 0.0 && y_align <= 1.0); priv = self->priv; clutter_actor_box_get_origin (box, &x_offset, &y_offset); clutter_actor_box_get_size (box, &available_width, &available_height); if (available_width <= 0) available_width = 0.f; if (available_height <= 0) available_height = 0.f; allocation.x1 = x_offset; allocation.y1 = y_offset; if (available_width == 0.f && available_height == 0.f) goto out; if (x_fill) child_width = available_width; if (y_fill) child_height = available_height; /* if we are filling horizontally and vertically then we're done */ if (x_fill && y_fill) goto out; if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) { gfloat min_width, natural_width; gfloat min_height, natural_height; if (!x_fill) { clutter_actor_get_preferred_width (self, available_height, &min_width, &natural_width); child_width = CLAMP (natural_width, min_width, available_width); } if (!y_fill) { clutter_actor_get_preferred_height (self, child_width, &min_height, &natural_height); child_height = CLAMP (natural_height, min_height, available_height); } } else if (priv->request_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) { gfloat min_width, natural_width; gfloat min_height, natural_height; if (!y_fill) { clutter_actor_get_preferred_height (self, available_width, &min_height, &natural_height); child_height = CLAMP (natural_height, min_height, available_height); } if (!x_fill) { clutter_actor_get_preferred_width (self, child_height, &min_width, &natural_width); child_width = CLAMP (natural_width, min_width, available_width); } } else if (priv->request_mode == CLUTTER_REQUEST_CONTENT_SIZE && priv->content != NULL) { gfloat natural_width, natural_height; clutter_content_get_preferred_size (priv->content, &natural_width, &natural_height); if (!x_fill) child_width = CLAMP (natural_width, 0, available_width); if (!y_fill) child_height = CLAMP (natural_height, 0, available_height); } /* invert the horizontal alignment for RTL languages */ if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL) x_align = 1.0 - x_align; if (!x_fill) allocation.x1 += ((available_width - child_width) * x_align); if (!y_fill) allocation.y1 += ((available_height - child_height) * y_align); out: allocation.x1 = floorf (allocation.x1); allocation.y1 = floorf (allocation.y1); allocation.x2 = ceilf (allocation.x1 + MAX (child_width, 0)); allocation.y2 = ceilf (allocation.y1 + MAX (child_height, 0)); clutter_actor_allocate (self, &allocation, flags); } /** * clutter_actor_grab_key_focus: * @self: a #ClutterActor * * Sets the key focus of the #ClutterStage including @self * to this #ClutterActor. * * Since: 1.0 */ void clutter_actor_grab_key_focus (ClutterActor *self) { ClutterActor *stage; g_return_if_fail (CLUTTER_IS_ACTOR (self)); stage = _clutter_actor_get_stage_internal (self); if (stage != NULL) clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self); } static void update_pango_context (ClutterBackend *backend, PangoContext *context) { ClutterSettings *settings; PangoFontDescription *font_desc; const cairo_font_options_t *font_options; gchar *font_name; PangoDirection pango_dir; gdouble resolution; settings = clutter_settings_get_default (); /* update the text direction */ if (clutter_get_default_text_direction () == CLUTTER_TEXT_DIRECTION_RTL) pango_dir = PANGO_DIRECTION_RTL; else pango_dir = PANGO_DIRECTION_LTR; pango_context_set_base_dir (context, pango_dir); g_object_get (settings, "font-name", &font_name, NULL); /* get the configuration for the PangoContext from the backend */ font_options = clutter_backend_get_font_options (backend); resolution = clutter_backend_get_resolution (backend); font_desc = pango_font_description_from_string (font_name); if (resolution < 0) resolution = 96.0; /* fall back */ pango_context_set_font_description (context, font_desc); pango_cairo_context_set_font_options (context, font_options); pango_cairo_context_set_resolution (context, resolution); pango_font_description_free (font_desc); free (font_name); } /** * clutter_actor_get_pango_context: * @self: a #ClutterActor * * Retrieves the #PangoContext for @self. The actor's #PangoContext * is already configured using the appropriate font map, resolution * and font options. * * Unlike clutter_actor_create_pango_context(), this context is owend * by the #ClutterActor and it will be updated each time the options * stored by the #ClutterBackend change. * * You can use the returned #PangoContext to create a #PangoLayout * and render text using cogl_pango_render_layout() to reuse the * glyphs cache also used by Clutter. * * Return value: (transfer none): the #PangoContext for a #ClutterActor. * The returned #PangoContext is owned by the actor and should not be * unreferenced by the application code * * Since: 1.0 */ PangoContext * clutter_actor_get_pango_context (ClutterActor *self) { ClutterActorPrivate *priv; ClutterBackend *backend = clutter_get_default_backend (); g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); priv = self->priv; if (G_UNLIKELY (priv->pango_context == NULL)) { priv->pango_context = clutter_actor_create_pango_context (self); g_signal_connect_object (backend, "resolution-changed", G_CALLBACK (update_pango_context), priv->pango_context, 0); g_signal_connect_object (backend, "font-changed", G_CALLBACK (update_pango_context), priv->pango_context, 0); } else update_pango_context (backend, priv->pango_context); return priv->pango_context; } /** * clutter_actor_create_pango_context: * @self: a #ClutterActor * * Creates a #PangoContext for the given actor. The #PangoContext * is already configured using the appropriate font map, resolution * and font options. * * See also clutter_actor_get_pango_context(). * * Return value: (transfer full): the newly created #PangoContext. * Use g_object_unref() on the returned value to deallocate its * resources * * Since: 1.0 */ PangoContext * clutter_actor_create_pango_context (ClutterActor *self) { CoglPangoFontMap *font_map; PangoContext *context; font_map = COGL_PANGO_FONT_MAP (clutter_get_font_map ()); context = cogl_pango_font_map_create_context (font_map); update_pango_context (clutter_get_default_backend (), context); pango_context_set_language (context, pango_language_get_default ()); return context; } /** * clutter_actor_create_pango_layout: * @self: a #ClutterActor * @text: (allow-none): the text to set on the #PangoLayout, or %NULL * * Creates a new #PangoLayout from the same #PangoContext used * by the #ClutterActor. The #PangoLayout is already configured * with the font map, resolution and font options, and the * given @text. * * If you want to keep around a #PangoLayout created by this * function you will have to connect to the #ClutterBackend::font-changed * and #ClutterBackend::resolution-changed signals, and call * pango_layout_context_changed() in response to them. * * Return value: (transfer full): the newly created #PangoLayout. * Use g_object_unref() when done * * Since: 1.0 */ PangoLayout * clutter_actor_create_pango_layout (ClutterActor *self, const gchar *text) { PangoContext *context; PangoLayout *layout; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); context = clutter_actor_get_pango_context (self); layout = pango_layout_new (context); if (text) pango_layout_set_text (layout, text, -1); return layout; } /** * clutter_actor_set_opacity_override: * @self: a #ClutterActor * @opacity: the override opacity value, or -1 to reset * * Allows overriding the calculated paint opacity (as returned by * clutter_actor_get_paint_opacity()). This is used internally by * ClutterClone and ClutterOffscreenEffect, and should be used by * actors that need to mimick those. * * In almost all cases this should not used by applications. * * Stability: unstable */ void clutter_actor_set_opacity_override (ClutterActor *self, gint opacity) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); /* ensure bounds */ if (opacity >= 0) opacity = CLAMP (opacity, 0, 255); else opacity = -1; self->priv->opacity_override = opacity; } /** * clutter_actor_get_opacity_override: * @self: a #ClutterActor * * See clutter_actor_set_opacity_override() * * Returns: the override value for the actor's opacity, or -1 if no override * is set. * * Since: 1.22 * * Stability: unstable */ gint clutter_actor_get_opacity_override (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1); return self->priv->opacity_override; } /* Allows you to disable applying the actors model view transform during * a paint. Used by ClutterClone. */ void _clutter_actor_set_enable_model_view_transform (ClutterActor *self, gboolean enable) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); self->priv->enable_model_view_transform = enable; } void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self, gboolean enable) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; priv->enable_paint_unmapped = enable; if (priv->enable_paint_unmapped) { /* Make sure that the parents of the widget are realized first; * otherwise checks in clutter_actor_update_map_state() will * fail. */ clutter_actor_realize (self); /* If the actor isn't ultimately connected to a toplevel, it can't be * realized or painted. */ if (CLUTTER_ACTOR_IS_REALIZED (self)) clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED); } else { clutter_actor_update_map_state (self, MAP_STATE_CHECK); } } static void clutter_anchor_coord_get_units (ClutterActor *self, const AnchorCoord *coord, gfloat *x, gfloat *y, gfloat *z) { if (coord->is_fractional) { gfloat actor_width, actor_height; clutter_actor_get_size (self, &actor_width, &actor_height); if (x) *x = actor_width * coord->v.fraction.x; if (y) *y = actor_height * coord->v.fraction.y; if (z) *z = 0; } else { if (x) *x = coord->v.units.x; if (y) *y = coord->v.units.y; if (z) *z = coord->v.units.z; } } static void clutter_anchor_coord_set_units (AnchorCoord *coord, gfloat x, gfloat y, gfloat z) { coord->is_fractional = FALSE; coord->v.units.x = x; coord->v.units.y = y; coord->v.units.z = z; } static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord) { if (coord->is_fractional) { if (coord->v.fraction.x == 0.0) { if (coord->v.fraction.y == 0.0) return CLUTTER_GRAVITY_NORTH_WEST; else if (coord->v.fraction.y == 0.5) return CLUTTER_GRAVITY_WEST; else if (coord->v.fraction.y == 1.0) return CLUTTER_GRAVITY_SOUTH_WEST; else return CLUTTER_GRAVITY_NONE; } else if (coord->v.fraction.x == 0.5) { if (coord->v.fraction.y == 0.0) return CLUTTER_GRAVITY_NORTH; else if (coord->v.fraction.y == 0.5) return CLUTTER_GRAVITY_CENTER; else if (coord->v.fraction.y == 1.0) return CLUTTER_GRAVITY_SOUTH; else return CLUTTER_GRAVITY_NONE; } else if (coord->v.fraction.x == 1.0) { if (coord->v.fraction.y == 0.0) return CLUTTER_GRAVITY_NORTH_EAST; else if (coord->v.fraction.y == 0.5) return CLUTTER_GRAVITY_EAST; else if (coord->v.fraction.y == 1.0) return CLUTTER_GRAVITY_SOUTH_EAST; else return CLUTTER_GRAVITY_NONE; } else return CLUTTER_GRAVITY_NONE; } else return CLUTTER_GRAVITY_NONE; } static void clutter_anchor_coord_set_gravity (AnchorCoord *coord, ClutterGravity gravity) { switch (gravity) { case CLUTTER_GRAVITY_NORTH: coord->v.fraction.x = 0.5; coord->v.fraction.y = 0.0; break; case CLUTTER_GRAVITY_NORTH_EAST: coord->v.fraction.x = 1.0; coord->v.fraction.y = 0.0; break; case CLUTTER_GRAVITY_EAST: coord->v.fraction.x = 1.0; coord->v.fraction.y = 0.5; break; case CLUTTER_GRAVITY_SOUTH_EAST: coord->v.fraction.x = 1.0; coord->v.fraction.y = 1.0; break; case CLUTTER_GRAVITY_SOUTH: coord->v.fraction.x = 0.5; coord->v.fraction.y = 1.0; break; case CLUTTER_GRAVITY_SOUTH_WEST: coord->v.fraction.x = 0.0; coord->v.fraction.y = 1.0; break; case CLUTTER_GRAVITY_WEST: coord->v.fraction.x = 0.0; coord->v.fraction.y = 0.5; break; case CLUTTER_GRAVITY_NORTH_WEST: coord->v.fraction.x = 0.0; coord->v.fraction.y = 0.0; break; case CLUTTER_GRAVITY_CENTER: coord->v.fraction.x = 0.5; coord->v.fraction.y = 0.5; break; default: coord->v.fraction.x = 0.0; coord->v.fraction.y = 0.0; break; } coord->is_fractional = TRUE; } static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord) { if (coord->is_fractional) return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0; else return (coord->v.units.x == 0.0 && coord->v.units.y == 0.0 && coord->v.units.z == 0.0); } /** * clutter_actor_get_flags: * @self: a #ClutterActor * * Retrieves the flags set on @self * * Return value: a bitwise or of #ClutterActorFlags or 0 * * Since: 1.0 */ ClutterActorFlags clutter_actor_get_flags (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); return self->flags; } /** * clutter_actor_set_flags: * @self: a #ClutterActor * @flags: the flags to set * * Sets @flags on @self * * This function will emit notifications for the changed properties * * Since: 1.0 */ void clutter_actor_set_flags (ClutterActor *self, ClutterActorFlags flags) { ClutterActorFlags old_flags; GObject *obj; gboolean was_reactive_set, reactive_set; gboolean was_realized_set, realized_set; gboolean was_mapped_set, mapped_set; gboolean was_visible_set, visible_set; g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->flags == flags) return; obj = G_OBJECT (self); g_object_ref (obj); g_object_freeze_notify (obj); old_flags = self->flags; was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0); was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0); was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0); was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0); self->flags |= flags; reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0); realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0); mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0); visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0); if (reactive_set != was_reactive_set) g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]); if (realized_set != was_realized_set) g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]); if (mapped_set != was_mapped_set) g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]); if (visible_set != was_visible_set) g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]); g_object_thaw_notify (obj); g_object_unref (obj); } /** * clutter_actor_unset_flags: * @self: a #ClutterActor * @flags: the flags to unset * * Unsets @flags on @self * * This function will emit notifications for the changed properties * * Since: 1.0 */ void clutter_actor_unset_flags (ClutterActor *self, ClutterActorFlags flags) { ClutterActorFlags old_flags; GObject *obj; gboolean was_reactive_set, reactive_set; gboolean was_realized_set, realized_set; gboolean was_mapped_set, mapped_set; gboolean was_visible_set, visible_set; g_return_if_fail (CLUTTER_IS_ACTOR (self)); obj = G_OBJECT (self); g_object_freeze_notify (obj); old_flags = self->flags; was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0); was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0); was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0); was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0); self->flags &= ~flags; if (self->flags == old_flags) return; reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0); realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0); mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0); visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0); if (reactive_set != was_reactive_set) g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]); if (realized_set != was_realized_set) g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]); if (mapped_set != was_mapped_set) g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]); if (visible_set != was_visible_set) g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]); g_object_thaw_notify (obj); } /** * clutter_actor_get_transformation_matrix: * @self: a #ClutterActor * @matrix: (out caller-allocates): the return location for a #ClutterMatrix * * Retrieves the transformations applied to @self relative to its * parent. * * Since: 1.0 * * Deprecated: 1.12: Use clutter_actor_get_transform() instead */ void clutter_actor_get_transformation_matrix (ClutterActor *self, ClutterMatrix *matrix) { clutter_actor_get_transform (self, matrix); } static void clutter_actor_set_transform_internal (ClutterActor *self, const ClutterMatrix *transform) { ClutterTransformInfo *info; gboolean was_set; GObject *obj; obj = G_OBJECT (self); info = _clutter_actor_get_transform_info (self); was_set = info->transform_set; info->transform = *transform; info->transform_set = !cogl_matrix_is_identity (&info->transform); self->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (obj, obj_props[PROP_TRANSFORM]); if (was_set != info->transform_set) g_object_notify_by_pspec (obj, obj_props[PROP_TRANSFORM_SET]); } /** * clutter_actor_set_transform: * @self: a #ClutterActor * @transform: (allow-none): a #ClutterMatrix, or %NULL to * unset a custom transformation * * Overrides the transformations of a #ClutterActor with a custom * matrix, which will be applied relative to the origin of the * actor's allocation and to the actor's pivot point. * * The #ClutterActor:transform property is animatable. * * Since: 1.12 */ void clutter_actor_set_transform (ClutterActor *self, const ClutterMatrix *transform) { const ClutterTransformInfo *info; ClutterMatrix new_transform; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); if (transform != NULL) clutter_matrix_init_from_matrix (&new_transform, transform); else clutter_matrix_init_identity (&new_transform); _clutter_actor_create_transition (self, obj_props[PROP_TRANSFORM], &info->transform, &new_transform); } /** * clutter_actor_get_transform: * @self: a #ClutterActor * @transform: (out caller-allocates): a #ClutterMatrix * * Retrieves the current transformation matrix of a #ClutterActor. * * Since: 1.12 */ void clutter_actor_get_transform (ClutterActor *self, ClutterMatrix *transform) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (transform != NULL); cogl_matrix_init_identity (transform); _clutter_actor_apply_modelview_transform (self, transform); } void _clutter_actor_set_in_clone_paint (ClutterActor *self, gboolean is_in_clone_paint) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); self->priv->in_clone_paint = is_in_clone_paint; } /** * clutter_actor_is_in_clone_paint: * @self: a #ClutterActor * * Checks whether @self is being currently painted by a #ClutterClone * * This function is useful only inside the ::paint virtual function * implementations or within handlers for the #ClutterActor::paint * signal * * This function should not be used by applications * * Return value: %TRUE if the #ClutterActor is currently being painted * by a #ClutterClone, and %FALSE otherwise * * Since: 1.0 */ gboolean clutter_actor_is_in_clone_paint (ClutterActor *self) { ClutterActor *parent; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); if (self->priv->in_clone_paint) return TRUE; if (self->priv->in_cloned_branch == 0) return FALSE; parent = self->priv->parent; while (parent != NULL) { if (parent->priv->in_cloned_branch == 0) break; if (parent->priv->in_clone_paint) return TRUE; parent = parent->priv->parent; } return FALSE; } static gboolean set_direction_recursive (ClutterActor *actor, gpointer user_data) { ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data); clutter_actor_set_text_direction (actor, text_dir); return TRUE; } /** * clutter_actor_set_text_direction: * @self: a #ClutterActor * @text_dir: the text direction for @self * * Sets the #ClutterTextDirection for an actor * * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT * * If @self implements #ClutterContainer then this function will recurse * inside all the children of @self (including the internal ones). * * Composite actors not implementing #ClutterContainer, or actors requiring * special handling when the text direction changes, should connect to * the #GObject::notify signal for the #ClutterActor:text-direction property * * Since: 1.2 */ void clutter_actor_set_text_direction (ClutterActor *self, ClutterTextDirection text_dir) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT); priv = self->priv; if (priv->text_direction != text_dir) { priv->text_direction = text_dir; /* we need to emit the notify::text-direction first, so that * the sub-classes can catch that and do specific handling of * the text direction; see clutter_text_direction_changed_cb() * inside clutter-text.c */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]); _clutter_actor_foreach_child (self, set_direction_recursive, GINT_TO_POINTER (text_dir)); clutter_actor_queue_relayout (self); } } void _clutter_actor_set_has_pointer (ClutterActor *self, gboolean has_pointer) { ClutterActorPrivate *priv = self->priv; if (priv->has_pointer != has_pointer) { priv->has_pointer = has_pointer; g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]); } } /** * clutter_actor_get_text_direction: * @self: a #ClutterActor * * Retrieves the value set using clutter_actor_set_text_direction() * * If no text direction has been previously set, the default text * direction, as returned by clutter_get_default_text_direction(), will * be returned instead * * Return value: the #ClutterTextDirection for the actor * * Since: 1.2 */ ClutterTextDirection clutter_actor_get_text_direction (ClutterActor *self) { ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_TEXT_DIRECTION_LTR); priv = self->priv; /* if no direction has been set yet use the default */ if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT) priv->text_direction = clutter_get_default_text_direction (); return priv->text_direction; } /** * clutter_actor_push_internal: * @self: a #ClutterActor * * Should be used by actors implementing the #ClutterContainer and with * internal children added through clutter_actor_set_parent(), for instance: * * |[ * static void * my_actor_init (MyActor *self) * { * self->priv = my_actor_get_instance_private (self); * * clutter_actor_push_internal (CLUTTER_ACTOR (self)); * * // calling clutter_actor_set_parent() now will result in * // the internal flag being set on a child of MyActor * * // internal child - a background texture * self->priv->background_tex = clutter_texture_new (); * clutter_actor_set_parent (self->priv->background_tex, * CLUTTER_ACTOR (self)); * * // internal child - a label * self->priv->label = clutter_text_new (); * clutter_actor_set_parent (self->priv->label, * CLUTTER_ACTOR (self)); * * clutter_actor_pop_internal (CLUTTER_ACTOR (self)); * * // calling clutter_actor_set_parent() now will not result in * // the internal flag being set on a child of MyActor * } * ]| * * This function will be used by Clutter to toggle an "internal child" * flag whenever clutter_actor_set_parent() is called; internal children * are handled differently by Clutter, specifically when destroying their * parent. * * Call clutter_actor_pop_internal() when you finished adding internal * children. * * Nested calls to clutter_actor_push_internal() are allowed, but each * one must by followed by a clutter_actor_pop_internal() call. * * Since: 1.2 * * Deprecated: 1.10: All children of an actor are accessible through * the #ClutterActor API, and #ClutterActor implements the * #ClutterContainer interface, so this function is only useful * for legacy containers overriding the default implementation. */ void clutter_actor_push_internal (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); self->priv->internal_child += 1; } /** * clutter_actor_pop_internal: * @self: a #ClutterActor * * Disables the effects of clutter_actor_push_internal(). * * Since: 1.2 * * Deprecated: 1.10: All children of an actor are accessible through * the #ClutterActor API. This function is only useful for legacy * containers overriding the default implementation of the * #ClutterContainer interface. */ void clutter_actor_pop_internal (ClutterActor *self) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (priv->internal_child == 0) { g_warning ("Mismatched %s: you need to call " "clutter_actor_push_composite() at least once before " "calling this function", G_STRFUNC); return; } priv->internal_child -= 1; } /** * clutter_actor_has_pointer: * @self: a #ClutterActor * * Checks whether an actor contains the pointer of a * #ClutterInputDevice * * Return value: %TRUE if the actor contains the pointer, and * %FALSE otherwise * * Since: 1.2 */ gboolean clutter_actor_has_pointer (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return self->priv->has_pointer; } /* XXX: This is a workaround for not being able to break the ABI of * the QUEUE_REDRAW signal. It is an out-of-band argument. See * clutter_actor_queue_clipped_redraw() for details. */ ClutterPaintVolume * _clutter_actor_get_queue_redraw_clip (ClutterActor *self) { return g_object_get_data (G_OBJECT (self), "-clutter-actor-queue-redraw-clip"); } void _clutter_actor_set_queue_redraw_clip (ClutterActor *self, ClutterPaintVolume *clip) { g_object_set_data (G_OBJECT (self), "-clutter-actor-queue-redraw-clip", clip); } /** * clutter_actor_has_allocation: * @self: a #ClutterActor * * Checks if the actor has an up-to-date allocation assigned to * it. This means that the actor should have an allocation: it's * visible and has a parent. It also means that there is no * outstanding relayout request in progress for the actor or its * children (There might be other outstanding layout requests in * progress that will cause the actor to get a new allocation * when the stage is laid out, however). * * If this function returns %FALSE, then the actor will normally * be allocated before it is next drawn on the screen. * * Return value: %TRUE if the actor has an up-to-date allocation * * Since: 1.4 */ gboolean clutter_actor_has_allocation (ClutterActor *self) { ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); priv = self->priv; return priv->parent != NULL && CLUTTER_ACTOR_IS_VISIBLE (self) && !priv->needs_allocation; } /** * clutter_actor_add_action: * @self: a #ClutterActor * @action: a #ClutterAction * * Adds @action to the list of actions applied to @self * * A #ClutterAction can only belong to one actor at a time * * The #ClutterActor will hold a reference on @action until either * clutter_actor_remove_action() or clutter_actor_clear_actions() * is called * * Since: 1.4 */ void clutter_actor_add_action (ClutterActor *self, ClutterAction *action) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTION (action)); priv = self->priv; if (priv->actions == NULL) { priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL); priv->actions->actor = self; } _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]); } /** * clutter_actor_add_action_with_name: * @self: a #ClutterActor * @name: the name to set on the action * @action: a #ClutterAction * * A convenience function for setting the name of a #ClutterAction * while adding it to the list of actions applied to @self * * This function is the logical equivalent of: * * |[ * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name); * clutter_actor_add_action (self, action); * ]| * * Since: 1.4 */ void clutter_actor_add_action_with_name (ClutterActor *self, const gchar *name, ClutterAction *action) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); g_return_if_fail (CLUTTER_IS_ACTION (action)); clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name); clutter_actor_add_action (self, action); } /** * clutter_actor_remove_action: * @self: a #ClutterActor * @action: a #ClutterAction * * Removes @action from the list of actions applied to @self * * The reference held by @self on the #ClutterAction will be released * * Since: 1.4 */ void clutter_actor_remove_action (ClutterActor *self, ClutterAction *action) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTION (action)); priv = self->priv; if (priv->actions == NULL) return; _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action)); if (_clutter_meta_group_peek_metas (priv->actions) == NULL) g_clear_object (&priv->actions); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]); } /** * clutter_actor_remove_action_by_name: * @self: a #ClutterActor * @name: the name of the action to remove * * Removes the #ClutterAction with the given name from the list * of actions applied to @self * * Since: 1.4 */ void clutter_actor_remove_action_by_name (ClutterActor *self, const gchar *name) { ClutterActorPrivate *priv; ClutterActorMeta *meta; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); priv = self->priv; if (priv->actions == NULL) return; meta = _clutter_meta_group_get_meta (priv->actions, name); if (meta == NULL) return; _clutter_meta_group_remove_meta (priv->actions, meta); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]); } /** * clutter_actor_get_actions: * @self: a #ClutterActor * * Retrieves the list of actions applied to @self * * Return value: (transfer container) (element-type Clutter.Action): a copy * of the list of #ClutterActions. The contents of the list are * owned by the #ClutterActor. Use g_list_free() to free the resources * allocated by the returned #GList * * Since: 1.4 */ GList * clutter_actor_get_actions (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); if (self->priv->actions == NULL) return NULL; return _clutter_meta_group_get_metas_no_internal (self->priv->actions); } /** * clutter_actor_get_action: * @self: a #ClutterActor * @name: the name of the action to retrieve * * Retrieves the #ClutterAction with the given name in the list * of actions applied to @self * * Return value: (transfer none): a #ClutterAction for the given * name, or %NULL. The returned #ClutterAction is owned by the * actor and it should not be unreferenced directly * * Since: 1.4 */ ClutterAction * clutter_actor_get_action (ClutterActor *self, const gchar *name) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); g_return_val_if_fail (name != NULL, NULL); if (self->priv->actions == NULL) return NULL; return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name)); } /** * clutter_actor_clear_actions: * @self: a #ClutterActor * * Clears the list of actions applied to @self * * Since: 1.4 */ void clutter_actor_clear_actions (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->actions == NULL) return; _clutter_meta_group_clear_metas_no_internal (self->priv->actions); } /** * clutter_actor_add_constraint: * @self: a #ClutterActor * @constraint: a #ClutterConstraint * * Adds @constraint to the list of #ClutterConstraints applied * to @self * * The #ClutterActor will hold a reference on the @constraint until * either clutter_actor_remove_constraint() or * clutter_actor_clear_constraints() is called. * * Since: 1.4 */ void clutter_actor_add_constraint (ClutterActor *self, ClutterConstraint *constraint) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint)); priv = self->priv; if (priv->constraints == NULL) { priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL); priv->constraints->actor = self; } _clutter_meta_group_add_meta (priv->constraints, CLUTTER_ACTOR_META (constraint)); clutter_actor_queue_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]); } /** * clutter_actor_add_constraint_with_name: * @self: a #ClutterActor * @name: the name to set on the constraint * @constraint: a #ClutterConstraint * * A convenience function for setting the name of a #ClutterConstraint * while adding it to the list of constraints applied to @self * * This function is the logical equivalent of: * * |[ * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name); * clutter_actor_add_constraint (self, constraint); * ]| * * Since: 1.4 */ void clutter_actor_add_constraint_with_name (ClutterActor *self, const gchar *name, ClutterConstraint *constraint) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint)); clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name); clutter_actor_add_constraint (self, constraint); } /** * clutter_actor_remove_constraint: * @self: a #ClutterActor * @constraint: a #ClutterConstraint * * Removes @constraint from the list of constraints applied to @self * * The reference held by @self on the #ClutterConstraint will be released * * Since: 1.4 */ void clutter_actor_remove_constraint (ClutterActor *self, ClutterConstraint *constraint) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint)); priv = self->priv; if (priv->constraints == NULL) return; _clutter_meta_group_remove_meta (priv->constraints, CLUTTER_ACTOR_META (constraint)); if (_clutter_meta_group_peek_metas (priv->constraints) == NULL) g_clear_object (&priv->constraints); clutter_actor_queue_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]); } /** * clutter_actor_remove_constraint_by_name: * @self: a #ClutterActor * @name: the name of the constraint to remove * * Removes the #ClutterConstraint with the given name from the list * of constraints applied to @self * * Since: 1.4 */ void clutter_actor_remove_constraint_by_name (ClutterActor *self, const gchar *name) { ClutterActorPrivate *priv; ClutterActorMeta *meta; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); priv = self->priv; if (priv->constraints == NULL) return; meta = _clutter_meta_group_get_meta (priv->constraints, name); if (meta == NULL) return; _clutter_meta_group_remove_meta (priv->constraints, meta); clutter_actor_queue_relayout (self); } /** * clutter_actor_get_constraints: * @self: a #ClutterActor * * Retrieves the list of constraints applied to @self * * Return value: (transfer container) (element-type Clutter.Constraint): a copy * of the list of #ClutterConstraints. The contents of the list are * owned by the #ClutterActor. Use g_list_free() to free the resources * allocated by the returned #GList * * Since: 1.4 */ GList * clutter_actor_get_constraints (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); if (self->priv->constraints == NULL) return NULL; return _clutter_meta_group_get_metas_no_internal (self->priv->constraints); } /** * clutter_actor_get_constraint: * @self: a #ClutterActor * @name: the name of the constraint to retrieve * * Retrieves the #ClutterConstraint with the given name in the list * of constraints applied to @self * * Return value: (transfer none): a #ClutterConstraint for the given * name, or %NULL. The returned #ClutterConstraint is owned by the * actor and it should not be unreferenced directly * * Since: 1.4 */ ClutterConstraint * clutter_actor_get_constraint (ClutterActor *self, const gchar *name) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); g_return_val_if_fail (name != NULL, NULL); if (self->priv->constraints == NULL) return NULL; return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name)); } /** * clutter_actor_clear_constraints: * @self: a #ClutterActor * * Clears the list of constraints applied to @self * * Since: 1.4 */ void clutter_actor_clear_constraints (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->constraints == NULL) return; _clutter_meta_group_clear_metas_no_internal (self->priv->constraints); clutter_actor_queue_relayout (self); } /** * clutter_actor_set_clip_to_allocation: * @self: a #ClutterActor * @clip_set: %TRUE to apply a clip tracking the allocation * * Sets whether @self should be clipped to the same size as its * allocation * * Since: 1.4 */ void clutter_actor_set_clip_to_allocation (ClutterActor *self, gboolean clip_set) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); clip_set = !!clip_set; priv = self->priv; if (priv->clip_to_allocation != clip_set) { priv->clip_to_allocation = clip_set; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]); } } /** * clutter_actor_get_clip_to_allocation: * @self: a #ClutterActor * * Retrieves the value set using clutter_actor_set_clip_to_allocation() * * Return value: %TRUE if the #ClutterActor is clipped to its allocation * * Since: 1.4 */ gboolean clutter_actor_get_clip_to_allocation (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return self->priv->clip_to_allocation; } /** * clutter_actor_add_effect: * @self: a #ClutterActor * @effect: a #ClutterEffect * * Adds @effect to the list of #ClutterEffects applied to @self * * The #ClutterActor will hold a reference on the @effect until either * clutter_actor_remove_effect() or clutter_actor_clear_effects() is * called. * * Since: 1.4 */ void clutter_actor_add_effect (ClutterActor *self, ClutterEffect *effect) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_EFFECT (effect)); _clutter_actor_add_effect_internal (self, effect); clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]); } /** * clutter_actor_add_effect_with_name: * @self: a #ClutterActor * @name: the name to set on the effect * @effect: a #ClutterEffect * * A convenience function for setting the name of a #ClutterEffect * while adding it to the list of effectss applied to @self * * This function is the logical equivalent of: * * |[ * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name); * clutter_actor_add_effect (self, effect); * ]| * * Since: 1.4 */ void clutter_actor_add_effect_with_name (ClutterActor *self, const gchar *name, ClutterEffect *effect) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); g_return_if_fail (CLUTTER_IS_EFFECT (effect)); clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name); clutter_actor_add_effect (self, effect); } /** * clutter_actor_remove_effect: * @self: a #ClutterActor * @effect: a #ClutterEffect * * Removes @effect from the list of effects applied to @self * * The reference held by @self on the #ClutterEffect will be released * * Since: 1.4 */ void clutter_actor_remove_effect (ClutterActor *self, ClutterEffect *effect) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_EFFECT (effect)); _clutter_actor_remove_effect_internal (self, effect); clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]); } /** * clutter_actor_remove_effect_by_name: * @self: a #ClutterActor * @name: the name of the effect to remove * * Removes the #ClutterEffect with the given name from the list * of effects applied to @self * * Since: 1.4 */ void clutter_actor_remove_effect_by_name (ClutterActor *self, const gchar *name) { ClutterActorPrivate *priv; ClutterActorMeta *meta; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); priv = self->priv; if (priv->effects == NULL) return; meta = _clutter_meta_group_get_meta (priv->effects, name); if (meta == NULL) return; clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta)); } /** * clutter_actor_get_effects: * @self: a #ClutterActor * * Retrieves the #ClutterEffects applied on @self, if any * * Return value: (transfer container) (element-type Clutter.Effect): a list * of #ClutterEffects, or %NULL. The elements of the returned * list are owned by Clutter and they should not be freed. You should * free the returned list using g_list_free() when done * * Since: 1.4 */ GList * clutter_actor_get_effects (ClutterActor *self) { ClutterActorPrivate *priv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); priv = self->priv; if (priv->effects == NULL) return NULL; return _clutter_meta_group_get_metas_no_internal (priv->effects); } /** * clutter_actor_get_effect: * @self: a #ClutterActor * @name: the name of the effect to retrieve * * Retrieves the #ClutterEffect with the given name in the list * of effects applied to @self * * Return value: (transfer none): a #ClutterEffect for the given * name, or %NULL. The returned #ClutterEffect is owned by the * actor and it should not be unreferenced directly * * Since: 1.4 */ ClutterEffect * clutter_actor_get_effect (ClutterActor *self, const gchar *name) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); g_return_val_if_fail (name != NULL, NULL); if (self->priv->effects == NULL) return NULL; return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name)); } /** * clutter_actor_clear_effects: * @self: a #ClutterActor * * Clears the list of effects applied to @self * * Since: 1.4 */ void clutter_actor_clear_effects (ClutterActor *self) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->effects == NULL) return; _clutter_meta_group_clear_metas_no_internal (self->priv->effects); clutter_actor_queue_redraw (self); } /** * clutter_actor_has_key_focus: * @self: a #ClutterActor * * Checks whether @self is the #ClutterActor that has key focus * * Return value: %TRUE if the actor has key focus, and %FALSE otherwise * * Since: 1.4 */ gboolean clutter_actor_has_key_focus (ClutterActor *self) { ClutterActor *stage; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); stage = _clutter_actor_get_stage_internal (self); if (stage == NULL) return FALSE; return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self; } static gboolean _clutter_actor_get_paint_volume_real (ClutterActor *self, ClutterPaintVolume *pv) { ClutterActorPrivate *priv = self->priv; /* Actors are only expected to report a valid paint volume * while they have a valid allocation. */ if (G_UNLIKELY (priv->needs_allocation)) { CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): " "Actor needs allocation", _clutter_actor_get_debug_name (self)); return FALSE; } /* Check if there are any handlers connected to the paint * signal. If there are then all bets are off for what the paint * volume for this actor might possibly be! * * XXX: It's expected that this is going to end up being quite a * costly check to have to do here, but we haven't come up with * another solution that can reliably catch paint signal handlers at * the right time to either avoid artefacts due to invalid stage * clipping or due to incorrect culling. * * Previously we checked in clutter_actor_paint(), but at that time * we may already be using a stage clip that could be derived from * an invalid paint-volume. We used to try and handle that by * queuing a follow up, unclipped, redraw but still the previous * checking wasn't enough to catch invalid volumes involved in * culling (considering that containers may derive their volume from * children that haven't yet been painted) * * Longer term, improved solutions could be: * - Disallow painting in the paint signal, only allow using it * for tracking when paints happen. We can add another API that * allows monkey patching the paint of arbitrary actors but in a * more controlled way and that also supports modifying the * paint-volume. * - If we could be notified somehow when signal handlers are * connected we wouldn't have to poll for handlers like this. * * XXX:2.0 - Remove when we remove the paint signal */ if (g_signal_has_handler_pending (self, actor_signals[PAINT], 0, TRUE)) { CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): " "Actor has \"paint\" signal handlers", _clutter_actor_get_debug_name (self)); return FALSE; } _clutter_paint_volume_init_static (pv, self); if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv)) { clutter_paint_volume_free (pv); CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): " "Actor failed to report a volume", _clutter_actor_get_debug_name (self)); return FALSE; } /* since effects can modify the paint volume, we allow them to actually * do this by making get_paint_volume() "context sensitive" */ if (priv->effects != NULL) { if (priv->current_effect != NULL) { const GList *effects, *l; /* if we are being called from within the paint sequence of * an actor, get the paint volume up to the current effect */ effects = _clutter_meta_group_peek_metas (priv->effects); for (l = effects; l != NULL || (l != NULL && l->data != priv->current_effect); l = l->next) { if (!_clutter_effect_get_paint_volume (l->data, pv)) { clutter_paint_volume_free (pv); CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): " "Effect (%s) failed to report a volume", _clutter_actor_get_debug_name (self), _clutter_actor_meta_get_debug_name (l->data)); return FALSE; } } } else { const GList *effects, *l; /* otherwise, get the cumulative volume */ effects = _clutter_meta_group_peek_metas (priv->effects); for (l = effects; l != NULL; l = l->next) if (!_clutter_effect_get_paint_volume (l->data, pv)) { clutter_paint_volume_free (pv); CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): " "Effect (%s) failed to report a volume", _clutter_actor_get_debug_name (self), _clutter_actor_meta_get_debug_name (l->data)); return FALSE; } } } return TRUE; } /* The public clutter_actor_get_paint_volume API returns a const * pointer since we return a pointer directly to the cached * PaintVolume associated with the actor and don't want the user to * inadvertently modify it, but for internal uses we sometimes need * access to the same PaintVolume but need to apply some book-keeping * modifications to it so we don't want a const pointer. */ static ClutterPaintVolume * _clutter_actor_get_paint_volume_mutable (ClutterActor *self) { ClutterActorPrivate *priv; priv = self->priv; if (priv->paint_volume_valid) { if (!priv->needs_paint_volume_update) return &priv->paint_volume; clutter_paint_volume_free (&priv->paint_volume); } if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume)) { priv->paint_volume_valid = TRUE; priv->needs_paint_volume_update = FALSE; return &priv->paint_volume; } else { priv->paint_volume_valid = FALSE; return NULL; } } /** * clutter_actor_get_paint_volume: * @self: a #ClutterActor * * Retrieves the paint volume of the passed #ClutterActor, or %NULL * when a paint volume can't be determined. * * The paint volume is defined as the 3D space occupied by an actor * when being painted. * * This function will call the #ClutterActorClass.get_paint_volume() * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor * should not usually care about overriding the default implementation, * unless they are, for instance: painting outside their allocation, or * actors with a depth factor (not in terms of #ClutterActor:depth but real * 3D depth). * * Note: 2D actors overriding #ClutterActorClass.get_paint_volume() * should ensure that their volume has a depth of 0. (This will be true * as long as you don't call clutter_paint_volume_set_depth().) * * Return value: (transfer none): a pointer to a #ClutterPaintVolume, * or %NULL if no volume could be determined. The returned pointer * is not guaranteed to be valid across multiple frames; if you want * to keep it, you will need to copy it using clutter_paint_volume_copy(). * * Since: 1.6 */ const ClutterPaintVolume * clutter_actor_get_paint_volume (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return _clutter_actor_get_paint_volume_mutable (self); } /** * clutter_actor_get_transformed_paint_volume: * @self: a #ClutterActor * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self * (or %NULL for the stage) * * Retrieves the 3D paint volume of an actor like * clutter_actor_get_paint_volume() does (Please refer to the * documentation of clutter_actor_get_paint_volume() for more * details.) and it additionally transforms the paint volume into the * coordinate space of @relative_to_ancestor. (Or the stage if %NULL * is passed for @relative_to_ancestor) * * This can be used by containers that base their paint volume on * the volume of their children. Such containers can query the * transformed paint volume of all of its children and union them * together using clutter_paint_volume_union(). * * Return value: (transfer none): a pointer to a #ClutterPaintVolume, * or %NULL if no volume could be determined. The returned pointer is * not guaranteed to be valid across multiple frames; if you wish to * keep it, you will have to copy it using clutter_paint_volume_copy(). * * Since: 1.6 */ const ClutterPaintVolume * clutter_actor_get_transformed_paint_volume (ClutterActor *self, ClutterActor *relative_to_ancestor) { const ClutterPaintVolume *volume; ClutterActor *stage; ClutterPaintVolume *transformed_volume; stage = _clutter_actor_get_stage_internal (self); if (G_UNLIKELY (stage == NULL)) return NULL; if (relative_to_ancestor == NULL) relative_to_ancestor = stage; volume = clutter_actor_get_paint_volume (self); if (volume == NULL) return NULL; transformed_volume = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage)); _clutter_paint_volume_copy_static (volume, transformed_volume); _clutter_paint_volume_transform_relative (transformed_volume, relative_to_ancestor); return transformed_volume; } /** * clutter_actor_get_paint_box: * @self: a #ClutterActor * @box: (out): return location for a #ClutterActorBox * * Retrieves the paint volume of the passed #ClutterActor, and * transforms it into a 2D bounding box in stage coordinates. * * This function is useful to determine the on screen area occupied by * the actor. The box is only an approximation and may often be * considerably larger due to the optimizations used to calculate the * box. The box is never smaller though, so it can reliably be used * for culling. * * There are times when a 2D paint box can't be determined, e.g. * because the actor isn't yet parented under a stage or because * the actor is unable to determine a paint volume. * * Return value: %TRUE if a 2D paint box could be determined, else * %FALSE. * * Since: 1.6 */ gboolean clutter_actor_get_paint_box (ClutterActor *self, ClutterActorBox *box) { ClutterActor *stage; ClutterPaintVolume *pv; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); g_return_val_if_fail (box != NULL, FALSE); stage = _clutter_actor_get_stage_internal (self); if (G_UNLIKELY (!stage)) return FALSE; pv = _clutter_actor_get_paint_volume_mutable (self); if (G_UNLIKELY (!pv)) return FALSE; _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box); return TRUE; } /** * clutter_actor_has_overlaps: * @self: A #ClutterActor * * Asks the actor's implementation whether it may contain overlapping * primitives. * * For example; Clutter may use this to determine whether the painting * should be redirected to an offscreen buffer to correctly implement * the opacity property. * * Custom actors can override the default response by implementing the * #ClutterActorClass.has_overlaps() virtual function. See * clutter_actor_set_offscreen_redirect() for more information. * * Return value: %TRUE if the actor may have overlapping primitives, and * %FALSE otherwise * * Since: 1.8 */ gboolean clutter_actor_has_overlaps (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE); return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self); } /** * clutter_actor_has_effects: * @self: A #ClutterActor * * Returns whether the actor has any effects applied. * * Return value: %TRUE if the actor has any effects, * %FALSE otherwise * * Since: 1.10 */ gboolean clutter_actor_has_effects (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); if (self->priv->effects == NULL) return FALSE; return _clutter_meta_group_has_metas_no_internal (self->priv->effects); } /** * clutter_actor_has_constraints: * @self: A #ClutterActor * * Returns whether the actor has any constraints applied. * * Return value: %TRUE if the actor has any constraints, * %FALSE otherwise * * Since: 1.10 */ gboolean clutter_actor_has_constraints (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); if (self->priv->constraints == NULL) return FALSE; return _clutter_meta_group_has_metas_no_internal (self->priv->constraints); } /** * clutter_actor_has_actions: * @self: A #ClutterActor * * Returns whether the actor has any actions applied. * * Return value: %TRUE if the actor has any actions, * %FALSE otherwise * * Since: 1.10 */ gboolean clutter_actor_has_actions (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); if (self->priv->actions == NULL) return FALSE; return _clutter_meta_group_has_metas_no_internal (self->priv->actions); } /** * clutter_actor_get_n_children: * @self: a #ClutterActor * * Retrieves the number of children of @self. * * Return value: the number of children of an actor * * Since: 1.10 */ gint clutter_actor_get_n_children (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); return self->priv->n_children; } /** * clutter_actor_get_child_at_index: * @self: a #ClutterActor * @index_: the position in the list of children * * Retrieves the actor at the given @index_ inside the list of * children of @self. * * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL * * Since: 1.10 */ ClutterActor * clutter_actor_get_child_at_index (ClutterActor *self, gint index_) { ClutterActor *iter; int i; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); g_return_val_if_fail (index_ <= self->priv->n_children, NULL); for (iter = self->priv->first_child, i = 0; iter != NULL && i < index_; iter = iter->priv->next_sibling, i += 1) ; return iter; } /*< private > * _clutter_actor_foreach_child: * @actor: The actor whos children you want to iterate * @callback: The function to call for each child * @user_data: Private data to pass to @callback * * Calls a given @callback once for each child of the specified @actor and * passing the @user_data pointer each time. * * Return value: returns %TRUE if all children were iterated, else * %FALSE if a callback broke out of iteration early. */ gboolean _clutter_actor_foreach_child (ClutterActor *self, ClutterForeachCallback callback, gpointer user_data) { ClutterActor *iter; gboolean cont; if (self->priv->first_child == NULL) return TRUE; cont = TRUE; iter = self->priv->first_child; /* we use this form so that it's safe to change the children * list while iterating it */ while (cont && iter != NULL) { ClutterActor *next = iter->priv->next_sibling; cont = callback (iter, user_data); iter = next; } return cont; } #if 0 /* For debugging purposes this gives us a simple way to print out * the scenegraph e.g in gdb using: * [| * _clutter_actor_traverse (stage, * 0, * clutter_debug_print_actor_cb, * NULL, * NULL); * |] */ static ClutterActorTraverseVisitFlags clutter_debug_print_actor_cb (ClutterActor *actor, int depth, void *user_data) { g_print ("%*s%s:%p\n", depth * 2, "", _clutter_actor_get_debug_name (actor), actor); return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE; } #endif static void _clutter_actor_traverse_breadth (ClutterActor *actor, ClutterTraverseCallback callback, gpointer user_data) { GQueue *queue = g_queue_new (); ClutterActor dummy; int current_depth = 0; g_queue_push_tail (queue, actor); g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */ while ((actor = g_queue_pop_head (queue))) { ClutterActorTraverseVisitFlags flags; if (actor == &dummy) { current_depth++; g_queue_push_tail (queue, &dummy); continue; } flags = callback (actor, current_depth, user_data); if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK) break; else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN)) { ClutterActor *iter; for (iter = actor->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) { g_queue_push_tail (queue, iter); } } } g_queue_free (queue); } static ClutterActorTraverseVisitFlags _clutter_actor_traverse_depth (ClutterActor *actor, ClutterTraverseCallback before_children_callback, ClutterTraverseCallback after_children_callback, int current_depth, gpointer user_data) { ClutterActorTraverseVisitFlags flags; flags = before_children_callback (actor, current_depth, user_data); if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK) return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK; if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN)) { ClutterActor *iter; for (iter = actor->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) { flags = _clutter_actor_traverse_depth (iter, before_children_callback, after_children_callback, current_depth + 1, user_data); if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK) return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK; } } if (after_children_callback) return after_children_callback (actor, current_depth, user_data); else return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE; } /* _clutter_actor_traverse: * @actor: The actor to start traversing the graph from * @flags: These flags may affect how the traversal is done * @before_children_callback: A function to call before visiting the * children of the current actor. * @after_children_callback: A function to call after visiting the * children of the current actor. (Ignored if * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.) * @user_data: The private data to pass to the callbacks * * Traverses the scenegraph starting at the specified @actor and * descending through all its children and its children's children. * For each actor traversed @before_children_callback and * @after_children_callback are called with the specified * @user_data, before and after visiting that actor's children. * * The callbacks can return flags that affect the ongoing traversal * such as by skipping over an actors children or bailing out of * any further traversing. */ void _clutter_actor_traverse (ClutterActor *actor, ClutterActorTraverseFlags flags, ClutterTraverseCallback before_children_callback, ClutterTraverseCallback after_children_callback, gpointer user_data) { if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST) _clutter_actor_traverse_breadth (actor, before_children_callback, user_data); else /* DEPTH_FIRST */ _clutter_actor_traverse_depth (actor, before_children_callback, after_children_callback, 0, /* start depth */ user_data); } static void on_layout_manager_changed (ClutterLayoutManager *manager, ClutterActor *self) { clutter_actor_queue_relayout (self); } /** * clutter_actor_set_layout_manager: * @self: a #ClutterActor * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it * * Sets the #ClutterLayoutManager delegate object that will be used to * lay out the children of @self. * * The #ClutterActor will take a reference on the passed @manager which * will be released either when the layout manager is removed, or when * the actor is destroyed. * * Since: 1.10 */ void clutter_actor_set_layout_manager (ClutterActor *self, ClutterLayoutManager *manager) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager)); priv = self->priv; if (priv->layout_manager != NULL) { g_signal_handlers_disconnect_by_func (priv->layout_manager, G_CALLBACK (on_layout_manager_changed), self); clutter_layout_manager_set_container (priv->layout_manager, NULL); g_clear_object (&priv->layout_manager); } priv->layout_manager = manager; if (priv->layout_manager != NULL) { g_object_ref_sink (priv->layout_manager); clutter_layout_manager_set_container (priv->layout_manager, CLUTTER_CONTAINER (self)); g_signal_connect (priv->layout_manager, "layout-changed", G_CALLBACK (on_layout_manager_changed), self); } clutter_actor_queue_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]); } /** * clutter_actor_get_layout_manager: * @self: a #ClutterActor * * Retrieves the #ClutterLayoutManager used by @self. * * Return value: (transfer none): a pointer to the #ClutterLayoutManager, * or %NULL * * Since: 1.10 */ ClutterLayoutManager * clutter_actor_get_layout_manager (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->layout_manager; } static const ClutterLayoutInfo default_layout_info = { CLUTTER_POINT_INIT_ZERO, /* fixed-pos */ { 0, 0, 0, 0 }, /* margin */ CLUTTER_ACTOR_ALIGN_FILL, /* x-align */ CLUTTER_ACTOR_ALIGN_FILL, /* y-align */ FALSE, FALSE, /* expand */ CLUTTER_SIZE_INIT_ZERO, /* minimum */ CLUTTER_SIZE_INIT_ZERO, /* natural */ }; static void layout_info_free (gpointer data) { if (G_LIKELY (data != NULL)) g_slice_free (ClutterLayoutInfo, data); } /*< private > * _clutter_actor_peek_layout_info: * @self: a #ClutterActor * * Retrieves a pointer to the ClutterLayoutInfo structure. * * If the actor does not have a ClutterLayoutInfo associated to it, %NULL is returned. * * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure */ ClutterLayoutInfo * _clutter_actor_peek_layout_info (ClutterActor *self) { return g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info); } /*< private > * _clutter_actor_get_layout_info: * @self: a #ClutterActor * * Retrieves a pointer to the ClutterLayoutInfo structure. * * If the actor does not have a ClutterLayoutInfo associated to it, one * will be created and initialized to the default values. * * This function should be used for setters. * * For getters, you should use _clutter_actor_get_layout_info_or_defaults() * instead. * * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure */ ClutterLayoutInfo * _clutter_actor_get_layout_info (ClutterActor *self) { ClutterLayoutInfo *retval; retval = _clutter_actor_peek_layout_info (self); if (retval == NULL) { retval = g_slice_new (ClutterLayoutInfo); *retval = default_layout_info; g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info, retval, layout_info_free); } return retval; } /*< private > * _clutter_actor_get_layout_info_or_defaults: * @self: a #ClutterActor * * Retrieves the ClutterLayoutInfo structure associated to an actor. * * If the actor does not have a ClutterLayoutInfo structure associated to it, * then the default structure will be returned. * * This function should only be used for getters. * * Return value: a const pointer to the ClutterLayoutInfo structure */ const ClutterLayoutInfo * _clutter_actor_get_layout_info_or_defaults (ClutterActor *self) { const ClutterLayoutInfo *info; info = _clutter_actor_peek_layout_info (self); if (info == NULL) return &default_layout_info; return info; } /** * clutter_actor_set_x_align: * @self: a #ClutterActor * @x_align: the horizontal alignment policy * * Sets the horizontal alignment policy of a #ClutterActor, in case the * actor received extra horizontal space. * * See also the #ClutterActor:x-align property. * * Since: 1.10 */ void clutter_actor_set_x_align (ClutterActor *self, ClutterActorAlign x_align) { ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_layout_info (self); if (info->x_align != x_align) { info->x_align = x_align; clutter_actor_queue_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]); } } /** * clutter_actor_get_x_align: * @self: a #ClutterActor * * Retrieves the horizontal alignment policy set using * clutter_actor_set_x_align(). * * Return value: the horizontal alignment policy. * * Since: 1.10 */ ClutterActorAlign clutter_actor_get_x_align (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL); return _clutter_actor_get_layout_info_or_defaults (self)->x_align; } /** * clutter_actor_set_y_align: * @self: a #ClutterActor * @y_align: the vertical alignment policy * * Sets the vertical alignment policy of a #ClutterActor, in case the * actor received extra vertical space. * * See also the #ClutterActor:y-align property. * * Since: 1.10 */ void clutter_actor_set_y_align (ClutterActor *self, ClutterActorAlign y_align) { ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_layout_info (self); if (info->y_align != y_align) { info->y_align = y_align; clutter_actor_queue_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]); } } /** * clutter_actor_get_y_align: * @self: a #ClutterActor * * Retrieves the vertical alignment policy set using * clutter_actor_set_y_align(). * * Return value: the vertical alignment policy. * * Since: 1.10 */ ClutterActorAlign clutter_actor_get_y_align (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL); return _clutter_actor_get_layout_info_or_defaults (self)->y_align; } static inline void clutter_actor_set_margin_internal (ClutterActor *self, gfloat margin, GParamSpec *pspec) { ClutterLayoutInfo *info; info = _clutter_actor_get_layout_info (self); if (pspec == obj_props[PROP_MARGIN_TOP]) info->margin.top = margin; else if (pspec == obj_props[PROP_MARGIN_RIGHT]) info->margin.right = margin; else if (pspec == obj_props[PROP_MARGIN_BOTTOM]) info->margin.bottom = margin; else info->margin.left = margin; clutter_actor_queue_relayout (self); g_object_notify_by_pspec (G_OBJECT (self), pspec); } /** * clutter_actor_set_margin: * @self: a #ClutterActor * @margin: a #ClutterMargin * * Sets all the components of the margin of a #ClutterActor. * * Since: 1.10 */ void clutter_actor_set_margin (ClutterActor *self, const ClutterMargin *margin) { ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (margin != NULL); info = _clutter_actor_get_layout_info (self); if (info->margin.top != margin->top) clutter_actor_set_margin_top (self, margin->top); if (info->margin.right != margin->right) clutter_actor_set_margin_right (self, margin->right); if (info->margin.bottom != margin->bottom) clutter_actor_set_margin_bottom (self, margin->bottom); if (info->margin.left != margin->left) clutter_actor_set_margin_left (self, margin->left); } /** * clutter_actor_get_margin: * @self: a #ClutterActor * @margin: (out caller-allocates): return location for a #ClutterMargin * * Retrieves all the components of the margin of a #ClutterActor. * * Since: 1.10 */ void clutter_actor_get_margin (ClutterActor *self, ClutterMargin *margin) { const ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (margin != NULL); info = _clutter_actor_get_layout_info_or_defaults (self); *margin = info->margin; } /** * clutter_actor_set_margin_top: * @self: a #ClutterActor * @margin: the top margin * * Sets the margin from the top of a #ClutterActor. * * The #ClutterActor:margin-top property is animatable. * * Since: 1.10 */ void clutter_actor_set_margin_top (ClutterActor *self, gfloat margin) { const ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (margin >= 0.f); info = _clutter_actor_get_layout_info_or_defaults (self); if (info->margin.top == margin) return; _clutter_actor_create_transition (self, obj_props[PROP_MARGIN_TOP], info->margin.top, margin); } /** * clutter_actor_get_margin_top: * @self: a #ClutterActor * * Retrieves the top margin of a #ClutterActor. * * Return value: the top margin * * Since: 1.10 */ gfloat clutter_actor_get_margin_top (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f); return _clutter_actor_get_layout_info_or_defaults (self)->margin.top; } /** * clutter_actor_set_margin_bottom: * @self: a #ClutterActor * @margin: the bottom margin * * Sets the margin from the bottom of a #ClutterActor. * * The #ClutterActor:margin-bottom property is animatable. * * Since: 1.10 */ void clutter_actor_set_margin_bottom (ClutterActor *self, gfloat margin) { const ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (margin >= 0.f); info = _clutter_actor_get_layout_info_or_defaults (self); if (info->margin.bottom == margin) return; _clutter_actor_create_transition (self, obj_props[PROP_MARGIN_BOTTOM], info->margin.bottom, margin); } /** * clutter_actor_get_margin_bottom: * @self: a #ClutterActor * * Retrieves the bottom margin of a #ClutterActor. * * Return value: the bottom margin * * Since: 1.10 */ gfloat clutter_actor_get_margin_bottom (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f); return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom; } /** * clutter_actor_set_margin_left: * @self: a #ClutterActor * @margin: the left margin * * Sets the margin from the left of a #ClutterActor. * * The #ClutterActor:margin-left property is animatable. * * Since: 1.10 */ void clutter_actor_set_margin_left (ClutterActor *self, gfloat margin) { const ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (margin >= 0.f); info = _clutter_actor_get_layout_info_or_defaults (self); if (info->margin.left == margin) return; _clutter_actor_create_transition (self, obj_props[PROP_MARGIN_LEFT], info->margin.left, margin); } /** * clutter_actor_get_margin_left: * @self: a #ClutterActor * * Retrieves the left margin of a #ClutterActor. * * Return value: the left margin * * Since: 1.10 */ gfloat clutter_actor_get_margin_left (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f); return _clutter_actor_get_layout_info_or_defaults (self)->margin.left; } /** * clutter_actor_set_margin_right: * @self: a #ClutterActor * @margin: the right margin * * Sets the margin from the right of a #ClutterActor. * * The #ClutterActor:margin-right property is animatable. * * Since: 1.10 */ void clutter_actor_set_margin_right (ClutterActor *self, gfloat margin) { const ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (margin >= 0.f); info = _clutter_actor_get_layout_info_or_defaults (self); if (info->margin.right == margin) return; _clutter_actor_create_transition (self, obj_props[PROP_MARGIN_RIGHT], info->margin.right, margin); } /** * clutter_actor_get_margin_right: * @self: a #ClutterActor * * Retrieves the right margin of a #ClutterActor. * * Return value: the right margin * * Since: 1.10 */ gfloat clutter_actor_get_margin_right (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f); return _clutter_actor_get_layout_info_or_defaults (self)->margin.right; } static inline void clutter_actor_set_background_color_internal (ClutterActor *self, const ClutterColor *color) { ClutterActorPrivate *priv = self->priv; GObject *obj; if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color)) return; obj = G_OBJECT (self); priv->bg_color = *color; priv->bg_color_set = TRUE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]); g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]); } /** * clutter_actor_set_background_color: * @self: a #ClutterActor * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously * set color * * Sets the background color of a #ClutterActor. * * The background color will be used to cover the whole allocation of the * actor. The default background color of an actor is transparent. * * To check whether an actor has a background color, you can use the * #ClutterActor:background-color-set actor property. * * The #ClutterActor:background-color property is animatable. * * Since: 1.10 */ void clutter_actor_set_background_color (ClutterActor *self, const ClutterColor *color) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (color == NULL) { GObject *obj = G_OBJECT (self); priv->bg_color_set = FALSE; clutter_actor_queue_redraw (self); g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]); } else _clutter_actor_create_transition (self, obj_props[PROP_BACKGROUND_COLOR], &priv->bg_color, color); } /** * clutter_actor_get_background_color: * @self: a #ClutterActor * @color: (out caller-allocates): return location for a #ClutterColor * * Retrieves the color set using clutter_actor_set_background_color(). * * Since: 1.10 */ void clutter_actor_get_background_color (ClutterActor *self, ClutterColor *color) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (color != NULL); *color = self->priv->bg_color; } /** * clutter_actor_get_previous_sibling: * @self: a #ClutterActor * * Retrieves the sibling of @self that comes before it in the list * of children of @self's parent. * * The returned pointer is only valid until the scene graph changes; it * is not safe to modify the list of children of @self while iterating * it. * * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL * * Since: 1.10 */ ClutterActor * clutter_actor_get_previous_sibling (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->prev_sibling; } /** * clutter_actor_get_next_sibling: * @self: a #ClutterActor * * Retrieves the sibling of @self that comes after it in the list * of children of @self's parent. * * The returned pointer is only valid until the scene graph changes; it * is not safe to modify the list of children of @self while iterating * it. * * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL * * Since: 1.10 */ ClutterActor * clutter_actor_get_next_sibling (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->next_sibling; } /** * clutter_actor_get_first_child: * @self: a #ClutterActor * * Retrieves the first child of @self. * * The returned pointer is only valid until the scene graph changes; it * is not safe to modify the list of children of @self while iterating * it. * * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL * * Since: 1.10 */ ClutterActor * clutter_actor_get_first_child (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->first_child; } /** * clutter_actor_get_last_child: * @self: a #ClutterActor * * Retrieves the last child of @self. * * The returned pointer is only valid until the scene graph changes; it * is not safe to modify the list of children of @self while iterating * it. * * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL * * Since: 1.10 */ ClutterActor * clutter_actor_get_last_child (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->last_child; } /* easy way to have properly named fields instead of the dummy ones * we use in the public structure */ typedef struct _RealActorIter { ClutterActor *root; /* dummy1 */ ClutterActor *current; /* dummy2 */ gpointer padding_1; /* dummy3 */ gint age; /* dummy4 */ gpointer padding_2; /* dummy5 */ } RealActorIter; /** * clutter_actor_iter_init: * @iter: a #ClutterActorIter * @root: a #ClutterActor * * Initializes a #ClutterActorIter, which can then be used to iterate * efficiently over a section of the scene graph, and associates it * with @root. * * Modifying the scene graph section that contains @root will invalidate * the iterator. * * |[ * ClutterActorIter iter; * ClutterActor *child; * * clutter_actor_iter_init (&iter, container); * while (clutter_actor_iter_next (&iter, &child)) * { * // do something with child * } * ]| * * Since: 1.10 */ void clutter_actor_iter_init (ClutterActorIter *iter, ClutterActor *root) { RealActorIter *ri = (RealActorIter *) iter; g_return_if_fail (iter != NULL); g_return_if_fail (CLUTTER_IS_ACTOR (root)); ri->root = root; ri->current = NULL; ri->age = root->priv->age; } /** * clutter_actor_iter_is_valid: * @iter: a #ClutterActorIter * * Checks whether a #ClutterActorIter is still valid. * * An iterator is considered valid if it has been initialized, and * if the #ClutterActor that it refers to hasn't been modified after * the initialization. * * Return value: %TRUE if the iterator is valid, and %FALSE otherwise * * Since: 1.12 */ gboolean clutter_actor_iter_is_valid (const ClutterActorIter *iter) { RealActorIter *ri = (RealActorIter *) iter; g_return_val_if_fail (iter != NULL, FALSE); if (ri->root == NULL) return FALSE; return ri->root->priv->age == ri->age; } /** * clutter_actor_iter_next: * @iter: a #ClutterActorIter * @child: (out) (transfer none): return location for a #ClutterActor * * Advances the @iter and retrieves the next child of the root #ClutterActor * that was used to initialize the #ClutterActorIterator. * * If the iterator can advance, this function returns %TRUE and sets the * @child argument. * * If the iterator cannot advance, this function returns %FALSE, and * the contents of @child are undefined. * * Return value: %TRUE if the iterator could advance, and %FALSE otherwise. * * Since: 1.10 */ gboolean clutter_actor_iter_next (ClutterActorIter *iter, ClutterActor **child) { RealActorIter *ri = (RealActorIter *) iter; g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (ri->root != NULL, FALSE); #ifndef G_DISABLE_ASSERT g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE); #endif if (ri->current == NULL) ri->current = ri->root->priv->first_child; else ri->current = ri->current->priv->next_sibling; if (child != NULL) *child = ri->current; return ri->current != NULL; } /** * clutter_actor_iter_prev: * @iter: a #ClutterActorIter * @child: (out) (transfer none): return location for a #ClutterActor * * Advances the @iter and retrieves the previous child of the root * #ClutterActor that was used to initialize the #ClutterActorIterator. * * If the iterator can advance, this function returns %TRUE and sets the * @child argument. * * If the iterator cannot advance, this function returns %FALSE, and * the contents of @child are undefined. * * Return value: %TRUE if the iterator could advance, and %FALSE otherwise. * * Since: 1.10 */ gboolean clutter_actor_iter_prev (ClutterActorIter *iter, ClutterActor **child) { RealActorIter *ri = (RealActorIter *) iter; g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (ri->root != NULL, FALSE); #ifndef G_DISABLE_ASSERT g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE); #endif if (ri->current == NULL) ri->current = ri->root->priv->last_child; else ri->current = ri->current->priv->prev_sibling; if (child != NULL) *child = ri->current; return ri->current != NULL; } /** * clutter_actor_iter_remove: * @iter: a #ClutterActorIter * * Safely removes the #ClutterActor currently pointer to by the iterator * from its parent. * * This function can only be called after clutter_actor_iter_next() or * clutter_actor_iter_prev() returned %TRUE, and cannot be called more * than once for the same actor. * * This function will call clutter_actor_remove_child() internally. * * Since: 1.10 */ void clutter_actor_iter_remove (ClutterActorIter *iter) { RealActorIter *ri = (RealActorIter *) iter; ClutterActor *cur; g_return_if_fail (iter != NULL); g_return_if_fail (ri->root != NULL); #ifndef G_DISABLE_ASSERT g_return_if_fail (ri->age == ri->root->priv->age); #endif g_return_if_fail (ri->current != NULL); cur = ri->current; if (cur != NULL) { ri->current = cur->priv->prev_sibling; clutter_actor_remove_child_internal (ri->root, cur, REMOVE_CHILD_DEFAULT_FLAGS); ri->age += 1; } } /** * clutter_actor_iter_destroy: * @iter: a #ClutterActorIter * * Safely destroys the #ClutterActor currently pointer to by the iterator * from its parent. * * This function can only be called after clutter_actor_iter_next() or * clutter_actor_iter_prev() returned %TRUE, and cannot be called more * than once for the same actor. * * This function will call clutter_actor_destroy() internally. * * Since: 1.10 */ void clutter_actor_iter_destroy (ClutterActorIter *iter) { RealActorIter *ri = (RealActorIter *) iter; ClutterActor *cur; g_return_if_fail (iter != NULL); g_return_if_fail (ri->root != NULL); #ifndef G_DISABLE_ASSERT g_return_if_fail (ri->age == ri->root->priv->age); #endif g_return_if_fail (ri->current != NULL); cur = ri->current; if (cur != NULL) { ri->current = cur->priv->prev_sibling; clutter_actor_destroy (cur); ri->age += 1; } } static const ClutterAnimationInfo default_animation_info = { NULL, /* transitions */ NULL, /* states */ NULL, /* cur_state */ }; static void clutter_animation_info_free (gpointer data) { if (data != NULL) { ClutterAnimationInfo *info = data; if (info->transitions != NULL) g_hash_table_unref (info->transitions); if (info->states != NULL) g_array_unref (info->states); g_slice_free (ClutterAnimationInfo, info); } } const ClutterAnimationInfo * _clutter_actor_get_animation_info_or_defaults (ClutterActor *self) { const ClutterAnimationInfo *res; GObject *obj = G_OBJECT (self); res = g_object_get_qdata (obj, quark_actor_animation_info); if (res != NULL) return res; return &default_animation_info; } ClutterAnimationInfo * _clutter_actor_get_animation_info (ClutterActor *self) { GObject *obj = G_OBJECT (self); ClutterAnimationInfo *res; res = g_object_get_qdata (obj, quark_actor_animation_info); if (res == NULL) { res = g_slice_new (ClutterAnimationInfo); *res = default_animation_info; g_object_set_qdata_full (obj, quark_actor_animation_info, res, clutter_animation_info_free); } return res; } ClutterTransition * _clutter_actor_get_transition (ClutterActor *actor, GParamSpec *pspec) { const ClutterAnimationInfo *info; info = _clutter_actor_get_animation_info_or_defaults (actor); if (info->transitions == NULL) return NULL; return g_hash_table_lookup (info->transitions, pspec->name); } static void transition_closure_free (gpointer data) { if (G_LIKELY (data != NULL)) { TransitionClosure *clos = data; ClutterTimeline *timeline; timeline = CLUTTER_TIMELINE (clos->transition); /* we disconnect the signal handler before stopping the timeline, * so that we don't end up inside on_transition_stopped() from * a call to g_hash_table_remove(). */ g_signal_handler_disconnect (clos->transition, clos->completed_id); if (clutter_timeline_is_playing (timeline)) clutter_timeline_stop (timeline); /* remove the reference added in add_transition_internal() */ g_object_unref (clos->transition); free (clos->name); g_slice_free (TransitionClosure, clos); } } static void on_transition_stopped (ClutterTransition *transition, gboolean is_finished, TransitionClosure *clos) { ClutterActor *actor = clos->actor; ClutterAnimationInfo *info; GQuark t_quark; gchar *t_name; if (clos->name == NULL) return; /* reset the caches used by animations */ clutter_actor_store_content_box (actor, NULL); info = _clutter_actor_get_animation_info (actor); /* we need copies because we emit the signal after the * TransitionClosure data structure has been freed */ t_quark = g_quark_from_string (clos->name); t_name = g_strdup (clos->name); if (clos->is_implicit || clutter_transition_get_remove_on_complete (transition)) { /* we take a reference here because removing the closure * will release the reference on the transition, and we * want the transition to survive the signal emission */ g_object_ref (transition); /* this is safe, because the timeline has now stopped, * so we won't recurse; the reference on the Animatable * will be dropped by the ::stopped signal closure in * ClutterTransition, which is RUN_LAST, and thus will * be called after this handler */ g_hash_table_remove (info->transitions, clos->name); } /* we emit the ::transition-stopped after removing the * transition, so that we can chain up new transitions * without interfering with the one that just finished */ g_signal_emit (actor, actor_signals[TRANSITION_STOPPED], t_quark, t_name, is_finished); free (t_name); /* if it's the last transition then we clean up */ if (g_hash_table_size (info->transitions) == 0) { g_hash_table_unref (info->transitions); info->transitions = NULL; CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed", _clutter_actor_get_debug_name (actor)); g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0); } } static void clutter_actor_add_transition_internal (ClutterActor *self, const gchar *name, ClutterTransition *transition, gboolean is_implicit) { ClutterTimeline *timeline; TransitionClosure *clos; ClutterAnimationInfo *info; info = _clutter_actor_get_animation_info (self); if (info->transitions == NULL) info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, transition_closure_free); if (g_hash_table_lookup (info->transitions, name) != NULL) { g_warning ("A transition with name '%s' already exists for " "the actor '%s'", name, _clutter_actor_get_debug_name (self)); return; } clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self)); timeline = CLUTTER_TIMELINE (transition); clos = g_slice_new (TransitionClosure); clos->actor = self; clos->transition = g_object_ref (transition); clos->name = g_strdup (name); clos->is_implicit = is_implicit; clos->completed_id = g_signal_connect (timeline, "stopped", G_CALLBACK (on_transition_stopped), clos); CLUTTER_NOTE (ANIMATION, "Adding transition '%s' [%p] to actor '%s'", clos->name, clos->transition, _clutter_actor_get_debug_name (self)); g_hash_table_insert (info->transitions, clos->name, clos); clutter_timeline_start (timeline); } static gboolean should_skip_implicit_transition (ClutterActor *self, GParamSpec *pspec) { ClutterActorPrivate *priv = self->priv; const ClutterAnimationInfo *info; /* this function is called from _clutter_actor_create_transition() which * calls _clutter_actor_get_animation_info() first, so we're guaranteed * to have the correct ClutterAnimationInfo pointer */ info = _clutter_actor_get_animation_info_or_defaults (self); /* if the easing state has a non-zero duration we always want an * implicit transition to occur */ if (info->cur_state->easing_duration == 0) return TRUE; /* on the other hand, if the actor hasn't been allocated yet, we want to * skip all transitions on the :allocation, to avoid actors "flying in" * into their new position and size */ if (pspec == obj_props[PROP_ALLOCATION] && priv->needs_allocation) return TRUE; /* if the actor is not mapped and is not part of a branch of the scene * graph that is being cloned, then we always skip implicit transitions * on the account of the fact that the actor is not going to be visible * when those transitions happen */ if (!CLUTTER_ACTOR_IS_MAPPED (self) && priv->in_cloned_branch == 0 && !clutter_actor_has_mapped_clones (self)) return TRUE; return FALSE; } /*< private >* * _clutter_actor_create_transition: * @actor: a #ClutterActor * @pspec: the property used for the transition * @...: initial and final state * * Creates a #ClutterTransition for the property represented by @pspec. * * Return value: a #ClutterTransition */ ClutterTransition * _clutter_actor_create_transition (ClutterActor *actor, GParamSpec *pspec, ...) { ClutterTimeline *timeline; ClutterInterval *interval; ClutterAnimationInfo *info; ClutterTransition *res = NULL; gboolean call_restore = FALSE; TransitionClosure *clos; va_list var_args; GValue initial = G_VALUE_INIT; GValue final = G_VALUE_INIT; GType ptype; char *error; g_assert (pspec != NULL); g_assert ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0); info = _clutter_actor_get_animation_info (actor); /* XXX - this will go away in 2.0 * * if no state has been pushed, we assume that the easing state is * in "compatibility mode": all transitions have a duration of 0 * msecs, which means that they happen immediately. in Clutter 2.0 * this will turn into a g_assert(info->states != NULL), as every * actor will start with a predefined easing state */ if (info->states == NULL) { clutter_actor_save_easing_state (actor); clutter_actor_set_easing_duration (actor, 0); call_restore = TRUE; } if (info->transitions == NULL) info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, transition_closure_free); va_start (var_args, pspec); ptype = G_PARAM_SPEC_VALUE_TYPE (pspec); G_VALUE_COLLECT_INIT (&initial, ptype, var_args, 0, &error); if (error != NULL) { g_critical ("%s: %s", G_STRLOC, error); free (error); goto out; } G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error); if (error != NULL) { g_critical ("%s: %s", G_STRLOC, error); g_value_unset (&initial); free (error); goto out; } if (should_skip_implicit_transition (actor, pspec)) { CLUTTER_NOTE (ANIMATION, "Skipping implicit transition for '%s::%s'", _clutter_actor_get_debug_name (actor), pspec->name); /* remove a transition, if one exists */ clutter_actor_remove_transition (actor, pspec->name); /* we don't go through the Animatable interface because we * already know we got here through an animatable property. */ clutter_actor_set_animatable_property (actor, pspec->param_id, &final, pspec); g_value_unset (&initial); g_value_unset (&final); goto out; } clos = g_hash_table_lookup (info->transitions, pspec->name); if (clos == NULL) { res = clutter_property_transition_new (pspec->name); interval = clutter_interval_new_with_values (ptype, &initial, &final); clutter_transition_set_interval (res, interval); timeline = CLUTTER_TIMELINE (res); clutter_timeline_set_delay (timeline, info->cur_state->easing_delay); clutter_timeline_set_duration (timeline, info->cur_state->easing_duration); clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode); #ifdef CLUTTER_ENABLE_DEBUG if (CLUTTER_HAS_DEBUG (ANIMATION)) { gchar *initial_v, *final_v; initial_v = g_strdup_value_contents (&initial); final_v = g_strdup_value_contents (&final); CLUTTER_NOTE (ANIMATION, "Created transition for %s:%s " "(len:%u, mode:%s, delay:%u) " "initial:%s, final:%s", _clutter_actor_get_debug_name (actor), pspec->name, info->cur_state->easing_duration, clutter_get_easing_name_for_mode (info->cur_state->easing_mode), info->cur_state->easing_delay, initial_v, final_v); free (initial_v); free (final_v); } #endif /* CLUTTER_ENABLE_DEBUG */ /* this will start the transition as well */ clutter_actor_add_transition_internal (actor, pspec->name, res, TRUE); /* the actor now owns the transition */ g_object_unref (res); g_value_unset (&initial); g_value_unset (&final); } else { ClutterAnimationMode cur_mode; guint cur_duration; CLUTTER_NOTE (ANIMATION, "Existing transition for %s:%s", _clutter_actor_get_debug_name (actor), pspec->name); timeline = CLUTTER_TIMELINE (clos->transition); cur_duration = clutter_timeline_get_duration (timeline); if (cur_duration != info->cur_state->easing_duration) clutter_timeline_set_duration (timeline, info->cur_state->easing_duration); cur_mode = clutter_timeline_get_progress_mode (timeline); if (cur_mode != info->cur_state->easing_mode) clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode); clutter_timeline_rewind (timeline); interval = clutter_transition_get_interval (clos->transition); clutter_interval_set_initial_value (interval, &initial); clutter_interval_set_final_value (interval, &final); res = clos->transition; } out: if (call_restore) clutter_actor_restore_easing_state (actor); va_end (var_args); return res; } /** * clutter_actor_add_transition: * @self: a #ClutterActor * @name: the name of the transition to add * @transition: the #ClutterTransition to add * * Adds a @transition to the #ClutterActor's list of animations. * * The @name string is a per-actor unique identifier of the @transition: only * one #ClutterTransition can be associated to the specified @name. * * The @transition will be started once added. * * This function will take a reference on the @transition. * * This function is usually called implicitly when modifying an animatable * property. * * Since: 1.10 */ void clutter_actor_add_transition (ClutterActor *self, const char *name, ClutterTransition *transition) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); clutter_actor_add_transition_internal (self, name, transition, FALSE); } /** * clutter_actor_remove_transition: * @self: a #ClutterActor * @name: the name of the transition to remove * * Removes the transition stored inside a #ClutterActor using @name * identifier. * * If the transition is currently in progress, it will be stopped. * * This function releases the reference acquired when the transition * was added to the #ClutterActor. * * Since: 1.10 */ void clutter_actor_remove_transition (ClutterActor *self, const char *name) { const ClutterAnimationInfo *info; TransitionClosure *clos; gboolean was_playing; GQuark t_quark; gchar *t_name; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (name != NULL); info = _clutter_actor_get_animation_info_or_defaults (self); if (info->transitions == NULL) return; clos = g_hash_table_lookup (info->transitions, name); if (clos == NULL) return; was_playing = clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)); t_quark = g_quark_from_string (clos->name); t_name = g_strdup (clos->name); g_hash_table_remove (info->transitions, name); /* we want to maintain the invariant that ::transition-stopped is * emitted after the transition has been removed, to allow replacing * or chaining; removing the transition from the hash table will * stop it, but transition_closure_free() will disconnect the signal * handler we install in add_transition_internal(), to avoid loops * or segfaults. * * since we know already that a transition will stop once it's removed * from an actor, we can simply emit the ::transition-stopped here * ourselves, if the timeline was playing (if it wasn't, then the * signal was already emitted at least once). */ if (was_playing) { g_signal_emit (self, actor_signals[TRANSITION_STOPPED], t_quark, t_name, FALSE); } free (t_name); } /** * clutter_actor_remove_all_transitions: * @self: a #ClutterActor * * Removes all transitions associated to @self. * * Since: 1.10 */ void clutter_actor_remove_all_transitions (ClutterActor *self) { const ClutterAnimationInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_animation_info_or_defaults (self); if (info->transitions == NULL) return; g_hash_table_remove_all (info->transitions); } /** * clutter_actor_set_easing_duration: * @self: a #ClutterActor * @msecs: the duration of the easing, or %NULL * * Sets the duration of the tweening for animatable properties * of @self for the current easing state. * * Since: 1.10 */ void clutter_actor_set_easing_duration (ClutterActor *self, guint msecs) { ClutterAnimationInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_animation_info (self); if (info->cur_state == NULL) { g_warning ("You must call clutter_actor_save_easing_state() prior " "to calling clutter_actor_set_easing_duration()."); return; } if (info->cur_state->easing_duration != msecs) info->cur_state->easing_duration = msecs; } /** * clutter_actor_get_easing_duration: * @self: a #ClutterActor * * Retrieves the duration of the tweening for animatable * properties of @self for the current easing state. * * Return value: the duration of the tweening, in milliseconds * * Since: 1.10 */ guint clutter_actor_get_easing_duration (ClutterActor *self) { const ClutterAnimationInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); info = _clutter_actor_get_animation_info_or_defaults (self); if (info->cur_state != NULL) return info->cur_state->easing_duration; return 0; } /** * clutter_actor_set_easing_mode: * @self: a #ClutterActor * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE * * Sets the easing mode for the tweening of animatable properties * of @self. * * Since: 1.10 */ void clutter_actor_set_easing_mode (ClutterActor *self, ClutterAnimationMode mode) { ClutterAnimationInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (mode != CLUTTER_CUSTOM_MODE); g_return_if_fail (mode < CLUTTER_ANIMATION_LAST); info = _clutter_actor_get_animation_info (self); if (info->cur_state == NULL) { g_warning ("You must call clutter_actor_save_easing_state() prior " "to calling clutter_actor_set_easing_mode()."); return; } if (info->cur_state->easing_mode != mode) info->cur_state->easing_mode = mode; } /** * clutter_actor_get_easing_mode: * @self: a #ClutterActor * * Retrieves the easing mode for the tweening of animatable properties * of @self for the current easing state. * * Return value: an easing mode * * Since: 1.10 */ ClutterAnimationMode clutter_actor_get_easing_mode (ClutterActor *self) { const ClutterAnimationInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC); info = _clutter_actor_get_animation_info_or_defaults (self); if (info->cur_state != NULL) return info->cur_state->easing_mode; return CLUTTER_EASE_OUT_CUBIC; } /** * clutter_actor_set_easing_delay: * @self: a #ClutterActor * @msecs: the delay before the start of the tweening, in milliseconds * * Sets the delay that should be applied before tweening animatable * properties. * * Since: 1.10 */ void clutter_actor_set_easing_delay (ClutterActor *self, guint msecs) { ClutterAnimationInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_animation_info (self); if (info->cur_state == NULL) { g_warning ("You must call clutter_actor_save_easing_state() prior " "to calling clutter_actor_set_easing_delay()."); return; } if (info->cur_state->easing_delay != msecs) info->cur_state->easing_delay = msecs; } /** * clutter_actor_get_easing_delay: * @self: a #ClutterActor * * Retrieves the delay that should be applied when tweening animatable * properties. * * Return value: a delay, in milliseconds * * Since: 1.10 */ guint clutter_actor_get_easing_delay (ClutterActor *self) { const ClutterAnimationInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0); info = _clutter_actor_get_animation_info_or_defaults (self); if (info->cur_state != NULL) return info->cur_state->easing_delay; return 0; } /** * clutter_actor_get_transition: * @self: a #ClutterActor * @name: the name of the transition * * Retrieves the #ClutterTransition of a #ClutterActor by using the * transition @name. * * Transitions created for animatable properties use the name of the * property itself, for instance the code below: * * |[ * clutter_actor_set_easing_duration (actor, 1000); * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z); * * transition = clutter_actor_get_transition (actor, "rotation-angle-y"); * g_signal_connect (transition, "stopped", * G_CALLBACK (on_transition_stopped), * actor); * ]| * * will call the `on_transition_stopped` callback when the transition * is finished. * * If you just want to get notifications of the completion of a transition, * you should use the #ClutterActor::transition-stopped signal, using the * transition name as the signal detail. * * Return value: (transfer none): a #ClutterTransition, or %NULL is none * was found to match the passed name; the returned instance is owned * by Clutter and it should not be freed * * Since: 1.10 */ ClutterTransition * clutter_actor_get_transition (ClutterActor *self, const char *name) { TransitionClosure *clos; const ClutterAnimationInfo *info; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); g_return_val_if_fail (name != NULL, NULL); info = _clutter_actor_get_animation_info_or_defaults (self); if (info->transitions == NULL) return NULL; clos = g_hash_table_lookup (info->transitions, name); if (clos == NULL) return NULL; return clos->transition; } /** * clutter_actor_save_easing_state: * @self: a #ClutterActor * * Saves the current easing state for animatable properties, and creates * a new state with the default values for easing mode and duration. * * New transitions created after calling this function will inherit the * duration, easing mode, and delay of the new easing state; this also * applies to transitions modified in flight. * * Since: 1.10 */ void clutter_actor_save_easing_state (ClutterActor *self) { ClutterAnimationInfo *info; AState new_state; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_animation_info (self); if (info->states == NULL) info->states = g_array_new (FALSE, FALSE, sizeof (AState)); new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC; new_state.easing_duration = 250; new_state.easing_delay = 0; g_array_append_val (info->states, new_state); info->cur_state = &g_array_index (info->states, AState, info->states->len - 1); } /** * clutter_actor_restore_easing_state: * @self: a #ClutterActor * * Restores the easing state as it was prior to a call to * clutter_actor_save_easing_state(). * * Since: 1.10 */ void clutter_actor_restore_easing_state (ClutterActor *self) { ClutterAnimationInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_animation_info (self); if (info->states == NULL) { g_critical ("The function clutter_actor_restore_easing_state() has " "been called without a previous call to " "clutter_actor_save_easing_state()."); return; } g_array_remove_index (info->states, info->states->len - 1); if (info->states->len > 0) info->cur_state = &g_array_index (info->states, AState, info->states->len - 1); else { g_array_unref (info->states); info->states = NULL; info->cur_state = NULL; } } /** * clutter_actor_set_content: * @self: a #ClutterActor * @content: (allow-none): a #ClutterContent, or %NULL * * Sets the contents of a #ClutterActor. * * Since: 1.10 */ void clutter_actor_set_content (ClutterActor *self, ClutterContent *content) { ClutterActorPrivate *priv; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content)); priv = self->priv; if (priv->content == content) return; if (priv->content != NULL) { _clutter_content_detached (priv->content, self); g_clear_object (&priv->content); } priv->content = content; if (priv->content != NULL) { g_object_ref (priv->content); _clutter_content_attached (priv->content, self); } /* if the actor's preferred size is the content's preferred size, * then we need to conditionally queue a relayout here... */ if (priv->request_mode == CLUTTER_REQUEST_CONTENT_SIZE) _clutter_actor_queue_only_relayout (self); clutter_actor_queue_redraw (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]); /* if the content gravity is not resize-fill, and the new content has a * different preferred size than the previous one, then the content box * may have been changed. since we compute that lazily, we just notify * here, and let whomever watches :content-box do whatever they need to * do. */ if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL) { if (priv->content_box_valid) { ClutterActorBox from_box, to_box; clutter_actor_get_content_box (self, &from_box); /* invalidate the cached content box */ priv->content_box_valid = FALSE; clutter_actor_get_content_box (self, &to_box); if (!clutter_actor_box_equal (&from_box, &to_box)) _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX], &from_box, &to_box); } g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]); } } /** * clutter_actor_get_content: * @self: a #ClutterActor * * Retrieves the contents of @self. * * Return value: (transfer none): a pointer to the #ClutterContent instance, * or %NULL if none was set * * Since: 1.10 */ ClutterContent * clutter_actor_get_content (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); return self->priv->content; } /** * clutter_actor_set_content_gravity: * @self: a #ClutterActor * @gravity: the #ClutterContentGravity * * Sets the gravity of the #ClutterContent used by @self. * * See the description of the #ClutterActor:content-gravity property for * more information. * * The #ClutterActor:content-gravity property is animatable. * * Since: 1.10 */ void clutter_actor_set_content_gravity (ClutterActor *self, ClutterContentGravity gravity) { ClutterActorPrivate *priv; ClutterActorBox from_box, to_box; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; if (priv->content_gravity == gravity) return; priv->content_box_valid = FALSE; clutter_actor_get_content_box (self, &from_box); priv->content_gravity = gravity; clutter_actor_get_content_box (self, &to_box); _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX], &from_box, &to_box); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]); } /** * clutter_actor_get_content_gravity: * @self: a #ClutterActor * * Retrieves the content gravity as set using * clutter_actor_set_content_gravity(). * * Return value: the content gravity * * Since: 1.10 */ ClutterContentGravity clutter_actor_get_content_gravity (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_CONTENT_GRAVITY_RESIZE_FILL); return self->priv->content_gravity; } /** * clutter_actor_get_content_box: * @self: a #ClutterActor * @box: (out caller-allocates): the return location for the bounding * box for the #ClutterContent * * Retrieves the bounding box for the #ClutterContent of @self. * * The bounding box is relative to the actor's allocation. * * If no #ClutterContent is set for @self, or if @self has not been * allocated yet, then the result is undefined. * * The content box is guaranteed to be, at most, as big as the allocation * of the #ClutterActor. * * If the #ClutterContent used by the actor has a preferred size, then * it is possible to modify the content box by using the * #ClutterActor:content-gravity property. * * Since: 1.10 */ void clutter_actor_get_content_box (ClutterActor *self, ClutterActorBox *box) { ClutterActorPrivate *priv; gfloat content_w, content_h; gfloat alloc_w, alloc_h; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (box != NULL); priv = self->priv; box->x1 = 0.f; box->y1 = 0.f; box->x2 = priv->allocation.x2 - priv->allocation.x1; box->y2 = priv->allocation.y2 - priv->allocation.y1; if (priv->content_box_valid) { *box = priv->content_box; return; } /* no need to do any more work */ if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL) return; if (priv->content == NULL) return; /* if the content does not have a preferred size then there is * no point in computing the content box */ if (!clutter_content_get_preferred_size (priv->content, &content_w, &content_h)) return; alloc_w = box->x2; alloc_h = box->y2; switch (priv->content_gravity) { case CLUTTER_CONTENT_GRAVITY_TOP_LEFT: box->x2 = box->x1 + MIN (content_w, alloc_w); box->y2 = box->y1 + MIN (content_h, alloc_h); break; case CLUTTER_CONTENT_GRAVITY_TOP: if (alloc_w > content_w) { box->x1 += ceilf ((alloc_w - content_w) / 2.0); box->x2 = box->x1 + content_w; } box->y2 = box->y1 + MIN (content_h, alloc_h); break; case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT: if (alloc_w > content_w) { box->x1 += (alloc_w - content_w); box->x2 = box->x1 + content_w; } box->y2 = box->y1 + MIN (content_h, alloc_h); break; case CLUTTER_CONTENT_GRAVITY_LEFT: box->x2 = box->x1 + MIN (content_w, alloc_w); if (alloc_h > content_h) { box->y1 += ceilf ((alloc_h - content_h) / 2.0); box->y2 = box->y1 + content_h; } break; case CLUTTER_CONTENT_GRAVITY_CENTER: if (alloc_w > content_w) { box->x1 += ceilf ((alloc_w - content_w) / 2.0); box->x2 = box->x1 + content_w; } if (alloc_h > content_h) { box->y1 += ceilf ((alloc_h - content_h) / 2.0); box->y2 = box->y1 + content_h; } break; case CLUTTER_CONTENT_GRAVITY_RIGHT: if (alloc_w > content_w) { box->x1 += (alloc_w - content_w); box->x2 = box->x1 + content_w; } if (alloc_h > content_h) { box->y1 += ceilf ((alloc_h - content_h) / 2.0); box->y2 = box->y1 + content_h; } break; case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT: box->x2 = box->x1 + MIN (content_w, alloc_w); if (alloc_h > content_h) { box->y1 += (alloc_h - content_h); box->y2 = box->y1 + content_h; } break; case CLUTTER_CONTENT_GRAVITY_BOTTOM: if (alloc_w > content_w) { box->x1 += ceilf ((alloc_w - content_w) / 2.0); box->x2 = box->x1 + content_w; } if (alloc_h > content_h) { box->y1 += (alloc_h - content_h); box->y2 = box->y1 + content_h; } break; case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT: if (alloc_w > content_w) { box->x1 += (alloc_w - content_w); box->x2 = box->x1 + content_w; } if (alloc_h > content_h) { box->y1 += (alloc_h - content_h); box->y2 = box->y1 + content_h; } break; case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL: g_assert_not_reached (); break; case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT: { double r_c = content_w / content_h; if ((alloc_w / r_c) > alloc_h) { box->y1 = 0.f; box->y2 = alloc_h; box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f; box->x2 = box->x1 + (alloc_h * r_c); } else { box->x1 = 0.f; box->x2 = alloc_w; box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f; box->y2 = box->y1 + (alloc_w / r_c); } CLUTTER_NOTE (LAYOUT, "r_c: %.3f, r_a: %.3f\t" "a: [%.2fx%.2f], c: [%.2fx%.2f]\t" "b: [%.2f, %.2f, %.2f, %.2f]", r_c, alloc_w / alloc_h, alloc_w, alloc_h, content_w, content_h, box->x1, box->y1, box->x2, box->y2); } break; } } /** * clutter_actor_set_content_scaling_filters: * @self: a #ClutterActor * @min_filter: the minification filter for the content * @mag_filter: the magnification filter for the content * * Sets the minification and magnification filter to be applied when * scaling the #ClutterActor:content of a #ClutterActor. * * The #ClutterActor:minification-filter will be used when reducing * the size of the content; the #ClutterActor:magnification-filter * will be used when increasing the size of the content. * * Since: 1.10 */ void clutter_actor_set_content_scaling_filters (ClutterActor *self, ClutterScalingFilter min_filter, ClutterScalingFilter mag_filter) { ClutterActorPrivate *priv; gboolean changed; GObject *obj; g_return_if_fail (CLUTTER_IS_ACTOR (self)); priv = self->priv; obj = G_OBJECT (self); g_object_freeze_notify (obj); changed = FALSE; if (priv->min_filter != min_filter) { priv->min_filter = min_filter; changed = TRUE; g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]); } if (priv->mag_filter != mag_filter) { priv->mag_filter = mag_filter; changed = TRUE; g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]); } if (changed) clutter_actor_queue_redraw (self); g_object_thaw_notify (obj); } /** * clutter_actor_get_content_scaling_filters: * @self: a #ClutterActor * @min_filter: (out) (allow-none): return location for the minification * filter, or %NULL * @mag_filter: (out) (allow-none): return location for the magnification * filter, or %NULL * * Retrieves the values set using clutter_actor_set_content_scaling_filters(). * * Since: 1.10 */ void clutter_actor_get_content_scaling_filters (ClutterActor *self, ClutterScalingFilter *min_filter, ClutterScalingFilter *mag_filter) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (min_filter != NULL) *min_filter = self->priv->min_filter; if (mag_filter != NULL) *mag_filter = self->priv->mag_filter; } /* * clutter_actor_queue_compute_expand: * @self: a #ClutterActor * * Invalidates the needs_x_expand and needs_y_expand flags on @self * and its parents up to the top-level actor. * * This function also queues a relayout if anything changed. */ static inline void clutter_actor_queue_compute_expand (ClutterActor *self) { ClutterActor *parent; gboolean changed; if (self->priv->needs_compute_expand) return; changed = FALSE; parent = self; while (parent != NULL) { if (!parent->priv->needs_compute_expand) { parent->priv->needs_compute_expand = TRUE; changed = TRUE; } parent = parent->priv->parent; } if (changed) clutter_actor_queue_relayout (self); } /** * clutter_actor_set_x_expand: * @self: a #ClutterActor * @expand: whether the actor should expand horizontally * * Sets whether a #ClutterActor should expand horizontally; this means * that layout manager should allocate extra space for the actor, if * possible. * * Setting an actor to expand will also make all its parent expand, so * that it's possible to build an actor tree and only set this flag on * its leaves and not on every single actor. * * Since: 1.12 */ void clutter_actor_set_x_expand (ClutterActor *self, gboolean expand) { ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); expand = !!expand; info = _clutter_actor_get_layout_info (self); if (info->x_expand != expand) { info->x_expand = expand; self->priv->x_expand_set = TRUE; clutter_actor_queue_compute_expand (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_EXPAND]); } } /** * clutter_actor_get_x_expand: * @self: a #ClutterActor * * Retrieves the value set with clutter_actor_set_x_expand(). * * See also: clutter_actor_needs_expand() * * Return value: %TRUE if the actor has been set to expand * * Since: 1.12 */ gboolean clutter_actor_get_x_expand (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return _clutter_actor_get_layout_info_or_defaults (self)->x_expand; } /** * clutter_actor_set_y_expand: * @self: a #ClutterActor * @expand: whether the actor should expand vertically * * Sets whether a #ClutterActor should expand horizontally; this means * that layout manager should allocate extra space for the actor, if * possible. * * Setting an actor to expand will also make all its parent expand, so * that it's possible to build an actor tree and only set this flag on * its leaves and not on every single actor. * * Since: 1.12 */ void clutter_actor_set_y_expand (ClutterActor *self, gboolean expand) { ClutterLayoutInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); expand = !!expand; info = _clutter_actor_get_layout_info (self); if (info->y_expand != expand) { info->y_expand = expand; self->priv->y_expand_set = TRUE; clutter_actor_queue_compute_expand (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_EXPAND]); } } /** * clutter_actor_get_y_expand: * @self: a #ClutterActor * * Retrieves the value set with clutter_actor_set_y_expand(). * * See also: clutter_actor_needs_expand() * * Return value: %TRUE if the actor has been set to expand * * Since: 1.12 */ gboolean clutter_actor_get_y_expand (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); return _clutter_actor_get_layout_info_or_defaults (self)->y_expand; } static void clutter_actor_compute_expand_recursive (ClutterActor *self, gboolean *x_expand_p, gboolean *y_expand_p) { ClutterActorIter iter; ClutterActor *child; gboolean x_expand, y_expand; x_expand = y_expand = FALSE; /* note that we don't recurse into children if we're already set to expand; * this avoids traversing the whole actor tree, even if it may lead to some * child left with the needs_compute_expand flag set. */ clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) { x_expand = x_expand || clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL); y_expand = y_expand || clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL); } *x_expand_p = x_expand; *y_expand_p = y_expand; } static void clutter_actor_compute_expand (ClutterActor *self) { if (self->priv->needs_compute_expand) { const ClutterLayoutInfo *info; gboolean x_expand, y_expand; info = _clutter_actor_get_layout_info_or_defaults (self); if (self->priv->x_expand_set) x_expand = info->x_expand; else x_expand = FALSE; if (self->priv->y_expand_set) y_expand = info->y_expand; else y_expand = FALSE; /* we don't need to recurse down to the children if the * actor has been forcibly set to expand */ if (!(self->priv->x_expand_set && self->priv->y_expand_set)) { if (self->priv->n_children != 0) { gboolean *x_expand_p, *y_expand_p; gboolean ignored = FALSE; x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand; y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand; clutter_actor_compute_expand_recursive (self, x_expand_p, y_expand_p); } } self->priv->needs_compute_expand = FALSE; self->priv->needs_x_expand = (x_expand != FALSE); self->priv->needs_y_expand = (y_expand != FALSE); } } /** * clutter_actor_needs_expand: * @self: a #ClutterActor * @orientation: the direction of expansion * * Checks whether an actor, or any of its children, is set to expand * horizontally or vertically. * * This function should only be called by layout managers that can * assign extra space to their children. * * If you want to know whether the actor was explicitly set to expand, * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand(). * * Return value: %TRUE if the actor should expand * * Since: 1.12 */ gboolean clutter_actor_needs_expand (ClutterActor *self, ClutterOrientation orientation) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); if (!CLUTTER_ACTOR_IS_VISIBLE (self)) return FALSE; if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) return FALSE; clutter_actor_compute_expand (self); switch (orientation) { case CLUTTER_ORIENTATION_HORIZONTAL: return self->priv->needs_x_expand; case CLUTTER_ORIENTATION_VERTICAL: return self->priv->needs_y_expand; } return FALSE; } /** * clutter_actor_set_content_repeat: * @self: a #ClutterActor * @repeat: the repeat policy * * Sets the policy for repeating the #ClutterActor:content of a * #ClutterActor. The behaviour is deferred to the #ClutterContent * implementation. * * Since: 1.12 */ void clutter_actor_set_content_repeat (ClutterActor *self, ClutterContentRepeat repeat) { g_return_if_fail (CLUTTER_IS_ACTOR (self)); if (self->priv->content_repeat == repeat) return; self->priv->content_repeat = repeat; clutter_actor_queue_redraw (self); } /** * clutter_actor_get_content_repeat: * @self: a #ClutterActor * * Retrieves the repeat policy for a #ClutterActor set by * clutter_actor_set_content_repeat(). * * Return value: the content repeat policy * * Since: 1.12 */ ClutterContentRepeat clutter_actor_get_content_repeat (ClutterActor *self) { g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_REPEAT_NONE); return self->priv->content_repeat; } void _clutter_actor_handle_event (ClutterActor *self, const ClutterEvent *event) { GPtrArray *event_tree; ClutterActor *iter; gboolean is_key_event; gint i = 0; /* XXX - for historical reasons that are now lost in the mists of time, * key events are delivered regardless of whether an actor is set as * reactive; this should be changed for 2.0. */ is_key_event = event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_KEY_RELEASE; event_tree = g_ptr_array_sized_new (64); g_ptr_array_set_free_func (event_tree, (GDestroyNotify) g_object_unref); /* build the list of of emitters for the event */ iter = self; while (iter != NULL) { ClutterActor *parent = iter->priv->parent; if (CLUTTER_ACTOR_IS_REACTIVE (iter) || /* an actor must be reactive */ parent == NULL || /* unless it's the stage */ is_key_event) /* or this is a key event */ { /* keep a reference on the actor, so that it remains valid * for the duration of the signal emission */ g_ptr_array_add (event_tree, g_object_ref (iter)); } iter = parent; } /* Capture: from top-level downwards */ for (i = event_tree->len - 1; i >= 0; i--) if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, TRUE)) goto done; /* Bubble: from source upwards */ for (i = 0; i < event_tree->len; i++) if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, FALSE)) goto done; done: g_ptr_array_free (event_tree, TRUE); } static void clutter_actor_set_child_transform_internal (ClutterActor *self, const ClutterMatrix *transform) { ClutterTransformInfo *info = _clutter_actor_get_transform_info (self); ClutterActorIter iter; ClutterActor *child; GObject *obj; gboolean was_set = info->child_transform_set; clutter_matrix_init_from_matrix (&info->child_transform, transform); /* if it's the identity matrix, we need to toggle the boolean flag */ info->child_transform_set = !cogl_matrix_is_identity (transform); /* we need to reset the transform_valid flag on each child */ clutter_actor_iter_init (&iter, self); while (clutter_actor_iter_next (&iter, &child)) child->priv->transform_valid = FALSE; clutter_actor_queue_redraw (self); obj = G_OBJECT (self); g_object_notify_by_pspec (obj, obj_props[PROP_CHILD_TRANSFORM]); if (was_set != info->child_transform_set) g_object_notify_by_pspec (obj, obj_props[PROP_CHILD_TRANSFORM_SET]); } /** * clutter_actor_set_child_transform: * @self: a #ClutterActor * @transform: (allow-none): a #ClutterMatrix, or %NULL * * Sets the transformation matrix to be applied to all the children * of @self prior to their own transformations. The default child * transformation is the identity matrix. * * If @transform is %NULL, the child transform will be unset. * * The #ClutterActor:child-transform property is animatable. * * Since: 1.12 */ void clutter_actor_set_child_transform (ClutterActor *self, const ClutterMatrix *transform) { const ClutterTransformInfo *info; ClutterMatrix new_transform; g_return_if_fail (CLUTTER_IS_ACTOR (self)); info = _clutter_actor_get_transform_info_or_defaults (self); if (transform != NULL) clutter_matrix_init_from_matrix (&new_transform, transform); else clutter_matrix_init_identity (&new_transform); _clutter_actor_create_transition (self, obj_props[PROP_CHILD_TRANSFORM], &info->child_transform, &new_transform); } /** * clutter_actor_get_child_transform: * @self: a #ClutterActor * @transform: (out caller-allocates): a #ClutterMatrix * * Retrieves the child transformation matrix set using * clutter_actor_set_child_transform(); if none is currently set, * the @transform matrix will be initialized to the identity matrix. * * Since: 1.12 */ void clutter_actor_get_child_transform (ClutterActor *self, ClutterMatrix *transform) { const ClutterTransformInfo *info; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (transform != NULL); info = _clutter_actor_get_transform_info_or_defaults (self); if (info->child_transform_set) clutter_matrix_init_from_matrix (transform, &info->child_transform); else clutter_matrix_init_identity (transform); } static void clutter_actor_push_in_cloned_branch (ClutterActor *self) { ClutterActor *iter; for (iter = self->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) clutter_actor_push_in_cloned_branch (iter); self->priv->in_cloned_branch += 1; } static void clutter_actor_pop_in_cloned_branch (ClutterActor *self) { ClutterActor *iter; self->priv->in_cloned_branch -= 1; for (iter = self->priv->first_child; iter != NULL; iter = iter->priv->next_sibling) clutter_actor_pop_in_cloned_branch (iter); } void _clutter_actor_attach_clone (ClutterActor *actor, ClutterActor *clone) { ClutterActorPrivate *priv = actor->priv; g_assert (clone != NULL); if (priv->clones == NULL) priv->clones = g_hash_table_new (NULL, NULL); g_hash_table_add (priv->clones, clone); clutter_actor_push_in_cloned_branch (actor); } void _clutter_actor_detach_clone (ClutterActor *actor, ClutterActor *clone) { ClutterActorPrivate *priv = actor->priv; g_assert (clone != NULL); if (priv->clones == NULL || g_hash_table_lookup (priv->clones, clone) == NULL) return; clutter_actor_pop_in_cloned_branch (actor); g_hash_table_remove (priv->clones, clone); if (g_hash_table_size (priv->clones) == 0) { g_hash_table_unref (priv->clones); priv->clones = NULL; } } void _clutter_actor_queue_redraw_on_clones (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; GHashTableIter iter; gpointer key; if (priv->clones == NULL) return; g_hash_table_iter_init (&iter, priv->clones); while (g_hash_table_iter_next (&iter, &key, NULL)) clutter_actor_queue_redraw (key); } void _clutter_actor_queue_relayout_on_clones (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; GHashTableIter iter; gpointer key; if (priv->clones == NULL) return; g_hash_table_iter_init (&iter, priv->clones); while (g_hash_table_iter_next (&iter, &key, NULL)) clutter_actor_queue_relayout (key); } /** * clutter_actor_has_mapped_clones: * @self: a #ClutterActor * * Returns whether a #ClutterActor has any mapped clones. * * Return: %TRUE if the actor has mapped clones, and %FALSE otherwise * * Since: 1.16 */ gboolean clutter_actor_has_mapped_clones (ClutterActor *self) { ClutterActorPrivate *priv; GHashTableIter iter; gpointer key; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE); priv = self->priv; if (priv->clones == NULL) return FALSE; g_hash_table_iter_init (&iter, priv->clones); while (g_hash_table_iter_next (&iter, &key, NULL)) { if (CLUTTER_ACTOR_IS_MAPPED (key)) return TRUE; } return FALSE; } CoglFramebuffer * _clutter_actor_get_active_framebuffer (ClutterActor *self) { ClutterStage *stage; if (!CLUTTER_ACTOR_IN_PAINT (self)) { g_critical ("The active framebuffer of actor '%s' can only be " "retrieved during the paint sequence. Please, check " "your code.", _clutter_actor_get_debug_name (self)); return NULL; } stage = (ClutterStage *) _clutter_actor_get_stage_internal (self); if (stage == NULL) { g_critical ("The active framebuffer of actor '%s' is only available " "if the actor is associated to a ClutterStage.", _clutter_actor_get_debug_name (self)); return NULL; } return _clutter_stage_get_active_framebuffer (stage); } static void clutter_actor_child_model__items_changed (GListModel *model, guint position, guint removed, guint added, gpointer user_data) { ClutterActor *parent = user_data; ClutterActorPrivate *priv = parent->priv; guint i; while (removed--) { ClutterActor *child = clutter_actor_get_child_at_index (parent, position); clutter_actor_destroy (child); } for (i = 0; i < added; i++) { GObject *item = g_list_model_get_item (model, position + i); ClutterActor *child = priv->create_child_func (item, priv->create_child_data); /* The actor returned by the function can have a floating reference, * if the implementation is in pure C, or have a full reference, usually * the case for language bindings. To avoid leaking references, we * try to assume ownership of the instance, and release the reference * at the end unconditionally, leaving the only reference to the actor * itself. */ if (g_object_is_floating (child)) g_object_ref_sink (child); clutter_actor_insert_child_at_index (parent, child, position + i); g_object_unref (child); g_object_unref (item); } } /** * clutter_actor_bind_model: * @self: a #ClutterActor * @model: (nullable): a #GListModel * @create_child_func: a function that creates #ClutterActor instances * from the contents of the @model * @user_data: user data passed to @create_child_func * @notify: function called when unsetting the @model * * Binds a #GListModel to a #ClutterActor. * * If the #ClutterActor was already bound to a #GListModel, the previous * binding is destroyed. * * The existing children of #ClutterActor are destroyed when setting a * model, and new children are created and added, representing the contents * of the @model. The #ClutterActor is updated whenever the @model changes. * If @model is %NULL, the #ClutterActor is left empty. * * When a #ClutterActor is bound to a model, adding and removing children * directly is undefined behaviour. * * Since: 1.24 */ void clutter_actor_bind_model (ClutterActor *self, GListModel *model, ClutterActorCreateChildFunc create_child_func, gpointer user_data, GDestroyNotify notify) { ClutterActorPrivate *priv = clutter_actor_get_instance_private (self); g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); g_return_if_fail (model == NULL || create_child_func != NULL); if (priv->child_model != NULL) { if (priv->create_child_notify != NULL) priv->create_child_notify (priv->create_child_data); g_signal_handlers_disconnect_by_func (priv->child_model, clutter_actor_child_model__items_changed, self); g_clear_object (&priv->child_model); priv->create_child_func = NULL; priv->create_child_data = NULL; priv->create_child_notify = NULL; } clutter_actor_destroy_all_children (self); if (model == NULL) return; priv->child_model = g_object_ref (model); priv->create_child_func = create_child_func; priv->create_child_data = user_data; priv->create_child_notify = notify; g_signal_connect (priv->child_model, "items-changed", G_CALLBACK (clutter_actor_child_model__items_changed), self); clutter_actor_child_model__items_changed (priv->child_model, 0, 0, g_list_model_get_n_items (priv->child_model), self); } typedef struct { GType child_type; GArray *props; } BindClosure; typedef struct { const char *model_property; const char *child_property; GBindingFlags flags; } BindProperty; static void bind_closure_free (gpointer data_) { BindClosure *data = data_; if (data == NULL) return; g_array_unref (data->props); g_slice_free (BindClosure, data); } static ClutterActor * bind_child_with_properties (gpointer item, gpointer data_) { BindClosure *data = data_; ClutterActor *res; guint i; res = g_object_new (data->child_type, NULL); for (i = 0; i < data->props->len; i++) { const BindProperty *prop = &g_array_index (data->props, BindProperty, i); g_object_bind_property (item, prop->model_property, res, prop->child_property, prop->flags); } return res; } /** * clutter_actor_bind_model_with_properties: * @self: a #ClutterActor * @model: a #GListModel * @child_type: the type of #ClutterActor to use when creating * children mapping to items inside the @model * @first_model_property: the first property of @model to bind * @...: tuples of property names on the @model, on the child, and the * #GBindingFlags used to bind them, terminated by %NULL * * Binds a #GListModel to a #ClutterActor. * * Unlike clutter_actor_bind_model(), this function automatically creates * a child #ClutterActor of type @child_type, and binds properties on the * items inside the @model to the corresponding properties on the child, * for instance: * * |[ * clutter_actor_bind_model_with_properties (actor, model, * MY_TYPE_CHILD_VIEW, * "label", "text", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE, * "icon", "image", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE, * "selected", "selected", G_BINDING_BIDIRECTIONAL, * "active", "active", G_BINDING_BIDIRECTIONAL, * NULL); * ]| * * is the equivalent of calling clutter_actor_bind_model() with a * #ClutterActorCreateChildFunc of: * * |[ * ClutterActor *res = g_object_new (MY_TYPE_CHILD_VIEW, NULL); * * g_object_bind_property (item, "label", res, "text", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); * g_object_bind_property (item, "icon", res, "image", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); * g_object_bind_property (item, "selected", res, "selected", G_BINDING_BIDIRECTIONAL); * g_object_bind_property (item, "active", res, "active", G_BINDING_BIDIRECTIONAL); * * return res; * ]| * * If the #ClutterActor was already bound to a #GListModel, the previous * binding is destroyed. * * When a #ClutterActor is bound to a model, adding and removing children * directly is undefined behaviour. * * See also: clutter_actor_bind_model() * * Since: 1.24 */ void clutter_actor_bind_model_with_properties (ClutterActor *self, GListModel *model, GType child_type, const char *first_model_property, ...) { va_list args; BindClosure *clos; const char *model_property; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (G_IS_LIST_MODEL (model)); g_return_if_fail (g_type_is_a (child_type, CLUTTER_TYPE_ACTOR)); clos = g_slice_new0 (BindClosure); clos->child_type = child_type; clos->props = g_array_new (FALSE, FALSE, sizeof (BindProperty)); va_start (args, first_model_property); model_property = first_model_property; while (model_property != NULL) { const char *child_property = va_arg (args, char *); GBindingFlags binding_flags = va_arg (args, guint); BindProperty bind; bind.model_property = g_intern_string (model_property); bind.child_property = g_intern_string (child_property); bind.flags = binding_flags; g_array_append_val (clos->props, bind); model_property = va_arg (args, char *); } clutter_actor_bind_model (self, model, bind_child_with_properties, clos, bind_closure_free); } /*< private > * clutter_actor_create_texture_paint_node: * @self: a #ClutterActor * @texture: a #CoglTexture * * Creates a #ClutterPaintNode initialized using the state of the * given #ClutterActor, ready to be used inside the implementation * of the #ClutterActorClass.paint_node virtual function. * * The returned paint node has the geometry set to the size of the * #ClutterActor:content-box property; it uses the filters specified * in the #ClutterActor:minification-filter and #ClutterActor:magnification-filter * properties; and respects the #ClutterActor:content-repeat property. * * Returns: (transfer full): The newly created #ClutterPaintNode * * Since: 1.24 */ ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self, CoglTexture *texture) { ClutterActorPrivate *priv = clutter_actor_get_instance_private (self); ClutterPaintNode *node; ClutterActorBox box; ClutterColor color; g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL); g_return_val_if_fail (texture != NULL, NULL); clutter_actor_get_content_box (self, &box); /* ClutterTextureNode will premultiply the blend color, so we * want it to be white with the paint opacity */ color.red = 255; color.green = 255; color.blue = 255; color.alpha = clutter_actor_get_paint_opacity_internal (self); node = clutter_texture_node_new (texture, &color, priv->min_filter, priv->mag_filter); clutter_paint_node_set_name (node, "Texture"); if (priv->content_repeat == CLUTTER_REPEAT_NONE) clutter_paint_node_add_rectangle (node, &box); else { float t_w = 1.f, t_h = 1.f; if ((priv->content_repeat & CLUTTER_REPEAT_X_AXIS) != FALSE) t_w = (box.x2 - box.x1) / cogl_texture_get_width (texture); if ((priv->content_repeat & CLUTTER_REPEAT_Y_AXIS) != FALSE) t_h = (box.y2 - box.y1) / cogl_texture_get_height (texture); clutter_paint_node_add_texture_rectangle (node, &box, 0.f, 0.f, t_w, t_h); } return node; } muffin-5.2.1/clutter/clutter/clutter-muffin.h0000664000175000017500000000601514211404421021417 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2016 Red Hat Inc. * * 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, see . * */ #ifndef __CLUTTER_MUFFIN_H__ #define __CLUTTER_MUFFIN_H__ #define __CLUTTER_H_INSIDE__ #include "clutter-backend.h" #include "clutter-macros.h" #include "clutter-stage-view.h" #include "cogl/clutter-stage-cogl.h" #include "x11/clutter-stage-x11.h" typedef enum _SyncMethod /* In order of priority */ { /* SUPPORTED LATENCY SMOOTHNESS */ SYNC_NONE = 0, /* Always High Poor */ SYNC_FALLBACK, /* Always Medium Medium */ SYNC_SWAP_THROTTLING, /* Usually Medium-high Medium, sometimes best */ SYNC_PRESENTATION_TIME /* Usually Low Good, sometimes best */ /* ^ As you can see SWAP_THROTTLING doesn't add much value. And it does create the the very real risk of blocking the main loop for up to 16ms at a time. So it might be a good idea to retire it in future and instead just make the backends use swap interval 0 + PRESENTATION_TIME. */ } SyncMethod; CLUTTER_AVAILABLE_IN_MUFFIN SyncMethod _clutter_get_sync_method (void); CLUTTER_AVAILABLE_IN_MUFFIN void _clutter_set_sync_method (SyncMethod sync_method); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_set_custom_backend_func (ClutterBackend *(* func) (void)); CLUTTER_AVAILABLE_IN_MUFFIN gboolean _clutter_get_sync_to_vblank (void); CLUTTER_AVAILABLE_IN_MUFFIN void _clutter_set_sync_to_vblank (gboolean sync_to_vblank); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_master_clock_set_sync_method (SyncMethod method); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_stage_x11_update_sync_state (ClutterStage *stage, SyncMethod method); CLUTTER_AVAILABLE_IN_MUFFIN int64_t clutter_stage_get_frame_counter (ClutterStage *stage); CLUTTER_AVAILABLE_IN_MUFFIN void clutter_stage_capture_into (ClutterStage *stage, gboolean paint, cairo_rectangle_int_t *rect, uint8_t *data); #undef __CLUTTER_H_INSIDE__ #endif /* __CLUTTER_MUFFIN_H__ */ muffin-5.2.1/clutter/clutter/clutter-interval.h0000664000175000017500000001431414211404421021760 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2008 Intel Corporation. * * 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, see . * * Author: * Emmanuele Bassi */ #ifndef __CLUTTER_INTERVAL_H__ #define __CLUTTER_INTERVAL_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_INTERVAL (clutter_interval_get_type ()) #define CLUTTER_INTERVAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INTERVAL, ClutterInterval)) #define CLUTTER_IS_INTERVAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INTERVAL)) #define CLUTTER_INTERVAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_INTERVAL, ClutterIntervalClass)) #define CLUTTER_IS_INTERVAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_INTERVAL)) #define CLUTTER_INTERVAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_INTERVAL, ClutterIntervalClass)) typedef struct _ClutterIntervalPrivate ClutterIntervalPrivate; typedef struct _ClutterIntervalClass ClutterIntervalClass; /** * ClutterInterval: * * The #ClutterInterval structure contains only private data and should * be accessed using the provided functions. * * Since: 1.0 */ struct _ClutterInterval { /*< private >*/ GInitiallyUnowned parent_instance; ClutterIntervalPrivate *priv; }; /** * ClutterIntervalClass: * @validate: virtual function for validating an interval * using a #GParamSpec * @compute_value: virtual function for computing the value * inside an interval using an adimensional factor between 0 and 1 * * The #ClutterIntervalClass contains only private data. * * Since: 1.0 */ struct _ClutterIntervalClass { /*< private >*/ GInitiallyUnownedClass parent_class; /*< public >*/ gboolean (* validate) (ClutterInterval *interval, GParamSpec *pspec); gboolean (* compute_value) (ClutterInterval *interval, gdouble factor, GValue *value); /*< private >*/ /* padding for future expansion */ void (*_clutter_reserved1) (void); void (*_clutter_reserved2) (void); void (*_clutter_reserved3) (void); void (*_clutter_reserved4) (void); void (*_clutter_reserved5) (void); void (*_clutter_reserved6) (void); }; CLUTTER_AVAILABLE_IN_1_0 GType clutter_interval_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterInterval *clutter_interval_new (GType gtype, ...); CLUTTER_AVAILABLE_IN_1_0 ClutterInterval *clutter_interval_new_with_values (GType gtype, const GValue *initial, const GValue *final); CLUTTER_AVAILABLE_IN_1_0 ClutterInterval *clutter_interval_clone (ClutterInterval *interval); CLUTTER_AVAILABLE_IN_1_0 GType clutter_interval_get_value_type (ClutterInterval *interval); CLUTTER_AVAILABLE_IN_1_10 void clutter_interval_set_initial (ClutterInterval *interval, ...); CLUTTER_AVAILABLE_IN_1_0 void clutter_interval_set_initial_value (ClutterInterval *interval, const GValue *value); CLUTTER_AVAILABLE_IN_1_0 void clutter_interval_get_initial_value (ClutterInterval *interval, GValue *value); CLUTTER_AVAILABLE_IN_1_0 GValue * clutter_interval_peek_initial_value (ClutterInterval *interval); CLUTTER_AVAILABLE_IN_1_10 void clutter_interval_set_final (ClutterInterval *interval, ...); CLUTTER_AVAILABLE_IN_1_0 void clutter_interval_set_final_value (ClutterInterval *interval, const GValue *value); CLUTTER_AVAILABLE_IN_1_0 void clutter_interval_get_final_value (ClutterInterval *interval, GValue *value); CLUTTER_AVAILABLE_IN_1_0 GValue * clutter_interval_peek_final_value (ClutterInterval *interval); CLUTTER_AVAILABLE_IN_1_0 void clutter_interval_set_interval (ClutterInterval *interval, ...); CLUTTER_AVAILABLE_IN_1_0 void clutter_interval_get_interval (ClutterInterval *interval, ...); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_interval_validate (ClutterInterval *interval, GParamSpec *pspec); CLUTTER_AVAILABLE_IN_1_0 gboolean clutter_interval_compute_value (ClutterInterval *interval, gdouble factor, GValue *value); CLUTTER_AVAILABLE_IN_1_4 const GValue * clutter_interval_compute (ClutterInterval *interval, gdouble factor); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_interval_is_valid (ClutterInterval *interval); G_END_DECLS #endif /* __CLUTTER_INTERVAL_H__ */ muffin-5.2.1/clutter/clutter/clutter-timeline.h0000664000175000017500000003065714211404421021752 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 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, see . */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #ifndef __CLUTTER_TIMELINE_H__ #define __CLUTTER_TIMELINE_H__ #include G_BEGIN_DECLS #define CLUTTER_TYPE_TIMELINE (clutter_timeline_get_type ()) #define CLUTTER_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TIMELINE, ClutterTimeline)) #define CLUTTER_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TIMELINE, ClutterTimelineClass)) #define CLUTTER_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TIMELINE)) #define CLUTTER_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TIMELINE)) #define CLUTTER_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TIMELINE, ClutterTimelineClass)) typedef struct _ClutterTimelineClass ClutterTimelineClass; typedef struct _ClutterTimelinePrivate ClutterTimelinePrivate; /** * ClutterTimelineProgressFunc: * @timeline: a #ClutterTimeline * @elapsed: the elapsed time, in milliseconds * @total: the total duration of the timeline, in milliseconds, * @user_data: data passed to the function * * A function for defining a custom progress. * * Return value: the progress, as a floating point value between -1.0 and 2.0. * * Since: 1.10 */ typedef gdouble (* ClutterTimelineProgressFunc) (ClutterTimeline *timeline, gdouble elapsed, gdouble total, gpointer user_data); /** * ClutterTimeline: * * The #ClutterTimeline structure contains only private data * and should be accessed using the provided API * * Since: 0.2 */ struct _ClutterTimeline { /*< private >*/ GObject parent_instance; ClutterTimelinePrivate *priv; }; /** * ClutterTimelineClass: * @started: class handler for the #ClutterTimeline::started signal * @completed: class handler for the #ClutterTimeline::completed signal * @paused: class handler for the #ClutterTimeline::paused signal * @new_frame: class handler for the #ClutterTimeline::new-frame signal * @marker_reached: class handler for the #ClutterTimeline::marker-reached signal * @stopped: class handler for the #ClutterTimeline::stopped signal * * The #ClutterTimelineClass structure contains only private data * * Since: 0.2 */ struct _ClutterTimelineClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ void (*started) (ClutterTimeline *timeline); void (*completed) (ClutterTimeline *timeline); void (*paused) (ClutterTimeline *timeline); void (*new_frame) (ClutterTimeline *timeline, gint msecs); void (*marker_reached) (ClutterTimeline *timeline, const gchar *marker_name, gint msecs); void (*stopped) (ClutterTimeline *timeline, gboolean is_finished); /*< private >*/ void (*_clutter_timeline_1) (void); void (*_clutter_timeline_2) (void); void (*_clutter_timeline_3) (void); void (*_clutter_timeline_4) (void); }; CLUTTER_AVAILABLE_IN_ALL GType clutter_timeline_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_ALL ClutterTimeline * clutter_timeline_new (guint msecs); CLUTTER_AVAILABLE_IN_ALL guint clutter_timeline_get_duration (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_set_duration (ClutterTimeline *timeline, guint msecs); CLUTTER_AVAILABLE_IN_ALL ClutterTimelineDirection clutter_timeline_get_direction (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_set_direction (ClutterTimeline *timeline, ClutterTimelineDirection direction); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_start (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_pause (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_stop (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_1_6 void clutter_timeline_set_auto_reverse (ClutterTimeline *timeline, gboolean reverse); CLUTTER_AVAILABLE_IN_1_6 gboolean clutter_timeline_get_auto_reverse (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_1_10 void clutter_timeline_set_repeat_count (ClutterTimeline *timeline, gint count); CLUTTER_AVAILABLE_IN_1_10 gint clutter_timeline_get_repeat_count (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_rewind (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_skip (ClutterTimeline *timeline, guint msecs); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_advance (ClutterTimeline *timeline, guint msecs); CLUTTER_AVAILABLE_IN_ALL guint clutter_timeline_get_elapsed_time (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL gdouble clutter_timeline_get_progress (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_timeline_is_playing (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_set_delay (ClutterTimeline *timeline, guint msecs); CLUTTER_AVAILABLE_IN_ALL guint clutter_timeline_get_delay (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_ALL guint clutter_timeline_get_delta (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_1_14 void clutter_timeline_add_marker (ClutterTimeline *timeline, const gchar *marker_name, gdouble progress); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_add_marker_at_time (ClutterTimeline *timeline, const gchar *marker_name, guint msecs); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_remove_marker (ClutterTimeline *timeline, const gchar *marker_name); CLUTTER_AVAILABLE_IN_ALL gchar ** clutter_timeline_list_markers (ClutterTimeline *timeline, gint msecs, gsize *n_markers) G_GNUC_MALLOC; CLUTTER_AVAILABLE_IN_ALL gboolean clutter_timeline_has_marker (ClutterTimeline *timeline, const gchar *marker_name); CLUTTER_AVAILABLE_IN_ALL void clutter_timeline_advance_to_marker (ClutterTimeline *timeline, const gchar *marker_name); CLUTTER_AVAILABLE_IN_1_10 void clutter_timeline_set_progress_func (ClutterTimeline *timeline, ClutterTimelineProgressFunc func, gpointer data, GDestroyNotify notify); CLUTTER_AVAILABLE_IN_1_10 void clutter_timeline_set_progress_mode (ClutterTimeline *timeline, ClutterAnimationMode mode); CLUTTER_AVAILABLE_IN_1_10 ClutterAnimationMode clutter_timeline_get_progress_mode (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_1_12 void clutter_timeline_set_step_progress (ClutterTimeline *timeline, gint n_steps, ClutterStepMode step_mode); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_timeline_get_step_progress (ClutterTimeline *timeline, gint *n_steps, ClutterStepMode *step_mode); CLUTTER_AVAILABLE_IN_1_12 void clutter_timeline_set_cubic_bezier_progress (ClutterTimeline *timeline, const ClutterPoint *c_1, const ClutterPoint *c_2); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_timeline_get_cubic_bezier_progress (ClutterTimeline *timeline, ClutterPoint *c_1, ClutterPoint *c_2); CLUTTER_AVAILABLE_IN_1_10 gint64 clutter_timeline_get_duration_hint (ClutterTimeline *timeline); CLUTTER_AVAILABLE_IN_1_10 gint clutter_timeline_get_current_repeat (ClutterTimeline *timeline); G_END_DECLS #endif /* _CLUTTER_TIMELINE_H__ */ muffin-5.2.1/clutter/clutter/clutter-backend-private.h0000664000175000017500000001762414211404421023202 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright (C) 2010 Intel Corporation. * * 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, see . */ #ifndef __CLUTTER_BACKEND_PRIVATE_H__ #define __CLUTTER_BACKEND_PRIVATE_H__ #include #include #include #include "clutter-event-translator.h" #define CLUTTER_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND, ClutterBackendClass)) #define CLUTTER_IS_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND)) #define CLUTTER_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND, ClutterBackendClass)) G_BEGIN_DECLS typedef struct _ClutterBackendPrivate ClutterBackendPrivate; struct _ClutterBackend { /*< private >*/ GObject parent_instance; CoglRenderer *cogl_renderer; CoglDisplay *cogl_display; CoglContext *cogl_context; GSource *cogl_source; CoglOnscreen *dummy_onscreen; ClutterDeviceManager *device_manager; cairo_font_options_t *font_options; gchar *font_name; gfloat units_per_em; gint32 units_serial; GList *event_translators; ClutterInputMethod *input_method; }; struct _ClutterBackendClass { /*< private >*/ GObjectClass parent_class; /* vfuncs */ gboolean (* pre_parse) (ClutterBackend *backend, GError **error); gboolean (* post_parse) (ClutterBackend *backend, GError **error); ClutterStageWindow * (* create_stage) (ClutterBackend *backend, ClutterStage *wrapper, GError **error); void (* init_events) (ClutterBackend *backend); void (* init_features) (ClutterBackend *backend); void (* add_options) (ClutterBackend *backend, GOptionGroup *group); ClutterFeatureFlags (* get_features) (ClutterBackend *backend); CoglRenderer * (* get_renderer) (ClutterBackend *backend, GError **error); CoglDisplay * (* get_display) (ClutterBackend *backend, CoglRenderer *renderer, CoglSwapChain *swap_chain, GError **error); gboolean (* create_context) (ClutterBackend *backend, GError **error); ClutterDeviceManager *(* get_device_manager) (ClutterBackend *backend); void (* copy_event_data) (ClutterBackend *backend, const ClutterEvent *src, ClutterEvent *dest); void (* free_event_data) (ClutterBackend *backend, ClutterEvent *event); gboolean (* translate_event) (ClutterBackend *backend, gpointer native, ClutterEvent *event); PangoDirection (* get_keymap_direction) (ClutterBackend *backend); void (* bell_notify) (ClutterBackend *backend); /* signals */ void (* resolution_changed) (ClutterBackend *backend); void (* font_changed) (ClutterBackend *backend); void (* settings_changed) (ClutterBackend *backend); }; ClutterBackend * _clutter_create_backend (void); ClutterStageWindow * _clutter_backend_create_stage (ClutterBackend *backend, ClutterStage *wrapper, GError **error); gboolean _clutter_backend_create_context (ClutterBackend *backend, GError **error); void _clutter_backend_add_options (ClutterBackend *backend, GOptionGroup *group); gboolean _clutter_backend_pre_parse (ClutterBackend *backend, GError **error); gboolean _clutter_backend_post_parse (ClutterBackend *backend, GError **error); void _clutter_backend_init_events (ClutterBackend *backend); void _clutter_backend_copy_event_data (ClutterBackend *backend, const ClutterEvent *src, ClutterEvent *dest); void _clutter_backend_free_event_data (ClutterBackend *backend, ClutterEvent *event); gboolean _clutter_backend_translate_event (ClutterBackend *backend, gpointer native, ClutterEvent *event); CLUTTER_AVAILABLE_IN_MUFFIN void _clutter_backend_add_event_translator (ClutterBackend *backend, ClutterEventTranslator *translator); void _clutter_backend_remove_event_translator (ClutterBackend *backend, ClutterEventTranslator *translator); ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend); gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend, PangoFontDescription *font_desc); gint32 _clutter_backend_get_units_serial (ClutterBackend *backend); PangoDirection _clutter_backend_get_keymap_direction (ClutterBackend *backend); CLUTTER_AVAILABLE_IN_MUFFIN void _clutter_backend_reset_cogl_framebuffer (ClutterBackend *backend); void clutter_set_allowed_drivers (const char *drivers); void clutter_try_set_windowing_backend (const char *drivers); G_END_DECLS #endif /* __CLUTTER_BACKEND_PRIVATE_H__ */ muffin-5.2.1/clutter/clutter/clutter-input-device.h0000664000175000017500000002247114211404421022533 0ustar jpeisachjpeisach/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 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, see . * * Author: Emmanuele Bassi */ #ifndef __CLUTTER_INPUT_DEVICE_H__ #define __CLUTTER_INPUT_DEVICE_H__ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define CLUTTER_TYPE_INPUT_DEVICE (clutter_input_device_get_type ()) #define CLUTTER_INPUT_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDevice)) #define CLUTTER_IS_INPUT_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE)) #define CLUTTER_INPUT_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDeviceClass)) #define CLUTTER_IS_INPUT_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_INPUT_DEVICE)) #define CLUTTER_INPUT_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDeviceClass)) /** * ClutterInputDevice: * * Generic representation of an input device. The actual contents of this * structure depend on the backend used. */ typedef struct _ClutterInputDeviceClass ClutterInputDeviceClass; CLUTTER_AVAILABLE_IN_1_0 GType clutter_input_device_get_type (void) G_GNUC_CONST; CLUTTER_AVAILABLE_IN_1_0 ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_0 gint clutter_input_device_get_device_id (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_12 gboolean clutter_input_device_get_coords (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterPoint *point); CLUTTER_AVAILABLE_IN_1_16 ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 ClutterActor * clutter_input_device_get_pointer_actor (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 void clutter_input_device_set_enabled (ClutterInputDevice *device, gboolean enabled); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_input_device_get_enabled (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 guint clutter_input_device_get_n_axes (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 ClutterInputAxis clutter_input_device_get_axis (ClutterInputDevice *device, guint index_); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_input_device_get_axis_value (ClutterInputDevice *device, gdouble *axes, ClutterInputAxis axis, gdouble *value); CLUTTER_AVAILABLE_IN_1_2 guint clutter_input_device_get_n_keys (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 void clutter_input_device_set_key (ClutterInputDevice *device, guint index_, guint keyval, ClutterModifierType modifiers); CLUTTER_AVAILABLE_IN_1_2 gboolean clutter_input_device_get_key (ClutterInputDevice *device, guint index_, guint *keyval, ClutterModifierType *modifiers); CLUTTER_AVAILABLE_IN_1_2 ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 GList * clutter_input_device_get_slave_devices (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_2 void clutter_input_device_update_from_event (ClutterInputDevice *device, ClutterEvent *event, gboolean update_stage); CLUTTER_AVAILABLE_IN_1_10 void clutter_input_device_grab (ClutterInputDevice *device, ClutterActor *actor); CLUTTER_AVAILABLE_IN_1_10 void clutter_input_device_ungrab (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_10 ClutterActor * clutter_input_device_get_grabbed_actor (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_12 void clutter_input_device_sequence_grab (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterActor *actor); CLUTTER_AVAILABLE_IN_1_12 void clutter_input_device_sequence_ungrab (ClutterInputDevice *device, ClutterEventSequence *sequence); CLUTTER_AVAILABLE_IN_1_12 ClutterActor * clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice *device, ClutterEventSequence *sequence); CLUTTER_AVAILABLE_IN_1_10 gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device, guint hardware_keycode, guint *evdev_keycode); CLUTTER_AVAILABLE_IN_1_22 const gchar * clutter_input_device_get_vendor_id (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_1_22 const gchar * clutter_input_device_get_product_id (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_ALL gint clutter_input_device_get_n_rings (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_ALL gint clutter_input_device_get_n_strips (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_ALL gint clutter_input_device_get_n_mode_groups (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_ALL gint clutter_input_device_get_group_n_modes (ClutterInputDevice *device, gint group); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_input_device_is_mode_switch_button (ClutterInputDevice *device, guint group, guint button); CLUTTER_AVAILABLE_IN_ALL gint clutter_input_device_get_mode_switch_button_group (ClutterInputDevice *device, guint button); CLUTTER_AVAILABLE_IN_ALL const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_ALL ClutterInputDeviceMapping clutter_input_device_get_mapping_mode (ClutterInputDevice *device); CLUTTER_AVAILABLE_IN_ALL void clutter_input_device_set_mapping_mode (ClutterInputDevice *device, ClutterInputDeviceMapping mapping); CLUTTER_AVAILABLE_IN_ALL gboolean clutter_input_device_is_grouped (ClutterInputDevice *device, ClutterInputDevice *other_device); G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_H__ */ muffin-5.2.1/clutter/configure.ac0000664000175000017500000007340314211404421017113 0ustar jpeisachjpeisach# clutter package version number, (as distinct from shared library version) # An odd micro number indicates in-progress development from Git # An even micro number indicates a released version # # Making a point release: # - increase clutter_micro_version to the next even number # - increase clutter_interface_age to the next even number # After the release: # - increase clutter_micro_version to the next odd number # - increase clutter_interface_version to the next odd number m4_define([clutter_major_version], [1]) m4_define([clutter_minor_version], [26]) m4_define([clutter_micro_version], [1]) # • for stable releases: increase the interface age by 1 for each release; # if the API changes, set to 0. interface_age and binary_age are used to # create the soname of the shared object: # # ( * 100 + ) - # # this allows using the same soname for different micro-releases in case # no API was added or deprecated. for instance: # # clutter 1.2.0 -> 100 * 2 + 0 = 200, interface age = 0 -> 200 # clutter 1.2.2 -> 100 * 2 + 2 = 202, interface age = 2 -> 200 # clutter 1.2.4 -> 100 * 2 + 4 = 204, interface age = 4 -> 200 # [ API addition, deprecation ] # clutter 1.2.6 -> 100 * 2 + 6 = 206, interface age = 0 -> 206 # clutter 1.2.8 -> 100 * 2 + 8 = 208, interface age = 2 -> 206 # clutter 1.2.10 -> 100 * 2 + 10 = 210, interface age = 4 -> 206 # ... # # • for development releases: keep clutter_interface_age to 0 m4_define([clutter_interface_age], [1]) m4_define([clutter_binary_age], [m4_eval(100 * clutter_minor_version + clutter_micro_version)]) m4_define([clutter_release_status], [m4_if(m4_eval(clutter_micro_version % 2), [1], [git], [m4_if(m4_eval(clutter_minor_version % 2), [1], [snapshot], [release])])]) m4_define([clutter_version], [clutter_major_version.clutter_minor_version.clutter_micro_version]) AC_PREREQ([2.63]) AC_INIT([clutter], [clutter_version], [http://bugzilla.gnome.org/enter_bug.cgi?product=clutter], [clutter], [http://www.clutter-project.org]) AC_CONFIG_SRCDIR([clutter/clutter.h]) AC_CONFIG_HEADERS([clutter/clutter-build-config.h]) AC_CONFIG_AUX_DIR([build]) AC_CONFIG_MACRO_DIR([build/autotools]) AM_INIT_AUTOMAKE([1.11 foreign -Wno-portability no-define no-dist-gzip dist-xz tar-ustar]) AM_SILENT_RULES([yes]) dnl = Check that we are configured by muffin ============================== AC_ARG_VAR([MUFFIN_VERSION]) AC_ARG_VAR([MUFFIN_PLUGIN_API_VERSION]) AS_IF([test "x$MUFFIN_VERSION" = "x"], [AC_MSG_ERROR([Clutter can only be configured by muffin])],) AC_SUBST([CLUTTER_MAJOR_VERSION], [clutter_major_version]) AC_SUBST([CLUTTER_MINOR_VERSION], [clutter_minor_version]) AC_SUBST([CLUTTER_MICRO_VERSION], [clutter_micro_version]) AC_SUBST([CLUTTER_VERSION], [clutter_version]) AC_SUBST([CLUTTER_RELEASE_STATUS], [clutter_release_status]) m4_define([lt_current], [m4_eval(100 * clutter_minor_version + clutter_micro_version - clutter_interface_age)]) m4_define([lt_revision], [clutter_interface_age]) m4_define([lt_age], [m4_eval(clutter_binary_age - clutter_interface_age)]) CLUTTER_LT_CURRENT=lt_current CLUTTER_LT_REV=lt_revision CLUTTER_LT_AGE=lt_age CLUTTER_LT_VERSION="$CLUTTER_LT_CURRENT:$CLUTTER_LT_REV:$CLUTTER_LT_AGE" CLUTTER_LT_LDFLAGS="-avoid-version" AC_SUBST([CLUTTER_LT_CURRENT], [lt_current]) AC_SUBST([CLUTTER_LT_REVISION], [lt_revision]) AC_SUBST([CLUTTER_LT_VERSION], [$CLUTTER_LT_VERSION]) AC_PROG_SED dnl = Preliminary platform checks ============================================= AC_CANONICAL_HOST AC_DEFINE([OS_LINUX], [1], [Define to 1 if building for Linux]) AC_SUBST(CLUTTER_LT_LDFLAGS) AC_CACHE_SAVE dnl = Dependencies ========================================================= # Checks for programs. AM_PROG_CC_C_O # require libtool >= 2.2 LT_PREREQ([2.2.6]) LT_INIT([disable-static]) LT_LIB_M # Checks for header files. AC_HEADER_STDC # required versions for dependencies m4_define([glib_req_version], [2.50.3]) m4_define([cogl_req_version], [1.21.2]) m4_define([json_glib_req_version], [0.12.0]) m4_define([atk_req_version], [2.5.3]) m4_define([cairo_req_version], [1.14.0]) m4_define([pango_req_version], [1.30]) m4_define([gi_req_version], [1.39.0]) m4_define([xcomposite_req_version], [0.4]) m4_define([gdk_req_version], [3.3.18]) m4_define([libinput_req_version], [1.4.0]) m4_define([libudev_req_version], [136]) m4_define([libwacom_req_version], [0.13]) AC_SUBST([GLIB_REQ_VERSION], [glib_req_version]) AC_SUBST([COGL_REQ_VERSION], [cogl_req_version]) AC_SUBST([JSON_GLIB_REQ_VERSION], [json_glib_req_version]) AC_SUBST([ATK_REQ_VERSION], [atk_req_version]) AC_SUBST([CAIRO_REQ_VERSION], [cairo_req_version]) AC_SUBST([PANGO_REQ_VERSION], [pango_req_version]) AC_SUBST([GI_REQ_VERSION], [gi_req_version]) AC_SUBST([XCOMPOSITE_REQ_VERSION], [xcomposite_req_version]) AC_SUBST([GDK_REQ_VERSION], [gdk_req_version]) AC_SUBST([LIBINPUT_REQ_VERSION], [libinput_req_version]) AC_SUBST([LIBUDEV_REQ_VERSION], [libudev_req_version]) AC_SUBST([LIBWACOM_REQ_VERSION], [libwacom_req_version]) # Checks for typedefs, structures, and compiler characteristics. AM_PATH_GLIB_2_0([glib_req_version], [], [AC_MSG_ERROR([glib-2.0 is required])], [gobject gio gthread gmodule-no-export]) # Check for -Bsymbolic-functions to avoid intra-library PLT jumps AC_ARG_ENABLE([Bsymbolic], [AS_HELP_STRING([--disable-Bsymbolic], [Avoid linking with -Bsymbolic])], [], [ saved_LDFLAGS="${LDFLAGS}" AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) LDFLAGS=-Wl,-Bsymbolic-functions AC_TRY_LINK([], [return 0], [ AC_MSG_RESULT([yes]) enable_Bsymbolic=yes ], [ AC_MSG_RESULT([no]) enable_Bsymbolic=no ]) LDFLAGS="${saved_LDFLAGS}" ]) AS_IF([test "x$enable_Bsymbolic" = "xyes"], [CLUTTER_LINK_FLAGS=-Wl[,]-Bsymbolic-functions]) AC_SUBST(CLUTTER_LINK_FLAGS) # Check for the visibility flags CLUTTER_HIDDEN_VISIBILITY_CFLAGS="" dnl on other compilers, check if we can do -fvisibility=hidden SAVED_CFLAGS="${CFLAGS}" CFLAGS="-fvisibility=hidden" AC_MSG_CHECKING([for -fvisibility=hidden compiler flag]) AC_TRY_COMPILE([], [return 0], AC_MSG_RESULT(yes) enable_fvisibility_hidden=yes, AC_MSG_RESULT(no) enable_fvisibility_hidden=no) CFLAGS="${SAVED_CFLAGS}" AS_IF([test "${enable_fvisibility_hidden}" = "yes"], [ AC_DEFINE([_CLUTTER_EXTERN], [__attribute__((visibility("default"))) extern], [defines how to decorate public symbols while building]) CLUTTER_HIDDEN_VISIBILITY_CFLAGS="-fvisibility=hidden" ]) AC_SUBST(CLUTTER_HIDDEN_VISIBILITY_CFLAGS) AC_CACHE_SAVE dnl ======================================================================== FLAVOUR_LIBS="" FLAVOUR_CFLAGS="" CLUTTER_BACKENDS="" CLUTTER_INPUT_BACKENDS="" CLUTTER_CONFIG_DEFINES= # base dependencies for core CLUTTER_BASE_PC_FILES="cairo-gobject >= $CAIRO_REQ_VERSION gio-2.0 >= glib_req_version atk >= $ATK_REQ_VERSION pangocairo >= $PANGO_REQ_VERSION json-glib-1.0 >= $JSON_GLIB_REQ_VERSION" # private base dependencies CLUTTER_BASE_PC_FILES_PRIVATE="" # backend specific pkg-config files BACKEND_PC_FILES="" # private backend specific dependencies BACKEND_PC_FILES_PRIVATE="" dnl === Clutter windowing system backend ====================================== CLUTTER_BACKENDS="$CLUTTER_BACKENDS x11" CLUTTER_INPUT_BACKENDS="$CLUTTER_INPUT_BACKENDS x11" SUPPORT_X11=1 SUPPORT_GLX=1 SUPPORT_COGL=1 # we use fontconfig API and pango-ft2 when the fontconfig # configuration changes; we don't expose any API for this # so we add pango-ft2 to the private Requires. PKG_CHECK_EXISTS([pangoft2], [ AC_DEFINE([HAVE_PANGO_FT2], [1], [Supports PangoFt2]) BACKEND_PC_FILES_PRIVATE="$BACKEND_PC_FILES_PRIVATE pangoft2" ], []) AC_ARG_ENABLE( [wayland-egl-server], [AC_HELP_STRING([--enable-wayland-egl-server=@<:@no/yes@:>@], [Enable server side wayland support @<:@default=no@:>@])], [], enable_wayland_egl_server=no ) AS_IF([test "x$enable_wayland_egl_server" = "xyes"], [ CLUTTER_BACKENDS="$CLUTTER_BACKENDS egl" SUPPORT_EGL=1 AC_DEFINE([CLUTTER_EGL_BACKEND_GENERIC], [1], [Use Generic EGL backend]) BACKEND_PC_FILES="$BACKEND_PC_FILES wayland-egl wayland-server libdrm gbm" SUPPORT_WAYLAND_COMPOSITOR=1 CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES #define CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT 1" CLUTTER_INPUT_BACKENDS="$CLUTTER_INPUT_BACKENDS evdev" SUPPORT_EVDEV=1 BACKEND_PC_FILES_PRIVATE="$BACKEND_PC_FILES_PRIVATE libudev >= $LIBUDEV_REQ_VERSION libinput >= $LIBINPUT_REQ_VERSION xkbcommon" AC_DEFINE([HAVE_EVDEV], [1], [Have evdev support for input handling]) ]) AM_CONDITIONAL(SUPPORT_WAYLAND, [test "x$enable_wayland_egl_server" = "xyes"]) AC_DEFINE_UNQUOTED([CLUTTER_DRIVERS], ["*"], [List of Cogl drivers]) dnl strip leading spaces CLUTTER_BACKENDS=${CLUTTER_BACKENDS#* } AC_SUBST(CLUTTER_BACKENDS) CLUTTER_INPUT_BACKENDS=${CLUTTER_INPUT_BACKENDS#* } AC_SUBST(CLUTTER_INPUT_BACKENDS) AC_CACHE_SAVE dnl === Clutter configuration ================================================= # windowing systems AS_IF([test "x$SUPPORT_X11" = "x1"], [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES #define CLUTTER_WINDOWING_X11 \"x11\" #define CLUTTER_INPUT_X11 \"x11\""]) AS_IF([test "x$SUPPORT_GLX" = "x1"], [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES #define CLUTTER_WINDOWING_GLX \"glx\""]) AS_IF([test "x$SUPPORT_EGL" = "x1"], [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES #define CLUTTER_WINDOWING_EGL \"eglnative\""]) AS_IF([test "x$SUPPORT_EVDEV" = "x1"], [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES #define CLUTTER_INPUT_EVDEV \"evdev\""]) # the 'null' input backend is special CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES #define CLUTTER_INPUT_NULL \"null\"" AC_SUBST([CLUTTER_CONFIG_DEFINES]) dnl === Clutter substitutions kept for backwards compatibility ================ AC_SUBST([CLUTTER_WINSYS], [deprecated]) AC_SUBST([CLUTTER_WINSYS_BASE], [deprecated]) AC_SUBST([CLUTTER_STAGE_TYPE], [deprecated]) AC_SUBST([CLUTTER_SONAME_INFIX], [deprecated]) AC_SUBST([CLUTTER_FLAVOUR], [deprecated]) AC_SUBST([CLUTTER_COGL], [deprecated]) AC_SUBST([COGL_DRIVER], [deprecated]) dnl === X11 checks, only for X11-based backends =============================== X11_PC_FILES="" X11_EXTS="" x11_tests=no AS_IF([test "x$SUPPORT_X11" = "x1"], [ # base X11 includes and libraries AC_MSG_CHECKING([for X11]) # start with pkg-config PKG_CHECK_EXISTS([x11], [have_x11=yes], [have_x11=no]) AS_IF([test "x$have_x11" = "xyes"], [ X11_PC_FILES="x11" # we actually need to ask for CFLAGS and LIBS X11_CFLAGS=`$PKG_CONFIG --cflags $X11_PC_FILES` X11_LIBS=`$PKG_CONFIG --libs $X11_PC_FILES` AC_MSG_RESULT([found]) ], [ # no pkg-config, let's go old school AC_PATH_X AS_IF([test "x$no_x" = "xyes"], [AC_MSG_ERROR([No X11 Libraries found])], [ AS_IF([test "x$x_includes" != "xNONE" && test -n "$x_includes"], [X11_CFLAGS=-I`echo $x_includes | sed -e "s/:/ -I/g"`]) AS_IF([test "x$x_libraries" != "xNONE" && test -n "$x_libraries"], [X11_LIBS=-L`echo $x_libraries | sed -e "s/:/ -L/g"`]) AC_MSG_RESULT([found]) ] ) ] ) # XEXT (required) AC_MSG_CHECKING([for XEXT extension]) PKG_CHECK_EXISTS([xext], [have_xext=yes], [have_xext=no]) AS_IF([test "x$have_xext" = "xyes"], [ AC_DEFINE(HAVE_XEXT, [1], [Define to 1 if we have the XEXT X extension]) X11_LIBS="$X11_LIBS -lXext" X11_PC_FILES="$X11_PC_FILES xext" X11_EXTS="$X11_EXTS xext" AC_MSG_RESULT([found]) ], [AC_MSG_ERROR([Not found])] ) # XDAMAGE (required) AC_MSG_CHECKING([for XDAMAGE extension]) PKG_CHECK_EXISTS([xdamage], [have_xdamage=yes], [have_xdamage=no]) AS_IF([test "x$have_xdamage" = "xyes"], [ AC_DEFINE(HAVE_XDAMAGE, [1], [Define to 1 if we have the XDAMAGE X extension]) X11_LIBS="$X11_LIBS -lXdamage" X11_PC_FILES="$X11_PC_FILES xdamage" X11_EXTS="$X11_EXTS xdamage" AC_MSG_RESULT([found]) ], [AC_MSG_ERROR([not found])] ) # XCOMPOSITE (optional) AC_MSG_CHECKING([for XCOMPOSITE extension >= $XCOMPOSITE_REQ_VERSION]) PKG_CHECK_EXISTS([xcomposite >= $XCOMPOSITE_REQ_VERSION], [have_xcomposite=yes], [have_xcomposite=no]) AS_IF([test "x$have_xcomposite" = "xyes"], [ AC_DEFINE(HAVE_XCOMPOSITE, [1], [Define to 1 if we have the XCOMPOSITE X extension]) X11_LIBS="$X11_LIBS -lXcomposite" X11_PC_FILES="$X11_PC_FILES xcomposite >= $XCOMPOSITE_REQ_VERSION" X11_EXTS="$X11_EXTS xcomposite" AC_MSG_RESULT([found]) ], [AC_MSG_ERROR([not found])] ) # XTEST (required) AC_MSG_CHECKING([for XTest extension]) PKG_CHECK_EXISTS([xtst], [have_xtest=yes], [have_xtest=no]) AS_IF([test "x$have_xtest" = "xyes"], [ AC_DEFINE(HAVE_XTEST, [1], [Define to 1 if we have the XTest X extension]) X11_LIBS="$X11_LIBS -lXtst" X11_PC_FILES="$X11_PC_FILES xtst" X11_EXTS="$X11_EXTS xtst" AC_MSG_RESULT([found]) ], [AC_MSG_ERROR([Not found])] ) # X Generic Extensions (optional) clutter_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $X11_CFLAGS" clutter_save_LIBS="$LIBS" LIBS="$LIBS $X11_LIBS" have_xge=no AC_CHECK_FUNC([XGetEventData], [ AC_DEFINE([HAVE_XGE], [1], [Define to 1 if X Generic Extensions is available]) have_xge=yes X11_EXTS="$X11_EXTS xge" ]) CPPFLAGS="$clutter_save_CPPFLAGS" LIBS="$clutter_save_LIBS" # XI (optional) AC_ARG_ENABLE([xinput], [AS_HELP_STRING([--enable-xinput], [Use the XI X extension])], [], [enable_xinput=yes]) AS_IF([test "x$enable_xinput" = "xyes"], [ PKG_CHECK_EXISTS([xi], [have_xinput=yes], [have_xinput=no]) ], [ have_xinput=no ]) AS_CASE([$have_xinput], [yes], [ AC_CHECK_HEADERS([X11/extensions/XInput2.h], [ have_xinput2=yes AC_DEFINE([HAVE_XINPUT_2], [1], [Define to 1 if XI2 is available]) ]) clutter_save_LIBS="$LIBS" LIBS="$LIBS -lXi" AC_CHECK_FUNC([XIAllowTouchEvents], [ AC_CHECK_MEMBER([XIScrollClassInfo.number], [ have_xinput_2_2=yes AC_DEFINE([HAVE_XINPUT_2_2], [1], [Define to 1 if XInput 2.2 is available]) ], [have_xinput_2_2=no], [[#include ]])]) LIBS="$clutter_save_LIBS" X11_LIBS="$X11_LIBS $XINPUT_LIBS" X11_PC_FILES="$X11_PC_FILES xi" AS_IF([test "x$have_xinput_2_2" = "xyes"], [X11_EXTS="$X11_EXTS xi2.2"], [X11_EXTS="$X11_EXTS xi2.0"]) ], [no], [have_xinput2=no], [*], [AC_MSG_ERROR([Invalid argument for --enable-xinput])] ) # XKB clutter_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $X11_CFLAGS" clutter_save_LIBS="$LIBS" LIBS="$LIBS $X11_LIBS" have_xkb=no AC_CHECK_FUNC([XkbQueryExtension], [ AC_DEFINE(HAVE_XKB, 1, [Define to use XKB extension]) have_xkb=yes X11_EXTS="$X11_EXTS xkb" ]) CPPFLAGS="$clutter_save_CPPFLAGS" LIBS="$clutter_save_LIBS" x11_tests=yes BACKEND_PC_FILES="$BACKEND_PC_FILES $X11_PC_FILES" FLAVOUR_LIBS="$FLAVOUR_LIBS $X11_LIBS" FLAVOUR_CFLAGS="$FLAVOUR_CFLAGS $X11_CFLAGS" ] ) AM_CONDITIONAL([BUILD_XI2], [test "x$have_xinput2" = "xyes"]) AM_CONDITIONAL([X11_TESTS], [test "x$x11_tests" = "xyes"]) X11_EXTS=${X11_EXTS#* } AC_CACHE_SAVE dnl === Libwacom support for X11 =============================================== AC_ARG_WITH(libwacom, AC_HELP_STRING([--without-libwacom], [disable the use of libwacom for advanced tablet management]),, with_libwacom=auto) have_libwacom=no AC_MSG_CHECKING([libwacom]) if test x$with_libwacom = xno ; then AC_MSG_RESULT([disabled]) else if $PKG_CONFIG --exists libwacom '>=' $LIBWACOM_REQ_VERSION; then have_libwacom=yes AC_MSG_RESULT(yes) PKG_CHECK_MODULES([LIBWACOM], [libwacom]) AC_SUBST(LIBWACOM_CFLAGS) AC_SUBST(LIBWACOM_LIBS) AC_DEFINE([HAVE_LIBWACOM], 1, [Building with libwacom for advanced tablet management]) else AC_MSG_RESULT(no) if test x$with_libwacom = xyes ; then AC_MSG_ERROR([libwacom forced but not found]) fi fi fi dnl === Enable GDK-Pixbuf in tests ============================================ m4_define([pixbuf_default], [yes]) AC_ARG_ENABLE([gdk-pixbuf], [AS_HELP_STRING([--enable-gdk-pixbuf=@<:@no/yes@:>@], [Enable tests using GDK-Pixbuf @<:@default=]pixbuf_default[@:>@])], [enable_pixbuf=$enable_val], [enable_pixbuf=pixbuf_default]) AS_CASE([$enable_pixbuf], [yes], [ PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0]) AC_SUBST(GDK_PIXBUF_CFLAGS) AC_SUBST(GDK_PIXBUF_LIBS) pixbuf_tests=yes ], [no], [ pixbuf_tests=no ] ) AM_CONDITIONAL([PIXBUF_TESTS], [test "x$pixbuf_tests" = "xyes"]) dnl === Enable debug level ==================================================== m4_define([debug_default], [m4_if(m4_eval(clutter_minor_version % 2), [1], [yes], [minimum])]) AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug=@<:@no/minimum/yes@:>@], [Control Clutter debugging level @<:@default=]debug_default[@:>@])], [], [enable_debug=debug_default]) AS_CASE([$enable_debug], [yes], [ test "$cflags_set" = set || CFLAGS="$CFLAGS -g" CLUTTER_DEBUG_CFLAGS="-DCLUTTER_ENABLE_DEBUG" ], [minimum], [CLUTTER_DEBUG_CFLAGS="-DG_DISABLE_CAST_CHECKS"], [no], [CLUTTER_DEBUG_CFLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS"], [AC_MSG_ERROR([Unknown argument for --enable-debug])] ) AC_SUBST(CLUTTER_DEBUG_CFLAGS) dnl === Enable deprecation guards ================================================== m4_define([deprecated_default], [m4_if(m4_eval(clutter_minor_version % 2), [1], [no], [yes])]) AC_ARG_ENABLE([deprecated], [AS_HELP_STRING([--enable-deprecated=@<:@no/yes@:>@], [Whether deprecated symbols should be disabled when compiling Clutter @<:@default=]deprecated_default[@:>@])], [], [enable_deprecated=deprecated_default]) AS_CASE([$enable_deprecated], [no], [ CLUTTER_DEPRECATED_CFLAGS="-DG_DISABLE_SINGLE_INCLUDES -DCOGL_DISABLE_DEPRECATED" ], [yes], [ CLUTTER_DEPRECATED_CFLAGS="-DGLIB_DISABLE_DEPRECATION_WARNINGS" ], [AC_MSG_ERROR([Unknown argument for --enable-deprecated])] ) AC_SUBST([CLUTTER_DEPRECATED_CFLAGS]) dnl === Enable strict compiler flags ========================================== # use strict compiler flags only when building from git; the rules for # distcheck will take care of turning this on when making a release m4_define([maintainer_flags_default], [m4_if(m4_eval(clutter_micro_version % 2), [1], [yes], [no])]) AC_ARG_ENABLE([maintainer-flags], [AS_HELP_STRING([--enable-maintainer-flags=@<:@no/yes/error@:>@], [Use strict compiler flags @<:@default=]maintainer_flags_default[@:>@])], [], [enable_maintainer_flags=maintainer_flags_default]) MAINTAINER_COMPILER_FLAGS="$MAINTAINER_COMPILER_FLAGS -Wall -Wcast-align -Wuninitialized -Wno-strict-aliasing -Wshadow" AC_ARG_ENABLE([Werror], [AS_HELP_STRING([--disable-Werror], [Removes -Werror from compiler flags])], [], [enable_Werror=yes]) AS_IF([test "x$enable_Werror" = xyes], [ MAINTAINER_COMPILER_FLAGS="$MAINTAINER_COMPILER_FLAGS -Werror=logical-op -Werror=pointer-arith -Werror=missing-declarations -Werror=redundant-decls -Werror=empty-body -Werror=format -Werror=format-security -Werror=format-nonliteral -Werror=init-self -Werror=declaration-after-statement -Werror=vla" ]) AS_CASE([$enable_maintainer_flags], [yes], [ AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS]) ], [no], [ ], [error], [ MAINTAINER_COMPILER_FLAGS="$MAINTAINER_COMPILER_FLAGS -Werror" AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS]) ], [*], [AC_MSG_ERROR([Invalid option for --enable-maintainer-flags])] ) # strip leading spaces MAINTAINER_CFLAGS=${MAINTAINER_CFLAGS#* } AC_SUBST(MAINTAINER_CFLAGS) dnl === Dependencies, compiler flags and linker libraries ===================== # strip leading space BACKEND_PC_FILES=${BACKEND_PC_FILES#* } # public dependencies, will fill the Requires: field of clutter.pc CLUTTER_REQUIRES="$CLUTTER_BASE_PC_FILES $BACKEND_PC_FILES" PKG_CHECK_MODULES(CLUTTER_DEPS, [$CLUTTER_REQUIRES]) # private dependencies, will fill the Requires.private: field of clutter.pc AS_IF([test "x$CLUTTER_BASE_PC_FILES_PRIVATE" = "x" && test "x$BACKEND_PC_FILES_PRIVATE" = "x"], [ CLUTTER_REQUIRES_PRIVATE="" CLUTTER_DEPS_PRIVATE_CFLAGS="" CLUTTER_DEPS_PRIVATE_LIBS="" ], [ CLUTTER_REQUIRES_PRIVATE="$CLUTTER_BASE_PC_FILES_PRIVATE $BACKEND_PC_FILES_PRIVATE" PKG_CHECK_MODULES(CLUTTER_DEPS_PRIVATE, [$CLUTTER_REQUIRES_PRIVATE]) ]) AC_SUBST(CLUTTER_REQUIRES) AC_SUBST(CLUTTER_REQUIRES_PRIVATE) CLUTTER_CFLAGS="$FLAVOUR_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_DEPS_PRIVATE_CFLAGS $GLIB_CFLAGS $LIBWACOM_CFLAGS" CLUTTER_LIBS="$FLAVOUR_LIBS $CLUTTER_DEPS_LIBS $CLUTTER_DEPS_PRIVATE_LIBS $GLIB_LIBS $LIBWACOM_LIBS" AC_SUBST(CLUTTER_CFLAGS) AC_SUBST(CLUTTER_LIBS) dnl === Test coverage ========================================================= AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], [Enable gcov])], [use_gcov=$enableval], [use_gcov=no]) AS_IF([test "x$use_gcov" = "xyes"], [ dnl we need gcc: AS_IF([test "$GCC" != "yes"], [AC_MSG_ERROR([GCC is required for --enable-gcov])]) dnl Check if ccache is being used AC_CHECK_PROG(SHTOOL, shtool, shtool) AS_CASE([`$SHTOOL path $CC`], [*ccache*], [gcc_ccache=yes], [gcc_ccache=no]) if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) fi ltp_version_list="1.6 1.7 1.8 1.9 1.10" AC_CHECK_PROG(LTP, lcov, lcov) AC_CHECK_PROG(LTP_GENHTML, genhtml, genhtml) if test "$LTP"; then AC_CACHE_CHECK([for ltp version], clutter_cv_ltp_version, [ clutter_cv_ltp_version=invalid ltp_version=`$LTP -v 2>/dev/null | $SED -e 's/^.* //'` for ltp_check_version in $ltp_version_list; do if test "$ltp_version" = "$ltp_check_version"; then clutter_cv_ltp_version="$ltp_check_version (ok)" fi done ]) else ltp_msg="To enable code coverage reporting you must have one of the following LTP versions installed: $ltp_version_list" AC_MSG_ERROR([$ltp_msg]) fi case $clutter_cv_ltp_version in ""|invalid[)] ltp_msg="You must have one of the following versions of LTP: $ltp_version_list (found: $ltp_version)." AC_MSG_ERROR([$ltp_msg]) LTP="exit 0;" ;; esac if test -z "$LTP_GENHTML"; then AC_MSG_ERROR([Could not find genhtml from the LTP package]) fi AC_DEFINE(HAVE_GCOV, 1, [Whether you have gcov]) dnl Remove all optimization flags from CFLAGS changequote({,}) CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` CLUTTER_CFLAGS=`echo "$CLUTTER_CFLAGS" | $SED -e 's/-O[0-9]*//g'` changequote([,]) dnl Define the special gcc flags CLUTTER_GCOV_CFLAGS="-O0 -fprofile-arcs -ftest-coverage" CLUTTER_GCOV_LDADD="-lgcov" AC_SUBST(CLUTTER_GCOV_CFLAGS) AC_SUBST(CLUTTER_GCOV_LDADD) CLUTTER_CFLAGS="$CLUTTER_CFLAGS $CLUTTER_GCOV_CFLAGS" CLUTTER_LIBS="$CLUTTER_LIBS $CLUTTER_GCOV_LDADD" ]) AM_CONDITIONAL(ENABLE_GCOV, test "x$use_gcov" = "xyes") dnl === GObject-Introspection check =========================================== GOBJECT_INTROSPECTION_CHECK([gi_req_version]) dnl === Conformance test suite ================================================ GLIB_TESTS AC_ARG_ENABLE([examples], [AS_HELP_STRING([--enable-examples], [Whether examples should be built])], [], [enable_examples=no]) AM_CONDITIONAL(BUILD_EXAMPLES, [test "x$enable_examples" = "xyes"]) dnl =========================================================================== AC_CONFIG_FILES([ Makefile build/Makefile build/autotools/Makefile clutter/Makefile clutter/clutter-config.h clutter/clutter-version.h clutter/muffin-clutter-$MUFFIN_PLUGIN_API_VERSION.pc:clutter/muffin-clutter.pc.in tests/Makefile tests/accessibility/Makefile tests/conform/Makefile tests/interactive/Makefile tests/interactive/wrapper.sh tests/micro-bench/Makefile tests/performance/Makefile examples/Makefile ]) AC_OUTPUT dnl === Summary =============================================================== echo "" echo "Clutter - $VERSION (${CLUTTER_RELEASE_STATUS})" # Global flags echo "" echo " • Global:" echo " Prefix: ${prefix}" echo " Libdir: ${libdir}" echo " Sysconfdir: ${sysconfdir}" # Compiler/Debug related flags echo "" echo " • Compiler options:" echo " Clutter debug level: ${enable_debug}" echo " Compiler flags: ${CFLAGS} ${MAINTAINER_CFLAGS}" echo " Enable coverage tests: ${use_gcov}" echo " Enable deprecated symbols: ${enable_deprecated}" # Miscellaneous echo "" echo " • Extra:" echo " Build introspection data: ${enable_introspection}" if test "x$x11_tests" = "xyes"; then echo " Build X11-specific tests: ${x11_tests}" fi if test "x$pixbuf_tests" = "xyes"; then echo " Build tests using GDK-Pixbuf: ${pixbuf_tests}" fi echo " Install test suites: ${enable_installed_tests}" echo " Build examples: ${enable_examples}" # Clutter backend related flags echo "" echo " • Clutter Backends:" echo " Windowing systems: ${CLUTTER_BACKENDS}" echo " Input backends: ${CLUTTER_INPUT_BACKENDS}" if test "x$SUPPORT_X11" = "x1"; then echo "" echo " - X11 backend options:" echo " Enabled extensions: ${X11_EXTS}" fi if test "x$SUPPORT_WAYLAND_COMPOSITOR" = "x1"; then echo "" echo " - Wayland compositor support enabled" fi echo "" muffin-5.2.1/clutter/build/0000775000175000017500000000000014211404421015715 5ustar jpeisachjpeisachmuffin-5.2.1/clutter/build/autotools/0000775000175000017500000000000014211404421017746 5ustar jpeisachjpeisachmuffin-5.2.1/clutter/build/autotools/Makefile.am0000664000175000017500000000021314211404421021776 0ustar jpeisachjpeisachNULL = EXTRA_DIST = \ introspection.m4 \ as-compiler-flag.m4 \ glibtests.m4 \ glib-tap.mk \ tap-driver.sh \ tap-test \ $(NULL) muffin-5.2.1/clutter/build/autotools/glibtests.m40000664000175000017500000000243414211404421022213 0ustar jpeisachjpeisachdnl GLIB_TESTS dnl AC_DEFUN([GLIB_TESTS], [ AC_ARG_ENABLE(installed-tests, AS_HELP_STRING([--enable-installed-tests], [Enable installation of some test cases]), [case ${enableval} in yes) ENABLE_INSTALLED_TESTS="1" ;; no) ENABLE_INSTALLED_TESTS="" ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-installed-tests]) ;; esac]) AM_CONDITIONAL([ENABLE_INSTALLED_TESTS], test "$ENABLE_INSTALLED_TESTS" = "1") AC_ARG_ENABLE(always-build-tests, AS_HELP_STRING([--enable-always-build-tests], [Enable always building tests during 'make all']), [case ${enableval} in yes) ENABLE_ALWAYS_BUILD_TESTS="1" ;; no) ENABLE_ALWAYS_BUILD_TESTS="" ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-always-build-tests]) ;; esac]) AM_CONDITIONAL([ENABLE_ALWAYS_BUILD_TESTS], test "$ENABLE_ALWAYS_BUILD_TESTS" = "1") if test "$ENABLE_INSTALLED_TESTS" = "1"; then AC_SUBST(installed_test_metadir, [${datadir}/installed-tests/]AC_PACKAGE_NAME) AC_SUBST(installed_testdir, [${libexecdir}/installed-tests/]AC_PACKAGE_NAME) fi ]) muffin-5.2.1/clutter/build/autotools/tap-driver.sh0000775000175000017500000004607214211404421022373 0ustar jpeisachjpeisach#! /bin/sh # Copyright (C) 2011-2013 Free Software Foundation, 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, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . scriptversion=2011-12-27.17; # UTC # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u me=tap-driver.sh fatal () { echo "$me: fatal: $*" >&2 exit 1 } usage_error () { echo "$me: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat < # trap : 1 3 2 13 15 if test $merge -gt 0; then exec 2>&1 else exec 2>&3 fi "$@" echo $? ) | LC_ALL=C ${AM_TAP_AWK-awk} \ -v me="$me" \ -v test_script_name="$test_name" \ -v log_file="$log_file" \ -v trs_file="$trs_file" \ -v expect_failure="$expect_failure" \ -v merge="$merge" \ -v ignore_exit="$ignore_exit" \ -v comments="$comments" \ -v diag_string="$diag_string" \ ' # FIXME: the usages of "cat >&3" below could be optimized when using # FIXME: GNU awk, and/on on systems that supports /dev/fd/. # Implementation note: in what follows, `result_obj` will be an # associative array that (partly) simulates a TAP result object # from the `TAP::Parser` perl module. ## ----------- ## ## FUNCTIONS ## ## ----------- ## function fatal(msg) { print me ": " msg | "cat >&2" exit 1 } function abort(where) { fatal("internal error " where) } # Convert a boolean to a "yes"/"no" string. function yn(bool) { return bool ? "yes" : "no"; } function add_test_result(result) { if (!test_results_index) test_results_index = 0 test_results_list[test_results_index] = result test_results_index += 1 test_results_seen[result] = 1; } # Whether the test script should be re-run by "make recheck". function must_recheck() { for (k in test_results_seen) if (k != "XFAIL" && k != "PASS" && k != "SKIP") return 1 return 0 } # Whether the content of the log file associated to this test should # be copied into the "global" test-suite.log. function copy_in_global_log() { for (k in test_results_seen) if (k != "PASS") return 1 return 0 } # FIXME: this can certainly be improved ... function get_global_test_result() { if ("ERROR" in test_results_seen) return "ERROR" if ("FAIL" in test_results_seen || "XPASS" in test_results_seen) return "FAIL" all_skipped = 1 for (k in test_results_seen) if (k != "SKIP") all_skipped = 0 if (all_skipped) return "SKIP" return "PASS"; } function stringify_result_obj(result_obj) { if (result_obj["is_unplanned"] || result_obj["number"] != testno) return "ERROR" if (plan_seen == LATE_PLAN) return "ERROR" if (result_obj["directive"] == "TODO") return result_obj["is_ok"] ? "XPASS" : "XFAIL" if (result_obj["directive"] == "SKIP") return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL; if (length(result_obj["directive"])) abort("in function stringify_result_obj()") return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL } function decorate_result(result) { color_name = color_for_result[result] if (color_name) return color_map[color_name] "" result "" color_map["std"] # If we are not using colorized output, or if we do not know how # to colorize the given result, we should return it unchanged. return result } function report(result, details) { if (result ~ /^(X?(PASS|FAIL)|SKIP|ERROR)/) { msg = ": " test_script_name add_test_result(result) } else if (result == "#") { msg = " " test_script_name ":" } else { abort("in function report()") } if (length(details)) msg = msg " " details # Output on console might be colorized. print decorate_result(result) msg # Log the result in the log file too, to help debugging (this is # especially true when said result is a TAP error or "Bail out!"). print result msg | "cat >&3"; } function testsuite_error(error_message) { report("ERROR", "- " error_message) } function handle_tap_result() { details = result_obj["number"]; if (length(result_obj["description"])) details = details " " result_obj["description"] if (plan_seen == LATE_PLAN) { details = details " # AFTER LATE PLAN"; } else if (result_obj["is_unplanned"]) { details = details " # UNPLANNED"; } else if (result_obj["number"] != testno) { details = sprintf("%s # OUT-OF-ORDER (expecting %d)", details, testno); } else if (result_obj["directive"]) { details = details " # " result_obj["directive"]; if (length(result_obj["explanation"])) details = details " " result_obj["explanation"] } report(stringify_result_obj(result_obj), details) } # `skip_reason` should be empty whenever planned > 0. function handle_tap_plan(planned, skip_reason) { planned += 0 # Avoid getting confused if, say, `planned` is "00" if (length(skip_reason) && planned > 0) abort("in function handle_tap_plan()") if (plan_seen) { # Error, only one plan per stream is acceptable. testsuite_error("multiple test plans") return; } planned_tests = planned # The TAP plan can come before or after *all* the TAP results; we speak # respectively of an "early" or a "late" plan. If we see the plan line # after at least one TAP result has been seen, assume we have a late # plan; in this case, any further test result seen after the plan will # be flagged as an error. plan_seen = (testno >= 1 ? LATE_PLAN : EARLY_PLAN) # If testno > 0, we have an error ("too many tests run") that will be # automatically dealt with later, so do not worry about it here. If # $plan_seen is true, we have an error due to a repeated plan, and that # has already been dealt with above. Otherwise, we have a valid "plan # with SKIP" specification, and should report it as a particular kind # of SKIP result. if (planned == 0 && testno == 0) { if (length(skip_reason)) skip_reason = "- " skip_reason; report("SKIP", skip_reason); } } function extract_tap_comment(line) { if (index(line, diag_string) == 1) { # Strip leading `diag_string` from `line`. line = substr(line, length(diag_string) + 1) # And strip any leading and trailing whitespace left. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) # Return what is left (if any). return line; } return ""; } # When this function is called, we know that line is a TAP result line, # so that it matches the (perl) RE "^(not )?ok\b". function setup_result_obj(line) { # Get the result, and remove it from the line. result_obj["is_ok"] = (substr(line, 1, 2) == "ok" ? 1 : 0) sub("^(not )?ok[ \t]*", "", line) # If the result has an explicit number, get it and strip it; otherwise, # automatically assing the next progresive number to it. if (line ~ /^[0-9]+$/ || line ~ /^[0-9]+[^a-zA-Z0-9_]/) { match(line, "^[0-9]+") # The final `+ 0` is to normalize numbers with leading zeros. result_obj["number"] = substr(line, 1, RLENGTH) + 0 line = substr(line, RLENGTH + 1) } else { result_obj["number"] = testno } if (plan_seen == LATE_PLAN) # No further test results are acceptable after a "late" TAP plan # has been seen. result_obj["is_unplanned"] = 1 else if (plan_seen && testno > planned_tests) result_obj["is_unplanned"] = 1 else result_obj["is_unplanned"] = 0 # Strip trailing and leading whitespace. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) # This will have to be corrected if we have a "TODO"/"SKIP" directive. result_obj["description"] = line result_obj["directive"] = "" result_obj["explanation"] = "" if (index(line, "#") == 0) return # No possible directive, nothing more to do. # Directives are case-insensitive. rx = "[ \t]*#[ \t]*([tT][oO][dD][oO]|[sS][kK][iI][pP])[ \t]*" # See whether we have the directive, and if yes, where. pos = match(line, rx "$") if (!pos) pos = match(line, rx "[^a-zA-Z0-9_]") # If there was no TAP directive, we have nothing more to do. if (!pos) return # Let`s now see if the TAP directive has been escaped. For example: # escaped: ok \# SKIP # not escaped: ok \\# SKIP # escaped: ok \\\\\# SKIP # not escaped: ok \ # SKIP if (substr(line, pos, 1) == "#") { bslash_count = 0 for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--) bslash_count += 1 if (bslash_count % 2) return # Directive was escaped. } # Strip the directive and its explanation (if any) from the test # description. result_obj["description"] = substr(line, 1, pos - 1) # Now remove the test description from the line, that has been dealt # with already. line = substr(line, pos) # Strip the directive, and save its value (normalized to upper case). sub("^[ \t]*#[ \t]*", "", line) result_obj["directive"] = toupper(substr(line, 1, 4)) line = substr(line, 5) # Now get the explanation for the directive (if any), with leading # and trailing whitespace removed. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) result_obj["explanation"] = line } function get_test_exit_message(status) { if (status == 0) return "" if (status !~ /^[1-9][0-9]*$/) abort("getting exit status") if (status < 127) exit_details = "" else if (status == 127) exit_details = " (command not found?)" else if (status >= 128 && status <= 255) exit_details = sprintf(" (terminated by signal %d?)", status - 128) else if (status > 256 && status <= 384) # We used to report an "abnormal termination" here, but some Korn # shells, when a child process die due to signal number n, can leave # in $? an exit status of 256+n instead of the more standard 128+n. # Apparently, both behaviours are allowed by POSIX (2008), so be # prepared to handle them both. See also Austing Group report ID # 0000051 exit_details = sprintf(" (terminated by signal %d?)", status - 256) else # Never seen in practice. exit_details = " (abnormal termination)" return sprintf("exited with status %d%s", status, exit_details) } function write_test_results() { print ":global-test-result: " get_global_test_result() > trs_file print ":recheck: " yn(must_recheck()) > trs_file print ":copy-in-global-log: " yn(copy_in_global_log()) > trs_file for (i = 0; i < test_results_index; i += 1) print ":test-result: " test_results_list[i] > trs_file close(trs_file); } BEGIN { ## ------- ## ## SETUP ## ## ------- ## '"$init_colors"' # Properly initialized once the TAP plan is seen. planned_tests = 0 COOKED_PASS = expect_failure ? "XPASS": "PASS"; COOKED_FAIL = expect_failure ? "XFAIL": "FAIL"; # Enumeration-like constants to remember which kind of plan (if any) # has been seen. It is important that NO_PLAN evaluates "false" as # a boolean. NO_PLAN = 0 EARLY_PLAN = 1 LATE_PLAN = 2 testno = 0 # Number of test results seen so far. bailed_out = 0 # Whether a "Bail out!" directive has been seen. # Whether the TAP plan has been seen or not, and if yes, which kind # it is ("early" is seen before any test result, "late" otherwise). plan_seen = NO_PLAN ## --------- ## ## PARSING ## ## --------- ## is_first_read = 1 while (1) { # Involutions required so that we are able to read the exit status # from the last input line. st = getline if (st < 0) # I/O error. fatal("I/O error while reading from input stream") else if (st == 0) # End-of-input { if (is_first_read) abort("in input loop: only one input line") break } if (is_first_read) { is_first_read = 0 nextline = $0 continue } else { curline = nextline nextline = $0 $0 = curline } # Copy any input line verbatim into the log file. print | "cat >&3" # Parsing of TAP input should stop after a "Bail out!" directive. if (bailed_out) continue # TAP test result. if ($0 ~ /^(not )?ok$/ || $0 ~ /^(not )?ok[^a-zA-Z0-9_]/) { testno += 1 setup_result_obj($0) handle_tap_result() } # TAP plan (normal or "SKIP" without explanation). else if ($0 ~ /^1\.\.[0-9]+[ \t]*$/) { # The next two lines will put the number of planned tests in $0. sub("^1\\.\\.", "") sub("[^0-9]*$", "") handle_tap_plan($0, "") continue } # TAP "SKIP" plan, with an explanation. else if ($0 ~ /^1\.\.0+[ \t]*#/) { # The next lines will put the skip explanation in $0, stripping # any leading and trailing whitespace. This is a little more # tricky in truth, since we want to also strip a potential leading # "SKIP" string from the message. sub("^[^#]*#[ \t]*(SKIP[: \t][ \t]*)?", "") sub("[ \t]*$", ""); handle_tap_plan(0, $0) } # "Bail out!" magic. # Older versions of prove and TAP::Harness (e.g., 3.17) did not # recognize a "Bail out!" directive when preceded by leading # whitespace, but more modern versions (e.g., 3.23) do. So we # emulate the latter, "more modern" behaviour. else if ($0 ~ /^[ \t]*Bail out!/) { bailed_out = 1 # Get the bailout message (if any), with leading and trailing # whitespace stripped. The message remains stored in `$0`. sub("^[ \t]*Bail out![ \t]*", ""); sub("[ \t]*$", ""); # Format the error message for the bailout_message = "Bail out!" if (length($0)) bailout_message = bailout_message " " $0 testsuite_error(bailout_message) } # Maybe we have too look for dianogtic comments too. else if (comments != 0) { comment = extract_tap_comment($0); if (length(comment)) report("#", comment); } } ## -------- ## ## FINISH ## ## -------- ## # A "Bail out!" directive should cause us to ignore any following TAP # error, as well as a non-zero exit status from the TAP producer. if (!bailed_out) { if (!plan_seen) { testsuite_error("missing test plan") } else if (planned_tests != testno) { bad_amount = testno > planned_tests ? "many" : "few" testsuite_error(sprintf("too %s tests run (expected %d, got %d)", bad_amount, planned_tests, testno)) } if (!ignore_exit) { # Fetch exit status from the last line. exit_message = get_test_exit_message(nextline) if (exit_message) testsuite_error(exit_message) } } write_test_results() exit 0 } # End of "BEGIN" block. ' # TODO: document that we consume the file descriptor 3 :-( } 3>"$log_file" test $? -eq 0 || fatal "I/O or internal error" # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: muffin-5.2.1/clutter/build/autotools/.gitignore0000664000175000017500000000013614211404421021736 0ustar jpeisachjpeisachgtk-doc.m4 libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4 shave shave-libtool muffin-5.2.1/clutter/build/autotools/as-compiler-flag.m40000664000175000017500000000273714211404421023343 0ustar jpeisachjpeisachdnl as-compiler-flag.m4 0.1.0 dnl autostars m4 macro for detection of compiler flags dnl David Schleef dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $ dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) dnl Tries to compile with the given CFLAGS. dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, dnl and ACTION-IF-NOT-ACCEPTED otherwise. AC_DEFUN([AS_COMPILER_FLAG], [ AC_MSG_CHECKING([to see if compiler understands $1]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then m4_ifvaln([$2],[$2]) true else m4_ifvaln([$3],[$3]) true fi AC_MSG_RESULT([$flag_ok]) ]) dnl AS_COMPILER_FLAGS(VAR, FLAGS) dnl Tries to compile with the given CFLAGS. AC_DEFUN([AS_COMPILER_FLAGS], [ list=$2 flags_supported="" flags_unsupported="" AC_MSG_CHECKING([for supported compiler flags]) for each in $list do save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $each" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then flags_supported="$flags_supported $each" else flags_unsupported="$flags_unsupported $each" fi done AC_MSG_RESULT([$flags_supported]) if test "X$flags_unsupported" != X ; then AC_MSG_WARN([unsupported compiler flags: $flags_unsupported]) fi $1="$$1 $flags_supported" ]) muffin-5.2.1/clutter/build/autotools/glib-tap.mk0000664000175000017500000001450614211404421022004 0ustar jpeisachjpeisach# GLIB - Library of useful C routines TESTS_ENVIRONMENT= \ G_TEST_SRCDIR="$(abs_srcdir)" \ G_TEST_BUILDDIR="$(abs_builddir)" \ G_DEBUG=gc-friendly \ MALLOC_CHECK_=2 \ MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build/autotools/tap-driver.sh LOG_COMPILER = $(top_srcdir)/build/autotools/tap-test NULL = # initialize variables for unconditional += appending BUILT_SOURCES = BUILT_EXTRA_DIST = CLEANFILES = *.log *.trs DISTCLEANFILES = MAINTAINERCLEANFILES = EXTRA_DIST = TESTS = installed_test_LTLIBRARIES = installed_test_PROGRAMS = installed_test_SCRIPTS = nobase_installed_test_DATA = noinst_LTLIBRARIES = noinst_PROGRAMS = noinst_SCRIPTS = noinst_DATA = check_LTLIBRARIES = check_PROGRAMS = check_SCRIPTS = check_DATA = # We support a fairly large range of possible variables. It is expected that all types of files in a test suite # will belong in exactly one of the following variables. # # First, we support the usual automake suffixes, but in lowercase, with the customary meaning: # # test_programs, test_scripts, test_data, test_ltlibraries # # The above are used to list files that are involved in both uninstalled and installed testing. The # test_programs and test_scripts are taken to be actual testcases and will be run as part of the test suite. # Note that _data is always used with the nobase_ automake variable name to ensure that installed test data is # installed in the same way as it appears in the package layout. # # In order to mark a particular file as being only for one type of testing, use 'installed' or 'uninstalled', # like so: # # installed_test_programs, uninstalled_test_programs # installed_test_scripts, uninstalled_test_scripts # installed_test_data, uninstalled_test_data # installed_test_ltlibraries, uninstalled_test_ltlibraries # # Additionally, we support 'extra' infixes for programs and scripts. This is used for support programs/scripts # that should not themselves be run as testcases (but exist to be used from other testcases): # # test_extra_programs, installed_test_extra_programs, uninstalled_test_extra_programs # test_extra_scripts, installed_test_extra_scripts, uninstalled_test_extra_scripts # # Additionally, for _scripts and _data, we support the customary dist_ prefix so that the named script or data # file automatically end up in the tarball. # # dist_test_scripts, dist_test_data, dist_test_extra_scripts # dist_installed_test_scripts, dist_installed_test_data, dist_installed_test_extra_scripts # dist_uninstalled_test_scripts, dist_uninstalled_test_data, dist_uninstalled_test_extra_scripts # # Note that no file is automatically disted unless it appears in one of the dist_ variables. This follows the # standard automake convention of not disting programs scripts or data by default. # # test_programs, test_scripts, uninstalled_test_programs and uninstalled_test_scripts (as well as their disted # variants) will be run as part of the in-tree 'make check'. These are all assumed to be runnable under # gtester. That's a bit strange for scripts, but it's possible. TESTS += $(test_programs) $(test_scripts) $(uninstalled_test_programs) $(uninstalled_test_scripts) \ $(dist_test_scripts) $(dist_uninstalled_test_scripts) # Note: build even the installed-only targets during 'make check' to ensure that they still work. # We need to do a bit of trickery here and manage disting via EXTRA_DIST instead of using dist_ prefixes to # prevent automake from mistreating gmake functions like $(wildcard ...) and $(addprefix ...) as if they were # filenames, including removing duplicate instances of the opening part before the space, eg. '$(addprefix'. all_test_programs = $(test_programs) $(uninstalled_test_programs) $(installed_test_programs) \ $(test_extra_programs) $(uninstalled_test_extra_programs) $(installed_test_extra_programs) all_test_scripts = $(test_scripts) $(uninstalled_test_scripts) $(installed_test_scripts) \ $(test_extra_scripts) $(uninstalled_test_extra_scripts) $(installed_test_extra_scripts) all_dist_test_scripts = $(dist_test_scripts) $(dist_uninstalled_test_scripts) $(dist_installed_test_scripts) \ $(dist_test_extra_scripts) $(dist_uninstalled_test_extra_scripts) $(dist_installed_test_extra_scripts) all_test_scripts += $(all_dist_test_scripts) EXTRA_DIST += $(all_dist_test_scripts) all_test_data = $(test_data) $(uninstalled_test_data) $(installed_test_data) all_dist_test_data = $(dist_test_data) $(dist_uninstalled_test_data) $(dist_installed_test_data) all_test_data += $(all_dist_test_data) EXTRA_DIST += $(all_dist_test_data) all_test_ltlibs = $(test_ltlibraries) $(uninstalled_test_ltlibraries) $(installed_test_ltlibraries) if ENABLE_ALWAYS_BUILD_TESTS noinst_LTLIBRARIES += $(all_test_ltlibs) noinst_PROGRAMS += $(all_test_programs) noinst_SCRIPTS += $(all_test_scripts) noinst_DATA += $(all_test_data) else check_LTLIBRARIES += $(all_test_ltlibs) check_PROGRAMS += $(all_test_programs) check_SCRIPTS += $(all_test_scripts) check_DATA += $(all_test_data) endif if ENABLE_INSTALLED_TESTS installed_test_PROGRAMS += $(test_programs) $(installed_test_programs) \ $(test_extra_programs) $(installed_test_extra_programs) installed_test_SCRIPTS += $(test_scripts) $(installed_test_scripts) \ $(test_extra_scripts) $(test_installed_extra_scripts) installed_test_SCRIPTS += $(dist_test_scripts) $(dist_test_extra_scripts) \ $(dist_installed_test_scripts) $(dist_installed_test_extra_scripts) nobase_installed_test_DATA += $(test_data) $(installed_test_data) nobase_installed_test_DATA += $(dist_test_data) $(dist_installed_test_data) installed_test_LTLIBRARIES += $(test_ltlibraries) $(installed_test_ltlibraries) installed_testcases = $(test_programs) $(installed_test_programs) \ $(test_scripts) $(installed_test_scripts) \ $(dist_test_scripts) $(dist_installed_test_scripts) installed_test_meta_DATA = $(installed_testcases:=.test) %.test: %$(EXEEXT) Makefile $(AM_V_GEN) (echo '[Test]' > $@.tmp; \ echo 'Type=session' >> $@.tmp; \ echo 'Exec=env G_ENABLE_DIAGNOSTIC=0 CLUTTER_ENABLE_DIAGNOSTIC=0 $(installed_testdir)/$<' >> $@.tmp; \ mv $@.tmp $@) CLEANFILES += $(installed_test_meta_DATA) endif muffin-5.2.1/clutter/build/autotools/tap-test0000775000175000017500000000012414211404421021432 0ustar jpeisachjpeisach#! /bin/sh # run a GTest in tap mode. The test binary is passed as $1 $1 -k --tap muffin-5.2.1/clutter/build/Makefile.am0000664000175000017500000000002414211404421017745 0ustar jpeisachjpeisachSUBDIRS = autotools muffin-5.2.1/cogl/0000775000175000017500000000000014211404421014060 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl-pango/0000775000175000017500000000000014211404421016106 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl-pango/cogl-pango-pipeline-cache.c0000664000175000017500000001616014211404421023150 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-pango-pipeline-cache.h" #include "cogl/cogl-context-private.h" #include "cogl/cogl-texture-private.h" typedef struct _CoglPangoPipelineCacheEntry CoglPangoPipelineCacheEntry; struct _CoglPangoPipelineCacheEntry { /* This will take a reference or it can be NULL to represent the pipeline used to render colors */ CoglTexture *texture; /* This will only take a weak reference */ CoglPipeline *pipeline; }; static void _cogl_pango_pipeline_cache_key_destroy (void *data) { if (data) cogl_object_unref (data); } static void _cogl_pango_pipeline_cache_value_destroy (void *data) { CoglPangoPipelineCacheEntry *cache_entry = data; if (cache_entry->texture) cogl_object_unref (cache_entry->texture); /* We don't need to unref the pipeline because it only takes a weak reference */ g_slice_free (CoglPangoPipelineCacheEntry, cache_entry); } CoglPangoPipelineCache * _cogl_pango_pipeline_cache_new (CoglContext *ctx, CoglBool use_mipmapping) { CoglPangoPipelineCache *cache = g_new (CoglPangoPipelineCache, 1); cache->ctx = cogl_object_ref (ctx); /* The key is the pipeline pointer. A reference is taken when the pipeline is used as a key so we should unref it again in the destroy function */ cache->hash_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, _cogl_pango_pipeline_cache_key_destroy, _cogl_pango_pipeline_cache_value_destroy); cache->base_texture_rgba_pipeline = NULL; cache->base_texture_alpha_pipeline = NULL; cache->use_mipmapping = use_mipmapping; return cache; } static CoglPipeline * get_base_texture_rgba_pipeline (CoglPangoPipelineCache *cache) { if (cache->base_texture_rgba_pipeline == NULL) { CoglPipeline *pipeline; pipeline = cache->base_texture_rgba_pipeline = cogl_pipeline_new (cache->ctx); cogl_pipeline_set_layer_wrap_mode (pipeline, 0, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); if (cache->use_mipmapping) cogl_pipeline_set_layer_filters (pipeline, 0, COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR, COGL_PIPELINE_FILTER_LINEAR); } return cache->base_texture_rgba_pipeline; } static CoglPipeline * get_base_texture_alpha_pipeline (CoglPangoPipelineCache *cache) { if (cache->base_texture_alpha_pipeline == NULL) { CoglPipeline *pipeline; pipeline = cogl_pipeline_copy (get_base_texture_rgba_pipeline (cache)); cache->base_texture_alpha_pipeline = pipeline; /* The default combine mode of materials is to modulate (A x B) * the texture RGBA channels with the RGBA channels of the * previous layer (which in our case is just the font color) * * Since the RGB for an alpha texture is defined as 0, this gives us: * * result.rgb = color.rgb * 0 * result.a = color.a * texture.a * * What we want is premultiplied rgba values: * * result.rgba = color.rgb * texture.a * result.a = color.a * texture.a */ cogl_pipeline_set_layer_combine (pipeline, 0, /* layer */ "RGBA = MODULATE (PREVIOUS, TEXTURE[A])", NULL); } return cache->base_texture_alpha_pipeline; } typedef struct { CoglPangoPipelineCache *cache; CoglTexture *texture; } PipelineDestroyNotifyData; static void pipeline_destroy_notify_cb (void *user_data) { PipelineDestroyNotifyData *data = user_data; g_hash_table_remove (data->cache->hash_table, data->texture); g_slice_free (PipelineDestroyNotifyData, data); } CoglPipeline * _cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, CoglTexture *texture) { CoglPangoPipelineCacheEntry *entry; PipelineDestroyNotifyData *destroy_data; static CoglUserDataKey pipeline_destroy_notify_key; /* Look for an existing entry */ entry = g_hash_table_lookup (cache->hash_table, texture); if (entry) return cogl_object_ref (entry->pipeline); /* No existing pipeline was found so let's create another */ entry = g_slice_new (CoglPangoPipelineCacheEntry); if (texture) { CoglPipeline *base; entry->texture = cogl_object_ref (texture); if (_cogl_texture_get_format (entry->texture) == COGL_PIXEL_FORMAT_A_8) base = get_base_texture_alpha_pipeline (cache); else base = get_base_texture_rgba_pipeline (cache); entry->pipeline = cogl_pipeline_copy (base); cogl_pipeline_set_layer_texture (entry->pipeline, 0 /* layer */, texture); } else { entry->texture = NULL; entry->pipeline = cogl_pipeline_new (cache->ctx); } /* Add a weak reference to the pipeline so we can remove it from the hash table when it is destroyed */ destroy_data = g_slice_new (PipelineDestroyNotifyData); destroy_data->cache = cache; destroy_data->texture = texture; cogl_object_set_user_data (COGL_OBJECT (entry->pipeline), &pipeline_destroy_notify_key, destroy_data, pipeline_destroy_notify_cb); g_hash_table_insert (cache->hash_table, texture ? cogl_object_ref (texture) : NULL, entry); /* This doesn't take a reference on the pipeline so that it will use the newly created reference */ return entry->pipeline; } void _cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache) { if (cache->base_texture_rgba_pipeline) cogl_object_unref (cache->base_texture_rgba_pipeline); if (cache->base_texture_alpha_pipeline) cogl_object_unref (cache->base_texture_alpha_pipeline); g_hash_table_destroy (cache->hash_table); cogl_object_unref (cache->ctx); free (cache); } muffin-5.2.1/cogl/cogl-pango/Makefile.am0000664000175000017500000000615714211404421020153 0ustar jpeisachjpeisachNULL = CLEANFILES = DISTCLEANFILES = EXTRA_DIST = source_c = \ cogl-pango-display-list.c \ cogl-pango-fontmap.c \ cogl-pango-render.c \ cogl-pango-glyph-cache.c \ cogl-pango-pipeline-cache.c \ $(NULL) source_h = cogl-pango.h source_h_priv = \ cogl-pango-display-list.h \ cogl-pango-private.h \ cogl-pango-glyph-cache.h \ cogl-pango-pipeline-cache.h \ $(NULL) muffinlibdir = $(libdir)/muffin muffinlib_LTLIBRARIES = libmuffin-cogl-pango-@MUFFIN_PLUGIN_API_VERSION@.la libmuffin_cogl_pango_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = $(source_c) $(source_h) $(source_h_priv) libmuffin_cogl_pango_@MUFFIN_PLUGIN_API_VERSION@_la_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_PANGO_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS) libmuffin_cogl_pango_@MUFFIN_PLUGIN_API_VERSION@_la_LIBADD = $(top_builddir)/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la libmuffin_cogl_pango_@MUFFIN_PLUGIN_API_VERSION@_la_LIBADD += $(COGL_DEP_LIBS) $(COGL_PANGO_DEP_LIBS) $(COGL_EXTRA_LDFLAGS) libmuffin_cogl_pango_@MUFFIN_PLUGIN_API_VERSION@_la_LDFLAGS = \ -export-dynamic \ -rpath $(muffinlibdir) \ -export-symbols-regex "^cogl_pango_.*" \ -no-undefined \ -avoid-version AM_CPPFLAGS = \ -DCOGL_COMPILATION \ -DG_LOG_DOMAIN=\"CoglPango\" \ -I$(top_srcdir)/cogl \ -I$(top_builddir)/cogl \ -I$(top_srcdir)/cogl/winsys \ -I$(top_srcdir) \ -I$(top_builddir) cogl_base_includedir = $(includedir)/muffin cogl_pangoheadersdir = $(cogl_base_includedir)/cogl/cogl-pango cogl_pangoheaders_HEADERS = $(source_h) pc_files = muffin-cogl-pango-$(MUFFIN_PLUGIN_API_VERSION).pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pc_files) DISTCLEANFILES += $(pc_files) EXTRA_DIST += cogl-pango.symbols -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = if HAVE_INTROSPECTION INTROSPECTION_COMPILER_ARGS=--includedir=$(top_builddir)/cogl CoglPango-@MUFFIN_PLUGIN_API_VERSION@.gir: libmuffin-cogl-pango-$(MUFFIN_PLUGIN_API_VERSION).la Makefile CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_NAMESPACE = CoglPango CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_VERSION = @MUFFIN_PLUGIN_API_VERSION@ CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_LIBS = $(top_builddir)/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la libmuffin-cogl-pango-$(MUFFIN_PLUGIN_API_VERSION).la CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_FILES = $(source_h) $(source_c) CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) $(COGL_PANGO_DEP_CFLAGS) CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_INCLUDES = Pango-1.0 PangoCairo-1.0 CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_EXPORT_PACKAGES = muffin-cogl-pango-@MUFFIN_PLUGIN_API_VERSION@ CoglPango_@MUFFIN_PLUGIN_API_VERSION@_gir_SCANNERFLAGS = \ --warn-all \ --identifier-prefix=CoglPango \ --symbol-prefix=cogl_pango \ --c-include='cogl-pango/cogl-pango.h' \ --include-uninstalled=$(top_builddir)/cogl/Cogl-@MUFFIN_PLUGIN_API_VERSION@.gir INTROSPECTION_GIRS += CoglPango-@MUFFIN_PLUGIN_API_VERSION@.gir girdir = $(muffinlibdir) gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(muffinlibdir) typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) endif muffin-5.2.1/cogl/cogl-pango/cogl-pango-display-list.c0000664000175000017500000004004514211404421022717 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include "cogl-pango-display-list.h" #include "cogl-pango-pipeline-cache.h" #include "cogl/cogl-context-private.h" typedef enum { COGL_PANGO_DISPLAY_LIST_TEXTURE, COGL_PANGO_DISPLAY_LIST_RECTANGLE, COGL_PANGO_DISPLAY_LIST_TRAPEZOID } CoglPangoDisplayListNodeType; typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode; typedef struct _CoglPangoDisplayListRectangle CoglPangoDisplayListRectangle; struct _CoglPangoDisplayList { CoglBool color_override; CoglColor color; GSList *nodes; GSList *last_node; CoglPangoPipelineCache *pipeline_cache; }; /* This matches the format expected by cogl_rectangles_with_texture_coords */ struct _CoglPangoDisplayListRectangle { float x_1, y_1, x_2, y_2; float s_1, t_1, s_2, t_2; }; struct _CoglPangoDisplayListNode { CoglPangoDisplayListNodeType type; CoglBool color_override; CoglColor color; CoglPipeline *pipeline; union { struct { /* The texture to render these coords from */ CoglTexture *texture; /* Array of rectangles in the format expected by cogl_rectangles_with_texture_coords */ GArray *rectangles; /* A primitive representing those vertices */ CoglPrimitive *primitive; } texture; struct { float x_1, y_1; float x_2, y_2; } rectangle; struct { CoglPrimitive *primitive; } trapezoid; } d; }; CoglPangoDisplayList * _cogl_pango_display_list_new (CoglPangoPipelineCache *pipeline_cache) { CoglPangoDisplayList *dl = g_slice_new0 (CoglPangoDisplayList); dl->pipeline_cache = pipeline_cache; return dl; } static void _cogl_pango_display_list_append_node (CoglPangoDisplayList *dl, CoglPangoDisplayListNode *node) { if (dl->last_node) dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node); else dl->last_node = dl->nodes = g_slist_prepend (NULL, node); } void _cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl, const CoglColor *color) { dl->color_override = TRUE; dl->color = *color; } void _cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl) { dl->color_override = FALSE; } void _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, CoglTexture *texture, float x_1, float y_1, float x_2, float y_2, float tx_1, float ty_1, float tx_2, float ty_2) { CoglPangoDisplayListNode *node; CoglPangoDisplayListRectangle *rectangle; /* Add to the last node if it is a texture node with the same target texture */ if (dl->last_node && (node = dl->last_node->data)->type == COGL_PANGO_DISPLAY_LIST_TEXTURE && node->d.texture.texture == texture && (dl->color_override ? (node->color_override && cogl_color_equal (&dl->color, &node->color)) : !node->color_override)) { /* Get rid of the vertex buffer so that it will be recreated */ if (node->d.texture.primitive != NULL) { cogl_object_unref (node->d.texture.primitive); node->d.texture.primitive = NULL; } } else { /* Otherwise create a new node */ node = g_slice_new (CoglPangoDisplayListNode); node->type = COGL_PANGO_DISPLAY_LIST_TEXTURE; node->color_override = dl->color_override; node->color = dl->color; node->pipeline = NULL; node->d.texture.texture = cogl_object_ref (texture); node->d.texture.rectangles = g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListRectangle)); node->d.texture.primitive = NULL; _cogl_pango_display_list_append_node (dl, node); } g_array_set_size (node->d.texture.rectangles, node->d.texture.rectangles->len + 1); rectangle = &g_array_index (node->d.texture.rectangles, CoglPangoDisplayListRectangle, node->d.texture.rectangles->len - 1); rectangle->x_1 = x_1; rectangle->y_1 = y_1; rectangle->x_2 = x_2; rectangle->y_2 = y_2; rectangle->s_1 = tx_1; rectangle->t_1 = ty_1; rectangle->s_2 = tx_2; rectangle->t_2 = ty_2; } void _cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, float x_1, float y_1, float x_2, float y_2) { CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode); node->type = COGL_PANGO_DISPLAY_LIST_RECTANGLE; node->color_override = dl->color_override; node->color = dl->color; node->d.rectangle.x_1 = x_1; node->d.rectangle.y_1 = y_1; node->d.rectangle.x_2 = x_2; node->d.rectangle.y_2 = y_2; node->pipeline = NULL; _cogl_pango_display_list_append_node (dl, node); } void _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, float y_1, float x_11, float x_21, float y_2, float x_12, float x_22) { CoglContext *ctx = dl->pipeline_cache->ctx; CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode); CoglVertexP2 vertices[4] = { { x_11, y_1 }, { x_12, y_2 }, { x_22, y_2 }, { x_21, y_1 } }; node->type = COGL_PANGO_DISPLAY_LIST_TRAPEZOID; node->color_override = dl->color_override; node->color = dl->color; node->pipeline = NULL; node->d.trapezoid.primitive = cogl_primitive_new_p2 (ctx, COGL_VERTICES_MODE_TRIANGLE_FAN, 4, vertices); _cogl_pango_display_list_append_node (dl, node); } static void emit_rectangles_through_journal (CoglFramebuffer *fb, CoglPipeline *pipeline, CoglPangoDisplayListNode *node) { const float *rectangles = (const float *)node->d.texture.rectangles->data; cogl_framebuffer_draw_textured_rectangles (fb, pipeline, rectangles, node->d.texture.rectangles->len); } static void emit_vertex_buffer_geometry (CoglFramebuffer *fb, CoglPipeline *pipeline, CoglPangoDisplayListNode *node) { CoglContext *ctx = fb->context; /* It's expensive to go through the Cogl journal for large runs * of text in part because the journal transforms the quads in software * to avoid changing the modelview matrix. So for larger runs of text * we load the vertices into a VBO, and this has the added advantage * that if the text doesn't change from frame to frame the VBO can * be re-used avoiding the repeated cost of validating the data and * mapping it into the GPU... */ if (node->d.texture.primitive == NULL) { CoglAttributeBuffer *buffer; CoglVertexP2T2 *verts, *v; int n_verts; CoglBool allocated = FALSE; CoglAttribute *attributes[2]; CoglPrimitive *prim; int i; n_verts = node->d.texture.rectangles->len * 4; buffer = cogl_attribute_buffer_new_with_size (ctx, n_verts * sizeof (CoglVertexP2T2)); if ((verts = cogl_buffer_map (COGL_BUFFER (buffer), COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD)) == NULL) { verts = g_new (CoglVertexP2T2, n_verts); allocated = TRUE; } v = verts; /* Copy the rectangles into the buffer and expand into four vertices instead of just two */ for (i = 0; i < node->d.texture.rectangles->len; i++) { const CoglPangoDisplayListRectangle *rectangle = &g_array_index (node->d.texture.rectangles, CoglPangoDisplayListRectangle, i); v->x = rectangle->x_1; v->y = rectangle->y_1; v->s = rectangle->s_1; v->t = rectangle->t_1; v++; v->x = rectangle->x_1; v->y = rectangle->y_2; v->s = rectangle->s_1; v->t = rectangle->t_2; v++; v->x = rectangle->x_2; v->y = rectangle->y_2; v->s = rectangle->s_2; v->t = rectangle->t_2; v++; v->x = rectangle->x_2; v->y = rectangle->y_1; v->s = rectangle->s_2; v->t = rectangle->t_1; v++; } if (allocated) { cogl_buffer_set_data (COGL_BUFFER (buffer), 0, /* offset */ verts, sizeof (CoglVertexP2T2) * n_verts); free (verts); } else cogl_buffer_unmap (COGL_BUFFER (buffer)); attributes[0] = cogl_attribute_new (buffer, "cogl_position_in", sizeof (CoglVertexP2T2), G_STRUCT_OFFSET (CoglVertexP2T2, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (buffer, "cogl_tex_coord0_in", sizeof (CoglVertexP2T2), G_STRUCT_OFFSET (CoglVertexP2T2, s), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); prim = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, n_verts, attributes, 2 /* n_attributes */); #ifdef CLUTTER_COGL_HAS_GL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUADS)) cogl_primitive_set_mode (prim, GL_QUADS); else #endif { /* GLES doesn't support GL_QUADS so instead we use a VBO with indexed vertices to generate GL_TRIANGLES from the quads */ CoglIndices *indices = cogl_get_rectangle_indices (ctx, node->d.texture.rectangles->len); cogl_primitive_set_indices (prim, indices, node->d.texture.rectangles->len * 6); } node->d.texture.primitive = prim; cogl_object_unref (buffer); cogl_object_unref (attributes[0]); cogl_object_unref (attributes[1]); } cogl_primitive_draw (node->d.texture.primitive, fb, pipeline); } static void _cogl_framebuffer_draw_display_list_texture (CoglFramebuffer *fb, CoglPipeline *pipeline, CoglPangoDisplayListNode *node) { /* For small runs of text like icon labels, we can get better performance * going through the Cogl journal since text may then be batched together * with other geometry. */ /* FIXME: 25 is a number I plucked out of thin air; it would be good * to determine this empirically! */ if (node->d.texture.rectangles->len < 25) emit_rectangles_through_journal (fb, pipeline, node); else emit_vertex_buffer_geometry (fb, pipeline, node); } void _cogl_pango_display_list_render (CoglFramebuffer *fb, CoglPangoDisplayList *dl, const CoglColor *color) { GSList *l; for (l = dl->nodes; l; l = l->next) { CoglPangoDisplayListNode *node = l->data; CoglColor draw_color; if (node->pipeline == NULL) { if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE) node->pipeline = _cogl_pango_pipeline_cache_get (dl->pipeline_cache, node->d.texture.texture); else node->pipeline = _cogl_pango_pipeline_cache_get (dl->pipeline_cache, NULL); } if (node->color_override) /* Use the override color but preserve the alpha from the draw color */ cogl_color_init_from_4ub (&draw_color, cogl_color_get_red_byte (&node->color), cogl_color_get_green_byte (&node->color), cogl_color_get_blue_byte (&node->color), cogl_color_get_alpha_byte (color)); else draw_color = *color; cogl_color_premultiply (&draw_color); cogl_pipeline_set_color (node->pipeline, &draw_color); switch (node->type) { case COGL_PANGO_DISPLAY_LIST_TEXTURE: _cogl_framebuffer_draw_display_list_texture (fb, node->pipeline, node); break; case COGL_PANGO_DISPLAY_LIST_RECTANGLE: cogl_framebuffer_draw_rectangle (fb, node->pipeline, node->d.rectangle.x_1, node->d.rectangle.y_1, node->d.rectangle.x_2, node->d.rectangle.y_2); break; case COGL_PANGO_DISPLAY_LIST_TRAPEZOID: cogl_framebuffer_draw_primitive (fb, node->pipeline, node->d.trapezoid.primitive); break; } } } static void _cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node) { if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE) { g_array_free (node->d.texture.rectangles, TRUE); if (node->d.texture.texture != NULL) cogl_object_unref (node->d.texture.texture); if (node->d.texture.primitive != NULL) cogl_object_unref (node->d.texture.primitive); } else if (node->type == COGL_PANGO_DISPLAY_LIST_TRAPEZOID) cogl_object_unref (node->d.trapezoid.primitive); if (node->pipeline) cogl_object_unref (node->pipeline); g_slice_free (CoglPangoDisplayListNode, node); } void _cogl_pango_display_list_clear (CoglPangoDisplayList *dl) { g_slist_foreach (dl->nodes, (GFunc) _cogl_pango_display_list_node_free, NULL); g_slist_free (dl->nodes); dl->nodes = NULL; dl->last_node = NULL; } void _cogl_pango_display_list_free (CoglPangoDisplayList *dl) { _cogl_pango_display_list_clear (dl); g_slice_free (CoglPangoDisplayList, dl); } muffin-5.2.1/cogl/cogl-pango/cogl-pango-pipeline-cache.h0000664000175000017500000000423214211404421023152 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifndef __COGL_PANGO_PIPELINE_CACHE_H__ #define __COGL_PANGO_PIPELINE_CACHE_H__ #include #include "cogl/cogl-context-private.h" COGL_BEGIN_DECLS typedef struct _CoglPangoPipelineCache { CoglContext *ctx; GHashTable *hash_table; CoglPipeline *base_texture_alpha_pipeline; CoglPipeline *base_texture_rgba_pipeline; CoglBool use_mipmapping; } CoglPangoPipelineCache; CoglPangoPipelineCache * _cogl_pango_pipeline_cache_new (CoglContext *ctx, CoglBool use_mipmapping); /* Returns a pipeline that can be used to render glyphs in the given texture. The pipeline has a new reference so it is up to the caller to unref it */ CoglPipeline * _cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, CoglTexture *texture); void _cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache); COGL_END_DECLS #endif /* __COGL_PANGO_PIPELINE_CACHE_H__ */ muffin-5.2.1/cogl/cogl-pango/cogl-pango-display-list.h0000664000175000017500000000574214211404421022731 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_PANGO_DISPLAY_LIST_H__ #define __COGL_PANGO_DISPLAY_LIST_H__ #include #include "cogl-pango-pipeline-cache.h" COGL_BEGIN_DECLS typedef struct _CoglPangoDisplayList CoglPangoDisplayList; CoglPangoDisplayList * _cogl_pango_display_list_new (CoglPangoPipelineCache *); void _cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl, const CoglColor *color); void _cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl); void _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl, CoglTexture *texture, float x_1, float y_1, float x_2, float y_2, float tx_1, float ty_1, float tx_2, float ty_2); void _cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl, float x_1, float y_1, float x_2, float y_2); void _cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl, float y_1, float x_11, float x_21, float y_2, float x_12, float x_22); void _cogl_pango_display_list_render (CoglFramebuffer *framebuffer, CoglPangoDisplayList *dl, const CoglColor *color); void _cogl_pango_display_list_clear (CoglPangoDisplayList *dl); void _cogl_pango_display_list_free (CoglPangoDisplayList *dl); COGL_END_DECLS #endif /* __COGL_PANGO_DISPLAY_LIST_H__ */ muffin-5.2.1/cogl/cogl-pango/cogl-pango-private.h0000664000175000017500000000377414211404421021770 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008 OpenedHand * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts * Robert Bragg * Matthew Allum */ #ifndef __COGL_PANGO_PRIVATE_H__ #define __COGL_PANGO_PRIVATE_H__ #include "cogl-pango.h" COGL_BEGIN_DECLS PangoRenderer * _cogl_pango_renderer_new (CoglContext *context); void _cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer); void _cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer, CoglBool value); CoglBool _cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer); CoglContext * _cogl_pango_font_map_get_cogl_context (CoglPangoFontMap *fm); PangoRenderer * _cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm); COGL_END_DECLS #endif /* __COGL_PANGO_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl-pango/muffin-cogl-pango.pc.in0000664000175000017500000000065114211404421022351 0ustar jpeisachjpeisachprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@/muffin includedir=@includedir@/muffin apiversion=@MUFFIN_PLUGIN_API_VERSION@ requires=@COGL_PKG_REQUIRES@ muffin-cogl-@MUFFIN_PLUGIN_API_VERSION@ Name: Cogl Description: An object oriented GL/GLES Abstraction/Utility Layer Version: @MUFFIN_VERSION@ Libs: -L${libdir} -lmuffin-cogl-pango-@MUFFIN_PLUGIN_API_VERSION@ Cflags: -I${includedir}/cogl Requires: ${requires} muffin-5.2.1/cogl/cogl-pango/cogl-pango-glyph-cache.c0000664000175000017500000003253514211404421022472 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008 OpenedHand * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-pango-glyph-cache.h" #include "cogl-pango-private.h" #include "cogl/cogl-atlas.h" #include "cogl/cogl-atlas-texture-private.h" typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey; struct _CoglPangoGlyphCache { CoglContext *ctx; /* Hash table to quickly check whether a particular glyph in a particular font is already cached */ GHashTable *hash_table; /* List of CoglAtlases */ GSList *atlases; /* List of callbacks to invoke when an atlas is reorganized */ GHookList reorganize_callbacks; /* TRUE if we've ever stored a texture in the global atlas. This is used to make sure we only register one callback to listen for global atlas reorganizations */ CoglBool using_global_atlas; /* True if some of the glyphs are dirty. This is used as an optimization in _cogl_pango_glyph_cache_set_dirty_glyphs to avoid iterating the hash table if we know none of them are dirty */ CoglBool has_dirty_glyphs; /* Whether mipmapping is being used for this cache. This only affects whether we decide to put the glyph in the global atlas */ CoglBool use_mipmapping; }; struct _CoglPangoGlyphCacheKey { PangoFont *font; PangoGlyph glyph; }; static void cogl_pango_glyph_cache_value_free (CoglPangoGlyphCacheValue *value) { if (value->texture) cogl_object_unref (value->texture); g_slice_free (CoglPangoGlyphCacheValue, value); } static void cogl_pango_glyph_cache_key_free (CoglPangoGlyphCacheKey *key) { g_object_unref (key->font); g_slice_free (CoglPangoGlyphCacheKey, key); } static unsigned int cogl_pango_glyph_cache_hash_func (const void *key) { const CoglPangoGlyphCacheKey *cache_key = (const CoglPangoGlyphCacheKey *) key; /* Generate a number affected by both the font and the glyph number. We can safely directly compare the pointers because the key holds a reference to the font so it is not possible that a different font will have the same memory address */ return GPOINTER_TO_UINT (cache_key->font) ^ cache_key->glyph; } static CoglBool cogl_pango_glyph_cache_equal_func (const void *a, const void *b) { const CoglPangoGlyphCacheKey *key_a = (const CoglPangoGlyphCacheKey *) a; const CoglPangoGlyphCacheKey *key_b = (const CoglPangoGlyphCacheKey *) b; /* We can safely directly compare the pointers for the fonts because the key holds a reference to the font so it is not possible that a different font will have the same memory address */ return key_a->font == key_b->font && key_a->glyph == key_b->glyph; } CoglPangoGlyphCache * cogl_pango_glyph_cache_new (CoglContext *ctx, CoglBool use_mipmapping) { CoglPangoGlyphCache *cache; cache = malloc (sizeof (CoglPangoGlyphCache)); /* Note: as a rule we don't take references to a CoglContext * internally since */ cache->ctx = ctx; cache->hash_table = g_hash_table_new_full (cogl_pango_glyph_cache_hash_func, cogl_pango_glyph_cache_equal_func, (GDestroyNotify) cogl_pango_glyph_cache_key_free, (GDestroyNotify) cogl_pango_glyph_cache_value_free); cache->atlases = NULL; g_hook_list_init (&cache->reorganize_callbacks, sizeof (GHook)); cache->has_dirty_glyphs = FALSE; cache->using_global_atlas = FALSE; cache->use_mipmapping = use_mipmapping; return cache; } static void cogl_pango_glyph_cache_reorganize_cb (void *user_data) { CoglPangoGlyphCache *cache = user_data; g_hook_list_invoke (&cache->reorganize_callbacks, FALSE); } void cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache) { g_slist_foreach (cache->atlases, (GFunc) cogl_object_unref, NULL); g_slist_free (cache->atlases); cache->atlases = NULL; cache->has_dirty_glyphs = FALSE; g_hash_table_remove_all (cache->hash_table); } void cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache) { if (cache->using_global_atlas) { _cogl_atlas_texture_remove_reorganize_callback ( cache->ctx, cogl_pango_glyph_cache_reorganize_cb, cache); } cogl_pango_glyph_cache_clear (cache); g_hash_table_unref (cache->hash_table); g_hook_list_clear (&cache->reorganize_callbacks); free (cache); } static void cogl_pango_glyph_cache_update_position_cb (void *user_data, CoglTexture *new_texture, const CoglRectangleMapEntry *rect) { CoglPangoGlyphCacheValue *value = user_data; float tex_width, tex_height; if (value->texture) cogl_object_unref (value->texture); value->texture = cogl_object_ref (new_texture); tex_width = cogl_texture_get_width (new_texture); tex_height = cogl_texture_get_height (new_texture); value->tx1 = rect->x / tex_width; value->ty1 = rect->y / tex_height; value->tx2 = (rect->x + value->draw_width) / tex_width; value->ty2 = (rect->y + value->draw_height) / tex_height; value->tx_pixel = rect->x; value->ty_pixel = rect->y; /* The glyph has changed position so it will need to be redrawn */ value->dirty = TRUE; } static CoglBool cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache, PangoFont *font, PangoGlyph glyph, CoglPangoGlyphCacheValue *value) { CoglAtlasTexture *texture; CoglError *ignore_error = NULL; if (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SHARED_ATLAS)) return FALSE; /* If the cache is using mipmapping then we can't use the global atlas because it would just get migrated back out */ if (cache->use_mipmapping) return FALSE; texture = cogl_atlas_texture_new_with_size (cache->ctx, value->draw_width, value->draw_height); if (!cogl_texture_allocate (COGL_TEXTURE (texture), &ignore_error)) { cogl_error_free (ignore_error); return FALSE; } value->texture = COGL_TEXTURE (texture); value->tx1 = 0; value->ty1 = 0; value->tx2 = 1; value->ty2 = 1; value->tx_pixel = 0; value->ty_pixel = 0; /* The first time we store a texture in the global atlas we'll register for notifications when the global atlas is reorganized so we can forward the notification on as a glyph reorganization */ if (!cache->using_global_atlas) { _cogl_atlas_texture_add_reorganize_callback (cache->ctx, cogl_pango_glyph_cache_reorganize_cb, cache); cache->using_global_atlas = TRUE; } return TRUE; } static CoglBool cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache, PangoFont *font, PangoGlyph glyph, CoglPangoGlyphCacheValue *value) { CoglAtlas *atlas = NULL; GSList *l; /* Look for an atlas that can reserve the space */ for (l = cache->atlases; l; l = l->next) if (_cogl_atlas_reserve_space (l->data, value->draw_width + 1, value->draw_height + 1, value)) { atlas = l->data; break; } /* If we couldn't find one then start a new atlas */ if (atlas == NULL) { atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_A_8, COGL_ATLAS_CLEAR_TEXTURE | COGL_ATLAS_DISABLE_MIGRATION, cogl_pango_glyph_cache_update_position_cb); COGL_NOTE (ATLAS, "Created new atlas for glyphs: %p", atlas); /* If we still can't reserve space then something has gone seriously wrong so we'll just give up */ if (!_cogl_atlas_reserve_space (atlas, value->draw_width + 1, value->draw_height + 1, value)) { cogl_object_unref (atlas); return FALSE; } _cogl_atlas_add_reorganize_callback (atlas, cogl_pango_glyph_cache_reorganize_cb, NULL, cache); cache->atlases = g_slist_prepend (cache->atlases, atlas); } return TRUE; } CoglPangoGlyphCacheValue * cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, CoglBool create, PangoFont *font, PangoGlyph glyph) { CoglPangoGlyphCacheKey lookup_key; CoglPangoGlyphCacheValue *value; lookup_key.font = font; lookup_key.glyph = glyph; value = g_hash_table_lookup (cache->hash_table, &lookup_key); if (create && value == NULL) { CoglPangoGlyphCacheKey *key; PangoRectangle ink_rect; value = g_slice_new (CoglPangoGlyphCacheValue); value->texture = NULL; pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL); value->draw_x = ink_rect.x; value->draw_y = ink_rect.y; value->draw_width = ink_rect.width; value->draw_height = ink_rect.height; /* If the glyph is zero-sized then we don't need to reserve any space for it and we can just avoid painting anything */ if (ink_rect.width < 1 || ink_rect.height < 1) value->dirty = FALSE; else { /* Try adding the glyph to the global atlas... */ if (!cogl_pango_glyph_cache_add_to_global_atlas (cache, font, glyph, value) && /* If it fails try the local atlas */ !cogl_pango_glyph_cache_add_to_local_atlas (cache, font, glyph, value)) { cogl_pango_glyph_cache_value_free (value); return NULL; } value->dirty = TRUE; cache->has_dirty_glyphs = TRUE; } key = g_slice_new (CoglPangoGlyphCacheKey); key->font = g_object_ref (font); key->glyph = glyph; g_hash_table_insert (cache->hash_table, key, value); } return value; } static void _cogl_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr, void *value_ptr, void *user_data) { CoglPangoGlyphCacheKey *key = key_ptr; CoglPangoGlyphCacheValue *value = value_ptr; CoglPangoGlyphCacheDirtyFunc func = user_data; if (value->dirty) { func (key->font, key->glyph, value); value->dirty = FALSE; } } void _cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache, CoglPangoGlyphCacheDirtyFunc func) { /* If we know that there are no dirty glyphs then we can shortcut out early */ if (!cache->has_dirty_glyphs) return; g_hash_table_foreach (cache->hash_table, _cogl_pango_glyph_cache_set_dirty_glyphs_cb, func); cache->has_dirty_glyphs = FALSE; } void _cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache, GHookFunc func, void *user_data) { GHook *hook = g_hook_alloc (&cache->reorganize_callbacks); hook->func = func; hook->data = user_data; g_hook_prepend (&cache->reorganize_callbacks, hook); } void _cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache, GHookFunc func, void *user_data) { GHook *hook = g_hook_find_func_data (&cache->reorganize_callbacks, FALSE, func, user_data); if (hook) g_hook_destroy_link (&cache->reorganize_callbacks, hook); } muffin-5.2.1/cogl/cogl-pango/cogl-pango.h0000664000175000017500000002262114211404421020310 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008 OpenedHand * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts * Robert Bragg * Matthew Allum */ #ifndef __COGL_PANGO_H__ #define __COGL_PANGO_H__ #include #include #include /* XXX: Currently this header may be included both as an internal * header (within the cogl-pango implementation) and as a public * header. * * Since should not be included for internal use we * determine the current context and switch between including cogl.h * or specific internal cogl headers here... */ #ifndef COGL_COMPILATION #include #else #include "cogl/cogl-context.h" #include "cogl/cogl-macros.h" #endif COGL_BEGIN_DECLS /* It's too difficult to actually subclass the pango cairo font * map. Instead we just make a fake set of macros that actually just * directly use the original type */ #define COGL_PANGO_TYPE_FONT_MAP PANGO_TYPE_CAIRO_FONT_MAP #define COGL_PANGO_FONT_MAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COGL_PANGO_TYPE_FONT_MAP, CoglPangoFontMap)) #define COGL_PANGO_IS_FONT_MAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COGL_PANGO_TYPE_FONT_MAP)) typedef PangoCairoFontMap CoglPangoFontMap; /** * cogl_pango_font_map_new: * * Creates a new font map. * * Return value: (transfer full): the newly created #PangoFontMap * * Since: 1.14 */ PangoFontMap * cogl_pango_font_map_new (void); /** * cogl_pango_font_map_create_context: * @font_map: a #CoglPangoFontMap * * Create a #PangoContext for the given @font_map. * * Returns: (transfer full): the newly created context: free with g_object_unref(). */ PangoContext * cogl_pango_font_map_create_context (CoglPangoFontMap *font_map); /** * cogl_pango_font_map_set_resolution: * @font_map: a #CoglPangoFontMap * @dpi: The resolution in "dots per inch". (Physical inches aren't * actually involved; the terminology is conventional.) * * Sets the resolution for the @font_map. This is a scale factor * between points specified in a #PangoFontDescription and Cogl units. * The default value is %96, meaning that a 10 point font will be 13 * units high. (10 * 96. / 72. = 13.3). * * Since: 1.14 */ void cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map, double dpi); /** * cogl_pango_font_map_clear_glyph_cache: * @font_map: a #CoglPangoFontMap * * Clears the glyph cache for @font_map. * * Since: 1.0 */ void cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *font_map); /** * cogl_pango_ensure_glyph_cache_for_layout: * @layout: A #PangoLayout * * This updates any internal glyph cache textures as necessary to be * able to render the given @layout. * * This api should be used to avoid mid-scene modifications of * glyph-cache textures which can lead to undefined rendering results. * * Since: 1.0 */ void cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout); /** * cogl_pango_font_map_set_use_mipmapping: * @font_map: a #CoglPangoFontMap * @value: %TRUE to enable the use of mipmapping * * Sets whether the renderer for the passed font map should use * mipmapping when rendering a #PangoLayout. * * Since: 1.0 */ void cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *font_map, CoglBool value); /** * cogl_pango_font_map_get_use_mipmapping: * @font_map: a #CoglPangoFontMap * * Retrieves whether the #CoglPangoRenderer used by @font_map will use * mipmapping when rendering the glyphs. * * Return value: %TRUE if mipmapping is used, %FALSE otherwise. * * Since: 1.0 */ CoglBool cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *font_map); /** * cogl_pango_font_map_get_renderer: * @font_map: a #CoglPangoFontMap * * Retrieves the #CoglPangoRenderer for the passed @font_map. * * Return value: (transfer none): a #PangoRenderer * * Since: 1.0 */ PangoRenderer * cogl_pango_font_map_get_renderer (CoglPangoFontMap *font_map); /** * cogl_pango_show_layout: (skip) * @framebuffer: A #CoglFramebuffer to draw too. * @layout: a #PangoLayout * @x: X coordinate to render the layout at * @y: Y coordinate to render the layout at * @color: color to use when rendering the layout * * Draws a solidly coloured @layout on the given @framebuffer at (@x, * @y) within the @framebuffer's current model-view coordinate * space. * * Since: 1.14 */ void cogl_pango_show_layout (CoglFramebuffer *framebuffer, PangoLayout *layout, float x, float y, const CoglColor *color); /** * cogl_pango_show_layout_line: (skip) * @framebuffer: A #CoglFramebuffer to draw too. * @line: a #PangoLayoutLine * @x: X coordinate to render the line at * @y: Y coordinate to render the line at * @color: color to use when rendering the line * * Draws a solidly coloured @line on the given @framebuffer at (@x, * @y) within the @framebuffer's current model-view coordinate * space. * * Since: 1.14 */ void cogl_pango_show_layout_line (CoglFramebuffer *framebuffer, PangoLayoutLine *line, float x, float y, const CoglColor *color); #define COGL_PANGO_TYPE_RENDERER (cogl_pango_renderer_get_type ()) #define COGL_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COGL_PANGO_TYPE_RENDERER, CoglPangoRenderer)) #define COGL_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COGL_PANGO_TYPE_RENDERER, CoglPangoRendererClass)) #define COGL_PANGO_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COGL_PANGO_TYPE_RENDERER)) #define COGL_PANGO_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COGL_PANGO_TYPE_RENDERER)) #define COGL_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COGL_PANGO_TYPE_RENDERER, CoglPangoRendererClass)) /* opaque types */ typedef struct _CoglPangoRenderer CoglPangoRenderer; typedef struct _CoglPangoRendererClass CoglPangoRendererClass; GType cogl_pango_renderer_get_type (void) G_GNUC_CONST; /** * cogl_pango_render_layout_subpixel: * @layout: a #PangoLayout * @x: X coordinate (in Pango units) to render the layout at * @y: Y coordinate (in Pango units) to render the layout at * @color: color to use when rendering the layout * @flags: * * Draws a solidly coloured @layout on the given @framebuffer at (@x, * @y) within the @framebuffer's current model-view coordinate * space. * * Since: 1.0 * Deprecated: 1.16: Use cogl_pango_show_layout() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pango_show_layout) void cogl_pango_render_layout_subpixel (PangoLayout *layout, int x, int y, const CoglColor *color, int flags); /** * cogl_pango_render_layout: * @layout: a #PangoLayout * @x: X coordinate to render the layout at * @y: Y coordinate to render the layout at * @color: color to use when rendering the layout * @flags: * * Draws a solidly coloured @layout on the given @framebuffer at (@x, * @y) within the @framebuffer's current model-view coordinate * space. * * Since: 1.0 * Deprecated: 1.16: Use cogl_pango_show_layout() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pango_show_layout) void cogl_pango_render_layout (PangoLayout *layout, int x, int y, const CoglColor *color, int flags); /** * cogl_pango_render_layout_line: * @line: a #PangoLayoutLine * @x: X coordinate to render the line at * @y: Y coordinate to render the line at * @color: color to use when rendering the line * * Renders @line at the given coordinates using the given color. * * Since: 1.0 * Deprecated: 1.16: Use cogl_pango_show_layout() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pango_show_layout_line) void cogl_pango_render_layout_line (PangoLayoutLine *line, int x, int y, const CoglColor *color); COGL_END_DECLS #endif /* __COGL_PANGO_H__ */ muffin-5.2.1/cogl/cogl-pango/cogl-pango.symbols0000664000175000017500000000062414211404421021550 0ustar jpeisachjpeisachcogl_pango_ensure_glyph_cache_for_layout cogl_pango_font_map_clear_glyph_cache cogl_pango_font_map_create_context cogl_pango_font_map_get_renderer cogl_pango_font_map_get_use_mipmapping cogl_pango_font_map_new cogl_pango_font_map_set_resolution cogl_pango_font_map_set_use_mipmapping cogl_pango_renderer_get_type cogl_pango_render_layout cogl_pango_render_layout_line cogl_pango_render_layout_subpixel muffin-5.2.1/cogl/cogl-pango/cogl-pango-fontmap.c0000664000175000017500000001163014211404421021743 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008 OpenedHand * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * SECTION:cogl-pango * @short_description: COGL-based text rendering using Pango * * FIXME * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif /* This is needed to get the Pango headers to export stuff needed to subclass */ #ifndef PANGO_ENABLE_BACKEND #define PANGO_ENABLE_BACKEND 1 #endif #include #include #include #include "cogl-pango.h" #include "cogl-pango-private.h" #include "cogl-util.h" #include "cogl/cogl-context-private.h" static GQuark cogl_pango_font_map_get_priv_key (void) G_GNUC_CONST; typedef struct _CoglPangoFontMapPriv { CoglContext *ctx; PangoRenderer *renderer; } CoglPangoFontMapPriv; static void free_priv (gpointer data) { CoglPangoFontMapPriv *priv = data; cogl_object_unref (priv->ctx); cogl_object_unref (priv->renderer); free (priv); } PangoFontMap * cogl_pango_font_map_new (void) { PangoFontMap *fm = pango_cairo_font_map_new (); CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1); _COGL_GET_CONTEXT (context, NULL); priv->ctx = cogl_object_ref (context); /* XXX: The public pango api doesn't let us sub-class * PangoCairoFontMap so we attach our own private data using qdata * for now. */ g_object_set_qdata_full (G_OBJECT (fm), cogl_pango_font_map_get_priv_key (), priv, free_priv); return fm; } PangoContext * cogl_pango_font_map_create_context (CoglPangoFontMap *fm) { _COGL_RETURN_VAL_IF_FAIL (COGL_PANGO_IS_FONT_MAP (fm), NULL); #if PANGO_VERSION_CHECK (1, 22, 0) /* We can just directly use the pango context from the Cairo font map */ return pango_font_map_create_context (PANGO_FONT_MAP (fm)); #else return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fm)); #endif } static CoglPangoFontMapPriv * _cogl_pango_font_map_get_priv (CoglPangoFontMap *fm) { return g_object_get_qdata (G_OBJECT (fm), cogl_pango_font_map_get_priv_key ()); } PangoRenderer * _cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm) { CoglPangoFontMapPriv *priv = _cogl_pango_font_map_get_priv (fm); if (G_UNLIKELY (!priv->renderer)) priv->renderer = _cogl_pango_renderer_new (priv->ctx); return priv->renderer; } PangoRenderer * cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm) { return _cogl_pango_font_map_get_renderer (fm); } CoglContext * _cogl_pango_font_map_get_cogl_context (CoglPangoFontMap *fm) { CoglPangoFontMapPriv *priv = _cogl_pango_font_map_get_priv (fm); return priv->ctx; } void cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map, double dpi) { _COGL_RETURN_IF_FAIL (COGL_PANGO_IS_FONT_MAP (font_map)); pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (font_map), dpi); } void cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *fm) { PangoRenderer *renderer = _cogl_pango_font_map_get_renderer (fm); _cogl_pango_renderer_clear_glyph_cache (COGL_PANGO_RENDERER (renderer)); } void cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *fm, CoglBool value) { PangoRenderer *renderer = _cogl_pango_font_map_get_renderer (fm); _cogl_pango_renderer_set_use_mipmapping (COGL_PANGO_RENDERER (renderer), value); } CoglBool cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *fm) { PangoRenderer *renderer = _cogl_pango_font_map_get_renderer (fm); return _cogl_pango_renderer_get_use_mipmapping (COGL_PANGO_RENDERER (renderer)); } static GQuark cogl_pango_font_map_get_priv_key (void) { static GQuark priv_key = 0; if (G_UNLIKELY (priv_key == 0)) priv_key = g_quark_from_static_string ("CoglPangoFontMap"); return priv_key; } muffin-5.2.1/cogl/cogl-pango/cogl-pango-glyph-cache.h0000664000175000017500000000622514211404421022474 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008 OpenedHand * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_PANGO_GLYPH_CACHE_H__ #define __COGL_PANGO_GLYPH_CACHE_H__ #include #include #include "cogl/cogl-texture.h" COGL_BEGIN_DECLS typedef struct _CoglPangoGlyphCache CoglPangoGlyphCache; typedef struct _CoglPangoGlyphCacheValue CoglPangoGlyphCacheValue; struct _CoglPangoGlyphCacheValue { CoglTexture *texture; float tx1; float ty1; float tx2; float ty2; int tx_pixel; int ty_pixel; int draw_x; int draw_y; int draw_width; int draw_height; /* This will be set to TRUE when the glyph atlas is reorganized which means the glyph will need to be redrawn */ CoglBool dirty; }; typedef void (* CoglPangoGlyphCacheDirtyFunc) (PangoFont *font, PangoGlyph glyph, CoglPangoGlyphCacheValue *value); CoglPangoGlyphCache * cogl_pango_glyph_cache_new (CoglContext *ctx, CoglBool use_mipmapping); void cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache); CoglPangoGlyphCacheValue * cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, CoglBool create, PangoFont *font, PangoGlyph glyph); void cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache); void _cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache, GHookFunc func, void *user_data); void _cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache, GHookFunc func, void *user_data); void _cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache, CoglPangoGlyphCacheDirtyFunc func); COGL_END_DECLS #endif /* __COGL_PANGO_GLYPH_CACHE_H__ */ muffin-5.2.1/cogl/cogl-pango/cogl-pango-render.c0000664000175000017500000007353714211404421021574 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008 OpenedHand * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts * Robert Bragg * Matthew Allum */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #ifndef PANGO_ENABLE_BACKEND #define PANGO_ENABLE_BACKEND 1 #endif #include #include #include #include #include "cogl/cogl-debug.h" #include "cogl/cogl-context-private.h" #include "cogl/cogl-texture-private.h" #include "cogl-pango-private.h" #include "cogl-pango-glyph-cache.h" #include "cogl-pango-display-list.h" enum { PROP_0, PROP_COGL_CONTEXT, PROP_LAST }; typedef struct { CoglPangoGlyphCache *glyph_cache; CoglPangoPipelineCache *pipeline_cache; } CoglPangoRendererCaches; struct _CoglPangoRenderer { PangoRenderer parent_instance; CoglContext *ctx; /* Two caches of glyphs as textures and their corresponding pipeline caches, one with mipmapped textures and one without */ CoglPangoRendererCaches no_mipmap_caches; CoglPangoRendererCaches mipmap_caches; CoglBool use_mipmapping; /* The current display list that is being built */ CoglPangoDisplayList *display_list; }; struct _CoglPangoRendererClass { PangoRendererClass class_instance; }; typedef struct _CoglPangoLayoutQdata CoglPangoLayoutQdata; /* An instance of this struct gets attached to each PangoLayout to cache the VBO and to detect changes to the layout */ struct _CoglPangoLayoutQdata { CoglPangoRenderer *renderer; /* The cache of the geometry for the layout */ CoglPangoDisplayList *display_list; /* A reference to the first line of the layout. This is just used to detect changes */ PangoLayoutLine *first_line; /* Whether mipmapping was previously used to render this layout. We need to regenerate the display list if the mipmapping value is changed because it will be using a different set of textures */ CoglBool mipmapping_used; }; static void _cogl_pango_ensure_glyph_cache_for_layout_line (PangoLayoutLine *line); typedef struct { CoglPangoDisplayList *display_list; float x1, y1, x2, y2; } CoglPangoRendererSliceCbData; PangoRenderer * _cogl_pango_renderer_new (CoglContext *context) { return PANGO_RENDERER (g_object_new (COGL_PANGO_TYPE_RENDERER, "context", context, NULL)); } static void cogl_pango_renderer_slice_cb (CoglTexture *texture, const float *slice_coords, const float *virtual_coords, void *user_data) { CoglPangoRendererSliceCbData *data = user_data; /* Note: this assumes that there is only one slice containing the whole texture and it doesn't attempt to split up the vertex coordinates based on the virtual_coords */ _cogl_pango_display_list_add_texture (data->display_list, texture, data->x1, data->y1, data->x2, data->y2, slice_coords[0], slice_coords[1], slice_coords[2], slice_coords[3]); } static void cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv, CoglPangoGlyphCacheValue *cache_value, float x1, float y1) { CoglPangoRendererSliceCbData data; _COGL_RETURN_IF_FAIL (priv->display_list != NULL); data.display_list = priv->display_list; data.x1 = x1; data.y1 = y1; data.x2 = x1 + (float) cache_value->draw_width; data.y2 = y1 + (float) cache_value->draw_height; /* We iterate the internal sub textures of the texture so that we can get a pointer to the base texture even if the texture is in the global atlas. That way the display list can recognise that the neighbouring glyphs are coming from the same atlas and bundle them together into a single VBO */ cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (cache_value->texture), cache_value->tx1, cache_value->ty1, cache_value->tx2, cache_value->ty2, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, cogl_pango_renderer_slice_cb, &data); } static void cogl_pango_renderer_dispose (GObject *object); static void cogl_pango_renderer_finalize (GObject *object); static void cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer, PangoFont *font, PangoGlyphString *glyphs, int x, int y); static void cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer, PangoRenderPart part, int x, int y, int width, int height); static void cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer, PangoRenderPart part, double y1, double x11, double x21, double y2, double x12, double x22); G_DEFINE_TYPE (CoglPangoRenderer, cogl_pango_renderer, PANGO_TYPE_RENDERER); static void cogl_pango_renderer_init (CoglPangoRenderer *priv) { } static void _cogl_pango_renderer_constructed (GObject *gobject) { CoglPangoRenderer *renderer = COGL_PANGO_RENDERER (gobject); CoglContext *ctx = renderer->ctx; renderer->no_mipmap_caches.pipeline_cache = _cogl_pango_pipeline_cache_new (ctx, FALSE); renderer->mipmap_caches.pipeline_cache = _cogl_pango_pipeline_cache_new (ctx, TRUE); renderer->no_mipmap_caches.glyph_cache = cogl_pango_glyph_cache_new (ctx, FALSE); renderer->mipmap_caches.glyph_cache = cogl_pango_glyph_cache_new (ctx, TRUE); _cogl_pango_renderer_set_use_mipmapping (renderer, FALSE); if (G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->constructed) G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->constructed (gobject); } static void cogl_pango_renderer_set_property (GObject *object, unsigned int prop_id, const GValue *value, GParamSpec *pspec) { CoglPangoRenderer *renderer = COGL_PANGO_RENDERER (object); switch (prop_id) { case PROP_COGL_CONTEXT: renderer->ctx = g_value_get_pointer (value); cogl_object_ref (renderer->ctx); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void cogl_pango_renderer_class_init (CoglPangoRendererClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); GParamSpec *pspec; object_class->set_property = cogl_pango_renderer_set_property; object_class->constructed = _cogl_pango_renderer_constructed; object_class->dispose = cogl_pango_renderer_dispose; object_class->finalize = cogl_pango_renderer_finalize; pspec = g_param_spec_pointer ("context", "Context", "The Cogl Context", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_COGL_CONTEXT, pspec); renderer_class->draw_glyphs = cogl_pango_renderer_draw_glyphs; renderer_class->draw_rectangle = cogl_pango_renderer_draw_rectangle; renderer_class->draw_trapezoid = cogl_pango_renderer_draw_trapezoid; } static void cogl_pango_renderer_dispose (GObject *object) { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object); if (priv->ctx) { cogl_object_unref (priv->ctx); priv->ctx = NULL; } } static void cogl_pango_renderer_finalize (GObject *object) { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object); cogl_pango_glyph_cache_free (priv->no_mipmap_caches.glyph_cache); cogl_pango_glyph_cache_free (priv->mipmap_caches.glyph_cache); _cogl_pango_pipeline_cache_free (priv->no_mipmap_caches.pipeline_cache); _cogl_pango_pipeline_cache_free (priv->mipmap_caches.pipeline_cache); G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object); } static CoglPangoRenderer * cogl_pango_get_renderer_from_context (PangoContext *context) { PangoFontMap *font_map; CoglPangoFontMap *cogl_font_map; PangoRenderer *renderer; font_map = pango_context_get_font_map (context); g_return_val_if_fail (COGL_PANGO_IS_FONT_MAP (font_map), NULL); cogl_font_map = COGL_PANGO_FONT_MAP (font_map); renderer = _cogl_pango_font_map_get_renderer (cogl_font_map); g_return_val_if_fail (COGL_PANGO_IS_RENDERER (renderer), NULL); return COGL_PANGO_RENDERER (renderer); } static GQuark cogl_pango_layout_get_qdata_key (void) { static GQuark key = 0; if (G_UNLIKELY (key == 0)) key = g_quark_from_static_string ("CoglPangoDisplayList"); return key; } static void cogl_pango_layout_qdata_forget_display_list (CoglPangoLayoutQdata *qdata) { if (qdata->display_list) { CoglPangoRendererCaches *caches = qdata->mipmapping_used ? &qdata->renderer->mipmap_caches : &qdata->renderer->no_mipmap_caches; _cogl_pango_glyph_cache_remove_reorganize_callback (caches->glyph_cache, (GHookFunc) cogl_pango_layout_qdata_forget_display_list, qdata); _cogl_pango_display_list_free (qdata->display_list); qdata->display_list = NULL; } } static void cogl_pango_render_qdata_destroy (CoglPangoLayoutQdata *qdata) { cogl_pango_layout_qdata_forget_display_list (qdata); if (qdata->first_line) pango_layout_line_unref (qdata->first_line); g_slice_free (CoglPangoLayoutQdata, qdata); } void cogl_pango_show_layout (CoglFramebuffer *fb, PangoLayout *layout, float x, float y, const CoglColor *color) { PangoContext *context; CoglPangoRenderer *priv; CoglPangoLayoutQdata *qdata; context = pango_layout_get_context (layout); priv = cogl_pango_get_renderer_from_context (context); if (G_UNLIKELY (!priv)) return; qdata = g_object_get_qdata (G_OBJECT (layout), cogl_pango_layout_get_qdata_key ()); if (qdata == NULL) { qdata = g_slice_new0 (CoglPangoLayoutQdata); qdata->renderer = priv; g_object_set_qdata_full (G_OBJECT (layout), cogl_pango_layout_get_qdata_key (), qdata, (GDestroyNotify) cogl_pango_render_qdata_destroy); } /* Check if the layout has changed since the last build of the display list. This trick was suggested by Behdad Esfahbod here: http://mail.gnome.org/archives/gtk-i18n-list/2009-May/msg00019.html */ if (qdata->display_list && ((qdata->first_line && qdata->first_line->layout != layout) || qdata->mipmapping_used != priv->use_mipmapping)) cogl_pango_layout_qdata_forget_display_list (qdata); if (qdata->display_list == NULL) { CoglPangoRendererCaches *caches = priv->use_mipmapping ? &priv->mipmap_caches : &priv->no_mipmap_caches; cogl_pango_ensure_glyph_cache_for_layout (layout); qdata->display_list = _cogl_pango_display_list_new (caches->pipeline_cache); /* Register for notification of when the glyph cache changes so we can rebuild the display list */ _cogl_pango_glyph_cache_add_reorganize_callback (caches->glyph_cache, (GHookFunc) cogl_pango_layout_qdata_forget_display_list, qdata); priv->display_list = qdata->display_list; pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, 0, 0); priv->display_list = NULL; qdata->mipmapping_used = priv->use_mipmapping; } cogl_framebuffer_push_matrix (fb); cogl_framebuffer_translate (fb, x, y, 0); _cogl_pango_display_list_render (fb, qdata->display_list, color); cogl_framebuffer_pop_matrix (fb); /* Keep a reference to the first line of the layout so we can detect changes */ if (qdata->first_line) { pango_layout_line_unref (qdata->first_line); qdata->first_line = NULL; } if (pango_layout_get_line_count (layout) > 0) { qdata->first_line = pango_layout_get_line (layout, 0); pango_layout_line_ref (qdata->first_line); } } void cogl_pango_render_layout_subpixel (PangoLayout *layout, int x, int y, const CoglColor *color, int flags) { cogl_pango_show_layout (cogl_get_draw_framebuffer (), layout, x / (float) PANGO_SCALE, y / (float) PANGO_SCALE, color); } void cogl_pango_render_layout (PangoLayout *layout, int x, int y, const CoglColor *color, int flags) { cogl_pango_render_layout_subpixel (layout, x * PANGO_SCALE, y * PANGO_SCALE, color, flags); } void cogl_pango_show_layout_line (CoglFramebuffer *fb, PangoLayoutLine *line, float x, float y, const CoglColor *color) { PangoContext *context; CoglPangoRenderer *priv; CoglPangoRendererCaches *caches; int pango_x = x * PANGO_SCALE; int pango_y = y * PANGO_SCALE; context = pango_layout_get_context (line->layout); priv = cogl_pango_get_renderer_from_context (context); if (G_UNLIKELY (!priv)) return; caches = (priv->use_mipmapping ? &priv->mipmap_caches : &priv->no_mipmap_caches); priv->display_list = _cogl_pango_display_list_new (caches->pipeline_cache); _cogl_pango_ensure_glyph_cache_for_layout_line (line); pango_renderer_draw_layout_line (PANGO_RENDERER (priv), line, pango_x, pango_y); _cogl_pango_display_list_render (fb, priv->display_list, color); _cogl_pango_display_list_free (priv->display_list); priv->display_list = NULL; } void cogl_pango_render_layout_line (PangoLayoutLine *line, int x, int y, const CoglColor *color) { cogl_pango_show_layout_line (cogl_get_draw_framebuffer (), line, x / (float) PANGO_SCALE, y / (float) PANGO_SCALE, color); } void _cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer) { cogl_pango_glyph_cache_clear (renderer->mipmap_caches.glyph_cache); cogl_pango_glyph_cache_clear (renderer->no_mipmap_caches.glyph_cache); } void _cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer, CoglBool value) { renderer->use_mipmapping = value; } CoglBool _cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer) { return renderer->use_mipmapping; } static CoglPangoGlyphCacheValue * cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer, CoglBool create, PangoFont *font, PangoGlyph glyph) { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); CoglPangoRendererCaches *caches = (priv->use_mipmapping ? &priv->mipmap_caches : &priv->no_mipmap_caches); return cogl_pango_glyph_cache_lookup (caches->glyph_cache, create, font, glyph); } static void cogl_pango_renderer_set_dirty_glyph (PangoFont *font, PangoGlyph glyph, CoglPangoGlyphCacheValue *value) { cairo_surface_t *surface; cairo_t *cr; cairo_scaled_font_t *scaled_font; cairo_glyph_t cairo_glyph; cairo_format_t format_cairo; CoglPixelFormat format_cogl; COGL_NOTE (PANGO, "redrawing glyph %i", glyph); /* Glyphs that don't take up any space will end up without a texture. These should never become dirty so they shouldn't end up here */ _COGL_RETURN_IF_FAIL (value->texture != NULL); if (_cogl_texture_get_format (value->texture) == COGL_PIXEL_FORMAT_A_8) { format_cairo = CAIRO_FORMAT_A8; format_cogl = COGL_PIXEL_FORMAT_A_8; } else { format_cairo = CAIRO_FORMAT_ARGB32; /* Cairo stores the data in native byte order as ARGB but Cogl's pixel formats specify the actual byte order. Therefore we need to use a different format depending on the architecture */ #if G_BYTE_ORDER == G_LITTLE_ENDIAN format_cogl = COGL_PIXEL_FORMAT_BGRA_8888_PRE; #else format_cogl = COGL_PIXEL_FORMAT_ARGB_8888_PRE; #endif } surface = cairo_image_surface_create (format_cairo, value->draw_width, value->draw_height); cr = cairo_create (surface); scaled_font = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font)); cairo_set_scaled_font (cr, scaled_font); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); cairo_glyph.x = -value->draw_x; cairo_glyph.y = -value->draw_y; /* The PangoCairo glyph numbers directly map to Cairo glyph numbers */ cairo_glyph.index = glyph; cairo_show_glyphs (cr, &cairo_glyph, 1); cairo_destroy (cr); cairo_surface_flush (surface); /* Copy the glyph to the texture */ cogl_texture_set_region (value->texture, 0, /* src_x */ 0, /* src_y */ value->tx_pixel, /* dst_x */ value->ty_pixel, /* dst_y */ value->draw_width, /* dst_width */ value->draw_height, /* dst_height */ value->draw_width, /* width */ value->draw_height, /* height */ format_cogl, cairo_image_surface_get_stride (surface), cairo_image_surface_get_data (surface)); cairo_surface_destroy (surface); } static void _cogl_pango_ensure_glyph_cache_for_layout_line_internal (PangoLayoutLine *line) { PangoContext *context; PangoRenderer *renderer; GSList *l; context = pango_layout_get_context (line->layout); renderer = PANGO_RENDERER (cogl_pango_get_renderer_from_context (context)); for (l = line->runs; l; l = l->next) { PangoLayoutRun *run = l->data; PangoGlyphString *glyphs = run->glyphs; int i; for (i = 0; i < glyphs->num_glyphs; i++) { PangoGlyphInfo *gi = &glyphs->glyphs[i]; /* If the glyph isn't cached then this will reserve space for it now. We won't actually draw the glyph yet because reserving space could cause all of the other glyphs to be moved so we might as well redraw them all later once we know that the position is settled */ cogl_pango_renderer_get_cached_glyph (renderer, TRUE, run->item->analysis.font, gi->glyph); } } } static void _cogl_pango_set_dirty_glyphs (CoglPangoRenderer *priv) { _cogl_pango_glyph_cache_set_dirty_glyphs (priv->mipmap_caches.glyph_cache, cogl_pango_renderer_set_dirty_glyph); _cogl_pango_glyph_cache_set_dirty_glyphs (priv->no_mipmap_caches.glyph_cache, cogl_pango_renderer_set_dirty_glyph); } static void _cogl_pango_ensure_glyph_cache_for_layout_line (PangoLayoutLine *line) { PangoContext *context; CoglPangoRenderer *priv; context = pango_layout_get_context (line->layout); priv = cogl_pango_get_renderer_from_context (context); _cogl_pango_ensure_glyph_cache_for_layout_line_internal (line); /* Now that we know all of the positions are settled we'll fill in any dirty glyphs */ _cogl_pango_set_dirty_glyphs (priv); } void cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout) { PangoContext *context; CoglPangoRenderer *priv; PangoLayoutIter *iter; context = pango_layout_get_context (layout); priv = cogl_pango_get_renderer_from_context (context); _COGL_RETURN_IF_FAIL (PANGO_IS_LAYOUT (layout)); if ((iter = pango_layout_get_iter (layout)) == NULL) return; do { PangoLayoutLine *line; line = pango_layout_iter_get_line_readonly (iter); _cogl_pango_ensure_glyph_cache_for_layout_line_internal (line); } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); /* Now that we know all of the positions are settled we'll fill in any dirty glyphs */ _cogl_pango_set_dirty_glyphs (priv); } static void cogl_pango_renderer_set_color_for_part (PangoRenderer *renderer, PangoRenderPart part) { PangoColor *pango_color = pango_renderer_get_color (renderer, part); CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); if (pango_color) { CoglColor color; cogl_color_init_from_4ub (&color, pango_color->red >> 8, pango_color->green >> 8, pango_color->blue >> 8, 0xff); _cogl_pango_display_list_set_color_override (priv->display_list, &color); } else _cogl_pango_display_list_remove_color_override (priv->display_list); } static void cogl_pango_renderer_draw_box (PangoRenderer *renderer, int x, int y, int width, int height) { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); _COGL_RETURN_IF_FAIL (priv->display_list != NULL); _cogl_pango_display_list_add_rectangle (priv->display_list, x, y - height, x + width, y); } static void cogl_pango_renderer_get_device_units (PangoRenderer *renderer, int xin, int yin, float *xout, float *yout) { const PangoMatrix *matrix; if ((matrix = pango_renderer_get_matrix (renderer))) { /* Convert user-space coords to device coords */ *xout = ((xin * matrix->xx + yin * matrix->xy) / PANGO_SCALE + matrix->x0); *yout = ((yin * matrix->yy + xin * matrix->yx) / PANGO_SCALE + matrix->y0); } else { *xout = PANGO_PIXELS (xin); *yout = PANGO_PIXELS (yin); } } static void cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer, PangoRenderPart part, int x, int y, int width, int height) { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); float x1, x2, y1, y2; _COGL_RETURN_IF_FAIL (priv->display_list != NULL); cogl_pango_renderer_set_color_for_part (renderer, part); cogl_pango_renderer_get_device_units (renderer, x, y, &x1, &y1); cogl_pango_renderer_get_device_units (renderer, x + width, y + height, &x2, &y2); _cogl_pango_display_list_add_rectangle (priv->display_list, x1, y1, x2, y2); } static void cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer, PangoRenderPart part, double y1, double x11, double x21, double y2, double x12, double x22) { CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer); _COGL_RETURN_IF_FAIL (priv->display_list != NULL); cogl_pango_renderer_set_color_for_part (renderer, part); _cogl_pango_display_list_add_trapezoid (priv->display_list, y1, x11, x21, y2, x12, x22); } static void cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer, PangoFont *font, PangoGlyphString *glyphs, int xi, int yi) { CoglPangoRenderer *priv = (CoglPangoRenderer *) renderer; CoglPangoGlyphCacheValue *cache_value; int i; cogl_pango_renderer_set_color_for_part (renderer, PANGO_RENDER_PART_FOREGROUND); for (i = 0; i < glyphs->num_glyphs; i++) { PangoGlyphInfo *gi = glyphs->glyphs + i; float x, y; cogl_pango_renderer_get_device_units (renderer, xi + gi->geometry.x_offset, yi + gi->geometry.y_offset, &x, &y); if ((gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)) { if (font == NULL) { cogl_pango_renderer_draw_box (renderer, x, y, PANGO_UNKNOWN_GLYPH_WIDTH, PANGO_UNKNOWN_GLYPH_HEIGHT); } else { PangoRectangle ink_rect; pango_font_get_glyph_extents (font, gi->glyph, &ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL); cogl_pango_renderer_draw_box (renderer, x + ink_rect.x, y + ink_rect.y + ink_rect.height, ink_rect.width, ink_rect.height); } } else { /* Get the texture containing the glyph */ cache_value = cogl_pango_renderer_get_cached_glyph (renderer, FALSE, font, gi->glyph); /* cogl_pango_ensure_glyph_cache_for_layout should always be called before rendering a layout so we should never have a dirty glyph here */ g_assert (cache_value == NULL || !cache_value->dirty); if (cache_value == NULL) { cogl_pango_renderer_draw_box (renderer, x, y, PANGO_UNKNOWN_GLYPH_WIDTH, PANGO_UNKNOWN_GLYPH_HEIGHT); } else if (cache_value->texture) { x += (float)(cache_value->draw_x); y += (float)(cache_value->draw_y); cogl_pango_renderer_draw_glyph (priv, cache_value, x, y); } } xi += gi->geometry.width; } } muffin-5.2.1/cogl/Makefile.am0000664000175000017500000000104014211404421016107 0ustar jpeisachjpeisachSUBDIRS = test-fixtures SUBDIRS += cogl if BUILD_COGL_PATH SUBDIRS += cogl-path endif if BUILD_COGL_PANGO SUBDIRS += cogl-pango endif if BUILD_COGL_GLES2 SUBDIRS += cogl-gles2 endif SUBDIRS += tests ACLOCAL_AMFLAGS = -I build/autotools ${ACLOCAL_FLAGS} EXTRA_DIST = \ config-custom.h # .changelog expects these to be initializes CLEANFILES= DISTCLEANFILES= DISTCHECK_CONFIGURE_FLAGS = \ --enable-maintainer-flags \ --enable-profile \ --enable-gles2 \ --enable-gl \ --enable-xlib-egl-platform \ --enable-glx \ --enable-cogl-gst muffin-5.2.1/cogl/tests/0000775000175000017500000000000014211404421015222 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/tests/config.env.in0000664000175000017500000000010214211404421017577 0ustar jpeisachjpeisachHAVE_GL=@HAVE_GL@ HAVE_GLES1=@HAVE_GLES1@ HAVE_GLES2=@HAVE_GLES2@ muffin-5.2.1/cogl/tests/Makefile.am0000664000175000017500000000117514211404421017262 0ustar jpeisachjpeisachSUBDIRS = conform if UNIT_TESTS SUBDIRS += unit endif SUBDIRS += micro-perf data DIST_SUBDIRS = conform unit micro-perf data EXTRA_DIST = README test-launcher.sh run-tests.sh if UNIT_TESTS test conform: ( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$? ( cd ./unit && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$? else test conform: ( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$? endif .PHONY: test conform # run make test as part of make check check-local: test if ENABLE_INSTALLED_TESTS insttestdir = $(libexecdir)/installed-tests/muffin-cogl insttest_SCRIPTS = run-tests.sh insttest_DATA = config.env endif muffin-5.2.1/cogl/tests/README0000664000175000017500000000527314211404421016111 0ustar jpeisachjpeisachOutline of test categories: The conform/ tests: ------------------- These tests should be non-interactive unit-tests that verify a single feature is behaving as documented. See conform/ADDING_NEW_TESTS for more details. Although it may seem a bit awkward; all the tests are built into a single binary because it makes building the tests *much* faster by avoiding lots of linking. Each test has a wrapper script generated though so running the individual tests should be convenient enough. Running the wrapper script will also print out for convenience how you could run the test under gdb or valgrind like this for example: NOTE: For debugging purposes, you can run this single test as follows: $ libtool --mode=execute \ gdb --eval-command="b test_cogl_depth_test" \ --args ./test-conformance -p /conform/cogl/test_cogl_depth_test or: $ env G_SLICE=always-malloc \ libtool --mode=execute \ valgrind ./test-conformance -p /conform/cogl/test_cogl_depth_test By default the conformance tests are run offscreen. This makes the tests run much faster and they also don't interfere with other work you may want to do by constantly stealing focus. CoglOnscreen framebuffers obviously don't get tested this way so it's important that the tests also get run onscreen every once in a while, especially if changes are being made to CoglFramebuffer related code. Onscreen testing can be enabled by setting COGL_TEST_ONSCREEN=1 in your environment. The micro-bench/ tests: ----------------------- These should be focused performance tests, ideally testing a single metric. Please never forget that these tests are synthetic and if you are using them then you understand what metric is being tested. They probably don't reflect any real world application loads and the intention is that you use these tests once you have already determined the crux of your problem and need focused feedback that your changes are indeed improving matters. There is no exit status requirements for these tests, but they should give clear feedback as to their performance. If the framerate is the feedback metric, then the test should forcibly enable FPS debugging. The data/ directory: -------------------- This contains optional data (like images) that can be referenced by a test. Misc notes: ----------- • All tests should ideally include a detailed description in the source explaining exactly what the test is for, how the test was designed to work, and possibly a rationale for the approach taken for testing. • When running tests under Valgrind, you should follow the instructions available here: http://live.gnome.org/Valgrind and also use the suppression file available inside the data/ directory. muffin-5.2.1/cogl/tests/data/0000775000175000017500000000000014211404421016133 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/tests/data/Makefile.am0000664000175000017500000000005314211404421020165 0ustar jpeisachjpeisachNULL = EXTRA_DIST = valgrind.suppressions muffin-5.2.1/cogl/tests/data/valgrind.suppressions0000664000175000017500000000401214211404421022435 0ustar jpeisachjpeisach{ ioctl_1 Memcheck:Param ioctl(generic) fun:ioctl fun:driDrawableInitVBlank fun:intelMakeCurrent fun:glXMakeContextCurrent } { ioctl_2 Memcheck:Param ioctl(generic) fun:ioctl fun:driDrawableGetMSC32 fun:clutter_backend_glx_redraw } { ioctl_3 Memcheck:Param ioctl(generic) fun:ioctl fun:driWaitForMSC32 fun:clutter_backend_glx_redraw } { mesa_init_context Memcheck:Leak fun:*alloc ... fun:glXCreateNewContext } { type_register Memcheck:Leak fun:*alloc ... fun:g_type_register_* } { type_ref Memcheck:Leak fun:*alloc ... fun:g_type_class_ref } { type_interface_prereq Memcheck:Leak fun:*alloc ... fun:g_type_interface_add_prerequisite } { get_charset Memcheck:Leak fun:*alloc ... fun:g_get_charset } { cogl_features Memcheck:Leak fun:*alloc ... fun:cogl_get_features } { glx_query_version Memcheck:Leak fun:*alloc ... fun:glXQueryVersion } { glx_create_context Memcheck:Leak fun:*alloc ... fun:glXCreateNewContext } { glx_make_current Memcheck:Leak fun:*alloc ... fun:glXMakeContextCurrent } { gl_draw_arrays Memcheck:Leak fun:*malloc ... fun:glDrawArrays } { cogl_clear Memcheck:Leak fun:*alloc ... fun:cogl_clear } { default_font Memcheck:Leak fun:*alloc ... fun:clutter_backend_get_font_name } { id_pool Memcheck:Leak fun:*alloc ... fun:clutter_id_pool_new } { x_open_display Memcheck:Leak fun:*alloc ... fun:XOpenDisplay } # ... and font descriptions from every "sans 12" type string { pango_font_description_from_string Memcheck:Leak fun:*alloc ... fun:pango_font_description_from_string } # other lib init { fontconfig_init Memcheck:Leak fun:*alloc ... fun:FcConfigParseAndLoad } { freetype_init Memcheck:Leak fun:*alloc ... fun:FT_Open_Face } { x_init_ext Memcheck:Leak fun:*alloc ... fun:XInitExtension } muffin-5.2.1/cogl/tests/test-launcher.sh0000775000175000017500000000147314211404421020344 0ustar jpeisachjpeisach#!/bin/sh TEST_BINARY=$1 shift SYMBOL_PREFIX=$1 shift UNIT_TEST=$1 shift test -z ${UNIT_TEST} && { echo "Usage: $0 UNIT_TEST" exit 1 } BINARY_NAME=`basename $TEST_BINARY` UNIT_TEST=`echo $UNIT_TEST|sed 's/-/_/g'` echo "Running: ./$BINARY_NAME ${UNIT_TEST} $@" echo "" COGL_TEST_VERBOSE=1 $TEST_BINARY ${UNIT_TEST} "$@" exit_val=$? if test $exit_val -eq 0; then echo "OK" fi echo "" echo "NOTE: For debugging purposes, you can run this single test as follows:" echo "$ libtool --mode=execute \\" echo " gdb --eval-command=\"start\" --eval-command=\"b ${UNIT_TEST#${SYMBOL_PREFIX}}\" \\" echo " --args ./$BINARY_NAME ${UNIT_TEST}" echo "or:" echo "$ env G_SLICE=always-malloc \\" echo " libtool --mode=execute \\" echo " valgrind ./$BINARY_NAME ${UNIT_TEST}" exit $exit_val muffin-5.2.1/cogl/tests/micro-perf/0000775000175000017500000000000014211404421017265 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/tests/micro-perf/Makefile.am0000664000175000017500000000073314211404421021324 0ustar jpeisachjpeisachNULL = AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_builddir)/cogl \ -DCOGL_DISABLE_DEPRECATED test_conformance_CPPFLAGS = \ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" noinst_PROGRAMS = noinst_PROGRAMS += test-journal AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) common_ldadd = \ $(COGL_DEP_LIBS) \ $(top_builddir)/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la \ $(LIBM) test_journal_SOURCES = test-journal.c test_journal_LDADD = $(common_ldadd) muffin-5.2.1/cogl/tests/micro-perf/test-journal.c0000664000175000017500000001341614211404421022065 0ustar jpeisachjpeisach#include #include #include #include "cogl/cogl-profile.h" #define FRAMEBUFFER_WIDTH 800 #define FRAMEBUFFER_HEIGHT 600 CoglBool run_all = FALSE; typedef struct _Data { CoglContext *ctx; CoglFramebuffer *fb; CoglPipeline *pipeline; CoglPipeline *alpha_pipeline; GTimer *timer; int frame; } Data; static void test_rectangles (Data *data) { #define RECT_WIDTH 5 #define RECT_HEIGHT 5 int x; int y; cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1); cogl_framebuffer_push_rectangle_clip (data->fb, 10, 10, FRAMEBUFFER_WIDTH - 10, FRAMEBUFFER_HEIGHT - 10); /* Should the rectangles be randomly positioned/colored/rotated? * * It could be good to develop equivalent GL and Cairo tests so we can * have a sanity check for our Cogl performance. * * The color should vary to check that we correctly batch color changes * The use of alpha should vary so we have a variation of which rectangles * require blending. * Should this be a random variation? * It could be good to experiment with focibly enabling blending for * rectangles that don't technically need it for the sake of extending * batching. E.g. if you a long run of interleved rectangles with every * other rectangle needing blending then it may be worth enabling blending * for all the rectangles to avoid the state changes. * The modelview should change between rectangles to check the software * transform codepath. * Should we group some rectangles under the same modelview? Potentially * we could avoid software transform for long runs of rectangles with the * same modelview. * */ for (y = 0; y < FRAMEBUFFER_HEIGHT; y += RECT_HEIGHT) { for (x = 0; x < FRAMEBUFFER_WIDTH; x += RECT_WIDTH) { cogl_framebuffer_push_matrix (data->fb); cogl_framebuffer_translate (data->fb, x, y, 0); cogl_framebuffer_rotate (data->fb, 45, 0, 0, 1); cogl_pipeline_set_color4f (data->pipeline, 1, (1.0f/FRAMEBUFFER_WIDTH)*y, (1.0f/FRAMEBUFFER_HEIGHT)*x, 1); cogl_framebuffer_draw_rectangle (data->fb, data->pipeline, 0, 0, RECT_WIDTH, RECT_HEIGHT); cogl_framebuffer_pop_matrix (data->fb); } } for (y = 0; y < FRAMEBUFFER_HEIGHT; y += RECT_HEIGHT) { for (x = 0; x < FRAMEBUFFER_WIDTH; x += RECT_WIDTH) { cogl_framebuffer_push_matrix (data->fb); cogl_framebuffer_translate (data->fb, x, y, 0); cogl_pipeline_set_color4f (data->alpha_pipeline, 1, (1.0f/FRAMEBUFFER_WIDTH)*x, (1.0f/FRAMEBUFFER_HEIGHT)*y, (1.0f/FRAMEBUFFER_WIDTH)*x); cogl_framebuffer_draw_rectangle (data->fb, data->alpha_pipeline, 0, 0, RECT_WIDTH, RECT_HEIGHT); cogl_framebuffer_pop_matrix (data->fb); } } cogl_framebuffer_pop_clip (data->fb); } static CoglBool paint_cb (void *user_data) { Data *data = user_data; double elapsed; data->frame++; test_rectangles (data); cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb)); elapsed = g_timer_elapsed (data->timer, NULL); if (elapsed > 1.0) { g_print ("fps = %f\n", data->frame / elapsed); g_timer_start (data->timer); data->frame = 0; } return FALSE; /* remove the callback */ } static void frame_event_cb (CoglOnscreen *onscreen, CoglFrameEvent event, CoglFrameInfo *info, void *user_data) { if (event == COGL_FRAME_EVENT_SYNC) paint_cb (user_data); } int main (int argc, char **argv) { Data data; CoglOnscreen *onscreen; GSource *cogl_source; GMainLoop *loop; COGL_STATIC_TIMER (mainloop_timer, NULL, //no parent "Mainloop", "The time spent in the glib mainloop", 0); // no application private data data.ctx = cogl_context_new (NULL, NULL); onscreen = cogl_onscreen_new (data.ctx, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT); cogl_onscreen_set_swap_throttled (onscreen, FALSE); cogl_onscreen_show (onscreen); data.fb = onscreen; cogl_framebuffer_orthographic (data.fb, 0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, -1, 100); data.pipeline = cogl_pipeline_new (data.ctx); cogl_pipeline_set_color4f (data.pipeline, 1, 1, 1, 1); data.alpha_pipeline = cogl_pipeline_new (data.ctx); cogl_pipeline_set_color4f (data.alpha_pipeline, 1, 1, 1, 0.5); cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT); g_source_attach (cogl_source, NULL); cogl_onscreen_add_frame_callback (COGL_ONSCREEN (data.fb), frame_event_cb, &data, NULL); /* destroy notify */ g_idle_add (paint_cb, &data); data.frame = 0; data.timer = g_timer_new (); g_timer_start (data.timer); loop = g_main_loop_new (NULL, TRUE); COGL_TIMER_START (uprof_get_mainloop_context (), mainloop_timer); g_main_loop_run (loop); COGL_TIMER_STOP (uprof_get_mainloop_context (), mainloop_timer); return 0; } muffin-5.2.1/cogl/tests/run-tests.sh0000775000175000017500000000632514211404421017533 0ustar jpeisachjpeisach#!/bin/bash if test -z "$G_DEBUG"; then G_DEBUG=fatal-warnings else G_DEBUG="$G_DEBUG,fatal-warnings" fi export G_DEBUG ENVIRONMENT_CONFIG=$1 shift TEST_BINARY=$1 shift . $ENVIRONMENT_CONFIG set +m trap "" ERR trap "" SIGABRT trap "" SIGFPE trap "" SIGSEGV EXIT=0 MISSING_FEATURE="WARNING: Missing required feature"; KNOWN_FAILURE="WARNING: Test is known to fail"; echo "Key:" echo "ok = Test passed" echo "n/a = Driver is missing a feature required for the test" echo "FAIL = Unexpected failure" echo "FIXME = Test failed, but it was an expected failure" echo "PASS! = Unexpected pass" echo "" get_status() { case $1 in # Special value we use to indicate that the test failed # but it was an expected failure so don't fail the # overall test run as a result... 300) echo -n "FIXME";; # Special value we use to indicate that the test passed # but we weren't expecting it to pass‽ 400) echo -n 'PASS!';; # Special value to indicate the test is missing a required feature 500) echo -n "n/a";; 0) echo -n "ok";; *) echo -n "FAIL";; esac } run_test() { $($TEST_BINARY $1 &>.log) TMP=$? var_name=$2_result eval $var_name=$TMP if grep -q "$MISSING_FEATURE" .log; then if test $TMP -ne 0; then eval $var_name=500 else eval $var_name=400 fi elif grep -q "$KNOWN_FAILURE" .log; then if test $TMP -ne 0; then eval $var_name=300 else eval $var_name=400 fi else if test $TMP -ne 0; then EXIT=$TMP; fi fi } TITLE_FORMAT="%35s" printf $TITLE_FORMAT "Test" if test $HAVE_GL -eq 1; then GL_FORMAT=" %6s %8s %7s %6s %6s" printf "$GL_FORMAT" "GL+FF" "GL+ARBFP" "GL+GLSL" "GL-NPT" "GL3" fi if test $HAVE_GLES2 -eq 1; then GLES2_FORMAT=" %6s %7s" printf "$GLES2_FORMAT" "ES2" "ES2-NPT" fi echo "" echo "" for test in `cat unit-tests` do export COGL_DEBUG= if test $HAVE_GL -eq 1; then export COGL_DRIVER=gl export COGL_DEBUG=disable-glsl,disable-arbfp run_test $test gl_ff export COGL_DRIVER=gl # NB: we can't explicitly disable fixed + glsl in this case since # the arbfp code only supports fragment processing so we need either # the fixed or glsl vertends export COGL_DEBUG= run_test $test gl_arbfp export COGL_DRIVER=gl export COGL_DEBUG=disable-fixed,disable-arbfp run_test $test gl_glsl export COGL_DRIVER=gl export COGL_DEBUG=disable-npot-textures run_test $test gl_npot export COGL_DRIVER=gl3 export COGL_DEBUG= run_test $test gl3 fi if test $HAVE_GLES2 -eq 1; then export COGL_DRIVER=gles2 export COGL_DEBUG= run_test $test gles2 export COGL_DRIVER=gles2 export COGL_DEBUG=disable-npot-textures run_test $test gles2_npot fi printf $TITLE_FORMAT "$test:" if test $HAVE_GL -eq 1; then printf "$GL_FORMAT" \ "`get_status $gl_ff_result`" \ "`get_status $gl_arbfp_result`" \ "`get_status $gl_glsl_result`" \ "`get_status $gl_npot_result`" \ "`get_status $gl3_result`" fi if test $HAVE_GLES2 -eq 1; then printf "$GLES2_FORMAT" \ "`get_status $gles2_result`" \ "`get_status $gles2_npot_result`" fi echo "" done exit $EXIT muffin-5.2.1/cogl/tests/unit/0000775000175000017500000000000014211404421016201 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/tests/unit/Makefile.am0000664000175000017500000000503014211404421020233 0ustar jpeisachjpeisachNULL = noinst_PROGRAMS = test-unit test_unit_SOURCES = test-unit-main.c SHEXT = $(EXEEXT) # For convenience, this provides a way to easily run individual unit tests: .PHONY: wrappers clean-wrappers wrappers: stamp-test-unit @true stamp-test-unit: Makefile test-unit$(EXEEXT) @mkdir -p wrappers . $(top_builddir)/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la ; \ $(NM) $(top_builddir)/cogl/.libs/"$$dlname"| \ grep '[DR] _\?unit_test_'|sed 's/.\+ [DR] _\?//' > unit-tests @chmod +x $(top_srcdir)/tests/test-launcher.sh @( echo "/stamp-test-unit" ; \ echo "/test-unit$(EXEEXT)" ; \ echo "*.o" ; \ echo ".gitignore" ; \ echo "unit-tests" ; ) > .gitignore @for i in `cat unit-tests`; \ do \ unit=`echo $$i | sed -e s/_/-/g | sed s/unit-test-//`; \ echo " GEN $$unit"; \ ( echo "#!/bin/sh" ; echo "$(top_srcdir)/tests/test-launcher.sh $(abs_builddir)/test-unit$(EXEEXT) 'unit_test_' '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \ chmod +x $$unit$(SHEXT); \ echo "/$$unit$(SHEXT)" >> .gitignore; \ done \ && echo timestamp > $(@F) clean-wrappers: @for i in `cat unit-tests`; \ do \ unit=`echo $$i | sed -e s/_/-/g | sed s/unit-test-//`; \ echo " RM $$unit"; \ rm -f $$unit$(SHEXT) ; \ done \ && rm -f unit-tests \ && rm -f stamp-test-unit # NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting # a phony rule that will generate symlink scripts for running individual tests BUILT_SOURCES = wrappers # The include of the $(buildir)/cogl directory here is to make it so # that tests that directly include Cogl source code for whitebox # testing (such as test-bitmask) will still compile AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_srcdir)/test-fixtures \ -I$(top_builddir)/cogl AM_CPPFLAGS += \ -DCOGL_DISABLE_DEPRECATED \ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" \ -DCOGL_COMPILATION test_unit_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) test_unit_LDADD = \ $(COGL_DEP_LIBS) \ $(top_builddir)/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la \ $(LIBM) test_unit_LDFLAGS = -export-dynamic # XXX: uncomment when tests get fixed #test: wrappers # @$(top_srcdir)/tests/run-tests.sh $(abs_builddir)/../config.env $(abs_builddir)/test-unit$(EXEEXT) # XXX: we could prevent the unit test suite from running # by simply defining this variable conditionally TEST_PROGS = test-unit .PHONY: test DISTCLEANFILES = .gitignore # we override the clean-generic target to clean up the wrappers so # we cannot use CLEANFILES clean-generic: clean-wrappers $(QUIET_RM)rm -f .log muffin-5.2.1/cogl/tests/unit/test-unit-main.c0000664000175000017500000000173714211404421021233 0ustar jpeisachjpeisach#include "cogl-config.h" #include #include #include int main (int argc, char **argv) { GModule *main_module; const CoglUnitTest *unit_test; int i; if (argc != 2) { g_printerr ("usage %s UNIT_TEST\n", argv[0]); exit (1); } /* Just for convenience in case people try passing the wrapper * filenames for the UNIT_TEST argument we normalize '-' characters * to '_' characters... */ for (i = 0; argv[1][i]; i++) { if (argv[1][i] == '-') argv[1][i] = '_'; } main_module = g_module_open (NULL, /* use main module */ 0 /* flags */); if (!g_module_symbol (main_module, argv[1], (void **) &unit_test)) { g_printerr ("Unknown test name \"%s\"\n", argv[1]); return 1; } test_utils_init (unit_test->requirement_flags, unit_test->known_failure_flags); unit_test->run (); test_utils_fini (); return 0; } muffin-5.2.1/cogl/tests/conform/0000775000175000017500000000000014211404421016665 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/tests/conform/test-pipeline-uniforms.c0000664000175000017500000002720414211404421023460 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define LONG_ARRAY_SIZE 128 typedef struct _TestState { CoglPipeline *pipeline_red; CoglPipeline *pipeline_green; CoglPipeline *pipeline_blue; CoglPipeline *matrix_pipeline; CoglPipeline *vector_pipeline; CoglPipeline *int_pipeline; CoglPipeline *long_pipeline; int long_uniform_locations[LONG_ARRAY_SIZE]; } TestState; static const char color_source[] = "uniform float red, green, blue;\n" "\n" "void\n" "main ()\n" "{\n" " cogl_color_out = vec4 (red, green, blue, 1.0);\n" "}\n"; static const char matrix_source[] = "uniform mat4 matrix_array[4];\n" "\n" "void\n" "main ()\n" "{\n" " vec4 color = vec4 (0.0, 0.0, 0.0, 1.0);\n" " int i;\n" "\n" " for (i = 0; i < 4; i++)\n" " color = matrix_array[i] * color;\n" "\n" " cogl_color_out = color;\n" "}\n"; static const char vector_source[] = "uniform vec4 vector_array[2];\n" "uniform vec3 short_vector;\n" "\n" "void\n" "main ()\n" "{\n" " cogl_color_out = (vector_array[0] +\n" " vector_array[1] +\n" " vec4 (short_vector, 1.0));\n" "}\n"; static const char int_source[] = "uniform ivec4 vector_array[2];\n" "uniform int single_value;\n" "\n" "void\n" "main ()\n" "{\n" " cogl_color_out = (vec4 (vector_array[0]) +\n" " vec4 (vector_array[1]) +\n" " vec4 (float (single_value), 0.0, 0.0, 255.0)) / 255.0;\n" "}\n"; static const char long_source[] = "uniform int long_array[" G_STRINGIFY (LONG_ARRAY_SIZE) "];\n" "const int last_index = " G_STRINGIFY (LONG_ARRAY_SIZE) " - 1;\n" "\n" "void\n" "main ()\n" "{\n" " cogl_color_out = vec4 (float (long_array[last_index]), 0.0, 0.0, 1.0);\n" "}\n"; static CoglPipeline * create_pipeline_for_shader (TestState *state, const char *shader_source) { CoglPipeline *pipeline; CoglHandle shader; CoglHandle program; pipeline = cogl_pipeline_new (test_ctx); shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); cogl_shader_source (shader, shader_source); program = cogl_create_program (); cogl_program_attach_shader (program, shader); cogl_pipeline_set_user_program (pipeline, program); cogl_handle_unref (shader); cogl_handle_unref (program); return pipeline; } static void init_state (TestState *state) { int uniform_location; state->pipeline_red = create_pipeline_for_shader (state, color_source); uniform_location = cogl_pipeline_get_uniform_location (state->pipeline_red, "red"); cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 1.0f); uniform_location = cogl_pipeline_get_uniform_location (state->pipeline_red, "green"); cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f); uniform_location = cogl_pipeline_get_uniform_location (state->pipeline_red, "blue"); cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f); state->pipeline_green = cogl_pipeline_copy (state->pipeline_red); uniform_location = cogl_pipeline_get_uniform_location (state->pipeline_green, "green"); cogl_pipeline_set_uniform_1f (state->pipeline_green, uniform_location, 1.0f); state->pipeline_blue = cogl_pipeline_copy (state->pipeline_red); uniform_location = cogl_pipeline_get_uniform_location (state->pipeline_blue, "blue"); cogl_pipeline_set_uniform_1f (state->pipeline_blue, uniform_location, 1.0f); state->matrix_pipeline = create_pipeline_for_shader (state, matrix_source); state->vector_pipeline = create_pipeline_for_shader (state, vector_source); state->int_pipeline = create_pipeline_for_shader (state, int_source); state->long_pipeline = NULL; } static void init_long_pipeline_state (TestState *state) { int i; state->long_pipeline = create_pipeline_for_shader (state, long_source); /* This tries to lookup a large number of uniform names to make sure that the bitmask of overriden uniforms flows over the size of a single long so that it has to resort to allocating it */ for (i = 0; i < LONG_ARRAY_SIZE; i++) { char *uniform_name = g_strdup_printf ("long_array[%i]", i); state->long_uniform_locations[i] = cogl_pipeline_get_uniform_location (state->long_pipeline, uniform_name); free (uniform_name); } } static void destroy_state (TestState *state) { cogl_object_unref (state->pipeline_red); cogl_object_unref (state->pipeline_green); cogl_object_unref (state->pipeline_blue); cogl_object_unref (state->matrix_pipeline); cogl_object_unref (state->vector_pipeline); cogl_object_unref (state->int_pipeline); if (state->long_pipeline) cogl_object_unref (state->long_pipeline); } static void paint_pipeline (CoglPipeline *pipeline, int pos) { cogl_framebuffer_draw_rectangle (test_fb, pipeline, pos * 10, 0, pos * 10 + 10, 10); } static void paint_color_pipelines (TestState *state) { CoglPipeline *temp_pipeline; int uniform_location; int i; /* Paint with the first pipeline that sets the uniforms to bright red */ paint_pipeline (state->pipeline_red, 0); /* Paint with the two other pipelines. These inherit from the red pipeline and only override one other component. The values for the two other components should be inherited from the red pipeline. */ paint_pipeline (state->pipeline_green, 1); paint_pipeline (state->pipeline_blue, 2); /* Try modifying a single pipeline for multiple rectangles */ temp_pipeline = cogl_pipeline_copy (state->pipeline_green); uniform_location = cogl_pipeline_get_uniform_location (temp_pipeline, "green"); for (i = 0; i <= 8; i++) { cogl_pipeline_set_uniform_1f (temp_pipeline, uniform_location, i / 8.0f); paint_pipeline (temp_pipeline, i + 3); } cogl_object_unref (temp_pipeline); } static void paint_matrix_pipeline (CoglPipeline *pipeline) { CoglMatrix matrices[4]; float matrix_floats[16 * 4]; int uniform_location; int i; for (i = 0; i < 4; i++) cogl_matrix_init_identity (matrices + i); /* Use the first matrix to make the color red */ cogl_matrix_translate (matrices + 0, 1.0f, 0.0f, 0.0f); /* Rotate the vertex so that it ends up green */ cogl_matrix_rotate (matrices + 1, 90.0f, 0.0f, 0.0f, 1.0f); /* Scale the vertex so it ends up halved */ cogl_matrix_scale (matrices + 2, 0.5f, 0.5f, 0.5f); /* Add a blue component in the final matrix. The final matrix is uploaded as transposed so we need to transpose first to cancel that out */ cogl_matrix_translate (matrices + 3, 0.0f, 0.0f, 1.0f); cogl_matrix_transpose (matrices + 3); for (i = 0; i < 4; i++) memcpy (matrix_floats + i * 16, cogl_matrix_get_array (matrices + i), sizeof (float) * 16); /* Set the first three matrices as transposed */ uniform_location = cogl_pipeline_get_uniform_location (pipeline, "matrix_array"); cogl_pipeline_set_uniform_matrix (pipeline, uniform_location, 4, /* dimensions */ 3, /* count */ FALSE, /* not transposed */ matrix_floats); /* Set the last matrix as untransposed */ uniform_location = cogl_pipeline_get_uniform_location (pipeline, "matrix_array[3]"); cogl_pipeline_set_uniform_matrix (pipeline, uniform_location, 4, /* dimensions */ 1, /* count */ TRUE, /* transposed */ matrix_floats + 16 * 3); paint_pipeline (pipeline, 12); } static void paint_vector_pipeline (CoglPipeline *pipeline) { float vector_array_values[] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }; float short_vector_values[] = { 0.0f, 0.0f, 1.0f }; int uniform_location; uniform_location = cogl_pipeline_get_uniform_location (pipeline, "vector_array"); cogl_pipeline_set_uniform_float (pipeline, uniform_location, 4, /* n_components */ 2, /* count */ vector_array_values); uniform_location = cogl_pipeline_get_uniform_location (pipeline, "short_vector"); cogl_pipeline_set_uniform_float (pipeline, uniform_location, 3, /* n_components */ 1, /* count */ short_vector_values); paint_pipeline (pipeline, 13); } static void paint_int_pipeline (CoglPipeline *pipeline) { int vector_array_values[] = { 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00 }; int single_value = 0x80; int uniform_location; uniform_location = cogl_pipeline_get_uniform_location (pipeline, "vector_array"); cogl_pipeline_set_uniform_int (pipeline, uniform_location, 4, /* n_components */ 2, /* count */ vector_array_values); uniform_location = cogl_pipeline_get_uniform_location (pipeline, "single_value"); cogl_pipeline_set_uniform_1i (pipeline, uniform_location, single_value); paint_pipeline (pipeline, 14); } static void paint_long_pipeline (TestState *state) { int i; for (i = 0; i < LONG_ARRAY_SIZE; i++) { int location = state->long_uniform_locations[i]; cogl_pipeline_set_uniform_1i (state->long_pipeline, location, i == LONG_ARRAY_SIZE - 1); } paint_pipeline (state->long_pipeline, 15); } static void paint (TestState *state) { cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); paint_color_pipelines (state); paint_matrix_pipeline (state->matrix_pipeline); paint_vector_pipeline (state->vector_pipeline); paint_int_pipeline (state->int_pipeline); } static void check_pos (int pos, uint32_t color) { test_utils_check_pixel (test_fb, pos * 10 + 5, 5, color); } static void validate_result (void) { int i; check_pos (0, 0xff0000ff); check_pos (1, 0xffff00ff); check_pos (2, 0xff00ffff); for (i = 0; i <= 8; i++) { int green_value = i / 8.0f * 255.0f + 0.5f; check_pos (i + 3, 0xff0000ff + (green_value << 16)); } check_pos (12, 0x0080ffff); check_pos (13, 0xffffffff); check_pos (14, 0x80ffffff); } static void validate_long_pipeline_result (void) { check_pos (15, 0xff0000ff); } void test_pipeline_uniforms (void) { TestState state; init_state (&state); cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); paint (&state); validate_result (); /* Try the test again after querying the location of a large number of uniforms. This should verify that the bitmasks still work even if they have to allocate a separate array to store the bits */ init_long_pipeline_state (&state); paint (&state); paint_long_pipeline (&state); validate_result (); validate_long_pipeline_result (); destroy_state (&state); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-color-hsl.c0000664000175000017500000000254014211404421021711 0ustar jpeisachjpeisach#include #include #include #include "test-utils.h" #define cogl_assert_float(a, b) \ do { \ if (fabsf ((a) - (b)) >= 0.0001f) \ g_assert_cmpfloat ((a), ==, (b)); \ } while (0) void test_color_hsl (void) { CoglColor color; float hue, saturation, luminance; cogl_color_init_from_4ub(&color, 108, 198, 78, 255); cogl_color_to_hsl(&color, &hue, &saturation, &luminance); cogl_assert_float(hue, 105.f); cogl_assert_float(saturation, 0.512821); cogl_assert_float(luminance, 0.541176); memset(&color, 0, sizeof (CoglColor)); cogl_color_init_from_hsl(&color, hue, saturation, luminance); g_assert_cmpint (cogl_color_get_red_byte (&color), ==, 108); g_assert_cmpint (cogl_color_get_green_byte (&color), ==, 198); g_assert_cmpint (cogl_color_get_blue_byte (&color), ==, 78); g_assert_cmpint (cogl_color_get_alpha_byte (&color), ==, 255); memset(&color, 0, sizeof (CoglColor)); cogl_color_init_from_hsl(&color, hue, 0, luminance); cogl_assert_float (cogl_color_get_red_float (&color), luminance); cogl_assert_float (cogl_color_get_green_float (&color), luminance); cogl_assert_float (cogl_color_get_blue_float (&color), luminance); cogl_assert_float (cogl_color_get_alpha_float (&color), 1.0f); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-gles2-context.c0000664000175000017500000007221614211404421022514 0ustar jpeisachjpeisach #include #include #include #include "test-utils.h" typedef struct _TestState { CoglTexture *offscreen_texture; CoglOffscreen *offscreen; CoglGLES2Context *gles2_ctx; const CoglGLES2Vtable *gles2; } TestState; static void test_push_pop_single_context (void) { CoglTexture *offscreen_texture; CoglOffscreen *offscreen; CoglPipeline *pipeline; CoglGLES2Context *gles2_ctx; const CoglGLES2Vtable *gles2; CoglError *error = NULL; offscreen_texture = cogl_texture_2d_new_with_size (test_ctx, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb)); offscreen = cogl_offscreen_new_with_texture (offscreen_texture); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, offscreen_texture); gles2_ctx = cogl_gles2_context_new (test_ctx, &error); if (!gles2_ctx) g_error ("Failed to create GLES2 context: %s\n", error->message); gles2 = cogl_gles2_context_get_vtable (gles2_ctx); /* Clear onscreen to 0xffff00 using GLES2 */ if (!cogl_push_gles2_context (test_ctx, gles2_ctx, test_fb, test_fb, &error)) { g_error ("Failed to push gles2 context: %s\n", error->message); } gles2->glClearColor (1, 1, 0, 1); gles2->glClear (GL_COLOR_BUFFER_BIT); cogl_pop_gles2_context (test_ctx); test_utils_check_pixel (test_fb, 0, 0, 0xffff00ff); /* Clear offscreen to 0xff0000 using GLES2 and then copy the result * onscreen. * * If we fail to bind the new context here then we'd probably end up * clearing onscreen to 0xff0000 and copying 0xffff00 to onscreen * instead. */ if (!cogl_push_gles2_context (test_ctx, gles2_ctx, offscreen, offscreen, &error)) { g_error ("Failed to push gles2 context: %s\n", error->message); } gles2->glClearColor (1, 0, 0, 1); gles2->glClear (GL_COLOR_BUFFER_BIT); cogl_pop_gles2_context (test_ctx); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1, 1, 1, -1); /* NB: Cogl doesn't automatically support mid-scene modifications * of textures and so we explicitly flush the drawn rectangle to the * framebuffer now otherwise it may be batched until after the * offscreen texture has been modified again. */ cogl_flush (); /* Clear the offscreen framebuffer to blue using GLES2 before * reading back from the onscreen framebuffer in case we mistakenly * read from the offscreen framebuffer and get a false positive */ if (!cogl_push_gles2_context (test_ctx, gles2_ctx, offscreen, offscreen, &error)) { g_error ("Failed to push gles2 context: %s\n", error->message); } gles2->glClearColor (0, 0, 1, 1); gles2->glClear (GL_COLOR_BUFFER_BIT); cogl_pop_gles2_context (test_ctx); test_utils_check_pixel (test_fb, 0, 0, 0xff0000ff); /* Now copy the offscreen blue clear to the onscreen framebufer and * check that too */ cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1, 1, 1, -1); test_utils_check_pixel (test_fb, 0, 0, 0x0000ffff); if (!cogl_push_gles2_context (test_ctx, gles2_ctx, test_fb, test_fb, &error)) { g_error ("Failed to push gles2 context: %s\n", error->message); } gles2->glClearColor (1, 0, 1, 1); gles2->glClear (GL_COLOR_BUFFER_BIT); cogl_pop_gles2_context (test_ctx); test_utils_check_pixel (test_fb, 0, 0, 0xff00ffff); cogl_object_unref (gles2_ctx); cogl_object_unref (pipeline); } static void create_gles2_context (CoglTexture **offscreen_texture, CoglOffscreen **offscreen, CoglPipeline **pipeline, CoglGLES2Context **gles2_ctx, const CoglGLES2Vtable **gles2) { CoglError *error = NULL; *offscreen_texture = cogl_texture_2d_new_with_size (test_ctx, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb)); *offscreen = cogl_offscreen_new_with_texture (*offscreen_texture); *pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (*pipeline, 0, *offscreen_texture); *gles2_ctx = cogl_gles2_context_new (test_ctx, &error); if (!*gles2_ctx) g_error ("Failed to create GLES2 context: %s\n", error->message); *gles2 = cogl_gles2_context_get_vtable (*gles2_ctx); } static void test_push_pop_multi_context (void) { CoglTexture *offscreen_texture0; CoglOffscreen *offscreen0; CoglPipeline *pipeline0; CoglGLES2Context *gles2_ctx0; const CoglGLES2Vtable *gles20; CoglTexture *offscreen_texture1; CoglOffscreen *offscreen1; CoglPipeline *pipeline1; CoglGLES2Context *gles2_ctx1; const CoglGLES2Vtable *gles21; CoglError *error = NULL; create_gles2_context (&offscreen_texture0, &offscreen0, &pipeline0, &gles2_ctx0, &gles20); create_gles2_context (&offscreen_texture1, &offscreen1, &pipeline1, &gles2_ctx1, &gles21); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1); if (!cogl_push_gles2_context (test_ctx, gles2_ctx0, offscreen0, offscreen0, &error)) { g_error ("Failed to push gles2 context 0: %s\n", error->message); } gles20->glClearColor (1, 0, 0, 1); gles20->glClear (GL_COLOR_BUFFER_BIT); if (!cogl_push_gles2_context (test_ctx, gles2_ctx1, offscreen1, offscreen1, &error)) { g_error ("Failed to push gles2 context 1: %s\n", error->message); } gles21->glClearColor (0, 1, 0, 1); gles21->glClear (GL_COLOR_BUFFER_BIT); cogl_pop_gles2_context (test_ctx); cogl_pop_gles2_context (test_ctx); test_utils_check_pixel (test_fb, 0, 0, 0xffffffff); cogl_framebuffer_draw_rectangle (test_fb, pipeline0, -1, 1, 1, -1); test_utils_check_pixel (test_fb, 0, 0, 0xff0000ff); cogl_framebuffer_draw_rectangle (test_fb, pipeline1, -1, 1, 1, -1); test_utils_check_pixel (test_fb, 0, 0, 0x00ff00ff); } static GLuint create_gles2_framebuffer (const CoglGLES2Vtable *gles2, int width, int height) { GLuint texture_handle; GLuint fbo_handle; GLenum status; gles2->glGenTextures (1, &texture_handle); gles2->glGenFramebuffers (1, &fbo_handle); gles2->glBindTexture (GL_TEXTURE_2D, texture_handle); gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gles2->glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); gles2->glBindTexture (GL_TEXTURE_2D, 0); gles2->glBindFramebuffer (GL_FRAMEBUFFER, fbo_handle); gles2->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_handle, 0); status = gles2->glCheckFramebufferStatus (GL_FRAMEBUFFER); if (cogl_test_verbose ()) g_print ("status for gles2 framebuffer = 0x%x %s\n", status, status == GL_FRAMEBUFFER_COMPLETE ? "(complete)" : "(?)"); gles2->glBindFramebuffer (GL_FRAMEBUFFER, 0); return fbo_handle; } static void test_gles2_read_pixels (void) { CoglTexture *offscreen_texture; CoglOffscreen *offscreen; CoglPipeline *pipeline; CoglGLES2Context *gles2_ctx; const CoglGLES2Vtable *gles2; CoglError *error = NULL; GLubyte pixel[4]; GLuint fbo_handle; create_gles2_context (&offscreen_texture, &offscreen, &pipeline, &gles2_ctx, &gles2); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1); if (!cogl_push_gles2_context (test_ctx, gles2_ctx, offscreen, offscreen, &error)) { g_error ("Failed to push gles2 context: %s\n", error->message); } gles2->glClearColor (1, 0, 0, 1); gles2->glClear (GL_COLOR_BUFFER_BIT); gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); test_utils_compare_pixel (pixel, 0xff0000ff); fbo_handle = create_gles2_framebuffer (gles2, 256, 256); gles2->glBindFramebuffer (GL_FRAMEBUFFER, fbo_handle); gles2->glClearColor (0, 1, 0, 1); gles2->glClear (GL_COLOR_BUFFER_BIT); gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); test_utils_compare_pixel (pixel, 0x00ff00ff); gles2->glBindFramebuffer (GL_FRAMEBUFFER, 0); gles2->glClearColor (0, 1, 1, 1); gles2->glClear (GL_COLOR_BUFFER_BIT); gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); test_utils_compare_pixel (pixel, 0x00ffffff); cogl_pop_gles2_context (test_ctx); test_utils_check_pixel (test_fb, 0, 0, 0xffffffff); /* Bind different read and write buffers */ if (!cogl_push_gles2_context (test_ctx, gles2_ctx, offscreen, test_fb, &error)) { g_error ("Failed to push gles2 context: %s\n", error->message); } gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); test_utils_compare_pixel (pixel, 0x00ffffff); cogl_pop_gles2_context (test_ctx); test_utils_check_pixel (test_fb, 0, 0, 0xffffffff); /* Bind different read and write buffers (the other way around from * before so when we test with COGL_TEST_ONSCREEN=1 we will read * from an onscreen framebuffer) */ if (!cogl_push_gles2_context (test_ctx, gles2_ctx, test_fb, offscreen, &error)) { g_error ("Failed to push gles2 context: %s\n", error->message); } gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); test_utils_compare_pixel (pixel, 0xffffffff); cogl_pop_gles2_context (test_ctx); } void test_gles2_context (void) { test_push_pop_single_context (); test_push_pop_multi_context (); test_gles2_read_pixels (); if (cogl_test_verbose ()) g_print ("OK\n"); } static GLuint create_shader (const CoglGLES2Vtable *gles2, GLenum type, const char *source) { GLuint shader; GLint status; int length = strlen (source); shader = gles2->glCreateShader (type); gles2->glShaderSource (shader, 1, &source, &length); gles2->glCompileShader (shader); gles2->glGetShaderiv (shader, GL_COMPILE_STATUS, &status); if (!status) { char buf[512]; gles2->glGetShaderInfoLog (shader, sizeof (buf), NULL, buf); g_error ("Shader compilation failed:\n%s", buf); } return shader; } static GLuint create_program (const CoglGLES2Vtable *gles2, const char *vertex_shader_source, const char *fragment_shader_source) { GLuint fragment_shader, vertex_shader, program; GLint status; vertex_shader = create_shader (gles2, GL_VERTEX_SHADER, vertex_shader_source); fragment_shader = create_shader (gles2, GL_FRAGMENT_SHADER, fragment_shader_source); program = gles2->glCreateProgram (); gles2->glAttachShader (program, vertex_shader); gles2->glAttachShader (program, fragment_shader); gles2->glLinkProgram (program); gles2->glGetProgramiv (program, GL_LINK_STATUS, &status); if (!status) { char buf[512]; gles2->glGetProgramInfoLog (program, sizeof (buf), NULL, buf); g_error ("Program linking failed:\n%s", buf); } return program; } typedef struct { const CoglGLES2Vtable *gles2; GLint color_location; GLint pos_location; int fb_width, fb_height; } PaintData; typedef void (* PaintMethod) (PaintData *data); /* Top vertices are counter-clockwise */ static const float top_vertices[] = { -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 1.0f, 1.0f }; /* Bottom vertices are clockwise */ static const float bottom_vertices[] = { 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, -1.0f }; static void paint_quads (PaintData *data) { const CoglGLES2Vtable *gles2 = data->gles2; gles2->glEnableVertexAttribArray (data->pos_location); /* Paint the top half in red */ gles2->glUniform4f (data->color_location, 1.0f, 0.0f, 0.0f, 1.0f); gles2->glVertexAttribPointer (data->pos_location, 2, /* size */ GL_FLOAT, GL_FALSE, /* not normalized */ sizeof (float) * 2, top_vertices); gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* Paint the bottom half in blue */ gles2->glUniform4f (data->color_location, 0.0f, 0.0f, 1.0f, 1.0f); gles2->glVertexAttribPointer (data->pos_location, 2, /* size */ GL_FLOAT, GL_FALSE, /* not normalized */ sizeof (float) * 2, bottom_vertices); gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); } static void paint_viewport (PaintData *data) { const CoglGLES2Vtable *gles2 = data->gles2; int viewport[4]; /* Vertices to fill the entire framebuffer */ static const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; gles2->glEnableVertexAttribArray (data->pos_location); gles2->glVertexAttribPointer (data->pos_location, 2, /* size */ GL_FLOAT, GL_FALSE, /* not normalized */ sizeof (float) * 2, vertices); /* Paint the top half in red */ gles2->glViewport (0, data->fb_height / 2, data->fb_width, data->fb_height / 2); gles2->glUniform4f (data->color_location, 1.0f, 0.0f, 0.0f, 1.0f); gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* Paint the bottom half in blue */ gles2->glViewport (0, 0, data->fb_width, data->fb_height / 2); gles2->glUniform4f (data->color_location, 0.0f, 0.0f, 1.0f, 1.0f); gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); gles2->glGetIntegerv (GL_VIEWPORT, viewport); g_assert_cmpint (viewport[0], ==, 0.0f); g_assert_cmpint (viewport[1], ==, 0.0f); g_assert_cmpint (viewport[2], ==, data->fb_width); g_assert_cmpint (viewport[3], ==, data->fb_height / 2); } static void paint_scissor (PaintData *data) { const CoglGLES2Vtable *gles2 = data->gles2; float scissor[4]; gles2->glEnable (GL_SCISSOR_TEST); /* Paint the top half in red */ gles2->glScissor (0, data->fb_height / 2, data->fb_width, data->fb_height / 2); gles2->glClearColor (1.0, 0.0, 0.0, 1.0); gles2->glClear (GL_COLOR_BUFFER_BIT); /* Paint the bottom half in blue */ gles2->glScissor (0, 0, data->fb_width, data->fb_height / 2); gles2->glClearColor (0.0, 0.0, 1.0, 1.0); gles2->glClear (GL_COLOR_BUFFER_BIT); gles2->glGetFloatv (GL_SCISSOR_BOX, scissor); g_assert_cmpfloat (scissor[0], ==, 0.0f); g_assert_cmpfloat (scissor[1], ==, 0.0f); g_assert_cmpfloat (scissor[2], ==, data->fb_width); g_assert_cmpfloat (scissor[3], ==, data->fb_height / 2); } static void paint_cull (PaintData *data) { const CoglGLES2Vtable *gles2 = data->gles2; GLint front_face; int i; gles2->glEnableVertexAttribArray (data->pos_location); gles2->glEnable (GL_CULL_FACE); /* First time round we'll use GL_CCW as the front face so that the * bottom quad will be culled */ gles2->glFrontFace (GL_CCW); gles2->glUniform4f (data->color_location, 1.0f, 0.0f, 0.0f, 1.0f); gles2->glGetIntegerv (GL_FRONT_FACE, &front_face); g_assert_cmpint (front_face, ==, GL_CCW); for (i = 0; i < 2; i++) { /* Paint both quads in the same color. One of these will be * culled */ gles2->glVertexAttribPointer (data->pos_location, 2, /* size */ GL_FLOAT, GL_FALSE, /* not normalized */ sizeof (float) * 2, top_vertices); gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); gles2->glVertexAttribPointer (data->pos_location, 2, /* size */ GL_FLOAT, GL_FALSE, /* not normalized */ sizeof (float) * 2, bottom_vertices); gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* Second time round we'll use GL_CW as the front face so that the * top quad will be culled */ gles2->glFrontFace (GL_CW); gles2->glUniform4f (data->color_location, 0.0f, 0.0f, 1.0f, 1.0f); gles2->glGetIntegerv (GL_FRONT_FACE, &front_face); g_assert_cmpint (front_face, ==, GL_CW); } } static void verify_read_pixels (const PaintData *data) { int stride = data->fb_width * 4; uint8_t *buf = malloc (data->fb_height * stride); data->gles2->glReadPixels (0, 0, /* x/y */ data->fb_width, data->fb_height, GL_RGBA, GL_UNSIGNED_BYTE, buf); /* In GL, the lines earlier in the buffer are the bottom */ /* Bottom should be blue */ test_utils_compare_pixel (buf + data->fb_width / 2 * 4 + data->fb_height / 4 * stride, 0x0000ffff); /* Top should be red */ test_utils_compare_pixel (buf + data->fb_width / 2 * 4 + data->fb_height * 3 / 4 * stride, 0xff0000ff); free (buf); } void test_gles2_context_fbo (void) { static const char vertex_shader_source[] = "attribute vec2 pos;\n" "\n" "void\n" "main ()\n" "{\n" " gl_Position = vec4 (pos, 0.0, 1.0);\n" "}\n"; static const char fragment_shader_source[] = "precision mediump float;\n" "uniform vec4 color;\n" "\n" "void\n" "main ()\n" "{\n" " gl_FragColor = color;\n" "}\n"; static const PaintMethod paint_methods[] = { paint_quads, paint_viewport, paint_scissor, paint_cull }; int i; PaintData data; data.fb_width = cogl_framebuffer_get_width (test_fb); data.fb_height = cogl_framebuffer_get_height (test_fb); for (i = 0; i < G_N_ELEMENTS (paint_methods); i++) { CoglTexture *offscreen_texture; CoglOffscreen *offscreen; CoglPipeline *pipeline; CoglGLES2Context *gles2_ctx; GLuint program; CoglError *error = NULL; create_gles2_context (&offscreen_texture, &offscreen, &pipeline, &gles2_ctx, &data.gles2); if (!cogl_push_gles2_context (test_ctx, gles2_ctx, offscreen, offscreen, &error)) g_error ("Failed to push gles2 context: %s\n", error->message); program = create_program (data.gles2, vertex_shader_source, fragment_shader_source); data.gles2->glClearColor (1.0, 1.0, 0.0, 1.0); data.gles2->glClear (GL_COLOR_BUFFER_BIT); data.gles2->glUseProgram (program); data.color_location = data.gles2->glGetUniformLocation (program, "color"); if (data.color_location == -1) g_error ("Couldn't find ‘color’ uniform"); data.pos_location = data.gles2->glGetAttribLocation (program, "pos"); if (data.pos_location == -1) g_error ("Couldn't find ‘pos’ attribute"); paint_methods[i] (&data); verify_read_pixels (&data); cogl_pop_gles2_context (test_ctx); cogl_object_unref (offscreen); cogl_object_unref (gles2_ctx); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1.0f, 1.0f, 1.0f, -1.0f); cogl_object_unref (pipeline); cogl_object_unref (offscreen_texture); /* Top half of the framebuffer should be red */ test_utils_check_pixel (test_fb, data.fb_width / 2, data.fb_height / 4, 0xff0000ff); /* Bottom half should be blue */ test_utils_check_pixel (test_fb, data.fb_width / 2, data.fb_height * 3 / 4, 0x0000ffff); } } /* Position to draw a rectangle in. The top half of this rectangle * will be red, and the bottom will be blue */ #define RECTANGLE_DRAW_X 10 #define RECTANGLE_DRAW_Y 15 /* Position to copy the rectangle to in the destination texture */ #define RECTANGLE_COPY_X 110 #define RECTANGLE_COPY_Y 115 #define RECTANGLE_WIDTH 30 #define RECTANGLE_HEIGHT 40 static void verify_region (const CoglGLES2Vtable *gles2, int x, int y, int width, int height, uint32_t expected_pixel) { uint8_t *buf, *p; buf = malloc (width * height * 4); gles2->glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buf); for (p = buf + width * height * 4; p > buf; p -= 4) test_utils_compare_pixel (p - 4, expected_pixel); free (buf); } void test_gles2_context_copy_tex_image (void) { static const char vertex_shader_source[] = "attribute vec2 pos;\n" "attribute vec2 tex_coord_attrib;\n" "varying vec2 tex_coord_varying;\n" "\n" "void\n" "main ()\n" "{\n" " gl_Position = vec4 (pos, 0.0, 1.0);\n" " tex_coord_varying = tex_coord_attrib;\n" "}\n"; static const char fragment_shader_source[] = "precision mediump float;\n" "varying vec2 tex_coord_varying;\n" "uniform sampler2D tex;\n" "\n" "void\n" "main ()\n" "{\n" " gl_FragColor = texture2D (tex, tex_coord_varying);\n" "}\n"; static const float verts[] = { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); CoglTexture *offscreen_texture; CoglOffscreen *offscreen; CoglPipeline *pipeline; CoglGLES2Context *gles2_ctx; const CoglGLES2Vtable *gles2; CoglError *error = NULL; GLuint tex; GLint tex_uniform_location; GLint pos_location; GLint tex_coord_location; GLuint program; create_gles2_context (&offscreen_texture, &offscreen, &pipeline, &gles2_ctx, &gles2); if (!cogl_push_gles2_context (test_ctx, gles2_ctx, offscreen, offscreen, &error)) g_error ("Failed to push gles2 context: %s\n", error->message); gles2->glClearColor (1.0, 1.0, 0.0, 1.0); gles2->glClear (GL_COLOR_BUFFER_BIT); /* Draw a rectangle using clear and the scissor so that we don't * have to create a shader */ gles2->glEnable (GL_SCISSOR_TEST); /* Top half red */ gles2->glScissor (RECTANGLE_DRAW_X, RECTANGLE_DRAW_Y + RECTANGLE_HEIGHT / 2, RECTANGLE_WIDTH, RECTANGLE_HEIGHT / 2); gles2->glClearColor (1.0, 0.0, 0.0, 1.0); gles2->glClear (GL_COLOR_BUFFER_BIT); /* Bottom half blue */ gles2->glScissor (RECTANGLE_DRAW_X, RECTANGLE_DRAW_Y, RECTANGLE_WIDTH, RECTANGLE_HEIGHT / 2); gles2->glClearColor (0.0, 0.0, 1.0, 1.0); gles2->glClear (GL_COLOR_BUFFER_BIT); /* Draw where the rectangle would be if the coordinates were flipped * in white to make it obvious that that is the problem if the * assertion fails */ gles2->glScissor (RECTANGLE_DRAW_X, fb_width - (RECTANGLE_DRAW_Y + RECTANGLE_HEIGHT), RECTANGLE_WIDTH, RECTANGLE_HEIGHT); gles2->glClearColor (1.0, 1.0, 1.0, 1.0); gles2->glClear (GL_COLOR_BUFFER_BIT); gles2->glDisable (GL_SCISSOR_TEST); /* Create a texture */ gles2->glGenTextures (1, &tex); gles2->glBindTexture (GL_TEXTURE_2D, tex); gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /* Copy the entire framebuffer into the texture */ gles2->glCopyTexImage2D (GL_TEXTURE_2D, 0, /* level */ GL_RGBA, 0, 0, /* x/y */ fb_width, fb_height, 0 /* border */); /* Copy the rectangle into another part of the texture */ gles2->glCopyTexSubImage2D (GL_TEXTURE_2D, 0, /* level */ RECTANGLE_COPY_X, RECTANGLE_COPY_Y, RECTANGLE_DRAW_X, RECTANGLE_DRAW_Y, RECTANGLE_WIDTH, RECTANGLE_HEIGHT); /* Clear the framebuffer to make the test more thorough */ gles2->glClearColor (1.0, 1.0, 0.0, 1.0); gles2->glClear (GL_COLOR_BUFFER_BIT); /* Create a program to render the texture */ program = create_program (gles2, vertex_shader_source, fragment_shader_source); pos_location = gles2->glGetAttribLocation (program, "pos"); if (pos_location == -1) g_error ("Couldn't find ‘pos’ attribute"); tex_coord_location = gles2->glGetAttribLocation (program, "tex_coord_attrib"); if (tex_coord_location == -1) g_error ("Couldn't find ‘tex_coord_attrib’ attribute"); tex_uniform_location = gles2->glGetUniformLocation (program, "tex"); if (tex_uniform_location == -1) g_error ("Couldn't find ‘tex’ uniform"); gles2->glUseProgram (program); gles2->glUniform1i (tex_uniform_location, 0); /* Render the texture to fill the framebuffer */ gles2->glEnableVertexAttribArray (pos_location); gles2->glVertexAttribPointer (pos_location, 2, /* n_components */ GL_FLOAT, FALSE, /* normalized */ sizeof (float) * 4, verts); gles2->glEnableVertexAttribArray (tex_coord_location); gles2->glVertexAttribPointer (tex_coord_location, 2, /* n_components */ GL_FLOAT, FALSE, /* normalized */ sizeof (float) * 4, verts + 2); gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* Verify top of drawn rectangle is red */ verify_region (gles2, RECTANGLE_DRAW_X, RECTANGLE_DRAW_Y + RECTANGLE_HEIGHT / 2, RECTANGLE_WIDTH, RECTANGLE_HEIGHT / 2, 0xff0000ff); /* Verify bottom of drawn rectangle is blue */ verify_region (gles2, RECTANGLE_DRAW_X, RECTANGLE_DRAW_Y, RECTANGLE_WIDTH, RECTANGLE_HEIGHT / 2, 0x0000ffff); /* Verify top of copied rectangle is red */ verify_region (gles2, RECTANGLE_COPY_X, RECTANGLE_COPY_Y + RECTANGLE_HEIGHT / 2, RECTANGLE_WIDTH, RECTANGLE_HEIGHT / 2, 0xff0000ff); /* Verify bottom of copied rectangle is blue */ verify_region (gles2, RECTANGLE_COPY_X, RECTANGLE_COPY_Y, RECTANGLE_WIDTH, RECTANGLE_HEIGHT / 2, 0x0000ffff); cogl_pop_gles2_context (test_ctx); cogl_object_unref (offscreen); cogl_object_unref (gles2_ctx); cogl_object_unref (pipeline); cogl_object_unref (offscreen_texture); } muffin-5.2.1/cogl/tests/conform/test-layer-remove.c0000664000175000017500000001162414211404421022421 0ustar jpeisachjpeisach#include #include "test-utils.h" #define TEST_SQUARE_SIZE 10 static CoglPipeline * create_two_layer_pipeline (void) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglColor color; /* The pipeline is initially black */ cogl_pipeline_set_color4ub (pipeline, 0, 0, 0, 255); /* The first layer adds a full red component */ cogl_color_init_from_4ub (&color, 255, 0, 0, 255); cogl_pipeline_set_layer_combine_constant (pipeline, 0, &color); cogl_pipeline_set_layer_combine (pipeline, 0, /* layer_num */ "RGBA=ADD(PREVIOUS,CONSTANT)", NULL); /* The second layer adds a full green component */ cogl_color_init_from_4ub (&color, 0, 255, 0, 255); cogl_pipeline_set_layer_combine_constant (pipeline, 1, &color); cogl_pipeline_set_layer_combine (pipeline, 1, /* layer_num */ "RGBA=ADD(PREVIOUS,CONSTANT)", NULL); return pipeline; } static void test_color (CoglPipeline *pipeline, uint32_t color, int pos) { cogl_framebuffer_draw_rectangle (test_fb, pipeline, pos * TEST_SQUARE_SIZE, 0, pos * TEST_SQUARE_SIZE + TEST_SQUARE_SIZE, TEST_SQUARE_SIZE); test_utils_check_pixel (test_fb, pos * TEST_SQUARE_SIZE + TEST_SQUARE_SIZE / 2, TEST_SQUARE_SIZE / 2, color); } void test_layer_remove (void) { CoglPipeline *pipeline0, *pipeline1; CoglColor color; int pos = 0; cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); /** TEST 1 **/ /* Basic sanity check that the pipeline combines the two colors * together properly */ pipeline0 = create_two_layer_pipeline (); test_color (pipeline0, 0xffff00ff, pos++); cogl_object_unref (pipeline0); /** TEST 2 **/ /* Check that we can remove the second layer */ pipeline0 = create_two_layer_pipeline (); cogl_pipeline_remove_layer (pipeline0, 1); test_color (pipeline0, 0xff0000ff, pos++); cogl_object_unref (pipeline0); /** TEST 3 **/ /* Check that we can remove the first layer */ pipeline0 = create_two_layer_pipeline (); cogl_pipeline_remove_layer (pipeline0, 0); test_color (pipeline0, 0x00ff00ff, pos++); cogl_object_unref (pipeline0); /** TEST 4 **/ /* Check that we can make a copy and remove a layer from the * original pipeline */ pipeline0 = create_two_layer_pipeline (); pipeline1 = cogl_pipeline_copy (pipeline0); cogl_pipeline_remove_layer (pipeline0, 1); test_color (pipeline0, 0xff0000ff, pos++); test_color (pipeline1, 0xffff00ff, pos++); cogl_object_unref (pipeline0); cogl_object_unref (pipeline1); /** TEST 5 **/ /* Check that we can make a copy and remove the second layer from the * new pipeline */ pipeline0 = create_two_layer_pipeline (); pipeline1 = cogl_pipeline_copy (pipeline0); cogl_pipeline_remove_layer (pipeline1, 1); test_color (pipeline0, 0xffff00ff, pos++); test_color (pipeline1, 0xff0000ff, pos++); cogl_object_unref (pipeline0); cogl_object_unref (pipeline1); /** TEST 6 **/ /* Check that we can make a copy and remove the first layer from the * new pipeline */ pipeline0 = create_two_layer_pipeline (); pipeline1 = cogl_pipeline_copy (pipeline0); cogl_pipeline_remove_layer (pipeline1, 0); test_color (pipeline0, 0xffff00ff, pos++); test_color (pipeline1, 0x00ff00ff, pos++); cogl_object_unref (pipeline0); cogl_object_unref (pipeline1); /** TEST 7 **/ /* Check that we can modify a layer in a child pipeline */ pipeline0 = create_two_layer_pipeline (); pipeline1 = cogl_pipeline_copy (pipeline0); cogl_color_init_from_4ub (&color, 0, 0, 255, 255); cogl_pipeline_set_layer_combine_constant (pipeline1, 0, &color); test_color (pipeline0, 0xffff00ff, pos++); test_color (pipeline1, 0x00ffffff, pos++); cogl_object_unref (pipeline0); cogl_object_unref (pipeline1); /** TEST 8 **/ /* Check that we can modify a layer in a child pipeline but then remove it */ pipeline0 = create_two_layer_pipeline (); pipeline1 = cogl_pipeline_copy (pipeline0); cogl_color_init_from_4ub (&color, 0, 0, 255, 255); cogl_pipeline_set_layer_combine_constant (pipeline1, 0, &color); cogl_pipeline_remove_layer (pipeline1, 0); test_color (pipeline0, 0xffff00ff, pos++); test_color (pipeline1, 0x00ff00ff, pos++); cogl_object_unref (pipeline0); cogl_object_unref (pipeline1); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-write-texture-formats.c0000664000175000017500000001337214211404421024315 0ustar jpeisachjpeisach#include #include #include "test-utils.h" /* * This tests writing data to an RGBA texture in all of the available * pixel formats */ static void test_color (CoglTexture *texture, uint32_t expected_pixel) { uint8_t received_pixel[4]; cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ received_pixel); test_utils_compare_pixel_and_alpha (received_pixel, expected_pixel); } static void test_write_byte (CoglContext *context, CoglPixelFormat format, uint8_t byte, uint32_t expected_pixel) { CoglTexture *texture = test_utils_create_color_texture (context, 0); cogl_texture_set_region (texture, 0, 0, /* src_x / src_y */ 0, 0, /* dst_x / dst_y */ 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 1, /* rowstride */ &byte); test_color (texture, expected_pixel); cogl_object_unref (texture); } static void test_write_short (CoglContext *context, CoglPixelFormat format, uint16_t value, uint32_t expected_pixel) { CoglTexture *texture = test_utils_create_color_texture (context, 0); cogl_texture_set_region (texture, 0, 0, /* src_x / src_y */ 0, 0, /* dst_x / dst_y */ 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 2, /* rowstride */ (uint8_t *) &value); test_color (texture, expected_pixel); cogl_object_unref (texture); } static void test_write_bytes (CoglContext *context, CoglPixelFormat format, uint32_t value, uint32_t expected_pixel) { CoglTexture *texture = test_utils_create_color_texture (context, 0); value = GUINT32_TO_BE (value); cogl_texture_set_region (texture, 0, 0, /* src_x / src_y */ 0, 0, /* dst_x / dst_y */ 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 4, /* rowstride */ (uint8_t *) &value); test_color (texture, expected_pixel); cogl_object_unref (texture); } static void test_write_int (CoglContext *context, CoglPixelFormat format, uint32_t expected_pixel, ...) { va_list ap; int bits; uint32_t tex_data = 0; int bits_sum = 0; CoglTexture *texture = test_utils_create_color_texture (context, 0); va_start (ap, expected_pixel); /* Convert the va args into a single 32-bit value */ while ((bits = va_arg (ap, int)) != -1) { uint32_t value = (va_arg (ap, int) * ((1 << bits) - 1) + 127) / 255; bits_sum += bits; tex_data |= value << (32 - bits_sum); } va_end (ap); cogl_texture_set_region (texture, 0, 0, /* src_x / src_y */ 0, 0, /* dst_x / dst_y */ 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 4, /* rowstride */ (uint8_t *) &tex_data); test_color (texture, expected_pixel); cogl_object_unref (texture); } void test_write_texture_formats (void) { test_write_byte (test_ctx, COGL_PIXEL_FORMAT_A_8, 0x34, 0x00000034); #if 0 /* I'm not sure what's the right value to put here because Nvidia and Mesa seem to behave differently so one of them must be wrong. */ test_write_byte (test_ctx, COGL_PIXEL_FORMAT_G_8, 0x34, 0x340000ff); #endif /* We should always be able to read from an RG buffer regardless of * whether RG textures are supported because Cogl will do the * conversion for us */ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_RG_88, 0x123456ff, 0x123400ff); test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGB_565, 0x0843, 0x080819ff); test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGBA_4444_PRE, 0x1234, 0x11223344); test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGBA_5551_PRE, 0x0887, 0x081019ff); test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_RGB_888, 0x123456ff, 0x123456ff); test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_BGR_888, 0x563412ff, 0x123456ff); test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0x12345678, 0x12345678); test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_BGRA_8888_PRE, 0x56341278, 0x12345678); test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_ARGB_8888_PRE, 0x78123456, 0x12345678); test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_ABGR_8888_PRE, 0x78563412, 0x12345678); test_write_int (test_ctx, COGL_PIXEL_FORMAT_RGBA_1010102_PRE, 0x123456ff, 10, 0x12, 10, 0x34, 10, 0x56, 2, 0xff, -1); test_write_int (test_ctx, COGL_PIXEL_FORMAT_BGRA_1010102_PRE, 0x123456ff, 10, 0x56, 10, 0x34, 10, 0x12, 2, 0xff, -1); test_write_int (test_ctx, COGL_PIXEL_FORMAT_ARGB_2101010_PRE, 0x123456ff, 2, 0xff, 10, 0x12, 10, 0x34, 10, 0x56, -1); test_write_int (test_ctx, COGL_PIXEL_FORMAT_ABGR_2101010_PRE, 0x123456ff, 2, 0xff, 10, 0x56, 10, 0x34, 10, 0x12, -1); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-sparse-pipeline.c0000664000175000017500000000322214211404421023105 0ustar jpeisachjpeisach#include #include #include "test-utils.h" typedef struct _TestState { int fb_width; int fb_height; } TestState; static void test_sparse_layer_combine (TestState *state) { CoglPipeline *pipeline; CoglTexture *tex1, *tex2; cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); /* This tests that the TEXTURE_* numbers used in the layer combine string refer to the layer number rather than the unit numbers by creating a pipeline with very large layer numbers. This should end up being mapped to much smaller unit numbers */ tex1 = test_utils_create_color_texture (test_ctx, 0xff0000ff); tex2 = test_utils_create_color_texture (test_ctx, 0x00ff00ff); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 50, tex1); cogl_pipeline_set_layer_texture (pipeline, 100, tex2); cogl_pipeline_set_layer_combine (pipeline, 200, "RGBA = ADD(TEXTURE_50, TEXTURE_100)", NULL); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1, -1, 1, 1); test_utils_check_pixel (test_fb, 2, 2, 0xffff00ff); cogl_object_unref (pipeline); cogl_object_unref (tex1); cogl_object_unref (tex2); } void test_sparse_pipeline (void) { TestState state; state.fb_width = cogl_framebuffer_get_width (test_fb); state.fb_height = cogl_framebuffer_get_height (test_fb); test_sparse_layer_combine (&state); /* FIXME: This should have a lot more tests, for example testing whether using an attribute with sparse texture coordinates will work */ if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-snippets.c0000664000175000017500000006621114211404421021661 0ustar jpeisachjpeisach#include #include #include "test-utils.h" typedef struct _TestState { int fb_width, fb_height; } TestState; typedef void (* SnippetTestFunc) (TestState *state); static CoglPipeline * create_texture_pipeline (TestState *state) { CoglPipeline *pipeline; CoglTexture *tex; static const uint8_t tex_data[] = { 0xff, 0x00, 0x00, 0xff, /* red */ 0x00, 0xff, 0x00, 0xff, /* green */ 0x00, 0x00, 0xff, 0xff, /* blue */ 0xff, 0xff, 0x00, 0xff, /* yellow */ }; tex = test_utils_texture_new_from_data (test_ctx, 2, 2, /* width/height */ TEST_UTILS_TEXTURE_NO_ATLAS, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 8, /* rowstride */ tex_data); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_pipeline_set_layer_filters (pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_object_unref (tex); return pipeline; } static void simple_fragment_snippet (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Simple fragment snippet */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, /* declarations */ "cogl_color_out.g += 1.0;"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff); } static void simple_vertex_snippet (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Simple vertex snippet */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, NULL, "cogl_color_out.b += 1.0;"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 10, 0, 20, 10); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 15, 5, 0xff00ffff); } static void shared_uniform (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; int location; /* Snippets sharing a uniform across the vertex and fragment hooks */ pipeline = cogl_pipeline_new (test_ctx); location = cogl_pipeline_get_uniform_location (pipeline, "a_value"); cogl_pipeline_set_uniform_1f (pipeline, location, 0.25f); cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, "uniform float a_value;", "cogl_color_out.b += a_value;"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "uniform float a_value;", "cogl_color_out.b += a_value;"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 20, 0, 30, 10); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 25, 5, 0xff0080ff); } static void lots_snippets (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; int location; int i; /* Lots of snippets on one pipeline */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 0, 0, 0, 255); for (i = 0; i < 3; i++) { char letter = 'x' + i; char *uniform_name = g_strdup_printf ("%c_value", letter); char *declarations = g_strdup_printf ("uniform float %s;\n", uniform_name); char *code = g_strdup_printf ("cogl_color_out.%c = %s;\n", letter, uniform_name); location = cogl_pipeline_get_uniform_location (pipeline, uniform_name); cogl_pipeline_set_uniform_1f (pipeline, location, (i + 1) * 0.1f); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, declarations, code); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); free (code); free (uniform_name); free (declarations); } cogl_framebuffer_draw_rectangle (test_fb, pipeline, 30, 0, 40, 10); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 35, 5, 0x19334cff); } static void shared_variable_pre_post (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Test that the pre string can declare variables used by the post string */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 255, 255, 255, 255); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, /* declarations */ "cogl_color_out = redvec;"); cogl_snippet_set_pre (snippet, "vec4 redvec = vec4 (1.0, 0.0, 0.0, 1.0);"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 40, 0, 50, 10); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 45, 5, 0xff0000ff); } static void test_pipeline_caching (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Check that the pipeline caching works when unrelated pipelines share snippets state. It's too hard to actually assert this in the conformance test but at least it should be possible to see by setting COGL_DEBUG=show-source to check whether this shader gets generated twice */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "/* This comment should only be seen ONCE\n" " when COGL_DEBUG=show-source is TRUE\n" " even though it is used in two different\n" " unrelated pipelines */", "cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);\n"); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_add_snippet (pipeline, snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 50, 0, 60, 10); cogl_object_unref (pipeline); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_add_snippet (pipeline, snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 60, 0, 70, 10); cogl_object_unref (pipeline); cogl_object_unref (snippet); test_utils_check_pixel (test_fb, 55, 5, 0x00ff00ff); test_utils_check_pixel (test_fb, 65, 5, 0x00ff00ff); } static void test_replace_string (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Check the replace string */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, NULL); cogl_snippet_set_pre (snippet, "cogl_color_out = vec4 (0.0, 0.5, 0.0, 1.0);"); /* Remove the generated output. If the replace string isn't working then the code from the pre string would get overwritten with white */ cogl_snippet_set_replace (snippet, "/* do nothing */"); cogl_snippet_set_post (snippet, "cogl_color_out += vec4 (0.5, 0.0, 0.0, 1.0);"); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_add_snippet (pipeline, snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 70, 0, 80, 10); cogl_object_unref (pipeline); cogl_object_unref (snippet); test_utils_check_pixel (test_fb, 75, 5, 0x808000ff); } static void test_texture_lookup_hook (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Check the texture lookup hook */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, NULL, "cogl_texel.b += 1.0;"); /* Flip the texture coordinates around the y axis so that it will get the green texel */ cogl_snippet_set_pre (snippet, "cogl_tex_coord.x = 1.0 - cogl_tex_coord.x;"); pipeline = create_texture_pipeline (state); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 80, 0, 90, 10, 0, 0, 0, 0); cogl_object_unref (pipeline); cogl_object_unref (snippet); test_utils_check_pixel (test_fb, 85, 5, 0x00ffffff); } static void test_multiple_samples (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Check that we can use the passed in sampler in the texture lookup to sample multiple times */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, NULL, NULL); cogl_snippet_set_replace (snippet, "cogl_texel = " "texture2D (cogl_sampler, vec2 (0.25, 0.25)) + " "texture2D (cogl_sampler, vec2 (0.75, 0.25));"); pipeline = create_texture_pipeline (state); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10); cogl_object_unref (pipeline); cogl_object_unref (snippet); test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff); } static void test_replace_lookup_hook (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Check replacing the texture lookup hook */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, NULL, NULL); cogl_snippet_set_replace (snippet, "cogl_texel = vec4 (0.0, 0.0, 1.0, 0.0);"); pipeline = create_texture_pipeline (state); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 90, 0, 100, 10, 0, 0, 0, 0); cogl_object_unref (pipeline); cogl_object_unref (snippet); test_utils_check_pixel (test_fb, 95, 5, 0x0000ffff); } static void test_replace_snippet (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Test replacing a previous snippet */ pipeline = create_texture_pipeline (state); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, "cogl_color_out = vec4 (0.5, 0.5, 0.5, 1.0);"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, NULL); cogl_snippet_set_pre (snippet, "cogl_color_out = vec4 (1.0, 1.0, 1.0, 1.0);"); cogl_snippet_set_replace (snippet, "cogl_color_out *= vec4 (1.0, 0.0, 0.0, 1.0);"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 100, 0, 110, 10, 0, 0, 0, 0); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 105, 5, 0xff0000ff); } static void test_replace_fragment_layer (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Test replacing the fragment layer code */ pipeline = create_texture_pipeline (state); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT, NULL, NULL); cogl_snippet_set_replace (snippet, "cogl_layer = vec4 (0.0, 0.0, 1.0, 1.0);"); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_object_unref (snippet); /* Add a second layer which samples from the texture in the first layer. The snippet override should cause the first layer not to generate the code for the texture lookup but this second layer should still be able to cause it to be generated */ cogl_pipeline_set_layer_combine (pipeline, 1, "RGB = ADD(TEXTURE_0, PREVIOUS)" "A = REPLACE(PREVIOUS)", NULL); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 110, 0, 120, 10, 0, 0, 0, 0); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 115, 5, 0xff00ffff); } static void test_modify_fragment_layer (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Test modifying the fragment layer code */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_uniform_1f (pipeline, cogl_pipeline_get_uniform_location (pipeline, "a_value"), 0.5); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT, "uniform float a_value;", "cogl_layer.g = a_value;"); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 120, 0, 130, 10, 0, 0, 0, 0); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 125, 5, 0xff80ffff); } static void test_modify_vertex_layer (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; CoglMatrix matrix; /* Test modifying the vertex layer code */ pipeline = create_texture_pipeline (state); cogl_matrix_init_identity (&matrix); cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f); cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM, NULL, "cogl_tex_coord.x = 1.0;"); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 130, 0, 140, 10, 0, 0, 0, 0); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 135, 5, 0xffff00ff); } static void test_replace_vertex_layer (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; CoglMatrix matrix; /* Test replacing the vertex layer code */ pipeline = create_texture_pipeline (state); cogl_matrix_init_identity (&matrix); cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f); cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM, NULL, NULL); cogl_snippet_set_replace (snippet, "cogl_tex_coord.x = 1.0;\n"); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 140, 0, 150, 10, 0, 0, 0, 0); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 145, 5, 0x00ff00ff); } static void test_vertex_transform_hook (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; CoglMatrix identity_matrix; CoglMatrix matrix; int location; /* Test the vertex transform hook */ cogl_matrix_init_identity (&identity_matrix); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 255, 0, 255, 255); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_TRANSFORM, "uniform mat4 pmat;", NULL); cogl_snippet_set_replace (snippet, "cogl_position_out = " "pmat * cogl_position_in;"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); /* Copy the current projection matrix to a uniform */ cogl_framebuffer_get_projection_matrix (test_fb, &matrix); location = cogl_pipeline_get_uniform_location (pipeline, "pmat"); cogl_pipeline_set_uniform_matrix (pipeline, location, 4, /* dimensions */ 1, /* count */ FALSE, /* don't transpose */ cogl_matrix_get_array (&matrix)); /* Replace the real projection matrix with the identity. This should mess up the drawing unless the snippet replacement is working */ cogl_framebuffer_set_projection_matrix (test_fb, &identity_matrix); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 150, 0, 160, 10); cogl_object_unref (pipeline); /* Restore the projection matrix */ cogl_framebuffer_set_projection_matrix (test_fb, &matrix); test_utils_check_pixel (test_fb, 155, 5, 0xff00ffff); } static void test_global_vertex_hook (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; pipeline = cogl_pipeline_new (test_ctx); /* Creates a function in the global declarations hook which is used * by a subsequent snippet. The subsequent snippets replace any * previous snippets but this shouldn't prevent the global * declarations from being generated */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS, /* declarations */ "float\n" "multiply_by_two (float number)\n" "{\n" " return number * 2.0;\n" "}\n", /* post */ "This string shouldn't be used so " "we can safely put garbage in here."); cogl_snippet_set_pre (snippet, "This string shouldn't be used so " "we can safely put garbage in here."); cogl_snippet_set_replace (snippet, "This string shouldn't be used so " "we can safely put garbage in here."); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, NULL, /* declarations */ NULL /* replace */); cogl_snippet_set_replace (snippet, "cogl_color_out.r = multiply_by_two (0.5);\n" "cogl_color_out.gba = vec3 (0.0, 0.0, 1.0);\n" "cogl_position_out = cogl_position_in;\n"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1, 1, 10.0f * 2.0f / state->fb_width - 1.0f, 10.0f * 2.0f / state->fb_height - 1.0f); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 5, 5, 0xff0000ff); } static void test_global_fragment_hook (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; pipeline = cogl_pipeline_new (test_ctx); /* Creates a function in the global declarations hook which is used * by a subsequent snippet. The subsequent snippets replace any * previous snippets but this shouldn't prevent the global * declarations from being generated */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS, /* declarations */ "float\n" "multiply_by_four (float number)\n" "{\n" " return number * 4.0;\n" "}\n", /* post */ "This string shouldn't be used so " "we can safely put garbage in here."); cogl_snippet_set_pre (snippet, "This string shouldn't be used so " "we can safely put garbage in here."); cogl_snippet_set_replace (snippet, "This string shouldn't be used so " "we can safely put garbage in here."); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, /* declarations */ NULL /* replace */); cogl_snippet_set_replace (snippet, "cogl_color_out.r = multiply_by_four (0.25);\n" "cogl_color_out.gba = vec3 (0.0, 0.0, 1.0);\n"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 5, 5, 0xff0000ff); } static void test_snippet_order (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; /* Verify that the snippets are executed in the right order. We'll replace the r component of the color in the pre sections of the snippets and the g component in the post. The pre sections should be executed in the reverse order they were added and the post sections in the same order as they were added. Therefore the r component should be taken from the the second snippet and the g component from the first */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 0, 0, 0, 255); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, "cogl_color_out.g = 0.5;\n"); cogl_snippet_set_pre (snippet, "cogl_color_out.r = 0.5;\n"); cogl_snippet_set_replace (snippet, "cogl_color_out.ba = vec2 (0.0, 1.0);"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, "cogl_color_out.g = 1.0;\n"); cogl_snippet_set_pre (snippet, "cogl_color_out.r = 1.0;\n"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 160, 0, 170, 10); cogl_object_unref (pipeline); test_utils_check_pixel (test_fb, 165, 5, 0x80ff00ff); } static void test_naming_texture_units (TestState *state) { CoglPipeline *pipeline; CoglSnippet *snippet; CoglTexture *tex1, *tex2; /* Test that we can sample from an arbitrary texture unit by naming its layer number */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, NULL); cogl_snippet_set_replace (snippet, "cogl_color_out = " "texture2D (cogl_sampler100, vec2 (0.0, 0.0)) + " "texture2D (cogl_sampler200, vec2 (0.0, 0.0));"); tex1 = test_utils_create_color_texture (test_ctx, 0xff0000ff); tex2 = test_utils_create_color_texture (test_ctx, 0x00ff00ff); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 100, tex1); cogl_pipeline_set_layer_texture (pipeline, 200, tex2); cogl_pipeline_add_snippet (pipeline, snippet); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10); cogl_object_unref (pipeline); cogl_object_unref (snippet); cogl_object_unref (tex1); cogl_object_unref (tex2); test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff); } static void test_snippet_properties (TestState *state) { CoglSnippet *snippet; /* Sanity check modifying the snippet */ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "foo", "bar"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL); cogl_snippet_set_declarations (snippet, "fu"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL); cogl_snippet_set_post (snippet, "ba"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL); cogl_snippet_set_pre (snippet, "fuba"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba"); cogl_snippet_set_replace (snippet, "baba"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, "baba"); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba"); g_assert_cmpint (cogl_snippet_get_hook (snippet), ==, COGL_SNIPPET_HOOK_FRAGMENT); } static SnippetTestFunc tests[] = { simple_fragment_snippet, simple_vertex_snippet, shared_uniform, lots_snippets, shared_variable_pre_post, test_pipeline_caching, test_replace_string, test_texture_lookup_hook, test_multiple_samples, test_replace_lookup_hook, test_replace_snippet, test_replace_fragment_layer, test_modify_fragment_layer, test_modify_vertex_layer, test_replace_vertex_layer, test_vertex_transform_hook, test_global_fragment_hook, test_global_vertex_hook, test_snippet_order, test_naming_texture_units, test_snippet_properties }; static void run_tests (TestState *state) { int i; for (i = 0; i < G_N_ELEMENTS (tests); i++) { cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); tests[i] (state); } } void test_snippets (void) { TestState state; state.fb_width = cogl_framebuffer_get_width (test_fb); state.fb_height = cogl_framebuffer_get_height (test_fb); cogl_framebuffer_orthographic (test_fb, 0, 0, state.fb_width, state.fb_height, -1, 100); run_tests (&state); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-color-mask.c0000664000175000017500000000623414211404421022062 0ustar jpeisachjpeisach#include #include "test-utils.h" #define TEX_SIZE 128 #define NUM_FBOS 3 typedef struct _TestState { int width; int height; CoglTexture *tex[NUM_FBOS]; CoglFramebuffer *fbo[NUM_FBOS]; } TestState; static void paint (TestState *state) { CoglColor bg; int i; cogl_set_source_color4ub (255, 255, 255, 255); /* We push the third framebuffer first so that later we can switch back to it by popping to test that that works */ cogl_push_framebuffer (state->fbo[2]); cogl_push_framebuffer (state->fbo[0]); cogl_rectangle (-1.0, -1.0, 1.0, 1.0); cogl_pop_framebuffer (); cogl_push_framebuffer (state->fbo[1]); cogl_rectangle (-1.0, -1.0, 1.0, 1.0); cogl_pop_framebuffer (); /* We should now be back on the third framebuffer */ cogl_rectangle (-1.0, -1.0, 1.0, 1.0); cogl_pop_framebuffer (); cogl_color_init_from_4ub (&bg, 128, 128, 128, 255); cogl_clear (&bg, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH); /* Render all of the textures to the screen */ for (i = 0; i < NUM_FBOS; i++) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, state->tex[i]); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 2.0f / NUM_FBOS * i - 1.0f, -1.0f, 2.0f / NUM_FBOS * (i + 1) - 1.0f, 1.0f); cogl_object_unref (pipeline); } /* Verify all of the fbos drew the right color */ for (i = 0; i < NUM_FBOS; i++) { uint8_t expected_colors[NUM_FBOS][4] = { { 0xff, 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff }, { 0x00, 0x00, 0xff, 0xff } }; test_utils_check_pixel_rgb (test_fb, state->width * (i + 0.5f) / NUM_FBOS, state->height / 2, expected_colors[i][0], expected_colors[i][1], expected_colors[i][2]); } } void test_color_mask (void) { TestState state; int i; state.width = cogl_framebuffer_get_width (test_fb); state.height = cogl_framebuffer_get_height (test_fb); for (i = 0; i < NUM_FBOS; i++) { state.tex[i] = test_utils_texture_new_with_size (test_ctx, 128, 128, TEST_UTILS_TEXTURE_NO_ATLAS, COGL_TEXTURE_COMPONENTS_RGB); state.fbo[i] = cogl_offscreen_new_with_texture (state.tex[i]); /* Clear the texture color bits */ cogl_framebuffer_clear4f (state.fbo[i], COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); cogl_framebuffer_set_color_mask (state.fbo[i], i == 0 ? COGL_COLOR_MASK_RED : i == 1 ? COGL_COLOR_MASK_GREEN : COGL_COLOR_MASK_BLUE); } /* XXX: we have to push/pop a framebuffer since this test currently * uses the legacy cogl_rectangle() api. */ cogl_push_framebuffer (test_fb); paint (&state); cogl_pop_framebuffer (); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-pipeline-user-matrix.c0000664000175000017500000001116514211404421024075 0ustar jpeisachjpeisach#include #include #include "test-utils.h" typedef struct _TestState { int width; int height; } TestState; static void validate_result (TestState *state) { uint32_t *pixels, *p; char *screen_pixel; const char *intended_pixel = "#ffffff"; /* The textures are setup so that when added together with the correct matrices then all of the pixels should be white. We can verify this by reading back the entire stage */ pixels = malloc (state->width * state->height * 4); cogl_framebuffer_read_pixels (test_fb, 0, 0, state->width, state->height, COGL_PIXEL_FORMAT_RGBA_8888_PRE, (uint8_t *)pixels); for (p = pixels; p < pixels + state->width * state->height; p++) { screen_pixel = g_strdup_printf ("#%06x", GUINT32_FROM_BE (*p) >> 8); g_assert_cmpstr (screen_pixel, ==, intended_pixel); free (screen_pixel); } } static void paint (TestState *state) { /* This texture is painted mirrored around the x-axis */ uint8_t data0[] = { 0xff, 0x00, 0x00, /* red -> becomes bottom left */ 0x00, 0xff, 0x00, /* green -> becomes bottom right */ 0x00, 0x00, 0xff, /* blue -> becomes top left */ 0xff, 0x00, 0xff /* magenta -> becomes top right */ }; /* This texture is painted mirrored about the y-axis */ uint8_t data1[] = { 0x00, 0xff, 0x00, /* green -> becomes top right */ 0xff, 0xff, 0x00, /* yellow -> becomes top left */ 0xff, 0x00, 0xff, /* magenta -> becomes bottom right */ 0x00, 0xff, 0xff /* cyan -> becomes bottom left */ }; CoglTexture *tex0, *tex1; CoglPipeline *pipeline; CoglMatrix matrix; CoglError *error = NULL; cogl_framebuffer_orthographic (test_fb, 0, 0, state->width, state->height, -1, 100); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); cogl_matrix_init_identity (&matrix); cogl_framebuffer_set_modelview_matrix (test_fb, &matrix); tex0 = cogl_texture_new_from_data (2, 2, COGL_TEXTURE_NO_ATLAS, COGL_PIXEL_FORMAT_RGB_888, COGL_PIXEL_FORMAT_ANY, 6, data0); tex1 = cogl_texture_new_from_data (2, 2, COGL_TEXTURE_NO_ATLAS, COGL_PIXEL_FORMAT_RGB_888, COGL_PIXEL_FORMAT_ANY, 6, data1); pipeline = cogl_pipeline_new (test_ctx); /* Set the two textures as layers */ cogl_pipeline_set_layer_texture (pipeline, 0, tex0); cogl_pipeline_set_layer_filters (pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_layer_texture (pipeline, 1, tex1); cogl_pipeline_set_layer_filters (pipeline, 1, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); /* Set a combine mode so that the two textures get added together */ if (!cogl_pipeline_set_layer_combine (pipeline, 1, "RGBA=ADD(PREVIOUS, TEXTURE)", &error)) { g_warning ("Error setting blend string: %s", error->message); g_assert_not_reached (); } /* Set a matrix on the first layer so that it will mirror about the y-axis */ cogl_matrix_init_identity (&matrix); cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f); cogl_matrix_scale (&matrix, 1.0f, -1.0f, 1.0f); cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix); /* Set a matrix on the second layer so that it will mirror about the x-axis */ cogl_matrix_init_identity (&matrix); cogl_matrix_translate (&matrix, 1.0f, 0.0f, 0.0f); cogl_matrix_scale (&matrix, -1.0f, 1.0f, 1.0f); cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, state->width, state->height); cogl_object_unref (tex1); cogl_object_unref (tex0); cogl_object_unref (pipeline); } void test_pipeline_user_matrix (void) { TestState state; state.width = cogl_framebuffer_get_width (test_fb); state.height = cogl_framebuffer_get_height (test_fb); paint (&state); validate_result (&state); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-custom-attributes.c0000664000175000017500000002514114211404421023507 0ustar jpeisachjpeisach#include #include #include "test-utils.h" typedef struct _TestState { CoglPipeline *pipeline; } TestState; typedef struct { int16_t x, y; float r, g, b, a; } FloatVert; typedef struct { int16_t x, y; uint8_t r, g, b, a; } ByteVert; typedef struct { int16_t x, y; int16_t r, g, b, a; } ShortVert; static void test_float_verts (TestState *state, int offset_x, int offset_y) { CoglAttribute *attributes[2]; CoglAttributeBuffer *buffer; CoglPrimitive *primitive; static const FloatVert float_verts[] = { { 0, 10, /**/ 1, 0, 0, 1 }, { 10, 10, /**/ 1, 0, 0, 1 }, { 5, 0, /**/ 1, 0, 0, 1 }, { 10, 10, /**/ 0, 1, 0, 1 }, { 20, 10, /**/ 0, 1, 0, 1 }, { 15, 0, /**/ 0, 1, 0, 1 } }; buffer = cogl_attribute_buffer_new (test_ctx, sizeof (float_verts), float_verts); attributes[0] = cogl_attribute_new (buffer, "cogl_position_in", sizeof (FloatVert), G_STRUCT_OFFSET (FloatVert, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_SHORT); attributes[1] = cogl_attribute_new (buffer, "color", sizeof (FloatVert), G_STRUCT_OFFSET (FloatVert, r), 4, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, offset_x, offset_y, 0.0f); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, 6, /* n_vertices */ attributes, 2); /* n_attributes */ cogl_primitive_draw (primitive, test_fb, state->pipeline); cogl_object_unref (primitive); cogl_framebuffer_pop_matrix (test_fb); cogl_object_unref (attributes[1]); cogl_object_unref (attributes[0]); cogl_object_unref (buffer); test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff); test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff); } static void test_byte_verts (TestState *state, int offset_x, int offset_y) { CoglAttribute *attributes[2]; CoglAttributeBuffer *buffer, *unnorm_buffer; CoglPrimitive *primitive; static const ByteVert norm_verts[] = { { 0, 10, /**/ 255, 0, 0, 255 }, { 10, 10, /**/ 255, 0, 0, 255 }, { 5, 0, /**/ 255, 0, 0, 255 }, { 10, 10, /**/ 0, 255, 0, 255 }, { 20, 10, /**/ 0, 255, 0, 255 }, { 15, 0, /**/ 0, 255, 0, 255 } }; static const ByteVert unnorm_verts[] = { { 0, 0, /**/ 0, 0, 1, 1 }, { 0, 0, /**/ 0, 0, 1, 1 }, { 0, 0, /**/ 0, 0, 1, 1 }, }; buffer = cogl_attribute_buffer_new (test_ctx, sizeof (norm_verts), norm_verts); attributes[0] = cogl_attribute_new (buffer, "cogl_position_in", sizeof (ByteVert), G_STRUCT_OFFSET (ByteVert, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_SHORT); attributes[1] = cogl_attribute_new (buffer, "color", sizeof (ByteVert), G_STRUCT_OFFSET (ByteVert, r), 4, /* n_components */ COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); cogl_attribute_set_normalized (attributes[1], TRUE); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, offset_x, offset_y, 0.0f); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, 6, /* n_vertices */ attributes, 2); /* n_attributes */ cogl_primitive_draw (primitive, test_fb, state->pipeline); cogl_object_unref (primitive); cogl_object_unref (attributes[1]); /* Test again with unnormalized attributes */ unnorm_buffer = cogl_attribute_buffer_new (test_ctx, sizeof (unnorm_verts), unnorm_verts); attributes[1] = cogl_attribute_new (unnorm_buffer, "color", sizeof (ByteVert), G_STRUCT_OFFSET (ByteVert, r), 4, /* n_components */ COGL_ATTRIBUTE_TYPE_BYTE); cogl_framebuffer_translate (test_fb, 20, 0, 0); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ attributes, 2); /* n_attributes */ cogl_primitive_draw (primitive, test_fb, state->pipeline); cogl_object_unref (primitive); cogl_framebuffer_pop_matrix (test_fb); cogl_object_unref (attributes[0]); cogl_object_unref (attributes[1]); cogl_object_unref (buffer); cogl_object_unref (unnorm_buffer); test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff); test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff); test_utils_check_pixel (test_fb, offset_x + 25, offset_y + 5, 0x0000ffff); } static void test_short_verts (TestState *state, int offset_x, int offset_y) { CoglAttribute *attributes[2]; CoglAttributeBuffer *buffer; CoglPipeline *pipeline, *pipeline2; CoglSnippet *snippet; CoglPrimitive *primitive; static const ShortVert short_verts[] = { { -10, -10, /**/ 0xffff, 0, 0, 0xffff }, { -1, -10, /**/ 0xffff, 0, 0, 0xffff }, { -5, -1, /**/ 0xffff, 0, 0, 0xffff } }; pipeline = cogl_pipeline_copy (state->pipeline); cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); buffer = cogl_attribute_buffer_new (test_ctx, sizeof (short_verts), short_verts); attributes[0] = cogl_attribute_new (buffer, "cogl_position_in", sizeof (ShortVert), G_STRUCT_OFFSET (ShortVert, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_SHORT); attributes[1] = cogl_attribute_new (buffer, "color", sizeof (ShortVert), G_STRUCT_OFFSET (ShortVert, r), 4, /* n_components */ COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT); cogl_attribute_set_normalized (attributes[1], TRUE); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, offset_x + 10.0f, offset_y + 10.0f, 0.0f); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ attributes, 2); /* n_attributes */ cogl_primitive_draw (primitive, test_fb, pipeline); cogl_object_unref (primitive); cogl_framebuffer_pop_matrix (test_fb); cogl_object_unref (attributes[0]); /* Test again treating the attribute as unsigned */ attributes[0] = cogl_attribute_new (buffer, "cogl_position_in", sizeof (ShortVert), G_STRUCT_OFFSET (ShortVert, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT); /* XXX: this is a hack to force the pipeline to use the glsl backend * because we know it's not possible to test short vertex position * components with the legacy GL backend since which might otherwise * be used internally... */ pipeline2 = cogl_pipeline_new (test_ctx); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, "attribute vec4 color;", "cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);"); cogl_pipeline_add_snippet (pipeline2, snippet); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, offset_x + 10.0f - 65525.0f, offset_y - 65525, 0.0f); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ attributes, 1); /* n_attributes */ cogl_primitive_draw (primitive, test_fb, pipeline2); cogl_object_unref (primitive); cogl_framebuffer_pop_matrix (test_fb); cogl_object_unref (attributes[0]); cogl_object_unref (pipeline2); cogl_object_unref (pipeline); cogl_object_unref (buffer); test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff); test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff); } static void paint (TestState *state) { cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); test_float_verts (state, 0, 0); test_byte_verts (state, 0, 10); test_short_verts (state, 0, 20); } void test_custom_attributes (void) { CoglSnippet *snippet; TestState state; cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); state.pipeline = cogl_pipeline_new (test_ctx); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, "attribute vec4 color;", "cogl_color_out = color;"); cogl_pipeline_add_snippet (state.pipeline, snippet); paint (&state); cogl_object_unref (state.pipeline); cogl_object_unref (snippet); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-vertex-buffer-mutability.c0000664000175000017500000001153114211404421024754 0ustar jpeisachjpeisach #include #include #include "test-conform-common.h" /* This test verifies that modifying a vertex buffer works, by updating * vertex positions, and deleting and re-adding different color attributes. * * If you want visual feedback of what this test paints for debugging purposes, * then remove the call to clutter_main_quit() in validate_result. */ typedef struct _TestState { CoglHandle buffer; ClutterGeometry stage_geom; } TestState; static void validate_result (TestState *state) { GLubyte pixel[4]; GLint y_off = 90; /* NB: We ignore the alpha, since we don't know if our render target is * RGB or RGBA */ #define RED 0 #define GREEN 1 #define BLUE 2 /* Should see a red pixel */ cogl_read_pixels (110, y_off, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[RED] != 0 && pixel[GREEN] == 0 && pixel[BLUE] == 0); /* Should see a green pixel */ cogl_read_pixels (210, y_off, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 1 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[RED] == 0 && pixel[GREEN] != 0 && pixel[BLUE] == 0); #undef RED #undef GREEN #undef BLUE /* Comment this out if you want visual feedback of what this test * paints. */ clutter_main_quit (); } static void on_paint (ClutterActor *actor, TestState *state) { GLfloat triangle_verts[3][2] = { {100.0, 0.0}, {200.0, 100.0}, {100.0, 100.0} }; GLbyte triangle_colors[3][4] = { {0x00, 0xff, 0x00, 0xff}, /* blue */ {0x00, 0xff, 0x00, 0x00}, /* transparent blue */ {0x00, 0xff, 0x00, 0x00} /* transparent blue */ }; /* * Draw a red triangle */ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_add (state->buffer, "gl_Vertex", 2, /* n components */ GL_FLOAT, FALSE, /* normalized */ 0, /* stride */ triangle_verts); cogl_vertex_buffer_delete (state->buffer, "gl_Color"); cogl_vertex_buffer_submit (state->buffer); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ /* * Draw a faded green triangle */ cogl_vertex_buffer_add (state->buffer, "gl_Color", 4, /* n components */ GL_UNSIGNED_BYTE, FALSE, /* normalized */ 0, /* stride */ triangle_colors); cogl_vertex_buffer_submit (state->buffer); cogl_translate (100, 0, 0); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ validate_result (state); } static CoglBool queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_vertex_buffer_mutability (TestUtilsGTestFixture *fixture, void *data) { TestState state; ClutterActor *stage; ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff}; ClutterActor *group; unsigned int idle_source; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr); clutter_actor_get_geometry (stage, &state.stage_geom); group = clutter_group_new (); clutter_actor_set_size (group, state.stage_geom.width, state.stage_geom.height); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); /* We force continuous redrawing incase someone comments out the * clutter_main_quit and wants visual feedback for the test since we * wont be doing anything else that will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); { GLfloat triangle_verts[3][2] = { {0.0, 0.0}, {100.0, 100.0}, {0.0, 100.0} }; GLbyte triangle_colors[3][4] = { {0x00, 0x00, 0xff, 0xff}, /* blue */ {0x00, 0x00, 0xff, 0x00}, /* transparent blue */ {0x00, 0x00, 0xff, 0x00} /* transparent blue */ }; state.buffer = cogl_vertex_buffer_new (3 /* n vertices */); cogl_vertex_buffer_add (state.buffer, "gl_Vertex", 2, /* n components */ GL_FLOAT, FALSE, /* normalized */ 0, /* stride */ triangle_verts); cogl_vertex_buffer_add (state.buffer, "gl_Color", 4, /* n components */ GL_UNSIGNED_BYTE, FALSE, /* normalized */ 0, /* stride */ triangle_colors); cogl_vertex_buffer_submit (state.buffer); } clutter_actor_show_all (stage); clutter_main (); cogl_handle_unref (state.buffer); g_source_remove (idle_source); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-alpha-test.c0000664000175000017500000000465014211404421022055 0ustar jpeisachjpeisach#include #include #include "test-utils.h" static CoglTexture2D * create_texture (CoglContext *context) { static const uint8_t data[] = { 0xff, 0x00, 0x00, 0xff, 0x00, 0xfa, 0x00, 0xfa }; return cogl_texture_2d_new_from_data (context, 2, 1, /* width/height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ data, NULL /* error */); } void test_alpha_test (void) { CoglTexture *tex = create_texture (test_ctx); CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); CoglColor clear_color; cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_pipeline_set_layer_filters (pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_alpha_test_function (pipeline, COGL_PIPELINE_ALPHA_FUNC_GEQUAL, 254 / 255.0f /* alpha reference */); cogl_color_init_from_4ub (&clear_color, 0x00, 0x00, 0xff, 0xff); cogl_framebuffer_clear (test_fb, COGL_BUFFER_BIT_COLOR, &clear_color); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1, -1, 1, 1); cogl_object_unref (pipeline); cogl_object_unref (tex); /* The left side of the framebuffer should use the first pixel from * the texture which is red */ test_utils_check_region (test_fb, 2, 2, fb_width / 2 - 4, fb_height - 4, 0xff0000ff); /* The right side of the framebuffer should use the clear color * because the second pixel from the texture is clipped from the * alpha test */ test_utils_check_region (test_fb, fb_width / 2 + 2, 2, fb_width / 2 - 4, fb_height - 4, 0x0000ffff); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/Makefile.am0000664000175000017500000001132614211404421020724 0ustar jpeisachjpeisachNULL = noinst_PROGRAMS = test-conformance common_sources = \ test-conform-main.c \ $(NULL) unported_test_sources = \ test-fixed.c \ test-materials.c \ test-viewport.c \ test-multitexture.c \ test-npot-texture.c \ test-object.c \ test-readpixels.c \ test-texture-mipmaps.c \ test-texture-pixmap-x11.c \ test-texture-rectangle.c \ test-vertex-buffer-contiguous.c \ test-vertex-buffer-interleved.c \ test-vertex-buffer-mutability.c \ $(NULL) test_sources = \ test-atlas-migration.c \ test-blend-strings.c \ test-blend.c \ test-depth-test.c \ test-color-hsl.c \ test-color-mask.c \ test-backface-culling.c \ test-just-vertex-shader.c \ test-pipeline-user-matrix.c \ test-pipeline-uniforms.c \ test-pixel-buffer.c \ test-premult.c \ test-snippets.c \ test-wrap-modes.c \ test-sub-texture.c \ test-custom-attributes.c \ test-offscreen.c \ test-primitive.c \ test-texture-3d.c \ test-sparse-pipeline.c \ test-read-texture-formats.c \ test-write-texture-formats.c \ test-point-size.c \ test-point-size-attribute.c \ test-point-sprite.c \ test-no-gl-header.c \ test-version.c \ test-gles2-context.c \ test-euler-quaternion.c \ test-layer-remove.c \ test-alpha-test.c \ test-map-buffer-range.c \ test-npot-texture.c \ test-alpha-textures.c \ test-wrap-rectangle-textures.c \ test-texture-get-set-data.c \ test-framebuffer-get-bits.c \ test-primitive-and-journal.c \ test-copy-replace-texture.c \ test-pipeline-cache-unrefs-texture.c \ test-texture-no-allocate.c \ test-pipeline-shader-state.c \ test-texture-rg.c \ test-fence.c \ $(NULL) if BUILD_COGL_PATH test_sources += \ test-path.c \ test-path-clip.c endif test_conformance_SOURCES = $(common_sources) $(test_sources) SHEXT = $(EXEEXT) # For convenience, this provides a way to easily run individual unit tests: .PHONY: wrappers clean-wrappers wrappers: stamp-test-conformance @true stamp-test-conformance: Makefile $(srcdir)/test-conform-main.c @mkdir -p wrappers @sed -n -e 's/^ \{1,\}ADD_TEST *( *\([a-zA-Z0-9_]\{1,\}\).*/\1/p' $(srcdir)/test-conform-main.c > unit-tests @chmod +x $(top_srcdir)/tests/test-launcher.sh @( echo "/stamp-test-conformance" ; \ echo "/test-conformance$(EXEEXT)" ; \ echo "*.o" ; \ echo ".gitignore" ; \ echo "unit-tests" ; ) > .gitignore @for i in `cat unit-tests`; \ do \ unit=`basename $$i | sed -e s/_/-/g`; \ echo " GEN $$unit"; \ ( echo "#!/bin/sh" ; echo "$(top_srcdir)/tests/test-launcher.sh $(abs_builddir)/test-conformance$(EXEEXT) '' '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \ chmod +x $$unit$(SHEXT); \ echo "/$$unit$(SHEXT)" >> .gitignore; \ done \ && echo timestamp > $(@F) clean-wrappers: @for i in `cat unit-tests`; \ do \ unit=`basename $$i | sed -e s/_/-/g`; \ echo " RM $$unit"; \ rm -f $$unit$(SHEXT) ; \ done \ && rm -f unit-tests \ && rm -f stamp-test-conformance # NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting # a phony rule that will generate symlink scripts for running individual tests BUILT_SOURCES = wrappers AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_builddir)/cogl \ -I$(top_srcdir)/test-fixtures AM_CPPFLAGS += \ -DCOGL_ENABLE_EXPERIMENTAL_API \ -DCOGL_DISABLE_DEPRECATED \ -DCOGL_DISABLE_DEPRECATION_WARNINGS \ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" test_conformance_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) -Wno-error=maybe-uninitialized -Wno-error=nested-externs -Wno-error=missing-prototypes test_conformance_LDADD = \ $(COGL_DEP_LIBS) \ $(top_builddir)/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la \ $(LIBM) if BUILD_COGL_PATH test_conformance_LDADD += $(top_builddir)/cogl-path/libmuffin-cogl-path-$(MUFFIN_PLUGIN_API_VERSION).la endif test_conformance_LDFLAGS = -export-dynamic # XXX: uncomment when tests get fixed #test: wrappers # @$(top_srcdir)/tests/run-tests.sh $(abs_builddir)/../config.env $(abs_builddir)/test-conformance$(EXEEXT) # XXX: we could prevent the conformance test suite from running # by simply defining this variable conditionally TEST_PROGS = test-conformance .PHONY: test DISTCLEANFILES = .gitignore # we override the clean-generic target to clean up the wrappers so # we cannot use CLEANFILES clean-generic: clean-wrappers $(QUIET_RM)rm -f .log if ENABLE_INSTALLED_TESTS insttestdir = $(libexecdir)/installed-tests/muffin-cogl/conform insttest_PROGRAMS = test-conformance insttest_DATA = unit-tests testmetadir = $(datadir)/installed-tests/muffin-cogl testmeta_DATA = conform.test conform.test: echo " GEN $@"; \ echo "[Test]" > $@.tmp; \ echo "Type=session" >> $@.tmp; \ echo "Exec=sh -c \"cd $(libexecdir)/installed-tests/muffin-cogl/conform; ../run-tests.sh ../config.env ./test-conformance\"" >> $@.tmp; \ mv $@.tmp $@ CLEANFILES = conform.test endif muffin-5.2.1/cogl/tests/conform/test-sub-texture.c0000664000175000017500000002501214211404421022275 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define SOURCE_SIZE 32 #define SOURCE_DIVISIONS_X 2 #define SOURCE_DIVISIONS_Y 2 #define DIVISION_WIDTH (SOURCE_SIZE / SOURCE_DIVISIONS_X) #define DIVISION_HEIGHT (SOURCE_SIZE / SOURCE_DIVISIONS_Y) #define TEST_INSET 1 static const uint32_t corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] = { 0xff0000ff, /* red top left */ 0x00ff00ff, /* green top right */ 0x0000ffff, /* blue bottom left */ 0xff00ffff /* purple bottom right */ }; typedef struct _TestState { CoglTexture2D *tex; } TestState; static CoglTexture2D * create_source (TestState *state) { int dx, dy; uint8_t *data = malloc (SOURCE_SIZE * SOURCE_SIZE * 4); CoglTexture2D *tex; /* Create a texture with a different coloured rectangle at each corner */ for (dy = 0; dy < SOURCE_DIVISIONS_Y; dy++) for (dx = 0; dx < SOURCE_DIVISIONS_X; dx++) { uint8_t *p = (data + dy * DIVISION_HEIGHT * SOURCE_SIZE * 4 + dx * DIVISION_WIDTH * 4); int x, y; for (y = 0; y < DIVISION_HEIGHT; y++) { for (x = 0; x < DIVISION_WIDTH; x++) { uint32_t color = GUINT32_FROM_BE (corner_colors[dx + dy * SOURCE_DIVISIONS_X]); memcpy (p, &color, 4); p += 4; } p += SOURCE_SIZE * 4 - DIVISION_WIDTH * 4; } } tex = cogl_texture_2d_new_from_data (test_ctx, SOURCE_SIZE, SOURCE_SIZE, COGL_PIXEL_FORMAT_RGBA_8888, SOURCE_SIZE * 4, data, NULL); return tex; } static CoglTexture2D * create_test_texture (TestState *state) { CoglTexture2D *tex; uint8_t *data = malloc (256 * 256 * 4), *p = data; int x, y; /* Create a texture that is 256x256 where the red component ranges from 0->255 along the x axis and the green component ranges from 0->255 along the y axis. The blue and alpha components are all 255 */ for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { *(p++) = x; *(p++) = y; *(p++) = 255; *(p++) = 255; } tex = cogl_texture_2d_new_from_data (test_ctx, 256, 256, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4, data, NULL); free (data); return tex; } static void paint (TestState *state) { CoglTexture2D *full_texture; CoglSubTexture *sub_texture, *sub_sub_texture; CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); /* Create a sub texture of the bottom right quarter of the texture */ sub_texture = cogl_sub_texture_new (test_ctx, state->tex, DIVISION_WIDTH, DIVISION_HEIGHT, DIVISION_WIDTH, DIVISION_HEIGHT); /* Paint it */ cogl_pipeline_set_layer_texture (pipeline, 0, sub_texture); cogl_object_unref (sub_texture); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0.0f, 0.0f, DIVISION_WIDTH, DIVISION_HEIGHT); /* Repeat a sub texture of the top half of the full texture. This is documented to be undefined so it doesn't technically have to work but it will with the current implementation */ sub_texture = cogl_sub_texture_new (test_ctx, state->tex, 0, 0, SOURCE_SIZE, DIVISION_HEIGHT); cogl_pipeline_set_layer_texture (pipeline, 0, sub_texture); cogl_object_unref (sub_texture); cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 0.0f, SOURCE_SIZE, SOURCE_SIZE * 2.0f, SOURCE_SIZE * 1.5f, 0.0f, 0.0f, 2.0f, 1.0f); /* Create a sub texture of a sub texture */ full_texture = create_test_texture (state); sub_texture = cogl_sub_texture_new (test_ctx, full_texture, 20, 10, 30, 20); cogl_object_unref (full_texture); sub_sub_texture = cogl_sub_texture_new (test_ctx, sub_texture, 20, 10, 10, 10); cogl_object_unref (sub_texture); cogl_pipeline_set_layer_texture (pipeline, 0, sub_sub_texture); cogl_object_unref (sub_sub_texture); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0.0f, SOURCE_SIZE * 2.0f, 10.0f, SOURCE_SIZE * 2.0f + 10.0f); cogl_object_unref (pipeline); } static void validate_part (int xpos, int ypos, int width, int height, uint32_t color) { test_utils_check_region (test_fb, xpos + TEST_INSET, ypos + TEST_INSET, width - TEST_INSET - 2, height - TEST_INSET - 2, color); } static uint8_t * create_update_data (void) { uint8_t *data = malloc (256 * 256 * 4), *p = data; int x, y; /* Create some image data that is 256x256 where the blue component ranges from 0->255 along the x axis and the alpha component ranges from 0->255 along the y axis. The red and green components are all zero */ for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { *(p++) = 0; *(p++) = 0; *(p++) = x; *(p++) = y; } return data; } static void validate_result (TestState *state) { int i, division_num, x, y; CoglTexture2D *test_tex; CoglSubTexture *sub_texture; uint8_t *texture_data, *p; int tex_width, tex_height; /* Sub texture of the bottom right corner of the texture */ validate_part (0, 0, DIVISION_WIDTH, DIVISION_HEIGHT, corner_colors[ (SOURCE_DIVISIONS_Y - 1) * SOURCE_DIVISIONS_X + SOURCE_DIVISIONS_X - 1]); /* Sub texture of the top half repeated horizontally */ for (i = 0; i < 2; i++) for (division_num = 0; division_num < SOURCE_DIVISIONS_X; division_num++) validate_part (i * SOURCE_SIZE + division_num * DIVISION_WIDTH, SOURCE_SIZE, DIVISION_WIDTH, DIVISION_HEIGHT, corner_colors[division_num]); /* Sub sub texture */ p = texture_data = malloc (10 * 10 * 4); cogl_flush (); cogl_framebuffer_read_pixels (test_fb, 0, SOURCE_SIZE * 2, 10, 10, COGL_PIXEL_FORMAT_RGBA_8888, p); for (y = 0; y < 10; y++) for (x = 0; x < 10; x++) { g_assert (*(p++) == x + 40); g_assert (*(p++) == y + 20); p += 2; } free (texture_data); /* Try reading back the texture data */ sub_texture = cogl_sub_texture_new (test_ctx, state->tex, SOURCE_SIZE / 4, SOURCE_SIZE / 4, SOURCE_SIZE / 2, SOURCE_SIZE / 2); tex_width = cogl_texture_get_width (sub_texture); tex_height = cogl_texture_get_height (sub_texture); p = texture_data = malloc (tex_width * tex_height * 4); cogl_texture_get_data (sub_texture, COGL_PIXEL_FORMAT_RGBA_8888, tex_width * 4, texture_data); for (y = 0; y < tex_height; y++) for (x = 0; x < tex_width; x++) { int div_x = ((x * SOURCE_SIZE / 2 / tex_width + SOURCE_SIZE / 4) / DIVISION_WIDTH); int div_y = ((y * SOURCE_SIZE / 2 / tex_height + SOURCE_SIZE / 4) / DIVISION_HEIGHT); uint32_t reference = corner_colors[div_x + div_y * SOURCE_DIVISIONS_X] >> 8; uint32_t color = GUINT32_FROM_BE (*((uint32_t *)p)) >> 8; g_assert (color == reference); p += 4; } free (texture_data); cogl_object_unref (sub_texture); /* Create a 256x256 test texture */ test_tex = create_test_texture (state); /* Create a sub texture the views the center half of the texture */ sub_texture = cogl_sub_texture_new (test_ctx, test_tex, 64, 64, 128, 128); /* Update the center half of the sub texture */ texture_data = create_update_data (); cogl_texture_set_region (sub_texture, 0, 0, 32, 32, 64, 64, 256, 256, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4, texture_data); free (texture_data); cogl_object_unref (sub_texture); /* Get the texture data */ p = texture_data = malloc (256 * 256 * 4); cogl_texture_get_data (test_tex, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4, texture_data); /* Verify the texture data */ for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { /* If we're in the center quarter */ if (x >= 96 && x < 160 && y >= 96 && y < 160) { g_assert ((*p++) == 0); g_assert ((*p++) == 0); g_assert ((*p++) == x - 96); g_assert ((*p++) == y - 96); } else { g_assert ((*p++) == x); g_assert ((*p++) == y); g_assert ((*p++) == 255); g_assert ((*p++) == 255); } } free (texture_data); cogl_object_unref (test_tex); } void test_sub_texture (void) { TestState state; state.tex = create_source (&state); cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); paint (&state); validate_result (&state); cogl_object_unref (state.tex); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-readpixels.c0000664000175000017500000001303314211404421022146 0ustar jpeisachjpeisach #include #include #include "test-conform-common.h" #define RED 0 #define GREEN 1 #define BLUE 2 #define FRAMEBUFFER_WIDTH 640 #define FRAMEBUFFER_HEIGHT 480 static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; static void on_paint (ClutterActor *actor, void *state) { float saved_viewport[4]; CoglMatrix saved_projection; CoglMatrix projection; CoglMatrix modelview; guchar *data; CoglHandle tex; CoglHandle offscreen; uint32_t *pixels; uint8_t *pixelsc; /* Save the Clutter viewport/matrices and load identity matrices */ cogl_get_viewport (saved_viewport); cogl_get_projection_matrix (&saved_projection); cogl_push_matrix (); cogl_matrix_init_identity (&projection); cogl_matrix_init_identity (&modelview); cogl_set_projection_matrix (&projection); cogl_set_modelview_matrix (&modelview); /* All offscreen rendering is done upside down so the first thing we * verify is reading back grid of colors from a CoglOffscreen framebuffer */ data = malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT); tex = test_utils_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, TEST_UTILS_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */ COGL_PIXEL_FORMAT_ANY, /* internal fmt */ FRAMEBUFFER_WIDTH * 4, /* rowstride */ data); free (data); offscreen = cogl_offscreen_new_with_texture (tex); cogl_push_framebuffer (offscreen); /* red, top left */ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_rectangle (-1, 1, 0, 0); /* green, top right */ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (0, 1, 1, 0); /* blue, bottom left */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-1, 0, 0, -1); /* white, bottom right */ cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff); cogl_rectangle (0, 0, 1, -1); pixels = calloc (1, FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT); cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, (guchar *)pixels); g_assert_cmpint (pixels[0], ==, 0xff0000ff); g_assert_cmpint (pixels[FRAMEBUFFER_WIDTH - 1], ==, 0xff00ff00); g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH], ==, 0xffff0000); g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH + FRAMEBUFFER_WIDTH - 1], ==, 0xffffffff); free (pixels); cogl_pop_framebuffer (); cogl_handle_unref (offscreen); /* Now verify reading back from an onscreen framebuffer... */ cogl_set_source_texture (tex); cogl_rectangle (-1, 1, 1, -1); pixels = calloc (1, FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT); cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, (guchar *)pixels); g_assert_cmpint (pixels[0], ==, 0xff0000ff); g_assert_cmpint (pixels[FRAMEBUFFER_WIDTH - 1], ==, 0xff00ff00); g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH], ==, 0xffff0000); g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH + FRAMEBUFFER_WIDTH - 1], ==, 0xffffffff); free (pixels); /* Verify using BGR format */ cogl_set_source_texture (tex); cogl_rectangle (-1, 1, 1, -1); pixelsc = calloc (1, FRAMEBUFFER_WIDTH * 3 * FRAMEBUFFER_HEIGHT); cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_BGR_888, (guchar *)pixelsc); g_assert_cmpint (pixelsc[0], ==, 0x00); g_assert_cmpint (pixelsc[1], ==, 0x00); g_assert_cmpint (pixelsc[2], ==, 0xff); g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 0], ==, 0x00); g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 1], ==, 0xff); g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 2], ==, 0x00); free (pixelsc); cogl_handle_unref (tex); /* Restore the viewport and matrices state */ cogl_set_viewport (saved_viewport[0], saved_viewport[1], saved_viewport[2], saved_viewport[3]); cogl_set_projection_matrix (&saved_projection); cogl_pop_matrix (); /* Comment this out if you want visual feedback of what this test * paints. */ clutter_main_quit (); } static CoglBool queue_redraw (void *stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_readpixels (TestUtilsGTestFixture *fixture, void *data) { unsigned int idle_source; ClutterActor *stage; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); /* We force continuous redrawing of the stage, since we need to skip * the first few frames, and we wont be doing anything else that * will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), NULL); clutter_actor_show (stage); clutter_main (); g_source_remove (idle_source); /* Remove all of the actors from the stage */ clutter_container_foreach (CLUTTER_CONTAINER (stage), (ClutterCallback) clutter_actor_destroy, NULL); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-primitive-and-journal.c0000664000175000017500000000753714211404421024242 0ustar jpeisachjpeisach#include #include "test-utils.h" typedef CoglVertexP2C4 Vertex; static void setup_orthographic_modelview (void) { CoglMatrix matrix; int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); /* Set up a non-identity modelview matrix. When the journal is * flushed it will usually flush the identity matrix. Using the * non-default matrix ensures that we test that Cogl restores the * matrix we asked for. The matrix sets up an orthographic transform * in the modelview matrix */ cogl_matrix_init_identity (&matrix); cogl_matrix_orthographic (&matrix, 0.0f, 0.0f, /* x_1 y_1 */ fb_width, fb_height, -1.0f, /* nearval */ 1.0f /* farval */); cogl_framebuffer_set_modelview_matrix (test_fb, &matrix); } static void create_primitives (CoglPrimitive *primitives[2]) { static const Vertex vertex_data[8] = { /* triangle strip 1 */ { 0, 0, 255, 0, 0, 255 }, { 0, 100, 255, 0, 0, 255 }, { 100, 0, 255, 0, 0, 255 }, { 100, 100, 255, 0, 0, 255 }, /* triangle strip 2 */ { 200, 0, 0, 0, 255, 255 }, { 200, 100, 0, 0, 255, 255 }, { 300, 0, 0, 0, 255, 255 }, { 300, 100, 0, 0, 255, 255 }, }; primitives[0] = cogl_primitive_new_p2c4 (test_ctx, COGL_VERTICES_MODE_TRIANGLE_STRIP, G_N_ELEMENTS (vertex_data), vertex_data); cogl_primitive_set_n_vertices (primitives[0], 4); primitives[1] = cogl_primitive_copy (primitives[0]); cogl_primitive_set_first_vertex (primitives[1], 4); cogl_primitive_set_n_vertices (primitives[1], 4); } static CoglPipeline * create_pipeline (void) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 0, 255, 0, 255); return pipeline; } void test_primitive_and_journal (void) { CoglPrimitive *primitives[2]; CoglPipeline *pipeline; setup_orthographic_modelview (); create_primitives (primitives); pipeline = create_pipeline (); /* Set a clip to clip all three rectangles to just the bottom half. * The journal flushes its own clip state so this verifies that the * clip state is correctly restored for the second primitive. */ cogl_framebuffer_push_rectangle_clip (test_fb, 0, 50, 300, 100); cogl_primitive_draw (primitives[0], test_fb, pipeline); /* Draw a rectangle using the journal in-between the two primitives. * This should test that the journal gets flushed correctly and that * the modelview matrix is restored. Half of the rectangle should be * overriden by the second primitive */ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 100, 0, /* x1/y1 */ 300, 100 /* x2/y2 */); cogl_primitive_draw (primitives[1], test_fb, pipeline); /* Check the three rectangles */ test_utils_check_region (test_fb, 1, 51, 98, 48, 0xff0000ff); test_utils_check_region (test_fb, 101, 51, 98, 48, 0x00ff00ff); test_utils_check_region (test_fb, 201, 51, 98, 48, 0x0000ffff); /* Check that the top half of all of the rectangles was clipped */ test_utils_check_region (test_fb, 1, 1, 298, 48, 0x000000ff); cogl_framebuffer_pop_clip (test_fb); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-alpha-textures.c0000664000175000017500000001013114211404421022750 0ustar jpeisachjpeisach#include #include #include "test-utils.h" static void create_pipeline (CoglTexture **tex_out, CoglPipeline **pipeline_out) { CoglTexture2D *tex; CoglPipeline *pipeline; static const uint8_t tex_data[] = { 0x00, 0x44, 0x88, 0xcc }; tex = cogl_texture_2d_new_from_data (test_ctx, 2, 2, /* width/height */ COGL_PIXEL_FORMAT_A_8, /* format */ 2, /* rowstride */ tex_data, NULL); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_filters (pipeline, 0, /* layer */ COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_layer_wrap_mode (pipeline, 0, /* layer */ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); /* This is the layer combine used by cogl-pango */ cogl_pipeline_set_layer_combine (pipeline, 0, /* layer */ "RGBA = MODULATE (PREVIOUS, TEXTURE[A])", NULL); cogl_pipeline_set_layer_texture (pipeline, 0, /* layer */ tex); *pipeline_out = pipeline; *tex_out = tex; } void test_alpha_textures (void) { CoglTexture *tex1, *tex2; CoglPipeline *pipeline1, *pipeline2; int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); uint8_t replacement_data[1] = { 0xff }; create_pipeline (&tex1, &pipeline1); cogl_framebuffer_draw_rectangle (test_fb, pipeline1, -1.0f, 1.0f, /* x1/y1 */ 1.0f, 0.0f /* x2/y2 */); create_pipeline (&tex2, &pipeline2); cogl_texture_set_region (tex2, 0, 0, /* src_x/y */ 1, 1, /* dst_x/y */ 1, 1, /* dst_width / dst_height */ 1, 1, /* width / height */ COGL_PIXEL_FORMAT_A_8, 1, /* rowstride */ replacement_data); cogl_framebuffer_draw_rectangle (test_fb, pipeline2, -1.0f, 0.0f, /* x1/y1 */ 1.0f, -1.0f /* x2/y2 */); cogl_object_unref (tex1); cogl_object_unref (tex2); cogl_object_unref (pipeline1); cogl_object_unref (pipeline2); /* Unmodified texture */ test_utils_check_pixel (test_fb, fb_width / 4, fb_height / 8, 0x000000ff); test_utils_check_pixel (test_fb, fb_width * 3 / 4, fb_height / 8, 0x444444ff); test_utils_check_pixel (test_fb, fb_width / 4, fb_height * 3 / 8, 0x888888ff); test_utils_check_pixel (test_fb, fb_width * 3 / 4, fb_height * 3 / 8, 0xccccccff); /* Modified texture */ test_utils_check_pixel (test_fb, fb_width / 4, fb_height * 5 / 8, 0x000000ff); test_utils_check_pixel (test_fb, fb_width * 3 / 4, fb_height * 5 / 8, 0x444444ff); test_utils_check_pixel (test_fb, fb_width / 4, fb_height * 7 / 8, 0x888888ff); test_utils_check_pixel (test_fb, fb_width * 3 / 4, fb_height * 7 / 8, 0xffffffff); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-no-gl-header.c0000664000175000017500000000044214211404421022250 0ustar jpeisachjpeisach#undef COGL_COMPILATION #include /* If you just include cogl/cogl.h, you shouldn't end up including any GL headers */ #ifdef GL_TRUE #error "Including cogl.h shouldn't be including any GL headers" #endif void test_no_gl_header (void); void test_no_gl_header (void) { } muffin-5.2.1/cogl/tests/conform/test-texture-3d.c0000664000175000017500000002065114211404421022016 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define TEX_WIDTH 4 #define TEX_HEIGHT 8 #define TEX_DEPTH 16 /* Leave four bytes of padding between each row */ #define TEX_ROWSTRIDE (TEX_WIDTH * 4 + 4) /* Leave four rows of padding between each image */ #define TEX_IMAGE_STRIDE ((TEX_HEIGHT + 4) * TEX_ROWSTRIDE) typedef struct _TestState { int fb_width; int fb_height; } TestState; static CoglTexture3D * create_texture_3d (CoglContext *context) { int x, y, z; uint8_t *data = malloc (TEX_IMAGE_STRIDE * TEX_DEPTH); uint8_t *p = data; CoglTexture3D *tex; CoglError *error = NULL; for (z = 0; z < TEX_DEPTH; z++) { for (y = 0; y < TEX_HEIGHT; y++) { for (x = 0; x < TEX_WIDTH; x++) { /* Set red, green, blue to values based on x, y, z */ *(p++) = 255 - x * 8; *(p++) = y * 8; *(p++) = 255 - z * 8; /* Fully opaque */ *(p++) = 0xff; } /* Set the padding between rows to 0xde */ memset (p, 0xde, TEX_ROWSTRIDE - (TEX_WIDTH * 4)); p += TEX_ROWSTRIDE - (TEX_WIDTH * 4); } /* Set the padding between images to 0xad */ memset (p, 0xba, TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE)); p += TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE); } tex = cogl_texture_3d_new_from_data (context, TEX_WIDTH, TEX_HEIGHT, TEX_DEPTH, COGL_PIXEL_FORMAT_RGBA_8888, TEX_ROWSTRIDE, TEX_IMAGE_STRIDE, data, &error); if (tex == NULL) { g_assert (error != NULL); g_warning ("Failed to create 3D texture: %s", error->message); g_assert_not_reached (); } free (data); return tex; } static void draw_frame (TestState *state) { CoglTexture *tex = create_texture_3d (test_ctx); CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); typedef struct { float x, y, s, t, r; } Vert; CoglPrimitive *primitive; CoglAttributeBuffer *attribute_buffer; CoglAttribute *attributes[2]; Vert *verts, *v; int i; cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_object_unref (tex); cogl_pipeline_set_layer_filters (pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); /* Render the texture repeated horizontally twice using a regular cogl rectangle. This should end up with the r texture coordinates as zero */ cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, 0.0f, 0.0f, TEX_WIDTH * 2, TEX_HEIGHT, 0.0f, 0.0f, 2.0f, 1.0f); /* Render all of the images in the texture using coordinates from a CoglPrimitive */ v = verts = g_new (Vert, 4 * TEX_DEPTH); for (i = 0; i < TEX_DEPTH; i++) { float r = (i + 0.5f) / TEX_DEPTH; v->x = i * TEX_WIDTH; v->y = TEX_HEIGHT; v->s = 0; v->t = 0; v->r = r; v++; v->x = i * TEX_WIDTH; v->y = TEX_HEIGHT * 2; v->s = 0; v->t = 1; v->r = r; v++; v->x = i * TEX_WIDTH + TEX_WIDTH; v->y = TEX_HEIGHT * 2; v->s = 1; v->t = 1; v->r = r; v++; v->x = i * TEX_WIDTH + TEX_WIDTH; v->y = TEX_HEIGHT; v->s = 1; v->t = 0; v->r = r; v++; } attribute_buffer = cogl_attribute_buffer_new (test_ctx, 4 * TEX_DEPTH * sizeof (Vert), verts); attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (Vert), G_STRUCT_OFFSET (Vert, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (attribute_buffer, "cogl_tex_coord_in", sizeof (Vert), G_STRUCT_OFFSET (Vert, s), 3, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, 6 * TEX_DEPTH, attributes, 2 /* n_attributes */); cogl_primitive_set_indices (primitive, cogl_get_rectangle_indices (test_ctx, TEX_DEPTH), 6 * TEX_DEPTH); cogl_primitive_draw (primitive, test_fb, pipeline); free (verts); cogl_object_unref (primitive); cogl_object_unref (attributes[0]); cogl_object_unref (attributes[1]); cogl_object_unref (attribute_buffer); cogl_object_unref (pipeline); } static void validate_block (int block_x, int block_y, int z) { int x, y; for (y = 0; y < TEX_HEIGHT; y++) for (x = 0; x < TEX_WIDTH; x++) test_utils_check_pixel_rgb (test_fb, block_x * TEX_WIDTH + x, block_y * TEX_HEIGHT + y, 255 - x * 8, y * 8, 255 - z * 8); } static void validate_result (void) { int i; validate_block (0, 0, 0); for (i = 0; i < TEX_DEPTH; i++) validate_block (i, 1, i); } static void test_multi_texture (TestState *state) { CoglPipeline *pipeline; CoglTexture3D *tex_3d; CoglTexture2D *tex_2d; uint8_t tex_data[4]; cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); /* Tests a pipeline that is using multi-texturing to combine a 3D texture with a 2D texture. The texture from another layer is sampled with TEXTURE_? just to pick up a specific bug that was happening with the ARBfp fragend */ pipeline = cogl_pipeline_new (test_ctx); tex_data[0] = 0xff; tex_data[1] = 0x00; tex_data[2] = 0x00; tex_data[3] = 0xff; tex_2d = cogl_texture_2d_new_from_data (test_ctx, 1, 1, /* width/height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ tex_data, NULL); cogl_pipeline_set_layer_texture (pipeline, 0, tex_2d); tex_data[0] = 0x00; tex_data[1] = 0xff; tex_data[2] = 0x00; tex_data[3] = 0xff; tex_3d = cogl_texture_3d_new_from_data (test_ctx, 1, 1, 1, /* width/height/depth */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ 4, /* image_stride */ tex_data, NULL); cogl_pipeline_set_layer_texture (pipeline, 1, tex_3d); cogl_pipeline_set_layer_combine (pipeline, 0, "RGBA = REPLACE(PREVIOUS)", NULL); cogl_pipeline_set_layer_combine (pipeline, 1, "RGBA = ADD(TEXTURE_0, TEXTURE_1)", NULL); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10); test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff); cogl_object_unref (tex_2d); cogl_object_unref (tex_3d); cogl_object_unref (pipeline); } void test_texture_3d (void) { TestState state; state.fb_width = cogl_framebuffer_get_width (test_fb); state.fb_height = cogl_framebuffer_get_height (test_fb); cogl_framebuffer_orthographic (test_fb, 0, 0, /* x_1, y_1 */ state.fb_width, /* x_2 */ state.fb_height /* y_2 */, -1, 100 /* near/far */); draw_frame (&state); validate_result (); test_multi_texture (&state); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-wrap-modes.c0000664000175000017500000002102214211404421022061 0ustar jpeisachjpeisach#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0 #include #include #include "test-utils.h" #define TEX_SIZE 4 typedef struct _TestState { int width; int height; CoglTexture *texture; } TestState; static CoglTexture * create_texture (TestUtilsTextureFlags flags) { uint8_t *data = malloc (TEX_SIZE * TEX_SIZE * 4), *p = data; CoglTexture *tex; int x, y; for (y = 0; y < TEX_SIZE; y++) for (x = 0; x < TEX_SIZE; x++) { *(p++) = 0; *(p++) = (x & 1) * 255; *(p++) = (y & 1) * 255; *(p++) = 255; } tex = test_utils_texture_new_from_data (test_ctx, TEX_SIZE, TEX_SIZE, flags, COGL_PIXEL_FORMAT_RGBA_8888_PRE, TEX_SIZE * 4, data); free (data); return tex; } static CoglPipeline * create_pipeline (TestState *state, CoglPipelineWrapMode wrap_mode_s, CoglPipelineWrapMode wrap_mode_t) { CoglPipeline *pipeline; pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, state->texture); cogl_pipeline_set_layer_filters (pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0, wrap_mode_s); cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0, wrap_mode_t); return pipeline; } static CoglPipelineWrapMode wrap_modes[] = { COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_AUTOMATIC, COGL_PIPELINE_WRAP_MODE_AUTOMATIC, COGL_PIPELINE_WRAP_MODE_AUTOMATIC, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE }; static void draw_tests (TestState *state) { int i; for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2) { CoglPipelineWrapMode wrap_mode_s, wrap_mode_t; CoglPipeline *pipeline; /* Create a separate pipeline for each pair of wrap modes so that we can verify whether the batch splitting works */ wrap_mode_s = wrap_modes[i]; wrap_mode_t = wrap_modes[i + 1]; pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t); /* Render the pipeline at four times the size of the texture */ cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, i * TEX_SIZE, 0, (i + 2) * TEX_SIZE, TEX_SIZE * 2, 0, 0, 2, 2); cogl_object_unref (pipeline); } } static const CoglTextureVertex vertices[4] = { { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, TEX_SIZE * 2, 0.0f, 0.0f, 2.0f }, { TEX_SIZE * 2, TEX_SIZE * 2, 0.0f, 2.0f, 2.0f }, { TEX_SIZE * 2, 0.0f, 0.0f, 2.0f, 0.0f } }; static void draw_tests_polygon (TestState *state) { int i; for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2) { CoglPipelineWrapMode wrap_mode_s, wrap_mode_t; CoglPipeline *pipeline; wrap_mode_s = wrap_modes[i]; wrap_mode_t = wrap_modes[i + 1]; pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t); cogl_set_source (pipeline); cogl_object_unref (pipeline); cogl_push_matrix (); cogl_translate (TEX_SIZE * i, 0.0f, 0.0f); /* Render the pipeline at four times the size of the texture */ cogl_polygon (vertices, G_N_ELEMENTS (vertices), FALSE); cogl_pop_matrix (); } } static void draw_tests_vbo (TestState *state) { CoglHandle vbo; int i; vbo = cogl_vertex_buffer_new (4); cogl_vertex_buffer_add (vbo, "gl_Vertex", 3, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (vertices[0]), &vertices[0].x); cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0", 2, COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, sizeof (vertices[0]), &vertices[0].tx); cogl_vertex_buffer_submit (vbo); for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2) { CoglPipelineWrapMode wrap_mode_s, wrap_mode_t; CoglPipeline *pipeline; wrap_mode_s = wrap_modes[i]; wrap_mode_t = wrap_modes[i + 1]; pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t); cogl_set_source (pipeline); cogl_object_unref (pipeline); cogl_push_matrix (); cogl_translate (TEX_SIZE * i, 0.0f, 0.0f); /* Render the pipeline at four times the size of the texture */ cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, 4); cogl_pop_matrix (); } cogl_handle_unref (vbo); } static void validate_set (TestState *state, int offset) { uint8_t data[TEX_SIZE * 2 * TEX_SIZE * 2 * 4], *p; int x, y, i; for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2) { CoglPipelineWrapMode wrap_mode_s, wrap_mode_t; wrap_mode_s = wrap_modes[i]; wrap_mode_t = wrap_modes[i + 1]; cogl_framebuffer_read_pixels (test_fb, i * TEX_SIZE, offset * TEX_SIZE * 2, TEX_SIZE * 2, TEX_SIZE * 2, COGL_PIXEL_FORMAT_RGBA_8888, data); p = data; for (y = 0; y < TEX_SIZE * 2; y++) for (x = 0; x < TEX_SIZE * 2; x++) { uint8_t green, blue; if (x < TEX_SIZE || wrap_mode_s == COGL_PIPELINE_WRAP_MODE_REPEAT || wrap_mode_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) green = (x & 1) * 255; else green = ((TEX_SIZE - 1) & 1) * 255; if (y < TEX_SIZE || wrap_mode_t == COGL_PIPELINE_WRAP_MODE_REPEAT || wrap_mode_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) blue = (y & 1) * 255; else blue = ((TEX_SIZE - 1) & 1) * 255; g_assert_cmpint (p[0], ==, 0); g_assert_cmpint (p[1], ==, green); g_assert_cmpint (p[2], ==, blue); p += 4; } } } static void validate_result (TestState *state) { validate_set (state, 0); /* non-atlased rectangle */ #if 0 /* this doesn't currently work */ validate_set (state, 1); /* atlased rectangle */ #endif validate_set (state, 2); /* cogl_polygon */ validate_set (state, 3); /* vertex buffer */ } static void paint (TestState *state) { /* Draw the tests first with a non atlased texture */ state->texture = create_texture (TEST_UTILS_TEXTURE_NO_ATLAS); draw_tests (state); cogl_object_unref (state->texture); /* Draw the tests again with a possible atlased texture. This should end up testing software repeats */ state->texture = create_texture (TEST_UTILS_TEXTURE_NONE); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, 0.0f, TEX_SIZE * 2.0f, 0.0f); draw_tests (state); cogl_pop_matrix (); cogl_object_unref (state->texture); /* Draw the tests using cogl_polygon */ state->texture = create_texture (COGL_TEXTURE_NO_ATLAS); cogl_push_matrix (); cogl_translate (0.0f, TEX_SIZE * 4.0f, 0.0f); draw_tests_polygon (state); cogl_pop_matrix (); cogl_object_unref (state->texture); /* Draw the tests using a vertex buffer */ state->texture = create_texture (COGL_TEXTURE_NO_ATLAS); cogl_push_matrix (); cogl_translate (0.0f, TEX_SIZE * 6.0f, 0.0f); draw_tests_vbo (state); cogl_pop_matrix (); cogl_object_unref (state->texture); validate_result (state); } void test_wrap_modes (void) { TestState state; state.width = cogl_framebuffer_get_width (test_fb); state.height = cogl_framebuffer_get_height (test_fb); cogl_framebuffer_orthographic (test_fb, 0, 0, state.width, state.height, -1, 100); /* XXX: we have to push/pop a framebuffer since this test currently * uses the legacy cogl_vertex_buffer_draw() api. */ cogl_push_framebuffer (test_fb); paint (&state); cogl_pop_framebuffer (); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-pipeline-shader-state.c0000664000175000017500000000575314211404421024207 0ustar jpeisachjpeisach#include #include #include "test-utils.h" void test_pipeline_shader_state (void) { CoglOffscreen *offscreen; CoglFramebuffer *fb; CoglPipeline *base_pipeline; CoglPipeline *draw_pipeline; CoglTexture2D *tex; CoglSnippet *snippet; float width = cogl_framebuffer_get_width (test_fb); float height = cogl_framebuffer_get_height (test_fb); cogl_framebuffer_orthographic (test_fb, 0, 0, width, height, -1, 100); tex = cogl_texture_2d_new_with_size (test_ctx, 128, 128); offscreen = cogl_offscreen_new_with_texture (tex); fb = offscreen; cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); cogl_object_unref (offscreen); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 0, 1); /* Setup a template pipeline... */ base_pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (base_pipeline, 1, tex); cogl_pipeline_set_color4f (base_pipeline, 1, 0, 0, 1); /* Derive a pipeline from the template, making a change that affects * fragment processing but making sure not to affect vertex * processing... */ draw_pipeline = cogl_pipeline_copy (base_pipeline); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, /* declarations */ "cogl_color_out = vec4 (0.0, 1.0, 0.1, 1.1);"); cogl_pipeline_add_snippet (draw_pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, draw_pipeline, 0, 0, width, height); cogl_object_unref (draw_pipeline); cogl_framebuffer_finish (test_fb); /* At this point we should have provoked cogl to cache some vertex * shader state for the draw_pipeline with the base_pipeline because * none of the changes made to the draw_pipeline affected vertex * processing. (NB: cogl will cache shader state with the oldest * ancestor that the state is still valid for to maximize the chance * that it can be used with other derived pipelines) * * Now we make a change to the base_pipeline to make sure that this * cached vertex shader gets invalidated. */ cogl_pipeline_set_layer_texture (base_pipeline, 0, tex); /* Now we derive another pipeline from base_pipeline to verify that * it doesn't end up re-using the old cached state */ draw_pipeline = cogl_pipeline_copy (base_pipeline); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, /* declarations */ "cogl_color_out = vec4 (0.0, 0.0, 1.1, 1.1);"); cogl_pipeline_add_snippet (draw_pipeline, snippet); cogl_object_unref (snippet); cogl_framebuffer_draw_rectangle (test_fb, draw_pipeline, 0, 0, width, height); cogl_object_unref (draw_pipeline); test_utils_check_region (test_fb, 0, 0, width, height, 0x0000ffff); } muffin-5.2.1/cogl/tests/conform/test-path.c0000664000175000017500000001624614211404421020753 0ustar jpeisachjpeisach#include #include #include #include "test-utils.h" #define BLOCK_SIZE 16 /* Number of pixels at the border of a block quadrant to skip when verifying */ #define TEST_INSET 1 typedef struct _TestState { int dummy; } TestState; static void draw_path_at (CoglPath *path, CoglPipeline *pipeline, int x, int y) { cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, x * BLOCK_SIZE, y * BLOCK_SIZE, 0.0f); cogl_set_framebuffer (test_fb); cogl_set_source (pipeline); cogl_path_fill (path); cogl_framebuffer_pop_matrix (test_fb); } static void check_block (int block_x, int block_y, int block_mask) { uint32_t data[BLOCK_SIZE * BLOCK_SIZE]; int qx, qy; /* Block mask represents which quarters of the block should be filled. The bits from 0->3 represent the top left, top right, bottom left and bottom right respectively */ cogl_framebuffer_read_pixels (test_fb, block_x * BLOCK_SIZE, block_y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, COGL_PIXEL_FORMAT_RGBA_8888_PRE, (uint8_t *)data); for (qy = 0; qy < 2; qy++) for (qx = 0; qx < 2; qx++) { int bit = qx | (qy << 1); const char *intended_pixel = ((block_mask & (1 << bit)) ? "#ffffff" : "#000000"); int x, y; for (x = 0; x < BLOCK_SIZE / 2 - TEST_INSET * 2; x++) for (y = 0; y < BLOCK_SIZE / 2 - TEST_INSET * 2; y++) { const uint32_t *p = data + (qx * BLOCK_SIZE / 2 + qy * BLOCK_SIZE * BLOCK_SIZE / 2 + (x + TEST_INSET) + (y + TEST_INSET) * BLOCK_SIZE); char *screen_pixel = g_strdup_printf ("#%06x", GUINT32_FROM_BE (*p) >> 8); g_assert_cmpstr (screen_pixel, ==, intended_pixel); free (screen_pixel); } } } static void paint (TestState *state) { CoglPath *path_a, *path_b, *path_c; CoglPipeline *white = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4f (white, 1, 1, 1, 1); /* Create a path filling just a quarter of a block. It will use two rectangles so that we have a sub path in the path */ path_a = cogl_path_new (); cogl_path_rectangle (path_a, BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2, BLOCK_SIZE, BLOCK_SIZE); cogl_path_rectangle (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2, BLOCK_SIZE * 3 / 4, BLOCK_SIZE); draw_path_at (path_a, white, 0, 0); /* Create another path filling the whole block */ path_b = cogl_path_new (); cogl_path_rectangle (path_b, 0, 0, BLOCK_SIZE, BLOCK_SIZE); draw_path_at (path_b, white, 1, 0); /* Draw the first path again */ draw_path_at (path_a, white, 2, 0); /* Draw a copy of path a */ path_c = cogl_path_copy (path_a); draw_path_at (path_c, white, 3, 0); /* Add another rectangle to path a. We'll use line_to's instead of cogl_rectangle so that we don't create another sub-path because that is more likely to break the copy */ cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2); cogl_path_line_to (path_a, 0, 0); cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0); cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2); draw_path_at (path_a, white, 4, 0); /* Draw the copy again. It should not have changed */ draw_path_at (path_c, white, 5, 0); /* Add another rectangle to path c. It will be added in two halves, one as an extension of the previous path and the other as a new sub path */ cogl_path_line_to (path_c, BLOCK_SIZE / 2, 0); cogl_path_line_to (path_c, BLOCK_SIZE * 3 / 4, 0); cogl_path_line_to (path_c, BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2); cogl_path_line_to (path_c, BLOCK_SIZE / 2, BLOCK_SIZE / 2); cogl_path_rectangle (path_c, BLOCK_SIZE * 3 / 4, 0, BLOCK_SIZE, BLOCK_SIZE / 2); draw_path_at (path_c, white, 6, 0); /* Draw the original path again. It should not have changed */ draw_path_at (path_a, white, 7, 0); cogl_object_unref (path_a); cogl_object_unref (path_b); cogl_object_unref (path_c); /* Draw a self-intersecting path. The part that intersects should be inverted */ path_a = cogl_path_new (); cogl_path_rectangle (path_a, 0, 0, BLOCK_SIZE, BLOCK_SIZE); cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2); cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2); cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0); cogl_path_close (path_a); draw_path_at (path_a, white, 8, 0); cogl_object_unref (path_a); /* Draw two sub paths. Where the paths intersect it should be inverted */ path_a = cogl_path_new (); cogl_path_rectangle (path_a, 0, 0, BLOCK_SIZE, BLOCK_SIZE); cogl_path_rectangle (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2, BLOCK_SIZE, BLOCK_SIZE); draw_path_at (path_a, white, 9, 0); cogl_object_unref (path_a); /* Draw a clockwise outer path */ path_a = cogl_path_new (); cogl_path_move_to (path_a, 0, 0); cogl_path_line_to (path_a, BLOCK_SIZE, 0); cogl_path_line_to (path_a, BLOCK_SIZE, BLOCK_SIZE); cogl_path_line_to (path_a, 0, BLOCK_SIZE); cogl_path_close (path_a); /* Add a clockwise sub path in the upper left quadrant */ cogl_path_move_to (path_a, 0, 0); cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0); cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2); cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2); cogl_path_close (path_a); /* Add a counter-clockwise sub path in the upper right quadrant */ cogl_path_move_to (path_a, BLOCK_SIZE / 2, 0); cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2); cogl_path_line_to (path_a, BLOCK_SIZE, BLOCK_SIZE / 2); cogl_path_line_to (path_a, BLOCK_SIZE, 0); cogl_path_close (path_a); /* Retain the path for the next test */ draw_path_at (path_a, white, 10, 0); /* Draw the same path again with the other fill rule */ cogl_path_set_fill_rule (path_a, COGL_PATH_FILL_RULE_NON_ZERO); draw_path_at (path_a, white, 11, 0); cogl_object_unref (path_a); } static void validate_result () { check_block (0, 0, 0x8 /* bottom right */); check_block (1, 0, 0xf /* all of them */); check_block (2, 0, 0x8 /* bottom right */); check_block (3, 0, 0x8 /* bottom right */); check_block (4, 0, 0x9 /* top left and bottom right */); check_block (5, 0, 0x8 /* bottom right */); check_block (6, 0, 0xa /* bottom right and top right */); check_block (7, 0, 0x9 /* top_left and bottom right */); check_block (8, 0, 0xe /* all but top left */); check_block (9, 0, 0x7 /* all but bottom right */); check_block (10, 0, 0xc /* bottom two */); check_block (11, 0, 0xd /* all but top right */); } void test_path (void) { TestState state; cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); paint (&state); validate_result (); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-object.c0000664000175000017500000000402314211404421021253 0ustar jpeisachjpeisach #include #include #include #include "test-conform-common.h" CoglUserDataKey private_key0; CoglUserDataKey private_key1; CoglUserDataKey private_key2; static int user_data0; static int user_data1; static int user_data2; static int destroy0_count = 0; static int destroy1_count = 0; static int destroy2_count = 0; static void destroy0_cb (void *user_data) { g_assert (user_data == &user_data0); destroy0_count++; } static void destroy1_cb (void *user_data) { g_assert (user_data == &user_data1); destroy1_count++; } static void destroy2_cb (void *user_data) { g_assert (user_data == &user_data2); destroy2_count++; } void test_object (TestUtilsGTestFixture *fixture, void *data) { CoglPath *path; /* Assuming that COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES == 2 * test associating 2 pointers to private data with an object */ cogl_path_new (); path = cogl_get_path (); cogl_object_set_user_data (COGL_OBJECT (path), &private_key0, &user_data0, destroy0_cb); cogl_object_set_user_data (COGL_OBJECT (path), &private_key1, &user_data1, destroy1_cb); cogl_object_set_user_data (COGL_OBJECT (path), &private_key2, &user_data2, destroy2_cb); cogl_object_set_user_data (COGL_OBJECT (path), &private_key1, NULL, destroy1_cb); cogl_object_set_user_data (COGL_OBJECT (path), &private_key1, &user_data1, destroy1_cb); cogl_object_unref (path); g_assert_cmpint (destroy0_count, ==, 1); g_assert_cmpint (destroy1_count, ==, 2); g_assert_cmpint (destroy2_count, ==, 1); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-wrap-rectangle-textures.c0000664000175000017500000001305414211404421024605 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define DRAW_SIZE 64 static CoglPipeline * create_base_pipeline (void) { CoglBitmap *bmp; CoglTextureRectangle *tex; CoglPipeline *pipeline; uint8_t tex_data[] = { 0x44, 0x44, 0x44, 0x88, 0x88, 0x88, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0xff }; bmp = cogl_bitmap_new_for_data (test_ctx, 2, 2, /* width/height */ COGL_PIXEL_FORMAT_RGB_888, 2 * 3, /* rowstride */ tex_data); tex = cogl_texture_rectangle_new_from_bitmap (bmp); cogl_object_unref (bmp); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_filters (pipeline, 0, /* layer */ COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_layer_texture (pipeline, 0, /* layer */ tex); cogl_object_unref (tex); return pipeline; } static void check_colors (int x_offset, int y_offset, const uint8_t expected_colors[9]) { int x, y; for (y = 0; y < 4; y++) for (x = 0; x < 4; x++) { uint32_t color = expected_colors[x + y * 4]; test_utils_check_region (test_fb, x * DRAW_SIZE / 4 + 1 + x_offset, y * DRAW_SIZE / 4 + 1 + y_offset, DRAW_SIZE / 4 - 2, DRAW_SIZE / 4 - 2, 0xff | (color << 8) | (color << 16) | (color << 24)); } } static void test_pipeline (CoglPipeline *pipeline, int x_offset, int y_offset, const uint8_t expected_colors[9]) { float x1 = x_offset; float y1 = y_offset; float x2 = x1 + DRAW_SIZE; float y2 = y1 + DRAW_SIZE; int y, x; cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, x1, y1, x2, y2, -0.5f, /* s1 */ -0.5f, /* t1 */ 1.5f, /* s2 */ 1.5f /* t2 */); check_colors (x_offset, y_offset, expected_colors); /* Also try drawing each quadrant of the rectangle with a small * rectangle */ for (y = -1; y < 3; y++) for (x = -1; x < 3; x++) { x1 = x_offset + (x + 1) * DRAW_SIZE / 4 + DRAW_SIZE; y1 = y_offset + (y + 1) * DRAW_SIZE / 4; x2 = x1 + DRAW_SIZE / 4; y2 = y1 + DRAW_SIZE / 4; cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, x1, y1, x2, y2, x / 2.0f, /* s1 */ y / 2.0f, /* t1 */ (x + 1) / 2.0f, /* s2 */ (y + 1) / 2.0f /* t2 */); } check_colors (x_offset + DRAW_SIZE, y_offset, expected_colors); } void test_wrap_rectangle_textures (void) { float fb_width = cogl_framebuffer_get_width (test_fb); float fb_height = cogl_framebuffer_get_height (test_fb); CoglPipeline *base_pipeline; CoglPipeline *clamp_pipeline; CoglPipeline *repeat_pipeline; /* The textures are drawn with the texture coordinates from * -0.5→1.5. That means we get one complete copy of the texture and * an extra half of the texture surrounding it. The drawing is * tested against a 4x4 grid of colors. The center 2x2 colours * specify the normal texture colors and the other colours specify * what the wrap mode should generate */ static const uint8_t clamp_colors[] = { 0x44, 0x44, 0x88, 0x88, 0x44, 0x44, 0x88, 0x88, 0xcc, 0xcc, 0xff, 0xff, 0xcc, 0xcc, 0xff, 0xff }; static const uint8_t repeat_colors[] = { 0xff, 0xcc, 0xff, 0xcc, 0x88, 0x44, 0x88, 0x44, 0xff, 0xcc, 0xff, 0xcc, 0x88, 0x44, 0x88, 0x44 }; cogl_framebuffer_orthographic (test_fb, 0, 0, /* x_1, y_1 */ fb_width, /* x_2 */ fb_height /* y_2 */, -1, 100 /* near/far */); base_pipeline = create_base_pipeline (); clamp_pipeline = cogl_pipeline_copy (base_pipeline); cogl_pipeline_set_layer_wrap_mode (clamp_pipeline, 0, /* layer */ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); repeat_pipeline = cogl_pipeline_copy (base_pipeline); cogl_pipeline_set_layer_wrap_mode (repeat_pipeline, 0, /* layer */ COGL_PIPELINE_WRAP_MODE_REPEAT); test_pipeline (clamp_pipeline, 0, 0, /* x/y offset */ clamp_colors); test_pipeline (repeat_pipeline, 0, DRAW_SIZE * 2, /* x/y offset */ repeat_colors); cogl_object_unref (repeat_pipeline); cogl_object_unref (clamp_pipeline); cogl_object_unref (base_pipeline); } muffin-5.2.1/cogl/tests/conform/test-backface-culling.c0000664000175000017500000002243714211404421023170 0ustar jpeisachjpeisach#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0 #include #include #include "test-utils.h" /* Size the texture so that it is just off a power of two to encourage it so use software tiling when NPOTs aren't available */ #define TEXTURE_SIZE 257 /* Amount of pixels to skip off the top, bottom, left and right of the texture when reading back the stage */ #define TEST_INSET 2 /* Size to actually render the texture at */ #define TEXTURE_RENDER_SIZE 8 typedef struct _TestState { CoglTexture *texture; CoglFramebuffer *offscreen; CoglTexture *offscreen_tex; int width, height; } TestState; static void validate_part (CoglFramebuffer *framebuffer, int xnum, int ynum, CoglBool shown) { test_utils_check_region (framebuffer, xnum * TEXTURE_RENDER_SIZE + TEST_INSET, ynum * TEXTURE_RENDER_SIZE + TEST_INSET, TEXTURE_RENDER_SIZE - TEST_INSET * 2, TEXTURE_RENDER_SIZE - TEST_INSET * 2, shown ? 0xff0000ff : 0x000000ff); } /* We draw everything 16 times. The draw number is used as a bitmask to test all of the combinations of enabling legacy state, both winding orders and all four culling modes */ #define USE_LEGACY_STATE(draw_num) (((draw_num) & 0x01) >> 0) #define FRONT_WINDING(draw_num) (((draw_num) & 0x02) >> 1) #define CULL_FACE_MODE(draw_num) (((draw_num) & 0x0c) >> 2) static void paint_test_backface_culling (TestState *state, CoglFramebuffer *framebuffer) { int draw_num; CoglPipeline *base_pipeline = cogl_pipeline_new (test_ctx); cogl_framebuffer_orthographic (framebuffer, 0, 0, state->width, state->height, -1, 100); cogl_framebuffer_clear4f (framebuffer, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_STENCIL, 0, 0, 0, 1); cogl_pipeline_set_layer_texture (base_pipeline, 0, state->texture); cogl_pipeline_set_layer_filters (base_pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_push_framebuffer (framebuffer); /* Render the scene sixteen times to test all of the combinations of cull face mode, legacy state and winding orders */ for (draw_num = 0; draw_num < 16; draw_num++) { float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE); CoglTextureVertex verts[4]; CoglPipeline *pipeline; cogl_push_matrix (); cogl_translate (0, TEXTURE_RENDER_SIZE * draw_num, 0); pipeline = cogl_pipeline_copy (base_pipeline); cogl_set_backface_culling_enabled (USE_LEGACY_STATE (draw_num)); cogl_pipeline_set_front_face_winding (pipeline, FRONT_WINDING (draw_num)); cogl_pipeline_set_cull_face_mode (pipeline, CULL_FACE_MODE (draw_num)); cogl_push_source (pipeline); memset (verts, 0, sizeof (verts)); x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a front-facing texture */ cogl_rectangle (x1, y1, x2, y2); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a front-facing texture with flipped texcoords */ cogl_rectangle_with_texture_coords (x1, y1, x2, y2, 1.0, 0.0, 0.0, 1.0); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a back-facing texture */ cogl_rectangle (x2, y1, x1, y2); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* If the texture is sliced then cogl_polygon doesn't work so we'll just use a solid color instead */ if (cogl_texture_is_sliced (state->texture)) cogl_set_source_color4ub (255, 0, 0, 255); /* Draw a front-facing polygon */ verts[0].x = x1; verts[0].y = y2; verts[1].x = x2; verts[1].y = y2; verts[2].x = x2; verts[2].y = y1; verts[3].x = x1; verts[3].y = y1; verts[0].tx = 0; verts[0].ty = 0; verts[1].tx = 1.0; verts[1].ty = 0; verts[2].tx = 1.0; verts[2].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0; cogl_polygon (verts, 4, FALSE); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); /* Draw a back-facing polygon */ verts[0].x = x1; verts[0].y = y1; verts[1].x = x2; verts[1].y = y1; verts[2].x = x2; verts[2].y = y2; verts[3].x = x1; verts[3].y = y2; verts[0].tx = 0; verts[0].ty = 0; verts[1].tx = 1.0; verts[1].ty = 0; verts[2].tx = 1.0; verts[2].ty = 1.0; verts[3].tx = 0; verts[3].ty = 1.0; cogl_polygon (verts, 4, FALSE); x1 = x2; x2 = x1 + (float)(TEXTURE_RENDER_SIZE); cogl_pop_matrix (); cogl_pop_source (); cogl_object_unref (pipeline); } cogl_pop_framebuffer (); cogl_object_unref (base_pipeline); } static void validate_result (CoglFramebuffer *framebuffer, int y_offset) { int draw_num; for (draw_num = 0; draw_num < 16; draw_num++) { CoglBool cull_front, cull_back; CoglPipelineCullFaceMode cull_mode; if (USE_LEGACY_STATE (draw_num)) cull_mode = COGL_PIPELINE_CULL_FACE_MODE_BACK; else cull_mode = CULL_FACE_MODE (draw_num); switch (cull_mode) { case COGL_PIPELINE_CULL_FACE_MODE_NONE: cull_front = FALSE; cull_back = FALSE; break; case COGL_PIPELINE_CULL_FACE_MODE_FRONT: cull_front = TRUE; cull_back = FALSE; break; case COGL_PIPELINE_CULL_FACE_MODE_BACK: cull_front = FALSE; cull_back = TRUE; break; case COGL_PIPELINE_CULL_FACE_MODE_BOTH: cull_front = TRUE; cull_back = TRUE; break; } if (FRONT_WINDING (draw_num) == COGL_WINDING_CLOCKWISE) { CoglBool tmp = cull_front; cull_front = cull_back; cull_back = tmp; } /* Front-facing texture */ validate_part (framebuffer, 0, y_offset + draw_num, !cull_front); /* Front-facing texture with flipped tex coords */ validate_part (framebuffer, 1, y_offset + draw_num, !cull_front); /* Back-facing texture */ validate_part (framebuffer, 2, y_offset + draw_num, !cull_back); /* Front-facing texture polygon */ validate_part (framebuffer, 3, y_offset + draw_num, !cull_front); /* Back-facing texture polygon */ validate_part (framebuffer, 4, y_offset + draw_num, !cull_back); } } static void paint (TestState *state) { CoglPipeline *pipeline; paint_test_backface_culling (state, test_fb); /* * Now repeat the test but rendered to an offscreen * framebuffer. Note that by default the conformance tests are * always run to an offscreen buffer but we might as well have this * check anyway in case it is being run with COGL_TEST_ONSCREEN=1 */ paint_test_backface_culling (state, state->offscreen); /* Copy the result of the offscreen rendering for validation and * also so we can have visual feedback. */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, state->offscreen_tex); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, TEXTURE_RENDER_SIZE * 16, state->width, state->height + TEXTURE_RENDER_SIZE * 16); cogl_object_unref (pipeline); validate_result (test_fb, 0); validate_result (test_fb, 16); } static CoglTexture * make_texture (void) { guchar *tex_data, *p; CoglTexture *tex; tex_data = malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4); for (p = tex_data + TEXTURE_SIZE * TEXTURE_SIZE * 4; p > tex_data;) { *(--p) = 255; *(--p) = 0; *(--p) = 0; *(--p) = 255; } tex = test_utils_texture_new_from_data (test_ctx, TEXTURE_SIZE, TEXTURE_SIZE, TEST_UTILS_TEXTURE_NO_ATLAS, COGL_PIXEL_FORMAT_RGBA_8888, TEXTURE_SIZE * 4, tex_data); free (tex_data); return tex; } void test_backface_culling (void) { TestState state; CoglTexture *tex; state.width = cogl_framebuffer_get_width (test_fb); state.height = cogl_framebuffer_get_height (test_fb); state.offscreen = NULL; state.texture = make_texture (); tex = test_utils_texture_new_with_size (test_ctx, state.width, state.height, TEST_UTILS_TEXTURE_NO_SLICING, COGL_TEXTURE_COMPONENTS_RGBA); state.offscreen = cogl_offscreen_new_with_texture (tex); state.offscreen_tex = tex; paint (&state); cogl_object_unref (state.offscreen); cogl_object_unref (state.offscreen_tex); cogl_object_unref (state.texture); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-texture-rg.c0000664000175000017500000000416614211404421022123 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define TEX_WIDTH 8 #define TEX_HEIGHT 8 static CoglTexture2D * make_texture (void) { uint8_t tex_data[TEX_WIDTH * TEX_HEIGHT * 2], *p = tex_data; int x, y; for (y = 0; y < TEX_HEIGHT; y++) for (x = 0; x < TEX_WIDTH; x++) { *(p++) = x * 256 / TEX_WIDTH; *(p++) = y * 256 / TEX_HEIGHT; } return cogl_texture_2d_new_from_data (test_ctx, TEX_WIDTH, TEX_HEIGHT, COGL_PIXEL_FORMAT_RG_88, TEX_WIDTH * 2, tex_data, NULL); } void test_texture_rg (void) { CoglPipeline *pipeline; CoglTexture2D *tex; int fb_width, fb_height; int x, y; fb_width = cogl_framebuffer_get_width (test_fb); fb_height = cogl_framebuffer_get_height (test_fb); tex = make_texture (); g_assert (cogl_texture_get_components (tex) == COGL_TEXTURE_COMPONENTS_RG); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_pipeline_set_layer_filters (pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1.0f, 1.0f, 1.0f, -1.0f); for (y = 0; y < TEX_HEIGHT; y++) for (x = 0; x < TEX_WIDTH; x++) { test_utils_check_pixel_rgb (test_fb, x * fb_width / TEX_WIDTH + fb_width / (TEX_WIDTH * 2), y * fb_height / TEX_HEIGHT + fb_height / (TEX_HEIGHT * 2), x * 256 / TEX_WIDTH, y * 256 / TEX_HEIGHT, 0); } cogl_object_unref (pipeline); cogl_object_unref (tex); } muffin-5.2.1/cogl/tests/conform/test-fixed.c0000664000175000017500000000075114211404421021110 0ustar jpeisachjpeisach#include #include #include "test-conform-common.h" void test_fixed (TestUtilsGTestFixture *fixture, void *data) { g_assert_cmpint (COGL_FIXED_1, ==, COGL_FIXED_FROM_FLOAT (1.0)); g_assert_cmpint (COGL_FIXED_1, ==, COGL_FIXED_FROM_INT (1)); g_assert_cmpint (COGL_FIXED_0_5, ==, COGL_FIXED_FROM_FLOAT (0.5)); g_assert_cmpfloat (COGL_FIXED_TO_FLOAT (COGL_FIXED_1), ==, 1.0); g_assert_cmpfloat (COGL_FIXED_TO_FLOAT (COGL_FIXED_0_5), ==, 0.5); } muffin-5.2.1/cogl/tests/conform/test-materials.c0000664000175000017500000001714714211404421022001 0ustar jpeisachjpeisach#include "cogl-config.h" #include #include #include #include "test-conform-common.h" static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; #define QUAD_WIDTH 20 #define RED 0 #define GREEN 1 #define BLUE 2 #define ALPHA 3 #define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24) #define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16) #define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8) #define MASK_ALPHA(COLOR) (COLOR & 0xff) typedef struct _TestState { ClutterGeometry stage_geom; } TestState; static void check_quad (int quad_x, int quad_y, uint32_t color) { test_utils_check_pixel (x * QUAD_WIDTH + (QUAD_WIDTH / 2), y * QUAD_WIDTH + (QUAD_WIDTH / 2), color); } static void test_material_with_primitives (TestState *state, int x, int y, uint32_t color) { CoglTextureVertex verts[4] = { { .x = 0, .y = 0, .z = 0 }, { .x = 0, .y = QUAD_WIDTH, .z = 0 }, { .x = QUAD_WIDTH, .y = QUAD_WIDTH, .z = 0 }, { .x = QUAD_WIDTH, .y = 0, .z = 0 }, }; CoglHandle vbo; cogl_push_matrix (); cogl_translate (x * QUAD_WIDTH, y * QUAD_WIDTH, 0); cogl_rectangle (0, 0, QUAD_WIDTH, QUAD_WIDTH); cogl_translate (0, QUAD_WIDTH, 0); cogl_polygon (verts, 4, FALSE); cogl_translate (0, QUAD_WIDTH, 0); vbo = cogl_vertex_buffer_new (4); cogl_vertex_buffer_add (vbo, "gl_Vertex", 2, /* n components */ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, /* normalized */ sizeof (CoglTextureVertex), /* stride */ verts); cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, /* first */ 4); /* count */ cogl_handle_unref (vbo); cogl_pop_matrix (); check_quad (x, y, color); check_quad (x, y+1, color); check_quad (x, y+2, color); } static void test_invalid_texture_layers (TestState *state, int x, int y) { CoglHandle material = cogl_material_new (); /* explicitly create a layer with an invalid handle. This may be desireable * if the user also sets a texture combine string that e.g. refers to a * constant color. */ cogl_material_set_layer (material, 0, NULL); cogl_set_source (material); cogl_handle_unref (material); /* We expect a white fallback material to be used */ test_material_with_primitives (state, x, y, 0xffffffff); } static void test_using_all_layers (TestState *state, int x, int y) { CoglHandle material = cogl_material_new (); uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff }; uint8_t red_pixel[] = { 0xff, 0x00, 0x00, 0xff }; CoglHandle white_texture; CoglHandle red_texture; GLint n_layers; int i; /* Create a material that uses the maximum number of layers. All but the last layer will use a solid white texture. The last layer will use a red texture. The layers will all be modulated together so the final fragment should be red. */ white_texture = test_utils_texture_new_from_data (1, 1, TEST_UTILS_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_ANY, 4, white_pixel); red_texture = test_utils_texture_new_from_data (1, 1, TEST_UTILS_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_ANY, 4, red_pixel); /* FIXME: Cogl doesn't provide a way to query the maximum number of texture layers so for now we'll just ask GL directly. */ #ifdef HAVE_COGL_GLES2 { GLint n_image_units, n_attribs; /* GLES 2 doesn't have GL_MAX_TEXTURE_UNITS and it uses GL_MAX_TEXTURE_IMAGE_UNITS instead */ glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &n_image_units); /* Cogl needs a vertex attrib for each layer to upload the texture coordinates */ glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, &n_attribs); /* We can't use two of the attribs because they are used by the position and color */ n_attribs -= 2; n_layers = MIN (n_attribs, n_image_units); } #else glGetIntegerv (GL_MAX_TEXTURE_UNITS, &n_layers); #endif /* FIXME: is this still true? */ /* Cogl currently can't cope with more than 32 layers so we'll also limit the maximum to that. */ if (n_layers > 32) n_layers = 32; for (i = 0; i < n_layers; i++) { cogl_material_set_layer_filters (material, i, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_material_set_layer (material, i, i == n_layers - 1 ? red_texture : white_texture); } cogl_set_source (material); cogl_handle_unref (material); cogl_handle_unref (white_texture); cogl_handle_unref (red_texture); /* We expect the final fragment to be red */ test_material_with_primitives (state, x, y, 0xff0000ff); } static void test_invalid_texture_layers_with_constant_colors (TestState *state, int x, int y) { CoglHandle material = cogl_material_new (); CoglColor constant_color; /* explicitly create a layer with an invalid handle */ cogl_material_set_layer (material, 0, NULL); /* ignore the fallback texture on the layer and use a constant color instead */ cogl_color_init_from_4ub (&constant_color, 0, 0, 255, 255); cogl_material_set_layer_combine (material, 0, "RGBA=REPLACE(CONSTANT)", NULL); cogl_material_set_layer_combine_constant (material, 0, &constant_color); cogl_set_source (material); cogl_handle_unref (material); /* We expect the final fragments to be green */ test_material_with_primitives (state, x, y, 0x0000ffff); } static void on_paint (ClutterActor *actor, TestState *state) { test_invalid_texture_layers (state, 0, 0 /* position */ ); test_invalid_texture_layers_with_constant_colors (state, 1, 0 /* position */ ); test_using_all_layers (state, 2, 0 /* position */ ); /* Comment this out if you want visual feedback for what this test paints */ #if 1 clutter_main_quit (); #endif } static CoglBool queue_redraw (void *stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_materials (TestUtilsGTestFixture *fixture, void *data) { TestState state; ClutterActor *stage; ClutterActor *group; unsigned int idle_source; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); clutter_actor_get_geometry (stage, &state.stage_geom); group = clutter_group_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); /* We force continuous redrawing of the stage, since we need to skip * the first few frames, and we wont be doing anything else that * will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); clutter_actor_show_all (stage); clutter_main (); g_source_remove (idle_source); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-premult.c0000664000175000017500000002432314211404421021502 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define QUAD_WIDTH 32 #define RED 0 #define GREEN 1 #define BLUE 2 #define ALPHA 3 #define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24) #define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16) #define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8) #define MASK_ALPHA(COLOR) (COLOR & 0xff) typedef enum _MakeTextureFlags { TEXTURE_FLAG_SET_PREMULTIPLIED = 1, TEXTURE_FLAG_SET_UNPREMULTIPLIED = 1<<1, } MakeTextureFlags; static guchar * gen_tex_data (uint32_t color) { guchar *tex_data, *p; uint8_t r = MASK_RED (color); uint8_t g = MASK_GREEN (color); uint8_t b = MASK_BLUE (color); uint8_t a = MASK_ALPHA (color); tex_data = malloc (QUAD_WIDTH * QUAD_WIDTH * 4); for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;) { *(--p) = a; *(--p) = b; *(--p) = g; *(--p) = r; } return tex_data; } static CoglTexture * make_texture (uint32_t color, CoglPixelFormat src_format, MakeTextureFlags flags) { CoglTexture2D *tex_2d; guchar *tex_data = gen_tex_data (color); CoglBitmap *bmp = cogl_bitmap_new_for_data (test_ctx, QUAD_WIDTH, QUAD_WIDTH, src_format, QUAD_WIDTH * 4, tex_data); tex_2d = cogl_texture_2d_new_from_bitmap (bmp); if (flags & TEXTURE_FLAG_SET_PREMULTIPLIED) cogl_texture_set_premultiplied (tex_2d, TRUE); else if (flags & TEXTURE_FLAG_SET_UNPREMULTIPLIED) cogl_texture_set_premultiplied (tex_2d, FALSE); cogl_object_unref (bmp); free (tex_data); return tex_2d; } static void set_region (CoglTexture *tex, uint32_t color, CoglPixelFormat format) { guchar *tex_data = gen_tex_data (color); cogl_texture_set_region (tex, 0, 0, /* src x, y */ 0, 0, /* dst x, y */ QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */ QUAD_WIDTH, QUAD_WIDTH, /* src width, height */ format, 0, /* auto compute row stride */ tex_data); } static void check_texture (CoglPipeline *pipeline, CoglHandle material, int x, int y, CoglTexture *tex, uint32_t expected_result) { /* Legacy */ cogl_push_framebuffer (test_fb); cogl_material_set_layer (material, 0, tex); cogl_set_source (material); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); test_utils_check_pixel (test_fb, x * QUAD_WIDTH + QUAD_WIDTH / 2, y * QUAD_WIDTH + QUAD_WIDTH / 2, expected_result); cogl_pop_framebuffer (); /* New API */ cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_framebuffer_draw_rectangle (test_fb, pipeline, x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); test_utils_check_pixel (test_fb, x * QUAD_WIDTH + QUAD_WIDTH / 2, y * QUAD_WIDTH + QUAD_WIDTH / 2, expected_result); } void test_premult (void) { CoglPipeline *pipeline; CoglHandle material; CoglTexture *tex; cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1.0f, 1.0f, 1.0f, 1.0f); /* Legacy */ material = cogl_material_new (); cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_material_set_layer_combine (material, 0, "RGBA = REPLACE (TEXTURE)", NULL); /* New API */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_pipeline_set_layer_combine (pipeline, 0, "RGBA = REPLACE (TEXTURE)", NULL); /* If the user explicitly specifies an unmultiplied internal format then * Cogl shouldn't automatically premultiply the given texture data... */ if (cogl_test_verbose ()) g_print ("make_texture (0xff00ff80, " "src = RGBA_8888, internal = RGBA_8888)\n"); tex = make_texture (0xff00ff80, COGL_PIXEL_FORMAT_RGBA_8888, /* src format */ TEXTURE_FLAG_SET_UNPREMULTIPLIED); check_texture (pipeline, material, 0, 0, /* position */ tex, 0xff00ff80); /* expected */ /* If the user explicitly requests a premultiplied internal format and * gives unmultiplied src data then Cogl should always premultiply that * for us */ if (cogl_test_verbose ()) g_print ("make_texture (0xff00ff80, " "src = RGBA_8888, internal = RGBA_8888_PRE)\n"); tex = make_texture (0xff00ff80, COGL_PIXEL_FORMAT_RGBA_8888, /* src format */ TEXTURE_FLAG_SET_PREMULTIPLIED); check_texture (pipeline, material, 1, 0, /* position */ tex, 0x80008080); /* expected */ /* If the user doesn't explicitly declare that the texture is premultiplied * then Cogl should assume it is by default should premultiply * unpremultiplied texture data... */ if (cogl_test_verbose ()) g_print ("make_texture (0xff00ff80, " "src = RGBA_8888, internal = ANY)\n"); tex = make_texture (0xff00ff80, COGL_PIXEL_FORMAT_RGBA_8888, /* src format */ 0); /* default premultiplied status */ check_texture (pipeline, material, 2, 0, /* position */ tex, 0x80008080); /* expected */ /* If the user requests a premultiplied internal texture format and supplies * premultiplied source data, Cogl should never modify that source data... */ if (cogl_test_verbose ()) g_print ("make_texture (0x80008080, " "src = RGBA_8888_PRE, " "internal = RGBA_8888_PRE)\n"); tex = make_texture (0x80008080, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */ TEXTURE_FLAG_SET_PREMULTIPLIED); check_texture (pipeline, material, 3, 0, /* position */ tex, 0x80008080); /* expected */ /* If the user requests an unmultiplied internal texture format, but * supplies premultiplied source data, then Cogl should always * un-premultiply the source data... */ if (cogl_test_verbose ()) g_print ("make_texture (0x80008080, " "src = RGBA_8888_PRE, internal = RGBA_8888)\n"); tex = make_texture (0x80008080, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */ TEXTURE_FLAG_SET_UNPREMULTIPLIED); check_texture (pipeline, material, 4, 0, /* position */ tex, 0xff00ff80); /* expected */ /* If the user allows any internal texture format and provides premultipled * source data then by default Cogl shouldn't modify the source data... * (In the future there will be additional Cogl API to control this * behaviour) */ if (cogl_test_verbose ()) g_print ("make_texture (0x80008080, " "src = RGBA_8888_PRE, internal = ANY)\n"); tex = make_texture (0x80008080, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */ 0); /* default premultiplied status */ check_texture (pipeline, material, 5, 0, /* position */ tex, 0x80008080); /* expected */ /* * Test cogl_texture_set_region() .... */ if (cogl_test_verbose ()) g_print ("make_texture (0xDEADBEEF, " "src = RGBA_8888, internal = RGBA_8888)\n"); tex = make_texture (0xDEADBEEF, COGL_PIXEL_FORMAT_RGBA_8888, /* src format */ TEXTURE_FLAG_SET_UNPREMULTIPLIED); if (cogl_test_verbose ()) g_print ("set_region (0xff00ff80, RGBA_8888)\n"); set_region (tex, 0xff00ff80, COGL_PIXEL_FORMAT_RGBA_8888); check_texture (pipeline, material, 6, 0, /* position */ tex, 0xff00ff80); /* expected */ /* Updating a texture region for an unmultiplied texture using premultiplied * region data should result in Cogl unmultiplying the given region data... */ if (cogl_test_verbose ()) g_print ("make_texture (0xDEADBEEF, " "src = RGBA_8888, internal = RGBA_8888)\n"); tex = make_texture (0xDEADBEEF, COGL_PIXEL_FORMAT_RGBA_8888, /* src format */ TEXTURE_FLAG_SET_UNPREMULTIPLIED); if (cogl_test_verbose ()) g_print ("set_region (0x80008080, RGBA_8888_PRE)\n"); set_region (tex, 0x80008080, COGL_PIXEL_FORMAT_RGBA_8888_PRE); check_texture (pipeline, material, 7, 0, /* position */ tex, 0xff00ff80); /* expected */ if (cogl_test_verbose ()) g_print ("make_texture (0xDEADBEEF, " "src = RGBA_8888_PRE, " "internal = RGBA_8888_PRE)\n"); tex = make_texture (0xDEADBEEF, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */ TEXTURE_FLAG_SET_PREMULTIPLIED); if (cogl_test_verbose ()) g_print ("set_region (0x80008080, RGBA_8888_PRE)\n"); set_region (tex, 0x80008080, COGL_PIXEL_FORMAT_RGBA_8888_PRE); check_texture (pipeline, material, 8, 0, /* position */ tex, 0x80008080); /* expected */ /* Updating a texture region for a premultiplied texture using unmultiplied * region data should result in Cogl premultiplying the given region data... */ if (cogl_test_verbose ()) g_print ("make_texture (0xDEADBEEF, " "src = RGBA_8888_PRE, " "internal = RGBA_8888_PRE)\n"); tex = make_texture (0xDEADBEEF, COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */ TEXTURE_FLAG_SET_PREMULTIPLIED); if (cogl_test_verbose ()) g_print ("set_region (0xff00ff80, RGBA_8888)\n"); set_region (tex, 0xff00ff80, COGL_PIXEL_FORMAT_RGBA_8888); check_texture (pipeline, material, 9, 0, /* position */ tex, 0x80008080); /* expected */ if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-pixel-buffer.c0000664000175000017500000001673014211404421022405 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define BITMAP_SIZE 256 /* * Creates a 256 x 256 with image data split into four quadrants. The * colours of these in reading order will be: blue, green, cyan, * red */ static void generate_bitmap_data (uint8_t *data, int stride) { int y, x; for (y = 0; y < BITMAP_SIZE; y++) { for (x = 0; x < BITMAP_SIZE; x++) { int color_num = x / (BITMAP_SIZE / 2) + y / (BITMAP_SIZE / 2) * 2 + 1; *(data++) = (color_num & 4) ? 255 : 0; *(data++) = (color_num & 2) ? 255 : 0; *(data++) = (color_num & 1) ? 255 : 0; *(data++) = 255; } data += stride - BITMAP_SIZE * 4; } } static CoglBitmap * create_bitmap (void) { CoglBitmap *bitmap; CoglBuffer *buffer; bitmap = cogl_bitmap_new_with_size (test_ctx, BITMAP_SIZE, BITMAP_SIZE, COGL_PIXEL_FORMAT_RGBA_8888); buffer = cogl_bitmap_get_buffer (bitmap); g_assert (cogl_is_pixel_buffer (buffer)); g_assert (cogl_is_buffer (buffer)); cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC); g_assert_cmpint (cogl_buffer_get_update_hint (buffer), ==, COGL_BUFFER_UPDATE_HINT_DYNAMIC); return bitmap; } static CoglBitmap * create_and_fill_bitmap (void) { CoglBitmap *bitmap = create_bitmap (); CoglBuffer *buffer = cogl_bitmap_get_buffer (bitmap); uint8_t *map; unsigned int stride; stride = cogl_bitmap_get_rowstride (bitmap); map = cogl_buffer_map (buffer, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD); g_assert (map); generate_bitmap_data (map, stride); cogl_buffer_unmap (buffer); return bitmap; } static CoglTexture * create_texture_from_bitmap (CoglBitmap *bitmap) { CoglTexture2D *texture; texture = cogl_texture_2d_new_from_bitmap (bitmap); g_assert (texture != NULL); return texture; } static CoglPipeline * create_pipeline_from_texture (CoglTexture *texture) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, texture); cogl_pipeline_set_layer_filters (pipeline, 0, /* layer_num */ COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); return pipeline; } static void check_colours (uint32_t color0, uint32_t color1, uint32_t color2, uint32_t color3) { int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); test_utils_check_region (test_fb, 1, 1, /* x/y */ fb_width / 2 - 2, /* width */ fb_height / 2 - 2, /* height */ color0); test_utils_check_region (test_fb, fb_width / 2 + 1, /* x */ 1, /* y */ fb_width / 2 - 2, /* width */ fb_height / 2 - 2, /* height */ color1); test_utils_check_region (test_fb, 1, /* x */ fb_height / 2 + 1, /* y */ fb_width / 2 - 2, /* width */ fb_height / 2 - 2, /* height */ color2); test_utils_check_region (test_fb, fb_width / 2 + 1, /* x */ fb_height / 2 + 1, /* y */ fb_width / 2 - 2, /* width */ fb_height / 2 - 2, /* height */ color3); } void test_pixel_buffer_map (void) { CoglBitmap *bitmap = create_and_fill_bitmap (); CoglPipeline *pipeline; CoglTexture *texture; texture = create_texture_from_bitmap (bitmap); pipeline = create_pipeline_from_texture (texture); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1.0f, 1.0f, 1.0f, -1.0f); cogl_object_unref (bitmap); cogl_object_unref (texture); cogl_object_unref (pipeline); check_colours (0x0000ffff, 0x00ff00ff, 0x00ffffff, 0xff0000ff); if (cogl_test_verbose ()) g_print ("OK\n"); } void test_pixel_buffer_set_data (void) { CoglBitmap *bitmap = create_bitmap (); CoglBuffer *buffer = cogl_bitmap_get_buffer (bitmap); CoglPipeline *pipeline; CoglTexture *texture; uint8_t *data; unsigned int stride; stride = cogl_bitmap_get_rowstride (bitmap); data = malloc (stride * BITMAP_SIZE); generate_bitmap_data (data, stride); cogl_buffer_set_data (buffer, 0, /* offset */ data, stride * (BITMAP_SIZE - 1) + BITMAP_SIZE * 4); free (data); texture = create_texture_from_bitmap (bitmap); pipeline = create_pipeline_from_texture (texture); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1.0f, 1.0f, 1.0f, -1.0f); cogl_object_unref (bitmap); cogl_object_unref (texture); cogl_object_unref (pipeline); check_colours (0x0000ffff, 0x00ff00ff, 0x00ffffff, 0xff0000ff); if (cogl_test_verbose ()) g_print ("OK\n"); } static CoglTexture * create_white_texture (void) { CoglTexture2D *texture; uint8_t *data = malloc (BITMAP_SIZE * BITMAP_SIZE * 4); memset (data, 255, BITMAP_SIZE * BITMAP_SIZE * 4); texture = cogl_texture_2d_new_from_data (test_ctx, BITMAP_SIZE, BITMAP_SIZE, COGL_PIXEL_FORMAT_RGBA_8888, BITMAP_SIZE * 4, /* rowstride */ data, NULL); /* don't catch errors */ free (data); return texture; } void test_pixel_buffer_sub_region (void) { CoglBitmap *bitmap = create_and_fill_bitmap (); CoglPipeline *pipeline; CoglTexture *texture; texture = create_white_texture (); /* Replace the top-right quadrant of the texture with the red part * of the bitmap */ cogl_texture_set_region_from_bitmap (texture, BITMAP_SIZE / 2, /* src_x */ BITMAP_SIZE / 2, /* src_y */ BITMAP_SIZE / 2, /* dst_x */ 0, /* dst_y */ BITMAP_SIZE / 2, /* width */ BITMAP_SIZE / 2, /* height */ bitmap); pipeline = create_pipeline_from_texture (texture); cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1.0f, 1.0f, 1.0f, -1.0f); cogl_object_unref (bitmap); cogl_object_unref (texture); cogl_object_unref (pipeline); check_colours (0xffffffff, 0xff0000ff, 0xffffffff, 0xffffffff); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-euler-quaternion.c0000664000175000017500000000560414211404421023312 0ustar jpeisachjpeisach#include #include #include #include "test-utils.h" /* Macros are used here instead of functions so that the * g_assert_cmpfloat will give a more interesting message when it * fails */ #define COMPARE_FLOATS(a, b) \ do { \ if (fabsf ((a) - (b)) >= 0.0001f) \ g_assert_cmpfloat ((a), ==, (b)); \ } while (0) #define COMPARE_MATRICES(a, b) \ do { \ COMPARE_FLOATS ((a)->xx, (b)->xx); \ COMPARE_FLOATS ((a)->yx, (b)->yx); \ COMPARE_FLOATS ((a)->zx, (b)->zx); \ COMPARE_FLOATS ((a)->wx, (b)->wx); \ COMPARE_FLOATS ((a)->xy, (b)->xy); \ COMPARE_FLOATS ((a)->yy, (b)->yy); \ COMPARE_FLOATS ((a)->zy, (b)->zy); \ COMPARE_FLOATS ((a)->wy, (b)->wy); \ COMPARE_FLOATS ((a)->xz, (b)->xz); \ COMPARE_FLOATS ((a)->yz, (b)->yz); \ COMPARE_FLOATS ((a)->zz, (b)->zz); \ COMPARE_FLOATS ((a)->wz, (b)->wz); \ COMPARE_FLOATS ((a)->xw, (b)->xw); \ COMPARE_FLOATS ((a)->yw, (b)->yw); \ COMPARE_FLOATS ((a)->zw, (b)->zw); \ COMPARE_FLOATS ((a)->ww, (b)->ww); \ } while (0) void test_euler_quaternion (void) { CoglEuler euler; CoglQuaternion quaternion; CoglMatrix matrix_a, matrix_b; /* Try doing the rotation with three separate rotations */ cogl_matrix_init_identity (&matrix_a); cogl_matrix_rotate (&matrix_a, -30.0f, 0.0f, 1.0f, 0.0f); cogl_matrix_rotate (&matrix_a, 40.0f, 1.0f, 0.0f, 0.0f); cogl_matrix_rotate (&matrix_a, 50.0f, 0.0f, 0.0f, 1.0f); /* And try the same rotation with a euler */ cogl_euler_init (&euler, -30, 40, 50); cogl_matrix_init_from_euler (&matrix_b, &euler); /* Verify that the matrices are approximately the same */ COMPARE_MATRICES (&matrix_a, &matrix_b); /* Try converting the euler to a matrix via a quaternion */ cogl_quaternion_init_from_euler (&quaternion, &euler); memset (&matrix_b, 0, sizeof (matrix_b)); cogl_matrix_init_from_quaternion (&matrix_b, &quaternion); COMPARE_MATRICES (&matrix_a, &matrix_b); /* Try applying the rotation from a euler to a framebuffer */ cogl_framebuffer_identity_matrix (test_fb); cogl_framebuffer_rotate_euler (test_fb, &euler); memset (&matrix_b, 0, sizeof (matrix_b)); cogl_framebuffer_get_modelview_matrix (test_fb, &matrix_b); COMPARE_MATRICES (&matrix_a, &matrix_b); /* And again with a quaternion */ cogl_framebuffer_identity_matrix (test_fb); cogl_framebuffer_rotate_quaternion (test_fb, &quaternion); memset (&matrix_b, 0, sizeof (matrix_b)); cogl_framebuffer_get_modelview_matrix (test_fb, &matrix_b); COMPARE_MATRICES (&matrix_a, &matrix_b); /* FIXME: This needs a lot more tests! */ if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-depth-test.c0000664000175000017500000002213314211404421022070 0ustar jpeisachjpeisach#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0 #include #include #include "test-utils.h" #define QUAD_WIDTH 20 #define RED 0 #define GREEN 1 #define BLUE 2 #define ALPHA 3 #define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24) #define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16) #define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8) #define MASK_ALPHA(COLOR) (COLOR & 0xff) typedef struct _TestState { int padding; } TestState; typedef struct { uint32_t color; float depth; CoglBool test_enable; CoglDepthTestFunction test_function; CoglBool write_enable; CoglBool fb_write_enable; float range_near; float range_far; } TestDepthState; static CoglBool draw_rectangle (TestState *state, int x, int y, TestDepthState *rect_state, CoglBool legacy_mode) { uint8_t Cr = MASK_RED (rect_state->color); uint8_t Cg = MASK_GREEN (rect_state->color); uint8_t Cb = MASK_BLUE (rect_state->color); uint8_t Ca = MASK_ALPHA (rect_state->color); CoglPipeline *pipeline; CoglDepthState depth_state; cogl_depth_state_init (&depth_state); cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable); cogl_depth_state_set_test_function (&depth_state, rect_state->test_function); cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable); cogl_depth_state_set_range (&depth_state, rect_state->range_near, rect_state->range_far); pipeline = cogl_pipeline_new (test_ctx); if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL)) { cogl_object_unref (pipeline); return FALSE; } if (!legacy_mode) { cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca); cogl_framebuffer_set_depth_write_enabled (test_fb, rect_state->fb_write_enable); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, 0, 0, rect_state->depth); cogl_framebuffer_draw_rectangle (test_fb, pipeline, x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_framebuffer_pop_matrix (test_fb); } else { cogl_push_framebuffer (test_fb); cogl_push_matrix (); cogl_set_source_color4ub (Cr, Cg, Cb, Ca); cogl_translate (0, 0, rect_state->depth); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_pop_matrix (); cogl_pop_framebuffer (); } cogl_object_unref (pipeline); return TRUE; } static void test_depth (TestState *state, int x, int y, TestDepthState *rect0_state, TestDepthState *rect1_state, TestDepthState *rect2_state, CoglBool legacy_mode, uint32_t expected_result) { CoglBool missing_feature = FALSE; if (rect0_state) missing_feature |= !draw_rectangle (state, x, y, rect0_state, legacy_mode); if (rect1_state) missing_feature |= !draw_rectangle (state, x, y, rect1_state, legacy_mode); if (rect2_state) missing_feature |= !draw_rectangle (state, x, y, rect2_state, legacy_mode); /* We don't consider it an error that we can't test something * the driver doesn't support. */ if (missing_feature) return; test_utils_check_pixel (test_fb, x * QUAD_WIDTH + (QUAD_WIDTH / 2), y * QUAD_WIDTH + (QUAD_WIDTH / 2), expected_result); } static void paint (TestState *state) { /* Sanity check a few of the different depth test functions * and that depth writing can be disabled... */ { /* Closest */ TestDepthState rect0_state = { 0xff0000ff, /* rgba color */ -10, /* depth */ FALSE, /* depth test enable */ COGL_DEPTH_TEST_FUNCTION_ALWAYS, TRUE, /* depth write enable */ TRUE, /* FB depth write enable */ 0, 1 /* depth range */ }; /* Furthest */ TestDepthState rect1_state = { 0x00ff00ff, /* rgba color */ -70, /* depth */ TRUE, /* depth test enable */ COGL_DEPTH_TEST_FUNCTION_ALWAYS, TRUE, /* depth write enable */ TRUE, /* FB depth write enable */ 0, 1 /* depth range */ }; /* In the middle */ TestDepthState rect2_state = { 0x0000ffff, /* rgba color */ -20, /* depth */ TRUE, /* depth test enable */ COGL_DEPTH_TEST_FUNCTION_NEVER, TRUE, /* depth write enable */ TRUE, /* FB depth write enable */ 0, 1 /* depth range */ }; test_depth (state, 0, 0, /* position */ &rect0_state, &rect1_state, &rect2_state, FALSE, /* legacy mode */ 0x00ff00ff); /* expected */ rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_ALWAYS; test_depth (state, 1, 0, /* position */ &rect0_state, &rect1_state, &rect2_state, FALSE, /* legacy mode */ 0x0000ffff); /* expected */ rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_LESS; test_depth (state, 2, 0, /* position */ &rect0_state, &rect1_state, &rect2_state, FALSE, /* legacy mode */ 0x0000ffff); /* expected */ rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_GREATER; test_depth (state, 3, 0, /* position */ &rect0_state, &rect1_state, &rect2_state, FALSE, /* legacy mode */ 0x00ff00ff); /* expected */ rect0_state.test_enable = TRUE; rect1_state.write_enable = FALSE; test_depth (state, 4, 0, /* position */ &rect0_state, &rect1_state, &rect2_state, FALSE, /* legacy mode */ 0x0000ffff); /* expected */ rect1_state.write_enable = TRUE; rect1_state.fb_write_enable = FALSE; test_depth (state, 4, 0, /* position */ &rect0_state, &rect1_state, &rect2_state, FALSE, /* legacy mode */ 0x0000ffff); /* expected */ /* Re-enable FB depth writing to verify state flush */ rect1_state.write_enable = TRUE; rect1_state.fb_write_enable = TRUE; test_depth (state, 4, 0, /* position */ &rect0_state, &rect1_state, &rect2_state, FALSE, /* legacy mode */ 0x00ff00ff); /* expected */ } /* Check that the depth buffer values can be mapped into different * ranges... */ { /* Closest by depth, furthest by depth range */ TestDepthState rect0_state = { 0xff0000ff, /* rgba color */ -10, /* depth */ TRUE, /* depth test enable */ COGL_DEPTH_TEST_FUNCTION_ALWAYS, TRUE, /* depth write enable */ TRUE, /* FB depth write enable */ 0.5, 1 /* depth range */ }; /* Furthest by depth, nearest by depth range */ TestDepthState rect1_state = { 0x00ff00ff, /* rgba color */ -70, /* depth */ TRUE, /* depth test enable */ COGL_DEPTH_TEST_FUNCTION_GREATER, TRUE, /* depth write enable */ TRUE, /* FB depth write enable */ 0, 0.5 /* depth range */ }; test_depth (state, 0, 1, /* position */ &rect0_state, &rect1_state, NULL, FALSE, /* legacy mode */ 0xff0000ff); /* expected */ } /* Test that the legacy cogl_set_depth_test_enabled() API still * works... */ { /* Nearest */ TestDepthState rect0_state = { 0xff0000ff, /* rgba color */ -10, /* depth */ FALSE, /* depth test enable */ COGL_DEPTH_TEST_FUNCTION_LESS, TRUE, /* depth write enable */ TRUE, /* FB depth write enable */ 0, 1 /* depth range */ }; /* Furthest */ TestDepthState rect1_state = { 0x00ff00ff, /* rgba color */ -70, /* depth */ FALSE, /* depth test enable */ COGL_DEPTH_TEST_FUNCTION_LESS, TRUE, /* depth write enable */ TRUE, /* FB depth write enable */ 0, 1 /* depth range */ }; cogl_set_depth_test_enabled (TRUE); test_depth (state, 0, 2, /* position */ &rect0_state, &rect1_state, NULL, TRUE, /* legacy mode */ 0xff0000ff); /* expected */ cogl_set_depth_test_enabled (FALSE); test_depth (state, 1, 2, /* position */ &rect0_state, &rect1_state, NULL, TRUE, /* legacy mode */ 0x00ff00ff); /* expected */ } } void test_depth_test (void) { TestState state; cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); paint (&state); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-texture-mipmaps.c0000664000175000017500000000761114211404421023157 0ustar jpeisachjpeisach#include #include #include #include "test-conform-common.h" static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; #define TEX_SIZE 64 typedef struct _TestState { unsigned int padding; } TestState; /* Creates a texture where the pixels are evenly divided between selecting just one of the R,G and B components */ static CoglHandle make_texture (void) { guchar *tex_data = malloc (TEX_SIZE * TEX_SIZE * 3), *p = tex_data; CoglHandle tex; int x, y; for (y = 0; y < TEX_SIZE; y++) for (x = 0; x < TEX_SIZE; x++) { memset (p, 0, 3); /* Set one of the components to full. The components should be evenly represented so that each gets a third of the texture */ p[(p - tex_data) / (TEX_SIZE * TEX_SIZE * 3 / 3)] = 255; p += 3; } tex = test_utils_texture_new_from_data (TEX_SIZE, TEX_SIZE, TEST_UTILS_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGB_888, COGL_PIXEL_FORMAT_ANY, TEX_SIZE * 3, tex_data); free (tex_data); return tex; } static void on_paint (ClutterActor *actor, TestState *state) { CoglHandle tex; CoglHandle material; uint8_t pixels[8]; tex = make_texture (); material = cogl_material_new (); cogl_material_set_layer (material, 0, tex); cogl_handle_unref (tex); /* Render a 1x1 pixel quad without mipmaps */ cogl_set_source (material); cogl_material_set_layer_filters (material, 0, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_rectangle (0, 0, 1, 1); /* Then with mipmaps */ cogl_material_set_layer_filters (material, 0, COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_rectangle (1, 0, 2, 1); cogl_handle_unref (material); /* Read back the two pixels we rendered */ cogl_read_pixels (0, 0, 2, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixels); /* The first pixel should be just one of the colors from the texture. It doesn't matter which one */ g_assert ((pixels[0] == 255 && pixels[1] == 0 && pixels[2] == 0) || (pixels[0] == 0 && pixels[1] == 255 && pixels[2] == 0) || (pixels[0] == 0 && pixels[1] == 0 && pixels[2] == 255)); /* The second pixel should be more or less the average of all of the pixels in the texture. Each component gets a third of the image so each component should be approximately 255/3 */ g_assert (ABS (pixels[4] - 255 / 3) <= 3 && ABS (pixels[5] - 255 / 3) <= 3 && ABS (pixels[6] - 255 / 3) <= 3); /* Comment this out if you want visual feedback for what this test paints */ #if 1 clutter_main_quit (); #endif } static CoglBool queue_redraw (void *stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_texture_mipmaps (TestUtilsGTestFixture *fixture, void *data) { TestState state; ClutterActor *stage; ClutterActor *group; unsigned int idle_source; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); group = clutter_group_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); /* We force continuous redrawing of the stage, since we need to skip * the first few frames, and we wont be doing anything else that * will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); clutter_actor_show_all (stage); clutter_main (); g_source_remove (idle_source); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-texture-no-allocate.c0000664000175000017500000000467514211404421023716 0ustar jpeisachjpeisach#include #include "test-utils.h" /* Tests that the various texture types can be freed without being * allocated */ /* Texture size that is probably to big to fit within the texture * limits */ #define BIG_TEX_WIDTH 16384 #define BIG_TEX_HEIGHT 128 void test_texture_no_allocate (void) { uint8_t *tex_data; CoglTexture *texture; CoglTexture2D *texture_2d; GError *error = NULL; tex_data = malloc (BIG_TEX_WIDTH * BIG_TEX_HEIGHT * 4); /* NB: if we make the atlas and sliced texture APIs public then this * could changed to explicitly use that instead of the magic texture * API */ /* Try to create an atlas texture that is too big so it will * internally be freed without allocating */ texture = cogl_atlas_texture_new_from_data (test_ctx, BIG_TEX_WIDTH, BIG_TEX_HEIGHT, /* format */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* rowstride */ BIG_TEX_WIDTH * 4, tex_data, &error); free (tex_data); /* It's ok if this causes an error, we just don't want it to * crash */ if (texture == NULL) cogl_error_free (error); else cogl_object_unref (texture); /* Try to create a sliced texture without allocating it */ texture = cogl_texture_2d_sliced_new_with_size (test_ctx, BIG_TEX_WIDTH, BIG_TEX_HEIGHT, COGL_TEXTURE_MAX_WASTE); cogl_object_unref (texture); /* 2D texture */ texture_2d = cogl_texture_2d_new_with_size (test_ctx, 64, 64); cogl_object_unref (texture_2d); /* 3D texture */ if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_3D)) { CoglTexture3D *texture_3d = cogl_texture_3d_new_with_size (test_ctx, 64, 64, 64); cogl_object_unref (texture_3d); } /* Rectangle texture */ if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE)) { CoglTextureRectangle *texture_rect = cogl_texture_rectangle_new_with_size (test_ctx, 64, 64); cogl_object_unref (texture_rect); } } muffin-5.2.1/cogl/tests/conform/test-offscreen.c0000664000175000017500000001300714211404421021761 0ustar jpeisachjpeisach#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0 #include #include "test-utils.h" #define RED 0 #define GREEN 1 #define BLUE 2 typedef struct _TestState { int fb_width; int fb_height; } TestState; static void check_quadrant (TestState *state, int qx, int qy, uint32_t expected_rgba) { /* The quadrants are all stuffed into the top right corner of the framebuffer */ int x = state->fb_width * qx / 4 + state->fb_width / 2; int y = state->fb_height * qy / 4; int width = state->fb_width / 4; int height = state->fb_height / 4; /* Subtract a two-pixel gap around the edges to allow some rounding differences */ x += 2; y += 2; width -= 4; height -= 4; test_utils_check_region (test_fb, x, y, width, height, expected_rgba); } static void test_paint (TestState *state) { CoglTexture2D *tex_2d; CoglTexture *tex; CoglOffscreen *offscreen; tex_2d = cogl_texture_2d_new_with_size (test_ctx, state->fb_width, state->fb_height); tex = tex_2d; offscreen = cogl_offscreen_new_with_texture (tex); /* Set a scale and translate transform on the window framebuffer * before switching to the offscreen framebuffer so we can verify it * gets restored when we switch back * * The test is going to draw a grid of 4 colors to a texture which * we subsequently draw to the window with a fullscreen rectangle. * This transform will flip the texture left to right, scale it to a * quarter of the window size and slide it to the top right of the * window. */ cogl_push_matrix (); cogl_translate (0.5, 0.5, 0); cogl_scale (-0.5, 0.5, 1); cogl_push_framebuffer (offscreen); /* Cogl should release the last reference when we call cogl_pop_framebuffer() */ cogl_object_unref (offscreen); /* Setup something other than the identity matrix for the modelview so we can * verify it gets restored when we call cogl_pop_framebuffer () */ cogl_scale (2, 2, 1); /* red, top left */ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_rectangle (-0.5, 0.5, 0, 0); /* green, top right */ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (0, 0.5, 0.5, 0); /* blue, bottom left */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-0.5, 0, 0, -0.5); /* white, bottom right */ cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff); cogl_rectangle (0, 0, 0.5, -0.5); cogl_pop_framebuffer (); cogl_set_source_texture (tex); cogl_rectangle (-1, 1, 1, -1); cogl_object_unref (tex_2d); cogl_pop_matrix (); /* NB: The texture is drawn flipped horizontally and scaled to fit in the * top right corner of the window. */ /* red, top right */ check_quadrant (state, 1, 0, 0xff0000ff); /* green, top left */ check_quadrant (state, 0, 0, 0x00ff00ff); /* blue, bottom right */ check_quadrant (state, 1, 1, 0x0000ffff); /* white, bottom left */ check_quadrant (state, 0, 1, 0xffffffff); } static void test_flush (TestState *state) { CoglTexture2D *tex_2d; CoglTexture *tex; CoglOffscreen *offscreen; CoglColor clear_color; int i; for (i = 0; i < 3; i++) { /* This tests that rendering to a framebuffer and then reading back the contents of the texture will automatically flush the journal */ tex_2d = cogl_texture_2d_new_with_size (test_ctx, 16, 16); /* width/height */ tex = tex_2d; offscreen = cogl_offscreen_new_with_texture (tex); cogl_push_framebuffer (offscreen); cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 255); cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR); cogl_set_source_color4ub (255, 0, 0, 255); cogl_rectangle (-1, -1, 1, 1); if (i == 0) /* First time check using read pixels on the offscreen */ test_utils_check_region (offscreen, 1, 1, 15, 15, 0xff0000ff); else if (i == 1) { uint8_t data[16 * 4 * 16]; int x, y; /* Second time try reading back the texture contents */ cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 16 * 4, /* rowstride */ data); for (y = 1; y < 15; y++) for (x = 1; x < 15; x++) test_utils_compare_pixel (data + x * 4 + y * 16 * 4, 0xff0000ff); } cogl_pop_framebuffer (); if (i == 2) { /* Third time try drawing the texture to the screen */ cogl_set_source_texture (tex); cogl_rectangle (-1, -1, 1, 1); test_utils_check_region (test_fb, 2, 2, /* x/y */ state->fb_width - 4, state->fb_height - 4, 0xff0000ff); } cogl_object_unref (tex_2d); cogl_object_unref (offscreen); } } void test_offscreen (void) { TestState state; state.fb_width = cogl_framebuffer_get_width (test_fb); state.fb_height = cogl_framebuffer_get_height (test_fb); /* XXX: we have to push/pop a framebuffer since this test currently * uses the legacy cogl_rectangle() api. */ cogl_push_framebuffer (test_fb); test_paint (&state); test_flush (&state); cogl_pop_framebuffer (); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-texture-rectangle.c0000664000175000017500000001705614211404421023461 0ustar jpeisachjpeisach#include #include #include "test-conform-common.h" static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; typedef struct _TestState { ClutterActor *stage; } TestState; static CoglHandle create_source_rect (void) { #ifdef GL_TEXTURE_RECTANGLE_ARB int x, y; GLint prev_unpack_row_length; GLint prev_unpack_alignment; GLint prev_unpack_skip_rows; GLint prev_unpack_skip_pixles; GLint prev_rectangle_binding; uint8_t *data = malloc (256 * 256 * 4), *p = data; CoglHandle tex; GLuint gl_tex; for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { *(p++) = x; *(p++) = y; *(p++) = 0; *(p++) = 255; } /* We are about to use OpenGL directly to create a TEXTURE_RECTANGLE * texture so we need to save the state that we modify so we can * restore it afterwards and be sure not to interfere with any state * caching that Cogl may do internally. */ glGetIntegerv (GL_UNPACK_ROW_LENGTH, &prev_unpack_row_length); glGetIntegerv (GL_UNPACK_ALIGNMENT, &prev_unpack_alignment); glGetIntegerv (GL_UNPACK_SKIP_ROWS, &prev_unpack_skip_rows); glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &prev_unpack_skip_pixles); glGetIntegerv (GL_TEXTURE_BINDING_RECTANGLE_ARB, &prev_rectangle_binding); glPixelStorei (GL_UNPACK_ROW_LENGTH, 256); glPixelStorei (GL_UNPACK_ALIGNMENT, 8); glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); glGenTextures (1, &gl_tex); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, gl_tex); glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); /* Now restore the original GL state as Cogl had left it */ glPixelStorei (GL_UNPACK_ROW_LENGTH, prev_unpack_row_length); glPixelStorei (GL_UNPACK_ALIGNMENT, prev_unpack_alignment); glPixelStorei (GL_UNPACK_SKIP_ROWS, prev_unpack_skip_rows); glPixelStorei (GL_UNPACK_SKIP_PIXELS, prev_unpack_skip_pixles); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, prev_rectangle_binding); g_assert (glGetError () == GL_NO_ERROR); free (data); tex = test_utils_texture_new_from_foreign (gl_tex, GL_TEXTURE_RECTANGLE_ARB, 256, 256, 0, 0, COGL_PIXEL_FORMAT_RGBA_8888); return tex; #else /* GL_TEXTURE_RECTANGLE_ARB */ return NULL; #endif /* GL_TEXTURE_RECTANGLE_ARB */ } static CoglHandle create_source_2d (void) { int x, y; uint8_t *data = malloc (256 * 256 * 4), *p = data; CoglHandle tex; for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { *(p++) = 0; *(p++) = x; *(p++) = y; *(p++) = 255; } tex = test_utils_texture_new_from_data (256, 256, TEST_UTILS_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_ANY, 256 * 4, data); free (data); return tex; } static void draw_frame (TestState *state) { GLuint gl_tex; CoglHandle tex_rect = create_source_rect (); CoglHandle material_rect = cogl_material_new (); CoglHandle tex_2d = create_source_2d (); CoglHandle material_2d = cogl_material_new (); g_assert (tex_rect != NULL); cogl_material_set_layer (material_rect, 0, tex_rect); cogl_material_set_layer_filters (material_rect, 0, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_material_set_layer (material_2d, 0, tex_2d); cogl_material_set_layer_filters (material_2d, 0, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_set_source (material_rect); /* Render the texture repeated horizontally twice */ cogl_rectangle_with_texture_coords (0.0f, 0.0f, 512.0f, 256.0f, 0.0f, 0.0f, 2.0f, 1.0f); /* Render the top half of the texture to test without repeating */ cogl_rectangle_with_texture_coords (0.0f, 256.0f, 256.0f, 384.0f, 0.0f, 0.0f, 1.0f, 0.5f); cogl_set_source (material_2d); /* Render the top half of a regular 2D texture */ cogl_rectangle_with_texture_coords (256.0f, 256.0f, 512.0f, 384.0f, 0.0f, 0.0f, 1.0f, 0.5f); /* Flush the rendering now so we can safely delete the texture */ cogl_flush (); cogl_handle_unref (material_rect); /* Cogl doesn't destroy foreign textures so we have to do it manually */ cogl_texture_get_gl_texture (tex_rect, &gl_tex, NULL); glDeleteTextures (1, &gl_tex); cogl_handle_unref (tex_rect); } static void validate_result (TestState *state) { uint8_t *data, *p; int x, y; p = data = malloc (512 * 384 * 4); cogl_read_pixels (0, 0, 512, 384, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888, data); for (y = 0; y < 384; y++) for (x = 0; x < 512; x++) { if (x >= 256 && y >= 256) { g_assert_cmpint (p[0], ==, 0); g_assert_cmpint (p[1], ==, x & 0xff); g_assert_cmpint (p[2], ==, y & 0xff); } else { g_assert_cmpint (p[0], ==, x & 0xff); g_assert_cmpint (p[1], ==, y & 0xff); g_assert_cmpint (p[2], ==, 0); } p += 4; } free (data); /* Comment this out to see what the test paints */ clutter_main_quit (); } static void on_paint (ClutterActor *actor, TestState *state) { draw_frame (state); validate_result (state); } static CoglBool queue_redraw (void *stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } static CoglBool check_rectangle_extension (void) { static const char rect_extension[] = "GL_ARB_texture_rectangle"; const char *extensions = (const char *) glGetString (GL_EXTENSIONS); const char *extensions_end; extensions_end = extensions + strlen (extensions); while (extensions < extensions_end) { const char *end = strchr (extensions, ' '); if (end == NULL) end = extensions_end; if (end - extensions == sizeof (rect_extension) - 1 && !memcmp (extensions, rect_extension, sizeof (rect_extension) - 1)) return TRUE; extensions = end + 1; } return FALSE; } void test_texture_rectangle (TestUtilsGTestFixture *fixture, void *data) { TestState state; unsigned int idle_source; unsigned int paint_handler; state.stage = clutter_stage_get_default (); /* Check whether GL supports the rectangle extension. If not we'll just assume the test passes */ if (check_rectangle_extension ()) { clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color); /* We force continuous redrawing of the stage, since we need to skip * the first few frames, and we wont be doing anything else that * will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, state.stage); paint_handler = g_signal_connect_after (state.stage, "paint", G_CALLBACK (on_paint), &state); clutter_actor_show_all (state.stage); clutter_main (); g_source_remove (idle_source); g_signal_handler_disconnect (state.stage, paint_handler); if (cogl_test_verbose ()) g_print ("OK\n"); } else if (cogl_test_verbose ()) g_print ("Skipping\n"); } muffin-5.2.1/cogl/tests/conform/test-pipeline-cache-unrefs-texture.c0000664000175000017500000000541614211404421025660 0ustar jpeisachjpeisach#include #include "test-utils.h" /* Keep track of the number of textures that we've created and are * still alive */ static int destroyed_texture_count = 0; #define N_TEXTURES 3 static void free_texture_cb (void *user_data) { destroyed_texture_count++; } static CoglTexture * create_texture (void) { static const guint8 data[] = { 0xff, 0xff, 0xff, 0xff }; static CoglUserDataKey texture_data_key; CoglTexture2D *tex_2d; tex_2d = cogl_texture_2d_new_from_data (test_ctx, 1, 1, /* width / height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ data, NULL); /* Set some user data on the texture so we can track when it has * been destroyed */ cogl_object_set_user_data (COGL_OBJECT (tex_2d), &texture_data_key, GINT_TO_POINTER (1), free_texture_cb); return tex_2d; } void test_pipeline_cache_unrefs_texture (void) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglPipeline *simple_pipeline; int i; /* Create a pipeline with three texture layers. That way we can be * pretty sure the pipeline will cause a unique shader to be * generated in the cache */ for (i = 0; i < N_TEXTURES; i++) { CoglTexture *tex = create_texture (); cogl_pipeline_set_layer_texture (pipeline, i, tex); cogl_object_unref (tex); } /* Draw something with the pipeline to ensure it gets into the * pipeline cache */ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10); cogl_framebuffer_finish (test_fb); /* Draw something else so that it is no longer the current flushed * pipeline, and the units have a different texture bound */ simple_pipeline = cogl_pipeline_new (test_ctx); for (i = 0; i < N_TEXTURES; i++) { CoglColor combine_constant; cogl_color_init_from_4ub (&combine_constant, i, 0, 0, 255); cogl_pipeline_set_layer_combine_constant (simple_pipeline, i, &combine_constant); } cogl_framebuffer_draw_rectangle (test_fb, simple_pipeline, 0, 0, 10, 10); cogl_framebuffer_finish (test_fb); cogl_object_unref (simple_pipeline); g_assert_cmpint (destroyed_texture_count, ==, 0); /* Destroy the pipeline. This should immediately cause the textures * to be freed */ cogl_object_unref (pipeline); g_assert_cmpint (destroyed_texture_count, ==, N_TEXTURES); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-path-clip.c0000664000175000017500000000411114211404421021664 0ustar jpeisachjpeisach#include #include #include #include "test-utils.h" void test_path_clip (void) { CoglPath *path; CoglPipeline *pipeline; int fb_width, fb_height; fb_width = cogl_framebuffer_get_width (test_fb); fb_height = cogl_framebuffer_get_height (test_fb); cogl_framebuffer_orthographic (test_fb, 0, 0, fb_width, fb_height, -1, 100); path = cogl_path_new (); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1.0f, 0.0f, 0.0f, 1.0f); /* Make an L-shape with the top right corner left untouched */ cogl_path_move_to (path, 0, fb_height); cogl_path_line_to (path, fb_width, fb_height); cogl_path_line_to (path, fb_width, fb_height / 2); cogl_path_line_to (path, fb_width / 2, fb_height / 2); cogl_path_line_to (path, fb_width / 2, 0); cogl_path_line_to (path, 0, 0); cogl_path_close (path); cogl_framebuffer_push_path_clip (test_fb, path); /* Try to fill the framebuffer with a blue rectangle. This should be * clipped to leave the top right quadrant as is */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 0, 0, 255, 255); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, fb_width, fb_height); cogl_framebuffer_pop_clip (test_fb); cogl_object_unref (pipeline); cogl_object_unref (path); /* Check each of the four quadrants */ test_utils_check_pixel (test_fb, fb_width / 4, fb_height / 4, 0x0000ffff); test_utils_check_pixel (test_fb, fb_width * 3 / 4, fb_height / 4, 0xff0000ff); test_utils_check_pixel (test_fb, fb_width / 4, fb_height * 3 / 4, 0x0000ffff); test_utils_check_pixel (test_fb, fb_width * 3 / 4, fb_height * 3 / 4, 0x0000ffff); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-copy-replace-texture.c0000664000175000017500000000705514211404421024076 0ustar jpeisachjpeisach#include #include #include "test-utils.h" /* Keep track of the number of textures that we've created and are * still alive */ static int alive_texture_mask = 0; #define N_LAYERS 3 #define N_PIPELINES 4 #define PIPELINE_LAYER_MASK(pipeline_num) \ (((1 << N_LAYERS) - 1) << (N_LAYERS * (pipeline_num) + 1)) #define LAST_PIPELINE_MASK PIPELINE_LAYER_MASK (N_PIPELINES - 1) #define FIRST_PIPELINE_MASK PIPELINE_LAYER_MASK (0) static void free_texture_cb (void *user_data) { int texture_num = GPOINTER_TO_INT (user_data); alive_texture_mask &= ~(1 << texture_num); } static CoglTexture * create_texture (void) { static const guint8 data[] = { 0xff, 0xff, 0xff, 0xff }; static CoglUserDataKey texture_data_key; CoglTexture2D *tex_2d; static int texture_num = 1; alive_texture_mask |= (1 << texture_num); tex_2d = cogl_texture_2d_new_from_data (test_ctx, 1, 1, /* width / height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ data, NULL); /* Set some user data on the texture so we can track when it has * been destroyed */ cogl_object_set_user_data (COGL_OBJECT (tex_2d), &texture_data_key, GINT_TO_POINTER (texture_num), free_texture_cb); texture_num++; return tex_2d; } void test_copy_replace_texture (void) { CoglPipeline *pipelines[N_PIPELINES]; int pipeline_num; /* Create a set of pipeline copies each with three of their own * replacement textures */ for (pipeline_num = 0; pipeline_num < N_PIPELINES; pipeline_num++) { int layer_num; if (pipeline_num == 0) pipelines[pipeline_num] = cogl_pipeline_new (test_ctx); else pipelines[pipeline_num] = cogl_pipeline_copy (pipelines[pipeline_num - 1]); for (layer_num = 0; layer_num < N_LAYERS; layer_num++) { CoglTexture *tex = create_texture (); cogl_pipeline_set_layer_texture (pipelines[pipeline_num], layer_num, tex); cogl_object_unref (tex); } } /* Unref everything but the last pipeline */ for (pipeline_num = 0; pipeline_num < N_PIPELINES - 1; pipeline_num++) cogl_object_unref (pipelines[pipeline_num]); if (alive_texture_mask && cogl_test_verbose ()) { int i; g_print ("Alive textures:"); for (i = 0; i < N_PIPELINES * N_LAYERS; i++) if ((alive_texture_mask & (1 << (i + 1)))) g_print (" %i", i); g_print ("\n"); } /* Ideally there should only be the textures from the last pipeline * left alive. We also let Cogl keep the textures from the first * texture alive because currently the child of the third layer in * the first pipeline will retain its authority on the unit index * state so that it can set it to 2. If there are more textures then * it means the pipeline isn't correctly pruning redundant * ancestors */ g_assert_cmpint (alive_texture_mask & ~FIRST_PIPELINE_MASK, ==, LAST_PIPELINE_MASK); /* Clean up the last pipeline */ cogl_object_unref (pipelines[N_PIPELINES - 1]); /* That should get rid of the last of the textures */ g_assert_cmpint (alive_texture_mask, ==, 0); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-blend-strings.c0000664000175000017500000003371414211404421022571 0ustar jpeisachjpeisach#include #include #include "test-utils.h" #define QUAD_WIDTH 20 #define RED 0 #define GREEN 1 #define BLUE 2 #define ALPHA 3 #define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24) #define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16) #define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8) #define MASK_ALPHA(COLOR) (COLOR & 0xff) #define BLEND_CONSTANT_UNUSED 0xDEADBEEF #define TEX_CONSTANT_UNUSED 0xDEADBEEF typedef struct _TestState { CoglContext *ctx; } TestState; static void test_blend (TestState *state, int x, int y, uint32_t src_color, uint32_t dst_color, const char *blend_string, uint32_t blend_constant, uint32_t expected_result) { /* src color */ uint8_t Sr = MASK_RED (src_color); uint8_t Sg = MASK_GREEN (src_color); uint8_t Sb = MASK_BLUE (src_color); uint8_t Sa = MASK_ALPHA (src_color); /* dest color */ uint8_t Dr = MASK_RED (dst_color); uint8_t Dg = MASK_GREEN (dst_color); uint8_t Db = MASK_BLUE (dst_color); uint8_t Da = MASK_ALPHA (dst_color); /* blend constant - when applicable */ uint8_t Br = MASK_RED (blend_constant); uint8_t Bg = MASK_GREEN (blend_constant); uint8_t Bb = MASK_BLUE (blend_constant); uint8_t Ba = MASK_ALPHA (blend_constant); CoglColor blend_const_color; CoglHandle material; CoglPipeline *pipeline; CoglBool status; CoglError *error = NULL; int y_off; int x_off; /* First write out the destination color without any blending... */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, Dr, Dg, Db, Da); cogl_pipeline_set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_set_source (pipeline); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_object_unref (pipeline); /* * Now blend a rectangle over our well defined destination: */ pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, Sr, Sg, Sb, Sa); status = cogl_pipeline_set_blend (pipeline, blend_string, &error); if (!status) { /* It's not strictly a test failure; you need a more capable GPU or * driver to test this blend string. */ if (cogl_test_verbose ()) { g_debug ("Failed to test blend string %s: %s", blend_string, error->message); g_print ("Skipping\n"); } return; } cogl_color_init_from_4ub (&blend_const_color, Br, Bg, Bb, Ba); cogl_pipeline_set_blend_constant (pipeline, &blend_const_color); cogl_set_source (pipeline); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_object_unref (pipeline); /* See what we got... */ y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2); x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2); if (cogl_test_verbose ()) { g_print ("test_blend (%d, %d):\n%s\n", x, y, blend_string); g_print (" src color = %02x, %02x, %02x, %02x\n", Sr, Sg, Sb, Sa); g_print (" dst color = %02x, %02x, %02x, %02x\n", Dr, Dg, Db, Da); if (blend_constant != BLEND_CONSTANT_UNUSED) g_print (" blend constant = %02x, %02x, %02x, %02x\n", Br, Bg, Bb, Ba); else g_print (" blend constant = UNUSED\n"); } test_utils_check_pixel (test_fb, x_off, y_off, expected_result); /* * Test with legacy API */ /* Clear previous work */ cogl_set_source_color4ub (0, 0, 0, 0xff); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); /* First write out the destination color without any blending... */ material = cogl_material_new (); cogl_material_set_color4ub (material, Dr, Dg, Db, Da); cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_set_source (material); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_handle_unref (material); /* * Now blend a rectangle over our well defined destination: */ material = cogl_material_new (); cogl_material_set_color4ub (material, Sr, Sg, Sb, Sa); status = cogl_material_set_blend (material, blend_string, &error); if (!status) { /* This is a failure as it must be equivalent to the new API */ g_warning ("Error setting blend string %s: %s", blend_string, error->message); g_assert_not_reached (); } cogl_color_init_from_4ub (&blend_const_color, Br, Bg, Bb, Ba); cogl_material_set_blend_constant (material, &blend_const_color); cogl_set_source (material); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_handle_unref (material); /* See what we got... */ test_utils_check_pixel (test_fb, x_off, y_off, expected_result); } static CoglTexture * make_texture (uint32_t color) { guchar *tex_data, *p; uint8_t r = MASK_RED (color); uint8_t g = MASK_GREEN (color); uint8_t b = MASK_BLUE (color); uint8_t a = MASK_ALPHA (color); CoglTexture *tex; tex_data = malloc (QUAD_WIDTH * QUAD_WIDTH * 4); for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;) { *(--p) = a; *(--p) = b; *(--p) = g; *(--p) = r; } /* Note: we claim that the data is premultiplied so that Cogl won't * premultiply the data on upload */ tex = test_utils_texture_new_from_data (test_ctx, QUAD_WIDTH, QUAD_WIDTH, TEST_UTILS_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888_PRE, QUAD_WIDTH * 4, tex_data); free (tex_data); return tex; } static void test_tex_combine (TestState *state, int x, int y, uint32_t tex0_color, uint32_t tex1_color, uint32_t combine_constant, const char *combine_string, uint32_t expected_result) { CoglTexture *tex0, *tex1; /* combine constant - when applicable */ uint8_t Cr = MASK_RED (combine_constant); uint8_t Cg = MASK_GREEN (combine_constant); uint8_t Cb = MASK_BLUE (combine_constant); uint8_t Ca = MASK_ALPHA (combine_constant); CoglColor combine_const_color; CoglHandle material; CoglBool status; CoglError *error = NULL; int y_off; int x_off; tex0 = make_texture (tex0_color); tex1 = make_texture (tex1_color); material = cogl_material_new (); cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80); cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_material_set_layer (material, 0, tex0); cogl_material_set_layer_combine (material, 0, "RGBA = REPLACE (TEXTURE)", NULL); cogl_material_set_layer (material, 1, tex1); status = cogl_material_set_layer_combine (material, 1, combine_string, &error); if (!status) { /* It's not strictly a test failure; you need a more capable GPU or * driver to test this texture combine string. */ g_debug ("Failed to test texture combine string %s: %s", combine_string, error->message); } cogl_color_init_from_4ub (&combine_const_color, Cr, Cg, Cb, Ca); cogl_material_set_layer_combine_constant (material, 1, &combine_const_color); cogl_set_source (material); cogl_rectangle (x * QUAD_WIDTH, y * QUAD_WIDTH, x * QUAD_WIDTH + QUAD_WIDTH, y * QUAD_WIDTH + QUAD_WIDTH); cogl_handle_unref (material); cogl_object_unref (tex0); cogl_object_unref (tex1); /* See what we got... */ y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2); x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2); if (cogl_test_verbose ()) { g_print ("test_tex_combine (%d, %d):\n%s\n", x, y, combine_string); g_print (" texture 0 color = 0x%08lX\n", (unsigned long)tex0_color); g_print (" texture 1 color = 0x%08lX\n", (unsigned long)tex1_color); if (combine_constant != TEX_CONSTANT_UNUSED) g_print (" combine constant = %02x, %02x, %02x, %02x\n", Cr, Cg, Cb, Ca); else g_print (" combine constant = UNUSED\n"); } test_utils_check_pixel (test_fb, x_off, y_off, expected_result); } static void paint (TestState *state) { test_blend (state, 0, 0, /* position */ 0xff0000ff, /* src */ 0xffffffff, /* dst */ "RGBA = ADD (SRC_COLOR, 0)", BLEND_CONSTANT_UNUSED, 0xff0000ff); /* expected */ test_blend (state, 1, 0, /* position */ 0x11223344, /* src */ 0x11223344, /* dst */ "RGBA = ADD (SRC_COLOR, DST_COLOR)", BLEND_CONSTANT_UNUSED, 0x22446688); /* expected */ test_blend (state, 2, 0, /* position */ 0x80808080, /* src */ 0xffffffff, /* dst */ "RGBA = ADD (SRC_COLOR * (CONSTANT), 0)", 0x80808080, /* constant (RGBA all = 0.5 when normalized) */ 0x40404040); /* expected */ test_blend (state, 3, 0, /* position */ 0x80000080, /* src (alpha = 0.5 when normalized) */ 0x40000000, /* dst */ "RGBA = ADD (SRC_COLOR * (SRC_COLOR[A])," " DST_COLOR * (1-SRC_COLOR[A]))", BLEND_CONSTANT_UNUSED, 0x60000040); /* expected */ /* XXX: * For all texture combine tests tex0 will use a combine mode of * "RGBA = REPLACE (TEXTURE)" */ test_tex_combine (state, 4, 0, /* position */ 0x11111111, /* texture 0 color */ 0x22222222, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGBA = ADD (PREVIOUS, TEXTURE)", /* tex combine */ 0x33333333); /* expected */ test_tex_combine (state, 5, 0, /* position */ 0x40404040, /* texture 0 color */ 0x80808080, /* texture 1 color (RGBA all = 0.5) */ TEX_CONSTANT_UNUSED, "RGBA = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */ 0x20202020); /* expected */ test_tex_combine (state, 6, 0, /* position */ 0xffffff80, /* texture 0 color (alpha = 0.5) */ 0xDEADBE40, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGB = REPLACE (PREVIOUS)" "A = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */ 0xffffff20); /* expected */ /* XXX: we are assuming test_tex_combine creates a material with * a color of 0x80808080 (i.e. the "PRIMARY" color) */ test_tex_combine (state, 7, 0, /* position */ 0xffffff80, /* texture 0 color (alpha = 0.5) */ 0xDEADBE20, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGB = REPLACE (PREVIOUS)" "A = MODULATE (PRIMARY, TEXTURE)", /* tex combine */ 0xffffff10); /* expected */ test_tex_combine (state, 8, 0, /* position */ 0x11111111, /* texture 0 color */ 0x22222222, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGBA = ADD (PREVIOUS, 1-TEXTURE)", /* tex combine */ 0xeeeeeeee); /* expected */ /* this is again assuming a primary color of 0x80808080 */ test_tex_combine (state, 9, 0, /* position */ 0x10101010, /* texture 0 color */ 0x20202020, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGBA = INTERPOLATE (PREVIOUS, TEXTURE, PRIMARY)", 0x18181818); /* expected */ #if 0 /* using TEXTURE_N appears to be broken in cogl-blend-string.c */ test_tex_combine (state, 0, 1, /* position */ 0xDEADBEEF, /* texture 0 color (not used) */ 0x11223344, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGBA = ADD (TEXTURE_1, TEXTURE)", /* tex combine */ 0x22446688); /* expected */ #endif test_tex_combine (state, 1, 1, /* position */ 0x21314151, /* texture 0 color */ 0x99999999, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGBA = ADD_SIGNED (PREVIOUS, TEXTURE)", /* tex combine */ 0x3a4a5a6a); /* expected */ test_tex_combine (state, 2, 1, /* position */ 0xfedcba98, /* texture 0 color */ 0x11111111, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGBA = SUBTRACT (PREVIOUS, TEXTURE)", /* tex combine */ 0xedcba987); /* expected */ test_tex_combine (state, 3, 1, /* position */ 0x8899aabb, /* texture 0 color */ 0xbbaa9988, /* texture 1 color */ TEX_CONSTANT_UNUSED, "RGB = DOT3_RGBA (PREVIOUS, TEXTURE)" "A = REPLACE (PREVIOUS)", 0x2a2a2abb); /* expected */ } void test_blend_strings (void) { TestState state; cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); /* XXX: we have to push/pop a framebuffer since this test currently * uses the legacy cogl_rectangle() api. */ cogl_push_framebuffer (test_fb); paint (&state); cogl_pop_framebuffer (); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-just-vertex-shader.c0000664000175000017500000001422314211404421023554 0ustar jpeisachjpeisach#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0 #include #include #include "test-utils.h" typedef struct _TestState { int paddiing; } TestState; static CoglTexture * create_dummy_texture (void) { /* Create a dummy 1x1 green texture to replace the color from the vertex shader */ static const uint8_t data[4] = { 0x00, 0xff, 0x00, 0xff }; return test_utils_texture_new_from_data (test_ctx, 1, 1, /* size */ TEST_UTILS_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGB_888, 4, /* rowstride */ data); } static void paint_legacy (TestState *state) { CoglHandle material = cogl_material_new (); CoglTexture *tex; CoglColor color; CoglError *error = NULL; CoglHandle shader, program; cogl_color_init_from_4ub (&color, 0, 0, 0, 255); cogl_clear (&color, COGL_BUFFER_BIT_COLOR); /* Set the primary vertex color as red */ cogl_color_set_from_4ub (&color, 0xff, 0x00, 0x00, 0xff); cogl_material_set_color (material, &color); /* Override the vertex color in the texture environment with a constant green color provided by a texture */ tex = create_dummy_texture (); cogl_material_set_layer (material, 0, tex); cogl_object_unref (tex); if (!cogl_material_set_layer_combine (material, 0, "RGBA=REPLACE(TEXTURE)", &error)) { g_warning ("Error setting layer combine: %s", error->message); g_assert_not_reached (); } /* Set up a dummy vertex shader that does nothing but the usual fixed function transform */ shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX); cogl_shader_source (shader, "void\n" "main ()\n" "{\n" " cogl_position_out = " "cogl_modelview_projection_matrix * " "cogl_position_in;\n" " cogl_color_out = cogl_color_in;\n" " cogl_tex_coord_out[0] = cogl_tex_coord_in;\n" "}\n"); cogl_shader_compile (shader); if (!cogl_shader_is_compiled (shader)) { char *log = cogl_shader_get_info_log (shader); g_warning ("Shader compilation failed:\n%s", log); free (log); g_assert_not_reached (); } program = cogl_create_program (); cogl_program_attach_shader (program, shader); cogl_program_link (program); cogl_handle_unref (shader); /* Draw something using the material */ cogl_set_source (material); cogl_rectangle (0, 0, 50, 50); /* Draw it again using the program. It should look exactly the same */ cogl_program_use (program); cogl_rectangle (50, 0, 100, 50); cogl_program_use (COGL_INVALID_HANDLE); cogl_handle_unref (material); cogl_handle_unref (program); } static void paint (TestState *state) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglTexture *tex; CoglColor color; CoglError *error = NULL; CoglHandle shader, program; cogl_color_init_from_4ub (&color, 0, 0, 0, 255); cogl_clear (&color, COGL_BUFFER_BIT_COLOR); /* Set the primary vertex color as red */ cogl_color_set_from_4ub (&color, 0xff, 0x00, 0x00, 0xff); cogl_pipeline_set_color (pipeline, &color); /* Override the vertex color in the texture environment with a constant green color provided by a texture */ tex = create_dummy_texture (); cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_object_unref (tex); if (!cogl_pipeline_set_layer_combine (pipeline, 0, "RGBA=REPLACE(TEXTURE)", &error)) { g_warning ("Error setting layer combine: %s", error->message); g_assert_not_reached (); } /* Set up a dummy vertex shader that does nothing but the usual fixed function transform */ shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX); cogl_shader_source (shader, "void\n" "main ()\n" "{\n" " cogl_position_out = " "cogl_modelview_projection_matrix * " "cogl_position_in;\n" " cogl_color_out = cogl_color_in;\n" " cogl_tex_coord_out[0] = cogl_tex_coord_in;\n" "}\n"); cogl_shader_compile (shader); if (!cogl_shader_is_compiled (shader)) { char *log = cogl_shader_get_info_log (shader); g_warning ("Shader compilation failed:\n%s", log); free (log); g_assert_not_reached (); } program = cogl_create_program (); cogl_program_attach_shader (program, shader); cogl_program_link (program); cogl_handle_unref (shader); /* Draw something without the program */ cogl_set_source (pipeline); cogl_rectangle (0, 0, 50, 50); /* Draw it again using the program. It should look exactly the same */ cogl_pipeline_set_user_program (pipeline, program); cogl_handle_unref (program); cogl_rectangle (50, 0, 100, 50); cogl_pipeline_set_user_program (pipeline, COGL_INVALID_HANDLE); cogl_object_unref (pipeline); } static void validate_result (CoglFramebuffer *framebuffer) { /* Non-shader version */ test_utils_check_pixel (framebuffer, 25, 25, 0x00ff0000); /* Shader version */ test_utils_check_pixel (framebuffer, 75, 25, 0x00ff0000); } void test_just_vertex_shader (void) { TestState state; cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); /* XXX: we have to push/pop a framebuffer since this test currently * uses the legacy cogl_rectangle() api. */ cogl_push_framebuffer (test_fb); paint_legacy (&state); validate_result (test_fb); paint (&state); validate_result (test_fb); cogl_pop_framebuffer (); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-framebuffer-get-bits.c0000664000175000017500000000265414211404421024015 0ustar jpeisachjpeisach#include #include "test-utils.h" void test_framebuffer_get_bits (void) { CoglTexture2D *tex_a = cogl_texture_2d_new_with_size (test_ctx, 16, 16); /* width/height */ CoglOffscreen *offscreen_a = cogl_offscreen_new_with_texture (tex_a); CoglFramebuffer *fb_a = offscreen_a; CoglTexture2D *tex_rgba = cogl_texture_2d_new_with_size (test_ctx, 16, 16); /* width/height */ CoglOffscreen *offscreen_rgba = cogl_offscreen_new_with_texture (tex_rgba); CoglFramebuffer *fb_rgba = offscreen_rgba; cogl_texture_set_components (tex_a, COGL_TEXTURE_COMPONENTS_A); cogl_framebuffer_allocate (fb_a, NULL); cogl_framebuffer_allocate (fb_rgba, NULL); g_assert_cmpint (cogl_framebuffer_get_red_bits (fb_a), ==, 0); g_assert_cmpint (cogl_framebuffer_get_green_bits (fb_a), ==, 0); g_assert_cmpint (cogl_framebuffer_get_blue_bits (fb_a), ==, 0); g_assert_cmpint (cogl_framebuffer_get_alpha_bits (fb_a), >=, 1); g_assert_cmpint (cogl_framebuffer_get_red_bits (fb_rgba), >=, 1); g_assert_cmpint (cogl_framebuffer_get_green_bits (fb_rgba), >=, 1); g_assert_cmpint (cogl_framebuffer_get_blue_bits (fb_rgba), >=, 1); g_assert_cmpint (cogl_framebuffer_get_alpha_bits (fb_rgba), >=, 1); cogl_object_unref (fb_rgba); cogl_object_unref (tex_rgba); cogl_object_unref (fb_a); cogl_object_unref (tex_a); } muffin-5.2.1/cogl/tests/conform/test-viewport.c0000664000175000017500000003552514211404421021677 0ustar jpeisachjpeisach #include #include #include "test-conform-common.h" #define RED 0 #define GREEN 1 #define BLUE 2 #define ALPHA 3 #define FRAMEBUFFER_WIDTH 640 #define FRAMEBUFFER_HEIGHT 480 static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; static void assert_region_color (int x, int y, int width, int height, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { uint8_t *data = calloc (1, width * height * 4); cogl_read_pixels (x, y, width, height, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, data); for (y = 0; y < height; y++) for (x = 0; x < width; x++) { uint8_t *pixel = &data[y*width*4 + x*4]; #if 1 g_assert (pixel[RED] == red && pixel[GREEN] == green && pixel[BLUE] == blue && pixel[ALPHA] == alpha); #endif } free (data); } static void assert_rectangle_color_and_black_border (int x, int y, int width, int height, uint8_t red, uint8_t green, uint8_t blue) { /* check the rectangle itself... */ assert_region_color (x, y, width, height, red, green, blue, 0xff); /* black to left of the rectangle */ assert_region_color (x-10, y-10, 10, height+20, 0x00, 0x00, 0x00, 0xff); /* black to right of the rectangle */ assert_region_color (x+width, y-10, 10, height+20, 0x00, 0x00, 0x00, 0xff); /* black above the rectangle */ assert_region_color (x-10, y-10, width+20, 10, 0x00, 0x00, 0x00, 0xff); /* and black below the rectangle */ assert_region_color (x-10, y+height, width+20, 10, 0x00, 0x00, 0x00, 0xff); } static void on_paint (ClutterActor *actor, void *state) { float saved_viewport[4]; CoglMatrix saved_projection; CoglMatrix projection; CoglMatrix modelview; guchar *data; CoglHandle tex; CoglHandle offscreen; CoglColor black; float x0; float y0; float width; float height; /* for clearing the offscreen framebuffer to black... */ cogl_color_init_from_4ub (&black, 0x00, 0x00, 0x00, 0xff); cogl_get_viewport (saved_viewport); cogl_get_projection_matrix (&saved_projection); cogl_push_matrix (); cogl_matrix_init_identity (&projection); cogl_matrix_init_identity (&modelview); cogl_set_projection_matrix (&projection); cogl_set_modelview_matrix (&modelview); /* - Create a 100x200 viewport (i.e. smaller than the onscreen framebuffer) * and position it a (20, 10) inside the framebuffer. * - Fill the whole viewport with a purple rectangle * - Verify that the framebuffer is black with a 100x200 purple rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 100, /* width */ 200); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* fill the viewport with purple.. */ cogl_set_source_color4ub (0xff, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0xff, 0x00, 0xff); /* - Create a viewport twice the size of the onscreen framebuffer with * a negative offset positioning it at (-20, -10) relative to the * buffer itself. * - Draw a 100x200 green rectangle at (40, 20) within the viewport (which * is (20, 10) within the framebuffer) * - Verify that the framebuffer is black with a 100x200 green rectangle at * (20, 10) */ cogl_set_viewport (-20, /* x */ -10, /* y */ FRAMEBUFFER_WIDTH * 2, /* width */ FRAMEBUFFER_HEIGHT * 2); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* draw a 100x200 green rectangle offset into the viewport such that its * top left corner should be found at (20, 10) in the offscreen buffer */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f; width = (1.0f / FRAMEBUFFER_WIDTH) * 100; height = (1.0f / FRAMEBUFFER_HEIGHT) * 200; cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (x0, y0, x0 + width, y0 - height); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0xff, 0x00); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 window space clip rectangle at (20, 10) * - Fill the whole viewport with a blue rectangle * - Verify that the framebuffer is black with a 100x200 blue rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); cogl_clip_push_window_rectangle (20, 10, 100, 200); /* fill the viewport with blue.. */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0x00, 0xff); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport * (i.e. (40, 20) inside the framebuffer) * - Fill the whole viewport with a green rectangle * - Verify that the framebuffer is black with a 100x200 green rectangle at * (40, 20) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* figure out where to position our clip rectangle in model space * coordinates... */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (2.0f / 200) * 20.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (2.0f / 400) * 10.0f; width = (2.0f / 200) * 100; height = (2.0f / 400) * 200; /* add the clip rectangle... */ cogl_push_matrix (); cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0); /* XXX: Rotate just enough to stop Cogl from converting our model space * rectangle into a window space rectangle.. */ cogl_rotate (0.1, 0, 0, 1); cogl_clip_push_rectangle (-(width/2.0), -(height/2.0), width/2.0, height/2.0); cogl_pop_matrix (); /* fill the viewport with green.. */ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (40, 20, 100, 200, 0x00, 0xff, 0x00); /* Set the viewport to something specific so we can verify that it gets * restored after we are done testing with an offscreen framebuffer... */ cogl_set_viewport (20, 10, 100, 200); /* * Next test offscreen drawing... */ data = malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT); tex = test_utils_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, TEST_UTILS_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */ COGL_PIXEL_FORMAT_ANY, /* internal fmt */ FRAMEBUFFER_WIDTH * 4, /* rowstride */ data); free (data); offscreen = cogl_offscreen_new_with_texture (tex); cogl_push_framebuffer (offscreen); /* - Create a 100x200 viewport (i.e. smaller than the offscreen framebuffer) * and position it a (20, 10) inside the framebuffer. * - Fill the whole viewport with a blue rectangle * - Verify that the framebuffer is black with a 100x200 blue rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 100, /* width */ 200); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* fill the viewport with blue.. */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0x00, 0xff); /* - Create a viewport twice the size of the offscreen framebuffer with * a negative offset positioning it at (-20, -10) relative to the * buffer itself. * - Draw a 100x200 red rectangle at (40, 20) within the viewport (which * is (20, 10) within the framebuffer) * - Verify that the framebuffer is black with a 100x200 red rectangle at * (20, 10) */ cogl_set_viewport (-20, /* x */ -10, /* y */ FRAMEBUFFER_WIDTH * 2, /* width */ FRAMEBUFFER_HEIGHT * 2); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* draw a 100x200 red rectangle offset into the viewport such that its * top left corner should be found at (20, 10) in the offscreen buffer */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f; width = (1.0f / FRAMEBUFFER_WIDTH) * 100; height = (1.0f / FRAMEBUFFER_HEIGHT) * 200; cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_rectangle (x0, y0, x0 + width, y0 - height); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0xff, 0x00, 0x00); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 window space clip rectangle at (20, 10) * - Fill the whole viewport with a blue rectangle * - Verify that the framebuffer is black with a 100x200 blue rectangle at * (20, 10) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); cogl_clip_push_window_rectangle (20, 10, 100, 200); /* fill the viewport with blue.. */ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0x00, 0x00, 0xff); /* - Create a 200x400 viewport and position it a (20, 10) inside the draw * buffer. * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport * (i.e. (40, 20) inside the framebuffer) * - Fill the whole viewport with a green rectangle * - Verify that the framebuffer is black with a 100x200 green rectangle at * (40, 20) */ cogl_set_viewport (20, /* x */ 10, /* y */ 200, /* width */ 400); /* height */ /* clear everything... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); /* figure out where to position our clip rectangle in model space * coordinates... */ /* (offset 40 pixels right from the left of the viewport) */ x0 = -1.0f + (2.0f / 200) * 20.f; /* (offset 20 pixels down from the top of the viewport) */ y0 = 1.0f - (2.0f / 400) * 10.0f; width = (2.0f / 200) * 100; height = (2.0f / 400) * 200; /* add the clip rectangle... */ cogl_push_matrix (); cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0); /* XXX: Rotate just enough to stop Cogl from converting our model space * rectangle into a window space rectangle.. */ cogl_rotate (0.1, 0, 0, 1); cogl_clip_push_rectangle (-(width/2.0), -(height/2.0), width/2, height/2); cogl_pop_matrix (); /* fill the viewport with green.. */ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff); cogl_rectangle (-1, 1, 1, -1); cogl_clip_pop (); assert_rectangle_color_and_black_border (40, 20, 100, 200, 0x00, 0xff, 0x00); /* Set the viewport to something obscure to verify that it gets * replace when we switch back to the onscreen framebuffer... */ cogl_set_viewport (0, 0, 10, 10); cogl_pop_framebuffer (); cogl_handle_unref (offscreen); /* * Verify that the previous onscreen framebuffer's viewport was restored * by drawing a white rectangle across the whole viewport. This should * draw a 100x200 rectangle at (20,10) relative to the onscreen draw * buffer... */ cogl_clear (&black, COGL_BUFFER_BIT_COLOR); cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff); cogl_rectangle (-1, 1, 1, -1); assert_rectangle_color_and_black_border (20, 10, 100, 200, 0xff, 0xff, 0xff); /* Uncomment to display the last contents of the offscreen framebuffer */ #if 1 cogl_matrix_init_identity (&projection); cogl_matrix_init_identity (&modelview); cogl_set_viewport (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT); cogl_set_projection_matrix (&projection); cogl_set_modelview_matrix (&modelview); cogl_set_source_texture (tex); cogl_rectangle (-1, 1, 1, -1); #endif cogl_handle_unref (tex); /* Finally restore the stage's original state... */ cogl_pop_matrix (); cogl_set_projection_matrix (&saved_projection); cogl_set_viewport (saved_viewport[0], saved_viewport[1], saved_viewport[2], saved_viewport[3]); /* Comment this out if you want visual feedback of what this test * paints. */ clutter_main_quit (); } static CoglBool queue_redraw (void *stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_viewport (TestUtilsGTestFixture *fixture, void *data) { unsigned int idle_source; ClutterActor *stage; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); /* We force continuous redrawing of the stage, since we need to skip * the first few frames, and we wont be doing anything else that * will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), NULL); clutter_actor_show (stage); clutter_main (); g_source_remove (idle_source); /* Remove all of the actors from the stage */ clutter_container_foreach (CLUTTER_CONTAINER (stage), (ClutterCallback) clutter_actor_destroy, NULL); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-texture-get-set-data.c0000664000175000017500000001032214211404421023761 0ustar jpeisachjpeisach#include #include #include "test-utils.h" static void check_texture (int width, int height, TestUtilsTextureFlags flags) { CoglTexture *tex; uint8_t *data, *p; int y, x; int rowstride; CoglBitmap *bmp; p = data = malloc (width * height * 4); for (y = 0; y < height; y++) for (x = 0; x < width; x++) { *(p++) = x; *(p++) = y; *(p++) = 128; *(p++) = (x ^ y); } bmp = cogl_bitmap_new_for_data (test_ctx, width, height, COGL_PIXEL_FORMAT_RGBA_8888, width * 4, data); tex = test_utils_texture_new_from_bitmap (bmp, flags, FALSE); /* Replace the bottom right quarter of the data with negated data to test set_region */ rowstride = width * 4; p = data + (height / 2) * rowstride + rowstride / 2; for (y = 0; y < height / 2; y++) { for (x = 0; x < width / 2; x++) { p[0] = ~p[0]; p[1] = ~p[1]; p[2] = ~p[2]; p[3] = ~p[3]; p += 4; } p += width * 2; } cogl_texture_set_region (tex, width / 2, height / 2, width / 2, /* dest x */ height / 2, /* dest y */ width / 2, /* region width */ height / 2, /* region height */ width, /* src width */ height, /* src height */ COGL_PIXEL_FORMAT_RGBA_8888, rowstride, data); /* Check passing a NULL pointer and a zero rowstride. The texture should calculate the needed data size and return it */ g_assert_cmpint (cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_ANY, 0, NULL), ==, width * height * 4); /* Try first receiving the data as RGB. This should cause a * conversion */ memset (data, 0, width * height * 4); cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_RGB_888, width * 3, data); p = data; for (y = 0; y < height; y++) for (x = 0; x < width; x++) { if (x >= width / 2 && y >= height / 2) { g_assert_cmpint (p[0], ==, ~x & 0xff); g_assert_cmpint (p[1], ==, ~y & 0xff); g_assert_cmpint (p[2], ==, ~128 & 0xff); } else { g_assert_cmpint (p[0], ==, x & 0xff); g_assert_cmpint (p[1], ==, y & 0xff); g_assert_cmpint (p[2], ==, 128); } p += 3; } /* Now try receiving the data as RGBA. This should not cause a * conversion and no unpremultiplication because we explicitly set * the internal format when we created the texture */ memset (data, 0, width * height * 4); cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_RGBA_8888, width * 4, data); p = data; for (y = 0; y < height; y++) for (x = 0; x < width; x++) { if (x >= width / 2 && y >= height / 2) { g_assert_cmpint (p[0], ==, ~x & 0xff); g_assert_cmpint (p[1], ==, ~y & 0xff); g_assert_cmpint (p[2], ==, ~128 & 0xff); g_assert_cmpint (p[3], ==, ~(x ^ y) & 0xff); } else { g_assert_cmpint (p[0], ==, x & 0xff); g_assert_cmpint (p[1], ==, y & 0xff); g_assert_cmpint (p[2], ==, 128); g_assert_cmpint (p[3], ==, (x ^ y) & 0xff); } p += 4; } cogl_object_unref (tex); free (data); } void test_texture_get_set_data (void) { /* First try without atlasing */ check_texture (256, 256, TEST_UTILS_TEXTURE_NO_ATLAS); /* Try again with atlasing. This should end up testing the atlas backend and the sub texture backend */ check_texture (256, 256, 0); /* Try with a really big texture in the hope that it will end up sliced. */ check_texture (4, 5128, TEST_UTILS_TEXTURE_NO_ATLAS); /* And in the other direction. */ check_texture (5128, 4, TEST_UTILS_TEXTURE_NO_ATLAS); } muffin-5.2.1/cogl/tests/conform/test-primitive.c0000664000175000017500000002342114211404421022020 0ustar jpeisachjpeisach#include #include #include #include "test-utils.h" typedef struct _TestState { int fb_width; int fb_height; } TestState; #define PRIM_COLOR 0xff00ffff #define TEX_COLOR 0x0000ffff #define N_ATTRIBS 8 typedef CoglPrimitive * (* TestPrimFunc) (CoglContext *ctx, uint32_t *expected_color); static CoglPrimitive * test_prim_p2 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP2 verts[] = { { 0, 0 }, { 0, 10 }, { 10, 0 } }; return cogl_primitive_new_p2 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static CoglPrimitive * test_prim_p3 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP3 verts[] = { { 0, 0, 0 }, { 0, 10, 0 }, { 10, 0, 0 } }; return cogl_primitive_new_p3 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static CoglPrimitive * test_prim_p2c4 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP2C4 verts[] = { { 0, 0, 255, 255, 0, 255 }, { 0, 10, 255, 255, 0, 255 }, { 10, 0, 255, 255, 0, 255 } }; *expected_color = 0xffff00ff; return cogl_primitive_new_p2c4 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static CoglPrimitive * test_prim_p3c4 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP3C4 verts[] = { { 0, 0, 0, 255, 255, 0, 255 }, { 0, 10, 0, 255, 255, 0, 255 }, { 10, 0, 0, 255, 255, 0, 255 } }; *expected_color = 0xffff00ff; return cogl_primitive_new_p3c4 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static CoglPrimitive * test_prim_p2t2 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP2T2 verts[] = { { 0, 0, 1, 0 }, { 0, 10, 1, 0 }, { 10, 0, 1, 0 } }; *expected_color = TEX_COLOR; return cogl_primitive_new_p2t2 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static CoglPrimitive * test_prim_p3t2 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP3T2 verts[] = { { 0, 0, 0, 1, 0 }, { 0, 10, 0, 1, 0 }, { 10, 0, 0, 1, 0 } }; *expected_color = TEX_COLOR; return cogl_primitive_new_p3t2 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static CoglPrimitive * test_prim_p2t2c4 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP2T2C4 verts[] = { { 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff }, { 0, 10, 1, 0, 0xff, 0xff, 0xf0, 0xff }, { 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } }; /* The blue component of the texture color should be replaced with 0xf0 */ *expected_color = (TEX_COLOR & 0xffff00ff) | 0x0000f000; return cogl_primitive_new_p2t2c4 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static CoglPrimitive * test_prim_p3t2c4 (CoglContext *ctx, uint32_t *expected_color) { static const CoglVertexP3T2C4 verts[] = { { 0, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff }, { 0, 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff }, { 10, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } }; /* The blue component of the texture color should be replaced with 0xf0 */ *expected_color = (TEX_COLOR & 0xffff00ff) | 0x0000f000; return cogl_primitive_new_p3t2c4 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, /* n_vertices */ verts); } static const TestPrimFunc test_prim_funcs[] = { test_prim_p2, test_prim_p3, test_prim_p2c4, test_prim_p3c4, test_prim_p2t2, test_prim_p3t2, test_prim_p2t2c4, test_prim_p3t2c4 }; static void test_paint (TestState *state) { CoglPipeline *pipeline; CoglTexture *tex; uint8_t tex_data[6]; int i; /* Create a two pixel texture. The first pixel is white and the second pixel is tex_color. The assumption is that if no texture coordinates are specified then it will default to 0,0 and get white */ tex_data[0] = 255; tex_data[1] = 255; tex_data[2] = 255; tex_data[3] = (TEX_COLOR >> 24) & 0xff; tex_data[4] = (TEX_COLOR >> 16) & 0xff; tex_data[5] = (TEX_COLOR >> 8) & 0xff; tex = test_utils_texture_new_from_data (test_ctx, 2, 1, /* size */ TEST_UTILS_TEXTURE_NO_ATLAS, COGL_PIXEL_FORMAT_RGB_888, 6, /* rowstride */ tex_data); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, (PRIM_COLOR >> 24) & 0xff, (PRIM_COLOR >> 16) & 0xff, (PRIM_COLOR >> 8) & 0xff, (PRIM_COLOR >> 0) & 0xff); cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_object_unref (tex); for (i = 0; i < G_N_ELEMENTS (test_prim_funcs); i++) { CoglPrimitive *prim; uint32_t expected_color = PRIM_COLOR; prim = test_prim_funcs[i] (test_ctx, &expected_color); cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, i * 10, 0, 0); cogl_primitive_draw (prim, test_fb, pipeline); cogl_framebuffer_pop_matrix (test_fb); test_utils_check_pixel (test_fb, i * 10 + 2, 2, expected_color); cogl_object_unref (prim); } cogl_object_unref (pipeline); } static CoglBool get_attributes_cb (CoglPrimitive *prim, CoglAttribute *attrib, void *user_data) { CoglAttribute ***p = user_data; *((* p)++) = attrib; return TRUE; } static int compare_pointers (const void *a, const void *b) { CoglAttribute *pa = *(CoglAttribute **) a; CoglAttribute *pb = *(CoglAttribute **) b; if (pa < pb) return -1; else if (pa > pb) return 1; else return 0; } static void test_copy (TestState *state) { static const uint16_t indices_data[2] = { 1, 2 }; CoglAttributeBuffer *buffer = cogl_attribute_buffer_new (test_ctx, 100, NULL); CoglAttribute *attributes[N_ATTRIBS]; CoglAttribute *attributes_a[N_ATTRIBS], *attributes_b[N_ATTRIBS]; CoglAttribute **p; CoglPrimitive *prim_a, *prim_b; CoglIndices *indices; int i; for (i = 0; i < N_ATTRIBS; i++) { char *name = g_strdup_printf ("foo_%i", i); attributes[i] = cogl_attribute_new (buffer, name, 16, /* stride */ 16, /* offset */ 2, /* components */ COGL_ATTRIBUTE_TYPE_FLOAT); free (name); } prim_a = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, 8, /* n_vertices */ attributes, N_ATTRIBS); indices = cogl_indices_new (test_ctx, COGL_INDICES_TYPE_UNSIGNED_SHORT, indices_data, 2 /* n_indices */); cogl_primitive_set_first_vertex (prim_a, 12); cogl_primitive_set_indices (prim_a, indices, 2); prim_b = cogl_primitive_copy (prim_a); p = attributes_a; cogl_primitive_foreach_attribute (prim_a, get_attributes_cb, &p); g_assert_cmpint (p - attributes_a, ==, N_ATTRIBS); p = attributes_b; cogl_primitive_foreach_attribute (prim_b, get_attributes_cb, &p); g_assert_cmpint (p - attributes_b, ==, N_ATTRIBS); qsort (attributes_a, N_ATTRIBS, sizeof (CoglAttribute *), compare_pointers); qsort (attributes_b, N_ATTRIBS, sizeof (CoglAttribute *), compare_pointers); g_assert (memcmp (attributes_a, attributes_b, sizeof (attributes_a)) == 0); g_assert_cmpint (cogl_primitive_get_first_vertex (prim_a), ==, cogl_primitive_get_first_vertex (prim_b)); g_assert_cmpint (cogl_primitive_get_n_vertices (prim_a), ==, cogl_primitive_get_n_vertices (prim_b)); g_assert_cmpint (cogl_primitive_get_mode (prim_a), ==, cogl_primitive_get_mode (prim_b)); g_assert (cogl_primitive_get_indices (prim_a) == cogl_primitive_get_indices (prim_b)); cogl_object_unref (prim_a); cogl_object_unref (prim_b); cogl_object_unref (indices); for (i = 0; i < N_ATTRIBS; i++) cogl_object_unref (attributes[i]); cogl_object_unref (buffer); } void test_primitive (void) { TestState state; state.fb_width = cogl_framebuffer_get_width (test_fb); state.fb_height = cogl_framebuffer_get_height (test_fb); cogl_framebuffer_orthographic (test_fb, 0, 0, state.fb_width, state.fb_height, -1, 100); test_paint (&state); test_copy (&state); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-vertex-buffer-interleved.c0000664000175000017500000000766714211404421024751 0ustar jpeisachjpeisach #include #include #include "test-conform-common.h" /* This test verifies that interleved attributes work with the vertex buffer * API. We add (x,y) GLfloat vertices, interleved with RGBA GLubyte color * attributes to a buffer, submit and draw. * * If you want visual feedback of what this test paints for debugging purposes, * then remove the call to clutter_main_quit() in validate_result. */ typedef struct _TestState { CoglHandle buffer; ClutterGeometry stage_geom; } TestState; typedef struct _InterlevedVertex { GLfloat x; GLfloat y; GLubyte r; GLubyte g; GLubyte b; GLubyte a; } InterlevedVertex; static void validate_result (TestState *state) { GLubyte pixel[4]; GLint y_off = 90; /* NB: We ignore the alpha, since we don't know if our render target is * RGB or RGBA */ #define RED 0 #define GREEN 1 #define BLUE 2 /* Should see a blue pixel */ cogl_read_pixels (10, y_off, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0); #undef RED #undef GREEN #undef BLUE /* Comment this out if you want visual feedback of what this test * paints. */ clutter_main_quit (); } static void on_paint (ClutterActor *actor, TestState *state) { /* Draw a faded blue triangle */ cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ validate_result (state); } static CoglBool queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_vertex_buffer_interleved (TestUtilsGTestFixture *fixture, void *data) { TestState state; ClutterActor *stage; ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff}; ClutterActor *group; unsigned int idle_source; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr); clutter_actor_get_geometry (stage, &state.stage_geom); group = clutter_group_new (); clutter_actor_set_size (group, state.stage_geom.width, state.stage_geom.height); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); /* We force continuous redrawing incase someone comments out the * clutter_main_quit and wants visual feedback for the test since we * wont be doing anything else that will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); { InterlevedVertex verts[3] = { { /* .x = */ 0.0, /* .y = */ 0.0, /* blue */ /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0xff }, { /* .x = */ 100.0, /* .y = */ 100.0, /* transparent blue */ /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 }, { /* .x = */ 0.0, /* .y = */ 100.0, /* transparent blue */ /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 }, }; /* We assume the compiler is doing no funny struct padding for this test: */ g_assert (sizeof (InterlevedVertex) == 12); state.buffer = cogl_vertex_buffer_new (3 /* n vertices */); cogl_vertex_buffer_add (state.buffer, "gl_Vertex", 2, /* n components */ GL_FLOAT, FALSE, /* normalized */ 12, /* stride */ &verts[0].x); cogl_vertex_buffer_add (state.buffer, "gl_Color", 4, /* n components */ GL_UNSIGNED_BYTE, FALSE, /* normalized */ 12, /* stride */ &verts[0].r); cogl_vertex_buffer_submit (state.buffer); } clutter_actor_show_all (stage); clutter_main (); cogl_handle_unref (state.buffer); g_source_remove (idle_source); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-vertex-buffer-contiguous.c0000664000175000017500000001716414211404421025000 0ustar jpeisachjpeisach #include #include #include "test-conform-common.h" /* This test verifies that the simplest usage of the vertex buffer API, * where we add contiguous (x,y) GLfloat vertices, and RGBA GLubyte color * attributes to a buffer, submit, and draw. * * It also tries to verify that the enable/disable attribute APIs are working * too. * * If you want visual feedback of what this test paints for debugging purposes, * then remove the call to clutter_main_quit() in validate_result. */ typedef struct _TestState { CoglHandle buffer; CoglHandle texture; CoglHandle material; ClutterGeometry stage_geom; } TestState; static void validate_result (TestState *state) { GLubyte pixel[4]; GLint y_off = 90; if (cogl_test_verbose ()) g_print ("y_off = %d\n", y_off); /* NB: We ignore the alpha, since we don't know if our render target is * RGB or RGBA */ #define RED 0 #define GREEN 1 #define BLUE 2 /* Should see a blue pixel */ cogl_read_pixels (10, y_off, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0); /* Should see a red pixel */ cogl_read_pixels (110, y_off, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 1 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[RED] != 0 && pixel[GREEN] == 0 && pixel[BLUE] == 0); /* Should see a blue pixel */ cogl_read_pixels (210, y_off, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 2 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0); /* Should see a green pixel, at bottom of 4th triangle */ cogl_read_pixels (310, y_off, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 3 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[GREEN] > pixel[RED] && pixel[GREEN] > pixel[BLUE]); /* Should see a red pixel, at top of 4th triangle */ cogl_read_pixels (310, y_off - 70, 1, 1, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); if (cogl_test_verbose ()) g_print ("pixel 4 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); g_assert (pixel[RED] > pixel[GREEN] && pixel[RED] > pixel[BLUE]); #undef RED #undef GREEN #undef BLUE /* Comment this out if you want visual feedback of what this test * paints. */ clutter_main_quit (); } static void on_paint (ClutterActor *actor, TestState *state) { /* Draw a faded blue triangle */ cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue"); cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ /* Draw a red triangle */ /* Here we are testing that the disable attribute works; if it doesn't * the triangle will remain faded blue */ cogl_translate (100, 0, 0); cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue"); cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ /* Draw a faded blue triangle */ /* Here we are testing that the re-enable works; if it doesn't * the triangle will remain red */ cogl_translate (100, 0, 0); cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue"); cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ /* Draw a textured triangle */ cogl_translate (100, 0, 0); cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue"); cogl_set_source (state->material); cogl_material_set_color4ub (state->material, 0xff, 0xff, 0xff, 0xff); cogl_vertex_buffer_draw (state->buffer, GL_TRIANGLE_STRIP, /* mode */ 0, /* first */ 3); /* count */ validate_result (state); } static CoglBool queue_redraw (gpointer stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_vertex_buffer_contiguous (TestUtilsGTestFixture *fixture, void *data) { TestState state; ClutterActor *stage; ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff}; ClutterActor *group; unsigned int idle_source; guchar tex_data[] = { 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr); clutter_actor_get_geometry (stage, &state.stage_geom); group = clutter_group_new (); clutter_actor_set_size (group, state.stage_geom.width, state.stage_geom.height); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); /* We force continuous redrawing incase someone comments out the * clutter_main_quit and wants visual feedback for the test since we * wont be doing anything else that will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); state.texture = cogl_texture_new_from_data (2, 2, COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_ANY, 0, /* auto calc row stride */ tex_data); state.material = cogl_material_new (); cogl_material_set_color4ub (state.material, 0x00, 0xff, 0x00, 0xff); cogl_material_set_layer (state.material, 0, state.texture); { GLfloat triangle_verts[3][2] = { {0.0, 0.0}, {100.0, 100.0}, {0.0, 100.0} }; GLbyte triangle_colors[3][4] = { {0x00, 0x00, 0xff, 0xff}, /* blue */ {0x00, 0x00, 0xff, 0x00}, /* transparent blue */ {0x00, 0x00, 0xff, 0x00} /* transparent blue */ }; GLfloat triangle_tex_coords[3][2] = { {0.0, 0.0}, {1.0, 1.0}, {0.0, 1.0} }; state.buffer = cogl_vertex_buffer_new (3 /* n vertices */); cogl_vertex_buffer_add (state.buffer, "gl_Vertex", 2, /* n components */ GL_FLOAT, FALSE, /* normalized */ 0, /* stride */ triangle_verts); cogl_vertex_buffer_add (state.buffer, "gl_Color::blue", 4, /* n components */ GL_UNSIGNED_BYTE, FALSE, /* normalized */ 0, /* stride */ triangle_colors); cogl_vertex_buffer_add (state.buffer, "gl_MultiTexCoord0", 2, /* n components */ GL_FLOAT, FALSE, /* normalized */ 0, /* stride */ triangle_tex_coords); cogl_vertex_buffer_submit (state.buffer); } clutter_actor_show_all (stage); clutter_main (); cogl_handle_unref (state.buffer); cogl_handle_unref (state.material); cogl_handle_unref (state.texture); g_source_remove (idle_source); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-conform-main.c0000664000175000017500000001203614211404421022375 0ustar jpeisachjpeisach#include "cogl-config.h" #include #include #include #include #include #include "test-utils.h" /* A bit of sugar for adding new conformance tests */ #define ADD_TEST(FUNC, REQUIREMENTS, KNOWN_FAIL_REQUIREMENTS) \ G_STMT_START { \ extern void FUNC (void); \ if (strcmp (#FUNC, argv[1]) == 0) \ { \ test_utils_init (REQUIREMENTS, KNOWN_FAIL_REQUIREMENTS); \ FUNC (); \ test_utils_fini (); \ exit (0); \ } \ } G_STMT_END #define UNPORTED_TEST(FUNC) int main (int argc, char **argv) { int i; if (argc != 2) { g_printerr ("usage %s UNIT_TEST\n", argv[0]); exit (1); } /* Just for convenience in case people try passing the wrapper * filenames for the UNIT_TEST argument we normalize '-' characters * to '_' characters... */ for (i = 0; argv[1][i]; i++) { if (argv[1][i] == '-') argv[1][i] = '_'; } /* This file is run through a sed script during the make step so the * lines containing the tests need to be formatted on a single line * each. */ UNPORTED_TEST (test_object); UNPORTED_TEST (test_fixed); UNPORTED_TEST (test_materials); ADD_TEST (test_pipeline_user_matrix, 0, 0); ADD_TEST (test_blend_strings, 0, 0); ADD_TEST (test_blend, 0, 0); ADD_TEST (test_premult, 0, TEST_KNOWN_FAILURE); UNPORTED_TEST (test_readpixels); #ifdef COGL_HAS_COGL_PATH_SUPPORT ADD_TEST (test_path, 0, 0); ADD_TEST (test_path_clip, 0, 0); #endif ADD_TEST (test_depth_test, 0, 0); ADD_TEST (test_color_mask, 0, 0); ADD_TEST (test_backface_culling, 0, TEST_REQUIREMENT_NPOT); ADD_TEST (test_layer_remove, 0, 0); ADD_TEST (test_sparse_pipeline, 0, 0); ADD_TEST (test_npot_texture, 0, 0); UNPORTED_TEST (test_multitexture); UNPORTED_TEST (test_texture_mipmaps); ADD_TEST (test_sub_texture, 0, 0); ADD_TEST (test_pixel_buffer_map, 0, 0); ADD_TEST (test_pixel_buffer_set_data, 0, 0); ADD_TEST (test_pixel_buffer_sub_region, 0, 0); UNPORTED_TEST (test_texture_rectangle); ADD_TEST (test_texture_3d, TEST_REQUIREMENT_TEXTURE_3D, 0); ADD_TEST (test_wrap_modes, 0, 0); UNPORTED_TEST (test_texture_pixmap_x11); ADD_TEST (test_texture_get_set_data, 0, 0); ADD_TEST (test_atlas_migration, 0, 0); ADD_TEST (test_read_texture_formats, 0, TEST_KNOWN_FAILURE); ADD_TEST (test_write_texture_formats, 0, 0); ADD_TEST (test_alpha_textures, 0, 0); ADD_TEST (test_wrap_rectangle_textures, TEST_REQUIREMENT_TEXTURE_RECTANGLE, TEST_KNOWN_FAILURE); UNPORTED_TEST (test_vertex_buffer_contiguous); UNPORTED_TEST (test_vertex_buffer_interleved); UNPORTED_TEST (test_vertex_buffer_mutability); ADD_TEST (test_primitive, 0, 0); ADD_TEST (test_just_vertex_shader, TEST_REQUIREMENT_GLSL, 0); ADD_TEST (test_pipeline_uniforms, TEST_REQUIREMENT_GLSL, 0); ADD_TEST (test_snippets, TEST_REQUIREMENT_GLSL, 0); ADD_TEST (test_custom_attributes, TEST_REQUIREMENT_GLSL, 0); ADD_TEST (test_offscreen, 0, 0); ADD_TEST (test_framebuffer_get_bits, TEST_REQUIREMENT_OFFSCREEN | TEST_REQUIREMENT_GL, 0); ADD_TEST (test_point_size, 0, 0); ADD_TEST (test_point_size_attribute, TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE, 0); ADD_TEST (test_point_size_attribute_snippet, TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE | TEST_REQUIREMENT_GLSL, 0); ADD_TEST (test_point_sprite, TEST_REQUIREMENT_POINT_SPRITE, 0); ADD_TEST (test_point_sprite_orientation, TEST_REQUIREMENT_POINT_SPRITE, TEST_KNOWN_FAILURE); ADD_TEST (test_point_sprite_glsl, TEST_REQUIREMENT_POINT_SPRITE | TEST_REQUIREMENT_GLSL, 0); ADD_TEST (test_version, 0, 0); ADD_TEST (test_alpha_test, 0, 0); ADD_TEST (test_map_buffer_range, TEST_REQUIREMENT_MAP_WRITE, 0); ADD_TEST (test_primitive_and_journal, 0, 0); ADD_TEST (test_copy_replace_texture, 0, 0); ADD_TEST (test_pipeline_cache_unrefs_texture, 0, 0); ADD_TEST (test_pipeline_shader_state, TEST_REQUIREMENT_GLSL, 0); UNPORTED_TEST (test_viewport); ADD_TEST (test_gles2_context, TEST_REQUIREMENT_GLES2_CONTEXT, 0); ADD_TEST (test_gles2_context_fbo, TEST_REQUIREMENT_GLES2_CONTEXT, 0); ADD_TEST (test_gles2_context_copy_tex_image, TEST_REQUIREMENT_GLES2_CONTEXT, 0); ADD_TEST (test_euler_quaternion, 0, 0); ADD_TEST (test_color_hsl, 0, 0); ADD_TEST (test_fence, TEST_REQUIREMENT_FENCE, 0); ADD_TEST (test_texture_no_allocate, 0, 0); ADD_TEST (test_texture_rg, TEST_REQUIREMENT_TEXTURE_RG, 0); g_printerr ("Unknown test name \"%s\"\n", argv[1]); return 1; } muffin-5.2.1/cogl/tests/conform/test-map-buffer-range.c0000664000175000017500000001001114211404421023115 0ustar jpeisachjpeisach#include #include #include "test-utils.h" static uint8_t tex_data[2 * 2 * 4] = { 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff }; /* Vertex data for a quad with all of the texture coordinates set to * the top left (red) pixel */ static CoglVertexP2T2 vertex_data[4] = { { -1, -1, 0, 0 }, { 1, -1, 0, 0 }, { -1, 1, 0, 0 }, { 1, 1, 0, 0 } }; void test_map_buffer_range (void) { CoglTexture2D *tex; CoglPipeline *pipeline; int fb_width, fb_height; CoglAttributeBuffer *buffer; CoglVertexP2T2 *data; CoglAttribute *pos_attribute; CoglAttribute *tex_coord_attribute; CoglPrimitive *primitive; tex = cogl_texture_2d_new_from_data (test_ctx, 2, 2, /* width/height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 2 * 4, /* rowstride */ tex_data, NULL /* error */); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, tex); cogl_pipeline_set_layer_filters (pipeline, 0, /* layer */ COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_layer_wrap_mode (pipeline, 0, /* layer */ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); fb_width = cogl_framebuffer_get_width (test_fb); fb_height = cogl_framebuffer_get_height (test_fb); buffer = cogl_attribute_buffer_new (test_ctx, sizeof (vertex_data), vertex_data); /* Replace the texture coordinates of the third vertex with the * coordinates for a green texel */ data = cogl_buffer_map_range (buffer, sizeof (vertex_data[0]) * 2, sizeof (vertex_data[0]), COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD_RANGE, NULL); /* don't catch errors */ g_assert (data != NULL); data->x = vertex_data[2].x; data->y = vertex_data[2].y; data->s = 1.0f; data->t = 0.0f; cogl_buffer_unmap (buffer); pos_attribute = cogl_attribute_new (buffer, "cogl_position_in", sizeof (vertex_data[0]), offsetof (CoglVertexP2T2, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); tex_coord_attribute = cogl_attribute_new (buffer, "cogl_tex_coord_in", sizeof (vertex_data[0]), offsetof (CoglVertexP2T2, s), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1); primitive = cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLE_STRIP, 4, /* n_vertices */ pos_attribute, tex_coord_attribute, NULL); cogl_primitive_draw (primitive, test_fb, pipeline); cogl_object_unref (primitive); /* Top left pixel should be the one that is replaced to be green */ test_utils_check_pixel (test_fb, 1, 1, 0x00ff00ff); /* The other three corners should be left as red */ test_utils_check_pixel (test_fb, fb_width - 2, 1, 0xff0000ff); test_utils_check_pixel (test_fb, 1, fb_height - 2, 0xff0000ff); test_utils_check_pixel (test_fb, fb_width - 2, fb_height - 2, 0xff0000ff); cogl_object_unref (buffer); cogl_object_unref (pos_attribute); cogl_object_unref (tex_coord_attribute); cogl_object_unref (pipeline); cogl_object_unref (tex); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-npot-texture.c0000664000175000017500000001224314211404421022466 0ustar jpeisachjpeisach#include #include #include "test-utils.h" /* Non-power-of-two sized texture that should cause slicing */ #define TEXTURE_SIZE 384 /* Number of times to split the texture up on each axis */ #define PARTS 2 /* The texture is split into four parts, each with a different colour */ #define PART_SIZE (TEXTURE_SIZE / PARTS) /* Amount of pixels to skip off the top, bottom, left and right of the texture when reading back the stage */ #define TEST_INSET 4 /* Size to actually render the texture at */ #define TEXTURE_RENDER_SIZE TEXTURE_SIZE /* The size of a part once rendered */ #define PART_RENDER_SIZE (TEXTURE_RENDER_SIZE / PARTS) static const uint32_t corner_colors[PARTS * PARTS] = { /* Top left - red */ 0xff0000ff, /* Top right - green */ 0x00ff00ff, /* Bottom left - blue */ 0x0000ffff, /* Bottom right - yellow */ 0xffff00ff }; static void validate_part (int xnum, int ynum, uint32_t color) { test_utils_check_region (test_fb, xnum * PART_RENDER_SIZE + TEST_INSET, ynum * PART_RENDER_SIZE + TEST_INSET, PART_RENDER_SIZE - TEST_INSET * 2, PART_RENDER_SIZE - TEST_INSET * 2, color); } static void validate_result (void) { /* Validate that all four corners of the texture are drawn in the right color */ validate_part (0, 0, corner_colors[0]); validate_part (1, 0, corner_colors[1]); validate_part (0, 1, corner_colors[2]); validate_part (1, 1, corner_colors[3]); } static CoglTexture * make_texture (void) { void *tex_data; uint32_t *p; CoglTexture *tex; int partx, party, width, height; p = tex_data = malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4); /* Make a texture with a different color for each part */ for (party = 0; party < PARTS; party++) { height = (party < PARTS - 1 ? PART_SIZE : TEXTURE_SIZE - PART_SIZE * (PARTS - 1)); for (partx = 0; partx < PARTS; partx++) { uint32_t color = corner_colors[party * PARTS + partx]; width = (partx < PARTS - 1 ? PART_SIZE : TEXTURE_SIZE - PART_SIZE * (PARTS - 1)); while (width-- > 0) *(p++) = GUINT32_TO_BE (color); } while (--height > 0) { memcpy (p, p - TEXTURE_SIZE, TEXTURE_SIZE * 4); p += TEXTURE_SIZE; } } tex = test_utils_texture_new_from_data (test_ctx, TEXTURE_SIZE, TEXTURE_SIZE, TEST_UTILS_TEXTURE_NO_ATLAS, COGL_PIXEL_FORMAT_RGBA_8888_PRE, TEXTURE_SIZE * 4, tex_data); free (tex_data); if (cogl_test_verbose ()) { if (cogl_texture_is_sliced (tex)) g_print ("Texture is sliced\n"); else g_print ("Texture is not sliced\n"); } /* The texture should be sliced unless NPOTs are supported */ g_assert (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT) ? !cogl_texture_is_sliced (tex) : cogl_texture_is_sliced (tex)); return tex; } static void paint (void) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglTexture *texture = make_texture (); int y, x; cogl_pipeline_set_layer_texture (pipeline, 0, texture); /* Just render the texture in the top left corner */ /* Render the texture using four separate rectangles */ for (y = 0; y < 2; y++) for (x = 0; x < 2; x++) cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline, x * TEXTURE_RENDER_SIZE / 2, y * TEXTURE_RENDER_SIZE / 2, (x + 1) * TEXTURE_RENDER_SIZE / 2, (y + 1) * TEXTURE_RENDER_SIZE / 2, x / 2.0f, y / 2.0f, (x + 1) / 2.0f, (y + 1) / 2.0f); cogl_object_unref (pipeline); cogl_object_unref (texture); } void test_npot_texture (void) { if (cogl_test_verbose ()) { if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT)) g_print ("NPOT textures are supported\n"); else g_print ("NPOT textures are not supported\n"); } cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); paint (); validate_result (); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-point-sprite.c0000664000175000017500000001462114211404421022447 0ustar jpeisachjpeisach#include #include "test-utils.h" #define POINT_SIZE 8 static const CoglVertexP2T2 point = { POINT_SIZE, POINT_SIZE, 0.0f, 0.0f }; static const uint8_t tex_data[3 * 2 * 2] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00 }; static void do_test (CoglBool check_orientation, CoglBool use_glsl) { int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); CoglPrimitive *prim; CoglError *error = NULL; CoglTexture2D *tex_2d; CoglPipeline *pipeline, *solid_pipeline; int tex_height; cogl_framebuffer_orthographic (test_fb, 0, 0, /* x_1, y_1 */ fb_width, /* x_2 */ fb_height /* y_2 */, -1, 100 /* near/far */); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1.0f, 1.0f, 1.0f, 1.0f); /* If we're not checking the orientation of the point sprite then * we'll set the height of the texture to 1 so that the vertical * orientation does not matter */ if (check_orientation) tex_height = 2; else tex_height = 1; tex_2d = cogl_texture_2d_new_from_data (test_ctx, 2, tex_height, /* width/height */ COGL_PIXEL_FORMAT_RGB_888, 6, /* row stride */ tex_data, &error); g_assert (tex_2d != NULL); g_assert (error == NULL); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, tex_2d); cogl_pipeline_set_layer_filters (pipeline, 0, /* layer_index */ COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); cogl_pipeline_set_point_size (pipeline, POINT_SIZE); /* If we're using GLSL then we don't need to enable point sprite * coords and we can just directly reference cogl_point_coord in the * snippet */ if (use_glsl) { CoglSnippet *snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, NULL, /* declarations */ NULL /* post */); static const char source[] = " cogl_texel = texture2D (cogl_sampler, cogl_point_coord);\n"; cogl_snippet_set_replace (snippet, source); /* Keep a reference to the original pipeline because there is no * way to remove a snippet in order to recreate the solid * pipeline */ solid_pipeline = cogl_pipeline_copy (pipeline); cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_object_unref (snippet); } else { CoglBool res = cogl_pipeline_set_layer_point_sprite_coords_enabled (pipeline, /* layer_index */ 0, /* enable */ TRUE, &error); g_assert (res == TRUE); g_assert (error == NULL); solid_pipeline = cogl_pipeline_copy (pipeline); res = cogl_pipeline_set_layer_point_sprite_coords_enabled (solid_pipeline, /* layer_index */ 0, /* enable */ FALSE, &error); g_assert (res == TRUE); g_assert (error == NULL); } prim = cogl_primitive_new_p2t2 (test_ctx, COGL_VERTICES_MODE_POINTS, 1, /* n_vertices */ &point); cogl_primitive_draw (prim, test_fb, pipeline); /* Render the primitive again without point sprites to make sure disabling it works */ cogl_framebuffer_push_matrix (test_fb); cogl_framebuffer_translate (test_fb, POINT_SIZE * 2, /* x */ 0.0f, /* y */ 0.0f /* z */); cogl_primitive_draw (prim, test_fb, solid_pipeline); cogl_framebuffer_pop_matrix (test_fb); cogl_object_unref (prim); cogl_object_unref (solid_pipeline); cogl_object_unref (pipeline); cogl_object_unref (tex_2d); test_utils_check_pixel (test_fb, POINT_SIZE - POINT_SIZE / 4, POINT_SIZE - POINT_SIZE / 4, 0x0000ffff); test_utils_check_pixel (test_fb, POINT_SIZE + POINT_SIZE / 4, POINT_SIZE - POINT_SIZE / 4, 0x00ff00ff); test_utils_check_pixel (test_fb, POINT_SIZE - POINT_SIZE / 4, POINT_SIZE + POINT_SIZE / 4, check_orientation ? 0x00ffffff : 0x0000ffff); test_utils_check_pixel (test_fb, POINT_SIZE + POINT_SIZE / 4, POINT_SIZE + POINT_SIZE / 4, check_orientation ? 0xff0000ff : 0x00ff00ff); /* When rendering without the point sprites all of the texture coordinates should be 0,0 so it should get the top-left texel which is blue */ test_utils_check_region (test_fb, POINT_SIZE * 3 - POINT_SIZE / 2 + 1, POINT_SIZE - POINT_SIZE / 2 + 1, POINT_SIZE - 2, POINT_SIZE - 2, 0x0000ffff); if (cogl_test_verbose ()) g_print ("OK\n"); } void test_point_sprite (void) { do_test (FALSE /* don't check orientation */, FALSE /* don't use GLSL */); } void test_point_sprite_orientation (void) { do_test (TRUE /* check orientation */, FALSE /* don't use GLSL */); } void test_point_sprite_glsl (void) { do_test (FALSE /* don't check orientation */, TRUE /* use GLSL */); } muffin-5.2.1/cogl/tests/conform/test-point-size-attribute.c0000664000175000017500000001217614211404421024117 0ustar jpeisachjpeisach#include #include "test-utils.h" /* This test assumes the GL driver supports point sizes up to 16 pixels. Cogl should probably have some way of querying the size so we start from that instead */ #define MAX_POINT_SIZE 16 #define MIN_POINT_SIZE 4 #define N_POINTS (MAX_POINT_SIZE - MIN_POINT_SIZE + 1) /* The size of the area that we'll paint each point in */ #define POINT_BOX_SIZE (MAX_POINT_SIZE * 2) typedef struct { float x, y; float point_size; } PointVertex; static int calc_coord_offset (int pos, int pos_index, int point_size) { switch (pos_index) { case 0: return pos - point_size / 2 - 2; case 1: return pos - point_size / 2 + 2; case 2: return pos + point_size / 2 - 2; case 3: return pos + point_size / 2 + 2; } g_assert_not_reached (); } static void verify_point_size (CoglFramebuffer *test_fb, int x_pos, int y_pos, int point_size) { int y, x; for (y = 0; y < 4; y++) for (x = 0; x < 4; x++) { CoglBool in_point = x >= 1 && x <= 2 && y >= 1 && y <= 2; uint32_t expected_pixel = in_point ? 0x00ff00ff : 0xff0000ff; test_utils_check_pixel (test_fb, calc_coord_offset (x_pos, x, point_size), calc_coord_offset (y_pos, y, point_size), expected_pixel); } } static CoglPrimitive * create_primitive (const char *attribute_name) { PointVertex vertices[N_POINTS]; CoglAttributeBuffer *buffer; CoglAttribute *attributes[2]; CoglPrimitive *prim; int i; for (i = 0; i < N_POINTS; i++) { vertices[i].x = i * POINT_BOX_SIZE + POINT_BOX_SIZE / 2; vertices[i].y = POINT_BOX_SIZE / 2; vertices[i].point_size = MAX_POINT_SIZE - i; } buffer = cogl_attribute_buffer_new (test_ctx, sizeof (vertices), vertices); attributes[0] = cogl_attribute_new (buffer, "cogl_position_in", sizeof (PointVertex), G_STRUCT_OFFSET (PointVertex, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (buffer, attribute_name, sizeof (PointVertex), G_STRUCT_OFFSET (PointVertex, point_size), 1, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); prim = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_POINTS, N_POINTS, attributes, 2 /* n_attributes */); for (i = 0; i < 2; i++) cogl_object_unref (attributes[i]); return prim; } static void do_test (const char *attribute_name, void (* pipeline_setup_func) (CoglPipeline *pipeline)) { int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); CoglPrimitive *primitive; CoglPipeline *pipeline; int i; cogl_framebuffer_orthographic (test_fb, 0, 0, /* x_1, y_1 */ fb_width, /* x_2 */ fb_height /* y_2 */, -1, 100 /* near/far */); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1.0f, 0.0f, 0.0f, 1.0f); primitive = create_primitive (attribute_name); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_color4ub (pipeline, 0x00, 0xff, 0x00, 0xff); cogl_pipeline_set_per_vertex_point_size (pipeline, TRUE, NULL); if (pipeline_setup_func) pipeline_setup_func (pipeline); cogl_primitive_draw (primitive, test_fb, pipeline); cogl_object_unref (pipeline); cogl_object_unref (primitive); /* Verify all of the points where drawn at the right size */ for (i = 0; i < N_POINTS; i++) verify_point_size (test_fb, i * POINT_BOX_SIZE + POINT_BOX_SIZE / 2, /* x */ POINT_BOX_SIZE / 2, /* y */ MAX_POINT_SIZE - i /* point size */); if (cogl_test_verbose ()) g_print ("OK\n"); } void test_point_size_attribute (void) { do_test ("cogl_point_size_in", NULL); } static void setup_snippet (CoglPipeline *pipeline) { CoglSnippet *snippet; snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_POINT_SIZE, "attribute float " "my_super_duper_point_size_attrib;\n", NULL); cogl_snippet_set_replace (snippet, "cogl_point_size_out = " "my_super_duper_point_size_attrib;\n"); cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); } void test_point_size_attribute_snippet (void) { do_test ("my_super_duper_point_size_attrib", setup_snippet); } muffin-5.2.1/cogl/tests/conform/test-read-texture-formats.c0000664000175000017500000001441514211404421024075 0ustar jpeisachjpeisach#include #include #include "test-utils.h" /* * This tests reading back an RGBA texture in all of the available * pixel formats */ static const uint8_t tex_data[4] = { 0x12, 0x34, 0x56, 0x78 }; static void test_read_byte (CoglTexture2D *tex_2d, CoglPixelFormat format, uint8_t expected_byte) { uint8_t received_byte; cogl_texture_get_data (tex_2d, format, 1, /* rowstride */ &received_byte); g_assert_cmpint (expected_byte, ==, received_byte); } static void test_read_short (CoglTexture2D *tex_2d, CoglPixelFormat format, ...) { va_list ap; int bits; uint16_t received_value; uint16_t expected_value = 0; char *received_value_str; char *expected_value_str; int bits_sum = 0; cogl_texture_get_data (tex_2d, format, 2, /* rowstride */ (uint8_t *) &received_value); va_start (ap, format); /* Convert the va args into a single 16-bit expected value */ while ((bits = va_arg (ap, int)) != -1) { int value = (va_arg (ap, int) * ((1 << bits) - 1) + 128) / 255; bits_sum += bits; expected_value |= value << (16 - bits_sum); } va_end (ap); received_value_str = g_strdup_printf ("0x%04x", received_value); expected_value_str = g_strdup_printf ("0x%04x", expected_value); g_assert_cmpstr (received_value_str, ==, expected_value_str); free (received_value_str); free (expected_value_str); } static void test_read_888 (CoglTexture2D *tex_2d, CoglPixelFormat format, uint32_t expected_pixel) { uint8_t pixel[4]; cogl_texture_get_data (tex_2d, format, 4, /* rowstride */ pixel); test_utils_compare_pixel (pixel, expected_pixel); } static void test_read_88 (CoglTexture2D *tex_2d, CoglPixelFormat format, uint32_t expected_pixel) { uint8_t pixel[4]; pixel[2] = 0x00; cogl_texture_get_data (tex_2d, format, 2, /* rowstride */ pixel); test_utils_compare_pixel (pixel, expected_pixel); } static void test_read_8888 (CoglTexture2D *tex_2d, CoglPixelFormat format, uint32_t expected_pixel) { uint32_t received_pixel; char *received_value_str; char *expected_value_str; cogl_texture_get_data (tex_2d, format, 4, /* rowstride */ (uint8_t *) &received_pixel); received_pixel = GUINT32_FROM_BE (received_pixel); received_value_str = g_strdup_printf ("0x%08x", received_pixel); expected_value_str = g_strdup_printf ("0x%08x", expected_pixel); g_assert_cmpstr (received_value_str, ==, expected_value_str); free (received_value_str); free (expected_value_str); } static void test_read_int (CoglTexture2D *tex_2d, CoglPixelFormat format, ...) { va_list ap; int bits; uint32_t received_value; uint32_t expected_value = 0; char *received_value_str; char *expected_value_str; int bits_sum = 0; cogl_texture_get_data (tex_2d, format, 4, /* rowstride */ (uint8_t *) &received_value); va_start (ap, format); /* Convert the va args into a single 32-bit expected value */ while ((bits = va_arg (ap, int)) != -1) { uint32_t value = (va_arg (ap, int) * ((1 << bits) - 1) + 128) / 255; bits_sum += bits; expected_value |= value << (32 - bits_sum); } va_end (ap); received_value_str = g_strdup_printf ("0x%08x", received_value); expected_value_str = g_strdup_printf ("0x%08x", expected_value); g_assert_cmpstr (received_value_str, ==, expected_value_str); free (received_value_str); free (expected_value_str); } void test_read_texture_formats (void) { CoglTexture2D *tex_2d; tex_2d = cogl_texture_2d_new_from_data (test_ctx, 1, 1, /* width / height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ tex_data, NULL); test_read_byte (tex_2d, COGL_PIXEL_FORMAT_A_8, 0x78); #if 0 /* I'm not sure what's the right value to put here because Nvidia and Mesa seem to behave differently so one of them must be wrong. */ test_read_byte (tex_2d, COGL_PIXEL_FORMAT_G_8, 0x9c); #endif /* We should always be able to read into an RG buffer regardless of * whether RG textures are supported because Cogl will do the * conversion for us */ test_read_88 (tex_2d, COGL_PIXEL_FORMAT_RG_88, 0x123400ff); test_read_short (tex_2d, COGL_PIXEL_FORMAT_RGB_565, 5, 0x12, 6, 0x34, 5, 0x56, -1); test_read_short (tex_2d, COGL_PIXEL_FORMAT_RGBA_4444_PRE, 4, 0x12, 4, 0x34, 4, 0x56, 4, 0x78, -1); test_read_short (tex_2d, COGL_PIXEL_FORMAT_RGBA_5551_PRE, 5, 0x12, 5, 0x34, 5, 0x56, 1, 0x78, -1); test_read_888 (tex_2d, COGL_PIXEL_FORMAT_RGB_888, 0x123456ff); test_read_888 (tex_2d, COGL_PIXEL_FORMAT_BGR_888, 0x563412ff); test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0x12345678); test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_BGRA_8888_PRE, 0x56341278); test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_ARGB_8888_PRE, 0x78123456); test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_ABGR_8888_PRE, 0x78563412); test_read_int (tex_2d, COGL_PIXEL_FORMAT_RGBA_1010102_PRE, 10, 0x12, 10, 0x34, 10, 0x56, 2, 0x78, -1); test_read_int (tex_2d, COGL_PIXEL_FORMAT_BGRA_1010102_PRE, 10, 0x56, 10, 0x34, 10, 0x12, 2, 0x78, -1); test_read_int (tex_2d, COGL_PIXEL_FORMAT_ARGB_2101010_PRE, 2, 0x78, 10, 0x12, 10, 0x34, 10, 0x56, -1); test_read_int (tex_2d, COGL_PIXEL_FORMAT_ABGR_2101010_PRE, 2, 0x78, 10, 0x56, 10, 0x34, 10, 0x12, -1); cogl_object_unref (tex_2d); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-blend.c0000664000175000017500000000371014211404421021073 0ustar jpeisachjpeisach#include #include #include "test-utils.h" static void paint (void) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); int width = cogl_framebuffer_get_width (test_fb); int half_width = width / 2; int height = cogl_framebuffer_get_height (test_fb); CoglVertexP2 tri0_vertices[] = { { 0, 0 }, { 0, height }, { half_width, height }, }; CoglVertexP2C4 tri1_vertices[] = { { half_width, 0, 0x80, 0x80, 0x80, 0x80 }, { half_width, height, 0x80, 0x80, 0x80, 0x80 }, { width, height, 0x80, 0x80, 0x80, 0x80 }, }; CoglPrimitive *tri0; CoglPrimitive *tri1; cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 0); tri0 = cogl_primitive_new_p2 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, tri0_vertices); tri1 = cogl_primitive_new_p2c4 (test_ctx, COGL_VERTICES_MODE_TRIANGLES, 3, tri1_vertices); /* Check that cogl correctly handles the case where we draw * different primitives same pipeline and switch from using the * opaque color associated with the pipeline and using a colour * attribute with an alpha component which implies blending is * required. * * If Cogl gets this wrong then then in all likelyhood the second * primitive will be drawn with blending still disabled. */ cogl_primitive_draw (tri0, test_fb, pipeline); cogl_primitive_draw (tri1, test_fb, pipeline); test_utils_check_pixel_and_alpha (test_fb, half_width + 5, height - 5, 0x80808080); } void test_blend (void) { cogl_framebuffer_orthographic (test_fb, 0, 0, cogl_framebuffer_get_width (test_fb), cogl_framebuffer_get_height (test_fb), -1, 100); paint (); } muffin-5.2.1/cogl/tests/conform/test-point-size.c0000664000175000017500000000602514211404421022112 0ustar jpeisachjpeisach#include #include "test-utils.h" /* This test assumes the GL driver supports point sizes up to 16 pixels. Cogl should probably have some way of querying the size so we start from that instead */ #define MAX_POINT_SIZE 16 /* The size of the area that we'll paint each point in */ #define POINT_BOX_SIZE (MAX_POINT_SIZE * 2) static int calc_coord_offset (int pos, int pos_index, int point_size) { switch (pos_index) { case 0: return pos - point_size / 2 - 2; case 1: return pos - point_size / 2 + 2; case 2: return pos + point_size / 2 - 2; case 3: return pos + point_size / 2 + 2; } g_assert_not_reached (); } static void verify_point_size (CoglFramebuffer *test_fb, int x_pos, int y_pos, int point_size) { int y, x; for (y = 0; y < 4; y++) for (x = 0; x < 4; x++) { CoglBool in_point = x >= 1 && x <= 2 && y >= 1 && y <= 2; uint32_t expected_pixel = in_point ? 0x00ff00ff : 0xff0000ff; test_utils_check_pixel (test_fb, calc_coord_offset (x_pos, x, point_size), calc_coord_offset (y_pos, y, point_size), expected_pixel); } } void test_point_size (void) { int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); int point_size; int x_pos; cogl_framebuffer_orthographic (test_fb, 0, 0, /* x_1, y_1 */ fb_width, /* x_2 */ fb_height /* y_2 */, -1, 100 /* near/far */); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1.0f, 0.0f, 0.0f, 1.0f); /* Try a rendering a single point with a few different point sizes */ for (x_pos = 0, point_size = MAX_POINT_SIZE; point_size >= 4; x_pos += POINT_BOX_SIZE, point_size /= 2) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglVertexP2 point = { x_pos + POINT_BOX_SIZE / 2, POINT_BOX_SIZE / 2 }; CoglPrimitive *prim = cogl_primitive_new_p2 (test_ctx, COGL_VERTICES_MODE_POINTS, 1, /* n_vertices */ &point); cogl_pipeline_set_point_size (pipeline, point_size); cogl_pipeline_set_color4ub (pipeline, 0, 255, 0, 255); cogl_primitive_draw (prim, test_fb, pipeline); cogl_object_unref (prim); cogl_object_unref (pipeline); } /* Verify all of the points where drawn at the right size */ for (x_pos = 0, point_size = MAX_POINT_SIZE; point_size >= 4; x_pos += POINT_BOX_SIZE, point_size /= 2) verify_point_size (test_fb, x_pos + POINT_BOX_SIZE / 2, POINT_BOX_SIZE / 2, point_size); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-fence.c0000664000175000017500000000302014211404421021061 0ustar jpeisachjpeisach#include #include "test-utils.h" #include "cogl-config.h" /* I'm writing this on the train after having dinner at a churrascuria. */ #define MAGIC_CHUNK_O_DATA ((void *) 0xdeadbeef) static GMainLoop *loop; gboolean timeout (void *user_data) { g_assert (!"timeout not reached"); return FALSE; } void callback (CoglFence *fence, void *user_data) { int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); test_utils_check_pixel (test_fb, fb_width - 1, fb_height - 1, 0x00ff0000); g_assert (user_data == MAGIC_CHUNK_O_DATA && "callback data not mangled"); g_main_loop_quit (loop); } void test_fence (void) { GSource *cogl_source; int fb_width = cogl_framebuffer_get_width (test_fb); int fb_height = cogl_framebuffer_get_height (test_fb); CoglFenceClosure *closure; cogl_source = cogl_glib_source_new (test_ctx, G_PRIORITY_DEFAULT); g_source_attach (cogl_source, NULL); loop = g_main_loop_new (NULL, TRUE); cogl_framebuffer_orthographic (test_fb, 0, 0, fb_width, fb_height, -1, 100); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0.0f, 1.0f, 0.0f, 0.0f); closure = cogl_framebuffer_add_fence_callback (test_fb, callback, MAGIC_CHUNK_O_DATA); g_assert (closure != NULL); g_timeout_add_seconds (5, timeout, NULL); g_main_loop_run (loop); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-version.c0000664000175000017500000000733614211404421021504 0ustar jpeisachjpeisach#include #include "test-utils.h" #include "cogl-config.h" /* So we can use _COGL_STATIC_ASSERT we include the internal * cogl-util.h header. Since internal headers explicitly guard against * applications including them directly instead of including * we define __COGL_H_INSIDE__ here to subvert those * guards in this case... */ #define __COGL_H_INSIDE__ #include #undef __COGL_H_INSIDE__ _COGL_STATIC_ASSERT (COGL_VERSION_ENCODE (COGL_VERSION_MAJOR, COGL_VERSION_MINOR, COGL_VERSION_MICRO) == COGL_VERSION, "The pre-encoded Cogl version does not match the version " "encoding macro"); _COGL_STATIC_ASSERT (COGL_VERSION_GET_MAJOR (COGL_VERSION_ENCODE (100, 200, 300)) == 100, "Getting the major component out of a encoded version " "does not work"); _COGL_STATIC_ASSERT (COGL_VERSION_GET_MINOR (COGL_VERSION_ENCODE (100, 200, 300)) == 200, "Getting the minor component out of a encoded version " "does not work"); _COGL_STATIC_ASSERT (COGL_VERSION_GET_MICRO (COGL_VERSION_ENCODE (100, 200, 300)) == 300, "Getting the micro component out of a encoded version " "does not work"); _COGL_STATIC_ASSERT (COGL_VERSION_CHECK (COGL_VERSION_MAJOR, COGL_VERSION_MINOR, COGL_VERSION_MICRO), "Checking the Cogl version against the current version " "does not pass"); _COGL_STATIC_ASSERT (!COGL_VERSION_CHECK (COGL_VERSION_MAJOR, COGL_VERSION_MINOR, COGL_VERSION_MICRO + 1), "Checking the Cogl version against a later micro version " "should not pass"); _COGL_STATIC_ASSERT (!COGL_VERSION_CHECK (COGL_VERSION_MAJOR, COGL_VERSION_MINOR + 1, COGL_VERSION_MICRO), "Checking the Cogl version against a later minor version " "should not pass"); _COGL_STATIC_ASSERT (!COGL_VERSION_CHECK (COGL_VERSION_MAJOR + 1, COGL_VERSION_MINOR, COGL_VERSION_MICRO), "Checking the Cogl version against a later major version " "should not pass"); _COGL_STATIC_ASSERT (COGL_VERSION_CHECK (COGL_VERSION_MAJOR - 1, COGL_VERSION_MINOR, COGL_VERSION_MICRO), "Checking the Cogl version against a older major version " "should pass"); void test_version (void) { const char *version = g_strdup_printf ("version = %i.%i.%i", COGL_VERSION_MAJOR, COGL_VERSION_MINOR, COGL_VERSION_MICRO); g_assert_cmpstr (version, ==, "version = " COGL_VERSION_STRING); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-multitexture.c0000664000175000017500000001324514211404421022566 0ustar jpeisachjpeisach#include #include #include #include "test-conform-common.h" static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; #define QUAD_WIDTH 20 #define RED 0 #define GREEN 1 #define BLUE 2 #define ALPHA 3 typedef struct _TestState { unsigned int padding; } TestState; static void assert_region_color (int x, int y, int width, int height, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { uint8_t *data = calloc (1, width * height * 4); cogl_read_pixels (x, y, width, height, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, data); for (y = 0; y < height; y++) for (x = 0; x < width; x++) { uint8_t *pixel = &data[y * width * 4 + x * 4]; #if 1 g_assert (pixel[RED] == red && pixel[GREEN] == green && pixel[BLUE] == blue); #endif } free (data); } /* Creates a texture divided into 4 quads with colors arranged as follows: * (The same value are used in all channels for each texel) * * |-----------| * |0x11 |0x00 | * |+ref | | * |-----------| * |0x00 |0x33 | * | |+ref | * |-----------| * * */ static CoglHandle make_texture (guchar ref) { int x; int y; guchar *tex_data, *p; CoglHandle tex; guchar val; tex_data = malloc (QUAD_WIDTH * QUAD_WIDTH * 16); for (y = 0; y < QUAD_WIDTH * 2; y++) for (x = 0; x < QUAD_WIDTH * 2; x++) { p = tex_data + (QUAD_WIDTH * 8 * y) + x * 4; if (x < QUAD_WIDTH && y < QUAD_WIDTH) val = 0x11 + ref; else if (x >= QUAD_WIDTH && y >= QUAD_WIDTH) val = 0x33 + ref; else val = 0x00; p[0] = p[1] = p[2] = p[3] = val; } /* Note: we don't use COGL_PIXEL_FORMAT_ANY for the internal format here * since we don't want to allow Cogl to premultiply our data. */ tex = test_utils_texture_new_from_data (QUAD_WIDTH * 2, QUAD_WIDTH * 2, TEST_UTILS_TEXTURE_NONE, COGL_PIXEL_FORMAT_RGBA_8888, COGL_PIXEL_FORMAT_RGBA_8888, QUAD_WIDTH * 8, tex_data); free (tex_data); return tex; } static void on_paint (ClutterActor *actor, TestState *state) { CoglHandle tex0, tex1; CoglHandle material; CoglBool status; CoglError *error = NULL; float tex_coords[] = { 0, 0, 0.5, 0.5, /* tex0 */ 0.5, 0.5, 1, 1 /* tex1 */ }; tex0 = make_texture (0x00); tex1 = make_texture (0x11); material = cogl_material_new (); /* An arbitrary color which should be replaced by the first texture layer */ cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80); cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_material_set_layer (material, 0, tex0); cogl_material_set_layer_combine (material, 0, "RGBA = REPLACE (TEXTURE)", NULL); /* We'll use nearest filtering mode on the textures, otherwise the edge of the quad can pull in texels from the neighbouring quarters of the texture due to imprecision */ cogl_material_set_layer_filters (material, 0, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_material_set_layer (material, 1, tex1); cogl_material_set_layer_filters (material, 1, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); status = cogl_material_set_layer_combine (material, 1, "RGBA = ADD (PREVIOUS, TEXTURE)", &error); if (!status) { /* It's not strictly a test failure; you need a more capable GPU or * driver to test this texture combine string. */ g_debug ("Failed to setup texture combine string " "RGBA = ADD (PREVIOUS, TEXTURE): %s", error->message); } cogl_set_source (material); cogl_rectangle_with_multitexture_coords (0, 0, QUAD_WIDTH, QUAD_WIDTH, tex_coords, 8); cogl_handle_unref (material); cogl_handle_unref (tex0); cogl_handle_unref (tex1); /* See what we got... */ assert_region_color (0, 0, QUAD_WIDTH, QUAD_WIDTH, 0x55, 0x55, 0x55, 0x55); /* Comment this out if you want visual feedback for what this test paints */ #if 1 clutter_main_quit (); #endif } static CoglBool queue_redraw (void *stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } void test_multitexture (TestUtilsGTestFixture *fixture, void *data) { TestState state; ClutterActor *stage; ClutterActor *group; unsigned int idle_source; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); group = clutter_group_new (); clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); /* We force continuous redrawing incase someone comments out the * clutter_main_quit and wants visual feedback for the test since we * wont be doing anything else that will trigger redrawing. */ idle_source = g_idle_add (queue_redraw, stage); g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); clutter_actor_show_all (stage); clutter_main (); g_source_remove (idle_source); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/tests/conform/test-texture-pixmap-x11.c0000664000175000017500000001540714211404421023420 0ustar jpeisachjpeisach#include #include "test-conform-common.h" static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; #ifdef COGL_HAS_XLIB #include #include #define PIXMAP_WIDTH 512 #define PIXMAP_HEIGHT 256 #define GRID_SQUARE_SIZE 16 /* Coordinates of a square that we'll update */ #define PIXMAP_CHANGE_X 1 #define PIXMAP_CHANGE_Y 1 typedef struct _TestState { ClutterActor *stage; CoglHandle tfp; Pixmap pixmap; unsigned int frame_count; Display *display; } TestState; static Pixmap create_pixmap (TestState *state) { Pixmap pixmap; XGCValues gc_values = { 0, }; GC black_gc, white_gc; int screen = DefaultScreen (state->display); int x, y; pixmap = XCreatePixmap (state->display, DefaultRootWindow (state->display), PIXMAP_WIDTH, PIXMAP_HEIGHT, DefaultDepth (state->display, screen)); gc_values.foreground = BlackPixel (state->display, screen); black_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values); gc_values.foreground = WhitePixel (state->display, screen); white_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values); /* Draw a grid of alternative black and white rectangles to the pixmap */ for (y = 0; y < PIXMAP_HEIGHT / GRID_SQUARE_SIZE; y++) for (x = 0; x < PIXMAP_WIDTH / GRID_SQUARE_SIZE; x++) XFillRectangle (state->display, pixmap, ((x ^ y) & 1) ? black_gc : white_gc, x * GRID_SQUARE_SIZE, y * GRID_SQUARE_SIZE, GRID_SQUARE_SIZE, GRID_SQUARE_SIZE); XFreeGC (state->display, black_gc); XFreeGC (state->display, white_gc); return pixmap; } static void update_pixmap (TestState *state) { XGCValues gc_values = { 0, }; GC black_gc; int screen = DefaultScreen (state->display); gc_values.foreground = BlackPixel (state->display, screen); black_gc = XCreateGC (state->display, state->pixmap, GCForeground, &gc_values); /* Fill in one the rectangles with black */ XFillRectangle (state->display, state->pixmap, black_gc, PIXMAP_CHANGE_X * GRID_SQUARE_SIZE, PIXMAP_CHANGE_Y * GRID_SQUARE_SIZE, GRID_SQUARE_SIZE, GRID_SQUARE_SIZE); XFreeGC (state->display, black_gc); } static CoglBool check_paint (TestState *state, int x, int y, int scale) { uint8_t *data, *p, update_value = 0; p = data = malloc (PIXMAP_WIDTH * PIXMAP_HEIGHT * 4); cogl_read_pixels (x, y, PIXMAP_WIDTH / scale, PIXMAP_HEIGHT / scale, COGL_READ_PIXELS_COLOR_BUFFER, COGL_PIXEL_FORMAT_RGBA_8888_PRE, data); for (y = 0; y < PIXMAP_HEIGHT / scale; y++) for (x = 0; x < PIXMAP_WIDTH / scale; x++) { int grid_x = x * scale / GRID_SQUARE_SIZE; int grid_y = y * scale / GRID_SQUARE_SIZE; /* If this is the updatable square then we'll let it be either color but we'll return which one it was */ if (grid_x == PIXMAP_CHANGE_X && grid_y == PIXMAP_CHANGE_Y) { if (x % (GRID_SQUARE_SIZE / scale) == 0 && y % (GRID_SQUARE_SIZE / scale) == 0) update_value = *p; else g_assert_cmpint (p[0], ==, update_value); g_assert (p[1] == update_value); g_assert (p[2] == update_value); p += 4; } else { uint8_t value = ((grid_x ^ grid_y) & 1) ? 0x00 : 0xff; g_assert_cmpint (*(p++), ==, value); g_assert_cmpint (*(p++), ==, value); g_assert_cmpint (*(p++), ==, value); p++; } } free (data); return update_value == 0x00; } /* We skip these frames first */ #define FRAME_COUNT_BASE 5 /* First paint the tfp with no mipmaps */ #define FRAME_COUNT_NORMAL 6 /* Then use mipmaps */ #define FRAME_COUNT_MIPMAP 7 /* After this frame will start waiting for the pixmap to change */ #define FRAME_COUNT_UPDATED 8 static void on_paint (ClutterActor *actor, TestState *state) { CoglHandle material; material = cogl_material_new (); cogl_material_set_layer (material, 0, state->tfp); if (state->frame_count == FRAME_COUNT_MIPMAP) { const CoglMaterialFilter min_filter = COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST; cogl_material_set_layer_filters (material, 0, min_filter, COGL_MATERIAL_FILTER_NEAREST); } else cogl_material_set_layer_filters (material, 0, COGL_MATERIAL_FILTER_NEAREST, COGL_MATERIAL_FILTER_NEAREST); cogl_set_source (material); cogl_rectangle (0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT); cogl_rectangle (0, PIXMAP_HEIGHT, PIXMAP_WIDTH / 4, PIXMAP_HEIGHT * 5 / 4); if (state->frame_count >= 5) { CoglBool big_updated, small_updated; big_updated = check_paint (state, 0, 0, 1); small_updated = check_paint (state, 0, PIXMAP_HEIGHT, 4); g_assert (big_updated == small_updated); if (state->frame_count < FRAME_COUNT_UPDATED) g_assert (big_updated == FALSE); else if (state->frame_count == FRAME_COUNT_UPDATED) /* Change the pixmap and keep drawing until it updates */ update_pixmap (state); else if (big_updated) /* If we successfully got the update then the test is over */ clutter_main_quit (); } state->frame_count++; } static CoglBool queue_redraw (void *stage) { clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); return TRUE; } #endif /* COGL_HAS_XLIB */ void test_texture_pixmap_x11 (TestUtilsGTestFixture *fixture, void *data) { #ifdef COGL_HAS_XLIB TestState state; unsigned int idle_handler; unsigned int paint_handler; state.frame_count = 0; state.stage = clutter_stage_get_default (); state.display = clutter_x11_get_default_display (); state.pixmap = create_pixmap (&state); state.tfp = cogl_texture_pixmap_x11_new (state.pixmap, TRUE); clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color); paint_handler = g_signal_connect_after (state.stage, "paint", G_CALLBACK (on_paint), &state); idle_handler = g_idle_add (queue_redraw, state.stage); clutter_actor_show_all (state.stage); clutter_main (); g_signal_handler_disconnect (state.stage, paint_handler); g_source_remove (idle_handler); XFreePixmap (state.display, state.pixmap); if (cogl_test_verbose ()) g_print ("OK\n"); #else /* COGL_HAS_XLIB */ if (cogl_test_verbose ()) g_print ("Skipping\n"); #endif /* COGL_HAS_XLIB */ } muffin-5.2.1/cogl/tests/conform/test-fixtures.c0000664000175000017500000000036614211404421021664 0ustar jpeisachjpeisach #include #include void test_simple_rig (void) { ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff }; stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); } muffin-5.2.1/cogl/tests/conform/test-atlas-migration.c0000664000175000017500000000745614211404421023115 0ustar jpeisachjpeisach#include #include "test-utils.h" #define N_TEXTURES 128 #define OPACITY_FOR_ROW(y) \ (0xff - ((y) & 0xf) * 0x10) #define COLOR_FOR_SIZE(size) \ (colors + (size) % 3) typedef struct { uint8_t red, green, blue, alpha; } TestColor; static const TestColor colors[] = { { 0xff, 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00, 0xff }, { 0x00, 0x00, 0xff, 0xff } }; static CoglTexture * create_texture (int size) { CoglTexture *texture; const TestColor *color; uint8_t *data, *p; int x, y; /* Create a red, green or blue texture depending on the size */ color = COLOR_FOR_SIZE (size); p = data = malloc (size * size * 4); /* Fill the data with the color but fade the opacity out with increasing y coordinates so that we can see the blending it the atlas migration accidentally blends with garbage in the texture */ for (y = 0; y < size; y++) { int opacity = OPACITY_FOR_ROW (y); for (x = 0; x < size; x++) { /* Store the colors premultiplied */ p[0] = color->red * opacity / 255; p[1] = color->green * opacity / 255; p[2] = color->blue * opacity / 255; p[3] = opacity; p += 4; } } texture = test_utils_texture_new_from_data (test_ctx, size, /* width */ size, /* height */ TEST_UTILS_TEXTURE_NONE, /* flags */ /* format */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* rowstride */ size * 4, data); free (data); return texture; } static void verify_texture (CoglTexture *texture, int size) { uint8_t *data, *p; int x, y; const TestColor *color; color = COLOR_FOR_SIZE (size); p = data = malloc (size * size * 4); cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_RGBA_8888_PRE, size * 4, data); for (y = 0; y < size; y++) { int opacity = OPACITY_FOR_ROW (y); for (x = 0; x < size; x++) { TestColor real_color = { color->red * opacity / 255, color->green * opacity / 255, color->blue * opacity / 255 }; test_utils_compare_pixel (p, (real_color.red << 24) | (real_color.green << 16) | (real_color.blue << 8) | opacity); g_assert_cmpint (p[3], ==, opacity); p += 4; } } free (data); } void test_atlas_migration (void) { CoglTexture *textures[N_TEXTURES]; int i, tex_num; /* Create and destroy all of the textures a few times to increase the chances that we'll end up reusing the buffers for previously discarded atlases */ for (i = 0; i < 5; i++) { for (tex_num = 0; tex_num < N_TEXTURES; tex_num++) textures[tex_num] = create_texture (tex_num + 1); for (tex_num = 0; tex_num < N_TEXTURES; tex_num++) cogl_object_unref (textures[tex_num]); } /* Create all the textures again */ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++) textures[tex_num] = create_texture (tex_num + 1); /* Verify that they all still have the right data */ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++) verify_texture (textures[tex_num], tex_num + 1); /* Destroy them all */ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++) cogl_object_unref (textures[tex_num]); if (cogl_test_verbose ()) g_print ("OK\n"); } muffin-5.2.1/cogl/cogl-path/0000775000175000017500000000000014211404421015736 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl-path/tesselator/0000775000175000017500000000000014211404421020123 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl-path/tesselator/dict.h0000664000175000017500000000671014211404421021223 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __dict_list_h_ #define __dict_list_h_ /* Use #define's so that another heap implementation can use this one */ #define DictKey DictListKey #define Dict DictList #define DictNode DictListNode #define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) #define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) #define dictSearch(dict,key) __gl_dictListSearch(dict,key) #define dictInsert(dict,key) __gl_dictListInsert(dict,key) #define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) #define dictDelete(dict,node) __gl_dictListDelete(dict,node) #define dictKey(n) __gl_dictListKey(n) #define dictSucc(n) __gl_dictListSucc(n) #define dictPred(n) __gl_dictListPred(n) #define dictMin(d) __gl_dictListMin(d) #define dictMax(d) __gl_dictListMax(d) typedef void *DictKey; typedef struct Dict Dict; typedef struct DictNode DictNode; Dict *dictNewDict( void *frame, int (*leq)(void *frame, DictKey key1, DictKey key2) ); void dictDeleteDict( Dict *dict ); /* Search returns the node with the smallest key greater than or equal * to the given key. If there is no such key, returns a node whose * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. */ DictNode *dictSearch( Dict *dict, DictKey key ); DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); void dictDelete( Dict *dict, DictNode *node ); #define __gl_dictListKey(n) ((n)->key) #define __gl_dictListSucc(n) ((n)->next) #define __gl_dictListPred(n) ((n)->prev) #define __gl_dictListMin(d) ((d)->head.next) #define __gl_dictListMax(d) ((d)->head.prev) #define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) /*** Private data structures ***/ struct DictNode { DictKey key; DictNode *next; DictNode *prev; }; struct Dict { DictNode head; void *frame; int (*leq)(void *frame, DictKey key1, DictKey key2); }; #endif muffin-5.2.1/cogl/cogl-path/tesselator/geom.c0000664000175000017500000002124114211404421021216 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include #include "mesh.h" #include "geom.h" int __gl_vertLeq( GLUvertex *u, GLUvertex *v ) { /* Returns TRUE if u is lexicographically <= v. */ return VertLeq( u, v ); } GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) { /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w), * evaluates the t-coord of the edge uw at the s-coord of the vertex v. * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v. * If uw is vertical (and thus passes thru v), the result is zero. * * The calculation is extremely accurate and stable, even when v * is very close to u or w. In particular if we set v->t = 0 and * let r be the negated result (this evaluates (uw)(v->s)), then * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t). */ GLdouble gapL, gapR; assert( VertLeq( u, v ) && VertLeq( v, w )); gapL = v->s - u->s; gapR = w->s - v->s; if( gapL + gapR > 0 ) { if( gapL < gapR ) { return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR)); } else { return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR)); } } /* vertical line */ return 0; } GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) { /* Returns a number whose sign matches EdgeEval(u,v,w) but which * is cheaper to evaluate. Returns > 0, == 0 , or < 0 * as v is above, on, or below the edge uw. */ GLdouble gapL, gapR; assert( VertLeq( u, v ) && VertLeq( v, w )); gapL = v->s - u->s; gapR = w->s - v->s; if( gapL + gapR > 0 ) { return (v->t - w->t) * gapL + (v->t - u->t) * gapR; } /* vertical line */ return 0; } /*********************************************************************** * Define versions of EdgeSign, EdgeEval with s and t transposed. */ GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) { /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w), * evaluates the t-coord of the edge uw at the s-coord of the vertex v. * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v. * If uw is vertical (and thus passes thru v), the result is zero. * * The calculation is extremely accurate and stable, even when v * is very close to u or w. In particular if we set v->s = 0 and * let r be the negated result (this evaluates (uw)(v->t)), then * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s). */ GLdouble gapL, gapR; assert( TransLeq( u, v ) && TransLeq( v, w )); gapL = v->t - u->t; gapR = w->t - v->t; if( gapL + gapR > 0 ) { if( gapL < gapR ) { return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR)); } else { return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR)); } } /* vertical line */ return 0; } GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) { /* Returns a number whose sign matches TransEval(u,v,w) but which * is cheaper to evaluate. Returns > 0, == 0 , or < 0 * as v is above, on, or below the edge uw. */ GLdouble gapL, gapR; assert( TransLeq( u, v ) && TransLeq( v, w )); gapL = v->t - u->t; gapR = w->t - v->t; if( gapL + gapR > 0 ) { return (v->s - w->s) * gapL + (v->s - u->s) * gapR; } /* vertical line */ return 0; } int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ) { /* For almost-degenerate situations, the results are not reliable. * Unless the floating-point arithmetic can be performed without * rounding errors, *any* implementation will give incorrect results * on some degenerate inputs, so the client must have some way to * handle this situation. */ return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0; } /* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b), * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces * this in the rare case that one argument is slightly negative. * The implementation is extremely stable numerically. * In particular it guarantees that the result r satisfies * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate * even when a and b differ greatly in magnitude. */ #define RealInterpolate(a,x,b,y) \ (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \ ((a <= b) ? ((b == 0) ? ((x+y) / 2) \ : (x + (y-x) * (a/(a+b)))) \ : (y + (x-y) * (b/(a+b))))) #ifndef FOR_TRITE_TEST_PROGRAM #define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y) #else /* Claim: the ONLY property the sweep algorithm relies on is that * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that. */ #include extern int RandomInterpolate; GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y) { printf("*********************%d\n",RandomInterpolate); if( RandomInterpolate ) { a = 1.2 * drand48() - 0.1; a = (a < 0) ? 0 : ((a > 1) ? 1 : a); b = 1.0 - a; } return RealInterpolate(a,x,b,y); } #endif #define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while (0) void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, GLUvertex *o2, GLUvertex *d2, GLUvertex *v ) /* Given edges (o1,d1) and (o2,d2), compute their point of intersection. * The computed point is guaranteed to lie in the intersection of the * bounding rectangles defined by each edge. */ { GLdouble z1, z2; /* This is certainly not the most efficient way to find the intersection * of two line segments, but it is very numerically stable. * * Strategy: find the two middle vertices in the VertLeq ordering, * and interpolate the intersection s-value from these. Then repeat * using the TransLeq ordering to find the intersection t-value. */ if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); } if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); } if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } if( ! VertLeq( o2, d1 )) { /* Technically, no intersection -- do our best */ v->s = (o2->s + d1->s) / 2; } else if( VertLeq( d1, d2 )) { /* Interpolate between o2 and d1 */ z1 = EdgeEval( o1, o2, d1 ); z2 = EdgeEval( o2, d1, d2 ); if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } v->s = Interpolate( z1, o2->s, z2, d1->s ); } else { /* Interpolate between o2 and d2 */ z1 = EdgeSign( o1, o2, d1 ); z2 = -EdgeSign( o1, d2, d1 ); if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } v->s = Interpolate( z1, o2->s, z2, d2->s ); } /* Now repeat the process for t */ if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); } if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); } if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } if( ! TransLeq( o2, d1 )) { /* Technically, no intersection -- do our best */ v->t = (o2->t + d1->t) / 2; } else if( TransLeq( d1, d2 )) { /* Interpolate between o2 and d1 */ z1 = TransEval( o1, o2, d1 ); z2 = TransEval( o2, d1, d2 ); if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } v->t = Interpolate( z1, o2->t, z2, d1->t ); } else { /* Interpolate between o2 and d2 */ z1 = TransSign( o1, o2, d1 ); z2 = -TransSign( o1, d2, d1 ); if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } v->t = Interpolate( z1, o2->t, z2, d2->t ); } } muffin-5.2.1/cogl/cogl-path/tesselator/tesselator.h0000664000175000017500000001205114211404421022460 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 2010 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ #ifndef __TESSELATOR_H__ #define __TESSELATOR_H__ /* This just includes the defines needed by the tesselator code */ #include "cogl/cogl-defines.h" #include "cogl/cogl-gl-header.h" typedef struct GLUtesselator GLUtesselator; #define GLU_TESS_MAX_COORD 1.0e150 void gluBeginPolygon (GLUtesselator* tess); void gluDeleteTess (GLUtesselator* tess); void gluEndPolygon (GLUtesselator* tess); typedef void (_GLUfuncptr)(); void gluGetTessProperty (GLUtesselator* tess, GLenum which, double* data); GLUtesselator *gluNewTess (void); void gluNextContour (GLUtesselator* tess, GLenum type); void gluTessBeginContour (GLUtesselator* tess); void gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data); void gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc); void gluTessEndContour (GLUtesselator* tess); void gluTessEndPolygon (GLUtesselator* tess); void gluTessNormal (GLUtesselator* tess, double valueX, double valueY, double valueZ); void gluTessProperty (GLUtesselator* tess, GLenum which, double data); void gluTessVertex (GLUtesselator* tess, double *location, GLvoid* data); /* ErrorCode */ #define GLU_INVALID_ENUM 100900 #define GLU_INVALID_VALUE 100901 #define GLU_OUT_OF_MEMORY 100902 /* TessCallback */ #define GLU_TESS_BEGIN 100100 #define GLU_BEGIN 100100 #define GLU_TESS_VERTEX 100101 #define GLU_VERTEX 100101 #define GLU_TESS_END 100102 #define GLU_END 100102 #define GLU_TESS_ERROR 100103 #define GLU_TESS_EDGE_FLAG 100104 #define GLU_EDGE_FLAG 100104 #define GLU_TESS_COMBINE 100105 #define GLU_TESS_BEGIN_DATA 100106 #define GLU_TESS_VERTEX_DATA 100107 #define GLU_TESS_END_DATA 100108 #define GLU_TESS_ERROR_DATA 100109 #define GLU_TESS_EDGE_FLAG_DATA 100110 #define GLU_TESS_COMBINE_DATA 100111 /* TessContour */ #define GLU_CW 100120 #define GLU_CCW 100121 #define GLU_INTERIOR 100122 #define GLU_EXTERIOR 100123 #define GLU_UNKNOWN 100124 /* TessProperty */ #define GLU_TESS_WINDING_RULE 100140 #define GLU_TESS_BOUNDARY_ONLY 100141 #define GLU_TESS_TOLERANCE 100142 /* TessError */ #define GLU_TESS_ERROR1 100151 #define GLU_TESS_ERROR2 100152 #define GLU_TESS_ERROR3 100153 #define GLU_TESS_ERROR4 100154 #define GLU_TESS_ERROR5 100155 #define GLU_TESS_ERROR6 100156 #define GLU_TESS_ERROR7 100157 #define GLU_TESS_ERROR8 100158 #define GLU_TESS_MISSING_BEGIN_POLYGON 100151 #define GLU_TESS_MISSING_BEGIN_CONTOUR 100152 #define GLU_TESS_MISSING_END_POLYGON 100153 #define GLU_TESS_MISSING_END_CONTOUR 100154 #define GLU_TESS_COORD_TOO_LARGE 100155 #define GLU_TESS_NEED_COMBINE_CALLBACK 100156 /* TessWinding */ #define GLU_TESS_WINDING_ODD 100130 #define GLU_TESS_WINDING_NONZERO 100131 #define GLU_TESS_WINDING_POSITIVE 100132 #define GLU_TESS_WINDING_NEGATIVE 100133 #define GLU_TESS_WINDING_ABS_GEQ_TWO 100134 #endif /* __TESSELATOR_H__ */ muffin-5.2.1/cogl/cogl-path/tesselator/memalloc.h0000664000175000017500000000316514211404421022072 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is a simple replacement for memalloc from the SGI tesselator code to force it to use glib's allocation instead */ #ifndef __MEMALLOC_H__ #define __MEMALLOC_H__ #include #define memRealloc g_realloc #define memAlloc malloc #define memFree free #define memInit(x) 1 /* tess.c defines TRUE and FALSE itself unconditionally so we need to undefine it from the glib headers */ #undef TRUE #undef FALSE #endif /* __MEMALLOC_H__ */ muffin-5.2.1/cogl/cogl-path/tesselator/mesh.c0000664000175000017500000005347514211404421021241 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include #include #include "mesh.h" #include "memalloc.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif static GLUvertex *allocVertex() { return (GLUvertex *)memAlloc( sizeof( GLUvertex )); } static GLUface *allocFace() { return (GLUface *)memAlloc( sizeof( GLUface )); } /************************ Utility Routines ************************/ /* Allocate and free half-edges in pairs for efficiency. * The *only* place that should use this fact is allocation/free. */ typedef struct { GLUhalfEdge e, eSym; } EdgePair; /* MakeEdge creates a new pair of half-edges which form their own loop. * No vertex or face structures are allocated, but these must be assigned * before the current edge operation is completed. */ static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext ) { GLUhalfEdge *e; GLUhalfEdge *eSym; GLUhalfEdge *ePrev; EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair )); if (pair == NULL) return NULL; e = &pair->e; eSym = &pair->eSym; /* Make sure eNext points to the first edge of the edge pair */ if( eNext->Sym < eNext ) { eNext = eNext->Sym; } /* Insert in circular doubly-linked list before eNext. * Note that the prev pointer is stored in Sym->next. */ ePrev = eNext->Sym->next; eSym->next = ePrev; ePrev->Sym->next = e; e->next = eNext; eNext->Sym->next = eSym; e->Sym = eSym; e->Onext = e; e->Lnext = eSym; e->Org = NULL; e->Lface = NULL; e->winding = 0; e->activeRegion = NULL; eSym->Sym = e; eSym->Onext = eSym; eSym->Lnext = e; eSym->Org = NULL; eSym->Lface = NULL; eSym->winding = 0; eSym->activeRegion = NULL; return e; } /* Splice( a, b ) is best described by the Guibas/Stolfi paper or the * CS348a notes (see mesh.h). Basically it modifies the mesh so that * a->Onext and b->Onext are exchanged. This can have various effects * depending on whether a and b belong to different face or vertex rings. * For more explanation see __gl_meshSplice() below. */ static void Splice( GLUhalfEdge *a, GLUhalfEdge *b ) { GLUhalfEdge *aOnext = a->Onext; GLUhalfEdge *bOnext = b->Onext; aOnext->Sym->Lnext = b; bOnext->Sym->Lnext = a; a->Onext = bOnext; b->Onext = aOnext; } /* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives * a place to insert the new vertex in the global vertex list. We insert * the new vertex *before* vNext so that algorithms which walk the vertex * list will not see the newly created vertices. */ static void MakeVertex( GLUvertex *newVertex, GLUhalfEdge *eOrig, GLUvertex *vNext ) { GLUhalfEdge *e; GLUvertex *vPrev; GLUvertex *vNew = newVertex; assert(vNew != NULL); /* insert in circular doubly-linked list before vNext */ vPrev = vNext->prev; vNew->prev = vPrev; vPrev->next = vNew; vNew->next = vNext; vNext->prev = vNew; vNew->anEdge = eOrig; vNew->data = NULL; /* leave coords, s, t undefined */ /* fix other edges on this vertex loop */ e = eOrig; do { e->Org = vNew; e = e->Onext; } while( e != eOrig ); } /* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left * face of all edges in the face loop to which eOrig belongs. "fNext" gives * a place to insert the new face in the global face list. We insert * the new face *before* fNext so that algorithms which walk the face * list will not see the newly created faces. */ static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext ) { GLUhalfEdge *e; GLUface *fPrev; GLUface *fNew = newFace; assert(fNew != NULL); /* insert in circular doubly-linked list before fNext */ fPrev = fNext->prev; fNew->prev = fPrev; fPrev->next = fNew; fNew->next = fNext; fNext->prev = fNew; fNew->anEdge = eOrig; fNew->data = NULL; fNew->trail = NULL; fNew->marked = FALSE; /* The new face is marked "inside" if the old one was. This is a * convenience for the common case where a face has been split in two. */ fNew->inside = fNext->inside; /* fix other edges on this face loop */ e = eOrig; do { e->Lface = fNew; e = e->Lnext; } while( e != eOrig ); } /* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym), * and removes from the global edge list. */ static void KillEdge( GLUhalfEdge *eDel ) { GLUhalfEdge *ePrev, *eNext; /* Half-edges are allocated in pairs, see EdgePair above */ if( eDel->Sym < eDel ) { eDel = eDel->Sym; } /* delete from circular doubly-linked list */ eNext = eDel->next; ePrev = eDel->Sym->next; eNext->Sym->next = ePrev; ePrev->Sym->next = eNext; memFree( eDel ); } /* KillVertex( vDel ) destroys a vertex and removes it from the global * vertex list. It updates the vertex loop to point to a given new vertex. */ static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg ) { GLUhalfEdge *e, *eStart = vDel->anEdge; GLUvertex *vPrev, *vNext; /* change the origin of all affected edges */ e = eStart; do { e->Org = newOrg; e = e->Onext; } while( e != eStart ); /* delete from circular doubly-linked list */ vPrev = vDel->prev; vNext = vDel->next; vNext->prev = vPrev; vPrev->next = vNext; memFree( vDel ); } /* KillFace( fDel ) destroys a face and removes it from the global face * list. It updates the face loop to point to a given new face. */ static void KillFace( GLUface *fDel, GLUface *newLface ) { GLUhalfEdge *e, *eStart = fDel->anEdge; GLUface *fPrev, *fNext; /* change the left face of all affected edges */ e = eStart; do { e->Lface = newLface; e = e->Lnext; } while( e != eStart ); /* delete from circular doubly-linked list */ fPrev = fDel->prev; fNext = fDel->next; fNext->prev = fPrev; fPrev->next = fNext; memFree( fDel ); } /****************** Basic Edge Operations **********************/ /* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face). * The loop consists of the two new half-edges. */ GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ) { GLUvertex *newVertex1= allocVertex(); GLUvertex *newVertex2= allocVertex(); GLUface *newFace= allocFace(); GLUhalfEdge *e; /* if any one is null then all get freed */ if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) { if (newVertex1 != NULL) memFree(newVertex1); if (newVertex2 != NULL) memFree(newVertex2); if (newFace != NULL) memFree(newFace); return NULL; } e = MakeEdge( &mesh->eHead ); if (e == NULL) { memFree(newVertex1); memFree(newVertex2); memFree(newFace); return NULL; } MakeVertex( newVertex1, e, &mesh->vHead ); MakeVertex( newVertex2, e->Sym, &mesh->vHead ); MakeFace( newFace, e, &mesh->fHead ); return e; } /* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the * mesh connectivity and topology. It changes the mesh so that * eOrg->Onext <- OLD( eDst->Onext ) * eDst->Onext <- OLD( eOrg->Onext ) * where OLD(...) means the value before the meshSplice operation. * * This can have two effects on the vertex structure: * - if eOrg->Org != eDst->Org, the two vertices are merged together * - if eOrg->Org == eDst->Org, the origin is split into two vertices * In both cases, eDst->Org is changed and eOrg->Org is untouched. * * Similarly (and independently) for the face structure, * - if eOrg->Lface == eDst->Lface, one loop is split into two * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. * * Some special cases: * If eDst == eOrg, the operation has no effect. * If eDst == eOrg->Lnext, the new face will have a single edge. * If eDst == eOrg->Lprev, the old face will have a single edge. * If eDst == eOrg->Onext, the new vertex will have a single edge. * If eDst == eOrg->Oprev, the old vertex will have a single edge. */ int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) { int joiningLoops = FALSE; int joiningVertices = FALSE; if( eOrg == eDst ) return 1; if( eDst->Org != eOrg->Org ) { /* We are merging two disjoint vertices -- destroy eDst->Org */ joiningVertices = TRUE; KillVertex( eDst->Org, eOrg->Org ); } if( eDst->Lface != eOrg->Lface ) { /* We are connecting two disjoint loops -- destroy eDst->Lface */ joiningLoops = TRUE; KillFace( eDst->Lface, eOrg->Lface ); } /* Change the edge structure */ Splice( eDst, eOrg ); if( ! joiningVertices ) { GLUvertex *newVertex= allocVertex(); if (newVertex == NULL) return 0; /* We split one vertex into two -- the new vertex is eDst->Org. * Make sure the old vertex points to a valid half-edge. */ MakeVertex( newVertex, eDst, eOrg->Org ); eOrg->Org->anEdge = eOrg; } if( ! joiningLoops ) { GLUface *newFace= allocFace(); if (newFace == NULL) return 0; /* We split one loop into two -- the new loop is eDst->Lface. * Make sure the old face points to a valid half-edge. */ MakeFace( newFace, eDst, eOrg->Lface ); eOrg->Lface->anEdge = eOrg; } return 1; } /* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; * the newly created loop will contain eDel->Dst. If the deletion of eDel * would create isolated vertices, those are deleted as well. * * This function could be implemented as two calls to __gl_meshSplice * plus a few calls to memFree, but this would allocate and delete * unnecessary vertices and faces. */ int __gl_meshDelete( GLUhalfEdge *eDel ) { GLUhalfEdge *eDelSym = eDel->Sym; int joiningLoops = FALSE; /* First step: disconnect the origin vertex eDel->Org. We make all * changes to get a consistent mesh in this "intermediate" state. */ if( eDel->Lface != eDel->Rface ) { /* We are joining two loops into one -- remove the left face */ joiningLoops = TRUE; KillFace( eDel->Lface, eDel->Rface ); } if( eDel->Onext == eDel ) { KillVertex( eDel->Org, NULL ); } else { /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ eDel->Rface->anEdge = eDel->Oprev; eDel->Org->anEdge = eDel->Onext; Splice( eDel, eDel->Oprev ); if( ! joiningLoops ) { GLUface *newFace= allocFace(); if (newFace == NULL) return 0; /* We are splitting one loop into two -- create a new loop for eDel. */ MakeFace( newFace, eDel, eDel->Lface ); } } /* Claim: the mesh is now in a consistent state, except that eDel->Org * may have been deleted. Now we disconnect eDel->Dst. */ if( eDelSym->Onext == eDelSym ) { KillVertex( eDelSym->Org, NULL ); KillFace( eDelSym->Lface, NULL ); } else { /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ eDel->Lface->anEdge = eDelSym->Oprev; eDelSym->Org->anEdge = eDelSym->Onext; Splice( eDelSym, eDelSym->Oprev ); } /* Any isolated vertices or faces have already been freed. */ KillEdge( eDel ); return 1; } /******************** Other Edge Operations **********************/ /* All these routines can be implemented with the basic edge * operations above. They are provided for convenience and efficiency. */ /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. * eOrg and eNew will have the same left face. */ GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ) { GLUhalfEdge *eNewSym; GLUhalfEdge *eNew = MakeEdge( eOrg ); if (eNew == NULL) return NULL; eNewSym = eNew->Sym; /* Connect the new edge appropriately */ Splice( eNew, eOrg->Lnext ); /* Set the vertex and face information */ eNew->Org = eOrg->Dst; { GLUvertex *newVertex= allocVertex(); if (newVertex == NULL) return NULL; MakeVertex( newVertex, eNewSym, eNew->Org ); } eNew->Lface = eNewSym->Lface = eOrg->Lface; return eNew; } /* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. * eOrg and eNew will have the same left face. */ GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ) { GLUhalfEdge *eNew; GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg ); if (tempHalfEdge == NULL) return NULL; eNew = tempHalfEdge->Sym; /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */ Splice( eOrg->Sym, eOrg->Sym->Oprev ); Splice( eOrg->Sym, eNew ); /* Set the vertex and face information */ eOrg->Dst = eNew->Org; eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */ eNew->Rface = eOrg->Rface; eNew->winding = eOrg->winding; /* copy old winding information */ eNew->Sym->winding = eOrg->Sym->winding; return eNew; } /* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst * to eDst->Org, and returns the corresponding half-edge eNew. * If eOrg->Lface == eDst->Lface, this splits one loop into two, * and the newly created loop is eNew->Lface. Otherwise, two disjoint * loops are merged into one, and the loop eDst->Lface is destroyed. * * If (eOrg == eDst), the new face will have only two edges. * If (eOrg->Lnext == eDst), the old face is reduced to a single edge. * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. */ GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) { GLUhalfEdge *eNewSym; int joiningLoops = FALSE; GLUhalfEdge *eNew = MakeEdge( eOrg ); if (eNew == NULL) return NULL; eNewSym = eNew->Sym; if( eDst->Lface != eOrg->Lface ) { /* We are connecting two disjoint loops -- destroy eDst->Lface */ joiningLoops = TRUE; KillFace( eDst->Lface, eOrg->Lface ); } /* Connect the new edge appropriately */ Splice( eNew, eOrg->Lnext ); Splice( eNewSym, eDst ); /* Set the vertex and face information */ eNew->Org = eOrg->Dst; eNewSym->Org = eDst->Org; eNew->Lface = eNewSym->Lface = eOrg->Lface; /* Make sure the old face points to a valid half-edge */ eOrg->Lface->anEdge = eNewSym; if( ! joiningLoops ) { GLUface *newFace= allocFace(); if (newFace == NULL) return NULL; /* We split one loop into two -- the new loop is eNew->Lface */ MakeFace( newFace, eNew, eOrg->Lface ); } return eNew; } /******************** Other Operations **********************/ /* __gl_meshZapFace( fZap ) destroys a face and removes it from the * global face list. All edges of fZap will have a NULL pointer as their * left face. Any edges which also have a NULL pointer as their right face * are deleted entirely (along with any isolated vertices this produces). * An entire mesh can be deleted by zapping its faces, one at a time, * in any order. Zapped faces cannot be used in further mesh operations! */ void __gl_meshZapFace( GLUface *fZap ) { GLUhalfEdge *eStart = fZap->anEdge; GLUhalfEdge *e, *eNext, *eSym; GLUface *fPrev, *fNext; /* walk around face, deleting edges whose right face is also NULL */ eNext = eStart->Lnext; do { e = eNext; eNext = e->Lnext; e->Lface = NULL; if( e->Rface == NULL ) { /* delete the edge -- see __gl_MeshDelete above */ if( e->Onext == e ) { KillVertex( e->Org, NULL ); } else { /* Make sure that e->Org points to a valid half-edge */ e->Org->anEdge = e->Onext; Splice( e, e->Oprev ); } eSym = e->Sym; if( eSym->Onext == eSym ) { KillVertex( eSym->Org, NULL ); } else { /* Make sure that eSym->Org points to a valid half-edge */ eSym->Org->anEdge = eSym->Onext; Splice( eSym, eSym->Oprev ); } KillEdge( e ); } } while( e != eStart ); /* delete from circular doubly-linked list */ fPrev = fZap->prev; fNext = fZap->next; fNext->prev = fPrev; fPrev->next = fNext; memFree( fZap ); } /* __gl_meshNewMesh() creates a new mesh with no edges, no vertices, * and no loops (what we usually call a "face"). */ GLUmesh *__gl_meshNewMesh( void ) { GLUvertex *v; GLUface *f; GLUhalfEdge *e; GLUhalfEdge *eSym; GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh )); if (mesh == NULL) { return NULL; } v = &mesh->vHead; f = &mesh->fHead; e = &mesh->eHead; eSym = &mesh->eHeadSym; v->next = v->prev = v; v->anEdge = NULL; v->data = NULL; f->next = f->prev = f; f->anEdge = NULL; f->data = NULL; f->trail = NULL; f->marked = FALSE; f->inside = FALSE; e->next = e; e->Sym = eSym; e->Onext = NULL; e->Lnext = NULL; e->Org = NULL; e->Lface = NULL; e->winding = 0; e->activeRegion = NULL; eSym->next = eSym; eSym->Sym = e; eSym->Onext = NULL; eSym->Lnext = NULL; eSym->Org = NULL; eSym->Lface = NULL; eSym->winding = 0; eSym->activeRegion = NULL; return mesh; } /* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in * both meshes, and returns the new mesh (the old meshes are destroyed). */ GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ) { GLUface *f1 = &mesh1->fHead; GLUvertex *v1 = &mesh1->vHead; GLUhalfEdge *e1 = &mesh1->eHead; GLUface *f2 = &mesh2->fHead; GLUvertex *v2 = &mesh2->vHead; GLUhalfEdge *e2 = &mesh2->eHead; /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */ if( f2->next != f2 ) { f1->prev->next = f2->next; f2->next->prev = f1->prev; f2->prev->next = f1; f1->prev = f2->prev; } if( v2->next != v2 ) { v1->prev->next = v2->next; v2->next->prev = v1->prev; v2->prev->next = v1; v1->prev = v2->prev; } if( e2->next != e2 ) { e1->Sym->next->Sym->next = e2->next; e2->next->Sym->next = e1->Sym->next; e2->Sym->next->Sym->next = e1; e1->Sym->next = e2->Sym->next; } memFree( mesh2 ); return mesh1; } #ifdef DELETE_BY_ZAPPING /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. */ void __gl_meshDeleteMesh( GLUmesh *mesh ) { GLUface *fHead = &mesh->fHead; while( fHead->next != fHead ) { __gl_meshZapFace( fHead->next ); } assert( mesh->vHead.next == &mesh->vHead ); memFree( mesh ); } #else /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. */ void __gl_meshDeleteMesh( GLUmesh *mesh ) { GLUface *f, *fNext; GLUvertex *v, *vNext; GLUhalfEdge *e, *eNext; for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { fNext = f->next; memFree( f ); } for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) { vNext = v->next; memFree( v ); } for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { /* One call frees both e and e->Sym (see EdgePair above) */ eNext = e->next; memFree( e ); } memFree( mesh ); } #endif #ifndef NDEBUG /* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. */ void __gl_meshCheckMesh( GLUmesh *mesh ) { GLUface *fHead = &mesh->fHead; GLUvertex *vHead = &mesh->vHead; GLUhalfEdge *eHead = &mesh->eHead; GLUface *f, *fPrev; GLUvertex *v, *vPrev; GLUhalfEdge *e, *ePrev; fPrev = fHead; for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) { assert( f->prev == fPrev ); e = f->anEdge; do { assert( e->Sym != e ); assert( e->Sym->Sym == e ); assert( e->Lnext->Onext->Sym == e ); assert( e->Onext->Sym->Lnext == e ); assert( e->Lface == f ); e = e->Lnext; } while( e != f->anEdge ); } assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL ); vPrev = vHead; for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) { assert( v->prev == vPrev ); e = v->anEdge; do { assert( e->Sym != e ); assert( e->Sym->Sym == e ); assert( e->Lnext->Onext->Sym == e ); assert( e->Onext->Sym->Lnext == e ); assert( e->Org == v ); e = e->Onext; } while( e != v->anEdge ); } assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL ); ePrev = eHead; for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) { assert( e->Sym->next == ePrev->Sym ); assert( e->Sym != e ); assert( e->Sym->Sym == e ); assert( e->Org != NULL ); assert( e->Dst != NULL ); assert( e->Lnext->Onext->Sym == e ); assert( e->Onext->Sym->Lnext == e ); } assert( e->Sym->next == ePrev->Sym && e->Sym == &mesh->eHeadSym && e->Sym->Sym == e && e->Org == NULL && e->Dst == NULL && e->Lface == NULL && e->Rface == NULL ); } #endif muffin-5.2.1/cogl/cogl-path/tesselator/GL/0000775000175000017500000000000014211404421020425 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl-path/tesselator/GL/glu.h0000664000175000017500000000326714211404421021375 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ /* This is just a wrapper to use our simplified version of glu.h so that the tesselator code can still #include */ #include "../tesselator.h" /* These aren't defined on GLES and we don't really want the tesselator code to use them but we're also trying to avoid modifying the C files so we just force them to be empty here */ #undef GLAPI #define GLAPI #undef GLAPIENTRY #define GLAPIENTRY /* GLES doesn't define a GLdouble type so lets just force it to a regular double */ #define GLdouble double muffin-5.2.1/cogl/cogl-path/tesselator/README0000664000175000017500000004674314211404421021021 0ustar jpeisachjpeisach/* */ General Polygon Tesselation --------------------------- This note describes a tesselator for polygons consisting of one or more closed contours. It is backward-compatible with the current OpenGL Utilities tesselator, and is intended to replace it. Here is a summary of the major differences: - input contours can be intersecting, self-intersecting, or degenerate. - supports a choice of several winding rules for determining which parts of the polygon are on the "interior". This makes it possible to do CSG operations on polygons. - boundary extraction: instead of tesselating the polygon, returns a set of closed contours which separate the interior from the exterior. - returns the output as a small number of triangle fans and strips, rather than a list of independent triangles (when possible). - output is available as an explicit mesh (a quad-edge structure), in addition to the normal callback interface. - the algorithm used is extremely robust. The interface ------------- The tesselator state is maintained in a "tesselator object". These are allocated and destroyed using GLUtesselator *gluNewTess( void ); void gluDeleteTess( GLUtesselator *tess ); Several tesselator objects may be used simultaneously. Inputs ------ The input contours are specified with the following routines: void gluTessBeginPolygon( GLUtesselator *tess ); void gluTessBeginContour( GLUtesselator *tess ); void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data ); void gluTessEndContour( GLUtesselator *tess ); void gluTessEndPolygon( GLUtesselator *tess ); Within each BeginPolygon/EndPolygon pair, there can be zero or more calls to BeginContour/EndContour. Within each contour, there are zero or more calls to gluTessVertex(). The vertices specify a closed contour (the last vertex of each contour is automatically linked to the first). "coords" give the coordinates of the vertex in 3-space. For useful results, all vertices should lie in some plane, since the vertices are projected onto a plane before tesselation. "data" is a pointer to a user-defined vertex structure, which typically contains other information such as color, texture coordinates, normal, etc. It is used to refer to the vertex during rendering. The library can be compiled in single- or double-precision; the type GLUcoord represents either "float" or "double" accordingly. The GLU version will be available in double-precision only. Compile with GLU_TESS_API_FLOAT defined to get the single-precision version. When EndPolygon is called, the tesselation algorithm determines which regions are interior to the given contours, according to one of several "winding rules" described below. The interior regions are then tesselated, and the output is provided as callbacks. Rendering Callbacks ------------------- Callbacks are specified by the client using void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)()); If "fn" is NULL, any previously defined callback is discarded. The callbacks used to provide output are: /* which == */ void begin( GLenum type ); /* GLU_TESS_BEGIN */ void edgeFlag( GLboolean flag ); /* GLU_TESS_EDGE_FLAG */ void vertex( void *data ); /* GLU_TESS_VERTEX */ void end( void ); /* GLU_TESS_END */ Any of the callbacks may be left undefined; if so, the corresponding information will not be supplied during rendering. The "begin" callback indicates the start of a primitive; type is one of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the notes on "boundary extraction" below). It is followed by any number of "vertex" callbacks, which supply the vertices in the same order as expected by the corresponding glBegin() call. After the last vertex of a given primitive, there is a callback to "end". If the "edgeFlag" callback is provided, no triangle fans or strips will be used. When edgeFlag is called, if "flag" is GL_TRUE then each vertex which follows begins an edge which lies on the polygon boundary (ie. an edge which separates an interior region from an exterior one). If "flag" is GL_FALSE, each vertex which follows begins an edge which lies in the polygon interior. "edgeFlag" will be called before the first call to "vertex". Other Callbacks --------------- void mesh( GLUmesh *mesh ); /* GLU_TESS_MESH */ - Returns an explicit mesh, represented using the quad-edge structure (Guibas/Stolfi '85). Other implementations of this interface might use a different mesh structure, so this is available only only as an SGI extension. When the mesh is no longer needed, it should be freed using void gluDeleteMesh( GLUmesh *mesh ); There is a brief description of this data structure in the include file "mesh.h". For the full details, see L. Guibas and J. Stolfi, Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985. For an introduction, see the course notes for CS348a, "Mathematical Foundations of Computer Graphics", available at the Stanford bookstore (and taught during the fall quarter). void error( GLenum errno ); /* GLU_TESS_ERROR */ - errno is one of GLU_TESS_MISSING_BEGIN_POLYGON, GLU_TESS_MISSING_END_POLYGON, GLU_TESS_MISSING_BEGIN_CONTOUR, GLU_TESS_MISSING_END_CONTOUR, GLU_TESS_COORD_TOO_LARGE, GLU_TESS_NEED_COMBINE_CALLBACK The first four are obvious. The interface recovers from these errors by inserting the missing call(s). GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded the predefined constant GLU_TESS_MAX_COORD in absolute value, and that the value has been clamped. (Coordinate values must be small enough so that two can be multiplied together without overflow.) GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an intersection between two edges in the input data, and the "combine" callback (below) was not provided. No output will be generated. void combine( GLUcoord coords[3], void *data[4], /* GLU_TESS_COMBINE */ GLUcoord weight[4], void **outData ); - When the algorithm detects an intersection, or wishes to merge features, it needs to create a new vertex. The vertex is defined as a linear combination of up to 4 existing vertices, referenced by data[0..3]. The coefficients of the linear combination are given by weight[0..3]; these weights always sum to 1.0. All vertex pointers are valid even when some of the weights are zero. "coords" gives the location of the new vertex. The user must allocate another vertex, interpolate parameters using "data" and "weights", and return the new vertex pointer in "outData". This handle is supplied during rendering callbacks. For example, if the polygon lies in an arbitrary plane in 3-space, and we associate a color with each vertex, the combine callback might look like this: void myCombine( GLUcoord coords[3], VERTEX *d[4], GLUcoord w[4], VERTEX **dataOut ) { VERTEX *new = new_vertex(); new->x = coords[0]; new->y = coords[1]; new->z = coords[2]; new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r; new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g; new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b; new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a; *dataOut = new; } If the algorithm detects an intersection, then the "combine" callback must be defined, and must write a non-NULL pointer into "dataOut". Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no output is generated. This is the only error that can occur during tesselation and rendering. Control over Tesselation ------------------------ void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value ); Properties defined: - GLU_TESS_WINDING_RULE. Possible values: GLU_TESS_WINDING_ODD GLU_TESS_WINDING_NONZERO GLU_TESS_WINDING_POSITIVE GLU_TESS_WINDING_NEGATIVE GLU_TESS_WINDING_ABS_GEQ_TWO The input contours parition the plane into regions. A winding rule determines which of these regions are inside the polygon. For a single contour C, the winding number of a point x is simply the signed number of revolutions we make around x as we travel once around C (where CCW is positive). When there are several contours, the individual winding numbers are summed. This procedure associates a signed integer value with each point x in the plane. Note that the winding number is the same for all points in a single region. The winding rule classifies a region as "inside" if its winding number belongs to the chosen category (odd, nonzero, positive, negative, or absolute value of at least two). The current GLU tesselator implements the "odd" rule. The "nonzero" rule is another common way to define the interior. The other three rules are useful for polygon CSG operations (see below). - GLU_TESS_BOUNDARY_ONLY. Values: TRUE (non-zero) or FALSE (zero). If TRUE, returns a set of closed contours which separate the polygon interior and exterior (rather than a tesselation). Exterior contours are oriented CCW with respect to the normal, interior contours are oriented CW. The GLU_TESS_BEGIN callback uses the type GL_LINE_LOOP for each contour. - GLU_TESS_TOLERANCE. Value: a real number between 0.0 and 1.0. This specifies a tolerance for merging features to reduce the size of the output. For example, two vertices which are very close to each other might be replaced by a single vertex. The tolerance is multiplied by the largest coordinate magnitude of any input vertex; this specifies the maximum distance that any feature can move as the result of a single merge operation. If a single feature takes part in several merge operations, the total distance moved could be larger. Feature merging is completely optional; the tolerance is only a hint. The implementation is free to merge in some cases and not in others, or to never merge features at all. The default tolerance is zero. The current implementation merges vertices only if they are exactly coincident, regardless of the current tolerance. A vertex is spliced into an edge only if the implementation is unable to distinguish which side of the edge the vertex lies on. Two edges are merged only when both endpoints are identical. void gluTessNormal( GLUtesselator *tess, GLUcoord x, GLUcoord y, GLUcoord z ) - Lets the user supply the polygon normal, if known. All input data is projected into a plane perpendicular to the normal before tesselation. All output triangles are oriented CCW with respect to the normal (CW orientation can be obtained by reversing the sign of the supplied normal). For example, if you know that all polygons lie in the x-y plane, call "gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons. - If the supplied normal is (0,0,0) (the default value), the normal is determined as follows. The direction of the normal, up to its sign, is found by fitting a plane to the vertices, without regard to how the vertices are connected. It is expected that the input data lies approximately in plane; otherwise projection perpendicular to the computed normal may substantially change the geometry. The sign of the normal is chosen so that the sum of the signed areas of all input contours is non-negative (where a CCW contour has positive area). - The supplied normal persists until it is changed by another call to gluTessNormal. Backward compatibility with the GLU tesselator ---------------------------------------------- The preferred interface is the one described above. The following routines are obsolete, and are provided only for backward compatibility: typedef GLUtesselator GLUtriangulatorObj; /* obsolete name */ void gluBeginPolygon( GLUtesselator *tess ); void gluNextContour( GLUtesselator *tess, GLenum type ); void gluEndPolygon( GLUtesselator *tess ); "type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or GLU_UNKNOWN. It is ignored by the current GLU tesselator. GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END, GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG. Polygon CSG operations ---------------------- The features of the tesselator make it easy to find the union, difference, or intersection of several polygons. First, assume that each polygon is defined so that the winding number is 0 for each exterior region, and 1 for each interior region. Under this model, CCW contours define the outer boundary of the polygon, and CW contours define holes. Contours may be nested, but a nested contour must be oriented oppositely from the contour that contains it. If the original polygons do not satisfy this description, they can be converted to this form by first running the tesselator with the GLU_TESS_BOUNDARY_ONLY property turned on. This returns a list of contours satisfying the restriction above. By allocating two tesselator objects, the callbacks from one tesselator can be fed directly to the input of another. Given two or more polygons of the form above, CSG operations can be implemented as follows: Union Draw all the input contours as a single polygon. The winding number of each resulting region is the number of original polygons which cover it. The union can be extracted using the GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules. Note that with the nonzero rule, we would get the same result if all contour orientations were reversed. Intersection (two polygons at a time only) Draw a single polygon using the contours from both input polygons. Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO. (Since this winding rule looks at the absolute value, reversing all contour orientations does not change the result.) Difference Suppose we want to compute A \ (B union C union D). Draw a single polygon consisting of the unmodified contours from A, followed by the contours of B,C,D with the vertex order reversed (this changes the winding number of the interior regions to -1). To extract the result, use the GLU_TESS_WINDING_POSITIVE rule. If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an alternative to reversing the vertex order is to reverse the sign of the supplied normal. For example in the x-y plane, call gluTessNormal( tess, 0.0, 0.0, -1.0 ). Performance ----------- The tesselator is not intended for immediate-mode rendering; when possible the output should be cached in a user structure or display list. General polygon tesselation is an inherently difficult problem, especially given the goal of extreme robustness. The implementation makes an effort to output a small number of fans and strips; this should improve the rendering performance when the output is used in a display list. Single-contour input polygons are first tested to see whether they can be rendered as a triangle fan with respect to the first vertex (to avoid running the full decomposition algorithm on convex polygons). Non-convex polygons may be rendered by this "fast path" as well, if the algorithm gets lucky in its choice of a starting vertex. For best performance follow these guidelines: - supply the polygon normal, if available, using gluTessNormal(). This represents about 10% of the computation time. For example, if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1). - render many polygons using the same tesselator object, rather than allocating a new tesselator for each one. (In a multi-threaded, multi-processor environment you may get better performance using several tesselators.) Comparison with the GLU tesselator ---------------------------------- On polygons which make it through the "fast path", the tesselator is 3 to 5 times faster than the GLU tesselator. On polygons which don't make it through the fast path (but which don't have self-intersections or degeneracies), it is about 2 times slower. On polygons with self-intersections or degeneraces, there is nothing to compare against. The new tesselator generates many more fans and strips, reducing the number of vertices that need to be sent to the hardware. Key to the statistics: vert number of input vertices on all contours cntr number of input contours tri number of triangles in all output primitives strip number of triangle strips fan number of triangle fans ind number of independent triangles ms number of milliseconds for tesselation (on a 150MHz R4400 Indy) Convex polygon examples: New: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.0459 ms Old: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.149 ms New: 4 vert, 1 cntr, 2 tri, 0 strip, 1 fan, 0 ind, 0.0459 ms Old: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.161 ms New: 36 vert, 1 cntr, 34 tri, 0 strip, 1 fan, 0 ind, 0.153 ms Old: 36 vert, 1 cntr, 34 tri, 0 strip, 0 fan, 34 ind, 0.621 ms Concave single-contour polygons: New: 5 vert, 1 cntr, 3 tri, 0 strip, 1 fan, 0 ind, 0.052 ms Old: 5 vert, 1 cntr, 3 tri, 0 strip, 0 fan, 3 ind, 0.252 ms New: 19 vert, 1 cntr, 17 tri, 2 strip, 2 fan, 1 ind, 0.911 ms Old: 19 vert, 1 cntr, 17 tri, 0 strip, 0 fan, 17 ind, 0.529 ms New: 151 vert, 1 cntr, 149 tri, 13 strip, 18 fan, 3 ind, 6.82 ms Old: 151 vert, 1 cntr, 149 tri, 0 strip, 3 fan, 143 ind, 2.7 ms New: 574 vert, 1 cntr, 572 tri, 59 strip, 54 fan, 11 ind, 26.6 ms Old: 574 vert, 1 cntr, 572 tri, 0 strip, 31 fan, 499 ind, 12.4 ms Multiple contours, but no intersections: New: 7 vert, 2 cntr, 7 tri, 1 strip, 0 fan, 0 ind, 0.527 ms Old: 7 vert, 2 cntr, 7 tri, 0 strip, 0 fan, 7 ind, 0.274 ms New: 81 vert, 6 cntr, 89 tri, 9 strip, 7 fan, 6 ind, 3.88 ms Old: 81 vert, 6 cntr, 89 tri, 0 strip, 13 fan, 61 ind, 2.2 ms New: 391 vert, 19 cntr, 413 tri, 37 strip, 32 fan, 26 ind, 20.2 ms Old: 391 vert, 19 cntr, 413 tri, 0 strip, 25 fan, 363 ind, 8.68 ms Self-intersecting and degenerate examples: Bowtie: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.483 ms Star: 5 vert, 1 cntr, 5 tri, 0 strip, 0 fan, 5 ind, 0.91 ms Random: 24 vert, 7 cntr, 46 tri, 2 strip, 12 fan, 7 ind, 5.32 ms Font: 333 vert, 2 cntr, 331 tri, 32 strip, 16 fan, 3 ind, 14.1 ms : 167 vert, 35 cntr, 254 tri, 8 strip, 56 fan, 52 ind, 46.3 ms : 78 vert, 1 cntr, 2675 tri, 148 strip, 207 fan, 180 ind, 243 ms : 12480 vert, 2 cntr, 12478 tri, 736 strip,1275 fan, 5 ind, 1010 ms muffin-5.2.1/cogl/cogl-path/tesselator/priorityq-heap.h0000664000175000017500000001001714211404421023250 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __priorityq_heap_h_ #define __priorityq_heap_h_ /* Use #define's so that another heap implementation can use this one */ #define PQkey PQHeapKey #define PQhandle PQHeapHandle #define PriorityQ PriorityQHeap #define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq) #define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq) /* The basic operations are insertion of a new key (pqInsert), * and examination/extraction of a key whose value is minimum * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); * for this purpose pqInsert returns a "handle" which is supplied * as the argument. * * An initial heap may be created efficiently by calling pqInsert * repeatedly, then calling pqInit. In any case pqInit must be called * before any operations other than pqInsert are used. * * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. * This may also be tested with pqIsEmpty. */ #define pqInit(pq) __gl_pqHeapInit(pq) #define pqInsert(pq,key) __gl_pqHeapInsert(pq,key) #define pqMinimum(pq) __gl_pqHeapMinimum(pq) #define pqExtractMin(pq) __gl_pqHeapExtractMin(pq) #define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle) #define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq) /* Since we support deletion the data structure is a little more * complicated than an ordinary heap. "nodes" is the heap itself; * active nodes are stored in the range 1..pq->size. When the * heap exceeds its allocated size (pq->max), its size doubles. * The children of node i are nodes 2i and 2i+1. * * Each node stores an index into an array "handles". Each handle * stores a key, plus a pointer back to the node which currently * represents that key (ie. nodes[handles[i].node].handle == i). */ typedef void *PQkey; typedef long PQhandle; typedef struct PriorityQ PriorityQ; typedef struct { PQhandle handle; } PQnode; typedef struct { PQkey key; PQhandle node; } PQhandleElem; struct PriorityQ { PQnode *nodes; PQhandleElem *handles; long size, max; PQhandle freeList; int initialized; int (*leq)(PQkey key1, PQkey key2); }; PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); void pqDeletePriorityQ( PriorityQ *pq ); void pqInit( PriorityQ *pq ); PQhandle pqInsert( PriorityQ *pq, PQkey key ); PQkey pqExtractMin( PriorityQ *pq ); void pqDelete( PriorityQ *pq, PQhandle handle ); #define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key) #define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0) #endif muffin-5.2.1/cogl/cogl-path/tesselator/geom.h0000664000175000017500000000651414211404421021231 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __geom_h_ #define __geom_h_ #include "mesh.h" #ifdef NO_BRANCH_CONDITIONS /* MIPS architecture has special instructions to evaluate boolean * conditions -- more efficient than branching, IF you can get the * compiler to generate the right instructions (SGI compiler doesn't) */ #define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t)) #define VertLeq(u,v) (((u)->s < (v)->s) | \ ((u)->s == (v)->s & (u)->t <= (v)->t)) #else #define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t) #define VertLeq(u,v) (((u)->s < (v)->s) || \ ((u)->s == (v)->s && (u)->t <= (v)->t)) #endif #define EdgeEval(u,v,w) __gl_edgeEval(u,v,w) #define EdgeSign(u,v,w) __gl_edgeSign(u,v,w) /* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */ #define TransLeq(u,v) (((u)->t < (v)->t) || \ ((u)->t == (v)->t && (u)->s <= (v)->s)) #define TransEval(u,v,w) __gl_transEval(u,v,w) #define TransSign(u,v,w) __gl_transSign(u,v,w) #define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org ) #define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst ) #undef ABS #define ABS(x) ((x) < 0 ? -(x) : (x)) #define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t)) #define VertCCW(u,v,w) __gl_vertCCW(u,v,w) int __gl_vertLeq( GLUvertex *u, GLUvertex *v ); GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ); void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, GLUvertex *o2, GLUvertex *d2, GLUvertex *v ); #endif muffin-5.2.1/cogl/cogl-path/tesselator/normal.c0000664000175000017500000001713614211404421021567 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include "mesh.h" #include "tess.h" #include "normal.h" #include #include #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2]) #if 0 static void Normalize( GLdouble v[3] ) { GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; assert( len > 0 ); len = sqrt( len ); v[0] /= len; v[1] /= len; v[2] /= len; } #endif #undef ABS #define ABS(x) ((x) < 0 ? -(x) : (x)) static int LongAxis( GLdouble v[3] ) { int i = 0; if( ABS(v[1]) > ABS(v[0]) ) { i = 1; } if( ABS(v[2]) > ABS(v[i]) ) { i = 2; } return i; } static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] ) { GLUvertex *v, *v1, *v2; GLdouble c, tLen2, maxLen2; GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3]; GLUvertex *maxVert[3], *minVert[3]; GLUvertex *vHead = &tess->mesh->vHead; int i; maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD; minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD; for( v = vHead->next; v != vHead; v = v->next ) { for( i = 0; i < 3; ++i ) { c = v->coords[i]; if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; } if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; } } } /* Find two vertices separated by at least 1/sqrt(3) of the maximum * distance between any two vertices */ i = 0; if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; } if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; } if( minVal[i] >= maxVal[i] ) { /* All vertices are the same -- normal doesn't matter */ norm[0] = 0; norm[1] = 0; norm[2] = 1; return; } /* Look for a third vertex which forms the triangle with maximum area * (Length of normal == twice the triangle area) */ maxLen2 = 0; v1 = minVert[i]; v2 = maxVert[i]; d1[0] = v1->coords[0] - v2->coords[0]; d1[1] = v1->coords[1] - v2->coords[1]; d1[2] = v1->coords[2] - v2->coords[2]; for( v = vHead->next; v != vHead; v = v->next ) { d2[0] = v->coords[0] - v2->coords[0]; d2[1] = v->coords[1] - v2->coords[1]; d2[2] = v->coords[2] - v2->coords[2]; tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1]; tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2]; tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0]; tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2]; if( tLen2 > maxLen2 ) { maxLen2 = tLen2; norm[0] = tNorm[0]; norm[1] = tNorm[1]; norm[2] = tNorm[2]; } } if( maxLen2 <= 0 ) { /* All points lie on a single line -- any decent normal will do */ norm[0] = norm[1] = norm[2] = 0; norm[LongAxis(d1)] = 1; } } static void CheckOrientation( GLUtesselator *tess ) { GLdouble area; GLUface *f, *fHead = &tess->mesh->fHead; GLUvertex *v, *vHead = &tess->mesh->vHead; GLUhalfEdge *e; /* When we compute the normal automatically, we choose the orientation * so that the sum of the signed areas of all contours is non-negative. */ area = 0; for( f = fHead->next; f != fHead; f = f->next ) { e = f->anEdge; if( e->winding <= 0 ) continue; do { area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t); e = e->Lnext; } while( e != f->anEdge ); } if( area < 0 ) { /* Reverse the orientation by flipping all the t-coordinates */ for( v = vHead->next; v != vHead; v = v->next ) { v->t = - v->t; } tess->tUnit[0] = - tess->tUnit[0]; tess->tUnit[1] = - tess->tUnit[1]; tess->tUnit[2] = - tess->tUnit[2]; } } #ifdef FOR_TRITE_TEST_PROGRAM #include extern int RandomSweep; #define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0) #define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0) #else #if defined(SLANTED_SWEEP) /* The "feature merging" is not intended to be complete. There are * special cases where edges are nearly parallel to the sweep line * which are not implemented. The algorithm should still behave * robustly (ie. produce a reasonable tesselation) in the presence * of such edges, however it may miss features which could have been * merged. We could minimize this effect by choosing the sweep line * direction to be something unusual (ie. not parallel to one of the * coordinate axes). */ #define S_UNIT_X 0.50941539564955385 /* Pre-normalized */ #define S_UNIT_Y 0.86052074622010633 #else #define S_UNIT_X 1.0 #define S_UNIT_Y 0.0 #endif #endif /* Determine the polygon normal and project vertices onto the plane * of the polygon. */ void __gl_projectPolygon( GLUtesselator *tess ) { GLUvertex *v, *vHead = &tess->mesh->vHead; GLdouble norm[3]; GLdouble *sUnit, *tUnit; int i, computedNormal = FALSE; norm[0] = tess->normal[0]; norm[1] = tess->normal[1]; norm[2] = tess->normal[2]; if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { ComputeNormal( tess, norm ); computedNormal = TRUE; } sUnit = tess->sUnit; tUnit = tess->tUnit; i = LongAxis( norm ); #if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT) /* Choose the initial sUnit vector to be approximately perpendicular * to the normal. */ Normalize( norm ); sUnit[i] = 0; sUnit[(i+1)%3] = S_UNIT_X; sUnit[(i+2)%3] = S_UNIT_Y; /* Now make it exactly perpendicular */ w = Dot( sUnit, norm ); sUnit[0] -= w * norm[0]; sUnit[1] -= w * norm[1]; sUnit[2] -= w * norm[2]; Normalize( sUnit ); /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1]; tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2]; tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0]; Normalize( tUnit ); #else /* Project perpendicular to a coordinate axis -- better numerically */ sUnit[i] = 0; sUnit[(i+1)%3] = S_UNIT_X; sUnit[(i+2)%3] = S_UNIT_Y; tUnit[i] = 0; tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y; tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X; #endif /* Project the vertices onto the sweep plane */ for( v = vHead->next; v != vHead; v = v->next ) { v->s = Dot( v->coords, sUnit ); v->t = Dot( v->coords, tUnit ); } if( computedNormal ) { CheckOrientation( tess ); } } muffin-5.2.1/cogl/cogl-path/tesselator/dict-list.h0000664000175000017500000000671014211404421022174 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __dict_list_h_ #define __dict_list_h_ /* Use #define's so that another heap implementation can use this one */ #define DictKey DictListKey #define Dict DictList #define DictNode DictListNode #define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) #define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) #define dictSearch(dict,key) __gl_dictListSearch(dict,key) #define dictInsert(dict,key) __gl_dictListInsert(dict,key) #define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) #define dictDelete(dict,node) __gl_dictListDelete(dict,node) #define dictKey(n) __gl_dictListKey(n) #define dictSucc(n) __gl_dictListSucc(n) #define dictPred(n) __gl_dictListPred(n) #define dictMin(d) __gl_dictListMin(d) #define dictMax(d) __gl_dictListMax(d) typedef void *DictKey; typedef struct Dict Dict; typedef struct DictNode DictNode; Dict *dictNewDict( void *frame, int (*leq)(void *frame, DictKey key1, DictKey key2) ); void dictDeleteDict( Dict *dict ); /* Search returns the node with the smallest key greater than or equal * to the given key. If there is no such key, returns a node whose * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. */ DictNode *dictSearch( Dict *dict, DictKey key ); DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); void dictDelete( Dict *dict, DictNode *node ); #define __gl_dictListKey(n) ((n)->key) #define __gl_dictListSucc(n) ((n)->next) #define __gl_dictListPred(n) ((n)->prev) #define __gl_dictListMin(d) ((d)->head.next) #define __gl_dictListMax(d) ((d)->head.prev) #define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) /*** Private data structures ***/ struct DictNode { DictKey key; DictNode *next; DictNode *prev; }; struct Dict { DictNode head; void *frame; int (*leq)(void *frame, DictKey key1, DictKey key2); }; #endif muffin-5.2.1/cogl/cogl-path/tesselator/sweep.h0000664000175000017500000000646314211404421021430 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __sweep_h_ #define __sweep_h_ #include "mesh.h" /* __gl_computeInterior( tess ) computes the planar arrangement specified * by the given contours, and further subdivides this arrangement * into regions. Each region is marked "inside" if it belongs * to the polygon, according to the rule given by tess->windingRule. * Each interior region is guaranteed be monotone. */ int __gl_computeInterior( GLUtesselator *tess ); /* The following is here *only* for access by debugging routines */ #include "dict.h" /* For each pair of adjacent edges crossing the sweep line, there is * an ActiveRegion to represent the region between them. The active * regions are kept in sorted order in a dynamic dictionary. As the * sweep line crosses each vertex, we update the affected regions. */ struct ActiveRegion { GLUhalfEdge *eUp; /* upper edge, directed right to left */ DictNode *nodeUp; /* dictionary node corresponding to eUp */ int windingNumber; /* used to determine which regions are * inside the polygon */ GLboolean inside; /* is this region inside the polygon? */ GLboolean sentinel; /* marks fake edges at t = +/-infinity */ GLboolean dirty; /* marks regions where the upper or lower * edge has changed, but we haven't checked * whether they intersect yet */ GLboolean fixUpperEdge; /* marks temporary edges introduced when * we process a "right vertex" (one without * any edges leaving to the right) */ }; #define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp))) #define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp))) #endif muffin-5.2.1/cogl/cogl-path/tesselator/tess.c0000664000175000017500000004230514211404421021251 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include #include #include #include "memalloc.h" #include "tess.h" #include "mesh.h" #include "normal.h" #include "sweep.h" #include "tessmono.h" #include "render.h" #define GLU_TESS_DEFAULT_TOLERANCE 0.0 #define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {} /*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {} /*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {} /*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {} /*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {} /*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4], GLfloat weight[4], void **dataOut ) {} /*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {} /*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData ) {} /*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData ) {} /*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData ) {} /*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {} /*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData ) {} /*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4], GLfloat weight[4], void **outData, void *polygonData ) {} /* Half-edges are allocated in pairs (see mesh.c) */ typedef struct { GLUhalfEdge e, eSym; } EdgePair; #undef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \ MAX(sizeof(GLUvertex),sizeof(GLUface)))) GLUtesselator * GLAPIENTRY gluNewTess( void ) { GLUtesselator *tess; /* Only initialize fields which can be changed by the api. Other fields * are initialized where they are used. */ if (memInit( MAX_FAST_ALLOC ) == 0) { return 0; /* out of memory */ } tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator )); if (tess == NULL) { return 0; /* out of memory */ } tess->state = T_DORMANT; tess->normal[0] = 0; tess->normal[1] = 0; tess->normal[2] = 0; tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE; tess->windingRule = GLU_TESS_WINDING_ODD; tess->flagBoundary = FALSE; tess->boundaryOnly = FALSE; tess->callBegin = &noBegin; tess->callEdgeFlag = &noEdgeFlag; tess->callVertex = &noVertex; tess->callEnd = &noEnd; tess->callError = &noError; tess->callCombine = &noCombine; tess->callMesh = &noMesh; tess->callBeginData= &__gl_noBeginData; tess->callEdgeFlagData= &__gl_noEdgeFlagData; tess->callVertexData= &__gl_noVertexData; tess->callEndData= &__gl_noEndData; tess->callErrorData= &__gl_noErrorData; tess->callCombineData= &__gl_noCombineData; tess->polygonData= NULL; return tess; } static void MakeDormant( GLUtesselator *tess ) { /* Return the tessellator to its original dormant state. */ if( tess->mesh != NULL ) { __gl_meshDeleteMesh( tess->mesh ); } tess->state = T_DORMANT; tess->lastEdge = NULL; tess->mesh = NULL; } #define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s) static void GotoState( GLUtesselator *tess, enum TessState newState ) { while( tess->state != newState ) { /* We change the current state one level at a time, to get to * the desired state. */ if( tess->state < newState ) { switch( tess->state ) { case T_DORMANT: CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON ); gluTessBeginPolygon( tess, NULL ); break; case T_IN_POLYGON: CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR ); gluTessBeginContour( tess ); break; default: ; } } else { switch( tess->state ) { case T_IN_CONTOUR: CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR ); gluTessEndContour( tess ); break; case T_IN_POLYGON: CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON ); /* gluTessEndPolygon( tess ) is too much work! */ MakeDormant( tess ); break; default: ; } } } } void GLAPIENTRY gluDeleteTess( GLUtesselator *tess ) { RequireState( tess, T_DORMANT ); memFree( tess ); } void GLAPIENTRY gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value ) { GLenum windingRule; switch( which ) { case GLU_TESS_TOLERANCE: if( value < 0.0 || value > 1.0 ) break; tess->relTolerance = value; return; case GLU_TESS_WINDING_RULE: windingRule = (GLenum) value; if( windingRule != value ) break; /* not an integer */ switch( windingRule ) { case GLU_TESS_WINDING_ODD: case GLU_TESS_WINDING_NONZERO: case GLU_TESS_WINDING_POSITIVE: case GLU_TESS_WINDING_NEGATIVE: case GLU_TESS_WINDING_ABS_GEQ_TWO: tess->windingRule = windingRule; return; default: break; } case GLU_TESS_BOUNDARY_ONLY: tess->boundaryOnly = (value != 0); return; default: CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); return; } CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE ); } /* Returns tessellator property */ void GLAPIENTRY gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value ) { switch (which) { case GLU_TESS_TOLERANCE: /* tolerance should be in range [0..1] */ assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0); *value= tess->relTolerance; break; case GLU_TESS_WINDING_RULE: assert(tess->windingRule == GLU_TESS_WINDING_ODD || tess->windingRule == GLU_TESS_WINDING_NONZERO || tess->windingRule == GLU_TESS_WINDING_POSITIVE || tess->windingRule == GLU_TESS_WINDING_NEGATIVE || tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO); *value= tess->windingRule; break; case GLU_TESS_BOUNDARY_ONLY: assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE); *value= tess->boundaryOnly; break; default: *value= 0.0; CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); break; } } /* gluGetTessProperty() */ void GLAPIENTRY gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z ) { tess->normal[0] = x; tess->normal[1] = y; tess->normal[2] = z; } void GLAPIENTRY gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn) { switch( which ) { case GLU_TESS_BEGIN: tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn; return; case GLU_TESS_BEGIN_DATA: tess->callBeginData = (fn == NULL) ? &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn; return; case GLU_TESS_EDGE_FLAG: tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag : (void (GLAPIENTRY *)(GLboolean)) fn; /* If the client wants boundary edges to be flagged, * we render everything as separate triangles (no strips or fans). */ tess->flagBoundary = (fn != NULL); return; case GLU_TESS_EDGE_FLAG_DATA: tess->callEdgeFlagData= (fn == NULL) ? &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn; /* If the client wants boundary edges to be flagged, * we render everything as separate triangles (no strips or fans). */ tess->flagBoundary = (fn != NULL); return; case GLU_TESS_VERTEX: tess->callVertex = (fn == NULL) ? &noVertex : (void (GLAPIENTRY *)(void *)) fn; return; case GLU_TESS_VERTEX_DATA: tess->callVertexData = (fn == NULL) ? &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn; return; case GLU_TESS_END: tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn; return; case GLU_TESS_END_DATA: tess->callEndData = (fn == NULL) ? &__gl_noEndData : (void (GLAPIENTRY *)(void *)) fn; return; case GLU_TESS_ERROR: tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn; return; case GLU_TESS_ERROR_DATA: tess->callErrorData = (fn == NULL) ? &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn; return; case GLU_TESS_COMBINE: tess->callCombine = (fn == NULL) ? &noCombine : (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn; return; case GLU_TESS_COMBINE_DATA: tess->callCombineData = (fn == NULL) ? &__gl_noCombineData : (void (GLAPIENTRY *)(GLdouble [3], void *[4], GLfloat [4], void **, void *)) fn; return; case GLU_TESS_MESH: tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn; return; default: CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); return; } } static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) { GLUhalfEdge *e; e = tess->lastEdge; if( e == NULL ) { /* Make a self-loop (one vertex, one edge). */ e = __gl_meshMakeEdge( tess->mesh ); if (e == NULL) return 0; if ( !__gl_meshSplice( e, e->Sym ) ) return 0; } else { /* Create a new vertex and edge which immediately follow e * in the ordering around the left face. */ if (__gl_meshSplitEdge( e ) == NULL) return 0; e = e->Lnext; } /* The new vertex is now e->Org. */ e->Org->data = data; e->Org->coords[0] = coords[0]; e->Org->coords[1] = coords[1]; e->Org->coords[2] = coords[2]; /* The winding of an edge says how the winding number changes as we * cross from the edge''s right face to its left face. We add the * vertices in such an order that a CCW contour will add +1 to * the winding number of the region inside the contour. */ e->winding = 1; e->Sym->winding = -1; tess->lastEdge = e; return 1; } static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) { CachedVertex *v = &tess->cache[tess->cacheCount]; v->data = data; v->coords[0] = coords[0]; v->coords[1] = coords[1]; v->coords[2] = coords[2]; ++tess->cacheCount; } static int EmptyCache( GLUtesselator *tess ) { CachedVertex *v = tess->cache; CachedVertex *vLast; tess->mesh = __gl_meshNewMesh(); if (tess->mesh == NULL) return 0; for( vLast = v + tess->cacheCount; v < vLast; ++v ) { if ( !AddVertex( tess, v->coords, v->data ) ) return 0; } tess->cacheCount = 0; tess->emptyCache = FALSE; return 1; } void GLAPIENTRY gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) { int i, tooLarge = FALSE; GLdouble x, clamped[3]; RequireState( tess, T_IN_CONTOUR ); if( tess->emptyCache ) { if ( !EmptyCache( tess ) ) { CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); return; } tess->lastEdge = NULL; } for( i = 0; i < 3; ++i ) { x = coords[i]; if( x < - GLU_TESS_MAX_COORD ) { x = - GLU_TESS_MAX_COORD; tooLarge = TRUE; } if( x > GLU_TESS_MAX_COORD ) { x = GLU_TESS_MAX_COORD; tooLarge = TRUE; } clamped[i] = x; } if( tooLarge ) { CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE ); } if( tess->mesh == NULL ) { if( tess->cacheCount < TESS_MAX_CACHE ) { CacheVertex( tess, clamped, data ); return; } if ( !EmptyCache( tess ) ) { CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); return; } } if ( !AddVertex( tess, clamped, data ) ) { CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); } } void GLAPIENTRY gluTessBeginPolygon( GLUtesselator *tess, void *data ) { RequireState( tess, T_DORMANT ); tess->state = T_IN_POLYGON; tess->cacheCount = 0; tess->emptyCache = FALSE; tess->mesh = NULL; tess->polygonData= data; } void GLAPIENTRY gluTessBeginContour( GLUtesselator *tess ) { RequireState( tess, T_IN_POLYGON ); tess->state = T_IN_CONTOUR; tess->lastEdge = NULL; if( tess->cacheCount > 0 ) { /* Just set a flag so we don't get confused by empty contours * -- these can be generated accidentally with the obsolete * NextContour() interface. */ tess->emptyCache = TRUE; } } void GLAPIENTRY gluTessEndContour( GLUtesselator *tess ) { RequireState( tess, T_IN_CONTOUR ); tess->state = T_IN_POLYGON; } void GLAPIENTRY gluTessEndPolygon( GLUtesselator *tess ) { GLUmesh *mesh; if (setjmp(tess->env) != 0) { /* come back here if out of memory */ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); return; } RequireState( tess, T_IN_POLYGON ); tess->state = T_DORMANT; if( tess->mesh == NULL ) { if( ! tess->flagBoundary && tess->callMesh == &noMesh ) { /* Try some special code to make the easy cases go quickly * (eg. convex polygons). This code does NOT handle multiple contours, * intersections, edge flags, and of course it does not generate * an explicit mesh either. */ if( __gl_renderCache( tess )) { tess->polygonData= NULL; return; } } if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/ } /* Determine the polygon normal and project vertices onto the plane * of the polygon. */ __gl_projectPolygon( tess ); /* __gl_computeInterior( tess ) computes the planar arrangement specified * by the given contours, and further subdivides this arrangement * into regions. Each region is marked "inside" if it belongs * to the polygon, according to the rule given by tess->windingRule. * Each interior region is guaranteed be monotone. */ if ( !__gl_computeInterior( tess ) ) { longjmp(tess->env,1); /* could've used a label */ } mesh = tess->mesh; if( ! tess->fatalError ) { int rc = 1; /* If the user wants only the boundary contours, we throw away all edges * except those which separate the interior from the exterior. * Otherwise we tessellate all the regions marked "inside". */ if( tess->boundaryOnly ) { rc = __gl_meshSetWindingNumber( mesh, 1, TRUE ); } else { rc = __gl_meshTessellateInterior( mesh ); } if (rc == 0) longjmp(tess->env,1); /* could've used a label */ __gl_meshCheckMesh( mesh ); if( tess->callBegin != &noBegin || tess->callEnd != &noEnd || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag || tess->callBeginData != &__gl_noBeginData || tess->callEndData != &__gl_noEndData || tess->callVertexData != &__gl_noVertexData || tess->callEdgeFlagData != &__gl_noEdgeFlagData ) { if( tess->boundaryOnly ) { __gl_renderBoundary( tess, mesh ); /* output boundary contours */ } else { __gl_renderMesh( tess, mesh ); /* output strips and fans */ } } if( tess->callMesh != &noMesh ) { /* Throw away the exterior faces, so that all faces are interior. * This way the user doesn't have to check the "inside" flag, * and we don't need to even reveal its existence. It also leaves * the freedom for an implementation to not generate the exterior * faces in the first place. */ __gl_meshDiscardExterior( mesh ); (*tess->callMesh)( mesh ); /* user wants the mesh itself */ tess->mesh = NULL; tess->polygonData= NULL; return; } } __gl_meshDeleteMesh( mesh ); tess->polygonData= NULL; tess->mesh = NULL; } /*XXXblythe unused function*/ #if 0 void GLAPIENTRY gluDeleteMesh( GLUmesh *mesh ) { __gl_meshDeleteMesh( mesh ); } #endif /*******************************************************/ /* Obsolete calls -- for backward compatibility */ void GLAPIENTRY gluBeginPolygon( GLUtesselator *tess ) { gluTessBeginPolygon( tess, NULL ); gluTessBeginContour( tess ); } /*ARGSUSED*/ void GLAPIENTRY gluNextContour( GLUtesselator *tess, GLenum type ) { gluTessEndContour( tess ); gluTessBeginContour( tess ); } void GLAPIENTRY gluEndPolygon( GLUtesselator *tess ) { gluTessEndContour( tess ); gluTessEndPolygon( tess ); } muffin-5.2.1/cogl/cogl-path/tesselator/dict.c0000664000175000017500000000620314211404421021213 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include #include "dict-list.h" #include "memalloc.h" /* really __gl_dictListNewDict */ Dict *dictNewDict( void *frame, int (*leq)(void *frame, DictKey key1, DictKey key2) ) { Dict *dict = (Dict *) memAlloc( sizeof( Dict )); DictNode *head; if (dict == NULL) return NULL; head = &dict->head; head->key = NULL; head->next = head; head->prev = head; dict->frame = frame; dict->leq = leq; return dict; } /* really __gl_dictListDeleteDict */ void dictDeleteDict( Dict *dict ) { DictNode *node, *next; for( node = dict->head.next; node != &dict->head; node = next ) { next = node->next; memFree( node ); } memFree( dict ); } /* really __gl_dictListInsertBefore */ DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) { DictNode *newNode; do { node = node->prev; } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key)); newNode = (DictNode *) memAlloc( sizeof( DictNode )); if (newNode == NULL) return NULL; newNode->key = key; newNode->next = node->next; node->next->prev = newNode; newNode->prev = node; node->next = newNode; return newNode; } /* really __gl_dictListDelete */ void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/ { node->next->prev = node->prev; node->prev->next = node->next; memFree( node ); } /* really __gl_dictListSearch */ DictNode *dictSearch( Dict *dict, DictKey key ) { DictNode *node = &dict->head; do { node = node->next; } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key)); return node; } muffin-5.2.1/cogl/cogl-path/tesselator/tessmono.h0000664000175000017500000000616014211404421022146 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __tessmono_h_ #define __tessmono_h_ /* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region * (what else would it do??) The region must consist of a single * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this * case means that any vertical line intersects the interior of the * region in a single interval. * * Tessellation consists of adding interior edges (actually pairs of * half-edges), to split the region into non-overlapping triangles. * * __gl_meshTessellateInterior( mesh ) tessellates each region of * the mesh which is marked "inside" the polygon. Each such region * must be monotone. * * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces * which are not marked "inside" the polygon. Since further mesh operations * on NULL faces are not allowed, the main purpose is to clean up the * mesh so that exterior loops are not represented in the data structure. * * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the * winding numbers on all edges so that regions marked "inside" the * polygon have a winding number of "value", and regions outside * have a winding number of 0. * * If keepOnlyBoundary is TRUE, it also deletes all edges which do not * separate an interior region from an exterior one. */ int __gl_meshTessellateMonoRegion( GLUface *face ); int __gl_meshTessellateInterior( GLUmesh *mesh ); void __gl_meshDiscardExterior( GLUmesh *mesh ); int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, GLboolean keepOnlyBoundary ); #endif muffin-5.2.1/cogl/cogl-path/tesselator/tess.h0000664000175000017500000001444514211404421021262 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __tess_h_ #define __tess_h_ #include #include #include "mesh.h" #include "dict.h" #include "priorityq.h" /* The begin/end calls must be properly nested. We keep track of * the current state to enforce the ordering. */ enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR }; /* We cache vertex data for single-contour polygons so that we can * try a quick-and-dirty decomposition first. */ #define TESS_MAX_CACHE 100 typedef struct CachedVertex { GLdouble coords[3]; void *data; } CachedVertex; struct GLUtesselator { /*** state needed for collecting the input data ***/ enum TessState state; /* what begin/end calls have we seen? */ GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */ GLUmesh *mesh; /* stores the input contours, and eventually the tessellation itself */ void (GLAPIENTRY *callError)( GLenum errnum ); /*** state needed for projecting onto the sweep plane ***/ GLdouble normal[3]; /* user-specified normal (if provided) */ GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */ GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */ /*** state needed for the line sweep ***/ GLdouble relTolerance; /* tolerance for merging features */ GLenum windingRule; /* rule for determining polygon interior */ GLboolean fatalError; /* fatal error: needed combine callback */ Dict *dict; /* edge dictionary for sweep line */ PriorityQ *pq; /* priority queue of vertex events */ GLUvertex *event; /* current sweep event being processed */ void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4], GLfloat weight[4], void **outData ); /*** state needed for rendering callbacks (see render.c) ***/ GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */ GLboolean boundaryOnly; /* Extract contours, not triangles */ GLUface *lonelyTriList; /* list of triangles which could not be rendered as strips or fans */ void (GLAPIENTRY *callBegin)( GLenum type ); void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge ); void (GLAPIENTRY *callVertex)( void *data ); void (GLAPIENTRY *callEnd)( void ); void (GLAPIENTRY *callMesh)( GLUmesh *mesh ); /*** state needed to cache single-contour polygons for renderCache() */ GLboolean emptyCache; /* empty cache on next vertex() call */ int cacheCount; /* number of cached vertices */ CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */ /*** rendering callbacks that also pass polygon data ***/ void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData ); void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge, void *polygonData ); void (GLAPIENTRY *callVertexData)( void *data, void *polygonData ); void (GLAPIENTRY *callEndData)( void *polygonData ); void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData ); void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4], GLfloat weight[4], void **outData, void *polygonData ); jmp_buf env; /* place to jump to when memAllocs fail */ void *polygonData; /* client data for current polygon */ }; void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData ); void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData ); void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData ); void GLAPIENTRY __gl_noEndData( void *polygonData ); void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData ); void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4], GLfloat weight[4], void **outData, void *polygonData ); #define CALL_BEGIN_OR_BEGIN_DATA(a) \ if (tess->callBeginData != &__gl_noBeginData) \ (*tess->callBeginData)((a),tess->polygonData); \ else (*tess->callBegin)((a)); #define CALL_VERTEX_OR_VERTEX_DATA(a) \ if (tess->callVertexData != &__gl_noVertexData) \ (*tess->callVertexData)((a),tess->polygonData); \ else (*tess->callVertex)((a)); #define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \ if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \ (*tess->callEdgeFlagData)((a),tess->polygonData); \ else (*tess->callEdgeFlag)((a)); #define CALL_END_OR_END_DATA() \ if (tess->callEndData != &__gl_noEndData) \ (*tess->callEndData)(tess->polygonData); \ else (*tess->callEnd)(); #define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \ if (tess->callCombineData != &__gl_noCombineData) \ (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \ else (*tess->callCombine)((a),(b),(c),(d)); #define CALL_ERROR_OR_ERROR_DATA(a) \ if (tess->callErrorData != &__gl_noErrorData) \ (*tess->callErrorData)((a),tess->polygonData); \ else (*tess->callError)((a)); #endif muffin-5.2.1/cogl/cogl-path/tesselator/gluos.h0000664000175000017500000000007514211404421021427 0ustar jpeisachjpeisach/* This is a stub header to avoid having to change tess.c */ muffin-5.2.1/cogl/cogl-path/tesselator/priorityq-sort.h0000664000175000017500000001012614211404421023323 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __priorityq_sort_h_ #define __priorityq_sort_h_ #include "priorityq-heap.h" #undef PQkey #undef PQhandle #undef PriorityQ #undef pqNewPriorityQ #undef pqDeletePriorityQ #undef pqInit #undef pqInsert #undef pqMinimum #undef pqExtractMin #undef pqDelete #undef pqIsEmpty /* Use #define's so that another heap implementation can use this one */ #define PQkey PQSortKey #define PQhandle PQSortHandle #define PriorityQ PriorityQSort #define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) #define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) /* The basic operations are insertion of a new key (pqInsert), * and examination/extraction of a key whose value is minimum * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); * for this purpose pqInsert returns a "handle" which is supplied * as the argument. * * An initial heap may be created efficiently by calling pqInsert * repeatedly, then calling pqInit. In any case pqInit must be called * before any operations other than pqInsert are used. * * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. * This may also be tested with pqIsEmpty. */ #define pqInit(pq) __gl_pqSortInit(pq) #define pqInsert(pq,key) __gl_pqSortInsert(pq,key) #define pqMinimum(pq) __gl_pqSortMinimum(pq) #define pqExtractMin(pq) __gl_pqSortExtractMin(pq) #define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) #define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) /* Since we support deletion the data structure is a little more * complicated than an ordinary heap. "nodes" is the heap itself; * active nodes are stored in the range 1..pq->size. When the * heap exceeds its allocated size (pq->max), its size doubles. * The children of node i are nodes 2i and 2i+1. * * Each node stores an index into an array "handles". Each handle * stores a key, plus a pointer back to the node which currently * represents that key (ie. nodes[handles[i].node].handle == i). */ typedef PQHeapKey PQkey; typedef PQHeapHandle PQhandle; typedef struct PriorityQ PriorityQ; struct PriorityQ { PriorityQHeap *heap; PQkey *keys; PQkey **order; PQhandle size, max; int initialized; int (*leq)(PQkey key1, PQkey key2); }; PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); void pqDeletePriorityQ( PriorityQ *pq ); int pqInit( PriorityQ *pq ); PQhandle pqInsert( PriorityQ *pq, PQkey key ); PQkey pqExtractMin( PriorityQ *pq ); void pqDelete( PriorityQ *pq, PQhandle handle ); PQkey pqMinimum( PriorityQ *pq ); int pqIsEmpty( PriorityQ *pq ); #endif muffin-5.2.1/cogl/cogl-path/tesselator/tessmono.c0000664000175000017500000001611614211404421022143 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include #include "geom.h" #include "mesh.h" #include "tessmono.h" #include #define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ eDst->Sym->winding += eSrc->Sym->winding) /* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region * (what else would it do??) The region must consist of a single * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this * case means that any vertical line intersects the interior of the * region in a single interval. * * Tessellation consists of adding interior edges (actually pairs of * half-edges), to split the region into non-overlapping triangles. * * The basic idea is explained in Preparata and Shamos (which I don''t * have handy right now), although their implementation is more * complicated than this one. The are two edge chains, an upper chain * and a lower chain. We process all vertices from both chains in order, * from right to left. * * The algorithm ensures that the following invariant holds after each * vertex is processed: the untessellated region consists of two * chains, where one chain (say the upper) is a single edge, and * the other chain is concave. The left vertex of the single edge * is always to the left of all vertices in the concave chain. * * Each step consists of adding the rightmost unprocessed vertex to one * of the two chains, and forming a fan of triangles from the rightmost * of two chain endpoints. Determining whether we can add each triangle * to the fan is a simple orientation test. By making the fan as large * as possible, we restore the invariant (check it yourself). */ int __gl_meshTessellateMonoRegion( GLUface *face ) { GLUhalfEdge *up, *lo; /* All edges are oriented CCW around the boundary of the region. * First, find the half-edge whose origin vertex is rightmost. * Since the sweep goes from left to right, face->anEdge should * be close to the edge we want. */ up = face->anEdge; assert( up->Lnext != up && up->Lnext->Lnext != up ); for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev ) ; for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext ) ; lo = up->Lprev; while( up->Lnext != lo ) { if( VertLeq( up->Dst, lo->Org )) { /* up->Dst is on the left. It is safe to form triangles from lo->Org. * The EdgeGoesLeft test guarantees progress even when some triangles * are CW, given that the upper and lower chains are truly monotone. */ while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext ) || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) { GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); if (tempHalfEdge == NULL) return 0; lo = tempHalfEdge->Sym; } lo = lo->Lprev; } else { /* lo->Org is on the left. We can make CCW triangles from up->Dst. */ while( lo->Lnext != up && (EdgeGoesRight( up->Lprev ) || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) { GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev ); if (tempHalfEdge == NULL) return 0; up = tempHalfEdge->Sym; } up = up->Lnext; } } /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region * can be tessellated in a fan from this leftmost vertex. */ assert( lo->Lnext != up ); while( lo->Lnext->Lnext != up ) { GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); if (tempHalfEdge == NULL) return 0; lo = tempHalfEdge->Sym; } return 1; } /* __gl_meshTessellateInterior( mesh ) tessellates each region of * the mesh which is marked "inside" the polygon. Each such region * must be monotone. */ int __gl_meshTessellateInterior( GLUmesh *mesh ) { GLUface *f, *next; /*LINTED*/ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { /* Make sure we don''t try to tessellate the new triangles. */ next = f->next; if( f->inside ) { if ( !__gl_meshTessellateMonoRegion( f ) ) return 0; } } return 1; } /* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces * which are not marked "inside" the polygon. Since further mesh operations * on NULL faces are not allowed, the main purpose is to clean up the * mesh so that exterior loops are not represented in the data structure. */ void __gl_meshDiscardExterior( GLUmesh *mesh ) { GLUface *f, *next; /*LINTED*/ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { /* Since f will be destroyed, save its next pointer. */ next = f->next; if( ! f->inside ) { __gl_meshZapFace( f ); } } } #define MARKED_FOR_DELETION 0x7fffffff /* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the * winding numbers on all edges so that regions marked "inside" the * polygon have a winding number of "value", and regions outside * have a winding number of 0. * * If keepOnlyBoundary is TRUE, it also deletes all edges which do not * separate an interior region from an exterior one. */ int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, GLboolean keepOnlyBoundary ) { GLUhalfEdge *e, *eNext; for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { eNext = e->next; if( e->Rface->inside != e->Lface->inside ) { /* This is a boundary edge (one side is interior, one is exterior). */ e->winding = (e->Lface->inside) ? value : -value; } else { /* Both regions are interior, or both are exterior. */ if( ! keepOnlyBoundary ) { e->winding = 0; } else { if ( !__gl_meshDelete( e ) ) return 0; } } } return 1; } muffin-5.2.1/cogl/cogl-path/tesselator/render.h0000664000175000017500000000420414211404421021553 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __render_h_ #define __render_h_ #include "mesh.h" /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle * fans, strips, and separate triangles. A substantial effort is made * to use as few rendering primitives as possible (ie. to make the fans * and strips as large as possible). * * The rendering output is provided as callbacks (see the api). */ void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ); void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ); GLboolean __gl_renderCache( GLUtesselator *tess ); #endif muffin-5.2.1/cogl/cogl-path/tesselator/render.c0000664000175000017500000003674714211404421021567 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include #include #include "mesh.h" #include "tess.h" #include "render.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* This structure remembers the information we need about a primitive * to be able to render it later, once we have determined which * primitive is able to use the most triangles. */ struct FaceCount { long size; /* number of triangles used */ GLUhalfEdge *eStart; /* edge where this primitive starts */ void (*render)(GLUtesselator *, GLUhalfEdge *, long); /* routine to render this primitive */ }; static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ); static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ); static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ); static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head ); /************************ Strips and Fans decomposition ******************/ /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle * fans, strips, and separate triangles. A substantial effort is made * to use as few rendering primitives as possible (ie. to make the fans * and strips as large as possible). * * The rendering output is provided as callbacks (see the api). */ void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ) { GLUface *f; /* Make a list of separate triangles so we can render them all at once */ tess->lonelyTriList = NULL; for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { f->marked = FALSE; } for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { /* We examine all faces in an arbitrary order. Whenever we find * an unprocessed face F, we output a group of faces including F * whose size is maximum. */ if( f->inside && ! f->marked ) { RenderMaximumFaceGroup( tess, f ); assert( f->marked ); } } if( tess->lonelyTriList != NULL ) { RenderLonelyTriangles( tess, tess->lonelyTriList ); tess->lonelyTriList = NULL; } } static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ) { /* We want to find the largest triangle fan or strip of unmarked faces * which includes the given face fOrig. There are 3 possible fans * passing through fOrig (one centered at each vertex), and 3 possible * strips (one for each CCW permutation of the vertices). Our strategy * is to try all of these, and take the primitive which uses the most * triangles (a greedy approach). */ GLUhalfEdge *e = fOrig->anEdge; struct FaceCount max, newFace; max.size = 1; max.eStart = e; max.render = &RenderTriangle; if( ! tess->flagBoundary ) { newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; } newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; } newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } } (*(max.render))( tess, max.eStart, max.size ); } /* Macros which keep track of faces we have marked temporarily, and allow * us to backtrack when necessary. With triangle fans, this is not * really necessary, since the only awkward case is a loop of triangles * around a single origin vertex. However with strips the situation is * more complicated, and we need a general tracking method like the * one here. */ #define Marked(f) (! (f)->inside || (f)->marked) #define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE) #define FreeTrail(t) do { \ while( (t) != NULL ) { \ (t)->marked = FALSE; t = (t)->trail; \ } \ } while(0) /* absorb trailing semicolon */ static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ) { /* eOrig->Lface is the face we want to render. We want to find the size * of a maximal fan around eOrig->Org. To do this we just walk around * the origin vertex as far as possible in both directions. */ struct FaceCount newFace = { 0, NULL, &RenderFan }; GLUface *trail = NULL; GLUhalfEdge *e; for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) { AddToTrail( e->Lface, trail ); ++newFace.size; } for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) { AddToTrail( e->Rface, trail ); ++newFace.size; } newFace.eStart = e; /*LINTED*/ FreeTrail( trail ); return newFace; } #define IsEven(n) (((n) & 1) == 0) static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ) { /* Here we are looking for a maximal strip that contains the vertices * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the * reverse, such that all triangles are oriented CCW). * * Again we walk forward and backward as far as possible. However for * strips there is a twist: to get CCW orientations, there must be * an *even* number of triangles in the strip on one side of eOrig. * We walk the strip starting on a side with an even number of triangles; * if both side have an odd number, we are forced to shorten one side. */ struct FaceCount newFace = { 0, NULL, &RenderStrip }; long headSize = 0, tailSize = 0; GLUface *trail = NULL; GLUhalfEdge *e, *eTail, *eHead; for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) { AddToTrail( e->Lface, trail ); ++tailSize; e = e->Dprev; if( Marked( e->Lface )) break; AddToTrail( e->Lface, trail ); } eTail = e; for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) { AddToTrail( e->Rface, trail ); ++headSize; e = e->Oprev; if( Marked( e->Rface )) break; AddToTrail( e->Rface, trail ); } eHead = e; newFace.size = tailSize + headSize; if( IsEven( tailSize )) { newFace.eStart = eTail->Sym; } else if( IsEven( headSize )) { newFace.eStart = eHead; } else { /* Both sides have odd length, we must shorten one of them. In fact, * we must start from eHead to guarantee inclusion of eOrig->Lface. */ --newFace.size; newFace.eStart = eHead->Onext; } /*LINTED*/ FreeTrail( trail ); return newFace; } static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size ) { /* Just add the triangle to a triangle list, so we can render all * the separate triangles at once. */ assert( size == 1 ); AddToTrail( e->Lface, tess->lonelyTriList ); } static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f ) { /* Now we render all the separate triangles which could not be * grouped into a triangle fan or strip. */ GLUhalfEdge *e; int newState; int edgeState = -1; /* force edge state output for first vertex */ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES ); for( ; f != NULL; f = f->trail ) { /* Loop once for each edge (there will always be 3 edges) */ e = f->anEdge; do { if( tess->flagBoundary ) { /* Set the "edge state" to TRUE just before we output the * first vertex of each edge on the polygon boundary. */ newState = ! e->Rface->inside; if( edgeState != newState ) { edgeState = newState; CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState ); } } CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); e = e->Lnext; } while( e != f->anEdge ); } CALL_END_OR_END_DATA(); } static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size ) { /* Render as many CCW triangles as possible in a fan starting from * edge "e". The fan *should* contain exactly "size" triangles * (otherwise we've goofed up somewhere). */ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN ); CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); while( ! Marked( e->Lface )) { e->Lface->marked = TRUE; --size; e = e->Onext; CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); } assert( size == 0 ); CALL_END_OR_END_DATA(); } static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size ) { /* Render as many CCW triangles as possible in a strip starting from * edge "e". The strip *should* contain exactly "size" triangles * (otherwise we've goofed up somewhere). */ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP ); CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); while( ! Marked( e->Lface )) { e->Lface->marked = TRUE; --size; e = e->Dprev; CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); if( Marked( e->Lface )) break; e->Lface->marked = TRUE; --size; e = e->Onext; CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); } assert( size == 0 ); CALL_END_OR_END_DATA(); } /************************ Boundary contour decomposition ******************/ /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one * contour for each face marked "inside". The rendering output is * provided as callbacks (see the api). */ void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ) { GLUface *f; GLUhalfEdge *e; for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { if( f->inside ) { CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP ); e = f->anEdge; do { CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); e = e->Lnext; } while( e != f->anEdge ); CALL_END_OR_END_DATA(); } } } /************************ Quick-and-dirty decomposition ******************/ #define SIGN_INCONSISTENT 2 static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check ) /* * If check==FALSE, we compute the polygon normal and place it in norm[]. * If check==TRUE, we check that each triangle in the fan from v0 has a * consistent orientation with respect to norm[]. If triangles are * consistently oriented CCW, return 1; if CW, return -1; if all triangles * are degenerate return 0; otherwise (no consistent orientation) return * SIGN_INCONSISTENT. */ { CachedVertex *v0 = tess->cache; CachedVertex *vn = v0 + tess->cacheCount; CachedVertex *vc; GLdouble dot, xc, yc, zc, xp, yp, zp, n[3]; int sign = 0; /* Find the polygon normal. It is important to get a reasonable * normal even when the polygon is self-intersecting (eg. a bowtie). * Otherwise, the computed normal could be very tiny, but perpendicular * to the true plane of the polygon due to numerical noise. Then all * the triangles would appear to be degenerate and we would incorrectly * decompose the polygon as a fan (or simply not render it at all). * * We use a sum-of-triangles normal algorithm rather than the more * efficient sum-of-trapezoids method (used in CheckOrientation() * in normal.c). This lets us explicitly reverse the signed area * of some triangles to get a reasonable normal in the self-intersecting * case. */ if( ! check ) { norm[0] = norm[1] = norm[2] = 0.0; } vc = v0 + 1; xc = vc->coords[0] - v0->coords[0]; yc = vc->coords[1] - v0->coords[1]; zc = vc->coords[2] - v0->coords[2]; while( ++vc < vn ) { xp = xc; yp = yc; zp = zc; xc = vc->coords[0] - v0->coords[0]; yc = vc->coords[1] - v0->coords[1]; zc = vc->coords[2] - v0->coords[2]; /* Compute (vp - v0) cross (vc - v0) */ n[0] = yp*zc - zp*yc; n[1] = zp*xc - xp*zc; n[2] = xp*yc - yp*xc; dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2]; if( ! check ) { /* Reverse the contribution of back-facing triangles to get * a reasonable normal for self-intersecting polygons (see above) */ if( dot >= 0 ) { norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2]; } else { norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2]; } } else if( dot != 0 ) { /* Check the new orientation for consistency with previous triangles */ if( dot > 0 ) { if( sign < 0 ) return SIGN_INCONSISTENT; sign = 1; } else { if( sign > 0 ) return SIGN_INCONSISTENT; sign = -1; } } } return sign; } /* __gl_renderCache( tess ) takes a single contour and tries to render it * as a triangle fan. This handles convex polygons, as well as some * non-convex polygons if we get lucky. * * Returns TRUE if the polygon was successfully rendered. The rendering * output is provided as callbacks (see the api). */ GLboolean __gl_renderCache( GLUtesselator *tess ) { CachedVertex *v0 = tess->cache; CachedVertex *vn = v0 + tess->cacheCount; CachedVertex *vc; GLdouble norm[3]; int sign; if( tess->cacheCount < 3 ) { /* Degenerate contour -- no output */ return TRUE; } norm[0] = tess->normal[0]; norm[1] = tess->normal[1]; norm[2] = tess->normal[2]; if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { ComputeNormal( tess, norm, FALSE ); } sign = ComputeNormal( tess, norm, TRUE ); if( sign == SIGN_INCONSISTENT ) { /* Fan triangles did not have a consistent orientation */ return FALSE; } if( sign == 0 ) { /* All triangles were degenerate */ return TRUE; } /* Make sure we do the right thing for each winding rule */ switch( tess->windingRule ) { case GLU_TESS_WINDING_ODD: case GLU_TESS_WINDING_NONZERO: break; case GLU_TESS_WINDING_POSITIVE: if( sign < 0 ) return TRUE; break; case GLU_TESS_WINDING_NEGATIVE: if( sign > 0 ) return TRUE; break; case GLU_TESS_WINDING_ABS_GEQ_TWO: return TRUE; } CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN : GL_TRIANGLES ); CALL_VERTEX_OR_VERTEX_DATA( v0->data ); if( sign > 0 ) { for( vc = v0+1; vc < vn; ++vc ) { CALL_VERTEX_OR_VERTEX_DATA( vc->data ); } } else { for( vc = vn-1; vc > v0; --vc ) { CALL_VERTEX_OR_VERTEX_DATA( vc->data ); } } CALL_END_OR_END_DATA(); return TRUE; } muffin-5.2.1/cogl/cogl-path/tesselator/priorityq.h0000664000175000017500000001012614211404421022336 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __priorityq_sort_h_ #define __priorityq_sort_h_ #include "priorityq-heap.h" #undef PQkey #undef PQhandle #undef PriorityQ #undef pqNewPriorityQ #undef pqDeletePriorityQ #undef pqInit #undef pqInsert #undef pqMinimum #undef pqExtractMin #undef pqDelete #undef pqIsEmpty /* Use #define's so that another heap implementation can use this one */ #define PQkey PQSortKey #define PQhandle PQSortHandle #define PriorityQ PriorityQSort #define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) #define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) /* The basic operations are insertion of a new key (pqInsert), * and examination/extraction of a key whose value is minimum * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); * for this purpose pqInsert returns a "handle" which is supplied * as the argument. * * An initial heap may be created efficiently by calling pqInsert * repeatedly, then calling pqInit. In any case pqInit must be called * before any operations other than pqInsert are used. * * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. * This may also be tested with pqIsEmpty. */ #define pqInit(pq) __gl_pqSortInit(pq) #define pqInsert(pq,key) __gl_pqSortInsert(pq,key) #define pqMinimum(pq) __gl_pqSortMinimum(pq) #define pqExtractMin(pq) __gl_pqSortExtractMin(pq) #define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) #define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) /* Since we support deletion the data structure is a little more * complicated than an ordinary heap. "nodes" is the heap itself; * active nodes are stored in the range 1..pq->size. When the * heap exceeds its allocated size (pq->max), its size doubles. * The children of node i are nodes 2i and 2i+1. * * Each node stores an index into an array "handles". Each handle * stores a key, plus a pointer back to the node which currently * represents that key (ie. nodes[handles[i].node].handle == i). */ typedef PQHeapKey PQkey; typedef PQHeapHandle PQhandle; typedef struct PriorityQ PriorityQ; struct PriorityQ { PriorityQHeap *heap; PQkey *keys; PQkey **order; PQhandle size, max; int initialized; int (*leq)(PQkey key1, PQkey key2); }; PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); void pqDeletePriorityQ( PriorityQ *pq ); int pqInit( PriorityQ *pq ); PQhandle pqInsert( PriorityQ *pq, PQkey key ); PQkey pqExtractMin( PriorityQ *pq ); void pqDelete( PriorityQ *pq, PQhandle handle ); PQkey pqMinimum( PriorityQ *pq ); int pqIsEmpty( PriorityQ *pq ); #endif muffin-5.2.1/cogl/cogl-path/tesselator/normal.h0000664000175000017500000000347014211404421021570 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __normal_h_ #define __normal_h_ #include "tess.h" /* __gl_projectPolygon( tess ) determines the polygon normal * and project vertices onto the plane of the polygon. */ void __gl_projectPolygon( GLUtesselator *tess ); #endif muffin-5.2.1/cogl/cogl-path/tesselator/priorityq.c0000664000175000017500000001601314211404421022332 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include #include #include /* LONG_MAX */ #include "memalloc.h" /* Include all the code for the regular heap-based queue here. */ #include "priorityq-heap.c" /* Now redefine all the function names to map to their "Sort" versions. */ #include "priorityq-sort.h" /* really __gl_pqSortNewPriorityQ */ PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) { PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); if (pq == NULL) return NULL; pq->heap = __gl_pqHeapNewPriorityQ( leq ); if (pq->heap == NULL) { memFree(pq); return NULL; } pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) ); if (pq->keys == NULL) { __gl_pqHeapDeletePriorityQ(pq->heap); memFree(pq); return NULL; } pq->order = NULL; pq->size = 0; pq->max = INIT_SIZE; pq->initialized = FALSE; pq->leq = leq; return pq; } /* really __gl_pqSortDeletePriorityQ */ void pqDeletePriorityQ( PriorityQ *pq ) { assert(pq != NULL); if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap ); if (pq->order != NULL) memFree( pq->order ); if (pq->keys != NULL) memFree( pq->keys ); memFree( pq ); } #define LT(x,y) (! LEQ(y,x)) #define GT(x,y) (! LEQ(x,y)) #define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0) /* really __gl_pqSortInit */ int pqInit( PriorityQ *pq ) { PQkey **p, **r, **i, **j, *piv; struct { PQkey **p, **r; } Stack[50], *top = Stack; unsigned long seed = 2016473283; /* Create an array of indirect pointers to the keys, so that we * the handles we have returned are still valid. */ /* pq->order = (PQHeapKey **)memAlloc( (size_t) (pq->size * sizeof(pq->order[0])) ); */ pq->order = (PQHeapKey **)memAlloc( (size_t) ((pq->size+1) * sizeof(pq->order[0])) ); /* the previous line is a patch to compensate for the fact that IBM */ /* machines return a null on a malloc of zero bytes (unlike SGI), */ /* so we have to put in this defense to guard against a memory */ /* fault four lines down. from fossum@austin.ibm.com. */ if (pq->order == NULL) return 0; p = pq->order; r = p + pq->size - 1; for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) { *i = piv; } /* Sort the indirect pointers in descending order, * using randomized Quicksort */ top->p = p; top->r = r; ++top; while( --top >= Stack ) { p = top->p; r = top->r; while( r > p + 10 ) { seed = seed * 1539415821 + 1; i = p + seed % (r - p + 1); piv = *i; *i = *p; *p = piv; i = p - 1; j = r + 1; do { do { ++i; } while( GT( **i, *piv )); do { --j; } while( LT( **j, *piv )); Swap( i, j ); } while( i < j ); Swap( i, j ); /* Undo last swap */ if( i - p < r - j ) { top->p = j+1; top->r = r; ++top; r = i-1; } else { top->p = p; top->r = i-1; ++top; p = j+1; } } /* Insertion sort small lists */ for( i = p+1; i <= r; ++i ) { piv = *i; for( j = i; j > p && LT( **(j-1), *piv ); --j ) { *j = *(j-1); } *j = piv; } } pq->max = pq->size; pq->initialized = TRUE; __gl_pqHeapInit( pq->heap ); /* always succeeds */ #ifndef NDEBUG p = pq->order; r = p + pq->size - 1; for( i = p; i < r; ++i ) { assert( LEQ( **(i+1), **i )); } #endif return 1; } /* really __gl_pqSortInsert */ /* returns LONG_MAX iff out of memory */ PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) { long curr; if( pq->initialized ) { return __gl_pqHeapInsert( pq->heap, keyNew ); } curr = pq->size; if( ++ pq->size >= pq->max ) { PQkey *saveKey= pq->keys; /* If the heap overflows, double its size. */ pq->max <<= 1; pq->keys = (PQHeapKey *)memRealloc( pq->keys, (size_t) (pq->max * sizeof( pq->keys[0] ))); if (pq->keys == NULL) { pq->keys = saveKey; /* restore ptr to free upon return */ return LONG_MAX; } } assert(curr != LONG_MAX); pq->keys[curr] = keyNew; /* Negative handles index the sorted array. */ return -(curr+1); } /* really __gl_pqSortExtractMin */ PQkey pqExtractMin( PriorityQ *pq ) { PQkey sortMin, heapMin; if( pq->size == 0 ) { return __gl_pqHeapExtractMin( pq->heap ); } sortMin = *(pq->order[pq->size-1]); if( ! __gl_pqHeapIsEmpty( pq->heap )) { heapMin = __gl_pqHeapMinimum( pq->heap ); if( LEQ( heapMin, sortMin )) { return __gl_pqHeapExtractMin( pq->heap ); } } do { -- pq->size; } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ); return sortMin; } /* really __gl_pqSortMinimum */ PQkey pqMinimum( PriorityQ *pq ) { PQkey sortMin, heapMin; if( pq->size == 0 ) { return __gl_pqHeapMinimum( pq->heap ); } sortMin = *(pq->order[pq->size-1]); if( ! __gl_pqHeapIsEmpty( pq->heap )) { heapMin = __gl_pqHeapMinimum( pq->heap ); if( LEQ( heapMin, sortMin )) { return heapMin; } } return sortMin; } /* really __gl_pqSortIsEmpty */ int pqIsEmpty( PriorityQ *pq ) { return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap ); } /* really __gl_pqSortDelete */ void pqDelete( PriorityQ *pq, PQhandle curr ) { if( curr >= 0 ) { __gl_pqHeapDelete( pq->heap, curr ); return; } curr = -(curr+1); assert( curr < pq->max && pq->keys[curr] != NULL ); pq->keys[curr] = NULL; while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) { -- pq->size; } } muffin-5.2.1/cogl/cogl-path/tesselator/priorityq-heap.c0000664000175000017500000001462214211404421023251 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include #include #include "priorityq-heap.h" #include "memalloc.h" #define INIT_SIZE 32 #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifdef FOR_TRITE_TEST_PROGRAM #define LEQ(x,y) (*pq->leq)(x,y) #else /* Violates modularity, but a little faster */ #include "geom.h" #define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y) #endif /* really __gl_pqHeapNewPriorityQ */ PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) { PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); if (pq == NULL) return NULL; pq->size = 0; pq->max = INIT_SIZE; pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) ); if (pq->nodes == NULL) { memFree(pq); return NULL; } pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) ); if (pq->handles == NULL) { memFree(pq->nodes); memFree(pq); return NULL; } pq->initialized = FALSE; pq->freeList = 0; pq->leq = leq; pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */ pq->handles[1].key = NULL; return pq; } /* really __gl_pqHeapDeletePriorityQ */ void pqDeletePriorityQ( PriorityQ *pq ) { memFree( pq->handles ); memFree( pq->nodes ); memFree( pq ); } static void FloatDown( PriorityQ *pq, long curr ) { PQnode *n = pq->nodes; PQhandleElem *h = pq->handles; PQhandle hCurr, hChild; long child; hCurr = n[curr].handle; for( ;; ) { child = curr << 1; if( child < pq->size && LEQ( h[n[child+1].handle].key, h[n[child].handle].key )) { ++child; } assert(child <= pq->max); hChild = n[child].handle; if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) { n[curr].handle = hCurr; h[hCurr].node = curr; break; } n[curr].handle = hChild; h[hChild].node = curr; curr = child; } } static void FloatUp( PriorityQ *pq, long curr ) { PQnode *n = pq->nodes; PQhandleElem *h = pq->handles; PQhandle hCurr, hParent; long parent; hCurr = n[curr].handle; for( ;; ) { parent = curr >> 1; hParent = n[parent].handle; if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) { n[curr].handle = hCurr; h[hCurr].node = curr; break; } n[curr].handle = hParent; h[hParent].node = curr; curr = parent; } } /* really __gl_pqHeapInit */ void pqInit( PriorityQ *pq ) { long i; /* This method of building a heap is O(n), rather than O(n lg n). */ for( i = pq->size; i >= 1; --i ) { FloatDown( pq, i ); } pq->initialized = TRUE; } /* really __gl_pqHeapInsert */ /* returns LONG_MAX iff out of memory */ PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) { long curr; PQhandle free_handle; curr = ++ pq->size; if( (curr*2) > pq->max ) { PQnode *saveNodes= pq->nodes; PQhandleElem *saveHandles= pq->handles; /* If the heap overflows, double its size. */ pq->max <<= 1; pq->nodes = (PQnode *)memRealloc( pq->nodes, (size_t) ((pq->max + 1) * sizeof( pq->nodes[0] ))); if (pq->nodes == NULL) { pq->nodes = saveNodes; /* restore ptr to free upon return */ return LONG_MAX; } pq->handles = (PQhandleElem *)memRealloc( pq->handles, (size_t) ((pq->max + 1) * sizeof( pq->handles[0] ))); if (pq->handles == NULL) { pq->handles = saveHandles; /* restore ptr to free upon return */ return LONG_MAX; } } if( pq->freeList == 0 ) { free_handle = curr; } else { free_handle = pq->freeList; pq->freeList = pq->handles[free_handle].node; } pq->nodes[curr].handle = free_handle; pq->handles[free_handle].node = curr; pq->handles[free_handle].key = keyNew; if( pq->initialized ) { FloatUp( pq, curr ); } assert(free_handle != LONG_MAX); return free_handle; } /* really __gl_pqHeapExtractMin */ PQkey pqExtractMin( PriorityQ *pq ) { PQnode *n = pq->nodes; PQhandleElem *h = pq->handles; PQhandle hMin = n[1].handle; PQkey min = h[hMin].key; if( pq->size > 0 ) { n[1].handle = n[pq->size].handle; h[n[1].handle].node = 1; h[hMin].key = NULL; h[hMin].node = pq->freeList; pq->freeList = hMin; if( -- pq->size > 0 ) { FloatDown( pq, 1 ); } } return min; } /* really __gl_pqHeapDelete */ void pqDelete( PriorityQ *pq, PQhandle hCurr ) { PQnode *n = pq->nodes; PQhandleElem *h = pq->handles; long curr; assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL ); curr = h[hCurr].node; n[curr].handle = n[pq->size].handle; h[n[curr].handle].node = curr; if( curr <= -- pq->size ) { if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) { FloatDown( pq, curr ); } else { FloatUp( pq, curr ); } } h[hCurr].key = NULL; h[hCurr].node = pq->freeList; pq->freeList = hCurr; } muffin-5.2.1/cogl/cogl-path/tesselator/sweep.c0000664000175000017500000013655714211404421021433 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #include "gluos.h" #include #include #include /* longjmp */ #include /* LONG_MAX */ #include "mesh.h" #include "geom.h" #include "tess.h" #include "dict.h" #include "priorityq.h" #include "memalloc.h" #include "sweep.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifdef FOR_TRITE_TEST_PROGRAM extern void DebugEvent( GLUtesselator *tess ); #else #define DebugEvent( tess ) #endif /* * Invariants for the Edge Dictionary. * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) * at any valid location of the sweep event * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 * share a common endpoint * - for each e, e->Dst has been processed, but not e->Org * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) * where "event" is the current sweep line event. * - no edge e has zero length * * Invariants for the Mesh (the processed portion). * - the portion of the mesh left of the sweep line is a planar graph, * ie. there is *some* way to embed it in the plane * - no processed edge has zero length * - no two processed vertices have identical coordinates * - each "inside" region is monotone, ie. can be broken into two chains * of monotonically increasing vertices according to VertLeq(v1,v2) * - a non-invariant: these chains may intersect (very slightly) * * Invariants for the Sweep. * - if none of the edges incident to the event vertex have an activeRegion * (ie. none of these edges are in the edge dictionary), then the vertex * has only right-going edges. * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced * by ConnectRightVertex), then it is the only right-going edge from * its associated vertex. (This says that these edges exist only * when it is necessary.) */ #undef MAX #undef MIN #define MAX(x,y) ((x) >= (y) ? (x) : (y)) #define MIN(x,y) ((x) <= (y) ? (x) : (y)) /* When we merge two edges into one, we need to compute the combined * winding of the new edge. */ #define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ eDst->Sym->winding += eSrc->Sym->winding) static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ); static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ); static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ); static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1, ActiveRegion *reg2 ) /* * Both edges must be directed from right to left (this is the canonical * direction for the upper edge of each region). * * The strategy is to evaluate a "t" value for each edge at the * current sweep line position, given by tess->event. The calculations * are designed to be very stable, but of course they are not perfect. * * Special case: if both edge destinations are at the sweep event, * we sort the edges by slope (they would otherwise compare equally). */ { GLUvertex *event = tess->event; GLUhalfEdge *e1, *e2; GLdouble t1, t2; e1 = reg1->eUp; e2 = reg2->eUp; if( e1->Dst == event ) { if( e2->Dst == event ) { /* Two edges right of the sweep line which meet at the sweep event. * Sort them by slope. */ if( VertLeq( e1->Org, e2->Org )) { return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0; } return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0; } return EdgeSign( e2->Dst, event, e2->Org ) <= 0; } if( e2->Dst == event ) { return EdgeSign( e1->Dst, event, e1->Org ) >= 0; } /* General case - compute signed distance *from* e1, e2 to event */ t1 = EdgeEval( e1->Dst, event, e1->Org ); t2 = EdgeEval( e2->Dst, event, e2->Org ); return (t1 >= t2); } static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg ) { if( reg->fixUpperEdge ) { /* It was created with zero winding number, so it better be * deleted with zero winding number (ie. it better not get merged * with a real edge). */ assert( reg->eUp->winding == 0 ); } reg->eUp->activeRegion = NULL; dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */ memFree( reg ); } static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge ) /* * Replace an upper edge which needs fixing (see ConnectRightVertex). */ { assert( reg->fixUpperEdge ); if ( !__gl_meshDelete( reg->eUp ) ) return 0; reg->fixUpperEdge = FALSE; reg->eUp = newEdge; newEdge->activeRegion = reg; return 1; } static ActiveRegion *TopLeftRegion( ActiveRegion *reg ) { GLUvertex *org = reg->eUp->Org; GLUhalfEdge *e; /* Find the region above the uppermost edge with the same origin */ do { reg = RegionAbove( reg ); } while( reg->eUp->Org == org ); /* If the edge above was a temporary edge introduced by ConnectRightVertex, * now is the time to fix it. */ if( reg->fixUpperEdge ) { e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext ); if (e == NULL) return NULL; if ( !FixUpperEdge( reg, e ) ) return NULL; reg = RegionAbove( reg ); } return reg; } static ActiveRegion *TopRightRegion( ActiveRegion *reg ) { GLUvertex *dst = reg->eUp->Dst; /* Find the region above the uppermost edge with the same destination */ do { reg = RegionAbove( reg ); } while( reg->eUp->Dst == dst ); return reg; } static ActiveRegion *AddRegionBelow( GLUtesselator *tess, ActiveRegion *regAbove, GLUhalfEdge *eNewUp ) /* * Add a new active region to the sweep line, *somewhere* below "regAbove" * (according to where the new edge belongs in the sweep-line dictionary). * The upper edge of the new region will be "eNewUp". * Winding number and "inside" flag are not updated. */ { ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); if (regNew == NULL) longjmp(tess->env,1); regNew->eUp = eNewUp; /* __gl_dictListInsertBefore */ regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew ); if (regNew->nodeUp == NULL) longjmp(tess->env,1); regNew->fixUpperEdge = FALSE; regNew->sentinel = FALSE; regNew->dirty = FALSE; eNewUp->activeRegion = regNew; return regNew; } static GLboolean IsWindingInside( GLUtesselator *tess, int n ) { switch( tess->windingRule ) { case GLU_TESS_WINDING_ODD: return (n & 1); case GLU_TESS_WINDING_NONZERO: return (n != 0); case GLU_TESS_WINDING_POSITIVE: return (n > 0); case GLU_TESS_WINDING_NEGATIVE: return (n < 0); case GLU_TESS_WINDING_ABS_GEQ_TWO: return (n >= 2) || (n <= -2); } /*LINTED*/ assert( FALSE ); /*NOTREACHED*/ return GL_FALSE; /* avoid compiler complaints */ } static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg ) { reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding; reg->inside = IsWindingInside( tess, reg->windingNumber ); } static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg ) /* * Delete a region from the sweep line. This happens when the upper * and lower chains of a region meet (at a vertex on the sweep line). * The "inside" flag is copied to the appropriate mesh face (we could * not do this before -- since the structure of the mesh is always * changing, this face may not have even existed until now). */ { GLUhalfEdge *e = reg->eUp; GLUface *f = e->Lface; f->inside = reg->inside; f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */ DeleteRegion( tess, reg ); } static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess, ActiveRegion *regFirst, ActiveRegion *regLast ) /* * We are given a vertex with one or more left-going edges. All affected * edges should be in the edge dictionary. Starting at regFirst->eUp, * we walk down deleting all regions where both edges have the same * origin vOrg. At the same time we copy the "inside" flag from the * active region to the face, since at this point each face will belong * to at most one region (this was not necessarily true until this point * in the sweep). The walk stops at the region above regLast; if regLast * is NULL we walk as far as possible. At the same time we relink the * mesh if necessary, so that the ordering of edges around vOrg is the * same as in the dictionary. */ { ActiveRegion *reg, *regPrev; GLUhalfEdge *e, *ePrev; regPrev = regFirst; ePrev = regFirst->eUp; while( regPrev != regLast ) { regPrev->fixUpperEdge = FALSE; /* placement was OK */ reg = RegionBelow( regPrev ); e = reg->eUp; if( e->Org != ePrev->Org ) { if( ! reg->fixUpperEdge ) { /* Remove the last left-going edge. Even though there are no further * edges in the dictionary with this origin, there may be further * such edges in the mesh (if we are adding left edges to a vertex * that has already been processed). Thus it is important to call * FinishRegion rather than just DeleteRegion. */ FinishRegion( tess, regPrev ); break; } /* If the edge below was a temporary edge introduced by * ConnectRightVertex, now is the time to fix it. */ e = __gl_meshConnect( ePrev->Lprev, e->Sym ); if (e == NULL) longjmp(tess->env,1); if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1); } /* Relink edges so that ePrev->Onext == e */ if( ePrev->Onext != e ) { if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1); } FinishRegion( tess, regPrev ); /* may change reg->eUp */ ePrev = reg->eUp; regPrev = reg; } return ePrev; } static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp, GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft, GLboolean cleanUp ) /* * Purpose: insert right-going edges into the edge dictionary, and update * winding numbers and mesh connectivity appropriately. All right-going * edges share a common origin vOrg. Edges are inserted CCW starting at * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any * left-going edges already processed, then eTopLeft must be the edge * such that an imaginary upward vertical segment from vOrg would be * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft * should be NULL. */ { ActiveRegion *reg, *regPrev; GLUhalfEdge *e, *ePrev; int firstTime = TRUE; /* Insert the new right-going edges in the dictionary */ e = eFirst; do { assert( VertLeq( e->Org, e->Dst )); AddRegionBelow( tess, regUp, e->Sym ); e = e->Onext; } while ( e != eLast ); /* Walk *all* right-going edges from e->Org, in the dictionary order, * updating the winding numbers of each region, and re-linking the mesh * edges to match the dictionary ordering (if necessary). */ if( eTopLeft == NULL ) { eTopLeft = RegionBelow( regUp )->eUp->Rprev; } regPrev = regUp; ePrev = eTopLeft; for( ;; ) { reg = RegionBelow( regPrev ); e = reg->eUp->Sym; if( e->Org != ePrev->Org ) break; if( e->Onext != ePrev ) { /* Unlink e from its current position, and relink below ePrev */ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1); } /* Compute the winding number and "inside" flag for the new regions */ reg->windingNumber = regPrev->windingNumber - e->winding; reg->inside = IsWindingInside( tess, reg->windingNumber ); /* Check for two outgoing edges with same slope -- process these * before any intersection tests (see example in __gl_computeInterior). */ regPrev->dirty = TRUE; if( ! firstTime && CheckForRightSplice( tess, regPrev )) { AddWinding( e, ePrev ); DeleteRegion( tess, regPrev ); if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1); } firstTime = FALSE; regPrev = reg; ePrev = e; } regPrev->dirty = TRUE; assert( regPrev->windingNumber - e->winding == reg->windingNumber ); if( cleanUp ) { /* Check for intersections between newly adjacent edges. */ WalkDirtyRegions( tess, regPrev ); } } static void CallCombine( GLUtesselator *tess, GLUvertex *isect, void *data[4], GLfloat weights[4], int needed ) { GLdouble coords[3]; /* Copy coord data in case the callback changes it. */ coords[0] = isect->coords[0]; coords[1] = isect->coords[1]; coords[2] = isect->coords[2]; isect->data = NULL; CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data ); if( isect->data == NULL ) { if( ! needed ) { isect->data = data[0]; } else if( ! tess->fatalError ) { /* The only way fatal error is when two edges are found to intersect, * but the user has not provided the callback necessary to handle * generated intersection points. */ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK ); tess->fatalError = TRUE; } } } static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1, GLUhalfEdge *e2 ) /* * Two vertices with idential coordinates are combined into one. * e1->Org is kept, while e2->Org is discarded. */ { void *data[4] = { NULL, NULL, NULL, NULL }; GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 }; data[0] = e1->Org->data; data[1] = e2->Org->data; CallCombine( tess, e1->Org, data, weights, FALSE ); if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1); } static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst, GLfloat *weights ) /* * Find some weights which describe how the intersection vertex is * a linear combination of "org" and "dest". Each of the two edges * which generated "isect" is allocated 50% of the weight; each edge * splits the weight between its org and dst according to the * relative distance to "isect". */ { GLdouble t1 = VertL1dist( org, isect ); GLdouble t2 = VertL1dist( dst, isect ); weights[0] = 0.5 * t2 / (t1 + t2); weights[1] = 0.5 * t1 / (t1 + t2); isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0]; isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1]; isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2]; } static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect, GLUvertex *orgUp, GLUvertex *dstUp, GLUvertex *orgLo, GLUvertex *dstLo ) /* * We've computed a new intersection point, now we need a "data" pointer * from the user so that we can refer to this new vertex in the * rendering callbacks. */ { void *data[4]; GLfloat weights[4]; data[0] = orgUp->data; data[1] = dstUp->data; data[2] = orgLo->data; data[3] = dstLo->data; isect->coords[0] = isect->coords[1] = isect->coords[2] = 0; VertexWeights( isect, orgUp, dstUp, &weights[0] ); VertexWeights( isect, orgLo, dstLo, &weights[2] ); CallCombine( tess, isect, data, weights, TRUE ); } static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ) /* * Check the upper and lower edge of "regUp", to make sure that the * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which * origin is leftmost). * * The main purpose is to splice right-going edges with the same * dest vertex and nearly identical slopes (ie. we can't distinguish * the slopes numerically). However the splicing can also help us * to recover from numerical errors. For example, suppose at one * point we checked eUp and eLo, and decided that eUp->Org is barely * above eLo. Then later, we split eLo into two edges (eg. from * a splice operation like this one). This can change the result of * our test so that now eUp->Org is incident to eLo, or barely below it. * We must correct this condition to maintain the dictionary invariants. * * One possibility is to check these edges for intersection again * (ie. CheckForIntersect). This is what we do if possible. However * CheckForIntersect requires that tess->event lies between eUp and eLo, * so that it has something to fall back on when the intersection * calculation gives us an unusable answer. So, for those cases where * we can't check for intersection, this routine fixes the problem * by just splicing the offending vertex into the other edge. * This is a guaranteed solution, no matter how degenerate things get. * Basically this is a combinatorial solution to a numerical problem. */ { ActiveRegion *regLo = RegionBelow(regUp); GLUhalfEdge *eUp = regUp->eUp; GLUhalfEdge *eLo = regLo->eUp; if( VertLeq( eUp->Org, eLo->Org )) { if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE; /* eUp->Org appears to be below eLo */ if( ! VertEq( eUp->Org, eLo->Org )) { /* Splice eUp->Org into eLo */ if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1); regUp->dirty = regLo->dirty = TRUE; } else if( eUp->Org != eLo->Org ) { /* merge the two vertices, discarding eUp->Org */ pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */ SpliceMergeVertices( tess, eLo->Oprev, eUp ); } } else { if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE; /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */ RegionAbove(regUp)->dirty = regUp->dirty = TRUE; if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); } return TRUE; } static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp ) /* * Check the upper and lower edge of "regUp", to make sure that the * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which * destination is rightmost). * * Theoretically, this should always be true. However, splitting an edge * into two pieces can change the results of previous tests. For example, * suppose at one point we checked eUp and eLo, and decided that eUp->Dst * is barely above eLo. Then later, we split eLo into two edges (eg. from * a splice operation like this one). This can change the result of * the test so that now eUp->Dst is incident to eLo, or barely below it. * We must correct this condition to maintain the dictionary invariants * (otherwise new edges might get inserted in the wrong place in the * dictionary, and bad stuff will happen). * * We fix the problem by just splicing the offending vertex into the * other edge. */ { ActiveRegion *regLo = RegionBelow(regUp); GLUhalfEdge *eUp = regUp->eUp; GLUhalfEdge *eLo = regLo->eUp; GLUhalfEdge *e; assert( ! VertEq( eUp->Dst, eLo->Dst )); if( VertLeq( eUp->Dst, eLo->Dst )) { if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE; /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */ RegionAbove(regUp)->dirty = regUp->dirty = TRUE; e = __gl_meshSplitEdge( eUp ); if (e == NULL) longjmp(tess->env,1); if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1); e->Lface->inside = regUp->inside; } else { if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE; /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */ regUp->dirty = regLo->dirty = TRUE; e = __gl_meshSplitEdge( eLo ); if (e == NULL) longjmp(tess->env,1); if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1); e->Rface->inside = regUp->inside; } return TRUE; } static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp ) /* * Check the upper and lower edges of the given region to see if * they intersect. If so, create the intersection and add it * to the data structures. * * Returns TRUE if adding the new intersection resulted in a recursive * call to AddRightEdges(); in this case all "dirty" regions have been * checked for intersections, and possibly regUp has been deleted. */ { ActiveRegion *regLo = RegionBelow(regUp); GLUhalfEdge *eUp = regUp->eUp; GLUhalfEdge *eLo = regLo->eUp; GLUvertex *orgUp = eUp->Org; GLUvertex *orgLo = eLo->Org; GLUvertex *dstUp = eUp->Dst; GLUvertex *dstLo = eLo->Dst; GLdouble tMinUp, tMaxLo; GLUvertex isect, *orgMin; GLUhalfEdge *e; assert( ! VertEq( dstLo, dstUp )); assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 ); assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 ); assert( orgUp != tess->event && orgLo != tess->event ); assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge ); if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */ tMinUp = MIN( orgUp->t, dstUp->t ); tMaxLo = MAX( orgLo->t, dstLo->t ); if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */ if( VertLeq( orgUp, orgLo )) { if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE; } else { if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE; } /* At this point the edges intersect, at least marginally */ DebugEvent( tess ); __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect ); /* The following properties are guaranteed: */ assert( MIN( orgUp->t, dstUp->t ) <= isect.t ); assert( isect.t <= MAX( orgLo->t, dstLo->t )); assert( MIN( dstLo->s, dstUp->s ) <= isect.s ); assert( isect.s <= MAX( orgLo->s, orgUp->s )); if( VertLeq( &isect, tess->event )) { /* The intersection point lies slightly to the left of the sweep line, * so move it until it''s slightly to the right of the sweep line. * (If we had perfect numerical precision, this would never happen * in the first place). The easiest and safest thing to do is * replace the intersection by tess->event. */ isect.s = tess->event->s; isect.t = tess->event->t; } /* Similarly, if the computed intersection lies to the right of the * rightmost origin (which should rarely happen), it can cause * unbelievable inefficiency on sufficiently degenerate inputs. * (If you have the test program, try running test54.d with the * "X zoom" option turned on). */ orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo; if( VertLeq( orgMin, &isect )) { isect.s = orgMin->s; isect.t = orgMin->t; } if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) { /* Easy case -- intersection at one of the right endpoints */ (void) CheckForRightSplice( tess, regUp ); return FALSE; } if( (! VertEq( dstUp, tess->event ) && EdgeSign( dstUp, tess->event, &isect ) >= 0) || (! VertEq( dstLo, tess->event ) && EdgeSign( dstLo, tess->event, &isect ) <= 0 )) { /* Very unusual -- the new upper or lower edge would pass on the * wrong side of the sweep event, or through it. This can happen * due to very small numerical errors in the intersection calculation. */ if( dstLo == tess->event ) { /* Splice dstLo into eUp, and process the new region(s) */ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1); regUp = TopLeftRegion( regUp ); if (regUp == NULL) longjmp(tess->env,1); eUp = RegionBelow(regUp)->eUp; FinishLeftRegions( tess, RegionBelow(regUp), regLo ); AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE ); return TRUE; } if( dstUp == tess->event ) { /* Splice dstUp into eLo, and process the new region(s) */ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1); regLo = regUp; regUp = TopRightRegion( regUp ); e = RegionBelow(regUp)->eUp->Rprev; regLo->eUp = eLo->Oprev; eLo = FinishLeftRegions( tess, regLo, NULL ); AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE ); return TRUE; } /* Special case: called from ConnectRightVertex. If either * edge passes on the wrong side of tess->event, split it * (and wait for ConnectRightVertex to splice it appropriately). */ if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) { RegionAbove(regUp)->dirty = regUp->dirty = TRUE; if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); eUp->Org->s = tess->event->s; eUp->Org->t = tess->event->t; } if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) { regUp->dirty = regLo->dirty = TRUE; if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); eLo->Org->s = tess->event->s; eLo->Org->t = tess->event->t; } /* leave the rest for ConnectRightVertex */ return FALSE; } /* General case -- split both edges, splice into new vertex. * When we do the splice operation, the order of the arguments is * arbitrary as far as correctness goes. However, when the operation * creates a new face, the work done is proportional to the size of * the new face. We expect the faces in the processed part of * the mesh (ie. eUp->Lface) to be smaller than the faces in the * unprocessed original contours (which will be eLo->Oprev->Lface). */ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); eUp->Org->s = isect.s; eUp->Org->t = isect.t; eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */ if (eUp->Org->pqHandle == LONG_MAX) { pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ tess->pq = NULL; longjmp(tess->env,1); } GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo ); RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE; return FALSE; } static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ) /* * When the upper or lower edge of any region changes, the region is * marked "dirty". This routine walks through all the dirty regions * and makes sure that the dictionary invariants are satisfied * (see the comments at the beginning of this file). Of course * new dirty regions can be created as we make changes to restore * the invariants. */ { ActiveRegion *regLo = RegionBelow(regUp); GLUhalfEdge *eUp, *eLo; for( ;; ) { /* Find the lowest dirty region (we walk from the bottom up). */ while( regLo->dirty ) { regUp = regLo; regLo = RegionBelow(regLo); } if( ! regUp->dirty ) { regLo = regUp; regUp = RegionAbove( regUp ); if( regUp == NULL || ! regUp->dirty ) { /* We've walked all the dirty regions */ return; } } regUp->dirty = FALSE; eUp = regUp->eUp; eLo = regLo->eUp; if( eUp->Dst != eLo->Dst ) { /* Check that the edge ordering is obeyed at the Dst vertices. */ if( CheckForLeftSplice( tess, regUp )) { /* If the upper or lower edge was marked fixUpperEdge, then * we no longer need it (since these edges are needed only for * vertices which otherwise have no right-going edges). */ if( regLo->fixUpperEdge ) { DeleteRegion( tess, regLo ); if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1); regLo = RegionBelow( regUp ); eLo = regLo->eUp; } else if( regUp->fixUpperEdge ) { DeleteRegion( tess, regUp ); if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); regUp = RegionAbove( regLo ); eUp = regUp->eUp; } } } if( eUp->Org != eLo->Org ) { if( eUp->Dst != eLo->Dst && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge && (eUp->Dst == tess->event || eLo->Dst == tess->event) ) { /* When all else fails in CheckForIntersect(), it uses tess->event * as the intersection location. To make this possible, it requires * that tess->event lie between the upper and lower edges, and also * that neither of these is marked fixUpperEdge (since in the worst * case it might splice one of these edges into tess->event, and * violate the invariant that fixable edges are the only right-going * edge from their associated vertex). */ if( CheckForIntersect( tess, regUp )) { /* WalkDirtyRegions() was called recursively; we're done */ return; } } else { /* Even though we can't use CheckForIntersect(), the Org vertices * may violate the dictionary edge ordering. Check and correct this. */ (void) CheckForRightSplice( tess, regUp ); } } if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) { /* A degenerate loop consisting of only two edges -- delete it. */ AddWinding( eLo, eUp ); DeleteRegion( tess, regUp ); if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); regUp = RegionAbove( regLo ); } } } static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp, GLUhalfEdge *eBottomLeft ) /* * Purpose: connect a "right" vertex vEvent (one where all edges go left) * to the unprocessed portion of the mesh. Since there are no right-going * edges, two regions (one above vEvent and one below) are being merged * into one. "regUp" is the upper of these two regions. * * There are two reasons for doing this (adding a right-going edge): * - if the two regions being merged are "inside", we must add an edge * to keep them separated (the combined region would not be monotone). * - in any case, we must leave some record of vEvent in the dictionary, * so that we can merge vEvent with features that we have not seen yet. * For example, maybe there is a vertical edge which passes just to * the right of vEvent; we would like to splice vEvent into this edge. * * However, we don't want to connect vEvent to just any vertex. We don''t * want the new edge to cross any other edges; otherwise we will create * intersection vertices even when the input data had no self-intersections. * (This is a bad thing; if the user's input data has no intersections, * we don't want to generate any false intersections ourselves.) * * Our eventual goal is to connect vEvent to the leftmost unprocessed * vertex of the combined region (the union of regUp and regLo). * But because of unseen vertices with all right-going edges, and also * new vertices which may be created by edge intersections, we don''t * know where that leftmost unprocessed vertex is. In the meantime, we * connect vEvent to the closest vertex of either chain, and mark the region * as "fixUpperEdge". This flag says to delete and reconnect this edge * to the next processed vertex on the boundary of the combined region. * Quite possibly the vertex we connected to will turn out to be the * closest one, in which case we won''t need to make any changes. */ { GLUhalfEdge *eNew; GLUhalfEdge *eTopLeft = eBottomLeft->Onext; ActiveRegion *regLo = RegionBelow(regUp); GLUhalfEdge *eUp = regUp->eUp; GLUhalfEdge *eLo = regLo->eUp; int degenerate = FALSE; if( eUp->Dst != eLo->Dst ) { (void) CheckForIntersect( tess, regUp ); } /* Possible new degeneracies: upper or lower edge of regUp may pass * through vEvent, or may coincide with new intersection vertex */ if( VertEq( eUp->Org, tess->event )) { if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1); regUp = TopLeftRegion( regUp ); if (regUp == NULL) longjmp(tess->env,1); eTopLeft = RegionBelow( regUp )->eUp; FinishLeftRegions( tess, RegionBelow(regUp), regLo ); degenerate = TRUE; } if( VertEq( eLo->Org, tess->event )) { if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1); eBottomLeft = FinishLeftRegions( tess, regLo, NULL ); degenerate = TRUE; } if( degenerate ) { AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); return; } /* Non-degenerate situation -- need to add a temporary, fixable edge. * Connect to the closer of eLo->Org, eUp->Org. */ if( VertLeq( eLo->Org, eUp->Org )) { eNew = eLo->Oprev; } else { eNew = eUp; } eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew ); if (eNew == NULL) longjmp(tess->env,1); /* Prevent cleanup, otherwise eNew might disappear before we've even * had a chance to mark it as a temporary edge. */ AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE ); eNew->Sym->activeRegion->fixUpperEdge = TRUE; WalkDirtyRegions( tess, regUp ); } /* Because vertices at exactly the same location are merged together * before we process the sweep event, some degenerate cases can't occur. * However if someone eventually makes the modifications required to * merge features which are close together, the cases below marked * TOLERANCE_NONZERO will be useful. They were debugged before the * code to merge identical vertices in the main loop was added. */ #define TOLERANCE_NONZERO FALSE static void ConnectLeftDegenerate( GLUtesselator *tess, ActiveRegion *regUp, GLUvertex *vEvent ) /* * The event vertex lies exacty on an already-processed edge or vertex. * Adding the new vertex involves splicing it into the already-processed * part of the mesh. */ { GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast; ActiveRegion *reg; e = regUp->eUp; if( VertEq( e->Org, vEvent )) { /* e->Org is an unprocessed vertex - just combine them, and wait * for e->Org to be pulled from the queue */ assert( TOLERANCE_NONZERO ); SpliceMergeVertices( tess, e, vEvent->anEdge ); return; } if( ! VertEq( e->Dst, vEvent )) { /* General case -- splice vEvent into edge e which passes through it */ if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1); if( regUp->fixUpperEdge ) { /* This edge was fixable -- delete unused portion of original edge */ if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1); regUp->fixUpperEdge = FALSE; } if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1); SweepEvent( tess, vEvent ); /* recurse */ return; } /* vEvent coincides with e->Dst, which has already been processed. * Splice in the additional right-going edges. */ assert( TOLERANCE_NONZERO ); regUp = TopRightRegion( regUp ); reg = RegionBelow( regUp ); eTopRight = reg->eUp->Sym; eTopLeft = eLast = eTopRight->Onext; if( reg->fixUpperEdge ) { /* Here e->Dst has only a single fixable edge going right. * We can delete it since now we have some real right-going edges. */ assert( eTopLeft != eTopRight ); /* there are some left edges too */ DeleteRegion( tess, reg ); if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1); eTopRight = eTopLeft->Oprev; } if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1); if( ! EdgeGoesLeft( eTopLeft )) { /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */ eTopLeft = NULL; } AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE ); } static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent ) /* * Purpose: connect a "left" vertex (one where both edges go right) * to the processed portion of the mesh. Let R be the active region * containing vEvent, and let U and L be the upper and lower edge * chains of R. There are two possibilities: * * - the normal case: split R into two regions, by connecting vEvent to * the rightmost vertex of U or L lying to the left of the sweep line * * - the degenerate case: if vEvent is close enough to U or L, we * merge vEvent into that edge chain. The subcases are: * - merging with the rightmost vertex of U or L * - merging with the active edge of U or L * - merging with an already-processed portion of U or L */ { ActiveRegion *regUp, *regLo, *reg; GLUhalfEdge *eUp, *eLo, *eNew; ActiveRegion tmp; /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */ /* Get a pointer to the active region containing vEvent */ tmp.eUp = vEvent->anEdge->Sym; /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */ regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp )); regLo = RegionBelow( regUp ); eUp = regUp->eUp; eLo = regLo->eUp; /* Try merging with U or L first */ if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) { ConnectLeftDegenerate( tess, regUp, vEvent ); return; } /* Connect vEvent to rightmost processed vertex of either chain. * e->Dst is the vertex that we will connect to vEvent. */ reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo; if( regUp->inside || reg->fixUpperEdge) { if( reg == regUp ) { eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext ); if (eNew == NULL) longjmp(tess->env,1); } else { GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge); if (tempHalfEdge == NULL) longjmp(tess->env,1); eNew = tempHalfEdge->Sym; } if( reg->fixUpperEdge ) { if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1); } else { ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew )); } SweepEvent( tess, vEvent ); } else { /* The new vertex is in a region which does not belong to the polygon. * We don''t need to connect this vertex to the rest of the mesh. */ AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE ); } } static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ) /* * Does everything necessary when the sweep line crosses a vertex. * Updates the mesh and the edge dictionary. */ { ActiveRegion *regUp, *reg; GLUhalfEdge *e, *eTopLeft, *eBottomLeft; tess->event = vEvent; /* for access in EdgeLeq() */ DebugEvent( tess ); /* Check if this vertex is the right endpoint of an edge that is * already in the dictionary. In this case we don't need to waste * time searching for the location to insert new edges. */ e = vEvent->anEdge; while( e->activeRegion == NULL ) { e = e->Onext; if( e == vEvent->anEdge ) { /* All edges go right -- not incident to any processed edges */ ConnectLeftVertex( tess, vEvent ); return; } } /* Processing consists of two phases: first we "finish" all the * active regions where both the upper and lower edges terminate * at vEvent (ie. vEvent is closing off these regions). * We mark these faces "inside" or "outside" the polygon according * to their winding number, and delete the edges from the dictionary. * This takes care of all the left-going edges from vEvent. */ regUp = TopLeftRegion( e->activeRegion ); if (regUp == NULL) longjmp(tess->env,1); reg = RegionBelow( regUp ); eTopLeft = reg->eUp; eBottomLeft = FinishLeftRegions( tess, reg, NULL ); /* Next we process all the right-going edges from vEvent. This * involves adding the edges to the dictionary, and creating the * associated "active regions" which record information about the * regions between adjacent dictionary edges. */ if( eBottomLeft->Onext == eTopLeft ) { /* No right-going edges -- add a temporary "fixable" edge */ ConnectRightVertex( tess, regUp, eBottomLeft ); } else { AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); } } /* Make the sentinel coordinates big enough that they will never be * merged with real input features. (Even with the largest possible * input contour and the maximum tolerance of 1.0, no merging will be * done with coordinates larger than 3 * GLU_TESS_MAX_COORD). */ #define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD) static void AddSentinel( GLUtesselator *tess, GLdouble t ) /* * We add two sentinel edges above and below all other edges, * to avoid special cases at the top and bottom. */ { GLUhalfEdge *e; ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); if (reg == NULL) longjmp(tess->env,1); e = __gl_meshMakeEdge( tess->mesh ); if (e == NULL) longjmp(tess->env,1); e->Org->s = SENTINEL_COORD; e->Org->t = t; e->Dst->s = -SENTINEL_COORD; e->Dst->t = t; tess->event = e->Dst; /* initialize it */ reg->eUp = e; reg->windingNumber = 0; reg->inside = FALSE; reg->fixUpperEdge = FALSE; reg->sentinel = TRUE; reg->dirty = FALSE; reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */ if (reg->nodeUp == NULL) longjmp(tess->env,1); } static void InitEdgeDict( GLUtesselator *tess ) /* * We maintain an ordering of edge intersections with the sweep line. * This order is maintained in a dynamic dictionary. */ { /* __gl_dictListNewDict */ tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq ); if (tess->dict == NULL) longjmp(tess->env,1); AddSentinel( tess, -SENTINEL_COORD ); AddSentinel( tess, SENTINEL_COORD ); } static void DoneEdgeDict( GLUtesselator *tess ) { ActiveRegion *reg; #ifndef NDEBUG int fixedEdges = 0; #endif /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) { /* * At the end of all processing, the dictionary should contain * only the two sentinel edges, plus at most one "fixable" edge * created by ConnectRightVertex(). */ if( ! reg->sentinel ) { assert( reg->fixUpperEdge ); assert( ++fixedEdges == 1 ); } assert( reg->windingNumber == 0 ); DeleteRegion( tess, reg ); /* __gl_meshDelete( reg->eUp );*/ } dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */ } static void RemoveDegenerateEdges( GLUtesselator *tess ) /* * Remove zero-length edges, and contours with fewer than 3 vertices. */ { GLUhalfEdge *e, *eNext, *eLnext; GLUhalfEdge *eHead = &tess->mesh->eHead; /*LINTED*/ for( e = eHead->next; e != eHead; e = eNext ) { eNext = e->next; eLnext = e->Lnext; if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) { /* Zero-length edge, contour has at least 3 edges */ SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */ e = eLnext; eLnext = e->Lnext; } if( eLnext->Lnext == e ) { /* Degenerate contour (one or two edges) */ if( eLnext != e ) { if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; } if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1); } if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; } if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); } } } static int InitPriorityQ( GLUtesselator *tess ) /* * Insert all vertices into the priority queue which determines the * order in which vertices cross the sweep line. */ { PriorityQ *pq; GLUvertex *v, *vHead; /* __gl_pqSortNewPriorityQ */ pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq ); if (pq == NULL) return 0; vHead = &tess->mesh->vHead; for( v = vHead->next; v != vHead; v = v->next ) { v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */ if (v->pqHandle == LONG_MAX) break; } if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ tess->pq = NULL; return 0; } return 1; } static void DonePriorityQ( GLUtesselator *tess ) { pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */ } static int RemoveDegenerateFaces( GLUmesh *mesh ) /* * Delete any degenerate faces with only two edges. WalkDirtyRegions() * will catch almost all of these, but it won't catch degenerate faces * produced by splice operations on already-processed edges. * The two places this can happen are in FinishLeftRegions(), when * we splice in a "temporary" edge produced by ConnectRightVertex(), * and in CheckForLeftSplice(), where we splice already-processed * edges to ensure that our dictionary invariants are not violated * by numerical errors. * * In both these cases it is *very* dangerous to delete the offending * edge at the time, since one of the routines further up the stack * will sometimes be keeping a pointer to that edge. */ { GLUface *f, *fNext; GLUhalfEdge *e; /*LINTED*/ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { fNext = f->next; e = f->anEdge; assert( e->Lnext != e ); if( e->Lnext->Lnext == e ) { /* A face with only two edges */ AddWinding( e->Onext, e ); if ( !__gl_meshDelete( e ) ) return 0; } } return 1; } int __gl_computeInterior( GLUtesselator *tess ) /* * __gl_computeInterior( tess ) computes the planar arrangement specified * by the given contours, and further subdivides this arrangement * into regions. Each region is marked "inside" if it belongs * to the polygon, according to the rule given by tess->windingRule. * Each interior region is guaranteed be monotone. */ { GLUvertex *v, *vNext; tess->fatalError = FALSE; /* Each vertex defines an event for our sweep line. Start by inserting * all the vertices in a priority queue. Events are processed in * lexicographic order, ie. * * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y) */ RemoveDegenerateEdges( tess ); if ( !InitPriorityQ( tess ) ) return 0; /* if error */ InitEdgeDict( tess ); /* __gl_pqSortExtractMin */ while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) { for( ;; ) { vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */ if( vNext == NULL || ! VertEq( vNext, v )) break; /* Merge together all vertices at exactly the same location. * This is more efficient than processing them one at a time, * simplifies the code (see ConnectLeftDegenerate), and is also * important for correct handling of certain degenerate cases. * For example, suppose there are two identical edges A and B * that belong to different contours (so without this code they would * be processed by separate sweep events). Suppose another edge C * crosses A and B from above. When A is processed, we split it * at its intersection point with C. However this also splits C, * so when we insert B we may compute a slightly different * intersection point. This might leave two edges with a small * gap between them. This kind of error is especially obvious * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY). */ vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/ SpliceMergeVertices( tess, v->anEdge, vNext->anEdge ); } SweepEvent( tess, v ); } /* Set tess->event for debugging purposes */ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org; DebugEvent( tess ); DoneEdgeDict( tess ); DonePriorityQ( tess ); if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0; __gl_meshCheckMesh( tess->mesh ); return 1; } muffin-5.2.1/cogl/cogl-path/tesselator/mesh.h0000664000175000017500000002735214211404421021241 0ustar jpeisachjpeisach/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. */ /* ** Author: Eric Veach, July 1994. ** */ #ifndef __mesh_h_ #define __mesh_h_ #include typedef struct GLUmesh GLUmesh; typedef struct GLUvertex GLUvertex; typedef struct GLUface GLUface; typedef struct GLUhalfEdge GLUhalfEdge; typedef struct ActiveRegion ActiveRegion; /* Internal data */ /* The mesh structure is similar in spirit, notation, and operations * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives * for the manipulation of general subdivisions and the computation of * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985). * For a simplified description, see the course notes for CS348a, * "Mathematical Foundations of Computer Graphics", available at the * Stanford bookstore (and taught during the fall quarter). * The implementation also borrows a tiny subset of the graph-based approach * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988). * * The fundamental data structure is the "half-edge". Two half-edges * go together to make an edge, but they point in opposite directions. * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym), * its origin vertex (Org), the face on its left side (Lface), and the * adjacent half-edges in the CCW direction around the origin vertex * (Onext) and around the left face (Lnext). There is also a "next" * pointer for the global edge list (see below). * * The notation used for mesh navigation: * Sym = the mate of a half-edge (same edge, but opposite direction) * Onext = edge CCW around origin vertex (keep same origin) * Dnext = edge CCW around destination vertex (keep same dest) * Lnext = edge CCW around left face (dest becomes new origin) * Rnext = edge CCW around right face (origin becomes new dest) * * "prev" means to substitute CW for CCW in the definitions above. * * The mesh keeps global lists of all vertices, faces, and edges, * stored as doubly-linked circular lists with a dummy header node. * The mesh stores pointers to these dummy headers (vHead, fHead, eHead). * * The circular edge list is special; since half-edges always occur * in pairs (e and e->Sym), each half-edge stores a pointer in only * one direction. Starting at eHead and following the e->next pointers * will visit each *edge* once (ie. e or e->Sym, but not both). * e->Sym stores a pointer in the opposite direction, thus it is * always true that e->Sym->next->Sym->next == e. * * Each vertex has a pointer to next and previous vertices in the * circular list, and a pointer to a half-edge with this vertex as * the origin (NULL if this is the dummy header). There is also a * field "data" for client data. * * Each face has a pointer to the next and previous faces in the * circular list, and a pointer to a half-edge with this face as * the left face (NULL if this is the dummy header). There is also * a field "data" for client data. * * Note that what we call a "face" is really a loop; faces may consist * of more than one loop (ie. not simply connected), but there is no * record of this in the data structure. The mesh may consist of * several disconnected regions, so it may not be possible to visit * the entire mesh by starting at a half-edge and traversing the edge * structure. * * The mesh does NOT support isolated vertices; a vertex is deleted along * with its last edge. Similarly when two faces are merged, one of the * faces is deleted (see __gl_meshDelete below). For mesh operations, * all face (loop) and vertex pointers must not be NULL. However, once * mesh manipulation is finished, __gl_MeshZapFace can be used to delete * faces of the mesh, one at a time. All external faces can be "zapped" * before the mesh is returned to the client; then a NULL face indicates * a region which is not part of the output polygon. */ struct GLUvertex { GLUvertex *next; /* next vertex (never NULL) */ GLUvertex *prev; /* previous vertex (never NULL) */ GLUhalfEdge *anEdge; /* a half-edge with this origin */ void *data; /* client's data */ /* Internal data (keep hidden) */ GLdouble coords[3]; /* vertex location in 3D */ GLdouble s, t; /* projection onto the sweep plane */ long pqHandle; /* to allow deletion from priority queue */ }; struct GLUface { GLUface *next; /* next face (never NULL) */ GLUface *prev; /* previous face (never NULL) */ GLUhalfEdge *anEdge; /* a half edge with this left face */ void *data; /* room for client's data */ /* Internal data (keep hidden) */ GLUface *trail; /* "stack" for conversion to strips */ GLboolean marked; /* flag for conversion to strips */ GLboolean inside; /* this face is in the polygon interior */ }; struct GLUhalfEdge { GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */ GLUhalfEdge *Sym; /* same edge, opposite direction */ GLUhalfEdge *Onext; /* next edge CCW around origin */ GLUhalfEdge *Lnext; /* next edge CCW around left face */ GLUvertex *Org; /* origin vertex (Overtex too long) */ GLUface *Lface; /* left face */ /* Internal data (keep hidden) */ ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */ int winding; /* change in winding number when crossing from the right face to the left face */ }; #define Rface Sym->Lface #define Dst Sym->Org #define Oprev Sym->Lnext #define Lprev Onext->Sym #define Dprev Lnext->Sym #define Rprev Sym->Onext #define Dnext Rprev->Sym /* 3 pointers */ #define Rnext Oprev->Sym /* 3 pointers */ struct GLUmesh { GLUvertex vHead; /* dummy header for vertex list */ GLUface fHead; /* dummy header for face list */ GLUhalfEdge eHead; /* dummy header for edge list */ GLUhalfEdge eHeadSym; /* and its symmetric counterpart */ }; /* The mesh operations below have three motivations: completeness, * convenience, and efficiency. The basic mesh operations are MakeEdge, * Splice, and Delete. All the other edge operations can be implemented * in terms of these. The other operations are provided for convenience * and/or efficiency. * * When a face is split or a vertex is added, they are inserted into the * global list *before* the existing vertex or face (ie. e->Org or e->Lface). * This makes it easier to process all vertices or faces in the global lists * without worrying about processing the same data twice. As a convenience, * when a face is split, the "inside" flag is copied from the old face. * Other internal data (v->data, v->activeRegion, f->data, f->marked, * f->trail, e->winding) is set to zero. * * ********************** Basic Edge Operations ************************** * * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop. * The loop (face) consists of the two new half-edges. * * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the * mesh connectivity and topology. It changes the mesh so that * eOrg->Onext <- OLD( eDst->Onext ) * eDst->Onext <- OLD( eOrg->Onext ) * where OLD(...) means the value before the meshSplice operation. * * This can have two effects on the vertex structure: * - if eOrg->Org != eDst->Org, the two vertices are merged together * - if eOrg->Org == eDst->Org, the origin is split into two vertices * In both cases, eDst->Org is changed and eOrg->Org is untouched. * * Similarly (and independently) for the face structure, * - if eOrg->Lface == eDst->Lface, one loop is split into two * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. * * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; * the newly created loop will contain eDel->Dst. If the deletion of eDel * would create isolated vertices, those are deleted as well. * * ********************** Other Edge Operations ************************** * * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. * eOrg and eNew will have the same left face. * * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. * eOrg and eNew will have the same left face. * * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst * to eDst->Org, and returns the corresponding half-edge eNew. * If eOrg->Lface == eDst->Lface, this splits one loop into two, * and the newly created loop is eNew->Lface. Otherwise, two disjoint * loops are merged into one, and the loop eDst->Lface is destroyed. * * ************************ Other Operations ***************************** * * __gl_meshNewMesh() creates a new mesh with no edges, no vertices, * and no loops (what we usually call a "face"). * * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in * both meshes, and returns the new mesh (the old meshes are destroyed). * * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. * * __gl_meshZapFace( fZap ) destroys a face and removes it from the * global face list. All edges of fZap will have a NULL pointer as their * left face. Any edges which also have a NULL pointer as their right face * are deleted entirely (along with any isolated vertices this produces). * An entire mesh can be deleted by zapping its faces, one at a time, * in any order. Zapped faces cannot be used in further mesh operations! * * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. */ GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ); int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); int __gl_meshDelete( GLUhalfEdge *eDel ); GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ); GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ); GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); GLUmesh *__gl_meshNewMesh( void ); GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ); void __gl_meshDeleteMesh( GLUmesh *mesh ); void __gl_meshZapFace( GLUface *fZap ); #ifdef NDEBUG #define __gl_meshCheckMesh( mesh ) #else void __gl_meshCheckMesh( GLUmesh *mesh ); #endif #endif muffin-5.2.1/cogl/cogl-path/cogl-path-types.h0000664000175000017500000000610714211404421021133 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PATH_TYPES_H__ #define __COGL_PATH_TYPES_H__ #include COGL_BEGIN_DECLS typedef struct _CoglPath CoglPath; /** * CoglPathFillRule: * @COGL_PATH_FILL_RULE_NON_ZERO: Each time the line crosses an edge of * the path from left to right one is added to a counter and each time * it crosses from right to left the counter is decremented. If the * counter is non-zero then the point will be filled. See . * @COGL_PATH_FILL_RULE_EVEN_ODD: If the line crosses an edge of the * path an odd number of times then the point will filled, otherwise * it won't. See . * * #CoglPathFillRule is used to determine how a path is filled. There * are two options - 'non-zero' and 'even-odd'. To work out whether any * point will be filled imagine drawing an infinetely long line in any * direction from that point. The number of times and the direction * that the edges of the path crosses this line determines whether the * line is filled as described below. Any open sub paths are treated * as if there was an extra line joining the first point and the last * point. * * The default fill rule when creating a path is %COGL_PATH_FILL_RULE_EVEN_ODD. * *
* Example of filling various paths using the non-zero rule * *
* *
* Example of filling various paths using the even-odd rule * *
* * Since: 1.4 */ typedef enum { COGL_PATH_FILL_RULE_NON_ZERO, COGL_PATH_FILL_RULE_EVEN_ODD } CoglPathFillRule; COGL_END_DECLS #endif /* __COGL_PATH_TYPES_H__ */ muffin-5.2.1/cogl/cogl-path/Makefile.am0000664000175000017500000000521614211404421017776 0ustar jpeisachjpeisachNULL = BUILT_SOURCES = CLEANFILES = DISTCLEANFILES = EXTRA_DIST = # tesselator sources cogl_tesselator_sources = \ tesselator/dict-list.h \ tesselator/dict.c \ tesselator/dict.h \ tesselator/geom.c \ tesselator/geom.h \ tesselator/gluos.h \ tesselator/memalloc.h \ tesselator/mesh.c \ tesselator/mesh.h \ tesselator/normal.c \ tesselator/normal.h \ tesselator/priorityq-heap.h \ tesselator/priorityq-sort.h \ tesselator/priorityq.c \ tesselator/priorityq.h \ tesselator/render.c \ tesselator/render.h \ tesselator/sweep.c \ tesselator/sweep.h \ tesselator/tess.c \ tesselator/tess.h \ tesselator/tesselator.h \ tesselator/tessmono.c \ tesselator/tessmono.h \ tesselator/GL/glu.h \ $(NULL) source_c = \ $(cogl_tesselator_sources) \ cogl-path-private.h \ cogl-path.c \ $(NULL) EXTRA_DIST += \ tesselator/README \ tesselator/priorityq-heap.c \ cogl-path.symbols \ $(NULL) source_1_x_h = \ cogl-path-types.h \ $(NULL) source_h = \ cogl-path.h \ $(source_1_x_h) \ cogl-path-functions.h \ $(NULL) # glib-mkenums rules glib_enum_h = cogl-path-enum-types.h glib_enum_c = cogl-path-enum-types.c glib_enum_headers = $(source_1_x_h) include $(top_srcdir)/build/autotools/Makefile.am.enums muffinlibdir = $(libdir)/muffin muffinlib_LTLIBRARIES = libmuffin-cogl-path-@MUFFIN_PLUGIN_API_VERSION@.la libmuffin_cogl_path_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = $(source_c) $(source_h) nodist_libmuffin_cogl_path_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = $(BUILT_SOURCES) libmuffin_cogl_path_@MUFFIN_PLUGIN_API_VERSION@_la_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS) libmuffin_cogl_path_@MUFFIN_PLUGIN_API_VERSION@_la_LIBADD = $(top_builddir)/cogl/libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la -lm libmuffin_cogl_path_@MUFFIN_PLUGIN_API_VERSION@_la_LIBADD += $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS) libmuffin_cogl_path_@MUFFIN_PLUGIN_API_VERSION@_la_LDFLAGS = \ -export-dynamic \ -export-symbols-regex "^(cogl|cogl2)_(framebuffer|path|is|clip|[sg]et)_.*" \ -no-undefined \ -avoid-version \ -rpath $(muffinlibdir) AM_CPPFLAGS = \ -DCOGL_COMPILATION \ -DG_LOG_DOMAIN=\"CoglPath\" \ -I$(srcdir)/tesselator \ -I$(top_srcdir)/cogl \ -I$(top_builddir)/cogl \ -I$(top_srcdir)/cogl/winsys \ -I$(top_srcdir) \ -I$(top_builddir) cogl_base_includedir = $(includedir)/muffin cogl_pathheadersdir = $(cogl_base_includedir)/cogl/cogl-path cogl_pathheaders_HEADERS = $(source_h) nodist_cogl_pathheaders_HEADERS = cogl-path-enum-types.h pc_files = muffin-cogl-path-$(MUFFIN_PLUGIN_API_VERSION).pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pc_files) DISTCLEANFILES += $(pc_files) muffin-5.2.1/cogl/cogl-path/cogl-path-private.h0000664000175000017500000000650514211404421021443 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PATH_PRIVATE_H #define __COGL_PATH_PRIVATE_H #include "cogl-object.h" #include "cogl-attribute-private.h" typedef struct _floatVec2 { float x; float y; } floatVec2; typedef struct _CoglPathNode { float x; float y; unsigned int path_size; } CoglPathNode; typedef struct _CoglBezQuad { floatVec2 p1; floatVec2 p2; floatVec2 p3; } CoglBezQuad; typedef struct _CoglBezCubic { floatVec2 p1; floatVec2 p2; floatVec2 p3; floatVec2 p4; } CoglBezCubic; typedef struct _CoglPathData CoglPathData; struct _CoglPath { CoglObject _parent; CoglPathData *data; }; #define COGL_PATH_N_ATTRIBUTES 2 struct _CoglPathData { unsigned int ref_count; CoglContext *context; CoglPathFillRule fill_rule; GArray *path_nodes; floatVec2 path_start; floatVec2 path_pen; unsigned int last_path; floatVec2 path_nodes_min; floatVec2 path_nodes_max; CoglAttributeBuffer *fill_attribute_buffer; CoglIndices *fill_vbo_indices; unsigned int fill_vbo_n_indices; CoglAttribute *fill_attributes[COGL_PATH_N_ATTRIBUTES + 1]; CoglPrimitive *fill_primitive; CoglAttributeBuffer *stroke_attribute_buffer; CoglAttribute **stroke_attributes; unsigned int stroke_n_attributes; /* This is used as an optimisation for when the path contains a single contour specified using cogl2_path_rectangle. Cogl is more optimised to handle rectangles than paths so we can detect this case and divert to the journal or a rectangle clip. If it is TRUE then the entire path can be described by calling _cogl_path_get_bounds */ CoglBool is_rectangle; }; void _cogl_add_path_to_stencil_buffer (CoglPath *path, CoglBool merge, CoglBool need_clear); void _cogl_path_get_bounds (CoglPath *path, float *min_x, float *min_y, float *max_x, float *max_y); CoglBool _cogl_path_is_rectangle (CoglPath *path); #endif /* __COGL_PATH_PRIVATE_H */ muffin-5.2.1/cogl/cogl-path/cogl-path.h0000664000175000017500000000445214211404421017772 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PATH_H__ #define __COGL_PATH_H__ /** * SECTION:cogl-paths * @short_description: Functions for constructing and drawing 2D paths. * * There are two levels on which drawing with cogl-paths can be used. * The highest level functions construct various simple primitive * shapes to be either filled or stroked. Using a lower-level set of * functions more complex and arbitrary paths can be constructed by * concatenating straight line, bezier curve and arc segments. * * When constructing arbitrary paths, the current pen location is * initialized using the move_to command. The subsequent path segments * implicitly use the last pen location as their first vertex and move * the pen location to the last vertex they produce at the end. Also * there are special versions of functions that allow specifying the * vertices of the path segments relative to the last pen location * rather then in the absolute coordinates. */ #include #include #include #include #endif /* __COGL_PATH_H__ */ muffin-5.2.1/cogl/cogl-path/cogl-path-enum-types.h.in0000664000175000017500000000102314211404421022472 0ustar jpeisachjpeisach/*** BEGIN file-header ***/ #ifndef __COGL_PATH_ENUM_TYPES_H__ #define __COGL_PATH_ENUM_TYPES_H__ #include G_BEGIN_DECLS /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ /*** END file-production ***/ /*** BEGIN file-tail ***/ G_END_DECLS #endif /* __COGL_PATH_ENUM_TYPES_H__ */ /*** END file-tail ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) G_GNUC_CONST; #define COGL_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) /*** END value-header ***/ muffin-5.2.1/cogl/cogl-path/cogl-path.symbols0000664000175000017500000000232314211404421021226 0ustar jpeisachjpeisach/* cogl1-path-functions.h */ cogl_clip_push_from_path cogl_clip_push_from_path_preserve cogl_get_path cogl_is_path cogl_path_arc cogl_path_close cogl_path_copy cogl_path_curve_to cogl_path_ellipse cogl_path_fill cogl_path_fill_preserve cogl_path_get_fill_rule #ifdef COGL_HAS_GTYPE_SUPPORT cogl_path_get_gtype #endif cogl_path_line cogl_path_line_to cogl_path_move_to cogl_path_new cogl_path_polygon cogl_path_polyline cogl_path_rectangle cogl_path_rel_curve_to cogl_path_rel_line_to cogl_path_rel_move_to cogl_path_round_rectangle cogl_path_set_fill_rule cogl_path_stroke cogl_path_stroke_preserve cogl_set_path /* cogl2-path-functions.h */ cogl_framebuffer_fill_path cogl_framebuffer_push_path_clip cogl_framebuffer_stroke_path cogl2_clip_push_from_path cogl2_path_arc cogl2_path_close cogl2_path_curve_to cogl2_path_ellipse cogl2_path_fill cogl2_path_get_fill_rule cogl2_path_line cogl2_path_line_to cogl2_path_move_to cogl2_path_new cogl2_path_polygon cogl2_path_polyline cogl2_path_rectangle cogl2_path_rel_curve_to cogl2_path_rel_line_to cogl2_path_rel_move_to cogl2_path_round_rectangle cogl2_path_set_fill_rule cogl2_path_stroke /* cogl-path-enums.h-contents may change as header is generated */ cogl_path_fill_rule_get_type muffin-5.2.1/cogl/cogl-path/cogl-path-enum-types.c.in0000664000175000017500000000231314211404421022470 0ustar jpeisachjpeisach/*** BEGIN file-header ***/ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif /* We need to undefine this so that we will be sure to include * cogl-path.h instead of cogl2-path.h when we include the framebuffer * header. Otherwise it will include both headers and it won't * compile. */ #undef COGL_ENABLE_EXPERIMENTAL_2_0_API #include "cogl-path-enum-types.h" /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@filename@" */ #include "@filename@" /*** END file-production ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type (void) { static volatile gsize g_enum_type_id__volatile = 0; if (g_once_init_enter (&g_enum_type_id__volatile)) { static const G@Type@Value values[] = { /*** END value-header ***/ /*** BEGIN value-production ***/ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, /*** END value-production ***/ /*** BEGIN value-tail ***/ { 0, NULL, NULL } }; GType g_enum_type_id; g_enum_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id); } return g_enum_type_id__volatile; } /*** END value-tail ***/ muffin-5.2.1/cogl/cogl-path/cogl-path-functions.h0000664000175000017500000004016714211404421022003 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PATH_FUNCTIONS_H__ #define __COGL_PATH_FUNCTIONS_H__ #include #ifdef COGL_COMPILATION #include "cogl-context.h" #else #include #endif #include COGL_BEGIN_DECLS /** * cogl_path_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_path_get_gtype (void); #define cogl_path_new cogl2_path_new /** * cogl_path_new: * * Creates a new, empty path object. The default fill rule is * %COGL_PATH_FILL_RULE_EVEN_ODD. * * Return value: A pointer to a newly allocated #CoglPath, which can * be freed using cogl_object_unref(). * * Since: 2.0 */ CoglPath * cogl_path_new (void); /** * cogl_path_copy: * @path: A #CoglPath object * * Returns a new copy of the path in @path. The new path has a * reference count of 1 so you should unref it with * cogl_object_unref() if you no longer need it. * * Internally the path will share the data until one of the paths is * modified so copying paths should be relatively cheap. * * Return value: (transfer full): a copy of the path in @path. * * Since: 2.0 */ CoglPath * cogl_path_copy (CoglPath *path); /** * cogl_is_path: * @object: A #CoglObject * * Gets whether the given object references an existing path object. * * Return value: %TRUE if the object references a #CoglPath, * %FALSE otherwise. * * Since: 2.0 */ CoglBool cogl_is_path (void *object); #define cogl_path_move_to cogl2_path_move_to /** * cogl_path_move_to: * @x: X coordinate of the pen location to move to. * @y: Y coordinate of the pen location to move to. * * Moves the pen to the given location. If there is an existing path * this will start a new disjoint subpath. * * Since: 2.0 */ void cogl_path_move_to (CoglPath *path, float x, float y); #define cogl_path_rel_move_to cogl2_path_rel_move_to /** * cogl_path_rel_move_to: * @x: X offset from the current pen location to move the pen to. * @y: Y offset from the current pen location to move the pen to. * * Moves the pen to the given offset relative to the current pen * location. If there is an existing path this will start a new * disjoint subpath. * * Since: 2.0 */ void cogl_path_rel_move_to (CoglPath *path, float x, float y); #define cogl_path_line_to cogl2_path_line_to /** * cogl_path_line_to: * @x: X coordinate of the end line vertex * @y: Y coordinate of the end line vertex * * Adds a straight line segment to the current path that ends at the * given coordinates. * * Since: 2.0 */ void cogl_path_line_to (CoglPath *path, float x, float y); #define cogl_path_rel_line_to cogl2_path_rel_line_to /** * cogl_path_rel_line_to: * @x: X offset from the current pen location of the end line vertex * @y: Y offset from the current pen location of the end line vertex * * Adds a straight line segment to the current path that ends at the * given coordinates relative to the current pen location. * * Since: 2.0 */ void cogl_path_rel_line_to (CoglPath *path, float x, float y); #define cogl_path_arc cogl2_path_arc /** * cogl_path_arc: * @center_x: X coordinate of the elliptical arc center * @center_y: Y coordinate of the elliptical arc center * @radius_x: X radius of the elliptical arc * @radius_y: Y radius of the elliptical arc * @angle_1: Angle in degrees at which the arc begin * @angle_2: Angle in degrees at which the arc ends * * Adds an elliptical arc segment to the current path. A straight line * segment will link the current pen location with the first vertex * of the arc. If you perform a move_to to the arcs start just before * drawing it you create a free standing arc. * * The angles are measured in degrees where 0° is in the direction of * the positive X axis and 90° is in the direction of the positive Y * axis. The angle of the arc begins at @angle_1 and heads towards * @angle_2 (so if @angle_2 is less than @angle_1 it will decrease, * otherwise it will increase). * * Since: 2.0 */ void cogl_path_arc (CoglPath *path, float center_x, float center_y, float radius_x, float radius_y, float angle_1, float angle_2); #define cogl_path_curve_to cogl2_path_curve_to /** * cogl_path_curve_to: * @x_1: X coordinate of the second bezier control point * @y_1: Y coordinate of the second bezier control point * @x_2: X coordinate of the third bezier control point * @y_2: Y coordinate of the third bezier control point * @x_3: X coordinate of the fourth bezier control point * @y_3: Y coordinate of the fourth bezier control point * * Adds a cubic bezier curve segment to the current path with the given * second, third and fourth control points and using current pen location * as the first control point. * * Since: 2.0 */ void cogl_path_curve_to (CoglPath *path, float x_1, float y_1, float x_2, float y_2, float x_3, float y_3); #define cogl_path_rel_curve_to cogl2_path_rel_curve_to /** * cogl_path_rel_curve_to: * @x_1: X coordinate of the second bezier control point * @y_1: Y coordinate of the second bezier control point * @x_2: X coordinate of the third bezier control point * @y_2: Y coordinate of the third bezier control point * @x_3: X coordinate of the fourth bezier control point * @y_3: Y coordinate of the fourth bezier control point * * Adds a cubic bezier curve segment to the current path with the given * second, third and fourth control points and using current pen location * as the first control point. The given coordinates are relative to the * current pen location. * * Since: 2.0 */ void cogl_path_rel_curve_to (CoglPath *path, float x_1, float y_1, float x_2, float y_2, float x_3, float y_3); #define cogl_path_close cogl2_path_close /** * cogl_path_close: * * Closes the path being constructed by adding a straight line segment * to it that ends at the first vertex of the path. * * Since: 2.0 */ void cogl_path_close (CoglPath *path); #define cogl_path_line cogl2_path_line /** * cogl_path_line: * @x_1: X coordinate of the start line vertex * @y_1: Y coordinate of the start line vertex * @x_2: X coordinate of the end line vertex * @y_2: Y coordinate of the end line vertex * * Constructs a straight line shape starting and ending at the given * coordinates. If there is an existing path this will start a new * disjoint sub-path. * * Since: 2.0 */ void cogl_path_line (CoglPath *path, float x_1, float y_1, float x_2, float y_2); #define cogl_path_polyline cogl2_path_polyline /** * cogl_path_polyline: * @coords: (in) (array) (transfer none): A pointer to the first element of an * array of fixed-point values that specify the vertex coordinates. * @num_points: The total number of vertices. * * Constructs a series of straight line segments, starting from the * first given vertex coordinate. If there is an existing path this * will start a new disjoint sub-path. Each subsequent segment starts * where the previous one ended and ends at the next given vertex * coordinate. * * The coords array must contain 2 * num_points values. The first value * represents the X coordinate of the first vertex, the second value * represents the Y coordinate of the first vertex, continuing in the same * fashion for the rest of the vertices. (num_points - 1) segments will * be constructed. * * Since: 2.0 */ void cogl_path_polyline (CoglPath *path, const float *coords, int num_points); #define cogl_path_polygon cogl2_path_polygon /** * cogl_path_polygon: * @coords: (in) (array) (transfer none): A pointer to the first element of * an array of fixed-point values that specify the vertex coordinates. * @num_points: The total number of vertices. * * Constructs a polygonal shape of the given number of vertices. If * there is an existing path this will start a new disjoint sub-path. * * The coords array must contain 2 * num_points values. The first value * represents the X coordinate of the first vertex, the second value * represents the Y coordinate of the first vertex, continuing in the same * fashion for the rest of the vertices. * * Since: 2.0 */ void cogl_path_polygon (CoglPath *path, const float *coords, int num_points); #define cogl_path_rectangle cogl2_path_rectangle /** * cogl_path_rectangle: * @x_1: X coordinate of the top-left corner. * @y_1: Y coordinate of the top-left corner. * @x_2: X coordinate of the bottom-right corner. * @y_2: Y coordinate of the bottom-right corner. * * Constructs a rectangular shape at the given coordinates. If there * is an existing path this will start a new disjoint sub-path. * * Since: 2.0 */ void cogl_path_rectangle (CoglPath *path, float x_1, float y_1, float x_2, float y_2); #define cogl_path_ellipse cogl2_path_ellipse /** * cogl_path_ellipse: * @center_x: X coordinate of the ellipse center * @center_y: Y coordinate of the ellipse center * @radius_x: X radius of the ellipse * @radius_y: Y radius of the ellipse * * Constructs an ellipse shape. If there is an existing path this will * start a new disjoint sub-path. * * Since: 2.0 */ void cogl_path_ellipse (CoglPath *path, float center_x, float center_y, float radius_x, float radius_y); #define cogl_path_round_rectangle cogl2_path_round_rectangle /** * cogl_path_round_rectangle: * @x_1: X coordinate of the top-left corner. * @y_1: Y coordinate of the top-left corner. * @x_2: X coordinate of the bottom-right corner. * @y_2: Y coordinate of the bottom-right corner. * @radius: Radius of the corner arcs. * @arc_step: Angle increment resolution for subdivision of * the corner arcs. * * Constructs a rectangular shape with rounded corners. If there is an * existing path this will start a new disjoint sub-path. * * Since: 2.0 */ void cogl_path_round_rectangle (CoglPath *path, float x_1, float y_1, float x_2, float y_2, float radius, float arc_step); #define cogl_path_set_fill_rule cogl2_path_set_fill_rule /** * cogl_path_set_fill_rule: * @fill_rule: The new fill rule. * * Sets the fill rule of the current path to @fill_rule. This will * affect how the path is filled when cogl_path_fill() is later * called. Note that the fill rule state is attached to the path so * calling cogl_get_path() will preserve the fill rule and calling * cogl_path_new() will reset the fill rule back to the default. * * Since: 2.0 */ void cogl_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule); #define cogl_path_get_fill_rule cogl2_path_get_fill_rule /** * cogl_path_get_fill_rule: * * Retrieves the fill rule set using cogl_path_set_fill_rule(). * * Return value: the fill rule that is used for the current path. * * Since: 2.0 */ CoglPathFillRule cogl_path_get_fill_rule (CoglPath *path); #define cogl_path_fill cogl2_path_fill /** * cogl_path_fill: * * Fills the interior of the constructed shape using the current * drawing color. * * The interior of the shape is determined using the fill rule of the * path. See %CoglPathFillRule for details. * * The result of referencing sliced textures in your current * pipeline when filling a path are undefined. You should pass * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will * use while filling a path. * * Since: 2.0 */ void cogl_path_fill (CoglPath *path); /** * cogl_framebuffer_fill_path: * @framebuffer: A #CoglFramebuffer * @pipeline: A #CoglPipeline to render with * @path: The #CoglPath to fill * * Fills the interior of the path using the fragment operations * defined by the pipeline. * * The interior of the shape is determined using the fill rule of the * path. See %CoglPathFillRule for details. * * The result of referencing sliced textures in your current * pipeline when filling a path are undefined. You should pass * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will * use while filling a path. * * Stability: unstable * Deprecated: 1.16: Use cogl_path_fill() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_path_fill) void cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglPath *path); #define cogl_path_stroke cogl2_path_stroke /** * cogl_path_stroke: * * Strokes the constructed shape using the current drawing color and a * width of 1 pixel (regardless of the current transformation * matrix). * * Since: 2.0 */ void cogl_path_stroke (CoglPath *path); /** * cogl_framebuffer_stroke_path: * @framebuffer: A #CoglFramebuffer * @pipeline: A #CoglPipeline to render with * @path: The #CoglPath to stroke * * Strokes the edge of the path using the fragment operations defined * by the pipeline. The stroke line will have a width of 1 pixel * regardless of the current transformation matrix. * * Stability: unstable * Deprecated: 1.16: Use cogl_path_stroke() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_path_stroke) void cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglPath *path); /** * cogl_framebuffer_push_path_clip: * @framebuffer: A #CoglFramebuffer pointer * @path: The path to clip with. * * Sets a new clipping area using the silhouette of the specified, * filled @path. The clipping area is intersected with the previous * clipping area. To restore the previous clipping area, call * cogl_framebuffer_pop_clip(). * * Since: 1.0 * Stability: unstable */ void cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer, CoglPath *path); #define cogl_clip_push_from_path cogl2_clip_push_from_path /** * cogl_clip_push_from_path: * @path: The path to clip with. * * Sets a new clipping area using the silhouette of the specified, * filled @path. The clipping area is intersected with the previous * clipping area. To restore the previous clipping area, call * call cogl_clip_pop(). * * Since: 1.8 * Stability: Unstable * Deprecated: 1.16: Use cogl_framebuffer_push_path_clip() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_framebuffer_push_path_clip) void cogl_clip_push_from_path (CoglPath *path); COGL_END_DECLS #endif /* __COGL_PATH_FUNCTIONS_H__ */ muffin-5.2.1/cogl/cogl-path/muffin-cogl-path.pc.in0000664000175000017500000000062614211404421022033 0ustar jpeisachjpeisachprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@/muffin includedir=@includedir@/muffin apiversion=@MUFFIN_PLUGIN_API_VERSION@ requires=@COGL_PKG_REQUIRES@ muffin-cogl-@MUFFIN_PLUGIN_API_VERSION@ Name: Cogl Description: A 2D path drawing library for Cogl Version: @MUFFIN_VERSION@ Libs: -L${libdir} -lmuffin-cogl-path-@MUFFIN_PLUGIN_API_VERSION@ Cflags: -I${includedir}/cogl Requires: ${requires} muffin-5.2.1/cogl/cogl-path/cogl-path.c0000664000175000017500000012777214211404421020000 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Ivan Leben * Øyvind Kolås * Neil Roberts * Robert Bragg */ #include "cogl-config.h" #include "cogl-util.h" #include "cogl-object.h" #include "cogl-context-private.h" #include "cogl-journal-private.h" #include "cogl-pipeline-private.h" #include "cogl-framebuffer-private.h" #include "cogl-primitive-private.h" #include "cogl-texture-private.h" #include "cogl-primitives-private.h" #include "cogl-private.h" #include "cogl-attribute-private.h" #include "cogl1-context.h" #include "tesselator/tesselator.h" #include "cogl-path/cogl-path.h" #include "cogl-path-private.h" #include "cogl-gtype-private.h" #include #include #define _COGL_MAX_BEZ_RECURSE_DEPTH 16 static void _cogl_path_free (CoglPath *path); static void _cogl_path_build_fill_attribute_buffer (CoglPath *path); static CoglPrimitive *_cogl_path_get_fill_primitive (CoglPath *path); static void _cogl_path_build_stroke_attribute_buffer (CoglPath *path); COGL_OBJECT_DEFINE (Path, path); COGL_GTYPE_DEFINE_CLASS (Path, path); static void _cogl_path_data_clear_vbos (CoglPathData *data) { int i; if (data->fill_attribute_buffer) { cogl_object_unref (data->fill_attribute_buffer); cogl_object_unref (data->fill_vbo_indices); for (i = 0; i < COGL_PATH_N_ATTRIBUTES; i++) cogl_object_unref (data->fill_attributes[i]); data->fill_attribute_buffer = NULL; } if (data->fill_primitive) { cogl_object_unref (data->fill_primitive); data->fill_primitive = NULL; } if (data->stroke_attribute_buffer) { cogl_object_unref (data->stroke_attribute_buffer); for (i = 0; i < data->stroke_n_attributes; i++) cogl_object_unref (data->stroke_attributes[i]); free (data->stroke_attributes); data->stroke_attribute_buffer = NULL; } } static void _cogl_path_data_unref (CoglPathData *data) { if (--data->ref_count <= 0) { _cogl_path_data_clear_vbos (data); g_array_free (data->path_nodes, TRUE); g_slice_free (CoglPathData, data); } } static void _cogl_path_modify (CoglPath *path) { /* This needs to be called whenever the path is about to be modified to implement copy-on-write semantics */ /* If there is more than one path using the data then we need to copy the data instead */ if (path->data->ref_count != 1) { CoglPathData *old_data = path->data; path->data = g_slice_dup (CoglPathData, old_data); path->data->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); g_array_append_vals (path->data->path_nodes, old_data->path_nodes->data, old_data->path_nodes->len); path->data->fill_attribute_buffer = NULL; path->data->fill_primitive = NULL; path->data->stroke_attribute_buffer = NULL; path->data->ref_count = 1; _cogl_path_data_unref (old_data); } else /* The path is altered so the vbos will now be invalid */ _cogl_path_data_clear_vbos (path->data); } void cogl2_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule) { _COGL_RETURN_IF_FAIL (cogl_is_path (path)); if (path->data->fill_rule != fill_rule) { _cogl_path_modify (path); path->data->fill_rule = fill_rule; } } CoglPathFillRule cogl2_path_get_fill_rule (CoglPath *path) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (path), COGL_PATH_FILL_RULE_NON_ZERO); return path->data->fill_rule; } static void _cogl_path_add_node (CoglPath *path, CoglBool new_sub_path, float x, float y) { CoglPathNode new_node; CoglPathData *data; _cogl_path_modify (path); data = path->data; new_node.x = x; new_node.y = y; new_node.path_size = 0; if (new_sub_path || data->path_nodes->len == 0) data->last_path = data->path_nodes->len; g_array_append_val (data->path_nodes, new_node); g_array_index (data->path_nodes, CoglPathNode, data->last_path).path_size++; if (data->path_nodes->len == 1) { data->path_nodes_min.x = data->path_nodes_max.x = x; data->path_nodes_min.y = data->path_nodes_max.y = y; } else { if (x < data->path_nodes_min.x) data->path_nodes_min.x = x; if (x > data->path_nodes_max.x) data->path_nodes_max.x = x; if (y < data->path_nodes_min.y) data->path_nodes_min.y = y; if (y > data->path_nodes_max.y) data->path_nodes_max.y = y; } /* Once the path nodes have been modified then we'll assume it's no longer a rectangle. cogl2_path_rectangle will set this back to TRUE if this has been called from there */ data->is_rectangle = FALSE; } static void _cogl_path_stroke_nodes (CoglPath *path, CoglFramebuffer *framebuffer, CoglPipeline *pipeline) { CoglPathData *data; CoglPipeline *copy = NULL; unsigned int path_start; int path_num = 0; CoglPathNode *node; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer)); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); data = path->data; if (data->path_nodes->len == 0) return; if (cogl_pipeline_get_n_layers (pipeline) != 0) { copy = cogl_pipeline_copy (pipeline); _cogl_pipeline_prune_to_n_layers (copy, 0); pipeline = copy; } _cogl_path_build_stroke_attribute_buffer (path); for (path_start = 0; path_start < data->path_nodes->len; path_start += node->path_size) { CoglPrimitive *primitive; node = &g_array_index (data->path_nodes, CoglPathNode, path_start); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_LINE_STRIP, node->path_size, &data->stroke_attributes[path_num], 1); cogl_primitive_draw (primitive, framebuffer, pipeline); cogl_object_unref (primitive); path_num++; } if (copy) cogl_object_unref (copy); } void _cogl_path_get_bounds (CoglPath *path, float *min_x, float *min_y, float *max_x, float *max_y) { CoglPathData *data = path->data; if (data->path_nodes->len == 0) { *min_x = 0.0f; *min_y = 0.0f; *max_x = 0.0f; *max_y = 0.0f; } else { *min_x = data->path_nodes_min.x; *min_y = data->path_nodes_min.y; *max_x = data->path_nodes_max.x; *max_y = data->path_nodes_max.y; } } static void _cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path, CoglFramebuffer *framebuffer, CoglPipeline *pipeline) { /* We need at least three stencil bits to combine clips */ if (_cogl_framebuffer_get_stencil_bits (framebuffer) >= 3) { static CoglBool seen_warning = FALSE; if (!seen_warning) { g_warning ("Paths can not be filled using materials with " "sliced textures unless there is a stencil " "buffer"); seen_warning = TRUE; } } cogl_framebuffer_push_path_clip (framebuffer, path); cogl_framebuffer_draw_rectangle (framebuffer, pipeline, path->data->path_nodes_min.x, path->data->path_nodes_min.y, path->data->path_nodes_max.x, path->data->path_nodes_max.y); cogl_framebuffer_pop_clip (framebuffer); } static CoglBool validate_layer_cb (CoglPipelineLayer *layer, void *user_data) { CoglBool *needs_fallback = user_data; CoglTexture *texture = _cogl_pipeline_layer_get_texture (layer); /* If any of the layers of the current pipeline contain sliced * textures or textures with waste then it won't work to draw the * path directly. Instead we fallback to pushing the path as a clip * on the clip-stack and drawing the path's bounding rectangle * instead. */ if (texture != NULL && (cogl_texture_is_sliced (texture) || !_cogl_texture_can_hardware_repeat (texture))) *needs_fallback = TRUE; return !*needs_fallback; } static void _cogl_path_fill_nodes (CoglPath *path, CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglDrawFlags flags) { if (path->data->path_nodes->len == 0) return; /* If the path is a simple rectangle then we can divert to using cogl_framebuffer_draw_rectangle which should be faster because it can go through the journal instead of uploading the geometry just for two triangles */ if (path->data->is_rectangle && flags == 0) { float x_1, y_1, x_2, y_2; _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2); cogl_framebuffer_draw_rectangle (framebuffer, pipeline, x_1, y_1, x_2, y_2); } else { CoglBool needs_fallback = FALSE; CoglPrimitive *primitive; _cogl_pipeline_foreach_layer_internal (pipeline, validate_layer_cb, &needs_fallback); if (needs_fallback) { _cogl_path_fill_nodes_with_clipped_rectangle (path, framebuffer, pipeline); return; } primitive = _cogl_path_get_fill_primitive (path); _cogl_primitive_draw (primitive, framebuffer, pipeline, flags); } } /* TODO: Update to the protoype used in the Cogl master branch. * This is experimental API but not in sync with the cogl_path_fill() * api in Cogl master which takes explicit framebuffer and pipeline * arguments */ void cogl2_path_fill (CoglPath *path) { _COGL_RETURN_IF_FAIL (cogl_is_path (path)); _cogl_path_fill_nodes (path, cogl_get_draw_framebuffer (), cogl_get_source (), 0 /* flags */); } /* TODO: Update to the protoype used in the Cogl master branch. * This is experimental API but not in sync with the cogl_path_fill() * api in Cogl master which takes explicit framebuffer and pipeline * arguments */ void cogl2_path_stroke (CoglPath *path) { _COGL_RETURN_IF_FAIL (cogl_is_path (path)); if (path->data->path_nodes->len == 0) return; _cogl_path_stroke_nodes (path, cogl_get_draw_framebuffer (), cogl_get_source ()); } void cogl2_path_move_to (CoglPath *path, float x, float y) { CoglPathData *data; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); _cogl_path_add_node (path, TRUE, x, y); data = path->data; data->path_start.x = x; data->path_start.y = y; data->path_pen = data->path_start; } void cogl2_path_rel_move_to (CoglPath *path, float x, float y) { CoglPathData *data; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); data = path->data; cogl2_path_move_to (path, data->path_pen.x + x, data->path_pen.y + y); } void cogl2_path_line_to (CoglPath *path, float x, float y) { CoglPathData *data; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); _cogl_path_add_node (path, FALSE, x, y); data = path->data; data->path_pen.x = x; data->path_pen.y = y; } void cogl2_path_rel_line_to (CoglPath *path, float x, float y) { CoglPathData *data; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); data = path->data; cogl2_path_line_to (path, data->path_pen.x + x, data->path_pen.y + y); } void cogl2_path_close (CoglPath *path) { _COGL_RETURN_IF_FAIL (cogl_is_path (path)); _cogl_path_add_node (path, FALSE, path->data->path_start.x, path->data->path_start.y); path->data->path_pen = path->data->path_start; } void cogl2_path_line (CoglPath *path, float x_1, float y_1, float x_2, float y_2) { cogl2_path_move_to (path, x_1, y_1); cogl2_path_line_to (path, x_2, y_2); } void cogl2_path_polyline (CoglPath *path, const float *coords, int num_points) { int c = 0; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); cogl2_path_move_to (path, coords[0], coords[1]); for (c = 1; c < num_points; ++c) cogl2_path_line_to (path, coords[2*c], coords[2*c+1]); } void cogl2_path_polygon (CoglPath *path, const float *coords, int num_points) { cogl2_path_polyline (path, coords, num_points); cogl2_path_close (path); } void cogl2_path_rectangle (CoglPath *path, float x_1, float y_1, float x_2, float y_2) { CoglBool is_rectangle; /* If the path was previously empty and the rectangle isn't mirrored then we'll record that this is a simple rectangle path so that we can optimise it */ is_rectangle = (path->data->path_nodes->len == 0 && x_2 >= x_1 && y_2 >= y_1); cogl2_path_move_to (path, x_1, y_1); cogl2_path_line_to (path, x_2, y_1); cogl2_path_line_to (path, x_2, y_2); cogl2_path_line_to (path, x_1, y_2); cogl2_path_close (path); path->data->is_rectangle = is_rectangle; } CoglBool _cogl_path_is_rectangle (CoglPath *path) { return path->data->is_rectangle; } static void _cogl_path_arc (CoglPath *path, float center_x, float center_y, float radius_x, float radius_y, float angle_1, float angle_2, float angle_step, unsigned int move_first) { float a = 0x0; float cosa = 0x0; float sina = 0x0; float px = 0x0; float py = 0x0; /* Fix invalid angles */ if (angle_1 == angle_2 || angle_step == 0x0) return; if (angle_step < 0x0) angle_step = -angle_step; /* Walk the arc by given step */ a = angle_1; while (a != angle_2) { cosa = cosf (a * (G_PI/180.0)); sina = sinf (a * (G_PI/180.0)); px = center_x + (cosa * radius_x); py = center_y + (sina * radius_y); if (a == angle_1 && move_first) cogl2_path_move_to (path, px, py); else cogl2_path_line_to (path, px, py); if (G_LIKELY (angle_2 > angle_1)) { a += angle_step; if (a > angle_2) a = angle_2; } else { a -= angle_step; if (a < angle_2) a = angle_2; } } /* Make sure the final point is drawn */ cosa = cosf (angle_2 * (G_PI/180.0)); sina = sinf (angle_2 * (G_PI/180.0)); px = center_x + (cosa * radius_x); py = center_y + (sina * radius_y); cogl2_path_line_to (path, px, py); } void cogl2_path_arc (CoglPath *path, float center_x, float center_y, float radius_x, float radius_y, float angle_1, float angle_2) { float angle_step = 10; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); /* it is documented that a move to is needed to create a freestanding * arc */ _cogl_path_arc (path, center_x, center_y, radius_x, radius_y, angle_1, angle_2, angle_step, 0 /* no move */); } static void _cogl_path_rel_arc (CoglPath *path, float center_x, float center_y, float radius_x, float radius_y, float angle_1, float angle_2, float angle_step) { CoglPathData *data; data = path->data; _cogl_path_arc (path, data->path_pen.x + center_x, data->path_pen.y + center_y, radius_x, radius_y, angle_1, angle_2, angle_step, 0 /* no move */); } void cogl2_path_ellipse (CoglPath *path, float center_x, float center_y, float radius_x, float radius_y) { float angle_step = 10; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); /* FIXME: if shows to be slow might be optimized * by mirroring just a quarter of it */ _cogl_path_arc (path, center_x, center_y, radius_x, radius_y, 0, 360, angle_step, 1 /* move first */); cogl2_path_close (path); } void cogl2_path_round_rectangle (CoglPath *path, float x_1, float y_1, float x_2, float y_2, float radius, float arc_step) { float inner_width = x_2 - x_1 - radius * 2; float inner_height = y_2 - y_1 - radius * 2; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); cogl2_path_move_to (path, x_1, y_1 + radius); _cogl_path_rel_arc (path, radius, 0, radius, radius, 180, 270, arc_step); cogl2_path_line_to (path, path->data->path_pen.x + inner_width, path->data->path_pen.y); _cogl_path_rel_arc (path, 0, radius, radius, radius, -90, 0, arc_step); cogl2_path_line_to (path, path->data->path_pen.x, path->data->path_pen.y + inner_height); _cogl_path_rel_arc (path, -radius, 0, radius, radius, 0, 90, arc_step); cogl2_path_line_to (path, path->data->path_pen.x - inner_width, path->data->path_pen.y); _cogl_path_rel_arc (path, 0, -radius, radius, radius, 90, 180, arc_step); cogl2_path_close (path); } static void _cogl_path_bezier3_sub (CoglPath *path, CoglBezCubic *cubic) { CoglBezCubic cubics[_COGL_MAX_BEZ_RECURSE_DEPTH]; CoglBezCubic *cleft; CoglBezCubic *cright; CoglBezCubic *c; floatVec2 dif1; floatVec2 dif2; floatVec2 mm; floatVec2 c1; floatVec2 c2; floatVec2 c3; floatVec2 c4; floatVec2 c5; int cindex; /* Put first curve on stack */ cubics[0] = *cubic; cindex = 0; while (cindex >= 0) { c = &cubics[cindex]; /* Calculate distance of control points from their * counterparts on the line between end points */ dif1.x = (c->p2.x * 3) - (c->p1.x * 2) - c->p4.x; dif1.y = (c->p2.y * 3) - (c->p1.y * 2) - c->p4.y; dif2.x = (c->p3.x * 3) - (c->p4.x * 2) - c->p1.x; dif2.y = (c->p3.y * 3) - (c->p4.y * 2) - c->p1.y; if (dif1.x < 0) dif1.x = -dif1.x; if (dif1.y < 0) dif1.y = -dif1.y; if (dif2.x < 0) dif2.x = -dif2.x; if (dif2.y < 0) dif2.y = -dif2.y; /* Pick the greatest of two distances */ if (dif1.x < dif2.x) dif1.x = dif2.x; if (dif1.y < dif2.y) dif1.y = dif2.y; /* Cancel if the curve is flat enough */ if (dif1.x + dif1.y <= 1.0 || cindex == _COGL_MAX_BEZ_RECURSE_DEPTH-1) { /* Add subdivision point (skip last) */ if (cindex == 0) return; _cogl_path_add_node (path, FALSE, c->p4.x, c->p4.y); --cindex; continue; } /* Left recursion goes on top of stack! */ cright = c; cleft = &cubics[++cindex]; /* Subdivide into 2 sub-curves */ c1.x = ((c->p1.x + c->p2.x) / 2); c1.y = ((c->p1.y + c->p2.y) / 2); mm.x = ((c->p2.x + c->p3.x) / 2); mm.y = ((c->p2.y + c->p3.y) / 2); c5.x = ((c->p3.x + c->p4.x) / 2); c5.y = ((c->p3.y + c->p4.y) / 2); c2.x = ((c1.x + mm.x) / 2); c2.y = ((c1.y + mm.y) / 2); c4.x = ((mm.x + c5.x) / 2); c4.y = ((mm.y + c5.y) / 2); c3.x = ((c2.x + c4.x) / 2); c3.y = ((c2.y + c4.y) / 2); /* Add left recursion to stack */ cleft->p1 = c->p1; cleft->p2 = c1; cleft->p3 = c2; cleft->p4 = c3; /* Add right recursion to stack */ cright->p1 = c3; cright->p2 = c4; cright->p3 = c5; cright->p4 = c->p4; } } void cogl2_path_curve_to (CoglPath *path, float x_1, float y_1, float x_2, float y_2, float x_3, float y_3) { CoglBezCubic cubic; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); /* Prepare cubic curve */ cubic.p1 = path->data->path_pen; cubic.p2.x = x_1; cubic.p2.y = y_1; cubic.p3.x = x_2; cubic.p3.y = y_2; cubic.p4.x = x_3; cubic.p4.y = y_3; /* Run subdivision */ _cogl_path_bezier3_sub (path, &cubic); /* Add last point */ _cogl_path_add_node (path, FALSE, cubic.p4.x, cubic.p4.y); path->data->path_pen = cubic.p4; } void cogl2_path_rel_curve_to (CoglPath *path, float x_1, float y_1, float x_2, float y_2, float x_3, float y_3) { CoglPathData *data; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); data = path->data; cogl2_path_curve_to (path, data->path_pen.x + x_1, data->path_pen.y + y_1, data->path_pen.x + x_2, data->path_pen.y + y_2, data->path_pen.x + x_3, data->path_pen.y + y_3); } CoglPath * cogl2_path_new (void) { CoglPath *path; CoglPathData *data; _COGL_GET_CONTEXT (ctx, NULL); path = g_slice_new (CoglPath); data = path->data = g_slice_new (CoglPathData); data->ref_count = 1; data->context = ctx; data->fill_rule = COGL_PATH_FILL_RULE_EVEN_ODD; data->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); data->last_path = 0; data->fill_attribute_buffer = NULL; data->stroke_attribute_buffer = NULL; data->fill_primitive = NULL; data->is_rectangle = FALSE; return _cogl_path_object_new (path); } CoglPath * cogl_path_copy (CoglPath *old_path) { CoglPath *new_path; _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (old_path), NULL); new_path = g_slice_new (CoglPath); new_path->data = old_path->data; new_path->data->ref_count++; return _cogl_path_object_new (new_path); } static void _cogl_path_free (CoglPath *path) { _cogl_path_data_unref (path->data); g_slice_free (CoglPath, path); } /* If second order beziers were needed the following code could * be re-enabled: */ #if 0 static void _cogl_path_bezier2_sub (CoglPath *path, CoglBezQuad *quad) { CoglBezQuad quads[_COGL_MAX_BEZ_RECURSE_DEPTH]; CoglBezQuad *qleft; CoglBezQuad *qright; CoglBezQuad *q; floatVec2 mid; floatVec2 dif; floatVec2 c1; floatVec2 c2; floatVec2 c3; int qindex; /* Put first curve on stack */ quads[0] = *quad; qindex = 0; /* While stack is not empty */ while (qindex >= 0) { q = &quads[qindex]; /* Calculate distance of control point from its * counterpart on the line between end points */ mid.x = ((q->p1.x + q->p3.x) / 2); mid.y = ((q->p1.y + q->p3.y) / 2); dif.x = (q->p2.x - mid.x); dif.y = (q->p2.y - mid.y); if (dif.x < 0) dif.x = -dif.x; if (dif.y < 0) dif.y = -dif.y; /* Cancel if the curve is flat enough */ if (dif.x + dif.y <= 1.0 || qindex == _COGL_MAX_BEZ_RECURSE_DEPTH - 1) { /* Add subdivision point (skip last) */ if (qindex == 0) return; _cogl_path_add_node (path, FALSE, q->p3.x, q->p3.y); --qindex; continue; } /* Left recursion goes on top of stack! */ qright = q; qleft = &quads[++qindex]; /* Subdivide into 2 sub-curves */ c1.x = ((q->p1.x + q->p2.x) / 2); c1.y = ((q->p1.y + q->p2.y) / 2); c3.x = ((q->p2.x + q->p3.x) / 2); c3.y = ((q->p2.y + q->p3.y) / 2); c2.x = ((c1.x + c3.x) / 2); c2.y = ((c1.y + c3.y) / 2); /* Add left recursion onto stack */ qleft->p1 = q->p1; qleft->p2 = c1; qleft->p3 = c2; /* Add right recursion onto stack */ qright->p1 = c2; qright->p2 = c3; qright->p3 = q->p3; } } void cogl_path_curve2_to (CoglPath *path, float x_1, float y_1, float x_2, float y_2) { CoglBezQuad quad; /* Prepare quadratic curve */ quad.p1 = path->data->path_pen; quad.p2.x = x_1; quad.p2.y = y_1; quad.p3.x = x_2; quad.p3.y = y_2; /* Run subdivision */ _cogl_path_bezier2_sub (&quad); /* Add last point */ _cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y); path->data->path_pen = quad.p3; } void cogl_rel_curve2_to (CoglPath *path, float x_1, float y_1, float x_2, float y_2) { CoglPathData *data; _COGL_RETURN_IF_FAIL (cogl_is_path (path)); data = path->data; cogl_path_curve2_to (data->path_pen.x + x_1, data->path_pen.y + y_1, data->path_pen.x + x_2, data->path_pen.y + y_2); } #endif typedef struct _CoglPathTesselator CoglPathTesselator; typedef struct _CoglPathTesselatorVertex CoglPathTesselatorVertex; struct _CoglPathTesselator { GLUtesselator *glu_tess; GLenum primitive_type; int vertex_number; /* Array of CoglPathTesselatorVertex. This needs to grow when the combine callback is called */ GArray *vertices; /* Array of integers for the indices into the vertices array. Each element will either be uint8_t, uint16_t or uint32_t depending on the number of vertices */ GArray *indices; CoglIndicesType indices_type; /* Indices used to split fans and strips */ int index_a, index_b; }; struct _CoglPathTesselatorVertex { float x, y, s, t; }; static void _cogl_path_tesselator_begin (GLenum type, CoglPathTesselator *tess) { g_assert (type == GL_TRIANGLES || type == GL_TRIANGLE_FAN || type == GL_TRIANGLE_STRIP); tess->primitive_type = type; tess->vertex_number = 0; } static CoglIndicesType _cogl_path_tesselator_get_indices_type_for_size (int n_vertices) { if (n_vertices <= 256) return COGL_INDICES_TYPE_UNSIGNED_BYTE; else if (n_vertices <= 65536) return COGL_INDICES_TYPE_UNSIGNED_SHORT; else return COGL_INDICES_TYPE_UNSIGNED_INT; } static void _cogl_path_tesselator_allocate_indices_array (CoglPathTesselator *tess) { switch (tess->indices_type) { case COGL_INDICES_TYPE_UNSIGNED_BYTE: tess->indices = g_array_new (FALSE, FALSE, sizeof (uint8_t)); break; case COGL_INDICES_TYPE_UNSIGNED_SHORT: tess->indices = g_array_new (FALSE, FALSE, sizeof (uint16_t)); break; case COGL_INDICES_TYPE_UNSIGNED_INT: tess->indices = g_array_new (FALSE, FALSE, sizeof (uint32_t)); break; } } static void _cogl_path_tesselator_add_index (CoglPathTesselator *tess, int vertex_index) { switch (tess->indices_type) { case COGL_INDICES_TYPE_UNSIGNED_BYTE: { uint8_t val = vertex_index; g_array_append_val (tess->indices, val); } break; case COGL_INDICES_TYPE_UNSIGNED_SHORT: { uint16_t val = vertex_index; g_array_append_val (tess->indices, val); } break; case COGL_INDICES_TYPE_UNSIGNED_INT: { uint32_t val = vertex_index; g_array_append_val (tess->indices, val); } break; } } static void _cogl_path_tesselator_vertex (void *vertex_data, CoglPathTesselator *tess) { int vertex_index; vertex_index = GPOINTER_TO_INT (vertex_data); /* This tries to convert all of the primitives into GL_TRIANGLES with indices to share vertices */ switch (tess->primitive_type) { case GL_TRIANGLES: /* Directly use the vertex */ _cogl_path_tesselator_add_index (tess, vertex_index); break; case GL_TRIANGLE_FAN: if (tess->vertex_number == 0) tess->index_a = vertex_index; else if (tess->vertex_number == 1) tess->index_b = vertex_index; else { /* Create a triangle with the first vertex, the previous vertex and this vertex */ _cogl_path_tesselator_add_index (tess, tess->index_a); _cogl_path_tesselator_add_index (tess, tess->index_b); _cogl_path_tesselator_add_index (tess, vertex_index); /* Next time we will use this vertex as the previous vertex */ tess->index_b = vertex_index; } break; case GL_TRIANGLE_STRIP: if (tess->vertex_number == 0) tess->index_a = vertex_index; else if (tess->vertex_number == 1) tess->index_b = vertex_index; else { _cogl_path_tesselator_add_index (tess, tess->index_a); _cogl_path_tesselator_add_index (tess, tess->index_b); _cogl_path_tesselator_add_index (tess, vertex_index); if (tess->vertex_number & 1) tess->index_b = vertex_index; else tess->index_a = vertex_index; } break; default: g_assert_not_reached (); } tess->vertex_number++; } static void _cogl_path_tesselator_end (CoglPathTesselator *tess) { tess->primitive_type = GL_FALSE; } static void _cogl_path_tesselator_combine (double coords[3], void *vertex_data[4], float weight[4], void **out_data, CoglPathTesselator *tess) { CoglPathTesselatorVertex *vertex; CoglIndicesType new_indices_type; int i; /* Add a new vertex to the array */ g_array_set_size (tess->vertices, tess->vertices->len + 1); vertex = &g_array_index (tess->vertices, CoglPathTesselatorVertex, tess->vertices->len - 1); /* The data is just the index to the vertex */ *out_data = GINT_TO_POINTER (tess->vertices->len - 1); /* Set the coordinates of the new vertex */ vertex->x = coords[0]; vertex->y = coords[1]; /* Generate the texture coordinates as the weighted average of the four incoming coordinates */ vertex->s = 0.0f; vertex->t = 0.0f; for (i = 0; i < 4; i++) { CoglPathTesselatorVertex *old_vertex = &g_array_index (tess->vertices, CoglPathTesselatorVertex, GPOINTER_TO_INT (vertex_data[i])); vertex->s += old_vertex->s * weight[i]; vertex->t += old_vertex->t * weight[i]; } /* Check if we've reached the limit for the data type of our indices */ new_indices_type = _cogl_path_tesselator_get_indices_type_for_size (tess->vertices->len); if (new_indices_type != tess->indices_type) { CoglIndicesType old_indices_type = new_indices_type; GArray *old_vertices = tess->indices; /* Copy the indices to an array of the new type */ tess->indices_type = new_indices_type; _cogl_path_tesselator_allocate_indices_array (tess); switch (old_indices_type) { case COGL_INDICES_TYPE_UNSIGNED_BYTE: for (i = 0; i < old_vertices->len; i++) _cogl_path_tesselator_add_index (tess, g_array_index (old_vertices, uint8_t, i)); break; case COGL_INDICES_TYPE_UNSIGNED_SHORT: for (i = 0; i < old_vertices->len; i++) _cogl_path_tesselator_add_index (tess, g_array_index (old_vertices, uint16_t, i)); break; case COGL_INDICES_TYPE_UNSIGNED_INT: for (i = 0; i < old_vertices->len; i++) _cogl_path_tesselator_add_index (tess, g_array_index (old_vertices, uint32_t, i)); break; } g_array_free (old_vertices, TRUE); } } static void _cogl_path_build_fill_attribute_buffer (CoglPath *path) { CoglPathTesselator tess; unsigned int path_start = 0; CoglPathData *data = path->data; int i; /* If we've already got a vbo then we don't need to do anything */ if (data->fill_attribute_buffer) return; tess.primitive_type = FALSE; /* Generate a vertex for each point on the path */ tess.vertices = g_array_new (FALSE, FALSE, sizeof (CoglPathTesselatorVertex)); g_array_set_size (tess.vertices, data->path_nodes->len); for (i = 0; i < data->path_nodes->len; i++) { CoglPathNode *node = &g_array_index (data->path_nodes, CoglPathNode, i); CoglPathTesselatorVertex *vertex = &g_array_index (tess.vertices, CoglPathTesselatorVertex, i); vertex->x = node->x; vertex->y = node->y; /* Add texture coordinates so that a texture would be drawn to fit the bounding box of the path and then cropped by the path */ if (data->path_nodes_min.x == data->path_nodes_max.x) vertex->s = 0.0f; else vertex->s = ((node->x - data->path_nodes_min.x) / (data->path_nodes_max.x - data->path_nodes_min.x)); if (data->path_nodes_min.y == data->path_nodes_max.y) vertex->t = 0.0f; else vertex->t = ((node->y - data->path_nodes_min.y) / (data->path_nodes_max.y - data->path_nodes_min.y)); } tess.indices_type = _cogl_path_tesselator_get_indices_type_for_size (data->path_nodes->len); _cogl_path_tesselator_allocate_indices_array (&tess); tess.glu_tess = gluNewTess (); if (data->fill_rule == COGL_PATH_FILL_RULE_EVEN_ODD) gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); else gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); /* All vertices are on the xy-plane */ gluTessNormal (tess.glu_tess, 0.0, 0.0, 1.0); gluTessCallback (tess.glu_tess, GLU_TESS_BEGIN_DATA, _cogl_path_tesselator_begin); gluTessCallback (tess.glu_tess, GLU_TESS_VERTEX_DATA, _cogl_path_tesselator_vertex); gluTessCallback (tess.glu_tess, GLU_TESS_END_DATA, _cogl_path_tesselator_end); gluTessCallback (tess.glu_tess, GLU_TESS_COMBINE_DATA, _cogl_path_tesselator_combine); gluTessBeginPolygon (tess.glu_tess, &tess); while (path_start < data->path_nodes->len) { CoglPathNode *node = &g_array_index (data->path_nodes, CoglPathNode, path_start); gluTessBeginContour (tess.glu_tess); for (i = 0; i < node->path_size; i++) { double vertex[3] = { node[i].x, node[i].y, 0.0 }; gluTessVertex (tess.glu_tess, vertex, GINT_TO_POINTER (i + path_start)); } gluTessEndContour (tess.glu_tess); path_start += node->path_size; } gluTessEndPolygon (tess.glu_tess); gluDeleteTess (tess.glu_tess); data->fill_attribute_buffer = cogl_attribute_buffer_new (data->context, sizeof (CoglPathTesselatorVertex) * tess.vertices->len, tess.vertices->data); g_array_free (tess.vertices, TRUE); data->fill_attributes[0] = cogl_attribute_new (data->fill_attribute_buffer, "cogl_position_in", sizeof (CoglPathTesselatorVertex), G_STRUCT_OFFSET (CoglPathTesselatorVertex, x), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); data->fill_attributes[1] = cogl_attribute_new (data->fill_attribute_buffer, "cogl_tex_coord0_in", sizeof (CoglPathTesselatorVertex), G_STRUCT_OFFSET (CoglPathTesselatorVertex, s), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); data->fill_vbo_indices = cogl_indices_new (data->context, tess.indices_type, tess.indices->data, tess.indices->len); data->fill_vbo_n_indices = tess.indices->len; g_array_free (tess.indices, TRUE); } static CoglPrimitive * _cogl_path_get_fill_primitive (CoglPath *path) { if (path->data->fill_primitive) return path->data->fill_primitive; _cogl_path_build_fill_attribute_buffer (path); path->data->fill_primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES, path->data->fill_vbo_n_indices, path->data->fill_attributes, COGL_PATH_N_ATTRIBUTES); cogl_primitive_set_indices (path->data->fill_primitive, path->data->fill_vbo_indices, path->data->fill_vbo_n_indices); return path->data->fill_primitive; } static CoglClipStack * _cogl_clip_stack_push_from_path (CoglClipStack *stack, CoglPath *path, CoglMatrixEntry *modelview_entry, CoglMatrixEntry *projection_entry, const float *viewport) { float x_1, y_1, x_2, y_2; _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2); /* If the path is a simple rectangle then we can divert to pushing a rectangle clip instead which usually won't involve the stencil buffer */ if (_cogl_path_is_rectangle (path)) return _cogl_clip_stack_push_rectangle (stack, x_1, y_1, x_2, y_2, modelview_entry, projection_entry, viewport); else { CoglPrimitive *primitive = _cogl_path_get_fill_primitive (path); return _cogl_clip_stack_push_primitive (stack, primitive, x_1, y_1, x_2, y_2, modelview_entry, projection_entry, viewport); } } void cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer, CoglPath *path) { CoglMatrixEntry *modelview_entry = _cogl_framebuffer_get_modelview_entry (framebuffer); CoglMatrixEntry *projection_entry = _cogl_framebuffer_get_projection_entry (framebuffer); /* XXX: It would be nicer if we stored the private viewport as a * vec4 so we could avoid this redundant copy. */ float viewport[] = { framebuffer->viewport_x, framebuffer->viewport_y, framebuffer->viewport_width, framebuffer->viewport_height }; framebuffer->clip_stack = _cogl_clip_stack_push_from_path (framebuffer->clip_stack, path, modelview_entry, projection_entry, viewport); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } /* XXX: deprecated */ void cogl_clip_push_from_path (CoglPath *path) { cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (), path); } static void _cogl_path_build_stroke_attribute_buffer (CoglPath *path) { CoglPathData *data = path->data; CoglBuffer *buffer; unsigned int n_attributes = 0; unsigned int path_start; CoglPathNode *node; floatVec2 *buffer_p; unsigned int i; /* If we've already got a cached vbo then we don't need to do anything */ if (data->stroke_attribute_buffer) return; data->stroke_attribute_buffer = cogl_attribute_buffer_new_with_size (data->context, data->path_nodes->len * sizeof (floatVec2)); buffer = COGL_BUFFER (data->stroke_attribute_buffer); buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer); /* Copy the vertices in and count the number of sub paths. Each sub path will form a separate attribute so we can paint the disjoint line strips */ for (path_start = 0; path_start < data->path_nodes->len; path_start += node->path_size) { node = &g_array_index (data->path_nodes, CoglPathNode, path_start); for (i = 0; i < node->path_size; i++) { buffer_p[path_start + i].x = node[i].x; buffer_p[path_start + i].y = node[i].y; } n_attributes++; } _cogl_buffer_unmap_for_fill_or_fallback (buffer); data->stroke_attributes = g_new (CoglAttribute *, n_attributes); /* Now we can loop the sub paths again to create the attributes */ for (i = 0, path_start = 0; path_start < data->path_nodes->len; i++, path_start += node->path_size) { node = &g_array_index (data->path_nodes, CoglPathNode, path_start); data->stroke_attributes[i] = cogl_attribute_new (data->stroke_attribute_buffer, "cogl_position_in", sizeof (floatVec2), path_start * sizeof (floatVec2), 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); } data->stroke_n_attributes = n_attributes; } /* XXX: deprecated */ void cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglPath *path) { _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer)); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); _COGL_RETURN_IF_FAIL (cogl_is_path (path)); _cogl_path_fill_nodes (path, framebuffer, pipeline, 0 /* flags */); } /* XXX: deprecated */ void cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglPath *path) { _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer)); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); _COGL_RETURN_IF_FAIL (cogl_is_path (path)); _cogl_path_stroke_nodes (path, framebuffer, pipeline); } muffin-5.2.1/cogl/.gitignore0000664000175000017500000000273214211404421016054 0ustar jpeisachjpeisachABOUT-NLS INSTALL Makefile Makefile.in aclocal.m4 autom4te.cache compile *.pc .deps .libs .dirstamp *.o *.lo *.la *.gcov *.exe /README stamp-enum-types stamp-marshal /build/autotools/*.m4 /build/win32/*.bat !/build/autotools/acglib.m4 !/build/autotools/introspection.m4 !/build/autotools/as-glibconfig.m4 !/build/autotools/as-linguas.m4 !/build/autotools/as-compiler-flag.m4 /build/config.guess /build/config.rpath /build/config.sub *.gir *.typelib cogl-pango.rc cogl.rc cogl-defines.h cogl-egl-defines.h cogl-enum-types.c cogl-enum-types.h cogl-gl-header.h cogl-path-enum-types.c cogl-path-enum-types.h cogl-config.h cogl-config.h.in cogl-muffin-config.h config.log config.lt config.status configure depcomp /deps/glib/glibconfig.h /deps/gmodule/gmoduleconf.h /doc/reference/cogl/cogl-docs.xml /doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml /doc/reference/cogl-gst/cogl-gst-docs.xml gtk-doc.make install-sh libtool ltmain.sh missing mkinstalldirs stamp-h1 TAGS /tests/tools/disable-npots.sh /tests/conform/test-launcher.sh /tests/interactive/wrapper.sh /tests/conform/*.bat /tests/conform/config.env /tests/conform/.log /tests/unit/.log /tests/micro-perf/test-journal /tests/config.env /po/POTFILES /po/*.gmo /po/Makefile.in.in /po/Makevars.template /po/Rules-quot /po/boldquot.sed /po/en@boldquot.header /po/en@quot.header /po/insert-header.sin /po/quot.sed /po/remove-potcdate.sin /po/remove-potcdate.sed /po/stamp-po *.swn *.swo *.swp *~ *.orig *.rej .DS_Store .testlogs-* muffin-5.2.1/cogl/config-custom.h0000664000175000017500000000253114211404421017007 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* The contents of this file get #included by config.h so it is intended for extra configuration that needs to be included by all Cogl source files. */ #include muffin-5.2.1/cogl/cogl-gles2/0000775000175000017500000000000014211404421016016 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl-gles2/Makefile.am0000664000175000017500000000150414211404421020052 0ustar jpeisachjpeisach# preamble NULL = DISTCLEANFILES = muffinlibdir = $(libdir)/muffin muffinlib_LTLIBRARIES = libmuffin-cogl-gles2-@MUFFIN_PLUGIN_API_VERSION@.la AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_builddir) AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS) libmuffin_cogl_gles2_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = cogl-gles2-api.c libmuffin_cogl_gles2_@MUFFIN_PLUGIN_API_VERSION@_la_LDFLAGS = \ -no-undefined \ -rpath $(muffinlibdir) \ -avoid-version \ -export-dynamic \ -export-symbols-regex "^gl*" coglgles2includedir = $(includedir)/muffin/cogl/cogl-gles2/GLES2 coglgles2include_HEADERS = \ GLES2/gl2.h \ GLES2/gl2ext.h \ GLES2/gl2platform.h pc_files = muffin-cogl-gles2-$(MUFFIN_PLUGIN_API_VERSION).pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pc_files) DISTCLEANFILES += $(pc_files) muffin-5.2.1/cogl/cogl-gles2/GLES2/0000775000175000017500000000000014211404421016632 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl-gles2/GLES2/gl2ext.h0000664000175000017500000021157014211404421020216 0ustar jpeisachjpeisach#ifndef __gl2ext_h_ #define __gl2ext_h_ /* $Revision: 16994 $ on $Date:: 2012-02-29 18:29:34 -0800 #$ */ #ifdef __cplusplus extern "C" { #endif /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ #ifndef GL_APIENTRYP # define GL_APIENTRYP GL_APIENTRY* #endif /*------------------------------------------------------------------------* * OES extension tokens *------------------------------------------------------------------------*/ /* GL_OES_compressed_ETC1_RGB8_texture */ #ifndef GL_OES_compressed_ETC1_RGB8_texture #define GL_ETC1_RGB8_OES 0x8D64 #endif /* GL_OES_compressed_paletted_texture */ #ifndef GL_OES_compressed_paletted_texture #define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGBA8_OES 0x8B91 #define GL_PALETTE4_R5_G6_B5_OES 0x8B92 #define GL_PALETTE4_RGBA4_OES 0x8B93 #define GL_PALETTE4_RGB5_A1_OES 0x8B94 #define GL_PALETTE8_RGB8_OES 0x8B95 #define GL_PALETTE8_RGBA8_OES 0x8B96 #define GL_PALETTE8_R5_G6_B5_OES 0x8B97 #define GL_PALETTE8_RGBA4_OES 0x8B98 #define GL_PALETTE8_RGB5_A1_OES 0x8B99 #endif /* GL_OES_depth24 */ #ifndef GL_OES_depth24 #define GL_DEPTH_COMPONENT24_OES 0x81A6 #endif /* GL_OES_depth32 */ #ifndef GL_OES_depth32 #define GL_DEPTH_COMPONENT32_OES 0x81A7 #endif /* GL_OES_depth_texture */ /* No new tokens introduced by this extension. */ /* GL_OES_EGL_image */ #ifndef GL_OES_EGL_image typedef void* GLeglImageOES; #endif /* GL_OES_EGL_image_external */ #ifndef GL_OES_EGL_image_external /* GLeglImageOES defined in GL_OES_EGL_image already. */ #define GL_TEXTURE_EXTERNAL_OES 0x8D65 #define GL_SAMPLER_EXTERNAL_OES 0x8D66 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 #define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 #endif /* GL_OES_element_index_uint */ #ifndef GL_OES_element_index_uint #define GL_UNSIGNED_INT 0x1405 #endif /* GL_OES_get_program_binary */ #ifndef GL_OES_get_program_binary #define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE #define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF #endif /* GL_OES_mapbuffer */ #ifndef GL_OES_mapbuffer #define GL_WRITE_ONLY_OES 0x88B9 #define GL_BUFFER_ACCESS_OES 0x88BB #define GL_BUFFER_MAPPED_OES 0x88BC #define GL_BUFFER_MAP_POINTER_OES 0x88BD #endif /* GL_OES_packed_depth_stencil */ #ifndef GL_OES_packed_depth_stencil #define GL_DEPTH_STENCIL_OES 0x84F9 #define GL_UNSIGNED_INT_24_8_OES 0x84FA #define GL_DEPTH24_STENCIL8_OES 0x88F0 #endif /* GL_OES_rgb8_rgba8 */ #ifndef GL_OES_rgb8_rgba8 #define GL_RGB8_OES 0x8051 #define GL_RGBA8_OES 0x8058 #endif /* GL_OES_standard_derivatives */ #ifndef GL_OES_standard_derivatives #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B #endif /* GL_OES_stencil1 */ #ifndef GL_OES_stencil1 #define GL_STENCIL_INDEX1_OES 0x8D46 #endif /* GL_OES_stencil4 */ #ifndef GL_OES_stencil4 #define GL_STENCIL_INDEX4_OES 0x8D47 #endif /* GL_OES_texture_3D */ #ifndef GL_OES_texture_3D #define GL_TEXTURE_WRAP_R_OES 0x8072 #define GL_TEXTURE_3D_OES 0x806F #define GL_TEXTURE_BINDING_3D_OES 0x806A #define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 #define GL_SAMPLER_3D_OES 0x8B5F #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 #endif /* GL_OES_texture_float */ /* No new tokens introduced by this extension. */ /* GL_OES_texture_float_linear */ /* No new tokens introduced by this extension. */ /* GL_OES_texture_half_float */ #ifndef GL_OES_texture_half_float #define GL_HALF_FLOAT_OES 0x8D61 #endif /* GL_OES_texture_half_float_linear */ /* No new tokens introduced by this extension. */ /* GL_OES_texture_npot */ /* No new tokens introduced by this extension. */ /* GL_OES_vertex_array_object */ #ifndef GL_OES_vertex_array_object #define GL_VERTEX_ARRAY_BINDING_OES 0x85B5 #endif /* GL_OES_vertex_half_float */ /* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */ /* GL_OES_vertex_type_10_10_10_2 */ #ifndef GL_OES_vertex_type_10_10_10_2 #define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 #define GL_INT_10_10_10_2_OES 0x8DF7 #endif /*------------------------------------------------------------------------* * AMD extension tokens *------------------------------------------------------------------------*/ /* GL_AMD_compressed_3DC_texture */ #ifndef GL_AMD_compressed_3DC_texture #define GL_3DC_X_AMD 0x87F9 #define GL_3DC_XY_AMD 0x87FA #endif /* GL_AMD_compressed_ATC_texture */ #ifndef GL_AMD_compressed_ATC_texture #define GL_ATC_RGB_AMD 0x8C92 #define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 #define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE #endif /* GL_AMD_performance_monitor */ #ifndef GL_AMD_performance_monitor #define GL_COUNTER_TYPE_AMD 0x8BC0 #define GL_COUNTER_RANGE_AMD 0x8BC1 #define GL_UNSIGNED_INT64_AMD 0x8BC2 #define GL_PERCENTAGE_AMD 0x8BC3 #define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 #define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 #define GL_PERFMON_RESULT_AMD 0x8BC6 #endif /* GL_AMD_program_binary_Z400 */ #ifndef GL_AMD_program_binary_Z400 #define GL_Z400_BINARY_AMD 0x8740 #endif /*------------------------------------------------------------------------* * ANGLE extension tokens *------------------------------------------------------------------------*/ /* GL_ANGLE_framebuffer_blit */ #ifndef GL_ANGLE_framebuffer_blit #define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8 #define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 #define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA #endif /* GL_ANGLE_framebuffer_multisample */ #ifndef GL_ANGLE_framebuffer_multisample #define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56 #define GL_MAX_SAMPLES_ANGLE 0x8D57 #endif /* GL_ANGLE_instanced_arrays */ #ifndef GL_ANGLE_instanced_arrays #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE #endif /* GL_ANGLE_pack_reverse_row_order */ #ifndef GL_ANGLE_pack_reverse_row_order #define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4 #endif /* GL_ANGLE_texture_compression_dxt3 */ #ifndef GL_ANGLE_texture_compression_dxt3 #define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2 #endif /* GL_ANGLE_texture_compression_dxt5 */ #ifndef GL_ANGLE_texture_compression_dxt5 #define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 #endif /* GL_ANGLE_texture_usage */ #ifndef GL_ANGLE_texture_usage #define GL_TEXTURE_USAGE_ANGLE 0x93A2 #define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 #endif /* GL_ANGLE_translated_shader_source */ #ifndef GL_ANGLE_translated_shader_source #define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 #endif /*------------------------------------------------------------------------* * APPLE extension tokens *------------------------------------------------------------------------*/ /* GL_APPLE_rgb_422 */ #ifndef GL_APPLE_rgb_422 #define GL_RGB_422_APPLE 0x8A1F #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #endif /* GL_APPLE_framebuffer_multisample */ #ifndef GL_APPLE_framebuffer_multisample #define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56 #define GL_MAX_SAMPLES_APPLE 0x8D57 #define GL_READ_FRAMEBUFFER_APPLE 0x8CA8 #define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6 #define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA #endif /* GL_APPLE_texture_format_BGRA8888 */ #ifndef GL_APPLE_texture_format_BGRA8888 #define GL_BGRA_EXT 0x80E1 #endif /* GL_APPLE_texture_max_level */ #ifndef GL_APPLE_texture_max_level #define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D #endif /*------------------------------------------------------------------------* * ARM extension tokens *------------------------------------------------------------------------*/ /* GL_ARM_mali_shader_binary */ #ifndef GL_ARM_mali_shader_binary #define GL_MALI_SHADER_BINARY_ARM 0x8F60 #endif /* GL_ARM_rgba8 */ /* No new tokens introduced by this extension. */ /*------------------------------------------------------------------------* * EXT extension tokens *------------------------------------------------------------------------*/ /* GL_EXT_blend_minmax */ #ifndef GL_EXT_blend_minmax #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #endif /* GL_EXT_color_buffer_half_float */ #ifndef GL_EXT_color_buffer_half_float #define GL_RGBA16F_EXT 0x881A #define GL_RGB16F_EXT 0x881B #define GL_RG16F_EXT 0x822F #define GL_R16F_EXT 0x822D #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211 #define GL_UNSIGNED_NORMALIZED_EXT 0x8C17 #endif /* GL_EXT_debug_label */ #ifndef GL_EXT_debug_label #define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F #define GL_PROGRAM_OBJECT_EXT 0x8B40 #define GL_SHADER_OBJECT_EXT 0x8B48 #define GL_BUFFER_OBJECT_EXT 0x9151 #define GL_QUERY_OBJECT_EXT 0x9153 #define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 #endif /* GL_EXT_debug_marker */ /* No new tokens introduced by this extension. */ /* GL_EXT_discard_framebuffer */ #ifndef GL_EXT_discard_framebuffer #define GL_COLOR_EXT 0x1800 #define GL_DEPTH_EXT 0x1801 #define GL_STENCIL_EXT 0x1802 #endif /* GL_EXT_multisampled_render_to_texture */ #ifndef GL_EXT_multisampled_render_to_texture #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C #define GL_RENDERBUFFER_SAMPLES_EXT 0x9133 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x9134 #define GL_MAX_SAMPLES_EXT 0x9135 #endif /* GL_EXT_multi_draw_arrays */ /* No new tokens introduced by this extension. */ /* GL_EXT_occlusion_query_boolean */ #ifndef GL_EXT_occlusion_query_boolean #define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A #define GL_CURRENT_QUERY_EXT 0x8865 #define GL_QUERY_RESULT_EXT 0x8866 #define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 #endif /* GL_EXT_read_format_bgra */ #ifndef GL_EXT_read_format_bgra #define GL_BGRA_EXT 0x80E1 #define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 #endif /* GL_EXT_robustness */ #ifndef GL_EXT_robustness /* reuse GL_NO_ERROR */ #define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 #define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 #define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 #define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 #define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 #define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 #define GL_NO_RESET_NOTIFICATION_EXT 0x8261 #endif /* GL_EXT_separate_shader_objects */ #ifndef GL_EXT_separate_shader_objects #define GL_VERTEX_SHADER_BIT_EXT 0x00000001 #define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002 #define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF #define GL_PROGRAM_SEPARABLE_EXT 0x8258 #define GL_ACTIVE_PROGRAM_EXT 0x8259 #define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A #endif /* GL_EXT_shader_texture_lod */ /* No new tokens introduced by this extension. */ /* GL_EXT_shadow_samplers */ #ifndef GL_EXT_shadow_samplers #define GL_TEXTURE_COMPARE_MODE_EXT 0x884C #define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D #define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E #define GL_SAMPLER_2D_SHADOW_EXT 0x8B62 #endif /* GL_EXT_sRGB */ #ifndef GL_EXT_sRGB #define GL_SRGB_EXT 0x8C40 #define GL_SRGB_ALPHA_EXT 0x8C42 #define GL_SRGB8_ALPHA8_EXT 0x8C43 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 #endif /* GL_EXT_texture_compression_dxt1 */ #ifndef GL_EXT_texture_compression_dxt1 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #endif /* GL_EXT_texture_filter_anisotropic */ #ifndef GL_EXT_texture_filter_anisotropic #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif /* GL_EXT_texture_format_BGRA8888 */ #ifndef GL_EXT_texture_format_BGRA8888 #define GL_BGRA_EXT 0x80E1 #endif /* GL_EXT_texture_rg */ #ifndef GL_EXT_texture_rg #define GL_RED_EXT 0x1903 #define GL_RG_EXT 0x8227 #define GL_R8_EXT 0x8229 #define GL_RG8_EXT 0x822B #endif /* GL_EXT_texture_storage */ #ifndef GL_EXT_texture_storage #define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F #define GL_ALPHA8_EXT 0x803C #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_RGBA32F_EXT 0x8814 #define GL_RGB32F_EXT 0x8815 #define GL_ALPHA32F_EXT 0x8816 #define GL_LUMINANCE32F_EXT 0x8818 #define GL_LUMINANCE_ALPHA32F_EXT 0x8819 /* reuse GL_RGBA16F_EXT */ /* reuse GL_RGB16F_EXT */ #define GL_ALPHA16F_EXT 0x881C #define GL_LUMINANCE16F_EXT 0x881E #define GL_LUMINANCE_ALPHA16F_EXT 0x881F #define GL_RGB10_A2_EXT 0x8059 #define GL_RGB10_EXT 0x8052 #define GL_BGRA8_EXT 0x93A1 #define GL_R8_EXT 0x8229 #define GL_RG8_EXT 0x822B #define GL_R32F_EXT 0x822E #define GL_RG32F_EXT 0x8230 #define GL_R16F_EXT 0x822D #define GL_RG16F_EXT 0x822F #endif /* GL_EXT_texture_type_2_10_10_10_REV */ #ifndef GL_EXT_texture_type_2_10_10_10_REV #define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 #endif /* GL_EXT_unpack_subimage */ #ifndef GL_EXT_unpack_subimage #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #endif /*------------------------------------------------------------------------* * DMP extension tokens *------------------------------------------------------------------------*/ /* GL_DMP_shader_binary */ #ifndef GL_DMP_shader_binary #define GL_SHADER_BINARY_DMP 0x9250 #endif /*------------------------------------------------------------------------* * IMG extension tokens *------------------------------------------------------------------------*/ /* GL_IMG_program_binary */ #ifndef GL_IMG_program_binary #define GL_SGX_PROGRAM_BINARY_IMG 0x9130 #endif /* GL_IMG_read_format */ #ifndef GL_IMG_read_format #define GL_BGRA_IMG 0x80E1 #define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365 #endif /* GL_IMG_shader_binary */ #ifndef GL_IMG_shader_binary #define GL_SGX_BINARY_IMG 0x8C0A #endif /* GL_IMG_texture_compression_pvrtc */ #ifndef GL_IMG_texture_compression_pvrtc #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 #endif /* GL_IMG_multisampled_render_to_texture */ #ifndef GL_IMG_multisampled_render_to_texture #define GL_RENDERBUFFER_SAMPLES_IMG 0x9133 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134 #define GL_MAX_SAMPLES_IMG 0x9135 #define GL_TEXTURE_SAMPLES_IMG 0x9136 #endif /*------------------------------------------------------------------------* * NV extension tokens *------------------------------------------------------------------------*/ /* GL_NV_coverage_sample */ #ifndef GL_NV_coverage_sample #define GL_COVERAGE_COMPONENT_NV 0x8ED0 #define GL_COVERAGE_COMPONENT4_NV 0x8ED1 #define GL_COVERAGE_ATTACHMENT_NV 0x8ED2 #define GL_COVERAGE_BUFFERS_NV 0x8ED3 #define GL_COVERAGE_SAMPLES_NV 0x8ED4 #define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5 #define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6 #define GL_COVERAGE_AUTOMATIC_NV 0x8ED7 #define GL_COVERAGE_BUFFER_BIT_NV 0x8000 #endif /* GL_NV_depth_nonlinear */ #ifndef GL_NV_depth_nonlinear #define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C #endif /* GL_NV_draw_buffers */ #ifndef GL_NV_draw_buffers #define GL_MAX_DRAW_BUFFERS_NV 0x8824 #define GL_DRAW_BUFFER0_NV 0x8825 #define GL_DRAW_BUFFER1_NV 0x8826 #define GL_DRAW_BUFFER2_NV 0x8827 #define GL_DRAW_BUFFER3_NV 0x8828 #define GL_DRAW_BUFFER4_NV 0x8829 #define GL_DRAW_BUFFER5_NV 0x882A #define GL_DRAW_BUFFER6_NV 0x882B #define GL_DRAW_BUFFER7_NV 0x882C #define GL_DRAW_BUFFER8_NV 0x882D #define GL_DRAW_BUFFER9_NV 0x882E #define GL_DRAW_BUFFER10_NV 0x882F #define GL_DRAW_BUFFER11_NV 0x8830 #define GL_DRAW_BUFFER12_NV 0x8831 #define GL_DRAW_BUFFER13_NV 0x8832 #define GL_DRAW_BUFFER14_NV 0x8833 #define GL_DRAW_BUFFER15_NV 0x8834 #define GL_COLOR_ATTACHMENT0_NV 0x8CE0 #define GL_COLOR_ATTACHMENT1_NV 0x8CE1 #define GL_COLOR_ATTACHMENT2_NV 0x8CE2 #define GL_COLOR_ATTACHMENT3_NV 0x8CE3 #define GL_COLOR_ATTACHMENT4_NV 0x8CE4 #define GL_COLOR_ATTACHMENT5_NV 0x8CE5 #define GL_COLOR_ATTACHMENT6_NV 0x8CE6 #define GL_COLOR_ATTACHMENT7_NV 0x8CE7 #define GL_COLOR_ATTACHMENT8_NV 0x8CE8 #define GL_COLOR_ATTACHMENT9_NV 0x8CE9 #define GL_COLOR_ATTACHMENT10_NV 0x8CEA #define GL_COLOR_ATTACHMENT11_NV 0x8CEB #define GL_COLOR_ATTACHMENT12_NV 0x8CEC #define GL_COLOR_ATTACHMENT13_NV 0x8CED #define GL_COLOR_ATTACHMENT14_NV 0x8CEE #define GL_COLOR_ATTACHMENT15_NV 0x8CEF #endif /* GL_NV_fbo_color_attachments */ #ifndef GL_NV_fbo_color_attachments #define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF /* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */ #endif /* GL_NV_fence */ #ifndef GL_NV_fence #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 #endif /* GL_NV_read_buffer */ #ifndef GL_NV_read_buffer #define GL_READ_BUFFER_NV 0x0C02 #endif /* GL_NV_read_buffer_front */ /* No new tokens introduced by this extension. */ /* GL_NV_read_depth */ /* No new tokens introduced by this extension. */ /* GL_NV_read_depth_stencil */ /* No new tokens introduced by this extension. */ /* GL_NV_read_stencil */ /* No new tokens introduced by this extension. */ /* GL_NV_texture_compression_s3tc_update */ /* No new tokens introduced by this extension. */ /* GL_NV_texture_npot_2D_mipmap */ /* No new tokens introduced by this extension. */ /*------------------------------------------------------------------------* * QCOM extension tokens *------------------------------------------------------------------------*/ /* GL_QCOM_alpha_test */ #ifndef GL_QCOM_alpha_test #define GL_ALPHA_TEST_QCOM 0x0BC0 #define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1 #define GL_ALPHA_TEST_REF_QCOM 0x0BC2 #endif /* GL_QCOM_driver_control */ /* No new tokens introduced by this extension. */ /* GL_QCOM_extended_get */ #ifndef GL_QCOM_extended_get #define GL_TEXTURE_WIDTH_QCOM 0x8BD2 #define GL_TEXTURE_HEIGHT_QCOM 0x8BD3 #define GL_TEXTURE_DEPTH_QCOM 0x8BD4 #define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5 #define GL_TEXTURE_FORMAT_QCOM 0x8BD6 #define GL_TEXTURE_TYPE_QCOM 0x8BD7 #define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8 #define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9 #define GL_TEXTURE_TARGET_QCOM 0x8BDA #define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB #define GL_STATE_RESTORE 0x8BDC #endif /* GL_QCOM_extended_get2 */ /* No new tokens introduced by this extension. */ /* GL_QCOM_perfmon_global_mode */ #ifndef GL_QCOM_perfmon_global_mode #define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0 #endif /* GL_QCOM_writeonly_rendering */ #ifndef GL_QCOM_writeonly_rendering #define GL_WRITEONLY_RENDERING_QCOM 0x8823 #endif /* GL_QCOM_tiled_rendering */ #ifndef GL_QCOM_tiled_rendering #define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001 #define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002 #define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004 #define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008 #define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010 #define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020 #define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040 #define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080 #define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100 #define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200 #define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400 #define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800 #define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000 #define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000 #define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000 #define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000 #define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000 #define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000 #define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000 #define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000 #define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000 #define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000 #define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000 #define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000 #define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000 #define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000 #define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000 #define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000 #define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000 #define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000 #define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000 #define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000 #endif /*------------------------------------------------------------------------* * VIV extension tokens *------------------------------------------------------------------------*/ /* GL_VIV_shader_binary */ #ifndef GL_VIV_shader_binary #define GL_SHADER_BINARY_VIV 0x8FC4 #endif /*------------------------------------------------------------------------* * End of extension tokens, start of corresponding extension functions *------------------------------------------------------------------------*/ /*------------------------------------------------------------------------* * OES extension functions *------------------------------------------------------------------------*/ /* GL_OES_compressed_ETC1_RGB8_texture */ #ifndef GL_OES_compressed_ETC1_RGB8_texture #define GL_OES_compressed_ETC1_RGB8_texture 1 #endif /* GL_OES_compressed_paletted_texture */ #ifndef GL_OES_compressed_paletted_texture #define GL_OES_compressed_paletted_texture 1 #endif /* GL_OES_depth24 */ #ifndef GL_OES_depth24 #define GL_OES_depth24 1 #endif /* GL_OES_depth32 */ #ifndef GL_OES_depth32 #define GL_OES_depth32 1 #endif /* GL_OES_depth_texture */ #ifndef GL_OES_depth_texture #define GL_OES_depth_texture 1 #endif /* GL_OES_EGL_image */ #ifndef GL_OES_EGL_image #define GL_OES_EGL_image 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image); #endif typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); #endif /* GL_OES_EGL_image_external */ #ifndef GL_OES_EGL_image_external #define GL_OES_EGL_image_external 1 /* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */ #endif /* GL_OES_element_index_uint */ #ifndef GL_OES_element_index_uint #define GL_OES_element_index_uint 1 #endif /* GL_OES_fbo_render_mipmap */ #ifndef GL_OES_fbo_render_mipmap #define GL_OES_fbo_render_mipmap 1 #endif /* GL_OES_fragment_precision_high */ #ifndef GL_OES_fragment_precision_high #define GL_OES_fragment_precision_high 1 #endif /* GL_OES_get_program_binary */ #ifndef GL_OES_get_program_binary #define GL_OES_get_program_binary 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length); #endif typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length); #endif /* GL_OES_mapbuffer */ #ifndef GL_OES_mapbuffer #define GL_OES_mapbuffer 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access); GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target); GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params); #endif typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access); typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params); #endif /* GL_OES_packed_depth_stencil */ #ifndef GL_OES_packed_depth_stencil #define GL_OES_packed_depth_stencil 1 #endif /* GL_OES_rgb8_rgba8 */ #ifndef GL_OES_rgb8_rgba8 #define GL_OES_rgb8_rgba8 1 #endif /* GL_OES_standard_derivatives */ #ifndef GL_OES_standard_derivatives #define GL_OES_standard_derivatives 1 #endif /* GL_OES_stencil1 */ #ifndef GL_OES_stencil1 #define GL_OES_stencil1 1 #endif /* GL_OES_stencil4 */ #ifndef GL_OES_stencil4 #define GL_OES_stencil4 1 #endif /* GL_OES_texture_3D */ #ifndef GL_OES_texture_3D #define GL_OES_texture_3D 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels); GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); #endif typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels); typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); #endif /* GL_OES_texture_float */ #ifndef GL_OES_texture_float #define GL_OES_texture_float 1 #endif /* GL_OES_texture_float_linear */ #ifndef GL_OES_texture_float_linear #define GL_OES_texture_float_linear 1 #endif /* GL_OES_texture_half_float */ #ifndef GL_OES_texture_half_float #define GL_OES_texture_half_float 1 #endif /* GL_OES_texture_half_float_linear */ #ifndef GL_OES_texture_half_float_linear #define GL_OES_texture_half_float_linear 1 #endif /* GL_OES_texture_npot */ #ifndef GL_OES_texture_npot #define GL_OES_texture_npot 1 #endif /* GL_OES_vertex_array_object */ #ifndef GL_OES_vertex_array_object #define GL_OES_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array); GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays); GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays); GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array); #endif typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array); typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays); typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array); #endif /* GL_OES_vertex_half_float */ #ifndef GL_OES_vertex_half_float #define GL_OES_vertex_half_float 1 #endif /* GL_OES_vertex_type_10_10_10_2 */ #ifndef GL_OES_vertex_type_10_10_10_2 #define GL_OES_vertex_type_10_10_10_2 1 #endif /*------------------------------------------------------------------------* * AMD extension functions *------------------------------------------------------------------------*/ /* GL_AMD_compressed_3DC_texture */ #ifndef GL_AMD_compressed_3DC_texture #define GL_AMD_compressed_3DC_texture 1 #endif /* GL_AMD_compressed_ATC_texture */ #ifndef GL_AMD_compressed_ATC_texture #define GL_AMD_compressed_ATC_texture 1 #endif /* AMD_performance_monitor */ #ifndef GL_AMD_performance_monitor #define GL_AMD_performance_monitor 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data); GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor); GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor); GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #endif typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #endif /* GL_AMD_program_binary_Z400 */ #ifndef GL_AMD_program_binary_Z400 #define GL_AMD_program_binary_Z400 1 #endif /*------------------------------------------------------------------------* * ANGLE extension functions *------------------------------------------------------------------------*/ /* GL_ANGLE_framebuffer_blit */ #ifndef GL_ANGLE_framebuffer_blit #define GL_ANGLE_framebuffer_blit 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif /* GL_ANGLE_framebuffer_multisample */ #ifndef GL_ANGLE_framebuffer_multisample #define GL_ANGLE_framebuffer_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif #ifndef GL_ANGLE_instanced_arrays #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount); GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor); #endif typedef void (GL_APIENTRYP PFLGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (GL_APIENTRYP PFLGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); typedef void (GL_APIENTRYP PFLGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor); #endif /* GL_ANGLE_pack_reverse_row_order */ #ifndef GL_ANGLE_pack_reverse_row_order #define GL_ANGLE_pack_reverse_row_order 1 #endif /* GL_ANGLE_texture_compression_dxt3 */ #ifndef GL_ANGLE_texture_compression_dxt3 #define GL_ANGLE_texture_compression_dxt3 1 #endif /* GL_ANGLE_texture_compression_dxt5 */ #ifndef GL_ANGLE_texture_compression_dxt5 #define GL_ANGLE_texture_compression_dxt5 1 #endif /* GL_ANGLE_texture_usage */ #ifndef GL_ANGLE_texture_usage #define GL_ANGLE_texture_usage 1 #endif #ifndef GL_ANGLE_translated_shader_source #define GL_ANGLE_translated_shader_source 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); #endif typedef void (GL_APIENTRYP PFLGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); #endif /*------------------------------------------------------------------------* * APPLE extension functions *------------------------------------------------------------------------*/ /* GL_APPLE_rgb_422 */ #ifndef GL_APPLE_rgb_422 #define GL_APPLE_rgb_422 1 #endif /* GL_APPLE_framebuffer_multisample */ #ifndef GL_APPLE_framebuffer_multisample #define GL_APPLE_framebuffer_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei); GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void); #endif /* GL_APPLE_texture_format_BGRA8888 */ #ifndef GL_APPLE_texture_format_BGRA8888 #define GL_APPLE_texture_format_BGRA8888 1 #endif /* GL_APPLE_texture_max_level */ #ifndef GL_APPLE_texture_max_level #define GL_APPLE_texture_max_level 1 #endif /*------------------------------------------------------------------------* * ARM extension functions *------------------------------------------------------------------------*/ /* GL_ARM_mali_shader_binary */ #ifndef GL_ARM_mali_shader_binary #define GL_ARM_mali_shader_binary 1 #endif /* GL_ARM_rgba8 */ #ifndef GL_ARM_rgba8 #define GL_ARM_rgba8 1 #endif /*------------------------------------------------------------------------* * EXT extension functions *------------------------------------------------------------------------*/ /* GL_EXT_blend_minmax */ #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax 1 #endif /* GL_EXT_color_buffer_half_float */ #ifndef GL_EXT_color_buffer_half_float #define GL_EXT_color_buffer_half_float 1 #endif /* GL_EXT_debug_label */ #ifndef GL_EXT_debug_label #define GL_EXT_debug_label 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); #endif typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); #endif /* GL_EXT_debug_marker */ #ifndef GL_EXT_debug_marker #define GL_EXT_debug_marker 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void); #endif typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); #endif /* GL_EXT_discard_framebuffer */ #ifndef GL_EXT_discard_framebuffer #define GL_EXT_discard_framebuffer 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments); #endif typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); #endif /* GL_EXT_multisampled_render_to_texture */ #ifndef GL_EXT_multisampled_render_to_texture #define GL_EXT_multisampled_render_to_texture 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei); GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); #endif typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #endif #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei); GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); #endif /* GL_EXT_occlusion_query_boolean */ #ifndef GL_EXT_occlusion_query_boolean #define GL_EXT_occlusion_query_boolean 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids); GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids); GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id); GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id); GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target); GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params); #endif typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids); typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id); typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id); typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target); typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params); #endif /* GL_EXT_read_format_bgra */ #ifndef GL_EXT_read_format_bgra #define GL_EXT_read_format_bgra 1 #endif /* GL_EXT_robustness */ #ifndef GL_EXT_robustness #define GL_EXT_robustness 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void); GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params); GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params); #endif typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void); typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params); typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); #endif /* GL_EXT_separate_shader_objects */ #ifndef GL_EXT_separate_shader_objects #define GL_EXT_separate_shader_objects 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program); GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program); GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings); GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline); GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines); GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines); GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline); GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x); GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y); GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z); GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w); GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x); GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y); GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z); GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline); GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); #endif typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program); typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program); typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings); typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines); typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines); typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline); typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); #endif /* GL_EXT_shader_texture_lod */ #ifndef GL_EXT_shader_texture_lod #define GL_EXT_shader_texture_lod 1 #endif /* GL_EXT_shadow_samplers */ #ifndef GL_EXT_shadow_samplers #define GL_EXT_shadow_samplers 1 #endif /* GL_EXT_sRGB */ #ifndef GL_EXT_sRGB #define GL_EXT_sRGB 1 #endif /* GL_EXT_texture_compression_dxt1 */ #ifndef GL_EXT_texture_compression_dxt1 #define GL_EXT_texture_compression_dxt1 1 #endif /* GL_EXT_texture_filter_anisotropic */ #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic 1 #endif /* GL_EXT_texture_format_BGRA8888 */ #ifndef GL_EXT_texture_format_BGRA8888 #define GL_EXT_texture_format_BGRA8888 1 #endif /* GL_EXT_texture_rg */ #ifndef GL_EXT_texture_rg #define GL_EXT_texture_rg 1 #endif /* GL_EXT_texture_storage */ #ifndef GL_EXT_texture_storage #define GL_EXT_texture_storage 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #endif typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #endif /* GL_EXT_texture_type_2_10_10_10_REV */ #ifndef GL_EXT_texture_type_2_10_10_10_REV #define GL_EXT_texture_type_2_10_10_10_REV 1 #endif /* GL_EXT_unpack_subimage */ #ifndef GL_EXT_unpack_subimage #define GL_EXT_unpack_subimage 1 #endif /*------------------------------------------------------------------------* * DMP extension functions *------------------------------------------------------------------------*/ /* GL_DMP_shader_binary */ #ifndef GL_DMP_shader_binary #define GL_DMP_shader_binary 1 #endif /*------------------------------------------------------------------------* * IMG extension functions *------------------------------------------------------------------------*/ /* GL_IMG_program_binary */ #ifndef GL_IMG_program_binary #define GL_IMG_program_binary 1 #endif /* GL_IMG_read_format */ #ifndef GL_IMG_read_format #define GL_IMG_read_format 1 #endif /* GL_IMG_shader_binary */ #ifndef GL_IMG_shader_binary #define GL_IMG_shader_binary 1 #endif /* GL_IMG_texture_compression_pvrtc */ #ifndef GL_IMG_texture_compression_pvrtc #define GL_IMG_texture_compression_pvrtc 1 #endif /* GL_IMG_multisampled_render_to_texture */ #ifndef GL_IMG_multisampled_render_to_texture #define GL_IMG_multisampled_render_to_texture 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei); GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); #endif typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); #endif /*------------------------------------------------------------------------* * NV extension functions *------------------------------------------------------------------------*/ /* GL_NV_coverage_sample */ #ifndef GL_NV_coverage_sample #define GL_NV_coverage_sample 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask); GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation); #endif typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask); typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation); #endif /* GL_NV_depth_nonlinear */ #ifndef GL_NV_depth_nonlinear #define GL_NV_depth_nonlinear 1 #endif /* GL_NV_draw_buffers */ #ifndef GL_NV_draw_buffers #define GL_NV_draw_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs); #endif typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs); #endif /* GL_NV_fbo_color_attachments */ #ifndef GL_NV_fbo_color_attachments #define GL_NV_fbo_color_attachments 1 #endif /* GL_NV_fence */ #ifndef GL_NV_fence #define GL_NV_fence 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *); GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *); GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint); GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint); GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *); GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint); GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum); #endif typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); #endif /* GL_NV_read_buffer */ #ifndef GL_NV_read_buffer #define GL_NV_read_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode); #endif typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode); #endif /* GL_NV_read_buffer_front */ #ifndef GL_NV_read_buffer_front #define GL_NV_read_buffer_front 1 #endif /* GL_NV_read_depth */ #ifndef GL_NV_read_depth #define GL_NV_read_depth 1 #endif /* GL_NV_read_depth_stencil */ #ifndef GL_NV_read_depth_stencil #define GL_NV_read_depth_stencil 1 #endif /* GL_NV_read_stencil */ #ifndef GL_NV_read_stencil #define GL_NV_read_stencil 1 #endif /* GL_NV_texture_compression_s3tc_update */ #ifndef GL_NV_texture_compression_s3tc_update #define GL_NV_texture_compression_s3tc_update 1 #endif /* GL_NV_texture_npot_2D_mipmap */ #ifndef GL_NV_texture_npot_2D_mipmap #define GL_NV_texture_npot_2D_mipmap 1 #endif /*------------------------------------------------------------------------* * QCOM extension functions *------------------------------------------------------------------------*/ /* GL_QCOM_alpha_test */ #ifndef GL_QCOM_alpha_test #define GL_QCOM_alpha_test 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref); #endif typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref); #endif /* GL_QCOM_driver_control */ #ifndef GL_QCOM_driver_control #define GL_QCOM_driver_control 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls); GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl); GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl); #endif typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls); typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); #endif /* GL_QCOM_extended_get */ #ifndef GL_QCOM_extended_get #define GL_QCOM_extended_get 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures); GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params); #endif typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures); typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param); typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params); #endif /* GL_QCOM_extended_get2 */ #ifndef GL_QCOM_extended_get2 #define GL_QCOM_extended_get2 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders); GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms); GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program); GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length); #endif typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders); typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms); typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length); #endif /* GL_QCOM_perfmon_global_mode */ #ifndef GL_QCOM_perfmon_global_mode #define GL_QCOM_perfmon_global_mode 1 #endif /* GL_QCOM_writeonly_rendering */ #ifndef GL_QCOM_writeonly_rendering #define GL_QCOM_writeonly_rendering 1 #endif /* GL_QCOM_tiled_rendering */ #ifndef GL_QCOM_tiled_rendering #define GL_QCOM_tiled_rendering 1 #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask); #endif typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask); #endif /*------------------------------------------------------------------------* * VIV extension tokens *------------------------------------------------------------------------*/ /* GL_VIV_shader_binary */ #ifndef GL_VIV_shader_binary #define GL_VIV_shader_binary 1 #endif #ifdef __cplusplus } #endif #endif /* __gl2ext_h_ */ muffin-5.2.1/cogl/cogl-gles2/GLES2/gl2.h0000664000175000017500000003407714211404421017502 0ustar jpeisachjpeisach#ifndef __gl2_h_ #define __gl2_h_ /* $Revision: 16803 $ on $Date:: 2012-02-02 09:49:18 -0800 #$ */ #include #include #ifdef __cplusplus extern "C" { #endif /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ /*------------------------------------------------------------------------- * GL core functions. *-----------------------------------------------------------------------*/ GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name); GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode ); GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth); GL_APICALL void GL_APIENTRY glClearStencil (GLint s); GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers); GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers); GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers); GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures); GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar); GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glDisable (GLenum cap); GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); GL_APICALL void GL_APIENTRY glEnable (GLenum cap); GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); GL_APICALL void GL_APIENTRY glFinish (void); GL_APICALL void GL_APIENTRY glFlush (void); GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers); GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers); GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers); GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures); GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name); GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params); GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params); GL_APICALL GLenum GL_APIENTRY glGetError (void); GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params); GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params); GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params); GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params); GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog); GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params); GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params); GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog); GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name); GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params); GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params); GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params); GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params); GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name); GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params); GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params); GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer); GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length); GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params); GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params); GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x); GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v); GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x); GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v); GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y); GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v); GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y); GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v); GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z); GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v); GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z); GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v); GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v); GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w); GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v); GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x); GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values); GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y); GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values); GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z); GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values); GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values); GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr); GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); #ifdef __cplusplus } #endif #endif /* __gl2_h_ */ muffin-5.2.1/cogl/cogl-gles2/GLES2/gl2platform.h0000664000175000017500000000151514211404421021236 0ustar jpeisachjpeisach#ifndef __gl2platform_h_ #define __gl2platform_h_ /* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */ /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ /* Platform-specific types and definitions for OpenGL ES 2.X gl2.h * * Adopters may modify khrplatform.h and this file to suit their platform. * You are encouraged to submit all modifications to the Khronos group so that * they can be included in future versions of this file. Please submit changes * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) * by filing a bug against product "OpenGL-ES" component "Registry". */ #ifndef GL_APICALL #define GL_APICALL #endif #ifndef GL_APIENTRY #define GL_APIENTRY #endif #endif /* __gl2platform_h_ */ muffin-5.2.1/cogl/cogl-gles2/cogl-gles2-api.c0000664000175000017500000006351614211404421020702 0ustar jpeisachjpeisach #include #include void glBindTexture (GLenum target, GLuint texture) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBindTexture (target, texture); } void glBlendFunc (GLenum sfactor, GLenum dfactor) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBlendFunc (sfactor, dfactor); } void glClear (GLbitfield mask) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glClear (mask); } void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glClearColor (red, green, blue, alpha); } void glClearStencil (GLint s) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glClearStencil (s); } void glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glColorMask (red, green, blue, alpha); } void glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glCopyTexSubImage2D (target, level, xoffset, yoffset, x, y, width, height); } void glDeleteTextures (GLsizei n, const GLuint * textures) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDeleteTextures (n, textures); } void glDepthFunc (GLenum func) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDepthFunc (func); } void glDepthMask (GLboolean flag) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDepthMask (flag); } void glDisable (GLenum cap) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDisable (cap); } void glDrawArrays (GLenum mode, GLint first, GLsizei count) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDrawArrays (mode, first, count); } void glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid * indices) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDrawElements (mode, count, type, indices); } void glEnable (GLenum cap) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glEnable (cap); } void glFinish (void) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glFinish (); } void glFlush (void) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glFlush (); } void glFrontFace (GLenum mode) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glFrontFace (mode); } void glCullFace (GLenum mode) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glCullFace (mode); } void glGenTextures (GLsizei n, GLuint * textures) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGenTextures (n, textures); } GLenum glGetError (void) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glGetError (); } void glGetIntegerv (GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetIntegerv (pname, params); } void glGetBooleanv (GLenum pname, GLboolean * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetBooleanv (pname, params); } void glGetFloatv (GLenum pname, GLfloat * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetFloatv (pname, params); } const GLubyte * glGetString (GLenum name) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glGetString (name); } void glHint (GLenum target, GLenum mode) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glHint (target, mode); } GLboolean glIsTexture (GLuint texture) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glIsTexture (texture); } void glPixelStorei (GLenum pname, GLint param) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glPixelStorei (pname, param); } void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid * pixels) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glReadPixels (x, y, width, height, format, type, pixels); } void glScissor (GLint x, GLint y, GLsizei width, GLsizei height) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glScissor (x, y, width, height); } void glStencilFunc (GLenum func, GLint ref, GLuint mask) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glStencilFunc (func, ref, mask); } void glStencilMask (GLuint mask) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glStencilMask (mask); } void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glStencilOp (fail, zfail, zpass); } void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * pixels) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glTexImage2D (target, level, internalformat, width, height, border, format, type, pixels); } void glTexParameterf (GLenum target, GLenum pname, GLfloat param) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glTexParameterf (target, pname, param); } void glTexParameterfv (GLenum target, GLenum pname, const GLfloat * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glTexParameterfv (target, pname, params); } void glTexParameteri (GLenum target, GLenum pname, GLint param) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glTexParameteri (target, pname, param); } void glTexParameteriv (GLenum target, GLenum pname, const GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glTexParameteriv (target, pname, params); } void glGetTexParameterfv (GLenum target, GLenum pname, GLfloat * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetTexParameterfv (target, pname, params); } void glGetTexParameteriv (GLenum target, GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetTexParameteriv (target, pname, params); } void glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * pixels) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glTexSubImage2D (target, level, xoffset, yoffset, width, height, format, type, pixels); } void glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glCopyTexImage2D (target, level, internalformat, x, y, width, height, border); } void glViewport (GLint x, GLint y, GLsizei width, GLsizei height) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glViewport (x, y, width, height); } GLboolean glIsEnabled (GLenum cap) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glIsEnabled (cap); } void glLineWidth (GLfloat width) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glLineWidth (width); } void glPolygonOffset (GLfloat factor, GLfloat units) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glPolygonOffset (factor, units); } void glDepthRangef (GLfloat near_val, GLfloat far_val) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDepthRangef (near_val, far_val); } void glClearDepthf (GLclampf depth) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glClearDepthf (depth); } void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glCompressedTexImage2D (target, level, internalformat, width, height, border, imageSize, data); } void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid * data) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glCompressedTexSubImage2D (target, level, xoffset, yoffset, width, height, format, imageSize, data); } void glSampleCoverage (GLclampf value, GLboolean invert) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glSampleCoverage (value, invert); } void glGetBufferParameteriv (GLenum target, GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetBufferParameteriv (target, pname, params); } void glGenBuffers (GLsizei n, GLuint * buffers) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGenBuffers (n, buffers); } void glBindBuffer (GLenum target, GLuint buffer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBindBuffer (target, buffer); } void glBufferData (GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBufferData (target, size, data, usage); } void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBufferSubData (target, offset, size, data); } void glDeleteBuffers (GLsizei n, const GLuint * buffers) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDeleteBuffers (n, buffers); } GLboolean glIsBuffer (GLuint buffer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glIsBuffer (buffer); } void glActiveTexture (GLenum texture) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glActiveTexture (texture); } void glGenRenderbuffers (GLsizei n, GLuint * renderbuffers) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGenRenderbuffers (n, renderbuffers); } void glDeleteRenderbuffers (GLsizei n, const GLuint * renderbuffers) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDeleteRenderbuffers (n, renderbuffers); } void glBindRenderbuffer (GLenum target, GLuint renderbuffer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBindRenderbuffer (target, renderbuffer); } void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glRenderbufferStorage (target, internalformat, width, height); } void glGenFramebuffers (GLsizei n, GLuint * framebuffers) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGenFramebuffers (n, framebuffers); } void glBindFramebuffer (GLenum target, GLuint framebuffer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBindFramebuffer (target, framebuffer); } void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glFramebufferTexture2D (target, attachment, textarget, texture, level); } void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glFramebufferRenderbuffer (target, attachment, renderbuffertarget, renderbuffer); } GLboolean glIsRenderbuffer (GLuint renderbuffer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glIsRenderbuffer (renderbuffer); } GLenum glCheckFramebufferStatus (GLenum target) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glCheckFramebufferStatus (target); } void glDeleteFramebuffers (GLsizei n, const GLuint * framebuffers) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDeleteFramebuffers (n, framebuffers); } void glGenerateMipmap (GLenum target) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGenerateMipmap (target); } void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetFramebufferAttachmentParameteriv (target, attachment, pname, params); } void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetRenderbufferParameteriv (target, pname, params); } GLboolean glIsFramebuffer (GLuint framebuffer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glIsFramebuffer (framebuffer); } void glBlendEquation (GLenum mode) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBlendEquation (mode); } void glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBlendColor (red, green, blue, alpha); } void glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBlendFuncSeparate (srcRGB, dstRGB, srcAlpha, dstAlpha); } void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBlendEquationSeparate (modeRGB, modeAlpha); } void glReleaseShaderCompiler (void) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glReleaseShaderCompiler (); } void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetShaderPrecisionFormat (shadertype, precisiontype, range, precision); } void glShaderBinary (GLsizei n, const GLuint * shaders, GLenum binaryformat, const GLvoid * binary, GLsizei length) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glShaderBinary (n, shaders, binaryformat, binary, length); } void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glStencilFuncSeparate (face, func, ref, mask); } void glStencilMaskSeparate (GLenum face, GLuint mask) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glStencilMaskSeparate (face, mask); } void glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glStencilOpSeparate (face, fail, zfail, zpass); } GLuint glCreateProgram (void) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glCreateProgram (); } GLuint glCreateShader (GLenum shaderType) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glCreateShader (shaderType); } void glShaderSource (GLuint shader, GLsizei count, const GLchar * const *string, const GLint * length) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glShaderSource (shader, count, string, length); } void glCompileShader (GLuint shader) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glCompileShader (shader); } void glDeleteShader (GLuint shader) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDeleteShader (shader); } void glAttachShader (GLuint program, GLuint shader) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glAttachShader (program, shader); } void glLinkProgram (GLuint program) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glLinkProgram (program); } void glUseProgram (GLuint program) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUseProgram (program); } GLint glGetUniformLocation (GLuint program, const char *name) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glGetUniformLocation (program, name); } void glDeleteProgram (GLuint program) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDeleteProgram (program); } void glGetShaderInfoLog (GLuint shader, GLsizei maxLength, GLsizei * length, char *infoLog) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetShaderInfoLog (shader, maxLength, length, infoLog); } void glGetShaderiv (GLuint shader, GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetShaderiv (shader, pname, params); } void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttribPointer (index, size, type, normalized, stride, pointer); } void glEnableVertexAttribArray (GLuint index) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glEnableVertexAttribArray (index); } void glDisableVertexAttribArray (GLuint index) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDisableVertexAttribArray (index); } void glUniform1f (GLint location, GLfloat v0) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform1f (location, v0); } void glUniform2f (GLint location, GLfloat v0, GLfloat v1) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform2f (location, v0, v1); } void glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform3f (location, v0, v1, v2); } void glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform4f (location, v0, v1, v2, v3); } void glUniform1fv (GLint location, GLsizei count, const GLfloat * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform1fv (location, count, value); } void glUniform2fv (GLint location, GLsizei count, const GLfloat * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform2fv (location, count, value); } void glUniform3fv (GLint location, GLsizei count, const GLfloat * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform3fv (location, count, value); } void glUniform4fv (GLint location, GLsizei count, const GLfloat * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform4fv (location, count, value); } void glUniform1i (GLint location, GLint v0) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform1i (location, v0); } void glUniform2i (GLint location, GLint v0, GLint v1) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform2i (location, v0, v1); } void glUniform3i (GLint location, GLint v0, GLint v1, GLint v2) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform3i (location, v0, v1, v2); } void glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform4i (location, v0, v1, v2, v3); } void glUniform1iv (GLint location, GLsizei count, const GLint * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform1iv (location, count, value); } void glUniform2iv (GLint location, GLsizei count, const GLint * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform2iv (location, count, value); } void glUniform3iv (GLint location, GLsizei count, const GLint * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform3iv (location, count, value); } void glUniform4iv (GLint location, GLsizei count, const GLint * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniform4iv (location, count, value); } void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniformMatrix2fv (location, count, transpose, value); } void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniformMatrix3fv (location, count, transpose, value); } void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glUniformMatrix4fv (location, count, transpose, value); } void glGetUniformfv (GLuint program, GLint location, GLfloat * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetUniformfv (program, location, params); } void glGetUniformiv (GLuint program, GLint location, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetUniformiv (program, location, params); } void glGetProgramiv (GLuint program, GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetProgramiv (program, pname, params); } void glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei * length, char *infoLog) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetProgramInfoLog (program, bufSize, length, infoLog); } void glVertexAttrib1f (GLuint indx, GLfloat x) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib1f (indx, x); } void glVertexAttrib1fv (GLuint indx, const GLfloat * values) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib1fv (indx, values); } void glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib2f (indx, x, y); } void glVertexAttrib2fv (GLuint indx, const GLfloat * values) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib2fv (indx, values); } void glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib3f (indx, x, y, z); } void glVertexAttrib3fv (GLuint indx, const GLfloat * values) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib3fv (indx, values); } void glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib4f (index, x, y, z, w); } void glVertexAttrib4fv (GLuint indx, const GLfloat * values) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glVertexAttrib4fv (indx, values); } void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetVertexAttribfv (index, pname, params); } void glGetVertexAttribiv (GLuint index, GLenum pname, GLint * params) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetVertexAttribiv (index, pname, params); } void glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid ** pointer) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetVertexAttribPointerv (index, pname, pointer); } GLint glGetAttribLocation (GLuint program, const char *name) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glGetAttribLocation (program, name); } void glBindAttribLocation (GLuint program, GLuint index, const GLchar * name) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glBindAttribLocation (program, index, name); } void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei * length, GLint * size, GLenum * type, GLchar * name) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetActiveAttrib (program, index, bufsize, length, size, type, name); } void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei * length, GLint * size, GLenum * type, GLchar * name) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetActiveUniform (program, index, bufsize, length, size, type, name); } void glDetachShader (GLuint program, GLuint shader) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glDetachShader (program, shader); } void glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei * count, GLuint * shaders) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetAttachedShaders (program, maxcount, count, shaders); } void glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei * length, GLchar * source) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glGetShaderSource (shader, bufsize, length, source); } GLboolean glIsShader (GLuint shader) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glIsShader (shader); } GLboolean glIsProgram (GLuint program) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); return vtable->glIsProgram (program); } void glValidateProgram (GLuint program) { CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable (); vtable->glValidateProgram (program); } muffin-5.2.1/cogl/cogl-gles2/muffin-cogl-gles2.pc.in0000664000175000017500000000065114211404421022171 0ustar jpeisachjpeisachprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@/muffin includedir=@includedir@/muffin apiversion=@MUFFIN_PLUGIN_API_VERSION@ requires=@COGL_PKG_REQUIRES@ muffin-cogl-@MUFFIN_PLUGIN_API_VERSION@ Name: Cogl Description: An object oriented GL/GLES Abstraction/Utility Layer Version: @MUFFIN_VERSION@ Libs: -L${libdir} -lmuffin-cogl-gles2-@MUFFIN_PLUGIN_API_VERSION@ Cflags: -I${includedir}/cogl Requires: ${requires} muffin-5.2.1/cogl/cogl-muffin-config.h.in0000664000175000017500000000057214211404421020313 0ustar jpeisachjpeisach/* Have GL for rendering */ #undef HAVE_COGL_GL /* Have GLES 1.1 for rendering */ #undef HAVE_COGL_GLES /* Have GLES 2.0 for rendering */ #undef HAVE_COGL_GLES2 /* Define to 1 if you have the `ffs' function. */ #undef HAVE_FFS /* Define to 1 if you have the `memmem' function. */ #undef HAVE_MEMMEM /* Whether _Static_assert can be used or not */ #undef HAVE_STATIC_ASSERT muffin-5.2.1/cogl/test-fixtures/0000775000175000017500000000000014211404421016706 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/test-fixtures/Makefile.am0000664000175000017500000000100514211404421020736 0ustar jpeisachjpeisach noinst_LTLIBRARIES = libtest-fixtures.la libtest_fixtures_la_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_builddir)/cogl \ -Wall \ $(NULL) libtest_fixtures_la_CPPFLAGS += \ -DCOGL_DISABLE_DEPRECATED \ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" \ -DCOGL_COMPILATION libtest_fixtures_la_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) -Wno-error=maybe-uninitialized -Wno-error=nested-externs -Wno-error=missing-prototypes libtest_fixtures_la_SOURCES = \ test-unit.h \ test-utils.h \ test-utils.c muffin-5.2.1/cogl/test-fixtures/test-utils.h0000664000175000017500000002430614211404421021201 0ustar jpeisachjpeisach#ifndef _TEST_UTILS_H_ #define _TEST_UTILS_H_ /* NB: This header is for private and public api testing and so * we need consider that if we are testing the public api we should * just include but since that will only provide * opaque typedefs we need to include the specific internal headers * for testing private apis... */ #ifdef COGL_COMPILATION #include #include #include #include #include #include #include #include #else #include #endif #include /* We don't really care about functions that are defined without a header for the unit tests so we can just disable it here */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wmissing-declarations" #endif typedef enum _TestFlags { TEST_KNOWN_FAILURE = 1<<0, TEST_REQUIREMENT_GL = 1<<1, TEST_REQUIREMENT_NPOT = 1<<2, TEST_REQUIREMENT_TEXTURE_3D = 1<<3, TEST_REQUIREMENT_TEXTURE_RECTANGLE = 1<<4, TEST_REQUIREMENT_TEXTURE_RG = 1<<5, TEST_REQUIREMENT_POINT_SPRITE = 1<<6, TEST_REQUIREMENT_GLES2_CONTEXT = 1<<7, TEST_REQUIREMENT_MAP_WRITE = 1<<8, TEST_REQUIREMENT_GLSL = 1<<9, TEST_REQUIREMENT_OFFSCREEN = 1<<10, TEST_REQUIREMENT_FENCE = 1<<11, TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE = 1<<12 } TestFlags; /** * TestUtilsTextureFlags: * @TEST_UTILS_TEXTURE_NONE: No flags specified * @TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of * the mipmap pyramid from the base level image whenever it is * updated. The mipmaps are only generated when the texture is * rendered with a mipmap filter so it should be free to leave out * this flag when using other filtering modes * @TEST_UTILS_TEXTURE_NO_SLICING: Disables the slicing of the texture * @TEST_UTILS_TEXTURE_NO_ATLAS: Disables the insertion of the texture inside * the texture atlas used by Cogl * * Flags to pass to the test_utils_texture_new_* family of functions. */ typedef enum { TEST_UTILS_TEXTURE_NONE = 0, TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP = 1 << 0, TEST_UTILS_TEXTURE_NO_SLICING = 1 << 1, TEST_UTILS_TEXTURE_NO_ATLAS = 1 << 2 } TestUtilsTextureFlags; extern CoglContext *test_ctx; extern CoglFramebuffer *test_fb; void test_utils_init (TestFlags requirement_flags, TestFlags known_failure_flags); void test_utils_fini (void); /* * test_utils_texture_new_with_size: * @context: A #CoglContext * @width: width of texture in pixels. * @height: height of texture in pixels. * @flags: Optional flags for the texture, or %TEST_UTILS_TEXTURE_NONE * @components: What texture components are required * * Creates a new #CoglTexture with the specified dimensions and pixel format. * * The storage for the texture is not necesarily created before this * function returns. The storage can be explicitly allocated using * cogl_texture_allocate() or preferably you can let Cogl * automatically allocate the storage lazily when uploading data when * Cogl may know more about how the texture will be used and can * optimize how it is allocated. * * Return value: A newly created #CoglTexture */ CoglTexture * test_utils_texture_new_with_size (CoglContext *ctx, int width, int height, TestUtilsTextureFlags flags, CoglTextureComponents components); /* * test_utils_texture_new_from_data: * @context: A #CoglContext * @width: width of texture in pixels * @height: height of texture in pixels * @flags: Optional flags for the texture, or %TEST_UTILS_TEXTURE_NONE * @format: the #CoglPixelFormat the buffer is stored in in RAM * @rowstride: the memory offset in bytes between the starts of * scanlines in @data * @data: pointer the memory region where the source buffer resides * @error: A #CoglError to catch exceptional errors or %NULL * * Creates a new #CoglTexture based on data residing in memory. * * Note: If the given @format has an alpha channel then the data * will be loaded into a premultiplied internal format. If you want * to avoid having the source data be premultiplied then you can * either specify that the data is already premultiplied or use * test_utils_texture_new_from_bitmap which lets you explicitly * request whether the data should internally be premultipled or not. * * Return value: A newly created #CoglTexture or %NULL on failure */ CoglTexture * test_utils_texture_new_from_data (CoglContext *ctx, int width, int height, TestUtilsTextureFlags flags, CoglPixelFormat format, int rowstride, const uint8_t *data); /* * test_utils_texture_new_from_bitmap: * @bitmap: A #CoglBitmap pointer * @flags: Optional flags for the texture, or %TEST_UTILS_TEXTURE_NONE * @premultiplied: Whether the texture should hold premultipled data. * (if the bitmap already holds premultiplied data * and %TRUE is given then no premultiplication will * be done. The data will be premultipled while * uploading if the bitmap has an alpha channel but * does not already have a premultiplied format.) * * Creates a #CoglTexture from a #CoglBitmap. * * Return value: A newly created #CoglTexture or %NULL on failure */ CoglTexture * test_utils_texture_new_from_bitmap (CoglBitmap *bitmap, TestUtilsTextureFlags flags, CoglBool premultiplied); /* * test_utils_check_pixel: * @framebuffer: The #CoglFramebuffer to read from * @x: x co-ordinate of the pixel to test * @y: y co-ordinate of the pixel to test * @pixel: An integer of the form 0xRRGGBBAA representing the expected * pixel value * * This performs reads a pixel on the given cogl @framebuffer and * asserts that it matches the given color. The alpha channel of the * color is ignored. The pixels are converted to a string and compared * with g_assert_cmpstr so that if the comparison fails then the * assert will display a meaningful message */ void test_utils_check_pixel (CoglFramebuffer *framebuffer, int x, int y, uint32_t expected_pixel); /** * @framebuffer: The #CoglFramebuffer to read from * @x: x co-ordinate of the pixel to test * @y: y co-ordinate of the pixel to test * @pixel: An integer of the form 0xRRGGBBAA representing the expected * pixel value * * This performs reads a pixel on the given cogl @framebuffer and * asserts that it matches the given color. The alpha channel is also * checked unlike with test_utils_check_pixel(). The pixels are * converted to a string and compared with g_assert_cmpstr so that if * the comparison fails then the assert will display a meaningful * message. */ void test_utils_check_pixel_and_alpha (CoglFramebuffer *fb, int x, int y, uint32_t expected_pixel); /* * test_utils_check_pixel: * @framebuffer: The #CoglFramebuffer to read from * @x: x co-ordinate of the pixel to test * @y: y co-ordinate of the pixel to test * @pixel: An integer of the form 0xrrggbb representing the expected pixel value * * This performs reads a pixel on the given cogl @framebuffer and * asserts that it matches the given color. The alpha channel of the * color is ignored. The pixels are converted to a string and compared * with g_assert_cmpstr so that if the comparison fails then the * assert will display a meaningful message */ void test_utils_check_pixel_rgb (CoglFramebuffer *framebuffer, int x, int y, int r, int g, int b); /* * test_utils_check_region: * @framebuffer: The #CoglFramebuffer to read from * @x: x co-ordinate of the region to test * @y: y co-ordinate of the region to test * @width: width of the region to test * @height: height of the region to test * @pixel: An integer of the form 0xrrggbb representing the expected region color * * Performs a read pixel on the specified region of the given cogl * @framebuffer and asserts that it matches the given color. The alpha * channel of the color is ignored. The pixels are converted to a * string and compared with g_assert_cmpstr so that if the comparison * fails then the assert will display a meaningful message */ void test_utils_check_region (CoglFramebuffer *framebuffer, int x, int y, int width, int height, uint32_t expected_rgba); /* * test_utils_compare_pixel: * @screen_pixel: A pixel stored in memory * @expected_pixel: The expected RGBA value * * Compares a pixel from a buffer to an expected value. The pixels are * converted to a string and compared with g_assert_cmpstr so that if * the comparison fails then the assert will display a meaningful * message. */ void test_utils_compare_pixel (const uint8_t *screen_pixel, uint32_t expected_pixel); /* * test_utils_compare_pixel_and_alpha: * @screen_pixel: A pixel stored in memory * @expected_pixel: The expected RGBA value * * Compares a pixel from a buffer to an expected value. This is * similar to test_utils_compare_pixel() except that it doesn't ignore * the alpha component. */ void test_utils_compare_pixel_and_alpha (const uint8_t *screen_pixel, uint32_t expected_pixel); /* * test_utils_create_color_texture: * @context: A #CoglContext * @color: A color to put in the texture * * Creates a 1x1-pixel RGBA texture filled with the given color. */ CoglTexture * test_utils_create_color_texture (CoglContext *context, uint32_t color); /* cogl_test_verbose: * * Queries if the user asked for verbose output or not. */ CoglBool cogl_test_verbose (void); /* test_util_is_pot: * @number: A number to test * * Returns whether the given integer is a power of two */ static inline CoglBool test_utils_is_pot (unsigned int number) { /* Make sure there is only one bit set */ return (number & (number - 1)) == 0; } #endif /* _TEST_UTILS_H_ */ muffin-5.2.1/cogl/test-fixtures/test-utils.c0000664000175000017500000003664314211404421021203 0ustar jpeisachjpeisach#include "cogl-config.h" #include #include "test-unit.h" #include "test-utils.h" #define FB_WIDTH 512 #define FB_HEIGHT 512 static CoglBool cogl_test_is_verbose; CoglContext *test_ctx; CoglFramebuffer *test_fb; static CoglBool check_flags (TestFlags flags, CoglRenderer *renderer) { if (flags & TEST_REQUIREMENT_GL && cogl_renderer_get_driver (renderer) != COGL_DRIVER_GL && cogl_renderer_get_driver (renderer) != COGL_DRIVER_GL3) { return FALSE; } if (flags & TEST_REQUIREMENT_NPOT && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT)) { return FALSE; } if (flags & TEST_REQUIREMENT_TEXTURE_3D && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_3D)) { return FALSE; } if (flags & TEST_REQUIREMENT_TEXTURE_RECTANGLE && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE)) { return FALSE; } if (flags & TEST_REQUIREMENT_TEXTURE_RG && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RG)) { return FALSE; } if (flags & TEST_REQUIREMENT_POINT_SPRITE && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_POINT_SPRITE)) { return FALSE; } if (flags & TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE)) { return FALSE; } if (flags & TEST_REQUIREMENT_GLES2_CONTEXT && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_GLES2_CONTEXT)) { return FALSE; } if (flags & TEST_REQUIREMENT_MAP_WRITE && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE)) { return FALSE; } if (flags & TEST_REQUIREMENT_GLSL && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_GLSL)) { return FALSE; } if (flags & TEST_REQUIREMENT_OFFSCREEN && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_OFFSCREEN)) { return FALSE; } if (flags & TEST_REQUIREMENT_FENCE && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_FENCE)) { return FALSE; } if (flags & TEST_KNOWN_FAILURE) { return FALSE; } return TRUE; } CoglBool is_boolean_env_set (const char *variable) { char *val = getenv (variable); CoglBool ret; if (!val) return FALSE; if (g_ascii_strcasecmp (val, "1") == 0 || g_ascii_strcasecmp (val, "on") == 0 || g_ascii_strcasecmp (val, "true") == 0) ret = TRUE; else if (g_ascii_strcasecmp (val, "0") == 0 || g_ascii_strcasecmp (val, "off") == 0 || g_ascii_strcasecmp (val, "false") == 0) ret = FALSE; else { g_critical ("Spurious boolean environment variable value (%s=%s)", variable, val); ret = TRUE; } return ret; } void test_utils_init (TestFlags requirement_flags, TestFlags known_failure_flags) { static int counter = 0; CoglError *error = NULL; CoglOnscreen *onscreen = NULL; CoglDisplay *display; CoglRenderer *renderer; CoglBool missing_requirement; CoglBool known_failure; if (counter != 0) g_critical ("We don't support running more than one test at a time\n" "in a single test run due to the state leakage that can\n" "cause subsequent tests to fail.\n" "\n" "If you want to run all the tests you should run\n" "$ make test-report"); counter++; if (is_boolean_env_set ("COGL_TEST_VERBOSE") || is_boolean_env_set ("V")) cogl_test_is_verbose = TRUE; /* NB: This doesn't have any effect since commit 47444dac of glib * because the environment variable is read in a magic constructor * so it is too late to set them here */ if (g_getenv ("G_DEBUG")) { char *debug = g_strconcat (g_getenv ("G_DEBUG"), ",fatal-warnings", NULL); g_setenv ("G_DEBUG", debug, TRUE); free (debug); } else g_setenv ("G_DEBUG", "fatal-warnings", TRUE); g_setenv ("COGL_X11_SYNC", "1", 0); test_ctx = cogl_context_new (NULL, &error); if (!test_ctx) g_critical ("Failed to create a CoglContext: %s", error->message); display = cogl_context_get_display (test_ctx); renderer = cogl_display_get_renderer (display); missing_requirement = !check_flags (requirement_flags, renderer); known_failure = !check_flags (known_failure_flags, renderer); if (is_boolean_env_set ("COGL_TEST_ONSCREEN")) { onscreen = cogl_onscreen_new (test_ctx, 640, 480); test_fb = COGL_FRAMEBUFFER (onscreen); } else { CoglOffscreen *offscreen; CoglTexture2D *tex = cogl_texture_2d_new_with_size (test_ctx, FB_WIDTH, FB_HEIGHT); offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex)); test_fb = COGL_FRAMEBUFFER (offscreen); } if (!cogl_framebuffer_allocate (test_fb, &error)) g_critical ("Failed to allocate framebuffer: %s", error->message); if (onscreen) cogl_onscreen_show (onscreen); cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH | COGL_BUFFER_BIT_STENCIL, 0, 0, 0, 1); if (missing_requirement) g_print ("WARNING: Missing required feature[s] for this test\n"); else if (known_failure) g_print ("WARNING: Test is known to fail\n"); } void test_utils_fini (void) { if (test_fb) cogl_object_unref (test_fb); if (test_ctx) cogl_object_unref (test_ctx); } static CoglBool compare_component (int a, int b) { return ABS (a - b) <= 1; } void test_utils_compare_pixel_and_alpha (const uint8_t *screen_pixel, uint32_t expected_pixel) { /* Compare each component with a small fuzz factor */ if (!compare_component (screen_pixel[0], expected_pixel >> 24) || !compare_component (screen_pixel[1], (expected_pixel >> 16) & 0xff) || !compare_component (screen_pixel[2], (expected_pixel >> 8) & 0xff) || !compare_component (screen_pixel[3], (expected_pixel >> 0) & 0xff)) { uint32_t screen_pixel_num = GUINT32_FROM_BE (*(uint32_t *) screen_pixel); char *screen_pixel_string = g_strdup_printf ("#%08x", screen_pixel_num); char *expected_pixel_string = g_strdup_printf ("#%08x", expected_pixel); g_assert_cmpstr (screen_pixel_string, ==, expected_pixel_string); free (screen_pixel_string); free (expected_pixel_string); } } void test_utils_compare_pixel (const uint8_t *screen_pixel, uint32_t expected_pixel) { /* Compare each component with a small fuzz factor */ if (!compare_component (screen_pixel[0], expected_pixel >> 24) || !compare_component (screen_pixel[1], (expected_pixel >> 16) & 0xff) || !compare_component (screen_pixel[2], (expected_pixel >> 8) & 0xff)) { uint32_t screen_pixel_num = GUINT32_FROM_BE (*(uint32_t *) screen_pixel); char *screen_pixel_string = g_strdup_printf ("#%06x", screen_pixel_num >> 8); char *expected_pixel_string = g_strdup_printf ("#%06x", expected_pixel >> 8); g_assert_cmpstr (screen_pixel_string, ==, expected_pixel_string); free (screen_pixel_string); free (expected_pixel_string); } } void test_utils_check_pixel (CoglFramebuffer *test_fb, int x, int y, uint32_t expected_pixel) { uint8_t pixel[4]; cogl_framebuffer_read_pixels (test_fb, x, y, 1, 1, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); test_utils_compare_pixel (pixel, expected_pixel); } void test_utils_check_pixel_and_alpha (CoglFramebuffer *test_fb, int x, int y, uint32_t expected_pixel) { uint8_t pixel[4]; cogl_framebuffer_read_pixels (test_fb, x, y, 1, 1, COGL_PIXEL_FORMAT_RGBA_8888_PRE, pixel); test_utils_compare_pixel_and_alpha (pixel, expected_pixel); } void test_utils_check_pixel_rgb (CoglFramebuffer *test_fb, int x, int y, int r, int g, int b) { test_utils_check_pixel (test_fb, x, y, (r << 24) | (g << 16) | (b << 8)); } void test_utils_check_region (CoglFramebuffer *test_fb, int x, int y, int width, int height, uint32_t expected_rgba) { uint8_t *pixels, *p; pixels = p = malloc (width * height * 4); cogl_framebuffer_read_pixels (test_fb, x, y, width, height, COGL_PIXEL_FORMAT_RGBA_8888, p); /* Check whether the center of each division is the right color */ for (y = 0; y < height; y++) for (x = 0; x < width; x++) { test_utils_compare_pixel (p, expected_rgba); p += 4; } free (pixels); } CoglTexture * test_utils_create_color_texture (CoglContext *context, uint32_t color) { CoglTexture2D *tex_2d; color = GUINT32_TO_BE (color); tex_2d = cogl_texture_2d_new_from_data (context, 1, 1, /* width/height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ (uint8_t *) &color, NULL); return COGL_TEXTURE (tex_2d); } CoglBool cogl_test_verbose (void) { return cogl_test_is_verbose; } static void set_auto_mipmap_cb (CoglTexture *sub_texture, const float *sub_texture_coords, const float *meta_coords, void *user_data) { cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (sub_texture), FALSE); } CoglTexture * test_utils_texture_new_with_size (CoglContext *ctx, int width, int height, TestUtilsTextureFlags flags, CoglTextureComponents components) { CoglTexture *tex; CoglError *skip_error = NULL; if ((test_utils_is_pot (width) && test_utils_is_pot (height)) || (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP))) { /* First try creating a fast-path non-sliced texture */ tex = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height)); cogl_texture_set_components (tex, components); if (!cogl_texture_allocate (tex, &skip_error)) { cogl_error_free (skip_error); cogl_object_unref (tex); tex = NULL; } } else tex = NULL; if (!tex) { /* If it fails resort to sliced textures */ int max_waste = flags & TEST_UTILS_TEXTURE_NO_SLICING ? -1 : COGL_TEXTURE_MAX_WASTE; CoglTexture2DSliced *tex_2ds = cogl_texture_2d_sliced_new_with_size (ctx, width, height, max_waste); tex = COGL_TEXTURE (tex_2ds); cogl_texture_set_components (tex, components); } if (flags & TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP) { /* To be able to iterate the slices of a #CoglTexture2DSliced we * need to ensure the texture is allocated... */ cogl_texture_allocate (tex, NULL); /* don't catch exceptions */ cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex), 0, 0, 1, 1, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, set_auto_mipmap_cb, NULL); /* don't catch exceptions */ } cogl_texture_allocate (tex, NULL); return tex; } CoglTexture * test_utils_texture_new_from_bitmap (CoglBitmap *bitmap, TestUtilsTextureFlags flags, CoglBool premultiplied) { CoglAtlasTexture *atlas_tex; CoglTexture *tex; CoglError *internal_error = NULL; if (!flags) { /* First try putting the texture in the atlas */ atlas_tex = cogl_atlas_texture_new_from_bitmap (bitmap); cogl_texture_set_premultiplied (COGL_TEXTURE (atlas_tex), premultiplied); if (cogl_texture_allocate (COGL_TEXTURE (atlas_tex), &internal_error)) return COGL_TEXTURE (atlas_tex); cogl_error_free (internal_error); cogl_object_unref (atlas_tex); internal_error = NULL; } /* If that doesn't work try a fast path 2D texture */ if ((test_utils_is_pot (cogl_bitmap_get_width (bitmap)) && test_utils_is_pot (cogl_bitmap_get_height (bitmap))) || (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP))) { tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap)); cogl_texture_set_premultiplied (tex, premultiplied); if (cogl_error_matches (internal_error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_NO_MEMORY)) { g_assert_not_reached (); return NULL; } if (!tex) { cogl_error_free (internal_error); internal_error = NULL; } } else tex = NULL; if (!tex) { /* Otherwise create a sliced texture */ int max_waste = flags & TEST_UTILS_TEXTURE_NO_SLICING ? -1 : COGL_TEXTURE_MAX_WASTE; CoglTexture2DSliced *tex_2ds = cogl_texture_2d_sliced_new_from_bitmap (bitmap, max_waste); tex = COGL_TEXTURE (tex_2ds); cogl_texture_set_premultiplied (tex, premultiplied); } if (flags & TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP) { cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex), 0, 0, 1, 1, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, set_auto_mipmap_cb, NULL); /* don't catch exceptions */ } cogl_texture_allocate (tex, NULL); return tex; } CoglTexture * test_utils_texture_new_from_data (CoglContext *ctx, int width, int height, TestUtilsTextureFlags flags, CoglPixelFormat format, int rowstride, const uint8_t *data) { CoglBitmap *bmp; CoglTexture *tex; g_assert_cmpint (format, !=, COGL_PIXEL_FORMAT_ANY); g_assert (data != NULL); /* Wrap the data into a bitmap */ bmp = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); tex = test_utils_texture_new_from_bitmap (bmp, flags, TRUE); cogl_object_unref (bmp); return tex; } muffin-5.2.1/cogl/test-fixtures/test-unit.h0000664000175000017500000000125714211404421021020 0ustar jpeisachjpeisach#ifndef _TEST_UNIT_H_ #define _TEST_UNIT_H_ #include #ifdef ENABLE_UNIT_TESTS typedef struct _CoglUnitTest { const char *name; TestFlags requirement_flags; TestFlags known_failure_flags; void (*run) (void); } CoglUnitTest; #define UNIT_TEST(NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS) \ static void NAME (void); \ \ const CoglUnitTest unit_test_##NAME = \ { #NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS, NAME }; \ \ static void NAME (void) #else /* ENABLE_UNIT_TESTS */ #define UNIT_TEST(NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS) \ static inline void NAME (void) #endif /* ENABLE_UNIT_TESTS */ #endif /* _TEST_UNIT_H_ */ muffin-5.2.1/cogl/cogl/0000775000175000017500000000000014211404421015004 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/cogl-color.h0000664000175000017500000003371214211404421017223 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_COLOR_H__ #define __COGL_COLOR_H__ /** * SECTION:cogl-color * @short_description: A generic color definition * * #CoglColor is a simple structure holding the definition of a color such * that it can be efficiently used by GL * * Since: 1.0 */ #include #include #include COGL_BEGIN_DECLS /** * cogl_color_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_color_get_gtype (void); /** * cogl_color_new: * * Creates a new (empty) color * * Return value: a newly-allocated #CoglColor. Use cogl_color_free() * to free the allocated resources * * Since: 1.0 */ CoglColor * cogl_color_new (void); /** * cogl_color_copy: * @color: the color to copy * * Creates a copy of @color * * Return value: a newly-allocated #CoglColor. Use cogl_color_free() * to free the allocate resources * * Since: 1.0 */ CoglColor * cogl_color_copy (const CoglColor *color); /** * cogl_color_free: * @color: the color to free * * Frees the resources allocated by cogl_color_new() and cogl_color_copy() * * Since: 1.0 */ void cogl_color_free (CoglColor *color); /** * cogl_color_init_from_4ub: * @color: A pointer to a #CoglColor to initialize * @red: value of the red channel, between 0 and 255 * @green: value of the green channel, between 0 and 255 * @blue: value of the blue channel, between 0 and 255 * @alpha: value of the alpha channel, between 0 and 255 * * Sets the values of the passed channels into a #CoglColor. * * Since: 1.4 */ void cogl_color_init_from_4ub (CoglColor *color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); /** * cogl_color_set_from_4ub: * @color: A pointer to a #CoglColor to initialize * @red: value of the red channel, between 0 and 255 * @green: value of the green channel, between 0 and 255 * @blue: value of the blue channel, between 0 and 255 * @alpha: value of the alpha channel, between 0 and 255 * * Sets the values of the passed channels into a #CoglColor. * * Since: 1.0 * Deprecated: 1.4: Use cogl_color_init_from_4ub instead. */ COGL_DEPRECATED_IN_1_4_FOR (cogl_color_init_from_4ub) void cogl_color_set_from_4ub (CoglColor *color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); /** * cogl_color_init_from_4f: * @color: A pointer to a #CoglColor to initialize * @red: value of the red channel, between 0 and 1.0 * @green: value of the green channel, between 0 and 1.0 * @blue: value of the blue channel, between 0 and 1.0 * @alpha: value of the alpha channel, between 0 and 1.0 * * Sets the values of the passed channels into a #CoglColor * * Since: 1.4 */ void cogl_color_init_from_4f (CoglColor *color, float red, float green, float blue, float alpha); /** * cogl_color_set_from_4f: * @color: A pointer to a #CoglColor to initialize * @red: value of the red channel, between 0 and %1.0 * @green: value of the green channel, between 0 and %1.0 * @blue: value of the blue channel, between 0 and %1.0 * @alpha: value of the alpha channel, between 0 and %1.0 * * Sets the values of the passed channels into a #CoglColor * * Since: 1.0 * Deprecated: 1.4: Use cogl_color_init_from_4f instead. */ COGL_DEPRECATED_IN_1_4_FOR (cogl_color_init_from_4f) void cogl_color_set_from_4f (CoglColor *color, float red, float green, float blue, float alpha); /** * cogl_color_init_from_4fv: * @color: A pointer to a #CoglColor to initialize * @color_array: a pointer to an array of 4 float color components * * Sets the values of the passed channels into a #CoglColor * * Since: 1.4 */ void cogl_color_init_from_4fv (CoglColor *color, const float *color_array); /** * cogl_color_get_red_byte: * @color: a #CoglColor * * Retrieves the red channel of @color as a byte value * between 0 and 255 * * Return value: the red channel of the passed color * * Since: 1.0 */ unsigned char cogl_color_get_red_byte (const CoglColor *color); /** * cogl_color_get_green_byte: * @color: a #CoglColor * * Retrieves the green channel of @color as a byte value * between 0 and 255 * * Return value: the green channel of the passed color * * Since: 1.0 */ unsigned char cogl_color_get_green_byte (const CoglColor *color); /** * cogl_color_get_blue_byte: * @color: a #CoglColor * * Retrieves the blue channel of @color as a byte value * between 0 and 255 * * Return value: the blue channel of the passed color * * Since: 1.0 */ unsigned char cogl_color_get_blue_byte (const CoglColor *color); /** * cogl_color_get_alpha_byte: * @color: a #CoglColor * * Retrieves the alpha channel of @color as a byte value * between 0 and 255 * * Return value: the alpha channel of the passed color * * Since: 1.0 */ unsigned char cogl_color_get_alpha_byte (const CoglColor *color); /** * cogl_color_get_red_float: * @color: a #CoglColor * * Retrieves the red channel of @color as a floating point * value between 0.0 and 1.0 * * Return value: the red channel of the passed color * * Since: 1.0 */ float cogl_color_get_red_float (const CoglColor *color); /** * cogl_color_get_green_float: * @color: a #CoglColor * * Retrieves the green channel of @color as a floating point * value between 0.0 and 1.0 * * Return value: the green channel of the passed color * * Since: 1.0 */ float cogl_color_get_green_float (const CoglColor *color); /** * cogl_color_get_blue_float: * @color: a #CoglColor * * Retrieves the blue channel of @color as a floating point * value between 0.0 and 1.0 * * Return value: the blue channel of the passed color * * Since: 1.0 */ float cogl_color_get_blue_float (const CoglColor *color); /** * cogl_color_get_alpha_float: * @color: a #CoglColor * * Retrieves the alpha channel of @color as a floating point * value between 0.0 and 1.0 * * Return value: the alpha channel of the passed color * * Since: 1.0 */ float cogl_color_get_alpha_float (const CoglColor *color); /** * cogl_color_get_red: * @color: a #CoglColor * * Retrieves the red channel of @color as a fixed point * value between 0 and 1.0. * * Return value: the red channel of the passed color * * Since: 1.0 */ float cogl_color_get_red (const CoglColor *color); /** * cogl_color_get_green: * @color: a #CoglColor * * Retrieves the green channel of @color as a fixed point * value between 0 and 1.0. * * Return value: the green channel of the passed color * * Since: 1.0 */ float cogl_color_get_green (const CoglColor *color); /** * cogl_color_get_blue: * @color: a #CoglColor * * Retrieves the blue channel of @color as a fixed point * value between 0 and 1.0. * * Return value: the blue channel of the passed color * * Since: 1.0 */ float cogl_color_get_blue (const CoglColor *color); /** * cogl_color_get_alpha: * @color: a #CoglColor * * Retrieves the alpha channel of @color as a fixed point * value between 0 and 1.0. * * Return value: the alpha channel of the passed color * * Since: 1.0 */ float cogl_color_get_alpha (const CoglColor *color); /** * cogl_color_set_red_byte: * @color: a #CoglColor * @red: a byte value between 0 and 255 * * Sets the red channel of @color to @red. * * Since: 1.4 */ void cogl_color_set_red_byte (CoglColor *color, unsigned char red); /** * cogl_color_set_green_byte: * @color: a #CoglColor * @green: a byte value between 0 and 255 * * Sets the green channel of @color to @green. * * Since: 1.4 */ void cogl_color_set_green_byte (CoglColor *color, unsigned char green); /** * cogl_color_set_blue_byte: * @color: a #CoglColor * @blue: a byte value between 0 and 255 * * Sets the blue channel of @color to @blue. * * Since: 1.4 */ void cogl_color_set_blue_byte (CoglColor *color, unsigned char blue); /** * cogl_color_set_alpha_byte: * @color: a #CoglColor * @alpha: a byte value between 0 and 255 * * Sets the alpha channel of @color to @alpha. * * Since: 1.4 */ void cogl_color_set_alpha_byte (CoglColor *color, unsigned char alpha); /** * cogl_color_set_red_float: * @color: a #CoglColor * @red: a float value between 0.0f and 1.0f * * Sets the red channel of @color to @red. * * since: 1.4 */ void cogl_color_set_red_float (CoglColor *color, float red); /** * cogl_color_set_green_float: * @color: a #CoglColor * @green: a float value between 0.0f and 1.0f * * Sets the green channel of @color to @green. * * since: 1.4 */ void cogl_color_set_green_float (CoglColor *color, float green); /** * cogl_color_set_blue_float: * @color: a #CoglColor * @blue: a float value between 0.0f and 1.0f * * Sets the blue channel of @color to @blue. * * since: 1.4 */ void cogl_color_set_blue_float (CoglColor *color, float blue); /** * cogl_color_set_alpha_float: * @color: a #CoglColor * @alpha: a float value between 0.0f and 1.0f * * Sets the alpha channel of @color to @alpha. * * since: 1.4 */ void cogl_color_set_alpha_float (CoglColor *color, float alpha); /** * cogl_color_set_red: * @color: a #CoglColor * @red: a float value between 0.0f and 1.0f * * Sets the red channel of @color to @red. * * Since: 1.4 */ void cogl_color_set_red (CoglColor *color, float red); /** * cogl_color_set_green: * @color: a #CoglColor * @green: a float value between 0.0f and 1.0f * * Sets the green channel of @color to @green. * * Since: 1.4 */ void cogl_color_set_green (CoglColor *color, float green); /** * cogl_color_set_blue: * @color: a #CoglColor * @blue: a float value between 0.0f and 1.0f * * Sets the blue channel of @color to @blue. * * Since: 1.4 */ void cogl_color_set_blue (CoglColor *color, float blue); /** * cogl_color_set_alpha: * @color: a #CoglColor * @alpha: a float value between 0.0f and 1.0f * * Sets the alpha channel of @color to @alpha. * * Since: 1.4 */ void cogl_color_set_alpha (CoglColor *color, float alpha); /** * cogl_color_premultiply: * @color: the color to premultiply * * Converts a non-premultiplied color to a pre-multiplied color. For * example, semi-transparent red is (1.0, 0, 0, 0.5) when non-premultiplied * and (0.5, 0, 0, 0.5) when premultiplied. * * Since: 1.0 */ void cogl_color_premultiply (CoglColor *color); /** * cogl_color_unpremultiply: * @color: the color to unpremultiply * * Converts a pre-multiplied color to a non-premultiplied color. For * example, semi-transparent red is (0.5, 0, 0, 0.5) when premultiplied * and (1.0, 0, 0, 0.5) when non-premultiplied. * * Since: 1.4 */ void cogl_color_unpremultiply (CoglColor *color); /** * cogl_color_equal: * @v1: a #CoglColor * @v2: a #CoglColor * * Compares two #CoglColors and checks if they are the same. * * This function can be passed to g_hash_table_new() as the @key_equal_func * parameter, when using #CoglColors as keys in a #GHashTable. * * Return value: %TRUE if the two colors are the same. * * Since: 1.0 */ CoglBool cogl_color_equal (const void *v1, const void *v2); /** * cogl_color_to_hsl: * @color: a #CoglColor * @hue: (out): return location for the hue value or %NULL * @saturation: (out): return location for the saturation value or %NULL * @luminance: (out): return location for the luminance value or %NULL * * Converts @color to the HLS format. * * The @hue value is in the 0 .. 360 range. The @luminance and * @saturation values are in the 0 .. 1 range. * * Since: 1.16 */ void cogl_color_to_hsl (const CoglColor *color, float *hue, float *saturation, float *luminance); /** * cogl_color_init_from_hsl: * @color: (out): return location for a #CoglColor * @hue: hue value, in the 0 .. 360 range * @saturation: saturation value, in the 0 .. 1 range * @luminance: luminance value, in the 0 .. 1 range * * Converts a color expressed in HLS (hue, luminance and saturation) * values into a #CoglColor. * * Since: 1.16 */ void cogl_color_init_from_hsl (CoglColor *color, float hue, float saturation, float luminance); COGL_END_DECLS #endif /* __COGL_COLOR_H__ */ muffin-5.2.1/cogl/cogl/cogl-gl-header.h.in0000664000175000017500000000301614211404421020334 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(COGL_COMPILATION) && !defined(COGL_ENABLE_MUFFIN_API) #error "cogl-gl-header.h should only be included when compiling Cogl" #endif #ifndef __COGL_GL_HEADER_H__ #define __COGL_GL_HEADER_H__ #include "cogl-defines.h" @COGL_GL_HEADER_INCLUDES@ #ifndef GL_OES_EGL_image #define GLeglImageOES void * #endif #endif /* __COGL_GL_HEADER_H__ */ muffin-5.2.1/cogl/cogl/cogl-matrix.c0000664000175000017500000021054214211404421017402 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2011 Intel Corporation. * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ /* * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Note: a lot of this code is based on code that was taken from Mesa. * * Changes compared to the original code from Mesa: * * - instead of allocating matrix->m and matrix->inv using malloc, our * public CoglMatrix typedef is large enough to directly contain the * matrix, its inverse, a type and a set of flags. * - instead of having a _cogl_matrix_analyse which updates the type, * flags and inverse, we have _cogl_matrix_update_inverse which * essentially does the same thing (internally making use of * _cogl_matrix_update_type_and_flags()) but with additional guards in * place to bail out when the inverse matrix is still valid. * - when initializing a matrix with the identity matrix we don't * immediately initialize the inverse matrix; rather we just set the * dirty flag for the inverse (since it's likely the user won't request * the inverse of the identity matrix) */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include #include #include #include #include #include #include #include COGL_GTYPE_DEFINE_BOXED (Matrix, matrix, cogl_matrix_copy, cogl_matrix_free); /* * Symbolic names to some of the entries in the matrix * * These are handy for the viewport mapping, which is expressed as a matrix. */ #define MAT_SX 0 #define MAT_SY 5 #define MAT_SZ 10 #define MAT_TX 12 #define MAT_TY 13 #define MAT_TZ 14 /* * These identify different kinds of 4x4 transformation matrices and we use * this information to find fast-paths when available. */ enum CoglMatrixType { COGL_MATRIX_TYPE_GENERAL, /**< general 4x4 matrix */ COGL_MATRIX_TYPE_IDENTITY, /**< identity matrix */ COGL_MATRIX_TYPE_3D_NO_ROT, /**< orthogonal projection and others... */ COGL_MATRIX_TYPE_PERSPECTIVE, /**< perspective projection matrix */ COGL_MATRIX_TYPE_2D, /**< 2-D transformation */ COGL_MATRIX_TYPE_2D_NO_ROT, /**< 2-D scale & translate only */ COGL_MATRIX_TYPE_3D, /**< 3-D transformation */ COGL_MATRIX_N_TYPES } ; #define DEG2RAD (G_PI/180.0) /* Dot product of two 2-element vectors */ #define DOT2(A,B) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] ) /* Dot product of two 3-element vectors */ #define DOT3(A,B) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] ) #define CROSS3(N, U, V) \ do { \ (N)[0] = (U)[1]*(V)[2] - (U)[2]*(V)[1]; \ (N)[1] = (U)[2]*(V)[0] - (U)[0]*(V)[2]; \ (N)[2] = (U)[0]*(V)[1] - (U)[1]*(V)[0]; \ } while (0) #define SUB_3V(DST, SRCA, SRCB) \ do { \ (DST)[0] = (SRCA)[0] - (SRCB)[0]; \ (DST)[1] = (SRCA)[1] - (SRCB)[1]; \ (DST)[2] = (SRCA)[2] - (SRCB)[2]; \ } while (0) #define LEN_SQUARED_3FV( V ) ((V)[0]*(V)[0]+(V)[1]*(V)[1]+(V)[2]*(V)[2]) /* * \defgroup MatFlags MAT_FLAG_XXX-flags * * Bitmasks to indicate different kinds of 4x4 matrices in CoglMatrix::flags */ #define MAT_FLAG_IDENTITY 0 /*< is an identity matrix flag. * (Not actually used - the identity * matrix is identified by the absense * of all other flags.) */ #define MAT_FLAG_GENERAL 0x1 /*< is a general matrix flag */ #define MAT_FLAG_ROTATION 0x2 /*< is a rotation matrix flag */ #define MAT_FLAG_TRANSLATION 0x4 /*< is a translation matrix flag */ #define MAT_FLAG_UNIFORM_SCALE 0x8 /*< is an uniform scaling matrix flag */ #define MAT_FLAG_GENERAL_SCALE 0x10 /*< is a general scaling matrix flag */ #define MAT_FLAG_GENERAL_3D 0x20 /*< general 3D matrix flag */ #define MAT_FLAG_PERSPECTIVE 0x40 /*< is a perspective proj matrix flag */ #define MAT_FLAG_SINGULAR 0x80 /*< is a singular matrix flag */ #define MAT_DIRTY_TYPE 0x100 /*< matrix type is dirty */ #define MAT_DIRTY_FLAGS 0x200 /*< matrix flags are dirty */ #define MAT_DIRTY_INVERSE 0x400 /*< matrix inverse is dirty */ /* angle preserving matrix flags mask */ #define MAT_FLAGS_ANGLE_PRESERVING (MAT_FLAG_ROTATION | \ MAT_FLAG_TRANSLATION | \ MAT_FLAG_UNIFORM_SCALE) /* geometry related matrix flags mask */ #define MAT_FLAGS_GEOMETRY (MAT_FLAG_GENERAL | \ MAT_FLAG_ROTATION | \ MAT_FLAG_TRANSLATION | \ MAT_FLAG_UNIFORM_SCALE | \ MAT_FLAG_GENERAL_SCALE | \ MAT_FLAG_GENERAL_3D | \ MAT_FLAG_PERSPECTIVE | \ MAT_FLAG_SINGULAR) /* length preserving matrix flags mask */ #define MAT_FLAGS_LENGTH_PRESERVING (MAT_FLAG_ROTATION | \ MAT_FLAG_TRANSLATION) /* 3D (non-perspective) matrix flags mask */ #define MAT_FLAGS_3D (MAT_FLAG_ROTATION | \ MAT_FLAG_TRANSLATION | \ MAT_FLAG_UNIFORM_SCALE | \ MAT_FLAG_GENERAL_SCALE | \ MAT_FLAG_GENERAL_3D) /* dirty matrix flags mask */ #define MAT_DIRTY_ALL (MAT_DIRTY_TYPE | \ MAT_DIRTY_FLAGS | \ MAT_DIRTY_INVERSE) /* * Test geometry related matrix flags. * * @mat a pointer to a CoglMatrix structure. * @a flags mask. * * Returns: non-zero if all geometry related matrix flags are contained within * the mask, or zero otherwise. */ #define TEST_MAT_FLAGS(mat, a) \ ((MAT_FLAGS_GEOMETRY & (~(a)) & ((mat)->flags) ) == 0) /* * Names of the corresponding CoglMatrixType values. */ static const char *types[] = { "COGL_MATRIX_TYPE_GENERAL", "COGL_MATRIX_TYPE_IDENTITY", "COGL_MATRIX_TYPE_3D_NO_ROT", "COGL_MATRIX_TYPE_PERSPECTIVE", "COGL_MATRIX_TYPE_2D", "COGL_MATRIX_TYPE_2D_NO_ROT", "COGL_MATRIX_TYPE_3D" }; /* * Identity matrix. */ static float identity[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; #define A(row,col) a[(col<<2)+row] #define B(row,col) b[(col<<2)+row] #define R(row,col) result[(col<<2)+row] /* * Perform a full 4x4 matrix multiplication. * * It's assumed that @result != @b. @product == @a is allowed. * * KW: 4*16 = 64 multiplications */ static void matrix_multiply4x4 (float *result, const float *a, const float *b) { int i; for (i = 0; i < 4; i++) { const float ai0 = A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); } } /* * Multiply two matrices known to occupy only the top three rows, such * as typical model matrices, and orthogonal matrices. * * @a matrix. * @b matrix. * @product will receive the product of \p a and \p b. */ static void matrix_multiply3x4 (float *result, const float *a, const float *b) { int i; for (i = 0; i < 3; i++) { const float ai0 = A(i,0), ai1 = A(i,1), ai2 = A(i,2), ai3 = A(i,3); R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0); R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1); R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2); R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3; } R(3,0) = 0; R(3,1) = 0; R(3,2) = 0; R(3,3) = 1; } #undef A #undef B #undef R /* * Multiply a matrix by an array of floats with known properties. * * @mat pointer to a CoglMatrix structure containing the left multiplication * matrix, and that will receive the product result. * @m right multiplication matrix array. * @flags flags of the matrix \p m. * * Joins both flags and marks the type and inverse as dirty. Calls * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4() * otherwise. */ static void matrix_multiply_array_with_flags (CoglMatrix *result, const float *array, unsigned int flags) { result->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); if (TEST_MAT_FLAGS (result, MAT_FLAGS_3D)) matrix_multiply3x4 ((float *)result, (float *)result, array); else matrix_multiply4x4 ((float *)result, (float *)result, array); } /* Joins both flags and marks the type and inverse as dirty. Calls * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4() * otherwise. */ static void _cogl_matrix_multiply (CoglMatrix *result, const CoglMatrix *a, const CoglMatrix *b) { result->flags = (a->flags | b->flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); if (TEST_MAT_FLAGS(result, MAT_FLAGS_3D)) matrix_multiply3x4 ((float *)result, (float *)a, (float *)b); else matrix_multiply4x4 ((float *)result, (float *)a, (float *)b); } void cogl_matrix_multiply (CoglMatrix *result, const CoglMatrix *a, const CoglMatrix *b) { _cogl_matrix_multiply (result, a, b); _COGL_MATRIX_DEBUG_PRINT (result); } #if 0 /* Marks the matrix flags with general flag, and type and inverse dirty flags. * Calls matrix_multiply4x4() for the multiplication. */ static void _cogl_matrix_multiply_array (CoglMatrix *result, const float *array) { result->flags |= (MAT_FLAG_GENERAL | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE | MAT_DIRTY_FLAGS); matrix_multiply4x4 ((float *)result, (float *)result, (float *)array); } #endif /* * Print a matrix array. * * Called by _cogl_matrix_print() to print a matrix or its inverse. */ static void print_matrix_floats (const char *prefix, const float m[16]) { int i; for (i = 0;i < 4; i++) g_print ("%s\t%f %f %f %f\n", prefix, m[i], m[4+i], m[8+i], m[12+i] ); } void _cogl_matrix_prefix_print (const char *prefix, const CoglMatrix *matrix) { if (!(matrix->flags & MAT_DIRTY_TYPE)) { _COGL_RETURN_IF_FAIL (matrix->type < COGL_MATRIX_N_TYPES); g_print ("%sMatrix type: %s, flags: %x\n", prefix, types[matrix->type], (int)matrix->flags); } else g_print ("%sMatrix type: DIRTY, flags: %x\n", prefix, (int)matrix->flags); print_matrix_floats (prefix, (float *)matrix); g_print ("%sInverse: \n", prefix); if (!(matrix->flags & MAT_DIRTY_INVERSE)) { float prod[16]; print_matrix_floats (prefix, matrix->inv); matrix_multiply4x4 (prod, (float *)matrix, matrix->inv); g_print ("%sMat * Inverse:\n", prefix); print_matrix_floats (prefix, prod); } else g_print ("%s - not available\n", prefix); } /* * Dumps the contents of a CoglMatrix structure. */ void cogl_debug_matrix_print (const CoglMatrix *matrix) { _cogl_matrix_prefix_print ("", matrix); } /* * References an element of 4x4 matrix. * * @m matrix array. * @c column of the desired element. * @r row of the desired element. * * Returns: value of the desired element. * * Calculate the linear storage index of the element and references it. */ #define MAT(m,r,c) (m)[(c)*4+(r)] /* * Swaps the values of two floating pointer variables. * * Used by invert_matrix_general() to swap the row pointers. */ #define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; } /* * Compute inverse of 4x4 transformation matrix. * * @mat pointer to a CoglMatrix structure. The matrix inverse will be * stored in the CoglMatrix::inv attribute. * * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). * * \author * Code contributed by Jacques Leroy jle@star.be * * Calculates the inverse matrix by performing the gaussian matrix reduction * with partial pivoting followed by back/substitution with the loops manually * unrolled. */ static CoglBool invert_matrix_general (CoglMatrix *matrix) { const float *m = (float *)matrix; float *out = matrix->inv; float wtmp[4][8]; float m0, m1, m2, m3, s; float *r0, *r1, *r2, *r3; r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; r0[0] = MAT (m, 0, 0), r0[1] = MAT (m, 0, 1), r0[2] = MAT (m, 0, 2), r0[3] = MAT (m, 0, 3), r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, r1[0] = MAT (m, 1, 0), r1[1] = MAT (m, 1, 1), r1[2] = MAT (m, 1, 2), r1[3] = MAT (m, 1, 3), r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, r2[0] = MAT (m, 2, 0), r2[1] = MAT (m, 2, 1), r2[2] = MAT (m, 2, 2), r2[3] = MAT (m, 2, 3), r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, r3[0] = MAT (m, 3, 0), r3[1] = MAT (m, 3, 1), r3[2] = MAT (m, 3, 2), r3[3] = MAT (m, 3, 3), r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; /* choose pivot - or die */ if (fabsf (r3[0]) > fabsf (r2[0])) SWAP_ROWS (r3, r2); if (fabsf (r2[0]) > fabsf (r1[0])) SWAP_ROWS (r2, r1); if (fabsf (r1[0]) > fabsf (r0[0])) SWAP_ROWS (r1, r0); if (0.0 == r0[0]) return FALSE; /* eliminate first variable */ m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; s = r0[4]; if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } s = r0[5]; if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } s = r0[6]; if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } s = r0[7]; if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } /* choose pivot - or die */ if (fabsf (r3[1]) > fabsf (r2[1])) SWAP_ROWS (r3, r2); if (fabsf (r2[1]) > fabsf (r1[1])) SWAP_ROWS (r2, r1); if (0.0 == r1[1]) return FALSE; /* eliminate second variable */ m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1]; r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } /* choose pivot - or die */ if (fabsf (r3[2]) > fabsf (r2[2])) SWAP_ROWS (r3, r2); if (0.0 == r2[2]) return FALSE; /* eliminate third variable */ m3 = r3[2] / r2[2]; r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7]; /* last check */ if (0.0 == r3[3]) return FALSE; s = 1.0f / r3[3]; /* now back substitute row 3 */ r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; m2 = r2[3]; /* now back substitute row 2 */ s = 1.0f / r2[2]; r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); m1 = r1[3]; r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; m0 = r0[3]; r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; m1 = r1[2]; /* now back substitute row 1 */ s = 1.0f / r1[1]; r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); m0 = r0[2]; r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; m0 = r0[1]; /* now back substitute row 0 */ s = 1.0f / r0[0]; r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); MAT (out, 0, 0) = r0[4]; MAT (out, 0, 1) = r0[5], MAT (out, 0, 2) = r0[6]; MAT (out, 0, 3) = r0[7], MAT (out, 1, 0) = r1[4]; MAT (out, 1, 1) = r1[5], MAT (out, 1, 2) = r1[6]; MAT (out, 1, 3) = r1[7], MAT (out, 2, 0) = r2[4]; MAT (out, 2, 1) = r2[5], MAT (out, 2, 2) = r2[6]; MAT (out, 2, 3) = r2[7], MAT (out, 3, 0) = r3[4]; MAT (out, 3, 1) = r3[5], MAT (out, 3, 2) = r3[6]; MAT (out, 3, 3) = r3[7]; return TRUE; } #undef SWAP_ROWS /* * Compute inverse of a general 3d transformation matrix. * * @mat pointer to a CoglMatrix structure. The matrix inverse will be * stored in the CoglMatrix::inv attribute. * * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). * * \author Adapted from graphics gems II. * * Calculates the inverse of the upper left by first calculating its * determinant and multiplying it to the symmetric adjust matrix of each * element. Finally deals with the translation part by transforming the * original translation vector using by the calculated submatrix inverse. */ static CoglBool invert_matrix_3d_general (CoglMatrix *matrix) { const float *in = (float *)matrix; float *out = matrix->inv; float pos, neg, t; float det; /* Calculate the determinant of upper left 3x3 submatrix and * determine if the matrix is singular. */ pos = neg = 0.0; t = MAT (in,0,0) * MAT (in,1,1) * MAT (in,2,2); if (t >= 0.0) pos += t; else neg += t; t = MAT (in,1,0) * MAT (in,2,1) * MAT (in,0,2); if (t >= 0.0) pos += t; else neg += t; t = MAT (in,2,0) * MAT (in,0,1) * MAT (in,1,2); if (t >= 0.0) pos += t; else neg += t; t = -MAT (in,2,0) * MAT (in,1,1) * MAT (in,0,2); if (t >= 0.0) pos += t; else neg += t; t = -MAT (in,1,0) * MAT (in,0,1) * MAT (in,2,2); if (t >= 0.0) pos += t; else neg += t; t = -MAT (in,0,0) * MAT (in,2,1) * MAT (in,1,2); if (t >= 0.0) pos += t; else neg += t; det = pos + neg; if (det*det < 1e-25) return FALSE; det = 1.0f / det; MAT (out,0,0) = ( (MAT (in, 1, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 1, 2) )*det); MAT (out,0,1) = (- (MAT (in, 0, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 0, 2) )*det); MAT (out,0,2) = ( (MAT (in, 0, 1)*MAT (in, 1, 2) - MAT (in, 1, 1)*MAT (in, 0, 2) )*det); MAT (out,1,0) = (- (MAT (in,1,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,1,2) )*det); MAT (out,1,1) = ( (MAT (in,0,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,0,2) )*det); MAT (out,1,2) = (- (MAT (in,0,0)*MAT (in,1,2) - MAT (in,1,0)*MAT (in,0,2) )*det); MAT (out,2,0) = ( (MAT (in,1,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,1,1) )*det); MAT (out,2,1) = (- (MAT (in,0,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,0,1) )*det); MAT (out,2,2) = ( (MAT (in,0,0)*MAT (in,1,1) - MAT (in,1,0)*MAT (in,0,1) )*det); /* Do the translation part */ MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) + MAT (in, 1, 3) * MAT (out, 0, 1) + MAT (in, 2, 3) * MAT (out, 0, 2) ); MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) + MAT (in, 1, 3) * MAT (out, 1, 1) + MAT (in, 2, 3) * MAT (out, 1, 2) ); MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2 ,0) + MAT (in, 1, 3) * MAT (out, 2, 1) + MAT (in, 2, 3) * MAT (out, 2, 2) ); return TRUE; } /* * Compute inverse of a 3d transformation matrix. * * @mat pointer to a CoglMatrix structure. The matrix inverse will be * stored in the CoglMatrix::inv attribute. * * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). * * If the matrix is not an angle preserving matrix then calls * invert_matrix_3d_general for the actual calculation. Otherwise calculates * the inverse matrix analyzing and inverting each of the scaling, rotation and * translation parts. */ static CoglBool invert_matrix_3d (CoglMatrix *matrix) { const float *in = (float *)matrix; float *out = matrix->inv; memcpy (out, identity, 16 * sizeof (float)); if (!TEST_MAT_FLAGS(matrix, MAT_FLAGS_ANGLE_PRESERVING)) return invert_matrix_3d_general (matrix); if (matrix->flags & MAT_FLAG_UNIFORM_SCALE) { float scale = (MAT (in, 0, 0) * MAT (in, 0, 0) + MAT (in, 0, 1) * MAT (in, 0, 1) + MAT (in, 0, 2) * MAT (in, 0, 2)); if (scale == 0.0) return FALSE; scale = 1.0f / scale; /* Transpose and scale the 3 by 3 upper-left submatrix. */ MAT (out, 0, 0) = scale * MAT (in, 0, 0); MAT (out, 1, 0) = scale * MAT (in, 0, 1); MAT (out, 2, 0) = scale * MAT (in, 0, 2); MAT (out, 0, 1) = scale * MAT (in, 1, 0); MAT (out, 1, 1) = scale * MAT (in, 1, 1); MAT (out, 2, 1) = scale * MAT (in, 1, 2); MAT (out, 0, 2) = scale * MAT (in, 2, 0); MAT (out, 1, 2) = scale * MAT (in, 2, 1); MAT (out, 2, 2) = scale * MAT (in, 2, 2); } else if (matrix->flags & MAT_FLAG_ROTATION) { /* Transpose the 3 by 3 upper-left submatrix. */ MAT (out, 0, 0) = MAT (in, 0, 0); MAT (out, 1, 0) = MAT (in, 0, 1); MAT (out, 2, 0) = MAT (in, 0, 2); MAT (out, 0, 1) = MAT (in, 1, 0); MAT (out, 1, 1) = MAT (in, 1, 1); MAT (out, 2, 1) = MAT (in, 1, 2); MAT (out, 0, 2) = MAT (in, 2, 0); MAT (out, 1, 2) = MAT (in, 2, 1); MAT (out, 2, 2) = MAT (in, 2, 2); } else { /* pure translation */ memcpy (out, identity, 16 * sizeof (float)); MAT (out, 0, 3) = - MAT (in, 0, 3); MAT (out, 1, 3) = - MAT (in, 1, 3); MAT (out, 2, 3) = - MAT (in, 2, 3); return TRUE; } if (matrix->flags & MAT_FLAG_TRANSLATION) { /* Do the translation part */ MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) + MAT (in, 1, 3) * MAT (out, 0, 1) + MAT (in, 2, 3) * MAT (out, 0, 2) ); MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) + MAT (in, 1, 3) * MAT (out, 1, 1) + MAT (in, 2, 3) * MAT (out, 1, 2) ); MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2, 0) + MAT (in, 1, 3) * MAT (out, 2, 1) + MAT (in, 2, 3) * MAT (out, 2, 2) ); } else MAT (out, 0, 3) = MAT (out, 1, 3) = MAT (out, 2, 3) = 0.0; return TRUE; } /* * Compute inverse of an identity transformation matrix. * * @mat pointer to a CoglMatrix structure. The matrix inverse will be * stored in the CoglMatrix::inv attribute. * * Returns: always %TRUE. * * Simply copies identity into CoglMatrix::inv. */ static CoglBool invert_matrix_identity (CoglMatrix *matrix) { memcpy (matrix->inv, identity, 16 * sizeof (float)); return TRUE; } /* * Compute inverse of a no-rotation 3d transformation matrix. * * @mat pointer to a CoglMatrix structure. The matrix inverse will be * stored in the CoglMatrix::inv attribute. * * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). * * Calculates the */ static CoglBool invert_matrix_3d_no_rotation (CoglMatrix *matrix) { const float *in = (float *)matrix; float *out = matrix->inv; if (MAT (in,0,0) == 0 || MAT (in,1,1) == 0 || MAT (in,2,2) == 0) return FALSE; memcpy (out, identity, 16 * sizeof (float)); MAT (out,0,0) = 1.0f / MAT (in,0,0); MAT (out,1,1) = 1.0f / MAT (in,1,1); MAT (out,2,2) = 1.0f / MAT (in,2,2); if (matrix->flags & MAT_FLAG_TRANSLATION) { MAT (out,0,3) = - (MAT (in,0,3) * MAT (out,0,0)); MAT (out,1,3) = - (MAT (in,1,3) * MAT (out,1,1)); MAT (out,2,3) = - (MAT (in,2,3) * MAT (out,2,2)); } return TRUE; } /* * Compute inverse of a no-rotation 2d transformation matrix. * * @mat pointer to a CoglMatrix structure. The matrix inverse will be * stored in the CoglMatrix::inv attribute. * * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). * * Calculates the inverse matrix by applying the inverse scaling and * translation to the identity matrix. */ static CoglBool invert_matrix_2d_no_rotation (CoglMatrix *matrix) { const float *in = (float *)matrix; float *out = matrix->inv; if (MAT (in, 0, 0) == 0 || MAT (in, 1, 1) == 0) return FALSE; memcpy (out, identity, 16 * sizeof (float)); MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0); MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1); if (matrix->flags & MAT_FLAG_TRANSLATION) { MAT (out, 0, 3) = - (MAT (in, 0, 3) * MAT (out, 0, 0)); MAT (out, 1, 3) = - (MAT (in, 1, 3) * MAT (out, 1, 1)); } return TRUE; } #if 0 /* broken */ static CoglBool invert_matrix_perspective (CoglMatrix *matrix) { const float *in = matrix; float *out = matrix->inv; if (MAT (in,2,3) == 0) return FALSE; memcpy( out, identity, 16 * sizeof(float) ); MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0); MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1); MAT (out, 0, 3) = MAT (in, 0, 2); MAT (out, 1, 3) = MAT (in, 1, 2); MAT (out,2,2) = 0; MAT (out,2,3) = -1; MAT (out,3,2) = 1.0f / MAT (in,2,3); MAT (out,3,3) = MAT (in,2,2) * MAT (out,3,2); return TRUE; } #endif /* * Matrix inversion function pointer type. */ typedef CoglBool (*inv_mat_func)(CoglMatrix *matrix); /* * Table of the matrix inversion functions according to the matrix type. */ static inv_mat_func inv_mat_tab[7] = { invert_matrix_general, invert_matrix_identity, invert_matrix_3d_no_rotation, #if 0 /* Don't use this function for now - it fails when the projection matrix * is premultiplied by a translation (ala Chromium's tilesort SPU). */ invert_matrix_perspective, #else invert_matrix_general, #endif invert_matrix_3d, /* lazy! */ invert_matrix_2d_no_rotation, invert_matrix_3d }; #define ZERO(x) (1<flags &= ~MAT_FLAGS_GEOMETRY; /* Check for translation - no-one really cares */ if ((mask & MASK_NO_TRX) != MASK_NO_TRX) matrix->flags |= MAT_FLAG_TRANSLATION; /* Do the real work */ if (mask == (unsigned int) MASK_IDENTITY) matrix->type = COGL_MATRIX_TYPE_IDENTITY; else if ((mask & MASK_2D_NO_ROT) == (unsigned int) MASK_2D_NO_ROT) { matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT; if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE) matrix->flags |= MAT_FLAG_GENERAL_SCALE; } else if ((mask & MASK_2D) == (unsigned int) MASK_2D) { float mm = DOT2 (m, m); float m4m4 = DOT2 (m+4,m+4); float mm4 = DOT2 (m,m+4); matrix->type = COGL_MATRIX_TYPE_2D; /* Check for scale */ if (SQ (mm-1) > SQ (1e-6) || SQ (m4m4-1) > SQ (1e-6)) matrix->flags |= MAT_FLAG_GENERAL_SCALE; /* Check for rotation */ if (SQ (mm4) > SQ (1e-6)) matrix->flags |= MAT_FLAG_GENERAL_3D; else matrix->flags |= MAT_FLAG_ROTATION; } else if ((mask & MASK_3D_NO_ROT) == (unsigned int) MASK_3D_NO_ROT) { matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; /* Check for scale */ if (SQ (m[0]-m[5]) < SQ (1e-6) && SQ (m[0]-m[10]) < SQ (1e-6)) { if (SQ (m[0]-1.0) > SQ (1e-6)) matrix->flags |= MAT_FLAG_UNIFORM_SCALE; } else matrix->flags |= MAT_FLAG_GENERAL_SCALE; } else if ((mask & MASK_3D) == (unsigned int) MASK_3D) { float c1 = DOT3 (m,m); float c2 = DOT3 (m+4,m+4); float c3 = DOT3 (m+8,m+8); float d1 = DOT3 (m, m+4); float cp[3]; matrix->type = COGL_MATRIX_TYPE_3D; /* Check for scale */ if (SQ (c1-c2) < SQ (1e-6) && SQ (c1-c3) < SQ (1e-6)) { if (SQ (c1-1.0) > SQ (1e-6)) matrix->flags |= MAT_FLAG_UNIFORM_SCALE; /* else no scale at all */ } else matrix->flags |= MAT_FLAG_GENERAL_SCALE; /* Check for rotation */ if (SQ (d1) < SQ (1e-6)) { CROSS3 ( cp, m, m+4); SUB_3V ( cp, cp, (m+8)); if (LEN_SQUARED_3FV(cp) < SQ(1e-6)) matrix->flags |= MAT_FLAG_ROTATION; else matrix->flags |= MAT_FLAG_GENERAL_3D; } else matrix->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */ } else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0f) { matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE; matrix->flags |= MAT_FLAG_GENERAL; } else { matrix->type = COGL_MATRIX_TYPE_GENERAL; matrix->flags |= MAT_FLAG_GENERAL; } } /* * Analyze a matrix given that its flags are accurate. * * This is the more common operation, hopefully. */ static void analyse_from_flags (CoglMatrix *matrix) { const float *m = (float *)matrix; if (TEST_MAT_FLAGS(matrix, 0)) matrix->type = COGL_MATRIX_TYPE_IDENTITY; else if (TEST_MAT_FLAGS(matrix, (MAT_FLAG_TRANSLATION | MAT_FLAG_UNIFORM_SCALE | MAT_FLAG_GENERAL_SCALE))) { if ( m[10] == 1.0f && m[14] == 0.0f ) matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT; else matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; } else if (TEST_MAT_FLAGS (matrix, MAT_FLAGS_3D)) { if ( m[ 8]==0.0f && m[ 9]==0.0f && m[2]==0.0f && m[6]==0.0f && m[10]==1.0f && m[14]==0.0f) { matrix->type = COGL_MATRIX_TYPE_2D; } else matrix->type = COGL_MATRIX_TYPE_3D; } else if ( m[4]==0.0f && m[12]==0.0f && m[1]==0.0f && m[13]==0.0f && m[2]==0.0f && m[6]==0.0f && m[3]==0.0f && m[7]==0.0f && m[11]==-1.0f && m[15]==0.0f) { matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE; } else matrix->type = COGL_MATRIX_TYPE_GENERAL; } /* * Analyze and update the type and flags of a matrix. * * If the matrix type is dirty then calls either analyse_from_scratch() or * analyse_from_flags() to determine its type, according to whether the flags * are dirty or not, respectively. If the matrix has an inverse and it's dirty * then calls matrix_invert(). Finally clears the dirty flags. */ static void _cogl_matrix_update_type_and_flags (CoglMatrix *matrix) { if (matrix->flags & MAT_DIRTY_TYPE) { if (matrix->flags & MAT_DIRTY_FLAGS) analyse_from_scratch (matrix); else analyse_from_flags (matrix); } matrix->flags &= ~(MAT_DIRTY_FLAGS | MAT_DIRTY_TYPE); } /* * Compute inverse of a transformation matrix. * * @mat pointer to a CoglMatrix structure. The matrix inverse will be * stored in the CoglMatrix::inv attribute. * * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). * * Calls the matrix inversion function in inv_mat_tab corresponding to the * given matrix type. In case of failure, updates the MAT_FLAG_SINGULAR flag, * and copies the identity matrix into CoglMatrix::inv. */ static CoglBool _cogl_matrix_update_inverse (CoglMatrix *matrix) { if (matrix->flags & MAT_DIRTY_FLAGS || matrix->flags & MAT_DIRTY_INVERSE) { _cogl_matrix_update_type_and_flags (matrix); if (inv_mat_tab[matrix->type](matrix)) matrix->flags &= ~MAT_FLAG_SINGULAR; else { matrix->flags |= MAT_FLAG_SINGULAR; memcpy (matrix->inv, identity, 16 * sizeof (float)); } matrix->flags &= ~MAT_DIRTY_INVERSE; } if (matrix->flags & MAT_FLAG_SINGULAR) return FALSE; else return TRUE; } CoglBool cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse) { if (_cogl_matrix_update_inverse ((CoglMatrix *)matrix)) { cogl_matrix_init_from_array (inverse, matrix->inv); return TRUE; } else { cogl_matrix_init_identity (inverse); return FALSE; } } /* * Generate a 4x4 transformation matrix from glRotate parameters, and * post-multiply the input matrix by it. * * \author * This function was contributed by Erich Boleyn (erich@uruk.org). * Optimizations contributed by Rudolf Opalla (rudi@khm.de). */ static void _cogl_matrix_rotate (CoglMatrix *matrix, float angle, float x, float y, float z) { float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c; float m[16]; CoglBool optimized; s = sinf (angle * DEG2RAD); c = cosf (angle * DEG2RAD); memcpy (m, identity, 16 * sizeof (float)); optimized = FALSE; #define M(row,col) m[col*4+row] if (x == 0.0f) { if (y == 0.0f) { if (z != 0.0f) { optimized = TRUE; /* rotate only around z-axis */ M (0,0) = c; M (1,1) = c; if (z < 0.0f) { M (0,1) = s; M (1,0) = -s; } else { M (0,1) = -s; M (1,0) = s; } } } else if (z == 0.0f) { optimized = TRUE; /* rotate only around y-axis */ M (0,0) = c; M (2,2) = c; if (y < 0.0f) { M (0,2) = -s; M (2,0) = s; } else { M (0,2) = s; M (2,0) = -s; } } } else if (y == 0.0f) { if (z == 0.0f) { optimized = TRUE; /* rotate only around x-axis */ M (1,1) = c; M (2,2) = c; if (x < 0.0f) { M (1,2) = s; M (2,1) = -s; } else { M (1,2) = -s; M (2,1) = s; } } } if (!optimized) { const float mag = sqrtf (x * x + y * y + z * z); if (mag <= 1.0e-4) { /* no rotation, leave mat as-is */ return; } x /= mag; y /= mag; z /= mag; /* * Arbitrary axis rotation matrix. * * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation * (which is about the X-axis), and the two composite transforms * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary * from the arbitrary axis to the X-axis then back. They are * all elementary rotations. * * Rz' is a rotation about the Z-axis, to bring the axis vector * into the x-z plane. Then Ry' is applied, rotating about the * Y-axis to bring the axis vector parallel with the X-axis. The * rotation about the X-axis is then performed. Ry and Rz are * simply the respective inverse transforms to bring the arbitrary * axis back to it's original orientation. The first transforms * Rz' and Ry' are considered inverses, since the data from the * arbitrary axis gives you info on how to get to it, not how * to get away from it, and an inverse must be applied. * * The basic calculation used is to recognize that the arbitrary * axis vector (x, y, z), since it is of unit length, actually * represents the sines and cosines of the angles to rotate the * X-axis to the same orientation, with theta being the angle about * Z and phi the angle about Y (in the order described above) * as follows: * * cos ( theta ) = x / sqrt ( 1 - z^2 ) * sin ( theta ) = y / sqrt ( 1 - z^2 ) * * cos ( phi ) = sqrt ( 1 - z^2 ) * sin ( phi ) = z * * Note that cos ( phi ) can further be inserted to the above * formulas: * * cos ( theta ) = x / cos ( phi ) * sin ( theta ) = y / sin ( phi ) * * ...etc. Because of those relations and the standard trigonometric * relations, it is pssible to reduce the transforms down to what * is used below. It may be that any primary axis chosen will give the * same results (modulo a sign convention) using thie method. * * Particularly nice is to notice that all divisions that might * have caused trouble when parallel to certain planes or * axis go away with care paid to reducing the expressions. * After checking, it does perform correctly under all cases, since * in all the cases of division where the denominator would have * been zero, the numerator would have been zero as well, giving * the expected result. */ xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; one_c = 1.0f - c; /* We already hold the identity-matrix so we can skip some statements */ M (0,0) = (one_c * xx) + c; M (0,1) = (one_c * xy) - zs; M (0,2) = (one_c * zx) + ys; /* M (0,3) = 0.0f; */ M (1,0) = (one_c * xy) + zs; M (1,1) = (one_c * yy) + c; M (1,2) = (one_c * yz) - xs; /* M (1,3) = 0.0f; */ M (2,0) = (one_c * zx) - ys; M (2,1) = (one_c * yz) + xs; M (2,2) = (one_c * zz) + c; /* M (2,3) = 0.0f; */ /* M (3,0) = 0.0f; M (3,1) = 0.0f; M (3,2) = 0.0f; M (3,3) = 1.0f; */ } #undef M matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_ROTATION); } void cogl_matrix_rotate (CoglMatrix *matrix, float angle, float x, float y, float z) { _cogl_matrix_rotate (matrix, angle, x, y, z); _COGL_MATRIX_DEBUG_PRINT (matrix); } void cogl_matrix_rotate_quaternion (CoglMatrix *matrix, const CoglQuaternion *quaternion) { CoglMatrix rotation_transform; cogl_matrix_init_from_quaternion (&rotation_transform, quaternion); cogl_matrix_multiply (matrix, matrix, &rotation_transform); } void cogl_matrix_rotate_euler (CoglMatrix *matrix, const CoglEuler *euler) { CoglMatrix rotation_transform; cogl_matrix_init_from_euler (&rotation_transform, euler); cogl_matrix_multiply (matrix, matrix, &rotation_transform); } /* * Apply a perspective projection matrix. * * Creates the projection matrix and multiplies it with matrix, marking the * MAT_FLAG_PERSPECTIVE flag. */ static void _cogl_matrix_frustum (CoglMatrix *matrix, float left, float right, float bottom, float top, float nearval, float farval) { float x, y, a, b, c, d; float m[16]; x = (2.0f * nearval) / (right - left); y = (2.0f * nearval) / (top - bottom); a = (right + left) / (right - left); b = (top + bottom) / (top - bottom); c = -(farval + nearval) / ( farval - nearval); d = -(2.0f * farval * nearval) / (farval - nearval); /* error? */ #define M(row,col) m[col*4+row] M (0,0) = x; M (0,1) = 0.0f; M (0,2) = a; M (0,3) = 0.0f; M (1,0) = 0.0f; M (1,1) = y; M (1,2) = b; M (1,3) = 0.0f; M (2,0) = 0.0f; M (2,1) = 0.0f; M (2,2) = c; M (2,3) = d; M (3,0) = 0.0f; M (3,1) = 0.0f; M (3,2) = -1.0f; M (3,3) = 0.0f; #undef M matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_PERSPECTIVE); } void cogl_matrix_frustum (CoglMatrix *matrix, float left, float right, float bottom, float top, float z_near, float z_far) { _cogl_matrix_frustum (matrix, left, right, bottom, top, z_near, z_far); _COGL_MATRIX_DEBUG_PRINT (matrix); } void cogl_matrix_perspective (CoglMatrix *matrix, float fov_y, float aspect, float z_near, float z_far) { float ymax = z_near * tan (fov_y * G_PI / 360.0); cogl_matrix_frustum (matrix, -ymax * aspect, /* left */ ymax * aspect, /* right */ -ymax, /* bottom */ ymax, /* top */ z_near, z_far); _COGL_MATRIX_DEBUG_PRINT (matrix); } /* * Apply an orthographic projection matrix. * * Creates the projection matrix and multiplies it with matrix, marking the * MAT_FLAG_GENERAL_SCALE and MAT_FLAG_TRANSLATION flags. */ static void _cogl_matrix_orthographic (CoglMatrix *matrix, float x_1, float y_1, float x_2, float y_2, float nearval, float farval) { float m[16]; #define M(row, col) m[col * 4 + row] M (0,0) = 2.0f / (x_2 - x_1); M (0,1) = 0.0f; M (0,2) = 0.0f; M (0,3) = -(x_2 + x_1) / (x_2 - x_1); M (1,0) = 0.0f; M (1,1) = 2.0f / (y_1 - y_2); M (1,2) = 0.0f; M (1,3) = -(y_1 + y_2) / (y_1 - y_2); M (2,0) = 0.0f; M (2,1) = 0.0f; M (2,2) = -2.0f / (farval - nearval); M (2,3) = -(farval + nearval) / (farval - nearval); M (3,0) = 0.0f; M (3,1) = 0.0f; M (3,2) = 0.0f; M (3,3) = 1.0f; #undef M matrix_multiply_array_with_flags (matrix, m, (MAT_FLAG_GENERAL_SCALE | MAT_FLAG_TRANSLATION)); } void cogl_matrix_ortho (CoglMatrix *matrix, float left, float right, float bottom, float top, float near, float far) { _cogl_matrix_orthographic (matrix, left, top, right, bottom, near, far); _COGL_MATRIX_DEBUG_PRINT (matrix); } void cogl_matrix_orthographic (CoglMatrix *matrix, float x_1, float y_1, float x_2, float y_2, float near, float far) { _cogl_matrix_orthographic (matrix, x_1, y_1, x_2, y_2, near, far); _COGL_MATRIX_DEBUG_PRINT (matrix); } /* * Multiply a matrix with a general scaling matrix. * * Multiplies in-place the elements of matrix by the scale factors. Checks if * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and * MAT_DIRTY_INVERSE dirty flags. */ static void _cogl_matrix_scale (CoglMatrix *matrix, float x, float y, float z) { float *m = (float *)matrix; m[0] *= x; m[4] *= y; m[8] *= z; m[1] *= x; m[5] *= y; m[9] *= z; m[2] *= x; m[6] *= y; m[10] *= z; m[3] *= x; m[7] *= y; m[11] *= z; if (fabsf (x - y) < 1e-8 && fabsf (x - z) < 1e-8) matrix->flags |= MAT_FLAG_UNIFORM_SCALE; else matrix->flags |= MAT_FLAG_GENERAL_SCALE; matrix->flags |= (MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); } void cogl_matrix_scale (CoglMatrix *matrix, float sx, float sy, float sz) { _cogl_matrix_scale (matrix, sx, sy, sz); _COGL_MATRIX_DEBUG_PRINT (matrix); } /* * Multiply a matrix with a translation matrix. * * Adds the translation coordinates to the elements of matrix in-place. Marks * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE * dirty flags. */ static void _cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z) { float *m = (float *)matrix; m[12] = m[0] * x + m[4] * y + m[8] * z + m[12]; m[13] = m[1] * x + m[5] * y + m[9] * z + m[13]; m[14] = m[2] * x + m[6] * y + m[10] * z + m[14]; m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; matrix->flags |= (MAT_FLAG_TRANSLATION | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); } void cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z) { _cogl_matrix_translate (matrix, x, y, z); _COGL_MATRIX_DEBUG_PRINT (matrix); } #if 0 /* * Set matrix to do viewport and depthrange mapping. * Transforms Normalized Device Coords to window/Z values. */ static void _cogl_matrix_viewport (CoglMatrix *matrix, float x, float y, float width, float height, float zNear, float zFar, float depthMax) { float *m = (float *)matrix; m[MAT_SX] = width / 2.0f; m[MAT_TX] = m[MAT_SX] + x; m[MAT_SY] = height / 2.0f; m[MAT_TY] = m[MAT_SY] + y; m[MAT_SZ] = depthMax * ((zFar - zNear) / 2.0f); m[MAT_TZ] = depthMax * ((zFar - zNear) / 2.0f + zNear); matrix->flags = MAT_FLAG_GENERAL_SCALE | MAT_FLAG_TRANSLATION; matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; } #endif /* * Set a matrix to the identity matrix. * * @mat matrix. * * Copies ::identity into \p CoglMatrix::m, and into CoglMatrix::inv if * not NULL. Sets the matrix type to identity, resets the flags. It * doesn't initialize the inverse matrix, it just marks it dirty. */ static void _cogl_matrix_init_identity (CoglMatrix *matrix) { memcpy (matrix, identity, 16 * sizeof (float)); matrix->type = COGL_MATRIX_TYPE_IDENTITY; matrix->flags = MAT_DIRTY_INVERSE; } void cogl_matrix_init_identity (CoglMatrix *matrix) { _cogl_matrix_init_identity (matrix); _COGL_MATRIX_DEBUG_PRINT (matrix); } /* * Set a matrix to the (tx, ty, tz) translation matrix. * * @matix matrix. * @tx x coordinate of the translation vector * @ty y coordinate of the translation vector * @tz z coordinate of the translation vector */ static void _cogl_matrix_init_translation (CoglMatrix *matrix, float tx, float ty, float tz) { memcpy (matrix, identity, 16 * sizeof (float)); matrix->xw = tx; matrix->yw = ty; matrix->zw = tz; matrix->type = COGL_MATRIX_TYPE_3D; matrix->flags = MAT_FLAG_TRANSLATION | MAT_DIRTY_INVERSE; } void cogl_matrix_init_translation (CoglMatrix *matrix, float tx, float ty, float tz) { _cogl_matrix_init_translation (matrix, tx, ty, tz); _COGL_MATRIX_DEBUG_PRINT (matrix); } #if 0 /* * Test if the given matrix preserves vector lengths. */ static CoglBool _cogl_matrix_is_length_preserving (const CoglMatrix *m) { return TEST_MAT_FLAGS (m, MAT_FLAGS_LENGTH_PRESERVING); } /* * Test if the given matrix does any rotation. * (or perhaps if the upper-left 3x3 is non-identity) */ static CoglBool _cogl_matrix_has_rotation (const CoglMatrix *matrix) { if (matrix->flags & (MAT_FLAG_GENERAL | MAT_FLAG_ROTATION | MAT_FLAG_GENERAL_3D | MAT_FLAG_PERSPECTIVE)) return TRUE; else return FALSE; } static CoglBool _cogl_matrix_is_general_scale (const CoglMatrix *matrix) { return (matrix->flags & MAT_FLAG_GENERAL_SCALE) ? TRUE : FALSE; } static CoglBool _cogl_matrix_is_dirty (const CoglMatrix *matrix) { return (matrix->flags & MAT_DIRTY_ALL) ? TRUE : FALSE; } #endif /* * Loads a matrix array into CoglMatrix. * * @m matrix array. * @mat matrix. * * Copies \p m into CoglMatrix::m and marks the MAT_FLAG_GENERAL and * MAT_DIRTY_ALL * flags. */ static void _cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) { memcpy (matrix, array, 16 * sizeof (float)); matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL); } void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) { _cogl_matrix_init_from_array (matrix, array); _COGL_MATRIX_DEBUG_PRINT (matrix); } void _cogl_matrix_init_from_matrix_without_inverse (CoglMatrix *matrix, const CoglMatrix *src) { memcpy (matrix, src, 16 * sizeof (float)); matrix->type = src->type; matrix->flags = src->flags | MAT_DIRTY_INVERSE; } static void _cogl_matrix_init_from_quaternion (CoglMatrix *matrix, const CoglQuaternion *quaternion) { float qnorm = _COGL_QUATERNION_NORM (quaternion); float s = (qnorm > 0.0f) ? (2.0f / qnorm) : 0.0f; float xs = quaternion->x * s; float ys = quaternion->y * s; float zs = quaternion->z * s; float wx = quaternion->w * xs; float wy = quaternion->w * ys; float wz = quaternion->w * zs; float xx = quaternion->x * xs; float xy = quaternion->x * ys; float xz = quaternion->x * zs; float yy = quaternion->y * ys; float yz = quaternion->y * zs; float zz = quaternion->z * zs; matrix->xx = 1.0f - (yy + zz); matrix->yx = xy + wz; matrix->zx = xz - wy; matrix->xy = xy - wz; matrix->yy = 1.0f - (xx + zz); matrix->zy = yz + wx; matrix->xz = xz + wy; matrix->yz = yz - wx; matrix->zz = 1.0f - (xx + yy); matrix->xw = matrix->yw = matrix->zw = 0.0f; matrix->wx = matrix->wy = matrix->wz = 0.0f; matrix->ww = 1.0f; matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL); } void cogl_matrix_init_from_quaternion (CoglMatrix *matrix, const CoglQuaternion *quaternion) { _cogl_matrix_init_from_quaternion (matrix, quaternion); } void cogl_matrix_init_from_euler (CoglMatrix *matrix, const CoglEuler *euler) { /* Convert angles to radians */ float heading_rad = euler->heading / 180.0f * G_PI; float pitch_rad = euler->pitch / 180.0f * G_PI; float roll_rad = euler->roll / 180.0f * G_PI; /* Pre-calculate the sin and cos */ float sin_heading = sinf (heading_rad); float cos_heading = cosf (heading_rad); float sin_pitch = sinf (pitch_rad); float cos_pitch = cosf (pitch_rad); float sin_roll = sinf (roll_rad); float cos_roll = cosf (roll_rad); /* These calculations are based on the following website but they * use a different order for the rotations so it has been modified * slightly. * http://www.euclideanspace.com/maths/geometry/ * rotations/conversions/eulerToMatrix/index.htm */ /* Heading rotation x=0, y=1, z=0 gives: * * [ ch 0 sh 0 ] * [ 0 1 0 0 ] * [ -sh 0 ch 0 ] * [ 0 0 0 1 ] * * Pitch rotation x=1, y=0, z=0 gives: * [ 1 0 0 0 ] * [ 0 cp -sp 0 ] * [ 0 sp cp 0 ] * [ 0 0 0 1 ] * * Roll rotation x=0, y=0, z=1 gives: * [ cr -sr 0 0 ] * [ sr cr 0 0 ] * [ 0 0 1 0 ] * [ 0 0 0 1 ] * * Heading matrix * pitch matrix = * [ ch sh*sp cp*sh 0 ] * [ 0 cp -sp 0 ] * [ -sh ch*sp ch*cp 0 ] * [ 0 0 0 1 ] * * That matrix * roll matrix = * [ ch*cr + sh*sp*sr sh*sp*cr - ch*sr sh*cp 0 ] * [ cp*sr cp*cr -sp 0 ] * [ ch*sp*sr - sh*cr sh*sr + ch*sp*cr ch*cp 0 ] * [ 0 0 0 1 ] */ matrix->xx = cos_heading * cos_roll + sin_heading * sin_pitch * sin_roll; matrix->yx = cos_pitch * sin_roll; matrix->zx = cos_heading * sin_pitch * sin_roll - sin_heading * cos_roll; matrix->wx = 0.0f; matrix->xy = sin_heading * sin_pitch * cos_roll - cos_heading * sin_roll; matrix->yy = cos_pitch * cos_roll; matrix->zy = sin_heading * sin_roll + cos_heading * sin_pitch * cos_roll; matrix->wy = 0.0f; matrix->xz = sin_heading * cos_pitch; matrix->yz = -sin_pitch; matrix->zz = cos_heading * cos_pitch; matrix->wz = 0; matrix->xw = 0; matrix->yw = 0; matrix->zw = 0; matrix->ww = 1; matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL); } /* * Transpose a float matrix. */ static void _cogl_matrix_util_transposef (float to[16], const float from[16]) { to[0] = from[0]; to[1] = from[4]; to[2] = from[8]; to[3] = from[12]; to[4] = from[1]; to[5] = from[5]; to[6] = from[9]; to[7] = from[13]; to[8] = from[2]; to[9] = from[6]; to[10] = from[10]; to[11] = from[14]; to[12] = from[3]; to[13] = from[7]; to[14] = from[11]; to[15] = from[15]; } void cogl_matrix_view_2d_in_frustum (CoglMatrix *matrix, float left, float right, float bottom, float top, float z_near, float z_2d, float width_2d, float height_2d) { float left_2d_plane = left / z_near * z_2d; float right_2d_plane = right / z_near * z_2d; float bottom_2d_plane = bottom / z_near * z_2d; float top_2d_plane = top / z_near * z_2d; float width_2d_start = right_2d_plane - left_2d_plane; float height_2d_start = top_2d_plane - bottom_2d_plane; /* Factors to scale from framebuffer geometry to frustum * cross-section geometry. */ float width_scale = width_2d_start / width_2d; float height_scale = height_2d_start / height_2d; cogl_matrix_translate (matrix, left_2d_plane, top_2d_plane, -z_2d); cogl_matrix_scale (matrix, width_scale, -height_scale, width_scale); } /* Assuming a symmetric perspective matrix is being used for your * projective transform this convenience function lets you compose a * view transform such that geometry on the z=0 plane will map to * screen coordinates with a top left origin of (0,0) and with the * given width and height. */ void cogl_matrix_view_2d_in_perspective (CoglMatrix *matrix, float fov_y, float aspect, float z_near, float z_2d, float width_2d, float height_2d) { float top = z_near * tan (fov_y * G_PI / 360.0); cogl_matrix_view_2d_in_frustum (matrix, -top * aspect, top * aspect, -top, top, z_near, z_2d, width_2d, height_2d); } CoglBool cogl_matrix_equal (const void *v1, const void *v2) { const CoglMatrix *a = v1; const CoglMatrix *b = v2; _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE); _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE); /* We want to avoid having a fuzzy _equal() function (e.g. that uses * an arbitrary epsilon value) since this function noteably conforms * to the prototype suitable for use with g_hash_table_new() and a * fuzzy hash function isn't really appropriate for comparing hash * table keys since it's possible that you could end up fetching * different values if you end up with multiple similar keys in use * at the same time. If you consider that fuzzyness allows cases * such as A == B == C but A != C then you could also end up loosing * values in a hash table. * * We do at least use the == operator to compare values though so * that -0 is considered equal to 0. */ /* XXX: We don't compare the flags, inverse matrix or padding */ if (a->xx == b->xx && a->xy == b->xy && a->xz == b->xz && a->xw == b->xw && a->yx == b->yx && a->yy == b->yy && a->yz == b->yz && a->yw == b->yw && a->zx == b->zx && a->zy == b->zy && a->zz == b->zz && a->zw == b->zw && a->wx == b->wx && a->wy == b->wy && a->wz == b->wz && a->ww == b->ww) return TRUE; else return FALSE; } CoglMatrix * cogl_matrix_copy (const CoglMatrix *matrix) { if (G_LIKELY (matrix)) return g_slice_dup (CoglMatrix, matrix); return NULL; } void cogl_matrix_free (CoglMatrix *matrix) { g_slice_free (CoglMatrix, matrix); } const float * cogl_matrix_get_array (const CoglMatrix *matrix) { return (float *)matrix; } void cogl_matrix_transform_point (const CoglMatrix *matrix, float *x, float *y, float *z, float *w) { float _x = *x, _y = *y, _z = *z, _w = *w; *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w; *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w; *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w; *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w; } typedef struct _Point2f { float x; float y; } Point2f; typedef struct _Point3f { float x; float y; float z; } Point3f; typedef struct _Point4f { float x; float y; float z; float w; } Point4f; static void _cogl_matrix_transform_points_f2 (const CoglMatrix *matrix, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points) { int i; for (i = 0; i < n_points; i++) { Point2f p = *(Point2f *)((uint8_t *)points_in + i * stride_in); Point3f *o = (Point3f *)((uint8_t *)points_out + i * stride_out); o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xw; o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yw; o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zw; } } static void _cogl_matrix_project_points_f2 (const CoglMatrix *matrix, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points) { int i; for (i = 0; i < n_points; i++) { Point2f p = *(Point2f *)((uint8_t *)points_in + i * stride_in); Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out); o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xw; o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yw; o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zw; o->w = matrix->wx * p.x + matrix->wy * p.y + matrix->ww; } } static void _cogl_matrix_transform_points_f3 (const CoglMatrix *matrix, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points) { int i; for (i = 0; i < n_points; i++) { Point3f p = *(Point3f *)((uint8_t *)points_in + i * stride_in); Point3f *o = (Point3f *)((uint8_t *)points_out + i * stride_out); o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xz * p.z + matrix->xw; o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yz * p.z + matrix->yw; o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zz * p.z + matrix->zw; } } static void _cogl_matrix_project_points_f3 (const CoglMatrix *matrix, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points) { int i; for (i = 0; i < n_points; i++) { Point3f p = *(Point3f *)((uint8_t *)points_in + i * stride_in); Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out); o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xz * p.z + matrix->xw; o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yz * p.z + matrix->yw; o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zz * p.z + matrix->zw; o->w = matrix->wx * p.x + matrix->wy * p.y + matrix->wz * p.z + matrix->ww; } } static void _cogl_matrix_project_points_f4 (const CoglMatrix *matrix, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points) { int i; for (i = 0; i < n_points; i++) { Point4f p = *(Point4f *)((uint8_t *)points_in + i * stride_in); Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out); o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xz * p.z + matrix->xw * p.w; o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yz * p.z + matrix->yw * p.w; o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zz * p.z + matrix->zw * p.w; o->w = matrix->wx * p.x + matrix->wy * p.y + matrix->wz * p.z + matrix->ww * p.w; } } void cogl_matrix_transform_points (const CoglMatrix *matrix, int n_components, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points) { /* The results of transforming always have three components... */ _COGL_RETURN_IF_FAIL (stride_out >= sizeof (Point3f)); if (n_components == 2) _cogl_matrix_transform_points_f2 (matrix, stride_in, points_in, stride_out, points_out, n_points); else { _COGL_RETURN_IF_FAIL (n_components == 3); _cogl_matrix_transform_points_f3 (matrix, stride_in, points_in, stride_out, points_out, n_points); } } void cogl_matrix_project_points (const CoglMatrix *matrix, int n_components, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points) { if (n_components == 2) _cogl_matrix_project_points_f2 (matrix, stride_in, points_in, stride_out, points_out, n_points); else if (n_components == 3) _cogl_matrix_project_points_f3 (matrix, stride_in, points_in, stride_out, points_out, n_points); else { _COGL_RETURN_IF_FAIL (n_components == 4); _cogl_matrix_project_points_f4 (matrix, stride_in, points_in, stride_out, points_out, n_points); } } CoglBool cogl_matrix_is_identity (const CoglMatrix *matrix) { if (!(matrix->flags & MAT_DIRTY_TYPE) && matrix->type == COGL_MATRIX_TYPE_IDENTITY) return TRUE; else return memcmp (matrix, identity, sizeof (float) * 16) == 0; } void cogl_matrix_look_at (CoglMatrix *matrix, float eye_position_x, float eye_position_y, float eye_position_z, float object_x, float object_y, float object_z, float world_up_x, float world_up_y, float world_up_z) { CoglMatrix tmp; float forward[3]; float side[3]; float up[3]; /* Get a unit viewing direction vector */ cogl_vector3_init (forward, object_x - eye_position_x, object_y - eye_position_y, object_z - eye_position_z); cogl_vector3_normalize (forward); cogl_vector3_init (up, world_up_x, world_up_y, world_up_z); /* Take the sideways direction as being perpendicular to the viewing * direction and the word up vector. */ cogl_vector3_cross_product (side, forward, up); cogl_vector3_normalize (side); /* Now we have unit sideways and forward-direction vectors calculate * a new mutually perpendicular up vector. */ cogl_vector3_cross_product (up, side, forward); tmp.xx = side[0]; tmp.yx = side[1]; tmp.zx = side[2]; tmp.wx = 0; tmp.xy = up[0]; tmp.yy = up[1]; tmp.zy = up[2]; tmp.wy = 0; tmp.xz = -forward[0]; tmp.yz = -forward[1]; tmp.zz = -forward[2]; tmp.wz = 0; tmp.xw = 0; tmp.yw = 0; tmp.zw = 0; tmp.ww = 1; tmp.flags = (MAT_FLAG_GENERAL_3D | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); cogl_matrix_translate (&tmp, -eye_position_x, -eye_position_y, -eye_position_z); cogl_matrix_multiply (matrix, matrix, &tmp); } void cogl_matrix_transpose (CoglMatrix *matrix) { float new_values[16]; /* We don't need to do anything if the matrix is the identity matrix */ if (!(matrix->flags & MAT_DIRTY_TYPE) && matrix->type == COGL_MATRIX_TYPE_IDENTITY) return; _cogl_matrix_util_transposef (new_values, cogl_matrix_get_array (matrix)); cogl_matrix_init_from_array (matrix, new_values); } GType cogl_gtype_matrix_get_type (void) { return cogl_matrix_get_gtype (); } muffin-5.2.1/cogl/cogl/cogl-egl.h0000664000175000017500000000740614211404421016655 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_EGL_H__ #define __COGL_EGL_H__ /* NB: this is a top-level header that can be included directly but we * want to be careful not to define __COGL_H_INSIDE__ when this is * included internally while building Cogl itself since * __COGL_H_INSIDE__ is used in headers to guard public vs private api * definitions */ #ifndef COGL_COMPILATION /* Note: When building Cogl .gir we explicitly define * __COGL_EGL_H_INSIDE__ */ #ifndef __COGL_EGL_H_INSIDE__ #define __COGL_EGL_H_INSIDE__ #endif /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_EGL__ #endif #endif /* COGL_COMPILATION */ #include #include COGL_BEGIN_DECLS /** * cogl_egl_context_get_egl_display: * @context: A #CoglContext pointer * * If you have done a runtime check to determine that Cogl is using * EGL internally then this API can be used to retrieve the EGLDisplay * handle that was setup internally. The result is undefined if Cogl * is not using EGL. * * Note: The current window system backend can be checked using * cogl_renderer_get_winsys_id(). * * Return value: The internally setup EGLDisplay handle. * Since: 1.8 * Stability: unstable */ EGLDisplay cogl_egl_context_get_egl_display (CoglContext *context); /** * cogl_egl_context_get_egl_context: * @context: A #CoglContext pointer * * If you have done a runtime check to determine that Cogl is using * EGL internally then this API can be used to retrieve the EGLContext * handle that was setup internally. The result is undefined if Cogl * is not using EGL. * * Note: The current window system backend can be checked using * cogl_renderer_get_winsys_id(). * * Return value: The internally setup EGLDisplay handle. * Since: 1.18 * Stability: unstable */ EGLContext cogl_egl_context_get_egl_context (CoglContext *context); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_EGL__ #undef __COGL_H_INSIDE__ #undef __COGL_EGL_H_INSIDE__ #undef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_EGL__ #endif #endif /* __COGL_EGL_H__ */ muffin-5.2.1/cogl/cogl/cogl-spans.c0000664000175000017500000001235214211404421017221 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "math.h" #include "cogl-util.h" #include "cogl-spans.h" void _cogl_span_iter_update (CoglSpanIter *iter) { /* Pick current span */ iter->span = &iter->spans[iter->index]; /* Offset next position by span size */ iter->next_pos = iter->pos + iter->span->size - iter->span->waste; /* Check if span intersects the area to cover */ if (iter->next_pos <= iter->cover_start || iter->pos >= iter->cover_end) { /* Intersection undefined */ iter->intersects = FALSE; return; } iter->intersects = TRUE; /* Clip start position to coverage area */ if (iter->pos < iter->cover_start) iter->intersect_start = iter->cover_start; else iter->intersect_start = iter->pos; /* Clip end position to coverage area */ if (iter->next_pos > iter->cover_end) iter->intersect_end = iter->cover_end; else iter->intersect_end = iter->next_pos; } void _cogl_span_iter_begin (CoglSpanIter *iter, const CoglSpan *spans, int n_spans, float normalize_factor, float cover_start, float cover_end, CoglPipelineWrapMode wrap_mode) { /* XXX: If CLAMP_TO_EDGE needs to be emulated then it needs to be * done at a higher level than here... */ _COGL_RETURN_IF_FAIL (wrap_mode == COGL_PIPELINE_WRAP_MODE_REPEAT || wrap_mode == COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT); iter->span = NULL; iter->spans = spans; iter->n_spans = n_spans; /* We always iterate in a positive direction from the origin. If * iter->flipped == TRUE that means whoever is using this API should * interpreted the current span as extending in the opposite direction. I.e. * it extends to the left if iterating the X axis, or up if the Y axis. */ if (cover_start > cover_end) { float tmp = cover_start; cover_start = cover_end; cover_end = tmp; iter->flipped = TRUE; } else iter->flipped = FALSE; /* The texture spans cover the normalized texture coordinate space ranging * from [0,1] but to help support repeating of sliced textures we allow * iteration of any range so we need to relate the start of the range to the * nearest point equivalent to 0. */ if (normalize_factor != 1.0) { float cover_start_normalized = cover_start / normalize_factor; iter->origin = floorf (cover_start_normalized) * normalize_factor; } else iter->origin = floorf (cover_start); iter->wrap_mode = wrap_mode; if (wrap_mode == COGL_PIPELINE_WRAP_MODE_REPEAT) iter->index = 0; else if (wrap_mode == COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT) { if ((int)iter->origin % 2) { iter->index = iter->n_spans - 1; iter->mirror_direction = -1; iter->flipped = !iter->flipped; } else { iter->index = 0; iter->mirror_direction = 1; } } else g_warn_if_reached (); iter->cover_start = cover_start; iter->cover_end = cover_end; iter->pos = iter->origin; /* Update intersection */ _cogl_span_iter_update (iter); while (iter->next_pos <= iter->cover_start) _cogl_span_iter_next (iter); } void _cogl_span_iter_next (CoglSpanIter *iter) { /* Move current position */ iter->pos = iter->next_pos; if (iter->wrap_mode == COGL_PIPELINE_WRAP_MODE_REPEAT) iter->index = (iter->index + 1) % iter->n_spans; else if (iter->wrap_mode == COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT) { iter->index += iter->mirror_direction; if (iter->index == iter->n_spans || iter->index == -1) { iter->mirror_direction = -iter->mirror_direction; iter->index += iter->mirror_direction; iter->flipped = !iter->flipped; } } else g_warn_if_reached (); /* Update intersection */ _cogl_span_iter_update (iter); } CoglBool _cogl_span_iter_end (CoglSpanIter *iter) { /* End reached when whole area covered */ return iter->pos >= iter->cover_end; } muffin-5.2.1/cogl/cogl/cogl-muffin.h0000664000175000017500000000350714211404421017370 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2016 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_MUFFIN_H___ #define __COGL_MUFFIN_H___ #include "cogl-muffin-config.h" #include "cogl-defines.h" #include #include #include #include #include #include #include void cogl_renderer_set_custom_winsys (CoglRenderer *renderer, CoglCustomWinsysVtableGetter winsys_vtable_getter, void *user_data); #endif /* __COGL_MUFFIN_H___ */ muffin-5.2.1/cogl/cogl/cogl-glib-source.h0000664000175000017500000000626114211404421020317 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_GSOURCE_H__ #define __COGL_GSOURCE_H__ #include #include G_BEGIN_DECLS /** * cogl_glib_source_new: * @context: A #CoglContext * @priority: The priority of the #GSource * * Creates a #GSource which handles Cogl's internal system event * processing. This can be used as a convenience instead of * cogl_poll_renderer_get_info() and cogl_poll_renderer_dispatch() in * applications that are already using the GLib main loop. After this * is called the #GSource should be attached to the main loop using * g_source_attach(). * * Applications that manually connect to a #CoglRenderer before they * create a #CoglContext should instead use * cogl_glib_renderer_source_new() so that events may be dispatched * before a context has been created. In that case you don't need to * use this api in addition later, it is simply enough to use * cogl_glib_renderer_source_new() instead. * * This api is actually just a thin convenience wrapper around * cogl_glib_renderer_source_new() * * Return value: a new #GSource * * Stability: unstable * Since: 1.10 */ GSource * cogl_glib_source_new (CoglContext *context, int priority); /** * cogl_glib_renderer_source_new: * @renderer: A #CoglRenderer * @priority: The priority of the #GSource * * Creates a #GSource which handles Cogl's internal system event * processing. This can be used as a convenience instead of * cogl_poll_renderer_get_info() and cogl_poll_renderer_dispatch() in * applications that are already using the GLib main loop. After this * is called the #GSource should be attached to the main loop using * g_source_attach(). * * Return value: a new #GSource * * Stability: unstable * Since: 1.16 */ GSource * cogl_glib_renderer_source_new (CoglRenderer *renderer, int priority); G_END_DECLS #endif /* __COGL_GSOURCE_H__ */ muffin-5.2.1/cogl/cogl/cogl-primitive-private.h0000664000175000017500000000411414211404421021557 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PRIMITIVE_PRIVATE_H #define __COGL_PRIMITIVE_PRIVATE_H #include "cogl-object-private.h" #include "cogl-attribute-buffer-private.h" #include "cogl-attribute-private.h" #include "cogl-framebuffer.h" struct _CoglPrimitive { CoglObject _parent; CoglIndices *indices; CoglVerticesMode mode; int first_vertex; int n_vertices; int immutable_ref; CoglAttribute **attributes; int n_attributes; int n_embedded_attributes; CoglAttribute *embedded_attribute; }; CoglPrimitive * _cogl_primitive_immutable_ref (CoglPrimitive *primitive); void _cogl_primitive_immutable_unref (CoglPrimitive *primitive); void _cogl_primitive_draw (CoglPrimitive *primitive, CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglDrawFlags flags); #endif /* __COGL_PRIMITIVE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-primitive.c0000664000175000017500000005342314211404421020111 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-object-private.h" #include "cogl-primitive.h" #include "cogl-primitive-private.h" #include "cogl-attribute-private.h" #include "cogl-framebuffer-private.h" #include "cogl-gtype-private.h" #include #include static void _cogl_primitive_free (CoglPrimitive *primitive); COGL_OBJECT_DEFINE (Primitive, primitive); COGL_GTYPE_DEFINE_CLASS (Primitive, primitive); CoglPrimitive * cogl_primitive_new_with_attributes (CoglVerticesMode mode, int n_vertices, CoglAttribute **attributes, int n_attributes) { CoglPrimitive *primitive; int i; primitive = g_slice_alloc (sizeof (CoglPrimitive) + sizeof (CoglAttribute *) * (n_attributes - 1)); primitive->mode = mode; primitive->first_vertex = 0; primitive->n_vertices = n_vertices; primitive->indices = NULL; primitive->immutable_ref = 0; primitive->n_attributes = n_attributes; primitive->n_embedded_attributes = n_attributes; primitive->attributes = &primitive->embedded_attribute; for (i = 0; i < n_attributes; i++) { CoglAttribute *attribute = attributes[i]; cogl_object_ref (attribute); _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL); primitive->attributes[i] = attribute; } return _cogl_primitive_object_new (primitive); } /* This is just an internal convenience wrapper around new_with_attributes that also unrefs the attributes. It is just used for the builtin struct constructors */ static CoglPrimitive * _cogl_primitive_new_with_attributes_unref (CoglVerticesMode mode, int n_vertices, CoglAttribute **attributes, int n_attributes) { CoglPrimitive *primitive; int i; primitive = cogl_primitive_new_with_attributes (mode, n_vertices, attributes, n_attributes); for (i = 0; i < n_attributes; i++) cogl_object_unref (attributes[i]); return primitive; } CoglPrimitive * cogl_primitive_new (CoglVerticesMode mode, int n_vertices, ...) { va_list ap; int n_attributes; CoglAttribute **attributes; int i; CoglAttribute *attribute; va_start (ap, n_vertices); for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++) ; va_end (ap); attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes); va_start (ap, n_vertices); for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++) attributes[i] = attribute; va_end (ap); return cogl_primitive_new_with_attributes (mode, n_vertices, attributes, i); } CoglPrimitive * cogl_primitive_new_p2 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP2 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP2), data); CoglAttribute *attributes[1]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP2), offsetof (CoglVertexP2, x), 2, COGL_ATTRIBUTE_TYPE_FLOAT); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 1); } CoglPrimitive * cogl_primitive_new_p3 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP3 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP3), data); CoglAttribute *attributes[1]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP3), offsetof (CoglVertexP3, x), 3, COGL_ATTRIBUTE_TYPE_FLOAT); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 1); } CoglPrimitive * cogl_primitive_new_p2c4 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP2C4 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP2C4), data); CoglAttribute *attributes[2]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP2C4), offsetof (CoglVertexP2C4, x), 2, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (attribute_buffer, "cogl_color_in", sizeof (CoglVertexP2C4), offsetof (CoglVertexP2C4, r), 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 2); } CoglPrimitive * cogl_primitive_new_p3c4 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP3C4 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP3C4), data); CoglAttribute *attributes[2]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP3C4), offsetof (CoglVertexP3C4, x), 3, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (attribute_buffer, "cogl_color_in", sizeof (CoglVertexP3C4), offsetof (CoglVertexP3C4, r), 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 2); } CoglPrimitive * cogl_primitive_new_p2t2 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP2T2 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP2T2), data); CoglAttribute *attributes[2]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP2T2), offsetof (CoglVertexP2T2, x), 2, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (attribute_buffer, "cogl_tex_coord0_in", sizeof (CoglVertexP2T2), offsetof (CoglVertexP2T2, s), 2, COGL_ATTRIBUTE_TYPE_FLOAT); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 2); } CoglPrimitive * cogl_primitive_new_p3t2 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP3T2 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP3T2), data); CoglAttribute *attributes[2]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP3T2), offsetof (CoglVertexP3T2, x), 3, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (attribute_buffer, "cogl_tex_coord0_in", sizeof (CoglVertexP3T2), offsetof (CoglVertexP3T2, s), 2, COGL_ATTRIBUTE_TYPE_FLOAT); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 2); } CoglPrimitive * cogl_primitive_new_p2t2c4 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP2T2C4 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP2T2C4), data); CoglAttribute *attributes[3]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP2T2C4), offsetof (CoglVertexP2T2C4, x), 2, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (attribute_buffer, "cogl_tex_coord0_in", sizeof (CoglVertexP2T2C4), offsetof (CoglVertexP2T2C4, s), 2, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[2] = cogl_attribute_new (attribute_buffer, "cogl_color_in", sizeof (CoglVertexP2T2C4), offsetof (CoglVertexP2T2C4, r), 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 3); } CoglPrimitive * cogl_primitive_new_p3t2c4 (CoglContext *ctx, CoglVerticesMode mode, int n_vertices, const CoglVertexP3T2C4 *data) { CoglAttributeBuffer *attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * sizeof (CoglVertexP3T2C4), data); CoglAttribute *attributes[3]; attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (CoglVertexP3T2C4), offsetof (CoglVertexP3T2C4, x), 3, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[1] = cogl_attribute_new (attribute_buffer, "cogl_tex_coord0_in", sizeof (CoglVertexP3T2C4), offsetof (CoglVertexP3T2C4, s), 2, COGL_ATTRIBUTE_TYPE_FLOAT); attributes[2] = cogl_attribute_new (attribute_buffer, "cogl_color_in", sizeof (CoglVertexP3T2C4), offsetof (CoglVertexP3T2C4, r), 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); cogl_object_unref (attribute_buffer); return _cogl_primitive_new_with_attributes_unref (mode, n_vertices, attributes, 3); } static void _cogl_primitive_free (CoglPrimitive *primitive) { int i; for (i = 0; i < primitive->n_attributes; i++) cogl_object_unref (primitive->attributes[i]); if (primitive->attributes != &primitive->embedded_attribute) g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes, primitive->attributes); if (primitive->indices) cogl_object_unref (primitive->indices); g_slice_free1 (sizeof (CoglPrimitive) + sizeof (CoglAttribute *) * (primitive->n_embedded_attributes - 1), primitive); } static void warn_about_midscene_changes (void) { static CoglBool seen = FALSE; if (!seen) { g_warning ("Mid-scene modification of primitives has " "undefined results\n"); seen = TRUE; } } void cogl_primitive_set_attributes (CoglPrimitive *primitive, CoglAttribute **attributes, int n_attributes) { int i; _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive)); if (G_UNLIKELY (primitive->immutable_ref)) { warn_about_midscene_changes (); return; } /* NB: we don't unref the previous attributes before refing the new * in case we would end up releasing the last reference for an * attribute thats actually in the new list too. */ for (i = 0; i < n_attributes; i++) { _COGL_RETURN_IF_FAIL (cogl_is_attribute (attributes[i])); cogl_object_ref (attributes[i]); } for (i = 0; i < primitive->n_attributes; i++) cogl_object_unref (primitive->attributes[i]); /* First try to use the embedded storage assocated with the * primitive, else fallback to slice allocating separate storage for * the attribute pointers... */ if (n_attributes <= primitive->n_embedded_attributes) { if (primitive->attributes != &primitive->embedded_attribute) g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes, primitive->attributes); primitive->attributes = &primitive->embedded_attribute; } else { if (primitive->attributes != &primitive->embedded_attribute) g_slice_free1 (sizeof (CoglAttribute *) * primitive->n_attributes, primitive->attributes); primitive->attributes = g_slice_alloc (sizeof (CoglAttribute *) * n_attributes); } memcpy (primitive->attributes, attributes, sizeof (CoglAttribute *) * n_attributes); primitive->n_attributes = n_attributes; } int cogl_primitive_get_first_vertex (CoglPrimitive *primitive) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), 0); return primitive->first_vertex; } void cogl_primitive_set_first_vertex (CoglPrimitive *primitive, int first_vertex) { _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive)); if (G_UNLIKELY (primitive->immutable_ref)) { warn_about_midscene_changes (); return; } primitive->first_vertex = first_vertex; } int cogl_primitive_get_n_vertices (CoglPrimitive *primitive) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), 0); return primitive->n_vertices; } void cogl_primitive_set_n_vertices (CoglPrimitive *primitive, int n_vertices) { _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive)); primitive->n_vertices = n_vertices; } CoglVerticesMode cogl_primitive_get_mode (CoglPrimitive *primitive) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), 0); return primitive->mode; } void cogl_primitive_set_mode (CoglPrimitive *primitive, CoglVerticesMode mode) { _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive)); if (G_UNLIKELY (primitive->immutable_ref)) { warn_about_midscene_changes (); return; } primitive->mode = mode; } void cogl_primitive_set_indices (CoglPrimitive *primitive, CoglIndices *indices, int n_indices) { _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive)); if (G_UNLIKELY (primitive->immutable_ref)) { warn_about_midscene_changes (); return; } if (indices) cogl_object_ref (indices); if (primitive->indices) cogl_object_unref (primitive->indices); primitive->indices = indices; primitive->n_vertices = n_indices; } CoglIndices * cogl_primitive_get_indices (CoglPrimitive *primitive) { return primitive->indices; } CoglPrimitive * cogl_primitive_copy (CoglPrimitive *primitive) { CoglPrimitive *copy; copy = cogl_primitive_new_with_attributes (primitive->mode, primitive->n_vertices, primitive->attributes, primitive->n_attributes); cogl_primitive_set_indices (copy, primitive->indices, primitive->n_vertices); cogl_primitive_set_first_vertex (copy, primitive->first_vertex); return copy; } CoglPrimitive * _cogl_primitive_immutable_ref (CoglPrimitive *primitive) { int i; _COGL_RETURN_VAL_IF_FAIL (cogl_is_primitive (primitive), NULL); primitive->immutable_ref++; for (i = 0; i < primitive->n_attributes; i++) _cogl_attribute_immutable_ref (primitive->attributes[i]); return primitive; } void _cogl_primitive_immutable_unref (CoglPrimitive *primitive) { int i; _COGL_RETURN_IF_FAIL (cogl_is_primitive (primitive)); _COGL_RETURN_IF_FAIL (primitive->immutable_ref > 0); primitive->immutable_ref--; for (i = 0; i < primitive->n_attributes; i++) _cogl_attribute_immutable_unref (primitive->attributes[i]); } void cogl_primitive_foreach_attribute (CoglPrimitive *primitive, CoglPrimitiveAttributeCallback callback, void *user_data) { int i; for (i = 0; i < primitive->n_attributes; i++) if (!callback (primitive, primitive->attributes[i], user_data)) break; } void _cogl_primitive_draw (CoglPrimitive *primitive, CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglDrawFlags flags) { if (primitive->indices) _cogl_framebuffer_draw_indexed_attributes (framebuffer, pipeline, primitive->mode, primitive->first_vertex, primitive->n_vertices, primitive->indices, primitive->attributes, primitive->n_attributes, flags); else _cogl_framebuffer_draw_attributes (framebuffer, pipeline, primitive->mode, primitive->first_vertex, primitive->n_vertices, primitive->attributes, primitive->n_attributes, flags); } void cogl_primitive_draw (CoglPrimitive *primitive, CoglFramebuffer *framebuffer, CoglPipeline *pipeline) { _cogl_primitive_draw (primitive, framebuffer, pipeline, 0 /* flags */); } muffin-5.2.1/cogl/cogl/cogl-bitmap.c0000664000175000017500000003420314211404421017350 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-debug.h" #include "cogl-private.h" #include "cogl-bitmap-private.h" #include "cogl-buffer-private.h" #include "cogl-pixel-buffer.h" #include "cogl-context-private.h" #include "cogl-buffer-gl-private.h" #include "cogl-error-private.h" #include "cogl-gtype-private.h" #include static void _cogl_bitmap_free (CoglBitmap *bmp); COGL_OBJECT_DEFINE (Bitmap, bitmap); COGL_GTYPE_DEFINE_CLASS (Bitmap, bitmap); static void _cogl_bitmap_free (CoglBitmap *bmp) { g_assert (!bmp->mapped); g_assert (!bmp->bound); if (bmp->shared_bmp) cogl_object_unref (bmp->shared_bmp); if (bmp->buffer) cogl_object_unref (bmp->buffer); g_slice_free (CoglBitmap, bmp); } CoglBool _cogl_bitmap_convert_premult_status (CoglBitmap *bmp, CoglPixelFormat dst_format, CoglError **error) { /* Do we need to unpremultiply? */ if ((bmp->format & COGL_PREMULT_BIT) > 0 && (dst_format & COGL_PREMULT_BIT) == 0 && COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (dst_format)) return _cogl_bitmap_unpremult (bmp, error); /* Do we need to premultiply? */ if ((bmp->format & COGL_PREMULT_BIT) == 0 && COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (bmp->format) && (dst_format & COGL_PREMULT_BIT) > 0) /* Try premultiplying using imaging library */ return _cogl_bitmap_premult (bmp, error); return TRUE; } CoglBitmap * _cogl_bitmap_copy (CoglBitmap *src_bmp, CoglError **error) { CoglBitmap *dst_bmp; CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp); int width = cogl_bitmap_get_width (src_bmp); int height = cogl_bitmap_get_height (src_bmp); dst_bmp = _cogl_bitmap_new_with_malloc_buffer (src_bmp->context, width, height, src_format, error); if (!dst_bmp) return NULL; if (!_cogl_bitmap_copy_subregion (src_bmp, dst_bmp, 0, 0, /* src_x/y */ 0, 0, /* dst_x/y */ width, height, error)) { cogl_object_unref (dst_bmp); return NULL; } return dst_bmp; } CoglBool _cogl_bitmap_copy_subregion (CoglBitmap *src, CoglBitmap *dst, int src_x, int src_y, int dst_x, int dst_y, int width, int height, CoglError **error) { uint8_t *srcdata; uint8_t *dstdata; int bpp; int line; CoglBool succeeded = FALSE; /* Intended only for fast copies when format is equal! */ _COGL_RETURN_VAL_IF_FAIL ((src->format & ~COGL_PREMULT_BIT) == (dst->format & ~COGL_PREMULT_BIT), FALSE); bpp = _cogl_pixel_format_get_bytes_per_pixel (src->format); if ((srcdata = _cogl_bitmap_map (src, COGL_BUFFER_ACCESS_READ, 0, error))) { if ((dstdata = _cogl_bitmap_map (dst, COGL_BUFFER_ACCESS_WRITE, 0, error))) { srcdata += src_y * src->rowstride + src_x * bpp; dstdata += dst_y * dst->rowstride + dst_x * bpp; for (line = 0; line < height; ++line) { memcpy (dstdata, srcdata, width * bpp); srcdata += src->rowstride; dstdata += dst->rowstride; } succeeded = TRUE; _cogl_bitmap_unmap (dst); } _cogl_bitmap_unmap (src); } return succeeded; } CoglBool cogl_bitmap_get_size_from_file (const char *filename, int *width, int *height) { return _cogl_bitmap_get_size_from_file (filename, width, height); } CoglBitmap * cogl_bitmap_new_for_data (CoglContext *context, int width, int height, CoglPixelFormat format, int rowstride, uint8_t *data) { CoglBitmap *bmp; g_return_val_if_fail (cogl_is_context (context), NULL); /* Rowstride from width if not given */ if (rowstride == 0) rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); bmp = g_slice_new (CoglBitmap); bmp->context = context; bmp->format = format; bmp->width = width; bmp->height = height; bmp->rowstride = rowstride; bmp->data = data; bmp->mapped = FALSE; bmp->bound = FALSE; bmp->shared_bmp = NULL; bmp->buffer = NULL; return _cogl_bitmap_object_new (bmp); } CoglBitmap * _cogl_bitmap_new_with_malloc_buffer (CoglContext *context, unsigned int width, unsigned int height, CoglPixelFormat format, CoglError **error) { static CoglUserDataKey bitmap_free_key; int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); int rowstride = ((width * bpp) + 3) & ~3; uint8_t *data = g_try_malloc (rowstride * height); CoglBitmap *bitmap; if (!data) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_NO_MEMORY, "Failed to allocate memory for bitmap"); return NULL; } bitmap = cogl_bitmap_new_for_data (context, width, height, format, rowstride, data); cogl_object_set_user_data (COGL_OBJECT (bitmap), &bitmap_free_key, data, free); return bitmap; } CoglBitmap * _cogl_bitmap_new_shared (CoglBitmap *shared_bmp, CoglPixelFormat format, int width, int height, int rowstride) { CoglBitmap *bmp; bmp = cogl_bitmap_new_for_data (shared_bmp->context, width, height, format, rowstride, NULL /* data */); bmp->shared_bmp = cogl_object_ref (shared_bmp); return bmp; } CoglBitmap * cogl_bitmap_new_from_file (const char *filename, CoglError **error) { _COGL_GET_CONTEXT (ctx, NULL); _COGL_RETURN_VAL_IF_FAIL (filename != NULL, NULL); _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); return _cogl_bitmap_from_file (ctx, filename, error); } CoglBitmap * cogl_bitmap_new_from_buffer (CoglBuffer *buffer, CoglPixelFormat format, int width, int height, int rowstride, int offset) { CoglBitmap *bmp; _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); bmp = cogl_bitmap_new_for_data (buffer->context, width, height, format, rowstride, NULL /* data */); bmp->buffer = cogl_object_ref (buffer); bmp->data = GINT_TO_POINTER (offset); return bmp; } CoglBitmap * cogl_bitmap_new_with_size (CoglContext *context, unsigned int width, unsigned int height, CoglPixelFormat format) { CoglPixelBuffer *pixel_buffer; CoglBitmap *bitmap; unsigned int rowstride; /* creating a buffer to store "any" format does not make sense */ _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); /* for now we fallback to cogl_pixel_buffer_new, later, we could ask * libdrm a tiled buffer for instance */ rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); pixel_buffer = cogl_pixel_buffer_new (context, height * rowstride, NULL); /* data */ _COGL_RETURN_VAL_IF_FAIL (pixel_buffer != NULL, NULL); bitmap = cogl_bitmap_new_from_buffer (COGL_BUFFER (pixel_buffer), format, width, height, rowstride, 0 /* offset */); cogl_object_unref (pixel_buffer); return bitmap; } CoglPixelFormat cogl_bitmap_get_format (CoglBitmap *bitmap) { return bitmap->format; } void _cogl_bitmap_set_format (CoglBitmap *bitmap, CoglPixelFormat format) { bitmap->format = format; } int cogl_bitmap_get_width (CoglBitmap *bitmap) { return bitmap->width; } int cogl_bitmap_get_height (CoglBitmap *bitmap) { return bitmap->height; } int cogl_bitmap_get_rowstride (CoglBitmap *bitmap) { return bitmap->rowstride; } CoglPixelBuffer * cogl_bitmap_get_buffer (CoglBitmap *bitmap) { while (bitmap->shared_bmp) bitmap = bitmap->shared_bmp; return COGL_PIXEL_BUFFER (bitmap->buffer); } uint32_t cogl_bitmap_error_quark (void) { return g_quark_from_static_string ("cogl-bitmap-error-quark"); } uint8_t * _cogl_bitmap_map (CoglBitmap *bitmap, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error) { /* Divert to another bitmap if this data is shared */ if (bitmap->shared_bmp) return _cogl_bitmap_map (bitmap->shared_bmp, access, hints, error); g_assert (!bitmap->mapped); if (bitmap->buffer) { uint8_t *data = _cogl_buffer_map (bitmap->buffer, access, hints, error); COGL_NOTE (BITMAP, "A pixel array is being mapped from a bitmap. This " "usually means that some conversion on the pixel array is " "needed so a sub-optimal format is being used."); if (data) { bitmap->mapped = TRUE; return data + GPOINTER_TO_INT (bitmap->data); } else return NULL; } else { bitmap->mapped = TRUE; return bitmap->data; } } void _cogl_bitmap_unmap (CoglBitmap *bitmap) { /* Divert to another bitmap if this data is shared */ if (bitmap->shared_bmp) { _cogl_bitmap_unmap (bitmap->shared_bmp); return; } g_assert (bitmap->mapped); bitmap->mapped = FALSE; if (bitmap->buffer) cogl_buffer_unmap (bitmap->buffer); } uint8_t * _cogl_bitmap_gl_bind (CoglBitmap *bitmap, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error) { uint8_t *ptr; CoglError *internal_error = NULL; g_return_val_if_fail (access & (COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE), NULL); /* Divert to another bitmap if this data is shared */ if (bitmap->shared_bmp) return _cogl_bitmap_gl_bind (bitmap->shared_bmp, access, hints, error); _COGL_RETURN_VAL_IF_FAIL (!bitmap->bound, NULL); /* If the bitmap wasn't created from a buffer then the implementation of bind is the same as map */ if (bitmap->buffer == NULL) { uint8_t *data = _cogl_bitmap_map (bitmap, access, hints, error); if (data) bitmap->bound = TRUE; return data; } if (access == COGL_BUFFER_ACCESS_READ) ptr = _cogl_buffer_gl_bind (bitmap->buffer, COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK, &internal_error); else if (access == COGL_BUFFER_ACCESS_WRITE) ptr = _cogl_buffer_gl_bind (bitmap->buffer, COGL_BUFFER_BIND_TARGET_PIXEL_PACK, &internal_error); else { ptr = NULL; g_assert_not_reached (); return NULL; } /* NB: _cogl_buffer_gl_bind() may return NULL in non-error * conditions so we have to explicitly check internal_error to see * if an exception was thrown */ if (internal_error) { _cogl_propagate_error (error, internal_error); return NULL; } bitmap->bound = TRUE; /* The data pointer actually stores the offset */ return ptr + GPOINTER_TO_INT (bitmap->data); } void _cogl_bitmap_gl_unbind (CoglBitmap *bitmap) { /* Divert to another bitmap if this data is shared */ if (bitmap->shared_bmp) { _cogl_bitmap_gl_unbind (bitmap->shared_bmp); return; } g_assert (bitmap->bound); bitmap->bound = FALSE; /* If the bitmap wasn't created from a pixel array then the implementation of unbind is the same as unmap */ if (bitmap->buffer) _cogl_buffer_gl_unbind (bitmap->buffer); else _cogl_bitmap_unmap (bitmap); } CoglContext * _cogl_bitmap_get_context (CoglBitmap *bitmap) { return bitmap->context; } muffin-5.2.1/cogl/cogl/cogl-xlib.h0000664000175000017500000001047314211404421017042 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_XLIB_H__ #define __COGL_XLIB_H__ #include /* NB: this is a top-level header that can be included directly but we * want to be careful not to define __COGL_H_INSIDE__ when this is * included internally while building Cogl itself since * __COGL_H_INSIDE__ is used in headers to guard public vs private api * definitions */ #ifndef COGL_COMPILATION /* Note: When building Cogl .gir we explicitly define * __COGL_XLIB_H_INSIDE__ */ #ifndef __COGL_XLIB_H_INSIDE__ #define __COGL_XLIB_H_INSIDE__ #endif /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_XLIB_H_MUST_UNDEF_COGL_H_INSIDE__ #endif #endif /* COGL_COMPILATION */ #include #include #include #include COGL_BEGIN_DECLS /* * cogl_xlib_get_display: * * Return value: the Xlib display that will be used by the Xlib winsys * backend. The display needs to be set with _cogl_xlib_set_display() * before this function is called. * * Stability: Unstable * Deprecated: 1.16: Use cogl_xlib_renderer_get_display() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_xlib_renderer_get_display) Display * cogl_xlib_get_display (void); /* * cogl_xlib_set_display: * * Sets the Xlib display that Cogl will use for the Xlib winsys * backend. This function should eventually go away when Cogl gains a * more complete winsys abstraction. * * Stability: Unstable * Deprecated: 1.16: Use cogl_xlib_renderer_set_foreign_display() * instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_xlib_renderer_set_foreign_display) void cogl_xlib_set_display (Display *display); /* * cogl_xlib_handle_event: * @xevent: pointer to XEvent structure * * This function processes a single X event; it can be used to hook * into external X event retrieval (for example that done by Clutter * or GDK). * * Return value: #CoglXlibFilterReturn. %COGL_XLIB_FILTER_REMOVE * indicates that Cogl has internally handled the event and the * caller should do no further processing. %COGL_XLIB_FILTER_CONTINUE * indicates that Cogl is either not interested in the event, * or has used the event to update internal state without taking * any exclusive action. * * Stability: Unstable * Deprecated: 1.16: Use cogl_xlib_renderer_handle_event() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_xlib_renderer_handle_event) CoglFilterReturn cogl_xlib_handle_event (XEvent *xevent); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_XLIB_H_MUST_UNDEF_COGL_H_INSIDE__ #undef __COGL_H_INSIDE__ #undef __COGL_XLIB_H_INSIDE__ #undef __COGL_XLIB_H_MUST_UNDEF_COGL_H_INSIDE__ #endif #endif /* __COGL_XLIB_H__ */ muffin-5.2.1/cogl/cogl/cogl-indices.h0000664000175000017500000001247714211404421017530 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_INDICES_H__ #define __COGL_INDICES_H__ /* We forward declare the CoglIndices type here to avoid some circular * dependency issues with the following headers. */ typedef struct _CoglIndices CoglIndices; #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-indices * @short_description: Describe vertex indices stored in a #CoglIndexBuffer. * * Indices allow you to avoid duplicating vertices in your vertex data * by virtualizing your data and instead providing a sequence of index * values that tell the GPU which data should be used for each vertex. * * If the GPU is given a sequence of indices it doesn't simply walk * through each vertex of your data in order it will instead walk * through the indices which can provide random access to the * underlying data. * * Since it's very common to have duplicate vertices when describing a * shape as a list of triangles it can often be a significant space * saving to describe geometry using indices. Reducing the size of * your models can make it cheaper to map them into the GPU by * reducing the demand on memory bandwidth and may help to make better * use of your GPUs internal vertex caching. * * For example, to describe a quadrilateral as 2 triangles for the GPU * you could either provide data with 6 vertices or instead with * indices you can provide vertex data for just 4 vertices and an * index buffer that specfies the 6 vertices by indexing the shared * vertices multiple times. * * |[ * CoglVertex2f quad_vertices[] = { * {x0, y0}, //0 = top left * {x1, y1}, //1 = bottom left * {x2, y2}, //2 = bottom right * {x3, y3}, //3 = top right * }; * //tell the gpu how to interpret the quad as 2 triangles... * unsigned char indices[] = {0, 1, 2, 0, 2, 3}; * ]| * * Even in the above illustration we see a saving of 10bytes for one * quad compared to having data for 6 vertices and no indices but if * you need to draw 100s or 1000s of quads then its really quite * significant. * * Something else to consider is that often indices can be defined * once and remain static while the vertex data may change for * animations perhaps. That means you may be able to ignore the * negligable cost of mapping your indices into the GPU if they don't * ever change. * * The above illustration is actually a good example of static indices * because it's really common that developers have quad mesh data that * they need to display and we know exactly what that indices array * needs to look like depending on the number of quads that need to be * drawn. It doesn't matter how the quads might be animated and * changed the indices will remain the same. Cogl even has a utility * (cogl_get_rectangle_indices()) to get access to re-useable indices * for drawing quads as above. */ /** * cogl_indices_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_indices_get_gtype (void); CoglIndices * cogl_indices_new (CoglContext *context, CoglIndicesType type, const void *indices_data, int n_indices); CoglIndices * cogl_indices_new_for_buffer (CoglIndicesType type, CoglIndexBuffer *buffer, size_t offset); CoglIndexBuffer * cogl_indices_get_buffer (CoglIndices *indices); CoglIndicesType cogl_indices_get_type (CoglIndices *indices); size_t cogl_indices_get_offset (CoglIndices *indices); void cogl_indices_set_offset (CoglIndices *indices, size_t offset); CoglIndices * cogl_get_rectangle_indices (CoglContext *context, int n_rectangles); /** * cogl_is_indices: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglIndices. * * Return value: %TRUE if the object references a #CoglIndices * and %FALSE otherwise. * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_indices (void *object); COGL_END_DECLS #endif /* __COGL_INDICES_H__ */ muffin-5.2.1/cogl/cogl/cogl-matrix-private.h0000664000175000017500000000346014211404421021056 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_MATRIX_PRIVATE_H #define __COGL_MATRIX_PRIVATE_H #include COGL_BEGIN_DECLS #define _COGL_MATRIX_DEBUG_PRINT(MATRIX) \ if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_MATRICES))) \ { \ g_print ("%s:\n", G_STRFUNC); \ cogl_debug_matrix_print (MATRIX); \ } void _cogl_matrix_prefix_print (const char *prefix, const CoglMatrix *matrix); void _cogl_matrix_init_from_matrix_without_inverse (CoglMatrix *matrix, const CoglMatrix *src); COGL_END_DECLS #endif /* __COGL_MATRIX_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-texture-rectangle.h0000664000175000017500000002031314211404421021540 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifndef __COGL_TEXURE_RECTANGLE_H #define __COGL_TEXURE_RECTANGLE_H #include "cogl-context.h" COGL_BEGIN_DECLS /** * SECTION:cogl-texture-rectangle * @short_description: Functions for creating and manipulating rectangle * textures for use with non-normalized coordinates. * * These functions allow low-level "rectangle" textures to be allocated. * These textures are never constrained to power-of-two sizes but they * also don't support having a mipmap and can only be wrapped with * %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE. * * The most notable difference between rectangle textures and 2D * textures is that rectangle textures are sampled using un-normalized * texture coordinates, so instead of using coordinates (0,0) and * (1,1) to map to the top-left and bottom right corners of the * texture you would instead use (0,0) and (width,height). * * The use of non-normalized coordinates can be particularly * convenient when writing glsl shaders that use a texture as a lookup * table since you don't need to upload separate uniforms to map * normalized coordinates to texels. * * If you want to sample from a rectangle texture from GLSL you should * use the sampler2DRect sampler type. * * Applications wanting to use #CoglTextureRectangle should first check * for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature using * cogl_has_feature(). */ typedef struct _CoglTextureRectangle CoglTextureRectangle; #define COGL_TEXTURE_RECTANGLE(X) ((CoglTextureRectangle *)X) /** * cogl_texture_rectangle_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_texture_rectangle_get_gtype (void); /** * cogl_is_texture_rectangle: * @object: A #CoglObject * * Gets whether the given object references an existing * #CoglTextureRectangle object. * * Return value: %TRUE if the object references a * #CoglTextureRectangle, %FALSE otherwise. */ CoglBool cogl_is_texture_rectangle (void *object); /** * cogl_texture_rectangle_new_with_size: * @ctx: A #CoglContext pointer * @width: The texture width to allocate * @height: The texture height to allocate * * Creates a new #CoglTextureRectangle texture with a given @width, * and @height. This texture is a low-level texture that the GPU can * sample from directly unlike high-level textures such as * #CoglTexture2DSliced and #CoglAtlasTexture. * * Unlike for #CoglTexture2D textures, coordinates for * #CoglTextureRectangle textures should not be normalized. So instead * of using the coordinate (1, 1) to sample the bottom right corner of * a rectangle texture you would use (@width, @height) where @width * and @height are the width and height of the texture. * * If you want to sample from a rectangle texture from GLSL you * should use the sampler2DRect sampler type. * * Applications wanting to use #CoglTextureRectangle should * first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature * using cogl_has_feature(). * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is going to be used and can optimize how it is * allocated. * * Returns value: (transfer full): A pointer to a new #CoglTextureRectangle * object with no storage allocated yet. * * Since: 1.10 * Stability: unstable */ CoglTextureRectangle * cogl_texture_rectangle_new_with_size (CoglContext *ctx, int width, int height); /** * cogl_texture_rectangle_new_from_bitmap: * @bitmap: A #CoglBitmap * * Allocates a new #CoglTextureRectangle texture which will be * initialized with the pixel data from @bitmap. This texture is a * low-level texture that the GPU can sample from directly unlike * high-level textures such as #CoglTexture2DSliced and * #CoglAtlasTexture. * * Unlike for #CoglTexture2D textures, coordinates for * #CoglTextureRectangle textures should not be normalized. So instead * of using the coordinate (1, 1) to sample the bottom right corner of * a rectangle texture you would use (@width, @height) where @width * and @height are the width and height of the texture. * * If you want to sample from a rectangle texture from GLSL you * should use the sampler2DRect sampler type. * * Applications wanting to use #CoglTextureRectangle should * first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature * using cogl_has_feature(). * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is going to be used and can optimize how it is * allocated. * * Return value: (transfer full): A pointer to a new * #CoglTextureRectangle texture. * Since: 2.0 * Stability: unstable */ CoglTextureRectangle * cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bitmap); /** * cogl_texture_rectangle_new_from_foreign: * @ctx: A #CoglContext * @gl_handle: A GL handle for a GL_TEXTURE_RECTANGLE texture object * @width: Width of the foreign GL texture * @height: Height of the foreign GL texture * @format: The format of the texture * * Wraps an existing GL_TEXTURE_RECTANGLE texture object as a * #CoglTextureRectangle. This can be used for integrating Cogl with * software using OpenGL directly. * * Unlike for #CoglTexture2D textures, coordinates for * #CoglTextureRectangle textures should not be normalized. So instead * of using the coordinate (1, 1) to sample the bottom right corner of * a rectangle texture you would use (@width, @height) where @width * and @height are the width and height of the texture. * * The results are undefined for passing an invalid @gl_handle * or if @width or @height don't have the correct texture * geometry. * * If you want to sample from a rectangle texture from GLSL you * should use the sampler2DRect sampler type. * * Applications wanting to use #CoglTextureRectangle should * first check for the %COGL_FEATURE_ID_TEXTURE_RECTANGLE feature * using cogl_has_feature(). * * The texture is still configurable until it has been allocated so * for example you can declare whether the texture is premultiplied * with cogl_texture_set_premultiplied(). * * Return value: (transfer full): A new #CoglTextureRectangle texture */ CoglTextureRectangle * cogl_texture_rectangle_new_from_foreign (CoglContext *ctx, unsigned int gl_handle, int width, int height, CoglPixelFormat format); COGL_END_DECLS #endif /* __COGL_TEXURE_RECTANGLE_H */ muffin-5.2.1/cogl/cogl/cogl-gtype.c0000664000175000017500000000670514211404421017232 0ustar jpeisachjpeisach#include "cogl-gtype-private.h" #include void _cogl_gtype_object_init_value (GValue *value) { value->data[0].v_pointer = NULL; } void _cogl_gtype_object_free_value (GValue *value) { if (value->data[0].v_pointer != NULL) cogl_object_unref (value->data[0].v_pointer); } void _cogl_gtype_object_copy_value (const GValue *src, GValue *dst) { if (src->data[0].v_pointer != NULL) dst->data[0].v_pointer = cogl_object_ref (src->data[0].v_pointer); else dst->data[0].v_pointer = NULL; } gpointer _cogl_gtype_object_peek_pointer (const GValue *value) { return value->data[0].v_pointer; } gchar * _cogl_gtype_object_collect_value (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { CoglObject *object; object = collect_values[0].v_pointer; if (object == NULL) { value->data[0].v_pointer = NULL; return NULL; } if (object->klass == NULL) return g_strconcat ("invalid unclassed CoglObject pointer for " "value type '", G_VALUE_TYPE_NAME (value), "'", NULL); value->data[0].v_pointer = cogl_object_ref (object); return NULL; } gchar * _cogl_gtype_object_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { CoglObject **object_p = collect_values[0].v_pointer; if (object_p == NULL) return g_strconcat ("value location for '", G_VALUE_TYPE_NAME (value), "' passed as NULL", NULL); if (value->data[0].v_pointer == NULL) *object_p = NULL; else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) *object_p = value->data[0].v_pointer; else *object_p = cogl_object_ref (value->data[0].v_pointer); return NULL; } void _cogl_gtype_object_class_base_init (CoglObjectClass *klass) { } void _cogl_gtype_object_class_base_finalize (CoglObjectClass *klass) { } void _cogl_gtype_object_class_init (CoglObjectClass *klass) { } void _cogl_gtype_object_init (CoglObject *object) { } void _cogl_gtype_dummy_iface_init (gpointer iface) { } /** * cogl_object_value_set_object: * @value: a #GValue initialized with %COGL_GTYPE_TYPE_OBJECT * @object: (type Cogl.GtypeObject) (allow-none): a #CoglGtypeObject, or %NULL * * Sets the contents of a #GValue initialized with %COGL_GTYPE_TYPE_OBJECT. * */ void cogl_object_value_set_object (GValue *value, gpointer object) { CoglObject *old_object; old_object = value->data[0].v_pointer; if (object != NULL) { /* take over ownership */ value->data[0].v_pointer = object; } else value->data[0].v_pointer = NULL; if (old_object != NULL) cogl_object_unref (old_object); } /** * cogl_object_value_get_object: * @value: a #GValue initialized with %COGL_GTYPE_TYPE_OBJECT * * Retrieves a pointer to the #CoglGtypeObject contained inside * the passed #GValue. * * Return value: (transfer none) (type Cogl.GtypeObject): a pointer to * a #CoglGtypeObject, or %NULL */ gpointer cogl_object_value_get_object (const GValue *value) { return value->data[0].v_pointer; } muffin-5.2.1/cogl/cogl/cogl-texture-rectangle.c0000664000175000017500000006435714211404421021553 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-private.h" #include "cogl-util.h" #include "cogl-texture-private.h" #include "cogl-texture-rectangle-private.h" #include "cogl-texture-driver.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-journal-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" #include "cogl-util-gl-private.h" #include "cogl-gtype-private.h" #include #include /* These aren't defined under GLES */ #ifndef GL_TEXTURE_RECTANGLE_ARB #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #endif #ifndef GL_CLAMP #define GL_CLAMP 0x2900 #endif #ifndef GL_CLAMP_TO_BORDER #define GL_CLAMP_TO_BORDER 0x812D #endif static void _cogl_texture_rectangle_free (CoglTextureRectangle *tex_rect); COGL_TEXTURE_DEFINE (TextureRectangle, texture_rectangle); COGL_GTYPE_DEFINE_CLASS (TextureRectangle, texture_rectangle, COGL_GTYPE_IMPLEMENT_INTERFACE (texture)); static const CoglTextureVtable cogl_texture_rectangle_vtable; static CoglBool can_use_wrap_mode (GLenum wrap_mode) { return (wrap_mode == GL_CLAMP || wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_CLAMP_TO_BORDER); } static void _cogl_texture_rectangle_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); CoglContext *ctx = tex->context; /* Only set the wrap mode if it's different from the current value to avoid too many GL calls. Texture rectangle doesn't make use of the r coordinate so we can ignore its wrap mode */ if (tex_rect->gl_legacy_texobj_wrap_mode_s != wrap_mode_s || tex_rect->gl_legacy_texobj_wrap_mode_t != wrap_mode_t) { g_assert (can_use_wrap_mode (wrap_mode_s)); g_assert (can_use_wrap_mode (wrap_mode_t)); _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, tex_rect->gl_texture, tex_rect->is_foreign); GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, wrap_mode_s) ); GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, wrap_mode_t) ); tex_rect->gl_legacy_texobj_wrap_mode_s = wrap_mode_s; tex_rect->gl_legacy_texobj_wrap_mode_t = wrap_mode_t; } } static void _cogl_texture_rectangle_free (CoglTextureRectangle *tex_rect) { if (!tex_rect->is_foreign && tex_rect->gl_texture) _cogl_delete_gl_texture (tex_rect->gl_texture); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (tex_rect)); } static CoglBool _cogl_texture_rectangle_can_create (CoglContext *ctx, unsigned int width, unsigned int height, CoglPixelFormat internal_format, CoglError **error) { GLenum gl_intformat; GLenum gl_format; GLenum gl_type; if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE)) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_TYPE, "The CoglTextureRectangle feature isn't available"); return FALSE; } ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, &gl_format, &gl_type); /* Check that the driver can create a texture with that size */ if (!ctx->texture_driver->size_supported (ctx, GL_TEXTURE_RECTANGLE_ARB, gl_intformat, gl_format, gl_type, width, height)) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE, "The requested texture size + format is unsupported"); return FALSE; } return TRUE; } static void _cogl_texture_rectangle_set_auto_mipmap (CoglTexture *tex, CoglBool value) { /* Rectangle textures currently never support mipmapping so there's no point in doing anything here */ } static CoglTextureRectangle * _cogl_texture_rectangle_create_base (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format, CoglTextureLoader *loader) { CoglTextureRectangle *tex_rect = g_new (CoglTextureRectangle, 1); CoglTexture *tex = COGL_TEXTURE (tex_rect); _cogl_texture_init (tex, ctx, width, height, internal_format, loader, &cogl_texture_rectangle_vtable); tex_rect->gl_texture = 0; tex_rect->is_foreign = FALSE; /* We default to GL_LINEAR for both filters */ tex_rect->gl_legacy_texobj_min_filter = GL_LINEAR; tex_rect->gl_legacy_texobj_mag_filter = GL_LINEAR; /* Wrap mode not yet set */ tex_rect->gl_legacy_texobj_wrap_mode_s = GL_FALSE; tex_rect->gl_legacy_texobj_wrap_mode_t = GL_FALSE; return _cogl_texture_rectangle_object_new (tex_rect); } CoglTextureRectangle * cogl_texture_rectangle_new_with_size (CoglContext *ctx, int width, int height) { CoglTextureLoader *loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED; loader->src.sized.width = width; loader->src.sized.height = height; return _cogl_texture_rectangle_create_base (ctx, width, height, COGL_PIXEL_FORMAT_RGBA_8888_PRE, loader); } static CoglBool allocate_with_size (CoglTextureRectangle *tex_rect, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_rect); CoglContext *ctx = tex->context; CoglPixelFormat internal_format; int width = loader->src.sized.width; int height = loader->src.sized.height; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; GLenum gl_texture; internal_format = _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); if (!_cogl_texture_rectangle_can_create (ctx, width, height, internal_format, error)) return FALSE; ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, &gl_format, &gl_type); gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_RECTANGLE_ARB, internal_format); _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, gl_texture, tex_rect->is_foreign); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat, width, height, 0, gl_format, gl_type, NULL); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { GE( ctx, glDeleteTextures (1, &gl_texture) ); return FALSE; } tex_rect->internal_format = internal_format; tex_rect->gl_texture = gl_texture; tex_rect->gl_format = gl_intformat; _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), internal_format, width, height); return TRUE; } static CoglBool allocate_from_bitmap (CoglTextureRectangle *tex_rect, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_rect); CoglContext *ctx = tex->context; CoglPixelFormat internal_format; CoglBitmap *bmp = loader->src.bitmap.bitmap; int width = cogl_bitmap_get_width (bmp); int height = cogl_bitmap_get_height (bmp); CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place; CoglBitmap *upload_bmp; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; internal_format = _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp)); if (!_cogl_texture_rectangle_can_create (ctx, width, height, internal_format, error)) return FALSE; upload_bmp = _cogl_bitmap_convert_for_upload (bmp, internal_format, can_convert_in_place, error); if (upload_bmp == NULL) return FALSE; ctx->driver_vtable->pixel_format_to_gl (ctx, cogl_bitmap_get_format (upload_bmp), NULL, /* internal format */ &gl_format, &gl_type); ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, NULL, NULL); tex_rect->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_RECTANGLE_ARB, internal_format); if (!ctx->texture_driver->upload_to_gl (ctx, GL_TEXTURE_RECTANGLE_ARB, tex_rect->gl_texture, FALSE, upload_bmp, gl_intformat, gl_format, gl_type, error)) { cogl_object_unref (upload_bmp); return FALSE; } tex_rect->gl_format = gl_intformat; tex_rect->internal_format = internal_format; cogl_object_unref (upload_bmp); _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), internal_format, width, height); return TRUE; } static CoglBool allocate_from_gl_foreign (CoglTextureRectangle *tex_rect, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_rect); CoglContext *ctx = tex->context; CoglPixelFormat format = loader->src.gl_foreign.format; GLint gl_compressed = GL_FALSE; GLenum gl_int_format = 0; if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_RECTANGLE_ARB)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Foreign GL_TEXTURE_RECTANGLE textures are not " "supported by your system"); return FALSE; } /* Make sure binding succeeds */ _cogl_gl_util_clear_gl_errors (ctx); _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, loader->src.gl_foreign.gl_handle, TRUE); if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Failed to bind foreign GL_TEXTURE_RECTANGLE texture"); return FALSE; } /* Obtain texture parameters */ #ifdef HAVE_COGL_GL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS)) { GLint val; GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_COMPRESSED, &gl_compressed) ); GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_INTERNAL_FORMAT, &val) ); gl_int_format = val; /* If we can query GL for the actual pixel format then we'll ignore the passed in format and use that. */ if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx, gl_int_format, &format)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Unsupported internal format for foreign texture"); return FALSE; } } else #endif { /* Otherwise we'll assume we can derive the GL format from the passed in format */ ctx->driver_vtable->pixel_format_to_gl (ctx, format, &gl_int_format, NULL, NULL); } /* Compressed texture images not supported */ if (gl_compressed == GL_TRUE) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Compressed foreign textures aren't currently supported"); return FALSE; } /* Setup bitmap info */ tex_rect->is_foreign = TRUE; tex_rect->gl_texture = loader->src.gl_foreign.gl_handle; tex_rect->gl_format = gl_int_format; /* Unknown filter */ tex_rect->gl_legacy_texobj_min_filter = GL_FALSE; tex_rect->gl_legacy_texobj_mag_filter = GL_FALSE; tex_rect->internal_format = format; _cogl_texture_set_allocated (COGL_TEXTURE (tex_rect), format, loader->src.gl_foreign.width, loader->src.gl_foreign.height); return TRUE; } static CoglBool _cogl_texture_rectangle_allocate (CoglTexture *tex, CoglError **error) { CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); CoglTextureLoader *loader = tex->loader; _COGL_RETURN_VAL_IF_FAIL (loader, FALSE); switch (loader->src_type) { case COGL_TEXTURE_SOURCE_TYPE_SIZED: return allocate_with_size (tex_rect, loader, error); case COGL_TEXTURE_SOURCE_TYPE_BITMAP: return allocate_from_bitmap (tex_rect, loader, error); case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN: return allocate_from_gl_foreign (tex_rect, loader, error); default: break; } g_return_val_if_reached (FALSE); } CoglTextureRectangle * cogl_texture_rectangle_new_from_bitmap (CoglBitmap *bmp) { CoglTextureLoader *loader; _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP; loader->src.bitmap.bitmap = cogl_object_ref (bmp); loader->src.bitmap.can_convert_in_place = FALSE; /* TODO add api for this */ return _cogl_texture_rectangle_create_base (_cogl_bitmap_get_context (bmp), cogl_bitmap_get_width (bmp), cogl_bitmap_get_height (bmp), cogl_bitmap_get_format (bmp), loader); } CoglTextureRectangle * cogl_texture_rectangle_new_from_foreign (CoglContext *ctx, unsigned int gl_handle, int width, int height, CoglPixelFormat format) { CoglTextureLoader *loader; /* NOTE: width, height and internal format are not queriable in * GLES, hence such a function prototype. Also in the case of full * opengl the user may be creating a Cogl texture for a * texture_from_pixmap object where glTexImage2D may not have been * called and the texture_from_pixmap spec doesn't clarify that it * is reliable to query back the size from OpenGL. */ /* Assert that it is a valid GL texture object */ _COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), NULL); /* Validate width and height */ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN; loader->src.gl_foreign.gl_handle = gl_handle; loader->src.gl_foreign.width = width; loader->src.gl_foreign.height = height; loader->src.gl_foreign.format = format; return _cogl_texture_rectangle_create_base (ctx, width, height, format, loader); } static int _cogl_texture_rectangle_get_max_waste (CoglTexture *tex) { return -1; } static CoglBool _cogl_texture_rectangle_is_sliced (CoglTexture *tex) { return FALSE; } static CoglBool _cogl_texture_rectangle_can_hardware_repeat (CoglTexture *tex) { return FALSE; } static void _cogl_texture_rectangle_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { *s *= tex->width; *t *= tex->height; } static CoglTransformResult _cogl_texture_rectangle_transform_quad_coords_to_gl (CoglTexture *tex, float *coords) { CoglBool need_repeat = FALSE; int i; for (i = 0; i < 4; i++) { if (coords[i] < 0.0f || coords[i] > 1.0f) need_repeat = TRUE; coords[i] *= (i & 1) ? tex->height : tex->width; } return (need_repeat ? COGL_TRANSFORM_SOFTWARE_REPEAT : COGL_TRANSFORM_NO_REPEAT); } static CoglBool _cogl_texture_rectangle_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); if (out_gl_handle) *out_gl_handle = tex_rect->gl_texture; if (out_gl_target) *out_gl_target = GL_TEXTURE_RECTANGLE_ARB; return TRUE; } static void _cogl_texture_rectangle_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); CoglContext *ctx = tex->context; if (min_filter == tex_rect->gl_legacy_texobj_min_filter && mag_filter == tex_rect->gl_legacy_texobj_mag_filter) return; /* Rectangle textures don't support mipmapping */ g_assert (min_filter == GL_LINEAR || min_filter == GL_NEAREST); /* Store new values */ tex_rect->gl_legacy_texobj_min_filter = min_filter; tex_rect->gl_legacy_texobj_mag_filter = mag_filter; /* Apply new filters to the texture */ _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, tex_rect->gl_texture, tex_rect->is_foreign); GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, mag_filter) ); GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, min_filter) ); } static void _cogl_texture_rectangle_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { /* Rectangle textures don't support mipmaps */ g_assert ((flags & COGL_TEXTURE_NEEDS_MIPMAP) == 0); } static void _cogl_texture_rectangle_ensure_non_quad_rendering (CoglTexture *tex) { /* Nothing needs to be done */ } static CoglBool _cogl_texture_rectangle_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, int level, CoglBitmap *bmp, CoglError **error) { CoglBitmap *upload_bmp; GLenum gl_format; GLenum gl_type; CoglContext *ctx = tex->context; CoglBool status; upload_bmp = _cogl_bitmap_convert_for_upload (bmp, _cogl_texture_get_format (tex), FALSE, /* can't convert in place */ error); if (upload_bmp == NULL) return FALSE; ctx->driver_vtable->pixel_format_to_gl (ctx, cogl_bitmap_get_format (upload_bmp), NULL, /* internal format */ &gl_format, &gl_type); /* Send data to GL */ status = ctx->texture_driver->upload_subregion_to_gl (ctx, tex, FALSE, src_x, src_y, dst_x, dst_y, dst_width, dst_height, level, upload_bmp, gl_format, gl_type, error); cogl_object_unref (upload_bmp); return status; } static CoglBool _cogl_texture_rectangle_get_data (CoglTexture *tex, CoglPixelFormat format, int rowstride, uint8_t *data) { CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); CoglContext *ctx = tex->context; int bpp; GLenum gl_format; GLenum gl_type; bpp = _cogl_pixel_format_get_bytes_per_pixel (format); ctx->driver_vtable->pixel_format_to_gl (ctx, format, NULL, /* internal format */ &gl_format, &gl_type); ctx->texture_driver->prep_gl_for_pixels_download (ctx, rowstride, tex->width, bpp); _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, tex_rect->gl_texture, tex_rect->is_foreign); return ctx->texture_driver->gl_get_tex_image (ctx, GL_TEXTURE_RECTANGLE_ARB, gl_format, gl_type, data); } static CoglPixelFormat _cogl_texture_rectangle_get_format (CoglTexture *tex) { return COGL_TEXTURE_RECTANGLE (tex)->internal_format; } static GLenum _cogl_texture_rectangle_get_gl_format (CoglTexture *tex) { return COGL_TEXTURE_RECTANGLE (tex)->gl_format; } static CoglBool _cogl_texture_rectangle_is_foreign (CoglTexture *tex) { return COGL_TEXTURE_RECTANGLE (tex)->is_foreign; } static CoglTextureType _cogl_texture_rectangle_get_type (CoglTexture *tex) { return COGL_TEXTURE_TYPE_RECTANGLE; } static const CoglTextureVtable cogl_texture_rectangle_vtable = { TRUE, /* primitive */ _cogl_texture_rectangle_allocate, _cogl_texture_rectangle_set_region, _cogl_texture_rectangle_get_data, NULL, /* foreach_sub_texture_in_region */ _cogl_texture_rectangle_get_max_waste, _cogl_texture_rectangle_is_sliced, _cogl_texture_rectangle_can_hardware_repeat, _cogl_texture_rectangle_transform_coords_to_gl, _cogl_texture_rectangle_transform_quad_coords_to_gl, _cogl_texture_rectangle_get_gl_texture, _cogl_texture_rectangle_gl_flush_legacy_texobj_filters, _cogl_texture_rectangle_pre_paint, _cogl_texture_rectangle_ensure_non_quad_rendering, _cogl_texture_rectangle_gl_flush_legacy_texobj_wrap_modes, _cogl_texture_rectangle_get_format, _cogl_texture_rectangle_get_gl_format, _cogl_texture_rectangle_get_type, _cogl_texture_rectangle_is_foreign, _cogl_texture_rectangle_set_auto_mipmap }; muffin-5.2.1/cogl/cogl/cogl-color-private.h0000664000175000017500000000324414211404421020670 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_COLOR_PRIVATE_PRIVATE_H #define __COGL_COLOR_PRIVATE_PRIVATE_H #include "cogl-color.h" #include /* cogl-pipeline.c wants to be able to hash CoglColor data so it needs * the exact data size to be able to avoid reading the padding bytes. */ #define _COGL_COLOR_DATA_SIZE 4 void _cogl_color_get_rgba_4ubv (const CoglColor *color, uint8_t *dest); #endif /* __COGL_COLOR_PRIVATE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-gles2-context.c0000664000175000017500000017150414211404421020600 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Tomeu Vizoso * Robert Bragg * Neil Roberts * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-gles2.h" #include "cogl-gles2-context-private.h" #include "cogl-context-private.h" #include "cogl-display-private.h" #include "cogl-framebuffer-private.h" #include "cogl-framebuffer-gl-private.h" #include "cogl-onscreen-template-private.h" #include "cogl-renderer-private.h" #include "cogl-swap-chain-private.h" #include "cogl-texture-2d-gl.h" #include "cogl-texture-2d-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" #include "cogl-gtype-private.h" static void _cogl_gles2_context_free (CoglGLES2Context *gles2_context); COGL_OBJECT_DEFINE (GLES2Context, gles2_context); COGL_GTYPE_DEFINE_CLASS (GLES2Context, gles2_context); static CoglGLES2Context *current_gles2_context; static CoglUserDataKey offscreen_wrapper_key; /* The application's main function is renamed to this so that we can * provide an alternative main function */ #define MAIN_WRAPPER_REPLACEMENT_NAME "_c31" /* This uniform is used to flip the rendering or not depending on * whether we are rendering to an offscreen buffer or not */ #define MAIN_WRAPPER_FLIP_UNIFORM "_cogl_flip_vector" /* These comments are used to delimit the added wrapper snippet so * that we can remove it again when the shader source is requested via * glGetShaderSource */ #define MAIN_WRAPPER_BEGIN "/*_COGL_WRAPPER_BEGIN*/" #define MAIN_WRAPPER_END "/*_COGL_WRAPPER_END*/" /* This wrapper function around 'main' is appended to every vertex shader * so that we can add some extra code to flip the rendering when * rendering to an offscreen buffer */ static const char main_wrapper_function[] = MAIN_WRAPPER_BEGIN "\n" "uniform vec4 " MAIN_WRAPPER_FLIP_UNIFORM ";\n" "\n" "void\n" "main ()\n" "{\n" " " MAIN_WRAPPER_REPLACEMENT_NAME " ();\n" " gl_Position *= " MAIN_WRAPPER_FLIP_UNIFORM ";\n" "}\n" MAIN_WRAPPER_END; enum { RESTORE_FB_NONE, RESTORE_FB_FROM_OFFSCREEN, RESTORE_FB_FROM_ONSCREEN, }; uint32_t _cogl_gles2_context_error_quark (void) { return g_quark_from_static_string ("cogl-gles2-context-error-quark"); } static void shader_data_unref (CoglGLES2Context *context, CoglGLES2ShaderData *shader_data) { if (--shader_data->ref_count < 1) /* Removing the hash table entry should also destroy the data */ g_hash_table_remove (context->shader_map, GINT_TO_POINTER (shader_data->object_id)); } static void program_data_unref (CoglGLES2ProgramData *program_data) { if (--program_data->ref_count < 1) /* Removing the hash table entry should also destroy the data */ g_hash_table_remove (program_data->context->program_map, GINT_TO_POINTER (program_data->object_id)); } static void detach_shader (CoglGLES2ProgramData *program_data, CoglGLES2ShaderData *shader_data) { GList *l; for (l = program_data->attached_shaders; l; l = l->next) { if (l->data == shader_data) { shader_data_unref (program_data->context, shader_data); program_data->attached_shaders = g_list_delete_link (program_data->attached_shaders, l); break; } } } static CoglBool is_symbol_character (char ch) { return g_ascii_isalnum (ch) || ch == '_'; } static void replace_token (char *string, const char *token, const char *replacement, int length) { char *token_pos; char *last_pos = string; char *end = string + length; int token_length = strlen (token); /* NOTE: this assumes token and replacement are the same length */ while ((token_pos = _cogl_util_memmem (last_pos, end - last_pos, token, token_length))) { /* Make sure this isn't in the middle of some longer token */ if ((token_pos <= string || !is_symbol_character (token_pos[-1])) && (token_pos + token_length == end || !is_symbol_character (token_pos[token_length]))) memcpy (token_pos, replacement, token_length); last_pos = token_pos + token_length; } } static void update_current_flip_state (CoglGLES2Context *gles2_ctx) { CoglGLES2FlipState new_flip_state; if (gles2_ctx->current_fbo_handle == 0 && cogl_is_offscreen (gles2_ctx->write_buffer)) new_flip_state = COGL_GLES2_FLIP_STATE_FLIPPED; else new_flip_state = COGL_GLES2_FLIP_STATE_NORMAL; /* If the flip state has changed then we need to reflush all of the * dependent state */ if (new_flip_state != gles2_ctx->current_flip_state) { gles2_ctx->viewport_dirty = TRUE; gles2_ctx->scissor_dirty = TRUE; gles2_ctx->front_face_dirty = TRUE; gles2_ctx->current_flip_state = new_flip_state; } } static GLuint get_current_texture_2d_object (CoglGLES2Context *gles2_ctx) { return g_array_index (gles2_ctx->texture_units, CoglGLES2TextureUnitData, gles2_ctx->current_texture_unit).current_texture_2d; } static void set_texture_object_data (CoglGLES2Context *gles2_ctx, GLenum target, GLint level, GLenum internal_format, GLsizei width, GLsizei height) { GLuint texture_id = get_current_texture_2d_object (gles2_ctx); CoglGLES2TextureObjectData *texture_object; /* We want to keep track of all texture objects where the data is * created by this context so that we can delete them later */ texture_object = g_hash_table_lookup (gles2_ctx->texture_object_map, GUINT_TO_POINTER (texture_id)); if (texture_object == NULL) { texture_object = g_slice_new0 (CoglGLES2TextureObjectData); texture_object->object_id = texture_id; g_hash_table_insert (gles2_ctx->texture_object_map, GUINT_TO_POINTER (texture_id), texture_object); } switch (target) { case GL_TEXTURE_2D: texture_object->target = GL_TEXTURE_2D; /* We want to keep track of the dimensions of any texture object * setting the GL_TEXTURE_2D target */ if (level == 0) { texture_object->width = width; texture_object->height = height; texture_object->format = internal_format; } break; case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: texture_object->target = GL_TEXTURE_CUBE_MAP; break; } } static void copy_flipped_texture (CoglGLES2Context *gles2_ctx, int level, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { GLuint tex_id = get_current_texture_2d_object (gles2_ctx); CoglGLES2TextureObjectData *tex_object_data; CoglContext *ctx; const CoglWinsysVtable *winsys; CoglTexture2D *dst_texture; CoglPixelFormat internal_format; tex_object_data = g_hash_table_lookup (gles2_ctx->texture_object_map, GUINT_TO_POINTER (tex_id)); /* We can't do anything if the application hasn't set a level 0 * image on this texture object */ if (tex_object_data == NULL || tex_object_data->target != GL_TEXTURE_2D || tex_object_data->width <= 0 || tex_object_data->height <= 0) return; switch (tex_object_data->format) { case GL_RGB: internal_format = COGL_PIXEL_FORMAT_RGB_888; break; case GL_RGBA: internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; break; case GL_ALPHA: internal_format = COGL_PIXEL_FORMAT_A_8; break; case GL_LUMINANCE: internal_format = COGL_PIXEL_FORMAT_G_8; break; default: /* We can't handle this format so just give up */ return; } ctx = gles2_ctx->context; winsys = ctx->display->renderer->winsys_vtable; /* We need to make sure the rendering on the GLES2 context is * complete before the blit will be ready in the GLES2 context */ ctx->glFinish (); /* We need to force Cogl to rebind the texture because according to * the GL spec a shared texture isn't guaranteed to be updated until * is rebound */ _cogl_get_texture_unit (0)->dirty_gl_texture = TRUE; /* Temporarily switch back to the Cogl context */ winsys->restore_context (ctx); dst_texture = cogl_gles2_texture_2d_new_from_handle (gles2_ctx->context, gles2_ctx, tex_id, tex_object_data->width, tex_object_data->height, internal_format); if (dst_texture) { CoglTexture *src_texture = COGL_OFFSCREEN (gles2_ctx->read_buffer)->texture; CoglPipeline *pipeline = cogl_pipeline_new (ctx); const CoglOffscreenFlags flags = COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL; CoglOffscreen *offscreen = _cogl_offscreen_new_with_texture_full (COGL_TEXTURE (dst_texture), flags, level); int src_width = cogl_texture_get_width (src_texture); int src_height = cogl_texture_get_height (src_texture); /* The framebuffer size might be different from the texture size * if a level > 0 is used */ int dst_width = cogl_framebuffer_get_width (COGL_FRAMEBUFFER (offscreen)); int dst_height = cogl_framebuffer_get_height (COGL_FRAMEBUFFER (offscreen)); float x_1, y_1, x_2, y_2, s_1, t_1, s_2, t_2; cogl_pipeline_set_layer_texture (pipeline, 0, src_texture); cogl_pipeline_set_blend (pipeline, "RGBA = ADD(SRC_COLOR, 0)", NULL); cogl_pipeline_set_layer_filters (pipeline, 0, /* layer_num */ COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); x_1 = dst_x * 2.0f / dst_width - 1.0f; y_1 = dst_y * 2.0f / dst_height - 1.0f; x_2 = x_1 + width * 2.0f / dst_width; y_2 = y_1 + height * 2.0f / dst_height; s_1 = src_x / (float) src_width; t_1 = 1.0f - src_y / (float) src_height; s_2 = (src_x + width) / (float) src_width; t_2 = 1.0f - (src_y + height) / (float) src_height; cogl_framebuffer_draw_textured_rectangle (COGL_FRAMEBUFFER (offscreen), pipeline, x_1, y_1, x_2, y_2, s_1, t_1, s_2, t_2); _cogl_framebuffer_flush_journal (COGL_FRAMEBUFFER (offscreen)); /* We need to make sure the rendering is complete before the * blit will be ready in the GLES2 context */ ctx->glFinish (); cogl_object_unref (pipeline); cogl_object_unref (dst_texture); cogl_object_unref (offscreen); } winsys->set_gles2_context (gles2_ctx, NULL); /* From what I understand of the GL spec, changes to a shared object * are not guaranteed to be propagated to another context until that * object is rebound in that context so we can just rebind it * here */ gles2_ctx->vtable->glBindTexture (GL_TEXTURE_2D, tex_id); } /* We wrap glBindFramebuffer so that when framebuffer 0 is bound * we can instead bind the write_framebuffer passed to * cogl_push_gles2_context(). */ static void gl_bind_framebuffer_wrapper (GLenum target, GLuint framebuffer) { CoglGLES2Context *gles2_ctx = current_gles2_context; gles2_ctx->current_fbo_handle = framebuffer; if (framebuffer == 0 && cogl_is_offscreen (gles2_ctx->write_buffer)) { CoglGLES2Offscreen *write = gles2_ctx->gles2_write_buffer; framebuffer = write->gl_framebuffer.fbo_handle; } gles2_ctx->context->glBindFramebuffer (target, framebuffer); update_current_flip_state (gles2_ctx); } static int transient_bind_read_buffer (CoglGLES2Context *gles2_ctx) { if (gles2_ctx->current_fbo_handle == 0) { if (cogl_is_offscreen (gles2_ctx->read_buffer)) { CoglGLES2Offscreen *read = gles2_ctx->gles2_read_buffer; GLuint read_fbo_handle = read->gl_framebuffer.fbo_handle; gles2_ctx->context->glBindFramebuffer (GL_FRAMEBUFFER, read_fbo_handle); return RESTORE_FB_FROM_OFFSCREEN; } else { _cogl_framebuffer_gl_bind (gles2_ctx->read_buffer, 0 /* target ignored */); return RESTORE_FB_FROM_ONSCREEN; } } else return RESTORE_FB_NONE; } static void restore_write_buffer (CoglGLES2Context *gles2_ctx, int restore_mode) { switch (restore_mode) { case RESTORE_FB_FROM_OFFSCREEN: gl_bind_framebuffer_wrapper (GL_FRAMEBUFFER, 0); break; case RESTORE_FB_FROM_ONSCREEN: /* Note: we can't restore the original write buffer using * _cogl_framebuffer_gl_bind() if it's an offscreen * framebuffer because _cogl_framebuffer_gl_bind() doesn't * know about the fbo handle owned by the gles2 context. */ if (cogl_is_offscreen (gles2_ctx->write_buffer)) gl_bind_framebuffer_wrapper (GL_FRAMEBUFFER, 0); else _cogl_framebuffer_gl_bind (gles2_ctx->write_buffer, GL_FRAMEBUFFER); break; case RESTORE_FB_NONE: break; } } /* We wrap glReadPixels so when framebuffer 0 is bound then we can * read from the read_framebuffer passed to cogl_push_gles2_context(). */ static void gl_read_pixels_wrapper (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { CoglGLES2Context *gles2_ctx = current_gles2_context; int restore_mode = transient_bind_read_buffer (gles2_ctx); gles2_ctx->context->glReadPixels (x, y, width, height, format, type, pixels); restore_write_buffer (gles2_ctx, restore_mode); /* If the read buffer is a CoglOffscreen then the data will be * upside down compared to what GL expects so we need to flip it */ if (gles2_ctx->current_fbo_handle == 0 && cogl_is_offscreen (gles2_ctx->read_buffer)) { int bpp, bytes_per_row, stride, y; uint8_t *bytes = pixels; uint8_t *temprow; /* Try to determine the bytes per pixel for the given * format/type combination. If there's a format which doesn't * make sense then we'll just give up because GL will probably * have just thrown an error */ switch (format) { case GL_RGB: switch (type) { case GL_UNSIGNED_BYTE: bpp = 3; break; case GL_UNSIGNED_SHORT_5_6_5: bpp = 2; break; default: return; } break; case GL_RGBA: switch (type) { case GL_UNSIGNED_BYTE: bpp = 4; break; case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_5_5_5_1: bpp = 2; break; default: return; } break; case GL_ALPHA: switch (type) { case GL_UNSIGNED_BYTE: bpp = 1; break; default: return; } break; default: return; } bytes_per_row = bpp * width; stride = ((bytes_per_row + gles2_ctx->pack_alignment - 1) & ~(gles2_ctx->pack_alignment - 1)); temprow = g_alloca (bytes_per_row); /* vertically flip the buffer in-place */ for (y = 0; y < height / 2; y++) { if (y != height - y - 1) /* skip center row */ { memcpy (temprow, bytes + y * stride, bytes_per_row); memcpy (bytes + y * stride, bytes + (height - y - 1) * stride, bytes_per_row); memcpy (bytes + (height - y - 1) * stride, temprow, bytes_per_row); } } } } static void gl_copy_tex_image_2d_wrapper (GLenum target, GLint level, GLenum internal_format, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { CoglGLES2Context *gles2_ctx = current_gles2_context; /* If we are reading from a CoglOffscreen buffer then the image will * be upside down with respect to what GL expects so we can't use * glCopyTexImage2D. Instead we we'll try to use the Cogl API to * flip it */ if (gles2_ctx->current_fbo_handle == 0 && cogl_is_offscreen (gles2_ctx->read_buffer)) { /* This will only work with the GL_TEXTURE_2D target. FIXME: * GLES2 also supports setting cube map textures with * glTexImage2D so we need to handle that too */ if (target != GL_TEXTURE_2D) return; /* Create an empty texture to hold the data */ gles2_ctx->vtable->glTexImage2D (target, level, internal_format, width, height, border, internal_format, /* format */ GL_UNSIGNED_BYTE, /* type */ NULL /* data */); copy_flipped_texture (gles2_ctx, level, x, y, /* src_x/src_y */ 0, 0, /* dst_x/dst_y */ width, height); } else { int restore_mode = transient_bind_read_buffer (gles2_ctx); gles2_ctx->context->glCopyTexImage2D (target, level, internal_format, x, y, width, height, border); restore_write_buffer (gles2_ctx, restore_mode); set_texture_object_data (gles2_ctx, target, level, internal_format, width, height); } } static void gl_copy_tex_sub_image_2d_wrapper (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { CoglGLES2Context *gles2_ctx = current_gles2_context; /* If we are reading from a CoglOffscreen buffer then the image will * be upside down with respect to what GL expects so we can't use * glCopyTexSubImage2D. Instead we we'll try to use the Cogl API to * flip it */ if (gles2_ctx->current_fbo_handle == 0 && cogl_is_offscreen (gles2_ctx->read_buffer)) { /* This will only work with the GL_TEXTURE_2D target. FIXME: * GLES2 also supports setting cube map textures with * glTexImage2D so we need to handle that too */ if (target != GL_TEXTURE_2D) return; copy_flipped_texture (gles2_ctx, level, x, y, /* src_x/src_y */ xoffset, yoffset, /* dst_x/dst_y */ width, height); } else { int restore_mode = transient_bind_read_buffer (gles2_ctx); gles2_ctx->context->glCopyTexSubImage2D (target, level, xoffset, yoffset, x, y, width, height); restore_write_buffer (gles2_ctx, restore_mode); } } static GLuint gl_create_shader_wrapper (GLenum type) { CoglGLES2Context *gles2_ctx = current_gles2_context; GLuint id; id = gles2_ctx->context->glCreateShader (type); if (id != 0) { CoglGLES2ShaderData *data = g_slice_new (CoglGLES2ShaderData); data->object_id = id; data->type = type; data->ref_count = 1; data->deleted = FALSE; g_hash_table_insert (gles2_ctx->shader_map, GINT_TO_POINTER (id), data); } return id; } static void gl_delete_shader_wrapper (GLuint shader) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ShaderData *shader_data; if ((shader_data = g_hash_table_lookup (gles2_ctx->shader_map, GINT_TO_POINTER (shader))) && !shader_data->deleted) { shader_data->deleted = TRUE; shader_data_unref (gles2_ctx, shader_data); } gles2_ctx->context->glDeleteShader (shader); } static GLuint gl_create_program_wrapper (void) { CoglGLES2Context *gles2_ctx = current_gles2_context; GLuint id; id = gles2_ctx->context->glCreateProgram (); if (id != 0) { CoglGLES2ProgramData *data = g_slice_new (CoglGLES2ProgramData); data->object_id = id; data->attached_shaders = NULL; data->ref_count = 1; data->deleted = FALSE; data->context = gles2_ctx; data->flip_vector_location = 0; data->flip_vector_state = COGL_GLES2_FLIP_STATE_UNKNOWN; g_hash_table_insert (gles2_ctx->program_map, GINT_TO_POINTER (id), data); } return id; } static void gl_delete_program_wrapper (GLuint program) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ProgramData *program_data; if ((program_data = g_hash_table_lookup (gles2_ctx->program_map, GINT_TO_POINTER (program))) && !program_data->deleted) { program_data->deleted = TRUE; program_data_unref (program_data); } gles2_ctx->context->glDeleteProgram (program); } static void gl_use_program_wrapper (GLuint program) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ProgramData *program_data; program_data = g_hash_table_lookup (gles2_ctx->program_map, GINT_TO_POINTER (program)); if (program_data) program_data->ref_count++; if (gles2_ctx->current_program) program_data_unref (gles2_ctx->current_program); gles2_ctx->current_program = program_data; gles2_ctx->context->glUseProgram (program); } static void gl_attach_shader_wrapper (GLuint program, GLuint shader) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ProgramData *program_data; CoglGLES2ShaderData *shader_data; if ((program_data = g_hash_table_lookup (gles2_ctx->program_map, GINT_TO_POINTER (program))) && (shader_data = g_hash_table_lookup (gles2_ctx->shader_map, GINT_TO_POINTER (shader))) && /* Ignore attempts to attach a shader that is already attached */ g_list_find (program_data->attached_shaders, shader_data) == NULL) { shader_data->ref_count++; program_data->attached_shaders = g_list_prepend (program_data->attached_shaders, shader_data); } gles2_ctx->context->glAttachShader (program, shader); } static void gl_detach_shader_wrapper (GLuint program, GLuint shader) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ProgramData *program_data; CoglGLES2ShaderData *shader_data; if ((program_data = g_hash_table_lookup (gles2_ctx->program_map, GINT_TO_POINTER (program))) && (shader_data = g_hash_table_lookup (gles2_ctx->shader_map, GINT_TO_POINTER (shader)))) detach_shader (program_data, shader_data); gles2_ctx->context->glDetachShader (program, shader); } static void gl_shader_source_wrapper (GLuint shader, GLsizei count, const char *const *string, const GLint *length) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ShaderData *shader_data; if ((shader_data = g_hash_table_lookup (gles2_ctx->shader_map, GINT_TO_POINTER (shader))) && shader_data->type == GL_VERTEX_SHADER) { char **string_copy = g_alloca ((count + 1) * sizeof (char *)); int *length_copy = g_alloca ((count + 1) * sizeof (int)); int i; /* Replace any occurences of the symbol 'main' with a different * symbol so that we can provide our own wrapper main * function */ for (i = 0; i < count; i++) { int string_length; if (length == NULL || length[i] < 0) string_length = strlen (string[i]); else string_length = length[i]; string_copy[i] = g_memdup (string[i], string_length); replace_token (string_copy[i], "main", MAIN_WRAPPER_REPLACEMENT_NAME, string_length); length_copy[i] = string_length; } string_copy[count] = (char *) main_wrapper_function; length_copy[count] = sizeof (main_wrapper_function) - 1; gles2_ctx->context->glShaderSource (shader, count + 1, (const char *const *) string_copy, length_copy); /* Note: we don't need to free the last entry in string_copy[] * because it is our static wrapper string... */ for (i = 0; i < count; i++) free (string_copy[i]); } else gles2_ctx->context->glShaderSource (shader, count, string, length); } static void gl_get_shader_source_wrapper (GLuint shader, GLsizei buf_size, GLsizei *length_out, GLchar *source) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ShaderData *shader_data; GLsizei length; gles2_ctx->context->glGetShaderSource (shader, buf_size, &length, source); if ((shader_data = g_hash_table_lookup (gles2_ctx->shader_map, GINT_TO_POINTER (shader))) && shader_data->type == GL_VERTEX_SHADER) { GLsizei copy_length = MIN (length, buf_size - 1); static const char wrapper_marker[] = MAIN_WRAPPER_BEGIN; char *wrapper_start; /* Strip out the wrapper snippet we added when the source was * specified */ wrapper_start = _cogl_util_memmem (source, copy_length, wrapper_marker, sizeof (wrapper_marker) - 1); if (wrapper_start) { length = wrapper_start - source; copy_length = length; *wrapper_start = '\0'; } /* Correct the name of the main function back to its original */ replace_token (source, MAIN_WRAPPER_REPLACEMENT_NAME, "main", copy_length); } if (length_out) *length_out = length; } static void gl_link_program_wrapper (GLuint program) { CoglGLES2Context *gles2_ctx = current_gles2_context; CoglGLES2ProgramData *program_data; gles2_ctx->context->glLinkProgram (program); program_data = g_hash_table_lookup (gles2_ctx->program_map, GINT_TO_POINTER (program)); if (program_data) { GLint status; gles2_ctx->context->glGetProgramiv (program, GL_LINK_STATUS, &status); if (status) program_data->flip_vector_location = gles2_ctx->context->glGetUniformLocation (program, MAIN_WRAPPER_FLIP_UNIFORM); } } static void gl_get_program_iv_wrapper (GLuint program, GLenum pname, GLint *params) { CoglGLES2Context *gles2_ctx = current_gles2_context; gles2_ctx->context->glGetProgramiv (program, pname, params); switch (pname) { case GL_ATTACHED_SHADERS: /* Decrease the number of shaders to try and hide the shader * wrapper we added */ if (*params > 1) (*params)--; break; } } static void flush_viewport_state (CoglGLES2Context *gles2_ctx) { if (gles2_ctx->viewport_dirty) { int y; if (gles2_ctx->current_flip_state == COGL_GLES2_FLIP_STATE_FLIPPED) { /* We need to know the height of the current framebuffer in * order to flip the viewport. Fortunately we don't need to * track the height of the FBOs created within the GLES2 * context because we would never be flipping if they are * bound so we can just assume Cogl's framebuffer is bound * when we are flipping */ int fb_height = cogl_framebuffer_get_height (gles2_ctx->write_buffer); y = fb_height - (gles2_ctx->viewport[1] + gles2_ctx->viewport[3]); } else y = gles2_ctx->viewport[1]; gles2_ctx->context->glViewport (gles2_ctx->viewport[0], y, gles2_ctx->viewport[2], gles2_ctx->viewport[3]); gles2_ctx->viewport_dirty = FALSE; } } static void flush_scissor_state (CoglGLES2Context *gles2_ctx) { if (gles2_ctx->scissor_dirty) { int y; if (gles2_ctx->current_flip_state == COGL_GLES2_FLIP_STATE_FLIPPED) { /* See comment above about the viewport flipping */ int fb_height = cogl_framebuffer_get_height (gles2_ctx->write_buffer); y = fb_height - (gles2_ctx->scissor[1] + gles2_ctx->scissor[3]); } else y = gles2_ctx->scissor[1]; gles2_ctx->context->glScissor (gles2_ctx->scissor[0], y, gles2_ctx->scissor[2], gles2_ctx->scissor[3]); gles2_ctx->scissor_dirty = FALSE; } } static void flush_front_face_state (CoglGLES2Context *gles2_ctx) { if (gles2_ctx->front_face_dirty) { GLenum front_face; if (gles2_ctx->current_flip_state == COGL_GLES2_FLIP_STATE_FLIPPED) { if (gles2_ctx->front_face == GL_CW) front_face = GL_CCW; else front_face = GL_CW; } else front_face = gles2_ctx->front_face; gles2_ctx->context->glFrontFace (front_face); gles2_ctx->front_face_dirty = FALSE; } } static void pre_draw_wrapper (CoglGLES2Context *gles2_ctx) { /* If there's no current program then we'll just let GL report an * error */ if (gles2_ctx->current_program == NULL) return; flush_viewport_state (gles2_ctx); flush_scissor_state (gles2_ctx); flush_front_face_state (gles2_ctx); /* We want to flip rendering when the application is rendering to a * Cogl offscreen buffer in order to maintain the flipped texture * coordinate origin */ if (gles2_ctx->current_flip_state != gles2_ctx->current_program->flip_vector_state) { GLuint location = gles2_ctx->current_program->flip_vector_location; float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; if (gles2_ctx->current_flip_state == COGL_GLES2_FLIP_STATE_FLIPPED) value[1] = -1.0f; gles2_ctx->context->glUniform4fv (location, 1, value); gles2_ctx->current_program->flip_vector_state = gles2_ctx->current_flip_state; } } static void gl_clear_wrapper (GLbitfield mask) { CoglGLES2Context *gles2_ctx = current_gles2_context; /* Clearing is affected by the scissor state so we need to ensure * that's flushed */ flush_scissor_state (gles2_ctx); gles2_ctx->context->glClear (mask); } static void gl_draw_elements_wrapper (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { CoglGLES2Context *gles2_ctx = current_gles2_context; pre_draw_wrapper (gles2_ctx); gles2_ctx->context->glDrawElements (mode, count, type, indices); } static void gl_draw_arrays_wrapper (GLenum mode, GLint first, GLsizei count) { CoglGLES2Context *gles2_ctx = current_gles2_context; pre_draw_wrapper (gles2_ctx); gles2_ctx->context->glDrawArrays (mode, first, count); } static void gl_get_program_info_log_wrapper (GLuint program, GLsizei buf_size, GLsizei *length_out, GLchar *info_log) { CoglGLES2Context *gles2_ctx = current_gles2_context; GLsizei length; gles2_ctx->context->glGetProgramInfoLog (program, buf_size, &length, info_log); replace_token (info_log, MAIN_WRAPPER_REPLACEMENT_NAME, "main", MIN (length, buf_size)); if (length_out) *length_out = length; } static void gl_get_shader_info_log_wrapper (GLuint shader, GLsizei buf_size, GLsizei *length_out, GLchar *info_log) { CoglGLES2Context *gles2_ctx = current_gles2_context; GLsizei length; gles2_ctx->context->glGetShaderInfoLog (shader, buf_size, &length, info_log); replace_token (info_log, MAIN_WRAPPER_REPLACEMENT_NAME, "main", MIN (length, buf_size)); if (length_out) *length_out = length; } static void gl_front_face_wrapper (GLenum mode) { CoglGLES2Context *gles2_ctx = current_gles2_context; /* If the mode doesn't make any sense then we'll just let the * context deal with it directly so that it will throw an error */ if (mode != GL_CW && mode != GL_CCW) gles2_ctx->context->glFrontFace (mode); else { gles2_ctx->front_face = mode; gles2_ctx->front_face_dirty = TRUE; } } static void gl_viewport_wrapper (GLint x, GLint y, GLsizei width, GLsizei height) { CoglGLES2Context *gles2_ctx = current_gles2_context; /* If the viewport is invalid then we'll just let the context deal * with it directly so that it will throw an error */ if (width < 0 || height < 0) gles2_ctx->context->glViewport (x, y, width, height); else { gles2_ctx->viewport[0] = x; gles2_ctx->viewport[1] = y; gles2_ctx->viewport[2] = width; gles2_ctx->viewport[3] = height; gles2_ctx->viewport_dirty = TRUE; } } static void gl_scissor_wrapper (GLint x, GLint y, GLsizei width, GLsizei height) { CoglGLES2Context *gles2_ctx = current_gles2_context; /* If the scissor is invalid then we'll just let the context deal * with it directly so that it will throw an error */ if (width < 0 || height < 0) gles2_ctx->context->glScissor (x, y, width, height); else { gles2_ctx->scissor[0] = x; gles2_ctx->scissor[1] = y; gles2_ctx->scissor[2] = width; gles2_ctx->scissor[3] = height; gles2_ctx->scissor_dirty = TRUE; } } static void gl_get_boolean_v_wrapper (GLenum pname, GLboolean *params) { CoglGLES2Context *gles2_ctx = current_gles2_context; switch (pname) { case GL_VIEWPORT: { int i; for (i = 0; i < 4; i++) params[i] = !!gles2_ctx->viewport[i]; } break; case GL_SCISSOR_BOX: { int i; for (i = 0; i < 4; i++) params[i] = !!gles2_ctx->scissor[i]; } break; default: gles2_ctx->context->glGetBooleanv (pname, params); } } static void gl_get_integer_v_wrapper (GLenum pname, GLint *params) { CoglGLES2Context *gles2_ctx = current_gles2_context; switch (pname) { case GL_VIEWPORT: { int i; for (i = 0; i < 4; i++) params[i] = gles2_ctx->viewport[i]; } break; case GL_SCISSOR_BOX: { int i; for (i = 0; i < 4; i++) params[i] = gles2_ctx->scissor[i]; } break; case GL_FRONT_FACE: params[0] = gles2_ctx->front_face; break; default: gles2_ctx->context->glGetIntegerv (pname, params); } } static void gl_get_float_v_wrapper (GLenum pname, GLfloat *params) { CoglGLES2Context *gles2_ctx = current_gles2_context; switch (pname) { case GL_VIEWPORT: { int i; for (i = 0; i < 4; i++) params[i] = gles2_ctx->viewport[i]; } break; case GL_SCISSOR_BOX: { int i; for (i = 0; i < 4; i++) params[i] = gles2_ctx->scissor[i]; } break; case GL_FRONT_FACE: params[0] = gles2_ctx->front_face; break; default: gles2_ctx->context->glGetFloatv (pname, params); } } static void gl_pixel_store_i_wrapper (GLenum pname, GLint param) { CoglGLES2Context *gles2_ctx = current_gles2_context; gles2_ctx->context->glPixelStorei (pname, param); if (pname == GL_PACK_ALIGNMENT && (param == 1 || param == 2 || param == 4 || param == 8)) gles2_ctx->pack_alignment = param; } static void gl_active_texture_wrapper (GLenum texture) { CoglGLES2Context *gles2_ctx = current_gles2_context; int texture_unit; gles2_ctx->context->glActiveTexture (texture); texture_unit = texture - GL_TEXTURE0; /* If the application is binding some odd looking texture unit * numbers then we'll just ignore it and hope that GL has generated * an error */ if (texture_unit >= 0 && texture_unit < 512) { gles2_ctx->current_texture_unit = texture_unit; g_array_set_size (gles2_ctx->texture_units, MAX (texture_unit, gles2_ctx->texture_units->len)); } } static void gl_delete_textures_wrapper (GLsizei n, const GLuint *textures) { CoglGLES2Context *gles2_ctx = current_gles2_context; int texture_index; int texture_unit; gles2_ctx->context->glDeleteTextures (n, textures); for (texture_index = 0; texture_index < n; texture_index++) { /* Reset any texture units that have any of these textures bound */ for (texture_unit = 0; texture_unit < gles2_ctx->texture_units->len; texture_unit++) { CoglGLES2TextureUnitData *unit = &g_array_index (gles2_ctx->texture_units, CoglGLES2TextureUnitData, texture_unit); if (unit->current_texture_2d == textures[texture_index]) unit->current_texture_2d = 0; } /* Remove the binding. We can do this immediately because unlike * shader objects the deletion isn't delayed until the object is * unbound */ g_hash_table_remove (gles2_ctx->texture_object_map, GUINT_TO_POINTER (textures[texture_index])); } } static void gl_bind_texture_wrapper (GLenum target, GLuint texture) { CoglGLES2Context *gles2_ctx = current_gles2_context; gles2_ctx->context->glBindTexture (target, texture); if (target == GL_TEXTURE_2D) { CoglGLES2TextureUnitData *unit = &g_array_index (gles2_ctx->texture_units, CoglGLES2TextureUnitData, gles2_ctx->current_texture_unit); unit->current_texture_2d = texture; } } static void gl_tex_image_2d_wrapper (GLenum target, GLint level, GLint internal_format, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { CoglGLES2Context *gles2_ctx = current_gles2_context; gles2_ctx->context->glTexImage2D (target, level, internal_format, width, height, border, format, type, pixels); set_texture_object_data (gles2_ctx, target, level, internal_format, width, height); } static void _cogl_gles2_offscreen_free (CoglGLES2Offscreen *gles2_offscreen) { _cogl_list_remove (&gles2_offscreen->link); g_slice_free (CoglGLES2Offscreen, gles2_offscreen); } static void force_delete_program_object (CoglGLES2Context *context, CoglGLES2ProgramData *program_data) { if (!program_data->deleted) { context->context->glDeleteProgram (program_data->object_id); program_data->deleted = TRUE; program_data_unref (program_data); } } static void force_delete_shader_object (CoglGLES2Context *context, CoglGLES2ShaderData *shader_data) { if (!shader_data->deleted) { context->context->glDeleteShader (shader_data->object_id); shader_data->deleted = TRUE; shader_data_unref (context, shader_data); } } static void force_delete_texture_object (CoglGLES2Context *context, CoglGLES2TextureObjectData *texture_data) { context->context->glDeleteTextures (1, &texture_data->object_id); } static void _cogl_gles2_context_free (CoglGLES2Context *gles2_context) { CoglContext *ctx = gles2_context->context; const CoglWinsysVtable *winsys; GList *objects, *l; if (gles2_context->current_program) program_data_unref (gles2_context->current_program); /* Try to forcibly delete any shaders, programs and textures so that * they won't get leaked. Because all GLES2 contexts are in the same * share list as Cogl's context these won't get deleted by default. * FIXME: we should do this for all of the other resources too, like * textures */ objects = g_hash_table_get_values (gles2_context->program_map); for (l = objects; l; l = l->next) force_delete_program_object (gles2_context, l->data); g_list_free (objects); objects = g_hash_table_get_values (gles2_context->shader_map); for (l = objects; l; l = l->next) force_delete_shader_object (gles2_context, l->data); g_list_free (objects); objects = g_hash_table_get_values (gles2_context->texture_object_map); for (l = objects; l; l = l->next) force_delete_texture_object (gles2_context, l->data); g_list_free (objects); /* All of the program and shader objects should now be destroyed */ if (g_hash_table_size (gles2_context->program_map) > 0) g_warning ("Program objects have been leaked from a CoglGLES2Context"); if (g_hash_table_size (gles2_context->shader_map) > 0) g_warning ("Shader objects have been leaked from a CoglGLES2Context"); g_hash_table_destroy (gles2_context->program_map); g_hash_table_destroy (gles2_context->shader_map); g_hash_table_destroy (gles2_context->texture_object_map); g_array_free (gles2_context->texture_units, TRUE); winsys = ctx->display->renderer->winsys_vtable; winsys->destroy_gles2_context (gles2_context); while (!_cogl_list_empty (&gles2_context->foreign_offscreens)) { CoglGLES2Offscreen *gles2_offscreen = _cogl_container_of (gles2_context->foreign_offscreens.next, CoglGLES2Offscreen, link); /* Note: this will also indirectly free the gles2_offscreen by * calling the destroy notify for the _user_data */ cogl_object_set_user_data (COGL_OBJECT (gles2_offscreen->original_offscreen), &offscreen_wrapper_key, NULL, NULL); } free (gles2_context->vtable); free (gles2_context); } static void free_shader_data (CoglGLES2ShaderData *data) { g_slice_free (CoglGLES2ShaderData, data); } static void free_program_data (CoglGLES2ProgramData *data) { while (data->attached_shaders) detach_shader (data, data->attached_shaders->data); g_slice_free (CoglGLES2ProgramData, data); } static void free_texture_object_data (CoglGLES2TextureObjectData *data) { g_slice_free (CoglGLES2TextureObjectData, data); } CoglGLES2Context * cogl_gles2_context_new (CoglContext *ctx, CoglError **error) { CoglGLES2Context *gles2_ctx; const CoglWinsysVtable *winsys; if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLES2_CONTEXT)) { _cogl_set_error (error, COGL_GLES2_CONTEXT_ERROR, COGL_GLES2_CONTEXT_ERROR_UNSUPPORTED, "Backend doesn't support creating GLES2 contexts"); return NULL; } gles2_ctx = calloc (1, sizeof (CoglGLES2Context)); gles2_ctx->context = ctx; _cogl_list_init (&gles2_ctx->foreign_offscreens); winsys = ctx->display->renderer->winsys_vtable; gles2_ctx->winsys = winsys->context_create_gles2_context (ctx, error); if (gles2_ctx->winsys == NULL) { free (gles2_ctx); return NULL; } gles2_ctx->current_flip_state = COGL_GLES2_FLIP_STATE_UNKNOWN; gles2_ctx->viewport_dirty = TRUE; gles2_ctx->scissor_dirty = TRUE; gles2_ctx->front_face_dirty = TRUE; gles2_ctx->front_face = GL_CCW; gles2_ctx->pack_alignment = 4; gles2_ctx->vtable = calloc (1, sizeof (CoglGLES2Vtable)); #define COGL_EXT_BEGIN(name, \ min_gl_major, min_gl_minor, \ gles_availability, \ extension_suffixes, extension_names) #define COGL_EXT_FUNCTION(ret, name, args) \ gles2_ctx->vtable->name = (void *) ctx->name; #define COGL_EXT_END() #include "gl-prototypes/cogl-gles2-functions.h" #undef COGL_EXT_BEGIN #undef COGL_EXT_FUNCTION #undef COGL_EXT_END gles2_ctx->vtable->glBindFramebuffer = (void *) gl_bind_framebuffer_wrapper; gles2_ctx->vtable->glReadPixels = (void *) gl_read_pixels_wrapper; gles2_ctx->vtable->glCopyTexImage2D = (void *) gl_copy_tex_image_2d_wrapper; gles2_ctx->vtable->glCopyTexSubImage2D = (void *) gl_copy_tex_sub_image_2d_wrapper; gles2_ctx->vtable->glCreateShader = gl_create_shader_wrapper; gles2_ctx->vtable->glDeleteShader = gl_delete_shader_wrapper; gles2_ctx->vtable->glCreateProgram = gl_create_program_wrapper; gles2_ctx->vtable->glDeleteProgram = gl_delete_program_wrapper; gles2_ctx->vtable->glUseProgram = gl_use_program_wrapper; gles2_ctx->vtable->glAttachShader = gl_attach_shader_wrapper; gles2_ctx->vtable->glDetachShader = gl_detach_shader_wrapper; gles2_ctx->vtable->glShaderSource = gl_shader_source_wrapper; gles2_ctx->vtable->glGetShaderSource = gl_get_shader_source_wrapper; gles2_ctx->vtable->glLinkProgram = gl_link_program_wrapper; gles2_ctx->vtable->glGetProgramiv = gl_get_program_iv_wrapper; gles2_ctx->vtable->glGetProgramInfoLog = gl_get_program_info_log_wrapper; gles2_ctx->vtable->glGetShaderInfoLog = gl_get_shader_info_log_wrapper; gles2_ctx->vtable->glClear = gl_clear_wrapper; gles2_ctx->vtable->glDrawElements = gl_draw_elements_wrapper; gles2_ctx->vtable->glDrawArrays = gl_draw_arrays_wrapper; gles2_ctx->vtable->glFrontFace = gl_front_face_wrapper; gles2_ctx->vtable->glViewport = gl_viewport_wrapper; gles2_ctx->vtable->glScissor = gl_scissor_wrapper; gles2_ctx->vtable->glGetBooleanv = gl_get_boolean_v_wrapper; gles2_ctx->vtable->glGetIntegerv = gl_get_integer_v_wrapper; gles2_ctx->vtable->glGetFloatv = gl_get_float_v_wrapper; gles2_ctx->vtable->glPixelStorei = gl_pixel_store_i_wrapper; gles2_ctx->vtable->glActiveTexture = gl_active_texture_wrapper; gles2_ctx->vtable->glDeleteTextures = gl_delete_textures_wrapper; gles2_ctx->vtable->glBindTexture = gl_bind_texture_wrapper; gles2_ctx->vtable->glTexImage2D = gl_tex_image_2d_wrapper; gles2_ctx->shader_map = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, /* key_destroy */ (GDestroyNotify) free_shader_data); gles2_ctx->program_map = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, /* key_destroy */ (GDestroyNotify) free_program_data); gles2_ctx->texture_object_map = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, /* key_destroy */ (GDestroyNotify) free_texture_object_data); gles2_ctx->texture_units = g_array_new (FALSE, /* not zero terminated */ TRUE, /* clear */ sizeof (CoglGLES2TextureUnitData)); gles2_ctx->current_texture_unit = 0; g_array_set_size (gles2_ctx->texture_units, 1); return _cogl_gles2_context_object_new (gles2_ctx); } const CoglGLES2Vtable * cogl_gles2_context_get_vtable (CoglGLES2Context *gles2_ctx) { return gles2_ctx->vtable; } /* When drawing to a CoglFramebuffer from a separate context we have * to be able to allocate ancillary buffers for that context... */ static CoglGLES2Offscreen * _cogl_gles2_offscreen_allocate (CoglOffscreen *offscreen, CoglGLES2Context *gles2_context, CoglError **error) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen); const CoglWinsysVtable *winsys; CoglError *internal_error = NULL; CoglGLES2Offscreen *gles2_offscreen; int level_width; int level_height; if (!framebuffer->allocated && !cogl_framebuffer_allocate (framebuffer, error)) { return NULL; } _cogl_list_for_each (gles2_offscreen, &gles2_context->foreign_offscreens, link) { if (gles2_offscreen->original_offscreen == offscreen) return gles2_offscreen; } winsys = _cogl_framebuffer_get_winsys (framebuffer); winsys->save_context (framebuffer->context); if (!winsys->set_gles2_context (gles2_context, &internal_error)) { winsys->restore_context (framebuffer->context); cogl_error_free (internal_error); _cogl_set_error (error, COGL_FRAMEBUFFER_ERROR, COGL_FRAMEBUFFER_ERROR_ALLOCATE, "Failed to bind gles2 context to create framebuffer"); return NULL; } gles2_offscreen = g_slice_new0 (CoglGLES2Offscreen); _cogl_texture_get_level_size (offscreen->texture, offscreen->texture_level, &level_width, &level_height, NULL); if (!_cogl_framebuffer_try_creating_gl_fbo (gles2_context->context, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &COGL_FRAMEBUFFER (offscreen)->config, offscreen->allocation_flags, &gles2_offscreen->gl_framebuffer)) { winsys->restore_context (framebuffer->context); g_slice_free (CoglGLES2Offscreen, gles2_offscreen); _cogl_set_error (error, COGL_FRAMEBUFFER_ERROR, COGL_FRAMEBUFFER_ERROR_ALLOCATE, "Failed to create an OpenGL framebuffer object"); return NULL; } winsys->restore_context (framebuffer->context); gles2_offscreen->original_offscreen = offscreen; _cogl_list_insert (&gles2_context->foreign_offscreens, &gles2_offscreen->link); /* So we avoid building up an ever growing collection of ancillary * buffers for wrapped framebuffers, we make sure that the wrappers * get freed when the original offscreen framebuffer is freed. */ cogl_object_set_user_data (COGL_OBJECT (framebuffer), &offscreen_wrapper_key, gles2_offscreen, (CoglUserDataDestroyCallback) _cogl_gles2_offscreen_free); return gles2_offscreen; } CoglBool cogl_push_gles2_context (CoglContext *ctx, CoglGLES2Context *gles2_ctx, CoglFramebuffer *read_buffer, CoglFramebuffer *write_buffer, CoglError **error) { const CoglWinsysVtable *winsys = ctx->display->renderer->winsys_vtable; CoglError *internal_error = NULL; _COGL_RETURN_VAL_IF_FAIL (gles2_ctx != NULL, FALSE); /* The read/write buffers are properties of the gles2 context and we * don't currently track the read/write buffers as part of the stack * entries so we explicitly don't allow the same context to be * pushed multiple times. */ if (g_queue_find (&ctx->gles2_context_stack, gles2_ctx)) { g_critical ("Pushing the same GLES2 context multiple times isn't " "supported"); return FALSE; } if (ctx->gles2_context_stack.length == 0) { _cogl_journal_flush (read_buffer->journal); if (write_buffer != read_buffer) _cogl_journal_flush (write_buffer->journal); winsys->save_context (ctx); } else gles2_ctx->vtable->glFlush (); if (gles2_ctx->read_buffer != read_buffer) { if (cogl_is_offscreen (read_buffer)) { gles2_ctx->gles2_read_buffer = _cogl_gles2_offscreen_allocate (COGL_OFFSCREEN (read_buffer), gles2_ctx, error); /* XXX: what consistency guarantees should this api have? * * It should be safe to return at this point but we provide * no guarantee to the caller whether their given buffers * may be referenced and old buffers unreferenced even * if the _push fails. */ if (!gles2_ctx->gles2_read_buffer) return FALSE; } else gles2_ctx->gles2_read_buffer = NULL; if (gles2_ctx->read_buffer) cogl_object_unref (gles2_ctx->read_buffer); gles2_ctx->read_buffer = cogl_object_ref (read_buffer); } if (gles2_ctx->write_buffer != write_buffer) { if (cogl_is_offscreen (write_buffer)) { gles2_ctx->gles2_write_buffer = _cogl_gles2_offscreen_allocate (COGL_OFFSCREEN (write_buffer), gles2_ctx, error); /* XXX: what consistency guarantees should this api have? * * It should be safe to return at this point but we provide * no guarantee to the caller whether their given buffers * may be referenced and old buffers unreferenced even * if the _push fails. */ if (!gles2_ctx->gles2_write_buffer) return FALSE; } else gles2_ctx->gles2_write_buffer = NULL; if (gles2_ctx->write_buffer) cogl_object_unref (gles2_ctx->write_buffer); gles2_ctx->write_buffer = cogl_object_ref (write_buffer); update_current_flip_state (gles2_ctx); } if (!winsys->set_gles2_context (gles2_ctx, &internal_error)) { winsys->restore_context (ctx); cogl_error_free (internal_error); _cogl_set_error (error, COGL_GLES2_CONTEXT_ERROR, COGL_GLES2_CONTEXT_ERROR_DRIVER, "Driver failed to make GLES2 context current"); return FALSE; } g_queue_push_tail (&ctx->gles2_context_stack, gles2_ctx); /* The last time this context was pushed may have been with a * different offscreen draw framebuffer and so if GL framebuffer 0 * is bound for this GLES2 context we may need to bind a new, * corresponding, window system framebuffer... */ if (gles2_ctx->current_fbo_handle == 0) { if (cogl_is_offscreen (gles2_ctx->write_buffer)) { CoglGLES2Offscreen *write = gles2_ctx->gles2_write_buffer; GLuint handle = write->gl_framebuffer.fbo_handle; gles2_ctx->context->glBindFramebuffer (GL_FRAMEBUFFER, handle); } } current_gles2_context = gles2_ctx; /* If this is the first time this gles2 context has been used then * we'll force the viewport and scissor to the right size. GL has * the semantics that the viewport and scissor default to the size * of the first surface the context is used with. If the first * CoglFramebuffer that this context is used with is an offscreen, * then the surface from GL's point of view will be the 1x1 dummy * surface so the viewport will be wrong. Therefore we just override * the default viewport and scissor here */ if (!gles2_ctx->has_been_bound) { int fb_width = cogl_framebuffer_get_width (write_buffer); int fb_height = cogl_framebuffer_get_height (write_buffer); gles2_ctx->vtable->glViewport (0, 0, /* x/y */ fb_width, fb_height); gles2_ctx->vtable->glScissor (0, 0, /* x/y */ fb_width, fb_height); gles2_ctx->has_been_bound = TRUE; } return TRUE; } CoglGLES2Vtable * cogl_gles2_get_current_vtable (void) { return current_gles2_context ? current_gles2_context->vtable : NULL; } void cogl_pop_gles2_context (CoglContext *ctx) { CoglGLES2Context *gles2_ctx; const CoglWinsysVtable *winsys = ctx->display->renderer->winsys_vtable; _COGL_RETURN_IF_FAIL (ctx->gles2_context_stack.length > 0); g_queue_pop_tail (&ctx->gles2_context_stack); gles2_ctx = g_queue_peek_tail (&ctx->gles2_context_stack); if (gles2_ctx) { winsys->set_gles2_context (gles2_ctx, NULL); current_gles2_context = gles2_ctx; } else { winsys->restore_context (ctx); current_gles2_context = NULL; } } CoglTexture2D * cogl_gles2_texture_2d_new_from_handle (CoglContext *ctx, CoglGLES2Context *gles2_ctx, unsigned int handle, int width, int height, CoglPixelFormat format) { return cogl_texture_2d_gl_new_from_foreign (ctx, handle, width, height, format); } CoglBool cogl_gles2_texture_get_handle (CoglTexture *texture, unsigned int *handle, unsigned int *target) { return cogl_texture_get_gl_texture (texture, handle, target); } muffin-5.2.1/cogl/cogl/cogl-macros.h0000664000175000017500000002215714211404421017372 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_MACROS_H__ #define __COGL_MACROS_H__ #include /* These macros are used to mark deprecated functions, and thus have * to be exposed in a public header. * * They are only intended for internal use and should not be used by * other projects. */ #if defined(COGL_DISABLE_DEPRECATION_WARNINGS) || defined(COGL_COMPILATION) #define COGL_DEPRECATED #define COGL_DEPRECATED_FOR(f) #define COGL_UNAVAILABLE(maj,min) #else /* COGL_DISABLE_DEPRECATION_WARNINGS */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) #define COGL_DEPRECATED __attribute__((__deprecated__)) #elif defined(_MSC_VER) && (_MSC_VER >= 1300) #define COGL_DEPRECATED __declspec(deprecated) #else #define COGL_DEPRECATED #endif #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define COGL_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead"))) #elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320) #define COGL_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead")) #else #define COGL_DEPRECATED_FOR(f) G_DEPRECATED #endif #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define COGL_UNAVAILABLE(maj,min) __attribute__((deprecated("Not available before " #maj "." #min))) #elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320) #define COGL_UNAVAILABLE(maj,min) __declspec(deprecated("is not available before " #maj "." #min)) #else #define COGL_UNAVAILABLE(maj,min) #endif #endif /* COGL_DISABLE_DEPRECATION_WARNINGS */ /** * COGL_VERSION_MIN_REQUIRED: * * A macro that should be defined by the user prior to including the * cogl.h header. * * The definition should be one of the predefined Cogl version macros, * such as: %COGL_VERSION_1_8, %COGL_VERSION_1_10, ... * * This macro defines the lower bound for the Cogl API to be used. * * If a function has been deprecated in a newer version of Cogl, it * is possible to use this symbol to avoid the compiler warnings without * disabling warnings for every deprecated function. * * Since: 1.16 */ #ifndef COGL_VERSION_MIN_REQUIRED # define COGL_VERSION_MIN_REQUIRED (COGL_VERSION_CURRENT_STABLE) #endif /** * COGL_VERSION_MAX_ALLOWED: * * A macro that should be define by the user prior to including the * cogl.h header. * * The definition should be one of the predefined Cogl version macros, * such as: %COGL_VERSION_1_0, %COGL_VERSION_1_2, ... * * This macro defines the upper bound for the Cogl API to be used. * * If a function has been introduced in a newer version of Cogl, it * is possible to use this symbol to get compiler warnings when trying * to use that function. * * Since: 1.16 */ #ifndef COGL_VERSION_MAX_ALLOWED # if COGL_VERSION_MIN_REQUIRED > COGL_VERSION_PREVIOUS_STABLE # define COGL_VERSION_MAX_ALLOWED COGL_VERSION_MIN_REQUIRED # else # define COGL_VERSION_MAX_ALLOWED COGL_VERSION_CURRENT_STABLE # endif #endif /* sanity checks */ #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_MIN_REQUIRED # error "COGL_VERSION_MAX_ALLOWED must be >= COGL_VERSION_MIN_REQUIRED" #endif #if COGL_VERSION_MIN_REQUIRED < COGL_VERSION_1_0 # error "COGL_VERSION_MIN_REQUIRED must be >= COGL_VERSION_1_0" #endif /* XXX: Every new stable minor release should add a set of macros here */ #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_0 # define COGL_DEPRECATED_IN_1_0 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_0_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_0 # define COGL_DEPRECATED_IN_1_0_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_0 # define COGL_AVAILABLE_IN_1_0 COGL_UNAVAILABLE(1, 0) #else # define COGL_AVAILABLE_IN_1_0 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_2 # define COGL_DEPRECATED_IN_1_2 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_2_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_2 # define COGL_DEPRECATED_IN_1_2_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_2 # define COGL_AVAILABLE_IN_1_2 COGL_UNAVAILABLE(1, 2) #else # define COGL_AVAILABLE_IN_1_2 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_4 # define COGL_DEPRECATED_IN_1_4 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_4_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_4 # define COGL_DEPRECATED_IN_1_4_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_4 # define COGL_AVAILABLE_IN_1_4 COGL_UNAVAILABLE(1, 4) #else # define COGL_AVAILABLE_IN_1_4 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_6 # define COGL_DEPRECATED_IN_1_6 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_6_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_6 # define COGL_DEPRECATED_IN_1_6_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_6 # define COGL_AVAILABLE_IN_1_6 COGL_UNAVAILABLE(1, 6) #else # define COGL_AVAILABLE_IN_1_6 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_8 # define COGL_DEPRECATED_IN_1_8 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_8_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_8 # define COGL_DEPRECATED_IN_1_8_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_8 # define COGL_AVAILABLE_IN_1_8 COGL_UNAVAILABLE(1, 8) #else # define COGL_AVAILABLE_IN_1_8 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_10 # define COGL_DEPRECATED_IN_1_10 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_10_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_10 # define COGL_DEPRECATED_IN_1_10_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_10 # define COGL_AVAILABLE_IN_1_10 COGL_UNAVAILABLE(1, 10) #else # define COGL_AVAILABLE_IN_1_10 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_12 # define COGL_DEPRECATED_IN_1_12 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_12_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_12 # define COGL_DEPRECATED_IN_1_12_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_12 # define COGL_AVAILABLE_IN_1_12 COGL_UNAVAILABLE(1, 12) #else # define COGL_AVAILABLE_IN_1_12 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_14 # define COGL_DEPRECATED_IN_1_14 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_14_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_14 # define COGL_DEPRECATED_IN_1_14_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_14 # define COGL_AVAILABLE_IN_1_14 COGL_UNAVAILABLE(1, 14) #else # define COGL_AVAILABLE_IN_1_14 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_16 # define COGL_DEPRECATED_IN_1_16 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_16_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_16 # define COGL_DEPRECATED_IN_1_16_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_16 # define COGL_AVAILABLE_IN_1_16 COGL_UNAVAILABLE(1, 16) #else # define COGL_AVAILABLE_IN_1_16 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_18 # define COGL_DEPRECATED_IN_1_18 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_18_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_18 # define COGL_DEPRECATED_IN_1_18_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_18 # define COGL_AVAILABLE_IN_1_18 COGL_UNAVAILABLE(1, 18) #else # define COGL_AVAILABLE_IN_1_18 #endif #if COGL_VERSION_MIN_REQUIRED >= COGL_VERSION_1_20 # define COGL_DEPRECATED_IN_1_20 COGL_DEPRECATED # define COGL_DEPRECATED_IN_1_20_FOR(f) COGL_DEPRECATED_FOR(f) #else # define COGL_DEPRECATED_IN_1_20 # define COGL_DEPRECATED_IN_1_20_FOR(f) #endif #if COGL_VERSION_MAX_ALLOWED < COGL_VERSION_1_20 # define COGL_AVAILABLE_IN_1_20 COGL_UNAVAILABLE(1, 18) #else # define COGL_AVAILABLE_IN_1_20 #endif #endif /* __COGL_MACROS_H__ */ muffin-5.2.1/cogl/cogl/cogl-glib-source.c0000664000175000017500000001250714211404421020312 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-glib-source.h" #include "cogl-poll.h" typedef struct _CoglGLibSource { GSource source; CoglRenderer *renderer; GArray *poll_fds; int poll_fds_age; int64_t expiration_time; } CoglGLibSource; static CoglBool cogl_glib_source_prepare (GSource *source, int *timeout) { CoglGLibSource *cogl_source = (CoglGLibSource *) source; CoglPollFD *poll_fds; int n_poll_fds; int64_t cogl_timeout; int age; int i; age = cogl_poll_renderer_get_info (cogl_source->renderer, &poll_fds, &n_poll_fds, &cogl_timeout); /* We have to be careful not to call g_source_add/remove_poll unless * the FDs have changed because it will cause the main loop to * immediately wake up. If we call it every time the source is * prepared it will effectively never go idle. */ if (age != cogl_source->poll_fds_age) { /* Remove any existing polls before adding the new ones */ for (i = 0; i < cogl_source->poll_fds->len; i++) { GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i); g_source_remove_poll (source, poll_fd); } g_array_set_size (cogl_source->poll_fds, n_poll_fds); for (i = 0; i < n_poll_fds; i++) { GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i); poll_fd->fd = poll_fds[i].fd; g_source_add_poll (source, poll_fd); } } cogl_source->poll_fds_age = age; /* Update the events */ for (i = 0; i < n_poll_fds; i++) { GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i); poll_fd->events = poll_fds[i].events; poll_fd->revents = 0; } if (cogl_timeout == -1) { *timeout = -1; cogl_source->expiration_time = -1; } else { /* Round up to ensure that we don't try again too early */ *timeout = (cogl_timeout + 999) / 1000; cogl_source->expiration_time = (g_source_get_time (source) + cogl_timeout); } return *timeout == 0; } static CoglBool cogl_glib_source_check (GSource *source) { CoglGLibSource *cogl_source = (CoglGLibSource *) source; int i; if (cogl_source->expiration_time >= 0 && g_source_get_time (source) >= cogl_source->expiration_time) return TRUE; for (i = 0; i < cogl_source->poll_fds->len; i++) { GPollFD *poll_fd = &g_array_index (cogl_source->poll_fds, GPollFD, i); if (poll_fd->revents != 0) return TRUE; } return FALSE; } static CoglBool cogl_glib_source_dispatch (GSource *source, GSourceFunc callback, void *user_data) { CoglGLibSource *cogl_source = (CoglGLibSource *) source; CoglPollFD *poll_fds = (CoglPollFD *) &g_array_index (cogl_source->poll_fds, GPollFD, 0); cogl_poll_renderer_dispatch (cogl_source->renderer, poll_fds, cogl_source->poll_fds->len); return TRUE; } static void cogl_glib_source_finalize (GSource *source) { CoglGLibSource *cogl_source = (CoglGLibSource *) source; g_array_free (cogl_source->poll_fds, TRUE); } static GSourceFuncs cogl_glib_source_funcs = { cogl_glib_source_prepare, cogl_glib_source_check, cogl_glib_source_dispatch, cogl_glib_source_finalize }; GSource * cogl_glib_renderer_source_new (CoglRenderer *renderer, int priority) { GSource *source; CoglGLibSource *cogl_source; source = g_source_new (&cogl_glib_source_funcs, sizeof (CoglGLibSource)); cogl_source = (CoglGLibSource *) source; cogl_source->renderer = renderer; cogl_source->poll_fds = g_array_new (FALSE, FALSE, sizeof (GPollFD)); if (priority != G_PRIORITY_DEFAULT) g_source_set_priority (source, priority); return source; } GSource * cogl_glib_source_new (CoglContext *context, int priority) { return cogl_glib_renderer_source_new (cogl_context_get_renderer (context), priority); } muffin-5.2.1/cogl/cogl/cogl-node.c0000664000175000017500000000645714211404421017033 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-node-private.h" void _cogl_pipeline_node_init (CoglNode *node) { node->parent = NULL; _cogl_list_init (&node->children); } void _cogl_pipeline_node_set_parent_real (CoglNode *node, CoglNode *parent, CoglNodeUnparentVFunc unparent, CoglBool take_strong_reference) { /* NB: the old parent may indirectly be keeping the new parent alive * so we have to ref the new parent before unrefing the old. * * Note: we take a reference here regardless of * take_strong_reference because weak children may need special * handling when the parent disposes itself which relies on a * consistent link to all weak nodes. Once the node is linked to its * parent then we remove the reference at the end if * take_strong_reference == FALSE. */ cogl_object_ref (parent); if (node->parent) unparent (node); _cogl_list_insert (&parent->children, &node->link); node->parent = parent; node->has_parent_reference = take_strong_reference; /* Now that there is a consistent parent->child link we can remove * the parent reference if no reference was requested. If it turns * out that the new parent was only being kept alive by the old * parent then it will be disposed of here. */ if (!take_strong_reference) cogl_object_unref (parent); } void _cogl_pipeline_node_unparent_real (CoglNode *node) { CoglNode *parent = node->parent; if (parent == NULL) return; _COGL_RETURN_IF_FAIL (!_cogl_list_empty (&parent->children)); _cogl_list_remove (&node->link); if (node->has_parent_reference) cogl_object_unref (parent); node->parent = NULL; } void _cogl_pipeline_node_foreach_child (CoglNode *node, CoglNodeChildCallback callback, void *user_data) { CoglNode *child, *next; _cogl_list_for_each_safe (child, next, &node->children, link) callback (child, user_data); } muffin-5.2.1/cogl/cogl/cogl-sub-texture.c0000664000175000017500000003756714211404421020403 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-texture-private.h" #include "cogl-sub-texture-private.h" #include "cogl-sub-texture.h" #include "cogl-context-private.h" #include "cogl-object.h" #include "cogl-texture-driver.h" #include "cogl-texture-rectangle-private.h" #include "cogl-texture-2d.h" #include "cogl-texture-gl-private.h" #include "cogl-gtype-private.h" #include #include static void _cogl_sub_texture_free (CoglSubTexture *sub_tex); COGL_TEXTURE_DEFINE (SubTexture, sub_texture); COGL_GTYPE_DEFINE_CLASS (SubTexture, sub_texture); static const CoglTextureVtable cogl_sub_texture_vtable; static void _cogl_sub_texture_unmap_quad (CoglSubTexture *sub_tex, float *coords) { CoglTexture *tex = COGL_TEXTURE (sub_tex); /* NB: coords[] come in as non-normalized if sub_tex->full_texture * is a CoglTextureRectangle otherwhise they are normalized. The * coordinates we write out though must always be normalized. * * NB: sub_tex->sub_x/y/width/height are in non-normalized * coordinates. */ if (cogl_is_texture_rectangle (sub_tex->full_texture)) { coords[0] = (coords[0] - sub_tex->sub_x) / tex->width; coords[1] = (coords[1] - sub_tex->sub_y) / tex->height; coords[2] = (coords[2] - sub_tex->sub_x) / tex->width; coords[3] = (coords[3] - sub_tex->sub_y) / tex->height; } else { float width = cogl_texture_get_width (sub_tex->full_texture); float height = cogl_texture_get_height (sub_tex->full_texture); coords[0] = (coords[0] * width - sub_tex->sub_x) / tex->width; coords[1] = (coords[1] * height - sub_tex->sub_y) / tex->height; coords[2] = (coords[2] * width - sub_tex->sub_x) / tex->width; coords[3] = (coords[3] * height - sub_tex->sub_y) / tex->height; } } static void _cogl_sub_texture_map_quad (CoglSubTexture *sub_tex, float *coords) { CoglTexture *tex = COGL_TEXTURE (sub_tex); /* NB: coords[] always come in as normalized coordinates but may go * out as non-normalized if sub_tex->full_texture is a * CoglTextureRectangle. * * NB: sub_tex->sub_x/y/width/height are in non-normalized * coordinates. */ if (cogl_is_texture_rectangle (sub_tex->full_texture)) { coords[0] = coords[0] * tex->width + sub_tex->sub_x; coords[1] = coords[1] * tex->height + sub_tex->sub_y; coords[2] = coords[2] * tex->width + sub_tex->sub_x; coords[3] = coords[3] * tex->height + sub_tex->sub_y; } else { float width = cogl_texture_get_width (sub_tex->full_texture); float height = cogl_texture_get_height (sub_tex->full_texture); coords[0] = (coords[0] * tex->width + sub_tex->sub_x) / width; coords[1] = (coords[1] * tex->height + sub_tex->sub_y) / height; coords[2] = (coords[2] * tex->width + sub_tex->sub_x) / width; coords[3] = (coords[3] * tex->height + sub_tex->sub_y) / height; } } typedef struct _CoglSubTextureForeachData { CoglSubTexture *sub_tex; CoglMetaTextureCallback callback; void *user_data; } CoglSubTextureForeachData; static void unmap_coords_cb (CoglTexture *slice_texture, const float *slice_texture_coords, const float *meta_coords, void *user_data) { CoglSubTextureForeachData *data = user_data; float unmapped_coords[4]; memcpy (unmapped_coords, meta_coords, sizeof (unmapped_coords)); _cogl_sub_texture_unmap_quad (data->sub_tex, unmapped_coords); data->callback (slice_texture, slice_texture_coords, unmapped_coords, data->user_data); } static void _cogl_sub_texture_foreach_sub_texture_in_region ( CoglTexture *tex, float virtual_tx_1, float virtual_ty_1, float virtual_tx_2, float virtual_ty_2, CoglMetaTextureCallback callback, void *user_data) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); CoglTexture *full_texture = sub_tex->full_texture; float mapped_coords[4] = { virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2}; float virtual_coords[4] = { virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2}; /* map the virtual coordinates to ->full_texture coordinates */ _cogl_sub_texture_map_quad (sub_tex, mapped_coords); /* TODO: Add something like cogl_is_low_level_texture() */ if (cogl_is_texture_2d (full_texture) || cogl_is_texture_rectangle (full_texture)) { callback (sub_tex->full_texture, mapped_coords, virtual_coords, user_data); } else { CoglSubTextureForeachData data; data.sub_tex = sub_tex; data.callback = callback; data.user_data = user_data; cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (full_texture), mapped_coords[0], mapped_coords[1], mapped_coords[2], mapped_coords[3], COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, unmap_coords_cb, &data); } } static void _cogl_sub_texture_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); _cogl_texture_gl_flush_legacy_texobj_wrap_modes (sub_tex->full_texture, wrap_mode_s, wrap_mode_t, wrap_mode_p); } static void _cogl_sub_texture_free (CoglSubTexture *sub_tex) { cogl_object_unref (sub_tex->next_texture); cogl_object_unref (sub_tex->full_texture); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (sub_tex)); } CoglSubTexture * cogl_sub_texture_new (CoglContext *ctx, CoglTexture *next_texture, int sub_x, int sub_y, int sub_width, int sub_height) { CoglTexture *full_texture; CoglSubTexture *sub_tex; CoglTexture *tex; unsigned int next_width, next_height; next_width = cogl_texture_get_width (next_texture); next_height = cogl_texture_get_height (next_texture); /* The region must specify a non-zero subset of the full texture */ _COGL_RETURN_VAL_IF_FAIL (sub_x >= 0 && sub_y >= 0, NULL); _COGL_RETURN_VAL_IF_FAIL (sub_width > 0 && sub_height > 0, NULL); _COGL_RETURN_VAL_IF_FAIL (sub_x + sub_width <= next_width, NULL); _COGL_RETURN_VAL_IF_FAIL (sub_y + sub_height <= next_height, NULL); sub_tex = g_new (CoglSubTexture, 1); tex = COGL_TEXTURE (sub_tex); _cogl_texture_init (tex, ctx, sub_width, sub_height, _cogl_texture_get_format (next_texture), NULL, /* no loader */ &cogl_sub_texture_vtable); /* If the next texture is also a sub texture we can avoid one level of indirection by referencing the full texture of that texture instead. */ if (cogl_is_sub_texture (next_texture)) { CoglSubTexture *other_sub_tex = COGL_SUB_TEXTURE (next_texture); full_texture = other_sub_tex->full_texture; sub_x += other_sub_tex->sub_x; sub_y += other_sub_tex->sub_y; } else full_texture = next_texture; sub_tex->next_texture = cogl_object_ref (next_texture); sub_tex->full_texture = cogl_object_ref (full_texture); sub_tex->sub_x = sub_x; sub_tex->sub_y = sub_y; return _cogl_sub_texture_object_new (sub_tex); } static CoglBool _cogl_sub_texture_allocate (CoglTexture *tex, CoglError **error) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); CoglBool status = cogl_texture_allocate (sub_tex->full_texture, error); _cogl_texture_set_allocated (tex, _cogl_texture_get_format (sub_tex->full_texture), tex->width, tex->height); return status; } CoglTexture * cogl_sub_texture_get_parent (CoglSubTexture *sub_texture) { return sub_texture->next_texture; } static int _cogl_sub_texture_get_max_waste (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); return cogl_texture_get_max_waste (sub_tex->full_texture); } static CoglBool _cogl_sub_texture_is_sliced (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); return cogl_texture_is_sliced (sub_tex->full_texture); } static CoglBool _cogl_sub_texture_can_hardware_repeat (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); /* We can hardware repeat if the subtexture actually represents all of the of the full texture */ return (tex->width == cogl_texture_get_width (sub_tex->full_texture) && tex->height == cogl_texture_get_height (sub_tex->full_texture) && _cogl_texture_can_hardware_repeat (sub_tex->full_texture)); } static void _cogl_sub_texture_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); /* This won't work if the sub texture is not the size of the full texture and the coordinates are outside the range [0,1] */ *s = ((*s * tex->width + sub_tex->sub_x) / cogl_texture_get_width (sub_tex->full_texture)); *t = ((*t * tex->height + sub_tex->sub_y) / cogl_texture_get_height (sub_tex->full_texture)); _cogl_texture_transform_coords_to_gl (sub_tex->full_texture, s, t); } static CoglTransformResult _cogl_sub_texture_transform_quad_coords_to_gl (CoglTexture *tex, float *coords) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); int i; /* We can't support repeating with this method. In this case cogl-primitives will resort to manual repeating */ for (i = 0; i < 4; i++) if (coords[i] < 0.0f || coords[i] > 1.0f) return COGL_TRANSFORM_SOFTWARE_REPEAT; _cogl_sub_texture_map_quad (sub_tex, coords); return _cogl_texture_transform_quad_coords_to_gl (sub_tex->full_texture, coords); } static CoglBool _cogl_sub_texture_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); return cogl_texture_get_gl_texture (sub_tex->full_texture, out_gl_handle, out_gl_target); } static void _cogl_sub_texture_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); _cogl_texture_gl_flush_legacy_texobj_filters (sub_tex->full_texture, min_filter, mag_filter); } static void _cogl_sub_texture_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); _cogl_texture_pre_paint (sub_tex->full_texture, flags); } static void _cogl_sub_texture_ensure_non_quad_rendering (CoglTexture *tex) { } static CoglBool _cogl_sub_texture_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, int level, CoglBitmap *bmp, CoglError **error) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); if (level != 0) { int full_width = cogl_texture_get_width (sub_tex->full_texture); int full_height = cogl_texture_get_width (sub_tex->full_texture); _COGL_RETURN_VAL_IF_FAIL (sub_tex->sub_x == 0 && cogl_texture_get_width (tex) == full_width, FALSE); _COGL_RETURN_VAL_IF_FAIL (sub_tex->sub_y == 0 && cogl_texture_get_height (tex) == full_height, FALSE); } return _cogl_texture_set_region_from_bitmap (sub_tex->full_texture, src_x, src_y, dst_width, dst_height, bmp, dst_x + sub_tex->sub_x, dst_y + sub_tex->sub_y, level, error); } static CoglPixelFormat _cogl_sub_texture_get_format (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); return _cogl_texture_get_format (sub_tex->full_texture); } static GLenum _cogl_sub_texture_get_gl_format (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); return _cogl_texture_gl_get_format (sub_tex->full_texture); } static CoglTextureType _cogl_sub_texture_get_type (CoglTexture *tex) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); return _cogl_texture_get_type (sub_tex->full_texture); } static const CoglTextureVtable cogl_sub_texture_vtable = { FALSE, /* not primitive */ _cogl_sub_texture_allocate, _cogl_sub_texture_set_region, NULL, /* get_data */ _cogl_sub_texture_foreach_sub_texture_in_region, _cogl_sub_texture_get_max_waste, _cogl_sub_texture_is_sliced, _cogl_sub_texture_can_hardware_repeat, _cogl_sub_texture_transform_coords_to_gl, _cogl_sub_texture_transform_quad_coords_to_gl, _cogl_sub_texture_get_gl_texture, _cogl_sub_texture_gl_flush_legacy_texobj_filters, _cogl_sub_texture_pre_paint, _cogl_sub_texture_ensure_non_quad_rendering, _cogl_sub_texture_gl_flush_legacy_texobj_wrap_modes, _cogl_sub_texture_get_format, _cogl_sub_texture_get_gl_format, _cogl_sub_texture_get_type, NULL, /* is_foreign */ NULL /* set_auto_mipmap */ }; muffin-5.2.1/cogl/cogl/cogl-xlib.c0000664000175000017500000000633314211404421017035 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include #include #include #include #include #include #include "cogl-xlib.h" /* FIXME: when we remove the last X11 based Clutter backend then we * will get rid of these functions and instead rely on the equivalent * _cogl_xlib_renderer API */ /* This can't be in the Cogl context because it can be set before context is created */ static Display *_cogl_xlib_display = NULL; Display * cogl_xlib_get_display (void) { _COGL_GET_CONTEXT (ctx, NULL); return cogl_xlib_renderer_get_display (ctx->display->renderer); } void cogl_xlib_set_display (Display *display) { /* This can only be called once before the Cogl context is created */ g_assert (_cogl_xlib_display == NULL); _cogl_xlib_display = display; } /* These three functions are wrappers around the equivalent renderer functions. They can be removed once all xlib-based backends in Clutter know about the renderer */ CoglFilterReturn cogl_xlib_handle_event (XEvent *xevent) { _COGL_GET_CONTEXT (ctx, COGL_FILTER_CONTINUE); /* Pass the event on to the renderer */ return cogl_xlib_renderer_handle_event (ctx->display->renderer, xevent); } void _cogl_xlib_query_damage_extension (void) { int damage_error; Display *display; _COGL_GET_CONTEXT (ctxt, NO_RETVAL); /* Check whether damage events are supported on this display */ display = cogl_xlib_renderer_get_display (ctxt->display->renderer); if (!XDamageQueryExtension (display, &ctxt->damage_base, &damage_error)) ctxt->damage_base = -1; } int _cogl_xlib_get_damage_base (void) { CoglX11Renderer *x11_renderer; _COGL_GET_CONTEXT (ctxt, -1); x11_renderer = (CoglX11Renderer *) _cogl_xlib_renderer_get_data (ctxt->display->renderer); return x11_renderer->damage_base; } muffin-5.2.1/cogl/cogl/cogl-object-private.h0000664000175000017500000004014114211404421021015 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifndef __COGL_OBJECT_PRIVATE_H #define __COGL_OBJECT_PRIVATE_H #include #include "cogl-types.h" #include "cogl-object.h" #include "cogl-debug.h" /* For compatability until all components have been converted */ typedef struct _CoglObjectClass CoglHandleClass; typedef struct _CoglObject CoglHandleObject; /* XXX: sadly we didn't fully consider when we copied the cairo API * for _set_user_data that the callback doesn't get a pointer to the * instance which is desired in most cases. This means you tend to end * up creating micro allocations for the private data just so you can * pair up the data of interest with the original instance for * identification when it is later destroyed. * * Internally we use a small hack to avoid needing these micro * allocations by actually passing the instance as a second argument * to the callback */ typedef void (*CoglUserDataDestroyInternalCallback) (void *user_data, void *instance); typedef struct _CoglObjectClass { GTypeClass base_class; const char *name; void *virt_free; void *virt_unref; } CoglObjectClass; #define COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES 2 typedef struct { CoglUserDataKey *key; void *user_data; CoglUserDataDestroyInternalCallback destroy; } CoglUserDataEntry; /* All Cogl objects inherit from this base object by adding a member: * * CoglObject _parent; * * at the top of its main structure. This structure is initialized * when you call _cogl_#type_name#_object_new (new_object); */ struct _CoglObject { CoglObjectClass *klass; /* equivalent to GTypeInstance */ CoglUserDataEntry user_data_entry[ COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES]; GArray *user_data_array; int n_user_data_entries; unsigned int ref_count; }; /* Helper macro to encapsulate the common code for COGL reference counted objects */ #ifdef COGL_OBJECT_DEBUG #define _COGL_OBJECT_DEBUG_NEW(type_name, obj) \ COGL_NOTE (OBJECT, "COGL " G_STRINGIFY (type_name) " NEW %p %i", \ (obj), (obj)->ref_count) #define _COGL_OBJECT_DEBUG_REF(type_name, object) G_STMT_START { \ CoglObject *__obj = (CoglObject *)object; \ COGL_NOTE (OBJECT, "COGL %s REF %p %i", \ (__obj)->klass->name, \ (__obj), (__obj)->ref_count); } G_STMT_END #define _COGL_OBJECT_DEBUG_UNREF(type_name, object) G_STMT_START { \ CoglObject *__obj = (CoglObject *)object; \ COGL_NOTE (OBJECT, "COGL %s UNREF %p %i", \ (__obj)->klass->name, \ (__obj), (__obj)->ref_count - 1); } G_STMT_END #define COGL_OBJECT_DEBUG_FREE(obj) \ COGL_NOTE (OBJECT, "COGL %s FREE %p", \ (obj)->klass->name, (obj)) #else /* !COGL_OBJECT_DEBUG */ #define _COGL_OBJECT_DEBUG_NEW(type_name, obj) #define _COGL_OBJECT_DEBUG_REF(type_name, obj) #define _COGL_OBJECT_DEBUG_UNREF(type_name, obj) #define COGL_OBJECT_DEBUG_FREE(obj) #endif /* COGL_OBJECT_DEBUG */ #define _COGL_GTYPE_INIT_CLASS(type_name) do { \ _cogl_##type_name##_class.base_class.g_type = cogl_##type_name##_get_gtype (); \ } while (0) #define COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ CoglObjectClass _cogl_##type_name##_class; \ static unsigned long _cogl_object_##type_name##_count; \ \ static inline void \ _cogl_object_##type_name##_inc (void) \ { \ _cogl_object_##type_name##_count++; \ } \ \ static inline void \ _cogl_object_##type_name##_dec (void) \ { \ _cogl_object_##type_name##_count--; \ } \ \ static void \ _cogl_object_##type_name##_indirect_free (CoglObject *obj) \ { \ _cogl_##type_name##_free ((Cogl##TypeName *) obj); \ _cogl_object_##type_name##_dec (); \ } \ \ static void \ _cogl_object_##type_name##_class_init (void) \ { \ _cogl_object_##type_name##_count = 0; \ \ if (_cogl_debug_instances == NULL) \ _cogl_debug_instances = \ g_hash_table_new (g_str_hash, g_str_equal); \ \ _cogl_##type_name##_class.virt_free = \ _cogl_object_##type_name##_indirect_free; \ _cogl_##type_name##_class.virt_unref = \ _cogl_object_default_unref; \ _cogl_##type_name##_class.name = "Cogl"#TypeName; \ \ g_hash_table_insert (_cogl_debug_instances, \ (void *) _cogl_##type_name##_class.name, \ &_cogl_object_##type_name##_count); \ \ { code; } \ } \ \ static Cogl##TypeName * \ _cogl_##type_name##_object_new (Cogl##TypeName *new_obj) \ { \ CoglObject *obj = (CoglObject *)&new_obj->_parent; \ obj->ref_count = 0; \ cogl_object_ref (obj); \ obj->n_user_data_entries = 0; \ obj->user_data_array = NULL; \ \ obj->klass = &_cogl_##type_name##_class; \ if (!obj->klass->virt_free) \ { \ _cogl_object_##type_name##_class_init (); \ } \ \ _cogl_object_##type_name##_inc (); \ _COGL_OBJECT_DEBUG_NEW (TypeName, obj); \ return new_obj; \ } #define COGL_OBJECT_DEFINE_WITH_CODE_GTYPE(TypeName, type_name, code) \ \ COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, \ type_name, \ do { code; } while (0); \ _COGL_GTYPE_INIT_CLASS (type_name)) \ \ CoglBool \ cogl_is_##type_name (void *object) \ { \ CoglObject *obj = object; \ \ if (object == NULL) \ return FALSE; \ \ return obj->klass == &_cogl_##type_name##_class; \ } #define COGL_OBJECT_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ CoglBool \ cogl_is_##type_name (void *object) \ { \ CoglObject *obj = object; \ \ if (object == NULL) \ return FALSE; \ \ return obj->klass == &_cogl_##type_name##_class; \ } #define COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ CoglBool \ _cogl_is_##type_name (void *object) \ { \ CoglObject *obj = object; \ \ if (object == NULL) \ return FALSE; \ \ return obj->klass == &_cogl_##type_name##_class; \ } #define COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING(type_name) \ \ void * G_GNUC_DEPRECATED \ cogl_##type_name##_ref (void *object) \ { \ if (!cogl_is_##type_name (object)) \ return NULL; \ \ _COGL_OBJECT_DEBUG_REF (TypeName, object); \ \ cogl_handle_ref (object); \ \ return object; \ } \ \ void G_GNUC_DEPRECATED \ cogl_##type_name##_unref (void *object) \ { \ if (!cogl_is_##type_name (object)) \ { \ g_warning (G_STRINGIFY (cogl_##type_name##_unref) \ ": Ignoring unref of Cogl handle " \ "due to type mismatch"); \ return; \ } \ \ _COGL_OBJECT_DEBUG_UNREF (TypeName, object); \ \ cogl_handle_unref (object); \ } #define COGL_OBJECT_DEFINE(TypeName, type_name) \ COGL_OBJECT_DEFINE_WITH_CODE_GTYPE (TypeName, type_name, (void) 0) #define COGL_OBJECT_INTERNAL_DEFINE(TypeName, type_name) \ COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE (TypeName, type_name, (void) 0) /* For temporary compatability */ #define COGL_HANDLE_INTERNAL_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE (TypeName, type_name, code) \ \ static Cogl##TypeName * \ _cogl_##type_name##_handle_new (CoglHandle handle) \ { \ return _cogl_##type_name##_object_new (handle); \ } #define COGL_HANDLE_DEFINE_WITH_CODE(TypeName, type_name, code) \ \ COGL_OBJECT_DEFINE_WITH_CODE (TypeName, type_name, code) \ \ static Cogl##TypeName * \ _cogl_##type_name##_handle_new (CoglHandle handle) \ { \ return _cogl_##type_name##_object_new (handle); \ } #define COGL_HANDLE_DEFINE(TypeName, type_name) \ COGL_HANDLE_DEFINE_WITH_CODE (TypeName, type_name, (void) 0) void _cogl_object_set_user_data (CoglObject *object, CoglUserDataKey *key, void *user_data, CoglUserDataDestroyInternalCallback destroy); void _cogl_object_default_unref (void *obj); #endif /* __COGL_OBJECT_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-onscreen.h0000664000175000017500000010235414211404421017720 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011,2012,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_ONSCREEN_H #define __COGL_ONSCREEN_H #include #include #include #include #include COGL_BEGIN_DECLS typedef struct _CoglOnscreen CoglOnscreen; #define COGL_ONSCREEN(X) ((CoglOnscreen *)(X)) /** * cogl_onscreen_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_onscreen_get_gtype (void); /** * cogl_onscreen_new: (constructor) * @context: A #CoglContext * @width: The desired framebuffer width * @height: The desired framebuffer height * * Instantiates an "unallocated" #CoglOnscreen framebuffer that may be * configured before later being allocated, either implicitly when * it is first used or explicitly via cogl_framebuffer_allocate(). * * Return value: (transfer full): A newly instantiated #CoglOnscreen framebuffer * Since: 1.8 * Stability: unstable */ CoglOnscreen * cogl_onscreen_new (CoglContext *context, int width, int height); #ifdef COGL_HAS_X11 typedef void (*CoglOnscreenX11MaskCallback) (CoglOnscreen *onscreen, uint32_t event_mask, void *user_data); /** * cogl_x11_onscreen_set_foreign_window_xid: * @onscreen: The unallocated framebuffer to associated with an X * window. * @xid: The XID of an existing X window * @update: A callback that notifies of updates to what Cogl requires * to be in the core X protocol event mask. * @user_data: user data passed to @update * * Ideally we would recommend that you let Cogl be responsible for * creating any X window required to back an onscreen framebuffer but * if you really need to target a window created manually this * function can be called before @onscreen has been allocated to set a * foreign XID for your existing X window. * * Since Cogl needs, for example, to track changes to the size of an X * window it requires that certain events be selected for via the core * X protocol. This requirement may also be changed asynchronously so * you must pass in an @update callback to inform you of Cogl's * required event mask. * * For example if you are using Xlib you could use this API roughly * as follows: * [{ * static void * my_update_cogl_x11_event_mask (CoglOnscreen *onscreen, * uint32_t event_mask, * void *user_data) * { * XSetWindowAttributes attrs; * MyData *data = user_data; * attrs.event_mask = event_mask | data->my_event_mask; * XChangeWindowAttributes (data->xdpy, * data->xwin, * CWEventMask, * &attrs); * } * * { * *snip* * cogl_x11_onscreen_set_foreign_window_xid (onscreen, * data->xwin, * my_update_cogl_x11_event_mask, * data); * *snip* * } * }] * * Since: 2.0 * Stability: Unstable */ void cogl_x11_onscreen_set_foreign_window_xid (CoglOnscreen *onscreen, uint32_t xid, CoglOnscreenX11MaskCallback update, void *user_data); /** * cogl_x11_onscreen_get_window_xid: * @onscreen: A #CoglOnscreen framebuffer * * Assuming you know the given @onscreen framebuffer is based on an x11 window * this queries the XID of that window. If * cogl_x11_onscreen_set_foreign_window_xid() was previously called then it * will return that same XID otherwise it will be the XID of a window Cogl * created internally. If the window has not been allocated yet and a foreign * xid has not been set then it's undefined what value will be returned. * * It's undefined what this function does if called when not using an x11 based * renderer. * * Since: 1.10 * Stability: unstable */ uint32_t cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen); /* XXX: we should maybe remove this, since nothing currently uses * it and the current implementation looks dubious. */ uint32_t cogl_x11_onscreen_get_visual_xid (CoglOnscreen *onscreen); #endif /* COGL_HAS_X11 */ /** * cogl_onscreen_set_swap_throttled: * @onscreen: A #CoglOnscreen framebuffer * @throttled: Whether swap throttling is wanted or not. * * Requests that the given @onscreen framebuffer should have swap buffer * requests (made using cogl_onscreen_swap_buffers()) throttled either by a * displays vblank period or perhaps some other mechanism in a composited * environment. * * Since: 1.8 * Stability: unstable */ void cogl_onscreen_set_swap_throttled (CoglOnscreen *onscreen, CoglBool throttled); /** * cogl_onscreen_show: * @onscreen: The onscreen framebuffer to make visible * * This requests to make @onscreen visible to the user. * * Actually the precise semantics of this function depend on the * window system currently in use, and if you don't have a * multi-windowining system this function may in-fact do nothing. * * This function will implicitly allocate the given @onscreen * framebuffer before showing it if it hasn't already been allocated. * * When using the Wayland winsys calling this will set the surface to * a toplevel type which will make it appear. If the application wants * to set a different type for the surface, it can avoid calling * cogl_onscreen_show() and set its own type directly with the Wayland * client API via cogl_wayland_onscreen_get_surface(). * * Since Cogl doesn't explicitly track the visibility status of * onscreen framebuffers it wont try to avoid redundant window system * requests e.g. to show an already visible window. This also means * that it's acceptable to alternatively use native APIs to show and * hide windows without confusing Cogl. * * Since: 2.0 * Stability: Unstable */ void cogl_onscreen_show (CoglOnscreen *onscreen); /** * cogl_onscreen_hide: * @onscreen: The onscreen framebuffer to make invisible * * This requests to make @onscreen invisible to the user. * * Actually the precise semantics of this function depend on the * window system currently in use, and if you don't have a * multi-windowining system this function may in-fact do nothing. * * This function does not implicitly allocate the given @onscreen * framebuffer before hiding it. * * Since Cogl doesn't explicitly track the visibility status of * onscreen framebuffers it wont try to avoid redundant window system * requests e.g. to show an already visible window. This also means * that it's acceptable to alternatively use native APIs to show and * hide windows without confusing Cogl. * * Since: 2.0 * Stability: Unstable */ void cogl_onscreen_hide (CoglOnscreen *onscreen); /** * cogl_onscreen_swap_buffers: * @onscreen: A #CoglOnscreen framebuffer * * Swaps the current back buffer being rendered too, to the front for display. * * This function also implicitly discards the contents of the color, depth and * stencil buffers as if cogl_framebuffer_discard_buffers() were used. The * significance of the discard is that you should not expect to be able to * start a new frame that incrementally builds on the contents of the previous * frame. * * It is highly recommended that applications use * cogl_onscreen_swap_buffers_with_damage() instead whenever possible * and also use the cogl_onscreen_get_buffer_age() api so they can * perform incremental updates to older buffers instead of having to * render a full buffer for every frame. * * Since: 1.10 * Stability: unstable */ void cogl_onscreen_swap_buffers (CoglOnscreen *onscreen); /** * cogl_onscreen_get_buffer_age: * @onscreen: A #CoglOnscreen framebuffer * * Gets the current age of the buffer contents. * * This function allows applications to query the age of the current * back buffer contents for a #CoglOnscreen as the number of frames * elapsed since the contents were most recently defined. * * These age values exposes enough information to applications about * how Cogl internally manages back buffers to allow applications to * re-use the contents of old frames and minimize how much must be * redrawn for the next frame. * * The back buffer contents can either be reported as invalid (has an * age of 0) or it may be reported to be the same contents as from n * frames prior to the current frame. * * The queried value remains valid until the next buffer swap. * * One caveat is that under X11 the buffer age does not reflect * changes to buffer contents caused by the window systems. X11 * applications must track Expose events to determine what buffer * regions need to additionally be repaired each frame. * * The recommended way to take advantage of this buffer age api is to * build up a circular buffer of length 3 for tracking damage regions * over the last 3 frames and when starting a new frame look at the * age of the buffer and combine the damage regions for the current * frame with the damage regions of previous @age frames so you know * everything that must be redrawn to update the old contents for the * new frame. * * If the system doesn't not support being able to track the age * of back buffers then this function will always return 0 which * implies that the contents are undefined. * * The %COGL_FEATURE_ID_BUFFER_AGE feature can optionally be * explicitly checked to determine if Cogl is currently tracking the * age of #CoglOnscreen back buffer contents. If this feature is * missing then this function will always return 0. * * Return value: The age of the buffer contents or 0 when the buffer * contents are undefined. * * Since: 1.14 * Stability: stable */ int cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen); /** * cogl_onscreen_swap_buffers_with_damage: * @onscreen: A #CoglOnscreen framebuffer * @rectangles: An array of integer 4-tuples representing damaged * rectangles as (x, y, width, height) tuples. * @n_rectangles: The number of 4-tuples to be read from @rectangles * * Swaps the current back buffer being rendered too, to the front for * display and provides information to any system compositor about * what regions of the buffer have changed (damage) with respect to * the last swapped buffer. * * This function has the same semantics as * cogl_framebuffer_swap_buffers() except that it additionally allows * applications to pass a list of damaged rectangles which may be * passed on to a compositor so that it can minimize how much of the * screen is redrawn in response to this applications newly swapped * front buffer. * * For example if your application is only animating a small object in * the corner of the screen and everything else is remaining static * then it can help the compositor to know that only the bottom right * corner of your newly swapped buffer has really changed with respect * to your previously swapped front buffer. * * If @n_rectangles is 0 then the whole buffer will implicitly be * reported as damaged as if cogl_onscreen_swap_buffers() had been * called. * * This function also implicitly discards the contents of the color, * depth and stencil buffers as if cogl_framebuffer_discard_buffers() * were used. The significance of the discard is that you should not * expect to be able to start a new frame that incrementally builds on * the contents of the previous frame. If you want to perform * incremental updates to older back buffers then please refer to the * cogl_onscreen_get_buffer_age() api. * * Whenever possible it is recommended that applications use this * function instead of cogl_onscreen_swap_buffers() to improve * performance when running under a compositor. * * It is highly recommended to use this API in conjunction with * the cogl_onscreen_get_buffer_age() api so that your application can * perform incremental rendering based on old back buffers. * * Since: 1.16 * Stability: unstable */ void cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles); /** * cogl_onscreen_swap_region: * @onscreen: A #CoglOnscreen framebuffer * @rectangles: An array of integer 4-tuples representing rectangles as * (x, y, width, height) tuples. * @n_rectangles: The number of 4-tuples to be read from @rectangles * * Swaps a region of the back buffer being rendered too, to the front for * display. @rectangles represents the region as array of @n_rectangles each * defined by 4 sequential (x, y, width, height) integers. * * This function also implicitly discards the contents of the color, depth and * stencil buffers as if cogl_framebuffer_discard_buffers() were used. The * significance of the discard is that you should not expect to be able to * start a new frame that incrementally builds on the contents of the previous * frame. * * Since: 1.10 * Stability: unstable */ void cogl_onscreen_swap_region (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles); /** * CoglFrameEvent: * @COGL_FRAME_EVENT_SYNC: Notifies that the system compositor has * acknowledged a frame and is ready for a * new frame to be created. * @COGL_FRAME_EVENT_COMPLETE: Notifies that a frame has ended. This * is a good time for applications to * collect statistics about the frame * since the #CoglFrameInfo should hold * the most data at this point. No other * events should be expected after a * @COGL_FRAME_EVENT_COMPLETE event. * * Identifiers that are passed to #CoglFrameCallback functions * (registered using cogl_onscreen_add_frame_callback()) that * mark the progression of a frame in some way which usually * means that new information will have been accumulated in the * frame's corresponding #CoglFrameInfo object. * * The last event that will be sent for a frame will be a * @COGL_FRAME_EVENT_COMPLETE event and so these are a good * opportunity to collect statistics about a frame since the * #CoglFrameInfo should hold the most data at this point. * * A frame may not be completed before the next frame can start * so applications should avoid needing to collect all statistics for * a particular frame before they can start a new frame. * * Since: 1.14 * Stability: unstable */ typedef enum _CoglFrameEvent { COGL_FRAME_EVENT_SYNC = 1, COGL_FRAME_EVENT_COMPLETE } CoglFrameEvent; /** * CoglFrameCallback: * @onscreen: The onscreen that the frame is associated with * @event: A #CoglFrameEvent notifying how the frame has progressed * @info: The meta information, such as timing information, about * the frame that has progressed. * @user_data: The user pointer passed to * cogl_onscreen_add_frame_callback() * * Is a callback that can be registered via * cogl_onscreen_add_frame_callback() to be called when a frame * progresses in some notable way. * * Please see the documentation for #CoglFrameEvent and * cogl_onscreen_add_frame_callback() for more details about what * events can be notified. * * Since: 1.14 * Stability: unstable */ typedef void (*CoglFrameCallback) (CoglOnscreen *onscreen, CoglFrameEvent event, CoglFrameInfo *info, void *user_data); /** * CoglFrameClosure: * * An opaque type that tracks a #CoglFrameCallback and associated user * data. A #CoglFrameClosure pointer will be returned from * cogl_onscreen_add_frame_callback() and it allows you to remove a * callback later using cogl_onscreen_remove_frame_callback(). * * Since: 1.14 * Stability: unstable */ typedef struct _CoglClosure CoglFrameClosure; /** * cogl_frame_closure_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_frame_closure_get_gtype (void); /** * cogl_onscreen_add_frame_callback: * @onscreen: A #CoglOnscreen framebuffer * @callback: (scope notified): A callback function to call for frame events * @user_data: (closure): A private pointer to be passed to @callback * @destroy: (allow-none): An optional callback to destroy @user_data * when the @callback is removed or @onscreen is freed. * * Installs a @callback function that will be called for significant * events relating to the given @onscreen framebuffer. * * The @callback will be used to notify when the system compositor is * ready for this application to render a new frame. In this case * %COGL_FRAME_EVENT_SYNC will be passed as the event argument to the * given @callback in addition to the #CoglFrameInfo corresponding to * the frame beeing acknowledged by the compositor. * * The @callback will also be called to notify when the frame has * ended. In this case %COGL_FRAME_EVENT_COMPLETE will be passed as * the event argument to the given @callback in addition to the * #CoglFrameInfo corresponding to the newly presented frame. The * meaning of "ended" here simply means that no more timing * information will be collected within the corresponding * #CoglFrameInfo and so this is a good opportunity to analyse the * given info. It does not necessarily mean that the GPU has finished * rendering the corresponding frame. * * We highly recommend throttling your application according to * %COGL_FRAME_EVENT_SYNC events so that your application can avoid * wasting resources, drawing more frames than your system compositor * can display. * * Return value: a #CoglFrameClosure pointer that can be used to * remove the callback and associated @user_data later. * Since: 1.14 * Stability: unstable */ CoglFrameClosure * cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen, CoglFrameCallback callback, void *user_data, CoglUserDataDestroyCallback destroy); /** * cogl_onscreen_remove_frame_callback: * @onscreen: A #CoglOnscreen * @closure: A #CoglFrameClosure returned from * cogl_onscreen_add_frame_callback() * * Removes a callback and associated user data that were previously * registered using cogl_onscreen_add_frame_callback(). * * If a destroy callback was passed to * cogl_onscreen_add_frame_callback() to destroy the user data then * this will get called. * * Since: 1.14 * Stability: unstable */ void cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen, CoglFrameClosure *closure); typedef void (*CoglSwapBuffersNotify) (CoglFramebuffer *framebuffer, void *user_data); /** * cogl_onscreen_add_swap_buffers_callback: * @onscreen: A #CoglOnscreen framebuffer * @callback: (scope notified): A callback function to call when a swap * has completed * @user_data: (closure): A private pointer to be passed to @callback * * Installs a @callback function that should be called whenever a swap buffers * request (made using cogl_onscreen_swap_buffers()) for the given * @onscreen completes. * * Applications should check for the %COGL_FEATURE_ID_SWAP_BUFFERS_EVENT * feature before using this API. It's currently undefined when and if * registered callbacks will be called if this feature is not supported. * * We recommend using this mechanism when available to manually throttle your * applications (in conjunction with cogl_onscreen_set_swap_throttled()) so * your application will be able to avoid long blocks in the driver caused by * throttling when you request to swap buffers too quickly. * * Return value: a unique identifier that can be used to remove to remove * the callback later. * Since: 1.10 * Stability: unstable * Deprecated: 1.14: Use cogl_onscreen_add_frame_callback() instead */ COGL_DEPRECATED_IN_1_14_FOR (cogl_onscreen_add_frame_callback) unsigned int cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen, CoglSwapBuffersNotify callback, void *user_data); /** * cogl_onscreen_remove_swap_buffers_callback: * @onscreen: A #CoglOnscreen framebuffer * @id: An identifier returned from cogl_onscreen_add_swap_buffers_callback() * * Removes a callback that was previously registered * using cogl_onscreen_add_swap_buffers_callback(). * * Since: 1.10 * Stability: unstable * Deprecated: 1.14: Use cogl_onscreen_remove_frame_callback() instead */ COGL_DEPRECATED_IN_1_14_FOR (cogl_onscreen_remove_frame_callback) void cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen, unsigned int id); /** * cogl_onscreen_set_resizable: * @onscreen: A #CoglOnscreen framebuffer * * Lets you request Cogl to mark an @onscreen framebuffer as * resizable or not. * * By default, if possible, a @onscreen will be created by Cogl * as non resizable, but it is not guaranteed that this is always * possible for all window systems. * * Cogl does not know whether marking the @onscreen framebuffer * is truly meaningful for your current window system (consider * applications being run fullscreen on a phone or TV) so this * function may not have any useful effect. If you are running on a * multi windowing system such as X11 or Win32 or OSX then Cogl will * request to the window system that users be allowed to resize the * @onscreen, although it's still possible that some other window * management policy will block this possibility. * * Whenever an @onscreen framebuffer is resized the viewport * will be automatically updated to match the new size of the * framebuffer with an origin of (0,0). If your application needs more * specialized control of the viewport it will need to register a * resize handler using cogl_onscreen_add_resize_callback() so that it * can track when the viewport has been changed automatically. * * Since: 2.0 */ void cogl_onscreen_set_resizable (CoglOnscreen *onscreen, CoglBool resizable); /** * cogl_onscreen_get_resizable: * @onscreen: A #CoglOnscreen framebuffer * * Lets you query whether @onscreen has been marked as resizable via * the cogl_onscreen_set_resizable() api. * * By default, if possible, a @onscreen will be created by Cogl * as non resizable, but it is not guaranteed that this is always * possible for all window systems. * * If cogl_onscreen_set_resizable(@onscreen, %TRUE) has been * previously called then this function will return %TRUE, but it's * possible that the current windowing system being used does not * support window resizing (consider fullscreen windows on a phone or * a TV). This function is not aware of whether resizing is truly * meaningful with your window system, only whether the @onscreen has * been marked as resizable. * * Return value: Returns whether @onscreen has been marked as * resizable or not. * Since: 2.0 */ CoglBool cogl_onscreen_get_resizable (CoglOnscreen *onscreen); /** * CoglOnscreenResizeCallback: * @onscreen: A #CoglOnscreen framebuffer that was resized * @width: The new width of @onscreen * @height: The new height of @onscreen * @user_data: The private passed to * cogl_onscreen_add_resize_callback() * * Is a callback type used with the * cogl_onscreen_add_resize_callback() allowing applications to be * notified whenever an @onscreen framebuffer is resized. * * Cogl automatically updates the viewport of an @onscreen * framebuffer that is resized so this callback is also an indication * that the viewport has been modified too * * A resize callback will only ever be called while dispatching * Cogl events from the system mainloop; so for example during * cogl_poll_renderer_dispatch(). This is so that callbacks shouldn't * occur while an application might have arbitrary locks held for * example. * * Since: 2.0 */ typedef void (*CoglOnscreenResizeCallback) (CoglOnscreen *onscreen, int width, int height, void *user_data); /** * CoglOnscreenResizeClosure: * * An opaque type that tracks a #CoglOnscreenResizeCallback and * associated user data. A #CoglOnscreenResizeClosure pointer will be * returned from cogl_onscreen_add_resize_callback() and it allows you * to remove a callback later using * cogl_onscreen_remove_resize_callback(). * * Since: 2.0 * Stability: unstable */ typedef struct _CoglClosure CoglOnscreenResizeClosure; /** * cogl_onscreen_resize_closure_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_onscreen_resize_closure_get_gtype (void); /** * cogl_onscreen_add_resize_callback: * @onscreen: A #CoglOnscreen framebuffer * @callback: (scope notified): A #CoglOnscreenResizeCallback to call when * the @onscreen changes size. * @user_data: (closure): Private data to be passed to @callback. * @destroy: (allow-none): An optional callback to destroy @user_data * when the @callback is removed or @onscreen is freed. * * Registers a @callback with @onscreen that will be called whenever * the @onscreen framebuffer changes size. * * The @callback can be removed using * cogl_onscreen_remove_resize_callback() passing the returned closure * pointer. * * Since Cogl automatically updates the viewport of an @onscreen * framebuffer that is resized, a resize callback can also be used to * track when the viewport has been changed automatically by Cogl in * case your application needs more specialized control over the * viewport. * * A resize callback will only ever be called while dispatching * Cogl events from the system mainloop; so for example during * cogl_poll_renderer_dispatch(). This is so that callbacks shouldn't * occur while an application might have arbitrary locks held for * example. * * Return value: a #CoglOnscreenResizeClosure pointer that can be used to * remove the callback and associated @user_data later. * Since: 2.0 */ CoglOnscreenResizeClosure * cogl_onscreen_add_resize_callback (CoglOnscreen *onscreen, CoglOnscreenResizeCallback callback, void *user_data, CoglUserDataDestroyCallback destroy); /** * cogl_onscreen_remove_resize_callback: * @onscreen: A #CoglOnscreen framebuffer * @closure: An identifier returned from cogl_onscreen_add_resize_callback() * * Removes a resize @callback and @user_data pair that were previously * associated with @onscreen via cogl_onscreen_add_resize_callback(). * * Since: 2.0 */ void cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen, CoglOnscreenResizeClosure *closure); /** * CoglOnscreenDirtyInfo: * @x: Left edge of the dirty rectangle * @y: Top edge of the dirty rectangle, measured from the top of the window * @width: Width of the dirty rectangle * @height: Height of the dirty rectangle * * A structure passed to callbacks registered using * cogl_onscreen_add_dirty_callback(). The members describe a * rectangle within the onscreen buffer that should be redrawn. * * Since: 1.16 * Stability: unstable */ typedef struct _CoglOnscreenDirtyInfo CoglOnscreenDirtyInfo; struct _CoglOnscreenDirtyInfo { int x, y; int width, height; }; /** * CoglOnscreenDirtyCallback: * @onscreen: The onscreen that the frame is associated with * @info: A #CoglOnscreenDirtyInfo struct containing the details of the * dirty area * @user_data: The user pointer passed to * cogl_onscreen_add_frame_callback() * * Is a callback that can be registered via * cogl_onscreen_add_dirty_callback() to be called when the windowing * system determines that a region of the onscreen window has been * lost and the application should redraw it. * * Since: 1.16 * Stability: unstable */ typedef void (*CoglOnscreenDirtyCallback) (CoglOnscreen *onscreen, const CoglOnscreenDirtyInfo *info, void *user_data); /** * CoglOnscreenDirtyClosure: * * An opaque type that tracks a #CoglOnscreenDirtyCallback and associated * user data. A #CoglOnscreenDirtyClosure pointer will be returned from * cogl_onscreen_add_dirty_callback() and it allows you to remove a * callback later using cogl_onscreen_remove_dirty_callback(). * * Since: 1.16 * Stability: unstable */ typedef struct _CoglClosure CoglOnscreenDirtyClosure; /** * cogl_onscreen_dirty_closure_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_onscreen_dirty_closure_get_gtype (void); /** * cogl_onscreen_add_dirty_callback: * @onscreen: A #CoglOnscreen framebuffer * @callback: (scope notified): A callback function to call for dirty events * @user_data: (closure): A private pointer to be passed to @callback * @destroy: (allow-none): An optional callback to destroy @user_data when the * @callback is removed or @onscreen is freed. * * Installs a @callback function that will be called whenever the * window system has lost the contents of a region of the onscreen * buffer and the application should redraw it to repair the buffer. * For example this may happen in a window system without a compositor * if a window that was previously covering up the onscreen window has * been moved causing a region of the onscreen to be exposed. * * The @callback will be passed a #CoglOnscreenDirtyInfo struct which * decribes a rectangle containing the newly dirtied region. Note that * this may be called multiple times to describe a non-rectangular * region composed of multiple smaller rectangles. * * The dirty events are separate from %COGL_FRAME_EVENT_SYNC events so * the application should also listen for this event before rendering * the dirty region to ensure that the framebuffer is actually ready * for rendering. * * Return value: a #CoglOnscreenDirtyClosure pointer that can be used to * remove the callback and associated @user_data later. * Since: 1.16 * Stability: unstable */ CoglOnscreenDirtyClosure * cogl_onscreen_add_dirty_callback (CoglOnscreen *onscreen, CoglOnscreenDirtyCallback callback, void *user_data, CoglUserDataDestroyCallback destroy); /** * cogl_onscreen_remove_dirty_callback: * @onscreen: A #CoglOnscreen * @closure: A #CoglOnscreenDirtyClosure returned from * cogl_onscreen_add_dirty_callback() * * Removes a callback and associated user data that were previously * registered using cogl_onscreen_add_dirty_callback(). * * If a destroy callback was passed to * cogl_onscreen_add_dirty_callback() to destroy the user data then * this will also get called. * * Since: 1.16 * Stability: unstable */ void cogl_onscreen_remove_dirty_callback (CoglOnscreen *onscreen, CoglOnscreenDirtyClosure *closure); /** * cogl_is_onscreen: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglOnscreen. * * Return value: %TRUE if the object references a #CoglOnscreen * and %FALSE otherwise. * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_onscreen (void *object); /** * cogl_onscreen_get_frame_counter: * * Gets the value of the framebuffers frame counter. This is * a counter that increases by one each time * cogl_onscreen_swap_buffers() or cogl_onscreen_swap_region() * is called. * * Return value: the current frame counter value * Since: 1.14 * Stability: unstable */ int64_t cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen); COGL_END_DECLS #endif /* __COGL_ONSCREEN_H */ muffin-5.2.1/cogl/cogl/cogl-attribute-buffer.c0000664000175000017500000000656414211404421021357 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-object-private.h" #include "cogl-attribute-buffer.h" #include "cogl-attribute-buffer-private.h" #include "cogl-context-private.h" #include "cogl-gtype-private.h" static void _cogl_attribute_buffer_free (CoglAttributeBuffer *array); COGL_BUFFER_DEFINE (AttributeBuffer, attribute_buffer); COGL_GTYPE_DEFINE_CLASS (AttributeBuffer, attribute_buffer); CoglAttributeBuffer * cogl_attribute_buffer_new_with_size (CoglContext *context, size_t bytes) { CoglAttributeBuffer *buffer = g_slice_new (CoglAttributeBuffer); /* parent's constructor */ _cogl_buffer_initialize (COGL_BUFFER (buffer), context, bytes, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER, COGL_BUFFER_UPDATE_HINT_STATIC); return _cogl_attribute_buffer_object_new (buffer); } CoglAttributeBuffer * cogl_attribute_buffer_new (CoglContext *context, size_t bytes, const void *data) { CoglAttributeBuffer *buffer; buffer = cogl_attribute_buffer_new_with_size (context, bytes); /* Note: to keep the common cases simple this API doesn't throw * CoglErrors, so developers can assume this function never returns * NULL and we will simply abort on error. * * Developers wanting to catch errors can use * cogl_attribute_buffer_new_with_size() and catch errors when later * calling cogl_buffer_set_data() or cogl_buffer_map(). */ /* XXX: NB: for Cogl 2.0 we don't allow NULL data here but we can't * break the api for 1.x and so we keep the check for now. */ if (data) _cogl_buffer_set_data (COGL_BUFFER (buffer), 0, data, bytes, NULL); return buffer; } static void _cogl_attribute_buffer_free (CoglAttributeBuffer *array) { /* parent's destructor */ _cogl_buffer_fini (COGL_BUFFER (array)); g_slice_free (CoglAttributeBuffer, array); } muffin-5.2.1/cogl/cogl/cogl-framebuffer-private.h0000664000175000017500000004271514211404421022044 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_FRAMEBUFFER_PRIVATE_H #define __COGL_FRAMEBUFFER_PRIVATE_H #include "cogl-object-private.h" #include "cogl-matrix-stack-private.h" #include "cogl-journal-private.h" #include "cogl-winsys-private.h" #include "cogl-attribute-private.h" #include "cogl-offscreen.h" #include "cogl-gl-header.h" #include "cogl-clip-stack.h" #ifdef COGL_HAS_XLIB_SUPPORT #include #endif #ifdef COGL_HAS_GLX_SUPPORT #include #include #endif typedef enum _CoglFramebufferType { COGL_FRAMEBUFFER_TYPE_ONSCREEN, COGL_FRAMEBUFFER_TYPE_OFFSCREEN } CoglFramebufferType; typedef struct { CoglSwapChain *swap_chain; CoglBool need_stencil; int samples_per_pixel; CoglBool swap_throttled; CoglBool depth_texture_enabled; CoglBool stereo_enabled; } CoglFramebufferConfig; /* Flags to pass to _cogl_offscreen_new_with_texture_full */ typedef enum { COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL = 1 } CoglOffscreenFlags; /* XXX: The order of these indices determines the order they are * flushed. * * Flushing clip state may trash the modelview and projection matrices * so we must do it before flushing the matrices. */ typedef enum _CoglFramebufferStateIndex { COGL_FRAMEBUFFER_STATE_INDEX_BIND = 0, COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT = 1, COGL_FRAMEBUFFER_STATE_INDEX_CLIP = 2, COGL_FRAMEBUFFER_STATE_INDEX_DITHER = 3, COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW = 4, COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION = 5, COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK = 6, COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING = 7, COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE = 8, COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE = 9, COGL_FRAMEBUFFER_STATE_INDEX_MAX = 10 } CoglFramebufferStateIndex; typedef enum _CoglFramebufferState { COGL_FRAMEBUFFER_STATE_BIND = 1<<0, COGL_FRAMEBUFFER_STATE_VIEWPORT = 1<<1, COGL_FRAMEBUFFER_STATE_CLIP = 1<<2, COGL_FRAMEBUFFER_STATE_DITHER = 1<<3, COGL_FRAMEBUFFER_STATE_MODELVIEW = 1<<4, COGL_FRAMEBUFFER_STATE_PROJECTION = 1<<5, COGL_FRAMEBUFFER_STATE_COLOR_MASK = 1<<6, COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING = 1<<7, COGL_FRAMEBUFFER_STATE_DEPTH_WRITE = 1<<8, COGL_FRAMEBUFFER_STATE_STEREO_MODE = 1<<9 } CoglFramebufferState; #define COGL_FRAMEBUFFER_STATE_ALL ((1<config to configure if we want a depth or stencil buffer so * we can get rid of these flags */ CoglOffscreenFlags create_flags; }; void _cogl_framebuffer_init (CoglFramebuffer *framebuffer, CoglContext *ctx, CoglFramebufferType type, int width, int height); /* XXX: For a public api we might instead want a way to explicitly * set the _premult status of a framebuffer or what components we * care about instead of exposing the CoglPixelFormat * internal_format. * * The current use case for this api is where we create an offscreen * framebuffer for a shared atlas texture that has a format of * RGBA_8888 disregarding the premultiplied alpha status for * individual atlased textures or whether the alpha component is being * discarded. We want to overried the internal_format that will be * derived from the texture. */ void _cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer, CoglPixelFormat internal_format); void _cogl_framebuffer_free (CoglFramebuffer *framebuffer); const CoglWinsysVtable * _cogl_framebuffer_get_winsys (CoglFramebuffer *framebuffer); void _cogl_framebuffer_clear_without_flush4f (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha); void _cogl_framebuffer_mark_clear_clip_dirty (CoglFramebuffer *framebuffer); void _cogl_framebuffer_mark_mid_scene (CoglFramebuffer *framebuffer); /* * _cogl_framebuffer_get_clip_stack: * @framebuffer: A #CoglFramebuffer * * Gets a pointer to the current clip stack. This can be used to later * return to the same clip stack state with * _cogl_framebuffer_set_clip_stack(). A reference is not taken on the * stack so if you want to keep it you should call * _cogl_clip_stack_ref(). * * Return value: a pointer to the @framebuffer clip stack. */ CoglClipStack * _cogl_framebuffer_get_clip_stack (CoglFramebuffer *framebuffer); /* * _cogl_framebuffer_set_clip_stack: * @framebuffer: A #CoglFramebuffer * @stack: a pointer to the replacement clip stack * * Replaces the @framebuffer clip stack with @stack. */ void _cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer, CoglClipStack *stack); CoglMatrixStack * _cogl_framebuffer_get_modelview_stack (CoglFramebuffer *framebuffer); CoglMatrixStack * _cogl_framebuffer_get_projection_stack (CoglFramebuffer *framebuffer); void _cogl_framebuffer_add_dependency (CoglFramebuffer *framebuffer, CoglFramebuffer *dependency); void _cogl_framebuffer_remove_all_dependencies (CoglFramebuffer *framebuffer); void _cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer); void _cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer); void _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state); CoglFramebuffer * _cogl_get_read_framebuffer (void); GSList * _cogl_create_framebuffer_stack (void); void _cogl_free_framebuffer_stack (GSList *stack); /* * _cogl_offscreen_new_with_texture_full: * @texture: A #CoglTexture pointer * @create_flags: Flags specifying how to create the FBO * @level: The mipmap level within the texture to target * * Creates a new offscreen buffer which will target the given * texture. By default the buffer will have a depth and stencil * buffer. This can be disabled by passing * %COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL in @create_flags. * * Return value: the new CoglOffscreen object. */ CoglOffscreen * _cogl_offscreen_new_with_texture_full (CoglTexture *texture, CoglOffscreenFlags create_flags, int level); /* * _cogl_push_framebuffers: * @draw_buffer: A pointer to the buffer used for drawing * @read_buffer: A pointer to the buffer used for reading back pixels * * Redirects drawing and reading to the specified framebuffers as in * cogl_push_framebuffer() except that it allows the draw and read * buffer to be different. The buffers are pushed as a pair so that * they can later both be restored with a single call to * cogl_pop_framebuffer(). */ void _cogl_push_framebuffers (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer); /* * _cogl_blit_framebuffer: * @src: The source #CoglFramebuffer * @dest: The destination #CoglFramebuffer * @src_x: Source x position * @src_y: Source y position * @dst_x: Destination x position * @dst_y: Destination y position * @width: Width of region to copy * @height: Height of region to copy * * This blits a region of the color buffer of the current draw buffer * to the current read buffer. The draw and read buffers can be set up * using _cogl_push_framebuffers(). This function should only be * called if the COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT feature is * advertised. The two buffers must both be offscreen and have the * same format. * * Note that this function differs a lot from the glBlitFramebuffer * function provided by the GL_EXT_framebuffer_blit extension. Notably * it doesn't support having different sizes for the source and * destination rectangle. This isn't supported by the corresponding * GL_ANGLE_framebuffer_blit extension on GLES2.0 and it doesn't seem * like a particularly useful feature. If the application wanted to * scale the results it may make more sense to draw a primitive * instead. * * We can only really support blitting between two offscreen buffers * for this function on GLES2.0. This is because we effectively render * upside down to offscreen buffers to maintain Cogl's representation * of the texture coordinate system where 0,0 is the top left of the * texture. If we were to blit from an offscreen to an onscreen buffer * then we would need to mirror the blit along the x-axis but the GLES * extension does not support this. * * The GL function is documented to be affected by the scissor. This * function therefore ensure that an empty clip stack is flushed * before performing the blit which means the scissor is effectively * ignored. * * The function also doesn't support specifying the buffers to copy * and instead only the color buffer is copied. When copying the depth * or stencil buffers the extension on GLES2.0 only supports copying * the full buffer which would be awkward to document with this * API. If we wanted to support that feature it may be better to have * a separate function to copy the entire buffer for a given mask. */ void _cogl_blit_framebuffer (CoglFramebuffer *src, CoglFramebuffer *dest, int src_x, int src_y, int dst_x, int dst_y, int width, int height); void _cogl_framebuffer_push_projection (CoglFramebuffer *framebuffer); void _cogl_framebuffer_pop_projection (CoglFramebuffer *framebuffer); void _cogl_framebuffer_save_clip_stack (CoglFramebuffer *framebuffer); void _cogl_framebuffer_restore_clip_stack (CoglFramebuffer *framebuffer); void _cogl_framebuffer_unref (CoglFramebuffer *framebuffer); /* This can be called directly by the CoglJournal to draw attributes * skipping the implicit journal flush, the framebuffer flush and * pipeline validation. */ void _cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); void _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); gboolean _cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx, CoglTexture *texture, int texture_level, int texture_level_width, int texture_level_height, CoglTexture *depth_texture, CoglFramebufferConfig *config, CoglOffscreenAllocateFlags flags, CoglGLFramebuffer *gl_framebuffer); unsigned long _cogl_framebuffer_compare (CoglFramebuffer *a, CoglFramebuffer *b, unsigned long state); static inline CoglMatrixEntry * _cogl_framebuffer_get_modelview_entry (CoglFramebuffer *framebuffer) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); return modelview_stack->last_entry; } static inline CoglMatrixEntry * _cogl_framebuffer_get_projection_entry (CoglFramebuffer *framebuffer) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); return projection_stack->last_entry; } CoglBool _cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error); /* * _cogl_framebuffer_get_stencil_bits: * @framebuffer: a pointer to a #CoglFramebuffer * * Retrieves the number of stencil bits of @framebuffer * * Return value: the number of bits * * Since: 2.0 * Stability: unstable */ int _cogl_framebuffer_get_stencil_bits (CoglFramebuffer *framebuffer); #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-feature-private.h0000664000175000017500000000736614211404421021216 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_FEATURE_PRIVATE_H #define __COGL_FEATURE_PRIVATE_H #include #define COGL_CHECK_GL_VERSION(driver_major, driver_minor, \ target_major, target_minor) \ ((driver_major) > (target_major) || \ ((driver_major) == (target_major) && (driver_minor) >= (target_minor))) typedef enum { COGL_EXT_IN_GLES = (1 << 0), COGL_EXT_IN_GLES2 = (1 << 1), COGL_EXT_IN_GLES3 = (1 << 2) } CoglExtGlesAvailability; typedef struct _CoglFeatureFunction CoglFeatureFunction; struct _CoglFeatureFunction { /* The name of the function without the "EXT" or "ARB" suffix */ const char *name; /* The offset in the context of where to store the function pointer */ unsigned int pointer_offset; }; typedef struct _CoglFeatureData CoglFeatureData; struct _CoglFeatureData { /* A minimum GL version which the functions should be defined in without needing an extension. Set to 255,255 if it's only provided in an extension */ int min_gl_major, min_gl_minor; /* Flags specifying which versions of GLES the feature is available in core in */ CoglExtGlesAvailability gles_availability; /* \0 separated list of namespaces to try. Eg "EXT\0ARB\0" */ const char *namespaces; /* \0 separated list of required extension names without the GL_EXT or GL_ARB prefix. Any of the extensions must be available for the feature to be considered available. If the suffix for an extension is different from the namespace, you can specify it with a ':' after the namespace */ const char *extension_names; /* A set of feature flags to enable if the extension is available */ CoglFeatureFlags feature_flags; /* A set of private feature flags to enable if the extension is * available */ int feature_flags_private; /* An optional corresponding winsys feature. */ CoglWinsysFeature winsys_feature; /* A list of functions required for this feature. Terminated with a NULL name */ const CoglFeatureFunction *functions; }; CoglBool _cogl_feature_check (CoglRenderer *renderer, const char *driver_prefix, const CoglFeatureData *data, int gl_major, int gl_minor, CoglDriver driver, char * const *extensions, void *function_table); void _cogl_feature_check_ext_functions (CoglContext *context, int gl_major, int gl_minor, char * const *gl_extensions); #endif /* __COGL_FEATURE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-bitmap-pixbuf.c0000664000175000017500000001020714211404421020641 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-bitmap-private.h" #include "cogl-context-private.h" #include "cogl-private.h" #include "cogl-error-private.h" #include #include CoglBool _cogl_bitmap_get_size_from_file (const char *filename, int *width, int *height) { _COGL_RETURN_VAL_IF_FAIL (filename != NULL, FALSE); if (gdk_pixbuf_get_file_info (filename, width, height) != NULL) return TRUE; return FALSE; } CoglBitmap * _cogl_bitmap_from_file (CoglContext *ctx, const char *filename, CoglError **error) { static CoglUserDataKey pixbuf_key; GdkPixbuf *pixbuf; CoglBool has_alpha; GdkColorspace color_space; CoglPixelFormat pixel_format; int width; int height; int rowstride; int bits_per_sample; int n_channels; CoglBitmap *bmp; GError *glib_error = NULL; /* Load from file using GdkPixbuf */ pixbuf = gdk_pixbuf_new_from_file (filename, &glib_error); if (pixbuf == NULL) { _cogl_propagate_gerror (error, glib_error); return FALSE; } /* Get pixbuf properties */ has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); color_space = gdk_pixbuf_get_colorspace (pixbuf); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf); n_channels = gdk_pixbuf_get_n_channels (pixbuf); /* According to current docs this should be true and so * the translation to cogl pixel format below valid */ g_assert (bits_per_sample == 8); if (has_alpha) g_assert (n_channels == 4); else g_assert (n_channels == 3); /* Translate to cogl pixel format */ switch (color_space) { case GDK_COLORSPACE_RGB: /* The only format supported by GdkPixbuf so far */ pixel_format = has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888; break; default: /* Ouch, spec changed! */ g_object_unref (pixbuf); return FALSE; } /* We just use the data directly from the pixbuf so that we don't have to copy to a seperate buffer. Note that Cogl is expected not to read past the end of bpp*width on the last row even if the rowstride is much larger so we don't need to worry about GdkPixbuf's semantics that it may under-allocate the buffer. */ bmp = cogl_bitmap_new_for_data (ctx, width, height, pixel_format, rowstride, gdk_pixbuf_get_pixels (pixbuf)); cogl_object_set_user_data (COGL_OBJECT (bmp), &pixbuf_key, pixbuf, g_object_unref); return bmp; } muffin-5.2.1/cogl/cogl/cogl-primitive.h0000664000175000017500000010173014211404421020111 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PRIMITIVE_H__ #define __COGL_PRIMITIVE_H__ /* We forward declare the CoglPrimitive type here to avoid some circular * dependency issues with the following headers. */ typedef struct _CoglPrimitive CoglPrimitive; #include /* for CoglVerticesMode */ #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-primitive * @short_description: Functions for creating, manipulating and drawing * primitives * * FIXME */ /** * CoglPrimitive: (ref-func cogl_object_ref) (unref-func cogl_object_unref) * (set-value-func cogl_object_value_set_object) * (get-value-func cogl_object_value_get_object) */ /** * cogl_primitive_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_primitive_get_gtype (void); /** * CoglVertexP2: * @x: The x component of a position attribute * @y: The y component of a position attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p2(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y; } CoglVertexP2; /** * CoglVertexP3: * @x: The x component of a position attribute * @y: The y component of a position attribute * @z: The z component of a position attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p3(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y, z; } CoglVertexP3; /** * CoglVertexP2C4: * @x: The x component of a position attribute * @y: The y component of a position attribute * @r: The red component of a color attribute * @b: The green component of a color attribute * @g: The blue component of a color attribute * @a: The alpha component of a color attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p2c4(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y; uint8_t r, g, b, a; } CoglVertexP2C4; /** * CoglVertexP3C4: * @x: The x component of a position attribute * @y: The y component of a position attribute * @z: The z component of a position attribute * @r: The red component of a color attribute * @b: The green component of a color attribute * @g: The blue component of a color attribute * @a: The alpha component of a color attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p3c4(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y, z; uint8_t r, g, b, a; } CoglVertexP3C4; /** * CoglVertexP2T2: * @x: The x component of a position attribute * @y: The y component of a position attribute * @s: The s component of a texture coordinate attribute * @t: The t component of a texture coordinate attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p2t2(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y; float s, t; } CoglVertexP2T2; /** * CoglVertexP3T2: * @x: The x component of a position attribute * @y: The y component of a position attribute * @z: The z component of a position attribute * @s: The s component of a texture coordinate attribute * @t: The t component of a texture coordinate attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p3t2(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y, z; float s, t; } CoglVertexP3T2; /** * CoglVertexP2T2C4: * @x: The x component of a position attribute * @y: The y component of a position attribute * @s: The s component of a texture coordinate attribute * @t: The t component of a texture coordinate attribute * @r: The red component of a color attribute * @b: The green component of a color attribute * @g: The blue component of a color attribute * @a: The alpha component of a color attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p3t2c4(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y; float s, t; uint8_t r, g, b, a; } CoglVertexP2T2C4; /** * CoglVertexP3T2C4: * @x: The x component of a position attribute * @y: The y component of a position attribute * @z: The z component of a position attribute * @s: The s component of a texture coordinate attribute * @t: The t component of a texture coordinate attribute * @r: The red component of a color attribute * @b: The green component of a color attribute * @g: The blue component of a color attribute * @a: The alpha component of a color attribute * * A convenience vertex definition that can be used with * cogl_primitive_new_p3t2c4(). * * Since: 1.6 * Stability: Unstable */ typedef struct { float x, y, z; float s, t; uint8_t r, g, b, a; } CoglVertexP3T2C4; /** * cogl_primitive_new: * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to process when drawing * @...: A %NULL terminated list of attributes * * Combines a set of #CoglAttributes with a specific draw @mode * and defines a vertex count so a #CoglPrimitive object can be retained and * drawn later with no addition information required. * * The value passed as @n_vertices will simply update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * * Return value: (transfer full): A newly allocated #CoglPrimitive object * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new (CoglVerticesMode mode, int n_vertices, ...); /** * cogl_primitive_new_with_attributes: (skip) * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to process when drawing * @attributes: An array of CoglAttribute * @n_attributes: The number of attributes * * Combines a set of #CoglAttributes with a specific draw @mode * and defines a vertex count so a #CoglPrimitive object can be retained and * drawn later with no addition information required. * * The value passed as @n_vertices will simply update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * * Return value: (transfer full): A newly allocated #CoglPrimitive object * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_with_attributes (CoglVerticesMode mode, int n_vertices, CoglAttribute **attributes, int n_attributes); /** * cogl_primitive_new_p2: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP2): An array * of #CoglVertexP2 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position * attribute with a #CoglAttribute and upload your data. * * For example to draw a convex polygon you can do: * |[ * CoglVertexP2 triangle[] = * { * { 0, 300 }, * { 150, 0, }, * { 300, 300 } * }; * prim = cogl_primitive_new_p2 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p2 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP2 *data); /** * cogl_primitive_new_p3: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP3): An array of * #CoglVertexP3 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position * attribute with a #CoglAttribute and upload your data. * * For example to draw a convex polygon you can do: * |[ * CoglVertexP3 triangle[] = * { * { 0, 300, 0 }, * { 150, 0, 0 }, * { 300, 300, 0 } * }; * prim = cogl_primitive_new_p3 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p3 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP3 *data); /** * cogl_primitive_new_p2c4: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP2C4): An array * of #CoglVertexP2C4 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position * and color attributes with #CoglAttributes and upload * your data. * * For example to draw a convex polygon with a linear gradient you * can do: * |[ * CoglVertexP2C4 triangle[] = * { * { 0, 300, 0xff, 0x00, 0x00, 0xff }, * { 150, 0, 0x00, 0xff, 0x00, 0xff }, * { 300, 300, 0xff, 0x00, 0x00, 0xff } * }; * prim = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p2c4 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP2C4 *data); /** * cogl_primitive_new_p3c4: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP3C4): An array * of #CoglVertexP3C4 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position * and color attributes with #CoglAttributes and upload * your data. * * For example to draw a convex polygon with a linear gradient you * can do: * |[ * CoglVertexP3C4 triangle[] = * { * { 0, 300, 0, 0xff, 0x00, 0x00, 0xff }, * { 150, 0, 0, 0x00, 0xff, 0x00, 0xff }, * { 300, 300, 0, 0xff, 0x00, 0x00, 0xff } * }; * prim = cogl_primitive_new_p3c4 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p3c4 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP3C4 *data); /** * cogl_primitive_new_p2t2: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP2T2): An array * of #CoglVertexP2T2 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position and * texture coordinate attributes with #CoglAttributes and * upload your data. * * For example to draw a convex polygon with texture mapping you can * do: * |[ * CoglVertexP2T2 triangle[] = * { * { 0, 300, 0.0, 1.0}, * { 150, 0, 0.5, 0.0}, * { 300, 300, 1.0, 1.0} * }; * prim = cogl_primitive_new_p2t2 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p2t2 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP2T2 *data); /** * cogl_primitive_new_p3t2: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP3T2): An array * of #CoglVertexP3T2 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position and * texture coordinate attributes with #CoglAttributes and * upload your data. * * For example to draw a convex polygon with texture mapping you can * do: * |[ * CoglVertexP3T2 triangle[] = * { * { 0, 300, 0, 0.0, 1.0}, * { 150, 0, 0, 0.5, 0.0}, * { 300, 300, 0, 1.0, 1.0} * }; * prim = cogl_primitive_new_p3t2 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p3t2 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP3T2 *data); /** * cogl_primitive_new_p2t2c4: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP2T2C4): An * array of #CoglVertexP2T2C4 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position, texture * coordinate and color attributes with #CoglAttributes and * upload your data. * * For example to draw a convex polygon with texture mapping and a * linear gradient you can do: * |[ * CoglVertexP2T2C4 triangle[] = * { * { 0, 300, 0.0, 1.0, 0xff, 0x00, 0x00, 0xff}, * { 150, 0, 0.5, 0.0, 0x00, 0xff, 0x00, 0xff}, * { 300, 300, 1.0, 1.0, 0xff, 0x00, 0x00, 0xff} * }; * prim = cogl_primitive_new_p2t2c4 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p2t2c4 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP2T2C4 *data); /** * cogl_primitive_new_p3t2c4: (skip) * @context: A #CoglContext * @mode: A #CoglVerticesMode defining how to draw the vertices * @n_vertices: The number of vertices to read from @data and also * the number of vertices to read when later drawing. * @data: (array length=n_vertices): (type Cogl.VertexP3T2C4): An * array of #CoglVertexP3T2C4 vertices * * Provides a convenient way to describe a primitive, such as a single * triangle strip or a triangle fan, that will internally allocate the * necessary #CoglAttributeBuffer storage, describe the position, texture * coordinate and color attributes with #CoglAttributes and * upload your data. * * For example to draw a convex polygon with texture mapping and a * linear gradient you can do: * |[ * CoglVertexP3T2C4 triangle[] = * { * { 0, 300, 0, 0.0, 1.0, 0xff, 0x00, 0x00, 0xff}, * { 150, 0, 0, 0.5, 0.0, 0x00, 0xff, 0x00, 0xff}, * { 300, 300, 0, 1.0, 1.0, 0xff, 0x00, 0x00, 0xff} * }; * prim = cogl_primitive_new_p3t2c4 (COGL_VERTICES_MODE_TRIANGLE_FAN, * 3, triangle); * cogl_primitive_draw (prim); * ]| * * The value passed as @n_vertices is initially used to determine how * much can be read from @data but it will also be used to update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to read when drawing. * The primitive API doesn't support drawing with sliced * textures (since switching between slices implies changing state and * so that implies multiple primitives need to be submitted). You * should pass the %COGL_TEXTURE_NO_SLICING flag to all textures that * might be used while drawing with this API. If your hardware doesn't * support non-power of two textures (For example you are using GLES * 1.1) then you will need to make sure your assets are resized to a * power-of-two size (though they don't have to be square) * * Return value: (transfer full): A newly allocated #CoglPrimitive * with a reference of 1. This can be freed using cogl_object_unref(). * * Since: 1.6 * Stability: Unstable */ CoglPrimitive * cogl_primitive_new_p3t2c4 (CoglContext *context, CoglVerticesMode mode, int n_vertices, const CoglVertexP3T2C4 *data); int cogl_primitive_get_first_vertex (CoglPrimitive *primitive); void cogl_primitive_set_first_vertex (CoglPrimitive *primitive, int first_vertex); /** * cogl_primitive_get_n_vertices: * @primitive: A #CoglPrimitive object * * Queries the number of vertices to read when drawing the given * @primitive. Usually this value is implicitly set when associating * vertex data or indices with a #CoglPrimitive. * * If cogl_primitive_set_indices() has been used to associate a * sequence of #CoglIndices with the given @primitive then the * number of vertices to read can also be phrased as the number * of indices to read. * * To be clear; it doesn't refer to the number of vertices - in * terms of data - associated with the primitive it's just the number * of vertices to read and draw. * * Returns: The number of vertices to read when drawing. * * Since: 1.8 * Stability: unstable */ int cogl_primitive_get_n_vertices (CoglPrimitive *primitive); /** * cogl_primitive_set_n_vertices: * @primitive: A #CoglPrimitive object * @n_vertices: The number of vertices to read when drawing. * * Specifies how many vertices should be read when drawing the given * @primitive. * * Usually this value is set implicitly when associating vertex data * or indices with a #CoglPrimitive. * * To be clear; it doesn't refer to the number of vertices - in * terms of data - associated with the primitive it's just the number * of vertices to read and draw. * * Since: 1.8 * Stability: unstable */ void cogl_primitive_set_n_vertices (CoglPrimitive *primitive, int n_vertices); CoglVerticesMode cogl_primitive_get_mode (CoglPrimitive *primitive); void cogl_primitive_set_mode (CoglPrimitive *primitive, CoglVerticesMode mode); /** * cogl_primitive_set_attributes: (skip) * @primitive: A #CoglPrimitive object * @attributes: an array of #CoglAttribute pointers * @n_attributes: the number of elements in @attributes * * Replaces all the attributes of the given #CoglPrimitive object. * * Since: 1.6 * Stability: Unstable */ void cogl_primitive_set_attributes (CoglPrimitive *primitive, CoglAttribute **attributes, int n_attributes); /** * cogl_primitive_set_indices: (skip) * @primitive: A #CoglPrimitive * @indices: A #CoglIndices array * @n_indices: The number of indices to reference when drawing * * Associates a sequence of #CoglIndices with the given @primitive. * * #CoglIndices provide a way to virtualize your real vertex data by * providing a sequence of indices that index into your real vertex * data. The GPU will walk though the index values to indirectly * lookup the data for each vertex instead of sequentially walking * through the data directly. This lets you save memory by indexing * shared data multiple times instead of duplicating the data. * * The value passed as @n_indices will simply update the * #CoglPrimitive n_vertices property as if * cogl_primitive_set_n_vertices() were called. This property defines * the number of vertices to draw or, put another way, how many * indices should be read from @indices when drawing. * * The #CoglPrimitive first_vertex property * also affects drawing with indices by defining the first entry of the * indices to start drawing from. * * Since: 1.10 * Stability: unstable */ void cogl_primitive_set_indices (CoglPrimitive *primitive, CoglIndices *indices, int n_indices); /** * cogl_primitive_get_indices: (skip) * @primitive: A #CoglPrimitive * * Return value: (transfer none): the indices that were set with * cogl_primitive_set_indices() or %NULL if no indices were set. * * Since: 1.10 * Stability: unstable */ CoglIndices * cogl_primitive_get_indices (CoglPrimitive *primitive); /** * cogl_primitive_copy: * @primitive: A primitive copy * * Makes a copy of an existing #CoglPrimitive. Note that the primitive * is a shallow copy which means it will use the same attributes and * attribute buffers as the original primitive. * * Return value: (transfer full): the new primitive * Since: 1.10 * Stability: unstable */ CoglPrimitive * cogl_primitive_copy (CoglPrimitive *primitive); /** * cogl_is_primitive: * @object: A #CoglObject * * Gets whether the given object references a #CoglPrimitive. * * Returns: %TRUE if the @object references a #CoglPrimitive, * %FALSE otherwise * * Since: 1.6 * Stability: Unstable */ CoglBool cogl_is_primitive (void *object); /** * CoglPrimitiveAttributeCallback: * @primitive: The #CoglPrimitive whose attributes are being iterated * @attribute: The #CoglAttribute * @user_data: The private data passed to cogl_primitive_foreach_attribute() * * The callback prototype used with cogl_primitive_foreach_attribute() * for iterating all the attributes of a #CoglPrimitive. * * The function should return TRUE to continue iteration or FALSE to * stop. * * Since: 1.10 * Stability: Unstable */ typedef CoglBool (* CoglPrimitiveAttributeCallback) (CoglPrimitive *primitive, CoglAttribute *attribute, void *user_data); /** * cogl_primitive_foreach_attribute: * @primitive: A #CoglPrimitive object * @callback: (scope call): A #CoglPrimitiveAttributeCallback to be * called for each attribute * @user_data: (closure): Private data that will be passed to the * callback * * Iterates all the attributes of the given #CoglPrimitive. * * Since: 1.10 * Stability: Unstable */ void cogl_primitive_foreach_attribute (CoglPrimitive *primitive, CoglPrimitiveAttributeCallback callback, void *user_data); /** * cogl_primitive_draw: (skip) * @primitive: A #CoglPrimitive geometry object * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * * Draws the given @primitive geometry to the specified destination * @framebuffer using the graphics processing state described by @pipeline. * * This drawing api doesn't support high-level meta texture types such * as #CoglTexture2DSliced so it is the user's responsibility to * ensure that only low-level textures that can be directly sampled by * a GPU such as #CoglTexture2D, #CoglTextureRectangle or #CoglTexture3D * are associated with layers of the given @pipeline. * * Stability: unstable * Since: 1.16 */ void cogl_primitive_draw (CoglPrimitive *primitive, CoglFramebuffer *framebuffer, CoglPipeline *pipeline); COGL_END_DECLS #endif /* __COGL_PRIMITIVE_H__ */ muffin-5.2.1/cogl/cogl/cogl-texture.c0000664000175000017500000011734014211404421017600 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * Copyright (C) 2010 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Matthew Allum * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-bitmap.h" #include "cogl-bitmap-private.h" #include "cogl-buffer-private.h" #include "cogl-pixel-buffer-private.h" #include "cogl-private.h" #include "cogl-texture-private.h" #include "cogl-texture-driver.h" #include "cogl-texture-2d-sliced-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d-gl.h" #include "cogl-texture-3d-private.h" #include "cogl-texture-rectangle-private.h" #include "cogl-sub-texture-private.h" #include "cogl-atlas-texture-private.h" #include "cogl-pipeline.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-object-private.h" #include "cogl-primitives.h" #include "cogl-framebuffer-private.h" #include "cogl1-context.h" #include "cogl-sub-texture.h" #include "cogl-primitive-texture.h" #include "cogl-error-private.h" #include "cogl-gtype-private.h" #include #include #include /* This isn't defined in the GLES headers */ #ifndef GL_RED #define GL_RED 0x1903 #endif COGL_GTYPE_DEFINE_INTERFACE (Texture, texture); uint32_t cogl_texture_error_quark (void) { return g_quark_from_static_string ("cogl-texture-error-quark"); } /* XXX: * The CoglObject macros don't support any form of inheritance, so for * now we implement the CoglObject support for the CoglTexture * abstract class manually. */ static GSList *_cogl_texture_types; void _cogl_texture_register_texture_type (const CoglObjectClass *klass) { _cogl_texture_types = g_slist_prepend (_cogl_texture_types, (void *) klass); } CoglBool cogl_is_texture (void *object) { CoglObject *obj = (CoglObject *)object; GSList *l; if (object == NULL) return FALSE; for (l = _cogl_texture_types; l; l = l->next) if (l->data == obj->klass) return TRUE; return FALSE; } void _cogl_texture_init (CoglTexture *texture, CoglContext *context, int width, int height, CoglPixelFormat src_format, CoglTextureLoader *loader, const CoglTextureVtable *vtable) { texture->context = context; texture->max_level = 0; texture->width = width; texture->height = height; texture->allocated = FALSE; texture->vtable = vtable; texture->framebuffers = NULL; texture->loader = loader; _cogl_texture_set_internal_format (texture, src_format); /* Although we want to initialize texture::components according * to the source format, we always want the internal layout to * be considered premultiplied by default. * * NB: this ->premultiplied state is user configurable so to avoid * awkward documentation, setting this to 'true' does not depend on * ->components having an alpha component (we will simply ignore the * premultiplied status later if there is no alpha component). * This way we don't have to worry about updating the * ->premultiplied state in _set_components(). Similarly we don't * have to worry about updating the ->components state in * _set_premultiplied(). */ texture->premultiplied = TRUE; } static void _cogl_texture_free_loader (CoglTexture *texture) { if (texture->loader) { CoglTextureLoader *loader = texture->loader; switch (loader->src_type) { case COGL_TEXTURE_SOURCE_TYPE_SIZED: case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE: case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN: case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE_EXTERNAL: break; case COGL_TEXTURE_SOURCE_TYPE_BITMAP: cogl_object_unref (loader->src.bitmap.bitmap); break; } g_slice_free (CoglTextureLoader, loader); texture->loader = NULL; } } CoglTextureLoader * _cogl_texture_create_loader (void) { return g_slice_new0 (CoglTextureLoader); } void _cogl_texture_free (CoglTexture *texture) { _cogl_texture_free_loader (texture); free (texture); } CoglBool _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format, CoglPixelFormat dst_format) { return ((src_format & dst_format & COGL_A_BIT) && src_format != COGL_PIXEL_FORMAT_A_8 && dst_format != COGL_PIXEL_FORMAT_A_8 && (src_format & COGL_PREMULT_BIT) != (dst_format & COGL_PREMULT_BIT)); } CoglBool _cogl_texture_is_foreign (CoglTexture *texture) { if (texture->vtable->is_foreign) return texture->vtable->is_foreign (texture); else return FALSE; } unsigned int cogl_texture_get_width (CoglTexture *texture) { return texture->width; } unsigned int cogl_texture_get_height (CoglTexture *texture) { return texture->height; } CoglPixelFormat _cogl_texture_get_format (CoglTexture *texture) { if (!texture->allocated) cogl_texture_allocate (texture, NULL); return texture->vtable->get_format (texture); } int cogl_texture_get_max_waste (CoglTexture *texture) { return texture->vtable->get_max_waste (texture); } int _cogl_texture_get_n_levels (CoglTexture *texture) { int width = cogl_texture_get_width (texture); int height = cogl_texture_get_height (texture); int max_dimension = MAX (width, height); if (cogl_is_texture_3d (texture)) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture); max_dimension = MAX (max_dimension, tex_3d->depth); } return _cogl_util_fls (max_dimension); } void _cogl_texture_get_level_size (CoglTexture *texture, int level, int *width, int *height, int *depth) { int current_width = cogl_texture_get_width (texture); int current_height = cogl_texture_get_height (texture); int current_depth; int i; if (cogl_is_texture_3d (texture)) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture); current_depth = tex_3d->depth; } else current_depth = 0; /* NB: The OpenGL spec (like D3D) uses a floor() convention to * round down the size of a mipmap level when dividing the size * of the previous level results in a fraction... */ for (i = 0; i < level; i++) { current_width = MAX (1, current_width >> 1); current_height = MAX (1, current_height >> 1); current_depth = MAX (1, current_depth >> 1); } if (width) *width = current_width; if (height) *height = current_height; if (depth) *depth = current_depth; } CoglBool cogl_texture_is_sliced (CoglTexture *texture) { if (!texture->allocated) cogl_texture_allocate (texture, NULL); return texture->vtable->is_sliced (texture); } /* If this returns FALSE, that implies _foreach_sub_texture_in_region * will be needed to iterate over multiple sub textures for regions whos * texture coordinates extend out of the range [0,1] */ CoglBool _cogl_texture_can_hardware_repeat (CoglTexture *texture) { if (!texture->allocated) cogl_texture_allocate (texture, NULL); return texture->vtable->can_hardware_repeat (texture); } /* NB: You can't use this with textures comprised of multiple sub textures (use * cogl_texture_is_sliced() to check) since coordinate transformation for such * textures will be different for each slice. */ void _cogl_texture_transform_coords_to_gl (CoglTexture *texture, float *s, float *t) { texture->vtable->transform_coords_to_gl (texture, s, t); } CoglTransformResult _cogl_texture_transform_quad_coords_to_gl (CoglTexture *texture, float *coords) { return texture->vtable->transform_quad_coords_to_gl (texture, coords); } CoglBool cogl_texture_get_gl_texture (CoglTexture *texture, GLuint *out_gl_handle, GLenum *out_gl_target) { if (!texture->allocated) cogl_texture_allocate (texture, NULL); return texture->vtable->get_gl_texture (texture, out_gl_handle, out_gl_target); } CoglTextureType _cogl_texture_get_type (CoglTexture *texture) { return texture->vtable->get_type (texture); } void _cogl_texture_pre_paint (CoglTexture *texture, CoglTexturePrePaintFlags flags) { /* Assert that the storage for the texture exists already if we're * about to reference it for painting. * * Note: we abort on error here since it's a bit late to do anything * about it if we fail to allocate the texture and the app could * have explicitly allocated the texture earlier to handle problems * gracefully. * * XXX: Maybe it could even be considered a programmer error if the * texture hasn't been allocated by this point since it implies we * are abount to paint with undefined texture contents? */ cogl_texture_allocate (texture, NULL); texture->vtable->pre_paint (texture, flags); } void _cogl_texture_ensure_non_quad_rendering (CoglTexture *texture) { texture->vtable->ensure_non_quad_rendering (texture); } CoglBool _cogl_texture_set_region_from_bitmap (CoglTexture *texture, int src_x, int src_y, int width, int height, CoglBitmap *bmp, int dst_x, int dst_y, int level, CoglError **error) { _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_width (bmp) - src_x) >= width, FALSE); _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_height (bmp) - src_y) >= height, FALSE); _COGL_RETURN_VAL_IF_FAIL (width > 0, FALSE); _COGL_RETURN_VAL_IF_FAIL (height > 0, FALSE); /* Assert that the storage for this texture has been allocated */ if (!cogl_texture_allocate (texture, error)) return FALSE; /* Note that we don't prepare the bitmap for upload here because some backends may be internally using a different format for the actual GL texture than that reported by _cogl_texture_get_format. For example the atlas textures are always stored in an RGBA texture even if the texture format is advertised as RGB. */ return texture->vtable->set_region (texture, src_x, src_y, dst_x, dst_y, width, height, level, bmp, error); } CoglBool cogl_texture_set_region_from_bitmap (CoglTexture *texture, int src_x, int src_y, int dst_x, int dst_y, unsigned int dst_width, unsigned int dst_height, CoglBitmap *bitmap) { CoglError *ignore_error = NULL; CoglBool status = _cogl_texture_set_region_from_bitmap (texture, src_x, src_y, dst_width, dst_height, bitmap, dst_x, dst_y, 0, /* level */ &ignore_error); if (!status) cogl_error_free (ignore_error); return status; } CoglBool _cogl_texture_set_region (CoglTexture *texture, int width, int height, CoglPixelFormat format, int rowstride, const uint8_t *data, int dst_x, int dst_y, int level, CoglError **error) { CoglContext *ctx = texture->context; CoglBitmap *source_bmp; CoglBool ret; _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, FALSE); /* Rowstride from width if none specified */ if (rowstride == 0) rowstride = _cogl_pixel_format_get_bytes_per_pixel (format) * width; /* Init source bitmap */ source_bmp = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); ret = _cogl_texture_set_region_from_bitmap (texture, 0, 0, width, height, source_bmp, dst_x, dst_y, level, error); cogl_object_unref (source_bmp); return ret; } CoglBool cogl_texture_set_region (CoglTexture *texture, int src_x, int src_y, int dst_x, int dst_y, unsigned int dst_width, unsigned int dst_height, int width, int height, CoglPixelFormat format, unsigned int rowstride, const uint8_t *data) { CoglError *ignore_error = NULL; const uint8_t *first_pixel; int bytes_per_pixel = _cogl_pixel_format_get_bytes_per_pixel (format); CoglBool status; /* Rowstride from width if none specified */ if (rowstride == 0) rowstride = bytes_per_pixel * width; first_pixel = data + rowstride * src_y + bytes_per_pixel * src_x; status = _cogl_texture_set_region (texture, dst_width, dst_height, format, rowstride, first_pixel, dst_x, dst_y, 0, &ignore_error); if (!status) cogl_error_free (ignore_error); return status; } CoglBool cogl_texture_set_data (CoglTexture *texture, CoglPixelFormat format, int rowstride, const uint8_t *data, int level, CoglError **error) { int level_width; int level_height; _cogl_texture_get_level_size (texture, level, &level_width, &level_height, NULL); return _cogl_texture_set_region (texture, level_width, level_height, format, rowstride, data, 0, 0, /* dest x, y */ level, error); } static CoglBool get_texture_bits_via_offscreen (CoglTexture *meta_texture, CoglTexture *sub_texture, int x, int y, int width, int height, uint8_t *dst_bits, unsigned int dst_rowstride, CoglPixelFormat closest_format) { CoglContext *ctx = sub_texture->context; CoglOffscreen *offscreen; CoglFramebuffer *framebuffer; CoglBitmap *bitmap; CoglBool ret; CoglError *ignore_error = NULL; CoglPixelFormat real_format; if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) return FALSE; offscreen = _cogl_offscreen_new_with_texture_full (sub_texture, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0); framebuffer = COGL_FRAMEBUFFER (offscreen); if (!cogl_framebuffer_allocate (framebuffer, &ignore_error)) { cogl_error_free (ignore_error); return FALSE; } /* Currently the framebuffer's internal format corresponds to the * internal format of @sub_texture but in the case of atlas textures * it's possible that this format doesn't reflect the correct * premultiplied alpha status or what components are valid since * atlas textures are always stored in a shared texture with a * format of _RGBA_8888. * * Here we override the internal format to make sure the * framebuffer's internal format matches the internal format of the * parent meta_texture instead. */ real_format = _cogl_texture_get_format (meta_texture); _cogl_framebuffer_set_internal_format (framebuffer, real_format); bitmap = cogl_bitmap_new_for_data (ctx, width, height, closest_format, dst_rowstride, dst_bits); ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer, x, y, COGL_READ_PIXELS_COLOR_BUFFER, bitmap, &ignore_error); if (!ret) cogl_error_free (ignore_error); cogl_object_unref (bitmap); cogl_object_unref (framebuffer); return ret; } static CoglBool get_texture_bits_via_copy (CoglTexture *texture, int x, int y, int width, int height, uint8_t *dst_bits, unsigned int dst_rowstride, CoglPixelFormat dst_format) { unsigned int full_rowstride; uint8_t *full_bits; CoglBool ret = TRUE; int bpp; int full_tex_width, full_tex_height; full_tex_width = cogl_texture_get_width (texture); full_tex_height = cogl_texture_get_height (texture); bpp = _cogl_pixel_format_get_bytes_per_pixel (dst_format); full_rowstride = bpp * full_tex_width; full_bits = malloc (full_rowstride * full_tex_height); if (texture->vtable->get_data (texture, dst_format, full_rowstride, full_bits)) { uint8_t *dst = dst_bits; uint8_t *src = full_bits + x * bpp + y * full_rowstride; int i; for (i = 0; i < height; i++) { memcpy (dst, src, bpp * width); dst += dst_rowstride; src += full_rowstride; } } else ret = FALSE; free (full_bits); return ret; } typedef struct { CoglTexture *meta_texture; int orig_width; int orig_height; CoglBitmap *target_bmp; uint8_t *target_bits; CoglBool success; CoglError *error; } CoglTextureGetData; static void texture_get_cb (CoglTexture *subtexture, const float *subtexture_coords, const float *virtual_coords, void *user_data) { CoglTextureGetData *tg_data = user_data; CoglTexture *meta_texture = tg_data->meta_texture; CoglPixelFormat closest_format = cogl_bitmap_get_format (tg_data->target_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (closest_format); unsigned int rowstride = cogl_bitmap_get_rowstride (tg_data->target_bmp); int subtexture_width = cogl_texture_get_width (subtexture); int subtexture_height = cogl_texture_get_height (subtexture); int x_in_subtexture = (int) (0.5 + subtexture_width * subtexture_coords[0]); int y_in_subtexture = (int) (0.5 + subtexture_height * subtexture_coords[1]); int width = ((int) (0.5 + subtexture_width * subtexture_coords[2]) - x_in_subtexture); int height = ((int) (0.5 + subtexture_height * subtexture_coords[3]) - y_in_subtexture); int x_in_bitmap = (int) (0.5 + tg_data->orig_width * virtual_coords[0]); int y_in_bitmap = (int) (0.5 + tg_data->orig_height * virtual_coords[1]); uint8_t *dst_bits; if (!tg_data->success) return; dst_bits = tg_data->target_bits + x_in_bitmap * bpp + y_in_bitmap * rowstride; /* If we can read everything as a single slice, then go ahead and do that * to avoid allocating an FBO. We'll leave it up to the GL implementation to * do glGetTexImage as efficiently as possible. (GLES doesn't have that, * so we'll fall through) */ if (x_in_subtexture == 0 && y_in_subtexture == 0 && width == subtexture_width && height == subtexture_height) { if (subtexture->vtable->get_data (subtexture, closest_format, rowstride, dst_bits)) return; } /* Next best option is a FBO and glReadPixels */ if (get_texture_bits_via_offscreen (meta_texture, subtexture, x_in_subtexture, y_in_subtexture, width, height, dst_bits, rowstride, closest_format)) return; /* Getting ugly: read the entire texture, copy out the part we want */ if (get_texture_bits_via_copy (subtexture, x_in_subtexture, y_in_subtexture, width, height, dst_bits, rowstride, closest_format)) return; /* No luck, the caller will fall back to the draw-to-backbuffer and * read implementation */ tg_data->success = FALSE; } int cogl_texture_get_data (CoglTexture *texture, CoglPixelFormat format, unsigned int rowstride, uint8_t *data) { CoglContext *ctx = texture->context; int bpp; int byte_size; CoglPixelFormat closest_format; GLenum closest_gl_format; GLenum closest_gl_type; CoglBitmap *target_bmp; int tex_width; int tex_height; CoglPixelFormat texture_format; CoglError *ignore_error = NULL; CoglTextureGetData tg_data; texture_format = _cogl_texture_get_format (texture); /* Default to internal format if none specified */ if (format == COGL_PIXEL_FORMAT_ANY) format = texture_format; tex_width = cogl_texture_get_width (texture); tex_height = cogl_texture_get_height (texture); /* Rowstride from texture width if none specified */ bpp = _cogl_pixel_format_get_bytes_per_pixel (format); if (rowstride == 0) rowstride = tex_width * bpp; /* Return byte size if only that requested */ byte_size = tex_height * rowstride; if (data == NULL) return byte_size; closest_format = ctx->texture_driver->find_best_gl_get_data_format (ctx, texture_format, format, &closest_gl_format, &closest_gl_type); /* We can assume that whatever data GL gives us will have the premult status of the original texture */ if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (closest_format)) closest_format = ((closest_format & ~COGL_PREMULT_BIT) | (texture_format & COGL_PREMULT_BIT)); /* If the application is requesting a conversion from a * component-alpha texture and the driver doesn't support them * natively then we can only read into an alpha-format buffer. In * this case the driver will be faking the alpha textures with a * red-component texture and it won't swizzle to the correct format * while reading */ if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES)) { if (texture_format == COGL_PIXEL_FORMAT_A_8) { closest_format = COGL_PIXEL_FORMAT_A_8; closest_gl_format = GL_RED; closest_gl_type = GL_UNSIGNED_BYTE; } else if (format == COGL_PIXEL_FORMAT_A_8) { /* If we are converting to a component-alpha texture then we * need to read all of the components to a temporary buffer * because there is no way to get just the 4th component. * Note: it doesn't matter whether the texture is * pre-multiplied here because we're only going to look at * the alpha component */ closest_format = COGL_PIXEL_FORMAT_RGBA_8888; closest_gl_format = GL_RGBA; closest_gl_type = GL_UNSIGNED_BYTE; } } /* Is the requested format supported? */ if (closest_format == format) /* Target user data directly */ target_bmp = cogl_bitmap_new_for_data (ctx, tex_width, tex_height, format, rowstride, data); else { target_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, tex_width, tex_height, closest_format, &ignore_error); if (!target_bmp) { cogl_error_free (ignore_error); return 0; } } tg_data.target_bits = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, &ignore_error); if (tg_data.target_bits) { tg_data.meta_texture = texture; tg_data.orig_width = tex_width; tg_data.orig_height = tex_height; tg_data.target_bmp = target_bmp; tg_data.error = NULL; tg_data.success = TRUE; /* If there are any dependent framebuffers on the texture then we need to flush their journals so the texture contents will be up-to-date */ _cogl_texture_flush_journal_rendering (texture); /* Iterating through the subtextures allows piecing together * the data for a sliced texture, and allows us to do the * read-from-framebuffer logic here in a simple fashion rather than * passing offsets down through the code. */ cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (texture), 0, 0, 1, 1, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, texture_get_cb, &tg_data); _cogl_bitmap_unmap (target_bmp); } else { cogl_error_free (ignore_error); tg_data.success = FALSE; } /* XXX: In some cases this api may fail to read back the texture * data; such as for GLES which doesn't support glGetTexImage */ if (!tg_data.success) { cogl_object_unref (target_bmp); return 0; } /* Was intermediate used? */ if (closest_format != format) { CoglBitmap *new_bmp; CoglBool result; CoglError *error = NULL; /* Convert to requested format directly into the user's buffer */ new_bmp = cogl_bitmap_new_for_data (ctx, tex_width, tex_height, format, rowstride, data); result = _cogl_bitmap_convert_into_bitmap (target_bmp, new_bmp, &error); if (!result) { cogl_error_free (error); /* Return failure after cleaning up */ byte_size = 0; } cogl_object_unref (new_bmp); } cogl_object_unref (target_bmp); return byte_size; } static void _cogl_texture_framebuffer_destroy_cb (void *user_data, void *instance) { CoglTexture *tex = user_data; CoglFramebuffer *framebuffer = instance; tex->framebuffers = g_list_remove (tex->framebuffers, framebuffer); } void _cogl_texture_associate_framebuffer (CoglTexture *texture, CoglFramebuffer *framebuffer) { static CoglUserDataKey framebuffer_destroy_notify_key; /* Note: we don't take a reference on the framebuffer here because * that would introduce a circular reference. */ texture->framebuffers = g_list_prepend (texture->framebuffers, framebuffer); /* Since we haven't taken a reference on the framebuffer we setup * some private data so we will be notified if it is destroyed... */ _cogl_object_set_user_data (COGL_OBJECT (framebuffer), &framebuffer_destroy_notify_key, texture, _cogl_texture_framebuffer_destroy_cb); } const GList * _cogl_texture_get_associated_framebuffers (CoglTexture *texture) { return texture->framebuffers; } void _cogl_texture_flush_journal_rendering (CoglTexture *texture) { GList *l; /* It could be that a referenced texture is part of a framebuffer * which has an associated journal that must be flushed before it * can be sampled from by the current primitive... */ for (l = texture->framebuffers; l; l = l->next) _cogl_framebuffer_flush_journal (l->data); } /* This function lets you define a meta texture as a grid of textures * whereby the x and y grid-lines are defined by an array of * CoglSpans. With that grid based description this function can then * iterate all the cells of the grid that lye within a region * specified as virtual, meta-texture, coordinates. This function can * also cope with regions that extend beyond the original meta-texture * grid by iterating cells repeatedly according to the wrap_x/y * arguments. * * To differentiate between texture coordinates of a specific, real, * slice texture and the texture coordinates of a composite, meta * texture, the coordinates of the meta texture are called "virtual" * coordinates and the coordinates of spans are called "slice" * coordinates. * * Note: no guarantee is given about the order in which the slices * will be visited. * * Note: The slice coordinates passed to @callback are always * normalized coordinates even if the span coordinates aren't * normalized. */ void _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans, int n_x_spans, CoglSpan *y_spans, int n_y_spans, CoglTexture **textures, float *virtual_coords, float x_normalize_factor, float y_normalize_factor, CoglPipelineWrapMode wrap_x, CoglPipelineWrapMode wrap_y, CoglMetaTextureCallback callback, void *user_data) { CoglSpanIter iter_x; CoglSpanIter iter_y; float slice_coords[4]; float span_virtual_coords[4]; /* Iterate the y axis of the virtual rectangle */ for (_cogl_span_iter_begin (&iter_y, y_spans, n_y_spans, y_normalize_factor, virtual_coords[1], virtual_coords[3], wrap_y); !_cogl_span_iter_end (&iter_y); _cogl_span_iter_next (&iter_y)) { if (iter_y.flipped) { slice_coords[1] = iter_y.intersect_end; slice_coords[3] = iter_y.intersect_start; span_virtual_coords[1] = iter_y.intersect_end; span_virtual_coords[3] = iter_y.intersect_start; } else { slice_coords[1] = iter_y.intersect_start; slice_coords[3] = iter_y.intersect_end; span_virtual_coords[1] = iter_y.intersect_start; span_virtual_coords[3] = iter_y.intersect_end; } /* Map the current intersection to normalized slice coordinates */ slice_coords[1] = (slice_coords[1] - iter_y.pos) / iter_y.span->size; slice_coords[3] = (slice_coords[3] - iter_y.pos) / iter_y.span->size; /* Iterate the x axis of the virtual rectangle */ for (_cogl_span_iter_begin (&iter_x, x_spans, n_x_spans, x_normalize_factor, virtual_coords[0], virtual_coords[2], wrap_x); !_cogl_span_iter_end (&iter_x); _cogl_span_iter_next (&iter_x)) { CoglTexture *span_tex; if (iter_x.flipped) { slice_coords[0] = iter_x.intersect_end; slice_coords[2] = iter_x.intersect_start; span_virtual_coords[0] = iter_x.intersect_end; span_virtual_coords[2] = iter_x.intersect_start; } else { slice_coords[0] = iter_x.intersect_start; slice_coords[2] = iter_x.intersect_end; span_virtual_coords[0] = iter_x.intersect_start; span_virtual_coords[2] = iter_x.intersect_end; } /* Map the current intersection to normalized slice coordinates */ slice_coords[0] = (slice_coords[0] - iter_x.pos) / iter_x.span->size; slice_coords[2] = (slice_coords[2] - iter_x.pos) / iter_x.span->size; /* Pluck out the cogl texture for this span */ span_tex = textures[iter_y.index * n_x_spans + iter_x.index]; callback (COGL_TEXTURE (span_tex), slice_coords, span_virtual_coords, user_data); } } } void _cogl_texture_set_allocated (CoglTexture *texture, CoglPixelFormat internal_format, int width, int height) { _cogl_texture_set_internal_format (texture, internal_format); texture->width = width; texture->height = height; texture->allocated = TRUE; _cogl_texture_free_loader (texture); } CoglBool cogl_texture_allocate (CoglTexture *texture, CoglError **error) { if (texture->allocated) return TRUE; if (texture->components == COGL_TEXTURE_COMPONENTS_RG && !cogl_has_feature (texture->context, COGL_FEATURE_ID_TEXTURE_RG)) _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_FORMAT, "A red-green texture was requested but the driver " "does not support them"); texture->allocated = texture->vtable->allocate (texture, error); return texture->allocated; } void _cogl_texture_set_internal_format (CoglTexture *texture, CoglPixelFormat internal_format) { texture->premultiplied = FALSE; if (internal_format == COGL_PIXEL_FORMAT_ANY) internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; if (internal_format == COGL_PIXEL_FORMAT_A_8) { texture->components = COGL_TEXTURE_COMPONENTS_A; return; } else if (internal_format == COGL_PIXEL_FORMAT_RG_88) { texture->components = COGL_TEXTURE_COMPONENTS_RG; return; } else if (internal_format & COGL_DEPTH_BIT) { texture->components = COGL_TEXTURE_COMPONENTS_DEPTH; return; } else if (internal_format & COGL_A_BIT) { texture->components = COGL_TEXTURE_COMPONENTS_RGBA; if (internal_format & COGL_PREMULT_BIT) texture->premultiplied = TRUE; return; } else texture->components = COGL_TEXTURE_COMPONENTS_RGB; } CoglPixelFormat _cogl_texture_determine_internal_format (CoglTexture *texture, CoglPixelFormat src_format) { switch (texture->components) { case COGL_TEXTURE_COMPONENTS_DEPTH: if (src_format & COGL_DEPTH_BIT) return src_format; else { CoglContext *ctx = texture->context; if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) || _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) { return COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8; } else return COGL_PIXEL_FORMAT_DEPTH_16; } case COGL_TEXTURE_COMPONENTS_A: return COGL_PIXEL_FORMAT_A_8; case COGL_TEXTURE_COMPONENTS_RG: return COGL_PIXEL_FORMAT_RG_88; case COGL_TEXTURE_COMPONENTS_RGB: if (src_format != COGL_PIXEL_FORMAT_ANY && !(src_format & COGL_A_BIT) && !(src_format & COGL_DEPTH_BIT)) return src_format; else return COGL_PIXEL_FORMAT_RGB_888; case COGL_TEXTURE_COMPONENTS_RGBA: { CoglPixelFormat format; if (src_format != COGL_PIXEL_FORMAT_ANY && (src_format & COGL_A_BIT) && src_format != COGL_PIXEL_FORMAT_A_8) format = src_format; else format = COGL_PIXEL_FORMAT_RGBA_8888; if (texture->premultiplied) { if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format)) return format |= COGL_PREMULT_BIT; else return COGL_PIXEL_FORMAT_RGBA_8888_PRE; } else return format & ~COGL_PREMULT_BIT; } } g_return_val_if_reached (COGL_PIXEL_FORMAT_RGBA_8888_PRE); } void cogl_texture_set_components (CoglTexture *texture, CoglTextureComponents components) { _COGL_RETURN_IF_FAIL (!texture->allocated); if (texture->components == components) return; texture->components = components; } CoglTextureComponents cogl_texture_get_components (CoglTexture *texture) { return texture->components; } void cogl_texture_set_premultiplied (CoglTexture *texture, CoglBool premultiplied) { _COGL_RETURN_IF_FAIL (!texture->allocated); premultiplied = !!premultiplied; if (texture->premultiplied == premultiplied) return; texture->premultiplied = premultiplied; } CoglBool cogl_texture_get_premultiplied (CoglTexture *texture) { return texture->premultiplied; } void _cogl_texture_copy_internal_format (CoglTexture *src, CoglTexture *dest) { cogl_texture_set_components (dest, src->components); cogl_texture_set_premultiplied (dest, src->premultiplied); } muffin-5.2.1/cogl/cogl/cogl-pipeline-snippet-private.h0000664000175000017500000000715314211404421023042 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011, 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifndef __COGL_PIPELINE_SNIPPET_PRIVATE_H #define __COGL_PIPELINE_SNIPPET_PRIVATE_H #include #include "cogl-snippet.h" typedef struct { GList *entries; } CoglPipelineSnippetList; /* Arguments to pass to _cogl_pipeline_snippet_generate_code() */ typedef struct { CoglPipelineSnippetList *snippets; /* Only snippets at this hook point will be used */ CoglSnippetHook hook; /* The final function to chain on to after all of the snippets code has been run */ const char *chain_function; /* The name of the final generated function */ const char *final_name; /* A prefix to insert before each generate function name */ const char *function_prefix; /* The return type of all of the functions, or NULL to use void */ const char *return_type; /* A variable to return from the functions. The snippets are expected to modify this variable. Ignored if return_type is NULL */ const char *return_variable; /* If this is TRUE then it won't allocate a separate variable for the return value. Instead it is expected that the snippet will modify one of the argument variables directly and that will be returned */ CoglBool return_variable_is_argument; /* The argument names or NULL if there are none */ const char *arguments; /* The argument types or NULL */ const char *argument_declarations; /* The string to generate the source into */ GString *source_buf; } CoglPipelineSnippetData; void _cogl_pipeline_snippet_generate_code (const CoglPipelineSnippetData *data); void _cogl_pipeline_snippet_generate_declarations (GString *declarations_buf, CoglSnippetHook hook, CoglPipelineSnippetList *list); void _cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list); void _cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list, CoglSnippet *snippet); void _cogl_pipeline_snippet_list_copy (CoglPipelineSnippetList *dst, const CoglPipelineSnippetList *src); void _cogl_pipeline_snippet_list_hash (CoglPipelineSnippetList *list, unsigned int *hash); CoglBool _cogl_pipeline_snippet_list_equal (CoglPipelineSnippetList *list0, CoglPipelineSnippetList *list1); #endif /* __COGL_PIPELINE_SNIPPET_PRIVATE_H */ muffin-5.2.1/cogl/cogl/Makefile.am0000664000175000017500000003705014211404421017045 0ustar jpeisachjpeisach# preamble NULL = SUBDIRS = BUILT_SOURCES = EXTRA_DIST = CLEANFILES = DISTCLEANFILES = AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(srcdir)/deprecated \ -I$(srcdir)/winsys \ -I$(srcdir)/driver/gl \ -I$(srcdir)/driver/gl/gl \ -I$(srcdir)/driver/gl/gles \ $(NULL) AM_CPPFLAGS += \ -DG_LOG_DOMAIN=\"Cogl\" \ -DCOGL_COMPILATION \ -DCOGL_GL_LIBNAME=\"$(COGL_GL_LIBNAME)\" \ -DCOGL_GLES1_LIBNAME=\"$(COGL_GLES1_LIBNAME)\" \ -DCOGL_GLES2_LIBNAME=\"$(COGL_GLES2_LIBNAME)\" \ -DCOGL_LOCALEDIR=\""$(localedir)"\" \ $(NULL) if HAVE_COGL_DEFAULT_DRIVER AM_CPPFLAGS += \ -DCOGL_DEFAULT_DRIVER=\"$(COGL_DEFAULT_DRIVER)\" endif AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS) BUILT_SOURCES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h DISTCLEANFILES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h EXTRA_DIST += cogl-defines.h.in cogl-egl-defines.h.in cogl-gl-header.h.in pc_files = muffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pc_files) DISTCLEANFILES += $(pc_files) cogl_deprecated_h = \ deprecated/cogl-material-compat.h \ deprecated/cogl-vertex-buffer.h \ deprecated/cogl-shader.h \ deprecated/cogl-clutter.h \ deprecated/cogl-type-casts.h \ deprecated/cogl-auto-texture.h \ $(NULL) cogl_deprecated_nonintrospected_h = \ deprecated/cogl-framebuffer-deprecated.h \ $(NULL) # public 1.x api headers cogl_1_public_h = \ $(cogl_deprecated_h) \ cogl1-context.h \ cogl-bitmap.h \ cogl-color.h \ cogl-matrix.h \ cogl-offscreen.h \ cogl-primitives.h \ cogl-texture.h \ cogl-types.h \ cogl.h \ $(NULL) cogl_nonintrospected_h = \ cogl-object.h \ cogl-renderer.h \ cogl-swap-chain.h \ cogl-onscreen-template.h \ cogl-display.h \ cogl-context.h \ cogl-pipeline.h \ cogl-pipeline-state.h \ cogl-pipeline-layer-state.h \ cogl-snippet.h \ cogl-gles2.h \ cogl-gles2-types.h \ cogl-index-buffer.h \ cogl-attribute-buffer.h \ cogl-indices.h \ cogl-attribute.h \ cogl-primitive.h \ cogl-framebuffer.h \ cogl-onscreen.h \ cogl-frame-info.h \ cogl-vector.h \ cogl-euler.h \ cogl-output.h \ cogl-quaternion.h \ cogl-matrix-stack.h \ cogl-poll.h \ cogl-texture-3d.h \ cogl-texture-2d.h \ cogl-texture-2d-gl.h \ cogl-texture-rectangle.h \ cogl-texture-2d-sliced.h \ cogl-sub-texture.h \ cogl-atlas-texture.h \ cogl-meta-texture.h \ cogl-primitive-texture.h \ cogl-depth-state.h \ cogl-buffer.h \ cogl-pixel-buffer.h \ cogl-macros.h \ cogl-fence.h \ cogl-version.h \ cogl-error.h \ cogl-bitmap.h \ cogl-color.h \ cogl-matrix.h \ cogl-texture.h \ cogl-types.h \ cogl-gtype-private.h \ cogl-muffin.h \ $(NULL) cogl_nodist_h = \ $(NULL) # nop driver cogl_driver_sources = \ driver/nop/cogl-driver-nop.c \ driver/nop/cogl-framebuffer-nop-private.h \ driver/nop/cogl-framebuffer-nop.c \ driver/nop/cogl-attribute-nop-private.h \ driver/nop/cogl-attribute-nop.c \ driver/nop/cogl-clip-stack-nop-private.h \ driver/nop/cogl-clip-stack-nop.c \ driver/nop/cogl-texture-2d-nop-private.h \ driver/nop/cogl-texture-2d-nop.c \ $(NULL) # gl driver sources cogl_gl_prototypes_h = \ gl-prototypes/cogl-gles2-functions.h \ gl-prototypes/cogl-core-functions.h \ gl-prototypes/cogl-in-gles-core-functions.h \ gl-prototypes/cogl-in-gles2-core-functions.h \ gl-prototypes/cogl-glsl-functions.h \ $(NULL) cogl_driver_sources += \ driver/gl/cogl-util-gl-private.h \ driver/gl/cogl-util-gl.c \ driver/gl/cogl-framebuffer-gl-private.h \ driver/gl/cogl-framebuffer-gl.c \ driver/gl/cogl-texture-gl-private.h \ driver/gl/cogl-texture-gl.c \ driver/gl/cogl-texture-2d-gl-private.h \ driver/gl/cogl-texture-2d-gl.c \ driver/gl/cogl-attribute-gl-private.h \ driver/gl/cogl-attribute-gl.c \ driver/gl/cogl-clip-stack-gl-private.h \ driver/gl/cogl-clip-stack-gl.c \ driver/gl/cogl-buffer-gl-private.h \ driver/gl/cogl-buffer-gl.c \ driver/gl/cogl-pipeline-opengl.c \ driver/gl/cogl-pipeline-opengl-private.h \ driver/gl/cogl-pipeline-fragend-glsl.c \ driver/gl/cogl-pipeline-fragend-glsl-private.h \ driver/gl/gl/cogl-pipeline-fragend-arbfp.c \ driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h \ driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c \ driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h \ driver/gl/cogl-pipeline-fragend-fixed.c \ driver/gl/cogl-pipeline-fragend-fixed-private.h \ driver/gl/cogl-pipeline-vertend-glsl.c \ driver/gl/cogl-pipeline-vertend-glsl-private.h \ driver/gl/cogl-pipeline-vertend-fixed.c \ driver/gl/cogl-pipeline-vertend-fixed-private.h \ driver/gl/cogl-pipeline-progend-fixed.c \ driver/gl/cogl-pipeline-progend-fixed-private.h \ driver/gl/cogl-pipeline-progend-glsl.c \ driver/gl/cogl-pipeline-progend-glsl-private.h \ $(NULL) if COGL_DRIVER_GL_SUPPORTED cogl_driver_sources += \ driver/gl/gl/cogl-driver-gl.c \ driver/gl/gl/cogl-texture-driver-gl.c \ $(NULL) endif if COGL_DRIVER_GLES_SUPPORTED cogl_driver_sources += \ driver/gl/gles/cogl-driver-gles.c \ driver/gl/gles/cogl-texture-driver-gles.c \ $(NULL) endif # winsys sources, common to all backends cogl_winsys_common_sources = \ winsys/cogl-winsys-private.h \ winsys/cogl-winsys.c \ $(NULL) # sources cogl_sources_c = \ $(cogl_driver_sources) \ $(cogl_winsys_common_sources) \ cogl-private.h \ cogl-i18n-private.h \ cogl-debug.h \ cogl-debug-options.h \ cogl-gpu-info.c \ cogl-gpu-info-private.h \ cogl-context-private.h \ cogl-context.c \ cogl-renderer-private.h \ cogl-renderer.h \ cogl-renderer.c \ cogl-swap-chain-private.h \ cogl-swap-chain.h \ cogl-swap-chain.c \ cogl-onscreen-template-private.h \ cogl-onscreen-template.h \ cogl-onscreen-template.c \ cogl-display-private.h \ cogl-display.h \ cogl-display.c \ cogl-driver.h \ cogl.c \ cogl-object-private.h \ cogl-object.h \ cogl-object.c \ cogl-util.h \ cogl-util.c \ cogl-bitmap-private.h \ cogl-bitmap.c \ cogl-bitmap-conversion.c \ cogl-bitmap-packing.h \ cogl-primitives-private.h \ cogl-primitives.h \ cogl-primitives.c \ cogl-bitmap-pixbuf.c \ cogl-clip-stack.h \ cogl-clip-stack.c \ cogl-feature-private.h \ cogl-feature-private.c \ cogl-color-private.h \ cogl-color.c \ cogl-buffer-private.h \ cogl-buffer.c \ cogl-pixel-buffer-private.h \ cogl-pixel-buffer.c \ cogl-index-buffer-private.h \ cogl-index-buffer.c \ cogl-attribute-buffer-private.h \ cogl-attribute-buffer.c \ cogl-indices-private.h \ cogl-indices.c \ cogl-attribute-private.h \ cogl-attribute.c \ cogl-primitive-private.h \ cogl-primitive.c \ cogl-matrix.c \ cogl-vector.c \ cogl-euler.c \ cogl-quaternion-private.h \ cogl-quaternion.c \ cogl-matrix-private.h \ cogl-matrix-stack.c \ cogl-matrix-stack-private.h \ cogl-depth-state.c \ cogl-depth-state-private.h \ cogl-node.c \ cogl-node-private.h \ cogl-pipeline.c \ cogl-pipeline-private.h \ cogl-pipeline-layer.c \ cogl-pipeline-layer-private.h \ cogl-pipeline-state.c \ cogl-pipeline-layer-state-private.h \ cogl-pipeline-layer-state.c \ cogl-pipeline-state-private.h \ cogl-pipeline-debug.c \ cogl-glsl-shader.c \ cogl-glsl-shader-private.h \ cogl-glsl-shader-boilerplate.h \ cogl-pipeline-snippet-private.h \ cogl-pipeline-snippet.c \ cogl-pipeline-cache.h \ cogl-pipeline-cache.c \ cogl-pipeline-hash-table.h \ cogl-pipeline-hash-table.c \ cogl-sampler-cache.c \ cogl-sampler-cache-private.h \ cogl-blend-string.c \ cogl-blend-string.h \ cogl-debug.c \ cogl-sub-texture-private.h \ cogl-texture-private.h \ cogl-texture-2d-private.h \ cogl-texture-2d-sliced-private.h \ cogl-texture-3d-private.h \ cogl-texture-driver.h \ cogl-sub-texture.c \ cogl-texture.c \ cogl-texture-2d.c \ cogl-texture-2d-sliced.c \ cogl-texture-3d.c \ cogl-texture-rectangle-private.h \ cogl-texture-rectangle.c \ cogl-rectangle-map.h \ cogl-rectangle-map.c \ cogl-atlas.h \ cogl-atlas.c \ cogl-atlas-texture-private.h \ cogl-atlas-texture.c \ cogl-meta-texture.c \ cogl-primitive-texture.c \ cogl-blit.h \ cogl-blit.c \ cogl-spans.h \ cogl-spans.c \ cogl-journal-private.h \ cogl-journal.c \ cogl-frame-info-private.h \ cogl-frame-info.c \ cogl-framebuffer-private.h \ cogl-framebuffer.c \ cogl-onscreen-private.h \ cogl-onscreen.c \ cogl-output-private.h \ cogl-output.c \ cogl-profile.h \ cogl-profile.c \ cogl-flags.h \ cogl-bitmask.h \ cogl-bitmask.c \ cogl-gtype.c \ cogl-gtype-private.h \ cogl-point-in-poly-private.h \ cogl-point-in-poly.c \ cogl-list.c \ cogl-list.h \ winsys/cogl-winsys-stub-private.h \ winsys/cogl-winsys-stub.c \ cogl-config-private.h \ cogl-config.c \ cogl-boxed-value.h \ cogl-boxed-value.c \ cogl-snippet-private.h \ cogl-snippet.c \ cogl-poll-private.h \ cogl-poll.c \ gl-prototypes/cogl-all-functions.h \ gl-prototypes/cogl-gles1-functions.h \ gl-prototypes/cogl-gles2-functions.h \ gl-prototypes/cogl-core-functions.h \ gl-prototypes/cogl-in-gles-core-functions.h \ gl-prototypes/cogl-in-gles1-core-functions.h \ gl-prototypes/cogl-in-gles2-core-functions.h \ gl-prototypes/cogl-fixed-functions.h \ gl-prototypes/cogl-glsl-functions.h \ cogl-memory-stack-private.h \ cogl-memory-stack.c \ cogl-magazine-private.h \ cogl-magazine.c \ cogl-gles2-context-private.h \ cogl-gles2-context.c \ cogl-error-private.h \ cogl-error.c \ cogl-closure-list-private.h \ cogl-closure-list.c \ cogl-fence.c \ cogl-fence-private.h \ deprecated/cogl-vertex-buffer-private.h \ deprecated/cogl-vertex-buffer.c \ deprecated/cogl-material-compat.c \ deprecated/cogl-program.c \ deprecated/cogl-program-private.h \ deprecated/cogl-auto-texture.c \ deprecated/cogl-shader-private.h \ deprecated/cogl-shader.c \ deprecated/cogl-clutter.c \ deprecated/cogl-framebuffer-deprecated.c \ $(NULL) cogl_nonintrospected_h += cogl-glib-source.h cogl_sources_c += cogl-glib-source.c if SUPPORT_XLIB cogl_deprecated_nonintrospected_h += deprecated/cogl-clutter-xlib.h cogl_1_public_h += cogl-xlib-renderer.h cogl_nonintrospected_h += \ winsys/cogl-texture-pixmap-x11.h \ cogl-xlib.h cogl_sources_c += \ cogl-x11-renderer-private.h \ cogl-xlib-renderer-private.h \ cogl-xlib-renderer.c \ cogl-xlib.c \ cogl-xlib-private.h \ winsys/cogl-texture-pixmap-x11.c \ winsys/cogl-texture-pixmap-x11-private.h endif if SUPPORT_GLX cogl_nonintrospected_h += cogl-glx.h cogl_sources_c += \ cogl-glx-renderer-private.h \ cogl-glx-display-private.h \ winsys/cogl-winsys-glx-feature-functions.h \ winsys/cogl-winsys-glx-private.h \ winsys/cogl-winsys-glx.c endif if SUPPORT_WAYLAND_EGL_SERVER cogl_nonintrospected_h += cogl-wayland-server.h endif if SUPPORT_EGL_PLATFORM_XLIB cogl_sources_c += \ winsys/cogl-winsys-egl-x11.c \ winsys/cogl-winsys-egl-x11-private.h endif if SUPPORT_EGL cogl_nonintrospected_h += cogl-egl.h cogl_nodist_h += cogl-egl-defines.h cogl_sources_c += \ cogl-egl-private.h \ winsys/cogl-winsys-egl.c \ winsys/cogl-winsys-egl-feature-functions.h \ winsys/cogl-winsys-egl-private.h endif muffinlibdir = $(libdir)/muffin muffinlib_LTLIBRARIES = libmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@.la libmuffin_cogl_@MUFFIN_PLUGIN_API_VERSION@_la_LIBADD = $(LIBM) $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS) if UNIT_TESTS libmuffin_cogl_@MUFFIN_PLUGIN_API_VERSION@_la_LIBADD += $(top_builddir)/test-fixtures/libtest-fixtures.la endif # XXX: The aim is to eventually get rid of all private API exports # for cogl-pango. libmuffin_cogl_@MUFFIN_PLUGIN_API_VERSION@_la_LDFLAGS = \ -no-undefined \ -avoid-version \ -export-dynamic \ -rpath $(muffinlibdir) \ -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_texture_set_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_|_cogl_winsys_glx_get_vtable|_cogl_winsys_egl_xlib_get_vtable|_cogl_winsys_egl_get_vtable|_cogl_closure_disconnect|_cogl_onscreen_notify_complete|_cogl_onscreen_notify_frame_sync|_cogl_winsys_egl_renderer_connect_common|_cogl_winsys_error_quark|_cogl_set_error|_cogl_poll_renderer_add_fd|_cogl_poll_renderer_add_idle|_cogl_framebuffer_winsys_update_size|_cogl_winsys_egl_make_current|_cogl_winsys_egl_ensure_current|_cogl_pixel_format_get_bytes_per_pixel).*" libmuffin_cogl_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = $(cogl_sources_c) nodist_libmuffin_cogl_@MUFFIN_PLUGIN_API_VERSION@_la_SOURCES = $(BUILT_SOURCES) # Cogl installed headers cogl_headers = \ $(cogl_1_public_h) \ cogl-deprecated.h \ cogl-pango.h \ $(NULL) cogl_base_includedir = $(includedir)/muffin cogldeprecatedincludedir = $(cogl_base_includedir)/cogl/cogl/deprecated cogldeprecatedinclude_HEADERS = $(cogl_deprecated_h) $(cogl_deprecated_nonintrospected_h) coglincludedir = $(cogl_base_includedir)/cogl/cogl coglinclude_HEADERS = $(cogl_headers) $(cogl_nonintrospected_h) nodist_coglinclude_HEADERS = $(cogl_nodist_h) cogl-defines.h cogl_proto_includedir = $(cogl_base_includedir)/cogl/cogl/gl-prototypes cogl_proto_include_HEADERS = $(cogl_gl_prototypes_h) EXTRA_DIST += \ cogl.symbols -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = if HAVE_INTROSPECTION Cogl-@MUFFIN_PLUGIN_API_VERSION@.gir: libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la Makefile Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_NAMESPACE = Cogl Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_VERSION = $(MUFFIN_PLUGIN_API_VERSION) Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_LIBS = libmuffin-cogl-$(MUFFIN_PLUGIN_API_VERSION).la if UNIT_TESTS Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_LIBS += $(top_builddir)/test-fixtures/libtest-fixtures.la endif Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_FILES = $(cogl_1_public_h) Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) -UCOGL_COMPILATION -D__COGL_H_INSIDE__ -D__COGL_XLIB_H_INSIDE__ -D__COGL_EGL_H_INSIDE__ -D__COGL_GLX_H_INSIDE__ -DCOGL_GIR_SCANNING Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_INCLUDES = GL-1.0 GObject-2.0 Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_EXPORT_PACKAGES = muffin-cogl-@MUFFIN_PLUGIN_API_VERSION@ Cogl_@MUFFIN_PLUGIN_API_VERSION@_gir_SCANNERFLAGS = --warn-all --c-include='cogl/cogl.h' INTROSPECTION_GIRS += Cogl-@MUFFIN_PLUGIN_API_VERSION@.gir girdir = $(muffinlibdir) gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(muffinlibdir) typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) endif muffin-5.2.1/cogl/cogl/cogl-pipeline.h0000664000175000017500000001330314211404421017704 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PIPELINE_H__ #define __COGL_PIPELINE_H__ /* We forward declare the CoglPipeline type here to avoid some circular * dependency issues with the following headers. */ typedef struct _CoglPipeline CoglPipeline; #include #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-pipeline * @short_description: Functions for creating and manipulating the GPU * pipeline * * Cogl allows creating and manipulating objects representing the full * configuration of the GPU pipeline. In simplified terms the GPU * pipeline takes primitive geometry as the input, it first performs * vertex processing, allowing you to deform your geometry, then * rasterizes that (turning it from pure geometry into fragments) then * performs fragment processing including depth testing and texture * mapping. Finally it blends the result with the framebuffer. */ #define COGL_PIPELINE(OBJECT) ((CoglPipeline *)OBJECT) /** * cogl_pipeline_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_pipeline_get_gtype (void); /** * cogl_pipeline_new: * @context: a #CoglContext * * Allocates and initializes a default simple pipeline that will color * a primitive white. * * Return value: (transfer full): a pointer to a new #CoglPipeline * * Since: 2.0 * Stability: Unstable */ CoglPipeline * cogl_pipeline_new (CoglContext *context); /** * cogl_pipeline_copy: * @source: a #CoglPipeline object to copy * * Creates a new pipeline with the configuration copied from the * source pipeline. * * We would strongly advise developers to always aim to use * cogl_pipeline_copy() instead of cogl_pipeline_new() whenever there will * be any similarity between two pipelines. Copying a pipeline helps Cogl * keep track of a pipelines ancestry which we may use to help minimize GPU * state changes. * * Return value: (transfer full): a pointer to the newly allocated #CoglPipeline * * Since: 2.0 * Stability: Unstable */ CoglPipeline * cogl_pipeline_copy (CoglPipeline *source); /** * cogl_is_pipeline: * @object: A #CoglObject * * Gets whether the given @object references an existing pipeline object. * * Return value: %TRUE if the @object references a #CoglPipeline, * %FALSE otherwise * * Since: 2.0 * Stability: Unstable */ CoglBool cogl_is_pipeline (void *object); /** * CoglPipelineLayerCallback: * @pipeline: The #CoglPipeline whos layers are being iterated * @layer_index: The current layer index * @user_data: The private data passed to cogl_pipeline_foreach_layer() * * The callback prototype used with cogl_pipeline_foreach_layer() for * iterating all the layers of a @pipeline. * * Since: 2.0 * Stability: Unstable */ typedef CoglBool (*CoglPipelineLayerCallback) (CoglPipeline *pipeline, int layer_index, void *user_data); /** * cogl_pipeline_foreach_layer: * @pipeline: A #CoglPipeline object * @callback: (scope call): A #CoglPipelineLayerCallback to be * called for each layer index * @user_data: (closure): Private data that will be passed to the * callback * * Iterates all the layer indices of the given @pipeline. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_foreach_layer (CoglPipeline *pipeline, CoglPipelineLayerCallback callback, void *user_data); /** * cogl_pipeline_get_uniform_location: * @pipeline: A #CoglPipeline object * @uniform_name: The name of a uniform * * This is used to get an integer representing the uniform with the * name @uniform_name. The integer can be passed to functions such as * cogl_pipeline_set_uniform_1f() to set the value of a uniform. * * This function will always return a valid integer. Ie, unlike * OpenGL, it does not return -1 if the uniform is not available in * this pipeline so it can not be used to test whether uniforms are * present. It is not necessary to set the program on the pipeline * before calling this function. * * Return value: A integer representing the location of the given uniform. * * Since: 2.0 * Stability: Unstable */ int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); COGL_END_DECLS #endif /* __COGL_PIPELINE_H__ */ muffin-5.2.1/cogl/cogl/cogl-pipeline-state.c0000664000175000017500000021360014211404421021017 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-color-private.h" #include "cogl-blend-string.h" #include "cogl-util.h" #include "cogl-depth-state-private.h" #include "cogl-pipeline-state-private.h" #include "cogl-snippet-private.h" #include "cogl-error-private.h" #include #include "string.h" #ifndef GL_FUNC_ADD #define GL_FUNC_ADD 0x8006 #endif CoglPipeline * _cogl_pipeline_get_user_program (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), NULL); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER); return authority->big_state->user_program; } CoglBool _cogl_pipeline_color_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return cogl_color_equal (&authority0->color, &authority1->color); } CoglBool _cogl_pipeline_lighting_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { CoglPipelineLightingState *state0 = &authority0->big_state->lighting_state; CoglPipelineLightingState *state1 = &authority1->big_state->lighting_state; if (memcmp (state0->ambient, state1->ambient, sizeof (float) * 4) != 0) return FALSE; if (memcmp (state0->diffuse, state1->diffuse, sizeof (float) * 4) != 0) return FALSE; if (memcmp (state0->specular, state1->specular, sizeof (float) * 4) != 0) return FALSE; if (memcmp (state0->emission, state1->emission, sizeof (float) * 4) != 0) return FALSE; if (state0->shininess != state1->shininess) return FALSE; return TRUE; } CoglBool _cogl_pipeline_alpha_func_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { CoglPipelineAlphaFuncState *alpha_state0 = &authority0->big_state->alpha_state; CoglPipelineAlphaFuncState *alpha_state1 = &authority1->big_state->alpha_state; return alpha_state0->alpha_func == alpha_state1->alpha_func; } CoglBool _cogl_pipeline_alpha_func_reference_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { CoglPipelineAlphaFuncState *alpha_state0 = &authority0->big_state->alpha_state; CoglPipelineAlphaFuncState *alpha_state1 = &authority1->big_state->alpha_state; return (alpha_state0->alpha_func_reference == alpha_state1->alpha_func_reference); } CoglBool _cogl_pipeline_blend_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { CoglPipelineBlendState *blend_state0 = &authority0->big_state->blend_state; CoglPipelineBlendState *blend_state1 = &authority1->big_state->blend_state; _COGL_GET_CONTEXT (ctx, FALSE); if (blend_state0->blend_equation_rgb != blend_state1->blend_equation_rgb) return FALSE; if (blend_state0->blend_equation_alpha != blend_state1->blend_equation_alpha) return FALSE; if (blend_state0->blend_src_factor_alpha != blend_state1->blend_src_factor_alpha) return FALSE; if (blend_state0->blend_dst_factor_alpha != blend_state1->blend_dst_factor_alpha) return FALSE; if (blend_state0->blend_src_factor_rgb != blend_state1->blend_src_factor_rgb) return FALSE; if (blend_state0->blend_dst_factor_rgb != blend_state1->blend_dst_factor_rgb) return FALSE; if (blend_state0->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || blend_state0->blend_src_factor_rgb == GL_CONSTANT_COLOR || blend_state0->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || blend_state0->blend_dst_factor_rgb == GL_CONSTANT_COLOR) { if (!cogl_color_equal (&blend_state0->blend_constant, &blend_state1->blend_constant)) return FALSE; } return TRUE; } CoglBool _cogl_pipeline_depth_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { if (authority0->big_state->depth_state.test_enabled == FALSE && authority1->big_state->depth_state.test_enabled == FALSE) return TRUE; else { CoglDepthState *s0 = &authority0->big_state->depth_state; CoglDepthState *s1 = &authority1->big_state->depth_state; return s0->test_enabled == s1->test_enabled && s0->test_function == s1->test_function && s0->write_enabled == s1->write_enabled && s0->range_near == s1->range_near && s0->range_far == s1->range_far; } } CoglBool _cogl_pipeline_fog_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { CoglPipelineFogState *fog_state0 = &authority0->big_state->fog_state; CoglPipelineFogState *fog_state1 = &authority1->big_state->fog_state; if (fog_state0->enabled == fog_state1->enabled && cogl_color_equal (&fog_state0->color, &fog_state1->color) && fog_state0->mode == fog_state1->mode && fog_state0->density == fog_state1->density && fog_state0->z_near == fog_state1->z_near && fog_state0->z_far == fog_state1->z_far) return TRUE; else return FALSE; } CoglBool _cogl_pipeline_non_zero_point_size_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return (authority0->big_state->non_zero_point_size == authority1->big_state->non_zero_point_size); } CoglBool _cogl_pipeline_point_size_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return authority0->big_state->point_size == authority1->big_state->point_size; } CoglBool _cogl_pipeline_per_vertex_point_size_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return (authority0->big_state->per_vertex_point_size == authority1->big_state->per_vertex_point_size); } CoglBool _cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { CoglPipelineLogicOpsState *logic_ops_state0 = &authority0->big_state->logic_ops_state; CoglPipelineLogicOpsState *logic_ops_state1 = &authority1->big_state->logic_ops_state; return logic_ops_state0->color_mask == logic_ops_state1->color_mask; } CoglBool _cogl_pipeline_cull_face_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { CoglPipelineCullFaceState *cull_face_state0 = &authority0->big_state->cull_face_state; CoglPipelineCullFaceState *cull_face_state1 = &authority1->big_state->cull_face_state; /* The cull face state is considered equal if two pipelines are both set to no culling. If the front winding property is ever used for anything else or the comparison is used not just for drawing then this would have to change */ if (cull_face_state0->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE) return cull_face_state1->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE; return (cull_face_state0->mode == cull_face_state1->mode && cull_face_state0->front_winding == cull_face_state1->front_winding); } CoglBool _cogl_pipeline_user_shader_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return (authority0->big_state->user_program == authority1->big_state->user_program); } typedef struct { const CoglBoxedValue **dst_values; const CoglBoxedValue *src_values; int override_count; } GetUniformsClosure; static CoglBool get_uniforms_cb (int uniform_num, void *user_data) { GetUniformsClosure *data = user_data; if (data->dst_values[uniform_num] == NULL) data->dst_values[uniform_num] = data->src_values + data->override_count; data->override_count++; return TRUE; } static void _cogl_pipeline_get_all_uniform_values (CoglPipeline *pipeline, const CoglBoxedValue **values) { GetUniformsClosure data; _COGL_GET_CONTEXT (ctx, NO_RETVAL); memset (values, 0, sizeof (const CoglBoxedValue *) * ctx->n_uniform_names); data.dst_values = values; do { if ((pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)) { const CoglPipelineUniformsState *uniforms_state = &pipeline->big_state->uniforms_state; data.override_count = 0; data.src_values = uniforms_state->override_values; _cogl_bitmask_foreach (&uniforms_state->override_mask, get_uniforms_cb, &data); } pipeline = _cogl_pipeline_get_parent (pipeline); } while (pipeline); } CoglBool _cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { unsigned long *differences; const CoglBoxedValue **values0, **values1; int n_longs; int i; _COGL_GET_CONTEXT (ctx, FALSE); if (authority0 == authority1) return TRUE; values0 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names); values1 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names); n_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names); differences = g_alloca (n_longs * sizeof (unsigned long)); memset (differences, 0, sizeof (unsigned long) * n_longs); _cogl_pipeline_compare_uniform_differences (differences, authority0, authority1); _cogl_pipeline_get_all_uniform_values (authority0, values0); _cogl_pipeline_get_all_uniform_values (authority1, values1); COGL_FLAGS_FOREACH_START (differences, n_longs, i) { const CoglBoxedValue *value0 = values0[i]; const CoglBoxedValue *value1 = values1[i]; if (value0 == NULL) { if (value1 != NULL && value1->type != COGL_BOXED_NONE) return FALSE; } else if (value1 == NULL) { if (value0 != NULL && value0->type != COGL_BOXED_NONE) return FALSE; } else if (!_cogl_boxed_value_equal (value0, value1)) return FALSE; } COGL_FLAGS_FOREACH_END; return TRUE; } CoglBool _cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return _cogl_pipeline_snippet_list_equal (&authority0->big_state-> vertex_snippets, &authority1->big_state-> vertex_snippets); } CoglBool _cogl_pipeline_fragment_snippets_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return _cogl_pipeline_snippet_list_equal (&authority0->big_state-> fragment_snippets, &authority1->big_state-> fragment_snippets); } void cogl_pipeline_get_color (CoglPipeline *pipeline, CoglColor *color) { CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); *color = authority->color; } /* This is used heavily by the cogl journal when logging quads */ void _cogl_pipeline_get_colorubv (CoglPipeline *pipeline, uint8_t *color) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); _cogl_color_get_rgba_4ubv (&authority->color, color); } void cogl_pipeline_set_color (CoglPipeline *pipeline, const CoglColor *color) { CoglPipelineState state = COGL_PIPELINE_STATE_COLOR; CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); if (cogl_color_equal (color, &authority->color)) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, color, FALSE); pipeline->color = *color; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_color_equal); pipeline->dirty_real_blend_enable = TRUE; } void cogl_pipeline_set_color4ub (CoglPipeline *pipeline, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { CoglColor color; cogl_color_init_from_4ub (&color, red, green, blue, alpha); cogl_pipeline_set_color (pipeline, &color); } void cogl_pipeline_set_color4f (CoglPipeline *pipeline, float red, float green, float blue, float alpha) { CoglColor color; cogl_color_init_from_4f (&color, red, green, blue, alpha); cogl_pipeline_set_color (pipeline, &color); } CoglPipelineBlendEnable _cogl_pipeline_get_blend_enabled (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE); return authority->blend_enable; } static CoglBool _cogl_pipeline_blend_enable_equal (CoglPipeline *authority0, CoglPipeline *authority1) { return authority0->blend_enable == authority1->blend_enable ? TRUE : FALSE; } void _cogl_pipeline_set_blend_enabled (CoglPipeline *pipeline, CoglPipelineBlendEnable enable) { CoglPipelineState state = COGL_PIPELINE_STATE_BLEND_ENABLE; CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); _COGL_RETURN_IF_FAIL (enable > 1 && "don't pass TRUE or FALSE to _set_blend_enabled!"); authority = _cogl_pipeline_get_authority (pipeline, state); if (authority->blend_enable == enable) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->blend_enable = enable; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_blend_enable_equal); pipeline->dirty_real_blend_enable = TRUE; } void cogl_pipeline_get_ambient (CoglPipeline *pipeline, CoglColor *ambient) { CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); cogl_color_init_from_4fv (ambient, authority->big_state->lighting_state.ambient); } void cogl_pipeline_set_ambient (CoglPipeline *pipeline, const CoglColor *ambient) { CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; CoglPipeline *authority; CoglPipelineLightingState *lighting_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); lighting_state = &authority->big_state->lighting_state; if (cogl_color_equal (ambient, &lighting_state->ambient)) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); lighting_state = &pipeline->big_state->lighting_state; lighting_state->ambient[0] = cogl_color_get_red_float (ambient); lighting_state->ambient[1] = cogl_color_get_green_float (ambient); lighting_state->ambient[2] = cogl_color_get_blue_float (ambient); lighting_state->ambient[3] = cogl_color_get_alpha_float (ambient); _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); pipeline->dirty_real_blend_enable = TRUE; } void cogl_pipeline_get_diffuse (CoglPipeline *pipeline, CoglColor *diffuse) { CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); cogl_color_init_from_4fv (diffuse, authority->big_state->lighting_state.diffuse); } void cogl_pipeline_set_diffuse (CoglPipeline *pipeline, const CoglColor *diffuse) { CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; CoglPipeline *authority; CoglPipelineLightingState *lighting_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); lighting_state = &authority->big_state->lighting_state; if (cogl_color_equal (diffuse, &lighting_state->diffuse)) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); lighting_state = &pipeline->big_state->lighting_state; lighting_state->diffuse[0] = cogl_color_get_red_float (diffuse); lighting_state->diffuse[1] = cogl_color_get_green_float (diffuse); lighting_state->diffuse[2] = cogl_color_get_blue_float (diffuse); lighting_state->diffuse[3] = cogl_color_get_alpha_float (diffuse); _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); pipeline->dirty_real_blend_enable = TRUE; } void cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline, const CoglColor *color) { cogl_pipeline_set_ambient (pipeline, color); cogl_pipeline_set_diffuse (pipeline, color); } void cogl_pipeline_get_specular (CoglPipeline *pipeline, CoglColor *specular) { CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); cogl_color_init_from_4fv (specular, authority->big_state->lighting_state.specular); } void cogl_pipeline_set_specular (CoglPipeline *pipeline, const CoglColor *specular) { CoglPipeline *authority; CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; CoglPipelineLightingState *lighting_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); lighting_state = &authority->big_state->lighting_state; if (cogl_color_equal (specular, &lighting_state->specular)) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); lighting_state = &pipeline->big_state->lighting_state; lighting_state->specular[0] = cogl_color_get_red_float (specular); lighting_state->specular[1] = cogl_color_get_green_float (specular); lighting_state->specular[2] = cogl_color_get_blue_float (specular); lighting_state->specular[3] = cogl_color_get_alpha_float (specular); _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); pipeline->dirty_real_blend_enable = TRUE; } float cogl_pipeline_get_shininess (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); return authority->big_state->lighting_state.shininess; } void cogl_pipeline_set_shininess (CoglPipeline *pipeline, float shininess) { CoglPipeline *authority; CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; CoglPipelineLightingState *lighting_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); if (shininess < 0.0) { g_warning ("Out of range shininess %f supplied for pipeline\n", shininess); return; } authority = _cogl_pipeline_get_authority (pipeline, state); lighting_state = &authority->big_state->lighting_state; if (lighting_state->shininess == shininess) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); lighting_state = &pipeline->big_state->lighting_state; lighting_state->shininess = shininess; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); } void cogl_pipeline_get_emission (CoglPipeline *pipeline, CoglColor *emission) { CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); cogl_color_init_from_4fv (emission, authority->big_state->lighting_state.emission); } void cogl_pipeline_set_emission (CoglPipeline *pipeline, const CoglColor *emission) { CoglPipeline *authority; CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; CoglPipelineLightingState *lighting_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); lighting_state = &authority->big_state->lighting_state; if (cogl_color_equal (emission, &lighting_state->emission)) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); lighting_state = &pipeline->big_state->lighting_state; lighting_state->emission[0] = cogl_color_get_red_float (emission); lighting_state->emission[1] = cogl_color_get_green_float (emission); lighting_state->emission[2] = cogl_color_get_blue_float (emission); lighting_state->emission[3] = cogl_color_get_alpha_float (emission); _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); pipeline->dirty_real_blend_enable = TRUE; } static void _cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, CoglPipelineAlphaFunc alpha_func) { CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC; CoglPipeline *authority; CoglPipelineAlphaFuncState *alpha_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); alpha_state = &authority->big_state->alpha_state; if (alpha_state->alpha_func == alpha_func) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); alpha_state = &pipeline->big_state->alpha_state; alpha_state->alpha_func = alpha_func; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_alpha_func_state_equal); } static void _cogl_pipeline_set_alpha_test_function_reference (CoglPipeline *pipeline, float alpha_reference) { CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE; CoglPipeline *authority; CoglPipelineAlphaFuncState *alpha_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); alpha_state = &authority->big_state->alpha_state; if (alpha_state->alpha_func_reference == alpha_reference) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); alpha_state = &pipeline->big_state->alpha_state; alpha_state->alpha_func_reference = alpha_reference; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_alpha_func_reference_state_equal); } void cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, CoglPipelineAlphaFunc alpha_func, float alpha_reference) { _cogl_pipeline_set_alpha_test_function (pipeline, alpha_func); _cogl_pipeline_set_alpha_test_function_reference (pipeline, alpha_reference); } CoglPipelineAlphaFunc cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_ALPHA_FUNC); return authority->big_state->alpha_state.alpha_func; } float cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0.0f); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE); return authority->big_state->alpha_state.alpha_func_reference; } static GLenum arg_to_gl_blend_factor (CoglBlendStringArgument *arg) { if (arg->source.is_zero) return GL_ZERO; if (arg->factor.is_one) return GL_ONE; else if (arg->factor.is_src_alpha_saturate) return GL_SRC_ALPHA_SATURATE; else if (arg->factor.source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) { if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) { if (arg->factor.source.one_minus) return GL_ONE_MINUS_SRC_COLOR; else return GL_SRC_COLOR; } else { if (arg->factor.source.one_minus) return GL_ONE_MINUS_SRC_ALPHA; else return GL_SRC_ALPHA; } } else if (arg->factor.source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR) { if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) { if (arg->factor.source.one_minus) return GL_ONE_MINUS_DST_COLOR; else return GL_DST_COLOR; } else { if (arg->factor.source.one_minus) return GL_ONE_MINUS_DST_ALPHA; else return GL_DST_ALPHA; } } #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) else if (arg->factor.source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) { if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) { if (arg->factor.source.one_minus) return GL_ONE_MINUS_CONSTANT_COLOR; else return GL_CONSTANT_COLOR; } else { if (arg->factor.source.one_minus) return GL_ONE_MINUS_CONSTANT_ALPHA; else return GL_CONSTANT_ALPHA; } } #endif g_warning ("Unable to determine valid blend factor from blend string\n"); return GL_ONE; } static void setup_blend_state (CoglBlendStringStatement *statement, GLenum *blend_equation, GLint *blend_src_factor, GLint *blend_dst_factor) { switch (statement->function->type) { case COGL_BLEND_STRING_FUNCTION_ADD: *blend_equation = GL_FUNC_ADD; break; /* TODO - add more */ default: g_warning ("Unsupported blend function given"); *blend_equation = GL_FUNC_ADD; } *blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]); *blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]); } CoglBool cogl_pipeline_set_blend (CoglPipeline *pipeline, const char *blend_description, CoglError **error) { CoglPipelineState state = COGL_PIPELINE_STATE_BLEND; CoglPipeline *authority; CoglBlendStringStatement statements[2]; CoglBlendStringStatement *rgb; CoglBlendStringStatement *a; int count; CoglPipelineBlendState *blend_state; _COGL_GET_CONTEXT (ctx, FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); count = _cogl_blend_string_compile (blend_description, COGL_BLEND_STRING_CONTEXT_BLENDING, statements, error); if (!count) return FALSE; if (count == 1) rgb = a = statements; else { rgb = &statements[0]; a = &statements[1]; } authority = _cogl_pipeline_get_authority (pipeline, state); /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); blend_state = &pipeline->big_state->blend_state; setup_blend_state (rgb, &blend_state->blend_equation_rgb, &blend_state->blend_src_factor_rgb, &blend_state->blend_dst_factor_rgb); setup_blend_state (a, &blend_state->blend_equation_alpha, &blend_state->blend_src_factor_alpha, &blend_state->blend_dst_factor_alpha); /* If we are the current authority see if we can revert to one of our * ancestors being the authority */ if (pipeline == authority && _cogl_pipeline_get_parent (authority) != NULL) { CoglPipeline *parent = _cogl_pipeline_get_parent (authority); CoglPipeline *old_authority = _cogl_pipeline_get_authority (parent, state); if (_cogl_pipeline_blend_state_equal (authority, old_authority)) pipeline->differences &= ~state; } /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (pipeline != authority) { pipeline->differences |= state; _cogl_pipeline_prune_redundant_ancestry (pipeline); } pipeline->dirty_real_blend_enable = TRUE; return TRUE; } void cogl_pipeline_set_blend_constant (CoglPipeline *pipeline, const CoglColor *constant_color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLEND_CONSTANT)) return; #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) { CoglPipelineState state = COGL_PIPELINE_STATE_BLEND; CoglPipeline *authority; CoglPipelineBlendState *blend_state; authority = _cogl_pipeline_get_authority (pipeline, state); blend_state = &authority->big_state->blend_state; if (cogl_color_equal (constant_color, &blend_state->blend_constant)) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); blend_state = &pipeline->big_state->blend_state; blend_state->blend_constant = *constant_color; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_blend_state_equal); pipeline->dirty_real_blend_enable = TRUE; } #endif } CoglHandle cogl_pipeline_get_user_program (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), COGL_INVALID_HANDLE); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER); return authority->big_state->user_program; } /* XXX: for now we don't mind if the program has vertex shaders * attached but if we ever make a similar API public we should only * allow attaching of programs containing fragment shaders. Eventually * we will have a CoglPipeline abstraction to also cover vertex * processing. */ void cogl_pipeline_set_user_program (CoglPipeline *pipeline, CoglHandle program) { CoglPipelineState state = COGL_PIPELINE_STATE_USER_SHADER; CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); if (authority->big_state->user_program == program) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); if (program != COGL_INVALID_HANDLE) _cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_UNDEFINED); /* If we are the current authority see if we can revert to one of our * ancestors being the authority */ if (pipeline == authority && _cogl_pipeline_get_parent (authority) != NULL) { CoglPipeline *parent = _cogl_pipeline_get_parent (authority); CoglPipeline *old_authority = _cogl_pipeline_get_authority (parent, state); if (old_authority->big_state->user_program == program) pipeline->differences &= ~state; } else if (pipeline != authority) { /* If we weren't previously the authority on this state then we * need to extended our differences mask and so it's possible * that some of our ancestry will now become redundant, so we * aim to reparent ourselves if that's true... */ pipeline->differences |= state; _cogl_pipeline_prune_redundant_ancestry (pipeline); } if (program != COGL_INVALID_HANDLE) cogl_handle_ref (program); if (authority == pipeline && pipeline->big_state->user_program != COGL_INVALID_HANDLE) cogl_handle_unref (pipeline->big_state->user_program); pipeline->big_state->user_program = program; pipeline->dirty_real_blend_enable = TRUE; } CoglBool cogl_pipeline_set_depth_state (CoglPipeline *pipeline, const CoglDepthState *depth_state, CoglError **error) { CoglPipelineState state = COGL_PIPELINE_STATE_DEPTH; CoglPipeline *authority; CoglDepthState *orig_state; _COGL_GET_CONTEXT (ctx, FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); _COGL_RETURN_VAL_IF_FAIL (depth_state->magic == COGL_DEPTH_STATE_MAGIC, FALSE); authority = _cogl_pipeline_get_authority (pipeline, state); orig_state = &authority->big_state->depth_state; if (orig_state->test_enabled == depth_state->test_enabled && orig_state->write_enabled == depth_state->write_enabled && orig_state->test_function == depth_state->test_function && orig_state->range_near == depth_state->range_near && orig_state->range_far == depth_state->range_far) return TRUE; if (ctx->driver == COGL_DRIVER_GLES1 && (depth_state->range_near != 0 || depth_state->range_far != 1)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "glDepthRange not available on GLES 1"); return FALSE; } /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->big_state->depth_state = *depth_state; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_depth_state_equal); return TRUE; } void cogl_pipeline_get_depth_state (CoglPipeline *pipeline, CoglDepthState *state) { CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH); *state = authority->big_state->depth_state; } CoglColorMask cogl_pipeline_get_color_mask (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS); return authority->big_state->logic_ops_state.color_mask; } void cogl_pipeline_set_color_mask (CoglPipeline *pipeline, CoglColorMask color_mask) { CoglPipelineState state = COGL_PIPELINE_STATE_LOGIC_OPS; CoglPipeline *authority; CoglPipelineLogicOpsState *logic_ops_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); logic_ops_state = &authority->big_state->logic_ops_state; if (logic_ops_state->color_mask == color_mask) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); logic_ops_state = &pipeline->big_state->logic_ops_state; logic_ops_state->color_mask = color_mask; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_logic_ops_state_equal); } void _cogl_pipeline_set_fog_state (CoglPipeline *pipeline, const CoglPipelineFogState *fog_state) { CoglPipelineState state = COGL_PIPELINE_STATE_FOG; CoglPipeline *authority; CoglPipelineFogState *current_fog_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); current_fog_state = &authority->big_state->fog_state; if (current_fog_state->enabled == fog_state->enabled && cogl_color_equal (¤t_fog_state->color, &fog_state->color) && current_fog_state->mode == fog_state->mode && current_fog_state->density == fog_state->density && current_fog_state->z_near == fog_state->z_near && current_fog_state->z_far == fog_state->z_far) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->big_state->fog_state = *fog_state; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_fog_state_equal); } void cogl_pipeline_set_cull_face_mode (CoglPipeline *pipeline, CoglPipelineCullFaceMode cull_face_mode) { CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE; CoglPipeline *authority; CoglPipelineCullFaceState *cull_face_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); cull_face_state = &authority->big_state->cull_face_state; if (cull_face_state->mode == cull_face_mode) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->big_state->cull_face_state.mode = cull_face_mode; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_cull_face_state_equal); } void cogl_pipeline_set_front_face_winding (CoglPipeline *pipeline, CoglWinding front_winding) { CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE; CoglPipeline *authority; CoglPipelineCullFaceState *cull_face_state; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); cull_face_state = &authority->big_state->cull_face_state; if (cull_face_state->front_winding == front_winding) return; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->big_state->cull_face_state.front_winding = front_winding; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_cull_face_state_equal); } CoglPipelineCullFaceMode cogl_pipeline_get_cull_face_mode (CoglPipeline *pipeline) { CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE; CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), COGL_PIPELINE_CULL_FACE_MODE_NONE); authority = _cogl_pipeline_get_authority (pipeline, state); return authority->big_state->cull_face_state.mode; } CoglWinding cogl_pipeline_get_front_face_winding (CoglPipeline *pipeline) { CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE; CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), COGL_PIPELINE_CULL_FACE_MODE_NONE); authority = _cogl_pipeline_get_authority (pipeline, state); return authority->big_state->cull_face_state.front_winding; } float cogl_pipeline_get_point_size (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE); return authority->big_state->point_size; } static void _cogl_pipeline_set_non_zero_point_size (CoglPipeline *pipeline, CoglBool value) { CoglPipelineState state = COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE; CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->big_state->non_zero_point_size = !!value; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_non_zero_point_size_equal); } void cogl_pipeline_set_point_size (CoglPipeline *pipeline, float point_size) { CoglPipelineState state = COGL_PIPELINE_STATE_POINT_SIZE; CoglPipeline *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, state); if (authority->big_state->point_size == point_size) return; /* Changing the point size may additionally modify * COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE. */ if ((authority->big_state->point_size > 0.0f) != (point_size > 0.0f)) _cogl_pipeline_set_non_zero_point_size (pipeline, point_size > 0.0f); /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->big_state->point_size = point_size; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_point_size_equal); } CoglBool cogl_pipeline_set_per_vertex_point_size (CoglPipeline *pipeline, CoglBool enable, CoglError **error) { CoglPipelineState state = COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE; CoglPipeline *authority; _COGL_GET_CONTEXT (ctx, FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); authority = _cogl_pipeline_get_authority (pipeline, state); enable = !!enable; if (authority->big_state->per_vertex_point_size == enable) return TRUE; if (enable && !cogl_has_feature (ctx, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Per-vertex point size is not supported"); return FALSE; } /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); pipeline->big_state->per_vertex_point_size = enable; _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_point_size_equal); return TRUE; } CoglBool cogl_pipeline_get_per_vertex_point_size (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE); return authority->big_state->per_vertex_point_size; } static CoglBoxedValue * _cogl_pipeline_override_uniform (CoglPipeline *pipeline, int location) { CoglPipelineState state = COGL_PIPELINE_STATE_UNIFORMS; CoglPipelineUniformsState *uniforms_state; int override_index; _COGL_GET_CONTEXT (ctx, NULL); g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL); g_return_val_if_fail (location >= 0, NULL); g_return_val_if_fail (location < ctx->n_uniform_names, NULL); /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); uniforms_state = &pipeline->big_state->uniforms_state; /* Count the number of bits that are set below this location. That should give us the position where our new value should lie */ override_index = _cogl_bitmask_popcount_upto (&uniforms_state->override_mask, location); _cogl_bitmask_set (&uniforms_state->changed_mask, location, TRUE); /* If this pipeline already has an override for this value then we can just use it directly */ if (_cogl_bitmask_get (&uniforms_state->override_mask, location)) return uniforms_state->override_values + override_index; /* We need to create a new override value in the right position within the array. This is pretty inefficient but the hope is that it will be much more common to modify an existing uniform rather than modify a new one so it is more important to optimise the former case. */ if (uniforms_state->override_values == NULL) { g_assert (override_index == 0); uniforms_state->override_values = g_new (CoglBoxedValue, 1); } else { /* We need to grow the array and copy in the old values */ CoglBoxedValue *old_values = uniforms_state->override_values; int old_size = _cogl_bitmask_popcount (&uniforms_state->override_mask); uniforms_state->override_values = g_new (CoglBoxedValue, old_size + 1); /* Copy in the old values leaving a gap for the new value */ memcpy (uniforms_state->override_values, old_values, sizeof (CoglBoxedValue) * override_index); memcpy (uniforms_state->override_values + override_index + 1, old_values + override_index, sizeof (CoglBoxedValue) * (old_size - override_index)); free (old_values); } _cogl_boxed_value_init (uniforms_state->override_values + override_index); _cogl_bitmask_set (&uniforms_state->override_mask, location, TRUE); return uniforms_state->override_values + override_index; } void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value) { CoglBoxedValue *boxed_value; boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); _cogl_boxed_value_set_1f (boxed_value, value); } void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value) { CoglBoxedValue *boxed_value; boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); _cogl_boxed_value_set_1i (boxed_value, value); } void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value) { CoglBoxedValue *boxed_value; boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); _cogl_boxed_value_set_float (boxed_value, n_components, count, value); } void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value) { CoglBoxedValue *boxed_value; boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); _cogl_boxed_value_set_int (boxed_value, n_components, count, value); } void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, CoglBool transpose, const float *value) { CoglBoxedValue *boxed_value; boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); _cogl_boxed_value_set_matrix (boxed_value, dimensions, count, transpose, value); } static void _cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline, CoglSnippet *snippet) { CoglPipelineState state = COGL_PIPELINE_STATE_VERTEX_SNIPPETS; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); _cogl_pipeline_snippet_list_add (&pipeline->big_state->vertex_snippets, snippet); } static void _cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline, CoglSnippet *snippet) { CoglPipelineState state = COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS; /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); _cogl_pipeline_snippet_list_add (&pipeline->big_state->fragment_snippets, snippet); } void cogl_pipeline_add_snippet (CoglPipeline *pipeline, CoglSnippet *snippet) { g_return_if_fail (cogl_is_pipeline (pipeline)); g_return_if_fail (cogl_is_snippet (snippet)); g_return_if_fail (snippet->hook < COGL_SNIPPET_FIRST_LAYER_HOOK); if (snippet->hook < COGL_SNIPPET_FIRST_PIPELINE_FRAGMENT_HOOK) _cogl_pipeline_add_vertex_snippet (pipeline, snippet); else _cogl_pipeline_add_fragment_snippet (pipeline, snippet); } CoglBool _cogl_pipeline_has_non_layer_vertex_snippets (CoglPipeline *pipeline) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_VERTEX_SNIPPETS); return authority->big_state->vertex_snippets.entries != NULL; } static CoglBool check_layer_has_vertex_snippet (CoglPipelineLayer *layer, void *user_data) { unsigned long state = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS; CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, state); CoglBool *found_vertex_snippet = user_data; if (authority->big_state->vertex_snippets.entries) { *found_vertex_snippet = TRUE; return FALSE; } return TRUE; } CoglBool _cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline) { CoglBool found_vertex_snippet = FALSE; if (_cogl_pipeline_has_non_layer_vertex_snippets (pipeline)) return TRUE; _cogl_pipeline_foreach_layer_internal (pipeline, check_layer_has_vertex_snippet, &found_vertex_snippet); return found_vertex_snippet; } CoglBool _cogl_pipeline_has_non_layer_fragment_snippets (CoglPipeline *pipeline) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS); return authority->big_state->fragment_snippets.entries != NULL; } static CoglBool check_layer_has_fragment_snippet (CoglPipelineLayer *layer, void *user_data) { unsigned long state = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, state); CoglBool *found_fragment_snippet = user_data; if (authority->big_state->fragment_snippets.entries) { *found_fragment_snippet = TRUE; return FALSE; } return TRUE; } CoglBool _cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline) { CoglBool found_fragment_snippet = FALSE; if (_cogl_pipeline_has_non_layer_fragment_snippets (pipeline)) return TRUE; _cogl_pipeline_foreach_layer_internal (pipeline, check_layer_has_fragment_snippet, &found_fragment_snippet); return found_fragment_snippet; } void _cogl_pipeline_hash_color_state (CoglPipeline *authority, CoglPipelineHashState *state) { state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->color, _COGL_COLOR_DATA_SIZE); } void _cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority, CoglPipelineHashState *state) { uint8_t blend_enable = authority->blend_enable; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &blend_enable, 1); } void _cogl_pipeline_hash_lighting_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglPipelineLightingState *lighting_state = &authority->big_state->lighting_state; state->hash = _cogl_util_one_at_a_time_hash (state->hash, lighting_state, sizeof (CoglPipelineLightingState)); } void _cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &alpha_state->alpha_func, sizeof (alpha_state->alpha_func)); } void _cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state; float ref = alpha_state->alpha_func_reference; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &ref, sizeof (float)); } void _cogl_pipeline_hash_blend_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglPipelineBlendState *blend_state = &authority->big_state->blend_state; unsigned int hash; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!authority->real_blend_enable) return; hash = state->hash; hash = _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_rgb, sizeof (blend_state->blend_equation_rgb)); hash = _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_alpha, sizeof (blend_state->blend_equation_alpha)); hash = _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_alpha, sizeof (blend_state->blend_src_factor_alpha)); hash = _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_alpha, sizeof (blend_state->blend_dst_factor_alpha)); if (blend_state->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || blend_state->blend_src_factor_rgb == GL_CONSTANT_COLOR || blend_state->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || blend_state->blend_dst_factor_rgb == GL_CONSTANT_COLOR) { hash = _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_constant, sizeof (blend_state->blend_constant)); } hash = _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_rgb, sizeof (blend_state->blend_src_factor_rgb)); hash = _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_rgb, sizeof (blend_state->blend_dst_factor_rgb)); state->hash = hash; } void _cogl_pipeline_hash_user_shader_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglHandle user_program = authority->big_state->user_program; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &user_program, sizeof (user_program)); } void _cogl_pipeline_hash_depth_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglDepthState *depth_state = &authority->big_state->depth_state; unsigned int hash = state->hash; if (depth_state->test_enabled) { uint8_t enabled = depth_state->test_enabled; CoglDepthTestFunction function = depth_state->test_function; hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled)); hash = _cogl_util_one_at_a_time_hash (hash, &function, sizeof (function)); } if (depth_state->write_enabled) { uint8_t enabled = depth_state->write_enabled; float near_val = depth_state->range_near; float far_val = depth_state->range_far; hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled)); hash = _cogl_util_one_at_a_time_hash (hash, &near_val, sizeof (near_val)); hash = _cogl_util_one_at_a_time_hash (hash, &far_val, sizeof (far_val)); } state->hash = hash; } void _cogl_pipeline_hash_fog_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglPipelineFogState *fog_state = &authority->big_state->fog_state; unsigned long hash = state->hash; if (!fog_state->enabled) hash = _cogl_util_one_at_a_time_hash (hash, &fog_state->enabled, sizeof (fog_state->enabled)); else hash = _cogl_util_one_at_a_time_hash (hash, &fog_state, sizeof (CoglPipelineFogState)); state->hash = hash; } void _cogl_pipeline_hash_non_zero_point_size_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglBool non_zero_point_size = authority->big_state->non_zero_point_size; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &non_zero_point_size, sizeof (non_zero_point_size)); } void _cogl_pipeline_hash_point_size_state (CoglPipeline *authority, CoglPipelineHashState *state) { float point_size = authority->big_state->point_size; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &point_size, sizeof (point_size)); } void _cogl_pipeline_hash_per_vertex_point_size_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglBool per_vertex_point_size = authority->big_state->per_vertex_point_size; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &per_vertex_point_size, sizeof (per_vertex_point_size)); } void _cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &logic_ops_state->color_mask, sizeof (CoglColorMask)); } void _cogl_pipeline_hash_cull_face_state (CoglPipeline *authority, CoglPipelineHashState *state) { CoglPipelineCullFaceState *cull_face_state = &authority->big_state->cull_face_state; /* The cull face state is considered equal if two pipelines are both set to no culling. If the front winding property is ever used for anything else or the hashing is used not just for drawing then this would have to change */ if (cull_face_state->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE) state->hash = _cogl_util_one_at_a_time_hash (state->hash, &cull_face_state->mode, sizeof (CoglPipelineCullFaceMode)); else state->hash = _cogl_util_one_at_a_time_hash (state->hash, cull_face_state, sizeof (CoglPipelineCullFaceState)); } void _cogl_pipeline_hash_uniforms_state (CoglPipeline *authority, CoglPipelineHashState *state) { /* This isn't used anywhere yet because the uniform state doesn't affect program generation. It's quite a hassle to implement so let's just leave it until something actually needs it */ g_warn_if_reached (); } void _cogl_pipeline_compare_uniform_differences (unsigned long *differences, CoglPipeline *pipeline0, CoglPipeline *pipeline1) { GSList *head0 = NULL; GSList *head1 = NULL; CoglPipeline *node0; CoglPipeline *node1; int len0 = 0; int len1 = 0; int count; GSList *common_ancestor0; GSList *common_ancestor1; /* This algorithm is copied from _cogl_pipeline_compare_differences(). It might be nice to share the code more */ for (node0 = pipeline0; node0; node0 = _cogl_pipeline_get_parent (node0)) { GSList *link = alloca (sizeof (GSList)); link->next = head0; link->data = node0; head0 = link; len0++; } for (node1 = pipeline1; node1; node1 = _cogl_pipeline_get_parent (node1)) { GSList *link = alloca (sizeof (GSList)); link->next = head1; link->data = node1; head1 = link; len1++; } /* NB: There's no point looking at the head entries since we know both * pipelines must have the same default pipeline as their root node. */ common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; count = MIN (len0, len1) - 1; while (count--) { if (head0->data != head1->data) break; common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; } for (head0 = common_ancestor0->next; head0; head0 = head0->next) { node0 = head0->data; if ((node0->differences & COGL_PIPELINE_STATE_UNIFORMS)) { const CoglPipelineUniformsState *uniforms_state = &node0->big_state->uniforms_state; _cogl_bitmask_set_flags (&uniforms_state->override_mask, differences); } } for (head1 = common_ancestor1->next; head1; head1 = head1->next) { node1 = head1->data; if ((node1->differences & COGL_PIPELINE_STATE_UNIFORMS)) { const CoglPipelineUniformsState *uniforms_state = &node1->big_state->uniforms_state; _cogl_bitmask_set_flags (&uniforms_state->override_mask, differences); } } } void _cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority, CoglPipelineHashState *state) { _cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets, &state->hash); } void _cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority, CoglPipelineHashState *state) { _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets, &state->hash); } UNIT_TEST (check_blend_constant_ancestry, 0 /* no requirements */, 0 /* no known failures */) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglNode *node; int pipeline_length = 0; int i; /* Repeatedly making a copy of a pipeline and changing the same * state (in this case the blend constant) shouldn't cause a long * chain of pipelines to be created because the redundant ancestry * should be pruned. */ for (i = 0; i < 20; i++) { CoglColor color; CoglPipeline *tmp_pipeline; cogl_color_init_from_4f (&color, i / 20.0f, 0.0f, 0.0f, 1.0f); tmp_pipeline = cogl_pipeline_copy (pipeline); cogl_object_unref (pipeline); pipeline = tmp_pipeline; cogl_pipeline_set_blend_constant (pipeline, &color); } for (node = (CoglNode *) pipeline; node; node = node->parent) pipeline_length++; g_assert_cmpint (pipeline_length, <=, 2); cogl_object_unref (pipeline); } UNIT_TEST (check_uniform_ancestry, 0 /* no requirements */, TEST_KNOWN_FAILURE) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); CoglNode *node; int pipeline_length = 0; int i; /* Repeatedly making a copy of a pipeline and changing a uniform * shouldn't cause a long chain of pipelines to be created */ for (i = 0; i < 20; i++) { CoglPipeline *tmp_pipeline; int uniform_location; tmp_pipeline = cogl_pipeline_copy (pipeline); cogl_object_unref (pipeline); pipeline = tmp_pipeline; uniform_location = cogl_pipeline_get_uniform_location (pipeline, "a_uniform"); cogl_pipeline_set_uniform_1i (pipeline, uniform_location, i); } for (node = (CoglNode *) pipeline; node; node = node->parent) pipeline_length++; g_assert_cmpint (pipeline_length, <=, 2); cogl_object_unref (pipeline); } muffin-5.2.1/cogl/cogl/cogl-texture-2d-sliced.h0000664000175000017500000003171414211404421021351 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifndef __COGL_TEXURE_2D_SLICED_H #define __COGL_TEXURE_2D_SLICED_H #include "cogl-context.h" #include "cogl-types.h" /** * SECTION:cogl-texture-2d-sliced * @short_description: Functions for creating and manipulating 2D meta * textures that may internally be comprised of * multiple 2D textures with power-of-two sizes. * * These functions allow high-level meta textures (See the * #CoglMetaTexture interface) to be allocated that may internally be * comprised of multiple 2D texture "slices" with power-of-two sizes. * * This API can be useful when working with GPUs that don't have * native support for non-power-of-two textures or if you want to load * a texture that is larger than the GPUs maximum texture size limits. * * The algorithm for slicing works by first trying to map a virtual * size to the next larger power-of-two size and then seeing how many * wasted pixels that would result in. For example if you have a * virtual texture that's 259 texels wide, the next pot size = 512 and * the amount of waste would be 253 texels. If the amount of waste is * above a max-waste threshold then we would next slice that texture * into one that's 256 texels and then looking at how many more texels * remain unallocated after that we choose the next power-of-two size. * For the example of a 259 texel image that would mean having a 256 * texel wide texture, leaving 3 texels unallocated so we'd then * create a 4 texel wide texture - now there is only one texel of * waste. The algorithm continues to slice the right most textures * until the amount of waste is less than or equal to a specfied * max-waste threshold. The same logic for slicing from left to right * is also applied from top to bottom. */ typedef struct _CoglTexture2DSliced CoglTexture2DSliced; #define COGL_TEXTURE_2D_SLICED(X) ((CoglTexture2DSliced *)X) /** * cogl_texture_2d_sliced_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_texture_2d_sliced_get_gtype (void); /** * cogl_texture_2d_sliced_new_with_size: * @ctx: A #CoglContext * @width: The virtual width of your sliced texture. * @height: The virtual height of your sliced texture. * @max_waste: The threshold of how wide a strip of wasted texels * are allowed along the right and bottom textures before * they must be sliced to reduce the amount of waste. A * negative can be passed to disable slicing. * * Creates a #CoglTexture2DSliced that may internally be comprised of * 1 or more #CoglTexture2D textures depending on GPU limitations. * For example if the GPU only supports power-of-two sized textures * then a sliced texture will turn a non-power-of-two size into a * combination of smaller power-of-two sized textures. If the * requested texture size is larger than is supported by the hardware * then the texture will be sliced into smaller textures that can be * accessed by the hardware. * * @max_waste is used as a threshold for recursively slicing the * right-most or bottom-most slices into smaller sizes until the * wasted padding at the bottom and right of the textures is less than * specified. A negative @max_waste will disable slicing. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or let Cogl automatically allocate * storage lazily. * * It's possible for the allocation of a sliced texture to fail * later due to impossible slicing constraints if a negative * @max_waste value is given. If the given virtual texture size size * is larger than is supported by the hardware but slicing is disabled * the texture size would be too large to handle. * * Returns: (transfer full): A new #CoglTexture2DSliced object with no storage * allocated yet. * * Since: 1.10 * Stability: unstable */ CoglTexture2DSliced * cogl_texture_2d_sliced_new_with_size (CoglContext *ctx, int width, int height, int max_waste); /** * cogl_texture_2d_sliced_new_from_file: * @ctx: A #CoglContext * @filename: the file to load * @max_waste: The threshold of how wide a strip of wasted texels * are allowed along the right and bottom textures before * they must be sliced to reduce the amount of waste. A * negative can be passed to disable slicing. * @error: A #CoglError to catch exceptional errors or %NULL * * Creates a #CoglTexture2DSliced from an image file. * * A #CoglTexture2DSliced may internally be comprised of 1 or more * #CoglTexture2D textures depending on GPU limitations. For example * if the GPU only supports power-of-two sized textures then a sliced * texture will turn a non-power-of-two size into a combination of * smaller power-of-two sized textures. If the requested texture size * is larger than is supported by the hardware then the texture will * be sliced into smaller textures that can be accessed by the * hardware. * * @max_waste is used as a threshold for recursively slicing the * right-most or bottom-most slices into smaller sizes until the * wasted padding at the bottom and right of the textures is less than * specified. A negative @max_waste will disable slicing. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or let Cogl automatically allocate * storage lazily. * * It's possible for the allocation of a sliced texture to fail * later due to impossible slicing constraints if a negative * @max_waste value is given. If the given virtual texture size is * larger than is supported by the hardware but slicing is disabled * the texture size would be too large to handle. * * Return value: (transfer full): A newly created #CoglTexture2DSliced * or %NULL on failure and @error will be updated. * * Since: 1.16 */ CoglTexture2DSliced * cogl_texture_2d_sliced_new_from_file (CoglContext *ctx, const char *filename, int max_waste, CoglError **error); /** * cogl_texture_2d_sliced_new_from_data: * @ctx: A #CoglContext * @width: width of texture in pixels * @height: height of texture in pixels * @format: the #CoglPixelFormat the buffer is stored in in RAM * @max_waste: The threshold of how wide a strip of wasted texels * are allowed along the right and bottom textures before * they must be sliced to reduce the amount of waste. A * negative can be passed to disable slicing. * @rowstride: the memory offset in bytes between the start of each * row in @data. A value of 0 will make Cogl automatically * calculate @rowstride from @width and @format. * @data: pointer the memory region where the source buffer resides * @error: A #CoglError to catch exceptional errors or %NULL * * Creates a new #CoglTexture2DSliced texture based on data residing * in memory. * * A #CoglTexture2DSliced may internally be comprised of 1 or more * #CoglTexture2D textures depending on GPU limitations. For example * if the GPU only supports power-of-two sized textures then a sliced * texture will turn a non-power-of-two size into a combination of * smaller power-of-two sized textures. If the requested texture size * is larger than is supported by the hardware then the texture will * be sliced into smaller textures that can be accessed by the * hardware. * * @max_waste is used as a threshold for recursively slicing the * right-most or bottom-most slices into smaller sizes until the * wasted padding at the bottom and right of the textures is less than * specified. A negative @max_waste will disable slicing. * * This api will always immediately allocate GPU memory for all * the required texture slices and upload the given data so that the * @data pointer does not need to remain valid once this function * returns. This means it is not possible to configure the texture * before it is allocated. If you do need to configure the texture * before allocation (to specify constraints on the internal format * for example) then you can instead create a #CoglBitmap for your * data and use cogl_texture_2d_sliced_new_from_bitmap() or use * cogl_texture_2d_sliced_new_with_size() and then upload data using * cogl_texture_set_data() * * It's possible for the allocation of a sliced texture to fail * due to impossible slicing constraints if a negative @max_waste * value is given. If the given virtual texture size is larger than is * supported by the hardware but slicing is disabled the texture size * would be too large to handle. * * Return value: (transfer full): A newly created #CoglTexture2DSliced * or %NULL on failure and @error will be updated. * * Since: 1.16 */ CoglTexture2DSliced * cogl_texture_2d_sliced_new_from_data (CoglContext *ctx, int width, int height, int max_waste, CoglPixelFormat format, int rowstride, const uint8_t *data, CoglError **error); /** * cogl_texture_2d_sliced_new_from_bitmap: * @bmp: A #CoglBitmap * @max_waste: The threshold of how wide a strip of wasted texels * are allowed along the right and bottom textures before * they must be sliced to reduce the amount of waste. A * negative can be passed to disable slicing. * * Creates a new #CoglTexture2DSliced texture based on data residing * in a bitmap. * * A #CoglTexture2DSliced may internally be comprised of 1 or more * #CoglTexture2D textures depending on GPU limitations. For example * if the GPU only supports power-of-two sized textures then a sliced * texture will turn a non-power-of-two size into a combination of * smaller power-of-two sized textures. If the requested texture size * is larger than is supported by the hardware then the texture will * be sliced into smaller textures that can be accessed by the * hardware. * * @max_waste is used as a threshold for recursively slicing the * right-most or bottom-most slices into smaller sizes until the * wasted padding at the bottom and right of the textures is less than * specified. A negative @max_waste will disable slicing. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or let Cogl automatically allocate * storage lazily. * * It's possible for the allocation of a sliced texture to fail * later due to impossible slicing constraints if a negative * @max_waste value is given. If the given virtual texture size is * larger than is supported by the hardware but slicing is disabled * the texture size would be too large to handle. * * Return value: (transfer full): A newly created #CoglTexture2DSliced * or %NULL on failure and @error will be updated. * * Since: 1.16 */ CoglTexture2DSliced * cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, int max_waste); /** * cogl_is_texture_2d_sliced: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglTexture2DSliced. * * Return value: %TRUE if the object references a #CoglTexture2DSliced * and %FALSE otherwise. * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_texture_2d_sliced (void *object); #endif /* __COGL_TEXURE_2D_SLICED_H */ muffin-5.2.1/cogl/cogl/cogl-attribute.h0000664000175000017500000004601714211404421020112 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_ATTRIBUTE_H__ #define __COGL_ATTRIBUTE_H__ /* We forward declare the CoglAttribute type here to avoid some circular * dependency issues with the following headers. */ typedef struct _CoglAttribute CoglAttribute; #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-attribute * @short_description: Functions for declaring and drawing vertex * attributes * * FIXME */ /** * cogl_attribute_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_attribute_get_gtype (void); /** * cogl_attribute_new: (constructor) * @attribute_buffer: The #CoglAttributeBuffer containing the actual * attribute data * @name: The name of the attribute (used to reference it from GLSL) * @stride: The number of bytes to jump to get to the next attribute * value for the next vertex. (Usually * sizeof (MyVertex)) * @offset: The byte offset from the start of @attribute_buffer for * the first attribute value. (Usually * offsetof (MyVertex, component0) * @components: The number of components (e.g. 4 for an rgba color or * 3 for and (x,y,z) position) * @type: FIXME * * Describes the layout for a list of vertex attribute values (For * example, a list of texture coordinates or colors). * * The @name is used to access the attribute inside a GLSL vertex * shader and there are some special names you should use if they are * applicable: * * "cogl_position_in" (used for vertex positions) * "cogl_color_in" (used for vertex colors) * "cogl_tex_coord0_in", "cogl_tex_coord1", ... * (used for vertex texture coordinates) * "cogl_normal_in" (used for vertex normals) * "cogl_point_size_in" (used to set the size of points * per-vertex. Note this can only be used if * %COGL_FEATURE_ID_POINT_SIZE_ATTRIBUTE is advertised and * cogl_pipeline_set_per_vertex_point_size() is called on the pipeline. * * * * The attribute values corresponding to different vertices can either * be tightly packed or interleaved with other attribute values. For * example it's common to define a structure for a single vertex like: * |[ * typedef struct * { * float x, y, z; /* position attribute */ * float s, t; /* texture coordinate attribute */ * } MyVertex; * ]| * * And then create an array of vertex data something like: * |[ * MyVertex vertices[100] = { .... } * ]| * * In this case, to describe either the position or texture coordinate * attribute you have to move sizeof (MyVertex) bytes to * move from one vertex to the next. This is called the attribute * @stride. If you weren't interleving attributes and you instead had * a packed array of float x, y pairs then the attribute stride would * be (2 * sizeof (float)). So the @stride is the number of * bytes to move to find the attribute value of the next vertex. * * Normally a list of attributes starts at the beginning of an array. * So for the MyVertex example above the @offset is the * offset inside the MyVertex structure to the first * component of the attribute. For the texture coordinate attribute * the offset would be offsetof (MyVertex, s) or instead of * using the offsetof macro you could use sizeof (float) * * 3. If you've divided your @array into blocks of non-interleved * attributes then you will need to calculate the @offset as the number of * bytes in blocks preceding the attribute you're describing. * * An attribute often has more than one component. For example a color * is often comprised of 4 red, green, blue and alpha @components, and a * position may be comprised of 2 x and y @components. You should aim * to keep the number of components to a minimum as more components * means more data needs to be mapped into the GPU which can be a * bottlneck when dealing with a large number of vertices. * * Finally you need to specify the component data type. Here you * should aim to use the smallest type that meets your precision * requirements. Again the larger the type then more data needs to be * mapped into the GPU which can be a bottlneck when dealing with * a large number of vertices. * * Return value: (transfer full): A newly allocated #CoglAttribute * describing the layout for a list of attribute values * stored in @array. * * Since: 1.4 * Stability: Unstable */ /* XXX: look for a precedent to see if the stride/offset args should * have a different order. */ CoglAttribute * cogl_attribute_new (CoglAttributeBuffer *attribute_buffer, const char *name, size_t stride, size_t offset, int components, CoglAttributeType type); /** * cogl_attribute_new_const_1f: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @value: The constant value for the attribute * * Creates a new, single component, attribute whose value remains * constant across all the vertices of a primitive without needing to * duplicate the value for each vertex. * * The constant @value is a single precision floating point scalar * which should have a corresponding declaration in GLSL code like: * * [| * attribute float name; * |] * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant @value. */ CoglAttribute * cogl_attribute_new_const_1f (CoglContext *context, const char *name, float value); /** * cogl_attribute_new_const_2f: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @component0: The first component of a 2 component vector * @component1: The second component of a 2 component vector * * Creates a new, 2 component, attribute whose value remains * constant across all the vertices of a primitive without needing to * duplicate the value for each vertex. * * The constants (@component0, @component1) represent a 2 component * float vector which should have a corresponding declaration in GLSL * code like: * * [| * attribute vec2 name; * |] * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant vector. */ CoglAttribute * cogl_attribute_new_const_2f (CoglContext *context, const char *name, float component0, float component1); /** * cogl_attribute_new_const_3f: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @component0: The first component of a 3 component vector * @component1: The second component of a 3 component vector * @component2: The third component of a 3 component vector * * Creates a new, 3 component, attribute whose value remains * constant across all the vertices of a primitive without needing to * duplicate the value for each vertex. * * The constants (@component0, @component1, @component2) represent a 3 * component float vector which should have a corresponding * declaration in GLSL code like: * * [| * attribute vec3 name; * |] * * unless the built in name "cogl_normal_in" is being used where no * explicit GLSL declaration need be made. * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant vector. */ CoglAttribute * cogl_attribute_new_const_3f (CoglContext *context, const char *name, float component0, float component1, float component2); /** * cogl_attribute_new_const_4f: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @component0: The first component of a 4 component vector * @component1: The second component of a 4 component vector * @component2: The third component of a 4 component vector * @component3: The fourth component of a 4 component vector * * Creates a new, 4 component, attribute whose value remains * constant across all the vertices of a primitive without needing to * duplicate the value for each vertex. * * The constants (@component0, @component1, @component2, @constant3) * represent a 4 component float vector which should have a * corresponding declaration in GLSL code like: * * [| * attribute vec4 name; * |] * * unless one of the built in names "cogl_color_in", * "cogl_tex_coord0_in or "cogl_tex_coord1_in" etc is being used where * no explicit GLSL declaration need be made. * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant vector. */ CoglAttribute * cogl_attribute_new_const_4f (CoglContext *context, const char *name, float component0, float component1, float component2, float component3); /** * cogl_attribute_new_const_2fv: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @value: A pointer to a 2 component float vector * * Creates a new, 2 component, attribute whose value remains * constant across all the vertices of a primitive without needing to * duplicate the value for each vertex. * * The constants (value[0], value[1]) represent a 2 component float * vector which should have a corresponding declaration in GLSL code * like: * * [| * attribute vec2 name; * |] * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant vector. */ CoglAttribute * cogl_attribute_new_const_2fv (CoglContext *context, const char *name, const float *value); /** * cogl_attribute_new_const_3fv: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @value: A pointer to a 3 component float vector * * Creates a new, 3 component, attribute whose value remains * constant across all the vertices of a primitive without needing to * duplicate the value for each vertex. * * The constants (value[0], value[1], value[2]) represent a 3 * component float vector which should have a corresponding * declaration in GLSL code like: * * [| * attribute vec3 name; * |] * * unless the built in name "cogl_normal_in" is being used where no * explicit GLSL declaration need be made. * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant vector. */ CoglAttribute * cogl_attribute_new_const_3fv (CoglContext *context, const char *name, const float *value); /** * cogl_attribute_new_const_4fv: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @value: A pointer to a 4 component float vector * * Creates a new, 4 component, attribute whose value remains * constant across all the vertices of a primitive without needing to * duplicate the value for each vertex. * * The constants (value[0], value[1], value[2], value[3]) represent a * 4 component float vector which should have a corresponding * declaration in GLSL code like: * * [| * attribute vec4 name; * |] * * unless one of the built in names "cogl_color_in", * "cogl_tex_coord0_in or "cogl_tex_coord1_in" etc is being used where * no explicit GLSL declaration need be made. * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant vector. */ CoglAttribute * cogl_attribute_new_const_4fv (CoglContext *context, const char *name, const float *value); /** * cogl_attribute_new_const_2x2fv: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @matrix2x2: A pointer to a 2 by 2 matrix * @transpose: Whether the matrix should be transposed on upload or * not * * Creates a new matrix attribute whose value remains constant * across all the vertices of a primitive without needing to duplicate * the value for each vertex. * * @matrix2x2 represent a square 2 by 2 matrix specified in * column-major order (each pair of consecutive numbers represents a * column) which should have a corresponding declaration in GLSL code * like: * * [| * attribute mat2 name; * |] * * If @transpose is %TRUE then all matrix components are rotated * around the diagonal of the matrix such that the first column * becomes the first row and the second column becomes the second row. * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant matrix. */ CoglAttribute * cogl_attribute_new_const_2x2fv (CoglContext *context, const char *name, const float *matrix2x2, CoglBool transpose); /** * cogl_attribute_new_const_3x3fv: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @matrix3x3: A pointer to a 3 by 3 matrix * @transpose: Whether the matrix should be transposed on upload or * not * * Creates a new matrix attribute whose value remains constant * across all the vertices of a primitive without needing to duplicate * the value for each vertex. * * @matrix3x3 represent a square 3 by 3 matrix specified in * column-major order (each triple of consecutive numbers represents a * column) which should have a corresponding declaration in GLSL code * like: * * [| * attribute mat3 name; * |] * * If @transpose is %TRUE then all matrix components are rotated * around the diagonal of the matrix such that the first column * becomes the first row and the second column becomes the second row * etc. * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant matrix. */ CoglAttribute * cogl_attribute_new_const_3x3fv (CoglContext *context, const char *name, const float *matrix3x3, CoglBool transpose); /** * cogl_attribute_new_const_4x4fv: * @context: A #CoglContext * @name: The name of the attribute (used to reference it from GLSL) * @matrix4x4: A pointer to a 4 by 4 matrix * @transpose: Whether the matrix should be transposed on upload or * not * * Creates a new matrix attribute whose value remains constant * across all the vertices of a primitive without needing to duplicate * the value for each vertex. * * @matrix4x4 represent a square 4 by 4 matrix specified in * column-major order (each 4-tuple of consecutive numbers represents a * column) which should have a corresponding declaration in GLSL code * like: * * [| * attribute mat4 name; * |] * * If @transpose is %TRUE then all matrix components are rotated * around the diagonal of the matrix such that the first column * becomes the first row and the second column becomes the second row * etc. * * Return value: (transfer full): A newly allocated #CoglAttribute * representing the given constant matrix. */ CoglAttribute * cogl_attribute_new_const_4x4fv (CoglContext *context, const char *name, const float *matrix4x4, CoglBool transpose); /** * cogl_attribute_set_normalized: * @attribute: A #CoglAttribute * @normalized: The new value for the normalized property. * * Sets whether fixed point attribute types are mapped to the range * 0→1. For example when this property is TRUE and a * %COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE type is used then the value 255 * will be mapped to 1.0. * * The default value of this property depends on the name of the * attribute. For the builtin properties cogl_color_in and * cogl_normal_in it will default to TRUE and for all other names it * will default to FALSE. * * Stability: unstable * Since: 1.10 */ void cogl_attribute_set_normalized (CoglAttribute *attribute, CoglBool normalized); /** * cogl_attribute_get_normalized: * @attribute: A #CoglAttribute * * Return value: the value of the normalized property set with * cogl_attribute_set_normalized(). * * Stability: unstable * Since: 1.10 */ CoglBool cogl_attribute_get_normalized (CoglAttribute *attribute); /** * cogl_attribute_get_buffer: * @attribute: A #CoglAttribute * * Return value: (transfer none): the #CoglAttributeBuffer that was * set with cogl_attribute_set_buffer() or cogl_attribute_new(). * * Stability: unstable * Since: 1.10 */ CoglAttributeBuffer * cogl_attribute_get_buffer (CoglAttribute *attribute); /** * cogl_attribute_set_buffer: * @attribute: A #CoglAttribute * @attribute_buffer: A #CoglAttributeBuffer * * Sets a new #CoglAttributeBuffer for the attribute. * * Stability: unstable * Since: 1.10 */ void cogl_attribute_set_buffer (CoglAttribute *attribute, CoglAttributeBuffer *attribute_buffer); /** * cogl_is_attribute: * @object: A #CoglObject * * Gets whether the given object references a #CoglAttribute. * * Return value: %TRUE if the @object references a #CoglAttribute, * %FALSE otherwise */ CoglBool cogl_is_attribute (void *object); COGL_END_DECLS #endif /* __COGL_ATTRIBUTE_H__ */ muffin-5.2.1/cogl/cogl/cogl-index-buffer.h0000664000175000017500000000544314211404421020463 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_INDEX_BUFFER_H__ #define __COGL_INDEX_BUFFER_H__ #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-index-buffer * @short_description: Functions for creating and manipulating vertex * indices. * * FIXME */ #define COGL_INDEX_BUFFER(buffer) ((CoglIndexBuffer*) buffer) typedef struct _CoglIndexBuffer CoglIndexBuffer; /** * cogl_index_buffer_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_index_buffer_get_gtype (void); /** * cogl_index_buffer_new: * @context: A #CoglContext * @bytes: The number of bytes to allocate for vertex attribute data. * * Declares a new #CoglIndexBuffer of @size bytes to contain vertex * indices. Once declared, data can be set using * cogl_buffer_set_data() or by mapping it into the application's * address space using cogl_buffer_map(). * * Return value: (transfer full): A newly allocated #CoglIndexBuffer * * Since: 1.4 * Stability: Unstable */ CoglIndexBuffer * cogl_index_buffer_new (CoglContext *context, size_t bytes); /** * cogl_is_index_buffer: * @object: A #CoglObject * * Gets whether the given object references a #CoglIndexBuffer. * * Returns: %TRUE if the @object references a #CoglIndexBuffer, * %FALSE otherwise * * Since: 1.4 * Stability: Unstable */ CoglBool cogl_is_index_buffer (void *object); COGL_END_DECLS #endif /* __COGL_INDEX_BUFFER_H__ */ muffin-5.2.1/cogl/cogl/cogl-indices.c0000664000175000017500000001653714211404421017524 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-object-private.h" #include "cogl-context-private.h" #include "cogl-indices.h" #include "cogl-indices-private.h" #include "cogl-index-buffer.h" #include "cogl-gtype-private.h" #include static void _cogl_indices_free (CoglIndices *indices); COGL_OBJECT_DEFINE (Indices, indices); COGL_GTYPE_DEFINE_CLASS (Indices, indices); static size_t sizeof_indices_type (CoglIndicesType type) { switch (type) { case COGL_INDICES_TYPE_UNSIGNED_BYTE: return 1; case COGL_INDICES_TYPE_UNSIGNED_SHORT: return 2; case COGL_INDICES_TYPE_UNSIGNED_INT: return 4; } g_return_val_if_reached (0); } CoglIndices * cogl_indices_new_for_buffer (CoglIndicesType type, CoglIndexBuffer *buffer, size_t offset) { CoglIndices *indices = g_slice_new (CoglIndices); indices->buffer = cogl_object_ref (buffer); indices->offset = offset; indices->type = type; indices->immutable_ref = 0; return _cogl_indices_object_new (indices); } CoglIndices * cogl_indices_new (CoglContext *context, CoglIndicesType type, const void *indices_data, int n_indices) { size_t buffer_bytes = sizeof_indices_type (type) * n_indices; CoglIndexBuffer *index_buffer = cogl_index_buffer_new (context, buffer_bytes); CoglBuffer *buffer = COGL_BUFFER (index_buffer); CoglIndices *indices; CoglError *ignore_error = NULL; _cogl_buffer_set_data (buffer, 0, indices_data, buffer_bytes, &ignore_error); if (ignore_error) { cogl_error_free (ignore_error); cogl_object_unref (index_buffer); return NULL; } indices = cogl_indices_new_for_buffer (type, index_buffer, 0); cogl_object_unref (index_buffer); return indices; } CoglIndexBuffer * cogl_indices_get_buffer (CoglIndices *indices) { return indices->buffer; } CoglIndicesType cogl_indices_get_type (CoglIndices *indices) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_indices (indices), COGL_INDICES_TYPE_UNSIGNED_BYTE); return indices->type; } size_t cogl_indices_get_offset (CoglIndices *indices) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_indices (indices), 0); return indices->offset; } static void warn_about_midscene_changes (void) { static CoglBool seen = FALSE; if (!seen) { g_warning ("Mid-scene modification of indices has " "undefined results\n"); seen = TRUE; } } void cogl_indices_set_offset (CoglIndices *indices, size_t offset) { _COGL_RETURN_IF_FAIL (cogl_is_indices (indices)); if (G_UNLIKELY (indices->immutable_ref)) warn_about_midscene_changes (); indices->offset = offset; } static void _cogl_indices_free (CoglIndices *indices) { cogl_object_unref (indices->buffer); g_slice_free (CoglIndices, indices); } CoglIndices * _cogl_indices_immutable_ref (CoglIndices *indices) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_indices (indices), NULL); indices->immutable_ref++; _cogl_buffer_immutable_ref (COGL_BUFFER (indices->buffer)); return indices; } void _cogl_indices_immutable_unref (CoglIndices *indices) { _COGL_RETURN_IF_FAIL (cogl_is_indices (indices)); _COGL_RETURN_IF_FAIL (indices->immutable_ref > 0); indices->immutable_ref--; _cogl_buffer_immutable_unref (COGL_BUFFER (indices->buffer)); } CoglIndices * cogl_get_rectangle_indices (CoglContext *ctx, int n_rectangles) { int n_indices = n_rectangles * 6; /* Check if the largest index required will fit in a byte array... */ if (n_indices <= 256 / 4 * 6) { /* Generate the byte array if we haven't already */ if (ctx->rectangle_byte_indices == NULL) { uint8_t *byte_array = malloc (256 / 4 * 6 * sizeof (uint8_t)); uint8_t *p = byte_array; int i, vert_num = 0; for (i = 0; i < 256 / 4; i++) { *(p++) = vert_num + 0; *(p++) = vert_num + 1; *(p++) = vert_num + 2; *(p++) = vert_num + 0; *(p++) = vert_num + 2; *(p++) = vert_num + 3; vert_num += 4; } ctx->rectangle_byte_indices = cogl_indices_new (ctx, COGL_INDICES_TYPE_UNSIGNED_BYTE, byte_array, 256 / 4 * 6); free (byte_array); } return ctx->rectangle_byte_indices; } else { if (ctx->rectangle_short_indices_len < n_indices) { uint16_t *short_array; uint16_t *p; int i, vert_num = 0; if (ctx->rectangle_short_indices != NULL) cogl_object_unref (ctx->rectangle_short_indices); /* Pick a power of two >= MAX (512, n_indices) */ if (ctx->rectangle_short_indices_len == 0) ctx->rectangle_short_indices_len = 512; while (ctx->rectangle_short_indices_len < n_indices) ctx->rectangle_short_indices_len *= 2; /* Over-allocate to generate a whole number of quads */ p = short_array = malloc ((ctx->rectangle_short_indices_len + 5) / 6 * 6 * sizeof (uint16_t)); /* Fill in the complete quads */ for (i = 0; i < ctx->rectangle_short_indices_len; i += 6) { *(p++) = vert_num + 0; *(p++) = vert_num + 1; *(p++) = vert_num + 2; *(p++) = vert_num + 0; *(p++) = vert_num + 2; *(p++) = vert_num + 3; vert_num += 4; } ctx->rectangle_short_indices = cogl_indices_new (ctx, COGL_INDICES_TYPE_UNSIGNED_SHORT, short_array, ctx->rectangle_short_indices_len); free (short_array); } return ctx->rectangle_short_indices; } } muffin-5.2.1/cogl/cogl/cogl-color.c0000664000175000017500000002207214211404421017213 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-util.h" #include "cogl-color.h" #include "cogl-color-private.h" #include "cogl-gtype-private.h" COGL_GTYPE_DEFINE_BOXED (Color, color, cogl_color_copy, cogl_color_free); CoglColor * cogl_color_new (void) { return g_slice_new (CoglColor); } CoglColor * cogl_color_copy (const CoglColor *color) { if (G_LIKELY (color)) return g_slice_dup (CoglColor, color); return NULL; } void cogl_color_free (CoglColor *color) { if (G_LIKELY (color)) g_slice_free (CoglColor, color); } void cogl_color_init_from_4ub (CoglColor *color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { _COGL_RETURN_IF_FAIL (color != NULL); color->red = red; color->green = green; color->blue = blue; color->alpha = alpha; } /* XXX: deprecated, use cogl_color_init_from_4ub */ void cogl_color_set_from_4ub (CoglColor *dest, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { cogl_color_init_from_4ub (dest, red, green, blue, alpha); } void cogl_color_init_from_4f (CoglColor *color, float red, float green, float blue, float alpha) { _COGL_RETURN_IF_FAIL (color != NULL); color->red = (red * 255); color->green = (green * 255); color->blue = (blue * 255); color->alpha = (alpha * 255); } /* XXX: deprecated, use cogl_color_init_from_4f */ void cogl_color_set_from_4f (CoglColor *color, float red, float green, float blue, float alpha) { cogl_color_init_from_4f (color, red, green, blue, alpha); } void cogl_color_init_from_4fv (CoglColor *color, const float *color_array) { _COGL_RETURN_IF_FAIL (color != NULL); color->red = (color_array[0] * 255); color->green = (color_array[1] * 255); color->blue = (color_array[2] * 255); color->alpha = (color_array[3] * 255); } unsigned char cogl_color_get_red_byte (const CoglColor *color) { return color->red; } float cogl_color_get_red_float (const CoglColor *color) { return (float) color->red / 255.0; } float cogl_color_get_red (const CoglColor *color) { return ((float) color->red / 255.0); } unsigned char cogl_color_get_green_byte (const CoglColor *color) { return color->green; } float cogl_color_get_green_float (const CoglColor *color) { return (float) color->green / 255.0; } float cogl_color_get_green (const CoglColor *color) { return ((float) color->green / 255.0); } unsigned char cogl_color_get_blue_byte (const CoglColor *color) { return color->blue; } float cogl_color_get_blue_float (const CoglColor *color) { return (float) color->blue / 255.0; } float cogl_color_get_blue (const CoglColor *color) { return ((float) color->blue / 255.0); } unsigned char cogl_color_get_alpha_byte (const CoglColor *color) { return color->alpha; } float cogl_color_get_alpha_float (const CoglColor *color) { return (float) color->alpha / 255.0; } float cogl_color_get_alpha (const CoglColor *color) { return ((float) color->alpha / 255.0); } void cogl_color_set_red_byte (CoglColor *color, unsigned char red) { color->red = red; } void cogl_color_set_red_float (CoglColor *color, float red) { color->red = red * 255.0; } void cogl_color_set_red (CoglColor *color, float red) { color->red = red * 255.0; } void cogl_color_set_green_byte (CoglColor *color, unsigned char green) { color->green = green; } void cogl_color_set_green_float (CoglColor *color, float green) { color->green = green * 255.0; } void cogl_color_set_green (CoglColor *color, float green) { color->green = green * 255.0; } void cogl_color_set_blue_byte (CoglColor *color, unsigned char blue) { color->blue = blue; } void cogl_color_set_blue_float (CoglColor *color, float blue) { color->blue = blue * 255.0; } void cogl_color_set_blue (CoglColor *color, float blue) { color->blue = blue * 255.0; } void cogl_color_set_alpha_byte (CoglColor *color, unsigned char alpha) { color->alpha = alpha; } void cogl_color_set_alpha_float (CoglColor *color, float alpha) { color->alpha = alpha * 255.0; } void cogl_color_set_alpha (CoglColor *color, float alpha) { color->alpha = alpha * 255.0; } void cogl_color_premultiply (CoglColor *color) { color->red = (color->red * color->alpha + 128) / 255; color->green = (color->green * color->alpha + 128) / 255; color->blue = (color->blue * color->alpha + 128) / 255; } void cogl_color_unpremultiply (CoglColor *color) { if (color->alpha != 0) { color->red = (color->red * 255) / color->alpha; color->green = (color->green * 255) / color->alpha; color->blue = (color->blue * 255) / color->alpha; } } CoglBool cogl_color_equal (const void *v1, const void *v2) { const uint32_t *c1 = v1, *c2 = v2; _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE); _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE); /* XXX: We don't compare the padding */ return *c1 == *c2 ? TRUE : FALSE; } void _cogl_color_get_rgba_4ubv (const CoglColor *color, uint8_t *dest) { memcpy (dest, color, 4); } void cogl_color_to_hsl (const CoglColor *color, float *hue, float *saturation, float *luminance) { float red, green, blue; float min, max, delta; float h, l, s; red = color->red / 255.0; green = color->green / 255.0; blue = color->blue / 255.0; if (red > green) { if (red > blue) max = red; else max = blue; if (green < blue) min = green; else min = blue; } else { if (green > blue) max = green; else max = blue; if (red < blue) min = red; else min = blue; } l = (max + min) / 2; s = 0; h = 0; if (max != min) { if (l <= 0.5) s = (max - min) / (max + min); else s = (max - min) / (2.0 - max - min); delta = max - min; if (red == max) h = (green - blue) / delta; else if (green == max) h = 2.0 + (blue - red) / delta; else if (blue == max) h = 4.0 + (red - green) / delta; h *= 60; if (h < 0) h += 360.0; } if (hue) *hue = h; if (luminance) *luminance = l; if (saturation) *saturation = s; } void cogl_color_init_from_hsl (CoglColor *color, float hue, float saturation, float luminance) { float tmp1, tmp2; float tmp3[3]; float clr[3]; int i; hue /= 360.0; if (saturation == 0) { cogl_color_init_from_4f (color, luminance, luminance, luminance, 1.0f); return; } if (luminance <= 0.5) tmp2 = luminance * (1.0 + saturation); else tmp2 = luminance + saturation - (luminance * saturation); tmp1 = 2.0 * luminance - tmp2; tmp3[0] = hue + 1.0 / 3.0; tmp3[1] = hue; tmp3[2] = hue - 1.0 / 3.0; for (i = 0; i < 3; i++) { if (tmp3[i] < 0) tmp3[i] += 1.0; if (tmp3[i] > 1) tmp3[i] -= 1.0; if (6.0 * tmp3[i] < 1.0) clr[i] = tmp1 + (tmp2 - tmp1) * tmp3[i] * 6.0; else if (2.0 * tmp3[i] < 1.0) clr[i] = tmp2; else if (3.0 * tmp3[i] < 2.0) clr[i] = (tmp1 + (tmp2 - tmp1) * ((2.0 / 3.0) - tmp3[i]) * 6.0); else clr[i] = tmp1; } cogl_color_init_from_4f (color, clr[0], clr[1], clr[2], 1.0f); } muffin-5.2.1/cogl/cogl/cogl-sampler-cache-private.h0000664000175000017500000000644514211404421022264 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_SAMPLER_CACHE_PRIVATE_H #define __COGL_SAMPLER_CACHE_PRIVATE_H #include "cogl-context.h" #include "cogl-gl-header.h" /* These aren't defined in the GLES headers */ #ifndef GL_CLAMP_TO_BORDER #define GL_CLAMP_TO_BORDER 0x812d #endif #ifndef GL_MIRRORED_REPEAT #define GL_MIRRORED_REPEAT 0x8370 #endif /* GL_ALWAYS is just used here as a value that is known not to clash * with any valid GL wrap modes. * * XXX: keep the values in sync with the CoglPipelineWrapMode enum * so no conversion is actually needed. */ typedef enum _CoglSamplerCacheWrapMode { COGL_SAMPLER_CACHE_WRAP_MODE_REPEAT = GL_REPEAT, COGL_SAMPLER_CACHE_WRAP_MODE_MIRRORED_REPEAT = GL_MIRRORED_REPEAT, COGL_SAMPLER_CACHE_WRAP_MODE_CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE, COGL_SAMPLER_CACHE_WRAP_MODE_CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC = GL_ALWAYS } CoglSamplerCacheWrapMode; typedef struct _CoglSamplerCache CoglSamplerCache; typedef struct _CoglSamplerCacheEntry { GLuint sampler_object; GLenum min_filter; GLenum mag_filter; CoglSamplerCacheWrapMode wrap_mode_s; CoglSamplerCacheWrapMode wrap_mode_t; CoglSamplerCacheWrapMode wrap_mode_p; } CoglSamplerCacheEntry; CoglSamplerCache * _cogl_sampler_cache_new (CoglContext *context); const CoglSamplerCacheEntry * _cogl_sampler_cache_get_default_entry (CoglSamplerCache *cache); const CoglSamplerCacheEntry * _cogl_sampler_cache_update_wrap_modes (CoglSamplerCache *cache, const CoglSamplerCacheEntry *old_entry, CoglSamplerCacheWrapMode wrap_mode_s, CoglSamplerCacheWrapMode wrap_mode_t, CoglSamplerCacheWrapMode wrap_mode_p); const CoglSamplerCacheEntry * _cogl_sampler_cache_update_filters (CoglSamplerCache *cache, const CoglSamplerCacheEntry *old_entry, GLenum min_filter, GLenum mag_filter); void _cogl_sampler_cache_free (CoglSamplerCache *cache); #endif /* __COGL_SAMPLER_CACHE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-matrix-stack.h0000664000175000017500000005555214211404421020522 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Havoc Pennington for litl * Robert Bragg */ #ifndef _COGL_MATRIX_STACK_H_ #define _COGL_MATRIX_STACK_H_ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #include "cogl-matrix.h" #include "cogl-context.h" /** * SECTION:cogl-matrix-stack * @short_description: Functions for efficiently tracking many * related transformations * * Matrices can be used (for example) to describe the model-view * transforms of objects, texture transforms, and projective * transforms. * * The #CoglMatrix api provides a good way to manipulate individual * matrices representing a single transformation but if you need to * track many-many such transformations for many objects that are * organized in a scenegraph for example then using a separate * #CoglMatrix for each object may not be the most efficient way. * * A #CoglMatrixStack enables applications to track lots of * transformations that are related to each other in some kind of * hierarchy. In a scenegraph for example if you want to know how to * transform a particular node then you usually have to walk up * through the ancestors and accumulate their transforms before * finally applying the transform of the node itself. In this model * things are grouped together spatially according to their ancestry * and all siblings with the same parent share the same initial * transformation. The #CoglMatrixStack API is suited to tracking lots * of transformations that fit this kind of model. * * Compared to using the #CoglMatrix api directly to track many * related transforms, these can be some advantages to using a * #CoglMatrixStack: * * Faster equality comparisons of transformations * Efficient comparisons of the differences between arbitrary * transformations * Avoid redundant arithmetic related to common transforms * * Can be more space efficient (not always though) * * * For reference (to give an idea of when a #CoglMatrixStack can * provide a space saving) a #CoglMatrix can be expected to take 72 * bytes whereas a single #CoglMatrixEntry in a #CoglMatrixStack is * currently around 32 bytes on a 32bit CPU or 36 bytes on a 64bit * CPU. An entry is needed for each individual operation applied to * the stack (such as rotate, scale, translate) so if most of your * leaf node transformations only need one or two simple operations * relative to their parent then a matrix stack will likely take less * space than having a #CoglMatrix for each node. * * Even without any space saving though the ability to perform fast * comparisons and avoid redundant arithmetic (especially sine and * cosine calculations for rotations) can make using a matrix stack * worthwhile. */ /** * CoglMatrixStack: * * Tracks your current position within a hierarchy and lets you build * up a graph of transformations as you traverse through a hierarchy * such as a scenegraph. * * A #CoglMatrixStack always maintains a reference to a single * transformation at any point in time, representing the * transformation at the current position in the hierarchy. You can * get a reference to the current transformation by calling * cogl_matrix_stack_get_entry(). * * When a #CoglMatrixStack is first created with * cogl_matrix_stack_new() then it is conceptually positioned at the * root of your hierarchy and the current transformation simply * represents an identity transformation. * * As you traverse your object hierarchy (your scenegraph) then you * should call cogl_matrix_stack_push() whenever you move down one * level and call cogl_matrix_stack_pop() whenever you move back up * one level towards the root. * * At any time you can apply a set of operations, such as "rotate", * "scale", "translate" on top of the current transformation of a * #CoglMatrixStack using functions such as * cogl_matrix_stack_rotate(), cogl_matrix_stack_scale() and * cogl_matrix_stack_translate(). These operations will derive a new * current transformation and will never affect a transformation * that you have referenced using cogl_matrix_stack_get_entry(). * * Internally applying operations to a #CoglMatrixStack builds up a * graph of #CoglMatrixEntry structures which each represent a single * immutable transform. */ typedef struct _CoglMatrixStack CoglMatrixStack; /** * cogl_matrix_stack_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_matrix_stack_get_gtype (void); /** * CoglMatrixEntry: * * Represents a single immutable transformation that was retrieved * from a #CoglMatrixStack using cogl_matrix_stack_get_entry(). * * Internally a #CoglMatrixEntry represents a single matrix * operation (such as "rotate", "scale", "translate") which is applied * to the transform of a single parent entry. * * Using the #CoglMatrixStack api effectively builds up a graph of * these immutable #CoglMatrixEntry structures whereby operations * that can be shared between multiple transformations will result * in shared #CoglMatrixEntry nodes in the graph. * * When a #CoglMatrixStack is first created it references one * #CoglMatrixEntry that represents a single "load identity" * operation. This serves as the root entry and all operations * that are then applied to the stack will extend the graph * starting from this root "load identity" entry. * * Given the typical usage model for a #CoglMatrixStack and the way * the entries are built up while traversing a scenegraph then in most * cases where an application is interested in comparing two * transformations for equality then it is enough to simply compare * two #CoglMatrixEntry pointers directly. Technically this can lead * to false negatives that could be identified with a deeper * comparison but often these false negatives are unlikely and * don't matter anyway so this enables extremely cheap comparisons. * * #CoglMatrixEntrys are reference counted using * cogl_matrix_entry_ref() and cogl_matrix_entry_unref() not with * cogl_object_ref() and cogl_object_unref(). */ typedef struct _CoglMatrixEntry CoglMatrixEntry; /** * cogl_matrix_entry_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_matrix_entry_get_gtype (void); /** * cogl_matrix_stack_new: * @ctx: A #CoglContext * * Allocates a new #CoglMatrixStack that can be used to build up * transformations relating to objects in a scenegraph like hierarchy. * (See the description of #CoglMatrixStack and #CoglMatrixEntry for * more details of what a matrix stack is best suited for) * * When a #CoglMatrixStack is first allocated it is conceptually * positioned at the root of your scenegraph hierarchy. As you * traverse your scenegraph then you should call * cogl_matrix_stack_push() whenever you move down a level and * cogl_matrix_stack_pop() whenever you move back up a level towards * the root. * * Once you have allocated a #CoglMatrixStack you can get a reference * to the current transformation for the current position in the * hierarchy by calling cogl_matrix_stack_get_entry(). * * Once you have allocated a #CoglMatrixStack you can apply operations * such as rotate, scale and translate to modify the current transform * for the current position in the hierarchy by calling * cogl_matrix_stack_rotate(), cogl_matrix_stack_scale() and * cogl_matrix_stack_translate(). * * Return value: (transfer full): A newly allocated #CoglMatrixStack */ CoglMatrixStack * cogl_matrix_stack_new (CoglContext *ctx); /** * cogl_matrix_stack_push: * @stack: A #CoglMatrixStack * * Saves the current transform and starts a new transform that derives * from the current transform. * * This is usually called while traversing a scenegraph whenever you * traverse one level deeper. cogl_matrix_stack_pop() can then be * called when going back up one layer to restore the previous * transform of an ancestor. */ void cogl_matrix_stack_push (CoglMatrixStack *stack); /** * cogl_matrix_stack_pop: * @stack: A #CoglMatrixStack * * Restores the previous transform that was last saved by calling * cogl_matrix_stack_push(). * * This is usually called while traversing a scenegraph whenever you * return up one level in the graph towards the root node. */ void cogl_matrix_stack_pop (CoglMatrixStack *stack); /** * cogl_matrix_stack_load_identity: * @stack: A #CoglMatrixStack * * Resets the current matrix to the identity matrix. */ void cogl_matrix_stack_load_identity (CoglMatrixStack *stack); /** * cogl_matrix_stack_scale: * @stack: A #CoglMatrixStack * @x: Amount to scale along the x-axis * @y: Amount to scale along the y-axis * @z: Amount to scale along the z-axis * * Multiplies the current matrix by one that scales the x, y and z * axes by the given values. */ void cogl_matrix_stack_scale (CoglMatrixStack *stack, float x, float y, float z); /** * cogl_matrix_stack_translate: * @stack: A #CoglMatrixStack * @x: Distance to translate along the x-axis * @y: Distance to translate along the y-axis * @z: Distance to translate along the z-axis * * Multiplies the current matrix by one that translates along all * three axes according to the given values. */ void cogl_matrix_stack_translate (CoglMatrixStack *stack, float x, float y, float z); /** * cogl_matrix_stack_rotate: * @stack: A #CoglMatrixStack * @angle: Angle in degrees to rotate. * @x: X-component of vertex to rotate around. * @y: Y-component of vertex to rotate around. * @z: Z-component of vertex to rotate around. * * Multiplies the current matrix by one that rotates the around the * axis-vector specified by @x, @y and @z. The rotation follows the * right-hand thumb rule so for example rotating by 10 degrees about * the axis-vector (0, 0, 1) causes a small counter-clockwise * rotation. */ void cogl_matrix_stack_rotate (CoglMatrixStack *stack, float angle, float x, float y, float z); /** * cogl_matrix_stack_rotate_quaternion: * @stack: A #CoglMatrixStack * @quaternion: A #CoglQuaternion * * Multiplies the current matrix by one that rotates according to the * rotation described by @quaternion. */ void cogl_matrix_stack_rotate_quaternion (CoglMatrixStack *stack, const CoglQuaternion *quaternion); /** * cogl_matrix_stack_rotate_euler: * @stack: A #CoglMatrixStack * @euler: A #CoglEuler * * Multiplies the current matrix by one that rotates according to the * rotation described by @euler. */ void cogl_matrix_stack_rotate_euler (CoglMatrixStack *stack, const CoglEuler *euler); /** * cogl_matrix_stack_multiply: * @stack: A #CoglMatrixStack * @matrix: the matrix to multiply with the current model-view * * Multiplies the current matrix by the given matrix. */ void cogl_matrix_stack_multiply (CoglMatrixStack *stack, const CoglMatrix *matrix); /** * cogl_matrix_stack_frustum: * @stack: A #CoglMatrixStack * @left: X position of the left clipping plane where it * intersects the near clipping plane * @right: X position of the right clipping plane where it * intersects the near clipping plane * @bottom: Y position of the bottom clipping plane where it * intersects the near clipping plane * @top: Y position of the top clipping plane where it intersects * the near clipping plane * @z_near: The distance to the near clipping plane (Must be positive) * @z_far: The distance to the far clipping plane (Must be positive) * * Replaces the current matrix with a perspective matrix for a given * viewing frustum defined by 4 side clip planes that all cross * through the origin and 2 near and far clip planes. */ void cogl_matrix_stack_frustum (CoglMatrixStack *stack, float left, float right, float bottom, float top, float z_near, float z_far); /** * cogl_matrix_stack_perspective: * @stack: A #CoglMatrixStack * @fov_y: Vertical field of view angle in degrees. * @aspect: The (width over height) aspect ratio for display * @z_near: The distance to the near clipping plane (Must be positive, * and must not be 0) * @z_far: The distance to the far clipping plane (Must be positive) * * Replaces the current matrix with a perspective matrix based on the * provided values. * * You should be careful not to have too great a @z_far / @z_near * ratio since that will reduce the effectiveness of depth testing * since there wont be enough precision to identify the depth of * objects near to each other. */ void cogl_matrix_stack_perspective (CoglMatrixStack *stack, float fov_y, float aspect, float z_near, float z_far); /** * cogl_matrix_stack_orthographic: * @stack: A #CoglMatrixStack * @x_1: The x coordinate for the first vertical clipping plane * @y_1: The y coordinate for the first horizontal clipping plane * @x_2: The x coordinate for the second vertical clipping plane * @y_2: The y coordinate for the second horizontal clipping plane * @near: The distance to the near clipping * plane (will be negative if the plane is * behind the viewer) * @far: The distance to the far clipping * plane (will be negative if the plane is * behind the viewer) * * Replaces the current matrix with an orthographic projection matrix. */ void cogl_matrix_stack_orthographic (CoglMatrixStack *stack, float x_1, float y_1, float x_2, float y_2, float near, float far); /** * cogl_matrix_stack_get_inverse: * @stack: A #CoglMatrixStack * @inverse: (out): The destination for a 4x4 inverse transformation matrix * * Gets the inverse transform of the current matrix and uses it to * initialize a new #CoglMatrix. * * Return value: %TRUE if the inverse was successfully calculated or %FALSE * for degenerate transformations that can't be inverted (in this case the * @inverse matrix will simply be initialized with the identity matrix) */ CoglBool cogl_matrix_stack_get_inverse (CoglMatrixStack *stack, CoglMatrix *inverse); /** * cogl_matrix_stack_get_entry: * @stack: A #CoglMatrixStack * * Gets a reference to the current transform represented by a * #CoglMatrixEntry pointer. * * The transform represented by a #CoglMatrixEntry is * immutable. * * #CoglMatrixEntrys are reference counted using * cogl_matrix_entry_ref() and cogl_matrix_entry_unref() and you * should call cogl_matrix_entry_unref() when you are finished with * and entry you get via cogl_matrix_stack_get_entry(). * * Return value: (transfer none): A pointer to the #CoglMatrixEntry * representing the current matrix stack transform. */ CoglMatrixEntry * cogl_matrix_stack_get_entry (CoglMatrixStack *stack); /** * cogl_matrix_stack_get: * @stack: A #CoglMatrixStack * @matrix: (out): The potential destination for the current matrix * * Resolves the current @stack transform into a #CoglMatrix by * combining the operations that have been applied to build up the * current transform. * * There are two possible ways that this function may return its * result depending on whether the stack is able to directly point * to an internal #CoglMatrix or whether the result needs to be * composed of multiple operations. * * If an internal matrix contains the required result then this * function will directly return a pointer to that matrix, otherwise * if the function returns %NULL then @matrix will be initialized * to match the current transform of @stack. * * @matrix will be left untouched if a direct pointer is * returned. * * Return value: A direct pointer to the current transform or %NULL * and in that case @matrix will be initialized with * the value of the current transform. */ CoglMatrix * cogl_matrix_stack_get (CoglMatrixStack *stack, CoglMatrix *matrix); /** * cogl_matrix_entry_get: * @entry: A #CoglMatrixEntry * @matrix: (out): The potential destination for the transform as * a matrix * * Resolves the current @entry transform into a #CoglMatrix by * combining the sequence of operations that have been applied to * build up the current transform. * * There are two possible ways that this function may return its * result depending on whether it's possible to directly point * to an internal #CoglMatrix or whether the result needs to be * composed of multiple operations. * * If an internal matrix contains the required result then this * function will directly return a pointer to that matrix, otherwise * if the function returns %NULL then @matrix will be initialized * to match the transform of @entry. * * @matrix will be left untouched if a direct pointer is * returned. * * Return value: A direct pointer to a #CoglMatrix transform or %NULL * and in that case @matrix will be initialized with * the effective transform represented by @entry. */ CoglMatrix * cogl_matrix_entry_get (CoglMatrixEntry *entry, CoglMatrix *matrix); /** * cogl_matrix_stack_set: * @stack: A #CoglMatrixStack * @matrix: A #CoglMatrix replace the current matrix value with * * Replaces the current @stack matrix value with the value of @matrix. * This effectively discards any other operations that were applied * since the last time cogl_matrix_stack_push() was called or since * the stack was initialized. */ void cogl_matrix_stack_set (CoglMatrixStack *stack, const CoglMatrix *matrix); /** * cogl_is_matrix_stack: * @object: a #CoglObject * * Determines if the given #CoglObject refers to a #CoglMatrixStack. * * Return value: %TRUE if @object is a #CoglMatrixStack, otherwise * %FALSE. */ CoglBool cogl_is_matrix_stack (void *object); /** * cogl_matrix_entry_calculate_translation: * @entry0: The first reference transform * @entry1: A second reference transform * @x: (out): The destination for the x-component of the translation * @y: (out): The destination for the y-component of the translation * @z: (out): The destination for the z-component of the translation * * Determines if the only difference between two transforms is a * translation and if so returns what the @x, @y, and @z components of * the translation are. * * If the difference between the two translations involves anything * other than a translation then the function returns %FALSE. * * Return value: %TRUE if the only difference between the transform of * @entry0 and the transform of @entry1 is a translation, * otherwise %FALSE. */ CoglBool cogl_matrix_entry_calculate_translation (CoglMatrixEntry *entry0, CoglMatrixEntry *entry1, float *x, float *y, float *z); /** * cogl_matrix_entry_is_identity: * @entry: A #CoglMatrixEntry * * Determines whether @entry is known to represent an identity * transform. * * If this returns %TRUE then the entry is definitely the identity * matrix. If it returns %FALSE it may or may not be the identity * matrix but no expensive comparison is performed to verify it. * * Return value: %TRUE if @entry is definitely an identity transform, * otherwise %FALSE. */ CoglBool cogl_matrix_entry_is_identity (CoglMatrixEntry *entry); /** * cogl_matrix_entry_equal: * @entry0: The first #CoglMatrixEntry to compare * @entry1: A second #CoglMatrixEntry to compare * * Compares two arbitrary #CoglMatrixEntry transforms for equality * returning %TRUE if they are equal or %FALSE otherwise. * * In many cases it is unnecessary to use this api and instead * direct pointer comparisons of entries are good enough and much * cheaper too. * * Return value: %TRUE if @entry0 represents the same transform as * @entry1, otherwise %FALSE. */ CoglBool cogl_matrix_entry_equal (CoglMatrixEntry *entry0, CoglMatrixEntry *entry1); /** * cogl_debug_matrix_entry_print: * @entry: A #CoglMatrixEntry * * Allows visualizing the operations that build up the given @entry * for debugging purposes by printing to stdout. */ void cogl_debug_matrix_entry_print (CoglMatrixEntry *entry); /** * cogl_matrix_entry_ref: * @entry: A #CoglMatrixEntry * * Takes a reference on the given @entry to ensure the @entry stays * alive and remains valid. When you are finished with the @entry then * you should call cogl_matrix_entry_unref(). * * It is an error to pass an @entry pointer to cogl_object_ref() and * cogl_object_unref() */ CoglMatrixEntry * cogl_matrix_entry_ref (CoglMatrixEntry *entry); /** * cogl_matrix_entry_unref: * @entry: A #CoglMatrixEntry * * Releases a reference on @entry either taken by calling * cogl_matrix_entry_unref() or to release the reference given when * calling cogl_matrix_stack_get_entry(). */ void cogl_matrix_entry_unref (CoglMatrixEntry *entry); #endif /* _COGL_MATRIX_STACK_H_ */ muffin-5.2.1/cogl/cogl/cogl-error.h0000664000175000017500000001333314211404421017233 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_ERROR_H__ #define __COGL_ERROR_H__ #include "cogl-types.h" COGL_BEGIN_DECLS /** * SECTION:cogl-error * @short_description: A way for Cogl to throw exceptions * * As a general rule Cogl shields non-recoverable errors from * developers, such as most heap allocation failures (unless for * exceptionally large resources which we might reasonably expect to * fail) and this reduces the burden on developers. * * There are some Cogl apis though that can fail for exceptional * reasons that can also potentially be recovered from at runtime * and for these apis we use a standard convention for reporting * runtime recoverable errors. * * As an example if we look at the cogl_context_new() api which * takes an error argument: * |[ * CoglContext * * cogl_context_new (CoglDisplay *display, CoglError **error); * ]| * * A caller interested in catching any runtime error when creating a * new #CoglContext would pass the address of a #CoglError pointer * that has first been initialized to %NULL as follows: * * |[ * CoglError *error = NULL; * CoglContext *context; * * context = cogl_context_new (NULL, &error); * ]| * * The return status should usually be enough to determine if there * was an error set (in this example we can check if context == %NULL) * but if it's not possible to tell from the function's return status * you can instead look directly at the error pointer which you * initialized to %NULL. In this example we now check the error, * report any error to the user, free the error and then simply * abort without attempting to recover. * * |[ * if (context == NULL) * { * fprintf (stderr, "Failed to create a Cogl context: %s\n", * error->message); * cogl_error_free (error); * abort (); * } * ]| * * All Cogl APIs that accept an error argument can also be passed a * %NULL pointer. In this case if an exceptional error condition is hit * then Cogl will simply log the error message and abort the * application. This can be compared to language execeptions where the * developer has not attempted to catch the exception. This means the * above example is essentially redundant because it's what Cogl would * have done automatically and so, similarly, if your application has * no way to recover from a particular error you might just as well * pass a %NULL #CoglError pointer to save a bit of typing. * * If you are used to using the GLib API you will probably * recognize that #CoglError is just like a #GError. In fact if Cogl * has been built with --enable-glib then it is safe to cast a * #CoglError to a #GError. * * An important detail to be aware of if you are used to using * GLib's GError API is that Cogl deviates from the GLib GError * conventions in one noteable way which is that a %NULL error pointer * does not mean you want to ignore the details of an error, it means * you are not trying to catch any exceptional errors the function might * throw which will result in the program aborting with a log message * if an error is thrown. */ #define CoglError GError /** * cogl_error_free: * @error: A #CoglError thrown by the Cogl api * * Frees a #CoglError and associated resources. */ void cogl_error_free (CoglError *error); /** * cogl_error_copy: * @error: A #CoglError thrown by the Cogl api * * Makes a copy of @error which can later be freed using * cogl_error_free(). * * Return value: A newly allocated #CoglError initialized to match the * contents of @error. */ CoglError * cogl_error_copy (CoglError *error); /** * cogl_error_matches: * @error: A #CoglError thrown by the Cogl api or %NULL * @domain: The error domain * @code: The error code * * Returns %TRUE if error matches @domain and @code, %FALSE otherwise. * In particular, when error is %NULL, FALSE will be returned. * * Return value: whether the @error corresponds to the given @domain * and @code. */ CoglBool cogl_error_matches (CoglError *error, uint32_t domain, int code); /** * COGL_GLIB_ERROR: * @COGL_ERROR: A #CoglError thrown by the Cogl api or %NULL * * Simply casts a #CoglError to a #CoglError * * If Cogl is built with GLib support then it can safely be assumed * that a CoglError is a GError and can be used directly with the * GError api. */ #define COGL_GLIB_ERROR(COGL_ERROR) ((CoglError *)COGL_ERROR) COGL_END_DECLS #endif /* __COGL_ERROR_H__ */ muffin-5.2.1/cogl/cogl/cogl-debug.c0000664000175000017500000002425414211404421017167 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-i18n-private.h" #include "cogl-private.h" #include "cogl-debug.h" #include "cogl1-context.h" /* XXX: If you add a debug option, please also add an option * definition to cogl-debug-options.h. This will enable us - for * example - to emit a "help" description for the option. */ /* NB: Only these options get enabled if COGL_DEBUG=all is * used since they don't affect the behaviour of Cogl they * simply print out verbose information */ static const GDebugKey cogl_log_debug_keys[] = { { "object", COGL_DEBUG_OBJECT }, { "slicing", COGL_DEBUG_SLICING }, { "atlas", COGL_DEBUG_ATLAS }, { "blend-strings", COGL_DEBUG_BLEND_STRINGS }, { "journal", COGL_DEBUG_JOURNAL }, { "batching", COGL_DEBUG_BATCHING }, { "matrices", COGL_DEBUG_MATRICES }, { "draw", COGL_DEBUG_DRAW }, { "opengl", COGL_DEBUG_OPENGL }, { "pango", COGL_DEBUG_PANGO }, { "show-source", COGL_DEBUG_SHOW_SOURCE}, { "offscreen", COGL_DEBUG_OFFSCREEN }, { "texture-pixmap", COGL_DEBUG_TEXTURE_PIXMAP }, { "bitmap", COGL_DEBUG_BITMAP }, { "clipping", COGL_DEBUG_CLIPPING }, { "winsys", COGL_DEBUG_WINSYS }, { "performance", COGL_DEBUG_PERFORMANCE } }; static const int n_cogl_log_debug_keys = G_N_ELEMENTS (cogl_log_debug_keys); static const GDebugKey cogl_behavioural_debug_keys[] = { { "rectangles", COGL_DEBUG_RECTANGLES }, { "disable-batching", COGL_DEBUG_DISABLE_BATCHING }, { "disable-vbos", COGL_DEBUG_DISABLE_VBOS }, { "disable-pbos", COGL_DEBUG_DISABLE_PBOS }, { "disable-software-transform", COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM }, { "dump-atlas-image", COGL_DEBUG_DUMP_ATLAS_IMAGE }, { "disable-atlas", COGL_DEBUG_DISABLE_ATLAS }, { "disable-shared-atlas", COGL_DEBUG_DISABLE_SHARED_ATLAS }, { "disable-texturing", COGL_DEBUG_DISABLE_TEXTURING}, { "disable-arbfp", COGL_DEBUG_DISABLE_ARBFP}, { "disable-fixed", COGL_DEBUG_DISABLE_FIXED}, { "disable-glsl", COGL_DEBUG_DISABLE_GLSL}, { "disable-blending", COGL_DEBUG_DISABLE_BLENDING}, { "disable-npot-textures", COGL_DEBUG_DISABLE_NPOT_TEXTURES}, { "wireframe", COGL_DEBUG_WIREFRAME}, { "disable-software-clip", COGL_DEBUG_DISABLE_SOFTWARE_CLIP}, { "disable-program-caches", COGL_DEBUG_DISABLE_PROGRAM_CACHES}, { "disable-fast-read-pixel", COGL_DEBUG_DISABLE_FAST_READ_PIXEL} }; static const int n_cogl_behavioural_debug_keys = G_N_ELEMENTS (cogl_behavioural_debug_keys); unsigned long _cogl_debug_flags[COGL_DEBUG_N_LONGS]; GHashTable *_cogl_debug_instances; static void _cogl_parse_debug_string_for_keys (const char *value, CoglBool enable, const GDebugKey *keys, unsigned int nkeys) { int long_num, key_num; /* g_parse_debug_string expects the value field in GDebugKey to be a mask in an unsigned int but the flags are stored in an array of multiple longs so we need to build a separate array for each possible unsigned int */ for (long_num = 0; long_num < COGL_DEBUG_N_LONGS; long_num++) { int int_num; for (int_num = 0; int_num < sizeof (unsigned long) / sizeof (unsigned int); int_num++) { GDebugKey keys_for_int[sizeof (unsigned int) * 8]; int nkeys_for_int = 0; for (key_num = 0; key_num < nkeys; key_num++) { int long_index = COGL_FLAGS_GET_INDEX (keys[key_num].value); int int_index = (keys[key_num].value % (sizeof (unsigned long) * 8) / (sizeof (unsigned int) * 8)); if (long_index == long_num && int_index == int_num) { keys_for_int[nkeys_for_int] = keys[key_num]; keys_for_int[nkeys_for_int].value = COGL_FLAGS_GET_MASK (keys[key_num].value) >> (int_num * sizeof (unsigned int) * 8); nkeys_for_int++; } } if (nkeys_for_int > 0) { unsigned long mask = ((unsigned long) g_parse_debug_string (value, keys_for_int, nkeys_for_int)) << (int_num * sizeof (unsigned int) * 8); if (enable) _cogl_debug_flags[long_num] |= mask; else _cogl_debug_flags[long_num] &= ~mask; } } } } void _cogl_parse_debug_string (const char *value, CoglBool enable, CoglBool ignore_help) { if (ignore_help && strcmp (value, "help") == 0) return; /* We don't want to let g_parse_debug_string handle "all" because * literally enabling all the debug options wouldn't be useful to * anyone; instead the all option enables all non behavioural * options. */ if (strcmp (value, "all") == 0 || strcmp (value, "verbose") == 0) { int i; for (i = 0; i < n_cogl_log_debug_keys; i++) if (enable) COGL_DEBUG_SET_FLAG (cogl_log_debug_keys[i].value); else COGL_DEBUG_CLEAR_FLAG (cogl_log_debug_keys[i].value); } else if (g_ascii_strcasecmp (value, "help") == 0) { g_printerr ("\n\n%28s\n", _("Supported debug values:")); #define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \ g_printerr ("%28s %s\n", NAME ":", DESCRIPTION); #include "cogl-debug-options.h" g_printerr ("\n%28s\n", _("Special debug values:")); OPT (IGNORED, "ignored", "all", "ignored", \ N_("Enables all non-behavioural debug options")); OPT (IGNORED, "ignored", "verbose", "ignored", \ N_("Enables all non-behavioural debug options")); #undef OPT g_printerr ("\n" "%28s\n" " COGL_DISABLE_GL_EXTENSIONS: %s\n" " COGL_OVERRIDE_GL_VERSION: %s\n", _("Additional environment variables:"), _("Comma-separated list of GL extensions to pretend are " "disabled"), _("Override the GL version that Cogl will assume the driver " "supports")); exit (1); } else { _cogl_parse_debug_string_for_keys (value, enable, cogl_log_debug_keys, n_cogl_log_debug_keys); _cogl_parse_debug_string_for_keys (value, enable, cogl_behavioural_debug_keys, n_cogl_behavioural_debug_keys); } } #ifdef COGL_ENABLE_DEBUG static CoglBool cogl_arg_debug_cb (const char *key, const char *value, void *user_data) { _cogl_parse_debug_string (value, TRUE /* enable the flags */, FALSE /* don't ignore help */); return TRUE; } static CoglBool cogl_arg_no_debug_cb (const char *key, const char *value, void *user_data) { _cogl_parse_debug_string (value, FALSE, /* disable the flags */ TRUE /* ignore help */); return TRUE; } #endif /* COGL_ENABLE_DEBUG */ static GOptionEntry cogl_args[] = { #ifdef COGL_ENABLE_DEBUG { "cogl-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_debug_cb, N_("Cogl debugging flags to set"), "FLAGS" }, { "cogl-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_no_debug_cb, N_("Cogl debugging flags to unset"), "FLAGS" }, #endif /* COGL_ENABLE_DEBUG */ { NULL, }, }; void _cogl_debug_check_environment (void) { const char *env_string; env_string = g_getenv ("COGL_DEBUG"); if (env_string != NULL) { _cogl_parse_debug_string (env_string, TRUE /* enable the flags */, FALSE /* don't ignore help */); env_string = NULL; } env_string = g_getenv ("COGL_NO_DEBUG"); if (env_string != NULL) { _cogl_parse_debug_string (env_string, FALSE /* disable the flags */, FALSE /* don't ignore help */); env_string = NULL; } } static CoglBool pre_parse_hook (GOptionContext *context, GOptionGroup *group, void *data, GError **error) { _cogl_init (); return TRUE; } /* XXX: GOption based library initialization is not reliable because the * GOption API has no way to represent dependencies between libraries. */ GOptionGroup * cogl_get_option_group (void) { GOptionGroup *group; group = g_option_group_new ("cogl", _("Cogl Options"), _("Show Cogl options"), NULL, NULL); g_option_group_set_parse_hooks (group, pre_parse_hook, NULL); g_option_group_add_entries (group, cogl_args); return group; } muffin-5.2.1/cogl/cogl/cogl.symbols0000664000175000017500000006213714211404421017353 0ustar jpeisachjpeisach #ifdef COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT cogl_android_set_native_window #endif #ifdef COGL_HAS_GTYPE_SUPPORT cogl_atlas_texture_get_gtype #endif cogl_atlas_texture_new_with_size cogl_atlas_texture_new_from_file cogl_atlas_texture_new_from_data cogl_atlas_texture_new_from_bitmap #ifdef COGL_HAS_GTYPE_SUPPORT cogl_attribute_buffer_get_gtype #endif cogl_attribute_buffer_new_with_size cogl_attribute_buffer_new cogl_attribute_get_buffer #ifdef COGL_HAS_GTYPE_SUPPORT cogl_attribute_get_gtype #endif cogl_attribute_get_normalized cogl_attribute_new cogl_attribute_new_const_1f cogl_attribute_new_const_2f cogl_attribute_new_const_2fv cogl_attribute_new_const_2x2fv cogl_attribute_new_const_3f cogl_attribute_new_const_3fv cogl_attribute_new_const_3x3fv cogl_attribute_new_const_4f cogl_attribute_new_const_4fv cogl_attribute_new_const_4x4fv cogl_attribute_set_buffer cogl_attribute_set_normalized cogl_attribute_type_get_type cogl_begin_gl cogl_bitmap_error_get_type cogl_bitmap_get_buffer cogl_bitmap_get_format #ifdef COGL_HAS_GTYPE_SUPPORT cogl_bitmap_get_gtype #endif cogl_bitmap_get_height cogl_bitmap_get_rowstride cogl_bitmap_get_size_from_file cogl_bitmap_get_width cogl_bitmap_new_for_data cogl_bitmap_new_from_file cogl_bitmap_new_from_buffer cogl_bitmap_new_with_size cogl_blend_string_error_get_type cogl_buffer_bit_get_type cogl_buffer_get_size cogl_buffer_get_update_hint #if 0 /* not implemented! */ cogl_buffer_get_usage_hint #endif cogl_buffer_map cogl_buffer_map_range cogl_buffer_set_data cogl_buffer_set_update_hint #if 0 /* not implemented! */ cogl_buffer_set_usage_hint #endif cogl_buffer_target_get_type cogl_buffer_unmap #ifndef COGL_DISABLE_DEPRECATED cogl_check_extension #endif cogl_clear #ifndef COGL_DISABLE_DEPRECATED cogl_clip_ensure #endif cogl_clip_pop #ifndef COGL_DISABLE_DEPRECATED cogl_clip_push #endif cogl_clip_push_rectangle cogl_clip_push_window_rect cogl_clip_push_primitive #ifndef COGL_DISABLE_DEPRECATED cogl_clip_push_window_rectangle cogl_clip_stack_restore cogl_clip_stack_save #endif #ifndef COGL_WINSYS_INTEGRATED cogl_clutter_check_extension_CLUTTER cogl_clutter_winsys_has_feature_CLUTTER #ifdef COGL_HAS_XLIB cogl_clutter_winsys_xlib_get_visual_info_CLUTTER #endif #endif cogl_color_copy cogl_color_equal cogl_color_free cogl_color_get_alpha cogl_color_get_alpha_byte cogl_color_get_alpha_float cogl_color_get_blue cogl_color_get_blue_byte cogl_color_get_blue_float cogl_color_get_green cogl_color_get_green_byte cogl_color_get_green_float #ifdef COGL_HAS_GTYPE_SUPPORT cogl_color_get_gtype #endif cogl_color_get_red cogl_color_get_red_byte cogl_color_get_red_float cogl_color_init_from_hsl cogl_color_init_from_4f cogl_color_init_from_4fv cogl_color_init_from_4ub cogl_color_mask_get_type cogl_color_new cogl_color_premultiply cogl_color_set_alpha cogl_color_set_alpha_byte cogl_color_set_alpha_float cogl_color_set_blue cogl_color_set_blue_byte cogl_color_set_blue_float cogl_color_set_from_4f cogl_color_set_from_4ub cogl_color_set_green cogl_color_set_green_byte cogl_color_set_green_float cogl_color_set_red cogl_color_set_red_byte cogl_color_set_red_float cogl_color_to_hsl cogl_color_unpremultiply #ifdef COGL_HAS_EGL_SUPPORT cogl_egl_context_get_egl_display cogl_egl_context_get_egl_context #endif #ifdef COGL_HAS_GLX_SUPPORT cogl_glx_context_get_glx_context #endif cogl_context_get_display #ifdef COGL_HAS_GTYPE_SUPPORT cogl_context_get_gtype #endif cogl_context_get_renderer cogl_context_new cogl_create_program cogl_create_shader cogl_debug_matrix_entry_print cogl_debug_matrix_print cogl_debug_object_foreach_type cogl_debug_object_print_instances cogl_depth_state_get_range cogl_depth_state_get_test_enabled cogl_depth_state_get_test_function cogl_depth_state_get_write_enabled cogl_depth_state_init cogl_depth_state_set_test_enabled cogl_depth_state_set_test_function cogl_depth_state_set_range cogl_depth_state_set_write_enabled cogl_depth_test_function_get_type cogl_disable_fog #ifdef COGL_HAS_GTYPE_SUPPORT cogl_display_get_gtype #endif cogl_display_get_renderer cogl_display_new cogl_display_setup cogl_display_set_onscreen_template cogl_double_to_fixed cogl_end_gl cogl_error_copy cogl_error_free cogl_error_matches cogl_euler_copy cogl_euler_equal cogl_euler_free #ifdef COGL_HAS_GTYPE_SUPPORT cogl_euler_get_gtype #endif cogl_euler_init cogl_euler_init_from_matrix #if 0 /* not yet implemented */ cogl_euler_init_from_quaternion #endif cogl_features_available cogl_feature_flags_get_type cogl_fence_closure_get_user_data cogl_fixed_atan cogl_fixed_atan2 cogl_fixed_cos cogl_fixed_get_type cogl_fixed_log2 cogl_fixed_pow cogl_fixed_pow2 cogl_fixed_sin cogl_fixed_sqrt cogl_fixed_tan cogl_fog_mode_get_type cogl_foreach_feature cogl_flush cogl_framebuffer_add_fence_callback cogl_framebuffer_allocate cogl_framebuffer_cancel_fence_callback cogl_framebuffer_clear4f cogl_framebuffer_clear cogl_framebuffer_discard_buffers cogl_framebuffer_draw_primitive cogl_framebuffer_draw_rectangle cogl_framebuffer_draw_rectangles cogl_framebuffer_draw_textured_rectangle cogl_framebuffer_draw_textured_rectangles cogl_framebuffer_finish cogl_framebuffer_frustum cogl_framebuffer_get_alpha_bits cogl_framebuffer_get_blue_bits cogl_framebuffer_get_color_format cogl_framebuffer_get_color_mask cogl_framebuffer_get_context cogl_framebuffer_get_depth_bits cogl_framebuffer_get_depth_texture cogl_framebuffer_get_depth_texture_enabled cogl_framebuffer_get_depth_write_enabled cogl_framebuffer_get_dither_enabled cogl_framebuffer_get_green_bits #ifdef COGL_HAS_GTYPE_SUPPORT cogl_framebuffer_get_gtype #endif cogl_framebuffer_get_height cogl_framebuffer_get_modelview_matrix cogl_framebuffer_get_projection_matrix cogl_framebuffer_get_red_bits cogl_framebuffer_get_samples_per_pixel cogl_framebuffer_get_viewport4fv cogl_framebuffer_get_viewport_height cogl_framebuffer_get_viewport_width cogl_framebuffer_get_viewport_x cogl_framebuffer_get_viewport_y cogl_framebuffer_get_width cogl_framebuffer_identity_matrix cogl_framebuffer_orthographic cogl_framebuffer_perspective cogl_framebuffer_pop_clip cogl_framebuffer_pop_matrix cogl_framebuffer_push_matrix cogl_framebuffer_push_primitive_clip cogl_framebuffer_push_rectangle_clip cogl_framebuffer_push_scissor_clip cogl_framebuffer_read_pixels cogl_framebuffer_read_pixels_into_bitmap cogl_framebuffer_resolve_samples cogl_framebuffer_resolve_samples_region cogl_framebuffer_rotate #ifdef COGL_ENABLE_EXPERIMENTAL_API cogl_framebuffer_rotate_euler cogl_framebuffer_rotate_quaternion #endif cogl_framebuffer_scale cogl_framebuffer_set_color_mask cogl_framebuffer_set_depth_texture_enabled cogl_framebuffer_set_depth_write_enabled cogl_framebuffer_set_dither_enabled cogl_framebuffer_set_modelview_matrix cogl_framebuffer_set_projection_matrix cogl_framebuffer_set_samples_per_pixel cogl_framebuffer_set_viewport cogl_framebuffer_transform cogl_framebuffer_translate cogl_framebuffer_vdraw_attributes /* cogl_framebuffer_vdraw_indexed_attributes */ /* Not Implemented! */ #ifdef COGL_HAS_GTYPE_SUPPORT cogl_frame_closure_get_gtype #endif cogl_frame_info_get_frame_counter #ifdef COGL_HAS_GTYPE_SUPPORT cogl_frame_info_get_gtype #endif cogl_frame_info_get_output cogl_frame_info_get_presentation_time cogl_frame_info_get_refresh_rate cogl_frustum cogl_get_backface_culling_enabled cogl_get_bitmasks cogl_get_clock_time cogl_get_depth_test_enabled cogl_get_draw_framebuffer cogl_get_features cogl_get_graphics_reset_status cogl_get_modelview_matrix cogl_get_option_group cogl_get_proc_address cogl_get_projection_matrix cogl_get_rectangle_indices cogl_get_source cogl_get_static_identity_quaternion cogl_get_static_zero_quaternion cogl_get_viewport #ifdef COGL_HAS_GTYPE_SUPPORT cogl_gles2_context_get_gtype #endif cogl_gles2_context_get_vtable cogl_gles2_context_new cogl_gles2_get_current_vtable cogl_gles2_texture_get_handle cogl_gles2_texture_2d_new_from_handle #ifdef COGL_HAS_GLIB_SUPPORT cogl_glib_renderer_source_new cogl_glib_source_new #endif #ifdef COGL_HAS_GTYPE_SUPPORT cogl_gtype_matrix_get_type #endif cogl_handle_get_type cogl_handle_ref cogl_handle_unref cogl_has_feature cogl_has_features #ifdef COGL_HAS_GTYPE_SUPPORT cogl_index_buffer_get_gtype #endif cogl_index_buffer_new cogl_indices_get_buffer #ifdef COGL_HAS_GTYPE_SUPPORT cogl_indices_get_gtype #endif cogl_indices_get_offset cogl_indices_get_type cogl_indices_new cogl_indices_new_for_buffer cogl_indices_set_offset cogl_indices_type_get_type cogl_is_atlas_texture cogl_is_attribute cogl_is_attribute_buffer cogl_is_bitmap cogl_is_buffer cogl_is_context cogl_is_frame_info cogl_is_gles2_context cogl_is_index_buffer #if 0 /* not implemented! */ cogl_is_indices_array #endif cogl_is_material cogl_is_matrix_stack cogl_is_offscreen cogl_is_output cogl_is_pipeline cogl_is_pixel_buffer cogl_is_primitive cogl_is_primitive_texture cogl_is_program cogl_is_renderer cogl_is_shader cogl_is_snippet cogl_is_sub_texture cogl_is_texture #ifdef COGL_HAS_X11 cogl_is_texture_pixmap_x11 #endif cogl_is_texture_rectangle cogl_is_texture_2d cogl_is_texture_3d #ifdef COGL_HAS_EGL_PLATFORM_KMS_SUPPORT cogl_kms_display_queue_modes_reset cogl_kms_display_set_layout cogl_kms_renderer_get_kms_fd #endif cogl_material_alpha_func_get_type cogl_material_copy cogl_material_filter_get_type cogl_material_foreach_layer cogl_material_get_ambient cogl_material_get_color cogl_material_get_depth_state cogl_material_get_diffuse cogl_material_get_emission cogl_material_get_layers cogl_material_get_layer_point_sprite_coords_enabled cogl_material_get_layer_wrap_mode_p cogl_material_get_layer_wrap_mode_s cogl_material_get_layer_wrap_mode_t cogl_material_get_n_layers cogl_material_get_point_size cogl_material_get_shininess cogl_material_get_specular cogl_material_get_user_program cogl_material_layer_get_mag_filter cogl_material_layer_get_min_filter cogl_material_layer_get_texture cogl_material_layer_get_type cogl_material_layer_get_wrap_mode_p cogl_material_layer_get_wrap_mode_s cogl_material_layer_get_wrap_mode_t cogl_material_layer_type_get_type cogl_material_new cogl_material_remove_layer #ifndef COGL_DISABLE_DEPRECATED cogl_material_ref #endif cogl_material_set_alpha_test_function cogl_material_set_ambient cogl_material_set_ambient_and_diffuse cogl_material_set_blend cogl_material_set_blend_constant cogl_material_set_color cogl_material_set_color4f cogl_material_set_color4ub cogl_material_set_depth_state cogl_material_set_diffuse cogl_material_set_emission cogl_material_set_layer cogl_material_set_layer_combine cogl_material_set_layer_combine_constant cogl_material_set_layer_filters cogl_material_set_layer_matrix cogl_material_set_layer_point_sprite_coords_enabled cogl_material_set_layer_wrap_mode cogl_material_set_layer_wrap_mode_p cogl_material_set_layer_wrap_mode_s cogl_material_set_layer_wrap_mode_t cogl_material_set_point_size cogl_material_set_shininess cogl_material_set_specular cogl_material_set_user_program #ifndef COGL_DISABLE_DEPRECATED cogl_material_unref #endif cogl_material_wrap_mode_get_type cogl_matrix_copy cogl_matrix_entry_calculate_translation cogl_matrix_entry_equal cogl_matrix_entry_get #ifdef COGL_HAS_GTYPE_SUPPORT cogl_matrix_entry_get_gtype #endif cogl_matrix_entry_is_identity cogl_matrix_entry_ref cogl_matrix_entry_unref cogl_matrix_equal cogl_matrix_free cogl_matrix_frustum cogl_matrix_get_array #ifdef COGL_HAS_GTYPE_SUPPORT cogl_matrix_get_gtype #endif cogl_matrix_get_inverse cogl_matrix_init_from_array cogl_matrix_init_translation cogl_matrix_is_identity cogl_matrix_init_from_euler cogl_matrix_init_from_quaternion cogl_matrix_init_identity cogl_matrix_look_at cogl_matrix_multiply #ifndef COGL_DISABLE_DEPRECATED cogl_matrix_ortho #endif cogl_matrix_orthographic cogl_matrix_perspective cogl_matrix_project_points cogl_matrix_rotate #ifdef COGL_ENABLE_EXPERIMENTAL_API cogl_matrix_rotate_euler cogl_matrix_rotate_quaternion #endif cogl_matrix_scale cogl_matrix_stack_frustum cogl_matrix_stack_get cogl_matrix_stack_get_entry #ifdef COGL_HAS_GTYPE_SUPPORT cogl_matrix_stack_get_gtype #endif cogl_matrix_stack_get_inverse cogl_matrix_stack_load_identity cogl_matrix_stack_multiply cogl_matrix_stack_new cogl_matrix_stack_orthographic cogl_matrix_stack_perspective cogl_matrix_stack_pop cogl_matrix_stack_push cogl_matrix_stack_rotate cogl_matrix_stack_rotate_euler cogl_matrix_stack_rotate_quaternion cogl_matrix_stack_scale cogl_matrix_stack_set cogl_matrix_stack_translate cogl_matrix_transform_point cogl_matrix_transform_points cogl_matrix_translate cogl_matrix_transpose cogl_matrix_view_2d_in_frustum cogl_matrix_view_2d_in_perspective cogl_meta_texture_foreach_in_region #ifdef COGL_HAS_GTYPE_SUPPORT cogl_object_get_gtype #endif cogl_object_get_user_data cogl_object_ref cogl_object_set_user_data cogl_object_unref #ifdef COGL_HAS_GTYPE_SUPPORT cogl_offscreen_get_gtype #endif cogl_offscreen_new_to_texture cogl_offscreen_new_with_texture cogl_onscreen_add_dirty_callback cogl_onscreen_add_frame_callback cogl_onscreen_add_resize_callback cogl_onscreen_add_swap_buffers_callback #ifndef COGL_WINSYS_INTEGRATED cogl_onscreen_clutter_backend_set_size_CLUTTER #endif #ifdef COGL_HAS_GTYPE_SUPPORT cogl_onscreen_dirty_closure_get_gtype #endif cogl_onscreen_get_buffer_age cogl_onscreen_get_frame_counter #ifdef COGL_HAS_GTYPE_SUPPORT cogl_onscreen_get_gtype #endif cogl_onscreen_get_resizable cogl_onscreen_hide cogl_onscreen_new cogl_onscreen_set_swap_throttled cogl_onscreen_remove_dirty_callback cogl_onscreen_remove_frame_callback cogl_onscreen_remove_resize_callback cogl_onscreen_remove_swap_buffers_callback #ifdef COGL_HAS_GTYPE_SUPPORT cogl_onscreen_resize_closure_get_gtype #endif cogl_onscreen_set_resizable cogl_onscreen_set_swap_throttled cogl_onscreen_show cogl_onscreen_swap_buffers cogl_onscreen_swap_buffers_with_damage cogl_onscreen_swap_region #ifdef COGL_HAS_GTYPE_SUPPORT cogl_onscreen_template_get_gtype #endif cogl_onscreen_template_new cogl_onscreen_template_set_samples_per_pixel cogl_onscreen_template_set_swap_throttled cogl_ortho #ifdef COGL_HAS_GTYPE_SUPPORT cogl_output_get_gtype #endif cogl_output_get_height cogl_output_get_mm_height cogl_output_get_mm_width cogl_output_get_refresh_rate cogl_output_get_subpixel_order cogl_output_get_width cogl_output_get_x cogl_output_get_y cogl_perspective cogl_pipeline_add_layer_snippet cogl_pipeline_add_snippet cogl_pipeline_copy cogl_pipeline_foreach_layer cogl_pipeline_get_alpha_test_function cogl_pipeline_get_alpha_test_reference cogl_pipeline_get_ambient cogl_pipeline_get_color cogl_pipeline_get_color_mask cogl_pipeline_get_cull_face_mode cogl_pipeline_get_depth_state cogl_pipeline_get_diffuse cogl_pipeline_get_emission cogl_pipeline_get_front_face_winding #ifdef COGL_HAS_GTYPE_SUPPORT cogl_pipeline_get_gtype #endif cogl_pipeline_get_layer_mag_filter cogl_pipeline_get_layer_min_filter cogl_pipeline_get_layer_point_sprite_coords_enabled cogl_pipeline_get_layer_texture cogl_pipeline_get_layer_wrap_mode_p cogl_pipeline_get_layer_wrap_mode_s cogl_pipeline_get_layer_wrap_mode_t cogl_pipeline_get_n_layers cogl_pipeline_get_per_vertex_point_size cogl_pipeline_get_point_size cogl_pipeline_get_shininess cogl_pipeline_get_specular cogl_pipeline_get_uniform_location cogl_pipeline_get_user_program cogl_pipeline_new cogl_pipeline_set_alpha_test_function cogl_pipeline_set_ambient cogl_pipeline_set_ambient_and_diffuse cogl_pipeline_set_blend cogl_pipeline_set_blend_constant cogl_pipeline_set_color cogl_pipeline_set_color_mask cogl_pipeline_set_color4f cogl_pipeline_set_color4ub cogl_pipeline_set_cull_face_mode cogl_pipeline_set_depth_state cogl_pipeline_set_diffuse cogl_pipeline_set_emission cogl_pipeline_set_front_face_winding cogl_pipeline_set_layer_combine cogl_pipeline_set_layer_combine_constant cogl_pipeline_set_layer_filters cogl_pipeline_set_layer_matrix cogl_pipeline_set_layer_null_texture cogl_pipeline_set_layer_point_sprite_coords_enabled cogl_pipeline_set_layer_texture cogl_pipeline_set_layer_wrap_mode cogl_pipeline_set_layer_wrap_mode_p cogl_pipeline_set_layer_wrap_mode_s cogl_pipeline_set_layer_wrap_mode_t cogl_pipeline_set_per_vertex_point_size cogl_pipeline_set_point_size cogl_pipeline_remove_layer cogl_pipeline_set_shininess cogl_pipeline_set_specular cogl_pipeline_set_uniform_float cogl_pipeline_set_uniform_int cogl_pipeline_set_uniform_matrix cogl_pipeline_set_uniform_1f cogl_pipeline_set_uniform_1i cogl_pipeline_set_user_program #ifdef COGL_HAS_GTYPE_SUPPORT cogl_pixel_buffer_get_gtype #endif cogl_pixel_buffer_new #if 0 /* not exported in the main APIs for now */ cogl_pixel_buffer_set_region #endif cogl_pixel_format_get_type cogl_poll_renderer_dispatch cogl_poll_renderer_get_info cogl_polygon #ifndef COGL_DISABLE_DEPRECATED cogl_pop_draw_buffer #endif cogl_pop_framebuffer cogl_pop_gles2_context cogl_pop_matrix cogl_pop_source cogl_primitive_copy cogl_primitive_foreach_attribute cogl_primitive_get_first_vertex #ifdef COGL_HAS_GTYPE_SUPPORT cogl_primitive_get_gtype #endif cogl_primitive_get_indices cogl_primitive_get_mode cogl_primitive_get_n_vertices cogl_primitive_new cogl_primitive_new_p2 cogl_primitive_new_p2c4 cogl_primitive_new_p2t2 cogl_primitive_new_p2t2c4 cogl_primitive_new_p3 cogl_primitive_new_p3c4 cogl_primitive_new_p3t2 cogl_primitive_new_p3t2c4 cogl_primitive_new_with_attributes cogl_primitive_set_attributes cogl_primitive_set_first_vertex cogl_primitive_set_indices cogl_primitive_set_mode cogl_primitive_set_n_vertices cogl_primitive_draw cogl_primitive_texture_set_auto_mipmap cogl_program_attach_shader cogl_program_get_uniform_location cogl_program_link #ifndef COGL_DISABLE_DEPRECATED cogl_program_ref #endif cogl_program_set_uniform_float cogl_program_set_uniform_int cogl_program_set_uniform_matrix cogl_program_set_uniform_1f cogl_program_set_uniform_1i #ifndef COGL_DISABLE_DEPRECATED cogl_program_uniform_float cogl_program_uniform_int cogl_program_uniform_matrix cogl_program_uniform_1f cogl_program_uniform_1i cogl_program_unref #endif cogl_program_use #ifndef COGL_DISABLE_DEPRECATED cogl_push_draw_buffer #endif cogl_push_framebuffer cogl_push_gles2_context cogl_push_matrix cogl_push_source cogl_quaternion_copy cogl_quaternion_dot_product cogl_quaternion_equal cogl_quaternion_free #ifdef COGL_HAS_GTYPE_SUPPORT cogl_quaternion_get_gtype #endif cogl_quaternion_get_rotation_angle cogl_quaternion_get_rotation_axis cogl_quaternion_init cogl_quaternion_init_from_angle_vector cogl_quaternion_init_from_array cogl_quaternion_init_from_euler cogl_quaternion_init_from_x_rotation cogl_quaternion_init_from_y_rotation cogl_quaternion_init_from_z_rotation cogl_quaternion_init_identity cogl_quaternion_invert cogl_quaternion_multiply cogl_quaternion_nlerp cogl_quaternion_normalize cogl_quaternion_pow cogl_quaternion_slerp cogl_quaternion_squad cogl_read_pixels cogl_read_pixels_flags_get_type cogl_rectangle cogl_rectangles cogl_rectangles_with_texture_coords cogl_rectangle_with_multitexture_coords cogl_rectangle_with_texture_coords cogl_renderer_add_constraint cogl_renderer_check_onscreen_template cogl_renderer_connect cogl_renderer_foreach_output cogl_renderer_get_driver #ifdef COGL_HAS_GTYPE_SUPPORT cogl_renderer_get_gtype #endif cogl_renderer_get_n_fragment_texture_units cogl_renderer_error_get_type cogl_renderer_get_winsys_id cogl_renderer_new cogl_renderer_remove_constraint cogl_renderer_set_driver cogl_renderer_set_winsys_id cogl_rotate cogl_scale cogl_set_backface_culling_enabled cogl_set_depth_test_enabled #ifndef COGL_DISABLE_DEPRECATED cogl_set_draw_buffer #endif cogl_set_fog #ifdef COGL_HAS_SDL_SUPPORT cogl_sdl_context_new cogl_sdl_handle_event cogl_sdl_idle #if SDL_MAJOR_VERSION >= 2 cogl_sdl_onscreen_get_window #endif cogl_sdl_renderer_get_event_type cogl_sdl_renderer_set_event_type #endif cogl_set_framebuffer cogl_set_modelview_matrix cogl_set_projection_matrix cogl_set_source cogl_set_source_color cogl_set_source_color4f cogl_set_source_color4ub cogl_set_source_texture cogl_set_viewport cogl_shader_compile cogl_shader_get_info_log cogl_shader_get_type cogl_shader_is_compiled #ifndef COGL_DISABLE_DEPRECATED cogl_shader_ref #endif cogl_shader_source cogl_shader_type_get_type #ifndef COGL_DISABLE_DEPRECATED cogl_shader_unref #endif cogl_snippet_get_declarations cogl_snippet_get_hook cogl_snippet_get_post cogl_snippet_get_pre cogl_snippet_get_replace #ifdef COGL_HAS_GTYPE_SUPPORT cogl_snippet_get_gtype #endif cogl_snippet_new cogl_snippet_set_declarations cogl_snippet_set_post cogl_snippet_set_pre cogl_snippet_set_replace cogl_sqrti #ifdef COGL_HAS_GTYPE_SUPPORT cogl_sub_texture_get_gtype #endif cogl_sub_texture_get_parent cogl_sub_texture_new #ifdef COGL_HAS_GTYPE_SUPPORT cogl_swap_chain_get_gtype #endif cogl_swap_chain_new cogl_swap_chain_set_has_alpha cogl_swap_chain_set_length cogl_system_error_get_type cogl_texture_allocate cogl_texture_components_get_type cogl_texture_error_get_type cogl_texture_flags_get_type cogl_texture_get_components cogl_texture_get_data cogl_texture_get_format cogl_texture_get_gl_texture #ifdef COGL_HAS_GTYPE_SUPPORT cogl_texture_get_gtype #endif cogl_texture_get_height cogl_texture_get_max_waste cogl_texture_get_premultiplied cogl_texture_get_rowstride cogl_texture_get_width cogl_texture_is_sliced cogl_texture_new_from_bitmap cogl_texture_new_from_data cogl_texture_new_from_file cogl_texture_new_from_foreign cogl_texture_new_from_sub_texture cogl_texture_new_with_size #ifdef COGL_HAS_X11 cogl_texture_pixmap_x11_error_domain #ifdef COGL_HAS_GTYPE_SUPPORT cogl_texture_pixmap_x11_get_gtype #endif cogl_texture_pixmap_x11_is_using_tfp_extension cogl_texture_pixmap_x11_new cogl_texture_pixmap_x11_set_damage_object cogl_texture_pixmap_x11_update_area #endif #ifdef COGL_HAS_GTYPE_SUPPORT cogl_texture_rectangle_get_gtype #endif cogl_texture_rectangle_new_from_bitmap cogl_texture_rectangle_new_from_foreign cogl_texture_rectangle_new_with_size #ifndef COGL_DISABLE_DEPRECATED cogl_texture_ref #endif cogl_texture_set_components cogl_texture_set_data cogl_texture_set_premultiplied cogl_texture_set_region cogl_texture_set_region_from_bitmap cogl_texture_type_get_type #ifndef COGL_DISABLE_DEPRECATED cogl_texture_unref #endif #ifdef COGL_HAS_GTYPE_SUPPORT cogl_texture_2d_get_gtype #endif cogl_texture_2d_new_from_bitmap cogl_texture_2d_new_from_data cogl_texture_2d_new_from_file cogl_texture_2d_new_with_size #ifdef COGL_HAS_GTYPE_SUPPORT cogl_texture_2d_sliced_get_gtype #endif cogl_texture_2d_sliced_new_from_bitmap cogl_texture_2d_sliced_new_from_data cogl_texture_2d_sliced_new_from_file cogl_texture_2d_sliced_new_with_size #ifdef COGL_HAS_GTYPE_SUPPORT cogl_texture_3d_get_gtype #endif cogl_texture_3d_new_from_bitmap cogl_texture_3d_new_from_data cogl_texture_3d_new_with_size cogl_transform cogl_translate cogl_vector3_add cogl_vector3_copy cogl_vector3_cross_product cogl_vector3_distance cogl_vector3_divide_scalar cogl_vector3_dot_product cogl_vector3_equal cogl_vector3_equal_with_epsilon cogl_vector3_free cogl_vector3_init cogl_vector3_init_zero cogl_vector3_invert cogl_vector3_magnitude cogl_vector3_multiply_scalar cogl_vector3_normalize cogl_vector3_subtract cogl_vertex_buffer_add cogl_vertex_buffer_delete cogl_vertex_buffer_disable cogl_vertex_buffer_draw cogl_vertex_buffer_draw_elements cogl_vertex_buffer_enable cogl_vertex_buffer_get_n_vertices cogl_vertex_buffer_indices_get_for_quads cogl_vertex_buffer_indices_get_type cogl_vertex_buffer_indices_new cogl_vertex_buffer_new #ifndef COGL_DISABLE_DEPRECATED cogl_vertex_buffer_ref #endif cogl_vertex_buffer_submit #ifndef COGL_DISABLE_DEPRECATED cogl_vertex_buffer_unref #endif cogl_vertices_mode_get_type #ifdef COGL_DISABLE_DEPRECATED cogl_viewport #endif cogl_winsys_feature_get_type #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT cogl_wayland_display_set_compositor_display cogl_wayland_onscreen_resize cogl_wayland_renderer_get_display cogl_wayland_renderer_set_event_dispatch_enabled cogl_wayland_renderer_set_foreign_display cogl_wayland_texture_set_region_from_shm_buffer cogl_wayland_texture_2d_new_from_buffer #endif cogl_winding_get_type #ifdef COGL_HAS_XLIB cogl_xlib_get_display cogl_xlib_handle_event cogl_xlib_renderer_add_filter cogl_xlib_renderer_get_display cogl_xlib_renderer_get_foreign_display cogl_xlib_renderer_get_visual_info cogl_xlib_renderer_handle_event cogl_xlib_renderer_remove_filter cogl_xlib_renderer_request_reset_on_video_memory_purge cogl_xlib_renderer_set_event_retrieval_enabled cogl_xlib_renderer_set_foreign_display cogl_xlib_set_display #endif #ifdef COGL_HAS_X11 cogl_x11_onscreen_get_visual_xid cogl_x11_onscreen_set_foreign_window_xid #endif #ifndef COGL_NO_EXPORT_UNDERSCORE /* probably these should not be exported at all, but anyways, for now... */ /* eventually, this section should disappear (or cogl, cogl-pango, clutter et al */ /* will link without the following) */ _cogl_atlas_add_reorganize_callback _cogl_atlas_new _cogl_atlas_reserve_space _cogl_atlas_texture_add_reorganize_callback _cogl_atlas_texture_remove_reorganize_callback _cogl_buffer_map_for_fill_or_fallback _cogl_buffer_unmap_for_fill_or_fallback _cogl_clip_stack_push_rectangle _cogl_clip_stack_push_primitive _cogl_context_get_default _cogl_debug_instances _cogl_framebuffer_get_modelview_stack _cogl_framebuffer_get_projection_stack _cogl_framebuffer_get_stencil_bits _cogl_object_default_unref _cogl_pipeline_foreach_layer_internal _cogl_pipeline_layer_get_texture _cogl_pipeline_prune_to_n_layers _cogl_primitive_draw _cogl_system_error_quark _cogl_texture_can_hardware_repeat _cogl_texture_get_format #endif cogl_fence_closure_get_user_data cogl_framebuffer_add_fence_callback cogl_framebuffer_cancel_fence_callback muffin-5.2.1/cogl/cogl/cogl-euler.h0000664000175000017500000002117114211404421017215 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_EULER_H #define __COGL_EULER_H #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-euler * @short_description: Functions for initializing and manipulating * euler angles. * * Euler angles are a simple representation of a 3 dimensional * rotation; comprised of 3 ordered heading, pitch and roll rotations. * An important thing to understand is that the axis of rotation * belong to the object being rotated and so they also rotate as each * of the heading, pitch and roll rotations are applied. * * One way to consider euler angles is to imagine controlling an * aeroplane, where you first choose a heading (Such as flying south * east), then you set the pitch (such as 30 degrees to take off) and * then you might set a roll, by dipping the left, wing as you prepare * to turn. * * They have some advantages and limitations that it helps to be * aware of: * * Advantages: * * * Easy to understand and use, compared to quaternions and matrices, * so may be a good choice for a user interface. * * * Efficient storage, needing only 3 components any rotation can be * represented. * Actually the #CoglEuler type isn't optimized for size because * we may cache the equivalent #CoglQuaternion along with a euler * rotation, but it would be trivial for an application to track the * components of euler rotations in a packed float array if optimizing * for size was important. The values could be passed to Cogl only when * manipulation is necessary. * * * * Disadvantages: * * * Aliasing: it's possible to represent some rotations with multiple * different heading, pitch and roll rotations. * * * They can suffer from a problem called Gimbal Lock. A good * explanation of this can be seen on wikipedia here: * http://en.wikipedia.org/wiki/Gimbal_lock but basically two * of the axis of rotation may become aligned and so you loose a * degree of freedom. For example a pitch of +-90° would mean that * heading and bank rotate around the same axis. * * * If you use euler angles to orient something in 3D space and try to * transition between orientations by interpolating the component * angles you probably wont get the transitions you expect as they may * not follow the shortest path between the two orientations. * * * There's no standard to what order the component axis rotations are * applied. The most common convention seems to be what we do in Cogl * with heading (y-axis), pitch (x-axis) and then roll (z-axis), but * other software might apply x-axis, y-axis then z-axis or any other * order so you need to consider this if you are accepting euler * rotations from some other software. Other software may also use * slightly different aeronautical terms, such as "yaw" instead of * "heading" or "bank" instead of "roll". * * * * To minimize the aliasing issue we may refer to "Canonical Euler" * angles where heading and roll are restricted to +- 180° and pitch is * restricted to +- 90°. If pitch is +- 90° bank is set to 0°. * * Quaternions don't suffer from Gimbal Lock and they can be nicely * interpolated between, their disadvantage is that they don't have an * intuitive representation. * * A common practice is to accept angles in the intuitive Euler form * and convert them to quaternions internally to avoid Gimbal Lock and * handle interpolations. See cogl_quaternion_init_from_euler(). */ /** * CoglEuler: * @heading: Angle to rotate around an object's y axis * @pitch: Angle to rotate around an object's x axis * @roll: Angle to rotate around an object's z axis * * Represents an ordered rotation first of @heading degrees around an * object's y axis, then @pitch degrees around an object's x axis and * finally @roll degrees around an object's z axis. * * It's important to understand the that axis are associated * with the object being rotated, so the axis also rotate in sequence * with the rotations being applied. * * The members of a #CoglEuler can be initialized, for example, with * cogl_euler_init() and cogl_euler_init_from_quaternion (). * * You may also want to look at cogl_quaternion_init_from_euler() if * you want to do interpolation between 3d rotations. * * Since: 2.0 */ struct _CoglEuler { /*< public > */ float heading; float pitch; float roll; /*< private > */ /* May cached a quaternion here in the future */ float padding0; float padding1; float padding2; float padding3; float padding4; }; COGL_STRUCT_SIZE_ASSERT (CoglEuler, 32); /** * cogl_euler_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_euler_get_gtype (void); /** * cogl_euler_init: * @euler: The #CoglEuler angle to initialize * @heading: Angle to rotate around an object's y axis * @pitch: Angle to rotate around an object's x axis * @roll: Angle to rotate around an object's z axis * * Initializes @euler to represent a rotation of @x_angle degrees * around the x axis, then @y_angle degrees around the y_axis and * @z_angle degrees around the z axis. * * Since: 2.0 */ void cogl_euler_init (CoglEuler *euler, float heading, float pitch, float roll); /** * cogl_euler_init_from_matrix: * @euler: The #CoglEuler angle to initialize * @matrix: A #CoglMatrix containing a rotation, but no scaling, * mirroring or skewing. * * Extracts a euler rotation from the given @matrix and * initializses @euler with the component x, y and z rotation angles. */ void cogl_euler_init_from_matrix (CoglEuler *euler, const CoglMatrix *matrix); /** * cogl_euler_init_from_quaternion: * @euler: The #CoglEuler angle to initialize * @quaternion: A #CoglEuler with the rotation to initialize with * * Initializes a @euler rotation with the equivalent rotation * represented by the given @quaternion. */ void cogl_euler_init_from_quaternion (CoglEuler *euler, const CoglQuaternion *quaternion); /** * cogl_euler_equal: * @v1: The first euler angle to compare * @v2: The second euler angle to compare * * Compares the two given euler angles @v1 and @v1 and it they are * equal returns %TRUE else %FALSE. * * This function only checks that all three components rotations * are numerically equal, it does not consider that some rotations * can be represented with different component rotations * * Returns: %TRUE if @v1 and @v2 are equal else %FALSE. * Since: 2.0 */ CoglBool cogl_euler_equal (const void *v1, const void *v2); /** * cogl_euler_copy: * @src: A #CoglEuler to copy * * Allocates a new #CoglEuler and initilizes it with the component * angles of @src. The newly allocated euler should be freed using * cogl_euler_free(). * * Returns: A newly allocated #CoglEuler * Since: 2.0 */ CoglEuler * cogl_euler_copy (const CoglEuler *src); /** * cogl_euler_free: * @euler: A #CoglEuler allocated via cogl_euler_copy() * * Frees a #CoglEuler that was previously allocated using * cogl_euler_copy(). * * Since: 2.0 */ void cogl_euler_free (CoglEuler *euler); COGL_END_DECLS #endif /* __COGL_EULER_H */ muffin-5.2.1/cogl/cogl/cogl-swap-chain-private.h0000664000175000017500000000263014211404421021602 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_SWAP_CHAIN_PRIVATE_H #define __COGL_SWAP_CHAIN_PRIVATE_H #include "cogl-object-private.h" struct _CoglSwapChain { CoglObject _parent; CoglBool has_alpha; int length; }; #endif /* __COGL_SWAP_CHAIN_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-util.h0000664000175000017500000001775314211404421017071 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_UTIL_H #define __COGL_UTIL_H #include #include #include #include "cogl-types.h" #include /* Double check that config.h has been included */ #if (!defined (PACKAGE_NAME) && \ !defined (_COGL_IN_TEST_BITMASK) && \ !defined(COGL_ENABLE_MUFFIN_API)) #error "cogl-config.h must be included before including cogl-util.h" #endif int _cogl_util_next_p2 (int a); /* The signbit macro is defined by ISO C99 so it should be available, however if it's not we can fallback to an evil hack */ #ifdef signbit #define cogl_util_float_signbit(x) signbit(x) #else /* This trick was stolen from here: http://lists.boost.org/Archives/boost/2006/08/108731.php It xors the integer reinterpretations of -1.0f and 1.0f. In theory they should only differ by the signbit so that gives a mask for the sign which we can just test against the value */ static inline CoglBool cogl_util_float_signbit (float x) { static const union { float f; uint32_t i; } negative_one = { -1.0f }; static const union { float f; uint32_t i; } positive_one = { +1.0f }; union { float f; uint32_t i; } value = { x }; return !!((negative_one.i ^ positive_one.i) & value.i); } #endif /* This is a replacement for the nearbyint function which always rounds to the nearest integer. nearbyint is apparently a C99 function so it might not always be available but also it seems in glibc it is defined as a function call so this macro could end up faster anyway. We can't just add 0.5f because it will break for negative numbers. */ #define COGL_UTIL_NEARBYINT(x) ((int) ((x) < 0.0f ? (x) - 0.5f : (x) + 0.5f)) /* Returns whether the given integer is a power of two */ static inline CoglBool _cogl_util_is_pot (unsigned int num) { /* Make sure there is only one bit set */ return (num & (num - 1)) == 0; } /* Split Bob Jenkins' One-at-a-Time hash * * This uses the One-at-a-Time hash algorithm designed by Bob Jenkins * but the mixing step is split out so the function can be used in a * more incremental fashion. */ static inline unsigned int _cogl_util_one_at_a_time_hash (unsigned int hash, const void *key, size_t bytes) { const unsigned char *p = key; size_t i; for (i = 0; i < bytes; i++) { hash += p[i]; hash += (hash << 10); hash ^= (hash >> 6); } return hash; } unsigned int _cogl_util_one_at_a_time_mix (unsigned int hash); /* These two builtins are available since GCC 3.4 */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) #define COGL_UTIL_HAVE_BUILTIN_FFSL #define COGL_UTIL_HAVE_BUILTIN_POPCOUNTL #define COGL_UTIL_HAVE_BUILTIN_CLZ #endif /* The 'ffs' function is part of C99 so it isn't always available */ #ifdef HAVE_FFS #define _cogl_util_ffs ffs #else int _cogl_util_ffs (int num); #endif /* The 'ffsl' function is non-standard but GCC has a builtin for it since 3.4 which we can use */ #ifdef COGL_UTIL_HAVE_BUILTIN_FFSL #define _cogl_util_ffsl __builtin_ffsl #else /* If ints and longs are the same size we can just use ffs. Hopefully the compiler will optimise away this conditional */ #define _cogl_util_ffsl(x) \ (sizeof (long int) == sizeof (int) ? _cogl_util_ffs ((int) x) : \ _cogl_util_ffsl_wrapper (x)) int _cogl_util_ffsl_wrapper (long int num); #endif /* COGL_UTIL_HAVE_BUILTIN_FFSL */ static inline unsigned int _cogl_util_fls (unsigned int n) { #ifdef COGL_UTIL_HAVE_BUILTIN_CLZ return n == 0 ? 0 : sizeof (unsigned int) * 8 - __builtin_clz (n); #else unsigned int v = 1; if (n == 0) return 0; while (n >>= 1) v++; return v; #endif } #ifdef COGL_UTIL_HAVE_BUILTIN_POPCOUNTL #define _cogl_util_popcountl __builtin_popcountl #else extern const unsigned char _cogl_util_popcount_table[256]; /* There are many ways of doing popcount but doing a table lookup seems to be the most robust against different sizes for long. Some pages seem to claim it's the fastest method anyway. */ static inline int _cogl_util_popcountl (unsigned long num) { int i; int sum = 0; /* Let's hope GCC will unroll this loop.. */ for (i = 0; i < sizeof (num); i++) sum += _cogl_util_popcount_table[(num >> (i * 8)) & 0xff]; return sum; } #endif /* COGL_UTIL_HAVE_BUILTIN_POPCOUNTL */ #define _COGL_RETURN_IF_FAIL(EXPR) g_return_if_fail(EXPR) #define _COGL_RETURN_VAL_IF_FAIL(EXPR, VAL) g_return_val_if_fail(EXPR, VAL) /* Match a CoglPixelFormat according to channel masks, color depth, * bits per pixel and byte order. These information are provided by * the Visual and XImage structures. * * If no specific pixel format could be found, COGL_PIXEL_FORMAT_ANY * is returned. */ CoglPixelFormat _cogl_util_pixel_format_from_masks (unsigned long r_mask, unsigned long g_mask, unsigned long b_mask, int depth, int bpp, int byte_order); /* Since we can't rely on _Static_assert always being available for * all compilers we have limited static assert that can be used in * C code but not in headers. */ #define _COGL_TYPEDEF_ASSERT(EXPRESSION) \ typedef struct { char Compile_Time_Assertion[(EXPRESSION) ? 1 : -1]; } \ G_PASTE (_GStaticAssert_, __LINE__) /* _COGL_STATIC_ASSERT: * @expression: An expression to assert evaluates to true at compile * time. * @message: A message to print to the console if the assertion fails * at compile time. * * Allows you to assert that an expression evaluates to true at * compile time and aborts compilation if not. If possible message * will also be printed if the assertion fails. * * Note: Only Gcc >= 4.6 supports the c11 _Static_assert which lets us * print a nice message if the compile time assertion fails. */ #ifdef HAVE_STATIC_ASSERT #define _COGL_STATIC_ASSERT(EXPRESSION, MESSAGE) \ _Static_assert (EXPRESSION, MESSAGE); #else #define _COGL_STATIC_ASSERT(EXPRESSION, MESSAGE) #endif #ifdef HAVE_MEMMEM #define _cogl_util_memmem memmem #else char * _cogl_util_memmem (const void *haystack, size_t haystack_len, const void *needle, size_t needle_len); #endif static inline void _cogl_util_scissor_intersect (int rect_x0, int rect_y0, int rect_x1, int rect_y1, int *scissor_x0, int *scissor_y0, int *scissor_x1, int *scissor_y1) { *scissor_x0 = MAX (*scissor_x0, rect_x0); *scissor_y0 = MAX (*scissor_y0, rect_y0); *scissor_x1 = MIN (*scissor_x1, rect_x1); *scissor_y1 = MIN (*scissor_y1, rect_y1); } #endif /* __COGL_UTIL_H */ muffin-5.2.1/cogl/cogl/cogl-pipeline-layer-state-private.h0000664000175000017500000001333614211404421023612 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_LAYER_STATE_PRIVATE_H #define __COGL_PIPELINE_LAYER_STATE_PRIVATE_H #include "cogl-pipeline-layer-state.h" #include "cogl-pipeline-private.h" CoglPipelineLayer * _cogl_pipeline_set_layer_unit (CoglPipeline *required_owner, CoglPipelineLayer *layer, int unit_index); CoglPipelineFilter _cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline, int layer_index); CoglPipelineFilter _cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline, int layer_index); CoglBool _cogl_pipeline_layer_texture_type_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1, CoglPipelineEvalFlags flags); CoglBool _cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1, CoglPipelineEvalFlags flags); CoglBool _cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); CoglBool _cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); CoglBool _cogl_pipeline_layer_sampler_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); CoglBool _cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); CoglBool _cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); CoglBool _cogl_pipeline_layer_vertex_snippets_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); CoglBool _cogl_pipeline_layer_fragment_snippets_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); void _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_texture_type_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_sampler_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_vertex_snippets_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); void _cogl_pipeline_layer_hash_fragment_snippets_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); #endif /* __COGL_PIPELINE_LAYER_STATE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-util.c0000664000175000017500000002103614211404421017051 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-util.h" #include "cogl-private.h" /* * cogl_util_next_p2: * @a: Value to get the next power of two * * Calculates the next power of two greater than or equal to @a. * * Return value: @a if @a is already a power of two, otherwise returns * the next nearest power of two. */ int _cogl_util_next_p2 (int a) { int rval = 1; while (rval < a) rval <<= 1; return rval; } unsigned int _cogl_util_one_at_a_time_mix (unsigned int hash) { hash += ( hash << 3 ); hash ^= ( hash >> 11 ); hash += ( hash << 15 ); return hash; } /* The 'ffs' function is part of C99 so it isn't always available */ #ifndef HAVE_FFS int _cogl_util_ffs (int num) { int i = 1; if (num == 0) return 0; while ((num & 1) == 0) { num >>= 1; i++; } return i; } #endif /* HAVE_FFS */ /* The 'ffsl' is non-standard but when building with GCC we'll use its builtin instead */ #ifndef COGL_UTIL_HAVE_BUILTIN_FFSL int _cogl_util_ffsl_wrapper (long int num) { int i = 1; if (num == 0) return 0; while ((num & 1) == 0) { num >>= 1; i++; } return i; } #endif /* COGL_UTIL_HAVE_BUILTIN_FFSL */ #ifndef COGL_UTIL_HAVE_BUILTIN_POPCOUNTL const unsigned char _cogl_util_popcount_table[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; #endif /* COGL_UTIL_HAVE_BUILTIN_POPCOUNTL */ /* tests/conform/test-bitmask.c tests some cogl internals and includes this * file directly but since these functions depend on other internal Cogl * symbols we hide them from test-bitmask.c * * XXX: maybe there's a better way for us to handle internal testing * to avoid needing hacks like this. */ #ifndef _COGL_IN_TEST_BITMASK /* Given a set of red, green and blue component masks, a depth and * bits per pixel this function tries to determine a corresponding * CoglPixelFormat. * * The depth is measured in bits not including padding for un-used * alpha. The bits per pixel (bpp) does include padding for un-used * alpha. * * This function firstly aims to match formats with RGB ordered * components and only considers alpha coming first, in the most * significant bits. If the function fails to match then it recurses * by either switching the r and b masks around to check for BGR * ordered formats or it recurses with the masks shifted to check for * formats where the alpha component is the least significant bits. */ static CoglPixelFormat _cogl_util_pixel_format_from_masks_real (unsigned long r_mask, unsigned long g_mask, unsigned long b_mask, int depth, int bpp, CoglBool check_bgr, CoglBool check_afirst, int recursion_depth) { CoglPixelFormat image_format; if (depth == 24 && bpp == 24 && r_mask == 0xff0000 && g_mask == 0xff00 && b_mask == 0xff) { return COGL_PIXEL_FORMAT_RGB_888; } else if ((depth == 24 || depth == 32) && bpp == 32 && r_mask == 0xff0000 && g_mask == 0xff00 && b_mask == 0xff) { return COGL_PIXEL_FORMAT_ARGB_8888_PRE; } else if ((depth == 30 || depth == 32) && r_mask == 0x3ff00000 && g_mask == 0xffc00 && b_mask == 0x3ff) { return COGL_PIXEL_FORMAT_ARGB_2101010_PRE; } else if (depth == 16 && bpp == 16 && r_mask == 0xf800 && g_mask == 0x7e0 && b_mask == 0x1f) { return COGL_PIXEL_FORMAT_RGB_565; } if (recursion_depth == 2) return 0; /* Check for BGR ordering if we didn't find a match */ if (check_bgr) { image_format = _cogl_util_pixel_format_from_masks_real (b_mask, g_mask, r_mask, depth, bpp, FALSE, TRUE, recursion_depth + 1); if (image_format) return image_format ^ COGL_BGR_BIT; } /* Check for alpha in the least significant bits if we still * haven't found a match... */ if (check_afirst && depth != bpp) { int shift = bpp - depth; image_format = _cogl_util_pixel_format_from_masks_real (r_mask >> shift, g_mask >> shift, b_mask >> shift, depth, bpp, TRUE, FALSE, recursion_depth + 1); if (image_format) return image_format ^ COGL_AFIRST_BIT; } return 0; } CoglPixelFormat _cogl_util_pixel_format_from_masks (unsigned long r_mask, unsigned long g_mask, unsigned long b_mask, int depth, int bpp, CoglBool byte_order_is_lsb_first) { CoglPixelFormat image_format = _cogl_util_pixel_format_from_masks_real (r_mask, g_mask, b_mask, depth, bpp, TRUE, TRUE, 0); if (!image_format) { const char *byte_order[] = { "MSB first", "LSB first" }; g_warning ("Could not find a matching pixel format for red mask=0x%lx," "green mask=0x%lx, blue mask=0x%lx at depth=%d, bpp=%d " "and byte order=%s\n", r_mask, g_mask, b_mask, depth, bpp, byte_order[!!byte_order_is_lsb_first]); return 0; } /* If the image is in little-endian then the order in memory is reversed */ if (byte_order_is_lsb_first && _cogl_pixel_format_is_endian_dependant (image_format)) { image_format ^= COGL_BGR_BIT; if (image_format & COGL_A_BIT) image_format ^= COGL_AFIRST_BIT; } return image_format; } #ifndef HAVE_MEMMEM char * _cogl_util_memmem (const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) { size_t i; if (needle_len > haystack_len) return NULL; for (i = 0; i <= haystack_len - needle_len; i++) if (!memcmp ((const char *) haystack + i, needle, needle_len)) return (char *) haystack + i; return NULL; } #endif /* HAVE_MEMMEM */ #endif /* _COGL_IN_TEST_BITMASK */ muffin-5.2.1/cogl/cogl/cogl-error.c0000664000175000017500000000635514211404421017234 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-types.h" #include "cogl-util.h" #include "cogl-error-private.h" #include void cogl_error_free (CoglError *error) { g_error_free ((GError *)error); } CoglError * cogl_error_copy (CoglError *error) { return (CoglError *)g_error_copy ((GError *)error); } CoglBool cogl_error_matches (CoglError *error, uint32_t domain, int code) { return g_error_matches ((GError *)error, domain, code); } #define ERROR_OVERWRITTEN_WARNING \ "CoglError set over the top of a previous CoglError or " \ "uninitialized memory.\nThis indicates a bug in someone's " \ "code. You must ensure an error is NULL before it's set.\n" \ "The overwriting error message was: %s" void _cogl_set_error (CoglError **error, uint32_t domain, int code, const char *format, ...) { GError *new; va_list args; va_start (args, format); if (error == NULL) { g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args); va_end (args); return; } new = g_error_new_valist (domain, code, format, args); va_end (args); if (*error == NULL) *error = (CoglError *)new; else g_warning (ERROR_OVERWRITTEN_WARNING, new->message); } void _cogl_set_error_literal (CoglError **error, uint32_t domain, int code, const char *message) { _cogl_set_error (error, domain, code, "%s", message); } void _cogl_propagate_error (CoglError **dest, CoglError *src) { _COGL_RETURN_IF_FAIL (src != NULL); if (dest == NULL) { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "%s", src->message); cogl_error_free (src); } else if (*dest) g_warning (ERROR_OVERWRITTEN_WARNING, src->message); else *dest = src; } void _cogl_propagate_gerror (CoglError **dest, GError *src) { _cogl_propagate_error (dest, (CoglError *) src); } muffin-5.2.1/cogl/cogl/cogl-texture-2d-private.h0000664000175000017500000001005014211404421021546 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_TEXTURE_2D_PRIVATE_H #define __COGL_TEXTURE_2D_PRIVATE_H #include "cogl-object-private.h" #include "cogl-pipeline-private.h" #include "cogl-texture-private.h" #include "cogl-texture-2d.h" struct _CoglTexture2D { CoglTexture _parent; /* The internal format of the GL texture represented as a CoglPixelFormat */ CoglPixelFormat internal_format; CoglBool auto_mipmap; CoglBool mipmaps_dirty; CoglBool is_foreign; /* TODO: factor out these OpenGL specific members into some form * of driver private state. */ /* The internal format of the GL texture represented as a GL enum */ GLenum gl_internal_format; /* The texture object number */ GLuint gl_texture; GLenum gl_target; GLenum gl_legacy_texobj_min_filter; GLenum gl_legacy_texobj_mag_filter; GLint gl_legacy_texobj_wrap_mode_s; GLint gl_legacy_texobj_wrap_mode_t; CoglTexturePixel first_pixel; struct { void *user_data; GDestroyNotify destroy; } egl_image_external; }; CoglTexture2D * _cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp, CoglBool can_convert_in_place); CoglTexture2D * _cogl_texture_2d_create_base (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format, CoglTextureLoader *loader); void _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, CoglBool value); /* * _cogl_texture_2d_externally_modified: * @texture: A #CoglTexture2D object * * This should be called whenever the texture is modified other than * by using cogl_texture_set_region. It will cause the mipmaps to be * invalidated */ void _cogl_texture_2d_externally_modified (CoglTexture *texture); /* * _cogl_texture_2d_copy_from_framebuffer: * @texture: A #CoglTexture2D pointer * @src_x: X-position to within the framebuffer to read from * @src_y: Y-position to within the framebuffer to read from * @width: width of the rectangle to copy * @height: height of the rectangle to copy * @src_fb: A source #CoglFramebuffer to copy from * @dst_x: X-position to store the image within the texture * @dst_y: Y-position to store the image within the texture * @level: The mipmap level of @texture to copy too * * This copies a portion of the given @src_fb into the * texture. */ void _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *texture, int src_x, int src_y, int width, int height, CoglFramebuffer *src_fb, int dst_x, int dst_y, int level); #endif /* __COGL_TEXTURE_2D_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl1-context.h0000664000175000017500000006700014211404421017647 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_1_CONTEXT_H__ #define __COGL_1_CONTEXT_H__ #include #include #include #include COGL_BEGIN_DECLS /** * cogl_get_option_group: * * Retrieves the #GOptionGroup used by Cogl to parse the command * line options. Clutter uses this to handle the Cogl command line * options during its initialization process. * * Return value: a #GOptionGroup * * Since: 1.0 * Deprecated: 1.16: Not replaced */ COGL_DEPRECATED_IN_1_16 GOptionGroup * cogl_get_option_group (void); /* Misc */ /** * cogl_get_features: * * Returns all of the features supported by COGL. * * Return value: A logical OR of all the supported COGL features. * * Since: 0.8 * Deprecated: 1.10: Use cogl_foreach_feature() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_foreach_feature) CoglFeatureFlags cogl_get_features (void); /** * cogl_features_available: * @features: A bitmask of features to check for * * Checks whether the given COGL features are available. Multiple * features can be checked for by or-ing them together with the '|' * operator. %TRUE is only returned if all of the requested features * are available. * * Return value: %TRUE if the features are available, %FALSE otherwise. * Deprecated: 1.10: Use cogl_has_feature() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_has_feature) CoglBool cogl_features_available (CoglFeatureFlags features); /** * cogl_get_proc_address: (skip) * @name: the name of the function. * * Gets a pointer to a given GL or GL ES extension function. This acts * as a wrapper around glXGetProcAddress() or whatever is the * appropriate function for the current backend. * * This function should not be used to query core opengl API * symbols since eglGetProcAddress for example doesn't allow this and * and may return a junk pointer if you do. * * Return value: a pointer to the requested function or %NULL if the * function is not available. */ CoglFuncPtr cogl_get_proc_address (const char *name); /** * cogl_check_extension: * @name: extension to check for * @ext: list of extensions * * Check whether @name occurs in list of extensions in @ext. * * Return value: %TRUE if the extension occurs in the list, %FALSE otherwise. * * Deprecated: 1.2: OpenGL is an implementation detail for Cogl and so it's * not appropriate to expose OpenGL extensions through the Cogl API. This * function can be replaced by the following equivalent code: * |[ * CoglBool retval = (strstr (ext, name) != NULL) ? TRUE : FALSE; * ]| */ COGL_DEPRECATED CoglBool cogl_check_extension (const char *name, const char *ext); /** * cogl_get_bitmasks: * @red: (out): Return location for the number of red bits or %NULL * @green: (out): Return location for the number of green bits or %NULL * @blue: (out): Return location for the number of blue bits or %NULL * @alpha: (out): Return location for the number of alpha bits or %NULL * * Gets the number of bitplanes used for each of the color components * in the color buffer. Pass %NULL for any of the arguments if the * value is not required. * * Deprecated: 1.8: Use cogl_framebuffer_get_red/green/blue/alpha_bits() * instead */ COGL_DEPRECATED_IN_1_8_FOR (cogl_framebuffer_get_red_OR_green_OR_blue_OR_alpha_bits) void cogl_get_bitmasks (int *red, int *green, int *blue, int *alpha); /** * cogl_perspective: * @fovy: Vertical field of view angle in degrees. * @aspect: The (width over height) aspect ratio for display * @z_near: The distance to the near clipping plane (Must be positive) * @z_far: The distance to the far clipping plane (Must be positive) * * Replaces the current projection matrix with a perspective matrix * based on the provided values. * * You should be careful not to have to great a @z_far / @z_near * ratio since that will reduce the effectiveness of depth testing * since there wont be enough precision to identify the depth of * objects near to each other. * * Deprecated: 1.10: Use cogl_framebuffer_perspective() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_perspective) void cogl_perspective (float fovy, float aspect, float z_near, float z_far); /** * cogl_frustum: * @left: X position of the left clipping plane where it * intersects the near clipping plane * @right: X position of the right clipping plane where it * intersects the near clipping plane * @bottom: Y position of the bottom clipping plane where it * intersects the near clipping plane * @top: Y position of the top clipping plane where it intersects * the near clipping plane * @z_near: The distance to the near clipping plane (Must be positive) * @z_far: The distance to the far clipping plane (Must be positive) * * Replaces the current projection matrix with a perspective matrix * for a given viewing frustum defined by 4 side clip planes that * all cross through the origin and 2 near and far clip planes. * * Since: 0.8.2 * Deprecated: 1.10: Use cogl_framebuffer_frustum() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_frustum) void cogl_frustum (float left, float right, float bottom, float top, float z_near, float z_far); /** * cogl_ortho: * @left: The coordinate for the left clipping plane * @right: The coordinate for the right clipping plane * @bottom: The coordinate for the bottom clipping plane * @top: The coordinate for the top clipping plane * @near: The distance to the near clipping * plane (negative if the plane is behind the viewer) * @far: The distance for the far clipping * plane (negative if the plane is behind the viewer) * * Replaces the current projection matrix with an orthographic projection * matrix. See to see how the matrix is * calculated. * *
* * *
* * This function copies the arguments from OpenGL's glOrtho() even * though they are unnecessarily confusing due to the z near and z far * arguments actually being a "distance" from the origin, where * negative values are behind the viewer, instead of coordinates for * the z clipping planes which would have been consistent with the * left, right bottom and top arguments. * * Since: 1.0 * Deprecated: 1.10: Use cogl_framebuffer_orthographic() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_orthographic) void cogl_ortho (float left, float right, float bottom, float top, float near, float far); /** * cogl_viewport: * @width: Width of the viewport * @height: Height of the viewport * * Replace the current viewport with the given values. * * Since: 0.8.2 * Deprecated: 1.8: Use cogl_framebuffer_set_viewport instead */ COGL_DEPRECATED_IN_1_8_FOR (cogl_framebuffer_set_viewport) void cogl_viewport (unsigned int width, unsigned int height); /** * cogl_set_viewport: * @x: X offset of the viewport * @y: Y offset of the viewport * @width: Width of the viewport * @height: Height of the viewport * * Replaces the current viewport with the given values. * * Since: 1.2 * Deprecated: 1.8: Use cogl_framebuffer_set_viewport() instead */ COGL_DEPRECATED_IN_1_8_FOR (cogl_framebuffer_set_viewport) void cogl_set_viewport (int x, int y, int width, int height); /** * cogl_push_matrix: * * Stores the current model-view matrix on the matrix stack. The matrix * can later be restored with cogl_pop_matrix(). * * Deprecated: 1.10: Use cogl_framebuffer_push_matrix() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_push_matrix) void cogl_push_matrix (void); /** * cogl_pop_matrix: * * Restores the current model-view matrix from the matrix stack. * * Deprecated: 1.10: Use cogl_framebuffer_pop_matrix() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_push_matrix) void cogl_pop_matrix (void); /** * cogl_scale: * @x: Amount to scale along the x-axis * @y: Amount to scale along the y-axis * @z: Amount to scale along the z-axis * * Multiplies the current model-view matrix by one that scales the x, * y and z axes by the given values. * * Deprecated: 1.10: Use cogl_framebuffer_pop_matrix() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_scale) void cogl_scale (float x, float y, float z); /** * cogl_translate: * @x: Distance to translate along the x-axis * @y: Distance to translate along the y-axis * @z: Distance to translate along the z-axis * * Multiplies the current model-view matrix by one that translates the * model along all three axes according to the given values. * * Deprecated: 1.10: Use cogl_framebuffer_translate() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_translate) void cogl_translate (float x, float y, float z); /** * cogl_rotate: * @angle: Angle in degrees to rotate. * @x: X-component of vertex to rotate around. * @y: Y-component of vertex to rotate around. * @z: Z-component of vertex to rotate around. * * Multiplies the current model-view matrix by one that rotates the * model around the vertex specified by @x, @y and @z. The rotation * follows the right-hand thumb rule so for example rotating by 10 * degrees about the vertex (0, 0, 1) causes a small counter-clockwise * rotation. * * Deprecated: 1.10: Use cogl_framebuffer_rotate() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_rotate) void cogl_rotate (float angle, float x, float y, float z); /** * cogl_transform: * @matrix: the matrix to multiply with the current model-view * * Multiplies the current model-view matrix by the given matrix. * * Since: 1.4 * Deprecated: 1.10: Use cogl_framebuffer_transform() instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_transform) void cogl_transform (const CoglMatrix *matrix); /** * cogl_get_modelview_matrix: * @matrix: (out): return location for the model-view matrix * * Stores the current model-view matrix in @matrix. * * Deprecated: 1.10: Use cogl_framebuffer_get_modelview_matrix() * instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_get_modelview_matrix) void cogl_get_modelview_matrix (CoglMatrix *matrix); /** * cogl_set_modelview_matrix: * @matrix: the new model-view matrix * * Loads @matrix as the new model-view matrix. * * Deprecated: 1.10: Use cogl_framebuffer_set_modelview_matrix() * instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_set_modelview_matrix) void cogl_set_modelview_matrix (CoglMatrix *matrix); /** * cogl_get_projection_matrix: * @matrix: (out): return location for the projection matrix * * Stores the current projection matrix in @matrix. * * Deprecated: 1.10: Use cogl_framebuffer_get_projection_matrix() * instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_get_projection_matrix) void cogl_get_projection_matrix (CoglMatrix *matrix); /** * cogl_set_projection_matrix: * @matrix: the new projection matrix * * Loads matrix as the new projection matrix. * * Deprecated: 1.10: Use cogl_framebuffer_set_projection_matrix() * instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_set_projection_matrix) void cogl_set_projection_matrix (CoglMatrix *matrix); /** * cogl_get_viewport: * @v: (out) (array fixed-size=4): pointer to a 4 element array * of #floats to receive the viewport dimensions. * * Stores the current viewport in @v. @v[0] and @v[1] get the x and y * position of the viewport and @v[2] and @v[3] get the width and * height. * * Deprecated: 1.10: Use cogl_framebuffer_get_viewport4fv() * instead */ COGL_DEPRECATED_IN_1_10_FOR (cogl_framebuffer_get_viewport4fv) void cogl_get_viewport (float v[4]); /** * cogl_set_depth_test_enabled: * @setting: %TRUE to enable depth testing or %FALSE to disable. * * Sets whether depth testing is enabled. If it is disabled then the * order that actors are layered on the screen depends solely on the * order specified using clutter_actor_raise() and * clutter_actor_lower(), otherwise it will also take into account the * actor's depth. Depth testing is disabled by default. * * Deprecated: 1.16: Use cogl_pipeline_set_depth_state() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_depth_state) void cogl_set_depth_test_enabled (CoglBool setting); /** * cogl_get_depth_test_enabled: * * Queries if depth testing has been enabled via cogl_set_depth_test_enable() * * Return value: %TRUE if depth testing is enabled, and %FALSE otherwise * * Deprecated: 1.16: Use cogl_pipeline_set_depth_state() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_depth_state) CoglBool cogl_get_depth_test_enabled (void); /** * cogl_set_backface_culling_enabled: * @setting: %TRUE to enable backface culling or %FALSE to disable. * * Sets whether textures positioned so that their backface is showing * should be hidden. This can be used to efficiently draw two-sided * textures or fully closed cubes without enabling depth testing. This * only affects calls to the cogl_rectangle* family of functions and * cogl_vertex_buffer_draw*. Backface culling is disabled by default. * * Deprecated: 1.16: Use cogl_pipeline_set_cull_face_mode() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_cull_face_mode) void cogl_set_backface_culling_enabled (CoglBool setting); /** * cogl_get_backface_culling_enabled: * * Queries if backface culling has been enabled via * cogl_set_backface_culling_enabled() * * Return value: %TRUE if backface culling is enabled, and %FALSE otherwise * * Deprecated: 1.16: Use cogl_pipeline_get_cull_face_mode() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_cull_face_mode) CoglBool cogl_get_backface_culling_enabled (void); /** * cogl_set_fog: * @fog_color: The color of the fog * @mode: A #CoglFogMode that determines the equation used to calculate the * fogging blend factor. * @density: Used by %COGL_FOG_MODE_EXPONENTIAL and by * %COGL_FOG_MODE_EXPONENTIAL_SQUARED equations. * @z_near: Position along Z axis where no fogging should be applied * @z_far: Position along Z axis where full fogging should be applied * * Enables fogging. Fogging causes vertices that are further away from the eye * to be rendered with a different color. The color is determined according to * the chosen fog mode; at it's simplest the color is linearly interpolated so * that vertices at @z_near are drawn fully with their original color and * vertices at @z_far are drawn fully with @fog_color. Fogging will remain * enabled until you call cogl_disable_fog(). * * The fogging functions only work correctly when primitives use * unmultiplied alpha colors. By default Cogl will premultiply textures * and cogl_set_source_color() will premultiply colors, so unless you * explicitly load your textures requesting an unmultiplied internal format * and use cogl_material_set_color() you can only use fogging with fully * opaque primitives. This might improve in the future when we can depend * on fragment shaders. * * Deprecated: 1.16: Use #CoglSnippet shader api for fog */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_API) void cogl_set_fog (const CoglColor *fog_color, CoglFogMode mode, float density, float z_near, float z_far); /** * cogl_disable_fog: * * This function disables fogging, so primitives drawn afterwards will not be * blended with any previously set fog color. * * Deprecated: 1.16: Use #CoglSnippet shader api for fog */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_API) void cogl_disable_fog (void); /** * cogl_clear: * @color: Background color to clear to * @buffers: A mask of #CoglBufferBit's identifying which auxiliary * buffers to clear * * Clears all the auxiliary buffers identified in the @buffers mask, and if * that includes the color buffer then the specified @color is used. * * Deprecated: 1.16: Use cogl_framebuffer_clear() api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_framebuffer_clear) void cogl_clear (const CoglColor *color, unsigned long buffers); /** * cogl_set_source: * @material: A #CoglMaterial * * This function changes the material at the top of the source stack. * The material at the top of this stack defines the GPU state used to * process subsequent primitives, such as rectangles drawn with * cogl_rectangle() or vertices drawn using cogl_vertex_buffer_draw(). * * Since: 1.0 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void cogl_set_source (void *material); /** * cogl_get_source: * * Returns the current source material as previously set using * cogl_set_source(). * * You should typically consider the returned material immutable * and not try to change any of its properties unless you own a * reference to that material. At times you may be able to get a * reference to an internally managed materials and the result of * modifying such materials is undefined. * * Return value: The current source material. * * Since: 1.6 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void * cogl_get_source (void); /** * cogl_push_source: * @material: A #CoglMaterial * * Pushes the given @material to the top of the source stack. The * material at the top of this stack defines the GPU state used to * process later primitives as defined by cogl_set_source(). * * Since: 1.6 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void cogl_push_source (void *material); /** * cogl_pop_source: * * Removes the material at the top of the source stack. The material * at the top of this stack defines the GPU state used to process * later primitives as defined by cogl_set_source(). * * Since: 1.6 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void cogl_pop_source (void); /** * cogl_set_source_color: * @color: a #CoglColor * * This is a convenience function for creating a solid fill source material * from the given color. This color will be used for any subsequent drawing * operation. * * The color will be premultiplied by Cogl, so the color should be * non-premultiplied. For example: use (1.0, 0.0, 0.0, 0.5) for * semi-transparent red. * * See also cogl_set_source_color4ub() and cogl_set_source_color4f() * if you already have the color components. * * Since: 1.0 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void cogl_set_source_color (const CoglColor *color); /** * cogl_set_source_color4ub: * @red: value of the red channel, between 0 and 255 * @green: value of the green channel, between 0 and 255 * @blue: value of the blue channel, between 0 and 255 * @alpha: value of the alpha channel, between 0 and 255 * * This is a convenience function for creating a solid fill source material * from the given color using unsigned bytes for each component. This * color will be used for any subsequent drawing operation. * * The value for each component is an unsigned byte in the range * between 0 and 255. * * Since: 1.0 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void cogl_set_source_color4ub (uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); /** * cogl_set_source_color4f: * @red: value of the red channel, between 0 and %1.0 * @green: value of the green channel, between 0 and %1.0 * @blue: value of the blue channel, between 0 and %1.0 * @alpha: value of the alpha channel, between 0 and %1.0 * * This is a convenience function for creating a solid fill source material * from the given color using normalized values for each component. This color * will be used for any subsequent drawing operation. * * The value for each component is a fixed point number in the range * between 0 and %1.0. If the values passed in are outside that * range, they will be clamped. * * Since: 1.0 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void cogl_set_source_color4f (float red, float green, float blue, float alpha); /** * cogl_set_source_texture: * @texture: The #CoglTexture you want as your source * * This is a convenience function for creating a material with the first * layer set to @texture and setting that material as the source with * cogl_set_source. * * Note: There is no interaction between calls to cogl_set_source_color * and cogl_set_source_texture. If you need to blend a texture with a color then * you can create a simple material like this: * * material = cogl_material_new (); * cogl_material_set_color4ub (material, 0xff, 0x00, 0x00, 0x80); * cogl_material_set_layer (material, 0, tex_handle); * cogl_set_source (material); * * * Since: 1.0 * Deprecated: 1.16: Latest drawing apis all take an explicit * #CoglPipeline argument so this stack of * #CoglMaterials shouldn't be used. */ COGL_DEPRECATED_IN_1_16 void cogl_set_source_texture (CoglTexture *texture); /** * cogl_flush: * * This function should only need to be called in exceptional circumstances. * * As an optimization Cogl drawing functions may batch up primitives * internally, so if you are trying to use raw GL outside of Cogl you stand a * better chance of being successful if you ask Cogl to flush any batched * geometry before making your state changes. * * It only ensure that the underlying driver is issued all the commands * necessary to draw the batched primitives. It provides no guarantees about * when the driver will complete the rendering. * * This provides no guarantees about the GL state upon returning and to avoid * confusing Cogl you should aim to restore any changes you make before * resuming use of Cogl. * * If you are making state changes with the intention of affecting Cogl drawing * primitives you are 100% on your own since you stand a good chance of * conflicting with Cogl internals. For example clutter-gst which currently * uses direct GL calls to bind ARBfp programs will very likely break when Cogl * starts to use ARBfb programs itself for the material API. * * Since: 1.0 */ void cogl_flush (void); /** * cogl_begin_gl: * * We do not advise nor reliably support the interleaving of raw GL drawing and * Cogl drawing functions, but if you insist, cogl_begin_gl() and cogl_end_gl() * provide a simple mechanism that may at least give you a fighting chance of * succeeding. * * Note: this doesn't help you modify the behaviour of Cogl drawing functions * through the modification of GL state; that will never be reliably supported, * but if you are trying to do something like: * * |[ * { * - setup some OpenGL state. * - draw using OpenGL (e.g. glDrawArrays() ) * - reset modified OpenGL state. * - continue using Cogl to draw * } * ]| * * You should surround blocks of drawing using raw GL with cogl_begin_gl() * and cogl_end_gl(): * * |[ * { * cogl_begin_gl (); * - setup some OpenGL state. * - draw using OpenGL (e.g. glDrawArrays() ) * - reset modified OpenGL state. * cogl_end_gl (); * - continue using Cogl to draw * } * ]| * * Don't ever try and do: * * |[ * { * - setup some OpenGL state. * - use Cogl to draw * - reset modified OpenGL state. * } * ]| * * When the internals of Cogl evolves, this is very liable to break. * * This function will flush all batched primitives, and subsequently flush * all internal Cogl state to OpenGL as if it were going to draw something * itself. * * The result is that the OpenGL modelview matrix will be setup; the state * corresponding to the current source material will be set up and other world * state such as backface culling, depth and fogging enabledness will be sent * to OpenGL. * * No special material state is flushed, so if you want Cogl to setup a * simplified material state it is your responsibility to set a simple source * material before calling cogl_begin_gl(). E.g. by calling * cogl_set_source_color4ub(). * * It is your responsibility to restore any OpenGL state that you modify * to how it was after calling cogl_begin_gl() if you don't do this then the * result of further Cogl calls is undefined. * * You can not nest begin/end blocks. * * Again we would like to stress, we do not advise the use of this API and if * possible we would prefer to improve Cogl than have developers require raw * OpenGL. * * Since: 1.0 * Deprecated: 1.16: Use the #CoglGLES2Context api instead */ COGL_DEPRECATED_IN_1_16_FOR (CoglGLES2Context_API) void cogl_begin_gl (void); /** * cogl_end_gl: * * This is the counterpart to cogl_begin_gl() used to delimit blocks of drawing * code using raw OpenGL. Please refer to cogl_begin_gl() for full details. * * Since: 1.0 * Deprecated: 1.16: Use the #CoglGLES2Context api instead */ COGL_DEPRECATED_IN_1_16_FOR (CoglGLES2Context_API) void cogl_end_gl (void); COGL_END_DECLS #endif /* __COGL_1_CONTEXT_H__ */ muffin-5.2.1/cogl/cogl/cogl-texture-2d-sliced-private.h0000664000175000017500000000454614211404421023024 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_TEXTURE_2D_SLICED_PRIVATE_H #define __COGL_TEXTURE_2D_SLICED_PRIVATE_H #include "cogl-bitmap-private.h" #include "cogl-pipeline-private.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-sliced.h" #include struct _CoglTexture2DSliced { CoglTexture _parent; GArray *slice_x_spans; GArray *slice_y_spans; GArray *slice_textures; int max_waste; CoglPixelFormat internal_format; }; CoglTexture2DSliced * _cogl_texture_2d_sliced_new_from_foreign (CoglContext *context, unsigned int gl_handle, unsigned int gl_target, int width, int height, int x_pot_waste, int y_pot_waste, CoglPixelFormat format); CoglTexture2DSliced * _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, int max_waste, CoglBool can_convert_in_place); #endif /* __COGL_TEXTURE_2D_SLICED_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-attribute-buffer.h0000664000175000017500000001124514211404421021354 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_ATTRIBUTE_BUFFER_H__ #define __COGL_ATTRIBUTE_BUFFER_H__ /* We forward declare the CoglAttributeBuffer type here to avoid some circular * dependency issues with the following headers. */ typedef struct _CoglAttributeBuffer CoglAttributeBuffer; #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-attribute-buffer * @short_description: Functions for creating and manipulating attribute * buffers * * FIXME */ #define COGL_ATTRIBUTE_BUFFER(buffer) ((CoglAttributeBuffer *)(buffer)) /** * cogl_attribute_buffer_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_attribute_buffer_get_gtype (void); /** * cogl_attribute_buffer_new_with_size: * @context: A #CoglContext * @bytes: The number of bytes to allocate for vertex attribute data. * * Describes a new #CoglAttributeBuffer of @size bytes to contain * arrays of vertex attribute data. Afterwards data can be set using * cogl_buffer_set_data() or by mapping it into the application's * address space using cogl_buffer_map(). * * The underlying storage of this buffer isn't allocated by this * function so that you have an opportunity to use the * cogl_buffer_set_update_hint() and cogl_buffer_set_usage_hint() * functions which may influence how the storage is allocated. The * storage will be allocated once you upload data to the buffer. * * Note: You can assume this function always succeeds and won't return * %NULL * * Return value: (transfer full): A newly allocated #CoglAttributeBuffer. Never %NULL. * * Stability: Unstable */ CoglAttributeBuffer * cogl_attribute_buffer_new_with_size (CoglContext *context, size_t bytes); /** * cogl_attribute_buffer_new: * @context: A #CoglContext * @bytes: The number of bytes to allocate for vertex attribute data. * @data: (array length=bytes): An optional pointer to vertex data to * upload immediately. * * Describes a new #CoglAttributeBuffer of @size bytes to contain * arrays of vertex attribute data and also uploads @size bytes read * from @data to the new buffer. * * You should never pass a %NULL data pointer. * * This function does not report out-of-memory errors back to * the caller by returning %NULL and so you can assume this function * always succeeds. * * In the unlikely case that there is an out of memory problem * then Cogl will abort the application with a message. If your * application needs to gracefully handle out-of-memory errors then * you can use cogl_attribute_buffer_new_with_size() and then * explicitly catch errors with cogl_buffer_set_data() or * cogl_buffer_map(). * * Return value: (transfer full): A newly allocated #CoglAttributeBuffer (never %NULL) * * Since: 1.4 * Stability: Unstable */ CoglAttributeBuffer * cogl_attribute_buffer_new (CoglContext *context, size_t bytes, const void *data); /** * cogl_is_attribute_buffer: * @object: A #CoglObject * * Gets whether the given object references a #CoglAttributeBuffer. * * Returns: %TRUE if @object references a #CoglAttributeBuffer, * %FALSE otherwise * * Since: 1.4 * Stability: Unstable */ CoglBool cogl_is_attribute_buffer (void *object); COGL_END_DECLS #endif /* __COGL_ATTRIBUTE_BUFFER_H__ */ muffin-5.2.1/cogl/cogl/cogl-onscreen.c0000664000175000017500000005365314211404421017722 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011, 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-onscreen-private.h" #include "cogl-frame-info-private.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-template-private.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl1-context.h" #include "cogl-closure-list-private.h" #include "cogl-poll-private.h" #include "cogl-gtype-private.h" #ifdef COGL_HAS_X11_SUPPORT #include "cogl-xlib-renderer.h" #endif static void _cogl_onscreen_free (CoglOnscreen *onscreen); COGL_OBJECT_DEFINE_WITH_CODE_GTYPE (Onscreen, onscreen, _cogl_onscreen_class.virt_unref = _cogl_framebuffer_unref); COGL_GTYPE_DEFINE_CLASS (Onscreen, onscreen, COGL_GTYPE_IMPLEMENT_INTERFACE (framebuffer)); static gpointer cogl_dummy_copy (gpointer data) { return data; } static void cogl_dummy_free (gpointer data) { } COGL_GTYPE_DEFINE_BOXED (FrameClosure, frame_closure, cogl_dummy_copy, cogl_dummy_free); COGL_GTYPE_DEFINE_BOXED (OnscreenResizeClosure, onscreen_resize_closure, cogl_dummy_copy, cogl_dummy_free); COGL_GTYPE_DEFINE_BOXED (OnscreenDirtyClosure, onscreen_dirty_closure, cogl_dummy_copy, cogl_dummy_free); static void _cogl_onscreen_init_from_template (CoglOnscreen *onscreen, CoglOnscreenTemplate *onscreen_template) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); _cogl_list_init (&onscreen->frame_closures); _cogl_list_init (&onscreen->resize_closures); _cogl_list_init (&onscreen->dirty_closures); framebuffer->config = onscreen_template->config; cogl_object_ref (framebuffer->config.swap_chain); } /* XXX: While we still have backend in Clutter we need a dummy object * to represent the CoglOnscreen framebuffer that the backend * creates... */ CoglOnscreen * _cogl_onscreen_new (void) { CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1); _COGL_GET_CONTEXT (ctx, NULL); _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen), ctx, COGL_FRAMEBUFFER_TYPE_ONSCREEN, 0x1eadbeef, /* width */ 0x1eadbeef); /* height */ /* NB: make sure to pass positive width/height numbers here * because otherwise we'll hit input validation assertions!*/ _cogl_onscreen_init_from_template (onscreen, ctx->display->onscreen_template); COGL_FRAMEBUFFER (onscreen)->allocated = TRUE; /* XXX: Note we don't initialize onscreen->winsys in this case. */ return _cogl_onscreen_object_new (onscreen); } CoglOnscreen * cogl_onscreen_new (CoglContext *ctx, int width, int height) { CoglOnscreen *onscreen; /* FIXME: We are assuming onscreen buffers will always be premultiplied so we'll set the premult flag on the bitmap format. This will usually be correct because the result of the default blending operations for Cogl ends up with premultiplied data in the framebuffer. However it is possible for the framebuffer to be in whatever format depending on what CoglPipeline is used to render to it. Eventually we may want to add a way for an application to inform Cogl that the framebuffer is not premultiplied in case it is being used for some special purpose. */ onscreen = g_new0 (CoglOnscreen, 1); _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen), ctx, COGL_FRAMEBUFFER_TYPE_ONSCREEN, width, /* width */ height); /* height */ _cogl_onscreen_init_from_template (onscreen, ctx->display->onscreen_template); return _cogl_onscreen_object_new (onscreen); } static void _cogl_onscreen_free (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer); CoglFrameInfo *frame_info; _cogl_closure_list_disconnect_all (&onscreen->resize_closures); _cogl_closure_list_disconnect_all (&onscreen->frame_closures); _cogl_closure_list_disconnect_all (&onscreen->dirty_closures); while ((frame_info = g_queue_pop_tail (&onscreen->pending_frame_infos))) cogl_object_unref (frame_info); g_queue_clear (&onscreen->pending_frame_infos); if (framebuffer->context->window_buffer == COGL_FRAMEBUFFER (onscreen)) framebuffer->context->window_buffer = NULL; winsys->onscreen_deinit (onscreen); _COGL_RETURN_IF_FAIL (onscreen->winsys == NULL); /* Chain up to parent */ _cogl_framebuffer_free (framebuffer); free (onscreen); } static void notify_event (CoglOnscreen *onscreen, CoglFrameEvent event, CoglFrameInfo *info) { _cogl_closure_list_invoke (&onscreen->frame_closures, CoglFrameCallback, onscreen, event, info); } static void _cogl_dispatch_onscreen_cb (CoglContext *context) { CoglOnscreenEvent *event, *tmp; CoglList queue; /* Dispatching the event callback may cause another frame to be * drawn which in may cause another event to be queued immediately. * To make sure this loop will only dispatch one set of events we'll * steal the queue and iterate that separately */ _cogl_list_init (&queue); _cogl_list_insert_list (&queue, &context->onscreen_events_queue); _cogl_list_init (&context->onscreen_events_queue); _cogl_closure_disconnect (context->onscreen_dispatch_idle); context->onscreen_dispatch_idle = NULL; _cogl_list_for_each_safe (event, tmp, &queue, link) { CoglOnscreen *onscreen = event->onscreen; CoglFrameInfo *info = event->info; notify_event (onscreen, event->type, info); cogl_object_unref (onscreen); cogl_object_unref (info); g_slice_free (CoglOnscreenEvent, event); } while (!_cogl_list_empty (&context->onscreen_dirty_queue)) { CoglOnscreenQueuedDirty *qe = _cogl_container_of (context->onscreen_dirty_queue.next, CoglOnscreenQueuedDirty, link); _cogl_list_remove (&qe->link); _cogl_closure_list_invoke (&qe->onscreen->dirty_closures, CoglOnscreenDirtyCallback, qe->onscreen, &qe->info); cogl_object_unref (qe->onscreen); g_slice_free (CoglOnscreenQueuedDirty, qe); } } static void _cogl_onscreen_queue_dispatch_idle (CoglOnscreen *onscreen) { CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context; if (!ctx->onscreen_dispatch_idle) { ctx->onscreen_dispatch_idle = _cogl_poll_renderer_add_idle (ctx->display->renderer, (CoglIdleCallback) _cogl_dispatch_onscreen_cb, ctx, NULL); } } void _cogl_onscreen_queue_dirty (CoglOnscreen *onscreen, const CoglOnscreenDirtyInfo *info) { CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context; CoglOnscreenQueuedDirty *qe = g_slice_new (CoglOnscreenQueuedDirty); qe->onscreen = cogl_object_ref (onscreen); qe->info = *info; _cogl_list_insert (ctx->onscreen_dirty_queue.prev, &qe->link); _cogl_onscreen_queue_dispatch_idle (onscreen); } void _cogl_onscreen_queue_full_dirty (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglOnscreenDirtyInfo info; info.x = 0; info.y = 0; info.width = framebuffer->width; info.height = framebuffer->height; _cogl_onscreen_queue_dirty (onscreen, &info); } void _cogl_onscreen_queue_event (CoglOnscreen *onscreen, CoglFrameEvent type, CoglFrameInfo *info) { CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context; CoglOnscreenEvent *event = g_slice_new (CoglOnscreenEvent); event->onscreen = cogl_object_ref (onscreen); event->info = cogl_object_ref (info); event->type = type; _cogl_list_insert (ctx->onscreen_events_queue.prev, &event->link); _cogl_onscreen_queue_dispatch_idle (onscreen); } void cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); const CoglWinsysVtable *winsys; CoglFrameInfo *info; _COGL_RETURN_IF_FAIL (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN); info = _cogl_frame_info_new (); info->frame_counter = onscreen->frame_counter; g_queue_push_tail (&onscreen->pending_frame_infos, info); /* FIXME: we shouldn't need to flush *all* journals here! */ cogl_flush (); winsys = _cogl_framebuffer_get_winsys (framebuffer); winsys->onscreen_swap_buffers_with_damage (onscreen, rectangles, n_rectangles); cogl_framebuffer_discard_buffers (framebuffer, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH | COGL_BUFFER_BIT_STENCIL); if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)) { CoglFrameInfo *info; g_warn_if_fail (onscreen->pending_frame_infos.length == 1); info = g_queue_pop_tail (&onscreen->pending_frame_infos); _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_SYNC, info); _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info); cogl_object_unref (info); } onscreen->frame_counter++; framebuffer->mid_scene = FALSE; } void cogl_onscreen_swap_buffers (CoglOnscreen *onscreen) { cogl_onscreen_swap_buffers_with_damage (onscreen, NULL, 0); } void cogl_onscreen_swap_region (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); const CoglWinsysVtable *winsys; CoglFrameInfo *info; _COGL_RETURN_IF_FAIL (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN); info = _cogl_frame_info_new (); info->frame_counter = onscreen->frame_counter; g_queue_push_tail (&onscreen->pending_frame_infos, info); /* FIXME: we shouldn't need to flush *all* journals here! */ cogl_flush (); winsys = _cogl_framebuffer_get_winsys (framebuffer); /* This should only be called if the winsys advertises COGL_WINSYS_FEATURE_SWAP_REGION */ _COGL_RETURN_IF_FAIL (winsys->onscreen_swap_region != NULL); winsys->onscreen_swap_region (COGL_ONSCREEN (framebuffer), rectangles, n_rectangles); cogl_framebuffer_discard_buffers (framebuffer, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH | COGL_BUFFER_BIT_STENCIL); if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)) { CoglFrameInfo *info; g_warn_if_fail (onscreen->pending_frame_infos.length == 1); info = g_queue_pop_tail (&onscreen->pending_frame_infos); _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_SYNC, info); _cogl_onscreen_queue_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info); cogl_object_unref (info); } onscreen->frame_counter++; framebuffer->mid_scene = FALSE; } int cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); const CoglWinsysVtable *winsys; _COGL_RETURN_VAL_IF_FAIL (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN, 0); winsys = _cogl_framebuffer_get_winsys (framebuffer); if (!winsys->onscreen_get_buffer_age) return 0; return winsys->onscreen_get_buffer_age (onscreen); } #ifdef COGL_HAS_X11_SUPPORT void cogl_x11_onscreen_set_foreign_window_xid (CoglOnscreen *onscreen, uint32_t xid, CoglOnscreenX11MaskCallback update, void *user_data) { /* We don't wan't applications to get away with being lazy here and not * passing an update callback... */ _COGL_RETURN_IF_FAIL (update); onscreen->foreign_xid = xid; onscreen->foreign_update_mask_callback = update; onscreen->foreign_update_mask_data = user_data; } uint32_t cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); if (onscreen->foreign_xid) return onscreen->foreign_xid; else { const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer); /* This should only be called for x11 onscreens */ _COGL_RETURN_VAL_IF_FAIL (winsys->onscreen_x11_get_window_xid != NULL, 0); return winsys->onscreen_x11_get_window_xid (onscreen); } } uint32_t cogl_x11_onscreen_get_visual_xid (CoglOnscreen *onscreen) { CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context; XVisualInfo *visinfo; uint32_t id; /* This should only be called for xlib based onscreens */ visinfo = cogl_xlib_renderer_get_visual_info (ctx->display->renderer); if (visinfo == NULL) return 0; id = (uint32_t)visinfo->visualid; return id; } #endif /* COGL_HAS_X11_SUPPORT */ CoglFrameClosure * cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen, CoglFrameCallback callback, void *user_data, CoglUserDataDestroyCallback destroy) { return _cogl_closure_list_add (&onscreen->frame_closures, callback, user_data, destroy); } void cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen, CoglFrameClosure *closure) { _COGL_RETURN_IF_FAIL (closure); _cogl_closure_disconnect (closure); } typedef struct _SwapBufferCallbackState { CoglSwapBuffersNotify callback; void *user_data; } SwapBufferCallbackState; static void destroy_swap_buffers_callback_state (void *user_data) { g_slice_free (SwapBufferCallbackState, user_data); } static void shim_swap_buffers_callback (CoglOnscreen *onscreen, CoglFrameEvent event, CoglFrameInfo *info, void *user_data) { SwapBufferCallbackState *state = user_data; /* XXX: Note that technically it is a change in semantics for this * interface to forward _SYNC events here and also makes the api * name somewhat missleading. * * In practice though this interface is currently used by * applications for throttling, not because they are strictly * interested in knowing when a frame has been presented and so * forwarding _SYNC events should serve them better. */ if (event == COGL_FRAME_EVENT_SYNC) state->callback (COGL_FRAMEBUFFER (onscreen), state->user_data); } unsigned int cogl_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen, CoglSwapBuffersNotify callback, void *user_data) { CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context; SwapBufferCallbackState *state = g_slice_new (SwapBufferCallbackState); CoglFrameClosure *closure; unsigned int id = ctx->next_swap_callback_id++; state->callback = callback; state->user_data = user_data; closure = cogl_onscreen_add_frame_callback (onscreen, shim_swap_buffers_callback, state, destroy_swap_buffers_callback_state); g_hash_table_insert (ctx->swap_callback_closures, GINT_TO_POINTER (id), closure); return id; } void cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen, unsigned int id) { CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context; CoglFrameClosure *closure = g_hash_table_lookup (ctx->swap_callback_closures, GINT_TO_POINTER (id)); _COGL_RETURN_IF_FAIL (closure); cogl_onscreen_remove_frame_callback (onscreen, closure); } void cogl_onscreen_set_swap_throttled (CoglOnscreen *onscreen, CoglBool throttled) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); framebuffer->config.swap_throttled = throttled; if (framebuffer->allocated) { const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer); winsys->onscreen_update_swap_throttled (onscreen); } } void cogl_onscreen_show (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); const CoglWinsysVtable *winsys; if (!framebuffer->allocated) { if (!cogl_framebuffer_allocate (framebuffer, NULL)) return; } winsys = _cogl_framebuffer_get_winsys (framebuffer); if (winsys->onscreen_set_visibility) winsys->onscreen_set_visibility (onscreen, TRUE); } void cogl_onscreen_hide (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); if (framebuffer->allocated) { const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer); if (winsys->onscreen_set_visibility) winsys->onscreen_set_visibility (onscreen, FALSE); } } void _cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info) { notify_event (onscreen, COGL_FRAME_EVENT_SYNC, info); } void _cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info) { notify_event (onscreen, COGL_FRAME_EVENT_COMPLETE, info); } void _cogl_onscreen_notify_resize (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); _cogl_closure_list_invoke (&onscreen->resize_closures, CoglOnscreenResizeCallback, onscreen, framebuffer->width, framebuffer->height); } void _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer, int width, int height) { if (framebuffer->width == width && framebuffer->height == height) return; framebuffer->width = width; framebuffer->height = height; cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height); if (!_cogl_has_private_feature (framebuffer->context, COGL_PRIVATE_FEATURE_DIRTY_EVENTS)) _cogl_onscreen_queue_full_dirty (COGL_ONSCREEN (framebuffer)); } void cogl_onscreen_set_resizable (CoglOnscreen *onscreen, CoglBool resizable) { CoglFramebuffer *framebuffer; const CoglWinsysVtable *winsys; if (onscreen->resizable == resizable) return; onscreen->resizable = resizable; framebuffer = COGL_FRAMEBUFFER (onscreen); if (framebuffer->allocated) { winsys = _cogl_framebuffer_get_winsys (COGL_FRAMEBUFFER (onscreen)); if (winsys->onscreen_set_resizable) winsys->onscreen_set_resizable (onscreen, resizable); } } CoglBool cogl_onscreen_get_resizable (CoglOnscreen *onscreen) { return onscreen->resizable; } CoglOnscreenResizeClosure * cogl_onscreen_add_resize_callback (CoglOnscreen *onscreen, CoglOnscreenResizeCallback callback, void *user_data, CoglUserDataDestroyCallback destroy) { return _cogl_closure_list_add (&onscreen->resize_closures, callback, user_data, destroy); } void cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen, CoglOnscreenResizeClosure *closure) { _cogl_closure_disconnect (closure); } CoglOnscreenDirtyClosure * cogl_onscreen_add_dirty_callback (CoglOnscreen *onscreen, CoglOnscreenDirtyCallback callback, void *user_data, CoglUserDataDestroyCallback destroy) { return _cogl_closure_list_add (&onscreen->dirty_closures, callback, user_data, destroy); } void cogl_onscreen_remove_dirty_callback (CoglOnscreen *onscreen, CoglOnscreenDirtyClosure *closure) { _COGL_RETURN_IF_FAIL (closure); _cogl_closure_disconnect (closure); } int64_t cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen) { return onscreen->frame_counter; } muffin-5.2.1/cogl/cogl/gl-prototypes/0000775000175000017500000000000014211404421017634 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/gl-prototypes/cogl-in-gles2-core-functions.h0000664000175000017500000001706514211404421025314 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is included multiple times with different definitions for * these macros. The macros are given the following arguments: * * COGL_EXT_BEGIN: * * @name: a unique symbol name for this feature * * @min_gl_major: the major part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * @min_gl_minor: the minor part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * * @gles_availability: flags to specify which versions of GLES the * functions are available in. Should be a combination of * COGL_EXT_IN_GLES and COGL_EXT_IN_GLES2. * * @extension_suffixes: A zero-separated list of suffixes in a * string. These are appended to the extension name to get a complete * extension name to try. The suffix is also appended to all of the * function names. The suffix can optionally include a ':' to specify * an alternate suffix for the function names. * * @extension_names: A list of extension names to try. If any of these * extensions match then it will be used. */ COGL_EXT_BEGIN (offscreen, 3, 0, COGL_EXT_IN_GLES2, /* for some reason the ARB version of this extension doesn't have an ARB suffix for the functions */ "ARB:\0EXT\0OES\0", "framebuffer_object\0") COGL_EXT_FUNCTION (void, glGenRenderbuffers, (GLsizei n, GLuint *renderbuffers)) COGL_EXT_FUNCTION (void, glDeleteRenderbuffers, (GLsizei n, const GLuint *renderbuffers)) COGL_EXT_FUNCTION (void, glBindRenderbuffer, (GLenum target, GLuint renderbuffer)) COGL_EXT_FUNCTION (void, glRenderbufferStorage, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) COGL_EXT_FUNCTION (void, glGenFramebuffers, (GLsizei n, GLuint *framebuffers)) COGL_EXT_FUNCTION (void, glBindFramebuffer, (GLenum target, GLuint framebuffer)) COGL_EXT_FUNCTION (void, glFramebufferTexture2D, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) COGL_EXT_FUNCTION (void, glFramebufferRenderbuffer, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) COGL_EXT_FUNCTION (GLboolean, glIsRenderbuffer, (GLuint renderbuffer)) COGL_EXT_FUNCTION (GLenum, glCheckFramebufferStatus, (GLenum target)) COGL_EXT_FUNCTION (void, glDeleteFramebuffers, (GLsizei n, const GLuint *framebuffers)) COGL_EXT_FUNCTION (void, glGenerateMipmap, (GLenum target)) COGL_EXT_FUNCTION (void, glGetFramebufferAttachmentParameteriv, (GLenum target, GLenum attachment, GLenum pname, GLint *params)) COGL_EXT_FUNCTION (void, glGetRenderbufferParameteriv, (GLenum target, GLenum pname, GLint *params)) COGL_EXT_FUNCTION (GLboolean, glIsFramebuffer, (GLuint framebuffer)) COGL_EXT_END () COGL_EXT_BEGIN (blending, 1, 2, COGL_EXT_IN_GLES2, "\0", "\0") COGL_EXT_FUNCTION (void, glBlendEquation, (GLenum mode)) COGL_EXT_FUNCTION (void, glBlendColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) COGL_EXT_END () /* Optional, declared in 1.4 or GLES 1.2 */ COGL_EXT_BEGIN (blend_func_separate, 1, 4, COGL_EXT_IN_GLES2, "EXT\0", "blend_func_separate\0") COGL_EXT_FUNCTION (void, glBlendFuncSeparate, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)) COGL_EXT_END () /* Optional, declared in 2.0 */ COGL_EXT_BEGIN (blend_equation_separate, 2, 0, COGL_EXT_IN_GLES2, "EXT\0", "blend_equation_separate\0") COGL_EXT_FUNCTION (void, glBlendEquationSeparate, (GLenum modeRGB, GLenum modeAlpha)) COGL_EXT_END () COGL_EXT_BEGIN (gles2_only_api, 4, 1, COGL_EXT_IN_GLES2, "ARB:\0", "ES2_compatibility\0") COGL_EXT_FUNCTION (void, glReleaseShaderCompiler, (void)) COGL_EXT_FUNCTION (void, glGetShaderPrecisionFormat, (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)) COGL_EXT_FUNCTION (void, glShaderBinary, (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)) COGL_EXT_END () /* GL and GLES 2.0 apis */ COGL_EXT_BEGIN (two_point_zero_api, 2, 0, COGL_EXT_IN_GLES2, "\0", "\0") COGL_EXT_FUNCTION (void, glStencilFuncSeparate, (GLenum face, GLenum func, GLint ref, GLuint mask)) COGL_EXT_FUNCTION (void, glStencilMaskSeparate, (GLenum face, GLuint mask)) COGL_EXT_FUNCTION (void, glStencilOpSeparate, (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)) COGL_EXT_END () muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-in-gles-core-functions.h0000664000175000017500000001245414211404421025227 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is included multiple times with different definitions for * these macros. The macros are given the following arguments: * * COGL_EXT_BEGIN: * * @name: a unique symbol name for this feature * * @min_gl_major: the major part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * @min_gl_minor: the minor part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * * @gles_availability: flags to specify which versions of GLES the * functions are available in. Should be a combination of * COGL_EXT_IN_GLES and COGL_EXT_IN_GLES2. * * @extension_suffixes: A zero-separated list of suffixes in a * string. These are appended to the extension name to get a complete * extension name to try. The suffix is also appended to all of the * function names. The suffix can optionally include a ':' to specify * an alternate suffix for the function names. * * @extension_names: A list of extension names to try. If any of these * extensions match then it will be used. */ COGL_EXT_BEGIN (only_in_both_gles, 4, 1, COGL_EXT_IN_GLES | COGL_EXT_IN_GLES2, "ARB\0", "ES2_compatibility\0") COGL_EXT_FUNCTION (void, glDepthRangef, (GLfloat near_val, GLfloat far_val)) COGL_EXT_FUNCTION (void, glClearDepthf, (GLclampf depth)) COGL_EXT_END () COGL_EXT_BEGIN (only_in_both_gles_and_gl_1_3, 1, 3, COGL_EXT_IN_GLES | COGL_EXT_IN_GLES2, "\0", "\0") COGL_EXT_FUNCTION (void, glCompressedTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)) COGL_EXT_FUNCTION (void, glCompressedTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)) COGL_EXT_FUNCTION (void, glSampleCoverage, (GLclampf value, GLboolean invert)) COGL_EXT_END () COGL_EXT_BEGIN (only_in_both_gles_and_gl_1_5, 1, 5, COGL_EXT_IN_GLES | COGL_EXT_IN_GLES2, "\0", "\0") COGL_EXT_FUNCTION (void, glGetBufferParameteriv, (GLenum target, GLenum pname, GLint* params)) COGL_EXT_END () COGL_EXT_BEGIN (vbos, 1, 5, COGL_EXT_IN_GLES | COGL_EXT_IN_GLES2, "ARB\0", "vertex_buffer_object\0") COGL_EXT_FUNCTION (void, glGenBuffers, (GLsizei n, GLuint *buffers)) COGL_EXT_FUNCTION (void, glBindBuffer, (GLenum target, GLuint buffer)) COGL_EXT_FUNCTION (void, glBufferData, (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)) COGL_EXT_FUNCTION (void, glBufferSubData, (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)) COGL_EXT_FUNCTION (void, glDeleteBuffers, (GLsizei n, const GLuint *buffers)) COGL_EXT_FUNCTION (GLboolean, glIsBuffer, (GLuint buffer)) COGL_EXT_END () /* Available in GL 1.3, the multitexture extension or GLES. These are required */ COGL_EXT_BEGIN (multitexture_part0, 1, 3, COGL_EXT_IN_GLES | COGL_EXT_IN_GLES2, "ARB\0", "multitexture\0") COGL_EXT_FUNCTION (void, glActiveTexture, (GLenum texture)) COGL_EXT_END () muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-all-functions.h0000664000175000017500000003065214211404421023513 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is included multiple times with different definitions for * these macros. The macros are given the following arguments: * * COGL_EXT_BEGIN: * * @name: a unique symbol name for this feature * * @min_gl_major: the major part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * @min_gl_minor: the minor part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * * @gles_availability: flags to specify which versions of GLES the * functions are available in. Should be a combination of * COGL_EXT_IN_GLES and COGL_EXT_IN_GLES2. * * @extension_suffixes: A zero-separated list of suffixes in a * string. These are appended to the extension name to get a complete * extension name to try. The suffix is also appended to all of the * function names. The suffix can optionally include a ':' to specify * an alternate suffix for the function names. * * @extension_names: A list of extension names to try. If any of these * extensions match then it will be used. */ /* The functions in this file are part of the core GL,GLES1 and GLES2 apis */ #include "cogl-core-functions.h" /* The functions in this file are core to GLES1 only but may also be * extensions available for GLES2 and GL */ #include "cogl-in-gles1-core-functions.h" /* The functions in this file are core to GLES2 only but * may be extensions for GLES1 and GL */ #include "cogl-in-gles2-core-functions.h" /* The functions in this file are core to GLES1 and GLES2 but not core * to GL but they may be extensions available for GL */ #include "cogl-in-gles-core-functions.h" /* These are fixed-function APIs core to GL and GLES1 */ #include "cogl-fixed-functions.h" /* These are GLSL shader APIs core to GL 2.0 and GLES2 */ #include "cogl-glsl-functions.h" /* These are the core GL functions which are only available in big GL */ COGL_EXT_BEGIN (only_in_big_gl, 0, 0, 0, /* not in GLES */ "\0", "\0") COGL_EXT_FUNCTION (void, glGetTexLevelParameteriv, (GLenum target, GLint level, GLenum pname, GLint *params)) COGL_EXT_FUNCTION (void, glGetTexImage, (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels)) COGL_EXT_FUNCTION (void, glClipPlane, (GLenum plane, const double *equation)) COGL_EXT_FUNCTION (void, glDepthRange, (double near_val, double far_val)) COGL_EXT_FUNCTION (void, glDrawBuffer, (GLenum mode)) COGL_EXT_END () /* GLES doesn't support mapping buffers in core so this has to be a separate check */ COGL_EXT_BEGIN (map_vbos, 1, 5, 0, /* not in GLES core */ "ARB\0OES\0", "vertex_buffer_object\0mapbuffer\0") COGL_EXT_FUNCTION (void *, glMapBuffer, (GLenum target, GLenum access)) COGL_EXT_FUNCTION (GLboolean, glUnmapBuffer, (GLenum target)) COGL_EXT_END () COGL_EXT_BEGIN (texture_3d, 1, 2, 0, /* not in either GLES */ "OES\0", "texture_3D\0") COGL_EXT_FUNCTION (void, glTexImage3D, (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) COGL_EXT_FUNCTION (void, glTexSubImage3D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels)) COGL_EXT_END () COGL_EXT_BEGIN (offscreen_blit, 3, 0, 0, /* not in either GLES */ "EXT\0ANGLE\0", "framebuffer_blit\0") COGL_EXT_FUNCTION (void, glBlitFramebuffer, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) COGL_EXT_END () /* ARB_fragment_program */ COGL_EXT_BEGIN (arbfp, 255, 255, 0, /* not in either GLES */ "ARB\0", "fragment_program\0") COGL_EXT_FUNCTION (void, glGenPrograms, (GLsizei n, GLuint *programs)) COGL_EXT_FUNCTION (void, glDeletePrograms, (GLsizei n, GLuint *programs)) COGL_EXT_FUNCTION (void, glBindProgram, (GLenum target, GLuint program)) COGL_EXT_FUNCTION (void, glProgramString, (GLenum target, GLenum format, GLsizei len, const void *program)) COGL_EXT_FUNCTION (void, glProgramLocalParameter4fv, (GLenum target, GLuint index, GLfloat *params)) COGL_EXT_END () COGL_EXT_BEGIN (EGL_image, 255, 255, 0, /* not in either GLES */ "OES\0", "EGL_image\0") COGL_EXT_FUNCTION (void, glEGLImageTargetTexture2D, (GLenum target, GLeglImageOES image)) COGL_EXT_FUNCTION (void, glEGLImageTargetRenderbufferStorage, (GLenum target, GLeglImageOES image)) COGL_EXT_END () COGL_EXT_BEGIN (framebuffer_discard, 255, 255, 0, /* not in either GLES */ "EXT\0", "framebuffer_discard\0") COGL_EXT_FUNCTION (void, glDiscardFramebuffer, (GLenum target, GLsizei numAttachments, const GLenum *attachments)) COGL_EXT_END () COGL_EXT_BEGIN (IMG_multisampled_render_to_texture, 255, 255, 0, /* not in either GLES */ "\0", "IMG_multisampled_render_to_texture\0") COGL_EXT_FUNCTION (void, glRenderbufferStorageMultisampleIMG, (GLenum target, GLsizei samples, GLenum internal_format, GLsizei width, GLsizei height)) COGL_EXT_FUNCTION (void, glFramebufferTexture2DMultisampleIMG, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)) COGL_EXT_END () COGL_EXT_BEGIN (ARB_sampler_objects, 3, 3, 0, /* not in either GLES */ "ARB:\0", "sampler_objects\0") COGL_EXT_FUNCTION (void, glGenSamplers, (GLsizei count, GLuint *samplers)) COGL_EXT_FUNCTION (void, glDeleteSamplers, (GLsizei count, const GLuint *samplers)) COGL_EXT_FUNCTION (void, glBindSampler, (GLuint unit, GLuint sampler)) COGL_EXT_FUNCTION (void, glSamplerParameteri, (GLuint sampler, GLenum pname, GLint param)) COGL_EXT_END () /* These only list functions that come from the old GLSL extensions. * Functions that are common to the extensions and GLSL 2.0 should * instead be listed in cogl-glsl-functions.h */ COGL_EXT_BEGIN (shader_objects, 255, 255, 0, /* not in either GLES */ "ARB\0", "shader_objects\0") COGL_EXT_FUNCTION (GLuint, glCreateProgramObject, (void)) COGL_EXT_FUNCTION (GLuint, glCreateShaderObject, (GLenum shaderType)) COGL_EXT_FUNCTION (void, glDeleteObject, (GLuint obj)) COGL_EXT_FUNCTION (void, glAttachObject, (GLuint container, GLuint obj)) COGL_EXT_FUNCTION (void, glUseProgramObject, (GLuint programObj)) COGL_EXT_FUNCTION (void, glGetInfoLog, (GLuint obj, GLsizei maxLength, GLsizei *length, char *infoLog)) COGL_EXT_FUNCTION (void, glGetObjectParameteriv, (GLuint obj, GLenum pname, GLint *params)) COGL_EXT_FUNCTION (void, glDetachObject, (GLuint container, GLuint obj)) COGL_EXT_FUNCTION (void, glGetAttachedObjects, (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)) COGL_EXT_END () COGL_EXT_BEGIN (only_gl3, 3, 0, 0, /* not in either GLES */ "\0", "\0") COGL_EXT_FUNCTION (const GLubyte *, glGetStringi, (GLenum name, GLuint index)) COGL_EXT_END () COGL_EXT_BEGIN (vertex_array_object, 3, 0, 0, /* not in either GLES */ "ARB\0OES\0", "vertex_array_object\0") COGL_EXT_FUNCTION (void, glBindVertexArray, (GLuint array)) COGL_EXT_FUNCTION (void, glDeleteVertexArrays, (GLsizei n, const GLuint *arrays)) COGL_EXT_FUNCTION (void, glGenVertexArrays, (GLsizei n, GLuint *arrays)) COGL_EXT_END () COGL_EXT_BEGIN (map_region, 3, 0, COGL_EXT_IN_GLES3, "ARB:\0", "map_buffer_range\0") COGL_EXT_FUNCTION (GLvoid *, glMapBufferRange, (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)) COGL_EXT_END () #ifdef GL_ARB_sync COGL_EXT_BEGIN (sync, 3, 2, 0, /* not in either GLES */ "ARB:\0", "sync\0") COGL_EXT_FUNCTION (GLsync, glFenceSync, (GLenum condition, GLbitfield flags)) COGL_EXT_FUNCTION (GLenum, glClientWaitSync, (GLsync sync, GLbitfield flags, GLuint64 timeout)) COGL_EXT_FUNCTION (void, glDeleteSync, (GLsync sync)) COGL_EXT_END () #endif COGL_EXT_BEGIN (draw_buffers, 2, 0, COGL_EXT_IN_GLES3, "ARB\0EXT\0", "draw_buffers\0") COGL_EXT_FUNCTION (void, glDrawBuffers, (GLsizei n, const GLenum *bufs)) COGL_EXT_END () COGL_EXT_BEGIN (robustness, 255, 255, 0, "ARB\0", "robustness\0") COGL_EXT_FUNCTION (GLenum, glGetGraphicsResetStatus, (void)) COGL_EXT_END () muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-gles1-functions.h0000664000175000017500000000326314211404421023754 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* The functions in this file are part of the core GL,GLES1 and GLES2 apis */ #include "cogl-core-functions.h" /* The functions in this file are core to GLES1 and GLES2 but not core * to GL but they may be extensions available for GL */ #include "cogl-in-gles-core-functions.h" /* The functions in this file are core to GLES1 only but * may be extensions for GLES2 and GL */ #include "cogl-in-gles1-core-functions.h" /* These are fixed-function APIs core to GL and GLES1 */ #include "cogl-fixed-functions.h" muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-gles2-functions.h0000664000175000017500000000326214211404421023754 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* The functions in this file are part of the core GL,GLES1 and GLES2 apis */ #include "cogl-core-functions.h" /* The functions in this file are core to GLES1 and GLES2 but not core * to GL but they may be extensions available for GL */ #include "cogl-in-gles-core-functions.h" /* The functions in this file are core to GLES2 only but * may be extensions for GLES1 and GL */ #include "cogl-in-gles2-core-functions.h" /* These are APIs for using GLSL used by GL and GLES2 */ #include "cogl-glsl-functions.h" muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-in-gles1-core-functions.h0000664000175000017500000000563714211404421025315 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is included multiple times with different definitions for * these macros. The macros are given the following arguments: * * COGL_EXT_BEGIN: * * @name: a unique symbol name for this feature * * @min_gl_major: the major part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * @min_gl_minor: the minor part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * * @gles_availability: flags to specify which versions of GLES the * functions are available in. Should be a combination of * COGL_EXT_IN_GLES and COGL_EXT_IN_GLES2. * * @extension_suffixes: A zero-separated list of suffixes in a * string. These are appended to the extension name to get a complete * extension name to try. The suffix is also appended to all of the * function names. The suffix can optionally include a ':' to specify * an alternate suffix for the function names. * * @extension_names: A list of extension names to try. If any of these * extensions match then it will be used. */ /* These functions are only available in GLES and are used as replacements for some GL equivalents that only accept double arguments */ COGL_EXT_BEGIN (only_in_gles1, 255, 255, COGL_EXT_IN_GLES, "\0", "\0") COGL_EXT_FUNCTION (void, glClipPlanef, (GLenum plane, const GLfloat *equation)) COGL_EXT_END () COGL_EXT_BEGIN (multitexture_part1, 1, 3, COGL_EXT_IN_GLES, "ARB\0", "multitexture\0") COGL_EXT_FUNCTION (void, glClientActiveTexture, (GLenum texture)) COGL_EXT_END () muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-fixed-functions.h0000664000175000017500000001142614211404421024040 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is included multiple times with different definitions for * these macros. The macros are given the following arguments: * * COGL_EXT_BEGIN: * * @name: a unique symbol name for this feature * * @min_gl_major: the major part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * @min_gl_minor: the minor part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * * @gles_availability: flags to specify which versions of GLES the * functions are available in. Should be a combination of * COGL_EXT_IN_GLES and COGL_EXT_IN_GLES2. * * @extension_suffixes: A zero-separated list of suffixes in a * string. These are appended to the extension name to get a complete * extension name to try. The suffix is also appended to all of the * function names. The suffix can optionally include a ':' to specify * an alternate suffix for the function names. * * @extension_names: A list of extension names to try. If any of these * extensions match then it will be used. */ /* These are the core GL functions which are available when the API supports fixed-function (ie, GL and GLES1.1) */ COGL_EXT_BEGIN (fixed_function_core, 0, 0, COGL_EXT_IN_GLES, "\0", "\0") COGL_EXT_FUNCTION (void, glAlphaFunc, (GLenum func, GLclampf ref)) COGL_EXT_FUNCTION (void, glFogf, (GLenum pname, GLfloat param)) COGL_EXT_FUNCTION (void, glFogfv, (GLenum pname, const GLfloat *params)) COGL_EXT_FUNCTION (void, glLoadMatrixf, (const GLfloat *m)) COGL_EXT_FUNCTION (void, glMaterialfv, (GLenum face, GLenum pname, const GLfloat *params)) COGL_EXT_FUNCTION (void, glPointSize, (GLfloat size)) COGL_EXT_FUNCTION (void, glTexEnvfv, (GLenum target, GLenum pname, const GLfloat *params)) COGL_EXT_FUNCTION (void, glColor4ub, (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)) COGL_EXT_FUNCTION (void, glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) COGL_EXT_FUNCTION (void, glColorPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) COGL_EXT_FUNCTION (void, glDisableClientState, (GLenum array)) COGL_EXT_FUNCTION (void, glEnableClientState, (GLenum array)) COGL_EXT_FUNCTION (void, glLoadIdentity, (void)) COGL_EXT_FUNCTION (void, glMatrixMode, (GLenum mode)) COGL_EXT_FUNCTION (void, glNormal3f, (GLfloat x, GLfloat y, GLfloat z)) COGL_EXT_FUNCTION (void, glNormalPointer, (GLenum type, GLsizei stride, const GLvoid *pointer)) COGL_EXT_FUNCTION (void, glMultiTexCoord4f, (GLfloat s, GLfloat t, GLfloat r, GLfloat q)) COGL_EXT_FUNCTION (void, glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) COGL_EXT_FUNCTION (void, glTexEnvi, (GLenum target, GLenum pname, GLint param)) COGL_EXT_FUNCTION (void, glVertex4f, (GLfloat x, GLfloat y, GLfloat z, GLfloat w)) COGL_EXT_FUNCTION (void, glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) COGL_EXT_END () muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-core-functions.h0000664000175000017500000001737114211404421023676 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is included multiple times with different definitions for * these macros. The macros are given the following arguments: * * COGL_EXT_BEGIN: * * @name: a unique symbol name for this feature * * @min_gl_major: the major part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * @min_gl_minor: the minor part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * * @gles_availability: flags to specify which versions of GLES the * functions are available in. Should be a combination of * COGL_EXT_IN_GLES and COGL_EXT_IN_GLES2. * * @extension_suffixes: A zero-separated list of suffixes in a * string. These are appended to the extension name to get a complete * extension name to try. The suffix is also appended to all of the * function names. The suffix can optionally include a ':' to specify * an alternate suffix for the function names. * * @extension_names: A list of extension names to try. If any of these * extensions match then it will be used. */ /* These are the core GL functions which we assume will always be available */ COGL_EXT_BEGIN (core, 0, 0, COGL_EXT_IN_GLES | COGL_EXT_IN_GLES2, "\0", "\0") COGL_EXT_FUNCTION (void, glBindTexture, (GLenum target, GLuint texture)) COGL_EXT_FUNCTION (void, glBlendFunc, (GLenum sfactor, GLenum dfactor)) COGL_EXT_FUNCTION (void, glClear, (GLbitfield mask)) COGL_EXT_FUNCTION (void, glClearColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) COGL_EXT_FUNCTION (void, glClearStencil, (GLint s)) COGL_EXT_FUNCTION (void, glColorMask, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) COGL_EXT_FUNCTION (void, glCopyTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)) COGL_EXT_FUNCTION (void, glDeleteTextures, (GLsizei n, const GLuint* textures)) COGL_EXT_FUNCTION (void, glDepthFunc, (GLenum func)) COGL_EXT_FUNCTION (void, glDepthMask, (GLboolean flag)) COGL_EXT_FUNCTION (void, glDisable, (GLenum cap)) COGL_EXT_FUNCTION (void, glDrawArrays, (GLenum mode, GLint first, GLsizei count)) COGL_EXT_FUNCTION (void, glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)) COGL_EXT_FUNCTION (void, glEnable, (GLenum cap)) COGL_EXT_FUNCTION (void, glFinish, (void)) COGL_EXT_FUNCTION (void, glFlush, (void)) COGL_EXT_FUNCTION (void, glFrontFace, (GLenum mode)) COGL_EXT_FUNCTION (void, glCullFace, (GLenum mode)) COGL_EXT_FUNCTION (void, glGenTextures, (GLsizei n, GLuint* textures)) COGL_EXT_FUNCTION (GLenum, glGetError, (void)) COGL_EXT_FUNCTION (void, glGetIntegerv, (GLenum pname, GLint* params)) COGL_EXT_FUNCTION (void, glGetBooleanv, (GLenum pname, GLboolean* params)) COGL_EXT_FUNCTION (void, glGetFloatv, (GLenum pname, GLfloat* params)) COGL_EXT_FUNCTION (const GLubyte*, glGetString, (GLenum name)) COGL_EXT_FUNCTION (void, glHint, (GLenum target, GLenum mode)) COGL_EXT_FUNCTION (GLboolean, glIsTexture, (GLuint texture)) COGL_EXT_FUNCTION (void, glPixelStorei, (GLenum pname, GLint param)) COGL_EXT_FUNCTION (void, glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)) COGL_EXT_FUNCTION (void, glScissor, (GLint x, GLint y, GLsizei width, GLsizei height)) COGL_EXT_FUNCTION (void, glStencilFunc, (GLenum func, GLint ref, GLuint mask)) COGL_EXT_FUNCTION (void, glStencilMask, (GLuint mask)) COGL_EXT_FUNCTION (void, glStencilOp, (GLenum fail, GLenum zfail, GLenum zpass)) COGL_EXT_FUNCTION (void, glTexImage2D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)) COGL_EXT_FUNCTION (void, glTexParameterf, (GLenum target, GLenum pname, GLfloat param)) COGL_EXT_FUNCTION (void, glTexParameterfv, (GLenum target, GLenum pname, const GLfloat* params)) COGL_EXT_FUNCTION (void, glTexParameteri, (GLenum target, GLenum pname, GLint param)) COGL_EXT_FUNCTION (void, glTexParameteriv, (GLenum target, GLenum pname, const GLint* params)) COGL_EXT_FUNCTION (void, glGetTexParameterfv, (GLenum target, GLenum pname, GLfloat* params)) COGL_EXT_FUNCTION (void, glGetTexParameteriv, (GLenum target, GLenum pname, GLint* params)) COGL_EXT_FUNCTION (void, glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)) COGL_EXT_FUNCTION (void, glCopyTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)) COGL_EXT_FUNCTION (void, glViewport, (GLint x, GLint y, GLsizei width, GLsizei height)) COGL_EXT_FUNCTION (GLboolean, glIsEnabled, (GLenum cap)) COGL_EXT_FUNCTION (void, glLineWidth, (GLfloat width)) COGL_EXT_FUNCTION (void, glPolygonOffset, (GLfloat factor, GLfloat units)) COGL_EXT_END () muffin-5.2.1/cogl/cogl/gl-prototypes/cogl-glsl-functions.h0000664000175000017500000003036514211404421023705 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009, 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This is included multiple times with different definitions for * these macros. The macros are given the following arguments: * * COGL_EXT_BEGIN: * * @name: a unique symbol name for this feature * * @min_gl_major: the major part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * @min_gl_minor: the minor part of the minimum GL version where these * functions are available in core, or 255 if it isn't available in * any version. * * @gles_availability: flags to specify which versions of GLES the * functions are available in. Should be a combination of * COGL_EXT_IN_GLES and COGL_EXT_IN_GLES2. * * @extension_suffixes: A zero-separated list of suffixes in a * string. These are appended to the extension name to get a complete * extension name to try. The suffix is also appended to all of the * function names. The suffix can optionally include a ':' to specify * an alternate suffix for the function names. * * @extension_names: A list of extension names to try. If any of these * extensions match then it will be used. */ /* This lists functions that are unique to GL 2.0 or GLES 2.0 and are * not in the old GLSL extensions */ COGL_EXT_BEGIN (shaders_glsl_2_only, 2, 0, COGL_EXT_IN_GLES2, "\0", "\0") COGL_EXT_FUNCTION (GLuint, glCreateProgram, (void)) COGL_EXT_FUNCTION (GLuint, glCreateShader, (GLenum shaderType)) COGL_EXT_FUNCTION (void, glDeleteShader, (GLuint shader)) COGL_EXT_FUNCTION (void, glAttachShader, (GLuint program, GLuint shader)) COGL_EXT_FUNCTION (void, glUseProgram, (GLuint program)) COGL_EXT_FUNCTION (void, glDeleteProgram, (GLuint program)) COGL_EXT_FUNCTION (void, glGetShaderInfoLog, (GLuint shader, GLsizei maxLength, GLsizei *length, char *infoLog)) COGL_EXT_FUNCTION (void, glGetProgramInfoLog, (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog)) COGL_EXT_FUNCTION (void, glGetShaderiv, (GLuint shader, GLenum pname, GLint *params)) COGL_EXT_FUNCTION (void, glGetProgramiv, (GLuint program, GLenum pname, GLint *params)) COGL_EXT_FUNCTION (void, glDetachShader, (GLuint program, GLuint shader)) COGL_EXT_FUNCTION (void, glGetAttachedShaders, (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)) COGL_EXT_FUNCTION (GLboolean, glIsShader, (GLuint shader)) COGL_EXT_FUNCTION (GLboolean, glIsProgram, (GLuint program)) COGL_EXT_END () /* These functions are provided by GL_ARB_shader_objects or are in GL * 2.0 core */ COGL_EXT_BEGIN (shader_objects_or_gl2, 2, 0, COGL_EXT_IN_GLES2, "ARB\0", "shader_objects\0") COGL_EXT_FUNCTION (void, glShaderSource, (GLuint shader, GLsizei count, const char * const *string, const GLint *length)) COGL_EXT_FUNCTION (void, glCompileShader, (GLuint shader)) COGL_EXT_FUNCTION (void, glLinkProgram, (GLuint program)) COGL_EXT_FUNCTION (GLint, glGetUniformLocation, (GLuint program, const char *name)) COGL_EXT_FUNCTION (void, glUniform1f, (GLint location, GLfloat v0)) COGL_EXT_FUNCTION (void, glUniform2f, (GLint location, GLfloat v0, GLfloat v1)) COGL_EXT_FUNCTION (void, glUniform3f, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)) COGL_EXT_FUNCTION (void, glUniform4f, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)) COGL_EXT_FUNCTION (void, glUniform1fv, (GLint location, GLsizei count, const GLfloat * value)) COGL_EXT_FUNCTION (void, glUniform2fv, (GLint location, GLsizei count, const GLfloat * value)) COGL_EXT_FUNCTION (void, glUniform3fv, (GLint location, GLsizei count, const GLfloat * value)) COGL_EXT_FUNCTION (void, glUniform4fv, (GLint location, GLsizei count, const GLfloat * value)) COGL_EXT_FUNCTION (void, glUniform1i, (GLint location, GLint v0)) COGL_EXT_FUNCTION (void, glUniform2i, (GLint location, GLint v0, GLint v1)) COGL_EXT_FUNCTION (void, glUniform3i, (GLint location, GLint v0, GLint v1, GLint v2)) COGL_EXT_FUNCTION (void, glUniform4i, (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)) COGL_EXT_FUNCTION (void, glUniform1iv, (GLint location, GLsizei count, const GLint * value)) COGL_EXT_FUNCTION (void, glUniform2iv, (GLint location, GLsizei count, const GLint * value)) COGL_EXT_FUNCTION (void, glUniform3iv, (GLint location, GLsizei count, const GLint * value)) COGL_EXT_FUNCTION (void, glUniform4iv, (GLint location, GLsizei count, const GLint * value)) COGL_EXT_FUNCTION (void, glUniformMatrix2fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) COGL_EXT_FUNCTION (void, glUniformMatrix3fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) COGL_EXT_FUNCTION (void, glUniformMatrix4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) COGL_EXT_FUNCTION (void, glGetUniformfv, (GLuint program, GLint location, GLfloat *params)) COGL_EXT_FUNCTION (void, glGetUniformiv, (GLuint program, GLint location, GLint *params)) COGL_EXT_FUNCTION (void, glGetActiveUniform, (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)) COGL_EXT_FUNCTION (void, glGetShaderSource, (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)) COGL_EXT_FUNCTION (void, glValidateProgram, (GLuint program)) COGL_EXT_END () /* These functions are provided by GL_ARB_vertex_shader or are in GL * 2.0 core */ COGL_EXT_BEGIN (vertex_shaders, 2, 0, COGL_EXT_IN_GLES2, "ARB\0", "vertex_shader\0") COGL_EXT_FUNCTION (void, glVertexAttribPointer, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer)) COGL_EXT_FUNCTION (void, glEnableVertexAttribArray, (GLuint index)) COGL_EXT_FUNCTION (void, glDisableVertexAttribArray, (GLuint index)) COGL_EXT_FUNCTION (void, glVertexAttrib1f, (GLuint indx, GLfloat x)) COGL_EXT_FUNCTION (void, glVertexAttrib1fv, (GLuint indx, const GLfloat* values)) COGL_EXT_FUNCTION (void, glVertexAttrib2f, (GLuint indx, GLfloat x, GLfloat y)) COGL_EXT_FUNCTION (void, glVertexAttrib2fv, (GLuint indx, const GLfloat* values)) COGL_EXT_FUNCTION (void, glVertexAttrib3f, (GLuint indx, GLfloat x, GLfloat y, GLfloat z)) COGL_EXT_FUNCTION (void, glVertexAttrib3fv, (GLuint indx, const GLfloat* values)) COGL_EXT_FUNCTION (void, glVertexAttrib4f, (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)) COGL_EXT_FUNCTION (void, glVertexAttrib4fv, (GLuint indx, const GLfloat* values)) COGL_EXT_FUNCTION (void, glGetVertexAttribfv, (GLuint index, GLenum pname, GLfloat* params)) COGL_EXT_FUNCTION (void, glGetVertexAttribiv, (GLuint index, GLenum pname, GLint* params)) COGL_EXT_FUNCTION (void, glGetVertexAttribPointerv, (GLuint index, GLenum pname, GLvoid** pointer)) COGL_EXT_FUNCTION (GLint, glGetAttribLocation, (GLuint program, const char *name)) COGL_EXT_FUNCTION (void, glBindAttribLocation, (GLuint program, GLuint index, const GLchar* name)) COGL_EXT_FUNCTION (void, glGetActiveAttrib, (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)) COGL_EXT_END () muffin-5.2.1/cogl/cogl/cogl-xlib-renderer-private.h0000664000175000017500000000655514211404421022324 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_RENDERER_XLIB_PRIVATE_H #define __COGL_RENDERER_XLIB_PRIVATE_H #include "cogl-object-private.h" #include "cogl-xlib-private.h" #include "cogl-x11-renderer-private.h" #include "cogl-context.h" #include "cogl-output.h" typedef struct _CoglXlibRenderer { CoglX11Renderer _parent; Display *xdpy; /* Current top of the XError trap state stack. The actual memory for these is expected to be allocated on the stack by the caller */ CoglXlibTrapState *trap_state; unsigned long outputs_update_serial; XVisualInfo *xvisinfo; } CoglXlibRenderer; CoglBool _cogl_xlib_renderer_connect (CoglRenderer *renderer, CoglError **error); void _cogl_xlib_renderer_disconnect (CoglRenderer *renderer); /* * cogl_xlib_renderer_trap_errors: * @state: A temporary place to store data for the trap. * * Traps every X error until _cogl_xlib_renderer_untrap_errors() * called. You should allocate an uninitialised CoglXlibTrapState * struct on the stack to pass to this function. The same pointer * should later be passed to _cogl_xlib_renderer_untrap_errors(). * * Calls to _cogl_xlib_renderer_trap_errors() can be nested as long as * _cogl_xlib_renderer_untrap_errors() is called with the * corresponding state pointers in reverse order. */ void _cogl_xlib_renderer_trap_errors (CoglRenderer *renderer, CoglXlibTrapState *state); /* * cogl_xlib_renderer_untrap_errors: * @state: The state that was passed to _cogl_xlib_renderer_trap_errors(). * * Removes the X error trap and returns the current status. * * Return value: the trapped error code, or 0 for success */ int _cogl_xlib_renderer_untrap_errors (CoglRenderer *renderer, CoglXlibTrapState *state); CoglXlibRenderer * _cogl_xlib_renderer_get_data (CoglRenderer *renderer); int64_t _cogl_xlib_renderer_get_dispatch_timeout (CoglRenderer *renderer); CoglOutput * _cogl_xlib_renderer_output_for_rectangle (CoglRenderer *renderer, int x, int y, int width, int height); #endif /* __COGL_RENDERER_XLIB_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-boxed-value.c0000664000175000017500000002355514211404421020317 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-boxed-value.h" #include "cogl-context-private.h" #include "cogl-util-gl-private.h" CoglBool _cogl_boxed_value_equal (const CoglBoxedValue *bva, const CoglBoxedValue *bvb) { const void *pa, *pb; if (bva->type != bvb->type) return FALSE; switch (bva->type) { case COGL_BOXED_NONE: return TRUE; case COGL_BOXED_INT: if (bva->size != bvb->size || bva->count != bvb->count) return FALSE; if (bva->count == 1) { pa = bva->v.int_value; pb = bvb->v.int_value; } else { pa = bva->v.int_array; pb = bvb->v.int_array; } return !memcmp (pa, pb, sizeof (int) * bva->size * bva->count); case COGL_BOXED_FLOAT: if (bva->size != bvb->size || bva->count != bvb->count) return FALSE; if (bva->count == 1) { pa = bva->v.float_value; pb = bvb->v.float_value; } else { pa = bva->v.float_array; pb = bvb->v.float_array; } return !memcmp (pa, pb, sizeof (float) * bva->size * bva->count); case COGL_BOXED_MATRIX: if (bva->size != bvb->size || bva->count != bvb->count) return FALSE; if (bva->count == 1) { pa = bva->v.matrix; pb = bvb->v.matrix; } else { pa = bva->v.array; pb = bvb->v.array; } return !memcmp (pa, pb, sizeof (float) * bva->size * bva->size * bva->count); } g_warn_if_reached (); return FALSE; } static void _cogl_boxed_value_tranpose (float *dst, int size, const float *src) { int y, x; /* If the value is transposed we'll just transpose it now as it * is copied into the boxed value instead of passing TRUE to * glUniformMatrix because that is not supported on GLES and it * doesn't seem like the GL driver would be able to do anything * much smarter than this anyway */ for (y = 0; y < size; y++) for (x = 0; x < size; x++) *(dst++) = src[y + x * size]; } static void _cogl_boxed_value_set_x (CoglBoxedValue *bv, int size, int count, CoglBoxedType type, size_t value_size, const void *value, CoglBool transpose) { if (count == 1) { if (bv->count > 1) free (bv->v.array); if (transpose) _cogl_boxed_value_tranpose (bv->v.float_value, size, value); else memcpy (bv->v.float_value, value, value_size); } else { if (bv->count > 1) { if (bv->count != count || bv->size != size || bv->type != type) { free (bv->v.array); bv->v.array = malloc (count * value_size); } } else bv->v.array = malloc (count * value_size); if (transpose) { int value_num; for (value_num = 0; value_num < count; value_num++) _cogl_boxed_value_tranpose (bv->v.float_array + value_num * size * size, size, (const float *) value + value_num * size * size); } else memcpy (bv->v.array, value, count * value_size); } bv->type = type; bv->size = size; bv->count = count; } void _cogl_boxed_value_set_1f (CoglBoxedValue *bv, float value) { _cogl_boxed_value_set_x (bv, 1, 1, COGL_BOXED_FLOAT, sizeof (float), &value, FALSE); } void _cogl_boxed_value_set_1i (CoglBoxedValue *bv, int value) { _cogl_boxed_value_set_x (bv, 1, 1, COGL_BOXED_INT, sizeof (int), &value, FALSE); } void _cogl_boxed_value_set_float (CoglBoxedValue *bv, int n_components, int count, const float *value) { _cogl_boxed_value_set_x (bv, n_components, count, COGL_BOXED_FLOAT, sizeof (float) * n_components, value, FALSE); } void _cogl_boxed_value_set_int (CoglBoxedValue *bv, int n_components, int count, const int *value) { _cogl_boxed_value_set_x (bv, n_components, count, COGL_BOXED_INT, sizeof (int) * n_components, value, FALSE); } void _cogl_boxed_value_set_matrix (CoglBoxedValue *bv, int dimensions, int count, CoglBool transpose, const float *value) { _cogl_boxed_value_set_x (bv, dimensions, count, COGL_BOXED_MATRIX, sizeof (float) * dimensions * dimensions, value, transpose); } void _cogl_boxed_value_copy (CoglBoxedValue *dst, const CoglBoxedValue *src) { *dst = *src; if (src->count > 1) { switch (src->type) { case COGL_BOXED_NONE: break; case COGL_BOXED_INT: dst->v.int_array = g_memdup (src->v.int_array, src->size * src->count * sizeof (int)); break; case COGL_BOXED_FLOAT: dst->v.float_array = g_memdup (src->v.float_array, src->size * src->count * sizeof (float)); break; case COGL_BOXED_MATRIX: dst->v.float_array = g_memdup (src->v.float_array, src->size * src->size * src->count * sizeof (float)); break; } } } void _cogl_boxed_value_destroy (CoglBoxedValue *bv) { if (bv->count > 1) free (bv->v.array); } void _cogl_boxed_value_set_uniform (CoglContext *ctx, GLint location, const CoglBoxedValue *value) { switch (value->type) { case COGL_BOXED_NONE: break; case COGL_BOXED_INT: { const int *ptr; if (value->count == 1) ptr = value->v.int_value; else ptr = value->v.int_array; switch (value->size) { case 1: GE( ctx, glUniform1iv (location, value->count, ptr) ); break; case 2: GE( ctx, glUniform2iv (location, value->count, ptr) ); break; case 3: GE( ctx, glUniform3iv (location, value->count, ptr) ); break; case 4: GE( ctx, glUniform4iv (location, value->count, ptr) ); break; } } break; case COGL_BOXED_FLOAT: { const float *ptr; if (value->count == 1) ptr = value->v.float_value; else ptr = value->v.float_array; switch (value->size) { case 1: GE( ctx, glUniform1fv (location, value->count, ptr) ); break; case 2: GE( ctx, glUniform2fv (location, value->count, ptr) ); break; case 3: GE( ctx, glUniform3fv (location, value->count, ptr) ); break; case 4: GE( ctx, glUniform4fv (location, value->count, ptr) ); break; } } break; case COGL_BOXED_MATRIX: { const float *ptr; if (value->count == 1) ptr = value->v.matrix; else ptr = value->v.float_array; switch (value->size) { case 2: GE( ctx, glUniformMatrix2fv (location, value->count, FALSE, ptr) ); break; case 3: GE( ctx, glUniformMatrix3fv (location, value->count, FALSE, ptr) ); break; case 4: GE( ctx, glUniformMatrix4fv (location, value->count, FALSE, ptr) ); break; } } break; } } muffin-5.2.1/cogl/cogl/cogl-flags.h0000664000175000017500000001173014211404421017175 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #ifndef __COGL_FLAGS_H #define __COGL_FLAGS_H #include #include "cogl-util.h" COGL_BEGIN_DECLS /* These are macros used to implement a fixed-size array of bits. This should be used instead of CoglBitmask when the maximum bit number that will be set is known at compile time, for example when setting for recording a set of known available features */ /* The bits are stored in an array of unsigned longs. To use these macros, you would typically have an enum defining the available bits with an extra last enum to define the maximum value. Then to store the flags you would declare an array of unsigned longs sized using COGL_FLAGS_N_LONGS_FOR_SIZE, eg: typedef enum { FEATURE_A, FEATURE_B, FEATURE_C, N_FEATURES } Features; unsigned long feature_flags[COGL_FLAGS_N_LONGS_FOR_SIZE (N_FEATURES)]; */ #define COGL_FLAGS_N_LONGS_FOR_SIZE(size) \ (((size) + \ (sizeof (unsigned long) * 8 - 1)) \ / (sizeof (unsigned long) * 8)) /* @flag is expected to be constant so these should result in a constant expression. This means that setting a flag is equivalent to just setting in a bit in a global variable at a known location */ #define COGL_FLAGS_GET_INDEX(flag) \ ((flag) / (sizeof (unsigned long) * 8)) #define COGL_FLAGS_GET_MASK(flag) \ (1UL << ((unsigned long) (flag) & \ (sizeof (unsigned long) * 8 - 1))) #define COGL_FLAGS_GET(array, flag) \ (!!((array)[COGL_FLAGS_GET_INDEX (flag)] & \ COGL_FLAGS_GET_MASK (flag))) /* The expectation here is that @value will be constant so the if statement will be optimised out */ #define COGL_FLAGS_SET(array, flag, value) \ G_STMT_START { \ if (value) \ ((array)[COGL_FLAGS_GET_INDEX (flag)] |= \ COGL_FLAGS_GET_MASK (flag)); \ else \ ((array)[COGL_FLAGS_GET_INDEX (flag)] &= \ ~COGL_FLAGS_GET_MASK (flag)); \ } G_STMT_END /* Macros to help iterate an array of flags. It should be used like * this: * * int n_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (...); * unsigned long flags[n_longs]; * int bit_num; * * COGL_FLAGS_FOREACH_START (flags, n_longs, bit_num) * { * do_something_with_the_bit (bit_num); * } * COGL_FLAGS_FOREACH_END; */ #define COGL_FLAGS_FOREACH_START(array, n_longs, bit) \ G_STMT_START { \ const unsigned long *_p = (array); \ int _n_longs = (n_longs); \ int _i; \ \ for (_i = 0; _i < _n_longs; _i++) \ { \ unsigned long _mask = *(_p++); \ \ (bit) = _i * sizeof (unsigned long) * 8 - 1; \ \ while (_mask) \ { \ int _next_bit = _cogl_util_ffsl (_mask); \ (bit) += _next_bit; \ /* This odd two-part shift is to avoid */ \ /* shifting by sizeof (long)*8 which has */ \ /* undefined results according to the */ \ /* C spec (and seems to be a no-op in */ \ /* practice) */ \ _mask = (_mask >> (_next_bit - 1)) >> 1; \ #define COGL_FLAGS_FOREACH_END \ } } } G_STMT_END COGL_END_DECLS #endif /* __COGL_FLAGS_H */ muffin-5.2.1/cogl/cogl/cogl-pipeline-hash-table.h0000664000175000017500000000570714211404421021723 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PIPELINE_HASH_H__ #define __COGL_PIPELINE_HASH_H__ #include "cogl-pipeline-cache.h" typedef struct { /* Total number of pipelines that were ever added to the hash. This * is not decremented when a pipeline is removed. It is only used to * generate a warning if an unusually high number of pipelines are * generated */ int n_unique_pipelines; /* This is the expected minimum size we could prune the hash table * to if we were to remove all pipelines that are not in use. This * is only updated after we prune the table */ int expected_min_size; /* String that will be used to describe the usage of this hash table * in the debug warning when too many pipelines are generated. This * must be a static string because it won't be copied or freed */ const char *debug_string; unsigned int main_state; unsigned int layer_state; GHashTable *table; } CoglPipelineHashTable; void _cogl_pipeline_hash_table_init (CoglPipelineHashTable *hash, unsigned int main_state, unsigned int layer_state, const char *debug_string); void _cogl_pipeline_hash_table_destroy (CoglPipelineHashTable *hash); /* * Gets a pipeline from the hash that has the same state as * @key_pipeline according to the limited state bits passed to * _cogl_pipeline_hash_table_init(). If there is no matching pipelines * already then a copy of key_pipeline is stored in the hash so that * it will be used next time the function is called with a similar * pipeline. In that case the copy itself will be returned */ CoglPipelineCacheEntry * _cogl_pipeline_hash_table_get (CoglPipelineHashTable *hash, CoglPipeline *key_pipeline); #endif /* __COGL_PIPELINE_HASH_H__ */ muffin-5.2.1/cogl/cogl/cogl-index-buffer-private.h0000664000175000017500000000266414211404421022135 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_INDEX_BUFFER_PRIVATE_H #define __COGL_INDEX_BUFFER_PRIVATE_H #include "cogl-buffer-private.h" struct _CoglIndexBuffer { CoglBuffer _parent; }; #endif /* __COGL_INDEX_BUFFER_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-primitives.c0000664000175000017500000011567114211404421020300 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-context-private.h" #include "cogl-journal-private.h" #include "cogl-texture-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-vertex-buffer-private.h" #include "cogl-framebuffer-private.h" #include "cogl-attribute-private.h" #include "cogl-private.h" #include "cogl-meta-texture.h" #include "cogl-framebuffer-private.h" #include "cogl1-context.h" #include "cogl-primitives-private.h" #include #include #define _COGL_MAX_BEZ_RECURSE_DEPTH 16 typedef struct _TextureSlicedQuadState { CoglFramebuffer *framebuffer; CoglPipeline *pipeline; CoglTexture *main_texture; float tex_virtual_origin_x; float tex_virtual_origin_y; float quad_origin_x; float quad_origin_y; float v_to_q_scale_x; float v_to_q_scale_y; float quad_len_x; float quad_len_y; CoglBool flipped_x; CoglBool flipped_y; } TextureSlicedQuadState; typedef struct _TextureSlicedPolygonState { const CoglTextureVertex *vertices; int n_vertices; int stride; CoglAttribute **attributes; } TextureSlicedPolygonState; static void log_quad_sub_textures_cb (CoglTexture *texture, const float *subtexture_coords, const float *virtual_coords, void *user_data) { TextureSlicedQuadState *state = user_data; CoglFramebuffer *framebuffer = state->framebuffer; CoglTexture *texture_override; float quad_coords[4]; #define TEX_VIRTUAL_TO_QUAD(V, Q, AXIS) \ do { \ Q = V - state->tex_virtual_origin_##AXIS; \ Q *= state->v_to_q_scale_##AXIS; \ if (state->flipped_##AXIS) \ Q = state->quad_len_##AXIS - Q; \ Q += state->quad_origin_##AXIS; \ } while (0); TEX_VIRTUAL_TO_QUAD (virtual_coords[0], quad_coords[0], x); TEX_VIRTUAL_TO_QUAD (virtual_coords[1], quad_coords[1], y); TEX_VIRTUAL_TO_QUAD (virtual_coords[2], quad_coords[2], x); TEX_VIRTUAL_TO_QUAD (virtual_coords[3], quad_coords[3], y); #undef TEX_VIRTUAL_TO_QUAD COGL_NOTE (DRAW, "~~~~~ slice\n" "qx1: %f\t" "qy1: %f\n" "qx2: %f\t" "qy2: %f\n" "tx1: %f\t" "ty1: %f\n" "tx2: %f\t" "ty2: %f\n", quad_coords[0], quad_coords[1], quad_coords[2], quad_coords[3], subtexture_coords[0], subtexture_coords[1], subtexture_coords[2], subtexture_coords[3]); /* We only need to override the texture if it's different from the main texture */ if (texture == state->main_texture) texture_override = NULL; else texture_override = texture; _cogl_journal_log_quad (framebuffer->journal, quad_coords, state->pipeline, 1, /* one layer */ texture_override, /* replace the layer0 texture */ subtexture_coords, 4); } typedef struct _ValidateFirstLayerState { CoglPipeline *override_pipeline; } ValidateFirstLayerState; static CoglBool validate_first_layer_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { ValidateFirstLayerState *state = user_data; CoglPipelineWrapMode clamp_to_edge = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; CoglPipelineWrapMode wrap_s; CoglPipelineWrapMode wrap_t; /* We can't use hardware repeat so we need to set clamp to edge * otherwise it might pull in edge pixels from the other side. By * default WRAP_MODE_AUTOMATIC becomes CLAMP_TO_EDGE so we only need * to override if the wrap mode isn't already automatic or * clamp_to_edge. */ wrap_s = cogl_pipeline_get_layer_wrap_mode_s (pipeline, layer_index); if (wrap_s != COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE && wrap_s != COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { if (!state->override_pipeline) state->override_pipeline = cogl_pipeline_copy (pipeline); cogl_pipeline_set_layer_wrap_mode_s (state->override_pipeline, layer_index, clamp_to_edge); } wrap_t = cogl_pipeline_get_layer_wrap_mode_t (pipeline, layer_index); if (wrap_t != COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE && wrap_t != COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { if (!state->override_pipeline) state->override_pipeline = cogl_pipeline_copy (pipeline); cogl_pipeline_set_layer_wrap_mode_t (state->override_pipeline, layer_index, clamp_to_edge); } return FALSE; } /* This path doesn't currently support multitexturing but is used for * CoglTextures that don't support repeating using the GPU so we need to * manually emit extra geometry to fake the repeating. This includes: * * - CoglTexture2DSliced: when made of > 1 slice or if the users given * texture coordinates require repeating, * - CoglTexture2DAtlas: if the users given texture coordinates require * repeating, * - CoglTextureRectangle: if the users given texture coordinates require * repeating, * - CoglTexturePixmap: if the users given texture coordinates require * repeating */ /* TODO: support multitexturing */ static void _cogl_texture_quad_multiple_primitives (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglTexture *texture, int layer_index, const float *position, float tx_1, float ty_1, float tx_2, float ty_2) { TextureSlicedQuadState state; CoglBool tex_virtual_flipped_x; CoglBool tex_virtual_flipped_y; CoglBool quad_flipped_x; CoglBool quad_flipped_y; ValidateFirstLayerState validate_first_layer_state; CoglPipelineWrapMode wrap_s, wrap_t; wrap_s = cogl_pipeline_get_layer_wrap_mode_s (pipeline, layer_index); wrap_t = cogl_pipeline_get_layer_wrap_mode_t (pipeline, layer_index); validate_first_layer_state.override_pipeline = NULL; cogl_pipeline_foreach_layer (pipeline, validate_first_layer_cb, &validate_first_layer_state); state.framebuffer = framebuffer; state.main_texture = texture; if (validate_first_layer_state.override_pipeline) state.pipeline = validate_first_layer_state.override_pipeline; else state.pipeline = pipeline; /* Get together the data we need to transform the virtual texture * coordinates of each slice into quad coordinates... * * NB: We need to consider that the quad coordinates and the texture * coordinates may be inverted along the x or y axis, and must preserve the * inversions when we emit the final geometry. */ #define X0 0 #define Y0 1 #define X1 2 #define Y1 3 tex_virtual_flipped_x = (tx_1 > tx_2) ? TRUE : FALSE; tex_virtual_flipped_y = (ty_1 > ty_2) ? TRUE : FALSE; state.tex_virtual_origin_x = tex_virtual_flipped_x ? tx_2 : tx_1; state.tex_virtual_origin_y = tex_virtual_flipped_y ? ty_2 : ty_1; quad_flipped_x = (position[X0] > position[X1]) ? TRUE : FALSE; quad_flipped_y = (position[Y0] > position[Y1]) ? TRUE : FALSE; state.quad_origin_x = quad_flipped_x ? position[X1] : position[X0]; state.quad_origin_y = quad_flipped_y ? position[Y1] : position[Y0]; /* flatten the two forms of coordinate inversion into one... */ state.flipped_x = tex_virtual_flipped_x ^ quad_flipped_x; state.flipped_y = tex_virtual_flipped_y ^ quad_flipped_y; /* We use the _len_AXIS naming here instead of _width and _height because * log_quad_slice_cb uses a macro with symbol concatenation to handle both * axis, so this is more convenient... */ state.quad_len_x = fabs (position[X1] - position[X0]); state.quad_len_y = fabs (position[Y1] - position[Y0]); #undef X0 #undef Y0 #undef X1 #undef Y1 state.v_to_q_scale_x = fabs (state.quad_len_x / (tx_2 - tx_1)); state.v_to_q_scale_y = fabs (state.quad_len_y / (ty_2 - ty_1)); /* For backwards compatablity the default wrap mode for cogl_rectangle() is * _REPEAT... */ if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT; if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT; cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (texture), tx_1, ty_1, tx_2, ty_2, wrap_s, wrap_t, log_quad_sub_textures_cb, &state); if (validate_first_layer_state.override_pipeline) cogl_object_unref (validate_first_layer_state.override_pipeline); } typedef struct _ValidateTexCoordsState { int i; int n_layers; const float *user_tex_coords; int user_tex_coords_len; float *final_tex_coords; CoglPipeline *override_pipeline; CoglBool needs_multiple_primitives; } ValidateTexCoordsState; /* * Validate the texture coordinates for this rectangle. */ static CoglBool validate_tex_coords_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { ValidateTexCoordsState *state = user_data; CoglTexture *texture; const float *in_tex_coords; float *out_tex_coords; float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0}; CoglTransformResult transform_result; state->i++; /* FIXME: we should be able to avoid this copying when no * transform is required by the texture backend and the user * has supplied enough coordinates for all the layers. */ /* If the user didn't supply texture coordinates for this layer then use the default coords */ if (state->i >= state->user_tex_coords_len / 4) in_tex_coords = default_tex_coords; else in_tex_coords = &state->user_tex_coords[state->i * 4]; out_tex_coords = &state->final_tex_coords[state->i * 4]; memcpy (out_tex_coords, in_tex_coords, sizeof (float) * 4); texture = cogl_pipeline_get_layer_texture (pipeline, layer_index); /* NB: NULL textures are handled by _cogl_pipeline_flush_gl_state */ if (!texture) return TRUE; /* Convert the texture coordinates to GL. */ transform_result = _cogl_texture_transform_quad_coords_to_gl (texture, out_tex_coords); /* If the texture has waste or we are using GL_TEXTURE_RECT we * can't handle texture repeating so we can't use the layer if * repeating is required. * * NB: We already know that no texture matrix is being used if the * texture doesn't support hardware repeat. */ if (transform_result == COGL_TRANSFORM_SOFTWARE_REPEAT) { if (state->i == 0) { if (state->n_layers > 1) { static CoglBool warning_seen = FALSE; if (!warning_seen) g_warning ("Skipping layers 1..n of your material since " "the first layer doesn't support hardware " "repeat (e.g. because of waste or use of " "GL_TEXTURE_RECTANGLE_ARB) and you supplied " "texture coordinates outside the range [0,1]." "Falling back to software repeat assuming " "layer 0 is the most important one keep"); warning_seen = TRUE; } if (state->override_pipeline) cogl_object_unref (state->override_pipeline); state->needs_multiple_primitives = TRUE; return FALSE; } else { static CoglBool warning_seen = FALSE; if (!warning_seen) g_warning ("Skipping layer %d of your material " "since you have supplied texture coords " "outside the range [0,1] but the texture " "doesn't support hardware repeat (e.g. " "because of waste or use of " "GL_TEXTURE_RECTANGLE_ARB). This isn't " "supported with multi-texturing.", state->i); warning_seen = TRUE; cogl_pipeline_set_layer_texture (pipeline, layer_index, NULL); } } /* By default WRAP_MODE_AUTOMATIC becomes to CLAMP_TO_EDGE. If the texture coordinates need repeating then we'll override this to GL_REPEAT. Otherwise we'll leave it at CLAMP_TO_EDGE so that it won't blend in pixels from the opposite side when the full texture is drawn with GL_LINEAR filter mode */ if (transform_result == COGL_TRANSFORM_HARDWARE_REPEAT) { if (cogl_pipeline_get_layer_wrap_mode_s (pipeline, layer_index) == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { if (!state->override_pipeline) state->override_pipeline = cogl_pipeline_copy (pipeline); cogl_pipeline_set_layer_wrap_mode_s (state->override_pipeline, layer_index, COGL_PIPELINE_WRAP_MODE_REPEAT); } if (cogl_pipeline_get_layer_wrap_mode_t (pipeline, layer_index) == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { if (!state->override_pipeline) state->override_pipeline = cogl_pipeline_copy (pipeline); cogl_pipeline_set_layer_wrap_mode_t (state->override_pipeline, layer_index, COGL_PIPELINE_WRAP_MODE_REPEAT); } } return TRUE; } /* This path supports multitexturing but only when each of the layers is * handled with a single GL texture. Also if repeating is necessary then * _cogl_texture_can_hardware_repeat() must return TRUE. * This includes layers made from: * * - CoglTexture2DSliced: if only comprised of a single slice with optional * waste, assuming the users given texture coordinates don't require * repeating. * - CoglTexture{1D,2D,3D}: always. * - CoglTexture2DAtlas: assuming the users given texture coordinates don't * require repeating. * - CoglTextureRectangle: assuming the users given texture coordinates don't * require repeating. * - CoglTexturePixmap: assuming the users given texture coordinates don't * require repeating. */ static CoglBool _cogl_multitexture_quad_single_primitive (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, const float *position, const float *user_tex_coords, int user_tex_coords_len) { int n_layers = cogl_pipeline_get_n_layers (pipeline); ValidateTexCoordsState state; float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); state.i = -1; state.n_layers = n_layers; state.user_tex_coords = user_tex_coords; state.user_tex_coords_len = user_tex_coords_len; state.final_tex_coords = final_tex_coords; state.override_pipeline = NULL; state.needs_multiple_primitives = FALSE; cogl_pipeline_foreach_layer (pipeline, validate_tex_coords_cb, &state); if (state.needs_multiple_primitives) return FALSE; if (state.override_pipeline) pipeline = state.override_pipeline; _cogl_journal_log_quad (framebuffer->journal, position, pipeline, n_layers, NULL, /* no texture override */ final_tex_coords, n_layers * 4); if (state.override_pipeline) cogl_object_unref (state.override_pipeline); return TRUE; } typedef struct _ValidateLayerState { CoglContext *ctx; int i; int first_layer; CoglPipeline *override_source; CoglBool all_use_sliced_quad_fallback; } ValidateLayerState; static CoglBool _cogl_rectangles_validate_layer_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { ValidateLayerState *state = user_data; CoglTexture *texture; state->i++; /* We need to ensure the mipmaps are ready before deciding * anything else about the texture because the texture storage * could completely change if it needs to be migrated out of the * atlas and will affect how we validate the layer. * * FIXME: this needs to be generalized. There could be any * number of things that might require a shuffling of the * underlying texture storage. We could add two mechanisms to * generalize this a bit... * * 1) add a _cogl_pipeline_layer_update_storage() function that * would for instance consider if mipmapping is necessary and * potentially migrate the texture from an atlas. * * 2) allow setting of transient primitive-flags on a pipeline * that may affect the outcome of _update_storage(). One flag * could indicate that we expect to sample beyond the bounds of * the texture border. * * flags = COGL_PIPELINE_PRIMITIVE_FLAG_VALID_BORDERS; * _cogl_pipeline_layer_assert_primitive_flags (layer, flags) * _cogl_pipeline_layer_update_storage (layer) * enqueue primitive in journal * * when the primitive is dequeued and drawn we should: * _cogl_pipeline_flush_gl_state (pipeline) * draw primitive * _cogl_pipeline_unassert_primitive_flags (layer, flags); * * _cogl_pipeline_layer_update_storage should take into * consideration all the asserted primitive requirements. (E.g. * there could be multiple primitives in the journal - or in a * renderlist in the future - that need mipmaps or that need * valid contents beyond their borders (for cogl_polygon) * meaning they can't work with textures in an atas, so * _cogl_pipeline_layer_update_storage would pass on these * requirements to the texture atlas backend which would make * sure the referenced texture is migrated out of the atlas and * mipmaps are generated.) */ _cogl_pipeline_pre_paint_for_layer (pipeline, layer_index); texture = cogl_pipeline_get_layer_texture (pipeline, layer_index); /* NULL textures are handled by * _cogl_pipeline_flush_gl_state */ if (texture == NULL) return TRUE; if (state->i == 0) state->first_layer = layer_index; /* XXX: * For now, if the first layer is sliced then all other layers are * ignored since we currently don't support multi-texturing with * sliced textures. If the first layer is not sliced then any other * layers found to be sliced will be skipped. (with a warning) * * TODO: Add support for multi-texturing rectangles with sliced * textures if no texture matrices are in use. */ if (cogl_texture_is_sliced (texture)) { if (state->i == 0) { if (cogl_pipeline_get_n_layers (pipeline) > 1) { static CoglBool warning_seen = FALSE; if (!state->override_source) state->override_source = cogl_pipeline_copy (pipeline); _cogl_pipeline_prune_to_n_layers (state->override_source, 1); if (!warning_seen) g_warning ("Skipping layers 1..n of your pipeline since " "the first layer is sliced. We don't currently " "support any multi-texturing with sliced " "textures but assume layer 0 is the most " "important to keep"); warning_seen = TRUE; } state->all_use_sliced_quad_fallback = TRUE; return FALSE; } else { static CoglBool warning_seen = FALSE; CoglTexture2D *tex_2d; if (!warning_seen) g_warning ("Skipping layer %d of your pipeline consisting of " "a sliced texture (unsupported for multi texturing)", state->i); warning_seen = TRUE; /* Note: currently only 2D textures can be sliced. */ tex_2d = state->ctx->default_gl_texture_2d_tex; cogl_pipeline_set_layer_texture (pipeline, layer_index, COGL_TEXTURE (tex_2d)); return TRUE; } } #ifdef COGL_ENABLE_DEBUG /* If the texture can't be repeated with the GPU (e.g. because it has * waste or if using GL_TEXTURE_RECTANGLE_ARB) then if a texture matrix * is also in use we don't know if the result will end up trying * to texture from the waste area. * * Note: we check can_hardware_repeat() first since it's cheaper. * * Note: cases where the texture coordinates will require repeating * will be caught by later validation. */ if (!_cogl_texture_can_hardware_repeat (texture) && _cogl_pipeline_layer_has_user_matrix (pipeline, layer_index)) { static CoglBool warning_seen = FALSE; if (!warning_seen) g_warning ("layer %d of your pipeline uses a custom " "texture matrix but because the texture doesn't " "support hardware repeating you may see artefacts " "due to sampling beyond the texture's bounds.", state->i); warning_seen = TRUE; } #endif return TRUE; } void _cogl_framebuffer_draw_multitextured_rectangles ( CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglMultiTexturedRect *rects, int n_rects, CoglBool disable_legacy_state) { CoglContext *ctx = framebuffer->context; CoglPipeline *original_pipeline; ValidateLayerState state; int i; original_pipeline = pipeline; /* * Validate all the layers of the current source pipeline... */ state.ctx = ctx; state.i = -1; state.first_layer = 0; state.override_source = NULL; state.all_use_sliced_quad_fallback = FALSE; cogl_pipeline_foreach_layer (pipeline, _cogl_rectangles_validate_layer_cb, &state); if (state.override_source) pipeline = state.override_source; if (!disable_legacy_state) { if (G_UNLIKELY (ctx->legacy_state_set) && _cogl_get_enable_legacy_state ()) { /* If we haven't already made a pipeline copy */ if (pipeline == original_pipeline) pipeline = cogl_pipeline_copy (pipeline); _cogl_pipeline_apply_legacy_state (pipeline); } } /* * Emit geometry for each of the rectangles... */ for (i = 0; i < n_rects; i++) { CoglTexture *texture; const float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0}; const float *tex_coords; if (!state.all_use_sliced_quad_fallback) { CoglBool success = _cogl_multitexture_quad_single_primitive (framebuffer, pipeline, rects[i].position, rects[i].tex_coords, rects[i].tex_coords_len); /* NB: If _cogl_multitexture_quad_single_primitive fails then it * means the user tried to use texture repeat with a texture that * can't be repeated by the GPU (e.g. due to waste or use of * GL_TEXTURE_RECTANGLE_ARB) */ if (success) continue; } /* If multitexturing failed or we are drawing with a sliced texture * then we only support a single layer so we pluck out the texture * from the first pipeline layer... */ texture = cogl_pipeline_get_layer_texture (pipeline, state.first_layer); if (rects[i].tex_coords) tex_coords = rects[i].tex_coords; else tex_coords = default_tex_coords; COGL_NOTE (DRAW, "Drawing Tex Quad (Multi-Prim Mode)"); _cogl_texture_quad_multiple_primitives (framebuffer, pipeline, texture, state.first_layer, rects[i].position, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]); } if (pipeline != original_pipeline) cogl_object_unref (pipeline); } static void _cogl_rectangles_with_multitexture_coords ( CoglMultiTexturedRect *rects, int n_rects) { _cogl_framebuffer_draw_multitextured_rectangles (cogl_get_draw_framebuffer (), cogl_get_source (), rects, n_rects, FALSE); } void cogl_rectangles (const float *verts, unsigned int n_rects) { CoglMultiTexturedRect *rects; int i; /* XXX: All the cogl_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_rectangles_with_multitexture_coords. */ rects = g_alloca (n_rects * sizeof (CoglMultiTexturedRect)); for (i = 0; i < n_rects; i++) { rects[i].position = &verts[i * 4]; rects[i].tex_coords = NULL; rects[i].tex_coords_len = 0; } _cogl_rectangles_with_multitexture_coords (rects, n_rects); } void cogl_rectangles_with_texture_coords (const float *verts, unsigned int n_rects) { CoglMultiTexturedRect *rects; int i; /* XXX: All the cogl_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_rectangles_with_multitexture_coords. */ rects = g_alloca (n_rects * sizeof (CoglMultiTexturedRect)); for (i = 0; i < n_rects; i++) { rects[i].position = &verts[i * 8]; rects[i].tex_coords = &verts[i * 8 + 4]; rects[i].tex_coords_len = 4; } _cogl_rectangles_with_multitexture_coords (rects, n_rects); } void cogl_rectangle_with_texture_coords (float x_1, float y_1, float x_2, float y_2, float tx_1, float ty_1, float tx_2, float ty_2) { const float position[4] = {x_1, y_1, x_2, y_2}; const float tex_coords[4] = {tx_1, ty_1, tx_2, ty_2}; CoglMultiTexturedRect rect; /* XXX: All the cogl_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_rectangles_with_multitexture_coords. */ rect.position = position; rect.tex_coords = tex_coords; rect.tex_coords_len = 4; _cogl_rectangles_with_multitexture_coords (&rect, 1); } void cogl_rectangle_with_multitexture_coords (float x_1, float y_1, float x_2, float y_2, const float *user_tex_coords, int user_tex_coords_len) { const float position[4] = {x_1, y_1, x_2, y_2}; CoglMultiTexturedRect rect; /* XXX: All the cogl_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_rectangles_with_multitexture_coords. */ rect.position = position; rect.tex_coords = user_tex_coords; rect.tex_coords_len = user_tex_coords_len; _cogl_rectangles_with_multitexture_coords (&rect, 1); } void cogl_rectangle (float x_1, float y_1, float x_2, float y_2) { const float position[4] = {x_1, y_1, x_2, y_2}; CoglMultiTexturedRect rect; /* XXX: All the cogl_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_rectangles_with_multitexture_coords. */ rect.position = position; rect.tex_coords = NULL; rect.tex_coords_len = 0; _cogl_rectangles_with_multitexture_coords (&rect, 1); } void _cogl_rectangle_immediate (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2) { /* Draw a rectangle using the vertex array API to avoid going through the journal. This should only be used in cases where the code might be called while the journal is already being flushed such as when flushing the clip state */ CoglContext *ctx = framebuffer->context; float vertices[8] = { x_1, y_1, x_1, y_2, x_2, y_1, x_2, y_2 }; CoglAttributeBuffer *attribute_buffer; CoglAttribute *attributes[1]; attribute_buffer = cogl_attribute_buffer_new (ctx, sizeof (vertices), vertices); attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (float) * 2, /* stride */ 0, /* offset */ 2, /* n_components */ COGL_ATTRIBUTE_TYPE_FLOAT); _cogl_framebuffer_draw_attributes (framebuffer, pipeline, COGL_VERTICES_MODE_TRIANGLE_STRIP, 0, /* first_index */ 4, /* n_vertices */ attributes, 1, COGL_DRAW_SKIP_JOURNAL_FLUSH | COGL_DRAW_SKIP_PIPELINE_VALIDATION | COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH | COGL_DRAW_SKIP_LEGACY_STATE); cogl_object_unref (attributes[0]); cogl_object_unref (attribute_buffer); } typedef struct _AppendTexCoordsState { const CoglTextureVertex *vertices_in; int vertex; int layer; float *vertices_out; } AppendTexCoordsState; static CoglBool append_tex_coord_attributes_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { AppendTexCoordsState *state = user_data; CoglTexture *texture; float tx, ty; float *t; tx = state->vertices_in[state->vertex].tx; ty = state->vertices_in[state->vertex].ty; /* NULL textures will be handled in * _cogl_pipeline_flush_layers_gl_state but there is no need to worry * about scaling texture coordinates in this case */ texture = cogl_pipeline_get_layer_texture (pipeline, layer_index); if (texture != NULL) _cogl_texture_transform_coords_to_gl (texture, &tx, &ty); /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ t = state->vertices_out + 3 + 2 * state->layer; t[0] = tx; t[1] = ty; state->layer++; return TRUE; } typedef struct _ValidateState { CoglPipeline *original_pipeline; CoglPipeline *pipeline; } ValidateState; static CoglBool _cogl_polygon_validate_layer_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { ValidateState *state = user_data; /* By default COGL_PIPELINE_WRAP_MODE_AUTOMATIC becomes * GL_CLAMP_TO_EDGE but we want the polygon API to use GL_REPEAT to * maintain compatibility with previous releases */ if (cogl_pipeline_get_layer_wrap_mode_s (pipeline, layer_index) == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { if (state->original_pipeline == state->pipeline) state->pipeline = cogl_pipeline_copy (pipeline); cogl_pipeline_set_layer_wrap_mode_s (state->pipeline, layer_index, COGL_PIPELINE_WRAP_MODE_REPEAT); } if (cogl_pipeline_get_layer_wrap_mode_t (pipeline, layer_index) == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { if (state->original_pipeline == state->pipeline) state->pipeline = cogl_pipeline_copy (pipeline); cogl_pipeline_set_layer_wrap_mode_t (state->pipeline, layer_index, COGL_PIPELINE_WRAP_MODE_REPEAT); } return TRUE; } void cogl_polygon (const CoglTextureVertex *vertices, unsigned int n_vertices, CoglBool use_color) { CoglPipeline *pipeline; ValidateState validate_state; int n_layers; int n_attributes; CoglAttribute **attributes; int i; unsigned int stride; size_t stride_bytes; CoglAttributeBuffer *attribute_buffer; float *v; _COGL_GET_CONTEXT (ctx, NO_RETVAL); pipeline = cogl_get_source (); validate_state.original_pipeline = pipeline; validate_state.pipeline = pipeline; cogl_pipeline_foreach_layer (pipeline, _cogl_polygon_validate_layer_cb, &validate_state); pipeline = validate_state.pipeline; n_layers = cogl_pipeline_get_n_layers (pipeline); n_attributes = 1 + n_layers + (use_color ? 1 : 0); attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes); /* Our data is arranged like: * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */ stride = 3 + (2 * n_layers) + (use_color ? 1 : 0); stride_bytes = stride * sizeof (float); /* Make sure there is enough space in the global vertex array. This * is used so we can render the polygon with a single call to OpenGL * but still support any number of vertices */ g_array_set_size (ctx->polygon_vertices, n_vertices * stride); attribute_buffer = cogl_attribute_buffer_new (ctx, n_vertices * stride_bytes, NULL); attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", stride_bytes, 0, 3, COGL_ATTRIBUTE_TYPE_FLOAT); for (i = 0; i < n_layers; i++) { static const char *names[] = { "cogl_tex_coord0_in", "cogl_tex_coord1_in", "cogl_tex_coord2_in", "cogl_tex_coord3_in", "cogl_tex_coord4_in", "cogl_tex_coord5_in", "cogl_tex_coord6_in", "cogl_tex_coord7_in" }; char *allocated_name = NULL; const char *name; if (i < 8) name = names[i]; else name = allocated_name = g_strdup_printf ("cogl_tex_coord%d_in", i); attributes[i + 1] = cogl_attribute_new (attribute_buffer, name, stride_bytes, /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ 12 + 8 * i, 2, COGL_ATTRIBUTE_TYPE_FLOAT); free (allocated_name); } if (use_color) { attributes[n_attributes - 1] = cogl_attribute_new (attribute_buffer, "cogl_color_in", stride_bytes, /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ 12 + 8 * n_layers, 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); } /* Convert the vertices into an array of float vertex attributes */ v = (float *)ctx->polygon_vertices->data; for (i = 0; i < n_vertices; i++) { AppendTexCoordsState append_tex_coords_state; uint8_t *c; /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ v[0] = vertices[i].x; v[1] = vertices[i].y; v[2] = vertices[i].z; append_tex_coords_state.vertices_in = vertices; append_tex_coords_state.vertex = i; append_tex_coords_state.layer = 0; append_tex_coords_state.vertices_out = v; cogl_pipeline_foreach_layer (pipeline, append_tex_coord_attributes_cb, &append_tex_coords_state); if (use_color) { /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ c = (uint8_t *) (v + 3 + 2 * n_layers); c[0] = cogl_color_get_red_byte (&vertices[i].color); c[1] = cogl_color_get_green_byte (&vertices[i].color); c[2] = cogl_color_get_blue_byte (&vertices[i].color); c[3] = cogl_color_get_alpha_byte (&vertices[i].color); } v += stride; } v = (float *)ctx->polygon_vertices->data; cogl_buffer_set_data (COGL_BUFFER (attribute_buffer), 0, v, ctx->polygon_vertices->len * sizeof (float)); /* XXX: although this may seem redundant, we need to do this since * cogl_polygon() can be used with legacy state and its the source stack * which track whether legacy state is enabled. * * (We only have a CoglDrawFlag to disable legacy state not one * to enable it) */ cogl_push_source (pipeline); _cogl_framebuffer_draw_attributes (cogl_get_draw_framebuffer (), pipeline, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, n_vertices, attributes, n_attributes, 0 /* no draw flags */); cogl_pop_source (); if (pipeline != validate_state.original_pipeline) cogl_object_unref (pipeline); cogl_object_unref (attribute_buffer); for (i = 0; i < n_attributes; i++) cogl_object_unref (attributes[i]); } muffin-5.2.1/cogl/cogl/cogl-spans.h0000664000175000017500000000436314211404421017231 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_SPANS_PRIVATE_H #define __COGL_SPANS_PRIVATE_H #include "cogl-object-private.h" #include "cogl-pipeline-layer-state.h" typedef struct _CoglSpan { float start; float size; float waste; } CoglSpan; typedef struct _CoglSpanIter { int index; const CoglSpan *spans; int n_spans; const CoglSpan *span; float pos; float next_pos; float origin; float cover_start; float cover_end; float intersect_start; float intersect_end; CoglBool intersects; CoglBool flipped; CoglPipelineWrapMode wrap_mode; int mirror_direction; } CoglSpanIter; void _cogl_span_iter_update (CoglSpanIter *iter); void _cogl_span_iter_begin (CoglSpanIter *iter, const CoglSpan *spans, int n_spans, float normalize_factor, float cover_start, float cover_end, CoglPipelineWrapMode wrap_mode); void _cogl_span_iter_next (CoglSpanIter *iter); CoglBool _cogl_span_iter_end (CoglSpanIter *iter); #endif /* __COGL_SPANS_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-depth-state.c0000664000175000017500000000660514211404421020323 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-depth-state-private.h" #include "cogl-depth-state.h" void cogl_depth_state_init (CoglDepthState *state) { state->magic = COGL_DEPTH_STATE_MAGIC; /* The same as the GL defaults */ state->test_enabled = FALSE; state->write_enabled = TRUE; state->test_function = COGL_DEPTH_TEST_FUNCTION_LESS; state->range_near = 0; state->range_far = 1; } void cogl_depth_state_set_test_enabled (CoglDepthState *state, CoglBool enabled) { _COGL_RETURN_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC); state->test_enabled = enabled; } CoglBool cogl_depth_state_get_test_enabled (CoglDepthState *state) { _COGL_RETURN_VAL_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC, FALSE); return state->test_enabled; } void cogl_depth_state_set_write_enabled (CoglDepthState *state, CoglBool enabled) { _COGL_RETURN_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC); state->write_enabled = enabled; } CoglBool cogl_depth_state_get_write_enabled (CoglDepthState *state) { _COGL_RETURN_VAL_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC, FALSE); return state->write_enabled; } void cogl_depth_state_set_test_function (CoglDepthState *state, CoglDepthTestFunction function) { _COGL_RETURN_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC); state->test_function = function; } CoglDepthTestFunction cogl_depth_state_get_test_function (CoglDepthState *state) { _COGL_RETURN_VAL_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC, FALSE); return state->test_function; } void cogl_depth_state_set_range (CoglDepthState *state, float near, float far) { _COGL_RETURN_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC); state->range_near = near; state->range_far = far; } void cogl_depth_state_get_range (CoglDepthState *state, float *near_out, float *far_out) { _COGL_RETURN_IF_FAIL (state->magic == COGL_DEPTH_STATE_MAGIC); *near_out = state->range_near; *far_out = state->range_far; } muffin-5.2.1/cogl/cogl/cogl-closure-list.c0000664000175000017500000000406714211404421020526 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include "cogl-config.h" #include #include "cogl-closure-list-private.h" void _cogl_closure_disconnect (CoglClosure *closure) { _cogl_list_remove (&closure->link); if (closure->destroy_cb) closure->destroy_cb (closure->user_data); g_slice_free (CoglClosure, closure); } void _cogl_closure_list_disconnect_all (CoglList *list) { CoglClosure *closure, *next; _cogl_list_for_each_safe (closure, next, list, link) _cogl_closure_disconnect (closure); } CoglClosure * _cogl_closure_list_add (CoglList *list, void *function, void *user_data, CoglUserDataDestroyCallback destroy_cb) { CoglClosure *closure = g_slice_new (CoglClosure); closure->function = function; closure->user_data = user_data; closure->destroy_cb = destroy_cb; _cogl_list_insert (list, &closure->link); return closure; } muffin-5.2.1/cogl/cogl/cogl-bitmask.h0000664000175000017500000002316414211404421017537 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #ifndef __COGL_BITMASK_H #define __COGL_BITMASK_H #include #include "cogl-util.h" COGL_BEGIN_DECLS /* * CoglBitmask implements a growable array of bits. A CoglBitmask can * be allocated on the stack but it must be initialised with * _cogl_bitmask_init() before use and then destroyed with * _cogl_bitmask_destroy(). A CoglBitmask will try to avoid allocating * any memory unless more than the number of bits in a long - 1 bits * are needed. * * Internally a CoglBitmask is a pointer. If the least significant bit * of the pointer is 1 then the rest of the bits are directly used as * part of the bitmask, otherwise it is a pointer to a GArray of * unsigned ints. This relies on the fact the malloc will return a * pointer aligned to at least two bytes (so that the least * significant bit of the address is always 0). It also assumes that * the size of a pointer is always greater than or equal to the size * of a long (although there is a compile time assert to verify this). * * If the maximum possible bit number in the set is known at compile * time, it may make more sense to use the macros in cogl-flags.h * instead of this type. */ typedef struct _CoglBitmaskImaginaryType *CoglBitmask; /* These are internal helper macros */ #define _cogl_bitmask_to_number(bitmask) \ ((unsigned long) (*bitmask)) #define _cogl_bitmask_to_bits(bitmask) \ (_cogl_bitmask_to_number (bitmask) >> 1UL) /* The least significant bit is set to mark that no array has been allocated yet */ #define _cogl_bitmask_from_bits(bits) \ ((void *) ((((unsigned long) (bits)) << 1UL) | 1UL)) /* Internal helper macro to determine whether this bitmask has a GArray allocated or whether the pointer is just used directly */ #define _cogl_bitmask_has_array(bitmask) \ (!(_cogl_bitmask_to_number (bitmask) & 1UL)) /* Number of bits we can use before needing to allocate an array */ #define COGL_BITMASK_MAX_DIRECT_BITS (sizeof (unsigned long) * 8 - 1) /* * _cogl_bitmask_init: * @bitmask: A pointer to a bitmask * * Initialises the cogl bitmask. This must be called before any other * bitmask functions are called. Initially all of the values are * zero */ #define _cogl_bitmask_init(bitmask) \ G_STMT_START { *(bitmask) = _cogl_bitmask_from_bits (0); } G_STMT_END CoglBool _cogl_bitmask_get_from_array (const CoglBitmask *bitmask, unsigned int bit_num); void _cogl_bitmask_set_in_array (CoglBitmask *bitmask, unsigned int bit_num, CoglBool value); void _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask, unsigned int n_bits, CoglBool value); void _cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask); void _cogl_bitmask_set_flags_array (const CoglBitmask *bitmask, unsigned long *flags); int _cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask); int _cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask, int upto); /* * cogl_bitmask_set_bits: * @dst: The bitmask to modify * @src: The bitmask to copy bits from * * This makes sure that all of the bits that are set in @src are also * set in @dst. Any unset bits in @src are left alone in @dst. */ void _cogl_bitmask_set_bits (CoglBitmask *dst, const CoglBitmask *src); /* * cogl_bitmask_xor_bits: * @dst: The bitmask to modify * @src: The bitmask to copy bits from * * For every bit that is set in src, the corresponding bit in dst is * inverted. */ void _cogl_bitmask_xor_bits (CoglBitmask *dst, const CoglBitmask *src); /* The foreach function can return FALSE to stop iteration */ typedef CoglBool (* CoglBitmaskForeachFunc) (int bit_num, void *user_data); /* * cogl_bitmask_foreach: * @bitmask: A pointer to a bitmask * @func: A callback function * @user_data: A pointer to pass to the callback * * This calls @func for each bit that is set in @bitmask. */ void _cogl_bitmask_foreach (const CoglBitmask *bitmask, CoglBitmaskForeachFunc func, void *user_data); /* * _cogl_bitmask_get: * @bitmask: A pointer to a bitmask * @bit_num: A bit number * * Return value: whether bit number @bit_num is set in @bitmask */ static inline CoglBool _cogl_bitmask_get (const CoglBitmask *bitmask, unsigned int bit_num) { if (_cogl_bitmask_has_array (bitmask)) return _cogl_bitmask_get_from_array (bitmask, bit_num); else if (bit_num >= COGL_BITMASK_MAX_DIRECT_BITS) return FALSE; else return !!(_cogl_bitmask_to_bits (bitmask) & (1UL << bit_num)); } /* * _cogl_bitmask_set: * @bitmask: A pointer to a bitmask * @bit_num: A bit number * @value: The new value * * Sets or resets a bit number @bit_num in @bitmask according to @value. */ static inline void _cogl_bitmask_set (CoglBitmask *bitmask, unsigned int bit_num, CoglBool value) { if (_cogl_bitmask_has_array (bitmask) || bit_num >= COGL_BITMASK_MAX_DIRECT_BITS) _cogl_bitmask_set_in_array (bitmask, bit_num, value); else if (value) *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) | (1UL << bit_num)); else *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) & ~(1UL << bit_num)); } /* * _cogl_bitmask_set_range: * @bitmask: A pointer to a bitmask * @n_bits: The number of bits to set * @value: The value to set * * Sets the first @n_bits in @bitmask to @value. */ static inline void _cogl_bitmask_set_range (CoglBitmask *bitmask, unsigned int n_bits, CoglBool value) { if (_cogl_bitmask_has_array (bitmask) || n_bits > COGL_BITMASK_MAX_DIRECT_BITS) _cogl_bitmask_set_range_in_array (bitmask, n_bits, value); else if (value) *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) | ~(~0UL << n_bits)); else *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) & (~0UL << n_bits)); } /* * _cogl_bitmask_destroy: * @bitmask: A pointer to a bitmask * * Destroys any resources allocated by the bitmask */ static inline void _cogl_bitmask_destroy (CoglBitmask *bitmask) { if (_cogl_bitmask_has_array (bitmask)) g_array_free ((GArray *) *bitmask, TRUE); } /* * _cogl_bitmask_clear_all: * @bitmask: A pointer to a bitmask * * Clears all the bits in a bitmask without destroying any resources. */ static inline void _cogl_bitmask_clear_all (CoglBitmask *bitmask) { if (_cogl_bitmask_has_array (bitmask)) _cogl_bitmask_clear_all_in_array (bitmask); else *bitmask = _cogl_bitmask_from_bits (0); } /* * _cogl_bitmask_set_flags: * @bitmask: A pointer to a bitmask * @flags: An array of flags * * Bitwise or's the bits from @bitmask into the flags array (see * cogl-flags) pointed to by @flags. */ static inline void _cogl_bitmask_set_flags (const CoglBitmask *bitmask, unsigned long *flags) { if (_cogl_bitmask_has_array (bitmask)) _cogl_bitmask_set_flags_array (bitmask, flags); else flags[0] |= _cogl_bitmask_to_bits (bitmask); } /* * _cogl_bitmask_popcount: * @bitmask: A pointer to a bitmask * * Counts the number of bits that are set in the bitmask. * * Return value: the number of bits set in @bitmask. */ static inline int _cogl_bitmask_popcount (const CoglBitmask *bitmask) { return (_cogl_bitmask_has_array (bitmask) ? _cogl_bitmask_popcount_in_array (bitmask) : _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask))); } /* * _cogl_bitmask_popcount: * @Bitmask: A pointer to a bitmask * @upto: The maximum bit index to consider * * Counts the number of bits that are set and have an index which is * less than @upto. * * Return value: the number of bits set in @bitmask that are less than @upto. */ static inline int _cogl_bitmask_popcount_upto (const CoglBitmask *bitmask, int upto) { if (_cogl_bitmask_has_array (bitmask)) return _cogl_bitmask_popcount_upto_in_array (bitmask, upto); else if (upto >= (int) COGL_BITMASK_MAX_DIRECT_BITS) return _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask)); else return _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask) & ((1UL << upto) - 1)); } COGL_END_DECLS #endif /* __COGL_BITMASK_H */ muffin-5.2.1/cogl/cogl/cogl-context.h0000664000175000017500000003525614211404421017576 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_CONTEXT_H__ #define __COGL_CONTEXT_H__ /* We forward declare the CoglContext type here to avoid some circular * dependency issues with the following headers. */ typedef struct _CoglContext CoglContext; #include #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-context * @short_description: The top level application context. * * A #CoglContext is the top most sandbox of Cogl state for an * application or toolkit. Its main purpose is to act as a sandbox * for the memory management of state objects. Normally an application * will only create a single context since there is no way to share * resources between contexts. * * For those familiar with OpenGL or perhaps Cairo it should be * understood that unlike these APIs a Cogl context isn't a rendering * context as such. In other words Cogl doesn't aim to provide a state * machine style model for configuring rendering parameters. Most * rendering state in Cogl is directly associated with user managed * objects called pipelines and geometry is drawn with a specific * pipeline object to a framebuffer object and those 3 things fully * define the state for drawing. This is an important part of Cogl's * design since it helps you write orthogonal rendering components * that can all access the same GPU without having to worry about * what state other components have left you with. * * Cogl does not maintain internal references to the context for * resources that depend on the context so applications. This is to * help applications control the lifetime a context without us needing to * introduce special api to handle the breakup of internal circular * references due to internal resources and caches associated with the * context. * * One a context has been destroyed then all directly or indirectly * dependant resources will be in an inconsistent state and should not * be manipulated or queried in any way. * * For applications that rely on the operating system to clean up * resources this policy shouldn't affect them, but for applications * that need to carefully destroy and re-create Cogl contexts multiple * times throughout their lifetime (such as Android applications) they * should be careful to destroy all context dependant resources, such as * framebuffers or textures etc before unrefing and destroying the * context. */ #define COGL_CONTEXT(OBJECT) ((CoglContext *)OBJECT) /** * cogl_context_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_context_get_gtype (void); /** * cogl_context_new: (constructor) * @display: (allow-none): A #CoglDisplay pointer * @error: A CoglError return location. * * Creates a new #CoglContext which acts as an application sandbox * for any state objects that are allocated. * * Return value: (transfer full): A newly allocated #CoglContext * Since: 1.8 * Stability: unstable */ CoglContext * cogl_context_new (CoglDisplay *display, CoglError **error); /** * cogl_context_get_display: * @context: A #CoglContext pointer * * Retrieves the #CoglDisplay that is internally associated with the * given @context. This will return the same #CoglDisplay that was * passed to cogl_context_new() or if %NULL was passed to * cogl_context_new() then this function returns a pointer to the * display that was automatically setup internally. * * Return value: (transfer none): The #CoglDisplay associated with the * given @context. * Since: 1.8 * Stability: unstable */ CoglDisplay * cogl_context_get_display (CoglContext *context); /** * cogl_context_get_renderer: * @context: A #CoglContext pointer * * Retrieves the #CoglRenderer that is internally associated with the * given @context. This will return the same #CoglRenderer that was * passed to cogl_display_new() or if %NULL was passed to * cogl_display_new() or cogl_context_new() then this function returns * a pointer to the renderer that was automatically connected * internally. * * Return value: (transfer none): The #CoglRenderer associated with the * given @context. * Since: 1.16 * Stability: unstable */ CoglRenderer * cogl_context_get_renderer (CoglContext *context); /** * cogl_is_context: * @object: An object or %NULL * * Gets whether the given object references an existing context object. * * Return value: %TRUE if the @object references a #CoglContext, * %FALSE otherwise * * Since: 1.10 * Stability: Unstable */ CoglBool cogl_is_context (void *object); /* XXX: not guarded by the EXPERIMENTAL_API defines to avoid * upsetting glib-mkenums, but this can still be considered implicitly * experimental since it's only useable with experimental API... */ /** * CoglFeatureID: * @COGL_FEATURE_ID_TEXTURE_NPOT_BASIC: The hardware supports non power * of two textures, but you also need to check the * %COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP and %COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT * features to know if the hardware supports npot texture mipmaps * or repeat modes other than * %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE respectively. * @COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP: Mipmapping is supported in * conjuntion with non power of two textures. * @COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT: Repeat modes other than * %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE are supported by the * hardware. * @COGL_FEATURE_ID_TEXTURE_NPOT: Non power of two textures are supported * by the hardware. This is a equivalent to the * %COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, %COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP * and %COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT features combined. * @COGL_FEATURE_ID_TEXTURE_RECTANGLE: Support for rectangular * textures with non-normalized texture coordinates. * @COGL_FEATURE_ID_TEXTURE_RG: Support for * %COGL_TEXTURE_COMPONENTS_RG as the internal components of a * texture. * @COGL_FEATURE_ID_TEXTURE_3D: 3D texture support * @COGL_FEATURE_ID_OFFSCREEN: Offscreen rendering support * @COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE: Multisample support for * offscreen framebuffers * @COGL_FEATURE_ID_ONSCREEN_MULTIPLE: Multiple onscreen framebuffers * supported. * @COGL_FEATURE_ID_GLSL: GLSL support * @COGL_FEATURE_ID_ARBFP: ARBFP support * @COGL_FEATURE_ID_UNSIGNED_INT_INDICES: Set if * %COGL_INDICES_TYPE_UNSIGNED_INT is supported in * cogl_indices_new(). * @COGL_FEATURE_ID_DEPTH_RANGE: cogl_pipeline_set_depth_range() support * @COGL_FEATURE_ID_POINT_SPRITE: Whether * cogl_pipeline_set_layer_point_sprite_coords_enabled() is supported. * @COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE: Whether cogl_point_size_in * can be used as an attribute to set a per-vertex point size. * @COGL_FEATURE_ID_MAP_BUFFER_FOR_READ: Whether cogl_buffer_map() is * supported with CoglBufferAccess including read support. * @COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE: Whether cogl_buffer_map() is * supported with CoglBufferAccess including write support. * @COGL_FEATURE_ID_MIRRORED_REPEAT: Whether * %COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT is supported. * @COGL_FEATURE_ID_SWAP_BUFFERS_EVENT: * Available if the window system supports reporting an event * for swap buffer completions. * @COGL_FEATURE_ID_BUFFER_AGE: Available if the age of #CoglOnscreen back * buffers are tracked and so cogl_onscreen_get_buffer_age() can be * expected to return age values other than 0. * @COGL_FEATURE_ID_GLES2_CONTEXT: Whether creating new GLES2 contexts is * suported. * @COGL_FEATURE_ID_DEPTH_TEXTURE: Whether #CoglFramebuffer support rendering * the depth buffer to a texture. * @COGL_FEATURE_ID_PRESENTATION_TIME: Whether frame presentation * time stamps will be recorded in #CoglFrameInfo objects. * * All the capabilities that can vary between different GPUs supported * by Cogl. Applications that depend on any of these features should explicitly * check for them using cogl_has_feature() or cogl_has_features(). * * Since: 1.10 */ typedef enum _CoglFeatureID { COGL_FEATURE_ID_TEXTURE_NPOT_BASIC = 1, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, COGL_FEATURE_ID_TEXTURE_NPOT, COGL_FEATURE_ID_TEXTURE_RECTANGLE, COGL_FEATURE_ID_TEXTURE_3D, COGL_FEATURE_ID_GLSL, COGL_FEATURE_ID_ARBFP, COGL_FEATURE_ID_OFFSCREEN, COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE, COGL_FEATURE_ID_ONSCREEN_MULTIPLE, COGL_FEATURE_ID_UNSIGNED_INT_INDICES, COGL_FEATURE_ID_DEPTH_RANGE, COGL_FEATURE_ID_POINT_SPRITE, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, COGL_FEATURE_ID_MIRRORED_REPEAT, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, COGL_FEATURE_ID_GLES2_CONTEXT, COGL_FEATURE_ID_DEPTH_TEXTURE, COGL_FEATURE_ID_PRESENTATION_TIME, COGL_FEATURE_ID_FENCE, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE, COGL_FEATURE_ID_TEXTURE_RG, COGL_FEATURE_ID_BUFFER_AGE, COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL, /*< private >*/ _COGL_N_FEATURE_IDS /*< skip >*/ } CoglFeatureID; /** * cogl_has_feature: * @context: A #CoglContext pointer * @feature: A #CoglFeatureID * * Checks if a given @feature is currently available * * Cogl does not aim to be a lowest common denominator API, it aims to * expose all the interesting features of GPUs to application which * means applications have some responsibility to explicitly check * that certain features are available before depending on them. * * Returns: %TRUE if the @feature is currently supported or %FALSE if * not. * * Since: 1.10 * Stability: unstable */ CoglBool cogl_has_feature (CoglContext *context, CoglFeatureID feature); /** * cogl_has_features: * @context: A #CoglContext pointer * @...: A 0 terminated list of CoglFeatureIDs * * Checks if a list of features are all currently available. * * This checks all of the listed features using cogl_has_feature() and * returns %TRUE if all the features are available or %FALSE * otherwise. * * Return value: %TRUE if all the features are available, %FALSE * otherwise. * * Since: 1.10 * Stability: unstable */ CoglBool cogl_has_features (CoglContext *context, ...); /** * CoglFeatureCallback: * @feature: A single feature currently supported by Cogl * @user_data: A private pointer passed to cogl_foreach_feature(). * * A callback used with cogl_foreach_feature() for enumerating all * context level features supported by Cogl. * * Since: 0.10 * Stability: unstable */ typedef void (*CoglFeatureCallback) (CoglFeatureID feature, void *user_data); /** * cogl_foreach_feature: * @context: A #CoglContext pointer * @callback: (scope call): A #CoglFeatureCallback called for each * supported feature * @user_data: (closure): Private data to pass to the callback * * Iterates through all the context level features currently supported * for a given @context and for each feature @callback is called. * * Since: 1.10 * Stability: unstable */ void cogl_foreach_feature (CoglContext *context, CoglFeatureCallback callback, void *user_data); /** * cogl_get_clock_time: * @context: a #CoglContext pointer * * Returns the current time value from Cogl's internal clock. This * clock is used for measuring times such as the presentation time * in a #CoglFrameInfo. * * This method is meant for converting timestamps retrieved from Cogl * to other time systems, and is not meant to be used as a standalone * timing system. For that reason, if this function is called without * having retrieved a valid (non-zero) timestamp from Cogl first, it * may return 0 to indicate that Cogl has no active internal clock. * * Return value: the time value for the Cogl clock, in nanoseconds * from an arbitrary point in time, or 0 if Cogl doesn't have an * active internal clock. * Since: 1.14 * Stability: unstable */ int64_t cogl_get_clock_time (CoglContext *context); /** * CoglGraphicsResetStatus: * @COGL_GRAPHICS_RESET_STATUS_NO_ERROR: * @COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET: * @COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET: * @COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET: * @COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET: * * All the error values that might be returned by * cogl_get_graphics_reset_status(). Each value's meaning corresponds * to the similarly named value defined in the ARB_robustness and * NV_robustness_video_memory_purge extensions. */ typedef enum _CoglGraphicsResetStatus { COGL_GRAPHICS_RESET_STATUS_NO_ERROR, COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET, COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET, COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET, COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET, } CoglGraphicsResetStatus; /** * cogl_get_graphics_reset_status: * @context: a #CoglContext pointer * * Returns the graphics reset status as reported by * GetGraphicsResetStatusARB defined in the ARB_robustness extension. * * Note that Cogl doesn't normally enable the ARB_robustness * extension in which case this will only ever return * #COGL_GRAPHICS_RESET_STATUS_NO_ERROR. * * Applications must explicitly use a backend specific method to * request that errors get reported such as X11's * cogl_xlib_renderer_request_reset_on_video_memory_purge(). * * Return value: a #CoglGraphicsResetStatus */ CoglGraphicsResetStatus cogl_get_graphics_reset_status (CoglContext *context); COGL_END_DECLS #endif /* __COGL_CONTEXT_H__ */ muffin-5.2.1/cogl/cogl/cogl-profile.c0000664000175000017500000000770114211404421017537 0ustar jpeisachjpeisach#ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #ifdef COGL_ENABLE_PROFILE #include "cogl-profile.h" #include "cogl-debug.h" #include "cogl-i18n-private.h" #include UProfContext *_cogl_uprof_context; static CoglBool debug_option_getter (void *user_data) { unsigned int shift = GPOINTER_TO_UINT (user_data); return COGL_DEBUG_ENABLED (shift); } static void debug_option_setter (CoglBool value, void *user_data) { unsigned int shift = GPOINTER_TO_UINT (user_data); if (value) COGL_DEBUG_SET_FLAG (shift); else COGL_DEBUG_CLEAR_FLAG (shift); } static void print_exit_report (void) { if (getenv ("COGL_PROFILE_OUTPUT_REPORT")) { UProfContext *mainloop_context; UProfTimerResult *mainloop_timer; UProfReport *report; /* NB: uprof provides a shared context for mainloop statistics * which needs to be setup by the application which controls the * mainloop. * * If no "Mainloop" timer has been setup then we print a warning * since we can't provide a meaningful Cogl report without one. */ mainloop_context = uprof_get_mainloop_context (); mainloop_timer = uprof_context_get_timer_result (mainloop_context, "Mainloop"); /* just bail out if the mainloop timer wasn't hit */ if (!mainloop_timer) { g_warning ("\n\n" "No UProf \"Mainloop\" timer was setup by the " "application therefore we\ncan't provide a meaningful " "profile report.\n" "\n" "This should be done automatically if you are using Clutter " "(if\nbuilt with --enable-profile)\n" "\n" "If you aren't using Clutter then you can declare a " "\"Mainloop\" UProf\ntimer in your application like this:\n\n" " UPROF_STATIC_TIMER (mainloop_timer, \n" " NULL,\n" " \"Mainloop\",\n" " \"Time in glib mainloop\",\n" " 0);\n" "\n" "And start/stop it around your mainloop like this:\n" "\n" " UPROF_TIMER_START (uprof_get_mainloop_context (), mainloop_timer);\n" " g_main_loop_run (loop);\n" " UPROF_TIMER_STOP (uprof_get_mainloop_context (), mainloop_timer);\n"); return; } report = uprof_report_new ("Cogl report"); uprof_report_add_context (report, _cogl_uprof_context); uprof_report_print (report); uprof_report_unref (report); } uprof_context_unref (_cogl_uprof_context); } void _cogl_uprof_init (void) { _cogl_uprof_context = uprof_context_new ("Cogl"); uprof_context_link (_cogl_uprof_context, uprof_get_mainloop_context ()); #define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \ G_STMT_START { \ int shift = COGL_DEBUG_ ## MASK_NAME; \ uprof_context_add_boolean_option (_cogl_uprof_context, \ GROUP, \ NAME, \ NAME_FORMATTED, \ DESCRIPTION, \ debug_option_getter, \ debug_option_setter, \ GUINT_TO_POINTER (shift)); \ } G_STMT_END; #include "cogl-debug-options.h" #undef OPT atexit (print_exit_report); } void _cogl_profile_trace_message (const char *format, ...) { va_list ap; va_start (ap, format); g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, ap); va_end (ap); if (_cogl_uprof_context) uprof_context_vtrace_message (_cogl_uprof_context, format, ap); } #endif muffin-5.2.1/cogl/cogl/cogl-swap-chain.h0000664000175000017500000000372114211404421020134 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_SWAP_CHAIN_H__ #define __COGL_SWAP_CHAIN_H__ #include #include COGL_BEGIN_DECLS typedef struct _CoglSwapChain CoglSwapChain; /** * cogl_swap_chain_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_swap_chain_get_gtype (void); CoglSwapChain * cogl_swap_chain_new (void); void cogl_swap_chain_set_has_alpha (CoglSwapChain *swap_chain, CoglBool has_alpha); void cogl_swap_chain_set_length (CoglSwapChain *swap_chain, int length); CoglBool cogl_is_swap_chain (void *object); COGL_END_DECLS #endif /* __COGL_SWAP_CHAIN_H__ */ muffin-5.2.1/cogl/cogl/cogl-object.c0000664000175000017500000002020014211404421017332 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include "cogl-util.h" #include "cogl-types.h" #include "cogl-object-private.h" #include "cogl-gtype-private.h" COGL_GTYPE_DEFINE_BASE_CLASS (Object, object); void * cogl_object_ref (void *object) { CoglObject *obj = object; _COGL_RETURN_VAL_IF_FAIL (object != NULL, NULL); obj->ref_count++; return object; } CoglHandle cogl_handle_ref (CoglHandle handle) { return cogl_object_ref (handle); } void _cogl_object_default_unref (void *object) { CoglObject *obj = object; _COGL_RETURN_IF_FAIL (object != NULL); _COGL_RETURN_IF_FAIL (obj->ref_count > 0); if (--obj->ref_count < 1) { void (*free_func)(void *obj); if (obj->n_user_data_entries) { int i; int count = MIN (obj->n_user_data_entries, COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES); for (i = 0; i < count; i++) { CoglUserDataEntry *entry = &obj->user_data_entry[i]; if (entry->destroy) entry->destroy (entry->user_data, obj); } if (obj->user_data_array != NULL) { for (i = 0; i < obj->user_data_array->len; i++) { CoglUserDataEntry *entry = &g_array_index (obj->user_data_array, CoglUserDataEntry, i); if (entry->destroy) entry->destroy (entry->user_data, obj); } g_array_free (obj->user_data_array, TRUE); } } COGL_OBJECT_DEBUG_FREE (obj); free_func = obj->klass->virt_free; free_func (obj); } } void cogl_object_unref (void *obj) { void (* unref_func) (void *); _COGL_RETURN_IF_FAIL (obj != NULL); unref_func = ((CoglObject *) obj)->klass->virt_unref; unref_func (obj); } void cogl_handle_unref (CoglHandle handle) { cogl_object_unref (handle); } GType cogl_handle_get_type (void) { static GType our_type = 0; /* XXX: We are keeping the "CoglHandle" name for now incase it would * break bindings to change to "CoglObject" */ if (G_UNLIKELY (our_type == 0)) our_type = g_boxed_type_register_static (g_intern_static_string ("CoglHandle"), (GBoxedCopyFunc) cogl_object_ref, (GBoxedFreeFunc) cogl_object_unref); return our_type; } /* XXX: Unlike for cogl_object_get_user_data this code will return * an empty entry if available and no entry for the given key can be * found. */ static CoglUserDataEntry * _cogl_object_find_entry (CoglObject *object, CoglUserDataKey *key) { CoglUserDataEntry *entry = NULL; int count; int i; count = MIN (object->n_user_data_entries, COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES); for (i = 0; i < count; i++) { CoglUserDataEntry *current = &object->user_data_entry[i]; if (current->key == key) return current; if (current->user_data == NULL) entry = current; } if (G_UNLIKELY (object->user_data_array != NULL)) { for (i = 0; i < object->user_data_array->len; i++) { CoglUserDataEntry *current = &g_array_index (object->user_data_array, CoglUserDataEntry, i); if (current->key == key) return current; if (current->user_data == NULL) entry = current; } } return entry; } void _cogl_object_set_user_data (CoglObject *object, CoglUserDataKey *key, void *user_data, CoglUserDataDestroyInternalCallback destroy) { CoglUserDataEntry new_entry; CoglUserDataEntry *entry; if (user_data) { new_entry.key = key; new_entry.user_data = user_data; new_entry.destroy = destroy; } else memset (&new_entry, 0, sizeof (new_entry)); entry = _cogl_object_find_entry (object, key); if (entry) { if (G_LIKELY (entry->destroy)) entry->destroy (entry->user_data, object); } else { /* NB: Setting a value of NULL is documented to delete the * corresponding entry so we can return immediately in this * case. */ if (user_data == NULL) return; if (G_LIKELY (object->n_user_data_entries < COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES)) entry = &object->user_data_entry[object->n_user_data_entries++]; else { if (G_UNLIKELY (object->user_data_array == NULL)) { object->user_data_array = g_array_new (FALSE, FALSE, sizeof (CoglUserDataEntry)); } g_array_set_size (object->user_data_array, object->user_data_array->len + 1); entry = &g_array_index (object->user_data_array, CoglUserDataEntry, object->user_data_array->len - 1); object->n_user_data_entries++; } } *entry = new_entry; } void cogl_object_set_user_data (CoglObject *object, CoglUserDataKey *key, void *user_data, CoglUserDataDestroyCallback destroy) { _cogl_object_set_user_data (object, key, user_data, (CoglUserDataDestroyInternalCallback)destroy); } void * cogl_object_get_user_data (CoglObject *object, CoglUserDataKey *key) { int count; int i; count = MIN (object->n_user_data_entries, COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES); for (i = 0; i < count; i++) { CoglUserDataEntry *entry = &object->user_data_entry[i]; if (entry->key == key) return entry->user_data; } if (object->user_data_array != NULL) { for (i = 0; i < object->user_data_array->len; i++) { CoglUserDataEntry *entry = &g_array_index (object->user_data_array, CoglUserDataEntry, i); if (entry->key == key) return entry->user_data; } } return NULL; } void cogl_debug_object_foreach_type (CoglDebugObjectForeachTypeCallback func, void *user_data) { GHashTableIter iter; unsigned long *instance_count; CoglDebugObjectTypeInfo info; g_hash_table_iter_init (&iter, _cogl_debug_instances); while (g_hash_table_iter_next (&iter, (void *) &info.name, (void *) &instance_count)) { info.instance_count = *instance_count; func (&info, user_data); } } static void print_instances_cb (const CoglDebugObjectTypeInfo *info, void *user_data) { g_print ("\t%s: %lu\n", info->name, info->instance_count); } void cogl_debug_object_print_instances (void) { g_print ("Cogl instances:\n"); cogl_debug_object_foreach_type (print_instances_cb, NULL); } muffin-5.2.1/cogl/cogl/cogl-output.c0000664000175000017500000000531014211404421017431 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-output-private.h" #include "cogl-gtype-private.h" #include static void _cogl_output_free (CoglOutput *output); COGL_OBJECT_DEFINE (Output, output); COGL_GTYPE_DEFINE_CLASS (Output, output); CoglOutput * _cogl_output_new (const char *name) { CoglOutput *output; output = g_slice_new0 (CoglOutput); output->name = g_strdup (name); return _cogl_output_object_new (output); } static void _cogl_output_free (CoglOutput *output) { free (output->name); g_slice_free (CoglOutput, output); } gboolean _cogl_output_values_equal (CoglOutput *output, CoglOutput *other) { return memcmp ((const char *)output + G_STRUCT_OFFSET (CoglOutput, x), (const char *)other + G_STRUCT_OFFSET (CoglOutput, x), sizeof (CoglOutput) - G_STRUCT_OFFSET (CoglOutput, x)) == 0; } int cogl_output_get_x (CoglOutput *output) { return output->x; } int cogl_output_get_y (CoglOutput *output) { return output->y; } int cogl_output_get_width (CoglOutput *output) { return output->width; } int cogl_output_get_height (CoglOutput *output) { return output->height; } int cogl_output_get_mm_width (CoglOutput *output) { return output->mm_width; } int cogl_output_get_mm_height (CoglOutput *output) { return output->mm_height; } CoglSubpixelOrder cogl_output_get_subpixel_order (CoglOutput *output) { return output->subpixel_order; } float cogl_output_get_refresh_rate (CoglOutput *output) { return output->refresh_rate; } muffin-5.2.1/cogl/cogl/cogl-blend-string.c0000664000175000017500000007437414211404421020501 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include "cogl-context-private.h" #include "cogl-debug.h" #include "cogl-blend-string.h" #include "cogl-error-private.h" typedef enum _ParserState { PARSER_STATE_EXPECT_DEST_CHANNELS, PARSER_STATE_SCRAPING_DEST_CHANNELS, PARSER_STATE_EXPECT_FUNCTION_NAME, PARSER_STATE_SCRAPING_FUNCTION_NAME, PARSER_STATE_EXPECT_ARG_START, PARSER_STATE_EXPECT_STATEMENT_END } ParserState; typedef enum _ParserArgState { PARSER_ARG_STATE_START, PARSER_ARG_STATE_EXPECT_MINUS, PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME, PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME, PARSER_ARG_STATE_MAYBE_COLOR_MASK, PARSER_ARG_STATE_SCRAPING_MASK, PARSER_ARG_STATE_MAYBE_MULT, PARSER_ARG_STATE_EXPECT_OPEN_PAREN, PARSER_ARG_STATE_EXPECT_FACTOR, PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE, PARSER_ARG_STATE_MAYBE_MINUS, PARSER_ARG_STATE_EXPECT_CLOSE_PAREN, PARSER_ARG_STATE_EXPECT_END } ParserArgState; #define DEFINE_COLOR_SOURCE(NAME, NAME_LEN) \ {/*.type = */COGL_BLEND_STRING_COLOR_SOURCE_ ## NAME, \ /*.name = */#NAME, \ /*.name_len = */NAME_LEN} static CoglBlendStringColorSourceInfo blending_color_sources[] = { DEFINE_COLOR_SOURCE (SRC_COLOR, 9), DEFINE_COLOR_SOURCE (DST_COLOR, 9), DEFINE_COLOR_SOURCE (CONSTANT, 8) }; static CoglBlendStringColorSourceInfo tex_combine_color_sources[] = { DEFINE_COLOR_SOURCE (TEXTURE, 7), /* DEFINE_COLOR_SOURCE (TEXTURE_N, *) - handled manually */ DEFINE_COLOR_SOURCE (PRIMARY, 7), DEFINE_COLOR_SOURCE (CONSTANT, 8), DEFINE_COLOR_SOURCE (PREVIOUS, 8) }; static CoglBlendStringColorSourceInfo tex_combine_texture_n_color_source = { /*.type = */COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N, /*.name = */"TEXTURE_N", /*.name_len = */0 }; #undef DEFINE_COLOR_SOURCE #define DEFINE_FUNCTION(NAME, NAME_LEN, ARGC) \ { /*.type = */COGL_BLEND_STRING_FUNCTION_ ## NAME, \ /*.name = */#NAME, \ /*.name_len = */NAME_LEN, \ /*.argc = */ARGC } /* NB: These must be sorted so any name that's a subset of another * comes later than the longer name. */ static CoglBlendStringFunctionInfo tex_combine_functions[] = { DEFINE_FUNCTION (REPLACE, 7, 1), DEFINE_FUNCTION (MODULATE, 8, 2), DEFINE_FUNCTION (ADD_SIGNED, 10, 2), DEFINE_FUNCTION (ADD, 3, 2), DEFINE_FUNCTION (INTERPOLATE, 11, 3), DEFINE_FUNCTION (SUBTRACT, 8, 2), DEFINE_FUNCTION (DOT3_RGBA, 9, 2), DEFINE_FUNCTION (DOT3_RGB, 8, 2) }; static CoglBlendStringFunctionInfo blend_functions[] = { DEFINE_FUNCTION (ADD, 3, 2) }; #undef DEFINE_FUNCTION uint32_t cogl_blend_string_error_quark (void) { return g_quark_from_static_string ("cogl-blend-string-error-quark"); } void _cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement, CoglBlendStringStatement *rgb, CoglBlendStringStatement *a) { int i; memcpy (rgb, statement, sizeof (CoglBlendStringStatement)); memcpy (a, statement, sizeof (CoglBlendStringStatement)); rgb->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; a->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; for (i = 0; i < statement->function->argc; i++) { CoglBlendStringArgument *arg = &statement->args[i]; CoglBlendStringArgument *rgb_arg = &rgb->args[i]; CoglBlendStringArgument *a_arg = &a->args[i]; if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) { rgb_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; a_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; } if (arg->factor.is_color && arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) { rgb_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; a_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; } } } static CoglBool validate_tex_combine_statements (CoglBlendStringStatement *statements, int n_statements, CoglError **error) { int i, j; const char *error_string; CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR; for (i = 0; i < n_statements; i++) { for (j = 0; j < statements[i].function->argc; j++) { CoglBlendStringArgument *arg = &statements[i].args[j]; if (arg->source.is_zero) { error_string = "You can't use the constant '0' as a texture " "combine argument"; goto error; } if (!arg->factor.is_one) { error_string = "Argument factors are only relevant to blending " "not texture combining"; goto error; } } } return TRUE; error: _cogl_set_error (error, COGL_BLEND_STRING_ERROR, detail, "Invalid texture combine string: %s", error_string); if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS)) { g_debug ("Invalid texture combine string: %s", error_string); } return FALSE; } static CoglBool validate_blend_statements (CoglBlendStringStatement *statements, int n_statements, CoglError **error) { int i, j; const char *error_string; CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR; _COGL_GET_CONTEXT (ctx, 0); if (n_statements == 2 && !ctx->glBlendEquationSeparate && statements[0].function->type != statements[1].function->type) { error_string = "Separate blend functions for the RGB an A " "channels isn't supported by the driver"; detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; goto error; } for (i = 0; i < n_statements; i++) for (j = 0; j < statements[i].function->argc; j++) { CoglBlendStringArgument *arg = &statements[i].args[j]; if (arg->source.is_zero) continue; if ((j == 0 && arg->source.info->type != COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) || (j == 1 && arg->source.info->type != COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR)) { error_string = "For blending you must always use SRC_COLOR " "for arg0 and DST_COLOR for arg1"; goto error; } if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLEND_CONSTANT) && arg->factor.is_color && (arg->factor.source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT)) { error_string = "Driver doesn't support constant blend factors"; detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; goto error; } } return TRUE; error: _cogl_set_error (error, COGL_BLEND_STRING_ERROR, detail, "Invalid blend string: %s", error_string); return FALSE; } static CoglBool validate_statements_for_context (CoglBlendStringStatement *statements, int n_statements, CoglBlendStringContext context, CoglError **error) { const char *error_string; if (n_statements == 1) { if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) { error_string = "You need to also give a blend statement for the RGB" "channels"; goto error; } else if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) { error_string = "You need to also give a blend statement for the " "Alpha channel"; goto error; } } if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) return validate_blend_statements (statements, n_statements, error); else return validate_tex_combine_statements (statements, n_statements, error); error: _cogl_set_error (error, COGL_BLEND_STRING_ERROR, COGL_BLEND_STRING_ERROR_INVALID_ERROR, "Invalid %s string: %s", context == COGL_BLEND_STRING_CONTEXT_BLENDING ? "blend" : "texture combine", error_string); if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS)) { g_debug ("Invalid %s string: %s", context == COGL_BLEND_STRING_CONTEXT_BLENDING ? "blend" : "texture combine", error_string); } return FALSE; } static void print_argument (CoglBlendStringArgument *arg) { const char *mask_names[] = { "RGB", "A", "RGBA" }; g_print (" Arg:\n"); g_print (" is zero = %s\n", arg->source.is_zero ? "yes" : "no"); if (!arg->source.is_zero) { g_print (" color source = %s\n", arg->source.info->name); g_print (" one minus = %s\n", arg->source.one_minus ? "yes" : "no"); g_print (" mask = %s\n", mask_names[arg->source.mask]); g_print (" texture = %d\n", arg->source.texture); g_print ("\n"); g_print (" factor is_one = %s\n", arg->factor.is_one ? "yes" : "no"); g_print (" factor is_src_alpha_saturate = %s\n", arg->factor.is_src_alpha_saturate ? "yes" : "no"); g_print (" factor is_color = %s\n", arg->factor.is_color ? "yes" : "no"); if (arg->factor.is_color) { g_print (" factor color:is zero = %s\n", arg->factor.source.is_zero ? "yes" : "no"); g_print (" factor color:color source = %s\n", arg->factor.source.info->name); g_print (" factor color:one minus = %s\n", arg->factor.source.one_minus ? "yes" : "no"); g_print (" factor color:mask = %s\n", mask_names[arg->factor.source.mask]); g_print (" factor color:texture = %d\n", arg->factor.source.texture); } } } static void print_statement (int num, CoglBlendStringStatement *statement) { const char *mask_names[] = { "RGB", "A", "RGBA" }; int i; g_print ("Statement %d:\n", num); g_print (" Destination channel mask = %s\n", mask_names[statement->mask]); g_print (" Function = %s\n", statement->function->name); for (i = 0; i < statement->function->argc; i++) print_argument (&statement->args[i]); } static const CoglBlendStringFunctionInfo * get_function_info (const char *mark, const char *p, CoglBlendStringContext context) { size_t len = p - mark; CoglBlendStringFunctionInfo *functions; size_t array_len; int i; if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) { functions = blend_functions; array_len = G_N_ELEMENTS (blend_functions); } else { functions = tex_combine_functions; array_len = G_N_ELEMENTS (tex_combine_functions); } for (i = 0; i < array_len; i++) { if (len >= functions[i].name_len && strncmp (mark, functions[i].name, functions[i].name_len) == 0) return &functions[i]; } return NULL; } static const CoglBlendStringColorSourceInfo * get_color_src_info (const char *mark, const char *p, CoglBlendStringContext context) { size_t len = p - mark; CoglBlendStringColorSourceInfo *sources; size_t array_len; int i; if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) { sources = blending_color_sources; array_len = G_N_ELEMENTS (blending_color_sources); } else { sources = tex_combine_color_sources; array_len = G_N_ELEMENTS (tex_combine_color_sources); } if (len >= 8 && strncmp (mark, "TEXTURE_", 8) == 0 && g_ascii_isdigit (mark[8])) { return &tex_combine_texture_n_color_source; } for (i = 0; i < array_len; i++) { if (len >= sources[i].name_len && strncmp (mark, sources[i].name, sources[i].name_len) == 0) return &sources[i]; } return NULL; } static CoglBool is_symbol_char (const char c) { return (g_ascii_isalpha (c) || c == '_') ? TRUE : FALSE; } static CoglBool is_alphanum_char (const char c) { return (g_ascii_isalnum (c) || c == '_') ? TRUE : FALSE; } static CoglBool parse_argument (const char *string, /* original user string */ const char **ret_p, /* start of argument IN:OUT */ const CoglBlendStringStatement *statement, int current_arg, CoglBlendStringArgument *arg, /* OUT */ CoglBlendStringContext context, CoglError **error) { const char *p = *ret_p; const char *mark = NULL; const char *error_string = NULL; ParserArgState state = PARSER_ARG_STATE_START; CoglBool parsing_factor = FALSE; CoglBool implicit_factor_brace = FALSE; arg->source.is_zero = FALSE; arg->source.info = NULL; arg->source.texture = 0; arg->source.one_minus = FALSE; arg->source.mask = statement->mask; arg->factor.is_one = FALSE; arg->factor.is_color = FALSE; arg->factor.is_src_alpha_saturate = FALSE; arg->factor.source.is_zero = FALSE; arg->factor.source.info = NULL; arg->factor.source.texture = 0; arg->factor.source.one_minus = FALSE; arg->factor.source.mask = statement->mask; do { if (g_ascii_isspace (*p)) continue; if (*p == '\0') { error_string = "Unexpected end of string while parsing argument"; goto error; } switch (state) { case PARSER_ARG_STATE_START: if (*p == '1') state = PARSER_ARG_STATE_EXPECT_MINUS; else if (*p == '0') { arg->source.is_zero = TRUE; state = PARSER_ARG_STATE_EXPECT_END; } else { p--; /* backtrack */ state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; } continue; case PARSER_ARG_STATE_EXPECT_MINUS: if (*p != '-') { error_string = "expected a '-' following the 1"; goto error; } arg->source.one_minus = TRUE; state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; continue; case PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME: if (!is_symbol_char (*p)) { error_string = "expected a color source name"; goto error; } state = PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME; mark = p; if (parsing_factor) arg->factor.is_color = TRUE; /* fall through */ case PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME: if (!is_symbol_char (*p)) { CoglBlendStringColorSource *source = parsing_factor ? &arg->factor.source : &arg->source; source->info = get_color_src_info (mark, p, context); if (!source->info) { error_string = "Unknown color source name"; goto error; } if (source->info->type == COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N) { char *endp; source->texture = strtoul (&mark[strlen ("TEXTURE_")], &endp, 10); if (mark == endp) { error_string = "invalid texture number given with " "TEXTURE_N color source"; goto error; } p = endp; } state = PARSER_ARG_STATE_MAYBE_COLOR_MASK; } else continue; /* fall through */ case PARSER_ARG_STATE_MAYBE_COLOR_MASK: if (*p != '[') { p--; /* backtrack */ if (!parsing_factor) state = PARSER_ARG_STATE_MAYBE_MULT; else state = PARSER_ARG_STATE_EXPECT_END; continue; } state = PARSER_ARG_STATE_SCRAPING_MASK; mark = p; /* fall through */ case PARSER_ARG_STATE_SCRAPING_MASK: if (*p == ']') { size_t len = p - mark; CoglBlendStringColorSource *source = parsing_factor ? &arg->factor.source : &arg->source; if (len == 5 && strncmp (mark, "[RGBA", len) == 0) { if (statement->mask != COGL_BLEND_STRING_CHANNEL_MASK_RGBA) { error_string = "You can't use an RGBA color mask if the " "statement hasn't also got an RGBA= mask"; goto error; } source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA; } else if (len == 4 && strncmp (mark, "[RGB", len) == 0) source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; else if (len == 2 && strncmp (mark, "[A", len) == 0) source->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; else { error_string = "Expected a channel mask of [RGBA]" "[RGB] or [A]"; goto error; } if (parsing_factor) state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; else state = PARSER_ARG_STATE_MAYBE_MULT; } continue; case PARSER_ARG_STATE_EXPECT_OPEN_PAREN: if (*p != '(') { if (is_alphanum_char (*p)) { p--; /* compensate for implicit brace and ensure this * char gets considered part of the blend factor */ implicit_factor_brace = TRUE; } else { error_string = "Expected '(' around blend factor or alpha " "numeric character for blend factor name"; goto error; } } else implicit_factor_brace = FALSE; parsing_factor = TRUE; state = PARSER_ARG_STATE_EXPECT_FACTOR; continue; case PARSER_ARG_STATE_EXPECT_FACTOR: if (*p == '1') state = PARSER_ARG_STATE_MAYBE_MINUS; else if (*p == '0') { arg->source.is_zero = TRUE; state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; } else { state = PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE; mark = p; } continue; case PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE: if (!is_symbol_char (*p)) { size_t len = p - mark; if (len >= strlen ("SRC_ALPHA_SATURATE") && strncmp (mark, "SRC_ALPHA_SATURATE", len) == 0) { arg->factor.is_src_alpha_saturate = TRUE; state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; } else { state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; p = mark - 1; /* backtrack */ } } continue; case PARSER_ARG_STATE_MAYBE_MINUS: if (*p == '-') { if (implicit_factor_brace) { error_string = "Expected ( ) braces around blend factor with " "a subtraction"; goto error; } arg->factor.source.one_minus = TRUE; state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; } else { arg->factor.is_one = TRUE; state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; } continue; case PARSER_ARG_STATE_EXPECT_CLOSE_PAREN: if (implicit_factor_brace) { p--; state = PARSER_ARG_STATE_EXPECT_END; continue; } if (*p != ')') { error_string = "Expected closing parenthesis after blend factor"; goto error; } state = PARSER_ARG_STATE_EXPECT_END; continue; case PARSER_ARG_STATE_MAYBE_MULT: if (*p == '*') { state = PARSER_ARG_STATE_EXPECT_OPEN_PAREN; continue; } arg->factor.is_one = TRUE; state = PARSER_ARG_STATE_EXPECT_END; /* fall through */ case PARSER_ARG_STATE_EXPECT_END: if (*p != ',' && *p != ')') { error_string = "expected , or )"; goto error; } *ret_p = p - 1; return TRUE; } } while (p++); error: { int offset = p - string; _cogl_set_error (error, COGL_BLEND_STRING_ERROR, COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR, "Syntax error for argument %d at offset %d: %s", current_arg, offset, error_string); if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS)) { g_debug ("Syntax error for argument %d at offset %d: %s", current_arg, offset, error_string); } return FALSE; } } int _cogl_blend_string_compile (const char *string, CoglBlendStringContext context, CoglBlendStringStatement *statements, CoglError **error) { const char *p = string; const char *mark = NULL; const char *error_string; ParserState state = PARSER_STATE_EXPECT_DEST_CHANNELS; CoglBlendStringStatement *statement = statements; int current_statement = 0; int current_arg = 0; int remaining_argc = 0; #if 0 COGL_DEBUG_SET_FLAG (COGL_DEBUG_BLEND_STRINGS); #endif if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS)) { COGL_NOTE (BLEND_STRINGS, "Compiling %s string:\n%s\n", context == COGL_BLEND_STRING_CONTEXT_BLENDING ? "blend" : "texture combine", string); } do { if (g_ascii_isspace (*p)) continue; if (*p == '\0') { switch (state) { case PARSER_STATE_EXPECT_DEST_CHANNELS: if (current_statement != 0) goto finished; error_string = "Empty statement"; goto error; case PARSER_STATE_SCRAPING_DEST_CHANNELS: error_string = "Expected an '=' following the destination " "channel mask"; goto error; case PARSER_STATE_EXPECT_FUNCTION_NAME: error_string = "Expected a function name"; goto error; case PARSER_STATE_SCRAPING_FUNCTION_NAME: error_string = "Expected parenthesis after the function name"; goto error; case PARSER_STATE_EXPECT_ARG_START: error_string = "Expected to find the start of an argument"; goto error; case PARSER_STATE_EXPECT_STATEMENT_END: error_string = "Expected closing parenthesis for statement"; goto error; } } switch (state) { case PARSER_STATE_EXPECT_DEST_CHANNELS: mark = p; state = PARSER_STATE_SCRAPING_DEST_CHANNELS; /* fall through */ case PARSER_STATE_SCRAPING_DEST_CHANNELS: if (*p != '=') continue; if (strncmp (mark, "RGBA", 4) == 0) statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA; else if (strncmp (mark, "RGB", 3) == 0) statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; else if (strncmp (mark, "A", 1) == 0) statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; else { error_string = "Unknown destination channel mask; " "expected RGBA=, RGB= or A="; goto error; } state = PARSER_STATE_EXPECT_FUNCTION_NAME; continue; case PARSER_STATE_EXPECT_FUNCTION_NAME: mark = p; state = PARSER_STATE_SCRAPING_FUNCTION_NAME; /* fall through */ case PARSER_STATE_SCRAPING_FUNCTION_NAME: if (*p != '(') { if (!is_alphanum_char (*p)) { error_string = "non alpha numeric character in function" "name"; goto error; } continue; } statement->function = get_function_info (mark, p, context); if (!statement->function) { error_string = "Unknown function name"; goto error; } remaining_argc = statement->function->argc; current_arg = 0; state = PARSER_STATE_EXPECT_ARG_START; /* fall through */ case PARSER_STATE_EXPECT_ARG_START: if (*p != '(' && *p != ',') continue; if (remaining_argc) { p++; /* parse_argument expects to see the first char of the arg */ if (!parse_argument (string, &p, statement, current_arg, &statement->args[current_arg], context, error)) return 0; current_arg++; remaining_argc--; } if (!remaining_argc) state = PARSER_STATE_EXPECT_STATEMENT_END; continue; case PARSER_STATE_EXPECT_STATEMENT_END: if (*p != ')') { error_string = "Expected end of statement"; goto error; } state = PARSER_STATE_EXPECT_DEST_CHANNELS; if (current_statement++ == 1) goto finished; statement = &statements[current_statement]; } } while (p++); finished: if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS)) { if (current_statement > 0) print_statement (0, &statements[0]); if (current_statement > 1) print_statement (1, &statements[1]); } if (!validate_statements_for_context (statements, current_statement, context, error)) return 0; return current_statement; error: { int offset = p - string; _cogl_set_error (error, COGL_BLEND_STRING_ERROR, COGL_BLEND_STRING_ERROR_PARSE_ERROR, "Syntax error at offset %d: %s", offset, error_string); if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS)) { g_debug ("Syntax error at offset %d: %s", offset, error_string); } return 0; } } /* * INTERNAL TESTING CODE ... */ struct _TestString { const char *string; CoglBlendStringContext context; }; /* FIXME: this should probably be moved to a unit test */ int _cogl_blend_string_test (void); int _cogl_blend_string_test (void) { struct _TestString strings[] = { {" A = MODULATE ( TEXTURE[RGB], PREVIOUS[A], PREVIOUS[A] ) ", COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, {" RGB = MODULATE ( TEXTURE[RGB], PREVIOUS[A] ) ", COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, {"A=ADD(TEXTURE[A],PREVIOUS[RGB])", COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, {"A=ADD(TEXTURE[A],PREVIOUS[RGB])", COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, {"RGBA = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))", COGL_BLEND_STRING_CONTEXT_BLENDING }, {"RGB = ADD(SRC_COLOR, DST_COLOR*(0))", COGL_BLEND_STRING_CONTEXT_BLENDING }, {"RGB = ADD(SRC_COLOR, 0)", COGL_BLEND_STRING_CONTEXT_BLENDING }, {"RGB = ADD()", COGL_BLEND_STRING_CONTEXT_BLENDING }, {"RGB = ADD(SRC_COLOR, 0, DST_COLOR)", COGL_BLEND_STRING_CONTEXT_BLENDING }, {NULL} }; int i; CoglError *error = NULL; for (i = 0; strings[i].string; i++) { CoglBlendStringStatement statements[2]; int count = _cogl_blend_string_compile (strings[i].string, strings[i].context, statements, &error); if (!count) { g_print ("Failed to parse string:\n%s\n%s\n", strings[i].string, error->message); cogl_error_free (error); error = NULL; continue; } g_print ("Original:\n"); g_print ("%s\n", strings[i].string); if (count > 0) print_statement (0, &statements[0]); if (count > 1) print_statement (1, &statements[1]); } return 0; } muffin-5.2.1/cogl/cogl/cogl-closure-list-private.h0000664000175000017500000001072614211404421022202 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #ifndef _COGL_CLOSURE_LIST_PRIVATE_H_ #define _COGL_CLOSURE_LIST_PRIVATE_H_ #include "cogl-object.h" #include "cogl-list.h" /* * This implements a list of callbacks that can be used a bit like * signals in GObject, but that don't have any marshalling overhead. * * The idea is that any Cogl code that wants to provide a callback * point will provide api to add a callback for that particular point. * The function can take a function pointer with the correct * signature. Internally the Cogl code can use _cogl_closure_list_add, * _cogl_closure_disconnect and _cogl_closure_list_disconnect_all * * In the future we could consider exposing the CoglClosure type which * would allow applications to use _cogl_closure_disconnect() directly * so we don't need to expose new disconnect apis for each callback * point. */ typedef struct _CoglClosure { CoglList link; void *function; void *user_data; CoglUserDataDestroyCallback destroy_cb; } CoglClosure; /* * _cogl_closure_disconnect: * @closure: A closure connected to a Cogl closure list * * Removes the given closure from the callback list it is connected to * and destroys it. If the closure was created with a destroy function * then it will be invoked. */ void _cogl_closure_disconnect (CoglClosure *closure); void _cogl_closure_list_disconnect_all (CoglList *list); CoglClosure * _cogl_closure_list_add (CoglList *list, void *function, void *user_data, CoglUserDataDestroyCallback destroy_cb); /* * _cogl_closure_list_invoke: * @list: A pointer to a CoglList containing CoglClosures * @cb_type: The name of a typedef for the closure callback function signature * @...: The the arguments to pass to the callback * * A convenience macro to invoke a closure list with a variable number * of arguments that will be passed to the closure callback functions. * * Note that the arguments will be evaluated multiple times so it is * not safe to pass expressions that have side-effects. * * Note also that this function ignores the return value from the * callbacks. If you want to handle the return value you should * manually iterate the list and invoke the callbacks yourself. */ #define _cogl_closure_list_invoke(list, cb_type, ...) \ G_STMT_START { \ CoglClosure *_c, *_tmp; \ \ _cogl_list_for_each_safe (_c, _tmp, (list), link) \ { \ cb_type _cb = _c->function; \ _cb (__VA_ARGS__, _c->user_data); \ } \ } G_STMT_END #define _cogl_closure_list_invoke_no_args(list) \ G_STMT_START { \ CoglClosure *_c, *_tmp; \ \ _cogl_list_for_each_safe (_c, _tmp, (list), link) \ { \ void (*_cb)(void *) = _c->function; \ _cb (_c->user_data); \ } \ } G_STMT_END #endif /* _COGL_CLOSURE_LIST_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/cogl-egl-private.h0000664000175000017500000000263314211404421020322 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_EGL_PRIVATE_H__ #define __COGL_EGL_PRIVATE_H__ #include "cogl-egl-defines.h" #if defined(GL_OES_EGL_image) && !defined(GLeglImageOES) #define GLeglImageOES void * #endif #endif /* __COGL_EGL_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-xlib-private.h0000664000175000017500000000336514211404421020514 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_XLIB_PRIVATE_H #define __COGL_XLIB_PRIVATE_H #include typedef struct _CoglXlibTrapState CoglXlibTrapState; struct _CoglXlibTrapState { /* These values are intended to be internal to * _cogl_xlib_{un,}trap_errors but they need to be in the header so * that the struct can be allocated on the stack */ int (* old_error_handler) (Display *, XErrorEvent *); int trapped_error_code; CoglXlibTrapState *old_state; }; void _cogl_xlib_query_damage_extension (void); int _cogl_xlib_get_damage_base (void); #endif /* __COGL_XLIB_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-private.h0000664000175000017500000001357614211404421017565 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PRIVATE_H__ #define __COGL_PRIVATE_H__ #include #include "cogl-context.h" #include "cogl-flags.h" COGL_BEGIN_DECLS typedef enum { COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE, COGL_PRIVATE_FEATURE_MESA_PACK_INVERT, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT, COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES, COGL_PRIVATE_FEATURE_PBOS, COGL_PRIVATE_FEATURE_VBOS, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS, COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT, COGL_PRIVATE_FEATURE_ALPHA_TEST, COGL_PRIVATE_FEATURE_FORMAT_CONVERSION, COGL_PRIVATE_FEATURE_QUADS, COGL_PRIVATE_FEATURE_BLEND_CONSTANT, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL, COGL_PRIVATE_FEATURE_ARBFP, COGL_PRIVATE_FEATURE_OES_EGL_SYNC, /* If this is set then the winsys is responsible for queueing dirty * events. Otherwise a dirty event will be queued when the onscreen * is first allocated or when it is shown or resized */ COGL_PRIVATE_FEATURE_DIRTY_EVENTS, COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE, /* These features let us avoid conditioning code based on the exact * driver being used and instead check for broad opengl feature * sets that can be shared by several GL apis */ COGL_PRIVATE_FEATURE_ANY_GL, COGL_PRIVATE_FEATURE_GL_FIXED, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE, COGL_PRIVATE_FEATURE_GL_EMBEDDED, COGL_PRIVATE_FEATURE_GL_WEB, /* This is currently only implemented for GLX, but isn't actually * that winsys dependent */ COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT, COGL_N_PRIVATE_FEATURES } CoglPrivateFeature; /* Sometimes when evaluating pipelines, either during comparisons or * if calculating a hash value we need to tweak the evaluation * semantics */ typedef enum _CoglPipelineEvalFlags { COGL_PIPELINE_EVAL_FLAG_NONE = 0 } CoglPipelineEvalFlags; void _cogl_transform_point (const CoglMatrix *matrix_mv, const CoglMatrix *matrix_p, const float *viewport, float *x, float *y); CoglBool _cogl_check_extension (const char *name, char * const *ext); void _cogl_clear (const CoglColor *color, unsigned long buffers); void _cogl_init (void); void _cogl_push_source (CoglPipeline *pipeline, CoglBool enable_legacy); CoglBool _cogl_get_enable_legacy_state (void); #define _cogl_has_private_feature(ctx, feature) \ COGL_FLAGS_GET ((ctx)->private_features, (feature)) /* * _cogl_pixel_format_get_bytes_per_pixel: * @format: a #CoglPixelFormat * * Queries how many bytes a pixel of the given @format takes. * * Return value: The number of bytes taken for a pixel of the given * @format. */ int _cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format); /* * _cogl_pixel_format_has_aligned_components: * @format: a #CoglPixelFormat * * Queries whether the ordering of the components for the given * @format depend on the endianness of the host CPU or if the * components can be accessed using bit shifting and bitmasking by * loading a whole pixel into a word. * * XXX: If we ever consider making something like this public we * should really try to think of a better name and come up with * much clearer documentation since it really depends on what * point of view you consider this from whether a format like * COGL_PIXEL_FORMAT_RGBA_8888 is endian dependent. E.g. If you * read an RGBA_8888 pixel into a uint32 * it's endian dependent how you mask out the different channels. * But If you already have separate color components and you want * to write them to an RGBA_8888 pixel then the bytes can be * written sequentially regardless of the endianness. * * Return value: %TRUE if you need to consider the host CPU * endianness when dealing with the given @format * else %FALSE. */ CoglBool _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format); /* * COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT(format): * @format: a #CoglPixelFormat * * Returns TRUE if the pixel format can take a premult bit. This is * currently true for all formats that have an alpha channel except * COGL_PIXEL_FORMAT_A_8 (because that doesn't have any other * components to multiply by the alpha). */ #define COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT(format) \ (((format) & COGL_A_BIT) && (format) != COGL_PIXEL_FORMAT_A_8) COGL_END_DECLS #endif /* __COGL_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-sub-texture-private.h0000664000175000017500000000437514211404421022047 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_SUB_TEXTURE_PRIVATE_H #define __COGL_SUB_TEXTURE_PRIVATE_H #include "cogl-texture-private.h" #include struct _CoglSubTexture { CoglTexture _parent; /* This is the texture that was passed in to _cogl_sub_texture_new. If this is also a sub texture then we will use the full texture from that to render instead of making a chain. However we want to preserve the next texture in case the user is expecting us to keep a reference and also so that we can later add a cogl_sub_texture_get_parent_texture() function. */ CoglTexture *next_texture; /* This is the texture that will actually be used to draw. It will point to the end of the chain if a sub texture of a sub texture is created */ CoglTexture *full_texture; /* The offset of the region represented by this sub-texture. This is * the offset in full_texture which won't necessarily be the same as * the offset passed to _cogl_sub_texture_new if next_texture is * actually already a sub texture */ int sub_x; int sub_y; }; #endif /* __COGL_SUB_TEXTURE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-renderer.h0000664000175000017500000003244314211404421017713 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_RENDERER_H__ #define __COGL_RENDERER_H__ #include #include #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-renderer * @short_description: Choosing a means to render * * A #CoglRenderer represents a means to render. It encapsulates the * selection of an underlying driver, such as OpenGL or OpenGL-ES and * a selection of a window system binding API such as GLX or EGL. * * A #CoglRenderer has two states, "unconnected" and "connected". When * a renderer is first instantiated using cogl_renderer_new() it is * unconnected so that it can be configured and constraints can be * specified for how the backend driver and window system should be * chosen. * * After configuration a #CoglRenderer can (optionally) be explicitly * connected using cogl_renderer_connect() which allows for the * handling of connection errors so that fallback configurations can * be tried if necessary. Applications that don't support any * fallbacks though can skip using cogl_renderer_connect() and leave * Cogl to automatically connect the renderer. * * Once you have a configured #CoglRenderer it can be used to create a * #CoglDisplay object using cogl_display_new(). * * Many applications don't need to explicitly use * cogl_renderer_new() or cogl_display_new() and can just jump * straight to cogl_context_new() and pass a %NULL display argument so * Cogl will automatically connect and setup a renderer and * display. */ /** * COGL_RENDERER_ERROR: * * An error domain for exceptions reported by Cogl */ #define COGL_RENDERER_ERROR cogl_renderer_error_quark () uint32_t cogl_renderer_error_quark (void); typedef struct _CoglRenderer CoglRenderer; /** * cogl_renderer_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_renderer_get_gtype (void); /** * cogl_is_renderer: * @object: A #CoglObject pointer * * Determines if the given @object is a #CoglRenderer * * Return value: %TRUE if @object is a #CoglRenderer, else %FALSE. * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_renderer (void *object); /** * cogl_renderer_new: * * Instantiates a new (unconnected) #CoglRenderer object. A * #CoglRenderer represents a means to render. It encapsulates the * selection of an underlying driver, such as OpenGL or OpenGL-ES and * a selection of a window system binding API such as GLX or EGL. * * While the renderer is unconnected it can be configured so that * applications may specify backend constraints, such as "must use * x11" for example via cogl_renderer_add_constraint(). * * There are also some platform specific configuration apis such * as cogl_xlib_renderer_set_foreign_display() that may also be * used while the renderer is unconnected. * * Once the renderer has been configured, then it may (optionally) be * explicitly connected using cogl_renderer_connect() which allows * errors to be handled gracefully and potentially fallback * configurations can be tried out if there are initial failures. * * If a renderer is not explicitly connected then cogl_display_new() * will automatically connect the renderer for you. If you don't * have any code to deal with error/fallback situations then its fine * to just let Cogl do the connection for you. * * Once you have setup your renderer then the next step is to create a * #CoglDisplay using cogl_display_new(). * * Many applications don't need to explicitly use * cogl_renderer_new() or cogl_display_new() and can just jump * straight to cogl_context_new() and pass a %NULL display argument * so Cogl will automatically connect and setup a renderer and * display. * * Return value: (transfer full): A newly created #CoglRenderer. * * Since: 1.10 * Stability: unstable */ CoglRenderer * cogl_renderer_new (void); /* optional configuration APIs */ /** * CoglWinsysID: * @COGL_WINSYS_ID_ANY: Implies no preference for which backend is used * @COGL_WINSYS_ID_STUB: Use the no-op stub backend * @COGL_WINSYS_ID_GLX: Use the GLX window system binding API * @COGL_WINSYS_ID_EGL_XLIB: Use EGL with the X window system via XLib * * Identifies specific window system backends that Cogl supports. * * These can be used to query what backend Cogl is using or to try and * explicitly select a backend to use. */ typedef enum { COGL_WINSYS_ID_ANY, COGL_WINSYS_ID_STUB, COGL_WINSYS_ID_GLX, COGL_WINSYS_ID_EGL_XLIB, COGL_WINSYS_ID_CUSTOM, } CoglWinsysID; /** * cogl_renderer_set_winsys_id: * @renderer: A #CoglRenderer * @winsys_id: An ID of the winsys you explicitly want to use. * * This allows you to explicitly select a winsys backend to use instead * of letting Cogl automatically select a backend. * * if you select an unsupported backend then cogl_renderer_connect() * will fail and report an error. * * This may only be called on an un-connected #CoglRenderer. */ void cogl_renderer_set_winsys_id (CoglRenderer *renderer, CoglWinsysID winsys_id); /** * cogl_renderer_get_winsys_id: * @renderer: A #CoglRenderer * * Queries which window system backend Cogl has chosen to use. * * This may only be called on a connected #CoglRenderer. * * Returns: The #CoglWinsysID corresponding to the chosen window * system backend. */ CoglWinsysID cogl_renderer_get_winsys_id (CoglRenderer *renderer); /** * cogl_renderer_get_n_fragment_texture_units: * @renderer: A #CoglRenderer * * Queries how many texture units can be used from fragment programs * * Returns: the number of texture image units. * * Since: 1.8 * Stability: Unstable */ int cogl_renderer_get_n_fragment_texture_units (CoglRenderer *renderer); /** * cogl_renderer_check_onscreen_template: (skip) * @renderer: A #CoglRenderer * @onscreen_template: A #CoglOnscreenTemplate * @error: A pointer to a #CoglError for reporting exceptions * * Tests if a given @onscreen_template can be supported with the given * @renderer. * * Return value: %TRUE if the @onscreen_template can be supported, * else %FALSE. * Since: 1.10 * Stability: unstable */ CoglBool cogl_renderer_check_onscreen_template (CoglRenderer *renderer, CoglOnscreenTemplate *onscreen_template, CoglError **error); /* Final connection API */ /** * cogl_renderer_connect: * @renderer: An unconnected #CoglRenderer * @error: a pointer to a #CoglError for reporting exceptions * * Connects the configured @renderer. Renderer connection isn't a * very active process, it basically just means validating that * any given constraint criteria can be satisfied and that a * usable driver and window system backend can be found. * * Return value: %TRUE if there was no error while connecting the * given @renderer. %FALSE if there was an error. * Since: 1.10 * Stability: unstable */ CoglBool cogl_renderer_connect (CoglRenderer *renderer, CoglError **error); /** * CoglRendererConstraint: * @COGL_RENDERER_CONSTRAINT_USES_X11: Require the renderer to be X11 based * @COGL_RENDERER_CONSTRAINT_USES_XLIB: Require the renderer to be X11 * based and use Xlib * @COGL_RENDERER_CONSTRAINT_USES_EGL: Require the renderer to be EGL based * @COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2: Require that the * renderer supports creating a #CoglGLES2Context via * cogl_gles2_context_new(). This can be used to integrate GLES 2.0 * code into Cogl based applications. * * These constraint flags are hard-coded features of the different renderer * backends. Sometimes a platform may support multiple rendering options which * Cogl will usually choose from automatically. Some of these features are * important to higher level applications and frameworks though, such as * whether a renderer is X11 based because an application might only support * X11 based input handling. An application might also need to ensure EGL is * used internally too if they depend on access to an EGLDisplay for some * purpose. * * Applications should ideally minimize how many of these constraints * they depend on to ensure maximum portability. * * Since: 1.10 * Stability: unstable */ typedef enum { COGL_RENDERER_CONSTRAINT_USES_X11 = (1 << 0), COGL_RENDERER_CONSTRAINT_USES_XLIB = (1 << 1), COGL_RENDERER_CONSTRAINT_USES_EGL = (1 << 2), COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2 = (1 << 3) } CoglRendererConstraint; /** * cogl_renderer_add_constraint: * @renderer: An unconnected #CoglRenderer * @constraint: A #CoglRendererConstraint to add * * This adds a renderer selection @constraint. * * Applications should ideally minimize how many of these constraints they * depend on to ensure maximum portability. * * Since: 1.10 * Stability: unstable */ void cogl_renderer_add_constraint (CoglRenderer *renderer, CoglRendererConstraint constraint); /** * cogl_renderer_remove_constraint: * @renderer: An unconnected #CoglRenderer * @constraint: A #CoglRendererConstraint to remove * * This removes a renderer selection @constraint. * * Applications should ideally minimize how many of these constraints they * depend on to ensure maximum portability. * * Since: 1.10 * Stability: unstable */ void cogl_renderer_remove_constraint (CoglRenderer *renderer, CoglRendererConstraint constraint); /** * CoglDriver: * @COGL_DRIVER_ANY: Implies no preference for which driver is used * @COGL_DRIVER_NOP: A No-Op driver. * @COGL_DRIVER_GL: An OpenGL driver. * @COGL_DRIVER_GL3: An OpenGL driver using the core GL 3.1 profile * @COGL_DRIVER_GLES1: An OpenGL ES 1.1 driver. * @COGL_DRIVER_GLES2: An OpenGL ES 2.0 driver. * @COGL_DRIVER_WEBGL: A WebGL driver. * * Identifiers for underlying hardware drivers that may be used by * Cogl for rendering. * * Since: 1.10 * Stability: unstable */ typedef enum { COGL_DRIVER_ANY, COGL_DRIVER_NOP, COGL_DRIVER_GL, COGL_DRIVER_GL3, COGL_DRIVER_GLES1, COGL_DRIVER_GLES2, COGL_DRIVER_WEBGL } CoglDriver; /** * cogl_renderer_set_driver: * @renderer: An unconnected #CoglRenderer * * Requests that Cogl should try to use a specific underlying driver * for rendering. * * If you select an unsupported driver then cogl_renderer_connect() * will fail and report an error. Most applications should not * explicitly select a driver and should rely on Cogl automatically * choosing the driver. * * This may only be called on an un-connected #CoglRenderer. * * Since: 1.10 * Stability: unstable */ void cogl_renderer_set_driver (CoglRenderer *renderer, CoglDriver driver); /** * cogl_renderer_get_driver: * @renderer: A connected #CoglRenderer * * Queries what underlying driver is being used by Cogl. * * This may only be called on a connected #CoglRenderer. * * Since: 1.10 * Stability: unstable */ CoglDriver cogl_renderer_get_driver (CoglRenderer *renderer); /** * CoglOutputCallback: * @output: The current display output being iterated * @user_data: The user pointer passed to * cogl_renderer_foreach_output() * * A callback type that can be passed to * cogl_renderer_foreach_output() for iterating display outputs for a * given renderer. * * Since: 1.14 * Stability: Unstable */ typedef void (*CoglOutputCallback) (CoglOutput *output, void *user_data); /** * cogl_renderer_foreach_output: * @renderer: A connected #CoglRenderer * @callback: (scope call): A #CoglOutputCallback to be called for * each display output * @user_data: A user pointer to be passed to @callback * * Iterates all known display outputs for the given @renderer and * passes a corresponding #CoglOutput pointer to the given @callback * for each one, along with the given @user_data. * * Since: 1.14 * Stability: Unstable */ void cogl_renderer_foreach_output (CoglRenderer *renderer, CoglOutputCallback callback, void *user_data); COGL_END_DECLS #endif /* __COGL_RENDERER_H__ */ muffin-5.2.1/cogl/cogl/cogl-glx-display-private.h0000664000175000017500000000373414211404421022013 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_DISPLAY_GLX_PRIVATE_H #define __COGL_DISPLAY_GLX_PRIVATE_H #include "cogl-object-private.h" typedef struct _CoglGLXCachedConfig { /* This will be -1 if there is no cached config in this slot */ int depth; CoglBool found; GLXFBConfig fb_config; CoglBool stereo; CoglBool can_mipmap; } CoglGLXCachedConfig; #define COGL_GLX_N_CACHED_CONFIGS 6 typedef struct _CoglGLXDisplay { CoglGLXCachedConfig glx_cached_configs[COGL_GLX_N_CACHED_CONFIGS]; CoglBool found_fbconfig; CoglBool fbconfig_has_rgba_visual; CoglBool is_direct; CoglBool have_vblank_counter; CoglBool can_vblank_wait; GLXFBConfig fbconfig; /* Single context for all wins */ GLXContext glx_context; GLXWindow dummy_glxwin; Window dummy_xwin; } CoglGLXDisplay; #endif /* __COGL_DISPLAY_GLX_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-onscreen-template.c0000664000175000017500000000650014211404421021520 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-object.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-template-private.h" #include "cogl-gtype-private.h" #include static void _cogl_onscreen_template_free (CoglOnscreenTemplate *onscreen_template); COGL_OBJECT_DEFINE (OnscreenTemplate, onscreen_template); COGL_GTYPE_DEFINE_CLASS (OnscreenTemplate, onscreen_template); static void _cogl_onscreen_template_free (CoglOnscreenTemplate *onscreen_template) { g_slice_free (CoglOnscreenTemplate, onscreen_template); } CoglOnscreenTemplate * cogl_onscreen_template_new (CoglSwapChain *swap_chain) { CoglOnscreenTemplate *onscreen_template = g_slice_new0 (CoglOnscreenTemplate); char *user_config; onscreen_template->config.swap_chain = swap_chain; if (swap_chain) cogl_object_ref (swap_chain); else onscreen_template->config.swap_chain = cogl_swap_chain_new (); onscreen_template->config.swap_throttled = TRUE; onscreen_template->config.need_stencil = TRUE; onscreen_template->config.samples_per_pixel = 0; user_config = getenv ("COGL_POINT_SAMPLES_PER_PIXEL"); if (user_config) { unsigned long samples_per_pixel = strtoul (user_config, NULL, 10); if (samples_per_pixel != ULONG_MAX) onscreen_template->config.samples_per_pixel = samples_per_pixel; } return _cogl_onscreen_template_object_new (onscreen_template); } void cogl_onscreen_template_set_samples_per_pixel ( CoglOnscreenTemplate *onscreen_template, int samples_per_pixel) { onscreen_template->config.samples_per_pixel = samples_per_pixel; } void cogl_onscreen_template_set_swap_throttled ( CoglOnscreenTemplate *onscreen_template, CoglBool throttled) { onscreen_template->config.swap_throttled = throttled; } void cogl_onscreen_template_set_stereo_enabled ( CoglOnscreenTemplate *onscreen_template, CoglBool enabled) { onscreen_template->config.stereo_enabled = enabled; } muffin-5.2.1/cogl/cogl/cogl-pipeline-state-private.h0000664000175000017500000001530614211404421022477 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_STATE_PRIVATE_H #define __COGL_PIPELINE_STATE_PRIVATE_H CoglPipeline * _cogl_pipeline_get_user_program (CoglPipeline *pipeline); CoglBool _cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline); CoglBool _cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline); CoglBool _cogl_pipeline_has_non_layer_vertex_snippets (CoglPipeline *pipeline); CoglBool _cogl_pipeline_has_non_layer_fragment_snippets (CoglPipeline *pipeline); void _cogl_pipeline_set_fog_state (CoglPipeline *pipeline, const CoglPipelineFogState *fog_state); CoglBool _cogl_pipeline_color_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_lighting_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_alpha_func_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_alpha_func_reference_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_blend_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_depth_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_fog_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_non_zero_point_size_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_point_size_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_per_vertex_point_size_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_user_shader_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_cull_face_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); CoglBool _cogl_pipeline_fragment_snippets_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); void _cogl_pipeline_hash_color_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_layers_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_lighting_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_blend_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_user_shader_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_depth_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_fog_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_non_zero_point_size_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_point_size_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_per_vertex_point_size_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_cull_face_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_uniforms_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority, CoglPipelineHashState *state); void _cogl_pipeline_compare_uniform_differences (unsigned long *differences, CoglPipeline *pipeline0, CoglPipeline *pipeline1); #endif /* __COGL_PIPELINE_STATE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-texture-3d.h0000664000175000017500000001665614211404421020121 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_TEXTURE_3D_H #define __COGL_TEXTURE_3D_H COGL_BEGIN_DECLS /** * SECTION:cogl-texture-3d * @short_description: Functions for creating and manipulating 3D textures * * These functions allow 3D textures to be used. 3D textures can be * thought of as layers of 2D images arranged into a cuboid * shape. When choosing a texel from the texture, Cogl will take into * account the 'r' texture coordinate to select one of the images. */ typedef struct _CoglTexture3D CoglTexture3D; #define COGL_TEXTURE_3D(X) ((CoglTexture3D *)X) /** * cogl_texture_3d_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_texture_3d_get_gtype (void); /** * cogl_texture_3d_new_with_size: * @context: a #CoglContext * @width: width of the texture in pixels. * @height: height of the texture in pixels. * @depth: depth of the texture in pixels. * * Creates a low-level #CoglTexture3D texture with the specified * dimensions and pixel format. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is going to be used and can optimize how it is * allocated. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * This texture will fail to allocate later if * %COGL_FEATURE_ID_TEXTURE_3D is not advertised. Allocation can also * fail if the requested dimensions are not supported by the * GPU. * * Returns: (transfer full): A new #CoglTexture3D object with no storage yet allocated. * Since: 1.10 * Stability: Unstable */ CoglTexture3D * cogl_texture_3d_new_with_size (CoglContext *context, int width, int height, int depth); /** * cogl_texture_3d_new_from_data: * @context: a #CoglContext * @width: width of the texture in pixels. * @height: height of the texture in pixels. * @depth: depth of the texture in pixels. * @format: the #CoglPixelFormat the buffer is stored in in RAM * @rowstride: the memory offset in bytes between the starts of * scanlines in @data or 0 to infer it from the width and format * @image_stride: the number of bytes from one image to the next. This * can be used to add padding between the images in a similar way * that the rowstride can be used to add padding between * rows. Alternatively 0 can be passed to infer the @image_stride * from the @height. * @data: pointer the memory region where the source buffer resides * @error: A CoglError return location. * * Creates a low-level 3D texture and initializes it with @data. The * data is assumed to be packed array of @depth images. There can be * padding between the images using @image_stride. * * This api will always immediately allocate GPU memory for the * texture and upload the given data so that the @data pointer does * not need to remain valid once this function returns. This means it * is not possible to configure the texture before it is allocated. If * you do need to configure the texture before allocation (to specify * constraints on the internal format for example) then you can * instead create a #CoglBitmap for your data and use * cogl_texture_3d_new_from_bitmap(). * * Return value: (transfer full): the newly created #CoglTexture3D or * %NULL if there was an error and an exception will be * returned through @error. * Since: 1.10 * Stability: Unstable */ CoglTexture3D * cogl_texture_3d_new_from_data (CoglContext *context, int width, int height, int depth, CoglPixelFormat format, int rowstride, int image_stride, const uint8_t *data, CoglError **error); /** * cogl_texture_3d_new_from_bitmap: * @bitmap: A #CoglBitmap object. * @height: height of the texture in pixels. * @depth: depth of the texture in pixels. * * Creates a low-level 3D texture and initializes it with the images * in @bitmap. The images are assumed to be packed together after one * another in the increasing y axis. The height of individual image is * given as @height and the number of images is given in @depth. The * actual height of the bitmap can be larger than @height × @depth. In * this case it assumes there is padding between the images. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is going to be used and can optimize how it is * allocated. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * This texture will fail to allocate later if * %COGL_FEATURE_ID_TEXTURE_3D is not advertised. Allocation can also * fail if the requested dimensions are not supported by the * GPU. * * Return value: (transfer full): a newly created #CoglTexture3D * Since: 2.0 * Stability: unstable */ CoglTexture3D * cogl_texture_3d_new_from_bitmap (CoglBitmap *bitmap, int height, int depth); /** * cogl_is_texture_3d: * @object: a #CoglObject * * Checks whether the given object references a #CoglTexture3D * * Return value: %TRUE if the passed object represents a 3D texture * and %FALSE otherwise * * Since: 1.4 * Stability: Unstable */ CoglBool cogl_is_texture_3d (void *object); COGL_END_DECLS #endif /* __COGL_TEXTURE_3D_H */ muffin-5.2.1/cogl/cogl/cogl-frame-info.c0000664000175000017500000000426314211404421020122 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-frame-info-private.h" #include "cogl-gtype-private.h" static void _cogl_frame_info_free (CoglFrameInfo *info); COGL_OBJECT_DEFINE (FrameInfo, frame_info); COGL_GTYPE_DEFINE_CLASS (FrameInfo, frame_info); CoglFrameInfo * _cogl_frame_info_new (void) { CoglFrameInfo *info; info = g_slice_new0 (CoglFrameInfo); return _cogl_frame_info_object_new (info); } static void _cogl_frame_info_free (CoglFrameInfo *info) { g_slice_free (CoglFrameInfo, info); } int64_t cogl_frame_info_get_frame_counter (CoglFrameInfo *info) { return info->frame_counter; } int64_t cogl_frame_info_get_presentation_time (CoglFrameInfo *info) { return info->presentation_time; } float cogl_frame_info_get_refresh_rate (CoglFrameInfo *info) { return info->refresh_rate; } CoglOutput * cogl_frame_info_get_output (CoglFrameInfo *info) { return info->output; } int64_t cogl_frame_info_get_global_frame_counter (CoglFrameInfo *info) { return info->global_frame_counter; } muffin-5.2.1/cogl/cogl/cogl-framebuffer.h0000664000175000017500000021004314211404421020363 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_FRAMEBUFFER_H #define __COGL_FRAMEBUFFER_H /* We forward declare the CoglFramebuffer type here to avoid some circular * dependency issues with the following headers. */ #if defined(__COGL_H_INSIDE__) && !defined(COGL_ENABLE_MUFFIN_API) && \ !defined(COGL_GIR_SCANNING) /* For the public C api we typedef interface types as void to avoid needing * lots of casting in code and instead we will rely on runtime type checking * for these objects. */ typedef void CoglFramebuffer; #else typedef struct _CoglFramebuffer CoglFramebuffer; #define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X)) #endif #include #include #include #include #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-framebuffer * @short_description: A common interface for manipulating framebuffers * * Framebuffers are a collection of buffers that can be rendered too. * A framebuffer may be comprised of one or more color buffers, an * optional depth buffer and an optional stencil buffer. Other * configuration parameters are associated with framebuffers too such * as whether the framebuffer supports multi-sampling (an anti-aliasing * technique) or dithering. * * There are two kinds of framebuffer in Cogl, #CoglOnscreen * framebuffers and #CoglOffscreen framebuffers. As the names imply * offscreen framebuffers are for rendering something offscreen * (perhaps to a texture which is bound as one of the color buffers). * The exact semantics of onscreen framebuffers depends on the window * system backend that you are using, but typically you can expect * rendering to a #CoglOnscreen framebuffer will be immediately * visible to the user. * * If you want to create a new framebuffer then you should start by * looking at the #CoglOnscreen and #CoglOffscreen constructor * functions, such as cogl_offscreen_new_with_texture() or * cogl_onscreen_new(). The #CoglFramebuffer interface deals with * all aspects that are common between those two types of framebuffer. * * Setup of a new CoglFramebuffer happens in two stages. There is a * configuration stage where you specify all the options and ancillary * buffers you want associated with your framebuffer and then when you * are happy with the configuration you can "allocate" the framebuffer * using cogl_framebuffer_allocate(). Technically explicitly calling * cogl_framebuffer_allocate() is optional for convenience and the * framebuffer will automatically be allocated when you first try to * draw to it, but if you do the allocation manually then you can * also catch any possible errors that may arise from your * configuration. */ /** * cogl_framebuffer_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_framebuffer_get_gtype (void); /** * cogl_framebuffer_allocate: * @framebuffer: A #CoglFramebuffer * @error: A pointer to a #CoglError for returning exceptions. * * Explicitly allocates a configured #CoglFramebuffer allowing developers to * check and handle any errors that might arise from an unsupported * configuration so that fallback configurations may be tried. * * Many applications don't support any fallback options at least when * they are initially developed and in that case the don't need to use this API * since Cogl will automatically allocate a framebuffer when it first gets * used. The disadvantage of relying on automatic allocation is that the * program will abort with an error message if there is an error during * automatic allocation. * * Return value: %TRUE if there were no error allocating the framebuffer, else %FALSE. * Since: 1.8 * Stability: unstable */ CoglBool cogl_framebuffer_allocate (CoglFramebuffer *framebuffer, CoglError **error); /** * cogl_framebuffer_get_width: * @framebuffer: A #CoglFramebuffer * * Queries the current width of the given @framebuffer. * * Return value: The width of @framebuffer. * Since: 1.8 * Stability: unstable */ int cogl_framebuffer_get_width (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_height: * @framebuffer: A #CoglFramebuffer * * Queries the current height of the given @framebuffer. * * Return value: The height of @framebuffer. * Since: 1.8 * Stability: unstable */ int cogl_framebuffer_get_height (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_set_viewport: * @framebuffer: A #CoglFramebuffer * @x: The top-left x coordinate of the viewport origin (only integers * supported currently) * @y: The top-left y coordinate of the viewport origin (only integers * supported currently) * @width: The width of the viewport (only integers supported currently) * @height: The height of the viewport (only integers supported currently) * * Defines a scale and offset for everything rendered relative to the * top-left of the destination framebuffer. * * By default the viewport has an origin of (0,0) and width and height * that match the framebuffer's size. Assuming a default projection and * modelview matrix then you could translate the contents of a window * down and right by leaving the viewport size unchanged by moving the * offset to (10,10). The viewport coordinates are measured in pixels. * If you left the x and y origin as (0,0) you could scale the windows * contents down by specify and width and height that's half the real * size of the framebuffer. * * Although the function takes floating point arguments, existing * drivers only allow the use of integer values. In the future floating * point values will be exposed via a checkable feature. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer, float x, float y, float width, float height); /** * cogl_framebuffer_get_viewport_x: * @framebuffer: A #CoglFramebuffer * * Queries the x coordinate of the viewport origin as set using cogl_framebuffer_set_viewport() * or the default value which is 0. * * Return value: The x coordinate of the viewport origin. * Since: 1.8 * Stability: unstable */ float cogl_framebuffer_get_viewport_x (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_viewport_y: * @framebuffer: A #CoglFramebuffer * * Queries the y coordinate of the viewport origin as set using cogl_framebuffer_set_viewport() * or the default value which is 0. * * Return value: The y coordinate of the viewport origin. * Since: 1.8 * Stability: unstable */ float cogl_framebuffer_get_viewport_y (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_viewport_width: * @framebuffer: A #CoglFramebuffer * * Queries the width of the viewport as set using cogl_framebuffer_set_viewport() * or the default value which is the width of the framebuffer. * * Return value: The width of the viewport. * Since: 1.8 * Stability: unstable */ float cogl_framebuffer_get_viewport_width (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_viewport_height: * @framebuffer: A #CoglFramebuffer * * Queries the height of the viewport as set using cogl_framebuffer_set_viewport() * or the default value which is the height of the framebuffer. * * Return value: The height of the viewport. * Since: 1.8 * Stability: unstable */ float cogl_framebuffer_get_viewport_height (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_viewport4fv: * @framebuffer: A #CoglFramebuffer * @viewport: (out caller-allocates) (array fixed-size=4): A pointer to an * array of 4 floats to receive the (x, y, width, height) * components of the current viewport. * * Queries the x, y, width and height components of the current viewport as set * using cogl_framebuffer_set_viewport() or the default values which are 0, 0, * framebuffer_width and framebuffer_height. The values are written into the * given @viewport array. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_get_viewport4fv (CoglFramebuffer *framebuffer, float *viewport); /** * cogl_framebuffer_push_matrix: * @framebuffer: A #CoglFramebuffer pointer * * Copies the current model-view matrix onto the matrix stack. The matrix * can later be restored with cogl_framebuffer_pop_matrix(). * * Since: 1.10 */ void cogl_framebuffer_push_matrix (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_pop_matrix: * @framebuffer: A #CoglFramebuffer pointer * * Restores the model-view matrix on the top of the matrix stack. * * Since: 1.10 */ void cogl_framebuffer_pop_matrix (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_identity_matrix: * @framebuffer: A #CoglFramebuffer pointer * * Resets the current model-view matrix to the identity matrix. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_identity_matrix (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_scale: * @framebuffer: A #CoglFramebuffer pointer * @x: Amount to scale along the x-axis * @y: Amount to scale along the y-axis * @z: Amount to scale along the z-axis * * Multiplies the current model-view matrix by one that scales the x, * y and z axes by the given values. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_scale (CoglFramebuffer *framebuffer, float x, float y, float z); /** * cogl_framebuffer_translate: * @framebuffer: A #CoglFramebuffer pointer * @x: Distance to translate along the x-axis * @y: Distance to translate along the y-axis * @z: Distance to translate along the z-axis * * Multiplies the current model-view matrix by one that translates the * model along all three axes according to the given values. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_translate (CoglFramebuffer *framebuffer, float x, float y, float z); /** * cogl_framebuffer_rotate: * @framebuffer: A #CoglFramebuffer pointer * @angle: Angle in degrees to rotate. * @x: X-component of vertex to rotate around. * @y: Y-component of vertex to rotate around. * @z: Z-component of vertex to rotate around. * * Multiplies the current model-view matrix by one that rotates the * model around the axis-vector specified by @x, @y and @z. The * rotation follows the right-hand thumb rule so for example rotating * by 10 degrees about the axis-vector (0, 0, 1) causes a small * counter-clockwise rotation. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_rotate (CoglFramebuffer *framebuffer, float angle, float x, float y, float z); /** * cogl_framebuffer_rotate_quaternion: * @framebuffer: A #CoglFramebuffer pointer * @quaternion: A #CoglQuaternion * * Multiplies the current model-view matrix by one that rotates * according to the rotation described by @quaternion. * * Since: 2.0 * Stability: unstable */ void cogl_framebuffer_rotate_quaternion (CoglFramebuffer *framebuffer, const CoglQuaternion *quaternion); /** * cogl_framebuffer_rotate_euler: * @framebuffer: A #CoglFramebuffer pointer * @euler: A #CoglEuler * * Multiplies the current model-view matrix by one that rotates * according to the rotation described by @euler. * * Since: 2.0 * Stability: unstable */ void cogl_framebuffer_rotate_euler (CoglFramebuffer *framebuffer, const CoglEuler *euler); /** * cogl_framebuffer_transform: * @framebuffer: A #CoglFramebuffer pointer * @matrix: the matrix to multiply with the current model-view * * Multiplies the current model-view matrix by the given matrix. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_transform (CoglFramebuffer *framebuffer, const CoglMatrix *matrix); /** * cogl_framebuffer_get_modelview_matrix: * @framebuffer: A #CoglFramebuffer pointer * @matrix: (out): return location for the model-view matrix * * Stores the current model-view matrix in @matrix. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_get_modelview_matrix (CoglFramebuffer *framebuffer, CoglMatrix *matrix); /** * cogl_framebuffer_set_modelview_matrix: * @framebuffer: A #CoglFramebuffer pointer * @matrix: the new model-view matrix * * Sets @matrix as the new model-view matrix. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_set_modelview_matrix (CoglFramebuffer *framebuffer, const CoglMatrix *matrix); /** * cogl_framebuffer_perspective: * @framebuffer: A #CoglFramebuffer pointer * @fov_y: Vertical field of view angle in degrees. * @aspect: The (width over height) aspect ratio for display * @z_near: The distance to the near clipping plane (Must be positive, * and must not be 0) * @z_far: The distance to the far clipping plane (Must be positive) * * Replaces the current projection matrix with a perspective matrix * based on the provided values. * * You should be careful not to have to great a @z_far / @z_near * ratio since that will reduce the effectiveness of depth testing * since there wont be enough precision to identify the depth of * objects near to each other. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_perspective (CoglFramebuffer *framebuffer, float fov_y, float aspect, float z_near, float z_far); /** * cogl_framebuffer_frustum: * @framebuffer: A #CoglFramebuffer pointer * @left: X position of the left clipping plane where it * intersects the near clipping plane * @right: X position of the right clipping plane where it * intersects the near clipping plane * @bottom: Y position of the bottom clipping plane where it * intersects the near clipping plane * @top: Y position of the top clipping plane where it intersects * the near clipping plane * @z_near: The distance to the near clipping plane (Must be positive) * @z_far: The distance to the far clipping plane (Must be positive) * * Replaces the current projection matrix with a perspective matrix * for a given viewing frustum defined by 4 side clip planes that * all cross through the origin and 2 near and far clip planes. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_frustum (CoglFramebuffer *framebuffer, float left, float right, float bottom, float top, float z_near, float z_far); /** * cogl_framebuffer_orthographic: * @framebuffer: A #CoglFramebuffer pointer * @x_1: The x coordinate for the first vertical clipping plane * @y_1: The y coordinate for the first horizontal clipping plane * @x_2: The x coordinate for the second vertical clipping plane * @y_2: The y coordinate for the second horizontal clipping plane * @near: The distance to the near clipping * plane (will be negative if the plane is * behind the viewer) * @far: The distance to the far clipping * plane (will be negative if the plane is * behind the viewer) * * Replaces the current projection matrix with an orthographic projection * matrix. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_orthographic (CoglFramebuffer *framebuffer, float x_1, float y_1, float x_2, float y_2, float near, float far); /** * cogl_framebuffer_get_projection_matrix: * @framebuffer: A #CoglFramebuffer pointer * @matrix: (out): return location for the projection matrix * * Stores the current projection matrix in @matrix. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_get_projection_matrix (CoglFramebuffer *framebuffer, CoglMatrix *matrix); /** * cogl_framebuffer_set_projection_matrix: * @framebuffer: A #CoglFramebuffer pointer * @matrix: the new projection matrix * * Sets @matrix as the new projection matrix. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_set_projection_matrix (CoglFramebuffer *framebuffer, const CoglMatrix *matrix); /** * cogl_framebuffer_push_scissor_clip: * @framebuffer: A #CoglFramebuffer pointer * @x: left edge of the clip rectangle in window coordinates * @y: top edge of the clip rectangle in window coordinates * @width: width of the clip rectangle * @height: height of the clip rectangle * * Specifies a rectangular clipping area for all subsequent drawing * operations. Any drawing commands that extend outside the rectangle * will be clipped so that only the portion inside the rectangle will * be displayed. The rectangle dimensions are not transformed by the * current model-view matrix. * * The rectangle is intersected with the current clip region. To undo * the effect of this function, call cogl_framebuffer_pop_clip(). * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_push_scissor_clip (CoglFramebuffer *framebuffer, int x, int y, int width, int height); /** * cogl_framebuffer_push_rectangle_clip: * @framebuffer: A #CoglFramebuffer pointer * @x_1: x coordinate for top left corner of the clip rectangle * @y_1: y coordinate for top left corner of the clip rectangle * @x_2: x coordinate for bottom right corner of the clip rectangle * @y_2: y coordinate for bottom right corner of the clip rectangle * * Specifies a modelview transformed rectangular clipping area for all * subsequent drawing operations. Any drawing commands that extend * outside the rectangle will be clipped so that only the portion * inside the rectangle will be displayed. The rectangle dimensions * are transformed by the current model-view matrix. * * The rectangle is intersected with the current clip region. To undo * the effect of this function, call cogl_framebuffer_pop_clip(). * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_push_rectangle_clip (CoglFramebuffer *framebuffer, float x_1, float y_1, float x_2, float y_2); /** * cogl_framebuffer_push_primitive_clip: * @framebuffer: A #CoglFramebuffer pointer * @primitive: A #CoglPrimitive describing a flat 2D shape * @bounds_x1: x coordinate for the top-left corner of the primitives * bounds * @bounds_y1: y coordinate for the top-left corner of the primitives * bounds * @bounds_x2: x coordinate for the bottom-right corner of the * primitives bounds. * @bounds_y2: y coordinate for the bottom-right corner of the * primitives bounds. * * Sets a new clipping area using a 2D shaped described with a * #CoglPrimitive. The shape must not contain self overlapping * geometry and must lie on a single 2D plane. A bounding box of the * 2D shape in local coordinates (the same coordinates used to * describe the shape) must be given. It is acceptable for the bounds * to be larger than the true bounds but behaviour is undefined if the * bounds are smaller than the true bounds. * * The primitive is transformed by the current model-view matrix and * the silhouette is intersected with the previous clipping area. To * restore the previous clipping area, call * cogl_framebuffer_pop_clip(). * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer, CoglPrimitive *primitive, float bounds_x1, float bounds_y1, float bounds_x2, float bounds_y2); /** * cogl_framebuffer_pop_clip: * @framebuffer: A #CoglFramebuffer pointer * * Reverts the clipping region to the state before the last call to * cogl_framebuffer_push_scissor_clip(), cogl_framebuffer_push_rectangle_clip() * cogl_framebuffer_push_path_clip(), or cogl_framebuffer_push_primitive_clip(). * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_red_bits: * @framebuffer: a pointer to a #CoglFramebuffer * * Retrieves the number of red bits of @framebuffer * * Return value: the number of bits * * Since: 1.8 * Stability: unstable */ int cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_green_bits: * @framebuffer: a pointer to a #CoglFramebuffer * * Retrieves the number of green bits of @framebuffer * * Return value: the number of bits * * Since: 1.8 * Stability: unstable */ int cogl_framebuffer_get_green_bits (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_blue_bits: * @framebuffer: a pointer to a #CoglFramebuffer * * Retrieves the number of blue bits of @framebuffer * * Return value: the number of bits * * Since: 1.8 * Stability: unstable */ int cogl_framebuffer_get_blue_bits (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_alpha_bits: * @framebuffer: a pointer to a #CoglFramebuffer * * Retrieves the number of alpha bits of @framebuffer * * Return value: the number of bits * * Since: 1.8 * Stability: unstable */ int cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_depth_bits: * @framebuffer: a pointer to a #CoglFramebuffer * * Retrieves the number of depth bits of @framebuffer * * Return value: the number of bits * * Since: 2.0 * Stability: unstable */ int cogl_framebuffer_get_depth_bits (CoglFramebuffer *framebuffer); /* * cogl_framebuffer_get_is_stereo: * @framebuffer: a pointer to a #CoglFramebuffer * * Retrieves whether @framebuffer has separate left and right * buffers for use with stereo drawing. See * cogl_framebuffer_set_stereo_mode(). * * Return value: %TRUE if @framebuffer has separate left and * right buffers. * * Since: 1.20 * Stability: unstable */ CoglBool cogl_framebuffer_get_is_stereo (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_dither_enabled: * @framebuffer: a pointer to a #CoglFramebuffer * * Returns whether dithering has been requested for the given @framebuffer. * See cogl_framebuffer_set_dither_enabled() for more details about dithering. * * This may return %TRUE even when the underlying @framebuffer * display pipeline does not support dithering. This value only represents * the user's request for dithering. * * Return value: %TRUE if dithering has been requested or %FALSE if not. * Since: 1.8 * Stability: unstable */ CoglBool cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_set_dither_enabled: * @framebuffer: a pointer to a #CoglFramebuffer * @dither_enabled: %TRUE to enable dithering or %FALSE to disable * * Enables or disabled dithering if supported by the hardware. * * Dithering is a hardware dependent technique to increase the visible * color resolution beyond what the underlying hardware supports by playing * tricks with the colors placed into the framebuffer to give the illusion * of other colors. (For example this can be compared to half-toning used * by some news papers to show varying levels of grey even though their may * only be black and white are available). * * If the current display pipeline for @framebuffer does not support dithering * then this has no affect. * * Dithering is enabled by default. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer, CoglBool dither_enabled); /** * cogl_framebuffer_get_depth_write_enabled: * @framebuffer: a pointer to a #CoglFramebuffer * * Queries whether depth buffer writing is enabled for @framebuffer. This * can be controlled via cogl_framebuffer_set_depth_write_enabled(). * * Return value: %TRUE if depth writing is enabled or %FALSE if not. * Since: 1.18 * Stability: unstable */ CoglBool cogl_framebuffer_get_depth_write_enabled (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_set_depth_write_enabled: * @framebuffer: a pointer to a #CoglFramebuffer * @depth_write_enabled: %TRUE to enable depth writing or %FALSE to disable * * Enables or disables depth buffer writing when rendering to @framebuffer. * If depth writing is enabled for both the framebuffer and the rendering * pipeline, and the framebuffer has an associated depth buffer, depth * information will be written to this buffer during rendering. * * Depth buffer writing is enabled by default. * * Since: 1.18 * Stability: unstable */ void cogl_framebuffer_set_depth_write_enabled (CoglFramebuffer *framebuffer, CoglBool depth_write_enabled); /** * cogl_framebuffer_get_color_mask: * @framebuffer: a pointer to a #CoglFramebuffer * * Gets the current #CoglColorMask of which channels would be written to the * current framebuffer. Each bit set in the mask means that the * corresponding color would be written. * * Returns: A #CoglColorMask * Since: 1.8 * Stability: unstable */ CoglColorMask cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_set_color_mask: * @framebuffer: a pointer to a #CoglFramebuffer * @color_mask: A #CoglColorMask of which color channels to write to * the current framebuffer. * * Defines a bit mask of which color channels should be written to the * given @framebuffer. If a bit is set in @color_mask that means that * color will be written. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer, CoglColorMask color_mask); /** * cogl_framebuffer_get_stereo_mode: * @framebuffer: a pointer to a #CoglFramebuffer * * Gets the current #CoglStereoMode, which defines which stereo buffers * should be drawn to. See cogl_framebuffer_set_stereo_mode(). * * Returns: A #CoglStereoMode * Since: 1.20 * Stability: unstable */ CoglStereoMode cogl_framebuffer_get_stereo_mode (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_set_stereo_mode: * @framebuffer: a pointer to a #CoglFramebuffer * @stereo_mode: A #CoglStereoMode specifying which stereo buffers * should be drawn tow. * * Sets which stereo buffers should be drawn to. The default * is %COGL_STEREO_BOTH, which means that both the left and * right buffers will be affected by drawing. For this to have * an effect, the display system must support stereo drawables, * and the framebuffer must have been created with stereo * enabled. (See cogl_onscreen_template_set_stereo_enabled(), * cogl_framebuffer_get_is_stereo().) * * Since: 1.20 * Stability: unstable */ void cogl_framebuffer_set_stereo_mode (CoglFramebuffer *framebuffer, CoglStereoMode stereo_mode); /** * cogl_framebuffer_set_depth_texture_enabled: * @framebuffer: A #CoglFramebuffer * @enabled: TRUE or FALSE * * If @enabled is #TRUE, the depth buffer used when rendering to @framebuffer * is available as a texture. You can retrieve the texture with * cogl_framebuffer_get_depth_texture(). * * It's possible that your GPU does not support depth textures. You * should check the %COGL_FEATURE_ID_DEPTH_TEXTURE feature before using this * function. * It's not valid to call this function after the framebuffer has been * allocated as the creation of the depth texture is done at allocation time. * * * Since: 1.14 * Stability: unstable */ void cogl_framebuffer_set_depth_texture_enabled (CoglFramebuffer *framebuffer, CoglBool enabled); /** * cogl_framebuffer_get_depth_texture_enabled: * @framebuffer: A #CoglFramebuffer * * Queries whether texture based depth buffer has been enabled via * cogl_framebuffer_set_depth_texture_enabled(). * * Return value: %TRUE if a depth texture has been enabled, else * %FALSE. * * Since: 1.14 * Stability: unstable */ CoglBool cogl_framebuffer_get_depth_texture_enabled (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_get_depth_texture: * @framebuffer: A #CoglFramebuffer * * Retrieves the depth buffer of @framebuffer as a #CoglTexture. You need to * call cogl_framebuffer_get_depth_texture(fb, TRUE); before using this * function. * * Calling this function implicitely allocates the framebuffer. * The texture returned stays valid as long as the framebuffer stays * valid. * * Returns: (transfer none): the depth texture * * Since: 1.14 * Stability: unstable */ CoglTexture * cogl_framebuffer_get_depth_texture (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_set_samples_per_pixel: * @framebuffer: A #CoglFramebuffer framebuffer * @samples_per_pixel: The minimum number of samples per pixel * * Requires that when rendering to @framebuffer then @n point samples * should be made per pixel which will all contribute to the final * resolved color for that pixel. The idea is that the hardware aims * to get quality similar to what you would get if you rendered * everything twice as big (for 4 samples per pixel) and then scaled * that image back down with filtering. It can effectively remove the * jagged edges of polygons and should be more efficient than if you * were to manually render at a higher resolution and downscale * because the hardware is often able to take some shortcuts. For * example the GPU may only calculate a single texture sample for all * points of a single pixel, and for tile based architectures all the * extra sample data (such as depth and stencil samples) may be * handled on-chip and so avoid increased demand on system memory * bandwidth. * * By default this value is usually set to 0 and that is referred to * as "single-sample" rendering. A value of 1 or greater is referred * to as "multisample" rendering. * * There are some semantic differences between single-sample * rendering and multisampling with just 1 point sample such as it * being redundant to use the cogl_framebuffer_resolve_samples() and * cogl_framebuffer_resolve_samples_region() apis with single-sample * rendering. * * It's recommended that * cogl_framebuffer_resolve_samples_region() be explicitly used at the * end of rendering to a point sample buffer to minimize the number of * samples that get resolved. By default Cogl will implicitly resolve * all framebuffer samples but if only a small region of a * framebuffer has changed this can lead to redundant work being * done. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_set_samples_per_pixel (CoglFramebuffer *framebuffer, int samples_per_pixel); /** * cogl_framebuffer_get_samples_per_pixel: * @framebuffer: A #CoglFramebuffer framebuffer * * Gets the number of points that are sampled per-pixel when * rasterizing geometry. Usually by default this will return 0 which * means that single-sample not multisample rendering has been chosen. * When using a GPU supporting multisample rendering it's possible to * increase the number of samples per pixel using * cogl_framebuffer_set_samples_per_pixel(). * * Calling cogl_framebuffer_get_samples_per_pixel() before the * framebuffer has been allocated will simply return the value set * using cogl_framebuffer_set_samples_per_pixel(). After the * framebuffer has been allocated the value will reflect the actual * number of samples that will be made by the GPU. * * Returns: The number of point samples made per pixel when * rasterizing geometry or 0 if single-sample rendering * has been chosen. * * Since: 1.10 * Stability: unstable */ int cogl_framebuffer_get_samples_per_pixel (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_resolve_samples: * @framebuffer: A #CoglFramebuffer framebuffer * * When point sample rendering (also known as multisample rendering) * has been enabled via cogl_framebuffer_set_samples_per_pixel() * then you can optionally call this function (or * cogl_framebuffer_resolve_samples_region()) to explicitly resolve * the point samples into values for the final color buffer. * * Some GPUs will implicitly resolve the point samples during * rendering and so this function is effectively a nop, but with other * architectures it is desirable to defer the resolve step until the * end of the frame. * * Since Cogl will automatically ensure samples are resolved if the * target color buffer is used as a source this API only needs to be * used if explicit control is desired - perhaps because you want to * ensure that the resolve is completed in advance to avoid later * having to wait for the resolve to complete. * * If you are performing incremental updates to a framebuffer you * should consider using cogl_framebuffer_resolve_samples_region() * instead to avoid resolving redundant pixels. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_resolve_samples (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_resolve_samples_region: * @framebuffer: A #CoglFramebuffer framebuffer * @x: top-left x coordinate of region to resolve * @y: top-left y coordinate of region to resolve * @width: width of region to resolve * @height: height of region to resolve * * When point sample rendering (also known as multisample rendering) * has been enabled via cogl_framebuffer_set_samples_per_pixel() * then you can optionally call this function (or * cogl_framebuffer_resolve_samples()) to explicitly resolve the point * samples into values for the final color buffer. * * Some GPUs will implicitly resolve the point samples during * rendering and so this function is effectively a nop, but with other * architectures it is desirable to defer the resolve step until the * end of the frame. * * Use of this API is recommended if incremental, small updates to * a framebuffer are being made because by default Cogl will * implicitly resolve all the point samples of the framebuffer which * can result in redundant work if only a small number of samples have * changed. * * Because some GPUs implicitly resolve point samples this function * only guarantees that at-least the region specified will be resolved * and if you have rendered to a larger region then it's possible that * other samples may be implicitly resolved. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_resolve_samples_region (CoglFramebuffer *framebuffer, int x, int y, int width, int height); /** * cogl_framebuffer_get_context: * @framebuffer: A #CoglFramebuffer * * Can be used to query the #CoglContext a given @framebuffer was * instantiated within. This is the #CoglContext that was passed to * cogl_onscreen_new() for example. * * Return value: (transfer none): The #CoglContext that the given * @framebuffer was instantiated within. * Since: 1.8 * Stability: unstable */ CoglContext * cogl_framebuffer_get_context (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_clear: * @framebuffer: A #CoglFramebuffer * @buffers: A mask of #CoglBufferBit's identifying which auxiliary * buffers to clear * @color: The color to clear the color buffer too if specified in * @buffers. * * Clears all the auxiliary buffers identified in the @buffers mask, and if * that includes the color buffer then the specified @color is used. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_clear (CoglFramebuffer *framebuffer, unsigned long buffers, const CoglColor *color); /** * cogl_framebuffer_clear4f: * @framebuffer: A #CoglFramebuffer * @buffers: A mask of #CoglBufferBit's identifying which auxiliary * buffers to clear * @red: The red component of color to clear the color buffer too if * specified in @buffers. * @green: The green component of color to clear the color buffer too if * specified in @buffers. * @blue: The blue component of color to clear the color buffer too if * specified in @buffers. * @alpha: The alpha component of color to clear the color buffer too if * specified in @buffers. * * Clears all the auxiliary buffers identified in the @buffers mask, and if * that includes the color buffer then the specified @color is used. * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha); /** * cogl_framebuffer_draw_primitive: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @primitive: A #CoglPrimitive geometry object * * Draws the given @primitive geometry to the specified destination * @framebuffer using the graphics processing state described by @pipeline. * * This drawing api doesn't support high-level meta texture types such * as #CoglTexture2DSliced so it is the user's responsibility to * ensure that only low-level textures that can be directly sampled by * a GPU such as #CoglTexture2D, #CoglTextureRectangle or #CoglTexture3D * are associated with layers of the given @pipeline. * * This api doesn't support any of the legacy global state options such * as cogl_set_depth_test_enabled(), cogl_set_backface_culling_enabled() or * cogl_program_use() * * Stability: unstable * Since: 1.10 * Deprecated: 1.16: Use #CoglPrimitives and * cogl_primitive_draw() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_draw) void cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglPrimitive *primitive); /** * cogl_framebuffer_vdraw_attributes: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @mode: The #CoglVerticesMode defining the topology of vertices * @first_vertex: The vertex offset within the given attributes to draw from * @n_vertices: The number of vertices to draw from the given attributes * @...: A set of vertex #CoglAttributes defining vertex geometry * * First defines a geometry primitive by grouping a set of vertex attributes; * specifying a @first_vertex; a number of vertices (@n_vertices) and * specifying what kind of topology the vertices have via @mode. * * Then the function draws the given @primitive geometry to the specified * destination @framebuffer using the graphics processing pipeline described by * @pipeline. * * The list of #CoglAttributes define the attributes of the vertices to * be drawn, such as positions, colors and normals and should be %NULL * terminated. * * This drawing api doesn't support high-level meta texture types such * as #CoglTexture2DSliced so it is the user's responsibility to * ensure that only low-level textures that can be directly sampled by * a GPU such as #CoglTexture2D, #CoglTextureRectangle or #CoglTexture3D * are associated with layers of the given @pipeline. * * Stability: unstable * Since: 1.10 * Deprecated: 1.16: Use #CoglPrimitives and * cogl_primitive_draw() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_draw) void cogl_framebuffer_vdraw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, ...) COGL_GNUC_NULL_TERMINATED; /** * cogl_framebuffer_draw_attributes: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @mode: The #CoglVerticesMode defining the topology of vertices * @first_vertex: The vertex offset within the given attributes to draw from * @n_vertices: The number of vertices to draw from the given attributes * @attributes: An array of pointers to #CoglAttribute<-- -->s defining vertex * geometry * @n_attributes: The number of attributes in the @attributes array. * * First defines a geometry primitive by grouping a set of vertex @attributes; * specifying a @first_vertex; a number of vertices (@n_vertices) and * specifying what kind of topology the vertices have via @mode. * * Then the function draws the given @primitive geometry to the specified * destination @framebuffer using the graphics processing pipeline described by * @pipeline. * * The list of #CoglAttributes define the attributes of the vertices to * be drawn, such as positions, colors and normals and the number of attributes * is given as @n_attributes. * * This drawing api doesn't support high-level meta texture types such * as #CoglTexture2DSliced so it is the user's responsibility to * ensure that only low-level textures that can be directly sampled by * a GPU such as #CoglTexture2D, #CoglTextureRectangle or #CoglTexture3D * are associated with layers of the given @pipeline. * * This api doesn't support any of the legacy global state options such * as cogl_set_depth_test_enabled(), cogl_set_backface_culling_enabled() or * cogl_program_use() * * Stability: unstable * Since: 1.10 * Deprecated: 1.16: Use #CoglPrimitives and * cogl_primitive_draw() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_draw) void cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes); /** * cogl_framebuffer_vdraw_indexed_attributes: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @mode: The #CoglVerticesMode defining the topology of vertices * @first_vertex: The vertex offset within the given attributes to draw from * @n_vertices: The number of vertices to draw from the given attributes * @indices: The array of indices used by the GPU to lookup attribute * data for each vertex. * @...: A set of vertex #CoglAttributes defining vertex geometry * * Behaves the same as cogl_framebuffer_vdraw_attributes() except that * instead of reading vertex data sequentially from the specified * attributes the @indices provide an indirection for how the data * should be indexed allowing a random access order to be * specified. * * For example an indices array of [0, 1, 2, 0, 2, 3] could be used * used to draw two triangles (@mode = %COGL_VERTICES_MODE_TRIANGLES + * @n_vertices = 6) but only provide attribute data for the 4 corners * of a rectangle. When the GPU needs to read in each of the 6 * vertices it will read the @indices array for each vertex in * sequence and use the index to look up the vertex attribute data. So * here you can see that first and fourth vertex will point to the * same data and third and fifth vertex will also point to shared * data. * * Drawing with indices can be a good way of minimizing the size of a * mesh by allowing you to avoid data for duplicate vertices because * multiple entries in the index array can refer back to a single * shared vertex. * * The @indices array must be at least as long as @first_vertex * + @n_vertices otherwise the GPU will overrun the indices array when * looking up vertex data. * * Since it's very common to want to draw a run of rectangles using * indices to avoid duplicating vertex data you can use * cogl_get_rectangle_indices() to get a set of indices that can be * shared. * * This drawing api doesn't support high-level meta texture types such * as #CoglTexture2DSliced so it is the user's responsibility to * ensure that only low-level textures that can be directly sampled by * a GPU such as #CoglTexture2D, #CoglTextureRectangle or * #CoglTexture3D are associated with layers of the given @pipeline. * * This api doesn't support any of the legacy global state * options such as cogl_set_depth_test_enabled(), * cogl_set_backface_culling_enabled() or cogl_program_use() * * Stability: unstable * Since: 1.10 * Deprecated: 1.16: Use #CoglPrimitives and * cogl_primitive_draw() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_draw) void cogl_framebuffer_vdraw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, ...) COGL_GNUC_NULL_TERMINATED; /** * cogl_framebuffer_draw_indexed_attributes: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @mode: The #CoglVerticesMode defining the topology of vertices * @first_vertex: The vertex offset within the given attributes to draw from * @n_vertices: The number of vertices to draw from the given attributes * @indices: The array of indices used by the GPU to lookup attribute * data for each vertex. * @attributes: An array of pointers to #CoglAttribute<-- -->s defining vertex * geometry * @n_attributes: The number of attributes in the @attributes array. * * Behaves the same as cogl_framebuffer_draw_attributes() except that * instead of reading vertex data sequentially from the specified * @attributes the @indices provide an indirection for how the data * should be indexed allowing a random access order to be * specified. * * For example an indices array of [0, 1, 2, 0, 2, 3] could be used * used to draw two triangles (@mode = %COGL_VERTICES_MODE_TRIANGLES + * @n_vertices = 6) but only provide attribute data for the 4 corners * of a rectangle. When the GPU needs to read in each of the 6 * vertices it will read the @indices array for each vertex in * sequence and use the index to look up the vertex attribute data. So * here you can see that first and fourth vertex will point to the * same data and third and fifth vertex will also point to shared * data. * * Drawing with indices can be a good way of minimizing the size of a * mesh by allowing you to avoid data for duplicate vertices because * multiple entries in the index array can refer back to a single * shared vertex. * * The @indices array must be at least as long as @first_vertex * + @n_vertices otherwise the GPU will overrun the indices array when * looking up vertex data. * * Since it's very common to want to draw a run of rectangles using * indices to avoid duplicating vertex data you can use * cogl_get_rectangle_indices() to get a set of indices that can be * shared. * * This drawing api doesn't support high-level meta texture types such * as #CoglTexture2DSliced so it is the user's responsibility to * ensure that only low-level textures that can be directly sampled by * a GPU such as #CoglTexture2D, #CoglTextureRectangle or * #CoglTexture3D are associated with layers of the given @pipeline. * * This api doesn't support any of the legacy global state * options such as cogl_set_depth_test_enabled(), * cogl_set_backface_culling_enabled() or cogl_program_use() * * Stability: unstable * Since: 1.10 * Deprecated: 1.16: Use #CoglPrimitives and * cogl_primitive_draw() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_draw) void cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes); /** * cogl_framebuffer_draw_rectangle: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @x_1: X coordinate of the top-left corner * @y_1: Y coordinate of the top-left corner * @x_2: X coordinate of the bottom-right corner * @y_2: Y coordinate of the bottom-right corner * * Draws a rectangle to @framebuffer with the given @pipeline state * and with the top left corner positioned at (@x_1, @y_1) and the * bottom right corner positioned at (@x_2, @y_2). * * The position is the position before the rectangle has been * transformed by the model-view matrix and the projection * matrix. * * If you want to describe a rectangle with a texture mapped on * it then you can use * cogl_framebuffer_draw_textured_rectangle(). * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_draw_rectangle (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2); /** * cogl_framebuffer_draw_textured_rectangle: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @x_1: x coordinate upper left on screen. * @y_1: y coordinate upper left on screen. * @x_2: x coordinate lower right on screen. * @y_2: y coordinate lower right on screen. * @s_1: S texture coordinate of the top-left coorner * @t_1: T texture coordinate of the top-left coorner * @s_2: S texture coordinate of the bottom-right coorner * @t_2: T texture coordinate of the bottom-right coorner * * Draws a textured rectangle to @framebuffer using the given * @pipeline state with the top left corner positioned at (@x_1, @y_1) * and the bottom right corner positioned at (@x_2, @y_2). The top * left corner will have texture coordinates of (@s_1, @t_1) and the * bottom right corner will have texture coordinates of (@s_2, @t_2). * * The position is the position before the rectangle has been * transformed by the model-view matrix and the projection * matrix. * * This is a high level drawing api that can handle any kind of * #CoglMetaTexture texture such as #CoglTexture2DSliced textures * which may internally be comprised of multiple low-level textures. * This is unlike low-level drawing apis such as cogl_primitive_draw() * which only support low level texture types that are directly * supported by GPUs such as #CoglTexture2D. * * The given texture coordinates will only be used for the first * texture layer of the pipeline and if your pipeline has more than * one layer then all other layers will have default texture * coordinates of @s_1=0.0 @t_1=0.0 @s_2=1.0 @t_2=1.0 * * The given texture coordinates should always be normalized such that * (0, 0) corresponds to the top left and (1, 1) corresponds to the * bottom right. To map an entire texture across the rectangle pass * in @s_1=0, @t_1=0, @s_2=1, @t_2=1. * * Even if you have associated a #CoglTextureRectangle texture * with one of your @pipeline layers which normally implies working * with non-normalized texture coordinates this api should still be * passed normalized texture coordinates. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_draw_textured_rectangle (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2, float s_1, float t_1, float s_2, float t_2); /** * cogl_framebuffer_draw_multitextured_rectangle: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @x_1: x coordinate upper left on screen. * @y_1: y coordinate upper left on screen. * @x_2: x coordinate lower right on screen. * @y_2: y coordinate lower right on screen. * @tex_coords: (in) (array) (transfer none): An array containing groups of * 4 float values: [s_1, t_1, s_2, t_2] that are interpreted as two texture * coordinates; one for the top left texel, and one for the bottom right * texel. Each value should be between 0.0 and 1.0, where the coordinate * (0.0, 0.0) represents the top left of the texture, and (1.0, 1.0) the * bottom right. * @tex_coords_len: The length of the @tex_coords array. (For one layer * and one group of texture coordinates, this would be 4) * * Draws a textured rectangle to @framebuffer with the given @pipeline * state with the top left corner positioned at (@x_1, @y_1) and the * bottom right corner positioned at (@x_2, @y_2). As a pipeline may * contain multiple texture layers this interface lets you supply * texture coordinates for each layer of the pipeline. * * The position is the position before the rectangle has been * transformed by the model-view matrix and the projection * matrix. * * This is a high level drawing api that can handle any kind of * #CoglMetaTexture texture for the first layer such as * #CoglTexture2DSliced textures which may internally be comprised of * multiple low-level textures. This is unlike low-level drawing apis * such as cogl_primitive_draw() which only support low level texture * types that are directly supported by GPUs such as #CoglTexture2D. * * This api can not currently handle multiple high-level meta * texture layers. The first layer may be a high level meta texture * such as #CoglTexture2DSliced but all other layers much be low * level textures such as #CoglTexture2D and additionally they * should be textures that can be sampled using normalized coordinates * (so not #CoglTextureRectangle textures). * * The top left texture coordinate for layer 0 of any pipeline will be * (tex_coords[0], tex_coords[1]) and the bottom right coordinate will * be (tex_coords[2], tex_coords[3]). The coordinates for layer 1 * would be (tex_coords[4], tex_coords[5]) (tex_coords[6], * tex_coords[7]) and so on... * * The given texture coordinates should always be normalized such that * (0, 0) corresponds to the top left and (1, 1) corresponds to the * bottom right. To map an entire texture across the rectangle pass * in tex_coords[0]=0, tex_coords[1]=0, tex_coords[2]=1, * tex_coords[3]=1. * * Even if you have associated a #CoglTextureRectangle texture * which normally implies working with non-normalized texture * coordinates this api should still be passed normalized texture * coordinates. * * The first pair of coordinates are for the first layer (with the * smallest layer index) and if you supply less texture coordinates * than there are layers in the current source material then default * texture coordinates (0.0, 0.0, 1.0, 1.0) are generated. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_draw_multitextured_rectangle (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2, const float *tex_coords, int tex_coords_len); /** * cogl_framebuffer_draw_rectangles: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @coordinates: (in) (array) (transfer none): an array of coordinates * containing groups of 4 float values: [x_1, y_1, x_2, y_2] that are * interpreted as two position coordinates; one for the top left of * the rectangle (x1, y1), and one for the bottom right of the * rectangle (x2, y2). * @n_rectangles: number of rectangles defined in @coordinates. * * Draws a series of rectangles to @framebuffer with the given * @pipeline state in the same way that * cogl_framebuffer_draw_rectangle() does. * * The top left corner of the first rectangle is positioned at * (coordinates[0], coordinates[1]) and the bottom right corner is * positioned at (coordinates[2], coordinates[3]). The positions for * the second rectangle are (coordinates[4], coordinates[5]) and * (coordinates[6], coordinates[7]) and so on... * * The position is the position before the rectangle has been * transformed by the model-view matrix and the projection * matrix. * * As a general rule for better performance its recommended to use * this this API instead of calling * cogl_framebuffer_draw_textured_rectangle() separately for multiple * rectangles if all of the rectangles will be drawn together with the * same @pipeline state. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_draw_rectangles (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, const float *coordinates, unsigned int n_rectangles); /** * cogl_framebuffer_draw_textured_rectangles: * @framebuffer: A destination #CoglFramebuffer * @pipeline: A #CoglPipeline state object * @coordinates: (in) (array) (transfer none): an array containing * groups of 8 float values: [x_1, y_1, x_2, y_2, s_1, t_1, s_2, t_2] * that have the same meaning as the arguments for * cogl_framebuffer_draw_textured_rectangle(). * @n_rectangles: number of rectangles to @coordinates to draw * * Draws a series of rectangles to @framebuffer with the given * @pipeline state in the same way that * cogl_framebuffer_draw_textured_rectangle() does. * * The position is the position before the rectangle has been * transformed by the model-view matrix and the projection * matrix. * * This is a high level drawing api that can handle any kind of * #CoglMetaTexture texture such as #CoglTexture2DSliced textures * which may internally be comprised of multiple low-level textures. * This is unlike low-level drawing apis such as cogl_primitive_draw() * which only support low level texture types that are directly * supported by GPUs such as #CoglTexture2D. * * The top left corner of the first rectangle is positioned at * (coordinates[0], coordinates[1]) and the bottom right corner is * positioned at (coordinates[2], coordinates[3]). The top left * texture coordinate is (coordinates[4], coordinates[5]) and the * bottom right texture coordinate is (coordinates[6], * coordinates[7]). The coordinates for subsequent rectangles * are defined similarly by the subsequent coordinates. * * As a general rule for better performance its recommended to use * this this API instead of calling * cogl_framebuffer_draw_textured_rectangle() separately for multiple * rectangles if all of the rectangles will be drawn together with the * same @pipeline state. * * The given texture coordinates should always be normalized such that * (0, 0) corresponds to the top left and (1, 1) corresponds to the * bottom right. To map an entire texture across the rectangle pass * in tex_coords[0]=0, tex_coords[1]=0, tex_coords[2]=1, * tex_coords[3]=1. * * Even if you have associated a #CoglTextureRectangle texture * which normally implies working with non-normalized texture * coordinates this api should still be passed normalized texture * coordinates. * * Since: 1.10 * Stability: unstable */ void cogl_framebuffer_draw_textured_rectangles (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, const float *coordinates, unsigned int n_rectangles); /* XXX: Should we take an n_buffers + buffer id array instead of using * the CoglBufferBits type which doesn't seem future proof? */ /** * cogl_framebuffer_discard_buffers: * @framebuffer: A #CoglFramebuffer * @buffers: A #CoglBufferBit mask of which ancillary buffers you want * to discard. * * Declares that the specified @buffers no longer need to be referenced * by any further rendering commands. This can be an important * optimization to avoid subsequent frames of rendering depending on * the results of a previous frame. * * For example; some tile-based rendering GPUs are able to avoid allocating and * accessing system memory for the depth and stencil buffer so long as these * buffers are not required as input for subsequent frames and that can save a * significant amount of memory bandwidth used to save and restore their * contents to system memory between frames. * * It is currently considered an error to try and explicitly discard the color * buffer by passing %COGL_BUFFER_BIT_COLOR. This is because the color buffer is * already implicitly discard when you finish rendering to a #CoglOnscreen * framebuffer, and it's not meaningful to try and discard the color buffer of * a #CoglOffscreen framebuffer since they are single-buffered. * * * Since: 1.8 * Stability: unstable */ void cogl_framebuffer_discard_buffers (CoglFramebuffer *framebuffer, unsigned long buffers); /** * cogl_framebuffer_finish: * @framebuffer: A #CoglFramebuffer pointer * * This blocks the CPU until all pending rendering associated with the * specified framebuffer has completed. It's very rare that developers should * ever need this level of synchronization with the GPU and should never be * used unless you clearly understand why you need to explicitly force * synchronization. * * One example might be for benchmarking purposes to be sure timing * measurements reflect the time that the GPU is busy for not just the time it * takes to queue rendering commands. * * Stability: unstable * Since: 1.10 */ void cogl_framebuffer_finish (CoglFramebuffer *framebuffer); /** * cogl_framebuffer_read_pixels_into_bitmap: * @framebuffer: A #CoglFramebuffer * @x: The x position to read from * @y: The y position to read from * @source: Identifies which auxillary buffer you want to read * (only COGL_READ_PIXELS_COLOR_BUFFER supported currently) * @bitmap: The bitmap to store the results in. * * This reads a rectangle of pixels from the given framebuffer where * position (0, 0) is the top left. The pixel at (x, y) is the first * read, and a rectangle of pixels with the same size as the bitmap is * read right and downwards from that point. * * Currently Cogl assumes that the framebuffer is in a premultiplied * format so if the format of @bitmap is non-premultiplied it will * convert it. To read the pixel values without any conversion you * should either specify a format that doesn't use an alpha channel or * use one of the formats ending in PRE. * * Return value: %TRUE if the read succeeded or %FALSE otherwise. The * function is only likely to fail if the bitmap points to a pixel * buffer and it could not be mapped. * Since: 1.10 * Stability: unstable */ CoglBool cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap); /** * cogl_framebuffer_read_pixels: * @framebuffer: A #CoglFramebuffer * @x: The x position to read from * @y: The y position to read from * @width: The width of the region of rectangles to read * @height: The height of the region of rectangles to read * @format: The pixel format to store the data in * @pixels: The address of the buffer to store the data in * * This is a convenience wrapper around * cogl_framebuffer_read_pixels_into_bitmap() which allocates a * temporary #CoglBitmap to read pixel data directly into the given * buffer. The rowstride of the buffer is assumed to be the width of * the region times the bytes per pixel of the format. The source for * the data is always taken from the color buffer. If you want to use * any other rowstride or source, please use the * cogl_framebuffer_read_pixels_into_bitmap() function directly. * * The implementation of the function looks like this: * * |[ * bitmap = cogl_bitmap_new_for_data (context, * width, height, * format, * /* rowstride */ * bpp * width, * pixels); * cogl_framebuffer_read_pixels_into_bitmap (framebuffer, * x, y, * COGL_READ_PIXELS_COLOR_BUFFER, * bitmap); * cogl_object_unref (bitmap); * ]| * * Return value: %TRUE if the read succeeded or %FALSE otherwise. * Since: 1.10 * Stability: unstable */ CoglBool cogl_framebuffer_read_pixels (CoglFramebuffer *framebuffer, int x, int y, int width, int height, CoglPixelFormat format, uint8_t *pixels); /** * cogl_get_draw_framebuffer: * * Gets the current #CoglFramebuffer as set using * cogl_push_framebuffer() * * Return value: (transfer none): The current #CoglFramebuffer * Stability: unstable * Since: 1.8 */ CoglFramebuffer * cogl_get_draw_framebuffer (void); uint32_t cogl_framebuffer_error_quark (void); /** * COGL_FRAMEBUFFER_ERROR: * * An error domain for reporting #CoglFramebuffer exceptions */ #define COGL_FRAMEBUFFER_ERROR (cogl_framebuffer_error_quark ()) typedef enum { /*< prefix=COGL_FRAMEBUFFER_ERROR >*/ COGL_FRAMEBUFFER_ERROR_ALLOCATE } CoglFramebufferError; /** * cogl_is_framebuffer: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglFramebuffer. * * Return value: %TRUE if the object references a #CoglFramebuffer * and %FALSE otherwise. * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_framebuffer (void *object); COGL_END_DECLS #endif /* __COGL_FRAMEBUFFER_H */ muffin-5.2.1/cogl/cogl/cogl-snippet-private.h0000664000175000017500000000475614211404421021245 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifndef __COGL_SNIPPET_PRIVATE_H #define __COGL_SNIPPET_PRIVATE_H #include #include "cogl-snippet.h" #include "cogl-object-private.h" /* These values are also used in the enum for CoglSnippetHook. They are copied here because we don't really want these names to be part of the public API */ #define COGL_SNIPPET_HOOK_BAND_SIZE 2048 #define COGL_SNIPPET_FIRST_PIPELINE_HOOK 0 #define COGL_SNIPPET_FIRST_PIPELINE_VERTEX_HOOK \ COGL_SNIPPET_FIRST_PIPELINE_HOOK #define COGL_SNIPPET_FIRST_PIPELINE_FRAGMENT_HOOK \ (COGL_SNIPPET_FIRST_PIPELINE_VERTEX_HOOK + COGL_SNIPPET_HOOK_BAND_SIZE) #define COGL_SNIPPET_FIRST_LAYER_HOOK (COGL_SNIPPET_HOOK_BAND_SIZE * 2) #define COGL_SNIPPET_FIRST_LAYER_VERTEX_HOOK COGL_SNIPPET_FIRST_LAYER_HOOK #define COGL_SNIPPET_FIRST_LAYER_FRAGMENT_HOOK \ (COGL_SNIPPET_FIRST_LAYER_VERTEX_HOOK + COGL_SNIPPET_HOOK_BAND_SIZE) struct _CoglSnippet { CoglObject _parent; CoglSnippetHook hook; /* This is set to TRUE the first time the snippet is attached to the pipeline. After that any attempts to modify the snippet will be ignored. */ CoglBool immutable; char *declarations; char *pre; char *replace; char *post; }; void _cogl_snippet_make_immutable (CoglSnippet *snippet); #endif /* __COGL_SNIPPET_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-quaternion.c0000664000175000017500000004341514211404421020266 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg * * Various references relating to quaternions: * * http://www.cs.caltech.edu/courses/cs171/quatut.pdf * http://mathworld.wolfram.com/Quaternion.html * http://www.gamedev.net/reference/articles/article1095.asp * http://www.cprogramming.com/tutorial/3d/quaternions.html * http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm * http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56 * 3D Maths Primer for Graphics and Game Development ISBN-10: 1556229119 */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include #include #include #include "cogl-gtype-private.h" #include #include #define FLOAT_EPSILON 1e-03 COGL_GTYPE_DEFINE_BOXED (Quaternion, quaternion, cogl_quaternion_copy, cogl_quaternion_free); static CoglQuaternion zero_quaternion = { 0.0, 0.0, 0.0, 0.0, }; static CoglQuaternion identity_quaternion = { 1.0, 0.0, 0.0, 0.0, }; /* This function is just here to be called from GDB so we don't really want to put a declaration in a header and we just add it here to avoid a warning */ void _cogl_quaternion_print (CoglQuaternion *quarternion); void _cogl_quaternion_print (CoglQuaternion *quaternion) { g_print ("[ %6.4f (%6.4f, %6.4f, %6.4f)]\n", quaternion->w, quaternion->x, quaternion->y, quaternion->z); } void cogl_quaternion_init (CoglQuaternion *quaternion, float angle, float x, float y, float z) { float axis[3] = { x, y, z}; cogl_quaternion_init_from_angle_vector (quaternion, angle, axis); } void cogl_quaternion_init_from_angle_vector (CoglQuaternion *quaternion, float angle, const float *axis3f_in) { /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ float axis[3]; float half_angle; float sin_half_angle; /* XXX: Should we make cogl_vector3_normalize have separate in and * out args? */ axis[0] = axis3f_in[0]; axis[1] = axis3f_in[1]; axis[2] = axis3f_in[2]; cogl_vector3_normalize (axis); half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f; sin_half_angle = sinf (half_angle); quaternion->w = cosf (half_angle); quaternion->x = axis[0] * sin_half_angle; quaternion->y = axis[1] * sin_half_angle; quaternion->z = axis[2] * sin_half_angle; cogl_quaternion_normalize (quaternion); } void cogl_quaternion_init_identity (CoglQuaternion *quaternion) { quaternion->w = 1.0; quaternion->x = 0.0; quaternion->y = 0.0; quaternion->z = 0.0; } void cogl_quaternion_init_from_array (CoglQuaternion *quaternion, const float *array) { quaternion->w = array[0]; quaternion->x = array[1]; quaternion->y = array[2]; quaternion->z = array[3]; } void cogl_quaternion_init_from_x_rotation (CoglQuaternion *quaternion, float angle) { /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ float half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f; quaternion->w = cosf (half_angle); quaternion->x = sinf (half_angle); quaternion->y = 0.0f; quaternion->z = 0.0f; } void cogl_quaternion_init_from_y_rotation (CoglQuaternion *quaternion, float angle) { /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ float half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f; quaternion->w = cosf (half_angle); quaternion->x = 0.0f; quaternion->y = sinf (half_angle); quaternion->z = 0.0f; } void cogl_quaternion_init_from_z_rotation (CoglQuaternion *quaternion, float angle) { /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ float half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f; quaternion->w = cosf (half_angle); quaternion->x = 0.0f; quaternion->y = 0.0f; quaternion->z = sinf (half_angle); } void cogl_quaternion_init_from_euler (CoglQuaternion *quaternion, const CoglEuler *euler) { /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ float sin_heading = sinf (euler->heading * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f); float sin_pitch = sinf (euler->pitch * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f); float sin_roll = sinf (euler->roll * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f); float cos_heading = cosf (euler->heading * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f); float cos_pitch = cosf (euler->pitch * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f); float cos_roll = cosf (euler->roll * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f); quaternion->w = cos_heading * cos_pitch * cos_roll + sin_heading * sin_pitch * sin_roll; quaternion->x = cos_heading * sin_pitch * cos_roll + sin_heading * cos_pitch * sin_roll; quaternion->y = sin_heading * cos_pitch * cos_roll - cos_heading * sin_pitch * sin_roll; quaternion->z = cos_heading * cos_pitch * sin_roll - sin_heading * sin_pitch * cos_roll; } void cogl_quaternion_init_from_quaternion (CoglQuaternion *quaternion, CoglQuaternion *src) { memcpy (quaternion, src, sizeof (float) * 4); } /* XXX: it could be nice to make something like this public... */ /* * COGL_MATRIX_READ: * @MATRIX: A 4x4 transformation matrix * @ROW: The row of the value you want to read * @COLUMN: The column of the value you want to read * * Reads a value from the given matrix using integers to index * into the matrix. */ #define COGL_MATRIX_READ(MATRIX, ROW, COLUMN) \ (((const float *)matrix)[COLUMN * 4 + ROW]) void cogl_quaternion_init_from_matrix (CoglQuaternion *quaternion, const CoglMatrix *matrix) { /* Algorithm devised by Ken Shoemake, Ref: * http://campar.in.tum.de/twiki/pub/Chair/DwarfTutorial/quatut.pdf */ /* 3D maths literature refers to the diagonal of a matrix as the * "trace" of a matrix... */ float trace = matrix->xx + matrix->yy + matrix->zz; float root; if (trace > 0.0f) { root = sqrtf (trace + 1); quaternion->w = root * 0.5f; root = 0.5f / root; quaternion->x = (matrix->zy - matrix->yz) * root; quaternion->y = (matrix->xz - matrix->zx) * root; quaternion->z = (matrix->yx - matrix->xy) * root; } else { #define X 0 #define Y 1 #define Z 2 #define W 3 int h = X; if (matrix->yy > matrix->xx) h = Y; if (matrix->zz > COGL_MATRIX_READ (matrix, h, h)) h = Z; switch (h) { #define CASE_MACRO(i, j, k, I, J, K) \ case I: \ root = sqrtf ((COGL_MATRIX_READ (matrix, I, I) - \ (COGL_MATRIX_READ (matrix, J, J) + \ COGL_MATRIX_READ (matrix, K, K))) + \ COGL_MATRIX_READ (matrix, W, W)); \ quaternion->i = root * 0.5f;\ root = 0.5f / root;\ quaternion->j = (COGL_MATRIX_READ (matrix, I, J) + \ COGL_MATRIX_READ (matrix, J, I)) * root; \ quaternion->k = (COGL_MATRIX_READ (matrix, K, I) + \ COGL_MATRIX_READ (matrix, I, K)) * root; \ quaternion->w = (COGL_MATRIX_READ (matrix, K, J) - \ COGL_MATRIX_READ (matrix, J, K)) * root;\ break CASE_MACRO (x, y, z, X, Y, Z); CASE_MACRO (y, z, x, Y, Z, X); CASE_MACRO (z, x, y, Z, X, Y); #undef CASE_MACRO #undef X #undef Y #undef Z } } if (matrix->ww != 1.0f) { float s = 1.0 / sqrtf (matrix->ww); quaternion->w *= s; quaternion->x *= s; quaternion->y *= s; quaternion->z *= s; } } CoglBool cogl_quaternion_equal (const void *v1, const void *v2) { const CoglQuaternion *a = v1; const CoglQuaternion *b = v2; _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE); _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE); if (v1 == v2) return TRUE; return (a->w == b->w && a->x == b->x && a->y == b->y && a->z == b->z); } CoglQuaternion * cogl_quaternion_copy (const CoglQuaternion *src) { if (G_LIKELY (src)) { CoglQuaternion *new = g_slice_new (CoglQuaternion); memcpy (new, src, sizeof (float) * 4); return new; } else return NULL; } void cogl_quaternion_free (CoglQuaternion *quaternion) { g_slice_free (CoglQuaternion, quaternion); } float cogl_quaternion_get_rotation_angle (const CoglQuaternion *quaternion) { /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ /* FIXME: clamp [-1, 1] */ return 2.0f * acosf (quaternion->w) * _COGL_QUATERNION_RADIANS_TO_DEGREES; } void cogl_quaternion_get_rotation_axis (const CoglQuaternion *quaternion, float *vector3) { float sin_half_angle_sqr; float one_over_sin_angle_over_2; /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ /* NB: sin²(𝜃) + cos²(𝜃) = 1 */ sin_half_angle_sqr = 1.0f - quaternion->w * quaternion->w; if (sin_half_angle_sqr <= 0.0f) { /* Either an identity quaternion or numerical imprecision. * Either way we return an arbitrary vector. */ vector3[0] = 1; vector3[1] = 0; vector3[2] = 0; return; } /* Calculate 1 / sin(𝜃/2) */ one_over_sin_angle_over_2 = 1.0f / sqrtf (sin_half_angle_sqr); vector3[0] = quaternion->x * one_over_sin_angle_over_2; vector3[1] = quaternion->y * one_over_sin_angle_over_2; vector3[2] = quaternion->z * one_over_sin_angle_over_2; } void cogl_quaternion_normalize (CoglQuaternion *quaternion) { float slen = _COGL_QUATERNION_NORM (quaternion); float factor = 1.0f / sqrtf (slen); quaternion->x *= factor; quaternion->y *= factor; quaternion->z *= factor; quaternion->w *= factor; return; } float cogl_quaternion_dot_product (const CoglQuaternion *a, const CoglQuaternion *b) { return a->w * b->w + a->x * b->x + a->y * b->y + a->z * b->z; } void cogl_quaternion_invert (CoglQuaternion *quaternion) { quaternion->x = -quaternion->x; quaternion->y = -quaternion->y; quaternion->z = -quaternion->z; } void cogl_quaternion_multiply (CoglQuaternion *result, const CoglQuaternion *a, const CoglQuaternion *b) { float w = a->w; float x = a->x; float y = a->y; float z = a->z; _COGL_RETURN_IF_FAIL (b != result); result->w = w * b->w - x * b->x - y * b->y - z * b->z; result->x = w * b->x + x * b->w + y * b->z - z * b->y; result->y = w * b->y + y * b->w + z * b->x - x * b->z; result->z = w * b->z + z * b->w + x * b->y - y * b->x; } void cogl_quaternion_pow (CoglQuaternion *quaternion, float exponent) { float half_angle; float new_half_angle; float factor; /* Try and identify and nop identity quaternions to avoid * dividing by zero */ if (fabs (quaternion->w) > 0.9999f) return; /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair * in this form: * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] */ /* FIXME: clamp [-1, 1] */ /* Extract 𝜃/2 from w */ half_angle = acosf (quaternion->w); /* Compute the new 𝜃/2 */ new_half_angle = half_angle * exponent; /* Compute the new w value */ quaternion->w = cosf (new_half_angle); /* And new xyz values */ factor = sinf (new_half_angle) / sinf (half_angle); quaternion->x *= factor; quaternion->y *= factor; quaternion->z *= factor; } void cogl_quaternion_slerp (CoglQuaternion *result, const CoglQuaternion *a, const CoglQuaternion *b, float t) { float cos_difference; float qb_w; float qb_x; float qb_y; float qb_z; float fa; float fb; _COGL_RETURN_IF_FAIL (t >=0 && t <= 1.0f); if (t == 0) { *result = *a; return; } else if (t == 1) { *result = *b; return; } /* compute the cosine of the angle between the two given quaternions */ cos_difference = cogl_quaternion_dot_product (a, b); /* If negative, use -b. Two quaternions q and -q represent the same angle but * may produce a different slerp. We choose b or -b to rotate using the acute * angle. */ if (cos_difference < 0.0f) { qb_w = -b->w; qb_x = -b->x; qb_y = -b->y; qb_z = -b->z; cos_difference = -cos_difference; } else { qb_w = b->w; qb_x = b->x; qb_y = b->y; qb_z = b->z; } /* If we have two unit quaternions the dot should be <= 1.0 */ g_assert (cos_difference < 1.1f); /* Determine the interpolation factors for each quaternion, simply using * linear interpolation for quaternions that are nearly exactly the same. * (this will avoid divisions by zero) */ if (cos_difference > 0.9999f) { fa = 1.0f - t; fb = t; /* XXX: should we also normalize() at the end in this case? */ } else { /* Calculate the sin of the angle between the two quaternions using the * trig identity: sin²(𝜃) + cos²(𝜃) = 1 */ float sin_difference = sqrtf (1.0f - cos_difference * cos_difference); float difference = atan2f (sin_difference, cos_difference); float one_over_sin_difference = 1.0f / sin_difference; fa = sinf ((1.0f - t) * difference) * one_over_sin_difference; fb = sinf (t * difference) * one_over_sin_difference; } /* Finally interpolate the two quaternions */ result->x = fa * a->x + fb * qb_x; result->y = fa * a->y + fb * qb_y; result->z = fa * a->z + fb * qb_z; result->w = fa * a->w + fb * qb_w; } void cogl_quaternion_nlerp (CoglQuaternion *result, const CoglQuaternion *a, const CoglQuaternion *b, float t) { float cos_difference; float qb_w; float qb_x; float qb_y; float qb_z; float fa; float fb; _COGL_RETURN_IF_FAIL (t >=0 && t <= 1.0f); if (t == 0) { *result = *a; return; } else if (t == 1) { *result = *b; return; } /* compute the cosine of the angle between the two given quaternions */ cos_difference = cogl_quaternion_dot_product (a, b); /* If negative, use -b. Two quaternions q and -q represent the same angle but * may produce a different slerp. We choose b or -b to rotate using the acute * angle. */ if (cos_difference < 0.0f) { qb_w = -b->w; qb_x = -b->x; qb_y = -b->y; qb_z = -b->z; cos_difference = -cos_difference; } else { qb_w = b->w; qb_x = b->x; qb_y = b->y; qb_z = b->z; } /* If we have two unit quaternions the dot should be <= 1.0 */ g_assert (cos_difference < 1.1f); fa = 1.0f - t; fb = t; result->x = fa * a->x + fb * qb_x; result->y = fa * a->y + fb * qb_y; result->z = fa * a->z + fb * qb_z; result->w = fa * a->w + fb * qb_w; cogl_quaternion_normalize (result); } void cogl_quaternion_squad (CoglQuaternion *result, const CoglQuaternion *prev, const CoglQuaternion *a, const CoglQuaternion *b, const CoglQuaternion *next, float t) { CoglQuaternion slerp0; CoglQuaternion slerp1; cogl_quaternion_slerp (&slerp0, a, b, t); cogl_quaternion_slerp (&slerp1, prev, next, t); cogl_quaternion_slerp (result, &slerp0, &slerp1, 2.0f * t * (1.0f - t)); } const CoglQuaternion * cogl_get_static_identity_quaternion (void) { return &identity_quaternion; } const CoglQuaternion * cogl_get_static_zero_quaternion (void) { return &zero_quaternion; } muffin-5.2.1/cogl/cogl/cogl-display-private.h0000664000175000017500000000321514211404421021215 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_DISPLAY_PRIVATE_H #define __COGL_DISPLAY_PRIVATE_H #include "cogl-object-private.h" #include "cogl-display.h" #include "cogl-renderer.h" #include "cogl-onscreen-template.h" struct _CoglDisplay { CoglObject _parent; CoglBool setup; CoglRenderer *renderer; CoglOnscreenTemplate *onscreen_template; #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT struct wl_display *wayland_compositor_display; #endif void *winsys; }; #endif /* __COGL_DISPLAY_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-fence-private.h0000664000175000017500000000344014211404421020630 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_FENCE_PRIVATE_H__ #define __COGL_FENCE_PRIVATE_H__ #include "cogl-fence.h" #include "cogl-list.h" #include "cogl-winsys-private.h" typedef enum { FENCE_TYPE_PENDING, #ifdef GL_ARB_sync FENCE_TYPE_GL_ARB, #endif FENCE_TYPE_WINSYS, FENCE_TYPE_ERROR } CoglFenceType; struct _CoglFenceClosure { CoglList link; CoglFramebuffer *framebuffer; CoglFenceType type; void *fence_obj; CoglFenceCallback callback; void *user_data; }; void _cogl_fence_submit (CoglFenceClosure *fence); void _cogl_fence_cancel_fences_for_framebuffer (CoglFramebuffer *framebuffer); #endif /* __COGL_FENCE_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-pipeline-cache.h0000664000175000017500000000655514211404421020760 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PIPELINE_CACHE_H__ #define __COGL_PIPELINE_CACHE_H__ #include "cogl-pipeline.h" typedef struct _CoglPipelineCache CoglPipelineCache; typedef struct { CoglPipeline *pipeline; /* Number of usages of this template. If this drops to zero then it * will be a candidate for removal from the cache */ int usage_count; } CoglPipelineCacheEntry; CoglPipelineCache * _cogl_pipeline_cache_new (void); void _cogl_pipeline_cache_free (CoglPipelineCache *cache); /* * Gets a pipeline from the cache that has the same state as * @key_pipeline for the state in * COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN. If there is no * matching pipline already then a copy of key_pipeline is stored in * the cache so that it will be used next time the function is called * with a similar pipeline. In that case the copy itself will be * returned */ CoglPipelineCacheEntry * _cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache, CoglPipeline *key_pipeline); /* * Gets a pipeline from the cache that has the same state as * @key_pipeline for the state in * COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN. If there is no * matching pipline already then a copy of key_pipeline is stored in * the cache so that it will be used next time the function is called * with a similar pipeline. In that case the copy itself will be * returned */ CoglPipelineCacheEntry * _cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache, CoglPipeline *key_pipeline); /* * Gets a pipeline from the cache that has the same state as * @key_pipeline for the combination of the state state in * COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN and * COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN. If there is no * matching pipline already then a copy of key_pipeline is stored in * the cache so that it will be used next time the function is called * with a similar pipeline. In that case the copy itself will be * returned */ CoglPipelineCacheEntry * _cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache, CoglPipeline *key_pipeline); #endif /* __COGL_PIPELINE_CACHE_H__ */ muffin-5.2.1/cogl/cogl/cogl-pixel-buffer.h0000664000175000017500000001035514211404421020473 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Damien Lespiau * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PIXEL_BUFFER_H__ #define __COGL_PIXEL_BUFFER_H__ /* XXX: We forward declare CoglPixelBuffer here to allow for circular * dependencies between some headers */ typedef struct _CoglPixelBuffer CoglPixelBuffer; #include #include #include COGL_BEGIN_DECLS #define COGL_PIXEL_BUFFER(buffer) ((CoglPixelBuffer *)(buffer)) /** * CoglPixelBuffer: (skip) */ /** * cogl_pixel_buffer_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_pixel_buffer_get_gtype (void); /** * cogl_pixel_buffer_new: * @context: A #CoglContext * @size: The number of bytes to allocate for the pixel data. * @data: An optional pointer to vertex data to upload immediately * * Declares a new #CoglPixelBuffer of @size bytes to contain arrays of * pixels. Once declared, data can be set using cogl_buffer_set_data() * or by mapping it into the application's address space using * cogl_buffer_map(). * * If @data isn't %NULL then @size bytes will be read from @data and * immediately copied into the new buffer. * * Return value: (transfer full): a newly allocated #CoglPixelBuffer * * Since: 1.10 * Stability: unstable */ CoglPixelBuffer * cogl_pixel_buffer_new (CoglContext *context, size_t size, const void *data); /** * cogl_is_pixel_buffer: * @object: a #CoglObject to test * * Checks whether @object is a pixel buffer. * * Return value: %TRUE if the @object is a pixel buffer, and %FALSE * otherwise * * Since: 1.2 * Stability: Unstable */ CoglBool cogl_is_pixel_buffer (void *object); #if 0 /* * cogl_pixel_buffer_set_region: * @buffer: A #CoglPixelBuffer object * @data: pixel data to upload to @array * @src_width: width in pixels of the region to update * @src_height: height in pixels of the region to update * @src_rowstride: row stride in bytes of the source array * @dst_x: upper left destination horizontal coordinate * @dst_y: upper left destination vertical coordinate * * Uploads new data into a pixel array. The source data pointed by @data can * have a different stride than @array in which case the function will do the * right thing for you. For performance reasons, it is recommended for the * source data to have the same stride than @array. * * Return value: %TRUE if the upload succeeded, %FALSE otherwise * * Since: 1.2 * Stability: Unstable */ CoglBool cogl_pixel_buffer_set_region (CoglPixelBuffer *buffer, uint8_t *data, unsigned int src_width, unsigned int src_height, unsigned int src_rowstride, unsigned int dst_x, unsigned int dst_y); #endif COGL_END_DECLS #endif /* __COGL_PIXEL_BUFFER_H__ */ muffin-5.2.1/cogl/cogl/cogl-attribute-buffer-private.h0000664000175000017500000000270414211404421023024 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_ATTRIBUTE_BUFFER_PRIVATE_H #define __COGL_ATTRIBUTE_BUFFER_PRIVATE_H #include "cogl-buffer-private.h" struct _CoglAttributeBuffer { CoglBuffer _parent; }; #endif /* __COGL_ATTRIBUTE_BUFFER_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-gles2-context-private.h0000664000175000017500000001426314211404421022253 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Tomeu Vizoso * Robert Bragg * */ #ifndef __COGL_GLES2_CONTEXT_PRIVATE_H #define __COGL_GLES2_CONTEXT_PRIVATE_H #include #include "cogl-object-private.h" #include "cogl-framebuffer-private.h" #include "cogl-list.h" typedef struct _CoglGLES2Offscreen { CoglList link; CoglOffscreen *original_offscreen; CoglGLFramebuffer gl_framebuffer; } CoglGLES2Offscreen; typedef struct { /* GL's ID for the shader */ GLuint object_id; /* Shader type */ GLenum type; /* Number of references to this shader. The shader will have one * reference when it is created. This reference will be removed when * glDeleteShader is called. An additional reference will be taken * whenever the shader is attached to a program. This is necessary * to correctly detect when a shader is destroyed because * glDeleteShader doesn't actually delete the object if it is * attached to a program */ int ref_count; /* Set once this object has had glDeleteShader called on it. We need * to keep track of this so we don't deref the data twice if the * application calls glDeleteShader multiple times */ CoglBool deleted; } CoglGLES2ShaderData; typedef enum { COGL_GLES2_FLIP_STATE_UNKNOWN, COGL_GLES2_FLIP_STATE_NORMAL, COGL_GLES2_FLIP_STATE_FLIPPED } CoglGLES2FlipState; typedef struct { /* GL's ID for the program */ GLuint object_id; /* List of shaders attached to this program */ GList *attached_shaders; /* Reference count. There can be up to two references. One of these * will exist between glCreateProgram and glDeleteShader, the other * will exist while the program is made current. This is necessary * to correctly detect when the program is deleted because * glDeleteShader will delay the deletion if the program is * current */ int ref_count; /* Set once this object has had glDeleteProgram called on it. We need * to keep track of this so we don't deref the data twice if the * application calls glDeleteProgram multiple times */ CoglBool deleted; GLuint flip_vector_location; /* A cache of what value we've put in the flip vector uniform so * that we don't flush unless it's changed */ CoglGLES2FlipState flip_vector_state; CoglGLES2Context *context; } CoglGLES2ProgramData; /* State tracked for each texture unit */ typedef struct { /* The currently bound texture for the GL_TEXTURE_2D */ GLuint current_texture_2d; } CoglGLES2TextureUnitData; /* State tracked for each texture object */ typedef struct { /* GL's ID for this object */ GLuint object_id; GLenum target; /* The details for texture when it has a 2D target */ int width, height; GLenum format; } CoglGLES2TextureObjectData; struct _CoglGLES2Context { CoglObject _parent; CoglContext *context; /* This is set to FALSE until the first time the GLES2 context is * bound to something. We need to keep track of this so we can set * the viewport and scissor the first time it is bound. */ CoglBool has_been_bound; CoglFramebuffer *read_buffer; CoglGLES2Offscreen *gles2_read_buffer; CoglFramebuffer *write_buffer; CoglGLES2Offscreen *gles2_write_buffer; GLuint current_fbo_handle; CoglList foreign_offscreens; CoglGLES2Vtable *vtable; /* Hash table mapping GL's IDs for shaders and objects to ShaderData * and ProgramData so that we can maintain extra data for these * objects. Although technically the IDs will end up global across * all GLES2 contexts because they will all be in the same share * list, we don't really want to expose this outside of the Cogl API * so we will assume it is undefined behaviour if an application * relies on this. */ GHashTable *shader_map; GHashTable *program_map; /* Currently in use program. We need to keep track of this so that * we can keep a reference to the data for the program while it is * current */ CoglGLES2ProgramData *current_program; /* Whether the currently bound framebuffer needs flipping. This is * used to check for changes so that we can dirty the following * state flags */ CoglGLES2FlipState current_flip_state; /* The following state is tracked separately from the GL context * because we need to modify it depending on whether we are flipping * the geometry. */ CoglBool viewport_dirty; int viewport[4]; CoglBool scissor_dirty; int scissor[4]; CoglBool front_face_dirty; GLenum front_face; /* We need to keep track of the pack alignment so we can flip the * results of glReadPixels read from a CoglOffscreen */ int pack_alignment; /* A hash table of CoglGLES2TextureObjects indexed by the texture * object ID so that we can track some state */ GHashTable *texture_object_map; /* Array of CoglGLES2TextureUnits to keep track of state for each * texture unit */ GArray *texture_units; /* The currently active texture unit indexed from 0 (not from * GL_TEXTURE0) */ int current_texture_unit; void *winsys; }; #endif /* __COGL_GLES2_CONTEXT_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-memory-stack.c0000664000175000017500000001373214211404421020513 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * CoglMemoryStack provides a really simple, but lightning fast * memory stack allocation strategy: * * - The underlying pool of memory is grow-only. * - The pool is considered to be a stack which may be comprised * of multiple smaller stacks. Allocation is done as follows: * - If there's enough memory in the current sub-stack then the * stack-pointer will be returned as the allocation and the * stack-pointer will be incremented by the allocation size. * - If there isn't enough memory in the current sub-stack * then a new sub-stack is allocated twice as big as the current * sub-stack or twice as big as the requested allocation size if * that's bigger and the stack-pointer is set to the start of the * new sub-stack. * - Allocations can't be freed in a random-order, you can only * rewind the entire stack back to the start. There is no * the concept of stack frames to allow partial rewinds. * * For example; we plan to use this in our tesselator which has to * allocate lots of small vertex, edge and face structures because * when tesselation has been finished we just want to free the whole * lot in one go. * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-memory-stack-private.h" #include "cogl-list.h" #include #include typedef struct _CoglMemorySubStack { CoglList link; size_t bytes; uint8_t *data; } CoglMemorySubStack; struct _CoglMemoryStack { CoglList sub_stacks; CoglMemorySubStack *sub_stack; size_t sub_stack_offset; }; static CoglMemorySubStack * _cogl_memory_sub_stack_alloc (size_t bytes) { CoglMemorySubStack *sub_stack = g_slice_new (CoglMemorySubStack); sub_stack->bytes = bytes; sub_stack->data = malloc (bytes); return sub_stack; } static void _cogl_memory_stack_add_sub_stack (CoglMemoryStack *stack, size_t sub_stack_bytes) { CoglMemorySubStack *sub_stack = _cogl_memory_sub_stack_alloc (sub_stack_bytes); _cogl_list_insert (stack->sub_stacks.prev, &sub_stack->link); stack->sub_stack = sub_stack; stack->sub_stack_offset = 0; } CoglMemoryStack * _cogl_memory_stack_new (size_t initial_size_bytes) { CoglMemoryStack *stack = g_slice_new0 (CoglMemoryStack); _cogl_list_init (&stack->sub_stacks); _cogl_memory_stack_add_sub_stack (stack, initial_size_bytes); return stack; } void * _cogl_memory_stack_alloc (CoglMemoryStack *stack, size_t bytes) { CoglMemorySubStack *sub_stack; void *ret; sub_stack = stack->sub_stack; if (G_LIKELY (sub_stack->bytes - stack->sub_stack_offset >= bytes)) { ret = sub_stack->data + stack->sub_stack_offset; stack->sub_stack_offset += bytes; return ret; } /* If the stack has been rewound and then a large initial allocation * is made then we may need to skip over one or more of the * sub-stacks that are too small for the requested allocation * size... */ for (_cogl_list_set_iterator (sub_stack->link.next, sub_stack, link); &sub_stack->link != &stack->sub_stacks; _cogl_list_set_iterator (sub_stack->link.next, sub_stack, link)) { if (sub_stack->bytes >= bytes) { ret = sub_stack->data; stack->sub_stack = sub_stack; stack->sub_stack_offset = bytes; return ret; } } /* Finally if we couldn't find a free sub-stack with enough space * for the requested allocation we allocate another sub-stack that's * twice as big as the last sub-stack or twice as big as the * requested allocation if that's bigger. */ sub_stack = _cogl_container_of (stack->sub_stacks.prev, CoglMemorySubStack, link); _cogl_memory_stack_add_sub_stack (stack, MAX (sub_stack->bytes, bytes) * 2); sub_stack = _cogl_container_of (stack->sub_stacks.prev, CoglMemorySubStack, link); stack->sub_stack_offset += bytes; return sub_stack->data; } void _cogl_memory_stack_rewind (CoglMemoryStack *stack) { stack->sub_stack = _cogl_container_of (stack->sub_stacks.next, CoglMemorySubStack, link); stack->sub_stack_offset = 0; } static void _cogl_memory_sub_stack_free (CoglMemorySubStack *sub_stack) { free (sub_stack->data); g_slice_free (CoglMemorySubStack, sub_stack); } void _cogl_memory_stack_free (CoglMemoryStack *stack) { while (!_cogl_list_empty (&stack->sub_stacks)) { CoglMemorySubStack *sub_stack = _cogl_container_of (stack->sub_stacks.next, CoglMemorySubStack, link); _cogl_list_remove (&sub_stack->link); _cogl_memory_sub_stack_free (sub_stack); } g_slice_free (CoglMemoryStack, stack); } muffin-5.2.1/cogl/cogl/cogl-memory-stack-private.h0000664000175000017500000000312314211404421022161 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_MEMORY_STACK__ #define __COGL_MEMORY_STACK__ #include typedef struct _CoglMemoryStack CoglMemoryStack; CoglMemoryStack * _cogl_memory_stack_new (size_t initial_size_bytes); void * _cogl_memory_stack_alloc (CoglMemoryStack *stack, size_t bytes); void _cogl_memory_stack_rewind (CoglMemoryStack *stack); void _cogl_memory_stack_free (CoglMemoryStack *stack); #endif /* __COGL_MEMORY_STACK__ */ muffin-5.2.1/cogl/cogl/cogl-i18n-private.h0000664000175000017500000000250114211404421020324 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef _COGL_I18N_PRIVATE_H_ #define _COGL_I18N_PRIVATE_H_ #include #define _(X) X #define N_(X) X #endif /* _COGL_I18N_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/cogl-blit.h0000664000175000017500000000563114211404421017036 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_BLIT_H #define __COGL_BLIT_H #include #include "cogl-object-private.h" #include "cogl-texture.h" #include "cogl-framebuffer.h" /* This structures and functions are used when a series of blits needs to be performed between two textures. In this case there are multiple methods we can use, most of which involve transferring between an FBO bound to the texture. */ typedef struct _CoglBlitData CoglBlitData; typedef CoglBool (* CoglBlitBeginFunc) (CoglBlitData *data); typedef void (* CoglBlitEndFunc) (CoglBlitData *data); typedef void (* CoglBlitFunc) (CoglBlitData *data, int src_x, int src_y, int dst_x, int dst_y, int width, int height); typedef struct { const char *name; CoglBlitBeginFunc begin_func; CoglBlitFunc blit_func; CoglBlitEndFunc end_func; } CoglBlitMode; struct _CoglBlitData { CoglTexture *src_tex, *dst_tex; unsigned int src_width; unsigned int src_height; const CoglBlitMode *blit_mode; /* If we're not using an FBO then we malloc a buffer and copy the complete texture data in */ unsigned char *image_data; CoglPixelFormat format; int bpp; CoglFramebuffer *src_fb; CoglFramebuffer *dest_fb; CoglPipeline *pipeline; }; void _cogl_blit_begin (CoglBlitData *data, CoglTexture *dst_tex, CoglTexture *src_tex); void _cogl_blit (CoglBlitData *data, int src_x, int src_y, int dst_x, int dst_y, int width, int height); void _cogl_blit_end (CoglBlitData *data); #endif /* __COGL_BLIT_H */ muffin-5.2.1/cogl/cogl/cogl-rectangle-map.h0000664000175000017500000000536114211404421020623 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_RECTANGLE_MAP_H #define __COGL_RECTANGLE_MAP_H #include #include "cogl-types.h" typedef struct _CoglRectangleMap CoglRectangleMap; typedef struct _CoglRectangleMapEntry CoglRectangleMapEntry; typedef void (* CoglRectangleMapCallback) (const CoglRectangleMapEntry *entry, void *rectangle_data, void *user_data); struct _CoglRectangleMapEntry { unsigned int x, y; unsigned int width, height; }; CoglRectangleMap * _cogl_rectangle_map_new (unsigned int width, unsigned int height, GDestroyNotify value_destroy_func); CoglBool _cogl_rectangle_map_add (CoglRectangleMap *map, unsigned int width, unsigned int height, void *data, CoglRectangleMapEntry *rectangle); void _cogl_rectangle_map_remove (CoglRectangleMap *map, const CoglRectangleMapEntry *rectangle); unsigned int _cogl_rectangle_map_get_width (CoglRectangleMap *map); unsigned int _cogl_rectangle_map_get_height (CoglRectangleMap *map); unsigned int _cogl_rectangle_map_get_remaining_space (CoglRectangleMap *map); unsigned int _cogl_rectangle_map_get_n_rectangles (CoglRectangleMap *map); void _cogl_rectangle_map_foreach (CoglRectangleMap *map, CoglRectangleMapCallback callback, void *data); void _cogl_rectangle_map_free (CoglRectangleMap *map); #endif /* __COGL_RECTANGLE_MAP_H */ muffin-5.2.1/cogl/cogl/cogl-onscreen-private.h0000664000175000017500000000604614211404421021371 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_ONSCREEN_PRIVATE_H #define __COGL_ONSCREEN_PRIVATE_H #include "cogl-onscreen.h" #include "cogl-framebuffer-private.h" #include "cogl-closure-list-private.h" #include "cogl-list.h" #include typedef struct _CoglOnscreenEvent { CoglList link; CoglOnscreen *onscreen; CoglFrameInfo *info; CoglFrameEvent type; } CoglOnscreenEvent; typedef struct _CoglOnscreenQueuedDirty { CoglList link; CoglOnscreen *onscreen; CoglOnscreenDirtyInfo info; } CoglOnscreenQueuedDirty; struct _CoglOnscreen { CoglFramebuffer _parent; #ifdef COGL_HAS_X11_SUPPORT uint32_t foreign_xid; CoglOnscreenX11MaskCallback foreign_update_mask_callback; void *foreign_update_mask_data; #endif CoglBool swap_throttled; CoglList frame_closures; CoglBool resizable; CoglList resize_closures; CoglList dirty_closures; int64_t frame_counter; int64_t swap_frame_counter; /* frame counter at last all to * cogl_onscreen_swap_region() or * cogl_onscreen_swap_buffers() */ GQueue pending_frame_infos; void *winsys; }; CoglOnscreen * _cogl_onscreen_new (void); void _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer, int width, int height); void _cogl_onscreen_queue_event (CoglOnscreen *onscreen, CoglFrameEvent type, CoglFrameInfo *info); void _cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info); void _cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info); void _cogl_onscreen_notify_resize (CoglOnscreen *onscreen); void _cogl_onscreen_queue_dirty (CoglOnscreen *onscreen, const CoglOnscreenDirtyInfo *info); void _cogl_onscreen_queue_full_dirty (CoglOnscreen *onscreen); #endif /* __COGL_ONSCREEN_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/0000775000175000017500000000000014211404421016277 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/driver/nop/0000775000175000017500000000000014211404421017073 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/driver/nop/cogl-clip-stack-nop-private.h0000664000175000017500000000302214211404421024457 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_CLIP_STACK_NOP_PRIVATE_H_ #define _COGL_CLIP_STACK_NOP_PRIVATE_H_ #include "cogl-types.h" #include "cogl-context-private.h" void _cogl_clip_stack_nop_flush (CoglClipStack *stack, CoglFramebuffer *framebuffer); #endif /* _COGL_CLIP_STACK_NOP_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/nop/cogl-clip-stack-nop.c0000664000175000017500000000270414211404421023010 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-clip-stack.h" #include "cogl-clip-stack-nop-private.h" #include "cogl-framebuffer-private.h" void _cogl_clip_stack_nop_flush (CoglClipStack *stack, CoglFramebuffer *framebuffer) { } muffin-5.2.1/cogl/cogl/driver/nop/cogl-framebuffer-nop.c0000664000175000017500000000761614211404421023251 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-framebuffer-nop-private.h" #include #include void _cogl_framebuffer_nop_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state) { } CoglBool _cogl_offscreen_nop_allocate (CoglOffscreen *offscreen, CoglError **error) { return TRUE; } void _cogl_offscreen_nop_free (CoglOffscreen *offscreen) { } void _cogl_framebuffer_nop_clear (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha) { } void _cogl_framebuffer_nop_query_bits (CoglFramebuffer *framebuffer, CoglFramebufferBits *bits) { memset (bits, 0, sizeof (CoglFramebufferBits)); } void _cogl_framebuffer_nop_finish (CoglFramebuffer *framebuffer) { } void _cogl_framebuffer_nop_discard_buffers (CoglFramebuffer *framebuffer, unsigned long buffers) { } void _cogl_framebuffer_nop_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags) { } void _cogl_framebuffer_nop_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags) { } CoglBool _cogl_framebuffer_nop_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error) { return TRUE; } muffin-5.2.1/cogl/cogl/driver/nop/cogl-texture-2d-nop.c0000664000175000017500000000762314211404421022766 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2011,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-private.h" #include "cogl-texture-2d-nop-private.h" #include "cogl-texture-2d-private.h" #include "cogl-error-private.h" void _cogl_texture_2d_nop_free (CoglTexture2D *tex_2d) { } CoglBool _cogl_texture_2d_nop_can_create (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format) { return TRUE; } void _cogl_texture_2d_nop_init (CoglTexture2D *tex_2d) { } CoglBool _cogl_texture_2d_nop_allocate (CoglTexture *tex, CoglError **error) { return TRUE; } void _cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { } void _cogl_texture_2d_nop_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { } void _cogl_texture_2d_nop_copy_from_framebuffer (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglFramebuffer *src_fb, int dst_x, int dst_y, int level) { } unsigned int _cogl_texture_2d_nop_get_gl_handle (CoglTexture2D *tex_2d) { return 0; } void _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d) { } CoglBool _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglBitmap *bitmap, int dst_x, int dst_y, int level, CoglError **error) { return TRUE; } void _cogl_texture_2d_nop_get_data (CoglTexture2D *tex_2d, CoglPixelFormat format, size_t rowstride, uint8_t *data) { } muffin-5.2.1/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h0000664000175000017500000000757214211404421024727 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_FRAMEBUFFER_NOP_PRIVATE_H_ #define _COGL_FRAMEBUFFER_NOP_PRIVATE_H_ #include "cogl-types.h" #include "cogl-context-private.h" CoglBool _cogl_offscreen_nop_allocate (CoglOffscreen *offscreen, CoglError **error); void _cogl_offscreen_nop_free (CoglOffscreen *offscreen); void _cogl_framebuffer_nop_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state); void _cogl_framebuffer_nop_clear (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha); void _cogl_framebuffer_nop_query_bits (CoglFramebuffer *framebuffer, CoglFramebufferBits *bits); void _cogl_framebuffer_nop_finish (CoglFramebuffer *framebuffer); void _cogl_framebuffer_nop_discard_buffers (CoglFramebuffer *framebuffer, unsigned long buffers); void _cogl_framebuffer_nop_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); void _cogl_framebuffer_nop_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); CoglBool _cogl_framebuffer_nop_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error); #endif /* _COGL_FRAMEBUFFER_NOP_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/nop/cogl-texture-2d-nop-private.h0000664000175000017500000000737714211404421024451 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_TEXTURE_2D_NOP_PRIVATE_H_ #define _COGL_TEXTURE_2D_NOP_PRIVATE_H_ #include "cogl-types.h" #include "cogl-context-private.h" #include "cogl-texture.h" void _cogl_texture_2d_nop_free (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_nop_can_create (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format); void _cogl_texture_2d_nop_init (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_nop_allocate (CoglTexture *tex, CoglError **error); void _cogl_texture_2d_nop_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter); void _cogl_texture_2d_nop_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p); void _cogl_texture_2d_nop_copy_from_framebuffer (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglFramebuffer *src_fb, int dst_x, int dst_y, int level); unsigned int _cogl_texture_2d_nop_get_gl_handle (CoglTexture2D *tex_2d); void _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglBitmap *bitmap, int dst_x, int dst_y, int level, CoglError **error); void _cogl_texture_2d_nop_get_data (CoglTexture2D *tex_2d, CoglPixelFormat format, size_t rowstride, uint8_t *data); #endif /* _COGL_TEXTURE_2D_NOP_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/nop/cogl-attribute-nop-private.h0000664000175000017500000000341314211404421024434 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_ATTRIBUTE_NOP_PRIVATE_H_ #define _COGL_ATTRIBUTE_NOP_PRIVATE_H_ #include "cogl-types.h" #include "cogl-context-private.h" void _cogl_nop_flush_attributes_state (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglFlushLayerState *layers_state, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes); #endif /* _COGL_ATTRIBUTE_NOP_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/nop/cogl-driver-nop.c0000664000175000017500000000551714211404421022256 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-private.h" #include "cogl-context-private.h" #include "cogl-feature-private.h" #include "cogl-renderer-private.h" #include "cogl-error-private.h" #include "cogl-framebuffer-nop-private.h" #include "cogl-texture-2d-nop-private.h" #include "cogl-attribute-nop-private.h" #include "cogl-clip-stack-nop-private.h" static CoglBool _cogl_driver_update_features (CoglContext *ctx, CoglError **error) { /* _cogl_gpu_info_init (ctx, &ctx->gpu); */ memset (ctx->private_features, 0, sizeof (ctx->private_features)); ctx->feature_flags = 0; return TRUE; } const CoglDriverVtable _cogl_driver_nop = { NULL, /* pixel_format_from_gl_internal */ NULL, /* pixel_format_to_gl */ NULL, /* pixel_format_to_gl_with_target */ _cogl_driver_update_features, _cogl_offscreen_nop_allocate, _cogl_offscreen_nop_free, _cogl_framebuffer_nop_flush_state, _cogl_framebuffer_nop_clear, _cogl_framebuffer_nop_query_bits, _cogl_framebuffer_nop_finish, _cogl_framebuffer_nop_discard_buffers, _cogl_framebuffer_nop_draw_attributes, _cogl_framebuffer_nop_draw_indexed_attributes, _cogl_framebuffer_nop_read_pixels_into_bitmap, _cogl_texture_2d_nop_free, _cogl_texture_2d_nop_can_create, _cogl_texture_2d_nop_init, _cogl_texture_2d_nop_allocate, _cogl_texture_2d_nop_copy_from_framebuffer, _cogl_texture_2d_nop_get_gl_handle, _cogl_texture_2d_nop_generate_mipmap, _cogl_texture_2d_nop_copy_from_bitmap, NULL, /* texture_2d_get_data */ _cogl_nop_flush_attributes_state, _cogl_clip_stack_nop_flush, }; muffin-5.2.1/cogl/cogl/driver/nop/cogl-attribute-nop.c0000664000175000017500000000336214211404421022762 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-types.h" #include "cogl-framebuffer.h" #include "cogl-attribute.h" #include "cogl-attribute-private.h" #include "cogl-attribute-nop-private.h" void _cogl_nop_flush_attributes_state (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglFlushLayerState *layers_state, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes) { } muffin-5.2.1/cogl/cogl/driver/gl/0000775000175000017500000000000014211404421016701 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-opengl.c0000664000175000017500000014477214211404421023075 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #include "cogl-config.h" #include "cogl-debug.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-pipeline-private.h" #include "cogl-context-private.h" #include "cogl-texture-private.h" #include "cogl-framebuffer-private.h" #include "cogl-offscreen.h" #include "cogl-texture-gl-private.h" #include "cogl-pipeline-progend-glsl-private.h" #include #include #include /* * GL/GLES compatability defines for pipeline thingies: */ /* These aren't defined in the GLES headers */ #ifndef GL_POINT_SPRITE #define GL_POINT_SPRITE 0x8861 #endif #ifndef GL_COORD_REPLACE #define GL_COORD_REPLACE 0x8862 #endif #ifndef GL_CLAMP_TO_BORDER #define GL_CLAMP_TO_BORDER 0x812d #endif #ifndef GL_PROGRAM_POINT_SIZE #define GL_PROGRAM_POINT_SIZE 0x8642 #endif static void texture_unit_init (CoglContext *ctx, CoglTextureUnit *unit, int index_) { unit->index = index_; unit->enabled_gl_target = 0; unit->gl_texture = 0; unit->gl_target = 0; unit->is_foreign = FALSE; unit->dirty_gl_texture = FALSE; unit->matrix_stack = cogl_matrix_stack_new (ctx); unit->layer = NULL; unit->layer_changes_since_flush = 0; unit->texture_storage_changed = FALSE; } static void texture_unit_free (CoglTextureUnit *unit) { if (unit->layer) cogl_object_unref (unit->layer); cogl_object_unref (unit->matrix_stack); } CoglTextureUnit * _cogl_get_texture_unit (int index_) { _COGL_GET_CONTEXT (ctx, NULL); if (ctx->texture_units->len < (index_ + 1)) { int i; int prev_len = ctx->texture_units->len; ctx->texture_units = g_array_set_size (ctx->texture_units, index_ + 1); for (i = prev_len; i <= index_; i++) { CoglTextureUnit *unit = &g_array_index (ctx->texture_units, CoglTextureUnit, i); texture_unit_init (ctx, unit, i); } } return &g_array_index (ctx->texture_units, CoglTextureUnit, index_); } void _cogl_destroy_texture_units (void) { int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); for (i = 0; i < ctx->texture_units->len; i++) { CoglTextureUnit *unit = &g_array_index (ctx->texture_units, CoglTextureUnit, i); texture_unit_free (unit); } g_array_free (ctx->texture_units, TRUE); } void _cogl_set_active_texture_unit (int unit_index) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->active_texture_unit != unit_index) { GE (ctx, glActiveTexture (GL_TEXTURE0 + unit_index)); ctx->active_texture_unit = unit_index; } } /* Note: _cogl_bind_gl_texture_transient conceptually has slightly * different semantics to OpenGL's glBindTexture because Cogl never * cares about tracking multiple textures bound to different targets * on the same texture unit. * * glBindTexture lets you bind multiple textures to a single texture * unit if they are bound to different targets. So it does something * like: * unit->current_texture[target] = texture; * * Cogl only lets you associate one texture with the currently active * texture unit, so the target is basically a redundant parameter * that's implicitly set on that texture. * * Technically this is just a thin wrapper around glBindTexture so * actually it does have the GL semantics but it seems worth * mentioning the conceptual difference in case anyone wonders why we * don't associate the gl_texture with a gl_target in the * CoglTextureUnit. */ void _cogl_bind_gl_texture_transient (GLenum gl_target, GLuint gl_texture, CoglBool is_foreign) { CoglTextureUnit *unit; _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* We choose to always make texture unit 1 active for transient * binds so that in the common case where multitexturing isn't used * we can simply ignore the state of this texture unit. Notably we * didn't use a large texture unit (.e.g. (GL_MAX_TEXTURE_UNITS - 1) * in case the driver doesn't have a sparse data structure for * texture units. */ _cogl_set_active_texture_unit (1); unit = _cogl_get_texture_unit (1); /* NB: If we have previously bound a foreign texture to this texture * unit we don't know if that texture has since been deleted and we * are seeing the texture name recycled */ if (unit->gl_texture == gl_texture && !unit->dirty_gl_texture && !unit->is_foreign) return; GE (ctx, glBindTexture (gl_target, gl_texture)); unit->dirty_gl_texture = TRUE; unit->is_foreign = is_foreign; } void _cogl_delete_gl_texture (GLuint gl_texture) { int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); for (i = 0; i < ctx->texture_units->len; i++) { CoglTextureUnit *unit = &g_array_index (ctx->texture_units, CoglTextureUnit, i); if (unit->gl_texture == gl_texture) { unit->gl_texture = 0; unit->gl_target = 0; unit->dirty_gl_texture = FALSE; } } GE (ctx, glDeleteTextures (1, &gl_texture)); } /* Whenever the underlying GL texture storage of a CoglTexture is * changed (e.g. due to migration out of a texture atlas) then we are * notified. This lets us ensure that we reflush that texture's state * if it is reused again with the same texture unit. */ void _cogl_pipeline_texture_storage_change_notify (CoglTexture *texture) { int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); for (i = 0; i < ctx->texture_units->len; i++) { CoglTextureUnit *unit = &g_array_index (ctx->texture_units, CoglTextureUnit, i); if (unit->layer && _cogl_pipeline_layer_get_texture (unit->layer) == texture) unit->texture_storage_changed = TRUE; /* NB: the texture may be bound to multiple texture units so * we continue to check the rest */ } } static void set_glsl_program (GLuint gl_program) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->current_gl_program != gl_program) { _cogl_gl_util_clear_gl_errors (ctx); ctx->glUseProgram (gl_program); if (_cogl_gl_util_get_error (ctx) == GL_NO_ERROR) ctx->current_gl_program = gl_program; else { GE( ctx, glUseProgram (0) ); ctx->current_gl_program = 0; } } } void _cogl_use_fragment_program (GLuint gl_program, CoglPipelineProgramType type) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* If we're changing program type... */ if (type != ctx->current_fragment_program_type) { /* ... disable the old type */ switch (ctx->current_fragment_program_type) { case COGL_PIPELINE_PROGRAM_TYPE_GLSL: /* If the program contains a vertex shader then we shouldn't disable it */ if (ctx->current_vertex_program_type != COGL_PIPELINE_PROGRAM_TYPE_GLSL) set_glsl_program (0); break; case COGL_PIPELINE_PROGRAM_TYPE_ARBFP: #ifdef HAVE_COGL_GL GE( ctx, glDisable (GL_FRAGMENT_PROGRAM_ARB) ); #endif break; case COGL_PIPELINE_PROGRAM_TYPE_FIXED: /* don't need to to anything */ break; } /* ... and enable the new type */ switch (type) { case COGL_PIPELINE_PROGRAM_TYPE_ARBFP: #ifdef HAVE_COGL_GL GE( ctx, glEnable (GL_FRAGMENT_PROGRAM_ARB) ); #endif break; case COGL_PIPELINE_PROGRAM_TYPE_GLSL: case COGL_PIPELINE_PROGRAM_TYPE_FIXED: /* don't need to to anything */ break; } } if (type == COGL_PIPELINE_PROGRAM_TYPE_GLSL) { #ifdef COGL_PIPELINE_FRAGEND_GLSL set_glsl_program (gl_program); #else g_warning ("Unexpected use of GLSL fragend!"); #endif /* COGL_PIPELINE_FRAGEND_GLSL */ } #ifndef COGL_PIPELINE_FRAGEND_ARBFP else if (type == COGL_PIPELINE_PROGRAM_TYPE_ARBFP) g_warning ("Unexpected use of ARBFP fragend!"); #endif /* COGL_PIPELINE_FRAGEND_ARBFP */ ctx->current_fragment_program_type = type; } void _cogl_use_vertex_program (GLuint gl_program, CoglPipelineProgramType type) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* If we're changing program type... */ if (type != ctx->current_vertex_program_type) { /* ... disable the old type */ switch (ctx->current_vertex_program_type) { case COGL_PIPELINE_PROGRAM_TYPE_GLSL: /* If the program contains a fragment shader then we shouldn't disable it */ if (ctx->current_fragment_program_type != COGL_PIPELINE_PROGRAM_TYPE_GLSL) set_glsl_program (0); break; case COGL_PIPELINE_PROGRAM_TYPE_ARBFP: /* It doesn't make sense to enable ARBfp for the vertex program */ g_assert_not_reached (); break; case COGL_PIPELINE_PROGRAM_TYPE_FIXED: /* don't need to to anything */ break; } /* ... and enable the new type */ switch (type) { case COGL_PIPELINE_PROGRAM_TYPE_ARBFP: /* It doesn't make sense to enable ARBfp for the vertex program */ g_assert_not_reached (); break; case COGL_PIPELINE_PROGRAM_TYPE_GLSL: case COGL_PIPELINE_PROGRAM_TYPE_FIXED: /* don't need to to anything */ break; } } if (type == COGL_PIPELINE_PROGRAM_TYPE_GLSL) { #ifdef COGL_PIPELINE_VERTEND_GLSL set_glsl_program (gl_program); #else g_warning ("Unexpected use of GLSL vertend!"); #endif /* COGL_PIPELINE_VERTEND_GLSL */ } #ifndef COGL_PIPELINE_VERTEND_ARBFP else if (type == COGL_PIPELINE_PROGRAM_TYPE_ARBFP) g_warning ("Unexpected use of ARBFP vertend!"); #endif /* COGL_PIPELINE_VERTEND_ARBFP */ ctx->current_vertex_program_type = type; } #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) static CoglBool blend_factor_uses_constant (GLenum blend_factor) { return (blend_factor == GL_CONSTANT_COLOR || blend_factor == GL_ONE_MINUS_CONSTANT_COLOR || blend_factor == GL_CONSTANT_ALPHA || blend_factor == GL_ONE_MINUS_CONSTANT_ALPHA); } #endif static void flush_depth_state (CoglContext *ctx, CoglDepthState *depth_state) { CoglBool depth_writing_enabled = depth_state->write_enabled; if (ctx->current_draw_buffer) depth_writing_enabled &= ctx->current_draw_buffer->depth_writing_enabled; if (ctx->depth_test_enabled_cache != depth_state->test_enabled) { if (depth_state->test_enabled == TRUE) GE (ctx, glEnable (GL_DEPTH_TEST)); else GE (ctx, glDisable (GL_DEPTH_TEST)); ctx->depth_test_enabled_cache = depth_state->test_enabled; } if (ctx->depth_test_function_cache != depth_state->test_function && depth_state->test_enabled == TRUE) { GE (ctx, glDepthFunc (depth_state->test_function)); ctx->depth_test_function_cache = depth_state->test_function; } if (ctx->depth_writing_enabled_cache != depth_writing_enabled) { GE (ctx, glDepthMask (depth_writing_enabled ? GL_TRUE : GL_FALSE)); ctx->depth_writing_enabled_cache = depth_writing_enabled; } if (ctx->driver != COGL_DRIVER_GLES1 && (ctx->depth_range_near_cache != depth_state->range_near || ctx->depth_range_far_cache != depth_state->range_far)) { if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED)) GE (ctx, glDepthRangef (depth_state->range_near, depth_state->range_far)); else GE (ctx, glDepthRange (depth_state->range_near, depth_state->range_far)); ctx->depth_range_near_cache = depth_state->range_near; ctx->depth_range_far_cache = depth_state->range_far; } } UNIT_TEST (check_gl_blend_enable, 0 /* no requirements */, 0 /* no failure cases */) { CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); /* By default blending should be disabled */ g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); _cogl_framebuffer_flush_journal (test_fb); /* After drawing an opaque rectangle blending should still be * disabled */ g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); cogl_pipeline_set_color4f (pipeline, 0, 0, 0, 0); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); _cogl_framebuffer_flush_journal (test_fb); /* After drawing a transparent rectangle blending should be enabled */ g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 1); cogl_pipeline_set_blend (pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL); cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); _cogl_framebuffer_flush_journal (test_fb); /* After setting a blend string that effectively disables blending * then blending should be disabled */ g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); } static void _cogl_pipeline_flush_color_blend_alpha_depth_state ( CoglPipeline *pipeline, unsigned long pipelines_difference, CoglBool with_color_attrib) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* On GLES2 we'll flush the color later */ if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED) && !with_color_attrib) { if ((pipelines_difference & COGL_PIPELINE_STATE_COLOR) || /* Assume if we were previously told to skip the color, then * the current color needs updating... */ ctx->current_pipeline_with_color_attrib) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); GE (ctx, glColor4ub (cogl_color_get_red_byte (&authority->color), cogl_color_get_green_byte (&authority->color), cogl_color_get_blue_byte (&authority->color), cogl_color_get_alpha_byte (&authority->color))); } } if (pipelines_difference & COGL_PIPELINE_STATE_BLEND) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND); CoglPipelineBlendState *blend_state = &authority->big_state->blend_state; /* GLES 1 only has glBlendFunc */ if (ctx->driver == COGL_DRIVER_GLES1) { GE (ctx, glBlendFunc (blend_state->blend_src_factor_rgb, blend_state->blend_dst_factor_rgb)); } #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) else { if (blend_factor_uses_constant (blend_state->blend_src_factor_rgb) || blend_factor_uses_constant (blend_state ->blend_src_factor_alpha) || blend_factor_uses_constant (blend_state->blend_dst_factor_rgb) || blend_factor_uses_constant (blend_state->blend_dst_factor_alpha)) { float red = cogl_color_get_red_float (&blend_state->blend_constant); float green = cogl_color_get_green_float (&blend_state->blend_constant); float blue = cogl_color_get_blue_float (&blend_state->blend_constant); float alpha = cogl_color_get_alpha_float (&blend_state->blend_constant); GE (ctx, glBlendColor (red, green, blue, alpha)); } if (ctx->glBlendEquationSeparate && blend_state->blend_equation_rgb != blend_state->blend_equation_alpha) GE (ctx, glBlendEquationSeparate (blend_state->blend_equation_rgb, blend_state->blend_equation_alpha)); else GE (ctx, glBlendEquation (blend_state->blend_equation_rgb)); if (ctx->glBlendFuncSeparate && (blend_state->blend_src_factor_rgb != blend_state->blend_src_factor_alpha || (blend_state->blend_dst_factor_rgb != blend_state->blend_dst_factor_alpha))) GE (ctx, glBlendFuncSeparate (blend_state->blend_src_factor_rgb, blend_state->blend_dst_factor_rgb, blend_state->blend_src_factor_alpha, blend_state->blend_dst_factor_alpha)); else GE (ctx, glBlendFunc (blend_state->blend_src_factor_rgb, blend_state->blend_dst_factor_rgb)); } #endif } #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEST)) { /* Under GLES2 the alpha function is implemented as part of the fragment shader */ if (pipelines_difference & (COGL_PIPELINE_STATE_ALPHA_FUNC | COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE)) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_ALPHA_FUNC); CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state; /* NB: Currently the Cogl defines are compatible with the GL ones: */ GE (ctx, glAlphaFunc (alpha_state->alpha_func, alpha_state->alpha_func_reference)); } /* Under GLES2 the lighting parameters are implemented as uniforms in the progend */ if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); CoglPipelineLightingState *lighting_state = &authority->big_state->lighting_state; GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, lighting_state->ambient)); GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, lighting_state->diffuse)); GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, lighting_state->specular)); GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, lighting_state->emission)); GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, &lighting_state->shininess)); } } #endif if (pipelines_difference & COGL_PIPELINE_STATE_DEPTH) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH); CoglDepthState *depth_state = &authority->big_state->depth_state; flush_depth_state (ctx, depth_state); } if (pipelines_difference & COGL_PIPELINE_STATE_LOGIC_OPS) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS); CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state; CoglColorMask color_mask = logic_ops_state->color_mask; if (ctx->current_draw_buffer) color_mask &= ctx->current_draw_buffer->color_mask; GE (ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED), !!(color_mask & COGL_COLOR_MASK_GREEN), !!(color_mask & COGL_COLOR_MASK_BLUE), !!(color_mask & COGL_COLOR_MASK_ALPHA))); ctx->current_gl_color_mask = color_mask; } if (pipelines_difference & COGL_PIPELINE_STATE_CULL_FACE) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_CULL_FACE); CoglPipelineCullFaceState *cull_face_state = &authority->big_state->cull_face_state; if (cull_face_state->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE) GE( ctx, glDisable (GL_CULL_FACE) ); else { CoglBool invert_winding; GE( ctx, glEnable (GL_CULL_FACE) ); switch (cull_face_state->mode) { case COGL_PIPELINE_CULL_FACE_MODE_NONE: g_assert_not_reached (); case COGL_PIPELINE_CULL_FACE_MODE_FRONT: GE( ctx, glCullFace (GL_FRONT) ); break; case COGL_PIPELINE_CULL_FACE_MODE_BACK: GE( ctx, glCullFace (GL_BACK) ); break; case COGL_PIPELINE_CULL_FACE_MODE_BOTH: GE( ctx, glCullFace (GL_FRONT_AND_BACK) ); break; } /* If we are painting to an offscreen framebuffer then we need to invert the winding of the front face because everything is painted upside down */ invert_winding = cogl_is_offscreen (ctx->current_draw_buffer); switch (cull_face_state->front_winding) { case COGL_WINDING_CLOCKWISE: GE( ctx, glFrontFace (invert_winding ? GL_CCW : GL_CW) ); break; case COGL_WINDING_COUNTER_CLOCKWISE: GE( ctx, glFrontFace (invert_winding ? GL_CW : GL_CCW) ); break; } } } #ifdef HAVE_COGL_GL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE) && (pipelines_difference & COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE)) { unsigned long state = COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE; CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, state); if (authority->big_state->per_vertex_point_size) GE( ctx, glEnable (GL_PROGRAM_POINT_SIZE) ); else GE( ctx, glDisable (GL_PROGRAM_POINT_SIZE) ); } #endif if (pipeline->real_blend_enable != ctx->gl_blend_enable_cache) { if (pipeline->real_blend_enable) GE (ctx, glEnable (GL_BLEND)); else GE (ctx, glDisable (GL_BLEND)); /* XXX: we shouldn't update any other blend state if blending * is disabled! */ ctx->gl_blend_enable_cache = pipeline->real_blend_enable; } } static int get_max_activateable_texture_units (void) { _COGL_GET_CONTEXT (ctx, 0); if (G_UNLIKELY (ctx->max_activateable_texture_units == -1)) { GLint values[3]; int n_values = 0; int i; #ifdef HAVE_COGL_GL if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED)) { /* GL_MAX_TEXTURE_COORDS is provided for both GLSL and ARBfp. It defines the number of texture coordinates that can be uploaded (but doesn't necessarily relate to how many texture images can be sampled) */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL) || cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP)) /* Previously this code subtracted the value by one but there was no explanation for why it did this and it doesn't seem to make sense so it has been removed */ GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_COORDS, values + n_values++)); /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is defined for GLSL but not ARBfp */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL)) GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, values + n_values++)); } #endif /* HAVE_COGL_GL */ #ifdef HAVE_COGL_GLES2 if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED) && _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE)) { GE (ctx, glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, values + n_values)); /* Two of the vertex attribs need to be used for the position and color */ values[n_values++] -= 2; GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, values + n_values++)); } #endif #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED)) { /* GL_MAX_TEXTURE_UNITS defines the number of units that are usable from the fixed function pipeline, therefore it isn't available in GLES2. These are also tied to the number of texture coordinates that can be uploaded so it should be less than that available from the shader extensions */ GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_UNITS, values + n_values++)); } #endif g_assert (n_values <= G_N_ELEMENTS (values) && n_values > 0); /* Use the maximum value */ ctx->max_activateable_texture_units = values[0]; for (i = 1; i < n_values; i++) ctx->max_activateable_texture_units = MAX (values[i], ctx->max_activateable_texture_units); } return ctx->max_activateable_texture_units; } typedef struct { int i; unsigned long *layer_differences; } CoglPipelineFlushLayerState; static CoglBool flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineFlushLayerState *flush_state = user_data; int unit_index = flush_state->i; CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index); unsigned long layers_difference = flush_state->layer_differences[unit_index]; _COGL_GET_CONTEXT (ctx, FALSE); /* There may not be enough texture units so we can bail out if * that's the case... */ if (G_UNLIKELY (unit_index >= get_max_activateable_texture_units ())) { static CoglBool shown_warning = FALSE; if (!shown_warning) { g_warning ("Your hardware does not have enough texture units" "to handle this many texture layers"); shown_warning = TRUE; } return FALSE; } if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA) { CoglTexture *texture = _cogl_pipeline_layer_get_texture_real (layer); GLuint gl_texture; GLenum gl_target; if (texture == NULL) switch (_cogl_pipeline_layer_get_texture_type (layer)) { case COGL_TEXTURE_TYPE_2D: texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex); break; case COGL_TEXTURE_TYPE_3D: texture = COGL_TEXTURE (ctx->default_gl_texture_3d_tex); break; case COGL_TEXTURE_TYPE_RECTANGLE: texture = COGL_TEXTURE (ctx->default_gl_texture_rect_tex); break; } cogl_texture_get_gl_texture (texture, &gl_texture, &gl_target); _cogl_set_active_texture_unit (unit_index); /* NB: There are several Cogl components and some code in * Clutter that will temporarily bind arbitrary GL textures to * query and modify texture object parameters. If you look at * _cogl_bind_gl_texture_transient() you can see we make sure * that such code always binds to texture unit 1 which means we * can't rely on the unit->gl_texture state if unit->index == 1. * * Because texture unit 1 is a bit special we actually defer any * necessary glBindTexture for it until the end of * _cogl_pipeline_flush_gl_state(). * * NB: we get notified whenever glDeleteTextures is used (see * _cogl_delete_gl_texture()) where we invalidate * unit->gl_texture references to deleted textures so it's safe * to compare unit->gl_texture with gl_texture. (Without the * hook it would be possible to delete a GL texture and create a * new one with the same name and comparing unit->gl_texture and * gl_texture wouldn't detect that.) * * NB: for foreign textures we don't know how the deletion of * the GL texture objects correspond to the deletion of the * CoglTextures so if there was previously a foreign texture * associated with the texture unit then we can't assume that we * aren't seeing a recycled texture name so we have to bind. */ if (unit->gl_texture != gl_texture || unit->is_foreign) { if (unit_index == 1) unit->dirty_gl_texture = TRUE; else GE (ctx, glBindTexture (gl_target, gl_texture)); unit->gl_texture = gl_texture; unit->gl_target = gl_target; } unit->is_foreign = _cogl_texture_is_foreign (texture); /* The texture_storage_changed boolean indicates if the * CoglTexture's underlying GL texture storage has changed since * it was flushed to the texture unit. We've just flushed the * latest state so we can reset this. */ unit->texture_storage_changed = FALSE; } if ((layers_difference & COGL_PIPELINE_LAYER_STATE_SAMPLER) && _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) { const CoglSamplerCacheEntry *sampler_state; sampler_state = _cogl_pipeline_layer_get_sampler_state (layer); GE( ctx, glBindSampler (unit_index, sampler_state->sampler_object) ); } /* FIXME: If using GLSL the progend we will use gl_PointCoord * instead of us needing to replace the texture coordinates but at * this point we can't currently tell if we are using the fixed or * glsl progend. */ #if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GL) if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED) && (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS)) { CoglPipelineState change = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, change); CoglPipelineLayerBigState *big_state = authority->big_state; _cogl_set_active_texture_unit (unit_index); GE (ctx, glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE, big_state->point_sprite_coords)); } #endif cogl_object_ref (layer); if (unit->layer != NULL) cogl_object_unref (unit->layer); unit->layer = layer; unit->layer_changes_since_flush = 0; flush_state->i++; return TRUE; } static void _cogl_pipeline_flush_common_gl_state (CoglPipeline *pipeline, unsigned long pipelines_difference, unsigned long *layer_differences, CoglBool with_color_attrib) { CoglPipelineFlushLayerState state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_pipeline_flush_color_blend_alpha_depth_state (pipeline, pipelines_difference, with_color_attrib); state.i = 0; state.layer_differences = layer_differences; _cogl_pipeline_foreach_layer_internal (pipeline, flush_layers_common_gl_state_cb, &state); } /* Re-assert the layer's wrap modes on the given CoglTexture. * * Note: we don't simply forward the wrap modes to layer->texture * since the actual texture being used may have been overridden. */ static void _cogl_pipeline_layer_forward_wrap_modes (CoglPipelineLayer *layer, CoglTexture *texture) { CoglSamplerCacheWrapMode wrap_mode_s, wrap_mode_t, wrap_mode_p; GLenum gl_wrap_mode_s, gl_wrap_mode_t, gl_wrap_mode_p; if (texture == NULL) return; _cogl_pipeline_layer_get_wrap_modes (layer, &wrap_mode_s, &wrap_mode_t, &wrap_mode_p); /* Update the wrap mode on the texture object. The texture backend should cache the value so that it will be a no-op if the object already has the same wrap mode set. The backend is best placed to do this because it knows how many of the coordinates will actually be used (ie, a 1D texture only cares about the 's' coordinate but a 3D texture would use all three). GL uses the wrap mode as part of the texture object state but we are pretending it's part of the per-layer environment state. This will break if the application tries to use different modes in different layers using the same texture. */ if (wrap_mode_s == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC) gl_wrap_mode_s = GL_CLAMP_TO_EDGE; else gl_wrap_mode_s = wrap_mode_s; if (wrap_mode_t == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC) gl_wrap_mode_t = GL_CLAMP_TO_EDGE; else gl_wrap_mode_t = wrap_mode_t; if (wrap_mode_p == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC) gl_wrap_mode_p = GL_CLAMP_TO_EDGE; else gl_wrap_mode_p = wrap_mode_p; _cogl_texture_gl_flush_legacy_texobj_wrap_modes (texture, gl_wrap_mode_s, gl_wrap_mode_t, gl_wrap_mode_p); } /* OpenGL associates the min/mag filters and repeat modes with the * texture object not the texture unit so we always have to re-assert * the filter and repeat modes whenever we use a texture since it may * be referenced by multiple pipelines with different modes. * * This function is bypassed in favour of sampler objects if * GL_ARB_sampler_objects is advertised. This fallback won't work if * the same texture is bound to multiple layers with different sampler * state. */ static void foreach_texture_unit_update_filter_and_wrap_modes (void) { int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); for (i = 0; i < ctx->texture_units->len; i++) { CoglTextureUnit *unit = &g_array_index (ctx->texture_units, CoglTextureUnit, i); if (unit->layer) { CoglTexture *texture = _cogl_pipeline_layer_get_texture (unit->layer); if (texture != NULL) { CoglPipelineFilter min; CoglPipelineFilter mag; _cogl_pipeline_layer_get_filters (unit->layer, &min, &mag); _cogl_texture_gl_flush_legacy_texobj_filters (texture, min, mag); _cogl_pipeline_layer_forward_wrap_modes (unit->layer, texture); } } } } typedef struct { int i; unsigned long *layer_differences; } CoglPipelineCompareLayersState; static CoglBool compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineCompareLayersState *state = user_data; CoglTextureUnit *unit = _cogl_get_texture_unit (state->i); if (unit->layer == layer) state->layer_differences[state->i] = unit->layer_changes_since_flush; else if (unit->layer) { state->layer_differences[state->i] = unit->layer_changes_since_flush; state->layer_differences[state->i] |= _cogl_pipeline_layer_compare_differences (layer, unit->layer); } else state->layer_differences[state->i] = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE; /* XXX: There is always a possibility that a CoglTexture's * underlying GL texture storage has been changed since it was last * bound to a texture unit which is why we have a callback into * _cogl_pipeline_texture_storage_change_notify whenever a textures * underlying GL texture storage changes which will set the * unit->texture_intern_changed flag. If we see that's been set here * then we force an update of the texture state... */ if (unit->texture_storage_changed) state->layer_differences[state->i] |= COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA; state->i++; return TRUE; } typedef struct { CoglFramebuffer *framebuffer; const CoglPipelineVertend *vertend; const CoglPipelineFragend *fragend; CoglPipeline *pipeline; unsigned long *layer_differences; CoglBool error_adding_layer; CoglBool added_layer; } CoglPipelineAddLayerState; static CoglBool vertend_add_layer_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineAddLayerState *state = user_data; const CoglPipelineVertend *vertend = state->vertend; CoglPipeline *pipeline = state->pipeline; int unit_index = _cogl_pipeline_layer_get_unit_index (layer); /* Either generate per layer code snippets or setup the * fixed function glTexEnv for each layer... */ if (G_LIKELY (vertend->add_layer (pipeline, layer, state->layer_differences[unit_index], state->framebuffer))) state->added_layer = TRUE; else { state->error_adding_layer = TRUE; return FALSE; } return TRUE; } static CoglBool fragend_add_layer_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineAddLayerState *state = user_data; const CoglPipelineFragend *fragend = state->fragend; CoglPipeline *pipeline = state->pipeline; int unit_index = _cogl_pipeline_layer_get_unit_index (layer); /* Either generate per layer code snippets or setup the * fixed function glTexEnv for each layer... */ if (G_LIKELY (fragend->add_layer (pipeline, layer, state->layer_differences[unit_index]))) state->added_layer = TRUE; else { state->error_adding_layer = TRUE; return FALSE; } return TRUE; } /* * _cogl_pipeline_flush_gl_state: * * Details of override options: * ->fallback_mask: is a bitmask of the pipeline layers that need to be * replaced with the default, fallback textures. The fallback textures are * fully transparent textures so they hopefully wont contribute to the * texture combining. * * The intention of fallbacks is to try and preserve * the number of layers the user is expecting so that texture coordinates * they gave will mostly still correspond to the textures they intended, and * have a fighting chance of looking close to their originally intended * result. * * ->disable_mask: is a bitmask of the pipeline layers that will simply have * texturing disabled. It's only really intended for disabling all layers * > X; i.e. we'd expect to see a contiguous run of 0 starting from the LSB * and at some point the remaining bits flip to 1. It might work to disable * arbitrary layers; though I'm not sure a.t.m how OpenGL would take to * that. * * The intention of the disable_mask is for emitting geometry when the user * hasn't supplied enough texture coordinates for all the layers and it's * not possible to auto generate default texture coordinates for those * layers. * * ->layer0_override_texture: forcibly tells us to bind this GL texture name for * layer 0 instead of plucking the gl_texture from the CoglTexture of layer * 0. * * The intention of this is for any primitives that supports sliced textures. * The code will can iterate each of the slices and re-flush the pipeline * forcing the GL texture of each slice in turn. * * ->wrap_mode_overrides: overrides the wrap modes set on each * layer. This is used to implement the automatic wrap mode. * * XXX: It might also help if we could specify a texture matrix for code * dealing with slicing that would be multiplied with the users own matrix. * * Normaly texture coords in the range [0, 1] refer to the extents of the * texture, but when your GL texture represents a slice of the real texture * (from the users POV) then a texture matrix would be a neat way of * transforming the mapping for each slice. * * Currently for textured rectangles we manually calculate the texture * coords for each slice based on the users given coords, but this solution * isn't ideal, and can't be used with CoglVertexBuffers. */ void _cogl_pipeline_flush_gl_state (CoglContext *ctx, CoglPipeline *pipeline, CoglFramebuffer *framebuffer, CoglBool with_color_attrib, CoglBool unknown_color_alpha) { CoglPipeline *current_pipeline = ctx->current_pipeline; unsigned long pipelines_difference; int n_layers; unsigned long *layer_differences; int i; CoglTextureUnit *unit1; const CoglPipelineProgend *progend; COGL_STATIC_TIMER (pipeline_flush_timer, "Mainloop", /* parent */ "Material Flush", "The time spent flushing material state", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, pipeline_flush_timer); /* Bail out asap if we've been asked to re-flush the already current * pipeline and we can see the pipeline hasn't changed */ if (current_pipeline == pipeline && ctx->current_pipeline_age == pipeline->age && ctx->current_pipeline_with_color_attrib == with_color_attrib && ctx->current_pipeline_unknown_color_alpha == unknown_color_alpha) goto done; else { /* Update derived state (currently just the 'real_blend_enable' * state) and determine a mask of state that differs between the * current pipeline and the one we are flushing. * * Note updating the derived state is done before doing any * pipeline comparisons so that we can correctly compare the * 'real_blend_enable' state itself. */ if (current_pipeline == pipeline) { pipelines_difference = ctx->current_pipeline_changes_since_flush; if (pipelines_difference & COGL_PIPELINE_STATE_AFFECTS_BLENDING || pipeline->unknown_color_alpha != unknown_color_alpha) { CoglBool save_real_blend_enable = pipeline->real_blend_enable; _cogl_pipeline_update_real_blend_enable (pipeline, unknown_color_alpha); if (save_real_blend_enable != pipeline->real_blend_enable) pipelines_difference |= COGL_PIPELINE_STATE_REAL_BLEND_ENABLE; } } else if (current_pipeline) { pipelines_difference = ctx->current_pipeline_changes_since_flush; _cogl_pipeline_update_real_blend_enable (pipeline, unknown_color_alpha); pipelines_difference |= _cogl_pipeline_compare_differences (ctx->current_pipeline, pipeline); } else { _cogl_pipeline_update_real_blend_enable (pipeline, unknown_color_alpha); pipelines_difference = COGL_PIPELINE_STATE_ALL; } } /* Get a layer_differences mask for each layer to be flushed */ n_layers = cogl_pipeline_get_n_layers (pipeline); if (n_layers) { CoglPipelineCompareLayersState state; layer_differences = g_alloca (sizeof (unsigned long) * n_layers); memset (layer_differences, 0, sizeof (unsigned long) * n_layers); state.i = 0; state.layer_differences = layer_differences; _cogl_pipeline_foreach_layer_internal (pipeline, compare_layer_differences_cb, &state); } else layer_differences = NULL; /* First flush everything that's the same regardless of which * pipeline backend is being used... * * 1) top level state: * glColor (or skip if a vertex attribute is being used for color) * blend state * alpha test state (except for GLES 2.0) * * 2) then foreach layer: * determine gl_target/gl_texture * bind texture * * Note: After _cogl_pipeline_flush_common_gl_state you can expect * all state of the layers corresponding texture unit to be * updated. */ _cogl_pipeline_flush_common_gl_state (pipeline, pipelines_difference, layer_differences, with_color_attrib); /* Now flush the fragment, vertex and program state according to the * current progend backend. * * Note: Some backends may not support the current pipeline * configuration and in that case it will report and error and we * will look for a different backend. * * NB: if pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED then * we have previously managed to successfully flush this pipeline * with the given progend so we will simply use that to avoid * fallback code paths. */ if (pipeline->progend == COGL_PIPELINE_PROGEND_UNDEFINED) _cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_DEFAULT); for (i = pipeline->progend; i < COGL_PIPELINE_N_PROGENDS; i++, _cogl_pipeline_set_progend (pipeline, i)) { const CoglPipelineVertend *vertend; const CoglPipelineFragend *fragend; CoglPipelineAddLayerState state; progend = _cogl_pipeline_progends[i]; if (G_UNLIKELY (!progend->start (pipeline))) continue; vertend = _cogl_pipeline_vertends[progend->vertend]; vertend->start (pipeline, n_layers, pipelines_difference); state.framebuffer = framebuffer; state.vertend = vertend; state.pipeline = pipeline; state.layer_differences = layer_differences; state.error_adding_layer = FALSE; state.added_layer = FALSE; _cogl_pipeline_foreach_layer_internal (pipeline, vertend_add_layer_cb, &state); if (G_UNLIKELY (state.error_adding_layer)) continue; if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference))) continue; /* Now prepare the fragment processing state (fragend) * * NB: We can't combine the setup of the vertend and fragend * since the backends that do code generation share * ctx->codegen_source_buffer as a scratch buffer. */ fragend = _cogl_pipeline_fragends[progend->fragend]; state.fragend = fragend; fragend->start (pipeline, n_layers, pipelines_difference); _cogl_pipeline_foreach_layer_internal (pipeline, fragend_add_layer_cb, &state); if (G_UNLIKELY (state.error_adding_layer)) continue; if (!state.added_layer) { if (fragend->passthrough && G_UNLIKELY (!fragend->passthrough (pipeline))) continue; } if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference))) continue; if (progend->end) progend->end (pipeline, pipelines_difference); break; } /* FIXME: This reference is actually resulting in lots of * copy-on-write reparenting because one-shot pipelines end up * living for longer than necessary and so any later modification of * the parent will cause a copy-on-write. * * XXX: The issue should largely go away when we switch to using * weak pipelines for overrides. */ cogl_object_ref (pipeline); if (ctx->current_pipeline != NULL) cogl_object_unref (ctx->current_pipeline); ctx->current_pipeline = pipeline; ctx->current_pipeline_changes_since_flush = 0; ctx->current_pipeline_with_color_attrib = with_color_attrib; ctx->current_pipeline_unknown_color_alpha = unknown_color_alpha; ctx->current_pipeline_age = pipeline->age; done: progend = _cogl_pipeline_progends[pipeline->progend]; /* We can't assume the color will be retained between flushes when * using the glsl progend because the generic attribute values are * not stored as part of the program object so they could be * overridden by any attribute changes in another program */ if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL && !with_color_attrib) { int attribute; CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); int name_index = COGL_ATTRIBUTE_COLOR_NAME_INDEX; attribute = _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index); if (attribute != -1) GE (ctx, glVertexAttrib4f (attribute, cogl_color_get_red_float (&authority->color), cogl_color_get_green_float (&authority->color), cogl_color_get_blue_float (&authority->color), cogl_color_get_alpha_float (&authority->color))); } /* Give the progend a chance to update any uniforms that might not * depend on the material state. This is used on GLES2 to update the * matrices */ if (progend->pre_paint) progend->pre_paint (pipeline, framebuffer); /* Handle the fact that OpenGL associates texture filter and wrap * modes with the texture objects not the texture units... */ if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) foreach_texture_unit_update_filter_and_wrap_modes (); /* If this pipeline has more than one layer then we always need * to make sure we rebind the texture for unit 1. * * NB: various components of Cogl may temporarily bind arbitrary * textures to texture unit 1 so they can query and modify texture * object parameters. cogl-pipeline.c (See * _cogl_bind_gl_texture_transient) */ unit1 = _cogl_get_texture_unit (1); if (cogl_pipeline_get_n_layers (pipeline) > 1 && unit1->dirty_gl_texture) { _cogl_set_active_texture_unit (1); GE (ctx, glBindTexture (unit1->gl_target, unit1->gl_texture)); unit1->dirty_gl_texture = FALSE; } COGL_TIMER_STOP (_cogl_uprof_context, pipeline_flush_timer); } muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h0000664000175000017500000000304614211404421025660 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_VERTEND_GLSL_PRIVATE_H #define __COGL_PIPELINE_VERTEND_GLSL_PRIVATE_H #include "cogl-pipeline-private.h" extern const CoglPipelineVertend _cogl_pipeline_glsl_vertend; GLuint _cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline); #endif /* __COGL_PIPELINE_VERTEND_GLSL_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-opengl-private.h0000664000175000017500000001405214211404421024535 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_OPENGL_PRIVATE_H #define __COGL_PIPELINE_OPENGL_PRIVATE_H #include "cogl-pipeline-private.h" #include "cogl-matrix-stack.h" /* * cogl-pipeline.c owns the GPU's texture unit state so we have some * private structures for describing the current state of a texture * unit that we track in a per context array (ctx->texture_units) that * grows according to the largest texture unit used so far... * * Roughly speaking the members in this structure are of two kinds: * either they are a low level reflection of the state we send to * OpenGL or they are for high level meta data assoicated with the * texture unit when flushing CoglPipelineLayers that is typically * used to optimize subsequent re-flushing of the same layer. * * The low level members are at the top, and the high level members * start with the .layer member. */ typedef struct _CoglTextureUnit { /* The base 0 texture unit index which can be used with * glActiveTexture () */ int index; /* The GL target currently glEnabled or 0 if nothing is * enabled. This is only used by the fixed pipeline fragend */ GLenum enabled_gl_target; /* The raw GL texture object name for which we called glBindTexture when * we flushed the last layer. (NB: The CoglTexture associated * with a layer may represent more than one GL texture) */ GLuint gl_texture; /* The target of the GL texture object. This is just used so that we * can quickly determine the intended target to flush when * dirty_gl_texture == TRUE */ GLenum gl_target; /* Foreign textures are those not created or deleted by Cogl. If we ever * call glBindTexture for a foreign texture then the next time we are * asked to glBindTexture we can't try and optimize a redundant state * change because we don't know if the original texture name was deleted * and now we are being asked to bind a recycled name. */ CoglBool is_foreign; /* We have many components in Cogl that need to temporarily bind arbitrary * textures e.g. to query texture object parameters and since we don't * want that to result in too much redundant reflushing of layer state * when all that's needed is to re-bind the layer's gl_texture we use this * to track when the unit->gl_texture state is out of sync with the GL * texture object really bound too (GL_TEXTURE0+unit->index). * * XXX: as a further optimization cogl-pipeline.c uses a convention * of always using texture unit 1 for these transient bindings so we * can assume this is only ever TRUE for unit 1. */ CoglBool dirty_gl_texture; /* A matrix stack giving us the means to associate a texture * transform matrix with the texture unit. */ CoglMatrixStack *matrix_stack; /* * Higher level layer state associated with the unit... */ /* The CoglPipelineLayer whos state was flushed to update this * texture unit last. * * This will be set to NULL if the layer is modified or freed which * means when we come to flush a layer; if this pointer is still * valid and == to the layer being flushed we don't need to update * any texture unit state. */ CoglPipelineLayer *layer; /* To help minimize the state changes required we track the * difference flags associated with the layer whos state was last * flushed to update this texture unit. * * Note: we track this explicitly because .layer may get invalidated * if that layer is modified or deleted. Even if the layer is * invalidated though these flags can be used to optimize the state * flush of the next layer */ unsigned long layer_changes_since_flush; /* Whenever a CoglTexture's internal GL texture storage changes * cogl-pipeline.c is notified with a call to * _cogl_pipeline_texture_storage_change_notify which inturn sets * this to TRUE for each texture unit that it is currently bound * too. When we later come to flush some pipeline state then we will * always check this to potentially force an update of the texture * state even if the pipeline hasn't changed. */ CoglBool texture_storage_changed; } CoglTextureUnit; CoglTextureUnit * _cogl_get_texture_unit (int index_); void _cogl_destroy_texture_units (void); void _cogl_set_active_texture_unit (int unit_index); void _cogl_bind_gl_texture_transient (GLenum gl_target, GLuint gl_texture, CoglBool is_foreign); void _cogl_delete_gl_texture (GLuint gl_texture); void _cogl_pipeline_flush_gl_state (CoglContext *context, CoglPipeline *pipeline, CoglFramebuffer *framebuffer, CoglBool skip_gl_state, CoglBool unknown_color_alpha); #endif /* __COGL_PIPELINE_OPENGL_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed-private.h0000664000175000017500000000273714211404421026024 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifndef __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H #define __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H #include "cogl-pipeline-private.h" extern const CoglPipelineVertend _cogl_pipeline_fixed_vertend; #endif /* __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl.c0000664000175000017500000005605014211404421024206 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #ifdef COGL_PIPELINE_VERTEND_GLSL #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-program-private.h" #include "cogl-pipeline-vertend-glsl-private.h" #include "cogl-pipeline-state-private.h" #include "cogl-glsl-shader-private.h" const CoglPipelineVertend _cogl_pipeline_glsl_vertend; typedef struct { unsigned int ref_count; GLuint gl_shader; GString *header, *source; CoglPipelineCacheEntry *cache_entry; } CoglPipelineShaderState; static CoglUserDataKey shader_state_key; static CoglPipelineShaderState * shader_state_new (CoglPipelineCacheEntry *cache_entry) { CoglPipelineShaderState *shader_state; shader_state = g_slice_new0 (CoglPipelineShaderState); shader_state->ref_count = 1; shader_state->cache_entry = cache_entry; return shader_state; } static CoglPipelineShaderState * get_shader_state (CoglPipeline *pipeline) { return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key); } static void destroy_shader_state (void *user_data, void *instance) { CoglPipelineShaderState *shader_state = user_data; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (shader_state->cache_entry && shader_state->cache_entry->pipeline != instance) shader_state->cache_entry->usage_count--; if (--shader_state->ref_count == 0) { if (shader_state->gl_shader) GE( ctx, glDeleteShader (shader_state->gl_shader) ); g_slice_free (CoglPipelineShaderState, shader_state); } } static void set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { if (shader_state) { shader_state->ref_count++; /* If we're not setting the state on the template pipeline then * mark it as a usage of the pipeline cache entry */ if (shader_state->cache_entry && shader_state->cache_entry->pipeline != pipeline) shader_state->cache_entry->usage_count++; } _cogl_object_set_user_data (COGL_OBJECT (pipeline), &shader_state_key, shader_state, destroy_shader_state); } static void dirty_shader_state (CoglPipeline *pipeline) { cogl_object_set_user_data (COGL_OBJECT (pipeline), &shader_state_key, NULL, NULL); } GLuint _cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); if (shader_state) return shader_state->gl_shader; else return 0; } static CoglPipelineSnippetList * get_vertex_snippets (CoglPipeline *pipeline) { pipeline = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_VERTEX_SNIPPETS); return &pipeline->big_state->vertex_snippets; } static CoglPipelineSnippetList * get_layer_vertex_snippets (CoglPipelineLayer *layer) { unsigned long state = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS; layer = _cogl_pipeline_layer_get_authority (layer, state); return &layer->big_state->vertex_snippets; } static CoglBool add_layer_declaration_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineShaderState *shader_state = user_data; CoglTextureType texture_type = _cogl_pipeline_layer_get_texture_type (layer); const char *target_string; _cogl_gl_util_get_texture_target_string (texture_type, &target_string, NULL); g_string_append_printf (shader_state->header, "uniform sampler%s cogl_sampler%i;\n", target_string, layer->index); return TRUE; } static void add_layer_declarations (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { /* We always emit sampler uniforms in case there will be custom * layer snippets that want to sample arbitrary layers. */ _cogl_pipeline_foreach_layer_internal (pipeline, add_layer_declaration_cb, shader_state); } static void add_global_declarations (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { CoglSnippetHook hook = COGL_SNIPPET_HOOK_VERTEX_GLOBALS; CoglPipelineSnippetList *snippets = get_vertex_snippets (pipeline); /* Add the global data hooks. All of the code in these snippets is * always added and only the declarations data is used */ _cogl_pipeline_snippet_generate_declarations (shader_state->header, hook, snippets); } static void _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; CoglPipelineCacheEntry *cache_entry = NULL; CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline); _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Now lookup our glsl backend private state (allocating if * necessary) */ shader_state = get_shader_state (pipeline); if (shader_state == NULL) { CoglPipeline *authority; /* Get the authority for anything affecting vertex shader state */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, _cogl_pipeline_get_state_for_vertex_codegen (ctx) & ~COGL_PIPELINE_STATE_LAYERS, COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN); shader_state = get_shader_state (authority); if (shader_state == NULL) { /* Check if there is already a similar cached pipeline whose shader state we can share */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { cache_entry = _cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (cache_entry->pipeline); } if (shader_state) shader_state->ref_count++; else shader_state = shader_state_new (cache_entry); set_shader_state (authority, shader_state); shader_state->ref_count--; if (cache_entry) set_shader_state (cache_entry->pipeline, shader_state); } if (authority != pipeline) set_shader_state (pipeline, shader_state); } if (user_program) { /* If the user program contains a vertex shader then we don't need to generate one */ if (_cogl_program_has_vertex_shader (user_program)) { if (shader_state->gl_shader) { GE( ctx, glDeleteShader (shader_state->gl_shader) ); shader_state->gl_shader = 0; } return; } } if (shader_state->gl_shader) return; /* If we make it here then we have a shader_state struct without a gl_shader either because this is the first time we've encountered it or because the user program has changed */ /* We reuse two grow-only GStrings for code-gen. One string contains the uniform and attribute declarations while the other contains the main function. We need two strings because we need to dynamically declare attributes as the add_layer callback is invoked */ g_string_set_size (ctx->codegen_header_buffer, 0); g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->header = ctx->codegen_header_buffer; shader_state->source = ctx->codegen_source_buffer; add_layer_declarations (pipeline, shader_state); add_global_declarations (pipeline, shader_state); g_string_append (shader_state->source, "void\n" "cogl_generated_source ()\n" "{\n"); if (cogl_pipeline_get_per_vertex_point_size (pipeline)) g_string_append (shader_state->header, "attribute float cogl_point_size_in;\n"); else if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM)) { /* There is no builtin uniform for the point size on GLES2 so we need to copy it from the custom uniform in the vertex shader if we're not using per-vertex point sizes, however we'll only do this if the point-size is non-zero. Toggle the point size between zero and non-zero causes a state change which generates a new program */ if (cogl_pipeline_get_point_size (pipeline) > 0.0f) { g_string_append (shader_state->header, "uniform float cogl_point_size_in;\n"); g_string_append (shader_state->source, " cogl_point_size_out = cogl_point_size_in;\n"); } } } static CoglBool _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference, CoglFramebuffer *framebuffer) { CoglPipelineShaderState *shader_state; CoglPipelineSnippetData snippet_data; int layer_index = layer->index; _COGL_GET_CONTEXT (ctx, FALSE); shader_state = get_shader_state (pipeline); if (shader_state->source == NULL) return TRUE; /* Transform the texture coordinates by the layer's user matrix. * * FIXME: this should avoid doing the transform if there is no user * matrix set. This might need a separate layer state flag for * whether there is a user matrix * * FIXME: we could be more clever here and try to detect if the * fragment program is going to use the texture coordinates and * avoid setting them if not */ g_string_append_printf (shader_state->header, "vec4\n" "cogl_real_transform_layer%i (mat4 matrix, " "vec4 tex_coord)\n" "{\n" " return matrix * tex_coord;\n" "}\n", layer_index); /* Wrap the layer code in any snippets that have been hooked */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = get_layer_vertex_snippets (layer); snippet_data.hook = COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM; snippet_data.chain_function = g_strdup_printf ("cogl_real_transform_layer%i", layer_index); snippet_data.final_name = g_strdup_printf ("cogl_transform_layer%i", layer_index); snippet_data.function_prefix = g_strdup_printf ("cogl_transform_layer%i", layer_index); snippet_data.return_type = "vec4"; snippet_data.return_variable = "cogl_tex_coord"; snippet_data.return_variable_is_argument = TRUE; snippet_data.arguments = "cogl_matrix, cogl_tex_coord"; snippet_data.argument_declarations = "mat4 cogl_matrix, vec4 cogl_tex_coord"; snippet_data.source_buf = shader_state->header; _cogl_pipeline_snippet_generate_code (&snippet_data); free ((char *) snippet_data.chain_function); free ((char *) snippet_data.final_name); free ((char *) snippet_data.function_prefix); g_string_append_printf (shader_state->source, " cogl_tex_coord%i_out = " "cogl_transform_layer%i (cogl_texture_matrix%i,\n" " " " cogl_tex_coord%i_in);\n", layer_index, layer_index, layer_index, layer_index); return TRUE; } static CoglBool _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; _COGL_GET_CONTEXT (ctx, FALSE); shader_state = get_shader_state (pipeline); if (shader_state->source) { const char *source_strings[2]; GLint lengths[2]; GLint compile_status; GLuint shader; CoglPipelineSnippetData snippet_data; CoglPipelineSnippetList *vertex_snippets; CoglBool has_per_vertex_point_size = cogl_pipeline_get_per_vertex_point_size (pipeline); COGL_STATIC_COUNTER (vertend_glsl_compile_counter, "glsl vertex compile counter", "Increments each time a new GLSL " "vertex shader is compiled", 0 /* no application private data */); COGL_COUNTER_INC (_cogl_uprof_context, vertend_glsl_compile_counter); g_string_append (shader_state->header, "void\n" "cogl_real_vertex_transform ()\n" "{\n" " cogl_position_out = " "cogl_modelview_projection_matrix * " "cogl_position_in;\n" "}\n"); g_string_append (shader_state->source, " cogl_vertex_transform ();\n"); if (has_per_vertex_point_size) { g_string_append (shader_state->header, "void\n" "cogl_real_point_size_calculation ()\n" "{\n" " cogl_point_size_out = cogl_point_size_in;\n" "}\n"); g_string_append (shader_state->source, " cogl_point_size_calculation ();\n"); } g_string_append (shader_state->source, " cogl_color_out = cogl_color_in;\n" "}\n"); vertex_snippets = get_vertex_snippets (pipeline); /* Add hooks for the vertex transform part */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = vertex_snippets; snippet_data.hook = COGL_SNIPPET_HOOK_VERTEX_TRANSFORM; snippet_data.chain_function = "cogl_real_vertex_transform"; snippet_data.final_name = "cogl_vertex_transform"; snippet_data.function_prefix = "cogl_vertex_transform"; snippet_data.source_buf = shader_state->header; _cogl_pipeline_snippet_generate_code (&snippet_data); /* Add hooks for the point size calculation part */ if (has_per_vertex_point_size) { memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = vertex_snippets; snippet_data.hook = COGL_SNIPPET_HOOK_POINT_SIZE; snippet_data.chain_function = "cogl_real_point_size_calculation"; snippet_data.final_name = "cogl_point_size_calculation"; snippet_data.function_prefix = "cogl_point_size_calculation"; snippet_data.source_buf = shader_state->header; _cogl_pipeline_snippet_generate_code (&snippet_data); } /* Add all of the hooks for vertex processing */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = vertex_snippets; snippet_data.hook = COGL_SNIPPET_HOOK_VERTEX; snippet_data.chain_function = "cogl_generated_source"; snippet_data.final_name = "cogl_vertex_hook"; snippet_data.function_prefix = "cogl_vertex_hook"; snippet_data.source_buf = shader_state->source; _cogl_pipeline_snippet_generate_code (&snippet_data); g_string_append (shader_state->source, "void\n" "main ()\n" "{\n" " cogl_vertex_hook ();\n"); /* If there are any snippets then we can't rely on the projection matrix to flip the rendering for offscreen buffers so we'll need to flip it using an extra statement and a uniform */ if (_cogl_pipeline_has_vertex_snippets (pipeline)) { g_string_append (shader_state->header, "uniform vec4 _cogl_flip_vector;\n"); g_string_append (shader_state->source, " cogl_position_out *= _cogl_flip_vector;\n"); } g_string_append (shader_state->source, "}\n"); GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) ); lengths[0] = shader_state->header->len; source_strings[0] = shader_state->header->str; lengths[1] = shader_state->source->len; source_strings[1] = shader_state->source->str; _cogl_glsl_shader_set_source_with_boilerplate (ctx, shader, GL_VERTEX_SHADER, pipeline, 2, /* count */ source_strings, lengths); GE( ctx, glCompileShader (shader) ); GE( ctx, glGetShaderiv (shader, GL_COMPILE_STATUS, &compile_status) ); if (!compile_status) { GLint len = 0; char *shader_log; GE( ctx, glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &len) ); shader_log = g_alloca (len); GE( ctx, glGetShaderInfoLog (shader, len, &len, shader_log) ); g_warning ("Shader compilation failed:\n%s", shader_log); } shader_state->header = NULL; shader_state->source = NULL; shader_state->gl_shader = shader; } #ifdef HAVE_COGL_GL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM) && (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE)) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE); if (authority->big_state->point_size > 0.0f) GE( ctx, glPointSize (authority->big_state->point_size) ); } #endif /* HAVE_COGL_GL */ return TRUE; } static void _cogl_pipeline_vertend_glsl_pre_change_notify (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if ((change & _cogl_pipeline_get_state_for_vertex_codegen (ctx))) dirty_shader_state (pipeline); } /* NB: layers are considered immutable once they have any dependants * so although multiple pipelines can end up depending on a single * static layer, we can guarantee that if a layer is being *changed* * then it can only have one pipeline depending on it. * * XXX: Don't forget this is *pre* change, we can't read the new value * yet! */ static void _cogl_pipeline_vertend_glsl_layer_pre_change_notify ( CoglPipeline *owner, CoglPipelineLayer *layer, CoglPipelineLayerState change) { CoglPipelineShaderState *shader_state; shader_state = get_shader_state (owner); if (!shader_state) return; if ((change & COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN)) { dirty_shader_state (owner); return; } /* TODO: we could be saving snippets of texture combine code along * with each layer and then when a layer changes we would just free * the snippet. */ } const CoglPipelineVertend _cogl_pipeline_glsl_vertend = { _cogl_pipeline_vertend_glsl_start, _cogl_pipeline_vertend_glsl_add_layer, _cogl_pipeline_vertend_glsl_end, _cogl_pipeline_vertend_glsl_pre_change_notify, _cogl_pipeline_vertend_glsl_layer_pre_change_notify }; UNIT_TEST (check_point_size_shader, 0 /* no requirements */, 0 /* no failure cases */) { CoglPipeline *pipelines[4]; CoglPipelineShaderState *shader_states[G_N_ELEMENTS (pipelines)]; int i; /* Default pipeline with zero point size */ pipelines[0] = cogl_pipeline_new (test_ctx); /* Point size 1 */ pipelines[1] = cogl_pipeline_new (test_ctx); cogl_pipeline_set_point_size (pipelines[1], 1.0f); /* Point size 2 */ pipelines[2] = cogl_pipeline_new (test_ctx); cogl_pipeline_set_point_size (pipelines[2], 2.0f); /* Same as the first pipeline, but reached by restoring the old * state from a copy */ pipelines[3] = cogl_pipeline_copy (pipelines[1]); cogl_pipeline_set_point_size (pipelines[3], 0.0f); /* Draw something with all of the pipelines to make sure their state * is flushed */ for (i = 0; i < G_N_ELEMENTS (pipelines); i++) cogl_framebuffer_draw_rectangle (test_fb, pipelines[i], 0.0f, 0.0f, 10.0f, 10.0f); cogl_framebuffer_finish (test_fb); /* Get all of the shader states. These might be NULL if the driver * is not using GLSL */ for (i = 0; i < G_N_ELEMENTS (pipelines); i++) shader_states[i] = get_shader_state (pipelines[i]); /* If the first two pipelines are using GLSL then they should have * the same shader unless there is no builtin uniform for the point * size */ if (shader_states[0]) { if (_cogl_has_private_feature (test_ctx, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM)) g_assert (shader_states[0] == shader_states[1]); else g_assert (shader_states[0] != shader_states[1]); } /* The second and third pipelines should always have the same shader * state because only toggling between zero and non-zero should * change the shader */ g_assert (shader_states[1] == shader_states[2]); /* The fourth pipeline should be exactly the same as the first */ g_assert (shader_states[0] == shader_states[3]); } #endif /* COGL_PIPELINE_VERTEND_GLSL */ muffin-5.2.1/cogl/cogl/driver/gl/gles/0000775000175000017500000000000014211404421017633 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/driver/gl/gles/cogl-driver-gles.c0000664000175000017500000004161614211404421023154 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-feature-private.h" #include "cogl-renderer-private.h" #include "cogl-private.h" #include "cogl-framebuffer-gl-private.h" #include "cogl-texture-2d-gl-private.h" #include "cogl-attribute-gl-private.h" #include "cogl-clip-stack-gl-private.h" #include "cogl-buffer-gl-private.h" #ifndef GL_UNSIGNED_INT_24_8 #define GL_UNSIGNED_INT_24_8 0x84FA #endif #ifndef GL_DEPTH_STENCIL #define GL_DEPTH_STENCIL 0x84F9 #endif #ifndef GL_RG #define GL_RG 0x8227 #endif #ifndef GL_RG8 #define GL_RG8 0x822B #endif static CoglBool _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, GLenum gl_int_format, CoglPixelFormat *out_format) { return TRUE; } static CoglPixelFormat _cogl_driver_pixel_format_to_gl_with_target (CoglContext *context, CoglPixelFormat format, CoglPixelFormat target_format, GLenum *out_glintformat, GLenum *out_glformat, GLenum *out_gltype) { CoglPixelFormat required_format; GLenum glintformat; GLenum glformat = 0; GLenum gltype; required_format = format; /* Find GL equivalents */ switch (format) { case COGL_PIXEL_FORMAT_A_8: glintformat = GL_ALPHA; glformat = GL_ALPHA; gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_G_8: glintformat = GL_LUMINANCE; glformat = GL_LUMINANCE; gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_RG_88: if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RG)) { glintformat = GL_RG8; glformat = GL_RG; } else { /* If red-green textures aren't supported then we'll use RGB * as an internal format. Note this should only end up * mattering for downloading the data because Cogl will * refuse to allocate a texture with RG components if RG * textures aren't supported */ glintformat = GL_RGB; glformat = GL_RGB; required_format = COGL_PIXEL_FORMAT_RGB_888; } gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_BGRA_8888: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: /* There is an extension to support this format */ if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888)) { /* For some reason the extension says you have to specify BGRA for the internal format too */ glintformat = GL_BGRA_EXT; glformat = GL_BGRA_EXT; gltype = GL_UNSIGNED_BYTE; required_format = format; break; } /* flow through */ /* Just one 24-bit ordering supported */ case COGL_PIXEL_FORMAT_RGB_888: case COGL_PIXEL_FORMAT_BGR_888: glintformat = GL_RGB; glformat = GL_RGB; gltype = GL_UNSIGNED_BYTE; required_format = COGL_PIXEL_FORMAT_RGB_888; break; /* Just one 32-bit ordering supported */ case COGL_PIXEL_FORMAT_RGBA_8888: case COGL_PIXEL_FORMAT_RGBA_8888_PRE: case COGL_PIXEL_FORMAT_ARGB_8888: case COGL_PIXEL_FORMAT_ARGB_8888_PRE: case COGL_PIXEL_FORMAT_ABGR_8888: case COGL_PIXEL_FORMAT_ABGR_8888_PRE: case COGL_PIXEL_FORMAT_RGBA_1010102: case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: case COGL_PIXEL_FORMAT_BGRA_1010102: case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: case COGL_PIXEL_FORMAT_ABGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: case COGL_PIXEL_FORMAT_ARGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_BYTE; required_format = COGL_PIXEL_FORMAT_RGBA_8888; required_format |= (format & COGL_PREMULT_BIT); break; /* The following three types of channel ordering * are always defined using system word byte * ordering (even according to GLES spec) */ case COGL_PIXEL_FORMAT_RGB_565: glintformat = GL_RGB; glformat = GL_RGB; gltype = GL_UNSIGNED_SHORT_5_6_5; break; case COGL_PIXEL_FORMAT_RGBA_4444: case COGL_PIXEL_FORMAT_RGBA_4444_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_SHORT_4_4_4_4; break; case COGL_PIXEL_FORMAT_RGBA_5551: case COGL_PIXEL_FORMAT_RGBA_5551_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_SHORT_5_5_5_1; break; case COGL_PIXEL_FORMAT_DEPTH_16: glintformat = GL_DEPTH_COMPONENT; glformat = GL_DEPTH_COMPONENT; gltype = GL_UNSIGNED_SHORT; break; case COGL_PIXEL_FORMAT_DEPTH_32: glintformat = GL_DEPTH_COMPONENT; glformat = GL_DEPTH_COMPONENT; gltype = GL_UNSIGNED_INT; break; case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: glintformat = GL_DEPTH_STENCIL; glformat = GL_DEPTH_STENCIL; gltype = GL_UNSIGNED_INT_24_8; break; case COGL_PIXEL_FORMAT_ANY: case COGL_PIXEL_FORMAT_YUV: g_assert_not_reached (); break; } /* All of the pixel formats are handled above so if this hits then we've been given an invalid pixel format */ g_assert (glformat != 0); if (out_glintformat != NULL) *out_glintformat = glintformat; if (out_glformat != NULL) *out_glformat = glformat; if (out_gltype != NULL) *out_gltype = gltype; return required_format; } static CoglPixelFormat _cogl_driver_pixel_format_to_gl (CoglContext *context, CoglPixelFormat format, GLenum *out_glintformat, GLenum *out_glformat, GLenum *out_gltype) { return _cogl_driver_pixel_format_to_gl_with_target (context, format, format, out_glintformat, out_glformat, out_gltype); } static CoglBool _cogl_get_gl_version (CoglContext *ctx, int *major_out, int *minor_out) { const char *version_string; /* Get the OpenGL version number */ if ((version_string = _cogl_context_get_gl_version (ctx)) == NULL) return FALSE; if (!g_str_has_prefix (version_string, "OpenGL ES ")) return FALSE; return _cogl_gl_util_parse_gl_version (version_string + 10, major_out, minor_out); } static CoglBool _cogl_driver_update_features (CoglContext *context, CoglError **error) { unsigned long private_features [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_N_PRIVATE_FEATURES)] = { 0 }; CoglFeatureFlags flags = 0; char **gl_extensions; int gl_major, gl_minor; int i; /* We have to special case getting the pointer to the glGetString function because we need to use it to determine what functions we can expect */ context->glGetString = (void *) _cogl_renderer_get_proc_address (context->display->renderer, "glGetString", TRUE); gl_extensions = _cogl_context_get_gl_extensions (context); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS))) { char *all_extensions = g_strjoinv (" ", gl_extensions); COGL_NOTE (WINSYS, "Checking features\n" " GL_VENDOR: %s\n" " GL_RENDERER: %s\n" " GL_VERSION: %s\n" " GL_EXTENSIONS: %s", context->glGetString (GL_VENDOR), context->glGetString (GL_RENDERER), _cogl_context_get_gl_version (context), all_extensions); free (all_extensions); } context->glsl_major = 1; context->glsl_minor = 0; context->glsl_version_to_use = 100; _cogl_gpu_info_init (context, &context->gpu); if (!_cogl_get_gl_version (context, &gl_major, &gl_minor)) { gl_major = 1; gl_minor = 1; } _cogl_feature_check_ext_functions (context, gl_major, gl_minor, gl_extensions); #ifdef HAVE_COGL_GLES if (context->driver == COGL_DRIVER_GLES1) { int max_clip_planes; GE( context, glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) ); if (max_clip_planes >= 4) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES, TRUE); } #endif if (context->driver == COGL_DRIVER_GLES2) { flags |= COGL_FEATURE_SHADERS_GLSL | COGL_FEATURE_OFFSCREEN; /* Note GLES 2 core doesn't support mipmaps for npot textures or * repeat modes other than CLAMP_TO_EDGE. */ flags |= COGL_FEATURE_TEXTURE_NPOT_BASIC; flags |= COGL_FEATURE_DEPTH_RANGE; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GLSL, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_BLEND_CONSTANT, TRUE); } else if (context->driver == COGL_DRIVER_GLES1) { COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_GL_FIXED, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ALPHA_TEST, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM, TRUE); } COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_VBOS, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ANY_GL, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES, TRUE); /* Both GLES 1.1 and GLES 2.0 support point sprites in core */ flags |= COGL_FEATURE_POINT_SPRITE; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE); if (context->glGenRenderbuffers) { flags |= COGL_FEATURE_OFFSCREEN; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE); } if (context->glBlitFramebuffer) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT, TRUE); if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions)) { flags |= COGL_FEATURE_UNSIGNED_INT_INDICES; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE); } if (_cogl_check_extension ("GL_OES_depth_texture", gl_extensions)) { flags |= COGL_FEATURE_DEPTH_TEXTURE; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_TEXTURE, TRUE); } if (_cogl_check_extension ("GL_OES_texture_npot", gl_extensions)) { flags |= (COGL_FEATURE_TEXTURE_NPOT | COGL_FEATURE_TEXTURE_NPOT_BASIC | COGL_FEATURE_TEXTURE_NPOT_MIPMAP | COGL_FEATURE_TEXTURE_NPOT_REPEAT); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_NPOT, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE); } else if (_cogl_check_extension ("GL_IMG_texture_npot", gl_extensions)) { flags |= (COGL_FEATURE_TEXTURE_NPOT_BASIC | COGL_FEATURE_TEXTURE_NPOT_MIPMAP); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE); } if (context->glTexImage3D) { flags |= COGL_FEATURE_TEXTURE_3D; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE); } if (context->glMapBuffer) { /* The GL_OES_mapbuffer extension doesn't support mapping for read */ flags |= COGL_FEATURE_MAP_BUFFER_FOR_WRITE; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); } if (context->glMapBufferRange) { /* MapBufferRange in ES3+ does support mapping for read */ flags |= (COGL_FEATURE_MAP_BUFFER_FOR_WRITE | COGL_FEATURE_MAP_BUFFER_FOR_READ); COGL_FLAGS_SET(context->features, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); COGL_FLAGS_SET(context->features, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, TRUE); } if (context->glEGLImageTargetTexture2D) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE, TRUE); if (_cogl_check_extension ("GL_OES_packed_depth_stencil", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL, TRUE); if (_cogl_check_extension ("GL_EXT_texture_format_BGRA8888", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888, TRUE); if (_cogl_check_extension ("GL_EXT_unpack_subimage", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE, TRUE); /* A nameless vendor implemented the extension, but got the case wrong * per the spec. */ if (_cogl_check_extension ("GL_OES_EGL_sync", gl_extensions) || _cogl_check_extension ("GL_OES_egl_sync", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_OES_EGL_SYNC, TRUE); if (_cogl_check_extension ("GL_EXT_texture_rg", gl_extensions)) COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_RG, TRUE); /* Cache features */ for (i = 0; i < G_N_ELEMENTS (private_features); i++) context->private_features[i] |= private_features[i]; context->feature_flags |= flags; g_strfreev (gl_extensions); return TRUE; } const CoglDriverVtable _cogl_driver_gles = { _cogl_driver_pixel_format_from_gl_internal, _cogl_driver_pixel_format_to_gl, _cogl_driver_pixel_format_to_gl_with_target, _cogl_driver_update_features, _cogl_offscreen_gl_allocate, _cogl_offscreen_gl_free, _cogl_framebuffer_gl_flush_state, _cogl_framebuffer_gl_clear, _cogl_framebuffer_gl_query_bits, _cogl_framebuffer_gl_finish, _cogl_framebuffer_gl_discard_buffers, _cogl_framebuffer_gl_draw_attributes, _cogl_framebuffer_gl_draw_indexed_attributes, _cogl_framebuffer_gl_read_pixels_into_bitmap, _cogl_texture_2d_gl_free, _cogl_texture_2d_gl_can_create, _cogl_texture_2d_gl_init, _cogl_texture_2d_gl_allocate, _cogl_texture_2d_gl_copy_from_framebuffer, _cogl_texture_2d_gl_get_gl_handle, _cogl_texture_2d_gl_generate_mipmap, _cogl_texture_2d_gl_copy_from_bitmap, NULL, /* texture_2d_get_data */ _cogl_gl_flush_attributes_state, _cogl_clip_stack_gl_flush, _cogl_buffer_gl_create, _cogl_buffer_gl_destroy, _cogl_buffer_gl_map_range, _cogl_buffer_gl_unmap, _cogl_buffer_gl_set_data, }; muffin-5.2.1/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c0000664000175000017500000005310114211404421024642 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Matthew Allum * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-private.h" #include "cogl-util.h" #include "cogl-bitmap.h" #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" #include "cogl-pipeline.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-primitives.h" #include "cogl-util-gl-private.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" #include #include #include #ifndef GL_TEXTURE_3D #define GL_TEXTURE_3D 0x806F #endif #ifndef GL_MAX_3D_TEXTURE_SIZE_OES #define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 #endif /* This extension isn't available for GLES 1.1 so these won't be defined */ #ifndef GL_UNPACK_ROW_LENGTH #define GL_UNPACK_ROW_LENGTH 0x0CF2 #endif #ifndef GL_UNPACK_SKIP_ROWS #define GL_UNPACK_SKIP_ROWS 0x0CF3 #endif #ifndef GL_UNPACK_SKIP_PIXELS #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #endif static GLuint _cogl_texture_driver_gen (CoglContext *ctx, GLenum gl_target, CoglPixelFormat internal_format) { GLuint tex; GE (ctx, glGenTextures (1, &tex)); _cogl_bind_gl_texture_transient (gl_target, tex, FALSE); switch (gl_target) { case GL_TEXTURE_2D: case GL_TEXTURE_3D: /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ); break; default: g_assert_not_reached(); } return tex; } static void prep_gl_for_pixels_upload_full (CoglContext *ctx, int pixels_rowstride, int pixels_src_x, int pixels_src_y, int pixels_bpp) { if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE)) { GE( ctx, glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); GE( ctx, glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); GE( ctx, glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); } else { g_assert (pixels_src_x == 0); g_assert (pixels_src_y == 0); } _cogl_texture_gl_prep_alignment_for_pixels_upload (ctx, pixels_rowstride); } static void _cogl_texture_driver_prep_gl_for_pixels_upload (CoglContext *ctx, int pixels_rowstride, int pixels_bpp) { prep_gl_for_pixels_upload_full (ctx, pixels_rowstride, 0, 0, /* src_x/y */ pixels_bpp); } static void _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx, int pixels_rowstride, int image_width, int pixels_bpp) { _cogl_texture_gl_prep_alignment_for_pixels_download (ctx, pixels_bpp, image_width, pixels_rowstride); } static CoglBitmap * prepare_bitmap_alignment_for_upload (CoglContext *ctx, CoglBitmap *src_bmp, CoglError **error) { CoglPixelFormat format = cogl_bitmap_get_format (src_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); int src_rowstride = cogl_bitmap_get_rowstride (src_bmp); int width = cogl_bitmap_get_width (src_bmp); int alignment = 1; if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) || src_rowstride == 0) return cogl_object_ref (src_bmp); /* Work out the alignment of the source rowstride */ alignment = 1 << (_cogl_util_ffs (src_rowstride) - 1); alignment = MIN (alignment, 8); /* If the aligned data equals the rowstride then we can upload from the bitmap directly using GL_UNPACK_ALIGNMENT */ if (((width * bpp + alignment - 1) & ~(alignment - 1)) == src_rowstride) return cogl_object_ref (src_bmp); /* Otherwise we need to copy the bitmap to pack the alignment because GLES has no GL_ROW_LENGTH */ else return _cogl_bitmap_copy (src_bmp, error); } static CoglBool _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, CoglTexture *texture, CoglBool is_foreign, int src_x, int src_y, int dst_x, int dst_y, int width, int height, int level, CoglBitmap *source_bmp, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { GLenum gl_target; GLuint gl_handle; uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); CoglBitmap *slice_bmp; int rowstride; CoglBool status = TRUE; CoglError *internal_error = NULL; int level_width; int level_height; cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); /* If we have the GL_EXT_unpack_subimage extension then we can upload from subregions directly. Otherwise we may need to copy the bitmap */ if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) && (src_x != 0 || src_y != 0 || width != cogl_bitmap_get_width (source_bmp) || height != cogl_bitmap_get_height (source_bmp))) { slice_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, width, height, source_format, error); if (!slice_bmp) return FALSE; if (!_cogl_bitmap_copy_subregion (source_bmp, slice_bmp, src_x, src_y, 0, 0, /* dst_x/y */ width, height, error)) { cogl_object_unref (slice_bmp); return FALSE; } src_x = src_y = 0; } else { slice_bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error); if (!slice_bmp) return FALSE; } rowstride = cogl_bitmap_get_rowstride (slice_bmp); /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, rowstride, src_x, src_y, bpp); data = _cogl_bitmap_gl_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error); /* NB: _cogl_bitmap_gl_bind() may return NULL when successfull so we * have to explicitly check the cogl error pointer to catch * problems... */ if (internal_error) { _cogl_propagate_error (error, internal_error); cogl_object_unref (slice_bmp); return FALSE; } _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); _cogl_texture_get_level_size (texture, level, &level_width, &level_height, NULL); if (level_width == width && level_height == height) { /* GL gets upset if you use glTexSubImage2D to define the * contents of a mipmap level so we make sure to use * glTexImage2D if we are uploading a full mipmap level. */ ctx->glTexImage2D (gl_target, level, _cogl_texture_gl_get_format (texture), width, height, 0, source_gl_format, source_gl_type, data); } else { /* GL gets upset if you use glTexSubImage2D to initialize the * contents of a mipmap level so if this is the first time * we've seen a request to upload to this level we call * glTexImage2D first to assert that the storage for this * level exists. */ if (texture->max_level < level) { ctx->glTexImage2D (gl_target, level, _cogl_texture_gl_get_format (texture), level_width, level_height, 0, source_gl_format, source_gl_type, NULL); } ctx->glTexSubImage2D (gl_target, level, dst_x, dst_y, width, height, source_gl_format, source_gl_type, data); } if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; _cogl_bitmap_gl_unbind (slice_bmp); cogl_object_unref (slice_bmp); return status; } static CoglBool _cogl_texture_driver_upload_to_gl (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); int rowstride; int bmp_width = cogl_bitmap_get_width (source_bmp); int bmp_height = cogl_bitmap_get_height (source_bmp); CoglBitmap *bmp; uint8_t *data; CoglError *internal_error = NULL; CoglBool status = TRUE; bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error); if (!bmp) return FALSE; rowstride = cogl_bitmap_get_rowstride (bmp); /* Setup gl alignment to match rowstride and top-left corner */ _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); data = _cogl_bitmap_gl_bind (bmp, COGL_BUFFER_ACCESS_READ, 0, /* hints */ &internal_error); /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we * have to explicitly check the cogl error pointer to catch * problems... */ if (internal_error) { cogl_object_unref (bmp); _cogl_propagate_error (error, internal_error); return FALSE; } /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage2D (gl_target, 0, internal_gl_format, bmp_width, bmp_height, 0, source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; _cogl_bitmap_gl_unbind (bmp); cogl_object_unref (bmp); return status; } static CoglBool _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, GLint height, GLint depth, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); int rowstride = cogl_bitmap_get_rowstride (source_bmp); int bmp_width = cogl_bitmap_get_width (source_bmp); int bmp_height = cogl_bitmap_get_height (source_bmp); uint8_t *data; _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); /* If the rowstride or image height can't be specified with just GL_ALIGNMENT alone then we need to copy the bitmap because there is no GL_ROW_LENGTH */ if (rowstride / bpp != bmp_width || height != bmp_height / depth) { CoglBitmap *bmp; int image_height = bmp_height / depth; CoglPixelFormat source_bmp_format = cogl_bitmap_get_format (source_bmp); int i; _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, bmp_width * bpp, bpp); /* Initialize the texture with empty data and then upload each image with a sub-region update */ /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage3D (gl_target, 0, /* level */ internal_gl_format, bmp_width, height, depth, 0, source_gl_format, source_gl_type, NULL); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) return FALSE; bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, bmp_width, height, source_bmp_format, error); if (!bmp) return FALSE; for (i = 0; i < depth; i++) { if (!_cogl_bitmap_copy_subregion (source_bmp, bmp, 0, image_height * i, 0, 0, bmp_width, height, error)) { cogl_object_unref (bmp); return FALSE; } data = _cogl_bitmap_gl_bind (bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (!data) { cogl_object_unref (bmp); return FALSE; } /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexSubImage3D (gl_target, 0, /* level */ 0, /* xoffset */ 0, /* yoffset */ i, /* zoffset */ bmp_width, /* width */ height, /* height */ 1, /* depth */ source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { cogl_object_unref (bmp); _cogl_bitmap_gl_unbind (bmp); return FALSE; } _cogl_bitmap_gl_unbind (bmp); } cogl_object_unref (bmp); } else { data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (!data) return FALSE; _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage3D (gl_target, 0, /* level */ internal_gl_format, bmp_width, height, depth, 0, source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { _cogl_bitmap_gl_unbind (source_bmp); return FALSE; } _cogl_bitmap_gl_unbind (source_bmp); } return TRUE; } /* NB: GLES doesn't support glGetTexImage2D, so cogl-texture will instead * fallback to a generic render + readpixels approach to downloading * texture data. (See _cogl_texture_draw_and_read() ) */ static CoglBool _cogl_texture_driver_gl_get_tex_image (CoglContext *ctx, GLenum gl_target, GLenum dest_gl_format, GLenum dest_gl_type, uint8_t *dest) { return FALSE; } static CoglBool _cogl_texture_driver_size_supported_3d (CoglContext *ctx, GLenum gl_target, GLenum gl_format, GLenum gl_type, int width, int height, int depth) { GLint max_size; /* GLES doesn't support a proxy texture target so let's at least check whether the size is greater than GL_MAX_3D_TEXTURE_SIZE_OES */ GE( ctx, glGetIntegerv (GL_MAX_3D_TEXTURE_SIZE_OES, &max_size) ); return width <= max_size && height <= max_size && depth <= max_size; } static CoglBool _cogl_texture_driver_size_supported (CoglContext *ctx, GLenum gl_target, GLenum gl_intformat, GLenum gl_format, GLenum gl_type, int width, int height) { GLint max_size; /* GLES doesn't support a proxy texture target so let's at least check whether the size is greater than GL_MAX_TEXTURE_SIZE */ GE( ctx, glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_size) ); return width <= max_size && height <= max_size; } static void _cogl_texture_driver_try_setting_gl_border_color (CoglContext *ctx, GLuint gl_target, const GLfloat *transparent_color) { /* FAIL! */ } static CoglBool _cogl_texture_driver_allows_foreign_gl_target (CoglContext *ctx, GLenum gl_target) { /* Allow 2-dimensional textures only */ if (gl_target != GL_TEXTURE_2D) return FALSE; return TRUE; } static CoglPixelFormat _cogl_texture_driver_find_best_gl_get_data_format (CoglContext *context, CoglPixelFormat format, CoglPixelFormat target_format, GLenum *closest_gl_format, GLenum *closest_gl_type) { /* Find closest format that's supported by GL (Can't use _cogl_pixel_format_to_gl since available formats when reading pixels on GLES are severely limited) */ *closest_gl_format = GL_RGBA; *closest_gl_type = GL_UNSIGNED_BYTE; return COGL_PIXEL_FORMAT_RGBA_8888; } const CoglTextureDriver _cogl_texture_driver_gles = { _cogl_texture_driver_gen, _cogl_texture_driver_prep_gl_for_pixels_upload, _cogl_texture_driver_upload_subregion_to_gl, _cogl_texture_driver_upload_to_gl, _cogl_texture_driver_upload_to_gl_3d, _cogl_texture_driver_prep_gl_for_pixels_download, _cogl_texture_driver_gl_get_tex_image, _cogl_texture_driver_size_supported, _cogl_texture_driver_size_supported_3d, _cogl_texture_driver_try_setting_gl_border_color, _cogl_texture_driver_allows_foreign_gl_target, _cogl_texture_driver_find_best_gl_get_data_format }; muffin-5.2.1/cogl/cogl/driver/gl/cogl-clip-stack-gl-private.h0000664000175000017500000000304614211404421024101 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_CLIP_STACK_GL_PRIVATE_H_ #define _COGL_CLIP_STACK_GL_PRIVATE_H_ #include "cogl-types.h" #include "cogl-framebuffer.h" #include "cogl-clip-stack.h" void _cogl_clip_stack_gl_flush (CoglClipStack *stack, CoglFramebuffer *framebuffer); #endif /* _COGL_CLIP_STACK_GL_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-buffer-gl-private.h0000664000175000017500000000445314211404421023323 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_BUFFER_GL_PRIVATE_H_ #define _COGL_BUFFER_GL_PRIVATE_H_ #include "cogl-types.h" #include "cogl-context.h" #include "cogl-buffer.h" #include "cogl-buffer-private.h" void _cogl_buffer_gl_create (CoglBuffer *buffer); void _cogl_buffer_gl_destroy (CoglBuffer *buffer); void * _cogl_buffer_gl_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error); void _cogl_buffer_gl_unmap (CoglBuffer *buffer); CoglBool _cogl_buffer_gl_set_data (CoglBuffer *buffer, unsigned int offset, const void *data, unsigned int size, CoglError **error); void * _cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target, CoglError **error); void _cogl_buffer_gl_unbind (CoglBuffer *buffer); #endif /* _COGL_BUFFER_GL_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed-private.h0000664000175000017500000000274114211404421025756 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_FRAGEND_FIXED_PRIVATE_H #define __COGL_PIPELINE_FRAGEND_FIXED_PRIVATE_H #include "cogl-pipeline-private.h" extern const CoglPipelineFragend _cogl_pipeline_fixed_fragend; #endif /* __COGL_PIPELINE_FRAGEND_FIXED_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-util-gl-private.h0000664000175000017500000000761614211404421023033 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012, 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifndef _COGL_UTIL_GL_PRIVATE_H_ #include "cogl-types.h" #include "cogl-context.h" #include "cogl-gl-header.h" #include "cogl-texture.h" /* In OpenGL ES context, GL_CONTEXT_LOST has a _KHR prefix */ #ifndef GL_CONTEXT_LOST #define GL_CONTEXT_LOST GL_CONTEXT_LOST_KHR #endif #ifdef COGL_GL_DEBUG const char * _cogl_gl_error_to_string (GLenum error_code); #define GE(ctx, x) G_STMT_START { \ GLenum __err; \ (ctx)->x; \ while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR && __err != GL_CONTEXT_LOST) \ { \ g_warning ("%s: GL error (%d): %s\n", \ G_STRLOC, \ __err, \ _cogl_gl_error_to_string (__err)); \ } } G_STMT_END #define GE_RET(ret, ctx, x) G_STMT_START { \ GLenum __err; \ ret = (ctx)->x; \ while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR && __err != GL_CONTEXT_LOST) \ { \ g_warning ("%s: GL error (%d): %s\n", \ G_STRLOC, \ __err, \ _cogl_gl_error_to_string (__err)); \ } } G_STMT_END #else /* !COGL_GL_DEBUG */ #define GE(ctx, x) ((ctx)->x) #define GE_RET(ret, ctx, x) (ret = ((ctx)->x)) #endif /* COGL_GL_DEBUG */ GLenum _cogl_gl_util_get_error (CoglContext *ctx); void _cogl_gl_util_clear_gl_errors (CoglContext *ctx); CoglBool _cogl_gl_util_catch_out_of_memory (CoglContext *ctx, CoglError **error); void _cogl_gl_util_get_texture_target_string (CoglTextureType texture_type, const char **target_string_out, const char **swizzle_out); /* Parses a GL version number stored in a string. @version_string must * point to the beginning of the version number (ie, it can't point to * the "OpenGL ES" part on GLES). The version number can be followed * by the end of the string, a space or a full stop. Anything else * will be treated as invalid. Returns TRUE and sets major_out and * minor_out if it is succesfully parsed or FALSE otherwise. */ CoglBool _cogl_gl_util_parse_gl_version (const char *version_string, int *major_out, int *minor_out); #endif /* _COGL_UTIL_GL_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-texture-gl.c0000664000175000017500000001214714211404421022074 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #ifdef HAVE_STRINGS_H #include #endif #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-texture-gl-private.h" #include "cogl-texture-3d-private.h" #include "cogl-util.h" #include "cogl-pipeline-opengl-private.h" static inline int calculate_alignment (int rowstride) { int alignment = 1 << (_cogl_util_ffs (rowstride) - 1); return MIN (alignment, 8); } void _cogl_texture_gl_prep_alignment_for_pixels_upload (CoglContext *ctx, int pixels_rowstride) { GE( ctx, glPixelStorei (GL_UNPACK_ALIGNMENT, calculate_alignment (pixels_rowstride)) ); } void _cogl_texture_gl_prep_alignment_for_pixels_download (CoglContext *ctx, int bpp, int width, int rowstride) { int alignment; /* If no padding is needed then we can always use an alignment of 1. * We want to do this even though it is equivalent to the alignment * of the rowstride because the Intel driver in Mesa currently has * an optimisation when reading data into a PBO that only works if * the alignment is exactly 1. * * https://bugs.freedesktop.org/show_bug.cgi?id=46632 */ if (rowstride == bpp * width) alignment = 1; else alignment = calculate_alignment (rowstride); GE( ctx, glPixelStorei (GL_PACK_ALIGNMENT, alignment) ); } void _cogl_texture_gl_flush_legacy_texobj_wrap_modes (CoglTexture *texture, unsigned int wrap_mode_s, unsigned int wrap_mode_t, unsigned int wrap_mode_p) { texture->vtable->gl_flush_legacy_texobj_wrap_modes (texture, wrap_mode_s, wrap_mode_t, wrap_mode_p); } void _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture, unsigned int min_filter, unsigned int mag_filter) { texture->vtable->gl_flush_legacy_texobj_filters (texture, min_filter, mag_filter); } void _cogl_texture_gl_maybe_update_max_level (CoglTexture *texture, int max_level) { /* This isn't supported on GLES */ #ifdef HAVE_COGL_GL CoglContext *ctx = texture->context; if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL) && texture->max_level < max_level) { CoglContext *ctx = texture->context; GLuint gl_handle; GLenum gl_target; cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); texture->max_level = max_level; _cogl_bind_gl_texture_transient (gl_target, gl_handle, _cogl_texture_is_foreign (texture)); GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MAX_LEVEL, texture->max_level)); } #endif /* HAVE_COGL_GL */ } void _cogl_texture_gl_generate_mipmaps (CoglTexture *texture) { CoglContext *ctx = texture->context; int n_levels = _cogl_texture_get_n_levels (texture); GLuint gl_handle; GLenum gl_target; _cogl_texture_gl_maybe_update_max_level (texture, n_levels - 1); cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); _cogl_bind_gl_texture_transient (gl_target, gl_handle, _cogl_texture_is_foreign (texture)); GE( ctx, glGenerateMipmap (gl_target) ); } GLenum _cogl_texture_gl_get_format (CoglTexture *texture) { return texture->vtable->get_gl_format (texture); } muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed.c0000664000175000017500000000771714211404421024352 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-state-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-framebuffer-private.h" #ifdef COGL_PIPELINE_VERTEND_FIXED #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-program-private.h" const CoglPipelineVertend _cogl_pipeline_fixed_vertend; static void _cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { _cogl_use_vertex_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED); } static CoglBool _cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference, CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; int unit_index = _cogl_pipeline_layer_get_unit_index (layer); CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index); if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX) { CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX; CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, state); CoglMatrixEntry *matrix_entry; cogl_matrix_stack_set (unit->matrix_stack, &authority->big_state->matrix); _cogl_set_active_texture_unit (unit_index); matrix_entry = unit->matrix_stack->last_entry; _cogl_matrix_entry_flush_to_gl_builtins (ctx, matrix_entry, COGL_MATRIX_TEXTURE, framebuffer, FALSE /* enable flip */); } return TRUE; } static CoglBool _cogl_pipeline_vertend_fixed_end (CoglPipeline *pipeline, unsigned long pipelines_difference) { _COGL_GET_CONTEXT (ctx, FALSE); if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE); if (authority->big_state->point_size > 0.0f) GE( ctx, glPointSize (authority->big_state->point_size) ); } return TRUE; } const CoglPipelineVertend _cogl_pipeline_fixed_vertend = { _cogl_pipeline_vertend_fixed_start, _cogl_pipeline_vertend_fixed_add_layer, _cogl_pipeline_vertend_fixed_end, NULL, /* pipeline_change_notify */ NULL /* layer_change_notify */ }; #endif /* COGL_PIPELINE_VERTEND_FIXED */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-buffer-gl.c0000664000175000017500000003005314211404421021641 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2011,2012,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Damien Lespiau * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-buffer-gl-private.h" #include "cogl-error-private.h" #include "cogl-util-gl-private.h" /* * GL/GLES compatibility defines for the buffer API: */ #ifndef GL_PIXEL_PACK_BUFFER #define GL_PIXEL_PACK_BUFFER 0x88EB #endif #ifndef GL_PIXEL_UNPACK_BUFFER #define GL_PIXEL_UNPACK_BUFFER 0x88EC #endif #ifndef GL_ARRAY_BUFFER #define GL_ARRAY_BUFFER 0x8892 #endif #ifndef GL_ELEMENT_ARRAY_BUFFER #define GL_ARRAY_BUFFER 0x8893 #endif #ifndef GL_READ_ONLY #define GL_READ_ONLY 0x88B8 #endif #ifndef GL_WRITE_ONLY #define GL_WRITE_ONLY 0x88B9 #endif #ifndef GL_READ_WRITE #define GL_READ_WRITE 0x88BA #endif #ifndef GL_MAP_READ_BIT #define GL_MAP_READ_BIT 0x0001 #endif #ifndef GL_MAP_WRITE_BIT #define GL_MAP_WRITE_BIT 0x0002 #endif #ifndef GL_MAP_INVALIDATE_RANGE_BIT #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #endif #ifndef GL_MAP_INVALIDATE_BUFFER_BIT #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #endif void _cogl_buffer_gl_create (CoglBuffer *buffer) { CoglContext *ctx = buffer->context; GE (ctx, glGenBuffers (1, &buffer->gl_handle)); } void _cogl_buffer_gl_destroy (CoglBuffer *buffer) { GE( buffer->context, glDeleteBuffers (1, &buffer->gl_handle) ); } static GLenum update_hints_to_gl_enum (CoglBuffer *buffer) { /* usage hint is always DRAW for now */ switch (buffer->update_hint) { case COGL_BUFFER_UPDATE_HINT_STATIC: return GL_STATIC_DRAW; case COGL_BUFFER_UPDATE_HINT_DYNAMIC: return GL_DYNAMIC_DRAW; case COGL_BUFFER_UPDATE_HINT_STREAM: /* OpenGL ES 1.1 only knows about STATIC_DRAW and DYNAMIC_DRAW */ #if defined(HAVE_COGL_GL) || defined(HAVE_COGL_GLES2) if (buffer->context->driver != COGL_DRIVER_GLES1) return GL_STREAM_DRAW; #else return GL_DYNAMIC_DRAW; #endif } g_assert_not_reached (); } static GLenum convert_bind_target_to_gl_target (CoglBufferBindTarget target) { switch (target) { case COGL_BUFFER_BIND_TARGET_PIXEL_PACK: return GL_PIXEL_PACK_BUFFER; case COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK: return GL_PIXEL_UNPACK_BUFFER; case COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER: return GL_ARRAY_BUFFER; case COGL_BUFFER_BIND_TARGET_INDEX_BUFFER: return GL_ELEMENT_ARRAY_BUFFER; default: g_return_val_if_reached (COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK); } } static CoglBool recreate_store (CoglBuffer *buffer, CoglError **error) { CoglContext *ctx = buffer->context; GLenum gl_target; GLenum gl_enum; /* This assumes the buffer is already bound */ gl_target = convert_bind_target_to_gl_target (buffer->last_target); gl_enum = update_hints_to_gl_enum (buffer); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glBufferData (gl_target, buffer->size, NULL, gl_enum); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) return FALSE; buffer->store_created = TRUE; return TRUE; } GLenum _cogl_buffer_access_to_gl_enum (CoglBufferAccess access) { if ((access & COGL_BUFFER_ACCESS_READ_WRITE) == COGL_BUFFER_ACCESS_READ_WRITE) return GL_READ_WRITE; else if (access & COGL_BUFFER_ACCESS_WRITE) return GL_WRITE_ONLY; else return GL_READ_ONLY; } static void * _cogl_buffer_bind_no_create (CoglBuffer *buffer, CoglBufferBindTarget target) { CoglContext *ctx = buffer->context; _COGL_RETURN_VAL_IF_FAIL (buffer != NULL, NULL); /* Don't allow binding the buffer to multiple targets at the same time */ _COGL_RETURN_VAL_IF_FAIL (ctx->current_buffer[buffer->last_target] != buffer, NULL); /* Don't allow nesting binds to the same target */ _COGL_RETURN_VAL_IF_FAIL (ctx->current_buffer[target] == NULL, NULL); buffer->last_target = target; ctx->current_buffer[target] = buffer; if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) { GLenum gl_target = convert_bind_target_to_gl_target (buffer->last_target); GE( ctx, glBindBuffer (gl_target, buffer->gl_handle) ); return NULL; } else return buffer->data; } void * _cogl_buffer_gl_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error) { uint8_t *data; CoglBufferBindTarget target; GLenum gl_target; CoglContext *ctx = buffer->context; if (((access & COGL_BUFFER_ACCESS_READ) && !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) || ((access & COGL_BUFFER_ACCESS_WRITE) && !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE))) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Tried to map a buffer with unsupported access mode"); return NULL; } target = buffer->last_target; _cogl_buffer_bind_no_create (buffer, target); gl_target = convert_bind_target_to_gl_target (target); if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) && offset == 0 && size >= buffer->size) hints |= COGL_BUFFER_MAP_HINT_DISCARD; /* If the map buffer range extension is supported then we will * always use it even if we are mapping the full range because the * normal mapping function doesn't support passing the discard * hints */ if (ctx->glMapBufferRange) { GLbitfield gl_access = 0; CoglBool should_recreate_store = !buffer->store_created; if ((access & COGL_BUFFER_ACCESS_READ)) gl_access |= GL_MAP_READ_BIT; if ((access & COGL_BUFFER_ACCESS_WRITE)) gl_access |= GL_MAP_WRITE_BIT; if ((hints & COGL_BUFFER_MAP_HINT_DISCARD)) { /* glMapBufferRange generates an error if you pass the * discard hint along with asking for read access. However * it can make sense to ask for both if write access is also * requested so that the application can immediately read * back what it just wrote. To work around the restriction * in GL we just recreate the buffer storage in that case * which is an alternative way to indicate that the buffer * contents can be discarded. */ if ((access & COGL_BUFFER_ACCESS_READ)) should_recreate_store = TRUE; else gl_access |= GL_MAP_INVALIDATE_BUFFER_BIT; } else if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) && !(access & COGL_BUFFER_ACCESS_READ)) gl_access |= GL_MAP_INVALIDATE_RANGE_BIT; if (should_recreate_store) { if (!recreate_store (buffer, error)) { _cogl_buffer_gl_unbind (buffer); return NULL; } } /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); data = ctx->glMapBufferRange (gl_target, offset, size, gl_access); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { _cogl_buffer_gl_unbind (buffer); return NULL; } _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); } else { /* create an empty store if we don't have one yet. creating the store * lazily allows the user of the CoglBuffer to set a hint before the * store is created. */ if (!buffer->store_created || (hints & COGL_BUFFER_MAP_HINT_DISCARD)) { if (!recreate_store (buffer, error)) { _cogl_buffer_gl_unbind (buffer); return NULL; } } /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); data = ctx->glMapBuffer (gl_target, _cogl_buffer_access_to_gl_enum (access)); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { _cogl_buffer_gl_unbind (buffer); return NULL; } _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); data += offset; } if (data) buffer->flags |= COGL_BUFFER_FLAG_MAPPED; _cogl_buffer_gl_unbind (buffer); return data; } void _cogl_buffer_gl_unmap (CoglBuffer *buffer) { CoglContext *ctx = buffer->context; _cogl_buffer_bind_no_create (buffer, buffer->last_target); GE( ctx, glUnmapBuffer (convert_bind_target_to_gl_target (buffer->last_target)) ); buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED; _cogl_buffer_gl_unbind (buffer); } CoglBool _cogl_buffer_gl_set_data (CoglBuffer *buffer, unsigned int offset, const void *data, unsigned int size, CoglError **error) { CoglBufferBindTarget target; GLenum gl_target; CoglContext *ctx = buffer->context; CoglBool status = TRUE; CoglError *internal_error = NULL; target = buffer->last_target; _cogl_buffer_gl_bind (buffer, target, &internal_error); /* NB: _cogl_buffer_gl_bind() may return NULL in non-error * conditions so we have to explicity check internal_error * to see if an exception was thrown. */ if (internal_error) { _cogl_propagate_error (error, internal_error); return FALSE; } gl_target = convert_bind_target_to_gl_target (target); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glBufferSubData (gl_target, offset, size, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; _cogl_buffer_gl_unbind (buffer); return status; } void * _cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target, CoglError **error) { void *ret; ret = _cogl_buffer_bind_no_create (buffer, target); /* create an empty store if we don't have one yet. creating the store * lazily allows the user of the CoglBuffer to set a hint before the * store is created. */ if ((buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) && !buffer->store_created) { if (!recreate_store (buffer, error)) { _cogl_buffer_gl_unbind (buffer); return NULL; } } return ret; } void _cogl_buffer_gl_unbind (CoglBuffer *buffer) { CoglContext *ctx = buffer->context; _COGL_RETURN_IF_FAIL (buffer != NULL); /* the unbind should pair up with a previous bind */ _COGL_RETURN_IF_FAIL (ctx->current_buffer[buffer->last_target] == buffer); if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) { GLenum gl_target = convert_bind_target_to_gl_target (buffer->last_target); GE( ctx, glBindBuffer (gl_target, 0) ); } ctx->current_buffer[buffer->last_target] = NULL; } muffin-5.2.1/cogl/cogl/driver/gl/cogl-framebuffer-gl.c0000664000175000017500000016170014211404421022660 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-framebuffer-private.h" #include "cogl-framebuffer-gl-private.h" #include "cogl-buffer-gl-private.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" #include "cogl-texture-private.h" #include #include #ifndef GL_FRAMEBUFFER #define GL_FRAMEBUFFER 0x8D40 #endif #ifndef GL_RENDERBUFFER #define GL_RENDERBUFFER 0x8D41 #endif #ifndef GL_STENCIL_ATTACHMENT #define GL_STENCIL_ATTACHMENT 0x8D00 #endif #ifndef GL_COLOR_ATTACHMENT0 #define GL_COLOR_ATTACHMENT0 0x8CE0 #endif #ifndef GL_FRAMEBUFFER_COMPLETE #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #endif #ifndef GL_STENCIL_INDEX8 #define GL_STENCIL_INDEX8 0x8D48 #endif #ifndef GL_DEPTH_STENCIL #define GL_DEPTH_STENCIL 0x84F9 #endif #ifndef GL_DEPTH24_STENCIL8 #define GL_DEPTH24_STENCIL8 0x88F0 #endif #ifndef GL_DEPTH_ATTACHMENT #define GL_DEPTH_ATTACHMENT 0x8D00 #endif #ifndef GL_DEPTH_STENCIL_ATTACHMENT #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #endif #ifndef GL_DEPTH_COMPONENT16 #define GL_DEPTH_COMPONENT16 0x81A5 #endif #ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #endif #ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #endif #ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #endif #ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #endif #ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #endif #ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #endif #ifndef GL_READ_FRAMEBUFFER #define GL_READ_FRAMEBUFFER 0x8CA8 #endif #ifndef GL_DRAW_FRAMEBUFFER #define GL_DRAW_FRAMEBUFFER 0x8CA9 #endif #ifndef GL_TEXTURE_SAMPLES_IMG #define GL_TEXTURE_SAMPLES_IMG 0x9136 #endif #ifndef GL_PACK_INVERT_MESA #define GL_PACK_INVERT_MESA 0x8758 #endif #ifndef GL_BACK_LEFT #define GL_BACK_LEFT 0x0402 #endif #ifndef GL_BACK_RIGHT #define GL_BACK_RIGHT 0x0403 #endif #ifndef GL_COLOR #define GL_COLOR 0x1800 #endif #ifndef GL_DEPTH #define GL_DEPTH 0x1801 #endif #ifndef GL_STENCIL #define GL_STENCIL 0x1802 #endif static void _cogl_framebuffer_gl_flush_viewport_state (CoglFramebuffer *framebuffer) { float gl_viewport_y; g_assert (framebuffer->viewport_width >=0 && framebuffer->viewport_height >=0); /* Convert the Cogl viewport y offset to an OpenGL viewport y offset * NB: OpenGL defines its window and viewport origins to be bottom * left, while Cogl defines them to be top left. * NB: We render upside down to offscreen framebuffers so we don't * need to convert the y offset in this case. */ if (cogl_is_offscreen (framebuffer)) gl_viewport_y = framebuffer->viewport_y; else gl_viewport_y = framebuffer->height - (framebuffer->viewport_y + framebuffer->viewport_height); COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)", framebuffer->viewport_x, gl_viewport_y, framebuffer->viewport_width, framebuffer->viewport_height); GE (framebuffer->context, glViewport (framebuffer->viewport_x, gl_viewport_y, framebuffer->viewport_width, framebuffer->viewport_height)); } static void _cogl_framebuffer_gl_flush_clip_state (CoglFramebuffer *framebuffer) { _cogl_clip_stack_flush (framebuffer->clip_stack, framebuffer); } static void _cogl_framebuffer_gl_flush_dither_state (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled) { if (framebuffer->dither_enabled) GE (ctx, glEnable (GL_DITHER)); else GE (ctx, glDisable (GL_DITHER)); ctx->current_gl_dither_enabled = framebuffer->dither_enabled; } } static void _cogl_framebuffer_gl_flush_modelview_state (CoglFramebuffer *framebuffer) { CoglMatrixEntry *modelview_entry = _cogl_framebuffer_get_modelview_entry (framebuffer); _cogl_context_set_current_modelview_entry (framebuffer->context, modelview_entry); } static void _cogl_framebuffer_gl_flush_projection_state (CoglFramebuffer *framebuffer) { CoglMatrixEntry *projection_entry = _cogl_framebuffer_get_projection_entry (framebuffer); _cogl_context_set_current_projection_entry (framebuffer->context, projection_entry); } static void _cogl_framebuffer_gl_flush_color_mask_state (CoglFramebuffer *framebuffer) { CoglContext *context = framebuffer->context; /* The color mask state is really owned by a CoglPipeline so to * ensure the color mask is updated the next time we draw something * we need to make sure the logic ops for the pipeline are * re-flushed... */ context->current_pipeline_changes_since_flush |= COGL_PIPELINE_STATE_LOGIC_OPS; context->current_pipeline_age--; } static void _cogl_framebuffer_gl_flush_front_face_winding_state (CoglFramebuffer *framebuffer) { CoglContext *context = framebuffer->context; CoglPipelineCullFaceMode mode; /* NB: The face winding state is actually owned by the current * CoglPipeline. * * If we don't have a current pipeline then we can just assume that * when we later do flush a pipeline we will check the current * framebuffer to know how to setup the winding */ if (!context->current_pipeline) return; mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline); /* If the current CoglPipeline has a culling mode that doesn't care * about the winding we can avoid forcing an update of the state and * bail out. */ if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE || mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH) return; /* Since the winding state is really owned by the current pipeline * the way we "flush" an updated winding is to dirty the pipeline * state... */ context->current_pipeline_changes_since_flush |= COGL_PIPELINE_STATE_CULL_FACE; context->current_pipeline_age--; } static void _cogl_framebuffer_gl_flush_stereo_mode_state (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; GLenum draw_buffer = GL_BACK; if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) return; if (!ctx->glDrawBuffer) return; /* The one-shot default draw buffer setting in _cogl_framebuffer_gl_bind * must have already happened. If not it would override what we set here. */ g_assert (ctx->was_bound_to_onscreen); switch (framebuffer->stereo_mode) { case COGL_STEREO_BOTH: draw_buffer = GL_BACK; break; case COGL_STEREO_LEFT: draw_buffer = GL_BACK_LEFT; break; case COGL_STEREO_RIGHT: draw_buffer = GL_BACK_RIGHT; break; } if (ctx->current_gl_draw_buffer != draw_buffer) { GE (ctx, glDrawBuffer (draw_buffer)); ctx->current_gl_draw_buffer = draw_buffer; } } void _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target) { CoglContext *ctx = framebuffer->context; if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) { CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer); GE (ctx, glBindFramebuffer (target, offscreen->gl_framebuffer.fbo_handle)); } else { const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer); winsys->onscreen_bind (COGL_ONSCREEN (framebuffer)); /* glBindFramebuffer is an an extension with OpenGL ES 1.1 */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) GE (ctx, glBindFramebuffer (target, 0)); /* Initialise the glDrawBuffer state the first time the context * is bound to the default framebuffer. If the winsys is using a * surfaceless context for the initial make current then the * default draw buffer will be GL_NONE so we need to correct * that. We can't do it any earlier because binding GL_BACK when * there is no default framebuffer won't work */ if (!ctx->was_bound_to_onscreen) { if (ctx->glDrawBuffer) { GE (ctx, glDrawBuffer (GL_BACK)); } else if (ctx->glDrawBuffers) { /* glDrawBuffer isn't available on GLES 3.0 so we need * to be able to use glDrawBuffers as well. On GLES 2 * neither is available but the state should always be * GL_BACK anyway so we don't need to set anything. On * desktop GL this must be GL_BACK_LEFT instead of * GL_BACK but as this code path will only be hit for * GLES we can just use GL_BACK. */ static const GLenum buffers[] = { GL_BACK }; GE (ctx, glDrawBuffers (G_N_ELEMENTS (buffers), buffers)); } ctx->was_bound_to_onscreen = TRUE; } } } void _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state) { CoglContext *ctx = draw_buffer->context; unsigned long differences; int bit; /* We can assume that any state that has changed for the current * framebuffer is different to the currently flushed value. */ differences = ctx->current_draw_buffer_changes; /* Any state of the current framebuffer that hasn't already been * flushed is assumed to be unknown so we will always flush that * state if asked. */ differences |= ~ctx->current_draw_buffer_state_flushed; /* We only need to consider the state we've been asked to flush */ differences &= state; if (ctx->current_draw_buffer != draw_buffer) { /* If the previous draw buffer is NULL then we'll assume everything has changed. This can happen if a framebuffer is destroyed while it is the last flushed draw buffer. In that case the framebuffer destructor will set ctx->current_draw_buffer to NULL */ if (ctx->current_draw_buffer == NULL) differences |= state; else /* NB: we only need to compare the state we're being asked to flush * and we don't need to compare the state we've already decided * we will definitely flush... */ differences |= _cogl_framebuffer_compare (ctx->current_draw_buffer, draw_buffer, state & ~differences); /* NB: we don't take a reference here, to avoid a circular * reference. */ ctx->current_draw_buffer = draw_buffer; ctx->current_draw_buffer_state_flushed = 0; } if (ctx->current_read_buffer != read_buffer && state & COGL_FRAMEBUFFER_STATE_BIND) { differences |= COGL_FRAMEBUFFER_STATE_BIND; /* NB: we don't take a reference here, to avoid a circular * reference. */ ctx->current_read_buffer = read_buffer; } if (!differences) return; /* Lazily ensure the framebuffers have been allocated */ if (G_UNLIKELY (!draw_buffer->allocated)) cogl_framebuffer_allocate (draw_buffer, NULL); if (G_UNLIKELY (!read_buffer->allocated)) cogl_framebuffer_allocate (read_buffer, NULL); /* We handle buffer binding separately since the method depends on whether * we are binding the same buffer for read and write or not unlike all * other state that only relates to the draw_buffer. */ if (differences & COGL_FRAMEBUFFER_STATE_BIND) { if (draw_buffer == read_buffer) _cogl_framebuffer_gl_bind (draw_buffer, GL_FRAMEBUFFER); else { /* NB: Currently we only take advantage of binding separate * read/write buffers for offscreen framebuffer blit * purposes. */ _COGL_RETURN_IF_FAIL (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)); _COGL_RETURN_IF_FAIL (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); _COGL_RETURN_IF_FAIL (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN); _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER); _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER); } differences &= ~COGL_FRAMEBUFFER_STATE_BIND; } COGL_FLAGS_FOREACH_START (&differences, 1, bit) { /* XXX: We considered having an array of callbacks for each state index * that we'd call here but decided that this way the compiler is more * likely going to be able to in-line the flush functions and use the * index to jump straight to the required code. */ switch (bit) { case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT: _cogl_framebuffer_gl_flush_viewport_state (draw_buffer); break; case COGL_FRAMEBUFFER_STATE_INDEX_CLIP: _cogl_framebuffer_gl_flush_clip_state (draw_buffer); break; case COGL_FRAMEBUFFER_STATE_INDEX_DITHER: _cogl_framebuffer_gl_flush_dither_state (draw_buffer); break; case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW: _cogl_framebuffer_gl_flush_modelview_state (draw_buffer); break; case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION: _cogl_framebuffer_gl_flush_projection_state (draw_buffer); break; case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK: _cogl_framebuffer_gl_flush_color_mask_state (draw_buffer); break; case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING: _cogl_framebuffer_gl_flush_front_face_winding_state (draw_buffer); break; case COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE: /* Nothing to do for depth write state change; the state will always * be taken into account when flushing the pipeline's depth state. */ break; case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE: _cogl_framebuffer_gl_flush_stereo_mode_state (draw_buffer); break; default: g_warn_if_reached (); } } COGL_FLAGS_FOREACH_END; ctx->current_draw_buffer_state_flushed |= state; ctx->current_draw_buffer_changes &= ~state; } static CoglTexture * create_depth_texture (CoglContext *ctx, int width, int height) { CoglTexture2D *depth_texture = cogl_texture_2d_new_with_size (ctx, width, height); cogl_texture_set_components (COGL_TEXTURE (depth_texture), COGL_TEXTURE_COMPONENTS_DEPTH); return COGL_TEXTURE (depth_texture); } static CoglTexture * attach_depth_texture (CoglContext *ctx, CoglTexture *depth_texture, CoglOffscreenAllocateFlags flags) { GLuint tex_gl_handle; GLenum tex_gl_target; if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) { /* attach a GL_DEPTH_STENCIL texture to the GL_DEPTH_ATTACHMENT and * GL_STENCIL_ATTACHMENT attachement points */ g_assert (_cogl_texture_get_format (depth_texture) == COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8); cogl_texture_get_gl_texture (depth_texture, &tex_gl_handle, &tex_gl_target); GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex_gl_target, tex_gl_handle, 0)); GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, tex_gl_target, tex_gl_handle, 0)); } else if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH) { /* attach a newly created GL_DEPTH_COMPONENT16 texture to the * GL_DEPTH_ATTACHMENT attachement point */ g_assert (_cogl_texture_get_format (depth_texture) == COGL_PIXEL_FORMAT_DEPTH_16); cogl_texture_get_gl_texture (COGL_TEXTURE (depth_texture), &tex_gl_handle, &tex_gl_target); GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex_gl_target, tex_gl_handle, 0)); } return COGL_TEXTURE (depth_texture); } static GList * try_creating_renderbuffers (CoglContext *ctx, int width, int height, CoglOffscreenAllocateFlags flags, int n_samples) { GList *renderbuffers = NULL; GLuint gl_depth_stencil_handle; if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) { GLenum format; /* WebGL adds a GL_DEPTH_STENCIL_ATTACHMENT and requires that we * use the GL_DEPTH_STENCIL format. */ #ifdef HAVE_COGL_WEBGL format = GL_DEPTH_STENCIL; #else /* Although GL_OES_packed_depth_stencil is mostly equivalent to * GL_EXT_packed_depth_stencil, one notable difference is that * GL_OES_packed_depth_stencil doesn't allow GL_DEPTH_STENCIL to * be passed as an internal format to glRenderbufferStorage. */ if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL)) format = GL_DEPTH_STENCIL; else { _COGL_RETURN_VAL_IF_FAIL ( _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL), NULL); format = GL_DEPTH24_STENCIL8; } #endif /* Create a renderbuffer for depth and stenciling */ GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle)); GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle)); if (n_samples) GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, n_samples, format, width, height)); else GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format, width, height)); GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); #ifdef HAVE_COGL_WEBGL GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_depth_stencil_handle)); #else GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_depth_stencil_handle)); GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, gl_depth_stencil_handle)); #endif renderbuffers = g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_stencil_handle)); } if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH) { GLuint gl_depth_handle; GE (ctx, glGenRenderbuffers (1, &gl_depth_handle)); GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle)); /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's * available under GLES */ if (n_samples) GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, n_samples, GL_DEPTH_COMPONENT16, width, height)); else GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height)); GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, gl_depth_handle)); renderbuffers = g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle)); } if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL) { GLuint gl_stencil_handle; GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle)); GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle)); if (n_samples) GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, n_samples, GL_STENCIL_INDEX8, width, height)); else GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height)); GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_stencil_handle)); renderbuffers = g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle)); } return renderbuffers; } static void delete_renderbuffers (CoglContext *ctx, GList *renderbuffers) { GList *l; for (l = renderbuffers; l; l = l->next) { GLuint renderbuffer = GPOINTER_TO_UINT (l->data); GE (ctx, glDeleteRenderbuffers (1, &renderbuffer)); } g_list_free (renderbuffers); } /* * NB: This function may be called with a standalone GLES2 context * bound so we can create a shadow framebuffer that wraps the same * CoglTexture as the given CoglOffscreen. This function shouldn't * modify anything in */ static CoglBool try_creating_fbo (CoglContext *ctx, CoglTexture *texture, int texture_level, int texture_level_width, int texture_level_height, CoglTexture *depth_texture, CoglFramebufferConfig *config, CoglOffscreenAllocateFlags flags, CoglGLFramebuffer *gl_framebuffer) { GLuint tex_gl_handle; GLenum tex_gl_target; GLenum status; int n_samples; if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target)) return FALSE; if (tex_gl_target != GL_TEXTURE_2D #ifdef HAVE_COGL_GL && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB #endif ) return FALSE; if (config->samples_per_pixel) { if (!ctx->glFramebufferTexture2DMultisampleIMG) return FALSE; n_samples = config->samples_per_pixel; } else n_samples = 0; /* We are about to generate and bind a new fbo, so we pretend to * change framebuffer state so that the old framebuffer will be * rebound again before drawing. */ ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND; /* Generate framebuffer */ ctx->glGenFramebuffers (1, &gl_framebuffer->fbo_handle); GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_framebuffer->fbo_handle)); if (n_samples) { GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_gl_target, tex_gl_handle, n_samples, texture_level)); } else GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_gl_target, tex_gl_handle, texture_level)); /* attach either a depth/stencil texture, a depth texture or render buffers * depending on what we've been asked to provide */ if (depth_texture && flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL | COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)) { attach_depth_texture (ctx, depth_texture, flags); /* Let's clear the flags that are now fulfilled as we might need to * create renderbuffers (for the ALLOCATE_FLAG_DEPTH | * ALLOCATE_FLAG_STENCIL case) */ flags &= ~(COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL | COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH); } if (flags) { gl_framebuffer->renderbuffers = try_creating_renderbuffers (ctx, texture_level_width, texture_level_height, flags, n_samples); } /* Make sure it's complete */ status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { GE (ctx, glDeleteFramebuffers (1, &gl_framebuffer->fbo_handle)); delete_renderbuffers (ctx, gl_framebuffer->renderbuffers); gl_framebuffer->renderbuffers = NULL; return FALSE; } /* Update the real number of samples_per_pixel now that we have a * complete framebuffer */ if (n_samples) { GLenum attachment = GL_COLOR_ATTACHMENT0; GLenum pname = GL_TEXTURE_SAMPLES_IMG; int texture_samples; GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, attachment, pname, &texture_samples) ); gl_framebuffer->samples_per_pixel = texture_samples; } return TRUE; } CoglBool _cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx, CoglTexture *texture, int texture_level, int texture_level_width, int texture_level_height, CoglTexture *depth_texture, CoglFramebufferConfig *config, CoglOffscreenAllocateFlags flags, CoglGLFramebuffer *gl_framebuffer) { return try_creating_fbo (ctx, texture, texture_level, texture_level_width, texture_level_height, depth_texture, config, flags, gl_framebuffer); } CoglBool _cogl_offscreen_gl_allocate (CoglOffscreen *offscreen, CoglError **error) { CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen); CoglContext *ctx = fb->context; CoglOffscreenAllocateFlags flags; CoglGLFramebuffer *gl_framebuffer = &offscreen->gl_framebuffer; int level_width; int level_height; _COGL_RETURN_VAL_IF_FAIL (offscreen->texture_level < _cogl_texture_get_n_levels (offscreen->texture), FALSE); _cogl_texture_get_level_size (offscreen->texture, offscreen->texture_level, &level_width, &level_height, NULL); if (fb->config.depth_texture_enabled && offscreen->depth_texture == NULL) { offscreen->depth_texture = create_depth_texture (ctx, level_width, level_height); if (!cogl_texture_allocate (offscreen->depth_texture, error)) { cogl_object_unref (offscreen->depth_texture); offscreen->depth_texture = NULL; return FALSE; } _cogl_texture_associate_framebuffer (offscreen->depth_texture, fb); } /* XXX: The framebuffer_object spec isn't clear in defining whether attaching * a texture as a renderbuffer with mipmap filtering enabled while the * mipmaps have not been uploaded should result in an incomplete framebuffer * object. (different drivers make different decisions) * * To avoid an error with drivers that do consider this a problem we * explicitly set non mipmapped filters here. These will later be reset when * the texture is actually used for rendering according to the filters set on * the corresponding CoglPipeline. */ _cogl_texture_gl_flush_legacy_texobj_filters (offscreen->texture, GL_NEAREST, GL_NEAREST); if (((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) && try_creating_fbo (ctx, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &fb->config, flags = 0, gl_framebuffer)) || (ctx->have_last_offscreen_allocate_flags && try_creating_fbo (ctx, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &fb->config, flags = ctx->last_offscreen_allocate_flags, gl_framebuffer)) || ( /* NB: WebGL introduces a DEPTH_STENCIL_ATTACHMENT and doesn't * need an extension to handle _FLAG_DEPTH_STENCIL */ #ifndef HAVE_COGL_WEBGL (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) || _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) && #endif try_creating_fbo (ctx, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &fb->config, flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL, gl_framebuffer)) || try_creating_fbo (ctx, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &fb->config, flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH | COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, gl_framebuffer) || try_creating_fbo (ctx, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &fb->config, flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, gl_framebuffer) || try_creating_fbo (ctx, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &fb->config, flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH, gl_framebuffer) || try_creating_fbo (ctx, offscreen->texture, offscreen->texture_level, level_width, level_height, offscreen->depth_texture, &fb->config, flags = 0, gl_framebuffer)) { fb->samples_per_pixel = gl_framebuffer->samples_per_pixel; if (!offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL) { /* Record that the last set of flags succeeded so that we can try that set first next time */ ctx->last_offscreen_allocate_flags = flags; ctx->have_last_offscreen_allocate_flags = TRUE; } /* Save the flags we managed to successfully allocate the * renderbuffers with in case we need to make renderbuffers for a * GLES2 context later */ offscreen->allocation_flags = flags; return TRUE; } else { _cogl_set_error (error, COGL_FRAMEBUFFER_ERROR, COGL_FRAMEBUFFER_ERROR_ALLOCATE, "Failed to create an OpenGL framebuffer object"); return FALSE; } } void _cogl_offscreen_gl_free (CoglOffscreen *offscreen) { CoglContext *ctx = COGL_FRAMEBUFFER (offscreen)->context; delete_renderbuffers (ctx, offscreen->gl_framebuffer.renderbuffers); GE (ctx, glDeleteFramebuffers (1, &offscreen->gl_framebuffer.fbo_handle)); } void _cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha) { CoglContext *ctx = framebuffer->context; GLbitfield gl_buffers = 0; if (buffers & COGL_BUFFER_BIT_COLOR) { GE( ctx, glClearColor (red, green, blue, alpha) ); gl_buffers |= GL_COLOR_BUFFER_BIT; if (ctx->current_gl_color_mask != framebuffer->color_mask) { CoglColorMask color_mask = framebuffer->color_mask; GE( ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED), !!(color_mask & COGL_COLOR_MASK_GREEN), !!(color_mask & COGL_COLOR_MASK_BLUE), !!(color_mask & COGL_COLOR_MASK_ALPHA))); ctx->current_gl_color_mask = color_mask; /* Make sure the ColorMask is updated when the next primitive is drawn */ ctx->current_pipeline_changes_since_flush |= COGL_PIPELINE_STATE_LOGIC_OPS; ctx->current_pipeline_age--; } } if (buffers & COGL_BUFFER_BIT_DEPTH) { gl_buffers |= GL_DEPTH_BUFFER_BIT; if (ctx->depth_writing_enabled_cache != framebuffer->depth_writing_enabled) { GE( ctx, glDepthMask (framebuffer->depth_writing_enabled)); ctx->depth_writing_enabled_cache = framebuffer->depth_writing_enabled; /* Make sure the DepthMask is updated when the next primitive is drawn */ ctx->current_pipeline_changes_since_flush |= COGL_PIPELINE_STATE_DEPTH; ctx->current_pipeline_age--; } } if (buffers & COGL_BUFFER_BIT_STENCIL) gl_buffers |= GL_STENCIL_BUFFER_BIT; GE (ctx, glClear (gl_buffers)); } static inline void _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; if (G_LIKELY (!framebuffer->dirty_bitmasks)) return; cogl_framebuffer_allocate (framebuffer, NULL); _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_BIND); #ifdef HAVE_COGL_GL if ((ctx->driver == COGL_DRIVER_GL3 && framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) || (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS) && framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)) { gboolean is_offscreen = framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN; const struct { GLenum attachment, pname; size_t offset; } params[] = { { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, offsetof (CoglFramebufferBits, red) }, { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, offsetof (CoglFramebufferBits, green) }, { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, offsetof (CoglFramebufferBits, blue) }, { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, offsetof (CoglFramebufferBits, alpha) }, { is_offscreen ? GL_DEPTH_ATTACHMENT : GL_DEPTH, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, offsetof (CoglFramebufferBits, depth) }, { is_offscreen ? GL_STENCIL_ATTACHMENT : GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, offsetof (CoglFramebufferBits, stencil) }, }; int i; for (i = 0; i < G_N_ELEMENTS (params); i++) { int *value = (int *) ((uint8_t *) &framebuffer->bits + params[i].offset); GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, params[i].attachment, params[i].pname, value) ); } } else #endif /* HAVE_COGL_GL */ { GE( ctx, glGetIntegerv (GL_RED_BITS, &framebuffer->bits.red) ); GE( ctx, glGetIntegerv (GL_GREEN_BITS, &framebuffer->bits.green) ); GE( ctx, glGetIntegerv (GL_BLUE_BITS, &framebuffer->bits.blue) ); GE( ctx, glGetIntegerv (GL_ALPHA_BITS, &framebuffer->bits.alpha) ); GE( ctx, glGetIntegerv (GL_DEPTH_BITS, &framebuffer->bits.depth) ); GE( ctx, glGetIntegerv (GL_STENCIL_BITS, &framebuffer->bits.stencil) ); } /* If we don't have alpha textures then the alpha bits are actually * stored in the red component */ if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN && framebuffer->internal_format == COGL_PIXEL_FORMAT_A_8) { framebuffer->bits.alpha = framebuffer->bits.red; framebuffer->bits.red = 0; } COGL_NOTE (OFFSCREEN, "RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d", framebuffer, framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN ? "offscreen" : "onscreen", framebuffer->bits.red, framebuffer->bits.blue, framebuffer->bits.green, framebuffer->bits.alpha, framebuffer->bits.depth, framebuffer->bits.stencil); framebuffer->dirty_bitmasks = FALSE; } void _cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer, CoglFramebufferBits *bits) { _cogl_framebuffer_init_bits (framebuffer); /* TODO: cache these in some driver specific location not * directly as part of CoglFramebuffer. */ *bits = framebuffer->bits; } void _cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer) { GE (framebuffer->context, glFinish ()); } void _cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer, unsigned long buffers) { CoglContext *ctx = framebuffer->context; if (ctx->glDiscardFramebuffer) { GLenum attachments[3]; int i = 0; if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) { if (buffers & COGL_BUFFER_BIT_COLOR) attachments[i++] = GL_COLOR; if (buffers & COGL_BUFFER_BIT_DEPTH) attachments[i++] = GL_DEPTH; if (buffers & COGL_BUFFER_BIT_STENCIL) attachments[i++] = GL_STENCIL; } else { if (buffers & COGL_BUFFER_BIT_COLOR) attachments[i++] = GL_COLOR_ATTACHMENT0; if (buffers & COGL_BUFFER_BIT_DEPTH) attachments[i++] = GL_DEPTH_ATTACHMENT; if (buffers & COGL_BUFFER_BIT_STENCIL) attachments[i++] = GL_STENCIL_ATTACHMENT; } _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_BIND); GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments)); } } void _cogl_framebuffer_gl_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags) { _cogl_flush_attributes_state (framebuffer, pipeline, flags, attributes, n_attributes); GE (framebuffer->context, glDrawArrays ((GLenum)mode, first_vertex, n_vertices)); } static size_t sizeof_index_type (CoglIndicesType type) { switch (type) { case COGL_INDICES_TYPE_UNSIGNED_BYTE: return 1; case COGL_INDICES_TYPE_UNSIGNED_SHORT: return 2; case COGL_INDICES_TYPE_UNSIGNED_INT: return 4; } g_return_val_if_reached (0); } void _cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags) { CoglBuffer *buffer; uint8_t *base; size_t buffer_offset; size_t index_size; GLenum indices_gl_type = 0; _cogl_flush_attributes_state (framebuffer, pipeline, flags, attributes, n_attributes); buffer = COGL_BUFFER (cogl_indices_get_buffer (indices)); /* Note: we don't try and catch errors with binding the index buffer * here since OOM errors at this point indicate that nothing has yet * been uploaded to the indices buffer which we consider to be a * programmer error. */ base = _cogl_buffer_gl_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER, NULL); buffer_offset = cogl_indices_get_offset (indices); index_size = sizeof_index_type (cogl_indices_get_type (indices)); switch (cogl_indices_get_type (indices)) { case COGL_INDICES_TYPE_UNSIGNED_BYTE: indices_gl_type = GL_UNSIGNED_BYTE; break; case COGL_INDICES_TYPE_UNSIGNED_SHORT: indices_gl_type = GL_UNSIGNED_SHORT; break; case COGL_INDICES_TYPE_UNSIGNED_INT: indices_gl_type = GL_UNSIGNED_INT; break; } GE (framebuffer->context, glDrawElements ((GLenum)mode, n_vertices, indices_gl_type, base + buffer_offset + index_size * first_vertex)); _cogl_buffer_gl_unbind (buffer); } static CoglBool mesa_46631_slow_read_pixels_workaround (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error) { CoglContext *ctx; CoglPixelFormat format; CoglBitmap *pbo; int width; int height; CoglBool res; uint8_t *dst; const uint8_t *src; ctx = cogl_framebuffer_get_context (framebuffer); width = cogl_bitmap_get_width (bitmap); height = cogl_bitmap_get_height (bitmap); format = cogl_bitmap_get_format (bitmap); pbo = cogl_bitmap_new_with_size (ctx, width, height, format); /* Read into the pbo. We need to disable the flipping because the blit fast path in the driver does not work with GL_PACK_INVERT_MESA is set */ res = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer, x, y, source | COGL_READ_PIXELS_NO_FLIP, pbo, error); if (!res) { cogl_object_unref (pbo); return FALSE; } /* Copy the pixels back into application's buffer */ dst = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, error); if (!dst) { cogl_object_unref (pbo); return FALSE; } src = _cogl_bitmap_map (pbo, COGL_BUFFER_ACCESS_READ, 0, /* hints */ error); if (src) { int src_rowstride = cogl_bitmap_get_rowstride (pbo); int dst_rowstride = cogl_bitmap_get_rowstride (bitmap); int to_copy = _cogl_pixel_format_get_bytes_per_pixel (format) * width; int y; /* If the framebuffer is onscreen we need to flip the data while copying */ if (!cogl_is_offscreen (framebuffer)) { src += src_rowstride * (height - 1); src_rowstride = -src_rowstride; } for (y = 0; y < height; y++) { memcpy (dst, src, to_copy); dst += dst_rowstride; src += src_rowstride; } _cogl_bitmap_unmap (pbo); } else res = FALSE; _cogl_bitmap_unmap (bitmap); cogl_object_unref (pbo); return res; } CoglBool _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error) { CoglContext *ctx = framebuffer->context; int framebuffer_height = cogl_framebuffer_get_height (framebuffer); int width = cogl_bitmap_get_width (bitmap); int height = cogl_bitmap_get_height (bitmap); CoglPixelFormat format = cogl_bitmap_get_format (bitmap); CoglPixelFormat required_format; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; CoglBool pack_invert_set; int status = FALSE; /* Workaround for cases where its faster to read into a temporary * PBO. This is only worth doing if: * * • The GPU is an Intel GPU. In that case there is a known * fast-path when reading into a PBO that will use the blitter * instead of the Mesa fallback code. The driver bug will only be * set if this is the case. * • We're not already reading into a PBO. * • The target format is BGRA. The fast-path blit does not get hit * otherwise. * • The size of the data is not trivially small. This isn't a * requirement to hit the fast-path blit but intuitively it feels * like if the amount of data is too small then the cost of * allocating a PBO will outweigh the cost of temporarily * converting the data to floats. */ if ((ctx->gpu.driver_bugs & COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS) && (width > 8 || height > 8) && (format & ~COGL_PREMULT_BIT) == COGL_PIXEL_FORMAT_BGRA_8888 && cogl_bitmap_get_buffer (bitmap) == NULL) { CoglError *ignore_error = NULL; if (mesa_46631_slow_read_pixels_workaround (framebuffer, x, y, source, bitmap, &ignore_error)) return TRUE; else cogl_error_free (ignore_error); } _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_BIND); /* The y co-ordinate should be given in OpenGL's coordinate system * so 0 is the bottom row * * NB: all offscreen rendering is done upside down so no conversion * is necissary in this case. */ if (!cogl_is_offscreen (framebuffer)) y = framebuffer_height - y - height; required_format = ctx->driver_vtable->pixel_format_to_gl_with_target (ctx, framebuffer->internal_format, format, &gl_intformat, &gl_format, &gl_type); /* NB: All offscreen rendering is done upside down so there is no need * to flip in this case... */ if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) && (source & COGL_READ_PIXELS_NO_FLIP) == 0 && !cogl_is_offscreen (framebuffer)) { GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE)); pack_invert_set = TRUE; } else pack_invert_set = FALSE; /* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an implementation specific format under GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and GL_IMPLEMENTATION_COLOR_READ_TYPE_OES is supported. We could try to be more clever and check if the requested type matches that but we would need some reliable functions to convert from GL types to Cogl types. For now, lets just always read in GL_RGBA/GL_UNSIGNED_BYTE and convert if necessary. We also need to use this intermediate buffer if the rowstride has padding because GLES does not support setting GL_ROW_LENGTH */ if ((!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT) && (gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE || cogl_bitmap_get_rowstride (bitmap) != 4 * width)) || (required_format & ~COGL_PREMULT_BIT) != (format & ~COGL_PREMULT_BIT)) { CoglBitmap *tmp_bmp; CoglPixelFormat read_format; int bpp, rowstride; uint8_t *tmp_data; CoglBool succeeded; if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT)) read_format = required_format; else { read_format = COGL_PIXEL_FORMAT_RGBA_8888; gl_format = GL_RGBA; gl_type = GL_UNSIGNED_BYTE; } if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (read_format)) read_format = ((read_format & ~COGL_PREMULT_BIT) | (framebuffer->internal_format & COGL_PREMULT_BIT)); tmp_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, width, height, read_format, error); if (!tmp_bmp) goto EXIT; bpp = _cogl_pixel_format_get_bytes_per_pixel (read_format); rowstride = cogl_bitmap_get_rowstride (tmp_bmp); ctx->texture_driver->prep_gl_for_pixels_download (ctx, rowstride, width, bpp); /* Note: we don't worry about catching errors here since we know * we won't be lazily allocating storage for this buffer so it * won't fail due to lack of memory. */ tmp_data = _cogl_bitmap_gl_bind (tmp_bmp, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, NULL); GE( ctx, glReadPixels (x, y, width, height, gl_format, gl_type, tmp_data) ); _cogl_bitmap_gl_unbind (tmp_bmp); succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap, error); cogl_object_unref (tmp_bmp); if (!succeeded) goto EXIT; } else { CoglBitmap *shared_bmp; CoglPixelFormat bmp_format; int bpp, rowstride; CoglBool succeeded = FALSE; uint8_t *pixels; CoglError *internal_error = NULL; rowstride = cogl_bitmap_get_rowstride (bitmap); /* We match the premultiplied state of the target buffer to the * premultiplied state of the framebuffer so that it will get * converted to the right format below */ if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format)) bmp_format = ((format & ~COGL_PREMULT_BIT) | (framebuffer->internal_format & COGL_PREMULT_BIT)); else bmp_format = format; if (bmp_format != format) shared_bmp = _cogl_bitmap_new_shared (bitmap, bmp_format, width, height, rowstride); else shared_bmp = cogl_object_ref (bitmap); bpp = _cogl_pixel_format_get_bytes_per_pixel (bmp_format); ctx->texture_driver->prep_gl_for_pixels_download (ctx, rowstride, width, bpp); pixels = _cogl_bitmap_gl_bind (shared_bmp, COGL_BUFFER_ACCESS_WRITE, 0, /* hints */ &internal_error); /* NB: _cogl_bitmap_gl_bind() can return NULL in sucessfull * cases so we have to explicitly check the cogl error pointer * to know if there was a problem */ if (internal_error) { cogl_object_unref (shared_bmp); _cogl_propagate_error (error, internal_error); goto EXIT; } GE( ctx, glReadPixels (x, y, width, height, gl_format, gl_type, pixels) ); _cogl_bitmap_gl_unbind (shared_bmp); /* Convert to the premult format specified by the caller in-place. This will do nothing if the premult status is already correct. */ if (_cogl_bitmap_convert_premult_status (shared_bmp, format, error)) succeeded = TRUE; cogl_object_unref (shared_bmp); if (!succeeded) goto EXIT; } /* NB: All offscreen rendering is done upside down so there is no need * to flip in this case... */ if (!cogl_is_offscreen (framebuffer) && (source & COGL_READ_PIXELS_NO_FLIP) == 0 && !pack_invert_set) { uint8_t *temprow; int rowstride; uint8_t *pixels; rowstride = cogl_bitmap_get_rowstride (bitmap); pixels = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE, 0, /* hints */ error); if (pixels == NULL) goto EXIT; temprow = g_alloca (rowstride * sizeof (uint8_t)); /* vertically flip the buffer in-place */ for (y = 0; y < height / 2; y++) { if (y != height - y - 1) /* skip center row */ { memcpy (temprow, pixels + y * rowstride, rowstride); memcpy (pixels + y * rowstride, pixels + (height - y - 1) * rowstride, rowstride); memcpy (pixels + (height - y - 1) * rowstride, temprow, rowstride); } } _cogl_bitmap_unmap (bitmap); } status = TRUE; EXIT: /* Currently this function owns the pack_invert state and we don't want this * to interfere with other Cogl components so all other code can assume that * we leave the pack_invert state off. */ if (pack_invert_set) GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE)); return status; } muffin-5.2.1/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h0000664000175000017500000000760014211404421024333 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_FRAMEBUFFER_GL_PRIVATE_H__ #define __COGL_FRAMEBUFFER_GL_PRIVATE_H__ CoglBool _cogl_offscreen_gl_allocate (CoglOffscreen *offscreen, CoglError **error); void _cogl_offscreen_gl_free (CoglOffscreen *offscreen); void _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state); void _cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha); void _cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer, CoglFramebufferBits *bits); void _cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer); void _cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer, unsigned long buffers); void _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target); void _cogl_framebuffer_gl_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); void _cogl_framebuffer_gl_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); CoglBool _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error); #endif /* __COGL_FRAMEBUFFER_GL_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-progend-fixed.c0000664000175000017500000000720214211404421024326 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-pipeline-private.h" #include "cogl-pipeline-state-private.h" #ifdef COGL_PIPELINE_PROGEND_FIXED #include "cogl-context.h" #include "cogl-context-private.h" #include "cogl-framebuffer-private.h" static CoglBool _cogl_pipeline_progend_fixed_start (CoglPipeline *pipeline) { _COGL_GET_CONTEXT (ctx, FALSE); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED))) return FALSE; if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED)) return FALSE; /* Vertex snippets are only supported in the GLSL fragend */ if (_cogl_pipeline_has_vertex_snippets (pipeline)) return FALSE; /* Fragment snippets are only supported in the GLSL fragend */ if (_cogl_pipeline_has_fragment_snippets (pipeline)) return FALSE; /* If there is a user program then the appropriate backend for that * language should handle it. */ if (cogl_pipeline_get_user_program (pipeline)) return FALSE; /* The fixed progend can't handle the per-vertex point size * attribute */ if (cogl_pipeline_get_per_vertex_point_size (pipeline)) return FALSE; return TRUE; } static void _cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline, CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; if (ctx->current_projection_entry) _cogl_matrix_entry_flush_to_gl_builtins (ctx, ctx->current_projection_entry, COGL_MATRIX_PROJECTION, framebuffer, FALSE /* enable flip */); if (ctx->current_modelview_entry) _cogl_matrix_entry_flush_to_gl_builtins (ctx, ctx->current_modelview_entry, COGL_MATRIX_MODELVIEW, framebuffer, FALSE /* enable flip */); } const CoglPipelineProgend _cogl_pipeline_fixed_progend = { COGL_PIPELINE_VERTEND_FIXED, COGL_PIPELINE_FRAGEND_FIXED, _cogl_pipeline_progend_fixed_start, NULL, /* end */ NULL, /* pre_change_notify */ NULL, /* layer_pre_change_notify */ _cogl_pipeline_progend_fixed_pre_paint }; #endif /* COGL_PIPELINE_PROGEND_FIXED */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-progend-fixed-private.h0000664000175000017500000000273714211404421026013 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifndef __COGL_PIPELINE_PROGEND_FIXED_PRIVATE_H #define __COGL_PIPELINE_PROGEND_FIXED_PRIVATE_H #include "cogl-pipeline-private.h" extern const CoglPipelineProgend _cogl_pipeline_fixed_progend; #endif /* __COGL_PIPELINE_PROGEND_FIXED_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-attribute-gl-private.h0000664000175000017500000000357014211404421024054 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_ATTRIBUTE_GL_PRIVATE_H_ #define _COGL_ATTRIBUTE_GL_PRIVATE_H_ #include "cogl-types.h" #include "cogl-framebuffer.h" #include "cogl-attribute.h" #include "cogl-attribute-private.h" void _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglFlushLayerState *layers_state, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes); void _cogl_gl_disable_all_attributes (CoglContext *ctx); #endif /* _COGL_ATTRIBUTE_GL_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-texture-2d-gl.c0000664000175000017500000007476514211404421022415 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2011,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts * Robert Bragg */ #include "cogl-config.h" #include #include "cogl-private.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-gl.h" #include "cogl-texture-2d-gl-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-gl-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" #include "cogl-util-gl-private.h" #if defined (COGL_HAS_EGL_SUPPORT) /* We need this define from GLES2, but can't include the header as its type definitions may conflict with the GL ones */ #ifndef GL_OES_EGL_image_external #define GL_OES_EGL_image_external 1 #define GL_TEXTURE_EXTERNAL_OES 0x8D65 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 #define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 #define GL_SAMPLER_EXTERNAL_OES 0x8D66 #endif /* GL_OES_EGL_image_external */ #endif /* defined (COGL_HAS_EGL_SUPPORT) */ void _cogl_texture_2d_gl_free (CoglTexture2D *tex_2d) { if (!tex_2d->is_foreign && tex_2d->gl_texture) _cogl_delete_gl_texture (tex_2d->gl_texture); #if defined (COGL_HAS_EGL_SUPPORT) g_clear_pointer (&tex_2d->egl_image_external.user_data, tex_2d->egl_image_external.destroy); #endif } CoglBool _cogl_texture_2d_gl_can_create (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format) { GLenum gl_intformat; GLenum gl_format; GLenum gl_type; /* If NPOT textures aren't supported then the size must be a power of two */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && (!_cogl_util_is_pot (width) || !_cogl_util_is_pot (height))) return FALSE; ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, &gl_format, &gl_type); /* Check that the driver can create a texture with that size */ if (!ctx->texture_driver->size_supported (ctx, GL_TEXTURE_2D, gl_intformat, gl_format, gl_type, width, height)) return FALSE; return TRUE; } void _cogl_texture_2d_gl_init (CoglTexture2D *tex_2d) { tex_2d->gl_texture = 0; /* We default to GL_LINEAR for both filters */ tex_2d->gl_legacy_texobj_min_filter = GL_LINEAR; tex_2d->gl_legacy_texobj_mag_filter = GL_LINEAR; /* Wrap mode not yet set */ tex_2d->gl_legacy_texobj_wrap_mode_s = GL_FALSE; tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE; tex_2d->egl_image_external.user_data = NULL; tex_2d->egl_image_external.destroy = NULL; } static CoglBool allocate_with_size (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglPixelFormat internal_format; int width = loader->src.sized.width; int height = loader->src.sized.height; CoglContext *ctx = tex->context; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; GLenum gl_texture; internal_format = _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); if (!_cogl_texture_2d_gl_can_create (ctx, width, height, internal_format)) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE, "Failed to create texture 2d due to size/format" " constraints"); return FALSE; } ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, &gl_format, &gl_type); gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); tex_2d->gl_internal_format = gl_intformat; _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, gl_texture, tex_2d->is_foreign); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat, width, height, 0, gl_format, gl_type, NULL); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { GE( ctx, glDeleteTextures (1, &gl_texture) ); return FALSE; } tex_2d->gl_texture = gl_texture; tex_2d->gl_internal_format = gl_intformat; tex_2d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, width, height); return TRUE; } static CoglBool allocate_from_bitmap (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglBitmap *bmp = loader->src.bitmap.bitmap; CoglContext *ctx = _cogl_bitmap_get_context (bmp); CoglPixelFormat internal_format; int width = cogl_bitmap_get_width (bmp); int height = cogl_bitmap_get_height (bmp); CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place; CoglBitmap *upload_bmp; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; internal_format = _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp)); if (!_cogl_texture_2d_gl_can_create (ctx, width, height, internal_format)) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE, "Failed to create texture 2d due to size/format" " constraints"); return FALSE; } upload_bmp = _cogl_bitmap_convert_for_upload (bmp, internal_format, can_convert_in_place, error); if (upload_bmp == NULL) return FALSE; ctx->driver_vtable->pixel_format_to_gl (ctx, cogl_bitmap_get_format (upload_bmp), NULL, /* internal format */ &gl_format, &gl_type); ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, NULL, NULL); /* Keep a copy of the first pixel so that if glGenerateMipmap isn't supported we can fallback to using GL_GENERATE_MIPMAP */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) { CoglError *ignore = NULL; uint8_t *data = _cogl_bitmap_map (upload_bmp, COGL_BUFFER_ACCESS_READ, 0, &ignore); CoglPixelFormat format = cogl_bitmap_get_format (upload_bmp); tex_2d->first_pixel.gl_format = gl_format; tex_2d->first_pixel.gl_type = gl_type; if (data) { memcpy (tex_2d->first_pixel.data, data, _cogl_pixel_format_get_bytes_per_pixel (format)); _cogl_bitmap_unmap (upload_bmp); } else { g_warning ("Failed to read first pixel of bitmap for " "glGenerateMipmap fallback"); cogl_error_free (ignore); memset (tex_2d->first_pixel.data, 0, _cogl_pixel_format_get_bytes_per_pixel (format)); } } tex_2d->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); if (!ctx->texture_driver->upload_to_gl (ctx, GL_TEXTURE_2D, tex_2d->gl_texture, FALSE, upload_bmp, gl_intformat, gl_format, gl_type, error)) { cogl_object_unref (upload_bmp); return FALSE; } tex_2d->gl_internal_format = gl_intformat; cogl_object_unref (upload_bmp); tex_2d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, width, height); return TRUE; } #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) static CoglBool allocate_from_egl_image (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; CoglPixelFormat internal_format = loader->src.egl_image.format; tex_2d->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, FALSE); _cogl_gl_util_clear_gl_errors (ctx); ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, loader->src.egl_image.image); if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_BAD_PARAMETER, "Could not create a CoglTexture2D from a given " "EGLImage"); GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) ); return FALSE; } tex_2d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, loader->src.egl_image.width, loader->src.egl_image.height); return TRUE; } #endif static CoglBool allocate_from_gl_foreign (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; CoglPixelFormat format = loader->src.gl_foreign.format; GLint gl_compressed = GL_FALSE; GLenum gl_int_format = 0; if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Foreign GL_TEXTURE_2D textures are not " "supported by your system"); return FALSE; } /* Make sure binding succeeds */ _cogl_gl_util_clear_gl_errors (ctx); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, loader->src.gl_foreign.gl_handle, TRUE); if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Failed to bind foreign GL_TEXTURE_2D texture"); return FALSE; } /* Obtain texture parameters (only level 0 we are interested in) */ #ifdef HAVE_COGL_GL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS)) { GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &gl_compressed) ); { GLint val; GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &val) ); gl_int_format = val; } /* If we can query GL for the actual pixel format then we'll ignore the passed in format and use that. */ if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx, gl_int_format, &format)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Unsupported internal format for foreign texture"); return FALSE; } } else #endif { /* Otherwise we'll assume we can derive the GL format from the passed in format */ ctx->driver_vtable->pixel_format_to_gl (ctx, format, &gl_int_format, NULL, NULL); } /* Compressed texture images not supported */ if (gl_compressed == GL_TRUE) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Compressed foreign textures aren't currently supported"); return FALSE; } /* Note: previously this code would query the texture object for whether it has GL_GENERATE_MIPMAP enabled to determine whether to auto-generate the mipmap. This doesn't make much sense any more since Cogl switch to using glGenerateMipmap. Ideally I think cogl_texture_2d_gl_new_from_foreign should take a flags parameter so that the application can decide whether it wants auto-mipmapping. To be compatible with existing code, Cogl now disables its own auto-mipmapping but leaves the value of GL_GENERATE_MIPMAP alone so that it would still work but without the dirtiness tracking that Cogl would do. */ _cogl_texture_2d_set_auto_mipmap (COGL_TEXTURE (tex_2d), FALSE); /* Setup bitmap info */ tex_2d->is_foreign = TRUE; tex_2d->mipmaps_dirty = TRUE; tex_2d->gl_texture = loader->src.gl_foreign.gl_handle; tex_2d->gl_internal_format = gl_int_format; /* Unknown filter */ tex_2d->gl_legacy_texobj_min_filter = GL_FALSE; tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE; tex_2d->internal_format = format; _cogl_texture_set_allocated (tex, format, loader->src.gl_foreign.width, loader->src.gl_foreign.height); return TRUE; } #if defined (COGL_HAS_EGL_SUPPORT) static CoglBool allocate_custom_egl_image_external (CoglTexture2D *tex_2d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; CoglPixelFormat internal_format = loader->src.egl_image_external.format; _cogl_gl_util_clear_gl_errors (ctx); GE (ctx, glActiveTexture (GL_TEXTURE0)); GE (ctx, glGenTextures (1, &tex_2d->gl_texture)); GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, tex_2d->gl_texture)); if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_BAD_PARAMETER, "Could not create a CoglTexture2D from a given " "EGLImage"); GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) ); return FALSE; } GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); if (!loader->src.egl_image_external.alloc (tex_2d, tex_2d->egl_image_external.user_data, error)) { GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0)); GE (ctx, glDeleteTextures (1, &tex_2d->gl_texture)); return FALSE; } GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0)); tex_2d->internal_format = internal_format; tex_2d->gl_target = GL_TEXTURE_EXTERNAL_OES; return TRUE; } CoglTexture2D * cogl_texture_2d_new_from_egl_image_external (CoglContext *ctx, int width, int height, CoglTexture2DEGLImageExternalAlloc alloc, gpointer user_data, GDestroyNotify destroy, CoglError **error) { CoglTextureLoader *loader; CoglTexture2D *tex_2d; CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY; _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & COGL_RENDERER_CONSTRAINT_USES_EGL, NULL); _COGL_RETURN_VAL_IF_FAIL (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL), NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE_EXTERNAL; loader->src.egl_image_external.width = width; loader->src.egl_image_external.height = height; loader->src.egl_image_external.alloc = alloc; loader->src.egl_image_external.format = internal_format; tex_2d = _cogl_texture_2d_create_base (ctx, width, height, internal_format, loader); tex_2d->egl_image_external.user_data = user_data; tex_2d->egl_image_external.destroy = destroy; return tex_2d; } #endif /* defined (COGL_HAS_EGL_SUPPORT) */ CoglBool _cogl_texture_2d_gl_allocate (CoglTexture *tex, CoglError **error) { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglTextureLoader *loader = tex->loader; _COGL_RETURN_VAL_IF_FAIL (loader, FALSE); switch (loader->src_type) { case COGL_TEXTURE_SOURCE_TYPE_SIZED: return allocate_with_size (tex_2d, loader, error); case COGL_TEXTURE_SOURCE_TYPE_BITMAP: return allocate_from_bitmap (tex_2d, loader, error); case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE: #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) return allocate_from_egl_image (tex_2d, loader, error); #else g_return_val_if_reached (FALSE); #endif case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN: return allocate_from_gl_foreign (tex_2d, loader, error); case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE_EXTERNAL: return allocate_custom_egl_image_external (tex_2d, loader, error); } g_return_val_if_reached (FALSE); } void _cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglContext *ctx = tex->context; if (min_filter == tex_2d->gl_legacy_texobj_min_filter && mag_filter == tex_2d->gl_legacy_texobj_mag_filter) return; /* Store new values */ tex_2d->gl_legacy_texobj_min_filter = min_filter; tex_2d->gl_legacy_texobj_mag_filter = mag_filter; /* Apply new filters to the texture */ _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, tex_2d->is_foreign); GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) ); GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) ); } void _cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); CoglContext *ctx = tex->context; /* Only set the wrap mode if it's different from the current value to avoid too many GL calls. Texture 2D doesn't make use of the r coordinate so we can ignore its wrap mode */ if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s || tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t) { _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, tex_2d->is_foreign); GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode_s) ); GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode_t) ); tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s; tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t; } } CoglTexture2D * cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx, unsigned int gl_handle, int width, int height, CoglPixelFormat format) { CoglTextureLoader *loader; /* NOTE: width, height and internal format are not queriable * in GLES, hence such a function prototype. */ /* Note: We always trust the given width and height without querying * the texture object because the user may be creating a Cogl * texture for a texture_from_pixmap object where glTexImage2D may * not have been called and the texture_from_pixmap spec doesn't * clarify that it is reliable to query back the size from OpenGL. */ /* Assert it is a valid GL texture object */ _COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), FALSE); /* Validate width and height */ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN; loader->src.gl_foreign.gl_handle = gl_handle; loader->src.gl_foreign.width = width; loader->src.gl_foreign.height = height; loader->src.gl_foreign.format = format; return _cogl_texture_2d_create_base (ctx, width, height, format, loader); } void _cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglFramebuffer *src_fb, int dst_x, int dst_y, int level) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; /* Make sure the current framebuffers are bound, though we don't need to * flush the clip state here since we aren't going to draw to the * framebuffer. */ _cogl_framebuffer_flush_state (ctx->current_draw_buffer, src_fb, COGL_FRAMEBUFFER_STATE_ALL & ~COGL_FRAMEBUFFER_STATE_CLIP); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, tex_2d->is_foreign); ctx->glCopyTexSubImage2D (GL_TEXTURE_2D, 0, /* level */ dst_x, dst_y, src_x, src_y, width, height); } unsigned int _cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d) { return tex_2d->gl_texture; } void _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d) { CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; /* glGenerateMipmap is defined in the FBO extension. If it's not available we'll fallback to temporarily enabling GL_GENERATE_MIPMAP and reuploading the first pixel */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) _cogl_texture_gl_generate_mipmaps (COGL_TEXTURE (tex_2d)); #if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL) else { _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, tex_2d->is_foreign); GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE) ); GE( ctx, glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 1, 1, tex_2d->first_pixel.gl_format, tex_2d->first_pixel.gl_type, tex_2d->first_pixel.data) ); GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE) ); } #endif } CoglBool _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglBitmap *bmp, int dst_x, int dst_y, int level, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; CoglBitmap *upload_bmp; CoglPixelFormat upload_format; GLenum gl_format; GLenum gl_type; CoglBool status = TRUE; upload_bmp = _cogl_bitmap_convert_for_upload (bmp, _cogl_texture_get_format (tex), FALSE, /* can't convert in place */ error); if (upload_bmp == NULL) return FALSE; upload_format = cogl_bitmap_get_format (upload_bmp); ctx->driver_vtable->pixel_format_to_gl_with_target (ctx, upload_format, _cogl_texture_get_format (tex), NULL, /* internal gl format */ &gl_format, &gl_type); /* If this touches the first pixel then we'll update our copy */ if (dst_x == 0 && dst_y == 0 && !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) { CoglError *ignore = NULL; uint8_t *data = _cogl_bitmap_map (upload_bmp, COGL_BUFFER_ACCESS_READ, 0, &ignore); CoglPixelFormat bpp = _cogl_pixel_format_get_bytes_per_pixel (upload_format); tex_2d->first_pixel.gl_format = gl_format; tex_2d->first_pixel.gl_type = gl_type; if (data) { memcpy (tex_2d->first_pixel.data, (data + cogl_bitmap_get_rowstride (upload_bmp) * src_y + bpp * src_x), bpp); _cogl_bitmap_unmap (bmp); } else { g_warning ("Failed to read first bitmap pixel for " "glGenerateMipmap fallback"); cogl_error_free (ignore); memset (tex_2d->first_pixel.data, 0, bpp); } } status = ctx->texture_driver->upload_subregion_to_gl (ctx, tex, FALSE, src_x, src_y, dst_x, dst_y, width, height, level, upload_bmp, gl_format, gl_type, error); cogl_object_unref (upload_bmp); _cogl_texture_gl_maybe_update_max_level (tex, level); return status; } void _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, CoglPixelFormat format, int rowstride, uint8_t *data) { CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; int bpp; int width = COGL_TEXTURE (tex_2d)->width; GLenum gl_format; GLenum gl_type; bpp = _cogl_pixel_format_get_bytes_per_pixel (format); ctx->driver_vtable->pixel_format_to_gl (ctx, format, NULL, /* internal format */ &gl_format, &gl_type); ctx->texture_driver->prep_gl_for_pixels_download (ctx, rowstride, width, bpp); _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, tex_2d->is_foreign); ctx->texture_driver->gl_get_tex_image (ctx, GL_TEXTURE_2D, gl_format, gl_type, data); } muffin-5.2.1/cogl/cogl/driver/gl/cogl-clip-stack-gl.c0000664000175000017500000005454414211404421022435 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010,2011,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-primitives-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-clip-stack-gl-private.h" #include "cogl-primitive-private.h" #ifndef GL_CLIP_PLANE0 #define GL_CLIP_PLANE0 0x3000 #define GL_CLIP_PLANE1 0x3001 #define GL_CLIP_PLANE2 0x3002 #define GL_CLIP_PLANE3 0x3003 #define GL_CLIP_PLANE4 0x3004 #define GL_CLIP_PLANE5 0x3005 #endif static void project_vertex (const CoglMatrix *modelview_projection, float *vertex) { int i; cogl_matrix_transform_point (modelview_projection, &vertex[0], &vertex[1], &vertex[2], &vertex[3]); /* Convert from homogenized coordinates */ for (i = 0; i < 4; i++) vertex[i] /= vertex[3]; } static void set_clip_plane (CoglFramebuffer *framebuffer, int plane_num, const float *vertex_a, const float *vertex_b) { CoglContext *ctx = framebuffer->context; float planef[4]; double planed[4]; float angle; CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); CoglMatrix inverse_projection; cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection); /* Calculate the angle between the axes and the line crossing the two points */ angle = atan2f (vertex_b[1] - vertex_a[1], vertex_b[0] - vertex_a[0]) * (180.0/G_PI); cogl_matrix_stack_push (modelview_stack); /* Load the inverse of the projection matrix so we can specify the plane * in screen coordinates */ cogl_matrix_stack_set (modelview_stack, &inverse_projection); /* Rotate about point a */ cogl_matrix_stack_translate (modelview_stack, vertex_a[0], vertex_a[1], vertex_a[2]); /* Rotate the plane by the calculated angle so that it will connect the two points */ cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f); cogl_matrix_stack_translate (modelview_stack, -vertex_a[0], -vertex_a[1], -vertex_a[2]); /* Clip planes can only be used when a fixed function backend is in use so we know we can directly push this matrix to the builtin state */ _cogl_matrix_entry_flush_to_gl_builtins (ctx, modelview_stack->last_entry, COGL_MATRIX_MODELVIEW, framebuffer, FALSE /* don't disable flip */); planef[0] = 0; planef[1] = -1.0; planef[2] = 0; planef[3] = vertex_a[1]; switch (ctx->driver) { default: g_assert_not_reached (); break; case COGL_DRIVER_GLES1: GE( ctx, glClipPlanef (plane_num, planef) ); break; case COGL_DRIVER_GL: case COGL_DRIVER_GL3: planed[0] = planef[0]; planed[1] = planef[1]; planed[2] = planef[2]; planed[3] = planef[3]; GE( ctx, glClipPlane (plane_num, planed) ); break; } cogl_matrix_stack_pop (modelview_stack); } static void set_clip_planes (CoglFramebuffer *framebuffer, CoglMatrixEntry *modelview_entry, float x_1, float y_1, float x_2, float y_2) { CoglMatrix modelview_matrix; CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); CoglMatrix projection_matrix; CoglMatrix modelview_projection; float signed_area; float vertex_tl[4] = { x_1, y_1, 0, 1.0 }; float vertex_tr[4] = { x_2, y_1, 0, 1.0 }; float vertex_bl[4] = { x_1, y_2, 0, 1.0 }; float vertex_br[4] = { x_2, y_2, 0, 1.0 }; cogl_matrix_stack_get (projection_stack, &projection_matrix); cogl_matrix_entry_get (modelview_entry, &modelview_matrix); cogl_matrix_multiply (&modelview_projection, &projection_matrix, &modelview_matrix); project_vertex (&modelview_projection, vertex_tl); project_vertex (&modelview_projection, vertex_tr); project_vertex (&modelview_projection, vertex_bl); project_vertex (&modelview_projection, vertex_br); /* Calculate the signed area of the polygon formed by the four vertices so that we can know its orientation */ signed_area = (vertex_tl[0] * (vertex_tr[1] - vertex_bl[1]) + vertex_tr[0] * (vertex_br[1] - vertex_tl[1]) + vertex_br[0] * (vertex_bl[1] - vertex_tr[1]) + vertex_bl[0] * (vertex_tl[1] - vertex_br[1])); /* Set the clip planes to form lines between all of the vertices using the same orientation as we calculated */ if (signed_area > 0.0f) { /* counter-clockwise */ set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_bl); set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_bl, vertex_br); set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_tr); set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_tr, vertex_tl); } else { /* clockwise */ set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_tr); set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_tr, vertex_br); set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_bl); set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_bl, vertex_tl); } } static void add_stencil_clip_rectangle (CoglFramebuffer *framebuffer, CoglMatrixEntry *modelview_entry, float x_1, float y_1, float x_2, float y_2, CoglBool first) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); /* NB: This can be called while flushing the journal so we need * to be very conservative with what state we change. */ _cogl_context_set_current_projection_entry (ctx, projection_stack->last_entry); _cogl_context_set_current_modelview_entry (ctx, modelview_entry); if (first) { GE( ctx, glEnable (GL_STENCIL_TEST) ); /* Initially disallow everything */ GE( ctx, glClearStencil (0) ); GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) ); /* Punch out a hole to allow the rectangle */ GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) ); GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) ); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, x_1, y_1, x_2, y_2); } else { /* Add one to every pixel of the stencil buffer in the rectangle */ GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) ); GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) ); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, x_1, y_1, x_2, y_2); /* Subtract one from all pixels in the stencil buffer so that only pixels where both the original stencil buffer and the rectangle are set will be valid */ GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry); _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, -1.0, -1.0, 1.0, 1.0); } /* Restore the stencil mode */ GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) ); GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); } typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, void *user_data); static void add_stencil_clip_silhouette (CoglFramebuffer *framebuffer, SilhouettePaintCallback silhouette_callback, CoglMatrixEntry *modelview_entry, float bounds_x1, float bounds_y1, float bounds_x2, float bounds_y2, CoglBool merge, CoglBool need_clear, void *user_data) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); /* NB: This can be called while flushing the journal so we need * to be very conservative with what state we change. */ _cogl_context_set_current_projection_entry (ctx, projection_stack->last_entry); _cogl_context_set_current_modelview_entry (ctx, modelview_entry); _cogl_pipeline_flush_gl_state (ctx, ctx->stencil_pipeline, framebuffer, FALSE, FALSE); GE( ctx, glEnable (GL_STENCIL_TEST) ); GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) ); GE( ctx, glDepthMask (FALSE) ); if (merge) { GE (ctx, glStencilMask (2)); GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6)); } else { /* If we're not using the stencil buffer for clipping then we don't need to clear the whole stencil buffer, just the area that will be drawn */ if (need_clear) /* If this is being called from the clip stack code then it will have set up a scissor for the minimum bounding box of all of the clips. That box will likely mean that this _cogl_clear won't need to clear the entire buffer. _cogl_framebuffer_clear_without_flush4f is used instead of cogl_clear because it won't try to flush the journal */ _cogl_framebuffer_clear_without_flush4f (framebuffer, COGL_BUFFER_BIT_STENCIL, 0, 0, 0, 0); else { /* Just clear the bounding box */ GE( ctx, glStencilMask (~(GLuint) 0) ); GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) ); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, bounds_x1, bounds_y1, bounds_x2, bounds_y2); } GE (ctx, glStencilMask (1)); GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3)); } GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT)); silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data); if (merge) { /* Now we have the new stencil buffer in bit 1 and the old stencil buffer in bit 0 so we need to intersect them */ GE (ctx, glStencilMask (3)); GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3)); GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR)); /* Decrement all of the bits twice so that only pixels where the value is 3 will remain */ _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry); _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, -1.0, -1.0, 1.0, 1.0); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, -1.0, -1.0, 1.0, 1.0); } GE (ctx, glStencilMask (~(GLuint) 0)); GE (ctx, glDepthMask (TRUE)); GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE)); GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1)); GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP)); } static void paint_primitive_silhouette (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, void *user_data) { _cogl_primitive_draw (user_data, framebuffer, pipeline, COGL_DRAW_SKIP_JOURNAL_FLUSH | COGL_DRAW_SKIP_PIPELINE_VALIDATION | COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH | COGL_DRAW_SKIP_LEGACY_STATE); } static void add_stencil_clip_primitive (CoglFramebuffer *framebuffer, CoglMatrixEntry *modelview_entry, CoglPrimitive *primitive, float bounds_x1, float bounds_y1, float bounds_x2, float bounds_y2, CoglBool merge, CoglBool need_clear) { add_stencil_clip_silhouette (framebuffer, paint_primitive_silhouette, modelview_entry, bounds_x1, bounds_y1, bounds_x2, bounds_y2, merge, need_clear, primitive); } static void enable_clip_planes (CoglContext *ctx) { GE( ctx, glEnable (GL_CLIP_PLANE0) ); GE( ctx, glEnable (GL_CLIP_PLANE1) ); GE( ctx, glEnable (GL_CLIP_PLANE2) ); GE( ctx, glEnable (GL_CLIP_PLANE3) ); } static void disable_clip_planes (CoglContext *ctx) { GE( ctx, glDisable (GL_CLIP_PLANE3) ); GE( ctx, glDisable (GL_CLIP_PLANE2) ); GE( ctx, glDisable (GL_CLIP_PLANE1) ); GE( ctx, glDisable (GL_CLIP_PLANE0) ); } void _cogl_clip_stack_gl_flush (CoglClipStack *stack, CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; int has_clip_planes; CoglBool using_clip_planes = FALSE; CoglBool using_stencil_buffer = FALSE; int scissor_x0; int scissor_y0; int scissor_x1; int scissor_y1; CoglClipStack *entry; int scissor_y_start; /* If we have already flushed this state then we don't need to do anything */ if (ctx->current_clip_stack_valid) { if (ctx->current_clip_stack == stack && (ctx->needs_viewport_scissor_workaround == FALSE || (framebuffer->viewport_age == framebuffer->viewport_age_for_scissor_workaround && ctx->viewport_scissor_workaround_framebuffer == framebuffer))) return; _cogl_clip_stack_unref (ctx->current_clip_stack); } ctx->current_clip_stack_valid = TRUE; ctx->current_clip_stack = _cogl_clip_stack_ref (stack); has_clip_planes = _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES); if (has_clip_planes) disable_clip_planes (ctx); GE( ctx, glDisable (GL_STENCIL_TEST) ); /* If the stack is empty then there's nothing else to do * * See comment below about ctx->needs_viewport_scissor_workaround */ if (stack == NULL && !ctx->needs_viewport_scissor_workaround) { COGL_NOTE (CLIPPING, "Flushed empty clip stack"); ctx->current_clip_stack_uses_stencil = FALSE; GE (ctx, glDisable (GL_SCISSOR_TEST)); return; } /* Calculate the scissor rect first so that if we eventually have to clear the stencil buffer then the clear will be clipped to the intersection of all of the bounding boxes. This saves having to clear the whole stencil buffer */ _cogl_clip_stack_get_bounds (stack, &scissor_x0, &scissor_y0, &scissor_x1, &scissor_y1); /* XXX: ONGOING BUG: Intel viewport scissor * * Intel gen6 drivers don't correctly handle offset viewports, since * primitives aren't clipped within the bounds of the viewport. To * workaround this we push our own clip for the viewport that will * use scissoring to ensure we clip as expected. * * TODO: file a bug upstream! */ if (ctx->needs_viewport_scissor_workaround) { _cogl_util_scissor_intersect (framebuffer->viewport_x, framebuffer->viewport_y, framebuffer->viewport_x + framebuffer->viewport_width, framebuffer->viewport_y + framebuffer->viewport_height, &scissor_x0, &scissor_y0, &scissor_x1, &scissor_y1); framebuffer->viewport_age_for_scissor_workaround = framebuffer->viewport_age; ctx->viewport_scissor_workaround_framebuffer = framebuffer; } /* Enable scissoring as soon as possible */ if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1) scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0; else { /* We store the entry coordinates in Cogl coordinate space * but OpenGL requires the window origin to be the bottom * left so we may need to convert the incoming coordinates. * * NB: Cogl forces all offscreen rendering to be done upside * down so in this case no conversion is needed. */ if (cogl_is_offscreen (framebuffer)) scissor_y_start = scissor_y0; else { int framebuffer_height = cogl_framebuffer_get_height (framebuffer); scissor_y_start = framebuffer_height - scissor_y1; } } COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)", scissor_x0, scissor_y0, scissor_x1, scissor_y1); GE (ctx, glEnable (GL_SCISSOR_TEST)); GE (ctx, glScissor (scissor_x0, scissor_y_start, scissor_x1 - scissor_x0, scissor_y1 - scissor_y0)); /* Add all of the entries. This will end up adding them in the reverse order that they were specified but as all of the clips are intersecting it should work out the same regardless of the order */ for (entry = stack; entry; entry = entry->parent) { switch (entry->type) { case COGL_CLIP_STACK_PRIMITIVE: { CoglClipStackPrimitive *primitive_entry = (CoglClipStackPrimitive *) entry; COGL_NOTE (CLIPPING, "Adding stencil clip for primitive"); add_stencil_clip_primitive (framebuffer, primitive_entry->matrix_entry, primitive_entry->primitive, primitive_entry->bounds_x1, primitive_entry->bounds_y1, primitive_entry->bounds_x2, primitive_entry->bounds_y2, using_stencil_buffer, TRUE); using_stencil_buffer = TRUE; break; } case COGL_CLIP_STACK_RECT: { CoglClipStackRect *rect = (CoglClipStackRect *) entry; /* We don't need to do anything extra if the clip for this rectangle was entirely described by its scissor bounds */ if (!rect->can_be_scissor) { /* If we support clip planes and we haven't already used them then use that instead */ if (has_clip_planes) { COGL_NOTE (CLIPPING, "Adding clip planes clip for rectangle"); set_clip_planes (framebuffer, rect->matrix_entry, rect->x0, rect->y0, rect->x1, rect->y1); using_clip_planes = TRUE; /* We can't use clip planes a second time */ has_clip_planes = FALSE; } else { COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle"); add_stencil_clip_rectangle (framebuffer, rect->matrix_entry, rect->x0, rect->y0, rect->x1, rect->y1, !using_stencil_buffer); using_stencil_buffer = TRUE; } } break; } case COGL_CLIP_STACK_WINDOW_RECT: break; /* We don't need to do anything for window space rectangles because * their functionality is entirely implemented by the entry bounding * box */ } } /* Enabling clip planes is delayed to now so that they won't affect setting up the stencil buffer */ if (using_clip_planes) enable_clip_planes (ctx); ctx->current_clip_stack_uses_stencil = using_stencil_buffer; } muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h0000664000175000017500000000321714211404421025647 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifndef __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H #define __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H #include "cogl-pipeline-private.h" #include "cogl-attribute-private.h" extern const CoglPipelineProgend _cogl_pipeline_glsl_progend; int _cogl_pipeline_progend_glsl_get_attrib_location (CoglPipeline *pipeline, int name_index); #endif /* __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h0000664000175000017500000000304614211404421025617 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_FRAGEND_GLSL_PRIVATE_H #define __COGL_PIPELINE_FRAGEND_GLSL_PRIVATE_H #include "cogl-pipeline-private.h" extern const CoglPipelineFragend _cogl_pipeline_glsl_fragend; GLuint _cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline); #endif /* __COGL_PIPELINE_FRAGEND_GLSL_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed.c0000664000175000017500000003330614211404421024302 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-state-private.h" #include "cogl-pipeline-opengl-private.h" #ifdef COGL_PIPELINE_FRAGEND_FIXED #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-texture-private.h" #include "cogl-blend-string.h" #include "cogl-profile.h" #include "cogl-program-private.h" #include #include #include #ifndef GL_TEXTURE_RECTANGLE_ARB #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #endif const CoglPipelineFragend _cogl_pipeline_fixed_fragend; static void _cogl_disable_texture_unit (int unit_index) { CoglTextureUnit *unit; _COGL_GET_CONTEXT (ctx, NO_RETVAL); unit = &g_array_index (ctx->texture_units, CoglTextureUnit, unit_index); if (unit->enabled_gl_target) { _cogl_set_active_texture_unit (unit_index); GE (ctx, glDisable (unit->enabled_gl_target)); unit->enabled_gl_target = 0; } } static int get_max_texture_units (void) { _COGL_GET_CONTEXT (ctx, 0); /* This function is called quite often so we cache the value to avoid too many GL calls */ if (ctx->max_texture_units == -1) { ctx->max_texture_units = 1; GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_UNITS, &ctx->max_texture_units)); } return ctx->max_texture_units; } static void _cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED); } static void translate_sources (CoglPipeline *pipeline, int n_sources, CoglPipelineCombineSource *source_in, GLenum *source_out) { int i; /* The texture source numbers specified in the layer combine are the layer numbers so we need to map these to unit indices */ for (i = 0; i < n_sources; i++) switch (source_in[i]) { case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE: source_out[i] = GL_TEXTURE; break; case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT: source_out[i] = GL_CONSTANT; break; case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR: source_out[i] = GL_PRIMARY_COLOR; break; case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS: source_out[i] = GL_PREVIOUS; break; default: { int layer_num = source_in[i] - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0; CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; CoglPipelineLayer *layer = _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags); if (layer == NULL) { static CoglBool warning_seen = FALSE; if (!warning_seen) { g_warning ("The application is trying to use a texture " "combine with a layer number that does not exist"); warning_seen = TRUE; } source_out[i] = GL_PREVIOUS; } else source_out[i] = (_cogl_pipeline_layer_get_unit_index (layer) + GL_TEXTURE0); } } } static CoglBool _cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference) { CoglTextureUnit *unit = _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer)); int unit_index = unit->index; int n_rgb_func_args; int n_alpha_func_args; _COGL_GET_CONTEXT (ctx, FALSE); /* XXX: Beware that since we are changing the active texture unit we * must make sure we don't call into other Cogl components that may * temporarily bind texture objects to query/modify parameters since * they will end up binding texture unit 1. See * _cogl_bind_gl_texture_transient for more details. */ _cogl_set_active_texture_unit (unit_index); if (G_UNLIKELY (unit_index >= get_max_texture_units ())) { _cogl_disable_texture_unit (unit_index); /* TODO: although this isn't considered an error that * warrants falling back to a different backend we * should print a warning here. */ return TRUE; } /* Handle enabling or disabling the right texture type */ if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE) { CoglTextureType texture_type = _cogl_pipeline_layer_get_texture_type (layer); GLenum gl_target; switch (texture_type) { case COGL_TEXTURE_TYPE_2D: gl_target = GL_TEXTURE_2D; break; case COGL_TEXTURE_TYPE_3D: gl_target = GL_TEXTURE_3D; break; case COGL_TEXTURE_TYPE_RECTANGLE: gl_target = GL_TEXTURE_RECTANGLE_ARB; break; default: g_assert_not_reached (); } _cogl_set_active_texture_unit (unit_index); /* The common GL code handles binding the right texture so we just need to handle enabling and disabling it */ if (unit->enabled_gl_target != gl_target) { /* Disable the previous target if it's still enabled */ if (unit->enabled_gl_target) GE (ctx, glDisable (unit->enabled_gl_target)); /* Enable the new target */ if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) { GE (ctx, glEnable (gl_target)); unit->enabled_gl_target = gl_target; } } } else { /* Even though there may be no difference between the last flushed * texture state and the current layers texture state it may be that the * texture unit has been disabled for some time so we need to assert that * it's enabled now. */ if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)) && unit->enabled_gl_target == 0) { _cogl_set_active_texture_unit (unit_index); GE (ctx, glEnable (unit->gl_target)); unit->enabled_gl_target = unit->gl_target; } } if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE) { CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_COMBINE); CoglPipelineLayerBigState *big_state = authority->big_state; GLenum sources[3]; GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)); /* Set the combiner functions... */ GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, big_state->texture_combine_rgb_func)); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, big_state->texture_combine_alpha_func)); /* * Setup the function arguments... */ /* For the RGB components... */ n_rgb_func_args = _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func); translate_sources (pipeline, n_rgb_func_args, big_state->texture_combine_rgb_src, sources); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, sources[0])); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, big_state->texture_combine_rgb_op[0])); if (n_rgb_func_args > 1) { GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, sources[1])); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, big_state->texture_combine_rgb_op[1])); } if (n_rgb_func_args > 2) { GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB, sources[2])); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB, big_state->texture_combine_rgb_op[2])); } /* For the Alpha component */ n_alpha_func_args = _cogl_get_n_args_for_combine_func (big_state->texture_combine_alpha_func); translate_sources (pipeline, n_alpha_func_args, big_state->texture_combine_alpha_src, sources); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, sources[0])); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, big_state->texture_combine_alpha_op[0])); if (n_alpha_func_args > 1) { GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, sources[1])); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, big_state->texture_combine_alpha_op[1])); } if (n_alpha_func_args > 2) { GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA, sources[2])); GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, big_state->texture_combine_alpha_op[2])); } } if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT) { CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT); CoglPipelineLayerBigState *big_state = authority->big_state; GE (ctx, glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, big_state->texture_combine_constant)); } return TRUE; } static CoglBool get_highest_unit_index_cb (CoglPipelineLayer *layer, void *user_data) { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); int *highest_index = user_data; *highest_index = unit_index; return TRUE; } static CoglBool _cogl_pipeline_fragend_fixed_end (CoglPipeline *pipeline, unsigned long pipelines_difference) { int highest_unit_index = -1; int i; _COGL_GET_CONTEXT (ctx, FALSE); _cogl_pipeline_foreach_layer_internal (pipeline, get_highest_unit_index_cb, &highest_unit_index); /* Disable additional texture units that may have previously been in use.. */ for (i = highest_unit_index + 1; i < ctx->texture_units->len; i++) _cogl_disable_texture_unit (i); if (pipelines_difference & COGL_PIPELINE_STATE_FOG) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_FOG); CoglPipelineFogState *fog_state = &authority->big_state->fog_state; if (fog_state->enabled) { GLfloat fogColor[4]; GLenum gl_mode = GL_LINEAR; fogColor[0] = cogl_color_get_red_float (&fog_state->color); fogColor[1] = cogl_color_get_green_float (&fog_state->color); fogColor[2] = cogl_color_get_blue_float (&fog_state->color); fogColor[3] = cogl_color_get_alpha_float (&fog_state->color); GE (ctx, glEnable (GL_FOG)); GE (ctx, glFogfv (GL_FOG_COLOR, fogColor)); if (ctx->driver == COGL_DRIVER_GLES1) switch (fog_state->mode) { case COGL_FOG_MODE_LINEAR: gl_mode = GL_LINEAR; break; case COGL_FOG_MODE_EXPONENTIAL: gl_mode = GL_EXP; break; case COGL_FOG_MODE_EXPONENTIAL_SQUARED: gl_mode = GL_EXP2; break; } /* TODO: support other modes for GLES2 */ /* NB: GLES doesn't have glFogi */ GE (ctx, glFogf (GL_FOG_MODE, gl_mode)); GE (ctx, glHint (GL_FOG_HINT, GL_NICEST)); GE (ctx, glFogf (GL_FOG_DENSITY, fog_state->density)); GE (ctx, glFogf (GL_FOG_START, fog_state->z_near)); GE (ctx, glFogf (GL_FOG_END, fog_state->z_far)); } else GE (ctx, glDisable (GL_FOG)); } return TRUE; } const CoglPipelineFragend _cogl_pipeline_fixed_fragend = { _cogl_pipeline_fragend_fixed_start, _cogl_pipeline_fragend_fixed_add_layer, NULL, /* passthrough */ _cogl_pipeline_fragend_fixed_end, NULL, /* pipeline_change_notify */ NULL, /* pipeline_set_parent_notify */ NULL, /* layer_change_notify */ }; #endif /* COGL_PIPELINE_FRAGEND_FIXED */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl.c0000664000175000017500000010566314211404421024202 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-offscreen.h" #ifdef COGL_PIPELINE_PROGEND_GLSL #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-program-private.h" #include "cogl-pipeline-fragend-glsl-private.h" #include "cogl-pipeline-vertend-glsl-private.h" #include "cogl-pipeline-cache.h" #include "cogl-pipeline-state-private.h" #include "cogl-attribute-private.h" #include "cogl-framebuffer-private.h" #include "cogl-pipeline-progend-glsl-private.h" /* These are used to generalise updating some uniforms that are required when building for drivers missing some fixed function state that we use */ typedef void (* UpdateUniformFunc) (CoglPipeline *pipeline, int uniform_location, void *getter_func); static void update_float_uniform (CoglPipeline *pipeline, int uniform_location, void *getter_func); typedef struct { const char *uniform_name; void *getter_func; UpdateUniformFunc update_func; CoglPipelineState change; /* This builtin is only necessary if the following private feature * is not implemented in the driver */ CoglPrivateFeature feature_replacement; } BuiltinUniformData; static BuiltinUniformData builtin_uniforms[] = { { "cogl_point_size_in", cogl_pipeline_get_point_size, update_float_uniform, COGL_PIPELINE_STATE_POINT_SIZE, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM }, { "_cogl_alpha_test_ref", cogl_pipeline_get_alpha_test_reference, update_float_uniform, COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE, COGL_PRIVATE_FEATURE_ALPHA_TEST } }; const CoglPipelineProgend _cogl_pipeline_glsl_progend; typedef struct _UnitState { unsigned int dirty_combine_constant:1; unsigned int dirty_texture_matrix:1; GLint combine_constant_uniform; GLint texture_matrix_uniform; } UnitState; typedef struct { unsigned int ref_count; /* Age that the user program had last time we generated a GL program. If it's different then we need to relink the program */ unsigned int user_program_age; GLuint program; unsigned long dirty_builtin_uniforms; GLint builtin_uniform_locations[G_N_ELEMENTS (builtin_uniforms)]; GLint modelview_uniform; GLint projection_uniform; GLint mvp_uniform; CoglMatrixEntryCache projection_cache; CoglMatrixEntryCache modelview_cache; /* We need to track the last pipeline that the program was used with * so know if we need to update all of the uniforms */ CoglPipeline *last_used_for_pipeline; /* Array of GL uniform locations indexed by Cogl's uniform location. We are careful only to allocated this array if a custom uniform is actually set */ GArray *uniform_locations; /* Array of attribute locations. */ GArray *attribute_locations; /* The 'flip' uniform is used to flip the geometry upside-down when the framebuffer requires it only when there are vertex snippets. Otherwise this is acheived using the projection matrix */ GLint flip_uniform; int flushed_flip_state; UnitState *unit_state; CoglPipelineCacheEntry *cache_entry; } CoglPipelineProgramState; static CoglUserDataKey program_state_key; static CoglPipelineProgramState * get_program_state (CoglPipeline *pipeline) { return cogl_object_get_user_data (COGL_OBJECT (pipeline), &program_state_key); } #define UNIFORM_LOCATION_UNKNOWN -2 #define ATTRIBUTE_LOCATION_UNKNOWN -2 /* Under GLES2 the vertex attribute API needs to query the attribute numbers because it can't used the fixed function API to set the builtin attributes. We cache the attributes here because the progend knows when the program is changed so it can clear the cache. This should always be called after the pipeline is flushed so they can assert that the gl program is valid */ /* All attributes names get internally mapped to a global set of * sequential indices when they are setup which we need to need to * then be able to map to a GL attribute location once we have * a linked GLSL program */ int _cogl_pipeline_progend_glsl_get_attrib_location (CoglPipeline *pipeline, int name_index) { CoglPipelineProgramState *program_state = get_program_state (pipeline); int *locations; _COGL_GET_CONTEXT (ctx, -1); _COGL_RETURN_VAL_IF_FAIL (program_state != NULL, -1); _COGL_RETURN_VAL_IF_FAIL (program_state->program != 0, -1); if (G_UNLIKELY (program_state->attribute_locations == NULL)) program_state->attribute_locations = g_array_new (FALSE, FALSE, sizeof (int)); if (G_UNLIKELY (program_state->attribute_locations->len <= name_index)) { int i = program_state->attribute_locations->len; g_array_set_size (program_state->attribute_locations, name_index + 1); for (; i < program_state->attribute_locations->len; i++) g_array_index (program_state->attribute_locations, int, i) = ATTRIBUTE_LOCATION_UNKNOWN; } locations = &g_array_index (program_state->attribute_locations, int, 0); if (locations[name_index] == ATTRIBUTE_LOCATION_UNKNOWN) { CoglAttributeNameState *name_state = g_array_index (ctx->attribute_name_index_map, CoglAttributeNameState *, name_index); _COGL_RETURN_VAL_IF_FAIL (name_state != NULL, 0); GE_RET( locations[name_index], ctx, glGetAttribLocation (program_state->program, name_state->name) ); } return locations[name_index]; } static void clear_attribute_cache (CoglPipelineProgramState *program_state) { if (program_state->attribute_locations) { g_array_free (program_state->attribute_locations, TRUE); program_state->attribute_locations = NULL; } } static void clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state) { _cogl_matrix_entry_cache_destroy (&program_state->projection_cache); _cogl_matrix_entry_cache_init (&program_state->projection_cache); _cogl_matrix_entry_cache_destroy (&program_state->modelview_cache); _cogl_matrix_entry_cache_init (&program_state->modelview_cache); } static CoglPipelineProgramState * program_state_new (int n_layers, CoglPipelineCacheEntry *cache_entry) { CoglPipelineProgramState *program_state; program_state = g_slice_new (CoglPipelineProgramState); program_state->ref_count = 1; program_state->program = 0; program_state->unit_state = g_new (UnitState, n_layers); program_state->uniform_locations = NULL; program_state->attribute_locations = NULL; program_state->cache_entry = cache_entry; _cogl_matrix_entry_cache_init (&program_state->modelview_cache); _cogl_matrix_entry_cache_init (&program_state->projection_cache); return program_state; } static void destroy_program_state (void *user_data, void *instance) { CoglPipelineProgramState *program_state = user_data; _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* If the program state was last used for this pipeline then clear it so that if same address gets used again for a new pipeline then we won't think it's the same pipeline and avoid updating the uniforms */ if (program_state->last_used_for_pipeline == instance) program_state->last_used_for_pipeline = NULL; if (program_state->cache_entry && program_state->cache_entry->pipeline != instance) program_state->cache_entry->usage_count--; if (--program_state->ref_count == 0) { clear_attribute_cache (program_state); _cogl_matrix_entry_cache_destroy (&program_state->projection_cache); _cogl_matrix_entry_cache_destroy (&program_state->modelview_cache); if (program_state->program) GE( ctx, glDeleteProgram (program_state->program) ); free (program_state->unit_state); if (program_state->uniform_locations) g_array_free (program_state->uniform_locations, TRUE); g_slice_free (CoglPipelineProgramState, program_state); } } static void set_program_state (CoglPipeline *pipeline, CoglPipelineProgramState *program_state) { if (program_state) { program_state->ref_count++; /* If we're not setting the state on the template pipeline then * mark it as a usage of the pipeline cache entry */ if (program_state->cache_entry && program_state->cache_entry->pipeline != pipeline) program_state->cache_entry->usage_count++; } _cogl_object_set_user_data (COGL_OBJECT (pipeline), &program_state_key, program_state, destroy_program_state); } static void dirty_program_state (CoglPipeline *pipeline) { cogl_object_set_user_data (COGL_OBJECT (pipeline), &program_state_key, NULL, NULL); } static void link_program (GLint gl_program) { GLint link_status; _COGL_GET_CONTEXT (ctx, NO_RETVAL); GE( ctx, glLinkProgram (gl_program) ); GE( ctx, glGetProgramiv (gl_program, GL_LINK_STATUS, &link_status) ); if (!link_status) { GLint log_length; GLsizei out_log_length; char *log; GE( ctx, glGetProgramiv (gl_program, GL_INFO_LOG_LENGTH, &log_length) ); log = malloc (log_length); GE( ctx, glGetProgramInfoLog (gl_program, log_length, &out_log_length, log) ); g_warning ("Failed to link GLSL program:\n%.*s\n", log_length, log); free (log); } } typedef struct { int unit; GLuint gl_program; CoglBool update_all; CoglPipelineProgramState *program_state; } UpdateUniformsState; static CoglBool get_uniform_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { UpdateUniformsState *state = user_data; CoglPipelineProgramState *program_state = state->program_state; UnitState *unit_state = &program_state->unit_state[state->unit]; GLint uniform_location; _COGL_GET_CONTEXT (ctx, FALSE); /* We can reuse the source buffer to create the uniform name because the program has now been linked */ g_string_set_size (ctx->codegen_source_buffer, 0); g_string_append_printf (ctx->codegen_source_buffer, "cogl_sampler%i", layer_index); GE_RET( uniform_location, ctx, glGetUniformLocation (state->gl_program, ctx->codegen_source_buffer->str) ); /* We can set the uniform immediately because the samplers are the unit index not the texture object number so it will never change. Unfortunately GL won't let us use a constant instead of a uniform */ if (uniform_location != -1) GE( ctx, glUniform1i (uniform_location, state->unit) ); g_string_set_size (ctx->codegen_source_buffer, 0); g_string_append_printf (ctx->codegen_source_buffer, "_cogl_layer_constant_%i", layer_index); GE_RET( uniform_location, ctx, glGetUniformLocation (state->gl_program, ctx->codegen_source_buffer->str) ); unit_state->combine_constant_uniform = uniform_location; g_string_set_size (ctx->codegen_source_buffer, 0); g_string_append_printf (ctx->codegen_source_buffer, "cogl_texture_matrix[%i]", layer_index); GE_RET( uniform_location, ctx, glGetUniformLocation (state->gl_program, ctx->codegen_source_buffer->str) ); unit_state->texture_matrix_uniform = uniform_location; state->unit++; return TRUE; } static CoglBool update_constants_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { UpdateUniformsState *state = user_data; CoglPipelineProgramState *program_state = state->program_state; UnitState *unit_state = &program_state->unit_state[state->unit++]; _COGL_GET_CONTEXT (ctx, FALSE); if (unit_state->combine_constant_uniform != -1 && (state->update_all || unit_state->dirty_combine_constant)) { float constant[4]; _cogl_pipeline_get_layer_combine_constant (pipeline, layer_index, constant); GE (ctx, glUniform4fv (unit_state->combine_constant_uniform, 1, constant)); unit_state->dirty_combine_constant = FALSE; } if (unit_state->texture_matrix_uniform != -1 && (state->update_all || unit_state->dirty_texture_matrix)) { const CoglMatrix *matrix; const float *array; matrix = _cogl_pipeline_get_layer_matrix (pipeline, layer_index); array = cogl_matrix_get_array (matrix); GE (ctx, glUniformMatrix4fv (unit_state->texture_matrix_uniform, 1, FALSE, array)); unit_state->dirty_texture_matrix = FALSE; } return TRUE; } static void update_builtin_uniforms (CoglContext *context, CoglPipeline *pipeline, GLuint gl_program, CoglPipelineProgramState *program_state) { int i; if (program_state->dirty_builtin_uniforms == 0) return; for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++) if (!_cogl_has_private_feature (context, builtin_uniforms[i].feature_replacement) && (program_state->dirty_builtin_uniforms & (1 << i)) && program_state->builtin_uniform_locations[i] != -1) builtin_uniforms[i].update_func (pipeline, program_state ->builtin_uniform_locations[i], builtin_uniforms[i].getter_func); program_state->dirty_builtin_uniforms = 0; } typedef struct { CoglPipelineProgramState *program_state; unsigned long *uniform_differences; int n_differences; CoglContext *ctx; const CoglBoxedValue *values; int value_index; } FlushUniformsClosure; static CoglBool flush_uniform_cb (int uniform_num, void *user_data) { FlushUniformsClosure *data = user_data; if (COGL_FLAGS_GET (data->uniform_differences, uniform_num)) { GArray *uniform_locations; GLint uniform_location; if (data->program_state->uniform_locations == NULL) data->program_state->uniform_locations = g_array_new (FALSE, FALSE, sizeof (GLint)); uniform_locations = data->program_state->uniform_locations; if (uniform_locations->len <= uniform_num) { unsigned int old_len = uniform_locations->len; g_array_set_size (uniform_locations, uniform_num + 1); while (old_len <= uniform_num) { g_array_index (uniform_locations, GLint, old_len) = UNIFORM_LOCATION_UNKNOWN; old_len++; } } uniform_location = g_array_index (uniform_locations, GLint, uniform_num); if (uniform_location == UNIFORM_LOCATION_UNKNOWN) { const char *uniform_name = g_ptr_array_index (data->ctx->uniform_names, uniform_num); uniform_location = data->ctx->glGetUniformLocation (data->program_state->program, uniform_name); g_array_index (uniform_locations, GLint, uniform_num) = uniform_location; } if (uniform_location != -1) _cogl_boxed_value_set_uniform (data->ctx, uniform_location, data->values + data->value_index); data->n_differences--; COGL_FLAGS_SET (data->uniform_differences, uniform_num, FALSE); } data->value_index++; return data->n_differences > 0; } static void _cogl_pipeline_progend_glsl_flush_uniforms (CoglPipeline *pipeline, CoglPipelineProgramState * program_state, GLuint gl_program, CoglBool program_changed) { CoglPipelineUniformsState *uniforms_state; FlushUniformsClosure data; int n_uniform_longs; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) uniforms_state = &pipeline->big_state->uniforms_state; else uniforms_state = NULL; data.program_state = program_state; data.ctx = ctx; n_uniform_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names); data.uniform_differences = g_newa (unsigned long, n_uniform_longs); /* Try to find a common ancestor for the values that were already flushed on the pipeline that this program state was last used for so we can avoid flushing those */ if (program_changed || program_state->last_used_for_pipeline == NULL) { if (program_changed) { /* The program has changed so all of the uniform locations are invalid */ if (program_state->uniform_locations) g_array_set_size (program_state->uniform_locations, 0); } /* We need to flush everything so mark all of the uniforms as dirty */ memset (data.uniform_differences, 0xff, n_uniform_longs * sizeof (unsigned long)); data.n_differences = G_MAXINT; } else if (program_state->last_used_for_pipeline) { int i; memset (data.uniform_differences, 0, n_uniform_longs * sizeof (unsigned long)); _cogl_pipeline_compare_uniform_differences (data.uniform_differences, program_state->last_used_for_pipeline, pipeline); /* We need to be sure to flush any uniforms that have changed since the last flush */ if (uniforms_state) _cogl_bitmask_set_flags (&uniforms_state->changed_mask, data.uniform_differences); /* Count the number of differences. This is so we can stop early when we've flushed all of them */ data.n_differences = 0; for (i = 0; i < n_uniform_longs; i++) data.n_differences += _cogl_util_popcountl (data.uniform_differences[i]); } while (pipeline && data.n_differences > 0) { if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) { const CoglPipelineUniformsState *parent_uniforms_state = &pipeline->big_state->uniforms_state; data.values = parent_uniforms_state->override_values; data.value_index = 0; _cogl_bitmask_foreach (&parent_uniforms_state->override_mask, flush_uniform_cb, &data); } pipeline = _cogl_pipeline_get_parent (pipeline); } if (uniforms_state) _cogl_bitmask_clear_all (&uniforms_state->changed_mask); } static CoglBool _cogl_pipeline_progend_glsl_start (CoglPipeline *pipeline) { CoglHandle user_program; _COGL_GET_CONTEXT (ctx, FALSE); if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL)) return FALSE; user_program = cogl_pipeline_get_user_program (pipeline); if (user_program && _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL) return FALSE; return TRUE; } static void _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline, unsigned long pipelines_difference) { CoglPipelineProgramState *program_state; GLuint gl_program; CoglBool program_changed = FALSE; UpdateUniformsState state; CoglProgram *user_program; CoglPipelineCacheEntry *cache_entry = NULL; _COGL_GET_CONTEXT (ctx, NO_RETVAL); program_state = get_program_state (pipeline); user_program = cogl_pipeline_get_user_program (pipeline); if (program_state == NULL) { CoglPipeline *authority; /* Get the authority for anything affecting program state. This should include both fragment codegen state and vertex codegen state */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, (_cogl_pipeline_get_state_for_vertex_codegen (ctx) | _cogl_pipeline_get_state_for_fragment_codegen (ctx)) & ~COGL_PIPELINE_STATE_LAYERS, _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) | COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN); program_state = get_program_state (authority); if (program_state == NULL) { /* Check if there is already a similar cached pipeline whose program state we can share */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { cache_entry = _cogl_pipeline_cache_get_combined_template (ctx->pipeline_cache, authority); program_state = get_program_state (cache_entry->pipeline); } if (program_state) program_state->ref_count++; else program_state = program_state_new (cogl_pipeline_get_n_layers (authority), cache_entry); set_program_state (authority, program_state); program_state->ref_count--; if (cache_entry) set_program_state (cache_entry->pipeline, program_state); } if (authority != pipeline) set_program_state (pipeline, program_state); } /* If the program has changed since the last link then we do * need to relink */ if (program_state->program && user_program && user_program->age != program_state->user_program_age) { GE( ctx, glDeleteProgram (program_state->program) ); program_state->program = 0; } if (program_state->program == 0) { GLuint backend_shader; GSList *l; GE_RET( program_state->program, ctx, glCreateProgram () ); /* Attach all of the shader from the user program */ if (user_program) { for (l = user_program->attached_shaders; l; l = l->next) { CoglShader *shader = l->data; _cogl_shader_compile_real (shader, pipeline); g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL); GE( ctx, glAttachShader (program_state->program, shader->gl_handle) ); } program_state->user_program_age = user_program->age; } /* Attach any shaders from the GLSL backends */ if ((backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline))) GE( ctx, glAttachShader (program_state->program, backend_shader) ); if ((backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline))) GE( ctx, glAttachShader (program_state->program, backend_shader) ); /* XXX: OpenGL as a special case requires the vertex position to * be bound to generic attribute 0 so for simplicity we * unconditionally bind the cogl_position_in attribute here... */ GE( ctx, glBindAttribLocation (program_state->program, 0, "cogl_position_in")); link_program (program_state->program); program_changed = TRUE; } gl_program = program_state->program; _cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL); _cogl_use_vertex_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL); state.unit = 0; state.gl_program = gl_program; state.program_state = program_state; if (program_changed) { cogl_pipeline_foreach_layer (pipeline, get_uniform_cb, &state); clear_attribute_cache (program_state); GE_RET (program_state->flip_uniform, ctx, glGetUniformLocation (gl_program, "_cogl_flip_vector")); program_state->flushed_flip_state = -1; } state.unit = 0; state.update_all = (program_changed || program_state->last_used_for_pipeline != pipeline); cogl_pipeline_foreach_layer (pipeline, update_constants_cb, &state); if (program_changed) { int i; clear_flushed_matrix_stacks (program_state); for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++) if (!_cogl_has_private_feature (ctx, builtin_uniforms[i].feature_replacement)) GE_RET( program_state->builtin_uniform_locations[i], ctx, glGetUniformLocation (gl_program, builtin_uniforms[i].uniform_name) ); GE_RET( program_state->modelview_uniform, ctx, glGetUniformLocation (gl_program, "cogl_modelview_matrix") ); GE_RET( program_state->projection_uniform, ctx, glGetUniformLocation (gl_program, "cogl_projection_matrix") ); GE_RET( program_state->mvp_uniform, ctx, glGetUniformLocation (gl_program, "cogl_modelview_projection_matrix") ); } if (program_changed || program_state->last_used_for_pipeline != pipeline) program_state->dirty_builtin_uniforms = ~(unsigned long) 0; update_builtin_uniforms (ctx, pipeline, gl_program, program_state); _cogl_pipeline_progend_glsl_flush_uniforms (pipeline, program_state, gl_program, program_changed); if (user_program) _cogl_program_flush_uniforms (user_program, gl_program, program_changed); /* We need to track the last pipeline that the program was used with * so know if we need to update all of the uniforms */ program_state->last_used_for_pipeline = pipeline; } static void _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if ((change & (_cogl_pipeline_get_state_for_vertex_codegen (ctx) | _cogl_pipeline_get_state_for_fragment_codegen (ctx)))) { dirty_program_state (pipeline); } else { int i; for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++) if (!_cogl_has_private_feature (ctx, builtin_uniforms[i].feature_replacement) && (change & builtin_uniforms[i].change)) { CoglPipelineProgramState *program_state = get_program_state (pipeline); if (program_state) program_state->dirty_builtin_uniforms |= 1 << i; return; } } } /* NB: layers are considered immutable once they have any dependants * so although multiple pipelines can end up depending on a single * static layer, we can guarantee that if a layer is being *changed* * then it can only have one pipeline depending on it. * * XXX: Don't forget this is *pre* change, we can't read the new value * yet! */ static void _cogl_pipeline_progend_glsl_layer_pre_change_notify ( CoglPipeline *owner, CoglPipelineLayer *layer, CoglPipelineLayerState change) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if ((change & (_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) | COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN))) { dirty_program_state (owner); } else if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT) { CoglPipelineProgramState *program_state = get_program_state (owner); if (program_state) { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); program_state->unit_state[unit_index].dirty_combine_constant = TRUE; } } else if (change & COGL_PIPELINE_LAYER_STATE_USER_MATRIX) { CoglPipelineProgramState *program_state = get_program_state (owner); if (program_state) { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); program_state->unit_state[unit_index].dirty_texture_matrix = TRUE; } } } static void _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline, CoglFramebuffer *framebuffer) { CoglBool needs_flip; CoglMatrixEntry *projection_entry; CoglMatrixEntry *modelview_entry; CoglPipelineProgramState *program_state; CoglBool modelview_changed; CoglBool projection_changed; CoglBool need_modelview; CoglBool need_projection; CoglMatrix modelview, projection; _COGL_GET_CONTEXT (ctx, NO_RETVAL); program_state = get_program_state (pipeline); projection_entry = ctx->current_projection_entry; modelview_entry = ctx->current_modelview_entry; /* An initial pipeline is flushed while creating the context. At this point there are no matrices selected so we can't do anything */ if (modelview_entry == NULL || projection_entry == NULL) return; needs_flip = cogl_is_offscreen (ctx->current_draw_buffer); projection_changed = _cogl_matrix_entry_cache_maybe_update (&program_state->projection_cache, projection_entry, (needs_flip && program_state->flip_uniform == -1)); modelview_changed = _cogl_matrix_entry_cache_maybe_update (&program_state->modelview_cache, modelview_entry, /* never flip modelview */ FALSE); if (modelview_changed || projection_changed) { if (program_state->mvp_uniform != -1) need_modelview = need_projection = TRUE; else { need_projection = (program_state->projection_uniform != -1 && projection_changed); need_modelview = (program_state->modelview_uniform != -1 && modelview_changed); } if (need_modelview) cogl_matrix_entry_get (modelview_entry, &modelview); if (need_projection) { if (needs_flip && program_state->flip_uniform == -1) { CoglMatrix tmp_matrix; cogl_matrix_entry_get (projection_entry, &tmp_matrix); cogl_matrix_multiply (&projection, &ctx->y_flip_matrix, &tmp_matrix); } else cogl_matrix_entry_get (projection_entry, &projection); } if (projection_changed && program_state->projection_uniform != -1) GE (ctx, glUniformMatrix4fv (program_state->projection_uniform, 1, /* count */ FALSE, /* transpose */ cogl_matrix_get_array (&projection))); if (modelview_changed && program_state->modelview_uniform != -1) GE (ctx, glUniformMatrix4fv (program_state->modelview_uniform, 1, /* count */ FALSE, /* transpose */ cogl_matrix_get_array (&modelview))); if (program_state->mvp_uniform != -1) { /* The journal usually uses an identity matrix for the modelview so we can optimise this common case by avoiding the matrix multiplication */ if (cogl_matrix_entry_is_identity (modelview_entry)) { GE (ctx, glUniformMatrix4fv (program_state->mvp_uniform, 1, /* count */ FALSE, /* transpose */ cogl_matrix_get_array (&projection))); } else { CoglMatrix combined; cogl_matrix_multiply (&combined, &projection, &modelview); GE (ctx, glUniformMatrix4fv (program_state->mvp_uniform, 1, /* count */ FALSE, /* transpose */ cogl_matrix_get_array (&combined))); } } } if (program_state->flip_uniform != -1 && program_state->flushed_flip_state != needs_flip) { static const float do_flip[4] = { 1.0f, -1.0f, 1.0f, 1.0f }; static const float dont_flip[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; GE( ctx, glUniform4fv (program_state->flip_uniform, 1, /* count */ needs_flip ? do_flip : dont_flip) ); program_state->flushed_flip_state = needs_flip; } } static void update_float_uniform (CoglPipeline *pipeline, int uniform_location, void *getter_func) { float (* float_getter_func) (CoglPipeline *) = getter_func; float value; _COGL_GET_CONTEXT (ctx, NO_RETVAL); value = float_getter_func (pipeline); GE( ctx, glUniform1f (uniform_location, value) ); } const CoglPipelineProgend _cogl_pipeline_glsl_progend = { COGL_PIPELINE_VERTEND_GLSL, COGL_PIPELINE_FRAGEND_GLSL, _cogl_pipeline_progend_glsl_start, _cogl_pipeline_progend_glsl_end, _cogl_pipeline_progend_glsl_pre_change_notify, _cogl_pipeline_progend_glsl_layer_pre_change_notify, _cogl_pipeline_progend_glsl_pre_paint }; #endif /* COGL_PIPELINE_PROGEND_GLSL */ muffin-5.2.1/cogl/cogl/driver/gl/gl/0000775000175000017500000000000014211404421017303 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c0000664000175000017500000010056614211404421024702 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-state-private.h" #include "cogl-pipeline-layer-private.h" #ifdef COGL_PIPELINE_FRAGEND_ARBFP #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-texture-private.h" #include "cogl-blend-string.h" #include "cogl-journal-private.h" #include "cogl-color-private.h" #include "cogl-profile.h" #include "cogl-program-private.h" #include #include #include /* This might not be defined on GLES */ #ifndef GL_TEXTURE_3D #define GL_TEXTURE_3D 0x806F #endif const CoglPipelineFragend _cogl_pipeline_arbfp_fragend; typedef struct _UnitState { int constant_id; /* The program.local[] index */ unsigned int dirty_combine_constant:1; unsigned int has_combine_constant:1; unsigned int sampled:1; } UnitState; typedef struct { int ref_count; CoglHandle user_program; /* XXX: only valid during codegen */ GString *source; GLuint gl_program; UnitState *unit_state; int next_constant_id; /* Age of the program the last time the uniforms were flushed. This is used to detect when we need to flush all of the uniforms */ unsigned int user_program_age; /* We need to track the last pipeline that an ARBfp program was used * with so know if we need to update any program.local parameters. */ CoglPipeline *last_used_for_pipeline; CoglPipelineCacheEntry *cache_entry; } CoglPipelineShaderState; static CoglUserDataKey shader_state_key; static CoglPipelineShaderState * shader_state_new (int n_layers, CoglPipelineCacheEntry *cache_entry) { CoglPipelineShaderState *shader_state; shader_state = g_slice_new0 (CoglPipelineShaderState); shader_state->ref_count = 1; shader_state->unit_state = g_new0 (UnitState, n_layers); shader_state->cache_entry = cache_entry; return shader_state; } static CoglPipelineShaderState * get_shader_state (CoglPipeline *pipeline) { return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key); } static void destroy_shader_state (void *user_data, void *instance) { CoglPipelineShaderState *shader_state = user_data; _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* If the shader state was last used for this pipeline then clear it so that if same address gets used again for a new pipeline then we won't think it's the same pipeline and avoid updating the constants */ if (shader_state->last_used_for_pipeline == instance) shader_state->last_used_for_pipeline = NULL; if (shader_state->cache_entry && shader_state->cache_entry->pipeline != instance) shader_state->cache_entry->usage_count--; if (--shader_state->ref_count == 0) { if (shader_state->gl_program) { GE (ctx, glDeletePrograms (1, &shader_state->gl_program)); shader_state->gl_program = 0; } free (shader_state->unit_state); g_slice_free (CoglPipelineShaderState, shader_state); } } static void set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { if (shader_state) { shader_state->ref_count++; /* If we're not setting the state on the template pipeline then * mark it as a usage of the pipeline cache entry */ if (shader_state->cache_entry && shader_state->cache_entry->pipeline != pipeline) shader_state->cache_entry->usage_count++; } _cogl_object_set_user_data (COGL_OBJECT (pipeline), &shader_state_key, shader_state, destroy_shader_state); } static void dirty_shader_state (CoglPipeline *pipeline) { cogl_object_set_user_data (COGL_OBJECT (pipeline), &shader_state_key, NULL, NULL); } static void _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; CoglPipeline *authority; CoglPipelineCacheEntry *cache_entry = NULL; CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline); _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Now lookup our ARBfp backend private state */ shader_state = get_shader_state (pipeline); /* If we have a valid shader_state then we are all set and don't * need to generate a new program. */ if (shader_state) return; /* If we don't have an associated arbfp program yet then find the * arbfp-authority (the oldest ancestor whose state will result in * the same program being generated as for this pipeline). * * We always make sure to associate new programs with the * arbfp-authority to maximize the chance that other pipelines can * share it. */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, _cogl_pipeline_get_state_for_fragment_codegen (ctx) & ~COGL_PIPELINE_STATE_LAYERS, _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)); shader_state = get_shader_state (authority); if (shader_state) { /* If we are going to share our program state with an arbfp-authority * then add a reference to the program state associated with that * arbfp-authority... */ set_shader_state (pipeline, shader_state); return; } /* If we haven't yet found an existing program then before we resort to * generating a new arbfp program we see if we can find a suitable * program in the pipeline_cache. */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { cache_entry = _cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (cache_entry->pipeline); if (shader_state) shader_state->ref_count++; } /* If we still haven't got a shader state then we'll have to create a new one */ if (shader_state == NULL) { shader_state = shader_state_new (n_layers, cache_entry); shader_state->user_program = user_program; if (user_program == COGL_INVALID_HANDLE) { /* We reuse a single grow-only GString for code-gen */ g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->source = ctx->codegen_source_buffer; g_string_append (shader_state->source, "!!ARBfp1.0\n" "TEMP output;\n" "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n" "PARAM half = {.5, .5, .5, .5};\n" "PARAM one = {1, 1, 1, 1};\n" "PARAM two = {2, 2, 2, 2};\n" "PARAM minus_one = {-1, -1, -1, -1};\n"); } } set_shader_state (pipeline, shader_state); shader_state->ref_count--; /* Since we have already resolved the arbfp-authority at this point * we might as well also associate any program we find from the cache * with the authority too... */ if (authority != pipeline) set_shader_state (authority, shader_state); /* If we found a template then we'll attach it to that too so that next time a similar pipeline is used it can use the same state */ if (cache_entry) set_shader_state (cache_entry->pipeline, shader_state); } static const char * texture_type_to_arbfp_string (CoglTextureType texture_type) { switch (texture_type) { #if 0 /* TODO */ case COGL_TEXTURE_TYPE_1D: return "1D"; #endif case COGL_TEXTURE_TYPE_2D: return "2D"; case COGL_TEXTURE_TYPE_3D: return "3D"; case COGL_TEXTURE_TYPE_RECTANGLE: return "RECT"; } g_warn_if_reached (); return "2D"; } static void setup_texture_source (CoglPipelineShaderState *shader_state, int unit_index, CoglTextureType texture_type) { if (!shader_state->unit_state[unit_index].sampled) { if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) g_string_append_printf (shader_state->source, "TEMP texel%d;\n" "MOV texel%d, one;\n", unit_index, unit_index); else g_string_append_printf (shader_state->source, "TEMP texel%d;\n" "TEX texel%d,fragment.texcoord[%d]," "texture[%d],%s;\n", unit_index, unit_index, unit_index, unit_index, texture_type_to_arbfp_string (texture_type)); shader_state->unit_state[unit_index].sampled = TRUE; } } typedef enum _CoglPipelineFragendARBfpArgType { COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE, COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_CONSTANT, COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_TEXTURE } CoglPipelineFragendARBfpArgType; typedef struct _CoglPipelineFragendARBfpArg { const char *name; CoglPipelineFragendARBfpArgType type; /* for type = TEXTURE */ int texture_unit; CoglTextureType texture_type; /* for type = CONSTANT */ int constant_id; const char *swizzle; } CoglPipelineFragendARBfpArg; static void append_arg (GString *source, const CoglPipelineFragendARBfpArg *arg) { switch (arg->type) { case COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_TEXTURE: g_string_append_printf (source, "texel%d%s", arg->texture_unit, arg->swizzle); break; case COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_CONSTANT: g_string_append_printf (source, "program.local[%d]%s", arg->constant_id, arg->swizzle); break; case COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE: g_string_append_printf (source, "%s%s", arg->name, arg->swizzle); break; } } /* Note: we are trying to avoid duplicating strings during codegen * which is why we have the slightly awkward * CoglPipelineFragendARBfpArg mechanism. */ static void setup_arg (CoglPipeline *pipeline, CoglPipelineLayer *layer, CoglBlendStringChannelMask mask, int arg_index, CoglPipelineCombineSource src, GLint op, CoglPipelineFragendARBfpArg *arg) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); static const char *tmp_name[3] = { "tmp0", "tmp1", "tmp2" }; switch (src) { case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE: arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_TEXTURE; arg->name = "texel%d"; arg->texture_unit = _cogl_pipeline_layer_get_unit_index (layer); setup_texture_source (shader_state, arg->texture_unit, _cogl_pipeline_layer_get_texture_type (layer)); break; case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT: { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); UnitState *unit_state = &shader_state->unit_state[unit_index]; unit_state->constant_id = shader_state->next_constant_id++; unit_state->has_combine_constant = TRUE; unit_state->dirty_combine_constant = TRUE; arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_CONSTANT; arg->name = "program.local[%d]"; arg->constant_id = unit_state->constant_id; break; } case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR: arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE; arg->name = "fragment.color.primary"; break; case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS: arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE; if (_cogl_pipeline_layer_get_unit_index (layer) == 0) arg->name = "fragment.color.primary"; else arg->name = "output"; break; default: /* Sample the texture attached to a specific layer */ { int layer_num = src - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0; CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; CoglPipelineLayer *other_layer = _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags); if (other_layer == NULL) { static CoglBool warning_seen = FALSE; if (!warning_seen) { g_warning ("The application is trying to use a texture " "combine with a layer number that does not exist"); warning_seen = TRUE; } arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE; arg->name = "output"; } else { CoglTextureType texture_type; arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_TEXTURE; arg->name = "texture[%d]"; arg->texture_unit = _cogl_pipeline_layer_get_unit_index (other_layer); texture_type = _cogl_pipeline_layer_get_texture_type (other_layer); setup_texture_source (shader_state, arg->texture_unit, texture_type); } } break; } arg->swizzle = ""; switch (op) { case COGL_PIPELINE_COMBINE_OP_SRC_COLOR: break; case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR: g_string_append_printf (shader_state->source, "SUB tmp%d, one, ", arg_index); append_arg (shader_state->source, arg); g_string_append_printf (shader_state->source, ";\n"); arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE; arg->name = tmp_name[arg_index]; arg->swizzle = ""; break; case COGL_PIPELINE_COMBINE_OP_SRC_ALPHA: /* avoid a swizzle if we know RGB are going to be masked * in the end anyway */ if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) arg->swizzle = ".a"; break; case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA: g_string_append_printf (shader_state->source, "SUB tmp%d, one, ", arg_index); append_arg (shader_state->source, arg); /* avoid a swizzle if we know RGB are going to be masked * in the end anyway */ if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) g_string_append_printf (shader_state->source, ".a;\n"); else g_string_append_printf (shader_state->source, ";\n"); arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE; arg->name = tmp_name[arg_index]; break; default: g_error ("Unknown texture combine operator %d", op); break; } } static CoglBool fragend_arbfp_args_equal (CoglPipelineFragendARBfpArg *arg0, CoglPipelineFragendARBfpArg *arg1) { if (arg0->type != arg1->type) return FALSE; if (arg0->name != arg1->name && strcmp (arg0->name, arg1->name) != 0) return FALSE; if (arg0->type == COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_TEXTURE && arg0->texture_unit != arg1->texture_unit) return FALSE; /* Note we don't have to check the target; a texture unit can only * have one target enabled at a time. */ if (arg0->type == COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_CONSTANT && arg0->constant_id != arg1->constant_id) return FALSE; if (arg0->swizzle != arg1->swizzle && strcmp (arg0->swizzle, arg1->swizzle) != 0) return FALSE; return TRUE; } static void append_function (CoglPipeline *pipeline, CoglBlendStringChannelMask mask, GLint function, CoglPipelineFragendARBfpArg *args, int n_args) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); const char *mask_name; switch (mask) { case COGL_BLEND_STRING_CHANNEL_MASK_RGB: mask_name = ".rgb"; break; case COGL_BLEND_STRING_CHANNEL_MASK_ALPHA: mask_name = ".a"; break; case COGL_BLEND_STRING_CHANNEL_MASK_RGBA: mask_name = ""; break; default: g_error ("Unknown channel mask %d", mask); mask_name = ""; } switch (function) { case COGL_PIPELINE_COMBINE_FUNC_ADD: g_string_append_printf (shader_state->source, "ADD_SAT output%s, ", mask_name); break; case COGL_PIPELINE_COMBINE_FUNC_MODULATE: /* Note: no need to saturate since we can assume operands * have values in the range [0,1] */ g_string_append_printf (shader_state->source, "MUL output%s, ", mask_name); break; case COGL_PIPELINE_COMBINE_FUNC_REPLACE: /* Note: no need to saturate since we can assume operand * has a value in the range [0,1] */ g_string_append_printf (shader_state->source, "MOV output%s, ", mask_name); break; case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT: g_string_append_printf (shader_state->source, "SUB_SAT output%s, ", mask_name); break; case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED: g_string_append_printf (shader_state->source, "ADD tmp3%s, ", mask_name); append_arg (shader_state->source, &args[0]); g_string_append (shader_state->source, ", "); append_arg (shader_state->source, &args[1]); g_string_append (shader_state->source, ";\n"); g_string_append_printf (shader_state->source, "SUB_SAT output%s, tmp3, half", mask_name); n_args = 0; break; case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB: /* These functions are the same except that GL_DOT3_RGB never * updates the alpha channel. * * NB: GL_DOT3_RGBA is a bit special because it effectively forces * an RGBA mask and we end up ignoring any separate alpha channel * function. */ case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA: { const char *tmp4 = "tmp4"; /* The maths for this was taken from Mesa; * apparently: * * tmp3 = 2*src0 - 1 * tmp4 = 2*src1 - 1 * output = DP3 (tmp3, tmp4) * * is the same as: * * output = 4 * DP3 (src0 - 0.5, src1 - 0.5) */ g_string_append (shader_state->source, "MAD tmp3, two, "); append_arg (shader_state->source, &args[0]); g_string_append (shader_state->source, ", minus_one;\n"); if (!fragend_arbfp_args_equal (&args[0], &args[1])) { g_string_append (shader_state->source, "MAD tmp4, two, "); append_arg (shader_state->source, &args[1]); g_string_append (shader_state->source, ", minus_one;\n"); } else tmp4 = "tmp3"; g_string_append_printf (shader_state->source, "DP3_SAT output%s, tmp3, %s", mask_name, tmp4); n_args = 0; } break; case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE: /* Note: no need to saturate since we can assume operands * have values in the range [0,1] */ /* NB: GL_INTERPOLATE = arg0*arg2 + arg1*(1-arg2) * but LRP dst, a, b, c = b*a + c*(1-a) */ g_string_append_printf (shader_state->source, "LRP output%s, ", mask_name); append_arg (shader_state->source, &args[2]); g_string_append (shader_state->source, ", "); append_arg (shader_state->source, &args[0]); g_string_append (shader_state->source, ", "); append_arg (shader_state->source, &args[1]); n_args = 0; break; default: g_error ("Unknown texture combine function %d", function); g_string_append_printf (shader_state->source, "MUL_SAT output%s, ", mask_name); n_args = 2; break; } if (n_args > 0) append_arg (shader_state->source, &args[0]); if (n_args > 1) { g_string_append (shader_state->source, ", "); append_arg (shader_state->source, &args[1]); } g_string_append (shader_state->source, ";\n"); } static void append_masked_combine (CoglPipeline *arbfp_authority, CoglPipelineLayer *layer, CoglBlendStringChannelMask mask, CoglPipelineCombineFunc function, CoglPipelineCombineSource *src, CoglPipelineCombineOp *op) { int i; int n_args; CoglPipelineFragendARBfpArg args[3]; n_args = _cogl_get_n_args_for_combine_func (function); for (i = 0; i < n_args; i++) { setup_arg (arbfp_authority, layer, mask, i, src[i], op[i], &args[i]); } append_function (arbfp_authority, mask, function, args, n_args); } static CoglBool _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); CoglPipelineLayer *combine_authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_COMBINE); CoglPipelineLayerBigState *big_state = combine_authority->big_state; /* Notes... * * We are ignoring the issue of texture indirection limits until * someone complains (Ref Section 3.11.6 in the ARB_fragment_program * spec) * * There always five TEMPs named tmp0, tmp1 and tmp2, tmp3 and tmp4 * available and these constants: 'one' = {1, 1, 1, 1}, 'half' * {.5, .5, .5, .5}, 'two' = {2, 2, 2, 2}, 'minus_one' = {-1, -1, * -1, -1} * * tmp0-2 are intended for dealing with some of the texture combine * operands (e.g. GL_ONE_MINUS_SRC_COLOR) tmp3/4 are for dealing * with the GL_ADD_SIGNED texture combine and the GL_DOT3_RGB[A] * functions. * * Each layer outputs to the TEMP called "output", and reads from * output if it needs to refer to GL_PREVIOUS. (we detect if we are * layer0 so we will read fragment.color for GL_PREVIOUS in that * case) * * We aim to do all the channels together if the same function is * used for RGB as for A. * * We aim to avoid string duplication / allocations during codegen. * * We are careful to only saturate when writing to output. */ if (!shader_state->source) return TRUE; if (!_cogl_pipeline_layer_needs_combine_separate (combine_authority)) { append_masked_combine (pipeline, layer, COGL_BLEND_STRING_CHANNEL_MASK_RGBA, big_state->texture_combine_rgb_func, big_state->texture_combine_rgb_src, big_state->texture_combine_rgb_op); } else if (big_state->texture_combine_rgb_func == COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA) { /* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function * since if you use it, it overrides your ALPHA function... */ append_masked_combine (pipeline, layer, COGL_BLEND_STRING_CHANNEL_MASK_RGBA, big_state->texture_combine_rgb_func, big_state->texture_combine_rgb_src, big_state->texture_combine_rgb_op); } else { append_masked_combine (pipeline, layer, COGL_BLEND_STRING_CHANNEL_MASK_RGB, big_state->texture_combine_rgb_func, big_state->texture_combine_rgb_src, big_state->texture_combine_rgb_op); append_masked_combine (pipeline, layer, COGL_BLEND_STRING_CHANNEL_MASK_ALPHA, big_state->texture_combine_alpha_func, big_state->texture_combine_alpha_src, big_state->texture_combine_alpha_op); } return TRUE; } static CoglBool _cogl_pipeline_fragend_arbfp_passthrough (CoglPipeline *pipeline) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); if (!shader_state->source) return TRUE; g_string_append (shader_state->source, "MOV output, fragment.color.primary;\n"); return TRUE; } typedef struct _UpdateConstantsState { int unit; CoglBool update_all; CoglPipelineShaderState *shader_state; } UpdateConstantsState; static CoglBool update_constants_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { UpdateConstantsState *state = user_data; CoglPipelineShaderState *shader_state = state->shader_state; UnitState *unit_state = &shader_state->unit_state[state->unit++]; _COGL_GET_CONTEXT (ctx, FALSE); if (unit_state->has_combine_constant && (state->update_all || unit_state->dirty_combine_constant)) { float constant[4]; _cogl_pipeline_get_layer_combine_constant (pipeline, layer_index, constant); GE (ctx, glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB, unit_state->constant_id, constant)); unit_state->dirty_combine_constant = FALSE; } return TRUE; } static CoglBool _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); GLuint gl_program; _COGL_GET_CONTEXT (ctx, FALSE); if (shader_state->source) { COGL_STATIC_COUNTER (fragend_arbfp_compile_counter, "arbfp compile counter", "Increments each time a new ARBfp " "program is compiled", 0 /* no application private data */); COGL_COUNTER_INC (_cogl_uprof_context, fragend_arbfp_compile_counter); g_string_append (shader_state->source, "MOV result.color,output;\n"); g_string_append (shader_state->source, "END\n"); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE))) g_message ("pipeline program:\n%s", shader_state->source->str); GE (ctx, glGenPrograms (1, &shader_state->gl_program)); GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader_state->gl_program)); _cogl_gl_util_clear_gl_errors (ctx); ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, shader_state->source->len, shader_state->source->str); if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) { g_warning ("\n%s\n%s", shader_state->source->str, ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB)); } shader_state->source = NULL; } if (shader_state->user_program != COGL_INVALID_HANDLE) { /* An arbfp program should contain exactly one shader which we can use directly */ CoglProgram *program = shader_state->user_program; CoglShader *shader = program->attached_shaders->data; gl_program = shader->gl_handle; } else gl_program = shader_state->gl_program; GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program)); _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_ARBFP); if (shader_state->user_program == COGL_INVALID_HANDLE) { UpdateConstantsState state; state.unit = 0; state.shader_state = shader_state; /* If this arbfp program was last used with a different pipeline * then we need to ensure we update all program.local params */ state.update_all = pipeline != shader_state->last_used_for_pipeline; cogl_pipeline_foreach_layer (pipeline, update_constants_cb, &state); } else { CoglProgram *program = shader_state->user_program; CoglBool program_changed; /* If the shader has changed since it was last flushed then we need to update all uniforms */ program_changed = program->age != shader_state->user_program_age; _cogl_program_flush_uniforms (program, gl_program, program_changed); shader_state->user_program_age = program->age; } /* We need to track what pipeline used this arbfp program last since * we will need to update program.local params when switching * between different pipelines. */ shader_state->last_used_for_pipeline = pipeline; return TRUE; } static void _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify ( CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx))) dirty_shader_state (pipeline); } /* NB: layers are considered immutable once they have any dependants * so although multiple pipelines can end up depending on a single * static layer, we can guarantee that if a layer is being *changed* * then it can only have one pipeline depending on it. * * XXX: Don't forget this is *pre* change, we can't read the new value * yet! */ static void _cogl_pipeline_fragend_arbfp_layer_pre_change_notify ( CoglPipeline *owner, CoglPipelineLayer *layer, CoglPipelineLayerState change) { CoglPipelineShaderState *shader_state = get_shader_state (owner); _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!shader_state) return; if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx))) { dirty_shader_state (owner); return; } if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT) { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); shader_state->unit_state[unit_index].dirty_combine_constant = TRUE; } /* TODO: we could be saving snippets of texture combine code along * with each layer and then when a layer changes we would just free * the snippet. */ return; } const CoglPipelineFragend _cogl_pipeline_arbfp_fragend = { _cogl_pipeline_fragend_arbfp_start, _cogl_pipeline_fragend_arbfp_add_layer, _cogl_pipeline_fragend_arbfp_passthrough, _cogl_pipeline_fragend_arbfp_end, _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify, NULL, _cogl_pipeline_fragend_arbfp_layer_pre_change_notify }; #endif /* COGL_PIPELINE_FRAGEND_ARBFP */ muffin-5.2.1/cogl/cogl/driver/gl/gl/cogl-driver-gl.c0000664000175000017500000006065614211404421022301 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-private.h" #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-feature-private.h" #include "cogl-renderer-private.h" #include "cogl-error-private.h" #include "cogl-framebuffer-gl-private.h" #include "cogl-texture-2d-gl-private.h" #include "cogl-attribute-gl-private.h" #include "cogl-clip-stack-gl-private.h" #include "cogl-buffer-gl-private.h" static CoglBool _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, GLenum gl_int_format, CoglPixelFormat *out_format) { /* It doesn't really matter we convert to exact same format (some have no cogl match anyway) since format is re-matched against cogl when getting or setting texture image data. */ switch (gl_int_format) { case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: /* Cogl only supports one single-component texture so if we have * ended up with a red texture then it is probably being used as * a component-alpha texture */ case GL_RED: *out_format = COGL_PIXEL_FORMAT_A_8; return TRUE; case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: case GL_LUMINANCE12: case GL_LUMINANCE16: *out_format = COGL_PIXEL_FORMAT_G_8; return TRUE; case GL_RG: *out_format = COGL_PIXEL_FORMAT_RG_88; return TRUE; case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2: *out_format = COGL_PIXEL_FORMAT_RGB_888; return TRUE; case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: *out_format = COGL_PIXEL_FORMAT_RGBA_8888; return TRUE; } return FALSE; } static CoglPixelFormat _cogl_driver_pixel_format_to_gl_with_target (CoglContext *context, CoglPixelFormat format, CoglPixelFormat target_format, GLenum *out_glintformat, GLenum *out_glformat, GLenum *out_gltype) { CoglPixelFormat required_format; GLenum glintformat = 0; GLenum glformat = 0; GLenum gltype = 0; required_format = format; /* Find GL equivalents */ switch (format) { case COGL_PIXEL_FORMAT_A_8: /* If the driver doesn't natively support alpha textures then we * will use a red component texture with a swizzle to implement * the texture */ if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) == 0) { glintformat = GL_RED; glformat = GL_RED; } else { glintformat = GL_ALPHA; glformat = GL_ALPHA; } gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_G_8: glintformat = GL_LUMINANCE; glformat = GL_LUMINANCE; gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_RG_88: if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RG)) { glintformat = GL_RG; glformat = GL_RG; } else { /* If red-green textures aren't supported then we'll use RGB * as an internal format. Note this should only end up * mattering for downloading the data because Cogl will * refuse to allocate a texture with RG components if RG * textures aren't supported */ glintformat = GL_RGB; glformat = GL_RGB; required_format = COGL_PIXEL_FORMAT_RGB_888; } gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_RGB_888: glintformat = GL_RGB; glformat = GL_RGB; gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_BGR_888: glintformat = GL_RGB; glformat = GL_BGR; gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_RGBA_8888: case COGL_PIXEL_FORMAT_RGBA_8888_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_BYTE; break; case COGL_PIXEL_FORMAT_BGRA_8888: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: glintformat = GL_RGBA; /* If the driver has texture_swizzle, pretend internal * and buffer format are the same here, the pixels * will be flipped through this extension. */ if (target_format == format && _cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) glformat = GL_RGBA; else glformat = GL_BGRA; gltype = GL_UNSIGNED_BYTE; break; /* The following two types of channel ordering * have no GL equivalent unless defined using * system word byte ordering */ case COGL_PIXEL_FORMAT_ARGB_8888: case COGL_PIXEL_FORMAT_ARGB_8888_PRE: glintformat = GL_RGBA; glformat = GL_BGRA; #if G_BYTE_ORDER == G_LITTLE_ENDIAN gltype = GL_UNSIGNED_INT_8_8_8_8; #else gltype = GL_UNSIGNED_INT_8_8_8_8_REV; #endif break; case COGL_PIXEL_FORMAT_ABGR_8888: case COGL_PIXEL_FORMAT_ABGR_8888_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; #if G_BYTE_ORDER == G_LITTLE_ENDIAN gltype = GL_UNSIGNED_INT_8_8_8_8; #else gltype = GL_UNSIGNED_INT_8_8_8_8_REV; #endif break; case COGL_PIXEL_FORMAT_RGBA_1010102: case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_INT_10_10_10_2; break; case COGL_PIXEL_FORMAT_BGRA_1010102: case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: glintformat = GL_RGBA; glformat = GL_BGRA; gltype = GL_UNSIGNED_INT_10_10_10_2; break; case COGL_PIXEL_FORMAT_ABGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_INT_2_10_10_10_REV; break; case COGL_PIXEL_FORMAT_ARGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: glintformat = GL_RGBA; glformat = GL_BGRA; gltype = GL_UNSIGNED_INT_2_10_10_10_REV; break; /* The following three types of channel ordering * are always defined using system word byte * ordering (even according to GLES spec) */ case COGL_PIXEL_FORMAT_RGB_565: glintformat = GL_RGB; glformat = GL_RGB; gltype = GL_UNSIGNED_SHORT_5_6_5; break; case COGL_PIXEL_FORMAT_RGBA_4444: case COGL_PIXEL_FORMAT_RGBA_4444_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_SHORT_4_4_4_4; break; case COGL_PIXEL_FORMAT_RGBA_5551: case COGL_PIXEL_FORMAT_RGBA_5551_PRE: glintformat = GL_RGBA; glformat = GL_RGBA; gltype = GL_UNSIGNED_SHORT_5_5_5_1; break; case COGL_PIXEL_FORMAT_DEPTH_16: glintformat = GL_DEPTH_COMPONENT16; glformat = GL_DEPTH_COMPONENT; gltype = GL_UNSIGNED_SHORT; break; case COGL_PIXEL_FORMAT_DEPTH_32: glintformat = GL_DEPTH_COMPONENT32; glformat = GL_DEPTH_COMPONENT; gltype = GL_UNSIGNED_INT; break; case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: glintformat = GL_DEPTH_STENCIL; glformat = GL_DEPTH_STENCIL; gltype = GL_UNSIGNED_INT_24_8; break; case COGL_PIXEL_FORMAT_ANY: case COGL_PIXEL_FORMAT_YUV: g_assert_not_reached (); break; } /* All of the pixel formats are handled above so if this hits then we've been given an invalid pixel format */ g_assert (glformat != 0); if (out_glintformat != NULL) *out_glintformat = glintformat; if (out_glformat != NULL) *out_glformat = glformat; if (out_gltype != NULL) *out_gltype = gltype; return required_format; } static CoglPixelFormat _cogl_driver_pixel_format_to_gl (CoglContext *context, CoglPixelFormat format, GLenum *out_glintformat, GLenum *out_glformat, GLenum *out_gltype) { return _cogl_driver_pixel_format_to_gl_with_target (context, format, format, out_glintformat, out_glformat, out_gltype); } static CoglBool _cogl_get_gl_version (CoglContext *ctx, int *major_out, int *minor_out) { const char *version_string; /* Get the OpenGL version number */ if ((version_string = _cogl_context_get_gl_version (ctx)) == NULL) return FALSE; return _cogl_gl_util_parse_gl_version (version_string, major_out, minor_out); } static CoglBool check_gl_version (CoglContext *ctx, char **gl_extensions, CoglError **error) { int major, minor; if (!_cogl_get_gl_version (ctx, &major, &minor)) { _cogl_set_error (error, COGL_DRIVER_ERROR, COGL_DRIVER_ERROR_UNKNOWN_VERSION, "The OpenGL version could not be determined"); return FALSE; } /* GL 1.3 supports all of the required functionality in core */ if (COGL_CHECK_GL_VERSION (major, minor, 1, 3)) return TRUE; /* OpenGL 1.2 is only supported if we have the multitexturing extension */ if (!_cogl_check_extension ("GL_ARB_multitexture", gl_extensions)) { _cogl_set_error (error, COGL_DRIVER_ERROR, COGL_DRIVER_ERROR_INVALID_VERSION, "The OpenGL driver is missing " "the GL_ARB_multitexture extension"); return FALSE; } /* OpenGL 1.2 is required */ if (!COGL_CHECK_GL_VERSION (major, minor, 1, 2)) { _cogl_set_error (error, COGL_DRIVER_ERROR, COGL_DRIVER_ERROR_INVALID_VERSION, "The OpenGL version of your driver (%i.%i) " "is not compatible with Cogl", major, minor); return FALSE; } return TRUE; } static CoglBool _cogl_driver_update_features (CoglContext *ctx, CoglError **error) { CoglFeatureFlags flags = 0; unsigned long private_features [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_N_PRIVATE_FEATURES)] = { 0 }; char **gl_extensions; int gl_major = 0, gl_minor = 0; int i; /* We have to special case getting the pointer to the glGetString* functions because we need to use them to determine what functions we can expect */ ctx->glGetString = (void *) _cogl_renderer_get_proc_address (ctx->display->renderer, "glGetString", TRUE); ctx->glGetStringi = (void *) _cogl_renderer_get_proc_address (ctx->display->renderer, "glGetStringi", TRUE); ctx->glGetIntegerv = (void *) _cogl_renderer_get_proc_address (ctx->display->renderer, "glGetIntegerv", TRUE); gl_extensions = _cogl_context_get_gl_extensions (ctx); if (!check_gl_version (ctx, gl_extensions, error)) return FALSE; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS))) { char *all_extensions = g_strjoinv (" ", gl_extensions); COGL_NOTE (WINSYS, "Checking features\n" " GL_VENDOR: %s\n" " GL_RENDERER: %s\n" " GL_VERSION: %s\n" " GL_EXTENSIONS: %s", ctx->glGetString (GL_VENDOR), ctx->glGetString (GL_RENDERER), _cogl_context_get_gl_version (ctx), all_extensions); free (all_extensions); } _cogl_get_gl_version (ctx, &gl_major, &gl_minor); _cogl_gpu_info_init (ctx, &ctx->gpu); ctx->glsl_major = 1; ctx->glsl_minor = 1; if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0)) { const char *glsl_version = (char *)ctx->glGetString (GL_SHADING_LANGUAGE_VERSION); _cogl_gl_util_parse_gl_version (glsl_version, &ctx->glsl_major, &ctx->glsl_minor); } if (COGL_CHECK_GL_VERSION (ctx->glsl_major, ctx->glsl_minor, 1, 2)) /* We want to use version 120 if it is available so that the * gl_PointCoord can be used. */ ctx->glsl_version_to_use = 120; else ctx->glsl_version_to_use = 110; flags = (COGL_FEATURE_TEXTURE_READ_PIXELS | COGL_FEATURE_UNSIGNED_INT_INDICES | COGL_FEATURE_DEPTH_RANGE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE); if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4)) COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE); _cogl_feature_check_ext_functions (ctx, gl_major, gl_minor, gl_extensions); if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0) || _cogl_check_extension ("GL_ARB_texture_non_power_of_two", gl_extensions)) { flags |= COGL_FEATURE_TEXTURE_NPOT | COGL_FEATURE_TEXTURE_NPOT_BASIC | COGL_FEATURE_TEXTURE_NPOT_MIPMAP | COGL_FEATURE_TEXTURE_NPOT_REPEAT; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT, TRUE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE); } if (_cogl_check_extension ("GL_MESA_pack_invert", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_MESA_PACK_INVERT, TRUE); if (ctx->glGenRenderbuffers) { flags |= COGL_FEATURE_OFFSCREEN; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS, TRUE); } if (ctx->glBlitFramebuffer) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT, TRUE); if (ctx->glRenderbufferStorageMultisampleIMG) { flags |= COGL_FEATURE_OFFSCREEN_MULTISAMPLE; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE, TRUE); } if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0) || _cogl_check_extension ("GL_ARB_depth_texture", gl_extensions)) { flags |= COGL_FEATURE_DEPTH_TEXTURE; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_DEPTH_TEXTURE, TRUE); } if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 1) || _cogl_check_extension ("GL_EXT_pixel_buffer_object", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_PBOS, TRUE); if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4) || _cogl_check_extension ("GL_EXT_blend_color", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_BLEND_CONSTANT, TRUE); if (ctx->glGenPrograms) { flags |= COGL_FEATURE_SHADERS_ARBFP; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_ARBFP, TRUE); } if (ctx->glCreateProgram) { flags |= COGL_FEATURE_SHADERS_GLSL; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, TRUE); } else { /* If all of the old GLSL extensions are available then we can fake * the GL 2.0 GLSL support by diverting to the old function names */ if (ctx->glCreateProgramObject && /* GL_ARB_shader_objects */ ctx->glVertexAttribPointer && /* GL_ARB_vertex_shader */ _cogl_check_extension ("GL_ARB_fragment_shader", gl_extensions)) { ctx->glCreateShader = ctx->glCreateShaderObject; ctx->glCreateProgram = ctx->glCreateProgramObject; ctx->glDeleteShader = ctx->glDeleteObject; ctx->glDeleteProgram = ctx->glDeleteObject; ctx->glAttachShader = ctx->glAttachObject; ctx->glUseProgram = ctx->glUseProgramObject; ctx->glGetProgramInfoLog = ctx->glGetInfoLog; ctx->glGetShaderInfoLog = ctx->glGetInfoLog; ctx->glGetShaderiv = ctx->glGetObjectParameteriv; ctx->glGetProgramiv = ctx->glGetObjectParameteriv; ctx->glDetachShader = ctx->glDetachObject; ctx->glGetAttachedShaders = ctx->glGetAttachedObjects; /* FIXME: there doesn't seem to be an equivalent for glIsShader * and glIsProgram. This doesn't matter for now because Cogl * doesn't use these but if we add support for simulating a * GLES2 context on top of regular GL then we'll need to do * something here */ flags |= COGL_FEATURE_SHADERS_GLSL; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, TRUE); } } if ((COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0) || _cogl_check_extension ("GL_ARB_point_sprite", gl_extensions)) && /* If GLSL is supported then we only enable point sprite support * too if we have glsl >= 1.2 otherwise we don't have the * gl_PointCoord builtin which we depend on in the glsl backend. */ (!COGL_FLAGS_GET (ctx->features, COGL_FEATURE_ID_GLSL) || COGL_CHECK_GL_VERSION (ctx->glsl_major, ctx->glsl_minor, 1, 2))) { flags |= COGL_FEATURE_POINT_SPRITE; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE); } if (ctx->glGenBuffers) { COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_VBOS, TRUE); flags |= (COGL_FEATURE_MAP_BUFFER_FOR_READ | COGL_FEATURE_MAP_BUFFER_FOR_WRITE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, TRUE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); } if (_cogl_check_extension ("GL_ARB_texture_rectangle", gl_extensions)) { flags |= COGL_FEATURE_TEXTURE_RECTANGLE; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_RECTANGLE, TRUE); } if (ctx->glTexImage3D) { flags |= COGL_FEATURE_TEXTURE_3D; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE); } if (ctx->glEGLImageTargetTexture2D) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE, TRUE); if (_cogl_check_extension ("GL_EXT_packed_depth_stencil", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL, TRUE); if (ctx->glGenSamplers) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS, TRUE); if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 3) || _cogl_check_extension ("GL_ARB_texture_swizzle", gl_extensions) || _cogl_check_extension ("GL_EXT_texture_swizzle", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE, TRUE); /* The per-vertex point size is only available via GLSL with the * gl_PointSize builtin. This is only available in GL 2.0 (not the * GLSL extensions) */ if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0)) { COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE, TRUE); } if (ctx->driver == COGL_DRIVER_GL) { int max_clip_planes = 0; /* Features which are not available in GL 3 */ COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_GL_FIXED, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ALPHA_TEST, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_QUADS, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES, TRUE); GE( ctx, glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) ); if (max_clip_planes >= 4) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES, TRUE); } COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ANY_GL, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_FORMAT_CONVERSION, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_BLEND_CONSTANT, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS, TRUE); COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL, TRUE); if (ctx->glFenceSync) COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_FENCE, TRUE); if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0) || _cogl_check_extension ("GL_ARB_texture_rg", gl_extensions)) COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_RG, TRUE); /* Cache features */ for (i = 0; i < G_N_ELEMENTS (private_features); i++) ctx->private_features[i] |= private_features[i]; ctx->feature_flags |= flags; g_strfreev (gl_extensions); if (!COGL_FLAGS_GET (private_features, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && !COGL_FLAGS_GET (private_features, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) { _cogl_set_error (error, COGL_DRIVER_ERROR, COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND, "The GL_ARB_texture_swizzle extension is required " "to use the GL3 driver"); return FALSE; } return TRUE; } const CoglDriverVtable _cogl_driver_gl = { _cogl_driver_pixel_format_from_gl_internal, _cogl_driver_pixel_format_to_gl, _cogl_driver_pixel_format_to_gl_with_target, _cogl_driver_update_features, _cogl_offscreen_gl_allocate, _cogl_offscreen_gl_free, _cogl_framebuffer_gl_flush_state, _cogl_framebuffer_gl_clear, _cogl_framebuffer_gl_query_bits, _cogl_framebuffer_gl_finish, _cogl_framebuffer_gl_discard_buffers, _cogl_framebuffer_gl_draw_attributes, _cogl_framebuffer_gl_draw_indexed_attributes, _cogl_framebuffer_gl_read_pixels_into_bitmap, _cogl_texture_2d_gl_free, _cogl_texture_2d_gl_can_create, _cogl_texture_2d_gl_init, _cogl_texture_2d_gl_allocate, _cogl_texture_2d_gl_copy_from_framebuffer, _cogl_texture_2d_gl_get_gl_handle, _cogl_texture_2d_gl_generate_mipmap, _cogl_texture_2d_gl_copy_from_bitmap, _cogl_texture_2d_gl_get_data, _cogl_gl_flush_attributes_state, _cogl_clip_stack_gl_flush, _cogl_buffer_gl_create, _cogl_buffer_gl_destroy, _cogl_buffer_gl_map_range, _cogl_buffer_gl_unmap, _cogl_buffer_gl_set_data, }; muffin-5.2.1/cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h0000664000175000017500000000276714211404421027510 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifndef __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H #define __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H #include "cogl-pipeline-private.h" extern const CoglPipelineProgend _cogl_pipeline_fixed_arbfp_progend; #endif /* __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c0000664000175000017500000004777114211404421024002 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Matthew Allum * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-private.h" #include "cogl-util.h" #include "cogl-bitmap.h" #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" #include "cogl-pipeline.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-primitives.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-util-gl-private.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" #include #include #include #ifndef GL_TEXTURE_SWIZZLE_RGBA #define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 #endif static GLuint _cogl_texture_driver_gen (CoglContext *ctx, GLenum gl_target, CoglPixelFormat internal_format) { GLuint tex; GE (ctx, glGenTextures (1, &tex)); _cogl_bind_gl_texture_transient (gl_target, tex, FALSE); switch (gl_target) { case GL_TEXTURE_2D: case GL_TEXTURE_3D: /* In case automatic mipmap generation gets disabled for this * texture but a minification filter depending on mipmap * interpolation is selected then we initialize the max mipmap * level to 0 so OpenGL will consider the texture storage to be * "complete". */ #ifdef HAVE_COGL_GL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL)) GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MAX_LEVEL, 0)); #endif /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ); break; case GL_TEXTURE_RECTANGLE_ARB: /* Texture rectangles already default to GL_LINEAR so nothing needs to be done */ break; default: g_assert_not_reached(); } /* If the driver doesn't support alpha textures directly then we'll * fake them by setting the swizzle parameters */ if (internal_format == COGL_PIXEL_FORMAT_A_8 && !_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) { static const GLint red_swizzle[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED }; GE( ctx, glTexParameteriv (gl_target, GL_TEXTURE_SWIZZLE_RGBA, red_swizzle) ); } /* If swizzle extension is available, prefer it to flip bgra buffers to rgba */ if ((internal_format == COGL_PIXEL_FORMAT_BGRA_8888 || internal_format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) && _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) { static const GLint bgra_swizzle[] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA }; GE( ctx, glTexParameteriv (gl_target, GL_TEXTURE_SWIZZLE_RGBA, bgra_swizzle) ); } return tex; } /* OpenGL - unlike GLES - can upload a sub region of pixel data from a larger * source buffer */ static void prep_gl_for_pixels_upload_full (CoglContext *ctx, int pixels_rowstride, int image_height, int pixels_src_x, int pixels_src_y, int pixels_bpp) { GE( ctx, glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); GE( ctx, glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); GE( ctx, glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) GE( ctx, glPixelStorei (GL_UNPACK_IMAGE_HEIGHT, image_height) ); _cogl_texture_gl_prep_alignment_for_pixels_upload (ctx, pixels_rowstride); } static void _cogl_texture_driver_prep_gl_for_pixels_upload (CoglContext *ctx, int pixels_rowstride, int pixels_bpp) { prep_gl_for_pixels_upload_full (ctx, pixels_rowstride, 0, 0, 0, pixels_bpp); } /* OpenGL - unlike GLES - can download pixel data into a sub region of * a larger destination buffer */ static void prep_gl_for_pixels_download_full (CoglContext *ctx, int image_width, int pixels_rowstride, int image_height, int pixels_src_x, int pixels_src_y, int pixels_bpp) { GE( ctx, glPixelStorei (GL_PACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); GE( ctx, glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) ); GE( ctx, glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) ); if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) GE( ctx, glPixelStorei (GL_PACK_IMAGE_HEIGHT, image_height) ); _cogl_texture_gl_prep_alignment_for_pixels_download (ctx, pixels_bpp, image_width, pixels_rowstride); } static void _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx, int image_width, int pixels_rowstride, int pixels_bpp) { prep_gl_for_pixels_download_full (ctx, pixels_rowstride, image_width, 0 /* image height */, 0, 0, /* pixels_src_x/y */ pixels_bpp); } static CoglBool _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, CoglTexture *texture, CoglBool is_foreign, int src_x, int src_y, int dst_x, int dst_y, int width, int height, int level, CoglBitmap *source_bmp, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { GLenum gl_target; GLuint gl_handle; uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); CoglBool status = TRUE; CoglError *internal_error = NULL; int level_width; int level_height; cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error); /* NB: _cogl_bitmap_gl_bind() may return NULL when successfull so we * have to explicitly check the cogl error pointer to catch * problems... */ if (internal_error) { _cogl_propagate_error (error, internal_error); return FALSE; } /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, cogl_bitmap_get_rowstride (source_bmp), 0, src_x, src_y, bpp); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); _cogl_texture_get_level_size (texture, level, &level_width, &level_height, NULL); if (level_width == width && level_height == height) { /* GL gets upset if you use glTexSubImage2D to initialize the * contents of a mipmap level so we make sure to use * glTexImage2D if we are uploading a full mipmap level. */ ctx->glTexImage2D (gl_target, level, _cogl_texture_gl_get_format (texture), width, height, 0, source_gl_format, source_gl_type, data); } else { /* GL gets upset if you use glTexSubImage2D to initialize the * contents of a mipmap level so if this is the first time * we've seen a request to upload to this level we call * glTexImage2D first to assert that the storage for this * level exists. */ if (texture->max_level < level) { ctx->glTexImage2D (gl_target, level, _cogl_texture_gl_get_format (texture), level_width, level_height, 0, source_gl_format, source_gl_type, NULL); } ctx->glTexSubImage2D (gl_target, level, dst_x, dst_y, width, height, source_gl_format, source_gl_type, data); } if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; _cogl_bitmap_gl_unbind (source_bmp); return status; } static CoglBool _cogl_texture_driver_upload_to_gl (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); CoglBool status = TRUE; CoglError *internal_error = NULL; data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, /* hints */ &internal_error); /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we * have to explicitly check the cogl error pointer to catch * problems... */ if (internal_error) { _cogl_propagate_error (error, internal_error); return FALSE; } /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, cogl_bitmap_get_rowstride (source_bmp), 0, 0, 0, bpp); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage2D (gl_target, 0, internal_gl_format, cogl_bitmap_get_width (source_bmp), cogl_bitmap_get_height (source_bmp), 0, source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; _cogl_bitmap_gl_unbind (source_bmp); return status; } static CoglBool _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, GLint height, GLint depth, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); CoglBool status = TRUE; data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (!data) return FALSE; /* Setup gl alignment to match rowstride and top-left corner */ prep_gl_for_pixels_upload_full (ctx, cogl_bitmap_get_rowstride (source_bmp), (cogl_bitmap_get_height (source_bmp) / depth), 0, 0, bpp); _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage3D (gl_target, 0, /* level */ internal_gl_format, cogl_bitmap_get_width (source_bmp), height, depth, 0, source_gl_format, source_gl_type, data); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; _cogl_bitmap_gl_unbind (source_bmp); return status; } static CoglBool _cogl_texture_driver_gl_get_tex_image (CoglContext *ctx, GLenum gl_target, GLenum dest_gl_format, GLenum dest_gl_type, uint8_t *dest) { GE (ctx, glGetTexImage (gl_target, 0, /* level */ dest_gl_format, dest_gl_type, (GLvoid *)dest)); return TRUE; } static CoglBool _cogl_texture_driver_size_supported_3d (CoglContext *ctx, GLenum gl_target, GLenum gl_format, GLenum gl_type, int width, int height, int depth) { GLenum proxy_target; GLint new_width = 0; if (gl_target == GL_TEXTURE_3D) proxy_target = GL_PROXY_TEXTURE_3D; else /* Unknown target, assume it's not supported */ return FALSE; /* Proxy texture allows for a quick check for supported size */ GE( ctx, glTexImage3D (proxy_target, 0, GL_RGBA, width, height, depth, 0 /* border */, gl_format, gl_type, NULL) ); GE( ctx, glGetTexLevelParameteriv (proxy_target, 0, GL_TEXTURE_WIDTH, &new_width) ); return new_width != 0; } static CoglBool _cogl_texture_driver_size_supported (CoglContext *ctx, GLenum gl_target, GLenum gl_intformat, GLenum gl_format, GLenum gl_type, int width, int height) { GLenum proxy_target; GLint new_width = 0; if (gl_target == GL_TEXTURE_2D) proxy_target = GL_PROXY_TEXTURE_2D; #if HAVE_COGL_GL else if (gl_target == GL_TEXTURE_RECTANGLE_ARB) proxy_target = GL_PROXY_TEXTURE_RECTANGLE_ARB; #endif else /* Unknown target, assume it's not supported */ return FALSE; /* Proxy texture allows for a quick check for supported size */ GE( ctx, glTexImage2D (proxy_target, 0, gl_intformat, width, height, 0 /* border */, gl_format, gl_type, NULL) ); GE( ctx, glGetTexLevelParameteriv (proxy_target, 0, GL_TEXTURE_WIDTH, &new_width) ); return new_width != 0; } static void _cogl_texture_driver_try_setting_gl_border_color (CoglContext *ctx, GLuint gl_target, const GLfloat *transparent_color) { /* Use a transparent border color so that we can leave the color buffer alone when using texture co-ordinates outside of the texture */ GE( ctx, glTexParameterfv (gl_target, GL_TEXTURE_BORDER_COLOR, transparent_color) ); } static CoglBool _cogl_texture_driver_allows_foreign_gl_target (CoglContext *ctx, GLenum gl_target) { /* GL_ARB_texture_rectangle textures are supported if they are created from foreign because some chipsets have trouble with GL_ARB_texture_non_power_of_two. There is no Cogl call to create them directly to emphasize the fact that they don't work fully (for example, no mipmapping and complicated shader support) */ /* Allow 2-dimensional or rectangle textures only */ if (gl_target != GL_TEXTURE_2D && gl_target != GL_TEXTURE_RECTANGLE_ARB) return FALSE; return TRUE; } static CoglPixelFormat _cogl_texture_driver_find_best_gl_get_data_format (CoglContext *context, CoglPixelFormat format, CoglPixelFormat target_format, GLenum *closest_gl_format, GLenum *closest_gl_type) { return context->driver_vtable->pixel_format_to_gl_with_target (context, format, target_format, NULL, /* don't need */ closest_gl_format, closest_gl_type); } const CoglTextureDriver _cogl_texture_driver_gl = { _cogl_texture_driver_gen, _cogl_texture_driver_prep_gl_for_pixels_upload, _cogl_texture_driver_upload_subregion_to_gl, _cogl_texture_driver_upload_to_gl, _cogl_texture_driver_upload_to_gl_3d, _cogl_texture_driver_prep_gl_for_pixels_download, _cogl_texture_driver_gl_get_tex_image, _cogl_texture_driver_size_supported, _cogl_texture_driver_size_supported_3d, _cogl_texture_driver_try_setting_gl_border_color, _cogl_texture_driver_allows_foreign_gl_target, _cogl_texture_driver_find_best_gl_get_data_format }; muffin-5.2.1/cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h0000664000175000017500000000273114211404421026352 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_FRAGEND_ARBFP_PRIVATE_H #define __COGL_PIPELINE_FRAGEND_ARBFP_PRIVATE_H #include "cogl-pipeline-private.h" extern const CoglPipelineFragend _cogl_pipeline_arbfp_fragend; #endif /* __COGL_PIPELINE_ARBFP_PRIVATE_H */ muffin-5.2.1/cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c0000664000175000017500000000761114211404421026024 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-pipeline-private.h" #include "cogl-pipeline-state-private.h" #ifdef COGL_PIPELINE_PROGEND_FIXED_ARBFP #include "cogl-context.h" #include "cogl-context-private.h" #include "cogl-framebuffer-private.h" #include "cogl-program-private.h" static CoglBool _cogl_pipeline_progend_fixed_arbfp_start (CoglPipeline *pipeline) { CoglHandle user_program; _COGL_GET_CONTEXT (ctx, FALSE); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED))) return FALSE; if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED)) return FALSE; /* Vertex snippets are only supported in the GLSL fragend */ if (_cogl_pipeline_has_vertex_snippets (pipeline)) return FALSE; /* Validate that we can handle the fragment state using ARBfp */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP)) return FALSE; /* Fragment snippets are only supported in the GLSL fragend */ if (_cogl_pipeline_has_fragment_snippets (pipeline)) return FALSE; user_program = cogl_pipeline_get_user_program (pipeline); if (user_program && _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_ARBFP) return FALSE; /* The ARBfp progend can't handle the per-vertex point size * attribute */ if (cogl_pipeline_get_per_vertex_point_size (pipeline)) return FALSE; return TRUE; } static void _cogl_pipeline_progend_fixed_arbfp_pre_paint (CoglPipeline *pipeline, CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; if (ctx->current_projection_entry) _cogl_matrix_entry_flush_to_gl_builtins (ctx, ctx->current_projection_entry, COGL_MATRIX_PROJECTION, framebuffer, FALSE /* enable flip */); if (ctx->current_modelview_entry) _cogl_matrix_entry_flush_to_gl_builtins (ctx, ctx->current_modelview_entry, COGL_MATRIX_MODELVIEW, framebuffer, FALSE /* enable flip */); } const CoglPipelineProgend _cogl_pipeline_fixed_arbfp_progend = { COGL_PIPELINE_VERTEND_FIXED, COGL_PIPELINE_FRAGEND_ARBFP, _cogl_pipeline_progend_fixed_arbfp_start, NULL, /* end */ NULL, /* pre_change_notify */ NULL, /* layer_pre_change_notify */ _cogl_pipeline_progend_fixed_arbfp_pre_paint }; #endif /* COGL_PIPELINE_PROGEND_FIXED_ARBFP */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-texture-gl-private.h0000664000175000017500000000473514211404421023555 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #ifndef _COGL_TEXTURE_GL_PRIVATE_H_ #define _COGL_TEXTURE_GL_PRIVATE_H_ #include "cogl-context.h" void _cogl_texture_gl_prep_alignment_for_pixels_upload (CoglContext *ctx, int pixels_rowstride); void _cogl_texture_gl_prep_alignment_for_pixels_download (CoglContext *ctx, int bpp, int width, int rowstride); void _cogl_texture_gl_flush_legacy_texobj_wrap_modes (CoglTexture *texture, unsigned int wrap_mode_s, unsigned int wrap_mode_t, unsigned int wrap_mode_p); void _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture, unsigned int min_filter, unsigned int mag_filter); void _cogl_texture_gl_maybe_update_max_level (CoglTexture *texture, int max_level); void _cogl_texture_gl_generate_mipmaps (CoglTexture *texture); GLenum _cogl_texture_gl_get_format (CoglTexture *texture); #endif /* _COGL_TEXTURE_GL_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-util-gl.c0000664000175000017500000001267214211404421021354 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012, 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-types.h" #include "cogl-context-private.h" #include "cogl-error-private.h" #include "cogl-util-gl-private.h" #ifdef COGL_GL_DEBUG /* GL error to string conversion */ static const struct { GLuint error_code; const char *error_string; } gl_errors[] = { { GL_NO_ERROR, "No error" }, { GL_INVALID_ENUM, "Invalid enumeration value" }, { GL_INVALID_VALUE, "Invalid value" }, { GL_INVALID_OPERATION, "Invalid operation" }, #ifdef HAVE_COGL_GL { GL_STACK_OVERFLOW, "Stack overflow" }, { GL_STACK_UNDERFLOW, "Stack underflow" }, #endif { GL_OUT_OF_MEMORY, "Out of memory" }, #ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "Invalid framebuffer operation" } #endif }; static const unsigned int n_gl_errors = G_N_ELEMENTS (gl_errors); const char * _cogl_gl_error_to_string (GLenum error_code) { int i; for (i = 0; i < n_gl_errors; i++) { if (gl_errors[i].error_code == error_code) return gl_errors[i].error_string; } return "Unknown GL error"; } #endif /* COGL_GL_DEBUG */ GLenum _cogl_gl_util_get_error (CoglContext *ctx) { GLenum gl_error = ctx->glGetError (); if (gl_error != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) return gl_error; else return GL_NO_ERROR; } void _cogl_gl_util_clear_gl_errors (CoglContext *ctx) { GLenum gl_error; while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) ; } CoglBool _cogl_gl_util_catch_out_of_memory (CoglContext *ctx, CoglError **error) { GLenum gl_error; CoglBool out_of_memory = FALSE; while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) { if (gl_error == GL_OUT_OF_MEMORY) out_of_memory = TRUE; #ifdef COGL_GL_DEBUG else { g_warning ("%s: GL error (%d): %s\n", G_STRLOC, gl_error, _cogl_gl_error_to_string (gl_error)); } #endif } if (out_of_memory) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_NO_MEMORY, "Out of memory"); return TRUE; } return FALSE; } void _cogl_gl_util_get_texture_target_string (CoglTextureType texture_type, const char **target_string_out, const char **swizzle_out) { const char *target_string, *tex_coord_swizzle; switch (texture_type) { #if 0 /* TODO */ case COGL_TEXTURE_TYPE_1D: target_string = "1D"; tex_coord_swizzle = "s"; break; #endif case COGL_TEXTURE_TYPE_2D: target_string = "2D"; tex_coord_swizzle = "st"; break; case COGL_TEXTURE_TYPE_3D: target_string = "3D"; tex_coord_swizzle = "stp"; break; case COGL_TEXTURE_TYPE_RECTANGLE: target_string = "2DRect"; tex_coord_swizzle = "st"; break; default: target_string = "Unknown"; tex_coord_swizzle = NULL; g_assert_not_reached (); } if (target_string_out) *target_string_out = target_string; if (swizzle_out) *swizzle_out = tex_coord_swizzle; } CoglBool _cogl_gl_util_parse_gl_version (const char *version_string, int *major_out, int *minor_out) { const char *major_end, *minor_end; int major = 0, minor = 0; /* Extract the major number */ for (major_end = version_string; *major_end >= '0' && *major_end <= '9'; major_end++) major = (major * 10) + *major_end - '0'; /* If there were no digits or the major number isn't followed by a dot then it is invalid */ if (major_end == version_string || *major_end != '.') return FALSE; /* Extract the minor number */ for (minor_end = major_end + 1; *minor_end >= '0' && *minor_end <= '9'; minor_end++) minor = (minor * 10) + *minor_end - '0'; /* If there were no digits or there is an unexpected character then it is invalid */ if (minor_end == major_end + 1 || (*minor_end && *minor_end != ' ' && *minor_end != '.')) return FALSE; *major_out = major; *minor_out = minor; return TRUE; } muffin-5.2.1/cogl/cogl/driver/gl/cogl-attribute-gl.c0000664000175000017500000004507714211404421022407 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2011,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-private.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" #include "cogl-context-private.h" #include "cogl-attribute.h" #include "cogl-attribute-private.h" #include "cogl-attribute-gl-private.h" #include "cogl-pipeline-progend-glsl-private.h" #include "cogl-buffer-gl-private.h" typedef struct _ForeachChangedBitState { CoglContext *context; const CoglBitmask *new_bits; CoglPipeline *pipeline; } ForeachChangedBitState; static CoglBool toggle_builtin_attribute_enabled_cb (int bit_num, void *user_data) { ForeachChangedBitState *state = user_data; CoglContext *context = state->context; _COGL_RETURN_VAL_IF_FAIL (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_GL_FIXED), FALSE); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) { CoglBool enabled = _cogl_bitmask_get (state->new_bits, bit_num); GLenum cap; switch (bit_num) { case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: cap = GL_COLOR_ARRAY; break; case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY: cap = GL_VERTEX_ARRAY; break; case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: cap = GL_NORMAL_ARRAY; break; default: g_assert_not_reached (); } if (enabled) GE (context, glEnableClientState (cap)); else GE (context, glDisableClientState (cap)); } #endif return TRUE; } static CoglBool toggle_texcood_attribute_enabled_cb (int bit_num, void *user_data) { ForeachChangedBitState *state = user_data; CoglContext *context = state->context; _COGL_RETURN_VAL_IF_FAIL (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_GL_FIXED), FALSE); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) { CoglBool enabled = _cogl_bitmask_get (state->new_bits, bit_num); GE( context, glClientActiveTexture (GL_TEXTURE0 + bit_num) ); if (enabled) GE( context, glEnableClientState (GL_TEXTURE_COORD_ARRAY) ); else GE( context, glDisableClientState (GL_TEXTURE_COORD_ARRAY) ); } #endif return TRUE; } static CoglBool toggle_custom_attribute_enabled_cb (int bit_num, void *user_data) { ForeachChangedBitState *state = user_data; CoglBool enabled = _cogl_bitmask_get (state->new_bits, bit_num); CoglContext *context = state->context; if (enabled) GE( context, glEnableVertexAttribArray (bit_num) ); else GE( context, glDisableVertexAttribArray (bit_num) ); return TRUE; } static void foreach_changed_bit_and_save (CoglContext *context, CoglBitmask *current_bits, const CoglBitmask *new_bits, CoglBitmaskForeachFunc callback, ForeachChangedBitState *state) { /* Get the list of bits that are different */ _cogl_bitmask_clear_all (&context->changed_bits_tmp); _cogl_bitmask_set_bits (&context->changed_bits_tmp, current_bits); _cogl_bitmask_xor_bits (&context->changed_bits_tmp, new_bits); /* Iterate over each bit to change */ state->new_bits = new_bits; _cogl_bitmask_foreach (&context->changed_bits_tmp, callback, state); /* Store the new values */ _cogl_bitmask_clear_all (current_bits); _cogl_bitmask_set_bits (current_bits, new_bits); } #ifdef COGL_PIPELINE_PROGEND_GLSL static void setup_generic_buffered_attribute (CoglContext *context, CoglPipeline *pipeline, CoglAttribute *attribute, uint8_t *base) { int name_index = attribute->name_state->name_index; int attrib_location = _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index); if (attrib_location == -1) return; GE( context, glVertexAttribPointer (attrib_location, attribute->d.buffered.n_components, attribute->d.buffered.type, attribute->normalized, attribute->d.buffered.stride, base + attribute->d.buffered.offset) ); _cogl_bitmask_set (&context->enable_custom_attributes_tmp, attrib_location, TRUE); } static void setup_generic_const_attribute (CoglContext *context, CoglPipeline *pipeline, CoglAttribute *attribute) { int name_index = attribute->name_state->name_index; int attrib_location = _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index); int columns; int i; if (attrib_location == -1) return; if (attribute->d.constant.boxed.type == COGL_BOXED_MATRIX) columns = attribute->d.constant.boxed.size; else columns = 1; /* Note: it's ok to access a COGL_BOXED_FLOAT as a matrix with only * one column... */ switch (attribute->d.constant.boxed.size) { case 1: GE( context, glVertexAttrib1fv (attrib_location, attribute->d.constant.boxed.v.matrix)); break; case 2: for (i = 0; i < columns; i++) GE( context, glVertexAttrib2fv (attrib_location + i, attribute->d.constant.boxed.v.matrix)); break; case 3: for (i = 0; i < columns; i++) GE( context, glVertexAttrib3fv (attrib_location + i, attribute->d.constant.boxed.v.matrix)); break; case 4: for (i = 0; i < columns; i++) GE( context, glVertexAttrib4fv (attrib_location + i, attribute->d.constant.boxed.v.matrix)); break; default: g_warn_if_reached (); } } #endif /* COGL_PIPELINE_PROGEND_GLSL */ static void setup_legacy_buffered_attribute (CoglContext *ctx, CoglPipeline *pipeline, CoglAttribute *attribute, uint8_t *base) { switch (attribute->name_state->name_id) { case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp, COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY, TRUE); GE (ctx, glColorPointer (attribute->d.buffered.n_components, attribute->d.buffered.type, attribute->d.buffered.stride, base + attribute->d.buffered.offset)); break; case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp, COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY, TRUE); GE (ctx, glNormalPointer (attribute->d.buffered.type, attribute->d.buffered.stride, base + attribute->d.buffered.offset)); break; case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: { int layer_number = attribute->name_state->layer_number; const CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; CoglPipelineLayer *layer = _cogl_pipeline_get_layer_with_flags (pipeline, layer_number, flags); if (layer) { int unit = _cogl_pipeline_layer_get_unit_index (layer); _cogl_bitmask_set (&ctx->enable_texcoord_attributes_tmp, unit, TRUE); GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit)); GE (ctx, glTexCoordPointer (attribute->d.buffered.n_components, attribute->d.buffered.type, attribute->d.buffered.stride, base + attribute->d.buffered.offset)); } break; } case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY: _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp, COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY, TRUE); GE (ctx, glVertexPointer (attribute->d.buffered.n_components, attribute->d.buffered.type, attribute->d.buffered.stride, base + attribute->d.buffered.offset)); break; case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY: #ifdef COGL_PIPELINE_PROGEND_GLSL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE)) setup_generic_buffered_attribute (ctx, pipeline, attribute, base); #endif break; default: g_warn_if_reached (); } } static void setup_legacy_const_attribute (CoglContext *ctx, CoglPipeline *pipeline, CoglAttribute *attribute) { #ifdef COGL_PIPELINE_PROGEND_GLSL if (attribute->name_state->name_id == COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY) { if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE)) setup_generic_const_attribute (ctx, pipeline, attribute); } else #endif { float vector[4] = { 0, 0, 0, 1 }; float *boxed = attribute->d.constant.boxed.v.float_value; int n_components = attribute->d.constant.boxed.size; int i; for (i = 0; i < n_components; i++) vector[i] = boxed[i]; switch (attribute->name_state->name_id) { case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: GE (ctx, glColor4f (vector[0], vector[1], vector[2], vector[3])); break; case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: GE (ctx, glNormal3f (vector[0], vector[1], vector[2])); break; case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: { int layer_number = attribute->name_state->layer_number; const CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; CoglPipelineLayer *layer = _cogl_pipeline_get_layer_with_flags (pipeline, layer_number, flags); if (layer) { int unit = _cogl_pipeline_layer_get_unit_index (layer); GE (ctx, glClientActiveTexture (GL_TEXTURE0 + unit)); GE (ctx, glMultiTexCoord4f (vector[0], vector[1], vector[2], vector[3])); } break; } case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY: GE (ctx, glVertex4f (vector[0], vector[1], vector[2], vector[3])); break; default: g_warn_if_reached (); } } } static void apply_attribute_enable_updates (CoglContext *context, CoglPipeline *pipeline) { ForeachChangedBitState changed_bits_state; changed_bits_state.context = context; changed_bits_state.new_bits = &context->enable_builtin_attributes_tmp; changed_bits_state.pipeline = pipeline; foreach_changed_bit_and_save (context, &context->enabled_builtin_attributes, &context->enable_builtin_attributes_tmp, toggle_builtin_attribute_enabled_cb, &changed_bits_state); changed_bits_state.new_bits = &context->enable_texcoord_attributes_tmp; foreach_changed_bit_and_save (context, &context->enabled_texcoord_attributes, &context->enable_texcoord_attributes_tmp, toggle_texcood_attribute_enabled_cb, &changed_bits_state); changed_bits_state.new_bits = &context->enable_custom_attributes_tmp; foreach_changed_bit_and_save (context, &context->enabled_custom_attributes, &context->enable_custom_attributes_tmp, toggle_custom_attribute_enabled_cb, &changed_bits_state); } void _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglFlushLayerState *layers_state, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes) { CoglContext *ctx = framebuffer->context; int i; CoglBool with_color_attrib = FALSE; CoglBool unknown_color_alpha = FALSE; CoglPipeline *copy = NULL; /* Iterate the attributes to see if we have a color attribute which * may affect our decision to enable blending or not. * * We need to do this before flushing the pipeline. */ for (i = 0; i < n_attributes; i++) switch (attributes[i]->name_state->name_id) { case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 && _cogl_attribute_get_n_components (attributes[i]) == 4) unknown_color_alpha = TRUE; with_color_attrib = TRUE; break; default: break; } if (G_UNLIKELY (layers_state->options.flags)) { /* If we haven't already created a derived pipeline... */ if (!copy) { copy = cogl_pipeline_copy (pipeline); pipeline = copy; } _cogl_pipeline_apply_overrides (pipeline, &layers_state->options); /* TODO: * overrides = cogl_pipeline_get_data (pipeline, * last_overrides_key); * if (overrides) * { * age = cogl_pipeline_get_age (pipeline); * XXX: actually we also need to check for legacy_state * and blending overrides for use of glColorPointer... * if (overrides->ags != age || * memcmp (&overrides->options, &options, * sizeof (options) != 0) * { * cogl_object_unref (overrides->weak_pipeline); * g_slice_free (Overrides, overrides); * overrides = NULL; * } * } * if (!overrides) * { * overrides = g_slice_new (Overrides); * overrides->weak_pipeline = * cogl_pipeline_weak_copy (pipeline); * _cogl_pipeline_apply_overrides (overrides->weak_pipeline, * &options); * * cogl_pipeline_set_data (pipeline, last_overrides_key, * weak_overrides, * free_overrides_cb, * NULL); * } * pipeline = overrides->weak_pipeline; */ } _cogl_pipeline_flush_gl_state (ctx, pipeline, framebuffer, with_color_attrib, unknown_color_alpha); _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp); /* Bind the attribute pointers. We need to do this after the * pipeline is flushed because when using GLSL that is the only * point when we can determine the attribute locations */ for (i = 0; i < n_attributes; i++) { CoglAttribute *attribute = attributes[i]; CoglAttributeBuffer *attribute_buffer; CoglBuffer *buffer; uint8_t *base; if (attribute->is_buffered) { attribute_buffer = cogl_attribute_get_buffer (attribute); buffer = COGL_BUFFER (attribute_buffer); /* Note: we don't try and catch errors with binding buffers * here since OOM errors at this point indicate that nothing * has yet been uploaded to attribute buffer which we * consider to be a programmer error. */ base = _cogl_buffer_gl_bind (buffer, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, NULL); if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL) setup_generic_buffered_attribute (ctx, pipeline, attribute, base); else setup_legacy_buffered_attribute (ctx, pipeline, attribute, base); _cogl_buffer_gl_unbind (buffer); } else { if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL) setup_generic_const_attribute (ctx, pipeline, attribute); else setup_legacy_const_attribute (ctx, pipeline, attribute); } } apply_attribute_enable_updates (ctx, pipeline); if (copy) cogl_object_unref (copy); } void _cogl_gl_disable_all_attributes (CoglContext *ctx) { _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp); /* XXX: we can pass a NULL source pipeline here because we know a * source pipeline only needs to be referenced when enabling * attributes. */ apply_attribute_enable_updates (ctx, NULL); } muffin-5.2.1/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl.c0000664000175000017500000011573214211404421024150 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-layer-private.h" #include "cogl-blend-string.h" #include "cogl-snippet-private.h" #include "cogl-list.h" #ifdef COGL_PIPELINE_FRAGEND_GLSL #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-shader-private.h" #include "cogl-program-private.h" #include "cogl-pipeline-cache.h" #include "cogl-pipeline-fragend-glsl-private.h" #include "cogl-glsl-shader-private.h" #include /* * GL/GLES compatability defines for pipeline thingies: */ /* This might not be defined on GLES */ #ifndef GL_TEXTURE_3D #define GL_TEXTURE_3D 0x806F #endif const CoglPipelineFragend _cogl_pipeline_glsl_backend; typedef struct _UnitState { unsigned int sampled:1; unsigned int combine_constant_used:1; } UnitState; typedef struct _LayerData { CoglList link; /* Layer index for the for the previous layer. This isn't necessarily the same as this layer's index - 1 because the indices can have gaps. If this is the first layer then it will be -1 */ int previous_layer_index; CoglPipelineLayer *layer; } LayerData; typedef struct { int ref_count; GLuint gl_shader; GString *header, *source; UnitState *unit_state; /* List of layers that we haven't generated code for yet. These are in reverse order. As soon as we're about to generate code for layer we'll remove it from the list so we don't generate it again */ CoglList layers; CoglPipelineCacheEntry *cache_entry; } CoglPipelineShaderState; static CoglUserDataKey shader_state_key; static void ensure_layer_generated (CoglPipeline *pipeline, int layer_num); static CoglPipelineShaderState * shader_state_new (int n_layers, CoglPipelineCacheEntry *cache_entry) { CoglPipelineShaderState *shader_state; shader_state = g_slice_new0 (CoglPipelineShaderState); shader_state->ref_count = 1; shader_state->unit_state = g_new0 (UnitState, n_layers); shader_state->cache_entry = cache_entry; return shader_state; } static CoglPipelineShaderState * get_shader_state (CoglPipeline *pipeline) { return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key); } static void destroy_shader_state (void *user_data, void *instance) { CoglPipelineShaderState *shader_state = user_data; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (shader_state->cache_entry && shader_state->cache_entry->pipeline != instance) shader_state->cache_entry->usage_count--; if (--shader_state->ref_count == 0) { if (shader_state->gl_shader) GE( ctx, glDeleteShader (shader_state->gl_shader) ); free (shader_state->unit_state); g_slice_free (CoglPipelineShaderState, shader_state); } } static void set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { if (shader_state) { shader_state->ref_count++; /* If we're not setting the state on the template pipeline then * mark it as a usage of the pipeline cache entry */ if (shader_state->cache_entry && shader_state->cache_entry->pipeline != pipeline) shader_state->cache_entry->usage_count++; } _cogl_object_set_user_data (COGL_OBJECT (pipeline), &shader_state_key, shader_state, destroy_shader_state); } static void dirty_shader_state (CoglPipeline *pipeline) { cogl_object_set_user_data (COGL_OBJECT (pipeline), &shader_state_key, NULL, NULL); } GLuint _cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); if (shader_state) return shader_state->gl_shader; else return 0; } static CoglPipelineSnippetList * get_fragment_snippets (CoglPipeline *pipeline) { pipeline = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS); return &pipeline->big_state->fragment_snippets; } static CoglPipelineSnippetList * get_layer_fragment_snippets (CoglPipelineLayer *layer) { unsigned long state = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; layer = _cogl_pipeline_layer_get_authority (layer, state); return &layer->big_state->fragment_snippets; } static CoglBool has_replace_hook (CoglPipelineLayer *layer, CoglSnippetHook hook) { GList *l; for (l = get_layer_fragment_snippets (layer)->entries; l; l = l->next) { CoglSnippet *snippet = l->data; if (snippet->hook == hook && snippet->replace) return TRUE; } return FALSE; } static CoglBool add_layer_declaration_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineShaderState *shader_state = user_data; CoglTextureType texture_type = _cogl_pipeline_layer_get_texture_type (layer); const char *target_string; _cogl_gl_util_get_texture_target_string (texture_type, &target_string, NULL); g_string_append_printf (shader_state->header, "uniform sampler%s cogl_sampler%i;\n", target_string, layer->index); return TRUE; } static void add_layer_declarations (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { /* We always emit sampler uniforms in case there will be custom * layer snippets that want to sample arbitrary layers. */ _cogl_pipeline_foreach_layer_internal (pipeline, add_layer_declaration_cb, shader_state); } static void add_global_declarations (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { CoglSnippetHook hook = COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS; CoglPipelineSnippetList *snippets = get_fragment_snippets (pipeline); /* Add the global data hooks. All of the code in these snippets is * always added and only the declarations data is used */ _cogl_pipeline_snippet_generate_declarations (shader_state->header, hook, snippets); } static void _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; CoglPipeline *authority; CoglPipelineCacheEntry *cache_entry = NULL; CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline); int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Now lookup our glsl backend private state */ shader_state = get_shader_state (pipeline); if (shader_state == NULL) { /* If we don't have an associated glsl shader yet then find the * glsl-authority (the oldest ancestor whose state will result in * the same shader being generated as for this pipeline). * * We always make sure to associate new shader with the * glsl-authority to maximize the chance that other pipelines can * share it. */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, _cogl_pipeline_get_state_for_fragment_codegen (ctx) & ~COGL_PIPELINE_STATE_LAYERS, _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)); shader_state = get_shader_state (authority); /* If we don't have an existing program associated with the * glsl-authority then start generating code for a new shader... */ if (shader_state == NULL) { /* Check if there is already a similar cached pipeline whose shader state we can share */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { cache_entry = _cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (cache_entry->pipeline); } if (shader_state) shader_state->ref_count++; else shader_state = shader_state_new (n_layers, cache_entry); set_shader_state (authority, shader_state); shader_state->ref_count--; if (cache_entry) set_shader_state (cache_entry->pipeline, shader_state); } /* If the pipeline isn't actually its own glsl-authority * then take a reference to the program state associated * with the glsl-authority... */ if (authority != pipeline) set_shader_state (pipeline, shader_state); } if (user_program) { /* If the user program contains a fragment shader then we don't need to generate one */ if (_cogl_program_has_fragment_shader (user_program)) { if (shader_state->gl_shader) { GE( ctx, glDeleteShader (shader_state->gl_shader) ); shader_state->gl_shader = 0; } return; } } if (shader_state->gl_shader) return; /* If we make it here then we have a glsl_shader_state struct without a gl_shader either because this is the first time we've encountered it or because the user program has changed */ /* We reuse two grow-only GStrings for code-gen. One string contains the uniform and attribute declarations while the other contains the main function. We need two strings because we need to dynamically declare attributes as the add_layer callback is invoked */ g_string_set_size (ctx->codegen_header_buffer, 0); g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->header = ctx->codegen_header_buffer; shader_state->source = ctx->codegen_source_buffer; _cogl_list_init (&shader_state->layers); add_layer_declarations (pipeline, shader_state); add_global_declarations (pipeline, shader_state); g_string_append (shader_state->source, "void\n" "cogl_generated_source ()\n" "{\n"); for (i = 0; i < n_layers; i++) { shader_state->unit_state[i].sampled = FALSE; shader_state->unit_state[i].combine_constant_used = FALSE; } } static void add_constant_lookup (CoglPipelineShaderState *shader_state, CoglPipeline *pipeline, CoglPipelineLayer *layer, const char *swizzle) { g_string_append_printf (shader_state->header, "_cogl_layer_constant_%i.%s", layer->index, swizzle); } static void ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state, CoglPipeline *pipeline, CoglPipelineLayer *layer) { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); CoglPipelineSnippetData snippet_data; CoglTextureType texture_type; const char *target_string, *tex_coord_swizzle; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (shader_state->unit_state[unit_index].sampled) return; texture_type = _cogl_pipeline_layer_get_texture_type (layer); _cogl_gl_util_get_texture_target_string (texture_type, &target_string, &tex_coord_swizzle); shader_state->unit_state[unit_index].sampled = TRUE; g_string_append_printf (shader_state->header, "vec4 cogl_texel%i;\n", layer->index); g_string_append_printf (shader_state->source, " cogl_texel%i = cogl_texture_lookup%i (" "cogl_sampler%i, ", layer->index, layer->index, layer->index); if (cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline, layer->index)) g_string_append_printf (shader_state->source, "vec4 (cogl_point_coord, 0.0, 1.0)"); else g_string_append_printf (shader_state->source, "cogl_tex_coord%i_in", layer->index); g_string_append (shader_state->source, ");\n"); /* There's no need to generate the real texture lookup if it's going to be replaced */ if (!has_replace_hook (layer, COGL_SNIPPET_HOOK_TEXTURE_LOOKUP)) { g_string_append_printf (shader_state->header, "vec4\n" "cogl_real_texture_lookup%i (sampler%s tex,\n" " vec4 coords)\n" "{\n" " return ", layer->index, target_string); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) g_string_append (shader_state->header, "vec4 (1.0, 1.0, 1.0, 1.0);\n"); else g_string_append_printf (shader_state->header, "texture%s (tex, coords.%s);\n", target_string, tex_coord_swizzle); g_string_append (shader_state->header, "}\n"); } /* Wrap the texture lookup in any snippets that have been hooked */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = get_layer_fragment_snippets (layer); snippet_data.hook = COGL_SNIPPET_HOOK_TEXTURE_LOOKUP; snippet_data.chain_function = g_strdup_printf ("cogl_real_texture_lookup%i", layer->index); snippet_data.final_name = g_strdup_printf ("cogl_texture_lookup%i", layer->index); snippet_data.function_prefix = g_strdup_printf ("cogl_texture_lookup_hook%i", layer->index); snippet_data.return_type = "vec4"; snippet_data.return_variable = "cogl_texel"; snippet_data.arguments = "cogl_sampler, cogl_tex_coord"; snippet_data.argument_declarations = g_strdup_printf ("sampler%s cogl_sampler, vec4 cogl_tex_coord", target_string); snippet_data.source_buf = shader_state->header; _cogl_pipeline_snippet_generate_code (&snippet_data); free ((char *) snippet_data.chain_function); free ((char *) snippet_data.final_name); free ((char *) snippet_data.function_prefix); free ((char *) snippet_data.argument_declarations); } static void add_arg (CoglPipelineShaderState *shader_state, CoglPipeline *pipeline, CoglPipelineLayer *layer, int previous_layer_index, CoglPipelineCombineSource src, CoglPipelineCombineOp operand, const char *swizzle) { GString *shader_source = shader_state->header; char alpha_swizzle[5] = "aaaa"; g_string_append_c (shader_source, '('); if (operand == COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR || operand == COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA) g_string_append_printf (shader_source, "vec4(1.0, 1.0, 1.0, 1.0).%s - ", swizzle); /* If the operand is reading from the alpha then replace the swizzle with the same number of copies of the alpha */ if (operand == COGL_PIPELINE_COMBINE_OP_SRC_ALPHA || operand == COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA) { alpha_swizzle[strlen (swizzle)] = '\0'; swizzle = alpha_swizzle; } switch (src) { case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE: g_string_append_printf (shader_source, "cogl_texel%i.%s", layer->index, swizzle); break; case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT: add_constant_lookup (shader_state, pipeline, layer, swizzle); break; case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS: if (previous_layer_index >= 0) { g_string_append_printf (shader_source, "cogl_layer%i.%s", previous_layer_index, swizzle); break; } /* flow through */ case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR: g_string_append_printf (shader_source, "cogl_color_in.%s", swizzle); break; default: { int layer_num = src - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0; CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; CoglPipelineLayer *other_layer = _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags); if (other_layer == NULL) { static CoglBool warning_seen = FALSE; if (!warning_seen) { g_warning ("The application is trying to use a texture " "combine with a layer number that does not exist"); warning_seen = TRUE; } g_string_append_printf (shader_source, "vec4 (1.0, 1.0, 1.0, 1.0).%s", swizzle); } else g_string_append_printf (shader_source, "cogl_texel%i.%s", other_layer->index, swizzle); } break; } g_string_append_c (shader_source, ')'); } static void ensure_arg_generated (CoglPipeline *pipeline, CoglPipelineLayer *layer, int previous_layer_index, CoglPipelineCombineSource src) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); switch (src) { case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR: /* This doesn't involve any other layers */ break; case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT: { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); /* Create a sampler uniform for this layer if we haven't already */ if (!shader_state->unit_state[unit_index].combine_constant_used) { g_string_append_printf (shader_state->header, "uniform vec4 _cogl_layer_constant_%i;\n", layer->index); shader_state->unit_state[unit_index].combine_constant_used = TRUE; } } break; case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS: if (previous_layer_index >= 0) ensure_layer_generated (pipeline, previous_layer_index); break; case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE: ensure_texture_lookup_generated (shader_state, pipeline, layer); break; default: if (src >= COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0) { int layer_num = src - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0; CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; CoglPipelineLayer *other_layer = _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags); if (other_layer) ensure_texture_lookup_generated (shader_state, pipeline, other_layer); } break; } } static void ensure_args_for_func (CoglPipeline *pipeline, CoglPipelineLayer *layer, int previous_layer_index, CoglPipelineCombineFunc function, CoglPipelineCombineSource *src) { int n_args = _cogl_get_n_args_for_combine_func (function); int i; for (i = 0; i < n_args; i++) ensure_arg_generated (pipeline, layer, previous_layer_index, src[i]); } static void append_masked_combine (CoglPipeline *pipeline, CoglPipelineLayer *layer, int previous_layer_index, const char *swizzle, CoglPipelineCombineFunc function, CoglPipelineCombineSource *src, CoglPipelineCombineOp *op) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); GString *shader_source = shader_state->header; g_string_append_printf (shader_state->header, " cogl_layer.%s = ", swizzle); switch (function) { case COGL_PIPELINE_COMBINE_FUNC_REPLACE: add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], swizzle); break; case COGL_PIPELINE_COMBINE_FUNC_MODULATE: add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], swizzle); g_string_append (shader_source, " * "); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], swizzle); break; case COGL_PIPELINE_COMBINE_FUNC_ADD: add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], swizzle); g_string_append (shader_source, " + "); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], swizzle); break; case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED: add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], swizzle); g_string_append (shader_source, " + "); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], swizzle); g_string_append_printf (shader_source, " - vec4(0.5, 0.5, 0.5, 0.5).%s", swizzle); break; case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT: add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], swizzle); g_string_append (shader_source, " - "); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], swizzle); break; case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE: add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], swizzle); g_string_append (shader_source, " * "); add_arg (shader_state, pipeline, layer, previous_layer_index, src[2], op[2], swizzle); g_string_append (shader_source, " + "); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], swizzle); g_string_append_printf (shader_source, " * (vec4(1.0, 1.0, 1.0, 1.0).%s - ", swizzle); add_arg (shader_state, pipeline, layer, previous_layer_index, src[2], op[2], swizzle); g_string_append_c (shader_source, ')'); break; case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB: case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA: g_string_append (shader_source, "vec4(4.0 * (("); add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], "r"); g_string_append (shader_source, " - 0.5) * ("); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], "r"); g_string_append (shader_source, " - 0.5) + ("); add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], "g"); g_string_append (shader_source, " - 0.5) * ("); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], "g"); g_string_append (shader_source, " - 0.5) + ("); add_arg (shader_state, pipeline, layer, previous_layer_index, src[0], op[0], "b"); g_string_append (shader_source, " - 0.5) * ("); add_arg (shader_state, pipeline, layer, previous_layer_index, src[1], op[1], "b"); g_string_append_printf (shader_source, " - 0.5))).%s", swizzle); break; } g_string_append_printf (shader_source, ";\n"); } static void ensure_layer_generated (CoglPipeline *pipeline, int layer_index) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); CoglPipelineLayer *combine_authority; CoglPipelineLayerBigState *big_state; CoglPipelineLayer *layer; CoglPipelineSnippetData snippet_data; LayerData *layer_data; /* Find the layer that corresponds to this layer_num */ _cogl_list_for_each (layer_data, &shader_state->layers, link) { layer = layer_data->layer; if (layer->index == layer_index) goto found; } /* If we didn't find it then we can assume the layer has already been generated */ return; found: /* Remove the layer from the list so we don't generate it again */ _cogl_list_remove (&layer_data->link); combine_authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_COMBINE); big_state = combine_authority->big_state; /* Make a global variable for the result of the layer code */ g_string_append_printf (shader_state->header, "vec4 cogl_layer%i;\n", layer_index); /* Skip the layer generation if there is a snippet that replaces the default layer code. This is important because generating this code may cause the code for other layers to be generated and stored in the global variable. If this code isn't actually used then the global variables would be uninitialised and they may be used from other layers */ if (!has_replace_hook (layer, COGL_SNIPPET_HOOK_LAYER_FRAGMENT)) { ensure_args_for_func (pipeline, layer, layer_data->previous_layer_index, big_state->texture_combine_rgb_func, big_state->texture_combine_rgb_src); ensure_args_for_func (pipeline, layer, layer_data->previous_layer_index, big_state->texture_combine_alpha_func, big_state->texture_combine_alpha_src); g_string_append_printf (shader_state->header, "vec4\n" "cogl_real_generate_layer%i ()\n" "{\n" " vec4 cogl_layer;\n", layer_index); if (!_cogl_pipeline_layer_needs_combine_separate (combine_authority) || /* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function * since if you use it, it overrides your ALPHA function... */ big_state->texture_combine_rgb_func == COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA) append_masked_combine (pipeline, layer, layer_data->previous_layer_index, "rgba", big_state->texture_combine_rgb_func, big_state->texture_combine_rgb_src, big_state->texture_combine_rgb_op); else { append_masked_combine (pipeline, layer, layer_data->previous_layer_index, "rgb", big_state->texture_combine_rgb_func, big_state->texture_combine_rgb_src, big_state->texture_combine_rgb_op); append_masked_combine (pipeline, layer, layer_data->previous_layer_index, "a", big_state->texture_combine_alpha_func, big_state->texture_combine_alpha_src, big_state->texture_combine_alpha_op); } g_string_append (shader_state->header, " return cogl_layer;\n" "}\n"); } /* Wrap the layer code in any snippets that have been hooked */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = get_layer_fragment_snippets (layer); snippet_data.hook = COGL_SNIPPET_HOOK_LAYER_FRAGMENT; snippet_data.chain_function = g_strdup_printf ("cogl_real_generate_layer%i", layer_index); snippet_data.final_name = g_strdup_printf ("cogl_generate_layer%i", layer_index); snippet_data.function_prefix = g_strdup_printf ("cogl_generate_layer%i", layer_index); snippet_data.return_type = "vec4"; snippet_data.return_variable = "cogl_layer"; snippet_data.source_buf = shader_state->header; _cogl_pipeline_snippet_generate_code (&snippet_data); free ((char *) snippet_data.chain_function); free ((char *) snippet_data.final_name); free ((char *) snippet_data.function_prefix); g_string_append_printf (shader_state->source, " cogl_layer%i = cogl_generate_layer%i ();\n", layer_index, layer_index); g_slice_free (LayerData, layer_data); } static CoglBool _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); LayerData *layer_data; if (!shader_state->source) return TRUE; /* Store the layers in reverse order */ layer_data = g_slice_new (LayerData); layer_data->layer = layer; if (_cogl_list_empty (&shader_state->layers)) { layer_data->previous_layer_index = -1; } else { LayerData *first = _cogl_container_of (shader_state->layers.next, LayerData, link); layer_data->previous_layer_index = first->layer->index; } _cogl_list_insert (&shader_state->layers, &layer_data->link); return TRUE; } /* GLES2 and GL3 don't have alpha testing so we need to implement it in the shader */ #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) static void add_alpha_test_snippet (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) { CoglPipelineAlphaFunc alpha_func; alpha_func = cogl_pipeline_get_alpha_test_function (pipeline); if (alpha_func == COGL_PIPELINE_ALPHA_FUNC_ALWAYS) /* Do nothing */ return; if (alpha_func == COGL_PIPELINE_ALPHA_FUNC_NEVER) { /* Always discard the fragment */ g_string_append (shader_state->source, " discard;\n"); return; } /* For all of the other alpha functions we need a uniform for the reference */ g_string_append (shader_state->header, "uniform float _cogl_alpha_test_ref;\n"); g_string_append (shader_state->source, " if (cogl_color_out.a "); switch (alpha_func) { case COGL_PIPELINE_ALPHA_FUNC_LESS: g_string_append (shader_state->source, ">="); break; case COGL_PIPELINE_ALPHA_FUNC_EQUAL: g_string_append (shader_state->source, "!="); break; case COGL_PIPELINE_ALPHA_FUNC_LEQUAL: g_string_append (shader_state->source, ">"); break; case COGL_PIPELINE_ALPHA_FUNC_GREATER: g_string_append (shader_state->source, "<="); break; case COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL: g_string_append (shader_state->source, "=="); break; case COGL_PIPELINE_ALPHA_FUNC_GEQUAL: g_string_append (shader_state->source, "< "); break; case COGL_PIPELINE_ALPHA_FUNC_ALWAYS: case COGL_PIPELINE_ALPHA_FUNC_NEVER: g_assert_not_reached (); break; } g_string_append (shader_state->source, " _cogl_alpha_test_ref)\n discard;\n"); } #endif /* HAVE_COGL_GLES2 */ static CoglBool _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state = get_shader_state (pipeline); _COGL_GET_CONTEXT (ctx, FALSE); if (shader_state->source) { const char *source_strings[2]; GLint lengths[2]; GLint compile_status; GLuint shader; CoglPipelineSnippetData snippet_data; COGL_STATIC_COUNTER (fragend_glsl_compile_counter, "glsl fragment compile counter", "Increments each time a new GLSL " "fragment shader is compiled", 0 /* no application private data */); COGL_COUNTER_INC (_cogl_uprof_context, fragend_glsl_compile_counter); /* We only need to generate code to calculate the fragment value for the last layer. If the value of this layer depends on any previous layers then it will recursively generate the code for those layers */ if (!_cogl_list_empty (&shader_state->layers)) { CoglPipelineLayer *last_layer; LayerData *layer_data, *tmp; layer_data = _cogl_container_of (shader_state->layers.next, LayerData, link); last_layer = layer_data->layer; ensure_layer_generated (pipeline, last_layer->index); g_string_append_printf (shader_state->source, " cogl_color_out = cogl_layer%i;\n", last_layer->index); _cogl_list_for_each_safe (layer_data, tmp, &shader_state->layers, link) g_slice_free (LayerData, layer_data); } else g_string_append (shader_state->source, " cogl_color_out = cogl_color_in;\n"); #if defined(HAVE_COGL_GLES2) || defined (HAVE_COGL_GL) if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEST)) add_alpha_test_snippet (pipeline, shader_state); #endif /* Close the function surrounding the generated fragment processing */ g_string_append (shader_state->source, "}\n"); /* Add all of the hooks for fragment processing */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = get_fragment_snippets (pipeline); snippet_data.hook = COGL_SNIPPET_HOOK_FRAGMENT; snippet_data.chain_function = "cogl_generated_source"; snippet_data.final_name = "main"; snippet_data.function_prefix = "cogl_fragment_hook"; snippet_data.source_buf = shader_state->source; _cogl_pipeline_snippet_generate_code (&snippet_data); GE_RET( shader, ctx, glCreateShader (GL_FRAGMENT_SHADER) ); lengths[0] = shader_state->header->len; source_strings[0] = shader_state->header->str; lengths[1] = shader_state->source->len; source_strings[1] = shader_state->source->str; _cogl_glsl_shader_set_source_with_boilerplate (ctx, shader, GL_FRAGMENT_SHADER, pipeline, 2, /* count */ source_strings, lengths); GE( ctx, glCompileShader (shader) ); GE( ctx, glGetShaderiv (shader, GL_COMPILE_STATUS, &compile_status) ); if (!compile_status) { GLint len = 0; char *shader_log; GE( ctx, glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &len) ); shader_log = g_alloca (len); GE( ctx, glGetShaderInfoLog (shader, len, &len, shader_log) ); g_warning ("Shader compilation failed:\n%s", shader_log); } shader_state->header = NULL; shader_state->source = NULL; shader_state->gl_shader = shader; } return TRUE; } static void _cogl_pipeline_fragend_glsl_pre_change_notify (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx))) dirty_shader_state (pipeline); } /* NB: layers are considered immutable once they have any dependants * so although multiple pipelines can end up depending on a single * static layer, we can guarantee that if a layer is being *changed* * then it can only have one pipeline depending on it. * * XXX: Don't forget this is *pre* change, we can't read the new value * yet! */ static void _cogl_pipeline_fragend_glsl_layer_pre_change_notify ( CoglPipeline *owner, CoglPipelineLayer *layer, CoglPipelineLayerState change) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx))) { dirty_shader_state (owner); return; } /* TODO: we could be saving snippets of texture combine code along * with each layer and then when a layer changes we would just free * the snippet. */ } const CoglPipelineFragend _cogl_pipeline_glsl_fragend = { _cogl_pipeline_fragend_glsl_start, _cogl_pipeline_fragend_glsl_add_layer, NULL, /* passthrough */ _cogl_pipeline_fragend_glsl_end, _cogl_pipeline_fragend_glsl_pre_change_notify, NULL, /* pipeline_set_parent_notify */ _cogl_pipeline_fragend_glsl_layer_pre_change_notify }; #endif /* COGL_PIPELINE_FRAGEND_GLSL */ muffin-5.2.1/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h0000664000175000017500000001061614211404421024053 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef _COGL_TEXTURE_2D_GL_PRIVATE_H_ #define _COGL_TEXTURE_2D_GL_PRIVATE_H_ #include "cogl-types.h" #include "cogl-context-private.h" #include "cogl-texture.h" void _cogl_texture_2d_gl_free (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_gl_can_create (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format); void _cogl_texture_2d_gl_init (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_gl_allocate (CoglTexture *tex, CoglError **error); CoglTexture2D * _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, CoglPixelFormat internal_format, CoglBool can_convert_in_place, CoglError **error); #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) CoglTexture2D * _cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx, int width, int height, CoglPixelFormat format, EGLImageKHR image, CoglError **error); #endif void _cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter); void _cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p); void _cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglFramebuffer *src_fb, int dst_x, int dst_y, int level); unsigned int _cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d); void _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglBitmap *bitmap, int dst_x, int dst_y, int level, CoglError **error); void _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, CoglPixelFormat format, int rowstride, uint8_t *data); #endif /* _COGL_TEXTURE_2D_GL_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/cogl-object.h0000664000175000017500000001537714211404421017362 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_OBJECT_H #define __COGL_OBJECT_H #include #include COGL_BEGIN_DECLS typedef struct _CoglObject CoglObject; #define COGL_OBJECT(X) ((CoglObject *)X) /** * CoglObject: (ref-func cogl_object_ref) (unref-func cogl_object_unref) * (set-value-func cogl_object_value_set_object) * (get-value-func cogl_object_value_get_object) */ /** * cogl_object_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_object_get_gtype (void); /** * cogl_object_ref: (skip) * @object: a #CoglObject * * Increases the reference count of @object by 1 * * Returns: the @object, with its reference count increased */ void * cogl_object_ref (void *object); /** * cogl_object_unref: (skip) * @object: a #CoglObject * * Drecreases the reference count of @object by 1; if the reference * count reaches 0, the resources allocated by @object will be freed */ void cogl_object_unref (void *object); /** * CoglUserDataKey: * @unused: ignored. * * A #CoglUserDataKey is used to declare a key for attaching data to a * #CoglObject using cogl_object_set_user_data. The typedef only exists as a * formality to make code self documenting since only the unique address of a * #CoglUserDataKey is used. * * Typically you would declare a static #CoglUserDataKey and set private data * on an object something like this: * * |[ * static CoglUserDataKey path_private_key; * * static void * destroy_path_private_cb (void *data) * { * free (data); * } * * static void * my_path_set_data (CoglPath *path, void *data) * { * cogl_object_set_user_data (COGL_OBJECT (path), * &private_key, * data, * destroy_path_private_cb); * } * ]| * * Since: 1.4 */ typedef struct { int unused; } CoglUserDataKey; /** * CoglUserDataDestroyCallback: * @user_data: The data whos association with a #CoglObject has been * destoyed. * * When associating private data with a #CoglObject a callback can be * given which will be called either if the object is destroyed or if * cogl_object_set_user_data() is called with NULL user_data for the * same key. * * Since: 1.4 */ typedef GDestroyNotify CoglUserDataDestroyCallback; /** * CoglDebugObjectTypeInfo: * @name: A human readable name for the type. * @instance_count: The number of objects of this type that are * currently in use * * This struct is used to pass information to the callback when * cogl_debug_object_foreach_type() is called. * * Since: 1.8 * Stability: unstable */ typedef struct { const char *name; unsigned long instance_count; } CoglDebugObjectTypeInfo; /** * CoglDebugObjectForeachTypeCallback: * @info: A pointer to a struct containing information about the type. * * A callback function to use for cogl_debug_object_foreach_type(). * * Since: 1.8 * Stability: unstable */ typedef void (* CoglDebugObjectForeachTypeCallback) (const CoglDebugObjectTypeInfo *info, void *user_data); /** * cogl_object_set_user_data: (skip) * @object: The object to associate private data with * @key: The address of a #CoglUserDataKey which provides a unique value * with which to index the private data. * @user_data: The data to associate with the given object, * or %NULL to remove a previous association. * @destroy: A #CoglUserDataDestroyCallback to call if the object is * destroyed or if the association is removed by later setting * %NULL data for the same key. * * Associates some private @user_data with a given #CoglObject. To * later remove the association call cogl_object_set_user_data() with * the same @key but NULL for the @user_data. * * Since: 1.4 */ void cogl_object_set_user_data (CoglObject *object, CoglUserDataKey *key, void *user_data, CoglUserDataDestroyCallback destroy); /** * cogl_object_get_user_data: (skip) * @object: The object with associated private data to query * @key: The address of a #CoglUserDataKey which provides a unique value * with which to index the private data. * * Finds the user data previously associated with @object using * the given @key. If no user data has been associated with @object * for the given @key this function returns NULL. * * Returns: (transfer none): The user data previously associated * with @object using the given @key; or %NULL if no associated * data is found. * * Since: 1.4 */ void * cogl_object_get_user_data (CoglObject *object, CoglUserDataKey *key); /** * cogl_debug_object_foreach_type: * @func: (scope call): A callback function for each type * @user_data: (closure): A pointer to pass to @func * * Invokes @func once for each type of object that Cogl uses and * passes a count of the number of objects for that type. This is * intended to be used solely for debugging purposes to track down * issues with objects leaking. * * Since: 1.8 * Stability: unstable */ void cogl_debug_object_foreach_type (CoglDebugObjectForeachTypeCallback func, void *user_data); /** * cogl_debug_object_print_instances: * * Prints a list of all the object types that Cogl uses along with the * number of objects of that type that are currently in use. This is * intended to be used solely for debugging purposes to track down * issues with objects leaking. * * Since: 1.8 * Stability: unstable */ void cogl_debug_object_print_instances (void); COGL_END_DECLS #endif /* __COGL_OBJECT_H */ muffin-5.2.1/cogl/cogl/cogl-debug-options.h0000664000175000017500000001455014211404421020663 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ OPT (OBJECT, N_("Cogl Tracing"), "ref-counts", N_("CoglObject references"), N_("Debug ref counting issues for CoglObjects")) OPT (SLICING, N_("Cogl Tracing"), "slicing", N_("Trace Texture Slicing"), N_("debug the creation of texture slices")) OPT (ATLAS, N_("Cogl Tracing"), "atlas", N_("Trace Atlas Textures"), N_("Debug texture atlas management")) OPT (BLEND_STRINGS, N_("Cogl Tracing"), "blend-strings", N_("Trace Blend Strings"), N_("Debug CoglBlendString parsing")) OPT (JOURNAL, N_("Cogl Tracing"), "journal", N_("Trace Journal"), N_("View all the geometry passing through the journal")) OPT (BATCHING, N_("Cogl Tracing"), "batching", N_("Trace Batching"), N_("Show how geometry is being batched in the journal")) OPT (MATRICES, N_("Cogl Tracing"), "matrices", N_("Trace matrices"), N_("Trace all matrix manipulation")) /* XXX we should replace the "draw" option its very hand wavy... */ OPT (DRAW, N_("Cogl Tracing"), "draw", N_("Trace Misc Drawing"), N_("Trace some misc drawing operations")) OPT (PANGO, N_("Cogl Tracing"), "pango", N_("Trace Pango Renderer"), N_("Trace the Cogl Pango renderer")) OPT (TEXTURE_PIXMAP, N_("Cogl Tracing"), "texture-pixmap", N_("Trace CoglTexturePixmap backend"), N_("Trace the Cogl texture pixmap backend")) OPT (RECTANGLES, N_("Visualize"), "rectangles", N_("Outline rectangles"), N_("Add wire outlines for all rectangular geometry")) OPT (WIREFRAME, N_("Visualize"), "wireframe", N_("Show wireframes"), N_("Add wire outlines for all geometry")) OPT (DISABLE_BATCHING, N_("Root Cause"), "disable-batching", N_("Disable Journal batching"), N_("Disable batching of geometry in the Cogl Journal.")) OPT (DISABLE_VBOS, N_("Root Cause"), "disable-vbos", N_("Disable GL Vertex Buffers"), N_("Disable use of OpenGL vertex buffer objects")) OPT (DISABLE_PBOS, N_("Root Cause"), "disable-pbos", N_("Disable GL Pixel Buffers"), N_("Disable use of OpenGL pixel buffer objects")) OPT (DISABLE_SOFTWARE_TRANSFORM, N_("Root Cause"), "disable-software-transform", N_("Disable software rect transform"), N_("Use the GPU to transform rectangular geometry")) OPT (DUMP_ATLAS_IMAGE, N_("Cogl Specialist"), "dump-atlas-image", N_("Dump atlas images"), N_("Dump texture atlas changes to an image file")) OPT (DISABLE_ATLAS, N_("Root Cause"), "disable-atlas", N_("Disable texture atlasing"), N_("Disable use of texture atlasing")) OPT (DISABLE_SHARED_ATLAS, N_("Root Cause"), "disable-shared-atlas", N_("Disable sharing the texture atlas between text and images"), N_("When this is set the glyph cache will always use a separate texture " "for its atlas. Otherwise it will try to share the atlas with images.")) OPT (DISABLE_TEXTURING, N_("Root Cause"), "disable-texturing", N_("Disable texturing"), N_("Disable texturing any primitives")) OPT (DISABLE_ARBFP, N_("Root Cause"), "disable-arbfp", N_("Disable arbfp"), N_("Disable use of ARB fragment programs")) OPT (DISABLE_FIXED, N_("Root Cause"), "disable-fixed", N_("Disable fixed"), N_("Disable use of the fixed function pipeline backend")) OPT (DISABLE_GLSL, N_("Root Cause"), "disable-glsl", N_("Disable GLSL"), N_("Disable use of GLSL")) OPT (DISABLE_BLENDING, N_("Root Cause"), "disable-blending", N_("Disable blending"), N_("Disable use of blending")) OPT (DISABLE_NPOT_TEXTURES, N_("Root Cause"), "disable-npot-textures", N_("Disable non-power-of-two textures"), N_("Makes Cogl think that the GL driver doesn't support NPOT textures " "so that it will create sliced textures or textures with waste instead.")) OPT (DISABLE_SOFTWARE_CLIP, N_("Root Cause"), "disable-software-clip", N_("Disable software clipping"), N_("Disables Cogl's attempts to clip some rectangles in software.")) OPT (SHOW_SOURCE, N_("Cogl Tracing"), "show-source", N_("Show source"), N_("Show generated ARBfp/GLSL source code")) OPT (OPENGL, N_("Cogl Tracing"), "opengl", N_("Trace some OpenGL"), N_("Traces some select OpenGL calls")) OPT (OFFSCREEN, N_("Cogl Tracing"), "offscreen", N_("Trace offscreen support"), N_("Debug offscreen support")) OPT (DISABLE_BLENDING, N_("Root Cause"), "disable-program-caches", N_("Disable program caches"), N_("Disable fallback caches for arbfp and glsl programs")) OPT (DISABLE_FAST_READ_PIXEL, N_("Root Cause"), "disable-fast-read-pixel", N_("Disable read pixel optimization"), N_("Disable optimization for reading 1px for simple " "scenes of opaque rectangles")) OPT (CLIPPING, N_("Cogl Tracing"), "clipping", N_("Trace clipping"), N_("Logs information about how Cogl is implementing clipping")) OPT (PERFORMANCE, N_("Cogl Tracing"), "performance", N_("Trace performance concerns"), N_("Tries to highlight sub-optimal Cogl usage.")) muffin-5.2.1/cogl/cogl/cogl-pango.h0000664000175000017500000000262614211404421017211 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PANGO_H_COMPAT__ #define __COGL_PANGO_H_COMPAT__ #warning "#include is deprecated; please #include " #include #endif /* __COGL_PANGO_H_COMPAT__ */ muffin-5.2.1/cogl/cogl/cogl-sampler-cache.c0000664000175000017500000003044414211404421020603 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-sampler-cache-private.h" #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #ifndef GL_TEXTURE_WRAP_R #define GL_TEXTURE_WRAP_R 0x8072 #endif struct _CoglSamplerCache { CoglContext *context; /* The samplers are hashed in two tables. One is using the enum values that Cogl exposes (so it can include the 'automatic' wrap mode) and the other is using the converted values that will be given to GL. The first is used to get a unique pointer for the sampler state so that pipelines only need to store a single pointer instead of the whole state and the second is used so that only a single GL sampler object will be created for each unique GL state. */ GHashTable *hash_table_cogl; GHashTable *hash_table_gl; /* This is used for generated fake unique sampler object numbers when the sampler object extension is not supported */ GLuint next_fake_sampler_object_number; }; static CoglSamplerCacheWrapMode get_real_wrap_mode (CoglSamplerCacheWrapMode wrap_mode) { if (wrap_mode == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC) return COGL_SAMPLER_CACHE_WRAP_MODE_CLAMP_TO_EDGE; return wrap_mode; } static void canonicalize_key (CoglSamplerCacheEntry *key) { /* This converts the wrap modes to the enums that will actually be given to GL so that it can be used as a key to get a unique GL sampler object for the state */ key->wrap_mode_s = get_real_wrap_mode (key->wrap_mode_s); key->wrap_mode_t = get_real_wrap_mode (key->wrap_mode_t); key->wrap_mode_p = get_real_wrap_mode (key->wrap_mode_p); } static CoglBool wrap_mode_equal_gl (CoglSamplerCacheWrapMode wrap_mode0, CoglSamplerCacheWrapMode wrap_mode1) { /* We want to compare the actual GLenum that will be used so that if two different wrap_modes actually use the same GL state we'll still use the same sampler object */ return get_real_wrap_mode (wrap_mode0) == get_real_wrap_mode (wrap_mode1); } static CoglBool sampler_state_equal_gl (const void *value0, const void *value1) { const CoglSamplerCacheEntry *state0 = value0; const CoglSamplerCacheEntry *state1 = value1; return (state0->mag_filter == state1->mag_filter && state0->min_filter == state1->min_filter && wrap_mode_equal_gl (state0->wrap_mode_s, state1->wrap_mode_s) && wrap_mode_equal_gl (state0->wrap_mode_t, state1->wrap_mode_t) && wrap_mode_equal_gl (state0->wrap_mode_p, state1->wrap_mode_p)); } static unsigned int hash_wrap_mode_gl (unsigned int hash, CoglSamplerCacheWrapMode wrap_mode) { /* We want to hash the actual GLenum that will be used so that if two different wrap_modes actually use the same GL state we'll still use the same sampler object */ GLenum real_wrap_mode = get_real_wrap_mode (wrap_mode); return _cogl_util_one_at_a_time_hash (hash, &real_wrap_mode, sizeof (real_wrap_mode)); } static unsigned int hash_sampler_state_gl (const void *key) { const CoglSamplerCacheEntry *entry = key; unsigned int hash = 0; hash = _cogl_util_one_at_a_time_hash (hash, &entry->mag_filter, sizeof (entry->mag_filter)); hash = _cogl_util_one_at_a_time_hash (hash, &entry->min_filter, sizeof (entry->min_filter)); hash = hash_wrap_mode_gl (hash, entry->wrap_mode_s); hash = hash_wrap_mode_gl (hash, entry->wrap_mode_t); hash = hash_wrap_mode_gl (hash, entry->wrap_mode_p); return _cogl_util_one_at_a_time_mix (hash); } static CoglBool sampler_state_equal_cogl (const void *value0, const void *value1) { const CoglSamplerCacheEntry *state0 = value0; const CoglSamplerCacheEntry *state1 = value1; return (state0->mag_filter == state1->mag_filter && state0->min_filter == state1->min_filter && state0->wrap_mode_s == state1->wrap_mode_s && state0->wrap_mode_t == state1->wrap_mode_t && state0->wrap_mode_p == state1->wrap_mode_p); } static unsigned int hash_sampler_state_cogl (const void *key) { const CoglSamplerCacheEntry *entry = key; unsigned int hash = 0; hash = _cogl_util_one_at_a_time_hash (hash, &entry->mag_filter, sizeof (entry->mag_filter)); hash = _cogl_util_one_at_a_time_hash (hash, &entry->min_filter, sizeof (entry->min_filter)); hash = _cogl_util_one_at_a_time_hash (hash, &entry->wrap_mode_s, sizeof (entry->wrap_mode_s)); hash = _cogl_util_one_at_a_time_hash (hash, &entry->wrap_mode_t, sizeof (entry->wrap_mode_t)); hash = _cogl_util_one_at_a_time_hash (hash, &entry->wrap_mode_p, sizeof (entry->wrap_mode_p)); return _cogl_util_one_at_a_time_mix (hash); } CoglSamplerCache * _cogl_sampler_cache_new (CoglContext *context) { CoglSamplerCache *cache = g_new (CoglSamplerCache, 1); /* No reference is taken on the context because it would create a circular reference */ cache->context = context; cache->hash_table_gl = g_hash_table_new (hash_sampler_state_gl, sampler_state_equal_gl); cache->hash_table_cogl = g_hash_table_new (hash_sampler_state_cogl, sampler_state_equal_cogl); cache->next_fake_sampler_object_number = 1; return cache; } static void set_wrap_mode (CoglContext *context, GLuint sampler_object, GLenum param, CoglSamplerCacheWrapMode wrap_mode) { GE( context, glSamplerParameteri (sampler_object, param, wrap_mode) ); } static CoglSamplerCacheEntry * _cogl_sampler_cache_get_entry_gl (CoglSamplerCache *cache, const CoglSamplerCacheEntry *key) { CoglSamplerCacheEntry *entry; entry = g_hash_table_lookup (cache->hash_table_gl, key); if (entry == NULL) { CoglContext *context = cache->context; entry = g_slice_dup (CoglSamplerCacheEntry, key); if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) { GE( context, glGenSamplers (1, &entry->sampler_object) ); GE( context, glSamplerParameteri (entry->sampler_object, GL_TEXTURE_MIN_FILTER, entry->min_filter) ); GE( context, glSamplerParameteri (entry->sampler_object, GL_TEXTURE_MAG_FILTER, entry->mag_filter) ); set_wrap_mode (context, entry->sampler_object, GL_TEXTURE_WRAP_S, entry->wrap_mode_s); set_wrap_mode (context, entry->sampler_object, GL_TEXTURE_WRAP_T, entry->wrap_mode_t); set_wrap_mode (context, entry->sampler_object, GL_TEXTURE_WRAP_R, entry->wrap_mode_p); } else { /* If sampler objects aren't supported then we'll invent a unique number so that pipelines can still compare the unique state just by comparing the sampler object numbers */ entry->sampler_object = cache->next_fake_sampler_object_number++; } g_hash_table_insert (cache->hash_table_gl, entry, entry); } return entry; } static CoglSamplerCacheEntry * _cogl_sampler_cache_get_entry_cogl (CoglSamplerCache *cache, const CoglSamplerCacheEntry *key) { CoglSamplerCacheEntry *entry; entry = g_hash_table_lookup (cache->hash_table_cogl, key); if (entry == NULL) { CoglSamplerCacheEntry canonical_key; CoglSamplerCacheEntry *gl_entry; entry = g_slice_dup (CoglSamplerCacheEntry, key); /* Get the sampler object number from the canonical GL version of the sampler state cache */ canonical_key = *key; canonicalize_key (&canonical_key); gl_entry = _cogl_sampler_cache_get_entry_gl (cache, &canonical_key); entry->sampler_object = gl_entry->sampler_object; g_hash_table_insert (cache->hash_table_cogl, entry, entry); } return entry; } const CoglSamplerCacheEntry * _cogl_sampler_cache_get_default_entry (CoglSamplerCache *cache) { CoglSamplerCacheEntry key; key.wrap_mode_s = COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC; key.wrap_mode_t = COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC; key.wrap_mode_p = COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC; key.min_filter = GL_LINEAR; key.mag_filter = GL_LINEAR; return _cogl_sampler_cache_get_entry_cogl (cache, &key); } const CoglSamplerCacheEntry * _cogl_sampler_cache_update_wrap_modes (CoglSamplerCache *cache, const CoglSamplerCacheEntry *old_entry, CoglSamplerCacheWrapMode wrap_mode_s, CoglSamplerCacheWrapMode wrap_mode_t, CoglSamplerCacheWrapMode wrap_mode_p) { CoglSamplerCacheEntry key = *old_entry; key.wrap_mode_s = wrap_mode_s; key.wrap_mode_t = wrap_mode_t; key.wrap_mode_p = wrap_mode_p; return _cogl_sampler_cache_get_entry_cogl (cache, &key); } const CoglSamplerCacheEntry * _cogl_sampler_cache_update_filters (CoglSamplerCache *cache, const CoglSamplerCacheEntry *old_entry, GLenum min_filter, GLenum mag_filter) { CoglSamplerCacheEntry key = *old_entry; key.min_filter = min_filter; key.mag_filter = mag_filter; return _cogl_sampler_cache_get_entry_cogl (cache, &key); } static void hash_table_free_gl_cb (void *key, void *value, void *user_data) { CoglContext *context = user_data; CoglSamplerCacheEntry *entry = value; if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) GE( context, glDeleteSamplers (1, &entry->sampler_object) ); g_slice_free (CoglSamplerCacheEntry, entry); } static void hash_table_free_cogl_cb (void *key, void *value, void *user_data) { CoglSamplerCacheEntry *entry = value; g_slice_free (CoglSamplerCacheEntry, entry); } void _cogl_sampler_cache_free (CoglSamplerCache *cache) { g_hash_table_foreach (cache->hash_table_gl, hash_table_free_gl_cb, cache->context); g_hash_table_destroy (cache->hash_table_gl); g_hash_table_foreach (cache->hash_table_cogl, hash_table_free_cogl_cb, cache->context); g_hash_table_destroy (cache->hash_table_cogl); free (cache); } muffin-5.2.1/cogl/cogl/cogl-types.h0000664000175000017500000007537114211404421017260 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_TYPES_H__ #define __COGL_TYPES_H__ #include #include #include #include #include /* Guard C code in headers, while including them from C++ */ #ifdef __cplusplus #define COGL_BEGIN_DECLS extern "C" { #define COGL_END_DECLS } #else #define COGL_BEGIN_DECLS #define COGL_END_DECLS #endif COGL_BEGIN_DECLS /** * SECTION:cogl-types * @short_description: Types used throughout the library * * General types used by various Cogl functions. */ /** * CoglBool: * * A boolean data type used throughout the Cogl C api. This should be * used in conjunction with the %TRUE and %FALSE macro defines for * setting and testing boolean values. * * Since: 2.0 * Stability: stable */ typedef int CoglBool; #if __GNUC__ >= 4 #define COGL_GNUC_NULL_TERMINATED __attribute__((__sentinel__)) #else #define COGL_GNUC_NULL_TERMINATED #endif #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) && \ !defined (COGL_COMPILATION) #define COGL_GNUC_DEPRECATED \ __attribute__((__deprecated__)) #else #define COGL_GNUC_DEPRECATED #endif /* __GNUC__ */ /* Some structures are meant to be opaque but they have public definitions because we want the size to be public so they can be allocated on the stack. This macro is used to ensure that users don't accidentally access private members */ #ifdef COGL_COMPILATION #define COGL_PRIVATE(x) x #else #define COGL_PRIVATE(x) private_member_ ## x #endif /* To help catch accidental changes to public structs that should * be stack allocated we use this macro to compile time assert that * a struct size is as expected. */ #define COGL_STRUCT_SIZE_ASSERT(TYPE, SIZE) \ typedef struct { \ char compile_time_assert_ ## TYPE ## _size[ \ (sizeof (TYPE) == (SIZE)) ? 1 : -1]; \ } _ ## TYPE ## SizeCheck /** * CoglHandle: * * Type used for storing references to cogl objects, the CoglHandle is * a fully opaque type without any public data members. */ typedef void * CoglHandle; /** * COGL_INVALID_HANDLE: * * A COGL handle that is not valid, used for unitialized handles as well as * error conditions. */ #define COGL_INVALID_HANDLE NULL #define COGL_TYPE_HANDLE (cogl_handle_get_type ()) GType cogl_handle_get_type (void) G_GNUC_CONST; /** * cogl_handle_ref: * @handle: a #CoglHandle * * Increases the reference count of @handle by 1 * * Return value: (transfer none): the handle, with its reference count increased */ CoglHandle cogl_handle_ref (CoglHandle handle); /** * cogl_handle_unref: * @handle: a #CoglHandle * * Drecreases the reference count of @handle by 1; if the reference * count reaches 0, the resources allocated by @handle will be freed */ void cogl_handle_unref (CoglHandle handle); /** * CoglFuncPtr: * * The type used by cogl for function pointers, note that this type * is used as a generic catch-all cast for function pointers and the * actual arguments and return type may be different. */ typedef void (* CoglFuncPtr) (void); /* We forward declare this in cogl-types to avoid circular dependencies * between cogl-matrix.h, cogl-euler.h and cogl-quaterion.h */ typedef struct _CoglMatrix CoglMatrix; /* Same as above we forward declared CoglQuaternion to avoid * circular dependencies. */ typedef struct _CoglQuaternion CoglQuaternion; /* Same as above we forward declared CoglEuler to avoid * circular dependencies. */ typedef struct _CoglEuler CoglEuler; /** * CoglAngle: * * Integer representation of an angle such that 1024 corresponds to * full circle (i.e., 2 * pi). * * Since: 1.0 */ typedef int32_t CoglAngle; typedef struct _CoglColor CoglColor; typedef struct _CoglTextureVertex CoglTextureVertex; /* Enum declarations */ #define COGL_A_BIT (1 << 4) #define COGL_BGR_BIT (1 << 5) #define COGL_AFIRST_BIT (1 << 6) #define COGL_PREMULT_BIT (1 << 7) #define COGL_DEPTH_BIT (1 << 8) #define COGL_STENCIL_BIT (1 << 9) /* XXX: Notes to those adding new formats here... * * First this diagram outlines how we allocate the 32bits of a * CoglPixelFormat currently... * * 6 bits for flags * |-----| * enum unused 4 bits for the bytes-per-pixel * and component alignment info * |------| |-------------| |--| * 00000000 xxxxxxxx xxxxxxSD PFBA0000 * ^ stencil * ^ depth * ^ premult * ^ alpha first * ^ bgr order * ^ has alpha * * The most awkward part about the formats is how we use the last 4 * bits to encode the bytes per pixel and component alignment * information. Ideally we should have had 3 bits for the bpp and a * flag for alignment but we didn't plan for that in advance so we * instead use a small lookup table to query the bpp and whether the * components are byte aligned or not. * * The mapping is the following (see discussion on bug #660188): * * 0 = undefined * 1, 8 = 1 bpp (e.g. A_8, G_8) * 2 = 3 bpp, aligned (e.g. 888) * 3 = 4 bpp, aligned (e.g. 8888) * 4-6 = 2 bpp, not aligned (e.g. 565, 4444, 5551) * 7 = YUV: undefined bpp, undefined alignment * 9 = 2 bpp, aligned * 10 = depth, aligned (8, 16, 24, 32, 32f) * 11 = undefined * 12 = 3 bpp, not aligned * 13 = 4 bpp, not aligned (e.g. 2101010) * 14-15 = undefined * * Note: the gap at 10-11 is just because we wanted to maintain that * all non-aligned formats have the third bit set in case that's * useful later. * * Since we don't want to waste bits adding more and more flags, we'd * like to see most new pixel formats that can't be represented * uniquely with the existing flags in the least significant byte * simply be enumerated with sequential values in the most significant * enum byte. * * Note: Cogl avoids exposing any padded XRGB or RGBX formats and * instead we leave it up to applications to decided whether they * consider the A component as padding or valid data. We shouldn't * change this policy without good reasoning. * * So to add a new format: * 1) Use the mapping table above to figure out what to but in * the lowest nibble. * 2) OR in the COGL_PREMULT_BIT, COGL_AFIRST_BIT, COGL_A_BIT and * COGL_BGR_BIT flags as appropriate. * 3) If the result is not yet unique then also combine with an * increment of the last sequence number in the most significant * byte. * * The last sequence number used was 0 (i.e. no formats currently need * a sequence number) * Update this note whenever a new sequence number is used. */ /** * CoglPixelFormat: * @COGL_PIXEL_FORMAT_ANY: Any format * @COGL_PIXEL_FORMAT_A_8: 8 bits alpha mask * @COGL_PIXEL_FORMAT_RG_88: RG, 16 bits. Note that red-green textures * are only available if %COGL_FEATURE_ID_TEXTURE_RG is advertised. * See cogl_texture_set_components() for details. * @COGL_PIXEL_FORMAT_RGB_565: RGB, 16 bits * @COGL_PIXEL_FORMAT_RGBA_4444: RGBA, 16 bits * @COGL_PIXEL_FORMAT_RGBA_5551: RGBA, 16 bits * @COGL_PIXEL_FORMAT_YUV: Not currently supported * @COGL_PIXEL_FORMAT_G_8: Single luminance component * @COGL_PIXEL_FORMAT_RGB_888: RGB, 24 bits * @COGL_PIXEL_FORMAT_BGR_888: BGR, 24 bits * @COGL_PIXEL_FORMAT_RGBA_8888: RGBA, 32 bits * @COGL_PIXEL_FORMAT_BGRA_8888: BGRA, 32 bits * @COGL_PIXEL_FORMAT_ARGB_8888: ARGB, 32 bits * @COGL_PIXEL_FORMAT_ABGR_8888: ABGR, 32 bits * @COGL_PIXEL_FORMAT_RGBA_1010102 : RGBA, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_BGRA_1010102 : BGRA, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_ARGB_2101010 : ARGB, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_ABGR_2101010 : ABGR, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_RGBA_8888_PRE: Premultiplied RGBA, 32 bits * @COGL_PIXEL_FORMAT_BGRA_8888_PRE: Premultiplied BGRA, 32 bits * @COGL_PIXEL_FORMAT_ARGB_8888_PRE: Premultiplied ARGB, 32 bits * @COGL_PIXEL_FORMAT_ABGR_8888_PRE: Premultiplied ABGR, 32 bits * @COGL_PIXEL_FORMAT_RGBA_4444_PRE: Premultiplied RGBA, 16 bits * @COGL_PIXEL_FORMAT_RGBA_5551_PRE: Premultiplied RGBA, 16 bits * @COGL_PIXEL_FORMAT_RGBA_1010102_PRE: Premultiplied RGBA, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_BGRA_1010102_PRE: Premultiplied BGRA, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_ARGB_2101010_PRE: Premultiplied ARGB, 32 bits, 10 bpc * @COGL_PIXEL_FORMAT_ABGR_2101010_PRE: Premultiplied ABGR, 32 bits, 10 bpc * * Pixel formats used by Cogl. For the formats with a byte per * component, the order of the components specify the order in * increasing memory addresses. So for example * %COGL_PIXEL_FORMAT_RGB_888 would have the red component in the * lowest address, green in the next address and blue after that * regardless of the endianness of the system. * * For the formats with non byte aligned components the component * order specifies the order within a 16-bit or 32-bit number from * most significant bit to least significant. So for * %COGL_PIXEL_FORMAT_RGB_565, the red component would be in bits * 11-15, the green component would be in 6-11 and the blue component * would be in 1-5. Therefore the order in memory depends on the * endianness of the system. * * When uploading a texture %COGL_PIXEL_FORMAT_ANY can be used as the * internal format. Cogl will try to pick the best format to use * internally and convert the texture data if necessary. * * Since: 0.8 */ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/ COGL_PIXEL_FORMAT_ANY = 0, COGL_PIXEL_FORMAT_A_8 = 1 | COGL_A_BIT, COGL_PIXEL_FORMAT_RGB_565 = 4, COGL_PIXEL_FORMAT_RGBA_4444 = 5 | COGL_A_BIT, COGL_PIXEL_FORMAT_RGBA_5551 = 6 | COGL_A_BIT, COGL_PIXEL_FORMAT_YUV = 7, COGL_PIXEL_FORMAT_G_8 = 8, COGL_PIXEL_FORMAT_RG_88 = 9, COGL_PIXEL_FORMAT_RGB_888 = 2, COGL_PIXEL_FORMAT_BGR_888 = (2 | COGL_BGR_BIT), COGL_PIXEL_FORMAT_RGBA_8888 = (3 | COGL_A_BIT), COGL_PIXEL_FORMAT_BGRA_8888 = (3 | COGL_A_BIT | COGL_BGR_BIT), COGL_PIXEL_FORMAT_ARGB_8888 = (3 | COGL_A_BIT | COGL_AFIRST_BIT), COGL_PIXEL_FORMAT_ABGR_8888 = (3 | COGL_A_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT), COGL_PIXEL_FORMAT_RGBA_1010102 = (13 | COGL_A_BIT), COGL_PIXEL_FORMAT_BGRA_1010102 = (13 | COGL_A_BIT | COGL_BGR_BIT), COGL_PIXEL_FORMAT_ARGB_2101010 = (13 | COGL_A_BIT | COGL_AFIRST_BIT), COGL_PIXEL_FORMAT_ABGR_2101010 = (13 | COGL_A_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT), COGL_PIXEL_FORMAT_RGBA_8888_PRE = (3 | COGL_A_BIT | COGL_PREMULT_BIT), COGL_PIXEL_FORMAT_BGRA_8888_PRE = (3 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT), COGL_PIXEL_FORMAT_ARGB_8888_PRE = (3 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_AFIRST_BIT), COGL_PIXEL_FORMAT_ABGR_8888_PRE = (3 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT), COGL_PIXEL_FORMAT_RGBA_4444_PRE = (COGL_PIXEL_FORMAT_RGBA_4444 | COGL_A_BIT | COGL_PREMULT_BIT), COGL_PIXEL_FORMAT_RGBA_5551_PRE = (COGL_PIXEL_FORMAT_RGBA_5551 | COGL_A_BIT | COGL_PREMULT_BIT), COGL_PIXEL_FORMAT_RGBA_1010102_PRE = (COGL_PIXEL_FORMAT_RGBA_1010102 | COGL_PREMULT_BIT), COGL_PIXEL_FORMAT_BGRA_1010102_PRE = (COGL_PIXEL_FORMAT_BGRA_1010102 | COGL_PREMULT_BIT), COGL_PIXEL_FORMAT_ARGB_2101010_PRE = (COGL_PIXEL_FORMAT_ARGB_2101010 | COGL_PREMULT_BIT), COGL_PIXEL_FORMAT_ABGR_2101010_PRE = (COGL_PIXEL_FORMAT_ABGR_2101010 | COGL_PREMULT_BIT), COGL_PIXEL_FORMAT_DEPTH_16 = (9 | COGL_DEPTH_BIT), COGL_PIXEL_FORMAT_DEPTH_32 = (3 | COGL_DEPTH_BIT), COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 = (3 | COGL_DEPTH_BIT | COGL_STENCIL_BIT) } CoglPixelFormat; /** * CoglFeatureFlags: * @COGL_FEATURE_TEXTURE_RECTANGLE: ARB_texture_rectangle support * @COGL_FEATURE_TEXTURE_NPOT: Non power of two textures are supported * by the hardware. This is a equivalent to the * %COGL_FEATURE_TEXTURE_NPOT_BASIC, %COGL_FEATURE_TEXTURE_NPOT_MIPMAP * and %COGL_FEATURE_TEXTURE_NPOT_REPEAT features combined. * @COGL_FEATURE_TEXTURE_YUV: ycbcr conversion support * @COGL_FEATURE_TEXTURE_READ_PIXELS: glReadPixels() support * @COGL_FEATURE_SHADERS_GLSL: GLSL support * @COGL_FEATURE_SHADERS_ARBFP: ARBFP support * @COGL_FEATURE_OFFSCREEN: FBO support * @COGL_FEATURE_OFFSCREEN_MULTISAMPLE: Multisample support on FBOs * @COGL_FEATURE_OFFSCREEN_BLIT: Blit support on FBOs * @COGL_FEATURE_FOUR_CLIP_PLANES: At least 4 clip planes available * @COGL_FEATURE_STENCIL_BUFFER: Stencil buffer support * @COGL_FEATURE_VBOS: VBO support * @COGL_FEATURE_PBOS: PBO support * @COGL_FEATURE_UNSIGNED_INT_INDICES: Set if * %COGL_INDICES_TYPE_UNSIGNED_INT is supported in * cogl_vertex_buffer_indices_new(). * @COGL_FEATURE_DEPTH_RANGE: cogl_material_set_depth_range() support * @COGL_FEATURE_TEXTURE_NPOT_BASIC: The hardware supports non power * of two textures, but you also need to check the * %COGL_FEATURE_TEXTURE_NPOT_MIPMAP and %COGL_FEATURE_TEXTURE_NPOT_REPEAT * features to know if the hardware supports npot texture mipmaps * or repeat modes other than * %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE respectively. * @COGL_FEATURE_TEXTURE_NPOT_MIPMAP: Mipmapping is supported in * conjuntion with non power of two textures. * @COGL_FEATURE_TEXTURE_NPOT_REPEAT: Repeat modes other than * %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE are supported by the * hardware. * @COGL_FEATURE_POINT_SPRITE: Whether * cogl_material_set_layer_point_sprite_coords_enabled() is supported. * @COGL_FEATURE_TEXTURE_3D: 3D texture support * @COGL_FEATURE_MAP_BUFFER_FOR_READ: Whether cogl_buffer_map() is * supported with CoglBufferAccess including read support. * @COGL_FEATURE_MAP_BUFFER_FOR_WRITE: Whether cogl_buffer_map() is * supported with CoglBufferAccess including write support. * @COGL_FEATURE_DEPTH_TEXTURE: Whether #CoglFramebuffer support rendering the * depth buffer to a texture. * * Flags for the supported features. * * Since: 0.8 */ typedef enum { COGL_FEATURE_TEXTURE_RECTANGLE = (1 << 1), COGL_FEATURE_TEXTURE_NPOT = (1 << 2), COGL_FEATURE_TEXTURE_YUV = (1 << 3), COGL_FEATURE_TEXTURE_READ_PIXELS = (1 << 4), COGL_FEATURE_SHADERS_GLSL = (1 << 5), COGL_FEATURE_OFFSCREEN = (1 << 6), COGL_FEATURE_OFFSCREEN_MULTISAMPLE = (1 << 7), COGL_FEATURE_OFFSCREEN_BLIT = (1 << 8), COGL_FEATURE_FOUR_CLIP_PLANES = (1 << 9), COGL_FEATURE_STENCIL_BUFFER = (1 << 10), COGL_FEATURE_VBOS = (1 << 11), COGL_FEATURE_PBOS = (1 << 12), COGL_FEATURE_UNSIGNED_INT_INDICES = (1 << 13), COGL_FEATURE_DEPTH_RANGE = (1 << 14), COGL_FEATURE_TEXTURE_NPOT_BASIC = (1 << 15), COGL_FEATURE_TEXTURE_NPOT_MIPMAP = (1 << 16), COGL_FEATURE_TEXTURE_NPOT_REPEAT = (1 << 17), COGL_FEATURE_POINT_SPRITE = (1 << 18), COGL_FEATURE_TEXTURE_3D = (1 << 19), COGL_FEATURE_SHADERS_ARBFP = (1 << 20), COGL_FEATURE_MAP_BUFFER_FOR_READ = (1 << 21), COGL_FEATURE_MAP_BUFFER_FOR_WRITE = (1 << 22), COGL_FEATURE_ONSCREEN_MULTIPLE = (1 << 23), COGL_FEATURE_DEPTH_TEXTURE = (1 << 24) } CoglFeatureFlags; /** * CoglBufferTarget: * @COGL_WINDOW_BUFFER: FIXME * @COGL_OFFSCREEN_BUFFER: FIXME * * Target flags for FBOs. * * Since: 0.8 */ typedef enum { COGL_WINDOW_BUFFER = (1 << 1), COGL_OFFSCREEN_BUFFER = (1 << 2) } CoglBufferTarget; /** * CoglColor: * @red: amount of red * @green: amount of green * @blue: amount of green * @alpha: alpha * * A structure for holding a color definition. The contents of * the CoglColor structure are private and should never by accessed * directly. * * Since: 1.0 */ struct _CoglColor { /*< private >*/ uint8_t COGL_PRIVATE (red); uint8_t COGL_PRIVATE (green); uint8_t COGL_PRIVATE (blue); uint8_t COGL_PRIVATE (alpha); /* padding in case we want to change to floats at * some point */ uint32_t COGL_PRIVATE (padding0); uint32_t COGL_PRIVATE (padding1); uint32_t COGL_PRIVATE (padding2); }; COGL_STRUCT_SIZE_ASSERT (CoglColor, 16); /** * CoglTextureVertex: * @x: Model x-coordinate * @y: Model y-coordinate * @z: Model z-coordinate * @tx: Texture x-coordinate * @ty: Texture y-coordinate * @color: The color to use at this vertex. This is ignored if * use_color is %FALSE when calling cogl_polygon() * * Used to specify vertex information when calling cogl_polygon() */ struct _CoglTextureVertex { float x, y, z; float tx, ty; CoglColor color; }; COGL_STRUCT_SIZE_ASSERT (CoglTextureVertex, 36); /** * CoglTextureFlags: * @COGL_TEXTURE_NONE: No flags specified * @COGL_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of * the mipmap pyramid from the base level image whenever it is * updated. The mipmaps are only generated when the texture is * rendered with a mipmap filter so it should be free to leave out * this flag when using other filtering modes * @COGL_TEXTURE_NO_SLICING: Disables the slicing of the texture * @COGL_TEXTURE_NO_ATLAS: Disables the insertion of the texture inside * the texture atlas used by Cogl * * Flags to pass to the cogl_texture_new_* family of functions. * * Since: 1.0 */ typedef enum { COGL_TEXTURE_NONE = 0, COGL_TEXTURE_NO_AUTO_MIPMAP = 1 << 0, COGL_TEXTURE_NO_SLICING = 1 << 1, COGL_TEXTURE_NO_ATLAS = 1 << 2 } CoglTextureFlags; /** * CoglFogMode: * @COGL_FOG_MODE_LINEAR: Calculates the fog blend factor as: * |[ * f = end - eye_distance / end - start * ]| * @COGL_FOG_MODE_EXPONENTIAL: Calculates the fog blend factor as: * |[ * f = e ^ -(density * eye_distance) * ]| * @COGL_FOG_MODE_EXPONENTIAL_SQUARED: Calculates the fog blend factor as: * |[ * f = e ^ -(density * eye_distance)^2 * ]| * * The fog mode determines the equation used to calculate the fogging blend * factor while fogging is enabled. The simplest %COGL_FOG_MODE_LINEAR mode * determines f as: * * |[ * f = end - eye_distance / end - start * ]| * * Where eye_distance is the distance of the current fragment in eye * coordinates from the origin. * * Since: 1.0 */ typedef enum { COGL_FOG_MODE_LINEAR, COGL_FOG_MODE_EXPONENTIAL, COGL_FOG_MODE_EXPONENTIAL_SQUARED } CoglFogMode; /** * COGL_BLEND_STRING_ERROR: * * #CoglError domain for blend string parser errors * * Since: 1.0 */ #define COGL_BLEND_STRING_ERROR (cogl_blend_string_error_quark ()) /** * CoglBlendStringError: * @COGL_BLEND_STRING_ERROR_PARSE_ERROR: Generic parse error * @COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR: Argument parse error * @COGL_BLEND_STRING_ERROR_INVALID_ERROR: Internal parser error * @COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR: Blend string not * supported by the GPU * * Error enumeration for the blend strings parser * * Since: 1.0 */ typedef enum { /*< prefix=COGL_BLEND_STRING_ERROR >*/ COGL_BLEND_STRING_ERROR_PARSE_ERROR, COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR, COGL_BLEND_STRING_ERROR_INVALID_ERROR, COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR } CoglBlendStringError; uint32_t cogl_blend_string_error_quark (void); #define COGL_SYSTEM_ERROR (_cogl_system_error_quark ()) /** * CoglSystemError: * @COGL_SYSTEM_ERROR_UNSUPPORTED: You tried to use a feature or * configuration not currently available. * @COGL_SYSTEM_ERROR_NO_MEMORY: You tried to allocate a resource * such as a texture and there wasn't enough memory. * * Error enumeration for Cogl * * The @COGL_SYSTEM_ERROR_UNSUPPORTED error can be thrown for a * variety of reasons. For example: * * * You've tried to use a feature that is not * advertised by cogl_has_feature(). This could happen if you create * a 2d texture with a non-power-of-two size when * %COGL_FEATURE_ID_TEXTURE_NPOT is not advertised. * The GPU can not handle the configuration you have * requested. An example might be if you try to use too many texture * layers in a single #CoglPipeline * The driver does not support some * configuration. * * * Currently this is only used by Cogl API marked as experimental so * this enum should also be considered experimental. * * Since: 1.4 * Stability: unstable */ typedef enum { /*< prefix=COGL_ERROR >*/ COGL_SYSTEM_ERROR_UNSUPPORTED, COGL_SYSTEM_ERROR_NO_MEMORY } CoglSystemError; uint32_t _cogl_system_error_quark (void); /** * CoglAttributeType: * @COGL_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte * @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an * unsigned byte * @COGL_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer * @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of * an unsigned short integer * @COGL_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float * * Data types for the components of a vertex attribute. * * Since: 1.0 */ typedef enum { COGL_ATTRIBUTE_TYPE_BYTE = 0x1400, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE = 0x1401, COGL_ATTRIBUTE_TYPE_SHORT = 0x1402, COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT = 0x1403, COGL_ATTRIBUTE_TYPE_FLOAT = 0x1406 } CoglAttributeType; /** * CoglIndicesType: * @COGL_INDICES_TYPE_UNSIGNED_BYTE: Your indices are unsigned bytes * @COGL_INDICES_TYPE_UNSIGNED_SHORT: Your indices are unsigned shorts * @COGL_INDICES_TYPE_UNSIGNED_INT: Your indices are unsigned ints * * You should aim to use the smallest data type that gives you enough * range, since it reduces the size of your index array and can help * reduce the demand on memory bandwidth. * * Note that %COGL_INDICES_TYPE_UNSIGNED_INT is only supported if the * %COGL_FEATURE_ID_UNSIGNED_INT_INDICES feature is available. This * should always be available on OpenGL but on OpenGL ES it will only * be available if the GL_OES_element_index_uint extension is * advertized. */ typedef enum { COGL_INDICES_TYPE_UNSIGNED_BYTE, COGL_INDICES_TYPE_UNSIGNED_SHORT, COGL_INDICES_TYPE_UNSIGNED_INT } CoglIndicesType; /** * CoglVerticesMode: * @COGL_VERTICES_MODE_POINTS: FIXME, equivalent to * GL_POINTS * @COGL_VERTICES_MODE_LINES: FIXME, equivalent to GL_LINES * @COGL_VERTICES_MODE_LINE_LOOP: FIXME, equivalent to * GL_LINE_LOOP * @COGL_VERTICES_MODE_LINE_STRIP: FIXME, equivalent to * GL_LINE_STRIP * @COGL_VERTICES_MODE_TRIANGLES: FIXME, equivalent to * GL_TRIANGLES * @COGL_VERTICES_MODE_TRIANGLE_STRIP: FIXME, equivalent to * GL_TRIANGLE_STRIP * @COGL_VERTICES_MODE_TRIANGLE_FAN: FIXME, equivalent to GL_TRIANGLE_FAN * * Different ways of interpreting vertices when drawing. * * Since: 1.0 */ typedef enum { COGL_VERTICES_MODE_POINTS = 0x0000, COGL_VERTICES_MODE_LINES = 0x0001, COGL_VERTICES_MODE_LINE_LOOP = 0x0002, COGL_VERTICES_MODE_LINE_STRIP = 0x0003, COGL_VERTICES_MODE_TRIANGLES = 0x0004, COGL_VERTICES_MODE_TRIANGLE_STRIP = 0x0005, COGL_VERTICES_MODE_TRIANGLE_FAN = 0x0006 } CoglVerticesMode; /* NB: The above definitions are taken from gl.h equivalents */ /* XXX: should this be CoglMaterialDepthTestFunction? * It makes it very verbose but would be consistent with * CoglMaterialWrapMode */ /** * CoglDepthTestFunction: * @COGL_DEPTH_TEST_FUNCTION_NEVER: Never passes. * @COGL_DEPTH_TEST_FUNCTION_LESS: Passes if the fragment's depth * value is less than the value currently in the depth buffer. * @COGL_DEPTH_TEST_FUNCTION_EQUAL: Passes if the fragment's depth * value is equal to the value currently in the depth buffer. * @COGL_DEPTH_TEST_FUNCTION_LEQUAL: Passes if the fragment's depth * value is less or equal to the value currently in the depth buffer. * @COGL_DEPTH_TEST_FUNCTION_GREATER: Passes if the fragment's depth * value is greater than the value currently in the depth buffer. * @COGL_DEPTH_TEST_FUNCTION_NOTEQUAL: Passes if the fragment's depth * value is not equal to the value currently in the depth buffer. * @COGL_DEPTH_TEST_FUNCTION_GEQUAL: Passes if the fragment's depth * value greater than or equal to the value currently in the depth buffer. * @COGL_DEPTH_TEST_FUNCTION_ALWAYS: Always passes. * * When using depth testing one of these functions is used to compare * the depth of an incoming fragment against the depth value currently * stored in the depth buffer. The function is changed using * cogl_depth_state_set_test_function(). * * The test is only done when depth testing is explicitly enabled. (See * cogl_depth_state_set_test_enabled()) */ typedef enum { COGL_DEPTH_TEST_FUNCTION_NEVER = 0x0200, COGL_DEPTH_TEST_FUNCTION_LESS = 0x0201, COGL_DEPTH_TEST_FUNCTION_EQUAL = 0x0202, COGL_DEPTH_TEST_FUNCTION_LEQUAL = 0x0203, COGL_DEPTH_TEST_FUNCTION_GREATER = 0x0204, COGL_DEPTH_TEST_FUNCTION_NOTEQUAL = 0x0205, COGL_DEPTH_TEST_FUNCTION_GEQUAL = 0x0206, COGL_DEPTH_TEST_FUNCTION_ALWAYS = 0x0207 } CoglDepthTestFunction; /* NB: The above definitions are taken from gl.h equivalents */ typedef enum { /*< prefix=COGL_RENDERER_ERROR >*/ COGL_RENDERER_ERROR_XLIB_DISPLAY_OPEN, COGL_RENDERER_ERROR_BAD_CONSTRAINT } CoglRendererError; /** * CoglFilterReturn: * @COGL_FILTER_CONTINUE: The event was not handled, continues the * processing * @COGL_FILTER_REMOVE: Remove the event, stops the processing * * Return values for the #CoglXlibFilterFunc and #CoglWin32FilterFunc functions. * * Stability: Unstable */ typedef enum _CoglFilterReturn { /*< prefix=COGL_FILTER >*/ COGL_FILTER_CONTINUE, COGL_FILTER_REMOVE } CoglFilterReturn; typedef enum _CoglWinsysFeature { /* Available if the window system can support multiple onscreen * framebuffers at the same time. */ COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, /* Available if onscreen framebuffer swaps can be automatically * throttled to the vblank frequency. */ COGL_WINSYS_FEATURE_SWAP_THROTTLE, /* Available if its possible to query a counter that * increments at each vblank. */ COGL_WINSYS_FEATURE_VBLANK_COUNTER, /* Available if its possible to wait until the next vertical * blank period */ COGL_WINSYS_FEATURE_VBLANK_WAIT, /* Available if the window system supports mapping native * pixmaps to textures. */ COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP, /* Available if the window system supports reporting an event * for swap buffer completions. */ COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, /* Available if it's possible to swap a list of sub rectangles * from the back buffer to the front buffer */ COGL_WINSYS_FEATURE_SWAP_REGION, /* Available if swap_region requests can be automatically throttled * to the vblank frequency. */ COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, /* Available if the swap region implementation won't tear and thus * only needs to be throttled to the framerate */ COGL_WINSYS_FEATURE_SWAP_REGION_SYNCHRONIZED, /* Avaiable if the age of the back buffer can be queried */ COGL_WINSYS_FEATURE_BUFFER_AGE, /* Avaiable if the winsys directly handles _SYNC and _COMPLETE events */ COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, COGL_WINSYS_FEATURE_N_FEATURES } CoglWinsysFeature; /** * CoglColorMask: * @COGL_COLOR_MASK_NONE: None of the color channels are masked * @COGL_COLOR_MASK_RED: Masks the red color channel * @COGL_COLOR_MASK_GREEN: Masks the green color channel * @COGL_COLOR_MASK_BLUE: Masks the blue color channel * @COGL_COLOR_MASK_ALPHA: Masks the alpha color channel * @COGL_COLOR_MASK_ALL: All of the color channels are masked * * Defines a bit mask of color channels. This can be used with * cogl_pipeline_set_color_mask() for example to define which color * channels should be written to the current framebuffer when * drawing something. */ typedef enum { COGL_COLOR_MASK_NONE = 0, COGL_COLOR_MASK_RED = 1L<<0, COGL_COLOR_MASK_GREEN = 1L<<1, COGL_COLOR_MASK_BLUE = 1L<<2, COGL_COLOR_MASK_ALPHA = 1L<<3, /* XXX: glib-mkenums is a perl script that can't cope if we split * this onto multiple lines! *sigh* */ COGL_COLOR_MASK_ALL = (COGL_COLOR_MASK_RED | COGL_COLOR_MASK_GREEN | COGL_COLOR_MASK_BLUE | COGL_COLOR_MASK_ALPHA) } CoglColorMask; /** * CoglWinding: * @COGL_WINDING_CLOCKWISE: Vertices are in a clockwise order * @COGL_WINDING_COUNTER_CLOCKWISE: Vertices are in a counter-clockwise order * * Enum used to represent the two directions of rotation. This can be * used to set the front face for culling by calling * cogl_pipeline_set_front_face_winding(). */ typedef enum { COGL_WINDING_CLOCKWISE, COGL_WINDING_COUNTER_CLOCKWISE } CoglWinding; /** * CoglBufferBit: * @COGL_BUFFER_BIT_COLOR: Selects the primary color buffer * @COGL_BUFFER_BIT_DEPTH: Selects the depth buffer * @COGL_BUFFER_BIT_STENCIL: Selects the stencil buffer * * Types of auxiliary buffers * * Since: 1.0 */ typedef enum { COGL_BUFFER_BIT_COLOR = 1L<<0, COGL_BUFFER_BIT_DEPTH = 1L<<1, COGL_BUFFER_BIT_STENCIL = 1L<<2 } CoglBufferBit; /** * CoglReadPixelsFlags: * @COGL_READ_PIXELS_COLOR_BUFFER: Read from the color buffer * * Flags for cogl_framebuffer_read_pixels_into_bitmap() * * Since: 1.0 */ typedef enum { /*< prefix=COGL_READ_PIXELS >*/ COGL_READ_PIXELS_COLOR_BUFFER = 1L << 0 } CoglReadPixelsFlags; /** * CoglStereoMode: * @COGL_STEREO_BOTH: draw to both stereo buffers * @COGL_STEREO_LEFT: draw only to the left stereo buffer * @COGL_STEREO_RIGHT: draw only to the left stereo buffer * * Represents how draw should affect the two buffers * of a stereo framebuffer. See cogl_framebuffer_set_stereo_mode(). */ typedef enum { COGL_STEREO_BOTH, COGL_STEREO_LEFT, COGL_STEREO_RIGHT } CoglStereoMode; COGL_END_DECLS #endif /* __COGL_TYPES_H__ */ muffin-5.2.1/cogl/cogl/cogl-quaternion.h0000664000175000017500000003707414211404421020277 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_QUATERNION_H__ #define __COGL_QUATERNION_H__ #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-quaternion * @short_description: Functions for initializing and manipulating * quaternions. * * Quaternions have become a standard form for representing 3D * rotations and have some nice properties when compared with other * representation such as (roll,pitch,yaw) Euler angles. They can be * used to interpolate between different rotations and they don't * suffer from a problem called * "Gimbal lock" * where two of the axis of rotation may become aligned and you loose a * degree of freedom. * . */ #include #include #include /** * CoglQuaternion: * @w: based on the angle of rotation it is cos(𝜃/2) * @x: based on the angle of rotation and x component of the axis of * rotation it is sin(𝜃/2)*axis.x * @y: based on the angle of rotation and y component of the axis of * rotation it is sin(𝜃/2)*axis.y * @z: based on the angle of rotation and z component of the axis of * rotation it is sin(𝜃/2)*axis.z * * A quaternion is comprised of a scalar component and a 3D vector * component. The scalar component is normally referred to as w and the * vector might either be referred to as v or a (for axis) or expanded * with the individual components: (x, y, z) A full quaternion would * then be written as [w (x, y, z)]. * * Quaternions can be considered to represent an axis and angle * pair although sadly these numbers are buried somewhat under some * maths... * * For the curious you can see here that a given axis (a) and angle (𝜃) * pair are represented in a quaternion as follows: * |[ * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )] * ]| * * Unit Quaternions: * When using Quaternions to represent spatial orientations for 3D * graphics it's always assumed you have a unit quaternion. The * magnitude of a quaternion is defined as: * |[ * sqrt (w² + x² + y² + z²) * ]| * and a unit quaternion satisfies this equation: * |[ * w² + x² + y² + z² = 1 * ]| * * Thankfully most of the time we don't actually have to worry about * the maths that goes on behind the scenes but if you are curious to * learn more here are some external references: * * * * * * * * * * * * * * * * 3D Maths Primer for Graphics and Game Development ISBN-10: 1556229119 * * * * * * * * * */ struct _CoglQuaternion { /*< public >*/ float w; float x; float y; float z; /*< private >*/ float padding0; float padding1; float padding2; float padding3; }; COGL_STRUCT_SIZE_ASSERT (CoglQuaternion, 32); /** * cogl_quaternion_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_quaternion_get_gtype (void); /** * cogl_quaternion_init: * @quaternion: An uninitialized #CoglQuaternion * @angle: The angle you want to rotate around the given axis * @x: The x component of your axis vector about which you want to * rotate. * @y: The y component of your axis vector about which you want to * rotate. * @z: The z component of your axis vector about which you want to * rotate. * * Initializes a quaternion that rotates @angle degrees around the * axis vector (@x, @y, @z). The axis vector does not need to be * normalized. * * Returns: A normalized, unit quaternion representing an orientation * rotated @angle degrees around the axis vector (@x, @y, @z) * * Since: 2.0 */ void cogl_quaternion_init (CoglQuaternion *quaternion, float angle, float x, float y, float z); /** * cogl_quaternion_init_from_angle_vector: * @quaternion: An uninitialized #CoglQuaternion * @angle: The angle to rotate around @axis3f * @axis3f: your 3 component axis vector about which you want to rotate. * * Initializes a quaternion that rotates @angle degrees around the * given @axis vector. The axis vector does not need to be * normalized. * * Returns: A normalized, unit quaternion representing an orientation * rotated @angle degrees around the given @axis vector. * * Since: 2.0 */ void cogl_quaternion_init_from_angle_vector (CoglQuaternion *quaternion, float angle, const float *axis3f); /** * cogl_quaternion_init_identity: * @quaternion: An uninitialized #CoglQuaternion * * Initializes the quaternion with the canonical quaternion identity * [1 (0, 0, 0)] which represents no rotation. Multiplying a * quaternion with this identity leaves the quaternion unchanged. * * You might also want to consider using * cogl_get_static_identity_quaternion(). * * Since: 2.0 */ void cogl_quaternion_init_identity (CoglQuaternion *quaternion); /** * cogl_quaternion_init_from_array: * @quaternion: A #CoglQuaternion * @array: An array of 4 floats w,(x,y,z) * * Initializes a [w (x, y,z)] quaternion directly from an array of 4 * floats: [w,x,y,z]. * * Since: 2.0 */ void cogl_quaternion_init_from_array (CoglQuaternion *quaternion, const float *array); /** * cogl_quaternion_init_from_x_rotation: * @quaternion: An uninitialized #CoglQuaternion * @angle: The angle to rotate around the x axis * * XXX: check which direction this rotates * * Since: 2.0 */ void cogl_quaternion_init_from_x_rotation (CoglQuaternion *quaternion, float angle); /** * cogl_quaternion_init_from_y_rotation: * @quaternion: An uninitialized #CoglQuaternion * @angle: The angle to rotate around the y axis * * * Since: 2.0 */ void cogl_quaternion_init_from_y_rotation (CoglQuaternion *quaternion, float angle); /** * cogl_quaternion_init_from_z_rotation: * @quaternion: An uninitialized #CoglQuaternion * @angle: The angle to rotate around the z axis * * * Since: 2.0 */ void cogl_quaternion_init_from_z_rotation (CoglQuaternion *quaternion, float angle); /** * cogl_quaternion_init_from_euler: * @quaternion: A #CoglQuaternion * @euler: A #CoglEuler with which to initialize the quaternion * * Since: 2.0 */ void cogl_quaternion_init_from_euler (CoglQuaternion *quaternion, const CoglEuler *euler); /** * cogl_quaternion_init_from_quaternion: * @quaternion: A #CoglQuaternion * @src: A #CoglQuaternion with which to initialize @quaternion * * Since: 2.0 */ void cogl_quaternion_init_from_quaternion (CoglQuaternion *quaternion, CoglQuaternion *src); /** * cogl_quaternion_init_from_matrix: * @quaternion: A Cogl Quaternion * @matrix: A rotation matrix with which to initialize the quaternion * * Initializes a quaternion from a rotation matrix. * * Since: 1.10 * Stability: unstable */ void cogl_quaternion_init_from_matrix (CoglQuaternion *quaternion, const CoglMatrix *matrix); /** * cogl_quaternion_equal: * @v1: A #CoglQuaternion * @v2: A #CoglQuaternion * * Compares that all the components of quaternions @a and @b are * equal. * * An epsilon value is not used to compare the float components, but * the == operator is at least used so that 0 and -0 are considered * equal. * * Returns: %TRUE if the quaternions are equal else %FALSE. * * Since: 2.0 */ CoglBool cogl_quaternion_equal (const void *v1, const void *v2); /** * cogl_quaternion_copy: * @src: A #CoglQuaternion * * Allocates a new #CoglQuaternion on the stack and initializes it with * the same values as @src. * * Returns: A newly allocated #CoglQuaternion which should be freed * using cogl_quaternion_free() * * Since: 2.0 */ CoglQuaternion * cogl_quaternion_copy (const CoglQuaternion *src); /** * cogl_quaternion_free: * @quaternion: A #CoglQuaternion * * Frees a #CoglQuaternion that was previously allocated via * cogl_quaternion_copy(). * * Since: 2.0 */ void cogl_quaternion_free (CoglQuaternion *quaternion); /** * cogl_quaternion_get_rotation_angle: * @quaternion: A #CoglQuaternion * * * Since: 2.0 */ float cogl_quaternion_get_rotation_angle (const CoglQuaternion *quaternion); /** * cogl_quaternion_get_rotation_axis: * @quaternion: A #CoglQuaternion * @vector3: (out): an allocated 3-float array * * Since: 2.0 */ void cogl_quaternion_get_rotation_axis (const CoglQuaternion *quaternion, float *vector3); /** * cogl_quaternion_normalize: * @quaternion: A #CoglQuaternion * * * Since: 2.0 */ void cogl_quaternion_normalize (CoglQuaternion *quaternion); /** * cogl_quaternion_dot_product: * @a: A #CoglQuaternion * @b: A #CoglQuaternion * * Since: 2.0 */ float cogl_quaternion_dot_product (const CoglQuaternion *a, const CoglQuaternion *b); /** * cogl_quaternion_invert: * @quaternion: A #CoglQuaternion * * * Since: 2.0 */ void cogl_quaternion_invert (CoglQuaternion *quaternion); /** * cogl_quaternion_multiply: * @result: The destination #CoglQuaternion * @left: The second #CoglQuaternion rotation to apply * @right: The first #CoglQuaternion rotation to apply * * This combines the rotations of two quaternions into @result. The * operation is not commutative so the order is important because AxB * != BxA. Cogl follows the standard convention for quaternions here * so the rotations are applied @right to @left. This is similar to the * combining of matrices. * * It is possible to multiply the @a quaternion in-place, so * @result can be equal to @a but can't be equal to @b. * * Since: 2.0 */ void cogl_quaternion_multiply (CoglQuaternion *result, const CoglQuaternion *left, const CoglQuaternion *right); /** * cogl_quaternion_pow: * @quaternion: A #CoglQuaternion * @exponent: the exponent * * * Since: 2.0 */ void cogl_quaternion_pow (CoglQuaternion *quaternion, float exponent); /** * cogl_quaternion_slerp: * @result: The destination #CoglQuaternion * @a: The first #CoglQuaternion * @b: The second #CoglQuaternion * @t: The factor in the range [0,1] used to interpolate between * quaternion @a and @b. * * Performs a spherical linear interpolation between two quaternions. * * Noteable properties: * * * commutative: No * * * constant velocity: Yes * * * torque minimal (travels along the surface of the 4-sphere): Yes * * * more expensive than cogl_quaternion_nlerp() * * */ void cogl_quaternion_slerp (CoglQuaternion *result, const CoglQuaternion *a, const CoglQuaternion *b, float t); /** * cogl_quaternion_nlerp: * @result: The destination #CoglQuaternion * @a: The first #CoglQuaternion * @b: The second #CoglQuaternion * @t: The factor in the range [0,1] used to interpolate between * quaterion @a and @b. * * Performs a normalized linear interpolation between two quaternions. * That is it does a linear interpolation of the quaternion components * and then normalizes the result. This will follow the shortest arc * between the two orientations (just like the slerp() function) but * will not progress at a constant speed. Unlike slerp() nlerp is * commutative which is useful if you are blending animations * together. (I.e. nlerp (tmp, a, b) followed by nlerp (result, tmp, * d) is the same as nlerp (tmp, a, d) followed by nlerp (result, tmp, * b)). Finally nlerp is cheaper than slerp so it can be a good choice * if you don't need the constant speed property of the slerp() function. * * Notable properties: * * * commutative: Yes * * * constant velocity: No * * * torque minimal (travels along the surface of the 4-sphere): Yes * * * faster than cogl_quaternion_slerp() * * */ void cogl_quaternion_nlerp (CoglQuaternion *result, const CoglQuaternion *a, const CoglQuaternion *b, float t); /** * cogl_quaternion_squad: * @result: The destination #CoglQuaternion * @prev: A #CoglQuaternion used before @a * @a: The first #CoglQuaternion * @b: The second #CoglQuaternion * @next: A #CoglQuaternion that will be used after @b * @t: The factor in the range [0,1] used to interpolate between * quaternion @a and @b. * * * Since: 2.0 */ void cogl_quaternion_squad (CoglQuaternion *result, const CoglQuaternion *prev, const CoglQuaternion *a, const CoglQuaternion *b, const CoglQuaternion *next, float t); /** * cogl_get_static_identity_quaternion: * * Returns a pointer to a singleton quaternion constant describing the * canonical identity [1 (0, 0, 0)] which represents no rotation. * * If you multiply a quaternion with the identity quaternion you will * get back the same value as the original quaternion. * * Returns: A pointer to an identity quaternion * * Since: 2.0 */ const CoglQuaternion * cogl_get_static_identity_quaternion (void); /** * cogl_get_static_zero_quaternion: * * Returns: a pointer to a singleton quaternion constant describing a * rotation of 180 degrees around a degenerate axis: * [0 (0, 0, 0)] * * Since: 2.0 */ const CoglQuaternion * cogl_get_static_zero_quaternion (void); COGL_END_DECLS #endif /* __COGL_QUATERNION_H__ */ muffin-5.2.1/cogl/cogl/cogl-texture-private.h0000664000175000017500000003415314211404421021255 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_TEXTURE_PRIVATE_H #define __COGL_TEXTURE_PRIVATE_H #include "cogl-bitmap-private.h" #include "cogl-object-private.h" #include "cogl-pipeline-private.h" #include "cogl-spans.h" #include "cogl-meta-texture.h" #include "cogl-framebuffer.h" #include "cogl-texture-2d.h" #ifdef COGL_HAS_EGL_SUPPORT #include "cogl-egl-defines.h" #endif typedef struct _CoglTextureVtable CoglTextureVtable; /* Encodes three possibiloities result of transforming a quad */ typedef enum { /* quad doesn't cross the boundaries of a texture */ COGL_TRANSFORM_NO_REPEAT, /* quad crosses boundaries, hardware wrap mode can handle */ COGL_TRANSFORM_HARDWARE_REPEAT, /* quad crosses boundaries, needs software fallback; * for a sliced texture, this might not actually involve * repeating, just a quad crossing multiple slices */ COGL_TRANSFORM_SOFTWARE_REPEAT, } CoglTransformResult; /* Flags given to the pre_paint method */ typedef enum { /* The texture is going to be used with filters that require mipmapping. This gives the texture the opportunity to automatically update the mipmap tree */ COGL_TEXTURE_NEEDS_MIPMAP = 1 } CoglTexturePrePaintFlags; struct _CoglTextureVtable { /* Virtual functions that must be implemented for a texture backend */ CoglBool is_primitive; CoglBool (* allocate) (CoglTexture *tex, CoglError **error); /* This should update the specified sub region of the texture with a sub region of the given bitmap. The bitmap is not converted before being set so the caller is expected to have called _cogl_bitmap_convert_for_upload with a suitable internal_format before passing here */ CoglBool (* set_region) (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, int level, CoglBitmap *bitmap, CoglError **error); /* This should copy the image data of the texture into @data. The requested format will have been first passed through ctx->texture_driver->find_best_gl_get_data_format so it should always be a format that is valid for GL (ie, no conversion should be necessary). */ CoglBool (* get_data) (CoglTexture *tex, CoglPixelFormat format, int rowstride, uint8_t *data); void (* foreach_sub_texture_in_region) (CoglTexture *tex, float virtual_tx_1, float virtual_ty_1, float virtual_tx_2, float virtual_ty_2, CoglMetaTextureCallback callback, void *user_data); int (* get_max_waste) (CoglTexture *tex); CoglBool (* is_sliced) (CoglTexture *tex); CoglBool (* can_hardware_repeat) (CoglTexture *tex); void (* transform_coords_to_gl) (CoglTexture *tex, float *s, float *t); CoglTransformResult (* transform_quad_coords_to_gl) (CoglTexture *tex, float *coords); CoglBool (* get_gl_texture) (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target); /* OpenGL driver specific virtual function */ void (* gl_flush_legacy_texobj_filters) (CoglTexture *tex, GLenum min_filter, GLenum mag_filter); void (* pre_paint) (CoglTexture *tex, CoglTexturePrePaintFlags flags); void (* ensure_non_quad_rendering) (CoglTexture *tex); /* OpenGL driver specific virtual function */ void (* gl_flush_legacy_texobj_wrap_modes) (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p); CoglPixelFormat (* get_format) (CoglTexture *tex); GLenum (* get_gl_format) (CoglTexture *tex); CoglTextureType (* get_type) (CoglTexture *tex); CoglBool (* is_foreign) (CoglTexture *tex); /* Only needs to be implemented if is_primitive == TRUE */ void (* set_auto_mipmap) (CoglTexture *texture, CoglBool value); }; typedef enum _CoglTextureSoureType { COGL_TEXTURE_SOURCE_TYPE_SIZED = 1, COGL_TEXTURE_SOURCE_TYPE_BITMAP, COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE, COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN, COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE_EXTERNAL } CoglTextureSourceType; typedef struct _CoglTextureLoader { CoglTextureSourceType src_type; union { struct { int width; int height; int depth; /* for 3d textures */ } sized; struct { CoglBitmap *bitmap; int height; /* for 3d textures */ int depth; /* for 3d textures */ CoglBool can_convert_in_place; } bitmap; #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) struct { EGLImageKHR image; int width; int height; CoglPixelFormat format; } egl_image; #endif #if defined (COGL_HAS_EGL_SUPPORT) struct { int width; int height; CoglTexture2DEGLImageExternalAlloc alloc; CoglPixelFormat format; } egl_image_external; #endif struct { int width; int height; unsigned int gl_handle; CoglPixelFormat format; } gl_foreign; } src; } CoglTextureLoader; struct _CoglTexture { CoglObject _parent; CoglContext *context; CoglTextureLoader *loader; GList *framebuffers; int max_level; int width; int height; CoglBool allocated; /* * Internal format */ CoglTextureComponents components; unsigned int premultiplied:1; const CoglTextureVtable *vtable; }; typedef enum _CoglTextureChangeFlags { /* Whenever the internals of a texture are changed such that the * underlying GL textures that represent the CoglTexture change then * we notify cogl-material.c via * _cogl_pipeline_texture_pre_change_notify */ COGL_TEXTURE_CHANGE_GL_TEXTURES } CoglTextureChangeFlags; typedef struct _CoglTexturePixel CoglTexturePixel; /* This is used by the texture backends to store the first pixel of each GL texture. This is only used when glGenerateMipmap is not available so that we can temporarily set GL_GENERATE_MIPMAP and reupload a pixel */ struct _CoglTexturePixel { /* We need to store the format of the pixel because we store the data in the source format which might end up being different for each slice if a subregion is updated with a different format */ GLenum gl_format; GLenum gl_type; uint8_t data[4]; }; void _cogl_texture_init (CoglTexture *texture, CoglContext *ctx, int width, int height, CoglPixelFormat src_format, CoglTextureLoader *loader, const CoglTextureVtable *vtable); void _cogl_texture_free (CoglTexture *texture); /* This is used to register a type to the list of handle types that will be considered a texture in cogl_is_texture() */ void _cogl_texture_register_texture_type (const CoglObjectClass *klass); #define COGL_TEXTURE_DEFINE(TypeName, type_name) \ COGL_OBJECT_DEFINE_WITH_CODE_GTYPE \ (TypeName, type_name, \ _cogl_texture_register_texture_type (&_cogl_##type_name##_class)) #define COGL_TEXTURE_INTERNAL_DEFINE(TypeName, type_name) \ COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE \ (TypeName, type_name, \ _cogl_texture_register_texture_type (&_cogl_##type_name##_class)) CoglBool _cogl_texture_can_hardware_repeat (CoglTexture *texture); void _cogl_texture_transform_coords_to_gl (CoglTexture *texture, float *s, float *t); CoglTransformResult _cogl_texture_transform_quad_coords_to_gl (CoglTexture *texture, float *coords); void _cogl_texture_pre_paint (CoglTexture *texture, CoglTexturePrePaintFlags flags); void _cogl_texture_ensure_non_quad_rendering (CoglTexture *texture); /* * This determines a CoglPixelFormat according to texture::components * and texture::premultiplied (i.e. the user required components and * whether the texture should be considered premultiplied) * * A reference/source format can be given (or COGL_PIXEL_FORMAT_ANY) * and wherever possible this function tries to simply return the * given source format if its compatible with the required components. * * Texture backends can call this when allocating a texture to know * how to convert a source image in preparation for uploading. */ CoglPixelFormat _cogl_texture_determine_internal_format (CoglTexture *texture, CoglPixelFormat src_format); /* This is called by texture backends when they have successfully * allocated a texture. * * Most texture backends currently track the internal layout of * textures using a CoglPixelFormat which will be finalized when a * texture is allocated. At this point we need to update * texture::components and texture::premultiplied according to the * determined layout. * * XXX: Going forward we should probably aim to stop using * CoglPixelFormat at all for tracking the internal layout of * textures. */ void _cogl_texture_set_internal_format (CoglTexture *texture, CoglPixelFormat internal_format); CoglBool _cogl_texture_is_foreign (CoglTexture *texture); void _cogl_texture_associate_framebuffer (CoglTexture *texture, CoglFramebuffer *framebuffer); const GList * _cogl_texture_get_associated_framebuffers (CoglTexture *texture); void _cogl_texture_flush_journal_rendering (CoglTexture *texture); void _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans, int n_x_spans, CoglSpan *y_spans, int n_y_spans, CoglTexture **textures, float *virtual_coords, float x_normalize_factor, float y_normalize_factor, CoglPipelineWrapMode wrap_x, CoglPipelineWrapMode wrap_y, CoglMetaTextureCallback callback, void *user_data); /* * _cogl_texture_get_type: * @texture: a #CoglTexture pointer * * Retrieves the texture type of the underlying hardware texture that * this #CoglTexture will use. * * Return value: The type of the hardware texture. */ CoglTextureType _cogl_texture_get_type (CoglTexture *texture); CoglBool _cogl_texture_set_region (CoglTexture *texture, int width, int height, CoglPixelFormat format, int rowstride, const uint8_t *data, int dst_x, int dst_y, int level, CoglError **error); CoglBool _cogl_texture_set_region_from_bitmap (CoglTexture *texture, int src_x, int src_y, int width, int height, CoglBitmap *bmp, int dst_x, int dst_y, int level, CoglError **error); CoglBool _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format, CoglPixelFormat dst_format); int _cogl_texture_get_n_levels (CoglTexture *texture); void _cogl_texture_get_level_size (CoglTexture *texture, int level, int *width, int *height, int *depth); void _cogl_texture_set_allocated (CoglTexture *texture, CoglPixelFormat internal_format, int width, int height); CoglPixelFormat _cogl_texture_get_format (CoglTexture *texture); CoglTextureLoader * _cogl_texture_create_loader (void); void _cogl_texture_copy_internal_format (CoglTexture *src, CoglTexture *dest); #endif /* __COGL_TEXTURE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-glsl-shader-private.h0000664000175000017500000000341114211404421021753 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef _COGL_GLSL_SHADER_PRIVATE_H_ #define _COGL_GLSL_SHADER_PRIVATE_H_ void _cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx, GLuint shader_gl_handle, GLenum shader_gl_type, CoglPipeline *pipeline, GLsizei count_in, const char **strings_in, const GLint *lengths_in); #endif /* _COGL_GLSL_SHADER_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/cogl-list.c0000664000175000017500000000443514211404421017053 0ustar jpeisachjpeisach/* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011, 2012 Intel Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting documentation, and * that the name of the copyright holders not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no representations * about the suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ /* This list implementation is based on the Wayland source code */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include "cogl-list.h" void _cogl_list_init (CoglList *list) { list->prev = list; list->next = list; } void _cogl_list_insert (CoglList *list, CoglList *elm) { elm->prev = list; elm->next = list->next; list->next = elm; elm->next->prev = elm; } void _cogl_list_remove (CoglList *elm) { elm->prev->next = elm->next; elm->next->prev = elm->prev; elm->next = NULL; elm->prev = NULL; } int _cogl_list_length (CoglList *list) { CoglList *e; int count; count = 0; e = list->next; while (e != list) { e = e->next; count++; } return count; } int _cogl_list_empty (CoglList *list) { return list->next == list; } void _cogl_list_insert_list (CoglList *list, CoglList *other) { if (_cogl_list_empty (other)) return; other->next->prev = list; other->prev->next = list->next; list->next->prev = other->prev; list->next = other->next; } muffin-5.2.1/cogl/cogl/cogl-texture-3d.c0000664000175000017500000006127414211404421020110 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-private.h" #include "cogl-util.h" #include "cogl-texture-private.h" #include "cogl-texture-3d-private.h" #include "cogl-texture-3d.h" #include "cogl-texture-gl-private.h" #include "cogl-texture-driver.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-journal-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" #include "cogl-util-gl-private.h" #include "cogl-gtype-private.h" #include #include /* These might not be defined on GLES */ #ifndef GL_TEXTURE_3D #define GL_TEXTURE_3D 0x806F #endif #ifndef GL_TEXTURE_WRAP_R #define GL_TEXTURE_WRAP_R 0x8072 #endif static void _cogl_texture_3d_free (CoglTexture3D *tex_3d); COGL_TEXTURE_DEFINE (Texture3D, texture_3d); COGL_GTYPE_DEFINE_CLASS (Texture3D, texture_3d, COGL_GTYPE_IMPLEMENT_INTERFACE (texture)); static const CoglTextureVtable cogl_texture_3d_vtable; static void _cogl_texture_3d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex); CoglContext *ctx = tex->context; /* Only set the wrap mode if it's different from the current value to avoid too many GL calls. */ if (tex_3d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s || tex_3d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t || tex_3d->gl_legacy_texobj_wrap_mode_p != wrap_mode_p) { _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, tex_3d->gl_texture, FALSE); GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, wrap_mode_s) ); GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, wrap_mode_t) ); GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, wrap_mode_p) ); tex_3d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s; tex_3d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t; tex_3d->gl_legacy_texobj_wrap_mode_p = wrap_mode_p; } } static void _cogl_texture_3d_free (CoglTexture3D *tex_3d) { if (tex_3d->gl_texture) _cogl_delete_gl_texture (tex_3d->gl_texture); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (tex_3d)); } static void _cogl_texture_3d_set_auto_mipmap (CoglTexture *tex, CoglBool value) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex); tex_3d->auto_mipmap = value; } static CoglTexture3D * _cogl_texture_3d_create_base (CoglContext *ctx, int width, int height, int depth, CoglPixelFormat internal_format, CoglTextureLoader *loader) { CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1); CoglTexture *tex = COGL_TEXTURE (tex_3d); _cogl_texture_init (tex, ctx, width, height, internal_format, loader, &cogl_texture_3d_vtable); tex_3d->gl_texture = 0; tex_3d->depth = depth; tex_3d->mipmaps_dirty = TRUE; tex_3d->auto_mipmap = TRUE; /* We default to GL_LINEAR for both filters */ tex_3d->gl_legacy_texobj_min_filter = GL_LINEAR; tex_3d->gl_legacy_texobj_mag_filter = GL_LINEAR; /* Wrap mode not yet set */ tex_3d->gl_legacy_texobj_wrap_mode_s = GL_FALSE; tex_3d->gl_legacy_texobj_wrap_mode_t = GL_FALSE; tex_3d->gl_legacy_texobj_wrap_mode_p = GL_FALSE; return _cogl_texture_3d_object_new (tex_3d); } CoglTexture3D * cogl_texture_3d_new_with_size (CoglContext *ctx, int width, int height, int depth) { CoglTextureLoader *loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED; loader->src.sized.width = width; loader->src.sized.height = height; loader->src.sized.depth = depth; return _cogl_texture_3d_create_base (ctx, width, height, depth, COGL_PIXEL_FORMAT_RGBA_8888_PRE, loader); } CoglTexture3D * cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp, int height, int depth) { CoglTextureLoader *loader; _COGL_RETURN_VAL_IF_FAIL (bmp, NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP; loader->src.bitmap.bitmap = cogl_object_ref (bmp); loader->src.bitmap.height = height; loader->src.bitmap.depth = depth; loader->src.bitmap.can_convert_in_place = FALSE; /* TODO add api for this */ return _cogl_texture_3d_create_base (_cogl_bitmap_get_context (bmp), cogl_bitmap_get_width (bmp), height, depth, cogl_bitmap_get_format (bmp), loader); } CoglTexture3D * cogl_texture_3d_new_from_data (CoglContext *context, int width, int height, int depth, CoglPixelFormat format, int rowstride, int image_stride, const uint8_t *data, CoglError **error) { CoglBitmap *bitmap; CoglTexture3D *ret; _COGL_RETURN_VAL_IF_FAIL (data, NULL); _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); /* Rowstride from width if not given */ if (rowstride == 0) rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); /* Image stride from height and rowstride if not given */ if (image_stride == 0) image_stride = height * rowstride; if (image_stride < rowstride * height) return NULL; /* GL doesn't support uploading when the image_stride isn't a multiple of the rowstride. If this happens we'll just pack the image into a new bitmap. The documentation for this function recommends avoiding this situation. */ if (image_stride % rowstride != 0) { uint8_t *bmp_data; int bmp_rowstride; int z, y; bitmap = _cogl_bitmap_new_with_malloc_buffer (context, width, depth * height, format, error); if (!bitmap) return NULL; bmp_data = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, error); if (bmp_data == NULL) { cogl_object_unref (bitmap); return NULL; } bmp_rowstride = cogl_bitmap_get_rowstride (bitmap); /* Copy all of the images in */ for (z = 0; z < depth; z++) for (y = 0; y < height; y++) memcpy (bmp_data + (z * bmp_rowstride * height + bmp_rowstride * y), data + z * image_stride + rowstride * y, bmp_rowstride); _cogl_bitmap_unmap (bitmap); } else bitmap = cogl_bitmap_new_for_data (context, width, image_stride / rowstride * depth, format, rowstride, (uint8_t *) data); ret = cogl_texture_3d_new_from_bitmap (bitmap, height, depth); cogl_object_unref (bitmap); if (ret && !cogl_texture_allocate (COGL_TEXTURE (ret), error)) { cogl_object_unref (ret); return NULL; } return ret; } static CoglBool _cogl_texture_3d_can_create (CoglContext *ctx, int width, int height, int depth, CoglPixelFormat internal_format, CoglError **error) { GLenum gl_intformat; GLenum gl_type; /* This should only happen on GLES */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "3D textures are not supported by the GPU"); return FALSE; } /* If NPOT textures aren't supported then the size must be a power of two */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT) && (!_cogl_util_is_pot (width) || !_cogl_util_is_pot (height) || !_cogl_util_is_pot (depth))) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "A non-power-of-two size was requested but this is not " "supported by the GPU"); return FALSE; } ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, NULL, &gl_type); /* Check that the driver can create a texture with that size */ if (!ctx->texture_driver->size_supported_3d (ctx, GL_TEXTURE_3D, gl_intformat, gl_type, width, height, depth)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "The requested dimensions are not supported by the GPU"); return FALSE; } return TRUE; } static CoglBool allocate_with_size (CoglTexture3D *tex_3d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_3d); CoglContext *ctx = tex->context; CoglPixelFormat internal_format; int width = loader->src.sized.width; int height = loader->src.sized.height; int depth = loader->src.sized.depth; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; GLenum gl_texture; internal_format = _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); if (!_cogl_texture_3d_can_create (ctx, width, height, depth, internal_format, error)) return FALSE; ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, &gl_format, &gl_type); gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format); _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, gl_texture, FALSE); /* Clear any GL errors */ _cogl_gl_util_clear_gl_errors (ctx); ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat, width, height, depth, 0, gl_format, gl_type, NULL); if (_cogl_gl_util_catch_out_of_memory (ctx, error)) { GE( ctx, glDeleteTextures (1, &gl_texture) ); return FALSE; } tex_3d->gl_texture = gl_texture; tex_3d->gl_format = gl_intformat; tex_3d->depth = depth; tex_3d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, width, height); return TRUE; } static CoglBool allocate_from_bitmap (CoglTexture3D *tex_3d, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_3d); CoglContext *ctx = tex->context; CoglPixelFormat internal_format; CoglBitmap *bmp = loader->src.bitmap.bitmap; int bmp_width = cogl_bitmap_get_width (bmp); int height = loader->src.bitmap.height; int depth = loader->src.bitmap.depth; CoglPixelFormat bmp_format = cogl_bitmap_get_format (bmp); CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place; CoglBitmap *upload_bmp; CoglPixelFormat upload_format; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; internal_format = _cogl_texture_determine_internal_format (tex, bmp_format); if (!_cogl_texture_3d_can_create (ctx, bmp_width, height, depth, internal_format, error)) return FALSE; upload_bmp = _cogl_bitmap_convert_for_upload (bmp, internal_format, can_convert_in_place, error); if (upload_bmp == NULL) return FALSE; upload_format = cogl_bitmap_get_format (upload_bmp); ctx->driver_vtable->pixel_format_to_gl (ctx, upload_format, NULL, /* internal format */ &gl_format, &gl_type); ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, &gl_intformat, NULL, NULL); /* Keep a copy of the first pixel so that if glGenerateMipmap isn't supported we can fallback to using GL_GENERATE_MIPMAP */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) { CoglError *ignore = NULL; uint8_t *data = _cogl_bitmap_map (upload_bmp, COGL_BUFFER_ACCESS_READ, 0, &ignore); tex_3d->first_pixel.gl_format = gl_format; tex_3d->first_pixel.gl_type = gl_type; if (data) { memcpy (tex_3d->first_pixel.data, data, _cogl_pixel_format_get_bytes_per_pixel (upload_format)); _cogl_bitmap_unmap (upload_bmp); } else { g_warning ("Failed to read first pixel of bitmap for " "glGenerateMipmap fallback"); cogl_error_free (ignore); memset (tex_3d->first_pixel.data, 0, _cogl_pixel_format_get_bytes_per_pixel (upload_format)); } } tex_3d->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format); if (!ctx->texture_driver->upload_to_gl_3d (ctx, GL_TEXTURE_3D, tex_3d->gl_texture, FALSE, /* is_foreign */ height, depth, upload_bmp, gl_intformat, gl_format, gl_type, error)) { cogl_object_unref (upload_bmp); return FALSE; } tex_3d->gl_format = gl_intformat; cogl_object_unref (upload_bmp); tex_3d->depth = loader->src.bitmap.depth; tex_3d->internal_format = internal_format; _cogl_texture_set_allocated (tex, internal_format, bmp_width, loader->src.bitmap.height); return TRUE; } static CoglBool _cogl_texture_3d_allocate (CoglTexture *tex, CoglError **error) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex); CoglTextureLoader *loader = tex->loader; _COGL_RETURN_VAL_IF_FAIL (loader, FALSE); switch (loader->src_type) { case COGL_TEXTURE_SOURCE_TYPE_SIZED: return allocate_with_size (tex_3d, loader, error); case COGL_TEXTURE_SOURCE_TYPE_BITMAP: return allocate_from_bitmap (tex_3d, loader, error); default: break; } g_return_val_if_reached (FALSE); } static int _cogl_texture_3d_get_max_waste (CoglTexture *tex) { return -1; } static CoglBool _cogl_texture_3d_is_sliced (CoglTexture *tex) { return FALSE; } static CoglBool _cogl_texture_3d_can_hardware_repeat (CoglTexture *tex) { return TRUE; } static void _cogl_texture_3d_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { /* The texture coordinates map directly so we don't need to do anything */ } static CoglTransformResult _cogl_texture_3d_transform_quad_coords_to_gl (CoglTexture *tex, float *coords) { /* The texture coordinates map directly so we don't need to do anything other than check for repeats */ CoglBool need_repeat = FALSE; int i; for (i = 0; i < 4; i++) if (coords[i] < 0.0f || coords[i] > 1.0f) need_repeat = TRUE; return (need_repeat ? COGL_TRANSFORM_HARDWARE_REPEAT : COGL_TRANSFORM_NO_REPEAT); } static CoglBool _cogl_texture_3d_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex); if (out_gl_handle) *out_gl_handle = tex_3d->gl_texture; if (out_gl_target) *out_gl_target = GL_TEXTURE_3D; return TRUE; } static void _cogl_texture_3d_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex); CoglContext *ctx = tex->context; if (min_filter == tex_3d->gl_legacy_texobj_min_filter && mag_filter == tex_3d->gl_legacy_texobj_mag_filter) return; /* Store new values */ tex_3d->gl_legacy_texobj_min_filter = min_filter; tex_3d->gl_legacy_texobj_mag_filter = mag_filter; /* Apply new filters to the texture */ _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, tex_3d->gl_texture, FALSE); GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, mag_filter) ); GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, min_filter) ); } static void _cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex); CoglContext *ctx = tex->context; /* Only update if the mipmaps are dirty */ if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) && tex_3d->auto_mipmap && tex_3d->mipmaps_dirty) { /* glGenerateMipmap is defined in the FBO extension. If it's not available we'll fallback to temporarily enabling GL_GENERATE_MIPMAP and reuploading the first pixel */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) _cogl_texture_gl_generate_mipmaps (tex); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) else if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED)) { _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, tex_3d->gl_texture, FALSE); GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE) ); GE( ctx, glTexSubImage3D (GL_TEXTURE_3D, 0, /* level */ 0, /* xoffset */ 0, /* yoffset */ 0, /* zoffset */ 1, /* width */ 1, /* height */ 1, /* depth */ tex_3d->first_pixel.gl_format, tex_3d->first_pixel.gl_type, tex_3d->first_pixel.data) ); GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_FALSE) ); } #endif tex_3d->mipmaps_dirty = FALSE; } } static void _cogl_texture_3d_ensure_non_quad_rendering (CoglTexture *tex) { /* Nothing needs to be done */ } static CoglBool _cogl_texture_3d_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, int level, CoglBitmap *bmp, CoglError **error) { /* This function doesn't really make sense for 3D textures because it can't specify which image to upload to */ _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Setting a 2D region on a 3D texture isn't " "currently supported"); return FALSE; } static int _cogl_texture_3d_get_data (CoglTexture *tex, CoglPixelFormat format, int rowstride, uint8_t *data) { /* FIXME: we could probably implement this by assuming the data is big enough to hold all of the images and that there is no stride between the images. However it would be better to have an API that can provide an image stride and this function probably isn't particularly useful anyway so for now it just reports failure */ return 0; } static CoglPixelFormat _cogl_texture_3d_get_format (CoglTexture *tex) { return COGL_TEXTURE_3D (tex)->internal_format; } static GLenum _cogl_texture_3d_get_gl_format (CoglTexture *tex) { return COGL_TEXTURE_3D (tex)->gl_format; } static CoglTextureType _cogl_texture_3d_get_type (CoglTexture *tex) { return COGL_TEXTURE_TYPE_3D; } static const CoglTextureVtable cogl_texture_3d_vtable = { TRUE, /* primitive */ _cogl_texture_3d_allocate, _cogl_texture_3d_set_region, _cogl_texture_3d_get_data, NULL, /* foreach_sub_texture_in_region */ _cogl_texture_3d_get_max_waste, _cogl_texture_3d_is_sliced, _cogl_texture_3d_can_hardware_repeat, _cogl_texture_3d_transform_coords_to_gl, _cogl_texture_3d_transform_quad_coords_to_gl, _cogl_texture_3d_get_gl_texture, _cogl_texture_3d_gl_flush_legacy_texobj_filters, _cogl_texture_3d_pre_paint, _cogl_texture_3d_ensure_non_quad_rendering, _cogl_texture_3d_gl_flush_legacy_texobj_wrap_modes, _cogl_texture_3d_get_format, _cogl_texture_3d_get_gl_format, _cogl_texture_3d_get_type, NULL, /* is_foreign */ _cogl_texture_3d_set_auto_mipmap }; muffin-5.2.1/cogl/cogl/cogl-quaternion-private.h0000664000175000017500000000314414211404421021736 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifndef __COGL_QUATERNION_PRIVATE_H__ #define __COGL_QUATERNION_PRIVATE_H__ #include /* squared length */ #define _COGL_QUATERNION_NORM(Q) \ ((Q)->x*(Q)->x + (Q)->y*(Q)->y + (Q)->z*(Q)->z + (Q)->w*(Q)->w) #define _COGL_QUATERNION_DEGREES_TO_RADIANS (G_PI / 180.0f) #define _COGL_QUATERNION_RADIANS_TO_DEGREES (180.0f / G_PI) #endif /* __COGL_QUATERNION_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-pipeline-layer-state.c0000664000175000017500000017667314211404421022153 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-pipeline-private.h" #include "cogl-blend-string.h" #include "cogl-util.h" #include "cogl-matrix.h" #include "cogl-snippet-private.h" #include "cogl-texture-private.h" #include "cogl-pipeline-layer-state-private.h" #include "cogl-error-private.h" #include "string.h" #if 0 #include "cogl-context-private.h" #include "cogl-color-private.h" #endif /* * XXX: consider special casing layer->unit_index so it's not a sparse * property so instead we can assume it's valid for all layer * instances. * - We would need to initialize ->unit_index in * _cogl_pipeline_layer_copy (). * * XXX: If you use this API you should consider that the given layer * might not be writeable and so a new derived layer will be allocated * and modified instead. The layer modified will be returned so you * can identify when this happens. */ CoglPipelineLayer * _cogl_pipeline_set_layer_unit (CoglPipeline *required_owner, CoglPipelineLayer *layer, int unit_index) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT; CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, change); CoglPipelineLayer *new; if (authority->unit_index == unit_index) return layer; new = _cogl_pipeline_layer_pre_change_notify (required_owner, layer, change); if (new != layer) layer = new; else { /* If the layer we found is currently the authority on the state * we are changing see if we can revert to one of our ancestors * being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, change); if (old_authority->unit_index == unit_index) { layer->differences &= ~change; return layer; } } } layer->unit_index = unit_index; /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= change; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } return layer; } CoglTexture * _cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer) { CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA); return authority->texture; } CoglTexture * cogl_pipeline_get_layer_texture (CoglPipeline *pipeline, int layer_index) { CoglPipelineLayer *layer = _cogl_pipeline_get_layer (pipeline, layer_index); return _cogl_pipeline_layer_get_texture (layer); } CoglTextureType _cogl_pipeline_layer_get_texture_type (CoglPipelineLayer *layer) { CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE); return authority->texture_type; } static void _cogl_pipeline_set_layer_texture_type (CoglPipeline *pipeline, int layer_index, CoglTextureType texture_type) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglPipelineLayer *new; /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); if (texture_type == authority->texture_type) return; new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change); if (new != layer) layer = new; else { /* If the original layer we found is currently the authority on * the state we are changing see if we can revert to one of our * ancestors being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, change); if (old_authority->texture_type == texture_type) { layer->differences &= ~change; g_assert (layer->owner == pipeline); if (layer->differences == 0) _cogl_pipeline_prune_empty_layer_difference (pipeline, layer); goto changed; } } } layer->texture_type = texture_type; /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= change; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } changed: pipeline->dirty_real_blend_enable = TRUE; } static void _cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline, int layer_index, CoglTexture *texture) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglPipelineLayer *new; /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); if (authority->texture == texture) return; new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change); if (new != layer) layer = new; else { /* If the original layer we found is currently the authority on * the state we are changing see if we can revert to one of our * ancestors being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, change); if (old_authority->texture == texture) { layer->differences &= ~change; if (layer->texture != NULL) cogl_object_unref (layer->texture); g_assert (layer->owner == pipeline); if (layer->differences == 0) _cogl_pipeline_prune_empty_layer_difference (pipeline, layer); goto changed; } } } if (texture != NULL) cogl_object_ref (texture); if (layer == authority && layer->texture != NULL) cogl_object_unref (layer->texture); layer->texture = texture; /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= change; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } changed: pipeline->dirty_real_blend_enable = TRUE; } void cogl_pipeline_set_layer_texture (CoglPipeline *pipeline, int layer_index, CoglTexture *texture) { /* For the convenience of fragend code we separate texture state * into the "type" and the "data", and setting a layer texture * updates both of these properties. * * One example for why this is helpful is that the fragends may * cache programs they generate and want to re-use those programs * with all pipelines having equivalent fragment processing state. * For the sake of determining if pipelines have equivalent fragment * processing state we don't need to compare that the same * underlying texture objects are referenced by the pipelines but we * do need to see if they use the same texture types. Making this * distinction is much simpler if they are in different state * groups. * * Note: if a NULL texture is set then we leave the type unchanged * so we can avoid needlessly invalidating any associated fragment * program. */ if (texture) { CoglTextureType texture_type = _cogl_texture_get_type (texture); _cogl_pipeline_set_layer_texture_type (pipeline, layer_index, texture_type); } _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture); } void cogl_pipeline_set_layer_null_texture (CoglPipeline *pipeline, int layer_index, CoglTextureType texture_type) { CoglContext *ctx = _cogl_context_get_default (); /* Disallow setting texture types that aren't supported */ switch (texture_type) { case COGL_TEXTURE_TYPE_2D: break; case COGL_TEXTURE_TYPE_3D: if (ctx->default_gl_texture_3d_tex == NULL) { g_warning ("The default 3D texture was set on a pipeline but " "3D textures are not supported"); texture_type = COGL_TEXTURE_TYPE_2D; return; } break; case COGL_TEXTURE_TYPE_RECTANGLE: if (ctx->default_gl_texture_rect_tex == NULL) { g_warning ("The default rectangle texture was set on a pipeline but " "rectangle textures are not supported"); texture_type = COGL_TEXTURE_TYPE_2D; } break; } _cogl_pipeline_set_layer_texture_type (pipeline, layer_index, texture_type); _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, NULL); } static void _cogl_pipeline_set_layer_sampler_state (CoglPipeline *pipeline, CoglPipelineLayer *layer, CoglPipelineLayer *authority, const CoglSamplerCacheEntry *state) { CoglPipelineLayer *new; CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; if (authority->sampler_cache_entry == state) return; new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change); if (new != layer) layer = new; else { /* If the original layer we found is currently the authority on * the state we are changing see if we can revert to one of our * ancestors being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, change); if (old_authority->sampler_cache_entry == state) { layer->differences &= ~change; g_assert (layer->owner == pipeline); if (layer->differences == 0) _cogl_pipeline_prune_empty_layer_difference (pipeline, layer); return; } } } layer->sampler_cache_entry = state; /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= change; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } } static CoglSamplerCacheWrapMode public_to_internal_wrap_mode (CoglPipelineWrapMode mode) { return (CoglSamplerCacheWrapMode)mode; } static CoglPipelineWrapMode internal_to_public_wrap_mode (CoglSamplerCacheWrapMode internal_mode) { _COGL_RETURN_VAL_IF_FAIL (internal_mode != COGL_SAMPLER_CACHE_WRAP_MODE_CLAMP_TO_BORDER, COGL_PIPELINE_WRAP_MODE_AUTOMATIC); return (CoglPipelineWrapMode)internal_mode; } void cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglSamplerCacheWrapMode internal_mode = public_to_internal_wrap_mode (mode); const CoglSamplerCacheEntry *sampler_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); sampler_state = _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache, authority->sampler_cache_entry, internal_mode, authority->sampler_cache_entry-> wrap_mode_t, authority->sampler_cache_entry-> wrap_mode_p); _cogl_pipeline_set_layer_sampler_state (pipeline, layer, authority, sampler_state); } void cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglSamplerCacheWrapMode internal_mode = public_to_internal_wrap_mode (mode); const CoglSamplerCacheEntry *sampler_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); sampler_state = _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache, authority->sampler_cache_entry, authority->sampler_cache_entry-> wrap_mode_s, internal_mode, authority->sampler_cache_entry-> wrap_mode_p); _cogl_pipeline_set_layer_sampler_state (pipeline, layer, authority, sampler_state); } /* The rationale for naming the third texture coordinate 'p' instead of OpenGL's usual 'r' is that 'r' conflicts with the usual naming of the 'red' component when treating a vector as a color. Under GLSL this is awkward because the texture swizzling for a vector uses a single letter for each component and the names for colors, textures and positions are synonymous. GLSL works around this by naming the components of the texture s, t, p and q. Cogl already effectively already exposes this naming because it exposes GLSL so it makes sense to use that naming consistently. Another alternative could be u, v and w. This is what Blender and Direct3D use. However the w component conflicts with the w component of a position vertex. */ void cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglSamplerCacheWrapMode internal_mode = public_to_internal_wrap_mode (mode); const CoglSamplerCacheEntry *sampler_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); sampler_state = _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache, authority->sampler_cache_entry, authority->sampler_cache_entry-> wrap_mode_s, authority->sampler_cache_entry-> wrap_mode_t, internal_mode); _cogl_pipeline_set_layer_sampler_state (pipeline, layer, authority, sampler_state); } void cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglSamplerCacheWrapMode internal_mode = public_to_internal_wrap_mode (mode); const CoglSamplerCacheEntry *sampler_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); sampler_state = _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache, authority->sampler_cache_entry, internal_mode, internal_mode, internal_mode); _cogl_pipeline_set_layer_sampler_state (pipeline, layer, authority, sampler_state); /* XXX: I wonder if we should really be duplicating the mode into * the 'p' wrap mode too? */ } /* FIXME: deprecate this API */ CoglPipelineWrapMode _cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *authority; const CoglSamplerCacheEntry *sampler_state; _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), FALSE); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); sampler_state = authority->sampler_cache_entry; return internal_to_public_wrap_mode (sampler_state->wrap_mode_s); } CoglPipelineWrapMode cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index) { CoglPipelineLayer *layer; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* FIXME: we shouldn't ever construct a layer in a getter function */ return _cogl_pipeline_layer_get_wrap_mode_s (layer); } /* FIXME: deprecate this API */ CoglPipelineWrapMode _cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *authority; const CoglSamplerCacheEntry *sampler_state; _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), FALSE); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); sampler_state = authority->sampler_cache_entry; return internal_to_public_wrap_mode (sampler_state->wrap_mode_t); } CoglPipelineWrapMode cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index) { CoglPipelineLayer *layer; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* FIXME: we shouldn't ever construct a layer in a getter function */ return _cogl_pipeline_layer_get_wrap_mode_t (layer); } CoglPipelineWrapMode _cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, change); const CoglSamplerCacheEntry *sampler_state; sampler_state = authority->sampler_cache_entry; return internal_to_public_wrap_mode (sampler_state->wrap_mode_p); } CoglPipelineWrapMode cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index) { CoglPipelineLayer *layer; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); return _cogl_pipeline_layer_get_wrap_mode_p (layer); } void _cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer, CoglSamplerCacheWrapMode *wrap_mode_s, CoglSamplerCacheWrapMode *wrap_mode_t, CoglSamplerCacheWrapMode *wrap_mode_p) { CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_SAMPLER); *wrap_mode_s = authority->sampler_cache_entry->wrap_mode_s; *wrap_mode_t = authority->sampler_cache_entry->wrap_mode_t; *wrap_mode_p = authority->sampler_cache_entry->wrap_mode_p; } CoglBool cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, int layer_index, CoglBool enable, CoglError **error) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; CoglPipelineLayer *layer; CoglPipelineLayer *new; CoglPipelineLayer *authority; _COGL_GET_CONTEXT (ctx, FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); /* Don't allow point sprite coordinates to be enabled if the driver doesn't support it */ if (enable && !cogl_has_feature (ctx, COGL_FEATURE_ID_POINT_SPRITE)) { if (error) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Point sprite texture coordinates are enabled for " "a layer but the GL driver does not support it."); } else { static CoglBool warning_seen = FALSE; if (!warning_seen) g_warning ("Point sprite texture coordinates are enabled " "for a layer but the GL driver does not support it."); warning_seen = TRUE; } return FALSE; } /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); if (authority->big_state->point_sprite_coords == enable) return TRUE; new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change); if (new != layer) layer = new; else { /* If the original layer we found is currently the authority on * the state we are changing see if we can revert to one of our * ancestors being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, change); if (old_authority->big_state->point_sprite_coords == enable) { layer->differences &= ~change; g_assert (layer->owner == pipeline); if (layer->differences == 0) _cogl_pipeline_prune_empty_layer_difference (pipeline, layer); return TRUE; } } } layer->big_state->point_sprite_coords = enable; /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= change; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } return TRUE; } CoglBool cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, int layer_index) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; CoglPipelineLayer *layer; CoglPipelineLayer *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* FIXME: we shouldn't ever construct a layer in a getter function */ authority = _cogl_pipeline_layer_get_authority (layer, change); return authority->big_state->point_sprite_coords; } static void _cogl_pipeline_layer_add_vertex_snippet (CoglPipeline *pipeline, int layer_index, CoglSnippet *snippet) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS; CoglPipelineLayer *layer, *authority; /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change); _cogl_pipeline_snippet_list_add (&layer->big_state->vertex_snippets, snippet); /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= change; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } } static void _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline, int layer_index, CoglSnippet *snippet) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; CoglPipelineLayer *layer, *authority; /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, change); layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change); _cogl_pipeline_snippet_list_add (&layer->big_state->fragment_snippets, snippet); /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= change; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } } void cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline, int layer_index, CoglSnippet *snippet) { _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet)); _COGL_RETURN_IF_FAIL (snippet->hook >= COGL_SNIPPET_FIRST_LAYER_HOOK); if (snippet->hook < COGL_SNIPPET_FIRST_LAYER_FRAGMENT_HOOK) _cogl_pipeline_layer_add_vertex_snippet (pipeline, layer_index, snippet); else _cogl_pipeline_layer_add_fragment_snippet (pipeline, layer_index, snippet); } CoglBool _cogl_pipeline_layer_texture_type_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1, CoglPipelineEvalFlags flags) { return authority0->texture_type == authority1->texture_type; } CoglBool _cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1, CoglPipelineEvalFlags flags) { if (authority0->texture == NULL) { if (authority1->texture == NULL) return (_cogl_pipeline_layer_get_texture_type (authority0) == _cogl_pipeline_layer_get_texture_type (authority1)); else return FALSE; } else if (authority1->texture == NULL) return FALSE; else { GLuint gl_handle0, gl_handle1; cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL); cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL); return gl_handle0 == gl_handle1; } } CoglBool _cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1) { CoglPipelineLayerBigState *big_state0 = authority0->big_state; CoglPipelineLayerBigState *big_state1 = authority1->big_state; int n_args; int i; if (big_state0->texture_combine_rgb_func != big_state1->texture_combine_rgb_func) return FALSE; if (big_state0->texture_combine_alpha_func != big_state1->texture_combine_alpha_func) return FALSE; n_args = _cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func); for (i = 0; i < n_args; i++) { if ((big_state0->texture_combine_rgb_src[i] != big_state1->texture_combine_rgb_src[i]) || (big_state0->texture_combine_rgb_op[i] != big_state1->texture_combine_rgb_op[i])) return FALSE; } n_args = _cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func); for (i = 0; i < n_args; i++) { if ((big_state0->texture_combine_alpha_src[i] != big_state1->texture_combine_alpha_src[i]) || (big_state0->texture_combine_alpha_op[i] != big_state1->texture_combine_alpha_op[i])) return FALSE; } return TRUE; } CoglBool _cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1) { return memcmp (authority0->big_state->texture_combine_constant, authority1->big_state->texture_combine_constant, sizeof (float) * 4) == 0 ? TRUE : FALSE; } CoglBool _cogl_pipeline_layer_sampler_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1) { /* We compare the actual sampler objects rather than just the entry pointers because two states with different values can lead to the same state in GL terms when AUTOMATIC is used as a wrap mode */ return (authority0->sampler_cache_entry->sampler_object == authority1->sampler_cache_entry->sampler_object); } CoglBool _cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1) { CoglPipelineLayerBigState *big_state0 = authority0->big_state; CoglPipelineLayerBigState *big_state1 = authority1->big_state; if (!cogl_matrix_equal (&big_state0->matrix, &big_state1->matrix)) return FALSE; return TRUE; } CoglBool _cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1) { CoglPipelineLayerBigState *big_state0 = authority0->big_state; CoglPipelineLayerBigState *big_state1 = authority1->big_state; return big_state0->point_sprite_coords == big_state1->point_sprite_coords; } CoglBool _cogl_pipeline_layer_vertex_snippets_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1) { return _cogl_pipeline_snippet_list_equal (&authority0->big_state-> vertex_snippets, &authority1->big_state-> vertex_snippets); } CoglBool _cogl_pipeline_layer_fragment_snippets_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1) { return _cogl_pipeline_snippet_list_equal (&authority0->big_state-> fragment_snippets, &authority1->big_state-> fragment_snippets); } static void setup_texture_combine_state (CoglBlendStringStatement *statement, CoglPipelineCombineFunc *texture_combine_func, CoglPipelineCombineSource *texture_combine_src, CoglPipelineCombineOp *texture_combine_op) { int i; switch (statement->function->type) { case COGL_BLEND_STRING_FUNCTION_REPLACE: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE; break; case COGL_BLEND_STRING_FUNCTION_MODULATE: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE; break; case COGL_BLEND_STRING_FUNCTION_ADD: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD; break; case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED; break; case COGL_BLEND_STRING_FUNCTION_INTERPOLATE: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE; break; case COGL_BLEND_STRING_FUNCTION_SUBTRACT: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT; break; case COGL_BLEND_STRING_FUNCTION_DOT3_RGB: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB; break; case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA: *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA; break; } for (i = 0; i < statement->function->argc; i++) { CoglBlendStringArgument *arg = &statement->args[i]; switch (arg->source.info->type) { case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT: texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT; break; case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE: texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; break; case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N: texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture; break; case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY: texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR; break; case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS: texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS; break; default: g_warning ("Unexpected texture combine source"); texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; } if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) { if (statement->args[i].source.one_minus) texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR; else texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR; } else { if (statement->args[i].source.one_minus) texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA; else texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA; } } } CoglBool cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, int layer_index, const char *combine_description, CoglError **error) { CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE; CoglPipelineLayer *authority; CoglPipelineLayer *layer; CoglBlendStringStatement statements[2]; CoglBlendStringStatement split[2]; CoglBlendStringStatement *rgb; CoglBlendStringStatement *a; int count; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, state); count = _cogl_blend_string_compile (combine_description, COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE, statements, error); if (!count) return FALSE; if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) { _cogl_blend_string_split_rgba_statement (statements, &split[0], &split[1]); rgb = &split[0]; a = &split[1]; } else { rgb = &statements[0]; a = &statements[1]; } /* FIXME: compare the new state with the current state! */ /* possibly flush primitives referencing the current state... */ layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); setup_texture_combine_state (rgb, &layer->big_state->texture_combine_rgb_func, layer->big_state->texture_combine_rgb_src, layer->big_state->texture_combine_rgb_op); setup_texture_combine_state (a, &layer->big_state->texture_combine_alpha_func, layer->big_state->texture_combine_alpha_src, layer->big_state->texture_combine_alpha_op); /* If the original layer we found is currently the authority on * the state we are changing see if we can revert to one of our * ancestors being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, state); if (_cogl_pipeline_layer_combine_state_equal (authority, old_authority)) { layer->differences &= ~state; g_assert (layer->owner == pipeline); if (layer->differences == 0) _cogl_pipeline_prune_empty_layer_difference (pipeline, layer); goto changed; } } /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= state; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } changed: pipeline->dirty_real_blend_enable = TRUE; return TRUE; } void cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, int layer_index, const CoglColor *constant_color) { CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglPipelineLayer *new; float color_as_floats[4]; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, state); color_as_floats[0] = cogl_color_get_red_float (constant_color); color_as_floats[1] = cogl_color_get_green_float (constant_color); color_as_floats[2] = cogl_color_get_blue_float (constant_color); color_as_floats[3] = cogl_color_get_alpha_float (constant_color); if (memcmp (authority->big_state->texture_combine_constant, color_as_floats, sizeof (float) * 4) == 0) return; new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); if (new != layer) layer = new; else { /* If the original layer we found is currently the authority on * the state we are changing see if we can revert to one of our * ancestors being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, state); CoglPipelineLayerBigState *old_big_state = old_authority->big_state; if (memcmp (old_big_state->texture_combine_constant, color_as_floats, sizeof (float) * 4) == 0) { layer->differences &= ~state; g_assert (layer->owner == pipeline); if (layer->differences == 0) _cogl_pipeline_prune_empty_layer_difference (pipeline, layer); goto changed; } } } memcpy (layer->big_state->texture_combine_constant, color_as_floats, sizeof (color_as_floats)); /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= state; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } changed: pipeline->dirty_real_blend_enable = TRUE; } void _cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline, int layer_index, float *constant) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT; CoglPipelineLayer *layer; CoglPipelineLayer *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* FIXME: we shouldn't ever construct a layer in a getter function */ authority = _cogl_pipeline_layer_get_authority (layer, change); memcpy (constant, authority->big_state->texture_combine_constant, sizeof (float) * 4); } /* We should probably make a public API version of this that has a matrix out-param. For an internal API it's good to be able to avoid copying the matrix */ const CoglMatrix * _cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_USER_MATRIX; CoglPipelineLayer *layer; CoglPipelineLayer *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), NULL); layer = _cogl_pipeline_get_layer (pipeline, layer_index); authority = _cogl_pipeline_layer_get_authority (layer, change); return &authority->big_state->matrix; } void cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline, int layer_index, const CoglMatrix *matrix) { CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX; CoglPipelineLayer *layer; CoglPipelineLayer *authority; CoglPipelineLayer *new; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, state); if (cogl_matrix_equal (matrix, &authority->big_state->matrix)) return; new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); if (new != layer) layer = new; else { /* If the original layer we found is currently the authority on * the state we are changing see if we can revert to one of our * ancestors being the authority. */ if (layer == authority && _cogl_pipeline_layer_get_parent (authority) != NULL) { CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); CoglPipelineLayer *old_authority = _cogl_pipeline_layer_get_authority (parent, state); if (cogl_matrix_equal (matrix, &old_authority->big_state->matrix)) { layer->differences &= ~state; g_assert (layer->owner == pipeline); if (layer->differences == 0) _cogl_pipeline_prune_empty_layer_difference (pipeline, layer); return; } } } layer->big_state->matrix = *matrix; /* If we weren't previously the authority on this state then we need * to extended our differences mask and so it's possible that some * of our ancestry will now become redundant, so we aim to reparent * ourselves if that's true... */ if (layer != authority) { layer->differences |= state; _cogl_pipeline_layer_prune_redundant_ancestry (layer); } } CoglTexture * _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer) { _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), NULL); return _cogl_pipeline_layer_get_texture_real (layer); } CoglBool _cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline, int layer_index) { CoglPipelineLayer *layer; CoglPipelineLayer *authority; layer = _cogl_pipeline_get_layer (pipeline, layer_index); authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_USER_MATRIX); /* If the authority is the default pipeline then no, otherwise yes */ return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE; } void _cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer, CoglPipelineFilter *min_filter, CoglPipelineFilter *mag_filter) { CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_SAMPLER); *min_filter = authority->sampler_cache_entry->min_filter; *mag_filter = authority->sampler_cache_entry->mag_filter; } void _cogl_pipeline_get_layer_filters (CoglPipeline *pipeline, int layer_index, CoglPipelineFilter *min_filter, CoglPipelineFilter *mag_filter) { CoglPipelineLayer *layer; CoglPipelineLayer *authority; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); layer = _cogl_pipeline_get_layer (pipeline, layer_index); authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_SAMPLER); *min_filter = authority->sampler_cache_entry->min_filter; *mag_filter = authority->sampler_cache_entry->mag_filter; } CoglPipelineFilter cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline, int layer_index) { CoglPipelineFilter min_filter; CoglPipelineFilter mag_filter; _cogl_pipeline_get_layer_filters (pipeline, layer_index, &min_filter, &mag_filter); return min_filter; } CoglPipelineFilter cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline, int layer_index) { CoglPipelineFilter min_filter; CoglPipelineFilter mag_filter; _cogl_pipeline_get_layer_filters (pipeline, layer_index, &min_filter, &mag_filter); return mag_filter; } CoglPipelineFilter _cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer) { CoglPipelineLayer *authority; _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), 0); authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_SAMPLER); return authority->sampler_cache_entry->min_filter; } CoglPipelineFilter _cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer) { CoglPipelineLayer *authority; _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), 0); authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_SAMPLER); return authority->sampler_cache_entry->mag_filter; } void cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, int layer_index, CoglPipelineFilter min_filter, CoglPipelineFilter mag_filter) { CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_SAMPLER; CoglPipelineLayer *layer; CoglPipelineLayer *authority; const CoglSamplerCacheEntry *sampler_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); _COGL_RETURN_IF_FAIL (mag_filter == COGL_PIPELINE_FILTER_NEAREST || mag_filter == COGL_PIPELINE_FILTER_LINEAR); /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * * Note: If the layer already existed it's possibly owned by another * pipeline. If the layer is created then it will be owned by * pipeline. */ layer = _cogl_pipeline_get_layer (pipeline, layer_index); /* Now find the ancestor of the layer that is the authority for the * state we want to change */ authority = _cogl_pipeline_layer_get_authority (layer, state); sampler_state = _cogl_sampler_cache_update_filters (ctx->sampler_cache, authority->sampler_cache_entry, min_filter, mag_filter); _cogl_pipeline_set_layer_sampler_state (pipeline, layer, authority, sampler_state); } const CoglSamplerCacheEntry * _cogl_pipeline_layer_get_sampler_state (CoglPipelineLayer *layer) { CoglPipelineLayer *authority; authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_SAMPLER); return authority->sampler_cache_entry; } void _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { int unit = authority->unit_index; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit)); } void _cogl_pipeline_layer_hash_texture_type_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { CoglTextureType texture_type = authority->texture_type; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &texture_type, sizeof (texture_type)); } void _cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { GLuint gl_handle; cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL); state->hash = _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle)); } void _cogl_pipeline_layer_hash_sampler_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->sampler_cache_entry, sizeof (authority->sampler_cache_entry)); } void _cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { unsigned int hash = state->hash; CoglPipelineLayerBigState *b = authority->big_state; int n_args; int i; hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_func, sizeof (b->texture_combine_rgb_func)); n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func); for (i = 0; i < n_args; i++) { hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_src[i], sizeof (b->texture_combine_rgb_src[i])); hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_op[i], sizeof (b->texture_combine_rgb_op[i])); } hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_func, sizeof (b->texture_combine_alpha_func)); n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func); for (i = 0; i < n_args; i++) { hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_src[i], sizeof (b->texture_combine_alpha_src[i])); hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_op[i], sizeof (b->texture_combine_alpha_op[i])); } state->hash = hash; } void _cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { CoglPipelineLayerBigState *b = authority->big_state; CoglBool need_hash = FALSE; int n_args; int i; /* XXX: If the user also asked to hash the ALPHA_FUNC_STATE then it * would be nice if we could combine the n_args loops in this * function and _cogl_pipeline_layer_hash_combine_state. */ n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func); for (i = 0; i < n_args; i++) { if (b->texture_combine_rgb_src[i] == COGL_PIPELINE_COMBINE_SOURCE_CONSTANT) { /* XXX: should we be careful to only hash the alpha * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */ need_hash = TRUE; goto done; } } n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func); for (i = 0; i < n_args; i++) { if (b->texture_combine_alpha_src[i] == COGL_PIPELINE_COMBINE_SOURCE_CONSTANT) { /* XXX: should we be careful to only hash the alpha * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */ need_hash = TRUE; goto done; } } done: if (need_hash) { float *constant = b->texture_combine_constant; state->hash = _cogl_util_one_at_a_time_hash (state->hash, constant, sizeof (float) * 4); } } void _cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { CoglPipelineLayerBigState *big_state = authority->big_state; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix, sizeof (float) * 16); } void _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { CoglPipelineLayerBigState *big_state = authority->big_state; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->point_sprite_coords, sizeof (big_state->point_sprite_coords)); } void _cogl_pipeline_layer_hash_vertex_snippets_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { _cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets, &state->hash); } void _cogl_pipeline_layer_hash_fragment_snippets_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state) { _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets, &state->hash); } muffin-5.2.1/cogl/cogl/cogl-pipeline-layer.c0000664000175000017500000010004714211404421021013 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-texture-private.h" #include "cogl-pipeline.h" #include "cogl-pipeline-layer-private.h" #include "cogl-pipeline-layer-state-private.h" #include "cogl-pipeline-layer-state.h" #include "cogl-node-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-context-private.h" #include "cogl-texture-private.h" #include static void _cogl_pipeline_layer_free (CoglPipelineLayer *layer); /* This type was made deprecated before the cogl_is_pipeline_layer function was ever exposed in the public headers so there's no need to make the cogl_is_pipeline_layer function public. We use INTERNAL so that the cogl_is_* function won't get defined */ COGL_OBJECT_INTERNAL_DEFINE (PipelineLayer, pipeline_layer); CoglPipelineLayer * _cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer, unsigned long difference) { CoglPipelineLayer *authority = layer; while (!(authority->differences & difference)) authority = _cogl_pipeline_layer_get_parent (authority); return authority; } int _cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer) { CoglPipelineLayer *authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_UNIT); return authority->unit_index; } CoglBool _cogl_pipeline_layer_has_alpha (CoglPipelineLayer *layer) { CoglPipelineLayer *combine_authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_COMBINE); CoglPipelineLayerBigState *big_state = combine_authority->big_state; CoglPipelineLayer *tex_authority; CoglPipelineLayer *snippets_authority; /* has_alpha maintains the alpha status for the GL_PREVIOUS layer */ /* For anything but the default texture combine we currently just * assume it may result in an alpha value < 1 * * FIXME: we could do better than this. */ if (big_state->texture_combine_alpha_func != COGL_PIPELINE_COMBINE_FUNC_MODULATE || big_state->texture_combine_alpha_src[0] != COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS || big_state->texture_combine_alpha_op[0] != COGL_PIPELINE_COMBINE_OP_SRC_ALPHA || big_state->texture_combine_alpha_src[1] != COGL_PIPELINE_COMBINE_SOURCE_TEXTURE || big_state->texture_combine_alpha_op[1] != COGL_PIPELINE_COMBINE_OP_SRC_ALPHA) { return TRUE; } /* NB: A layer may have a combine mode set on it but not yet * have an associated texture which would mean we'd fallback * to the default texture which doesn't have an alpha component */ tex_authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA); if (tex_authority->texture && _cogl_texture_get_format (tex_authority->texture) & COGL_A_BIT) { return TRUE; } /* All bets are off if the layer contains any snippets */ snippets_authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS); if (snippets_authority->big_state->vertex_snippets.entries != NULL) return TRUE; snippets_authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS); if (snippets_authority->big_state->fragment_snippets.entries != NULL) return TRUE; return FALSE; } unsigned int _cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func) { switch (func) { case COGL_PIPELINE_COMBINE_FUNC_REPLACE: return 1; case COGL_PIPELINE_COMBINE_FUNC_MODULATE: case COGL_PIPELINE_COMBINE_FUNC_ADD: case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED: case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT: case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB: case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA: return 2; case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE: return 3; } return 0; } void _cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest, CoglPipelineLayer *src, unsigned long differences) { CoglPipelineLayerBigState *big_dest, *big_src; if ((differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE) && !dest->has_big_state) { dest->big_state = g_slice_new (CoglPipelineLayerBigState); dest->has_big_state = TRUE; } big_dest = dest->big_state; big_src = src->big_state; dest->differences |= differences; while (differences) { int index = _cogl_util_ffs (differences) - 1; differences &= ~(1 << index); /* This convoluted switch statement is just here so that we'll * get a warning if a new state is added without handling it * here */ switch (index) { case COGL_PIPELINE_LAYER_STATE_COUNT: case COGL_PIPELINE_LAYER_STATE_UNIT_INDEX: g_warn_if_reached (); break; case COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE_INDEX: dest->texture_type = src->texture_type; break; case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX: dest->texture = src->texture; if (dest->texture) cogl_object_ref (dest->texture); break; case COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX: dest->sampler_cache_entry = src->sampler_cache_entry; break; case COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX: { CoglPipelineCombineFunc func; int n_args, i; func = big_src->texture_combine_rgb_func; big_dest->texture_combine_rgb_func = func; n_args = _cogl_get_n_args_for_combine_func (func); for (i = 0; i < n_args; i++) { big_dest->texture_combine_rgb_src[i] = big_src->texture_combine_rgb_src[i]; big_dest->texture_combine_rgb_op[i] = big_src->texture_combine_rgb_op[i]; } func = big_src->texture_combine_alpha_func; big_dest->texture_combine_alpha_func = func; n_args = _cogl_get_n_args_for_combine_func (func); for (i = 0; i < n_args; i++) { big_dest->texture_combine_alpha_src[i] = big_src->texture_combine_alpha_src[i]; big_dest->texture_combine_alpha_op[i] = big_src->texture_combine_alpha_op[i]; } } break; case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX: memcpy (big_dest->texture_combine_constant, big_src->texture_combine_constant, sizeof (big_dest->texture_combine_constant)); break; case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX: big_dest->point_sprite_coords = big_src->point_sprite_coords; break; case COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX: _cogl_pipeline_snippet_list_copy (&big_dest->vertex_snippets, &big_src->vertex_snippets); break; case COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX: _cogl_pipeline_snippet_list_copy (&big_dest->fragment_snippets, &big_src->fragment_snippets); break; } } } static void _cogl_pipeline_layer_init_multi_property_sparse_state ( CoglPipelineLayer *layer, CoglPipelineLayerState change) { CoglPipelineLayer *authority; /* Nothing to initialize in these cases since they are all comprised * of one member which we expect to immediately be overwritten. */ if (!(change & COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY)) return; authority = _cogl_pipeline_layer_get_authority (layer, change); switch (change) { /* XXX: avoid using a default: label so we get a warning if we * don't explicitly handle a newly defined state-group here. */ case COGL_PIPELINE_LAYER_STATE_UNIT: case COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE: case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA: case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS: case COGL_PIPELINE_LAYER_STATE_USER_MATRIX: case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT: case COGL_PIPELINE_LAYER_STATE_SAMPLER: g_return_if_reached (); /* XXX: technically we could probably even consider these as * single property state-groups from the pov that currently the * corresponding property setters always update all of the values * at the same time. */ case COGL_PIPELINE_LAYER_STATE_COMBINE: { int n_args; int i; CoglPipelineLayerBigState *src_big_state = authority->big_state; CoglPipelineLayerBigState *dest_big_state = layer->big_state; GLint func = src_big_state->texture_combine_rgb_func; dest_big_state->texture_combine_rgb_func = func; n_args = _cogl_get_n_args_for_combine_func (func); for (i = 0; i < n_args; i++) { dest_big_state->texture_combine_rgb_src[i] = src_big_state->texture_combine_rgb_src[i]; dest_big_state->texture_combine_rgb_op[i] = src_big_state->texture_combine_rgb_op[i]; } func = src_big_state->texture_combine_alpha_func; dest_big_state->texture_combine_alpha_func = func; n_args = _cogl_get_n_args_for_combine_func (func); for (i = 0; i < n_args; i++) { dest_big_state->texture_combine_alpha_src[i] = src_big_state->texture_combine_alpha_src[i]; dest_big_state->texture_combine_alpha_op[i] = src_big_state->texture_combine_alpha_op[i]; } break; } case COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS: _cogl_pipeline_snippet_list_copy (&layer->big_state->vertex_snippets, &authority->big_state-> vertex_snippets); break; case COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS: _cogl_pipeline_snippet_list_copy (&layer->big_state->fragment_snippets, &authority->big_state-> fragment_snippets); break; } } /* NB: If a layer has descendants we can't modify the layer * NB: If the layer is owned and the owner has descendants we can't * modify the layer. * * This function will allocate a new derived layer if you are trying * to change the state of a layer with dependants (as described above) * so you must always check the return value. * * If a new layer is returned it will be owned by required_owner. * (NB: a layer is always modified with respect to a pipeline - the * "required_owner") * * required_owner can only by NULL for new, currently unowned layers * with no dependants. */ CoglPipelineLayer * _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner, CoglPipelineLayer *layer, CoglPipelineLayerState change) { CoglTextureUnit *unit; /* Identify the case where the layer is new with no owner or * dependants and so we don't need to do anything. */ if (_cogl_list_empty (&COGL_NODE (layer)->children) && layer->owner == NULL) goto init_layer_state; /* We only allow a NULL required_owner for new layers */ _COGL_RETURN_VAL_IF_FAIL (required_owner != NULL, layer); /* Chain up: * A modification of a layer is indirectly also a modification of * its owner so first make sure to flush the journal of any * references to the current owner state and if necessary perform * a copy-on-write for the required_owner if it has dependants. */ _cogl_pipeline_pre_change_notify (required_owner, COGL_PIPELINE_STATE_LAYERS, NULL, TRUE); /* Unlike pipelines; layers are simply considered immutable once * they have dependants - either direct children, or another * pipeline as an owner. */ if (!_cogl_list_empty (&COGL_NODE (layer)->children) || layer->owner != required_owner) { CoglPipelineLayer *new = _cogl_pipeline_layer_copy (layer); if (layer->owner == required_owner) _cogl_pipeline_remove_layer_difference (required_owner, layer, FALSE); _cogl_pipeline_add_layer_difference (required_owner, new, FALSE); cogl_object_unref (new); layer = new; goto init_layer_state; } /* Note: At this point we know there is only one pipeline dependant on * this layer (required_owner), and there are no other layers * dependant on this layer so it's ok to modify it. */ /* NB: Although layers can have private state associated with them * by multiple backends we know that a layer can't be *changed* if * it has multiple dependants so if we reach here we know we only * have a single owner and can only be associated with a single * backend that needs to be notified of the layer change... */ if (required_owner->progend != COGL_PIPELINE_PROGEND_UNDEFINED) { const CoglPipelineProgend *progend = _cogl_pipeline_progends[required_owner->progend]; const CoglPipelineFragend *fragend = _cogl_pipeline_fragends[progend->fragend]; const CoglPipelineVertend *vertend = _cogl_pipeline_vertends[progend->vertend]; if (fragend->layer_pre_change_notify) fragend->layer_pre_change_notify (required_owner, layer, change); if (vertend->layer_pre_change_notify) vertend->layer_pre_change_notify (required_owner, layer, change); if (progend->layer_pre_change_notify) progend->layer_pre_change_notify (required_owner, layer, change); } /* If the layer being changed is the same as the last layer we * flushed to the corresponding texture unit then we keep a track of * the changes so we can try to minimize redundant OpenGL calls if * the same layer is flushed again. */ unit = _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer)); if (unit->layer == layer) unit->layer_changes_since_flush |= change; init_layer_state: if (required_owner) required_owner->age++; if (change & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE && !layer->has_big_state) { layer->big_state = g_slice_new (CoglPipelineLayerBigState); layer->has_big_state = TRUE; } /* Note: conceptually we have just been notified that a single * property value is about to change, but since some state-groups * contain multiple properties and 'layer' is about to take over * being the authority for the property's corresponding state-group * we need to maintain the integrity of the other property values * too. * * To ensure this we handle multi-property state-groups by copying * all the values from the old-authority to the new... * * We don't have to worry about non-sparse property groups since * we never take over being an authority for such properties so * they automatically maintain integrity. */ if (change & COGL_PIPELINE_LAYER_STATE_ALL_SPARSE && !(layer->differences & change)) { _cogl_pipeline_layer_init_multi_property_sparse_state (layer, change); layer->differences |= change; } return layer; } static void _cogl_pipeline_layer_unparent (CoglNode *layer) { /* Chain up */ _cogl_pipeline_node_unparent_real (layer); } static void _cogl_pipeline_layer_set_parent (CoglPipelineLayer *layer, CoglPipelineLayer *parent) { /* Chain up */ _cogl_pipeline_node_set_parent_real (COGL_NODE (layer), COGL_NODE (parent), _cogl_pipeline_layer_unparent, TRUE); } CoglPipelineLayer * _cogl_pipeline_layer_copy (CoglPipelineLayer *src) { CoglPipelineLayer *layer = g_slice_new (CoglPipelineLayer); _cogl_pipeline_node_init (COGL_NODE (layer)); layer->owner = NULL; layer->index = src->index; layer->differences = 0; layer->has_big_state = FALSE; _cogl_pipeline_layer_set_parent (layer, src); return _cogl_pipeline_layer_object_new (layer); } /* XXX: This is duplicated logic; the same as for * _cogl_pipeline_prune_redundant_ancestry it would be nice to find a * way to consolidate these functions! */ void _cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer) { CoglPipelineLayer *new_parent = _cogl_pipeline_layer_get_parent (layer); /* walk up past ancestors that are now redundant and potentially * reparent the layer. */ while (_cogl_pipeline_layer_get_parent (new_parent) && (new_parent->differences | layer->differences) == layer->differences) new_parent = _cogl_pipeline_layer_get_parent (new_parent); _cogl_pipeline_layer_set_parent (layer, new_parent); } /* Determine the mask of differences between two layers. * * XXX: If layers and pipelines could both be cast to a common Tree * type of some kind then we could have a unified * compare_differences() function. */ unsigned long _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0, CoglPipelineLayer *layer1) { GSList *head0 = NULL; GSList *head1 = NULL; CoglPipelineLayer *node0; CoglPipelineLayer *node1; int len0 = 0; int len1 = 0; int count; GSList *common_ancestor0; GSList *common_ancestor1; unsigned long layers_difference = 0; /* Algorithm: * * 1) Walk the ancestors of each layer to the root node, adding a * pointer to each ancester node to two linked lists * * 2) Compare the lists to find the nodes where they start to * differ marking the common_ancestor node for each list. * * 3) For each list now iterate starting after the common_ancestor * nodes ORing each nodes ->difference mask into the final * differences mask. */ for (node0 = layer0; node0; node0 = _cogl_pipeline_layer_get_parent (node0)) { GSList *link = alloca (sizeof (GSList)); link->next = head0; link->data = node0; head0 = link; len0++; } for (node1 = layer1; node1; node1 = _cogl_pipeline_layer_get_parent (node1)) { GSList *link = alloca (sizeof (GSList)); link->next = head1; link->data = node1; head1 = link; len1++; } /* NB: There's no point looking at the head entries since we know both layers * must have the same default layer as their root node. */ common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; count = MIN (len0, len1) - 1; while (count--) { if (head0->data != head1->data) break; common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; } for (head0 = common_ancestor0->next; head0; head0 = head0->next) { node0 = head0->data; layers_difference |= node0->differences; } for (head1 = common_ancestor1->next; head1; head1 = head1->next) { node1 = head1->data; layers_difference |= node1->differences; } return layers_difference; } static CoglBool layer_state_equal (CoglPipelineLayerStateIndex state_index, CoglPipelineLayer **authorities0, CoglPipelineLayer **authorities1, CoglPipelineLayerStateComparitor comparitor) { return comparitor (authorities0[state_index], authorities1[state_index]); } void _cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer, unsigned long differences, CoglPipelineLayer **authorities) { unsigned long remaining = differences; CoglPipelineLayer *authority = layer; do { unsigned long found = authority->differences & remaining; int i; if (found == 0) continue; for (i = 0; TRUE; i++) { unsigned long state = (1L< found) break; } remaining &= ~found; if (remaining == 0) return; } while ((authority = _cogl_pipeline_layer_get_parent (authority))); g_assert (remaining == 0); } CoglBool _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0, CoglPipelineLayer *layer1, unsigned long differences_mask, CoglPipelineEvalFlags flags) { unsigned long layers_difference; CoglPipelineLayer *authorities0[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT]; CoglPipelineLayer *authorities1[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT]; if (layer0 == layer1) return TRUE; layers_difference = _cogl_pipeline_layer_compare_differences (layer0, layer1); /* Only compare the sparse state groups requested by the caller... */ layers_difference &= differences_mask; _cogl_pipeline_layer_resolve_authorities (layer0, layers_difference, authorities0); _cogl_pipeline_layer_resolve_authorities (layer1, layers_difference, authorities1); if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE) { CoglPipelineLayerStateIndex state_index = COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE_INDEX; if (!_cogl_pipeline_layer_texture_type_equal (authorities0[state_index], authorities1[state_index], flags)) return FALSE; } if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA) { CoglPipelineLayerStateIndex state_index = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX; if (!_cogl_pipeline_layer_texture_data_equal (authorities0[state_index], authorities1[state_index], flags)) return FALSE; } if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE && !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX, authorities0, authorities1, _cogl_pipeline_layer_combine_state_equal)) return FALSE; if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT && !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX, authorities0, authorities1, _cogl_pipeline_layer_combine_constant_equal)) return FALSE; if (layers_difference & COGL_PIPELINE_LAYER_STATE_SAMPLER && !layer_state_equal (COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX, authorities0, authorities1, _cogl_pipeline_layer_sampler_equal)) return FALSE; if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX && !layer_state_equal (COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX, authorities0, authorities1, _cogl_pipeline_layer_user_matrix_equal)) return FALSE; if (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS && !layer_state_equal (COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX, authorities0, authorities1, _cogl_pipeline_layer_point_sprite_coords_equal)) return FALSE; if (layers_difference & COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS && !layer_state_equal (COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX, authorities0, authorities1, _cogl_pipeline_layer_vertex_snippets_equal)) return FALSE; if (layers_difference & COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS && !layer_state_equal (COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX, authorities0, authorities1, _cogl_pipeline_layer_fragment_snippets_equal)) return FALSE; return TRUE; } static void _cogl_pipeline_layer_free (CoglPipelineLayer *layer) { _cogl_pipeline_layer_unparent (COGL_NODE (layer)); if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA && layer->texture != NULL) cogl_object_unref (layer->texture); if (layer->differences & COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS) _cogl_pipeline_snippet_list_free (&layer->big_state->vertex_snippets); if (layer->differences & COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS) _cogl_pipeline_snippet_list_free (&layer->big_state->fragment_snippets); if (layer->differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE) g_slice_free (CoglPipelineLayerBigState, layer->big_state); g_slice_free (CoglPipelineLayer, layer); } void _cogl_pipeline_init_default_layers (void) { CoglPipelineLayer *layer = g_slice_new0 (CoglPipelineLayer); CoglPipelineLayerBigState *big_state = g_slice_new0 (CoglPipelineLayerBigState); CoglPipelineLayer *new; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_pipeline_node_init (COGL_NODE (layer)); layer->index = 0; layer->differences = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE; layer->unit_index = 0; layer->texture = NULL; layer->texture_type = COGL_TEXTURE_TYPE_2D; layer->sampler_cache_entry = _cogl_sampler_cache_get_default_entry (ctx->sampler_cache); layer->big_state = big_state; layer->has_big_state = TRUE; /* Choose the same default combine mode as OpenGL: * RGBA = MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */ big_state->texture_combine_rgb_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE; big_state->texture_combine_rgb_src[0] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS; big_state->texture_combine_rgb_src[1] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; big_state->texture_combine_rgb_op[0] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR; big_state->texture_combine_rgb_op[1] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR; big_state->texture_combine_alpha_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE; big_state->texture_combine_alpha_src[0] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS; big_state->texture_combine_alpha_src[1] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; big_state->texture_combine_alpha_op[0] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA; big_state->texture_combine_alpha_op[1] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA; big_state->point_sprite_coords = FALSE; cogl_matrix_init_identity (&big_state->matrix); ctx->default_layer_0 = _cogl_pipeline_layer_object_new (layer); /* TODO: we should make default_layer_n comprise of two * descendants of default_layer_0: * - the first descendant should change the texture combine * to what we expect is most commonly used for multitexturing * - the second should revert the above change. * * why? the documentation for how a new layer is initialized * doesn't say that layers > 0 have different defaults so unless * we change the documentation we can't use different defaults, * but if the user does what we expect and changes the * texture combine then we can revert the authority to the * first descendant which means we can maximize the number * of layers with a common ancestor. * * The main problem will be that we'll need to disable the * optimizations for flattening the ancestry when we make * the second descendant which reverts the state. */ ctx->default_layer_n = _cogl_pipeline_layer_copy (layer); new = _cogl_pipeline_set_layer_unit (NULL, ctx->default_layer_n, 1); g_assert (new == ctx->default_layer_n); /* Since we passed a newly allocated layer we don't expect that * _set_layer_unit() will have to allocate *another* layer. */ /* Finally we create a dummy dependant for ->default_layer_n which * effectively ensures that ->default_layer_n and ->default_layer_0 * remain immutable. */ ctx->dummy_layer_dependant = _cogl_pipeline_layer_copy (ctx->default_layer_n); } void _cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer) { CoglPipelineLayer *texture_authority; texture_authority = _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA); if (texture_authority->texture != NULL) { CoglTexturePrePaintFlags flags = 0; CoglPipelineFilter min_filter; CoglPipelineFilter mag_filter; _cogl_pipeline_layer_get_filters (layer, &min_filter, &mag_filter); if (min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST || min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR) flags |= COGL_TEXTURE_NEEDS_MIPMAP; _cogl_texture_pre_paint (texture_authority->texture, flags); } } /* Determines if we need to handle the RGB and A texture combining * separately or is the same function used for both channel masks and * with the same arguments... */ CoglBool _cogl_pipeline_layer_needs_combine_separate (CoglPipelineLayer *combine_authority) { CoglPipelineLayerBigState *big_state = combine_authority->big_state; int n_args; int i; if (big_state->texture_combine_rgb_func != big_state->texture_combine_alpha_func) return TRUE; n_args = _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func); for (i = 0; i < n_args; i++) { if (big_state->texture_combine_rgb_src[i] != big_state->texture_combine_alpha_src[i]) return TRUE; /* * We can allow some variation of the source operands without * needing a separation... * * "A = REPLACE (CONSTANT[A])" + either of the following... * "RGB = REPLACE (CONSTANT[RGB])" * "RGB = REPLACE (CONSTANT[A])" * * can be combined as: * "RGBA = REPLACE (CONSTANT)" or * "RGBA = REPLACE (CONSTANT[A])" or * * And "A = REPLACE (1-CONSTANT[A])" + either of the following... * "RGB = REPLACE (1-CONSTANT)" or * "RGB = REPLACE (1-CONSTANT[A])" * * can be combined as: * "RGBA = REPLACE (1-CONSTANT)" or * "RGBA = REPLACE (1-CONSTANT[A])" */ switch (big_state->texture_combine_alpha_op[i]) { case GL_SRC_ALPHA: switch (big_state->texture_combine_rgb_op[i]) { case GL_SRC_COLOR: case GL_SRC_ALPHA: break; default: return FALSE; } break; case GL_ONE_MINUS_SRC_ALPHA: switch (big_state->texture_combine_rgb_op[i]) { case GL_ONE_MINUS_SRC_COLOR: case GL_ONE_MINUS_SRC_ALPHA: break; default: return FALSE; } break; default: return FALSE; /* impossible */ } } return FALSE; } muffin-5.2.1/cogl/cogl/cogl-bitmap.h0000664000175000017500000002172114211404421017356 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_BITMAP_H__ #define __COGL_BITMAP_H__ /* XXX: We forward declare CoglBitmap here to allow for circular * dependencies between some headers */ typedef struct _CoglBitmap CoglBitmap; #include #include #include #include #include COGL_BEGIN_DECLS /** * cogl_bitmap_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_bitmap_get_gtype (void); /** * SECTION:cogl-bitmap * @short_description: Functions for loading images * * Cogl allows loading image data into memory as CoglBitmaps without * loading them immediately into GPU textures. * * #CoglBitmap is available since Cogl 1.0 */ /** * cogl_bitmap_new_from_file: * @filename: the file to load. * @error: a #CoglError or %NULL. * * Loads an image file from disk. This function can be safely called from * within a thread. * * Return value: (transfer full): a #CoglBitmap to the new loaded * image data, or %NULL if loading the image failed. * * Since: 1.0 */ CoglBitmap * cogl_bitmap_new_from_file (const char *filename, CoglError **error); /** * cogl_bitmap_new_from_buffer: (skip) * @buffer: A #CoglBuffer containing image data * @format: The #CoglPixelFormat defining the format of the image data * in the given @buffer. * @width: The width of the image data in the given @buffer. * @height: The height of the image data in the given @buffer. * @rowstride: The rowstride in bytes of the image data in the given @buffer. * @offset: The offset into the given @buffer to the first pixel that * should be considered part of the #CoglBitmap. * * Wraps some image data that has been uploaded into a #CoglBuffer as * a #CoglBitmap. The data is not copied in this process. * * Return value: (transfer full): a #CoglBitmap encapsulating the given @buffer. * * Since: 1.8 * Stability: unstable */ CoglBitmap * cogl_bitmap_new_from_buffer (CoglBuffer *buffer, CoglPixelFormat format, int width, int height, int rowstride, int offset); /** * cogl_bitmap_new_with_size: (skip) * @context: A #CoglContext * @width: width of the bitmap in pixels * @height: height of the bitmap in pixels * @format: the format of the pixels the array will store * * Creates a new #CoglBitmap with the given width, height and format. * The initial contents of the bitmap are undefined. * * The data for the bitmap will be stored in a newly created * #CoglPixelBuffer. You can get a pointer to the pixel buffer using * cogl_bitmap_get_buffer(). The #CoglBuffer API can then be * used to fill the bitmap with data. * * Cogl will try its best to provide a hardware array you can * map, write into and effectively do a zero copy upload when creating * a texture from it with cogl_texture_new_from_bitmap(). For various * reasons, such arrays are likely to have a stride larger than width * * bytes_per_pixel. The user must take the stride into account when * writing into it. The stride can be retrieved with * cogl_bitmap_get_rowstride(). * * Return value: (transfer full): a #CoglPixelBuffer representing the * newly created array or %NULL on failure * * Since: 1.10 * Stability: Unstable */ CoglBitmap * cogl_bitmap_new_with_size (CoglContext *context, unsigned int width, unsigned int height, CoglPixelFormat format); /** * cogl_bitmap_new_for_data: (skip) * @context: A #CoglContext * @width: The width of the bitmap. * @height: The height of the bitmap. * @format: The format of the pixel data. * @rowstride: The rowstride of the bitmap (the number of bytes from * the start of one row of the bitmap to the next). * @data: A pointer to the data. The bitmap will take ownership of this data. * * Creates a bitmap using some existing data. The data is not copied * so the application must keep the buffer alive for the lifetime of * the #CoglBitmap. This can be used for example with * cogl_framebuffer_read_pixels_into_bitmap() to read data directly * into an application buffer with the specified rowstride. * * Return value: (transfer full): A new #CoglBitmap. * Since: 1.10 * Stability: unstable */ CoglBitmap * cogl_bitmap_new_for_data (CoglContext *context, int width, int height, CoglPixelFormat format, int rowstride, uint8_t *data); /** * cogl_bitmap_get_format: * @bitmap: A #CoglBitmap * * Return value: the #CoglPixelFormat that the data for the bitmap is in. * Since: 1.10 * Stability: unstable */ CoglPixelFormat cogl_bitmap_get_format (CoglBitmap *bitmap); /** * cogl_bitmap_get_width: * @bitmap: A #CoglBitmap * * Return value: the width of the bitmap * Since: 1.10 * Stability: unstable */ int cogl_bitmap_get_width (CoglBitmap *bitmap); /** * cogl_bitmap_get_height: * @bitmap: A #CoglBitmap * * Return value: the height of the bitmap * Since: 1.10 * Stability: unstable */ int cogl_bitmap_get_height (CoglBitmap *bitmap); /** * cogl_bitmap_get_rowstride: * @bitmap: A #CoglBitmap * * Return value: the rowstride of the bitmap. This is the number of * bytes between the address of start of one row to the address of the * next row in the image. * Since: 1.10 * Stability: unstable */ int cogl_bitmap_get_rowstride (CoglBitmap *bitmap); /** * cogl_bitmap_get_buffer: (skip) * @bitmap: A #CoglBitmap * * Return value: (transfer none): the #CoglPixelBuffer that this * buffer uses for storage. Note that if the bitmap was created with * cogl_bitmap_new_from_file() then it will not actually be using a * pixel buffer and this function will return %NULL. * Stability: unstable * Since: 1.10 */ CoglPixelBuffer * cogl_bitmap_get_buffer (CoglBitmap *bitmap); /** * cogl_bitmap_get_size_from_file: * @filename: the file to check * @width: (out): return location for the bitmap width, or %NULL * @height: (out): return location for the bitmap height, or %NULL * * Parses an image file enough to extract the width and height * of the bitmap. * * Return value: %TRUE if the image was successfully parsed * * Since: 1.0 */ CoglBool cogl_bitmap_get_size_from_file (const char *filename, int *width, int *height); /** * cogl_is_bitmap: * @object: a #CoglObject pointer * * Checks whether @object is a #CoglBitmap * * Return value: %TRUE if the passed @object represents a bitmap, * and %FALSE otherwise * * Since: 1.0 */ CoglBool cogl_is_bitmap (void *object); /** * COGL_BITMAP_ERROR: * * #CoglError domain for bitmap errors. * * Since: 1.4 */ #define COGL_BITMAP_ERROR (cogl_bitmap_error_quark ()) /** * CoglBitmapError: * @COGL_BITMAP_ERROR_FAILED: Generic failure code, something went * wrong. * @COGL_BITMAP_ERROR_UNKNOWN_TYPE: Unknown image type. * @COGL_BITMAP_ERROR_CORRUPT_IMAGE: An image file was broken somehow. * * Error codes that can be thrown when performing bitmap * operations. Note that gdk_pixbuf_new_from_file() can also throw * errors directly from the underlying image loading library. For * example, if GdkPixbuf is used then errors #GdkPixbufErrors * will be used directly. * * Since: 1.4 */ typedef enum { COGL_BITMAP_ERROR_FAILED, COGL_BITMAP_ERROR_UNKNOWN_TYPE, COGL_BITMAP_ERROR_CORRUPT_IMAGE } CoglBitmapError; uint32_t cogl_bitmap_error_quark (void); COGL_END_DECLS #endif /* __COGL_BITMAP_H__ */ muffin-5.2.1/cogl/cogl/cogl-renderer-private.h0000664000175000017500000000702014211404421021354 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_RENDERER_PRIVATE_H #define __COGL_RENDERER_PRIVATE_H #include #include "cogl-object-private.h" #include "cogl-winsys-private.h" #include "cogl-driver.h" #include "cogl-texture-driver.h" #include "cogl-context.h" #include "cogl-closure-list-private.h" #ifdef COGL_HAS_XLIB_SUPPORT #include #endif typedef const CoglWinsysVtable *(*CoglCustomWinsysVtableGetter) (CoglRenderer *renderer); struct _CoglRenderer { CoglObject _parent; CoglBool connected; CoglDriver driver_override; const CoglDriverVtable *driver_vtable; const CoglTextureDriver *texture_driver; const CoglWinsysVtable *winsys_vtable; void *custom_winsys_user_data; CoglCustomWinsysVtableGetter custom_winsys_vtable_getter; CoglWinsysID winsys_id_override; GList *constraints; GArray *poll_fds; int poll_fds_age; GList *poll_sources; CoglList idle_closures; GList *outputs; #ifdef COGL_HAS_XLIB_SUPPORT Display *foreign_xdpy; CoglBool xlib_enable_event_retrieval; CoglBool xlib_want_reset_on_video_memory_purge; CoglBool xlib_enable_threaded_swap_wait; #endif CoglDriver driver; unsigned long private_features [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_N_PRIVATE_FEATURES)]; GModule *libgl_module; /* List of callback functions that will be given every native event */ GSList *event_filters; void *winsys; }; /* Mask of constraints that effect driver selection. All of the other * constraints effect only the winsys selection */ #define COGL_RENDERER_DRIVER_CONSTRAINTS \ COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2 typedef CoglFilterReturn (* CoglNativeFilterFunc) (void *native_event, void *data); CoglFilterReturn _cogl_renderer_handle_native_event (CoglRenderer *renderer, void *event); void _cogl_renderer_add_native_filter (CoglRenderer *renderer, CoglNativeFilterFunc func, void *data); void _cogl_renderer_remove_native_filter (CoglRenderer *renderer, CoglNativeFilterFunc func, void *data); void * _cogl_renderer_get_proc_address (CoglRenderer *renderer, const char *name, CoglBool in_core); #endif /* __COGL_RENDERER_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-config.c0000664000175000017500000000773214211404421017350 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-config-private.h" #include char *_cogl_config_driver; char *_cogl_config_renderer; char *_cogl_config_disable_gl_extensions; char *_cogl_config_override_gl_version; /* Array of config options that just set a global string */ static const struct { const char *conf_name; char **variable; } cogl_config_string_options[] = { { "COGL_DRIVER", &_cogl_config_driver }, { "COGL_RENDERER", &_cogl_config_renderer }, { "COGL_DISABLE_GL_EXTENSIONS", &_cogl_config_disable_gl_extensions }, { "COGL_OVERRIDE_GL_VERSION", &_cogl_config_override_gl_version } }; static void _cogl_config_process (GKeyFile *key_file) { char *value; int i; value = g_key_file_get_string (key_file, "global", "COGL_DEBUG", NULL); if (value) { _cogl_parse_debug_string (value, TRUE /* enable the flags */, TRUE /* ignore help option */); free (value); } value = g_key_file_get_string (key_file, "global", "COGL_NO_DEBUG", NULL); if (value) { _cogl_parse_debug_string (value, FALSE /* disable the flags */, TRUE /* ignore help option */); free (value); } for (i = 0; i < G_N_ELEMENTS (cogl_config_string_options); i++) { const char *conf_name = cogl_config_string_options[i].conf_name; char **variable = cogl_config_string_options[i].variable; value = g_key_file_get_string (key_file, "global", conf_name, NULL); if (value) { free (*variable); *variable = value; } } } void _cogl_config_read (void) { GKeyFile *key_file = g_key_file_new (); const char * const *system_dirs = g_get_system_config_dirs (); char *filename; CoglBool status = FALSE; int i; for (i = 0; system_dirs[i]; i++) { filename = g_build_filename (system_dirs[i], "cogl", "cogl.conf", NULL); status = g_key_file_load_from_file (key_file, filename, 0, NULL); free (filename); if (status) { _cogl_config_process (key_file); g_key_file_free (key_file); key_file = g_key_file_new (); break; } } filename = g_build_filename (g_get_user_config_dir (), "cogl", "cogl.conf", NULL); status = g_key_file_load_from_file (key_file, filename, 0, NULL); free (filename); if (status) _cogl_config_process (key_file); g_key_file_free (key_file); } muffin-5.2.1/cogl/cogl/cogl-glx.h0000664000175000017500000000610414211404421016672 0ustar jpeisachjpeisach/* * Cogl * * A Low-Level GPU Graphics and Utilities API * * Copyright (C) 2014 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_GLX_H__ #define __COGL_GLX_H__ /* NB: this is a top-level header that can be included directly but we * want to be careful not to define __COGL_H_INSIDE__ when this is * included internally while building Cogl itself since * __COGL_H_INSIDE__ is used in headers to guard public vs private api * definitions */ #ifndef COGL_COMPILATION /* Note: When building Cogl .gir we explicitly define * __COGL_GLX_H_INSIDE__ */ #ifndef __COGL_GLX_H_INSIDE__ #define __COGL_GLX_H_INSIDE__ #endif /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_GLX_ #endif #endif /* COGL_COMPILATION */ #include #include COGL_BEGIN_DECLS /** * cogl_glx_context_get_glx_context: * @context: A #CoglContext pointer * * If you have done a runtime check to determine that Cogl is using * GLX internally then this API can be used to retrieve the GLXContext * handle that was setup internally. The result is undefined if Cogl * is not using GLX. * * Return value: The internally setup GLXContext handle. * Since: 1.18 * Stability: unstable */ GLXContext cogl_glx_context_get_glx_context (CoglContext *context); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_GLX_ #warning #undef __COGL_H_INSIDE__ #undef __COGL_GLX_H_INSIDE__ #undef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_GLX_ #endif #endif /* __COGL_GLX_H__ */ muffin-5.2.1/cogl/cogl/cogl-texture-2d-sliced.c0000664000175000017500000015114414211404421021344 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Matthew Allum * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-private.h" #include "cogl-util.h" #include "cogl-bitmap.h" #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-gl.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d-sliced-private.h" #include "cogl-texture-gl-private.h" #include "cogl-texture-driver.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-spans.h" #include "cogl-journal-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-primitive-texture.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" #include "cogl-gtype-private.h" #include #include #include static void _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds); COGL_TEXTURE_DEFINE (Texture2DSliced, texture_2d_sliced); COGL_GTYPE_DEFINE_CLASS (Texture2DSliced, texture_2d_sliced, COGL_GTYPE_IMPLEMENT_INTERFACE (texture)); static const CoglTextureVtable cogl_texture_2d_sliced_vtable; typedef struct _ForeachData { CoglMetaTextureCallback callback; void *user_data; float x_normalize_factor; float y_normalize_factor; } ForeachData; static void re_normalize_sub_texture_coords_cb (CoglTexture *sub_texture, const float *sub_texture_coords, const float *meta_coords, void *user_data) { ForeachData *data = user_data; /* The coordinates passed to the span iterating code were * un-normalized so we need to renormalize them before passing them * on */ float re_normalized_coords[4] = { meta_coords[0] * data->x_normalize_factor, meta_coords[1] * data->y_normalize_factor, meta_coords[2] * data->x_normalize_factor, meta_coords[3] * data->y_normalize_factor }; data->callback (sub_texture, sub_texture_coords, re_normalized_coords, data->user_data); } static void _cogl_texture_2d_sliced_foreach_sub_texture_in_region ( CoglTexture *tex, float virtual_tx_1, float virtual_ty_1, float virtual_tx_2, float virtual_ty_2, CoglMetaTextureCallback callback, void *user_data) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglSpan *x_spans = (CoglSpan *)tex_2ds->slice_x_spans->data; CoglSpan *y_spans = (CoglSpan *)tex_2ds->slice_y_spans->data; CoglTexture **textures = (CoglTexture **)tex_2ds->slice_textures->data; float un_normalized_coords[4]; ForeachData data; /* NB: its convenient for us to store non-normalized coordinates in * our CoglSpans but that means we need to un-normalize the incoming * virtual coordinates and make sure we re-normalize the coordinates * before calling the given callback. */ data.callback = callback; data.user_data = user_data; data.x_normalize_factor = 1.0f / tex->width; data.y_normalize_factor = 1.0f / tex->height; un_normalized_coords[0] = virtual_tx_1 * tex->width; un_normalized_coords[1] = virtual_ty_1 * tex->height; un_normalized_coords[2] = virtual_tx_2 * tex->width; un_normalized_coords[3] = virtual_ty_2 * tex->height; /* Note that the normalize factors passed here are the reciprocal of * the factors calculated above because the span iterating code * normalizes by dividing by the factor instead of multiplying */ _cogl_texture_spans_foreach_in_region (x_spans, tex_2ds->slice_x_spans->len, y_spans, tex_2ds->slice_y_spans->len, textures, un_normalized_coords, tex->width, tex->height, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, re_normalize_sub_texture_coords_cb, &data); } static uint8_t * _cogl_texture_2d_sliced_allocate_waste_buffer (CoglTexture2DSliced *tex_2ds, CoglPixelFormat format) { CoglSpan *last_x_span; CoglSpan *last_y_span; uint8_t *waste_buf = NULL; /* If the texture has any waste then allocate a buffer big enough to fill the gaps */ last_x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, tex_2ds->slice_x_spans->len - 1); last_y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, tex_2ds->slice_y_spans->len - 1); if (last_x_span->waste > 0 || last_y_span->waste > 0) { int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); CoglSpan *first_x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0); CoglSpan *first_y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, 0); unsigned int right_size = first_y_span->size * last_x_span->waste; unsigned int bottom_size = first_x_span->size * last_y_span->waste; waste_buf = malloc (MAX (right_size, bottom_size) * bpp); } return waste_buf; } static CoglBool _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, CoglBitmap *source_bmp, CoglTexture2D *slice_tex, uint8_t *waste_buf, CoglSpan *x_span, CoglSpan *y_span, CoglSpanIter *x_iter, CoglSpanIter *y_iter, int src_x, int src_y, int dst_x, int dst_y, CoglError **error) { CoglBool need_x, need_y; CoglContext *ctx = COGL_TEXTURE (tex_2ds)->context; /* If the x_span is sliced and the upload touches the rightmost pixels then fill the waste with copies of the pixels */ need_x = x_span->waste > 0 && x_iter->intersect_end - x_iter->pos >= x_span->size - x_span->waste; /* same for the bottom-most pixels */ need_y = y_span->waste > 0 && y_iter->intersect_end - y_iter->pos >= y_span->size - y_span->waste; if (need_x || need_y) { int bmp_rowstride = cogl_bitmap_get_rowstride (source_bmp); CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); uint8_t *bmp_data; const uint8_t *src; uint8_t *dst; unsigned int wy, wx; CoglBitmap *waste_bmp; bmp_data = _cogl_bitmap_map (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (bmp_data == NULL) return FALSE; if (need_x) { src = (bmp_data + ((src_y + (int) y_iter->intersect_start - dst_y) * bmp_rowstride) + (src_x + (int)x_span->start + (int)x_span->size - (int)x_span->waste - dst_x - 1) * bpp); dst = waste_buf; for (wy = 0; wy < y_iter->intersect_end - y_iter->intersect_start; wy++) { for (wx = 0; wx < x_span->waste; wx++) { memcpy (dst, src, bpp); dst += bpp; } src += bmp_rowstride; } waste_bmp = cogl_bitmap_new_for_data (ctx, x_span->waste, y_iter->intersect_end - y_iter->intersect_start, source_format, x_span->waste * bpp, waste_buf); if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), 0, /* src_x */ 0, /* src_y */ x_span->waste, /* width */ /* height */ y_iter->intersect_end - y_iter->intersect_start, waste_bmp, /* dst_x */ x_span->size - x_span->waste, y_iter->intersect_start - y_span->start, /* dst_y */ 0, /* level */ error)) { cogl_object_unref (waste_bmp); _cogl_bitmap_unmap (source_bmp); return FALSE; } cogl_object_unref (waste_bmp); } if (need_y) { unsigned int copy_width, intersect_width; src = (bmp_data + ((src_x + (int) x_iter->intersect_start - dst_x) * bpp) + (src_y + (int)y_span->start + (int)y_span->size - (int)y_span->waste - dst_y - 1) * bmp_rowstride); dst = waste_buf; if (x_iter->intersect_end - x_iter->pos >= x_span->size - x_span->waste) copy_width = x_span->size + x_iter->pos - x_iter->intersect_start; else copy_width = x_iter->intersect_end - x_iter->intersect_start; intersect_width = x_iter->intersect_end - x_iter->intersect_start; for (wy = 0; wy < y_span->waste; wy++) { memcpy (dst, src, intersect_width * bpp); dst += intersect_width * bpp; for (wx = intersect_width; wx < copy_width; wx++) { memcpy (dst, dst - bpp, bpp); dst += bpp; } } waste_bmp = cogl_bitmap_new_for_data (ctx, copy_width, y_span->waste, source_format, copy_width * bpp, waste_buf); if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), 0, /* src_x */ 0, /* src_y */ copy_width, /* width */ y_span->waste, /* height */ waste_bmp, /* dst_x */ x_iter->intersect_start - x_iter->pos, /* dst_y */ y_span->size - y_span->waste, 0, /* level */ error)) { cogl_object_unref (waste_bmp); _cogl_bitmap_unmap (source_bmp); return FALSE; } cogl_object_unref (waste_bmp); } _cogl_bitmap_unmap (source_bmp); } return TRUE; } static CoglBool _cogl_texture_2d_sliced_upload_bitmap (CoglTexture2DSliced *tex_2ds, CoglBitmap *bmp, CoglError **error) { CoglSpan *x_span; CoglSpan *y_span; CoglTexture2D *slice_tex; int x, y; uint8_t *waste_buf; CoglPixelFormat bmp_format; bmp_format = cogl_bitmap_get_format (bmp); waste_buf = _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds, bmp_format); /* Iterate vertical slices */ for (y = 0; y < tex_2ds->slice_y_spans->len; ++y) { y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y); /* Iterate horizontal slices */ for (x = 0; x < tex_2ds->slice_x_spans->len; ++x) { int slice_num = y * tex_2ds->slice_x_spans->len + x; CoglSpanIter x_iter, y_iter; x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x); /* Pick the gl texture object handle */ slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, slice_num); if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), x_span->start, /* src x */ y_span->start, /* src y */ x_span->size - x_span->waste, /* width */ y_span->size - y_span->waste, /* height */ bmp, 0, /* dst x */ 0, /* dst y */ 0, /* level */ error)) { if (waste_buf) free (waste_buf); return FALSE; } /* Set up a fake iterator that covers the whole slice */ x_iter.intersect_start = x_span->start; x_iter.intersect_end = (x_span->start + x_span->size - x_span->waste); x_iter.pos = x_span->start; y_iter.intersect_start = y_span->start; y_iter.intersect_end = (y_span->start + y_span->size - y_span->waste); y_iter.pos = y_span->start; if (!_cogl_texture_2d_sliced_set_waste (tex_2ds, bmp, slice_tex, waste_buf, x_span, y_span, &x_iter, &y_iter, 0, /* src_x */ 0, /* src_y */ 0, /* dst_x */ 0, error)) /* dst_y */ { if (waste_buf) free (waste_buf); return FALSE; } } } if (waste_buf) free (waste_buf); return TRUE; } static CoglBool _cogl_texture_2d_sliced_upload_subregion (CoglTexture2DSliced *tex_2ds, int src_x, int src_y, int dst_x, int dst_y, int width, int height, CoglBitmap *source_bmp, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2ds); CoglSpan *x_span; CoglSpan *y_span; CoglSpanIter x_iter; CoglSpanIter y_iter; CoglTexture2D *slice_tex; int source_x = 0, source_y = 0; int inter_w = 0, inter_h = 0; int local_x = 0, local_y = 0; uint8_t *waste_buf; CoglPixelFormat source_format; source_format = cogl_bitmap_get_format (source_bmp); waste_buf = _cogl_texture_2d_sliced_allocate_waste_buffer (tex_2ds, source_format); /* Iterate vertical spans */ for (source_y = src_y, _cogl_span_iter_begin (&y_iter, (CoglSpan *)tex_2ds->slice_y_spans->data, tex_2ds->slice_y_spans->len, tex->height, dst_y, dst_y + height, COGL_PIPELINE_WRAP_MODE_REPEAT); !_cogl_span_iter_end (&y_iter); _cogl_span_iter_next (&y_iter), source_y += inter_h ) { y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y_iter.index); /* Iterate horizontal spans */ for (source_x = src_x, _cogl_span_iter_begin (&x_iter, (CoglSpan *)tex_2ds->slice_x_spans->data, tex_2ds->slice_x_spans->len, tex->width, dst_x, dst_x + width, COGL_PIPELINE_WRAP_MODE_REPEAT); !_cogl_span_iter_end (&x_iter); _cogl_span_iter_next (&x_iter), source_x += inter_w ) { int slice_num; x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x_iter.index); /* Pick intersection width and height */ inter_w = (x_iter.intersect_end - x_iter.intersect_start); inter_h = (y_iter.intersect_end - y_iter.intersect_start); /* Localize intersection top-left corner to slice*/ local_x = (x_iter.intersect_start - x_iter.pos); local_y = (y_iter.intersect_start - y_iter.pos); slice_num = y_iter.index * tex_2ds->slice_x_spans->len + x_iter.index; /* Pick slice texture */ slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, slice_num); if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), source_x, source_y, inter_w, /* width */ inter_h, /* height */ source_bmp, local_x, /* dst x */ local_y, /* dst y */ 0, /* level */ error)) { if (waste_buf) free (waste_buf); return FALSE; } if (!_cogl_texture_2d_sliced_set_waste (tex_2ds, source_bmp, slice_tex, waste_buf, x_span, y_span, &x_iter, &y_iter, src_x, src_y, dst_x, dst_y, error)) { if (waste_buf) free (waste_buf); return FALSE; } } } if (waste_buf) free (waste_buf); return TRUE; } static int _cogl_rect_slices_for_size (int size_to_fill, int max_span_size, int max_waste, GArray *out_spans) { int n_spans = 0; CoglSpan span; /* Init first slice span */ span.start = 0; span.size = max_span_size; span.waste = 0; /* Repeat until whole area covered */ while (size_to_fill >= span.size) { /* Add another slice span of same size */ if (out_spans) g_array_append_val (out_spans, span); span.start += span.size; size_to_fill -= span.size; n_spans++; } /* Add one last smaller slice span */ if (size_to_fill > 0) { span.size = size_to_fill; if (out_spans) g_array_append_val (out_spans, span); n_spans++; } return n_spans; } static int _cogl_pot_slices_for_size (int size_to_fill, int max_span_size, int max_waste, GArray *out_spans) { int n_spans = 0; CoglSpan span; /* Init first slice span */ span.start = 0; span.size = max_span_size; span.waste = 0; /* Fix invalid max_waste */ if (max_waste < 0) max_waste = 0; while (TRUE) { /* Is the whole area covered? */ if (size_to_fill > span.size) { /* Not yet - add a span of this size */ if (out_spans) g_array_append_val (out_spans, span); span.start += span.size; size_to_fill -= span.size; n_spans++; } else if (span.size - size_to_fill <= max_waste) { /* Yes and waste is small enough */ /* Pick the next power of two up from size_to_fill. This can sometimes be less than the span.size that would be chosen otherwise */ span.size = _cogl_util_next_p2 (size_to_fill); span.waste = span.size - size_to_fill; if (out_spans) g_array_append_val (out_spans, span); return ++n_spans; } else { /* Yes but waste is too large */ while (span.size - size_to_fill > max_waste) { span.size /= 2; g_assert (span.size > 0); } } } /* Can't get here */ return 0; } static void _cogl_texture_2d_sliced_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); int i; /* Pass the set wrap mode on to all of the child textures */ for (i = 0; i < tex_2ds->slice_textures->len; i++) { CoglTexture2D *slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, i); _cogl_texture_gl_flush_legacy_texobj_wrap_modes (COGL_TEXTURE (slice_tex), wrap_mode_s, wrap_mode_t, wrap_mode_p); } } static void free_spans (CoglTexture2DSliced *tex_2ds) { if (tex_2ds->slice_x_spans != NULL) { g_array_free (tex_2ds->slice_x_spans, TRUE); tex_2ds->slice_x_spans = NULL; } if (tex_2ds->slice_y_spans != NULL) { g_array_free (tex_2ds->slice_y_spans, TRUE); tex_2ds->slice_y_spans = NULL; } } static CoglBool setup_spans (CoglContext *ctx, CoglTexture2DSliced *tex_2ds, int width, int height, int max_waste, CoglPixelFormat internal_format, CoglError **error) { int max_width; int max_height; int n_x_slices; int n_y_slices; int (*slices_for_size) (int, int, int, GArray*); /* Initialize size of largest slice according to supported features */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT)) { max_width = width; max_height = height; slices_for_size = _cogl_rect_slices_for_size; } else { max_width = _cogl_util_next_p2 (width); max_height = _cogl_util_next_p2 (height); slices_for_size = _cogl_pot_slices_for_size; } /* Negative number means no slicing forced by the user */ if (max_waste <= -1) { CoglSpan span; /* Check if size supported else bail out */ if (!ctx->driver_vtable->texture_2d_can_create (ctx, max_width, max_height, internal_format)) { _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE, "Sliced texture size of %d x %d not possible " "with max waste set to -1", width, height); return FALSE; } n_x_slices = 1; n_y_slices = 1; /* Init span arrays */ tex_2ds->slice_x_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), 1); tex_2ds->slice_y_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), 1); /* Add a single span for width and height */ span.start = 0; span.size = max_width; span.waste = max_width - width; g_array_append_val (tex_2ds->slice_x_spans, span); span.size = max_height; span.waste = max_height - height; g_array_append_val (tex_2ds->slice_y_spans, span); } else { /* Decrease the size of largest slice until supported by GL */ while (!ctx->driver_vtable->texture_2d_can_create (ctx, max_width, max_height, internal_format)) { /* Alternate between width and height */ if (max_width > max_height) max_width /= 2; else max_height /= 2; if (max_width == 0 || max_height == 0) { /* Maybe it would be ok to just g_warn_if_reached() for this * codepath */ _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE, "No suitable slice geometry found"); free_spans (tex_2ds); return FALSE; } } /* Determine the slices required to cover the bitmap area */ n_x_slices = slices_for_size (width, max_width, max_waste, NULL); n_y_slices = slices_for_size (height, max_height, max_waste, NULL); /* Init span arrays with reserved size */ tex_2ds->slice_x_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), n_x_slices); tex_2ds->slice_y_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), n_y_slices); /* Fill span arrays with info */ slices_for_size (width, max_width, max_waste, tex_2ds->slice_x_spans); slices_for_size (height, max_height, max_waste, tex_2ds->slice_y_spans); } return TRUE; } static void free_slices (CoglTexture2DSliced *tex_2ds) { if (tex_2ds->slice_textures != NULL) { int i; for (i = 0; i < tex_2ds->slice_textures->len; i++) { CoglTexture2D *slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, i); cogl_object_unref (slice_tex); } g_array_free (tex_2ds->slice_textures, TRUE); } free_spans (tex_2ds); } static CoglBool allocate_slices (CoglTexture2DSliced *tex_2ds, int width, int height, int max_waste, CoglPixelFormat internal_format, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2ds); CoglContext *ctx = tex->context; int n_x_slices; int n_y_slices; int n_slices; int x, y; CoglSpan *x_span; CoglSpan *y_span; tex_2ds->internal_format = internal_format; if (!setup_spans (ctx, tex_2ds, width, height, max_waste, internal_format, error)) { return FALSE; } n_x_slices = tex_2ds->slice_x_spans->len; n_y_slices = tex_2ds->slice_y_spans->len; n_slices = n_x_slices * n_y_slices; tex_2ds->slice_textures = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexture2D *), n_slices); /* Allocate each slice */ for (y = 0; y < n_y_slices; ++y) { y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, y); for (x = 0; x < n_x_slices; ++x) { CoglTexture *slice; x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x); COGL_NOTE (SLICING, "CREATE SLICE (%d,%d)\tsize (%d,%d)", x, y, (int)(x_span->size - x_span->waste), (int)(y_span->size - y_span->waste)); slice = COGL_TEXTURE ( cogl_texture_2d_new_with_size (ctx, x_span->size, y_span->size)); _cogl_texture_copy_internal_format (tex, slice); g_array_append_val (tex_2ds->slice_textures, slice); if (!cogl_texture_allocate (slice, error)) { free_slices (tex_2ds); return FALSE; } } } return TRUE; } static void _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds) { free_slices (tex_2ds); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (tex_2ds)); } static CoglTexture2DSliced * _cogl_texture_2d_sliced_create_base (CoglContext *ctx, int width, int height, int max_waste, CoglPixelFormat internal_format, CoglTextureLoader *loader) { CoglTexture2DSliced *tex_2ds = g_new0 (CoglTexture2DSliced, 1); _cogl_texture_init (COGL_TEXTURE (tex_2ds), ctx, width, height, internal_format, loader, &cogl_texture_2d_sliced_vtable); tex_2ds->max_waste = max_waste; return _cogl_texture_2d_sliced_object_new (tex_2ds); } CoglTexture2DSliced * cogl_texture_2d_sliced_new_with_size (CoglContext *ctx, int width, int height, int max_waste) { CoglTextureLoader *loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED; loader->src.sized.width = width; loader->src.sized.height = height; return _cogl_texture_2d_sliced_create_base (ctx, width, height, max_waste, COGL_PIXEL_FORMAT_RGBA_8888_PRE, loader); } CoglTexture2DSliced * _cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, int max_waste, CoglBool can_convert_in_place) { CoglTextureLoader *loader; _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP; loader->src.bitmap.bitmap = cogl_object_ref (bmp); loader->src.bitmap.can_convert_in_place = can_convert_in_place; return _cogl_texture_2d_sliced_create_base (_cogl_bitmap_get_context (bmp), cogl_bitmap_get_width (bmp), cogl_bitmap_get_height (bmp), max_waste, cogl_bitmap_get_format (bmp), loader); } CoglTexture2DSliced * cogl_texture_2d_sliced_new_from_bitmap (CoglBitmap *bmp, int max_waste) { return _cogl_texture_2d_sliced_new_from_bitmap (bmp, max_waste, FALSE); } CoglTexture2DSliced * _cogl_texture_2d_sliced_new_from_foreign (CoglContext *ctx, unsigned int gl_handle, unsigned int gl_target, int width, int height, int x_pot_waste, int y_pot_waste, CoglPixelFormat format) { CoglTextureLoader *loader; /* NOTE: width, height and internal format are not queriable * in GLES, hence such a function prototype. */ /* This should only be called when the texture target is 2D. If a rectangle texture is used then _cogl_texture_new_from_foreign will create a cogl_texture_rectangle instead */ _COGL_RETURN_VAL_IF_FAIL (gl_target == GL_TEXTURE_2D, NULL); /* Assert it is a valid GL texture object */ _COGL_RETURN_VAL_IF_FAIL (ctx->glIsTexture (gl_handle), FALSE); /* Validate width and height */ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL); /* Validate pot waste */ _COGL_RETURN_VAL_IF_FAIL (x_pot_waste >= 0 && x_pot_waste < width && y_pot_waste >= 0 && y_pot_waste < height, NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN; loader->src.gl_foreign.gl_handle = gl_handle; loader->src.gl_foreign.width = width + x_pot_waste; loader->src.gl_foreign.height = height + y_pot_waste; loader->src.gl_foreign.format = format; return _cogl_texture_2d_sliced_create_base (ctx, width, height, 0, /* max waste */ format, loader); } CoglTexture2DSliced * cogl_texture_2d_sliced_new_from_data (CoglContext *ctx, int width, int height, int max_waste, CoglPixelFormat format, int rowstride, const uint8_t *data, CoglError **error) { CoglBitmap *bmp; CoglTexture2DSliced *tex_2ds; _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); /* Rowstride from width if not given */ if (rowstride == 0) rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); /* Wrap the data into a bitmap */ bmp = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); tex_2ds = cogl_texture_2d_sliced_new_from_bitmap (bmp, max_waste); cogl_object_unref (bmp); if (tex_2ds && !cogl_texture_allocate (COGL_TEXTURE (tex_2ds), error)) { cogl_object_unref (tex_2ds); return NULL; } return tex_2ds; } CoglTexture2DSliced * cogl_texture_2d_sliced_new_from_file (CoglContext *ctx, const char *filename, int max_waste, CoglError **error) { CoglBitmap *bmp; CoglTexture2DSliced *tex_2ds = NULL; _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); bmp = _cogl_bitmap_from_file (ctx, filename, error); if (bmp == NULL) return NULL; tex_2ds = _cogl_texture_2d_sliced_new_from_bitmap (bmp, max_waste, TRUE); /* can convert in-place */ cogl_object_unref (bmp); return tex_2ds; } static CoglBool allocate_with_size (CoglTexture2DSliced *tex_2ds, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2ds); CoglPixelFormat internal_format = _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); if (allocate_slices (tex_2ds, loader->src.sized.width, loader->src.sized.height, tex_2ds->max_waste, internal_format, error)) { _cogl_texture_set_allocated (COGL_TEXTURE (tex_2ds), internal_format, loader->src.sized.width, loader->src.sized.height); return TRUE; } else return FALSE; } static CoglBool allocate_from_bitmap (CoglTexture2DSliced *tex_2ds, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2ds); CoglBitmap *bmp = loader->src.bitmap.bitmap; int width = cogl_bitmap_get_width (bmp); int height = cogl_bitmap_get_height (bmp); CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place; CoglPixelFormat internal_format; CoglBitmap *upload_bmp; _COGL_RETURN_VAL_IF_FAIL (tex_2ds->slice_textures == NULL, FALSE); internal_format = _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp)); upload_bmp = _cogl_bitmap_convert_for_upload (bmp, internal_format, can_convert_in_place, error); if (upload_bmp == NULL) return FALSE; if (!allocate_slices (tex_2ds, width, height, tex_2ds->max_waste, internal_format, error)) { cogl_object_unref (upload_bmp); return FALSE; } if (!_cogl_texture_2d_sliced_upload_bitmap (tex_2ds, upload_bmp, error)) { free_slices (tex_2ds); cogl_object_unref (upload_bmp); return FALSE; } cogl_object_unref (upload_bmp); _cogl_texture_set_allocated (tex, internal_format, width, height); return TRUE; } static CoglBool allocate_from_gl_foreign (CoglTexture2DSliced *tex_2ds, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2ds); CoglContext *ctx = tex->context; CoglPixelFormat format = loader->src.gl_foreign.format; int gl_width = loader->src.gl_foreign.width; int gl_height = loader->src.gl_foreign.height; int x_pot_waste = gl_width - tex->width; int y_pot_waste = gl_height - tex->height; CoglSpan x_span; CoglSpan y_span; CoglTexture2D *tex_2d = cogl_texture_2d_gl_new_from_foreign (ctx, loader->src.gl_foreign.gl_handle, gl_width, gl_height, format); if (!cogl_texture_allocate (COGL_TEXTURE (tex_2d), error)) { cogl_object_unref (tex_2d); return FALSE; } /* The texture 2d backend may use a different pixel format if it queries the actual texture so we'll refetch the format it actually used */ format = _cogl_texture_get_format (tex); tex_2ds->internal_format = format; /* Create slice arrays */ tex_2ds->slice_x_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), 1); tex_2ds->slice_y_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglSpan), 1); tex_2ds->slice_textures = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexture2D *), 1); /* Store info for a single slice */ x_span.start = 0; x_span.size = gl_width; x_span.waste = x_pot_waste; g_array_append_val (tex_2ds->slice_x_spans, x_span); y_span.start = 0; y_span.size = gl_height; y_span.waste = y_pot_waste; g_array_append_val (tex_2ds->slice_y_spans, y_span); g_array_append_val (tex_2ds->slice_textures, tex_2d); _cogl_texture_set_allocated (tex, format, tex->width, tex->height); return TRUE; } static CoglBool _cogl_texture_2d_sliced_allocate (CoglTexture *tex, CoglError **error) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTextureLoader *loader = tex->loader; _COGL_RETURN_VAL_IF_FAIL (loader, FALSE); switch (loader->src_type) { case COGL_TEXTURE_SOURCE_TYPE_SIZED: return allocate_with_size (tex_2ds, loader, error); case COGL_TEXTURE_SOURCE_TYPE_BITMAP: return allocate_from_bitmap (tex_2ds, loader, error); case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN: return allocate_from_gl_foreign (tex_2ds, loader, error); default: break; } g_return_val_if_reached (FALSE); } static CoglBool _cogl_texture_2d_sliced_is_foreign (CoglTexture *tex) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2D *slice_tex; /* Make sure slices were created */ if (tex_2ds->slice_textures == NULL) return FALSE; /* Pass the call on to the first slice */ slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, 0); return _cogl_texture_is_foreign (COGL_TEXTURE (slice_tex)); } static int _cogl_texture_2d_sliced_get_max_waste (CoglTexture *tex) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); return tex_2ds->max_waste; } static CoglBool _cogl_texture_2d_sliced_is_sliced (CoglTexture *tex) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); /* It's only after allocating a sliced texture that we will know * whether it really needed to be sliced... */ if (!tex->allocated) cogl_texture_allocate (tex, NULL); if (tex_2ds->slice_x_spans->len != 1 || tex_2ds->slice_y_spans->len != 1) return TRUE; else return FALSE; } static CoglBool _cogl_texture_2d_sliced_can_hardware_repeat (CoglTexture *tex) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2D *slice_tex; CoglSpan *x_span; CoglSpan *y_span; /* If there's more than one texture then we can't hardware repeat */ if (tex_2ds->slice_textures->len != 1) return FALSE; /* If there's any waste then we can't hardware repeat */ x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0); y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, 0); if (x_span->waste > 0 || y_span->waste > 0) return FALSE; /* Otherwise pass the query on to the single slice texture */ slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, 0); return _cogl_texture_can_hardware_repeat (COGL_TEXTURE (slice_tex)); } static void _cogl_texture_2d_sliced_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglSpan *x_span; CoglSpan *y_span; CoglTexture2D *slice_tex; g_assert (!_cogl_texture_2d_sliced_is_sliced (tex)); /* Don't include the waste in the texture coordinates */ x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, 0); y_span = &g_array_index (tex_2ds->slice_y_spans, CoglSpan, 0); *s *= tex->width / (float)x_span->size; *t *= tex->height / (float)y_span->size; /* Let the child texture further transform the coords */ slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, 0); _cogl_texture_transform_coords_to_gl (COGL_TEXTURE (slice_tex), s, t); } static CoglTransformResult _cogl_texture_2d_sliced_transform_quad_coords_to_gl (CoglTexture *tex, float *coords) { CoglBool need_repeat = FALSE; int i; /* This is a bit lazy - in the case where the quad lies entirely * within a single slice we could avoid the fallback. But that * could likely lead to visual inconsistency if the fallback involves * dropping layers, so this might be the right thing to do anyways. */ if (_cogl_texture_2d_sliced_is_sliced (tex)) return COGL_TRANSFORM_SOFTWARE_REPEAT; for (i = 0; i < 4; i++) if (coords[i] < 0.0f || coords[i] > 1.0f) need_repeat = TRUE; if (need_repeat && !_cogl_texture_2d_sliced_can_hardware_repeat (tex)) return COGL_TRANSFORM_SOFTWARE_REPEAT; _cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 0, coords + 1); _cogl_texture_2d_sliced_transform_coords_to_gl (tex, coords + 2, coords + 3); return (need_repeat ? COGL_TRANSFORM_HARDWARE_REPEAT : COGL_TRANSFORM_NO_REPEAT); } static CoglBool _cogl_texture_2d_sliced_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2D *slice_tex; if (tex_2ds->slice_textures == NULL) return FALSE; if (tex_2ds->slice_textures->len < 1) return FALSE; slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, 0); return cogl_texture_get_gl_texture (COGL_TEXTURE (slice_tex), out_gl_handle, out_gl_target); } static void _cogl_texture_2d_sliced_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2D *slice_tex; int i; _COGL_RETURN_IF_FAIL (tex_2ds->slice_textures != NULL); /* Apply new filters to every slice. The slice texture itself should cache the value and avoid resubmitting the same filter value to GL */ for (i = 0; i < tex_2ds->slice_textures->len; i++) { slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, i); _cogl_texture_gl_flush_legacy_texobj_filters (COGL_TEXTURE (slice_tex), min_filter, mag_filter); } } static void _cogl_texture_2d_sliced_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); int i; _COGL_RETURN_IF_FAIL (tex_2ds->slice_textures != NULL); /* Pass the pre-paint on to every slice */ for (i = 0; i < tex_2ds->slice_textures->len; i++) { CoglTexture2D *slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, i); _cogl_texture_pre_paint (COGL_TEXTURE (slice_tex), flags); } } static void _cogl_texture_2d_sliced_ensure_non_quad_rendering (CoglTexture *tex) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); int i; _COGL_RETURN_IF_FAIL (tex_2ds->slice_textures != NULL); /* Pass the call on to every slice */ for (i = 0; i < tex_2ds->slice_textures->len; i++) { CoglTexture2D *slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, i); _cogl_texture_ensure_non_quad_rendering (COGL_TEXTURE (slice_tex)); } } static CoglBool _cogl_texture_2d_sliced_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, int level, CoglBitmap *bmp, CoglError **error) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglBitmap *upload_bmp; CoglBool status; upload_bmp = _cogl_bitmap_convert_for_upload (bmp, _cogl_texture_get_format (tex), FALSE, /* can't convert in place */ error); if (!upload_bmp) return FALSE; status = _cogl_texture_2d_sliced_upload_subregion (tex_2ds, src_x, src_y, dst_x, dst_y, dst_width, dst_height, upload_bmp, error); cogl_object_unref (upload_bmp); return status; } static CoglPixelFormat _cogl_texture_2d_sliced_get_format (CoglTexture *tex) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); return tex_2ds->internal_format; } static GLenum _cogl_texture_2d_sliced_get_gl_format (CoglTexture *tex) { CoglTexture2DSliced *tex_2ds = COGL_TEXTURE_2D_SLICED (tex); CoglTexture2D *slice_tex; /* Assert that we've allocated our slices at this point */ cogl_texture_allocate (tex, NULL); /* (abort on error) */ /* Pass the call on to the first slice */ slice_tex = g_array_index (tex_2ds->slice_textures, CoglTexture2D *, 0); return _cogl_texture_gl_get_format (COGL_TEXTURE (slice_tex)); } static CoglTextureType _cogl_texture_2d_sliced_get_type (CoglTexture *tex) { return COGL_TEXTURE_TYPE_2D; } static const CoglTextureVtable cogl_texture_2d_sliced_vtable = { FALSE, /* not primitive */ _cogl_texture_2d_sliced_allocate, _cogl_texture_2d_sliced_set_region, NULL, /* get_data */ _cogl_texture_2d_sliced_foreach_sub_texture_in_region, _cogl_texture_2d_sliced_get_max_waste, _cogl_texture_2d_sliced_is_sliced, _cogl_texture_2d_sliced_can_hardware_repeat, _cogl_texture_2d_sliced_transform_coords_to_gl, _cogl_texture_2d_sliced_transform_quad_coords_to_gl, _cogl_texture_2d_sliced_get_gl_texture, _cogl_texture_2d_sliced_gl_flush_legacy_texobj_filters, _cogl_texture_2d_sliced_pre_paint, _cogl_texture_2d_sliced_ensure_non_quad_rendering, _cogl_texture_2d_sliced_gl_flush_legacy_texobj_wrap_modes, _cogl_texture_2d_sliced_get_format, _cogl_texture_2d_sliced_get_gl_format, _cogl_texture_2d_sliced_get_type, _cogl_texture_2d_sliced_is_foreign, NULL /* set_auto_mipmap */ }; muffin-5.2.1/cogl/cogl/cogl-point-in-poly.c0000664000175000017500000001015514211404421020612 0ustar jpeisachjpeisach/* * Point Inclusion in Polygon Test * * Copyright (c) 1970-2003, Wm. Randolph Franklin * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above * copyright notice in the documentation and/or other materials * provided with the distribution. * 3. The name of W. Randolph Franklin may not be used to endorse or * promote products derived from this Software without specific * prior written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Note: * The algorithm for this point_in_poly() function was learnt from: * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-point-in-poly-private.h" #include /* We've made a notable change to the original algorithm referenced * above to make sure we have reliable results for screen aligned * rectangles even though there may be some numerical in-precision in * how the vertices of the polygon were calculated. * * We've avoided introducing an epsilon factor to the comparisons * since we feel there's a risk of changing some semantics in ways that * might not be desirable. One of those is that if you transform two * polygons which share an edge and test a point close to that edge * then this algorithm will currently give a positive result for only * one polygon. * * Another concern is the way this algorithm resolves the corner case * where the horizontal ray being cast to count edge crossings may * cross directly through a vertex. The solution is based on the "idea * of Simulation of Simplicity" and "pretends to shift the ray * infinitesimally down so that it either clearly intersects, or * clearly doesn't touch". I'm not familiar with the idea myself so I * expect a misplaced epsilon is likely to break that aspect of the * algorithm. * * The simple solution we've gone for is to pixel align the polygon * vertices which should eradicate most noise due to in-precision. */ int _cogl_util_point_in_screen_poly (float point_x, float point_y, void *vertices, size_t stride, int n_vertices) { int i, j, c = 0; for (i = 0, j = n_vertices - 1; i < n_vertices; j = i++) { float vert_xi = *(float *)((uint8_t *)vertices + i * stride); float vert_xj = *(float *)((uint8_t *)vertices + j * stride); float vert_yi = *(float *)((uint8_t *)vertices + i * stride + sizeof (float)); float vert_yj = *(float *)((uint8_t *)vertices + j * stride + sizeof (float)); vert_xi = COGL_UTIL_NEARBYINT (vert_xi); vert_xj = COGL_UTIL_NEARBYINT (vert_xj); vert_yi = COGL_UTIL_NEARBYINT (vert_yi); vert_yj = COGL_UTIL_NEARBYINT (vert_yj); if (((vert_yi > point_y) != (vert_yj > point_y)) && (point_x < (vert_xj - vert_xi) * (point_y - vert_yi) / (vert_yj - vert_yi) + vert_xi) ) c = !c; } return c; } muffin-5.2.1/cogl/cogl/cogl-display.c0000664000175000017500000001047114211404421017542 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-private.h" #include "cogl-object.h" #include "cogl-display-private.h" #include "cogl-renderer-private.h" #include "cogl-winsys-private.h" #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT #include "cogl-wayland-server.h" #endif #include "cogl-gtype-private.h" static void _cogl_display_free (CoglDisplay *display); COGL_OBJECT_DEFINE (Display, display); COGL_GTYPE_DEFINE_CLASS (Display, display); static const CoglWinsysVtable * _cogl_display_get_winsys (CoglDisplay *display) { return display->renderer->winsys_vtable; } static void _cogl_display_free (CoglDisplay *display) { const CoglWinsysVtable *winsys; if (display->setup) { winsys = _cogl_display_get_winsys (display); winsys->display_destroy (display); display->setup = FALSE; } if (display->renderer) { cogl_object_unref (display->renderer); display->renderer = NULL; } if (display->onscreen_template) { cogl_object_unref (display->onscreen_template); display->onscreen_template = NULL; } g_slice_free (CoglDisplay, display); } CoglDisplay * cogl_display_new (CoglRenderer *renderer, CoglOnscreenTemplate *onscreen_template) { CoglDisplay *display = g_slice_new0 (CoglDisplay); CoglError *error = NULL; _cogl_init (); display->renderer = renderer; if (renderer) cogl_object_ref (renderer); else display->renderer = cogl_renderer_new (); if (!cogl_renderer_connect (display->renderer, &error)) g_error ("Failed to connect to renderer: %s\n", error->message); display->setup = FALSE; display = _cogl_display_object_new (display); cogl_display_set_onscreen_template (display, onscreen_template); return display; } CoglRenderer * cogl_display_get_renderer (CoglDisplay *display) { return display->renderer; } void cogl_display_set_onscreen_template (CoglDisplay *display, CoglOnscreenTemplate *onscreen_template) { _COGL_RETURN_IF_FAIL (display->setup == FALSE); if (onscreen_template) cogl_object_ref (onscreen_template); if (display->onscreen_template) cogl_object_unref (display->onscreen_template); display->onscreen_template = onscreen_template; /* NB: we want to maintain the invariable that there is always an * onscreen template associated with a CoglDisplay... */ if (!onscreen_template) display->onscreen_template = cogl_onscreen_template_new (NULL); } CoglBool cogl_display_setup (CoglDisplay *display, CoglError **error) { const CoglWinsysVtable *winsys; if (display->setup) return TRUE; winsys = _cogl_display_get_winsys (display); if (!winsys->display_setup (display, error)) return FALSE; display->setup = TRUE; return TRUE; } #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT void cogl_wayland_display_set_compositor_display (CoglDisplay *display, struct wl_display *wayland_display) { _COGL_RETURN_IF_FAIL (display->setup == FALSE); display->wayland_compositor_display = wayland_display; } #endif muffin-5.2.1/cogl/cogl/cogl-buffer-private.h0000664000175000017500000001273614211404421021031 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Damien Lespiau * Robert Bragg */ #ifndef __COGL_BUFFER_PRIVATE_H__ #define __COGL_BUFFER_PRIVATE_H__ #include #include "cogl-object-private.h" #include "cogl-buffer.h" #include "cogl-context.h" #include "cogl-gl-header.h" COGL_BEGIN_DECLS typedef struct _CoglBufferVtable CoglBufferVtable; struct _CoglBufferVtable { void * (* map_range) (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error); void (* unmap) (CoglBuffer *buffer); CoglBool (* set_data) (CoglBuffer *buffer, unsigned int offset, const void *data, unsigned int size, CoglError **error); }; typedef enum _CoglBufferFlags { COGL_BUFFER_FLAG_NONE = 0, COGL_BUFFER_FLAG_BUFFER_OBJECT = 1UL << 0, /* real openGL buffer object */ COGL_BUFFER_FLAG_MAPPED = 1UL << 1, COGL_BUFFER_FLAG_MAPPED_FALLBACK = 1UL << 2 } CoglBufferFlags; typedef enum { COGL_BUFFER_USAGE_HINT_TEXTURE, COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER, COGL_BUFFER_USAGE_HINT_INDEX_BUFFER } CoglBufferUsageHint; typedef enum { COGL_BUFFER_BIND_TARGET_PIXEL_PACK, COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER, COGL_BUFFER_BIND_TARGET_COUNT } CoglBufferBindTarget; struct _CoglBuffer { CoglObject _parent; CoglContext *context; CoglBufferVtable vtable; CoglBufferBindTarget last_target; CoglBufferFlags flags; GLuint gl_handle; /* OpenGL handle */ unsigned int size; /* size of the buffer, in bytes */ CoglBufferUsageHint usage_hint; CoglBufferUpdateHint update_hint; /* points to the mapped memory when the CoglBuffer is a VBO, PBO, * ... or points to allocated memory in the fallback paths */ uint8_t *data; int immutable_ref; unsigned int store_created:1; }; /* This is used to register a type to the list of handle types that will be considered a texture in cogl_is_texture() */ void _cogl_buffer_register_buffer_type (const CoglObjectClass *klass); #define COGL_BUFFER_DEFINE(TypeName, type_name) \ COGL_OBJECT_DEFINE_WITH_CODE \ (TypeName, type_name, \ _cogl_buffer_register_buffer_type (&_cogl_##type_name##_class)) void _cogl_buffer_initialize (CoglBuffer *buffer, CoglContext *context, size_t size, CoglBufferBindTarget default_target, CoglBufferUsageHint usage_hint, CoglBufferUpdateHint update_hint); void _cogl_buffer_fini (CoglBuffer *buffer); CoglBufferUsageHint _cogl_buffer_get_usage_hint (CoglBuffer *buffer); GLenum _cogl_buffer_access_to_gl_enum (CoglBufferAccess access); CoglBuffer * _cogl_buffer_immutable_ref (CoglBuffer *buffer); void _cogl_buffer_immutable_unref (CoglBuffer *buffer); CoglBool _cogl_buffer_set_data (CoglBuffer *buffer, size_t offset, const void *data, size_t size, CoglError **error); void * _cogl_buffer_map (CoglBuffer *buffer, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error); /* This is a wrapper around cogl_buffer_map_range for internal use when we want to map the buffer for write only to replace the entire contents. If the map fails then it will fallback to writing to a temporary buffer. When _cogl_buffer_unmap_for_fill_or_fallback is called the temporary buffer will be copied into the array. Note that these calls share a global array so they can not be nested. */ void * _cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer, size_t offset, size_t size); void * _cogl_buffer_map_for_fill_or_fallback (CoglBuffer *buffer); void _cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer); COGL_END_DECLS #endif /* __COGL_BUFFER_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-depth-state-private.h0000664000175000017500000000260114211404421021770 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifndef __COGL_DEPTH_STATE_PRIVATE_H #define __COGL_DEPTH_STATE_PRIVATE_H #define COGL_DEPTH_STATE_MAGIC 0xDEADBEEF #endif /* __COGL_DEPTH_STATE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-glx-renderer-private.h0000664000175000017500000000677014211404421022157 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_RENDERER_GLX_PRIVATE_H #define __COGL_RENDERER_GLX_PRIVATE_H #include #include "cogl-object-private.h" #include "cogl-xlib-renderer-private.h" typedef struct _CoglGLXRenderer { int glx_major; int glx_minor; int glx_error_base; int glx_event_base; /* Vblank stuff */ int dri_fd; /* enumeration with relatioship between OML_sync_control * UST (unadjusted-system-time) and the system clock */ enum { COGL_GLX_UST_IS_UNKNOWN, COGL_GLX_UST_IS_GETTIMEOFDAY, COGL_GLX_UST_IS_MONOTONIC_TIME, COGL_GLX_UST_IS_OTHER } ust_type; /* GModule pointing to libGL which we use to get glX functions out of */ GModule *libgl_module; CoglClosure *flush_notifications_idle; /* Copy of the winsys features that are based purely on the * information we can get without using a GL context. We want to * determine this before we have a context so that we can use the * function pointers from the extensions earlier. This is necessary * to use the glXCreateContextAttribs function. */ unsigned long base_winsys_features [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_WINSYS_FEATURE_N_FEATURES)]; CoglFeatureFlags legacy_feature_flags; /* Function pointers for core GLX functionality. We can't just link against these directly because we need to conditionally load libGL when we are using GLX so that it won't conflict with a GLES library if we are using EGL + GLES. These are just the functions that we want to use before calling glXGetProcAddress */ Bool (* glXQueryExtension) (Display *dpy, int *errorb, int *event); const char * (* glXQueryExtensionsString) (Display *dpy, int screen); Bool (* glXQueryVersion) (Display *dpy, int *maj, int *min); void * (* glXGetProcAddress) (const GLubyte *procName); int (* glXQueryDrawable) (Display *dpy, GLXDrawable drawable, int attribute, unsigned int *value); /* Function pointers for GLX specific extensions */ #define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d, e, f, g) #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \ ret (APIENTRY * name) args; #define COGL_WINSYS_FEATURE_END() #include "cogl-winsys-glx-feature-functions.h" #undef COGL_WINSYS_FEATURE_BEGIN #undef COGL_WINSYS_FEATURE_FUNCTION #undef COGL_WINSYS_FEATURE_END } CoglGLXRenderer; #endif /* __COGL_RENDERER_GLX_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-debug.h0000664000175000017500000000742214211404421017172 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_DEBUG_H__ #define __COGL_DEBUG_H__ #include "cogl-profile.h" #include "cogl-flags.h" #include "cogl-util.h" #include COGL_BEGIN_DECLS typedef enum { COGL_DEBUG_SLICING, COGL_DEBUG_OFFSCREEN, COGL_DEBUG_DRAW, COGL_DEBUG_PANGO, COGL_DEBUG_RECTANGLES, COGL_DEBUG_OBJECT, COGL_DEBUG_BLEND_STRINGS, COGL_DEBUG_DISABLE_BATCHING, COGL_DEBUG_DISABLE_VBOS, COGL_DEBUG_DISABLE_PBOS, COGL_DEBUG_JOURNAL, COGL_DEBUG_BATCHING, COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM, COGL_DEBUG_MATRICES, COGL_DEBUG_ATLAS, COGL_DEBUG_DUMP_ATLAS_IMAGE, COGL_DEBUG_DISABLE_ATLAS, COGL_DEBUG_DISABLE_SHARED_ATLAS, COGL_DEBUG_OPENGL, COGL_DEBUG_DISABLE_TEXTURING, COGL_DEBUG_DISABLE_ARBFP, COGL_DEBUG_DISABLE_FIXED, COGL_DEBUG_DISABLE_GLSL, COGL_DEBUG_SHOW_SOURCE, COGL_DEBUG_DISABLE_BLENDING, COGL_DEBUG_TEXTURE_PIXMAP, COGL_DEBUG_BITMAP, COGL_DEBUG_DISABLE_NPOT_TEXTURES, COGL_DEBUG_WIREFRAME, COGL_DEBUG_DISABLE_SOFTWARE_CLIP, COGL_DEBUG_DISABLE_PROGRAM_CACHES, COGL_DEBUG_DISABLE_FAST_READ_PIXEL, COGL_DEBUG_CLIPPING, COGL_DEBUG_WINSYS, COGL_DEBUG_PERFORMANCE, COGL_DEBUG_N_FLAGS } CoglDebugFlags; extern GHashTable *_cogl_debug_instances; #define COGL_DEBUG_N_LONGS COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_DEBUG_N_FLAGS) extern unsigned long _cogl_debug_flags[COGL_DEBUG_N_LONGS]; #define COGL_DEBUG_ENABLED(flag) \ COGL_FLAGS_GET (_cogl_debug_flags, flag) #define COGL_DEBUG_SET_FLAG(flag) \ COGL_FLAGS_SET (_cogl_debug_flags, flag, TRUE) #define COGL_DEBUG_CLEAR_FLAG(flag) \ COGL_FLAGS_SET (_cogl_debug_flags, flag, FALSE) #ifdef __GNUC__ #define COGL_NOTE(type,x,a...) G_STMT_START { \ if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_##type))) { \ _cogl_profile_trace_message ("[" #type "] " G_STRLOC " & " x, ##a); \ } } G_STMT_END #else #define COGL_NOTE(type,...) G_STMT_START { \ if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_##type))) { \ char *_fmt = g_strdup_printf (__VA_ARGS__); \ _cogl_profile_trace_message ("[" #type "] " G_STRLOC " & %s", _fmt);\ free (_fmt); \ } } G_STMT_END #endif /* __GNUC__ */ void _cogl_debug_check_environment (void); void _cogl_parse_debug_string (const char *value, CoglBool enable, CoglBool ignore_help); COGL_END_DECLS #endif /* __COGL_DEBUG_H__ */ muffin-5.2.1/cogl/cogl/cogl-pipeline-private.h0000664000175000017500000010335614211404421021364 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_PRIVATE_H #define __COGL_PIPELINE_PRIVATE_H #include "cogl-node-private.h" #include "cogl-pipeline-layer-private.h" #include "cogl-pipeline.h" #include "cogl-matrix.h" #include "cogl-object-private.h" #include "cogl-profile.h" #include "cogl-list.h" #include "cogl-boxed-value.h" #include "cogl-pipeline-snippet-private.h" #include "cogl-pipeline-state.h" #include "cogl-framebuffer.h" #include "cogl-bitmask.h" #include #ifdef HAVE_COGL_GL #define COGL_PIPELINE_PROGEND_FIXED_ARBFP 0 #define COGL_PIPELINE_PROGEND_FIXED 1 #define COGL_PIPELINE_PROGEND_GLSL 2 #define COGL_PIPELINE_N_PROGENDS 3 #define COGL_PIPELINE_VERTEND_FIXED 0 #define COGL_PIPELINE_VERTEND_GLSL 1 #define COGL_PIPELINE_N_VERTENDS 2 #define COGL_PIPELINE_FRAGEND_ARBFP 0 #define COGL_PIPELINE_FRAGEND_FIXED 1 #define COGL_PIPELINE_FRAGEND_GLSL 2 #define COGL_PIPELINE_N_FRAGENDS 3 #else /* HAVE_COGL_GL */ #ifdef HAVE_COGL_GLES2 #define COGL_PIPELINE_PROGEND_GLSL 0 #define COGL_PIPELINE_VERTEND_GLSL 0 #define COGL_PIPELINE_FRAGEND_GLSL 0 #ifdef HAVE_COGL_GLES #define COGL_PIPELINE_PROGEND_FIXED 1 #define COGL_PIPELINE_VERTEND_FIXED 1 #define COGL_PIPELINE_FRAGEND_FIXED 1 #define COGL_PIPELINE_N_PROGENDS 2 #define COGL_PIPELINE_N_VERTENDS 2 #define COGL_PIPELINE_N_FRAGENDS 2 #else #define COGL_PIPELINE_N_PROGENDS 1 #define COGL_PIPELINE_N_VERTENDS 1 #define COGL_PIPELINE_N_FRAGENDS 1 #endif #else /* HAVE_COGL_GLES2 */ #ifdef HAVE_COGL_GLES #define COGL_PIPELINE_PROGEND_FIXED 0 #define COGL_PIPELINE_VERTEND_FIXED 0 #define COGL_PIPELINE_FRAGEND_FIXED 0 #define COGL_PIPELINE_N_PROGENDS 1 #define COGL_PIPELINE_N_VERTENDS 1 #define COGL_PIPELINE_N_FRAGENDS 1 #else #error No drivers defined #endif #endif /* HAVE_COGL_GLES2 */ #endif /* HAVE_COGL_GL */ #define COGL_PIPELINE_PROGEND_DEFAULT 0 #define COGL_PIPELINE_PROGEND_UNDEFINED 3 /* XXX: should I rename these as * COGL_PIPELINE_STATE_INDEX_XYZ... ? */ typedef enum { /* sparse state */ COGL_PIPELINE_STATE_COLOR_INDEX, COGL_PIPELINE_STATE_BLEND_ENABLE_INDEX, COGL_PIPELINE_STATE_LAYERS_INDEX, COGL_PIPELINE_STATE_LIGHTING_INDEX, COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX, COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX, COGL_PIPELINE_STATE_BLEND_INDEX, COGL_PIPELINE_STATE_USER_SHADER_INDEX, COGL_PIPELINE_STATE_DEPTH_INDEX, COGL_PIPELINE_STATE_FOG_INDEX, COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE_INDEX, COGL_PIPELINE_STATE_POINT_SIZE_INDEX, COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX, COGL_PIPELINE_STATE_LOGIC_OPS_INDEX, COGL_PIPELINE_STATE_CULL_FACE_INDEX, COGL_PIPELINE_STATE_UNIFORMS_INDEX, COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX, COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX, /* non-sparse */ COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX, COGL_PIPELINE_STATE_COUNT } CoglPipelineStateIndex; #define COGL_PIPELINE_STATE_SPARSE_COUNT (COGL_PIPELINE_STATE_COUNT - 1) /* Used in pipeline->differences masks and for notifying pipeline * state changes. * * XXX: If you add or remove state groups here you may need to update * some of the state masks following this enum too! * * FIXME: perhaps it would be better to rename this enum to * CoglPipelineStateGroup to better convey the fact that a single enum * here can map to multiple properties. */ typedef enum _CoglPipelineState { COGL_PIPELINE_STATE_COLOR = 1L<big_state. */ /* Layers represent their state in a tree structure where some of * the state relating to a given pipeline or layer may actually be * owned by one if is ancestors in the tree. We have a common data * type to track the tree heirachy so we can share code... */ CoglNode _parent; /* When weak pipelines are destroyed the user is notified via this * callback */ CoglPipelineDestroyCallback destroy_callback; /* When notifying that a weak pipeline has been destroyed this * private data is passed to the above callback */ void *destroy_data; /* We need to track if a pipeline is referenced in the journal * because we can't allow modification to these pipelines without * flushing the journal first */ unsigned int journal_ref_count; /* A mask of which sparse state groups are different in this * pipeline in comparison to its parent. */ unsigned int differences; /* Whenever a pipeline is modified we increment the age. There's no * guarantee that it won't wrap but it can nevertheless be a * convenient mechanism to determine when a pipeline has been * changed to you can invalidate some some associated cache that * depends on the old state. */ unsigned int age; /* This is the primary color of the pipeline. * * This is a sparse property, ref COGL_PIPELINE_STATE_COLOR */ CoglColor color; /* A pipeline may be made up with multiple layers used to combine * textures together. * * This is sparse state, ref COGL_PIPELINE_STATE_LAYERS */ unsigned int n_layers; GList *layer_differences; /* As a basic way to reduce memory usage we divide the pipeline * state into two groups; the minimal state modified in 90% of * all pipelines and the rest, so that the second group can * be allocated dynamically when required... */ CoglPipelineBigState *big_state; #ifdef COGL_DEBUG_ENABLED /* For debugging purposes it's possible to associate a static const * string with a pipeline which can be an aid when trying to trace * where the pipeline originates from */ const char *static_breadcrumb; #endif /* Cached state... */ /* A cached, complete list of the layers this pipeline depends * on sorted by layer->unit_index. */ CoglPipelineLayer **layers_cache; /* To avoid a separate ->layers_cache allocation for common * pipelines with only a few layers... */ CoglPipelineLayer *short_layers_cache[3]; /* The deprecated cogl_pipeline_get_layers() API returns a * const GList of layers, which we track here... */ GList *deprecated_get_layers_list; /* XXX: consider adding an authorities cache to speed up sparse * property value lookups: * CoglPipeline *authorities_cache[COGL_PIPELINE_N_SPARSE_PROPERTIES]; * and corresponding authorities_cache_dirty:1 bitfield */ /* bitfields */ /* Weak pipelines don't count as dependants on their parents which * means that the parent pipeline can be modified without * considering how the modifications may affect the weak pipeline. */ unsigned int is_weak:1; /* Determines if pipeline->big_state is valid */ unsigned int has_big_state:1; /* By default blending is enabled automatically depending on the * unlit color, the lighting colors or the texture format. The user * can override this to explicitly enable or disable blending. * * This is a sparse property */ unsigned int blend_enable:3; /* There are many factors that can determine if we need to enable * blending, this holds our final decision */ unsigned int real_blend_enable:1; /* Since the code for deciding if blending really needs to be * enabled for a particular pipeline is quite expensive we update * the real_blend_enable flag lazily when flushing a pipeline if * this dirty flag has been set. */ unsigned int dirty_real_blend_enable:1; /* Whenever a pipeline is flushed we keep track of whether the * pipeline was used with a color attribute where we don't know * whether the colors are opaque. The real_blend_enable state * depends on this, and must be updated whenever this changes (even * if dirty_real_blend_enable isn't set) */ unsigned int unknown_color_alpha:1; unsigned int layers_cache_dirty:1; unsigned int deprecated_get_layers_list_dirty:1; #ifdef COGL_DEBUG_ENABLED /* For debugging purposes it's possible to associate a static const * string with a pipeline which can be an aid when trying to trace * where the pipeline originates from */ unsigned int has_static_breadcrumb:1; #endif /* There are multiple fragment and vertex processing backends for * CoglPipeline, glsl, arbfp and fixed that are bundled under a * "progend". This identifies the backend being used for the * pipeline. */ unsigned int progend:3; }; typedef struct _CoglPipelineFragend { void (*start) (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference); CoglBool (*add_layer) (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference); CoglBool (*passthrough) (CoglPipeline *pipeline); CoglBool (*end) (CoglPipeline *pipeline, unsigned long pipelines_difference); void (*pipeline_pre_change_notify) (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color); void (*pipeline_set_parent_notify) (CoglPipeline *pipeline); void (*layer_pre_change_notify) (CoglPipeline *owner, CoglPipelineLayer *layer, CoglPipelineLayerState change); } CoglPipelineFragend; typedef struct _CoglPipelineVertend { void (*start) (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference); CoglBool (*add_layer) (CoglPipeline *pipeline, CoglPipelineLayer *layer, unsigned long layers_difference, CoglFramebuffer *framebuffer); CoglBool (*end) (CoglPipeline *pipeline, unsigned long pipelines_difference); void (*pipeline_pre_change_notify) (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color); void (*layer_pre_change_notify) (CoglPipeline *owner, CoglPipelineLayer *layer, CoglPipelineLayerState change); } CoglPipelineVertend; typedef struct { int vertend; int fragend; CoglBool (*start) (CoglPipeline *pipeline); void (*end) (CoglPipeline *pipeline, unsigned long pipelines_difference); void (*pipeline_pre_change_notify) (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color); void (*layer_pre_change_notify) (CoglPipeline *owner, CoglPipelineLayer *layer, CoglPipelineLayerState change); /* This is called after all of the other functions whenever the pipeline is flushed, even if the pipeline hasn't changed since the last flush */ void (* pre_paint) (CoglPipeline *pipeline, CoglFramebuffer *framebuffer); } CoglPipelineProgend; typedef enum { COGL_PIPELINE_PROGRAM_TYPE_GLSL = 1, COGL_PIPELINE_PROGRAM_TYPE_ARBFP, COGL_PIPELINE_PROGRAM_TYPE_FIXED } CoglPipelineProgramType; extern const CoglPipelineFragend * _cogl_pipeline_fragends[COGL_PIPELINE_N_FRAGENDS]; extern const CoglPipelineVertend * _cogl_pipeline_vertends[COGL_PIPELINE_N_VERTENDS]; extern const CoglPipelineProgend * _cogl_pipeline_progends[]; void _cogl_pipeline_init_default_pipeline (void); static inline CoglPipeline * _cogl_pipeline_get_parent (CoglPipeline *pipeline) { CoglNode *parent_node = COGL_NODE (pipeline)->parent; return COGL_PIPELINE (parent_node); } static inline CoglPipeline * _cogl_pipeline_get_authority (CoglPipeline *pipeline, unsigned long difference) { CoglPipeline *authority = pipeline; while (!(authority->differences & difference)) authority = _cogl_pipeline_get_parent (authority); return authority; } typedef CoglBool (*CoglPipelineStateComparitor) (CoglPipeline *authority0, CoglPipeline *authority1); void _cogl_pipeline_update_authority (CoglPipeline *pipeline, CoglPipeline *authority, CoglPipelineState state, CoglPipelineStateComparitor comparitor); void _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color, CoglBool from_layer_change); void _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline); void _cogl_pipeline_update_real_blend_enable (CoglPipeline *pipeline, CoglBool unknown_color_alpha); typedef enum { COGL_PIPELINE_GET_LAYER_NO_CREATE = 1<<0 } CoglPipelineGetLayerFlags; CoglPipelineLayer * _cogl_pipeline_get_layer_with_flags (CoglPipeline *pipeline, int layer_index, CoglPipelineGetLayerFlags flags); #define _cogl_pipeline_get_layer(p, l) \ _cogl_pipeline_get_layer_with_flags (p, l, 0) CoglBool _cogl_is_pipeline_layer (void *object); void _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority, CoglPipelineLayer *layer); /* * SECTION:cogl-pipeline-internals * @short_description: Functions for creating custom primitives that make use * of Cogl pipelines for filling. * * Normally you shouldn't need to use this API directly, but if you need to * developing a custom/specialised primitive - probably using raw OpenGL - then * this API aims to expose enough of the pipeline internals to support being * able to fill your geometry according to a given Cogl pipeline. */ CoglBool _cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline); /* * Calls the pre_paint method on the layer texture if there is * one. This will determine whether mipmaps are needed based on the * filter settings. */ void _cogl_pipeline_pre_paint_for_layer (CoglPipeline *pipeline, int layer_id); /* * CoglPipelineFlushFlag: * @COGL_PIPELINE_FLUSH_FALLBACK_MASK: The fallback_layers member is set to * a uint32_t mask of the layers that can't be supported with the user * supplied texture and need to be replaced with fallback textures. (1 = * fallback, and the least significant bit = layer 0) * @COGL_PIPELINE_FLUSH_DISABLE_MASK: The disable_layers member is set to * a uint32_t mask of the layers that you want to completly disable * texturing for (1 = fallback, and the least significant bit = layer 0) * @COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE: The layer0_override_texture member is * set to a GLuint OpenGL texture name to override the texture used for * layer 0 of the pipeline. This is intended for dealing with sliced * textures where you will need to point to each of the texture slices in * turn when drawing your geometry. Passing a value of 0 is the same as * not passing the option at all. * @COGL_PIPELINE_FLUSH_SKIP_GL_COLOR: When flushing the GL state for the * pipeline don't call glColor. */ typedef enum _CoglPipelineFlushFlag { COGL_PIPELINE_FLUSH_FALLBACK_MASK = 1L<<0, COGL_PIPELINE_FLUSH_DISABLE_MASK = 1L<<1, COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE = 1L<<2, COGL_PIPELINE_FLUSH_SKIP_GL_COLOR = 1L<<3 } CoglPipelineFlushFlag; /* * CoglPipelineFlushOptions: * */ typedef struct _CoglPipelineFlushOptions { CoglPipelineFlushFlag flags; uint32_t fallback_layers; uint32_t disable_layers; CoglTexture *layer0_override_texture; } CoglPipelineFlushOptions; void _cogl_use_fragment_program (GLuint gl_program, CoglPipelineProgramType type); void _cogl_use_vertex_program (GLuint gl_program, CoglPipelineProgramType type); unsigned int _cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func); /* * _cogl_pipeline_weak_copy: * @pipeline: A #CoglPipeline object * @callback: A callback to notify when your weak pipeline is destroyed * @user_data: Private data to pass to your given callback. * * Returns a weak copy of the given source @pipeline. Unlike a normal * copy no internal reference is taken on the source @pipeline and you * can expect that later modifications of the source pipeline (or in * fact any other pipeline) can result in the weak pipeline being * destroyed. * * To understand this better its good to know a bit about the internal * design of #CoglPipeline... * * Internally #CoglPipelines are represented as a graph of * property diff's, where each node is a diff of properties that gets * applied on top of its parent. Copying a pipeline creates an empty * diff and a child->parent relationship between the empty diff and * the source @pipeline, parent. * * Because of this internal graph design a single #CoglPipeline may * indirectly depend on a chain of ancestors to fully define all of * its properties. Because a node depends on its ancestors it normally * owns a reference to its parent to stop it from being freed. Also if * you try to modify a pipeline with children we internally use a * copy-on-write mechanism to ensure that you don't indirectly change * the properties those children. * * Weak pipelines avoid the use of copy-on-write to preserve the * integrity of weak dependants and instead weak dependants are * simply destroyed allowing the parent to be modified directly. Also * because weak pipelines don't own a reference to their parent they * won't stop the source @pipeline from being freed when the user * releases their reference on it. * * Because weak pipelines don't own a reference on their parent they * are the recommended mechanism for creating derived pipelines that you * want to cache as a private property of the original pipeline * because they won't result in a circular dependency. * * An example use case: * * Consider for example you are implementing a custom primitive that is * not compatible with certain source pipelines. To handle this you * implement a validation stage that given an arbitrary pipeline as * input will create a derived pipeline that is suitable for drawing * your primitive. * * Because you don't want to have to repeat this validation every time * the same incompatible pipeline is given as input you want to cache * the result as a private property of the original pipeline. If the * derived pipeline were created using cogl_pipeline_copy that would * create a circular dependency so the original pipeline can never be * freed. * * If you instead create a weak copy you won't stop the original pipeline * from being freed if it's no longer needed, and you will instead simply * be notified that your weak pipeline has been destroyed. * * This is the recommended coding pattern for validating an input * pipeline and caching a derived result: * |[ * static CoglUserDataKey _cogl_my_cache_key; * * typedef struct { * CoglPipeline *validated_source; * } MyValidatedMaterialCache; * * static void * destroy_cache_cb (CoglObject *object, void *user_data) * { * g_slice_free (MyValidatedMaterialCache, user_data); * } * * static void * invalidate_cache_cb (CoglPipeline *destroyed, void *user_data) * { * MyValidatedMaterialCache *cache = user_data; * cogl_object_unref (cache->validated_source); * cache->validated_source = NULL; * } * * static CoglPipeline * * get_validated_pipeline (CoglPipeline *source) * { * MyValidatedMaterialCache *cache = * cogl_object_get_user_data (COGL_OBJECT (source), * &_cogl_my_cache_key); * if (G_UNLIKELY (cache == NULL)) * { * cache = g_slice_new (MyValidatedMaterialCache); * cogl_object_set_user_data (COGL_OBJECT (source), * &_cogl_my_cache_key, * cache, destroy_cache_cb); * cache->validated_source = source; * } * * if (G_UNLIKELY (cache->validated_source == NULL)) * { * cache->validated_source = source; * * / * Start validating source... * / * * / * If you find you need to change something... * / * if (cache->validated_source == source) * cache->validated_source = * cogl_pipeline_weak_copy (source, * invalidate_cache_cb, * cache); * * / * Modify cache->validated_source * / * } * * return cache->validated_source; * } * ]| */ CoglPipeline * _cogl_pipeline_weak_copy (CoglPipeline *pipeline, CoglPipelineDestroyCallback callback, void *user_data); void _cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend); CoglPipeline * _cogl_pipeline_get_parent (CoglPipeline *pipeline); void _cogl_pipeline_get_colorubv (CoglPipeline *pipeline, uint8_t *color); /* XXX: At some point it could be good for this to accept a mask of * the state groups we are interested in comparing since we can * probably use that information in a number situations to reduce * the work we do. */ unsigned long _cogl_pipeline_compare_differences (CoglPipeline *pipeline0, CoglPipeline *pipeline1); CoglBool _cogl_pipeline_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1, unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags); unsigned int _cogl_pipeline_hash (CoglPipeline *pipeline, unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags); /* Makes a copy of the given pipeline that is a child of the root * pipeline rather than a child of the source pipeline. That way the * new pipeline won't hold a reference to the source pipeline. The * differences specified in @differences and @layer_differences are * copied across and all other state is left with the default * values. */ CoglPipeline * _cogl_pipeline_deep_copy (CoglPipeline *pipeline, unsigned long differences, unsigned long layer_differences); CoglPipeline * _cogl_pipeline_journal_ref (CoglPipeline *pipeline); void _cogl_pipeline_journal_unref (CoglPipeline *pipeline); const CoglMatrix * _cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index); void _cogl_pipeline_texture_storage_change_notify (CoglTexture *texture); void _cogl_pipeline_apply_legacy_state (CoglPipeline *pipeline); void _cogl_pipeline_apply_overrides (CoglPipeline *pipeline, CoglPipelineFlushOptions *options); CoglPipelineBlendEnable _cogl_pipeline_get_blend_enabled (CoglPipeline *pipeline); void _cogl_pipeline_set_blend_enabled (CoglPipeline *pipeline, CoglPipelineBlendEnable enable); CoglBool _cogl_pipeline_get_fog_enabled (CoglPipeline *pipeline); #ifdef COGL_DEBUG_ENABLED void _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline, const char *breadcrumb); #endif unsigned long _cogl_pipeline_get_age (CoglPipeline *pipeline); CoglPipeline * _cogl_pipeline_get_authority (CoglPipeline *pipeline, unsigned long difference); void _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline, CoglPipelineLayer *layer, CoglBool inc_n_layers); void _cogl_pipeline_remove_layer_difference (CoglPipeline *pipeline, CoglPipelineLayer *layer, CoglBool dec_n_layers); CoglPipeline * _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline, CoglPipelineState pipeline_state, CoglPipelineLayerState layer_state); void _cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline, int layer_index, float *constant); void _cogl_pipeline_prune_to_n_layers (CoglPipeline *pipeline, int n); /* * API to support the deprecate cogl_pipeline_layer_xyz functions... */ const GList * _cogl_pipeline_get_layers (CoglPipeline *pipeline); typedef CoglBool (*CoglPipelineInternalLayerCallback) (CoglPipelineLayer *layer, void *user_data); void _cogl_pipeline_foreach_layer_internal (CoglPipeline *pipeline, CoglPipelineInternalLayerCallback callback, void *user_data); CoglBool _cogl_pipeline_layer_numbers_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1); CoglBool _cogl_pipeline_layer_and_unit_numbers_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1); CoglBool _cogl_pipeline_need_texture_combine_separate (CoglPipelineLayer *combine_authority); void _cogl_pipeline_init_state_hash_functions (void); void _cogl_pipeline_init_layer_state_hash_functions (void); CoglPipelineState _cogl_pipeline_get_state_for_vertex_codegen (CoglContext *context); CoglPipelineLayerState _cogl_pipeline_get_layer_state_for_fragment_codegen (CoglContext *context); CoglPipelineState _cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context); #endif /* __COGL_PIPELINE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-xlib-renderer.h0000664000175000017500000002344014211404421020644 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #if !defined(__COGL_XLIB_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_XLIB_RENDERER_H__ #define __COGL_XLIB_RENDERER_H__ #include #include /* NB: this is a top-level header that can be included directly but we * want to be careful not to define __COGL_H_INSIDE__ when this is * included internally while building Cogl itself since * __COGL_H_INSIDE__ is used in headers to guard public vs private api * definitions */ #ifndef COGL_COMPILATION /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_XLIB_RENDERER_H_MUST_UNDEF_COGL_H_INSIDE_COGL_XLIB_RENDERER_ #endif #endif /* COGL_COMPILATION */ #include COGL_BEGIN_DECLS /** * cogl_xlib_renderer_handle_event: (skip) * @renderer: a #CoglRenderer * @event: pointer to an XEvent structure * * This function processes a single event; it can be used to hook into * external event retrieval (for example that done by Clutter or * GDK). * * Return value: #CoglFilterReturn. %COGL_FILTER_REMOVE indicates that * Cogl has internally handled the event and the caller should do no * further processing. %COGL_FILTER_CONTINUE indicates that Cogl is * either not interested in the event, or has used the event to update * internal state without taking any exclusive action. */ CoglFilterReturn cogl_xlib_renderer_handle_event (CoglRenderer *renderer, XEvent *event); /* * CoglXlibFilterFunc: * @event: pointer to an XEvent structure * @data: the data that was given when the filter was added * * A callback function that can be registered with * cogl_xlib_renderer_add_filter(). The function should return * %COGL_FILTER_REMOVE if it wants to prevent further processing or * %COGL_FILTER_CONTINUE otherwise. */ typedef CoglFilterReturn (* CoglXlibFilterFunc) (XEvent *event, void *data); /** * cogl_xlib_renderer_add_filter: (skip) * @renderer: a #CoglRenderer * @func: the callback function * @data: user data passed to @func when called * * Adds a callback function that will receive all native events. The * function can stop further processing of the event by return * %COGL_FILTER_REMOVE. */ void cogl_xlib_renderer_add_filter (CoglRenderer *renderer, CoglXlibFilterFunc func, void *data); /** * cogl_xlib_renderer_remove_filter: (skip) * @renderer: a #CoglRenderer * @func: the callback function * @data: user data given when the callback was installed * * Removes a callback that was previously added with * cogl_xlib_renderer_add_filter(). */ void cogl_xlib_renderer_remove_filter (CoglRenderer *renderer, CoglXlibFilterFunc func, void *data); /** * cogl_xlib_renderer_get_foreign_display: (skip) * @renderer: a #CoglRenderer * * Return value: the foreign Xlib display that will be used by any Xlib based * winsys backend. The display needs to be set with * cogl_xlib_renderer_set_foreign_display() before this function is called. */ Display * cogl_xlib_renderer_get_foreign_display (CoglRenderer *renderer); /** * cogl_xlib_renderer_set_foreign_display: (skip) * @renderer: a #CoglRenderer * * Sets a foreign Xlib display that Cogl will use for and Xlib based winsys * backend. * * Note that calling this function will automatically call * cogl_xlib_renderer_set_event_retrieval_enabled() to disable Cogl's * event retrieval. Cogl still needs to see all of the X events so the * application should also use cogl_xlib_renderer_handle_event() if it * uses this function. */ void cogl_xlib_renderer_set_foreign_display (CoglRenderer *renderer, Display *display); /** * cogl_xlib_renderer_set_event_retrieval_enabled: (skip) * @renderer: a #CoglRenderer * @enable: The new value * * Sets whether Cogl should automatically retrieve events from the X * display. This defaults to %TRUE unless * cogl_xlib_renderer_set_foreign_display() is called. It can be set * to %FALSE if the application wants to handle its own event * retrieval. Note that Cogl still needs to see all of the X events to * function properly so the application should call * cogl_xlib_renderer_handle_event() for each event if it disables * automatic event retrieval. * * Since: 1.10 * Stability: unstable */ void cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, CoglBool enable); /** * cogl_xlib_renderer_set_threaded_swap_wait_enabled: (skip) * @renderer: a #CoglRenderer * @enable: The new value * * Sets whether Cogl is allowed to use a separate threaded to wait for the * completion of glXSwapBuffers() and call the frame callback for the * corresponding #CoglOnscreen. This is a way of emulating the * INTEL_swap_event extension, and will only ever be used if * INTEL_swap_event is not present; it will also only be used for * specific white-listed drivers that are known to work correctly with * multiple contexts sharing state between threads. * * The advantage of enabling this is that it will allow your main loop * to do other work while waiting for the system to be ready to draw * the next frame, instead of blocking in glXSwapBuffers(). A disadvantage * is that the driver will be prevented from buffering up multiple frames * even if it thinks that it would be advantageous. In general, this * will work best for something like a system compositor that is doing * simple drawing but handling lots of other complex tasks. * * If you enable this, you must call XInitThreads() before any other * X11 calls in your program. (See the documentation for XInitThreads()) * * Stability: unstable */ void cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer, CoglBool enable); /** * cogl_xlib_renderer_get_display: (skip) */ Display * cogl_xlib_renderer_get_display (CoglRenderer *renderer); /** * cogl_xlib_renderer_get_visual_info: (skip) */ XVisualInfo * cogl_xlib_renderer_get_visual_info (CoglRenderer *renderer); /** * cogl_xlib_renderer_request_reset_on_video_memory_purge: (skip) * @renderer: a #CoglRenderer * @enable: The new value * * Sets whether Cogl should make use of the * NV_robustness_video_memory_purge extension, if exposed by the * driver, by initializing the GLX context appropriately. * * The extension is only useful when running on certain versions of * the NVIDIA driver. Quoting from the spec: * * "The NVIDIA OpenGL driver architecture on Linux has a limitation: * resources located in video memory are not persistent across certain * events. VT switches, suspend/resume events, and mode switching * events may erase the contents of video memory. Any resource that * is located exclusively in video memory, such as framebuffer objects * (FBOs), will be lost." * * "This extension provides a way for applications to discover when video * memory content has been lost, so that the application can re-populate * the video memory content as necessary." * * "Any driver that exposes this extension is a driver that considers * video memory to be volatile. Once the driver stack has been * improved, the extension will no longer be exposed." * * cogl_get_graphics_reset_status() needs to be called at least once * every frame to find out if video memory was purged. * * Note that this doesn't cause Cogl to enable robust buffer access * but other context reset errors may still happen and be reported via * cogl_get_graphics_reset_status() if external factors cause the * driver to trigger them. * * This defaults to %FALSE and is effective only if called before * cogl_display_setup() . */ void cogl_xlib_renderer_request_reset_on_video_memory_purge (CoglRenderer *renderer, CoglBool enable); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_XLIB_RENDERER_H_MUST_UNDEF_COGL_H_INSIDE_COGL_XLIB_RENDERER_ #undef __COGL_H_INSIDE__ #undef __COGL_XLIB_RENDERER_H_MUST_UNDEF_COGL_H_INSIDE_COGL_XLIB_RENDERER_ #endif #endif /* __COGL_XLIB_RENDERER_H__ */ muffin-5.2.1/cogl/cogl/cogl-pipeline-layer-state.h0000664000175000017500000005367214211404421022151 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PIPELINE_LAYER_STATE_H__ #define __COGL_PIPELINE_LAYER_STATE_H__ #include #include #include #include COGL_BEGIN_DECLS /** * CoglPipelineFilter: * @COGL_PIPELINE_FILTER_NEAREST: Measuring in manhatten distance from the, * current pixel center, use the nearest texture texel * @COGL_PIPELINE_FILTER_LINEAR: Use the weighted average of the 4 texels * nearest the current pixel center * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose * texel size most closely matches the current pixel, and use the * %COGL_PIPELINE_FILTER_NEAREST criterion * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose * texel size most closely matches the current pixel, and use the * %COGL_PIPELINE_FILTER_LINEAR criterion * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels * whose texel size most closely matches the current pixel, use * the %COGL_PIPELINE_FILTER_NEAREST criterion on each one and take * their weighted average * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels * whose texel size most closely matches the current pixel, use * the %COGL_PIPELINE_FILTER_LINEAR criterion on each one and take * their weighted average * * Texture filtering is used whenever the current pixel maps either to more * than one texture element (texel) or less than one. These filter enums * correspond to different strategies used to come up with a pixel color, by * possibly referring to multiple neighbouring texels and taking a weighted * average or simply using the nearest texel. */ typedef enum { COGL_PIPELINE_FILTER_NEAREST = 0x2600, COGL_PIPELINE_FILTER_LINEAR = 0x2601, COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST = 0x2700, COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST = 0x2701, COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR = 0x2702, COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR = 0x2703 } CoglPipelineFilter; /* NB: these values come from the equivalents in gl.h */ /** * CoglPipelineWrapMode: * @COGL_PIPELINE_WRAP_MODE_REPEAT: The texture will be repeated. This * is useful for example to draw a tiled background. * @COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE: The coordinates outside the * range 0→1 will sample copies of the edge pixels of the * texture. This is useful to avoid artifacts if only one copy of * the texture is being rendered. * @COGL_PIPELINE_WRAP_MODE_AUTOMATIC: Cogl will try to automatically * decide which of the above two to use. For cogl_rectangle(), it * will use repeat mode if any of the texture coordinates are * outside the range 0→1, otherwise it will use clamp to edge. For * cogl_polygon() it will always use repeat mode. For * cogl_vertex_buffer_draw() it will use repeat mode except for * layers that have point sprite coordinate generation enabled. This * is the default value. * * The wrap mode specifies what happens when texture coordinates * outside the range 0→1 are used. Note that if the filter mode is * anything but %COGL_PIPELINE_FILTER_NEAREST then texels outside the * range 0→1 might be used even when the coordinate is exactly 0 or 1 * because OpenGL will try to sample neighbouring pixels. For example * if you are trying to render the full texture then you may get * artifacts around the edges when the pixels from the other side are * merged in if the wrap mode is set to repeat. * * Since: 2.0 */ /* GL_ALWAYS is just used here as a value that is known not to clash * with any valid GL wrap modes * * XXX: keep the values in sync with the CoglPipelineWrapModeInternal * enum so no conversion is actually needed. */ typedef enum { COGL_PIPELINE_WRAP_MODE_REPEAT = 0x2901, COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT = 0x8370, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE = 0x812F, COGL_PIPELINE_WRAP_MODE_AUTOMATIC = 0x0207 /* GL_ALWAYS */ } CoglPipelineWrapMode; /* NB: these values come from the equivalents in gl.h */ /** * cogl_pipeline_set_layer: * @pipeline: A #CoglPipeline object * @layer_index: the index of the layer * @texture: a #CoglTexture for the layer object * * In addition to the standard OpenGL lighting model a Cogl pipeline may have * one or more layers comprised of textures that can be blended together in * order, with a number of different texture combine modes. This function * defines a new texture layer. * * The index values of multiple layers do not have to be consecutive; it is * only their relative order that is important. * * The @texture parameter can also be %NULL in which case the pipeline * will use a default white texture. The type of the default texture * will be the same as whatever texture was last used for the pipeline * or %COGL_TEXTURE_TYPE_2D if none has been specified yet. To * explicitly specify the type of default texture required, use * cogl_pipeline_set_layer_null_texture() instead. * * In the future, we may define other types of pipeline layers, such * as purely GLSL based layers. * * Since: 2.0 * Stability: unstable */ void cogl_pipeline_set_layer_texture (CoglPipeline *pipeline, int layer_index, CoglTexture *texture); /** * cogl_pipeline_set_layer_null_texture: * @pipeline: A #CoglPipeline * @layer_index: The layer number to modify * @texture_type: The type of the default texture to use * * Sets the texture for this layer to be the default texture for the * given type. This is equivalent to calling * cogl_pipeline_set_layer_texture() with %NULL for the texture * argument except that you can also specify the type of default * texture to use. The default texture is a 1x1 pixel white texture. * * This function is mostly useful if you want to create a base * pipeline that you want to create multiple copies from using * cogl_pipeline_copy(). In that case this function can be used to * specify the texture type so that any pipeline copies can share the * internal texture type state for efficiency. * * Since: 1.10 * Stability: unstable */ void cogl_pipeline_set_layer_null_texture (CoglPipeline *pipeline, int layer_index, CoglTextureType texture_type); /** * cogl_pipeline_get_layer_texture: * @pipeline: A #CoglPipeline object * @layer_index: the index of the layer * * Return value: (transfer none): the texture that was set for the * given layer of the pipeline or %NULL if no texture was set. * Stability: unstable * Since: 1.10 */ CoglTexture * cogl_pipeline_get_layer_texture (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_remove_layer: * @pipeline: A #CoglPipeline object * @layer_index: Specifies the layer you want to remove * * This function removes a layer from your pipeline * Since: 1.10 * Stability: unstable */ void cogl_pipeline_remove_layer (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_set_layer_combine: * @pipeline: A #CoglPipeline object * @layer_index: Specifies the layer you want define a combine function for * @blend_string: A Cogl blend string * describing the desired texture combine function. * @error: A #CoglError that may report parse errors or lack of GPU/driver * support. May be %NULL, in which case a warning will be printed out if an * error is encountered. * * If not already familiar; you can refer * here for an overview of what blend * strings are and there syntax. * * These are all the functions available for texture combining: * * REPLACE(arg0) = arg0 * MODULATE(arg0, arg1) = arg0 x arg1 * ADD(arg0, arg1) = arg0 + arg1 * ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5 * INTERPOLATE(arg0, arg1, arg2) = arg0 x arg2 + arg1 x (1 - arg2) * SUBTRACT(arg0, arg1) = arg0 - arg1 * * * DOT3_RGB(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * * * * * DOT3_RGBA(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * * * * * Refer to the * color-source syntax for * describing the arguments. The valid source names for texture combining * are: * * * TEXTURE * Use the color from the current texture layer * * * TEXTURE_0, TEXTURE_1, etc * Use the color from the specified texture layer * * * CONSTANT * Use the color from the constant given with * cogl_pipeline_set_layer_combine_constant() * * * PRIMARY * Use the color of the pipeline as set with * cogl_pipeline_set_color() * * * PREVIOUS * Either use the texture color from the previous layer, or * if this is layer 0, use the color of the pipeline as set with * cogl_pipeline_set_color() * * * * * Layer Combine Examples * This is effectively what the default blending is: * * RGBA = MODULATE (PREVIOUS, TEXTURE) * * This could be used to cross-fade between two images, using * the alpha component of a constant as the interpolator. The constant * color is given by calling * cogl_pipeline_set_layer_combine_constant(). * * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A]) * * * * You can't give a multiplication factor for arguments as you can * with blending. * * Return value: %TRUE if the blend string was successfully parsed, and the * described texture combining is supported by the underlying driver and * or hardware. On failure, %FALSE is returned and @error is set * * Since: 2.0 * Stability: unstable */ CoglBool cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, int layer_index, const char *blend_string, CoglError **error); /** * cogl_pipeline_set_layer_combine_constant: * @pipeline: A #CoglPipeline object * @layer_index: Specifies the layer you want to specify a constant used * for texture combining * @constant: The constant color you want * * When you are using the 'CONSTANT' color source in a layer combine * description then you can use this function to define its value. * * Since: 2.0 * Stability: unstable */ void cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, int layer_index, const CoglColor *constant); /** * cogl_pipeline_set_layer_matrix: * @pipeline: A #CoglPipeline object * @layer_index: the index for the layer inside @pipeline * @matrix: the transformation matrix for the layer * * This function lets you set a matrix that can be used to e.g. translate * and rotate a single layer of a pipeline used to fill your geometry. * * Since: 1.10 * Stability: unstable */ void cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline, int layer_index, const CoglMatrix *matrix); /** * cogl_pipeline_get_n_layers: * @pipeline: A #CoglPipeline object * * Retrieves the number of layers defined for the given @pipeline * * Return value: the number of layers * * Since: 2.0 * Stability: unstable */ int cogl_pipeline_get_n_layers (CoglPipeline *pipeline); /** * cogl_pipeline_set_layer_filters: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * @min_filter: the filter used when scaling a texture down. * @mag_filter: the filter used when magnifying a texture. * * Changes the decimation and interpolation filters used when a texture is * drawn at other scales than 100%. * * It is an error to pass anything other than * %COGL_PIPELINE_FILTER_NEAREST or %COGL_PIPELINE_FILTER_LINEAR as * magnification filters since magnification doesn't ever need to * reference values stored in the mipmap chain. * * Since: 1.10 * Stability: unstable */ void cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, int layer_index, CoglPipelineFilter min_filter, CoglPipelineFilter mag_filter); /** * cogl_pipeline_get_layer_min_filter: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * * Retrieves the currently set minification #CoglPipelineFilter set on * the specified layer. The miniifcation filter determines how the * layer should be sampled when down-scaled. * * The default filter is %COGL_PIPELINE_FILTER_LINEAR but this can be * changed using cogl_pipeline_set_layer_filters(). * * Return value: The minification #CoglPipelineFilter for the * specified layer. * Since: 1.10 * Stability: unstable */ CoglPipelineFilter cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_get_layer_mag_filter: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * * Retrieves the currently set magnification #CoglPipelineFilter set on * the specified layer. The magnification filter determines how the * layer should be sampled when up-scaled. * * The default filter is %COGL_PIPELINE_FILTER_LINEAR but this can be * changed using cogl_pipeline_set_layer_filters(). * * Return value: The magnification #CoglPipelineFilter for the * specified layer. * Since: 1.10 * Stability: unstable */ CoglPipelineFilter cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_set_layer_point_sprite_coords_enabled: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * @enable: whether to enable point sprite coord generation. * @error: A return location for a CoglError, or NULL to ignore errors. * * When rendering points, if @enable is %TRUE then the texture * coordinates for this layer will be replaced with coordinates that * vary from 0.0 to 1.0 across the primitive. The top left of the * point will have the coordinates 0.0,0.0 and the bottom right will * have 1.0,1.0. If @enable is %FALSE then the coordinates will be * fixed for the entire point. * * This function will only work if %COGL_FEATURE_ID_POINT_SPRITE is * available. If the feature is not available then the function will * return %FALSE and set @error. * * Return value: %TRUE if the function succeeds, %FALSE otherwise. * Since: 2.0 * Stability: unstable */ CoglBool cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, int layer_index, CoglBool enable, CoglError **error); /** * cogl_pipeline_get_layer_point_sprite_coords_enabled: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to check. * * Gets whether point sprite coordinate generation is enabled for this * texture layer. * * Return value: whether the texture coordinates will be replaced with * point sprite coordinates. * * Since: 2.0 * Stability: unstable */ CoglBool cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_get_layer_wrap_mode_s: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * * Returns the wrap mode for the 's' coordinate of texture lookups on this * layer. * * Return value: the wrap mode for the 's' coordinate of texture lookups on * this layer. * * Since: 1.6 * Stability: unstable */ CoglPipelineWrapMode cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_set_layer_wrap_mode_s: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for the 's' coordinate of texture lookups on this layer. * * Since: 2.0 * Stability: unstable */ void cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode); /** * cogl_pipeline_get_layer_wrap_mode_t: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * * Returns the wrap mode for the 't' coordinate of texture lookups on this * layer. * * Return value: the wrap mode for the 't' coordinate of texture lookups on * this layer. * * Since: 1.6 * Stability: unstable */ CoglPipelineWrapMode cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_set_layer_wrap_mode_t: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for the 't' coordinate of texture lookups on this layer. * * Since: 2.0 * Stability: unstable */ void cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode); /** * cogl_pipeline_get_layer_wrap_mode_p: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * * Returns the wrap mode for the 'p' coordinate of texture lookups on this * layer. * * Return value: the wrap mode for the 'p' coordinate of texture lookups on * this layer. * * Since: 1.6 * Stability: unstable */ CoglPipelineWrapMode cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index); /** * cogl_pipeline_set_layer_wrap_mode_p: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for the 'p' coordinate of texture lookups on * this layer. 'p' is the third coordinate. * * Since: 2.0 * Stability: unstable */ void cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode); /** * cogl_pipeline_set_layer_wrap_mode: * @pipeline: A #CoglPipeline object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for all three coordinates of texture lookups on * this layer. This is equivalent to calling * cogl_pipeline_set_layer_wrap_mode_s(), * cogl_pipeline_set_layer_wrap_mode_t() and * cogl_pipeline_set_layer_wrap_mode_p() separately. * * Since: 2.0 * Stability: unstable */ void cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode); /** * cogl_pipeline_add_layer_snippet: * @pipeline: A #CoglPipeline * @layer: The layer to hook the snippet to * @snippet: A #CoglSnippet * * Adds a shader snippet that will hook on to the given layer of the * pipeline. The exact part of the pipeline that the snippet wraps * around depends on the hook that is given to * cogl_snippet_new(). Note that some hooks can't be used with a layer * and need to be added with cogl_pipeline_add_snippet() instead. * * Since: 1.10 * Stability: Unstable */ void cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline, int layer, CoglSnippet *snippet); COGL_END_DECLS #endif /* __COGL_PIPELINE_LAYER_STATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-gles2.h0000664000175000017500000003355714211404421017130 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Tomeu Vizoso * Robert Bragg * */ #ifndef __COGL_GLES2_H__ #define __COGL_GLES2_H__ /* NB: cogl-gles2.h is a top-level header that can be included directly * but we want to be careful not to define __COGL_H_INSIDE__ when this * is included internally while building Cogl itself since * __COGL_H_INSIDE__ is used in headers to guard public vs private * api definitions */ #ifndef COGL_COMPILATION /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_GLES2__ #endif #endif /* COGL_COMPILATION */ #include #include #include #include #include /* CoglGLES2Vtable depends on GLES 2.0 typedefs being available but we * want to be careful that the public api doesn't expose arbitrary * system GL headers as part of the Cogl API so although when building * internally we consistently refer to the system headers to avoid * conflicts we only expose the minimal set of GLES 2.0 types and enums * publicly. */ #if defined(COGL_COMPILATION) || defined(COGL_ENABLE_MUFFIN_API) #include "cogl-gl-header.h" #else #include #endif COGL_BEGIN_DECLS /** * SECTION:cogl-gles2 * @short_description: A portable api to access OpenGLES 2.0 * * Cogl provides portable access to the OpenGLES api through a single * library that is able to smooth over inconsistencies between the * different vendor drivers for OpenGLES in a single place. * * The api is designed to allow Cogl to transparently implement the * api on top of other drivers, such as OpenGL, D3D or on Cogl's own * drawing api so even if your platform doesn't come with an * OpenGLES 2.0 api Cogl may still be able to expose the api to your * application. * * Since Cogl is a library and not an api specification it is possible * to add OpenGLES 2.0 api features to Cogl which can immidiately * benefit developers regardless of what platform they are running on. * * With this api it's possible to re-use existing OpenGLES 2.0 code * within applications that are rendering with the Cogl API and also * it's possible for applications that render using OpenGLES 2.0 to * incorporate content rendered with Cogl. * * Applications can check for OpenGLES 2.0 api support by checking for * %COGL_FEATURE_ID_GLES2_CONTEXT support with cogl_has_feature(). * * Since: 1.12 * Stability: unstable */ /** * CoglGLES2Context: * * Represents an OpenGLES 2.0 api context used as a sandbox for * OpenGLES 2.0 state. This is comparable to an EGLContext for those * who have used OpenGLES 2.0 with EGL before. * * Since: 1.12 * Stability: unstable */ typedef struct _CoglGLES2Context CoglGLES2Context; /** * CoglGLES2Vtable: * * Provides function pointers for the full OpenGLES 2.0 api. The * api must be accessed this way and not by directly calling * symbols of any system OpenGLES 2.0 api. * * Since: 1.12 * Stability: unstable */ typedef struct _CoglGLES2Vtable CoglGLES2Vtable; struct _CoglGLES2Vtable { /*< private >*/ #define COGL_EXT_BEGIN(name, \ min_gl_major, min_gl_minor, \ gles_availability, \ extension_suffixes, extension_names) #define COGL_EXT_FUNCTION(ret, name, args) \ ret (* name) args; #define COGL_EXT_END() #include #include #undef COGL_EXT_BEGIN #undef COGL_EXT_FUNCTION #undef COGL_EXT_END }; /** * cogl_gles2_context_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_gles2_context_get_gtype (void); uint32_t _cogl_gles2_context_error_quark (void); /** * COGL_GLES2_CONTEXT_ERROR: * * An error domain for runtime exceptions relating to the * cogl_gles2_context api. * * Since: 2.0 * Stability: unstable */ #define COGL_GLES2_CONTEXT_ERROR (_cogl_gles2_context_error_quark ()) /** * CoglGLES2ContextError: * @COGL_GLES2_CONTEXT_ERROR_UNSUPPORTED: Creating GLES2 contexts * isn't supported. Applications should use cogl_has_feature() to * check for the %COGL_FEATURE_ID_GLES2_CONTEXT. * @COGL_GLES2_CONTEXT_ERROR_DRIVER: An underlying driver error * occured. * * Error codes that relate to the cogl_gles2_context api. */ typedef enum { /*< prefix=COGL_GLES2_CONTEXT_ERROR >*/ COGL_GLES2_CONTEXT_ERROR_UNSUPPORTED, COGL_GLES2_CONTEXT_ERROR_DRIVER } CoglGLES2ContextError; /** * cogl_gles2_context_new: * @ctx: A #CoglContext * @error: A pointer to a #CoglError for returning exceptions * * Allocates a new OpenGLES 2.0 context that can be used to render to * #CoglOffscreen framebuffers (Rendering to #CoglOnscreen * framebuffers is not currently supported). * * To actually access the OpenGLES 2.0 api itself you need to use * cogl_gles2_context_get_vtable(). You should not try to directly link * to and use the symbols provided by the a system OpenGLES 2.0 * driver. * * Once you have allocated an OpenGLES 2.0 context you can make it * current using cogl_push_gles2_context(). For those familiar with * using the EGL api, this serves a similar purpose to eglMakeCurrent. * * Before using this api applications can check for OpenGLES 2.0 * api support by checking for %COGL_FEATURE_ID_GLES2_CONTEXT support * with cogl_has_feature(). This function will return %FALSE and * return an %COGL_GLES2_CONTEXT_ERROR_UNSUPPORTED error if the * feature isn't available. * * Since: 2.0 * Return value: A newly allocated #CoglGLES2Context or %NULL if there * was an error and @error will be updated in that case. * Stability: unstable */ CoglGLES2Context * cogl_gles2_context_new (CoglContext *ctx, CoglError **error); /** * cogl_gles2_context_get_vtable: * @gles2_ctx: A #CoglGLES2Context allocated with * cogl_gles2_context_new() * * Queries the OpenGLES 2.0 api function pointers that should be * used for rendering with the given @gles2_ctx. * * You should not try to directly link to and use the symbols * provided by any system OpenGLES 2.0 driver. * * Since: 2.0 * Return value: A pointer to a #CoglGLES2Vtable providing pointers * to functions for the full OpenGLES 2.0 api. * Stability: unstable */ const CoglGLES2Vtable * cogl_gles2_context_get_vtable (CoglGLES2Context *gles2_ctx); /** * cogl_push_gles2_context: * @ctx: A #CoglContext * @gles2_ctx: A #CoglGLES2Context allocated with * cogl_gles2_context_new() * @read_buffer: A #CoglFramebuffer to access to read operations * such as glReadPixels. (must be a #CoglOffscreen * framebuffer currently) * @write_buffer: A #CoglFramebuffer to access for drawing operations * such as glDrawArrays. (must be a #CoglOffscreen * framebuffer currently) * @error: A pointer to a #CoglError for returning exceptions * * Pushes the given @gles2_ctx onto a stack associated with @ctx so * that the OpenGLES 2.0 api can be used instead of the Cogl * rendering apis to read and write to the specified framebuffers. * * Usage of the api available through a #CoglGLES2Vtable is only * allowed between cogl_push_gles2_context() and * cogl_pop_gles2_context() calls. * * If there is a runtime problem with switching over to the given * @gles2_ctx then this function will return %FALSE and return * an error through @error. * * Since: 2.0 * Return value: %TRUE if operation was successfull or %FALSE * otherwise and @error will be updated. * Stability: unstable */ CoglBool cogl_push_gles2_context (CoglContext *ctx, CoglGLES2Context *gles2_ctx, CoglFramebuffer *read_buffer, CoglFramebuffer *write_buffer, CoglError **error); /** * cogl_pop_gles2_context: * @ctx: A #CoglContext * * Restores the previously active #CoglGLES2Context if there * were nested calls to cogl_push_gles2_context() or otherwise * restores the ability to render with the Cogl api instead * of OpenGLES 2.0. * * The behaviour is undefined if calls to cogl_pop_gles2_context() * are not balenced with the number of corresponding calls to * cogl_push_gles2_context(). * * Since: 2.0 * Stability: unstable */ void cogl_pop_gles2_context (CoglContext *ctx); /** * cogl_gles2_get_current_vtable: * * Returns the OpenGL ES 2.0 api vtable for the currently pushed * #CoglGLES2Context (last pushed with cogl_push_gles2_context()) or * %NULL if no #CoglGLES2Context has been pushed. * * Return value: The #CoglGLES2Vtable for the currently pushed * #CoglGLES2Context or %NULL if none has been pushed. * Since: 2.0 * Stability: unstable */ CoglGLES2Vtable * cogl_gles2_get_current_vtable (void); /** * cogl_gles2_texture_2d_new_from_handle: * @ctx: A #CoglContext * @gles2_ctx: A #CoglGLES2Context allocated with * cogl_gles2_context_new() * @handle: An OpenGL ES 2.0 texture handle created with * glGenTextures() * @width: Width of the texture to allocate * @height: Height of the texture to allocate * @format: The format of the texture * * Creates a #CoglTexture2D from an OpenGL ES 2.0 texture handle that * was created within the given @gles2_ctx via glGenTextures(). The * texture needs to have been associated with the GL_TEXTURE_2D target. * * This interface is only intended for sharing textures to read * from. The behaviour is undefined if the texture is modified using * the Cogl api. * * Applications should only pass this function handles that were * created via a #CoglGLES2Vtable or via libcogl-gles2 and not pass * handles created directly using the system's native libGLESv2 * api. * * Since: 2.0 * Stability: unstable */ CoglTexture2D * cogl_gles2_texture_2d_new_from_handle (CoglContext *ctx, CoglGLES2Context *gles2_ctx, unsigned int handle, int width, int height, CoglPixelFormat format); /** * cogl_gles2_texture_get_handle: * @texture: A #CoglTexture * @handle: A return location for an OpenGL ES 2.0 texture handle * @target: A return location for an OpenGL ES 2.0 texture target * * Gets an OpenGL ES 2.0 texture handle for a #CoglTexture that can * then be referenced by a #CoglGLES2Context. As well as returning * a texture handle the texture's target (such as GL_TEXTURE_2D) is * also returned. * * If the #CoglTexture can not be shared with a #CoglGLES2Context then * this function will return %FALSE. * * This api does not affect the lifetime of the CoglTexture and you * must take care not to reference the returned handle after the * original texture has been freed. * * This interface is only intended for sharing textures to read * from. The behaviour is undefined if the texture is modified by a * GLES2 context. * * This function will only return %TRUE for low-level * #CoglTextures such as #CoglTexture2D or #CoglTexture3D but * not for high level meta textures such as * #CoglTexture2DSliced * * The handle returned should not be passed directly to a system * OpenGL ES 2.0 library, the handle is only intended to be used via * a #CoglGLES2Vtable or via libcogl-gles2. * * Return value: %TRUE if a handle and target could be returned * otherwise %FALSE is returned. * Since: 2.0 * Stability: unstable */ CoglBool cogl_gles2_texture_get_handle (CoglTexture *texture, unsigned int *handle, unsigned int *target); /** * cogl_is_gles2_context: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglGLES2Context. * * Return value: %TRUE if the object references a #CoglGLES2Context * and %FALSE otherwise. * Since: 2.0 * Stability: unstable */ CoglBool cogl_is_gles2_context (void *object); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_GLES2__ #undef __COGL_H_INSIDE__ #undef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_GLES2__ #endif #endif /* __COGL_GLES2_H__ */ muffin-5.2.1/cogl/cogl/cogl-magazine-private.h0000664000175000017500000000426714211404421021353 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_MAGAZINE_PRIVATE_H__ #define __COGL_MAGAZINE_PRIVATE_H__ #include #include "cogl-memory-stack-private.h" typedef struct _CoglMagazineChunk CoglMagazineChunk; struct _CoglMagazineChunk { CoglMagazineChunk *next; }; typedef struct _CoglMagazine { size_t chunk_size; CoglMemoryStack *stack; CoglMagazineChunk *head; } CoglMagazine; CoglMagazine * _cogl_magazine_new (size_t chunk_size, int initial_chunk_count); static inline void * _cogl_magazine_chunk_alloc (CoglMagazine *magazine) { if (G_LIKELY (magazine->head)) { CoglMagazineChunk *chunk = magazine->head; magazine->head = chunk->next; return chunk; } else return _cogl_memory_stack_alloc (magazine->stack, magazine->chunk_size); } static inline void _cogl_magazine_chunk_free (CoglMagazine *magazine, void *data) { CoglMagazineChunk *chunk = data; chunk->next = magazine->head; magazine->head = chunk; } void _cogl_magazine_free (CoglMagazine *magazine); #endif /* __COGL_MAGAZINE_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-display.h0000664000175000017500000001650214211404421017550 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_DISPLAY_H__ #define __COGL_DISPLAY_H__ #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-display * @short_description: Common aspects of a display pipeline * * The basic intention for this object is to let the application * configure common display preferences before creating a context, and * there are a few different aspects to this... * * Firstly there are options directly relating to the physical display * pipeline that is currently being used including the digital to * analogue conversion hardware and the screens the user sees. * * Another aspect is that display options may constrain or affect how * onscreen framebuffers should later be configured. The original * rationale for the display object in fact was to let us handle GLX * and EGLs requirements that framebuffers must be "compatible" with * the config associated with the current context meaning we have to * force the user to describe how they would like to create their * onscreen windows before we can choose a suitable fbconfig and * create a GLContext. */ typedef struct _CoglDisplay CoglDisplay; #define COGL_DISPLAY(OBJECT) ((CoglDisplay *)OBJECT) /** * cogl_display_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_display_get_gtype (void); /** * cogl_display_new: * @renderer: A #CoglRenderer * @onscreen_template: A #CoglOnscreenTemplate * * Explicitly allocates a new #CoglDisplay object to encapsulate the * common state of the display pipeline that applies to the whole * application. * * Many applications don't need to explicitly use * cogl_display_new() and can just jump straight to cogl_context_new() * and pass a %NULL display argument so Cogl will automatically * connect and setup a renderer and display. * * A @display can only be made for a specific choice of renderer which * is why this takes the @renderer argument. * * A common use for explicitly allocating a display object is to * define a template for allocating onscreen framebuffers which is * what the @onscreen_template argument is for, or alternatively * you can use cogl_display_set_onscreen_template(). * * When a display is first allocated via cogl_display_new() it is in a * mutable configuration mode. It's designed this way so we can * extend the apis available for configuring a display without * requiring huge numbers of constructor arguments. * * When you have finished configuring a display object you can * optionally call cogl_display_setup() to explicitly apply the * configuration and check for errors. Alternaitvely you can pass the * display to cogl_context_new() and Cogl will implicitly apply your * configuration but if there are errors then the application will * abort with a message. For simple applications with no fallback * options then relying on the implicit setup can be fine. * * Return value: (transfer full): A newly allocated #CoglDisplay * object in a mutable configuration mode. * Since: 1.10 * Stability: unstable */ CoglDisplay * cogl_display_new (CoglRenderer *renderer, CoglOnscreenTemplate *onscreen_template); /** * cogl_display_get_renderer: * @display: a #CoglDisplay * * Queries the #CoglRenderer associated with the given @display. * * Return value: (transfer none): The associated #CoglRenderer * * Since: 1.10 * Stability: unstable */ CoglRenderer * cogl_display_get_renderer (CoglDisplay *display); /** * cogl_display_set_onscreen_template: * @display: a #CoglDisplay * @onscreen_template: A template for creating #CoglOnscreen framebuffers * * Specifies a template for creating #CoglOnscreen framebuffers. * * Depending on the system, the constraints for creating #CoglOnscreen * framebuffers need to be known before setting up a #CoglDisplay because the * final setup of the display may constrain how onscreen framebuffers may be * allocated. If Cogl knows how an application wants to allocate onscreen * framebuffers then it can try to make sure to setup the display accordingly. * * Since: 1.16 * Stability: unstable */ void cogl_display_set_onscreen_template (CoglDisplay *display, CoglOnscreenTemplate *onscreen_template); /** * cogl_display_setup: * @display: a #CoglDisplay * @error: return location for a #CoglError * * Explicitly sets up the given @display object. Use of this api is * optional since Cogl will internally setup the display if not done * explicitly. * * When a display is first allocated via cogl_display_new() it is in a * mutable configuration mode. This allows us to extend the apis * available for configuring a display without requiring huge numbers * of constructor arguments. * * Its possible to request a configuration that might not be * supportable on the current system and so this api provides a means * to apply the configuration explicitly but if it fails then an * exception will be returned so you can handle the error gracefully * and perhaps fall back to an alternative configuration. * * If you instead rely on Cogl implicitly calling cogl_display_setup() * for you then if there is an error with the configuration you won't * get an opportunity to handle that and the application may abort * with a message. For simple applications that don't have any * fallback options this behaviour may be fine. * * Return value: Returns %TRUE if there was no error, else it returns * %FALSE and returns an exception via @error. * Since: 1.10 * Stability: unstable */ CoglBool cogl_display_setup (CoglDisplay *display, CoglError **error); /** * cogl_is_display: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglDisplay. * * Return value: %TRUE if the object references a #CoglDisplay * and %FALSE otherwise. * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_display (void *object); COGL_END_DECLS #endif /* __COGL_DISPLAY_H__ */ muffin-5.2.1/cogl/cogl/cogl-poll.c0000664000175000017500000001565014211404421017047 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-poll.h" #include "cogl-poll-private.h" #include "cogl-winsys-private.h" #include "cogl-renderer-private.h" struct _CoglPollSource { int fd; CoglPollPrepareCallback prepare; CoglPollDispatchCallback dispatch; void *user_data; }; int cogl_poll_renderer_get_info (CoglRenderer *renderer, CoglPollFD **poll_fds, int *n_poll_fds, int64_t *timeout) { GList *l, *next; _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), 0); _COGL_RETURN_VAL_IF_FAIL (poll_fds != NULL, 0); _COGL_RETURN_VAL_IF_FAIL (n_poll_fds != NULL, 0); _COGL_RETURN_VAL_IF_FAIL (timeout != NULL, 0); *timeout = -1; if (!_cogl_list_empty (&renderer->idle_closures)) *timeout = 0; /* This loop needs to cope with the prepare callback removing its * own fd */ for (l = renderer->poll_sources; l; l = next) { CoglPollSource *source = l->data; next = l->next; if (source->prepare) { int64_t source_timeout = source->prepare (source->user_data); if (source_timeout >= 0 && (*timeout == -1 || *timeout > source_timeout)) *timeout = source_timeout; } } /* This is deliberately set after calling the prepare callbacks in * case one of them removes its fd */ *poll_fds = (void *)renderer->poll_fds->data; *n_poll_fds = renderer->poll_fds->len; return renderer->poll_fds_age; } void cogl_poll_renderer_dispatch (CoglRenderer *renderer, const CoglPollFD *poll_fds, int n_poll_fds) { GList *l, *next; _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); _cogl_closure_list_invoke_no_args (&renderer->idle_closures); /* This loop needs to cope with the dispatch callback removing its * own fd */ for (l = renderer->poll_sources; l; l = next) { CoglPollSource *source = l->data; int i; next = l->next; if (source->fd == -1) { source->dispatch (source->user_data, 0); continue; } for (i = 0; i < n_poll_fds; i++) { const CoglPollFD *pollfd = &poll_fds[i]; if (pollfd->fd == source->fd) { source->dispatch (source->user_data, pollfd->revents); break; } } } } static int find_pollfd (CoglRenderer *renderer, int fd) { int i; for (i = 0; i < renderer->poll_fds->len; i++) { CoglPollFD *pollfd = &g_array_index (renderer->poll_fds, CoglPollFD, i); if (pollfd->fd == fd) return i; } return -1; } void _cogl_poll_renderer_remove_fd (CoglRenderer *renderer, int fd) { int i = find_pollfd (renderer, fd); GList *l; if (i < 0) return; g_array_remove_index_fast (renderer->poll_fds, i); renderer->poll_fds_age++; for (l = renderer->poll_sources; l; l = l->next) { CoglPollSource *source = l->data; if (source->fd == fd) { renderer->poll_sources = g_list_delete_link (renderer->poll_sources, l); g_slice_free (CoglPollSource, source); break; } } } void _cogl_poll_renderer_modify_fd (CoglRenderer *renderer, int fd, CoglPollFDEvent events) { int fd_index = find_pollfd (renderer, fd); if (fd_index == -1) g_warn_if_reached (); else { CoglPollFD *pollfd = &g_array_index (renderer->poll_sources, CoglPollFD, fd_index); pollfd->events = events; renderer->poll_fds_age++; } } void _cogl_poll_renderer_add_fd (CoglRenderer *renderer, int fd, CoglPollFDEvent events, CoglPollPrepareCallback prepare, CoglPollDispatchCallback dispatch, void *user_data) { CoglPollFD pollfd = { fd, events }; CoglPollSource *source; _cogl_poll_renderer_remove_fd (renderer, fd); source = g_slice_new0 (CoglPollSource); source->fd = fd; source->prepare = prepare; source->dispatch = dispatch; source->user_data = user_data; renderer->poll_sources = g_list_prepend (renderer->poll_sources, source); g_array_append_val (renderer->poll_fds, pollfd); renderer->poll_fds_age++; } CoglPollSource * _cogl_poll_renderer_add_source (CoglRenderer *renderer, CoglPollPrepareCallback prepare, CoglPollDispatchCallback dispatch, void *user_data) { CoglPollSource *source; source = g_slice_new0 (CoglPollSource); source->fd = -1; source->prepare = prepare; source->dispatch = dispatch; source->user_data = user_data; renderer->poll_sources = g_list_prepend (renderer->poll_sources, source); return source; } void _cogl_poll_renderer_remove_source (CoglRenderer *renderer, CoglPollSource *source) { GList *l; for (l = renderer->poll_sources; l; l = l->next) { if (l->data == source) { renderer->poll_sources = g_list_delete_link (renderer->poll_sources, l); g_slice_free (CoglPollSource, source); break; } } } CoglClosure * _cogl_poll_renderer_add_idle (CoglRenderer *renderer, CoglIdleCallback idle_cb, void *user_data, CoglUserDataDestroyCallback destroy_cb) { return _cogl_closure_list_add (&renderer->idle_closures, idle_cb, user_data, destroy_cb); } muffin-5.2.1/cogl/cogl/cogl-profile.h0000664000175000017500000000427014211404421017542 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PROFILE_H__ #define __COGL_PROFILE_H__ #ifdef COGL_ENABLE_PROFILE #include extern UProfContext *_cogl_uprof_context; #define COGL_STATIC_TIMER UPROF_STATIC_TIMER #define COGL_STATIC_COUNTER UPROF_STATIC_COUNTER #define COGL_COUNTER_INC UPROF_COUNTER_INC #define COGL_COUNTER_DEC UPROF_COUNTER_DEC #define COGL_TIMER_START UPROF_TIMER_START #define COGL_TIMER_STOP UPROF_TIMER_STOP void _cogl_uprof_init (void); void _cogl_profile_trace_message (const char *format, ...); #else #define COGL_STATIC_TIMER(A,B,C,D,E) extern void _cogl_dummy_decl (void) #define COGL_STATIC_COUNTER(A,B,C,D) extern void _cogl_dummy_decl (void) #define COGL_COUNTER_INC(A,B) G_STMT_START{ (void)0; }G_STMT_END #define COGL_COUNTER_DEC(A,B) G_STMT_START{ (void)0; }G_STMT_END #define COGL_TIMER_START(A,B) G_STMT_START{ (void)0; }G_STMT_END #define COGL_TIMER_STOP(A,B) G_STMT_START{ (void)0; }G_STMT_END #define _cogl_profile_trace_message g_message #endif #endif /* __COGL_PROFILE_H__ */ muffin-5.2.1/cogl/cogl/cogl-bitmask.c0000664000175000017500000003223014211404421017524 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #include "cogl-config.h" #include #include #include #include "cogl-bitmask.h" #include "cogl-util.h" #include "cogl-flags.h" /* This code assumes that we can cast an unsigned long to a pointer and back without losing any data */ _COGL_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *), "This toolchain breaks Cogl's assumption that it can " "safely cast an unsigned long to a pointer without " "loosing data"); #define ARRAY_INDEX(bit_num) \ ((bit_num) / (sizeof (unsigned long) * 8)) #define BIT_INDEX(bit_num) \ ((bit_num) & (sizeof (unsigned long) * 8 - 1)) #define BIT_MASK(bit_num) \ (1UL << BIT_INDEX (bit_num)) CoglBool _cogl_bitmask_get_from_array (const CoglBitmask *bitmask, unsigned int bit_num) { GArray *array = (GArray *) *bitmask; /* If the index is off the end of the array then assume the bit is not set */ if (bit_num >= sizeof (unsigned long) * 8 * array->len) return FALSE; else return !!(g_array_index (array, unsigned long, ARRAY_INDEX (bit_num)) & BIT_MASK (bit_num)); } static void _cogl_bitmask_convert_to_array (CoglBitmask *bitmask) { GArray *array; /* Fetch the old values */ unsigned long old_values = _cogl_bitmask_to_bits (bitmask); array = g_array_new (FALSE, /* not zero-terminated */ TRUE, /* do clear new entries */ sizeof (unsigned long)); /* Copy the old values back in */ g_array_append_val (array, old_values); *bitmask = (struct _CoglBitmaskImaginaryType *) array; } void _cogl_bitmask_set_in_array (CoglBitmask *bitmask, unsigned int bit_num, CoglBool value) { GArray *array; unsigned int array_index; unsigned long new_value_mask; /* If the bitmask is not already an array then we need to allocate one */ if (!_cogl_bitmask_has_array (bitmask)) _cogl_bitmask_convert_to_array (bitmask); array = (GArray *) *bitmask; array_index = ARRAY_INDEX (bit_num); /* Grow the array if necessary. This will clear the new data */ if (array_index >= array->len) g_array_set_size (array, array_index + 1); new_value_mask = BIT_MASK (bit_num); if (value) g_array_index (array, unsigned long, array_index) |= new_value_mask; else g_array_index (array, unsigned long, array_index) &= ~new_value_mask; } void _cogl_bitmask_set_bits (CoglBitmask *dst, const CoglBitmask *src) { if (_cogl_bitmask_has_array (src)) { GArray *src_array, *dst_array; int i; if (!_cogl_bitmask_has_array (dst)) _cogl_bitmask_convert_to_array (dst); dst_array = (GArray *) *dst; src_array = (GArray *) *src; if (dst_array->len < src_array->len) g_array_set_size (dst_array, src_array->len); for (i = 0; i < src_array->len; i++) g_array_index (dst_array, unsigned long, i) |= g_array_index (src_array, unsigned long, i); } else if (_cogl_bitmask_has_array (dst)) { GArray *dst_array; dst_array = (GArray *) *dst; g_array_index (dst_array, unsigned long, 0) |= _cogl_bitmask_to_bits (src); } else *dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) | _cogl_bitmask_to_bits (src)); } void _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask, unsigned int n_bits, CoglBool value) { GArray *array; unsigned int array_index, bit_index; if (n_bits == 0) return; /* If the bitmask is not already an array then we need to allocate one */ if (!_cogl_bitmask_has_array (bitmask)) _cogl_bitmask_convert_to_array (bitmask); array = (GArray *) *bitmask; /* Get the array index of the top most value that will be touched */ array_index = ARRAY_INDEX (n_bits - 1); /* Get the bit index of the top most value */ bit_index = BIT_INDEX (n_bits - 1); /* Grow the array if necessary. This will clear the new data */ if (array_index >= array->len) g_array_set_size (array, array_index + 1); if (value) { /* Set the bits that are touching this index */ g_array_index (array, unsigned long, array_index) |= ~0UL >> (sizeof (unsigned long) * 8 - 1 - bit_index); /* Set all of the bits in any lesser indices */ memset (array->data, 0xff, sizeof (unsigned long) * array_index); } else { /* Clear the bits that are touching this index */ g_array_index (array, unsigned long, array_index) &= ~1UL << bit_index; /* Clear all of the bits in any lesser indices */ memset (array->data, 0x00, sizeof (unsigned long) * array_index); } } void _cogl_bitmask_xor_bits (CoglBitmask *dst, const CoglBitmask *src) { if (_cogl_bitmask_has_array (src)) { GArray *src_array, *dst_array; int i; if (!_cogl_bitmask_has_array (dst)) _cogl_bitmask_convert_to_array (dst); dst_array = (GArray *) *dst; src_array = (GArray *) *src; if (dst_array->len < src_array->len) g_array_set_size (dst_array, src_array->len); for (i = 0; i < src_array->len; i++) g_array_index (dst_array, unsigned long, i) ^= g_array_index (src_array, unsigned long, i); } else if (_cogl_bitmask_has_array (dst)) { GArray *dst_array; dst_array = (GArray *) *dst; g_array_index (dst_array, unsigned long, 0) ^= _cogl_bitmask_to_bits (src); } else *dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) ^ _cogl_bitmask_to_bits (src)); } void _cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask) { GArray *array = (GArray *) *bitmask; memset (array->data, 0, sizeof (unsigned long) * array->len); } void _cogl_bitmask_foreach (const CoglBitmask *bitmask, CoglBitmaskForeachFunc func, void *user_data) { if (_cogl_bitmask_has_array (bitmask)) { GArray *array = (GArray *) *bitmask; const unsigned long *values = &g_array_index (array, unsigned long, 0); int bit_num; COGL_FLAGS_FOREACH_START (values, array->len, bit_num) { if (!func (bit_num, user_data)) return; } COGL_FLAGS_FOREACH_END; } else { unsigned long mask = _cogl_bitmask_to_bits (bitmask); int bit_num; COGL_FLAGS_FOREACH_START (&mask, 1, bit_num) { if (!func (bit_num, user_data)) return; } COGL_FLAGS_FOREACH_END; } } void _cogl_bitmask_set_flags_array (const CoglBitmask *bitmask, unsigned long *flags) { const GArray *array = (const GArray *) *bitmask; int i; for (i = 0; i < array->len; i++) flags[i] |= g_array_index (array, unsigned long, i); } int _cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask) { const GArray *array = (const GArray *) *bitmask; int pop = 0; int i; for (i = 0; i < array->len; i++) pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i)); return pop; } int _cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask, int upto) { const GArray *array = (const GArray *) *bitmask; if (upto >= array->len * sizeof (unsigned long) * 8) return _cogl_bitmask_popcount_in_array (bitmask); else { unsigned long top_mask; int array_index = ARRAY_INDEX (upto); int bit_index = BIT_INDEX (upto); int pop = 0; int i; for (i = 0; i < array_index; i++) pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i)); top_mask = g_array_index (array, unsigned long, array_index); return pop + _cogl_util_popcountl (top_mask & ((1UL << bit_index) - 1)); } } typedef struct { int n_bits; int *bits; } CheckData; static CoglBool check_bit (int bit_num, void *user_data) { CheckData *data = user_data; int i; for (i = 0; i < data->n_bits; i++) if (data->bits[i] == bit_num) { data->bits[i] = -1; return TRUE; } g_assert_not_reached (); return TRUE; } static void verify_bits (const CoglBitmask *bitmask, ...) { CheckData data; va_list ap, ap_copy; int i; va_start (ap, bitmask); G_VA_COPY (ap_copy, ap); for (data.n_bits = 0; va_arg (ap, int) != -1; data.n_bits++); data.bits = alloca (data.n_bits * (sizeof (int))); G_VA_COPY (ap, ap_copy); for (i = 0; i < data.n_bits; i++) data.bits[i] = va_arg (ap, int); _cogl_bitmask_foreach (bitmask, check_bit, &data); for (i = 0; i < data.n_bits; i++) g_assert_cmpint (data.bits[i], ==, -1); g_assert_cmpint (_cogl_bitmask_popcount (bitmask), ==, data.n_bits); for (i = 0; i < 1024; i++) { int upto_popcount = 0; int j; G_VA_COPY (ap, ap_copy); for (j = 0; j < data.n_bits; j++) if (va_arg (ap, int) < i) upto_popcount++; g_assert_cmpint (_cogl_bitmask_popcount_upto (bitmask, i), ==, upto_popcount); G_VA_COPY (ap, ap_copy); for (j = 0; j < data.n_bits; j++) if (va_arg (ap, int) == i) break; g_assert_cmpint (_cogl_bitmask_get (bitmask, i), ==, (j < data.n_bits)); } } UNIT_TEST (check_bitmask_api, 0 /* no requirements */, 0 /* no failure cases */) { CoglBitmask bitmask; CoglBitmask other_bitmask; /* A dummy bit to make it use arrays sometimes */ int dummy_bit; int i; for (dummy_bit = -1; dummy_bit < 256; dummy_bit += 40) { _cogl_bitmask_init (&bitmask); _cogl_bitmask_init (&other_bitmask); if (dummy_bit != -1) _cogl_bitmask_set (&bitmask, dummy_bit, TRUE); verify_bits (&bitmask, dummy_bit, -1); _cogl_bitmask_set (&bitmask, 1, TRUE); _cogl_bitmask_set (&bitmask, 4, TRUE); _cogl_bitmask_set (&bitmask, 5, TRUE); verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1); _cogl_bitmask_set (&bitmask, 4, FALSE); verify_bits (&bitmask, 1, 5, dummy_bit, -1); _cogl_bitmask_clear_all (&bitmask); verify_bits (&bitmask, -1); if (dummy_bit != -1) _cogl_bitmask_set (&bitmask, dummy_bit, TRUE); verify_bits (&bitmask, dummy_bit, -1); _cogl_bitmask_set (&bitmask, 1, TRUE); _cogl_bitmask_set (&bitmask, 4, TRUE); _cogl_bitmask_set (&bitmask, 5, TRUE); _cogl_bitmask_set (&other_bitmask, 5, TRUE); _cogl_bitmask_set (&other_bitmask, 6, TRUE); _cogl_bitmask_set_bits (&bitmask, &other_bitmask); verify_bits (&bitmask, 1, 4, 5, 6, dummy_bit, -1); verify_bits (&other_bitmask, 5, 6, -1); _cogl_bitmask_set (&bitmask, 6, FALSE); verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1); _cogl_bitmask_xor_bits (&bitmask, &other_bitmask); verify_bits (&bitmask, 1, 4, 6, dummy_bit, -1); verify_bits (&other_bitmask, 5, 6, -1); _cogl_bitmask_set_range (&bitmask, 5, TRUE); verify_bits (&bitmask, 0, 1, 2, 3, 4, 6, dummy_bit, -1); _cogl_bitmask_set_range (&bitmask, 4, FALSE); verify_bits (&bitmask, 4, 6, dummy_bit, -1); _cogl_bitmask_destroy (&other_bitmask); _cogl_bitmask_destroy (&bitmask); } /* Extra tests for really long bitmasks */ _cogl_bitmask_init (&bitmask); _cogl_bitmask_set_range (&bitmask, 400, TRUE); _cogl_bitmask_init (&other_bitmask); _cogl_bitmask_set (&other_bitmask, 5, TRUE); _cogl_bitmask_xor_bits (&bitmask, &other_bitmask); for (i = 0; i < 1024; i++) g_assert_cmpint (_cogl_bitmask_get (&bitmask, i), ==, (i == 5 ? FALSE : i < 400 ? TRUE : FALSE)); _cogl_bitmask_set_range (&other_bitmask, 500, TRUE); _cogl_bitmask_set_bits (&bitmask, &other_bitmask); for (i = 0; i < 1024; i++) g_assert_cmpint (_cogl_bitmask_get (&bitmask, i), ==, (i < 500)); } muffin-5.2.1/cogl/cogl/cogl-magazine.c0000664000175000017500000000516614211404421017675 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * CoglMagazine provides a really light weight allocator for chunks * of memory with a pre-determined size. * * This allocator builds on CoglMemoryStack for making all initial * allocations but never frees memory back to the stack. * * Memory chunks that haven't been allocated yet are stored in a * singly linked, fifo, list. * * Allocating from a magazine is simply a question of popping an entry * from the head of the fifo list. If no entries are available then * instead allocate from the memory stack instead. * * When an entry is freed, it is put back into the fifo list for * re-use. * * No attempt is ever made to shrink the amount of memory associated * with a CoglMagazine. * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-memory-stack-private.h" #include "cogl-magazine-private.h" #include #define ROUND_UP_8(X) ((X + (8 - 1)) & ~(8 - 1)) CoglMagazine * _cogl_magazine_new (size_t chunk_size, int initial_chunk_count) { CoglMagazine *magazine = g_new0 (CoglMagazine, 1); chunk_size = MAX (chunk_size, sizeof (CoglMagazineChunk)); chunk_size = ROUND_UP_8 (chunk_size); magazine->chunk_size = chunk_size; magazine->stack = _cogl_memory_stack_new (chunk_size * initial_chunk_count); magazine->head = NULL; return magazine; } void _cogl_magazine_free (CoglMagazine *magazine) { _cogl_memory_stack_free (magazine->stack); free (magazine); } muffin-5.2.1/cogl/cogl/cogl-attribute-private.h0000664000175000017500000001012614211404421021552 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_ATTRIBUTE_PRIVATE_H #define __COGL_ATTRIBUTE_PRIVATE_H #include "cogl-object-private.h" #include "cogl-attribute.h" #include "cogl-framebuffer.h" #include "cogl-pipeline-private.h" #include "cogl-boxed-value.h" typedef enum { COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY, COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY, COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY, COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY, COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY, COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY } CoglAttributeNameID; typedef struct _CoglAttributeNameState { char *name; CoglAttributeNameID name_id; int name_index; CoglBool normalized_default; int layer_number; } CoglAttributeNameState; struct _CoglAttribute { CoglObject _parent; const CoglAttributeNameState *name_state; CoglBool normalized; CoglBool is_buffered; union { struct { CoglAttributeBuffer *attribute_buffer; size_t stride; size_t offset; int n_components; CoglAttributeType type; } buffered; struct { CoglContext *context; CoglBoxedValue boxed; } constant; } d; int immutable_ref; }; typedef enum { COGL_DRAW_SKIP_JOURNAL_FLUSH = 1 << 0, COGL_DRAW_SKIP_PIPELINE_VALIDATION = 1 << 1, COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH = 1 << 2, COGL_DRAW_SKIP_LEGACY_STATE = 1 << 3, /* By default the vertex attribute drawing code will assume that if there is a color attribute array enabled then we can't determine if the colors will be opaque so we need to enabling blending. However when drawing from the journal we know what the contents of the color array is so we can override this by passing this flag. */ COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE = 1 << 4, /* This forcibly disables the debug option to divert all drawing to * wireframes */ COGL_DRAW_SKIP_DEBUG_WIREFRAME = 1 << 5 } CoglDrawFlags; /* During CoglContext initialization we register the "cogl_color_in" * attribute name so it gets a global name_index of 0. We need to know * the name_index for "cogl_color_in" in * _cogl_pipeline_flush_gl_state() */ #define COGL_ATTRIBUTE_COLOR_NAME_INDEX 0 CoglAttributeNameState * _cogl_attribute_register_attribute_name (CoglContext *context, const char *name); CoglAttribute * _cogl_attribute_immutable_ref (CoglAttribute *attribute); void _cogl_attribute_immutable_unref (CoglAttribute *attribute); typedef struct { int unit; CoglPipelineFlushOptions options; uint32_t fallback_layers; } CoglFlushLayerState; void _cogl_flush_attributes_state (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes); int _cogl_attribute_get_n_components (CoglAttribute *attribute); #endif /* __COGL_ATTRIBUTE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl.h0000664000175000017500000001264014211404421016104 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_H__ #define __COGL_H__ #ifdef COGL_COMPILATION #error " shouldn't be included internally" #endif /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_MUST_UNDEF_COGL_H_INSIDE__ #endif /* We currently keep gtype integration delimited in case we eventually * want to split it out into a separate utility library when Cogl * becomes a standalone project. (like cairo-gobject.so) */ #define _COGL_SUPPORTS_GTYPE_INTEGRATION /* * API common to the 1.x and 2.0 api... */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 1.x only api... */ #if 0 #ifndef COGL_ENABLE_EXPERIMENTAL_2_0_API #warning #endif #endif /* It would be good to move these casts up into 1.x only api if we can * update Clutter, Mutter and GnomeShell to avoid redundant casts when * they enable the experimental api... */ #include #include #include #include #include #include #ifdef COGL_ENABLE_MUFFIN_API #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* XXX: This will definitly go away once all the Clutter winsys * code has been migrated down into Cogl! */ #include /* * API deprecations */ #include /* * Cogl Path api compatability * * The cogl_path_ api used to be part of the core Cogl api so for * compatability we include cogl-path.h via cogl.h * * Note: we have to make sure not to include cogl-path.h while * building core cogl or generating the Cogl .gir data because * cogl-path now gets built after cogl and some cogl-path headers are * only generated at build time... */ #if defined (COGL_HAS_COGL_PATH_SUPPORT) && \ !defined (COGL_COMPILATION) && \ !defined (COGL_GIR_SCANNING) #include #endif /** * SECTION:cogl * @short_description: General purpose API * * General utility functions for COGL. */ /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE__ #undef __COGL_H_INSIDE__ #undef __COGL_MUST_UNDEF_COGL_H_INSIDE__ #endif #endif /* __COGL_H__ */ muffin-5.2.1/cogl/cogl/cogl.c0000664000175000017500000005107714211404421016106 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #include "cogl-config.h" #include #include #include #define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_4 #include "cogl-i18n-private.h" #include "cogl-debug.h" #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-winsys-private.h" #include "cogl-framebuffer-private.h" #include "cogl-matrix-private.h" #include "cogl-journal-private.h" #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" #include "cogl-texture-driver.h" #include "cogl-attribute-private.h" #include "cogl-framebuffer-private.h" #include "cogl-renderer-private.h" #include "cogl-config-private.h" #include "cogl-private.h" #include "cogl1-context.h" #include "cogl-offscreen.h" #include "cogl-attribute-gl-private.h" #include "cogl-clutter.h" #include "deprecated/cogl-framebuffer-deprecated.h" CoglFuncPtr cogl_get_proc_address (const char* name) { _COGL_GET_CONTEXT (ctx, NULL); return _cogl_renderer_get_proc_address (ctx->display->renderer, name, FALSE); } CoglBool _cogl_check_extension (const char *name, char * const *ext) { while (*ext) if (!strcmp (name, *ext)) return TRUE; else ext++; return FALSE; } /* XXX: This has been deprecated as public API */ CoglBool cogl_check_extension (const char *name, const char *ext) { return cogl_clutter_check_extension (name, ext); } /* XXX: it's expected that we'll deprecated this with * cogl_framebuffer_clear at some point. */ void cogl_clear (const CoglColor *color, unsigned long buffers) { cogl_framebuffer_clear (cogl_get_draw_framebuffer (), buffers, color); } /* XXX: This API has been deprecated */ void cogl_set_depth_test_enabled (CoglBool setting) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->legacy_depth_test_enabled == setting) return; ctx->legacy_depth_test_enabled = setting; if (ctx->legacy_depth_test_enabled) ctx->legacy_state_set++; else ctx->legacy_state_set--; } /* XXX: This API has been deprecated */ CoglBool cogl_get_depth_test_enabled (void) { _COGL_GET_CONTEXT (ctx, FALSE); return ctx->legacy_depth_test_enabled; } void cogl_set_backface_culling_enabled (CoglBool setting) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->legacy_backface_culling_enabled == setting) return; ctx->legacy_backface_culling_enabled = setting; if (ctx->legacy_backface_culling_enabled) ctx->legacy_state_set++; else ctx->legacy_state_set--; } CoglBool cogl_get_backface_culling_enabled (void) { _COGL_GET_CONTEXT (ctx, FALSE); return ctx->legacy_backface_culling_enabled; } void cogl_set_source_color (const CoglColor *color) { CoglPipeline *pipeline; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (cogl_color_get_alpha_byte (color) == 0xff) { cogl_pipeline_set_color (ctx->opaque_color_pipeline, color); pipeline = ctx->opaque_color_pipeline; } else { CoglColor premultiplied = *color; cogl_color_premultiply (&premultiplied); cogl_pipeline_set_color (ctx->blended_color_pipeline, &premultiplied); pipeline = ctx->blended_color_pipeline; } cogl_set_source (pipeline); } void cogl_set_viewport (int x, int y, int width, int height) { CoglFramebuffer *framebuffer; _COGL_GET_CONTEXT (ctx, NO_RETVAL); framebuffer = cogl_get_draw_framebuffer (); cogl_framebuffer_set_viewport (framebuffer, x, y, width, height); } /* XXX: This should be deprecated, and we should expose a way to also * specify an x and y viewport offset */ void cogl_viewport (unsigned int width, unsigned int height) { cogl_set_viewport (0, 0, width, height); } CoglFeatureFlags cogl_get_features (void) { _COGL_GET_CONTEXT (ctx, 0); return ctx->feature_flags; } CoglBool cogl_features_available (CoglFeatureFlags features) { _COGL_GET_CONTEXT (ctx, 0); return (ctx->feature_flags & features) == features; } CoglBool cogl_has_feature (CoglContext *ctx, CoglFeatureID feature) { return COGL_FLAGS_GET (ctx->features, feature); } CoglBool cogl_has_features (CoglContext *ctx, ...) { va_list args; CoglFeatureID feature; va_start (args, ctx); while ((feature = va_arg (args, CoglFeatureID))) if (!cogl_has_feature (ctx, feature)) return FALSE; va_end (args); return TRUE; } void cogl_foreach_feature (CoglContext *ctx, CoglFeatureCallback callback, void *user_data) { int i; for (i = 0; i < _COGL_N_FEATURE_IDS; i++) if (COGL_FLAGS_GET (ctx->features, i)) callback (i, user_data); } /* XXX: This function should either be replaced with one returning * integers, or removed/deprecated and make the * _cogl_framebuffer_get_viewport* functions public. */ void cogl_get_viewport (float viewport[4]) { CoglFramebuffer *framebuffer; _COGL_GET_CONTEXT (ctx, NO_RETVAL); framebuffer = cogl_get_draw_framebuffer (); cogl_framebuffer_get_viewport4fv (framebuffer, viewport); } void cogl_get_bitmasks (int *red, int *green, int *blue, int *alpha) { CoglFramebuffer *framebuffer; framebuffer = cogl_get_draw_framebuffer (); if (red) *red = cogl_framebuffer_get_red_bits (framebuffer); if (green) *green = cogl_framebuffer_get_green_bits (framebuffer); if (blue) *blue = cogl_framebuffer_get_blue_bits (framebuffer); if (alpha) *alpha = cogl_framebuffer_get_alpha_bits (framebuffer); } void cogl_set_fog (const CoglColor *fog_color, CoglFogMode mode, float density, float z_near, float z_far) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->legacy_fog_state.enabled == FALSE) ctx->legacy_state_set++; ctx->legacy_fog_state.enabled = TRUE; ctx->legacy_fog_state.color = *fog_color; ctx->legacy_fog_state.mode = mode; ctx->legacy_fog_state.density = density; ctx->legacy_fog_state.z_near = z_near; ctx->legacy_fog_state.z_far = z_far; } void cogl_disable_fog (void) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->legacy_fog_state.enabled == TRUE) ctx->legacy_state_set--; ctx->legacy_fog_state.enabled = FALSE; } void cogl_flush (void) { GList *l; _COGL_GET_CONTEXT (ctx, NO_RETVAL); for (l = ctx->framebuffers; l; l = l->next) _cogl_framebuffer_flush_journal (l->data); } void cogl_read_pixels (int x, int y, int width, int height, CoglReadPixelsFlags source, CoglPixelFormat format, uint8_t *pixels) { int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); CoglBitmap *bitmap; _COGL_GET_CONTEXT (ctx, NO_RETVAL); bitmap = cogl_bitmap_new_for_data (ctx, width, height, format, bpp * width, /* rowstride */ pixels); cogl_framebuffer_read_pixels_into_bitmap (_cogl_get_read_framebuffer (), x, y, source, bitmap); cogl_object_unref (bitmap); } void cogl_begin_gl (void) { CoglPipeline *pipeline; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->in_begin_gl_block) { static CoglBool shown = FALSE; if (!shown) g_warning ("You should not nest cogl_begin_gl/cogl_end_gl blocks"); shown = TRUE; return; } ctx->in_begin_gl_block = TRUE; /* Flush all batched primitives */ cogl_flush (); /* Flush framebuffer state, including clip state, modelview and * projection matrix state * * NB: _cogl_framebuffer_flush_state may disrupt various state (such * as the pipeline state) when flushing the clip stack, so should * always be done first when preparing to draw. */ _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (), _cogl_get_read_framebuffer (), COGL_FRAMEBUFFER_STATE_ALL); /* Setup the state for the current pipeline */ /* We considered flushing a specific, minimal pipeline here to try and * simplify the GL state, but decided to avoid special cases and second * guessing what would be actually helpful. * * A user should instead call cogl_set_source_color4ub() before * cogl_begin_gl() to simplify the state flushed. * * XXX: note defining n_tex_coord_attribs using * cogl_pipeline_get_n_layers is a hack, but the problem is that * n_tex_coord_attribs is usually defined when drawing a primitive * which isn't happening here. * * Maybe it would be more useful if this code did flush the * opaque_color_pipeline and then call into cogl-pipeline-opengl.c to then * restore all state for the material's backend back to default OpenGL * values. */ pipeline = cogl_get_source (); _cogl_pipeline_flush_gl_state (ctx, pipeline, cogl_get_draw_framebuffer (), FALSE, FALSE); /* Disable any cached vertex arrays */ _cogl_gl_disable_all_attributes (ctx); } void cogl_end_gl (void) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!ctx->in_begin_gl_block) { static CoglBool shown = FALSE; if (!shown) g_warning ("cogl_end_gl is being called before cogl_begin_gl"); shown = TRUE; return; } ctx->in_begin_gl_block = FALSE; } void cogl_push_matrix (void) { cogl_framebuffer_push_matrix (cogl_get_draw_framebuffer ()); } void cogl_pop_matrix (void) { cogl_framebuffer_pop_matrix (cogl_get_draw_framebuffer ()); } void cogl_scale (float x, float y, float z) { cogl_framebuffer_scale (cogl_get_draw_framebuffer (), x, y, z); } void cogl_translate (float x, float y, float z) { cogl_framebuffer_translate (cogl_get_draw_framebuffer (), x, y, z); } void cogl_rotate (float angle, float x, float y, float z) { cogl_framebuffer_rotate (cogl_get_draw_framebuffer (), angle, x, y, z); } void cogl_transform (const CoglMatrix *matrix) { cogl_framebuffer_transform (cogl_get_draw_framebuffer (), matrix); } void cogl_perspective (float fov_y, float aspect, float z_near, float z_far) { cogl_framebuffer_perspective (cogl_get_draw_framebuffer (), fov_y, aspect, z_near, z_far); } void cogl_frustum (float left, float right, float bottom, float top, float z_near, float z_far) { cogl_framebuffer_frustum (cogl_get_draw_framebuffer (), left, right, bottom, top, z_near, z_far); } void cogl_ortho (float left, float right, float bottom, float top, float near, float far) { cogl_framebuffer_orthographic (cogl_get_draw_framebuffer (), left, top, right, bottom, near, far); } void cogl_get_modelview_matrix (CoglMatrix *matrix) { cogl_framebuffer_get_modelview_matrix (cogl_get_draw_framebuffer (), matrix); } void cogl_set_modelview_matrix (CoglMatrix *matrix) { cogl_framebuffer_set_modelview_matrix (cogl_get_draw_framebuffer (), matrix); } void cogl_get_projection_matrix (CoglMatrix *matrix) { cogl_framebuffer_get_projection_matrix (cogl_get_draw_framebuffer (), matrix); } void cogl_set_projection_matrix (CoglMatrix *matrix) { cogl_framebuffer_set_projection_matrix (cogl_get_draw_framebuffer (), matrix); } uint32_t _cogl_driver_error_quark (void) { return g_quark_from_static_string ("cogl-driver-error-quark"); } typedef struct _CoglSourceState { CoglPipeline *pipeline; int push_count; /* If this is TRUE then the pipeline will be copied and the legacy state will be applied whenever the pipeline is used. This is necessary because some internal Cogl code expects to be able to push a temporary pipeline to put GL into a known state. For that to work it also needs to prevent applying the legacy state */ CoglBool enable_legacy; } CoglSourceState; static void _push_source_real (CoglPipeline *pipeline, CoglBool enable_legacy) { CoglSourceState *top = g_slice_new (CoglSourceState); _COGL_GET_CONTEXT (ctx, NO_RETVAL); top->pipeline = cogl_object_ref (pipeline); top->enable_legacy = enable_legacy; top->push_count = 1; ctx->source_stack = g_list_prepend (ctx->source_stack, top); } /* FIXME: This should take a context pointer for Cogl 2.0 Technically * we could make it so we can retrieve a context reference from the * pipeline, but this would not by symmetric with cogl_pop_source. */ void cogl_push_source (void *material_or_pipeline) { CoglPipeline *pipeline = COGL_PIPELINE (material_or_pipeline); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); _cogl_push_source (pipeline, TRUE); } /* This internal version of cogl_push_source is the same except it never applies the legacy state. Some parts of Cogl use this internally to set a temporary pipeline with a known state */ void _cogl_push_source (CoglPipeline *pipeline, CoglBool enable_legacy) { CoglSourceState *top; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); if (ctx->source_stack) { top = ctx->source_stack->data; if (top->pipeline == pipeline && top->enable_legacy == enable_legacy) { top->push_count++; return; } else _push_source_real (pipeline, enable_legacy); } else _push_source_real (pipeline, enable_legacy); } /* FIXME: This needs to take a context pointer for Cogl 2.0 */ void cogl_pop_source (void) { CoglSourceState *top; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (ctx->source_stack); top = ctx->source_stack->data; top->push_count--; if (top->push_count == 0) { cogl_object_unref (top->pipeline); g_slice_free (CoglSourceState, top); ctx->source_stack = g_list_delete_link (ctx->source_stack, ctx->source_stack); } } /* FIXME: This needs to take a context pointer for Cogl 2.0 */ void * cogl_get_source (void) { CoglSourceState *top; _COGL_GET_CONTEXT (ctx, NULL); _COGL_RETURN_VAL_IF_FAIL (ctx->source_stack, NULL); top = ctx->source_stack->data; return top->pipeline; } CoglBool _cogl_get_enable_legacy_state (void) { CoglSourceState *top; _COGL_GET_CONTEXT (ctx, FALSE); _COGL_RETURN_VAL_IF_FAIL (ctx->source_stack, FALSE); top = ctx->source_stack->data; return top->enable_legacy; } void cogl_set_source (void *material_or_pipeline) { CoglSourceState *top; CoglPipeline *pipeline = COGL_PIPELINE (material_or_pipeline); _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); _COGL_RETURN_IF_FAIL (ctx->source_stack); top = ctx->source_stack->data; if (top->pipeline == pipeline && top->enable_legacy) return; if (top->push_count == 1) { /* NB: top->pipeline may be only thing keeping pipeline * alive currently so ref pipeline first... */ cogl_object_ref (pipeline); cogl_object_unref (top->pipeline); top->pipeline = pipeline; top->enable_legacy = TRUE; } else { top->push_count--; cogl_push_source (pipeline); } } void cogl_set_source_texture (CoglTexture *texture) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (texture != NULL); cogl_pipeline_set_layer_texture (ctx->texture_pipeline, 0, texture); cogl_set_source (ctx->texture_pipeline); } void cogl_set_source_color4ub (uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { CoglColor c = { 0, }; cogl_color_init_from_4ub (&c, red, green, blue, alpha); cogl_set_source_color (&c); } void cogl_set_source_color4f (float red, float green, float blue, float alpha) { CoglColor c = { 0, }; cogl_color_init_from_4f (&c, red, green, blue, alpha); cogl_set_source_color (&c); } /* Scale from OpenGL normalized device coordinates (ranging from -1 to 1) * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with * (0,0) being top left. */ #define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \ ( ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x) ) /* Note: for Y we first flip all coordinates around the X axis while in * normalized device coodinates */ #define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \ ( ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y) ) /* Transform a homogeneous vertex position from model space to Cogl * window coordinates (with 0,0 being top left) */ void _cogl_transform_point (const CoglMatrix *matrix_mv, const CoglMatrix *matrix_p, const float *viewport, float *x, float *y) { float z = 0; float w = 1; /* Apply the modelview matrix transform */ cogl_matrix_transform_point (matrix_mv, x, y, &z, &w); /* Apply the projection matrix transform */ cogl_matrix_transform_point (matrix_p, x, y, &z, &w); /* Perform perspective division */ *x /= w; *y /= w; /* Apply viewport transform */ *x = VIEWPORT_TRANSFORM_X (*x, viewport[0], viewport[2]); *y = VIEWPORT_TRANSFORM_Y (*y, viewport[1], viewport[3]); } #undef VIEWPORT_TRANSFORM_X #undef VIEWPORT_TRANSFORM_Y uint32_t _cogl_system_error_quark (void) { return g_quark_from_static_string ("cogl-system-error-quark"); } void _cogl_init (void) { static CoglBool initialized = FALSE; if (initialized == FALSE) { #if !GLIB_CHECK_VERSION (2, 36, 0) g_type_init (); #endif _cogl_config_read (); _cogl_debug_check_environment (); initialized = TRUE; } } /* * Returns the number of bytes-per-pixel of a given format. The bpp * can be extracted from the least significant nibble of the pixel * format (see CoglPixelFormat). * * The mapping is the following (see discussion on bug #660188): * * 0 = undefined * 1, 8 = 1 bpp (e.g. A_8, G_8) * 2 = 3 bpp, aligned (e.g. 888) * 3 = 4 bpp, aligned (e.g. 8888) * 4-6 = 2 bpp, not aligned (e.g. 565, 4444, 5551) * 7 = undefined yuv * 9 = 2 bpp, aligned * 10 = undefined * 11 = undefined * 12 = 3 bpp, not aligned * 13 = 4 bpp, not aligned (e.g. 2101010) * 14-15 = undefined */ int _cogl_pixel_format_get_bytes_per_pixel (CoglPixelFormat format) { int bpp_lut[] = { 0, 1, 3, 4, 2, 2, 2, 0, 1, 2, 0, 0, 3, 4, 0, 0 }; return bpp_lut [format & 0xf]; } /* Note: this also refers to the mapping defined above for * _cogl_pixel_format_get_bytes_per_pixel() */ CoglBool _cogl_pixel_format_is_endian_dependant (CoglPixelFormat format) { int aligned_lut[] = { -1, 1, 1, 1, 0, 0, 0, -1, 1, 1, -1, -1, 0, 0, -1, -1}; int aligned = aligned_lut[format & 0xf]; _COGL_RETURN_VAL_IF_FAIL (aligned != -1, FALSE); /* NB: currently checking whether the format components are aligned * or not determines whether the format is endian dependent or not. * In the future though we might consider adding formats with * aligned components that are also endian independant. */ return aligned; } muffin-5.2.1/cogl/cogl/cogl-boxed-value.h0000664000175000017500000000644114211404421020317 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_BOXED_VALUE_H #define __COGL_BOXED_VALUE_H #include #include "cogl-context.h" typedef enum { COGL_BOXED_NONE, COGL_BOXED_INT, COGL_BOXED_FLOAT, COGL_BOXED_MATRIX } CoglBoxedType; typedef struct _CoglBoxedValue { CoglBoxedType type; int size, count; union { float float_value[4]; int int_value[4]; float matrix[16]; float *float_array; int *int_array; void *array; } v; } CoglBoxedValue; #define _cogl_boxed_value_init(bv) \ G_STMT_START { \ CoglBoxedValue *_bv = (bv); \ _bv->type = COGL_BOXED_NONE; \ _bv->count = 1; \ } G_STMT_END CoglBool _cogl_boxed_value_equal (const CoglBoxedValue *bva, const CoglBoxedValue *bvb); void _cogl_boxed_value_set_1f (CoglBoxedValue *bv, float value); void _cogl_boxed_value_set_1i (CoglBoxedValue *bv, int value); void _cogl_boxed_value_set_float (CoglBoxedValue *bv, int n_components, int count, const float *value); void _cogl_boxed_value_set_int (CoglBoxedValue *bv, int n_components, int count, const int *value); void _cogl_boxed_value_set_matrix (CoglBoxedValue *bv, int dimensions, int count, CoglBool transpose, const float *value); /* * _cogl_boxed_value_copy: * @dst: The destination boxed value * @src: The source boxed value * * This copies @src to @dst. It is assumed that @dst is initialised. */ void _cogl_boxed_value_copy (CoglBoxedValue *dst, const CoglBoxedValue *src); void _cogl_boxed_value_destroy (CoglBoxedValue *bv); void _cogl_boxed_value_set_uniform (CoglContext *ctx, int location, const CoglBoxedValue *value); #endif /* __COGL_BOXED_VALUE_H */ muffin-5.2.1/cogl/cogl/cogl-defines.h.in0000664000175000017500000000313214211404421020120 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_DEFINES_H__ #define __COGL_DEFINES_H__ @COGL_DEFINES@ #define COGL_VERSION_MAJOR_INTERNAL 1 #define COGL_VERSION_MINOR_INTERNAL @COGL_1_MINOR_VERSION@ #define COGL_VERSION_MICRO_INTERNAL @COGL_1_MICRO_VERSION@ #define COGL_VERSION_STRING_INTERNAL "@COGL_1_VERSION@" #endif muffin-5.2.1/cogl/cogl/cogl-point-in-poly-private.h0000664000175000017500000000313314211404421022265 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_POINT_INT_POLYGON_PRIVATE_H #define __COGL_POINT_INT_POLYGON_PRIVATE_H #include COGL_BEGIN_DECLS int _cogl_util_point_in_screen_poly (float point_x, float point_y, void *vertices, size_t stride, int n_vertices); COGL_END_DECLS #endif /* __COGL_POINT_INT_POLYGON_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-index-buffer.c0000664000175000017500000000744414211404421020461 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-object-private.h" #include "cogl-indices.h" #include "cogl-indices-private.h" #include "cogl-context-private.h" #include "cogl-gtype-private.h" static void _cogl_index_buffer_free (CoglIndexBuffer *indices); COGL_BUFFER_DEFINE (IndexBuffer, index_buffer); COGL_GTYPE_DEFINE_CLASS (IndexBuffer, index_buffer); /* XXX: Unlike the wiki design this just takes a size. A single * indices buffer should be able to contain multiple ranges of indices * which the wiki design doesn't currently consider. */ CoglIndexBuffer * cogl_index_buffer_new (CoglContext *context, size_t bytes) { CoglIndexBuffer *indices = g_slice_new (CoglIndexBuffer); /* parent's constructor */ _cogl_buffer_initialize (COGL_BUFFER (indices), context, bytes, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER, COGL_BUFFER_USAGE_HINT_INDEX_BUFFER, COGL_BUFFER_UPDATE_HINT_STATIC); return _cogl_index_buffer_object_new (indices); } static void _cogl_index_buffer_free (CoglIndexBuffer *indices) { /* parent's destructor */ _cogl_buffer_fini (COGL_BUFFER (indices)); g_slice_free (CoglIndexBuffer, indices); } /* XXX: do we want a convenience function like this as an alternative * to using cogl_buffer_set_data? The advantage of this is that we can * track meta data such as the indices type and max_index_value for a * range as part of the indices buffer. If we just leave people to use * cogl_buffer_set_data then we either need a way to specify the type * and max index value at draw time or we'll want a separate way to * declare the type and max value for a range after uploading the * data. * * XXX: I think in the end it'll be that CoglIndices are to * CoglIndexBuffers as CoglAttributes are to CoglAttributeBuffers. I.e * a CoglIndexBuffer is a lite subclass of CoglBuffer that simply * implies that the buffer will later be bound as indices but doesn't * track more detailed meta data. CoglIndices build on a * CoglIndexBuffer and define the type and max_index_value for some * sub-range of a CoglIndexBuffer. */ #if 0 void cogl_index_buffer_set_data (CoglIndexBuffer *indices, CoglIndicesType type, int max_index_value, size_t write_offset, void *user_indices, int n_indices) { GList *l; for (l = indices->ranges; l; l = l->next) { } cogl_buffer_set } #endif muffin-5.2.1/cogl/cogl/cogl-atlas-texture-private.h0000664000175000017500000000565414211404421022363 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef _COGL_ATLAS_TEXTURE_PRIVATE_H_ #define _COGL_ATLAS_TEXTURE_PRIVATE_H_ #include "cogl-object-private.h" #include "cogl-texture-private.h" #include "cogl-rectangle-map.h" #include "cogl-atlas.h" #include "cogl-atlas-texture.h" struct _CoglAtlasTexture { CoglTexture _parent; /* The format that the texture is in. This isn't necessarily the same format as the atlas texture because we can store pre-multiplied and non-pre-multiplied textures together */ CoglPixelFormat internal_format; /* The rectangle that was used to add this texture to the atlas. This includes the 1-pixel border */ CoglRectangleMapEntry rectangle; /* The atlas that this texture is in. If the texture is no longer in an atlas then this will be NULL. A reference is taken on the atlas by the texture (but not vice versa so there is no cycle) */ CoglAtlas *atlas; /* Either a CoglSubTexture representing the atlas region for easy * rendering or if the texture has been migrated out of the atlas it * may be some other texture type such as CoglTexture2D */ CoglTexture *sub_texture; }; CoglAtlasTexture * _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, CoglBool can_convert_in_place); void _cogl_atlas_texture_add_reorganize_callback (CoglContext *ctx, GHookFunc callback, void *user_data); void _cogl_atlas_texture_remove_reorganize_callback (CoglContext *ctx, GHookFunc callback, void *user_data); CoglBool _cogl_is_atlas_texture (void *object); #endif /* _COGL_ATLAS_TEXTURE_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/cogl-poll.h0000664000175000017500000001645614211404421017061 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_POLL_H__ #define __COGL_POLL_H__ #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-poll * @short_description: Functions for integrating Cogl with an * application's main loop * * Cogl needs to integrate with the application's main loop so that it * can internally handle some events from the driver. All Cogl * applications must use these functions. They provide enough * information to describe the state that Cogl will need to wake up * on. An application using the GLib main loop can instead use * cogl_glib_source_new() which provides a #GSource ready to be added * to the main loop. */ /** * CoglPollFDEvent: * @COGL_POLL_FD_EVENT_IN: there is data to read * @COGL_POLL_FD_EVENT_PRI: data can be written (without blocking) * @COGL_POLL_FD_EVENT_OUT: there is urgent data to read. * @COGL_POLL_FD_EVENT_ERR: error condition * @COGL_POLL_FD_EVENT_HUP: hung up (the connection has been broken, usually * for pipes and sockets). * @COGL_POLL_FD_EVENT_NVAL: invalid request. The file descriptor is not open. * * A bitmask of events that Cogl may need to wake on for a file * descriptor. Note that these all have the same values as the * corresponding defines for the poll function call on Unix so they * may be directly passed to poll. * * Since: 1.10 * Stability: unstable */ typedef enum { COGL_POLL_FD_EVENT_IN = COGL_SYSDEF_POLLIN, COGL_POLL_FD_EVENT_PRI = COGL_SYSDEF_POLLPRI, COGL_POLL_FD_EVENT_OUT = COGL_SYSDEF_POLLOUT, COGL_POLL_FD_EVENT_ERR = COGL_SYSDEF_POLLERR, COGL_POLL_FD_EVENT_HUP = COGL_SYSDEF_POLLHUP, COGL_POLL_FD_EVENT_NVAL = COGL_SYSDEF_POLLNVAL } CoglPollFDEvent; /** * CoglPollFD: * @fd: The file descriptor to block on * @events: A bitmask of events to block on * @revents: A bitmask of returned events * * A struct for describing the state of a file descriptor that Cogl * needs to block on. The @events field contains a bitmask of * #CoglPollFDEvents that should cause the application to wake * up. After the application is woken up from idle it should pass back * an array of #CoglPollFDs to Cogl and update the @revents * mask to the actual events that occurred on the file descriptor. * * Note that CoglPollFD is deliberately exactly the same as struct * pollfd on Unix so that it can simply be cast when calling poll. * * Since: 1.10 * Stability: unstable */ typedef struct { int fd; short int events; short int revents; } CoglPollFD; /** * cogl_poll_renderer_get_info: * @renderer: A #CoglRenderer * @poll_fds: A return location for a pointer to an array * of #CoglPollFDs * @n_poll_fds: A return location for the number of entries in *@poll_fds * @timeout: A return location for the maximum length of time to wait * in microseconds, or -1 to wait indefinitely. * * Is used to integrate Cogl with an application mainloop that is based * on the unix poll(2) api (or select() or something equivalent). This * api should be called whenever an application is about to go idle so * that Cogl has a chance to describe what file descriptor events it * needs to be woken up for. * * If your application is using the Glib mainloop then you * should jump to the cogl_glib_source_new() api as a more convenient * way of integrating Cogl with the mainloop. * * After the function is called *@poll_fds will contain a pointer to * an array of #CoglPollFD structs describing the file descriptors * that Cogl expects. The fd and events members will be updated * accordingly. After the application has completed its idle it is * expected to either update the revents members directly in this * array or to create a copy of the array and update them * there. * * When the application mainloop returns from calling poll(2) (or its * equivalent) then it should call cogl_poll_renderer_dispatch() * passing a pointer the array of CoglPollFDs with updated * revent values. * * @timeout will contain a maximum amount of time to wait in * microseconds before the application should wake up or -1 if the * application should wait indefinitely. This can also be 0 if * Cogl needs to be woken up immediately. * * Return value: A "poll fd state age" that changes whenever the set * of poll_fds has changed. If this API is being used to * integrate with another system mainloop api then * knowing if the set of file descriptors and events has * really changed can help avoid redundant work * depending the api. The age isn't guaranteed to change * when the timeout changes. * * Stability: unstable * Since: 1.16 */ int cogl_poll_renderer_get_info (CoglRenderer *renderer, CoglPollFD **poll_fds, int *n_poll_fds, int64_t *timeout); /** * cogl_poll_renderer_dispatch: * @renderer: A #CoglRenderer * @poll_fds: An array of #CoglPollFDs describing the events * that have occurred since the application went idle. * @n_poll_fds: The length of the @poll_fds array. * * This should be called whenever an application is woken up from * going idle in its main loop. The @poll_fds array should contain a * list of file descriptors matched with the events that occurred in * revents. The events field is ignored. It is safe to pass in extra * file descriptors that Cogl didn't request when calling * cogl_poll_renderer_get_info() or a shorter array missing some file * descriptors that Cogl requested. * * If your application didn't originally create a #CoglRenderer * manually then you can easily get a #CoglRenderer pointer by calling * cogl_get_renderer(). * * Stability: unstable * Since: 1.16 */ void cogl_poll_renderer_dispatch (CoglRenderer *renderer, const CoglPollFD *poll_fds, int n_poll_fds); COGL_END_DECLS #endif /* __COGL_POLL_H__ */ muffin-5.2.1/cogl/cogl/cogl-output.h0000664000175000017500000001637114211404421017447 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Owen Taylor */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_OUTPUT_H #define __COGL_OUTPUT_H #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-output * @short_description: information about an output device * * The #CoglOutput object holds information about an output device * such as a monitor or laptop display. It can be queried to find * out the position of the output with respect to the screen * coordinate system and other information such as the resolution * and refresh rate of the device. * * There can be any number of outputs which may overlap: the * same area of the screen may be displayed by multiple output * devices. * * XXX: though it's possible to query the position of the output * with respect to screen coordinates, there is currently no way * of finding out the position of a #CoglOnscreen in screen * coordinates, at least without using windowing-system specific * API's, so it's not easy to get the output positions relative * to the #CoglOnscreen. */ typedef struct _CoglOutput CoglOutput; #define COGL_OUTPUT(X) ((CoglOutput *)(X)) /** * cogl_output_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_output_get_gtype (void); /** * CoglSubpixelOrder: * @COGL_SUBPIXEL_ORDER_UNKNOWN: the layout of subpixel * components for the device is unknown. * @COGL_SUBPIXEL_ORDER_NONE: the device displays colors * without geometrically-separated subpixel components, * or the positioning or colors of the components do not * match any of the values in the enumeration. * @COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB: the device has * horizontally arranged components in the order * red-green-blue from left to right. * @COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR: the device has * horizontally arranged components in the order * blue-green-red from left to right. * @COGL_SUBPIXEL_ORDER_VERTICAL_RGB: the device has * vertically arranged components in the order * red-green-blue from top to bottom. * @COGL_SUBPIXEL_ORDER_VERTICAL_BGR: the device has * vertically arranged components in the order * blue-green-red from top to bottom. * * Some output devices (such as LCD panels) display colors * by making each pixel consist of smaller "subpixels" * that each have a particular color. By using knowledge * of the layout of this subpixel components, it is possible * to create image content with higher resolution than the * pixel grid. * * Since: 1.14 * Stability: unstable */ typedef enum { COGL_SUBPIXEL_ORDER_UNKNOWN, COGL_SUBPIXEL_ORDER_NONE, COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB, COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR, COGL_SUBPIXEL_ORDER_VERTICAL_RGB, COGL_SUBPIXEL_ORDER_VERTICAL_BGR } CoglSubpixelOrder; /** * cogl_is_output: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglOutput. * * Return value: %TRUE if the object references a #CoglOutput * and %FALSE otherwise. * Since: 1.14 * Stability: unstable */ CoglBool cogl_is_output (void *object); /** * cogl_output_get_x: * @output: a #CoglOutput * * Gets the X position of the output with respect to the coordinate * system of the screen. * * Return value: the X position of the output as a pixel offset * from the left side of the screen coordinate space * Since: 1.14 * Stability: unstable */ int cogl_output_get_x (CoglOutput *output); /** * cogl_output_get_y: * @output: a #CoglOutput * * Gets the Y position of the output with respect to the coordinate * system of the screen. * * Return value: the Y position of the output as a pixel offset * from the top side of the screen coordinate space * Since: 1.14 * Stability: unstable */ int cogl_output_get_y (CoglOutput *output); /** * cogl_output_get_width: * @output: a #CoglOutput * * Gets the width of the output in pixels. * * Return value: the width of the output in pixels * Since: 1.14 * Stability: unstable */ int cogl_output_get_width (CoglOutput *output); /** * cogl_output_get_height: * @output: a #CoglOutput * * Gets the height of the output in pixels. * * Return value: the height of the output in pixels * Since: 1.14 * Stability: unstable */ int cogl_output_get_height (CoglOutput *output); /** * cogl_output_get_mm_width: * @output: a #CoglOutput * * Gets the physical width of the output. In some cases (such as * as a projector), the value returned here might correspond to * nominal resolution rather than the actual physical size of the * output device. * * Return value: the height of the output in millimeters. A value * of 0 indicates the width is unknown * Since: 1.14 * Stability: unstable */ int cogl_output_get_mm_width (CoglOutput *output); /** * cogl_output_get_mm_height: * @output: a #CoglOutput * * Gets the physical height of the output. In some cases (such as * as a projector), the value returned here might correspond to * nominal resolution rather than the actual physical size of the * output device. * * Return value: the height of the output in millimeters. A value * of 0 indicates that the height is unknown * Since: 1.14 * Stability: unstable */ int cogl_output_get_mm_height (CoglOutput *output); /** * cogl_output_get_subpixel_order: * @output: a #CoglOutput * * For an output device where each pixel is made up of smaller components * with different colors, returns the layout of the subpixel * components. * * Return value: the order of subpixel components for the output device * Since: 1.14 * Stability: unstable */ CoglSubpixelOrder cogl_output_get_subpixel_order (CoglOutput *output); /** * cogl_output_get_refresh_rate: * @output: a #CoglOutput * * Gets the number of times per second that the output device refreshes * the display contents. * * Return value: the refresh rate of the output device. A value of zero * indicates that the refresh rate is unknown. * Since: 1.14 * Stability: unstable */ float cogl_output_get_refresh_rate (CoglOutput *output); COGL_END_DECLS #endif /* __COGL_OUTPUT_H */ muffin-5.2.1/cogl/cogl/cogl-context.c0000664000175000017500000006632114211404421017566 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-object.h" #include "cogl-private.h" #include "cogl-winsys-private.h" #include "winsys/cogl-winsys-stub-private.h" #include "cogl-profile.h" #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-display-private.h" #include "cogl-renderer-private.h" #include "cogl-journal-private.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-3d-private.h" #include "cogl-texture-rectangle-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-private.h" #include "cogl-attribute-private.h" #include "cogl1-context.h" #include "cogl-gpu-info-private.h" #include "cogl-config-private.h" #include "cogl-error-private.h" #include "cogl-gtype-private.h" #include "cogl/deprecated/cogl-framebuffer-deprecated.h" #include #include #ifdef HAVE_COGL_GL #include "cogl-pipeline-fragend-arbfp-private.h" #endif /* These aren't defined in the GLES headers */ #ifndef GL_POINT_SPRITE #define GL_POINT_SPRITE 0x8861 #endif #ifndef GL_NUM_EXTENSIONS #define GL_NUM_EXTENSIONS 0x821D #endif /* This is a relatively new extension */ #ifndef GL_PURGED_CONTEXT_RESET_NV #define GL_PURGED_CONTEXT_RESET_NV 0x92BB #endif /* These aren't defined in the GLES2 headers */ #ifndef GL_GUILTY_CONTEXT_RESET_ARB #define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 #endif #ifndef GL_INNOCENT_CONTEXT_RESET_ARB #define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 #endif #ifndef GL_UNKNOWN_CONTEXT_RESET_ARB #define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 #endif static void _cogl_context_free (CoglContext *context); COGL_OBJECT_DEFINE (Context, context); COGL_GTYPE_DEFINE_CLASS (Context, context); extern void _cogl_create_context_driver (CoglContext *context); static CoglContext *_cogl_context = NULL; static void _cogl_init_feature_overrides (CoglContext *ctx) { if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_VBOS))) COGL_FLAGS_SET (ctx->private_features, COGL_PRIVATE_FEATURE_VBOS, FALSE); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PBOS))) COGL_FLAGS_SET (ctx->private_features, COGL_PRIVATE_FEATURE_PBOS, FALSE); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ARBFP))) { ctx->feature_flags &= ~COGL_FEATURE_SHADERS_ARBFP; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_ARBFP, FALSE); } if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_GLSL))) { ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL; COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, FALSE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE, FALSE); } if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_NPOT_TEXTURES))) { ctx->feature_flags &= ~(COGL_FEATURE_TEXTURE_NPOT | COGL_FEATURE_TEXTURE_NPOT_BASIC | COGL_FEATURE_TEXTURE_NPOT_MIPMAP | COGL_FEATURE_TEXTURE_NPOT_REPEAT); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT, FALSE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, FALSE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, FALSE); COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, FALSE); } } const CoglWinsysVtable * _cogl_context_get_winsys (CoglContext *context) { return context->display->renderer->winsys_vtable; } /* For reference: There was some deliberation over whether to have a * constructor that could throw an exception but looking at standard * practices with several high level OO languages including python, C++, * C# Java and Ruby they all support exceptions in constructors and the * general consensus appears to be that throwing an exception is neater * than successfully constructing with an internal error status that * would then have to be explicitly checked via some form of ::is_ok() * method. */ CoglContext * cogl_context_new (CoglDisplay *display, CoglError **error) { CoglContext *context; uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff }; CoglBitmap *white_pixel_bitmap; const CoglWinsysVtable *winsys; int i; CoglError *internal_error = NULL; _cogl_init (); #ifdef COGL_ENABLE_PROFILE /* We need to be absolutely sure that uprof has been initialized * before calling _cogl_uprof_init. uprof_init (NULL, NULL) * will be a NOP if it has been initialized but it will also * mean subsequent parsing of the UProf GOptionGroup will have no * affect. * * Sadly GOptionGroup based library initialization is extremely * fragile by design because GOptionGroups have no notion of * dependencies and so the order things are initialized isn't * currently under tight control. */ uprof_init (NULL, NULL); _cogl_uprof_init (); #endif /* Allocate context memory */ context = calloc (1, sizeof (CoglContext)); /* Convert the context into an object immediately in case any of the code below wants to verify that the context pointer is a valid object */ _cogl_context_object_new (context); /* XXX: Gross hack! * Currently everything in Cogl just assumes there is a default * context which it can access via _COGL_GET_CONTEXT() including * code used to construct a CoglContext. Until all of that code * has been updated to take an explicit context argument we have * to immediately make our pointer the default context. */ _cogl_context = context; /* Init default values */ memset (context->features, 0, sizeof (context->features)); context->feature_flags = 0; memset (context->private_features, 0, sizeof (context->private_features)); context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_UNKNOWN; memset (context->winsys_features, 0, sizeof (context->winsys_features)); if (!display) { CoglRenderer *renderer = cogl_renderer_new (); if (!cogl_renderer_connect (renderer, error)) { free (context); return NULL; } display = cogl_display_new (renderer, NULL); cogl_object_unref(renderer); } else cogl_object_ref (display); if (!cogl_display_setup (display, error)) { cogl_object_unref (display); free (context); return NULL; } context->display = display; /* This is duplicated data, but it's much more convenient to have the driver attached to the context and the value is accessed a lot throughout Cogl */ context->driver = display->renderer->driver; /* Again this is duplicated data, but it convenient to be able * access these from the context. */ context->driver_vtable = display->renderer->driver_vtable; context->texture_driver = display->renderer->texture_driver; for (i = 0; i < G_N_ELEMENTS (context->private_features); i++) context->private_features[i] |= display->renderer->private_features[i]; winsys = _cogl_context_get_winsys (context); if (!winsys->context_init (context, error)) { cogl_object_unref (display); free (context); return NULL; } context->attribute_name_states_hash = g_hash_table_new_full (g_str_hash, g_str_equal, free, free); context->attribute_name_index_map = NULL; context->n_attribute_names = 0; /* The "cogl_color_in" attribute needs a deterministic name_index * so we make sure it's the first attribute name we register */ _cogl_attribute_register_attribute_name (context, "cogl_color_in"); context->uniform_names = g_ptr_array_new_with_free_func ((GDestroyNotify) free); context->uniform_name_hash = g_hash_table_new (g_str_hash, g_str_equal); context->n_uniform_names = 0; /* Initialise the driver specific state */ _cogl_init_feature_overrides (context); /* XXX: ONGOING BUG: Intel viewport scissor * * Intel gen6 drivers don't currently correctly handle offset * viewports, since primitives aren't clipped within the bounds of * the viewport. To workaround this we push our own clip for the * viewport that will use scissoring to ensure we clip as expected. * * TODO: file a bug upstream! */ if (context->gpu.driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA && context->gpu.architecture == COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE && !getenv ("COGL_DISABLE_INTEL_VIEWPORT_SCISSORT_WORKAROUND")) context->needs_viewport_scissor_workaround = TRUE; else context->needs_viewport_scissor_workaround = FALSE; context->sampler_cache = _cogl_sampler_cache_new (context); _cogl_pipeline_init_default_pipeline (); _cogl_pipeline_init_default_layers (); _cogl_pipeline_init_state_hash_functions (); _cogl_pipeline_init_layer_state_hash_functions (); context->current_clip_stack_valid = FALSE; context->current_clip_stack = NULL; context->legacy_backface_culling_enabled = FALSE; cogl_matrix_init_identity (&context->identity_matrix); cogl_matrix_init_identity (&context->y_flip_matrix); cogl_matrix_scale (&context->y_flip_matrix, 1, -1, 1); context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW; context->texture_units = g_array_new (FALSE, FALSE, sizeof (CoglTextureUnit)); if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_ANY_GL)) { /* See cogl-pipeline.c for more details about why we leave texture unit 1 * active by default... */ context->active_texture_unit = 1; GE (context, glActiveTexture (GL_TEXTURE1)); } context->legacy_fog_state.enabled = FALSE; context->opaque_color_pipeline = cogl_pipeline_new (context); context->blended_color_pipeline = cogl_pipeline_new (context); context->texture_pipeline = cogl_pipeline_new (context); context->codegen_header_buffer = g_string_new (""); context->codegen_source_buffer = g_string_new (""); context->codegen_boilerplate_buffer = g_string_new (""); context->source_stack = NULL; context->legacy_state_set = 0; context->default_gl_texture_2d_tex = NULL; context->default_gl_texture_3d_tex = NULL; context->default_gl_texture_rect_tex = NULL; context->framebuffers = NULL; context->current_draw_buffer = NULL; context->current_read_buffer = NULL; context->current_draw_buffer_state_flushed = 0; context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL; context->swap_callback_closures = g_hash_table_new (g_direct_hash, g_direct_equal); _cogl_list_init (&context->onscreen_events_queue); _cogl_list_init (&context->onscreen_dirty_queue); g_queue_init (&context->gles2_context_stack); context->journal_flush_attributes_array = g_array_new (TRUE, FALSE, sizeof (CoglAttribute *)); context->journal_clip_bounds = NULL; context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (float)); context->current_pipeline = NULL; context->current_pipeline_changes_since_flush = 0; context->current_pipeline_with_color_attrib = FALSE; _cogl_bitmask_init (&context->enabled_builtin_attributes); _cogl_bitmask_init (&context->enable_builtin_attributes_tmp); _cogl_bitmask_init (&context->enabled_texcoord_attributes); _cogl_bitmask_init (&context->enable_texcoord_attributes_tmp); _cogl_bitmask_init (&context->enabled_custom_attributes); _cogl_bitmask_init (&context->enable_custom_attributes_tmp); _cogl_bitmask_init (&context->changed_bits_tmp); context->max_texture_units = -1; context->max_activateable_texture_units = -1; context->current_fragment_program_type = COGL_PIPELINE_PROGRAM_TYPE_FIXED; context->current_vertex_program_type = COGL_PIPELINE_PROGRAM_TYPE_FIXED; context->current_gl_program = 0; context->current_gl_dither_enabled = TRUE; context->current_gl_color_mask = COGL_COLOR_MASK_ALL; context->gl_blend_enable_cache = FALSE; context->depth_test_enabled_cache = FALSE; context->depth_test_function_cache = COGL_DEPTH_TEST_FUNCTION_LESS; context->depth_writing_enabled_cache = TRUE; context->depth_range_near_cache = 0; context->depth_range_far_cache = 1; context->legacy_depth_test_enabled = FALSE; context->pipeline_cache = _cogl_pipeline_cache_new (); for (i = 0; i < COGL_BUFFER_BIND_TARGET_COUNT; i++) context->current_buffer[i] = NULL; context->window_buffer = NULL; context->framebuffer_stack = _cogl_create_framebuffer_stack (); /* XXX: In this case the Clutter backend is still responsible for * the OpenGL binding API and for creating onscreen framebuffers and * so we have to add a dummy framebuffer to represent the backend * owned window... */ if (_cogl_context_get_winsys (context) == _cogl_winsys_stub_get_vtable ()) { CoglOnscreen *window = _cogl_onscreen_new (); cogl_set_framebuffer (COGL_FRAMEBUFFER (window)); cogl_object_unref (COGL_FRAMEBUFFER (window)); } context->current_path = NULL; context->stencil_pipeline = cogl_pipeline_new (context); context->in_begin_gl_block = FALSE; context->quad_buffer_indices_byte = NULL; context->quad_buffer_indices = NULL; context->quad_buffer_indices_len = 0; context->rectangle_byte_indices = NULL; context->rectangle_short_indices = NULL; context->rectangle_short_indices_len = 0; context->texture_download_pipeline = NULL; context->blit_texture_pipeline = NULL; #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_ALPHA_TEST)) /* The default for GL_ALPHA_TEST is to always pass which is equivalent to * the test being disabled therefore we assume that for all drivers there * will be no performance impact if we always leave the test enabled which * makes things a bit simpler for us. Under GLES2 the alpha test is * implemented in the fragment shader so there is no enable for it */ GE (context, glEnable (GL_ALPHA_TEST)); #endif #if defined (HAVE_COGL_GL) if ((context->driver == COGL_DRIVER_GL3)) { GLuint vertex_array; /* In a forward compatible context, GL 3 doesn't support rendering * using the default vertex array object. Cogl doesn't use vertex * array objects yet so for now we just create a dummy array * object that we will use as our own default object. Eventually * it could be good to attach the vertex array objects to * CoglPrimitives */ context->glGenVertexArrays (1, &vertex_array); context->glBindVertexArray (vertex_array); } #endif context->current_modelview_entry = NULL; context->current_projection_entry = NULL; _cogl_matrix_entry_identity_init (&context->identity_entry); _cogl_matrix_entry_cache_init (&context->builtin_flushed_projection); _cogl_matrix_entry_cache_init (&context->builtin_flushed_modelview); /* Create default textures used for fall backs */ context->default_gl_texture_2d_tex = cogl_texture_2d_new_from_data (context, 1, 1, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0, /* rowstride */ white_pixel, NULL); /* abort on error */ /* If 3D or rectangle textures aren't supported then these will * return errors that we can simply ignore. */ internal_error = NULL; context->default_gl_texture_3d_tex = cogl_texture_3d_new_from_data (context, 1, 1, 1, /* width, height, depth */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0, /* rowstride */ 0, /* image stride */ white_pixel, &internal_error); if (internal_error) cogl_error_free (internal_error); /* TODO: add cogl_texture_rectangle_new_from_data() */ white_pixel_bitmap = cogl_bitmap_new_for_data (context, 1, 1, /* width/height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ white_pixel); internal_error = NULL; context->default_gl_texture_rect_tex = cogl_texture_rectangle_new_from_bitmap (white_pixel_bitmap); /* XXX: we need to allocate the texture now because the white_pixel * data is on the stack */ cogl_texture_allocate (COGL_TEXTURE (context->default_gl_texture_rect_tex), &internal_error); if (internal_error) cogl_error_free (internal_error); cogl_object_unref (white_pixel_bitmap); cogl_push_source (context->opaque_color_pipeline); context->atlases = NULL; g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook)); context->buffer_map_fallback_array = g_byte_array_new (); context->buffer_map_fallback_in_use = FALSE; /* As far as I can tell, GL_POINT_SPRITE doesn't have any effect unless GL_COORD_REPLACE is enabled for an individual layer. Therefore it seems like it should be ok to just leave it enabled all the time instead of having to have a set property on each pipeline to track whether any layers have point sprite coords enabled. We don't need to do this for GL3 or GLES2 because point sprites are handled using a builtin varying in the shader. */ if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_GL_FIXED) && cogl_has_feature (context, COGL_FEATURE_ID_POINT_SPRITE)) GE (context, glEnable (GL_POINT_SPRITE)); _cogl_list_init (&context->fences); return context; } static void _cogl_context_free (CoglContext *context) { const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context); winsys->context_deinit (context); _cogl_free_framebuffer_stack (context->framebuffer_stack); if (context->current_path) cogl_handle_unref (context->current_path); if (context->default_gl_texture_2d_tex) cogl_object_unref (context->default_gl_texture_2d_tex); if (context->default_gl_texture_3d_tex) cogl_object_unref (context->default_gl_texture_3d_tex); if (context->default_gl_texture_rect_tex) cogl_object_unref (context->default_gl_texture_rect_tex); if (context->opaque_color_pipeline) cogl_object_unref (context->opaque_color_pipeline); if (context->blended_color_pipeline) cogl_object_unref (context->blended_color_pipeline); if (context->texture_pipeline) cogl_object_unref (context->texture_pipeline); if (context->blit_texture_pipeline) cogl_object_unref (context->blit_texture_pipeline); if (context->swap_callback_closures) g_hash_table_destroy (context->swap_callback_closures); g_warn_if_fail (context->gles2_context_stack.length == 0); if (context->journal_flush_attributes_array) g_array_free (context->journal_flush_attributes_array, TRUE); if (context->journal_clip_bounds) g_array_free (context->journal_clip_bounds, TRUE); if (context->polygon_vertices) g_array_free (context->polygon_vertices, TRUE); if (context->quad_buffer_indices_byte) cogl_object_unref (context->quad_buffer_indices_byte); if (context->quad_buffer_indices) cogl_object_unref (context->quad_buffer_indices); if (context->rectangle_byte_indices) cogl_object_unref (context->rectangle_byte_indices); if (context->rectangle_short_indices) cogl_object_unref (context->rectangle_short_indices); if (context->default_pipeline) cogl_object_unref (context->default_pipeline); if (context->dummy_layer_dependant) cogl_object_unref (context->dummy_layer_dependant); if (context->default_layer_n) cogl_object_unref (context->default_layer_n); if (context->default_layer_0) cogl_object_unref (context->default_layer_0); if (context->current_clip_stack_valid) _cogl_clip_stack_unref (context->current_clip_stack); g_slist_free (context->atlases); g_hook_list_clear (&context->atlas_reorganize_callbacks); _cogl_bitmask_destroy (&context->enabled_builtin_attributes); _cogl_bitmask_destroy (&context->enable_builtin_attributes_tmp); _cogl_bitmask_destroy (&context->enabled_texcoord_attributes); _cogl_bitmask_destroy (&context->enable_texcoord_attributes_tmp); _cogl_bitmask_destroy (&context->enabled_custom_attributes); _cogl_bitmask_destroy (&context->enable_custom_attributes_tmp); _cogl_bitmask_destroy (&context->changed_bits_tmp); if (context->current_modelview_entry) cogl_matrix_entry_unref (context->current_modelview_entry); if (context->current_projection_entry) cogl_matrix_entry_unref (context->current_projection_entry); _cogl_matrix_entry_cache_destroy (&context->builtin_flushed_projection); _cogl_matrix_entry_cache_destroy (&context->builtin_flushed_modelview); _cogl_pipeline_cache_free (context->pipeline_cache); _cogl_sampler_cache_free (context->sampler_cache); _cogl_destroy_texture_units (); g_ptr_array_free (context->uniform_names, TRUE); g_hash_table_destroy (context->uniform_name_hash); g_hash_table_destroy (context->attribute_name_states_hash); g_array_free (context->attribute_name_index_map, TRUE); g_byte_array_free (context->buffer_map_fallback_array, TRUE); cogl_object_unref (context->display); free (context); } CoglContext * _cogl_context_get_default (void) { CoglError *error = NULL; /* Create if doesn't exist yet */ if (_cogl_context == NULL) { _cogl_context = cogl_context_new (NULL, &error); if (!_cogl_context) { g_warning ("Failed to create default context: %s", error->message); cogl_error_free (error); } } return _cogl_context; } CoglDisplay * cogl_context_get_display (CoglContext *context) { return context->display; } CoglRenderer * cogl_context_get_renderer (CoglContext *context) { return context->display->renderer; } CoglBool _cogl_context_update_features (CoglContext *context, CoglError **error) { return context->driver_vtable->update_features (context, error); } void _cogl_context_set_current_projection_entry (CoglContext *context, CoglMatrixEntry *entry) { cogl_matrix_entry_ref (entry); if (context->current_projection_entry) cogl_matrix_entry_unref (context->current_projection_entry); context->current_projection_entry = entry; } void _cogl_context_set_current_modelview_entry (CoglContext *context, CoglMatrixEntry *entry) { cogl_matrix_entry_ref (entry); if (context->current_modelview_entry) cogl_matrix_entry_unref (context->current_modelview_entry); context->current_modelview_entry = entry; } char ** _cogl_context_get_gl_extensions (CoglContext *context) { const char *env_disabled_extensions; char **ret; /* In GL 3, querying GL_EXTENSIONS is deprecated so we have to build * the array using glGetStringi instead */ #ifdef HAVE_COGL_GL if (context->driver == COGL_DRIVER_GL3) { int num_extensions, i; context->glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions); ret = malloc (sizeof (char *) * (num_extensions + 1)); for (i = 0; i < num_extensions; i++) { const char *ext = (const char *) context->glGetStringi (GL_EXTENSIONS, i); ret[i] = g_strdup (ext); } ret[num_extensions] = NULL; } else #endif { const char *all_extensions = (const char *) context->glGetString (GL_EXTENSIONS); ret = g_strsplit (all_extensions, " ", 0 /* max tokens */); } if ((env_disabled_extensions = g_getenv ("COGL_DISABLE_GL_EXTENSIONS")) || _cogl_config_disable_gl_extensions) { char **split_env_disabled_extensions; char **split_conf_disabled_extensions; char **src, **dst; if (env_disabled_extensions) split_env_disabled_extensions = g_strsplit (env_disabled_extensions, ",", 0 /* no max tokens */); else split_env_disabled_extensions = NULL; if (_cogl_config_disable_gl_extensions) split_conf_disabled_extensions = g_strsplit (_cogl_config_disable_gl_extensions, ",", 0 /* no max tokens */); else split_conf_disabled_extensions = NULL; for (dst = ret, src = ret; *src; src++) { char **d; if (split_env_disabled_extensions) for (d = split_env_disabled_extensions; *d; d++) if (!strcmp (*src, *d)) goto disabled; if (split_conf_disabled_extensions) for (d = split_conf_disabled_extensions; *d; d++) if (!strcmp (*src, *d)) goto disabled; *(dst++) = *src; continue; disabled: free (*src); continue; } *dst = NULL; if (split_env_disabled_extensions) g_strfreev (split_env_disabled_extensions); if (split_conf_disabled_extensions) g_strfreev (split_conf_disabled_extensions); } return ret; } const char * _cogl_context_get_gl_version (CoglContext *context) { const char *version_override; if ((version_override = g_getenv ("COGL_OVERRIDE_GL_VERSION"))) return version_override; else if (_cogl_config_override_gl_version) return _cogl_config_override_gl_version; else return (const char *) context->glGetString (GL_VERSION); } int64_t cogl_get_clock_time (CoglContext *context) { const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context); if (winsys->context_get_clock_time) return winsys->context_get_clock_time (context); else return 0; } CoglGraphicsResetStatus cogl_get_graphics_reset_status (CoglContext *context) { if (!context->glGetGraphicsResetStatus) return COGL_GRAPHICS_RESET_STATUS_NO_ERROR; switch (context->glGetGraphicsResetStatus ()) { case GL_GUILTY_CONTEXT_RESET_ARB: return COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET; case GL_INNOCENT_CONTEXT_RESET_ARB: return COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET; case GL_UNKNOWN_CONTEXT_RESET_ARB: return COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET; case GL_PURGED_CONTEXT_RESET_NV: return COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET; default: return COGL_GRAPHICS_RESET_STATUS_NO_ERROR; } } muffin-5.2.1/cogl/cogl/cogl-egl-defines.h.in0000664000175000017500000000252614211404421020673 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_EGL_DEFINES_H__ #define __COGL_EGL_DEFINES_H__ #ifdef COGL_HAS_EGL_SUPPORT @COGL_EGL_INCLUDES@ #endif /* COGL_HAS_EGL_SUPPORT */ #endif muffin-5.2.1/cogl/cogl/cogl-swap-chain.c0000664000175000017500000000422414211404421020126 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-object.h" #include "cogl-swap-chain-private.h" #include "cogl-swap-chain.h" #include "cogl-gtype-private.h" static void _cogl_swap_chain_free (CoglSwapChain *swap_chain); COGL_OBJECT_DEFINE (SwapChain, swap_chain); COGL_GTYPE_DEFINE_CLASS (SwapChain, swap_chain); static void _cogl_swap_chain_free (CoglSwapChain *swap_chain) { g_slice_free (CoglSwapChain, swap_chain); } CoglSwapChain * cogl_swap_chain_new (void) { CoglSwapChain *swap_chain = g_slice_new0 (CoglSwapChain); swap_chain->length = -1; /* no preference */ return _cogl_swap_chain_object_new (swap_chain); } void cogl_swap_chain_set_has_alpha (CoglSwapChain *swap_chain, CoglBool has_alpha) { swap_chain->has_alpha = has_alpha; } void cogl_swap_chain_set_length (CoglSwapChain *swap_chain, int length) { swap_chain->length = length; } muffin-5.2.1/cogl/cogl/cogl-blend-string.h0000664000175000017500000001017314211404421020471 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef COGL_BLEND_STRING_H #define COGL_BLEND_STRING_H #include #include typedef enum _CoglBlendStringContext { COGL_BLEND_STRING_CONTEXT_BLENDING, COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE } CoglBlendStringContext; /* NB: debug stringify code will get upset if these * are re-ordered */ typedef enum _CoglBlendStringChannelMask { COGL_BLEND_STRING_CHANNEL_MASK_RGB, COGL_BLEND_STRING_CHANNEL_MASK_ALPHA, COGL_BLEND_STRING_CHANNEL_MASK_RGBA } CoglBlendStringChannelMask; typedef enum _CoglBlendStringColorSourceType { /* blending */ COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR, COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR, /* shared */ COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT, /* texture combining */ COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE, COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N, COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY, COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS } CoglBlendStringColorSourceType; typedef struct _CoglBlendStringColorSourceInfo { CoglBlendStringColorSourceType type; const char *name; size_t name_len; } CoglBlendStringColorSourceInfo; typedef struct _CoglBlendStringColorSource { CoglBool is_zero; const CoglBlendStringColorSourceInfo *info; int texture; /* for the TEXTURE_N color source */ CoglBool one_minus; CoglBlendStringChannelMask mask; } CoglBlendStringColorSource; typedef struct _CoglBlendStringFactor { CoglBool is_one; CoglBool is_src_alpha_saturate; CoglBool is_color; CoglBlendStringColorSource source; } CoglBlendStringFactor; typedef struct _CoglBlendStringArgument { CoglBlendStringColorSource source; CoglBlendStringFactor factor; } CoglBlendStringArgument; typedef enum _CoglBlendStringFunctionType { /* shared */ COGL_BLEND_STRING_FUNCTION_ADD, /* texture combine only */ COGL_BLEND_STRING_FUNCTION_REPLACE, COGL_BLEND_STRING_FUNCTION_MODULATE, COGL_BLEND_STRING_FUNCTION_ADD_SIGNED, COGL_BLEND_STRING_FUNCTION_INTERPOLATE, COGL_BLEND_STRING_FUNCTION_SUBTRACT, COGL_BLEND_STRING_FUNCTION_DOT3_RGB, COGL_BLEND_STRING_FUNCTION_DOT3_RGBA } CoglBlendStringFunctionType; typedef struct _CoglBlendStringFunctionInfo { enum _CoglBlendStringFunctionType type; const char *name; size_t name_len; int argc; } CoglBlendStringFunctionInfo; typedef struct _CoglBlendStringStatement { CoglBlendStringChannelMask mask; const CoglBlendStringFunctionInfo *function; CoglBlendStringArgument args[3]; } CoglBlendStringStatement; CoglBool _cogl_blend_string_compile (const char *string, CoglBlendStringContext context, CoglBlendStringStatement *statements, CoglError **error); void _cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement, CoglBlendStringStatement *rgb, CoglBlendStringStatement *a); #endif /* COGL_BLEND_STRING_H */ muffin-5.2.1/cogl/cogl/muffin-cogl.pc.in0000664000175000017500000000057314211404421020150 0ustar jpeisachjpeisachprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@/muffin includedir=@includedir@/muffin apiversion=@MUFFIN_PLUGIN_API_VERSION@ requires=@COGL_PKG_REQUIRES@ Name: Cogl Description: An object oriented GL/GLES Abstraction/Utility Layer Version: @MUFFIN_VERSION@ Libs: -L${libdir} -lmuffin-cogl-@MUFFIN_PLUGIN_API_VERSION@ Cflags: -I${includedir}/cogl Requires: ${requires} muffin-5.2.1/cogl/cogl/cogl-primitive-texture.c0000664000175000017500000000360214211404421021601 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-primitive-texture.h" #include "cogl-texture-private.h" CoglBool cogl_is_primitive_texture (void *object) { return (cogl_is_texture (object) && COGL_TEXTURE (object)->vtable->is_primitive); } void cogl_primitive_texture_set_auto_mipmap (CoglPrimitiveTexture *primitive_texture, CoglBool value) { CoglTexture *texture; _COGL_RETURN_IF_FAIL (cogl_is_primitive_texture (primitive_texture)); texture = COGL_TEXTURE (primitive_texture); g_assert (texture->vtable->set_auto_mipmap != NULL); texture->vtable->set_auto_mipmap (texture, value); } muffin-5.2.1/cogl/cogl/cogl-texture-2d.c0000664000175000017500000005237714211404421020113 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-private.h" #include "cogl-util.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d-gl-private.h" #include "cogl-texture-driver.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-journal-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-framebuffer-private.h" #include "cogl-error-private.h" #ifdef COGL_HAS_EGL_SUPPORT #include "cogl-winsys-egl-private.h" #endif #include "cogl-gtype-private.h" #include #include #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT #include "cogl-wayland-server.h" #endif static void _cogl_texture_2d_free (CoglTexture2D *tex_2d); COGL_TEXTURE_DEFINE (Texture2D, texture_2d); COGL_GTYPE_DEFINE_CLASS (Texture2D, texture_2d, COGL_GTYPE_IMPLEMENT_INTERFACE (texture)); static const CoglTextureVtable cogl_texture_2d_vtable; typedef struct _CoglTexture2DManualRepeatData { CoglTexture2D *tex_2d; CoglMetaTextureCallback callback; void *user_data; } CoglTexture2DManualRepeatData; static void _cogl_texture_2d_free (CoglTexture2D *tex_2d) { CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; ctx->driver_vtable->texture_2d_free (tex_2d); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (tex_2d)); } void _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, CoglBool value) { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); tex_2d->auto_mipmap = value; } CoglTexture2D * _cogl_texture_2d_create_base (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format, CoglTextureLoader *loader) { CoglTexture2D *tex_2d = g_new (CoglTexture2D, 1); CoglTexture *tex = COGL_TEXTURE (tex_2d); _cogl_texture_init (tex, ctx, width, height, internal_format, loader, &cogl_texture_2d_vtable); tex_2d->mipmaps_dirty = TRUE; tex_2d->auto_mipmap = TRUE; tex_2d->gl_target = GL_TEXTURE_2D; tex_2d->is_foreign = FALSE; ctx->driver_vtable->texture_2d_init (tex_2d); return _cogl_texture_2d_object_new (tex_2d); } CoglTexture2D * cogl_texture_2d_new_with_size (CoglContext *ctx, int width, int height) { CoglTextureLoader *loader; loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED; loader->src.sized.width = width; loader->src.sized.height = height; return _cogl_texture_2d_create_base (ctx, width, height, COGL_PIXEL_FORMAT_RGBA_8888_PRE, loader); } static CoglBool _cogl_texture_2d_allocate (CoglTexture *tex, CoglError **error) { CoglContext *ctx = tex->context; return ctx->driver_vtable->texture_2d_allocate (tex, error); } CoglTexture2D * _cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp, CoglBool can_convert_in_place) { CoglTextureLoader *loader; _COGL_RETURN_VAL_IF_FAIL (bmp != NULL, NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP; loader->src.bitmap.bitmap = cogl_object_ref (bmp); loader->src.bitmap.can_convert_in_place = can_convert_in_place; return _cogl_texture_2d_create_base (_cogl_bitmap_get_context (bmp), cogl_bitmap_get_width (bmp), cogl_bitmap_get_height (bmp), cogl_bitmap_get_format (bmp), loader); } CoglTexture2D * cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp) { return _cogl_texture_2d_new_from_bitmap (bmp, FALSE); /* can't convert in place */ } CoglTexture2D * cogl_texture_2d_new_from_file (CoglContext *ctx, const char *filename, CoglError **error) { CoglBitmap *bmp; CoglTexture2D *tex_2d = NULL; _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); bmp = _cogl_bitmap_from_file (ctx, filename, error); if (bmp == NULL) return NULL; tex_2d = _cogl_texture_2d_new_from_bitmap (bmp, TRUE); /* can convert in-place */ cogl_object_unref (bmp); return tex_2d; } CoglTexture2D * cogl_texture_2d_new_from_data (CoglContext *ctx, int width, int height, CoglPixelFormat format, int rowstride, const uint8_t *data, CoglError **error) { CoglBitmap *bmp; CoglTexture2D *tex_2d; _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); /* Rowstride from width if not given */ if (rowstride == 0) rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); /* Wrap the data into a bitmap */ bmp = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); tex_2d = cogl_texture_2d_new_from_bitmap (bmp); cogl_object_unref (bmp); if (tex_2d && !cogl_texture_allocate (COGL_TEXTURE (tex_2d), error)) { cogl_object_unref (tex_2d); return NULL; } return tex_2d; } #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) /* NB: The reason we require the width, height and format to be passed * even though they may seem redundant is because GLES 1/2 don't * provide a way to query these properties. */ CoglTexture2D * cogl_egl_texture_2d_new_from_image (CoglContext *ctx, int width, int height, CoglPixelFormat format, EGLImageKHR image, CoglError **error) { CoglTextureLoader *loader; CoglTexture2D *tex; _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & COGL_RENDERER_CONSTRAINT_USES_EGL, NULL); _COGL_RETURN_VAL_IF_FAIL (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE), NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE; loader->src.egl_image.image = image; loader->src.egl_image.width = width; loader->src.egl_image.height = height; loader->src.egl_image.format = format; tex = _cogl_texture_2d_create_base (ctx, width, height, format, loader); if (!cogl_texture_allocate (COGL_TEXTURE (tex), error)) { cogl_object_unref (tex); return NULL; } return tex; } #endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */ #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT static void shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer, CoglPixelFormat *format_out, CoglTextureComponents *components_out) { CoglPixelFormat format; CoglTextureComponents components = COGL_TEXTURE_COMPONENTS_RGBA; switch (wl_shm_buffer_get_format (shm_buffer)) { #if G_BYTE_ORDER == G_BIG_ENDIAN case WL_SHM_FORMAT_ARGB8888: format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; break; case WL_SHM_FORMAT_XRGB8888: format = COGL_PIXEL_FORMAT_ARGB_8888; components = COGL_TEXTURE_COMPONENTS_RGB; break; #elif G_BYTE_ORDER == G_LITTLE_ENDIAN case WL_SHM_FORMAT_ARGB8888: format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; break; case WL_SHM_FORMAT_XRGB8888: format = COGL_PIXEL_FORMAT_BGRA_8888; components = COGL_TEXTURE_COMPONENTS_RGB; break; #endif default: g_warn_if_reached (); format = COGL_PIXEL_FORMAT_ARGB_8888; } if (format_out) *format_out = format; if (components_out) *components_out = components; } CoglBool cogl_wayland_texture_set_region_from_shm_buffer (CoglTexture *texture, int src_x, int src_y, int width, int height, struct wl_shm_buffer * shm_buffer, int dst_x, int dst_y, int level, CoglError **error) { const uint8_t *data = wl_shm_buffer_get_data (shm_buffer); int32_t stride = wl_shm_buffer_get_stride (shm_buffer); CoglPixelFormat format; int bpp; shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL); bpp = _cogl_pixel_format_get_bytes_per_pixel (format); return _cogl_texture_set_region (COGL_TEXTURE (texture), width, height, format, stride, data + src_x * bpp + src_y * stride, dst_x, dst_y, level, error); } CoglTexture2D * cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, struct wl_resource *buffer, CoglError **error) { struct wl_shm_buffer *shm_buffer; CoglTexture2D *tex = NULL; shm_buffer = wl_shm_buffer_get (buffer); if (shm_buffer) { int stride = wl_shm_buffer_get_stride (shm_buffer); int width = wl_shm_buffer_get_width (shm_buffer); int height = wl_shm_buffer_get_height (shm_buffer); CoglPixelFormat format; CoglTextureComponents components; CoglBitmap *bmp; shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components); bmp = cogl_bitmap_new_for_data (ctx, width, height, format, stride, wl_shm_buffer_get_data (shm_buffer)); tex = cogl_texture_2d_new_from_bitmap (bmp); cogl_texture_set_components (COGL_TEXTURE (tex), components); cogl_object_unref (bmp); if (!cogl_texture_allocate (COGL_TEXTURE (tex), error)) { cogl_object_unref (tex); return NULL; } else return tex; } else { int format, width, height; if (_cogl_egl_query_wayland_buffer (ctx, buffer, EGL_TEXTURE_FORMAT, &format) && _cogl_egl_query_wayland_buffer (ctx, buffer, EGL_WIDTH, &width) && _cogl_egl_query_wayland_buffer (ctx, buffer, EGL_HEIGHT, &height)) { EGLImageKHR image; CoglPixelFormat internal_format; _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & COGL_RENDERER_CONSTRAINT_USES_EGL, NULL); switch (format) { case EGL_TEXTURE_RGB: internal_format = COGL_PIXEL_FORMAT_RGB_888; break; case EGL_TEXTURE_RGBA: internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; break; default: _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Can't create texture from unknown " "wayland buffer format %d\n", format); return NULL; } image = _cogl_egl_create_image (ctx, EGL_WAYLAND_BUFFER_WL, buffer, NULL); tex = cogl_egl_texture_2d_new_from_image (ctx, width, height, internal_format, image, error); _cogl_egl_destroy_image (ctx, image); return tex; } } _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Can't create texture from unknown " "wayland buffer type\n"); return NULL; } #endif /* COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT */ void _cogl_texture_2d_externally_modified (CoglTexture *texture) { if (!cogl_is_texture_2d (texture)) return; COGL_TEXTURE_2D (texture)->mipmaps_dirty = TRUE; } void _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglFramebuffer *src_fb, int dst_x, int dst_y, int level) { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; /* Assert that the storage for this texture has been allocated */ cogl_texture_allocate (tex, NULL); /* (abort on error) */ ctx->driver_vtable->texture_2d_copy_from_framebuffer (tex_2d, src_x, src_y, width, height, src_fb, dst_x, dst_y, level); tex_2d->mipmaps_dirty = TRUE; } static int _cogl_texture_2d_get_max_waste (CoglTexture *tex) { return -1; } static CoglBool _cogl_texture_2d_is_sliced (CoglTexture *tex) { return FALSE; } static CoglBool _cogl_texture_2d_can_hardware_repeat (CoglTexture *tex) { CoglContext *ctx = tex->context; if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT) || (_cogl_util_is_pot (tex->width) && _cogl_util_is_pot (tex->height))) return TRUE; else return FALSE; } static void _cogl_texture_2d_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { /* The texture coordinates map directly so we don't need to do anything */ } static CoglTransformResult _cogl_texture_2d_transform_quad_coords_to_gl (CoglTexture *tex, float *coords) { /* The texture coordinates map directly so we don't need to do anything other than check for repeats */ int i; for (i = 0; i < 4; i++) if (coords[i] < 0.0f || coords[i] > 1.0f) { /* Repeat is needed */ return (_cogl_texture_2d_can_hardware_repeat (tex) ? COGL_TRANSFORM_HARDWARE_REPEAT : COGL_TRANSFORM_SOFTWARE_REPEAT); } /* No repeat is needed */ return COGL_TRANSFORM_NO_REPEAT; } static CoglBool _cogl_texture_2d_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglContext *ctx = tex->context; CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); if (ctx->driver_vtable->texture_2d_get_gl_handle) { GLuint handle; if (out_gl_target) *out_gl_target = tex_2d->gl_target; handle = ctx->driver_vtable->texture_2d_get_gl_handle (tex_2d); if (out_gl_handle) *out_gl_handle = handle; return handle ? TRUE : FALSE; } else return FALSE; } static void _cogl_texture_2d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); /* Only update if the mipmaps are dirty */ if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) && tex_2d->auto_mipmap && tex_2d->mipmaps_dirty) { CoglContext *ctx = tex->context; ctx->driver_vtable->texture_2d_generate_mipmap (tex_2d); tex_2d->mipmaps_dirty = FALSE; } } static void _cogl_texture_2d_ensure_non_quad_rendering (CoglTexture *tex) { /* Nothing needs to be done */ } static CoglBool _cogl_texture_2d_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int width, int height, int level, CoglBitmap *bmp, CoglError **error) { CoglContext *ctx = tex->context; CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); if (!ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d, src_x, src_y, width, height, bmp, dst_x, dst_y, level, error)) { return FALSE; } tex_2d->mipmaps_dirty = TRUE; return TRUE; } static CoglBool _cogl_texture_2d_get_data (CoglTexture *tex, CoglPixelFormat format, int rowstride, uint8_t *data) { CoglContext *ctx = tex->context; if (ctx->driver_vtable->texture_2d_get_data) { CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); ctx->driver_vtable->texture_2d_get_data (tex_2d, format, rowstride, data); return TRUE; } else return FALSE; } static CoglPixelFormat _cogl_texture_2d_get_format (CoglTexture *tex) { return COGL_TEXTURE_2D (tex)->internal_format; } static GLenum _cogl_texture_2d_get_gl_format (CoglTexture *tex) { return COGL_TEXTURE_2D (tex)->gl_internal_format; } static CoglBool _cogl_texture_2d_is_foreign (CoglTexture *tex) { return COGL_TEXTURE_2D (tex)->is_foreign; } static CoglTextureType _cogl_texture_2d_get_type (CoglTexture *tex) { return COGL_TEXTURE_TYPE_2D; } static const CoglTextureVtable cogl_texture_2d_vtable = { TRUE, /* primitive */ _cogl_texture_2d_allocate, _cogl_texture_2d_set_region, _cogl_texture_2d_get_data, NULL, /* foreach_sub_texture_in_region */ _cogl_texture_2d_get_max_waste, _cogl_texture_2d_is_sliced, _cogl_texture_2d_can_hardware_repeat, _cogl_texture_2d_transform_coords_to_gl, _cogl_texture_2d_transform_quad_coords_to_gl, _cogl_texture_2d_get_gl_texture, _cogl_texture_2d_gl_flush_legacy_texobj_filters, _cogl_texture_2d_pre_paint, _cogl_texture_2d_ensure_non_quad_rendering, _cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes, _cogl_texture_2d_get_format, _cogl_texture_2d_get_gl_format, _cogl_texture_2d_get_type, _cogl_texture_2d_is_foreign, _cogl_texture_2d_set_auto_mipmap }; muffin-5.2.1/cogl/cogl/cogl-fence.h0000664000175000017500000001100514211404421017154 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_FENCE_H__ #define __COGL_FENCE_H__ #include #include /** * SECTION:cogl-fence * @short_description: Functions for notification of command completion * * Cogl allows notification of GPU command completion; users may mark * points in the GPU command stream and receive notification when the GPU * has executed to that point. */ /** * CoglFence: * * An opaque object representing a fence. This type is currently * unused but in the future may be used to pass extra information * about the fence completion. * * Since: 2.0 * Stability: Unstable */ typedef struct _CoglFence CoglFence; /** * CoglFenceCallback: * @fence: Unused. In the future this parameter may be used to pass * extra information about the fence completion but for now it * should be ignored. * @user_data: The private data passed to cogl_framebuffer_add_fence_callback() * * The callback prototype used with * cogl_framebuffer_add_fence_callback() for notification of GPU * command completion. * * Since: 2.0 * Stability: Unstable */ typedef void (* CoglFenceCallback) (CoglFence *fence, void *user_data); /** * CoglFenceClosure: * * An opaque type representing one future callback to be made when the * GPU command stream has passed a certain point. * * Since: 2.0 * Stability: Unstable */ typedef struct _CoglFenceClosure CoglFenceClosure; /** * cogl_frame_closure_get_user_data: * @closure: A #CoglFenceClosure returned from cogl_framebuffer_add_fence() * * Returns the user_data submitted to cogl_framebuffer_add_fence() which * returned a given #CoglFenceClosure. * * Since: 2.0 * Stability: Unstable */ void * cogl_fence_closure_get_user_data (CoglFenceClosure *closure); /** * cogl_framebuffer_add_fence_callback: * @framebuffer: The #CoglFramebuffer the commands have been submitted to * @callback: (scope notified): A #CoglFenceCallback to be called when * all commands submitted to Cogl have been executed * @user_data: (closure): Private data that will be passed to the callback * * Calls the provided callback when all previously-submitted commands have * been executed by the GPU. * * Returns non-NULL if the fence succeeded, or %NULL if it was unable to * be inserted and the callback will never be called. The user does not * need to free the closure; it will be freed automatically when the * callback is called, or cancelled. * * Since: 2.0 * Stability: Unstable */ CoglFenceClosure * cogl_framebuffer_add_fence_callback (CoglFramebuffer *framebuffer, CoglFenceCallback callback, void *user_data); /** * cogl_framebuffer_cancel_fence_callback: * @framebuffer: The #CoglFramebuffer the commands were submitted to * @closure: The #CoglFenceClosure returned from * cogl_framebuffer_add_fence_callback() * * Removes a fence previously submitted with * cogl_framebuffer_add_fence_callback(); the callback will not be * called. * * Since: 2.0 * Stability: Unstable */ void cogl_framebuffer_cancel_fence_callback (CoglFramebuffer *framebuffer, CoglFenceClosure *closure); #endif /* __COGL_FENCE_H__ */ muffin-5.2.1/cogl/cogl/cogl-list.h0000664000175000017500000001215514211404421017056 0ustar jpeisachjpeisach/* * Copyright © 2008 Kristian Høgsberg * Copyright © 2012, 2013 Intel Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting documentation, and * that the name of the copyright holders not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no representations * about the suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ /* This list implementation is based on the Wayland source code */ #ifndef COGL_LIST_H #define COGL_LIST_H #include /** * CoglList - linked list * * The list head is of "CoglList" type, and must be initialized * using cogl_list_init(). All entries in the list must be of the same * type. The item type must have a "CoglList" member. This * member will be initialized by cogl_list_insert(). There is no need to * call cogl_list_init() on the individual item. To query if the list is * empty in O(1), use cogl_list_empty(). * * Let's call the list reference "CoglList foo_list", the item type as * "item_t", and the item member as "CoglList link". The following code * * The following code will initialize a list: * * cogl_list_init (foo_list); * cogl_list_insert (foo_list, item1); Pushes item1 at the head * cogl_list_insert (foo_list, item2); Pushes item2 at the head * cogl_list_insert (item2, item3); Pushes item3 after item2 * * The list now looks like [item2, item3, item1] * * Will iterate the list in ascending order: * * item_t *item; * cogl_list_for_each(item, foo_list, link) { * Do_something_with_item(item); * } */ typedef struct _CoglList CoglList; struct _CoglList { CoglList *prev; CoglList *next; }; void _cogl_list_init (CoglList *list); void _cogl_list_insert (CoglList *list, CoglList *elm); void _cogl_list_remove (CoglList *elm); int _cogl_list_length (CoglList *list); int _cogl_list_empty (CoglList *list); void _cogl_list_insert_list (CoglList *list, CoglList *other); /* This assigns to iterator first so that taking a reference to it * later in the second step won't be an undefined operation. It * assigns the value of list_node rather than 0 so that it is possible * have list_node be based on the previous value of iterator. In that * respect iterator is just used as a convenient temporary variable. * The compiler optimises all of this down to a single subtraction by * a constant */ #define _cogl_list_set_iterator(list_node, iterator, member) \ ((iterator) = (void *) (list_node), \ (iterator) = (void *) ((char *) (iterator) - \ (((char *) &(iterator)->member) - \ (char *) (iterator)))) #define _cogl_container_of(ptr, type, member) \ (type *) ((char *) (ptr) - offsetof (type, member)) #define _cogl_list_for_each(pos, head, member) \ for (_cogl_list_set_iterator ((head)->next, pos, member); \ &pos->member != (head); \ _cogl_list_set_iterator (pos->member.next, pos, member)) #define _cogl_list_for_each_safe(pos, tmp, head, member) \ for (_cogl_list_set_iterator ((head)->next, pos, member), \ _cogl_list_set_iterator ((pos)->member.next, tmp, member); \ &pos->member != (head); \ pos = tmp, \ _cogl_list_set_iterator (pos->member.next, tmp, member)) #define _cogl_list_for_each_reverse(pos, head, member) \ for (_cogl_list_set_iterator ((head)->prev, pos, member); \ &pos->member != (head); \ _cogl_list_set_iterator (pos->member.prev, pos, member)) #define _cogl_list_for_each_reverse_safe(pos, tmp, head, member) \ for (_cogl_list_set_iterator ((head)->prev, pos, member), \ _cogl_list_set_iterator ((pos)->member.prev, tmp, member); \ &pos->member != (head); \ pos = tmp, \ _cogl_list_set_iterator (pos->member.prev, tmp, member)) #endif /* COGL_LIST_H */ muffin-5.2.1/cogl/cogl/cogl-config-private.h0000664000175000017500000000302314211404421021012 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_CONFIG_PRIVATE_H #define __COGL_CONFIG_PRIVATE_H void _cogl_config_read (void); extern char *_cogl_config_driver; extern char *_cogl_config_renderer; extern char *_cogl_config_disable_gl_extensions; extern char *_cogl_config_override_gl_version; #endif /* __COGL_CONFIG_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-bitmap-packing.h0000664000175000017500000005521514211404421020775 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This file is included multiple times with different definitions for the component_type type (either uint8_t or uint16_t). The code ends up exactly the same for both but we only want to end up hitting the 16-bit path when one of the types in the conversion is > 8 bits per component. */ /* Unpacking to RGBA */ #define UNPACK_1(b) ((b) * ((1 << (sizeof (component_type) * 8)) - 1)) #define UNPACK_2(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ 1) / 3) #define UNPACK_4(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ 7) / 15) #define UNPACK_5(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ 15) / 31) #define UNPACK_6(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ 31) / 63) #define UNPACK_10(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ 511) / 1023) inline static void G_PASTE (_cogl_unpack_a_8_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = 0; dst[1] = 0; dst[2] = 0; dst[3] = UNPACK_BYTE (*src); dst += 4; src++; } } inline static void G_PASTE (_cogl_unpack_g_8_, component_size) (const uint8_t *src, component_type *dst, int width) { /* FIXME: I'm not sure if this is right. It looks like Nvidia and Mesa handle luminance textures differently. Maybe we should consider just removing luminance textures for Cogl 2.0 because they have been removed in GL 3.0 */ while (width-- > 0) { component_type v = UNPACK_BYTE (src[0]); dst[0] = v; dst[1] = v; dst[2] = v; dst[3] = UNPACK_BYTE (255); dst += 4; src++; } } inline static void G_PASTE (_cogl_unpack_rg_88_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = UNPACK_BYTE (src[0]); dst[1] = UNPACK_BYTE (src[1]); dst[2] = 0; dst[3] = UNPACK_BYTE (255); dst += 4; src += 2; } } inline static void G_PASTE (_cogl_unpack_rgb_888_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = UNPACK_BYTE (src[0]); dst[1] = UNPACK_BYTE (src[1]); dst[2] = UNPACK_BYTE (src[2]); dst[3] = UNPACK_BYTE (255); dst += 4; src += 3; } } inline static void G_PASTE (_cogl_unpack_bgr_888_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = UNPACK_BYTE (src[2]); dst[1] = UNPACK_BYTE (src[1]); dst[2] = UNPACK_BYTE (src[0]); dst[3] = UNPACK_BYTE (255); dst += 4; src += 3; } } inline static void G_PASTE (_cogl_unpack_bgra_8888_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = UNPACK_BYTE (src[2]); dst[1] = UNPACK_BYTE (src[1]); dst[2] = UNPACK_BYTE (src[0]); dst[3] = UNPACK_BYTE (src[3]); dst += 4; src += 4; } } inline static void G_PASTE (_cogl_unpack_argb_8888_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = UNPACK_BYTE (src[1]); dst[1] = UNPACK_BYTE (src[2]); dst[2] = UNPACK_BYTE (src[3]); dst[3] = UNPACK_BYTE (src[0]); dst += 4; src += 4; } } inline static void G_PASTE (_cogl_unpack_abgr_8888_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = UNPACK_BYTE (src[3]); dst[1] = UNPACK_BYTE (src[2]); dst[2] = UNPACK_BYTE (src[1]); dst[3] = UNPACK_BYTE (src[0]); dst += 4; src += 4; } } inline static void G_PASTE (_cogl_unpack_rgba_8888_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { dst[0] = UNPACK_BYTE (src[0]); dst[1] = UNPACK_BYTE (src[1]); dst[2] = UNPACK_BYTE (src[2]); dst[3] = UNPACK_BYTE (src[3]); dst += 4; src += 4; } } inline static void G_PASTE (_cogl_unpack_rgb_565_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { uint16_t v = *(const uint16_t *) src; dst[0] = UNPACK_5 (v >> 11); dst[1] = UNPACK_6 ((v >> 5) & 63); dst[2] = UNPACK_5 (v & 31); dst[3] = UNPACK_BYTE (255); dst += 4; src += 2; } } inline static void G_PASTE (_cogl_unpack_rgba_4444_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { uint16_t v = *(const uint16_t *) src; dst[0] = UNPACK_4 (v >> 12); dst[1] = UNPACK_4 ((v >> 8) & 15); dst[2] = UNPACK_4 ((v >> 4) & 15); dst[3] = UNPACK_4 (v & 15); dst += 4; src += 2; } } inline static void G_PASTE (_cogl_unpack_rgba_5551_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { uint16_t v = *(const uint16_t *) src; dst[0] = UNPACK_5 (v >> 11); dst[1] = UNPACK_5 ((v >> 6) & 31); dst[2] = UNPACK_5 ((v >> 1) & 31); dst[3] = UNPACK_1 (v & 1); dst += 4; src += 2; } } inline static void G_PASTE (_cogl_unpack_rgba_1010102_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { uint32_t v = *(const uint32_t *) src; dst[0] = UNPACK_10 (v >> 22); dst[1] = UNPACK_10 ((v >> 12) & 1023); dst[2] = UNPACK_10 ((v >> 2) & 1023); dst[3] = UNPACK_2 (v & 3); dst += 4; src += 2; } } inline static void G_PASTE (_cogl_unpack_bgra_1010102_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { uint32_t v = *(const uint32_t *) src; dst[2] = UNPACK_10 (v >> 22); dst[1] = UNPACK_10 ((v >> 12) & 1023); dst[0] = UNPACK_10 ((v >> 2) & 1023); dst[3] = UNPACK_2 (v & 3); dst += 4; src += 2; } } inline static void G_PASTE (_cogl_unpack_argb_2101010_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { uint32_t v = *(const uint32_t *) src; dst[3] = UNPACK_2 (v >> 30); dst[0] = UNPACK_10 ((v >> 20) & 1023); dst[1] = UNPACK_10 ((v >> 10) & 1023); dst[2] = UNPACK_10 (v & 1023); dst += 4; src += 2; } } inline static void G_PASTE (_cogl_unpack_abgr_2101010_, component_size) (const uint8_t *src, component_type *dst, int width) { while (width-- > 0) { uint32_t v = *(const uint32_t *) src; dst[3] = UNPACK_2 (v >> 30); dst[2] = UNPACK_10 ((v >> 20) & 1023); dst[1] = UNPACK_10 ((v >> 10) & 1023); dst[0] = UNPACK_10 (v & 1023); dst += 4; src += 2; } } #undef UNPACK_1 #undef UNPACK_2 #undef UNPACK_4 #undef UNPACK_5 #undef UNPACK_6 #undef UNPACK_10 inline static void G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format, const uint8_t *src, component_type *dst, int width) { switch (format) { case COGL_PIXEL_FORMAT_A_8: G_PASTE (_cogl_unpack_a_8_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_G_8: G_PASTE (_cogl_unpack_g_8_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RG_88: G_PASTE (_cogl_unpack_rg_88_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGB_888: G_PASTE (_cogl_unpack_rgb_888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_BGR_888: G_PASTE (_cogl_unpack_bgr_888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_8888: case COGL_PIXEL_FORMAT_RGBA_8888_PRE: G_PASTE (_cogl_unpack_rgba_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_BGRA_8888: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: G_PASTE (_cogl_unpack_bgra_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ARGB_8888: case COGL_PIXEL_FORMAT_ARGB_8888_PRE: G_PASTE (_cogl_unpack_argb_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ABGR_8888: case COGL_PIXEL_FORMAT_ABGR_8888_PRE: G_PASTE (_cogl_unpack_abgr_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGB_565: G_PASTE (_cogl_unpack_rgb_565_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_4444: case COGL_PIXEL_FORMAT_RGBA_4444_PRE: G_PASTE (_cogl_unpack_rgba_4444_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_5551: case COGL_PIXEL_FORMAT_RGBA_5551_PRE: G_PASTE (_cogl_unpack_rgba_5551_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_1010102: case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: G_PASTE (_cogl_unpack_rgba_1010102_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_BGRA_1010102: case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: G_PASTE (_cogl_unpack_bgra_1010102_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ARGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: G_PASTE (_cogl_unpack_argb_2101010_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ABGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: G_PASTE (_cogl_unpack_abgr_2101010_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_DEPTH_16: case COGL_PIXEL_FORMAT_DEPTH_32: case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: case COGL_PIXEL_FORMAT_ANY: case COGL_PIXEL_FORMAT_YUV: g_assert_not_reached (); } } /* Packing from RGBA */ /* Pack and round to nearest */ #define PACK_SIZE(b, max) \ (((b) * (max) + (1 << (sizeof (component_type) * 8 - 1)) - 1) / \ ((1 << (sizeof (component_type) * 8)) - 1)) #define PACK_1(b) PACK_SIZE (b, 1) #define PACK_2(b) PACK_SIZE (b, 3) #define PACK_4(b) PACK_SIZE (b, 15) #define PACK_5(b) PACK_SIZE (b, 31) #define PACK_6(b) PACK_SIZE (b, 63) #define PACK_10(b) PACK_SIZE (b, 1023) inline static void G_PASTE (_cogl_pack_a_8_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { *dst = PACK_BYTE (src[3]); src += 4; dst++; } } inline static void G_PASTE (_cogl_pack_g_8_, component_size) (const component_type *src, uint8_t *dst, int width) { /* FIXME: I'm not sure if this is right. It looks like Nvidia and Mesa handle luminance textures differently. Maybe we should consider just removing luminance textures for Cogl 2.0 because they have been removed in GL 3.0 */ while (width-- > 0) { component_type v = (src[0] + src[1] + src[2]) / 3; *dst = PACK_BYTE (v); src += 4; dst++; } } inline static void G_PASTE (_cogl_pack_rg_88_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { dst[0] = PACK_BYTE (src[0]); dst[1] = PACK_BYTE (src[1]); src += 4; dst += 2; } } inline static void G_PASTE (_cogl_pack_rgb_888_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { dst[0] = PACK_BYTE (src[0]); dst[1] = PACK_BYTE (src[1]); dst[2] = PACK_BYTE (src[2]); src += 4; dst += 3; } } inline static void G_PASTE (_cogl_pack_bgr_888_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { dst[2] = PACK_BYTE (src[0]); dst[1] = PACK_BYTE (src[1]); dst[0] = PACK_BYTE (src[2]); src += 4; dst += 3; } } inline static void G_PASTE (_cogl_pack_bgra_8888_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { dst[2] = PACK_BYTE (src[0]); dst[1] = PACK_BYTE (src[1]); dst[0] = PACK_BYTE (src[2]); dst[3] = PACK_BYTE (src[3]); src += 4; dst += 4; } } inline static void G_PASTE (_cogl_pack_argb_8888_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { dst[1] = PACK_BYTE (src[0]); dst[2] = PACK_BYTE (src[1]); dst[3] = PACK_BYTE (src[2]); dst[0] = PACK_BYTE (src[3]); src += 4; dst += 4; } } inline static void G_PASTE (_cogl_pack_abgr_8888_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { dst[3] = PACK_BYTE (src[0]); dst[2] = PACK_BYTE (src[1]); dst[1] = PACK_BYTE (src[2]); dst[0] = PACK_BYTE (src[3]); src += 4; dst += 4; } } inline static void G_PASTE (_cogl_pack_rgba_8888_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { dst[0] = PACK_BYTE (src[0]); dst[1] = PACK_BYTE (src[1]); dst[2] = PACK_BYTE (src[2]); dst[3] = PACK_BYTE (src[3]); src += 4; dst += 4; } } inline static void G_PASTE (_cogl_pack_rgb_565_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { uint16_t *v = (uint16_t *) dst; *v = ((PACK_5 (src[0]) << 11) | (PACK_6 (src[1]) << 5) | PACK_5 (src[2])); src += 4; dst += 2; } } inline static void G_PASTE (_cogl_pack_rgba_4444_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { uint16_t *v = (uint16_t *) dst; *v = ((PACK_4 (src[0]) << 12) | (PACK_4 (src[1]) << 8) | (PACK_4 (src[2]) << 4) | PACK_4 (src[3])); src += 4; dst += 2; } } inline static void G_PASTE (_cogl_pack_rgba_5551_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { uint16_t *v = (uint16_t *) dst; *v = ((PACK_5 (src[0]) << 11) | (PACK_5 (src[1]) << 6) | (PACK_5 (src[2]) << 1) | PACK_1 (src[3])); src += 4; dst += 2; } } inline static void G_PASTE (_cogl_pack_rgba_1010102_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { uint32_t *v = (uint32_t *) dst; *v = ((PACK_10 (src[0]) << 22) | (PACK_10 (src[1]) << 12) | (PACK_10 (src[2]) << 2) | PACK_2 (src[3])); src += 4; dst += 4; } } inline static void G_PASTE (_cogl_pack_bgra_1010102_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { uint32_t *v = (uint32_t *) dst; *v = ((PACK_10 (src[2]) << 22) | (PACK_10 (src[1]) << 12) | (PACK_10 (src[0]) << 2) | PACK_2 (src[3])); src += 4; dst += 4; } } inline static void G_PASTE (_cogl_pack_argb_2101010_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { uint32_t *v = (uint32_t *) dst; *v = ((PACK_2 (src[3]) << 30) | (PACK_10 (src[0]) << 20) | (PACK_10 (src[1]) << 10) | PACK_10 (src[2])); src += 4; dst += 4; } } inline static void G_PASTE (_cogl_pack_abgr_2101010_, component_size) (const component_type *src, uint8_t *dst, int width) { while (width-- > 0) { uint32_t *v = (uint32_t *) dst; *v = ((PACK_2 (src[3]) << 30) | (PACK_10 (src[2]) << 20) | (PACK_10 (src[1]) << 10) | PACK_10 (src[0])); src += 4; dst += 4; } } #undef PACK_SIZE #undef PACK_1 #undef PACK_2 #undef PACK_4 #undef PACK_5 #undef PACK_6 #undef PACK_10 inline static void G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format, const component_type *src, uint8_t *dst, int width) { switch (format) { case COGL_PIXEL_FORMAT_A_8: G_PASTE (_cogl_pack_a_8_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_G_8: G_PASTE (_cogl_pack_g_8_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RG_88: G_PASTE (_cogl_pack_rg_88_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGB_888: G_PASTE (_cogl_pack_rgb_888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_BGR_888: G_PASTE (_cogl_pack_bgr_888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_8888: case COGL_PIXEL_FORMAT_RGBA_8888_PRE: G_PASTE (_cogl_pack_rgba_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_BGRA_8888: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: G_PASTE (_cogl_pack_bgra_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ARGB_8888: case COGL_PIXEL_FORMAT_ARGB_8888_PRE: G_PASTE (_cogl_pack_argb_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ABGR_8888: case COGL_PIXEL_FORMAT_ABGR_8888_PRE: G_PASTE (_cogl_pack_abgr_8888_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGB_565: G_PASTE (_cogl_pack_rgb_565_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_4444: case COGL_PIXEL_FORMAT_RGBA_4444_PRE: G_PASTE (_cogl_pack_rgba_4444_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_5551: case COGL_PIXEL_FORMAT_RGBA_5551_PRE: G_PASTE (_cogl_pack_rgba_5551_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_RGBA_1010102: case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: G_PASTE (_cogl_pack_rgba_1010102_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_BGRA_1010102: case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: G_PASTE (_cogl_pack_bgra_1010102_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ARGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: G_PASTE (_cogl_pack_argb_2101010_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_ABGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: G_PASTE (_cogl_pack_abgr_2101010_, component_size) (src, dst, width); break; case COGL_PIXEL_FORMAT_DEPTH_16: case COGL_PIXEL_FORMAT_DEPTH_32: case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: case COGL_PIXEL_FORMAT_ANY: case COGL_PIXEL_FORMAT_YUV: g_assert_not_reached (); } } muffin-5.2.1/cogl/cogl/cogl-fence.c0000664000175000017500000001467014211404421017162 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-fence.h" #include "cogl-fence-private.h" #include "cogl-context-private.h" #include "cogl-winsys-private.h" #define FENCE_CHECK_TIMEOUT 5000 /* microseconds */ void * cogl_fence_closure_get_user_data (CoglFenceClosure *closure) { return closure->user_data; } static void _cogl_fence_check (CoglFenceClosure *fence) { CoglContext *context = fence->framebuffer->context; if (fence->type == FENCE_TYPE_WINSYS) { const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context); CoglBool ret; ret = winsys->fence_is_complete (context, fence->fence_obj); if (!ret) return; } #ifdef GL_ARB_sync else if (fence->type == FENCE_TYPE_GL_ARB) { GLenum arb; arb = context->glClientWaitSync (fence->fence_obj, GL_SYNC_FLUSH_COMMANDS_BIT, 0); if (arb != GL_ALREADY_SIGNALED && arb != GL_CONDITION_SATISFIED) return; } #endif fence->callback (NULL, /* dummy CoglFence object */ fence->user_data); cogl_framebuffer_cancel_fence_callback (fence->framebuffer, fence); } static void _cogl_fence_poll_dispatch (void *source, int revents) { CoglContext *context = source; CoglFenceClosure *fence, *tmp; _cogl_list_for_each_safe (fence, tmp, &context->fences, link) _cogl_fence_check (fence); } static int64_t _cogl_fence_poll_prepare (void *source) { CoglContext *context = source; GList *l; /* If there are any pending fences in any of the journals then we * need to flush the journal otherwise the fence will never be * hit and the main loop might block forever */ for (l = context->framebuffers; l; l = l->next) { CoglFramebuffer *fb = l->data; if (!_cogl_list_empty (&fb->journal->pending_fences)) _cogl_framebuffer_flush_journal (fb); } if (!_cogl_list_empty (&context->fences)) return FENCE_CHECK_TIMEOUT; else return -1; } void _cogl_fence_submit (CoglFenceClosure *fence) { CoglContext *context = fence->framebuffer->context; const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context); fence->type = FENCE_TYPE_ERROR; if (winsys->fence_add) { fence->fence_obj = winsys->fence_add (context); if (fence->fence_obj) { fence->type = FENCE_TYPE_WINSYS; goto done; } } #ifdef GL_ARB_sync if (context->glFenceSync) { fence->fence_obj = context->glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0); if (fence->fence_obj) { fence->type = FENCE_TYPE_GL_ARB; goto done; } } #endif done: _cogl_list_insert (context->fences.prev, &fence->link); if (!context->fences_poll_source) { context->fences_poll_source = _cogl_poll_renderer_add_source (context->display->renderer, _cogl_fence_poll_prepare, _cogl_fence_poll_dispatch, context); } } CoglFenceClosure * cogl_framebuffer_add_fence_callback (CoglFramebuffer *framebuffer, CoglFenceCallback callback, void *user_data) { CoglContext *context = framebuffer->context; CoglJournal *journal = framebuffer->journal; CoglFenceClosure *fence; if (!COGL_FLAGS_GET (context->features, COGL_FEATURE_ID_FENCE)) return NULL; fence = g_slice_new (CoglFenceClosure); fence->framebuffer = framebuffer; fence->callback = callback; fence->user_data = user_data; fence->fence_obj = NULL; if (journal->entries->len) { _cogl_list_insert (journal->pending_fences.prev, &fence->link); fence->type = FENCE_TYPE_PENDING; } else _cogl_fence_submit (fence); return fence; } void cogl_framebuffer_cancel_fence_callback (CoglFramebuffer *framebuffer, CoglFenceClosure *fence) { CoglContext *context = framebuffer->context; if (fence->type == FENCE_TYPE_PENDING) { _cogl_list_remove (&fence->link); } else { _cogl_list_remove (&fence->link); if (fence->type == FENCE_TYPE_WINSYS) { const CoglWinsysVtable *winsys = _cogl_context_get_winsys (context); winsys->fence_destroy (context, fence->fence_obj); } #ifdef GL_ARB_sync else if (fence->type == FENCE_TYPE_GL_ARB) { context->glDeleteSync (fence->fence_obj); } #endif } g_slice_free (CoglFenceClosure, fence); } void _cogl_fence_cancel_fences_for_framebuffer (CoglFramebuffer *framebuffer) { CoglJournal *journal = framebuffer->journal; CoglContext *context = framebuffer->context; CoglFenceClosure *fence, *tmp; while (!_cogl_list_empty (&journal->pending_fences)) { fence = _cogl_container_of (journal->pending_fences.next, CoglFenceClosure, link); cogl_framebuffer_cancel_fence_callback (framebuffer, fence); } _cogl_list_for_each_safe (fence, tmp, &context->fences, link) { if (fence->framebuffer == framebuffer) cogl_framebuffer_cancel_fence_callback (framebuffer, fence); } } muffin-5.2.1/cogl/cogl/cogl-journal-private.h0000664000175000017500000001016614211404421021225 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_JOURNAL_PRIVATE_H #define __COGL_JOURNAL_PRIVATE_H #include "cogl-texture.h" #include "cogl-object-private.h" #include "cogl-clip-stack.h" #include "cogl-fence-private.h" #define COGL_JOURNAL_VBO_POOL_SIZE 8 typedef struct _CoglJournal { CoglObject _parent; /* A pointer the framebuffer that is using this journal. This is only valid when the journal is not empty. It *does* take a reference on the framebuffer. Although this creates a circular reference, the framebuffer has special code to handle the case where the journal is the only thing holding a reference and it will cause the journal to flush */ CoglFramebuffer *framebuffer; GArray *entries; GArray *vertices; size_t needed_vbo_len; /* A pool of attribute buffers is used so that we can avoid repeatedly reallocating buffers. Only one of these buffers at a time will be used by Cogl but we keep more than one alive anyway in case the GL driver is internally using the buffer and it would have to allocate a new one when we start writing to it */ CoglAttributeBuffer *vbo_pool[COGL_JOURNAL_VBO_POOL_SIZE]; /* The next vbo to use from the pool. We just cycle through them in order */ unsigned int next_vbo_in_pool; int fast_read_pixel_count; CoglList pending_fences; } CoglJournal; /* To improve batching of geometry when submitting vertices to OpenGL we * log the texture rectangles we want to draw to a journal, so when we * later flush the journal we aim to batch data, and gl draw calls. */ typedef struct _CoglJournalEntry { CoglPipeline *pipeline; CoglMatrixEntry *modelview_entry; CoglClipStack *clip_stack; /* Offset into ctx->logged_vertices */ size_t array_offset; int n_layers; } CoglJournalEntry; CoglJournal * _cogl_journal_new (CoglFramebuffer *framebuffer); void _cogl_journal_log_quad (CoglJournal *journal, const float *position, CoglPipeline *pipeline, int n_layers, CoglTexture *layer0_override_texture, const float *tex_coords, unsigned int tex_coords_len); void _cogl_journal_flush (CoglJournal *journal); void _cogl_journal_discard (CoglJournal *journal); CoglBool _cogl_journal_all_entries_within_bounds (CoglJournal *journal, float clip_x0, float clip_y0, float clip_x1, float clip_y1); CoglBool _cogl_journal_try_read_pixel (CoglJournal *journal, int x, int y, CoglBitmap *bitmap, CoglBool *found_intersection); CoglBool _cogl_is_journal (void *object); #endif /* __COGL_JOURNAL_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-meta-texture.h0000664000175000017500000002077314211404421020534 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_META_TEXTURE_H__ #define __COGL_META_TEXTURE_H__ #include COGL_BEGIN_DECLS /** * SECTION:cogl-meta-texture * @short_description: Interface for high-level textures built from * low-level textures like #CoglTexture2D and * #CoglTexture3D. * * Cogl helps to make it easy to deal with high level textures such * as #CoglAtlasTextures, #CoglSubTextures, * #CoglTexturePixmapX11 textures and #CoglTexture2DSliced textures * consistently. * * A #CoglMetaTexture is a texture that might internally be * represented by one or more low-level #CoglTextures * such as #CoglTexture2D or #CoglTexture3D. These low-level textures * are the only ones that a GPU really understands but because * applications often want more high-level texture abstractions * (such as storing multiple textures inside one larger "atlas" * texture) it's desirable to be able to deal with these * using a common interface. * * For example the GPU is not able to automatically handle repeating a * texture that is part of a larger atlas texture but if you use * %COGL_PIPELINE_WRAP_MODE_REPEAT with an atlas texture when drawing * with cogl_rectangle() you should see that it "Just Works™" - at * least if you don't use multi-texturing. The reason this works is * because cogl_rectangle() internally understands the #CoglMetaTexture * interface and is able to manually resolve the low-level textures * using this interface and by making multiple draw calls it can * emulate the texture repeat modes. * * Cogl doesn't aim to pretend that meta-textures are just like real * textures because it would get extremely complex to try and emulate * low-level GPU semantics transparently for these textures. The low * level drawing APIs of Cogl, such as cogl_primitive_draw() don't * actually know anything about the #CoglMetaTexture interface and its * the developer's responsibility to resolve all textures referenced * by a #CoglPipeline to low-level textures before drawing. * * If you want to develop custom primitive APIs like * cogl_framebuffer_draw_rectangle() and you want to support drawing * with #CoglAtlasTextures or #CoglSubTextures for * example, then you will need to use this #CoglMetaTexture interface * to be able to resolve high-level textures into low-level textures * before drawing with Cogl's low-level drawing APIs such as * cogl_primitive_draw(). * * Most developers won't need to use this interface directly * but still it is worth understanding the distinction between * low-level and meta textures because you may find other references * in the documentation that detail limitations of using * meta-textures. */ #if defined(__COGL_H_INSIDE__) && !defined(COGL_ENABLE_MUFFIN_API) && \ !defined(COGL_GIR_SCANNING) /* For the public C api we typedef interface types as void to avoid needing * lots of casting in code and instead we will rely on runtime type checking * for these objects. */ typedef void CoglMetaTexture; #else typedef struct _CoglMetaTexture CoglMetaTexture; #define COGL_META_TEXTURE(X) ((CoglMetaTexture *)X) #endif /** * CoglMetaTextureCallback: * @sub_texture: A low-level #CoglTexture making up part of a * #CoglMetaTexture. * @sub_texture_coords: A float 4-tuple ordered like * (tx1,ty1,tx2,ty2) defining what region of the * current @sub_texture maps to a sub-region of a * #CoglMetaTexture. (tx1,ty1) is the top-left * sub-region coordinate and (tx2,ty2) is the * bottom-right. These are low-level texture * coordinates. * @meta_coords: A float 4-tuple ordered like (tx1,ty1,tx2,ty2) * defining what sub-region of a #CoglMetaTexture this * low-level @sub_texture maps too. (tx1,ty1) is * the top-left sub-region coordinate and (tx2,ty2) is * the bottom-right. These are high-level meta-texture * coordinates. * @user_data: A private pointer passed to * cogl_meta_texture_foreach_in_region(). * * A callback used with cogl_meta_texture_foreach_in_region() to * retrieve details of all the low-level #CoglTextures that * make up a given #CoglMetaTexture. * * Since: 1.10 * Stability: unstable */ typedef void (*CoglMetaTextureCallback) (CoglTexture *sub_texture, const float *sub_texture_coords, const float *meta_coords, void *user_data); /** * cogl_meta_texture_foreach_in_region: * @meta_texture: An object implementing the #CoglMetaTexture * interface. * @tx_1: The top-left x coordinate of the region to iterate * @ty_1: The top-left y coordinate of the region to iterate * @tx_2: The bottom-right x coordinate of the region to iterate * @ty_2: The bottom-right y coordinate of the region to iterate * @wrap_s: The wrap mode for the x-axis * @wrap_t: The wrap mode for the y-axis * @callback: A #CoglMetaTextureCallback pointer to be called * for each low-level texture within the specified region. * @user_data: A private pointer that is passed to @callback. * * Allows you to manually iterate the low-level textures that define a * given region of a high-level #CoglMetaTexture. * * For example cogl_texture_2d_sliced_new_with_size() can be used to * create a meta texture that may slice a large image into multiple, * smaller power-of-two sized textures. These high level textures are * not directly understood by a GPU and so this API must be used to * manually resolve the underlying textures for drawing. * * All high level textures (#CoglAtlasTexture, #CoglSubTexture, * #CoglTexturePixmapX11, and #CoglTexture2DSliced) can be handled * consistently using this interface which greately simplifies * implementing primitives that support all texture types. * * For example if you use the cogl_rectangle() API then Cogl will * internally use this API to resolve the low level textures of any * meta textures you have associated with CoglPipeline layers. * * The low level drawing APIs such as cogl_primitive_draw() * don't understand the #CoglMetaTexture interface and so it is your * responsibility to use this API to resolve all CoglPipeline textures * into low-level textures before drawing. * * For each low-level texture that makes up part of the given region * of the @meta_texture, @callback is called specifying how the * low-level texture maps to the original region. * * Since: 1.10 * Stability: unstable */ void cogl_meta_texture_foreach_in_region (CoglMetaTexture *meta_texture, float tx_1, float ty_1, float tx_2, float ty_2, CoglPipelineWrapMode wrap_s, CoglPipelineWrapMode wrap_t, CoglMetaTextureCallback callback, void *user_data); COGL_END_DECLS #endif /* __COGL_META_TEXTURE_H__ */ muffin-5.2.1/cogl/cogl/cogl-deprecated.h0000664000175000017500000000363414211404421020205 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef COGL_DEPRECATED_H #define cogl_color cogl_color_REPLACED_BY_cogl_set_source_color #define cogl_enable_depth_test cogl_enable_depth_test_RENAMED_TO_cogl_set_depth_test_enabled #define cogl_enable_backface_culling cogl_enable_backface_culling_RENAMED_TO_cogl_set_backface_culling_enabled #define cogl_texture_rectangle cogl_texture_rectangle_REPLACE_BY_cogl_set_source_texture_AND_cogl_rectangle_with_texture_coords #define cogl_texture_multiple_rectangles cogl_texture_multiple_rectangles_REPLACED_BY_cogl_set_source_texture_AND_cogl_rectangles_with_texture_coords #define cogl_texture_polygon cogl_texture_polygon_REPLACED_BY_cogl_set_source_texture_AND_cogl_polygon #endif muffin-5.2.1/cogl/cogl/cogl-node-private.h0000664000175000017500000000563014211404421020500 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_NODE_PRIVATE_H #define __COGL_NODE_PRIVATE_H #include "cogl-object-private.h" #include "cogl-list.h" typedef struct _CoglNode CoglNode; /* Pipelines and layers represent their state in a tree structure where * some of the state relating to a given pipeline or layer may actually * be owned by one if is ancestors in the tree. We have a common data * type to track the tree heirachy so we can share code... */ struct _CoglNode { /* the parent in terms of class hierarchy, so anything inheriting * from CoglNode also inherits from CoglObject. */ CoglObject _parent; /* The parent pipeline/layer */ CoglNode *parent; /* The list entry here contains pointers to the node's siblings */ CoglList link; /* List of children */ CoglList children; /* TRUE if the node took a strong reference on its parent. Weak * pipelines for instance don't take a reference on their parent. */ CoglBool has_parent_reference; }; #define COGL_NODE(X) ((CoglNode *)(X)) void _cogl_pipeline_node_init (CoglNode *node); typedef void (*CoglNodeUnparentVFunc) (CoglNode *node); void _cogl_pipeline_node_set_parent_real (CoglNode *node, CoglNode *parent, CoglNodeUnparentVFunc unparent, CoglBool take_strong_reference); void _cogl_pipeline_node_unparent_real (CoglNode *node); typedef CoglBool (*CoglNodeChildCallback) (CoglNode *child, void *user_data); void _cogl_pipeline_node_foreach_child (CoglNode *node, CoglNodeChildCallback callback, void *user_data); #endif /* __COGL_NODE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-poll-private.h0000664000175000017500000000534714211404421020526 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_POLL_PRIVATE_H__ #define __COGL_POLL_PRIVATE_H__ #include "cogl-poll.h" #include "cogl-renderer.h" #include "cogl-closure-list-private.h" void _cogl_poll_renderer_remove_fd (CoglRenderer *renderer, int fd); typedef int64_t (*CoglPollPrepareCallback) (void *user_data); typedef void (*CoglPollDispatchCallback) (void *user_data, int revents); void _cogl_poll_renderer_add_fd (CoglRenderer *renderer, int fd, CoglPollFDEvent events, CoglPollPrepareCallback prepare, CoglPollDispatchCallback dispatch, void *user_data); void _cogl_poll_renderer_modify_fd (CoglRenderer *renderer, int fd, CoglPollFDEvent events); typedef struct _CoglPollSource CoglPollSource; CoglPollSource * _cogl_poll_renderer_add_source (CoglRenderer *renderer, CoglPollPrepareCallback prepare, CoglPollDispatchCallback dispatch, void *user_data); void _cogl_poll_renderer_remove_source (CoglRenderer *renderer, CoglPollSource *source); typedef void (*CoglIdleCallback) (void *user_data); CoglClosure * _cogl_poll_renderer_add_idle (CoglRenderer *renderer, CoglIdleCallback idle_cb, void *user_data, CoglUserDataDestroyCallback destroy_cb); #endif /* __COGL_POLL_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-version.h0000664000175000017500000002371214211404421017571 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_VERSION_H__ #define __COGL_VERSION_H__ #include /** * SECTION:cogl-version * @short_description: Macros for determining the version of Cogl being used * * Cogl offers a set of macros for checking the version of the library * at compile time. * * Cogl adds version information to both API deprecations and additions; * by definining the macros %COGL_VERSION_MIN_REQUIRED and * %COGL_VERSION_MAX_ALLOWED, you can specify the range of Cogl versions * whose API you want to use. Functions that were deprecated before, or * introduced after, this range will trigger compiler warnings. For instance, * if we define the following symbols: * * |[ * COGL_VERSION_MIN_REQUIRED = COGL_VERSION_1_6 * COGL_VERSION_MAX_ALLOWED = COGL_VERSION_1_8 * ]| * * and we have the following functions annotated in the Cogl headers: * * |[ * COGL_DEPRECATED_IN_1_4 void cogl_function_A (void); * COGL_DEPRECATED_IN_1_6 void cogl_function_B (void); * COGL_AVAILABLE_IN_1_8 void cogl_function_C (void); * COGL_AVAILABLE_IN_1_10 void cogl_function_D (void); * ]| * * then any application code using the functions above will get the output: * * |[ * cogl_function_A: deprecation warning * cogl_function_B: no warning * cogl_function_C: no warning * cogl_function_D: symbol not available warning * ]| * * It is possible to disable the compiler warnings by defining the macro * %COGL_DISABLE_DEPRECATION_WARNINGS before including the cogl.h * header. */ /** * COGL_VERSION_MAJOR: * * The major version of the Cogl library (1, if %COGL_VERSION is 1.2.3) * * Since: 1.12.0 */ #define COGL_VERSION_MAJOR COGL_VERSION_MAJOR_INTERNAL /** * COGL_VERSION_MINOR: * * The minor version of the Cogl library (2, if %COGL_VERSION is 1.2.3) * * Since: 1.12.0 */ #define COGL_VERSION_MINOR COGL_VERSION_MINOR_INTERNAL /** * COGL_VERSION_MICRO: * * The micro version of the Cogl library (3, if %COGL_VERSION is 1.2.3) * * Since: 1.12.0 */ #define COGL_VERSION_MICRO COGL_VERSION_MICRO_INTERNAL /** * COGL_VERSION_STRING: * * The full version of the Cogl library, in string form (suited for * string concatenation) * * Since: 1.12.0 */ #define COGL_VERSION_STRING COGL_VERSION_STRING_INTERNAL /* Macros to handle compacting a 3-component version number into an * int for quick comparison. This assumes all of the components are <= * 1023 and that an int is >= 31 bits */ #define COGL_VERSION_COMPONENT_BITS 10 #define COGL_VERSION_MAX_COMPONENT_VALUE \ ((1 << COGL_VERSION_COMPONENT_BITS) - 1) /** * COGL_VERSION: * * The Cogl version encoded into a single integer using the * COGL_VERSION_ENCODE() macro. This can be used for quick comparisons * with particular versions. * * Since: 1.12.0 */ #define COGL_VERSION \ COGL_VERSION_ENCODE (COGL_VERSION_MAJOR, \ COGL_VERSION_MINOR, \ COGL_VERSION_MICRO) /** * COGL_VERSION_ENCODE: * @major: The major part of a version number * @minor: The minor part of a version number * @micro: The micro part of a version number * * Encodes a 3 part version number into a single integer. This can be * used to compare the Cogl version. For example if there is a known * bug in Cogl versions between 1.3.2 and 1.3.4 you could use the * following code to provide a workaround: * * |[ * #if COGL_VERSION >= COGL_VERSION_ENCODE (1, 3, 2) && \ * COGL_VERSION <= COGL_VERSION_ENCODE (1, 3, 4) * /* Do the workaround */ * #endif * ]| * * Since: 1.12.0 */ #define COGL_VERSION_ENCODE(major, minor, micro) \ (((major) << (COGL_VERSION_COMPONENT_BITS * 2)) | \ ((minor) << COGL_VERSION_COMPONENT_BITS) \ | (micro)) /** * COGL_VERSION_GET_MAJOR: * @version: An encoded version number * * Extracts the major part of an encoded version number. * * Since: 1.12.0 */ #define COGL_VERSION_GET_MAJOR(version) \ (((version) >> (COGL_VERSION_COMPONENT_BITS * 2)) \ & COGL_VERSION_MAX_COMPONENT_VALUE) /** * COGL_VERSION_GET_MINOR: * @version: An encoded version number * * Extracts the minor part of an encoded version number. * * Since: 1.12.0 */ #define COGL_VERSION_GET_MINOR(version) \ (((version) >> COGL_VERSION_COMPONENT_BITS) & \ COGL_VERSION_MAX_COMPONENT_VALUE) /** * COGL_VERSION_GET_MICRO: * @version: An encoded version number * * Extracts the micro part of an encoded version number. * * Since: 1.12.0 */ #define COGL_VERSION_GET_MICRO(version) \ ((version) & COGL_VERSION_MAX_COMPONENT_VALUE) /** * COGL_VERSION_CHECK: * @major: The major part of a version number * @minor: The minor part of a version number * @micro: The micro part of a version number * * A convenient macro to check whether the Cogl version being compiled * against is at least the given version number. For example if the * function cogl_pipeline_frobnicate was added in version 2.0.1 and * you want to conditionally use that function when it is available, * you could write the following: * * |[ * #if COGL_VERSION_CHECK (2, 0, 1) * cogl_pipeline_frobnicate (pipeline); * #else * /* Frobnication is not supported. Use a red color instead */ * cogl_pipeline_set_color_4f (pipeline, 1.0f, 0.0f, 0.0f, 1.0f); * #endif * ]| * * Return value: %TRUE if the Cogl version being compiled against is * greater than or equal to the given three part version number. * Since: 1.12.0 */ #define COGL_VERSION_CHECK(major, minor, micro) \ (COGL_VERSION >= COGL_VERSION_ENCODE (major, minor, micro)) /** * COGL_VERSION_1_0: * * A macro that evaluates to the 1.0 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_0 (COGL_VERSION_ENCODE (1, 0, 0)) /** * COGL_VERSION_1_2: * * A macro that evaluates to the 1.2 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_2 (COGL_VERSION_ENCODE (1, 2, 0)) /** * COGL_VERSION_1_4: * * A macro that evaluates to the 1.4 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_4 (COGL_VERSION_ENCODE (1, 4, 0)) /** * COGL_VERSION_1_6: * * A macro that evaluates to the 1.6 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_6 (COGL_VERSION_ENCODE (1, 6, 0)) /** * COGL_VERSION_1_8: * * A macro that evaluates to the 1.8 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_8 (COGL_VERSION_ENCODE (1, 8, 0)) /** * COGL_VERSION_1_10: * * A macro that evaluates to the 1.10 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_10 (COGL_VERSION_ENCODE (1, 10, 0)) /** * COGL_VERSION_1_12: * * A macro that evaluates to the 1.12 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_12 (COGL_VERSION_ENCODE (1, 12, 0)) /** * COGL_VERSION_1_14: * * A macro that evaluates to the 1.14 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_14 (COGL_VERSION_ENCODE (1, 14, 0)) /** * COGL_VERSION_1_16: * * A macro that evaluates to the 1.16 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.16 */ #define COGL_VERSION_1_16 (COGL_VERSION_ENCODE (1, 16, 0)) /** * COGL_VERSION_1_18: * * A macro that evaluates to the 1.18 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.18 */ #define COGL_VERSION_1_18 (COGL_VERSION_ENCODE (1, 18, 0)) /** * COGL_VERSION_1_20: * * A macro that evaluates to the 1.20 version of Cogl, in a format * that can be used by the C pre-processor. * * Since: 1.20 */ #define COGL_VERSION_1_20 (COGL_VERSION_ENCODE (1, 20, 0)) /* evaluates to the current stable version; for development cycles, * this means the next stable target */ #if (COGL_VERSION_MINOR_INTERNAL % 2) #define COGL_VERSION_CURRENT_STABLE \ (COGL_VERSION_ENCODE (COGL_VERSION_MAJOR_INTERNAL, \ COGL_VERSION_MINOR_INTERNAL + 1, 0)) #else #define COGL_VERSION_CURRENT_STABLE \ (COGL_VERSION_ENCODE (COGL_VERSION_MAJOR_INTERNAL, \ COGL_VERSION_MINOR_INTERNAL, 0)) #endif /* evaluates to the previous stable version */ #if (COGL_VERSION_MINOR_INTERNAL % 2) #define COGL_VERSION_PREVIOUS_STABLE \ (COGL_VERSION_ENCODE (COGL_VERSION_MAJOR_INTERNAL, \ COGL_VERSION_MINOR_INTERNAL - 1, 0)) #else #define COGL_VERSION_PREVIOUS_STABLE \ (COGL_VERSION_ENCODE (COGL_VERSION_MAJOR_INTERNAL, \ COGL_VERSION_MINOR_INTERNAL - 2, 0)) #endif #endif /* __COGL_VERSION_H__ */ muffin-5.2.1/cogl/cogl/cogl-meta-texture.c0000664000175000017500000005353114211404421020525 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-texture.h" #include "cogl-matrix.h" #include "cogl-spans.h" #include "cogl-meta-texture.h" #include "cogl-texture-rectangle-private.h" #include #include typedef struct _ForeachData { float meta_region_coords[4]; CoglPipelineWrapMode wrap_s; CoglPipelineWrapMode wrap_t; CoglMetaTextureCallback callback; void *user_data; int width; int height; CoglTexture *padded_textures[9]; const float *grid_slice_texture_coords; float slice_offset_s; float slice_offset_t; float slice_range_s; float slice_range_t; } ForeachData; static void padded_grid_repeat_cb (CoglTexture *slice_texture, const float *slice_texture_coords, const float *meta_coords, void *user_data) { ForeachData *data; float mapped_coords[4]; /* Ignore padding slices for the current grid */ if (!slice_texture) return; data = user_data; /* NB: the slice_texture_coords[] we get here will always be * normalized. * * We now need to map the normalized slice_texture_coords[] we have * here back to the real slice coordinates we saved in the previous * stage... */ mapped_coords[0] = slice_texture_coords[0] * data->slice_range_s + data->slice_offset_s; mapped_coords[1] = slice_texture_coords[1] * data->slice_range_t + data->slice_offset_t; mapped_coords[2] = slice_texture_coords[2] * data->slice_range_s + data->slice_offset_s; mapped_coords[3] = slice_texture_coords[3] * data->slice_range_t + data->slice_offset_t; data->callback (slice_texture, mapped_coords, meta_coords, data->user_data); } static int setup_padded_spans (CoglSpan *spans, float start, float end, float range, int *real_index) { int span_index = 0; if (start > 0) { spans[0].start = 0; spans[0].size = start; spans[0].waste = 0; span_index++; spans[1].start = spans[0].size; } else spans[span_index].start = 0; spans[span_index].size = end - start; spans[span_index].waste = 0; *real_index = span_index; span_index++; if (end < range) { spans[span_index].start = spans[span_index - 1].start + spans[span_index - 1].size; spans[span_index].size = range - end; spans[span_index].waste = 0; span_index++; } return span_index; } /* This handles each sub-texture within the range [0,1] of our * original meta texture and repeats each one separately across the * users requested virtual texture coordinates. * * A notable advantage of this approach is that we will batch * together callbacks corresponding to the same underlying slice * together. */ static void create_grid_and_repeat_cb (CoglTexture *slice_texture, const float *slice_texture_coords, const float *meta_coords, void *user_data) { ForeachData *data = user_data; CoglSpan x_spans[3]; int n_x_spans; int x_real_index; CoglSpan y_spans[3]; int n_y_spans; int y_real_index; /* NB: This callback is called for each slice of the meta-texture * in the range [0,1]. * * We define a "padded grid" for each slice of the meta-texture in * the range [0,1]. The x axis and y axis grid lines are defined * using CoglSpans. * * The padded grid maps over the meta-texture coordinates in the * range [0,1] but only contains one valid cell that corresponds to * current slice being iterated and all the surrounding cells just * provide padding. * * Once we've defined our padded grid we then repeat that across * the user's original region, calling their callback whenever * we see our current slice - ignoring padding. * * NB: we can assume meta_coords[] are normalized at this point * since TextureRectangles aren't iterated with this code-path. * * NB: spans are always defined using non-normalized coordinates */ n_x_spans = setup_padded_spans (x_spans, meta_coords[0] * data->width, meta_coords[2] * data->width, data->width, &x_real_index); n_y_spans = setup_padded_spans (y_spans, meta_coords[1] * data->height, meta_coords[3] * data->height, data->height, &y_real_index); data->padded_textures[n_x_spans * y_real_index + x_real_index] = slice_texture; /* Our callback is going to be passed normalized slice texture * coordinates, and we will need to map the range [0,1] to the real * slice_texture_coords we have here... */ data->grid_slice_texture_coords = slice_texture_coords; data->slice_range_s = fabs (data->grid_slice_texture_coords[2] - data->grid_slice_texture_coords[0]); data->slice_range_t = fabs (data->grid_slice_texture_coords[3] - data->grid_slice_texture_coords[1]); data->slice_offset_s = MIN (data->grid_slice_texture_coords[0], data->grid_slice_texture_coords[2]); data->slice_offset_t = MIN (data->grid_slice_texture_coords[1], data->grid_slice_texture_coords[3]); /* Now actually iterate the region the user originally requested * using the current padded grid */ _cogl_texture_spans_foreach_in_region (x_spans, n_x_spans, y_spans, n_y_spans, data->padded_textures, data->meta_region_coords, data->width, data->height, data->wrap_s, data->wrap_t, padded_grid_repeat_cb, data); /* Clear the padded_textures ready for the next iteration */ data->padded_textures[n_x_spans * y_real_index + x_real_index] = NULL; } #define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0) typedef struct _ClampData { float start; float end; CoglBool s_flipped; CoglBool t_flipped; CoglMetaTextureCallback callback; void *user_data; } ClampData; static void clamp_s_cb (CoglTexture *sub_texture, const float *sub_texture_coords, const float *meta_coords, void *user_data) { ClampData *clamp_data = user_data; float mapped_meta_coords[4] = { clamp_data->start, meta_coords[1], clamp_data->end, meta_coords[3] }; if (clamp_data->s_flipped) SWAP (mapped_meta_coords[0], mapped_meta_coords[2]); /* NB: we never need to flip the t coords when dealing with * s-axis clamping so no need to check if ->t_flipped */ clamp_data->callback (sub_texture, sub_texture_coords, mapped_meta_coords, clamp_data->user_data); } static void clamp_t_cb (CoglTexture *sub_texture, const float *sub_texture_coords, const float *meta_coords, void *user_data) { ClampData *clamp_data = user_data; float mapped_meta_coords[4] = { meta_coords[0], clamp_data->start, meta_coords[2], clamp_data->end, }; if (clamp_data->s_flipped) SWAP (mapped_meta_coords[0], mapped_meta_coords[2]); if (clamp_data->t_flipped) SWAP (mapped_meta_coords[1], mapped_meta_coords[3]); clamp_data->callback (sub_texture, sub_texture_coords, mapped_meta_coords, clamp_data->user_data); } static CoglBool foreach_clamped_region (CoglMetaTexture *meta_texture, float *tx_1, float *ty_1, float *tx_2, float *ty_2, CoglPipelineWrapMode wrap_s, CoglPipelineWrapMode wrap_t, CoglMetaTextureCallback callback, void *user_data) { float width = cogl_texture_get_width (COGL_TEXTURE (meta_texture)); ClampData clamp_data; /* Consider that *tx_1 may be > *tx_2 and to simplify things * we just flip them around if that's the case and keep a note * of the fact that they are flipped. */ if (*tx_1 > *tx_2) { SWAP (*tx_1, *tx_2); clamp_data.s_flipped = TRUE; } else clamp_data.s_flipped = FALSE; /* The same goes for ty_1 and ty_2... */ if (*ty_1 > *ty_2) { SWAP (*ty_1, *ty_2); clamp_data.t_flipped = TRUE; } else clamp_data.t_flipped = FALSE; clamp_data.callback = callback; clamp_data.user_data = user_data; if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE) { float max_s_coord; float half_texel_width; /* Consider that rectangle textures have non-normalized * coordinates... */ if (cogl_is_texture_rectangle (meta_texture)) max_s_coord = width; else max_s_coord = 1.0; half_texel_width = max_s_coord / (width * 2); /* Handle any left clamped region */ if (*tx_1 < 0) { clamp_data.start = *tx_1; clamp_data.end = MIN (0, *tx_2);; cogl_meta_texture_foreach_in_region (meta_texture, half_texel_width, *ty_1, half_texel_width, *ty_2, COGL_PIPELINE_WRAP_MODE_REPEAT, wrap_t, clamp_s_cb, &clamp_data); /* Have we handled everything? */ if (*tx_2 <= 0) return TRUE; /* clamp tx_1 since we've handled everything with x < 0 */ *tx_1 = 0; } /* Handle any right clamped region - including the corners */ if (*tx_2 > max_s_coord) { clamp_data.start = MAX (max_s_coord, *tx_1); clamp_data.end = *tx_2; cogl_meta_texture_foreach_in_region (meta_texture, max_s_coord - half_texel_width, *ty_1, max_s_coord - half_texel_width, *ty_2, COGL_PIPELINE_WRAP_MODE_REPEAT, wrap_t, clamp_s_cb, &clamp_data); /* Have we handled everything? */ if (*tx_1 >= max_s_coord) return TRUE; /* clamp tx_2 since we've handled everything with x > * max_s_coord */ *tx_2 = max_s_coord; } } if (wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE) { float height = cogl_texture_get_height (COGL_TEXTURE (meta_texture)); float max_t_coord; float half_texel_height; /* Consider that rectangle textures have non-normalized * coordinates... */ if (cogl_is_texture_rectangle (meta_texture)) max_t_coord = height; else max_t_coord = 1.0; half_texel_height = max_t_coord / (height * 2); /* Handle any top clamped region */ if (*ty_1 < 0) { clamp_data.start = *ty_1; clamp_data.end = MIN (0, *ty_2);; cogl_meta_texture_foreach_in_region (meta_texture, *tx_1, half_texel_height, *tx_2, half_texel_height, wrap_s, COGL_PIPELINE_WRAP_MODE_REPEAT, clamp_t_cb, &clamp_data); /* Have we handled everything? */ if (*tx_2 <= 0) return TRUE; /* clamp ty_1 since we've handled everything with y < 0 */ *ty_1 = 0; } /* Handle any bottom clamped region */ if (*ty_2 > max_t_coord) { clamp_data.start = MAX (max_t_coord, *ty_1);; clamp_data.end = *ty_2; cogl_meta_texture_foreach_in_region (meta_texture, *tx_1, max_t_coord - half_texel_height, *tx_2, max_t_coord - half_texel_height, wrap_s, COGL_PIPELINE_WRAP_MODE_REPEAT, clamp_t_cb, &clamp_data); /* Have we handled everything? */ if (*ty_1 >= max_t_coord) return TRUE; /* clamp ty_2 since we've handled everything with y > * max_t_coord */ *ty_2 = max_t_coord; } } if (clamp_data.s_flipped) SWAP (*tx_1, *tx_2); if (clamp_data.t_flipped) SWAP (*ty_1, *ty_2); return FALSE; } typedef struct _NormalizeData { CoglMetaTextureCallback callback; void *user_data; float s_normalize_factor; float t_normalize_factor; } NormalizeData; static void normalize_meta_coords_cb (CoglTexture *slice_texture, const float *slice_coords, const float *meta_coords, void *user_data) { NormalizeData *data = user_data; float normalized_meta_coords[4] = { meta_coords[0] * data->s_normalize_factor, meta_coords[1] * data->t_normalize_factor, meta_coords[2] * data->s_normalize_factor, meta_coords[3] * data->t_normalize_factor }; data->callback (slice_texture, slice_coords, normalized_meta_coords, data->user_data); } typedef struct _UnNormalizeData { CoglMetaTextureCallback callback; void *user_data; float width; float height; } UnNormalizeData; static void un_normalize_slice_coords_cb (CoglTexture *slice_texture, const float *slice_coords, const float *meta_coords, void *user_data) { UnNormalizeData *data = user_data; float un_normalized_slice_coords[4] = { slice_coords[0] * data->width, slice_coords[1] * data->height, slice_coords[2] * data->width, slice_coords[3] * data->height }; data->callback (slice_texture, un_normalized_slice_coords, meta_coords, data->user_data); } void cogl_meta_texture_foreach_in_region (CoglMetaTexture *meta_texture, float tx_1, float ty_1, float tx_2, float ty_2, CoglPipelineWrapMode wrap_s, CoglPipelineWrapMode wrap_t, CoglMetaTextureCallback callback, void *user_data) { CoglTexture *texture = COGL_TEXTURE (meta_texture); float width = cogl_texture_get_width (texture); float height = cogl_texture_get_height (texture); NormalizeData normalize_data; if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) wrap_s = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) wrap_t = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE || wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE) { CoglBool finished = foreach_clamped_region (meta_texture, &tx_1, &ty_1, &tx_2, &ty_2, wrap_s, wrap_t, callback, user_data); if (finished) return; /* Since clamping has been handled we now want to normalize our * wrap modes we se can assume from this point on we don't * need to consider CLAMP_TO_EDGE. (NB: The spans code will * assert that CLAMP_TO_EDGE isn't requested) */ if (wrap_s == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE) wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT; if (wrap_t == COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE) wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT; } /* It makes things simpler to deal with non-normalized region * coordinates beyond this point and only re-normalize just before * calling the user's callback... */ if (!cogl_is_texture_rectangle (COGL_TEXTURE (meta_texture))) { normalize_data.callback = callback; normalize_data.user_data = user_data; normalize_data.s_normalize_factor = 1.0f / width; normalize_data.t_normalize_factor = 1.0f / height; callback = normalize_meta_coords_cb; user_data = &normalize_data; tx_1 *= width; ty_1 *= height; tx_2 *= width; ty_2 *= height; } /* XXX: at some point this wont be routed through the CoglTexture * vtable, instead there will be a separate CoglMetaTexture * interface vtable. */ if (texture->vtable->foreach_sub_texture_in_region) { ForeachData data; data.meta_region_coords[0] = tx_1; data.meta_region_coords[1] = ty_1; data.meta_region_coords[2] = tx_2; data.meta_region_coords[3] = ty_2; data.wrap_s = wrap_s; data.wrap_t = wrap_t; data.callback = callback; data.user_data = user_data; data.width = width; data.height = height; memset (data.padded_textures, 0, sizeof (data.padded_textures)); /* * 1) We iterate all the slices of the meta-texture only within * the range [0,1]. * * 2) We define a "padded grid" for each slice of the * meta-texture in the range [0,1]. * * The padded grid maps over the meta-texture coordinates in * the range [0,1] but only contains one valid cell that * corresponds to current slice being iterated and all the * surrounding cells just provide padding. * * 3) Once we've defined our padded grid we then repeat that * across the user's original region, calling their callback * whenever we see our current slice - ignoring padding. * * A notable benefit of this design is that repeating a texture * made of multiple slices will result in us repeating each * slice in-turn so the user gets repeat callbacks for the same * texture batched together. For manual emulation of texture * repeats done by drawing geometry this makes it more likely * that we can batch geometry. */ texture->vtable->foreach_sub_texture_in_region (texture, 0, 0, 1, 1, create_grid_and_repeat_cb, &data); } else { CoglSpan x_span = { 0, width, 0 }; CoglSpan y_span = { 0, height, 0 }; float meta_region_coords[4] = { tx_1, ty_1, tx_2, ty_2 }; UnNormalizeData un_normalize_data; /* If we are dealing with a CoglTextureRectangle then we need a shim * callback that un_normalizes the slice coordinates we get from * _cogl_texture_spans_foreach_in_region before passing them to * the user's callback. */ if (cogl_is_texture_rectangle (meta_texture)) { un_normalize_data.callback = callback; un_normalize_data.user_data = user_data; un_normalize_data.width = width; un_normalize_data.height = height; callback = un_normalize_slice_coords_cb; user_data = &un_normalize_data; } _cogl_texture_spans_foreach_in_region (&x_span, 1, &y_span, 1, &texture, meta_region_coords, width, height, wrap_s, wrap_t, callback, user_data); } } #undef SWAP muffin-5.2.1/cogl/cogl/cogl-texture-rectangle-private.h0000664000175000017500000000434314211404421023215 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_TEXTURE_RECTANGLE_H #define __COGL_TEXTURE_RECTANGLE_H #include "cogl-pipeline-private.h" #include "cogl-texture-private.h" #include "cogl-texture-rectangle.h" struct _CoglTextureRectangle { CoglTexture _parent; /* The internal format of the texture represented as a CoglPixelFormat */ CoglPixelFormat internal_format; /* TODO: factor out these OpenGL specific members into some form * of driver private state. */ /* The internal format of the GL texture represented as a GL enum */ GLenum gl_format; /* The texture object number */ GLuint gl_texture; GLenum gl_legacy_texobj_min_filter; GLenum gl_legacy_texobj_mag_filter; GLint gl_legacy_texobj_wrap_mode_s; GLint gl_legacy_texobj_wrap_mode_t; CoglBool is_foreign; }; CoglTextureRectangle * _cogl_texture_rectangle_new_from_foreign (GLuint gl_handle, GLuint width, GLuint height, CoglPixelFormat format); #endif /* __COGL_TEXTURE_RECTANGLE_H */ muffin-5.2.1/cogl/cogl/cogl-matrix.h0000664000175000017500000006164014211404421017412 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_MATRIX_H #define __COGL_MATRIX_H #include #include #include #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-matrix * @short_description: Functions for initializing and manipulating 4x4 matrices * * Matrices are used in Cogl to describe affine model-view transforms, texture * transforms, and projective transforms. This exposes a utility API that can * be used for direct manipulation of these matrices. */ /** * CoglMatrix: * * A CoglMatrix holds a 4x4 transform matrix. This is a single precision, * column-major matrix which means it is compatible with what OpenGL expects. * * A CoglMatrix can represent transforms such as, rotations, scaling, * translation, sheering, and linear projections. You can combine these * transforms by multiplying multiple matrices in the order you want them * applied. * * The transformation of a vertex (x, y, z, w) by a CoglMatrix is given by: * * |[ * x_new = xx * x + xy * y + xz * z + xw * w * y_new = yx * x + yy * y + yz * z + yw * w * z_new = zx * x + zy * y + zz * z + zw * w * w_new = wx * x + wy * y + wz * z + ww * w * ]| * * Where w is normally 1 * * You must consider the members of the CoglMatrix structure read only, * and all matrix modifications must be done via the cogl_matrix API. This * allows Cogl to annotate the matrices internally. Violation of this will give * undefined results. If you need to initialize a matrix with a constant other * than the identity matrix you can use cogl_matrix_init_from_array(). */ struct _CoglMatrix { /* column 0 */ float xx; float yx; float zx; float wx; /* column 1 */ float xy; float yy; float zy; float wy; /* column 2 */ float xz; float yz; float zz; float wz; /* column 3 */ float xw; float yw; float zw; float ww; /*< private >*/ /* Note: we may want to extend this later with private flags * and a cache of the inverse transform matrix. */ float COGL_PRIVATE (inv)[16]; unsigned long COGL_PRIVATE (type); unsigned long COGL_PRIVATE (flags); unsigned long COGL_PRIVATE (_padding3); }; COGL_STRUCT_SIZE_ASSERT (CoglMatrix, 128 + sizeof (unsigned long) * 3); /** * cogl_matrix_init_identity: * @matrix: A 4x4 transformation matrix * * Resets matrix to the identity matrix: * * |[ * .xx=1; .xy=0; .xz=0; .xw=0; * .yx=0; .yy=1; .yz=0; .yw=0; * .zx=0; .zy=0; .zz=1; .zw=0; * .wx=0; .wy=0; .wz=0; .ww=1; * ]| */ void cogl_matrix_init_identity (CoglMatrix *matrix); /** * cogl_matrix_init_translation: * @matrix: A 4x4 transformation matrix * @tx: x coordinate of the translation vector * @ty: y coordinate of the translation vector * @tz: z coordinate of the translation vector * * Resets matrix to the (tx, ty, tz) translation matrix: * * |[ * .xx=1; .xy=0; .xz=0; .xw=tx; * .yx=0; .yy=1; .yz=0; .yw=ty; * .zx=0; .zy=0; .zz=1; .zw=tz; * .wx=0; .wy=0; .wz=0; .ww=1; * ]| * * Since: 2.0 */ void cogl_matrix_init_translation (CoglMatrix *matrix, float tx, float ty, float tz); /** * cogl_matrix_multiply: * @result: The address of a 4x4 matrix to store the result in * @a: A 4x4 transformation matrix * @b: A 4x4 transformation matrix * * Multiplies the two supplied matrices together and stores * the resulting matrix inside @result. * * It is possible to multiply the @a matrix in-place, so * @result can be equal to @a but can't be equal to @b. */ void cogl_matrix_multiply (CoglMatrix *result, const CoglMatrix *a, const CoglMatrix *b); /** * cogl_matrix_rotate: * @matrix: A 4x4 transformation matrix * @angle: The angle you want to rotate in degrees * @x: X component of your rotation vector * @y: Y component of your rotation vector * @z: Z component of your rotation vector * * Multiplies @matrix with a rotation matrix that applies a rotation * of @angle degrees around the specified 3D vector. */ void cogl_matrix_rotate (CoglMatrix *matrix, float angle, float x, float y, float z); /** * cogl_matrix_rotate_quaternion: * @matrix: A 4x4 transformation matrix * @quaternion: A quaternion describing a rotation * * Multiplies @matrix with a rotation transformation described by the * given #CoglQuaternion. * * Since: 2.0 */ void cogl_matrix_rotate_quaternion (CoglMatrix *matrix, const CoglQuaternion *quaternion); /** * cogl_matrix_rotate_euler: * @matrix: A 4x4 transformation matrix * @euler: A euler describing a rotation * * Multiplies @matrix with a rotation transformation described by the * given #CoglEuler. * * Since: 2.0 */ void cogl_matrix_rotate_euler (CoglMatrix *matrix, const CoglEuler *euler); /** * cogl_matrix_translate: * @matrix: A 4x4 transformation matrix * @x: The X translation you want to apply * @y: The Y translation you want to apply * @z: The Z translation you want to apply * * Multiplies @matrix with a transform matrix that translates along * the X, Y and Z axis. */ void cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z); /** * cogl_matrix_scale: * @matrix: A 4x4 transformation matrix * @sx: The X scale factor * @sy: The Y scale factor * @sz: The Z scale factor * * Multiplies @matrix with a transform matrix that scales along the X, * Y and Z axis. */ void cogl_matrix_scale (CoglMatrix *matrix, float sx, float sy, float sz); /** * cogl_matrix_look_at: * @matrix: A 4x4 transformation matrix * @eye_position_x: The X coordinate to look from * @eye_position_y: The Y coordinate to look from * @eye_position_z: The Z coordinate to look from * @object_x: The X coordinate of the object to look at * @object_y: The Y coordinate of the object to look at * @object_z: The Z coordinate of the object to look at * @world_up_x: The X component of the world's up direction vector * @world_up_y: The Y component of the world's up direction vector * @world_up_z: The Z component of the world's up direction vector * * Applies a view transform @matrix that positions the camera at * the coordinate (@eye_position_x, @eye_position_y, @eye_position_z) * looking towards an object at the coordinate (@object_x, @object_y, * @object_z). The top of the camera is aligned to the given world up * vector, which is normally simply (0, 1, 0) to map up to the * positive direction of the y axis. * * Because there is a lot of missleading documentation online for * gluLookAt regarding the up vector we want to try and be a bit * clearer here. * * The up vector should simply be relative to your world coordinates * and does not need to change as you move the eye and object * positions. Many online sources may claim that the up vector needs * to be perpendicular to the vector between the eye and object * position (partly because the man page is somewhat missleading) but * that is not necessary for this function. * * You should never look directly along the world-up * vector. * * It is assumed you are using a typical projection matrix where * your origin maps to the center of your viewport. * * Almost always when you use this function it should be the first * transform applied to a new modelview transform * * Since: 1.8 * Stability: unstable */ void cogl_matrix_look_at (CoglMatrix *matrix, float eye_position_x, float eye_position_y, float eye_position_z, float object_x, float object_y, float object_z, float world_up_x, float world_up_y, float world_up_z); /** * cogl_matrix_frustum: * @matrix: A 4x4 transformation matrix * @left: X position of the left clipping plane where it * intersects the near clipping plane * @right: X position of the right clipping plane where it * intersects the near clipping plane * @bottom: Y position of the bottom clipping plane where it * intersects the near clipping plane * @top: Y position of the top clipping plane where it intersects * the near clipping plane * @z_near: The distance to the near clipping plane (Must be positive) * @z_far: The distance to the far clipping plane (Must be positive) * * Multiplies @matrix by the given frustum perspective matrix. */ void cogl_matrix_frustum (CoglMatrix *matrix, float left, float right, float bottom, float top, float z_near, float z_far); /** * cogl_matrix_perspective: * @matrix: A 4x4 transformation matrix * @fov_y: Vertical field of view angle in degrees. * @aspect: The (width over height) aspect ratio for display * @z_near: The distance to the near clipping plane (Must be positive, * and must not be 0) * @z_far: The distance to the far clipping plane (Must be positive) * * Multiplies @matrix by the described perspective matrix * * You should be careful not to have to great a @z_far / @z_near * ratio since that will reduce the effectiveness of depth testing * since there wont be enough precision to identify the depth of * objects near to each other. */ void cogl_matrix_perspective (CoglMatrix *matrix, float fov_y, float aspect, float z_near, float z_far); /** * cogl_matrix_orthographic: * @matrix: A 4x4 transformation matrix * @x_1: The x coordinate for the first vertical clipping plane * @y_1: The y coordinate for the first horizontal clipping plane * @x_2: The x coordinate for the second vertical clipping plane * @y_2: The y coordinate for the second horizontal clipping plane * @near: The distance to the near clipping * plane (will be negative if the plane is * behind the viewer) * @far: The distance to the far clipping * plane (will be negative if the plane is * behind the viewer) * * Multiplies @matrix by a parallel projection matrix. * * Since: 1.10 * Stability: unstable */ void cogl_matrix_orthographic (CoglMatrix *matrix, float x_1, float y_1, float x_2, float y_2, float near, float far); /** * cogl_matrix_ortho: * @matrix: A 4x4 transformation matrix * @left: The coordinate for the left clipping plane * @right: The coordinate for the right clipping plane * @bottom: The coordinate for the bottom clipping plane * @top: The coordinate for the top clipping plane * @near: The distance to the near clipping * plane (will be negative if the plane is * behind the viewer) * @far: The distance to the far clipping * plane (will be negative if the plane is * behind the viewer) * * Multiplies @matrix by a parallel projection matrix. * * Deprecated: 1.10: Use cogl_matrix_orthographic() */ COGL_DEPRECATED_IN_1_10_FOR (cogl_matrix_orthographic) void cogl_matrix_ortho (CoglMatrix *matrix, float left, float right, float bottom, float top, float near, float far); /** * cogl_matrix_view_2d_in_frustum: * @matrix: A 4x4 transformation matrix * @left: coord of left vertical clipping plane * @right: coord of right vertical clipping plane * @bottom: coord of bottom horizontal clipping plane * @top: coord of top horizontal clipping plane * @z_near: The distance to the near clip plane. Never pass 0 and always pass * a positive number. * @z_2d: The distance to the 2D plane. (Should always be positive and * be between @z_near and the z_far value that was passed to * cogl_matrix_frustum()) * @width_2d: The width of the 2D coordinate system * @height_2d: The height of the 2D coordinate system * * Multiplies @matrix by a view transform that maps the 2D coordinates * (0,0) top left and (@width_2d,@height_2d) bottom right the full viewport * size. Geometry at a depth of 0 will now lie on this 2D plane. * * Note: this doesn't multiply the matrix by any projection matrix, * but it assumes you have a perspective projection as defined by * passing the corresponding arguments to cogl_matrix_frustum(). * Toolkits such as Clutter that mix 2D and 3D drawing can use this to * create a 2D coordinate system within a 3D perspective projected * view frustum. * * Since: 1.8 * Stability: unstable */ void cogl_matrix_view_2d_in_frustum (CoglMatrix *matrix, float left, float right, float bottom, float top, float z_near, float z_2d, float width_2d, float height_2d); /** * cogl_matrix_view_2d_in_perspective: * @fov_y: A field of view angle for the Y axis * @aspect: The ratio of width to height determining the field of view angle * for the x axis. * @z_near: The distance to the near clip plane. Never pass 0 and always pass * a positive number. * @z_2d: The distance to the 2D plane. (Should always be positive and * be between @z_near and the z_far value that was passed to * cogl_matrix_frustum()) * @width_2d: The width of the 2D coordinate system * @height_2d: The height of the 2D coordinate system * * Multiplies @matrix by a view transform that maps the 2D coordinates * (0,0) top left and (@width_2d,@height_2d) bottom right the full viewport * size. Geometry at a depth of 0 will now lie on this 2D plane. * * Note: this doesn't multiply the matrix by any projection matrix, * but it assumes you have a perspective projection as defined by * passing the corresponding arguments to cogl_matrix_perspective(). * * Toolkits such as Clutter that mix 2D and 3D drawing can use this to * create a 2D coordinate system within a 3D perspective projected * view frustum. * * Since: 1.8 * Stability: unstable */ void cogl_matrix_view_2d_in_perspective (CoglMatrix *matrix, float fov_y, float aspect, float z_near, float z_2d, float width_2d, float height_2d); /** * cogl_matrix_init_from_array: * @matrix: A 4x4 transformation matrix * @array: A linear array of 16 floats (column-major order) * * Initializes @matrix with the contents of @array */ void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array); /** * cogl_matrix_get_array: * @matrix: A 4x4 transformation matrix * * Casts @matrix to a float array which can be directly passed to OpenGL. * * Return value: a pointer to the float array */ const float * cogl_matrix_get_array (const CoglMatrix *matrix); /** * cogl_matrix_init_from_quaternion: * @matrix: A 4x4 transformation matrix * @quaternion: A #CoglQuaternion * * Initializes @matrix from a #CoglQuaternion rotation. */ void cogl_matrix_init_from_quaternion (CoglMatrix *matrix, const CoglQuaternion *quaternion); /** * cogl_matrix_init_from_euler: * @matrix: A 4x4 transformation matrix * @euler: A #CoglEuler * * Initializes @matrix from a #CoglEuler rotation. */ void cogl_matrix_init_from_euler (CoglMatrix *matrix, const CoglEuler *euler); /** * cogl_matrix_equal: * @v1: A 4x4 transformation matrix * @v2: A 4x4 transformation matrix * * Compares two matrices to see if they represent the same * transformation. Although internally the matrices may have different * annotations associated with them and may potentially have a cached * inverse matrix these are not considered in the comparison. * * Since: 1.4 */ CoglBool cogl_matrix_equal (const void *v1, const void *v2); /** * cogl_matrix_copy: * @matrix: A 4x4 transformation matrix you want to copy * * Allocates a new #CoglMatrix on the heap and initializes it with * the same values as @matrix. * * Return value: (transfer full): A newly allocated #CoglMatrix which * should be freed using cogl_matrix_free() * * Since: 1.6 */ CoglMatrix * cogl_matrix_copy (const CoglMatrix *matrix); /** * cogl_matrix_free: * @matrix: A 4x4 transformation matrix you want to free * * Frees a #CoglMatrix that was previously allocated via a call to * cogl_matrix_copy(). * * Since: 1.6 */ void cogl_matrix_free (CoglMatrix *matrix); /** * cogl_matrix_get_inverse: * @matrix: A 4x4 transformation matrix * @inverse: (out): The destination for a 4x4 inverse transformation matrix * * Gets the inverse transform of a given matrix and uses it to initialize * a new #CoglMatrix. * * Although the first parameter is annotated as const to indicate * that the transform it represents isn't modified this function may * technically save a copy of the inverse transform within the given * #CoglMatrix so that subsequent requests for the inverse transform may * avoid costly inversion calculations. * * Return value: %TRUE if the inverse was successfully calculated or %FALSE * for degenerate transformations that can't be inverted (in this case the * @inverse matrix will simply be initialized with the identity matrix) * * Since: 1.2 */ CoglBool cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse); /* FIXME: to be consistent with cogl_matrix_{transform,project}_points * this could be renamed to cogl_matrix_project_point for Cogl 2.0... */ /** * cogl_matrix_transform_point: * @matrix: A 4x4 transformation matrix * @x: (inout): The X component of your points position * @y: (inout): The Y component of your points position * @z: (inout): The Z component of your points position * @w: (inout): The W component of your points position * * Transforms a point whos position is given and returned as four float * components. */ void cogl_matrix_transform_point (const CoglMatrix *matrix, float *x, float *y, float *z, float *w); /** * cogl_matrix_transform_points: * @matrix: A transformation matrix * @n_components: The number of position components for each input point. * (either 2 or 3) * @stride_in: The stride in bytes between input points. * @points_in: A pointer to the first component of the first input point. * @stride_out: The stride in bytes between output points. * @points_out: A pointer to the first component of the first output point. * @n_points: The number of points to transform. * * Transforms an array of input points and writes the result to * another array of output points. The input points can either have 2 * or 3 components each. The output points always have 3 components. * The output array can simply point to the input array to do the * transform in-place. * * If you need to transform 4 component points see * cogl_matrix_project_points(). * * Here's an example with differing input/output strides: * |[ * typedef struct { * float x,y; * uint8_t r,g,b,a; * float s,t,p; * } MyInVertex; * typedef struct { * uint8_t r,g,b,a; * float x,y,z; * } MyOutVertex; * MyInVertex vertices[N_VERTICES]; * MyOutVertex results[N_VERTICES]; * CoglMatrix matrix; * * my_load_vertices (vertices); * my_get_matrix (&matrix); * * cogl_matrix_transform_points (&matrix, * 2, * sizeof (MyInVertex), * &vertices[0].x, * sizeof (MyOutVertex), * &results[0].x, * N_VERTICES); * ]| * * Stability: unstable */ void cogl_matrix_transform_points (const CoglMatrix *matrix, int n_components, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points); /** * cogl_matrix_project_points: * @matrix: A projection matrix * @n_components: The number of position components for each input point. * (either 2, 3 or 4) * @stride_in: The stride in bytes between input points. * @points_in: A pointer to the first component of the first input point. * @stride_out: The stride in bytes between output points. * @points_out: A pointer to the first component of the first output point. * @n_points: The number of points to transform. * * Projects an array of input points and writes the result to another * array of output points. The input points can either have 2, 3 or 4 * components each. The output points always have 4 components (known * as homogenous coordinates). The output array can simply point to * the input array to do the transform in-place. * * Here's an example with differing input/output strides: * |[ * typedef struct { * float x,y; * uint8_t r,g,b,a; * float s,t,p; * } MyInVertex; * typedef struct { * uint8_t r,g,b,a; * float x,y,z; * } MyOutVertex; * MyInVertex vertices[N_VERTICES]; * MyOutVertex results[N_VERTICES]; * CoglMatrix matrix; * * my_load_vertices (vertices); * my_get_matrix (&matrix); * * cogl_matrix_project_points (&matrix, * 2, * sizeof (MyInVertex), * &vertices[0].x, * sizeof (MyOutVertex), * &results[0].x, * N_VERTICES); * ]| * * Stability: unstable */ void cogl_matrix_project_points (const CoglMatrix *matrix, int n_components, size_t stride_in, const void *points_in, size_t stride_out, void *points_out, int n_points); /** * cogl_matrix_is_identity: * @matrix: A #CoglMatrix * * Determines if the given matrix is an identity matrix. * * Returns: %TRUE if @matrix is an identity matrix else %FALSE * Since: 1.8 */ CoglBool cogl_matrix_is_identity (const CoglMatrix *matrix); /** * cogl_matrix_transpose: * @matrix: A #CoglMatrix * * Replaces @matrix with its transpose. Ie, every element (i,j) in the * new matrix is taken from element (j,i) in the old matrix. * * Since: 1.10 */ void cogl_matrix_transpose (CoglMatrix *matrix); /** * cogl_debug_matrix_print: * @matrix: A #CoglMatrix * * Prints the contents of a #CoglMatrix to stdout. * * Since: 2.0 */ void cogl_debug_matrix_print (const CoglMatrix *matrix); #define COGL_GTYPE_TYPE_MATRIX (cogl_matrix_get_gtype ()) /** * cogl_matrix_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_matrix_get_gtype (void); /** * cogl_gtype_matrix_get_type: * * Returns: the GType for the registered "CoglMatrix" boxed type. This * can be used for example to define GObject properties that accept a * #CoglMatrix value. * * Deprecated: 1.18: Use cogl_matrix_get_gtype() instead. */ GType cogl_gtype_matrix_get_type (void); COGL_END_DECLS #endif /* __COGL_MATRIX_H */ muffin-5.2.1/cogl/cogl/winsys/0000775000175000017500000000000014211404421016340 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/winsys/cogl-winsys-egl-x11.c0000664000175000017500000007011014211404421022135 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-winsys-egl-x11-private.h" #include "cogl-winsys-egl-private.h" #include "cogl-xlib-renderer-private.h" #include "cogl-xlib-renderer.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-private.h" #include "cogl-display-private.h" #include "cogl-renderer-private.h" #include "cogl-texture-pixmap-x11-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d.h" #include "cogl-error-private.h" #include "cogl-poll-private.h" #define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask) static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable; typedef struct _CoglDisplayXlib { Window dummy_xwin; } CoglDisplayXlib; typedef struct _CoglOnscreenXlib { Window xwin; CoglBool is_foreign_xwin; } CoglOnscreenXlib; #ifdef EGL_KHR_image_pixmap typedef struct _CoglTexturePixmapEGL { EGLImageKHR image; CoglTexture *texture; } CoglTexturePixmapEGL; #endif static CoglOnscreen * find_onscreen_for_xid (CoglContext *context, uint32_t xid) { GList *l; for (l = context->framebuffers; l; l = l->next) { CoglFramebuffer *framebuffer = l->data; CoglOnscreenEGL *egl_onscreen; CoglOnscreenXlib *xlib_onscreen; if (!framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) continue; egl_onscreen = COGL_ONSCREEN (framebuffer)->winsys; xlib_onscreen = egl_onscreen->platform; if (xlib_onscreen->xwin == (Window)xid) return COGL_ONSCREEN (framebuffer); } return NULL; } static void flush_pending_resize_notifications_cb (void *data, void *user_data) { CoglFramebuffer *framebuffer = data; if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) { CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); CoglOnscreenEGL *egl_onscreen = onscreen->winsys; if (egl_onscreen->pending_resize_notify) { _cogl_onscreen_notify_resize (onscreen); egl_onscreen->pending_resize_notify = FALSE; } } } static void flush_pending_resize_notifications_idle (void *user_data) { CoglContext *context = user_data; CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; /* This needs to be disconnected before invoking the callbacks in * case the callbacks cause it to be queued again */ _cogl_closure_disconnect (egl_renderer->resize_notify_idle); egl_renderer->resize_notify_idle = NULL; g_list_foreach (context->framebuffers, flush_pending_resize_notifications_cb, NULL); } static void notify_resize (CoglContext *context, Window drawable, int width, int height) { CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; CoglOnscreen *onscreen = find_onscreen_for_xid (context, drawable); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglOnscreenEGL *egl_onscreen; if (!onscreen) return; egl_onscreen = onscreen->winsys; _cogl_framebuffer_winsys_update_size (framebuffer, width, height); /* We only want to notify that a resize happened when the * application calls cogl_context_dispatch so instead of immediately * notifying we queue an idle callback */ if (!egl_renderer->resize_notify_idle) { egl_renderer->resize_notify_idle = _cogl_poll_renderer_add_idle (renderer, flush_pending_resize_notifications_idle, context, NULL); } egl_onscreen->pending_resize_notify = TRUE; } static CoglFilterReturn event_filter_cb (XEvent *xevent, void *data) { CoglContext *context = data; if (xevent->type == ConfigureNotify) { notify_resize (context, xevent->xconfigure.window, xevent->xconfigure.width, xevent->xconfigure.height); } else if (xevent->type == Expose) { CoglOnscreen *onscreen = find_onscreen_for_xid (context, xevent->xexpose.window); if (onscreen) { CoglOnscreenDirtyInfo info; info.x = xevent->xexpose.x; info.y = xevent->xexpose.y; info.width = xevent->xexpose.width; info.height = xevent->xexpose.height; _cogl_onscreen_queue_dirty (onscreen, &info); } } return COGL_FILTER_CONTINUE; } static XVisualInfo * get_visual_info (CoglDisplay *display, EGLConfig egl_config) { CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); CoglRendererEGL *egl_renderer = display->renderer->winsys; XVisualInfo visinfo_template; int template_mask = 0; XVisualInfo *visinfo = NULL; int visinfos_count; EGLint visualid, red_size, green_size, blue_size, alpha_size; eglGetConfigAttrib (egl_renderer->edpy, egl_config, EGL_NATIVE_VISUAL_ID, &visualid); if (visualid != 0) { visinfo_template.visualid = visualid; template_mask |= VisualIDMask; } else { /* some EGL drivers don't implement the EGL_NATIVE_VISUAL_ID * attribute, so attempt to find the closest match. */ eglGetConfigAttrib (egl_renderer->edpy, egl_config, EGL_RED_SIZE, &red_size); eglGetConfigAttrib (egl_renderer->edpy, egl_config, EGL_GREEN_SIZE, &green_size); eglGetConfigAttrib (egl_renderer->edpy, egl_config, EGL_BLUE_SIZE, &blue_size); eglGetConfigAttrib (egl_renderer->edpy, egl_config, EGL_ALPHA_SIZE, &alpha_size); visinfo_template.depth = red_size + green_size + blue_size + alpha_size; template_mask |= VisualDepthMask; visinfo_template.screen = DefaultScreen (xlib_renderer->xdpy); template_mask |= VisualScreenMask; } visinfo = XGetVisualInfo (xlib_renderer->xdpy, template_mask, &visinfo_template, &visinfos_count); return visinfo; } static void _cogl_winsys_renderer_disconnect (CoglRenderer *renderer) { CoglRendererEGL *egl_renderer = renderer->winsys; _cogl_xlib_renderer_disconnect (renderer); eglTerminate (egl_renderer->edpy); g_slice_free (CoglRendererEGL, egl_renderer); } static EGLDisplay _cogl_winsys_egl_get_display (void *native) { EGLDisplay dpy = NULL; const char *client_exts = eglQueryString (NULL, EGL_EXTENSIONS); if (g_strstr_len (client_exts, -1, "EGL_KHR_platform_base")) { PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = (void *) eglGetProcAddress ("eglGetPlatformDisplay"); if (get_platform_display) dpy = get_platform_display (EGL_PLATFORM_X11_KHR, native, NULL); if (dpy) return dpy; } if (g_strstr_len (client_exts, -1, "EGL_EXT_platform_base")) { PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT"); if (get_platform_display) dpy = get_platform_display (EGL_PLATFORM_X11_KHR, native, NULL); if (dpy) return dpy; } return eglGetDisplay ((EGLNativeDisplayType) native); } static CoglBool _cogl_winsys_renderer_connect (CoglRenderer *renderer, CoglError **error) { CoglRendererEGL *egl_renderer; CoglXlibRenderer *xlib_renderer; renderer->winsys = g_slice_new0 (CoglRendererEGL); egl_renderer = renderer->winsys; xlib_renderer = _cogl_xlib_renderer_get_data (renderer); egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable; if (!_cogl_xlib_renderer_connect (renderer, error)) goto error; egl_renderer->edpy = _cogl_winsys_egl_get_display (xlib_renderer->xdpy); if (!_cogl_winsys_egl_renderer_connect_common (renderer, error)) goto error; return TRUE; error: _cogl_winsys_renderer_disconnect (renderer); return FALSE; } static int _cogl_winsys_egl_add_config_attributes (CoglDisplay *display, CoglFramebufferConfig *config, EGLint *attributes) { int i = 0; attributes[i++] = EGL_SURFACE_TYPE; attributes[i++] = EGL_WINDOW_BIT; return i; } static CoglBool _cogl_winsys_egl_choose_config (CoglDisplay *display, EGLint *attributes, EGLConfig *out_config, CoglError **error) { CoglRenderer *renderer = display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; EGLint config_count = 0; EGLBoolean status; status = eglChooseConfig (egl_renderer->edpy, attributes, out_config, 1, &config_count); if (status != EGL_TRUE || config_count == 0) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "No compatible EGL configs found"); return FALSE; } return TRUE; } static CoglBool _cogl_winsys_egl_display_setup (CoglDisplay *display, CoglError **error) { CoglDisplayEGL *egl_display = display->winsys; CoglDisplayXlib *xlib_display; xlib_display = g_slice_new0 (CoglDisplayXlib); egl_display->platform = xlib_display; return TRUE; } static void _cogl_winsys_egl_display_destroy (CoglDisplay *display) { CoglDisplayEGL *egl_display = display->winsys; g_slice_free (CoglDisplayXlib, egl_display->platform); } static CoglBool _cogl_winsys_egl_context_init (CoglContext *context, CoglError **error) { cogl_xlib_renderer_add_filter (context->display->renderer, event_filter_cb, context); context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE); COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, TRUE); /* We'll manually handle queueing dirty events in response to * Expose events from X */ COGL_FLAGS_SET (context->private_features, COGL_PRIVATE_FEATURE_DIRTY_EVENTS, TRUE); return TRUE; } static void _cogl_winsys_egl_context_deinit (CoglContext *context) { cogl_xlib_renderer_remove_filter (context->display->renderer, event_filter_cb, context); } static CoglBool _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen, EGLConfig egl_config, CoglError **error) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglDisplay *display = context->display; CoglRenderer *renderer = display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); CoglOnscreenXlib *xlib_onscreen; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; Window xwin; /* FIXME: We need to explicitly Select for ConfigureNotify events. * For foreign windows we need to be careful not to mess up any * existing event mask. * We need to document that for windows we create then toolkits * must be careful not to clear event mask bits that we select. */ /* XXX: Note we ignore the user's original width/height when * given a foreign X window. */ if (onscreen->foreign_xid) { Status status; CoglXlibTrapState state; XWindowAttributes attr; int xerror; xwin = onscreen->foreign_xid; _cogl_xlib_renderer_trap_errors (display->renderer, &state); status = XGetWindowAttributes (xlib_renderer->xdpy, xwin, &attr); xerror = _cogl_xlib_renderer_untrap_errors (display->renderer, &state); if (status == 0 || xerror) { char message[1000]; XGetErrorText (xlib_renderer->xdpy, xerror, message, sizeof (message)); _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_ONSCREEN, "Unable to query geometry of foreign " "xid 0x%08lX: %s", xwin, message); return FALSE; } _cogl_framebuffer_winsys_update_size (framebuffer, attr.width, attr.height); /* Make sure the app selects for the events we require... */ onscreen->foreign_update_mask_callback (onscreen, COGL_ONSCREEN_X11_EVENT_MASK, onscreen-> foreign_update_mask_data); } else { int width; int height; CoglXlibTrapState state; XVisualInfo *xvisinfo; XSetWindowAttributes xattr; unsigned long mask; int xerror; width = cogl_framebuffer_get_width (framebuffer); height = cogl_framebuffer_get_height (framebuffer); _cogl_xlib_renderer_trap_errors (display->renderer, &state); xvisinfo = get_visual_info (display, egl_config); if (xvisinfo == NULL) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_ONSCREEN, "Unable to retrieve the X11 visual of context's " "fbconfig"); return FALSE; } /* window attributes */ xattr.background_pixel = WhitePixel (xlib_renderer->xdpy, DefaultScreen (xlib_renderer->xdpy)); xattr.border_pixel = 0; /* XXX: is this an X resource that we are leaking‽... */ xattr.colormap = XCreateColormap (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), xvisinfo->visual, AllocNone); xattr.event_mask = COGL_ONSCREEN_X11_EVENT_MASK; mask = CWBorderPixel | CWColormap | CWEventMask; xwin = XCreateWindow (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), 0, 0, width, height, 0, xvisinfo->depth, InputOutput, xvisinfo->visual, mask, &xattr); XFree (xvisinfo); XSync (xlib_renderer->xdpy, False); xerror = _cogl_xlib_renderer_untrap_errors (display->renderer, &state); if (xerror) { char message[1000]; XGetErrorText (xlib_renderer->xdpy, xerror, message, sizeof (message)); _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_ONSCREEN, "X error while creating Window for CoglOnscreen: %s", message); return FALSE; } } xlib_onscreen = g_slice_new (CoglOnscreenXlib); egl_onscreen->platform = xlib_onscreen; xlib_onscreen->xwin = xwin; xlib_onscreen->is_foreign_xwin = onscreen->foreign_xid ? TRUE : FALSE; egl_onscreen->egl_surface = eglCreateWindowSurface (egl_renderer->edpy, egl_config, (EGLNativeWindowType) xlib_onscreen->xwin, NULL); return TRUE; } static void _cogl_winsys_egl_onscreen_deinit (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglRenderer *renderer = context->display->renderer; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); CoglXlibTrapState old_state; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; CoglOnscreenXlib *xlib_onscreen = egl_onscreen->platform; _cogl_xlib_renderer_trap_errors (renderer, &old_state); if (!xlib_onscreen->is_foreign_xwin && xlib_onscreen->xwin != None) { XDestroyWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); xlib_onscreen->xwin = None; } else xlib_onscreen->xwin = None; XSync (xlib_renderer->xdpy, False); if (_cogl_xlib_renderer_untrap_errors (renderer, &old_state) != Success) g_warning ("X Error while destroying X window"); g_slice_free (CoglOnscreenXlib, xlib_onscreen); } static void _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen, CoglBool visibility) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); CoglOnscreenEGL *onscreen_egl = onscreen->winsys; CoglOnscreenXlib *xlib_onscreen = onscreen_egl->platform; if (visibility) XMapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); else XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); } static void _cogl_winsys_onscreen_set_resizable (CoglOnscreen *onscreen, CoglBool resizable) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglOnscreenEGL *egl_onscreen = onscreen->winsys; CoglOnscreenXlib *xlib_onscreen = egl_onscreen->platform; XSizeHints *size_hints = XAllocSizeHints (); if (resizable) { /* TODO: Add cogl_onscreen_request_minimum_size () */ size_hints->min_width = 1; size_hints->min_height = 1; size_hints->max_width = INT_MAX; size_hints->max_height = INT_MAX; } else { int width = cogl_framebuffer_get_width (framebuffer); int height = cogl_framebuffer_get_height (framebuffer); size_hints->min_width = width; size_hints->min_height = height; size_hints->max_width = width; size_hints->max_height = height; } XSetWMNormalHints (xlib_renderer->xdpy, xlib_onscreen->xwin, size_hints); XFree (size_hints); } static uint32_t _cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen) { CoglOnscreenEGL *egl_onscreen = onscreen->winsys; CoglOnscreenXlib *xlib_onscreen = egl_onscreen->platform; return xlib_onscreen->xwin; } static CoglBool _cogl_winsys_egl_context_created (CoglDisplay *display, CoglError **error) { CoglRenderer *renderer = display->renderer; CoglDisplayEGL *egl_display = display->winsys; CoglRendererEGL *egl_renderer = renderer->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); CoglDisplayXlib *xlib_display = egl_display->platform; XVisualInfo *xvisinfo; XSetWindowAttributes attrs; const char *error_message; xvisinfo = get_visual_info (display, egl_display->egl_config); if (xvisinfo == NULL) { error_message = "Unable to find suitable X visual"; goto fail; } attrs.override_redirect = True; attrs.colormap = XCreateColormap (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), xvisinfo->visual, AllocNone); attrs.border_pixel = 0; if ((egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0) { xlib_display->dummy_xwin = XCreateWindow (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), -100, -100, 1, 1, 0, xvisinfo->depth, CopyFromParent, xvisinfo->visual, CWOverrideRedirect | CWColormap | CWBorderPixel, &attrs); egl_display->dummy_surface = eglCreateWindowSurface (egl_renderer->edpy, egl_display->egl_config, (EGLNativeWindowType) xlib_display->dummy_xwin, NULL); if (egl_display->dummy_surface == EGL_NO_SURFACE) { error_message = "Unable to create an EGL surface"; XFree (xvisinfo); goto fail; } } xlib_renderer->xvisinfo = xvisinfo; if (!_cogl_winsys_egl_make_current (display, egl_display->dummy_surface, egl_display->dummy_surface, egl_display->egl_context)) { if (egl_display->dummy_surface == EGL_NO_SURFACE) error_message = "Unable to eglMakeCurrent with no surface"; else error_message = "Unable to eglMakeCurrent with dummy surface"; goto fail; } return TRUE; fail: _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "%s", error_message); return FALSE; } static void _cogl_winsys_egl_cleanup_context (CoglDisplay *display) { CoglDisplayEGL *egl_display = display->winsys; CoglDisplayXlib *xlib_display = egl_display->platform; CoglRenderer *renderer = display->renderer; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); CoglRendererEGL *egl_renderer = renderer->winsys; if (egl_display->dummy_surface != EGL_NO_SURFACE) { eglDestroySurface (egl_renderer->edpy, egl_display->dummy_surface); egl_display->dummy_surface = EGL_NO_SURFACE; } if (xlib_display->dummy_xwin) { XDestroyWindow (xlib_renderer->xdpy, xlib_display->dummy_xwin); xlib_display->dummy_xwin = None; } } #ifdef EGL_KHR_image_pixmap static CoglBool _cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap) { CoglTexture *tex = COGL_TEXTURE (tex_pixmap); CoglContext *ctx = tex->context; CoglTexturePixmapEGL *egl_tex_pixmap; EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; CoglPixelFormat texture_format; CoglRendererEGL *egl_renderer; egl_renderer = ctx->display->renderer->winsys; if (!(egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_X11_PIXMAP) || !_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE)) { tex_pixmap->winsys = NULL; return FALSE; } egl_tex_pixmap = g_new0 (CoglTexturePixmapEGL, 1); egl_tex_pixmap->image = _cogl_egl_create_image (ctx, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)tex_pixmap->pixmap, attribs); if (egl_tex_pixmap->image == EGL_NO_IMAGE_KHR) { free (egl_tex_pixmap); return FALSE; } texture_format = (tex_pixmap->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); egl_tex_pixmap->texture = COGL_TEXTURE ( cogl_egl_texture_2d_new_from_image (ctx, tex->width, tex->height, texture_format, egl_tex_pixmap->image, NULL)); tex_pixmap->winsys = egl_tex_pixmap; return TRUE; } static void _cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap) { CoglTexturePixmapEGL *egl_tex_pixmap; /* FIXME: It should be possible to get to a CoglContext from any * CoglTexture pointer. */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!tex_pixmap->winsys) return; egl_tex_pixmap = tex_pixmap->winsys; if (egl_tex_pixmap->texture) cogl_object_unref (egl_tex_pixmap->texture); if (egl_tex_pixmap->image != EGL_NO_IMAGE_KHR) _cogl_egl_destroy_image (ctx, egl_tex_pixmap->image); tex_pixmap->winsys = NULL; free (egl_tex_pixmap); } static CoglBool _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, CoglTexturePixmapStereoMode stereo_mode, CoglBool needs_mipmap) { if (needs_mipmap) return FALSE; return TRUE; } static void _cogl_winsys_texture_pixmap_x11_damage_notify (CoglTexturePixmapX11 *tex_pixmap) { } static CoglTexture * _cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap, CoglTexturePixmapStereoMode stereo_mode) { CoglTexturePixmapEGL *egl_tex_pixmap = tex_pixmap->winsys; return egl_tex_pixmap->texture; } #endif /* EGL_KHR_image_pixmap */ static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable = { .add_config_attributes = _cogl_winsys_egl_add_config_attributes, .choose_config = _cogl_winsys_egl_choose_config, .display_setup = _cogl_winsys_egl_display_setup, .display_destroy = _cogl_winsys_egl_display_destroy, .context_created = _cogl_winsys_egl_context_created, .cleanup_context = _cogl_winsys_egl_cleanup_context, .context_init = _cogl_winsys_egl_context_init, .context_deinit = _cogl_winsys_egl_context_deinit, .onscreen_init = _cogl_winsys_egl_onscreen_init, .onscreen_deinit = _cogl_winsys_egl_onscreen_deinit }; const CoglWinsysVtable * _cogl_winsys_egl_xlib_get_vtable (void) { static CoglBool vtable_inited = FALSE; static CoglWinsysVtable vtable; if (!vtable_inited) { /* The EGL_X11 winsys is a subclass of the EGL winsys so we start by copying its vtable */ vtable = *_cogl_winsys_egl_get_vtable (); vtable.id = COGL_WINSYS_ID_EGL_XLIB; vtable.name = "EGL_XLIB"; vtable.constraints |= (COGL_RENDERER_CONSTRAINT_USES_X11 | COGL_RENDERER_CONSTRAINT_USES_XLIB); vtable.renderer_connect = _cogl_winsys_renderer_connect; vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect; vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; vtable.onscreen_set_resizable = _cogl_winsys_onscreen_set_resizable; vtable.onscreen_x11_get_window_xid = _cogl_winsys_onscreen_x11_get_window_xid; #ifdef EGL_KHR_image_pixmap /* X11 tfp support... */ /* XXX: instead of having a rather monolithic winsys vtable we could * perhaps look for a way to separate these... */ vtable.texture_pixmap_x11_create = _cogl_winsys_texture_pixmap_x11_create; vtable.texture_pixmap_x11_free = _cogl_winsys_texture_pixmap_x11_free; vtable.texture_pixmap_x11_update = _cogl_winsys_texture_pixmap_x11_update; vtable.texture_pixmap_x11_damage_notify = _cogl_winsys_texture_pixmap_x11_damage_notify; vtable.texture_pixmap_x11_get_texture = _cogl_winsys_texture_pixmap_x11_get_texture; #endif /* EGL_KHR_image_pixmap) */ vtable_inited = TRUE; } return &vtable; } muffin-5.2.1/cogl/cogl/winsys/cogl-texture-pixmap-x11.h0000664000175000017500000002267014211404421023045 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_TEXTURE_PIXMAP_X11_H #define __COGL_TEXTURE_PIXMAP_X11_H /* NB: this is a top-level header that can be included directly but we * want to be careful not to define __COGL_H_INSIDE__ when this is * included internally while building Cogl itself since * __COGL_H_INSIDE__ is used in headers to guard public vs private api * definitions */ #ifndef COGL_COMPILATION /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_TEXTURE_PIXMAP_X11_ #endif #endif /* COGL_COMPILATION */ #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-texture-pixmap-x11 * @short_description: Functions for creating and manipulating 2D meta * textures derived from X11 pixmaps. * * These functions allow high-level meta textures (See the * #CoglMetaTexture interface) that derive their contents from an X11 * pixmap. */ typedef struct _CoglTexturePixmapX11 CoglTexturePixmapX11; #define COGL_TEXTURE_PIXMAP_X11(X) ((CoglTexturePixmapX11 *)X) /** * cogl_texture_pixmap_x11_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_texture_pixmap_x11_get_gtype (void); typedef enum { COGL_TEXTURE_PIXMAP_X11_DAMAGE_RAW_RECTANGLES, COGL_TEXTURE_PIXMAP_X11_DAMAGE_DELTA_RECTANGLES, COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX, COGL_TEXTURE_PIXMAP_X11_DAMAGE_NON_EMPTY } CoglTexturePixmapX11ReportLevel; /** * COGL_TEXTURE_PIXMAP_X11_ERROR: * * #CoglError domain for texture-pixmap-x11 errors. * * Since: 1.10 */ #define COGL_TEXTURE_PIXMAP_X11_ERROR (cogl_texture_pixmap_x11_error_quark ()) /** * CoglTexturePixmapX11Error: * @COGL_TEXTURE_PIXMAP_X11_ERROR_X11: An X11 protocol error * * Error codes that can be thrown when performing texture-pixmap-x11 * operations. * * Since: 1.10 */ typedef enum { COGL_TEXTURE_PIXMAP_X11_ERROR_X11, } CoglTexturePixmapX11Error; uint32_t cogl_texture_pixmap_x11_error_quark (void); /** * cogl_texture_pixmap_x11_new: * @context: A #CoglContext * @pixmap: A X11 pixmap ID * @automatic_updates: Whether to automatically copy the contents of * the pixmap to the texture. * @error: A #CoglError for exceptions * * Creates a texture that contains the contents of @pixmap. If * @automatic_updates is %TRUE then Cogl will attempt to listen for * damage events on the pixmap and automatically update the texture * when it changes. * * Return value: a new #CoglTexturePixmapX11 instance * * Since: 1.10 * Stability: Unstable */ CoglTexturePixmapX11 * cogl_texture_pixmap_x11_new (CoglContext *context, uint32_t pixmap, CoglBool automatic_updates, CoglError **error); /** * cogl_texture_pixmap_x11_new_left: * @context: A #CoglContext * @pixmap: A X11 pixmap ID * @automatic_updates: Whether to automatically copy the contents of * the pixmap to the texture. * @error: A #CoglError for exceptions * * Creates one of a pair of textures to contain the contents of @pixmap, * which has stereo content. (Different images for the right and left eyes.) * The left image is drawn using this texture; the right image is drawn * using a texture created by calling * cogl_texture_pixmap_x11_new_right() and passing in this texture as an * argument. * * In general, you should not use this function unless you have * queried the %GLX_STEREO_TREE_EXT attribute of the corresponding * window using glXQueryDrawable() and determined that the window is * stereo. Note that this attribute can change over time and * notification is also provided through events defined in the * EXT_stereo_tree GLX extension. As long as the system has support for * stereo content, drawing using the left and right pixmaps will not * produce an error even if the window doesn't have stereo * content any more, but drawing with the right pixmap will produce * undefined output, so you need to listen for these events and * re-render to avoid race conditions. (Recreating a non-stereo * pixmap is not necessary, but may save resources.) * * Return value: a new #CoglTexturePixmapX11 instance * * Since: 1.20 * Stability: Unstable */ CoglTexturePixmapX11 * cogl_texture_pixmap_x11_new_left (CoglContext *context, uint32_t pixmap, CoglBool automatic_updates, CoglError **error); /** * cogl_texture_pixmap_x11_new_right: * @left_texture: A #CoglTexturePixmapX11 instance created with * cogl_texture_pixmap_x11_new_left(). * * Creates a texture object that corresponds to the right-eye image * of a pixmap with stereo content. @left_texture must have been * created using cogl_texture_pixmap_x11_new_left(). * * Return value: a new #CoglTexturePixmapX11 instance * * Since: 1.20 * Stability: Unstable */ CoglTexturePixmapX11 * cogl_texture_pixmap_x11_new_right (CoglTexturePixmapX11 *left_texture); /** * cogl_texture_pixmap_x11_update_area: * @texture: A #CoglTexturePixmapX11 instance * @x: x coordinate of the area to update * @y: y coordinate of the area to update * @width: width of the area to update * @height: height of the area to update * * Forces an update of the given @texture so that it is refreshed with * the contents of the pixmap that was given to * cogl_texture_pixmap_x11_new(). * * Since: 1.4 * Stability: Unstable */ void cogl_texture_pixmap_x11_update_area (CoglTexturePixmapX11 *texture, int x, int y, int width, int height); /** * cogl_texture_pixmap_x11_is_using_tfp_extension: * @texture: A #CoglTexturePixmapX11 instance * * Checks whether the given @texture is using the * GLX_EXT_texture_from_pixmap or similar extension to copy the * contents of the pixmap to the texture. This extension is usually * implemented as zero-copy operation so it implies the updates are * working efficiently. * * Return value: %TRUE if the texture is using an efficient extension * and %FALSE otherwise * * Since: 1.4 * Stability: Unstable */ CoglBool cogl_texture_pixmap_x11_is_using_tfp_extension (CoglTexturePixmapX11 *texture); /** * cogl_texture_pixmap_x11_set_damage_object: * @texture: A #CoglTexturePixmapX11 instance * @damage: A X11 Damage object or 0 * @report_level: The report level which describes how to interpret * the damage events. This should match the level that the damage * object was created with. * * Sets the damage object that will be used to track automatic updates * to the @texture. Damage tracking can be disabled by passing 0 for * @damage. Otherwise this damage will replace the one used if %TRUE * was passed for automatic_updates to cogl_texture_pixmap_x11_new(). * * Note that Cogl will subtract from the damage region as it processes * damage events. * * Since: 1.4 * Stability: Unstable */ void cogl_texture_pixmap_x11_set_damage_object (CoglTexturePixmapX11 *texture, uint32_t damage, CoglTexturePixmapX11ReportLevel report_level); /** * cogl_is_texture_pixmap_x11: * @object: A pointer to a #CoglObject * * Checks whether @object points to a #CoglTexturePixmapX11 instance. * * Return value: %TRUE if the object is a #CoglTexturePixmapX11, and * %FALSE otherwise * * Since: 1.4 * Stability: Unstable */ CoglBool cogl_is_texture_pixmap_x11 (void *object); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_TEXTURE_PIXMAP_X11_ #undef __COGL_H_INSIDE__ #undef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_TEXTURE_PIXMAP_X11_ #endif #endif /* __COGL_TEXTURE_PIXMAP_X11_H */ muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h0000664000175000017500000001427714211404421025206 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This can be included multiple times with different definitions for * the COGL_WINSYS_FEATURE_* functions. */ /* Macro prototypes: * COGL_WINSYS_FEATURE_BEGIN (name, namespaces, extension_names, * implied_private_egl_feature_flags) * COGL_WINSYS_FEATURE_FUNCTION (return_type, function_name, * (arguments)) * ... * COGL_WINSYS_FEATURE_END () * * Note: You can list multiple namespace and extension names if the * corresponding _FEATURE_FUNCTIONS have the same semantics accross * the different extension variants. * * XXX: NB: Don't add a trailing semicolon when using these macros */ COGL_WINSYS_FEATURE_BEGIN (swap_region, "NOK\0", "swap_region\0", COGL_EGL_WINSYS_FEATURE_SWAP_REGION) COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglSwapBuffersRegion, (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects)) COGL_WINSYS_FEATURE_END () /* XXX: These macros can't handle falling back to looking for * EGL_KHR_image if EGL_KHR_image_base and EGL_KHR_image_pixmap aren't * found... */ #ifdef EGL_KHR_image_base COGL_WINSYS_FEATURE_BEGIN (image_base, "KHR\0", "image_base\0", 0) COGL_WINSYS_FEATURE_FUNCTION (EGLImageKHR, eglCreateImage, (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)) COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglDestroyImage, (EGLDisplay dpy, EGLImageKHR image)) COGL_WINSYS_FEATURE_END () #endif COGL_WINSYS_FEATURE_BEGIN (image_pixmap, "KHR\0", "image_pixmap\0", COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_X11_PIXMAP) COGL_WINSYS_FEATURE_END () #ifdef EGL_WL_bind_wayland_display COGL_WINSYS_FEATURE_BEGIN (bind_wayland_display, "WL\0", "bind_wayland_display\0", COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_WAYLAND_BUFFER) COGL_WINSYS_FEATURE_FUNCTION (EGLImageKHR, eglBindWaylandDisplay, (EGLDisplay dpy, struct wl_display *wayland_display)) COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglUnbindWaylandDisplay, (EGLDisplay dpy, struct wl_display *wayland_display)) COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglQueryWaylandBuffer, (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value)) COGL_WINSYS_FEATURE_END () #endif /* EGL_WL_bind_wayland_display */ COGL_WINSYS_FEATURE_BEGIN (create_context, "KHR\0", "create_context\0", COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (buffer_age, "EXT\0", "buffer_age\0", COGL_EGL_WINSYS_FEATURE_BUFFER_AGE) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (swap_buffers_with_damage, "EXT\0", "swap_buffers_with_damage\0", 0) COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglSwapBuffersWithDamage, (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects)) COGL_WINSYS_FEATURE_END () #if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync) COGL_WINSYS_FEATURE_BEGIN (fence_sync, "KHR\0", "fence_sync\0", COGL_EGL_WINSYS_FEATURE_FENCE_SYNC) COGL_WINSYS_FEATURE_FUNCTION (EGLSyncKHR, eglCreateSync, (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)) COGL_WINSYS_FEATURE_FUNCTION (EGLint, eglClientWaitSync, (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)) COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglDestroySync, (EGLDisplay dpy, EGLSyncKHR sync)) COGL_WINSYS_FEATURE_END () #endif COGL_WINSYS_FEATURE_BEGIN (surfaceless_context, "KHR\0", "surfaceless_context\0", COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) COGL_WINSYS_FEATURE_END () muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-glx.c0000664000175000017500000031462114211404421021561 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010,2011,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-i18n-private.h" #include "cogl-util.h" #include "cogl-winsys-private.h" #include "cogl-feature-private.h" #include "cogl-context-private.h" #include "cogl-framebuffer.h" #include "cogl-swap-chain-private.h" #include "cogl-renderer-private.h" #include "cogl-glx-renderer-private.h" #include "cogl-onscreen-template-private.h" #include "cogl-glx-display-private.h" #include "cogl-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-rectangle-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-frame-info-private.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-private.h" #include "cogl-swap-chain-private.h" #include "cogl-xlib-renderer.h" #include "cogl-util.h" #include "cogl-winsys-glx-private.h" #include "cogl-error-private.h" #include "cogl-poll-private.h" #include "cogl-version.h" #include "cogl-glx.h" #include #include #include #include #include #include #include #include #include #include #include /* This is a relatively new extension */ #ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV #define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7 #endif #define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask) #define MAX_GLX_CONFIG_ATTRIBS 30 typedef struct _CoglContextGLX { GLXDrawable current_drawable; } CoglContextGLX; typedef struct _CoglOnscreenXlib { Window xwin; int x, y; CoglBool is_foreign_xwin; CoglOutput *output; } CoglOnscreenXlib; typedef struct _CoglOnscreenGLX { CoglOnscreenXlib _parent; GLXDrawable glxwin; uint32_t last_swap_vsync_counter; uint32_t pending_sync_notify; uint32_t pending_complete_notify; uint32_t pending_resize_notify; GThread *swap_wait_thread; GQueue *swap_wait_queue; GCond swap_wait_cond; GMutex swap_wait_mutex; int swap_wait_pipe[2]; GLXContext swap_wait_context; CoglBool closing_down; } CoglOnscreenGLX; typedef struct _CoglPixmapTextureEyeGLX { CoglTexture *glx_tex; CoglBool bind_tex_image_queued; CoglBool pixmap_bound; } CoglPixmapTextureEyeGLX; typedef struct _CoglTexturePixmapGLX { GLXPixmap glx_pixmap; CoglBool has_mipmap_space; CoglBool can_mipmap; CoglPixmapTextureEyeGLX left; CoglPixmapTextureEyeGLX right; } CoglTexturePixmapGLX; /* Define a set of arrays containing the functions required from GL for each winsys feature */ #define COGL_WINSYS_FEATURE_BEGIN(major_version, minor_version, \ name, namespaces, extension_names, \ feature_flags, \ winsys_feature) \ static const CoglFeatureFunction \ cogl_glx_feature_ ## name ## _funcs[] = { #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \ { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglGLXRenderer, name) }, #define COGL_WINSYS_FEATURE_END() \ { NULL, 0 }, \ }; #include "cogl-winsys-glx-feature-functions.h" /* Define an array of features */ #undef COGL_WINSYS_FEATURE_BEGIN #define COGL_WINSYS_FEATURE_BEGIN(major_version, minor_version, \ name, namespaces, extension_names, \ feature_flags, \ winsys_feature) \ { major_version, minor_version, \ 0, namespaces, extension_names, \ feature_flags, \ 0, \ winsys_feature, \ cogl_glx_feature_ ## name ## _funcs }, #undef COGL_WINSYS_FEATURE_FUNCTION #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) #undef COGL_WINSYS_FEATURE_END #define COGL_WINSYS_FEATURE_END() static const CoglFeatureData winsys_feature_data[] = { #include "cogl-winsys-glx-feature-functions.h" }; static CoglFuncPtr _cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer, const char *name, CoglBool in_core) { CoglGLXRenderer *glx_renderer = renderer->winsys; /* The GLX_ARB_get_proc_address extension documents that this should * work for core functions too so we don't need to do anything * special with in_core */ return glx_renderer->glXGetProcAddress ((const GLubyte *) name); } static CoglOnscreen * find_onscreen_for_xid (CoglContext *context, uint32_t xid) { GList *l; for (l = context->framebuffers; l; l = l->next) { CoglFramebuffer *framebuffer = l->data; CoglOnscreenXlib *xlib_onscreen; if (framebuffer->type != COGL_FRAMEBUFFER_TYPE_ONSCREEN) continue; /* Does the GLXEvent have the GLXDrawable or the X Window? */ xlib_onscreen = COGL_ONSCREEN (framebuffer)->winsys; if (xlib_onscreen != NULL && xlib_onscreen->xwin == (Window)xid) return COGL_ONSCREEN (framebuffer); } return NULL; } static int64_t get_monotonic_time_ns (void) { struct timespec ts; clock_gettime (CLOCK_MONOTONIC, &ts); return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec; } static void ensure_ust_type (CoglRenderer *renderer, GLXDrawable drawable) { CoglGLXRenderer *glx_renderer = renderer->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); int64_t ust; int64_t msc; int64_t sbc; struct timeval tv; int64_t current_system_time; int64_t current_monotonic_time; if (glx_renderer->ust_type != COGL_GLX_UST_IS_UNKNOWN) return; glx_renderer->ust_type = COGL_GLX_UST_IS_OTHER; if (glx_renderer->glXGetSyncValues == NULL) goto out; if (!glx_renderer->glXGetSyncValues (xlib_renderer->xdpy, drawable, &ust, &msc, &sbc)) goto out; /* This is the time source that existing (buggy) linux drm drivers * use */ gettimeofday (&tv, NULL); current_system_time = (tv.tv_sec * G_GINT64_CONSTANT (1000000)) + tv.tv_usec; if (current_system_time > ust - 1000000 && current_system_time < ust + 1000000) { glx_renderer->ust_type = COGL_GLX_UST_IS_GETTIMEOFDAY; goto out; } /* This is the time source that the newer (fixed) linux drm * drivers use (Linux >= 3.8) */ current_monotonic_time = get_monotonic_time_ns () / 1000; if (current_monotonic_time > ust - 1000000 && current_monotonic_time < ust + 1000000) { glx_renderer->ust_type = COGL_GLX_UST_IS_MONOTONIC_TIME; goto out; } out: COGL_NOTE (WINSYS, "Classified OML system time as: %s", glx_renderer->ust_type == COGL_GLX_UST_IS_GETTIMEOFDAY ? "gettimeofday" : (glx_renderer->ust_type == COGL_GLX_UST_IS_MONOTONIC_TIME ? "monotonic" : "other")); return; } static int64_t ust_to_nanoseconds (CoglRenderer *renderer, GLXDrawable drawable, int64_t ust) { CoglGLXRenderer *glx_renderer = renderer->winsys; ensure_ust_type (renderer, drawable); switch (glx_renderer->ust_type) { case COGL_GLX_UST_IS_UNKNOWN: g_assert_not_reached (); break; case COGL_GLX_UST_IS_GETTIMEOFDAY: case COGL_GLX_UST_IS_MONOTONIC_TIME: return 1000 * ust; case COGL_GLX_UST_IS_OTHER: /* In this case the scale of UST is undefined so we can't easily * scale to nanoseconds. * * For example the driver may be reporting the rdtsc CPU counter * as UST values and so the scale would need to be determined * empirically. * * Potentially we could block for a known duration within * ensure_ust_type() to measure the timescale of UST but for now * we just ignore unknown time sources */ return 0; } return 0; } static int64_t _cogl_winsys_get_clock_time (CoglContext *context) { CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; if (!glx_renderer->glXWaitForMsc) return get_monotonic_time_ns (); /* We don't call ensure_ust_type() because we don't have a drawable * to work with. cogl_get_clock_time() is documented to only work * once a valid, non-zero, timestamp has been retrieved from Cogl. */ switch (glx_renderer->ust_type) { case COGL_GLX_UST_IS_UNKNOWN: case COGL_GLX_UST_IS_OTHER: return 0; case COGL_GLX_UST_IS_GETTIMEOFDAY: { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * G_GINT64_CONSTANT (1000000000) + tv.tv_usec * G_GINT64_CONSTANT (1000); } case COGL_GLX_UST_IS_MONOTONIC_TIME: { return get_monotonic_time_ns (); } } g_assert_not_reached(); return 0; } static void flush_pending_notifications_cb (void *data, void *user_data) { CoglFramebuffer *framebuffer = data; if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) { CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); CoglOnscreenGLX *glx_onscreen = onscreen->winsys; while (glx_onscreen->pending_sync_notify > 0 || glx_onscreen->pending_complete_notify > 0 || glx_onscreen->pending_resize_notify > 0) { if (glx_onscreen->pending_sync_notify > 0) { CoglFrameInfo *info = g_queue_peek_head (&onscreen->pending_frame_infos); _cogl_onscreen_notify_frame_sync (onscreen, info); glx_onscreen->pending_sync_notify--; } if (glx_onscreen->pending_complete_notify > 0) { CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos); _cogl_onscreen_notify_complete (onscreen, info); cogl_object_unref (info); glx_onscreen->pending_complete_notify--; } if (glx_onscreen->pending_resize_notify > 0) { _cogl_onscreen_notify_resize (onscreen); glx_onscreen->pending_resize_notify--; } } } } static void flush_pending_notifications_idle (void *user_data) { CoglContext *context = user_data; CoglRenderer *renderer = context->display->renderer; CoglGLXRenderer *glx_renderer = renderer->winsys; /* This needs to be disconnected before invoking the callbacks in * case the callbacks cause it to be queued again */ _cogl_closure_disconnect (glx_renderer->flush_notifications_idle); glx_renderer->flush_notifications_idle = NULL; g_list_foreach (context->framebuffers, flush_pending_notifications_cb, NULL); } static void set_sync_pending (CoglOnscreen *onscreen) { CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; CoglGLXRenderer *glx_renderer = renderer->winsys; /* We only want to dispatch sync events when the application calls * cogl_context_dispatch so instead of immediately notifying we * queue an idle callback */ if (!glx_renderer->flush_notifications_idle) { glx_renderer->flush_notifications_idle = _cogl_poll_renderer_add_idle (renderer, flush_pending_notifications_idle, context, NULL); } glx_onscreen->pending_sync_notify++; } static void set_complete_pending (CoglOnscreen *onscreen) { CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; CoglGLXRenderer *glx_renderer = renderer->winsys; /* We only want to notify swap completion when the application calls * cogl_context_dispatch so instead of immediately notifying we * queue an idle callback */ if (!glx_renderer->flush_notifications_idle) { glx_renderer->flush_notifications_idle = _cogl_poll_renderer_add_idle (renderer, flush_pending_notifications_idle, context, NULL); } glx_onscreen->pending_complete_notify++; } static void notify_swap_buffers (CoglContext *context, GLXBufferSwapComplete *swap_event) { CoglOnscreen *onscreen = find_onscreen_for_xid (context, (uint32_t)swap_event->drawable); CoglOnscreenGLX *glx_onscreen; if (!onscreen) return; glx_onscreen = onscreen->winsys; /* We only want to notify that the swap is complete when the application calls cogl_context_dispatch so instead of immediately notifying we'll set a flag to remember to notify later */ set_sync_pending (onscreen); if (swap_event->ust != 0) { CoglFrameInfo *info = g_queue_peek_head (&onscreen->pending_frame_infos); info->presentation_time = ust_to_nanoseconds (context->display->renderer, glx_onscreen->glxwin, swap_event->ust); } set_complete_pending (onscreen); } static void update_output (CoglOnscreen *onscreen) { CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglDisplay *display = context->display; CoglOutput *output; int width, height; width = cogl_framebuffer_get_width (framebuffer); height = cogl_framebuffer_get_height (framebuffer); output = _cogl_xlib_renderer_output_for_rectangle (display->renderer, xlib_onscreen->x, xlib_onscreen->y, width, height); if (xlib_onscreen->output != output) { if (xlib_onscreen->output) cogl_object_unref (xlib_onscreen->output); xlib_onscreen->output = output; if (output) cogl_object_ref (xlib_onscreen->output); } } static void notify_resize (CoglContext *context, XConfigureEvent *configure_event) { CoglOnscreen *onscreen = find_onscreen_for_xid (context, configure_event->window); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglRenderer *renderer = context->display->renderer; CoglGLXRenderer *glx_renderer = renderer->winsys; CoglOnscreenGLX *glx_onscreen; CoglOnscreenXlib *xlib_onscreen; if (!onscreen) return; glx_onscreen = onscreen->winsys; xlib_onscreen = onscreen->winsys; _cogl_framebuffer_winsys_update_size (framebuffer, configure_event->width, configure_event->height); /* We only want to notify that a resize happened when the * application calls cogl_context_dispatch so instead of immediately * notifying we queue an idle callback */ if (!glx_renderer->flush_notifications_idle) { glx_renderer->flush_notifications_idle = _cogl_poll_renderer_add_idle (renderer, flush_pending_notifications_idle, context, NULL); } glx_onscreen->pending_resize_notify++; if (!xlib_onscreen->is_foreign_xwin) { int x, y; if (configure_event->send_event) { x = configure_event->x; y = configure_event->y; } else { Window child; XTranslateCoordinates (configure_event->display, configure_event->window, DefaultRootWindow (configure_event->display), 0, 0, &x, &y, &child); } xlib_onscreen->x = x; xlib_onscreen->y = y; update_output (onscreen); } } static CoglFilterReturn glx_event_filter_cb (XEvent *xevent, void *data) { CoglContext *context = data; #ifdef GLX_INTEL_swap_event CoglGLXRenderer *glx_renderer; #endif if (xevent->type == ConfigureNotify) { notify_resize (context, &xevent->xconfigure); /* we let ConfigureNotify pass through */ return COGL_FILTER_CONTINUE; } #ifdef GLX_INTEL_swap_event glx_renderer = context->display->renderer->winsys; if (xevent->type == (glx_renderer->glx_event_base + GLX_BufferSwapComplete)) { GLXBufferSwapComplete *swap_event = (GLXBufferSwapComplete *) xevent; notify_swap_buffers (context, swap_event); /* remove SwapComplete events from the queue */ return COGL_FILTER_REMOVE; } #endif /* GLX_INTEL_swap_event */ if (xevent->type == Expose) { CoglOnscreen *onscreen = find_onscreen_for_xid (context, xevent->xexpose.window); if (onscreen) { CoglOnscreenDirtyInfo info; info.x = xevent->xexpose.x; info.y = xevent->xexpose.y; info.width = xevent->xexpose.width; info.height = xevent->xexpose.height; _cogl_onscreen_queue_dirty (onscreen, &info); } return COGL_FILTER_CONTINUE; } return COGL_FILTER_CONTINUE; } static void _cogl_winsys_renderer_disconnect (CoglRenderer *renderer) { CoglGLXRenderer *glx_renderer = renderer->winsys; _cogl_xlib_renderer_disconnect (renderer); if (glx_renderer->libgl_module) g_module_close (glx_renderer->libgl_module); g_slice_free (CoglGLXRenderer, renderer->winsys); } static CoglBool update_all_outputs (CoglRenderer *renderer) { GList *l; _COGL_GET_CONTEXT (context, FALSE); if (context->display == NULL) /* during connection */ return FALSE; if (context->display->renderer != renderer) return FALSE; for (l = context->framebuffers; l; l = l->next) { CoglFramebuffer *framebuffer = l->data; if (framebuffer->type != COGL_FRAMEBUFFER_TYPE_ONSCREEN) continue; update_output (COGL_ONSCREEN (framebuffer)); } return TRUE; } static void _cogl_winsys_renderer_outputs_changed (CoglRenderer *renderer) { update_all_outputs (renderer); } static CoglBool resolve_core_glx_functions (CoglRenderer *renderer, CoglError **error) { CoglGLXRenderer *glx_renderer; glx_renderer = renderer->winsys; if (!g_module_symbol (glx_renderer->libgl_module, "glXQueryExtension", (void **) &glx_renderer->glXQueryExtension) || !g_module_symbol (glx_renderer->libgl_module, "glXQueryVersion", (void **) &glx_renderer->glXQueryVersion) || !g_module_symbol (glx_renderer->libgl_module, "glXQueryExtensionsString", (void **) &glx_renderer->glXQueryExtensionsString) || (!g_module_symbol (glx_renderer->libgl_module, "glXGetProcAddress", (void **) &glx_renderer->glXGetProcAddress) && !g_module_symbol (glx_renderer->libgl_module, "glXGetProcAddressARB", (void **) &glx_renderer->glXGetProcAddress)) || !g_module_symbol (glx_renderer->libgl_module, "glXQueryDrawable", (void **) &glx_renderer->glXQueryDrawable)) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "Failed to resolve required GLX symbol"); return FALSE; } return TRUE; } static void update_base_winsys_features (CoglRenderer *renderer) { CoglGLXRenderer *glx_renderer = renderer->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); const char *glx_extensions; int default_screen; char **split_extensions; int i; default_screen = DefaultScreen (xlib_renderer->xdpy); glx_extensions = glx_renderer->glXQueryExtensionsString (xlib_renderer->xdpy, default_screen); COGL_NOTE (WINSYS, " GLX Extensions: %s", glx_extensions); split_extensions = g_strsplit (glx_extensions, " ", 0 /* max_tokens */); for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++) if (_cogl_feature_check (renderer, "GLX", winsys_feature_data + i, glx_renderer->glx_major, glx_renderer->glx_minor, COGL_DRIVER_GL, /* the driver isn't used */ split_extensions, glx_renderer)) { glx_renderer->legacy_feature_flags |= winsys_feature_data[i].feature_flags; if (winsys_feature_data[i].winsys_feature) COGL_FLAGS_SET (glx_renderer->base_winsys_features, winsys_feature_data[i].winsys_feature, TRUE); } g_strfreev (split_extensions); /* The GLX_SGI_video_sync spec explicitly states this extension * only works for direct contexts; we don't know per-renderer * if the context is direct or not, so we turn off the feature * flag; we still use the extension within this file looking * instead at glx_display->have_vblank_counter. */ COGL_FLAGS_SET (glx_renderer->base_winsys_features, COGL_WINSYS_FEATURE_VBLANK_COUNTER, FALSE); COGL_FLAGS_SET (glx_renderer->base_winsys_features, COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, TRUE); /* Because of the direct-context dependency, the VBLANK_WAIT feature * doesn't reflect the presence of GLX_SGI_video_sync. */ if (glx_renderer->glXWaitForMsc) COGL_FLAGS_SET (glx_renderer->base_winsys_features, COGL_WINSYS_FEATURE_VBLANK_WAIT, TRUE); } static CoglBool _cogl_winsys_renderer_connect (CoglRenderer *renderer, CoglError **error) { CoglGLXRenderer *glx_renderer; CoglXlibRenderer *xlib_renderer; renderer->winsys = g_slice_new0 (CoglGLXRenderer); glx_renderer = renderer->winsys; xlib_renderer = _cogl_xlib_renderer_get_data (renderer); if (!_cogl_xlib_renderer_connect (renderer, error)) goto error; if (renderer->driver != COGL_DRIVER_GL && renderer->driver != COGL_DRIVER_GL3) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "GLX Backend can only be used in conjunction with OpenGL"); goto error; } glx_renderer->libgl_module = g_module_open (COGL_GL_LIBNAME, G_MODULE_BIND_LAZY); if (glx_renderer->libgl_module == NULL) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "Failed to dynamically open the OpenGL library"); goto error; } if (!resolve_core_glx_functions (renderer, error)) goto error; if (!glx_renderer->glXQueryExtension (xlib_renderer->xdpy, &glx_renderer->glx_error_base, &glx_renderer->glx_event_base)) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "XServer appears to lack required GLX support"); goto error; } /* XXX: Note: For a long time Mesa exported a hybrid GLX, exporting * extensions specified to require GLX 1.3, but still reporting 1.2 * via glXQueryVersion. */ if (!glx_renderer->glXQueryVersion (xlib_renderer->xdpy, &glx_renderer->glx_major, &glx_renderer->glx_minor) || !(glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 2)) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "XServer appears to lack required GLX 1.2 support"); goto error; } update_base_winsys_features (renderer); glx_renderer->dri_fd = -1; return TRUE; error: _cogl_winsys_renderer_disconnect (renderer); return FALSE; } static CoglBool update_winsys_features (CoglContext *context, CoglError **error) { CoglGLXDisplay *glx_display = context->display->winsys; CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; _COGL_RETURN_VAL_IF_FAIL (glx_display->glx_context, FALSE); if (!_cogl_context_update_features (context, error)) return FALSE; memcpy (context->winsys_features, glx_renderer->base_winsys_features, sizeof (context->winsys_features)); context->feature_flags |= glx_renderer->legacy_feature_flags; context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE; COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE); if (glx_renderer->glXCopySubBuffer || context->glBlitFramebuffer) { CoglGpuInfo *info = &context->gpu; CoglGpuInfoArchitecture arch = info->architecture; COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION, TRUE); /* * "The "drisw" binding in Mesa for loading sofware renderers is * broken, and neither glBlitFramebuffer nor glXCopySubBuffer * work correctly." * - ajax * - https://bugzilla.gnome.org/show_bug.cgi?id=674208 * * This is broken in software Mesa at least as of 7.10 and got * fixed in Mesa 10.1 */ if (info->driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA && info->driver_package_version < COGL_VERSION_ENCODE (10, 1, 0) && (arch == COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE || arch == COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE || arch == COGL_GPU_INFO_ARCHITECTURE_SWRAST)) { COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION, FALSE); } } /* Note: glXCopySubBuffer and glBlitFramebuffer won't be throttled * by the SwapInterval so we have to throttle swap_region requests * manually... */ if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION) && (glx_display->have_vblank_counter || glx_display->can_vblank_wait)) COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE); if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)) { COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, TRUE); /* TODO: remove this deprecated feature */ COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_PRESENTATION_TIME, TRUE); } else { CoglGpuInfo *info = &context->gpu; if (glx_display->have_vblank_counter && context->display->renderer->xlib_enable_threaded_swap_wait && info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) { COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, TRUE); COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, TRUE); /* TODO: remove this deprecated feature */ COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_PRESENTATION_TIME, TRUE); COGL_FLAGS_SET (context->private_features, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT, TRUE); } } /* We'll manually handle queueing dirty events in response to * Expose events from X */ COGL_FLAGS_SET (context->private_features, COGL_PRIVATE_FEATURE_DIRTY_EVENTS, TRUE); if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE)) COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_BUFFER_AGE, TRUE); return TRUE; } static void glx_attributes_from_framebuffer_config (CoglDisplay *display, CoglFramebufferConfig *config, int *attributes) { CoglGLXRenderer *glx_renderer = display->renderer->winsys; int i = 0; attributes[i++] = GLX_DRAWABLE_TYPE; attributes[i++] = GLX_WINDOW_BIT; attributes[i++] = GLX_RENDER_TYPE; attributes[i++] = GLX_RGBA_BIT; attributes[i++] = GLX_DOUBLEBUFFER; attributes[i++] = GL_TRUE; attributes[i++] = GLX_RED_SIZE; attributes[i++] = 1; attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1; attributes[i++] = GLX_BLUE_SIZE; attributes[i++] = 1; attributes[i++] = GLX_ALPHA_SIZE; attributes[i++] = config->swap_chain->has_alpha ? 1 : GLX_DONT_CARE; attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1; attributes[i++] = GLX_STENCIL_SIZE; attributes[i++] = config->need_stencil ? 1: GLX_DONT_CARE; if (config->stereo_enabled) { attributes[i++] = GLX_STEREO; attributes[i++] = TRUE; } if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 4 && config->samples_per_pixel) { attributes[i++] = GLX_SAMPLE_BUFFERS; attributes[i++] = 1; attributes[i++] = GLX_SAMPLES; attributes[i++] = config->samples_per_pixel; } attributes[i++] = None; g_assert (i < MAX_GLX_CONFIG_ATTRIBS); } /* It seems the GLX spec never defined an invalid GLXFBConfig that * we could overload as an indication of error, so we have to return * an explicit boolean status. */ static CoglBool find_fbconfig (CoglDisplay *display, CoglFramebufferConfig *config, GLXFBConfig *config_ret, CoglError **error) { CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); CoglGLXRenderer *glx_renderer = display->renderer->winsys; GLXFBConfig *configs = NULL; int n_configs; static int attributes[MAX_GLX_CONFIG_ATTRIBS]; CoglBool ret = TRUE; int xscreen_num = DefaultScreen (xlib_renderer->xdpy); glx_attributes_from_framebuffer_config (display, config, attributes); configs = glx_renderer->glXChooseFBConfig (xlib_renderer->xdpy, xscreen_num, attributes, &n_configs); if (!configs || n_configs == 0) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Failed to find any compatible fbconfigs"); ret = FALSE; goto done; } if (config->swap_chain->has_alpha) { int i; for (i = 0; i < n_configs; i++) { XVisualInfo *vinfo; vinfo = glx_renderer->glXGetVisualFromFBConfig (xlib_renderer->xdpy, configs[i]); if (vinfo == NULL) continue; if (vinfo->depth == 32 && (vinfo->red_mask | vinfo->green_mask | vinfo->blue_mask) != 0xffffffff) { COGL_NOTE (WINSYS, "Found an ARGB FBConfig [index:%d]", i); *config_ret = configs[i]; goto done; } } _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Unable to find fbconfig with rgba visual"); ret = FALSE; goto done; } else { COGL_NOTE (WINSYS, "Using the first available FBConfig"); *config_ret = configs[0]; } done: XFree (configs); return ret; } static GLXContext create_gl3_context (CoglDisplay *display, GLXFBConfig fb_config) { CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); CoglGLXRenderer *glx_renderer = display->renderer->winsys; /* We want a core profile 3.1 context with no deprecated features */ static const int attrib_list[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 1, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None }; /* NV_robustness_video_memory_purge relies on GLX_ARB_create_context and in part on ARB_robustness. Namely, it needs the notification strategy to be set to GLX_LOSE_CONTEXT_ON_RESET_ARB and that the driver exposes the GetGraphicsResetStatusARB function. This means we don't actually enable robust buffer access. */ static const int attrib_list_reset_on_purge[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 1, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_TRUE, GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB, None }; /* Make sure that the display supports the GLX_ARB_create_context extension */ if (glx_renderer->glXCreateContextAttribs == NULL) return NULL; /* We can't check the presence of this extension with the usual COGL_WINSYS_FEATURE machinery because that only gets initialized later when the CoglContext is created. */ if (display->renderer->xlib_want_reset_on_video_memory_purge && strstr (glx_renderer->glXQueryExtensionsString (xlib_renderer->xdpy, DefaultScreen (xlib_renderer->xdpy)), "GLX_NV_robustness_video_memory_purge")) { CoglXlibTrapState old_state; GLXContext ctx; _cogl_xlib_renderer_trap_errors (display->renderer, &old_state); ctx = glx_renderer->glXCreateContextAttribs (xlib_renderer->xdpy, fb_config, NULL /* share_context */, True, /* direct */ attrib_list_reset_on_purge); if (!_cogl_xlib_renderer_untrap_errors (display->renderer, &old_state) && ctx) return ctx; } return glx_renderer->glXCreateContextAttribs (xlib_renderer->xdpy, fb_config, NULL /* share_context */, True, /* direct */ attrib_list); } static CoglBool create_context (CoglDisplay *display, CoglError **error) { CoglGLXDisplay *glx_display = display->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); CoglGLXRenderer *glx_renderer = display->renderer->winsys; CoglBool support_transparent_windows = display->onscreen_template->config.swap_chain->has_alpha; GLXFBConfig config; CoglError *fbconfig_error = NULL; XSetWindowAttributes attrs; XVisualInfo *xvisinfo; GLXDrawable dummy_drawable; CoglXlibTrapState old_state; _COGL_RETURN_VAL_IF_FAIL (glx_display->glx_context == NULL, TRUE); glx_display->found_fbconfig = find_fbconfig (display, &display->onscreen_template->config, &config, &fbconfig_error); if (!glx_display->found_fbconfig) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Unable to find suitable fbconfig for the GLX context: %s", fbconfig_error->message); cogl_error_free (fbconfig_error); return FALSE; } glx_display->fbconfig = config; glx_display->fbconfig_has_rgba_visual = support_transparent_windows; COGL_NOTE (WINSYS, "Creating GLX Context (display: %p)", xlib_renderer->xdpy); _cogl_xlib_renderer_trap_errors (display->renderer, &old_state); if (display->renderer->driver == COGL_DRIVER_GL3) glx_display->glx_context = create_gl3_context (display, config); else glx_display->glx_context = glx_renderer->glXCreateNewContext (xlib_renderer->xdpy, config, GLX_RGBA_TYPE, NULL, True); if (_cogl_xlib_renderer_untrap_errors (display->renderer, &old_state) || glx_display->glx_context == NULL) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Unable to create suitable GL context"); return FALSE; } glx_display->is_direct = glx_renderer->glXIsDirect (xlib_renderer->xdpy, glx_display->glx_context); glx_display->have_vblank_counter = glx_display->is_direct && glx_renderer->glXWaitVideoSync; glx_display->can_vblank_wait = glx_renderer->glXWaitForMsc || glx_display->have_vblank_counter; COGL_NOTE (WINSYS, "Setting %s context", glx_display->is_direct ? "direct" : "indirect"); /* XXX: GLX doesn't let us make a context current without a window * so we create a dummy window that we can use while no CoglOnscreen * framebuffer is in use. */ xvisinfo = glx_renderer->glXGetVisualFromFBConfig (xlib_renderer->xdpy, config); if (xvisinfo == NULL) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Unable to retrieve the X11 visual"); return FALSE; } _cogl_xlib_renderer_trap_errors (display->renderer, &old_state); attrs.override_redirect = True; attrs.colormap = XCreateColormap (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), xvisinfo->visual, AllocNone); attrs.border_pixel = 0; glx_display->dummy_xwin = XCreateWindow (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), -100, -100, 1, 1, 0, xvisinfo->depth, CopyFromParent, xvisinfo->visual, CWOverrideRedirect | CWColormap | CWBorderPixel, &attrs); /* Try and create a GLXWindow to use with extensions dependent on * GLX versions >= 1.3 that don't accept regular X Windows as GLX * drawables. */ if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 3) { glx_display->dummy_glxwin = glx_renderer->glXCreateWindow (xlib_renderer->xdpy, config, glx_display->dummy_xwin, NULL); } if (glx_display->dummy_glxwin) dummy_drawable = glx_display->dummy_glxwin; else dummy_drawable = glx_display->dummy_xwin; COGL_NOTE (WINSYS, "Selecting dummy 0x%x for the GLX context", (unsigned int) dummy_drawable); glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, dummy_drawable, dummy_drawable, glx_display->glx_context); xlib_renderer->xvisinfo = xvisinfo; if (_cogl_xlib_renderer_untrap_errors (display->renderer, &old_state)) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Unable to select the newly created GLX context"); return FALSE; } return TRUE; } static void _cogl_winsys_display_destroy (CoglDisplay *display) { CoglGLXDisplay *glx_display = display->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); CoglGLXRenderer *glx_renderer = display->renderer->winsys; _COGL_RETURN_IF_FAIL (glx_display != NULL); if (glx_display->glx_context) { glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, None, None, NULL); glx_renderer->glXDestroyContext (xlib_renderer->xdpy, glx_display->glx_context); glx_display->glx_context = NULL; } if (glx_display->dummy_glxwin) { glx_renderer->glXDestroyWindow (xlib_renderer->xdpy, glx_display->dummy_glxwin); glx_display->dummy_glxwin = None; } if (glx_display->dummy_xwin) { XDestroyWindow (xlib_renderer->xdpy, glx_display->dummy_xwin); glx_display->dummy_xwin = None; } g_slice_free (CoglGLXDisplay, display->winsys); display->winsys = NULL; } static CoglBool _cogl_winsys_display_setup (CoglDisplay *display, CoglError **error) { CoglGLXDisplay *glx_display; int i; _COGL_RETURN_VAL_IF_FAIL (display->winsys == NULL, FALSE); glx_display = g_slice_new0 (CoglGLXDisplay); display->winsys = glx_display; if (!create_context (display, error)) goto error; for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++) glx_display->glx_cached_configs[i].depth = -1; return TRUE; error: _cogl_winsys_display_destroy (display); return FALSE; } static CoglBool _cogl_winsys_context_init (CoglContext *context, CoglError **error) { context->winsys = g_new0 (CoglContextGLX, 1); cogl_xlib_renderer_add_filter (context->display->renderer, glx_event_filter_cb, context); return update_winsys_features (context, error); } static void _cogl_winsys_context_deinit (CoglContext *context) { cogl_xlib_renderer_remove_filter (context->display->renderer, glx_event_filter_cb, context); free (context->winsys); } static CoglBool _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, CoglError **error) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglDisplay *display = context->display; CoglGLXDisplay *glx_display = display->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); CoglGLXRenderer *glx_renderer = display->renderer->winsys; Window xwin; CoglOnscreenXlib *xlib_onscreen; CoglOnscreenGLX *glx_onscreen; GLXFBConfig fbconfig; CoglError *fbconfig_error = NULL; _COGL_RETURN_VAL_IF_FAIL (glx_display->glx_context, FALSE); if (!find_fbconfig (display, &framebuffer->config, &fbconfig, &fbconfig_error)) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Unable to find suitable fbconfig for the GLX context: %s", fbconfig_error->message); cogl_error_free (fbconfig_error); return FALSE; } /* Update the real number of samples_per_pixel now that we have * found an fbconfig... */ if (framebuffer->config.samples_per_pixel) { int samples; int status = glx_renderer->glXGetFBConfigAttrib (xlib_renderer->xdpy, fbconfig, GLX_SAMPLES, &samples); g_return_val_if_fail (status == Success, TRUE); framebuffer->samples_per_pixel = samples; } /* FIXME: We need to explicitly Select for ConfigureNotify events. * For foreign windows we need to be careful not to mess up any * existing event mask. * We need to document that for windows we create then toolkits * must be careful not to clear event mask bits that we select. */ /* XXX: Note we ignore the user's original width/height when * given a foreign X window. */ if (onscreen->foreign_xid) { Status status; CoglXlibTrapState state; XWindowAttributes attr; int xerror; xwin = onscreen->foreign_xid; _cogl_xlib_renderer_trap_errors (display->renderer, &state); status = XGetWindowAttributes (xlib_renderer->xdpy, xwin, &attr); XSync (xlib_renderer->xdpy, False); xerror = _cogl_xlib_renderer_untrap_errors (display->renderer, &state); if (status == 0 || xerror) { char message[1000]; XGetErrorText (xlib_renderer->xdpy, xerror, message, sizeof(message)); _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_ONSCREEN, "Unable to query geometry of foreign xid 0x%08lX: %s", xwin, message); return FALSE; } _cogl_framebuffer_winsys_update_size (framebuffer, attr.width, attr.height); /* Make sure the app selects for the events we require... */ onscreen->foreign_update_mask_callback (onscreen, COGL_ONSCREEN_X11_EVENT_MASK, onscreen->foreign_update_mask_data); } else { int width; int height; CoglXlibTrapState state; XVisualInfo *xvisinfo; XSetWindowAttributes xattr; unsigned long mask; int xerror; width = cogl_framebuffer_get_width (framebuffer); height = cogl_framebuffer_get_height (framebuffer); _cogl_xlib_renderer_trap_errors (display->renderer, &state); xvisinfo = glx_renderer->glXGetVisualFromFBConfig (xlib_renderer->xdpy, fbconfig); if (xvisinfo == NULL) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_ONSCREEN, "Unable to retrieve the X11 visual of context's " "fbconfig"); return FALSE; } /* window attributes */ xattr.background_pixel = WhitePixel (xlib_renderer->xdpy, DefaultScreen (xlib_renderer->xdpy)); xattr.border_pixel = 0; /* XXX: is this an X resource that we are leaking‽... */ xattr.colormap = XCreateColormap (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), xvisinfo->visual, AllocNone); xattr.event_mask = COGL_ONSCREEN_X11_EVENT_MASK; mask = CWBorderPixel | CWColormap | CWEventMask; xwin = XCreateWindow (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), 0, 0, width, height, 0, xvisinfo->depth, InputOutput, xvisinfo->visual, mask, &xattr); XFree (xvisinfo); XSync (xlib_renderer->xdpy, False); xerror = _cogl_xlib_renderer_untrap_errors (display->renderer, &state); if (xerror) { char message[1000]; XGetErrorText (xlib_renderer->xdpy, xerror, message, sizeof (message)); _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_ONSCREEN, "X error while creating Window for CoglOnscreen: %s", message); return FALSE; } } onscreen->winsys = g_slice_new0 (CoglOnscreenGLX); xlib_onscreen = onscreen->winsys; glx_onscreen = onscreen->winsys; xlib_onscreen->xwin = xwin; xlib_onscreen->is_foreign_xwin = onscreen->foreign_xid ? TRUE : FALSE; /* Try and create a GLXWindow to use with extensions dependent on * GLX versions >= 1.3 that don't accept regular X Windows as GLX * drawables. */ if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 3) { glx_onscreen->glxwin = glx_renderer->glXCreateWindow (xlib_renderer->xdpy, fbconfig, xlib_onscreen->xwin, NULL); } #ifdef GLX_INTEL_swap_event if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) && !_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT)) { GLXDrawable drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; /* similarly to above, we unconditionally select this event * because we rely on it to advance the master clock, and * drive redraw/relayout, animations and event handling. */ glx_renderer->glXSelectEvent (xlib_renderer->xdpy, drawable, GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK); } #endif /* GLX_INTEL_swap_event */ return TRUE; } static void _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglContextGLX *glx_context = context->winsys; CoglGLXDisplay *glx_display = context->display->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; CoglXlibTrapState old_state; CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; GLXDrawable drawable; /* If we never successfully allocated then there's nothing to do */ if (glx_onscreen == NULL) return; if (xlib_onscreen->output != NULL) { cogl_object_unref (xlib_onscreen->output); xlib_onscreen->output = NULL; } if (glx_onscreen->swap_wait_thread) { g_mutex_lock (&glx_onscreen->swap_wait_mutex); glx_onscreen->closing_down = TRUE; g_cond_signal (&glx_onscreen->swap_wait_cond); g_mutex_unlock (&glx_onscreen->swap_wait_mutex); g_thread_join (glx_onscreen->swap_wait_thread); glx_onscreen->swap_wait_thread = NULL; g_cond_clear (&glx_onscreen->swap_wait_cond); g_mutex_clear (&glx_onscreen->swap_wait_mutex); g_queue_free (glx_onscreen->swap_wait_queue); glx_onscreen->swap_wait_queue = NULL; _cogl_poll_renderer_remove_fd (context->display->renderer, glx_onscreen->swap_wait_pipe[0]); close (glx_onscreen->swap_wait_pipe[0]); close (glx_onscreen->swap_wait_pipe[1]); glx_renderer->glXDestroyContext (xlib_renderer->xdpy, glx_onscreen->swap_wait_context); } _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state); drawable = glx_onscreen->glxwin == None ? xlib_onscreen->xwin : glx_onscreen->glxwin; /* Cogl always needs a valid context bound to something so if we are * destroying the onscreen that is currently bound we'll switch back * to the dummy drawable. Although the documentation for * glXDestroyWindow states that a currently bound window won't * actually be destroyed until it is unbound, it looks like this * doesn't work if the X window itself is destroyed */ if (drawable == glx_context->current_drawable) { GLXDrawable dummy_drawable = (glx_display->dummy_glxwin == None ? glx_display->dummy_xwin : glx_display->dummy_glxwin); glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, dummy_drawable, dummy_drawable, glx_display->glx_context); glx_context->current_drawable = dummy_drawable; } if (glx_onscreen->glxwin != None) { glx_renderer->glXDestroyWindow (xlib_renderer->xdpy, glx_onscreen->glxwin); glx_onscreen->glxwin = None; } if (!xlib_onscreen->is_foreign_xwin && xlib_onscreen->xwin != None) { XDestroyWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); xlib_onscreen->xwin = None; } else xlib_onscreen->xwin = None; XSync (xlib_renderer->xdpy, False); _cogl_xlib_renderer_untrap_errors (context->display->renderer, &old_state); g_slice_free (CoglOnscreenGLX, onscreen->winsys); onscreen->winsys = NULL; } static void _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglContextGLX *glx_context = context->winsys; CoglGLXDisplay *glx_display = context->display->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglXlibTrapState old_state; GLXDrawable drawable; drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; if (glx_context->current_drawable == drawable) return; _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state); COGL_NOTE (WINSYS, "MakeContextCurrent dpy: %p, window: 0x%x (%s), context: %p", xlib_renderer->xdpy, (unsigned int) drawable, xlib_onscreen->is_foreign_xwin ? "foreign" : "native", glx_display->glx_context); glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, drawable, drawable, glx_display->glx_context); /* In case we are using GLX_SGI_swap_control for vblank syncing * we need call glXSwapIntervalSGI here to make sure that it * affects the current drawable. * * Note: we explicitly set to 0 when we aren't using the swap * interval to synchronize since some drivers have a default * swap interval of 1. Sadly some drivers even ignore requests * to disable the swap interval. * * NB: glXSwapIntervalSGI applies to the context not the * drawable which is why we can't just do this once when the * framebuffer is allocated. * * FIXME: We should check for GLX_EXT_swap_control which allows * per framebuffer swap intervals. GLX_MESA_swap_control also * allows per-framebuffer swap intervals but the semantics tend * to be more muddled since Mesa drivers tend to expose both the * MESA and SGI extensions which should technically be mutually * exclusive. */ if (glx_renderer->glXSwapInterval) { CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen); if (fb->config.swap_throttled) glx_renderer->glXSwapInterval (1); else glx_renderer->glXSwapInterval (0); } XSync (xlib_renderer->xdpy, False); /* FIXME: We should be reporting a CoglError here */ if (_cogl_xlib_renderer_untrap_errors (context->display->renderer, &old_state)) { g_warning ("X Error received while making drawable 0x%08lX current", drawable); return; } glx_context->current_drawable = drawable; } static void _cogl_winsys_wait_for_gpu (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *ctx = framebuffer->context; ctx->glFinish (); } static void _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *ctx = framebuffer->context; CoglGLXRenderer *glx_renderer; CoglXlibRenderer *xlib_renderer; CoglGLXDisplay *glx_display; glx_renderer = ctx->display->renderer->winsys; xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer); glx_display = ctx->display->winsys; if (glx_display->can_vblank_wait) { CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos); if (glx_renderer->glXWaitForMsc) { CoglOnscreenGLX *glx_onscreen = onscreen->winsys; Drawable drawable = glx_onscreen->glxwin; int64_t ust; int64_t msc; int64_t sbc; glx_renderer->glXWaitForMsc (xlib_renderer->xdpy, drawable, 0, 1, 0, &ust, &msc, &sbc); info->presentation_time = ust_to_nanoseconds (ctx->display->renderer, drawable, ust); } else { uint32_t current_count; glx_renderer->glXGetVideoSync (¤t_count); glx_renderer->glXWaitVideoSync (2, (current_count + 1) % 2, ¤t_count); info->presentation_time = get_monotonic_time_ns (); } } } static uint32_t _cogl_winsys_get_vsync_counter (CoglContext *ctx) { uint32_t video_sync_count; CoglGLXRenderer *glx_renderer; glx_renderer = ctx->display->renderer->winsys; glx_renderer->glXGetVideoSync (&video_sync_count); return video_sync_count; } #ifndef GLX_BACK_BUFFER_AGE_EXT #define GLX_BACK_BUFFER_AGE_EXT 0x20F4 #endif static int _cogl_winsys_onscreen_get_buffer_age (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; GLXDrawable drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; unsigned int age; if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE)) return 0; glx_renderer->glXQueryDrawable (xlib_renderer->xdpy, drawable, GLX_BACK_BUFFER_AGE_EXT, &age); return age; } static void set_frame_info_output (CoglOnscreen *onscreen, CoglOutput *output) { CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos); info->output = output; if (output) { float refresh_rate = cogl_output_get_refresh_rate (output); if (refresh_rate != 0.0) info->refresh_rate = refresh_rate; } } static gpointer threaded_swap_wait (gpointer data) { CoglOnscreen *onscreen = data; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglDisplay *display = context->display; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); CoglGLXDisplay *glx_display = display->winsys; CoglGLXRenderer *glx_renderer = display->renderer->winsys; GLXDrawable dummy_drawable; if (glx_display->dummy_glxwin) dummy_drawable = glx_display->dummy_glxwin; else dummy_drawable = glx_display->dummy_xwin; glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, dummy_drawable, dummy_drawable, glx_onscreen->swap_wait_context); g_mutex_lock (&glx_onscreen->swap_wait_mutex); while (TRUE) { gpointer queue_element; uint32_t vblank_counter; while (!glx_onscreen->closing_down && glx_onscreen->swap_wait_queue->length == 0) g_cond_wait (&glx_onscreen->swap_wait_cond, &glx_onscreen->swap_wait_mutex); if (glx_onscreen->closing_down) break; queue_element = g_queue_pop_tail (glx_onscreen->swap_wait_queue); vblank_counter = GPOINTER_TO_UINT(queue_element); g_mutex_unlock (&glx_onscreen->swap_wait_mutex); glx_renderer->glXWaitVideoSync (2, (vblank_counter + 1) % 2, &vblank_counter); g_mutex_lock (&glx_onscreen->swap_wait_mutex); if (!glx_onscreen->closing_down) { int bytes_written = 0; union { char bytes[8]; int64_t presentation_time; } u; u.presentation_time = get_monotonic_time_ns (); while (bytes_written < 8) { int res = write (glx_onscreen->swap_wait_pipe[1], u.bytes + bytes_written, 8 - bytes_written); if (res == -1) { if (errno != EINTR) g_error ("Error writing to swap notification pipe: %s\n", g_strerror (errno)); } else { bytes_written += res; } } } } g_mutex_unlock (&glx_onscreen->swap_wait_mutex); glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, None, None, NULL); return NULL; } static int64_t threaded_swap_wait_pipe_prepare (void *user_data) { return -1; } static void threaded_swap_wait_pipe_dispatch (void *user_data, int revents) { CoglOnscreen *onscreen = user_data; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglFrameInfo *info; if ((revents & COGL_POLL_FD_EVENT_IN)) { int bytes_read = 0; union { char bytes[8]; int64_t presentation_time; } u; while (bytes_read < 8) { int res = read (glx_onscreen->swap_wait_pipe[0], u.bytes + bytes_read, 8 - bytes_read); if (res == -1) { if (errno != EINTR) g_error ("Error reading from swap notification pipe: %s\n", g_strerror (errno)); } else { bytes_read += res; } } set_sync_pending (onscreen); set_complete_pending (onscreen); info = g_queue_peek_head (&onscreen->pending_frame_infos); info->presentation_time = u.presentation_time; } } static void start_threaded_swap_wait (CoglOnscreen *onscreen, uint32_t vblank_counter) { CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; if (glx_onscreen->swap_wait_thread == NULL) { CoglDisplay *display = context->display; CoglGLXRenderer *glx_renderer = display->renderer->winsys; CoglGLXDisplay *glx_display = display->winsys; CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); GLXDrawable drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; int i; ensure_ust_type (display->renderer, drawable); if ((pipe (glx_onscreen->swap_wait_pipe) == -1)) g_error ("Couldn't create pipe for swap notification: %s\n", g_strerror (errno)); for (i = 0; i < 2; i++) { if (fcntl(glx_onscreen->swap_wait_pipe[i], F_SETFD, fcntl(glx_onscreen->swap_wait_pipe[i], F_GETFD, 0) | FD_CLOEXEC) == -1) g_error ("Couldn't set swap notification pipe CLOEXEC: %s\n", g_strerror (errno)); } _cogl_poll_renderer_add_fd (display->renderer, glx_onscreen->swap_wait_pipe[0], COGL_POLL_FD_EVENT_IN, threaded_swap_wait_pipe_prepare, threaded_swap_wait_pipe_dispatch, onscreen); glx_onscreen->swap_wait_queue = g_queue_new (); g_mutex_init (&glx_onscreen->swap_wait_mutex); g_cond_init (&glx_onscreen->swap_wait_cond); glx_onscreen->swap_wait_context = glx_renderer->glXCreateNewContext (xlib_renderer->xdpy, glx_display->fbconfig, GLX_RGBA_TYPE, glx_display->glx_context, True); glx_onscreen->swap_wait_thread = g_thread_new ("cogl_glx_swap_wait", threaded_swap_wait, onscreen); } g_mutex_lock (&glx_onscreen->swap_wait_mutex); g_queue_push_head (glx_onscreen->swap_wait_queue, GUINT_TO_POINTER(vblank_counter)); g_cond_signal (&glx_onscreen->swap_wait_cond); g_mutex_unlock (&glx_onscreen->swap_wait_mutex); } static void _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, const int *user_rectangles, int n_rectangles) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; CoglGLXDisplay *glx_display = context->display->winsys; CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; GLXDrawable drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; uint32_t end_frame_vsync_counter = 0; CoglBool have_counter; CoglBool can_wait; int x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* * We assume that glXCopySubBuffer is synchronized which means it won't prevent multiple * blits per retrace if they can all be performed in the blanking period. If that's the * case then we still want to use the vblank sync menchanism but * we only need it to throttle redraws. */ CoglBool blit_sub_buffer_is_synchronized = _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION_SYNCHRONIZED); int framebuffer_width = cogl_framebuffer_get_width (framebuffer); int framebuffer_height = cogl_framebuffer_get_height (framebuffer); int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4); int i; /* glXCopySubBuffer expects rectangles relative to the bottom left corner but * we are given rectangles relative to the top left so we need to flip * them... */ memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4); for (i = 0; i < n_rectangles; i++) { int *rect = &rectangles[4 * i]; if (i == 0) { x_min = rect[0]; x_max = rect[0] + rect[2]; y_min = rect[1]; y_max = rect[1] + rect[3]; } else { x_min = MIN (x_min, rect[0]); x_max = MAX (x_max, rect[0] + rect[2]); y_min = MIN (y_min, rect[1]); y_max = MAX (y_max, rect[1] + rect[3]); } rect[1] = framebuffer_height - rect[1] - rect[3]; } _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_BIND); if (framebuffer->config.swap_throttled) { have_counter = glx_display->have_vblank_counter; can_wait = glx_display->can_vblank_wait; } else { have_counter = FALSE; can_wait = FALSE; } /* We need to ensure that all the rendering is done, otherwise * redraw operations that are slower than the framerate can * queue up in the pipeline during a heavy animation, causing a * larger and larger backlog of rendering visible as lag to the * user. * * For an exaggerated example consider rendering at 60fps (so 16ms * per frame) and you have a really slow frame that takes 160ms to * render, even though painting the scene and issuing the commands * to the GPU takes no time at all. If all we did was use the * video_sync extension to throttle the painting done by the CPU * then every 16ms we would have another frame queued up even though * the GPU has only rendered one tenth of the current frame. By the * time the GPU would get to the 2nd frame there would be 9 frames * waiting to be rendered. * * The problem is that we don't currently have a good way to throttle * the GPU, only the CPU so we have to resort to synchronizing the * GPU with the CPU to throttle it. * * Note: since calling glFinish() and synchronizing the CPU with * the GPU is far from ideal, we hope that this is only a short * term solution. * - One idea is to using sync objects to track render * completion so we can throttle the backlog (ideally with an * additional extension that lets us get notifications in our * mainloop instead of having to busy wait for the * completion.) * - Another option is to support clipped redraws by reusing the * contents of old back buffers such that we can flip instead * of using a blit and then we can use GLX_INTEL_swap_events * to throttle. For this though we would still probably want an * additional extension so we can report the limited region of * the window damage to X/compositors. */ _cogl_winsys_wait_for_gpu (onscreen); if (blit_sub_buffer_is_synchronized && have_counter && can_wait) { end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context); /* If we have the GLX_SGI_video_sync extension then we can * be a bit smarter about how we throttle blits by avoiding * any waits if we can see that the video sync count has * already progressed. */ if (glx_onscreen->last_swap_vsync_counter == end_frame_vsync_counter) _cogl_winsys_wait_for_vblank (onscreen); } else if (can_wait) _cogl_winsys_wait_for_vblank (onscreen); if (glx_renderer->glXCopySubBuffer) { Display *xdpy = xlib_renderer->xdpy; int i; for (i = 0; i < n_rectangles; i++) { int *rect = &rectangles[4 * i]; glx_renderer->glXCopySubBuffer (xdpy, drawable, rect[0], rect[1], rect[2], rect[3]); } } else if (context->glBlitFramebuffer) { int i; /* XXX: checkout how this state interacts with the code to use * glBlitFramebuffer in Neil's texture atlasing branch */ /* glBlitFramebuffer is affected by the scissor so we need to * ensure we have flushed an empty clip stack to get rid of it. * We also mark that the clip state is dirty so that it will be * flushed to the correct state the next time something is * drawn */ _cogl_clip_stack_flush (NULL, framebuffer); context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; context->glDrawBuffer (GL_FRONT); for (i = 0; i < n_rectangles; i++) { int *rect = &rectangles[4 * i]; int x2 = rect[0] + rect[2]; int y2 = rect[1] + rect[3]; context->glBlitFramebuffer (rect[0], rect[1], x2, y2, rect[0], rect[1], x2, y2, GL_COLOR_BUFFER_BIT, GL_NEAREST); } context->glDrawBuffer (context->current_gl_draw_buffer); } /* NB: unlike glXSwapBuffers, glXCopySubBuffer and * glBlitFramebuffer don't issue an implicit glFlush() so we * have to flush ourselves if we want the request to complete in * a finite amount of time since otherwise the driver can batch * the command indefinitely. */ context->glFlush (); /* NB: It's important we save the counter we read before acting on * the swap request since if we are mixing and matching different * swap methods between frames we don't want to read the timer e.g. * after calling glFinish() some times and not for others. * * In other words; this way we consistently save the time at the end * of the applications frame such that the counter isn't muddled by * the varying costs of different swap methods. */ if (have_counter) glx_onscreen->last_swap_vsync_counter = end_frame_vsync_counter; if (!xlib_onscreen->is_foreign_xwin) { CoglOutput *output; x_min = CLAMP (x_min, 0, framebuffer_width); x_max = CLAMP (x_max, 0, framebuffer_width); y_min = CLAMP (y_min, 0, framebuffer_width); y_max = CLAMP (y_max, 0, framebuffer_height); output = _cogl_xlib_renderer_output_for_rectangle (context->display->renderer, xlib_onscreen->x + x_min, xlib_onscreen->y + y_min, x_max - x_min, y_max - y_min); set_frame_info_output (onscreen, output); } /* XXX: we don't get SwapComplete events based on how we implement * the _swap_region() API but if cogl-onscreen.c knows we are * handling _SYNC and _COMPLETE events in the winsys then we need to * send fake events in this case. */ if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)) { set_sync_pending (onscreen); set_complete_pending (onscreen); } } static void _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; CoglGLXDisplay *glx_display = context->display->winsys; CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglBool have_counter; GLXDrawable drawable; /* XXX: theoretically this shouldn't be necessary but at least with * the Intel drivers we have see that if we don't call * glXMakeContextCurrent for the drawable we are swapping then * we get a BadDrawable error from the X server. */ _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_BIND); drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; if (framebuffer->config.swap_throttled) { have_counter = glx_display->have_vblank_counter; if (glx_renderer->glXSwapInterval) { if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT)) { /* If we didn't wait for the GPU here, then it's easy to get the case * where there is a VBlank between the point where we get the vsync counter * and the point where the GPU is ready to actually perform the glXSwapBuffers(), * and the swap wait terminates at the first VBlank rather than the one * where the swap buffers happens. Calling glFinish() here makes this a * rare race since the GPU is already ready to swap when we call glXSwapBuffers(). * The glFinish() also prevents any serious damage if the rare race happens, * since it will wait for the preceding glXSwapBuffers() and prevent us from * getting premanently ahead. (For NVIDIA drivers, glFinish() after glXSwapBuffers() * waits for the buffer swap to happen.) */ _cogl_winsys_wait_for_gpu (onscreen); start_threaded_swap_wait (onscreen, _cogl_winsys_get_vsync_counter (context)); } } else { CoglBool can_wait = have_counter || glx_display->can_vblank_wait; uint32_t end_frame_vsync_counter = 0; /* If the swap_region API is also being used then we need to track * the vsync counter for each swap request so we can manually * throttle swap_region requests. */ if (have_counter) end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context); /* If we are going to wait for VBLANK manually, we not only * need to flush out pending drawing to the GPU before we * sleep, we need to wait for it to finish. Otherwise, we * may end up with the situation: * * - We finish drawing - GPU drawing continues * - We go to sleep - GPU drawing continues * VBLANK - We call glXSwapBuffers - GPU drawing continues * - GPU drawing continues * - Swap buffers happens * * Producing a tear. Calling glFinish() first will cause us * to properly wait for the next VBLANK before we swap. This * obviously does not happen when we use _GLX_SWAP and let * the driver do the right thing */ _cogl_winsys_wait_for_gpu (onscreen); if (have_counter && can_wait) { if (glx_onscreen->last_swap_vsync_counter == end_frame_vsync_counter) _cogl_winsys_wait_for_vblank (onscreen); } else if (can_wait) _cogl_winsys_wait_for_vblank (onscreen); } } else have_counter = FALSE; glx_renderer->glXSwapBuffers (xlib_renderer->xdpy, drawable); if (have_counter) glx_onscreen->last_swap_vsync_counter = _cogl_winsys_get_vsync_counter (context); set_frame_info_output (onscreen, xlib_onscreen->output); } static uint32_t _cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen) { CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; return xlib_onscreen->xwin; } static void _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglContextGLX *glx_context = context->winsys; CoglOnscreenGLX *glx_onscreen = onscreen->winsys; CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; GLXDrawable drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; if (glx_context->current_drawable != drawable) return; glx_context->current_drawable = 0; _cogl_winsys_onscreen_bind (onscreen); } static void _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen, CoglBool visibility) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; if (visibility) XMapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); else XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); } static void _cogl_winsys_onscreen_set_resizable (CoglOnscreen *onscreen, CoglBool resizable) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; XSizeHints *size_hints = XAllocSizeHints (); if (resizable) { /* TODO: Add cogl_onscreen_request_minimum_size () */ size_hints->min_width = 1; size_hints->min_height = 1; size_hints->max_width = INT_MAX; size_hints->max_height = INT_MAX; } else { int width = cogl_framebuffer_get_width (framebuffer); int height = cogl_framebuffer_get_height (framebuffer); size_hints->min_width = width; size_hints->min_height = height; size_hints->max_width = width; size_hints->max_height = height; } XSetWMNormalHints (xlib_renderer->xdpy, xlib_onscreen->xwin, size_hints); XFree (size_hints); } static CoglBool get_fbconfig_for_depth (CoglContext *context, unsigned int depth, CoglBool stereo, GLXFBConfig *fbconfig_ret, CoglBool *can_mipmap_ret) { CoglXlibRenderer *xlib_renderer; CoglGLXRenderer *glx_renderer; CoglGLXDisplay *glx_display; Display *dpy; GLXFBConfig *fbconfigs; int n_elements, i; int db, stencil, alpha, mipmap, rgba, value; int spare_cache_slot = 0; CoglBool found = FALSE; xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer); glx_renderer = context->display->renderer->winsys; glx_display = context->display->winsys; /* Check if we've already got a cached config for this depth and stereo */ for (i = 0; i < COGL_GLX_N_CACHED_CONFIGS; i++) if (glx_display->glx_cached_configs[i].depth == -1) spare_cache_slot = i; else if (glx_display->glx_cached_configs[i].depth == depth && glx_display->glx_cached_configs[i].stereo == stereo) { *fbconfig_ret = glx_display->glx_cached_configs[i].fb_config; *can_mipmap_ret = glx_display->glx_cached_configs[i].can_mipmap; return glx_display->glx_cached_configs[i].found; } dpy = xlib_renderer->xdpy; fbconfigs = glx_renderer->glXGetFBConfigs (dpy, DefaultScreen (dpy), &n_elements); db = G_MAXSHORT; stencil = G_MAXSHORT; mipmap = 0; rgba = 0; for (i = 0; i < n_elements; i++) { XVisualInfo *vi; int visual_depth; vi = glx_renderer->glXGetVisualFromFBConfig (dpy, fbconfigs[i]); if (vi == NULL) continue; visual_depth = vi->depth; XFree (vi); if (visual_depth != depth) continue; glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_ALPHA_SIZE, &alpha); glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BUFFER_SIZE, &value); if (value != depth && (value - alpha) != depth) continue; glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_STEREO, &value); if (!!value != !!stereo) continue; if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 4) { glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_SAMPLES, &value); if (value > 1) continue; } value = 0; if (depth == 32) { glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &value); if (value) rgba = 1; } if (!value) { if (rgba) continue; glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &value); if (!value) continue; } glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_DOUBLEBUFFER, &value); if (value > db) continue; db = value; glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_STENCIL_SIZE, &value); if (value > stencil) continue; stencil = value; /* glGenerateMipmap is defined in the offscreen extension */ if (cogl_has_feature (context, COGL_FEATURE_ID_OFFSCREEN)) { glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BIND_TO_MIPMAP_TEXTURE_EXT, &value); if (value < mipmap) continue; mipmap = value; } *fbconfig_ret = fbconfigs[i]; *can_mipmap_ret = mipmap; found = TRUE; } if (n_elements) XFree (fbconfigs); glx_display->glx_cached_configs[spare_cache_slot].depth = depth; glx_display->glx_cached_configs[spare_cache_slot].found = found; glx_display->glx_cached_configs[spare_cache_slot].fb_config = *fbconfig_ret; glx_display->glx_cached_configs[spare_cache_slot].can_mipmap = mipmap; return found; } static CoglBool should_use_rectangle (CoglContext *context) { if (context->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_UNKNOWN) { if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RECTANGLE)) { const char *rect_env; /* Use the rectangle only if it is available and either: the COGL_PIXMAP_TEXTURE_RECTANGLE environment variable is set to 'force' *or* the env var is set to 'allow' or not set and NPOTs textures are not available */ context->rectangle_state = cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_NPOT) ? COGL_WINSYS_RECTANGLE_STATE_DISABLE : COGL_WINSYS_RECTANGLE_STATE_ENABLE; if ((rect_env = g_getenv ("COGL_PIXMAP_TEXTURE_RECTANGLE")) || /* For compatibility, we'll also look at the old Clutter environment variable */ (rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE"))) { if (g_ascii_strcasecmp (rect_env, "force") == 0) context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_ENABLE; else if (g_ascii_strcasecmp (rect_env, "disable") == 0) context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE; else if (g_ascii_strcasecmp (rect_env, "allow")) g_warning ("Unknown value for COGL_PIXMAP_TEXTURE_RECTANGLE, " "should be 'force' or 'disable'"); } } else context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE; } return context->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_ENABLE; } static CoglBool try_create_glx_pixmap (CoglContext *context, CoglTexturePixmapX11 *tex_pixmap, CoglBool mipmap) { CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys; CoglRenderer *renderer; CoglXlibRenderer *xlib_renderer; CoglGLXRenderer *glx_renderer; Display *dpy; /* We have to initialize this *opaque* variable because gcc tries to * be too smart for its own good and warns that the variable may be * used uninitialized otherwise. */ GLXFBConfig fb_config = (GLXFBConfig)0; int attribs[7]; int i = 0; GLenum target; CoglXlibTrapState trap_state; unsigned int depth = tex_pixmap->depth; Visual* visual = tex_pixmap->visual; renderer = context->display->renderer; xlib_renderer = _cogl_xlib_renderer_get_data (renderer); glx_renderer = renderer->winsys; dpy = xlib_renderer->xdpy; if (!get_fbconfig_for_depth (context, depth, tex_pixmap->stereo_mode != COGL_TEXTURE_PIXMAP_MONO, &fb_config, &glx_tex_pixmap->can_mipmap)) { COGL_NOTE (TEXTURE_PIXMAP, "No suitable FBConfig found for depth %i", depth); return FALSE; } if (should_use_rectangle (context)) { target = GLX_TEXTURE_RECTANGLE_EXT; glx_tex_pixmap->can_mipmap = FALSE; } else target = GLX_TEXTURE_2D_EXT; if (!glx_tex_pixmap->can_mipmap) mipmap = FALSE; attribs[i++] = GLX_TEXTURE_FORMAT_EXT; /* Check whether an alpha channel is used by comparing the total * number of 1-bits in color masks against the color depth requested * by the client. */ if (_cogl_util_popcountl (visual->red_mask | visual->green_mask | visual->blue_mask) == depth) attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT; else attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT; attribs[i++] = GLX_MIPMAP_TEXTURE_EXT; attribs[i++] = mipmap; attribs[i++] = GLX_TEXTURE_TARGET_EXT; attribs[i++] = target; attribs[i++] = None; /* We need to trap errors from glXCreatePixmap because it can * sometimes fail during normal usage. For example on NVidia it gets * upset if you try to create two GLXPixmaps for the same drawable. */ _cogl_xlib_renderer_trap_errors (renderer, &trap_state); glx_tex_pixmap->glx_pixmap = glx_renderer->glXCreatePixmap (dpy, fb_config, tex_pixmap->pixmap, attribs); glx_tex_pixmap->has_mipmap_space = mipmap; XSync (dpy, False); if (_cogl_xlib_renderer_untrap_errors (renderer, &trap_state)) { COGL_NOTE (TEXTURE_PIXMAP, "Failed to create pixmap for %p", tex_pixmap); _cogl_xlib_renderer_trap_errors (renderer, &trap_state); glx_renderer->glXDestroyPixmap (dpy, glx_tex_pixmap->glx_pixmap); XSync (dpy, False); _cogl_xlib_renderer_untrap_errors (renderer, &trap_state); glx_tex_pixmap->glx_pixmap = None; return FALSE; } return TRUE; } static CoglBool _cogl_winsys_texture_pixmap_x11_create (CoglTexturePixmapX11 *tex_pixmap) { CoglTexturePixmapGLX *glx_tex_pixmap; CoglContext *ctx = COGL_TEXTURE (tex_pixmap)->context; if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP)) { tex_pixmap->winsys = NULL; return FALSE; } glx_tex_pixmap = g_new0 (CoglTexturePixmapGLX, 1); glx_tex_pixmap->glx_pixmap = None; glx_tex_pixmap->can_mipmap = FALSE; glx_tex_pixmap->has_mipmap_space = FALSE; glx_tex_pixmap->left.glx_tex = NULL; glx_tex_pixmap->right.glx_tex = NULL; glx_tex_pixmap->left.bind_tex_image_queued = TRUE; glx_tex_pixmap->right.bind_tex_image_queued = TRUE; glx_tex_pixmap->left.pixmap_bound = FALSE; glx_tex_pixmap->right.pixmap_bound = FALSE; tex_pixmap->winsys = glx_tex_pixmap; if (!try_create_glx_pixmap (ctx, tex_pixmap, FALSE)) { tex_pixmap->winsys = NULL; free (glx_tex_pixmap); return FALSE; } return TRUE; } static void free_glx_pixmap (CoglContext *context, CoglTexturePixmapGLX *glx_tex_pixmap) { CoglXlibTrapState trap_state; CoglRenderer *renderer; CoglXlibRenderer *xlib_renderer; CoglGLXRenderer *glx_renderer; renderer = context->display->renderer; xlib_renderer = _cogl_xlib_renderer_get_data (renderer); glx_renderer = renderer->winsys; if (glx_tex_pixmap->left.pixmap_bound) glx_renderer->glXReleaseTexImage (xlib_renderer->xdpy, glx_tex_pixmap->glx_pixmap, GLX_FRONT_LEFT_EXT); if (glx_tex_pixmap->right.pixmap_bound) glx_renderer->glXReleaseTexImage (xlib_renderer->xdpy, glx_tex_pixmap->glx_pixmap, GLX_FRONT_RIGHT_EXT); /* FIXME - we need to trap errors and synchronize here because * of ordering issues between the XPixmap destruction and the * GLXPixmap destruction. * * If the X pixmap is destroyed, the GLX pixmap is destroyed as * well immediately, and thus, when Cogl calls glXDestroyPixmap() * it'll cause a BadDrawable error. * * this is technically a bug in the X server, which should not * destroy either pixmaps until the call to glXDestroyPixmap(); so * at some point we should revisit this code and remove the * trap+sync after verifying that the destruction is indeed safe. * * for reference, see: * http://bugzilla.clutter-project.org/show_bug.cgi?id=2324 */ _cogl_xlib_renderer_trap_errors (renderer, &trap_state); glx_renderer->glXDestroyPixmap (xlib_renderer->xdpy, glx_tex_pixmap->glx_pixmap); XSync (xlib_renderer->xdpy, False); _cogl_xlib_renderer_untrap_errors (renderer, &trap_state); glx_tex_pixmap->glx_pixmap = None; glx_tex_pixmap->left.pixmap_bound = FALSE; glx_tex_pixmap->right.pixmap_bound = FALSE; } static void _cogl_winsys_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap) { CoglTexturePixmapGLX *glx_tex_pixmap; if (!tex_pixmap->winsys) return; glx_tex_pixmap = tex_pixmap->winsys; free_glx_pixmap (COGL_TEXTURE (tex_pixmap)->context, glx_tex_pixmap); if (glx_tex_pixmap->left.glx_tex) cogl_object_unref (glx_tex_pixmap->left.glx_tex); if (glx_tex_pixmap->right.glx_tex) cogl_object_unref (glx_tex_pixmap->right.glx_tex); tex_pixmap->winsys = NULL; free (glx_tex_pixmap); } static CoglBool _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, CoglTexturePixmapStereoMode stereo_mode, CoglBool needs_mipmap) { CoglTexture *tex = COGL_TEXTURE (tex_pixmap); CoglContext *ctx = COGL_TEXTURE (tex_pixmap)->context; CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys; CoglPixmapTextureEyeGLX *texture_info; int buffer; CoglGLXRenderer *glx_renderer; if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) { texture_info = &glx_tex_pixmap->right; buffer = GLX_FRONT_RIGHT_EXT; } else { texture_info = &glx_tex_pixmap->left; buffer = GLX_FRONT_LEFT_EXT; } /* If we don't have a GLX pixmap then fallback */ if (glx_tex_pixmap->glx_pixmap == None) return FALSE; glx_renderer = ctx->display->renderer->winsys; /* Lazily create a texture to hold the pixmap */ if (texture_info->glx_tex == NULL) { CoglPixelFormat texture_format; CoglError *error = NULL; texture_format = (tex_pixmap->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); if (should_use_rectangle (ctx)) { texture_info->glx_tex = COGL_TEXTURE ( cogl_texture_rectangle_new_with_size (ctx, tex->width, tex->height)); _cogl_texture_set_internal_format (tex, texture_format); if (cogl_texture_allocate (texture_info->glx_tex, &error)) COGL_NOTE (TEXTURE_PIXMAP, "Created a texture rectangle for %p", tex_pixmap); else { COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a " "texture rectangle could not be created: %s", tex_pixmap, error->message); cogl_error_free (error); free_glx_pixmap (ctx, glx_tex_pixmap); return FALSE; } } else { texture_info->glx_tex = COGL_TEXTURE ( cogl_texture_2d_new_with_size (ctx, tex->width, tex->height)); _cogl_texture_set_internal_format (tex, texture_format); if (cogl_texture_allocate (texture_info->glx_tex, &error)) COGL_NOTE (TEXTURE_PIXMAP, "Created a texture 2d for %p", tex_pixmap); else { COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a " "texture 2d could not be created: %s", tex_pixmap, error->message); cogl_error_free (error); free_glx_pixmap (ctx, glx_tex_pixmap); return FALSE; } } } if (needs_mipmap) { /* If we can't support mipmapping then temporarily fallback */ if (!glx_tex_pixmap->can_mipmap) return FALSE; /* Recreate the GLXPixmap if it wasn't previously created with a * mipmap tree */ if (!glx_tex_pixmap->has_mipmap_space) { free_glx_pixmap (ctx, glx_tex_pixmap); COGL_NOTE (TEXTURE_PIXMAP, "Recreating GLXPixmap with mipmap " "support for %p", tex_pixmap); if (!try_create_glx_pixmap (ctx, tex_pixmap, TRUE)) { /* If the pixmap failed then we'll permanently fallback * to using XImage. This shouldn't happen. */ COGL_NOTE (TEXTURE_PIXMAP, "Falling back to XGetImage " "updates for %p because creating the GLXPixmap " "with mipmap support failed", tex_pixmap); if (texture_info->glx_tex) cogl_object_unref (texture_info->glx_tex); return FALSE; } glx_tex_pixmap->left.bind_tex_image_queued = TRUE; glx_tex_pixmap->right.bind_tex_image_queued = TRUE; } } if (texture_info->bind_tex_image_queued) { GLuint gl_handle, gl_target; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer); cogl_texture_get_gl_texture (texture_info->glx_tex, &gl_handle, &gl_target); COGL_NOTE (TEXTURE_PIXMAP, "Rebinding GLXPixmap for %p", tex_pixmap); _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE); if (texture_info->pixmap_bound) glx_renderer->glXReleaseTexImage (xlib_renderer->xdpy, glx_tex_pixmap->glx_pixmap, buffer); glx_renderer->glXBindTexImage (xlib_renderer->xdpy, glx_tex_pixmap->glx_pixmap, buffer, NULL); /* According to the recommended usage in the spec for * GLX_EXT_texture_pixmap we should release the texture after * we've finished drawing with it and it is undefined what * happens if you render to a pixmap that is bound to a texture. * However that would require the texture backend to know when * Cogl has finished painting and it may be more expensive to * keep unbinding the texture. Leaving it bound appears to work * on Mesa and NVidia drivers and it is also what Compiz does so * it is probably ok */ texture_info->bind_tex_image_queued = FALSE; texture_info->pixmap_bound = TRUE; _cogl_texture_2d_externally_modified (texture_info->glx_tex); } return TRUE; } static void _cogl_winsys_texture_pixmap_x11_damage_notify (CoglTexturePixmapX11 *tex_pixmap) { CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys; glx_tex_pixmap->left.bind_tex_image_queued = TRUE; glx_tex_pixmap->right.bind_tex_image_queued = TRUE; } static CoglTexture * _cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap, CoglTexturePixmapStereoMode stereo_mode) { CoglTexturePixmapGLX *glx_tex_pixmap = tex_pixmap->winsys; if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) return glx_tex_pixmap->right.glx_tex; else return glx_tex_pixmap->left.glx_tex; } static CoglWinsysVtable _cogl_winsys_vtable = { .id = COGL_WINSYS_ID_GLX, .name = "GLX", .constraints = (COGL_RENDERER_CONSTRAINT_USES_X11 | COGL_RENDERER_CONSTRAINT_USES_XLIB), .renderer_get_proc_address = _cogl_winsys_renderer_get_proc_address, .renderer_connect = _cogl_winsys_renderer_connect, .renderer_disconnect = _cogl_winsys_renderer_disconnect, .renderer_outputs_changed = _cogl_winsys_renderer_outputs_changed, .display_setup = _cogl_winsys_display_setup, .display_destroy = _cogl_winsys_display_destroy, .context_init = _cogl_winsys_context_init, .context_deinit = _cogl_winsys_context_deinit, .context_get_clock_time = _cogl_winsys_get_clock_time, .onscreen_init = _cogl_winsys_onscreen_init, .onscreen_deinit = _cogl_winsys_onscreen_deinit, .onscreen_bind = _cogl_winsys_onscreen_bind, .onscreen_swap_buffers_with_damage = _cogl_winsys_onscreen_swap_buffers_with_damage, .onscreen_swap_region = _cogl_winsys_onscreen_swap_region, .onscreen_get_buffer_age = _cogl_winsys_onscreen_get_buffer_age, .onscreen_update_swap_throttled = _cogl_winsys_onscreen_update_swap_throttled, .onscreen_x11_get_window_xid = _cogl_winsys_onscreen_x11_get_window_xid, .onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility, .onscreen_set_resizable = _cogl_winsys_onscreen_set_resizable, /* X11 tfp support... */ /* XXX: instead of having a rather monolithic winsys vtable we could * perhaps look for a way to separate these... */ .texture_pixmap_x11_create = _cogl_winsys_texture_pixmap_x11_create, .texture_pixmap_x11_free = _cogl_winsys_texture_pixmap_x11_free, .texture_pixmap_x11_update = _cogl_winsys_texture_pixmap_x11_update, .texture_pixmap_x11_damage_notify = _cogl_winsys_texture_pixmap_x11_damage_notify, .texture_pixmap_x11_get_texture = _cogl_winsys_texture_pixmap_x11_get_texture, }; /* XXX: we use a function because no doubt someone will complain * about using c99 member initializers because they aren't portable * to windows. We want to avoid having to rigidly follow the real * order of members since some members are #ifdefd and we'd have * to mirror the #ifdefing to add padding etc. For any winsys that * can assume the platform has a sane compiler then we can just use * c99 initializers for insane platforms they can initialize * the members by name in a function. */ const CoglWinsysVtable * _cogl_winsys_glx_get_vtable (void) { return &_cogl_winsys_vtable; } GLXContext cogl_glx_context_get_glx_context (CoglContext *context) { CoglGLXDisplay *glx_display = context->display->winsys; return glx_display->glx_context; } muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-private.h0000664000175000017500000001220614211404421022440 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_WINSYS_PRIVATE_H #define __COGL_WINSYS_PRIVATE_H #include "cogl-renderer.h" #include "cogl-onscreen.h" #include "cogl-gles2.h" #ifdef COGL_HAS_XLIB_SUPPORT #include "cogl-texture-pixmap-x11-private.h" #endif #ifdef COGL_HAS_XLIB_SUPPORT #include #include "cogl-texture-pixmap-x11-private.h" #endif #ifdef COGL_HAS_EGL_SUPPORT #include "cogl-egl-private.h" #endif #include "cogl-poll.h" uint32_t _cogl_winsys_error_quark (void); #define COGL_WINSYS_ERROR (_cogl_winsys_error_quark ()) typedef enum { /*< prefix=COGL_WINSYS_ERROR >*/ COGL_WINSYS_ERROR_INIT, COGL_WINSYS_ERROR_CREATE_CONTEXT, COGL_WINSYS_ERROR_CREATE_ONSCREEN, COGL_WINSYS_ERROR_MAKE_CURRENT, COGL_WINSYS_ERROR_CREATE_GLES2_CONTEXT, } CoglWinsysError; typedef enum { COGL_WINSYS_RECTANGLE_STATE_UNKNOWN, COGL_WINSYS_RECTANGLE_STATE_DISABLE, COGL_WINSYS_RECTANGLE_STATE_ENABLE } CoglWinsysRectangleState; typedef struct _CoglWinsysVtable { CoglWinsysID id; CoglRendererConstraint constraints; const char *name; /* Required functions */ CoglFuncPtr (*renderer_get_proc_address) (CoglRenderer *renderer, const char *name, CoglBool in_core); CoglBool (*renderer_connect) (CoglRenderer *renderer, CoglError **error); void (*renderer_disconnect) (CoglRenderer *renderer); void (*renderer_outputs_changed) (CoglRenderer *renderer); CoglBool (*display_setup) (CoglDisplay *display, CoglError **error); void (*display_destroy) (CoglDisplay *display); CoglBool (*context_init) (CoglContext *context, CoglError **error); void (*context_deinit) (CoglContext *context); void * (*context_create_gles2_context) (CoglContext *ctx, CoglError **error); CoglBool (*onscreen_init) (CoglOnscreen *onscreen, CoglError **error); void (*onscreen_deinit) (CoglOnscreen *onscreen); void (*onscreen_bind) (CoglOnscreen *onscreen); void (*onscreen_swap_buffers_with_damage) (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles); void (*onscreen_update_swap_throttled) (CoglOnscreen *onscreen); void (*onscreen_set_visibility) (CoglOnscreen *onscreen, CoglBool visibility); /* Optional functions */ int64_t (*context_get_clock_time) (CoglContext *context); void (*onscreen_swap_region) (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles); void (*onscreen_set_resizable) (CoglOnscreen *onscreen, CoglBool resizable); int (*onscreen_get_buffer_age) (CoglOnscreen *onscreen); uint32_t (*onscreen_x11_get_window_xid) (CoglOnscreen *onscreen); #ifdef COGL_HAS_XLIB_SUPPORT CoglBool (*texture_pixmap_x11_create) (CoglTexturePixmapX11 *tex_pixmap); void (*texture_pixmap_x11_free) (CoglTexturePixmapX11 *tex_pixmap); CoglBool (*texture_pixmap_x11_update) (CoglTexturePixmapX11 *tex_pixmap, CoglTexturePixmapStereoMode stereo_mode, CoglBool needs_mipmap); void (*texture_pixmap_x11_damage_notify) (CoglTexturePixmapX11 *tex_pixmap); CoglTexture * (*texture_pixmap_x11_get_texture) (CoglTexturePixmapX11 *tex_pixmap, CoglTexturePixmapStereoMode stereo_mode); #endif void (*save_context) (CoglContext *ctx); CoglBool (*set_gles2_context) (CoglGLES2Context *gles2_ctx, CoglError **error); void (*restore_context) (CoglContext *ctx); void (*destroy_gles2_context) (CoglGLES2Context *gles2_ctx); void * (*fence_add) (CoglContext *ctx); CoglBool (*fence_is_complete) (CoglContext *ctx, void *fence); void (*fence_destroy) (CoglContext *ctx, void *fence); } CoglWinsysVtable; typedef const CoglWinsysVtable *(*CoglWinsysVtableGetter) (void); CoglBool _cogl_winsys_has_feature (CoglWinsysFeature feature); #endif /* __COGL_WINSYS_PRIVATE_H */ muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-egl.c0000664000175000017500000010760114211404421021534 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010,2011,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-i18n-private.h" #include "cogl-util.h" #include "cogl-winsys-egl-private.h" #include "cogl-winsys-private.h" #include "cogl-feature-private.h" #include "cogl-context-private.h" #include "cogl-framebuffer.h" #include "cogl-onscreen-private.h" #include "cogl-swap-chain-private.h" #include "cogl-renderer-private.h" #include "cogl-onscreen-template-private.h" #include "cogl-gles2-context-private.h" #include "cogl-error-private.h" #include "cogl-egl.h" #include "cogl-private.h" #include #include #include #include #include #ifndef EGL_KHR_create_context #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB #define EGL_CONTEXT_FLAGS_KHR 0x30FC #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD #define EGL_OPENGL_ES3_BIT_KHR 0x0040 #define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #endif #define MAX_EGL_CONFIG_ATTRIBS 30 /* Define a set of arrays containing the functions required from GL for each winsys feature */ #define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \ egl_private_flags) \ static const CoglFeatureFunction \ cogl_egl_feature_ ## name ## _funcs[] = { #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \ { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglRendererEGL, pf_ ## name) }, #define COGL_WINSYS_FEATURE_END() \ { NULL, 0 }, \ }; #include "cogl-winsys-egl-feature-functions.h" /* Define an array of features */ #undef COGL_WINSYS_FEATURE_BEGIN #define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \ egl_private_flags) \ { 255, 255, 0, namespaces, extension_names, \ 0, egl_private_flags, \ 0, \ cogl_egl_feature_ ## name ## _funcs }, #undef COGL_WINSYS_FEATURE_FUNCTION #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) #undef COGL_WINSYS_FEATURE_END #define COGL_WINSYS_FEATURE_END() static const CoglFeatureData winsys_feature_data[] = { #include "cogl-winsys-egl-feature-functions.h" }; static const char * get_error_string (void) { switch (eglGetError()){ case EGL_BAD_DISPLAY: return "Invalid display"; case EGL_NOT_INITIALIZED: return "Display not initialized"; case EGL_BAD_ALLOC: return "Not enough resources to allocate context"; case EGL_BAD_ATTRIBUTE: return "Invalid attribute"; case EGL_BAD_CONFIG: return "Invalid config"; case EGL_BAD_CONTEXT: return "Invalid context"; case EGL_BAD_CURRENT_SURFACE: return "Invalid current surface"; case EGL_BAD_MATCH: return "Bad match"; case EGL_BAD_NATIVE_PIXMAP: return "Invalid native pixmap"; case EGL_BAD_NATIVE_WINDOW: return "Invalid native window"; case EGL_BAD_PARAMETER: return "Invalid parameter"; case EGL_BAD_SURFACE: return "Invalid surface"; default: g_assert_not_reached (); } } static CoglFuncPtr _cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer, const char *name, CoglBool in_core) { void *ptr = NULL; if (!in_core) ptr = eglGetProcAddress (name); /* eglGetProcAddress doesn't support fetching core API so we need to get that separately with GModule */ if (ptr == NULL) g_module_symbol (renderer->libgl_module, name, &ptr); return ptr; } static void _cogl_winsys_renderer_disconnect (CoglRenderer *renderer) { /* This function must be overridden by a platform winsys */ g_assert_not_reached (); } /* Updates all the function pointers */ static void check_egl_extensions (CoglRenderer *renderer) { CoglRendererEGL *egl_renderer = renderer->winsys; const char *egl_extensions; char **split_extensions; int i; egl_extensions = eglQueryString (egl_renderer->edpy, EGL_EXTENSIONS); split_extensions = g_strsplit (egl_extensions, " ", 0 /* max_tokens */); COGL_NOTE (WINSYS, " EGL Extensions: %s", egl_extensions); egl_renderer->private_features = 0; for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++) if (_cogl_feature_check (renderer, "EGL", winsys_feature_data + i, 0, 0, COGL_DRIVER_GL, /* the driver isn't used */ split_extensions, egl_renderer)) { egl_renderer->private_features |= winsys_feature_data[i].feature_flags_private; } g_strfreev (split_extensions); } CoglBool _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer, CoglError **error) { CoglRendererEGL *egl_renderer = renderer->winsys; if (!eglInitialize (egl_renderer->edpy, &egl_renderer->egl_version_major, &egl_renderer->egl_version_minor)) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "Couldn't initialize EGL"); return FALSE; } check_egl_extensions (renderer); return TRUE; } static CoglBool _cogl_winsys_renderer_connect (CoglRenderer *renderer, CoglError **error) { /* This function must be overridden by a platform winsys */ g_assert_not_reached (); } static void egl_attributes_from_framebuffer_config (CoglDisplay *display, CoglFramebufferConfig *config, EGLint *attributes) { CoglRenderer *renderer = display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; int i = 0; /* Let the platform add attributes first, including setting the * EGL_SURFACE_TYPE */ i = egl_renderer->platform_vtable->add_config_attributes (display, config, attributes); if (config->need_stencil) { attributes[i++] = EGL_STENCIL_SIZE; attributes[i++] = 2; } attributes[i++] = EGL_RED_SIZE; attributes[i++] = 1; attributes[i++] = EGL_GREEN_SIZE; attributes[i++] = 1; attributes[i++] = EGL_BLUE_SIZE; attributes[i++] = 1; attributes[i++] = EGL_ALPHA_SIZE; attributes[i++] = config->swap_chain->has_alpha ? 1 : EGL_DONT_CARE; attributes[i++] = EGL_DEPTH_SIZE; attributes[i++] = 1; attributes[i++] = EGL_BUFFER_SIZE; attributes[i++] = EGL_DONT_CARE; attributes[i++] = EGL_RENDERABLE_TYPE; attributes[i++] = ((renderer->driver == COGL_DRIVER_GL || renderer->driver == COGL_DRIVER_GL3) ? EGL_OPENGL_BIT : renderer->driver == COGL_DRIVER_GLES1 ? EGL_OPENGL_ES_BIT : EGL_OPENGL_ES2_BIT); if (config->samples_per_pixel) { attributes[i++] = EGL_SAMPLE_BUFFERS; attributes[i++] = 1; attributes[i++] = EGL_SAMPLES; attributes[i++] = config->samples_per_pixel; } attributes[i++] = EGL_NONE; g_assert (i < MAX_EGL_CONFIG_ATTRIBS); } EGLBoolean _cogl_winsys_egl_make_current (CoglDisplay *display, EGLSurface draw, EGLSurface read, EGLContext context) { CoglDisplayEGL *egl_display = display->winsys; CoglRendererEGL *egl_renderer = display->renderer->winsys; EGLBoolean ret; if (egl_display->current_draw_surface == draw && egl_display->current_read_surface == read && egl_display->current_context == context) return EGL_TRUE; ret = eglMakeCurrent (egl_renderer->edpy, draw, read, context); egl_display->current_draw_surface = draw; egl_display->current_read_surface = read; egl_display->current_context = context; return ret; } EGLBoolean _cogl_winsys_egl_ensure_current (CoglDisplay *display) { CoglDisplayEGL *egl_display = display->winsys; CoglRendererEGL *egl_renderer = display->renderer->winsys; return eglMakeCurrent (egl_renderer->edpy, egl_display->current_draw_surface, egl_display->current_read_surface, egl_display->current_context); } static void cleanup_context (CoglDisplay *display) { CoglRenderer *renderer = display->renderer; CoglDisplayEGL *egl_display = display->winsys; CoglRendererEGL *egl_renderer = renderer->winsys; if (egl_display->egl_context != EGL_NO_CONTEXT) { _cogl_winsys_egl_make_current (display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext (egl_renderer->edpy, egl_display->egl_context); egl_display->egl_context = EGL_NO_CONTEXT; } if (egl_renderer->platform_vtable->cleanup_context) egl_renderer->platform_vtable->cleanup_context (display); } static CoglBool try_create_context (CoglDisplay *display, CoglError **error) { CoglRenderer *renderer = display->renderer; CoglDisplayEGL *egl_display = display->winsys; CoglRendererEGL *egl_renderer = renderer->winsys; EGLDisplay edpy; EGLConfig config; EGLint attribs[9]; EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS]; GError *config_error = NULL; const char *error_message; _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context == NULL, TRUE); if (renderer->driver == COGL_DRIVER_GL || renderer->driver == COGL_DRIVER_GL3) eglBindAPI (EGL_OPENGL_API); egl_attributes_from_framebuffer_config (display, &display->onscreen_template->config, cfg_attribs); edpy = egl_renderer->edpy; if (!egl_renderer->platform_vtable->choose_config (display, cfg_attribs, &config, &config_error)) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Couldn't choose config: %s", config_error->message); g_error_free (config_error); goto err; } egl_display->egl_config = config; if (display->renderer->driver == COGL_DRIVER_GL3) { if (!(egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT)) { error_message = "Driver does not support GL 3 contexts"; goto fail; } /* Try to get a core profile 3.1 context with no deprecated features */ attribs[0] = EGL_CONTEXT_MAJOR_VERSION_KHR; attribs[1] = 3; attribs[2] = EGL_CONTEXT_MINOR_VERSION_KHR; attribs[3] = 1; attribs[4] = EGL_CONTEXT_FLAGS_KHR; attribs[5] = EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; attribs[6] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; attribs[7] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; attribs[8] = EGL_NONE; } else if (display->renderer->driver == COGL_DRIVER_GLES2) { attribs[0] = EGL_CONTEXT_CLIENT_VERSION; attribs[1] = 2; attribs[2] = EGL_NONE; } else attribs[0] = EGL_NONE; egl_display->egl_context = eglCreateContext (edpy, config, EGL_NO_CONTEXT, attribs); if (egl_display->egl_context == EGL_NO_CONTEXT) { error_message = "Unable to create a suitable EGL context"; goto fail; } if (egl_renderer->platform_vtable->context_created && !egl_renderer->platform_vtable->context_created (display, error)) return FALSE; return TRUE; fail: _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "%s", error_message); err: cleanup_context (display); return FALSE; } static void _cogl_winsys_display_destroy (CoglDisplay *display) { CoglRendererEGL *egl_renderer = display->renderer->winsys; CoglDisplayEGL *egl_display = display->winsys; _COGL_RETURN_IF_FAIL (egl_display != NULL); cleanup_context (display); if (egl_renderer->platform_vtable->display_destroy) egl_renderer->platform_vtable->display_destroy (display); g_slice_free (CoglDisplayEGL, display->winsys); display->winsys = NULL; } static CoglBool _cogl_winsys_display_setup (CoglDisplay *display, CoglError **error) { CoglDisplayEGL *egl_display; CoglRenderer *renderer = display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; _COGL_RETURN_VAL_IF_FAIL (display->winsys == NULL, FALSE); egl_display = g_slice_new0 (CoglDisplayEGL); display->winsys = egl_display; #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT if (display->wayland_compositor_display) { struct wl_display *wayland_display = display->wayland_compositor_display; CoglRendererEGL *egl_renderer = display->renderer->winsys; if (egl_renderer->pf_eglBindWaylandDisplay) egl_renderer->pf_eglBindWaylandDisplay (egl_renderer->edpy, wayland_display); } #endif if (egl_renderer->platform_vtable->display_setup && !egl_renderer->platform_vtable->display_setup (display, error)) goto error; if (!try_create_context (display, error)) goto error; egl_display->found_egl_config = TRUE; return TRUE; error: _cogl_winsys_display_destroy (display); return FALSE; } static CoglBool _cogl_winsys_context_init (CoglContext *context, CoglError **error) { CoglRenderer *renderer = context->display->renderer; CoglDisplayEGL *egl_display = context->display->winsys; CoglRendererEGL *egl_renderer = renderer->winsys; context->winsys = g_new0 (CoglContextEGL, 1); _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE); memset (context->winsys_features, 0, sizeof (context->winsys_features)); check_egl_extensions (renderer); if (!_cogl_context_update_features (context, error)) return FALSE; if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SWAP_REGION) { COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION, TRUE); COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE); } if ((egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_FENCE_SYNC) && _cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_OES_EGL_SYNC)) COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_FENCE, TRUE); if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_BUFFER_AGE) { COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_BUFFER_AGE, TRUE); COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_BUFFER_AGE, TRUE); } /* NB: We currently only support creating standalone GLES2 contexts * for offscreen rendering and so we need a dummy (non-visible) * surface to be able to bind those contexts */ if (egl_display->dummy_surface != EGL_NO_SURFACE && context->driver == COGL_DRIVER_GLES2) COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GLES2_CONTEXT, TRUE); if (egl_renderer->platform_vtable->context_init && !egl_renderer->platform_vtable->context_init (context, error)) return FALSE; return TRUE; } static void _cogl_winsys_context_deinit (CoglContext *context) { CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; if (egl_renderer->platform_vtable->context_deinit) egl_renderer->platform_vtable->context_deinit (context); free (context->winsys); } typedef struct _CoglGLES2ContextEGL { EGLContext egl_context; EGLSurface dummy_surface; } CoglGLES2ContextEGL; static void * _cogl_winsys_context_create_gles2_context (CoglContext *ctx, CoglError **error) { CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys; CoglDisplayEGL *egl_display = ctx->display->winsys; EGLint attribs[3]; EGLContext egl_context; attribs[0] = EGL_CONTEXT_CLIENT_VERSION; attribs[1] = 2; attribs[2] = EGL_NONE; egl_context = eglCreateContext (egl_renderer->edpy, egl_display->egl_config, egl_display->egl_context, attribs); if (egl_context == EGL_NO_CONTEXT) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_GLES2_CONTEXT, "%s", get_error_string ()); return NULL; } return (void *)egl_context; } static void _cogl_winsys_destroy_gles2_context (CoglGLES2Context *gles2_ctx) { CoglContext *context = gles2_ctx->context; CoglDisplay *display = context->display; CoglDisplayEGL *egl_display = display->winsys; CoglRenderer *renderer = display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; EGLContext egl_context = gles2_ctx->winsys; _COGL_RETURN_IF_FAIL (egl_display->current_context != egl_context); eglDestroyContext (egl_renderer->edpy, egl_context); } static CoglBool _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, CoglError **error) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglDisplay *display = context->display; CoglDisplayEGL *egl_display = display->winsys; CoglRenderer *renderer = display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; EGLint attributes[MAX_EGL_CONFIG_ATTRIBS]; EGLConfig egl_config; EGLint config_count = 0; EGLBoolean status; _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE); egl_attributes_from_framebuffer_config (display, &framebuffer->config, attributes); status = eglChooseConfig (egl_renderer->edpy, attributes, &egl_config, 1, &config_count); if (status != EGL_TRUE || config_count == 0) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_ONSCREEN, "Failed to find a suitable EGL configuration"); return FALSE; } /* Update the real number of samples_per_pixel now that we have * found an egl_config... */ if (framebuffer->config.samples_per_pixel) { EGLint samples; status = eglGetConfigAttrib (egl_renderer->edpy, egl_config, EGL_SAMPLES, &samples); g_return_val_if_fail (status == EGL_TRUE, TRUE); framebuffer->samples_per_pixel = samples; } onscreen->winsys = g_slice_new0 (CoglOnscreenEGL); if (egl_renderer->platform_vtable->onscreen_init && !egl_renderer->platform_vtable->onscreen_init (onscreen, egl_config, error)) { g_slice_free (CoglOnscreenEGL, onscreen->winsys); return FALSE; } return TRUE; } static void _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; CoglDisplayEGL *egl_display = context->display->winsys; CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; /* If we never successfully allocated then there's nothing to do */ if (egl_onscreen == NULL) return; if (egl_onscreen->egl_surface != EGL_NO_SURFACE) { /* Cogl always needs a valid context bound to something so if we * are destroying the onscreen that is currently bound we'll * switch back to the dummy drawable. */ if ((egl_display->dummy_surface != EGL_NO_SURFACE || (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) != 0) && (egl_display->current_draw_surface == egl_onscreen->egl_surface || egl_display->current_read_surface == egl_onscreen->egl_surface)) { _cogl_winsys_egl_make_current (context->display, egl_display->dummy_surface, egl_display->dummy_surface, egl_display->current_context); } if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface) == EGL_FALSE) g_warning ("Failed to destroy EGL surface"); egl_onscreen->egl_surface = EGL_NO_SURFACE; } if (egl_renderer->platform_vtable->onscreen_deinit) egl_renderer->platform_vtable->onscreen_deinit (onscreen); g_slice_free (CoglOnscreenEGL, onscreen->winsys); onscreen->winsys = NULL; } static CoglBool bind_onscreen_with_context (CoglOnscreen *onscreen, EGLContext egl_context) { CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen); CoglContext *context = fb->context; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; CoglBool status = _cogl_winsys_egl_make_current (context->display, egl_onscreen->egl_surface, egl_onscreen->egl_surface, egl_context); if (status) { CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; if (fb->config.swap_throttled) eglSwapInterval (egl_renderer->edpy, 1); else eglSwapInterval (egl_renderer->edpy, 0); } return status; } static CoglBool bind_onscreen (CoglOnscreen *onscreen) { CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen); CoglContext *context = fb->context; CoglDisplayEGL *egl_display = context->display->winsys; return bind_onscreen_with_context (onscreen, egl_display->egl_context); } static void _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) { bind_onscreen (onscreen); } #ifndef EGL_BUFFER_AGE_EXT #define EGL_BUFFER_AGE_EXT 0x313D #endif static int _cogl_winsys_onscreen_get_buffer_age (CoglOnscreen *onscreen) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; EGLSurface surface = egl_onscreen->egl_surface; int age; if (!(egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_BUFFER_AGE)) return 0; eglQuerySurface (egl_renderer->edpy, surface, EGL_BUFFER_AGE_EXT, &age); return age; } static void _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, const int *user_rectangles, int n_rectangles) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); int framebuffer_height = cogl_framebuffer_get_height (framebuffer); int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4); int i; /* eglSwapBuffersRegion expects rectangles relative to the * bottom left corner but we are given rectangles relative to * the top left so we need to flip them... */ memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4); for (i = 0; i < n_rectangles; i++) { int *rect = &rectangles[4 * i]; rect[1] = framebuffer_height - rect[1] - rect[3]; } /* At least for eglSwapBuffers the EGL spec says that the surface to swap must be bound to the current context. It looks like Mesa also validates that this is the case for eglSwapBuffersRegion so we must bind here too */ _cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen), COGL_FRAMEBUFFER (onscreen), COGL_FRAMEBUFFER_STATE_BIND); if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy, egl_onscreen->egl_surface, n_rectangles, rectangles) == EGL_FALSE) g_warning ("Error reported by eglSwapBuffersRegion"); } static void _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; CoglRendererEGL *egl_renderer = renderer->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; /* The specification for EGL (at least in 1.4) says that the surface needs to be bound to the current context for the swap to work although it may change in future. Mesa explicitly checks for this and just returns an error if this is not the case so we can't just pretend this isn't in the spec. */ _cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen), COGL_FRAMEBUFFER (onscreen), COGL_FRAMEBUFFER_STATE_BIND); if (n_rectangles && egl_renderer->pf_eglSwapBuffersWithDamage) { CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen); size_t size = n_rectangles * sizeof (int) * 4; int *flipped = alloca (size); int i; memcpy (flipped, rectangles, size); for (i = 0; i < n_rectangles; i++) { const int *rect = rectangles + 4 * i; int *flip_rect = flipped + 4 * i; flip_rect[1] = fb->height - rect[1] - rect[3]; } if (egl_renderer->pf_eglSwapBuffersWithDamage (egl_renderer->edpy, egl_onscreen->egl_surface, flipped, n_rectangles) == EGL_FALSE) g_warning ("Error reported by eglSwapBuffersWithDamage"); } else eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface); } static void _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglDisplayEGL *egl_display = context->display->winsys; CoglOnscreenEGL *egl_onscreen = onscreen->winsys; if (egl_display->current_draw_surface != egl_onscreen->egl_surface) return; egl_display->current_draw_surface = EGL_NO_SURFACE; _cogl_winsys_onscreen_bind (onscreen); } static void _cogl_winsys_save_context (CoglContext *ctx) { CoglContextEGL *egl_context = ctx->winsys; CoglDisplayEGL *egl_display = ctx->display->winsys; egl_context->saved_draw_surface = egl_display->current_draw_surface; egl_context->saved_read_surface = egl_display->current_read_surface; } static CoglBool _cogl_winsys_set_gles2_context (CoglGLES2Context *gles2_ctx, CoglError **error) { CoglContext *ctx = gles2_ctx->context; CoglDisplayEGL *egl_display = ctx->display->winsys; CoglBool status; if (gles2_ctx->write_buffer && cogl_is_onscreen (gles2_ctx->write_buffer)) status = bind_onscreen_with_context (COGL_ONSCREEN (gles2_ctx->write_buffer), gles2_ctx->winsys); else status = _cogl_winsys_egl_make_current (ctx->display, egl_display->dummy_surface, egl_display->dummy_surface, gles2_ctx->winsys); if (!status) { _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_MAKE_CURRENT, "Failed to make gles2 context current"); return FALSE; } return TRUE; } static void _cogl_winsys_restore_context (CoglContext *ctx) { CoglContextEGL *egl_context = ctx->winsys; CoglDisplayEGL *egl_display = ctx->display->winsys; _cogl_winsys_egl_make_current (ctx->display, egl_context->saved_draw_surface, egl_context->saved_read_surface, egl_display->egl_context); } #if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync) static void * _cogl_winsys_fence_add (CoglContext *context) { CoglRendererEGL *renderer = context->display->renderer->winsys; void *ret; if (renderer->pf_eglCreateSync) ret = renderer->pf_eglCreateSync (renderer->edpy, EGL_SYNC_FENCE_KHR, NULL); else ret = NULL; return ret; } static CoglBool _cogl_winsys_fence_is_complete (CoglContext *context, void *fence) { CoglRendererEGL *renderer = context->display->renderer->winsys; EGLint ret; ret = renderer->pf_eglClientWaitSync (renderer->edpy, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 0); return (ret == EGL_CONDITION_SATISFIED_KHR); } static void _cogl_winsys_fence_destroy (CoglContext *context, void *fence) { CoglRendererEGL *renderer = context->display->renderer->winsys; renderer->pf_eglDestroySync (renderer->edpy, fence); } #endif static CoglWinsysVtable _cogl_winsys_vtable = { .constraints = COGL_RENDERER_CONSTRAINT_USES_EGL | COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2, /* This winsys is only used as a base for the EGL-platform winsys's so it does not have an ID or a name */ .renderer_get_proc_address = _cogl_winsys_renderer_get_proc_address, .renderer_connect = _cogl_winsys_renderer_connect, .renderer_disconnect = _cogl_winsys_renderer_disconnect, .display_setup = _cogl_winsys_display_setup, .display_destroy = _cogl_winsys_display_destroy, .context_init = _cogl_winsys_context_init, .context_deinit = _cogl_winsys_context_deinit, .context_create_gles2_context = _cogl_winsys_context_create_gles2_context, .destroy_gles2_context = _cogl_winsys_destroy_gles2_context, .onscreen_init = _cogl_winsys_onscreen_init, .onscreen_deinit = _cogl_winsys_onscreen_deinit, .onscreen_bind = _cogl_winsys_onscreen_bind, .onscreen_swap_buffers_with_damage = _cogl_winsys_onscreen_swap_buffers_with_damage, .onscreen_swap_region = _cogl_winsys_onscreen_swap_region, .onscreen_get_buffer_age = _cogl_winsys_onscreen_get_buffer_age, .onscreen_update_swap_throttled = _cogl_winsys_onscreen_update_swap_throttled, /* CoglGLES2Context related methods */ .save_context = _cogl_winsys_save_context, .set_gles2_context = _cogl_winsys_set_gles2_context, .restore_context = _cogl_winsys_restore_context, #if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync) .fence_add = _cogl_winsys_fence_add, .fence_is_complete = _cogl_winsys_fence_is_complete, .fence_destroy = _cogl_winsys_fence_destroy, #endif }; /* XXX: we use a function because no doubt someone will complain * about using c99 member initializers because they aren't portable * to windows. We want to avoid having to rigidly follow the real * order of members since some members are #ifdefd and we'd have * to mirror the #ifdefing to add padding etc. For any winsys that * can assume the platform has a sane compiler then we can just use * c99 initializers for insane platforms they can initialize * the members by name in a function. */ const CoglWinsysVtable * _cogl_winsys_egl_get_vtable (void) { return &_cogl_winsys_vtable; } #ifdef EGL_KHR_image_base EGLImageKHR _cogl_egl_create_image (CoglContext *ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attribs) { CoglDisplayEGL *egl_display = ctx->display->winsys; CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys; EGLContext egl_ctx; _COGL_RETURN_VAL_IF_FAIL (egl_renderer->pf_eglCreateImage, EGL_NO_IMAGE_KHR); /* The EGL_KHR_image_pixmap spec explicitly states that EGL_NO_CONTEXT must * always be used in conjunction with the EGL_NATIVE_PIXMAP_KHR target */ #ifdef EGL_KHR_image_pixmap if (target == EGL_NATIVE_PIXMAP_KHR) egl_ctx = EGL_NO_CONTEXT; else #endif #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT /* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be used * in conjunction with the EGL_WAYLAND_BUFFER_WL target */ if (target == EGL_WAYLAND_BUFFER_WL) egl_ctx = EGL_NO_CONTEXT; else #endif egl_ctx = egl_display->egl_context; return egl_renderer->pf_eglCreateImage (egl_renderer->edpy, egl_ctx, target, buffer, attribs); } void _cogl_egl_destroy_image (CoglContext *ctx, EGLImageKHR image) { CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys; _COGL_RETURN_IF_FAIL (egl_renderer->pf_eglDestroyImage); egl_renderer->pf_eglDestroyImage (egl_renderer->edpy, image); } #endif #ifdef EGL_WL_bind_wayland_display CoglBool _cogl_egl_query_wayland_buffer (CoglContext *ctx, struct wl_resource *buffer, int attribute, int *value) { CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys; _COGL_RETURN_VAL_IF_FAIL (egl_renderer->pf_eglQueryWaylandBuffer, FALSE); return egl_renderer->pf_eglQueryWaylandBuffer (egl_renderer->edpy, buffer, attribute, value); } #endif EGLDisplay cogl_egl_context_get_egl_display (CoglContext *context) { CoglRendererEGL *egl_renderer = context->display->renderer->winsys; return egl_renderer->edpy; } EGLContext cogl_egl_context_get_egl_context (CoglContext *context) { CoglDisplayEGL *egl_display = context->display->winsys; return egl_display->egl_context; } muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-glx-feature-functions.h0000664000175000017500000002165414211404421025226 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ /* This can be included multiple times with different definitions for * the COGL_WINSYS_FEATURE_* functions. */ /* Macro prototypes: * COGL_WINSYS_FEATURE_BEGIN (major_glx_version, minor_glx_version, * name, namespaces, extension_names, * implied_legacy_feature_flags, * implied_winsys_feature) * COGL_WINSYS_FEATURE_FUNCTION (return_type, function_name, * (arguments)) * ... * COGL_WINSYS_FEATURE_END () * * Note: You can list multiple namespace and extension names if the * corresponding _FEATURE_FUNCTIONS have the same semantics accross * the different extension variants. * * XXX: NB: Don't add a trailing semicolon when using these macros */ /* Base functions that we assume are always available */ COGL_WINSYS_FEATURE_BEGIN (0, 0, /* always available */ base_glx_functions, "\0", "\0", 0, /* no implied public feature */ 0 /* no winsys feature */) COGL_WINSYS_FEATURE_FUNCTION (void, glXDestroyContext, (Display *dpy, GLXContext ctx)) COGL_WINSYS_FEATURE_FUNCTION (void, glXSwapBuffers, (Display *dpy, GLXDrawable drawable)) COGL_WINSYS_FEATURE_FUNCTION (Bool, glXIsDirect, (Display *dpy, GLXContext ctx)) COGL_WINSYS_FEATURE_FUNCTION (int, glXGetFBConfigAttrib, (Display *dpy, GLXFBConfig config, int attribute, int *value)) COGL_WINSYS_FEATURE_FUNCTION (GLXWindow, glXCreateWindow, (Display *dpy, GLXFBConfig config, Window win, const int *attribList)) COGL_WINSYS_FEATURE_FUNCTION (void, glXDestroyWindow, (Display *dpy, GLXWindow window)) COGL_WINSYS_FEATURE_FUNCTION (GLXPixmap, glXCreatePixmap, (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attribList)) COGL_WINSYS_FEATURE_FUNCTION (void, glXDestroyPixmap, (Display *dpy, GLXPixmap pixmap)) COGL_WINSYS_FEATURE_FUNCTION (GLXContext, glXCreateNewContext, (Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct)) COGL_WINSYS_FEATURE_FUNCTION (Bool, glXMakeContextCurrent, (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx)) COGL_WINSYS_FEATURE_FUNCTION (void, glXSelectEvent, (Display *dpy, GLXDrawable drawable, unsigned long mask)) COGL_WINSYS_FEATURE_FUNCTION (GLXFBConfig *, glXGetFBConfigs, (Display *dpy, int screen, int *nelements)) COGL_WINSYS_FEATURE_FUNCTION (GLXFBConfig *, glXChooseFBConfig, (Display *dpy, int screen, const int *attrib_list, int *nelements)) COGL_WINSYS_FEATURE_FUNCTION (XVisualInfo *, glXGetVisualFromFBConfig, (Display *dpy, GLXFBConfig config)) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, texture_from_pixmap, "EXT\0", "texture_from_pixmap\0", 0, COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP) COGL_WINSYS_FEATURE_FUNCTION (void, glXBindTexImage, (Display *display, GLXDrawable drawable, int buffer, int *attribList)) COGL_WINSYS_FEATURE_FUNCTION (void, glXReleaseTexImage, (Display *display, GLXDrawable drawable, int buffer)) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, video_sync, "SGI\0", "video_sync\0", 0, COGL_WINSYS_FEATURE_VBLANK_COUNTER) COGL_WINSYS_FEATURE_FUNCTION (int, glXGetVideoSync, (unsigned int *count)) COGL_WINSYS_FEATURE_FUNCTION (int, glXWaitVideoSync, (int divisor, int remainder, unsigned int *count)) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, swap_control, "SGI\0", "swap_control\0", 0, COGL_WINSYS_FEATURE_SWAP_THROTTLE) COGL_WINSYS_FEATURE_FUNCTION (int, glXSwapInterval, (int interval)) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, sync_control, "OML\0", "sync_control\0", 0, 0) COGL_WINSYS_FEATURE_FUNCTION (Bool, glXGetSyncValues, (Display* dpy, GLXDrawable drawable, int64_t* ust, int64_t* msc, int64_t* sbc)) COGL_WINSYS_FEATURE_FUNCTION (Bool, glXWaitForMsc, (Display* dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t* ust, int64_t* msc, int64_t* sbc)) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, copy_sub_buffer, "MESA\0", "copy_sub_buffer\0", 0, /* We initially assumed that copy_sub_buffer is synchronized on * which is only the case for a subset of GPUs for example it is not * synchronized on INTEL gen6 and gen7, so we remove this assumption * for now */ #if 0 COGL_WINSYS_FEATURE_SWAP_REGION_SYNCHRONIZED) #endif 0) COGL_WINSYS_FEATURE_FUNCTION (void, glXCopySubBuffer, (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height)) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, swap_event, "INTEL\0", "swap_event\0", 0, COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, create_context, "ARB\0", "create_context", 0, 0) COGL_WINSYS_FEATURE_FUNCTION (GLXContext, glXCreateContextAttribs, (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list)) COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_BEGIN (255, 255, buffer_age, "EXT\0", "buffer_age\0", 0, COGL_WINSYS_FEATURE_BUFFER_AGE) COGL_WINSYS_FEATURE_END () muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-egl-x11-private.h0000664000175000017500000000261714211404421023621 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_WINSYS_EGL_X11_PRIVATE_H #define __COGL_WINSYS_EGL_X11_PRIVATE_H #include "cogl-winsys-private.h" const CoglWinsysVtable * _cogl_winsys_egl_xlib_get_vtable (void); #endif /* __COGL_WINSYS_EGL_X11_PRIVATE_H */ muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-glx-private.h0000664000175000017500000000253414211404421023233 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_WINSYS_GLX_PRIVATE_H #define __COGL_WINSYS_GLX_PRIVATE_H const CoglWinsysVtable * _cogl_winsys_glx_get_vtable (void); #endif /* __COGL_WINSYS_GLX_PRIVATE_H */ muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-stub-private.h0000664000175000017500000000254014211404421023413 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_WINSYS_STUB_PRIVATE_H #define __COGL_WINSYS_STUB_PRIVATE_H const CoglWinsysVtable * _cogl_winsys_stub_get_vtable (void); #endif /* __COGL_WINSYS_STUB_PRIVATE_H */ muffin-5.2.1/cogl/cogl/winsys/cogl-texture-pixmap-x11.c0000664000175000017500000011665314211404421023045 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts * Johan Bilien * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-util.h" #include "cogl-texture-pixmap-x11.h" #include "cogl-texture-pixmap-x11-private.h" #include "cogl-bitmap-private.h" #include "cogl-texture-private.h" #include "cogl-texture-driver.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d-sliced.h" #include "cogl-texture-rectangle-private.h" #include "cogl-context-private.h" #include "cogl-display-private.h" #include "cogl-renderer-private.h" #include "cogl-object-private.h" #include "cogl-winsys-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-xlib.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" #include "cogl-private.h" #include "cogl-gtype-private.h" #include #include #include #include #include #include #include static void _cogl_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap); COGL_TEXTURE_DEFINE (TexturePixmapX11, texture_pixmap_x11); COGL_GTYPE_DEFINE_CLASS (TexturePixmapX11, texture_pixmap_x11); static const CoglTextureVtable cogl_texture_pixmap_x11_vtable; uint32_t cogl_texture_pixmap_x11_error_quark (void) { return g_quark_from_static_string ("cogl-texture-pixmap-error-quark"); } static void cogl_damage_rectangle_union (CoglDamageRectangle *damage_rect, int x, int y, int width, int height) { /* If the damage region is empty then we'll just copy the new rectangle directly */ if (damage_rect->x1 == damage_rect->x2 || damage_rect->y1 == damage_rect->y2) { damage_rect->x1 = x; damage_rect->y1 = y; damage_rect->x2 = x + width; damage_rect->y2 = y + height; } else { if (damage_rect->x1 > x) damage_rect->x1 = x; if (damage_rect->y1 > y) damage_rect->y1 = y; if (damage_rect->x2 < x + width) damage_rect->x2 = x + width; if (damage_rect->y2 < y + height) damage_rect->y2 = y + height; } } static CoglBool cogl_damage_rectangle_is_whole (const CoglDamageRectangle *damage_rect, unsigned int width, unsigned int height) { return (damage_rect->x1 == 0 && damage_rect->y1 == 0 && damage_rect->x2 == width && damage_rect->y2 == height); } static const CoglWinsysVtable * _cogl_texture_pixmap_x11_get_winsys (CoglTexturePixmapX11 *tex_pixmap) { /* FIXME: A CoglContext should be reachable from a CoglTexture * pointer */ _COGL_GET_CONTEXT (ctx, NULL); return ctx->display->renderer->winsys_vtable; } static void process_damage_event (CoglTexturePixmapX11 *tex_pixmap, XDamageNotifyEvent *damage_event) { CoglTexture *tex = COGL_TEXTURE (tex_pixmap); Display *display; enum { DO_NOTHING, NEEDS_SUBTRACT, NEED_BOUNDING_BOX } handle_mode; const CoglWinsysVtable *winsys; _COGL_GET_CONTEXT (ctxt, NO_RETVAL); display = cogl_xlib_renderer_get_display (ctxt->display->renderer); COGL_NOTE (TEXTURE_PIXMAP, "Damage event received for %p", tex_pixmap); switch (tex_pixmap->damage_report_level) { case COGL_TEXTURE_PIXMAP_X11_DAMAGE_RAW_RECTANGLES: /* For raw rectangles we don't need do look at the damage region at all because the damage area is directly given in the event struct and the reporting of events is not affected by clearing the damage region */ handle_mode = DO_NOTHING; break; case COGL_TEXTURE_PIXMAP_X11_DAMAGE_DELTA_RECTANGLES: case COGL_TEXTURE_PIXMAP_X11_DAMAGE_NON_EMPTY: /* For delta rectangles and non empty we'll query the damage region for the bounding box */ handle_mode = NEED_BOUNDING_BOX; break; case COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX: /* For bounding box we need to clear the damage region but we don't actually care what it was because the damage event itself contains the bounding box of the region */ handle_mode = NEEDS_SUBTRACT; break; default: g_assert_not_reached (); } /* If the damage already covers the whole rectangle then we don't need to request the bounding box of the region because we're going to update the whole texture anyway. */ if (cogl_damage_rectangle_is_whole (&tex_pixmap->damage_rect, tex->width, tex->height)) { if (handle_mode != DO_NOTHING) XDamageSubtract (display, tex_pixmap->damage, None, None); } else if (handle_mode == NEED_BOUNDING_BOX) { XserverRegion parts; int r_count; XRectangle r_bounds; XRectangle *r_damage; /* We need to extract the damage region so we can get the bounding box */ parts = XFixesCreateRegion (display, 0, 0); XDamageSubtract (display, tex_pixmap->damage, None, parts); r_damage = XFixesFetchRegionAndBounds (display, parts, &r_count, &r_bounds); cogl_damage_rectangle_union (&tex_pixmap->damage_rect, r_bounds.x, r_bounds.y, r_bounds.width, r_bounds.height); if (r_damage) XFree (r_damage); XFixesDestroyRegion (display, parts); } else { if (handle_mode == NEEDS_SUBTRACT) /* We still need to subtract from the damage region but we don't care what the region actually was */ XDamageSubtract (display, tex_pixmap->damage, None, None); cogl_damage_rectangle_union (&tex_pixmap->damage_rect, damage_event->area.x, damage_event->area.y, damage_event->area.width, damage_event->area.height); } if (tex_pixmap->winsys) { /* If we're using the texture from pixmap extension then there's no point in getting the region and we can just mark that the texture needs updating */ winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); winsys->texture_pixmap_x11_damage_notify (tex_pixmap); } } static CoglFilterReturn _cogl_texture_pixmap_x11_filter (XEvent *event, void *data) { CoglTexturePixmapX11 *tex_pixmap = data; int damage_base; _COGL_GET_CONTEXT (ctxt, COGL_FILTER_CONTINUE); damage_base = _cogl_xlib_get_damage_base (); if (event->type == damage_base + XDamageNotify) { XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) event; if (damage_event->damage == tex_pixmap->damage) process_damage_event (tex_pixmap, damage_event); } return COGL_FILTER_CONTINUE; } static void set_damage_object_internal (CoglContext *ctx, CoglTexturePixmapX11 *tex_pixmap, Damage damage, CoglTexturePixmapX11ReportLevel report_level) { Display *display = cogl_xlib_renderer_get_display (ctx->display->renderer); if (tex_pixmap->damage) { cogl_xlib_renderer_remove_filter (ctx->display->renderer, _cogl_texture_pixmap_x11_filter, tex_pixmap); if (tex_pixmap->damage_owned) { XDamageDestroy (display, tex_pixmap->damage); tex_pixmap->damage_owned = FALSE; } } tex_pixmap->damage = damage; tex_pixmap->damage_report_level = report_level; if (damage) cogl_xlib_renderer_add_filter (ctx->display->renderer, _cogl_texture_pixmap_x11_filter, tex_pixmap); } static CoglTexturePixmapX11 * _cogl_texture_pixmap_x11_new (CoglContext *ctxt, uint32_t pixmap, CoglBool automatic_updates, CoglTexturePixmapStereoMode stereo_mode, CoglError **error) { CoglTexturePixmapX11 *tex_pixmap = g_new (CoglTexturePixmapX11, 1); Display *display = cogl_xlib_renderer_get_display (ctxt->display->renderer); Window pixmap_root_window; int pixmap_x, pixmap_y; unsigned int pixmap_width, pixmap_height; unsigned int pixmap_border_width; CoglPixelFormat internal_format; CoglTexture *tex = COGL_TEXTURE (tex_pixmap); XWindowAttributes window_attributes; int damage_base; const CoglWinsysVtable *winsys; if (!XGetGeometry (display, pixmap, &pixmap_root_window, &pixmap_x, &pixmap_y, &pixmap_width, &pixmap_height, &pixmap_border_width, &tex_pixmap->depth)) { free (tex_pixmap); _cogl_set_error (error, COGL_TEXTURE_PIXMAP_X11_ERROR, COGL_TEXTURE_PIXMAP_X11_ERROR_X11, "Unable to query pixmap size"); return NULL; } /* Note: the detailed pixel layout doesn't matter here, we are just * interested in RGB vs RGBA... */ internal_format = (tex_pixmap->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); _cogl_texture_init (tex, ctxt, pixmap_width, pixmap_height, internal_format, NULL, /* no loader */ &cogl_texture_pixmap_x11_vtable); tex_pixmap->pixmap = pixmap; tex_pixmap->stereo_mode = stereo_mode; tex_pixmap->left = NULL; tex_pixmap->image = NULL; tex_pixmap->shm_info.shmid = -1; tex_pixmap->tex = NULL; tex_pixmap->damage_owned = FALSE; tex_pixmap->damage = 0; /* We need a visual to use for shared memory images so we'll query it from the pixmap's root window */ if (!XGetWindowAttributes (display, pixmap_root_window, &window_attributes)) { free (tex_pixmap); _cogl_set_error (error, COGL_TEXTURE_PIXMAP_X11_ERROR, COGL_TEXTURE_PIXMAP_X11_ERROR_X11, "Unable to query root window attributes"); return NULL; } tex_pixmap->visual = window_attributes.visual; /* If automatic updates are requested and the Xlib connection supports damage events then we'll register a damage object on the pixmap */ damage_base = _cogl_xlib_get_damage_base (); if (automatic_updates && damage_base >= 0) { Damage damage = XDamageCreate (display, pixmap, XDamageReportBoundingBox); set_damage_object_internal (ctxt, tex_pixmap, damage, COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX); tex_pixmap->damage_owned = TRUE; } /* Assume the entire pixmap is damaged to begin with */ tex_pixmap->damage_rect.x1 = 0; tex_pixmap->damage_rect.x2 = pixmap_width; tex_pixmap->damage_rect.y1 = 0; tex_pixmap->damage_rect.y2 = pixmap_height; winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); if (winsys->texture_pixmap_x11_create) { tex_pixmap->use_winsys_texture = winsys->texture_pixmap_x11_create (tex_pixmap); } else tex_pixmap->use_winsys_texture = FALSE; if (!tex_pixmap->use_winsys_texture) tex_pixmap->winsys = NULL; _cogl_texture_set_allocated (tex, internal_format, pixmap_width, pixmap_height); return _cogl_texture_pixmap_x11_object_new (tex_pixmap); } CoglTexturePixmapX11 * cogl_texture_pixmap_x11_new (CoglContext *ctxt, uint32_t pixmap, CoglBool automatic_updates, CoglError **error) { return _cogl_texture_pixmap_x11_new (ctxt, pixmap, automatic_updates, COGL_TEXTURE_PIXMAP_MONO, error); } CoglTexturePixmapX11 * cogl_texture_pixmap_x11_new_left (CoglContext *ctxt, uint32_t pixmap, CoglBool automatic_updates, CoglError **error) { return _cogl_texture_pixmap_x11_new (ctxt, pixmap, automatic_updates, COGL_TEXTURE_PIXMAP_LEFT, error); } CoglTexturePixmapX11 * cogl_texture_pixmap_x11_new_right (CoglTexturePixmapX11 *tfp_left) { CoglTexture *texture_left = COGL_TEXTURE (tfp_left); CoglTexturePixmapX11 *tfp_right; CoglPixelFormat internal_format; g_return_val_if_fail (tfp_left->stereo_mode == COGL_TEXTURE_PIXMAP_LEFT, NULL); tfp_right = g_new0 (CoglTexturePixmapX11, 1); tfp_right->stereo_mode = COGL_TEXTURE_PIXMAP_RIGHT; tfp_right->left = cogl_object_ref (tfp_left); internal_format = (tfp_left->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); _cogl_texture_init (COGL_TEXTURE (tfp_right), texture_left->context, texture_left->width, texture_left->height, internal_format, NULL, /* no loader */ &cogl_texture_pixmap_x11_vtable); _cogl_texture_set_allocated (COGL_TEXTURE (tfp_right), internal_format, texture_left->width, texture_left->height); return _cogl_texture_pixmap_x11_object_new (tfp_right); } static CoglBool _cogl_texture_pixmap_x11_allocate (CoglTexture *tex, CoglError **error) { return TRUE; } /* Tries to allocate enough shared mem to handle a full size * update size of the X Pixmap. */ static void try_alloc_shm (CoglTexturePixmapX11 *tex_pixmap) { CoglTexture *tex = COGL_TEXTURE (tex_pixmap); XImage *dummy_image; Display *display; _COGL_GET_CONTEXT (ctx, NO_RETVAL); display = cogl_xlib_renderer_get_display (ctx->display->renderer); if (!XShmQueryExtension (display)) return; /* We are creating a dummy_image so we can have Xlib calculate * image->bytes_per_line - including any magic padding it may * want - for the largest possible ximage we might need to use * when handling updates to the texture. * * Note: we pass a NULL shminfo here, but that has no bearing * on the setup of the XImage, except that ximage->obdata will * == NULL. */ dummy_image = XShmCreateImage (display, tex_pixmap->visual, tex_pixmap->depth, ZPixmap, NULL, NULL, /* shminfo, */ tex->width, tex->height); if (!dummy_image) goto failed_image_create; tex_pixmap->shm_info.shmid = shmget (IPC_PRIVATE, dummy_image->bytes_per_line * dummy_image->height, IPC_CREAT | 0777); if (tex_pixmap->shm_info.shmid == -1) goto failed_shmget; tex_pixmap->shm_info.shmaddr = shmat (tex_pixmap->shm_info.shmid, 0, 0); if (tex_pixmap->shm_info.shmaddr == (void *) -1) goto failed_shmat; tex_pixmap->shm_info.readOnly = False; if (XShmAttach (display, &tex_pixmap->shm_info) == 0) goto failed_xshmattach; XDestroyImage (dummy_image); return; failed_xshmattach: g_warning ("XShmAttach failed"); shmdt (tex_pixmap->shm_info.shmaddr); failed_shmat: g_warning ("shmat failed"); shmctl (tex_pixmap->shm_info.shmid, IPC_RMID, 0); failed_shmget: g_warning ("shmget failed"); XDestroyImage (dummy_image); failed_image_create: tex_pixmap->shm_info.shmid = -1; } void cogl_texture_pixmap_x11_update_area (CoglTexturePixmapX11 *tex_pixmap, int x, int y, int width, int height) { /* We'll queue the update for both the GLX texture and the regular texture because we can't determine which will be needed until we actually render something */ if (tex_pixmap->stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) tex_pixmap = tex_pixmap->left; if (tex_pixmap->winsys) { const CoglWinsysVtable *winsys; winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); winsys->texture_pixmap_x11_damage_notify (tex_pixmap); } cogl_damage_rectangle_union (&tex_pixmap->damage_rect, x, y, width, height); } CoglBool cogl_texture_pixmap_x11_is_using_tfp_extension (CoglTexturePixmapX11 *tex_pixmap) { if (tex_pixmap->stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) tex_pixmap = tex_pixmap->left; return !!tex_pixmap->winsys; } void cogl_texture_pixmap_x11_set_damage_object (CoglTexturePixmapX11 *tex_pixmap, uint32_t damage, CoglTexturePixmapX11ReportLevel report_level) { int damage_base; _COGL_GET_CONTEXT (ctxt, NO_RETVAL); g_return_if_fail (tex_pixmap->stereo_mode != COGL_TEXTURE_PIXMAP_RIGHT); damage_base = _cogl_xlib_get_damage_base (); if (damage_base >= 0) set_damage_object_internal (ctxt, tex_pixmap, damage, report_level); } static CoglTexture * create_fallback_texture (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format) { CoglTexture *tex; CoglError *skip_error = NULL; if ((_cogl_util_is_pot (width) && _cogl_util_is_pot (height)) || (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP))) { /* First try creating a fast-path non-sliced texture */ tex = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height)); _cogl_texture_set_internal_format (tex, internal_format); /* TODO: instead of allocating storage here it would be better * if we had some api that let us just check that the size is * supported by the hardware so storage could be allocated * lazily when uploading data. */ if (!cogl_texture_allocate (tex, &skip_error)) { cogl_error_free (skip_error); cogl_object_unref (tex); tex = NULL; } } else tex = NULL; if (!tex) { CoglTexture2DSliced *tex_2ds = cogl_texture_2d_sliced_new_with_size (ctx, width, height, COGL_TEXTURE_MAX_WASTE); tex = COGL_TEXTURE (tex_2ds); _cogl_texture_set_internal_format (tex, internal_format); } return tex; } static void _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap) { CoglTexture *tex = COGL_TEXTURE (tex_pixmap); Display *display; Visual *visual; CoglPixelFormat image_format; XImage *image; int src_x, src_y; int x, y, width, height; int bpp; int offset; CoglError *ignore = NULL; _COGL_GET_CONTEXT (ctx, NO_RETVAL); display = cogl_xlib_renderer_get_display (ctx->display->renderer); visual = tex_pixmap->visual; /* If the damage region is empty then there's nothing to do */ if (tex_pixmap->damage_rect.x2 == tex_pixmap->damage_rect.x1) return; x = tex_pixmap->damage_rect.x1; y = tex_pixmap->damage_rect.y1; width = tex_pixmap->damage_rect.x2 - x; height = tex_pixmap->damage_rect.y2 - y; /* We lazily create the texture the first time it is needed in case this texture can be entirely handled using the GLX texture instead */ if (tex_pixmap->tex == NULL) { CoglPixelFormat texture_format; texture_format = (tex_pixmap->depth >= 32 ? COGL_PIXEL_FORMAT_RGBA_8888_PRE : COGL_PIXEL_FORMAT_RGB_888); tex_pixmap->tex = create_fallback_texture (ctx, tex->width, tex->height, texture_format); } if (tex_pixmap->image == NULL) { /* If we also haven't got a shm segment then this must be the first time we've tried to update, so lets try allocating shm first */ if (tex_pixmap->shm_info.shmid == -1) try_alloc_shm (tex_pixmap); if (tex_pixmap->shm_info.shmid == -1) { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetImage", tex_pixmap); /* We'll fallback to using a regular XImage. We'll download the entire area instead of a sub region because presumably if this is the first update then the entire pixmap is needed anyway and it saves trying to manually allocate an XImage at the right size */ tex_pixmap->image = XGetImage (display, tex_pixmap->pixmap, 0, 0, tex->width, tex->height, AllPlanes, ZPixmap); image = tex_pixmap->image; src_x = x; src_y = y; } else { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XShmGetImage", tex_pixmap); /* Create a temporary image using the beginning of the shared memory segment and the right size for the region we want to update. We need to reallocate the XImage every time because there is no XShmGetSubImage. */ image = XShmCreateImage (display, tex_pixmap->visual, tex_pixmap->depth, ZPixmap, NULL, &tex_pixmap->shm_info, width, height); image->data = tex_pixmap->shm_info.shmaddr; src_x = 0; src_y = 0; XShmGetImage (display, tex_pixmap->pixmap, image, x, y, AllPlanes); } } else { COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetSubImage", tex_pixmap); image = tex_pixmap->image; src_x = x; src_y = y; XGetSubImage (display, tex_pixmap->pixmap, x, y, width, height, AllPlanes, ZPixmap, image, x, y); } image_format = _cogl_util_pixel_format_from_masks (visual->red_mask, visual->green_mask, visual->blue_mask, image->depth, image->bits_per_pixel, image->byte_order == LSBFirst); bpp = _cogl_pixel_format_get_bytes_per_pixel (image_format); offset = image->bytes_per_line * src_y + bpp * src_x; _cogl_texture_set_region (tex_pixmap->tex, width, height, image_format, image->bytes_per_line, ((const uint8_t *) image->data) + offset, x, y, 0, /* level */ &ignore); /* If we have a shared memory segment then the XImage would be a temporary one with no data allocated so we can just XFree it */ if (tex_pixmap->shm_info.shmid != -1) XFree (image); memset (&tex_pixmap->damage_rect, 0, sizeof (CoglDamageRectangle)); } static void _cogl_texture_pixmap_x11_set_use_winsys_texture (CoglTexturePixmapX11 *tex_pixmap, CoglBool new_value) { if (tex_pixmap->use_winsys_texture != new_value) { /* Notify cogl-pipeline.c that the texture's underlying GL texture * storage is changing so it knows it may need to bind a new texture * if the CoglTexture is reused with the same texture unit. */ _cogl_pipeline_texture_storage_change_notify (COGL_TEXTURE (tex_pixmap)); tex_pixmap->use_winsys_texture = new_value; } } static void _cogl_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap, CoglBool needs_mipmap) { CoglTexturePixmapStereoMode stereo_mode = tex_pixmap->stereo_mode; if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) tex_pixmap = tex_pixmap->left; if (tex_pixmap->winsys) { const CoglWinsysVtable *winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); if (winsys->texture_pixmap_x11_update (tex_pixmap, stereo_mode, needs_mipmap)) { _cogl_texture_pixmap_x11_set_use_winsys_texture (tex_pixmap, TRUE); return; } } /* If it didn't work then fallback to using XGetImage. This may be temporary */ _cogl_texture_pixmap_x11_set_use_winsys_texture (tex_pixmap, FALSE); _cogl_texture_pixmap_x11_update_image_texture (tex_pixmap); } static CoglTexture * _cogl_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) { CoglTexturePixmapX11 *original_pixmap = tex_pixmap; CoglTexture *tex; int i; CoglTexturePixmapStereoMode stereo_mode = tex_pixmap->stereo_mode; if (stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) tex_pixmap = tex_pixmap->left; /* We try getting the texture twice, once without flushing the updates and once with. If pre_paint has been called already then we should have a good idea of which texture to use so we don't want to mess with that by ensuring the updates. However, if we couldn't find a texture then we'll just make a best guess by flushing without expecting mipmap support and try again. This would happen for example if an application calls get_gl_texture before the first paint */ for (i = 0; i < 2; i++) { if (tex_pixmap->use_winsys_texture) { const CoglWinsysVtable *winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); tex = winsys->texture_pixmap_x11_get_texture (tex_pixmap, stereo_mode); } else tex = tex_pixmap->tex; if (tex) return tex; _cogl_texture_pixmap_x11_update (original_pixmap, FALSE); } g_assert_not_reached (); return NULL; } static CoglBool _cogl_texture_pixmap_x11_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, int level, CoglBitmap *bmp, CoglError **error) { /* This doesn't make much sense for texture from pixmap so it's not supported */ _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Explicitly setting a region of a TFP texture unsupported"); return FALSE; } static CoglBool _cogl_texture_pixmap_x11_get_data (CoglTexture *tex, CoglPixelFormat format, int rowstride, uint8_t *data) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ return cogl_texture_get_data (child_tex, format, rowstride, data); } typedef struct _NormalizeCoordsWrapperData { int width; int height; CoglMetaTextureCallback callback; void *user_data; } NormalizeCoordsWrapperData; static void normalize_coords_wrapper_cb (CoglTexture *child_texture, const float *child_texture_coords, const float *meta_coords, void *user_data) { NormalizeCoordsWrapperData *data = user_data; float normalized_coords[4]; normalized_coords[0] = meta_coords[0] / data->width; normalized_coords[1] = meta_coords[1] / data->height; normalized_coords[2] = meta_coords[2] / data->width; normalized_coords[3] = meta_coords[3] / data->height; data->callback (child_texture, child_texture_coords, normalized_coords, data->user_data); } static void _cogl_texture_pixmap_x11_foreach_sub_texture_in_region (CoglTexture *tex, float virtual_tx_1, float virtual_ty_1, float virtual_tx_2, float virtual_ty_2, CoglMetaTextureCallback callback, void *user_data) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ /* tfp textures may be implemented in terms of a * CoglTextureRectangle texture which uses un-normalized texture * coordinates but we want to consistently deal with normalized * texture coordinates with CoglTexturePixmapX11... */ if (cogl_is_texture_rectangle (child_tex)) { NormalizeCoordsWrapperData data; int width = tex->width; int height = tex->height; virtual_tx_1 *= width; virtual_ty_1 *= height; virtual_tx_2 *= width; virtual_ty_2 *= height; data.width = width; data.height = height; data.callback = callback; data.user_data = user_data; cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (child_tex), virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, normalize_coords_wrapper_cb, &data); } else cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (child_tex), virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, callback, user_data); } static int _cogl_texture_pixmap_x11_get_max_waste (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); return cogl_texture_get_max_waste (child_tex); } static CoglBool _cogl_texture_pixmap_x11_is_sliced (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); return cogl_texture_is_sliced (child_tex); } static CoglBool _cogl_texture_pixmap_x11_can_hardware_repeat (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); return _cogl_texture_can_hardware_repeat (child_tex); } static void _cogl_texture_pixmap_x11_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ _cogl_texture_transform_coords_to_gl (child_tex, s, t); } static CoglTransformResult _cogl_texture_pixmap_x11_transform_quad_coords_to_gl (CoglTexture *tex, float *coords) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ return _cogl_texture_transform_quad_coords_to_gl (child_tex, coords); } static CoglBool _cogl_texture_pixmap_x11_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ return cogl_texture_get_gl_texture (child_tex, out_gl_handle, out_gl_target); } static void _cogl_texture_pixmap_x11_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ _cogl_texture_gl_flush_legacy_texobj_filters (child_tex, min_filter, mag_filter); } static void _cogl_texture_pixmap_x11_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex; _cogl_texture_pixmap_x11_update (tex_pixmap, !!(flags & COGL_TEXTURE_NEEDS_MIPMAP)); child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); _cogl_texture_pre_paint (child_tex, flags); } static void _cogl_texture_pixmap_x11_ensure_non_quad_rendering (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ _cogl_texture_ensure_non_quad_rendering (child_tex); } static void _cogl_texture_pixmap_x11_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ _cogl_texture_gl_flush_legacy_texobj_wrap_modes (child_tex, wrap_mode_s, wrap_mode_t, wrap_mode_p); } static CoglPixelFormat _cogl_texture_pixmap_x11_get_format (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ return _cogl_texture_get_format (child_tex); } static GLenum _cogl_texture_pixmap_x11_get_gl_format (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); return _cogl_texture_gl_get_format (child_tex); } static CoglTextureType _cogl_texture_pixmap_x11_get_type (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglTexture *child_tex; child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ return _cogl_texture_get_type (child_tex); } static void _cogl_texture_pixmap_x11_free (CoglTexturePixmapX11 *tex_pixmap) { Display *display; _COGL_GET_CONTEXT (ctxt, NO_RETVAL); if (tex_pixmap->stereo_mode == COGL_TEXTURE_PIXMAP_RIGHT) { cogl_object_unref (tex_pixmap->left); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (tex_pixmap)); return; } display = cogl_xlib_renderer_get_display (ctxt->display->renderer); set_damage_object_internal (ctxt, tex_pixmap, 0, 0); if (tex_pixmap->image) XDestroyImage (tex_pixmap->image); if (tex_pixmap->shm_info.shmid != -1) { XShmDetach (display, &tex_pixmap->shm_info); shmdt (tex_pixmap->shm_info.shmaddr); shmctl (tex_pixmap->shm_info.shmid, IPC_RMID, 0); } if (tex_pixmap->tex) cogl_object_unref (tex_pixmap->tex); if (tex_pixmap->winsys) { const CoglWinsysVtable *winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap); winsys->texture_pixmap_x11_free (tex_pixmap); } /* Chain up */ _cogl_texture_free (COGL_TEXTURE (tex_pixmap)); } static const CoglTextureVtable cogl_texture_pixmap_x11_vtable = { FALSE, /* not primitive */ _cogl_texture_pixmap_x11_allocate, _cogl_texture_pixmap_x11_set_region, _cogl_texture_pixmap_x11_get_data, _cogl_texture_pixmap_x11_foreach_sub_texture_in_region, _cogl_texture_pixmap_x11_get_max_waste, _cogl_texture_pixmap_x11_is_sliced, _cogl_texture_pixmap_x11_can_hardware_repeat, _cogl_texture_pixmap_x11_transform_coords_to_gl, _cogl_texture_pixmap_x11_transform_quad_coords_to_gl, _cogl_texture_pixmap_x11_get_gl_texture, _cogl_texture_pixmap_x11_gl_flush_legacy_texobj_filters, _cogl_texture_pixmap_x11_pre_paint, _cogl_texture_pixmap_x11_ensure_non_quad_rendering, _cogl_texture_pixmap_x11_gl_flush_legacy_texobj_wrap_modes, _cogl_texture_pixmap_x11_get_format, _cogl_texture_pixmap_x11_get_gl_format, _cogl_texture_pixmap_x11_get_type, NULL, /* is_foreign */ NULL /* set_auto_mipmap */ }; muffin-5.2.1/cogl/cogl/winsys/cogl-texture-pixmap-x11-private.h0000664000175000017500000000554114211404421024513 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_TEXTURE_PIXMAP_X11_PRIVATE_H #define __COGL_TEXTURE_PIXMAP_X11_PRIVATE_H #include #include #include #include #ifdef COGL_HAS_GLX_SUPPORT #include #endif #include "cogl-object-private.h" #include "cogl-texture-private.h" #include "cogl-texture-pixmap-x11.h" typedef struct _CoglDamageRectangle CoglDamageRectangle; struct _CoglDamageRectangle { unsigned int x1; unsigned int y1; unsigned int x2; unsigned int y2; }; /* For stereo, there are a pair of textures, but we want to share most * other state (the GLXPixmap, visual, etc.) The way we do this is that * the left-eye texture has all the state (there is in fact, no internal * difference between the a MONO and a LEFT texture ), and the * right-eye texture simply points to the left eye texture, with all * other fields ignored. */ typedef enum { COGL_TEXTURE_PIXMAP_MONO, COGL_TEXTURE_PIXMAP_LEFT, COGL_TEXTURE_PIXMAP_RIGHT } CoglTexturePixmapStereoMode; struct _CoglTexturePixmapX11 { CoglTexture _parent; CoglTexturePixmapStereoMode stereo_mode; CoglTexturePixmapX11 *left; /* Set only if stereo_mode=RIGHT */ Pixmap pixmap; CoglTexture *tex; unsigned int depth; Visual *visual; XImage *image; XShmSegmentInfo shm_info; Damage damage; CoglTexturePixmapX11ReportLevel damage_report_level; CoglBool damage_owned; CoglDamageRectangle damage_rect; void *winsys; /* During the pre_paint method, this will be set to TRUE if we should use the winsys texture, otherwise we will use the regular texture */ CoglBool use_winsys_texture; }; #endif /* __COGL_TEXTURE_PIXMAP_X11_PRIVATE_H */ muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-egl-private.h0000664000175000017500000001421714211404421023211 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_WINSYS_EGL_PRIVATE_H #define __COGL_WINSYS_EGL_PRIVATE_H #include "cogl-defines.h" #include "cogl-winsys-private.h" #include "cogl-context.h" #include "cogl-context-private.h" #include "cogl-framebuffer-private.h" /* XXX: depending on what version of Mesa you have then * eglQueryWaylandBuffer may take a wl_buffer or wl_resource argument * and the EGL header will only forward declare the corresponding * type. * * The use of wl_buffer has been deprecated and so internally we * assume that eglQueryWaylandBuffer takes a wl_resource but for * compatibility we forward declare wl_resource in case we are * building with EGL headers that still use wl_buffer. * * Placing the forward declaration here means it comes before we * #include cogl-winsys-egl-feature-functions.h bellow which * declares lots of function pointers for accessing EGL extensions * and cogl-winsys-egl.c will include this header before it also * includes cogl-winsys-egl-feature-functions.h that may depend * on this type. */ #ifdef EGL_WL_bind_wayland_display struct wl_resource; #endif typedef struct _CoglWinsysEGLVtable { CoglBool (* display_setup) (CoglDisplay *display, CoglError **error); void (* display_destroy) (CoglDisplay *display); CoglBool (* context_created) (CoglDisplay *display, CoglError **error); void (* cleanup_context) (CoglDisplay *display); CoglBool (* context_init) (CoglContext *context, CoglError **error); void (* context_deinit) (CoglContext *context); CoglBool (* onscreen_init) (CoglOnscreen *onscreen, EGLConfig config, CoglError **error); void (* onscreen_deinit) (CoglOnscreen *onscreen); int (* add_config_attributes) (CoglDisplay *display, CoglFramebufferConfig *config, EGLint *attributes); CoglBool (* choose_config) (CoglDisplay *display, EGLint *attributes, EGLConfig *out_config, CoglError **error); } CoglWinsysEGLVtable; typedef enum _CoglEGLWinsysFeature { COGL_EGL_WINSYS_FEATURE_SWAP_REGION =1L<<0, COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_X11_PIXMAP =1L<<1, COGL_EGL_WINSYS_FEATURE_EGL_IMAGE_FROM_WAYLAND_BUFFER =1L<<2, COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT =1L<<3, COGL_EGL_WINSYS_FEATURE_BUFFER_AGE =1L<<4, COGL_EGL_WINSYS_FEATURE_FENCE_SYNC =1L<<5, COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT =1L<<6 } CoglEGLWinsysFeature; typedef struct _CoglRendererEGL { CoglEGLWinsysFeature private_features; EGLDisplay edpy; EGLint egl_version_major; EGLint egl_version_minor; CoglClosure *resize_notify_idle; /* Data specific to the EGL platform */ void *platform; /* vtable for platform specific parts */ const CoglWinsysEGLVtable *platform_vtable; /* Function pointers for EGL specific extensions */ #define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d) #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \ ret (APIENTRY * pf_ ## name) args; #define COGL_WINSYS_FEATURE_END() #include "cogl-winsys-egl-feature-functions.h" #undef COGL_WINSYS_FEATURE_BEGIN #undef COGL_WINSYS_FEATURE_FUNCTION #undef COGL_WINSYS_FEATURE_END } CoglRendererEGL; typedef struct _CoglDisplayEGL { EGLContext egl_context; EGLSurface dummy_surface; EGLSurface egl_surface; EGLConfig egl_config; CoglBool found_egl_config; EGLSurface current_read_surface; EGLSurface current_draw_surface; EGLContext current_context; /* Platform specific display data */ void *platform; } CoglDisplayEGL; typedef struct _CoglContextEGL { EGLSurface saved_draw_surface; EGLSurface saved_read_surface; } CoglContextEGL; typedef struct _CoglOnscreenEGL { EGLSurface egl_surface; CoglBool pending_resize_notify; /* Platform specific data */ void *platform; } CoglOnscreenEGL; const CoglWinsysVtable * _cogl_winsys_egl_get_vtable (void); EGLBoolean _cogl_winsys_egl_make_current (CoglDisplay *display, EGLSurface draw, EGLSurface read, EGLContext context); EGLBoolean _cogl_winsys_egl_ensure_current (CoglDisplay *display); #ifdef EGL_KHR_image_base EGLImageKHR _cogl_egl_create_image (CoglContext *ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attribs); void _cogl_egl_destroy_image (CoglContext *ctx, EGLImageKHR image); #endif #ifdef EGL_WL_bind_wayland_display CoglBool _cogl_egl_query_wayland_buffer (CoglContext *ctx, struct wl_resource *buffer, int attribute, int *value); #endif CoglBool _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer, CoglError **error); #endif /* __COGL_WINSYS_EGL_PRIVATE_H */ muffin-5.2.1/cogl/cogl/winsys/cogl-winsys.c0000664000175000017500000000317014211404421020763 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include uint32_t _cogl_winsys_error_quark (void) { return g_quark_from_static_string ("cogl-winsys-error-quark"); } /* FIXME: we should distinguish renderer and context features */ CoglBool _cogl_winsys_has_feature (CoglWinsysFeature feature) { _COGL_GET_CONTEXT (ctx, FALSE); return COGL_FLAGS_GET (ctx->winsys_features, feature); } muffin-5.2.1/cogl/cogl/winsys/cogl-winsys-stub.c0000664000175000017500000001254114211404421021740 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-renderer-private.h" #include "cogl-display-private.h" #include "cogl-context-private.h" #include "cogl-framebuffer-private.h" #include "cogl-private.h" #include "cogl-winsys-stub-private.h" #include static int _cogl_winsys_stub_dummy_ptr; /* This provides a NOP winsys. This can be useful for debugging or for * integrating with toolkits that already have window system * integration code. */ static CoglFuncPtr _cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer, const char *name, CoglBool in_core) { static GModule *module = NULL; /* this should find the right function if the program is linked against a * library providing it */ if (G_UNLIKELY (module == NULL)) module = g_module_open (NULL, 0); if (module) { void *symbol; if (g_module_symbol (module, name, &symbol)) return symbol; } return NULL; } static void _cogl_winsys_renderer_disconnect (CoglRenderer *renderer) { renderer->winsys = NULL; } static CoglBool _cogl_winsys_renderer_connect (CoglRenderer *renderer, CoglError **error) { renderer->winsys = &_cogl_winsys_stub_dummy_ptr; return TRUE; } static void _cogl_winsys_display_destroy (CoglDisplay *display) { display->winsys = NULL; } static CoglBool _cogl_winsys_display_setup (CoglDisplay *display, CoglError **error) { display->winsys = &_cogl_winsys_stub_dummy_ptr; return TRUE; } static CoglBool _cogl_winsys_context_init (CoglContext *context, CoglError **error) { context->winsys = &_cogl_winsys_stub_dummy_ptr; if (!_cogl_context_update_features (context, error)) return FALSE; memset (context->winsys_features, 0, sizeof (context->winsys_features)); return TRUE; } static void _cogl_winsys_context_deinit (CoglContext *context) { context->winsys = NULL; } static CoglBool _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, CoglError **error) { return TRUE; } static void _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) { } static void _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) { } static void _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, const int *rectangles, int n_rectangles) { } static void _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen) { } static void _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen, CoglBool visibility) { } const CoglWinsysVtable * _cogl_winsys_stub_get_vtable (void) { static CoglBool vtable_inited = FALSE; static CoglWinsysVtable vtable; /* It would be nice if we could use C99 struct initializers here like the GLX backend does. However this code is more likely to be compiled using Visual Studio which (still!) doesn't support them so we initialize it in code instead */ if (!vtable_inited) { memset (&vtable, 0, sizeof (vtable)); vtable.id = COGL_WINSYS_ID_STUB; vtable.name = "STUB"; vtable.renderer_get_proc_address = _cogl_winsys_renderer_get_proc_address; vtable.renderer_connect = _cogl_winsys_renderer_connect; vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect; vtable.display_setup = _cogl_winsys_display_setup; vtable.display_destroy = _cogl_winsys_display_destroy; vtable.context_init = _cogl_winsys_context_init; vtable.context_deinit = _cogl_winsys_context_deinit; vtable.onscreen_init = _cogl_winsys_onscreen_init; vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit; vtable.onscreen_bind = _cogl_winsys_onscreen_bind; vtable.onscreen_swap_buffers_with_damage = _cogl_winsys_onscreen_swap_buffers_with_damage; vtable.onscreen_update_swap_throttled = _cogl_winsys_onscreen_update_swap_throttled; vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; vtable_inited = TRUE; } return &vtable; } muffin-5.2.1/cogl/cogl/cogl-pipeline-hash-table.c0000664000175000017500000001641714211404421021716 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-hash-table.h" #include "cogl-pipeline-cache.h" typedef struct { CoglPipelineCacheEntry parent; /* Calculating the hash is a little bit expensive for pipelines so * we don't want to do it repeatedly for entries that are already in * the hash table. Instead we cache the value here and calculate it * outside of the GHashTable. */ unsigned int hash_value; /* GHashTable annoyingly doesn't let us pass a user data pointer to * the hash and equal functions so to work around it we have to * store the pointer in every hash table entry. We will use this * entry as both the key and the value */ CoglPipelineHashTable *hash; /* The number of unique pipelines that had been created when this * pipeline was last accessed */ int age; } CoglPipelineHashTableEntry; static void value_destroy_cb (void *value) { CoglPipelineHashTableEntry *entry = value; cogl_object_unref (entry->parent.pipeline); g_slice_free (CoglPipelineHashTableEntry, entry); } static unsigned int entry_hash (const void *data) { const CoglPipelineHashTableEntry *entry = data; return entry->hash_value; } static CoglBool entry_equal (const void *a, const void *b) { const CoglPipelineHashTableEntry *entry_a = a; const CoglPipelineHashTableEntry *entry_b = b; const CoglPipelineHashTable *hash = entry_a->hash; return _cogl_pipeline_equal (entry_a->parent.pipeline, entry_b->parent.pipeline, hash->main_state, hash->layer_state, 0); } void _cogl_pipeline_hash_table_init (CoglPipelineHashTable *hash, unsigned int main_state, unsigned int layer_state, const char *debug_string) { hash->n_unique_pipelines = 0; hash->debug_string = debug_string; hash->main_state = main_state; hash->layer_state = layer_state; /* We'll only start pruning once we get to 16 unique pipelines */ hash->expected_min_size = 8; hash->table = g_hash_table_new_full (entry_hash, entry_equal, NULL, /* key destroy */ value_destroy_cb); } void _cogl_pipeline_hash_table_destroy (CoglPipelineHashTable *hash) { g_hash_table_destroy (hash->table); } static void collect_prunable_entries_cb (void *key, void *value, void *user_data) { GQueue *entries = user_data; CoglPipelineCacheEntry *entry = value; if (entry->usage_count == 0) g_queue_push_tail (entries, entry); } static int compare_pipeline_age_cb (const void *a, const void *b) { const CoglPipelineHashTableEntry *ae = a; const CoglPipelineHashTableEntry *be = b; return be->age - ae->age; } static void prune_old_pipelines (CoglPipelineHashTable *hash) { GQueue entries; GList *l; int i; /* Collect all of the prunable entries into a GQueue */ g_queue_init (&entries); g_hash_table_foreach (hash->table, collect_prunable_entries_cb, &entries); /* Sort the entries by increasing order of age */ entries.head = g_list_sort (entries.head, compare_pipeline_age_cb); /* The +1 is to include the pipeline that we're about to add */ hash->expected_min_size = (g_hash_table_size (hash->table) - entries.length + 1); /* Remove oldest half of the prunable pipelines. We still want to * keep some of the prunable entries that are recently used because * it's not unlikely that the application will recreate the same * pipeline */ for (l = entries.head, i = 0; i < entries.length / 2; l = l->next, i++) { CoglPipelineCacheEntry *entry = l->data; g_hash_table_remove (hash->table, entry); } g_list_free (entries.head); } CoglPipelineCacheEntry * _cogl_pipeline_hash_table_get (CoglPipelineHashTable *hash, CoglPipeline *key_pipeline) { CoglPipelineHashTableEntry dummy_entry; CoglPipelineHashTableEntry *entry; unsigned int copy_state; dummy_entry.parent.pipeline = key_pipeline; dummy_entry.hash = hash; dummy_entry.hash_value = _cogl_pipeline_hash (key_pipeline, hash->main_state, hash->layer_state, 0); entry = g_hash_table_lookup (hash->table, &dummy_entry); if (entry) { entry->age = hash->n_unique_pipelines; return &entry->parent; } if (hash->n_unique_pipelines == 50) g_warning ("Over 50 separate %s have been generated which is very " "unusual, so something is probably wrong!\n", hash->debug_string); /* If we are going to have more than twice the expected minimum * number of pipelines in the hash then we'll try pruning and update * the minimum */ if (g_hash_table_size (hash->table) >= hash->expected_min_size * 2) prune_old_pipelines (hash); entry = g_slice_new (CoglPipelineHashTableEntry); entry->parent.usage_count = 0; entry->hash = hash; entry->hash_value = dummy_entry.hash_value; entry->age = hash->n_unique_pipelines; copy_state = hash->main_state; if (hash->layer_state) copy_state |= COGL_PIPELINE_STATE_LAYERS; /* Create a new pipeline that is a child of the root pipeline * instead of a normal copy so that the template pipeline won't hold * a reference to the original pipeline */ entry->parent.pipeline = _cogl_pipeline_deep_copy (key_pipeline, copy_state, hash->layer_state); g_hash_table_insert (hash->table, entry, entry); hash->n_unique_pipelines++; return &entry->parent; } muffin-5.2.1/cogl/cogl/cogl-framebuffer.c0000664000175000017500000025102614211404421020364 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-debug.h" #include "cogl-context-private.h" #include "cogl-display-private.h" #include "cogl-renderer-private.h" #include "cogl-object-private.h" #include "cogl-util.h" #include "cogl-texture-private.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-template-private.h" #include "cogl-clip-stack.h" #include "cogl-journal-private.h" #include "cogl-winsys-private.h" #include "cogl-pipeline-state-private.h" #include "cogl-matrix-private.h" #include "cogl-primitive-private.h" #include "cogl-offscreen.h" #include "cogl1-context.h" #include "cogl-private.h" #include "cogl-primitives-private.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" #include "cogl-gtype-private.h" extern CoglObjectClass _cogl_onscreen_class; #ifdef COGL_ENABLE_DEBUG static CoglUserDataKey wire_pipeline_key; #endif static void _cogl_offscreen_free (CoglOffscreen *offscreen); COGL_OBJECT_DEFINE_WITH_CODE_GTYPE (Offscreen, offscreen, _cogl_offscreen_class.virt_unref = _cogl_framebuffer_unref); COGL_GTYPE_DEFINE_CLASS (Offscreen, offscreen); COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (offscreen); COGL_GTYPE_DEFINE_INTERFACE (Framebuffer, framebuffer); /* XXX: * The CoglObject macros don't support any form of inheritance, so for * now we implement the CoglObject support for the CoglFramebuffer * abstract class manually. */ uint32_t cogl_framebuffer_error_quark (void) { return g_quark_from_static_string ("cogl-framebuffer-error-quark"); } CoglBool cogl_is_framebuffer (void *object) { CoglObject *obj = object; if (obj == NULL) return FALSE; return (obj->klass == &_cogl_onscreen_class || obj->klass == &_cogl_offscreen_class); } void _cogl_framebuffer_init (CoglFramebuffer *framebuffer, CoglContext *ctx, CoglFramebufferType type, int width, int height) { framebuffer->context = ctx; framebuffer->type = type; framebuffer->width = width; framebuffer->height = height; framebuffer->internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; framebuffer->viewport_x = 0; framebuffer->viewport_y = 0; framebuffer->viewport_width = width; framebuffer->viewport_height = height; framebuffer->viewport_age = 0; framebuffer->viewport_age_for_scissor_workaround = -1; framebuffer->dither_enabled = TRUE; framebuffer->depth_writing_enabled = TRUE; framebuffer->modelview_stack = cogl_matrix_stack_new (ctx); framebuffer->projection_stack = cogl_matrix_stack_new (ctx); framebuffer->dirty_bitmasks = TRUE; framebuffer->color_mask = COGL_COLOR_MASK_ALL; framebuffer->samples_per_pixel = 0; framebuffer->clip_stack = NULL; framebuffer->journal = _cogl_journal_new (framebuffer); /* Ensure we know the framebuffer->clear_color* members can't be * referenced for our fast-path read-pixel optimization (see * _cogl_journal_try_read_pixel()) until some region of the * framebuffer is initialized. */ framebuffer->clear_clip_dirty = TRUE; /* XXX: We have to maintain a central list of all framebuffers * because at times we need to be able to flush all known journals. * * Examples where we need to flush all journals are: * - because journal entries can reference OpenGL texture * coordinates that may not survive texture-atlas reorganization * so we need the ability to flush those entries. * - because although we generally advise against modifying * pipelines after construction we have to handle that possibility * and since pipelines may be referenced in journal entries we * need to be able to flush them before allowing the pipelines to * be changed. * * Note we don't maintain a list of journals and associate * framebuffers with journals by e.g. having a journal->framebuffer * reference since that would introduce a circular reference. * * Note: As a future change to try and remove the need to index all * journals it might be possible to defer resolving of OpenGL * texture coordinates for rectangle primitives until we come to * flush a journal. This would mean for instance that a single * rectangle entry in a journal could later be expanded into * multiple quad primitives to handle sliced textures but would mean * we don't have to worry about retaining references to OpenGL * texture coordinates that may later become invalid. */ ctx->framebuffers = g_list_prepend (ctx->framebuffers, framebuffer); } void _cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer, CoglPixelFormat internal_format) { framebuffer->internal_format = internal_format; } void _cogl_framebuffer_free (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; _cogl_fence_cancel_fences_for_framebuffer (framebuffer); _cogl_clip_stack_unref (framebuffer->clip_stack); cogl_object_unref (framebuffer->modelview_stack); framebuffer->modelview_stack = NULL; cogl_object_unref (framebuffer->projection_stack); framebuffer->projection_stack = NULL; cogl_object_unref (framebuffer->journal); if (ctx->viewport_scissor_workaround_framebuffer == framebuffer) ctx->viewport_scissor_workaround_framebuffer = NULL; ctx->framebuffers = g_list_remove (ctx->framebuffers, framebuffer); if (ctx->current_draw_buffer == framebuffer) ctx->current_draw_buffer = NULL; if (ctx->current_read_buffer == framebuffer) ctx->current_read_buffer = NULL; } const CoglWinsysVtable * _cogl_framebuffer_get_winsys (CoglFramebuffer *framebuffer) { return framebuffer->context->display->renderer->winsys_vtable; } /* This version of cogl_clear can be used internally as an alternative * to avoid flushing the journal or the framebuffer state. This is * needed when doing operations that may be called whiling flushing * the journal */ void _cogl_framebuffer_clear_without_flush4f (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha) { CoglContext *ctx = framebuffer->context; if (!buffers) { static CoglBool shown = FALSE; if (!shown) { g_warning ("You should specify at least one auxiliary buffer " "when calling cogl_framebuffer_clear"); } return; } ctx->driver_vtable->framebuffer_clear (framebuffer, buffers, red, green, blue, alpha); } void _cogl_framebuffer_mark_clear_clip_dirty (CoglFramebuffer *framebuffer) { framebuffer->clear_clip_dirty = TRUE; } void _cogl_framebuffer_mark_mid_scene (CoglFramebuffer *framebuffer) { framebuffer->mid_scene = TRUE; } void cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha) { CoglContext *ctx = framebuffer->context; CoglClipStack *clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer); int scissor_x0; int scissor_y0; int scissor_x1; int scissor_y1; CoglBool saved_viewport_scissor_workaround; _cogl_clip_stack_get_bounds (clip_stack, &scissor_x0, &scissor_y0, &scissor_x1, &scissor_y1); /* NB: the previous clear could have had an arbitrary clip. * NB: everything for the last frame might still be in the journal * but we can't assume anything about how each entry was * clipped. * NB: Clutter will scissor its pick renders which would mean all * journal entries have a common ClipStack entry, but without * a layering violation Cogl has to explicitly walk the journal * entries to determine if this is the case. * NB: We have a software only read-pixel optimization in the * journal that determines the color at a given framebuffer * coordinate for simple scenes without rendering with the GPU. * When Clutter is hitting this fast-path we can expect to * receive calls to clear the framebuffer with an un-flushed * journal. * NB: To fully support software based picking for Clutter we * need to be able to reliably detect when the contents of a * journal can be discarded and when we can skip the call to * glClear because it matches the previous clear request. */ /* Note: we don't check for the stencil buffer being cleared here * since there isn't any public cogl api to manipulate the stencil * buffer. * * Note: we check for an exact clip match here because * 1) a smaller clip could mean existing journal entries may * need to contribute to regions outside the new clear-clip * 2) a larger clip would mean we need to issue a real * glClear and we only care about cases avoiding a * glClear. * * Note: Comparing without an epsilon is considered * appropriate here. */ if (buffers & COGL_BUFFER_BIT_COLOR && buffers & COGL_BUFFER_BIT_DEPTH && !framebuffer->clear_clip_dirty && framebuffer->clear_color_red == red && framebuffer->clear_color_green == green && framebuffer->clear_color_blue == blue && framebuffer->clear_color_alpha == alpha && scissor_x0 == framebuffer->clear_clip_x0 && scissor_y0 == framebuffer->clear_clip_y0 && scissor_x1 == framebuffer->clear_clip_x1 && scissor_y1 == framebuffer->clear_clip_y1) { /* NB: We only have to consider the clip state of journal * entries if the current clear is clipped since otherwise we * know every pixel of the framebuffer is affected by the clear * and so all journal entries become redundant and can simply be * discarded. */ if (clip_stack) { /* * Note: the function for checking the journal entries is * quite strict. It avoids detailed checking of all entry * clip_stacks by only checking the details of the first * entry and then it only verifies that the remaining * entries share the same clip_stack ancestry. This means * it's possible for some false negatives here but that will * just result in us falling back to a real clear. */ if (_cogl_journal_all_entries_within_bounds (framebuffer->journal, scissor_x0, scissor_y0, scissor_x1, scissor_y1)) { _cogl_journal_discard (framebuffer->journal); goto cleared; } } else { _cogl_journal_discard (framebuffer->journal); goto cleared; } } COGL_NOTE (DRAW, "Clear begin"); _cogl_framebuffer_flush_journal (framebuffer); /* XXX: ONGOING BUG: Intel viewport scissor * * The semantics of cogl_framebuffer_clear() are that it should not * be affected by the current viewport and so if we are currently * applying a workaround for viewport scissoring we need to * temporarily disable the workaround before clearing so any * special scissoring for the workaround will be removed first. * * Note: we only need to disable the workaround if the current * viewport doesn't match the framebuffer's size since otherwise * the workaround wont affect clearing anyway. */ if (ctx->needs_viewport_scissor_workaround && (framebuffer->viewport_x != 0 || framebuffer->viewport_y != 0 || framebuffer->viewport_width != framebuffer->width || framebuffer->viewport_height != framebuffer->height)) { saved_viewport_scissor_workaround = TRUE; ctx->needs_viewport_scissor_workaround = FALSE; ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } else saved_viewport_scissor_workaround = FALSE; /* NB: _cogl_framebuffer_flush_state may disrupt various state (such * as the pipeline state) when flushing the clip stack, so should * always be done first when preparing to draw. */ _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_ALL); _cogl_framebuffer_clear_without_flush4f (framebuffer, buffers, red, green, blue, alpha); /* XXX: ONGOING BUG: Intel viewport scissor * * See comment about temporarily disabling this workaround above */ if (saved_viewport_scissor_workaround) { ctx->needs_viewport_scissor_workaround = TRUE; ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } /* This is a debugging variable used to visually display the quad * batches from the journal. It is reset here to increase the * chances of getting the same colours for each frame during an * animation */ if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_RECTANGLES)) && buffers & COGL_BUFFER_BIT_COLOR) { framebuffer->context->journal_rectangles_color = 1; } COGL_NOTE (DRAW, "Clear end"); cleared: _cogl_framebuffer_mark_mid_scene (framebuffer); _cogl_framebuffer_mark_clear_clip_dirty (framebuffer); if (buffers & COGL_BUFFER_BIT_COLOR && buffers & COGL_BUFFER_BIT_DEPTH) { /* For our fast-path for reading back a single pixel of simple * scenes where the whole frame is in the journal we need to * track the cleared color of the framebuffer in case the point * read doesn't intersect any of the journal rectangles. */ framebuffer->clear_clip_dirty = FALSE; framebuffer->clear_color_red = red; framebuffer->clear_color_green = green; framebuffer->clear_color_blue = blue; framebuffer->clear_color_alpha = alpha; /* NB: A clear may be scissored so we need to track the extents * that the clear is applicable too... */ if (clip_stack) { _cogl_clip_stack_get_bounds (clip_stack, &framebuffer->clear_clip_x0, &framebuffer->clear_clip_y0, &framebuffer->clear_clip_x1, &framebuffer->clear_clip_y1); } else { /* FIXME: set degenerate clip */ } } } /* Note: the 'buffers' and 'color' arguments were switched around on * purpose compared to the original cogl_clear API since it was odd * that you would be expected to specify a color before even * necessarily choosing to clear the color buffer. */ void cogl_framebuffer_clear (CoglFramebuffer *framebuffer, unsigned long buffers, const CoglColor *color) { cogl_framebuffer_clear4f (framebuffer, buffers, cogl_color_get_red_float (color), cogl_color_get_green_float (color), cogl_color_get_blue_float (color), cogl_color_get_alpha_float (color)); } /* We will lazily allocate framebuffers if necessary when querying * their size/viewport but note we need to be careful in the case of * onscreen framebuffers that are instantiated with an initial request * size that we don't trigger an allocation when this is queried since * that would lead to a recursion when the winsys backend queries this * requested size during allocation. */ static void ensure_size_initialized (CoglFramebuffer *framebuffer) { /* In the case of offscreen framebuffers backed by a texture then * until that texture has been allocated we might not know the size * of the framebuffer */ if (framebuffer->width < 0) { /* Currently we assume the size is always initialized for * onscreen framebuffers. */ _COGL_RETURN_IF_FAIL (cogl_is_offscreen (framebuffer)); /* We also assume the size would have been initialized if the * framebuffer were allocated. */ _COGL_RETURN_IF_FAIL (!framebuffer->allocated); cogl_framebuffer_allocate (framebuffer, NULL); } } int cogl_framebuffer_get_width (CoglFramebuffer *framebuffer) { ensure_size_initialized (framebuffer); return framebuffer->width; } int cogl_framebuffer_get_height (CoglFramebuffer *framebuffer) { ensure_size_initialized (framebuffer); return framebuffer->height; } CoglClipStack * _cogl_framebuffer_get_clip_stack (CoglFramebuffer *framebuffer) { return framebuffer->clip_stack; } void _cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer, CoglClipStack *stack) { _cogl_clip_stack_ref (stack); _cogl_clip_stack_unref (framebuffer->clip_stack); framebuffer->clip_stack = stack; } void cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer, float x, float y, float width, float height) { CoglContext *context = framebuffer->context; _COGL_RETURN_IF_FAIL (width > 0 && height > 0); if (framebuffer->viewport_x == x && framebuffer->viewport_y == y && framebuffer->viewport_width == width && framebuffer->viewport_height == height) return; _cogl_framebuffer_flush_journal (framebuffer); framebuffer->viewport_x = x; framebuffer->viewport_y = y; framebuffer->viewport_width = width; framebuffer->viewport_height = height; framebuffer->viewport_age++; if (context->current_draw_buffer == framebuffer) { context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_VIEWPORT; if (context->needs_viewport_scissor_workaround) context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } } float cogl_framebuffer_get_viewport_x (CoglFramebuffer *framebuffer) { return framebuffer->viewport_x; } float cogl_framebuffer_get_viewport_y (CoglFramebuffer *framebuffer) { return framebuffer->viewport_y; } float cogl_framebuffer_get_viewport_width (CoglFramebuffer *framebuffer) { ensure_size_initialized (framebuffer); return framebuffer->viewport_width; } float cogl_framebuffer_get_viewport_height (CoglFramebuffer *framebuffer) { ensure_size_initialized (framebuffer); return framebuffer->viewport_height; } void cogl_framebuffer_get_viewport4fv (CoglFramebuffer *framebuffer, float *viewport) { ensure_size_initialized (framebuffer); viewport[0] = framebuffer->viewport_x; viewport[1] = framebuffer->viewport_y; viewport[2] = framebuffer->viewport_width; viewport[3] = framebuffer->viewport_height; } CoglMatrixStack * _cogl_framebuffer_get_modelview_stack (CoglFramebuffer *framebuffer) { return framebuffer->modelview_stack; } CoglMatrixStack * _cogl_framebuffer_get_projection_stack (CoglFramebuffer *framebuffer) { return framebuffer->projection_stack; } void _cogl_framebuffer_add_dependency (CoglFramebuffer *framebuffer, CoglFramebuffer *dependency) { GList *l; for (l = framebuffer->deps; l; l = l->next) { CoglFramebuffer *existing_dep = l->data; if (existing_dep == dependency) return; } /* TODO: generalize the primed-array type structure we e.g. use for * cogl_object_set_user_data or for pipeline children as a way to * avoid quite a lot of mid-scene micro allocations here... */ framebuffer->deps = g_list_prepend (framebuffer->deps, cogl_object_ref (dependency)); } void _cogl_framebuffer_remove_all_dependencies (CoglFramebuffer *framebuffer) { GList *l; for (l = framebuffer->deps; l; l = l->next) cogl_object_unref (l->data); g_list_free (framebuffer->deps); framebuffer->deps = NULL; } void _cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer) { _cogl_journal_flush (framebuffer->journal); } void _cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer) { GList *l; for (l = framebuffer->deps; l; l = l->next) _cogl_framebuffer_flush_journal (l->data); _cogl_framebuffer_remove_all_dependencies (framebuffer); } CoglOffscreen * _cogl_offscreen_new_with_texture_full (CoglTexture *texture, CoglOffscreenFlags create_flags, int level) { CoglContext *ctx = texture->context; CoglOffscreen *offscreen; CoglFramebuffer *fb; CoglOffscreen *ret; _COGL_RETURN_VAL_IF_FAIL (cogl_is_texture (texture), NULL); offscreen = g_new0 (CoglOffscreen, 1); offscreen->texture = cogl_object_ref (texture); offscreen->texture_level = level; offscreen->create_flags = create_flags; fb = COGL_FRAMEBUFFER (offscreen); /* NB: we can't assume we can query the texture's width yet, since * it might not have been allocated yet and for example if the * texture is being loaded from a file then the file might not * have been read yet. */ _cogl_framebuffer_init (fb, ctx, COGL_FRAMEBUFFER_TYPE_OFFSCREEN, -1, /* unknown width, until allocation */ -1); /* unknown height until allocation */ ret = _cogl_offscreen_object_new (offscreen); _cogl_texture_associate_framebuffer (texture, fb); return ret; } /* XXX: deprecated api */ CoglOffscreen * cogl_offscreen_new_to_texture (CoglTexture *texture) { CoglOffscreen *ret = _cogl_offscreen_new_with_texture_full (texture, 0, 0); CoglError *error = NULL; if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (ret), &error)) { cogl_object_unref (ret); cogl_error_free (error); ret = NULL; } return ret; } CoglOffscreen * cogl_offscreen_new_with_texture (CoglTexture *texture) { return _cogl_offscreen_new_with_texture_full (texture, 0, 0); } CoglTexture * cogl_offscreen_get_texture (CoglOffscreen *offscreen) { return offscreen->texture; } static void _cogl_offscreen_free (CoglOffscreen *offscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen); CoglContext *ctx = framebuffer->context; ctx->driver_vtable->offscreen_free (offscreen); /* Chain up to parent */ _cogl_framebuffer_free (framebuffer); if (offscreen->texture != NULL) cogl_object_unref (offscreen->texture); if (offscreen->depth_texture != NULL) cogl_object_unref (offscreen->depth_texture); free (offscreen); } CoglBool cogl_framebuffer_allocate (CoglFramebuffer *framebuffer, CoglError **error) { CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer); CoglContext *ctx = framebuffer->context; if (framebuffer->allocated) return TRUE; if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) { if (framebuffer->config.depth_texture_enabled) { _cogl_set_error (error, COGL_FRAMEBUFFER_ERROR, COGL_FRAMEBUFFER_ERROR_ALLOCATE, "Can't allocate onscreen framebuffer with a " "texture based depth buffer"); return FALSE; } if (!winsys->onscreen_init (onscreen, error)) return FALSE; /* If the winsys doesn't support dirty events then we'll report * one on allocation so that if the application only paints in * response to dirty events then it will at least paint once to * start */ if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_DIRTY_EVENTS)) _cogl_onscreen_queue_full_dirty (onscreen); } else { CoglOffscreen *offscreen = COGL_OFFSCREEN (framebuffer); if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Offscreen framebuffers not supported by system"); return FALSE; } if (!cogl_texture_allocate (offscreen->texture, error)) return FALSE; /* NB: it's only after allocating the texture that we will * determine whether a texture needs slicing... */ if (cogl_texture_is_sliced (offscreen->texture)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Can't create offscreen framebuffer from " "sliced texture"); return FALSE; } /* Now that the texture has been allocated we can determine a * size for the framebuffer... */ framebuffer->width = cogl_texture_get_width (offscreen->texture); framebuffer->height = cogl_texture_get_height (offscreen->texture); framebuffer->viewport_width = framebuffer->width; framebuffer->viewport_height = framebuffer->height; /* Forward the texture format as the internal format of the * framebuffer */ framebuffer->internal_format = _cogl_texture_get_format (offscreen->texture); if (!ctx->driver_vtable->offscreen_allocate (offscreen, error)) return FALSE; } framebuffer->allocated = TRUE; return TRUE; } static unsigned long _cogl_framebuffer_compare_viewport_state (CoglFramebuffer *a, CoglFramebuffer *b) { if (a->viewport_x != b->viewport_x || a->viewport_y != b->viewport_y || a->viewport_width != b->viewport_width || a->viewport_height != b->viewport_height || /* NB: we render upside down to offscreen framebuffers and that * can affect how we setup the GL viewport... */ a->type != b->type) { unsigned long differences = COGL_FRAMEBUFFER_STATE_VIEWPORT; CoglContext *context = a->context; /* XXX: ONGOING BUG: Intel viewport scissor * * Intel gen6 drivers don't currently correctly handle offset * viewports, since primitives aren't clipped within the bounds of * the viewport. To workaround this we push our own clip for the * viewport that will use scissoring to ensure we clip as expected. * * This workaround implies that a change in viewport state is * effectively also a change in the clipping state. * * TODO: file a bug upstream! */ if (G_UNLIKELY (context->needs_viewport_scissor_workaround)) differences |= COGL_FRAMEBUFFER_STATE_CLIP; return differences; } else return 0; } static unsigned long _cogl_framebuffer_compare_clip_state (CoglFramebuffer *a, CoglFramebuffer *b) { if (a->clip_stack != b->clip_stack) return COGL_FRAMEBUFFER_STATE_CLIP; else return 0; } static unsigned long _cogl_framebuffer_compare_dither_state (CoglFramebuffer *a, CoglFramebuffer *b) { return a->dither_enabled != b->dither_enabled ? COGL_FRAMEBUFFER_STATE_DITHER : 0; } static unsigned long _cogl_framebuffer_compare_modelview_state (CoglFramebuffer *a, CoglFramebuffer *b) { /* We always want to flush the modelview state. All this does is set the current modelview stack on the context to the framebuffer's stack. */ return COGL_FRAMEBUFFER_STATE_MODELVIEW; } static unsigned long _cogl_framebuffer_compare_projection_state (CoglFramebuffer *a, CoglFramebuffer *b) { /* We always want to flush the projection state. All this does is set the current projection stack on the context to the framebuffer's stack. */ return COGL_FRAMEBUFFER_STATE_PROJECTION; } static unsigned long _cogl_framebuffer_compare_color_mask_state (CoglFramebuffer *a, CoglFramebuffer *b) { if (cogl_framebuffer_get_color_mask (a) != cogl_framebuffer_get_color_mask (b)) return COGL_FRAMEBUFFER_STATE_COLOR_MASK; else return 0; } static unsigned long _cogl_framebuffer_compare_front_face_winding_state (CoglFramebuffer *a, CoglFramebuffer *b) { if (a->type != b->type) return COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING; else return 0; } static unsigned long _cogl_framebuffer_compare_depth_write_state (CoglFramebuffer *a, CoglFramebuffer *b) { return a->depth_writing_enabled != b->depth_writing_enabled ? COGL_FRAMEBUFFER_STATE_DEPTH_WRITE : 0; } static unsigned long _cogl_framebuffer_compare_stereo_mode (CoglFramebuffer *a, CoglFramebuffer *b) { return a->stereo_mode != b->stereo_mode ? COGL_FRAMEBUFFER_STATE_STEREO_MODE : 0; } unsigned long _cogl_framebuffer_compare (CoglFramebuffer *a, CoglFramebuffer *b, unsigned long state) { unsigned long differences = 0; int bit; if (state & COGL_FRAMEBUFFER_STATE_BIND) { differences |= COGL_FRAMEBUFFER_STATE_BIND; state &= ~COGL_FRAMEBUFFER_STATE_BIND; } COGL_FLAGS_FOREACH_START (&state, 1, bit) { /* XXX: We considered having an array of callbacks for each state index * that we'd call here but decided that this way the compiler is more * likely going to be able to in-line the comparison functions and use * the index to jump straight to the required code. */ switch (bit) { case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT: differences |= _cogl_framebuffer_compare_viewport_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_CLIP: differences |= _cogl_framebuffer_compare_clip_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_DITHER: differences |= _cogl_framebuffer_compare_dither_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW: differences |= _cogl_framebuffer_compare_modelview_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION: differences |= _cogl_framebuffer_compare_projection_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK: differences |= _cogl_framebuffer_compare_color_mask_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING: differences |= _cogl_framebuffer_compare_front_face_winding_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE: differences |= _cogl_framebuffer_compare_depth_write_state (a, b); break; case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE: differences |= _cogl_framebuffer_compare_stereo_mode (a, b); break; default: g_warn_if_reached (); } } COGL_FLAGS_FOREACH_END; return differences; } void _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state) { CoglContext *ctx = draw_buffer->context; ctx->driver_vtable->framebuffer_flush_state (draw_buffer, read_buffer, state); } int cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; CoglFramebufferBits bits; ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits); return bits.red; } int cogl_framebuffer_get_green_bits (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; CoglFramebufferBits bits; ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits); return bits.green; } int cogl_framebuffer_get_blue_bits (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; CoglFramebufferBits bits; ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits); return bits.blue; } int cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; CoglFramebufferBits bits; ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits); return bits.alpha; } int cogl_framebuffer_get_depth_bits (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; CoglFramebufferBits bits; ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits); return bits.depth; } int _cogl_framebuffer_get_stencil_bits (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; CoglFramebufferBits bits; ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits); return bits.stencil; } gboolean cogl_framebuffer_get_is_stereo (CoglFramebuffer *framebuffer) { return framebuffer->config.stereo_enabled; } CoglColorMask cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer) { return framebuffer->color_mask; } void cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer, CoglColorMask color_mask) { if (framebuffer->color_mask == color_mask) return; /* XXX: Currently color mask changes don't go through the journal */ _cogl_framebuffer_flush_journal (framebuffer); framebuffer->color_mask = color_mask; if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_COLOR_MASK; } CoglStereoMode cogl_framebuffer_get_stereo_mode (CoglFramebuffer *framebuffer) { return framebuffer->stereo_mode; } void cogl_framebuffer_set_stereo_mode (CoglFramebuffer *framebuffer, CoglStereoMode stereo_mode) { if (framebuffer->stereo_mode == stereo_mode) return; /* Stereo mode changes don't go through the journal */ _cogl_framebuffer_flush_journal (framebuffer); framebuffer->stereo_mode = stereo_mode; if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_STEREO_MODE; } CoglBool cogl_framebuffer_get_depth_write_enabled (CoglFramebuffer *framebuffer) { return framebuffer->depth_writing_enabled; } void cogl_framebuffer_set_depth_write_enabled (CoglFramebuffer *framebuffer, CoglBool depth_write_enabled) { if (framebuffer->depth_writing_enabled == depth_write_enabled) return; /* XXX: Currently depth write changes don't go through the journal */ _cogl_framebuffer_flush_journal (framebuffer); framebuffer->depth_writing_enabled = depth_write_enabled; if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_DEPTH_WRITE; } CoglBool cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer) { return framebuffer->dither_enabled; } void cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer, CoglBool dither_enabled) { if (framebuffer->dither_enabled == dither_enabled) return; cogl_flush (); /* Currently dithering changes aren't tracked in the journal */ framebuffer->dither_enabled = dither_enabled; if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_DITHER; } void cogl_framebuffer_set_depth_texture_enabled (CoglFramebuffer *framebuffer, CoglBool enabled) { _COGL_RETURN_IF_FAIL (!framebuffer->allocated); framebuffer->config.depth_texture_enabled = enabled; } CoglBool cogl_framebuffer_get_depth_texture_enabled (CoglFramebuffer *framebuffer) { return framebuffer->config.depth_texture_enabled; } CoglTexture * cogl_framebuffer_get_depth_texture (CoglFramebuffer *framebuffer) { /* lazily allocate the framebuffer... */ if (!cogl_framebuffer_allocate (framebuffer, NULL)) return NULL; _COGL_RETURN_VAL_IF_FAIL (cogl_is_offscreen (framebuffer), NULL); return COGL_OFFSCREEN(framebuffer)->depth_texture; } int cogl_framebuffer_get_samples_per_pixel (CoglFramebuffer *framebuffer) { if (framebuffer->allocated) return framebuffer->samples_per_pixel; else return framebuffer->config.samples_per_pixel; } void cogl_framebuffer_set_samples_per_pixel (CoglFramebuffer *framebuffer, int samples_per_pixel) { _COGL_RETURN_IF_FAIL (!framebuffer->allocated); framebuffer->config.samples_per_pixel = samples_per_pixel; } void cogl_framebuffer_resolve_samples (CoglFramebuffer *framebuffer) { cogl_framebuffer_resolve_samples_region (framebuffer, 0, 0, framebuffer->width, framebuffer->height); /* TODO: Make this happen implicitly when the resolve texture next gets used * as a source, either via cogl_texture_get_data(), via cogl_read_pixels() or * if used as a source for rendering. We would also implicitly resolve if * necessary before freeing a CoglFramebuffer. * * This API should still be kept but it is optional, only necessary * if the user wants to explicitly control when the resolve happens e.g. * to ensure it's done in advance of it being used as a source. * * Every texture should have a CoglFramebuffer *needs_resolve member * internally. When the texture gets validated before being used as a source * we should first check the needs_resolve pointer and if set we'll * automatically call cogl_framebuffer_resolve_samples (). * * Calling cogl_framebuffer_resolve_samples() or * cogl_framebuffer_resolve_samples_region() should reset the textures * needs_resolve pointer to NULL. * * Rendering anything to a framebuffer will cause the corresponding * texture's ->needs_resolve pointer to be set. * * XXX: Note: we only need to address this TODO item when adding support for * EXT_framebuffer_multisample because currently we only support hardware * that resolves implicitly anyway. */ } void cogl_framebuffer_resolve_samples_region (CoglFramebuffer *framebuffer, int x, int y, int width, int height) { /* NOP for now since we don't support EXT_framebuffer_multisample yet which * requires an explicit resolve. */ } CoglContext * cogl_framebuffer_get_context (CoglFramebuffer *framebuffer) { _COGL_RETURN_VAL_IF_FAIL (framebuffer != NULL, NULL); return framebuffer->context; } static CoglBool _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap) { CoglBool found_intersection; CoglPixelFormat format; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FAST_READ_PIXEL))) return FALSE; if (source != COGL_READ_PIXELS_COLOR_BUFFER) return FALSE; format = cogl_bitmap_get_format (bitmap); if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE && format != COGL_PIXEL_FORMAT_RGBA_8888) return FALSE; if (!_cogl_journal_try_read_pixel (framebuffer->journal, x, y, bitmap, &found_intersection)) return FALSE; /* If we can't determine the color from the primitives in the * journal then see if we can use the last recorded clear color */ /* If _cogl_journal_try_read_pixel() failed even though there was an * intersection of the given point with a primitive in the journal * then we can't fallback to the framebuffer's last clear color... * */ if (found_intersection) return TRUE; /* If the framebuffer has been rendered too since it was last * cleared then we can't return the last known clear color. */ if (framebuffer->clear_clip_dirty) return FALSE; if (x >= framebuffer->clear_clip_x0 && x < framebuffer->clear_clip_x1 && y >= framebuffer->clear_clip_y0 && y < framebuffer->clear_clip_y1) { uint8_t *pixel; CoglError *ignore_error = NULL; /* we currently only care about cases where the premultiplied or * unpremultipled colors are equivalent... */ if (framebuffer->clear_color_alpha != 1.0) return FALSE; pixel = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, &ignore_error); if (pixel == NULL) { cogl_error_free (ignore_error); return FALSE; } pixel[0] = framebuffer->clear_color_red * 255.0; pixel[1] = framebuffer->clear_color_green * 255.0; pixel[2] = framebuffer->clear_color_blue * 255.0; pixel[3] = framebuffer->clear_color_alpha * 255.0; _cogl_bitmap_unmap (bitmap); return TRUE; } return FALSE; } CoglBool _cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error) { CoglContext *ctx; int width; int height; _COGL_RETURN_VAL_IF_FAIL (source & COGL_READ_PIXELS_COLOR_BUFFER, FALSE); _COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), FALSE); if (!cogl_framebuffer_allocate (framebuffer, error)) return FALSE; width = cogl_bitmap_get_width (bitmap); height = cogl_bitmap_get_height (bitmap); if (width == 1 && height == 1 && !framebuffer->clear_clip_dirty) { /* If everything drawn so far for this frame is still in the * Journal then if all of the rectangles only have a flat * opaque color we have a fast-path for reading a single pixel * that avoids the relatively high cost of flushing primitives * to be drawn on the GPU (considering how simple the geometry * is in this case) and then blocking on the long GPU pipelines * for the result. */ if (_cogl_framebuffer_try_fast_read_pixel (framebuffer, x, y, source, bitmap)) return TRUE; } ctx = cogl_framebuffer_get_context (framebuffer); /* make sure any batched primitives get emitted to the driver * before issuing our read pixels... */ _cogl_framebuffer_flush_journal (framebuffer); return ctx->driver_vtable->framebuffer_read_pixels_into_bitmap (framebuffer, x, y, source, bitmap, error); } CoglBool cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap) { CoglError *ignore_error = NULL; CoglBool status = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer, x, y, source, bitmap, &ignore_error); if (!status) cogl_error_free (ignore_error); return status; } CoglBool cogl_framebuffer_read_pixels (CoglFramebuffer *framebuffer, int x, int y, int width, int height, CoglPixelFormat format, uint8_t *pixels) { int bpp = _cogl_pixel_format_get_bytes_per_pixel (format); CoglBitmap *bitmap; CoglBool ret; bitmap = cogl_bitmap_new_for_data (framebuffer->context, width, height, format, bpp * width, /* rowstride */ pixels); /* Note: we don't try and catch errors here since we created the * bitmap storage up-front and can assume we wont hit an * out-of-memory error which should be the only exception * this api throws. */ ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer, x, y, COGL_READ_PIXELS_COLOR_BUFFER, bitmap, NULL); cogl_object_unref (bitmap); return ret; } void _cogl_blit_framebuffer (CoglFramebuffer *src, CoglFramebuffer *dest, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { CoglContext *ctx = src->context; _COGL_RETURN_IF_FAIL (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)); /* We can only support blitting between offscreen buffers because otherwise we would need to mirror the image and GLES2.0 doesn't support this */ _COGL_RETURN_IF_FAIL (cogl_is_offscreen (src)); _COGL_RETURN_IF_FAIL (cogl_is_offscreen (dest)); /* The buffers must be the same format */ _COGL_RETURN_IF_FAIL (src->internal_format == dest->internal_format); /* Make sure the current framebuffers are bound. We explicitly avoid flushing the clip state so we can bind our own empty state */ _cogl_framebuffer_flush_state (dest, src, COGL_FRAMEBUFFER_STATE_ALL & ~COGL_FRAMEBUFFER_STATE_CLIP); /* Flush any empty clip stack because glBlitFramebuffer is affected by the scissor and we want to hide this feature for the Cogl API because it's not obvious to an app how the clip state will affect the scissor */ _cogl_clip_stack_flush (NULL, dest); /* XXX: Because we are manually flushing clip state here we need to * make sure that the clip state gets updated the next time we flush * framebuffer state by marking the current framebuffer's clip state * as changed */ ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; ctx->glBlitFramebuffer (src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); } void cogl_framebuffer_discard_buffers (CoglFramebuffer *framebuffer, unsigned long buffers) { CoglContext *ctx = framebuffer->context; _COGL_RETURN_IF_FAIL (buffers & COGL_BUFFER_BIT_COLOR); ctx->driver_vtable->framebuffer_discard_buffers (framebuffer, buffers); } void cogl_framebuffer_finish (CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; _cogl_framebuffer_flush_journal (framebuffer); ctx->driver_vtable->framebuffer_finish (framebuffer); } void cogl_framebuffer_push_matrix (CoglFramebuffer *framebuffer) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_push (modelview_stack); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_pop_matrix (CoglFramebuffer *framebuffer) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_pop (modelview_stack); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_identity_matrix (CoglFramebuffer *framebuffer) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_load_identity (modelview_stack); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_scale (CoglFramebuffer *framebuffer, float x, float y, float z) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_scale (modelview_stack, x, y, z); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_translate (CoglFramebuffer *framebuffer, float x, float y, float z) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_translate (modelview_stack, x, y, z); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_rotate (CoglFramebuffer *framebuffer, float angle, float x, float y, float z) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_rotate_quaternion (CoglFramebuffer *framebuffer, const CoglQuaternion *quaternion) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_rotate_quaternion (modelview_stack, quaternion); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_rotate_euler (CoglFramebuffer *framebuffer, const CoglEuler *euler) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_rotate_euler (modelview_stack, euler); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_transform (CoglFramebuffer *framebuffer, const CoglMatrix *matrix) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_multiply (modelview_stack, matrix); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; } void cogl_framebuffer_perspective (CoglFramebuffer *framebuffer, float fov_y, float aspect, float z_near, float z_far) { float ymax = z_near * tanf (fov_y * G_PI / 360.0); cogl_framebuffer_frustum (framebuffer, -ymax * aspect, /* left */ ymax * aspect, /* right */ -ymax, /* bottom */ ymax, /* top */ z_near, z_far); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_PROJECTION; } void cogl_framebuffer_frustum (CoglFramebuffer *framebuffer, float left, float right, float bottom, float top, float z_near, float z_far) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); /* XXX: The projection matrix isn't currently tracked in the journal * so we need to flush all journaled primitives first... */ _cogl_framebuffer_flush_journal (framebuffer); cogl_matrix_stack_load_identity (projection_stack); cogl_matrix_stack_frustum (projection_stack, left, right, bottom, top, z_near, z_far); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_PROJECTION; } void cogl_framebuffer_orthographic (CoglFramebuffer *framebuffer, float x_1, float y_1, float x_2, float y_2, float near, float far) { CoglMatrix ortho; CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); /* XXX: The projection matrix isn't currently tracked in the journal * so we need to flush all journaled primitives first... */ _cogl_framebuffer_flush_journal (framebuffer); cogl_matrix_init_identity (&ortho); cogl_matrix_orthographic (&ortho, x_1, y_1, x_2, y_2, near, far); cogl_matrix_stack_set (projection_stack, &ortho); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_PROJECTION; } void _cogl_framebuffer_push_projection (CoglFramebuffer *framebuffer) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); cogl_matrix_stack_push (projection_stack); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_PROJECTION; } void _cogl_framebuffer_pop_projection (CoglFramebuffer *framebuffer) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); cogl_matrix_stack_pop (projection_stack); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_PROJECTION; } void cogl_framebuffer_get_modelview_matrix (CoglFramebuffer *framebuffer, CoglMatrix *matrix) { CoglMatrixEntry *modelview_entry = _cogl_framebuffer_get_modelview_entry (framebuffer); cogl_matrix_entry_get (modelview_entry, matrix); _COGL_MATRIX_DEBUG_PRINT (matrix); } void cogl_framebuffer_set_modelview_matrix (CoglFramebuffer *framebuffer, const CoglMatrix *matrix) { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); cogl_matrix_stack_set (modelview_stack, matrix); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; _COGL_MATRIX_DEBUG_PRINT (matrix); } void cogl_framebuffer_get_projection_matrix (CoglFramebuffer *framebuffer, CoglMatrix *matrix) { CoglMatrixEntry *projection_entry = _cogl_framebuffer_get_projection_entry (framebuffer); cogl_matrix_entry_get (projection_entry, matrix); _COGL_MATRIX_DEBUG_PRINT (matrix); } void cogl_framebuffer_set_projection_matrix (CoglFramebuffer *framebuffer, const CoglMatrix *matrix) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); /* XXX: The projection matrix isn't currently tracked in the journal * so we need to flush all journaled primitives first... */ _cogl_framebuffer_flush_journal (framebuffer); cogl_matrix_stack_set (projection_stack, matrix); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_PROJECTION; _COGL_MATRIX_DEBUG_PRINT (matrix); } void cogl_framebuffer_push_scissor_clip (CoglFramebuffer *framebuffer, int x, int y, int width, int height) { framebuffer->clip_stack = _cogl_clip_stack_push_window_rectangle (framebuffer->clip_stack, x, y, width, height); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } void cogl_framebuffer_push_rectangle_clip (CoglFramebuffer *framebuffer, float x_1, float y_1, float x_2, float y_2) { CoglMatrixEntry *modelview_entry = _cogl_framebuffer_get_modelview_entry (framebuffer); CoglMatrixEntry *projection_entry = _cogl_framebuffer_get_projection_entry (framebuffer); /* XXX: It would be nicer if we stored the private viewport as a * vec4 so we could avoid this redundant copy. */ float viewport[] = { framebuffer->viewport_x, framebuffer->viewport_y, framebuffer->viewport_width, framebuffer->viewport_height }; framebuffer->clip_stack = _cogl_clip_stack_push_rectangle (framebuffer->clip_stack, x_1, y_1, x_2, y_2, modelview_entry, projection_entry, viewport); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } void cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer, CoglPrimitive *primitive, float bounds_x1, float bounds_y1, float bounds_x2, float bounds_y2) { CoglMatrixEntry *modelview_entry = _cogl_framebuffer_get_modelview_entry (framebuffer); CoglMatrixEntry *projection_entry = _cogl_framebuffer_get_projection_entry (framebuffer); /* XXX: It would be nicer if we stored the private viewport as a * vec4 so we could avoid this redundant copy. */ float viewport[] = { framebuffer->viewport_x, framebuffer->viewport_y, framebuffer->viewport_width, framebuffer->viewport_height }; framebuffer->clip_stack = _cogl_clip_stack_push_primitive (framebuffer->clip_stack, primitive, bounds_x1, bounds_y1, bounds_x2, bounds_y2, modelview_entry, projection_entry, viewport); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } void cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer) { framebuffer->clip_stack = _cogl_clip_stack_pop (framebuffer->clip_stack); if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; } void _cogl_framebuffer_unref (CoglFramebuffer *framebuffer) { /* The journal holds a reference to the framebuffer whenever it is non-empty. Therefore if the journal is non-empty and we will have exactly one reference then we know the journal is the only thing keeping the framebuffer alive. In that case we want to flush the journal and let the framebuffer die. It is fine at this point if flushing the journal causes something else to take a reference to it and it comes back to life */ if (framebuffer->journal->entries->len > 0) { unsigned int ref_count = ((CoglObject *) framebuffer)->ref_count; /* There should be at least two references - the one we are about to drop and the one held by the journal */ if (ref_count < 2) g_warning ("Inconsistent ref count on a framebuffer with journal " "entries."); if (ref_count == 2) _cogl_framebuffer_flush_journal (framebuffer); } /* Chain-up */ _cogl_object_default_unref (framebuffer); } #ifdef COGL_ENABLE_DEBUG static int get_index (void *indices, CoglIndicesType type, int _index) { if (!indices) return _index; switch (type) { case COGL_INDICES_TYPE_UNSIGNED_BYTE: return ((uint8_t *)indices)[_index]; case COGL_INDICES_TYPE_UNSIGNED_SHORT: return ((uint16_t *)indices)[_index]; case COGL_INDICES_TYPE_UNSIGNED_INT: return ((uint32_t *)indices)[_index]; } g_return_val_if_reached (0); } static void add_line (uint32_t *line_indices, int base, void *user_indices, CoglIndicesType user_indices_type, int index0, int index1, int *pos) { index0 = get_index (user_indices, user_indices_type, index0); index1 = get_index (user_indices, user_indices_type, index1); line_indices[(*pos)++] = base + index0; line_indices[(*pos)++] = base + index1; } static int get_line_count (CoglVerticesMode mode, int n_vertices) { if (mode == COGL_VERTICES_MODE_TRIANGLES && (n_vertices % 3) == 0) { return n_vertices; } else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN && n_vertices >= 3) { return 2 * n_vertices - 3; } else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP && n_vertices >= 3) { return 2 * n_vertices - 3; } /* In the journal we are a bit sneaky and actually use GL_QUADS * which isn't actually a valid CoglVerticesMode! */ #ifdef HAVE_COGL_GL else if (mode == GL_QUADS && (n_vertices % 4) == 0) { return n_vertices; } #endif g_return_val_if_reached (0); } static CoglIndices * get_wire_line_indices (CoglContext *ctx, CoglVerticesMode mode, int first_vertex, int n_vertices_in, CoglIndices *user_indices, int *n_indices) { int n_lines; uint32_t *line_indices; CoglIndexBuffer *index_buffer; void *indices; CoglIndicesType indices_type; int base = first_vertex; int pos; int i; CoglIndices *ret; if (user_indices) { index_buffer = cogl_indices_get_buffer (user_indices); indices = _cogl_buffer_map (COGL_BUFFER (index_buffer), COGL_BUFFER_ACCESS_READ, 0, NULL); indices_type = cogl_indices_get_type (user_indices); } else { index_buffer = NULL; indices = NULL; indices_type = COGL_INDICES_TYPE_UNSIGNED_BYTE; } n_lines = get_line_count (mode, n_vertices_in); /* Note: we are using COGL_INDICES_TYPE_UNSIGNED_INT so 4 bytes per index. */ line_indices = malloc (4 * n_lines * 2); pos = 0; if (mode == COGL_VERTICES_MODE_TRIANGLES && (n_vertices_in % 3) == 0) { for (i = 0; i < n_vertices_in; i += 3) { add_line (line_indices, base, indices, indices_type, i, i+1, &pos); add_line (line_indices, base, indices, indices_type, i+1, i+2, &pos); add_line (line_indices, base, indices, indices_type, i+2, i, &pos); } } else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN && n_vertices_in >= 3) { add_line (line_indices, base, indices, indices_type, 0, 1, &pos); add_line (line_indices, base, indices, indices_type, 1, 2, &pos); add_line (line_indices, base, indices, indices_type, 0, 2, &pos); for (i = 3; i < n_vertices_in; i++) { add_line (line_indices, base, indices, indices_type, i - 1, i, &pos); add_line (line_indices, base, indices, indices_type, 0, i, &pos); } } else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP && n_vertices_in >= 3) { add_line (line_indices, base, indices, indices_type, 0, 1, &pos); add_line (line_indices, base, indices, indices_type, 1, 2, &pos); add_line (line_indices, base, indices, indices_type, 0, 2, &pos); for (i = 3; i < n_vertices_in; i++) { add_line (line_indices, base, indices, indices_type, i - 1, i, &pos); add_line (line_indices, base, indices, indices_type, i - 2, i, &pos); } } /* In the journal we are a bit sneaky and actually use GL_QUADS * which isn't actually a valid CoglVerticesMode! */ #ifdef HAVE_COGL_GL else if (mode == GL_QUADS && (n_vertices_in % 4) == 0) { for (i = 0; i < n_vertices_in; i += 4) { add_line (line_indices, base, indices, indices_type, i, i + 1, &pos); add_line (line_indices, base, indices, indices_type, i + 1, i + 2, &pos); add_line (line_indices, base, indices, indices_type, i + 2, i + 3, &pos); add_line (line_indices, base, indices, indices_type, i + 3, i, &pos); } } #endif if (user_indices) cogl_buffer_unmap (COGL_BUFFER (index_buffer)); *n_indices = n_lines * 2; ret = cogl_indices_new (ctx, COGL_INDICES_TYPE_UNSIGNED_INT, line_indices, *n_indices); free (line_indices); return ret; } static CoglBool remove_layer_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { cogl_pipeline_remove_layer (pipeline, layer_index); return TRUE; } static void pipeline_destroyed_cb (CoglPipeline *weak_pipeline, void *user_data) { CoglPipeline *original_pipeline = user_data; /* XXX: I think we probably need to provide a custom unref function for * CoglPipeline because it's possible that we will reach this callback * because original_pipeline is being freed which means cogl_object_unref * will have already freed any associated user data. * * Setting more user data here will *probably* succeed but that may allocate * a new user-data array which could be leaked. * * Potentially we could have a _cogl_object_free_user_data function so * that a custom unref function could be written that can destroy weak * pipeline children before removing user data. */ cogl_object_set_user_data (COGL_OBJECT (original_pipeline), &wire_pipeline_key, NULL, NULL); cogl_object_unref (weak_pipeline); } static void draw_wireframe (CoglContext *ctx, CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglIndices *indices, CoglDrawFlags flags) { CoglIndices *wire_indices; CoglPipeline *wire_pipeline; int n_indices; wire_indices = get_wire_line_indices (ctx, mode, first_vertex, n_vertices, indices, &n_indices); wire_pipeline = cogl_object_get_user_data (COGL_OBJECT (pipeline), &wire_pipeline_key); if (!wire_pipeline) { wire_pipeline = _cogl_pipeline_weak_copy (pipeline, pipeline_destroyed_cb, NULL); cogl_object_set_user_data (COGL_OBJECT (pipeline), &wire_pipeline_key, wire_pipeline, NULL); /* If we have glsl then the pipeline may have an associated * vertex program and since we'd like to see the results of the * vertex program in the wireframe we just add a final clobber * of the wire color leaving the rest of the state untouched. */ if (cogl_has_feature (framebuffer->context, COGL_FEATURE_ID_GLSL)) { static CoglSnippet *snippet = NULL; /* The snippet is cached so that it will reuse the program * from the pipeline cache if possible */ if (snippet == NULL) { snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, NULL); cogl_snippet_set_replace (snippet, "cogl_color_out = " "vec4 (0.0, 1.0, 0.0, 1.0);\n"); } cogl_pipeline_add_snippet (wire_pipeline, snippet); } else { cogl_pipeline_foreach_layer (wire_pipeline, remove_layer_cb, NULL); cogl_pipeline_set_color4f (wire_pipeline, 0, 1, 0, 1); } } /* temporarily disable the wireframe to avoid recursion! */ flags |= COGL_DRAW_SKIP_DEBUG_WIREFRAME; _cogl_framebuffer_draw_indexed_attributes ( framebuffer, wire_pipeline, COGL_VERTICES_MODE_LINES, 0, n_indices, wire_indices, attributes, n_attributes, flags); COGL_DEBUG_SET_FLAG (COGL_DEBUG_WIREFRAME); cogl_object_unref (wire_indices); } #endif /* This can be called directly by the CoglJournal to draw attributes * skipping the implicit journal flush, the framebuffer flush and * pipeline validation. */ void _cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags) { #ifdef COGL_ENABLE_DEBUG if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME) && (flags & COGL_DRAW_SKIP_DEBUG_WIREFRAME) == 0) && mode != COGL_VERTICES_MODE_LINES && mode != COGL_VERTICES_MODE_LINE_LOOP && mode != COGL_VERTICES_MODE_LINE_STRIP) draw_wireframe (framebuffer->context, framebuffer, pipeline, mode, first_vertex, n_vertices, attributes, n_attributes, NULL, flags); else #endif { CoglContext *ctx = framebuffer->context; ctx->driver_vtable->framebuffer_draw_attributes (framebuffer, pipeline, mode, first_vertex, n_vertices, attributes, n_attributes, flags); } } /* XXX: deprecated */ void cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes) { _cogl_framebuffer_draw_attributes (framebuffer, pipeline, mode, first_vertex, n_vertices, attributes, n_attributes, COGL_DRAW_SKIP_LEGACY_STATE); } /* XXX: deprecated */ void cogl_framebuffer_vdraw_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, ...) { va_list ap; int n_attributes; CoglAttribute *attribute; CoglAttribute **attributes; int i; va_start (ap, n_vertices); for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++) ; va_end (ap); attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes); va_start (ap, n_vertices); for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++) attributes[i] = attribute; va_end (ap); _cogl_framebuffer_draw_attributes (framebuffer, pipeline, mode, first_vertex, n_vertices, attributes, n_attributes, COGL_DRAW_SKIP_LEGACY_STATE); } void _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags) { #ifdef COGL_ENABLE_DEBUG if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME) && (flags & COGL_DRAW_SKIP_DEBUG_WIREFRAME) == 0) && mode != COGL_VERTICES_MODE_LINES && mode != COGL_VERTICES_MODE_LINE_LOOP && mode != COGL_VERTICES_MODE_LINE_STRIP) draw_wireframe (framebuffer->context, framebuffer, pipeline, mode, first_vertex, n_vertices, attributes, n_attributes, indices, flags); else #endif { CoglContext *ctx = framebuffer->context; ctx->driver_vtable->framebuffer_draw_indexed_attributes (framebuffer, pipeline, mode, first_vertex, n_vertices, indices, attributes, n_attributes, flags); } } /* XXX: deprecated */ void cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes) { _cogl_framebuffer_draw_indexed_attributes (framebuffer, pipeline, mode, first_vertex, n_vertices, indices, attributes, n_attributes, COGL_DRAW_SKIP_LEGACY_STATE); } /* XXX: deprecated */ void cogl_framebuffer_vdraw_indexed_attributes (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, ...) { va_list ap; int n_attributes; CoglAttribute **attributes; int i; CoglAttribute *attribute; va_start (ap, indices); for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++) ; va_end (ap); attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes); va_start (ap, indices); for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++) attributes[i] = attribute; va_end (ap); _cogl_framebuffer_draw_indexed_attributes (framebuffer, pipeline, mode, first_vertex, n_vertices, indices, attributes, n_attributes, COGL_DRAW_SKIP_LEGACY_STATE); } void cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglPrimitive *primitive) { _cogl_primitive_draw (primitive, framebuffer, pipeline, COGL_DRAW_SKIP_LEGACY_STATE); } void cogl_framebuffer_draw_rectangle (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2) { const float position[4] = {x_1, y_1, x_2, y_2}; CoglMultiTexturedRect rect; /* XXX: All the _*_rectangle* APIs normalize their input into an array of * _CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_framebuffer_draw_multitextured_rectangles. */ rect.position = position; rect.tex_coords = NULL; rect.tex_coords_len = 0; _cogl_framebuffer_draw_multitextured_rectangles (framebuffer, pipeline, &rect, 1, TRUE); } void cogl_framebuffer_draw_textured_rectangle (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2, float s_1, float t_1, float s_2, float t_2) { const float position[4] = {x_1, y_1, x_2, y_2}; const float tex_coords[4] = {s_1, t_1, s_2, t_2}; CoglMultiTexturedRect rect; /* XXX: All the _*_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_framebuffer_draw_multitextured_rectangles. */ rect.position = position; rect.tex_coords = tex_coords; rect.tex_coords_len = 4; _cogl_framebuffer_draw_multitextured_rectangles (framebuffer, pipeline, &rect, 1, TRUE); } void cogl_framebuffer_draw_multitextured_rectangle (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2, const float *tex_coords, int tex_coords_len) { const float position[4] = {x_1, y_1, x_2, y_2}; CoglMultiTexturedRect rect; /* XXX: All the _*_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_framebuffer_draw_multitextured_rectangles. */ rect.position = position; rect.tex_coords = tex_coords; rect.tex_coords_len = tex_coords_len; _cogl_framebuffer_draw_multitextured_rectangles (framebuffer, pipeline, &rect, 1, TRUE); } void cogl_framebuffer_draw_rectangles (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, const float *coordinates, unsigned int n_rectangles) { CoglMultiTexturedRect *rects; int i; /* XXX: All the _*_rectangle* APIs normalize their input into an array of * CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_framebuffer_draw_multitextured_rectangles. */ rects = g_alloca (n_rectangles * sizeof (CoglMultiTexturedRect)); for (i = 0; i < n_rectangles; i++) { rects[i].position = &coordinates[i * 4]; rects[i].tex_coords = NULL; rects[i].tex_coords_len = 0; } _cogl_framebuffer_draw_multitextured_rectangles (framebuffer, pipeline, rects, n_rectangles, TRUE); } void cogl_framebuffer_draw_textured_rectangles (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, const float *coordinates, unsigned int n_rectangles) { CoglMultiTexturedRect *rects; int i; /* XXX: All the _*_rectangle* APIs normalize their input into an array of * _CoglMultiTexturedRect rectangles and pass these on to our work horse; * _cogl_framebuffer_draw_multitextured_rectangles. */ rects = g_alloca (n_rectangles * sizeof (CoglMultiTexturedRect)); for (i = 0; i < n_rectangles; i++) { rects[i].position = &coordinates[i * 8]; rects[i].tex_coords = &coordinates[i * 8 + 4]; rects[i].tex_coords_len = 4; } _cogl_framebuffer_draw_multitextured_rectangles (framebuffer, pipeline, rects, n_rectangles, TRUE); } muffin-5.2.1/cogl/cogl/cogl-blit.c0000664000175000017500000003303214211404421017025 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-util.h" #include "cogl-blit.h" #include "cogl-context-private.h" #include "cogl-framebuffer-private.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-private.h" #include "cogl-private.h" #include "cogl1-context.h" static const CoglBlitMode *_cogl_blit_default_mode = NULL; static CoglBool _cogl_blit_texture_render_begin (CoglBlitData *data) { CoglContext *ctx = data->src_tex->context; CoglOffscreen *offscreen; CoglFramebuffer *fb; CoglPipeline *pipeline; unsigned int dst_width, dst_height; CoglError *ignore_error = NULL; offscreen = _cogl_offscreen_new_with_texture_full (data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); fb = COGL_FRAMEBUFFER (offscreen); if (!cogl_framebuffer_allocate (fb, &ignore_error)) { cogl_error_free (ignore_error); cogl_object_unref (fb); return FALSE; } data->dest_fb = fb; dst_width = cogl_texture_get_width (data->dst_tex); dst_height = cogl_texture_get_height (data->dst_tex); /* Set up an orthographic projection so we can use pixel coordinates to render to the texture */ cogl_framebuffer_orthographic (fb, 0, 0, dst_width, dst_height, -1 /* near */, 1 /* far */); /* We cache a pipeline used for migrating on to the context so that it doesn't have to continuously regenerate a shader program */ if (ctx->blit_texture_pipeline == NULL) { ctx->blit_texture_pipeline = cogl_pipeline_new (ctx); cogl_pipeline_set_layer_filters (ctx->blit_texture_pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); /* Disable blending by just directly taking the contents of the source texture */ cogl_pipeline_set_blend (ctx->blit_texture_pipeline, "RGBA = ADD(SRC_COLOR, 0)", NULL); } pipeline = ctx->blit_texture_pipeline; cogl_pipeline_set_layer_texture (pipeline, 0, data->src_tex); data->pipeline = pipeline; return TRUE; } static void _cogl_blit_texture_render_blit (CoglBlitData *data, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { cogl_framebuffer_draw_textured_rectangle (data->dest_fb, data->pipeline, dst_x, dst_y, dst_x + width, dst_y + height, src_x / (float) data->src_width, src_y / (float) data->src_height, (src_x + width) / (float) data->src_width, (src_y + height) / (float) data->src_height); } static void _cogl_blit_texture_render_end (CoglBlitData *data) { CoglContext *ctx = data->src_tex->context; /* Attach the target texture to the texture render pipeline so that we don't keep a reference to the source texture forever. This is assuming that the destination texture will live for a long time which is currently the case when cogl_blit_* is used from the atlas code. It may be better in future to keep around a set of dummy 1x1 textures for each texture target that we could bind instead. This would also be useful when using a pipeline as a hash table key such as for the ARBfp program cache. */ cogl_pipeline_set_layer_texture (ctx->blit_texture_pipeline, 0, data->dst_tex); cogl_object_unref (data->dest_fb); } static CoglBool _cogl_blit_framebuffer_begin (CoglBlitData *data) { CoglContext *ctx = data->src_tex->context; CoglOffscreen *dst_offscreen = NULL, *src_offscreen = NULL; CoglFramebuffer *dst_fb, *src_fb; CoglError *ignore_error = NULL; /* We can only blit between FBOs if both textures are the same format and the blit framebuffer extension is supported */ if ((_cogl_texture_get_format (data->src_tex) & ~COGL_A_BIT) != (_cogl_texture_get_format (data->dst_tex) & ~COGL_A_BIT) || !_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)) return FALSE; dst_offscreen = _cogl_offscreen_new_with_texture_full (data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); dst_fb = COGL_FRAMEBUFFER (dst_offscreen); if (!cogl_framebuffer_allocate (dst_fb, &ignore_error)) { cogl_error_free (ignore_error); goto error; } src_offscreen= _cogl_offscreen_new_with_texture_full (data->src_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); src_fb = COGL_FRAMEBUFFER (src_offscreen); if (!cogl_framebuffer_allocate (src_fb, &ignore_error)) { cogl_error_free (ignore_error); goto error; } data->src_fb = src_fb; data->dest_fb = dst_fb; return TRUE; error: if (dst_offscreen) cogl_object_unref (dst_offscreen); if (src_offscreen) cogl_object_unref (src_offscreen); return FALSE; } static void _cogl_blit_framebuffer_blit (CoglBlitData *data, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { _cogl_blit_framebuffer (data->src_fb, data->dest_fb, src_x, src_y, dst_x, dst_y, width, height); } static void _cogl_blit_framebuffer_end (CoglBlitData *data) { cogl_object_unref (data->src_fb); cogl_object_unref (data->dest_fb); } static CoglBool _cogl_blit_copy_tex_sub_image_begin (CoglBlitData *data) { CoglOffscreen *offscreen; CoglFramebuffer *fb; CoglError *ignore_error = NULL; /* This will only work if the target texture is a CoglTexture2D */ if (!cogl_is_texture_2d (data->dst_tex)) return FALSE; offscreen = _cogl_offscreen_new_with_texture_full (data->src_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); fb = COGL_FRAMEBUFFER (offscreen); if (!cogl_framebuffer_allocate (fb, &ignore_error)) { cogl_error_free (ignore_error); cogl_object_unref (fb); return FALSE; } data->src_fb = fb; return TRUE; } static void _cogl_blit_copy_tex_sub_image_blit (CoglBlitData *data, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { _cogl_texture_2d_copy_from_framebuffer (COGL_TEXTURE_2D (data->dst_tex), src_x, src_y, width, height, data->src_fb, dst_x, dst_y, 0); /* level */ } static void _cogl_blit_copy_tex_sub_image_end (CoglBlitData *data) { cogl_object_unref (data->src_fb); } static CoglBool _cogl_blit_get_tex_data_begin (CoglBlitData *data) { data->format = _cogl_texture_get_format (data->src_tex); data->bpp = _cogl_pixel_format_get_bytes_per_pixel (data->format); data->image_data = malloc (data->bpp * data->src_width * data->src_height); cogl_texture_get_data (data->src_tex, data->format, data->src_width * data->bpp, data->image_data); return TRUE; } static void _cogl_blit_get_tex_data_blit (CoglBlitData *data, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { CoglError *ignore = NULL; int rowstride = data->src_width * data->bpp; int offset = rowstride * src_y + src_x * data->bpp; _cogl_texture_set_region (data->dst_tex, width, height, data->format, rowstride, data->image_data + offset, dst_x, dst_y, 0, /* level */ &ignore); /* TODO: support chaining up errors during the blit */ } static void _cogl_blit_get_tex_data_end (CoglBlitData *data) { free (data->image_data); } /* These should be specified in order of preference */ static const CoglBlitMode _cogl_blit_modes[] = { { "texture-render", _cogl_blit_texture_render_begin, _cogl_blit_texture_render_blit, _cogl_blit_texture_render_end }, { "framebuffer", _cogl_blit_framebuffer_begin, _cogl_blit_framebuffer_blit, _cogl_blit_framebuffer_end }, { "copy-tex-sub-image", _cogl_blit_copy_tex_sub_image_begin, _cogl_blit_copy_tex_sub_image_blit, _cogl_blit_copy_tex_sub_image_end }, { "get-tex-data", _cogl_blit_get_tex_data_begin, _cogl_blit_get_tex_data_blit, _cogl_blit_get_tex_data_end } }; void _cogl_blit_begin (CoglBlitData *data, CoglTexture *dst_tex, CoglTexture *src_tex) { int i; if (_cogl_blit_default_mode == NULL) { const char *default_mode_string; /* Allow the default to be specified with an environment variable. For the time being these functions are only used when blitting between atlas textures so the environment variable is named to be specific to the atlas code. If we want to use the code in other places we should create another environment variable for each specific use case */ if ((default_mode_string = g_getenv ("COGL_ATLAS_DEFAULT_BLIT_MODE"))) { for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++) if (!strcmp (_cogl_blit_modes[i].name, default_mode_string)) { _cogl_blit_default_mode = _cogl_blit_modes + i; break; } if (i >= G_N_ELEMENTS (_cogl_blit_modes)) { g_warning ("Unknown blit mode %s", default_mode_string); _cogl_blit_default_mode = _cogl_blit_modes; } } else /* Default to the first blit mode */ _cogl_blit_default_mode = _cogl_blit_modes; } memset (data, 0, sizeof (CoglBlitData)); data->dst_tex = dst_tex; data->src_tex = src_tex; data->src_width = cogl_texture_get_width (src_tex); data->src_height = cogl_texture_get_height (src_tex); /* Try the default blit mode first */ if (!_cogl_blit_default_mode->begin_func (data)) { COGL_NOTE (ATLAS, "Failed to set up blit mode %s", _cogl_blit_default_mode->name); /* Try all of the other modes in order */ for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++) if (_cogl_blit_modes + i != _cogl_blit_default_mode && _cogl_blit_modes[i].begin_func (data)) { /* Use this mode as the default from now on */ _cogl_blit_default_mode = _cogl_blit_modes + i; break; } else COGL_NOTE (ATLAS, "Failed to set up blit mode %s", _cogl_blit_modes[i].name); /* The last blit mode can't fail so this should never happen */ _COGL_RETURN_IF_FAIL (i < G_N_ELEMENTS (_cogl_blit_modes)); } data->blit_mode = _cogl_blit_default_mode; COGL_NOTE (ATLAS, "Setup blit using %s", _cogl_blit_default_mode->name); } void _cogl_blit (CoglBlitData *data, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { data->blit_mode->blit_func (data, src_x, src_y, dst_x, dst_y, width, height); } void _cogl_blit_end (CoglBlitData *data) { data->blit_mode->end_func (data); } muffin-5.2.1/cogl/cogl/cogl-xlib-renderer.c0000664000175000017500000004630114211404421020640 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-xlib-renderer.h" #include "cogl-util.h" #include "cogl-object.h" #include "cogl-output-private.h" #include "cogl-renderer-private.h" #include "cogl-xlib-renderer-private.h" #include "cogl-x11-renderer-private.h" #include "cogl-winsys-private.h" #include "cogl-error-private.h" #include "cogl-poll-private.h" #include #include #include #include #include static char *_cogl_x11_display_name = NULL; static GList *_cogl_xlib_renderers = NULL; static void destroy_xlib_renderer_data (void *user_data) { CoglXlibRenderer *data = user_data; if (data->xvisinfo) XFree (data->xvisinfo); g_slice_free (CoglXlibRenderer, user_data); } CoglXlibRenderer * _cogl_xlib_renderer_get_data (CoglRenderer *renderer) { static CoglUserDataKey key; CoglXlibRenderer *data; /* Constructs a CoglXlibRenderer struct on demand and attaches it to the object using user data. It's done this way instead of using a subclassing hierarchy in the winsys data because all EGL winsys's need the EGL winsys data but only one of them wants the Xlib data. */ data = cogl_object_get_user_data (COGL_OBJECT (renderer), &key); if (data == NULL) { data = g_slice_new0 (CoglXlibRenderer); cogl_object_set_user_data (COGL_OBJECT (renderer), &key, data, destroy_xlib_renderer_data); } return data; } static void register_xlib_renderer (CoglRenderer *renderer) { GList *l; for (l = _cogl_xlib_renderers; l; l = l->next) if (l->data == renderer) return; _cogl_xlib_renderers = g_list_prepend (_cogl_xlib_renderers, renderer); } static void unregister_xlib_renderer (CoglRenderer *renderer) { _cogl_xlib_renderers = g_list_remove (_cogl_xlib_renderers, renderer); } static CoglRenderer * get_renderer_for_xdisplay (Display *xdpy) { GList *l; for (l = _cogl_xlib_renderers; l; l = l->next) { CoglRenderer *renderer = l->data; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); if (xlib_renderer->xdpy == xdpy) return renderer; } return NULL; } static int error_handler (Display *xdpy, XErrorEvent *error) { CoglRenderer *renderer; CoglXlibRenderer *xlib_renderer; renderer = get_renderer_for_xdisplay (xdpy); xlib_renderer = _cogl_xlib_renderer_get_data (renderer); g_assert (xlib_renderer->trap_state); xlib_renderer->trap_state->trapped_error_code = error->error_code; return 0; } void _cogl_xlib_renderer_trap_errors (CoglRenderer *renderer, CoglXlibTrapState *state) { CoglXlibRenderer *xlib_renderer; xlib_renderer = _cogl_xlib_renderer_get_data (renderer); state->trapped_error_code = 0; state->old_error_handler = XSetErrorHandler (error_handler); state->old_state = xlib_renderer->trap_state; xlib_renderer->trap_state = state; } int _cogl_xlib_renderer_untrap_errors (CoglRenderer *renderer, CoglXlibTrapState *state) { CoglXlibRenderer *xlib_renderer; xlib_renderer = _cogl_xlib_renderer_get_data (renderer); g_assert (state == xlib_renderer->trap_state); XSetErrorHandler (state->old_error_handler); xlib_renderer->trap_state = state->old_state; return state->trapped_error_code; } static Display * assert_xlib_display (CoglRenderer *renderer, CoglError **error) { Display *xdpy = cogl_xlib_renderer_get_foreign_display (renderer); CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); /* A foreign display may have already been set... */ if (xdpy) { xlib_renderer->xdpy = xdpy; return xdpy; } xdpy = XOpenDisplay (_cogl_x11_display_name); if (xdpy == NULL) { _cogl_set_error (error, COGL_RENDERER_ERROR, COGL_RENDERER_ERROR_XLIB_DISPLAY_OPEN, "Failed to open X Display %s", _cogl_x11_display_name); return NULL; } xlib_renderer->xdpy = xdpy; return xdpy; } static int compare_outputs (CoglOutput *a, CoglOutput *b) { return strcmp (a->name, b->name); } #define CSO(X) COGL_SUBPIXEL_ORDER_ ## X static CoglSubpixelOrder subpixel_map[6][6] = { { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_RGB), CSO(HORIZONTAL_BGR), CSO(VERTICAL_RGB), CSO(VERTICAL_BGR) }, /* 0 */ { CSO(UNKNOWN), CSO(NONE), CSO(VERTICAL_RGB), CSO(VERTICAL_BGR), CSO(HORIZONTAL_BGR), CSO(HORIZONTAL_RGB) }, /* 90 */ { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_BGR), CSO(HORIZONTAL_RGB), CSO(VERTICAL_BGR), CSO(VERTICAL_RGB) }, /* 180 */ { CSO(UNKNOWN), CSO(NONE), CSO(VERTICAL_BGR), CSO(VERTICAL_RGB), CSO(HORIZONTAL_RGB), CSO(HORIZONTAL_BGR) }, /* 270 */ { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_BGR), CSO(HORIZONTAL_RGB), CSO(VERTICAL_RGB), CSO(VERTICAL_BGR) }, /* Reflect_X */ { CSO(UNKNOWN), CSO(NONE), CSO(HORIZONTAL_RGB), CSO(HORIZONTAL_BGR), CSO(VERTICAL_BGR), CSO(VERTICAL_RGB) }, /* Reflect_Y */ }; #undef CSO static void update_outputs (CoglRenderer *renderer, CoglBool notify) { CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); XRRScreenResources *resources; CoglXlibTrapState state; CoglBool error = FALSE; GList *new_outputs = NULL; GList *l, *m; CoglBool changed = FALSE; int i; xlib_renderer->outputs_update_serial = XNextRequest (xlib_renderer->xdpy); resources = XRRGetScreenResources (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy)); _cogl_xlib_renderer_trap_errors (renderer, &state); for (i = 0; resources && i < resources->ncrtc && !error; i++) { XRRCrtcInfo *crtc_info = NULL; XRROutputInfo *output_info = NULL; CoglOutput *output; float refresh_rate = 0; int j; crtc_info = XRRGetCrtcInfo (xlib_renderer->xdpy, resources, resources->crtcs[i]); if (crtc_info == NULL) { error = TRUE; goto next; } if (crtc_info->mode == None) goto next; for (j = 0; j < resources->nmode; j++) { if (resources->modes[j].id == crtc_info->mode) refresh_rate = (resources->modes[j].dotClock / ((float)resources->modes[j].hTotal * resources->modes[j].vTotal)); } output_info = XRRGetOutputInfo (xlib_renderer->xdpy, resources, crtc_info->outputs[0]); if (output_info == NULL) { error = TRUE; goto next; } output = _cogl_output_new (output_info->name); output->x = crtc_info->x; output->y = crtc_info->y; output->width = crtc_info->width; output->height = crtc_info->height; if ((crtc_info->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0) { output->mm_width = output_info->mm_height; output->mm_height = output_info->mm_width; } else { output->mm_width = output_info->mm_width; output->mm_height = output_info->mm_height; } output->refresh_rate = refresh_rate; switch (output_info->subpixel_order) { case SubPixelUnknown: default: output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; break; case SubPixelNone: output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE; break; case SubPixelHorizontalRGB: output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB; break; case SubPixelHorizontalBGR: output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR; break; case SubPixelVerticalRGB: output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB; break; case SubPixelVerticalBGR: output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR; break; } output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB; /* Handle the effect of rotation and reflection on subpixel order (ugh) */ for (j = 0; j < 6; j++) { if ((crtc_info->rotation & (1 << j)) != 0) output->subpixel_order = subpixel_map[j][output->subpixel_order]; } new_outputs = g_list_prepend (new_outputs, output); next: if (crtc_info != NULL) XFree (crtc_info); if (output_info != NULL) XFree (output_info); } XFree (resources); if (!error) { new_outputs = g_list_sort (new_outputs, (GCompareFunc)compare_outputs); l = new_outputs; m = renderer->outputs; while (l || m) { int cmp; CoglOutput *output_l = l ? (CoglOutput *)l->data : NULL; CoglOutput *output_m = m ? (CoglOutput *)m->data : NULL; if (l && m) cmp = compare_outputs (output_l, output_m); else if (l) cmp = -1; else cmp = 1; if (cmp == 0) { GList *m_next = m->next; if (!_cogl_output_values_equal (output_l, output_m)) { renderer->outputs = g_list_remove_link (renderer->outputs, m); renderer->outputs = g_list_insert_before (renderer->outputs, m_next, output_l); cogl_object_ref (output_l); changed = TRUE; } l = l->next; m = m_next; } else if (cmp < 0) { renderer->outputs = g_list_insert_before (renderer->outputs, m, output_l); cogl_object_ref (output_l); changed = TRUE; l = l->next; } else { GList *m_next = m->next; renderer->outputs = g_list_remove_link (renderer->outputs, m); changed = TRUE; m = m_next; } } } g_list_free_full (new_outputs, (GDestroyNotify)cogl_object_unref); _cogl_xlib_renderer_untrap_errors (renderer, &state); if (changed) { const CoglWinsysVtable *winsys = renderer->winsys_vtable; if (notify) COGL_NOTE (WINSYS, "Outputs changed:"); else COGL_NOTE (WINSYS, "Outputs:"); for (l = renderer->outputs; l; l = l->next) { CoglOutput *output = l->data; const char *subpixel_string; switch (output->subpixel_order) { case COGL_SUBPIXEL_ORDER_UNKNOWN: default: subpixel_string = "unknown"; break; case COGL_SUBPIXEL_ORDER_NONE: subpixel_string = "none"; break; case COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB: subpixel_string = "horizontal_rgb"; break; case COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR: subpixel_string = "horizontal_bgr"; break; case COGL_SUBPIXEL_ORDER_VERTICAL_RGB: subpixel_string = "vertical_rgb"; break; case COGL_SUBPIXEL_ORDER_VERTICAL_BGR: subpixel_string = "vertical_bgr"; break; } COGL_NOTE (WINSYS, " %10s: +%d+%dx%dx%d mm=%dx%d dpi=%.1fx%.1f " "subpixel_order=%s refresh_rate=%.3f", output->name, output->x, output->y, output->width, output->height, output->mm_width, output->mm_height, output->width / (output->mm_width / 25.4), output->height / (output->mm_height / 25.4), subpixel_string, output->refresh_rate); } if (notify && winsys->renderer_outputs_changed != NULL) winsys->renderer_outputs_changed (renderer); } } static CoglFilterReturn randr_filter (XEvent *event, void *data) { CoglRenderer *renderer = data; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); CoglX11Renderer *x11_renderer = (CoglX11Renderer *) xlib_renderer; if (x11_renderer->randr_base != -1 && (event->xany.type == x11_renderer->randr_base + RRScreenChangeNotify || event->xany.type == x11_renderer->randr_base + RRNotify) && event->xany.serial >= xlib_renderer->outputs_update_serial) update_outputs (renderer, TRUE); return COGL_FILTER_CONTINUE; } static int64_t prepare_xlib_events_timeout (void *user_data) { CoglRenderer *renderer = user_data; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); return XPending (xlib_renderer->xdpy) ? 0 : -1; } static void dispatch_xlib_events (void *user_data, int revents) { CoglRenderer *renderer = user_data; CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); if (renderer->xlib_enable_event_retrieval) while (XPending (xlib_renderer->xdpy)) { XEvent xevent; XNextEvent (xlib_renderer->xdpy, &xevent); cogl_xlib_renderer_handle_event (renderer, &xevent); } } CoglBool _cogl_xlib_renderer_connect (CoglRenderer *renderer, CoglError **error) { CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); CoglX11Renderer *x11_renderer = (CoglX11Renderer *) xlib_renderer; int damage_error; int randr_error; if (!assert_xlib_display (renderer, error)) return FALSE; if (getenv ("COGL_X11_SYNC")) XSynchronize (xlib_renderer->xdpy, TRUE); /* Check whether damage events are supported on this display */ if (!XDamageQueryExtension (xlib_renderer->xdpy, &x11_renderer->damage_base, &damage_error)) x11_renderer->damage_base = -1; /* Check whether randr is supported on this display */ if (!XRRQueryExtension (xlib_renderer->xdpy, &x11_renderer->randr_base, &randr_error)) x11_renderer->randr_base = -1; xlib_renderer->trap_state = NULL; if (renderer->xlib_enable_event_retrieval) { _cogl_poll_renderer_add_fd (renderer, ConnectionNumber (xlib_renderer->xdpy), COGL_POLL_FD_EVENT_IN, prepare_xlib_events_timeout, dispatch_xlib_events, renderer); } XRRSelectInput(xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputPropertyNotifyMask); update_outputs (renderer, FALSE); register_xlib_renderer (renderer); cogl_xlib_renderer_add_filter (renderer, randr_filter, renderer); return TRUE; } void _cogl_xlib_renderer_disconnect (CoglRenderer *renderer) { CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); g_list_free_full (renderer->outputs, (GDestroyNotify)cogl_object_unref); renderer->outputs = NULL; if (!renderer->foreign_xdpy && xlib_renderer->xdpy) XCloseDisplay (xlib_renderer->xdpy); unregister_xlib_renderer (renderer); } Display * cogl_xlib_renderer_get_display (CoglRenderer *renderer) { CoglXlibRenderer *xlib_renderer; _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL); xlib_renderer = _cogl_xlib_renderer_get_data (renderer); return xlib_renderer->xdpy; } CoglFilterReturn cogl_xlib_renderer_handle_event (CoglRenderer *renderer, XEvent *event) { return _cogl_renderer_handle_native_event (renderer, event); } void cogl_xlib_renderer_add_filter (CoglRenderer *renderer, CoglXlibFilterFunc func, void *data) { _cogl_renderer_add_native_filter (renderer, (CoglNativeFilterFunc)func, data); } void cogl_xlib_renderer_remove_filter (CoglRenderer *renderer, CoglXlibFilterFunc func, void *data) { _cogl_renderer_remove_native_filter (renderer, (CoglNativeFilterFunc)func, data); } int64_t _cogl_xlib_renderer_get_dispatch_timeout (CoglRenderer *renderer) { CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); if (renderer->xlib_enable_event_retrieval) { if (XPending (xlib_renderer->xdpy)) return 0; else return -1; } else return -1; } CoglOutput * _cogl_xlib_renderer_output_for_rectangle (CoglRenderer *renderer, int x, int y, int width, int height) { int max_overlap = 0; CoglOutput *max_overlapped = NULL; GList *l; int xa1 = x, xa2 = x + width; int ya1 = y, ya2 = y + height; for (l = renderer->outputs; l; l = l->next) { CoglOutput *output = l->data; int xb1 = output->x, xb2 = output->x + output->width; int yb1 = output->y, yb2 = output->y + output->height; int overlap_x = MIN(xa2, xb2) - MAX(xa1, xb1); int overlap_y = MIN(ya2, yb2) - MAX(ya1, yb1); if (overlap_x > 0 && overlap_y > 0) { int overlap = overlap_x * overlap_y; if (overlap > max_overlap) { max_overlap = overlap; max_overlapped = output; } } } return max_overlapped; } XVisualInfo * cogl_xlib_renderer_get_visual_info (CoglRenderer *renderer) { CoglXlibRenderer *xlib_renderer; _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL); xlib_renderer = _cogl_xlib_renderer_get_data (renderer); return xlib_renderer->xvisinfo; } muffin-5.2.1/cogl/cogl/cogl-frame-info-private.h0000664000175000017500000000307414211404421021576 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_FRAME_INFO_PRIVATE_H #define __COGL_FRAME_INFO_PRIVATE_H #include "cogl-frame-info.h" #include "cogl-object-private.h" struct _CoglFrameInfo { CoglObject _parent; int64_t frame_counter; int64_t presentation_time; float refresh_rate; int64_t global_frame_counter; CoglOutput *output; }; CoglFrameInfo *_cogl_frame_info_new (void); #endif /* __COGL_FRAME_INFO_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-gpu-info.c0000664000175000017500000003643014211404421017624 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include "cogl-gpu-info-private.h" #include "cogl-context-private.h" #include "cogl-version.h" typedef struct { const char *renderer_string; const char *version_string; const char *vendor_string; } CoglGpuInfoStrings; typedef struct CoglGpuInfoArchitectureDescription { CoglGpuInfoArchitecture architecture; const char *name; CoglGpuInfoArchitectureFlag flags; CoglBool (* check_function) (const CoglGpuInfoStrings *strings); } CoglGpuInfoArchitectureDescription; typedef struct { CoglGpuInfoVendor vendor; const char *name; CoglBool (* check_function) (const CoglGpuInfoStrings *strings); const CoglGpuInfoArchitectureDescription *architectures; } CoglGpuInfoVendorDescription; typedef struct { CoglGpuInfoDriverPackage driver_package; const char *name; CoglBool (* check_function) (const CoglGpuInfoStrings *strings, int *version_out); } CoglGpuInfoDriverPackageDescription; static CoglBool _cogl_gpu_info_parse_version_string (const char *version_string, int n_components, const char **tail, int *version_ret) { int version = 0; uint64_t part; int i; for (i = 0; ; i++) { errno = 0; part = g_ascii_strtoull (version_string, (char **) &version_string, 10); if (errno || part > COGL_VERSION_MAX_COMPONENT_VALUE) return FALSE; version |= part << ((2 - i) * COGL_VERSION_COMPONENT_BITS); if (i + 1 >= n_components) break; if (*version_string != '.') return FALSE; version_string++; } if (version_ret) *version_ret = version; if (tail) *tail = version_string; return TRUE; } static CoglBool match_phrase (const char *string, const char *phrase) { const char *part = strstr (string, phrase); int len; if (part == NULL) return FALSE; /* The match must either be at the beginning of the string or preceded by a space. */ if (part > string && part[-1] != ' ') return FALSE; /* Also match must either be at end of string or followed by a * space. */ len = strlen (phrase); if (part[len] != '\0' && part[len] != ' ') return FALSE; return TRUE; } static CoglBool check_intel_vendor (const CoglGpuInfoStrings *strings) { return match_phrase (strings->renderer_string, "Intel(R)"); } static CoglBool check_imagination_technologies_vendor (const CoglGpuInfoStrings *strings) { if (strcmp (strings->vendor_string, "Imagination Technologies") != 0) return FALSE; return TRUE; } static CoglBool check_arm_vendor (const CoglGpuInfoStrings *strings) { if (strcmp (strings->vendor_string, "ARM") != 0) return FALSE; return TRUE; } static CoglBool check_qualcomm_vendor (const CoglGpuInfoStrings *strings) { if (strcmp (strings->vendor_string, "Qualcomm") != 0) return FALSE; return TRUE; } static CoglBool check_nvidia_vendor (const CoglGpuInfoStrings *strings) { if (strcmp (strings->vendor_string, "NVIDIA") != 0 && strcmp (strings->vendor_string, "NVIDIA Corporation") != 0) return FALSE; return TRUE; } static CoglBool check_ati_vendor (const CoglGpuInfoStrings *strings) { if (strcmp (strings->vendor_string, "ATI") != 0) return FALSE; return TRUE; } static CoglBool check_mesa_vendor (const CoglGpuInfoStrings *strings) { if (strcmp (strings->vendor_string, "Tungsten Graphics, Inc") == 0) return TRUE; else if (strcmp (strings->vendor_string, "VMware, Inc.") == 0) return TRUE; else if (strcmp (strings->vendor_string, "Mesa Project") == 0) return TRUE; return FALSE; } static CoglBool check_true (const CoglGpuInfoStrings *strings) { /* This is a last resort so it always matches */ return TRUE; } static CoglBool check_sandybridge_architecture (const CoglGpuInfoStrings *strings) { return match_phrase (strings->renderer_string, "Sandybridge"); } static CoglBool check_llvmpipe_architecture (const CoglGpuInfoStrings *strings) { return match_phrase (strings->renderer_string, "llvmpipe"); } static CoglBool check_softpipe_architecture (const CoglGpuInfoStrings *strings) { return match_phrase (strings->renderer_string, "softpipe"); } static CoglBool check_swrast_architecture (const CoglGpuInfoStrings *strings) { return match_phrase (strings->renderer_string, "software rasterizer") || match_phrase (strings->renderer_string, "Software Rasterizer"); } static CoglBool check_sgx_architecture (const CoglGpuInfoStrings *strings) { if (strncmp (strings->renderer_string, "PowerVR SGX", 12) != 0) return FALSE; return TRUE; } static CoglBool check_mali_architecture (const CoglGpuInfoStrings *strings) { if (strncmp (strings->renderer_string, "Mali-", 5) != 0) return FALSE; return TRUE; } static const CoglGpuInfoArchitectureDescription intel_architectures[] = { { COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE, "Sandybridge", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE, check_sandybridge_architecture }, { COGL_GPU_INFO_ARCHITECTURE_UNKNOWN, "Unknown", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE, check_true } }; static const CoglGpuInfoArchitectureDescription powervr_architectures[] = { { COGL_GPU_INFO_ARCHITECTURE_SGX, "SGX", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_TILED | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_DEFERRED, check_sgx_architecture }, { COGL_GPU_INFO_ARCHITECTURE_UNKNOWN, "Unknown", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_TILED | COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_TILED, check_true } }; static const CoglGpuInfoArchitectureDescription arm_architectures[] = { { COGL_GPU_INFO_ARCHITECTURE_MALI, "Mali", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_TILED | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE, check_mali_architecture }, { COGL_GPU_INFO_ARCHITECTURE_UNKNOWN, "Unknown", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_TILED | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE, check_true } }; static const CoglGpuInfoArchitectureDescription mesa_architectures[] = { { COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE, "LLVM Pipe", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_SOFTWARE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_SOFTWARE, check_llvmpipe_architecture }, { COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE, "Softpipe", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_SOFTWARE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_SOFTWARE, check_softpipe_architecture }, { COGL_GPU_INFO_ARCHITECTURE_SWRAST, "SWRast", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_SOFTWARE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_SOFTWARE, check_swrast_architecture }, { COGL_GPU_INFO_ARCHITECTURE_UNKNOWN, "Unknown", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE, check_true } }; static const CoglGpuInfoArchitectureDescription unknown_architectures[] = { { COGL_GPU_INFO_ARCHITECTURE_UNKNOWN, "Unknown", COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE | COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE, check_true } }; static const CoglGpuInfoVendorDescription _cogl_gpu_info_vendors[] = { { COGL_GPU_INFO_VENDOR_INTEL, "Intel", check_intel_vendor, intel_architectures }, { COGL_GPU_INFO_VENDOR_IMAGINATION_TECHNOLOGIES, "Imagination Technologies", check_imagination_technologies_vendor, powervr_architectures }, { COGL_GPU_INFO_VENDOR_ARM, "ARM", check_arm_vendor, arm_architectures }, { COGL_GPU_INFO_VENDOR_QUALCOMM, "Qualcomm", check_qualcomm_vendor, unknown_architectures }, { COGL_GPU_INFO_VENDOR_NVIDIA, "Nvidia", check_nvidia_vendor, unknown_architectures }, { COGL_GPU_INFO_VENDOR_ATI, "ATI", check_ati_vendor, unknown_architectures }, /* Must be last */ { COGL_GPU_INFO_VENDOR_MESA, "Mesa", check_mesa_vendor, mesa_architectures }, { COGL_GPU_INFO_VENDOR_UNKNOWN, "Unknown", check_true, unknown_architectures } }; static CoglBool check_mesa_driver_package (const CoglGpuInfoStrings *strings, int *version_ret) { uint64_t micro_part; const char *v; /* The version string should always begin a two-part GL version number */ if (!_cogl_gpu_info_parse_version_string (strings->version_string, 2, /* n_components */ &v, /* tail */ NULL /* version_ret */)) return FALSE; /* In mesa this will be followed optionally by "(Core Profile)" and * then "Mesa" */ v = strstr (v, " Mesa "); if (!v) return FALSE; v += 6; /* Next there will be a version string that is at least two components. On a git devel build the version will be something like "-devel" instead */ if (!_cogl_gpu_info_parse_version_string (v, 2, /* n_components */ &v, /* tail */ version_ret)) return FALSE; /* If it is a development build then we'll just leave the micro number as 0 */ if (g_str_has_prefix (v, "-devel")) return TRUE; /* Otherwise there should be a micro version number */ if (*v != '.') return FALSE; errno = 0; micro_part = g_ascii_strtoull (v + 1, NULL /* endptr */, 10 /* base */); if (errno || micro_part > COGL_VERSION_MAX_COMPONENT_VALUE) return FALSE; *version_ret = COGL_VERSION_ENCODE (COGL_VERSION_GET_MAJOR (*version_ret), COGL_VERSION_GET_MINOR (*version_ret), micro_part); return TRUE; } UNIT_TEST (check_mesa_driver_package_parser, 0, /* no requirements */ 0 /* no failure cases */) { /* renderer_string, version_string, vendor_string;*/ const CoglGpuInfoStrings test_strings[2] = { { NULL, "3.1 Mesa 9.2-devel15436ad", NULL }, { NULL, "3.1 (Core Profile) Mesa 9.2.0-devel (git-15436ad)", NULL } }; int i; int version; for (i = 0; i < G_N_ELEMENTS (test_strings); i++) { g_assert (check_mesa_driver_package (&test_strings[i], &version)); g_assert_cmpint (version, ==, COGL_VERSION_ENCODE (9, 2, 0)); } } static CoglBool check_unknown_driver_package (const CoglGpuInfoStrings *strings, int *version_out) { *version_out = 0; /* This is a last resort so it always matches */ return TRUE; } static const CoglGpuInfoDriverPackageDescription _cogl_gpu_info_driver_packages[] = { { COGL_GPU_INFO_DRIVER_PACKAGE_MESA, "Mesa", check_mesa_driver_package }, /* Must be last */ { COGL_GPU_INFO_DRIVER_PACKAGE_UNKNOWN, "Unknown", check_unknown_driver_package } }; void _cogl_gpu_info_init (CoglContext *ctx, CoglGpuInfo *gpu) { CoglGpuInfoStrings strings; int i; strings.renderer_string = (const char *) ctx->glGetString (GL_RENDERER); strings.version_string = _cogl_context_get_gl_version (ctx); strings.vendor_string = (const char *) ctx->glGetString (GL_VENDOR); /* Determine the driver package */ for (i = 0; ; i++) { const CoglGpuInfoDriverPackageDescription *description = _cogl_gpu_info_driver_packages + i; if (description->check_function (&strings, &gpu->driver_package_version)) { gpu->driver_package = description->driver_package; gpu->driver_package_name = description->name; break; } } /* Determine the GPU vendor */ for (i = 0; ; i++) { const CoglGpuInfoVendorDescription *description = _cogl_gpu_info_vendors + i; if (description->check_function (&strings)) { int j; gpu->vendor = description->vendor; gpu->vendor_name = description->name; for (j = 0; ; j++) { const CoglGpuInfoArchitectureDescription *architecture = description->architectures + j; if (architecture->check_function (&strings)) { gpu->architecture = architecture->architecture; gpu->architecture_name = architecture->name; gpu->architecture_flags = architecture->flags; goto probed; } } } } probed: COGL_NOTE (WINSYS, "Driver package = %s, vendor = %s, architecture = %s\n", gpu->driver_package_name, gpu->vendor_name, gpu->architecture_name); /* Determine the driver bugs */ /* In Mesa the glReadPixels implementation is really slow when using the Intel driver. The Intel driver has a fast blit path when reading into a PBO. Reading into a temporary PBO and then memcpying back out to the application's memory is faster than a regular glReadPixels in this case */ if (gpu->vendor == COGL_GPU_INFO_VENDOR_INTEL && gpu->driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA) gpu->driver_bugs |= COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS; } muffin-5.2.1/cogl/cogl/cogl-attribute.c0000664000175000017500000005431214211404421020102 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-journal-private.h" #include "cogl-attribute.h" #include "cogl-attribute-private.h" #include "cogl-pipeline.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-texture-private.h" #include "cogl-framebuffer-private.h" #include "cogl-indices-private.h" #ifdef COGL_PIPELINE_PROGEND_GLSL #include "cogl-pipeline-progend-glsl-private.h" #endif #include "cogl-private.h" #include "cogl-gtype-private.h" #include #include #include /* This isn't defined in the GLES headers */ #ifndef GL_UNSIGNED_INT #define GL_UNSIGNED_INT 0x1405 #endif static void _cogl_attribute_free (CoglAttribute *attribute); COGL_OBJECT_DEFINE (Attribute, attribute); COGL_GTYPE_DEFINE_CLASS (Attribute, attribute); static CoglBool validate_cogl_attribute_name (const char *name, char **real_attribute_name, CoglAttributeNameID *name_id, CoglBool *normalized, int *layer_number) { name = name + 5; /* skip "cogl_" */ *normalized = FALSE; *layer_number = 0; if (strcmp (name, "position_in") == 0) *name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY; else if (strcmp (name, "color_in") == 0) { *name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY; *normalized = TRUE; } else if (strcmp (name, "tex_coord_in") == 0) { *real_attribute_name = "cogl_tex_coord0_in"; *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY; } else if (strncmp (name, "tex_coord", strlen ("tex_coord")) == 0) { char *endptr; *layer_number = strtoul (name + 9, &endptr, 10); if (strcmp (endptr, "_in") != 0) { g_warning ("Texture coordinate attributes should either be named " "\"cogl_tex_coord_in\" or named with a texture unit index " "like \"cogl_tex_coord2_in\"\n"); return FALSE; } *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY; } else if (strcmp (name, "normal_in") == 0) { *name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY; *normalized = TRUE; } else if (strcmp (name, "point_size_in") == 0) *name_id = COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY; else { g_warning ("Unknown cogl_* attribute name cogl_%s\n", name); return FALSE; } return TRUE; } CoglAttributeNameState * _cogl_attribute_register_attribute_name (CoglContext *context, const char *name) { CoglAttributeNameState *name_state = g_new (CoglAttributeNameState, 1); int name_index = context->n_attribute_names++; char *name_copy = g_strdup (name); name_state->name = NULL; name_state->name_index = name_index; if (strncmp (name, "cogl_", 5) == 0) { if (!validate_cogl_attribute_name (name, &name_state->name, &name_state->name_id, &name_state->normalized_default, &name_state->layer_number)) goto error; } else { name_state->name_id = COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY; name_state->normalized_default = FALSE; name_state->layer_number = 0; } if (name_state->name == NULL) name_state->name = name_copy; g_hash_table_insert (context->attribute_name_states_hash, name_copy, name_state); if (G_UNLIKELY (context->attribute_name_index_map == NULL)) context->attribute_name_index_map = g_array_new (FALSE, FALSE, sizeof (void *)); g_array_set_size (context->attribute_name_index_map, name_index + 1); g_array_index (context->attribute_name_index_map, CoglAttributeNameState *, name_index) = name_state; return name_state; error: free (name_state); return NULL; } static CoglBool validate_n_components (const CoglAttributeNameState *name_state, int n_components) { switch (name_state->name_id) { case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY: if (G_UNLIKELY (n_components == 1)) { g_critical ("glVertexPointer doesn't allow 1 component vertex " "positions so we currently only support \"cogl_vertex\" " "attributes where n_components == 2, 3 or 4"); return FALSE; } break; case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: if (G_UNLIKELY (n_components != 3 && n_components != 4)) { g_critical ("glColorPointer expects 3 or 4 component colors so we " "currently only support \"cogl_color\" attributes where " "n_components == 3 or 4"); return FALSE; } break; case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY: break; case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY: if (G_UNLIKELY (n_components != 3)) { g_critical ("glNormalPointer expects 3 component normals so we " "currently only support \"cogl_normal\" attributes " "where n_components == 3"); return FALSE; } break; case COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY: if (G_UNLIKELY (n_components != 1)) { g_critical ("The point size attribute can only have one " "component"); return FALSE; } break; case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY: return TRUE; } return TRUE; } CoglAttribute * cogl_attribute_new (CoglAttributeBuffer *attribute_buffer, const char *name, size_t stride, size_t offset, int n_components, CoglAttributeType type) { CoglAttribute *attribute = g_slice_new (CoglAttribute); CoglBuffer *buffer = COGL_BUFFER (attribute_buffer); CoglContext *ctx = buffer->context; attribute->is_buffered = TRUE; attribute->name_state = g_hash_table_lookup (ctx->attribute_name_states_hash, name); if (!attribute->name_state) { CoglAttributeNameState *name_state = _cogl_attribute_register_attribute_name (ctx, name); if (!name_state) goto error; attribute->name_state = name_state; } attribute->d.buffered.attribute_buffer = cogl_object_ref (attribute_buffer); attribute->d.buffered.stride = stride; attribute->d.buffered.offset = offset; attribute->d.buffered.n_components = n_components; attribute->d.buffered.type = type; attribute->immutable_ref = 0; if (attribute->name_state->name_id != COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY) { if (!validate_n_components (attribute->name_state, n_components)) return NULL; attribute->normalized = attribute->name_state->normalized_default; } else attribute->normalized = FALSE; return _cogl_attribute_object_new (attribute); error: _cogl_attribute_free (attribute); return NULL; } static CoglAttribute * _cogl_attribute_new_const (CoglContext *context, const char *name, int n_components, int n_columns, CoglBool transpose, const float *value) { CoglAttribute *attribute = g_slice_new (CoglAttribute); attribute->name_state = g_hash_table_lookup (context->attribute_name_states_hash, name); if (!attribute->name_state) { CoglAttributeNameState *name_state = _cogl_attribute_register_attribute_name (context, name); if (!name_state) goto error; attribute->name_state = name_state; } if (!validate_n_components (attribute->name_state, n_components)) goto error; attribute->is_buffered = FALSE; attribute->normalized = FALSE; attribute->d.constant.context = cogl_object_ref (context); attribute->d.constant.boxed.v.array = NULL; if (n_columns == 1) { _cogl_boxed_value_set_float (&attribute->d.constant.boxed, n_components, 1, value); } else { /* FIXME: Up until GL[ES] 3 only square matrices were supported * and we don't currently expose non-square matrices in Cogl. */ _COGL_RETURN_VAL_IF_FAIL (n_columns == n_components, NULL); _cogl_boxed_value_set_matrix (&attribute->d.constant.boxed, n_columns, 1, transpose, value); } return _cogl_attribute_object_new (attribute); error: _cogl_attribute_free (attribute); return NULL; } CoglAttribute * cogl_attribute_new_const_1f (CoglContext *context, const char *name, float value) { return _cogl_attribute_new_const (context, name, 1, /* n_components */ 1, /* 1 column vector */ FALSE, /* no transpose */ &value); } CoglAttribute * cogl_attribute_new_const_2fv (CoglContext *context, const char *name, const float *value) { return _cogl_attribute_new_const (context, name, 2, /* n_components */ 1, /* 1 column vector */ FALSE, /* no transpose */ value); } CoglAttribute * cogl_attribute_new_const_3fv (CoglContext *context, const char *name, const float *value) { return _cogl_attribute_new_const (context, name, 3, /* n_components */ 1, /* 1 column vector */ FALSE, /* no transpose */ value); } CoglAttribute * cogl_attribute_new_const_4fv (CoglContext *context, const char *name, const float *value) { return _cogl_attribute_new_const (context, name, 4, /* n_components */ 1, /* 1 column vector */ FALSE, /* no transpose */ value); } CoglAttribute * cogl_attribute_new_const_2f (CoglContext *context, const char *name, float component0, float component1) { float vec2[2] = { component0, component1 }; return _cogl_attribute_new_const (context, name, 2, /* n_components */ 1, /* 1 column vector */ FALSE, /* no transpose */ vec2); } CoglAttribute * cogl_attribute_new_const_3f (CoglContext *context, const char *name, float component0, float component1, float component2) { float vec3[3] = { component0, component1, component2 }; return _cogl_attribute_new_const (context, name, 3, /* n_components */ 1, /* 1 column vector */ FALSE, /* no transpose */ vec3); } CoglAttribute * cogl_attribute_new_const_4f (CoglContext *context, const char *name, float component0, float component1, float component2, float component3) { float vec4[4] = { component0, component1, component2, component3 }; return _cogl_attribute_new_const (context, name, 4, /* n_components */ 1, /* 1 column vector */ FALSE, /* no transpose */ vec4); } CoglAttribute * cogl_attribute_new_const_2x2fv (CoglContext *context, const char *name, const float *matrix2x2, CoglBool transpose) { return _cogl_attribute_new_const (context, name, 2, /* n_components */ 2, /* 2 column vector */ FALSE, /* no transpose */ matrix2x2); } CoglAttribute * cogl_attribute_new_const_3x3fv (CoglContext *context, const char *name, const float *matrix3x3, CoglBool transpose) { return _cogl_attribute_new_const (context, name, 3, /* n_components */ 3, /* 3 column vector */ FALSE, /* no transpose */ matrix3x3); } CoglAttribute * cogl_attribute_new_const_4x4fv (CoglContext *context, const char *name, const float *matrix4x4, CoglBool transpose) { return _cogl_attribute_new_const (context, name, 4, /* n_components */ 4, /* 4 column vector */ FALSE, /* no transpose */ matrix4x4); } CoglBool cogl_attribute_get_normalized (CoglAttribute *attribute) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), FALSE); return attribute->normalized; } static void warn_about_midscene_changes (void) { static CoglBool seen = FALSE; if (!seen) { g_warning ("Mid-scene modification of attributes has " "undefined results\n"); seen = TRUE; } } void cogl_attribute_set_normalized (CoglAttribute *attribute, CoglBool normalized) { _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute)); if (G_UNLIKELY (attribute->immutable_ref)) warn_about_midscene_changes (); attribute->normalized = normalized; } CoglAttributeBuffer * cogl_attribute_get_buffer (CoglAttribute *attribute) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL); _COGL_RETURN_VAL_IF_FAIL (attribute->is_buffered, NULL); return attribute->d.buffered.attribute_buffer; } void cogl_attribute_set_buffer (CoglAttribute *attribute, CoglAttributeBuffer *attribute_buffer) { _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute)); _COGL_RETURN_IF_FAIL (attribute->is_buffered); if (G_UNLIKELY (attribute->immutable_ref)) warn_about_midscene_changes (); cogl_object_ref (attribute_buffer); cogl_object_unref (attribute->d.buffered.attribute_buffer); attribute->d.buffered.attribute_buffer = attribute_buffer; } CoglAttribute * _cogl_attribute_immutable_ref (CoglAttribute *attribute) { CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer); _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL); attribute->immutable_ref++; _cogl_buffer_immutable_ref (buffer); return attribute; } void _cogl_attribute_immutable_unref (CoglAttribute *attribute) { CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer); _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute)); _COGL_RETURN_IF_FAIL (attribute->immutable_ref > 0); attribute->immutable_ref--; _cogl_buffer_immutable_unref (buffer); } static void _cogl_attribute_free (CoglAttribute *attribute) { if (attribute->is_buffered) cogl_object_unref (attribute->d.buffered.attribute_buffer); else _cogl_boxed_value_destroy (&attribute->d.constant.boxed); g_slice_free (CoglAttribute, attribute); } static CoglBool validate_layer_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { CoglTexture *texture = cogl_pipeline_get_layer_texture (pipeline, layer_index); CoglFlushLayerState *state = user_data; CoglBool status = TRUE; /* invalid textures will be handled correctly in * _cogl_pipeline_flush_layers_gl_state */ if (texture == NULL) goto validated; _cogl_texture_flush_journal_rendering (texture); /* Give the texture a chance to know that we're rendering non-quad shaped primitives. If the texture is in an atlas it will be migrated */ _cogl_texture_ensure_non_quad_rendering (texture); /* We need to ensure the mipmaps are ready before deciding * anything else about the texture because the texture storate * could completely change if it needs to be migrated out of the * atlas and will affect how we validate the layer. */ _cogl_pipeline_pre_paint_for_layer (pipeline, layer_index); if (!_cogl_texture_can_hardware_repeat (texture)) { g_warning ("Disabling layer %d of the current source material, " "because texturing with the vertex buffer API is not " "currently supported using sliced textures, or textures " "with waste\n", layer_index); /* XXX: maybe we can add a mechanism for users to forcibly use * textures with waste where it would be their responsability to use * texture coords in the range [0,1] such that sampling outside isn't * required. We can then use a texture matrix (or a modification of * the users own matrix) to map 1 to the edge of the texture data. * * Potentially, given the same guarantee as above we could also * support a single sliced layer too. We would have to redraw the * vertices once for each layer, each time with a fiddled texture * matrix. */ state->fallback_layers |= (1 << state->unit); state->options.flags |= COGL_PIPELINE_FLUSH_FALLBACK_MASK; } validated: state->unit++; return status; } void _cogl_flush_attributes_state (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes) { CoglContext *ctx = framebuffer->context; CoglFlushLayerState layers_state; CoglPipeline *copy = NULL; if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH)) _cogl_journal_flush (framebuffer->journal); layers_state.unit = 0; layers_state.options.flags = 0; layers_state.fallback_layers = 0; if (!(flags & COGL_DRAW_SKIP_PIPELINE_VALIDATION)) cogl_pipeline_foreach_layer (pipeline, validate_layer_cb, &layers_state); /* NB: _cogl_framebuffer_flush_state may disrupt various state (such * as the pipeline state) when flushing the clip stack, so should * always be done first when preparing to draw. We need to do this * before setting up the array pointers because setting up the clip * stack can cause some drawing which would change the array * pointers. */ if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH)) _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_ALL); /* In cogl_read_pixels we have a fast-path when reading a single * pixel and the scene is just comprised of simple rectangles still * in the journal. For this optimization to work we need to track * when the framebuffer really does get drawn to. */ _cogl_framebuffer_mark_mid_scene (framebuffer); _cogl_framebuffer_mark_clear_clip_dirty (framebuffer); if (G_UNLIKELY (!(flags & COGL_DRAW_SKIP_LEGACY_STATE)) && G_UNLIKELY (ctx->legacy_state_set) && _cogl_get_enable_legacy_state ()) { copy = cogl_pipeline_copy (pipeline); pipeline = copy; _cogl_pipeline_apply_legacy_state (pipeline); } ctx->driver_vtable->flush_attributes_state (framebuffer, pipeline, &layers_state, flags, attributes, n_attributes); if (copy) cogl_object_unref (copy); } int _cogl_attribute_get_n_components (CoglAttribute *attribute) { if (attribute->is_buffered) return attribute->d.buffered.n_components; else return attribute->d.constant.boxed.size; } muffin-5.2.1/cogl/cogl/cogl-gtype-private.h0000664000175000017500000003534514211404421020711 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_GTYPE_PRIVATE_H__ #define __COGL_GTYPE_PRIVATE_H__ #include "cogl-config.h" #include #include #include "cogl-object-private.h" /* Move this to public headers? */ typedef struct _CoglGtypeObject CoglGtypeObject; typedef struct _CoglGtypeClass CoglGtypeClass; struct _CoglGtypeObject { GTypeInstance parent_instance; guint dummy; }; struct _CoglGtypeClass { GTypeClass base_class; guint dummy; }; #define I_(str) (g_intern_static_string ((str))) /**/ #define COGL_GTYPE_DEFINE_BOXED(Name,underscore_name,copy_func,free_func) \ GType \ cogl_##underscore_name##_get_gtype (void) \ { \ static volatile size_t type_volatile = 0; \ if (g_once_init_enter (&type_volatile)) \ { \ GType type = \ g_boxed_type_register_static (g_intern_static_string (I_("Cogl" # Name)), \ (GBoxedCopyFunc)copy_func, \ (GBoxedFreeFunc)free_func); \ g_once_init_leave (&type_volatile, type); \ } \ return type_volatile; \ } #define COGL_GTYPE_IMPLEMENT_INTERFACE(name) { \ const GInterfaceInfo g_implement_interface_info = { \ (GInterfaceInitFunc) _cogl_gtype_dummy_iface_init, NULL, NULL \ }; \ g_type_add_interface_static (fundamental_type_id, \ cogl_##name##_get_gtype(), \ &g_implement_interface_info); \ } #define _COGL_GTYPE_DEFINE_BASE_CLASS_BEGIN(Name,name) \ GType \ cogl_##name##_get_gtype (void) \ { \ static volatile gsize type_id__volatile = 0; \ if (g_once_init_enter (&type_id__volatile)) \ { \ static const GTypeFundamentalInfo finfo = { \ (G_TYPE_FLAG_CLASSED | \ G_TYPE_FLAG_INSTANTIATABLE | \ G_TYPE_FLAG_DERIVABLE | \ G_TYPE_FLAG_DEEP_DERIVABLE), \ }; \ static const GTypeValueTable value_table = { \ _cogl_gtype_object_init_value, \ _cogl_gtype_object_free_value, \ _cogl_gtype_object_copy_value, \ _cogl_gtype_object_peek_pointer, \ "p", \ _cogl_gtype_object_collect_value, \ "p", \ _cogl_gtype_object_lcopy_value, \ }; \ const GTypeInfo node_info = { \ sizeof (CoglObjectClass), \ (GBaseInitFunc) _cogl_gtype_object_class_base_init, \ (GBaseFinalizeFunc) _cogl_gtype_object_class_base_finalize, \ (GClassInitFunc) _cogl_gtype_object_class_init, \ (GClassFinalizeFunc) NULL, \ NULL, \ sizeof (CoglObject), \ 0, \ (GInstanceInitFunc) _cogl_gtype_object_init, \ &value_table, \ }; \ GType fundamental_type_id = \ g_type_register_fundamental (g_type_fundamental_next (), \ I_("Cogl" # Name), \ &node_info, &finfo, \ G_TYPE_FLAG_ABSTRACT); \ g_once_init_leave (&type_id__volatile, \ fundamental_type_id); #define _COGL_GTYPE_DEFINE_BASE_CLASS_END() \ } \ return type_id__volatile; \ } #define COGL_GTYPE_DEFINE_BASE_CLASS(Name,name,...) \ _COGL_GTYPE_DEFINE_BASE_CLASS_BEGIN(Name,name) \ {__VA_ARGS__;} \ _COGL_GTYPE_DEFINE_BASE_CLASS_END() #define _COGL_GTYPE_DEFINE_INTERFACE_EXTENDED_BEGIN(Name,name) \ \ static void name##_default_init (Name##Interface *klass); \ GType \ name##_get_gtype (void) \ { \ static volatile gsize type_id__volatile = 0; \ if (g_once_init_enter (&type_id__volatile)) \ { \ GType fundamental_type_id = \ g_type_register_static_simple (G_TYPE_INTERFACE, \ g_intern_static_string (#Name), \ sizeof (Name##Interface), \ (GClassInitFunc)name##_default_init, \ 0, \ (GInstanceInitFunc)NULL, \ (GTypeFlags) 0); \ g_type_interface_add_prerequisite (fundamental_type_id, \ cogl_object_get_gtype()); \ { /* custom code follows */ #define _COGL_GTYPE_DEFINE_INTERFACE_EXTENDED_END() \ /* following custom code */ \ } \ g_once_init_leave (&type_id__volatile, \ fundamental_type_id); \ } \ return type_id__volatile; \ } /* closes name##_get_type() */ #define COGL_GTYPE_DEFINE_INTERFACE(Name,name) \ typedef struct _Cogl##Name##Iface Cogl##Name##Iface; \ typedef Cogl##Name##Iface Cogl##Name##Interface; \ struct _Cogl##Name##Iface \ { \ /*< private >*/ \ GTypeInterface g_iface; \ }; \ _COGL_GTYPE_DEFINE_INTERFACE_EXTENDED_BEGIN (Cogl##Name, cogl_##name) \ _COGL_GTYPE_DEFINE_INTERFACE_EXTENDED_END () \ static void \ cogl_##name##_default_init (Cogl##Name##Interface *iface) \ { \ } #define _COGL_GTYPE_DEFINE_TYPE_EXTENDED_BEGIN(Name,name,parent,flags) \ \ static void name##_init (Name *self); \ static void name##_class_init (Name##Class *klass); \ static gpointer name##_parent_class = NULL; \ static gint Name##_private_offset; \ \ static void \ name##_class_intern_init (gpointer klass) \ { \ name##_parent_class = g_type_class_peek_parent (klass); \ name##_class_init ((Name##Class*) klass); \ } \ \ static inline gpointer \ name##_get_instance_private (Name *self) \ { \ return (G_STRUCT_MEMBER_P (self, Name ##_private_offset)); \ } \ \ GType \ name##_get_gtype (void) \ { \ static volatile gsize type_id__volatile = 0; \ if (g_once_init_enter (&type_id__volatile)) \ { \ GType fundamental_type_id = \ g_type_register_static_simple (parent, \ g_intern_static_string (#Name), \ sizeof (Name##Class), \ (GClassInitFunc) name##_class_intern_init, \ sizeof (Name), \ (GInstanceInitFunc) name##_init, \ (GTypeFlags) flags); \ { /* custom code follows */ #define _COGL_GTYPE_DEFINE_TYPE_EXTENDED_END() \ /* following custom code */ \ } \ g_once_init_leave (&type_id__volatile, \ fundamental_type_id); \ } \ return type_id__volatile; \ } /* closes name##_get_type() */ #define COGL_GTYPE_DEFINE_CLASS(Name,name,...) \ typedef struct _Cogl##Name##Class Cogl##Name##Class; \ struct _Cogl##Name##Class { \ CoglObjectClass parent_class; \ }; \ _COGL_GTYPE_DEFINE_TYPE_EXTENDED_BEGIN(Cogl##Name, \ cogl_##name, \ cogl_object_get_gtype(), \ 0) \ {__VA_ARGS__;} \ _COGL_GTYPE_DEFINE_TYPE_EXTENDED_END() \ static void \ cogl_##name##_init (Cogl##Name *instance) \ { \ } \ static void \ cogl_##name##_class_init (Cogl##Name##Class *klass) \ { \ } void _cogl_gtype_object_init_value (GValue *value); void _cogl_gtype_object_free_value (GValue *value); void _cogl_gtype_object_copy_value (const GValue *src, GValue *dst); gpointer _cogl_gtype_object_peek_pointer (const GValue *value); gchar *_cogl_gtype_object_collect_value (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags); gchar *_cogl_gtype_object_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags); void _cogl_gtype_object_class_base_init (CoglObjectClass *klass); void _cogl_gtype_object_class_base_finalize (CoglObjectClass *klass); void _cogl_gtype_object_class_init (CoglObjectClass *klass); void _cogl_gtype_object_init (CoglObject *object); void cogl_object_value_set_object (GValue *value, gpointer object); gpointer cogl_object_value_get_object (const GValue *value); void _cogl_gtype_dummy_iface_init (gpointer iface); #endif /* __COGL_GTYPE_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-snippet.c0000664000175000017500000001061714211404421017561 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-types.h" #include "cogl-snippet-private.h" #include "cogl-util.h" #include "cogl-gtype-private.h" static void _cogl_snippet_free (CoglSnippet *snippet); COGL_OBJECT_DEFINE (Snippet, snippet); COGL_GTYPE_DEFINE_CLASS (Snippet, snippet); CoglSnippet * cogl_snippet_new (CoglSnippetHook hook, const char *declarations, const char *post) { CoglSnippet *snippet = g_slice_new0 (CoglSnippet); _cogl_snippet_object_new (snippet); snippet->hook = hook; cogl_snippet_set_declarations (snippet, declarations); cogl_snippet_set_post (snippet, post); return snippet; } CoglSnippetHook cogl_snippet_get_hook (CoglSnippet *snippet) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), 0); return snippet->hook; } static CoglBool _cogl_snippet_modify (CoglSnippet *snippet) { if (snippet->immutable) { g_warning ("A CoglSnippet should not be modified once it has been " "attached to a pipeline. Any modifications after that point " "will be ignored."); return FALSE; } return TRUE; } void cogl_snippet_set_declarations (CoglSnippet *snippet, const char *declarations) { _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet)); if (!_cogl_snippet_modify (snippet)) return; free (snippet->declarations); snippet->declarations = declarations ? g_strdup (declarations) : NULL; } const char * cogl_snippet_get_declarations (CoglSnippet *snippet) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), NULL); return snippet->declarations; } void cogl_snippet_set_pre (CoglSnippet *snippet, const char *pre) { _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet)); if (!_cogl_snippet_modify (snippet)) return; free (snippet->pre); snippet->pre = pre ? g_strdup (pre) : NULL; } const char * cogl_snippet_get_pre (CoglSnippet *snippet) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), NULL); return snippet->pre; } void cogl_snippet_set_replace (CoglSnippet *snippet, const char *replace) { _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet)); if (!_cogl_snippet_modify (snippet)) return; free (snippet->replace); snippet->replace = replace ? g_strdup (replace) : NULL; } const char * cogl_snippet_get_replace (CoglSnippet *snippet) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), NULL); return snippet->replace; } void cogl_snippet_set_post (CoglSnippet *snippet, const char *post) { _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet)); if (!_cogl_snippet_modify (snippet)) return; free (snippet->post); snippet->post = post ? g_strdup (post) : NULL; } const char * cogl_snippet_get_post (CoglSnippet *snippet) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), NULL); return snippet->post; } void _cogl_snippet_make_immutable (CoglSnippet *snippet) { snippet->immutable = TRUE; } static void _cogl_snippet_free (CoglSnippet *snippet) { free (snippet->declarations); free (snippet->pre); free (snippet->replace); free (snippet->post); g_slice_free (CoglSnippet, snippet); } muffin-5.2.1/cogl/cogl/cogl-texture.h0000664000175000017500000004151114211404421017601 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_TEXTURE_H__ #define __COGL_TEXTURE_H__ /* We forward declare the CoglTexture type here to avoid some circular * dependency issues with the following headers. */ #if defined(__COGL_H_INSIDE__) && !defined(COGL_ENABLE_MUFFIN_API) && \ !defined(COGL_GIR_SCANNING) /* For the public C api we typedef interface types as void to avoid needing * lots of casting in code and instead we will rely on runtime type checking * for these objects. */ typedef void CoglTexture; #else typedef struct _CoglTexture CoglTexture; #define COGL_TEXTURE(X) ((CoglTexture *)X) #endif #include #include #include #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-texture * @short_description: Functions for creating and manipulating textures * * Cogl allows creating and manipulating textures using a uniform * API that tries to hide all the various complexities of creating, * loading and manipulating textures. */ #define COGL_TEXTURE_MAX_WASTE 127 /** * cogl_texture_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_texture_get_gtype (void); /** * COGL_TEXTURE_ERROR: * * #CoglError domain for texture errors. * * Since: 1.8 * Stability: Unstable */ #define COGL_TEXTURE_ERROR (cogl_texture_error_quark ()) /** * CoglTextureError: * @COGL_TEXTURE_ERROR_SIZE: Unsupported size * @COGL_TEXTURE_ERROR_FORMAT: Unsupported format * @COGL_TEXTURE_ERROR_TYPE: A primitive texture type that is * unsupported by the driver was used * * Error codes that can be thrown when allocating textures. * * Since: 1.8 * Stability: Unstable */ typedef enum { COGL_TEXTURE_ERROR_SIZE, COGL_TEXTURE_ERROR_FORMAT, COGL_TEXTURE_ERROR_BAD_PARAMETER, COGL_TEXTURE_ERROR_TYPE } CoglTextureError; /** * CoglTextureType: * @COGL_TEXTURE_TYPE_2D: A #CoglTexture2D * @COGL_TEXTURE_TYPE_3D: A #CoglTexture3D * @COGL_TEXTURE_TYPE_RECTANGLE: A #CoglTextureRectangle * * Constants representing the underlying hardware texture type of a * #CoglTexture. * * Stability: unstable * Since: 1.10 */ typedef enum { COGL_TEXTURE_TYPE_2D, COGL_TEXTURE_TYPE_3D, COGL_TEXTURE_TYPE_RECTANGLE } CoglTextureType; uint32_t cogl_texture_error_quark (void); /** * cogl_is_texture: * @object: A #CoglObject pointer * * Gets whether the given object references a texture object. * * Return value: %TRUE if the @object references a texture, and * %FALSE otherwise */ CoglBool cogl_is_texture (void *object); /** * CoglTextureComponents: * @COGL_TEXTURE_COMPONENTS_A: Only the alpha component * @COGL_TEXTURE_COMPONENTS_RG: Red and green components. Note that * this can only be used if the %COGL_FEATURE_ID_TEXTURE_RG feature * is advertised. * @COGL_TEXTURE_COMPONENTS_RGB: Red, green and blue components * @COGL_TEXTURE_COMPONENTS_RGBA: Red, green, blue and alpha components * @COGL_TEXTURE_COMPONENTS_DEPTH: Only a depth component * * See cogl_texture_set_components(). * * Since: 1.18 */ typedef enum _CoglTextureComponents { COGL_TEXTURE_COMPONENTS_A = 1, COGL_TEXTURE_COMPONENTS_RG, COGL_TEXTURE_COMPONENTS_RGB, COGL_TEXTURE_COMPONENTS_RGBA, COGL_TEXTURE_COMPONENTS_DEPTH } CoglTextureComponents; /** * cogl_texture_set_components: * @texture: a #CoglTexture pointer. * * Affects the internal storage format for this texture by specifying * what components will be required for sampling later. * * This api affects how data is uploaded to the GPU since unused * components can potentially be discarded from source data. * * For textures created by the ‘_with_size’ constructors the default * is %COGL_TEXTURE_COMPONENTS_RGBA. The other constructors which take * a %CoglBitmap or a data pointer default to the same components as * the pixel format of the data. * * Note that the %COGL_TEXTURE_COMPONENTS_RG format is not available * on all drivers. The availability can be determined by checking for * the %COGL_FEATURE_ID_TEXTURE_RG feature. If this format is used on * a driver where it is not available then %COGL_TEXTURE_ERROR_FORMAT * will be raised when the texture is allocated. Even if the feature * is not available then %COGL_PIXEL_FORMAT_RG_88 can still be used as * an image format as long as %COGL_TEXTURE_COMPONENTS_RG isn't used * as the texture's components. * * Since: 1.18 */ void cogl_texture_set_components (CoglTexture *texture, CoglTextureComponents components); /** * cogl_texture_get_components: * @texture: a #CoglTexture pointer. * * Queries what components the given @texture stores internally as set * via cogl_texture_set_components(). * * For textures created by the ‘_with_size’ constructors the default * is %COGL_TEXTURE_COMPONENTS_RGBA. The other constructors which take * a %CoglBitmap or a data pointer default to the same components as * the pixel format of the data. * * Since: 1.18 */ CoglTextureComponents cogl_texture_get_components (CoglTexture *texture); /** * cogl_texture_set_premultiplied: * @texture: a #CoglTexture pointer. * @premultiplied: Whether any internally stored red, green or blue * components are pre-multiplied by an alpha * component. * * Affects the internal storage format for this texture by specifying * whether red, green and blue color components should be stored as * pre-multiplied alpha values. * * This api affects how data is uploaded to the GPU since Cogl will * convert source data to have premultiplied or unpremultiplied * components according to this state. * * For example if you create a texture via * cogl_texture_2d_new_with_size() and then upload data via * cogl_texture_set_data() passing a source format of * %COGL_PIXEL_FORMAT_RGBA_8888 then Cogl will internally multiply the * red, green and blue components of the source data by the alpha * component, for each pixel so that the internally stored data has * pre-multiplied alpha components. If you instead upload data that * already has pre-multiplied components by passing * %COGL_PIXEL_FORMAT_RGBA_8888_PRE as the source format to * cogl_texture_set_data() then the data can be uploaded without being * converted. * * By default the @premultipled state is @TRUE. * * Since: 1.18 */ void cogl_texture_set_premultiplied (CoglTexture *texture, CoglBool premultiplied); /** * cogl_texture_get_premultiplied: * @texture: a #CoglTexture pointer. * * Queries the pre-multiplied alpha status for internally stored red, * green and blue components for the given @texture as set by * cogl_texture_set_premultiplied(). * * By default the pre-multipled state is @TRUE. * * Return value: %TRUE if red, green and blue components are * internally stored pre-multiplied by the alpha * value or %FALSE if not. * Since: 1.18 */ CoglBool cogl_texture_get_premultiplied (CoglTexture *texture); /** * cogl_texture_get_width: * @texture: a #CoglTexture pointer. * * Queries the width of a cogl texture. * * Return value: the width of the GPU side texture in pixels */ unsigned int cogl_texture_get_width (CoglTexture *texture); /** * cogl_texture_get_height: * @texture: a #CoglTexture pointer. * * Queries the height of a cogl texture. * * Return value: the height of the GPU side texture in pixels */ unsigned int cogl_texture_get_height (CoglTexture *texture); /** * cogl_texture_get_max_waste: * @texture: a #CoglTexture pointer. * * Queries the maximum wasted (unused) pixels in one dimension of a GPU side * texture. * * Return value: the maximum waste */ int cogl_texture_get_max_waste (CoglTexture *texture); /** * cogl_texture_is_sliced: * @texture: a #CoglTexture pointer. * * Queries if a texture is sliced (stored as multiple GPU side tecture * objects). * * Return value: %TRUE if the texture is sliced, %FALSE if the texture * is stored as a single GPU texture */ CoglBool cogl_texture_is_sliced (CoglTexture *texture); /** * cogl_texture_get_gl_texture: * @texture: a #CoglTexture pointer. * @out_gl_handle: (out) (allow-none): pointer to return location for the * textures GL handle, or %NULL. * @out_gl_target: (out) (allow-none): pointer to return location for the * GL target type, or %NULL. * * Queries the GL handles for a GPU side texture through its #CoglTexture. * * If the texture is spliced the data for the first sub texture will be * queried. * * Return value: %TRUE if the handle was successfully retrieved, %FALSE * if the handle was invalid */ CoglBool cogl_texture_get_gl_texture (CoglTexture *texture, unsigned int *out_gl_handle, unsigned int *out_gl_target); /** * cogl_texture_get_data: * @texture: a #CoglTexture pointer. * @format: the #CoglPixelFormat to store the texture as. * @rowstride: the rowstride of @data in bytes or pass 0 to calculate * from the bytes-per-pixel of @format multiplied by the * @texture width. * @data: memory location to write the @texture's contents, or %NULL * to only query the data size through the return value. * * Copies the pixel data from a cogl texture to system memory. * * Don't pass the value of cogl_texture_get_rowstride() as the * @rowstride argument, the rowstride should be the rowstride you * want for the destination @data buffer not the rowstride of the * source texture * * Return value: the size of the texture data in bytes */ int cogl_texture_get_data (CoglTexture *texture, CoglPixelFormat format, unsigned int rowstride, uint8_t *data); /** * cogl_texture_set_region: * @texture: a #CoglTexture. * @src_x: upper left coordinate to use from source data. * @src_y: upper left coordinate to use from source data. * @dst_x: upper left destination horizontal coordinate. * @dst_y: upper left destination vertical coordinate. * @dst_width: width of destination region to write. (Must be less * than or equal to @width) * @dst_height: height of destination region to write. (Must be less * than or equal to @height) * @width: width of source data buffer. * @height: height of source data buffer. * @format: the #CoglPixelFormat used in the source buffer. * @rowstride: rowstride of source buffer (computed from width if none * specified) * @data: the actual pixel data. * * Sets the pixels in a rectangular subregion of @texture from an in-memory * buffer containing pixel data. * * The region set can't be larger than the source @data * * Return value: %TRUE if the subregion upload was successful, and * %FALSE otherwise */ CoglBool cogl_texture_set_region (CoglTexture *texture, int src_x, int src_y, int dst_x, int dst_y, unsigned int dst_width, unsigned int dst_height, int width, int height, CoglPixelFormat format, unsigned int rowstride, const uint8_t *data); /** * cogl_texture_set_data: * @texture a #CoglTexture. * @format: the #CoglPixelFormat used in the source @data buffer. * @rowstride: rowstride of the source @data buffer (computed from * the texture width and @format if it equals 0) * @data: the source data, pointing to the first top-left pixel to set * @level: The mipmap level to update (Normally 0 for the largest, * base texture) * @error: A #CoglError to return exceptional errors * * Sets all the pixels for a given mipmap @level by copying the pixel * data pointed to by the @data argument into the given @texture. * * @data should point to the first pixel to copy corresponding * to the top left of the mipmap @level being set. * * If @rowstride equals 0 then it will be automatically calculated * from the width of the mipmap level and the bytes-per-pixel for the * given @format. * * A mipmap @level of 0 corresponds to the largest, base image of a * texture and @level 1 is half the width and height of level 0. If * dividing any dimension of the previous level by two results in a * fraction then round the number down (floor()), but clamp to 1 * something like this: * * |[ * next_width = MAX (1, floor (prev_width)); * ]| * * You can determine the number of mipmap levels for a given texture * like this: * * |[ * n_levels = 1 + floor (log2 (max_dimension)); * ]| * * Where %max_dimension is the larger of cogl_texture_get_width() and * cogl_texture_get_height(). * * It is an error to pass a @level number >= the number of levels that * @texture can have according to the above calculation. * * Since the storage for a #CoglTexture is allocated lazily then * if the given @texture has not previously been allocated then this * api can return %FALSE and throw an exceptional @error if there is * not enough memory to allocate storage for @texture. * * Return value: %TRUE if the data upload was successful, and * %FALSE otherwise */ CoglBool cogl_texture_set_data (CoglTexture *texture, CoglPixelFormat format, int rowstride, const uint8_t *data, int level, CoglError **error); /** * cogl_texture_set_region_from_bitmap: * @texture: a #CoglTexture pointer * @src_x: upper left coordinate to use from the source bitmap. * @src_y: upper left coordinate to use from the source bitmap * @dst_x: upper left destination horizontal coordinate. * @dst_y: upper left destination vertical coordinate. * @dst_width: width of destination region to write. (Must be less * than or equal to the bitmap width) * @dst_height: height of destination region to write. (Must be less * than or equal to the bitmap height) * @bitmap: The source bitmap to read from * * Copies a specified source region from @bitmap to the position * (@src_x, @src_y) of the given destination texture @handle. * * The region updated can't be larger than the source * bitmap * * Return value: %TRUE if the subregion upload was successful, and * %FALSE otherwise * * Since: 1.8 * Stability: unstable */ CoglBool cogl_texture_set_region_from_bitmap (CoglTexture *texture, int src_x, int src_y, int dst_x, int dst_y, unsigned int dst_width, unsigned int dst_height, CoglBitmap *bitmap); /** * cogl_texture_allocate: * @texture: A #CoglTexture * @error: A #CoglError to return exceptional errors or %NULL * * Explicitly allocates the storage for the given @texture which * allows you to be sure that there is enough memory for the * texture and if not then the error can be handled gracefully. * * Normally applications don't need to use this api directly * since the texture will be implicitly allocated when data is set on * the texture, or if the texture is attached to a #CoglOffscreen * framebuffer and rendered too. * * Return value: %TRUE if the texture was successfully allocated, * otherwise %FALSE and @error will be updated if it * wasn't %NULL. */ CoglBool cogl_texture_allocate (CoglTexture *texture, CoglError **error); COGL_END_DECLS #endif /* __COGL_TEXTURE_H__ */ muffin-5.2.1/cogl/cogl/deprecated/0000775000175000017500000000000014211404421017104 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/cogl/deprecated/cogl-program.c0000664000175000017500000003400614211404421021644 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-util.h" #include "cogl-util-gl-private.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-shader-private.h" #include "cogl-program-private.h" #include static void _cogl_program_free (CoglProgram *program); COGL_HANDLE_DEFINE (Program, program); COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (program); /* A CoglProgram is effectively just a list of shaders that will be used together and a set of values for the custom uniforms. No actual GL program is created - instead this is the responsibility of the GLSL material backend. The uniform values are collected in an array and then flushed whenever the material backend requests it. */ static void _cogl_program_free (CoglProgram *program) { int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Unref all of the attached shaders */ g_slist_foreach (program->attached_shaders, (GFunc) cogl_handle_unref, NULL); /* Destroy the list */ g_slist_free (program->attached_shaders); for (i = 0; i < program->custom_uniforms->len; i++) { CoglProgramUniform *uniform = &g_array_index (program->custom_uniforms, CoglProgramUniform, i); free (uniform->name); if (uniform->value.count > 1) free (uniform->value.v.array); } g_array_free (program->custom_uniforms, TRUE); g_slice_free (CoglProgram, program); } CoglHandle cogl_create_program (void) { CoglProgram *program; program = g_slice_new0 (CoglProgram); program->custom_uniforms = g_array_new (FALSE, FALSE, sizeof (CoglProgramUniform)); program->age = 0; return _cogl_program_handle_new (program); } void cogl_program_attach_shader (CoglHandle program_handle, CoglHandle shader_handle) { CoglProgram *program; CoglShader *shader; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!cogl_is_program (program_handle) || !cogl_is_shader (shader_handle)) return; program = program_handle; shader = shader_handle; /* Only one shader is allowed if the type is ARBfp */ if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) _COGL_RETURN_IF_FAIL (program->attached_shaders == NULL); else if (shader->language == COGL_SHADER_LANGUAGE_GLSL) _COGL_RETURN_IF_FAIL (_cogl_program_get_language (program) == COGL_SHADER_LANGUAGE_GLSL); program->attached_shaders = g_slist_prepend (program->attached_shaders, cogl_handle_ref (shader_handle)); program->age++; } void cogl_program_link (CoglHandle handle) { /* There's no point in linking the program here because it will have to be relinked with a different fixed functionality shader whenever the settings change */ } void cogl_program_use (CoglHandle handle) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (handle == COGL_INVALID_HANDLE || cogl_is_program (handle)); if (ctx->current_program == 0 && handle != 0) ctx->legacy_state_set++; else if (handle == 0 && ctx->current_program != 0) ctx->legacy_state_set--; if (handle != COGL_INVALID_HANDLE) cogl_handle_ref (handle); if (ctx->current_program != COGL_INVALID_HANDLE) cogl_handle_unref (ctx->current_program); ctx->current_program = handle; } int cogl_program_get_uniform_location (CoglHandle handle, const char *uniform_name) { int i; CoglProgram *program; CoglProgramUniform *uniform; if (!cogl_is_program (handle)) return -1; program = handle; /* We can't just ask the GL program object for the uniform location directly because it will change every time the program is linked with a different shader. Instead we make our own mapping of uniform numbers and cache the names */ for (i = 0; i < program->custom_uniforms->len; i++) { uniform = &g_array_index (program->custom_uniforms, CoglProgramUniform, i); if (!strcmp (uniform->name, uniform_name)) return i; } /* Create a new uniform with the given name */ g_array_set_size (program->custom_uniforms, program->custom_uniforms->len + 1); uniform = &g_array_index (program->custom_uniforms, CoglProgramUniform, program->custom_uniforms->len - 1); uniform->name = g_strdup (uniform_name); memset (&uniform->value, 0, sizeof (CoglBoxedValue)); uniform->dirty = TRUE; uniform->location_valid = FALSE; return program->custom_uniforms->len - 1; } static CoglProgramUniform * cogl_program_modify_uniform (CoglProgram *program, int uniform_no) { CoglProgramUniform *uniform; _COGL_RETURN_VAL_IF_FAIL (cogl_is_program (program), NULL); _COGL_RETURN_VAL_IF_FAIL (uniform_no >= 0 && uniform_no < program->custom_uniforms->len, NULL); uniform = &g_array_index (program->custom_uniforms, CoglProgramUniform, uniform_no); uniform->dirty = TRUE; return uniform; } void cogl_program_uniform_1f (int uniform_no, float value) { CoglProgramUniform *uniform; _COGL_GET_CONTEXT (ctx, NO_RETVAL); uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); _cogl_boxed_value_set_1f (&uniform->value, value); } void cogl_program_set_uniform_1f (CoglHandle handle, int uniform_location, float value) { CoglProgramUniform *uniform; uniform = cogl_program_modify_uniform (handle, uniform_location); _cogl_boxed_value_set_1f (&uniform->value, value); } void cogl_program_uniform_1i (int uniform_no, int value) { CoglProgramUniform *uniform; _COGL_GET_CONTEXT (ctx, NO_RETVAL); uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); _cogl_boxed_value_set_1i (&uniform->value, value); } void cogl_program_set_uniform_1i (CoglHandle handle, int uniform_location, int value) { CoglProgramUniform *uniform; uniform = cogl_program_modify_uniform (handle, uniform_location); _cogl_boxed_value_set_1i (&uniform->value, value); } void cogl_program_uniform_float (int uniform_no, int size, int count, const float *value) { CoglProgramUniform *uniform; _COGL_GET_CONTEXT (ctx, NO_RETVAL); uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); _cogl_boxed_value_set_float (&uniform->value, size, count, value); } void cogl_program_set_uniform_float (CoglHandle handle, int uniform_location, int n_components, int count, const float *value) { CoglProgramUniform *uniform; uniform = cogl_program_modify_uniform (handle, uniform_location); _cogl_boxed_value_set_float (&uniform->value, n_components, count, value); } void cogl_program_uniform_int (int uniform_no, int size, int count, const int *value) { CoglProgramUniform *uniform; _COGL_GET_CONTEXT (ctx, NO_RETVAL); uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); _cogl_boxed_value_set_int (&uniform->value, size, count, value); } void cogl_program_set_uniform_int (CoglHandle handle, int uniform_location, int n_components, int count, const int *value) { CoglProgramUniform *uniform; uniform = cogl_program_modify_uniform (handle, uniform_location); _cogl_boxed_value_set_int (&uniform->value, n_components, count, value); } void cogl_program_set_uniform_matrix (CoglHandle handle, int uniform_location, int dimensions, int count, CoglBool transpose, const float *value) { CoglProgramUniform *uniform; uniform = cogl_program_modify_uniform (handle, uniform_location); _cogl_boxed_value_set_matrix (&uniform->value, dimensions, count, transpose, value); } void cogl_program_uniform_matrix (int uniform_no, int size, int count, CoglBool transpose, const float *value) { CoglProgramUniform *uniform; _COGL_GET_CONTEXT (ctx, NO_RETVAL); uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); _cogl_boxed_value_set_matrix (&uniform->value, size, count, transpose, value); } /* ARBfp local parameters can be referenced like: * * "program.local[5]" * ^14char offset (after whitespace is stripped) */ static int get_local_param_index (const char *uniform_name) { char *input = g_strdup (uniform_name); int i; char *p = input; char *endptr; int _index; for (i = 0; input[i] != '\0'; i++) if (input[i] != '_' && input[i] != '\t') *p++ = input[i]; input[i] = '\0'; _COGL_RETURN_VAL_IF_FAIL (strncmp ("program.local[", input, 14) == 0, -1); _index = g_ascii_strtoull (input + 14, &endptr, 10); _COGL_RETURN_VAL_IF_FAIL (endptr != input + 14, -1); _COGL_RETURN_VAL_IF_FAIL (*endptr == ']', -1); _COGL_RETURN_VAL_IF_FAIL (_index >= 0, -1); free (input); return _index; } #ifdef HAVE_COGL_GL static void _cogl_program_flush_uniform_arbfp (GLint location, CoglBoxedValue *value) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (value->type != COGL_BOXED_NONE) { _COGL_RETURN_IF_FAIL (value->type == COGL_BOXED_FLOAT); _COGL_RETURN_IF_FAIL (value->size == 4); _COGL_RETURN_IF_FAIL (value->count == 1); GE( ctx, glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB, location, value->v.float_value) ); } } #endif /* HAVE_COGL_GL */ void _cogl_program_flush_uniforms (CoglProgram *program, GLuint gl_program, CoglBool gl_program_changed) { CoglProgramUniform *uniform; int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (ctx->driver != COGL_DRIVER_GLES1); for (i = 0; i < program->custom_uniforms->len; i++) { uniform = &g_array_index (program->custom_uniforms, CoglProgramUniform, i); if (gl_program_changed || uniform->dirty) { if (gl_program_changed || !uniform->location_valid) { if (_cogl_program_get_language (program) == COGL_SHADER_LANGUAGE_GLSL) uniform->location = ctx->glGetUniformLocation (gl_program, uniform->name); else uniform->location = get_local_param_index (uniform->name); uniform->location_valid = TRUE; } /* If the uniform isn't really in the program then there's no need to actually set it */ if (uniform->location != -1) { switch (_cogl_program_get_language (program)) { case COGL_SHADER_LANGUAGE_GLSL: _cogl_boxed_value_set_uniform (ctx, uniform->location, &uniform->value); break; case COGL_SHADER_LANGUAGE_ARBFP: #ifdef HAVE_COGL_GL _cogl_program_flush_uniform_arbfp (uniform->location, &uniform->value); #endif break; } } uniform->dirty = FALSE; } } } CoglShaderLanguage _cogl_program_get_language (CoglHandle handle) { CoglProgram *program = handle; /* Use the language of the first shader */ if (program->attached_shaders) { CoglShader *shader = program->attached_shaders->data; return shader->language; } else return COGL_SHADER_LANGUAGE_GLSL; } static CoglBool _cogl_program_has_shader_type (CoglProgram *program, CoglShaderType type) { GSList *l; for (l = program->attached_shaders; l; l = l->next) { CoglShader *shader = l->data; if (shader->type == type) return TRUE; } return FALSE; } CoglBool _cogl_program_has_fragment_shader (CoglHandle handle) { return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_FRAGMENT); } CoglBool _cogl_program_has_vertex_shader (CoglHandle handle) { return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_VERTEX); } muffin-5.2.1/cogl/cogl/deprecated/cogl-material-compat.h0000664000175000017500000013672614211404421023275 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_MATERIAL_H__ #define __COGL_MATERIAL_H__ #include #include #include #include #include #include G_BEGIN_DECLS /** * SECTION:cogl-material * @short_description: Fuctions for creating and manipulating materials * * COGL allows creating and manipulating materials used to fill in * geometry. Materials may simply be lighting attributes (such as an * ambient and diffuse colour) or might represent one or more textures * blended together. */ typedef struct _CoglMaterial CoglMaterial; typedef struct _CoglMaterialLayer CoglMaterialLayer; #define COGL_TYPE_MATERIAL (cogl_material_get_type ()) GType cogl_material_get_type (void); #define COGL_MATERIAL(OBJECT) ((CoglMaterial *)OBJECT) /** * CoglMaterialFilter: * @COGL_MATERIAL_FILTER_NEAREST: Measuring in manhatten distance from the, * current pixel center, use the nearest texture texel * @COGL_MATERIAL_FILTER_LINEAR: Use the weighted average of the 4 texels * nearest the current pixel center * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose * texel size most closely matches the current pixel, and use the * %COGL_MATERIAL_FILTER_NEAREST criterion * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose * texel size most closely matches the current pixel, and use the * %COGL_MATERIAL_FILTER_LINEAR criterion * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels * whose texel size most closely matches the current pixel, use * the %COGL_MATERIAL_FILTER_NEAREST criterion on each one and take * their weighted average * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels * whose texel size most closely matches the current pixel, use * the %COGL_MATERIAL_FILTER_LINEAR criterion on each one and take * their weighted average * * Texture filtering is used whenever the current pixel maps either to more * than one texture element (texel) or less than one. These filter enums * correspond to different strategies used to come up with a pixel color, by * possibly referring to multiple neighbouring texels and taking a weighted * average or simply using the nearest texel. */ typedef enum { COGL_MATERIAL_FILTER_NEAREST = 0x2600, COGL_MATERIAL_FILTER_LINEAR = 0x2601, COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST = 0x2700, COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST = 0x2701, COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR = 0x2702, COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR = 0x2703 } CoglMaterialFilter; /* NB: these values come from the equivalents in gl.h */ /** * CoglMaterialWrapMode: * @COGL_MATERIAL_WRAP_MODE_REPEAT: The texture will be repeated. This * is useful for example to draw a tiled background. * @COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE: The coordinates outside the * range 0→1 will sample copies of the edge pixels of the * texture. This is useful to avoid artifacts if only one copy of * the texture is being rendered. * @COGL_MATERIAL_WRAP_MODE_AUTOMATIC: Cogl will try to automatically * decide which of the above two to use. For cogl_rectangle(), it * will use repeat mode if any of the texture coordinates are * outside the range 0→1, otherwise it will use clamp to edge. For * cogl_polygon() it will always use repeat mode. For * cogl_vertex_buffer_draw() it will use repeat mode except for * layers that have point sprite coordinate generation enabled. This * is the default value. * * The wrap mode specifies what happens when texture coordinates * outside the range 0→1 are used. Note that if the filter mode is * anything but %COGL_MATERIAL_FILTER_NEAREST then texels outside the * range 0→1 might be used even when the coordinate is exactly 0 or 1 * because OpenGL will try to sample neighbouring pixels. For example * if you are trying to render the full texture then you may get * artifacts around the edges when the pixels from the other side are * merged in if the wrap mode is set to repeat. * * Since: 1.4 */ /* GL_ALWAYS is just used here as a value that is known not to clash * with any valid GL wrap modes * * XXX: keep the values in sync with the CoglMaterialWrapModeInternal * enum so no conversion is actually needed. */ typedef enum { COGL_MATERIAL_WRAP_MODE_REPEAT = 0x2901, COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE = 0x812F, COGL_MATERIAL_WRAP_MODE_AUTOMATIC = 0x0207 } CoglMaterialWrapMode; /* NB: these values come from the equivalents in gl.h */ /** * cogl_material_new: * * Allocates and initializes a blank white material * * Return value: a pointer to a new #CoglMaterial * Deprecated: 1.16: Use cogl_pipeline_new() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_new) CoglMaterial * cogl_material_new (void); /** * cogl_material_copy: * @source: a #CoglMaterial object to copy * * Creates a new material with the configuration copied from the * source material. * * We would strongly advise developers to always aim to use * cogl_material_copy() instead of cogl_material_new() whenever there will * be any similarity between two materials. Copying a material helps Cogl * keep track of a materials ancestry which we may use to help minimize GPU * state changes. * * Returns: a pointer to the newly allocated #CoglMaterial * * Since: 1.2 * Deprecated: 1.16: Use cogl_pipeline_copy() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_copy) CoglMaterial * cogl_material_copy (CoglMaterial *source); /** * cogl_material_ref: * @material: a #CoglMaterial object. * * Increment the reference count for a #CoglMaterial. * * Return value: the @material. * * Since: 1.0 * * Deprecated: 1.2: Use cogl_object_ref() instead */ COGL_DEPRECATED CoglHandle cogl_material_ref (CoglHandle material); /** * cogl_material_unref: * @material: a #CoglMaterial object. * * Decrement the reference count for a #CoglMaterial. * * Since: 1.0 * * Deprecated: 1.2: Use cogl_object_unref() instead */ COGL_DEPRECATED void cogl_material_unref (CoglHandle material); /** * cogl_is_material: * @handle: A CoglHandle * * Gets whether the given handle references an existing material object. * * Return value: %TRUE if the handle references a #CoglMaterial, * %FALSE otherwise * Deprecated: 1.16: Use cogl_is_pipeline() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_is_pipeline) CoglBool cogl_is_material (CoglHandle handle); /** * cogl_material_set_color: * @material: A #CoglMaterial object * @color: The components of the color * * Sets the basic color of the material, used when no lighting is enabled. * * Note that if you don't add any layers to the material then the color * will be blended unmodified with the destination; the default blend * expects premultiplied colors: for example, use (0.5, 0.0, 0.0, 0.5) for * semi-transparent red. See cogl_color_premultiply(). * * The default value is (1.0, 1.0, 1.0, 1.0) * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_color() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_color) void cogl_material_set_color (CoglMaterial *material, const CoglColor *color); /** * cogl_material_set_color4ub: * @material: A #CoglMaterial object * @red: The red component * @green: The green component * @blue: The blue component * @alpha: The alpha component * * Sets the basic color of the material, used when no lighting is enabled. * * The default value is (0xff, 0xff, 0xff, 0xff) * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_color4ub() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_color4ub) void cogl_material_set_color4ub (CoglMaterial *material, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); /** * cogl_material_set_color4f: * @material: A #CoglMaterial object * @red: The red component * @green: The green component * @blue: The blue component * @alpha: The alpha component * * Sets the basic color of the material, used when no lighting is enabled. * * The default value is (1.0, 1.0, 1.0, 1.0) * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_color4f() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_color4f) void cogl_material_set_color4f (CoglMaterial *material, float red, float green, float blue, float alpha); /** * cogl_material_get_color: * @material: A #CoglMaterial object * @color: (out): The location to store the color * * Retrieves the current material color. * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_get_color() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_color) void cogl_material_get_color (CoglMaterial *material, CoglColor *color); /** * cogl_material_set_ambient: * @material: A #CoglMaterial object * @ambient: The components of the desired ambient color * * Sets the material's ambient color, in the standard OpenGL lighting * model. The ambient color affects the overall color of the object. * * Since the diffuse color will be intense when the light hits the surface * directly, the ambient will be most apparent where the light hits at a * slant. * * The default value is (0.2, 0.2, 0.2, 1.0) * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_set_ambient (CoglMaterial *material, const CoglColor *ambient); /** * cogl_material_get_ambient: * @material: A #CoglMaterial object * @ambient: The location to store the ambient color * * Retrieves the current ambient color for @material * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_get_ambient (CoglMaterial *material, CoglColor *ambient); /** * cogl_material_set_diffuse: * @material: A #CoglMaterial object * @diffuse: The components of the desired diffuse color * * Sets the material's diffuse color, in the standard OpenGL lighting * model. The diffuse color is most intense where the light hits the * surface directly - perpendicular to the surface. * * The default value is (0.8, 0.8, 0.8, 1.0) * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_set_diffuse (CoglMaterial *material, const CoglColor *diffuse); /** * cogl_material_get_diffuse: * @material: A #CoglMaterial object * @diffuse: The location to store the diffuse color * * Retrieves the current diffuse color for @material * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_get_diffuse (CoglMaterial *material, CoglColor *diffuse); /** * cogl_material_set_ambient_and_diffuse: * @material: A #CoglMaterial object * @color: The components of the desired ambient and diffuse colors * * Conveniently sets the diffuse and ambient color of @material at the same * time. See cogl_material_set_ambient() and cogl_material_set_diffuse(). * * The default ambient color is (0.2, 0.2, 0.2, 1.0) * * The default diffuse color is (0.8, 0.8, 0.8, 1.0) * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_set_ambient_and_diffuse (CoglMaterial *material, const CoglColor *color); /** * cogl_material_set_specular: * @material: A #CoglMaterial object * @specular: The components of the desired specular color * * Sets the material's specular color, in the standard OpenGL lighting * model. The intensity of the specular color depends on the viewport * position, and is brightest along the lines of reflection. * * The default value is (0.0, 0.0, 0.0, 1.0) * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_set_specular (CoglMaterial *material, const CoglColor *specular); /** * cogl_material_get_specular: * @material: A #CoglMaterial object * @specular: The location to store the specular color * * Retrieves the materials current specular color. * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_get_specular (CoglMaterial *material, CoglColor *specular); /** * cogl_material_set_shininess: * @material: A #CoglMaterial object * @shininess: The desired shininess; must be >= 0.0 * * Sets the shininess of the material, in the standard OpenGL lighting * model, which determines the size of the specular highlights. A * higher @shininess will produce smaller highlights which makes the * object appear more shiny. * * The default value is 0.0 * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_set_shininess (CoglMaterial *material, float shininess); /** * cogl_material_get_shininess: * @material: A #CoglMaterial object * * Retrieves the materials current emission color. * * Return value: The materials current shininess value * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) float cogl_material_get_shininess (CoglMaterial *material); /** * cogl_material_set_emission: * @material: A #CoglMaterial object * @emission: The components of the desired emissive color * * Sets the material's emissive color, in the standard OpenGL lighting * model. It will look like the surface is a light source emitting this * color. * * The default value is (0.0, 0.0, 0.0, 1.0) * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_set_emission (CoglMaterial *material, const CoglColor *emission); /** * cogl_material_get_emission: * @material: A #CoglMaterial object * @emission: The location to store the emission color * * Retrieves the materials current emission color. * * Since: 1.0 * Deprecated: 1.16: Use the #CoglSnippet shader api for lighting */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_get_emission (CoglMaterial *material, CoglColor *emission); /** * CoglMaterialAlphaFunc: * @COGL_MATERIAL_ALPHA_FUNC_NEVER: Never let the fragment through. * @COGL_MATERIAL_ALPHA_FUNC_LESS: Let the fragment through if the incoming * alpha value is less than the reference alpha value * @COGL_MATERIAL_ALPHA_FUNC_EQUAL: Let the fragment through if the incoming * alpha value equals the reference alpha value * @COGL_MATERIAL_ALPHA_FUNC_LEQUAL: Let the fragment through if the incoming * alpha value is less than or equal to the reference alpha value * @COGL_MATERIAL_ALPHA_FUNC_GREATER: Let the fragment through if the incoming * alpha value is greater than the reference alpha value * @COGL_MATERIAL_ALPHA_FUNC_NOTEQUAL: Let the fragment through if the incoming * alpha value does not equal the reference alpha value * @COGL_MATERIAL_ALPHA_FUNC_GEQUAL: Let the fragment through if the incoming * alpha value is greater than or equal to the reference alpha value. * @COGL_MATERIAL_ALPHA_FUNC_ALWAYS: Always let the fragment through. * * Alpha testing happens before blending primitives with the framebuffer and * gives an opportunity to discard fragments based on a comparison with the * incoming alpha value and a reference alpha value. The #CoglMaterialAlphaFunc * determines how the comparison is done. */ typedef enum { COGL_MATERIAL_ALPHA_FUNC_NEVER = 0x0200, COGL_MATERIAL_ALPHA_FUNC_LESS = 0x0201, COGL_MATERIAL_ALPHA_FUNC_EQUAL = 0x0202, COGL_MATERIAL_ALPHA_FUNC_LEQUAL = 0x0203, COGL_MATERIAL_ALPHA_FUNC_GREATER = 0x0204, COGL_MATERIAL_ALPHA_FUNC_NOTEQUAL = 0x0205, COGL_MATERIAL_ALPHA_FUNC_GEQUAL = 0x0206, COGL_MATERIAL_ALPHA_FUNC_ALWAYS = 0x0207 } CoglMaterialAlphaFunc; /** * cogl_material_set_alpha_test_function: * @material: A #CoglMaterial object * @alpha_func: A @CoglMaterialAlphaFunc constant * @alpha_reference: A reference point that the chosen alpha function uses * to compare incoming fragments to. * * Before a primitive is blended with the framebuffer, it goes through an * alpha test stage which lets you discard fragments based on the current * alpha value. This function lets you change the function used to evaluate * the alpha channel, and thus determine which fragments are discarded * and which continue on to the blending stage. * * The default is %COGL_MATERIAL_ALPHA_FUNC_ALWAYS * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_alpha_test_function() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_alpha_test_function) void cogl_material_set_alpha_test_function (CoglMaterial *material, CoglMaterialAlphaFunc alpha_func, float alpha_reference); /** * cogl_material_set_blend: * @material: A #CoglMaterial object * @blend_string: A Cogl blend string * describing the desired blend function. * @error: return location for a #CoglError that may report lack of driver * support if you give separate blend string statements for the alpha * channel and RGB channels since some drivers, or backends such as * GLES 1.1, don't support this feature. May be %NULL, in which case a * warning will be printed out using GLib's logging facilities if an * error is encountered. * * If not already familiar; please refer here * for an overview of what blend strings are, and their syntax. * * Blending occurs after the alpha test function, and combines fragments with * the framebuffer. * Currently the only blend function Cogl exposes is ADD(). So any valid * blend statements will be of the form: * * |[ * <channel-mask>=ADD(SRC_COLOR*(<factor>), DST_COLOR*(<factor>)) * ]| * * The brackets around blend factors are currently not * optional! * * This is the list of source-names usable as blend factors: * * SRC_COLOR: The color of the in comming fragment * DST_COLOR: The color of the framebuffer * CONSTANT: The constant set via cogl_material_set_blend_constant() * * * The source names can be used according to the * color-source and factor syntax, * so for example "(1-SRC_COLOR[A])" would be a valid factor, as would * "(CONSTANT[RGB])" * * These can also be used as factors: * * 0: (0, 0, 0, 0) * 1: (1, 1, 1, 1) * SRC_ALPHA_SATURATE_FACTOR: (f,f,f,1) where f = MIN(SRC_COLOR[A],1-DST_COLOR[A]) * * * Remember; all color components are normalized to the range [0, 1] * before computing the result of blending. * * * Blend Strings/1 * Blend a non-premultiplied source over a destination with * premultiplied alpha: * * "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))" * "A = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" * * * * * Blend Strings/2 * Blend a premultiplied source over a destination with * premultiplied alpha * * "RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" * * * * The default blend string is: * |[ * RGBA = ADD (SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A])) * ]| * * That gives normal alpha-blending when the calculated color for the material * is in premultiplied form. * * Return value: %TRUE if the blend string was successfully parsed, and the * described blending is supported by the underlying driver/hardware. If * there was an error, %FALSE is returned and @error is set accordingly (if * present). * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_blend() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_blend) CoglBool cogl_material_set_blend (CoglMaterial *material, const char *blend_string, CoglError **error); /** * cogl_material_set_blend_constant: * @material: A #CoglMaterial object * @constant_color: The constant color you want * * When blending is setup to reference a CONSTANT blend factor then * blending will depend on the constant set with this function. * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_blend_constant() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_blend_constant) void cogl_material_set_blend_constant (CoglMaterial *material, const CoglColor *constant_color); /** * cogl_material_set_point_size: * @material: a material. * @point_size: the new point size. * * Changes the size of points drawn when %COGL_VERTICES_MODE_POINTS is * used with the vertex buffer API. Note that typically the GPU will * only support a limited minimum and maximum range of point sizes. If * the chosen point size is outside that range then the nearest value * within that range will be used instead. The size of a point is in * screen space so it will be the same regardless of any * transformations. The default point size is 1.0. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_set_point_size() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_point_size) void cogl_material_set_point_size (CoglMaterial *material, float point_size); /** * cogl_material_get_point_size: * @material: a #CoglHandle to a material. * * Get the size of points drawn when %COGL_VERTICES_MODE_POINTS is * used with the vertex buffer API. * * Return value: the point size of the material. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_get_point_size() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_point_size) float cogl_material_get_point_size (CoglMaterial *material); /** * cogl_material_get_user_program: * @material: a #CoglMaterial object. * * Queries what user program has been associated with the given * @material using cogl_material_set_user_program(). * * Return value: (transfer none): The current user program * or %COGL_INVALID_HANDLE. * * Since: 1.4 * Deprecated: 1.16: Use #CoglSnippet api instead instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglHandle cogl_material_get_user_program (CoglMaterial *material); /** * cogl_material_set_user_program: * @material: a #CoglMaterial object. * @program: A #CoglHandle to a linked CoglProgram * * Associates a linked CoglProgram with the given material so that the * program can take full control of vertex and/or fragment processing. * * This is an example of how it can be used to associate an ARBfp * program with a #CoglMaterial: * |[ * CoglHandle shader; * CoglHandle program; * CoglMaterial *material; * * shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); * cogl_shader_source (shader, * "!!ARBfp1.0\n" * "MOV result.color,fragment.color;\n" * "END\n"); * cogl_shader_compile (shader); * * program = cogl_create_program (); * cogl_program_attach_shader (program, shader); * cogl_program_link (program); * * material = cogl_material_new (); * cogl_material_set_user_program (material, program); * * cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); * cogl_rectangle (0, 0, 100, 100); * ]| * * It is possibly worth keeping in mind that this API is not part of * the long term design for how we want to expose shaders to Cogl * developers (We are planning on deprecating the cogl_program and * cogl_shader APIs in favour of a "snippet" framework) but in the * meantime we hope this will handle most practical GLSL and ARBfp * requirements. * * Also remember you need to check for either the * %COGL_FEATURE_SHADERS_GLSL or %COGL_FEATURE_SHADERS_ARBFP before * using the cogl_program or cogl_shader API. * * Since: 1.4 * Deprecated: 1.16: Use #CoglSnippet api instead instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_material_set_user_program (CoglMaterial *material, CoglHandle program); /** * cogl_material_set_layer: * @material: A #CoglMaterial object * @layer_index: the index of the layer * @texture: a #CoglHandle for the layer object * * In addition to the standard OpenGL lighting model a Cogl material may have * one or more layers comprised of textures that can be blended together in * order, with a number of different texture combine modes. This function * defines a new texture layer. * * The index values of multiple layers do not have to be consecutive; it is * only their relative order that is important. * * In the future, we may define other types of material layers, such * as purely GLSL based layers. * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_layer() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer) void cogl_material_set_layer (CoglMaterial *material, int layer_index, CoglHandle texture); /** * cogl_material_remove_layer: * @material: A #CoglMaterial object * @layer_index: Specifies the layer you want to remove * * This function removes a layer from your material * Deprecated: 1.16: Use cogl_pipeline_remove_layer() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_remove_layer) void cogl_material_remove_layer (CoglMaterial *material, int layer_index); /** * cogl_material_set_layer_combine: * @material: A #CoglMaterial object * @layer_index: Specifies the layer you want define a combine function for * @blend_string: A Cogl blend string * describing the desired texture combine function. * @error: A #CoglError that may report parse errors or lack of GPU/driver * support. May be %NULL, in which case a warning will be printed out if an * error is encountered. * * If not already familiar; you can refer * here for an overview of what blend * strings are and there syntax. * * These are all the functions available for texture combining: * * REPLACE(arg0) = arg0 * MODULATE(arg0, arg1) = arg0 x arg1 * ADD(arg0, arg1) = arg0 + arg1 * ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5 * INTERPOLATE(arg0, arg1, arg2) = arg0 x arg2 + arg1 x (1 - arg2) * SUBTRACT(arg0, arg1) = arg0 - arg1 * * * DOT3_RGB(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * * * * * DOT3_RGBA(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * * * * * Refer to the * color-source syntax for * describing the arguments. The valid source names for texture combining * are: * * * TEXTURE * Use the color from the current texture layer * * * TEXTURE_0, TEXTURE_1, etc * Use the color from the specified texture layer * * * CONSTANT * Use the color from the constant given with * cogl_material_set_layer_constant() * * * PRIMARY * Use the color of the material as set with * cogl_material_set_color() * * * PREVIOUS * Either use the texture color from the previous layer, or * if this is layer 0, use the color of the material as set with * cogl_material_set_color() * * * * * Layer Combine Examples * This is effectively what the default blending is: * * RGBA = MODULATE (PREVIOUS, TEXTURE) * * This could be used to cross-fade between two images, using * the alpha component of a constant as the interpolator. The constant * color is given by calling cogl_material_set_layer_constant. * * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A]) * * * * You can't give a multiplication factor for arguments as you can * with blending. * * Return value: %TRUE if the blend string was successfully parsed, and the * described texture combining is supported by the underlying driver and * or hardware. On failure, %FALSE is returned and @error is set * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_layer_combine() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_combine) CoglBool cogl_material_set_layer_combine (CoglMaterial *material, int layer_index, const char *blend_string, CoglError **error); /** * cogl_material_set_layer_combine_constant: * @material: A #CoglMaterial object * @layer_index: Specifies the layer you want to specify a constant used * for texture combining * @constant: The constant color you want * * When you are using the 'CONSTANT' color source in a layer combine * description then you can use this function to define its value. * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_set_layer_combine_constant() * instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_combine_constant) void cogl_material_set_layer_combine_constant (CoglMaterial *material, int layer_index, const CoglColor *constant); /** * cogl_material_set_layer_matrix: * @material: A #CoglMaterial object * @layer_index: the index for the layer inside @material * @matrix: the transformation matrix for the layer * * This function lets you set a matrix that can be used to e.g. translate * and rotate a single layer of a material used to fill your geometry. * Deprecated: 1.16: Use cogl_pipeline_set_layer_matrix() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_matrix) void cogl_material_set_layer_matrix (CoglMaterial *material, int layer_index, const CoglMatrix *matrix); /** * cogl_material_get_layers: * @material: A #CoglMaterial object * * This function lets you access a material's internal list of layers * for iteration. * * You should avoid using this API if possible since it was only * made public by mistake and will be deprecated when we have * suitable alternative. * * It's important to understand that the list returned may not * remain valid if you modify the material or any of the layers in any * way and so you would have to re-get the list in that * situation. * * Return value: (element-type CoglMaterialLayer) (transfer none): A * list of #CoglMaterialLayer's that can be passed to the * cogl_material_layer_* functions. The list is owned by Cogl and it * should not be modified or freed * Deprecated: 1.16: Use cogl_pipeline_get_layers() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_layers) const GList * cogl_material_get_layers (CoglMaterial *material); /** * cogl_material_get_n_layers: * @material: A #CoglMaterial object * * Retrieves the number of layers defined for the given @material * * Return value: the number of layers * * Since: 1.0 * Deprecated: 1.16: Use cogl_pipeline_get_n_layers() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_n_layers) int cogl_material_get_n_layers (CoglMaterial *material); /** * CoglMaterialLayerType: * @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a * texture * * Available types of layers for a #CoglMaterial. This enumeration * might be expanded in later versions. * * Since: 1.0 */ typedef enum { COGL_MATERIAL_LAYER_TYPE_TEXTURE } CoglMaterialLayerType; /** * cogl_material_layer_get_type: * @layer: A #CoglMaterialLayer object * * Retrieves the type of the layer * * Currently there is only one type of layer defined: * %COGL_MATERIAL_LAYER_TYPE_TEXTURE, but considering we may add purely GLSL * based layers in the future, you should write code that checks the type * first. * * Return value: the type of the layer * Deprecated: 1.16: No replacement */ COGL_DEPRECATED_IN_1_16 CoglMaterialLayerType cogl_material_layer_get_type (CoglMaterialLayer *layer); /** * cogl_material_layer_get_texture: * @layer: A #CoglMaterialLayer object * * Extracts a texture handle for a specific layer. * * In the future Cogl may support purely GLSL based layers; for those * layers this function which will likely return %COGL_INVALID_HANDLE if you * try to get the texture handle from them. Considering this scenario, you * should call cogl_material_layer_get_type() first in order check it is of * type %COGL_MATERIAL_LAYER_TYPE_TEXTURE before calling this function. * * Return value: (transfer none): a #CoglHandle for the texture inside the layer * Deprecated: 1.16: No replacement */ COGL_DEPRECATED_IN_1_16 CoglHandle cogl_material_layer_get_texture (CoglMaterialLayer *layer); /** * cogl_material_layer_get_min_filter: * @layer: a #CoglHandle for a material layer * * Queries the currently set downscaling filter for a material layer * * Return value: the current downscaling filter * Deprecated: 1.16: No replacement */ COGL_DEPRECATED_IN_1_16 CoglMaterialFilter cogl_material_layer_get_min_filter (CoglMaterialLayer *layer); /** * cogl_material_layer_get_mag_filter: * @layer: A #CoglMaterialLayer object * * Queries the currently set downscaling filter for a material later * * Return value: the current downscaling filter * Deprecated: 1.16: No replacement */ COGL_DEPRECATED_IN_1_16 CoglMaterialFilter cogl_material_layer_get_mag_filter (CoglMaterialLayer *layer); /** * cogl_material_set_layer_filters: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * @min_filter: the filter used when scaling a texture down. * @mag_filter: the filter used when magnifying a texture. * * Changes the decimation and interpolation filters used when a texture is * drawn at other scales than 100%. * Deprecated: 1.16: Use cogl_pipeline_set_layer_filters() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_filters) void cogl_material_set_layer_filters (CoglMaterial *material, int layer_index, CoglMaterialFilter min_filter, CoglMaterialFilter mag_filter); /** * cogl_material_set_layer_point_sprite_coords_enabled: * @material: a #CoglHandle to a material. * @layer_index: the layer number to change. * @enable: whether to enable point sprite coord generation. * @error: A return location for a CoglError, or NULL to ignore errors. * * When rendering points, if @enable is %TRUE then the texture * coordinates for this layer will be replaced with coordinates that * vary from 0.0 to 1.0 across the primitive. The top left of the * point will have the coordinates 0.0,0.0 and the bottom right will * have 1.0,1.0. If @enable is %FALSE then the coordinates will be * fixed for the entire point. * * This function will only work if %COGL_FEATURE_POINT_SPRITE is * available. If the feature is not available then the function will * return %FALSE and set @error. * * Return value: %TRUE if the function succeeds, %FALSE otherwise. * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_set_layer_point_sprite_coords_enabled() * instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_point_sprite_coords_enabled) CoglBool cogl_material_set_layer_point_sprite_coords_enabled (CoglMaterial *material, int layer_index, CoglBool enable, CoglError **error); /** * cogl_material_get_layer_point_sprite_coords_enabled: * @material: a #CoglHandle to a material. * @layer_index: the layer number to check. * * Gets whether point sprite coordinate generation is enabled for this * texture layer. * * Return value: whether the texture coordinates will be replaced with * point sprite coordinates. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_get_layer_point_sprite_coords_enabled() * instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_layer_point_sprite_coords_enabled) CoglBool cogl_material_get_layer_point_sprite_coords_enabled (CoglMaterial *material, int layer_index); /** * cogl_material_get_layer_wrap_mode_s: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * * Returns the wrap mode for the 's' coordinate of texture lookups on this * layer. * * Return value: the wrap mode for the 's' coordinate of texture lookups on * this layer. * * Since: 1.6 * Deprecated: 1.16: Use cogl_pipeline_get_layer_wrap_mode_s() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_layer_wrap_mode_s) CoglMaterialWrapMode cogl_material_get_layer_wrap_mode_s (CoglMaterial *material, int layer_index); /** * cogl_material_set_layer_wrap_mode_s: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for the 's' coordinate of texture lookups on this layer. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_set_layer_wrap_mode_s() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_wrap_mode_s) void cogl_material_set_layer_wrap_mode_s (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode); /** * cogl_material_get_layer_wrap_mode_t: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * * Returns the wrap mode for the 't' coordinate of texture lookups on this * layer. * * Return value: the wrap mode for the 't' coordinate of texture lookups on * this layer. * * Since: 1.6 * Deprecated: 1.16: Use cogl_pipeline_get_layer_wrap_mode_t() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_layer_wrap_mode_t) CoglMaterialWrapMode cogl_material_get_layer_wrap_mode_t (CoglMaterial *material, int layer_index); /** * cogl_material_set_layer_wrap_mode_t: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for the 't' coordinate of texture lookups on this layer. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_set_layer_wrap_mode_t() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_wrap_mode_t) void cogl_material_set_layer_wrap_mode_t (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode); /** * cogl_material_get_layer_wrap_mode_p: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * * Returns the wrap mode for the 'p' coordinate of texture lookups on this * layer. * * Return value: the wrap mode for the 'p' coordinate of texture lookups on * this layer. * * Since: 1.6 * Deprecated: 1.16: Use cogl_pipeline_get_layer_wrap_mode_p() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_layer_wrap_mode_p) CoglMaterialWrapMode cogl_material_get_layer_wrap_mode_p (CoglMaterial *material, int layer_index); /** * cogl_material_set_layer_wrap_mode_p: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for the 'p' coordinate of texture lookups on * this layer. 'p' is the third coordinate. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_set_layer_wrap_mode_p() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_wrap_mode_p) void cogl_material_set_layer_wrap_mode_p (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode); /** * cogl_material_set_layer_wrap_mode: * @material: A #CoglMaterial object * @layer_index: the layer number to change. * @mode: the new wrap mode * * Sets the wrap mode for all three coordinates of texture lookups on * this layer. This is equivalent to calling * cogl_material_set_layer_wrap_mode_s(), * cogl_material_set_layer_wrap_mode_t() and * cogl_material_set_layer_wrap_mode_p() separately. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_set_layer_wrap_mode() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_layer_wrap_mode) void cogl_material_set_layer_wrap_mode (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode); /** * cogl_material_layer_get_wrap_mode_s: * @layer: A #CoglMaterialLayer object * * Gets the wrap mode for the 's' coordinate of texture lookups on this layer. * * Return value: the wrap mode value for the s coordinate. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_layer_get_wrap_mode_s() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_layer_get_wrap_mode_s) CoglMaterialWrapMode cogl_material_layer_get_wrap_mode_s (CoglMaterialLayer *layer); /** * cogl_material_layer_get_wrap_mode_t: * @layer: A #CoglMaterialLayer object * * Gets the wrap mode for the 't' coordinate of texture lookups on this layer. * * Return value: the wrap mode value for the t coordinate. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_layer_get_wrap_mode_t() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_layer_get_wrap_mode_t) CoglMaterialWrapMode cogl_material_layer_get_wrap_mode_t (CoglMaterialLayer *layer); /** * cogl_material_layer_get_wrap_mode_p: * @layer: A #CoglMaterialLayer object * * Gets the wrap mode for the 'p' coordinate of texture lookups on * this layer. 'p' is the third coordinate. * * Return value: the wrap mode value for the p coordinate. * * Since: 1.4 * Deprecated: 1.16: Use cogl_pipeline_layer_get_wrap_mode_p() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_layer_get_wrap_mode_p) CoglMaterialWrapMode cogl_material_layer_get_wrap_mode_p (CoglMaterialLayer *layer); /** * cogl_material_set_depth_state: (skip) * @material: A #CoglMaterial object * @state: A #CoglDepthState struct * @error: A #CoglError to report failures to setup the given @state. * * This commits all the depth state configured in @state struct to the * given @material. The configuration values are copied into the * material so there is no requirement to keep the #CoglDepthState * struct around if you don't need it any more. * * Note: Since some platforms do not support the depth range feature * it is possible for this function to fail and report an @error. * * Returns: TRUE if the GPU supports all the given @state else %FALSE * and returns an @error. * * Since: 1.8 * Stability: Unstable * Deprecated: 1.16: Use cogl_pipeline_set_depth_state() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_set_depth_state) CoglBool cogl_material_set_depth_state (CoglMaterial *material, const CoglDepthState *state, CoglError **error); /** * cogl_material_get_depth_state: (skip) * @material: A #CoglMaterial object * @state_out: A destination #CoglDepthState struct * * Retrieves the current depth state configuration for the given * @pipeline as previously set using cogl_pipeline_set_depth_state(). * * Since: 2.0 * Stability: Unstable * Deprecated: 1.16: Use cogl_pipeline_get_depth_state() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_pipeline_get_depth_state) void cogl_material_get_depth_state (CoglMaterial *material, CoglDepthState *state_out); /** * CoglMaterialLayerCallback: * @material: The #CoglMaterial whos layers are being iterated * @layer_index: The current layer index * @user_data: The private data passed to cogl_material_foreach_layer() * * The callback prototype used with cogl_material_foreach_layer() for * iterating all the layers of a @material. * * Since: 1.4 * Stability: Unstable * Deprecated: 1.16 */ typedef CoglBool (*CoglMaterialLayerCallback) (CoglMaterial *material, int layer_index, void *user_data); /** * cogl_material_foreach_layer: * @material: A #CoglMaterial object * @callback: (scope call): A #CoglMaterialLayerCallback to be called for each * layer index * @user_data: Private data that will be passed to the callback * * Iterates all the layer indices of the given @material. * * Since: 1.4 * Stability: Unstable * Deprecated: 1.16: No replacement */ COGL_DEPRECATED_IN_1_16 void cogl_material_foreach_layer (CoglMaterial *material, CoglMaterialLayerCallback callback, void *user_data); G_END_DECLS #endif /* __COGL_MATERIAL_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-clutter-xlib.h0000664000175000017500000000326314211404421022621 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #if !defined(__COGL_XLIB_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_CLUTTER_XLIB_H__ #define __COGL_CLUTTER_XLIB_H__ #include COGL_BEGIN_DECLS #define cogl_clutter_winsys_xlib_get_visual_info cogl_clutter_winsys_xlib_get_visual_info_CLUTTER /** * cogl_clutter_winsys_xlib_get_visual_info_CLUTTER: (skip) */ XVisualInfo * cogl_clutter_winsys_xlib_get_visual_info (void); COGL_END_DECLS #endif /* __COGL_CLUTTER_XLIB_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-vertex-buffer-private.h0000664000175000017500000001243214211404421024435 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_VERTEX_BUFFER_H #define __COGL_VERTEX_BUFFER_H #include "cogl-object-private.h" #include "cogl-primitive.h" #include /* Note we put quite a bit into the flags here to help keep * the down size of the CoglVertexBufferAttrib struct below. */ typedef enum _CoglVertexBufferAttribFlags { /* Types */ /* NB: update the _TYPE_MASK below if these are changed */ COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY = 1<<0, COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY = 1<<1, COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY = 1<<2, COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY = 1<<3, COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY = 1<<4, COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID = 1<<5, COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMALIZED = 1<<6, COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED = 1<<7, /* Usage hints */ /* FIXME - flatten into one flag, since its used as a boolean */ COGL_VERTEX_BUFFER_ATTRIB_FLAG_INFREQUENT_RESUBMIT = 1<<8, COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT = 1<<9, /* GL Data types */ /* NB: Update the _GL_TYPE_MASK below if these are changed */ COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_BYTE = 1<<10, COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_UNSIGNED_BYTE = 1<<11, COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_SHORT = 1<<12, COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_UNSIGNED_SHORT = 1<<13, COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_INT = 1<<14, COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_UNSIGNED_INT = 1<<15, COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_FLOAT = 1<<16, COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_DOUBLE = 1<<17, COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED = 1<<18, COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED = 1<<19 /* XXX NB: If we need > 24 bits then look at changing the layout * of struct _CoglVertexBufferAttrib below */ } CoglVertexBufferAttribFlags; #define COGL_VERTEX_BUFFER_ATTRIB_FLAG_TYPE_MASK \ (COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY \ | COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY \ | COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY \ | COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY \ | COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY \ | COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) typedef struct _CoglVertexBufferAttrib { /* TODO: look at breaking up the flags into seperate * bitfields and seperate enums */ CoglVertexBufferAttribFlags flags:24; uint8_t id; GQuark name; char *name_without_detail; union _u { const void *pointer; size_t vbo_offset; } u; CoglAttributeType type; size_t span_bytes; uint16_t stride; uint8_t n_components; uint8_t texture_unit; int attribute_first; CoglAttribute *attribute; } CoglVertexBufferAttrib; typedef enum _CoglVertexBufferVBOFlags { COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED = 1<<0, COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK = 1<<1, /* FIXME - flatten into one flag, since its used as a boolean */ COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT = 1<<3, COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT = 1<<4, COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED = 1<<5 } CoglVertexBufferVBOFlags; /* * A CoglVertexBufferVBO represents one or more attributes in a single * buffer object */ typedef struct _CoglVertexBufferVBO { CoglVertexBufferVBOFlags flags; CoglAttributeBuffer *attribute_buffer; size_t buffer_bytes; GList *attributes; } CoglVertexBufferVBO; typedef struct _CoglVertexBufferIndices { CoglHandleObject _parent; CoglIndices *indices; } CoglVertexBufferIndices; typedef struct _CoglVertexBuffer { CoglHandleObject _parent; int n_vertices; /*!< The number of vertices in the buffer */ GList *submitted_vbos; /* The VBOs currently submitted to the GPU */ /* Note: new_attributes is normally NULL and only valid while * modifying a buffer. */ GList *new_attributes; /*!< attributes pending submission */ CoglBool dirty_attributes; CoglPrimitive *primitive; } CoglVertexBuffer; #endif /* __COGL_VERTEX_BUFFER_H */ muffin-5.2.1/cogl/cogl/deprecated/cogl-framebuffer-deprecated.c0000664000175000017500000002041614211404421024557 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2014 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #include "cogl-config.h" #include "cogl-types.h" #include "cogl-context-private.h" #include "cogl-framebuffer-private.h" #include "cogl-framebuffer-deprecated.h" typedef struct _CoglFramebufferStackEntry { CoglFramebuffer *draw_buffer; CoglFramebuffer *read_buffer; } CoglFramebufferStackEntry; static CoglFramebufferStackEntry * create_stack_entry (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer) { CoglFramebufferStackEntry *entry = g_slice_new (CoglFramebufferStackEntry); entry->draw_buffer = draw_buffer; entry->read_buffer = read_buffer; return entry; } GSList * _cogl_create_framebuffer_stack (void) { CoglFramebufferStackEntry *entry; GSList *stack = NULL; entry = create_stack_entry (NULL, NULL); return g_slist_prepend (stack, entry); } void _cogl_free_framebuffer_stack (GSList *stack) { GSList *l; for (l = stack; l != NULL; l = l->next) { CoglFramebufferStackEntry *entry = l->data; if (entry->draw_buffer) cogl_object_unref (entry->draw_buffer); if (entry->read_buffer) cogl_object_unref (entry->read_buffer); g_slice_free (CoglFramebufferStackEntry, entry); } g_slist_free (stack); } static void notify_buffers_changed (CoglFramebuffer *old_draw_buffer, CoglFramebuffer *new_draw_buffer, CoglFramebuffer *old_read_buffer, CoglFramebuffer *new_read_buffer) { /* XXX: To support the deprecated cogl_set_draw_buffer API we keep * track of the last onscreen framebuffer that was set so that it * can be restored if the COGL_WINDOW_BUFFER enum is used. A * reference isn't taken to the framebuffer because otherwise we * would have a circular reference between the context and the * framebuffer. Instead the pointer is set to NULL in * _cogl_onscreen_free as a kind of a cheap weak reference */ if (new_draw_buffer && new_draw_buffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) new_draw_buffer->context->window_buffer = new_draw_buffer; } /* Set the current framebuffer without checking if it's already the * current framebuffer. This is used by cogl_pop_framebuffer while * the top of the stack is currently not up to date. */ static void _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer) { CoglFramebufferStackEntry *entry; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_RETURN_IF_FAIL (ctx != NULL); _COGL_RETURN_IF_FAIL (draw_buffer && read_buffer ? draw_buffer->context == read_buffer->context : TRUE); entry = ctx->framebuffer_stack->data; notify_buffers_changed (entry->draw_buffer, draw_buffer, entry->read_buffer, read_buffer); if (draw_buffer) cogl_object_ref (draw_buffer); if (entry->draw_buffer) cogl_object_unref (entry->draw_buffer); if (read_buffer) cogl_object_ref (read_buffer); if (entry->read_buffer) cogl_object_unref (entry->read_buffer); entry->draw_buffer = draw_buffer; entry->read_buffer = read_buffer; } static void _cogl_set_framebuffers (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer) { CoglFramebuffer *current_draw_buffer; CoglFramebuffer *current_read_buffer; _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer)); _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer)); current_draw_buffer = cogl_get_draw_framebuffer (); current_read_buffer = _cogl_get_read_framebuffer (); if (current_draw_buffer != draw_buffer || current_read_buffer != read_buffer) _cogl_set_framebuffers_real (draw_buffer, read_buffer); } void cogl_set_framebuffer (CoglFramebuffer *framebuffer) { _cogl_set_framebuffers (framebuffer, framebuffer); } /* XXX: deprecated API */ void cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (target == COGL_WINDOW_BUFFER) handle = ctx->window_buffer; /* This is deprecated public API. The public API doesn't currently really expose the concept of separate draw and read buffers so for the time being this actually just sets both buffers */ cogl_set_framebuffer (handle); } CoglFramebuffer * cogl_get_draw_framebuffer (void) { CoglFramebufferStackEntry *entry; _COGL_GET_CONTEXT (ctx, NULL); g_assert (ctx->framebuffer_stack); entry = ctx->framebuffer_stack->data; return entry->draw_buffer; } CoglFramebuffer * _cogl_get_read_framebuffer (void) { CoglFramebufferStackEntry *entry; _COGL_GET_CONTEXT (ctx, NULL); g_assert (ctx->framebuffer_stack); entry = ctx->framebuffer_stack->data; return entry->read_buffer; } void _cogl_push_framebuffers (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer) { CoglContext *ctx; CoglFramebuffer *old_draw_buffer, *old_read_buffer; _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer)); _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer)); ctx = draw_buffer->context; _COGL_RETURN_IF_FAIL (ctx != NULL); _COGL_RETURN_IF_FAIL (draw_buffer->context == read_buffer->context); _COGL_RETURN_IF_FAIL (ctx->framebuffer_stack != NULL); /* Copy the top of the stack so that when we call cogl_set_framebuffer it will still know what the old framebuffer was */ old_draw_buffer = cogl_get_draw_framebuffer (); if (old_draw_buffer) cogl_object_ref (old_draw_buffer); old_read_buffer = _cogl_get_read_framebuffer (); if (old_read_buffer) cogl_object_ref (old_read_buffer); ctx->framebuffer_stack = g_slist_prepend (ctx->framebuffer_stack, create_stack_entry (old_draw_buffer, old_read_buffer)); _cogl_set_framebuffers (draw_buffer, read_buffer); } void cogl_push_framebuffer (CoglFramebuffer *buffer) { _cogl_push_framebuffers (buffer, buffer); } /* XXX: deprecated API */ void cogl_push_draw_buffer (void) { cogl_push_framebuffer (cogl_get_draw_framebuffer ()); } void cogl_pop_framebuffer (void) { CoglFramebufferStackEntry *to_pop; CoglFramebufferStackEntry *to_restore; _COGL_GET_CONTEXT (ctx, NO_RETVAL); g_assert (ctx->framebuffer_stack != NULL); g_assert (ctx->framebuffer_stack->next != NULL); to_pop = ctx->framebuffer_stack->data; to_restore = ctx->framebuffer_stack->next->data; if (to_pop->draw_buffer != to_restore->draw_buffer || to_pop->read_buffer != to_restore->read_buffer) notify_buffers_changed (to_pop->draw_buffer, to_restore->draw_buffer, to_pop->read_buffer, to_restore->read_buffer); cogl_object_unref (to_pop->draw_buffer); cogl_object_unref (to_pop->read_buffer); g_slice_free (CoglFramebufferStackEntry, to_pop); ctx->framebuffer_stack = g_slist_delete_link (ctx->framebuffer_stack, ctx->framebuffer_stack); } /* XXX: deprecated API */ void cogl_pop_draw_buffer (void) { cogl_pop_framebuffer (); } CoglPixelFormat cogl_framebuffer_get_color_format (CoglFramebuffer *framebuffer) { return framebuffer->internal_format; } muffin-5.2.1/cogl/cogl/deprecated/cogl-clutter.h0000664000175000017500000000365314211404421021670 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_CLUTTER_H__ #define __COGL_CLUTTER_H__ COGL_BEGIN_DECLS #define cogl_clutter_check_extension cogl_clutter_check_extension_CLUTTER COGL_DEPRECATED_IN_1_16 CoglBool cogl_clutter_check_extension (const char *name, const char *ext); #define cogl_clutter_winsys_has_feature cogl_clutter_winsys_has_feature_CLUTTER COGL_DEPRECATED_FOR (cogl_has_feature) CoglBool cogl_clutter_winsys_has_feature (CoglWinsysFeature feature); #define cogl_onscreen_clutter_backend_set_size cogl_onscreen_clutter_backend_set_size_CLUTTER void cogl_onscreen_clutter_backend_set_size (int width, int height); COGL_END_DECLS #endif /* __COGL_CLUTTER_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-shader-private.h0000664000175000017500000000435214211404421023121 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_SHADER_H #define __COGL_SHADER_H #include "cogl-object-private.h" #include "cogl-shader.h" #include "cogl-gl-header.h" #include "cogl-pipeline.h" typedef struct _CoglShader CoglShader; typedef enum { COGL_SHADER_LANGUAGE_GLSL, COGL_SHADER_LANGUAGE_ARBFP } CoglShaderLanguage; struct _CoglShader { CoglHandleObject _parent; GLuint gl_handle; CoglPipeline *compilation_pipeline; CoglShaderType type; CoglShaderLanguage language; char *source; }; void _cogl_shader_compile_real (CoglHandle handle, CoglPipeline *pipeline); CoglShaderLanguage _cogl_program_get_language (CoglHandle handle); void _cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle, GLenum shader_gl_type, int n_tex_coord_attribs, GLsizei count_in, const char **strings_in, const GLint *lengths_in); #endif /* __COGL_SHADER_H */ muffin-5.2.1/cogl/cogl/deprecated/cogl-program-private.h0000664000175000017500000000552514211404421023325 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PROGRAM_H #define __COGL_PROGRAM_H #include "cogl-object-private.h" #include "cogl-shader-private.h" typedef struct _CoglProgram CoglProgram; struct _CoglProgram { CoglHandleObject _parent; GSList *attached_shaders; GArray *custom_uniforms; /* An age counter that changes whenever the list of shaders is modified */ unsigned int age; }; typedef struct _CoglProgramUniform CoglProgramUniform; struct _CoglProgramUniform { char *name; CoglBoxedValue value; /* The cached GL location for this uniform. This is only valid between calls to _cogl_program_dirty_all_uniforms */ GLint location; /* Whether we have a location yet */ unsigned int location_valid : 1; /* Whether the uniform value has changed since the last time the uniforms were flushed */ unsigned int dirty : 1; }; /* Internal function to flush the custom uniforms for the given use program. This assumes the target GL program is already bound. The gl_program still needs to be passed so that CoglProgram can query the uniform locations. gl_program_changed should be set to TRUE if we are flushing the uniforms against a different GL program from the last time it was flushed. This will cause it to requery all of the locations and assume that all uniforms are dirty */ void _cogl_program_flush_uniforms (CoglProgram *program, GLuint gl_program, CoglBool gl_program_changed); CoglShaderLanguage _cogl_program_get_language (CoglHandle handle); CoglBool _cogl_program_has_fragment_shader (CoglHandle handle); CoglBool _cogl_program_has_vertex_shader (CoglHandle handle); #endif /* __COGL_PROGRAM_H */ muffin-5.2.1/cogl/cogl/deprecated/cogl-auto-texture.c0000664000175000017500000003504214211404421022644 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2011,2012 Intel Corporation. * Copyright (C) 2010 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Matthew Allum * Neil Roberts * Robert Bragg */ #include "cogl-config.h" #include "cogl-context-private.h" #include "cogl-texture.h" #include "cogl-util.h" #include "cogl-texture-2d.h" #include "cogl-texture-2d-private.h" #include "cogl-primitive-texture.h" #include "cogl-texture-2d-sliced-private.h" #include "cogl-private.h" #include "cogl-object.h" #include "cogl-bitmap-private.h" #include "cogl-atlas-texture-private.h" #include "cogl-error-private.h" #include "cogl-texture-rectangle.h" #include "cogl-sub-texture.h" #include "cogl-texture-2d-gl.h" #include "deprecated/cogl-auto-texture.h" static CoglTexture * _cogl_texture_new_from_bitmap (CoglBitmap *bitmap, CoglTextureFlags flags, CoglPixelFormat internal_format, CoglBool can_convert_in_place, CoglError **error); static void set_auto_mipmap_cb (CoglTexture *sub_texture, const float *sub_texture_coords, const float *meta_coords, void *user_data) { cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (sub_texture), FALSE); } CoglTexture * cogl_texture_new_with_size (unsigned int width, unsigned int height, CoglTextureFlags flags, CoglPixelFormat internal_format) { CoglTexture *tex; CoglError *skip_error = NULL; _COGL_GET_CONTEXT (ctx, NULL); if ((_cogl_util_is_pot (width) && _cogl_util_is_pot (height)) || (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP))) { /* First try creating a fast-path non-sliced texture */ tex = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height)); _cogl_texture_set_internal_format (tex, internal_format); if (!cogl_texture_allocate (tex, &skip_error)) { cogl_error_free (skip_error); skip_error = NULL; cogl_object_unref (tex); tex = NULL; } } else tex = NULL; if (!tex) { /* If it fails resort to sliced textures */ int max_waste = flags & COGL_TEXTURE_NO_SLICING ? -1 : COGL_TEXTURE_MAX_WASTE; tex = COGL_TEXTURE (cogl_texture_2d_sliced_new_with_size (ctx, width, height, max_waste)); _cogl_texture_set_internal_format (tex, internal_format); } /* NB: This api existed before Cogl introduced lazy allocation of * textures and so we maintain its original synchronous allocation * semantics and return NULL if allocation fails... */ if (!cogl_texture_allocate (tex, &skip_error)) { cogl_error_free (skip_error); cogl_object_unref (tex); return NULL; } if (tex && flags & COGL_TEXTURE_NO_AUTO_MIPMAP) { cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex), 0, 0, 1, 1, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, set_auto_mipmap_cb, NULL); } return tex; } static CoglTexture * _cogl_texture_new_from_data (CoglContext *ctx, int width, int height, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, int rowstride, const uint8_t *data, CoglError **error) { CoglBitmap *bmp; CoglTexture *tex; _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); /* Rowstride from width if not given */ if (rowstride == 0) rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); /* Wrap the data into a bitmap */ bmp = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); tex = _cogl_texture_new_from_bitmap (bmp, flags, internal_format, FALSE, /* can't convert in place */ error); cogl_object_unref (bmp); return tex; } CoglTexture * cogl_texture_new_from_data (int width, int height, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, int rowstride, const uint8_t *data) { CoglError *ignore_error = NULL; CoglTexture *tex; _COGL_GET_CONTEXT (ctx, NULL); tex = _cogl_texture_new_from_data (ctx, width, height, flags, format, internal_format, rowstride, data, &ignore_error); if (!tex) cogl_error_free (ignore_error); return tex; } static CoglTexture * _cogl_texture_new_from_bitmap (CoglBitmap *bitmap, CoglTextureFlags flags, CoglPixelFormat internal_format, CoglBool can_convert_in_place, CoglError **error) { CoglContext *ctx = _cogl_bitmap_get_context (bitmap); CoglTexture *tex; CoglError *internal_error = NULL; if (!flags && !COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ATLAS)) { /* First try putting the texture in the atlas */ CoglAtlasTexture *atlas_tex = _cogl_atlas_texture_new_from_bitmap (bitmap, can_convert_in_place); _cogl_texture_set_internal_format (COGL_TEXTURE (atlas_tex), internal_format); if (cogl_texture_allocate (COGL_TEXTURE (atlas_tex), &internal_error)) return COGL_TEXTURE (atlas_tex); cogl_error_free (internal_error); internal_error = NULL; cogl_object_unref (atlas_tex); } /* If that doesn't work try a fast path 2D texture */ if ((_cogl_util_is_pot (bitmap->width) && _cogl_util_is_pot (bitmap->height)) || (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP))) { tex = COGL_TEXTURE (_cogl_texture_2d_new_from_bitmap (bitmap, can_convert_in_place)); _cogl_texture_set_internal_format (tex, internal_format); if (!cogl_texture_allocate (tex, &internal_error)) { cogl_error_free (internal_error); internal_error = NULL; cogl_object_unref (tex); tex = NULL; } } else tex = NULL; if (!tex) { /* Otherwise create a sliced texture */ int max_waste = flags & COGL_TEXTURE_NO_SLICING ? -1 : COGL_TEXTURE_MAX_WASTE; tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap, max_waste, can_convert_in_place)); _cogl_texture_set_internal_format (tex, internal_format); if (!cogl_texture_allocate (tex, error)) { cogl_object_unref (tex); tex = NULL; } } if (tex && flags & COGL_TEXTURE_NO_AUTO_MIPMAP) { cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex), 0, 0, 1, 1, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE, set_auto_mipmap_cb, NULL); } return tex; } CoglTexture * cogl_texture_new_from_bitmap (CoglBitmap *bitmap, CoglTextureFlags flags, CoglPixelFormat internal_format) { CoglError *ignore_error = NULL; CoglTexture *tex = _cogl_texture_new_from_bitmap (bitmap, flags, internal_format, FALSE, /* can't convert in-place */ &ignore_error); if (!tex) cogl_error_free (ignore_error); return tex; } CoglTexture * cogl_texture_new_from_file (const char *filename, CoglTextureFlags flags, CoglPixelFormat internal_format, CoglError **error) { CoglBitmap *bmp; CoglTexture *texture = NULL; _COGL_GET_CONTEXT (ctx, NULL); _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); bmp = cogl_bitmap_new_from_file (filename, error); if (bmp == NULL) return NULL; texture = _cogl_texture_new_from_bitmap (bmp, flags, internal_format, TRUE, /* can convert in-place */ error); cogl_object_unref (bmp); return texture; } CoglTexture * cogl_texture_new_from_foreign (GLuint gl_handle, GLenum gl_target, GLuint width, GLuint height, GLuint x_pot_waste, GLuint y_pot_waste, CoglPixelFormat format) { _COGL_GET_CONTEXT (ctx, NULL); #ifdef HAVE_COGL_GL if (gl_target == GL_TEXTURE_RECTANGLE_ARB) { CoglTextureRectangle *texture_rectangle; CoglSubTexture *sub_texture; if (x_pot_waste != 0 || y_pot_waste != 0) { /* It shouldn't be necessary to have waste in this case since * the texture isn't limited to power of two sizes. */ g_warning ("You can't create a foreign GL_TEXTURE_RECTANGLE cogl " "texture with waste\n"); return NULL; } texture_rectangle = cogl_texture_rectangle_new_from_foreign (ctx, gl_handle, width, height, format); _cogl_texture_set_internal_format (COGL_TEXTURE (texture_rectangle), format); /* CoglTextureRectangle textures work with non-normalized * coordinates, but the semantics for this function that people * depend on are that all returned texture works with normalized * coordinates so we wrap with a CoglSubTexture... */ sub_texture = cogl_sub_texture_new (ctx, COGL_TEXTURE (texture_rectangle), 0, 0, width, height); return COGL_TEXTURE (sub_texture); } #endif if (x_pot_waste != 0 || y_pot_waste != 0) { CoglTexture *tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_foreign (ctx, gl_handle, gl_target, width, height, x_pot_waste, y_pot_waste, format)); _cogl_texture_set_internal_format (tex, format); cogl_texture_allocate (tex, NULL); return tex; } else { CoglTexture *tex = COGL_TEXTURE (cogl_texture_2d_gl_new_from_foreign (ctx, gl_handle, width, height, format)); _cogl_texture_set_internal_format (tex, format); cogl_texture_allocate (tex, NULL); return tex; } } CoglTexture * cogl_texture_new_from_sub_texture (CoglTexture *full_texture, int sub_x, int sub_y, int sub_width, int sub_height) { _COGL_GET_CONTEXT (ctx, NULL); return COGL_TEXTURE (cogl_sub_texture_new (ctx, full_texture, sub_x, sub_y, sub_width, sub_height)); } muffin-5.2.1/cogl/cogl/deprecated/cogl-type-casts.h0000664000175000017500000000407214211404421022276 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_TYPE_CASTS_H__ #define __COGL_TYPE_CASTS_H__ /* The various interface types in Cogl used to be more strongly typed * which required lots type casting by developers. We provided * macros for performing these casts following a widely used Gnome * coding style. Since we now consistently typedef these interfaces * as void for the public C api and use runtime type checking to * catch programming errors the casts have become redundant and * so these macros are only kept for compatibility... */ #if !defined(COGL_ENABLE_MUFFIN_API) && !defined(COGL_GIR_SCANNING) #define COGL_FRAMEBUFFER(X) (X) #define COGL_BUFFER(X) (X) #define COGL_TEXTURE(X) (X) #define COGL_META_TEXTURE(X) (X) #define COGL_PRIMITIVE_TEXTURE(X) (X) #endif #endif /* __COGL_TYPE_CASTS_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-vertex-buffer.c0000664000175000017500000016065114211404421022767 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ /* XXX: For an overview of the functionality implemented here, please * see cogl-vertex-buffer.h, which contains the gtk-doc section overview * for the Vertex Buffers API. */ /* * TODO: We need to do a better job of minimizing when we call glVertexPointer * and pals in enable_state_for_drawing_buffer * * We should have an internal 2-tuple cache of (VBO, offset) for each of them * so we can avoid some GL calls. We could have cogl wrappers for the * gl*Pointer funcs that look like this: * * cogl_vertex_pointer (n_components, gl_type, stride, vbo, offset); * cogl_color_pointer (n_components, gl_type, stride, vbo, offset); * * They would also accept NULL for the VBO handle to support old style vertex * arrays. * * TODO: * Actually hook this up to the cogl shaders infrastructure. The vertex * buffer API has been designed to allow adding of arbitrary attributes for use * with shaders, but this has yet to be actually plumbed together and tested. * The bits we are missing: * - cogl_program_use doesn't currently record within ctx-> which program * is currently in use so a.t.m only Clutter knows the current shader. * - We don't query the current shader program for the generic vertex indices * (using glGetAttribLocation) so that we can call glEnableVertexAttribArray * with those indices. * (currently we just make up consecutive indices) * - some dirty flag mechanims to know when the shader program has changed * so we don't need to re-query it each time we draw a buffer. * * TODO * Expose API that lets developers get back a buffer handle for a particular * polygon so they may add custom attributes to them. * - It should be possible to query/modify attributes efficiently, in place, * avoiding copies. It would not be acceptable to simply require that * developers must query back the n_vertices of a buffer and then the * n_components, type and stride etc of each attribute since there * would be too many combinations to realistically handle. * * - In practice, some cases might be best solved with a higher level * EditableMesh API, (see futher below) but for many cases I think an * API like this might be appropriate: * * cogl_vertex_buffer_foreach_vertex (buffer_handle, * (AttributesBufferIteratorFunc)callback, * "gl_Vertex", "gl_Color", NULL); * static void callback (CoglVertexBufferVertex *vert) * { * GLfloat *pos = vert->attrib[0]; * GLubyte *color = vert->attrib[1]; * GLfloat *new_attrib = buf[vert->index]; * * new_attrib = pos*color; * } * * TODO * Think about a higher level Mesh API for building/modifying attribute buffers * - E.g. look at Blender for inspiration here. They can build a mesh from * "MVert", "MFace" and "MEdge" primitives. */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-vertex-buffer-private.h" #include "cogl-texture-private.h" #include "cogl-pipeline.h" #include "cogl-pipeline-private.h" #include "cogl-primitives.h" #include "cogl-framebuffer-private.h" #include "cogl-primitive-private.h" #include "cogl-journal-private.h" #include "cogl1-context.h" #include "cogl-vertex-buffer.h" #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) static void _cogl_vertex_buffer_free (CoglVertexBuffer *buffer); static void _cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices); static CoglUserDataKey _cogl_vertex_buffer_pipeline_priv_key; COGL_HANDLE_DEFINE (VertexBuffer, vertex_buffer); COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (vertex_buffer); COGL_HANDLE_DEFINE (VertexBufferIndices, vertex_buffer_indices); CoglHandle cogl_vertex_buffer_new (unsigned int n_vertices) { CoglVertexBuffer *buffer = g_slice_alloc (sizeof (CoglVertexBuffer)); buffer->n_vertices = n_vertices; buffer->submitted_vbos = NULL; buffer->new_attributes = NULL; buffer->primitive = cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES, n_vertices, NULL); /* return COGL_INVALID_HANDLE; */ return _cogl_vertex_buffer_handle_new (buffer); } unsigned int cogl_vertex_buffer_get_n_vertices (CoglHandle handle) { CoglVertexBuffer *buffer; if (!cogl_is_vertex_buffer (handle)) return 0; buffer = handle; return buffer->n_vertices; } /* There are a number of standard OpenGL attributes that we deal with * specially. These attributes are all namespaced with a "gl_" prefix * so we should catch any typos instead of silently adding a custom * attribute. */ static CoglVertexBufferAttribFlags validate_gl_attribute (const char *gl_attribute, uint8_t n_components, uint8_t *texture_unit) { CoglVertexBufferAttribFlags type; char *detail_seperator = NULL; int name_len; detail_seperator = strstr (gl_attribute, "::"); if (detail_seperator) name_len = detail_seperator - gl_attribute; else name_len = strlen (gl_attribute); if (strncmp (gl_attribute, "Vertex", name_len) == 0) { if (G_UNLIKELY (n_components == 1)) g_critical ("glVertexPointer doesn't allow 1 component vertex " "positions so we currently only support \"gl_Vertex\" " "attributes where n_components == 2, 3 or 4"); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY; } else if (strncmp (gl_attribute, "Color", name_len) == 0) { if (G_UNLIKELY (n_components != 3 && n_components != 4)) g_critical ("glColorPointer expects 3 or 4 component colors so we " "currently only support \"gl_Color\" attributes where " "n_components == 3 or 4"); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY; } else if (strncmp (gl_attribute, "MultiTexCoord", strlen ("MultiTexCoord")) == 0) { unsigned int unit; if (sscanf (gl_attribute, "MultiTexCoord%u", &unit) != 1) { g_warning ("gl_MultiTexCoord attributes should include a\n" "texture unit number, E.g. gl_MultiTexCoord0\n"); unit = 0; } /* FIXME: validate any '::' delimiter for this case */ *texture_unit = unit; type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY; } else if (strncmp (gl_attribute, "Normal", name_len) == 0) { if (G_UNLIKELY (n_components != 3)) g_critical ("glNormalPointer expects 3 component normals so we " "currently only support \"gl_Normal\" attributes where " "n_components == 3"); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY; } else { g_warning ("Unknown gl_* attribute name gl_%s\n", gl_attribute); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID; } return type; } /* There are a number of standard OpenGL attributes that we deal with * specially. These attributes are all namespaced with a "gl_" prefix * so we should catch any typos instead of silently adding a custom * attribute. */ static CoglVertexBufferAttribFlags validate_cogl_attribute (const char *cogl_attribute, uint8_t n_components, uint8_t *texture_unit) { CoglVertexBufferAttribFlags type; char *detail_seperator = NULL; int name_len; detail_seperator = strstr (cogl_attribute, "::"); if (detail_seperator) name_len = detail_seperator - cogl_attribute; else name_len = strlen (cogl_attribute); if (strncmp (cogl_attribute, "position_in", name_len) == 0) { if (G_UNLIKELY (n_components == 1)) g_critical ("glVertexPointer doesn't allow 1 component vertex " "positions so we currently only support " "\"cogl_position_in\" attributes where " "n_components == 2, 3 or 4"); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY; } else if (strncmp (cogl_attribute, "color_in", name_len) == 0) { if (G_UNLIKELY (n_components != 3 && n_components != 4)) g_critical ("glColorPointer expects 3 or 4 component colors so we " "currently only support \"cogl_color_in\" attributes " "where n_components == 3 or 4"); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY; } else if (strncmp (cogl_attribute, "cogl_tex_coord", strlen ("cogl_tex_coord")) == 0) { unsigned int unit; if (strcmp (cogl_attribute, "cogl_tex_coord_in") == 0) unit = 0; else if (sscanf (cogl_attribute, "cogl_tex_coord%u_in", &unit) != 1) { g_warning ("texture coordinate attributes should either be " "referenced as \"cogl_tex_coord_in\" or with a" "texture unit number like \"cogl_tex_coord1_in\""); unit = 0; } /* FIXME: validate any '::' delimiter for this case */ *texture_unit = unit; type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY; } else if (strncmp (cogl_attribute, "normal_in", name_len) == 0) { if (G_UNLIKELY (n_components != 3)) g_critical ("glNormalPointer expects 3 component normals so we " "currently only support \"cogl_normal_in\" attributes " "where n_components == 3"); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY; } else { g_warning ("Unknown cogl_* attribute name cogl_%s\n", cogl_attribute); type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID; } return type; } /* This validates that a custom attribute name is a valid GLSL variable name * * NB: attribute names may have a detail component delimited using '::' E.g. * custom_attrib::foo or custom_attrib::bar * * maybe I should hang a compiled regex somewhere to handle this */ static CoglBool validate_custom_attribute_name (const char *attribute_name) { char *detail_seperator = NULL; int name_len; int i; detail_seperator = strstr (attribute_name, "::"); if (detail_seperator) name_len = detail_seperator - attribute_name; else name_len = strlen (attribute_name); if (name_len == 0 || !g_ascii_isalpha (attribute_name[0]) || attribute_name[0] != '_') return FALSE; for (i = 1; i < name_len; i++) if (!g_ascii_isalnum (attribute_name[i]) || attribute_name[i] != '_') return FALSE; return TRUE; } /* Iterates the CoglVertexBufferVBOs of a buffer and creates a flat list * of all the submitted attributes * * Note: The CoglVertexBufferAttrib structs are deep copied, except the * internal CoglAttribute pointer is set to NULL. */ static GList * copy_submitted_attributes_list (CoglVertexBuffer *buffer) { GList *tmp; GList *submitted_attributes = NULL; for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) { CoglVertexBufferVBO *cogl_vbo = tmp->data; GList *tmp2; for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *attribute = tmp2->data; CoglVertexBufferAttrib *copy = g_slice_alloc (sizeof (CoglVertexBufferAttrib)); *copy = *attribute; copy->name_without_detail = g_strdup (attribute->name_without_detail); copy->attribute = NULL; submitted_attributes = g_list_prepend (submitted_attributes, copy); } } return submitted_attributes; } static size_t sizeof_attribute_type (CoglAttributeType type) { switch (type) { case COGL_ATTRIBUTE_TYPE_BYTE: return 1; case COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: return 1; case COGL_ATTRIBUTE_TYPE_SHORT: return 2; case COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: return 2; case COGL_ATTRIBUTE_TYPE_FLOAT: return 4; } g_return_val_if_reached (0); } static size_t strideof (CoglAttributeType type, int n_components) { return sizeof_attribute_type (type) * n_components; } static char * canonize_attribute_name (const char *attribute_name) { char *detail_seperator = NULL; int name_len; if (strncmp (attribute_name, "gl_", 3) != 0) return g_strdup (attribute_name); /* skip past the "gl_" */ attribute_name += 3; detail_seperator = strstr (attribute_name, "::"); if (detail_seperator) name_len = detail_seperator - attribute_name; else { name_len = strlen (attribute_name); detail_seperator = ""; } if (strncmp (attribute_name, "Vertex", name_len) == 0) return g_strconcat ("cogl_position_in", detail_seperator, NULL); else if (strncmp (attribute_name, "Color", name_len) == 0) return g_strconcat ("cogl_color_in", detail_seperator, NULL); else if (strncmp (attribute_name, "MultiTexCoord", strlen ("MultiTexCoord")) == 0) { unsigned int unit; if (sscanf (attribute_name, "MultiTexCoord%u", &unit) != 1) { g_warning ("gl_MultiTexCoord attributes should include a\n" "texture unit number, E.g. gl_MultiTexCoord0\n"); unit = 0; } return g_strdup_printf ("cogl_tex_coord%u_in%s", unit, detail_seperator); } else if (strncmp (attribute_name, "Normal", name_len) == 0) return g_strconcat ("cogl_normal_in", detail_seperator, NULL); else { g_warning ("Unknown gl_* attribute name gl_%s\n", attribute_name); return g_strdup (attribute_name); } } void cogl_vertex_buffer_add (CoglHandle handle, const char *attribute_name, uint8_t n_components, CoglAttributeType type, CoglBool normalized, uint16_t stride, const void *pointer) { CoglVertexBuffer *buffer; char *cogl_attribute_name; GQuark name_quark; CoglBool modifying_an_attrib = FALSE; CoglVertexBufferAttrib *attribute; CoglVertexBufferAttribFlags flags = 0; uint8_t texture_unit = 0; GList *tmp; char *detail; if (!cogl_is_vertex_buffer (handle)) return; buffer = handle; buffer->dirty_attributes = TRUE; cogl_attribute_name = canonize_attribute_name (attribute_name); name_quark = g_quark_from_string (cogl_attribute_name); /* The submit function works by diffing between submitted_attributes * and new_attributes to minimize the upload bandwidth + cost of * allocating new VBOs, so if there isn't already a list of new_attributes * we create one: */ if (!buffer->new_attributes) buffer->new_attributes = copy_submitted_attributes_list (buffer); /* Note: we first look for an existing attribute that we are modifying * so we may skip needing to validate the name */ for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *submitted_attribute = tmp->data; if (submitted_attribute->name == name_quark) { modifying_an_attrib = TRUE; attribute = submitted_attribute; /* since we will skip validate_gl/cogl_attribute in this case, we * need to pluck out the attribute type before overwriting the * flags: */ flags |= attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_TYPE_MASK; break; } } if (!modifying_an_attrib) { /* Validate the attribute name, is suitable as a variable name */ if (strncmp (attribute_name, "gl_", 3) == 0) { /* Note: we pass the original attribute name here so that * any warning messages correspond to the users original * attribute name... */ flags |= validate_gl_attribute (attribute_name + 3, n_components, &texture_unit); if (flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) return; } else if (strncmp (attribute_name, "cogl_", 5) == 0) { flags |= validate_cogl_attribute (attribute_name + 5, n_components, &texture_unit); if (flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) return; } else { flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY; if (validate_custom_attribute_name (attribute_name)) return; } attribute = g_slice_alloc0 (sizeof (CoglVertexBufferAttrib)); } attribute->name = name_quark; detail = strstr (cogl_attribute_name, "::"); if (detail) attribute->name_without_detail = g_strndup (cogl_attribute_name, detail - cogl_attribute_name); else attribute->name_without_detail = g_strdup (cogl_attribute_name); attribute->type = type; attribute->n_components = n_components; if (stride == 0) stride = strideof (type, n_components); attribute->stride = stride; attribute->u.pointer = pointer; attribute->texture_unit = texture_unit; attribute->attribute = NULL; flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; /* Note: We currently just assume, if an attribute is *ever* updated * then it should be taged as frequently changing. */ if (modifying_an_attrib) flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT; else flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_INFREQUENT_RESUBMIT; if (normalized) flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMALIZED; attribute->flags = flags; attribute->span_bytes = buffer->n_vertices * attribute->stride; if (!modifying_an_attrib) buffer->new_attributes = g_list_prepend (buffer->new_attributes, attribute); free (cogl_attribute_name); } static void _cogl_vertex_buffer_attrib_free (CoglVertexBufferAttrib *attribute) { if (attribute->attribute) cogl_object_unref (attribute->attribute); free (attribute->name_without_detail); g_slice_free (CoglVertexBufferAttrib, attribute); } void cogl_vertex_buffer_delete (CoglHandle handle, const char *attribute_name) { CoglVertexBuffer *buffer; char *cogl_attribute_name = canonize_attribute_name (attribute_name); GQuark name = g_quark_from_string (cogl_attribute_name); GList *tmp; free (cogl_attribute_name); if (!cogl_is_vertex_buffer (handle)) return; buffer = handle; buffer->dirty_attributes = TRUE; /* The submit function works by diffing between submitted_attributes * and new_attributes to minimize the upload bandwidth + cost of * allocating new VBOs, so if there isn't already a list of new_attributes * we create one: */ if (!buffer->new_attributes) buffer->new_attributes = copy_submitted_attributes_list (buffer); for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *submitted_attribute = tmp->data; if (submitted_attribute->name == name) { buffer->new_attributes = g_list_delete_link (buffer->new_attributes, tmp); _cogl_vertex_buffer_attrib_free (submitted_attribute); return; } } g_warning ("Failed to find an attribute named %s to delete\n", attribute_name); } static void set_attribute_enable (CoglHandle handle, const char *attribute_name, CoglBool state) { CoglVertexBuffer *buffer; char *cogl_attribute_name = canonize_attribute_name (attribute_name); GQuark name_quark = g_quark_from_string (cogl_attribute_name); GList *tmp; free (cogl_attribute_name); if (!cogl_is_vertex_buffer (handle)) return; buffer = handle; buffer->dirty_attributes = TRUE; /* NB: If a buffer is currently being edited, then there can be two seperate * lists of attributes; those that are currently submitted and a new list yet * to be submitted, we need to modify both. */ for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *attribute = tmp->data; if (attribute->name == name_quark) { if (state) attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; else attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; break; } } for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) { CoglVertexBufferVBO *cogl_vbo = tmp->data; GList *tmp2; for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *attribute = tmp2->data; if (attribute->name == name_quark) { if (state) attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; else attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; return; } } } g_warning ("Failed to %s attribute named %s/%s\n", state == TRUE ? "enable" : "disable", attribute_name, cogl_attribute_name); } void cogl_vertex_buffer_enable (CoglHandle handle, const char *attribute_name) { set_attribute_enable (handle, attribute_name, TRUE); } void cogl_vertex_buffer_disable (CoglHandle handle, const char *attribute_name) { set_attribute_enable (handle, attribute_name, FALSE); } /* Given an attribute that we know has already been submitted before, this * function looks for the existing VBO that contains it. * * Note: It will free redundant attribute struct once the corresponding * VBO has been found. */ static void filter_already_submitted_attribute (CoglVertexBufferAttrib *attribute, GList **reuse_vbos, GList **submitted_vbos) { GList *tmp; /* First check the cogl_vbos we already know are being reused since we * are more likley to get a match here */ for (tmp = *reuse_vbos; tmp != NULL; tmp = tmp->next) { CoglVertexBufferVBO *cogl_vbo = tmp->data; GList *tmp2; for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *vbo_attribute = tmp2->data; if (vbo_attribute->name == attribute->name) { vbo_attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED; /* Note: we don't free the redundant attribute here, since it * will be freed after all filtering in * cogl_vertex_buffer_submit */ return; } } } for (tmp = *submitted_vbos; tmp != NULL; tmp = tmp->next) { CoglVertexBufferVBO *cogl_vbo = tmp->data; CoglVertexBufferAttrib *reuse_attribute = NULL; GList *tmp2; for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *vbo_attribute = tmp2->data; if (vbo_attribute->name == attribute->name) { reuse_attribute = vbo_attribute; /* Note: we don't free the redundant attribute here, since it * will be freed after all filtering in * cogl_vertex_buffer_submit */ *submitted_vbos = g_list_remove_link (*submitted_vbos, tmp); tmp->next = *reuse_vbos; *reuse_vbos = tmp; break; } } if (!reuse_attribute) continue; /* Mark all but the matched attribute as UNUSED, so that when we * finish filtering all our attributes any attrributes still * marked as UNUSED can be removed from their cogl_vbo */ for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *vbo_attribute = tmp2->data; if (vbo_attribute != reuse_attribute) vbo_attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED; } return; } g_critical ("Failed to find the cogl vbo that corresponds to an\n" "attribute that had apparently already been submitted!"); } /* When we first mark a CoglVertexBufferVBO to be reused, we mark the * attributes as unsed, so that when filtering of attributes into VBOs is done * we can then prune the now unsed attributes. */ static void remove_unused_attributes (CoglVertexBufferVBO *cogl_vbo) { GList *tmp; GList *next; for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = next) { CoglVertexBufferAttrib *attribute = tmp->data; next = tmp->next; if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED) { cogl_vbo->attributes = g_list_delete_link (cogl_vbo->attributes, tmp); g_slice_free (CoglVertexBufferAttrib, attribute); } } } /* Give a newly added, strided, attribute, this function looks for a * CoglVertexBufferVBO that the attribute is interleved with. If it can't * find one then a new CoglVertexBufferVBO is allocated and added to the * list of new_strided_vbos. */ static void filter_strided_attribute (CoglVertexBufferAttrib *attribute, GList **new_vbos) { GList *tmp; CoglVertexBufferVBO *new_cogl_vbo; for (tmp = *new_vbos; tmp != NULL; tmp = tmp->next) { CoglVertexBufferVBO *cogl_vbo = tmp->data; GList *tmp2; if (!(cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED)) continue; for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *vbo_attribute = tmp2->data; const char *attribute_start = attribute->u.pointer; const char *vbo_attribute_start = vbo_attribute->u.pointer; /* NB: All attributes have buffer->n_vertices values which * simplifies determining which attributes are interleved * since we assume they will start no farther than +- a * stride away from each other: */ if (attribute_start <= (vbo_attribute_start - vbo_attribute->stride) || attribute_start >= (vbo_attribute_start + vbo_attribute->stride)) continue; /* Not interleved */ cogl_vbo->attributes = g_list_prepend (cogl_vbo->attributes, attribute); if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT) { cogl_vbo->flags &= ~COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT; cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT; } return; } } new_cogl_vbo = g_slice_alloc (sizeof (CoglVertexBufferVBO)); new_cogl_vbo->attributes = NULL; new_cogl_vbo->attributes = g_list_prepend (new_cogl_vbo->attributes, attribute); /* Any one of the interleved attributes will have the same span_bytes */ new_cogl_vbo->attribute_buffer = NULL; new_cogl_vbo->buffer_bytes = attribute->span_bytes; new_cogl_vbo->flags = COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED; if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INFREQUENT_RESUBMIT) new_cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT; else new_cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT; *new_vbos = g_list_prepend (*new_vbos, new_cogl_vbo); return; } /* This iterates through the list of submitted VBOs looking for one that * contains attribute. If found the list *link* is removed and returned */ static GList * unlink_submitted_vbo_containing_attribute (GList **submitted_vbos, CoglVertexBufferAttrib *attribute) { GList *tmp; GList *next = NULL; for (tmp = *submitted_vbos; tmp != NULL; tmp = next) { CoglVertexBufferVBO *submitted_vbo = tmp->data; GList *tmp2; next = tmp->next; for (tmp2 = submitted_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *submitted_attribute = tmp2->data; if (submitted_attribute->name == attribute->name) { *submitted_vbos = g_list_remove_link (*submitted_vbos, tmp); return tmp; } } } return NULL; } /* Unlinks all the submitted VBOs that conflict with the new cogl_vbo and * returns them as a list. */ static GList * get_submitted_vbo_conflicts (GList **submitted_vbos, CoglVertexBufferVBO *cogl_vbo) { GList *tmp; GList *conflicts = NULL; for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) { GList *link = unlink_submitted_vbo_containing_attribute (submitted_vbos, tmp->data); if (link) { /* prepend the link to the list of conflicts: */ link->next = conflicts; conflicts = link; } } return conflicts; } /* Any attributes in cogl_vbo gets removed from conflict_vbo */ static void disassociate_conflicting_attributes (CoglVertexBufferVBO *conflict_vbo, CoglVertexBufferVBO *cogl_vbo) { GList *tmp; /* NB: The attributes list in conflict_vbo will be shrinking so * we iterate those in the inner loop. */ for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *attribute = tmp->data; GList *tmp2; for (tmp2 = conflict_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) { CoglVertexBufferAttrib *conflict_attribute = tmp2->data; if (conflict_attribute->name == attribute->name) { _cogl_vertex_buffer_attrib_free (conflict_attribute); conflict_vbo->attributes = g_list_delete_link (conflict_vbo->attributes, tmp2); break; } } } } static void cogl_vertex_buffer_vbo_free (CoglVertexBufferVBO *cogl_vbo) { GList *tmp; _COGL_GET_CONTEXT (ctx, NO_RETVAL); for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) _cogl_vertex_buffer_attrib_free (tmp->data); g_list_free (cogl_vbo->attributes); if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED) cogl_object_unref (cogl_vbo->attribute_buffer); g_slice_free (CoglVertexBufferVBO, cogl_vbo); } /* This figures out the lowest attribute client pointer. (This pointer is used * to upload all the interleved attributes). * * In the process it also replaces the client pointer with the attributes * offset, and marks the attribute as submitted. */ static const void * prep_strided_vbo_for_upload (CoglVertexBufferVBO *cogl_vbo) { GList *tmp; const char *lowest_pointer = NULL; for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *attribute = tmp->data; const char *client_pointer = attribute->u.pointer; if (!lowest_pointer || client_pointer < lowest_pointer) lowest_pointer = client_pointer; } for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *attribute = tmp->data; const char *client_pointer = attribute->u.pointer; attribute->u.vbo_offset = client_pointer - lowest_pointer; attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED; } return lowest_pointer; } static CoglBool upload_multipack_vbo_via_map_buffer (CoglVertexBufferVBO *cogl_vbo) { GList *tmp; unsigned int offset = 0; uint8_t *buf; _COGL_GET_CONTEXT (ctx, FALSE); buf = cogl_buffer_map (COGL_BUFFER (cogl_vbo->attribute_buffer), COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD); if (!buf) return FALSE; for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *attribute = tmp->data; gsize attribute_size = attribute->span_bytes; gsize type_size = sizeof_attribute_type (attribute->type); PAD_FOR_ALIGNMENT (offset, type_size); memcpy (buf + offset, attribute->u.pointer, attribute_size); attribute->u.vbo_offset = offset; attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED; offset += attribute_size; } cogl_buffer_unmap (COGL_BUFFER (cogl_vbo->attribute_buffer)); return TRUE; } static void upload_multipack_vbo_via_buffer_sub_data (CoglVertexBufferVBO *cogl_vbo) { GList *l; unsigned int offset = 0; for (l = cogl_vbo->attributes; l != NULL; l = l->next) { CoglVertexBufferAttrib *attribute = l->data; gsize attribute_size = attribute->span_bytes; gsize type_size = sizeof_attribute_type (attribute->type); PAD_FOR_ALIGNMENT (offset, type_size); cogl_buffer_set_data (COGL_BUFFER (cogl_vbo->attribute_buffer), offset, attribute->u.pointer, attribute_size); attribute->u.vbo_offset = offset; attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED; offset += attribute_size; } } static void upload_attributes (CoglVertexBufferVBO *cogl_vbo) { CoglBufferUpdateHint usage; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT) usage = COGL_BUFFER_UPDATE_HINT_DYNAMIC; else usage = COGL_BUFFER_UPDATE_HINT_STATIC; cogl_buffer_set_update_hint (COGL_BUFFER (cogl_vbo->attribute_buffer), usage); if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED) { const void *pointer = prep_strided_vbo_for_upload (cogl_vbo); cogl_buffer_set_data (COGL_BUFFER (cogl_vbo->attribute_buffer), 0, /* offset */ pointer, cogl_vbo->buffer_bytes); } else /* MULTIPACK */ { /* I think it might depend on the specific driver/HW whether its better * to use glMapBuffer here or glBufferSubData here. There is even a good * thread about this topic here: * http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg35004.html * For now I have gone with glMapBuffer, but the jury is still out. */ if (!upload_multipack_vbo_via_map_buffer (cogl_vbo)) upload_multipack_vbo_via_buffer_sub_data (cogl_vbo); } cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED; } /* Note: although there ends up being quite a few inner loops involved with * resolving buffers, the number of attributes will be low so I don't expect * them to cause a problem. */ static void cogl_vertex_buffer_vbo_resolve (CoglVertexBuffer *buffer, CoglVertexBufferVBO *new_cogl_vbo, GList **final_vbos) { GList *conflicts; GList *tmp; GList *next; CoglBool found_target_vbo = FALSE; _COGL_GET_CONTEXT (ctx, NO_RETVAL); conflicts = get_submitted_vbo_conflicts (&buffer->submitted_vbos, new_cogl_vbo); for (tmp = conflicts; tmp != NULL; tmp = next) { CoglVertexBufferVBO *conflict_vbo = tmp->data; next = tmp->next; disassociate_conflicting_attributes (conflict_vbo, new_cogl_vbo); if (!conflict_vbo->attributes) { /* See if we can re-use this now empty VBO: */ if (!found_target_vbo && conflict_vbo->buffer_bytes == new_cogl_vbo->buffer_bytes) { found_target_vbo = TRUE; new_cogl_vbo->attribute_buffer = cogl_object_ref (conflict_vbo->attribute_buffer); cogl_vertex_buffer_vbo_free (conflict_vbo); upload_attributes (new_cogl_vbo); *final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo); } else cogl_vertex_buffer_vbo_free (conflict_vbo); } else { /* Relink the VBO back into buffer->submitted_vbos since it may * be involved in other conflicts later */ tmp->next = buffer->submitted_vbos; tmp->prev = NULL; buffer->submitted_vbos = tmp; } } if (!found_target_vbo) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); new_cogl_vbo->attribute_buffer = cogl_attribute_buffer_new (ctx, new_cogl_vbo->buffer_bytes, NULL); upload_attributes (new_cogl_vbo); *final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo); } } static void update_primitive_attributes (CoglVertexBuffer *buffer) { GList *l; int n_attributes = 0; CoglAttribute **attributes; int i; if (!buffer->dirty_attributes) return; buffer->dirty_attributes = FALSE; for (l = buffer->submitted_vbos; l; l = l->next) { CoglVertexBufferVBO *cogl_vbo = l->data; GList *l2; for (l2 = cogl_vbo->attributes; l2; l2 = l2->next, n_attributes++) ; } _COGL_RETURN_IF_FAIL (n_attributes > 0); attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes); i = 0; for (l = buffer->submitted_vbos; l; l = l->next) { CoglVertexBufferVBO *cogl_vbo = l->data; GList *l2; for (l2 = cogl_vbo->attributes; l2; l2 = l2->next) { CoglVertexBufferAttrib *attribute = l2->data; if (G_LIKELY (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED)) { if (G_UNLIKELY (!attribute->attribute)) { attribute->attribute = cogl_attribute_new (cogl_vbo->attribute_buffer, attribute->name_without_detail, attribute->stride, attribute->u.vbo_offset, attribute->n_components, attribute->type); } attributes[i++] = attribute->attribute; } } } cogl_primitive_set_attributes (buffer->primitive, attributes, i); } static void cogl_vertex_buffer_submit_real (CoglVertexBuffer *buffer) { GList *tmp; CoglVertexBufferVBO *new_multipack_vbo; GList *new_multipack_vbo_link; GList *new_vbos = NULL; GList *reuse_vbos = NULL; GList *final_vbos = NULL; if (!buffer->new_attributes) goto done; /* The objective now is to copy the attribute data supplied by the client * into buffer objects, but it's important to minimize the number of * redundant data uploads. * * We obviously aim to group together the attributes that are interleved so * that they can be delivered in one go to the driver. * All BOs for interleved data are created as STATIC_DRAW_ARB. * * Non interleved attributes tagged as INFREQUENT_RESUBMIT will be grouped * together back to back in a single BO created as STATIC_DRAW_ARB * * Non interleved attributes tagged as FREQUENT_RESUBMIT will be copied into * individual buffer objects, and the BO itself created DYNAMIC_DRAW_ARB * * If we are modifying a previously submitted CoglVertexBuffer then we are * carefull not to needlesly delete OpenGL buffer objects and replace with * new ones, instead we upload new data to the existing buffers. */ /* NB: We must forget attribute->pointer after submitting since the user * is free to re-use that memory for other purposes now. */ /* Pseudo code: * * Broadly speaking we start with a list of unsorted attributes, and filter * those into 'new' and 're-use' CoglVertexBufferVBO (CBO) lists. We then * take the list of new CBO structs and compare with the CBOs that have * already been submitted to the GPU (but ignoring those we already know will * be re-used) to determine what other CBOs can be re-used, due to being * superseded, and what new GL VBOs need to be created. * * We have two kinds of CBOs: * - Multi Pack CBOs * These contain multiple attributes tightly packed back to back) * - Strided CBOs * These typically contain multiple interleved sets of attributes, * though they can contain just one attribute with a stride * * First create a new-CBOs entry "new-multipack-CBO" * Tag "new-multipack-CBO" as MULTIPACK + INFREQUENT_RESUBMIT * For each unsorted attrib: * if already marked as submitted: * iterate reuse-CBOs: * if we find one that contains this attribute: * free redundant unsorted attrib struct * remove the UNUSED flag from the attrib found in the reuse-CBO * continue to next unsorted attrib * iterate submitted VBOs: * if we find one that contains this attribute: * free redundant unsorted attrib struct * unlink the vbo and move it to the list of reuse-CBOs * mark all attributes except the one just matched as UNUSED * assert (found) * continue to next unsorted attrib * if strided: * iterate the new, strided, CBOs, to see if the attribute is * interleved with one of them, if found: * add to the matched CBO * else if not found: * create a new-CBOs entry tagged STRIDED + INFREQUENT_RESUBMIT * else if unstrided && tagged with FREQUENT_RESUBMIT: * create a new-CBOs entry tagged MULTIPACK + FREQUENT_RESUBMIT * else * add to the new-multipack-CBO * free list of unsorted-attribs * * Next compare the new list of CBOs with the submitted set and try to * minimize the memory bandwidth required to upload the attributes and the * overhead of creating new GL-BOs. * * We deal with four sets of CBOs: * - The "new" CBOs * (as determined above during filtering) * - The "re-use" CBOs * (as determined above during filtering) * - The "submitted" CBOs * (I.e. ones currently submitted to the GPU) * - The "final" CBOs * (The result of resolving the differences between the above sets) * * The re-use CBOs are dealt with first, and we simply delete any remaining * attributes in these that are still marked as UNUSED, and move them * to the list of final CBOs. * * Next we iterate through the "new" CBOs, searching for conflicts * with the "submitted" CBOs and commit our decision to the "final" CBOs * * When searching for submitted entries we always unlink items from the * submitted list once we make matches (before we make descisions * based on the matches). If the CBO node is superseded it is freed, * if it is modified but may be needed for more descisions later it is * relinked back into the submitted list and if it's identical to a new * CBO it will be linked into the final list. * * At the end the list of submitted CBOs represents the attributes that were * deleted from the buffer. * * Iterate re-use-CBOs: * Iterate attribs for each: * if attrib UNUSED: * remove the attrib from the CBO + free * |Note: we could potentially mark this as a re-useable gap * |if needs be later. * add re-use CBO to the final-CBOs * Iterate new-CBOs: * List submitted CBOs conflicting with the this CBO (Unlinked items) * found-target-BO=FALSE * Iterate conflicting CBOs: * Disassociate conflicting attribs from conflicting CBO struct * If no attribs remain: * If found-target-BO!=TRUE * _AND_ If the total size of the conflicting CBO is compatible: * |Note: We don't currently consider re-using oversized buffers * found-target-BO=TRUE * upload replacement data * free submitted CBO struct * add new CBO struct to final-CBOs * else: * delete conflict GL-BO * delete conflict CBO struct * else: * relink CBO back into submitted-CBOs * * if found-target-BO == FALSE: * create a new GL-BO * upload data * add new CBO struct to final-BOs * * Iterate through the remaining "submitted" CBOs: * delete the submitted GL-BO * free the submitted CBO struct */ new_multipack_vbo = g_slice_alloc (sizeof (CoglVertexBufferVBO)); new_multipack_vbo->attribute_buffer = NULL; new_multipack_vbo->buffer_bytes = 0; new_multipack_vbo->flags = COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK | COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT; new_multipack_vbo->attributes = NULL; new_vbos = g_list_prepend (new_vbos, new_multipack_vbo); /* We save the link pointer here, just so we can do a fast removal later if * no attributes get added to this vbo. */ new_multipack_vbo_link = new_vbos; /* Start with a list of unsorted attributes, and filter those into * potential new Cogl BO structs */ for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) { CoglVertexBufferAttrib *attribute = tmp->data; if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED) { /* If the attribute is already marked as submitted, then we need * to find the existing VBO that contains it so we dont delete it. * * NB: this also frees the attribute struct since it's implicitly * redundant in this case. */ filter_already_submitted_attribute (attribute, &reuse_vbos, &buffer->submitted_vbos); } else if (attribute->stride) { /* look for a CoglVertexBufferVBO that the attribute is * interleved with. If one can't be found then a new * CoglVertexBufferVBO is allocated and added to the list of * new_vbos: */ filter_strided_attribute (attribute, &new_vbos); } else if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT) { CoglVertexBufferVBO *cogl_vbo = g_slice_alloc (sizeof (CoglVertexBufferVBO)); /* attributes we expect will be frequently resubmitted are placed * in their own VBO so that updates don't impact other attributes */ cogl_vbo->flags = COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK | COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT; cogl_vbo->attributes = NULL; cogl_vbo->attributes = g_list_prepend (cogl_vbo->attributes, attribute); cogl_vbo->attribute_buffer = NULL; cogl_vbo->buffer_bytes = attribute->span_bytes; new_vbos = g_list_prepend (new_vbos, cogl_vbo); } else { gsize type_size = sizeof_attribute_type (attribute->flags); /* Infrequently updated attributes just get packed back to back * in a single VBO: */ new_multipack_vbo->attributes = g_list_prepend (new_multipack_vbo->attributes, attribute); /* Note: we have to ensure that each run of attributes is * naturally aligned according to its data type, which may * require some padding bytes: */ /* XXX: We also have to be sure that the attributes aren't * reorderd before being uploaded because the alignment padding * is based on the adjacent attribute. */ PAD_FOR_ALIGNMENT (new_multipack_vbo->buffer_bytes, type_size); new_multipack_vbo->buffer_bytes += attribute->span_bytes; } } /* At this point all buffer->new_attributes have been filtered into * CoglVertexBufferVBOs... */ g_list_free (buffer->new_attributes); buffer->new_attributes = NULL; /* If the multipack vbo wasn't needed: */ if (new_multipack_vbo->attributes == NULL) { new_vbos = g_list_delete_link (new_vbos, new_multipack_vbo_link); g_slice_free (CoglVertexBufferVBO, new_multipack_vbo); } for (tmp = reuse_vbos; tmp != NULL; tmp = tmp->next) remove_unused_attributes (tmp->data); final_vbos = g_list_concat (final_vbos, reuse_vbos); for (tmp = new_vbos; tmp != NULL; tmp = tmp->next) cogl_vertex_buffer_vbo_resolve (buffer, tmp->data, &final_vbos); /* Anything left corresponds to deleted attributes: */ for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) cogl_vertex_buffer_vbo_free (tmp->data); g_list_free (buffer->submitted_vbos); g_list_free (new_vbos); buffer->submitted_vbos = final_vbos; done: update_primitive_attributes (buffer); } void cogl_vertex_buffer_submit (CoglHandle handle) { CoglVertexBuffer *buffer; if (!cogl_is_vertex_buffer (handle)) return; buffer = handle; cogl_vertex_buffer_submit_real (buffer); } typedef struct { /* We have a ref-count on this private structure because we need to refer to it both from the private data on a pipeline and any weak pipelines that we create from it. If we didn't have the ref count then we would depend on the order of destruction of a CoglPipeline and the weak materials to avoid a crash */ unsigned int ref_count; CoglPipeline *real_source; } VertexBufferMaterialPrivate; static void unref_pipeline_priv (VertexBufferMaterialPrivate *priv) { if (--priv->ref_count < 1) g_slice_free (VertexBufferMaterialPrivate, priv); } static void weak_override_source_destroyed_cb (CoglPipeline *pipeline, void *user_data) { VertexBufferMaterialPrivate *pipeline_priv = user_data; /* Unref the weak pipeline copy since it is no longer valid - probably because * one of its ancestors has been changed. */ cogl_object_unref (pipeline_priv->real_source); pipeline_priv->real_source = NULL; /* A reference was added when we copied the weak material so we need to unref it here */ unref_pipeline_priv (pipeline_priv); } static CoglBool validate_layer_cb (CoglPipeline *pipeline, int layer_index, void *user_data) { VertexBufferMaterialPrivate *pipeline_priv = user_data; CoglPipeline *source = pipeline_priv->real_source; if (!cogl_pipeline_get_layer_point_sprite_coords_enabled (source, layer_index)) { CoglPipelineWrapMode wrap_s; CoglPipelineWrapMode wrap_t; CoglPipelineWrapMode wrap_p; CoglBool need_override_source = FALSE; /* By default COGL_PIPELINE_WRAP_MODE_AUTOMATIC becomes * GL_CLAMP_TO_EDGE but we want GL_REPEAT to maintain * compatibility with older versions of Cogl so we'll override * it. We don't want to do this for point sprites because in * that case the whole texture is drawn so you would usually * want clamp-to-edge. */ wrap_s = cogl_pipeline_get_layer_wrap_mode_s (source, layer_index); if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { need_override_source = TRUE; wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT; } wrap_t = cogl_pipeline_get_layer_wrap_mode_t (source, layer_index); if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { need_override_source = TRUE; wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT; } wrap_p = cogl_pipeline_get_layer_wrap_mode_p (source, layer_index); if (wrap_p == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) { need_override_source = TRUE; wrap_p = COGL_PIPELINE_WRAP_MODE_REPEAT; } if (need_override_source) { if (pipeline_priv->real_source == pipeline) { pipeline_priv->ref_count++; pipeline_priv->real_source = source = _cogl_pipeline_weak_copy (pipeline, weak_override_source_destroyed_cb, pipeline_priv); } cogl_pipeline_set_layer_wrap_mode_s (source, layer_index, wrap_s); cogl_pipeline_set_layer_wrap_mode_t (source, layer_index, wrap_t); cogl_pipeline_set_layer_wrap_mode_p (source, layer_index, wrap_p); } } return TRUE; } static void destroy_pipeline_priv_cb (void *user_data) { unref_pipeline_priv (user_data); } static void update_primitive_and_draw (CoglVertexBuffer *buffer, CoglVerticesMode mode, int first, int count, CoglVertexBufferIndices *buffer_indices) { VertexBufferMaterialPrivate *pipeline_priv; CoglPipeline *users_source; _COGL_GET_CONTEXT (ctx, NO_RETVAL); cogl_primitive_set_mode (buffer->primitive, mode); cogl_primitive_set_first_vertex (buffer->primitive, first); cogl_primitive_set_n_vertices (buffer->primitive, count); if (buffer_indices) cogl_primitive_set_indices (buffer->primitive, buffer_indices->indices, count); else cogl_primitive_set_indices (buffer->primitive, NULL, count); cogl_vertex_buffer_submit_real (buffer); users_source = cogl_get_source (); pipeline_priv = cogl_object_get_user_data (COGL_OBJECT (users_source), &_cogl_vertex_buffer_pipeline_priv_key); if (G_UNLIKELY (!pipeline_priv)) { pipeline_priv = g_slice_new0 (VertexBufferMaterialPrivate); pipeline_priv->ref_count = 1; cogl_object_set_user_data (COGL_OBJECT (users_source), &_cogl_vertex_buffer_pipeline_priv_key, pipeline_priv, destroy_pipeline_priv_cb); } if (G_UNLIKELY (!pipeline_priv->real_source)) { pipeline_priv->real_source = users_source; cogl_pipeline_foreach_layer (pipeline_priv->real_source, validate_layer_cb, pipeline_priv); } /* XXX: although this may seem redundant, we need to do this since * CoglVertexBuffers can be used with legacy state and its the source stack * which track whether legacy state is enabled. * * (We only have a CoglDrawFlag to disable legacy state not one * to enable it) */ cogl_push_source (pipeline_priv->real_source); _cogl_primitive_draw (buffer->primitive, cogl_get_draw_framebuffer (), pipeline_priv->real_source, 0 /* no draw flags */); cogl_pop_source (); } void cogl_vertex_buffer_draw (CoglHandle handle, CoglVerticesMode mode, int first, int count) { CoglVertexBuffer *buffer; if (!cogl_is_vertex_buffer (handle)) return; buffer = handle; update_primitive_and_draw (buffer, mode, first, count, NULL); } static CoglHandle _cogl_vertex_buffer_indices_new_real (CoglIndices *indices) { CoglVertexBufferIndices *buffer_indices = g_slice_alloc (sizeof (CoglVertexBufferIndices)); buffer_indices->indices = indices; return _cogl_vertex_buffer_indices_handle_new (buffer_indices); } CoglHandle cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, const void *indices_array, int indices_len) { CoglIndices *indices; _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); indices = cogl_indices_new (ctx, indices_type, indices_array, indices_len); return _cogl_vertex_buffer_indices_new_real (indices); } CoglIndicesType cogl_vertex_buffer_indices_get_type (CoglHandle indices_handle) { CoglVertexBufferIndices *buffer_indices = NULL; if (!cogl_is_vertex_buffer_indices (indices_handle)) return COGL_INDICES_TYPE_UNSIGNED_SHORT; buffer_indices = indices_handle; return cogl_indices_get_type (buffer_indices->indices); } void _cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices) { cogl_object_unref (buffer_indices->indices); g_slice_free (CoglVertexBufferIndices, buffer_indices); } void cogl_vertex_buffer_draw_elements (CoglHandle handle, CoglVerticesMode mode, CoglHandle indices_handle, int min_index, int max_index, int indices_offset, int count) { CoglVertexBuffer *buffer; CoglVertexBufferIndices *buffer_indices; if (!cogl_is_vertex_buffer (handle)) return; buffer = handle; if (!cogl_is_vertex_buffer_indices (indices_handle)) return; buffer_indices = indices_handle; update_primitive_and_draw (buffer, mode, indices_offset, count, buffer_indices); } static void _cogl_vertex_buffer_free (CoglVertexBuffer *buffer) { GList *tmp; for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) cogl_vertex_buffer_vbo_free (tmp->data); g_list_free (buffer->submitted_vbos); for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) _cogl_vertex_buffer_attrib_free (tmp->data); g_list_free (buffer->new_attributes); if (buffer->primitive) cogl_object_unref (buffer->primitive); g_slice_free (CoglVertexBuffer, buffer); } CoglHandle cogl_vertex_buffer_indices_get_for_quads (unsigned int n_indices) { _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); if (n_indices <= 256 / 4 * 6) { if (ctx->quad_buffer_indices_byte == COGL_INVALID_HANDLE) { /* NB: cogl_get_quad_indices takes n_quads not n_indices... */ CoglIndices *indices = cogl_get_rectangle_indices (ctx, 256 / 4); cogl_object_ref (indices); ctx->quad_buffer_indices_byte = _cogl_vertex_buffer_indices_new_real (indices); } return ctx->quad_buffer_indices_byte; } else { if (ctx->quad_buffer_indices && ctx->quad_buffer_indices_len < n_indices) { cogl_handle_unref (ctx->quad_buffer_indices); ctx->quad_buffer_indices = COGL_INVALID_HANDLE; } if (ctx->quad_buffer_indices == COGL_INVALID_HANDLE) { /* NB: cogl_get_quad_indices takes n_quads not n_indices... */ CoglIndices *indices = cogl_get_rectangle_indices (ctx, n_indices / 6); cogl_object_ref (indices); ctx->quad_buffer_indices = _cogl_vertex_buffer_indices_new_real (indices); } ctx->quad_buffer_indices_len = n_indices; return ctx->quad_buffer_indices; } g_return_val_if_reached (NULL); } muffin-5.2.1/cogl/cogl/deprecated/cogl-shader.h0000664000175000017500000005401614211404421021453 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_SHADER_H__ #define __COGL_SHADER_H__ #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-shaders * @short_description: Fuctions for accessing the programmable GL pipeline * * Cogl allows accessing the GL programmable pipeline in order to create * vertex and fragment shaders. * * The shader source code can either be GLSL or ARBfp. If the source * code is ARBfp, it must begin with the string “!!ARBfp1.0”. The * application should check for the %COGL_FEATURE_SHADERS_GLSL or * %COGL_FEATURE_SHADERS_ARBFP features before using shaders. * * When using GLSL Cogl provides replacement names for most of the * builtin varyings and uniforms. It is recommended to use these names * wherever possible to increase portability between OpenGL 2.0 and * GLES 2.0. GLES 2.0 does not have most of the builtins under their * original names so they will only work with the Cogl names. * * For use in all GLSL shaders, the Cogl builtins are as follows: * * * * * uniform mat4 * cogl_modelview_matrix * * The current modelview matrix. This is equivalent to * #gl_ModelViewMatrix. * * * * uniform mat4 * cogl_projection_matrix * * The current projection matrix. This is equivalent to * #gl_ProjectionMatrix. * * * * uniform mat4 * cogl_modelview_projection_matrix * * The combined modelview and projection matrix. A vertex shader * would typically use this to transform the incoming vertex * position. The separate modelview and projection matrices are * usually only needed for lighting calculations. This is * equivalent to #gl_ModelViewProjectionMatrix. * * * * uniform mat4 * cogl_texture_matrix[] * * An array of matrices for transforming the texture * coordinates. This is equivalent to #gl_TextureMatrix. * * * * * * In a vertex shader, the following are also available: * * * * * attribute vec4 * cogl_position_in * * The incoming vertex position. This is equivalent to #gl_Vertex. * * * * attribute vec4 * cogl_color_in * * The incoming vertex color. This is equivalent to #gl_Color. * * * * attribute vec4 * cogl_tex_coord_in * * The texture coordinate for the first texture unit. This is * equivalent to #gl_MultiTexCoord0. * * * * attribute vec4 * cogl_tex_coord0_in * * The texture coordinate for the first texture unit. This is * equivalent to #gl_MultiTexCoord0. There is also * #cogl_tex_coord1_in and so on. * * * * attribute vec3 * cogl_normal_in * * The normal of the vertex. This is equivalent to #gl_Normal. * * * * vec4 * cogl_position_out * * The calculated position of the vertex. This must be written to * in all vertex shaders. This is equivalent to #gl_Position. * * * * float * cogl_point_size_out * * The calculated size of a point. This is equivalent to #gl_PointSize. * * * * varying vec4 * cogl_color_out * * The calculated color of a vertex. This is equivalent to #gl_FrontColor. * * * * varying vec4 * cogl_tex_coord_out[] * * An array of calculated texture coordinates for a vertex. This is * equivalent to #gl_TexCoord. * * * * * * In a fragment shader, the following are also available: * * * * * varying vec4 cogl_color_in * * The calculated color of a vertex. This is equivalent to #gl_FrontColor. * * * * varying vec4 * cogl_tex_coord_in[] * * An array of calculated texture coordinates for a vertex. This is * equivalent to #gl_TexCoord. * * * * vec4 cogl_color_out * * The final calculated color of the fragment. All fragment shaders * must write to this variable. This is equivalent to * #gl_FrontColor. * * * * float cogl_depth_out * * An optional output variable specifying the depth value to use * for this fragment. This is equivalent to #gl_FragDepth. * * * * bool cogl_front_facing * * A readonly variable that will be true if the current primitive * is front facing. This can be used to implement two-sided * coloring algorithms. This is equivalent to #gl_FrontFacing. * * * * * * It's worth nothing that this API isn't what Cogl would like to have * in the long term and it may be removed in Cogl 2.0. The * experimental #CoglShader API is the proposed replacement. */ /** * CoglShaderType: * @COGL_SHADER_TYPE_VERTEX: A program for proccessing vertices * @COGL_SHADER_TYPE_FRAGMENT: A program for processing fragments * * Types of shaders * * Since: 1.0 */ typedef enum { COGL_SHADER_TYPE_VERTEX, COGL_SHADER_TYPE_FRAGMENT } CoglShaderType; /** * cogl_create_shader: * @shader_type: COGL_SHADER_TYPE_VERTEX or COGL_SHADER_TYPE_FRAGMENT. * * Create a new shader handle, use cogl_shader_source() to set the * source code to be used on it. * * Returns: a new shader handle. * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglHandle cogl_create_shader (CoglShaderType shader_type); /** * cogl_shader_ref: * @handle: A #CoglHandle to a shader. * * Add an extra reference to a shader. * * Returns: @handle * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglHandle cogl_shader_ref (CoglHandle handle); /** * cogl_shader_unref: * @handle: A #CoglHandle to a shader. * * Removes a reference to a shader. If it was the last reference the * shader object will be destroyed. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_shader_unref (CoglHandle handle); /** * cogl_is_shader: * @handle: A CoglHandle * * Gets whether the given handle references an existing shader object. * * Returns: %TRUE if the handle references a shader, * %FALSE otherwise * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglBool cogl_is_shader (CoglHandle handle); /** * cogl_shader_source: * @shader: #CoglHandle for a shader. * @source: Shader source. * * Replaces the current source associated with a shader with a new * one. * * Please see above * for a description of the recommended format for the shader code. * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_shader_source (CoglHandle shader, const char *source); /** * cogl_shader_compile: * @handle: #CoglHandle for a shader. * * Compiles the shader, no return value, but the shader is now ready * for linking into a program. Note that calling this function is * optional. If it is not called then the shader will be automatically * compiled when it is linked. * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_shader_compile (CoglHandle handle); /** * cogl_shader_get_info_log: * @handle: #CoglHandle for a shader. * * Retrieves the information log for a coglobject, can be used in conjunction * with cogl_shader_get_parameteriv() to retrieve the compiler warnings/error * messages that caused a shader to not compile correctly, mainly useful for * debugging purposes. * * Return value: a newly allocated string containing the info log. Use * free() to free it * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) char * cogl_shader_get_info_log (CoglHandle handle); /** * cogl_shader_get_type: * @handle: #CoglHandle for a shader. * * Retrieves the type of a shader #CoglHandle * * Return value: %COGL_SHADER_TYPE_VERTEX if the shader is a vertex processor * or %COGL_SHADER_TYPE_FRAGMENT if the shader is a frament processor * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglShaderType cogl_shader_get_type (CoglHandle handle); /** * cogl_shader_is_compiled: * @handle: #CoglHandle for a shader. * * Retrieves whether a shader #CoglHandle has been compiled * * Return value: %TRUE if the shader object has sucessfully be compiled * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglBool cogl_shader_is_compiled (CoglHandle handle); /** * cogl_create_program: * * Create a new cogl program object that can be used to replace parts of the GL * rendering pipeline with custom code. * * Returns: a new cogl program. * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglHandle cogl_create_program (void); /** * cogl_program_ref: * @handle: A #CoglHandle to a program. * * Add an extra reference to a program. * * Deprecated: 1.0: Please use cogl_object_ref() instead. * * Returns: @handle */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglHandle cogl_program_ref (CoglHandle handle); /** * cogl_program_unref: * @handle: A #CoglHandle to a program. * * Removes a reference to a program. If it was the last reference the * program object will be destroyed. * * Deprecated: 1.0: Please use cogl_object_unref() instead. */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_unref (CoglHandle handle); /** * cogl_is_program: * @handle: A CoglHandle * * Gets whether the given handle references an existing program object. * * Returns: %TRUE if the handle references a program, * %FALSE otherwise * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) CoglBool cogl_is_program (CoglHandle handle); /** * cogl_program_attach_shader: * @program_handle: a #CoglHandle for a shdaer program. * @shader_handle: a #CoglHandle for a vertex of fragment shader. * * Attaches a shader to a program object. A program can have multiple * vertex or fragment shaders but only one of them may provide a * main() function. It is allowed to use a program with only a vertex * shader or only a fragment shader. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_attach_shader (CoglHandle program_handle, CoglHandle shader_handle); /** * cogl_program_link: * @handle: a #CoglHandle for a shader program. * * Links a program making it ready for use. Note that calling this * function is optional. If it is not called the program will * automatically be linked the first time it is used. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_link (CoglHandle handle); /** * cogl_program_use: * @handle: a #CoglHandle for a shader program or %COGL_INVALID_HANDLE. * * Activate a specific shader program replacing that part of the GL * rendering pipeline, if passed in %COGL_INVALID_HANDLE the default * behavior of GL is reinstated. * * This function affects the global state of the current Cogl * context. It is much more efficient to attach the shader to a * specific material used for rendering instead by calling * cogl_material_set_user_program(). * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_use (CoglHandle handle); /** * cogl_program_get_uniform_location: * @handle: a #CoglHandle for a shader program. * @uniform_name: the name of a uniform. * * Retrieve the location (offset) of a uniform variable in a shader program, * a uniform is a variable that is constant for all vertices/fragments for a * shader object and is possible to modify as an external parameter. * * Return value: the offset of a uniform in a specified program. * This uniform can be set using cogl_program_uniform_1f() when the * program is in use. * Deprecated: 1.16: Use #CoglSnippet api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) int cogl_program_get_uniform_location (CoglHandle handle, const char *uniform_name); /** * cogl_program_set_uniform_1f: * @program: A #CoglHandle for a linked program * @uniform_location: the uniform location retrieved from * cogl_program_get_uniform_location(). * @value: the new value of the uniform. * * Changes the value of a floating point uniform for the given linked * @program. * * Since: 1.4 * Deprecated: 1.16: Use #CoglSnippet api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_set_uniform_1f (CoglHandle program, int uniform_location, float value); /** * cogl_program_set_uniform_1i: * @program: A #CoglHandle for a linked program * @uniform_location: the uniform location retrieved from * cogl_program_get_uniform_location(). * @value: the new value of the uniform. * * Changes the value of an integer uniform for the given linked * @program. * * Since: 1.4 * Deprecated: 1.16: Use #CoglSnippet api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_set_uniform_1i (CoglHandle program, int uniform_location, int value); /** * cogl_program_set_uniform_float: * @program: A #CoglHandle for a linked program * @uniform_location: the uniform location retrieved from * cogl_program_get_uniform_location(). * @n_components: The number of components for the uniform. For * example with glsl you'd use 3 for a vec3 or 4 for a vec4. * @count: For uniform arrays this is the array length otherwise just * pass 1 * @value: (array length=count): the new value of the uniform[s]. * * Changes the value of a float vector uniform, or uniform array for * the given linked @program. * * Since: 1.4 * Deprecated: 1.16: Use #CoglSnippet api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_set_uniform_float (CoglHandle program, int uniform_location, int n_components, int count, const float *value); /** * cogl_program_set_uniform_int: * @program: A #CoglHandle for a linked program * @uniform_location: the uniform location retrieved from * cogl_program_get_uniform_location(). * @n_components: The number of components for the uniform. For * example with glsl you'd use 3 for a vec3 or 4 for a vec4. * @count: For uniform arrays this is the array length otherwise just * pass 1 * @value: (array length=count): the new value of the uniform[s]. * * Changes the value of a int vector uniform, or uniform array for * the given linked @program. * * Since: 1.4 * Deprecated: 1.16: Use #CoglSnippet api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_set_uniform_int (CoglHandle program, int uniform_location, int n_components, int count, const int *value); /** * cogl_program_set_uniform_matrix: * @program: A #CoglHandle for a linked program * @uniform_location: the uniform location retrieved from * cogl_program_get_uniform_location(). * @dimensions: The dimensions of the matrix. So for for example pass * 2 for a 2x2 matrix or 3 for 3x3. * @count: For uniform arrays this is the array length otherwise just * pass 1 * @transpose: Whether to transpose the matrix when setting the uniform. * @value: (array length=count): the new value of the uniform. * * Changes the value of a matrix uniform, or uniform array in the * given linked @program. * * Since: 1.4 * Deprecated: 1.16: Use #CoglSnippet api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_set_uniform_matrix (CoglHandle program, int uniform_location, int dimensions, int count, CoglBool transpose, const float *value); /** * cogl_program_uniform_1f: * @uniform_no: the uniform to set. * @value: the new value of the uniform. * * Changes the value of a floating point uniform in the currently * used (see cogl_program_use()) shader program. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_uniform_1f (int uniform_no, float value); /** * cogl_program_uniform_1i: * @uniform_no: the uniform to set. * @value: the new value of the uniform. * * Changes the value of an integer uniform in the currently * used (see cogl_program_use()) shader program. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_uniform_1i (int uniform_no, int value); /** * cogl_program_uniform_float: * @uniform_no: the uniform to set. * @size: Size of float vector. * @count: Size of array of uniforms. * @value: (array length=count): the new value of the uniform. * * Changes the value of a float vector uniform, or uniform array in the * currently used (see cogl_program_use()) shader program. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_uniform_float (int uniform_no, int size, int count, const float *value); /** * cogl_program_uniform_int: * @uniform_no: the uniform to set. * @size: Size of int vector. * @count: Size of array of uniforms. * @value: (array length=count): the new value of the uniform. * * Changes the value of a int vector uniform, or uniform array in the * currently used (see cogl_program_use()) shader program. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_uniform_int (int uniform_no, int size, int count, const int *value); /** * cogl_program_uniform_matrix: * @uniform_no: the uniform to set. * @size: Size of matrix. * @count: Size of array of uniforms. * @transpose: Whether to transpose the matrix when setting the uniform. * @value: (array length=count): the new value of the uniform. * * Changes the value of a matrix uniform, or uniform array in the * currently used (see cogl_program_use()) shader program. The @size * parameter is used to determine the square size of the matrix. * * Deprecated: 1.16: Use #CoglSnippet api */ COGL_DEPRECATED_IN_1_16_FOR (cogl_snippet_) void cogl_program_uniform_matrix (int uniform_no, int size, int count, CoglBool transpose, const float *value); COGL_END_DECLS #endif /* __COGL_SHADER_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-vertex-buffer.h0000664000175000017500000003742214211404421022773 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_VERTEX_BUFFER_H__ #define __COGL_VERTEX_BUFFER_H__ #include #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-vertex-buffer * @short_description: An API for submitting extensible arrays of vertex * attributes to be mapped into the GPU for fast drawing. * * For example to describe a textured triangle, you could create a new cogl * vertex buffer with 3 vertices, and then you might add 2 attributes for each * vertex: * * * a "gl_Position" describing the (x,y,z) position for each vertex. * * * a "gl_MultiTexCoord0" describing the (tx,ty) texture coordinates for each * vertex. * * * * The Vertex Buffer API is designed to be a fairly raw mechanism for * developers to be able to submit geometry to Cogl in a format that can be * directly consumed by an OpenGL driver and mapped into your GPU for fast * re-use. It is designed to avoid repeated validation of the attributes by the * driver; to minimize transport costs (e.g. considering indirect GLX * use-cases) and to potentially avoid repeated format conversions when * attributes are supplied in a format that is not natively supported by the * GPU. * * Although this API does allow you to modify attributes after they have been * submitted to the GPU you should be aware that modification is not that * cheap, since it implies validating the new data and potentially the * OpenGL driver will need to reformat it for the GPU. * * If at all possible think of tricks that let you re-use static attributes, * and if you do need to repeatedly update attributes (e.g. for some kind of * morphing geometry) then only update and re-submit the specific attributes * that have changed. */ /** * cogl_vertex_buffer_new: * @n_vertices: The number of vertices that your attributes will correspond to. * * Creates a new vertex buffer that you can use to add attributes. * * Return value: a new #CoglHandle * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) CoglHandle cogl_vertex_buffer_new (unsigned int n_vertices); /** * cogl_vertex_buffer_get_n_vertices: * @handle: A vertex buffer handle * * Retrieves the number of vertices that @handle represents * * Return value: the number of vertices * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) unsigned int cogl_vertex_buffer_get_n_vertices (CoglHandle handle); /** * cogl_vertex_buffer_add: * @handle: A vertex buffer handle * @attribute_name: The name of your attribute. It should be a valid GLSL * variable name and standard attribute types must use one of following * built-in names: (Note: they correspond to the built-in names of GLSL) * * "gl_Color" * "gl_Normal" * "gl_MultiTexCoord0, gl_MultiTexCoord1, ..." * "gl_Vertex" * * To support adding multiple variations of the same attribute the name * can have a detail component, E.g. "gl_Color::active" or * "gl_Color::inactive" * @n_components: The number of components per attribute and must be 1, 2, * 3 or 4 * @type: a #CoglAttributeType specifying the data type of each component. * @normalized: If %TRUE, this specifies that values stored in an integer * format should be mapped into the range [-1.0, 1.0] or [0.0, 1.0] * for unsigned values. If %FALSE they are converted to floats * directly. * @stride: This specifies the number of bytes from the start of one attribute * value to the start of the next value (for the same attribute). So, for * example, with a position interleved with color like this: * XYRGBAXYRGBAXYRGBA, then if each letter represents a byte, the * stride for both attributes is 6. The special value 0 means the * values are stored sequentially in memory. * @pointer: This addresses the first attribute in the vertex array. This * must remain valid until you either call cogl_vertex_buffer_submit() or * issue a draw call. * * Adds an attribute to a buffer, or replaces a previously added * attribute with the same name. * * You either can use one of the built-in names such as "gl_Vertex", or * "gl_MultiTexCoord0" to add standard attributes, like positions, colors * and normals, or you can add custom attributes for use in shaders. * * The number of vertices declared when calling cogl_vertex_buffer_new() * determines how many attribute values will be read from the supplied * @pointer. * * The data for your attribute isn't copied anywhere until you call * cogl_vertex_buffer_submit(), or issue a draw call which automatically * submits pending attribute changes. so the supplied pointer must remain * valid until then. If you are updating an existing attribute (done by * re-adding it) then you still need to re-call cogl_vertex_buffer_submit() * to commit the changes to the GPU. Be carefull to minimize the number * of calls to cogl_vertex_buffer_submit(), though. * * If you are interleving attributes it is assumed that each interleaved * attribute starts no farther than +- stride bytes from the other attributes * it is interleved with. I.e. this is ok: * * |-0-0-0-0-0-0-0-0-0-0| * * This is not ok: * * |- - - - -0-0-0-0-0-0 0 0 0 0| * * (Though you can have multiple groups of interleved attributes) * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) void cogl_vertex_buffer_add (CoglHandle handle, const char *attribute_name, uint8_t n_components, CoglAttributeType type, CoglBool normalized, uint16_t stride, const void *pointer); /** * cogl_vertex_buffer_delete: * @handle: A vertex buffer handle * @attribute_name: The name of a previously added attribute * * Deletes an attribute from a buffer. You will need to call * cogl_vertex_buffer_submit() or issue a draw call to commit this * change to the GPU. * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) void cogl_vertex_buffer_delete (CoglHandle handle, const char *attribute_name); /** * cogl_vertex_buffer_submit: * @handle: A vertex buffer handle * * Submits all the user added attributes to the GPU; once submitted, the * attributes can be used for drawing. * * You should aim to minimize calls to this function since it implies * validating your data; it potentially incurs a transport cost (especially if * you are using GLX indirect rendering) and potentially a format conversion * cost if the GPU doesn't natively support any of the given attribute formats. * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) void cogl_vertex_buffer_submit (CoglHandle handle); /** * cogl_vertex_buffer_disable: * @handle: A vertex buffer handle * @attribute_name: The name of the attribute you want to disable * * Disables a previosuly added attribute. * * Since it can be costly to add and remove new attributes to buffers; to make * individual buffers more reuseable it is possible to enable and disable * attributes before using a buffer for drawing. * * You don't need to call cogl_vertex_buffer_submit() after using this * function. * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) void cogl_vertex_buffer_disable (CoglHandle handle, const char *attribute_name); /** * cogl_vertex_buffer_enable: * @handle: A vertex buffer handle * @attribute_name: The name of the attribute you want to enable * * Enables a previosuly disabled attribute. * * Since it can be costly to add and remove new attributes to buffers; to make * individual buffers more reuseable it is possible to enable and disable * attributes before using a buffer for drawing. * * You don't need to call cogl_vertex_buffer_submit() after using this function * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) void cogl_vertex_buffer_enable (CoglHandle handle, const char *attribute_name); /** * cogl_vertex_buffer_draw: * @handle: A vertex buffer handle * @mode: A #CoglVerticesMode specifying how the vertices should be * interpreted. * @first: Specifies the index of the first vertex you want to draw with * @count: Specifies the number of vertices you want to draw. * * Allows you to draw geometry using all or a subset of the * vertices in a vertex buffer. * * Any un-submitted attribute changes are automatically submitted before * drawing. * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) void cogl_vertex_buffer_draw (CoglHandle handle, CoglVerticesMode mode, int first, int count); /** * cogl_vertex_buffer_indices_new: (skip) * @indices_type: a #CoglIndicesType specifying the data type used for * the indices. * @indices_array: (array length=indices_len): Specifies the address of * your array of indices * @indices_len: The number of indices in indices_array * * Depending on how much geometry you are submitting it can be worthwhile * optimizing the number of redundant vertices you submit. Using an index * array allows you to reference vertices multiple times, for example * during triangle strips. * * Return value: A CoglHandle for the indices which you can pass to * cogl_vertex_buffer_draw_elements(). * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) CoglHandle cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, const void *indices_array, int indices_len); /** * cogl_vertex_buffer_indices_get_type: * @indices: An indices handle * * Queries back the data type used for the given indices * * Returns: The CoglIndicesType used * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) CoglIndicesType cogl_vertex_buffer_indices_get_type (CoglHandle indices); /** * cogl_vertex_buffer_draw_elements: * @handle: A vertex buffer handle * @mode: A #CoglVerticesMode specifying how the vertices should be * interpreted. * @indices: A CoglHandle for a set of indices allocated via * cogl_vertex_buffer_indices_new () * @min_index: Specifies the minimum vertex index contained in indices * @max_index: Specifies the maximum vertex index contained in indices * @indices_offset: An offset into named indices. The offset marks the first * index to use for drawing. * @count: Specifies the number of vertices you want to draw. * * This function lets you use an array of indices to specify the vertices * within your vertex buffer that you want to draw. The indices themselves * are created by calling cogl_vertex_buffer_indices_new () * * Any un-submitted attribute changes are automatically submitted before * drawing. * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) void cogl_vertex_buffer_draw_elements (CoglHandle handle, CoglVerticesMode mode, CoglHandle indices, int min_index, int max_index, int indices_offset, int count); /** * cogl_vertex_buffer_ref: * @handle: a @CoglHandle. * * Increment the reference count for a vertex buffer * * Return value: the @handle. * * Deprecated: 1.2: Use cogl_object_ref() instead */ COGL_DEPRECATED_FOR (cogl_object_ref) CoglHandle cogl_vertex_buffer_ref (CoglHandle handle); /** * cogl_vertex_buffer_unref: * @handle: a @CoglHandle. * * Decrement the reference count for a vertex buffer * * Deprecated: 1.2: Use cogl_object_unref() instead */ COGL_DEPRECATED_FOR (cogl_object_unref) void cogl_vertex_buffer_unref (CoglHandle handle); /** * cogl_vertex_buffer_indices_get_for_quads: * @n_indices: the number of indices in the vertex buffer. * * Creates a vertex buffer containing the indices needed to draw pairs * of triangles from a list of vertices grouped as quads. There will * be at least @n_indices entries in the buffer (but there may be * more). * * The indices will follow this pattern: * * 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7 ... etc * * For example, if you submit vertices for a quad like like that shown * in then you can request 6 * indices to render two triangles like those shown in . * *
* Example of vertices submitted to form a quad * *
* *
* Illustration of the triangle indices that will be generated * *
* * Returns: A %CoglHandle containing the indices. The handled is * owned by Cogl and should not be modified or unref'd. * * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) CoglHandle cogl_vertex_buffer_indices_get_for_quads (unsigned int n_indices); /** * cogl_is_vertex_buffer: * @handle: a #CoglHandle for a vertex buffer object * * Checks whether @handle is a Vertex Buffer Object * * Return value: %TRUE if the handle is a VBO, and %FALSE * otherwise * * Since: 1.0 * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) CoglBool cogl_is_vertex_buffer (CoglHandle handle); /** * cogl_is_vertex_buffer_indices: * @handle: a #CoglHandle * * Checks whether @handle is a handle to the indices for a vertex * buffer object * * Return value: %TRUE if the handle is indices, and %FALSE * otherwise * * Since: 1.4 * Deprecated: 1.16: Use the #CoglPrimitive api instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_primitive_API) CoglBool cogl_is_vertex_buffer_indices (CoglHandle handle); COGL_END_DECLS #endif /* __COGL_VERTEX_BUFFER_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-framebuffer-deprecated.h0000664000175000017500000002246314211404421024570 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2014 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_FRAMEBUFFER_DEPRECATED_H__ #define __COGL_FRAMEBUFFER_DEPRECATED_H__ #include #include COGL_BEGIN_DECLS /** * cogl_set_framebuffer: (skip) * @buffer: A #CoglFramebuffer object, either onscreen or offscreen. * * This redirects all subsequent drawing to the specified framebuffer. This can * either be an offscreen buffer created with cogl_offscreen_new_to_texture () * or in the future it may be an onscreen framebuffers too. * * Since: 1.2 * Deprecated: 1.16: The latest drawing apis take explicit * #CoglFramebuffer arguments so this stack of * framebuffers shouldn't be used anymore. */ COGL_DEPRECATED_IN_1_16 void cogl_set_framebuffer (CoglFramebuffer *buffer); /** * cogl_push_framebuffer: (skip) * @buffer: A #CoglFramebuffer object, either onscreen or offscreen. * * Redirects all subsequent drawing to the specified framebuffer. This can * either be an offscreen buffer created with cogl_offscreen_new_to_texture () * or in the future it may be an onscreen framebuffer too. * * You should understand that a framebuffer owns the following state: * * The projection matrix * The modelview matrix stack * The viewport * The clip stack * * So these items will automatically be saved and restored when you * push and pop between different framebuffers. * * Also remember a newly allocated framebuffer will have an identity matrix for * the projection and modelview matrices which gives you a coordinate space * like OpenGL with (-1, -1) corresponding to the top left of the viewport, * (1, 1) corresponding to the bottom right and +z coming out towards the * viewer. * * If you want to set up a coordinate space like Clutter does with (0, 0) * corresponding to the top left and (framebuffer_width, framebuffer_height) * corresponding to the bottom right you can do so like this: * * |[ * static void * setup_viewport (unsigned int width, * unsigned int height, * float fovy, * float aspect, * float z_near, * float z_far) * { * float z_camera; * CoglMatrix projection_matrix; * CoglMatrix mv_matrix; * * cogl_set_viewport (0, 0, width, height); * cogl_perspective (fovy, aspect, z_near, z_far); * * cogl_get_projection_matrix (&projection_matrix); * z_camera = 0.5 * projection_matrix.xx; * * cogl_matrix_init_identity (&mv_matrix); * cogl_matrix_translate (&mv_matrix, -0.5f, -0.5f, -z_camera); * cogl_matrix_scale (&mv_matrix, 1.0f / width, -1.0f / height, 1.0f / width); * cogl_matrix_translate (&mv_matrix, 0.0f, -1.0 * height, 0.0f); * cogl_set_modelview_matrix (&mv_matrix); * } * * static void * my_init_framebuffer (ClutterStage *stage, * CoglFramebuffer *framebuffer, * unsigned int framebuffer_width, * unsigned int framebuffer_height) * { * ClutterPerspective perspective; * * clutter_stage_get_perspective (stage, &perspective); * * cogl_push_framebuffer (framebuffer); * setup_viewport (framebuffer_width, * framebuffer_height, * perspective.fovy, * perspective.aspect, * perspective.z_near, * perspective.z_far); * } * ]| * * The previous framebuffer can be restored by calling cogl_pop_framebuffer() * * Since: 1.2 * Deprecated: 1.16: The latest drawing apis take explicit * #CoglFramebuffer arguments so this stack of * framebuffers shouldn't be used anymore. */ COGL_DEPRECATED_IN_1_16 void cogl_push_framebuffer (CoglFramebuffer *buffer); /** * cogl_pop_framebuffer: (skip) * * Restores the framebuffer that was previously at the top of the stack. * All subsequent drawing will be redirected to this framebuffer. * * Since: 1.2 * Deprecated: 1.16: The latest drawing apis take explicit * #CoglFramebuffer arguments so this stack of * framebuffers shouldn't be used anymore. */ COGL_DEPRECATED_IN_1_16 void cogl_pop_framebuffer (void); /** * cogl_set_draw_buffer: * @target: A #CoglBufferTarget that specifies what kind of framebuffer you * are setting as the render target. * @offscreen: If you are setting a framebuffer of type COGL_OFFSCREEN_BUFFER * then this is a CoglHandle for the offscreen buffer. * * Redirects all subsequent drawing to the specified framebuffer. This * can either be an offscreen buffer created with * cogl_offscreen_new_to_texture () or you can revert to your original * on screen window buffer. * * Deprecated: 1.16: The latest drawing apis take explicit * #CoglFramebuffer arguments so this stack of * framebuffers shouldn't be used anymore. */ COGL_DEPRECATED_IN_1_16 void cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen); /** * cogl_push_draw_buffer: * * Save cogl_set_draw_buffer() state. * * Deprecated: 1.16: The latest drawing apis take explicit * #CoglFramebuffer arguments so this stack of * framebuffers shouldn't be used anymore. */ COGL_DEPRECATED_IN_1_16 void cogl_push_draw_buffer (void); /** * cogl_pop_draw_buffer: * * Restore cogl_set_draw_buffer() state. * * Deprecated: 1.16: The latest drawing apis take explicit * #CoglFramebuffer arguments so this stack of * framebuffers shouldn't be used anymore. */ COGL_DEPRECATED_IN_1_16 void cogl_pop_draw_buffer (void); /** * cogl_read_pixels: * @x: The window x position to start reading from * @y: The window y position to start reading from * @width: The width of the rectangle you want to read * @height: The height of the rectangle you want to read * @source: Identifies which auxillary buffer you want to read * (only COGL_READ_PIXELS_COLOR_BUFFER supported currently) * @format: The pixel format you want the result in * (only COGL_PIXEL_FORMAT_RGBA_8888 supported currently) * @pixels: The location to write the pixel data. * * This reads a rectangle of pixels from the current framebuffer where * position (0, 0) is the top left. The pixel at (x, y) is the first * read, and the data is returned with a rowstride of (width * 4). * * Currently Cogl assumes that the framebuffer is in a premultiplied * format so if @format is non-premultiplied it will convert it. To * read the pixel values without any conversion you should either * specify a format that doesn't use an alpha channel or use one of * the formats ending in PRE. * * Deprecated: 1.16: Use cogl_framebuffer_read_pixels() instead */ COGL_DEPRECATED_IN_1_16_FOR (cogl_framebuffer_read_pixels) void cogl_read_pixels (int x, int y, int width, int height, CoglReadPixelsFlags source, CoglPixelFormat format, uint8_t *pixels); /* XXX: Since this api was marked unstable, maybe we can just * remove this api if we can't find anyone is using it. */ /** * cogl_framebuffer_get_color_format: (skip) * @framebuffer: A #CoglFramebuffer framebuffer * * Queries the common #CoglPixelFormat of all color buffers attached * to this framebuffer. For an offscreen framebuffer created with * cogl_offscreen_new_with_texture() this will correspond to the format * of the texture. * * This API is deprecated because it is missleading to report a * #CoglPixelFormat for the internal format of the @framebuffer since * #CoglPixelFormat is such a precise format description and it's * only the set of components and the premultiplied alpha status * that is really known. * * Since: 1.8 * Stability: unstable * Deprecated 1.18: Removed since it is misleading */ COGL_DEPRECATED_IN_1_18 CoglPixelFormat cogl_framebuffer_get_color_format (CoglFramebuffer *framebuffer); COGL_END_DECLS #endif /* __COGL_FRAMEBUFFER_DEPRECATED_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-shader.c0000664000175000017500000002403314211404421021442 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-shader-private.h" #include "cogl-util-gl-private.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-glsl-shader-private.h" #include "cogl-glsl-shader-boilerplate.h" #include #include static void _cogl_shader_free (CoglShader *shader); COGL_HANDLE_DEFINE (Shader, shader); COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (shader); #ifndef GL_FRAGMENT_SHADER #define GL_FRAGMENT_SHADER 0x8B30 #endif #ifndef GL_VERTEX_SHADER #define GL_VERTEX_SHADER 0x8B31 #endif static void _cogl_shader_free (CoglShader *shader) { /* Frees shader resources but its handle is not released! Do that separately before this! */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); #ifdef HAVE_COGL_GL if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) { if (shader->gl_handle) GE (ctx, glDeletePrograms (1, &shader->gl_handle)); } else #endif if (shader->gl_handle) GE (ctx, glDeleteShader (shader->gl_handle)); g_slice_free (CoglShader, shader); } CoglHandle cogl_create_shader (CoglShaderType type) { CoglShader *shader; _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); switch (type) { case COGL_SHADER_TYPE_VERTEX: case COGL_SHADER_TYPE_FRAGMENT: break; default: g_warning ("Unexpected shader type (0x%08lX) given to " "cogl_create_shader", (unsigned long) type); return COGL_INVALID_HANDLE; } shader = g_slice_new (CoglShader); shader->language = COGL_SHADER_LANGUAGE_GLSL; shader->gl_handle = 0; shader->compilation_pipeline = NULL; shader->type = type; return _cogl_shader_handle_new (shader); } static void delete_shader (CoglShader *shader) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); #ifdef HAVE_COGL_GL if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) { if (shader->gl_handle) GE (ctx, glDeletePrograms (1, &shader->gl_handle)); } else #endif { if (shader->gl_handle) GE (ctx, glDeleteShader (shader->gl_handle)); } shader->gl_handle = 0; if (shader->compilation_pipeline) { cogl_object_unref (shader->compilation_pipeline); shader->compilation_pipeline = NULL; } } void cogl_shader_source (CoglHandle handle, const char *source) { CoglShader *shader; CoglShaderLanguage language; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!cogl_is_shader (handle)) return; shader = handle; #ifdef HAVE_COGL_GL if (strncmp (source, "!!ARBfp1.0", 10) == 0) language = COGL_SHADER_LANGUAGE_ARBFP; else #endif language = COGL_SHADER_LANGUAGE_GLSL; /* Delete the old object if the language is changing... */ if (G_UNLIKELY (language != shader->language) && shader->gl_handle) delete_shader (shader); shader->source = g_strdup (source); shader->language = language; } void cogl_shader_compile (CoglHandle handle) { CoglShader *shader; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!cogl_is_shader (handle)) return; #ifdef HAVE_COGL_GL shader = handle; if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) _cogl_shader_compile_real (handle, NULL); #endif /* XXX: For GLSL we don't actually compile anything until the shader * gets used so we have an opportunity to add some boilerplate to * the shader. * * At the end of the day this is obviously a badly designed API * given that we are having to lie to the user. It was a mistake to * so thinly wrap the OpenGL shader API and the current plan is to * replace it with a pipeline snippets API. */ } void _cogl_shader_compile_real (CoglHandle handle, CoglPipeline *pipeline) { CoglShader *shader = handle; _COGL_GET_CONTEXT (ctx, NO_RETVAL); #ifdef HAVE_COGL_GL if (shader->language == COGL_SHADER_LANGUAGE_ARBFP) { #ifdef COGL_GL_DEBUG GLenum gl_error; #endif if (shader->gl_handle) return; GE (ctx, glGenPrograms (1, &shader->gl_handle)); GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle)); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE))) g_message ("user ARBfp program:\n%s", shader->source); #ifdef COGL_GL_DEBUG _cogl_gl_util_clear_gl_errors (ctx); #endif ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen (shader->source), shader->source); #ifdef COGL_GL_DEBUG gl_error = _cogl_gl_util_get_error (ctx); if (gl_error != GL_NO_ERROR) { g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s", G_STRLOC, gl_error, shader->source, ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB)); } #endif } else #endif { GLenum gl_type; GLint status; if (shader->gl_handle) { CoglPipeline *prev = shader->compilation_pipeline; /* XXX: currently the only things that will affect the * boilerplate for user shaders, apart from driver features, * are the pipeline layer-indices and texture-unit-indices */ if (pipeline == prev || _cogl_pipeline_layer_and_unit_numbers_equal (prev, pipeline)) return; } if (shader->gl_handle) delete_shader (shader); switch (shader->type) { case COGL_SHADER_TYPE_VERTEX: gl_type = GL_VERTEX_SHADER; break; case COGL_SHADER_TYPE_FRAGMENT: gl_type = GL_FRAGMENT_SHADER; break; default: g_assert_not_reached (); break; } shader->gl_handle = ctx->glCreateShader (gl_type); _cogl_glsl_shader_set_source_with_boilerplate (ctx, shader->gl_handle, gl_type, pipeline, 1, (const char **) &shader->source, NULL); GE (ctx, glCompileShader (shader->gl_handle)); shader->compilation_pipeline = cogl_object_ref (pipeline); GE (ctx, glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status)); if (!status) { char buffer[512]; int len = 0; ctx->glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); buffer[len] = '\0'; g_warning ("Failed to compile GLSL program:\n" "src:\n%s\n" "error:\n%s\n", shader->source, buffer); } } } char * cogl_shader_get_info_log (CoglHandle handle) { if (!cogl_is_shader (handle)) return NULL; /* XXX: This API doesn't really do anything! * * This API is purely for compatibility * * The reason we don't do anything is because a shader needs to * be associated with a CoglPipeline for Cogl to be able to * compile and link anything. * * The way this API was originally designed as a very thin wrapper * over the GL api was a mistake and it's now very difficult to * make the API work in a meaningful way given how the rest of Cogl * has evolved. * * The CoglShader API is mostly deprecated by CoglSnippets and so * these days we do the bare minimum to support the existing users * of it until they are able to migrate to the snippets api. */ return g_strdup (""); } CoglShaderType cogl_shader_get_type (CoglHandle handle) { CoglShader *shader; _COGL_GET_CONTEXT (ctx, COGL_SHADER_TYPE_VERTEX); if (!cogl_is_shader (handle)) { g_warning ("Non shader handle type passed to cogl_shader_get_type"); return COGL_SHADER_TYPE_VERTEX; } shader = handle; return shader->type; } CoglBool cogl_shader_is_compiled (CoglHandle handle) { #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES2) if (!cogl_is_shader (handle)) return FALSE; /* XXX: This API doesn't really do anything! * * This API is purely for compatibility and blatantly lies to the * user about whether their shader has been compiled. * * I suppose we could say we're stretching the definition of * "compile" and are deferring any related errors to be "linker" * errors. * * The reason we don't do anything is because a shader needs to * be associated with a CoglPipeline for Cogl to be able to * compile and link anything. * * The CoglShader API is mostly deprecated by CoglSnippets and so * these days we do the bare minimum to support the existing users * of it until they are able to migrate to the snippets api. */ return TRUE; #else return FALSE; #endif } muffin-5.2.1/cogl/cogl/deprecated/cogl-material-compat.c0000664000175000017500000003300214211404421023247 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include #include #include G_DEFINE_BOXED_TYPE (CoglMaterial, cogl_material, cogl_object_ref, cogl_object_unref) CoglMaterial * cogl_material_new (void) { _COGL_GET_CONTEXT(ctx, NULL); return COGL_MATERIAL (cogl_pipeline_new (ctx)); } CoglMaterial * cogl_material_copy (CoglMaterial *source) { return COGL_MATERIAL (cogl_pipeline_copy (COGL_PIPELINE (source))); } CoglHandle cogl_material_ref (CoglHandle handle) { return cogl_object_ref (handle); } void cogl_material_unref (CoglHandle handle) { cogl_object_unref (handle); } CoglBool cogl_is_material (CoglHandle handle) { return cogl_is_pipeline (handle); } void cogl_material_set_color (CoglMaterial *material, const CoglColor *color) { cogl_pipeline_set_color (COGL_PIPELINE (material), color); } void cogl_material_set_color4ub (CoglMaterial *material, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { cogl_pipeline_set_color4ub (COGL_PIPELINE (material), red, green, blue, alpha); } void cogl_material_set_color4f (CoglMaterial *material, float red, float green, float blue, float alpha) { cogl_pipeline_set_color4f (COGL_PIPELINE (material), red, green, blue, alpha); } void cogl_material_get_color (CoglMaterial *material, CoglColor *color) { cogl_pipeline_get_color (COGL_PIPELINE (material), color); } void cogl_material_set_ambient (CoglMaterial *material, const CoglColor *ambient) { cogl_pipeline_set_ambient (COGL_PIPELINE (material), ambient); } void cogl_material_get_ambient (CoglMaterial *material, CoglColor *ambient) { cogl_pipeline_get_ambient (COGL_PIPELINE (material), ambient); } void cogl_material_set_diffuse (CoglMaterial *material, const CoglColor *diffuse) { cogl_pipeline_set_diffuse (COGL_PIPELINE (material), diffuse); } void cogl_material_get_diffuse (CoglMaterial *material, CoglColor *diffuse) { cogl_pipeline_get_diffuse (COGL_PIPELINE (material), diffuse); } void cogl_material_set_ambient_and_diffuse (CoglMaterial *material, const CoglColor *color) { cogl_pipeline_set_ambient_and_diffuse (COGL_PIPELINE (material), color); } void cogl_material_set_specular (CoglMaterial *material, const CoglColor *specular) { cogl_pipeline_set_specular (COGL_PIPELINE (material), specular); } void cogl_material_get_specular (CoglMaterial *material, CoglColor *specular) { cogl_pipeline_get_specular (COGL_PIPELINE (material), specular); } void cogl_material_set_shininess (CoglMaterial *material, float shininess) { cogl_pipeline_set_shininess (COGL_PIPELINE (material), shininess); } float cogl_material_get_shininess (CoglMaterial *material) { return cogl_pipeline_get_shininess (COGL_PIPELINE (material)); } void cogl_material_set_emission (CoglMaterial *material, const CoglColor *emission) { cogl_pipeline_set_emission (COGL_PIPELINE (material), emission); } void cogl_material_get_emission (CoglMaterial *material, CoglColor *emission) { cogl_pipeline_get_emission (COGL_PIPELINE (material), emission); } void cogl_material_set_alpha_test_function (CoglMaterial *material, CoglMaterialAlphaFunc alpha_func, float alpha_reference) { cogl_pipeline_set_alpha_test_function (COGL_PIPELINE (material), alpha_func, alpha_reference); } CoglBool cogl_material_set_blend (CoglMaterial *material, const char *blend_string, CoglError **error) { return cogl_pipeline_set_blend (COGL_PIPELINE (material), blend_string, error); } void cogl_material_set_blend_constant (CoglMaterial *material, const CoglColor *constant_color) { cogl_pipeline_set_blend_constant (COGL_PIPELINE (material), constant_color); } void cogl_material_set_point_size (CoglMaterial *material, float point_size) { cogl_pipeline_set_point_size (COGL_PIPELINE (material), point_size); } float cogl_material_get_point_size (CoglMaterial *material) { return cogl_pipeline_get_point_size (COGL_PIPELINE (material)); } CoglHandle cogl_material_get_user_program (CoglMaterial *material) { return cogl_pipeline_get_user_program (COGL_PIPELINE (material)); } void cogl_material_set_user_program (CoglMaterial *material, CoglHandle program) { cogl_pipeline_set_user_program (COGL_PIPELINE (material), program); } void cogl_material_set_layer (CoglMaterial *material, int layer_index, CoglHandle texture) { cogl_pipeline_set_layer_texture (COGL_PIPELINE (material), layer_index, texture); } void cogl_material_remove_layer (CoglMaterial *material, int layer_index) { cogl_pipeline_remove_layer (COGL_PIPELINE (material), layer_index); } CoglBool cogl_material_set_layer_combine (CoglMaterial *material, int layer_index, const char *blend_string, CoglError **error) { return cogl_pipeline_set_layer_combine (COGL_PIPELINE (material), layer_index, blend_string, error); } void cogl_material_set_layer_combine_constant (CoglMaterial *material, int layer_index, const CoglColor *constant) { cogl_pipeline_set_layer_combine_constant (COGL_PIPELINE (material), layer_index, constant); } void cogl_material_set_layer_matrix (CoglMaterial *material, int layer_index, const CoglMatrix *matrix) { cogl_pipeline_set_layer_matrix (COGL_PIPELINE (material), layer_index, matrix); } const GList * cogl_material_get_layers (CoglMaterial *material) { return _cogl_pipeline_get_layers (COGL_PIPELINE (material)); } int cogl_material_get_n_layers (CoglMaterial *material) { return cogl_pipeline_get_n_layers (COGL_PIPELINE (material)); } CoglMaterialLayerType cogl_material_layer_get_type (CoglMaterialLayer *layer) { return COGL_MATERIAL_LAYER_TYPE_TEXTURE; } CoglHandle cogl_material_layer_get_texture (CoglMaterialLayer *layer) { return _cogl_pipeline_layer_get_texture (COGL_PIPELINE_LAYER (layer)); } CoglMaterialFilter cogl_material_layer_get_min_filter (CoglMaterialLayer *layer) { return _cogl_pipeline_layer_get_min_filter (COGL_PIPELINE_LAYER (layer)); } CoglMaterialFilter cogl_material_layer_get_mag_filter (CoglMaterialLayer *layer) { return _cogl_pipeline_layer_get_mag_filter (COGL_PIPELINE_LAYER (layer)); } void cogl_material_set_layer_filters (CoglMaterial *material, int layer_index, CoglMaterialFilter min_filter, CoglMaterialFilter mag_filter) { cogl_pipeline_set_layer_filters (COGL_PIPELINE (material), layer_index, min_filter, mag_filter); } CoglBool cogl_material_set_layer_point_sprite_coords_enabled (CoglMaterial *material, int layer_index, CoglBool enable, CoglError **error) { CoglPipeline *pipeline = COGL_PIPELINE (material); return cogl_pipeline_set_layer_point_sprite_coords_enabled (pipeline, layer_index, enable, error); } CoglBool cogl_material_get_layer_point_sprite_coords_enabled (CoglMaterial *material, int layer_index) { CoglPipeline *pipeline = COGL_PIPELINE (material); return cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline, layer_index); } CoglMaterialWrapMode cogl_material_get_layer_wrap_mode_s (CoglMaterial *material, int layer_index) { return cogl_pipeline_get_layer_wrap_mode_s (COGL_PIPELINE (material), layer_index); } void cogl_material_set_layer_wrap_mode_s (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode) { cogl_pipeline_set_layer_wrap_mode_s (COGL_PIPELINE (material), layer_index, mode); } CoglMaterialWrapMode cogl_material_get_layer_wrap_mode_t (CoglMaterial *material, int layer_index) { return cogl_pipeline_get_layer_wrap_mode_t (COGL_PIPELINE (material), layer_index); } void cogl_material_set_layer_wrap_mode_t (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode) { cogl_pipeline_set_layer_wrap_mode_t (COGL_PIPELINE (material), layer_index, mode); } CoglMaterialWrapMode cogl_material_get_layer_wrap_mode_p (CoglMaterial *material, int layer_index) { return cogl_pipeline_get_layer_wrap_mode_p (COGL_PIPELINE (material), layer_index); } void cogl_material_set_layer_wrap_mode_p (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode) { cogl_pipeline_set_layer_wrap_mode_p (COGL_PIPELINE (material), layer_index, mode); } void cogl_material_set_layer_wrap_mode (CoglMaterial *material, int layer_index, CoglMaterialWrapMode mode) { cogl_pipeline_set_layer_wrap_mode (COGL_PIPELINE (material), layer_index, mode); } CoglMaterialWrapMode cogl_material_layer_get_wrap_mode_s (CoglMaterialLayer *layer) { return _cogl_pipeline_layer_get_wrap_mode_s (COGL_PIPELINE_LAYER (layer)); } CoglMaterialWrapMode cogl_material_layer_get_wrap_mode_t (CoglMaterialLayer *layer) { return _cogl_pipeline_layer_get_wrap_mode_t (COGL_PIPELINE_LAYER (layer)); } CoglMaterialWrapMode cogl_material_layer_get_wrap_mode_p (CoglMaterialLayer *layer) { return _cogl_pipeline_layer_get_wrap_mode_p (COGL_PIPELINE_LAYER (layer)); } void cogl_material_foreach_layer (CoglMaterial *material, CoglMaterialLayerCallback callback, void *user_data) { cogl_pipeline_foreach_layer (COGL_PIPELINE (material), (CoglPipelineLayerCallback)callback, user_data); } CoglBool cogl_material_set_depth_state (CoglMaterial *material, const CoglDepthState *state, CoglError **error) { return cogl_pipeline_set_depth_state (COGL_PIPELINE (material), state, error); } void cogl_material_get_depth_state (CoglMaterial *material, CoglDepthState *state_out) { cogl_pipeline_get_depth_state (COGL_PIPELINE (material), state_out); } muffin-5.2.1/cogl/cogl/deprecated/cogl-auto-texture.h0000664000175000017500000002151414211404421022650 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2014 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_AUTO_TEXTURE_H__ #define __COGL_AUTO_TEXTURE_H__ COGL_BEGIN_DECLS #include /** * cogl_texture_new_with_size: * @width: width of texture in pixels. * @height: height of texture in pixels. * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture. * * Creates a new #CoglTexture with the specified dimensions and pixel format. * * Return value: (transfer full): A newly created #CoglTexture or %NULL on failure * * Since: 0.8 * Deprecated: 1.18: Use specific constructors such as * cogl_texture_2d_new_with_size() */ COGL_DEPRECATED_IN_1_18_FOR(cogl_texture_2d_new_with_size__OR__cogl_texture_2d_sliced_new_with_size) CoglTexture * cogl_texture_new_with_size (unsigned int width, unsigned int height, CoglTextureFlags flags, CoglPixelFormat internal_format); /** * cogl_texture_new_from_file: * @filename: the file to load * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture. If %COGL_PIXEL_FORMAT_ANY is given then a premultiplied * format similar to the format of the source data will be used. The * default blending equations of Cogl expect premultiplied color data; * the main use of passing a non-premultiplied format here is if you * have non-premultiplied source data and are going to adjust the blend * mode (see cogl_material_set_blend()) or use the data for something * other than straight blending. * @error: return location for a #CoglError or %NULL * * Creates a #CoglTexture from an image file. * * Return value: (transfer full): A newly created #CoglTexture or * %NULL on failure * * Since: 0.8 * Deprecated: 1.18: Use specific constructors such as * cogl_texture_2d_new_from_file() */ COGL_DEPRECATED_IN_1_18_FOR(cogl_texture_2d_new_from_file__OR__cogl_texture_2d_sliced_new_from_file) CoglTexture * cogl_texture_new_from_file (const char *filename, CoglTextureFlags flags, CoglPixelFormat internal_format, CoglError **error); /** * cogl_texture_new_from_data: * @width: width of texture in pixels * @height: height of texture in pixels * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @format: the #CoglPixelFormat the buffer is stored in in RAM * @internal_format: the #CoglPixelFormat that will be used for storing * the buffer on the GPU. If COGL_PIXEL_FORMAT_ANY is given then a * premultiplied format similar to the format of the source data will * be used. The default blending equations of Cogl expect premultiplied * color data; the main use of passing a non-premultiplied format here * is if you have non-premultiplied source data and are going to adjust * the blend mode (see cogl_material_set_blend()) or use the data for * something other than straight blending. * @rowstride: the memory offset in bytes between the starts of * scanlines in @data * @data: pointer the memory region where the source buffer resides * * Creates a new #CoglTexture based on data residing in memory. * * Return value: (transfer full): A newly created #CoglTexture or * %NULL on failure * * Since: 0.8 * Deprecated: 1.18: Use specific constructors such as * cogl_texture_2d_new_from_data() */ COGL_DEPRECATED_IN_1_18_FOR(cogl_texture_2d_new_from_data__OR__cogl_texture_2d_sliced_new_from_data) CoglTexture * cogl_texture_new_from_data (int width, int height, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, int rowstride, const uint8_t *data); /** * cogl_texture_new_from_foreign: * @gl_handle: opengl handle of foreign texture. * @gl_target: opengl target type of foreign texture * @width: width of foreign texture * @height: height of foreign texture. * @x_pot_waste: horizontal waste on the right hand edge of the texture. * @y_pot_waste: vertical waste on the bottom edge of the texture. * @format: format of the foreign texture. * * Creates a #CoglTexture based on an existing OpenGL texture; the * width, height and format are passed along since it is not always * possible to query these from OpenGL. * * The waste arguments allow you to create a Cogl texture that maps to * a region smaller than the real OpenGL texture. For instance if your * hardware only supports power-of-two textures you may load a * non-power-of-two image into a larger power-of-two texture and use * the waste arguments to tell Cogl which region should be mapped to * the texture coordinate range [0:1]. * * Return value: (transfer full): A newly created #CoglTexture or * %NULL on failure * * Since: 0.8 * Deprecated: 1.18: Use specific constructors such as * cogl_texture_2d_new_from_foreign() */ COGL_DEPRECATED_IN_1_18_FOR(cogl_texture_2d_new_from_foreign) CoglTexture * cogl_texture_new_from_foreign (unsigned int gl_handle, unsigned int gl_target, unsigned int width, unsigned int height, unsigned int x_pot_waste, unsigned int y_pot_waste, CoglPixelFormat format); /** * cogl_texture_new_from_bitmap: * @bitmap: A #CoglBitmap pointer * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture * * Creates a #CoglTexture from a #CoglBitmap. * * Return value: (transfer full): A newly created #CoglTexture or * %NULL on failure * * Since: 1.0 * Deprecated: 1.18: Use specific constructors such as * cogl_texture_2d_new_from_bitmap() */ COGL_DEPRECATED_IN_1_18_FOR(cogl_texture_2d_new_from_bitmap__OR__cogl_texture_2d_sliced_new_from_bitmap) CoglTexture * cogl_texture_new_from_bitmap (CoglBitmap *bitmap, CoglTextureFlags flags, CoglPixelFormat internal_format); /** * cogl_texture_new_from_sub_texture: * @full_texture: a #CoglTexture pointer * @sub_x: X coordinate of the top-left of the subregion * @sub_y: Y coordinate of the top-left of the subregion * @sub_width: Width in pixels of the subregion * @sub_height: Height in pixels of the subregion * * Creates a new texture which represents a subregion of another * texture. The GL resources will be shared so that no new texture * data is actually allocated. * * Sub textures have undefined behaviour texture coordinates outside * of the range [0,1] are used. They also do not work with * CoglVertexBuffers. * * The sub texture will keep a reference to the full texture so you do * not need to keep one separately if you only want to use the sub * texture. * * Return value: (transfer full): A newly created #CoglTexture or * %NULL on failure * Since: 1.2 * Deprecated: 1.18: Use cogl_sub_texture_new() */ COGL_DEPRECATED_IN_1_18_FOR(cogl_sub_texture_new) CoglTexture * cogl_texture_new_from_sub_texture (CoglTexture *full_texture, int sub_x, int sub_y, int sub_width, int sub_height); COGL_END_DECLS #endif /* __COGL_AUTO_TEXTURE_H__ */ muffin-5.2.1/cogl/cogl/deprecated/cogl-clutter.c0000664000175000017500000000564414211404421021665 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include "cogl-util.h" #include "cogl-types.h" #include "cogl-private.h" #include "cogl-context-private.h" #include "cogl-winsys-private.h" #include "cogl-winsys-stub-private.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-private.h" #ifdef COGL_HAS_XLIB_SUPPORT #include "cogl-clutter-xlib.h" #include "cogl-xlib-renderer.h" #endif #include "cogl-clutter.h" CoglBool cogl_clutter_check_extension (const char *name, const char *ext) { char *end; int name_len, n; if (name == NULL || ext == NULL) return FALSE; end = (char*)(ext + strlen(ext)); name_len = strlen(name); while (ext < end) { n = strcspn(ext, " "); if ((name_len == n) && (!strncmp(name, ext, n))) return TRUE; ext += (n + 1); } return FALSE; } CoglBool cogl_clutter_winsys_has_feature (CoglWinsysFeature feature) { return _cogl_winsys_has_feature (feature); } void cogl_onscreen_clutter_backend_set_size (int width, int height) { CoglFramebuffer *framebuffer; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (_cogl_context_get_winsys (ctx) != _cogl_winsys_stub_get_vtable ()) return; framebuffer = COGL_FRAMEBUFFER (ctx->window_buffer); _cogl_framebuffer_winsys_update_size (framebuffer, width, height); } #ifdef COGL_HAS_XLIB_SUPPORT XVisualInfo * cogl_clutter_winsys_xlib_get_visual_info (void) { CoglRenderer *renderer; _COGL_GET_CONTEXT (ctx, NULL); _COGL_RETURN_VAL_IF_FAIL (ctx->display != NULL, NULL); renderer = cogl_display_get_renderer (ctx->display); _COGL_RETURN_VAL_IF_FAIL (renderer != NULL, NULL); return cogl_xlib_renderer_get_visual_info (renderer); } #endif muffin-5.2.1/cogl/cogl/cogl-pixel-buffer-private.h0000664000175000017500000000311214211404421022134 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Damien Lespiau * Robert Bragg */ #ifndef __COGL_PIXEL_BUFFER_PRIVATE_H__ #define __COGL_PIXEL_BUFFER_PRIVATE_H__ #include "cogl-object-private.h" #include "cogl-buffer-private.h" #include COGL_BEGIN_DECLS struct _CoglPixelBuffer { CoglBuffer _parent; }; COGL_END_DECLS #endif /* __COGL_PIXEL_BUFFER_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-pipeline-snippet.c0000664000175000017500000002145414211404421021365 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011, 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-types.h" #include "cogl-pipeline-snippet-private.h" #include "cogl-snippet-private.h" #include "cogl-util.h" /* Helper functions that are used by both GLSL pipeline backends */ void _cogl_pipeline_snippet_generate_code (const CoglPipelineSnippetData *data) { GList *first_snippet, *l; CoglSnippet *snippet; int snippet_num = 0; int n_snippets = 0; first_snippet = data->snippets->entries; /* First count the number of snippets so we can easily tell when we're at the last one */ for (l = data->snippets->entries; l; l = l->next) { snippet = l->data; if (snippet->hook == data->hook) { /* Don't bother processing any previous snippets if we reach one that has a replacement */ if (snippet->replace) { n_snippets = 1; first_snippet = l; } else n_snippets++; } } /* If there weren't any snippets then generate a stub function with the final name */ if (n_snippets == 0) { if (data->return_type) g_string_append_printf (data->source_buf, "\n" "%s\n" "%s (%s)\n" "{\n" " return %s (%s);\n" "}\n", data->return_type, data->final_name, data->argument_declarations ? data->argument_declarations : "", data->chain_function, data->arguments ? data->arguments : ""); else g_string_append_printf (data->source_buf, "\n" "void\n" "%s (%s)\n" "{\n" " %s (%s);\n" "}\n", data->final_name, data->argument_declarations ? data->argument_declarations : "", data->chain_function, data->arguments ? data->arguments : ""); return; } for (l = first_snippet; snippet_num < n_snippets; l = l->next) { snippet = l->data; if (snippet->hook == data->hook) { const char *source; if ((source = cogl_snippet_get_declarations (snippet))) g_string_append (data->source_buf, source); g_string_append_printf (data->source_buf, "\n" "%s\n", data->return_type ? data->return_type : "void"); if (snippet_num + 1 < n_snippets) g_string_append_printf (data->source_buf, "%s_%i", data->function_prefix, snippet_num); else g_string_append (data->source_buf, data->final_name); g_string_append (data->source_buf, " ("); if (data->argument_declarations) g_string_append (data->source_buf, data->argument_declarations); g_string_append (data->source_buf, ")\n" "{\n"); if (data->return_type && !data->return_variable_is_argument) g_string_append_printf (data->source_buf, " %s %s;\n" "\n", data->return_type, data->return_variable); if ((source = cogl_snippet_get_pre (snippet))) g_string_append (data->source_buf, source); /* Chain on to the next function, or bypass it if there is a replace string */ if ((source = cogl_snippet_get_replace (snippet))) g_string_append (data->source_buf, source); else { g_string_append (data->source_buf, " "); if (data->return_type) g_string_append_printf (data->source_buf, "%s = ", data->return_variable); if (snippet_num > 0) g_string_append_printf (data->source_buf, "%s_%i", data->function_prefix, snippet_num - 1); else g_string_append (data->source_buf, data->chain_function); g_string_append (data->source_buf, " ("); if (data->arguments) g_string_append (data->source_buf, data->arguments); g_string_append (data->source_buf, ");\n"); } if ((source = cogl_snippet_get_post (snippet))) g_string_append (data->source_buf, source); if (data->return_type) g_string_append_printf (data->source_buf, " return %s;\n", data->return_variable); g_string_append (data->source_buf, "}\n"); snippet_num++; } } } void _cogl_pipeline_snippet_generate_declarations (GString *declarations_buf, CoglSnippetHook hook, CoglPipelineSnippetList *snippets) { GList *l; for (l = snippets->entries; l; l = l->next) { CoglSnippet *snippet = l->data; if (snippet->hook == hook) { const char *source; if ((source = cogl_snippet_get_declarations (snippet))) g_string_append (declarations_buf, source); } } } void _cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list) { GList *l, *tmp; for (l = list->entries; l; l = tmp) { tmp = l->next; cogl_object_unref (l->data); g_list_free_1 (l); } } void _cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list, CoglSnippet *snippet) { list->entries = g_list_append (list->entries, cogl_object_ref (snippet)); _cogl_snippet_make_immutable (snippet); } void _cogl_pipeline_snippet_list_copy (CoglPipelineSnippetList *dst, const CoglPipelineSnippetList *src) { GQueue queue = G_QUEUE_INIT; const GList *l; for (l = src->entries; l; l = l->next) g_queue_push_tail (&queue, cogl_object_ref (l->data)); dst->entries = queue.head; } void _cogl_pipeline_snippet_list_hash (CoglPipelineSnippetList *list, unsigned int *hash) { GList *l; for (l = list->entries; l; l = l->next) { CoglSnippet *snippet = l->data; *hash = _cogl_util_one_at_a_time_hash (*hash, &snippet, sizeof (CoglSnippet *)); } } CoglBool _cogl_pipeline_snippet_list_equal (CoglPipelineSnippetList *list0, CoglPipelineSnippetList *list1) { GList *l0, *l1; for (l0 = list0->entries, l1 = list1->entries; l0 && l1; l0 = l0->next, l1 = l1->next) if (l0->data != l1->data) return FALSE; return l0 == NULL && l1 == NULL; } muffin-5.2.1/cogl/cogl/cogl-onscreen-template-private.h0000664000175000017500000000276214211404421023203 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_ONSCREEN_TEMPLATE_PRIVATE_H #define __COGL_ONSCREEN_TEMPLATE_PRIVATE_H #include "cogl-object-private.h" #include "cogl-swap-chain.h" #include "cogl-framebuffer-private.h" struct _CoglOnscreenTemplate { CoglObject _parent; CoglFramebufferConfig config; }; #endif /* __COGL_ONSCREEN_TEMPLATE_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-x11-renderer-private.h0000664000175000017500000000257714211404421021777 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_RENDERER_X11_PRIVATE_H #define __COGL_RENDERER_X11_PRIVATE_H typedef struct _CoglX11Renderer { int damage_base; int randr_base; } CoglX11Renderer; #endif /* __COGL_RENDERER_X11_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-atlas-texture.c0000664000175000017500000011125514211404421020701 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-util.h" #include "cogl-texture-private.h" #include "cogl-atlas-texture-private.h" #include "cogl-texture-2d-private.h" #include "cogl-sub-texture-private.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-texture-driver.h" #include "cogl-rectangle-map.h" #include "cogl-journal-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-atlas.h" #include "cogl1-context.h" #include "cogl-sub-texture.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" #include "cogl-gtype-private.h" #include static void _cogl_atlas_texture_free (CoglAtlasTexture *sub_tex); COGL_TEXTURE_DEFINE (AtlasTexture, atlas_texture); COGL_GTYPE_DEFINE_CLASS (AtlasTexture, atlas_texture); static const CoglTextureVtable cogl_atlas_texture_vtable; static CoglSubTexture * _cogl_atlas_texture_create_sub_texture (CoglTexture *full_texture, const CoglRectangleMapEntry *rectangle) { CoglContext *ctx = full_texture->context; /* Create a subtexture for the given rectangle not including the 1-pixel border */ return cogl_sub_texture_new (ctx, full_texture, rectangle->x + 1, rectangle->y + 1, rectangle->width - 2, rectangle->height - 2); } static void _cogl_atlas_texture_update_position_cb (void *user_data, CoglTexture *new_texture, const CoglRectangleMapEntry *rectangle) { CoglAtlasTexture *atlas_tex = user_data; /* Update the sub texture */ if (atlas_tex->sub_texture) cogl_object_unref (atlas_tex->sub_texture); atlas_tex->sub_texture = COGL_TEXTURE ( _cogl_atlas_texture_create_sub_texture (new_texture, rectangle)); /* Update the position */ atlas_tex->rectangle = *rectangle; } static void _cogl_atlas_texture_pre_reorganize_foreach_cb (const CoglRectangleMapEntry *entry, void *rectangle_data, void *user_data) { CoglAtlasTexture *atlas_tex = rectangle_data; /* Keep a reference to the texture because we don't want it to be destroyed during the reorganization */ cogl_object_ref (atlas_tex); /* Notify cogl-pipeline.c that the texture's underlying GL texture * storage is changing so it knows it may need to bind a new texture * if the CoglTexture is reused with the same texture unit. */ _cogl_pipeline_texture_storage_change_notify (COGL_TEXTURE (atlas_tex)); } static void _cogl_atlas_texture_pre_reorganize_cb (void *data) { CoglAtlas *atlas = data; /* We don't know if any journal entries currently depend on OpenGL * texture coordinates that would be invalidated by reorganizing * this atlas so we flush all journals before migrating. * * We are assuming that texture atlas migration never happens * during a flush so we don't have to consider recursion here. */ cogl_flush (); if (atlas->map) _cogl_rectangle_map_foreach (atlas->map, _cogl_atlas_texture_pre_reorganize_foreach_cb, NULL); } typedef struct { CoglAtlasTexture **textures; /* Number of textures found so far */ unsigned int n_textures; } CoglAtlasTextureGetRectanglesData; static void _cogl_atlas_texture_get_rectangles_cb (const CoglRectangleMapEntry *entry, void *rectangle_data, void *user_data) { CoglAtlasTextureGetRectanglesData *data = user_data; data->textures[data->n_textures++] = rectangle_data; } static void _cogl_atlas_texture_post_reorganize_cb (void *user_data) { CoglAtlas *atlas = user_data; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (atlas->map) { CoglAtlasTextureGetRectanglesData data; unsigned int i; data.textures = g_new (CoglAtlasTexture *, _cogl_rectangle_map_get_n_rectangles (atlas->map)); data.n_textures = 0; /* We need to remove all of the references that we took during the preorganize callback. We have to get a separate array of the textures because CoglRectangleMap doesn't support removing rectangles during iteration */ _cogl_rectangle_map_foreach (atlas->map, _cogl_atlas_texture_get_rectangles_cb, &data); for (i = 0; i < data.n_textures; i++) { /* Ignore textures that don't have an atlas yet. This will happen when a new texture is added because we allocate the structure for the texture so that it can get stored in the atlas but it isn't a valid object yet */ if (data.textures[i]->atlas) cogl_object_unref (data.textures[i]); } free (data.textures); } /* Notify any listeners that an atlas has changed */ g_hook_list_invoke (&ctx->atlas_reorganize_callbacks, FALSE); } static void _cogl_atlas_texture_atlas_destroyed_cb (void *user_data) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Remove the atlas from the global list */ ctx->atlases = g_slist_remove (ctx->atlases, user_data); } static CoglAtlas * _cogl_atlas_texture_create_atlas (CoglContext *ctx) { static CoglUserDataKey atlas_private_key; CoglAtlas *atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_RGBA_8888, 0, _cogl_atlas_texture_update_position_cb); _cogl_atlas_add_reorganize_callback (atlas, _cogl_atlas_texture_pre_reorganize_cb, _cogl_atlas_texture_post_reorganize_cb, atlas); ctx->atlases = g_slist_prepend (ctx->atlases, atlas); /* Set some data on the atlas so we can get notification when it is destroyed in order to remove it from the list. ctx->atlases effectively holds a weak reference. We don't need a strong reference because the atlas textures take a reference on the atlas so it will stay alive */ cogl_object_set_user_data (COGL_OBJECT (atlas), &atlas_private_key, atlas, _cogl_atlas_texture_atlas_destroyed_cb); return atlas; } static void _cogl_atlas_texture_foreach_sub_texture_in_region ( CoglTexture *tex, float virtual_tx_1, float virtual_ty_1, float virtual_tx_2, float virtual_ty_2, CoglMetaTextureCallback callback, void *user_data) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); CoglMetaTexture *meta_texture = COGL_META_TEXTURE (atlas_tex->sub_texture); /* Forward on to the sub texture */ cogl_meta_texture_foreach_in_region (meta_texture, virtual_tx_1, virtual_ty_1, virtual_tx_2, virtual_ty_2, COGL_PIPELINE_WRAP_MODE_REPEAT, COGL_PIPELINE_WRAP_MODE_REPEAT, callback, user_data); } static void _cogl_atlas_texture_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, GLenum wrap_mode_s, GLenum wrap_mode_t, GLenum wrap_mode_p) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ _cogl_texture_gl_flush_legacy_texobj_wrap_modes (atlas_tex->sub_texture, wrap_mode_s, wrap_mode_t, wrap_mode_p); } static void _cogl_atlas_texture_remove_from_atlas (CoglAtlasTexture *atlas_tex) { if (atlas_tex->atlas) { _cogl_atlas_remove (atlas_tex->atlas, &atlas_tex->rectangle); cogl_object_unref (atlas_tex->atlas); atlas_tex->atlas = NULL; } } static void _cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex) { _cogl_atlas_texture_remove_from_atlas (atlas_tex); if (atlas_tex->sub_texture) cogl_object_unref (atlas_tex->sub_texture); /* Chain up */ _cogl_texture_free (COGL_TEXTURE (atlas_tex)); } static int _cogl_atlas_texture_get_max_waste (CoglTexture *tex) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ return cogl_texture_get_max_waste (atlas_tex->sub_texture); } static CoglBool _cogl_atlas_texture_is_sliced (CoglTexture *tex) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ return cogl_texture_is_sliced (atlas_tex->sub_texture); } static CoglBool _cogl_atlas_texture_can_hardware_repeat (CoglTexture *tex) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ return _cogl_texture_can_hardware_repeat (atlas_tex->sub_texture); } static void _cogl_atlas_texture_transform_coords_to_gl (CoglTexture *tex, float *s, float *t) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ _cogl_texture_transform_coords_to_gl (atlas_tex->sub_texture, s, t); } static CoglTransformResult _cogl_atlas_texture_transform_quad_coords_to_gl (CoglTexture *tex, float *coords) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ return _cogl_texture_transform_quad_coords_to_gl (atlas_tex->sub_texture, coords); } static CoglBool _cogl_atlas_texture_get_gl_texture (CoglTexture *tex, GLuint *out_gl_handle, GLenum *out_gl_target) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ return cogl_texture_get_gl_texture (atlas_tex->sub_texture, out_gl_handle, out_gl_target); } static void _cogl_atlas_texture_gl_flush_legacy_texobj_filters (CoglTexture *tex, GLenum min_filter, GLenum mag_filter) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ _cogl_texture_gl_flush_legacy_texobj_filters (atlas_tex->sub_texture, min_filter, mag_filter); } static void _cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex) { CoglTexture *standalone_tex; /* Make sure this texture is not in the atlas */ if (!atlas_tex->atlas) return; COGL_NOTE (ATLAS, "Migrating texture out of the atlas"); /* We don't know if any journal entries currently depend on * OpenGL texture coordinates that would be invalidated by * migrating textures in this atlas so we flush all journals * before migrating. * * We are assuming that texture atlas migration never happens * during a flush so we don't have to consider recursion here. */ cogl_flush (); standalone_tex = _cogl_atlas_copy_rectangle (atlas_tex->atlas, atlas_tex->rectangle.x + 1, atlas_tex->rectangle.y + 1, atlas_tex->rectangle.width - 2, atlas_tex->rectangle.height - 2, atlas_tex->internal_format); /* Note: we simply silently ignore failures to migrate a texture * out (most likely due to lack of memory) and hope for the * best. * * Maybe we should find a way to report the problem back to the * app. */ if (!standalone_tex) return; /* Notify cogl-pipeline.c that the texture's underlying GL texture * storage is changing so it knows it may need to bind a new texture * if the CoglTexture is reused with the same texture unit. */ _cogl_pipeline_texture_storage_change_notify (COGL_TEXTURE (atlas_tex)); /* We need to unref the sub texture after doing the copy because the copy can involve rendering which might cause the texture to be used if it is used from a layer that is left in a texture unit */ cogl_object_unref (atlas_tex->sub_texture); atlas_tex->sub_texture = standalone_tex; _cogl_atlas_texture_remove_from_atlas (atlas_tex); } static void _cogl_atlas_texture_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); if ((flags & COGL_TEXTURE_NEEDS_MIPMAP)) /* Mipmaps do not work well with the current atlas so instead we'll just migrate the texture out and use a regular texture */ _cogl_atlas_texture_migrate_out_of_atlas (atlas_tex); /* Forward on to the sub texture */ _cogl_texture_pre_paint (atlas_tex->sub_texture, flags); } static void _cogl_atlas_texture_ensure_non_quad_rendering (CoglTexture *tex) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Sub textures can't support non-quad rendering so we'll just migrate the texture out */ _cogl_atlas_texture_migrate_out_of_atlas (atlas_tex); /* Forward on to the sub texture */ _cogl_texture_ensure_non_quad_rendering (atlas_tex->sub_texture); } static CoglBool _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, CoglBitmap *bmp, CoglError **error) { CoglAtlas *atlas = atlas_tex->atlas; /* Copy the central data */ if (!_cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y, dst_width, dst_height, bmp, dst_x + atlas_tex->rectangle.x + 1, dst_y + atlas_tex->rectangle.y + 1, 0, /* level 0 */ error)) return FALSE; /* Update the left edge pixels */ if (dst_x == 0 && !_cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y, 1, dst_height, bmp, atlas_tex->rectangle.x, dst_y + atlas_tex->rectangle.y + 1, 0, /* level 0 */ error)) return FALSE; /* Update the right edge pixels */ if (dst_x + dst_width == atlas_tex->rectangle.width - 2 && !_cogl_texture_set_region_from_bitmap (atlas->texture, src_x + dst_width - 1, src_y, 1, dst_height, bmp, atlas_tex->rectangle.x + atlas_tex->rectangle.width - 1, dst_y + atlas_tex->rectangle.y + 1, 0, /* level 0 */ error)) return FALSE; /* Update the top edge pixels */ if (dst_y == 0 && !_cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y, dst_width, 1, bmp, dst_x + atlas_tex->rectangle.x + 1, atlas_tex->rectangle.y, 0, /* level 0 */ error)) return FALSE; /* Update the bottom edge pixels */ if (dst_y + dst_height == atlas_tex->rectangle.height - 2 && !_cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y + dst_height - 1, dst_width, 1, bmp, dst_x + atlas_tex->rectangle.x + 1, atlas_tex->rectangle.y + atlas_tex->rectangle.height - 1, 0, /* level 0 */ error)) return FALSE; return TRUE; } static CoglBitmap * _cogl_atlas_texture_convert_bitmap_for_upload (CoglAtlasTexture *atlas_tex, CoglBitmap *bmp, CoglPixelFormat internal_format, CoglBool can_convert_in_place, CoglError **error) { CoglBitmap *upload_bmp; CoglBitmap *override_bmp; /* We'll prepare to upload using the format of the actual texture of the atlas texture instead of the format reported by _cogl_texture_get_format which would be the original internal format specified when the texture was created. However we'll preserve the premult status of the internal format because the images are all stored in the original premult format of the orignal format so we do need to trigger the conversion */ internal_format = (COGL_PIXEL_FORMAT_RGBA_8888 | (internal_format & COGL_PREMULT_BIT)); upload_bmp = _cogl_bitmap_convert_for_upload (bmp, internal_format, can_convert_in_place, error); if (upload_bmp == NULL) return NULL; /* We'll create another bitmap which uses the same data but overrides the format to remove the premult flag so that uploads to the atlas texture won't trigger the conversion again */ override_bmp = _cogl_bitmap_new_shared (upload_bmp, cogl_bitmap_get_format (upload_bmp) & ~COGL_PREMULT_BIT, cogl_bitmap_get_width (upload_bmp), cogl_bitmap_get_height (upload_bmp), cogl_bitmap_get_rowstride (upload_bmp)); cogl_object_unref (upload_bmp); return override_bmp; } static CoglBool _cogl_atlas_texture_set_region (CoglTexture *tex, int src_x, int src_y, int dst_x, int dst_y, int dst_width, int dst_height, int level, CoglBitmap *bmp, CoglError **error) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); if (level != 0 && atlas_tex->atlas) _cogl_atlas_texture_migrate_out_of_atlas (atlas_tex); /* If the texture is in the atlas then we need to copy the edge pixels to the border */ if (atlas_tex->atlas) { CoglBool ret; CoglBitmap *upload_bmp = _cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex, bmp, atlas_tex->internal_format, FALSE, /* can't convert in place */ error); if (!upload_bmp) return FALSE; /* Upload the data ignoring the premult bit */ ret = _cogl_atlas_texture_set_region_with_border (atlas_tex, src_x, src_y, dst_x, dst_y, dst_width, dst_height, upload_bmp, error); cogl_object_unref (upload_bmp); return ret; } else /* Otherwise we can just forward on to the sub texture */ return _cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture, src_x, src_y, dst_width, dst_height, bmp, dst_x, dst_y, level, error); } static CoglPixelFormat _cogl_atlas_texture_get_format (CoglTexture *tex) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* We don't want to forward this on the sub-texture because it isn't the necessarily the same format. This will happen if the texture isn't pre-multiplied */ return atlas_tex->internal_format; } static GLenum _cogl_atlas_texture_get_gl_format (CoglTexture *tex) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); /* Forward on to the sub texture */ return _cogl_texture_gl_get_format (atlas_tex->sub_texture); } static CoglBool _cogl_atlas_texture_can_use_format (CoglPixelFormat format) { /* We don't care about the ordering or the premult status and we can accept RGBA or RGB textures. Although we could also accept luminance and alpha only textures or 16-bit formats it seems that if the application is explicitly using these formats then they've got a reason to want the lower memory requirements so putting them in the atlas might not be a good idea */ format &= ~(COGL_PREMULT_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT); return (format == COGL_PIXEL_FORMAT_RGB_888 || format == COGL_PIXEL_FORMAT_RGBA_8888); } static CoglAtlasTexture * _cogl_atlas_texture_create_base (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format, CoglTextureLoader *loader) { CoglAtlasTexture *atlas_tex; COGL_NOTE (ATLAS, "Adding texture of size %ix%i", width, height); /* We need to allocate the texture now because we need the pointer to set as the data for the rectangle in the atlas */ atlas_tex = g_new0 (CoglAtlasTexture, 1); /* Mark it as having no atlas so we don't try to unref it in _cogl_atlas_texture_post_reorganize_cb */ atlas_tex->atlas = NULL; _cogl_texture_init (COGL_TEXTURE (atlas_tex), ctx, width, height, internal_format, loader, &cogl_atlas_texture_vtable); atlas_tex->sub_texture = NULL; atlas_tex->atlas = NULL; return _cogl_atlas_texture_object_new (atlas_tex); } CoglAtlasTexture * cogl_atlas_texture_new_with_size (CoglContext *ctx, int width, int height) { CoglTextureLoader *loader; /* We can't atlas zero-sized textures because it breaks the atlas * data structure */ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED; loader->src.sized.width = width; loader->src.sized.height = height; return _cogl_atlas_texture_create_base (ctx, width, height, COGL_PIXEL_FORMAT_RGBA_8888_PRE, loader); } static CoglBool allocate_space (CoglAtlasTexture *atlas_tex, int width, int height, CoglPixelFormat internal_format, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (atlas_tex); CoglContext *ctx = tex->context; CoglAtlas *atlas; GSList *l; /* If the texture is in a strange format then we won't use it */ if (!_cogl_atlas_texture_can_use_format (internal_format)) { COGL_NOTE (ATLAS, "Texture can not be added because the " "format is unsupported"); _cogl_set_error (error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_FORMAT, "Texture format unsuitable for atlasing"); return FALSE; } /* If we can't use FBOs then it will be too slow to migrate textures and we shouldn't use the atlas */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) { _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Atlasing disabled because migrations " "would be too slow"); return FALSE; } /* Look for an existing atlas that can hold the texture */ for (l = ctx->atlases; l; l = l->next) { /* We need to take a reference on the atlas before trying to * reserve space because in some circumstances atlas migration * can cause the atlas to be freed */ atlas = cogl_object_ref (l->data); /* Try to make some space in the atlas for the texture */ if (_cogl_atlas_reserve_space (atlas, /* Add two pixels for the border */ width + 2, height + 2, atlas_tex)) { /* keep the atlas reference */ break; } else { cogl_object_unref (atlas); } } /* If we couldn't find a suitable atlas then start another */ if (l == NULL) { atlas = _cogl_atlas_texture_create_atlas (ctx); COGL_NOTE (ATLAS, "Created new atlas for textures: %p", atlas); if (!_cogl_atlas_reserve_space (atlas, /* Add two pixels for the border */ width + 2, height + 2, atlas_tex)) { /* Ok, this means we really can't add it to the atlas */ cogl_object_unref (atlas); _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_NO_MEMORY, "Not enough memory to atlas texture"); return FALSE; } } atlas_tex->internal_format = internal_format; atlas_tex->atlas = atlas; return TRUE; } static CoglBool allocate_with_size (CoglAtlasTexture *atlas_tex, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (atlas_tex); CoglPixelFormat internal_format = _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); if (allocate_space (atlas_tex, loader->src.sized.width, loader->src.sized.height, internal_format, error)) { _cogl_texture_set_allocated (COGL_TEXTURE (atlas_tex), internal_format, loader->src.sized.width, loader->src.sized.height); return TRUE; } else return FALSE; } static CoglBool allocate_from_bitmap (CoglAtlasTexture *atlas_tex, CoglTextureLoader *loader, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (atlas_tex); CoglBitmap *bmp = loader->src.bitmap.bitmap; CoglPixelFormat bmp_format = cogl_bitmap_get_format (bmp); int width = cogl_bitmap_get_width (bmp); int height = cogl_bitmap_get_height (bmp); CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place; CoglPixelFormat internal_format; CoglBitmap *upload_bmp; _COGL_RETURN_VAL_IF_FAIL (atlas_tex->atlas == NULL, FALSE); internal_format = _cogl_texture_determine_internal_format (tex, bmp_format); upload_bmp = _cogl_atlas_texture_convert_bitmap_for_upload (atlas_tex, bmp, internal_format, can_convert_in_place, error); if (upload_bmp == NULL) return FALSE; if (!allocate_space (atlas_tex, width, height, internal_format, error)) { cogl_object_unref (upload_bmp); return FALSE; } /* Defer to set_region so that we can share the code for copying the edge pixels to the border. */ if (!_cogl_atlas_texture_set_region_with_border (atlas_tex, 0, /* src_x */ 0, /* src_y */ 0, /* dst_x */ 0, /* dst_y */ width, /* dst_width */ height, /* dst_height */ upload_bmp, error)) { _cogl_atlas_texture_remove_from_atlas (atlas_tex); cogl_object_unref (upload_bmp); return FALSE; } cogl_object_unref (upload_bmp); _cogl_texture_set_allocated (tex, internal_format, width, height); return TRUE; } static CoglBool _cogl_atlas_texture_allocate (CoglTexture *tex, CoglError **error) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); CoglTextureLoader *loader = tex->loader; _COGL_RETURN_VAL_IF_FAIL (loader, FALSE); switch (loader->src_type) { case COGL_TEXTURE_SOURCE_TYPE_SIZED: return allocate_with_size (atlas_tex, loader, error); case COGL_TEXTURE_SOURCE_TYPE_BITMAP: return allocate_from_bitmap (atlas_tex, loader, error); default: break; } g_return_val_if_reached (FALSE); } CoglAtlasTexture * _cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp, CoglBool can_convert_in_place) { CoglTextureLoader *loader; _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL); loader = _cogl_texture_create_loader (); loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP; loader->src.bitmap.bitmap = cogl_object_ref (bmp); loader->src.bitmap.can_convert_in_place = can_convert_in_place; return _cogl_atlas_texture_create_base (_cogl_bitmap_get_context (bmp), cogl_bitmap_get_width (bmp), cogl_bitmap_get_height (bmp), cogl_bitmap_get_format (bmp), loader); } CoglAtlasTexture * cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp) { return _cogl_atlas_texture_new_from_bitmap (bmp, FALSE); } CoglAtlasTexture * cogl_atlas_texture_new_from_data (CoglContext *ctx, int width, int height, CoglPixelFormat format, int rowstride, const uint8_t *data, CoglError **error) { CoglBitmap *bmp; CoglAtlasTexture *atlas_tex; _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); /* Rowstride from width if not given */ if (rowstride == 0) rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); /* Wrap the data into a bitmap */ bmp = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); atlas_tex = cogl_atlas_texture_new_from_bitmap (bmp); cogl_object_unref (bmp); if (atlas_tex && !cogl_texture_allocate (COGL_TEXTURE (atlas_tex), error)) { cogl_object_unref (atlas_tex); return NULL; } return atlas_tex; } CoglAtlasTexture * cogl_atlas_texture_new_from_file (CoglContext *ctx, const char *filename, CoglError **error) { CoglBitmap *bmp; CoglAtlasTexture *atlas_tex = NULL; _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL); bmp = cogl_bitmap_new_from_file (filename, error); if (bmp == NULL) return NULL; atlas_tex = _cogl_atlas_texture_new_from_bitmap (bmp, TRUE); /* convert in-place */ cogl_object_unref (bmp); return atlas_tex; } void _cogl_atlas_texture_add_reorganize_callback (CoglContext *ctx, GHookFunc callback, void *user_data) { GHook *hook = g_hook_alloc (&ctx->atlas_reorganize_callbacks); hook->func = callback; hook->data = user_data; g_hook_prepend (&ctx->atlas_reorganize_callbacks, hook); } void _cogl_atlas_texture_remove_reorganize_callback (CoglContext *ctx, GHookFunc callback, void *user_data) { GHook *hook = g_hook_find_func_data (&ctx->atlas_reorganize_callbacks, FALSE, callback, user_data); if (hook) g_hook_destroy_link (&ctx->atlas_reorganize_callbacks, hook); } static CoglTextureType _cogl_atlas_texture_get_type (CoglTexture *tex) { return COGL_TEXTURE_TYPE_2D; } static const CoglTextureVtable cogl_atlas_texture_vtable = { FALSE, /* not primitive */ _cogl_atlas_texture_allocate, _cogl_atlas_texture_set_region, NULL, /* get_data */ _cogl_atlas_texture_foreach_sub_texture_in_region, _cogl_atlas_texture_get_max_waste, _cogl_atlas_texture_is_sliced, _cogl_atlas_texture_can_hardware_repeat, _cogl_atlas_texture_transform_coords_to_gl, _cogl_atlas_texture_transform_quad_coords_to_gl, _cogl_atlas_texture_get_gl_texture, _cogl_atlas_texture_gl_flush_legacy_texobj_filters, _cogl_atlas_texture_pre_paint, _cogl_atlas_texture_ensure_non_quad_rendering, _cogl_atlas_texture_gl_flush_legacy_texobj_wrap_modes, _cogl_atlas_texture_get_format, _cogl_atlas_texture_get_gl_format, _cogl_atlas_texture_get_type, NULL, /* is_foreign */ NULL /* set_auto_mipmap */ }; muffin-5.2.1/cogl/cogl/cogl-rectangle-map.c0000664000175000017500000005645614211404421020631 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-util.h" #include "cogl-rectangle-map.h" #include "cogl-debug.h" /* Implements a data structure which keeps track of unused sub-rectangles within a larger rectangle using a binary tree structure. The algorithm for this is based on the description here: http://www.blackpawn.com/texts/lightmaps/default.html */ #if defined (COGL_ENABLE_DEBUG) && defined (HAVE_CAIRO) /* The cairo header is only used for debugging to generate an image of the atlas */ #include static void _cogl_rectangle_map_dump_image (CoglRectangleMap *map); #endif /* COGL_ENABLE_DEBUG && HAVE_CAIRO */ typedef struct _CoglRectangleMapNode CoglRectangleMapNode; typedef struct _CoglRectangleMapStackEntry CoglRectangleMapStackEntry; typedef void (* CoglRectangleMapInternalForeachCb) (CoglRectangleMapNode *node, void *data); typedef enum { COGL_RECTANGLE_MAP_BRANCH, COGL_RECTANGLE_MAP_FILLED_LEAF, COGL_RECTANGLE_MAP_EMPTY_LEAF } CoglRectangleMapNodeType; struct _CoglRectangleMap { CoglRectangleMapNode *root; unsigned int n_rectangles; unsigned int space_remaining; GDestroyNotify value_destroy_func; /* Stack used for walking the structure. This is only used during the lifetime of a single function call but it is kept here as an optimisation to avoid reallocating it every time it is needed */ GArray *stack; }; struct _CoglRectangleMapNode { CoglRectangleMapNodeType type; CoglRectangleMapEntry rectangle; unsigned int largest_gap; CoglRectangleMapNode *parent; union { /* Fields used when this is a branch */ struct { CoglRectangleMapNode *left; CoglRectangleMapNode *right; } branch; /* Field used when this is a filled leaf */ void *data; } d; }; struct _CoglRectangleMapStackEntry { /* The node to search */ CoglRectangleMapNode *node; /* Index of next branch of this node to explore. Basically either 0 to go left or 1 to go right */ CoglBool next_index; }; static CoglRectangleMapNode * _cogl_rectangle_map_node_new (void) { return g_slice_new (CoglRectangleMapNode); } static void _cogl_rectangle_map_node_free (CoglRectangleMapNode *node) { g_slice_free (CoglRectangleMapNode, node); } CoglRectangleMap * _cogl_rectangle_map_new (unsigned int width, unsigned int height, GDestroyNotify value_destroy_func) { CoglRectangleMap *map = g_new (CoglRectangleMap, 1); CoglRectangleMapNode *root = _cogl_rectangle_map_node_new (); root->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; root->parent = NULL; root->rectangle.x = 0; root->rectangle.y = 0; root->rectangle.width = width; root->rectangle.height = height; root->largest_gap = width * height; map->root = root; map->n_rectangles = 0; map->value_destroy_func = value_destroy_func; map->space_remaining = width * height; map->stack = g_array_new (FALSE, FALSE, sizeof (CoglRectangleMapStackEntry)); return map; } static void _cogl_rectangle_map_stack_push (GArray *stack, CoglRectangleMapNode *node, CoglBool next_index) { CoglRectangleMapStackEntry *new_entry; g_array_set_size (stack, stack->len + 1); new_entry = &g_array_index (stack, CoglRectangleMapStackEntry, stack->len - 1); new_entry->node = node; new_entry->next_index = next_index; } static void _cogl_rectangle_map_stack_pop (GArray *stack) { g_array_set_size (stack, stack->len - 1); } static CoglRectangleMapStackEntry * _cogl_rectangle_map_stack_get_top (GArray *stack) { return &g_array_index (stack, CoglRectangleMapStackEntry, stack->len - 1); } static CoglRectangleMapNode * _cogl_rectangle_map_node_split_horizontally (CoglRectangleMapNode *node, unsigned int left_width) { /* Splits the node horizontally (according to emacs' definition, not vim) by converting it to a branch and adding two new leaf nodes. The leftmost branch will have the width left_width and will be returned. If the node is already just the right size it won't do anything */ CoglRectangleMapNode *left_node, *right_node; if (node->rectangle.width == left_width) return node; left_node = _cogl_rectangle_map_node_new (); left_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; left_node->parent = node; left_node->rectangle.x = node->rectangle.x; left_node->rectangle.y = node->rectangle.y; left_node->rectangle.width = left_width; left_node->rectangle.height = node->rectangle.height; left_node->largest_gap = (left_node->rectangle.width * left_node->rectangle.height); node->d.branch.left = left_node; right_node = _cogl_rectangle_map_node_new (); right_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; right_node->parent = node; right_node->rectangle.x = node->rectangle.x + left_width; right_node->rectangle.y = node->rectangle.y; right_node->rectangle.width = node->rectangle.width - left_width; right_node->rectangle.height = node->rectangle.height; right_node->largest_gap = (right_node->rectangle.width * right_node->rectangle.height); node->d.branch.right = right_node; node->type = COGL_RECTANGLE_MAP_BRANCH; return left_node; } static CoglRectangleMapNode * _cogl_rectangle_map_node_split_vertically (CoglRectangleMapNode *node, unsigned int top_height) { /* Splits the node vertically (according to emacs' definition, not vim) by converting it to a branch and adding two new leaf nodes. The topmost branch will have the height top_height and will be returned. If the node is already just the right size it won't do anything */ CoglRectangleMapNode *top_node, *bottom_node; if (node->rectangle.height == top_height) return node; top_node = _cogl_rectangle_map_node_new (); top_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; top_node->parent = node; top_node->rectangle.x = node->rectangle.x; top_node->rectangle.y = node->rectangle.y; top_node->rectangle.width = node->rectangle.width; top_node->rectangle.height = top_height; top_node->largest_gap = (top_node->rectangle.width * top_node->rectangle.height); node->d.branch.left = top_node; bottom_node = _cogl_rectangle_map_node_new (); bottom_node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; bottom_node->parent = node; bottom_node->rectangle.x = node->rectangle.x; bottom_node->rectangle.y = node->rectangle.y + top_height; bottom_node->rectangle.width = node->rectangle.width; bottom_node->rectangle.height = node->rectangle.height - top_height; bottom_node->largest_gap = (bottom_node->rectangle.width * bottom_node->rectangle.height); node->d.branch.right = bottom_node; node->type = COGL_RECTANGLE_MAP_BRANCH; return top_node; } #ifdef COGL_ENABLE_DEBUG static unsigned int _cogl_rectangle_map_verify_recursive (CoglRectangleMapNode *node) { /* This is just used for debugging the data structure. It recursively walks the tree to verify that the largest gap values all add up */ switch (node->type) { case COGL_RECTANGLE_MAP_BRANCH: { int sum = _cogl_rectangle_map_verify_recursive (node->d.branch.left) + _cogl_rectangle_map_verify_recursive (node->d.branch.right); g_assert (node->largest_gap == MAX (node->d.branch.left->largest_gap, node->d.branch.right->largest_gap)); return sum; } case COGL_RECTANGLE_MAP_EMPTY_LEAF: g_assert (node->largest_gap == node->rectangle.width * node->rectangle.height); return 0; case COGL_RECTANGLE_MAP_FILLED_LEAF: g_assert (node->largest_gap == 0); return 1; } return 0; } static unsigned int _cogl_rectangle_map_get_space_remaining_recursive (CoglRectangleMapNode *node) { /* This is just used for debugging the data structure. It recursively walks the tree to verify that the remaining space value adds up */ switch (node->type) { case COGL_RECTANGLE_MAP_BRANCH: { CoglRectangleMapNode *l = node->d.branch.left; CoglRectangleMapNode *r = node->d.branch.right; return (_cogl_rectangle_map_get_space_remaining_recursive (l) + _cogl_rectangle_map_get_space_remaining_recursive (r)); } case COGL_RECTANGLE_MAP_EMPTY_LEAF: return node->rectangle.width * node->rectangle.height; case COGL_RECTANGLE_MAP_FILLED_LEAF: return 0; } return 0; } static void _cogl_rectangle_map_verify (CoglRectangleMap *map) { unsigned int actual_n_rectangles = _cogl_rectangle_map_verify_recursive (map->root); unsigned int actual_space_remaining = _cogl_rectangle_map_get_space_remaining_recursive (map->root); g_assert_cmpuint (actual_n_rectangles, ==, map->n_rectangles); g_assert_cmpuint (actual_space_remaining, ==, map->space_remaining); } #endif /* COGL_ENABLE_DEBUG */ CoglBool _cogl_rectangle_map_add (CoglRectangleMap *map, unsigned int width, unsigned int height, void *data, CoglRectangleMapEntry *rectangle) { unsigned int rectangle_size = width * height; /* Stack of nodes to search in */ GArray *stack = map->stack; CoglRectangleMapNode *found_node = NULL; /* Zero-sized rectangles break the algorithm for removing rectangles so we'll disallow them */ _COGL_RETURN_VAL_IF_FAIL (width > 0 && height > 0, FALSE); /* Start with the root node */ g_array_set_size (stack, 0); _cogl_rectangle_map_stack_push (stack, map->root, FALSE); /* Depth-first search for an empty node that is big enough */ while (stack->len > 0) { CoglRectangleMapStackEntry *stack_top; CoglRectangleMapNode *node; int next_index; /* Pop an entry off the stack */ stack_top = _cogl_rectangle_map_stack_get_top (stack); node = stack_top->node; next_index = stack_top->next_index; _cogl_rectangle_map_stack_pop (stack); /* Regardless of the type of the node, there's no point descending any further if the new rectangle won't fit within it */ if (node->rectangle.width >= width && node->rectangle.height >= height && node->largest_gap >= rectangle_size) { if (node->type == COGL_RECTANGLE_MAP_EMPTY_LEAF) { /* We've found a node we can use */ found_node = node; break; } else if (node->type == COGL_RECTANGLE_MAP_BRANCH) { if (next_index) /* Try the right branch */ _cogl_rectangle_map_stack_push (stack, node->d.branch.right, 0); else { /* Make sure we remember to try the right branch once we've finished descending the left branch */ _cogl_rectangle_map_stack_push (stack, node, 1); /* Try the left branch */ _cogl_rectangle_map_stack_push (stack, node->d.branch.left, 0); } } } } if (found_node) { CoglRectangleMapNode *node; /* Split according to whichever axis will leave us with the largest space */ if (found_node->rectangle.width - width > found_node->rectangle.height - height) { found_node = _cogl_rectangle_map_node_split_horizontally (found_node, width); found_node = _cogl_rectangle_map_node_split_vertically (found_node, height); } else { found_node = _cogl_rectangle_map_node_split_vertically (found_node, height); found_node = _cogl_rectangle_map_node_split_horizontally (found_node, width); } found_node->type = COGL_RECTANGLE_MAP_FILLED_LEAF; found_node->d.data = data; found_node->largest_gap = 0; if (rectangle) *rectangle = found_node->rectangle; /* Walk back up the tree and update the stored largest gap for the node's sub tree */ for (node = found_node->parent; node; node = node->parent) { /* This node is a parent so it should always be a branch */ g_assert (node->type == COGL_RECTANGLE_MAP_BRANCH); node->largest_gap = MAX (node->d.branch.left->largest_gap, node->d.branch.right->largest_gap); } /* There is now an extra rectangle in the map */ map->n_rectangles++; /* and less space */ map->space_remaining -= rectangle_size; #ifdef COGL_ENABLE_DEBUG if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DUMP_ATLAS_IMAGE))) { #ifdef HAVE_CAIRO _cogl_rectangle_map_dump_image (map); #endif /* Dumping the rectangle map is really slow so we might as well verify the space remaining here as it is also quite slow */ _cogl_rectangle_map_verify (map); } #endif return TRUE; } else return FALSE; } void _cogl_rectangle_map_remove (CoglRectangleMap *map, const CoglRectangleMapEntry *rectangle) { CoglRectangleMapNode *node = map->root; unsigned int rectangle_size = rectangle->width * rectangle->height; /* We can do a binary-chop down the search tree to find the rectangle */ while (node->type == COGL_RECTANGLE_MAP_BRANCH) { CoglRectangleMapNode *left_node = node->d.branch.left; /* If and only if the rectangle is in the left node then the x,y position of the rectangle will be within the node's rectangle */ if (rectangle->x < left_node->rectangle.x + left_node->rectangle.width && rectangle->y < left_node->rectangle.y + left_node->rectangle.height) /* Go left */ node = left_node; else /* Go right */ node = node->d.branch.right; } /* Make sure we found the right node */ if (node->type != COGL_RECTANGLE_MAP_FILLED_LEAF || node->rectangle.x != rectangle->x || node->rectangle.y != rectangle->y || node->rectangle.width != rectangle->width || node->rectangle.height != rectangle->height) /* This should only happen if someone tried to remove a rectangle that was not in the map so something has gone wrong */ g_return_if_reached (); else { /* Convert the node back to an empty node */ if (map->value_destroy_func) map->value_destroy_func (node->d.data); node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; node->largest_gap = rectangle_size; /* Walk back up the tree combining branch nodes that have two empty leaves back into a single empty leaf */ for (node = node->parent; node; node = node->parent) { /* This node is a parent so it should always be a branch */ g_assert (node->type == COGL_RECTANGLE_MAP_BRANCH); if (node->d.branch.left->type == COGL_RECTANGLE_MAP_EMPTY_LEAF && node->d.branch.right->type == COGL_RECTANGLE_MAP_EMPTY_LEAF) { _cogl_rectangle_map_node_free (node->d.branch.left); _cogl_rectangle_map_node_free (node->d.branch.right); node->type = COGL_RECTANGLE_MAP_EMPTY_LEAF; node->largest_gap = (node->rectangle.width * node->rectangle.height); } else break; } /* Reduce the amount of space remaining in all of the parents further up the chain */ for (; node; node = node->parent) node->largest_gap = MAX (node->d.branch.left->largest_gap, node->d.branch.right->largest_gap); /* There is now one less rectangle */ g_assert (map->n_rectangles > 0); map->n_rectangles--; /* and more space */ map->space_remaining += rectangle_size; } #ifdef COGL_ENABLE_DEBUG if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DUMP_ATLAS_IMAGE))) { #ifdef HAVE_CAIRO _cogl_rectangle_map_dump_image (map); #endif /* Dumping the rectangle map is really slow so we might as well verify the space remaining here as it is also quite slow */ _cogl_rectangle_map_verify (map); } #endif } unsigned int _cogl_rectangle_map_get_width (CoglRectangleMap *map) { return map->root->rectangle.width; } unsigned int _cogl_rectangle_map_get_height (CoglRectangleMap *map) { return map->root->rectangle.height; } unsigned int _cogl_rectangle_map_get_remaining_space (CoglRectangleMap *map) { return map->space_remaining; } unsigned int _cogl_rectangle_map_get_n_rectangles (CoglRectangleMap *map) { return map->n_rectangles; } static void _cogl_rectangle_map_internal_foreach (CoglRectangleMap *map, CoglRectangleMapInternalForeachCb func, void *data) { /* Stack of nodes to search in */ GArray *stack = map->stack; /* Start with the root node */ g_array_set_size (stack, 0); _cogl_rectangle_map_stack_push (stack, map->root, 0); /* Iterate all nodes depth-first */ while (stack->len > 0) { CoglRectangleMapStackEntry *stack_top = _cogl_rectangle_map_stack_get_top (stack); CoglRectangleMapNode *node = stack_top->node; switch (node->type) { case COGL_RECTANGLE_MAP_BRANCH: if (stack_top->next_index == 0) { /* Next time we come back to this node, go to the right */ stack_top->next_index = 1; /* Explore the left branch next */ _cogl_rectangle_map_stack_push (stack, node->d.branch.left, 0); } else if (stack_top->next_index == 1) { /* Next time we come back to this node, stop processing it */ stack_top->next_index = 2; /* Explore the right branch next */ _cogl_rectangle_map_stack_push (stack, node->d.branch.right, 0); } else { /* We're finished with this node so we can call the callback */ func (node, data); _cogl_rectangle_map_stack_pop (stack); } break; default: /* Some sort of leaf node, just call the callback */ func (node, data); _cogl_rectangle_map_stack_pop (stack); break; } } /* The stack should now be empty */ g_assert (stack->len == 0); } typedef struct _CoglRectangleMapForeachClosure { CoglRectangleMapCallback callback; void *data; } CoglRectangleMapForeachClosure; static void _cogl_rectangle_map_foreach_cb (CoglRectangleMapNode *node, void *data) { CoglRectangleMapForeachClosure *closure = data; if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF) closure->callback (&node->rectangle, node->d.data, closure->data); } void _cogl_rectangle_map_foreach (CoglRectangleMap *map, CoglRectangleMapCallback callback, void *data) { CoglRectangleMapForeachClosure closure; closure.callback = callback; closure.data = data; _cogl_rectangle_map_internal_foreach (map, _cogl_rectangle_map_foreach_cb, &closure); } static void _cogl_rectangle_map_free_cb (CoglRectangleMapNode *node, void *data) { CoglRectangleMap *map = data; if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF && map->value_destroy_func) map->value_destroy_func (node->d.data); _cogl_rectangle_map_node_free (node); } void _cogl_rectangle_map_free (CoglRectangleMap *map) { _cogl_rectangle_map_internal_foreach (map, _cogl_rectangle_map_free_cb, map); g_array_free (map->stack, TRUE); free (map); } #if defined (COGL_ENABLE_DEBUG) && defined (HAVE_CAIRO) static void _cogl_rectangle_map_dump_image_cb (CoglRectangleMapNode *node, void *data) { cairo_t *cr = data; if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF || node->type == COGL_RECTANGLE_MAP_EMPTY_LEAF) { /* Fill the rectangle using a different colour depending on whether the rectangle is used */ if (node->type == COGL_RECTANGLE_MAP_FILLED_LEAF) cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); else cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_rectangle (cr, node->rectangle.x, node->rectangle.y, node->rectangle.width, node->rectangle.height); cairo_fill_preserve (cr); /* Draw a white outline around the rectangle */ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_stroke (cr); } } static void _cogl_rectangle_map_dump_image (CoglRectangleMap *map) { /* This dumps a png to help visualize the map. Each leaf rectangle is drawn with a white outline. Unused leaves are filled in black and used leaves are blue */ cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, _cogl_rectangle_map_get_width (map), _cogl_rectangle_map_get_height (map)); cairo_t *cr = cairo_create (surface); _cogl_rectangle_map_internal_foreach (map, _cogl_rectangle_map_dump_image_cb, cr); cairo_destroy (cr); cairo_surface_write_to_png (surface, "cogl-rectangle-map-dump.png"); cairo_surface_destroy (surface); } #endif /* COGL_ENABLE_DEBUG && HAVE_CAIRO */ muffin-5.2.1/cogl/cogl/cogl-pixel-buffer.c0000664000175000017500000000733614211404421020473 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Damien Lespiau * Robert Bragg */ /* For an overview of the functionality implemented here, please see * cogl-buffer-array.h, which contains the gtk-doc section overview for the * Pixel Buffers API. */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include "cogl-private.h" #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-object.h" #include "cogl-pixel-buffer-private.h" #include "cogl-pixel-buffer.h" #include "cogl-gtype-private.h" /* * GL/GLES compatibility defines for the buffer API: */ #if defined (HAVE_COGL_GL) #ifndef GL_PIXEL_UNPACK_BUFFER #define GL_PIXEL_UNPACK_BUFFER GL_PIXEL_UNPACK_BUFFER_ARB #endif #ifndef GL_PIXEL_PACK_BUFFER #define GL_PIXEL_PACK_BUFFER GL_PIXEL_PACK_BUFFER_ARB #endif #endif static void _cogl_pixel_buffer_free (CoglPixelBuffer *buffer); COGL_BUFFER_DEFINE (PixelBuffer, pixel_buffer) COGL_GTYPE_DEFINE_CLASS (PixelBuffer, pixel_buffer) static CoglPixelBuffer * _cogl_pixel_buffer_new (CoglContext *context, size_t size, const void *data, CoglError **error) { CoglPixelBuffer *pixel_buffer = g_slice_new0 (CoglPixelBuffer); CoglBuffer *buffer = COGL_BUFFER (pixel_buffer); /* parent's constructor */ _cogl_buffer_initialize (buffer, context, size, COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK, COGL_BUFFER_USAGE_HINT_TEXTURE, COGL_BUFFER_UPDATE_HINT_STATIC); _cogl_pixel_buffer_object_new (pixel_buffer); if (data) { if (!_cogl_buffer_set_data (COGL_BUFFER (pixel_buffer), 0, data, size, error)) { cogl_object_unref (pixel_buffer); return NULL; } } return pixel_buffer; } CoglPixelBuffer * cogl_pixel_buffer_new (CoglContext *context, size_t size, const void *data) { CoglError *ignore_error = NULL; CoglPixelBuffer *buffer = _cogl_pixel_buffer_new (context, size, data, &ignore_error); if (!buffer) cogl_error_free (ignore_error); return buffer; } static void _cogl_pixel_buffer_free (CoglPixelBuffer *buffer) { /* parent's destructor */ _cogl_buffer_fini (COGL_BUFFER (buffer)); g_slice_free (CoglPixelBuffer, buffer); } muffin-5.2.1/cogl/cogl/cogl-buffer.h0000664000175000017500000002400614211404421017352 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C)2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Damien Lespiau * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_BUFFER_H__ #define __COGL_BUFFER_H__ #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-buffer * @short_description: Common buffer functions, including data upload APIs * @stability: unstable * * The CoglBuffer API provides a common interface to manipulate * buffers that have been allocated either via cogl_pixel_buffer_new() * or cogl_attribute_buffer_new(). The API allows you to upload data * to these buffers and define usage hints that help Cogl manage your * buffer optimally. * * Data can either be uploaded by supplying a pointer and size so Cogl * can copy your data, or you can mmap() a CoglBuffer and then you can * copy data to the buffer directly. * * One of the most common uses for CoglBuffers is to upload texture * data asynchronously since the ability to mmap the buffers into * the CPU makes it possible for another thread to handle the IO * of loading an image file and unpacking it into the mapped buffer * without blocking other Cogl operations. */ #if defined(__COGL_H_INSIDE__) && !defined(COGL_ENABLE_MUFFIN_API) && \ !defined(COGL_GIR_SCANNING) /* For the public C api we typedef interface types as void to avoid needing * lots of casting in code and instead we will rely on runtime type checking * for these objects. */ typedef void CoglBuffer; #else typedef struct _CoglBuffer CoglBuffer; #define COGL_BUFFER(buffer) ((CoglBuffer *)(buffer)) #endif #define COGL_BUFFER_ERROR (_cogl_buffer_error_domain ()) /** * CoglBufferError: * @COGL_BUFFER_ERROR_MAP: A buffer could not be mapped either * because the feature isn't supported or because a system * limitation was hit. * * Error enumeration for #CoglBuffer * * Stability: unstable */ typedef enum { /*< prefix=COGL_BUFFER_ERROR >*/ COGL_BUFFER_ERROR_MAP } CoglBufferError; uint32_t _cogl_buffer_error_domain (void); /** * cogl_is_buffer: * @object: a buffer object * * Checks whether @buffer is a buffer object. * * Return value: %TRUE if the handle is a CoglBuffer, and %FALSE otherwise * * Since: 1.2 * Stability: unstable */ CoglBool cogl_is_buffer (void *object); /** * cogl_buffer_get_size: * @buffer: a buffer object * * Retrieves the size of buffer * * Return value: the size of the buffer in bytes * * Since: 1.2 * Stability: unstable */ unsigned int cogl_buffer_get_size (CoglBuffer *buffer); /** * CoglBufferUpdateHint: * @COGL_BUFFER_UPDATE_HINT_STATIC: the buffer will not change over time * @COGL_BUFFER_UPDATE_HINT_DYNAMIC: the buffer will change from time to time * @COGL_BUFFER_UPDATE_HINT_STREAM: the buffer will be used once or a couple of * times * * The update hint on a buffer allows the user to give some detail on how often * the buffer data is going to be updated. * * Since: 1.2 * Stability: unstable */ typedef enum { /*< prefix=COGL_BUFFER_UPDATE_HINT >*/ COGL_BUFFER_UPDATE_HINT_STATIC, COGL_BUFFER_UPDATE_HINT_DYNAMIC, COGL_BUFFER_UPDATE_HINT_STREAM } CoglBufferUpdateHint; /** * cogl_buffer_set_update_hint: * @buffer: a buffer object * @hint: the new hint * * Sets the update hint on a buffer. See #CoglBufferUpdateHint for a description * of the available hints. * * Since: 1.2 * Stability: unstable */ void cogl_buffer_set_update_hint (CoglBuffer *buffer, CoglBufferUpdateHint hint); /** * cogl_buffer_get_update_hint: * @buffer: a buffer object * * Retrieves the update hints set using cogl_buffer_set_update_hint() * * Return value: the #CoglBufferUpdateHint currently used by the buffer * * Since: 1.2 * Stability: unstable */ CoglBufferUpdateHint cogl_buffer_get_update_hint (CoglBuffer *buffer); /** * CoglBufferAccess: * @COGL_BUFFER_ACCESS_READ: the buffer will be read * @COGL_BUFFER_ACCESS_WRITE: the buffer will written to * @COGL_BUFFER_ACCESS_READ_WRITE: the buffer will be used for both reading and * writing * * The access hints for cogl_buffer_set_update_hint() * * Since: 1.2 * Stability: unstable */ typedef enum { /*< prefix=COGL_BUFFER_ACCESS >*/ COGL_BUFFER_ACCESS_READ = 1 << 0, COGL_BUFFER_ACCESS_WRITE = 1 << 1, COGL_BUFFER_ACCESS_READ_WRITE = COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE } CoglBufferAccess; /** * CoglBufferMapHint: * @COGL_BUFFER_MAP_HINT_DISCARD: Tells Cogl that you plan to replace * all the buffer's contents. When this flag is used to map a * buffer, the entire contents of the buffer become undefined, even * if only a subregion of the buffer is mapped. * @COGL_BUFFER_MAP_HINT_DISCARD_RANGE: Tells Cogl that you plan to * replace all the contents of the mapped region. The contents of * the region specified are undefined after this flag is used to * map a buffer. * * Hints to Cogl about how you are planning to modify the data once it * is mapped. * * Since: 1.4 * Stability: unstable */ typedef enum { /*< prefix=COGL_BUFFER_MAP_HINT >*/ COGL_BUFFER_MAP_HINT_DISCARD = 1 << 0, COGL_BUFFER_MAP_HINT_DISCARD_RANGE = 1 << 1 } CoglBufferMapHint; /** * cogl_buffer_map: * @buffer: a buffer object * @access: how the mapped buffer will be used by the application * @hints: A mask of #CoglBufferMapHints that tell Cogl how * the data will be modified once mapped. * * Maps the buffer into the application address space for direct * access. This is equivalent to calling cogl_buffer_map_range() with * zero as the offset and the size of the entire buffer as the size. * * It is strongly recommended that you pass * %COGL_BUFFER_MAP_HINT_DISCARD as a hint if you are going to replace * all the buffer's data. This way if the buffer is currently being * used by the GPU then the driver won't have to stall the CPU and * wait for the hardware to finish because it can instead allocate a * new buffer to map. * * The behaviour is undefined if you access the buffer in a way * conflicting with the @access mask you pass. It is also an error to * release your last reference while the buffer is mapped. * * Return value: (transfer none): A pointer to the mapped memory or * %NULL is the call fails * * Since: 1.2 * Stability: unstable */ void * cogl_buffer_map (CoglBuffer *buffer, CoglBufferAccess access, CoglBufferMapHint hints); /** * cogl_buffer_map_range: * @buffer: a buffer object * @offset: Offset within the buffer to start the mapping * @size: The size of data to map * @access: how the mapped buffer will be used by the application * @hints: A mask of #CoglBufferMapHints that tell Cogl how * the data will be modified once mapped. * @error: A #CoglError for catching exceptional errors * * Maps a sub-region of the buffer into the application's address space * for direct access. * * It is strongly recommended that you pass * %COGL_BUFFER_MAP_HINT_DISCARD as a hint if you are going to replace * all the buffer's data. This way if the buffer is currently being * used by the GPU then the driver won't have to stall the CPU and * wait for the hardware to finish because it can instead allocate a * new buffer to map. You can pass * %COGL_BUFFER_MAP_HINT_DISCARD_RANGE instead if you want the * regions outside of the mapping to be retained. * * The behaviour is undefined if you access the buffer in a way * conflicting with the @access mask you pass. It is also an error to * release your last reference while the buffer is mapped. * * Return value: (transfer none): A pointer to the mapped memory or * %NULL is the call fails * * Since: 2.0 * Stability: unstable */ void * cogl_buffer_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error); /** * cogl_buffer_unmap: * @buffer: a buffer object * * Unmaps a buffer previously mapped by cogl_buffer_map(). * * Since: 1.2 * Stability: unstable */ void cogl_buffer_unmap (CoglBuffer *buffer); /** * cogl_buffer_set_data: * @buffer: a buffer object * @offset: destination offset (in bytes) in the buffer * @data: a pointer to the data to be copied into the buffer * @size: number of bytes to copy * * Updates part of the buffer with new data from @data. Where to put this new * data is controlled by @offset and @offset + @data should be less than the * buffer size. * * Return value: %TRUE is the operation succeeded, %FALSE otherwise * * Since: 1.2 * Stability: unstable */ CoglBool cogl_buffer_set_data (CoglBuffer *buffer, size_t offset, const void *data, size_t size); COGL_END_DECLS #endif /* __COGL_BUFFER_H__ */ muffin-5.2.1/cogl/cogl/cogl-texture-driver.h0000664000175000017500000001725414211404421021101 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_TEXTURE_DRIVER_H #define __COGL_TEXTURE_DRIVER_H typedef struct _CoglTextureDriver CoglTextureDriver; struct _CoglTextureDriver { /* * A very small wrapper around glGenTextures() that ensures we default to * non-mipmap filters when creating textures. This is to save some memory as * the driver will not allocate room for the mipmap tree. */ GLuint (* gen) (CoglContext *ctx, GLenum gl_target, CoglPixelFormat internal_format); /* * This sets up the glPixelStore state for an upload to a destination with * the same size, and with no offset. */ /* NB: GLES can't upload a sub region of pixel data from a larger source * buffer which is why this interface is limited. The GL driver has a more * flexible version of this function that is uses internally */ void (* prep_gl_for_pixels_upload) (CoglContext *ctx, int pixels_rowstride, int pixels_bpp); /* * This uploads a sub-region from source_bmp to a single GL texture * handle (i.e a single CoglTexture slice) * * It also updates the array of tex->first_pixels[slice_index] if * dst_{x,y} == 0 * * The driver abstraction is in place because GLES doesn't support the pixel * store options required to source from a subregion, so for GLES we have * to manually create a transient source bitmap. * * XXX: sorry for the ridiculous number of arguments :-( */ CoglBool (* upload_subregion_to_gl) (CoglContext *ctx, CoglTexture *texture, CoglBool is_foreign, int src_x, int src_y, int dst_x, int dst_y, int width, int height, int level, CoglBitmap *source_bmp, GLuint source_gl_format, GLuint source_gl_type, CoglError **error); /* * Replaces the contents of the GL texture with the entire bitmap. On * GL this just directly calls glTexImage2D, but under GLES it needs * to copy the bitmap if the rowstride is not a multiple of a possible * alignment value because there is no GL_UNPACK_ROW_LENGTH */ CoglBool (* upload_to_gl) (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error); /* * Replaces the contents of the GL texture with the entire bitmap. The * width of the texture is inferred from the bitmap. The height and * depth of the texture is given directly. The 'image_height' (which * is the number of rows between images) is inferred by dividing the * height of the bitmap by the depth. */ CoglBool (* upload_to_gl_3d) (CoglContext *ctx, GLenum gl_target, GLuint gl_handle, CoglBool is_foreign, GLint height, GLint depth, CoglBitmap *source_bmp, GLint internal_gl_format, GLuint source_gl_format, GLuint source_gl_type, CoglError **error); /* * This sets up the glPixelStore state for an download to a destination with * the same size, and with no offset. */ /* NB: GLES can't download pixel data into a sub region of a larger * destination buffer, the GL driver has a more flexible version of * this function that it uses internally. */ void (* prep_gl_for_pixels_download) (CoglContext *ctx, int image_width, int pixels_rowstride, int pixels_bpp); /* * This driver abstraction is needed because GLES doesn't support * glGetTexImage (). On GLES this currently just returns FALSE which * will lead to a generic fallback path being used that simply * renders the texture and reads it back from the framebuffer. (See * _cogl_texture_draw_and_read () ) */ CoglBool (* gl_get_tex_image) (CoglContext *ctx, GLenum gl_target, GLenum dest_gl_format, GLenum dest_gl_type, uint8_t *dest); /* * It may depend on the driver as to what texture sizes are supported... */ CoglBool (* size_supported) (CoglContext *ctx, GLenum gl_target, GLenum gl_intformat, GLenum gl_format, GLenum gl_type, int width, int height); CoglBool (* size_supported_3d) (CoglContext *ctx, GLenum gl_target, GLenum gl_format, GLenum gl_type, int width, int height, int depth); /* * This driver abstraction is needed because GLES doesn't support setting * a texture border color. */ void (* try_setting_gl_border_color) (CoglContext *ctx, GLuint gl_target, const GLfloat *transparent_color); /* * It may depend on the driver as to what texture targets may be used when * creating a foreign texture. E.g. OpenGL supports ARB_texture_rectangle * but GLES doesn't */ CoglBool (* allows_foreign_gl_target) (CoglContext *ctx, GLenum gl_target); /* * The driver may impose constraints on what formats can be used to store * texture data read from textures. For example GLES currently only supports * RGBA_8888, and so we need to manually convert the data if the final * destination has another format. */ CoglPixelFormat (* find_best_gl_get_data_format) (CoglContext *context, CoglPixelFormat format, CoglPixelFormat target_format, GLenum *closest_gl_format, GLenum *closest_gl_type); }; #endif /* __COGL_TEXTURE_DRIVER_H */ muffin-5.2.1/cogl/cogl/cogl-primitives.h0000664000175000017500000001637414211404421020305 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PRIMITIVES_H #define __COGL_PRIMITIVES_H #include COGL_BEGIN_DECLS /** * SECTION:cogl-primitives * @short_description: Functions that draw various primitive 3D shapes * * The primitives API provides utilities for drawing some * common 3D shapes in a more convenient way than the CoglVertexBuffer * API provides. */ /** * cogl_rectangle: * @x_1: X coordinate of the top-left corner * @y_1: Y coordinate of the top-left corner * @x_2: X coordinate of the bottom-right corner * @y_2: Y coordinate of the bottom-right corner * * Fills a rectangle at the given coordinates with the current source material **/ void cogl_rectangle (float x_1, float y_1, float x_2, float y_2); /** * cogl_rectangle_with_texture_coords: * @x1: x coordinate upper left on screen. * @y1: y coordinate upper left on screen. * @x2: x coordinate lower right on screen. * @y2: y coordinate lower right on screen. * @tx1: x part of texture coordinate to use for upper left pixel * @ty1: y part of texture coordinate to use for upper left pixel * @tx2: x part of texture coordinate to use for lower right pixel * @ty2: y part of texture coordinate to use for left pixel * * Draw a rectangle using the current material and supply texture coordinates * to be used for the first texture layer of the material. To draw the entire * texture pass in @tx1=0.0 @ty1=0.0 @tx2=1.0 @ty2=1.0. * * Since: 1.0 */ void cogl_rectangle_with_texture_coords (float x1, float y1, float x2, float y2, float tx1, float ty1, float tx2, float ty2); /** * cogl_rectangle_with_multitexture_coords: * @x1: x coordinate upper left on screen. * @y1: y coordinate upper left on screen. * @x2: x coordinate lower right on screen. * @y2: y coordinate lower right on screen. * @tex_coords: (in) (array) (transfer none): An array containing groups of * 4 float values: [tx1, ty1, tx2, ty2] that are interpreted as two texture * coordinates; one for the upper left texel, and one for the lower right * texel. Each value should be between 0.0 and 1.0, where the coordinate * (0.0, 0.0) represents the top left of the texture, and (1.0, 1.0) the * bottom right. * @tex_coords_len: The length of the tex_coords array. (e.g. for one layer * and one group of texture coordinates, this would be 4) * * This function draws a rectangle using the current source material to * texture or fill with. As a material may contain multiple texture layers * this interface lets you supply texture coordinates for each layer of the * material. * * The first pair of coordinates are for the first layer (with the smallest * layer index) and if you supply less texture coordinates than there are * layers in the current source material then default texture coordinates * (0.0, 0.0, 1.0, 1.0) are generated. * * Since: 1.0 */ void cogl_rectangle_with_multitexture_coords (float x1, float y1, float x2, float y2, const float *tex_coords, int tex_coords_len); /** * cogl_rectangles_with_texture_coords: * @verts: (in) (array) (transfer none): an array of vertices * @n_rects: number of rectangles to draw * * Draws a series of rectangles in the same way that * cogl_rectangle_with_texture_coords() does. In some situations it can give a * significant performance boost to use this function rather than * calling cogl_rectangle_with_texture_coords() separately for each rectangle. * * @verts should point to an array of #floats with * @n_rects * 8 elements. Each group of 8 values corresponds to the * parameters x1, y1, x2, y2, tx1, ty1, tx2 and ty2 and have the same * meaning as in cogl_rectangle_with_texture_coords(). * * Since: 0.8.6 */ void cogl_rectangles_with_texture_coords (const float *verts, unsigned int n_rects); /** * cogl_rectangles: * @verts: (in) (array) (transfer none): an array of vertices * @n_rects: number of rectangles to draw * * Draws a series of rectangles in the same way that * cogl_rectangle() does. In some situations it can give a * significant performance boost to use this function rather than * calling cogl_rectangle() separately for each rectangle. * * @verts should point to an array of #floats with * @n_rects * 4 elements. Each group of 4 values corresponds to the * parameters x1, y1, x2, and y2, and have the same * meaning as in cogl_rectangle(). * * Since: 1.0 */ void cogl_rectangles (const float *verts, unsigned int n_rects); /** * cogl_polygon: * @vertices: An array of #CoglTextureVertex structs * @n_vertices: The length of the vertices array * @use_color: %TRUE if the color member of #CoglTextureVertex should be used * * Draws a convex polygon using the current source material to fill / texture * with according to the texture coordinates passed. * * If @use_color is %TRUE then the color will be changed for each vertex using * the value specified in the color member of #CoglTextureVertex. This can be * used for example to make the texture fade out by setting the alpha value of * the color. * * All of the texture coordinates must be in the range [0,1] and repeating the * texture is not supported. * * Because of the way this function is implemented it will currently * only work if either the texture is not sliced or the backend is not * OpenGL ES and the minifying and magnifying functions are both set * to COGL_MATERIAL_FILTER_NEAREST. * * Since: 1.0 */ void cogl_polygon (const CoglTextureVertex *vertices, unsigned int n_vertices, CoglBool use_color); COGL_END_DECLS #endif /* __COGL_PRIMITIVES_H */ muffin-5.2.1/cogl/cogl/cogl-bitmap-conversion.c0000664000175000017500000005375314211404421021546 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-private.h" #include "cogl-bitmap-private.h" #include "cogl-context-private.h" #include "cogl-texture-private.h" #include #define component_type uint8_t #define component_size 8 /* We want to specially optimise the packing when we are converting to/from an 8-bit type so that it won't do anything. That way for example if we are just doing a swizzle conversion then the inner loop for the conversion will be really simple */ #define UNPACK_BYTE(b) (b) #define PACK_BYTE(b) (b) #include "cogl-bitmap-packing.h" #undef PACK_BYTE #undef UNPACK_BYTE #undef component_type #undef component_size #define component_type uint16_t #define component_size 16 #define UNPACK_BYTE(b) (((b) * 65535 + 127) / 255) #define PACK_BYTE(b) (((b) * 255 + 32767) / 65535) #include "cogl-bitmap-packing.h" #undef PACK_BYTE #undef UNPACK_BYTE #undef component_type #undef component_size /* (Un)Premultiplication */ inline static void _cogl_unpremult_alpha_0 (uint8_t *dst) { dst[0] = 0; dst[1] = 0; dst[2] = 0; dst[3] = 0; } inline static void _cogl_unpremult_alpha_last (uint8_t *dst) { uint8_t alpha = dst[3]; dst[0] = (dst[0] * 255) / alpha; dst[1] = (dst[1] * 255) / alpha; dst[2] = (dst[2] * 255) / alpha; } inline static void _cogl_unpremult_alpha_first (uint8_t *dst) { uint8_t alpha = dst[0]; dst[1] = (dst[1] * 255) / alpha; dst[2] = (dst[2] * 255) / alpha; dst[3] = (dst[3] * 255) / alpha; } /* No division form of floor((c*a + 128)/255) (I first encountered * this in the RENDER implementation in the X server.) Being exact * is important for a == 255 - we want to get exactly c. */ #define MULT(d,a,t) \ G_STMT_START { \ t = d * a + 128; \ d = ((t >> 8) + t) >> 8; \ } G_STMT_END inline static void _cogl_premult_alpha_last (uint8_t *dst) { uint8_t alpha = dst[3]; /* Using a separate temporary per component has given slightly better * code generation with GCC in the past; it shouldn't do any worse in * any case. */ unsigned int t1, t2, t3; MULT(dst[0], alpha, t1); MULT(dst[1], alpha, t2); MULT(dst[2], alpha, t3); } inline static void _cogl_premult_alpha_first (uint8_t *dst) { uint8_t alpha = dst[0]; unsigned int t1, t2, t3; MULT(dst[1], alpha, t1); MULT(dst[2], alpha, t2); MULT(dst[3], alpha, t3); } #undef MULT /* Use the SSE optimized version to premult four pixels at once when it is available. The same assembler code works for x86 and x86-64 because it doesn't refer to any non-SSE registers directly */ #if defined(__SSE2__) && defined(__GNUC__) \ && (defined(__x86_64) || defined(__i386)) #define COGL_USE_PREMULT_SSE2 #endif #ifdef COGL_USE_PREMULT_SSE2 inline static void _cogl_premult_alpha_last_four_pixels_sse2 (uint8_t *p) { /* 8 copies of 128 used below */ static const int16_t eight_halves[8] __attribute__ ((aligned (16))) = { 128, 128, 128, 128, 128, 128, 128, 128 }; /* Mask of the rgb components of the four pixels */ static const int8_t just_rgb[16] __attribute__ ((aligned (16))) = { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00 }; /* Each SSE register only holds two pixels because we need to work with 16-bit intermediate values. We still do four pixels by interleaving two registers in the hope that it will pipeline better */ asm (/* Load eight_halves into xmm5 for later */ "movdqa (%1), %%xmm5\n" /* Clear xmm3 */ "pxor %%xmm3, %%xmm3\n" /* Load two pixels from p into the low half of xmm0 */ "movlps (%0), %%xmm0\n" /* Load the next set of two pixels from p into the low half of xmm1 */ "movlps 8(%0), %%xmm1\n" /* Unpack 8 bytes from the low quad-words in each register to 8 16-bit values */ "punpcklbw %%xmm3, %%xmm0\n" "punpcklbw %%xmm3, %%xmm1\n" /* Copy alpha values of the first pixel in xmm0 to all components of the first pixel in xmm2 */ "pshuflw $255, %%xmm0, %%xmm2\n" /* same for xmm1 and xmm3 */ "pshuflw $255, %%xmm1, %%xmm3\n" /* The above also copies the second pixel directly so we now want to replace the RGB components with copies of the alpha components */ "pshufhw $255, %%xmm2, %%xmm2\n" "pshufhw $255, %%xmm3, %%xmm3\n" /* Multiply the rgb components by the alpha */ "pmullw %%xmm2, %%xmm0\n" "pmullw %%xmm3, %%xmm1\n" /* Add 128 to each component */ "paddw %%xmm5, %%xmm0\n" "paddw %%xmm5, %%xmm1\n" /* Copy the results to temporary registers xmm4 and xmm5 */ "movdqa %%xmm0, %%xmm4\n" "movdqa %%xmm1, %%xmm5\n" /* Divide the results by 256 */ "psrlw $8, %%xmm0\n" "psrlw $8, %%xmm1\n" /* Add the temporaries back in */ "paddw %%xmm4, %%xmm0\n" "paddw %%xmm5, %%xmm1\n" /* Divide again */ "psrlw $8, %%xmm0\n" "psrlw $8, %%xmm1\n" /* Pack the results back as bytes */ "packuswb %%xmm1, %%xmm0\n" /* Load just_rgb into xmm3 for later */ "movdqa (%2), %%xmm3\n" /* Reload all four pixels into xmm2 */ "movups (%0), %%xmm2\n" /* Mask out the alpha from the results */ "andps %%xmm3, %%xmm0\n" /* Mask out the RGB from the original four pixels */ "andnps %%xmm2, %%xmm3\n" /* Combine the two to get the right alpha values */ "orps %%xmm3, %%xmm0\n" /* Write to memory */ "movdqu %%xmm0, (%0)\n" : /* no outputs */ : "r" (p), "r" (eight_halves), "r" (just_rgb) : "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); } #endif /* COGL_USE_PREMULT_SSE2 */ static void _cogl_bitmap_premult_unpacked_span_8 (uint8_t *data, int width) { #ifdef COGL_USE_PREMULT_SSE2 /* Process 4 pixels at a time */ while (width >= 4) { _cogl_premult_alpha_last_four_pixels_sse2 (data); data += 4 * 4; width -= 4; } /* If there are any pixels left we will fall through and handle them below */ #endif /* COGL_USE_PREMULT_SSE2 */ while (width-- > 0) { _cogl_premult_alpha_last (data); data += 4; } } static void _cogl_bitmap_unpremult_unpacked_span_8 (uint8_t *data, int width) { int x; for (x = 0; x < width; x++) { if (data[3] == 0) _cogl_unpremult_alpha_0 (data); else _cogl_unpremult_alpha_last (data); data += 4; } } static void _cogl_bitmap_unpremult_unpacked_span_16 (uint16_t *data, int width) { while (width-- > 0) { uint16_t alpha = data[3]; if (alpha == 0) memset (data, 0, sizeof (uint16_t) * 3); else { data[0] = (data[0] * 65535) / alpha; data[1] = (data[1] * 65535) / alpha; data[2] = (data[2] * 65535) / alpha; } } } static void _cogl_bitmap_premult_unpacked_span_16 (uint16_t *data, int width) { while (width-- > 0) { uint16_t alpha = data[3]; data[0] = (data[0] * alpha) / 65535; data[1] = (data[1] * alpha) / 65535; data[2] = (data[2] * alpha) / 65535; } } static CoglBool _cogl_bitmap_can_fast_premult (CoglPixelFormat format) { switch (format & ~COGL_PREMULT_BIT) { case COGL_PIXEL_FORMAT_RGBA_8888: case COGL_PIXEL_FORMAT_BGRA_8888: case COGL_PIXEL_FORMAT_ARGB_8888: case COGL_PIXEL_FORMAT_ABGR_8888: return TRUE; default: return FALSE; } } static CoglBool _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format) { /* If the format is using more than 8 bits per component then we'll unpack into a 16-bit per component buffer instead of 8-bit so we won't lose as much precision. If we ever add support for formats with more than 16 bits for at least one of the components then we should probably do something else here, maybe convert to floats */ switch (format) { case COGL_PIXEL_FORMAT_DEPTH_16: case COGL_PIXEL_FORMAT_DEPTH_32: case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: case COGL_PIXEL_FORMAT_ANY: case COGL_PIXEL_FORMAT_YUV: g_assert_not_reached (); case COGL_PIXEL_FORMAT_A_8: case COGL_PIXEL_FORMAT_RG_88: case COGL_PIXEL_FORMAT_RGB_565: case COGL_PIXEL_FORMAT_RGBA_4444: case COGL_PIXEL_FORMAT_RGBA_5551: case COGL_PIXEL_FORMAT_G_8: case COGL_PIXEL_FORMAT_RGB_888: case COGL_PIXEL_FORMAT_BGR_888: case COGL_PIXEL_FORMAT_RGBA_8888: case COGL_PIXEL_FORMAT_BGRA_8888: case COGL_PIXEL_FORMAT_ARGB_8888: case COGL_PIXEL_FORMAT_ABGR_8888: case COGL_PIXEL_FORMAT_RGBA_8888_PRE: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: case COGL_PIXEL_FORMAT_ARGB_8888_PRE: case COGL_PIXEL_FORMAT_ABGR_8888_PRE: case COGL_PIXEL_FORMAT_RGBA_4444_PRE: case COGL_PIXEL_FORMAT_RGBA_5551_PRE: return FALSE; case COGL_PIXEL_FORMAT_RGBA_1010102: case COGL_PIXEL_FORMAT_BGRA_1010102: case COGL_PIXEL_FORMAT_ARGB_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010: case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: return TRUE; } g_assert_not_reached (); } CoglBool _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, CoglBitmap *dst_bmp, CoglError **error) { uint8_t *src_data; uint8_t *dst_data; uint8_t *src; uint8_t *dst; void *tmp_row; int src_rowstride; int dst_rowstride; int y; int width, height; CoglPixelFormat src_format; CoglPixelFormat dst_format; CoglBool use_16; CoglBool need_premult; src_format = cogl_bitmap_get_format (src_bmp); src_rowstride = cogl_bitmap_get_rowstride (src_bmp); dst_format = cogl_bitmap_get_format (dst_bmp); dst_rowstride = cogl_bitmap_get_rowstride (dst_bmp); width = cogl_bitmap_get_width (src_bmp); height = cogl_bitmap_get_height (src_bmp); _COGL_RETURN_VAL_IF_FAIL (width == cogl_bitmap_get_width (dst_bmp), FALSE); _COGL_RETURN_VAL_IF_FAIL (height == cogl_bitmap_get_height (dst_bmp), FALSE); need_premult = ((src_format & COGL_PREMULT_BIT) != (dst_format & COGL_PREMULT_BIT) && src_format != COGL_PIXEL_FORMAT_A_8 && dst_format != COGL_PIXEL_FORMAT_A_8 && (src_format & dst_format & COGL_A_BIT)); /* If the base format is the same then we can just copy the bitmap instead */ if ((src_format & ~COGL_PREMULT_BIT) == (dst_format & ~COGL_PREMULT_BIT) && (!need_premult || _cogl_bitmap_can_fast_premult (dst_format))) { if (!_cogl_bitmap_copy_subregion (src_bmp, dst_bmp, 0, 0, /* src_x / src_y */ 0, 0, /* dst_x / dst_y */ width, height, error)) return FALSE; if (need_premult) { if ((dst_format & COGL_PREMULT_BIT)) { if (!_cogl_bitmap_premult (dst_bmp, error)) return FALSE; } else { if (!_cogl_bitmap_unpremult (dst_bmp, error)) return FALSE; } } return TRUE; } src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0, error); if (src_data == NULL) return FALSE; dst_data = _cogl_bitmap_map (dst_bmp, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, error); if (dst_data == NULL) { _cogl_bitmap_unmap (src_bmp); return FALSE; } use_16 = _cogl_bitmap_needs_short_temp_buffer (dst_format); /* Allocate a buffer to hold a temporary RGBA row */ tmp_row = malloc (width * (use_16 ? sizeof (uint16_t) : sizeof (uint8_t)) * 4); /* FIXME: Optimize */ for (y = 0; y < height; y++) { src = src_data + y * src_rowstride; dst = dst_data + y * dst_rowstride; if (use_16) _cogl_unpack_16 (src_format, src, tmp_row, width); else _cogl_unpack_8 (src_format, src, tmp_row, width); /* Handle premultiplication */ if (need_premult) { if (dst_format & COGL_PREMULT_BIT) { if (use_16) _cogl_bitmap_premult_unpacked_span_16 (tmp_row, width); else _cogl_bitmap_premult_unpacked_span_8 (tmp_row, width); } else { if (use_16) _cogl_bitmap_unpremult_unpacked_span_16 (tmp_row, width); else _cogl_bitmap_unpremult_unpacked_span_8 (tmp_row, width); } } if (use_16) _cogl_pack_16 (dst_format, tmp_row, dst, width); else _cogl_pack_8 (dst_format, tmp_row, dst, width); } _cogl_bitmap_unmap (src_bmp); _cogl_bitmap_unmap (dst_bmp); free (tmp_row); return TRUE; } CoglBitmap * _cogl_bitmap_convert (CoglBitmap *src_bmp, CoglPixelFormat dst_format, CoglError **error) { CoglBitmap *dst_bmp; int width, height; _COGL_GET_CONTEXT (ctx, NULL); width = cogl_bitmap_get_width (src_bmp); height = cogl_bitmap_get_height (src_bmp); dst_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, width, height, dst_format, error); if (!dst_bmp) return NULL; if (!_cogl_bitmap_convert_into_bitmap (src_bmp, dst_bmp, error)) { cogl_object_unref (dst_bmp); return NULL; } return dst_bmp; } static CoglBool driver_can_convert (CoglContext *ctx, CoglPixelFormat src_format, CoglPixelFormat internal_format) { if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_FORMAT_CONVERSION)) return FALSE; if (src_format == internal_format) return TRUE; /* If the driver doesn't natively support alpha textures then it * won't work correctly to convert to/from component-alpha * textures */ if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && (src_format == COGL_PIXEL_FORMAT_A_8 || internal_format == COGL_PIXEL_FORMAT_A_8)) return FALSE; /* Same for red-green textures. If red-green textures aren't * supported then the internal format should never be RG_88 but we * should still be able to convert from an RG source image */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RG) && src_format == COGL_PIXEL_FORMAT_RG_88) return FALSE; return TRUE; } CoglBitmap * _cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp, CoglPixelFormat internal_format, CoglBool can_convert_in_place, CoglError **error) { CoglContext *ctx = _cogl_bitmap_get_context (src_bmp); CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp); CoglBitmap *dst_bmp; _COGL_RETURN_VAL_IF_FAIL (internal_format != COGL_PIXEL_FORMAT_ANY, NULL); /* OpenGL supports specifying a different format for the internal format when uploading texture data. We should use this to convert formats because it is likely to be faster and support more types than the Cogl bitmap code. However under GLES the internal format must be the same as the bitmap format and it only supports a limited number of formats so we must convert using the Cogl bitmap code instead */ if (driver_can_convert (ctx, src_format, internal_format)) { /* If the source format does not have the same premult flag as the internal_format then we need to copy and convert it */ if (_cogl_texture_needs_premult_conversion (src_format, internal_format)) { if (can_convert_in_place) { if (_cogl_bitmap_convert_premult_status (src_bmp, (src_format ^ COGL_PREMULT_BIT), error)) { dst_bmp = cogl_object_ref (src_bmp); } else return NULL; } else { dst_bmp = _cogl_bitmap_convert (src_bmp, src_format ^ COGL_PREMULT_BIT, error); if (dst_bmp == NULL) return NULL; } } else dst_bmp = cogl_object_ref (src_bmp); } else { CoglPixelFormat closest_format; closest_format = ctx->driver_vtable->pixel_format_to_gl (ctx, internal_format, NULL, /* ignore gl intformat */ NULL, /* ignore gl format */ NULL); /* ignore gl type */ if (closest_format != src_format) dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format, error); else dst_bmp = cogl_object_ref (src_bmp); } return dst_bmp; } CoglBool _cogl_bitmap_unpremult (CoglBitmap *bmp, CoglError **error) { uint8_t *p, *data; uint16_t *tmp_row; int x,y; CoglPixelFormat format; int width, height; int rowstride; format = cogl_bitmap_get_format (bmp); width = cogl_bitmap_get_width (bmp); height = cogl_bitmap_get_height (bmp); rowstride = cogl_bitmap_get_rowstride (bmp); if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE, 0, error)) == NULL) return FALSE; /* If we can't directly unpremult the data inline then we'll allocate a temporary row and unpack the data. This assumes if we can fast premult then we can also fast unpremult */ if (_cogl_bitmap_can_fast_premult (format)) tmp_row = NULL; else tmp_row = malloc (sizeof (uint16_t) * 4 * width); for (y = 0; y < height; y++) { p = (uint8_t*) data + y * rowstride; if (tmp_row) { _cogl_unpack_16 (format, p, tmp_row, width); _cogl_bitmap_unpremult_unpacked_span_16 (tmp_row, width); _cogl_pack_16 (format, tmp_row, p, width); } else { if (format & COGL_AFIRST_BIT) { for (x = 0; x < width; x++) { if (p[0] == 0) _cogl_unpremult_alpha_0 (p); else _cogl_unpremult_alpha_first (p); p += 4; } } else _cogl_bitmap_unpremult_unpacked_span_8 (p, width); } } free (tmp_row); _cogl_bitmap_unmap (bmp); _cogl_bitmap_set_format (bmp, format & ~COGL_PREMULT_BIT); return TRUE; } CoglBool _cogl_bitmap_premult (CoglBitmap *bmp, CoglError **error) { uint8_t *p, *data; uint16_t *tmp_row; int x,y; CoglPixelFormat format; int width, height; int rowstride; format = cogl_bitmap_get_format (bmp); width = cogl_bitmap_get_width (bmp); height = cogl_bitmap_get_height (bmp); rowstride = cogl_bitmap_get_rowstride (bmp); if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE, 0, error)) == NULL) return FALSE; /* If we can't directly premult the data inline then we'll allocate a temporary row and unpack the data. */ if (_cogl_bitmap_can_fast_premult (format)) tmp_row = NULL; else tmp_row = malloc (sizeof (uint16_t) * 4 * width); for (y = 0; y < height; y++) { p = (uint8_t*) data + y * rowstride; if (tmp_row) { _cogl_unpack_16 (format, p, tmp_row, width); _cogl_bitmap_premult_unpacked_span_16 (tmp_row, width); _cogl_pack_16 (format, tmp_row, p, width); } else { if (format & COGL_AFIRST_BIT) { for (x = 0; x < width; x++) { _cogl_premult_alpha_first (p); p += 4; } } else _cogl_bitmap_premult_unpacked_span_8 (p, width); } } free (tmp_row); _cogl_bitmap_unmap (bmp); _cogl_bitmap_set_format (bmp, format | COGL_PREMULT_BIT); return TRUE; } muffin-5.2.1/cogl/cogl/cogl-pipeline.c0000664000175000017500000032303014211404421017700 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-context-private.h" #include "cogl-object.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-pipeline-state-private.h" #include "cogl-pipeline-layer-state-private.h" #include "cogl-texture-private.h" #include "cogl-blend-string.h" #include "cogl-journal-private.h" #include "cogl-color-private.h" #include "cogl-util.h" #include "cogl-profile.h" #include "cogl-depth-state-private.h" #include "cogl1-context.h" #include "cogl-gtype-private.h" #include #include #include static void _cogl_pipeline_free (CoglPipeline *tex); static void recursively_free_layer_caches (CoglPipeline *pipeline); static CoglBool _cogl_pipeline_is_weak (CoglPipeline *pipeline); const CoglPipelineFragend *_cogl_pipeline_fragends[COGL_PIPELINE_N_FRAGENDS]; const CoglPipelineVertend *_cogl_pipeline_vertends[COGL_PIPELINE_N_VERTENDS]; /* The 'MAX' here is so that we don't define an empty array when there are no progends */ const CoglPipelineProgend * _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)]; #ifdef COGL_PIPELINE_FRAGEND_GLSL #include "cogl-pipeline-fragend-glsl-private.h" #endif #ifdef COGL_PIPELINE_FRAGEND_ARBFP #include "cogl-pipeline-fragend-arbfp-private.h" #endif #ifdef COGL_PIPELINE_FRAGEND_FIXED #include "cogl-pipeline-fragend-fixed-private.h" #endif #ifdef COGL_PIPELINE_VERTEND_GLSL #include "cogl-pipeline-vertend-glsl-private.h" #endif #ifdef COGL_PIPELINE_VERTEND_FIXED #include "cogl-pipeline-vertend-fixed-private.h" #endif #ifdef COGL_PIPELINE_PROGEND_FIXED_ARBFP #include "cogl-pipeline-progend-fixed-arbfp-private.h" #endif #ifdef COGL_PIPELINE_PROGEND_FIXED #include "cogl-pipeline-progend-fixed-private.h" #endif #ifdef COGL_PIPELINE_PROGEND_GLSL #include "cogl-pipeline-progend-glsl-private.h" #endif COGL_OBJECT_DEFINE (Pipeline, pipeline); COGL_GTYPE_DEFINE_CLASS (Pipeline, pipeline); /* * This initializes the first pipeline owned by the Cogl context. All * subsequently instantiated pipelines created via the cogl_pipeline_new() * API will initially be a copy of this pipeline. * * The default pipeline is the topmost ancester for all pipelines. */ void _cogl_pipeline_init_default_pipeline (void) { /* Create new - blank - pipeline */ CoglPipeline *pipeline = g_slice_new0 (CoglPipeline); /* XXX: NB: It's important that we zero this to avoid polluting * pipeline hash values with un-initialized data */ CoglPipelineBigState *big_state = g_slice_new0 (CoglPipelineBigState); CoglPipelineLightingState *lighting_state = &big_state->lighting_state; CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state; CoglPipelineBlendState *blend_state = &big_state->blend_state; CoglPipelineLogicOpsState *logic_ops_state = &big_state->logic_ops_state; CoglPipelineCullFaceState *cull_face_state = &big_state->cull_face_state; CoglPipelineUniformsState *uniforms_state = &big_state->uniforms_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Take this opportunity to setup the backends... */ #ifdef COGL_PIPELINE_FRAGEND_GLSL _cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_GLSL] = &_cogl_pipeline_glsl_fragend; #endif #ifdef COGL_PIPELINE_FRAGEND_ARBFP _cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_ARBFP] = &_cogl_pipeline_arbfp_fragend; #endif #ifdef COGL_PIPELINE_FRAGEND_FIXED _cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_FIXED] = &_cogl_pipeline_fixed_fragend; #endif #ifdef COGL_PIPELINE_PROGEND_FIXED _cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED_ARBFP] = &_cogl_pipeline_fixed_arbfp_progend; #endif #ifdef COGL_PIPELINE_PROGEND_FIXED _cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED] = &_cogl_pipeline_fixed_progend; #endif #ifdef COGL_PIPELINE_PROGEND_GLSL _cogl_pipeline_progends[COGL_PIPELINE_PROGEND_GLSL] = &_cogl_pipeline_glsl_progend; #endif #ifdef COGL_PIPELINE_VERTEND_GLSL _cogl_pipeline_vertends[COGL_PIPELINE_VERTEND_GLSL] = &_cogl_pipeline_glsl_vertend; #endif #ifdef COGL_PIPELINE_VERTEND_FIXED _cogl_pipeline_vertends[COGL_PIPELINE_VERTEND_FIXED] = &_cogl_pipeline_fixed_vertend; #endif _cogl_pipeline_node_init (COGL_NODE (pipeline)); pipeline->is_weak = FALSE; pipeline->journal_ref_count = 0; pipeline->progend = COGL_PIPELINE_PROGEND_UNDEFINED; pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE; pipeline->real_blend_enable = FALSE; pipeline->blend_enable = COGL_PIPELINE_BLEND_ENABLE_AUTOMATIC; pipeline->layer_differences = NULL; pipeline->n_layers = 0; pipeline->big_state = big_state; pipeline->has_big_state = TRUE; pipeline->static_breadcrumb = "default pipeline"; pipeline->has_static_breadcrumb = TRUE; pipeline->age = 0; /* Use the same defaults as the GL spec... */ cogl_color_init_from_4ub (&pipeline->color, 0xff, 0xff, 0xff, 0xff); /* Use the same defaults as the GL spec... */ lighting_state->ambient[0] = 0.2; lighting_state->ambient[1] = 0.2; lighting_state->ambient[2] = 0.2; lighting_state->ambient[3] = 1.0; lighting_state->diffuse[0] = 0.8; lighting_state->diffuse[1] = 0.8; lighting_state->diffuse[2] = 0.8; lighting_state->diffuse[3] = 1.0; lighting_state->specular[0] = 0; lighting_state->specular[1] = 0; lighting_state->specular[2] = 0; lighting_state->specular[3] = 1.0; lighting_state->emission[0] = 0; lighting_state->emission[1] = 0; lighting_state->emission[2] = 0; lighting_state->emission[3] = 1.0; lighting_state->shininess = 0.0f; /* Use the same defaults as the GL spec... */ alpha_state->alpha_func = COGL_PIPELINE_ALPHA_FUNC_ALWAYS; alpha_state->alpha_func_reference = 0.0; /* Not the same as the GL default, but seems saner... */ #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) blend_state->blend_equation_rgb = GL_FUNC_ADD; blend_state->blend_equation_alpha = GL_FUNC_ADD; blend_state->blend_src_factor_alpha = GL_ONE; blend_state->blend_dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA; cogl_color_init_from_4ub (&blend_state->blend_constant, 0x00, 0x00, 0x00, 0x00); #endif blend_state->blend_src_factor_rgb = GL_ONE; blend_state->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA; big_state->user_program = COGL_INVALID_HANDLE; cogl_depth_state_init (&big_state->depth_state); big_state->point_size = 0.0f; logic_ops_state->color_mask = COGL_COLOR_MASK_ALL; cull_face_state->mode = COGL_PIPELINE_CULL_FACE_MODE_NONE; cull_face_state->front_winding = COGL_WINDING_COUNTER_CLOCKWISE; _cogl_bitmask_init (&uniforms_state->override_mask); _cogl_bitmask_init (&uniforms_state->changed_mask); uniforms_state->override_values = NULL; ctx->default_pipeline = _cogl_pipeline_object_new (pipeline); } static void _cogl_pipeline_unparent (CoglNode *pipeline) { /* Chain up */ _cogl_pipeline_node_unparent_real (pipeline); } static CoglBool recursively_free_layer_caches_cb (CoglNode *node, void *user_data) { recursively_free_layer_caches (COGL_PIPELINE (node)); return TRUE; } /* This recursively frees the layers_cache of a pipeline and all of * its descendants. * * For instance if we change a pipelines ->layer_differences list * then that pipeline and all of its descendants may now have * incorrect layer caches. */ static void recursively_free_layer_caches (CoglPipeline *pipeline) { /* Note: we maintain the invariable that if a pipeline already has a * dirty layers_cache then so do all of its descendants. */ if (pipeline->layers_cache_dirty) return; if (G_UNLIKELY (pipeline->layers_cache != pipeline->short_layers_cache)) g_slice_free1 (sizeof (CoglPipelineLayer *) * pipeline->n_layers, pipeline->layers_cache); pipeline->layers_cache_dirty = TRUE; _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline), recursively_free_layer_caches_cb, NULL); } static void _cogl_pipeline_set_parent (CoglPipeline *pipeline, CoglPipeline *parent, CoglBool take_strong_reference) { /* Chain up */ _cogl_pipeline_node_set_parent_real (COGL_NODE (pipeline), COGL_NODE (parent), _cogl_pipeline_unparent, take_strong_reference); /* Since we just changed the ancestry of the pipeline its cache of * layers could now be invalid so free it... */ if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS) recursively_free_layer_caches (pipeline); /* If the backends are also caching state along with the pipeline * that depends on the pipeline's ancestry then it may be notified * here... */ if (pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED) { const CoglPipelineProgend *progend = _cogl_pipeline_progends[pipeline->progend]; const CoglPipelineFragend *fragend = _cogl_pipeline_fragends[progend->fragend]; /* Currently only the fragends ever care about reparenting of * pipelines... */ if (fragend->pipeline_set_parent_notify) fragend->pipeline_set_parent_notify (pipeline); } } static void _cogl_pipeline_promote_weak_ancestors (CoglPipeline *strong) { CoglNode *n; _COGL_RETURN_IF_FAIL (!strong->is_weak); /* If the parent of strong is weak, then we want to promote it by taking a reference on strong's grandparent. We don't need to take a reference on strong's direct parent */ if (COGL_NODE (strong)->parent == NULL) return; for (n = COGL_NODE (strong)->parent; /* We can assume that all weak pipelines have a parent */ COGL_PIPELINE (n)->is_weak; n = n->parent) /* 'n' is weak so we take a reference on its parent */ cogl_object_ref (n->parent); } static void _cogl_pipeline_revert_weak_ancestors (CoglPipeline *strong) { CoglNode *n; _COGL_RETURN_IF_FAIL (!strong->is_weak); /* This reverts the effect of calling _cogl_pipeline_promote_weak_ancestors */ if (COGL_NODE (strong)->parent == NULL) return; for (n = COGL_NODE (strong)->parent; /* We can assume that all weak pipelines have a parent */ COGL_PIPELINE (n)->is_weak; n = n->parent) /* 'n' is weak so we unref its parent */ cogl_object_unref (n->parent); } /* XXX: Always have an eye out for opportunities to lower the cost of * cogl_pipeline_copy. */ static CoglPipeline * _cogl_pipeline_copy (CoglPipeline *src, CoglBool is_weak) { CoglPipeline *pipeline = g_slice_new (CoglPipeline); _cogl_pipeline_node_init (COGL_NODE (pipeline)); pipeline->is_weak = is_weak; pipeline->journal_ref_count = 0; pipeline->differences = 0; pipeline->has_big_state = FALSE; /* NB: real_blend_enable isn't a sparse property, it's valid for * every pipeline node so we have fast access to it. */ pipeline->real_blend_enable = src->real_blend_enable; pipeline->dirty_real_blend_enable = src->dirty_real_blend_enable; pipeline->unknown_color_alpha = src->unknown_color_alpha; /* XXX: * consider generalizing the idea of "cached" properties. These * would still have an authority like other sparse properties but * you wouldn't have to walk up the ancestry to find the authority * because the value would be cached directly in each pipeline. */ pipeline->layers_cache_dirty = TRUE; pipeline->deprecated_get_layers_list = NULL; pipeline->deprecated_get_layers_list_dirty = TRUE; pipeline->progend = src->progend; pipeline->has_static_breadcrumb = FALSE; pipeline->age = 0; _cogl_pipeline_set_parent (pipeline, src, !is_weak); /* The semantics for copying a weak pipeline are that we promote all * weak ancestors to temporarily become strong pipelines until the * copy is freed. */ if (!is_weak) _cogl_pipeline_promote_weak_ancestors (pipeline); return _cogl_pipeline_object_new (pipeline); } CoglPipeline * cogl_pipeline_copy (CoglPipeline *src) { return _cogl_pipeline_copy (src, FALSE); } CoglPipeline * _cogl_pipeline_weak_copy (CoglPipeline *pipeline, CoglPipelineDestroyCallback callback, void *user_data) { CoglPipeline *copy; CoglPipeline *copy_pipeline; copy = _cogl_pipeline_copy (pipeline, TRUE); copy_pipeline = COGL_PIPELINE (copy); copy_pipeline->destroy_callback = callback; copy_pipeline->destroy_data = user_data; return copy; } CoglPipeline * cogl_pipeline_new (CoglContext *context) { CoglPipeline *new; new = cogl_pipeline_copy (context->default_pipeline); #ifdef COGL_DEBUG_ENABLED _cogl_pipeline_set_static_breadcrumb (new, "new"); #endif return new; } static CoglBool destroy_weak_children_cb (CoglNode *node, void *user_data) { CoglPipeline *pipeline = COGL_PIPELINE (node); if (_cogl_pipeline_is_weak (pipeline)) { _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline), destroy_weak_children_cb, NULL); pipeline->destroy_callback (pipeline, pipeline->destroy_data); _cogl_pipeline_unparent (COGL_NODE (pipeline)); } return TRUE; } static void _cogl_pipeline_free (CoglPipeline *pipeline) { if (!pipeline->is_weak) _cogl_pipeline_revert_weak_ancestors (pipeline); /* Weak pipelines don't take a reference on their parent */ _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline), destroy_weak_children_cb, NULL); g_assert (_cogl_list_empty (&COGL_NODE (pipeline)->children)); _cogl_pipeline_unparent (COGL_NODE (pipeline)); if (pipeline->differences & COGL_PIPELINE_STATE_USER_SHADER && pipeline->big_state->user_program) cogl_handle_unref (pipeline->big_state->user_program); if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) { CoglPipelineUniformsState *uniforms_state = &pipeline->big_state->uniforms_state; int n_overrides = _cogl_bitmask_popcount (&uniforms_state->override_mask); int i; for (i = 0; i < n_overrides; i++) _cogl_boxed_value_destroy (uniforms_state->override_values + i); free (uniforms_state->override_values); _cogl_bitmask_destroy (&uniforms_state->override_mask); _cogl_bitmask_destroy (&uniforms_state->changed_mask); } if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE) g_slice_free (CoglPipelineBigState, pipeline->big_state); if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS) { g_list_foreach (pipeline->layer_differences, (GFunc)cogl_object_unref, NULL); g_list_free (pipeline->layer_differences); } if (pipeline->differences & COGL_PIPELINE_STATE_VERTEX_SNIPPETS) _cogl_pipeline_snippet_list_free (&pipeline->big_state->vertex_snippets); if (pipeline->differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS) _cogl_pipeline_snippet_list_free (&pipeline->big_state->fragment_snippets); g_list_free (pipeline->deprecated_get_layers_list); recursively_free_layer_caches (pipeline); g_slice_free (CoglPipeline, pipeline); } CoglBool _cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); return pipeline->real_blend_enable; } static void _cogl_pipeline_update_layers_cache (CoglPipeline *pipeline) { /* Note: we assume this pipeline is a _LAYERS authority */ int n_layers; CoglPipeline *current; int layers_found; if (G_LIKELY (!pipeline->layers_cache_dirty) || pipeline->n_layers == 0) return; pipeline->layers_cache_dirty = FALSE; n_layers = pipeline->n_layers; if (G_LIKELY (n_layers < G_N_ELEMENTS (pipeline->short_layers_cache))) { pipeline->layers_cache = pipeline->short_layers_cache; memset (pipeline->layers_cache, 0, sizeof (CoglPipelineLayer *) * G_N_ELEMENTS (pipeline->short_layers_cache)); } else { pipeline->layers_cache = g_slice_alloc0 (sizeof (CoglPipelineLayer *) * n_layers); } /* Notes: * * Each pipeline doesn't have to contain a complete list of the layers * it depends on, some of them are indirectly referenced through the * pipeline's ancestors. * * pipeline->layer_differences only contains a list of layers that * have changed in relation to its parent. * * pipeline->layer_differences is not maintained sorted, but it * won't contain multiple layers corresponding to a particular * ->unit_index. * * Some of the ancestor pipelines may reference layers with * ->unit_index values >= n_layers so we ignore them. * * As we ascend through the ancestors we are searching for any * CoglPipelineLayers corresponding to the texture ->unit_index * values in the range [0,n_layers-1]. As soon as a pointer is found * we ignore layers of further ancestors with the same ->unit_index * values. */ layers_found = 0; for (current = pipeline; _cogl_pipeline_get_parent (current); current = _cogl_pipeline_get_parent (current)) { GList *l; if (!(current->differences & COGL_PIPELINE_STATE_LAYERS)) continue; for (l = current->layer_differences; l; l = l->next) { CoglPipelineLayer *layer = l->data; int unit_index = _cogl_pipeline_layer_get_unit_index (layer); if (unit_index < n_layers && !pipeline->layers_cache[unit_index]) { pipeline->layers_cache[unit_index] = layer; layers_found++; if (layers_found == n_layers) return; } } } g_warn_if_reached (); } /* XXX: Be carefull when using this API that the callback given doesn't result * in the layer cache being invalidated during the iteration! */ void _cogl_pipeline_foreach_layer_internal (CoglPipeline *pipeline, CoglPipelineInternalLayerCallback callback, void *user_data) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS); int n_layers; int i; CoglBool cont; n_layers = authority->n_layers; if (n_layers == 0) return; _cogl_pipeline_update_layers_cache (authority); for (i = 0, cont = TRUE; i < n_layers && cont == TRUE; i++) { _COGL_RETURN_IF_FAIL (authority->layers_cache_dirty == FALSE); cont = callback (authority->layers_cache[i], user_data); } } CoglBool _cogl_pipeline_layer_numbers_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1) { CoglPipeline *authority0 = _cogl_pipeline_get_authority (pipeline0, COGL_PIPELINE_STATE_LAYERS); CoglPipeline *authority1 = _cogl_pipeline_get_authority (pipeline1, COGL_PIPELINE_STATE_LAYERS); int n_layers = authority0->n_layers; int i; if (authority1->n_layers != n_layers) return FALSE; _cogl_pipeline_update_layers_cache (authority0); _cogl_pipeline_update_layers_cache (authority1); for (i = 0; i < n_layers; i++) { CoglPipelineLayer *layer0 = authority0->layers_cache[i]; CoglPipelineLayer *layer1 = authority1->layers_cache[i]; if (layer0->index != layer1->index) return FALSE; } return TRUE; } CoglBool _cogl_pipeline_layer_and_unit_numbers_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1) { CoglPipeline *authority0 = _cogl_pipeline_get_authority (pipeline0, COGL_PIPELINE_STATE_LAYERS); CoglPipeline *authority1 = _cogl_pipeline_get_authority (pipeline1, COGL_PIPELINE_STATE_LAYERS); int n_layers = authority0->n_layers; int i; if (authority1->n_layers != n_layers) return FALSE; _cogl_pipeline_update_layers_cache (authority0); _cogl_pipeline_update_layers_cache (authority1); for (i = 0; i < n_layers; i++) { CoglPipelineLayer *layer0 = authority0->layers_cache[i]; CoglPipelineLayer *layer1 = authority1->layers_cache[i]; int unit0, unit1; if (layer0->index != layer1->index) return FALSE; unit0 = _cogl_pipeline_layer_get_unit_index (layer0); unit1 = _cogl_pipeline_layer_get_unit_index (layer1); if (unit0 != unit1) return FALSE; } return TRUE; } typedef struct { int i; int *indices; } AppendLayerIndexState; static CoglBool append_layer_index_cb (CoglPipelineLayer *layer, void *user_data) { AppendLayerIndexState *state = user_data; state->indices[state->i++] = layer->index; return TRUE; } void cogl_pipeline_foreach_layer (CoglPipeline *pipeline, CoglPipelineLayerCallback callback, void *user_data) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS); AppendLayerIndexState state; CoglBool cont; int i; /* XXX: We don't know what the user is going to want to do to the layers * but any modification of layers can result in the layer graph changing * which could confuse _cogl_pipeline_foreach_layer_internal(). We first * get a list of layer indices which will remain valid so long as the * user doesn't remove layers. */ state.i = 0; state.indices = g_alloca (authority->n_layers * sizeof (int)); _cogl_pipeline_foreach_layer_internal (pipeline, append_layer_index_cb, &state); for (i = 0, cont = TRUE; i < authority->n_layers && cont; i++) cont = callback (pipeline, state.indices[i], user_data); } static CoglBool layer_has_alpha_cb (CoglPipelineLayer *layer, void *data) { CoglBool *has_alpha = data; *has_alpha = _cogl_pipeline_layer_has_alpha (layer); /* return FALSE to stop iterating layers if we find any layer * has alpha ... * * FIXME: actually we should never be bailing out because it's * always possible that a later layer could discard any previous * alpha! */ return !(*has_alpha); } /* NB: If this pipeline returns FALSE that doesn't mean that the * pipeline is definitely opaque, it just means that that the * given changes dont imply transparency. * * If you want to find out of the pipeline is opaque then assuming * this returns FALSE for a set of changes then you can follow * up */ static CoglBool _cogl_pipeline_change_implies_transparency (CoglPipeline *pipeline, unsigned int changes, const CoglColor *override_color, CoglBool unknown_color_alpha) { /* In the case of a layer state change we need to check everything * else first since they contribute to the has_alpha status of the * "PREVIOUS" layer. */ if (changes & COGL_PIPELINE_STATE_LAYERS) changes = COGL_PIPELINE_STATE_AFFECTS_BLENDING; if (unknown_color_alpha) return TRUE; if ((override_color && cogl_color_get_alpha_byte (override_color) != 0xff)) return TRUE; if (changes & COGL_PIPELINE_STATE_COLOR) { CoglColor tmp; cogl_pipeline_get_color (pipeline, &tmp); if (cogl_color_get_alpha_byte (&tmp) != 0xff) return TRUE; } if (changes & COGL_PIPELINE_STATE_USER_SHADER) { /* We can't make any assumptions about the alpha channel if the user * is using an unknown fragment shader. * * TODO: check that it isn't just a vertex shader! */ if (_cogl_pipeline_get_user_program (pipeline) != COGL_INVALID_HANDLE) return TRUE; } if (changes & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS) { if (_cogl_pipeline_has_non_layer_fragment_snippets (pipeline)) return TRUE; } if (changes & COGL_PIPELINE_STATE_VERTEX_SNIPPETS) { if (_cogl_pipeline_has_non_layer_vertex_snippets (pipeline)) return TRUE; } /* XXX: we should only need to look at these if lighting is enabled */ if (changes & COGL_PIPELINE_STATE_LIGHTING) { /* XXX: This stuff is showing up in sysprof reports which is * silly because lighting isn't currently actually supported * by Cogl except for these token properties. When we actually * expose lighting support we can avoid these checks when * lighting is disabled. */ #if 0 CoglColor tmp; cogl_pipeline_get_ambient (pipeline, &tmp); if (cogl_color_get_alpha_byte (&tmp) != 0xff) return TRUE; cogl_pipeline_get_diffuse (pipeline, &tmp); if (cogl_color_get_alpha_byte (&tmp) != 0xff) return TRUE; cogl_pipeline_get_specular (pipeline, &tmp); if (cogl_color_get_alpha_byte (&tmp) != 0xff) return TRUE; cogl_pipeline_get_emission (pipeline, &tmp); if (cogl_color_get_alpha_byte (&tmp) != 0xff) return TRUE; #endif } if (changes & COGL_PIPELINE_STATE_LAYERS) { /* has_alpha tracks the alpha status of the GL_PREVIOUS layer. * To start with that's defined by the pipeline color which * must be fully opaque if we got this far. */ CoglBool has_alpha = FALSE; _cogl_pipeline_foreach_layer_internal (pipeline, layer_has_alpha_cb, &has_alpha); if (has_alpha) return TRUE; } return FALSE; } static CoglBool _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline, unsigned int changes, const CoglColor *override_color, CoglBool unknown_color_alpha) { CoglPipeline *enable_authority; CoglPipeline *blend_authority; CoglPipelineBlendState *blend_state; CoglPipelineBlendEnable enabled; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BLENDING))) return FALSE; /* We unconditionally check the _BLEND_ENABLE state first because * all the other changes are irrelevent if blend_enable != _AUTOMATIC */ enable_authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE); enabled = enable_authority->blend_enable; if (enabled != COGL_PIPELINE_BLEND_ENABLE_AUTOMATIC) return enabled == COGL_PIPELINE_BLEND_ENABLE_ENABLED ? TRUE : FALSE; blend_authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND); blend_state = &blend_authority->big_state->blend_state; /* We are trying to identify some cases that are equivalent to * blending being disable, where the output is simply GL_SRC_COLOR. * * Note: we currently only consider a few cases that can be * optimized but there could be opportunities to special case more * blend functions later. */ /* As the most common way that we currently use to effectively * disable blending is to use an equation of * "RGBA=ADD(SRC_COLOR, 0)" that's the first thing we check * for... */ if (blend_state->blend_equation_rgb == GL_FUNC_ADD && blend_state->blend_equation_alpha == GL_FUNC_ADD && blend_state->blend_src_factor_alpha == GL_ONE && blend_state->blend_dst_factor_alpha == GL_ZERO) { return FALSE; } /* NB: The default blending equation for Cogl is * "RGBA=ADD(SRC_COLOR, DST_COLOR * (1-SRC_COLOR[A]))" * * Next we check if the default blending equation is being used. If * so then we follow that by looking for cases where SRC_COLOR[A] == * 1 since that simplifies "DST_COLOR * (1-SRC_COLOR[A])" to 0 which * also effectively requires no blending. */ if (blend_state->blend_equation_rgb != GL_FUNC_ADD || blend_state->blend_equation_alpha != GL_FUNC_ADD) return TRUE; if (blend_state->blend_src_factor_alpha != GL_ONE || blend_state->blend_dst_factor_alpha != GL_ONE_MINUS_SRC_ALPHA) return TRUE; if (blend_state->blend_src_factor_rgb != GL_ONE || blend_state->blend_dst_factor_rgb != GL_ONE_MINUS_SRC_ALPHA) return TRUE; /* Given the above constraints, it's now a case of finding any * SRC_ALPHA that != 1 */ if (_cogl_pipeline_change_implies_transparency (pipeline, changes, override_color, unknown_color_alpha)) return TRUE; /* At this point, considering just the state that has changed it * looks like blending isn't needed. If blending was previously * enabled though it could be that some other state still requires * that we have blending enabled because it implies transparency. * In this case we still need to go and check the other state... * * XXX: We could explicitly keep track of the mask of state groups * that are currently causing blending to be enabled so that we * never have to resort to checking *all* the state and can instead * always limit the check to those in the mask. */ if (pipeline->real_blend_enable) { unsigned int other_state = COGL_PIPELINE_STATE_AFFECTS_BLENDING & ~changes; if (other_state && _cogl_pipeline_change_implies_transparency (pipeline, other_state, NULL, FALSE)) return TRUE; } return FALSE; } void _cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend) { pipeline->progend = progend; } static void _cogl_pipeline_copy_differences (CoglPipeline *dest, CoglPipeline *src, unsigned long differences) { CoglPipelineBigState *big_state; if (differences & COGL_PIPELINE_STATE_COLOR) dest->color = src->color; if (differences & COGL_PIPELINE_STATE_BLEND_ENABLE) dest->blend_enable = src->blend_enable; if (differences & COGL_PIPELINE_STATE_LAYERS) { GList *l; if (dest->differences & COGL_PIPELINE_STATE_LAYERS && dest->layer_differences) { g_list_foreach (dest->layer_differences, (GFunc)cogl_object_unref, NULL); g_list_free (dest->layer_differences); } for (l = src->layer_differences; l; l = l->next) { /* NB: a layer can't have more than one ->owner so we can't * simply take a references on each of the original * layer_differences, we have to derive new layers from the * originals instead. */ CoglPipelineLayer *copy = _cogl_pipeline_layer_copy (l->data); _cogl_pipeline_add_layer_difference (dest, copy, FALSE); cogl_object_unref (copy); } /* Note: we initialize n_layers after adding the layer differences * since the act of adding the layers will initialize n_layers to 0 * because dest isn't initially a STATE_LAYERS authority. */ dest->n_layers = src->n_layers; } if (differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE) { if (!dest->has_big_state) { dest->big_state = g_slice_new (CoglPipelineBigState); dest->has_big_state = TRUE; } big_state = dest->big_state; } else goto check_for_blending_change; if (differences & COGL_PIPELINE_STATE_LIGHTING) { memcpy (&big_state->lighting_state, &src->big_state->lighting_state, sizeof (CoglPipelineLightingState)); } if (differences & COGL_PIPELINE_STATE_ALPHA_FUNC) big_state->alpha_state.alpha_func = src->big_state->alpha_state.alpha_func; if (differences & COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE) big_state->alpha_state.alpha_func_reference = src->big_state->alpha_state.alpha_func_reference; if (differences & COGL_PIPELINE_STATE_BLEND) { memcpy (&big_state->blend_state, &src->big_state->blend_state, sizeof (CoglPipelineBlendState)); } if (differences & COGL_PIPELINE_STATE_USER_SHADER) { if (src->big_state->user_program) big_state->user_program = cogl_handle_ref (src->big_state->user_program); else big_state->user_program = COGL_INVALID_HANDLE; } if (differences & COGL_PIPELINE_STATE_DEPTH) { memcpy (&big_state->depth_state, &src->big_state->depth_state, sizeof (CoglDepthState)); } if (differences & COGL_PIPELINE_STATE_FOG) { memcpy (&big_state->fog_state, &src->big_state->fog_state, sizeof (CoglPipelineFogState)); } if (differences & COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE) big_state->non_zero_point_size = src->big_state->non_zero_point_size; if (differences & COGL_PIPELINE_STATE_POINT_SIZE) big_state->point_size = src->big_state->point_size; if (differences & COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE) big_state->per_vertex_point_size = src->big_state->per_vertex_point_size; if (differences & COGL_PIPELINE_STATE_LOGIC_OPS) { memcpy (&big_state->logic_ops_state, &src->big_state->logic_ops_state, sizeof (CoglPipelineLogicOpsState)); } if (differences & COGL_PIPELINE_STATE_CULL_FACE) { memcpy (&big_state->cull_face_state, &src->big_state->cull_face_state, sizeof (CoglPipelineCullFaceState)); } if (differences & COGL_PIPELINE_STATE_UNIFORMS) { int n_overrides = _cogl_bitmask_popcount (&src->big_state->uniforms_state.override_mask); int i; big_state->uniforms_state.override_values = malloc (n_overrides * sizeof (CoglBoxedValue)); for (i = 0; i < n_overrides; i++) { CoglBoxedValue *dst_bv = big_state->uniforms_state.override_values + i; const CoglBoxedValue *src_bv = src->big_state->uniforms_state.override_values + i; _cogl_boxed_value_copy (dst_bv, src_bv); } _cogl_bitmask_init (&big_state->uniforms_state.override_mask); _cogl_bitmask_set_bits (&big_state->uniforms_state.override_mask, &src->big_state->uniforms_state.override_mask); _cogl_bitmask_init (&big_state->uniforms_state.changed_mask); } if (differences & COGL_PIPELINE_STATE_VERTEX_SNIPPETS) _cogl_pipeline_snippet_list_copy (&big_state->vertex_snippets, &src->big_state->vertex_snippets); if (differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS) _cogl_pipeline_snippet_list_copy (&big_state->fragment_snippets, &src->big_state->fragment_snippets); /* XXX: we shouldn't bother doing this in most cases since * _copy_differences is typically used to initialize pipeline state * by copying it from the current authority, so it's not actually * *changing* anything. */ check_for_blending_change: if (differences & COGL_PIPELINE_STATE_AFFECTS_BLENDING) dest->dirty_real_blend_enable = TRUE; dest->differences |= differences; } static void _cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline, CoglPipelineState change) { CoglPipeline *authority; _COGL_RETURN_IF_FAIL (change & COGL_PIPELINE_STATE_ALL_SPARSE); if (!(change & COGL_PIPELINE_STATE_MULTI_PROPERTY)) return; authority = _cogl_pipeline_get_authority (pipeline, change); switch (change) { /* XXX: avoid using a default: label so we get a warning if we * don't explicitly handle a newly defined state-group here. */ case COGL_PIPELINE_STATE_COLOR: case COGL_PIPELINE_STATE_BLEND_ENABLE: case COGL_PIPELINE_STATE_ALPHA_FUNC: case COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE: case COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE: case COGL_PIPELINE_STATE_POINT_SIZE: case COGL_PIPELINE_STATE_USER_SHADER: case COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE: case COGL_PIPELINE_STATE_REAL_BLEND_ENABLE: g_return_if_reached (); case COGL_PIPELINE_STATE_LAYERS: pipeline->n_layers = authority->n_layers; pipeline->layer_differences = NULL; break; case COGL_PIPELINE_STATE_LIGHTING: { memcpy (&pipeline->big_state->lighting_state, &authority->big_state->lighting_state, sizeof (CoglPipelineLightingState)); break; } case COGL_PIPELINE_STATE_BLEND: { memcpy (&pipeline->big_state->blend_state, &authority->big_state->blend_state, sizeof (CoglPipelineBlendState)); break; } case COGL_PIPELINE_STATE_DEPTH: { memcpy (&pipeline->big_state->depth_state, &authority->big_state->depth_state, sizeof (CoglDepthState)); break; } case COGL_PIPELINE_STATE_FOG: { memcpy (&pipeline->big_state->fog_state, &authority->big_state->fog_state, sizeof (CoglPipelineFogState)); break; } case COGL_PIPELINE_STATE_LOGIC_OPS: { memcpy (&pipeline->big_state->logic_ops_state, &authority->big_state->logic_ops_state, sizeof (CoglPipelineLogicOpsState)); break; } case COGL_PIPELINE_STATE_CULL_FACE: { memcpy (&pipeline->big_state->cull_face_state, &authority->big_state->cull_face_state, sizeof (CoglPipelineCullFaceState)); break; } case COGL_PIPELINE_STATE_UNIFORMS: { CoglPipelineUniformsState *uniforms_state = &pipeline->big_state->uniforms_state; _cogl_bitmask_init (&uniforms_state->override_mask); _cogl_bitmask_init (&uniforms_state->changed_mask); uniforms_state->override_values = NULL; break; } case COGL_PIPELINE_STATE_VERTEX_SNIPPETS: _cogl_pipeline_snippet_list_copy (&pipeline->big_state->vertex_snippets, &authority->big_state->vertex_snippets); break; case COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS: _cogl_pipeline_snippet_list_copy (&pipeline->big_state->fragment_snippets, &authority->big_state-> fragment_snippets); break; } } static CoglBool check_if_strong_cb (CoglNode *node, void *user_data) { CoglPipeline *pipeline = COGL_PIPELINE (node); CoglBool *has_strong_child = user_data; if (!_cogl_pipeline_is_weak (pipeline)) { *has_strong_child = TRUE; return FALSE; } return TRUE; } static CoglBool has_strong_children (CoglPipeline *pipeline) { CoglBool has_strong_child = FALSE; _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline), check_if_strong_cb, &has_strong_child); return has_strong_child; } static CoglBool _cogl_pipeline_is_weak (CoglPipeline *pipeline) { if (pipeline->is_weak && !has_strong_children (pipeline)) return TRUE; else return FALSE; } static CoglBool reparent_children_cb (CoglNode *node, void *user_data) { CoglPipeline *pipeline = COGL_PIPELINE (node); CoglPipeline *parent = user_data; _cogl_pipeline_set_parent (pipeline, parent, TRUE); return TRUE; } void _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color, CoglBool from_layer_change) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* If primitives have been logged in the journal referencing the * current state of this pipeline we need to flush the journal * before we can modify it... */ if (pipeline->journal_ref_count) { CoglBool skip_journal_flush = FALSE; /* XXX: We don't usually need to flush the journal just due to * color changes since pipeline colors are logged in the * journal's vertex buffer. The exception is when the change in * color enables or disables the need for blending. */ if (change == COGL_PIPELINE_STATE_COLOR) { CoglBool will_need_blending = _cogl_pipeline_needs_blending_enabled (pipeline, change, new_color, FALSE); CoglBool blend_enable = pipeline->real_blend_enable ? TRUE : FALSE; if (will_need_blending == blend_enable) skip_journal_flush = TRUE; } if (!skip_journal_flush) { /* XXX: note we use cogl_flush() not _cogl_flush_journal() so * we will flush *all* known journals that might reference the * current pipeline. */ cogl_flush (); } } /* XXX: * To simplify things for the vertex, fragment and program backends * we are careful about how we report STATE_LAYERS changes. * * All STATE_LAYERS change notifications with the exception of * ->n_layers will also result in layer_pre_change_notifications. * * For backends that perform code generation for fragment processing * they typically need to understand the details of how layers get * changed to determine if they need to repeat codegen. It doesn't * help them to report a pipeline STATE_LAYERS change for all layer * changes since it's so broad, they really need to wait for the * specific layer change to be notified. What does help though is * to report a STATE_LAYERS change for a change in ->n_layers * because they typically do need to repeat codegen in that case. * * Here we ensure that change notifications against a pipeline or * against a layer are mutually exclusive as far as fragment, vertex * and program backends are concerned. * * NB: A pipeline can potentially have private state from multiple * backends associated with it because descendants may cache state * with an ancestor to maximize the chance that it can later be * re-used by other descendants and a descendent can require a * different backend to an ancestor. */ if (!from_layer_change) { int i; for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++) { const CoglPipelineProgend *progend = _cogl_pipeline_progends[i]; const CoglPipelineVertend *vertend = _cogl_pipeline_vertends[progend->vertend]; const CoglPipelineFragend *fragend = _cogl_pipeline_fragends[progend->fragend]; if (vertend->pipeline_pre_change_notify) vertend->pipeline_pre_change_notify (pipeline, change, new_color); /* TODO: make the vertend and fragend implementation details * of the progend */ if (fragend->pipeline_pre_change_notify) fragend->pipeline_pre_change_notify (pipeline, change, new_color); if (progend->pipeline_pre_change_notify) progend->pipeline_pre_change_notify (pipeline, change, new_color); } } /* There may be an arbitrary tree of descendants of this pipeline; * any of which may indirectly depend on this pipeline as the * authority for some set of properties. (Meaning for example that * one of its descendants derives its color or blending state from * this pipeline.) * * We can't modify any property that this pipeline is the authority * for unless we create another pipeline to take its place first and * make sure descendants reference this new pipeline instead. */ /* The simplest descendants to handle are weak pipelines; we simply * destroy them if we are modifying a pipeline they depend on. This * means weak pipelines never cause us to do a copy-on-write. */ _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline), destroy_weak_children_cb, NULL); /* If there are still children remaining though we'll need to * perform a copy-on-write and reparent the dependants as children * of the copy. */ if (!_cogl_list_empty (&COGL_NODE (pipeline)->children)) { CoglPipeline *new_authority; COGL_STATIC_COUNTER (pipeline_copy_on_write_counter, "pipeline copy on write counter", "Increments each time a pipeline " "must be copied to allow modification", 0 /* no application private data */); COGL_COUNTER_INC (_cogl_uprof_context, pipeline_copy_on_write_counter); new_authority = cogl_pipeline_copy (_cogl_pipeline_get_parent (pipeline)); #ifdef COGL_DEBUG_ENABLED _cogl_pipeline_set_static_breadcrumb (new_authority, "pre_change_notify:copy-on-write"); #endif /* We could explicitly walk the descendants, OR together the set * of differences that we determine this pipeline is the * authority on and only copy those differences copied across. * * Or, if we don't explicitly walk the descendants we at least * know that pipeline->differences represents the largest set of * differences that this pipeline could possibly be an authority * on. * * We do the later just because it's simplest, but we might need * to come back to this later... */ _cogl_pipeline_copy_differences (new_authority, pipeline, pipeline->differences); /* Reparent the dependants of pipeline to be children of * new_authority instead... */ _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline), reparent_children_cb, new_authority); /* The children will keep the new authority alive so drop the * reference we got when copying... */ cogl_object_unref (new_authority); } /* At this point we know we have a pipeline with no strong * dependants (though we may have some weak children) so we are now * free to modify the pipeline. */ pipeline->age++; if (change & COGL_PIPELINE_STATE_NEEDS_BIG_STATE && !pipeline->has_big_state) { pipeline->big_state = g_slice_new (CoglPipelineBigState); pipeline->has_big_state = TRUE; } /* Note: conceptually we have just been notified that a single * property value is about to change, but since some state-groups * contain multiple properties and 'pipeline' is about to take over * being the authority for the property's corresponding state-group * we need to maintain the integrity of the other property values * too. * * To ensure this we handle multi-property state-groups by copying * all the values from the old-authority to the new... * * We don't have to worry about non-sparse property groups since * we never take over being an authority for such properties so * they automatically maintain integrity. */ if (change & COGL_PIPELINE_STATE_ALL_SPARSE && !(pipeline->differences & change)) { _cogl_pipeline_init_multi_property_sparse_state (pipeline, change); pipeline->differences |= change; } /* Each pipeline has a sorted cache of the layers it depends on * which will need updating via _cogl_pipeline_update_layers_cache * if a pipeline's layers are changed. */ if (change == COGL_PIPELINE_STATE_LAYERS) recursively_free_layer_caches (pipeline); /* If the pipeline being changed is the same as the last pipeline we * flushed then we keep a track of the changes so we can try to * minimize redundant OpenGL calls if the same pipeline is flushed * again. */ if (ctx->current_pipeline == pipeline) ctx->current_pipeline_changes_since_flush |= change; } void _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline, CoglPipelineLayer *layer, CoglBool inc_n_layers) { _COGL_RETURN_IF_FAIL (layer->owner == NULL); layer->owner = pipeline; cogl_object_ref (layer); /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ /* Note: the last argument to _cogl_pipeline_pre_change_notify is * needed to differentiate STATE_LAYER changes which don't affect * the number of layers from those that do. NB: Layer change * notifications that don't change the number of layers don't get * forwarded to the fragend. */ _cogl_pipeline_pre_change_notify (pipeline, COGL_PIPELINE_STATE_LAYERS, NULL, !inc_n_layers); pipeline->differences |= COGL_PIPELINE_STATE_LAYERS; pipeline->layer_differences = g_list_prepend (pipeline->layer_differences, layer); if (inc_n_layers) pipeline->n_layers++; /* Adding a layer difference may mean this pipeline now overrides * all of the layers of its parent which might make the parent * redundant so we should try to prune the hierarchy */ _cogl_pipeline_prune_redundant_ancestry (pipeline); } void _cogl_pipeline_remove_layer_difference (CoglPipeline *pipeline, CoglPipelineLayer *layer, CoglBool dec_n_layers) { /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being * changed, then initialize that state from the current authority. */ /* Note: the last argument to _cogl_pipeline_pre_change_notify is * needed to differentiate STATE_LAYER changes which don't affect * the number of layers from those that do. NB: Layer change * notifications that don't change the number of layers don't get * forwarded to the fragend. */ _cogl_pipeline_pre_change_notify (pipeline, COGL_PIPELINE_STATE_LAYERS, NULL, !dec_n_layers); /* We only need to remove the layer difference if the pipeline is * currently the owner. If it is not the owner then one of two * things will happen to make sure this layer is replaced. If it is * the last layer being removed then decrementing n_layers will * ensure that the last layer is skipped. If it is any other layer * then the subsequent layers will have been shifted down and cause * it be replaced */ if (layer->owner == pipeline) { layer->owner = NULL; cogl_object_unref (layer); pipeline->layer_differences = g_list_remove (pipeline->layer_differences, layer); } pipeline->differences |= COGL_PIPELINE_STATE_LAYERS; if (dec_n_layers) pipeline->n_layers--; } static void _cogl_pipeline_try_reverting_layers_authority (CoglPipeline *authority, CoglPipeline *old_authority) { if (authority->layer_differences == NULL && _cogl_pipeline_get_parent (authority)) { /* If the previous _STATE_LAYERS authority has the same * ->n_layers then we can revert to that being the authority * again. */ if (!old_authority) { old_authority = _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority), COGL_PIPELINE_STATE_LAYERS); } if (old_authority->n_layers == authority->n_layers) authority->differences &= ~COGL_PIPELINE_STATE_LAYERS; } } void _cogl_pipeline_update_real_blend_enable (CoglPipeline *pipeline, CoglBool unknown_color_alpha) { CoglPipeline *parent; unsigned int differences; if (pipeline->dirty_real_blend_enable == FALSE && pipeline->unknown_color_alpha == unknown_color_alpha) return; if (pipeline->dirty_real_blend_enable) { differences = pipeline->differences; parent = _cogl_pipeline_get_parent (pipeline); while (parent->dirty_real_blend_enable) { differences |= parent->differences; parent = _cogl_pipeline_get_parent (parent); } /* We initialize the pipeline's real_blend_enable with a known * reference value from its nearest ancestor with clean state so * we can then potentially reduce the work involved in checking * if the pipeline really needs blending itself because we can * just look at the things that differ between the ancestor and * this pipeline. */ pipeline->real_blend_enable = parent->real_blend_enable; } else /* pipeline->unknown_color_alpha != unknown_color_alpha */ differences = 0; /* Note we don't call _cogl_pipeline_pre_change_notify() for this * state change because ->real_blend_enable is lazily derived from * other state while flushing the pipeline and we'd need to avoid * recursion problems in cases where _pre_change_notify() flushes * the journal if the pipeline is referenced by a journal. */ pipeline->real_blend_enable = _cogl_pipeline_needs_blending_enabled (pipeline, differences, NULL, unknown_color_alpha); pipeline->dirty_real_blend_enable = FALSE; pipeline->unknown_color_alpha = unknown_color_alpha; } typedef struct { int keep_n; int current_pos; int first_index_to_prune; } CoglPipelinePruneLayersInfo; static CoglBool update_prune_layers_info_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelinePruneLayersInfo *state = user_data; if (state->current_pos == state->keep_n) { state->first_index_to_prune = layer->index; return FALSE; } state->current_pos++; return TRUE; } void _cogl_pipeline_prune_to_n_layers (CoglPipeline *pipeline, int n) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS); CoglPipelinePruneLayersInfo state; GList *l; GList *next; if (authority->n_layers <= n) return; /* This call to foreach_layer_internal needs to be done before * calling pre_change_notify because it recreates the layer cache. * We are relying on pre_change_notify to clear the layer cache * before we change the number of layers */ state.keep_n = n; state.current_pos = 0; _cogl_pipeline_foreach_layer_internal (pipeline, update_prune_layers_info_cb, &state); _cogl_pipeline_pre_change_notify (pipeline, COGL_PIPELINE_STATE_LAYERS, NULL, FALSE); pipeline->differences |= COGL_PIPELINE_STATE_LAYERS; pipeline->n_layers = n; /* It's possible that this pipeline owns some of the layers being * discarded, so we'll need to unlink them... */ for (l = pipeline->layer_differences; l; l = next) { CoglPipelineLayer *layer = l->data; next = l->next; /* we're modifying the list we're iterating */ if (layer->index >= state.first_index_to_prune) _cogl_pipeline_remove_layer_difference (pipeline, layer, FALSE); } pipeline->differences |= COGL_PIPELINE_STATE_LAYERS; } typedef struct { /* The layer we are trying to find */ int layer_index; /* The layer we find or untouched if not found */ CoglPipelineLayer *layer; /* If the layer can't be found then a new layer should be * inserted after this texture unit index... */ int insert_after; /* When adding a layer we need the list of layers to shift up * to a new texture unit. When removing we need the list of * layers to shift down. * * Note: the list isn't sorted */ CoglPipelineLayer **layers_to_shift; int n_layers_to_shift; /* When adding a layer we don't need a complete list of * layers_to_shift if we find a layer already corresponding to the * layer_index. */ CoglBool ignore_shift_layers_if_found; } CoglPipelineLayerInfo; /* Returns TRUE once we know there is nothing more to update */ static CoglBool update_layer_info (CoglPipelineLayer *layer, CoglPipelineLayerInfo *layer_info) { if (layer->index == layer_info->layer_index) { layer_info->layer = layer; if (layer_info->ignore_shift_layers_if_found) return TRUE; } else if (layer->index < layer_info->layer_index) { int unit_index = _cogl_pipeline_layer_get_unit_index (layer); layer_info->insert_after = unit_index; } else layer_info->layers_to_shift[layer_info->n_layers_to_shift++] = layer; return FALSE; } /* Returns FALSE to break out of a _foreach_layer () iteration */ static CoglBool update_layer_info_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineLayerInfo *layer_info = user_data; if (update_layer_info (layer, layer_info)) return FALSE; /* break */ else return TRUE; /* continue */ } static void _cogl_pipeline_get_layer_info (CoglPipeline *pipeline, CoglPipelineLayerInfo *layer_info) { /* Note: we are assuming this pipeline is a _STATE_LAYERS authority */ int n_layers = pipeline->n_layers; int i; /* FIXME: _cogl_pipeline_foreach_layer_internal now calls * _cogl_pipeline_update_layers_cache anyway so this codepath is * pointless! */ if (layer_info->ignore_shift_layers_if_found && pipeline->layers_cache_dirty) { /* The expectation is that callers of * _cogl_pipeline_get_layer_info are likely to be modifying the * list of layers associated with a pipeline so in this case * where we don't have a cache of the layers and we don't * necessarily have to iterate all the layers of the pipeline we * use a foreach_layer callback instead of updating the cache * and iterating that as below. */ _cogl_pipeline_foreach_layer_internal (pipeline, update_layer_info_cb, layer_info); return; } _cogl_pipeline_update_layers_cache (pipeline); for (i = 0; i < n_layers; i++) { CoglPipelineLayer *layer = pipeline->layers_cache[i]; if (update_layer_info (layer, layer_info)) return; } } CoglPipelineLayer * _cogl_pipeline_get_layer_with_flags (CoglPipeline *pipeline, int layer_index, CoglPipelineGetLayerFlags flags) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS); CoglPipelineLayerInfo layer_info; CoglPipelineLayer *layer; int unit_index; int i; CoglContext *ctx; /* The layer index of the layer we want info about */ layer_info.layer_index = layer_index; /* If a layer already exists with the given index this will be * updated. */ layer_info.layer = NULL; /* If a layer isn't found for the given index we'll need to know * where to insert a new layer. */ layer_info.insert_after = -1; /* If a layer can't be found then we'll need to insert a new layer * and bump up the texture unit for all layers with an index * > layer_index. */ layer_info.layers_to_shift = g_alloca (sizeof (CoglPipelineLayer *) * authority->n_layers); layer_info.n_layers_to_shift = 0; /* If an exact match is found though we don't need a complete * list of layers with indices > layer_index... */ layer_info.ignore_shift_layers_if_found = TRUE; _cogl_pipeline_get_layer_info (authority, &layer_info); if (layer_info.layer || (flags & COGL_PIPELINE_GET_LAYER_NO_CREATE)) return layer_info.layer; ctx = _cogl_context_get_default (); unit_index = layer_info.insert_after + 1; if (unit_index == 0) layer = _cogl_pipeline_layer_copy (ctx->default_layer_0); else { CoglPipelineLayer *new; layer = _cogl_pipeline_layer_copy (ctx->default_layer_n); new = _cogl_pipeline_set_layer_unit (NULL, layer, unit_index); /* Since we passed a newly allocated layer we wouldn't expect * _set_layer_unit() to have to allocate *another* layer. */ g_assert (new == layer); } layer->index = layer_index; for (i = 0; i < layer_info.n_layers_to_shift; i++) { CoglPipelineLayer *shift_layer = layer_info.layers_to_shift[i]; unit_index = _cogl_pipeline_layer_get_unit_index (shift_layer); _cogl_pipeline_set_layer_unit (pipeline, shift_layer, unit_index + 1); /* NB: shift_layer may not be writeable so _set_layer_unit() * will allocate a derived layer internally which will become * owned by pipeline. Check the return value if we need to do * anything else with this layer. */ } _cogl_pipeline_add_layer_difference (pipeline, layer, TRUE); cogl_object_unref (layer); return layer; } void _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority, CoglPipelineLayer *layer) { /* Find the GList link that references the empty layer */ GList *link = g_list_find (layers_authority->layer_differences, layer); /* No pipeline directly owns the root node layer so this is safe... */ CoglPipelineLayer *layer_parent = _cogl_pipeline_layer_get_parent (layer); CoglPipelineLayerInfo layer_info; CoglPipeline *old_layers_authority; _COGL_RETURN_IF_FAIL (link != NULL); /* If the layer's parent doesn't have an owner then we can simply * take ownership ourselves and drop our reference on the empty * layer. We don't want to take ownership of the root node layer so * we also need to verify that the parent has a parent */ if (layer_parent->index == layer->index && layer_parent->owner == NULL && _cogl_pipeline_layer_get_parent (layer_parent) != NULL) { cogl_object_ref (layer_parent); layer_parent->owner = layers_authority; link->data = layer_parent; cogl_object_unref (layer); recursively_free_layer_caches (layers_authority); return; } /* Now we want to find the layer that would become the authority for * layer->index if we were to remove layer from * layers_authority->layer_differences */ /* The layer index of the layer we want info about */ layer_info.layer_index = layer->index; /* If a layer already exists with the given index this will be * updated. */ layer_info.layer = NULL; /* If a layer can't be found then we'll need to insert a new layer * and bump up the texture unit for all layers with an index * > layer_index. */ layer_info.layers_to_shift = g_alloca (sizeof (CoglPipelineLayer *) * layers_authority->n_layers); layer_info.n_layers_to_shift = 0; /* If an exact match is found though we don't need a complete * list of layers with indices > layer_index... */ layer_info.ignore_shift_layers_if_found = TRUE; /* We know the default/root pipeline isn't a LAYERS authority so it's * safe to use the result of _cogl_pipeline_get_parent (layers_authority) * without checking it. */ old_layers_authority = _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (layers_authority), COGL_PIPELINE_STATE_LAYERS); _cogl_pipeline_get_layer_info (old_layers_authority, &layer_info); /* If layer is the defining layer for the corresponding ->index then * we can't get rid of it. */ if (!layer_info.layer) return; /* If the layer that would become the authority for layer->index is * _cogl_pipeline_layer_get_parent (layer) then we can simply remove the * layer difference. */ if (layer_info.layer == _cogl_pipeline_layer_get_parent (layer)) { _cogl_pipeline_remove_layer_difference (layers_authority, layer, FALSE); _cogl_pipeline_try_reverting_layers_authority (layers_authority, old_layers_authority); } } typedef struct { int i; CoglPipeline *pipeline; unsigned long fallback_layers; } CoglPipelineFallbackState; static CoglBool fallback_layer_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineFallbackState *state = user_data; CoglPipeline *pipeline = state->pipeline; CoglTextureType texture_type = _cogl_pipeline_layer_get_texture_type (layer); CoglTexture *texture = NULL; COGL_STATIC_COUNTER (layer_fallback_counter, "layer fallback counter", "Increments each time a layer's texture is " "forced to a fallback texture", 0 /* no application private data */); _COGL_GET_CONTEXT (ctx, FALSE); if (!(state->fallback_layers & 1<i)) return TRUE; COGL_COUNTER_INC (_cogl_uprof_context, layer_fallback_counter); switch (texture_type) { case COGL_TEXTURE_TYPE_2D: texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex); break; case COGL_TEXTURE_TYPE_3D: texture = COGL_TEXTURE (ctx->default_gl_texture_3d_tex); break; case COGL_TEXTURE_TYPE_RECTANGLE: texture = COGL_TEXTURE (ctx->default_gl_texture_rect_tex); break; } if (texture == NULL) { g_warning ("We don't have a fallback texture we can use to fill " "in for an invalid pipeline layer, since it was " "using an unsupported texture target "); /* might get away with this... */ texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex); } cogl_pipeline_set_layer_texture (pipeline, layer->index, texture); state->i++; return TRUE; } typedef struct { CoglPipeline *pipeline; CoglTexture *texture; } CoglPipelineOverrideLayerState; static CoglBool override_layer_texture_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineOverrideLayerState *state = user_data; cogl_pipeline_set_layer_texture (state->pipeline, layer->index, state->texture); return TRUE; } void _cogl_pipeline_apply_overrides (CoglPipeline *pipeline, CoglPipelineFlushOptions *options) { COGL_STATIC_COUNTER (apply_overrides_counter, "pipeline overrides counter", "Increments each time we have to apply " "override options to a pipeline", 0 /* no application private data */); COGL_COUNTER_INC (_cogl_uprof_context, apply_overrides_counter); if (options->flags & COGL_PIPELINE_FLUSH_DISABLE_MASK) { int i; /* NB: we can assume that once we see one bit to disable * a layer, all subsequent layers are also disabled. */ for (i = 0; i < 32 && options->disable_layers & (1<flags & COGL_PIPELINE_FLUSH_FALLBACK_MASK) { CoglPipelineFallbackState state; state.i = 0; state.pipeline = pipeline; state.fallback_layers = options->fallback_layers; _cogl_pipeline_foreach_layer_internal (pipeline, fallback_layer_cb, &state); } if (options->flags & COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE) { CoglPipelineOverrideLayerState state; _cogl_pipeline_prune_to_n_layers (pipeline, 1); /* NB: we are overriding the first layer, but we don't know * the user's given layer_index, which is why we use * _cogl_pipeline_foreach_layer_internal() here even though we know * there's only one layer. */ state.pipeline = pipeline; state.texture = options->layer0_override_texture; _cogl_pipeline_foreach_layer_internal (pipeline, override_layer_texture_cb, &state); } } static CoglBool _cogl_pipeline_layers_equal (CoglPipeline *authority0, CoglPipeline *authority1, unsigned long differences, CoglPipelineEvalFlags flags) { int i; if (authority0->n_layers != authority1->n_layers) return FALSE; _cogl_pipeline_update_layers_cache (authority0); _cogl_pipeline_update_layers_cache (authority1); for (i = 0; i < authority0->n_layers; i++) { if (!_cogl_pipeline_layer_equal (authority0->layers_cache[i], authority1->layers_cache[i], differences, flags)) return FALSE; } return TRUE; } /* Determine the mask of differences between two pipelines */ unsigned long _cogl_pipeline_compare_differences (CoglPipeline *pipeline0, CoglPipeline *pipeline1) { GSList *head0 = NULL; GSList *head1 = NULL; CoglPipeline *node0; CoglPipeline *node1; int len0 = 0; int len1 = 0; int count; GSList *common_ancestor0; GSList *common_ancestor1; unsigned long pipelines_difference = 0; /* Algorithm: * * 1) Walk the ancestors of each pipeline to the root node, adding a * pointer to each ancester node to two linked lists * * 2) Compare the lists to find the nodes where they start to * differ marking the common_ancestor node for each list. * * 3) For each list now iterate starting after the common_ancestor * nodes ORing each nodes ->difference mask into the final * differences mask. */ for (node0 = pipeline0; node0; node0 = _cogl_pipeline_get_parent (node0)) { GSList *link = alloca (sizeof (GSList)); link->next = head0; link->data = node0; head0 = link; len0++; } for (node1 = pipeline1; node1; node1 = _cogl_pipeline_get_parent (node1)) { GSList *link = alloca (sizeof (GSList)); link->next = head1; link->data = node1; head1 = link; len1++; } /* NB: There's no point looking at the head entries since we know both * pipelines must have the same default pipeline as their root node. */ common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; count = MIN (len0, len1) - 1; while (count--) { if (head0->data != head1->data) break; common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; } for (head0 = common_ancestor0->next; head0; head0 = head0->next) { node0 = head0->data; pipelines_difference |= node0->differences; } for (head1 = common_ancestor1->next; head1; head1 = head1->next) { node1 = head1->data; pipelines_difference |= node1->differences; } return pipelines_difference; } static void _cogl_pipeline_resolve_authorities (CoglPipeline *pipeline, unsigned long differences, CoglPipeline **authorities) { unsigned long remaining = differences; CoglPipeline *authority = pipeline; do { unsigned long found = authority->differences & remaining; int i; if (found == 0) continue; for (i = 0; TRUE; i++) { unsigned long state = (1L< found) break; } remaining &= ~found; if (remaining == 0) return; } while ((authority = _cogl_pipeline_get_parent (authority))); g_assert (remaining == 0); } /* Comparison of two arbitrary pipelines is done by: * 1) walking up the parents of each pipeline until a common * ancestor is found, and at each step ORing together the * difference masks. * * 2) using the final difference mask to determine which state * groups to compare. * * This is used, for example, by the Cogl journal to compare pipelines so that * it can split up geometry that needs different OpenGL state. * * XXX: When comparing texture layers, _cogl_pipeline_equal will actually * compare the underlying GL texture handle that the Cogl texture uses so that * atlas textures and sub textures will be considered equal if they point to * the same texture. This is useful for comparing pipelines in the journal but * it means that _cogl_pipeline_equal doesn't strictly compare whether the * pipelines are the same. If we needed those semantics we could perhaps add * another function or some flags to control the behaviour. * * XXX: Similarly when comparing the wrap modes, * COGL_PIPELINE_WRAP_MODE_AUTOMATIC is considered to be the same as * COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE because once they get to the * journal stage they act exactly the same. */ CoglBool _cogl_pipeline_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1, unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags) { unsigned long pipelines_difference; CoglPipeline *authorities0[COGL_PIPELINE_STATE_SPARSE_COUNT]; CoglPipeline *authorities1[COGL_PIPELINE_STATE_SPARSE_COUNT]; int bit; CoglBool ret; COGL_STATIC_TIMER (pipeline_equal_timer, "Mainloop", /* parent */ "_cogl_pipeline_equal", "The time spent comparing cogl pipelines", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, pipeline_equal_timer); if (pipeline0 == pipeline1) { ret = TRUE; goto done; } ret = FALSE; _cogl_pipeline_update_real_blend_enable (pipeline0, FALSE); _cogl_pipeline_update_real_blend_enable (pipeline1, FALSE); /* First check non-sparse properties */ if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE && pipeline0->real_blend_enable != pipeline1->real_blend_enable) goto done; /* Then check sparse properties */ pipelines_difference = _cogl_pipeline_compare_differences (pipeline0, pipeline1); /* Only compare the sparse state groups requested by the caller... */ pipelines_difference &= differences; _cogl_pipeline_resolve_authorities (pipeline0, pipelines_difference, authorities0); _cogl_pipeline_resolve_authorities (pipeline1, pipelines_difference, authorities1); COGL_FLAGS_FOREACH_START (&pipelines_difference, 1, bit) { /* XXX: We considered having an array of callbacks for each state index * that we'd call here but decided that this way the compiler is more * likely going to be able to in-line the comparison functions and use * the index to jump straight to the required code. */ switch ((CoglPipelineStateIndex)bit) { case COGL_PIPELINE_STATE_COLOR_INDEX: if (!cogl_color_equal (&authorities0[bit]->color, &authorities1[bit]->color)) goto done; break; case COGL_PIPELINE_STATE_LIGHTING_INDEX: if (!_cogl_pipeline_lighting_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX: if (!_cogl_pipeline_alpha_func_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX: if (!_cogl_pipeline_alpha_func_reference_state_equal ( authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_BLEND_INDEX: /* We don't need to compare the detailed blending state if we know * blending is disabled for both pipelines. */ if (pipeline0->real_blend_enable) { if (!_cogl_pipeline_blend_state_equal (authorities0[bit], authorities1[bit])) goto done; } break; case COGL_PIPELINE_STATE_DEPTH_INDEX: if (!_cogl_pipeline_depth_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_FOG_INDEX: if (!_cogl_pipeline_fog_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_CULL_FACE_INDEX: if (!_cogl_pipeline_cull_face_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE_INDEX: if (!_cogl_pipeline_non_zero_point_size_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_POINT_SIZE_INDEX: if (!_cogl_pipeline_point_size_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX: if (!_cogl_pipeline_per_vertex_point_size_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_LOGIC_OPS_INDEX: if (!_cogl_pipeline_logic_ops_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_USER_SHADER_INDEX: if (!_cogl_pipeline_user_shader_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_UNIFORMS_INDEX: if (!_cogl_pipeline_uniforms_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX: if (!_cogl_pipeline_vertex_snippets_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX: if (!_cogl_pipeline_fragment_snippets_state_equal (authorities0[bit], authorities1[bit])) goto done; break; case COGL_PIPELINE_STATE_LAYERS_INDEX: { if (!_cogl_pipeline_layers_equal (authorities0[bit], authorities1[bit], layer_differences, flags)) goto done; break; } case COGL_PIPELINE_STATE_BLEND_ENABLE_INDEX: case COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX: case COGL_PIPELINE_STATE_COUNT: g_warn_if_reached (); } } COGL_FLAGS_FOREACH_END; ret = TRUE; done: COGL_TIMER_STOP (_cogl_uprof_context, pipeline_equal_timer); return ret; } void _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline) { CoglPipeline *new_parent = _cogl_pipeline_get_parent (pipeline); /* Before considering pruning redundant ancestry we check if this * pipeline is an authority for layer state and if so only consider * reparenting if it *owns* all the layers it depends on. NB: A * pipeline can be be a STATE_LAYERS authority but it may still * defer to its ancestors to define the state for some of its * layers. * * For example a pipeline that derives from a parent with 5 layers * can become a STATE_LAYERS authority by simply changing it's * ->n_layers count to 4 and in that case it can still defer to its * ancestors to define the state of those 4 layers. * * If a pipeline depends on any ancestors for layer state then we * immediatly bail out. */ if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS) { if (pipeline->n_layers != g_list_length (pipeline->layer_differences)) return; } /* walk up past ancestors that are now redundant and potentially * reparent the pipeline. */ while (_cogl_pipeline_get_parent (new_parent) && (new_parent->differences | pipeline->differences) == pipeline->differences) new_parent = _cogl_pipeline_get_parent (new_parent); if (new_parent != _cogl_pipeline_get_parent (pipeline)) { CoglBool is_weak = _cogl_pipeline_is_weak (pipeline); _cogl_pipeline_set_parent (pipeline, new_parent, is_weak ? FALSE : TRUE); } } void _cogl_pipeline_update_authority (CoglPipeline *pipeline, CoglPipeline *authority, CoglPipelineState state, CoglPipelineStateComparitor comparitor) { /* If we are the current authority see if we can revert to one of * our ancestors being the authority */ if (pipeline == authority && _cogl_pipeline_get_parent (authority) != NULL) { CoglPipeline *parent = _cogl_pipeline_get_parent (authority); CoglPipeline *old_authority = _cogl_pipeline_get_authority (parent, state); if (comparitor (authority, old_authority)) pipeline->differences &= ~state; } else if (pipeline != authority) { /* If we weren't previously the authority on this state then we * need to extended our differences mask and so it's possible * that some of our ancestry will now become redundant, so we * aim to reparent ourselves if that's true... */ pipeline->differences |= state; _cogl_pipeline_prune_redundant_ancestry (pipeline); } } CoglBool _cogl_pipeline_get_fog_enabled (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_FOG); return authority->big_state->fog_state.enabled; } unsigned long _cogl_pipeline_get_age (CoglPipeline *pipeline) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0); return pipeline->age; } void cogl_pipeline_remove_layer (CoglPipeline *pipeline, int layer_index) { CoglPipeline *authority; CoglPipelineLayerInfo layer_info; int i; _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS); /* The layer index of the layer we want info about */ layer_info.layer_index = layer_index; /* This will be updated with a reference to the layer being removed * if it can be found. */ layer_info.layer = NULL; /* This will be filled in with a list of layers that need to be * dropped down to a lower texture unit to fill the gap of the * removed layer. */ layer_info.layers_to_shift = g_alloca (sizeof (CoglPipelineLayer *) * authority->n_layers); layer_info.n_layers_to_shift = 0; /* Unlike when we query layer info when adding a layer we must * always have a complete layers_to_shift list... */ layer_info.ignore_shift_layers_if_found = FALSE; _cogl_pipeline_get_layer_info (authority, &layer_info); if (layer_info.layer == NULL) return; for (i = 0; i < layer_info.n_layers_to_shift; i++) { CoglPipelineLayer *shift_layer = layer_info.layers_to_shift[i]; int unit_index = _cogl_pipeline_layer_get_unit_index (shift_layer); _cogl_pipeline_set_layer_unit (pipeline, shift_layer, unit_index - 1); /* NB: shift_layer may not be writeable so _set_layer_unit() * will allocate a derived layer internally which will become * owned by pipeline. Check the return value if we need to do * anything else with this layer. */ } _cogl_pipeline_remove_layer_difference (pipeline, layer_info.layer, TRUE); _cogl_pipeline_try_reverting_layers_authority (pipeline, NULL); pipeline->dirty_real_blend_enable = TRUE; } static CoglBool prepend_layer_to_list_cb (CoglPipelineLayer *layer, void *user_data) { GList **layers = user_data; *layers = g_list_prepend (*layers, layer); return TRUE; } /* TODO: deprecate this API and replace it with * cogl_pipeline_foreach_layer * TODO: update the docs to note that if the user modifies any layers * then the list may become invalid. */ const GList * _cogl_pipeline_get_layers (CoglPipeline *pipeline) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), NULL); if (!pipeline->deprecated_get_layers_list_dirty) g_list_free (pipeline->deprecated_get_layers_list); pipeline->deprecated_get_layers_list = NULL; _cogl_pipeline_foreach_layer_internal (pipeline, prepend_layer_to_list_cb, &pipeline->deprecated_get_layers_list); pipeline->deprecated_get_layers_list = g_list_reverse (pipeline->deprecated_get_layers_list); pipeline->deprecated_get_layers_list_dirty = 0; return pipeline->deprecated_get_layers_list; } int cogl_pipeline_get_n_layers (CoglPipeline *pipeline) { CoglPipeline *authority; _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0); authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS); return authority->n_layers; } void _cogl_pipeline_pre_paint_for_layer (CoglPipeline *pipeline, int layer_id) { CoglPipelineLayer *layer = _cogl_pipeline_get_layer (pipeline, layer_id); _cogl_pipeline_layer_pre_paint (layer); } /* While a pipeline is referenced by the Cogl journal we can not allow * modifications, so this gives us a mechanism to track journal * references separately */ CoglPipeline * _cogl_pipeline_journal_ref (CoglPipeline *pipeline) { pipeline->journal_ref_count++; return cogl_object_ref (pipeline); } void _cogl_pipeline_journal_unref (CoglPipeline *pipeline) { pipeline->journal_ref_count--; cogl_object_unref (pipeline); } #ifdef COGL_DEBUG_ENABLED void _cogl_pipeline_apply_legacy_state (CoglPipeline *pipeline) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* It was a mistake that we ever copied the OpenGL style API for * associating these things directly with the context when we * originally wrote Cogl. Until the corresponding deprecated APIs * can be removed though we now shoehorn the state changes through * the cogl_pipeline API instead. */ /* A program explicitly set on the pipeline has higher precedence than * one associated with the context using cogl_program_use() */ if (ctx->current_program && cogl_pipeline_get_user_program (pipeline) == COGL_INVALID_HANDLE) cogl_pipeline_set_user_program (pipeline, ctx->current_program); if (ctx->legacy_depth_test_enabled) { CoglDepthState depth_state; cogl_depth_state_init (&depth_state); cogl_depth_state_set_test_enabled (&depth_state, TRUE); cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL); } if (ctx->legacy_fog_state.enabled) _cogl_pipeline_set_fog_state (pipeline, &ctx->legacy_fog_state); if (ctx->legacy_backface_culling_enabled) cogl_pipeline_set_cull_face_mode (pipeline, COGL_PIPELINE_CULL_FACE_MODE_BACK); } void _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline, const char *breadcrumb) { pipeline->has_static_breadcrumb = TRUE; pipeline->static_breadcrumb = breadcrumb; } #endif typedef void (*LayerStateHashFunction) (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); static LayerStateHashFunction layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT]; /* XXX: We don't statically initialize the array of hash functions, so * we won't get caught out by later re-indexing the groups for some * reason. */ void _cogl_pipeline_init_layer_state_hash_functions (void) { CoglPipelineLayerStateIndex _index; layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_UNIT_INDEX] = _cogl_pipeline_layer_hash_unit_state; layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE_INDEX] = _cogl_pipeline_layer_hash_texture_type_state; layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX] = _cogl_pipeline_layer_hash_texture_data_state; layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX] = _cogl_pipeline_layer_hash_sampler_state; layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX] = _cogl_pipeline_layer_hash_combine_state; layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX] = _cogl_pipeline_layer_hash_combine_constant_state; layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX] = _cogl_pipeline_layer_hash_user_matrix_state; _index = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX; layer_state_hash_functions[_index] = _cogl_pipeline_layer_hash_point_sprite_state; _index = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX; layer_state_hash_functions[_index] = _cogl_pipeline_layer_hash_point_sprite_state; _index = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX; layer_state_hash_functions[_index] = _cogl_pipeline_layer_hash_fragment_snippets_state; { /* So we get a big error if we forget to update this code! */ _COGL_STATIC_ASSERT (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 10, "Don't forget to install a hash function for new " "pipeline state and update assert at end of " "_cogl_pipeline_init_state_hash_functions"); } } static CoglBool _cogl_pipeline_hash_layer_cb (CoglPipelineLayer *layer, void *user_data) { CoglPipelineHashState *state = user_data; unsigned long differences = state->layer_differences; CoglPipelineLayer *authorities[COGL_PIPELINE_LAYER_STATE_COUNT]; unsigned long mask; int i; /* Theoretically we would hash non-sparse layer state here but * currently layers don't have any. */ /* XXX: we resolve all the authorities here - not just those * corresponding to hash_state->layer_differences - because * the hashing of some state groups actually depends on the values * in other groups. For example we don't hash layer combine * constants if they are aren't referenced by the current layer * combine function. */ mask = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE; _cogl_pipeline_layer_resolve_authorities (layer, mask, authorities); /* So we go right ahead and hash the sparse state... */ for (i = 0; i < COGL_PIPELINE_LAYER_STATE_COUNT; i++) { unsigned long current_state = (1L< differences) break; } return TRUE; } void _cogl_pipeline_hash_layers_state (CoglPipeline *authority, CoglPipelineHashState *state) { state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->n_layers, sizeof (authority->n_layers)); _cogl_pipeline_foreach_layer_internal (authority, _cogl_pipeline_hash_layer_cb, state); } typedef void (*StateHashFunction) (CoglPipeline *authority, CoglPipelineHashState *state); static StateHashFunction state_hash_functions[COGL_PIPELINE_STATE_SPARSE_COUNT]; /* We don't statically initialize the array of hash functions * so we won't get caught out by later re-indexing the groups for * some reason. */ void _cogl_pipeline_init_state_hash_functions (void) { state_hash_functions[COGL_PIPELINE_STATE_COLOR_INDEX] = _cogl_pipeline_hash_color_state; state_hash_functions[COGL_PIPELINE_STATE_BLEND_ENABLE_INDEX] = _cogl_pipeline_hash_blend_enable_state; state_hash_functions[COGL_PIPELINE_STATE_LAYERS_INDEX] = _cogl_pipeline_hash_layers_state; state_hash_functions[COGL_PIPELINE_STATE_LIGHTING_INDEX] = _cogl_pipeline_hash_lighting_state; state_hash_functions[COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX] = _cogl_pipeline_hash_alpha_func_state; state_hash_functions[COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX] = _cogl_pipeline_hash_alpha_func_reference_state; state_hash_functions[COGL_PIPELINE_STATE_BLEND_INDEX] = _cogl_pipeline_hash_blend_state; state_hash_functions[COGL_PIPELINE_STATE_USER_SHADER_INDEX] = _cogl_pipeline_hash_user_shader_state; state_hash_functions[COGL_PIPELINE_STATE_DEPTH_INDEX] = _cogl_pipeline_hash_depth_state; state_hash_functions[COGL_PIPELINE_STATE_FOG_INDEX] = _cogl_pipeline_hash_fog_state; state_hash_functions[COGL_PIPELINE_STATE_CULL_FACE_INDEX] = _cogl_pipeline_hash_cull_face_state; state_hash_functions[COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE_INDEX] = _cogl_pipeline_hash_non_zero_point_size_state; state_hash_functions[COGL_PIPELINE_STATE_POINT_SIZE_INDEX] = _cogl_pipeline_hash_point_size_state; state_hash_functions[COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX] = _cogl_pipeline_hash_per_vertex_point_size_state; state_hash_functions[COGL_PIPELINE_STATE_LOGIC_OPS_INDEX] = _cogl_pipeline_hash_logic_ops_state; state_hash_functions[COGL_PIPELINE_STATE_UNIFORMS_INDEX] = _cogl_pipeline_hash_uniforms_state; state_hash_functions[COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX] = _cogl_pipeline_hash_vertex_snippets_state; state_hash_functions[COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX] = _cogl_pipeline_hash_fragment_snippets_state; { /* So we get a big error if we forget to update this code! */ _COGL_STATIC_ASSERT (COGL_PIPELINE_STATE_SPARSE_COUNT == 18, "Make sure to install a hash function for " "newly added pipeline state and update assert " "in _cogl_pipeline_init_state_hash_functions"); } } unsigned int _cogl_pipeline_hash (CoglPipeline *pipeline, unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags) { CoglPipeline *authorities[COGL_PIPELINE_STATE_SPARSE_COUNT]; unsigned int mask; int i; CoglPipelineHashState state; unsigned int final_hash = 0; state.hash = 0; state.layer_differences = layer_differences; state.flags = flags; _cogl_pipeline_update_real_blend_enable (pipeline, FALSE); /* hash non-sparse state */ if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE) { CoglBool enable = pipeline->real_blend_enable; state.hash = _cogl_util_one_at_a_time_hash (state.hash, &enable, sizeof (enable)); } /* hash sparse state */ mask = differences & COGL_PIPELINE_STATE_ALL_SPARSE; _cogl_pipeline_resolve_authorities (pipeline, mask, authorities); for (i = 0; i < COGL_PIPELINE_STATE_SPARSE_COUNT; i++) { unsigned int current_state = (1< differences) break; } return _cogl_util_one_at_a_time_mix (final_hash); } typedef struct { CoglContext *context; CoglPipeline *src_pipeline; CoglPipeline *dst_pipeline; unsigned int layer_differences; } DeepCopyData; static CoglBool deep_copy_layer_cb (CoglPipelineLayer *src_layer, void *user_data) { DeepCopyData *data = user_data; CoglPipelineLayer *dst_layer; unsigned int differences = data->layer_differences; dst_layer = _cogl_pipeline_get_layer (data->dst_pipeline, src_layer->index); while (src_layer != data->context->default_layer_n && src_layer != data->context->default_layer_0 && differences) { unsigned long to_copy = differences & src_layer->differences; if (to_copy) { _cogl_pipeline_layer_copy_differences (dst_layer, src_layer, to_copy); differences ^= to_copy; } src_layer = COGL_PIPELINE_LAYER (COGL_NODE (src_layer)->parent); } return TRUE; } CoglPipeline * _cogl_pipeline_deep_copy (CoglPipeline *pipeline, unsigned long differences, unsigned long layer_differences) { CoglPipeline *new, *authority; CoglBool copy_layer_state; _COGL_GET_CONTEXT (ctx, NULL); if ((differences & COGL_PIPELINE_STATE_LAYERS)) { copy_layer_state = TRUE; differences &= ~COGL_PIPELINE_STATE_LAYERS; } else copy_layer_state = FALSE; new = cogl_pipeline_new (ctx); for (authority = pipeline; authority != ctx->default_pipeline && differences; authority = COGL_PIPELINE (COGL_NODE (authority)->parent)) { unsigned long to_copy = differences & authority->differences; if (to_copy) { _cogl_pipeline_copy_differences (new, authority, to_copy); differences ^= to_copy; } } if (copy_layer_state) { DeepCopyData data; /* The unit index doesn't need to be copied because it should * end up with the same values anyway because the new pipeline * will have the same indices as the source pipeline */ layer_differences &= ~COGL_PIPELINE_LAYER_STATE_UNIT; data.context = ctx; data.src_pipeline = pipeline; data.dst_pipeline = new; data.layer_differences = layer_differences; _cogl_pipeline_foreach_layer_internal (pipeline, deep_copy_layer_cb, &data); } return new; } typedef struct { int i; CoglPipelineLayer **layers; } AddLayersToArrayState; static CoglBool add_layer_to_array_cb (CoglPipelineLayer *layer, void *user_data) { AddLayersToArrayState *state = user_data; state->layers[state->i++] = layer; return TRUE; } /* This tries to find the oldest ancestor whose pipeline and layer state matches the given flags. This is mostly used to detect code gen authorities so that we can reduce the numer of programs generated */ CoglPipeline * _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline, CoglPipelineState pipeline_state, CoglPipelineLayerState layer_state) { CoglPipeline *authority0; CoglPipeline *authority1; int n_layers; CoglPipelineLayer **authority0_layers; CoglPipelineLayer **authority1_layers; /* Find the first pipeline that modifies state that affects the * state or any layer state... */ authority0 = _cogl_pipeline_get_authority (pipeline, pipeline_state | COGL_PIPELINE_STATE_LAYERS); /* Find the next ancestor after that, that also modifies the * state... */ if (_cogl_pipeline_get_parent (authority0)) { authority1 = _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority0), pipeline_state | COGL_PIPELINE_STATE_LAYERS); } else return authority0; n_layers = cogl_pipeline_get_n_layers (authority0); for (;;) { AddLayersToArrayState state; int i; if (n_layers != cogl_pipeline_get_n_layers (authority1)) return authority0; /* If the programs differ by anything that isn't part of the layer state then we can't continue */ if (pipeline_state && (_cogl_pipeline_compare_differences (authority0, authority1) & pipeline_state)) return authority0; authority0_layers = g_alloca (sizeof (CoglPipelineLayer *) * n_layers); state.i = 0; state.layers = authority0_layers; _cogl_pipeline_foreach_layer_internal (authority0, add_layer_to_array_cb, &state); authority1_layers = g_alloca (sizeof (CoglPipelineLayer *) * n_layers); state.i = 0; state.layers = authority1_layers; _cogl_pipeline_foreach_layer_internal (authority1, add_layer_to_array_cb, &state); for (i = 0; i < n_layers; i++) { unsigned long layer_differences; if (authority0_layers[i] == authority1_layers[i]) continue; layer_differences = _cogl_pipeline_layer_compare_differences (authority0_layers[i], authority1_layers[i]); if (layer_differences & layer_state) return authority0; } /* Find the next ancestor after that, that also modifies state * affecting codegen... */ if (!_cogl_pipeline_get_parent (authority1)) break; authority0 = authority1; authority1 = _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority1), pipeline_state | COGL_PIPELINE_STATE_LAYERS); if (authority1 == authority0) break; } return authority1; } CoglPipelineState _cogl_pipeline_get_state_for_vertex_codegen (CoglContext *context) { CoglPipelineState state = (COGL_PIPELINE_STATE_LAYERS | COGL_PIPELINE_STATE_USER_SHADER | COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE | COGL_PIPELINE_STATE_VERTEX_SNIPPETS); /* If we don't have the builtin point size uniform then we'll add * one in the GLSL but we'll only do this if the point size is * non-zero. Whether or not the point size is zero is represented by * COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE */ if (!_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM)) state |= COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE; return state; } CoglPipelineLayerState _cogl_pipeline_get_layer_state_for_fragment_codegen (CoglContext *context) { CoglPipelineLayerState state = (COGL_PIPELINE_LAYER_STATE_COMBINE | COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE | COGL_PIPELINE_LAYER_STATE_UNIT | COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS); /* If the driver supports GLSL then we might be using gl_PointCoord * to implement the sprite coords. In that case the generated code * depends on the point sprite state */ if (cogl_has_feature (context, COGL_FEATURE_ID_GLSL)) state |= COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; return state; } CoglPipelineState _cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context) { CoglPipelineState state = (COGL_PIPELINE_STATE_LAYERS | COGL_PIPELINE_STATE_USER_SHADER | COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS); if (!_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_ALPHA_TEST)) state |= COGL_PIPELINE_STATE_ALPHA_FUNC; return state; } int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name) { void *location_ptr; char *uniform_name_copy; _COGL_GET_CONTEXT (ctx, -1); /* This API is designed as if the uniform locations are specific to a pipeline but they are actually unique across a whole CoglContext. Potentially this could just be cogl_context_get_uniform_location but it seems to make sense to keep the API this way so that we can change the internals if need be. */ /* Look for an existing uniform with this name */ if (g_hash_table_lookup_extended (ctx->uniform_name_hash, uniform_name, NULL, &location_ptr)) return GPOINTER_TO_INT (location_ptr); uniform_name_copy = g_strdup (uniform_name); g_ptr_array_add (ctx->uniform_names, uniform_name_copy); g_hash_table_insert (ctx->uniform_name_hash, uniform_name_copy, GINT_TO_POINTER (ctx->n_uniform_names)); return ctx->n_uniform_names++; } muffin-5.2.1/cogl/cogl/cogl-buffer.c0000664000175000017500000002633614211404421017355 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Damien Lespiau * Robert Bragg */ /* For an overview of the functionality implemented here, please see * cogl-buffer.h, which contains the gtk-doc section overview for the * Pixel Buffers API. */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-object-private.h" #include "cogl-pixel-buffer-private.h" /* XXX: * The CoglObject macros don't support any form of inheritance, so for * now we implement the CoglObject support for the CoglBuffer * abstract class manually. */ static GSList *_cogl_buffer_types; void _cogl_buffer_register_buffer_type (const CoglObjectClass *klass) { _cogl_buffer_types = g_slist_prepend (_cogl_buffer_types, (void *) klass); } CoglBool cogl_is_buffer (void *object) { const CoglObject *obj = object; GSList *l; if (object == NULL) return FALSE; for (l = _cogl_buffer_types; l; l = l->next) if (l->data == obj->klass) return TRUE; return FALSE; } /* * Fallback path, buffer->data points to a malloc'ed buffer. */ static void * malloc_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error) { buffer->flags |= COGL_BUFFER_FLAG_MAPPED; return buffer->data + offset; } static void malloc_unmap (CoglBuffer *buffer) { buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED; } static CoglBool malloc_set_data (CoglBuffer *buffer, unsigned int offset, const void *data, unsigned int size, CoglError **error) { memcpy (buffer->data + offset, data, size); return TRUE; } void _cogl_buffer_initialize (CoglBuffer *buffer, CoglContext *ctx, size_t size, CoglBufferBindTarget default_target, CoglBufferUsageHint usage_hint, CoglBufferUpdateHint update_hint) { CoglBool use_malloc = FALSE; buffer->context = ctx; buffer->flags = COGL_BUFFER_FLAG_NONE; buffer->store_created = FALSE; buffer->size = size; buffer->last_target = default_target; buffer->usage_hint = usage_hint; buffer->update_hint = update_hint; buffer->data = NULL; buffer->immutable_ref = 0; if (default_target == COGL_BUFFER_BIND_TARGET_PIXEL_PACK || default_target == COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK) { if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_PBOS)) use_malloc = TRUE; } else if (default_target == COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER || default_target == COGL_BUFFER_BIND_TARGET_INDEX_BUFFER) { if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_VBOS)) use_malloc = TRUE; } if (use_malloc) { buffer->vtable.map_range = malloc_map_range; buffer->vtable.unmap = malloc_unmap; buffer->vtable.set_data = malloc_set_data; buffer->data = malloc (size); } else { buffer->vtable.map_range = ctx->driver_vtable->buffer_map_range; buffer->vtable.unmap = ctx->driver_vtable->buffer_unmap; buffer->vtable.set_data = ctx->driver_vtable->buffer_set_data; ctx->driver_vtable->buffer_create (buffer); buffer->flags |= COGL_BUFFER_FLAG_BUFFER_OBJECT; } } void _cogl_buffer_fini (CoglBuffer *buffer) { _COGL_RETURN_IF_FAIL (!(buffer->flags & COGL_BUFFER_FLAG_MAPPED)); _COGL_RETURN_IF_FAIL (buffer->immutable_ref == 0); if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) buffer->context->driver_vtable->buffer_destroy (buffer); else free (buffer->data); } unsigned int cogl_buffer_get_size (CoglBuffer *buffer) { if (!cogl_is_buffer (buffer)) return 0; return COGL_BUFFER (buffer)->size; } void cogl_buffer_set_update_hint (CoglBuffer *buffer, CoglBufferUpdateHint hint) { if (!cogl_is_buffer (buffer)) return; if (G_UNLIKELY (hint > COGL_BUFFER_UPDATE_HINT_STREAM)) hint = COGL_BUFFER_UPDATE_HINT_STATIC; buffer->update_hint = hint; } CoglBufferUpdateHint cogl_buffer_get_update_hint (CoglBuffer *buffer) { if (!cogl_is_buffer (buffer)) return FALSE; return buffer->update_hint; } static void warn_about_midscene_changes (void) { static CoglBool seen = FALSE; if (!seen) { g_warning ("Mid-scene modification of buffers has " "undefined results\n"); seen = TRUE; } } void * _cogl_buffer_map (CoglBuffer *buffer, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); return cogl_buffer_map_range (buffer, 0, buffer->size, access, hints, error); } void * cogl_buffer_map (CoglBuffer *buffer, CoglBufferAccess access, CoglBufferMapHint hints) { CoglError *ignore_error = NULL; void *ptr = cogl_buffer_map_range (buffer, 0, buffer->size, access, hints, &ignore_error); if (!ptr) cogl_error_free (ignore_error); return ptr; } void * cogl_buffer_map_range (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); _COGL_RETURN_VAL_IF_FAIL (!(buffer->flags & COGL_BUFFER_FLAG_MAPPED), NULL); if (G_UNLIKELY (buffer->immutable_ref)) warn_about_midscene_changes (); buffer->data = buffer->vtable.map_range (buffer, offset, size, access, hints, error); return buffer->data; } void cogl_buffer_unmap (CoglBuffer *buffer) { if (!cogl_is_buffer (buffer)) return; if (!(buffer->flags & COGL_BUFFER_FLAG_MAPPED)) return; buffer->vtable.unmap (buffer); } void * _cogl_buffer_map_for_fill_or_fallback (CoglBuffer *buffer) { return _cogl_buffer_map_range_for_fill_or_fallback (buffer, 0, buffer->size); } void * _cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer, size_t offset, size_t size) { CoglContext *ctx = buffer->context; void *ret; CoglError *ignore_error = NULL; _COGL_RETURN_VAL_IF_FAIL (!ctx->buffer_map_fallback_in_use, NULL); ctx->buffer_map_fallback_in_use = TRUE; ret = cogl_buffer_map_range (buffer, offset, size, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, &ignore_error); if (ret) return ret; cogl_error_free (ignore_error); /* If the map fails then we'll use a temporary buffer to fill the data and then upload it using cogl_buffer_set_data when the buffer is unmapped. The temporary buffer is shared to avoid reallocating it every time */ g_byte_array_set_size (ctx->buffer_map_fallback_array, size); ctx->buffer_map_fallback_offset = offset; buffer->flags |= COGL_BUFFER_FLAG_MAPPED_FALLBACK; return ctx->buffer_map_fallback_array->data; } void _cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer) { CoglContext *ctx = buffer->context; _COGL_RETURN_IF_FAIL (ctx->buffer_map_fallback_in_use); ctx->buffer_map_fallback_in_use = FALSE; if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK)) { /* Note: don't try to catch OOM errors here since the use cases * we currently have for this api (the journal and path stroke * tesselator) don't have anything particularly sensible they * can do in response to a failure anyway so it seems better to * simply abort instead. * * If we find this is a problem for real world applications * then in the path tesselation case we could potentially add an * explicit cogl_path_tesselate_stroke() api that can throw an * error for the app to cache. For the journal we could * potentially flush the journal in smaller batches so we use * smaller buffers, though that would probably not help for * deferred renderers. */ _cogl_buffer_set_data (buffer, ctx->buffer_map_fallback_offset, ctx->buffer_map_fallback_array->data, ctx->buffer_map_fallback_array->len, NULL); buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK; } else cogl_buffer_unmap (buffer); } CoglBool _cogl_buffer_set_data (CoglBuffer *buffer, size_t offset, const void *data, size_t size, CoglError **error) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), FALSE); _COGL_RETURN_VAL_IF_FAIL ((offset + size) <= buffer->size, FALSE); if (G_UNLIKELY (buffer->immutable_ref)) warn_about_midscene_changes (); return buffer->vtable.set_data (buffer, offset, data, size, error); } CoglBool cogl_buffer_set_data (CoglBuffer *buffer, size_t offset, const void *data, size_t size) { CoglError *ignore_error = NULL; CoglBool status = _cogl_buffer_set_data (buffer, offset, data, size, &ignore_error); if (!status) cogl_error_free (ignore_error); return status; } CoglBuffer * _cogl_buffer_immutable_ref (CoglBuffer *buffer) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL); buffer->immutable_ref++; return buffer; } void _cogl_buffer_immutable_unref (CoglBuffer *buffer) { _COGL_RETURN_IF_FAIL (cogl_is_buffer (buffer)); _COGL_RETURN_IF_FAIL (buffer->immutable_ref > 0); buffer->immutable_ref--; } muffin-5.2.1/cogl/cogl/cogl-context-private.h0000664000175000017500000003366614211404421021251 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_CONTEXT_PRIVATE_H #define __COGL_CONTEXT_PRIVATE_H #include "cogl-context.h" #include "cogl-winsys-private.h" #include "cogl-flags.h" #ifdef COGL_HAS_XLIB_SUPPORT #include "cogl-xlib-private.h" #endif #include "cogl-display-private.h" #include "cogl-primitives.h" #include "cogl-clip-stack.h" #include "cogl-matrix-stack.h" #include "cogl-pipeline-private.h" #include "cogl-buffer-private.h" #include "cogl-bitmask.h" #include "cogl-atlas.h" #include "cogl-driver.h" #include "cogl-texture-driver.h" #include "cogl-pipeline-cache.h" #include "cogl-texture-2d.h" #include "cogl-texture-3d.h" #include "cogl-texture-rectangle.h" #include "cogl-sampler-cache-private.h" #include "cogl-gpu-info-private.h" #include "cogl-gl-header.h" #include "cogl-framebuffer-private.h" #include "cogl-onscreen-private.h" #include "cogl-fence-private.h" #include "cogl-poll-private.h" #include "cogl-path/cogl-path-types.h" #include "cogl-private.h" typedef struct { GLfloat v[3]; GLfloat t[2]; GLubyte c[4]; } CoglTextureGLVertex; struct _CoglContext { CoglObject _parent; CoglDisplay *display; CoglDriver driver; /* Information about the GPU and driver which we can use to determine certain workarounds */ CoglGpuInfo gpu; /* vtables for the driver functions */ const CoglDriverVtable *driver_vtable; const CoglTextureDriver *texture_driver; int glsl_major; int glsl_minor; /* This is the GLSL version that we will claim that snippets are * written against using the #version pragma. This will be the * largest version that is less than or equal to the version * provided by the driver without massively altering the syntax. Eg, * we wouldn't use version 1.3 even if it is available because that * removes the ‘attribute’ and ‘varying’ keywords. */ int glsl_version_to_use; /* Features cache */ unsigned long features[COGL_FLAGS_N_LONGS_FOR_SIZE (_COGL_N_FEATURE_IDS)]; CoglFeatureFlags feature_flags; /* legacy/deprecated feature flags */ unsigned long private_features [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_N_PRIVATE_FEATURES)]; CoglBool needs_viewport_scissor_workaround; CoglFramebuffer *viewport_scissor_workaround_framebuffer; CoglPipeline *default_pipeline; CoglPipelineLayer *default_layer_0; CoglPipelineLayer *default_layer_n; CoglPipelineLayer *dummy_layer_dependant; GHashTable *attribute_name_states_hash; GArray *attribute_name_index_map; int n_attribute_names; CoglBitmask enabled_builtin_attributes; CoglBitmask enabled_texcoord_attributes; CoglBitmask enabled_custom_attributes; /* These are temporary bitmasks that are used when disabling * builtin,texcoord and custom attribute arrays. They are here just * to avoid allocating new ones each time */ CoglBitmask enable_builtin_attributes_tmp; CoglBitmask enable_texcoord_attributes_tmp; CoglBitmask enable_custom_attributes_tmp; CoglBitmask changed_bits_tmp; CoglBool legacy_backface_culling_enabled; /* A few handy matrix constants */ CoglMatrix identity_matrix; CoglMatrix y_flip_matrix; /* Value that was last used when calling glMatrixMode to avoid calling it multiple times */ CoglMatrixMode flushed_matrix_mode; /* The matrix stack entries that should be flushed during the next * pipeline state flush */ CoglMatrixEntry *current_projection_entry; CoglMatrixEntry *current_modelview_entry; CoglMatrixEntry identity_entry; /* A cache of the last (immutable) matrix stack entries that were * flushed to the GL matrix builtins */ CoglMatrixEntryCache builtin_flushed_projection; CoglMatrixEntryCache builtin_flushed_modelview; GArray *texture_units; int active_texture_unit; CoglPipelineFogState legacy_fog_state; /* Pipelines */ CoglPipeline *opaque_color_pipeline; /* used for set_source_color */ CoglPipeline *blended_color_pipeline; /* used for set_source_color */ CoglPipeline *texture_pipeline; /* used for set_source_texture */ GString *codegen_header_buffer; GString *codegen_source_buffer; GString *codegen_boilerplate_buffer; GList *source_stack; int legacy_state_set; CoglPipelineCache *pipeline_cache; /* Textures */ CoglTexture2D *default_gl_texture_2d_tex; CoglTexture3D *default_gl_texture_3d_tex; CoglTextureRectangle *default_gl_texture_rect_tex; /* Central list of all framebuffers so all journals can be flushed * at any time. */ GList *framebuffers; /* Global journal buffers */ GArray *journal_flush_attributes_array; GArray *journal_clip_bounds; GArray *polygon_vertices; /* Some simple caching, to minimize state changes... */ CoglPipeline *current_pipeline; unsigned long current_pipeline_changes_since_flush; CoglBool current_pipeline_with_color_attrib; CoglBool current_pipeline_unknown_color_alpha; unsigned long current_pipeline_age; CoglBool gl_blend_enable_cache; CoglBool depth_test_enabled_cache; CoglDepthTestFunction depth_test_function_cache; CoglBool depth_writing_enabled_cache; float depth_range_near_cache; float depth_range_far_cache; CoglBool legacy_depth_test_enabled; CoglBuffer *current_buffer[COGL_BUFFER_BIND_TARGET_COUNT]; /* Framebuffers */ GSList *framebuffer_stack; CoglFramebuffer *window_buffer; unsigned long current_draw_buffer_state_flushed; unsigned long current_draw_buffer_changes; CoglFramebuffer *current_draw_buffer; CoglFramebuffer *current_read_buffer; gboolean have_last_offscreen_allocate_flags; CoglOffscreenAllocateFlags last_offscreen_allocate_flags; GHashTable *swap_callback_closures; int next_swap_callback_id; CoglList onscreen_events_queue; CoglList onscreen_dirty_queue; CoglClosure *onscreen_dispatch_idle; CoglGLES2Context *current_gles2_context; GQueue gles2_context_stack; /* This becomes TRUE the first time the context is bound to an * onscreen buffer. This is used by cogl-framebuffer-gl to determine * when to initialise the glDrawBuffer state */ CoglBool was_bound_to_onscreen; /* Primitives */ CoglPath *current_path; CoglPipeline *stencil_pipeline; /* Pre-generated VBOs containing indices to generate GL_TRIANGLES out of a vertex array of quads */ CoglIndices *quad_buffer_indices_byte; unsigned int quad_buffer_indices_len; CoglIndices *quad_buffer_indices; CoglIndices *rectangle_byte_indices; CoglIndices *rectangle_short_indices; int rectangle_short_indices_len; CoglBool in_begin_gl_block; CoglPipeline *texture_download_pipeline; CoglPipeline *blit_texture_pipeline; GSList *atlases; GHookList atlas_reorganize_callbacks; /* This debugging variable is used to pick a colour for visually displaying the quad batches. It needs to be global so that it can be reset by cogl_clear. It needs to be reset to increase the chances of getting the same colour during an animation */ uint8_t journal_rectangles_color; /* Cached values for GL_MAX_TEXTURE_[IMAGE_]UNITS to avoid calling glGetInteger too often */ GLint max_texture_units; GLint max_texture_image_units; GLint max_activateable_texture_units; /* Fragment processing programs */ CoglHandle current_program; CoglPipelineProgramType current_fragment_program_type; CoglPipelineProgramType current_vertex_program_type; GLuint current_gl_program; CoglBool current_gl_dither_enabled; CoglColorMask current_gl_color_mask; GLenum current_gl_draw_buffer; /* Clipping */ /* TRUE if we have a valid clipping stack flushed. In that case current_clip_stack will describe what the current state is. If this is FALSE then the current clip stack is completely unknown so it will need to be reflushed. In that case current_clip_stack doesn't need to be a valid pointer. We can't just use NULL in current_clip_stack to mark a dirty state because NULL is a valid stack (meaning no clipping) */ CoglBool current_clip_stack_valid; /* The clip state that was flushed. This isn't intended to be used as a stack to push and pop new entries. Instead the current stack that the user wants is part of the framebuffer state. This is just used to record the flush state so we can avoid flushing the same state multiple times. When the clip state is flushed this will hold a reference */ CoglClipStack *current_clip_stack; /* Whether the stencil buffer was used as part of the current clip state. If TRUE then any further use of the stencil buffer (such as for drawing paths) would need to be merged with the existing stencil buffer */ CoglBool current_clip_stack_uses_stencil; /* This is used as a temporary buffer to fill a CoglBuffer when cogl_buffer_map fails and we only want to map to fill it with new data */ GByteArray *buffer_map_fallback_array; CoglBool buffer_map_fallback_in_use; size_t buffer_map_fallback_offset; CoglWinsysRectangleState rectangle_state; CoglSamplerCache *sampler_cache; /* FIXME: remove these when we remove the last xlib based clutter * backend. they should be tracked as part of the renderer but e.g. * the eglx backend doesn't yet have a corresponding Cogl winsys * and so we wont have a renderer in that case. */ #ifdef COGL_HAS_XLIB_SUPPORT int damage_base; /* List of callback functions that will be given every Xlib event */ GSList *event_filters; /* Current top of the XError trap state stack. The actual memory for these is expected to be allocated on the stack by the caller */ CoglXlibTrapState *trap_state; #endif unsigned long winsys_features [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_WINSYS_FEATURE_N_FEATURES)]; void *winsys; /* Array of names of uniforms. These are used like quarks to give a unique number to each uniform name except that we ensure that they increase sequentially so that we can use the id as an index into a bitfield representing the uniforms that a pipeline overrides from its parent. */ GPtrArray *uniform_names; /* A hash table to quickly get an index given an existing name. The name strings are owned by the uniform_names array. The values are the uniform location cast to a pointer. */ GHashTable *uniform_name_hash; int n_uniform_names; CoglPollSource *fences_poll_source; CoglList fences; /* This defines a list of function pointers that Cogl uses from either GL or GLES. All functions are accessed indirectly through these pointers rather than linking to them directly */ #ifndef APIENTRY #define APIENTRY #endif #define COGL_EXT_BEGIN(name, \ min_gl_major, min_gl_minor, \ gles_availability, \ extension_suffixes, extension_names) #define COGL_EXT_FUNCTION(ret, name, args) \ ret (APIENTRY * name) args; #define COGL_EXT_END() #include "gl-prototypes/cogl-all-functions.h" #undef COGL_EXT_BEGIN #undef COGL_EXT_FUNCTION #undef COGL_EXT_END }; CoglContext * _cogl_context_get_default (); const CoglWinsysVtable * _cogl_context_get_winsys (CoglContext *context); /* Query the GL extensions and lookup the corresponding function * pointers. Theoretically the list of extensions can change for * different GL contexts so it is the winsys backend's responsiblity * to know when to re-query the GL extensions. The backend should also * check whether the GL context is supported by Cogl. If not it should * return FALSE and set @error */ CoglBool _cogl_context_update_features (CoglContext *context, CoglError **error); /* Obtains the context and returns retval if NULL */ #define _COGL_GET_CONTEXT(ctxvar, retval) \ CoglContext *ctxvar = _cogl_context_get_default (); \ if (ctxvar == NULL) return retval; #define NO_RETVAL void _cogl_context_set_current_projection_entry (CoglContext *context, CoglMatrixEntry *entry); void _cogl_context_set_current_modelview_entry (CoglContext *context, CoglMatrixEntry *entry); /* * _cogl_context_get_gl_extensions: * @context: A CoglContext * * Return value: a NULL-terminated array of strings representing the * supported extensions by the current driver. This array is owned * by the caller and should be freed with g_strfreev(). */ char ** _cogl_context_get_gl_extensions (CoglContext *context); const char * _cogl_context_get_gl_version (CoglContext *context); #endif /* __COGL_CONTEXT_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-texture-3d-private.h0000664000175000017500000000422114211404421021552 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #ifndef __COGL_TEXTURE_3D_PRIVATE_H #define __COGL_TEXTURE_3D_PRIVATE_H #include "cogl-object-private.h" #include "cogl-pipeline-private.h" #include "cogl-texture-private.h" #include "cogl-texture-3d.h" struct _CoglTexture3D { CoglTexture _parent; /* The internal format of the texture represented as a CoglPixelFormat */ CoglPixelFormat internal_format; int depth; CoglBool auto_mipmap; CoglBool mipmaps_dirty; /* TODO: factor out these OpenGL specific members into some form * of driver private state. */ /* The internal format of the GL texture represented as a GL enum */ GLenum gl_format; /* The texture object number */ GLuint gl_texture; GLenum gl_legacy_texobj_min_filter; GLenum gl_legacy_texobj_mag_filter; GLint gl_legacy_texobj_wrap_mode_s; GLint gl_legacy_texobj_wrap_mode_t; GLint gl_legacy_texobj_wrap_mode_p; CoglTexturePixel first_pixel; }; #endif /* __COGL_TEXTURE_3D_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-glsl-shader-boilerplate.h0000664000175000017500000000601014211404421022601 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #ifndef __COGL_SHADER_BOILERPLATE_H #define __COGL_SHADER_BOILERPLATE_H #define _COGL_COMMON_SHADER_BOILERPLATE \ "#define COGL_VERSION 100\n" \ "\n" \ "uniform mat4 cogl_modelview_matrix;\n" \ "uniform mat4 cogl_modelview_projection_matrix;\n" \ "uniform mat4 cogl_projection_matrix;\n" /* This declares all of the variables that we might need. This is * working on the assumption that the compiler will optimise them out * if they are not actually used. The GLSL spec at least implies that * this will happen for varyings but it doesn't explicitly so for * attributes */ #define _COGL_VERTEX_SHADER_BOILERPLATE \ _COGL_COMMON_SHADER_BOILERPLATE \ "#define cogl_color_out _cogl_color\n" \ "varying vec4 _cogl_color;\n" \ "#define cogl_tex_coord_out _cogl_tex_coord\n" \ "#define cogl_position_out gl_Position\n" \ "#define cogl_point_size_out gl_PointSize\n" \ "\n" \ "attribute vec4 cogl_color_in;\n" \ "attribute vec4 cogl_position_in;\n" \ "#define cogl_tex_coord_in cogl_tex_coord0_in;\n" \ "attribute vec3 cogl_normal_in;\n" #define _COGL_FRAGMENT_SHADER_BOILERPLATE \ "#ifdef GL_ES\n" \ "precision highp float;\n" \ "#endif\n" \ _COGL_COMMON_SHADER_BOILERPLATE \ "\n" \ "varying vec4 _cogl_color;\n" \ "\n" \ "#define cogl_color_in _cogl_color\n" \ "#define cogl_tex_coord_in _cogl_tex_coord\n" \ "\n" \ "#define cogl_color_out gl_FragColor\n" \ "#define cogl_depth_out gl_FragDepth\n" \ "\n" \ "#define cogl_front_facing gl_FrontFacing\n" \ "\n" \ "#define cogl_point_coord gl_PointCoord\n" #if 0 /* GLSL 1.2 has a bottom left origin, though later versions * allow use of an origin_upper_left keyword which would be * more appropriate for Cogl. */ "#define coglFragCoord gl_FragCoord\n" #endif #endif /* __COGL_SHADER_BOILERPLATE_H */ muffin-5.2.1/cogl/cogl/cogl-snippet.h0000664000175000017500000007601314211404421017570 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011, 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Neil Roberts */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_SNIPPET_H__ #define __COGL_SNIPPET_H__ COGL_BEGIN_DECLS /** * SECTION:cogl-snippet * @short_description: Functions for creating and manipulating shader snippets * * #CoglSnippets are used to modify or replace parts of a * #CoglPipeline using GLSL. GLSL is a programming language supported * by OpenGL on programmable hardware to provide a more flexible * description of what should be rendered. A description of GLSL * itself is outside the scope of this documentation but any good * OpenGL book should help to describe it. * * Unlike in OpenGL, when using GLSL with Cogl it is possible to write * short snippets to replace small sections of the pipeline instead of * having to replace the whole of either the vertex or fragment * pipelines. Of course it is also possible to replace the whole of * the pipeline if needed. * * Each snippet is a standalone chunk of code which would attach to * the pipeline at a particular point. The code is split into four * separate strings (all of which are optional): * * * * declarations * * The code in this string will be inserted outside of any function in * the global scope of the shader. This can be used to declare * uniforms, attributes, varyings and functions to be used by the * snippet. * * * * pre * * The code in this string will be inserted before the hook point. * * * * post * * The code in this string will be inserted after the hook point. This * can be used to modify the results of the builtin generated code for * that hook point. * * * * replace * * If present the code in this string will replace the generated code * for the hook point. * * * * * All of the strings apart from the declarations string of a pipeline * are generated in a single function so they can share variables * declared from one string in another. The scope of the code is * limited to each snippet so local variables declared in the snippet * will not collide with variables declared in another * snippet. However, code in the 'declarations' string is global to * the shader so it is the application's responsibility to ensure that * variables declared here will not collide with those from other * snippets. * * The snippets can be added to a pipeline with * cogl_pipeline_add_snippet() or * cogl_pipeline_add_layer_snippet(). Which function to use depends on * which hook the snippet is targetting. The snippets are all * generated in the order they are added to the pipeline. That is, the * post strings are executed in the order they are added to the * pipeline and the pre strings are executed in reverse order. If any * replace strings are given for a snippet then any other snippets * with the same hook added before that snippet will be ignored. The * different hooks are documented under #CoglSnippetHook. * * For portability with GLES2, it is recommended not to use the GLSL * builtin names such as gl_FragColor. Instead there are replacement * names under the cogl_* namespace which can be used instead. These * are: * * * * uniform mat4 * cogl_modelview_matrix * * The current modelview matrix. This is equivalent to * #gl_ModelViewMatrix. * * * * uniform mat4 * cogl_projection_matrix * * The current projection matrix. This is equivalent to * #gl_ProjectionMatrix. * * * * uniform mat4 * cogl_modelview_projection_matrix * * The combined modelview and projection matrix. A vertex shader * would typically use this to transform the incoming vertex * position. The separate modelview and projection matrices are * usually only needed for lighting calculations. This is * equivalent to #gl_ModelViewProjectionMatrix. * * * * uniform mat4 * cogl_texture_matrix[] * * An array of matrices for transforming the texture * coordinates. This is equivalent to #gl_TextureMatrix. * * * * * In a vertex shader, the following are also available: * * * * attribute vec4 * cogl_position_in * * The incoming vertex position. This is equivalent to #gl_Vertex. * * * * attribute vec4 * cogl_color_in * * The incoming vertex color. This is equivalent to #gl_Color. * * * * attribute vec4 * cogl_tex_coord_in * * The texture coordinate for layer 0. This is an alternative name * for #cogl_tex_coord0_in. * * * * attribute vec4 * cogl_tex_coord0_in * * The texture coordinate for the layer 0. This is equivalent to * #gl_MultiTexCoord0. There will also be #cogl_tex_coord1_in and * so on if more layers are added to the pipeline. * * * * attribute vec3 * cogl_normal_in * * The normal of the vertex. This is equivalent to #gl_Normal. * * * * vec4 * cogl_position_out * * The calculated position of the vertex. This must be written to * in all vertex shaders. This is equivalent to #gl_Position. * * * * float * cogl_point_size_in * * The incoming point size from the cogl_point_size_in attribute. * This is only available if * cogl_pipeline_set_per_vertex_point_size() is set on the * pipeline. * * * * float * cogl_point_size_out * * The calculated size of a point. This is equivalent to #gl_PointSize. * * * * varying vec4 * cogl_color_out * * The calculated color of a vertex. This is equivalent to #gl_FrontColor. * * * * varying vec4 * cogl_tex_coord0_out * * The calculated texture coordinate for layer 0 of the pipeline. * This is equivalent to #gl_TexCoord[0]. There will also be * #cogl_tex_coord1_out and so on if more layers are added to the * pipeline. In the fragment shader, this varying is called * #cogl_tex_coord0_in. * * * * * In a fragment shader, the following are also available: * * * * varying vec4 cogl_color_in * * The calculated color of a vertex. This is equivalent to #gl_FrontColor. * * * * varying vec4 * cogl_tex_coord0_in * * The texture coordinate for layer 0. This is equivalent to * #gl_TexCoord[0]. There will also be #cogl_tex_coord1_in and so * on if more layers are added to the pipeline. * * * * vec4 cogl_color_out * * The final calculated color of the fragment. All fragment shaders * must write to this variable. This is equivalent to * #gl_FrontColor. * * * * float cogl_depth_out * * An optional output variable specifying the depth value to use * for this fragment. This is equivalent to #gl_FragDepth. * * * * bool cogl_front_facing * * A readonly variable that will be true if the current primitive * is front facing. This can be used to implement two-sided * coloring algorithms. This is equivalent to #gl_FrontFacing. * * * * vec2 cogl_point_coord * * When rendering points, this will contain a vec2 which represents * the position within the point of the current fragment. * vec2(0.0,0.0) will be the topleft of the point and vec2(1.0,1.0) * will be the bottom right. Note that there is currently a bug in * Cogl where when rendering to an offscreen buffer these * coordinates will be upside-down. The value is undefined when not * rendering points. This builtin can only be used if the * %COGL_FEATURE_ID_POINT_SPRITE feature is available. * * * * * Here is an example of using a snippet to add a desaturate effect to the * generated color on a pipeline. * * * CoglPipeline *pipeline = cogl_pipeline_new (); * * /* Set up the pipeline here, ie by adding a texture or other * layers */ * * /* Create the snippet. The first string is the declarations which * we will use to add a uniform. The second is the 'post' string which * will contain the code to perform the desaturation. */ * CoglSnippet *snippet = * cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, * "uniform float factor;", * "float gray = dot (vec3 (0.299, 0.587, 0.114), " * " cogl_color_out.rgb);" * "cogl_color_out.rgb = mix (vec3 (gray)," * " cogl_color_out.rgb," * " factor);"); * * /* Add it to the pipeline */ * cogl_pipeline_add_snippet (pipeline, snippet); * /* The pipeline keeps a reference to the snippet * so we don't need to */ * cogl_object_unref (snippet); * * /* Update the custom uniform on the pipeline */ * int location = cogl_pipeline_get_uniform_location (pipeline, "factor"); * cogl_pipeline_set_uniform_1f (pipeline, location, 0.5f); * * /* Now we can render with the snippet as usual */ * cogl_push_source (pipeline); * cogl_rectangle (0, 0, 10, 10); * cogl_pop_source (); * */ typedef struct _CoglSnippet CoglSnippet; #define COGL_SNIPPET(OBJECT) ((CoglSnippet *)OBJECT) /** * cogl_snippet_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_snippet_get_gtype (void); /* Enumeration of all the hook points that a snippet can be attached to within a pipeline. */ /** * CoglSnippetHook: * @COGL_SNIPPET_HOOK_VERTEX_GLOBALS: A hook for declaring global data * that can be shared with all other snippets that are on a vertex * hook. * @COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS: A hook for declaring global * data wthat can be shared with all other snippets that are on a * fragment hook. * @COGL_SNIPPET_HOOK_VERTEX: A hook for the entire vertex processing * stage of the pipeline. * @COGL_SNIPPET_HOOK_VERTEX_TRANSFORM: A hook for the vertex transformation. * @COGL_SNIPPET_HOOK_POINT_SIZE: A hook for manipulating the point * size of a vertex. This is only used if * cogl_pipeline_set_per_vertex_point_size() is enabled on the * pipeline. * @COGL_SNIPPET_HOOK_FRAGMENT: A hook for the entire fragment * processing stage of the pipeline. * @COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM: A hook for applying the * layer matrix to a texture coordinate for a layer. * @COGL_SNIPPET_HOOK_LAYER_FRAGMENT: A hook for the fragment * processing of a particular layer. * @COGL_SNIPPET_HOOK_TEXTURE_LOOKUP: A hook for the texture lookup * stage of a given layer in a pipeline. * * #CoglSnippetHook is used to specify a location within a * #CoglPipeline where the code of the snippet should be used when it * is attached to a pipeline. * * * * %COGL_SNIPPET_HOOK_VERTEX_GLOBALS * * * Adds a shader snippet at the beginning of the global section of the * shader for the vertex processing. Any declarations here can be * shared with all other snippets that are attached to a vertex hook. * Only the ‘declarations’ string is used and the other strings are * ignored. * * * * * %COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS * * * Adds a shader snippet at the beginning of the global section of the * shader for the fragment processing. Any declarations here can be * shared with all other snippets that are attached to a fragment * hook. Only the ‘declarations’ string is used and the other strings * are ignored. * * * * * %COGL_SNIPPET_HOOK_VERTEX * * * Adds a shader snippet that will hook on to the vertex processing * stage of the pipeline. This gives a chance for the application to * modify the vertex attributes generated by the shader. Typically the * snippet will modify cogl_color_out or cogl_position_out builtins. * * * The ‘declarations’ string in @snippet will be inserted in the * global scope of the shader. Use this to declare any uniforms, * attributes or functions that the snippet requires. * * * The ‘pre’ string in @snippet will be inserted at the top of the * main() function before any vertex processing is done. * * * The ‘replace’ string in @snippet will be used instead of the * generated vertex processing if it is present. This can be used if * the application wants to provide a complete vertex shader and * doesn't need the generated output from Cogl. * * * The ‘post’ string in @snippet will be inserted after all of the * standard vertex processing is done. This can be used to modify the * outputs. * * * * * %COGL_SNIPPET_HOOK_VERTEX_TRANSFORM * * * Adds a shader snippet that will hook on to the vertex transform stage. * Typically the snippet will use the cogl_modelview_matrix, * cogl_projection_matrix and cogl_modelview_projection_matrix matrices and the * cogl_position_in attribute. The hook must write to cogl_position_out. * The default processing for this hook will multiply cogl_position_in by * the combined modelview-projection matrix and store it on cogl_position_out. * * * The ‘declarations’ string in @snippet will be inserted in the * global scope of the shader. Use this to declare any uniforms, * attributes or functions that the snippet requires. * * * The ‘pre’ string in @snippet will be inserted at the top of the * main() function before the vertex transform is done. * * * The ‘replace’ string in @snippet will be used instead of the * generated vertex transform if it is present. * * * The ‘post’ string in @snippet will be inserted after all of the * standard vertex transformation is done. This can be used to modify the * cogl_position_out in addition to the default processing. * * * * * %COGL_SNIPPET_HOOK_POINT_SIZE * * * Adds a shader snippet that will hook on to the point size * calculation step within the vertex shader stage. The snippet should * write to the builtin cogl_point_size_out with the new point size. * The snippet can either read cogl_point_size_in directly and write a * new value or first read an existing value in cogl_point_size_out * that would be set by a previous snippet. Note that this hook is * only used if cogl_pipeline_set_per_vertex_point_size() is enabled * on the pipeline. * * * The ‘declarations’ string in @snippet will be inserted in the * global scope of the shader. Use this to declare any uniforms, * attributes or functions that the snippet requires. * * * The ‘pre’ string in @snippet will be inserted just before * calculating the point size. * * * The ‘replace’ string in @snippet will be used instead of the * generated point size calculation if it is present. * * * The ‘post’ string in @snippet will be inserted after the * standard point size calculation is done. This can be used to modify * cogl_point_size_out in addition to the default processing. * * * * * %COGL_SNIPPET_HOOK_FRAGMENT * * * Adds a shader snippet that will hook on to the fragment processing * stage of the pipeline. This gives a chance for the application to * modify the fragment color generated by the shader. Typically the * snippet will modify cogl_color_out. * * * The ‘declarations’ string in @snippet will be inserted in the * global scope of the shader. Use this to declare any uniforms, * attributes or functions that the snippet requires. * * * The ‘pre’ string in @snippet will be inserted at the top of the * main() function before any fragment processing is done. * * * The ‘replace’ string in @snippet will be used instead of the * generated fragment processing if it is present. This can be used if * the application wants to provide a complete fragment shader and * doesn't need the generated output from Cogl. * * * The ‘post’ string in @snippet will be inserted after all of the * standard fragment processing is done. At this point the generated * value for the rest of the pipeline state will already be in * cogl_color_out so the application can modify the result by altering * this variable. * * * * * %COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM * * * Adds a shader snippet that will hook on to the texture coordinate * transformation of a particular layer. This can be used to replace * the processing for a layer or to modify the results. * * * Within the snippet code for this hook there are two extra * variables. The first is a mat4 called cogl_matrix which represents * the user matrix for this layer. The second is called cogl_tex_coord * and represents the incoming and outgoing texture coordinate. On * entry to the hook, cogl_tex_coord contains the value of the * corresponding texture coordinate attribute for this layer. The hook * is expected to modify this variable. The output will be passed as a * varying to the fragment processing stage. The default code will * just multiply cogl_matrix by cogl_tex_coord and store the result in * cogl_tex_coord. * * * The ‘declarations’ string in @snippet will be inserted in the * global scope of the shader. Use this to declare any uniforms, * attributes or functions that the snippet requires. * * * The ‘pre’ string in @snippet will be inserted just before the * fragment processing for this layer. At this point cogl_tex_coord * still contains the value of the texture coordinate attribute. * * * If a ‘replace’ string is given then this will be used instead of * the default fragment processing for this layer. The snippet can * modify cogl_tex_coord or leave it as is to apply no transformation. * * * The ‘post’ string in @snippet will be inserted just after the * transformation. At this point cogl_tex_coord will contain the * results of the transformation but it can be further modified by the * snippet. * * * * * %COGL_SNIPPET_HOOK_LAYER_FRAGMENT * * * Adds a shader snippet that will hook on to the fragment processing * of a particular layer. This can be used to replace the processing * for a layer or to modify the results. * * * Within the snippet code for this hook there is an extra vec4 * variable called ‘cogl_layer’. This contains the resulting color * that will be used for the layer. This can be modified in the ‘post’ * section or it the default processing can be replaced entirely using * the ‘replace’ section. * * * The ‘declarations’ string in @snippet will be inserted in the * global scope of the shader. Use this to declare any uniforms, * attributes or functions that the snippet requires. * * * The ‘pre’ string in @snippet will be inserted just before the * fragment processing for this layer. * * * If a ‘replace’ string is given then this will be used instead of * the default fragment processing for this layer. The snippet must write to * the ‘cogl_layer’ variable in that case. * * * The ‘post’ string in @snippet will be inserted just after the * fragment processing for the layer. The results can be modified by changing * the value of the ‘cogl_layer’ variable. * * * * * %COGL_SNIPPET_HOOK_TEXTURE_LOOKUP * * * Adds a shader snippet that will hook on to the texture lookup part * of a given layer. This gives a chance for the application to modify * the coordinates that will be used for the texture lookup or to * alter the returned texel. * * * Within the snippet code for this hook there are three extra * variables available. ‘cogl_sampler’ is a sampler object * representing the sampler for the layer where the snippet is * attached. ‘cogl_tex_coord’ is a vec4 which contains the texture * coordinates that will be used for the texture lookup. This can be * modified. ‘cogl_texel’ will contain the result of the texture * lookup. This can also be modified. * * * The ‘declarations’ string in @snippet will be inserted in the * global scope of the shader. Use this to declare any uniforms, * attributes or functions that the snippet requires. * * * The ‘pre’ string in @snippet will be inserted at the top of the * main() function before any fragment processing is done. This is a * good place to modify the cogl_tex_coord variable. * * * If a ‘replace’ string is given then this will be used instead of a * the default texture lookup. The snippet would typically use its own * sampler in this case. * * * The ‘post’ string in @snippet will be inserted after texture lookup * has been preformed. Here the snippet can modify the cogl_texel * variable to alter the returned texel. * * * * * * Since: 1.10 * Stability: Unstable */ typedef enum { /* Per pipeline vertex hooks */ COGL_SNIPPET_HOOK_VERTEX = 0, COGL_SNIPPET_HOOK_VERTEX_TRANSFORM, COGL_SNIPPET_HOOK_VERTEX_GLOBALS, COGL_SNIPPET_HOOK_POINT_SIZE, /* Per pipeline fragment hooks */ COGL_SNIPPET_HOOK_FRAGMENT = 2048, COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS, /* Per layer vertex hooks */ COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM = 4096, /* Per layer fragment hooks */ COGL_SNIPPET_HOOK_LAYER_FRAGMENT = 6144, COGL_SNIPPET_HOOK_TEXTURE_LOOKUP } CoglSnippetHook; /** * cogl_snippet_new: * @hook: The point in the pipeline that this snippet will wrap around * or replace. * @declarations: The source code for the declarations for this * snippet or %NULL. See cogl_snippet_set_declarations(). * @post: The source code to run after the hook point where this * shader snippet is attached or %NULL. See cogl_snippet_set_post(). * * Allocates and initializes a new snippet with the given source strings. * * Return value: a pointer to a new #CoglSnippet * * Since: 1.10 * Stability: Unstable */ CoglSnippet * cogl_snippet_new (CoglSnippetHook hook, const char *declarations, const char *post); /** * cogl_snippet_get_hook: * @snippet: A #CoglSnippet * * Return value: the hook that was set when cogl_snippet_new() was * called. * Since: 1.10 * Stability: Unstable */ CoglSnippetHook cogl_snippet_get_hook (CoglSnippet *snippet); /** * cogl_is_snippet: * @object: A #CoglObject pointer * * Gets whether the given @object references an existing snippet object. * * Return value: %TRUE if the @object references a #CoglSnippet, * %FALSE otherwise * * Since: 1.10 * Stability: Unstable */ CoglBool cogl_is_snippet (void *object); /** * cogl_snippet_set_declarations: * @snippet: A #CoglSnippet * @declarations: The new source string for the declarations section * of this snippet. * * Sets a source string that will be inserted in the global scope of * the generated shader when this snippet is used on a pipeline. This * string is typically used to declare uniforms, attributes or * functions that will be used by the other parts of the snippets. * * This function should only be called before the snippet is attached * to its first pipeline. After that the snippet should be considered * immutable. * * Since: 1.10 * Stability: Unstable */ void cogl_snippet_set_declarations (CoglSnippet *snippet, const char *declarations); /** * cogl_snippet_get_declarations: * @snippet: A #CoglSnippet * * Return value: the source string that was set with * cogl_snippet_set_declarations() or %NULL if none was set. * * Since: 1.10 * Stability: Unstable */ const char * cogl_snippet_get_declarations (CoglSnippet *snippet); /** * cogl_snippet_set_pre: * @snippet: A #CoglSnippet * @pre: The new source string for the pre section of this snippet. * * Sets a source string that will be inserted before the hook point in * the generated shader for the pipeline that this snippet is attached * to. Please see the documentation of each hook point in * #CoglPipeline for a description of how this string should be used. * * This function should only be called before the snippet is attached * to its first pipeline. After that the snippet should be considered * immutable. * * Since: 1.10 * Stability: Unstable */ void cogl_snippet_set_pre (CoglSnippet *snippet, const char *pre); /** * cogl_snippet_get_pre: * @snippet: A #CoglSnippet * * Return value: the source string that was set with * cogl_snippet_set_pre() or %NULL if none was set. * * Since: 1.10 * Stability: Unstable */ const char * cogl_snippet_get_pre (CoglSnippet *snippet); /** * cogl_snippet_set_replace: * @snippet: A #CoglSnippet * @replace: The new source string for the replace section of this snippet. * * Sets a source string that will be used instead of any generated * source code or any previous snippets for this hook point. Please * see the documentation of each hook point in #CoglPipeline for a * description of how this string should be used. * * This function should only be called before the snippet is attached * to its first pipeline. After that the snippet should be considered * immutable. * * Since: 1.10 * Stability: Unstable */ void cogl_snippet_set_replace (CoglSnippet *snippet, const char *replace); /** * cogl_snippet_get_replace: * @snippet: A #CoglSnippet * * Return value: the source string that was set with * cogl_snippet_set_replace() or %NULL if none was set. * * Since: 1.10 * Stability: Unstable */ const char * cogl_snippet_get_replace (CoglSnippet *snippet); /** * cogl_snippet_set_post: * @snippet: A #CoglSnippet * @post: The new source string for the post section of this snippet. * * Sets a source string that will be inserted after the hook point in * the generated shader for the pipeline that this snippet is attached * to. Please see the documentation of each hook point in * #CoglPipeline for a description of how this string should be used. * * This function should only be called before the snippet is attached * to its first pipeline. After that the snippet should be considered * immutable. * * Since: 1.10 * Stability: Unstable */ void cogl_snippet_set_post (CoglSnippet *snippet, const char *post); /** * cogl_snippet_get_post: * @snippet: A #CoglSnippet * * Return value: the source string that was set with * cogl_snippet_set_post() or %NULL if none was set. * * Since: 1.10 * Stability: Unstable */ const char * cogl_snippet_get_post (CoglSnippet *snippet); COGL_END_DECLS #endif /* __COGL_SNIPPET_H__ */ muffin-5.2.1/cogl/cogl/cogl-vector.h0000664000175000017500000002372514211404421017412 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_VECTOR_H #define __COGL_VECTOR_H COGL_BEGIN_DECLS /** * SECTION:cogl-vector * @short_description: Functions for handling single precision float * vectors. * * This exposes a utility API that can be used for basic manipulation of 3 * component float vectors. */ /** * cogl_vector3_init: * @vector: The 3 component vector you want to initialize * @x: The x component * @y: The y component * @z: The z component * * Initializes a 3 component, single precision float vector which can * then be manipulated with the cogl_vector convenience APIs. Vectors * can also be used in places where a "point" is often desired. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_init (float *vector, float x, float y, float z); /** * cogl_vector3_init_zero: * @vector: The 3 component vector you want to initialize * * Initializes a 3 component, single precision float vector with zero * for each component. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_init_zero (float *vector); /** * cogl_vector3_equal: * @v1: The first 3 component vector you want to compare * @v2: The second 3 component vector you want to compare * * Compares the components of two vectors and returns TRUE if they are * the same. * * The comparison of the components is done with the '==' operator * such that -0 is considered equal to 0, but otherwise there is no * fuzziness such as an epsilon to consider vectors that are * essentially identical except for some minor precision error * differences due to the way they have been manipulated. * * Returns: TRUE if the vectors are equal else FALSE. * * Since: 1.4 * Stability: Unstable */ CoglBool cogl_vector3_equal (const void *v1, const void *v2); /** * cogl_vector3_equal_with_epsilon: * @vector0: The first 3 component vector you want to compare * @vector1: The second 3 component vector you want to compare * @epsilon: The allowable difference between components to still be * considered equal * * Compares the components of two vectors using the given epsilon and * returns TRUE if they are the same, using an internal epsilon for * comparing the floats. * * Each component is compared against the epsilon value in this way: * |[ * if (fabsf (vector0->x - vector1->x) < epsilon) * ]| * * Returns: TRUE if the vectors are equal else FALSE. * * Since: 1.4 * Stability: Unstable */ CoglBool cogl_vector3_equal_with_epsilon (const float *vector0, const float *vector1, float epsilon); /** * cogl_vector3_copy: * @vector: The 3 component vector you want to copy * * Allocates a new 3 component float vector on the heap initializing * the components from the given @vector and returns a pointer to the * newly allocated vector. You should free the memory using * cogl_vector3_free() * * Returns: A newly allocated 3 component float vector * * Since: 1.4 * Stability: Unstable */ float * cogl_vector3_copy (const float *vector); /** * cogl_vector3_free: * @vector: The 3 component you want to free * * Frees a 3 component vector that was previously allocated with * cogl_vector3_copy() * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_free (float *vector); /** * cogl_vector3_invert: * @vector: The 3 component vector you want to manipulate * * Inverts/negates all the components of the given @vector. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_invert (float *vector); /** * cogl_vector3_add: * @result: Where you want the result written * @a: The first vector operand * @b: The second vector operand * * Adds each of the corresponding components in vectors @a and @b * storing the results in @result. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_add (float *result, const float *a, const float *b); /** * cogl_vector3_subtract: * @result: Where you want the result written * @a: The first vector operand * @b: The second vector operand * * Subtracts each of the corresponding components in vector @b from * @a storing the results in @result. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_subtract (float *result, const float *a, const float *b); /** * cogl_vector3_multiply_scalar: * @vector: The 3 component vector you want to manipulate * @scalar: The scalar you want to multiply the vector components by * * Multiplies each of the @vector components by the given scalar. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_multiply_scalar (float *vector, float scalar); /** * cogl_vector3_divide_scalar: * @vector: The 3 component vector you want to manipulate * @scalar: The scalar you want to divide the vector components by * * Divides each of the @vector components by the given scalar. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_divide_scalar (float *vector, float scalar); /** * cogl_vector3_normalize: * @vector: The 3 component vector you want to manipulate * * Updates the vector so it is a "unit vector" such that the * @vectors magnitude or length is equal to 1. * * It's safe to use this function with the [0, 0, 0] vector, it will not * try to divide components by 0 (its norm) and will leave the vector * untouched. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_normalize (float *vector); /** * cogl_vector3_magnitude: * @vector: The 3 component vector you want the magnitude for * * Calculates the scalar magnitude or length of @vector. * * Returns: The magnitude of @vector. * * Since: 1.4 * Stability: Unstable */ float cogl_vector3_magnitude (const float *vector); /** * cogl_vector3_cross_product: * @result: Where you want the result written * @u: Your first 3 component vector * @v: Your second 3 component vector * * Calculates the cross product between the two vectors @u and @v. * * The cross product is a vector perpendicular to both @u and @v. This * can be useful for calculating the normal of a polygon by creating * two vectors in its plane using the polygons vertices and taking * their cross product. * * If the two vectors are parallel then the cross product is 0. * * You can use a right hand rule to determine which direction the * perpendicular vector will point: If you place the two vectors tail, * to tail and imagine grabbing the perpendicular line that extends * through the common tail with your right hand such that you fingers * rotate in the direction from @u to @v then the resulting vector * points along your extended thumb. * * Returns: The cross product between two vectors @u and @v. * * Since: 1.4 * Stability: Unstable */ void cogl_vector3_cross_product (float *result, const float *u, const float *v); /** * cogl_vector3_dot_product: * @a: Your first 3 component vector * @b: Your second 3 component vector * * Calculates the dot product of the two 3 component vectors. This * can be used to determine the magnitude of one vector projected onto * another. (for example a surface normal) * * For example if you have a polygon with a given normal vector and * some other point for which you want to calculate its distance from * the polygon, you can create a vector between one of the polygon * vertices and that point and use the dot product to calculate the * magnitude for that vector but projected onto the normal of the * polygon. This way you don't just get the distance from the point to * the edge of the polygon you get the distance from the point to the * nearest part of the polygon. * * If you don't use a unit length normal in the above example * then you would then also have to divide the result by the magnitude * of the normal * * The dot product is calculated as: * |[ * (a->x * b->x + a->y * b->y + a->z * b->z) * ]| * * For reference, the dot product can also be calculated from the * angle between two vectors as: * |[ * |a||b|cos𝜃 * ]| * * Returns: The dot product of two vectors. * * Since: 1.4 * Stability: Unstable */ float cogl_vector3_dot_product (const float *a, const float *b); /** * cogl_vector3_distance: * @a: The first point * @b: The second point * * If you consider the two given vectors as (x,y,z) points instead * then this will compute the distance between those two points. * * Returns: The distance between two points given as 3 component * vectors. * * Since: 1.4 * Stability: Unstable */ float cogl_vector3_distance (const float *a, const float *b); COGL_END_DECLS #endif /* __COGL_VECTOR_H */ muffin-5.2.1/cogl/cogl/cogl-gpu-info-private.h0000664000175000017500000000672314211404421021303 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_GPU_INFO_PRIVATE_H #define __COGL_GPU_INFO_PRIVATE_H #include "cogl-context.h" typedef enum _CoglGpuInfoArchitectureFlag { COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE, COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_TILED, COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_SOFTWARE, COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE, COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_DEFERRED, COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_SOFTWARE } CoglGpuInfoArchitectureFlag; typedef enum _CoglGpuInfoArchitecture { COGL_GPU_INFO_ARCHITECTURE_UNKNOWN, COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE, COGL_GPU_INFO_ARCHITECTURE_SGX, COGL_GPU_INFO_ARCHITECTURE_MALI, COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE, COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE, COGL_GPU_INFO_ARCHITECTURE_SWRAST } CoglGpuInfoArchitecture; typedef enum { COGL_GPU_INFO_VENDOR_UNKNOWN, COGL_GPU_INFO_VENDOR_INTEL, COGL_GPU_INFO_VENDOR_IMAGINATION_TECHNOLOGIES, COGL_GPU_INFO_VENDOR_ARM, COGL_GPU_INFO_VENDOR_QUALCOMM, COGL_GPU_INFO_VENDOR_NVIDIA, COGL_GPU_INFO_VENDOR_ATI, COGL_GPU_INFO_VENDOR_MESA } CoglGpuInfoVendor; typedef enum { COGL_GPU_INFO_DRIVER_PACKAGE_UNKNOWN, COGL_GPU_INFO_DRIVER_PACKAGE_MESA } CoglGpuInfoDriverPackage; typedef enum { /* If this bug is present then it is faster to read pixels into a * PBO and then memcpy out of the PBO into system memory rather than * directly read into system memory. * https://bugs.freedesktop.org/show_bug.cgi?id=46631 */ COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS = 1 << 0 } CoglGpuInfoDriverBug; typedef struct _CoglGpuInfoVersion CoglGpuInfoVersion; typedef struct _CoglGpuInfo CoglGpuInfo; struct _CoglGpuInfo { CoglGpuInfoVendor vendor; const char *vendor_name; CoglGpuInfoDriverPackage driver_package; const char *driver_package_name; int driver_package_version; CoglGpuInfoArchitecture architecture; const char *architecture_name; CoglGpuInfoArchitectureFlag architecture_flags; CoglGpuInfoDriverBug driver_bugs; }; /* * _cogl_gpu_info_init: * @ctx: A #CoglContext * @gpu: A return location for the GPU information * * Determines information about the GPU and driver from the given * context. */ void _cogl_gpu_info_init (CoglContext *ctx, CoglGpuInfo *gpu); #endif /* __COGL_GPU_INFO_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-wayland-server.h0000664000175000017500000001431014211404421021041 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #ifndef __COGL_WAYLAND_SERVER_H #define __COGL_WAYLAND_SERVER_H #include /* NB: this is a top-level header that can be included directly but we * want to be careful not to define __COGL_H_INSIDE__ when this is * included internally while building Cogl itself since * __COGL_H_INSIDE__ is used in headers to guard public vs private api * definitions */ #ifndef COGL_COMPILATION /* Note: When building Cogl .gir we explicitly define * __COGL_H_INSIDE__ */ #ifndef __COGL_H_INSIDE__ #define __COGL_H_INSIDE__ #define __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_WAYLAND_SERVER_ #endif #endif /* COGL_COMPILATION */ #include #include COGL_BEGIN_DECLS /** * cogl_wayland_display_set_compositor_display: * @display: a #CoglDisplay * @wayland_display: A compositor's Wayland display pointer * * Informs Cogl of a compositor's Wayland display pointer. This * enables Cogl to register private wayland extensions required to * pass buffers between the clients and compositor. * * Since: 1.10 * Stability: unstable */ void cogl_wayland_display_set_compositor_display (CoglDisplay *display, struct wl_display *wayland_display); /** * cogl_wayland_texture_2d_new_from_buffer: * @ctx: A #CoglContext * @buffer: A Wayland resource for a buffer * @error: A #CoglError for exceptions * * Uploads the @buffer referenced by the given Wayland resource to a * #CoglTexture2D. The buffer resource may refer to a wl_buffer or a * wl_shm_buffer. * * The results are undefined for passing an invalid @buffer * pointer * It is undefined if future updates to @buffer outside the * control of Cogl will affect the allocated #CoglTexture2D. In some * cases the contents of the buffer are copied (such as shm buffers), * and in other cases the underlying storage is re-used directly (such * as drm buffers) * * Returns: A newly allocated #CoglTexture2D, or if Cogl could not * validate the @buffer in some way (perhaps because of * an unsupported format) it will return %NULL and set * @error. * * Since: 1.10 * Stability: unstable */ CoglTexture2D * cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, struct wl_resource *buffer, CoglError **error); /** * cogl_wayland_texture_set_region_from_shm_buffer: * @texture: a #CoglTexture * @width: The width of the region to copy * @height: The height of the region to copy * @shm_buffer: The source buffer * @src_x: The X offset within the source bufer to copy from * @src_y: The Y offset within the source bufer to copy from * @dst_x: The X offset within the texture to copy to * @dst_y: The Y offset within the texture to copy to * @level: The mipmap level of the texture to copy to * @error: A #CoglError to return exceptional errors * * Sets the pixels in a rectangular subregion of @texture from a * Wayland SHM buffer. Generally this would be used in response to * wl_surface.damage event in a compositor in order to update the * texture with the damaged region. This is just a convenience wrapper * around getting the SHM buffer pointer and calling * cogl_texture_set_region(). See that function for a description of * the level parameter. * * Since the storage for a #CoglTexture is allocated lazily then * if the given @texture has not previously been allocated then this * api can return %FALSE and throw an exceptional @error if there is * not enough memory to allocate storage for @texture. * * Return value: %TRUE if the subregion upload was successful, and * %FALSE otherwise * Since: 1.18 * Stability: unstable */ CoglBool cogl_wayland_texture_set_region_from_shm_buffer (CoglTexture *texture, int src_x, int src_y, int width, int height, struct wl_shm_buffer * shm_buffer, int dst_x, int dst_y, int level, CoglError **error); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in * isolation which means we need to be extra careful about how we * define and undefine __COGL_H_INSIDE__ used to detect when internal * headers are incorrectly included by developers. In the gobject * introspection case we have to manually define __COGL_H_INSIDE__ as * a commandline argument for the scanner which means we must be * careful not to undefine it in a header... */ #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_WAYLAND_SERVER_ #undef __COGL_H_INSIDE__ #undef __COGL_MUST_UNDEF_COGL_H_INSIDE_COGL_WAYLAND_SERVER_ #endif #endif /* __COGL_WAYLAND_SERVER_H */ muffin-5.2.1/cogl/cogl/cogl-bitmap-private.h0000664000175000017500000001477714211404421021043 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007 OpenedHand * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_BITMAP_H #define __COGL_BITMAP_H #include #include "cogl-object-private.h" #include "cogl-buffer.h" #include "cogl-bitmap.h" struct _CoglBitmap { CoglObject _parent; /* Pointer back to the context that this bitmap was created with */ CoglContext *context; CoglPixelFormat format; int width; int height; int rowstride; uint8_t *data; CoglBool mapped; CoglBool bound; /* If this is non-null then 'data' is ignored and instead it is fetched from this shared bitmap. */ CoglBitmap *shared_bmp; /* If this is non-null then 'data' is treated as an offset into the buffer and map will divert to mapping the buffer */ CoglBuffer *buffer; }; /* * _cogl_bitmap_new_with_malloc_buffer: * @context: A #CoglContext * @width: width of the bitmap in pixels * @height: height of the bitmap in pixels * @format: the format of the pixels the array will store * @error: A #CoglError for catching exceptional errors or %NULL * * This is equivalent to cogl_bitmap_new_with_size() except that it * allocated the buffer using malloc() instead of creating a * #CoglPixelBuffer. The buffer will be automatically destroyed when * the bitmap is freed. * * Return value: a #CoglPixelBuffer representing the newly created array * * Since: 1.10 * Stability: Unstable */ CoglBitmap * _cogl_bitmap_new_with_malloc_buffer (CoglContext *context, unsigned int width, unsigned int height, CoglPixelFormat format, CoglError **error); /* The idea of this function is that it will create a bitmap that shares the actual data with another bitmap. This is needed for the atlas texture backend because it needs upload a bitmap to a sub texture but override the format so that it ignores the premult flag. */ CoglBitmap * _cogl_bitmap_new_shared (CoglBitmap *shared_bmp, CoglPixelFormat format, int width, int height, int rowstride); CoglBitmap * _cogl_bitmap_convert (CoglBitmap *bmp, CoglPixelFormat dst_format, CoglError **error); CoglBitmap * _cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp, CoglPixelFormat internal_format, CoglBool can_convert_in_place, CoglError **error); CoglBool _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp, CoglBitmap *dst_bmp, CoglError **error); CoglBitmap * _cogl_bitmap_from_file (CoglContext *ctx, const char *filename, CoglError **error); CoglBool _cogl_bitmap_unpremult (CoglBitmap *dst_bmp, CoglError **error); CoglBool _cogl_bitmap_premult (CoglBitmap *dst_bmp, CoglError **error); CoglBool _cogl_bitmap_convert_premult_status (CoglBitmap *bmp, CoglPixelFormat dst_format, CoglError **error); CoglBool _cogl_bitmap_copy_subregion (CoglBitmap *src, CoglBitmap *dst, int src_x, int src_y, int dst_x, int dst_y, int width, int height, CoglError **error); /* Creates a deep copy of the source bitmap */ CoglBitmap * _cogl_bitmap_copy (CoglBitmap *src_bmp, CoglError **error); CoglBool _cogl_bitmap_get_size_from_file (const char *filename, int *width, int *height); void _cogl_bitmap_set_format (CoglBitmap *bitmap, CoglPixelFormat format); /* Maps the bitmap so that the pixels can be accessed directly or if the bitmap is just a memory bitmap then it just returns the pointer to memory. Note that the bitmap isn't guaranteed to allocated to the full size of rowstride*height so it is not safe to read up to the rowstride of the last row. This will be the case if the user uploads data using gdk_pixbuf_new_subpixbuf with a sub region containing the last row of the pixbuf because in that case the rowstride can be much larger than the width of the image */ uint8_t * _cogl_bitmap_map (CoglBitmap *bitmap, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error); void _cogl_bitmap_unmap (CoglBitmap *bitmap); /* These two are replacements for map and unmap that should used when * the pointer is going to be passed to GL for pixel packing or * unpacking. The address might not be valid for reading if the bitmap * was created with new_from_buffer but it will however be good to * pass to glTexImage2D for example. The access should be READ for * unpacking and WRITE for packing. It can not be both * * TODO: split this bind/unbind functions out into a GL specific file */ uint8_t * _cogl_bitmap_gl_bind (CoglBitmap *bitmap, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error); void _cogl_bitmap_gl_unbind (CoglBitmap *bitmap); CoglContext * _cogl_bitmap_get_context (CoglBitmap *bitmap); #endif /* __COGL_BITMAP_H */ muffin-5.2.1/cogl/cogl/cogl-frame-info.h0000664000175000017500000001064014211404421020123 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Owen Taylor */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_FRAME_INFO_H #define __COGL_FRAME_INFO_H #include #include #include #include G_BEGIN_DECLS typedef struct _CoglFrameInfo CoglFrameInfo; #define COGL_FRAME_INFO(X) ((CoglFrameInfo *)(X)) /** * cogl_frame_info_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_frame_info_get_gtype (void); /** * cogl_is_frame_info: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglFrameInfo. * * Return value: %TRUE if the object references a #CoglFrameInfo * and %FALSE otherwise. * Since: 2.0 * Stability: unstable */ CoglBool cogl_is_frame_info (void *object); /** * cogl_frame_info_get_frame_counter: * @info: a #CoglFrameInfo object * * Gets the frame counter for the #CoglOnscreen that corresponds * to this frame. * * Return value: The frame counter value * Since: 1.14 * Stability: unstable */ int64_t cogl_frame_info_get_frame_counter (CoglFrameInfo *info); /** * cogl_frame_info_get_presentation_time: * @info: a #CoglFrameInfo object * * Gets the presentation time for the frame. This is the time at which * the frame became visible to the user. * * The presentation time measured in nanoseconds is based on a * monotonic time source. The time source is not necessarily * correlated with system/wall clock time and may represent the time * elapsed since some undefined system event such as when the system * last booted. * * Linux kernel version less that 3.8 can result in * non-monotonic timestamps being reported when using a drm based * OpenGL driver. Also some buggy Mesa drivers up to 9.0.1 may also * incorrectly report non-monotonic timestamps. * * Return value: the presentation time for the frame * Since: 1.14 * Stability: unstable */ int64_t cogl_frame_info_get_presentation_time (CoglFrameInfo *info); /** * cogl_frame_info_get_refresh_rate: * @info: a #CoglFrameInfo object * * Gets the refresh rate in Hertz for the output that the frame was on * at the time the frame was presented. * * Some platforms can't associate a #CoglOutput with a * #CoglFrameInfo object but are able to report a refresh rate via * this api. Therefore if you need this information then this api is * more reliable than using cogl_frame_info_get_output() followed by * cogl_output_get_refresh_rate(). * * Return value: the refresh rate in Hertz * Since: 1.14 * Stability: unstable */ float cogl_frame_info_get_refresh_rate (CoglFrameInfo *info); /** * cogl_frame_info_get_output: * @info: a #CoglFrameInfo object * * Gets the #CoglOutput that the swapped frame was presented to. * * Return value: (transfer none): The #CoglOutput that the frame was * presented to, or %NULL if this could not be determined. * Since: 1.14 * Stability: unstable */ CoglOutput * cogl_frame_info_get_output (CoglFrameInfo *info); /** * cogl_frame_info_get_global_frame_counter: (skip) */ int64_t cogl_frame_info_get_global_frame_counter (CoglFrameInfo *info); G_END_DECLS #endif /* __COGL_FRAME_INFO_H */ muffin-5.2.1/cogl/cogl/cogl-pipeline-debug.c0000664000175000017500000002204314211404421020764 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-layer-private.h" #include "cogl-node-private.h" #include typedef struct { int parent_id; int *node_id_ptr; GString *graph; int indent; } PrintDebugState; static CoglBool dump_layer_cb (CoglNode *node, void *user_data) { CoglPipelineLayer *layer = COGL_PIPELINE_LAYER (node); PrintDebugState *state = user_data; int layer_id = *state->node_id_ptr; PrintDebugState state_out; GString *changes_label; CoglBool changes = FALSE; if (state->parent_id >= 0) g_string_append_printf (state->graph, "%*slayer%p -> layer%p;\n", state->indent, "", layer->_parent.parent, layer); g_string_append_printf (state->graph, "%*slayer%p [label=\"layer=0x%p\\n" "ref count=%d\" " "color=\"blue\"];\n", state->indent, "", layer, layer, COGL_OBJECT (layer)->ref_count); changes_label = g_string_new (""); g_string_append_printf (changes_label, "%*slayer%p -> layer_state%d [weight=100];\n" "%*slayer_state%d [shape=box label=\"", state->indent, "", layer, layer_id, state->indent, "", layer_id); if (layer->differences & COGL_PIPELINE_LAYER_STATE_UNIT) { changes = TRUE; g_string_append_printf (changes_label, "\\lunit=%u\\n", layer->unit_index); } if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA) { changes = TRUE; g_string_append_printf (changes_label, "\\ltexture=%p\\n", layer->texture); } if (changes) { g_string_append_printf (changes_label, "\"];\n"); g_string_append (state->graph, changes_label->str); g_string_free (changes_label, TRUE); } state_out.parent_id = layer_id; state_out.node_id_ptr = state->node_id_ptr; (*state_out.node_id_ptr)++; state_out.graph = state->graph; state_out.indent = state->indent + 2; _cogl_pipeline_node_foreach_child (COGL_NODE (layer), dump_layer_cb, &state_out); return TRUE; } static CoglBool dump_layer_ref_cb (CoglPipelineLayer *layer, void *data) { PrintDebugState *state = data; int pipeline_id = *state->node_id_ptr; g_string_append_printf (state->graph, "%*spipeline_state%d -> layer%p;\n", state->indent, "", pipeline_id, layer); return TRUE; } static CoglBool dump_pipeline_cb (CoglNode *node, void *user_data) { CoglPipeline *pipeline = COGL_PIPELINE (node); PrintDebugState *state = user_data; int pipeline_id = *state->node_id_ptr; PrintDebugState state_out; GString *changes_label; CoglBool changes = FALSE; CoglBool layers = FALSE; if (state->parent_id >= 0) g_string_append_printf (state->graph, "%*spipeline%d -> pipeline%d;\n", state->indent, "", state->parent_id, pipeline_id); g_string_append_printf (state->graph, "%*spipeline%d [label=\"pipeline=0x%p\\n" "ref count=%d\\n" "breadcrumb=\\\"%s\\\"\" color=\"red\"];\n", state->indent, "", pipeline_id, pipeline, COGL_OBJECT (pipeline)->ref_count, pipeline->has_static_breadcrumb ? #ifdef COGL_DEBUG_ENABLED pipeline->static_breadcrumb : "NULL" #else "NULL" #endif ); changes_label = g_string_new (""); g_string_append_printf (changes_label, "%*spipeline%d -> pipeline_state%d [weight=100];\n" "%*spipeline_state%d [shape=box label=\"", state->indent, "", pipeline_id, pipeline_id, state->indent, "", pipeline_id); if (pipeline->differences & COGL_PIPELINE_STATE_COLOR) { changes = TRUE; g_string_append_printf (changes_label, "\\lcolor=0x%02X%02X%02X%02X\\n", cogl_color_get_red_byte (&pipeline->color), cogl_color_get_green_byte (&pipeline->color), cogl_color_get_blue_byte (&pipeline->color), cogl_color_get_alpha_byte (&pipeline->color)); } if (pipeline->differences & COGL_PIPELINE_STATE_BLEND) { const char *blend_enable_name; changes = TRUE; switch (pipeline->blend_enable) { case COGL_PIPELINE_BLEND_ENABLE_AUTOMATIC: blend_enable_name = "AUTO"; break; case COGL_PIPELINE_BLEND_ENABLE_ENABLED: blend_enable_name = "ENABLED"; break; case COGL_PIPELINE_BLEND_ENABLE_DISABLED: blend_enable_name = "DISABLED"; break; default: blend_enable_name = "UNKNOWN"; } g_string_append_printf (changes_label, "\\lblend=%s\\n", blend_enable_name); } if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS) { changes = TRUE; layers = TRUE; g_string_append_printf (changes_label, "\\ln_layers=%d\\n", pipeline->n_layers); } if (changes) { g_string_append_printf (changes_label, "\"];\n"); g_string_append (state->graph, changes_label->str); g_string_free (changes_label, TRUE); } if (layers) { g_list_foreach (pipeline->layer_differences, (GFunc)dump_layer_ref_cb, state); } state_out.parent_id = pipeline_id; state_out.node_id_ptr = state->node_id_ptr; (*state_out.node_id_ptr)++; state_out.graph = state->graph; state_out.indent = state->indent + 2; _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline), dump_pipeline_cb, &state_out); return TRUE; } /* This function is just here to be called from GDB so we don't really want to put a declaration in a header and we just add it here to avoid a warning */ void _cogl_debug_dump_pipelines_dot_file (const char *filename); void _cogl_debug_dump_pipelines_dot_file (const char *filename) { GString *graph; PrintDebugState layer_state; PrintDebugState pipeline_state; int layer_id = 0; int pipeline_id = 0; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!ctx->default_pipeline) return; graph = g_string_new (""); g_string_append_printf (graph, "digraph {\n"); layer_state.graph = graph; layer_state.parent_id = -1; layer_state.node_id_ptr = &layer_id; layer_state.indent = 0; dump_layer_cb ((CoglNode *)ctx->default_layer_0, &layer_state); pipeline_state.graph = graph; pipeline_state.parent_id = -1; pipeline_state.node_id_ptr = &pipeline_id; pipeline_state.indent = 0; dump_pipeline_cb ((CoglNode *)ctx->default_pipeline, &pipeline_state); g_string_append_printf (graph, "}\n"); if (filename) g_file_set_contents (filename, graph->str, -1, NULL); else g_print ("%s", graph->str); g_string_free (graph, TRUE); } muffin-5.2.1/cogl/cogl/cogl-clip-stack.h0000664000175000017500000001620614211404421020136 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_CLIP_STACK_H #define __COGL_CLIP_STACK_H #include "cogl-matrix.h" #include "cogl-primitive.h" #include "cogl-framebuffer.h" #include "cogl-matrix-stack.h" /* The clip stack works like a GSList where only a pointer to the top of the stack is stored. The empty clip stack is represented simply by the NULL pointer. When an entry is added to or removed from the stack the new top of the stack is returned. When an entry is pushed a new clip stack entry is created which effectively takes ownership of the reference on the old entry. Therefore unrefing the top entry effectively loses ownership of all entries in the stack */ typedef struct _CoglClipStack CoglClipStack; typedef struct _CoglClipStackRect CoglClipStackRect; typedef struct _CoglClipStackWindowRect CoglClipStackWindowRect; typedef struct _CoglClipStackPrimitive CoglClipStackPrimitive; typedef enum { COGL_CLIP_STACK_RECT, COGL_CLIP_STACK_WINDOW_RECT, COGL_CLIP_STACK_PRIMITIVE } CoglClipStackType; /* A clip stack consists a list of entries. Each entry has a reference * count and a link to its parent node. The child takes a reference on * the parent and the CoglClipStack holds a reference to the top of * the stack. There are no links back from the parent to the * children. This allows stacks that have common ancestry to share the * entries. * * For example, the following sequence of operations would generate * the tree below: * * CoglClipStack *stack_a = NULL; * stack_a = _cogl_clip_stack_push_rectangle (stack_a, ...); * stack_a = _cogl_clip_stack_push_rectangle (stack_a, ...); * stack_a = _cogl_clip_stack_push_primitive (stack_a, ...); * CoglClipStack *stack_b = NULL; * stack_b = cogl_clip_stack_push_window_rectangle (stack_b, ...); * * stack_a * \ holds a ref to * +-----------+ * | prim node | * |ref count 1| * +-----------+ * \ * +-----------+ +-----------+ * both tops hold | rect node | | rect node | * a ref to the |ref count 2|--|ref count 1| * same rect node +-----------+ +-----------+ * / * +-----------+ * | win. rect | * |ref count 1| * +-----------+ * / holds a ref to * stack_b * */ struct _CoglClipStack { /* This will be null if there is no parent. If it is not null then this node must be holding a reference to the parent */ CoglClipStack *parent; CoglClipStackType type; /* All clip entries have a window-space bounding box which we can use to calculate a scissor. The scissor limits the clip so that we don't need to do a full stencil clear if the stencil buffer is needed. This is stored in Cogl's coordinate space (ie, 0,0 is the top left) */ int bounds_x0; int bounds_y0; int bounds_x1; int bounds_y1; unsigned int ref_count; }; struct _CoglClipStackRect { CoglClipStack _parent_data; /* The rectangle for this clip */ float x0; float y0; float x1; float y1; /* The matrix that was current when the clip was set */ CoglMatrixEntry *matrix_entry; /* If this is true then the clip for this rectangle is entirely described by the scissor bounds. This implies that the rectangle is screen aligned and we don't need to use the stencil buffer to set the clip. We keep the entry as a rect entry rather than a window rect entry so that it will be easier to detect if the modelview matrix is that same as when a rectangle is added to the journal. In that case we can use the original clip coordinates and modify the rectangle instead. */ CoglBool can_be_scissor; }; struct _CoglClipStackWindowRect { CoglClipStack _parent_data; /* The window rect clip doesn't need any specific data because it just adds to the scissor clip */ }; struct _CoglClipStackPrimitive { CoglClipStack _parent_data; /* The matrix that was current when the clip was set */ CoglMatrixEntry *matrix_entry; CoglPrimitive *primitive; float bounds_x1; float bounds_y1; float bounds_x2; float bounds_y2; }; CoglClipStack * _cogl_clip_stack_push_window_rectangle (CoglClipStack *stack, int x_offset, int y_offset, int width, int height); CoglClipStack * _cogl_clip_stack_push_rectangle (CoglClipStack *stack, float x_1, float y_1, float x_2, float y_2, CoglMatrixEntry *modelview_entry, CoglMatrixEntry *projection_entry, const float *viewport); CoglClipStack * _cogl_clip_stack_push_primitive (CoglClipStack *stack, CoglPrimitive *primitive, float bounds_x1, float bounds_y1, float bounds_x2, float bounds_y2, CoglMatrixEntry *modelview_entry, CoglMatrixEntry *projection_entry, const float *viewport); CoglClipStack * _cogl_clip_stack_pop (CoglClipStack *stack); void _cogl_clip_stack_get_bounds (CoglClipStack *stack, int *scissor_x0, int *scissor_y0, int *scissor_x1, int *scissor_y1); void _cogl_clip_stack_flush (CoglClipStack *stack, CoglFramebuffer *framebuffer); CoglClipStack * _cogl_clip_stack_ref (CoglClipStack *stack); void _cogl_clip_stack_unref (CoglClipStack *stack); #endif /* __COGL_CLIP_STACK_H */ muffin-5.2.1/cogl/cogl/cogl-pipeline-cache.c0000664000175000017500000001660014211404421020743 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011, 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Neil Roberts * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-context-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-cache.h" #include "cogl-pipeline-hash-table.h" struct _CoglPipelineCache { CoglPipelineHashTable fragment_hash; CoglPipelineHashTable vertex_hash; CoglPipelineHashTable combined_hash; }; CoglPipelineCache * _cogl_pipeline_cache_new (void) { CoglPipelineCache *cache = g_new (CoglPipelineCache, 1); unsigned long vertex_state; unsigned long layer_vertex_state; unsigned int fragment_state; unsigned int layer_fragment_state; _COGL_GET_CONTEXT (ctx, 0); vertex_state = _cogl_pipeline_get_state_for_vertex_codegen (ctx); layer_vertex_state = COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN; fragment_state = _cogl_pipeline_get_state_for_fragment_codegen (ctx); layer_fragment_state = _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx); _cogl_pipeline_hash_table_init (&cache->vertex_hash, vertex_state, layer_vertex_state, "vertex shaders"); _cogl_pipeline_hash_table_init (&cache->fragment_hash, fragment_state, layer_fragment_state, "fragment shaders"); _cogl_pipeline_hash_table_init (&cache->combined_hash, vertex_state | fragment_state, layer_vertex_state | layer_fragment_state, "programs"); return cache; } void _cogl_pipeline_cache_free (CoglPipelineCache *cache) { _cogl_pipeline_hash_table_destroy (&cache->fragment_hash); _cogl_pipeline_hash_table_destroy (&cache->vertex_hash); _cogl_pipeline_hash_table_destroy (&cache->combined_hash); free (cache); } CoglPipelineCacheEntry * _cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache, CoglPipeline *key_pipeline) { return _cogl_pipeline_hash_table_get (&cache->fragment_hash, key_pipeline); } CoglPipelineCacheEntry * _cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache, CoglPipeline *key_pipeline) { return _cogl_pipeline_hash_table_get (&cache->vertex_hash, key_pipeline); } CoglPipelineCacheEntry * _cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache, CoglPipeline *key_pipeline) { return _cogl_pipeline_hash_table_get (&cache->combined_hash, key_pipeline); } #ifdef ENABLE_UNIT_TESTS static void create_pipelines (CoglPipeline **pipelines, int n_pipelines) { int i; for (i = 0; i < n_pipelines; i++) { char *source = g_strdup_printf (" cogl_color_out = " "vec4 (%f, 0.0, 0.0, 1.0);\n", i / 255.0f); CoglSnippet *snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, /* declarations */ source); free (source); pipelines[i] = cogl_pipeline_new (test_ctx); cogl_pipeline_add_snippet (pipelines[i], snippet); cogl_object_unref (snippet); } /* Test that drawing with them works. This should create the entries * in the cache */ for (i = 0; i < n_pipelines; i++) { cogl_framebuffer_draw_rectangle (test_fb, pipelines[i], i, 0, i + 1, 1); test_utils_check_pixel_rgb (test_fb, i, 0, i, 0, 0); } } UNIT_TEST (check_pipeline_pruning, TEST_REQUIREMENT_GLSL, /* requirements */ 0 /* no failure cases */) { CoglPipeline *pipelines[18]; int fb_width, fb_height; CoglPipelineHashTable *fragment_hash = &test_ctx->pipeline_cache->fragment_hash; CoglPipelineHashTable *combined_hash = &test_ctx->pipeline_cache->combined_hash; int i; fb_width = cogl_framebuffer_get_width (test_fb); fb_height = cogl_framebuffer_get_height (test_fb); cogl_framebuffer_orthographic (test_fb, 0, 0, fb_width, fb_height, -1, 100); /* Create 18 unique pipelines. This should end up being more than * the initial expected minimum size so it will trigger the garbage * collection. However all of the pipelines will be in use so they * won't be collected */ create_pipelines (pipelines, 18); /* These pipelines should all have unique entries in the cache. We * should have run the garbage collection once and at that point the * expected minimum size would have been 17 */ g_assert_cmpint (g_hash_table_size (fragment_hash->table), ==, 18); g_assert_cmpint (g_hash_table_size (combined_hash->table), ==, 18); g_assert_cmpint (fragment_hash->expected_min_size, ==, 17); g_assert_cmpint (combined_hash->expected_min_size, ==, 17); /* Destroy the original pipelines and create some new ones. This * should run the garbage collector again but this time the * pipelines won't be in use so it should free some of them */ for (i = 0; i < 18; i++) cogl_object_unref (pipelines[i]); create_pipelines (pipelines, 18); /* The garbage collection should have freed half of the original 18 * pipelines which means there should now be 18*1.5 = 27 */ g_assert_cmpint (g_hash_table_size (fragment_hash->table), ==, 27); g_assert_cmpint (g_hash_table_size (combined_hash->table), ==, 27); /* The 35th pipeline would have caused the garbage collection. At * that point there would be 35-18=17 used unique pipelines. */ g_assert_cmpint (fragment_hash->expected_min_size, ==, 17); g_assert_cmpint (combined_hash->expected_min_size, ==, 17); for (i = 0; i < 18; i++) cogl_object_unref (pipelines[i]); } #endif /* ENABLE_UNIT_TESTS */ muffin-5.2.1/cogl/cogl/cogl-gles2-types.h0000664000175000017500000004304214211404421020260 0ustar jpeisachjpeisach#ifndef __COGL_GLES2_TYPES_H_ #define __COGL_GLES2_TYPES_H_ /* $Revision: 16803 $ on $Date:: 2012-02-02 09:49:18 -0800 #$ */ #include #ifdef __cplusplus extern "C" { #endif /* * This document is licensed under the SGI Free Software B License Version * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . */ /*------------------------------------------------------------------------- * Data type definitions *-----------------------------------------------------------------------*/ typedef void GLvoid; typedef char GLchar; typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef int8_t GLbyte; typedef short GLshort; typedef int GLint; typedef int GLsizei; typedef uint8_t GLubyte; typedef unsigned short GLushort; typedef unsigned int GLuint; typedef float GLfloat; typedef float GLclampf; typedef int32_t GLfixed; /* GL types for handling large vertex buffer objects */ typedef signed long int GLintptr; typedef long GLsizeiptr; /* OpenGL ES core versions */ #define GL_ES_VERSION_2_0 1 /* ClearBufferMask */ #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 /* Boolean */ #define GL_FALSE 0 #define GL_TRUE 1 /* BeginMode */ #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 /* AlphaFunction (not supported in ES20) */ /* GL_NEVER */ /* GL_LESS */ /* GL_EQUAL */ /* GL_LEQUAL */ /* GL_GREATER */ /* GL_NOTEQUAL */ /* GL_GEQUAL */ /* GL_ALWAYS */ /* BlendingFactorDest */ #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 /* BlendingFactorSrc */ /* GL_ZERO */ /* GL_ONE */ #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 /* GL_SRC_ALPHA */ /* GL_ONE_MINUS_SRC_ALPHA */ /* GL_DST_ALPHA */ /* GL_ONE_MINUS_DST_ALPHA */ /* BlendEquationSeparate */ #define GL_FUNC_ADD 0x8006 #define GL_BLEND_EQUATION 0x8009 #define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */ #define GL_BLEND_EQUATION_ALPHA 0x883D /* BlendSubtract */ #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B /* Separate Blend Functions */ #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 /* Buffer Objects */ #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_STREAM_DRAW 0x88E0 #define GL_STATIC_DRAW 0x88E4 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 /* CullFaceMode */ #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_FRONT_AND_BACK 0x0408 /* DepthFunction */ /* GL_NEVER */ /* GL_LESS */ /* GL_EQUAL */ /* GL_LEQUAL */ /* GL_GREATER */ /* GL_NOTEQUAL */ /* GL_GEQUAL */ /* GL_ALWAYS */ /* EnableCap */ #define GL_TEXTURE_2D 0x0DE1 #define GL_CULL_FACE 0x0B44 #define GL_BLEND 0x0BE2 #define GL_DITHER 0x0BD0 #define GL_STENCIL_TEST 0x0B90 #define GL_DEPTH_TEST 0x0B71 #define GL_SCISSOR_TEST 0x0C11 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_TEXTURE_EXTERNAL_OES 0x8D65 /* ErrorCode */ #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_OUT_OF_MEMORY 0x0505 /* FrontFaceDirection */ #define GL_CW 0x0900 #define GL_CCW 0x0901 /* GetPName */ #define GL_LINE_WIDTH 0x0B21 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_CULL_FACE_MODE 0x0B45 #define GL_FRONT_FACE 0x0B46 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_FUNC 0x0B74 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_VIEWPORT 0x0BA2 #define GL_SCISSOR_BOX 0x0C10 /* GL_SCISSOR_TEST */ #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_SUBPIXEL_BITS 0x0D50 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 #define GL_POLYGON_OFFSET_UNITS 0x2A00 /* GL_POLYGON_OFFSET_FILL */ #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB /* GetTextureParameter */ /* GL_TEXTURE_MAG_FILTER */ /* GL_TEXTURE_MIN_FILTER */ /* GL_TEXTURE_WRAP_S */ /* GL_TEXTURE_WRAP_T */ #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 /* HintMode */ #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 /* HintTarget */ #define GL_GENERATE_MIPMAP_HINT 0x8192 /* DataType */ #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 #define GL_FIXED 0x140C /* PixelFormat */ #define GL_DEPTH_COMPONENT 0x1902 #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A /* PixelType */ /* GL_UNSIGNED_BYTE */ #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 /* Shaders */ #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_SHADER_TYPE 0x8B4F #define GL_DELETE_STATUS 0x8B80 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D /* StencilFunction */ #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 /* StencilOp */ /* GL_ZERO */ #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 #define GL_INVERT 0x150A #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 /* StringName */ #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 /* TextureMagFilter */ #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 /* TextureMinFilter */ /* GL_NEAREST */ /* GL_LINEAR */ #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 /* TextureParameterName */ #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 /* TextureTarget */ /* GL_TEXTURE_2D */ #define GL_TEXTURE 0x1702 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C /* TextureUnit */ #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 /* TextureWrapMode */ #define GL_REPEAT 0x2901 #define GL_CLAMP_TO_EDGE 0x812F #define GL_MIRRORED_REPEAT 0x8370 /* Uniform Types */ #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_CUBE 0x8B60 /* Vertex Arrays */ #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F /* Read Format */ #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B /* Shader Source */ #define GL_COMPILE_STATUS 0x8B81 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_SHADER_COMPILER 0x8DFA /* Shader Binary */ #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 /* Shader Precision-Specified Types */ #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 /* Framebuffer Object. */ #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RGBA4 0x8056 #define GL_RGB5_A1 0x8057 #define GL_RGB565 0x8D62 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_STENCIL_INDEX8 0x8D48 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_NONE 0 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #ifdef __cplusplus } #endif #endif /* __COGL_GLES2_TYPES_H_ */ muffin-5.2.1/cogl/cogl/cogl-driver.h0000664000175000017500000002336614211404421017404 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_DRIVER_H #define __COGL_DRIVER_H #include "cogl-context.h" #include "cogl-offscreen.h" #include "cogl-framebuffer-private.h" #include "cogl-attribute-private.h" typedef struct _CoglDriverVtable CoglDriverVtable; struct _CoglDriverVtable { /* TODO: factor this out since this is OpenGL specific and * so can be ignored by non-OpenGL drivers. */ CoglBool (* pixel_format_from_gl_internal) (CoglContext *context, GLenum gl_int_format, CoglPixelFormat *out_format); /* TODO: factor this out since this is OpenGL specific and * so can be ignored by non-OpenGL drivers. */ CoglPixelFormat (* pixel_format_to_gl) (CoglContext *context, CoglPixelFormat format, GLenum *out_glintformat, GLenum *out_glformat, GLenum *out_gltype); CoglPixelFormat (* pixel_format_to_gl_with_target) (CoglContext *context, CoglPixelFormat format, CoglPixelFormat target_format, GLenum *out_glintformat, GLenum *out_glformat, GLenum *out_gltype); CoglBool (* update_features) (CoglContext *context, CoglError **error); CoglBool (* offscreen_allocate) (CoglOffscreen *offscreen, CoglError **error); void (* offscreen_free) (CoglOffscreen *offscreen); void (* framebuffer_flush_state) (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer, CoglFramebufferState state); void (* framebuffer_clear) (CoglFramebuffer *framebuffer, unsigned long buffers, float red, float green, float blue, float alpha); void (* framebuffer_query_bits) (CoglFramebuffer *framebuffer, CoglFramebufferBits *bits); void (* framebuffer_finish) (CoglFramebuffer *framebuffer); void (* framebuffer_discard_buffers) (CoglFramebuffer *framebuffer, unsigned long buffers); void (* framebuffer_draw_attributes) (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); void (* framebuffer_draw_indexed_attributes) (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglVerticesMode mode, int first_vertex, int n_vertices, CoglIndices *indices, CoglAttribute **attributes, int n_attributes, CoglDrawFlags flags); CoglBool (* framebuffer_read_pixels_into_bitmap) (CoglFramebuffer *framebuffer, int x, int y, CoglReadPixelsFlags source, CoglBitmap *bitmap, CoglError **error); /* Destroys any driver specific resources associated with the given * 2D texture. */ void (* texture_2d_free) (CoglTexture2D *tex_2d); /* Returns TRUE if the driver can support creating a 2D texture with * the given geometry and specified internal format. */ CoglBool (* texture_2d_can_create) (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format); /* Initializes driver private state before allocating any specific * storage for a 2D texture, where base texture and texture 2D * members will already be initialized before passing control to * the driver. */ void (* texture_2d_init) (CoglTexture2D *tex_2d); /* Allocates (uninitialized) storage for the given texture according * to the configured size and format of the texture */ CoglBool (* texture_2d_allocate) (CoglTexture *tex, CoglError **error); /* Initialize the specified region of storage of the given texture * with the contents of the specified framebuffer region */ void (* texture_2d_copy_from_framebuffer) (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglFramebuffer *src_fb, int dst_x, int dst_y, int level); /* If the given texture has a corresponding OpenGL texture handle * then return that. * * This is optional */ unsigned int (* texture_2d_get_gl_handle) (CoglTexture2D *tex_2d); /* Update all mipmap levels > 0 */ void (* texture_2d_generate_mipmap) (CoglTexture2D *tex_2d); /* Initialize the specified region of storage of the given texture * with the contents of the specified bitmap region * * Since this may need to create the underlying storage first * it may throw a NO_MEMORY error. */ CoglBool (* texture_2d_copy_from_bitmap) (CoglTexture2D *tex_2d, int src_x, int src_y, int width, int height, CoglBitmap *bitmap, int dst_x, int dst_y, int level, CoglError **error); /* Reads back the full contents of the given texture and write it to * @data in the given @format and with the given @rowstride. * * This is optional */ void (* texture_2d_get_data) (CoglTexture2D *tex_2d, CoglPixelFormat format, int rowstride, uint8_t *data); /* Prepares for drawing by flushing the journal, framebuffer state, * pipeline state and attribute state. */ void (* flush_attributes_state) (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglFlushLayerState *layer_state, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes); /* Flushes the clip stack to the GPU using a combination of the * stencil buffer, scissor and clip plane state. */ void (* clip_stack_flush) (CoglClipStack *stack, CoglFramebuffer *framebuffer); /* Enables the driver to create some meta data to represent a buffer * but with no corresponding storage allocated yet. */ void (* buffer_create) (CoglBuffer *buffer); void (* buffer_destroy) (CoglBuffer *buffer); /* Maps a buffer into the CPU */ void * (* buffer_map_range) (CoglBuffer *buffer, size_t offset, size_t size, CoglBufferAccess access, CoglBufferMapHint hints, CoglError **error); /* Unmaps a buffer */ void (* buffer_unmap) (CoglBuffer *buffer); /* Uploads data to the buffer without needing to map it necessarily */ CoglBool (* buffer_set_data) (CoglBuffer *buffer, unsigned int offset, const void *data, unsigned int size, CoglError **error); }; #define COGL_DRIVER_ERROR (_cogl_driver_error_quark ()) typedef enum { /*< prefix=COGL_DRIVER_ERROR >*/ COGL_DRIVER_ERROR_UNKNOWN_VERSION, COGL_DRIVER_ERROR_INVALID_VERSION, COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND, COGL_DRIVER_ERROR_FAILED_TO_LOAD_LIBRARY } CoglDriverError; uint32_t _cogl_driver_error_quark (void); #endif /* __COGL_DRIVER_H */ muffin-5.2.1/cogl/cogl/cogl-atlas.c0000664000175000017500000005654014211404421017210 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-atlas.h" #include "cogl-rectangle-map.h" #include "cogl-context-private.h" #include "cogl-texture-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d-sliced.h" #include "cogl-texture-driver.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-debug.h" #include "cogl-framebuffer-private.h" #include "cogl-blit.h" #include "cogl-private.h" #include static void _cogl_atlas_free (CoglAtlas *atlas); COGL_OBJECT_INTERNAL_DEFINE (Atlas, atlas); CoglAtlas * _cogl_atlas_new (CoglPixelFormat texture_format, CoglAtlasFlags flags, CoglAtlasUpdatePositionCallback update_position_cb) { CoglAtlas *atlas = g_new (CoglAtlas, 1); atlas->update_position_cb = update_position_cb; atlas->map = NULL; atlas->texture = NULL; atlas->flags = flags; atlas->texture_format = texture_format; g_hook_list_init (&atlas->pre_reorganize_callbacks, sizeof (GHook)); g_hook_list_init (&atlas->post_reorganize_callbacks, sizeof (GHook)); return _cogl_atlas_object_new (atlas); } static void _cogl_atlas_free (CoglAtlas *atlas) { COGL_NOTE (ATLAS, "%p: Atlas destroyed", atlas); if (atlas->texture) cogl_object_unref (atlas->texture); if (atlas->map) _cogl_rectangle_map_free (atlas->map); g_hook_list_clear (&atlas->pre_reorganize_callbacks); g_hook_list_clear (&atlas->post_reorganize_callbacks); free (atlas); } typedef struct _CoglAtlasRepositionData { /* The current user data for this texture */ void *user_data; /* The old and new positions of the texture */ CoglRectangleMapEntry old_position; CoglRectangleMapEntry new_position; } CoglAtlasRepositionData; static void _cogl_atlas_migrate (CoglAtlas *atlas, unsigned int n_textures, CoglAtlasRepositionData *textures, CoglTexture *old_texture, CoglTexture *new_texture, void *skip_user_data) { unsigned int i; CoglBlitData blit_data; /* If the 'disable migrate' flag is set then we won't actually copy the textures to their new location. Instead we'll just invoke the callback to update the position */ if ((atlas->flags & COGL_ATLAS_DISABLE_MIGRATION)) for (i = 0; i < n_textures; i++) /* Update the texture position */ atlas->update_position_cb (textures[i].user_data, new_texture, &textures[i].new_position); else { _cogl_blit_begin (&blit_data, new_texture, old_texture); for (i = 0; i < n_textures; i++) { /* Skip the texture that is being added because it doesn't contain any data yet */ if (textures[i].user_data != skip_user_data) _cogl_blit (&blit_data, textures[i].old_position.x, textures[i].old_position.y, textures[i].new_position.x, textures[i].new_position.y, textures[i].new_position.width, textures[i].new_position.height); /* Update the texture position */ atlas->update_position_cb (textures[i].user_data, new_texture, &textures[i].new_position); } _cogl_blit_end (&blit_data); } } typedef struct _CoglAtlasGetRectanglesData { CoglAtlasRepositionData *textures; /* Number of textures found so far */ unsigned int n_textures; } CoglAtlasGetRectanglesData; static void _cogl_atlas_get_rectangles_cb (const CoglRectangleMapEntry *rectangle, void *rect_data, void *user_data) { CoglAtlasGetRectanglesData *data = user_data; data->textures[data->n_textures].old_position = *rectangle; data->textures[data->n_textures++].user_data = rect_data; } static void _cogl_atlas_get_next_size (unsigned int *map_width, unsigned int *map_height) { /* Double the size of the texture by increasing whichever dimension is smaller */ if (*map_width < *map_height) *map_width <<= 1; else *map_height <<= 1; } static void _cogl_atlas_get_initial_size (CoglPixelFormat format, unsigned int *map_width, unsigned int *map_height) { unsigned int size; GLenum gl_intformat; GLenum gl_format; GLenum gl_type; _COGL_GET_CONTEXT (ctx, NO_RETVAL); ctx->driver_vtable->pixel_format_to_gl (ctx, format, &gl_intformat, &gl_format, &gl_type); /* At least on Intel hardware, the texture size will be rounded up to at least 1MB so we might as well try to aim for that as an initial minimum size. If the format is only 1 byte per pixel we can use 1024x1024, otherwise we'll assume it will take 4 bytes per pixel and use 512x512. */ if (_cogl_pixel_format_get_bytes_per_pixel (format) == 1) size = 1024; else size = 512; /* Some platforms might not support this large size so we'll decrease the size until it can */ while (size > 1 && !ctx->texture_driver->size_supported (ctx, GL_TEXTURE_2D, gl_intformat, gl_format, gl_type, size, size)) size >>= 1; *map_width = size; *map_height = size; } static CoglRectangleMap * _cogl_atlas_create_map (CoglPixelFormat format, unsigned int map_width, unsigned int map_height, unsigned int n_textures, CoglAtlasRepositionData *textures) { GLenum gl_intformat; GLenum gl_format; GLenum gl_type; _COGL_GET_CONTEXT (ctx, NULL); ctx->driver_vtable->pixel_format_to_gl (ctx, format, &gl_intformat, &gl_format, &gl_type); /* Keep trying increasingly larger atlases until we can fit all of the textures */ while (ctx->texture_driver->size_supported (ctx, GL_TEXTURE_2D, gl_intformat, gl_format, gl_type, map_width, map_height)) { CoglRectangleMap *new_atlas = _cogl_rectangle_map_new (map_width, map_height, NULL); unsigned int i; COGL_NOTE (ATLAS, "Trying to resize the atlas to %ux%u", map_width, map_height); /* Add all of the textures and keep track of the new position */ for (i = 0; i < n_textures; i++) if (!_cogl_rectangle_map_add (new_atlas, textures[i].old_position.width, textures[i].old_position.height, textures[i].user_data, &textures[i].new_position)) break; /* If the atlas can contain all of the textures then we have a winner */ if (i >= n_textures) return new_atlas; else COGL_NOTE (ATLAS, "Atlas size abandoned after trying " "%u out of %u textures", i, n_textures); _cogl_rectangle_map_free (new_atlas); _cogl_atlas_get_next_size (&map_width, &map_height); } /* If we get here then there's no atlas that can accommodate all of the rectangles */ return NULL; } static CoglTexture2D * _cogl_atlas_create_texture (CoglAtlas *atlas, int width, int height) { CoglTexture2D *tex; CoglError *ignore_error = NULL; _COGL_GET_CONTEXT (ctx, NULL); if ((atlas->flags & COGL_ATLAS_CLEAR_TEXTURE)) { uint8_t *clear_data; CoglBitmap *clear_bmp; int bpp = _cogl_pixel_format_get_bytes_per_pixel (atlas->texture_format); /* Create a buffer of zeroes to initially clear the texture */ clear_data = calloc (1, width * height * bpp); clear_bmp = cogl_bitmap_new_for_data (ctx, width, height, atlas->texture_format, width * bpp, clear_data); tex = cogl_texture_2d_new_from_bitmap (clear_bmp); _cogl_texture_set_internal_format (COGL_TEXTURE (tex), atlas->texture_format); if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error)) { cogl_error_free (ignore_error); cogl_object_unref (tex); tex = NULL; } cogl_object_unref (clear_bmp); free (clear_data); } else { tex = cogl_texture_2d_new_with_size (ctx, width, height); _cogl_texture_set_internal_format (COGL_TEXTURE (tex), atlas->texture_format); if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error)) { cogl_error_free (ignore_error); cogl_object_unref (tex); tex = NULL; } } return tex; } static int _cogl_atlas_compare_size_cb (const void *a, const void *b) { const CoglAtlasRepositionData *ta = a; const CoglAtlasRepositionData *tb = b; unsigned int a_size, b_size; a_size = ta->old_position.width * ta->old_position.height; b_size = tb->old_position.width * tb->old_position.height; return a_size < b_size ? 1 : a_size > b_size ? -1 : 0; } static void _cogl_atlas_notify_pre_reorganize (CoglAtlas *atlas) { g_hook_list_invoke (&atlas->pre_reorganize_callbacks, FALSE); } static void _cogl_atlas_notify_post_reorganize (CoglAtlas *atlas) { g_hook_list_invoke (&atlas->post_reorganize_callbacks, FALSE); } CoglBool _cogl_atlas_reserve_space (CoglAtlas *atlas, unsigned int width, unsigned int height, void *user_data) { CoglAtlasGetRectanglesData data; CoglRectangleMap *new_map; CoglTexture2D *new_tex; unsigned int map_width = 0, map_height = 0; CoglBool ret; CoglRectangleMapEntry new_position; /* Check if we can fit the rectangle into the existing map */ if (atlas->map && _cogl_rectangle_map_add (atlas->map, width, height, user_data, &new_position)) { COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste", atlas, _cogl_rectangle_map_get_width (atlas->map), _cogl_rectangle_map_get_height (atlas->map), _cogl_rectangle_map_get_n_rectangles (atlas->map), /* waste as a percentage */ _cogl_rectangle_map_get_remaining_space (atlas->map) * 100 / (_cogl_rectangle_map_get_width (atlas->map) * _cogl_rectangle_map_get_height (atlas->map))); atlas->update_position_cb (user_data, atlas->texture, &new_position); return TRUE; } /* If we make it here then we need to reorganize the atlas. First we'll notify any users of the atlas that this is going to happen so that for example in CoglAtlasTexture it can notify that the storage has changed and cause a flush */ _cogl_atlas_notify_pre_reorganize (atlas); /* Get an array of all the textures currently in the atlas. */ data.n_textures = 0; if (atlas->map == NULL) data.textures = malloc (sizeof (CoglAtlasRepositionData)); else { unsigned int n_rectangles = _cogl_rectangle_map_get_n_rectangles (atlas->map); data.textures = malloc (sizeof (CoglAtlasRepositionData) * (n_rectangles + 1)); _cogl_rectangle_map_foreach (atlas->map, _cogl_atlas_get_rectangles_cb, &data); } /* Add the new rectangle as a dummy texture so that it can be positioned with the rest */ data.textures[data.n_textures].old_position.x = 0; data.textures[data.n_textures].old_position.y = 0; data.textures[data.n_textures].old_position.width = width; data.textures[data.n_textures].old_position.height = height; data.textures[data.n_textures++].user_data = user_data; /* The atlasing algorithm works a lot better if the rectangles are added in decreasing order of size so we'll first sort the array */ qsort (data.textures, data.n_textures, sizeof (CoglAtlasRepositionData), _cogl_atlas_compare_size_cb); /* Try to create a new atlas that can contain all of the textures */ if (atlas->map) { map_width = _cogl_rectangle_map_get_width (atlas->map); map_height = _cogl_rectangle_map_get_height (atlas->map); /* If there is enough space in for the new rectangle in the existing atlas with at least 6% waste we'll start with the same size, otherwise we'll immediately double it */ if ((map_width * map_height - _cogl_rectangle_map_get_remaining_space (atlas->map) + width * height) * 53 / 50 > map_width * map_height) _cogl_atlas_get_next_size (&map_width, &map_height); } else _cogl_atlas_get_initial_size (atlas->texture_format, &map_width, &map_height); new_map = _cogl_atlas_create_map (atlas->texture_format, map_width, map_height, data.n_textures, data.textures); /* If we can't create a map with the texture then give up */ if (new_map == NULL) { COGL_NOTE (ATLAS, "%p: Could not fit texture in the atlas", atlas); ret = FALSE; } /* We need to migrate the existing textures into a new texture */ else if ((new_tex = _cogl_atlas_create_texture (atlas, _cogl_rectangle_map_get_width (new_map), _cogl_rectangle_map_get_height (new_map))) == NULL) { COGL_NOTE (ATLAS, "%p: Could not create a CoglTexture2D", atlas); _cogl_rectangle_map_free (new_map); ret = FALSE; } else { int waste; COGL_NOTE (ATLAS, "%p: Atlas %s with size %ix%i", atlas, atlas->map == NULL || _cogl_rectangle_map_get_width (atlas->map) != _cogl_rectangle_map_get_width (new_map) || _cogl_rectangle_map_get_height (atlas->map) != _cogl_rectangle_map_get_height (new_map) ? "resized" : "reorganized", _cogl_rectangle_map_get_width (new_map), _cogl_rectangle_map_get_height (new_map)); if (atlas->map) { /* Move all the textures to the right position in the new texture. This will also update the texture's rectangle */ _cogl_atlas_migrate (atlas, data.n_textures, data.textures, atlas->texture, COGL_TEXTURE (new_tex), user_data); _cogl_rectangle_map_free (atlas->map); cogl_object_unref (atlas->texture); } else /* We know there's only one texture so we can just directly update the rectangle from its new position */ atlas->update_position_cb (data.textures[0].user_data, COGL_TEXTURE (new_tex), &data.textures[0].new_position); atlas->map = new_map; atlas->texture = COGL_TEXTURE (new_tex); waste = (_cogl_rectangle_map_get_remaining_space (atlas->map) * 100 / (_cogl_rectangle_map_get_width (atlas->map) * _cogl_rectangle_map_get_height (atlas->map))); COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste", atlas, _cogl_rectangle_map_get_width (atlas->map), _cogl_rectangle_map_get_height (atlas->map), _cogl_rectangle_map_get_n_rectangles (atlas->map), waste); ret = TRUE; } free (data.textures); _cogl_atlas_notify_post_reorganize (atlas); return ret; } void _cogl_atlas_remove (CoglAtlas *atlas, const CoglRectangleMapEntry *rectangle) { _cogl_rectangle_map_remove (atlas->map, rectangle); COGL_NOTE (ATLAS, "%p: Removed rectangle sized %ix%i", atlas, rectangle->width, rectangle->height); COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste", atlas, _cogl_rectangle_map_get_width (atlas->map), _cogl_rectangle_map_get_height (atlas->map), _cogl_rectangle_map_get_n_rectangles (atlas->map), _cogl_rectangle_map_get_remaining_space (atlas->map) * 100 / (_cogl_rectangle_map_get_width (atlas->map) * _cogl_rectangle_map_get_height (atlas->map))); }; static CoglTexture * create_migration_texture (CoglContext *ctx, int width, int height, CoglPixelFormat internal_format) { CoglTexture *tex; CoglError *skip_error = NULL; if ((_cogl_util_is_pot (width) && _cogl_util_is_pot (height)) || (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP))) { /* First try creating a fast-path non-sliced texture */ tex = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height)); _cogl_texture_set_internal_format (tex, internal_format); /* TODO: instead of allocating storage here it would be better * if we had some api that let us just check that the size is * supported by the hardware so storage could be allocated * lazily when uploading data. */ if (!cogl_texture_allocate (tex, &skip_error)) { cogl_error_free (skip_error); cogl_object_unref (tex); tex = NULL; } } else tex = NULL; if (!tex) { CoglTexture2DSliced *tex_2ds = cogl_texture_2d_sliced_new_with_size (ctx, width, height, COGL_TEXTURE_MAX_WASTE); _cogl_texture_set_internal_format (COGL_TEXTURE (tex_2ds), internal_format); tex = COGL_TEXTURE (tex_2ds); } return tex; } CoglTexture * _cogl_atlas_copy_rectangle (CoglAtlas *atlas, int x, int y, int width, int height, CoglPixelFormat internal_format) { CoglTexture *tex; CoglBlitData blit_data; CoglError *ignore_error = NULL; _COGL_GET_CONTEXT (ctx, NULL); /* Create a new texture at the right size */ tex = create_migration_texture (ctx, width, height, internal_format); if (!cogl_texture_allocate (tex, &ignore_error)) { cogl_error_free (ignore_error); cogl_object_unref (tex); return NULL; } /* Blit the data out of the atlas to the new texture. If FBOs aren't available this will end up having to copy the entire atlas texture */ _cogl_blit_begin (&blit_data, tex, atlas->texture); _cogl_blit (&blit_data, x, y, 0, 0, width, height); _cogl_blit_end (&blit_data); return tex; } void _cogl_atlas_add_reorganize_callback (CoglAtlas *atlas, GHookFunc pre_callback, GHookFunc post_callback, void *user_data) { if (pre_callback) { GHook *hook = g_hook_alloc (&atlas->post_reorganize_callbacks); hook->func = pre_callback; hook->data = user_data; g_hook_prepend (&atlas->pre_reorganize_callbacks, hook); } if (post_callback) { GHook *hook = g_hook_alloc (&atlas->pre_reorganize_callbacks); hook->func = post_callback; hook->data = user_data; g_hook_prepend (&atlas->post_reorganize_callbacks, hook); } } void _cogl_atlas_remove_reorganize_callback (CoglAtlas *atlas, GHookFunc pre_callback, GHookFunc post_callback, void *user_data) { if (pre_callback) { GHook *hook = g_hook_find_func_data (&atlas->pre_reorganize_callbacks, FALSE, pre_callback, user_data); if (hook) g_hook_destroy_link (&atlas->pre_reorganize_callbacks, hook); } if (post_callback) { GHook *hook = g_hook_find_func_data (&atlas->post_reorganize_callbacks, FALSE, post_callback, user_data); if (hook) g_hook_destroy_link (&atlas->post_reorganize_callbacks, hook); } } muffin-5.2.1/cogl/cogl/cogl-vector.c0000664000175000017500000001460414211404421017401 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include #include #define X 0 #define Y 1 #define Z 2 #define W 3 void cogl_vector3_init (float *vector, float x, float y, float z) { vector[X] = x; vector[Y] = y; vector[Z] = z; } void cogl_vector3_init_zero (float *vector) { memset (vector, 0, sizeof (float) * 3); } CoglBool cogl_vector3_equal (const void *v1, const void *v2) { float *vector0 = (float *)v1; float *vector1 = (float *)v2; _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE); _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE); /* There's no point picking an arbitrary epsilon that's appropriate * for comparing the components so we just use == that will at least * consider -0 and 0 to be equal. */ return vector0[X] == vector1[X] && vector0[Y] == vector1[Y] && vector0[Z] == vector1[Z]; } CoglBool cogl_vector3_equal_with_epsilon (const float *vector0, const float *vector1, float epsilon) { _COGL_RETURN_VAL_IF_FAIL (vector0 != NULL, FALSE); _COGL_RETURN_VAL_IF_FAIL (vector1 != NULL, FALSE); if (fabsf (vector0[X] - vector1[X]) < epsilon && fabsf (vector0[Y] - vector1[Y]) < epsilon && fabsf (vector0[Z] - vector1[Z]) < epsilon) return TRUE; else return FALSE; } float * cogl_vector3_copy (const float *vector) { if (vector) return g_slice_copy (sizeof (float) * 3, vector); return NULL; } void cogl_vector3_free (float *vector) { g_slice_free1 (sizeof (float) * 3, vector); } void cogl_vector3_invert (float *vector) { vector[X] = -vector[X]; vector[Y] = -vector[Y]; vector[Z] = -vector[Z]; } void cogl_vector3_add (float *result, const float *a, const float *b) { result[X] = a[X] + b[X]; result[Y] = a[Y] + b[Y]; result[Z] = a[Z] + b[Z]; } void cogl_vector3_subtract (float *result, const float *a, const float *b) { result[X] = a[X] - b[X]; result[Y] = a[Y] - b[Y]; result[Z] = a[Z] - b[Z]; } void cogl_vector3_multiply_scalar (float *vector, float scalar) { vector[X] *= scalar; vector[Y] *= scalar; vector[Z] *= scalar; } void cogl_vector3_divide_scalar (float *vector, float scalar) { float one_over_scalar = 1.0f / scalar; vector[X] *= one_over_scalar; vector[Y] *= one_over_scalar; vector[Z] *= one_over_scalar; } void cogl_vector3_normalize (float *vector) { float mag_squared = vector[X] * vector[X] + vector[Y] * vector[Y] + vector[Z] * vector[Z]; if (mag_squared > 0.0f) { float one_over_mag = 1.0f / sqrtf (mag_squared); vector[X] *= one_over_mag; vector[Y] *= one_over_mag; vector[Z] *= one_over_mag; } } float cogl_vector3_magnitude (const float *vector) { return sqrtf (vector[X] * vector[X] + vector[Y] * vector[Y] + vector[Z] * vector[Z]); } void cogl_vector3_cross_product (float *result, const float *a, const float *b) { float tmp[3]; tmp[X] = a[Y] * b[Z] - a[Z] * b[Y]; tmp[Y] = a[Z] * b[X] - a[X] * b[Z]; tmp[Z] = a[X] * b[Y] - a[Y] * b[X]; result[X] = tmp[X]; result[Y] = tmp[Y]; result[Z] = tmp[Z]; } float cogl_vector3_dot_product (const float *a, const float *b) { return a[X] * b[X] + a[Y] * b[Y] + a[Z] * b[Z]; } float cogl_vector3_distance (const float *a, const float *b) { float dx = b[X] - a[X]; float dy = b[Y] - a[Y]; float dz = b[Z] - a[Z]; return sqrtf (dx * dx + dy * dy + dz * dz); } #if 0 void cogl_vector4_init (float *vector, float x, float y, float z) { vector[X] = x; vector[Y] = y; vector[Z] = z; vector[W] = w; } void cogl_vector4_init_zero (float *vector) { memset (vector, 0, sizeof (CoglVector4)); } void cogl_vector4_init_from_vector4 (float *vector, float *src) { *vector4 = *src; } CoglBool cogl_vector4_equal (const void *v0, const void *v1) { _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE); _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE); return memcmp (v1, v2, sizeof (float) * 4) == 0 ? TRUE : FALSE; } float * cogl_vector4_copy (float *vector) { if (vector) return g_slice_dup (CoglVector4, vector); return NULL; } void cogl_vector4_free (float *vector) { g_slice_free (CoglVector4, vector); } void cogl_vector4_invert (float *vector) { vector.x = -vector.x; vector.y = -vector.y; vector.z = -vector.z; vector.w = -vector.w; } void cogl_vector4_add (float *result, float *a, float *b) { result.x = a.x + b.x; result.y = a.y + b.y; result.z = a.z + b.z; result.w = a.w + b.w; } void cogl_vector4_subtract (float *result, float *a, float *b) { result.x = a.x - b.x; result.y = a.y - b.y; result.z = a.z - b.z; result.w = a.w - b.w; } void cogl_vector4_divide (float *vector, float scalar) { float one_over_scalar = 1.0f / scalar; result.x *= one_over_scalar; result.y *= one_over_scalar; result.z *= one_over_scalar; result.w *= one_over_scalar; } #endif muffin-5.2.1/cogl/cogl/cogl-offscreen.h0000664000175000017500000001340514211404421020054 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_OFFSCREEN_H__ #define __COGL_OFFSCREEN_H__ #include #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-offscreen * @short_description: Functions for creating and manipulating offscreen * framebuffers. * * Cogl allows creating and operating on offscreen framebuffers. */ typedef struct _CoglOffscreen CoglOffscreen; #define COGL_OFFSCREEN(X) ((CoglOffscreen *)X) /** * cogl_offscreen_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_offscreen_get_gtype (void); /* Offscreen api */ /** * cogl_offscreen_new_with_texture: * @texture: A #CoglTexture pointer * * This creates an offscreen framebuffer object using the given * @texture as the primary color buffer. It doesn't just initialize * the contents of the offscreen buffer with the @texture; they are * tightly bound so that drawing to the offscreen buffer effectively * updates the contents of the given texture. You don't need to * destroy the offscreen buffer before you can use the @texture again. * * This api only works with low-level #CoglTexture types such as * #CoglTexture2D, #CoglTexture3D and #CoglTextureRectangle, and not * with meta-texture types such as #CoglTexture2DSliced. * * The storage for the framebuffer is actually allocated lazily * so this function will never return %NULL to indicate a runtime * error. This means it is still possible to configure the framebuffer * before it is really allocated. * * Simple applications without full error handling can simply rely on * Cogl to lazily allocate the storage of framebuffers but you should * be aware that if Cogl encounters an error (such as running out of * GPU memory) then your application will simply abort with an error * message. If you need to be able to catch such exceptions at runtime * then you can explicitly allocate your framebuffer when you have * finished configuring it by calling cogl_framebuffer_allocate() and * passing in a #CoglError argument to catch any exceptions. * * Return value: (transfer full): a newly instantiated #CoglOffscreen * framebuffer. */ CoglOffscreen * cogl_offscreen_new_with_texture (CoglTexture *texture); /** * cogl_offscreen_new_to_texture: * @texture: A #CoglTexture pointer * * This creates an offscreen buffer object using the given @texture as the * primary color buffer. It doesn't just initialize the contents of the * offscreen buffer with the @texture; they are tightly bound so that * drawing to the offscreen buffer effectivly updates the contents of the * given texture. You don't need to destroy the offscreen buffer before * you can use the @texture again. * * This only works with low-level #CoglTexture types such as * #CoglTexture2D, #CoglTexture3D and #CoglTextureRectangle, and not * with meta-texture types such as #CoglTexture2DSliced. * * Return value: (transfer full): a newly instantiated #CoglOffscreen * framebuffer or %NULL if it wasn't possible to create the * buffer. * Deprecated: 1.16: Use cogl_offscreen_new_with_texture instead. */ COGL_DEPRECATED_IN_1_16_FOR (cogl_offscreen_new_with_texture) CoglOffscreen * cogl_offscreen_new_to_texture (CoglTexture *texture); /** * cogl_is_offscreen: * @object: A pointer to a #CoglObject * * Determines whether the given #CoglObject references an offscreen * framebuffer object. * * Returns: %TRUE if @object is a #CoglOffscreen framebuffer, * %FALSE otherwise */ CoglBool cogl_is_offscreen (void *object); /** * cogl_offscreen_ref: * @offscreen: A pointer to a #CoglOffscreen framebuffer * * Increments the reference count on the @offscreen framebuffer. * * Return value: (transfer none): For convenience it returns the * given @offscreen * * Deprecated: 1.2: cogl_object_ref() should be used in new code. */ COGL_DEPRECATED_FOR (cogl_object_ref) void * cogl_offscreen_ref (void *offscreen); /** * cogl_offscreen_unref: * @offscreen: A pointer to a #CoglOffscreen framebuffer * * Decreases the reference count for the @offscreen buffer and frees it when * the count reaches 0. * * Deprecated: 1.2: cogl_object_unref() should be used in new code. */ COGL_DEPRECATED_FOR (cogl_object_unref) void cogl_offscreen_unref (void *offscreen); /** * cogl_offscreen_get_texture: (skip) */ CoglTexture * cogl_offscreen_get_texture (CoglOffscreen *offscreen); COGL_END_DECLS #endif /* __COGL_OFFSCREEN_H__ */ muffin-5.2.1/cogl/cogl/cogl-sub-texture.h0000664000175000017500000001056114211404421020371 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Neil Roberts */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_SUB_TEXTURE_H #define __COGL_SUB_TEXTURE_H COGL_BEGIN_DECLS /** * SECTION:cogl-sub-texture * @short_description: Functions for creating and manipulating * sub-textures. * * These functions allow high-level textures to be created that * represent a sub-region of another texture. For example these * can be used to implement custom texture atlasing schemes. */ #define COGL_SUB_TEXTURE(tex) ((CoglSubTexture *) tex) typedef struct _CoglSubTexture CoglSubTexture; /** * cogl_sub_texture_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_sub_texture_get_gtype (void); /** * cogl_sub_texture_new: * @ctx: A #CoglContext pointer * @parent_texture: The full texture containing a sub-region you want * to make a #CoglSubTexture from. * @sub_x: The top-left x coordinate of the parent region to make * a texture from. * @sub_y: The top-left y coordinate of the parent region to make * a texture from. * @sub_width: The width of the parent region to make a texture from. * @sub_height: The height of the parent region to make a texture * from. * * Creates a high-level #CoglSubTexture representing a sub-region of * any other #CoglTexture. The sub-region must strictly lye within the * bounds of the @parent_texture. The returned texture implements the * #CoglMetaTexture interface because it's not a low level texture * that hardware can understand natively. * * Remember: Unless you are using high level drawing APIs such * as cogl_rectangle() or other APIs documented to understand the * #CoglMetaTexture interface then you need to use the * #CoglMetaTexture interface to resolve a #CoglSubTexture into a * low-level texture before drawing. * * Return value: (transfer full): A newly allocated #CoglSubTexture * representing a sub-region of @parent_texture. * * Since: 1.10 * Stability: unstable */ CoglSubTexture * cogl_sub_texture_new (CoglContext *ctx, CoglTexture *parent_texture, int sub_x, int sub_y, int sub_width, int sub_height); /** * cogl_sub_texture_get_parent: * @sub_texture: A pointer to a #CoglSubTexture * * Retrieves the parent texture that @sub_texture derives its content * from. This is the texture that was passed to * cogl_sub_texture_new() as the parent_texture argument. * * Return value: (transfer none): The parent texture that @sub_texture * derives its content from. * Since: 1.10 * Stability: unstable */ CoglTexture * cogl_sub_texture_get_parent (CoglSubTexture *sub_texture); /** * cogl_is_sub_texture: * @object: a #CoglObject * * Checks whether @object is a #CoglSubTexture. * * Return value: %TRUE if the passed @object represents a * #CoglSubTexture and %FALSE otherwise. * * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_sub_texture (void *object); COGL_END_DECLS #endif /* __COGL_SUB_TEXTURE_H */ muffin-5.2.1/cogl/cogl/cogl-renderer.c0000664000175000017500000005517514211404421017715 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include "cogl-util.h" #include "cogl-private.h" #include "cogl-object.h" #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-muffin.h" #include "cogl-renderer.h" #include "cogl-renderer-private.h" #include "cogl-display-private.h" #include "cogl-winsys-private.h" #include "cogl-winsys-stub-private.h" #include "cogl-config-private.h" #include "cogl-error-private.h" #include "cogl-gtype-private.h" #ifdef COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT #include "cogl-winsys-egl-x11-private.h" #endif #ifdef COGL_HAS_GLX_SUPPORT #include "cogl-winsys-glx-private.h" #endif #ifdef COGL_HAS_XLIB_SUPPORT #include "cogl-xlib-renderer.h" #endif #ifdef HAVE_COGL_GL extern const CoglTextureDriver _cogl_texture_driver_gl; extern const CoglDriverVtable _cogl_driver_gl; #endif #if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) extern const CoglTextureDriver _cogl_texture_driver_gles; extern const CoglDriverVtable _cogl_driver_gles; #endif extern const CoglDriverVtable _cogl_driver_nop; typedef struct _CoglDriverDescription { CoglDriver id; const char *name; CoglRendererConstraint constraints; /* It would be nice to make this a pointer and then use a compound * literal from C99 to initialise it but we probably can't get away * with using C99 here. Instead we'll just use a fixed-size array. * GCC should complain if someone adds an 8th feature to a * driver. */ const CoglPrivateFeature private_features[8]; const CoglDriverVtable *vtable; const CoglTextureDriver *texture_driver; const char *libgl_name; } CoglDriverDescription; static CoglDriverDescription _cogl_drivers[] = { #ifdef HAVE_COGL_GL { COGL_DRIVER_GL, "gl", 0, { COGL_PRIVATE_FEATURE_ANY_GL, COGL_PRIVATE_FEATURE_GL_FIXED, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE, -1 }, &_cogl_driver_gl, &_cogl_texture_driver_gl, COGL_GL_LIBNAME, }, { COGL_DRIVER_GL3, "gl3", 0, { COGL_PRIVATE_FEATURE_ANY_GL, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE, -1 }, &_cogl_driver_gl, &_cogl_texture_driver_gl, COGL_GL_LIBNAME, }, #endif #ifdef HAVE_COGL_GLES2 { COGL_DRIVER_GLES2, "gles2", COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2, { COGL_PRIVATE_FEATURE_ANY_GL, COGL_PRIVATE_FEATURE_GL_EMBEDDED, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE, -1 }, &_cogl_driver_gles, &_cogl_texture_driver_gles, COGL_GLES2_LIBNAME, }, #endif #ifdef HAVE_COGL_GLES { COGL_DRIVER_GLES1, "gles1", 0, { COGL_PRIVATE_FEATURE_ANY_GL, COGL_PRIVATE_FEATURE_GL_EMBEDDED, COGL_PRIVATE_FEATURE_GL_FIXED, -1 }, &_cogl_driver_gles, &_cogl_texture_driver_gles, COGL_GLES1_LIBNAME, }, #endif { COGL_DRIVER_NOP, "nop", 0, /* constraints satisfied */ { -1 }, &_cogl_driver_nop, NULL, /* texture driver */ NULL /* libgl_name */ } }; static CoglWinsysVtableGetter _cogl_winsys_vtable_getters[] = { #ifdef COGL_HAS_GLX_SUPPORT _cogl_winsys_glx_get_vtable, #endif #ifdef COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT _cogl_winsys_egl_xlib_get_vtable, #endif _cogl_winsys_stub_get_vtable, }; static void _cogl_renderer_free (CoglRenderer *renderer); COGL_OBJECT_DEFINE (Renderer, renderer); COGL_GTYPE_DEFINE_CLASS (Renderer, renderer); typedef struct _CoglNativeFilterClosure { CoglNativeFilterFunc func; void *data; } CoglNativeFilterClosure; uint32_t cogl_renderer_error_quark (void) { return g_quark_from_static_string ("cogl-renderer-error-quark"); } static const CoglWinsysVtable * _cogl_renderer_get_winsys (CoglRenderer *renderer) { return renderer->winsys_vtable; } static void native_filter_closure_free (CoglNativeFilterClosure *closure) { g_slice_free (CoglNativeFilterClosure, closure); } static void _cogl_renderer_free (CoglRenderer *renderer) { const CoglWinsysVtable *winsys = _cogl_renderer_get_winsys (renderer); _cogl_closure_list_disconnect_all (&renderer->idle_closures); if (winsys) winsys->renderer_disconnect (renderer); if (renderer->libgl_module) g_module_close (renderer->libgl_module); g_slist_foreach (renderer->event_filters, (GFunc) native_filter_closure_free, NULL); g_slist_free (renderer->event_filters); g_array_free (renderer->poll_fds, TRUE); free (renderer); } CoglRenderer * cogl_renderer_new (void) { CoglRenderer *renderer = g_new0 (CoglRenderer, 1); _cogl_init (); renderer->connected = FALSE; renderer->event_filters = NULL; renderer->poll_fds = g_array_new (FALSE, TRUE, sizeof (CoglPollFD)); _cogl_list_init (&renderer->idle_closures); #ifdef COGL_HAS_XLIB_SUPPORT renderer->xlib_enable_event_retrieval = TRUE; #endif return _cogl_renderer_object_new (renderer); } #ifdef COGL_HAS_XLIB_SUPPORT void cogl_xlib_renderer_set_foreign_display (CoglRenderer *renderer, Display *xdisplay) { _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); /* NB: Renderers are considered immutable once connected */ _COGL_RETURN_IF_FAIL (!renderer->connected); renderer->foreign_xdpy = xdisplay; /* If the application is using a foreign display then we can assume it will also do its own event retrieval */ cogl_xlib_renderer_set_event_retrieval_enabled (renderer, FALSE); } Display * cogl_xlib_renderer_get_foreign_display (CoglRenderer *renderer) { _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL); return renderer->foreign_xdpy; } void cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, CoglBool enable) { _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); /* NB: Renderers are considered immutable once connected */ _COGL_RETURN_IF_FAIL (!renderer->connected); renderer->xlib_enable_event_retrieval = enable; } void cogl_xlib_renderer_request_reset_on_video_memory_purge (CoglRenderer *renderer, CoglBool enable) { _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); _COGL_RETURN_IF_FAIL (!renderer->connected); renderer->xlib_want_reset_on_video_memory_purge = enable; } void cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer, CoglBool enable) { _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); /* NB: Renderers are considered immutable once connected */ _COGL_RETURN_IF_FAIL (!renderer->connected); renderer->xlib_enable_threaded_swap_wait = enable; } #endif /* COGL_HAS_XLIB_SUPPORT */ CoglBool cogl_renderer_check_onscreen_template (CoglRenderer *renderer, CoglOnscreenTemplate *onscreen_template, CoglError **error) { CoglDisplay *display; if (!cogl_renderer_connect (renderer, error)) return FALSE; display = cogl_display_new (renderer, onscreen_template); if (!cogl_display_setup (display, error)) { cogl_object_unref (display); return FALSE; } cogl_object_unref (display); return TRUE; } typedef CoglBool (*CoglDriverCallback) (CoglDriverDescription *description, void *user_data); static void foreach_driver_description (CoglDriver driver_override, CoglDriverCallback callback, void *user_data) { #ifdef COGL_DEFAULT_DRIVER const CoglDriverDescription *default_driver = NULL; #endif int i; if (driver_override != COGL_DRIVER_ANY) { for (i = 0; i < G_N_ELEMENTS (_cogl_drivers); i++) { if (_cogl_drivers[i].id == driver_override) { callback (&_cogl_drivers[i], user_data); return; } } g_warn_if_reached (); return; } #ifdef COGL_DEFAULT_DRIVER for (i = 0; i < G_N_ELEMENTS (_cogl_drivers); i++) { const CoglDriverDescription *desc = &_cogl_drivers[i]; if (g_ascii_strcasecmp (desc->name, COGL_DEFAULT_DRIVER) == 0) { default_driver = desc; break; } } if (default_driver) { if (!callback (default_driver, user_data)) return; } #endif for (i = 0; i < G_N_ELEMENTS (_cogl_drivers); i++) { #ifdef COGL_DEFAULT_DRIVER if (&_cogl_drivers[i] == default_driver) continue; #endif if (!callback (&_cogl_drivers[i], user_data)) return; } } static CoglDriver driver_name_to_id (const char *name) { int i; for (i = 0; i < G_N_ELEMENTS (_cogl_drivers); i++) { if (g_ascii_strcasecmp (_cogl_drivers[i].name, name) == 0) return _cogl_drivers[i].id; } return COGL_DRIVER_ANY; } static const char * driver_id_to_name (CoglDriver id) { switch (id) { case COGL_DRIVER_GL: return "gl"; case COGL_DRIVER_GL3: return "gl3"; case COGL_DRIVER_GLES1: return "gles1"; case COGL_DRIVER_GLES2: return "gles2"; case COGL_DRIVER_WEBGL: return "webgl"; case COGL_DRIVER_NOP: return "nop"; case COGL_DRIVER_ANY: g_warn_if_reached (); return "any"; } g_warn_if_reached (); return "unknown"; } typedef struct _SatisfyConstraintsState { GList *constraints; const CoglDriverDescription *driver_description; } SatisfyConstraintsState; static CoglBool satisfy_constraints (CoglDriverDescription *description, void *user_data) { SatisfyConstraintsState *state = user_data; GList *l; for (l = state->constraints; l; l = l->next) { CoglRendererConstraint constraint = GPOINTER_TO_UINT (l->data); /* Most of the constraints only affect the winsys selection so * we'll filter them out */ if (!(constraint & COGL_RENDERER_DRIVER_CONSTRAINTS)) continue; /* If the driver doesn't satisfy any constraint then continue * to the next driver description */ if (!(constraint & description->constraints)) return TRUE; } state->driver_description = description; return FALSE; } static CoglBool _cogl_renderer_choose_driver (CoglRenderer *renderer, CoglError **error) { const char *driver_name = g_getenv ("COGL_DRIVER"); CoglDriver driver_override = COGL_DRIVER_ANY; const char *invalid_override = NULL; const char *libgl_name; SatisfyConstraintsState state; const CoglDriverDescription *desc; int i; if (!driver_name) driver_name = _cogl_config_driver; if (driver_name) { driver_override = driver_name_to_id (driver_name); if (driver_override == COGL_DRIVER_ANY) invalid_override = driver_name; } if (renderer->driver_override != COGL_DRIVER_ANY) { if (driver_override != COGL_DRIVER_ANY && renderer->driver_override != driver_override) { _cogl_set_error (error, COGL_RENDERER_ERROR, COGL_RENDERER_ERROR_BAD_CONSTRAINT, "Application driver selection conflicts with driver " "specified in configuration"); return FALSE; } driver_override = renderer->driver_override; } if (driver_override != COGL_DRIVER_ANY) { CoglBool found = FALSE; int i; for (i = 0; i < G_N_ELEMENTS (_cogl_drivers); i++) { if (_cogl_drivers[i].id == driver_override) { found = TRUE; break; } } if (!found) invalid_override = driver_id_to_name (driver_override); } if (invalid_override) { _cogl_set_error (error, COGL_RENDERER_ERROR, COGL_RENDERER_ERROR_BAD_CONSTRAINT, "Driver \"%s\" is not available", invalid_override); return FALSE; } state.driver_description = NULL; state.constraints = renderer->constraints; foreach_driver_description (driver_override, satisfy_constraints, &state); if (!state.driver_description) { _cogl_set_error (error, COGL_RENDERER_ERROR, COGL_RENDERER_ERROR_BAD_CONSTRAINT, "No suitable driver found"); return FALSE; } desc = state.driver_description; renderer->driver = desc->id; renderer->driver_vtable = desc->vtable; renderer->texture_driver = desc->texture_driver; libgl_name = desc->libgl_name; memset(renderer->private_features, 0, sizeof (renderer->private_features)); for (i = 0; desc->private_features[i] != -1; i++) COGL_FLAGS_SET (renderer->private_features, desc->private_features[i], TRUE); if (COGL_FLAGS_GET (renderer->private_features, COGL_PRIVATE_FEATURE_ANY_GL)) { renderer->libgl_module = g_module_open (libgl_name, G_MODULE_BIND_LAZY); if (renderer->libgl_module == NULL) { _cogl_set_error (error, COGL_DRIVER_ERROR, COGL_DRIVER_ERROR_FAILED_TO_LOAD_LIBRARY, "Failed to dynamically open the GL library \"%s\"", libgl_name); return FALSE; } } return TRUE; } /* Final connection API */ void cogl_renderer_set_custom_winsys (CoglRenderer *renderer, CoglCustomWinsysVtableGetter winsys_vtable_getter, void *user_data) { renderer->custom_winsys_user_data = user_data; renderer->custom_winsys_vtable_getter = winsys_vtable_getter; } static CoglBool connect_custom_winsys (CoglRenderer *renderer, CoglError **error) { const CoglWinsysVtable *winsys; CoglError *tmp_error = NULL; GString *error_message; winsys = renderer->custom_winsys_vtable_getter (renderer); renderer->winsys_vtable = winsys; error_message = g_string_new (""); if (!winsys->renderer_connect (renderer, &tmp_error)) { g_string_append_c (error_message, '\n'); g_string_append (error_message, tmp_error->message); cogl_error_free (tmp_error); } else { renderer->connected = TRUE; g_string_free (error_message, TRUE); return TRUE; } renderer->winsys_vtable = NULL; _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "Failed to connected to any renderer: %s", error_message->str); g_string_free (error_message, TRUE); return FALSE; } CoglBool cogl_renderer_connect (CoglRenderer *renderer, CoglError **error) { int i; GString *error_message; CoglBool constraints_failed = FALSE; if (renderer->connected) return TRUE; /* The driver needs to be chosen before connecting the renderer because eglInitialize requires the library containing the GL API to be loaded before its called */ if (!_cogl_renderer_choose_driver (renderer, error)) return FALSE; if (renderer->custom_winsys_vtable_getter) return connect_custom_winsys (renderer, error); error_message = g_string_new (""); for (i = 0; i < G_N_ELEMENTS (_cogl_winsys_vtable_getters); i++) { const CoglWinsysVtable *winsys = _cogl_winsys_vtable_getters[i](); CoglError *tmp_error = NULL; GList *l; CoglBool skip_due_to_constraints = FALSE; if (renderer->winsys_id_override != COGL_WINSYS_ID_ANY) { if (renderer->winsys_id_override != winsys->id) continue; } else { char *user_choice = getenv ("COGL_RENDERER"); if (!user_choice) user_choice = _cogl_config_renderer; if (user_choice && g_ascii_strcasecmp (winsys->name, user_choice) != 0) continue; } for (l = renderer->constraints; l; l = l->next) { CoglRendererConstraint constraint = GPOINTER_TO_UINT (l->data); if (!(winsys->constraints & constraint)) { skip_due_to_constraints = TRUE; break; } } if (skip_due_to_constraints) { constraints_failed |= TRUE; continue; } /* At least temporarily we will associate this winsys with * the renderer in-case ->renderer_connect calls API that * wants to query the current winsys... */ renderer->winsys_vtable = winsys; if (!winsys->renderer_connect (renderer, &tmp_error)) { g_string_append_c (error_message, '\n'); g_string_append (error_message, tmp_error->message); cogl_error_free (tmp_error); } else { renderer->connected = TRUE; g_string_free (error_message, TRUE); return TRUE; } } if (!renderer->connected) { if (constraints_failed) { _cogl_set_error (error, COGL_RENDERER_ERROR, COGL_RENDERER_ERROR_BAD_CONSTRAINT, "Failed to connected to any renderer due to constraints"); return FALSE; } renderer->winsys_vtable = NULL; _cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_INIT, "Failed to connected to any renderer: %s", error_message->str); g_string_free (error_message, TRUE); return FALSE; } return TRUE; } CoglFilterReturn _cogl_renderer_handle_native_event (CoglRenderer *renderer, void *event) { GSList *l, *next; /* Pass the event on to all of the registered filters in turn */ for (l = renderer->event_filters; l; l = next) { CoglNativeFilterClosure *closure = l->data; /* The next pointer is taken now so that we can handle the closure being removed during emission */ next = l->next; if (closure->func (event, closure->data) == COGL_FILTER_REMOVE) return COGL_FILTER_REMOVE; } /* If the backend for the renderer also wants to see the events, it should just register its own filter */ return COGL_FILTER_CONTINUE; } void _cogl_renderer_add_native_filter (CoglRenderer *renderer, CoglNativeFilterFunc func, void *data) { CoglNativeFilterClosure *closure; closure = g_slice_new (CoglNativeFilterClosure); closure->func = func; closure->data = data; renderer->event_filters = g_slist_prepend (renderer->event_filters, closure); } void _cogl_renderer_remove_native_filter (CoglRenderer *renderer, CoglNativeFilterFunc func, void *data) { GSList *l, *prev = NULL; for (l = renderer->event_filters; l; prev = l, l = l->next) { CoglNativeFilterClosure *closure = l->data; if (closure->func == func && closure->data == data) { native_filter_closure_free (closure); if (prev) prev->next = g_slist_delete_link (prev->next, l); else renderer->event_filters = g_slist_delete_link (renderer->event_filters, l); break; } } } void cogl_renderer_set_winsys_id (CoglRenderer *renderer, CoglWinsysID winsys_id) { _COGL_RETURN_IF_FAIL (!renderer->connected); renderer->winsys_id_override = winsys_id; } CoglWinsysID cogl_renderer_get_winsys_id (CoglRenderer *renderer) { _COGL_RETURN_VAL_IF_FAIL (renderer->connected, 0); return renderer->winsys_vtable->id; } void * _cogl_renderer_get_proc_address (CoglRenderer *renderer, const char *name, CoglBool in_core) { const CoglWinsysVtable *winsys = _cogl_renderer_get_winsys (renderer); return winsys->renderer_get_proc_address (renderer, name, in_core); } int cogl_renderer_get_n_fragment_texture_units (CoglRenderer *renderer) { int n = 0; _COGL_GET_CONTEXT (ctx, 0); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES2) if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL) || cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP)) GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &n)); #endif return n; } void cogl_renderer_add_constraint (CoglRenderer *renderer, CoglRendererConstraint constraint) { g_return_if_fail (!renderer->connected); renderer->constraints = g_list_prepend (renderer->constraints, GUINT_TO_POINTER (constraint)); } void cogl_renderer_remove_constraint (CoglRenderer *renderer, CoglRendererConstraint constraint) { g_return_if_fail (!renderer->connected); renderer->constraints = g_list_remove (renderer->constraints, GUINT_TO_POINTER (constraint)); } void cogl_renderer_set_driver (CoglRenderer *renderer, CoglDriver driver) { _COGL_RETURN_IF_FAIL (!renderer->connected); renderer->driver_override = driver; } CoglDriver cogl_renderer_get_driver (CoglRenderer *renderer) { _COGL_RETURN_VAL_IF_FAIL (renderer->connected, 0); return renderer->driver; } void cogl_renderer_foreach_output (CoglRenderer *renderer, CoglOutputCallback callback, void *user_data) { GList *l; _COGL_RETURN_IF_FAIL (renderer->connected); _COGL_RETURN_IF_FAIL (callback != NULL); for (l = renderer->outputs; l; l = l->next) callback (l->data, user_data); } muffin-5.2.1/cogl/cogl/cogl-matrix-stack-private.h0000664000175000017500000001122714211404421022161 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Havoc Pennington for litl * Robert Bragg */ #ifndef _COGL_MATRIX_STACK_PRIVATE_H_ #define _COGL_MATRIX_STACK_PRIVATE_H_ #include "cogl-object-private.h" #include "cogl-matrix-stack.h" #include "cogl-context.h" #include "cogl-framebuffer.h" typedef enum _CoglMatrixOp { COGL_MATRIX_OP_LOAD_IDENTITY, COGL_MATRIX_OP_TRANSLATE, COGL_MATRIX_OP_ROTATE, COGL_MATRIX_OP_ROTATE_QUATERNION, COGL_MATRIX_OP_ROTATE_EULER, COGL_MATRIX_OP_SCALE, COGL_MATRIX_OP_MULTIPLY, COGL_MATRIX_OP_LOAD, COGL_MATRIX_OP_SAVE, } CoglMatrixOp; struct _CoglMatrixEntry { CoglMatrixEntry *parent; CoglMatrixOp op; unsigned int ref_count; #ifdef COGL_DEBUG_ENABLED /* used for performance tracing */ int composite_gets; #endif }; typedef struct _CoglMatrixEntryTranslate { CoglMatrixEntry _parent_data; float x; float y; float z; } CoglMatrixEntryTranslate; typedef struct _CoglMatrixEntryRotate { CoglMatrixEntry _parent_data; float angle; float x; float y; float z; } CoglMatrixEntryRotate; typedef struct _CoglMatrixEntryRotateEuler { CoglMatrixEntry _parent_data; /* This doesn't store an actual CoglEuler in order to avoid the * padding */ float heading; float pitch; float roll; } CoglMatrixEntryRotateEuler; typedef struct _CoglMatrixEntryRotateQuaternion { CoglMatrixEntry _parent_data; /* This doesn't store an actual CoglQuaternion in order to avoid the * padding */ float values[4]; } CoglMatrixEntryRotateQuaternion; typedef struct _CoglMatrixEntryScale { CoglMatrixEntry _parent_data; float x; float y; float z; } CoglMatrixEntryScale; typedef struct _CoglMatrixEntryMultiply { CoglMatrixEntry _parent_data; CoglMatrix *matrix; } CoglMatrixEntryMultiply; typedef struct _CoglMatrixEntryLoad { CoglMatrixEntry _parent_data; CoglMatrix *matrix; } CoglMatrixEntryLoad; typedef struct _CoglMatrixEntrySave { CoglMatrixEntry _parent_data; CoglMatrix *cache; CoglBool cache_valid; } CoglMatrixEntrySave; typedef union _CoglMatrixEntryFull { CoglMatrixEntry any; CoglMatrixEntryTranslate translate; CoglMatrixEntryRotate rotate; CoglMatrixEntryRotateEuler rotate_euler; CoglMatrixEntryRotateQuaternion rotate_quaternion; CoglMatrixEntryScale scale; CoglMatrixEntryMultiply multiply; CoglMatrixEntryLoad load; CoglMatrixEntrySave save; } CoglMatrixEntryFull; struct _CoglMatrixStack { CoglObject _parent; CoglContext *context; CoglMatrixEntry *last_entry; }; typedef struct _CoglMatrixEntryCache { CoglMatrixEntry *entry; CoglBool flushed_identity; CoglBool flipped; } CoglMatrixEntryCache; void _cogl_matrix_entry_identity_init (CoglMatrixEntry *entry); typedef enum { COGL_MATRIX_MODELVIEW, COGL_MATRIX_PROJECTION, COGL_MATRIX_TEXTURE } CoglMatrixMode; void _cogl_matrix_entry_flush_to_gl_builtins (CoglContext *ctx, CoglMatrixEntry *entry, CoglMatrixMode mode, CoglFramebuffer *framebuffer, CoglBool disable_flip); void _cogl_matrix_entry_cache_init (CoglMatrixEntryCache *cache); CoglBool _cogl_matrix_entry_cache_maybe_update (CoglMatrixEntryCache *cache, CoglMatrixEntry *entry, CoglBool flip); void _cogl_matrix_entry_cache_destroy (CoglMatrixEntryCache *cache); #endif /* _COGL_MATRIX_STACK_PRIVATE_H_ */ muffin-5.2.1/cogl/cogl/cogl-matrix-stack.c0000664000175000017500000010555214211404421020511 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009,2010,2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Havoc Pennington for litl * Robert Bragg * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-matrix-stack.h" #include "cogl-framebuffer-private.h" #include "cogl-object-private.h" #include "cogl-offscreen.h" #include "cogl-matrix-private.h" #include "cogl-magazine-private.h" #include "cogl-gtype-private.h" static void _cogl_matrix_stack_free (CoglMatrixStack *stack); COGL_OBJECT_DEFINE (MatrixStack, matrix_stack); COGL_GTYPE_DEFINE_CLASS (MatrixStack, matrix_stack); COGL_GTYPE_DEFINE_BOXED (MatrixEntry, matrix_entry, cogl_matrix_entry_ref, cogl_matrix_entry_unref); static CoglMagazine *cogl_matrix_stack_magazine; static CoglMagazine *cogl_matrix_stack_matrices_magazine; /* XXX: Note: this leaves entry->parent uninitialized! */ static CoglMatrixEntry * _cogl_matrix_entry_new (CoglMatrixOp operation) { CoglMatrixEntry *entry = _cogl_magazine_chunk_alloc (cogl_matrix_stack_magazine); entry->ref_count = 1; entry->op = operation; #ifdef COGL_DEBUG_ENABLED entry->composite_gets = 0; #endif return entry; } static void * _cogl_matrix_stack_push_entry (CoglMatrixStack *stack, CoglMatrixEntry *entry) { /* NB: The initial reference of the entry is transferred to the * stack here. * * The stack only maintains a reference to the top of the stack (the * last entry pushed) and each entry in-turn maintains a reference * to its parent. * * We don't need to take a reference to the parent from the entry * here because the we are stealing the reference that was held by * the stack while that parent was previously the top of the stack. */ entry->parent = stack->last_entry; stack->last_entry = entry; return entry; } static void * _cogl_matrix_stack_push_operation (CoglMatrixStack *stack, CoglMatrixOp operation) { CoglMatrixEntry *entry = _cogl_matrix_entry_new (operation); _cogl_matrix_stack_push_entry (stack, entry); return entry; } static void * _cogl_matrix_stack_push_replacement_entry (CoglMatrixStack *stack, CoglMatrixOp operation) { CoglMatrixEntry *old_top = stack->last_entry; CoglMatrixEntry *new_top; /* This would only be called for operations that completely replace * the matrix. In that case we don't need to keep a reference to * anything up to the last save entry. This optimisation could be * important for applications that aren't using the stack but * instead just perform their own matrix manipulations and load a * new stack every frame. If this optimisation isn't done then the * stack would just grow endlessly. See the comments * cogl_matrix_stack_pop for a description of how popping works. */ for (new_top = old_top; new_top->op != COGL_MATRIX_OP_SAVE && new_top->parent; new_top = new_top->parent) ; cogl_matrix_entry_ref (new_top); cogl_matrix_entry_unref (old_top); stack->last_entry = new_top; return _cogl_matrix_stack_push_operation (stack, operation); } void _cogl_matrix_entry_identity_init (CoglMatrixEntry *entry) { entry->ref_count = 1; entry->op = COGL_MATRIX_OP_LOAD_IDENTITY; entry->parent = NULL; #ifdef COGL_DEBUG_ENABLED entry->composite_gets = 0; #endif } void cogl_matrix_stack_load_identity (CoglMatrixStack *stack) { _cogl_matrix_stack_push_replacement_entry (stack, COGL_MATRIX_OP_LOAD_IDENTITY); } void cogl_matrix_stack_translate (CoglMatrixStack *stack, float x, float y, float z) { CoglMatrixEntryTranslate *entry; entry = _cogl_matrix_stack_push_operation (stack, COGL_MATRIX_OP_TRANSLATE); entry->x = x; entry->y = y; entry->z = z; } void cogl_matrix_stack_rotate (CoglMatrixStack *stack, float angle, float x, float y, float z) { CoglMatrixEntryRotate *entry; entry = _cogl_matrix_stack_push_operation (stack, COGL_MATRIX_OP_ROTATE); entry->angle = angle; entry->x = x; entry->y = y; entry->z = z; } void cogl_matrix_stack_rotate_quaternion (CoglMatrixStack *stack, const CoglQuaternion *quaternion) { CoglMatrixEntryRotateQuaternion *entry; entry = _cogl_matrix_stack_push_operation (stack, COGL_MATRIX_OP_ROTATE_QUATERNION); entry->values[0] = quaternion->w; entry->values[1] = quaternion->x; entry->values[2] = quaternion->y; entry->values[3] = quaternion->z; } void cogl_matrix_stack_rotate_euler (CoglMatrixStack *stack, const CoglEuler *euler) { CoglMatrixEntryRotateEuler *entry; entry = _cogl_matrix_stack_push_operation (stack, COGL_MATRIX_OP_ROTATE_EULER); entry->heading = euler->heading; entry->pitch = euler->pitch; entry->roll = euler->roll; } void cogl_matrix_stack_scale (CoglMatrixStack *stack, float x, float y, float z) { CoglMatrixEntryScale *entry; entry = _cogl_matrix_stack_push_operation (stack, COGL_MATRIX_OP_SCALE); entry->x = x; entry->y = y; entry->z = z; } void cogl_matrix_stack_multiply (CoglMatrixStack *stack, const CoglMatrix *matrix) { CoglMatrixEntryMultiply *entry; entry = _cogl_matrix_stack_push_operation (stack, COGL_MATRIX_OP_MULTIPLY); entry->matrix = _cogl_magazine_chunk_alloc (cogl_matrix_stack_matrices_magazine); cogl_matrix_init_from_array (entry->matrix, (float *)matrix); } void cogl_matrix_stack_set (CoglMatrixStack *stack, const CoglMatrix *matrix) { CoglMatrixEntryLoad *entry; entry = _cogl_matrix_stack_push_replacement_entry (stack, COGL_MATRIX_OP_LOAD); entry->matrix = _cogl_magazine_chunk_alloc (cogl_matrix_stack_matrices_magazine); cogl_matrix_init_from_array (entry->matrix, (float *)matrix); } void cogl_matrix_stack_frustum (CoglMatrixStack *stack, float left, float right, float bottom, float top, float z_near, float z_far) { CoglMatrixEntryLoad *entry; entry = _cogl_matrix_stack_push_replacement_entry (stack, COGL_MATRIX_OP_LOAD); entry->matrix = _cogl_magazine_chunk_alloc (cogl_matrix_stack_matrices_magazine); cogl_matrix_init_identity (entry->matrix); cogl_matrix_frustum (entry->matrix, left, right, bottom, top, z_near, z_far); } void cogl_matrix_stack_perspective (CoglMatrixStack *stack, float fov_y, float aspect, float z_near, float z_far) { CoglMatrixEntryLoad *entry; entry = _cogl_matrix_stack_push_replacement_entry (stack, COGL_MATRIX_OP_LOAD); entry->matrix = _cogl_magazine_chunk_alloc (cogl_matrix_stack_matrices_magazine); cogl_matrix_init_identity (entry->matrix); cogl_matrix_perspective (entry->matrix, fov_y, aspect, z_near, z_far); } void cogl_matrix_stack_orthographic (CoglMatrixStack *stack, float x_1, float y_1, float x_2, float y_2, float near, float far) { CoglMatrixEntryLoad *entry; entry = _cogl_matrix_stack_push_replacement_entry (stack, COGL_MATRIX_OP_LOAD); entry->matrix = _cogl_magazine_chunk_alloc (cogl_matrix_stack_matrices_magazine); cogl_matrix_init_identity (entry->matrix); cogl_matrix_orthographic (entry->matrix, x_1, y_1, x_2, y_2, near, far); } void cogl_matrix_stack_push (CoglMatrixStack *stack) { CoglMatrixEntrySave *entry; entry = _cogl_matrix_stack_push_operation (stack, COGL_MATRIX_OP_SAVE); entry->cache_valid = FALSE; } CoglMatrixEntry * cogl_matrix_entry_ref (CoglMatrixEntry *entry) { /* A NULL pointer is considered a valid stack so we should accept that as an argument */ if (entry) entry->ref_count++; return entry; } void cogl_matrix_entry_unref (CoglMatrixEntry *entry) { CoglMatrixEntry *parent; for (; entry && --entry->ref_count <= 0; entry = parent) { parent = entry->parent; switch (entry->op) { case COGL_MATRIX_OP_LOAD_IDENTITY: case COGL_MATRIX_OP_TRANSLATE: case COGL_MATRIX_OP_ROTATE: case COGL_MATRIX_OP_ROTATE_QUATERNION: case COGL_MATRIX_OP_ROTATE_EULER: case COGL_MATRIX_OP_SCALE: break; case COGL_MATRIX_OP_MULTIPLY: { CoglMatrixEntryMultiply *multiply = (CoglMatrixEntryMultiply *)entry; _cogl_magazine_chunk_free (cogl_matrix_stack_matrices_magazine, multiply->matrix); break; } case COGL_MATRIX_OP_LOAD: { CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)entry; _cogl_magazine_chunk_free (cogl_matrix_stack_matrices_magazine, load->matrix); break; } case COGL_MATRIX_OP_SAVE: { CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)entry; if (save->cache_valid) _cogl_magazine_chunk_free (cogl_matrix_stack_matrices_magazine, save->cache); break; } } _cogl_magazine_chunk_free (cogl_matrix_stack_magazine, entry); } } void cogl_matrix_stack_pop (CoglMatrixStack *stack) { CoglMatrixEntry *old_top; CoglMatrixEntry *new_top; _COGL_RETURN_IF_FAIL (stack != NULL); old_top = stack->last_entry; _COGL_RETURN_IF_FAIL (old_top != NULL); /* To pop we are moving the top of the stack to the old top's parent * node. The stack always needs to have a reference to the top entry * so we must take a reference to the new top. The stack would have * previously had a reference to the old top so we need to decrease * the ref count on that. We need to ref the new head first in case * this stack was the only thing referencing the old top. In that * case the call to cogl_matrix_entry_unref will unref the parent. */ /* Find the last save operation and remove it */ /* XXX: it would be an error to pop to the very beginning of the * stack so we don't need to check for NULL pointer dereferencing. */ for (new_top = old_top; new_top->op != COGL_MATRIX_OP_SAVE; new_top = new_top->parent) ; new_top = new_top->parent; cogl_matrix_entry_ref (new_top); cogl_matrix_entry_unref (old_top); stack->last_entry = new_top; } CoglBool cogl_matrix_stack_get_inverse (CoglMatrixStack *stack, CoglMatrix *inverse) { CoglMatrix matrix; CoglMatrix *internal = cogl_matrix_stack_get (stack, &matrix); if (internal) return cogl_matrix_get_inverse (internal, inverse); else return cogl_matrix_get_inverse (&matrix, inverse); } /* In addition to writing the stack matrix into the give @matrix * argument this function *may* sometimes also return a pointer * to a matrix too so if we are querying the inverse matrix we * should query from the return matrix so that the result can * be cached within the stack. */ CoglMatrix * cogl_matrix_entry_get (CoglMatrixEntry *entry, CoglMatrix *matrix) { int depth; CoglMatrixEntry *current; CoglMatrixEntry **children; int i; for (depth = 0, current = entry; current; current = current->parent, depth++) { switch (current->op) { case COGL_MATRIX_OP_LOAD_IDENTITY: cogl_matrix_init_identity (matrix); goto initialized; case COGL_MATRIX_OP_LOAD: { CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)current; _cogl_matrix_init_from_matrix_without_inverse (matrix, load->matrix); goto initialized; } case COGL_MATRIX_OP_SAVE: { CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)current; if (!save->cache_valid) { CoglMagazine *matrices_magazine = cogl_matrix_stack_matrices_magazine; save->cache = _cogl_magazine_chunk_alloc (matrices_magazine); cogl_matrix_entry_get (current->parent, save->cache); save->cache_valid = TRUE; } _cogl_matrix_init_from_matrix_without_inverse (matrix, save->cache); goto initialized; } default: continue; } } initialized: if (depth == 0) { switch (entry->op) { case COGL_MATRIX_OP_LOAD_IDENTITY: case COGL_MATRIX_OP_TRANSLATE: case COGL_MATRIX_OP_ROTATE: case COGL_MATRIX_OP_ROTATE_QUATERNION: case COGL_MATRIX_OP_ROTATE_EULER: case COGL_MATRIX_OP_SCALE: case COGL_MATRIX_OP_MULTIPLY: return NULL; case COGL_MATRIX_OP_LOAD: { CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)entry; return load->matrix; } case COGL_MATRIX_OP_SAVE: { CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)entry; return save->cache; } } g_warn_if_reached (); return NULL; } #ifdef COGL_ENABLE_DEBUG if (!current) { g_warning ("Inconsistent matrix stack"); return NULL; } entry->composite_gets++; #endif children = g_alloca (sizeof (CoglMatrixEntry) * depth); /* We need walk the list of entries from the init/load/save entry * back towards the leaf node but the nodes don't link to their * children so we need to re-walk them here to add to a separate * array. */ for (i = depth - 1, current = entry; i >= 0 && current; i--, current = current->parent) { children[i] = current; } #ifdef COGL_ENABLE_DEBUG if (COGL_DEBUG_ENABLED (COGL_DEBUG_PERFORMANCE) && entry->composite_gets >= 2) { COGL_NOTE (PERFORMANCE, "Re-composing a matrix stack entry multiple times"); } #endif for (i = 0; i < depth; i++) { switch (children[i]->op) { case COGL_MATRIX_OP_TRANSLATE: { CoglMatrixEntryTranslate *translate = (CoglMatrixEntryTranslate *)children[i]; cogl_matrix_translate (matrix, translate->x, translate->y, translate->z); continue; } case COGL_MATRIX_OP_ROTATE: { CoglMatrixEntryRotate *rotate= (CoglMatrixEntryRotate *)children[i]; cogl_matrix_rotate (matrix, rotate->angle, rotate->x, rotate->y, rotate->z); continue; } case COGL_MATRIX_OP_ROTATE_EULER: { CoglMatrixEntryRotateEuler *rotate = (CoglMatrixEntryRotateEuler *)children[i]; CoglEuler euler; cogl_euler_init (&euler, rotate->heading, rotate->pitch, rotate->roll); cogl_matrix_rotate_euler (matrix, &euler); continue; } case COGL_MATRIX_OP_ROTATE_QUATERNION: { CoglMatrixEntryRotateQuaternion *rotate = (CoglMatrixEntryRotateQuaternion *)children[i]; CoglQuaternion quaternion; cogl_quaternion_init_from_array (&quaternion, rotate->values); cogl_matrix_rotate_quaternion (matrix, &quaternion); continue; } case COGL_MATRIX_OP_SCALE: { CoglMatrixEntryScale *scale = (CoglMatrixEntryScale *)children[i]; cogl_matrix_scale (matrix, scale->x, scale->y, scale->z); continue; } case COGL_MATRIX_OP_MULTIPLY: { CoglMatrixEntryMultiply *multiply = (CoglMatrixEntryMultiply *)children[i]; cogl_matrix_multiply (matrix, matrix, multiply->matrix); continue; } case COGL_MATRIX_OP_LOAD_IDENTITY: case COGL_MATRIX_OP_LOAD: case COGL_MATRIX_OP_SAVE: g_warn_if_reached (); continue; } } return NULL; } CoglMatrixEntry * cogl_matrix_stack_get_entry (CoglMatrixStack *stack) { return stack->last_entry; } /* In addition to writing the stack matrix into the give @matrix * argument this function *may* sometimes also return a pointer * to a matrix too so if we are querying the inverse matrix we * should query from the return matrix so that the result can * be cached within the stack. */ CoglMatrix * cogl_matrix_stack_get (CoglMatrixStack *stack, CoglMatrix *matrix) { return cogl_matrix_entry_get (stack->last_entry, matrix); } static void _cogl_matrix_stack_free (CoglMatrixStack *stack) { cogl_matrix_entry_unref (stack->last_entry); g_slice_free (CoglMatrixStack, stack); } CoglMatrixStack * cogl_matrix_stack_new (CoglContext *ctx) { CoglMatrixStack *stack = g_slice_new (CoglMatrixStack); if (G_UNLIKELY (cogl_matrix_stack_magazine == NULL)) { cogl_matrix_stack_magazine = _cogl_magazine_new (sizeof (CoglMatrixEntryFull), 20); cogl_matrix_stack_matrices_magazine = _cogl_magazine_new (sizeof (CoglMatrix), 20); } stack->context = ctx; stack->last_entry = NULL; cogl_matrix_entry_ref (&ctx->identity_entry); _cogl_matrix_stack_push_entry (stack, &ctx->identity_entry); return _cogl_matrix_stack_object_new (stack); } static CoglMatrixEntry * _cogl_matrix_entry_skip_saves (CoglMatrixEntry *entry) { /* We currently assume that every stack starts with an * _OP_LOAD_IDENTITY so we don't need to worry about * NULL pointer dereferencing here. */ while (entry->op == COGL_MATRIX_OP_SAVE) entry = entry->parent; return entry; } CoglBool cogl_matrix_entry_calculate_translation (CoglMatrixEntry *entry0, CoglMatrixEntry *entry1, float *x, float *y, float *z) { GSList *head0 = NULL; GSList *head1 = NULL; CoglMatrixEntry *node0; CoglMatrixEntry *node1; int len0 = 0; int len1 = 0; int count; GSList *common_ancestor0; GSList *common_ancestor1; /* Algorithm: * * 1) Ignoring _OP_SAVE entries walk the ancestors of each entry to * the root node or any non-translation node, adding a pointer to * each ancestor node to two linked lists. * * 2) Compare the lists to find the nodes where they start to * differ marking the common_ancestor node for each list. * * 3) For the list corresponding to entry0, start iterating after * the common ancestor applying the negative of all translations * to x, y and z. * * 4) For the list corresponding to entry1, start iterating after * the common ancestor applying the positive of all translations * to x, y and z. * * If we come across any non-translation operations during 3) or 4) * then bail out returning FALSE. */ for (node0 = entry0; node0; node0 = node0->parent) { GSList *link; if (node0->op == COGL_MATRIX_OP_SAVE) continue; link = alloca (sizeof (GSList)); link->next = head0; link->data = node0; head0 = link; len0++; if (node0->op != COGL_MATRIX_OP_TRANSLATE) break; } for (node1 = entry1; node1; node1 = node1->parent) { GSList *link; if (node1->op == COGL_MATRIX_OP_SAVE) continue; link = alloca (sizeof (GSList)); link->next = head1; link->data = node1; head1 = link; len1++; if (node1->op != COGL_MATRIX_OP_TRANSLATE) break; } if (head0->data != head1->data) return FALSE; common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; count = MIN (len0, len1) - 1; while (count--) { if (head0->data != head1->data) break; common_ancestor0 = head0; common_ancestor1 = head1; head0 = head0->next; head1 = head1->next; } *x = 0; *y = 0; *z = 0; for (head0 = common_ancestor0->next; head0; head0 = head0->next) { CoglMatrixEntryTranslate *translate; node0 = head0->data; if (node0->op != COGL_MATRIX_OP_TRANSLATE) return FALSE; translate = (CoglMatrixEntryTranslate *)node0; *x = *x - translate->x; *y = *y - translate->y; *z = *z - translate->z; } for (head1 = common_ancestor1->next; head1; head1 = head1->next) { CoglMatrixEntryTranslate *translate; node1 = head1->data; if (node1->op != COGL_MATRIX_OP_TRANSLATE) return FALSE; translate = (CoglMatrixEntryTranslate *)node1; *x = *x + translate->x; *y = *y + translate->y; *z = *z + translate->z; } return TRUE; } CoglBool cogl_matrix_entry_is_identity (CoglMatrixEntry *entry) { return entry ? entry->op == COGL_MATRIX_OP_LOAD_IDENTITY : FALSE; } static void _cogl_matrix_flush_to_gl_builtin (CoglContext *ctx, CoglBool is_identity, CoglMatrix *matrix, CoglMatrixMode mode) { g_assert (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED)); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) if (ctx->flushed_matrix_mode != mode) { GLenum gl_mode = 0; switch (mode) { case COGL_MATRIX_MODELVIEW: gl_mode = GL_MODELVIEW; break; case COGL_MATRIX_PROJECTION: gl_mode = GL_PROJECTION; break; case COGL_MATRIX_TEXTURE: gl_mode = GL_TEXTURE; break; } GE (ctx, glMatrixMode (gl_mode)); ctx->flushed_matrix_mode = mode; } if (is_identity) GE (ctx, glLoadIdentity ()); else GE (ctx, glLoadMatrixf (cogl_matrix_get_array (matrix))); #endif } void _cogl_matrix_entry_flush_to_gl_builtins (CoglContext *ctx, CoglMatrixEntry *entry, CoglMatrixMode mode, CoglFramebuffer *framebuffer, CoglBool disable_flip) { g_assert (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED)); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) { CoglBool needs_flip; CoglMatrixEntryCache *cache; if (mode == COGL_MATRIX_PROJECTION) { /* Because Cogl defines texture coordinates to have a top left * origin and because offscreen framebuffers may be used for * rendering to textures we always render upside down to * offscreen buffers. Also for some backends we need to render * onscreen buffers upside-down too. */ if (disable_flip) needs_flip = FALSE; else needs_flip = cogl_is_offscreen (framebuffer); cache = &ctx->builtin_flushed_projection; } else { needs_flip = FALSE; if (mode == COGL_MATRIX_MODELVIEW) cache = &ctx->builtin_flushed_modelview; else cache = NULL; } /* We don't need to do anything if the state is the same */ if (!cache || _cogl_matrix_entry_cache_maybe_update (cache, entry, needs_flip)) { CoglBool is_identity; CoglMatrix matrix; if (entry->op == COGL_MATRIX_OP_LOAD_IDENTITY) is_identity = TRUE; else { is_identity = FALSE; cogl_matrix_entry_get (entry, &matrix); } if (needs_flip) { CoglMatrix flipped_matrix; cogl_matrix_multiply (&flipped_matrix, &ctx->y_flip_matrix, is_identity ? &ctx->identity_matrix : &matrix); _cogl_matrix_flush_to_gl_builtin (ctx, /* not identity */ FALSE, &flipped_matrix, mode); } else { _cogl_matrix_flush_to_gl_builtin (ctx, is_identity, &matrix, mode); } } } #endif } CoglBool cogl_matrix_entry_equal (CoglMatrixEntry *entry0, CoglMatrixEntry *entry1) { for (; entry0 && entry1; entry0 = entry0->parent, entry1 = entry1->parent) { entry0 = _cogl_matrix_entry_skip_saves (entry0); entry1 = _cogl_matrix_entry_skip_saves (entry1); if (entry0 == entry1) return TRUE; if (entry0->op != entry1->op) return FALSE; switch (entry0->op) { case COGL_MATRIX_OP_LOAD_IDENTITY: return TRUE; case COGL_MATRIX_OP_TRANSLATE: { CoglMatrixEntryTranslate *translate0 = (CoglMatrixEntryTranslate *)entry0; CoglMatrixEntryTranslate *translate1 = (CoglMatrixEntryTranslate *)entry1; /* We could perhaps use an epsilon to compare here? * I expect the false negatives are probaly never going to * be a problem and this is a bit cheaper. */ if (translate0->x != translate1->x || translate0->y != translate1->y || translate0->z != translate1->z) return FALSE; } break; case COGL_MATRIX_OP_ROTATE: { CoglMatrixEntryRotate *rotate0 = (CoglMatrixEntryRotate *)entry0; CoglMatrixEntryRotate *rotate1 = (CoglMatrixEntryRotate *)entry1; if (rotate0->angle != rotate1->angle || rotate0->x != rotate1->x || rotate0->y != rotate1->y || rotate0->z != rotate1->z) return FALSE; } break; case COGL_MATRIX_OP_ROTATE_QUATERNION: { CoglMatrixEntryRotateQuaternion *rotate0 = (CoglMatrixEntryRotateQuaternion *)entry0; CoglMatrixEntryRotateQuaternion *rotate1 = (CoglMatrixEntryRotateQuaternion *)entry1; int i; for (i = 0; i < 4; i++) if (rotate0->values[i] != rotate1->values[i]) return FALSE; } break; case COGL_MATRIX_OP_ROTATE_EULER: { CoglMatrixEntryRotateEuler *rotate0 = (CoglMatrixEntryRotateEuler *)entry0; CoglMatrixEntryRotateEuler *rotate1 = (CoglMatrixEntryRotateEuler *)entry1; if (rotate0->heading != rotate1->heading || rotate0->pitch != rotate1->pitch || rotate0->roll != rotate1->roll) return FALSE; } break; case COGL_MATRIX_OP_SCALE: { CoglMatrixEntryScale *scale0 = (CoglMatrixEntryScale *)entry0; CoglMatrixEntryScale *scale1 = (CoglMatrixEntryScale *)entry1; if (scale0->x != scale1->x || scale0->y != scale1->y || scale0->z != scale1->z) return FALSE; } break; case COGL_MATRIX_OP_MULTIPLY: { CoglMatrixEntryMultiply *mult0 = (CoglMatrixEntryMultiply *)entry0; CoglMatrixEntryMultiply *mult1 = (CoglMatrixEntryMultiply *)entry1; if (!cogl_matrix_equal (mult0->matrix, mult1->matrix)) return FALSE; } break; case COGL_MATRIX_OP_LOAD: { CoglMatrixEntryLoad *load0 = (CoglMatrixEntryLoad *)entry0; CoglMatrixEntryLoad *load1 = (CoglMatrixEntryLoad *)entry1; /* There's no need to check any further since an * _OP_LOAD makes all the ancestors redundant as far as * the final matrix value is concerned. */ return cogl_matrix_equal (load0->matrix, load1->matrix); } case COGL_MATRIX_OP_SAVE: /* We skip over saves above so we shouldn't see save entries */ g_warn_if_reached (); } } return FALSE; } void cogl_debug_matrix_entry_print (CoglMatrixEntry *entry) { int depth; CoglMatrixEntry *e; CoglMatrixEntry **children; int i; for (depth = 0, e = entry; e; e = e->parent) depth++; children = g_alloca (sizeof (CoglMatrixEntry) * depth); for (i = depth - 1, e = entry; i >= 0 && e; i--, e = e->parent) { children[i] = e; } g_print ("MatrixEntry %p =\n", entry); for (i = 0; i < depth; i++) { entry = children[i]; switch (entry->op) { case COGL_MATRIX_OP_LOAD_IDENTITY: g_print (" LOAD IDENTITY\n"); continue; case COGL_MATRIX_OP_TRANSLATE: { CoglMatrixEntryTranslate *translate = (CoglMatrixEntryTranslate *)entry; g_print (" TRANSLATE X=%f Y=%f Z=%f\n", translate->x, translate->y, translate->z); continue; } case COGL_MATRIX_OP_ROTATE: { CoglMatrixEntryRotate *rotate = (CoglMatrixEntryRotate *)entry; g_print (" ROTATE ANGLE=%f X=%f Y=%f Z=%f\n", rotate->angle, rotate->x, rotate->y, rotate->z); continue; } case COGL_MATRIX_OP_ROTATE_QUATERNION: { CoglMatrixEntryRotateQuaternion *rotate = (CoglMatrixEntryRotateQuaternion *)entry; g_print (" ROTATE QUATERNION w=%f x=%f y=%f z=%f\n", rotate->values[0], rotate->values[1], rotate->values[2], rotate->values[3]); continue; } case COGL_MATRIX_OP_ROTATE_EULER: { CoglMatrixEntryRotateEuler *rotate = (CoglMatrixEntryRotateEuler *)entry; g_print (" ROTATE EULER heading=%f pitch=%f roll=%f\n", rotate->heading, rotate->pitch, rotate->roll); continue; } case COGL_MATRIX_OP_SCALE: { CoglMatrixEntryScale *scale = (CoglMatrixEntryScale *)entry; g_print (" SCALE X=%f Y=%f Z=%f\n", scale->x, scale->y, scale->z); continue; } case COGL_MATRIX_OP_MULTIPLY: { CoglMatrixEntryMultiply *mult = (CoglMatrixEntryMultiply *)entry; g_print (" MULT:\n"); _cogl_matrix_prefix_print (" ", mult->matrix); continue; } case COGL_MATRIX_OP_LOAD: { CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)entry; g_print (" LOAD:\n"); _cogl_matrix_prefix_print (" ", load->matrix); continue; } case COGL_MATRIX_OP_SAVE: g_print (" SAVE\n"); } } } void _cogl_matrix_entry_cache_init (CoglMatrixEntryCache *cache) { cache->entry = NULL; cache->flushed_identity = FALSE; cache->flipped = FALSE; } /* NB: This function can report false negatives since it never does a * deep comparison of the stack matrices. */ CoglBool _cogl_matrix_entry_cache_maybe_update (CoglMatrixEntryCache *cache, CoglMatrixEntry *entry, CoglBool flip) { CoglBool is_identity; CoglBool updated = FALSE; if (cache->flipped != flip) { cache->flipped = flip; updated = TRUE; } is_identity = (entry->op == COGL_MATRIX_OP_LOAD_IDENTITY); if (cache->flushed_identity != is_identity) { cache->flushed_identity = is_identity; updated = TRUE; } if (cache->entry != entry) { cogl_matrix_entry_ref (entry); if (cache->entry) cogl_matrix_entry_unref (cache->entry); cache->entry = entry; /* We want to make sure here that if the cache->entry and the * given @entry are both identity matrices then even though they * are different entries we don't want to consider this an * update... */ updated |= !is_identity; } return updated; } void _cogl_matrix_entry_cache_destroy (CoglMatrixEntryCache *cache) { if (cache->entry) cogl_matrix_entry_unref (cache->entry); } muffin-5.2.1/cogl/cogl/cogl-feature-private.c0000664000175000017500000001745414211404421021210 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include "cogl-context-private.h" #include "cogl-feature-private.h" #include "cogl-renderer-private.h" #include "cogl-private.h" CoglBool _cogl_feature_check (CoglRenderer *renderer, const char *driver_prefix, const CoglFeatureData *data, int gl_major, int gl_minor, CoglDriver driver, char * const *extensions, void *function_table) { const char *suffix = NULL; int func_num; CoglExtGlesAvailability gles_availability = 0; CoglBool in_core; switch (driver) { case COGL_DRIVER_GLES1: gles_availability = COGL_EXT_IN_GLES; break; case COGL_DRIVER_GLES2: gles_availability = COGL_EXT_IN_GLES2; if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0)) gles_availability |= COGL_EXT_IN_GLES3; break; case COGL_DRIVER_ANY: g_assert_not_reached (); case COGL_DRIVER_WEBGL: /* FIXME: WebGL should probably have its own COGL_EXT_IN_WEBGL flag */ break; case COGL_DRIVER_NOP: case COGL_DRIVER_GL: case COGL_DRIVER_GL3: break; } /* First check whether the functions should be directly provided by GL */ if (((driver == COGL_DRIVER_GL || driver == COGL_DRIVER_GL3) && COGL_CHECK_GL_VERSION (gl_major, gl_minor, data->min_gl_major, data->min_gl_minor)) || (data->gles_availability & gles_availability)) { suffix = ""; in_core = TRUE; } else { /* Otherwise try all of the extensions */ const char *namespace, *namespace_suffix; unsigned int namespace_len; for (namespace = data->namespaces; *namespace; namespace += strlen (namespace) + 1) { const char *extension; GString *full_extension_name = g_string_new (""); /* If the namespace part contains a ':' then the suffix for the function names is different from the name space */ if ((namespace_suffix = strchr (namespace, ':'))) { namespace_len = namespace_suffix - namespace; namespace_suffix++; } else { namespace_len = strlen (namespace); namespace_suffix = namespace; } for (extension = data->extension_names; *extension; extension += strlen (extension) + 1) { g_string_assign (full_extension_name, driver_prefix); g_string_append_c (full_extension_name, '_'); g_string_append_len (full_extension_name, namespace, namespace_len); g_string_append_c (full_extension_name, '_'); g_string_append (full_extension_name, extension); if (_cogl_check_extension (full_extension_name->str, extensions)) break; } g_string_free (full_extension_name, TRUE); /* If we found an extension with this namespace then use it as the suffix */ if (*extension) { suffix = namespace_suffix; break; } } in_core = FALSE; } /* If we couldn't find anything that provides the functions then give up */ if (suffix == NULL) goto error; /* Try to get all of the entry points */ for (func_num = 0; data->functions[func_num].name; func_num++) { void *func; char *full_function_name; full_function_name = g_strconcat (data->functions[func_num].name, suffix, NULL); func = _cogl_renderer_get_proc_address (renderer, full_function_name, in_core); free (full_function_name); if (func == NULL) goto error; /* Set the function pointer in the context */ *(void **) ((uint8_t *) function_table + data->functions[func_num].pointer_offset) = func; } return TRUE; /* If the extension isn't found or one of the functions wasn't found * then set all of the functions pointers to NULL so Cogl can safely * do feature testing by just looking at the function pointers */ error: for (func_num = 0; data->functions[func_num].name; func_num++) *(void **) ((uint8_t *) function_table + data->functions[func_num].pointer_offset) = NULL; return FALSE; } /* Define a set of arrays containing the functions required from GL for each feature */ #define COGL_EXT_BEGIN(name, \ min_gl_major, min_gl_minor, \ gles_availability, \ namespaces, extension_names) \ static const CoglFeatureFunction cogl_ext_ ## name ## _funcs[] = { #define COGL_EXT_FUNCTION(ret, name, args) \ { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglContext, name) }, #define COGL_EXT_END() \ { NULL, 0 }, \ }; #include "gl-prototypes/cogl-all-functions.h" /* Define an array of features */ #undef COGL_EXT_BEGIN #define COGL_EXT_BEGIN(name, \ min_gl_major, min_gl_minor, \ gles_availability, \ namespaces, extension_names) \ { min_gl_major, min_gl_minor, gles_availability, namespaces, \ extension_names, 0, 0, 0, \ cogl_ext_ ## name ## _funcs }, #undef COGL_EXT_FUNCTION #define COGL_EXT_FUNCTION(ret, name, args) #undef COGL_EXT_END #define COGL_EXT_END() static const CoglFeatureData cogl_feature_ext_functions_data[] = { #include "gl-prototypes/cogl-all-functions.h" }; void _cogl_feature_check_ext_functions (CoglContext *context, int gl_major, int gl_minor, char * const *gl_extensions) { int i; for (i = 0; i < G_N_ELEMENTS (cogl_feature_ext_functions_data); i++) _cogl_feature_check (context->display->renderer, "GL", cogl_feature_ext_functions_data + i, gl_major, gl_minor, context->driver, gl_extensions, context); } muffin-5.2.1/cogl/cogl/cogl-texture-2d-gl.h0000664000175000017500000000517414211404421020511 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef _COGL_TEXTURE_2D_GL_H_ #define _COGL_TEXTURE_2D_GL_H_ #include "cogl-context.h" #include "cogl-texture-2d.h" COGL_BEGIN_DECLS /** * cogl_texture_2d_gl_new_from_foreign: * @ctx: A #CoglContext * @gl_handle: A GL handle for a GL_TEXTURE_2D texture object * @width: Width of the foreign GL texture * @height: Height of the foreign GL texture * @format: The format of the texture * * Wraps an existing GL_TEXTURE_2D texture object as a #CoglTexture2D. * This can be used for integrating Cogl with software using OpenGL * directly. * * The texture is still configurable until it has been allocated so * for example you can declare whether the texture is premultiplied * with cogl_texture_set_premultiplied(). * * The results are undefined for passing an invalid @gl_handle * or if @width or @height don't have the correct texture * geometry. * * Returns: (transfer full): A newly allocated #CoglTexture2D * * Since: 2.0 */ CoglTexture2D * cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx, unsigned int gl_handle, int width, int height, CoglPixelFormat format); COGL_END_DECLS #endif /* _COGL_TEXTURE_2D_GL_H_ */ muffin-5.2.1/cogl/cogl/cogl-texture-2d.h0000664000175000017500000002363414211404421020112 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011,2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * Authors: * Robert Bragg */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_TEXTURE_2D_H #define __COGL_TEXTURE_2D_H #include "cogl-context.h" #include "cogl-bitmap.h" #ifdef COGL_HAS_EGL_SUPPORT #include "cogl-egl-defines.h" #endif COGL_BEGIN_DECLS /** * SECTION:cogl-texture-2d * @short_description: Functions for creating and manipulating 2D textures * * These functions allow low-level 2D textures to be allocated. These * differ from sliced textures for example which may internally be * made up of multiple 2D textures, or atlas textures where Cogl must * internally modify user texture coordinates before they can be used * by the GPU. * * You should be aware that many GPUs only support power of two sizes * for #CoglTexture2D textures. You can check support for non power of * two textures by checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature * via cogl_has_feature(). */ typedef struct _CoglTexture2D CoglTexture2D; #define COGL_TEXTURE_2D(X) ((CoglTexture2D *)X) /** * cogl_texture_2d_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_texture_2d_get_gtype (void); /** * cogl_is_texture_2d: * @object: A #CoglObject * * Gets whether the given object references an existing #CoglTexture2D * object. * * Return value: %TRUE if the object references a #CoglTexture2D, * %FALSE otherwise */ CoglBool cogl_is_texture_2d (void *object); /** * cogl_texture_2d_new_with_size: * @ctx: A #CoglContext * @width: Width of the texture to allocate * @height: Height of the texture to allocate * * Creates a low-level #CoglTexture2D texture with a given @width and * @height that your GPU can texture from directly. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is being used and can optimize how it is allocated. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * Many GPUs only support power of two sizes for #CoglTexture2D * textures. You can check support for non power of two textures by * checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via * cogl_has_feature(). * * Returns: (transfer full): A new #CoglTexture2D object with no storage yet allocated. * * Since: 2.0 */ CoglTexture2D * cogl_texture_2d_new_with_size (CoglContext *ctx, int width, int height); /** * cogl_texture_2d_new_from_file: * @ctx: A #CoglContext * @filename: the file to load * @error: A #CoglError to catch exceptional errors or %NULL * * Creates a low-level #CoglTexture2D texture from an image file. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is being used and can optimize how it is allocated. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * Many GPUs only support power of two sizes for #CoglTexture2D * textures. You can check support for non power of two textures by * checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via * cogl_has_feature(). * * Return value: (transfer full): A newly created #CoglTexture2D or %NULL on failure * and @error will be updated. * * Since: 1.16 */ CoglTexture2D * cogl_texture_2d_new_from_file (CoglContext *ctx, const char *filename, CoglError **error); /** * cogl_texture_2d_new_from_data: * @ctx: A #CoglContext * @width: width of texture in pixels * @height: height of texture in pixels * @format: the #CoglPixelFormat the buffer is stored in in RAM * @rowstride: the memory offset in bytes between the starts of * scanlines in @data. A value of 0 will make Cogl automatically * calculate @rowstride from @width and @format. * @data: pointer the memory region where the source buffer resides * @error: A #CoglError for exceptions * * Creates a low-level #CoglTexture2D texture based on data residing * in memory. * * This api will always immediately allocate GPU memory for the * texture and upload the given data so that the @data pointer does * not need to remain valid once this function returns. This means it * is not possible to configure the texture before it is allocated. If * you do need to configure the texture before allocation (to specify * constraints on the internal format for example) then you can * instead create a #CoglBitmap for your data and use * cogl_texture_2d_new_from_bitmap() or use * cogl_texture_2d_new_with_size() and then upload data using * cogl_texture_set_data() * * Many GPUs only support power of two sizes for #CoglTexture2D * textures. You can check support for non power of two textures by * checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via * cogl_has_feature(). * * Returns: (transfer full): A newly allocated #CoglTexture2D, or if * the size is not supported (because it is too large or a * non-power-of-two size that the hardware doesn't support) * it will return %NULL and set @error. * * Since: 2.0 */ CoglTexture2D * cogl_texture_2d_new_from_data (CoglContext *ctx, int width, int height, CoglPixelFormat format, int rowstride, const uint8_t *data, CoglError **error); /** * cogl_texture_2d_new_from_bitmap: * @bitmap: A #CoglBitmap * * Creates a low-level #CoglTexture2D texture based on data residing * in a #CoglBitmap. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is being used and can optimize how it is allocated. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * Many GPUs only support power of two sizes for #CoglTexture2D * textures. You can check support for non power of two textures by * checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via * cogl_has_feature(). * * Returns: (transfer full): A newly allocated #CoglTexture2D * * Since: 2.0 * Stability: unstable */ CoglTexture2D * cogl_texture_2d_new_from_bitmap (CoglBitmap *bitmap); #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) /* NB: The reason we require the width, height and format to be passed * even though they may seem redundant is because GLES 1/2 don't * provide a way to query these properties. */ CoglTexture2D * cogl_egl_texture_2d_new_from_image (CoglContext *ctx, int width, int height, CoglPixelFormat format, EGLImageKHR image, CoglError **error); typedef gboolean (*CoglTexture2DEGLImageExternalAlloc) (CoglTexture2D *tex_2d, gpointer user_data, GError **error); CoglTexture2D * cogl_texture_2d_new_from_egl_image_external (CoglContext *ctx, int width, int height, CoglTexture2DEGLImageExternalAlloc alloc, gpointer user_data, GDestroyNotify destroy, CoglError **error); void cogl_texture_2d_egl_image_external_bind (CoglTexture2D *tex_2d); void cogl_texture_2d_egl_image_external_alloc_finish (CoglTexture2D *tex_2d, void *user_data, GDestroyNotify destroy); #endif COGL_END_DECLS #endif /* __COGL_TEXTURE_2D_H */ muffin-5.2.1/cogl/cogl/cogl-atlas-texture.h0000664000175000017500000002217014211404421020703 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2013 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef _COGL_ATLAS_TEXTURE_H_ #define _COGL_ATLAS_TEXTURE_H_ #include #include COGL_BEGIN_DECLS /** * SECTION:cogl-atlas-texture * @short_description: Functions for managing textures in Cogl's global * set of texture atlases * * A texture atlas is a texture that contains many smaller images that * an application is interested in. These are packed together as a way * of optimizing drawing with those images by avoiding the costs of * repeatedly telling the hardware to change what texture it should * sample from. This can enable more geometry to be batched together * into few draw calls. * * Each #CoglContext has an shared, pool of texture atlases that are * are managed by Cogl. * * This api lets applications upload texture data into one of Cogl's * shared texture atlases using a high-level #CoglAtlasTexture which * represents a sub-region of one of these atlases. * * A #CoglAtlasTexture is a high-level meta texture which has * some limitations to be aware of. Please see the documentation for * #CoglMetaTexture for more details. */ typedef struct _CoglAtlasTexture CoglAtlasTexture; #define COGL_ATLAS_TEXTURE(tex) ((CoglAtlasTexture *) tex) /** * cogl_atlas_texture_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_atlas_texture_get_gtype (void); /** * cogl_atlas_texture_new_with_size: * @ctx: A #CoglContext * @width: The width of your atlased texture. * @height: The height of your atlased texture. * * Creates a #CoglAtlasTexture with a given @width and @height. A * #CoglAtlasTexture represents a sub-region within one of Cogl's * shared texture atlases. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or let Cogl automatically allocate * storage lazily. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * Allocate call can fail if Cogl considers the internal * format to be incompatible with the format of its internal * atlases. * * The returned #CoglAtlasTexture is a high-level meta-texture * with some limitations. See the documentation for #CoglMetaTexture * for more details. * * Returns: (transfer full): A new #CoglAtlasTexture object. * Since: 1.16 * Stability: unstable */ CoglAtlasTexture * cogl_atlas_texture_new_with_size (CoglContext *ctx, int width, int height); /** * cogl_atlas_texture_new_from_file: * @ctx: A #CoglContext * @filename: the file to load * @error: A #CoglError to catch exceptional errors or %NULL * * Creates a #CoglAtlasTexture from an image file. A #CoglAtlasTexture * represents a sub-region within one of Cogl's shared texture * atlases. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or let Cogl automatically allocate * storage lazily. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * Allocate call can fail if Cogl considers the internal * format to be incompatible with the format of its internal * atlases. * * The returned #CoglAtlasTexture is a high-level meta-texture * with some limitations. See the documentation for #CoglMetaTexture * for more details. * * Return value: (transfer full): A new #CoglAtlasTexture object or * %NULL on failure and @error will be updated. * Since: 1.16 * Stability: unstable */ CoglAtlasTexture * cogl_atlas_texture_new_from_file (CoglContext *ctx, const char *filename, CoglError **error); /** * cogl_atlas_texture_new_from_data: * @ctx: A #CoglContext * @width: width of texture in pixels * @height: height of texture in pixels * @format: the #CoglPixelFormat the buffer is stored in in RAM * @rowstride: the memory offset in bytes between the start of each * row in @data. A value of 0 will make Cogl automatically * calculate @rowstride from @width and @format. * @data: pointer to the memory region where the source buffer resides * @error: A #CoglError to catch exceptional errors or %NULL * * Creates a new #CoglAtlasTexture texture based on data residing in * memory. A #CoglAtlasTexture represents a sub-region within one of * Cogl's shared texture atlases. * * This api will always immediately allocate GPU memory for the * texture and upload the given data so that the @data pointer does * not need to remain valid once this function returns. This means it * is not possible to configure the texture before it is allocated. If * you do need to configure the texture before allocation (to specify * constraints on the internal format for example) then you can * instead create a #CoglBitmap for your data and use * cogl_atlas_texture_new_from_bitmap() or use * cogl_atlas_texture_new_with_size() and then upload data using * cogl_texture_set_data() * * Allocate call can fail if Cogl considers the internal * format to be incompatible with the format of its internal * atlases. * * The returned #CoglAtlasTexture is a high-level * meta-texture with some limitations. See the documentation for * #CoglMetaTexture for more details. * * Return value: (transfer full): A new #CoglAtlasTexture object or * %NULL on failure and @error will be updated. * Since: 1.16 * Stability: unstable */ CoglAtlasTexture * cogl_atlas_texture_new_from_data (CoglContext *ctx, int width, int height, CoglPixelFormat format, int rowstride, const uint8_t *data, CoglError **error); /** * cogl_atlas_texture_new_from_bitmap: * @bitmap: A #CoglBitmap * * Creates a new #CoglAtlasTexture texture based on data residing in a * @bitmap. A #CoglAtlasTexture represents a sub-region within one of * Cogl's shared texture atlases. * * The storage for the texture is not allocated before this function * returns. You can call cogl_texture_allocate() to explicitly * allocate the underlying storage or preferably let Cogl * automatically allocate storage lazily when it may know more about * how the texture is being used and can optimize how it is allocated. * * The texture is still configurable until it has been allocated so * for example you can influence the internal format of the texture * using cogl_texture_set_components() and * cogl_texture_set_premultiplied(). * * Allocate call can fail if Cogl considers the internal * format to be incompatible with the format of its internal * atlases. * * The returned #CoglAtlasTexture is a high-level meta-texture * with some limitations. See the documentation for #CoglMetaTexture * for more details. * * Returns: (transfer full): A new #CoglAtlasTexture object. * Since: 1.16 * Stability: unstable */ CoglAtlasTexture * cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp); /** * cogl_is_atlas_texture: * @object: a #CoglObject * * Checks whether the given object references a #CoglAtlasTexture * * Return value: %TRUE if the passed object represents an atlas * texture and %FALSE otherwise * * Since: 1.16 * Stability: Unstable */ CoglBool cogl_is_atlas_texture (void *object); COGL_END_DECLS #endif /* _COGL_ATLAS_TEXTURE_H_ */ muffin-5.2.1/cogl/cogl/cogl-clip-stack.c0000664000175000017500000003073314211404421020132 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include "cogl-clip-stack.h" #include "cogl-primitives.h" #include "cogl-context-private.h" #include "cogl-framebuffer-private.h" #include "cogl-journal-private.h" #include "cogl-util.h" #include "cogl-matrix-private.h" #include "cogl-primitives-private.h" #include "cogl-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-attribute-private.h" #include "cogl-primitive-private.h" #include "cogl1-context.h" #include "cogl-offscreen.h" #include "cogl-matrix-stack.h" static void * _cogl_clip_stack_push_entry (CoglClipStack *clip_stack, size_t size, CoglClipStackType type) { CoglClipStack *entry = g_slice_alloc (size); /* The new entry starts with a ref count of 1 because the stack holds a reference to it as it is the top entry */ entry->ref_count = 1; entry->type = type; entry->parent = clip_stack; /* We don't need to take a reference to the parent from the entry because the we are stealing the ref in the new stack top */ return entry; } static void get_transformed_corners (float x_1, float y_1, float x_2, float y_2, CoglMatrix *modelview, CoglMatrix *projection, const float *viewport, float *transformed_corners) { int i; transformed_corners[0] = x_1; transformed_corners[1] = y_1; transformed_corners[2] = x_2; transformed_corners[3] = y_1; transformed_corners[4] = x_2; transformed_corners[5] = y_2; transformed_corners[6] = x_1; transformed_corners[7] = y_2; /* Project the coordinates to window space coordinates */ for (i = 0; i < 4; i++) { float *v = transformed_corners + i * 2; _cogl_transform_point (modelview, projection, viewport, v, v + 1); } } /* Sets the window-space bounds of the entry based on the projected coordinates of the given rectangle */ static void _cogl_clip_stack_entry_set_bounds (CoglClipStack *entry, float *transformed_corners) { float min_x = G_MAXFLOAT, min_y = G_MAXFLOAT; float max_x = -G_MAXFLOAT, max_y = -G_MAXFLOAT; int i; for (i = 0; i < 4; i++) { float *v = transformed_corners + i * 2; if (v[0] > max_x) max_x = v[0]; if (v[0] < min_x) min_x = v[0]; if (v[1] > max_y) max_y = v[1]; if (v[1] < min_y) min_y = v[1]; } entry->bounds_x0 = floorf (min_x); entry->bounds_x1 = ceilf (max_x); entry->bounds_y0 = floorf (min_y); entry->bounds_y1 = ceilf (max_y); } CoglClipStack * _cogl_clip_stack_push_window_rectangle (CoglClipStack *stack, int x_offset, int y_offset, int width, int height) { CoglClipStack *entry; entry = _cogl_clip_stack_push_entry (stack, sizeof (CoglClipStackWindowRect), COGL_CLIP_STACK_WINDOW_RECT); entry->bounds_x0 = x_offset; entry->bounds_x1 = x_offset + width; entry->bounds_y0 = y_offset; entry->bounds_y1 = y_offset + height; return entry; } CoglClipStack * _cogl_clip_stack_push_rectangle (CoglClipStack *stack, float x_1, float y_1, float x_2, float y_2, CoglMatrixEntry *modelview_entry, CoglMatrixEntry *projection_entry, const float *viewport) { CoglClipStackRect *entry; CoglMatrix modelview; CoglMatrix projection; CoglMatrix modelview_projection; /* Corners of the given rectangle in an clockwise order: * (0, 1) (2, 3) * * * * (6, 7) (4, 5) */ float rect[] = { x_1, y_1, x_2, y_1, x_2, y_2, x_1, y_2 }; /* Make a new entry */ entry = _cogl_clip_stack_push_entry (stack, sizeof (CoglClipStackRect), COGL_CLIP_STACK_RECT); entry->x0 = x_1; entry->y0 = y_1; entry->x1 = x_2; entry->y1 = y_2; entry->matrix_entry = cogl_matrix_entry_ref (modelview_entry); cogl_matrix_entry_get (modelview_entry, &modelview); cogl_matrix_entry_get (projection_entry, &projection); cogl_matrix_multiply (&modelview_projection, &projection, &modelview); /* Technically we could avoid the viewport transform at this point * if we want to make this a bit faster. */ _cogl_transform_point (&modelview, &projection, viewport, &rect[0], &rect[1]); _cogl_transform_point (&modelview, &projection, viewport, &rect[2], &rect[3]); _cogl_transform_point (&modelview, &projection, viewport, &rect[4], &rect[5]); _cogl_transform_point (&modelview, &projection, viewport, &rect[6], &rect[7]); /* If the fully transformed rectangle isn't still axis aligned we * can't handle it using a scissor. * * We don't use an epsilon here since we only really aim to catch * simple cases where the transform doesn't leave the rectangle screen * aligned and don't mind some false positives. */ if (rect[0] != rect[6] || rect[1] != rect[3] || rect[2] != rect[4] || rect[7] != rect[5]) { entry->can_be_scissor = FALSE; _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry, rect); } else { CoglClipStack *base_entry = (CoglClipStack *) entry; x_1 = rect[0]; y_1 = rect[1]; x_2 = rect[4]; y_2 = rect[5]; /* Consider that the modelview matrix may flip the rectangle * along the x or y axis... */ #define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0) if (x_1 > x_2) SWAP (x_1, x_2); if (y_1 > y_2) SWAP (y_1, y_2); #undef SWAP base_entry->bounds_x0 = COGL_UTIL_NEARBYINT (x_1); base_entry->bounds_y0 = COGL_UTIL_NEARBYINT (y_1); base_entry->bounds_x1 = COGL_UTIL_NEARBYINT (x_2); base_entry->bounds_y1 = COGL_UTIL_NEARBYINT (y_2); entry->can_be_scissor = TRUE; } return (CoglClipStack *) entry; } CoglClipStack * _cogl_clip_stack_push_primitive (CoglClipStack *stack, CoglPrimitive *primitive, float bounds_x1, float bounds_y1, float bounds_x2, float bounds_y2, CoglMatrixEntry *modelview_entry, CoglMatrixEntry *projection_entry, const float *viewport) { CoglClipStackPrimitive *entry; CoglMatrix modelview; CoglMatrix projection; float transformed_corners[8]; entry = _cogl_clip_stack_push_entry (stack, sizeof (CoglClipStackPrimitive), COGL_CLIP_STACK_PRIMITIVE); entry->primitive = cogl_object_ref (primitive); entry->matrix_entry = cogl_matrix_entry_ref (modelview_entry); entry->bounds_x1 = bounds_x1; entry->bounds_y1 = bounds_y1; entry->bounds_x2 = bounds_x2; entry->bounds_y2 = bounds_y2; cogl_matrix_entry_get (modelview_entry, &modelview); cogl_matrix_entry_get (projection_entry, &projection); get_transformed_corners (bounds_x1, bounds_y1, bounds_x2, bounds_y2, &modelview, &projection, viewport, transformed_corners); /* NB: this is referring to the bounds in window coordinates as opposed * to the bounds above in primitive local coordinates. */ _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry, transformed_corners); return (CoglClipStack *) entry; } CoglClipStack * _cogl_clip_stack_ref (CoglClipStack *entry) { /* A NULL pointer is considered a valid stack so we should accept that as an argument */ if (entry) entry->ref_count++; return entry; } void _cogl_clip_stack_unref (CoglClipStack *entry) { /* Unref all of the entries until we hit the root of the list or the entry still has a remaining reference */ while (entry && --entry->ref_count <= 0) { CoglClipStack *parent = entry->parent; switch (entry->type) { case COGL_CLIP_STACK_RECT: { CoglClipStackRect *rect = (CoglClipStackRect *) entry; cogl_matrix_entry_unref (rect->matrix_entry); g_slice_free1 (sizeof (CoglClipStackRect), entry); break; } case COGL_CLIP_STACK_WINDOW_RECT: g_slice_free1 (sizeof (CoglClipStackWindowRect), entry); break; case COGL_CLIP_STACK_PRIMITIVE: { CoglClipStackPrimitive *primitive_entry = (CoglClipStackPrimitive *) entry; cogl_matrix_entry_unref (primitive_entry->matrix_entry); cogl_object_unref (primitive_entry->primitive); g_slice_free1 (sizeof (CoglClipStackPrimitive), entry); break; } default: g_assert_not_reached (); } entry = parent; } } CoglClipStack * _cogl_clip_stack_pop (CoglClipStack *stack) { CoglClipStack *new_top; _COGL_RETURN_VAL_IF_FAIL (stack != NULL, NULL); /* To pop we are moving the top of the stack to the old top's parent node. The stack always needs to have a reference to the top entry so we must take a reference to the new top. The stack would have previously had a reference to the old top so we need to decrease the ref count on that. We need to ref the new head first in case this stack was the only thing referencing the old top. In that case the call to _cogl_clip_stack_entry_unref will unref the parent. */ new_top = stack->parent; _cogl_clip_stack_ref (new_top); _cogl_clip_stack_unref (stack); return new_top; } void _cogl_clip_stack_get_bounds (CoglClipStack *stack, int *scissor_x0, int *scissor_y0, int *scissor_x1, int *scissor_y1) { CoglClipStack *entry; *scissor_x0 = 0; *scissor_y0 = 0; *scissor_x1 = G_MAXINT; *scissor_y1 = G_MAXINT; for (entry = stack; entry; entry = entry->parent) { /* Get the intersection of the current scissor and the bounding box of this clip */ _cogl_util_scissor_intersect (entry->bounds_x0, entry->bounds_y0, entry->bounds_x1, entry->bounds_y1, scissor_x0, scissor_y0, scissor_x1, scissor_y1); } } void _cogl_clip_stack_flush (CoglClipStack *stack, CoglFramebuffer *framebuffer) { CoglContext *ctx = framebuffer->context; ctx->driver_vtable->clip_stack_flush (stack, framebuffer); } muffin-5.2.1/cogl/cogl/cogl-pipeline-state.h0000664000175000017500000007773114211404421021041 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PIPELINE_STATE_H__ #define __COGL_PIPELINE_STATE_H__ #include #include #include COGL_BEGIN_DECLS /** * cogl_pipeline_set_color: * @pipeline: A #CoglPipeline object * @color: The components of the color * * Sets the basic color of the pipeline, used when no lighting is enabled. * * Note that if you don't add any layers to the pipeline then the color * will be blended unmodified with the destination; the default blend * expects premultiplied colors: for example, use (0.5, 0.0, 0.0, 0.5) for * semi-transparent red. See cogl_color_premultiply(). * * The default value is (1.0, 1.0, 1.0, 1.0) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_color (CoglPipeline *pipeline, const CoglColor *color); /** * cogl_pipeline_set_color4ub: * @pipeline: A #CoglPipeline object * @red: The red component * @green: The green component * @blue: The blue component * @alpha: The alpha component * * Sets the basic color of the pipeline, used when no lighting is enabled. * * The default value is (0xff, 0xff, 0xff, 0xff) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_color4ub (CoglPipeline *pipeline, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); /** * cogl_pipeline_set_color4f: * @pipeline: A #CoglPipeline object * @red: The red component * @green: The green component * @blue: The blue component * @alpha: The alpha component * * Sets the basic color of the pipeline, used when no lighting is enabled. * * The default value is (1.0, 1.0, 1.0, 1.0) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_color4f (CoglPipeline *pipeline, float red, float green, float blue, float alpha); /** * cogl_pipeline_get_color: * @pipeline: A #CoglPipeline object * @color: (out): The location to store the color * * Retrieves the current pipeline color. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_get_color (CoglPipeline *pipeline, CoglColor *color); /** * cogl_pipeline_set_ambient: * @pipeline: A #CoglPipeline object * @ambient: The components of the desired ambient color * * Sets the pipeline's ambient color, in the standard OpenGL lighting * model. The ambient color affects the overall color of the object. * * Since the diffuse color will be intense when the light hits the surface * directly, the ambient will be most apparent where the light hits at a * slant. * * The default value is (0.2, 0.2, 0.2, 1.0) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_ambient (CoglPipeline *pipeline, const CoglColor *ambient); /** * cogl_pipeline_get_ambient: * @pipeline: A #CoglPipeline object * @ambient: The location to store the ambient color * * Retrieves the current ambient color for @pipeline * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_get_ambient (CoglPipeline *pipeline, CoglColor *ambient); /** * cogl_pipeline_set_diffuse: * @pipeline: A #CoglPipeline object * @diffuse: The components of the desired diffuse color * * Sets the pipeline's diffuse color, in the standard OpenGL lighting * model. The diffuse color is most intense where the light hits the * surface directly - perpendicular to the surface. * * The default value is (0.8, 0.8, 0.8, 1.0) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_diffuse (CoglPipeline *pipeline, const CoglColor *diffuse); /** * cogl_pipeline_get_diffuse: * @pipeline: A #CoglPipeline object * @diffuse: The location to store the diffuse color * * Retrieves the current diffuse color for @pipeline * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_get_diffuse (CoglPipeline *pipeline, CoglColor *diffuse); /** * cogl_pipeline_set_ambient_and_diffuse: * @pipeline: A #CoglPipeline object * @color: The components of the desired ambient and diffuse colors * * Conveniently sets the diffuse and ambient color of @pipeline at the same * time. See cogl_pipeline_set_ambient() and cogl_pipeline_set_diffuse(). * * The default ambient color is (0.2, 0.2, 0.2, 1.0) * * The default diffuse color is (0.8, 0.8, 0.8, 1.0) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline, const CoglColor *color); /** * cogl_pipeline_set_specular: * @pipeline: A #CoglPipeline object * @specular: The components of the desired specular color * * Sets the pipeline's specular color, in the standard OpenGL lighting * model. The intensity of the specular color depends on the viewport * position, and is brightest along the lines of reflection. * * The default value is (0.0, 0.0, 0.0, 1.0) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_specular (CoglPipeline *pipeline, const CoglColor *specular); /** * cogl_pipeline_get_specular: * @pipeline: A #CoglPipeline object * @specular: The location to store the specular color * * Retrieves the pipelines current specular color. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_get_specular (CoglPipeline *pipeline, CoglColor *specular); /** * cogl_pipeline_set_shininess: * @pipeline: A #CoglPipeline object * @shininess: The desired shininess; must be >= 0.0 * * Sets the shininess of the pipeline, in the standard OpenGL lighting * model, which determines the size of the specular highlights. A * higher @shininess will produce smaller highlights which makes the * object appear more shiny. * * The default value is 0.0 * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_shininess (CoglPipeline *pipeline, float shininess); /** * cogl_pipeline_get_shininess: * @pipeline: A #CoglPipeline object * * Retrieves the pipelines current emission color. * * Return value: The pipelines current shininess value * * Since: 2.0 * Stability: Unstable */ float cogl_pipeline_get_shininess (CoglPipeline *pipeline); /** * cogl_pipeline_set_emission: * @pipeline: A #CoglPipeline object * @emission: The components of the desired emissive color * * Sets the pipeline's emissive color, in the standard OpenGL lighting * model. It will look like the surface is a light source emitting this * color. * * The default value is (0.0, 0.0, 0.0, 1.0) * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_emission (CoglPipeline *pipeline, const CoglColor *emission); /** * cogl_pipeline_get_emission: * @pipeline: A #CoglPipeline object * @emission: The location to store the emission color * * Retrieves the pipelines current emission color. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_get_emission (CoglPipeline *pipeline, CoglColor *emission); /** * CoglPipelineAlphaFunc: * @COGL_PIPELINE_ALPHA_FUNC_NEVER: Never let the fragment through. * @COGL_PIPELINE_ALPHA_FUNC_LESS: Let the fragment through if the incoming * alpha value is less than the reference alpha value * @COGL_PIPELINE_ALPHA_FUNC_EQUAL: Let the fragment through if the incoming * alpha value equals the reference alpha value * @COGL_PIPELINE_ALPHA_FUNC_LEQUAL: Let the fragment through if the incoming * alpha value is less than or equal to the reference alpha value * @COGL_PIPELINE_ALPHA_FUNC_GREATER: Let the fragment through if the incoming * alpha value is greater than the reference alpha value * @COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL: Let the fragment through if the incoming * alpha value does not equal the reference alpha value * @COGL_PIPELINE_ALPHA_FUNC_GEQUAL: Let the fragment through if the incoming * alpha value is greater than or equal to the reference alpha value. * @COGL_PIPELINE_ALPHA_FUNC_ALWAYS: Always let the fragment through. * * Alpha testing happens before blending primitives with the framebuffer and * gives an opportunity to discard fragments based on a comparison with the * incoming alpha value and a reference alpha value. The #CoglPipelineAlphaFunc * determines how the comparison is done. */ typedef enum { COGL_PIPELINE_ALPHA_FUNC_NEVER = 0x0200, COGL_PIPELINE_ALPHA_FUNC_LESS = 0x0201, COGL_PIPELINE_ALPHA_FUNC_EQUAL = 0x0202, COGL_PIPELINE_ALPHA_FUNC_LEQUAL = 0x0203, COGL_PIPELINE_ALPHA_FUNC_GREATER = 0x0204, COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL = 0x0205, COGL_PIPELINE_ALPHA_FUNC_GEQUAL = 0x0206, COGL_PIPELINE_ALPHA_FUNC_ALWAYS = 0x0207 } CoglPipelineAlphaFunc; /* NB: these values come from the equivalents in gl.h */ /** * cogl_pipeline_set_alpha_test_function: * @pipeline: A #CoglPipeline object * @alpha_func: A @CoglPipelineAlphaFunc constant * @alpha_reference: A reference point that the chosen alpha function uses * to compare incoming fragments to. * * Before a primitive is blended with the framebuffer, it goes through an * alpha test stage which lets you discard fragments based on the current * alpha value. This function lets you change the function used to evaluate * the alpha channel, and thus determine which fragments are discarded * and which continue on to the blending stage. * * The default is %COGL_PIPELINE_ALPHA_FUNC_ALWAYS * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, CoglPipelineAlphaFunc alpha_func, float alpha_reference); /** * cogl_pipeline_get_alpha_test_function: * @pipeline: A #CoglPipeline object * * Return value: The alpha test function of @pipeline. * * Since: 2.0 * Stability: Unstable */ CoglPipelineAlphaFunc cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline); /** * cogl_pipeline_get_alpha_test_reference: * @pipeline: A #CoglPipeline object * * Return value: The alpha test reference value of @pipeline. * * Since: 2.0 * Stability: Unstable */ float cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline); /** * cogl_pipeline_set_blend: * @pipeline: A #CoglPipeline object * @blend_string: A Cogl blend string * describing the desired blend function. * @error: return location for a #CoglError that may report lack of driver * support if you give separate blend string statements for the alpha * channel and RGB channels since some drivers, or backends such as * GLES 1.1, don't support this feature. May be %NULL, in which case a * warning will be printed out using GLib's logging facilities if an * error is encountered. * * If not already familiar; please refer here * for an overview of what blend strings are, and their syntax. * * Blending occurs after the alpha test function, and combines fragments with * the framebuffer. * Currently the only blend function Cogl exposes is ADD(). So any valid * blend statements will be of the form: * * |[ * <channel-mask>=ADD(SRC_COLOR*(<factor>), DST_COLOR*(<factor>)) * ]| * * This is the list of source-names usable as blend factors: * * SRC_COLOR: The color of the in comming fragment * DST_COLOR: The color of the framebuffer * CONSTANT: The constant set via cogl_pipeline_set_blend_constant() * * * The source names can be used according to the * color-source and factor syntax, * so for example "(1-SRC_COLOR[A])" would be a valid factor, as would * "(CONSTANT[RGB])" * * These can also be used as factors: * * 0: (0, 0, 0, 0) * 1: (1, 1, 1, 1) * SRC_ALPHA_SATURATE_FACTOR: (f,f,f,1) where f = MIN(SRC_COLOR[A],1-DST_COLOR[A]) * * * Remember; all color components are normalized to the range [0, 1] * before computing the result of blending. * * * Blend Strings/1 * Blend a non-premultiplied source over a destination with * premultiplied alpha: * * "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))" * "A = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" * * * * * Blend Strings/2 * Blend a premultiplied source over a destination with * premultiplied alpha * * "RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" * * * * The default blend string is: * |[ * RGBA = ADD (SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A])) * ]| * * That gives normal alpha-blending when the calculated color for the pipeline * is in premultiplied form. * * Return value: %TRUE if the blend string was successfully parsed, and the * described blending is supported by the underlying driver/hardware. If * there was an error, %FALSE is returned and @error is set accordingly (if * present). * * Since: 2.0 * Stability: Unstable */ CoglBool cogl_pipeline_set_blend (CoglPipeline *pipeline, const char *blend_string, CoglError **error); /** * cogl_pipeline_set_blend_constant: * @pipeline: A #CoglPipeline object * @constant_color: The constant color you want * * When blending is setup to reference a CONSTANT blend factor then * blending will depend on the constant set with this function. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_blend_constant (CoglPipeline *pipeline, const CoglColor *constant_color); /** * cogl_pipeline_set_point_size: * @pipeline: a #CoglPipeline pointer * @point_size: the new point size. * * Changes the size of points drawn when %COGL_VERTICES_MODE_POINTS is * used with the attribute buffer API. Note that typically the GPU * will only support a limited minimum and maximum range of point * sizes. If the chosen point size is outside that range then the * nearest value within that range will be used instead. The size of a * point is in screen space so it will be the same regardless of any * transformations. * * If the point size is set to 0.0 then drawing points with the * pipeline will have undefined results. This is the default value so * if an application wants to draw points it must make sure to use a * pipeline that has an explicit point size set on it. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_point_size (CoglPipeline *pipeline, float point_size); /** * cogl_pipeline_get_point_size: * @pipeline: a #CoglPipeline pointer * * Get the size of points drawn when %COGL_VERTICES_MODE_POINTS is * used with the vertex buffer API. * * Return value: the point size of the @pipeline. * * Since: 2.0 * Stability: Unstable */ float cogl_pipeline_get_point_size (CoglPipeline *pipeline); /** * cogl_pipeline_set_per_vertex_point_size: * @pipeline: a #CoglPipeline pointer * @enable: whether to enable per-vertex point size * @error: a location to store a #CoglError if the change failed * * Sets whether to use a per-vertex point size or to use the value set * by cogl_pipeline_set_point_size(). If per-vertex point size is * enabled then the point size can be set for an individual point * either by drawing with a #CoglAttribute with the name * ‘cogl_point_size_in’ or by writing to the GLSL builtin * ‘cogl_point_size_out’ from a vertex shader snippet. * * If per-vertex point size is enabled and this attribute is not used * and cogl_point_size_out is not written to then the results are * undefined. * * Note that enabling this will only work if the * %COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE feature is available. If * this is not available then the function will return %FALSE and set * a #CoglError. * * Since: 2.0 * Stability: Unstable * Return value: %TRUE if the change suceeded or %FALSE otherwise */ CoglBool cogl_pipeline_set_per_vertex_point_size (CoglPipeline *pipeline, CoglBool enable, CoglError **error); /** * cogl_pipeline_get_per_vertex_point_size: * @pipeline: a #CoglPipeline pointer * * Since: 2.0 * Stability: Unstable * Return value: %TRUE if the pipeline has per-vertex point size * enabled or %FALSE otherwise. The per-vertex point size can be * enabled with cogl_pipeline_set_per_vertex_point_size(). */ CoglBool cogl_pipeline_get_per_vertex_point_size (CoglPipeline *pipeline); /** * cogl_pipeline_get_color_mask: * @pipeline: a #CoglPipeline object. * * Gets the current #CoglColorMask of which channels would be written to the * current framebuffer. Each bit set in the mask means that the * corresponding color would be written. * * Returns: A #CoglColorMask * Since: 1.8 * Stability: unstable */ CoglColorMask cogl_pipeline_get_color_mask (CoglPipeline *pipeline); /** * cogl_pipeline_set_color_mask: * @pipeline: a #CoglPipeline object. * @color_mask: A #CoglColorMask of which color channels to write to * the current framebuffer. * * Defines a bit mask of which color channels should be written to the * current framebuffer. If a bit is set in @color_mask that means that * color will be written. * * Since: 1.8 * Stability: unstable */ void cogl_pipeline_set_color_mask (CoglPipeline *pipeline, CoglColorMask color_mask); /** * cogl_pipeline_get_user_program: * @pipeline: a #CoglPipeline object. * * Queries what user program has been associated with the given * @pipeline using cogl_pipeline_set_user_program(). * * Return value: (transfer none): The current user program or %COGL_INVALID_HANDLE. * * Since: 2.0 * Stability: Unstable */ CoglHandle cogl_pipeline_get_user_program (CoglPipeline *pipeline); /** * cogl_pipeline_set_user_program: * @pipeline: a #CoglPipeline object. * @program: A #CoglHandle to a linked CoglProgram * * Associates a linked CoglProgram with the given pipeline so that the * program can take full control of vertex and/or fragment processing. * * This is an example of how it can be used to associate an ARBfp * program with a #CoglPipeline: * |[ * CoglHandle shader; * CoglHandle program; * CoglPipeline *pipeline; * * shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); * cogl_shader_source (shader, * "!!ARBfp1.0\n" * "MOV result.color,fragment.color;\n" * "END\n"); * cogl_shader_compile (shader); * * program = cogl_create_program (); * cogl_program_attach_shader (program, shader); * cogl_program_link (program); * * pipeline = cogl_pipeline_new (); * cogl_pipeline_set_user_program (pipeline, program); * * cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); * cogl_rectangle (0, 0, 100, 100); * ]| * * It is possibly worth keeping in mind that this API is not part of * the long term design for how we want to expose shaders to Cogl * developers (We are planning on deprecating the cogl_program and * cogl_shader APIs in favour of a "snippet" framework) but in the * meantime we hope this will handle most practical GLSL and ARBfp * requirements. * * Also remember you need to check for either the * %COGL_FEATURE_SHADERS_GLSL or %COGL_FEATURE_SHADERS_ARBFP before * using the cogl_program or cogl_shader API. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_user_program (CoglPipeline *pipeline, CoglHandle program); /** * cogl_pipeline_set_depth_state: * @pipeline: A #CoglPipeline object * @state: A #CoglDepthState struct * @error: A #CoglError to report failures to setup the given @state. * * This commits all the depth state configured in @state struct to the * given @pipeline. The configuration values are copied into the * pipeline so there is no requirement to keep the #CoglDepthState * struct around if you don't need it any more. * * Note: Since some platforms do not support the depth range feature * it is possible for this function to fail and report an @error. * * Returns: TRUE if the GPU supports all the given @state else %FALSE * and returns an @error. * * Since: 2.0 * Stability: Unstable */ CoglBool cogl_pipeline_set_depth_state (CoglPipeline *pipeline, const CoglDepthState *state, CoglError **error); /** * cogl_pipeline_get_depth_state: * @pipeline: A #CoglPipeline object * @state_out: (out): A destination #CoglDepthState struct * * Retrieves the current depth state configuration for the given * @pipeline as previously set using cogl_pipeline_set_depth_state(). * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_get_depth_state (CoglPipeline *pipeline, CoglDepthState *state_out); /** * CoglPipelineCullFaceMode: * @COGL_PIPELINE_CULL_FACE_MODE_NONE: Neither face will be * culled. This is the default. * @COGL_PIPELINE_CULL_FACE_MODE_FRONT: Front faces will be culled. * @COGL_PIPELINE_CULL_FACE_MODE_BACK: Back faces will be culled. * @COGL_PIPELINE_CULL_FACE_MODE_BOTH: All faces will be culled. * * Specifies which faces should be culled. This can be set on a * pipeline using cogl_pipeline_set_cull_face_mode(). */ typedef enum { COGL_PIPELINE_CULL_FACE_MODE_NONE, COGL_PIPELINE_CULL_FACE_MODE_FRONT, COGL_PIPELINE_CULL_FACE_MODE_BACK, COGL_PIPELINE_CULL_FACE_MODE_BOTH } CoglPipelineCullFaceMode; /** * cogl_pipeline_set_cull_face_mode: * @pipeline: A #CoglPipeline * @cull_face_mode: The new mode to set * * Sets which faces will be culled when drawing. Face culling can be * used to increase efficiency by avoiding drawing faces that would * get overridden. For example, if a model has gaps so that it is * impossible to see the inside then faces which are facing away from * the screen will never be seen so there is no point in drawing * them. This can be acheived by setting the cull face mode to * %COGL_PIPELINE_CULL_FACE_MODE_BACK. * * Face culling relies on the primitives being drawn with a specific * order to represent which faces are facing inside and outside the * model. This order can be specified by calling * cogl_pipeline_set_front_face_winding(). * * Status: Unstable * Since: 2.0 */ void cogl_pipeline_set_cull_face_mode (CoglPipeline *pipeline, CoglPipelineCullFaceMode cull_face_mode); /** * cogl_pipeline_get_cull_face_mode: * * Return value: the cull face mode that was previously set with * cogl_pipeline_set_cull_face_mode(). * * Status: Unstable * Since: 2.0 */ CoglPipelineCullFaceMode cogl_pipeline_get_cull_face_mode (CoglPipeline *pipeline); /** * cogl_pipeline_set_front_face_winding: * @pipeline: a #CoglPipeline * @front_winding: the winding order * * The order of the vertices within a primitive specifies whether it * is considered to be front or back facing. This function specifies * which order is considered to be the front * faces. %COGL_WINDING_COUNTER_CLOCKWISE sets the front faces to * primitives with vertices in a counter-clockwise order and * %COGL_WINDING_CLOCKWISE sets them to be clockwise. The default is * %COGL_WINDING_COUNTER_CLOCKWISE. * * Status: Unstable * Since: 2.0 */ void cogl_pipeline_set_front_face_winding (CoglPipeline *pipeline, CoglWinding front_winding); /** * cogl_pipeline_get_front_face_winding: * @pipeline: a #CoglPipeline * * The order of the vertices within a primitive specifies whether it * is considered to be front or back facing. This function specifies * which order is considered to be the front * faces. %COGL_WINDING_COUNTER_CLOCKWISE sets the front faces to * primitives with vertices in a counter-clockwise order and * %COGL_WINDING_CLOCKWISE sets them to be clockwise. The default is * %COGL_WINDING_COUNTER_CLOCKWISE. * * Returns: The @pipeline front face winding * * Status: Unstable * Since: 2.0 */ CoglWinding cogl_pipeline_get_front_face_winding (CoglPipeline *pipeline); /** * cogl_pipeline_set_uniform_1f: * @pipeline: A #CoglPipeline object * @uniform_location: The uniform's location identifier * @value: The new value for the uniform * * Sets a new value for the uniform at @uniform_location. If this * pipeline has a user program attached and is later used as a source * for drawing, the given value will be assigned to the uniform which * can be accessed from the shader's source. The value for * @uniform_location should be retrieved from the string name of the * uniform by calling cogl_pipeline_get_uniform_location(). * * This function should be used to set uniforms that are of type * float. It can also be used to set a single member of a float array * uniform. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); /** * cogl_pipeline_set_uniform_1i: * @pipeline: A #CoglPipeline object * @uniform_location: The uniform's location identifier * @value: The new value for the uniform * * Sets a new value for the uniform at @uniform_location. If this * pipeline has a user program attached and is later used as a source * for drawing, the given value will be assigned to the uniform which * can be accessed from the shader's source. The value for * @uniform_location should be retrieved from the string name of the * uniform by calling cogl_pipeline_get_uniform_location(). * * This function should be used to set uniforms that are of type * int. It can also be used to set a single member of a int array * uniform or a sampler uniform. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); /** * cogl_pipeline_set_uniform_float: * @pipeline: A #CoglPipeline object * @uniform_location: The uniform's location identifier * @n_components: The number of components in the corresponding uniform's type * @count: The number of values to set * @value: Pointer to the new values to set * * Sets new values for the uniform at @uniform_location. If this * pipeline has a user program attached and is later used as a source * for drawing, the given values will be assigned to the uniform which * can be accessed from the shader's source. The value for * @uniform_location should be retrieved from the string name of the * uniform by calling cogl_pipeline_get_uniform_location(). * * This function can be used to set any floating point type uniform, * including float arrays and float vectors. For example, to set a * single vec4 uniform you would use 4 for @n_components and 1 for * @count. To set an array of 8 float values, you could use 1 for * @n_components and 8 for @count. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); /** * cogl_pipeline_set_uniform_int: * @pipeline: A #CoglPipeline object * @uniform_location: The uniform's location identifier * @n_components: The number of components in the corresponding uniform's type * @count: The number of values to set * @value: Pointer to the new values to set * * Sets new values for the uniform at @uniform_location. If this * pipeline has a user program attached and is later used as a source * for drawing, the given values will be assigned to the uniform which * can be accessed from the shader's source. The value for * @uniform_location should be retrieved from the string name of the * uniform by calling cogl_pipeline_get_uniform_location(). * * This function can be used to set any integer type uniform, * including int arrays and int vectors. For example, to set a single * ivec4 uniform you would use 4 for @n_components and 1 for * @count. To set an array of 8 int values, you could use 1 for * @n_components and 8 for @count. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); /** * cogl_pipeline_set_uniform_matrix: * @pipeline: A #CoglPipeline object * @uniform_location: The uniform's location identifier * @dimensions: The size of the matrix * @count: The number of values to set * @transpose: Whether to transpose the matrix * @value: Pointer to the new values to set * * Sets new values for the uniform at @uniform_location. If this * pipeline has a user program attached and is later used as a source * for drawing, the given values will be assigned to the uniform which * can be accessed from the shader's source. The value for * @uniform_location should be retrieved from the string name of the * uniform by calling cogl_pipeline_get_uniform_location(). * * This function can be used to set any matrix type uniform, including * matrix arrays. For example, to set a single mat4 uniform you would * use 4 for @dimensions and 1 for @count. To set an array of 8 * mat3 values, you could use 3 for @dimensions and 8 for @count. * * If @transpose is %FALSE then the matrix is expected to be in * column-major order or if it is %TRUE then the matrix is in * row-major order. You can pass a #CoglMatrix by calling by passing * the result of cogl_matrix_get_array() in @value and setting * @transpose to %FALSE. * * Since: 2.0 * Stability: Unstable */ void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, CoglBool transpose, const float *value); /** * cogl_pipeline_add_snippet: * @pipeline: A #CoglPipeline * @snippet: The #CoglSnippet to add to the vertex processing hook * * Adds a shader snippet to @pipeline. The snippet will wrap around or * replace some part of the pipeline as defined by the hook point in * @snippet. Note that some hook points are specific to a layer and * must be added with cogl_pipeline_add_layer_snippet() instead. * * Since: 1.10 * Stability: Unstable */ void cogl_pipeline_add_snippet (CoglPipeline *pipeline, CoglSnippet *snippet); COGL_END_DECLS #endif /* __COGL_PIPELINE_STATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-output-private.h0000664000175000017500000000335314211404421021113 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_OUTPUT_PRIVATE_H #define __COGL_OUTPUT_PRIVATE_H #include "cogl-output.h" #include "cogl-object-private.h" struct _CoglOutput { CoglObject _parent; char *name; int x; /* Must be first field for _cogl_output_values_equal() */ int y; int width; int height; int mm_width; int mm_height; float refresh_rate; CoglSubpixelOrder subpixel_order; }; CoglOutput *_cogl_output_new (const char *name); CoglBool _cogl_output_values_equal (CoglOutput *output, CoglOutput *other); #endif /* __COGL_OUTPUT_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-glsl-shader.c0000664000175000017500000001544114211404421020304 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg * Neil Roberts */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-context-private.h" #include "cogl-util-gl-private.h" #include "cogl-glsl-shader-private.h" #include "cogl-glsl-shader-boilerplate.h" #include #include static CoglBool add_layer_vertex_boilerplate_cb (CoglPipelineLayer *layer, void *user_data) { GString *layer_declarations = user_data; int unit_index = _cogl_pipeline_layer_get_unit_index (layer); g_string_append_printf (layer_declarations, "attribute vec4 cogl_tex_coord%d_in;\n" "#define cogl_texture_matrix%i cogl_texture_matrix[%i]\n" "#define cogl_tex_coord%i_out _cogl_tex_coord[%i]\n", layer->index, layer->index, unit_index, layer->index, unit_index); return TRUE; } static CoglBool add_layer_fragment_boilerplate_cb (CoglPipelineLayer *layer, void *user_data) { GString *layer_declarations = user_data; g_string_append_printf (layer_declarations, "#define cogl_tex_coord%i_in _cogl_tex_coord[%i]\n", layer->index, _cogl_pipeline_layer_get_unit_index (layer)); return TRUE; } void _cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx, GLuint shader_gl_handle, GLenum shader_gl_type, CoglPipeline *pipeline, GLsizei count_in, const char **strings_in, const GLint *lengths_in) { const char *vertex_boilerplate; const char *fragment_boilerplate; const char **strings = g_alloca (sizeof (char *) * (count_in + 4)); GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 4)); char *version_string; int count = 0; int n_layers; vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE; fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE; version_string = g_strdup_printf ("#version %i\n\n", ctx->glsl_version_to_use); strings[count] = version_string; lengths[count++] = -1; if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED) && cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) { static const char texture_3d_extension[] = "#extension GL_OES_texture_3D : enable\n"; strings[count] = texture_3d_extension; lengths[count++] = sizeof (texture_3d_extension) - 1; } if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL)) { static const char texture_3d_extension[] = "#extension GL_OES_EGL_image_external : require\n"; strings[count] = texture_3d_extension; lengths[count++] = sizeof (texture_3d_extension) - 1; } if (shader_gl_type == GL_VERTEX_SHADER) { strings[count] = vertex_boilerplate; lengths[count++] = strlen (vertex_boilerplate); } else if (shader_gl_type == GL_FRAGMENT_SHADER) { strings[count] = fragment_boilerplate; lengths[count++] = strlen (fragment_boilerplate); } n_layers = cogl_pipeline_get_n_layers (pipeline); if (n_layers) { GString *layer_declarations = ctx->codegen_boilerplate_buffer; g_string_set_size (layer_declarations, 0); g_string_append_printf (layer_declarations, "varying vec4 _cogl_tex_coord[%d];\n", n_layers); if (shader_gl_type == GL_VERTEX_SHADER) { g_string_append_printf (layer_declarations, "uniform mat4 cogl_texture_matrix[%d];\n", n_layers); _cogl_pipeline_foreach_layer_internal (pipeline, add_layer_vertex_boilerplate_cb, layer_declarations); } else if (shader_gl_type == GL_FRAGMENT_SHADER) { _cogl_pipeline_foreach_layer_internal (pipeline, add_layer_fragment_boilerplate_cb, layer_declarations); } strings[count] = layer_declarations->str; lengths[count++] = -1; /* null terminated */ } memcpy (strings + count, strings_in, sizeof (char *) * count_in); if (lengths_in) memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in); else { int i; for (i = 0; i < count_in; i++) lengths[count + i] = -1; /* null terminated */ } count += count_in; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE))) { GString *buf = g_string_new (NULL); int i; g_string_append_printf (buf, "%s shader:\n", shader_gl_type == GL_VERTEX_SHADER ? "vertex" : "fragment"); for (i = 0; i < count; i++) if (lengths[i] != -1) g_string_append_len (buf, strings[i], lengths[i]); else g_string_append (buf, strings[i]); g_message ("%s", buf->str); g_string_free (buf, TRUE); } GE( ctx, glShaderSource (shader_gl_handle, count, (const char **) strings, lengths) ); free (version_string); } muffin-5.2.1/cogl/cogl/cogl-onscreen-template.h0000664000175000017500000001077014211404421021531 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_ONSCREEN_TEMPLATE_H__ #define __COGL_ONSCREEN_TEMPLATE_H__ #include #include COGL_BEGIN_DECLS typedef struct _CoglOnscreenTemplate CoglOnscreenTemplate; #define COGL_ONSCREEN_TEMPLATE(OBJECT) ((CoglOnscreenTemplate *)OBJECT) /** * cogl_onscreen_template_get_gtype: * * Returns: a #GType that can be used with the GLib type system. */ GType cogl_onscreen_template_get_gtype (void); CoglOnscreenTemplate * cogl_onscreen_template_new (CoglSwapChain *swap_chain); /** * cogl_onscreen_template_set_samples_per_pixel: * @onscreen_template: A #CoglOnscreenTemplate template framebuffer * @n: The minimum number of samples per pixel * * Requires that any future CoglOnscreen framebuffers derived from * this template must support making at least @n samples per pixel * which will all contribute to the final resolved color for that * pixel. * * By default this value is usually set to 0 and that is referred to * as "single-sample" rendering. A value of 1 or greater is referred * to as "multisample" rendering. * * There are some semantic differences between single-sample * rendering and multisampling with just 1 point sample such as it * being redundant to use the cogl_framebuffer_resolve_samples() and * cogl_framebuffer_resolve_samples_region() apis with single-sample * rendering. * * Since: 1.10 * Stability: unstable */ void cogl_onscreen_template_set_samples_per_pixel ( CoglOnscreenTemplate *onscreen_template, int n); /** * cogl_onscreen_template_set_swap_throttled: * @onscreen_template: A #CoglOnscreenTemplate template framebuffer * @throttled: Whether throttling should be enabled * * Requests that any future #CoglOnscreen framebuffers derived from this * template should enable or disable swap throttling according to the given * @throttled argument. * * Since: 1.10 * Stability: unstable */ void cogl_onscreen_template_set_swap_throttled ( CoglOnscreenTemplate *onscreen_template, CoglBool throttled); /** * cogl_onscreen_template_set_stereo_enabled: * @onscreen_template: A #CoglOnscreenTemplate template framebuffer * @enabled: Whether framebuffers are created with stereo buffers * * Sets whether future #CoglOnscreen framebuffers derived from this * template are attempted to be created with both left and right * buffers, for use with stereo display. If the display system * does not support stereo, then creation of the framebuffer will * fail. * * Since: 1.20 * Stability: unstable */ void cogl_onscreen_template_set_stereo_enabled ( CoglOnscreenTemplate *onscreen_template, CoglBool enabled); /** * cogl_is_onscreen_template: * @object: A #CoglObject pointer * * Gets whether the given object references a #CoglOnscreenTemplate. * * Return value: %TRUE if the object references a #CoglOnscreenTemplate * and %FALSE otherwise. * Since: 1.10 * Stability: unstable */ CoglBool cogl_is_onscreen_template (void *object); COGL_END_DECLS #endif /* __COGL_ONSCREEN_TEMPLATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-indices-private.h0000664000175000017500000000327414211404421021173 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_INDICES_PRIVATE_H #define __COGL_INDICES_PRIVATE_H #include "cogl-object-private.h" #include "cogl-index-buffer-private.h" #include "cogl-types.h" struct _CoglIndices { CoglObject _parent; CoglIndexBuffer *buffer; size_t offset; CoglIndicesType type; int immutable_ref; }; CoglIndices * _cogl_indices_immutable_ref (CoglIndices *indices); void _cogl_indices_immutable_unref (CoglIndices *indices); #endif /* __COGL_INDICES_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-error-private.h0000664000175000017500000000356614211404421020712 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_ERROR_PRIVATE_H__ #define __COGL_ERROR_PRIVATE_H__ #include "cogl-error.h" void _cogl_set_error (CoglError **error, uint32_t domain, int code, const char *format, ...) G_GNUC_PRINTF (4, 5); void _cogl_set_error_literal (CoglError **error, uint32_t domain, int code, const char *message); void _cogl_propagate_error (CoglError **dest, CoglError *src); void _cogl_propagate_gerror (CoglError **dest, GError *src); #define _cogl_clear_error(X) g_clear_error ((GError **)X) #endif /* __COGL_ERROR_PRIVATE_H__ */ muffin-5.2.1/cogl/cogl/cogl-euler.c0000664000175000017500000001360114211404421017207 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include #include #include #include "cogl-gtype-private.h" #include #include COGL_GTYPE_DEFINE_BOXED (Euler, euler, cogl_euler_copy, cogl_euler_free); void cogl_euler_init (CoglEuler *euler, float heading, float pitch, float roll) { euler->heading = heading; euler->pitch = pitch; euler->roll = roll; } void cogl_euler_init_from_matrix (CoglEuler *euler, const CoglMatrix *matrix) { /* * Extracting a canonical Euler angle from a matrix: * (where it is assumed the matrix contains no scaling, mirroring or * skewing) * * A Euler angle is a combination of three rotations around mutually * perpendicular axis. For this algorithm they are: * * Heading: A rotation about the Y axis by an angle H: * | cosH 0 sinH| * | 0 1 0| * |-sinH 0 cosH| * * Pitch: A rotation around the X axis by an angle P: * |1 0 0| * |0 cosP -sinP| * |0 sinP cosP| * * Roll: A rotation about the Z axis by an angle R: * |cosR -sinR 0| * |sinR cosR 0| * | 0 0 1| * * When multiplied as matrices this gives: * | cosHcosR+sinHsinPsinR sinRcosP -sinHcosR+cosHsinPsinR| * M = |-cosHsinR+sinHsinPcosR cosRcosP sinRsinH+cosHsinPcosB| * | sinHcosP -sinP cosHcosP | * * Given that there are an infinite number of ways to represent * a given orientation, the "canonical" Euler angle is any such that: * -180 < H < 180, * -180 < R < 180 and * -90 < P < 90 * * M[3][2] = -sinP lets us immediately solve for P = asin(-M[3][2]) * (Note: asin has a range of +-90) * This gives cosP * This means we can use M[3][1] to calculate sinH: * sinH = M[3][1]/cosP * And use M[3][3] to calculate cosH: * cosH = M[3][3]/cosP * This lets us calculate H = atan2(sinH,cosH), but we optimise this: * 1st note: atan2(x, y) does: atan(x/y) and uses the sign of x and y to * determine the quadrant of the final angle. * 2nd note: we know cosP is > 0 (ignoring cosP == 0) * Therefore H = atan2((M[3][1]/cosP) / (M[3][3]/cosP)) can be simplified * by skipping the division by cosP since it won't change the x/y ratio * nor will it change their sign. This gives: * H = atan2(M[3][1], M[3][3]) * R is computed in the same way as H from M[1][2] and M[2][2] so: * R = atan2(M[1][2], M[2][2]) * Note: If cosP were == 0 then H and R could not be calculated as above * because all the necessary matrix values would == 0. In other words we are * pitched vertically and so H and R would now effectively rotate around the * same axis - known as "Gimbal lock". In this situation we will set all the * rotation on H and set R = 0. * So with P = R = 0 we have cosP = 0, sinR = 0 and cosR = 1 * We can substitute those into the above equation for M giving: * | cosH 0 -sinH| * |sinHsinP 0 cosHsinP| * | 0 -sinP 0| * And calculate H as atan2 (-M[3][2], M[1][1]) */ float sinP; float H; /* heading */ float P; /* pitch */ float R; /* roll */ /* NB: CoglMatrix provides struct members named according to the * [row][column] indexed. So matrix->zx is row 3 column 1. */ sinP = -matrix->zy; /* Determine the Pitch, avoiding domain errors with asin () which * might occur due to previous imprecision in manipulating the * matrix. */ if (sinP <= -1.0f) P = -G_PI_2; else if (sinP >= 1.0f) P = G_PI_2; else P = asinf (sinP); /* If P is too close to 0 then we have hit Gimbal lock */ if (sinP > 0.999f) { H = atan2f (-matrix->zy, matrix->xx); R = 0; } else { H = atan2f (matrix->zx, matrix->zz); R = atan2f (matrix->xy, matrix->yy); } euler->heading = H; euler->pitch = P; euler->roll = R; } CoglBool cogl_euler_equal (const void *v1, const void *v2) { const CoglEuler *a = v1; const CoglEuler *b = v2; _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE); _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE); if (v1 == v2) return TRUE; return (a->heading == b->heading && a->pitch == b->pitch && a->roll == b->roll); } CoglEuler * cogl_euler_copy (const CoglEuler *src) { if (G_LIKELY (src)) { CoglEuler *new = g_slice_new (CoglEuler); memcpy (new, src, sizeof (float) * 3); return new; } else return NULL; } void cogl_euler_free (CoglEuler *euler) { g_slice_free (CoglEuler, euler); } muffin-5.2.1/cogl/cogl/cogl-atlas.h0000664000175000017500000000662614211404421017215 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __COGL_ATLAS_H #define __COGL_ATLAS_H #include "cogl-rectangle-map.h" #include "cogl-object-private.h" #include "cogl-texture.h" typedef void (* CoglAtlasUpdatePositionCallback) (void *user_data, CoglTexture *new_texture, const CoglRectangleMapEntry *rect); typedef enum { COGL_ATLAS_CLEAR_TEXTURE = (1 << 0), COGL_ATLAS_DISABLE_MIGRATION = (1 << 1) } CoglAtlasFlags; typedef struct _CoglAtlas CoglAtlas; #define COGL_ATLAS(object) ((CoglAtlas *) object) struct _CoglAtlas { CoglObject _parent; CoglRectangleMap *map; CoglTexture *texture; CoglPixelFormat texture_format; CoglAtlasFlags flags; CoglAtlasUpdatePositionCallback update_position_cb; GHookList pre_reorganize_callbacks; GHookList post_reorganize_callbacks; }; CoglAtlas * _cogl_atlas_new (CoglPixelFormat texture_format, CoglAtlasFlags flags, CoglAtlasUpdatePositionCallback update_position_cb); CoglBool _cogl_atlas_reserve_space (CoglAtlas *atlas, unsigned int width, unsigned int height, void *user_data); void _cogl_atlas_remove (CoglAtlas *atlas, const CoglRectangleMapEntry *rectangle); CoglTexture * _cogl_atlas_copy_rectangle (CoglAtlas *atlas, int x, int y, int width, int height, CoglPixelFormat format); void _cogl_atlas_add_reorganize_callback (CoglAtlas *atlas, GHookFunc pre_callback, GHookFunc post_callback, void *user_data); void _cogl_atlas_remove_reorganize_callback (CoglAtlas *atlas, GHookFunc pre_callback, GHookFunc post_callback, void *user_data); CoglBool _cogl_is_atlas (void *object); #endif /* __COGL_ATLAS_H */ muffin-5.2.1/cogl/cogl/cogl-primitive-texture.h0000664000175000017500000000777214211404421021622 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2012 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_PRIMITIVE_TEXTURE_H__ #define __COGL_PRIMITIVE_TEXTURE_H__ #include "cogl-types.h" COGL_BEGIN_DECLS /** * SECTION:cogl-primitive-texture * @short_description: Interface for low-level textures like * #CoglTexture2D and #CoglTexture3D. * * A #CoglPrimitiveTexture is a texture that is directly represented * by a single texture on the GPU. For example these could be a * #CoglTexture2D, #CoglTexture3D or #CoglTextureRectangle. This is * opposed to high level meta textures which may be composed of * multiple primitive textures or a sub-region of another texture such * as #CoglAtlasTexture and #CoglTexture2DSliced. * * A texture that implements this interface can be directly used with * the low level cogl_primitive_draw() API. Other types of textures * need to be first resolved to primitive textures using the * #CoglMetaTexture interface. * * Most developers won't need to use this interface directly but * still it is worth understanding the distinction between high-level * and primitive textures because you may find other references in the * documentation that detail limitations of using * primitive textures. */ #if defined(__COGL_H_INSIDE__) && !defined(COGL_ENABLE_MUFFIN_API) && \ !defined(COGL_GIR_SCANNING) /* For the public C api we typedef interface types as void to avoid needing * lots of casting in code and instead we will rely on runtime type checking * for these objects. */ typedef void CoglPrimitiveTexture; #else typedef struct _CoglPrimitiveTexture CoglPrimitiveTexture; #define COGL_PRIMITIVE_TEXTURE(X) ((CoglPrimitiveTexture *)X) #endif /** * cogl_is_primitive_texture: * @object: A #CoglObject pointer * * Gets whether the given object references a primitive texture object. * * Return value: %TRUE if the pointer references a primitive texture, and * %FALSE otherwise * Since: 2.0 * Stability: unstable */ CoglBool cogl_is_primitive_texture (void *object); /** * cogl_primitive_texture_set_auto_mipmap: * @primitive_texture: A #CoglPrimitiveTexture * @value: The new value for whether to auto mipmap * * Sets whether the texture will automatically update the smaller * mipmap levels after any part of level 0 is updated. The update will * only occur whenever the texture is used for drawing with a texture * filter that requires the lower mipmap levels. An application should * disable this if it wants to upload its own data for the other * levels. By default auto mipmapping is enabled. * * Since: 2.0 * Stability: unstable */ void cogl_primitive_texture_set_auto_mipmap (CoglPrimitiveTexture *primitive_texture, CoglBool value); COGL_END_DECLS #endif /* __COGL_PRIMITIVE_TEXTURE_H__ */ muffin-5.2.1/cogl/cogl/cogl-pipeline-layer-private.h0000664000175000017500000003241114211404421022467 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2008,2009,2010,2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * Authors: * Robert Bragg */ #ifndef __COGL_PIPELINE_LAYER_PRIVATE_H #define __COGL_PIPELINE_LAYER_PRIVATE_H #include "cogl-private.h" #include "cogl-pipeline.h" #include "cogl-node-private.h" #include "cogl-texture.h" #include "cogl-matrix.h" #include "cogl-pipeline-layer-state.h" #include "cogl-pipeline-snippet-private.h" #include "cogl-sampler-cache-private.h" #include typedef struct _CoglPipelineLayer CoglPipelineLayer; #define COGL_PIPELINE_LAYER(OBJECT) ((CoglPipelineLayer *)OBJECT) /* XXX: should I rename these as * COGL_PIPELINE_LAYER_STATE_INDEX_XYZ... ? */ typedef enum { /* sparse state */ COGL_PIPELINE_LAYER_STATE_UNIT_INDEX, COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE_INDEX, COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX, COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX, COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX, COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX, COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX, COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX, COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX, COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX, /* note: layers don't currently have any non-sparse state */ COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT, COGL_PIPELINE_LAYER_STATE_COUNT = COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT } CoglPipelineLayerStateIndex; /* XXX: If you add or remove state groups here you may need to update * some of the state masks following this enum too! * * FIXME: perhaps it would be better to rename this enum to * CoglPipelineLayerStateGroup to better convey the fact that a single * enum here can map to multiple properties. */ typedef enum { COGL_PIPELINE_LAYER_STATE_UNIT = 1L< TEXTURE0 to store very large layer numbers */ COGL_PIPELINE_COMBINE_SOURCE_TEXTURE, COGL_PIPELINE_COMBINE_SOURCE_CONSTANT, COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR, COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS, COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 } CoglPipelineCombineSource; typedef enum { /* These are the same values as GL */ COGL_PIPELINE_COMBINE_OP_SRC_COLOR = 0x0300, COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR = 0x0301, COGL_PIPELINE_COMBINE_OP_SRC_ALPHA = 0x0302, COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA = 0x0303 } CoglPipelineCombineOp; typedef struct { /* The texture combine state determines how the color of individual * texture fragments are calculated. */ CoglPipelineCombineFunc texture_combine_rgb_func; CoglPipelineCombineSource texture_combine_rgb_src[3]; CoglPipelineCombineOp texture_combine_rgb_op[3]; CoglPipelineCombineFunc texture_combine_alpha_func; CoglPipelineCombineSource texture_combine_alpha_src[3]; CoglPipelineCombineOp texture_combine_alpha_op[3]; float texture_combine_constant[4]; /* The texture matrix dscribes how to transform texture coordinates */ CoglMatrix matrix; CoglPipelineSnippetList vertex_snippets; CoglPipelineSnippetList fragment_snippets; CoglBool point_sprite_coords; } CoglPipelineLayerBigState; struct _CoglPipelineLayer { /* XXX: Please think twice about adding members that *have* be * initialized during a _cogl_pipeline_layer_copy. We are aiming * to have copies be as cheap as possible and copies may be * done by the primitives APIs which means they may happen * in performance critical code paths. * * XXX: If you are extending the state we track please consider if * the state is expected to vary frequently across many pipelines or * if the state can be shared among many derived pipelines instead. * This will determine if the state should be added directly to this * structure which will increase the memory overhead for *all* * layers or if instead it can go under ->big_state. */ /* Layers represent their state in a tree structure where some of * the state relating to a given pipeline or layer may actually be * owned by one if is ancestors in the tree. We have a common data * type to track the tree heirachy so we can share code... */ CoglNode _parent; /* Some layers have a pipeline owner, which is to say that the layer * is referenced in that pipelines->layer_differences list. A layer * doesn't always have an owner and may simply be an ancestor for * other layers that keeps track of some shared state. */ CoglPipeline *owner; /* The lowest index is blended first then others on top */ int index; /* A mask of which state groups are different in this layer * in comparison to its parent. */ unsigned int differences; /* Common differences * * As a basic way to reduce memory usage we divide the layer * state into two groups; the minimal state modified in 90% of * all layers and the rest, so that the second group can * be allocated dynamically when required. */ /* Each layer is directly associated with a single texture unit */ int unit_index; /* The type of the texture. This is always set even if the texture is NULL and it will be used to determine what type of texture lookups to use in any shaders generated by the pipeline backends. */ CoglTextureType texture_type; /* The texture for this layer, or NULL for an empty * layer */ CoglTexture *texture; const CoglSamplerCacheEntry *sampler_cache_entry; /* Infrequent differences aren't currently tracked in * a separate, dynamically allocated structure as they are * for pipelines... */ CoglPipelineLayerBigState *big_state; /* bitfields */ /* Determines if layer->big_state is valid */ unsigned int has_big_state:1; }; typedef CoglBool (*CoglPipelineLayerStateComparitor) (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1); void _cogl_pipeline_init_default_layers (void); static inline CoglPipelineLayer * _cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer) { CoglNode *parent_node = COGL_NODE (layer)->parent; return COGL_PIPELINE_LAYER (parent_node); } CoglPipelineLayer * _cogl_pipeline_layer_copy (CoglPipelineLayer *layer); void _cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer, unsigned long differences, CoglPipelineLayer **authorities); CoglBool _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0, CoglPipelineLayer *layer1, unsigned long differences_mask, CoglPipelineEvalFlags flags); CoglPipelineLayer * _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner, CoglPipelineLayer *layer, CoglPipelineLayerState change); void _cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer); CoglBool _cogl_pipeline_layer_has_alpha (CoglPipelineLayer *layer); CoglBool _cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline, int layer_index); /* * Calls the pre_paint method on the layer texture if there is * one. This will determine whether mipmaps are needed based on the * filter settings. */ void _cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layerr); void _cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer, CoglSamplerCacheWrapMode *wrap_mode_s, CoglSamplerCacheWrapMode *wrap_mode_t, CoglSamplerCacheWrapMode *wrap_mode_r); void _cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer, CoglPipelineFilter *min_filter, CoglPipelineFilter *mag_filter); const CoglSamplerCacheEntry * _cogl_pipeline_layer_get_sampler_state (CoglPipelineLayer *layer); void _cogl_pipeline_get_layer_filters (CoglPipeline *pipeline, int layer_index, CoglPipelineFilter *min_filter, CoglPipelineFilter *mag_filter); typedef enum { COGL_PIPELINE_LAYER_TYPE_TEXTURE } CoglPipelineLayerType; CoglPipelineLayerType _cogl_pipeline_layer_get_type (CoglPipelineLayer *layer); CoglTexture * _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer); CoglTexture * _cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer); CoglTextureType _cogl_pipeline_layer_get_texture_type (CoglPipelineLayer *layer); CoglPipelineFilter _cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer); CoglPipelineFilter _cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer); CoglPipelineWrapMode _cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer); CoglPipelineWrapMode _cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer); CoglPipelineWrapMode _cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer); void _cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest, CoglPipelineLayer *src, unsigned long differences); unsigned long _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0, CoglPipelineLayer *layer1); CoglPipelineLayer * _cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer, unsigned long difference); CoglTexture * _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer); int _cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer); CoglBool _cogl_pipeline_layer_needs_combine_separate (CoglPipelineLayer *combine_authority); #endif /* __COGL_PIPELINE_LAYER_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-primitives-private.h0000664000175000017500000000473114211404421021747 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2010 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifndef __COGL_PRIMITIVES_PRIVATE_H #define __COGL_PRIMITIVES_PRIVATE_H #include COGL_BEGIN_DECLS /* Draws a rectangle without going through the journal so that it will be flushed immediately. This should only be used in situations where the code may be called while the journal is already being flushed. In that case using the journal would go wrong */ void _cogl_rectangle_immediate (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, float x_1, float y_1, float x_2, float y_2); typedef struct _CoglMultiTexturedRect { const float *position; /* x0,y0,x1,y1 */ const float *tex_coords; /* (tx0,ty0,tx1,ty1)(tx0,ty0,tx1,ty1)(... */ int tex_coords_len; /* number of floats in tex_coords? */ } CoglMultiTexturedRect; void _cogl_framebuffer_draw_multitextured_rectangles ( CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglMultiTexturedRect *rects, int n_rects, CoglBool disable_legacy_state); COGL_END_DECLS #endif /* __COGL_PRIMITIVES_PRIVATE_H */ muffin-5.2.1/cogl/cogl/cogl-journal.c0000664000175000017500000017761514211404421017565 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2007,2008,2009 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * */ #ifdef HAVE_CONFIG_H #include "cogl-config.h" #endif #include "cogl-debug.h" #include "cogl-context-private.h" #include "cogl-journal-private.h" #include "cogl-texture-private.h" #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-vertex-buffer-private.h" #include "cogl-framebuffer-private.h" #include "cogl-profile.h" #include "cogl-attribute-private.h" #include "cogl-point-in-poly-private.h" #include "cogl-private.h" #include "cogl1-context.h" #include #include #include /* XXX NB: * The data logged in logged_vertices is formatted as follows: * * Per entry: * 4 RGBA GLubytes for the color * 2 floats for the top left position * 2 * n_layers floats for the top left texture coordinates * 2 floats for the bottom right position * 2 * n_layers floats for the bottom right texture coordinates */ #define GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS(N_LAYERS) \ (N_LAYERS * 2 + 2) /* XXX NB: * Once in the vertex array, the journal's vertex data is arranged as follows: * 4 vertices per quad: * 2 or 3 GLfloats per position (3 when doing software transforms) * 4 RGBA GLubytes, * 2 GLfloats per tex coord * n_layers * * Where n_layers corresponds to the number of pipeline layers enabled * * To avoid frequent changes in the stride of our vertex data we always pad * n_layers to be >= 2 * * There will be four vertices per quad in the vertex array * * When we are transforming quads in software we need to also track the z * coordinate of transformed vertices. * * So for a given number of layers this gets the stride in 32bit words: */ #define SW_TRANSFORM (!(COGL_DEBUG_ENABLED \ (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) #define POS_STRIDE (SW_TRANSFORM ? 3 : 2) /* number of 32bit words */ #define N_POS_COMPONENTS POS_STRIDE #define COLOR_STRIDE 1 /* number of 32bit words */ #define TEX_STRIDE 2 /* number of 32bit words */ #define MIN_LAYER_PADING 2 #define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \ (POS_STRIDE + COLOR_STRIDE + \ TEX_STRIDE * (N_LAYERS < MIN_LAYER_PADING ? MIN_LAYER_PADING : N_LAYERS)) /* If a batch is longer than this threshold then we'll assume it's not worth doing software clipping and it's cheaper to program the GPU to do the clip */ #define COGL_JOURNAL_HARDWARE_CLIP_THRESHOLD 8 typedef struct _CoglJournalFlushState { CoglContext *ctx; CoglJournal *journal; CoglAttributeBuffer *attribute_buffer; GArray *attributes; int current_attribute; size_t stride; size_t array_offset; GLuint current_vertex; CoglIndices *indices; size_t indices_type_size; CoglPipeline *pipeline; } CoglJournalFlushState; typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start, int n_entries, void *data); typedef CoglBool (*CoglJournalBatchTest) (CoglJournalEntry *entry0, CoglJournalEntry *entry1); static void _cogl_journal_free (CoglJournal *journal); COGL_OBJECT_INTERNAL_DEFINE (Journal, journal); static void _cogl_journal_free (CoglJournal *journal) { int i; if (journal->entries) g_array_free (journal->entries, TRUE); if (journal->vertices) g_array_free (journal->vertices, TRUE); for (i = 0; i < COGL_JOURNAL_VBO_POOL_SIZE; i++) if (journal->vbo_pool[i]) cogl_object_unref (journal->vbo_pool[i]); g_slice_free (CoglJournal, journal); } CoglJournal * _cogl_journal_new (CoglFramebuffer *framebuffer) { CoglJournal *journal = g_slice_new0 (CoglJournal); /* The journal keeps a pointer back to the framebuffer because there is effectively a 1:1 mapping between journals and framebuffers. However, to avoid a circular reference the journal doesn't take a reference unless it is non-empty. The framebuffer has a special unref implementation to ensure that the journal is flushed when the journal is the only thing keeping it alive */ journal->framebuffer = framebuffer; journal->entries = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); journal->vertices = g_array_new (FALSE, FALSE, sizeof (float)); _cogl_list_init (&journal->pending_fences); return _cogl_journal_object_new (journal); } static void _cogl_journal_dump_logged_quad (uint8_t *data, int n_layers) { size_t stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (n_layers); int i; g_print ("n_layers = %d; rgba=0x%02X%02X%02X%02X\n", n_layers, data[0], data[1], data[2], data[3]); data += 4; for (i = 0; i < 2; i++) { float *v = (float *)data + (i * stride); int j; g_print ("v%d: x = %f, y = %f", i, v[0], v[1]); for (j = 0; j < n_layers; j++) { float *t = v + 2 + TEX_STRIDE * j; g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]); } g_print ("\n"); } } static void _cogl_journal_dump_quad_vertices (uint8_t *data, int n_layers) { size_t stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers); int i; g_print ("n_layers = %d; stride = %d; pos stride = %d; color stride = %d; " "tex stride = %d; stride in bytes = %d\n", n_layers, (int)stride, POS_STRIDE, COLOR_STRIDE, TEX_STRIDE, (int)stride * 4); for (i = 0; i < 4; i++) { float *v = (float *)data + (i * stride); uint8_t *c = data + (POS_STRIDE * 4) + (i * stride * 4); int j; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) g_print ("v%d: x = %f, y = %f, rgba=0x%02X%02X%02X%02X", i, v[0], v[1], c[0], c[1], c[2], c[3]); else g_print ("v%d: x = %f, y = %f, z = %f, rgba=0x%02X%02X%02X%02X", i, v[0], v[1], v[2], c[0], c[1], c[2], c[3]); for (j = 0; j < n_layers; j++) { float *t = v + POS_STRIDE + COLOR_STRIDE + TEX_STRIDE * j; g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]); } g_print ("\n"); } } static void _cogl_journal_dump_quad_batch (uint8_t *data, int n_layers, int n_quads) { size_t byte_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4; int i; g_print ("_cogl_journal_dump_quad_batch: n_layers = %d, n_quads = %d\n", n_layers, n_quads); for (i = 0; i < n_quads; i++) _cogl_journal_dump_quad_vertices (data + byte_stride * 2 * i, n_layers); } static void batch_and_call (CoglJournalEntry *entries, int n_entries, CoglJournalBatchTest can_batch_callback, CoglJournalBatchCallback batch_callback, void *data) { int i; int batch_len = 1; CoglJournalEntry *batch_start = entries; if (n_entries < 1) return; for (i = 1; i < n_entries; i++) { CoglJournalEntry *entry0 = &entries[i - 1]; CoglJournalEntry *entry1 = entry0 + 1; if (can_batch_callback (entry0, entry1)) { batch_len++; continue; } batch_callback (batch_start, batch_len, data); batch_start = entry1; batch_len = 1; } /* The last batch... */ batch_callback (batch_start, batch_len, data); } static void _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start, int batch_len, void *data) { CoglJournalFlushState *state = data; CoglContext *ctx = state->ctx; CoglFramebuffer *framebuffer = state->journal->framebuffer; CoglAttribute **attributes; CoglDrawFlags draw_flags = (COGL_DRAW_SKIP_JOURNAL_FLUSH | COGL_DRAW_SKIP_PIPELINE_VALIDATION | COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH | COGL_DRAW_SKIP_LEGACY_STATE); COGL_STATIC_TIMER (time_flush_modelview_and_entries, "flush: pipeline+entries", /* parent */ "flush: modelview+entries", "The time spent flushing modelview + entries", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, time_flush_modelview_and_entries); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING))) g_print ("BATCHING: modelview batch len = %d\n", batch_len); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) _cogl_context_set_current_modelview_entry (ctx, batch_start->modelview_entry); attributes = (CoglAttribute **)state->attributes->data; if (!_cogl_pipeline_get_real_blend_enabled (state->pipeline)) draw_flags |= COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE; #ifdef HAVE_COGL_GL if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUADS)) { /* XXX: it's rather evil that we sneak in the GL_QUADS enum here... */ _cogl_framebuffer_draw_attributes (framebuffer, state->pipeline, GL_QUADS, state->current_vertex, batch_len * 4, attributes, state->attributes->len, draw_flags); } else #endif /* HAVE_COGL_GL */ { if (batch_len > 1) { CoglVerticesMode mode = COGL_VERTICES_MODE_TRIANGLES; int first_vertex = state->current_vertex * 6 / 4; _cogl_framebuffer_draw_indexed_attributes (framebuffer, state->pipeline, mode, first_vertex, batch_len * 6, state->indices, attributes, state->attributes->len, draw_flags); } else { _cogl_framebuffer_draw_attributes (framebuffer, state->pipeline, COGL_VERTICES_MODE_TRIANGLE_FAN, state->current_vertex, 4, attributes, state->attributes->len, draw_flags); } } /* DEBUGGING CODE XXX: This path will cause all rectangles to be * drawn with a coloured outline. Each batch will be rendered with * the same color. This may e.g. help with debugging texture slicing * issues, visually seeing what is batched and debugging blending * issues, plus it looks quite cool. */ if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_RECTANGLES))) { static CoglPipeline *outline = NULL; uint8_t color_intensity; int i; CoglAttribute *loop_attributes[1]; if (outline == NULL) outline = cogl_pipeline_new (ctx); /* The least significant three bits represent the three components so that the order of colours goes red, green, yellow, blue, magenta, cyan. Black and white are skipped. The next two bits give four scales of intensity for those colours in the order 0xff, 0xcc, 0x99, and 0x66. This gives a total of 24 colours. If there are more than 24 batches on the stage then it will wrap around */ color_intensity = 0xff - 0x33 * (ctx->journal_rectangles_color >> 3); cogl_pipeline_set_color4ub (outline, (ctx->journal_rectangles_color & 1) ? color_intensity : 0, (ctx->journal_rectangles_color & 2) ? color_intensity : 0, (ctx->journal_rectangles_color & 4) ? color_intensity : 0, 0xff); loop_attributes[0] = attributes[0]; /* we just want the position */ for (i = 0; i < batch_len; i++) _cogl_framebuffer_draw_attributes (framebuffer, outline, COGL_VERTICES_MODE_LINE_LOOP, 4 * i + state->current_vertex, 4, loop_attributes, 1, draw_flags); /* Go to the next color */ do ctx->journal_rectangles_color = ((ctx->journal_rectangles_color + 1) & ((1 << 5) - 1)); /* We don't want to use black or white */ while ((ctx->journal_rectangles_color & 0x07) == 0 || (ctx->journal_rectangles_color & 0x07) == 0x07); } state->current_vertex += (4 * batch_len); COGL_TIMER_STOP (_cogl_uprof_context, time_flush_modelview_and_entries); } static CoglBool compare_entry_modelviews (CoglJournalEntry *entry0, CoglJournalEntry *entry1) { /* Batch together quads with the same model view matrix */ return entry0->modelview_entry == entry1->modelview_entry; } /* At this point we have a run of quads that we know have compatible * pipelines, but they may not all have the same modelview matrix */ static void _cogl_journal_flush_pipeline_and_entries (CoglJournalEntry *batch_start, int batch_len, void *data) { CoglJournalFlushState *state = data; COGL_STATIC_TIMER (time_flush_pipeline_entries, "flush: texcoords+pipeline+entries", /* parent */ "flush: pipeline+entries", "The time spent flushing pipeline + entries", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, time_flush_pipeline_entries); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING))) g_print ("BATCHING: pipeline batch len = %d\n", batch_len); state->pipeline = batch_start->pipeline; /* If we haven't transformed the quads in software then we need to also break * up batches according to changes in the modelview matrix... */ if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) { batch_and_call (batch_start, batch_len, compare_entry_modelviews, _cogl_journal_flush_modelview_and_entries, data); } else _cogl_journal_flush_modelview_and_entries (batch_start, batch_len, data); COGL_TIMER_STOP (_cogl_uprof_context, time_flush_pipeline_entries); } static CoglBool compare_entry_pipelines (CoglJournalEntry *entry0, CoglJournalEntry *entry1) { /* batch rectangles using compatible pipelines */ if (_cogl_pipeline_equal (entry0->pipeline, entry1->pipeline, (COGL_PIPELINE_STATE_ALL & ~COGL_PIPELINE_STATE_COLOR), COGL_PIPELINE_LAYER_STATE_ALL, 0)) return TRUE; else return FALSE; } typedef struct _CreateAttributeState { int current; CoglJournalFlushState *flush_state; } CreateAttributeState; static CoglBool create_attribute_cb (CoglPipeline *pipeline, int layer_number, void *user_data) { CreateAttributeState *state = user_data; CoglJournalFlushState *flush_state = state->flush_state; CoglAttribute **attribute_entry = &g_array_index (flush_state->attributes, CoglAttribute *, state->current + 2); const char *names[] = { "cogl_tex_coord0_in", "cogl_tex_coord1_in", "cogl_tex_coord2_in", "cogl_tex_coord3_in", "cogl_tex_coord4_in", "cogl_tex_coord5_in", "cogl_tex_coord6_in", "cogl_tex_coord7_in" }; char *name; /* XXX NB: * Our journal's vertex data is arranged as follows: * 4 vertices per quad: * 2 or 3 floats per position (3 when doing software transforms) * 4 RGBA bytes, * 2 floats per tex coord * n_layers * (though n_layers may be padded; see definition of * GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details) */ name = layer_number < 8 ? (char *)names[layer_number] : g_strdup_printf ("cogl_tex_coord%d_in", layer_number); /* XXX: it may be worth having some form of static initializer for * attributes... */ *attribute_entry = cogl_attribute_new (flush_state->attribute_buffer, name, flush_state->stride, flush_state->array_offset + (POS_STRIDE + COLOR_STRIDE) * 4 + TEX_STRIDE * 4 * state->current, 2, COGL_ATTRIBUTE_TYPE_FLOAT); if (layer_number >= 8) free (name); state->current++; return TRUE; } /* Since the stride may not reflect the number of texture layers in use * (due to padding) we deal with texture coordinate offsets separately * from vertex and color offsets... */ static void _cogl_journal_flush_texcoord_vbo_offsets_and_entries ( CoglJournalEntry *batch_start, int batch_len, void *data) { CoglJournalFlushState *state = data; CreateAttributeState create_attrib_state; int i; COGL_STATIC_TIMER (time_flush_texcoord_pipeline_entries, "flush: vbo+texcoords+pipeline+entries", /* parent */ "flush: texcoords+pipeline+entries", "The time spent flushing texcoord offsets + pipeline " "+ entries", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, time_flush_texcoord_pipeline_entries); /* NB: attributes 0 and 1 are position and color */ for (i = 2; i < state->attributes->len; i++) cogl_object_unref (g_array_index (state->attributes, CoglAttribute *, i)); g_array_set_size (state->attributes, batch_start->n_layers + 2); create_attrib_state.current = 0; create_attrib_state.flush_state = state; cogl_pipeline_foreach_layer (batch_start->pipeline, create_attribute_cb, &create_attrib_state); batch_and_call (batch_start, batch_len, compare_entry_pipelines, _cogl_journal_flush_pipeline_and_entries, data); COGL_TIMER_STOP (_cogl_uprof_context, time_flush_texcoord_pipeline_entries); } static CoglBool compare_entry_layer_numbers (CoglJournalEntry *entry0, CoglJournalEntry *entry1) { if (_cogl_pipeline_layer_numbers_equal (entry0->pipeline, entry1->pipeline)) return TRUE; else return FALSE; } /* At this point we know the stride has changed from the previous batch * of journal entries */ static void _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start, int batch_len, void *data) { CoglJournalFlushState *state = data; CoglContext *ctx = state->journal->framebuffer->context; size_t stride; int i; CoglAttribute **attribute_entry; COGL_STATIC_TIMER (time_flush_vbo_texcoord_pipeline_entries, "flush: clip+vbo+texcoords+pipeline+entries", /* parent */ "flush: vbo+texcoords+pipeline+entries", "The time spent flushing vbo + texcoord offsets + " "pipeline + entries", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, time_flush_vbo_texcoord_pipeline_entries); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING))) g_print ("BATCHING: vbo offset batch len = %d\n", batch_len); /* XXX NB: * Our journal's vertex data is arranged as follows: * 4 vertices per quad: * 2 or 3 GLfloats per position (3 when doing software transforms) * 4 RGBA GLubytes, * 2 GLfloats per tex coord * n_layers * (though n_layers may be padded; see definition of * GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details) */ stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers); stride *= sizeof (float); state->stride = stride; for (i = 0; i < state->attributes->len; i++) cogl_object_unref (g_array_index (state->attributes, CoglAttribute *, i)); g_array_set_size (state->attributes, 2); attribute_entry = &g_array_index (state->attributes, CoglAttribute *, 0); *attribute_entry = cogl_attribute_new (state->attribute_buffer, "cogl_position_in", stride, state->array_offset, N_POS_COMPONENTS, COGL_ATTRIBUTE_TYPE_FLOAT); attribute_entry = &g_array_index (state->attributes, CoglAttribute *, 1); *attribute_entry = cogl_attribute_new (state->attribute_buffer, "cogl_color_in", stride, state->array_offset + (POS_STRIDE * 4), 4, COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE); if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUADS)) state->indices = cogl_get_rectangle_indices (ctx, batch_len); /* We only create new Attributes when the stride within the * AttributeBuffer changes. (due to a change in the number of pipeline * layers) While the stride remains constant we walk forward through * the above AttributeBuffer using a vertex offset passed to * cogl_draw_attributes */ state->current_vertex = 0; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL)) && cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) { uint8_t *verts; /* Mapping a buffer for read is probably a really bad thing to do but this will only happen during debugging so it probably doesn't matter */ verts = ((uint8_t *)_cogl_buffer_map (COGL_BUFFER (state->attribute_buffer), COGL_BUFFER_ACCESS_READ, 0, NULL) + state->array_offset); _cogl_journal_dump_quad_batch (verts, batch_start->n_layers, batch_len); cogl_buffer_unmap (COGL_BUFFER (state->attribute_buffer)); } batch_and_call (batch_start, batch_len, compare_entry_layer_numbers, _cogl_journal_flush_texcoord_vbo_offsets_and_entries, data); /* progress forward through the VBO containing all our vertices */ state->array_offset += (stride * 4 * batch_len); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL))) g_print ("new vbo offset = %lu\n", (unsigned long)state->array_offset); COGL_TIMER_STOP (_cogl_uprof_context, time_flush_vbo_texcoord_pipeline_entries); } static CoglBool compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1) { /* Currently the only thing that affects the stride for our vertex arrays * is the number of pipeline layers. We need to update our VBO offsets * whenever the stride changes. */ /* TODO: We should be padding the n_layers == 1 case as if it were * n_layers == 2 so we can reduce the need to split batches. */ if (entry0->n_layers == entry1->n_layers || (entry0->n_layers <= MIN_LAYER_PADING && entry1->n_layers <= MIN_LAYER_PADING)) return TRUE; else return FALSE; } /* At this point we know the batch has a unique clip stack */ static void _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start, int batch_len, void *data) { CoglJournalFlushState *state = data; CoglFramebuffer *framebuffer = state->journal->framebuffer; CoglContext *ctx = framebuffer->context; CoglMatrixStack *projection_stack; COGL_STATIC_TIMER (time_flush_clip_stack_pipeline_entries, "Journal Flush", /* parent */ "flush: clip+vbo+texcoords+pipeline+entries", "The time spent flushing clip + vbo + texcoord offsets + " "pipeline + entries", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, time_flush_clip_stack_pipeline_entries); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING))) g_print ("BATCHING: clip stack batch len = %d\n", batch_len); _cogl_clip_stack_flush (batch_start->clip_stack, framebuffer); /* XXX: Because we are manually flushing clip state here we need to * make sure that the clip state gets updated the next time we flush * framebuffer state by marking the current framebuffer's clip state * as changed. */ ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; /* If we have transformed all our quads at log time then we ensure * no further model transform is applied by loading the identity * matrix here. We need to do this after flushing the clip stack * because the clip stack flushing code can modify the current * modelview matrix entry */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))) _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry); /* Setting up the clip state can sometimes also update the current * projection matrix entry so we should update it again. This will have * no affect if the clip code didn't modify the projection */ projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); _cogl_context_set_current_projection_entry (ctx, projection_stack->last_entry); batch_and_call (batch_start, batch_len, compare_entry_strides, _cogl_journal_flush_vbo_offsets_and_entries, /* callback */ data); COGL_TIMER_STOP (_cogl_uprof_context, time_flush_clip_stack_pipeline_entries); } typedef struct { float x_1, y_1; float x_2, y_2; } ClipBounds; static CoglBool can_software_clip_entry (CoglJournalEntry *journal_entry, CoglJournalEntry *prev_journal_entry, CoglClipStack *clip_stack, ClipBounds *clip_bounds_out) { CoglPipeline *pipeline = journal_entry->pipeline; CoglClipStack *clip_entry; int layer_num; clip_bounds_out->x_1 = -G_MAXFLOAT; clip_bounds_out->y_1 = -G_MAXFLOAT; clip_bounds_out->x_2 = G_MAXFLOAT; clip_bounds_out->y_2 = G_MAXFLOAT; /* Check the pipeline is usable. We can short-cut here for entries using the same pipeline as the previous entry */ if (prev_journal_entry == NULL || pipeline != prev_journal_entry->pipeline) { /* If the pipeline has a user program then we can't reliably modify the texture coordinates */ if (cogl_pipeline_get_user_program (pipeline)) return FALSE; /* If any of the pipeline layers have a texture matrix then we can't reliably modify the texture coordinates */ for (layer_num = cogl_pipeline_get_n_layers (pipeline) - 1; layer_num >= 0; layer_num--) if (_cogl_pipeline_layer_has_user_matrix (pipeline, layer_num)) return FALSE; } /* Now we need to verify that each clip entry's matrix is just a translation of the journal entry's modelview matrix. We can also work out the bounds of the clip in modelview space using this translation */ for (clip_entry = clip_stack; clip_entry; clip_entry = clip_entry->parent) { float rect_x1, rect_y1, rect_x2, rect_y2; CoglClipStackRect *clip_rect; float tx, ty, tz; CoglMatrixEntry *modelview_entry; clip_rect = (CoglClipStackRect *) clip_entry; modelview_entry = journal_entry->modelview_entry; if (!cogl_matrix_entry_calculate_translation (clip_rect->matrix_entry, modelview_entry, &tx, &ty, &tz)) return FALSE; if (clip_rect->x0 < clip_rect->x1) { rect_x1 = clip_rect->x0; rect_x2 = clip_rect->x1; } else { rect_x1 = clip_rect->x1; rect_x2 = clip_rect->x0; } if (clip_rect->y0 < clip_rect->y1) { rect_y1 = clip_rect->y0; rect_y2 = clip_rect->y1; } else { rect_y1 = clip_rect->y1; rect_y2 = clip_rect->y0; } clip_bounds_out->x_1 = MAX (clip_bounds_out->x_1, rect_x1 - tx); clip_bounds_out->y_1 = MAX (clip_bounds_out->y_1, rect_y1 - ty); clip_bounds_out->x_2 = MIN (clip_bounds_out->x_2, rect_x2 - tx); clip_bounds_out->y_2 = MIN (clip_bounds_out->y_2, rect_y2 - ty); } if (clip_bounds_out->x_2 <= clip_bounds_out->x_1 || clip_bounds_out->y_2 <= clip_bounds_out->y_1) memset (clip_bounds_out, 0, sizeof (ClipBounds)); return TRUE; } static void software_clip_entry (CoglJournalEntry *journal_entry, float *verts, ClipBounds *clip_bounds) { size_t stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (journal_entry->n_layers); float rx1, ry1, rx2, ry2; float vx1, vy1, vx2, vy2; int layer_num; /* Remove the clip on the entry */ _cogl_clip_stack_unref (journal_entry->clip_stack); journal_entry->clip_stack = NULL; vx1 = verts[0]; vy1 = verts[1]; vx2 = verts[stride]; vy2 = verts[stride + 1]; if (vx1 < vx2) { rx1 = vx1; rx2 = vx2; } else { rx1 = vx2; rx2 = vx1; } if (vy1 < vy2) { ry1 = vy1; ry2 = vy2; } else { ry1 = vy2; ry2 = vy1; } rx1 = CLAMP (rx1, clip_bounds->x_1, clip_bounds->x_2); ry1 = CLAMP (ry1, clip_bounds->y_1, clip_bounds->y_2); rx2 = CLAMP (rx2, clip_bounds->x_1, clip_bounds->x_2); ry2 = CLAMP (ry2, clip_bounds->y_1, clip_bounds->y_2); /* Check if the rectangle intersects the clip at all */ if (rx1 == rx2 || ry1 == ry2) /* Will set all of the vertex data to 0 in the hope that this will create a degenerate rectangle and the GL driver will be able to clip it quickly */ memset (verts, 0, sizeof (float) * stride * 2); else { if (vx1 > vx2) { float t = rx1; rx1 = rx2; rx2 = t; } if (vy1 > vy2) { float t = ry1; ry1 = ry2; ry2 = t; } verts[0] = rx1; verts[1] = ry1; verts[stride] = rx2; verts[stride + 1] = ry2; /* Convert the rectangle coordinates to a fraction of the original rectangle */ rx1 = (rx1 - vx1) / (vx2 - vx1); ry1 = (ry1 - vy1) / (vy2 - vy1); rx2 = (rx2 - vx1) / (vx2 - vx1); ry2 = (ry2 - vy1) / (vy2 - vy1); for (layer_num = 0; layer_num < journal_entry->n_layers; layer_num++) { float *t = verts + 2 + 2 * layer_num; float tx1 = t[0], ty1 = t[1]; float tx2 = t[stride], ty2 = t[stride + 1]; t[0] = rx1 * (tx2 - tx1) + tx1; t[1] = ry1 * (ty2 - ty1) + ty1; t[stride] = rx2 * (tx2 - tx1) + tx1; t[stride + 1] = ry2 * (ty2 - ty1) + ty1; } } } static void maybe_software_clip_entries (CoglJournalEntry *batch_start, int batch_len, CoglJournalFlushState *state) { CoglContext *ctx; CoglJournal *journal; CoglClipStack *clip_stack, *clip_entry; int entry_num; /* This tries to find cases where the entry is logged with a clip but it would be faster to modify the vertex and texture coordinates rather than flush the clip so that it can batch better */ /* If the batch is reasonably long then it's worthwhile programming the GPU to do the clip */ if (batch_len >= COGL_JOURNAL_HARDWARE_CLIP_THRESHOLD) return; clip_stack = batch_start->clip_stack; if (clip_stack == NULL) return; /* Verify that all of the clip stack entries are a simple rectangle clip */ for (clip_entry = clip_stack; clip_entry; clip_entry = clip_entry->parent) if (clip_entry->type != COGL_CLIP_STACK_RECT) return; ctx = state->ctx; journal = state->journal; /* This scratch buffer is used to store the translation for each entry in the journal. We store it in a separate buffer because it's expensive to calculate but at this point we still don't know whether we can clip all of the entries so we don't want to do the rest of the dependant calculations until we're sure we can. */ if (ctx->journal_clip_bounds == NULL) ctx->journal_clip_bounds = g_array_new (FALSE, FALSE, sizeof (ClipBounds)); g_array_set_size (ctx->journal_clip_bounds, batch_len); for (entry_num = 0; entry_num < batch_len; entry_num++) { CoglJournalEntry *journal_entry = batch_start + entry_num; CoglJournalEntry *prev_journal_entry = entry_num ? batch_start + (entry_num - 1) : NULL; ClipBounds *clip_bounds = &g_array_index (ctx->journal_clip_bounds, ClipBounds, entry_num); if (!can_software_clip_entry (journal_entry, prev_journal_entry, clip_stack, clip_bounds)) return; } /* If we make it here then we know we can software clip the entire batch */ COGL_NOTE (CLIPPING, "Software clipping a batch of length %i", batch_len); for (entry_num = 0; entry_num < batch_len; entry_num++) { CoglJournalEntry *journal_entry = batch_start + entry_num; float *verts = &g_array_index (journal->vertices, float, journal_entry->array_offset + 1); ClipBounds *clip_bounds = &g_array_index (ctx->journal_clip_bounds, ClipBounds, entry_num); software_clip_entry (journal_entry, verts, clip_bounds); } return; } static void _cogl_journal_maybe_software_clip_entries (CoglJournalEntry *batch_start, int batch_len, void *data) { CoglJournalFlushState *state = data; COGL_STATIC_TIMER (time_check_software_clip, "Journal Flush", /* parent */ "flush: software clipping", "Time spent software clipping", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, time_check_software_clip); maybe_software_clip_entries (batch_start, batch_len, state); COGL_TIMER_STOP (_cogl_uprof_context, time_check_software_clip); } static CoglBool compare_entry_clip_stacks (CoglJournalEntry *entry0, CoglJournalEntry *entry1) { return entry0->clip_stack == entry1->clip_stack; } /* Gets a new vertex array from the pool. A reference is taken on the array so it can be treated as if it was just newly allocated */ static CoglAttributeBuffer * create_attribute_buffer (CoglJournal *journal, size_t n_bytes) { CoglAttributeBuffer *vbo; CoglContext *ctx = journal->framebuffer->context; /* If CoglBuffers are being emulated with malloc then there's not really any point in using the pool so we'll just allocate the buffer directly */ if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_VBOS)) return cogl_attribute_buffer_new_with_size (ctx, n_bytes); vbo = journal->vbo_pool[journal->next_vbo_in_pool]; if (vbo == NULL) { vbo = cogl_attribute_buffer_new_with_size (ctx, n_bytes); journal->vbo_pool[journal->next_vbo_in_pool] = vbo; } else if (cogl_buffer_get_size (COGL_BUFFER (vbo)) < n_bytes) { /* If the buffer is too small then we'll just recreate it */ cogl_object_unref (vbo); vbo = cogl_attribute_buffer_new_with_size (ctx, n_bytes); journal->vbo_pool[journal->next_vbo_in_pool] = vbo; } journal->next_vbo_in_pool = ((journal->next_vbo_in_pool + 1) % COGL_JOURNAL_VBO_POOL_SIZE); return cogl_object_ref (vbo); } static CoglAttributeBuffer * upload_vertices (CoglJournal *journal, const CoglJournalEntry *entries, int n_entries, size_t needed_vbo_len, GArray *vertices) { CoglAttributeBuffer *attribute_buffer; CoglBuffer *buffer; const float *vin; float *vout; int entry_num; int i; CoglMatrixEntry *last_modelview_entry = NULL; CoglMatrix modelview; g_assert (needed_vbo_len); attribute_buffer = create_attribute_buffer (journal, needed_vbo_len * 4); buffer = COGL_BUFFER (attribute_buffer); cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC); vout = _cogl_buffer_map_range_for_fill_or_fallback (buffer, 0, /* offset */ needed_vbo_len * 4); vin = &g_array_index (vertices, float, 0); /* Expand the number of vertices from 2 to 4 while uploading */ for (entry_num = 0; entry_num < n_entries; entry_num++) { const CoglJournalEntry *entry = entries + entry_num; size_t vb_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (entry->n_layers); size_t array_stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers); /* Copy the color to all four of the vertices */ for (i = 0; i < 4; i++) memcpy (vout + vb_stride * i + POS_STRIDE, vin, 4); vin++; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) { vout[vb_stride * 0] = vin[0]; vout[vb_stride * 0 + 1] = vin[1]; vout[vb_stride * 1] = vin[0]; vout[vb_stride * 1 + 1] = vin[array_stride + 1]; vout[vb_stride * 2] = vin[array_stride]; vout[vb_stride * 2 + 1] = vin[array_stride + 1]; vout[vb_stride * 3] = vin[array_stride]; vout[vb_stride * 3 + 1] = vin[1]; } else { float v[8]; v[0] = vin[0]; v[1] = vin[1]; v[2] = vin[0]; v[3] = vin[array_stride + 1]; v[4] = vin[array_stride]; v[5] = vin[array_stride + 1]; v[6] = vin[array_stride]; v[7] = vin[1]; if (entry->modelview_entry != last_modelview_entry) cogl_matrix_entry_get (entry->modelview_entry, &modelview); cogl_matrix_transform_points (&modelview, 2, /* n_components */ sizeof (float) * 2, /* stride_in */ v, /* points_in */ /* strideout */ vb_stride * sizeof (float), vout, /* points_out */ 4 /* n_points */); } for (i = 0; i < entry->n_layers; i++) { const float *tin = vin + 2; float *tout = vout + POS_STRIDE + COLOR_STRIDE; tout[vb_stride * 0 + i * 2] = tin[i * 2]; tout[vb_stride * 0 + 1 + i * 2] = tin[i * 2 + 1]; tout[vb_stride * 1 + i * 2] = tin[i * 2]; tout[vb_stride * 1 + 1 + i * 2] = tin[array_stride + i * 2 + 1]; tout[vb_stride * 2 + i * 2] = tin[array_stride + i * 2]; tout[vb_stride * 2 + 1 + i * 2] = tin[array_stride + i * 2 + 1]; tout[vb_stride * 3 + i * 2] = tin[array_stride + i * 2]; tout[vb_stride * 3 + 1 + i * 2] = tin[i * 2 + 1]; } vin += array_stride * 2; vout += vb_stride * 4; } _cogl_buffer_unmap_for_fill_or_fallback (buffer); return attribute_buffer; } void _cogl_journal_discard (CoglJournal *journal) { int i; if (journal->entries->len <= 0) return; for (i = 0; i < journal->entries->len; i++) { CoglJournalEntry *entry = &g_array_index (journal->entries, CoglJournalEntry, i); _cogl_pipeline_journal_unref (entry->pipeline); cogl_matrix_entry_unref (entry->modelview_entry); _cogl_clip_stack_unref (entry->clip_stack); } g_array_set_size (journal->entries, 0); g_array_set_size (journal->vertices, 0); journal->needed_vbo_len = 0; journal->fast_read_pixel_count = 0; /* The journal only holds a reference to the framebuffer while the journal is not empty */ cogl_object_unref (journal->framebuffer); } /* Note: A return value of FALSE doesn't mean 'no' it means * 'unknown' */ CoglBool _cogl_journal_all_entries_within_bounds (CoglJournal *journal, float clip_x0, float clip_y0, float clip_x1, float clip_y1) { CoglJournalEntry *entry = (CoglJournalEntry *)journal->entries->data; CoglClipStack *clip_entry; CoglClipStack *reference = NULL; int bounds_x0; int bounds_y0; int bounds_x1; int bounds_y1; int i; if (journal->entries->len == 0) return TRUE; /* Find the shortest clip_stack ancestry that leaves us in the * required bounds */ for (clip_entry = entry->clip_stack; clip_entry; clip_entry = clip_entry->parent) { _cogl_clip_stack_get_bounds (clip_entry, &bounds_x0, &bounds_y0, &bounds_x1, &bounds_y1); if (bounds_x0 >= clip_x0 && bounds_y0 >= clip_y0 && bounds_x1 <= clip_x1 && bounds_y1 <= clip_y1) reference = clip_entry; else break; } if (!reference) return FALSE; /* For the remaining journal entries we will only verify they share * 'reference' as an ancestor in their clip stack since that's * enough to know that they would be within the required bounds. */ for (i = 1; i < journal->entries->len; i++) { CoglBool found_reference = FALSE; entry = &g_array_index (journal->entries, CoglJournalEntry, i); for (clip_entry = entry->clip_stack; clip_entry; clip_entry = clip_entry->parent) { if (clip_entry == reference) { found_reference = TRUE; break; } } if (!found_reference) return FALSE; } return TRUE; } static void post_fences (CoglJournal *journal) { CoglFenceClosure *fence, *tmp; _cogl_list_for_each_safe (fence, tmp, &journal->pending_fences, link) { _cogl_list_remove (&fence->link); _cogl_fence_submit (fence); } } /* XXX NB: When _cogl_journal_flush() returns all state relating * to pipelines, all glEnable flags and current matrix state * is undefined. */ void _cogl_journal_flush (CoglJournal *journal) { CoglFramebuffer *framebuffer; CoglContext *ctx; CoglJournalFlushState state; int i; COGL_STATIC_TIMER (flush_timer, "Mainloop", /* parent */ "Journal Flush", "The time spent flushing the Cogl journal", 0 /* no application private data */); COGL_STATIC_TIMER (discard_timer, "Journal Flush", /* parent */ "flush: discard", "The time spent discarding the Cogl journal after a flush", 0 /* no application private data */); if (journal->entries->len == 0) { post_fences (journal); return; } framebuffer = journal->framebuffer; ctx = framebuffer->context; /* The entries in this journal may depend on images in other * framebuffers which may require that we flush the journals * associated with those framebuffers before we can flush * this journal... */ _cogl_framebuffer_flush_dependency_journals (framebuffer); /* Note: we start the timer after flushing dependency journals so * that the timer isn't started recursively. */ COGL_TIMER_START (_cogl_uprof_context, flush_timer); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING))) g_print ("BATCHING: journal len = %d\n", journal->entries->len); /* NB: the journal deals with flushing the modelview stack and clip state manually */ _cogl_framebuffer_flush_state (framebuffer, framebuffer, COGL_FRAMEBUFFER_STATE_ALL & ~(COGL_FRAMEBUFFER_STATE_MODELVIEW | COGL_FRAMEBUFFER_STATE_CLIP)); /* We need to mark the current modelview state of the framebuffer as * dirty because we are going to manually replace it */ ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW; state.ctx = ctx; state.journal = journal; state.attributes = ctx->journal_flush_attributes_array; if (G_UNLIKELY ((COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_CLIP)) == 0)) { /* We do an initial walk of the journal to analyse the clip stack batches to see if we can do software clipping. We do this as a separate walk of the journal because we can modify entries and this may end up joining together clip stack batches in the next iteration. */ batch_and_call ((CoglJournalEntry *)journal->entries->data, /* first entry */ journal->entries->len, /* max number of entries to consider */ compare_entry_clip_stacks, _cogl_journal_maybe_software_clip_entries, /* callback */ &state); /* data */ } /* We upload the vertices after the clip stack pass in case it modifies the entries */ state.attribute_buffer = upload_vertices (journal, &g_array_index (journal->entries, CoglJournalEntry, 0), journal->entries->len, journal->needed_vbo_len, journal->vertices); state.array_offset = 0; /* batch_and_call() batches a list of journal entries according to some * given criteria and calls a callback once for each determined batch. * * The process of flushing the journal is staggered to reduce the amount * of driver/GPU state changes necessary: * 1) We split the entries according to the clip state. * 2) We split the entries according to the stride of the vertices: * Each time the stride of our vertex data changes we need to call * gl{Vertex,Color}Pointer to inform GL of new VBO offsets. * Currently the only thing that affects the stride of our vertex data * is the number of pipeline layers. * 3) We split the entries explicitly by the number of pipeline layers: * We pad our vertex data when the number of layers is < 2 so that we * can minimize changes in stride. Each time the number of layers * changes we need to call glTexCoordPointer to inform GL of new VBO * offsets. * 4) We then split according to compatible Cogl pipelines: * This is where we flush pipeline state * 5) Finally we split according to modelview matrix changes: * This is when we finally tell GL to draw something. * Note: Splitting by modelview changes is skipped when are doing the * vertex transformation in software at log time. */ batch_and_call ((CoglJournalEntry *)journal->entries->data, /* first entry */ journal->entries->len, /* max number of entries to consider */ compare_entry_clip_stacks, _cogl_journal_flush_clip_stacks_and_entries, /* callback */ &state); /* data */ for (i = 0; i < state.attributes->len; i++) cogl_object_unref (g_array_index (state.attributes, CoglAttribute *, i)); g_array_set_size (state.attributes, 0); cogl_object_unref (state.attribute_buffer); COGL_TIMER_START (_cogl_uprof_context, discard_timer); _cogl_journal_discard (journal); COGL_TIMER_STOP (_cogl_uprof_context, discard_timer); post_fences (journal); COGL_TIMER_STOP (_cogl_uprof_context, flush_timer); } static CoglBool add_framebuffer_deps_cb (CoglPipelineLayer *layer, void *user_data) { CoglFramebuffer *framebuffer = user_data; CoglTexture *texture = _cogl_pipeline_layer_get_texture_real (layer); const GList *l; if (!texture) return TRUE; for (l = _cogl_texture_get_associated_framebuffers (texture); l; l = l->next) _cogl_framebuffer_add_dependency (framebuffer, l->data); return TRUE; } void _cogl_journal_log_quad (CoglJournal *journal, const float *position, CoglPipeline *pipeline, int n_layers, CoglTexture *layer0_override_texture, const float *tex_coords, unsigned int tex_coords_len) { CoglFramebuffer *framebuffer = journal->framebuffer; size_t stride; int next_vert; float *v; int i; int next_entry; uint32_t disable_layers; CoglJournalEntry *entry; CoglPipeline *final_pipeline; CoglClipStack *clip_stack; CoglPipelineFlushOptions flush_options; CoglMatrixStack *modelview_stack; COGL_STATIC_TIMER (log_timer, "Mainloop", /* parent */ "Journal Log", "The time spent logging in the Cogl journal", 0 /* no application private data */); COGL_TIMER_START (_cogl_uprof_context, log_timer); /* Adding something to the journal should mean that we are in the * middle of the scene. Although this will also end up being set * when the journal is actually flushed, we set it here explicitly * so that we will know sooner */ _cogl_framebuffer_mark_mid_scene (framebuffer); /* If the framebuffer was previously empty then we'll take a reference to the current framebuffer. This reference will be removed when the journal is flushed */ if (journal->vertices->len == 0) cogl_object_ref (framebuffer); /* The vertex data is logged into a separate array. The data needs to be copied into a vertex array before it's given to GL so we only store two vertices per quad and expand it to four while uploading. */ /* XXX: See definition of GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS for details * about how we pack our vertex data */ stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (n_layers); next_vert = journal->vertices->len; g_array_set_size (journal->vertices, next_vert + 2 * stride + 1); v = &g_array_index (journal->vertices, float, next_vert); /* We calculate the needed size of the vbo as we go because it depends on the number of layers in each entry and it's not easy calculate based on the length of the logged vertices array */ journal->needed_vbo_len += GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4; /* XXX: All the jumping around to fill in this strided buffer doesn't * seem ideal. */ /* FIXME: This is a hacky optimization, since it will break if we * change the definition of CoglColor: */ _cogl_pipeline_get_colorubv (pipeline, (uint8_t *) v); v++; memcpy (v, position, sizeof (float) * 2); memcpy (v + stride, position + 2, sizeof (float) * 2); for (i = 0; i < n_layers; i++) { /* XXX: See definition of GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS * for details about how we pack our vertex data */ GLfloat *t = v + 2 + i * 2; memcpy (t, tex_coords + i * 4, sizeof (float) * 2); memcpy (t + stride, tex_coords + i * 4 + 2, sizeof (float) * 2); } if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL))) { g_print ("Logged new quad:\n"); v = &g_array_index (journal->vertices, float, next_vert); _cogl_journal_dump_logged_quad ((uint8_t *)v, n_layers); } next_entry = journal->entries->len; g_array_set_size (journal->entries, next_entry + 1); entry = &g_array_index (journal->entries, CoglJournalEntry, next_entry); entry->n_layers = n_layers; entry->array_offset = next_vert; final_pipeline = pipeline; flush_options.flags = 0; if (G_UNLIKELY (cogl_pipeline_get_n_layers (pipeline) != n_layers)) { disable_layers = (1 << n_layers) - 1; disable_layers = ~disable_layers; flush_options.disable_layers = disable_layers; flush_options.flags |= COGL_PIPELINE_FLUSH_DISABLE_MASK; } if (G_UNLIKELY (layer0_override_texture)) { flush_options.flags |= COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE; flush_options.layer0_override_texture = layer0_override_texture; } if (G_UNLIKELY (flush_options.flags)) { final_pipeline = cogl_pipeline_copy (pipeline); _cogl_pipeline_apply_overrides (final_pipeline, &flush_options); } entry->pipeline = _cogl_pipeline_journal_ref (final_pipeline); clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer); entry->clip_stack = _cogl_clip_stack_ref (clip_stack); if (G_UNLIKELY (final_pipeline != pipeline)) cogl_object_unref (final_pipeline); modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); entry->modelview_entry = cogl_matrix_entry_ref (modelview_stack->last_entry); _cogl_pipeline_foreach_layer_internal (pipeline, add_framebuffer_deps_cb, framebuffer); if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BATCHING))) _cogl_journal_flush (journal); COGL_TIMER_STOP (_cogl_uprof_context, log_timer); } static void entry_to_screen_polygon (CoglFramebuffer *framebuffer, const CoglJournalEntry *entry, float *vertices, float *poly) { size_t array_stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers); CoglMatrixStack *projection_stack; CoglMatrix projection; CoglMatrix modelview; int i; float viewport[4]; poly[0] = vertices[0]; poly[1] = vertices[1]; poly[2] = 0; poly[3] = 1; poly[4] = vertices[0]; poly[5] = vertices[array_stride + 1]; poly[6] = 0; poly[7] = 1; poly[8] = vertices[array_stride]; poly[9] = vertices[array_stride + 1]; poly[10] = 0; poly[11] = 1; poly[12] = vertices[array_stride]; poly[13] = vertices[1]; poly[14] = 0; poly[15] = 1; /* TODO: perhaps split the following out into a more generalized * _cogl_transform_points utility... */ cogl_matrix_entry_get (entry->modelview_entry, &modelview); cogl_matrix_transform_points (&modelview, 2, /* n_components */ sizeof (float) * 4, /* stride_in */ poly, /* points_in */ /* strideout */ sizeof (float) * 4, poly, /* points_out */ 4 /* n_points */); projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); cogl_matrix_stack_get (projection_stack, &projection); cogl_matrix_project_points (&projection, 3, /* n_components */ sizeof (float) * 4, /* stride_in */ poly, /* points_in */ /* strideout */ sizeof (float) * 4, poly, /* points_out */ 4 /* n_points */); cogl_framebuffer_get_viewport4fv (framebuffer, viewport); /* Scale from OpenGL normalized device coordinates (ranging from -1 to 1) * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with * (0,0) being top left. */ #define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \ ( ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x) ) /* Note: for Y we first flip all coordinates around the X axis while in * normalized device coodinates */ #define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \ ( ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y) ) /* Scale from normalized device coordinates (in range [-1,1]) to * window coordinates ranging [0,window-size] ... */ for (i = 0; i < 4; i++) { float w = poly[4 * i + 3]; /* Perform perspective division */ poly[4 * i] /= w; poly[4 * i + 1] /= w; /* Apply viewport transform */ poly[4 * i] = VIEWPORT_TRANSFORM_X (poly[4 * i], viewport[0], viewport[2]); poly[4 * i + 1] = VIEWPORT_TRANSFORM_Y (poly[4 * i + 1], viewport[1], viewport[3]); } #undef VIEWPORT_TRANSFORM_X #undef VIEWPORT_TRANSFORM_Y } static CoglBool try_checking_point_hits_entry_after_clipping (CoglFramebuffer *framebuffer, CoglJournalEntry *entry, float *vertices, float x, float y, CoglBool *hit) { CoglBool can_software_clip = TRUE; CoglBool needs_software_clip = FALSE; CoglClipStack *clip_entry; *hit = TRUE; /* Verify that all of the clip stack entries are simple rectangle * clips */ for (clip_entry = entry->clip_stack; clip_entry; clip_entry = clip_entry->parent) { if (x < clip_entry->bounds_x0 || x >= clip_entry->bounds_x1 || y < clip_entry->bounds_y0 || y >= clip_entry->bounds_y1) { *hit = FALSE; return TRUE; } if (clip_entry->type == COGL_CLIP_STACK_WINDOW_RECT) { /* XXX: technically we could still run the software clip in * this case because for our purposes we know this clip * can be ignored now, but [can_]sofware_clip_entry() doesn't * know this and will bail out. */ can_software_clip = FALSE; } else if (clip_entry->type == COGL_CLIP_STACK_RECT) { CoglClipStackRect *rect_entry = (CoglClipStackRect *)entry; if (rect_entry->can_be_scissor == FALSE) needs_software_clip = TRUE; /* If can_be_scissor is TRUE then we know it's screen * aligned and the hit test we did above has determined * that we are inside this clip. */ } else return FALSE; } if (needs_software_clip) { ClipBounds clip_bounds; float poly[16]; if (!can_software_clip) return FALSE; if (!can_software_clip_entry (entry, NULL, entry->clip_stack, &clip_bounds)) return FALSE; software_clip_entry (entry, vertices, &clip_bounds); entry_to_screen_polygon (framebuffer, entry, vertices, poly); *hit = _cogl_util_point_in_screen_poly (x, y, poly, sizeof (float) * 4, 4); return TRUE; } return TRUE; } CoglBool _cogl_journal_try_read_pixel (CoglJournal *journal, int x, int y, CoglBitmap *bitmap, CoglBool *found_intersection) { CoglContext *ctx; CoglPixelFormat format; int i; /* XXX: this number has been plucked out of thin air, but the idea * is that if so many pixels are being read from the same un-changed * journal than we expect that it will be more efficient to fail * here so we end up flushing and rendering the journal so that * further reads can directly read from the framebuffer. There will * be a bit more lag to flush the render but if there are going to * continue being lots of arbitrary single pixel reads they will end * up faster in the end. */ if (journal->fast_read_pixel_count > 50) return FALSE; format = cogl_bitmap_get_format (bitmap); if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE && format != COGL_PIXEL_FORMAT_RGBA_8888) return FALSE; ctx = _cogl_bitmap_get_context (bitmap); *found_intersection = FALSE; /* NB: The most recently added journal entry is the last entry, and * assuming this is a simple scene only comprised of opaque coloured * rectangles with no special pipelines involved (e.g. enabling * depth testing) then we can assume painter's algorithm for the * entries and so our fast read-pixel just needs to walk backwards * through the journal entries trying to intersect each entry with * the given point of interest. */ for (i = journal->entries->len - 1; i >= 0; i--) { CoglJournalEntry *entry = &g_array_index (journal->entries, CoglJournalEntry, i); uint8_t *color = (uint8_t *)&g_array_index (journal->vertices, float, entry->array_offset); float *vertices = (float *)color + 1; float poly[16]; CoglFramebuffer *framebuffer = journal->framebuffer; uint8_t *pixel; CoglError *ignore_error; entry_to_screen_polygon (framebuffer, entry, vertices, poly); if (!_cogl_util_point_in_screen_poly (x, y, poly, sizeof (float) * 4, 4)) continue; if (entry->clip_stack) { CoglBool hit; if (!try_checking_point_hits_entry_after_clipping (framebuffer, entry, vertices, x, y, &hit)) return FALSE; /* hit couldn't be determined */ if (!hit) continue; } *found_intersection = TRUE; /* If we find that the rectangle the point of interest * intersects has any state more complex than a constant opaque * color then we bail out. */ if (!_cogl_pipeline_equal (ctx->opaque_color_pipeline, entry->pipeline, (COGL_PIPELINE_STATE_ALL & ~COGL_PIPELINE_STATE_COLOR), COGL_PIPELINE_LAYER_STATE_ALL, 0)) return FALSE; /* we currently only care about cases where the premultiplied or * unpremultipled colors are equivalent... */ if (color[3] != 0xff) return FALSE; pixel = _cogl_bitmap_map (bitmap, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD, &ignore_error); if (pixel == NULL) { cogl_error_free (ignore_error); return FALSE; } pixel[0] = color[0]; pixel[1] = color[1]; pixel[2] = color[2]; pixel[3] = color[3]; _cogl_bitmap_unmap (bitmap); goto success; } success: journal->fast_read_pixel_count++; return TRUE; } muffin-5.2.1/cogl/cogl/cogl-depth-state.h0000664000175000017500000002053614211404421020327 0ustar jpeisachjpeisach/* * Cogl * * A Low Level GPU Graphics and Utilities API * * Copyright (C) 2011 Intel Corporation. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Robert Bragg * */ #if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) #error "Only can be included directly." #endif #ifndef __COGL_DEPTH_STATE_H__ #define __COGL_DEPTH_STATE_H__ COGL_BEGIN_DECLS /** * SECTION:cogl-depth-state * @short_description: Functions for describing the depth testing * state of your GPU. */ /** * CoglDepthState: * * Since: 2.0 */ typedef struct { /*< private >*/ uint32_t COGL_PRIVATE (magic); CoglBool COGL_PRIVATE (test_enabled); CoglDepthTestFunction COGL_PRIVATE (test_function); CoglBool COGL_PRIVATE (write_enabled); float COGL_PRIVATE (range_near); float COGL_PRIVATE (range_far); uint32_t COGL_PRIVATE (padding0); uint32_t COGL_PRIVATE (padding1); uint32_t COGL_PRIVATE (padding2); uint32_t COGL_PRIVATE (padding3); uint32_t COGL_PRIVATE (padding4); uint32_t COGL_PRIVATE (padding5); uint32_t COGL_PRIVATE (padding6); uint32_t COGL_PRIVATE (padding7); uint32_t COGL_PRIVATE (padding8); uint32_t COGL_PRIVATE (padding9); } CoglDepthState; /** * cogl_depth_state_init: * @state: A #CoglDepthState struct * * Initializes the members of @state to their default values. * * You should never pass an un initialized #CoglDepthState structure * to cogl_pipeline_set_depth_state(). * * Since: 2.0 * Stability: Unstable */ void cogl_depth_state_init (CoglDepthState *state); /** * cogl_depth_state_set_test_enabled: * @state: A #CoglDepthState struct * @enable: The enable state you want * * Enables or disables depth testing according to the value of * @enable. * * If depth testing is enable then the #CoglDepthTestFunction set * using cogl_depth_state_set_test_function() us used to evaluate * the depth value of incoming fragments against the corresponding * value stored in the current depth buffer, and if the test passes * then the fragments depth value is used to update the depth buffer. * (unless you have disabled depth writing via * cogl_depth_state_set_write_enabled()) * * By default depth testing is disabled. * * NB: this won't directly affect the state of the GPU. You have * to then set the state on a #CoglPipeline using * cogl_pipeline_set_depth_state() * * Since: 2.0 * Stability: Unstable */ void cogl_depth_state_set_test_enabled (CoglDepthState *state, CoglBool enable); /** * cogl_depth_state_get_test_enabled: * @state: A #CoglDepthState struct * * Gets the current depth test enabled state as previously set by * cogl_depth_state_set_test_enabled(). * * Returns: The pipeline's current depth test enabled state. * Since: 2.0 * Stability: Unstable */ CoglBool cogl_depth_state_get_test_enabled (CoglDepthState *state); /** * cogl_depth_state_set_write_enabled: * @state: A #CoglDepthState struct * @enable: The enable state you want * * Enables or disables depth buffer writing according to the value of * @enable. Normally when depth testing is enabled and the comparison * between a fragment's depth value and the corresponding depth buffer * value passes then the fragment's depth is written to the depth * buffer unless writing is disabled here. * * By default depth writing is enabled * * NB: this won't directly affect the state of the GPU. You have * to then set the state on a #CoglPipeline using * cogl_pipeline_set_depth_state() * * Since: 2.0 * Stability: Unstable */ void cogl_depth_state_set_write_enabled (CoglDepthState *state, CoglBool enable); /** * cogl_depth_state_get_write_enabled: * @state: A #CoglDepthState struct * * Gets the depth writing enable state as set by the corresponding * cogl_depth_state_set_write_enabled(). * * Returns: The current depth writing enable state * Since: 2.0 * Stability: Unstable */ CoglBool cogl_depth_state_get_write_enabled (CoglDepthState *state); /** * cogl_depth_state_set_test_function: * @state: A #CoglDepthState struct * @function: The #CoglDepthTestFunction to set * * Sets the #CoglDepthTestFunction used to compare the depth value of * an incoming fragment against the corresponding value in the current * depth buffer. * * By default the depth test function is %COGL_DEPTH_TEST_FUNCTION_LESS * * NB: this won't directly affect the state of the GPU. You have * to then set the state on a #CoglPipeline using * cogl_pipeline_set_depth_state() * * Since: 2.0 * Stability: Unstable */ void cogl_depth_state_set_test_function (CoglDepthState *state, CoglDepthTestFunction function); /** * cogl_depth_state_get_test_function: * @state: A #CoglDepthState struct * * Gets the current depth test enable state as previously set via * cogl_depth_state_set_test_enabled(). * * Returns: The current depth test enable state. * Since: 2.0 * Stability: Unstable */ CoglDepthTestFunction cogl_depth_state_get_test_function (CoglDepthState *state); /** * cogl_depth_state_set_range: * @state: A #CoglDepthState object * @near_val: The near component of the desired depth range which will be * clamped to the range [0, 1] * @far_val: The far component of the desired depth range which will be * clamped to the range [0, 1] * * Sets the range to map depth values in normalized device coordinates * to before writing out to a depth buffer. * * After your geometry has be transformed, clipped and had perspective * division applied placing it in normalized device * coordinates all depth values between the near and far z clipping * planes are in the range -1 to 1. Before writing any depth value to * the depth buffer though the value is mapped into the range [0, 1]. * * With this function you can change the range which depth values are * mapped too although the range must still lye within the range [0, * 1]. * * If your driver does not support this feature (for example you are * using GLES 1 drivers) then if you don't use the default range * values you will get an error reported when calling * cogl_pipeline_set_depth_state (). You can check ahead of time for * the %COGL_FEATURE_ID_DEPTH_RANGE feature with * cogl_has_feature() to know if this function will succeed. * * By default normalized device coordinate depth values are mapped to * the full range of depth buffer values, [0, 1]. * * NB: this won't directly affect the state of the GPU. You have * to then set the state on a #CoglPipeline using * cogl_pipeline_set_depth_state(). * * Since: 2.0 * Stability: Unstable */ void cogl_depth_state_set_range (CoglDepthState *state, float near_val, float far_val); /** * cogl_depth_state_get_range: * @state: A #CoglDepthState object * @near_val: A pointer to store the near component of the depth range * @far_val: A pointer to store the far component of the depth range * * Gets the current range to which normalized depth values are mapped * before writing to the depth buffer. This corresponds to the range * set with cogl_depth_state_set_range(). * * Since: 2.0 * Stability: Unstable */ void cogl_depth_state_get_range (CoglDepthState *state, float *near_val, float *far_val); COGL_END_DECLS #endif /* __COGL_DEPTH_STATE_H__ */ muffin-5.2.1/cogl/configure.ac0000664000175000017500000011214514211404421016352 0ustar jpeisachjpeisachAC_PREREQ(2.59) dnl ================================================================ dnl XXX: If you are making a release then you need to check these dnl sections: dnl » API versions (Only the 1.x version needs to change) dnl (the pretty numbers that the users see) dnl dnl » Interface version details for libtool dnl (the shared library versioning information) dnl dnl » Source code release status dnl (mark the source code as being part of a "release" or from "git") dnl ================================================================ dnl ================================================================ dnl API versions (i.e. the pretty numbers that users see) dnl ================================================================ m4_define([cogl_major_version], [2]) m4_define([cogl_minor_version], [0]) m4_define([cogl_micro_version], [0]) m4_define([cogl_version], [cogl_major_version.cogl_minor_version.cogl_micro_version]) dnl Since the core Cogl library has to also maintain support for the dnl Cogl 1.x API for Clutter then we track the 1.x version separately. m4_define([cogl_1_minor_version], [22]) m4_define([cogl_1_micro_version], [1]) m4_define([cogl_1_version], [1.cogl_1_minor_version.cogl_1_micro_version]) dnl ================================================================ dnl Interface version details for libtool dnl ================================================================ # Note: we don't automatically deduce the libtool version info from # the pretty version number that users sees. This is because we want # to update the pretty version number before making a release since it # can affect the name of our pkg-config file and the naming or # location of other installed files which we want to be able to verify # as correct well before making a release. # # For reference on how the various numbers should be updated at # release time these rules are adapted from the libtool info pages: # # 1. Update the version information only immediately before a public # release. # # 2. If the library source code has changed at all since the last # update, then increment REVISION (`C:R:A' becomes `C:r+1:A'). # # 3. If any interfaces have been added, removed, or changed since the # last update, increment CURRENT, and set REVISION to 0. # # 4. If any interfaces have been added since the last public release, # then increment AGE. # # 5. If any interfaces have been removed since the last public release, # then set AGE to 0. m4_define([cogl_lt_current], 24) m4_define([cogl_lt_revision], 1) m4_define([cogl_lt_age], 4) # We do also tell libtool the pretty version: m4_define([cogl_lt_release], [cogl_version]) dnl ================================================================ dnl Source code release status dnl ================================================================ # Finally we explicitly track when we are building development source # from Git vs building source corresponding to a release. As with the # libtool version info we don't automatically derive this from the # pretty version number because we want to test the results of # updating the version number in advance of a release. # # Possible status values are: git, snapshot or release # m4_define([cogl_release_status], [git]) AC_INIT(cogl, [cogl_1_version]) AC_CONFIG_SRCDIR(cogl/cogl.h) AC_CONFIG_AUX_DIR([build]) AC_CONFIG_MACRO_DIR([build/autotools]) AC_CONFIG_HEADERS(cogl-config.h) AC_CONFIG_HEADERS(cogl-muffin-config.h) AC_GNU_SOURCE dnl ================================================================ dnl Check that we are configured by muffin dnl ================================================================ AC_ARG_VAR([MUFFIN_VERSION]) AC_ARG_VAR([MUFFIN_PLUGIN_API_VERSION]) AS_IF([test "x$MUFFIN_VERSION" = "x"], [AC_MSG_ERROR([Clutter can only be configured by muffin])],) dnl ================================================================ dnl Required versions for dependencies dnl ================================================================ m4_define([glib_req_version], [2.32.0]) m4_define([pangocairo_req_version], [1.20]) m4_define([gi_req_version], [0.9.5]) m4_define([gdk_pixbuf_req_version], [2.0]) m4_define([uprof_req_version], [0.3]) m4_define([xfixes_req_version], [3]) m4_define([xcomposite_req_version], [0.4]) m4_define([xrandr_req_version], [1.2]) m4_define([cairo_req_version], [1.10]) m4_define([wayland_server_req_version], [1.1.90]) m4_define([mirclient_req_version], [0.9.0]) dnl These variables get copied into the generated README AC_SUBST([GLIB_REQ_VERSION], [glib_req_version]) AC_SUBST([GDK_PIXBUF_REQ_VERSION], [gdk_pixbuf_req_version]) AC_SUBST([CAIRO_REQ_VERSION], [cairo_req_version]) AC_SUBST([PANGOCAIRO_REQ_VERSION], [pangocairo_req_version]) AC_SUBST([XCOMPOSITE_REQ_VERSION], [xcomposite_req_version]) AC_SUBST([XFIXES_REQ_VERSION], [xfixes_req_version]) AC_SUBST([GI_REQ_VERSION], [gi_req_version]) AC_SUBST([UPROF_REQ_VERSION], [uprof_req_version]) AC_SUBST([WAYLAND_SERVER_REQ_VERSION], [wayland_server_req_version]) # Save this value here, since automake will set cflags later and we # want to know if the user specified custom cflags or not. cflags_set=${CFLAGS+set} AM_INIT_AUTOMAKE([1.14 foreign -Wno-portability no-define no-dist-gzip dist-xz tar-ustar subdir-objects]) AM_SILENT_RULES([yes]) AH_BOTTOM([#include "config-custom.h"]) dnl ================================================================ dnl Export the API versioning dnl ================================================================ AC_SUBST([COGL_MAJOR_VERSION],[cogl_major_version]) AC_SUBST([COGL_MINOR_VERSION],[cogl_minor_version]) AC_SUBST([COGL_MICRO_VERSION],[cogl_micro_version]) AC_SUBST([COGL_VERSION],[cogl_version]) AC_SUBST([COGL_API_VERSION],[cogl_major_version.0]) AC_SUBST([COGL_API_VERSION_AM],[$COGL_MAJOR_VERSION\_0]) AC_SUBST([COGL_1_MINOR_VERSION],[cogl_1_minor_version]) AC_SUBST([COGL_1_MICRO_VERSION],[cogl_1_micro_version]) AC_SUBST([COGL_1_VERSION],[cogl_1_version]) dnl ================================================================ dnl Export the libtool versioning dnl ================================================================ AC_SUBST([COGL_LT_CURRENT], [cogl_lt_current]) AC_SUBST([COGL_LT_REVISION], [cogl_lt_revision]) AC_SUBST([COGL_LT_AGE], [cogl_lt_age]) AC_SUBST([COGL_LT_RELEASE], [cogl_lt_release]) dnl ================================================================ dnl Export the source code release status dnl ================================================================ AC_SUBST([COGL_RELEASE_STATUS], [cogl_release_status]) dnl ================================================================ dnl Compiler stuff. dnl ================================================================ AC_PROG_CC AC_PROG_CPP AC_PROG_CXX AM_PROG_CC_C_O AC_ISC_POSIX AC_C_CONST dnl ============================================================ dnl Compiler features dnl ============================================================ AC_MSG_CHECKING([for _Static_assert]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_Static_assert (1, "");], [(void) 0])], [AC_DEFINE([HAVE_STATIC_ASSERT], [1], [Whether _Static_assert can be used or not]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) dnl ================================================================ dnl Libtool stuff. dnl ================================================================ dnl AC_PROG_LIBTOOL dnl LIBTOOL="$LIBTOOL --preserve-dup-deps" LT_PREREQ([2.2.6]) LT_INIT([disable-static]) dnl when using libtool 2.x create libtool early, because it's used in the dnl internal glib configure (as-glibconfig.m4) m4_ifdef([LT_OUTPUT], [LT_OUTPUT]) dnl ================================================================ dnl Find an appropriate libm, for sin() etc. dnl ================================================================ LT_LIB_M AC_SUBST(LIBM) dnl ================================================================ dnl See what platform we are building for dnl ================================================================ AC_CANONICAL_HOST dnl ============================================================ dnl Installed tests dnl ============================================================ AC_ARG_ENABLE(installed_tests, AS_HELP_STRING([--enable-installed-tests], [Install test programs (default: no)]),, [enable_installed_tests=no]) AM_CONDITIONAL(ENABLE_INSTALLED_TESTS, test x$enable_installed_tests = xyes) dnl ============================================================ dnl Enable debugging dnl ============================================================ m4_define([debug_default], [m4_if(cogl_release_status, [git], [yes], [no])]) AC_ARG_ENABLE( [debug], [AC_HELP_STRING([--enable-debug=@<:@no/yes@:>@], [Control Cogl debugging level @<:@default=]debug_default[@:>@])], [], enable_debug=debug_default ) AS_CASE( [$enable_debug], [yes], [ test "$cflags_set" = set || CFLAGS="$CFLAGS -g -O0" COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DCOGL_GL_DEBUG -DCOGL_OBJECT_DEBUG -DCOGL_ENABLE_DEBUG" ], [no], [ COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS" ], [AC_MSG_ERROR([Unknown argument for --enable-debug])] ) AC_SUBST(COGL_DEBUG_CFLAGS) AC_ARG_ENABLE( [unit-tests], [AC_HELP_STRING([--enable-unit-tests=@<:@no/yes@:>@], [Build Cogl unit tests @<:@default=yes@:>@])], [], enable_unit_tests=yes ) AS_IF([test "x$enable_unit_tests" = "xyes"], [ AC_DEFINE([ENABLE_UNIT_TESTS], [1], [Whether to enable building unit tests]) ] ) AM_CONDITIONAL(UNIT_TESTS, test "x$enable_unit_tests" = "xyes") dnl ============================================================ dnl Enable cairo usage for debugging dnl (debugging code can use cairo to dump the atlas) dnl ============================================================ PKG_CHECK_EXISTS([CAIRO], [cairo >= cairo_req_version], [have_cairo=yes]) AC_ARG_ENABLE( [cairo], [AC_HELP_STRING([--enable-cairo=@<:@no/yes@:>@], [Control Cairo usage in Cogl debugging code @<:@default=auto@:>@])], [], [ AS_IF([test "x$enable_debug" = "xyes"], [enable_cairo=$have_cairo], [enable_cairo=no]) ] ) AS_IF([test "x$enable_cairo" = "xyes" && test "x$enable_debug" = "xyes"], [ AS_IF([test "x$have_cairo" != "xyes"], [AC_MSG_ERROR([Could not find Cairo])]) COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES cairo >= cairo_req_version" AC_DEFINE([HAVE_CAIRO], [1], [Whether we have cairo or not]) ]) dnl ============================================================ dnl Enable profiling dnl ============================================================ AC_ARG_ENABLE(profile, [AC_HELP_STRING([--enable-profile=@<:@no/yes@:>@], [Turn on uprof profiling support. yes; All UProf profiling probe points are compiled in and may be runtime enabled. no; No profiling support will built into cogl. @<:@default=no@:>@])], [], [enable_profile=no]) AS_IF([test "x$enable_profile" = "xyes"], [ AS_IF([test "x$GCC" = "xyes"], [ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES uprof-0.3" COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DCOGL_ENABLE_PROFILE" AS_IF([test "x$enable_debug" = "xyes"], [COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DUPROF_DEBUG"]) ], [ AC_MSG_ERROR([--enable-profile is currently only supported if using GCC]) ]) ]) AM_CONDITIONAL(PROFILE, test "x$enable_profile" != "xno") dnl ============================================================ dnl Enable strict compiler flags dnl ============================================================ # use strict compiler flags only when building from git; the rules for # distcheck will take care of turning this on when making a release m4_define([maintainer_default], [m4_if(cogl_release_status, [git], [yes], [no])]) AC_ARG_ENABLE( [maintainer-flags], [AC_HELP_STRING([--enable-maintainer-flags=@<:@no/yes/error@:>@], [Use strict compiler flags @<:@default=]maintainer_default[@:>@])], [], enable_maintainer_flags=maintainer_default ) MAINTAINER_COMPILER_FLAGS="-Wall -Wcast-align -Wformat -Wformat-security -Werror=uninitialized -Werror=no-strict-aliasing -Werror=empty-body -Werror=init-self -Werror=undef -Werror=declaration-after-statement -Werror=vla -Werror=pointer-arith -Werror=missing-declarations -Werror=maybe-uninitialized" AS_CASE( [$enable_maintainer_flags], [yes], [ AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS]) ], [no], [ ], [error], [ MAINTAINER_COMPILER_FLAGS="$MAINTAINER_COMPILER_FLAGS -Werror" AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS]) ], [*], [AC_MSG_ERROR([Invalid option for --enable-maintainer-flags])] ) # strip leading spaces COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS ${MAINTAINER_CFLAGS#* }" COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -Wno-error=sign-compare" dnl ============================================================ dnl Enable deprecation guards dnl ============================================================ # disable deprecated options from Glib only when building from git; # the rules for distcheck will take care of turning this on when # making a release m4_define([deprecated_default], [m4_if(cogl_release_status, [git], [no], [yes])]) AC_ARG_ENABLE([deprecated], [AS_HELP_STRING([--enable-deprecated=@<:@no/yes@:>@], [Whether deprecated symbols should be disabled when compiling Cogl @<:@default=]deprecated_default[@:>@])], [], [enable_deprecated=deprecated_default]) AS_CASE([$enable_deprecated], [no], [ DEPRECATED_CFLAGS="-DG_DISABLE_DEPRECATED -DG_DISABLE_SINGLE_INCLUDES" ], [yes], [ DEPRECATED_CFLAGS="" ], [AC_MSG_ERROR([Unknown argument for --enable-deprecated])] ) # strip leading spaces COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS ${DEPRECATED_CFLAGS#* }" dnl ================================================================ dnl Check for dependency packages. dnl ================================================================ AM_PATH_GLIB_2_0([glib_req_version], [], [AC_MSG_ERROR([glib-2.0 is required])], [gobject gthread gmodule-no-export]) COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gobject-2.0 gmodule-no-export-2.0" dnl ============================================================ dnl Should cogl-pango be built? dnl ============================================================ AC_ARG_ENABLE( [cogl-pango], [AC_HELP_STRING([--enable-cogl-pango=@<:@no/yes@:>@], [Enable pango support @<:@default=yes@:>@])], [], enable_cogl_pango=yes ) AS_IF([test "x$enable_cogl_pango" = "xyes"], [ COGL_PANGO_PKG_REQUIRES="$COGL_PANGO_PKG_REQUIRES pangocairo >= pangocairo_req_version" ] ) dnl ============================================================ dnl Should cogl-path be built? dnl ============================================================ AC_ARG_ENABLE( [cogl-path], [AC_HELP_STRING([--enable-cogl-path=@<:@no/yes@:>@], [Enable 2D path support @<:@default=yes@:>@])], [], enable_cogl_path=yes ) AS_IF([test "x$enable_cogl_path" = "xyes"], [ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_COGL_PATH_SUPPORT" ] ) dnl ============================================================ dnl Choose image loading backend dnl ============================================================ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gdk-pixbuf-2.0 >= gdk_pixbuf_req_version" COGL_IMAGE_BACKEND="gdk-pixbuf" dnl ============================================================ dnl Determine which drivers and window systems we can support dnl ============================================================ dnl ======================================================== dnl Drivers first... dnl ======================================================== EGL_CHECKED=no enabled_drivers="" HAVE_GLES1=0 AC_ARG_ENABLE( [gles1], [AC_HELP_STRING([--enable-gles1=@<:@no/yes@:>@], [Enable support for OpenGL-ES 1.1 @<:@default=no@:>@])], [], enable_gles1=no ) AS_IF([test "x$enable_gles1" = "xyes"], [ enabled_drivers="$enabled_drivers gles1" cogl_gl_headers="GLES/gl.h GLES/glext.h" AC_DEFINE([HAVE_COGL_GLES], 1, [Have GLES 1.1 for rendering]) COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES CLUTTER_COGL_HAS_GLES" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES1" HAVE_GLES1=1 PKG_CHECK_EXISTS([glesv1_cm], [COGL_PKG_REQUIRES_GL="$COGL_PKG_REQUIRES_GL glesv1_cm" COGL_GLES1_LIBNAME="libGLESv1_CM.so" ], [ # We have to check the two headers independently as GLES/glext.h # needs to include GLES/gl.h to have the GL types defined (eg. # GLenum). AC_CHECK_HEADER([GLES/gl.h], [], [AC_MSG_ERROR([Unable to locate GLES/gl.h])]) AC_CHECK_HEADER([GLES/glext.h], [], [AC_MSG_ERROR([Unable to locate GLES/glext.h])], [#include ]) # Early implementations provided only a GLES/egl.h while Khronos's # implementer guide now states EGL/egl.h is the One. Some # implementations keep a GLES/egl.h wrapper around EGL/egl.h for # backward compatibility while others provide EGL/egl.h only. AC_CHECK_HEADERS([GLES/egl.h EGL/egl.h]) AS_IF([test "x$ac_cv_header_GLES_egl_h" = "xyes"], [COGL_EGL_INCLUDES="#include "], [test "x$ac_cv_header_EGL_egl_h" = "xyes"], [ COGL_EGL_INCLUDES="#include " ], [AC_MSG_ERROR([Unable to locate EGL header])]) AC_SUBST([COGL_EGL_INCLUDES]) AC_CHECK_HEADERS([EGL/eglext.h], [COGL_EGL_INCLUDES="$COGL_EGL_INCLUDE #include "], [], [$COGL_EGL_INCLUDES]) # Check for a GLES 1.x Common Profile library with/without EGL. # # Note: historically GLES 1 libraries shipped with the # EGL and GLES symbols all bundled in one library. Now # the Khronos Implementers Guide defines two naming # schemes: -lGLES_CM should be used for a library that # bundles the GLES and EGL API together and -lGLESv1_CM # would be used for a standalone GLES API. AC_CHECK_LIB(GLES_CM, [eglInitialize], [COGL_GLES1_LIBNAME="libGLES_CM.so"], [ AC_CHECK_LIB(GLESv1_CM, [glFlush], [COGL_GLES1_LIBNAME="libGLESv1_CM.so" NEED_SEPARATE_EGL=yes ], [AC_MSG_ERROR([Unable to locate required GLES 1.x Common Profile library])]) ]) EGL_CHECKED=yes ]) ]) HAVE_GLES2=0 AC_ARG_ENABLE( [gles2], [AC_HELP_STRING([--enable-gles2=@<:@no/yes@:>@], [Enable support for OpenGL-ES 2.0 @<:@default=no@:>@])], [], enable_gles2=no ) AS_IF([test "x$enable_gles2" = "xyes"], [ enabled_drivers="$enabled_drivers gles2" cogl_gl_headers="GLES2/gl2.h GLES2/gl2ext.h" AC_DEFINE([HAVE_COGL_GLES2], 1, [Have GLES 2.0 for rendering]) COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES CLUTTER_COGL_HAS_GLES" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES2" HAVE_GLES2=1 PKG_CHECK_EXISTS([glesv2], [COGL_PKG_REQUIRES_GL="$COGL_PKG_REQUIRES_GL glesv2" COGL_GLES2_LIBNAME="libGLESv2.so" ], [ # We have to check the two headers independently as GLES2/gl2ext.h # needs to include GLES2/gl2.h to have the GL types defined (eg. # GLenum). AC_CHECK_HEADER([GLES2/gl2.h], [], [AC_MSG_ERROR([Unable to locate GLES2/gl2.h])]) AC_CHECK_HEADER([GLES2/gl2ext.h], [], [AC_MSG_ERROR([Unable to locate GLES2/gl2ext.h])], [#include ]) COGL_GLES2_LIBNAME="libGLESv2.so" ]) ]) HAVE_GL=0 AC_ARG_ENABLE( [gl], [AC_HELP_STRING([--enable-gl=@<:@no/yes@:>@], [Enable support for OpenGL @<:@default=yes@:>@])], [], [enable_gl=yes] ) AS_IF([test "x$enable_gl" = "xyes"], [ enabled_drivers="$enabled_drivers gl" PKG_CHECK_EXISTS([x11], [ALLOW_GLX=yes]) cogl_gl_headers="GL/gl.h" PKG_CHECK_EXISTS([gl], dnl We don't want to use COGL_PKG_REQUIRES here because we don't want to dnl directly link against libGL [COGL_PKG_REQUIRES_GL="$COGL_PKG_REQUIRES_GL gl"], [AC_CHECK_LIB(GL, [glGetString], , [AC_MSG_ERROR([Unable to locate required GL library])]) ]) COGL_GL_LIBNAME="libGL.so.1" AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering]) COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GL" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS CLUTTER_COGL_HAS_GL" HAVE_GL=1 ]) AM_CONDITIONAL([COGL_DRIVER_GL_SUPPORTED], [test "x$enable_gl" = "xyes"]) AM_CONDITIONAL([COGL_DRIVER_GLES_SUPPORTED], [test "x$enable_gles1" = "xyes" || test "x$enable_gles2" = "xyes"]) dnl Allow the GL library names and default driver to be overridden with configure options AC_ARG_WITH([gl-libname], [AS_HELP_STRING([--with-gl-libname], override the name of the GL library to dlopen)], [COGL_GL_LIBNAME="$withval"]) AC_ARG_WITH([gles1-libname], [AS_HELP_STRING([--with-gles1-libname], override the name of the GLESv1 library to dlopen)], [COGL_GLES1_LIBNAME="$withval"]) AC_ARG_WITH([gles2-libname], [AS_HELP_STRING([--with-gles2-libname], override the name of the GLESv2 library to dlopen)], [COGL_GLES2_LIBNAME="$withval"]) AC_ARG_WITH([default-driver], [AS_HELP_STRING([--with-default-driver], specify a default cogl driver)], [COGL_DEFAULT_DRIVER="${withval}"], [COGL_DEFAULT_DRIVER="" ]) AM_CONDITIONAL(HAVE_COGL_DEFAULT_DRIVER, [ test "x$COGL_DEFAULT_DRIVER" != "x" ]) AC_SUBST([COGL_GL_LIBNAME]) AC_SUBST([HAVE_GL]) AC_SUBST([COGL_GLES1_LIBNAME]) AC_SUBST([HAVE_GLES1]) AC_SUBST([COGL_GLES2_LIBNAME]) AC_SUBST([HAVE_GLES2]) AC_SUBST([COGL_DEFAULT_DRIVER]) AC_ARG_ENABLE( [cogl-gles2], [AC_HELP_STRING([--enable-cogl-gles2=@<:@no/yes@:>@], [Enable libcogl-gles2 frontend api for OpenGL-ES 2.0 @<:@default=auto@:>@])], [], [ AS_IF([test "x$HAVE_GLES2" = "x1"], [enable_cogl_gles2=yes], [enable_cogl_gles2=no]) ] ) AS_IF([test "x$enable_cogl_gles2" = "xyes"], [ AS_IF([test "x$HAVE_GLES2" != "x1"], [ AC_MSG_ERROR([libcogl-gles2 is currently only supported on systems with a native GLES 2.0 library]) ]) ]) AM_CONDITIONAL([BUILD_COGL_GLES2], [test "x$enable_cogl_gles2" = "xyes"]) dnl ======================================================== dnl Check window system integration libraries... dnl ======================================================== AC_ARG_ENABLE( [glx], [AC_HELP_STRING([--enable-glx=@<:@no/yes@:>@], [Enable support GLX @<:@default=auto@:>@])], [], [AS_IF([test "x$ALLOW_GLX" = "xyes"], [enable_glx=yes], [enable_glx=no])] ) AS_IF([test "x$enable_glx" = "xyes"], [ AS_IF([test "x$ALLOW_GLX" != "xyes"], [AC_MSG_ERROR([GLX not supported with this configuration])]) NEED_XLIB=yes SUPPORT_GLX=yes GL_WINSYS_APIS="$GL_WINSYS_APIS glx" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLX_SUPPORT" ]) AM_CONDITIONAL(SUPPORT_GLX, [test "x$SUPPORT_GLX" = "xyes"]) EGL_PLATFORM_COUNT=0 AC_ARG_ENABLE( [kms-egl-platform], [AC_HELP_STRING([--enable-kms-egl-platform=@<:@no/yes@:>@], [Enable support for the KMS egl platform @<:@default=no@:>@])], [], enable_kms_egl_platform=no ) AS_IF([test "x$enable_kms_egl_platform" = "xyes"], [ EGL_PLATFORM_COUNT=$((EGL_PLATFORM_COUNT+1)) NEED_EGL=yes EGL_PLATFORMS="$EGL_PLATFORMS kms" PKG_CHECK_EXISTS([gbm], [ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gbm" COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES libdrm" ], [AC_MSG_ERROR([Unable to locate required libgbm library for the KMS egl platform])]) GBM_VERSION=`$PKG_CONFIG --modversion gbm` GBM_MAJOR=`echo $GBM_VERSION | cut -d'.' -f1` GBM_MINOR=`echo $GBM_VERSION | cut -d'.' -f2` GBM_MICRO=`echo $GBM_VERSION | cut -d'.' -f3 | sed 's/-.*//'` AC_DEFINE_UNQUOTED([COGL_GBM_MAJOR], [$GBM_MAJOR], [The major version for libgbm]) AC_DEFINE_UNQUOTED([COGL_GBM_MINOR], [$GBM_MINOR], [The minor version for libgbm]) AC_DEFINE_UNQUOTED([COGL_GBM_MICRO], [$GBM_MICRO], [The micro version for libgbm]) COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_PLATFORM_KMS_SUPPORT" ]) AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_KMS, [test "x$enable_kms_egl_platform" = "xyes"]) AC_ARG_ENABLE( [wayland-egl-server], [AC_HELP_STRING([--enable-wayland-egl-server=@<:@no/yes@:>@], [Enable server side wayland support @<:@default=no@:>@])], [], enable_wayland_egl_server=no ) AS_IF([test "x$enable_wayland_egl_server" = "xyes"], [ NEED_EGL=yes PKG_CHECK_MODULES(WAYLAND_SERVER, [wayland-server >= wayland_server_req_version]) COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES wayland-server >= wayland_server_req_version" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT" ]) AM_CONDITIONAL(SUPPORT_WAYLAND_EGL_SERVER, [test "x$enable_wayland_egl_server" = "xyes"]) dnl This should go last, since it's the default fallback and we need dnl to check the value of $EGL_PLATFORM_COUNT here. AC_ARG_ENABLE( [xlib-egl-platform], [AC_HELP_STRING([--enable-xlib-egl-platform=@<:@no/yes@:>@], [Enable support for the Xlib egl platform @<:@default=auto@:>@])], [], enable_xlib_egl_platform=yes ) AS_IF([test "x$enable_xlib_egl_platform" = "xyes"], [ EGL_PLATFORM_COUNT=$((EGL_PLATFORM_COUNT+1)) NEED_EGL=yes NEED_XLIB=yes EGL_PLATFORMS="$EGL_PLATFORMS xlib" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT" ]) AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_XLIB, [test "x$enable_xlib_egl_platform" = "xyes"]) AS_IF([test "x$NEED_EGL" = "xyes" && test "x$EGL_CHECKED" != "xyes"], [ PKG_CHECK_EXISTS([egl], [COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES egl"], [ AC_CHECK_HEADERS( [EGL/egl.h], [], [AC_MSG_ERROR([Unable to locate required EGL headers])]) AC_CHECK_HEADERS( [EGL/eglext.h], [], [AC_MSG_ERROR([Unable to locate required EGL headers])], [#include ]) AC_CHECK_LIB(EGL, [eglInitialize], [COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -lEGL"], [AC_MSG_ERROR([Unable to locate required EGL library])]) COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -lEGL" ] ) COGL_EGL_INCLUDES="#include #include " AC_SUBST([COGL_EGL_INCLUDES]) ]) AS_IF([test "x$NEED_EGL" = "xyes"], [ SUPPORT_EGL=yes GL_WINSYS_APIS="$GL_WINSYS_APIS egl" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_SUPPORT" ]) AM_CONDITIONAL(SUPPORT_EGL, [test "x$SUPPORT_EGL" = "xyes"]) dnl ======================================================== dnl Check X11 dependencies if required dnl ======================================================== AS_IF([test "x$NEED_XLIB" = "xyes"], [ X11_MODULES="x11 xext xfixes >= xfixes_req_version xdamage xcomposite >= xcomposite_req_version xrandr >= xrandr_req_version" PKG_CHECK_MODULES(DUMMY, [$X11_MODULES], [COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES $X11_MODULES"]) SUPPORT_X11=yes SUPPORT_XLIB=yes COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_X11" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_X11_SUPPORT" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_XLIB" COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_XLIB_SUPPORT" ]) AM_CONDITIONAL(X11_TESTS, [test "x$SUPPORT_X11" = "xyes"]) AM_CONDITIONAL(SUPPORT_X11, [test "x$SUPPORT_X11" = "xyes"]) AM_CONDITIONAL(SUPPORT_XLIB, [test "x$SUPPORT_XLIB" = "xyes"]) dnl ================================================================ dnl Documentation stuff. dnl ================================================================ GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" GDKPIXBUF_PREFIX="`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`" AC_SUBST(GLIB_PREFIX) AC_SUBST(GDKPIXBUF_PREFIX) AC_SUBST(COGL_PKG_REQUIRES) if test -n "$COGL_PKG_REQUIRES"; then PKG_CHECK_MODULES(COGL_DEP, [$COGL_PKG_REQUIRES]) if test -n "$COGL_PKG_REQUIRES_GL"; then PKG_CHECK_MODULES(COGL_DEP_GL, [$COGL_PKG_REQUIRES_GL]) dnl Strip out the GL libraries from the GL pkg-config files so we can dnl dynamically load them instead gl_libs="" for x in $COGL_DEP_GL_LIBS; do AS_CASE([$x], [-lGL], [], [-lGLESv2], [], [-lGLESv1_CM], [], [*], [gl_libs="$gl_libs $x"]) done COGL_DEP_CFLAGS="$COGL_DEP_CFLAGS $COGL_DEP_CFLAGS_GL" COGL_DEP_LIBS="$COGL_DEP_LIBS $gl_libs" fi fi AC_SUBST(COGL_PANGO_PKG_REQUIRES) AS_IF([test "x$enable_cogl_pango" = "xyes"], [PKG_CHECK_MODULES(COGL_PANGO_DEP, [$COGL_PANGO_PKG_REQUIRES])] ) AM_CONDITIONAL([BUILD_COGL_PANGO], [test "x$enable_cogl_pango" = "xyes"]) AM_CONDITIONAL([BUILD_COGL_PATH], [test "x$enable_cogl_path" = "xyes"]) dnl ================================================================ dnl Misc program dependencies. dnl ================================================================ AC_PROG_INSTALL dnl ================================================================ dnl GObject-Introspection check dnl ================================================================ GOBJECT_INTROSPECTION_CHECK([gi_req_version]) dnl ================================================================ dnl Checks for header files. dnl ================================================================ AC_PATH_X AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h limits.h unistd.h) AC_CHECK_HEADER([endian.h], [AC_CHECK_DECL([__FLOAT_WORD_ORDER], AC_DEFINE([HAVE_FLOAT_WORD_ORDER], [1], [Has the __FLOAT_WORD_ORDER macro]))]) dnl ================================================================ dnl Checks for library functions. dnl ================================================================ dnl The 'ffs' function is part of C99 so it isn't always dnl available. Cogl has a fallback if needed. AC_CHECK_FUNCS([ffs]) dnl 'memmem' is a GNU extension but we have a simple fallback AC_CHECK_FUNCS([memmem]) dnl This is used in the cogl-gles2-gears example but it is a GNU extension save_libs="$LIBS" LIBS="$LIBS $LIBM" AC_CHECK_FUNCS([sincos]) LIBS="$save_libs" dnl ================================================================ dnl Platform values dnl ================================================================ dnl These are values from system headers that we want to copy into the dnl public Cogl headers without having to include the system header have_poll_h=no AC_CHECK_HEADER(poll.h, [ AC_COMPUTE_INT(COGL_SYSDEF_POLLIN, POLLIN, [#include ], AC_MSG_ERROR([Unable to get value of POLLIN])) AC_COMPUTE_INT(COGL_SYSDEF_POLLPRI, POLLPRI, [#include ], AC_MSG_ERROR([Unable to get value of POLLPRI])) AC_COMPUTE_INT(COGL_SYSDEF_POLLOUT, POLLOUT, [#include ], AC_MSG_ERROR([Unable to get value of POLLOUT])) AC_COMPUTE_INT(COGL_SYSDEF_POLLERR, POLLERR, [#include ], AC_MSG_ERROR([Unable to get value of POLLERR])) AC_COMPUTE_INT(COGL_SYSDEF_POLLHUP, POLLHUP, [#include ], AC_MSG_ERROR([Unable to get value of POLLHUP])) AC_COMPUTE_INT(COGL_SYSDEF_POLLNVAL, POLLNVAL, [#include ], AC_MSG_ERROR([Unable to get value of POLLNVAL])) COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_POLL_SUPPORT" have_poll_h=yes ]) AS_IF([test "x$have_poll_h" = "xno"], [ COGL_SYSDEF_POLLIN=1 COGL_SYSDEF_POLLPRI=2 COGL_SYSDEF_POLLOUT=4 COGL_SYSDEF_POLLERR=8 COGL_SYSDEF_POLLHUP=16 COGL_SYSDEF_POLLNVAL=32 ]) COGL_DEFINES_EXTRA="$COGL_DEFINES_EXTRA #define COGL_SYSDEF_POLLIN $COGL_SYSDEF_POLLIN #define COGL_SYSDEF_POLLPRI $COGL_SYSDEF_POLLPRI #define COGL_SYSDEF_POLLOUT $COGL_SYSDEF_POLLOUT #define COGL_SYSDEF_POLLERR $COGL_SYSDEF_POLLERR #define COGL_SYSDEF_POLLHUP $COGL_SYSDEF_POLLHUP #define COGL_SYSDEF_POLLNVAL $COGL_SYSDEF_POLLNVAL " dnl ================================================================ dnl What needs to be substituted in other files dnl ================================================================ COGL_DEFINES="$COGL_DEFINES_EXTRA" for x in $COGL_DEFINES_SYMBOLS; do COGL_DEFINES="$COGL_DEFINES #define $x 1" done; AC_SUBST(COGL_DEFINES) AM_SUBST_NOTMAKE(COGL_DEFINES) AS_IF([test "x$cogl_gl_headers" = "x"], [AC_MSG_ERROR([Internal error: no GL header set])]) dnl cogl_gl_headers is a space separate list of headers to dnl include. We'll now convert them to a single variable with a dnl #include line for each header COGL_GL_HEADER_INCLUDES="" for x in $cogl_gl_headers; do COGL_GL_HEADER_INCLUDES="$COGL_GL_HEADER_INCLUDES #include <$x>" done; AC_SUBST(COGL_GL_HEADER_INCLUDES) AM_SUBST_NOTMAKE(COGL_GL_HEADER_INCLUDES) AC_SUBST(COGL_DEP_CFLAGS) AC_SUBST(COGL_DEP_LIBS) AC_SUBST(COGL_PANGO_DEP_CFLAGS) AC_SUBST(COGL_PANGO_DEP_LIBS) AC_SUBST(COGL_GST_DEP_CFLAGS) AC_SUBST(COGL_GST_DEP_LIBS) AC_SUBST(COGL_EXTRA_CFLAGS) AC_SUBST(COGL_EXTRA_LDFLAGS) # just for compatability with the clutter build... MAINTAINER_CFLAGS= AC_SUBST(MAINTAINER_CFLAGS) AC_OUTPUT( Makefile test-fixtures/Makefile cogl/Makefile cogl/muffin-cogl-$MUFFIN_PLUGIN_API_VERSION.pc:cogl/muffin-cogl.pc.in cogl/cogl-defines.h cogl/cogl-gl-header.h cogl/cogl-egl-defines.h cogl-pango/Makefile cogl-pango/muffin-cogl-pango-$MUFFIN_PLUGIN_API_VERSION.pc:cogl-pango/muffin-cogl-pango.pc.in cogl-path/Makefile cogl-path/muffin-cogl-path-$MUFFIN_PLUGIN_API_VERSION.pc:cogl-path/muffin-cogl-path.pc.in cogl-gles2/Makefile cogl-gles2/muffin-cogl-gles2-$MUFFIN_PLUGIN_API_VERSION.pc:cogl-gles2/muffin-cogl-gles2.pc.in tests/Makefile tests/config.env tests/conform/Makefile tests/unit/Makefile tests/micro-perf/Makefile tests/data/Makefile ) dnl ================================================================ dnl Dah Da! dnl ================================================================ echo "" echo "Cogl - $COGL_1_VERSION/$COGL_VERSION (${COGL_RELEASE_STATUS})" # Global flags echo "" echo " • Global:" echo " Prefix: ${prefix}" if test "x$COGL_DEFAULT_DRIVER" != "x"; then echo " Default driver: ${COGL_DEFAULT_DRIVER}" fi echo "" # Features echo " • Features:" echo " Drivers: ${enabled_drivers}" for driver in $enabled_drivers; do driver=`echo $driver | tr "[gles]" "[GLES]"` libname=`eval echo \\$COGL_${driver}_LIBNAME` echo " Library name for $driver: $libname" done echo " GL Window System APIs:${GL_WINSYS_APIS}" if test "x$SUPPORT_EGL" = "xyes"; then echo " EGL Platforms:${EGL_PLATFORMS}" echo " Wayland compositor support: ${enable_wayland_egl_server}" fi echo " Build libcogl-gles2 GLES 2.0 frontend api: ${enable_cogl_gles2}" echo " Image backend: ${COGL_IMAGE_BACKEND}" echo " Cogl Pango: ${enable_cogl_pango}" echo " Cogl Path: ${enable_cogl_path}" # Compiler/Debug related flags echo "" echo " • Build options:" echo " Debugging: ${enable_debug}" echo " Profiling: ${enable_profile}" echo " Enable deprecated symbols: ${enable_deprecated}" echo " Compiler flags: ${CFLAGS} ${COGL_EXTRA_CFLAGS}" echo " Linker flags: ${LDFLAGS} ${COGL_EXTRA_LDFLAGS}" # Miscellaneous echo "" echo " • Extra:" echo " Build introspection data: ${enable_introspection}" echo " Build unit tests: ${enable_unit_tests}" echo "" muffin-5.2.1/cogl/build/0000775000175000017500000000000014211404421015157 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/build/autotools/0000775000175000017500000000000014211404421017210 5ustar jpeisachjpeisachmuffin-5.2.1/cogl/build/autotools/introspection.m40000664000175000017500000000661414211404421022361 0ustar jpeisachjpeisachdnl -*- mode: autoconf -*- dnl Copyright 2009 Johan Dahlin dnl dnl This file is free software; the author(s) gives unlimited dnl permission to copy and/or distribute it, with or without dnl modifications, as long as this notice is preserved. dnl # serial 1 m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], [ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first AC_BEFORE([LT_INIT],[$0])dnl setup libtool first dnl enable/disable introspection m4_if([$2], [require], [dnl enable_introspection=yes ],[dnl AC_ARG_ENABLE(introspection, AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]], [Enable introspection for this build]),, [enable_introspection=auto]) ])dnl AC_MSG_CHECKING([for gobject-introspection]) dnl presence/version checking AS_CASE([$enable_introspection], [no], [dnl found_introspection="no (disabled, use --enable-introspection to enable)" ],dnl [yes],[dnl PKG_CHECK_EXISTS([gobject-introspection-1.0],, AC_MSG_ERROR([gobject-introspection-1.0 is not installed])) PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME])) ],dnl [auto],[dnl PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no) ],dnl [dnl AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@]) ])dnl AC_MSG_RESULT([$found_introspection]) INTROSPECTION_SCANNER= INTROSPECTION_COMPILER= INTROSPECTION_GENERATE= INTROSPECTION_GIRDIR= INTROSPECTION_TYPELIBDIR= if test "x$found_introspection" = "xyes"; then INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection fi AC_SUBST(INTROSPECTION_SCANNER) AC_SUBST(INTROSPECTION_COMPILER) AC_SUBST(INTROSPECTION_GENERATE) AC_SUBST(INTROSPECTION_GIRDIR) AC_SUBST(INTROSPECTION_TYPELIBDIR) AC_SUBST(INTROSPECTION_CFLAGS) AC_SUBST(INTROSPECTION_LIBS) AC_SUBST(INTROSPECTION_MAKEFILE) AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") ]) dnl Usage: dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version]) AC_DEFUN([GOBJECT_INTROSPECTION_CHECK], [ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1]) ]) dnl Usage: dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version]) AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE], [ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require]) ]) muffin-5.2.1/cogl/build/autotools/Makefile.am.enums0000664000175000017500000000301014211404421022364 0ustar jpeisachjpeisach# Rules for generating enumeration types using glib-mkenums # # Define: # glib_enum_h = header template file # glib_enum_c = source template file # glib_enum_headers = list of headers to parse # # before including Makefile.am.enums. You will also need to have # the following targets already defined: # # CLEANFILES # DISTCLEANFILES # BUILT_SOURCES # EXTRA_DIST # # Author: Emmanuele Bassi # Basic sanity checks $(if $(GLIB_MKENUMS),,$(error Need to define GLIB_MKENUMS)) $(if $(or $(glib_enum_h), \ $(glib_enum_c)),, \ $(error Need to define glib_enum_h and glib_enum_c)) $(if $(glib_enum_headers),,$(error Need to define glib_enum_headers)) enum_tmpl_h=$(addprefix $(srcdir)/, $(glib_enum_h:.h=.h.in)) enum_tmpl_c=$(addprefix $(srcdir)/, $(glib_enum_c:.c=.c.in)) enum_headers=$(addprefix $(srcdir)/, $(glib_enum_headers)) CLEANFILES += stamp-enum-types DISTCLEANFILES += $(glib_enum_h) $(glib_enum_c) BUILT_SOURCES += $(glib_enum_h) $(glib_enum_c) EXTRA_DIST += $(enum_tmpl_h) $(enum_tmpl_c) stamp-enum-types: $(enum_headers) $(enum_tmpl_h) $(AM_V_GEN)$(GLIB_MKENUMS) \ --template $(enum_tmpl_h) \ $(enum_headers) > xgen-eh \ && (cmp -s xgen-eh $(glib_enum_h) || cp -f xgen-eh $(glib_enum_h)) \ && rm -f xgen-eh \ && echo timestamp > $(@F) $(glib_enum_h): stamp-enum-types @true $(glib_enum_c): $(enum_headers) $(enum_tmpl_h) $(enum_tmpl_c) $(AM_V_GEN)$(GLIB_MKENUMS) \ --template $(enum_tmpl_c) \ $(enum_headers) > xgen-ec \ && cp -f xgen-ec $(glib_enum_c) \ && rm -f xgen-ec muffin-5.2.1/cogl/build/autotools/as-compiler-flag.m40000664000175000017500000000273714211404421022605 0ustar jpeisachjpeisachdnl as-compiler-flag.m4 0.1.0 dnl autostars m4 macro for detection of compiler flags dnl David Schleef dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $ dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) dnl Tries to compile with the given CFLAGS. dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, dnl and ACTION-IF-NOT-ACCEPTED otherwise. AC_DEFUN([AS_COMPILER_FLAG], [ AC_MSG_CHECKING([to see if compiler understands $1]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then m4_ifvaln([$2],[$2]) true else m4_ifvaln([$3],[$3]) true fi AC_MSG_RESULT([$flag_ok]) ]) dnl AS_COMPILER_FLAGS(VAR, FLAGS) dnl Tries to compile with the given CFLAGS. AC_DEFUN([AS_COMPILER_FLAGS], [ list=$2 flags_supported="" flags_unsupported="" AC_MSG_CHECKING([for supported compiler flags]) for each in $list do save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $each" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then flags_supported="$flags_supported $each" else flags_unsupported="$flags_unsupported $each" fi done AC_MSG_RESULT([$flags_supported]) if test "X$flags_unsupported" != X ; then AC_MSG_WARN([unsupported compiler flags: $flags_unsupported]) fi $1="$$1 $flags_supported" ]) muffin-5.2.1/configure.ac0000664000175000017500000004037614211404421015434 0ustar jpeisachjpeisachAC_PREREQ(2.50) m4_define([muffin_major_version], [5]) m4_define([muffin_minor_version], [2]) m4_define([muffin_micro_version], [1]) m4_define([muffin_version], [muffin_major_version.muffin_minor_version.muffin_micro_version]) m4_define([muffin_plugin_api_version], [0]) AC_INIT([muffin], [muffin_version], [https://github.com/linuxmint/muffin/issues]) m4_ifdef([AX_IS_RELEASE], [AX_IS_RELEASE([always])]) AC_CONFIG_SRCDIR(src/core/display.c) AC_CONFIG_HEADERS(config.h) AC_CONFIG_SUBDIRS([cogl clutter]) AC_CONFIG_MACRO_DIR(m4) AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar subdir-objects]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AM_MAINTAINER_MODE([enable]) AC_GNU_SOURCE MUFFIN_MAJOR_VERSION=muffin_major_version MUFFIN_MINOR_VERSION=muffin_minor_version MUFFIN_MICRO_VERSION=muffin_micro_version MUFFIN_VERSION=muffin_version MUFFIN_PLUGIN_API_VERSION=muffin_plugin_api_version AC_SUBST(MUFFIN_MAJOR_VERSION) AC_SUBST(MUFFIN_MINOR_VERSION) AC_SUBST(MUFFIN_MICRO_VERSION) AC_SUBST(MUFFIN_VERSION) AC_SUBST(MUFFIN_PLUGIN_API_VERSION) # Make the muffin versions visible to the cogl and clutter subdirs export MUFFIN_PLUGIN_API_VERSION MUFFIN_VERSION MUFFIN_PLUGIN_DIR="$libdir/$PACKAGE/plugins" AC_SUBST(MUFFIN_PLUGIN_DIR) # Honor aclocal flags dnl ensure that when the Automake generated makefile calls aclocal, dnl it honours the $ACLOCAL_FLAGS environment variable ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}" if test -n "$ac_macro_dir"; then ACLOCAL_AMFLAGS="-I $ac_macro_dir $ACLOCAL_AMFLAGS" fi AC_SUBST([ACLOCAL_AMFLAGS]) GETTEXT_PACKAGE=muffin AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Name of default gettext domain]) LT_PREREQ([2.2.6]) LT_INIT([disable-static]) # Debian / Ubuntu set this flag to 'no' in libtool, causing linking errors # (i.e when linking against muffin-clutter). Not to explicitly redefine such # deps, we enable this flag for everybody. link_all_deplibs=yes link_all_deplibs_CXX=yes IT_PROG_INTLTOOL([0.34.90]) AC_PROG_CC AM_PROG_CC_C_O AC_ISC_POSIX AC_PROG_INSTALL AC_PROG_SED AC_HEADER_STDC AC_LIBTOOL_WIN32_DLL AM_PROG_LIBTOOL PKG_PROG_PKG_CONFIG([0.21]) # Sets GLIB_GENMARSHAL and GLIB_MKENUMS AM_PATH_GLIB_2_0([2.50.3]) #### Integer sizes AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(void *) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(__int64) ## byte order AC_C_BIGENDIAN #### Usability of visibility attributes gl_VISIBILITY AC_DEFINE(LOCAL_SYMBOL, [], [attribute of the non-exported symbols]) AC_DEFINE(API_EXPORTED, [], [attribute of the symbols exported in the API]) if test $HAVE_VISIBILITY = 1; then AC_DEFINE(LOCAL_SYMBOL, [__attribute__ ((visibility ("hidden")))]) AC_DEFINE(API_EXPORTED, [__attribute__ ((visibility ("default")))]) fi CANBERRA_GTK=libcanberra-gtk3 CANBERRA_GTK_VERSION=0.26 MUFFIN_PC_MODULES=" gtk+-3.0 >= 3.9.12 gio-unix-2.0 >= 2.35.1 glib-2.0 pango >= 1.14.0 cairo >= 1.10.0 json-glib-1.0 cinnamon-desktop >= 2.4.0 xcomposite >= 0.3 xcursor xdamage xext xfixes xi >= 1.6.0 xkbfile xkeyboard-config xkbcommon >= 0.4.3 xkbcommon-x11 xrender x11-xcb xcb-randr xcb-res gl egl " GLIB_GSETTINGS AC_ARG_ENABLE(verbose-mode, AC_HELP_STRING([--disable-verbose-mode], [disable muffin's ability to do verbose logging, for embedded/size-sensitive custom builds]),, enable_verbose_mode=yes) dnl ' if test x$enable_verbose_mode = xyes; then AC_DEFINE(WITH_VERBOSE_MODE,1,[Build with verbose mode support]) fi AC_ARG_ENABLE([gtk-doc], AC_HELP_STRING([--enable-gtk-doc], [use gtk-doc to build documentation [[default=yes]]]),, enable_gtk_doc=yes) # prefixes for fixing gtk-doc references CAIRO_PREFIX="`$PKG_CONFIG --variable=prefix cairo`" GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" PANGO_PREFIX="/usr" ATK_PREFIX="`$PKG_CONFIG --variable=prefix atk`" GDKPIXBUF_PREFIX="`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`" AC_SUBST(CAIRO_PREFIX) AC_SUBST(GLIB_PREFIX) AC_SUBST(PANGO_PREFIX) AC_SUBST(ATK_PREFIX) AC_SUBST(GDKPIXBUF_PREFIX) AC_ARG_ENABLE(sm, AC_HELP_STRING([--disable-sm], [disable muffin's session management support, for embedded/size-sensitive custom non-GNOME builds]),, enable_sm=auto) dnl ' AC_ARG_ENABLE(startup-notification, AC_HELP_STRING([--disable-startup-notification], [disable muffin's startup notification support, for embedded/size-sensitive custom non-GNOME builds]),, enable_startup_notification=auto) dnl ' AC_ARG_WITH(libcanberra, AC_HELP_STRING([--without-libcanberra], [disable the use of libcanberra for playing sounds]),, with_libcanberra=auto) AC_ARG_ENABLE(xsync, AC_HELP_STRING([--disable-xsync], [disable muffin's use of the XSync extension]),, enable_xsync=auto) dnl ' AC_ARG_ENABLE(shape, AC_HELP_STRING([--disable-shape], [disable muffin's use of the shaped window extension]),, enable_shape=auto) dnl ' ## try definining HAVE_BACKTRACE AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)]) AM_GLIB_GNU_GETTEXT ## here we get the flags we'll actually use PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.37.3) PKG_CHECK_MODULES(MUFFIN_MESSAGE, gtk+-3.0) PKG_CHECK_MODULES(MUFFIN_WINDOW_DEMO, gtk+-3.0) # Unconditionally use this dir to avoid a circular dep with gnomecc GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings" AC_SUBST(GNOME_KEYBINDINGS_KEYSDIR) STARTUP_NOTIFICATION_VERSION=0.7 AC_MSG_CHECKING([Startup notification library >= $STARTUP_NOTIFICATION_VERSION]) if $PKG_CONFIG --atleast-version $STARTUP_NOTIFICATION_VERSION libstartup-notification-1.0; then have_startup_notification=yes else have_startup_notification=no fi AC_MSG_RESULT($have_startup_notification) if test x$enable_startup_notification = xyes; then have_startup_notification=yes echo "startup-notification support forced on" elif test x$enable_startup_notification = xauto; then true else have_startup_notification=no fi if test x$have_startup_notification = xyes; then echo "Building with libstartup-notification" MUFFIN_PC_MODULES="$MUFFIN_PC_MODULES libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_VERSION" AC_DEFINE(HAVE_STARTUP_NOTIFICATION, , [Building with startup notification support]) 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) MUFFIN_PC_MODULES="$MUFFIN_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 INTROSPECTION_VERSION=0.9.2 GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_VERSION]) if test x$found_introspection != xno; then AC_DEFINE(HAVE_INTROSPECTION, 1, [Define if GObject introspection is available]) MUFFIN_PC_MODULES="$MUFFIN_PC_MODULES gobject-introspection-1.0" # Since we don't make any guarantees about stability and we don't support # parallel install, there's no real reason to change directories, filenames, # etc. as we change the Muffin tarball version. Note that this must match # api_version in src/Makefile.am # This is set to a magic number which is different from the API which # Mutter uses. Otherwise there will be dependency conflicts in RPM # based distributions that automatically resolve typelib file dependencies. META_GIR=Meta_Muffin_0_gir # META_GIR=[Meta_]muffin_major_version[_]muffin_minor_version[_gir] AC_SUBST(META_GIR) fi AC_MSG_CHECKING([Xcursor]) if $PKG_CONFIG xcursor; then have_xcursor=yes else have_xcursor=no fi AC_MSG_RESULT($have_xcursor) if test x$have_xcursor = xyes; then echo "Building with Xcursor" MUFFIN_PC_MODULES="$MUFFIN_PC_MODULES xcursor" AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support]) fi PKG_CHECK_MODULES(MUFFIN, $MUFFIN_PC_MODULES) AC_PATH_XTRA ALL_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" # Check for Xinerama extension (Solaris impl or Xfree impl) muffin_save_cppflags="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $X_CFLAGS" AC_ARG_ENABLE(xinerama, AC_HELP_STRING([--disable-xinerama], [disable muffin's use of the Xinerama extension]), try_xinerama=$enable_xinerama,try_xinerama=yes) dnl ' use_solaris_xinerama=no use_xfree_xinerama=no if test "${try_xinerama}" != no; then case "$host" in *-*-solaris*) # Check for solaris use_solaris_xinerama=yes AC_CHECK_LIB(Xext, XineramaGetInfo, use_solaris_xinerama=yes, use_solaris_xinerama=no, $ALL_X_LIBS) if test "x$use_solaris_xinerama" = "xyes"; then AC_CHECK_HEADER(X11/extensions/xinerama.h, if test -z "`echo $ALL_X_LIBS | grep "\-lXext" 2> /dev/null`"; then X_EXTRA_LIBS="-lXext $X_EXTRA_LIBS" fi AC_DEFINE(HAVE_SOLARIS_XINERAMA, , [Have Solaris-style Xinerama]) AC_DEFINE(HAVE_XINERAMA, , [Have some version of Xinerama]), use_solaris_xinerama=no, [#include ]) fi AC_MSG_CHECKING(for Xinerama support on Solaris) AC_MSG_RESULT($use_solaris_xinerama); ;; *) # Check for XFree use_xfree_xinerama=yes AC_CHECK_LIB(Xinerama, XineramaQueryExtension, [AC_CHECK_HEADER(X11/extensions/Xinerama.h, X_EXTRA_LIBS="-lXinerama $X_EXTRA_LIBS" if test -z "`echo $ALL_X_LIBS | grep "\-lXext" 2> /dev/null`"; then X_EXTRA_LIBS="-lXext $X_EXTRA_LIBS" fi AC_DEFINE(HAVE_XFREE_XINERAMA, , [Have XFree86-style Xinerama]) AC_DEFINE(HAVE_XINERAMA,, [Have some version of Xinerama]), use_xfree_xinerama=no, [#include ])], use_xfree_xinerama=no, -lXext $ALL_X_LIBS) AC_MSG_CHECKING(for Xinerama support on XFree86) AC_MSG_RESULT($use_xfree_xinerama); ;; esac fi CPPFLAGS="$muffin_save_cppflags" SHAPE_LIBS= found_shape=no AC_CHECK_LIB(Xext, XShapeQueryExtension, [AC_CHECK_HEADER(X11/extensions/shape.h, SHAPE_LIBS=-lXext found_shape=yes)], , $ALL_X_LIBS) if test x$enable_shape = xno; then found_shape=no fi if test x$enable_shape = xyes; then if test "$found_shape" = "no"; then AC_MSG_ERROR([--enable-shape forced and Shape not found]) exit 1 fi fi if test "x$found_shape" = "xyes"; then AC_DEFINE(HAVE_SHAPE, , [Have the shape extension library]) fi found_xkb=no AC_CHECK_LIB(X11, XkbQueryExtension, [AC_CHECK_HEADER(X11/XKBlib.h, found_xkb=yes)], , $ALL_X_LIBS) if test "x$found_xkb" = "xyes"; then AC_DEFINE(HAVE_XKB, , [Have keyboard extension library]) fi RANDR_LIBS= found_randr=no AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration, [AC_CHECK_HEADER(X11/extensions/Xrandr.h, RANDR_LIBS=-lXrandr found_randr=yes,, [#include ])], , -lXrender -lXext $ALL_X_LIBS) if test "x$found_randr" = "xyes"; then AC_DEFINE(HAVE_RANDR, , [Have the Xrandr extension library]) fi XSYNC_LIBS= found_xsync=no AC_CHECK_LIB(Xext, XSyncQueryExtension, [AC_CHECK_HEADER(X11/extensions/sync.h, found_xsync=yes,, [#include ])], , $ALL_X_LIBS) if test x$enable_xsync = xno; then found_xsync=no fi if test x$enable_xsync = xyes; then if test "$found_xsync" = "no"; then AC_MSG_ERROR([--enable-xsync forced and XSync not found]) exit 1 fi fi if test "x$found_xsync" = "xyes"; then XSYNC_LIBS=-lXext AC_DEFINE(HAVE_XSYNC, , [Have the Xsync extension library]) fi MUFFIN_LIBS="$MUFFIN_LIBS $XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm" MUFFIN_MESSAGE_LIBS="$MUFFIN_MESSAGE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" MUFFIN_WINDOW_DEMO_LIBS="$MUFFIN_WINDOW_DEMO_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm" MUFFIN_PROPS_LIBS="$MUFFIN_PROPS_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" found_sm=no case "$MUFFIN_LIBS" in *-lSM*) found_sm=yes ;; *) AC_CHECK_LIB(SM, SmcSaveYourselfDone, [AC_CHECK_HEADERS(X11/SM/SMlib.h, MUFFIN_LIBS="-lSM -lICE $MUFFIN_LIBS" found_sm=yes)], , $MUFFIN_LIBS) ;; esac if test x$enable_sm = xno; then found_sm=no fi if test x$enable_sm = xyes; then if test "$found_sm" = "no"; then AC_MSG_ERROR([--enable-sm forced and -lSM not found]) exit 1 fi fi if test "$found_sm" = "yes"; then AC_DEFINE(HAVE_SM, , [Building with SM support]) fi AM_CONDITIONAL(HAVE_SM, test "$found_sm" = "yes") HOST_ALIAS=$host_alias AC_SUBST(HOST_ALIAS) AC_PATH_PROG(GDK_PIXBUF_CSOURCE, gdk-pixbuf-csource, no) if test x"$GDK_PIXBUF_CSOURCE" = xno; then AC_MSG_ERROR([gdk-pixbuf-csource executable not found in your path - should be installed with GTK]) fi AC_SUBST(GDK_PIXBUF_CSOURCE) AC_PATH_PROG(ZENITY, zenity, no) if test x"$ZENITY" = xno; then AC_MSG_ERROR([zenity not found in your path - needed for dialogs]) fi AC_ARG_ENABLE(debug, [ --enable-debug enable debugging],, enable_debug=no) if test "x$enable_debug" = "xyes"; then CFLAGS="$CFLAGS -g -O" fi GTK_DOC_CHECK([1.15], [--flavour no-tmpl]) AC_CHECK_DECL([GL_EXT_x11_sync_object], [], [AC_MSG_ERROR([GL_EXT_x11_sync_object definition not found, please update your GL headers])], [#include ]) m4_ifdef([AX_COMPILER_FLAGS], [AX_COMPILER_FLAGS([WARN_CFLAGS],[WARN_LDFLAGS])]) AC_ARG_ENABLE(clutter-doc, [ --disable-clutter-doc disable Clutter docs generation],, clutter_doc=yes) AM_CONDITIONAL(CLUTTER_DOC, test "$clutter_doc" = "yes") AC_CONFIG_FILES([ Makefile data/Makefile doc/Makefile doc/man/Makefile doc/reference/Makefile doc/reference/muffin/Makefile doc/reference/muffin/muffin-docs.sgml doc/reference/clutter/Makefile doc/reference/clutter/clutter-docs.xml doc/reference/cogl/Makefile doc/reference/cogl/cogl-docs.xml src/Makefile src/wm-tester/Makefile src/libmuffin.pc src/muffin-plugins.pc src/tools/Makefile src/compositor/plugins/Makefile po/Makefile.in ]) AC_OUTPUT COGL_PC_VERSION=$(grep Version: cogl/cogl/muffin-cogl-$MUFFIN_PLUGIN_API_VERSION.pc|awk '{ print $2; }') AS_IF([test "x$COGL_PC_VERSION" != "x$MUFFIN_VERSION"], [AC_MSG_ERROR([muffin-cogl pkg-config file not updated, rerun ./configure])]) CLUTTER_PC_VERSION=$(grep Version: clutter/clutter/muffin-clutter-$MUFFIN_PLUGIN_API_VERSION.pc|awk '{ print $2; }') AS_IF([test "x$CLUTTER_PC_VERSION" != "x$MUFFIN_VERSION"], [AC_MSG_ERROR([muffin-clutter pkg-config file not updated, rerun ./configure])]) if test x$enable_verbose_mode = xno; then echo "*** WARNING WARNING WARNING WARNING WARNING" echo "*** Building without verbose mode" echo "*** This means there's no way to debug muffin problems." echo "*** Please build normal desktop versions of muffin" echo "*** with verbose mode enabled so users can use it when they report bugs." fi dnl ========================================================================== echo " muffin-$VERSION prefix: ${prefix} source code location: ${srcdir} compiler: ${CC} XFree86 Xinerama: ${use_xfree_xinerama} Solaris Xinerama: ${use_solaris_xinerama} Startup notification: ${have_startup_notification} libcanberra: ${have_libcanberra} Introspection: ${found_introspection} Session management: ${found_sm} Shape extension: ${found_shape} Xsync: ${found_xsync} Xcursor: ${have_xcursor} " muffin-5.2.1/.circleci/0000775000175000017500000000000014211404421014767 5ustar jpeisachjpeisachmuffin-5.2.1/.circleci/config.yml0000664000175000017500000000364214211404421016764 0ustar jpeisachjpeisachversion: 2.0 shared: &shared steps: - checkout - run: name: Prepare environment command: apt-get update - run: name: Install dependencies command: | wget https://github.com/linuxmint/cinnamon-desktop/releases/download/master.${CIRCLE_JOB}/packages.tar.gz -O cinnamon-desktop.tar.gz ls *.tar.gz | xargs -i tar zxvf {} apt install --yes --allow-downgrades ./packages/*.deb rm -rf packages - run: name: Build project command: mint-build -i - run: name: Prepare packages command: | if [ -z $CI_PULL_REQUEST ]; then mkdir /packages mv /root/*.deb /packages/ git log > /packages/git.log cd / tar zcvf packages.tar.gz packages fi - run: name: Deploy packages to Github command: | if [ -z $CI_PULL_REQUEST ]; then wget https://github.com/tcnksm/ghr/releases/download/v0.5.4/ghr_v0.5.4_linux_amd64.zip apt-get install --yes unzip unzip ghr_v0.5.4_linux_amd64.zip TAG="master".$CIRCLE_JOB ./ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME -replace $TAG /packages.tar.gz ./ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME -recreate -b "Latest unstable packages" $TAG /packages.tar.gz fi jobs: "mint20": <<: *shared docker: - image: linuxmintd/mint20-amd64 "lmde4": <<: *shared docker: - image: linuxmintd/lmde4-amd64 workflows: version: 2 build: jobs: - "mint20" - "lmde4" muffin-5.2.1/README-Mutter0000664000175000017500000004123314211404421015275 0ustar jpeisachjpeisachMetacity is not a meta-City as in an urban center, but rather Meta-ness as in the state of being meta. i.e. metacity : meta as opacity : opaque. Also it may have something to do with the Meta key on UNIX keyboards. The first release of Metacity was version 2.3. Metacity has no need for your petty hangups about version numbers. The stable releases so far are 2.4.x, 2.6.x, 2.8.[01], 2.8.1.x, 2.8.5-, 2.10.x, 2.12.x, 2.14.x, 2.16.x. Unstable branches are 2.3.x, 2.5.x, 2.8.2-4, 2.9.x, 2.11.x, 2.13.x, 2.15.x, 2.17.x. COMPILING MUFFIN === You need GTK+ 2.2. For startup notification to work you need libstartup-notification at http://www.freedesktop.org/software/startup-notification/ or on the GNOME ftp site. You need Clutter 1.0. You need gobject-introspection 0.6.3. REPORTING BUGS AND SUBMITTING PATCHES === Report new bugs on http://bugzilla.gnome.org. Please check for duplicates, *especially* if you are reporting a feature request. Please do *not* add "me too!" or "yes I really want this!" comments to feature requests in bugzilla. Please read http://pobox.com/~hp/features.html prior to adding any kind of flame about missing features or misfeatures. Feel free to send patches too; Metacity is relatively small and simple, so if you find a bug or want to add a feature it should be pretty easy. Send me mail, or put the patch in bugzilla. See the HACKING file for some notes on hacking Muffin. MUFFIN FEATURES === - Uses GTK+ 2.0 for drawing window frames. This means colors, fonts, etc. come from GTK+ theme. - Does not expose the concept of "window manager" to the user. Some of the features in the GNOME control panel and other parts of the desktop happen to be implemented in metacity, such as changing your window border theme, or changing your window navigation shortcuts, but the user doesn't need to know this. - Includes only the window manager; does not try to be a desktop environment. The pager, configuration, etc. are all separate and modular. The "libwnck" library (which I also wrote) is available for writing metacity extensions, pagers, and so on. (But libwnck isn't metacity specific, or GNOME-dependent; it requires only GTK, and should work with KWin, fvwm2, and other EWMH-compliant WMs.) - Has a simple theme system and a couple of extra themes come with it. Change themes via gsettings: gsettings set org.cinnamon.desktop.wm.preferences theme Crux gsettings set org.cinnamon.desktop.wm.preferences theme Gorilla gsettings set org.cinnamon.desktop.wm.preferences theme Atlanta gsettings set org.cinnamon.desktop.wm.preferences theme Bright See theme-format.txt for docs on the theme format. Use metacity-theme-viewer to preview themes. - Change number of workspaces via gsettings: gsettings set org.cinnamon.desktop.wm.preferences num-workspaces 5 Can also change workspaces from GNOME 2 pager. - Change focus mode: gsettings set org.cinnamon.desktop.wm.preferences focus-mode mouse gsettings set org.cinnamon.desktop.wm.preferences focus-mode sloppy gsettings set org.cinnamon.desktop.wm.preferences focus-mode click - Global keybinding defaults include: Alt-Tab forward cycle window focus Alt-Shift-Tab backward cycle focus Alt-Ctrl-Tab forward cycle focus among panels Alt-Ctrl-Shift-Tab backward cycle focus among panels Alt-Escape cycle window focus without a popup thingy Ctrl-Alt-Left Arrow previous workspace Ctrl-Alt-Right Arrow next workspace Ctrl-Alt-D minimize/unminimize all, to show desktop Change keybindings for example: gsettings set org.cinnamon.desktop.wm.keybindings switch-to-workspace-1 '[F1]' Also try the GNOME keyboard shortcuts control panel. - Window keybindings: Alt-space window menu Mnemonics work in the menu. That is, Alt-space then underlined letter in the menu item works. Choose Move from menu, and arrow keys to move the window. While moving, hold down Control to move slower, and Shift to snap to edges. Choose Resize from menu, and nothing happens yet, but eventually I might implement something. Keybindings for things like maximize window, vertical maximize, etc. can be bound, but may not all exist by default. See metacity.schemas. - Window mouse bindings: Clicking anywhere on frame with button 1 will raise/focus window If you click a window control, such as the close button, then the control will activate on button release if you are still over it on release (as with most GUI toolkits) If you click and drag borders with button 1 it resizes the window If you click and drag the titlebar with button 1 it moves the window. If you click anywhere on the frame with button 2 it lowers the window. If you click anywhere on the frame with button 3 it shows the window menu. If you hold down Super (windows key) and click inside a window, it will move the window (buttons 1 and 2) or show menu (button 3). Or you can configure a different modifier for this. If you pick up a window with button 1 and then switch workspaces the window will come with you to the new workspace, this is a feature copied from Enlightenment. If you hold down Shift while moving a window, the window snaps to edges of other windows and the screen. - Session management: Muffin connects to the session manager and will set itself up to be respawned. It theoretically restores sizes/positions/workspace for session-aware applications. - Muffin implements much of the EWMH window manager specification from freedesktop.org, as well as the older ICCCM. Please refer to the COMPLIANCE file for information on muffin compliance with these standards. - Uses Pango to render text, so has cool i18n capabilities. Supports UTF-8 window titles and such. - There are simple animations for actions such as minimization, to help users see what is happening. Should probably have a few more of these and make them nicer. - if you have the proper X setup, set the GDK_USE_XFT=1 environment variable to get antialiased window titles. - considers the panel when placing windows and maximizing them. - handles the window manager selection from the ICCCM. Will exit if another WM claims it, and can claim it from another WM if you pass the --replace argument. So if you're running another ICCCM-compliant WM, you can run "muffin --replace" to replace it with Metacity. - does basic colormap handling - and much more! well, maybe not a lot more. HOW TO ADD EXTERNAL FEATURES === You can write a muffin "plugin" such as a pager, window list, icon box, task menu, or even things like "window matching" using the Extended Window Manager Hints. See http://www.freedesktop.org for the EWMH specification. An easy-to-use library called "libwnck" is available that uses the EWMH and is specifically designed for writing WM accessories. You might be interested in existing accessories such as "Devil's Pie" by Ross Burton, which add features to Muffin (or other EWMH-compliant WMs). MUFFIN BUGS, NON-FEATURES, AND CAVEATS === See bugzilla: http://bugzilla.gnome.org/query.cgi FAQ === Q: Will you add my feature? A: If it makes sense to turn on unconditionally, or is genuinely a harmless preference that I would not be embarrassed to put in a simple, uncluttered, user-friendly configuration dialog. If the only rationale for your feature is that other window managers have it, or that you are personally used to it, or something like that, then I will not be impressed. Metacity is firmly in the "choose good defaults" camp rather than the "offer 6 equally broken ways to do it, and let the user pick one" camp. This is part of a "no crackrock" policy, despite some exceptions I'm mildly embarrassed about. For example, multiple workspaces probably constitute crackrock, they confuse most users and really are not that useful if you have a decent tasklist and so on. But I am too used to them to turn them off. Or alternatively iconification/tasklist is crack, and workspaces/pager are good. But having both is certainly a bit wrong. Sloppy focus is probably crackrock too. But don't think unlimited crack is OK just because I slipped up a little. No slippery slope here. Don't let this discourage patches and fixes - I love those. ;-) Just be prepared to hear the above objections if your patch adds some crack-ridden configuration option. http://pobox.com/~hp/free-software-ui.html http://pobox.com/~hp/features.html Q: Will Muffin be part of GNOME? A: It is not officially part of GNOME as of GNOME 2.27. We are hoping to have muffin officially included as of GNOME 2.28. Q: Why does Muffin remember the workspace/position of some apps but not others across logout/login? A: Muffin only stores sizes/positions for apps that are session managed. As far as I can determine, there is no way to attempt to remember workspace/position for non-session-aware apps without causing a lot of weird effects. The reason is that you don't know which non-SM-aware apps were launched by the session. When you initially log in, Metacity sees a bunch of new windows appear. But it can't distinguish between windows that were stored in your session, or windows you just launched after logging in. If Metacity tried to guess that a window was from the session, it could e.g. end up maximizing a dialog, or put a window you just launched on another desktop or in a weird place. And in fact I see a lot of bugs like this in window managers that try to handle non-session-aware apps. However, for session-aware apps, Muffin can tell that the application instance is from the session and thus restore it reliably, assuming the app properly restores the windows it had open on session save. So the correct way to fix the situation is to make apps session-aware. libSM has come with X for years, it's very standardized, it's shared by GNOME and KDE - even twm is session-aware. So anyone who won't take a patch to add SM is more archaic than twm - and you should flame them. ;-) Docs on session management: http://www.fifi.org/doc/xspecs/xsmp.txt.gz http://www.fifi.org/doc/xspecs/SMlib.txt.gz See also the ICCCM section on SM. For GNOME apps, use the GnomeClient object. For a simple example of using libSM directly, twm/session.c in the twm source code is pretty easy to understand. Q: How about adding viewports in addition to workspaces? A: I could conceivably be convinced to use viewports _instead_ of workspaces, though currently I'm not thinking that. But I don't think it makes any sense to have both; it's just confusing. They are functionally equivalent. You may think this means that you won't have certain keybindings, or something like that. This is a misconception. The only _fundamental_ difference between viewports and workspaces is that with viewports, windows can "overlap" and appear partially on one and partially on another. All other differences that traditionally exist in other window managers are accidental - the features commonly associated with viewports can be implemented for workspaces, and vice versa. So I don't want to have two kinds of workspace/desktop/viewport/whatever, but I'm willing to add features traditionally associated with either kind if those features make sense. Q: Why is the panel always on top? A: Because it's a better user interface, and until we made this not configurable a bunch of apps were not getting fixed (the app authors were just saying "put your panel on the bottom" instead of properly supporting fullscreen mode, and such). rationales.txt has the bugzilla URL for some flamefesting on this, if you want to go back and relive the glory. Read these and the bugzilla stuff before asking/commenting: http://pobox.com/~hp/free-software-ui.html http://pobox.com/~hp/features.html Q: Why is there no edge flipping? A: This one is also in rationales.txt. Because "ouija board" UI, where you just move the mouse around and the computer guesses what you mean, has a lot of issues. This includes mouse focus, shade-hover mode, edge flipping, autoraise, etc. Metacity has mouse focus and autoraise as a compromise, but these features are all confusing for many users, and cause problems with accessibility, fitt's law, and so on. Read these and the bugzilla stuff before asking/commenting: http://pobox.com/~hp/free-software-ui.html http://pobox.com/~hp/features.html Q: Why does wireframe move/resize suck? A: You can turn it on with the reduced_resources setting. But: it has low usability, and is a pain to implement, and there's no reason opaque move/resize should be a problem on any setup that can run a modern desktop worth a darn to begin with. Read these and the bugzilla stuff before asking/commenting: http://pobox.com/~hp/free-software-ui.html http://pobox.com/~hp/features.html The reason we had to add wireframe anyway was broken proprietary apps that can't handle lots of resize events. Q: Why no XYZ? A: You are probably getting the idea by now - check rationales.txt, query/search bugzilla, and read http://pobox.com/~hp/features.html and http://pobox.com/~hp/free-software-ui.html Then sit down and answer the question for yourself. Is the feature good? What's the rationale for it? Answer "why" not just "why not." Justify in terms of users as a whole, not just users like yourself. How else can you solve the same problem? etc. If that leads you to a strong opinion, then please, post the rationale for discussion to an appropriate bugzilla bug, or to usability@gnome.org. Please don't just "me too!" on bugzilla bugs, please don't think flames will get you anywhere, and please don't repeat rationale that's already been offered. Q: Your dumb web pages you made me read talk about solving problems in fundamental ways instead of adding preferences or workarounds. What are some examples where metacity has done this? A: There are quite a few, though many opportunities remain. Sometimes the real fix involves application changes. The metacity approach is that it's OK to require apps to change, though there are also plenty of workarounds in metacity for battles considered too hard to fight. Here are some examples: - fullscreen mode was introduced to allow position constraints, panel-on-top, and other such things to apply to normal windows while still allowing video players etc. to "just work" - "whether to include minimized windows in Alt+Tab" was solved by putting minimized windows at the *end* of the tab order. - Whether to pop up a feedback display during Alt+Tab was solved by having both Alt+Tab and Alt+Esc - Whether to have a "kill" feature was solved by automatically detecting and offering to kill stuck apps. Better, metacity actually does "kill -9" on the process, it doesn't just disconnect the process from the X server. You'll appreciate this if you ever did a "kill" on Netscape 4, and watched it keep eating 100% CPU even though the X server had booted it. - The workspaces vs. viewports mess was avoided by adding directional navigation and such to workspaces, see discussion earlier in this file. - Instead of configurable placement algorithms, there's just one that works fairly well most of the time. - To avoid excess CPU use during opaque move/resize, we rate limit the updates to the application window's size. - Instead of configurable "show size of window while resizing," it's only shown for windows where it matters, such as terminals. (Only use-case given for all windows is for web designers choosing their web browser size, but there are web sites and desktop backgrounds that do this for you.) - Using startup notification, applications open on the workspace where you launched them, not the active workspace when their window is opened. - and much more. Q: I think muffin sucks. A: Feel free to use any WM you like. The reason metacity follows the ICCCM and EWMH specifications is that it makes metacity a modular, interchangeable part in the desktop. libwnck-based apps such as the GNOME window list will work just fine with any EWMH-compliant WM. Q: Did you spend a lot of time on this? A: Originally the answer was no. Sadly the answer is now yes. Q: How can you claim that you are anti-crack, while still writing a window manager? A: I have no comment on that. muffin-5.2.1/.github/0000775000175000017500000000000014211404421014474 5ustar jpeisachjpeisachmuffin-5.2.1/.github/ISSUE_TEMPLATE.md0000664000175000017500000000045014211404421017200 0ustar jpeisachjpeisach ``` * muffin version (muffin --version or 'dpkg --list | grep libmuffin0' for Mint/Ubuntu) * Distribution - (Mint 17.2, Arch, Fedora 25, etc...) * Graphics hardware *and* driver used * 32 or 64 bit ``` **Issue** **Steps to reproduce** **Expected behaviour** **Other information** muffin-5.2.1/MAINTAINERS0000664000175000017500000000016014211404421014626 0ustar jpeisachjpeisachTomas Frydrych Email: tf linux intel com Userid: tomasf Owen Taylor Email: otaylor redhat com Userid: otaylor muffin-5.2.1/po/0000775000175000017500000000000014211404421013552 5ustar jpeisachjpeisachmuffin-5.2.1/po/uk.po0000664000175000017500000060035314211404421014540 0ustar jpeisachjpeisach# Copyright (C) 2001 Free Software Foundation, Inc. # Yuriy Syrota , 2001, 2002. # Maxim Dziumanenko , 2004-2008 # Korostil Daniel , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: metacity\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-03-18 17:38+0200\n" "PO-Revision-Date: 2012-03-18 17:42+0300\n" "Last-Translator: Korostil Daniel \n" "Language-Team: translation@linux.org.ua\n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" "10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Virtaal 0.7.1\n" #: ../src/50-muffin-windows.xml.in.h:1 msgid "Windows" msgstr "Вікна" #: ../src/50-muffin-windows.xml.in.h:2 msgid "View split on left" msgstr "Перегляд розділити ліворуч" #: ../src/50-muffin-windows.xml.in.h:3 msgid "View split on right" msgstr "Перегляд розділити праворуч" #. This probably means that a non-WM compositor like xcompmgr is running; #. * we have no way to get it to exit #: ../src/compositor/compositor.c:492 #, c-format msgid "" "Another compositing manager is already running on screen %i on display \"%s" "\"." msgstr "Уже запущено інший композитний менеджер на екрані %i через показ «%s»." #: ../src/core/bell.c:307 msgid "Bell event" msgstr "Подія гудка" #: ../src/core/core.c:157 #, c-format msgid "Unknown window information request: %d" msgstr "Запит інформації невідомого вікна: %d" #: ../src/core/delete.c:111 #, c-format msgid "%s is not responding." msgstr "%s не відповідає." #: ../src/core/delete.c:114 msgid "Application is not responding." msgstr "Програма не відповідає." #: ../src/core/delete.c:119 msgid "" "You may choose to wait a short while for it to continue or force the " "application to quit entirely." msgstr "" "Можете трошки зачекати відновлення активності або примусово закрити програму." #: ../src/core/delete.c:126 msgid "_Wait" msgstr "_Зачекати" #: ../src/core/delete.c:126 msgid "_Force Quit" msgstr "_Завершити примусово" #: ../src/core/display.c:387 #, c-format msgid "Missing %s extension required for compositing" msgstr "Нема розширення %s, яке потрібне для композитного режиму" #: ../src/core/display.c:453 #, c-format msgid "Failed to open X Window System display '%s'\n" msgstr "Не вдалось відкрити дисплей віконної системи X «%s»\n" #: ../src/core/keybindings.c:852 #, c-format msgid "" "Some other program is already using the key %s with modifiers %x as a " "binding\n" msgstr "Клавішу «%s» з модифікаторами «%x» вже використовує інша програма\n" #: ../src/core/main.c:206 msgid "Disable connection to session manager" msgstr "Вимкнути з'єднання з менеджером сеансу" #: ../src/core/main.c:212 msgid "Replace the running window manager" msgstr "Замінити запущений віконний менеджер" #: ../src/core/main.c:218 msgid "Specify session management ID" msgstr "Вказати ідентифікатор сеансу" #: ../src/core/main.c:223 msgid "X Display to use" msgstr "Дисплей X" #: ../src/core/main.c:229 msgid "Initialize session from savefile" msgstr "Розпочати сеанс зі збереженого файла" #: ../src/core/main.c:235 msgid "Make X calls synchronous" msgstr "Зробити виклики X синхронними" #: ../src/core/main.c:504 #, c-format msgid "Failed to scan themes directory: %s\n" msgstr "Помилка зчитування каталогу тем: %s\n" #: ../src/core/main.c:520 #, c-format msgid "" "Could not find a theme! Be sure %s exists and contains the usual themes.\n" msgstr "" "Не вдалось знайти тему! Перевірте, чи існує %s та чи містить він звичайну " "тему.\n" #: ../src/core/muffin.c:40 #, c-format msgid "" "muffin %s\n" "Copyright (C) 2001-%d Havoc Pennington, Red Hat, Inc., and others\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A " "PARTICULAR PURPOSE.\n" msgstr "" "Muffin %s\n" "© 2001-%d Havoc Pennington, Red Hat, Inc., та інші\n" "Це — вільне програмний засіб; умови копіювання дивіться в коді програми.\n" "Не надається НІЯКИХ гарантій; навіть ПРИДАТНОСТІ ДЛЯ ПРОДАЖУ чи " "ВІДПОВІДНОСТІ ПЕВНІЙ МЕТІ.\n" #: ../src/core/muffin.c:54 msgid "Print version" msgstr "Показати версію" #: ../src/core/muffin.c:60 msgid "Comma-separated list of compositor plugins" msgstr "Список композитних додатків розділених комою" #: ../src/core/prefs.c:1077 msgid "" "Workarounds for broken applications disabled. Some applications may not " "behave properly.\n" msgstr "" "Обхід для роботи із зіпсованими програмами вимкнено. Деякі додатки можуть " "працювати некоректно.\n" #: ../src/core/prefs.c:1152 #, c-format msgid "Could not parse font description \"%s\" from GSettings key %s\n" msgstr "Неможливо проаналізувати опис шрифту «%s» у ключі GSettings %s\n" #: ../src/core/prefs.c:1218 #, c-format msgid "" "\"%s\" found in configuration database is not a valid value for mouse button " "modifier\n" msgstr "" "У базі даних налаштування знайдено «%s» — що не є правильним значенням " "модифікатора клавіші миші.\n" #: ../src/core/prefs.c:1739 #, c-format msgid "" "\"%s\" found in configuration database is not a valid value for keybinding " "\"%s\"\n" msgstr "" "Знайдене у базі даних налаштування значення «%s» не є правильним записом " "прив'язки клавіш «%s»\n" #: ../src/core/prefs.c:1836 #, c-format msgid "Workspace %d" msgstr "Робочий простір %d" #: ../src/core/screen.c:730 #, c-format msgid "Screen %d on display '%s' is invalid\n" msgstr "Екран %d на дисплеї «%s» не правильний\n" #: ../src/core/screen.c:746 #, c-format msgid "" "Screen %d on display \"%s\" already has a window manager; try using the --" "replace option to replace the current window manager.\n" msgstr "" "Екран %d на дисплеї «%s» вже має менеджера вікон; спробуйте вказати параметр " "--replace, щоб замінити поточний менеджер вікон.\n" #: ../src/core/screen.c:773 #, c-format msgid "" "Could not acquire window manager selection on screen %d display \"%s\"\n" msgstr "" "Не вдалось одержати функцію виділення менеджеру вікон на екрані %d дисплею " "«%s»\n" #: ../src/core/screen.c:828 #, c-format msgid "Screen %d on display \"%s\" already has a window manager\n" msgstr "Екран %d на дисплеї «%s» вже має менеджера вікон\n" #: ../src/core/screen.c:1013 #, c-format msgid "Could not release screen %d on display \"%s\"\n" msgstr "Не вдалось відпустити екран %d на дисплеї «%s»\n" #: ../src/core/session.c:843 ../src/core/session.c:850 #, c-format msgid "Could not create directory '%s': %s\n" msgstr "Не вдалось створити каталог «%s»: %s\n" #: ../src/core/session.c:860 #, c-format msgid "Could not open session file '%s' for writing: %s\n" msgstr "Не вдалось відкрити для запису файл сеансу «%s»: %s\n" #: ../src/core/session.c:1001 #, c-format msgid "Error writing session file '%s': %s\n" msgstr "Помилка запису файла сеансу \"%s\": %s\n" #: ../src/core/session.c:1006 #, c-format msgid "Error closing session file '%s': %s\n" msgstr "Помилка закриття файла сеансу «%s»: %s\n" #: ../src/core/session.c:1136 #, c-format msgid "Failed to parse saved session file: %s\n" msgstr "Збій аналізування збереженого файла сеансу: %s\n" #: ../src/core/session.c:1185 #, c-format msgid " attribute seen but we already have the session ID" msgstr "Прочитано атрибут , але вже є ідентифікатор сеансу" #: ../src/core/session.c:1198 ../src/core/session.c:1273 #: ../src/core/session.c:1305 ../src/core/session.c:1377 #: ../src/core/session.c:1437 #, c-format msgid "Unknown attribute %s on <%s> element" msgstr "Невідомий атрибут %s у елементі <%s>" #: ../src/core/session.c:1215 #, c-format msgid "nested tag" msgstr "вкладена мітка " #: ../src/core/session.c:1457 #, c-format msgid "Unknown element %s" msgstr "Невідомий елемент %s" #: ../src/core/session.c:1809 msgid "" "These windows do not support "save current setup" and will have to " "be restarted manually next time you log in." msgstr "" "Ці вікна не підтримують "збереження поточних параметрів" і при " "наступному входженні їх треба запустити власноруч." #: ../src/core/util.c:111 #, c-format msgid "Failed to open debug log: %s\n" msgstr "Збій відкриття журналу зневадження: %s\n" #: ../src/core/util.c:121 #, c-format msgid "Failed to fdopen() log file %s: %s\n" msgstr "Збій виконання fdopen() для журналу %s: %s\n" #: ../src/core/util.c:127 #, c-format msgid "Opened log file %s\n" msgstr "Відкрито журнал %s\n" #: ../src/core/util.c:146 ../src/tools/muffin-message.c:149 #, c-format msgid "Muffin was compiled without support for verbose mode\n" msgstr "Muffin зібрано без підтримки докладного режиму\n" #: ../src/core/util.c:290 msgid "Window manager: " msgstr "Віконний менеджер:" #: ../src/core/util.c:438 msgid "Bug in window manager: " msgstr "Вада у віконному менеджері:" #: ../src/core/util.c:471 msgid "Window manager warning: " msgstr "Попередження віконного менеджера:" #: ../src/core/util.c:499 msgid "Window manager error: " msgstr "Помилка віконного менеджера:" #. first time through #: ../src/core/window.c:7266 #, c-format msgid "" "Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER " "window as specified in the ICCCM.\n" msgstr "" "Вікно %s встановило значення SM_CLIENT_ID на себе, замість вікна зі " "значенням WM_CLIENT_LEADER, як це вказано в ICCCM.\n" #. We ignore mwm_has_resize_func because WM_NORMAL_HINTS is the #. * authoritative source for that info. Some apps such as mplayer or #. * xine disable resize via MWM but not WM_NORMAL_HINTS, but that #. * leads to e.g. us not fullscreening their windows. Apps that set #. * MWM but not WM_NORMAL_HINTS are basically broken. We complain #. * about these apps but make them work. #. #: ../src/core/window.c:7931 #, c-format msgid "" "Window %s sets an MWM hint indicating it isn't resizable, but sets min size " "%d x %d and max size %d x %d; this doesn't make much sense.\n" msgstr "" "Вікно %s встановило підказку MWM, яка вказує, що його розмір не може " "змінюватись, але встановило мінімальний розмір %d x %d та максимальний %d x " "%d;, в чому не має сенсу.\n" #: ../src/core/window-props.c:309 #, c-format msgid "Application set a bogus _NET_WM_PID %lu\n" msgstr "Програма встановила неправильне значення параметра _NET_WM_PID %lu\n" #: ../src/core/window-props.c:426 #, c-format msgid "%s (on %s)" msgstr "%s (на %s)" #: ../src/core/window-props.c:1481 #, c-format msgid "Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n" msgstr "Неправильний параметр WM_TRANSIENT_FOR вікна 0x%lx вказано для %s.\n" #: ../src/core/window-props.c:1492 #, c-format msgid "WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n" msgstr "Вікно WM_TRANSIENT_FOR 0x%lx для %s створило б петлю.\n" #: ../src/core/xprops.c:155 #, c-format msgid "" "Window 0x%lx has property %s\n" "that was expected to have type %s format %d\n" "and actually has type %s format %d n_items %d.\n" "This is most likely an application bug, not a window manager bug.\n" "The window has title=\"%s\" class=\"%s\" name=\"%s\"\n" msgstr "" "Вікно 0x%lx має властивість %s,\n" "тип якої очікувався %s у форматі %d\n" "але насправді має тип %s формат %d n_items %d.\n" "Найімовірніше, це вада програми, а не менеджера вікон.\n" "Вікно має title=\"%s\" class=\"%s\" name=\"%s\"\n" #: ../src/core/xprops.c:411 #, c-format msgid "Property %s on window 0x%lx contained invalid UTF-8\n" msgstr "Властивість %s вікна 0x%lx містить неправильний UTF-8\n" #: ../src/core/xprops.c:494 #, c-format msgid "" "Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n" msgstr "" "Властивість %s вікна 0x%lx містить неправильний UTF-8 у пункті %d списку\n" #: ../src/muffin.desktop.in.h:1 ../src/muffin-wm.desktop.in.h:1 msgid "Muffin" msgstr "Muffin" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:1 msgid "Modifier to use for extended window management operations" msgstr "" "Модифікатор, що використовується для розширених дій віконного менеджера" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:2 msgid "" "This key will initiate the \"overlay\", which is a combination window " "overview and application launching system. The default is intended to be the " "\"Windows key\" on PC hardware. It's expected that this binding either the " "default or set to the empty string." msgstr "" "Ця клавіша ініціює «накладання», яке є поєднанням огляду вікон і системою " "запуску програм. Типово на це призначено клавішу «Win» в обладнанні. " "Очікується, що це буде прив'язка або типова, або порожній рядок." #: ../src/org.cinnamon.muffin.gschema.xml.in.h:3 msgid "Attach modal dialogs" msgstr "Долучити модальні вікна" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:4 msgid "" "When true, instead of having independent titlebars, modal dialogs appear " "attached to the titlebar of the parent window and are moved together with " "the parent window." msgstr "" "Якщо це позначено, замість незалежних заголовків, модальні вікна буде " "долучено до батьківського вікна заголовка і пересунуто разом з батьківських " "вікном." #: ../src/org.cinnamon.muffin.gschema.xml.in.h:5 msgid "Live Hidden Windows" msgstr "Активувати сховані вікна" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:6 msgid "" "Determines whether hidden windows (i.e., minimized windows and windows on " "other workspaces than the current one) should be kept alive." msgstr "" "Визначає, чи сховані вікна (наприклад, згорнуті вікна та вікна на інших " "робочих просторах) слід утримувати активними." #: ../src/org.cinnamon.muffin.gschema.xml.in.h:7 msgid "Enable edge tiling when dropping windows on screen edges" msgstr "Увімкнути розбиття країв, коли кладуться вікна на краї екрана" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:8 msgid "" "If enabled, dropping windows on vertical screen edges maximizes them " "vertically and resizes them horizontally to cover half of the available " "area. Dropping windows on the top screen edge maximizes them completely." msgstr "" "Якщо ввімкнено, перекидання вікон на вертикальні розгорне їх вертикально й " "змінить їхній розмір горизонтально, щоб покрити половину доступної ділянки. " "Перекидання вікон на верхівку екрана розгорне їх повністю." #: ../src/org.cinnamon.muffin.gschema.xml.in.h:9 msgid "Workspaces are managed dynamically" msgstr "Робочі простори організовуються динамічно" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:10 msgid "" "Determines whether workspaces are managed dynamically or whether there's a " "static number of workspaces (determined by the num-workspaces key in org." "gnome.desktop.wm.preferences)." msgstr "" "Визначає, чи робочі простори керуються динамічно, чи є певна статична " "кількість просторів (визначено ключем num-workspaces у " "org.cinnamon.desktop.wm.preferences)." #: ../src/org.cinnamon.muffin.gschema.xml.in.h:11 msgid "Workspaces only on primary" msgstr "Робочий простір лише на первинному" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:12 msgid "" "Determines whether workspace switching should happen for windows on all " "monitors or only for windows on the primary monitor." msgstr "" "Визначає, чи перемикання робочого простору повинно здійснюватись для вікон " "на всіх моніторах, чи лише для вікон на первинному моніторі." #: ../src/org.cinnamon.muffin.gschema.xml.in.h:13 msgid "No tab popup" msgstr "Без контекстних вкладок" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:14 msgid "" "Determines whether the use of popup and highlight frame should be disabled " "for window cycling." msgstr "" "Визначає, чи слід вимкнути виринання і підкреслювання рамки для повторюваних " "вікон. " #: ../src/org.cinnamon.muffin.gschema.xml.in.h:15 msgid "Draggable border width" msgstr "Перетяжна ширина меж" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:16 msgid "" "The amount of total draggable borders. If the theme's visible borders are " "not enough, invisible borders will be added to meet this value." msgstr "" "Загальний об'єм перетяжних меж. Якщо видимих меж теми не вистачає, буде " "використано це значення з невидимих меж." #: ../src/org.cinnamon.muffin.gschema.xml.in.h:17 msgid "Select window from tab popup" msgstr "Вибрати вікно з контекстних вкладок" #: ../src/org.cinnamon.muffin.gschema.xml.in.h:18 msgid "Cancel tab popup" msgstr "Скасувати контекстні вкладки" #: ../src/tools/muffin-message.c:123 #, c-format msgid "Usage: %s\n" msgstr "Використання: %s\n" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:69 msgid "Mi_nimize" msgstr "З_горнути" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:71 msgid "Ma_ximize" msgstr "_Розгорнути" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:73 msgid "Unma_ximize" msgstr "Відновити п_опередній розмір" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:75 msgid "Roll _Up" msgstr "_Скотити" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:77 msgid "_Unroll" msgstr "Роз_котити" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:79 msgid "_Move" msgstr "Пере_містити" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:81 msgid "_Resize" msgstr "Змінити _розмір" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:83 msgid "Move Titlebar On_screen" msgstr "Перемістити заголовок на _екран" #. separator #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:86 ../src/ui/menu.c:88 msgid "Always on _Top" msgstr "Завжди звер_ху" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:90 msgid "_Always on Visible Workspace" msgstr "Зав_жди на видимому робочому просторі" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:92 msgid "_Only on This Workspace" msgstr "_Лише на цьому робочому просторі" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:94 msgid "Move to Workspace _Left" msgstr "Перемістити у робочий простір _ліворуч" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:96 msgid "Move to Workspace R_ight" msgstr "Перемістити у робочий простір _праворуч" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:98 msgid "Move to Workspace _Up" msgstr "Перемістити у робочий простір з_верху" #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:100 msgid "Move to Workspace _Down" msgstr "Перемістити у робочу область з_низу" #. separator #. Translators: Translate this string the same way as you do in libwnck! #: ../src/ui/menu.c:104 msgid "_Close" msgstr "_Закрити" #: ../src/ui/menu.c:204 #, c-format msgid "Workspace %d%n" msgstr "Робочий простір %d%n" #: ../src/ui/menu.c:214 #, c-format msgid "Workspace 1_0" msgstr "Робочий простір 1_0" #: ../src/ui/menu.c:216 #, c-format msgid "Workspace %s%d" msgstr "Робочий простір %s%d" #: ../src/ui/menu.c:397 msgid "Move to Another _Workspace" msgstr "Перемістити у ін_ший робочий простір" #. This is the text that should appear next to menu accelerators #. * that use the shift key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:77 msgid "Shift" msgstr "Shift" #. This is the text that should appear next to menu accelerators #. * that use the control key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:83 msgid "Ctrl" msgstr "Ctrl" #. This is the text that should appear next to menu accelerators #. * that use the alt key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:89 msgid "Alt" msgstr "Alt" #. This is the text that should appear next to menu accelerators #. * that use the meta key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:95 msgid "Meta" msgstr "Meta" #. This is the text that should appear next to menu accelerators #. * that use the super key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:101 msgid "Super" msgstr "Super" #. This is the text that should appear next to menu accelerators #. * that use the hyper key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:107 msgid "Hyper" msgstr "Hyper" #. This is the text that should appear next to menu accelerators #. * that use the mod2 key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:113 msgid "Mod2" msgstr "Mod2" #. This is the text that should appear next to menu accelerators #. * that use the mod3 key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:119 msgid "Mod3" msgstr "Mod3" #. This is the text that should appear next to menu accelerators #. * that use the mod4 key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:125 msgid "Mod4" msgstr "Mod4" #. This is the text that should appear next to menu accelerators #. * that use the mod5 key. If the text on this key isn't typically #. * translated on keyboards used for your language, don't translate #. * this. #. #: ../src/ui/metaaccellabel.c:131 msgid "Mod5" msgstr "Mod5" #. Translators: This represents the size of a window. The first number is #. * the width of the window and the second is the height. #. #: ../src/ui/resizepopup.c:113 #, c-format msgid "%d x %d" msgstr "%d x %d" #: ../src/ui/theme.c:253 msgid "top" msgstr "top" #: ../src/ui/theme.c:255 msgid "bottom" msgstr "bottom" #: ../src/ui/theme.c:257 msgid "left" msgstr "left" #: ../src/ui/theme.c:259 msgid "right" msgstr "right" #: ../src/ui/theme.c:286 #, c-format msgid "frame geometry does not specify \"%s\" dimension" msgstr "геометрія рамки не визначає розмір «%s»" #: ../src/ui/theme.c:305 #, c-format msgid "frame geometry does not specify dimension \"%s\" for border \"%s\"" msgstr "геометрія рамки не визначає розмір «%s» рамки «%s»" #: ../src/ui/theme.c:342 #, c-format msgid "Button aspect ratio %g is not reasonable" msgstr "Неприпустимий коефіцієнт пропорційності %g" #: ../src/ui/theme.c:354 #, c-format msgid "Frame geometry does not specify size of buttons" msgstr "Геометрія рамки не визначає розміри кнопок" #: ../src/ui/theme.c:1067 #, c-format msgid "Gradients should have at least two colors" msgstr "Градієнти повинні мати принаймні два кольори" #: ../src/ui/theme.c:1219 #, c-format msgid "" "GTK custom color specification must have color name and fallback in " "parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\"" msgstr "" "Специфікації власного кольору GTK повинні мати назву кольору і запас у " "дужках, наприклад, gtk:custom(foo,bar); неможливо розібрати «%s»" #: ../src/ui/theme.c:1235 #, c-format msgid "" "Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-" "_ are valid" msgstr "" "Неправильний символ «%c» у параметрі color_name для gtk:custom, дозволено " "тільки A-Za-z0-9-_" #: ../src/ui/theme.c:1249 #, c-format msgid "" "Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not " "fit the format" msgstr "" "Формат Gtk:custom — «gtk:custom(color_name,fallback)», «%s» не відповідає " "формату" #: ../src/ui/theme.c:1294 #, c-format msgid "" "GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] " "where NORMAL is the state; could not parse \"%s\"" msgstr "" "При визначенні кольору GTK потрібно вказувати режим у прямокутних дужках, " "наприклад, gtk:fg[NORMAL], де NORMAL — режим; неможливо розібрати «%s»" #: ../src/ui/theme.c:1308 #, c-format msgid "" "GTK color specification must have a close bracket after the state, e.g. gtk:" "fg[NORMAL] where NORMAL is the state; could not parse \"%s\"" msgstr "" "При визначенні кольору GTK після вказування режиму повинна бути завершальна " "прямокутна дужка, наприклад, gtk:fg[NORMAL], де NORMAL — режим; неможливо " "розібрати «%s»" #: ../src/ui/theme.c:1319 #, c-format msgid "Did not understand state \"%s\" in color specification" msgstr "Неможливо розпізнати режим «%s» у визначенні кольору" #: ../src/ui/theme.c:1332 #, c-format msgid "Did not understand color component \"%s\" in color specification" msgstr "Неможливо розпізнати компонент кольору «%s» у визначенні кольору" #: ../src/ui/theme.c:1361 #, c-format msgid "" "Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the " "format" msgstr "" "Формат визначення змішаного кольору такий — «blend/bg_color/fg_color/alpha», " "«%s» не відповідає формату" #: ../src/ui/theme.c:1372 #, c-format msgid "Could not parse alpha value \"%s\" in blended color" msgstr "Неможливо розібрати значення альфа «%s» у змішаному кольорі" #: ../src/ui/theme.c:1382 #, c-format msgid "Alpha value \"%s\" in blended color is not between 0.0 and 1.0" msgstr "Значення альфа «%s» у змішаному кольорі поза межами 0.0 — 1.0" #: ../src/ui/theme.c:1429 #, c-format msgid "" "Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format" msgstr "" "Формат тіні такий — «shade/base_color/factor», «%s» не відповідає формату" #: ../src/ui/theme.c:1440 #, c-format msgid "Could not parse shade factor \"%s\" in shaded color" msgstr "Не вдалось проаналізувати компонент тіні «%s» у затіненому кольорі" #: ../src/ui/theme.c:1450 #, c-format msgid "Shade factor \"%s\" in shaded color is negative" msgstr "Компонент тіні «%s» у затіненому кольорі від'ємний" #: ../src/ui/theme.c:1479 #, c-format msgid "Could not parse color \"%s\"" msgstr "Не вдалось проаналізувати колір «%s»" #: ../src/ui/theme.c:1790 #, c-format msgid "Coordinate expression contains character '%s' which is not allowed" msgstr "Вираз координати містить заборонений символ «%s»" #: ../src/ui/theme.c:1817 #, c-format msgid "" "Coordinate expression contains floating point number '%s' which could not be " "parsed" msgstr "" "Вираз координати містить число з рухомою комою «%s», яке не вдалось розібрати" #: ../src/ui/theme.c:1831 #, c-format msgid "Coordinate expression contains integer '%s' which could not be parsed" msgstr "Вираз координати містить ціле число «%s», яке не вдалось розібрати" #: ../src/ui/theme.c:1953 #, c-format msgid "" "Coordinate expression contained unknown operator at the start of this text: " "\"%s\"" msgstr "Вираз координати містить невідомий оператор на початку тексту: «%s»" #: ../src/ui/theme.c:2010 #, c-format msgid "Coordinate expression was empty or not understood" msgstr "Вираз координати був пустий або його неможливо розпізнати" #: ../src/ui/theme.c:2121 ../src/ui/theme.c:2131 ../src/ui/theme.c:2165 #, c-format msgid "Coordinate expression results in division by zero" msgstr "Вираз координати призвів до ділення на нуль" #: ../src/ui/theme.c:2173 #, c-format msgid "" "Coordinate expression tries to use mod operator on a floating-point number" msgstr "" "Вираз координати намагається використати оператор знаходження залишку від " "ділення для числа з рухомою комою" #: ../src/ui/theme.c:2229 #, c-format msgid "" "Coordinate expression has an operator \"%s\" where an operand was expected" msgstr "Вираз координати містить оператор «%s», там де очікувався операнд" #: ../src/ui/theme.c:2238 #, c-format msgid "Coordinate expression had an operand where an operator was expected" msgstr "Вираз координати містить оператор, там де очікувався оператор" #: ../src/ui/theme.c:2246 #, c-format msgid "Coordinate expression ended with an operator instead of an operand" msgstr "Вираз координати закінчується оператором замість операнда" #: ../src/ui/theme.c:2256 #, c-format msgid "" "Coordinate expression has operator \"%c\" following operator \"%c\" with no " "operand in between" msgstr "" "Вираз координати містить оператор «%c», за яким йде оператор «%c» без " "операнду між ними" #: ../src/ui/theme.c:2407 ../src/ui/theme.c:2452 #, c-format msgid "Coordinate expression had unknown variable or constant \"%s\"" msgstr "Вираз координати містить невідому змінну або константу «%s»" #: ../src/ui/theme.c:2506 #, c-format msgid "Coordinate expression parser overflowed its buffer." msgstr "Переповнення буфера обробника координат." #: ../src/ui/theme.c:2535 #, c-format msgid "Coordinate expression had a close parenthesis with no open parenthesis" msgstr "Вираз координати містить завершальну дужку без відповідної починальної" #: ../src/ui/theme.c:2599 #, c-format msgid "Coordinate expression had an open parenthesis with no close parenthesis" msgstr "Вираз координати містить починальну дужку без відповідної завершальної" #: ../src/ui/theme.c:2610 #, c-format msgid "Coordinate expression doesn't seem to have any operators or operands" msgstr "Здається, вираз координати не містить жодного оператора чи операнду" #: ../src/ui/theme.c:2822 ../src/ui/theme.c:2842 ../src/ui/theme.c:2862 #, c-format msgid "Theme contained an expression that resulted in an error: %s\n" msgstr "Тема містить вираз, що призводить до помилки: %s\n" #: ../src/ui/theme.c:4533 #, c-format msgid "" "